diff --git a/.agents/skills/create-flet-control-integration-tests/SKILL.md b/.agents/skills/create-flet-control-integration-tests/SKILL.md new file mode 100644 index 0000000000..0591a2a05b --- /dev/null +++ b/.agents/skills/create-flet-control-integration-tests/SKILL.md @@ -0,0 +1,167 @@ +--- +name: create-flet-control-integration-tests +description: Use when asked to create or update integration tests for any Flet control in sdk/python/packages/flet/integration_tests, including visual goldens and interactive behavior tests. +--- + +## When to use + +Use this skill when adding, updating, or reviewing integration tests for a Flet control (core, material, cupertino, theme, services, types, or examples). + +Use it for: + +- visual rendering checks with golden screenshots +- interaction checks (hover, click, input, keyboard) +- control property behavior checks +- regression tests for control bugs + +## Test placement + +Pick the closest existing suite first: + +- Core controls: `sdk/python/packages/flet/integration_tests/controls/core` +- Material controls: `sdk/python/packages/flet/integration_tests/controls/material` +- Cupertino controls: `sdk/python/packages/flet/integration_tests/controls/cupertino` +- Theme tests: `sdk/python/packages/flet/integration_tests/controls/theme` +- Type helpers: `sdk/python/packages/flet/integration_tests/controls/types` +- Services: `sdk/python/packages/flet/integration_tests/controls/services` +- Examples: `sdk/python/packages/flet/integration_tests/examples` + +Prefer adding tests to an existing file for the same control. Create a new test file only when no suitable file exists. + +### Scope split rule (required) + +Do not mix `loop_scope="module"` and `loop_scope="function"` tests in the same file. + +Naming convention: + +- `test_.py` for module-scoped visual/stable tests (uses `flet_app`) +- `test__isolated.py` for function-scoped tests that require a fresh app per test (uses `flet_app_function`) + +## Fixture choice + +Use fixtures from `integration_tests/conftest.py`: + +- `flet_app` (`loop_scope="module"`): best for stable visual tests and bulk screenshot tests. +- `flet_app_function` (`loop_scope="function"`): best for tests that mutate state and must run in a separate app each. + +## Authoring workflow + +1. Identify behavior to verify. +2. Build deterministic layout/state: +- set `theme_mode` explicitly when visuals matter +- set fixed sizes/padding/spacing +- avoid random or time-varying content +3. Choose file by scope rule before writing tests. +4. Write test using async pytest. +5. Use screenshot assertion for UI behavior, functional assertion for non-visual behavior. +6. Name test so `request.node.name` can be used as screenshot key. +7. Run target test file. +8. If expected visuals changed, regenerate goldens with `FLET_TEST_GOLDEN=1` and re-run without golden mode. + +## Assertion patterns + +### Visual control assertion + +```python +await flet_app.assert_control_screenshot( + request.node.name, + control, +) +``` + +### Visual full-page assertion + +```python +flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), +) +``` + +### Functional assertion + +```python +finder = await flet_app_function.tester.find_by_tooltip("Info tooltip") +assert finder.count == 1 +``` + +## Minimal templates + +### Template: module-scope file (`test_.py`) + +```python +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container(width=240, height=80, alignment=ft.Alignment.CENTER), + ) +``` + +### Template: function-scope file (`test__isolated.py`) + +```python +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_(flet_app_function: ftt.FletTestApp): + flet_app_function.page.add(ft.IconButton(icon=ft.Icons.INFO, tooltip="Info")) + await flet_app_function.tester.pump_and_settle() + + finder = await flet_app_function.tester.find_by_tooltip("Info") + assert finder.count == 1 +``` + +## Run commands + +Run one test file: + +```bash +uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/core/test_control.py +``` + +Run a subset: + +```bash +uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/core/test_control.py -k test_visible +``` + +Generate or update goldens: + +```bash +FLET_TEST_GOLDEN=1 uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/core/test_control.py +``` + +## Quality checklist + +- Test file location matches control area. +- `module` and `function` scope tests are in separate files. +- Function-scoped files use the `test__isolated.py` naming convention. +- Fixture scope matches test intent. +- Screenshot keys are stable (`request.node.name` preferred). +- Visual tests are deterministic (theme/size/content). +- Goldens are updated only for intentional visual changes. +- No unrelated formatting or refactors in the same change. + +## References + +- `sdk/python/packages/flet/integration_tests/README.md` +- `sdk/python/packages/flet/integration_tests/conftest.py` +- `sdk/python/packages/flet/integration_tests/controls/core/test_control.py` +- `sdk/python/packages/flet/integration_tests/controls/core/test_control_isolated.py` +- `sdk/python/packages/flet/integration_tests/controls/core/test_layout_control.py` +- `sdk/python/packages/flet/integration_tests/examples/core/test_control.py` +- `sdk/python/examples/controls/control` diff --git a/.agents/skills/create-flet-example-projects/SKILL.md b/.agents/skills/create-flet-example-projects/SKILL.md new file mode 100644 index 0000000000..f1c8845bf0 --- /dev/null +++ b/.agents/skills/create-flet-example-projects/SKILL.md @@ -0,0 +1,146 @@ +--- +name: create-flet-example-projects +description: Use when asked to create Flet example projects from flat .py files with main.py and pyproject.toml metadata for Gallery/MCP indexing. +--- + +## When to use + +Use this skill when a user asks to: +- create one control/example folder (for example `examples/controls/chip`) in the project-per-example format +- migrate existing flat examples to the project-per-example format +- normalize a partially converted folder so all examples follow the same structure + +## Goal + +Ensure each runnable example is a standalone project containing: + +- `main.py` +- `pyproject.toml` with Gallery/MCP metadata +- `assets/` (if the example uses local assets) + +## Workflow + +1. Inspect source folder. +- Detect current state per example: + - flat file: `foo.py` + - project folder: `foo/main.py` + - mixed/partial conversion: both styles present or missing metadata files +- Find candidate flat modules: `*.py` in the target folder (exclude helper files such as `__init__.py`). +- Keep existing `media/` unless an example needs local assets copied into its own `assets/`. + +2. Convert or normalize examples. +- For `foo.py`, create `foo/` and move file to `foo/main.py`. +- If `foo/main.py` already exists, keep it and do not recreate/move files. +- If folder exists but `main.py` is missing, repair structure only when there is a clear source file. +- Do not create `foo/__init__.py`; import example modules directly in tests/docs (for example `import examples.controls.foo.bar.main as bar` or `import examples.controls.foo.bar as bar` when using namespace-package imports). +- When a control folder has been fully converted to project-per-example layout, delete the control-level `examples/controls//__init__.py` too. The converted folders should behave like namespace packages, matching prior migrations such as commit `7e65ad566`. + +3. Add `pyproject.toml` for each example project. +- Infer from path and code. +- Create missing `pyproject.toml` files for existing project folders. +- Update obviously stale metadata when migrating existing examples (for example wrong title/description/categories). +- Verify platform support before adding or omitting `[tool.flet].platforms`: + - Check the local implementation and docs for explicit platform guards, support tables, or platform-specific exceptions. + - If support is limited, add `[tool.flet].platforms` with only the supported platforms. + - If support is broad/all-platform, omit `[tool.flet].platforms`. +- Required fields: + - `[project]`: `name`, `version`, `description`, `requires-python`, `keywords`, `authors`, `dependencies` + - `[dependency-groups].dev`: include `flet-cli`, `flet-desktop`, `flet-web` + - `[tool.flet.gallery].categories` + - `[tool.flet.metadata]`: `title`, `controls`, `layout_pattern`, `complexity`, `features` + - `[tool.flet]`: `org`, `company`, `copyright` +- Add `[tool.flet].platforms` only when the example is platform-limited. +- Add permissions blocks only when code actually needs them. + +4. Infer metadata. +- Title: readable version of file/folder intent. +- Short description: one line of what the example demonstrates. +- `[project].description` must be meaningful and example-specific; avoid generic placeholders like "Example N" or " example for ". +- Description should mention the concrete behavior or interaction shown (for example: hover highlight, live updates, custom axes, event handling). +- Categories: typically control-based, e.g. `Input/Chip`, plus optional `Apps/Basic controls`. +- Tags: from control/topic/behavior words. +- Controls used: list key controls from code. +- Layout pattern: choose closest practical value (e.g. `filter-bar`, `inline-actions`, `dashboard`, `list-detail`). +- Complexity: `basic` unless logic/state/architecture is non-trivial. +- Features: notable behaviors only (click handling, selection, async loading, drag-and-drop, etc.). +- If an example supports exporting or downloading output, include `"save to file"` in `[tool.flet.metadata].features`. +- If an example module contains `async def` handlers or async control flow, append `"async"` to `keywords`. + + +5. Infer dependencies from imports. +- Always include `flet` for standard examples. +- Include extra packages if imported (for example extension packages). +- Do not add unused dependencies. + +6. Make examples mobile-safe. +- If `ft.context.disable_auto_update()` is not used, do not add explicit `page.update()` unless strictly necessary. +- Apply this `page.update()` rule to all examples in the touched folder (new, migrated, and already converted). +- Wrap app content in `ft.SafeArea` so example renders correctly on mobile. +- Add `expand=True` to `ft.SafeArea` only when needed for correct layout/sizing (for example to avoid Infinity/NaN sizing issues), and avoid adding it when not necessary. +- When converting legacy `page.add(a, b, ...)` style examples, wrap the controls in `ft.Column(controls=[...])` inside `ft.SafeArea(content=...)` rather than `ft.Row`, unless the original code explicitly used a row layout. + +- Apply this to all examples in the touched folder (new, migrated, and already converted), not only files changed by moves. +- During validation, confirm every `/main.py` in scope includes a top-level `ft.SafeArea` around rendered content. +- For declarative examples using `@ft.component`, do not pass component instances as regular control children (for example `SafeArea(content=App())`) because this can raise runtime attribute errors. +- In declarative examples, ensure the component itself returns regular controls (including `SafeArea` when needed) and render it at page level with `page.render(App)` in `main()`. + +7. Prefer `@ft.control` for custom controls in examples. +- If an example defines a custom control class inheriting from a Flet control (for example `class MyThing(ft.Column)`), prefer `@ft.control` style. +- Move constructor-style setup to declarative fields + `init()` where practical. +- Keep behavior unchanged and avoid refactors that alter public usage unless needed for compatibility. + +8. Remove deprecated Material 3 toggle usage. +- If `use_material3` appears in example code, remove it and simplify the example to current API usage. +- Remove related Material 3 toggle logic/UI that exists only to switch `use_material3`. +- Update example metadata (`pyproject.toml`) to remove stale Material 3 references when code is changed. + +9. Ensure runnable entrypoint. +- Every example `main.py` should end with: + - `if __name__ == "__main__":` + - ` ft.run(main)` +- Apply this to all examples in the touched folder (new, migrated, and already converted). + +10. Update references. +- Docs code includes: change from `.../example.py` to `.../example/main.py`. +- Inspect the relevant docs pages for each touched control/service/example area (for example `sdk/python/packages/flet/docs/controls/.md`) and update any `--8<--` includes or direct file-path references to the new `main.py` path. +- Tests/imports: use direct module imports and avoid relying on package-level `__init__.py` re-exports. +- For already-converted examples, only update references that are stale; avoid unnecessary churn. +- If removing a control-level `__init__.py`, confirm no remaining imports rely on `from examples.controls. import ...`. + +11. Validate. +- Run `python -m compileall` on changed `main.py` files. +- Run `uv run ruff check` on changed example files and fix violations until it passes (respecting repository `pyproject.toml` under `[tool.ruff]`). +- Search for stale paths to old flat files. +- Search docs and package sources for stale references to the migrated flat example paths and fix any hits in scope. +- Check `git status` to confirm expected moves and edits. +- When integration tests exist for the touched control, run the targeted test file(s). +- Confirm all in-scope `main.py` files include both top-level `ft.SafeArea` wrapping and the `if __name__ == "__main__": ft.run(main)` entrypoint. +- Confirm in-scope `ft.SafeArea` wrappers use `expand=True` only where needed for correct behavior and sizing; avoid forcing it by default. +- Confirm there are no unnecessary `page.update()` calls in in-scope examples (unless explicitly required by isolated-control or non-auto-update behavior). +- Confirm no in-scope examples use `use_material3`. +- Confirm each in-scope `pyproject.toml` has a meaningful, example-specific `[project].description` (not generic or templated text). +- Confirm metadata features include `"save to file"` when the example code supports file export/save behavior. +- Confirm there is no stale control-level `__init__.py` left behind once a touched control folder has been fully converted. +- Confirm the relevant docs pages were updated to reference `main.py` and that no stale doc includes remain for the touched examples. + + +## Code style + +- When writing wrapped controls (`SafeArea`, `Column`, `Row`, `Container`, etc.), keep `content=` or `controls=` as the last named argument in that control call. +- Apply this ordering consistently when creating or refactoring examples. +- Follow code style and linting rules defined in the repository `pyproject.toml` under `[tool.ruff]` for all edits. + +## Command checklist + +- Discover files: `rg --files ` +- Find docs links/imports: `rg -n "" packages examples` +- Syntax check: `python -m compileall ` +- Ruff check: `uv run ruff check ` + +## Output expectations + +Report: +- created example projects +- metadata added +- docs/tests updates +- validation results diff --git a/.agents/skills/docs-build-and-verify/SKILL.md b/.agents/skills/docs-build-and-verify/SKILL.md new file mode 100644 index 0000000000..4614729da5 --- /dev/null +++ b/.agents/skills/docs-build-and-verify/SKILL.md @@ -0,0 +1,80 @@ +--- +name: docs-build-and-verify +description: Use when asked to build, preview, or verify the Flet documentation website, including checking for broken links, broken images, and unresolved reST cross-references. +--- + +# Docs Build and Verification + +## Prerequisites + +Node.js 20 is required: + +```bash +nvm use 20 +``` + +## Build + +Full production build (includes broken link detection): + +```bash +cd website && yarn build +``` + +Dev server with hot reload: + +```bash +cd website && yarn start +``` + +Regenerate API data and sidebars only (no Docusaurus build): + +```bash +cd website && yarn crocodocs:generate +``` + +## Check Broken Links + +`yarn build` automatically reports broken links and anchors. The build fails if any are found. + +## Check Broken Images + +Run this after `yarn build` to find images referenced in HTML that don't exist: + +```bash +cd website && python3 -c " +import re, os, glob + +build_dir = 'build' +img_re = re.compile(r']+src=\"(/[^\"]+)\"', re.IGNORECASE) +broken = [] + +for html_file in sorted(glob.glob(f'{build_dir}/docs/**/index.html', recursive=True)): + page = html_file.replace(build_dir + '/', '').replace('/index.html', '') + content = open(html_file).read() + for match in img_re.finditer(content): + src = match.group(1) + if src.startswith('http') or src.startswith('data:'): + continue + file_path = os.path.join(build_dir, src.lstrip('/')) + if not os.path.exists(file_path): + broken.append((page, src)) + +if broken: + print(f'Found {len(broken)} broken images:') + for page, src in broken: + print(f' {page}: {src}') +else: + print('No broken images found!') +" +``` + +## Check Unresolved reST Cross-References + +After building, check for reST roles that failed to resolve and appear as raw text: + +```bash +cd website && grep -r ':attr:\|:class:\|:meth:\|:func:' build/docs/ --include='*.html' -l +``` + +If any files are listed, those pages have unresolved cross-references that render as plain text instead of links. diff --git a/.agents/skills/docs-conventions/SKILL.md b/.agents/skills/docs-conventions/SKILL.md new file mode 100644 index 0000000000..70f091728c --- /dev/null +++ b/.agents/skills/docs-conventions/SKILL.md @@ -0,0 +1,204 @@ +--- +name: docs-conventions +description: Use when writing or reviewing Flet documentation, including Python docstrings (Google style, reST roles, admonitions), Markdown docs (cross-references, images, code examples), and sidebar navigation. +--- + +# Documentation Conventions + +Docs live in `website/docs/`. Docusaurus renders them as the website. + +## Python Docstrings + +Use **Google style** docstrings with sections: `Args:`, `Returns:`, `Raises:`, `Note:`, `Example:`, `Warning:`. + +## Cross-references + +### reST roles + +Prefer these in Python docstrings. CrocoDocs renders them as links in +the API docs and they keep authoring terse when the auto-derived label is acceptable. + +**Supported roles:** `:class:`, `:attr:`, `:meth:`, `:func:`, `:data:`, `:mod:` + +```python +""" +If a parent is a :class:`~flet.ResponsiveRow`, this property determines +how many virtual columns the control spans. + +See :attr:`value` or :attr:`flet.Text.size` for the current selection. + +Calls :meth:`flet.Page.update` after modifying controls. +""" +``` + +**Rules:** + +- **Qualified reference:** `:attr:`flet.Page.route`` — links to the member, displays inline code `Page.route` +- **Extension reference:** `:attr:`flet_map.Map.animation_curve`` — links to the extension member, displays inline code `Map.animation_curve` +- **Short display with `~`:** `:attr:`~flet.Page.route`` — links to the member, displays inline code `route` +- **Local member (same class):** `:attr:`value`` — no qualifier needed +- **Method with parens:** `:meth:`update`` — do NOT include `()` in the target + +For plain class references like `:class:`flet.Page`` and extension references like +`:class:`flet_map.Map``, the website strips leading public package aliases automatically, +so they display as inline code `Page` and `Map`. + +**Not supported:** + +- Custom labels like `:class:`my label `` — the label is always auto-derived from the target +- Roles for symbols not in CrocoDocs API data degrade to inline code + +### Xrefs + +Reference-style Markdown links of the form `[label][key]`, where `key` is the +fully-qualified dotted symbol path (same form as reST role targets). + +Use as the default form for linking to API symbols from Markdown docs +(`.md` / `.mdx`). + +Examples: + +```markdown +Class: [`Page`][flet.Page] +Attribute: [`route`][flet.Page.route] +Method: [`Page.update()`][flet.Page.update] +Extension: [`Video.controls`][flet_video.Video.controls] +Plain text: [the route attribute][flet.Page.route] +``` + +**When to prefer over the other forms:** + +- **Flexible labels** — the first `[ ]` accepts any text or inline code, unlike reST roles whose label is always auto-derived from the target +- **Path-independent** — keys are dotted symbol paths, so links don't break when source files are moved, renamed, or restructured (unlike Markdown link paths with `../` and `#flet.X.y` anchors) +- **Terser** than Markdown links to the same symbol — no relative path or anchor to maintain +- **Greppable** — searching for the dotted key finds every reference to that symbol across all docs + +**Rules:** + +- The label (inside the first `[ ]`) is the rendered text — inline code or plain text +- The key (inside the second `[ ]`) is the fully-qualified dotted path; do NOT include `()` for methods +- Unresolved keys render as broken reference-style links (silent fallback) — verify with a build or `yarn crocodocs:generate` + +### Markdown links + +Fallback for cases xrefs cannot cover: + +- docs-only Python strings — the `docs_reason` parameter of `@deprecated`, extracted validation messages, or short admonition text +- links to non-API content (other doc pages, external URLs, anchors that aren't API symbols) +- when the xref entry is missing and you need a working link before regenerating + +Use relative `.md` paths with dot-format anchors. + +Examples: + +```markdown +Control: [`Page`](../controls/page.md) +Type: [`DragTargetEvent.global_position`](../types/dragtargetevent.md#flet.DragTargetEvent.global_position) +Plain text: [route](../controls/page.md#flet.Page.route) +Method: [`Page.update()`](../controls/page.md#flet.Page.update) +``` + +## Admonitions in docstrings + +Google-style section headers render as Docusaurus admonitions: + +```python +""" +Note: + Has effect only if the direct parent is a :class:`~flet.Column`. + +Warning: + This property is deprecated. Use :attr:`new_prop` instead. + +Example: + Setting up a basic layout: + ``ft.Column(controls=[ft.Text("Hello")])`` +""" +``` + +Supported kinds: `Note`, `Warning`, `Danger`, `Tip`, `Info`. +Unsupported kinds (e.g. `Limitation`, `Example`) are normalized to `note`. +Empty admonitions are skipped. + +## Admonitions + +```markdown +:::note +Basic note without title. +::: + +:::warning[Important] +Warning with a custom title. +::: +``` + +Supported types: `note`, `info`, `tip`, `warning`, `danger`. + +## Front matter + +```yaml +--- +class_name: "flet.Container" +examples: "controls/container" +example_images: "test-images/examples/material/golden/macos/container" +example_media: "examples/controls/container/media" +title: "Container" +--- +``` + +- `examples` — root-relative path under `sdk/python/examples/` +- `example_images` / `example_media` — root-relative under `website/static/docs/` + +## Images + +Use the CrocoDocs `Image` component. Paths without `../` are resolved against `/docs/`: + +```jsx +import {Image} from '@site/src/components/crocodocs'; + + +``` + +For absolute paths (one-off assets in `static/`): + +```jsx + +``` + +## Code examples + +```jsx +import {CodeExample} from '@site/src/components/crocodocs'; + + +``` + +Paths are relative to the configured `examples_root` (`sdk/python/examples/`). + +## Inline HTML + +Use `...` in Python docstrings for keyboard keys, for example +`Enter` or `Shift`. CrocoDocs preserves this tag in API +docs. + +## Sidebar Navigation + +Edit `website/sidebars.yml` to change navigation structure: + +```yaml +docs: + Getting started: + - getting-started/installation.md + Controls: + _generated_index: + title: Controls + slug: /controls + description: Browse the complete catalog of controls. + AlertDialog: controls/alertdialog.md +``` + +After editing, regenerate `sidebars.js`: + +```bash +cd website && yarn crocodocs:generate +``` diff --git a/.agents/skills/fix-members-short-description/SKILL.md b/.agents/skills/fix-members-short-description/SKILL.md new file mode 100644 index 0000000000..c2f2e60159 --- /dev/null +++ b/.agents/skills/fix-members-short-description/SKILL.md @@ -0,0 +1,47 @@ +--- +name: fix-members-short-description +description: Use when asked to fix short descriptions of Python type members. +--- + +## Inputs + +* File or directory with Python modules. + +## Instructions + +When Flet documentation is generated from docstrings the first sentence of a member docstring is used as a short description, for example: + +```py +@dataclass +class MyControl: + property_a: str + """ + Short description of a property. + + Full description. + Another line of full description. + """ +``` + +Here "Short description of a property." will be used as a short description. + +However, when a sentence is broken into multiple lines the lines must be "concatenated" with `\`, for example: + +```py +@dataclass +class MyControl: + property_a: str + """ + Short description of a property which could \ + take multiple lines. + + Full description. + Another line of full description. + """ +``` + +Your goal is to go through all members (properties, methods, etc.) of all types (classes, enums) in input file or directory and ensure the first sentence in their docstrings is broken into multiple lines correctly with `\` symbol. + +Apply the fix regardless of whether the first sentence starts on the same line as the opening `"""` or on a following line. + +Ensure every docstring line is at most 88 characters long (including any trailing `\`). If a line cannot be wrapped without breaking a single unbreakable token (e.g., a long URL or Windows registry path like `HKEY_LOCAL_MACHINE\\...`), add `# noqa: E501` to the docstring closing `"""` line instead of the long line. diff --git a/.agents/skills/flet-deprecation/SKILL.md b/.agents/skills/flet-deprecation/SKILL.md new file mode 100644 index 0000000000..13e977d8ac --- /dev/null +++ b/.agents/skills/flet-deprecation/SKILL.md @@ -0,0 +1,195 @@ +--- +name: flet-deprecation +description: Use when adding or changing deprecations for Python controls/APIs in sdk/python/packages/, including V.deprecated fields, deprecated decorators, version lifecycle, and docs admonitions/labels. +--- + +## When To Use + +Use this skill when you: +- deprecate a control/dataclass field with `Annotated[..., V.deprecated(...)]`, +- deprecate a function/method/class with `flet.utils.deprecated` helpers, +- update deprecation wording, versions, or removal timelines, +- verify docs rendering for deprecations (admonition + `deprecated` label). + +Do not use this skill for non-deprecation validation logic; use +[`flet-validation`](../flet-validation/SKILL.md). + +## Source Of Truth + +- Runtime decorators and warning helpers: `sdk/python/packages/flet/src/flet/utils/deprecated.py` +- Field-level deprecation rule: `sdk/python/packages/flet/src/flet/utils/validation.py` (`V.deprecated`) +- Docs extraction/labeling extension: `sdk/python/packages/flet/src/flet/utils/griffe_deprecations.py` + +## Deprecation Decision Order + +Use this order and stop at the first option that fits: +1. Property/field deprecation: `Annotated[..., V.deprecated(...)]`. +2. Function/method deprecation: `@deprecated(...)`. +3. Class/control deprecation: `@deprecated_class(...)`. + +Do not add parallel custom warning logic in `before_update()` when `V.deprecated` +already covers the field. + +## Runtime Contract For Property Renames + +Follow the non-copying model: +- Python sends both properties when both are set. +- Dart prefers the new property and uses old property as fallback. +- Python does not copy/synchronize old/new values in `before_update()`. + +Removal phase: +- At `delete_version` cleanup, remove old Python property/deprecation and remove + Dart fallback in the same migration. + +## Removal Version Policy + +- Default policy: remove deprecated APIs after 3 minor releases. +- Example: deprecated in `0.82.0` -> remove in `0.85.0`. +- Use that policy to set `delete_version` unless there is an approved exception. + +## Target Release Audit + +When working on a release for `{new_version}`, treat deprecations with +`delete_version == {new_version}` as mandatory audit items. + +- Scan Python packages for `@deprecated(...)`, `@deprecated_class(...)`, + and `V.deprecated(...)` entries whose `delete_version` equals `{new_version}`. +- Recommended check command: + `rg -n 'delete_version\\s*=\\s*"{new_version}"|delete_version\\s*=\\s*\\x27{new_version}\\x27' -S sdk/python/packages` +- Treat every match as release-relevant work, not informational output. +- If matches are found, summarize the findings first and ask the human for approval + before editing files or making removals. +- For each match, decide whether the deprecated API must be removed now, + whether a prior removal was missed, or whether the deprecation timeline is incorrect. +- If removal is due, make the code, docs, and changelog updates in the same change. +- After the cleanup edits are ready, summarize the resulting diff and ask the human + for approval before creating a commit. +- Once commit approval is received, batch all confirmed `{new_version}` cleanup + edits into one grouped commit instead of splitting them across multiple commits. + Use commit message format: `release: remove deprecated APIs for {new_version}` +- Do not consider the release prep complete while unresolved `{new_version}` removals remain. + +## Authoring Rules + +1. Always set `version`. +2. Set `delete_version` using the 3-minor policy by default. +3. Keep `reason` plain text for runtime warnings. +4. Use `docs_reason` for docs-only markdown text. +5. When a replacement exists, name that replacement API explicitly in `reason` and `docs_reason`. + +### Field Pattern + +```python +from typing import Annotated, Optional +from flet.utils.validation import V + +class ExampleControl: + old_prop: Annotated[ + Optional[str], + V.deprecated( + "new_prop", + version="0.17.0", + delete_version="0.20.0", + reason="Use new_prop instead.", + docs_reason="Use :attr:`new_prop` or [`new_prop`](../controls/examplecontrol.md#flet.ExampleControl.new_prop) instead.", + ), + ] = None +``` + +### Function/Method Pattern + +```python +from flet.utils.deprecated import deprecated + +class ExampleControl: + @deprecated( + reason="Use new_func instead.", + docs_reason="Use :meth:`new_func` or [`new_func()`](../controls/examplecontrol.md#flet.ExampleControl.new_func) instead.", + version="0.17.0", + delete_version="0.20.0", + ) + def old_func(self): + ... +``` + +### Class/Control Pattern + +```python +from flet.utils.deprecated import deprecated_class + +@deprecated_class( + reason="Use NewControl instead.", + docs_reason="Use :class:`~flet.NewControl` or [`NewControl`](../controls/newcontrol.md) instead.", + version="0.17.0", + delete_version="0.20.0", +) +class OldControl: + ... +``` + +### Deprecated Property Pattern + +```python +from flet.utils.deprecated import deprecated + +class ExampleControl: + @property + @deprecated( + reason="Use new_value instead.", + docs_reason="Use :attr:`new_value` or [`new_value`](../controls/examplecontrol.md#flet.ExampleControl.new_value) instead.", + version="0.17.0", + delete_version="0.20.0", + ) + def value(self): + ... +``` + +## `reason` vs `docs_reason` + +- Runtime warnings always use `reason`. +- Docs admonitions prefer `docs_reason`; fallback is `reason`. +- Keep markdown/cross-refs out of `reason` to avoid noisy runtime output. + +### Cross-reference Rule Inside `docs_reason` + +In `docs_reason`, use reST roles for simple references when the auto-derived label is +sufficient, and use Markdown links when you need more control over the displayed text. + +See [`docs-conventions`](../docs-conventions/SKILL.md) for details on supported cross-ref patterns and their syntax. + +## Docs Behavior Expectations + +For supported patterns, docs should auto-render: +- a `Deprecated` admonition section, +- a `deprecated` label/badge on the item. + +Do not duplicate with manual deprecation admonitions in docstrings unless there +is a special case not covered by the extension. + +## Testing Guidance + +Do not add one-off tests for every API that gets deprecated when it uses an +existing, already-tested pattern (`V.deprecated`, `@deprecated`, or +`@deprecated_class`). For routine deprecation metadata updates, rely on the +shared helper and docs extraction tests. + +Add or update tests only when the change affects deprecation infrastructure or +introduces meaningful new behavior, for example: +- changing runtime warning formatting or stacklevel behavior, +- changing docs extraction/labeling behavior, +- adding a new deprecation pattern, +- adding custom compatibility behavior outside the standard helper, +- fixing a regression where an existing test would not have failed. + +Prefer these locations for infrastructure tests: +- `sdk/python/packages/flet/tests/test_deprecated.py` +- `sdk/python/packages/flet/tests/test_griffe_deprecations.py` +- `sdk/python/packages/flet/tests/test_validation.py` (for `V.deprecated`) + +## Common Pitfalls + +- Putting markdown/cross-refs into runtime `reason`. +- Forgetting `delete_version` when a removal target is already known. +- Adding old/new value-copy logic in Python for rename migrations. +- Duplicating deprecation warnings in multiple lifecycle hooks manually. +- Broken cross-refs targets in `docs_reason`. diff --git a/.agents/skills/flet-validation/SKILL.md b/.agents/skills/flet-validation/SKILL.md new file mode 100644 index 0000000000..2a2854f587 --- /dev/null +++ b/.agents/skills/flet-validation/SKILL.md @@ -0,0 +1,192 @@ +--- +name: flet-validation +description: Use whenever editing validation for Python controls in sdk/python/packages/: adding/changing constrained properties, `Raises: ValueError` docstrings, `before_update()` checks, `raise ValueError`, Annotated/V rules, or __validation_rules__. +--- + +## When To Use + +Use this skill when you: +- add validation to a control property, +- migrate manual `before_update()` checks to `V` rules, +- update `Raises` sections tied to validation, +- align Python validation with Dart-side control behavior. + +Do not use this skill for unrelated doc-only edits outside control validation. +Do not use this skill for deprecation authoring conventions; use +[`flet-deprecation`](../flet-deprecation/SKILL.md). + +## Source Of Truth + +- Validation runtime API lives in: + `sdk/python/packages/flet/src/flet/utils/validation.py` +- The same runtime can validate regular dataclass models via `validate(instance)`; + this skill focuses on the control-specific authoring conventions. +- Import from public path only: + `from flet.utils.validation import V` + and when needed + `from flet.utils.validation import ValidationRules` + +## Validation Decision Order + +Use this order and stop at the first option that keeps logic clear: +1. `Annotated[..., V.*]` field rules (default). +2. `__validation_rules__: ValidationRules` for cross-field invariants that do + not map cleanly to one field. +3. `before_update()` only for normalization/mutation, or for truly non-ruleable + invariants. + +Never duplicate the same invariant in more than one layer. + +## Validation Authoring Rules + +1. Prefer field-level validation with `Annotated[...]` metadata. + - Example (close to current slider controls): + ``` + @dataclass + class Sample: + opacity: Annotated[ + Optional[Number], + V.between(0.0, 1.0), + ] = None + + value: Annotated[ + Optional[Number], + V.ge_field("min"), + V.le_field("max"), + ] = None + + min: Annotated[ + Number, + V.le_field("max"), + V.le_field("value"), + ] = 0.0 + + max: Annotated[ + Number, + V.ge_field("min"), + V.ge_field("value"), + ] = 1.0 + ``` + +2. Use class-level `__validation_rules__` only for invariants that cannot be + expressed cleanly with field rules. + - Type: + `__validation_rules__: ValidationRules = (...)` + - Use `V.ensure(...)` with an explicit message only when the predicate is + short and readable. + - If `V.ensure(lambda ...)` becomes hard to read, prefer either: + 1. a named predicate function passed to `V.ensure(...)`, or + 2. a clear `before_update()` check when it cannot be represented well with + existing `V.*` rules. + +3. Keep the `before_update()` override for normalization/mutation first. + - Remove validation checks duplicated by `V` rules. + - Prefer raising validation errors from rule evaluation (`validate()`), not + from ad-hoc `before_update()` checks, unless the invariant is genuinely + non-ruleable with current validation primitives. + +4. Cross-field comparisons use field rules only. + - Use: `V.gt_field`, `V.ge_field`, `V.lt_field`, `V.le_field` + +5. `None` handling is inferred from type hints. + - If a field is annotated as optional (for example `Optional[T]`), `None` is allowed. + - If a field is not optional, `None` fails validation. + - For `*_field` comparisons, if either side is optional and currently `None`, the + comparison is skipped; if a non-optional side is `None`, validation fails. + +6. Match Dart effective behavior. + - Review both: + 1. Flet Dart wrapper (`packages/flet/lib/src/controls/.dart` or + extension wrapper), + 2. wrapped Flutter widget source assertions/invariants. + - Mirror those constraints in Python so invalid payloads fail before crossing + to Dart. + - Validate against effective defaults applied on Dart side (for example + `min`/`max`). + - Include wrapper-imposed constraints when relevant (for example + bounds/rounding/division logic in wrapper formatting code). + +7. For new properties, validate against base widget assertions before wiring. + - When adding a Python property to a Flet control, confirm whether the mapped + Dart wrapper and underlying widget both enforce constraints for that property. + - Add equivalent Python-side validation (`Annotated[...]`, `__validation_rules__`, + or readable `before_update()`) to prevent Dart assertions from being the first + failure point. + +8. Keep error ownership clear. + - Runtime outbound value failures should raise `ValueError`. + - Validation declaration/build errors (invalid `V.*` arguments) should raise + `ValidationDeclarationError`. + +## Typing Style + +- Follow the codebase typing style: + - prefer `Optional[T]` over `T | None`, + - use `Union[...]` when needed. + +## Property Docstring Style + +When a property has validation, document it in that property’s docstring (google style). + +1. Add a `Raises:` block under the property docstring. + +2. Use one `ValueError` entry per logical rule, except `between(...)`. + - For `V.between(a, b)`, use one entry: + `ValueError: If it is not between \`a\` and \`b\`, inclusive.` + +3. Start each entry with `If it ...`, where 'it' refers to the property name. + +4. Use canonical wording from validation helper docstrings. + - The source of truth is + `sdk/python/packages/flet/src/flet/utils/validation.py`. + - Each `V.*` helper includes `Property docstring Raises wording`. + - Keep property `Raises` entries as negations of the annotation rule. + - For strict inequalities, say `"strictly"`. + For example: `V.gt(x)` -> `ValueError: If it is not strictly greater than \`x\`.` + - For sign-neutral divisibility helpers (`factor_of`, `multiple_of`), add + explicit sign rules (`V.gt(0)` or `V.lt(0)`) when direction matters, and + include separate `Raises` entries for those sign rules. + +5. Mention conditional applicability when needed. + - Example (for `min`/`max` checks against optional `value`): + ``` + Raises: + ValueError: If it is not less than or equal to [`value`][(c).], + when [`value`][(c).] is set. + ``` + +6. Keep examples and wording aligned with real control files. + - Prefer concrete property names such as `min`, `max`, `value`, + `start_value`, `end_value`, `min_lines`, `max_lines`. + - For cross-field rules, use same-class links: [`min`][(c).], [`max`][(c).]. + +## Cross-Referencing Conventions + +Follow the cross-reference guidance in: +[`docs-conventions`](../docs-conventions/SKILL.md). + +Most common pattern to use in control property docstrings: +- same-class properties: `[\`prop\`][(c).]` + +Keep symbol labels wrapped in backticks. + +## Required Test Matrix + +When adding/changing validation, include tests that cover: +- one valid case and one invalid case per new logical rule; +- boundary values (`==`, min/max edges) where applicable; +- cross-field set/unset combinations when optional values are involved; +- effective-default behavior when Dart applies defaults but Python value is + omitted. + +Prefer placing tests in: +- `sdk/python/packages/flet/tests/test_validation.py` for validation runtime; +- control-specific tests when behavior is tied to one control. + +## Common Pitfalls + +- Keeping stale manual `before_update()` validations after migration. +- Missing `Raises` entries on validated properties. +- Combining multiple non-between rules into one ambiguous `ValueError` sentence. +- Forgetting Dart defaults that still apply when Python property is omitted. +- Forcing complex `V.ensure(lambda ...)` expressions when `before_update()` would be cleaner. diff --git a/.agents/skills/imperative-to-declarative-flet/SKILL.md b/.agents/skills/imperative-to-declarative-flet/SKILL.md new file mode 100644 index 0000000000..b573fc7e6d --- /dev/null +++ b/.agents/skills/imperative-to-declarative-flet/SKILL.md @@ -0,0 +1,79 @@ +--- +name: imperative-to-declarative-flet +description: Convert an imperative Flet Python app in which controls are mutated and then page.update is called to declarative style using flet.component, flet.observable and state hooks. +metadata: + short-description: Port Flet app to declarative +--- + +# Imperative → Declarative (Flet Python) + +Port an existing imperative Flet app to “components mode” with `@ft.component`, hooks, and (optionally) `@ft.observable` models. + +## Outcomes + +- Original folder unchanged; new sibling folder created. +- Entry point uses `page.render(App)` (components mode). +- UI is derived from state; minimal/zero manual `page.update()` for normal UI updates. + +## Choose a state strategy + +- **Use `@ft.observable`** for nested app data you mutate in place (boards/lists/cards, drag+drop reorder). +- **Use `ft.use_state`** for local ephemeral UI state (hover flags, input text, dialog selection). +- Avoid storing live `Control`/component objects in state; store ids/enums and create controls during render. + +## Workflow + +### 1) Create a new declarative copy + +- Copy the existing app folder to a new one (e.g. `trolli` → `trolli-declarative-*`). +- Keep `assets/` with the new folder. + +### 2) Switch to components mode entrypoint + +- Create a root component `@ft.component def App(): ...`. +- Run with: + - `ft.run(lambda page: page.render(App), assets_dir=...)` +- Set page globals either: + - in a `main(page)` function before `page.render(App)`, or + - in `ft.on_mounted(...)` (works, but ordering can be less obvious). + +### 3) Centralize routing in `App` + +- Keep `app.route: str` as source of truth. +- In one place, define: + - `route_change(e)` to normalize/redirect/validate routes and set `app.route` + - a render-time `match app.route` (or a derived `active_screen`) to pick `content` +- Prefer: `route_change` mutates route state; `App()` render chooses UI based on that state. + +### 4) Componentize UI + +- Move UI chunks into `src/components/*.py`. +- Each component: + - takes only the model(s) it needs + - uses hooks for local UI state + - mutates observable models for app data changes + +### 5) Dialogs: reduce `page.update()` usage + +If a dialog mutates existing controls and calls `page.update()`, convert it to: + +- `@ft.component` dialog content with `ft.use_state` for `error`, `selected_color`, etc. +- event handlers call setters (no explicit updates) +- show it via `page.show_dialog(ft.AlertDialog(content=DialogContent(...)))` + +### 6) Assets/fonts checklist + +- Prefer an absolute `assets_dir` derived from `__file__`. +- If running via `flet run`, be aware it can set `FLET_ASSETS_DIR` and override `assets_dir=`. +- Font registration uses the dict key as the font family name: + - `page.fonts = {"Pacifico": "Pacifico-Regular.ttf"}` + - use `font_family="Pacifico"`. + +## Common pitfalls (and fixes) + +- **Event handler typing is invariant** (`Event[Sub]` ≠ `Event[Base]`): + - If `on_click` is declared on `Button`, annotate `e` as `ft.Event[ft.Button]` (or use `def handler(): ...`). +- **`TemplateRoute` params are dynamic**: + - `raw = getattr(troute, "id", None)` then `isinstance(raw, str)` before `int(raw)`. +- **`controls=[*[...], ...]` can confuse type checkers** with components: + - build lists in two steps and annotate/cast, or return raw controls from non-component factories. diff --git a/.agents/skills/implement-flet-extension/SKILL.md b/.agents/skills/implement-flet-extension/SKILL.md new file mode 100644 index 0000000000..01584b2c9d --- /dev/null +++ b/.agents/skills/implement-flet-extension/SKILL.md @@ -0,0 +1,96 @@ +--- +name: implement-flet-extension +description: Implement a new Flet extension/control that wraps a third-party Flutter package end-to-end, including dependency selection, version pinning, compatibility checks, Python/Flutter integration, docs, examples, tests, and CI updates. Use when adding any flet_* package backed by an external pub.dev package. +--- + +Implement a Flet extension around an external Flutter package using existing `flet_*` packages as implementation templates. + +## Inputs + +- Control/service name and Python package name (`flet_`). +- Target pub.dev package and intended version/range. +- API surface to expose in Python (properties, methods, events, types/enums). + +## Third-party Dependency Gate + +1. Confirm package health: maintenance activity, null-safety, platform support, and open issue risk. +2. Confirm license is compatible with Flet distribution. +3. Select a conservative version strategy: +- Pin exact version when behavior stability is critical. +- Use bounded ranges when required by ecosystem constraints. +4. Record key constraints and reasons in PR notes/commit message. + +## Control/Service Classification + +- Classify wrapped functionality before implementation: +1. `LayoutControl` for visual controls that participate in page/layout positioning. +2. Base `Control` for simple visual controls that do not require page positioning or define their own positioning rules/props (for example `Draggable`, `Divider`, `MenuBar`, `NavigationRail`). +3. Non-visual Service when functionality is not a renderable UI control. +- Inspect the wrapped Flutter package API to determine whether it includes non-visual/service functionality. +- For service patterns, follow existing extension examples: `sdk/python/packages/flet-audio`, `sdk/python/packages/flet-flashlight`, `sdk/python/packages/flet-secure-storage`. + +## API Mapping Rules + +- Expose only stable and useful features first; avoid mirroring every upstream option. +- Keep Python API idiomatic and concise; avoid redundant control-name prefixes. +- Map upstream naming inconsistencies to Flet conventions when needed. +- Add custom enums/types only when they improve correctness and discoverability. + +## Python-side Rules + +- Use `LayoutControl`, base `Control`, or Service base class according to classification. +- Implement typed properties, methods, and events exactly for chosen public API. +- Reuse existing serialization/event patterns from sibling controls/services. + +## Flutter-side Rules + +- Use `parseEnum()` for enums. +- For control attributes, prefer `widget.control.getBool()/getDouble()/...` accessors. +- For non-control parsing, use shared `parseSomething()` helpers. +- Do not add one-off private parser utilities when standard helpers exist. +- Put control-specific helpers in `utils/.dart`; shared helpers in `utils/.dart`. +- Prefer `parse`-prefixed helper names when converting input to Flutter structures. +- Avoid single-use local variables. + +### Default Value Matching (Critical) + +Properties with default values on the Python side are **not sent to Flutter** when unchanged from the default. Every Dart property read **must provide the same default** as its Python counterpart: + +- `control.getDouble("size", 100.0)!` when Python has `size: float = 100.0` +- `control.getBool("animate", true)!` when Python has `animate: bool = True` +- `parseDuration(value["dur"], const Duration(milliseconds: 500))!` when Python has `dur: DurationValue = field(default_factory=lambda: Duration(milliseconds=500))` +- `control.get("items")?.map(...).toList() ?? const []` when Python has `items: list[str] = field(default_factory=list)` + +Without matching defaults, Dart receives `null` and either crashes or silently uses the wrong value. This applies to all property types: bools, numbers, strings, enums, durations, collections, and nested `@ft.value` types. + +## Integration Checklist + +- Add dependency and registration to Flet client app. +- Add extension package to `sdk/python/pyproject.toml`. +- Add extension to `sdk/python/packages/flet/pyproject.toml`. +- Add extension to `sdk/python/examples/apps/flet_build_test/pyproject.toml`. +- Add extension to `.github/workflows/ci.yml` in both places: + - `build_flet_extensions` -> `PACKAGES` list. + - `py_publish` -> `for pkg in ...` publish loop. +- Add `.gitignore` to Flutter extension project if missing. + +## Docs, Examples, Tests + +- Add control/service docs under `website/docs/controls/` for controls and `website/docs/services/` for services. +- Add all custom enums/types docs and update `website/sidebars.yml` navigation. +- Use markdown filenames without underscores (`codeeditor.md`, not `code_editor.md`). +- Add examples under `sdk/python/examples` in the appropriate category for control vs service. +- Add integration tests under `packages/flet/integration_tests` in the appropriate category for control vs service. +- Ensure generated screenshots are suitable for docs usage when visual examples are added. + +## Upgrade and Compatibility Guardrails + +- Add at least one test that catches upstream behavioral changes likely to break wrapper mapping. +- Avoid exposing experimental upstream APIs unless explicitly requested. +- Keep wrapper surface narrow enough to maintain backwards compatibility across upstream updates. + +## Validation + +- Run relevant Python and integration tests for touched areas. +- Verify Python import paths, client runtime registration, and docs navigation. +- Verify dependency resolution and lockfile updates are intentional. diff --git a/.agents/skills/prepare-flet-release/SKILL.md b/.agents/skills/prepare-flet-release/SKILL.md new file mode 100644 index 0000000000..6ba4e7aa42 --- /dev/null +++ b/.agents/skills/prepare-flet-release/SKILL.md @@ -0,0 +1,50 @@ +--- +name: prepare-flet-release +description: Use when asked to prepare new Flet release by bumping versions and author release notes. +--- + +## Inputs + +* Previous Flet version from repo tags. +* Whether it's minor or major release. + +## Related Skills + +Always use [`flet-deprecation`](../flet-deprecation/SKILL.md) during release prep +to audit deprecations for the target version. Also use it when release prep includes: +- adding new deprecations in this release, +- removing APIs whose `delete_version` equals this release version, +- auditing changelog entries that mention deprecations/removals. + +Use [`write-changelog-entry`](../write-changelog-entry/SKILL.md) for drafting or refining individual changelog items. +That skill is the source of truth for item wording, scope selection, and what should or should not be mentioned in a single entry. + +## Steps + +* Take latest Flet release version from the repo and + increment third (patch) digit to get the next version if it's a minor release + or second (minor) digit if it's a major release. +* Pull the latest `main` and create a new branch named `prepare-release-{new_version}` from `main`. +* Set new version in packages/flet/pubspec.yaml. +* Run pub get in /client dir to refresh pubspec.lock with new version. +* Add new entries into `packages/flet/CHANGELOG.md` and `/CHANGELOG.md` from the git log since the last release. + * Use [`write-changelog-entry`](../write-changelog-entry/SKILL.md) for every individual item. + * Build the candidate set from relevant commits, PRs, and issues since the last release. + * Ensure that all inferred PRs and issues in the changelog have the `{version}` milestone attached on GitHub. + * If a related issue or PR is missing the `{version}` milestone, update the milestone on GitHub and keep the link in the changelog. + * When selecting candidates for `packages/flet/CHANGELOG.md`, prefer items with meaningful Flutter-side impact. + * When selecting candidates for `sdk/python/packages/*/CHANGELOG.md`, prefer published Python-facing changes; do not include extension-internal Flutter implementation work unless it materially changes user-visible Python behavior. +* Scan all changelogs for `Unreleased` sections, not only the root ones: + * `/CHANGELOG.md` + * `packages/flet/CHANGELOG.md` + * `sdk/python/packages/*/CHANGELOG.md` + Recommended check command: + `rg -n "^##\\s*\\[?Unreleased\\]?|^##\\s*Unreleased" -S CHANGELOG.md packages/flet/CHANGELOG.md sdk/python/packages/*/CHANGELOG.md` +* If any changelog has an `Unreleased` section, convert that section into the new release section (`## {new_version}`), preserving and re-sorting its items. Do not leave duplicate release content in both `Unreleased` and `{new_version}`. + This conversion must be done for every matched changelog from the scan above. +* Sort items in changelogs as following: + * New features + * Improvements + * Bug fixes + * Other changes (chore, refactor, etc.) +* Templates are in `sdk/python/templates/` and automatically packaged as zip artifacts with the GitHub Release. No manual branch creation in external repos is needed. diff --git a/.agents/skills/run-integration-tests/SKILL.md b/.agents/skills/run-integration-tests/SKILL.md new file mode 100644 index 0000000000..86edf509b7 --- /dev/null +++ b/.agents/skills/run-integration-tests/SKILL.md @@ -0,0 +1,10 @@ +--- +name: run-integration-tests +description: Use when asked to run integration tests. +--- + +## Instructions + +Integration tests are in `sdk/python/packages/flet/integration_tests` directory. + +Read `sdk/python/packages/flet/integration_tests/README.md` for further instructions. diff --git a/.agents/skills/run-unit-tests/SKILL.md b/.agents/skills/run-unit-tests/SKILL.md new file mode 100644 index 0000000000..c8baa43040 --- /dev/null +++ b/.agents/skills/run-unit-tests/SKILL.md @@ -0,0 +1,16 @@ +--- +name: run-unit-tests +description: Use when asked to run unit tests. +--- + +This skill is used to run unit tests of the Python part of Flet framework. + +## Instructions + +Run the following command to run `flet` package unit tests: + +``` +uv run --group test pytest packages/flet/tests +``` + +The directory in that commend is relative to `{root}/sdk/python`. diff --git a/.agents/skills/test-flet-apps-dev/SKILL.md b/.agents/skills/test-flet-apps-dev/SKILL.md new file mode 100644 index 0000000000..837a7fe852 --- /dev/null +++ b/.agents/skills/test-flet-apps-dev/SKILL.md @@ -0,0 +1,152 @@ +--- +name: test-flet-apps-dev +description: Use when testing or debugging Flet apps in maintainer/contributor development mode with local Python package sources and the local Flutter client, including web, desktop, browser, and computer-use verification workflows. +--- + +# Test Flet Apps In Dev Mode + +Use this skill when validating a Flet app, example, feature, or bug fix against +this repo's local Python packages and/or local Flutter client during maintainer +or contributor work. + +## Core model + +Flet dev-mode testing usually has one or two processes: + +1. A Python Flet app/server, run from `sdk/python`. +2. The local Flutter client, run from `client`, when Dart/client or extension code + must be tested. + +If only Python code changed, `uv run flet run ...` is often enough. If Dart, +Flutter, extension, or transport code changed, run the local Flutter client so +the changed Dart code is actually used. + +The local Flutter client debug build uses a fixed app-server URL from +`client/lib/main.dart`: + +```dart +if (kDebugMode) { + pageUrl = "http://localhost:8550"; +} +``` + +Therefore, when using the local Flutter client without extra URL arguments, +start the Python app on port `8550`. + +## Start the Python app + +Run from `{repo}/sdk/python`: + +```bash +uv run flet run -w -p 8550 examples/controls/core/interactive_viewer/handling_events/main.py +``` + +Adjust the sample path as needed. Use port `8550` when the local Flutter client +will connect with its default debug URL. Keep this process running and watch its +stdout for Python callback output, tracebacks, and event payloads. + +For web-only checks with the packaged web client, open: + +```text +http://127.0.0.1:8550 +``` + +## Run the local Flutter client + +Run these from `{repo}/client`. + +### Desktop + +Use when validating native desktop behavior on the current host OS: + +```bash +fvm flutter run -d macos # macOS +fvm flutter run -d windows # Windows +fvm flutter run -d linux # Linux +``` + +The debug client defaults to `http://localhost:8550` when no app URL argument is +provided. Use the platform target that exists on the current machine. Use +Computer Use or the relevant platform automation to navigate and interact with +the app window. + +### Flutter web in Chrome + +Use when Dart web behavior must be validated in Flutter's default web debug +browser: + +```bash +fvm flutter run -d chrome +``` + +This opens a fresh browser connected to the Python app server on port `8550`. + +### Flutter web in another Chromium browser + +If the requested browser is not listed by `flutter devices`, prefer the web +server target and open the served URL in that browser: + +```bash +fvm flutter run -d web-server --web-hostname 127.0.0.1 --web-port 8660 +open -a "Brave Browser" http://127.0.0.1:8660 +``` + +Using `CHROME_EXECUTABLE` can work, but Flutter may fail to attach its debug +websocket in non-default Chromium browsers. Fall back to `web-server` if that +happens. + +## Browser and UI interaction + +- For local browser targets (`localhost`, `127.0.0.1`, `file://`), prefer the + in-app browser or the Browser Use plugin when explicitly requested. +- Use Computer Use for native desktop apps and external browsers when browser + MCP is not the requested tool or cannot control that browser. +- For chart/canvas-heavy UI, click/hover coordinates may be necessary because + accessibility trees often expose only the HTML canvas container. + +## Reading evidence + +Always inspect both sides: + +- Python app stdout: event payloads, user `print()` calls, Python tracebacks. +- Flutter run stdout: client-side event payloads, WebSocket messages, Flutter + exceptions, hot reload/restart status. +- Browser/app state: the actual rendered UI and any visible error banner. + +For client/server protocol bugs, compare the raw outgoing Dart event in Flutter +logs with the decoded Python event object in Python logs. + +## Hot reload and restart + +For Flutter client sessions: + +- Press `r` for hot reload after many Dart-only edits. +- Press `R` for hot restart if state, initialization, or extension registration + may be stale. +- Quit with `q` before final response unless the user explicitly wants the app + left running. +- Press `h` for help on other Flutter run key commands. + +For Python app sessions, restart `uv run flet run ...` after Python source or +sample changes if the running process does not pick them up. + +## Troubleshooting + +- If a sandboxed Flutter command fails trying to write FVM or Flutter cache files + such as `engine.stamp`, rerun the same command with escalation. +- If `flutter devices` does not list Brave/Edge/etc., use `flutter run -d web-server` + and open the URL in the target browser. +- If the UI shows a generic Flet error banner, check Python stdout first; the + root cause is often a handler exception. +- If an event handler indexes a list payload, confirm the empty-list case before + treating it as a framework bug. +- If the local Flutter client cannot connect, confirm the Python app is running + on port `8550` or pass an explicit app URL when the client path supports it. + +## Finish checklist + +- Stop long-running app/test sessions unless asked to leave them running. +- State exactly which surfaces were tested: packaged web, local Flutter web, + desktop target, target browser, or sample-only. +- Include the key observed payload/error before and after the fix. +- Separate framework bugs from sample-code guard issues. diff --git a/.agents/skills/update-flet-control-doc-gifs/SKILL.md b/.agents/skills/update-flet-control-doc-gifs/SKILL.md new file mode 100644 index 0000000000..92b246d1fe --- /dev/null +++ b/.agents/skills/update-flet-control-doc-gifs/SKILL.md @@ -0,0 +1,64 @@ +--- +name: update-flet-control-doc-gifs +description: Create or update Flet control screenshots and GIFs that are generated from integration tests and shown in docs. Use when working on `sdk/python/packages/flet/integration_tests/examples`, refreshing static or interactive golden screenshots, or replacing old example media images or GIFs with generated test assets. +--- + +# Update Flet Control Doc Gifs + +Use this skill after the integration test structure is already in place and the task is to capture doc-ready screenshots or interactive GIF states from integration tests. + +## Workflow + +1. Locate the example-backed integration test under `sdk/python/packages/flet/integration_tests/examples`. +2. Prefer extending an existing interaction test instead of creating a second flow test. +3. Build the visual sequence with deterministic states: +- set `page.enable_screenshots = True` +- set `theme_mode` when visuals matter +- set fixed page size before screenshots +- prefer finding controls by visible text or other stable user-facing content; add a `key` only when there is no reliable human-facing locator +- call `pump_and_settle()` after each interaction +4. Capture only states that are visually meaningful: +- before interaction +- hover state +- popup/menu/dialog open +- reopened state that proves persistence +- single static screenshots when one frame is enough for docs +- do not keep screenshots taken after a click if the UI closes and the state is not visible +5. Use `assert_screenshot(...)` for regular golden screenshots and `create_gif([...], "", duration=...)` only when the docs benefit from an animated flow. + - Prefer storing only asserted or docs-facing states as named screenshots; keep intermediate hover/click frames in memory and pass them directly to `create_gif(...)` when they do not need standalone golden files. +6. Update docs to use the generated screenshot or GIF, not an old media asset from `examples/.../media`, when the integration-test asset is now the better docs artifact. +7. Update docs references to point at the intended generated screenshot or GIF path, but do not copy generated assets into `website/static/docs/test-images/...` as part of this workflow. + +## Naming + +- Use short screenshot names that describe visible states, for example `before_click`, `hover_popup`, `popup_open`, `checked_item_reopened`. +- Use one flow GIF name per control/example, for example `app_bar_flow`. +- Use descriptive static screenshot names when the asset is docs-facing, for example `image_for_docs`, `popup_open`, or `checked_item_reopened`. +- Give the integration test a behavior-based name such as `test_actions_and_popup_menu`; avoid placeholder names like `test_basic` when the test covers a specific flow. +- Keep screenshot names stable because they become golden filenames. + +## Docs Update Rules + +- Control docs usually point to generated assets through `frontMatter.example_images`. +- If a docs page still has `example_images` pointing at example media instead of generated test images, update that front matter first so the page has a single source of truth for screenshots and GIFs. +- When a docs page has multiple example sections, add the generated screenshot or GIF directly under the matching `CodeExample` block so each visual stays paired with the example it demonstrates. +- If a docs page still uses `frontMatter.example_media + '/old.png'` or `frontMatter.example_media + '/old.gif'`, replace it with `frontMatter.example_images + '/'` when the generated integration-test asset is the new source of truth. +- Generated screenshots and GIFs from integration tests are commonly stored at `sdk/python/packages/flet/integration_tests/examples/.../golden/macos//`. +- Do not copy generated screenshots or GIFs into `website/static/docs/test-images/...` as part of this skill. Keep the work limited to tests and docs references unless the user explicitly asks for a copy. + +## Verification Checklist + +- The interaction test still reflects the example behavior. +- Every screenshot included in a GIF is visibly different and useful. +- The GIF duration is intentional; prefer shorter loops for hover/click flows unless the interaction needs more time. +- The docs front matter points to the generated test-images location rather than stale example media paths. +- The docs page references the new screenshot or GIF path. +- The generated screenshot or GIF exists in the integration-test golden directory at the path implied by the test names. +- Remove or stop referencing obsolete media screenshots or GIFs only when the new generated asset fully replaces them. + +## References + +- `sdk/python/packages/flet/integration_tests/examples` +- `sdk/python/packages/flet/integration_tests/examples/controls/material/test_alert_dialog.py` +- `sdk/python/packages/flet/integration_tests/examples/controls/material/test_app_bar.py` +- `website/docs/controls` diff --git a/.agents/skills/write-changelog-entry/SKILL.md b/.agents/skills/write-changelog-entry/SKILL.md new file mode 100644 index 0000000000..07f324d585 --- /dev/null +++ b/.agents/skills/write-changelog-entry/SKILL.md @@ -0,0 +1,128 @@ +--- +name: write-changelog-entry +description: Use when asked to add, revise, or review a changelog or release-notes entry in this repo. Inspect the existing changelog section style and the relevant PR, issue, and commit context first, then write a focused entry in the correct release section without overstating docs, tests, or chores unless they are the primary user-facing change. +--- + +## Purpose + +Write changelog entries that match the surrounding section's style and reflect the actual shipped change for the intended audience. + +## Inputs + +* Target changelog file, if specified; otherwise infer it from the changed package + and audience. +* Release version or section if the user specifies one. +* Relevant PR number, issue number, commit(s), or branch context. + +## Target file selection + +Choose the narrowest correct changelog file before writing entries. + +* Use `/CHANGELOG.md` for repo-level or broadly user-facing Flet changes. +* Use `packages/flet/CHANGELOG.md` only for changes relevant to Flutter package + consumers and extension developers. See the dedicated section below. +* Use `sdk/python/packages//CHANGELOG.md` for changes scoped to a specific + Python package. +* For extension (ex: flet-audio) changelogs under + `sdk/python/packages//CHANGELOG.md`, write + entries from the published Python user's perspective. Do not surface internal Flutter + implementation changes unless they materially change the Python-facing feature, + behavior, or API. +* If one change clearly belongs in more than one published surface, update each relevant + changelog file. +* Do not default everything to `/CHANGELOG.md` when a package-specific changelog is the + better fit. + +## Root vs Flutter package changelog + +`/CHANGELOG.md` and `packages/flet/CHANGELOG.md` have different audiences. + +* `/CHANGELOG.md` is the broad Flet product changelog. Write entries from the app + developer's perspective, usually summarizing the shipped feature or fix at about + PR-title specificity. +* `packages/flet/CHANGELOG.md` is for Flutter package consumers and extension + developers. Write entries only when they need to know a specific Dart-side API, + utility, parser, serializer, runtime contract, dependency, or compatibility change. +* Do not repeat a root changelog entry in `packages/flet/CHANGELOG.md` merely because + the implementation touched Dart files. +* If both audiences are affected, update both changelogs, but phrase them differently: + the root entry should describe the user-facing outcome, while the Flutter package + entry should describe the precise Dart/extension-facing change. + +Example split: + +* Root: `Add support for text-or-control labels in \`NavigationDestination\`s.` +* Flutter package, only if applicable: `Extend \`Control\` with \`.buildTextOrWidget()\` to parse properties that accept either plain text or child controls.` + +## Workflow + +1. Inspect the target changelog section before editing. + * Match the existing headings and item style exactly. + * In this repo, preferred buckets are: + * `### New features` + * `### Improvements` + * `### Bug fixes` + * `### Documentation` + * `### Other changes` +2. Inspect the source of truth for scope and audience. + * Prefer PR title and PR description/summary over commit noise. + * Use linked issues to understand user-facing intent. + * Use commits only to confirm details or fill gaps. +3. Extract the primary shipped change. + * Lead with the API, control, command, or behavior that changed. + * Mention docs, examples, tests, refactors, or chores only when they are the main outcome the changelog audience would care about. +4. Write concise item(s) for the selected changelog(s). + * Avoid laundry lists unless the PR truly shipped multiple peer-level features. + * Prefer concrete nouns and verbs over implementation detail. + * Keep each sentence focused on what that changelog's audience gained or must know. +5. Add links and attribution in repo style. + * Include both related issue link(s) and PR link(s) when available, with issue links + first. + * If no issue exists, include PR link(s) only. + * Include issue-only direct-commit items when a shipped change has no PR. + * Use plain-text author attribution at the end: `by @login.` + * Use the PR author login for PR-based items. + * For issue-only direct-commit items, use the commit author login if available. + * If one item groups multiple PRs by different authors, attribute all relevant + authors: `by @user1, @user2.` + +## Repo-specific guidance + +* Do not mention tests in changelog items unless the change itself is test infrastructure. +* Use `### Documentation` for docs website, CrocoDocs, generated API reference, examples, + guides, or docs tooling changes when documentation is the primary deliverable. +* Do not mention docs/examples in other sections unless documentation is the primary deliverable. +* Avoid words like `refactor`, `cleanup`, or `coverage` unless the section is `Other changes` and that is truly the point. +* If a PR includes one main feature plus supporting docs/tests, write only the main feature. +* If a PR title is too narrow or too broad, use the PR description and diff to calibrate the final wording. +* If an item touches multiple controls, only group them when the change is one coherent feature. +* Do not add chore, trivial, or duplicate items to user-facing release notes. +* For extension package changelogs, prefer Python-facing API, behavior, packaging, and + usability changes over Flutter implementation details that are not directly published + to users. + +## Good patterns + +Root changelog: + +* `* Add \`scrollable\` to \`NavigationRail\` for overflowed destinations ([#1923](...), [#6356](...)) by @login.` +* `* Make \`NavigationDrawerDestination.label\` accept custom controls and add \`NavigationDrawerTheme.icon_theme\` ([#6379](...), [#6395](...)) by @login.` + +Flutter package changelog: + +* `* Improve \`parseBool()\` to accept string and numeric payload values ([#1234](...)) by @login.` +* `* Extend \`Control\` with \`.buildTextOrWidget()\` to parse properties that accept either strings or child controls ([#1234](...)) by @login.` +* `* Improve extension asset resolution to avoid package path collisions ([#1234](...)) by @login.` +* `* Add \`parseEnum()\` utility for consistent enum parsing ([#1234](...)) by @login.` + +## Checks + +Before finishing, verify: + +* The item sits under the right release and section. +* The wording matches neighboring entries in length and tone. +* The sentence describes the primary change for that changelog's audience. +* `packages/flet/CHANGELOG.md` entries are specific to Dart/Flutter package or + extension-facing behavior and are not bare repeats of root changelog entries. +* Issue and PR links follow repo style, including issue-only direct-commit cases. +* Attribution is plain text and placed last. diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 151c7b5a38..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,475 +0,0 @@ -version: 0.0.{build} - -skip_branch_with_pr: true - -skip_commits: - files: - - docs/**/* - - media/**/* - - "*.md" - -environment: - python_stack: python 3.12 - FLUTTER_VERSION: 3.29.3 - GITHUB_TOKEN: - secure: 9SKIwc3VSfYJ5IChvNR74qi9xlUYK71gpBEZQSL4ZiqOEIAultwlQo3tHiHGLS8tz+EQtwMXEoWvw1Bl4y7oImJiH7lPjqo+BZnD7fzj9jwUYdDrP0u/HcmTxLHedH2b - TWINE_USERNAME: __token__ - TWINE_PASSWORD: - secure: 174ncAbF5IjSIkmioPt62jeSnzmTlRNchUkE4QdjDWH8xK1olYtySXLJpo2q95HcP7lWJky1hv4APESiRRHnBWoY0XRFafzM/mbCDMzG1tZXiXZmpP1qzHAtRP2QSCIg18xh1TMktraUdTi7sbJnjjRhqzgbW1k0kLBxKw79MPFBhYQ/TiGcmaYWZbWVZNY3HCUCb6Dt7bG1OE2Ul9rD1gvs55xwO9Oq9FOVA1VnMYw= - TWINE_NON_INTERACTIVE: true - GEMFURY_TOKEN: - secure: trYGM65OQ1+HYnOYOe/NOHrofLpP3bz64nHwVWPJhiUIYll3MrrQd7ilFNp+zSkI - - matrix: - - job_name: Build Flet package for Flutter - job_group: build_flet_package - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu - - - job_name: Build Flet for Windows - job_group: build_flet - job_depends_on: build_flet_package - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 - - - job_name: Build Flet for macOS - job_group: build_flet - job_depends_on: build_flet_package - APPVEYOR_BUILD_WORKER_IMAGE: macos-monterey - - - job_name: Build Flet for Linux - job_group: build_flet_linux - job_depends_on: build_flet_package - ARCH: amd64 - PACKAGE_NAME: flet-desktop - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Build Flet Light for Linux - job_group: build_flet_linux - job_depends_on: build_flet_package - ARCH: amd64 - PACKAGE_NAME: flet-desktop-light - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Build Flet for Linux ARM64 - job_group: build_flet_linux - job_depends_on: build_flet_package - ARCH: arm64 - PACKAGE_NAME: flet-desktop - python_stack: python 3.10 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004-arm - - - job_name: Build Flet Light for Linux ARM64 - job_group: build_flet_linux - job_depends_on: build_flet_package - ARCH: arm64 - PACKAGE_NAME: flet-desktop-light - python_stack: python 3.10 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004-arm - - - job_name: Build Flet for web - job_group: build_flet - job_depends_on: build_flet_package - PYODIDE_URL: https://github.com/pyodide/pyodide/releases/download/0.27.5/pyodide-core-0.27.5.tar.bz2 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Test Python 3.9 - job_group: python_tests - python_stack: python 3.9 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Test Python 3.10 - job_group: python_tests - python_stack: python 3.10 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Test Python 3.11 - job_group: python_tests - python_stack: python 3.11 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Test Python 3.12 - job_group: python_tests - python_stack: python 3.12 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Test Python 3.13 - job_group: python_tests - python_stack: python 3.13 - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - - - job_name: Build Python wheels - job_group: python_build - job_depends_on: python_tests, build_flet, build_flet_linux - APPVEYOR_BUILD_WORKER_IMAGE: ubuntu2004 - -matrix: - fast_finish: true - -stack: $python_stack - -for: - # ====================================== - # Build Flet package for Flutter - # ====================================== - - - matrix: - only: - - job_name: Build Flet package for Flutter - - install: - - ps: | - if ($env:APPVEYOR_REPO_TAG_NAME) { - $env:PKG_VER = $env:APPVEYOR_REPO_TAG_NAME.replace("v", "") - } else { - $cv = [version](git describe --abbrev=0).substring(1) - $env:PKG_VER = "$($cv.major).$($cv.minor+1).0+$($env:APPVEYOR_BUILD_NUMBER)" - } - Update-AppveyorBuild -Version $env:PKG_VER - - python3 -m ensurepip --upgrade - - pip3 install --upgrade setuptools - - pip3 install pyyaml - - source ci/install_flutter.sh - - build_script: - - sh: | - if [[ "$APPVEYOR_REPO_TAG_NAME" != "" ]]; then - mkdir -p $HOME/.config/dart - echo $PUB_DEV_TOKEN | base64 --decode > $HOME/.config/dart/pub-credentials.json - - # patch pubspecs - for dir in packages/flet*; do - echo "Patching $dir/pubspec.yaml" - python3 ci/patch_pubspec.py $dir/pubspec.yaml $PKG_VER - done - - cd packages/flet - echo "Running flet tests" - flutter test || exit 1 - dart pub publish --force || exit 1 - cd $APPVEYOR_BUILD_FOLDER - - else - - cd packages/flet - echo "Running flet tests" - flutter test || exit 1 - dart pub publish --dry-run - cd $APPVEYOR_BUILD_FOLDER - - fi - - # ====================================== - # Build Flet Client for Windows - # ====================================== - - - matrix: - only: - - job_name: Build Flet for Windows - - install: - - python --version - - pip3 install --upgrade setuptools wheel twine tomlkit - - ps: irm https://astral.sh/uv/install.ps1 | iex - - ps: Add-SessionPath "$HOME\.local\bin" - - uv --version - - dart pub global activate fvm - - set PATH=%LOCALAPPDATA%\Pub\Cache\bin;%USERPROFILE%\fvm\default\bin;%PATH% - - fvm install %FLUTTER_VERSION% - - fvm global %FLUTTER_VERSION% - - flutter --version - - build_script: - - ps: $env:flet_sdk_root="$env:APPVEYOR_BUILD_FOLDER\sdk\python" - # patch version - - ps: | - $ErrorActionPreference = "Stop" - $env:PYPI_VER = $env:APPVEYOR_BUILD_VERSION.replace("+", ".dev") - $vp = "$env:flet_sdk_root/packages/flet-desktop/src/flet_desktop/version.py"; (Get-Content $vp).replace("version = `"`"", "version = `"$env:PYPI_VER`"") | Set-Content $vp - - python ci/patch_toml_versions.py %flet_sdk_root%/packages/flet-desktop/pyproject.toml %PYPI_VER% - - - cd client - - set RELEASE_DIR=build\windows\x64\runner\Release - - flutter build windows --build-name=%APPVEYOR_BUILD_VERSION% - - - copy "%WINDIR%\system32\msvcp140.dll" %RELEASE_DIR% - - copy "%WINDIR%\system32\vcruntime140.dll" %RELEASE_DIR% - - copy "%WINDIR%\system32\vcruntime140_1.dll" %RELEASE_DIR% - - dir %RELEASE_DIR% - - ren build\windows\x64\runner\Release flet - - cd build\windows\x64\runner - - 7z a flet-windows.zip flet - - mkdir %flet_sdk_root%\packages\flet-desktop\src\flet_desktop\app - - xcopy flet %flet_sdk_root%\packages\flet-desktop\src\flet_desktop\app\flet\ /s /e - - # build package - - cd %flet_sdk_root% - - uv build --wheel --package flet-desktop - - ps: | - $ErrorActionPreference = "Continue" - Get-ChildItem -Path dist/*-py3-none-any.whl | ForEach-Object { - python $env:APPVEYOR_BUILD_FOLDER\ci\repackage_wheel_with_tag.py $_.FullName "py3-none-win_amd64" - python $env:APPVEYOR_BUILD_FOLDER\ci\repackage_wheel_with_tag.py $_.FullName "py3-none-win32" - Remove-Item $_.FullName - } - $ErrorActionPreference = "Stop" - - dir dist - - # publish - - ps: | - if (($env:APPVEYOR_REPO_BRANCH -eq "main" -or $env:APPVEYOR_REPO_TAG_NAME) -and (-not $env:APPVEYOR_PULL_REQUEST_NUMBER)) { - twine upload $env:flet_sdk_root\dist\* - } elseif (-not $env:APPVEYOR_PULL_REQUEST_NUMBER) { - $wheels = (Get-ChildItem $env:flet_sdk_root/dist/*.whl | Select-Object -ExpandProperty FullName) - foreach ($wheel in $wheels) { - curl.exe -sF package=@$wheel https://$env:GEMFURY_TOKEN@push.fury.io/flet/ - } - } - - test: off - - artifacts: - - path: client\build\windows\x64\runner\flet-windows.zip - - path: sdk\python\packages\*.whl - - deploy: - provider: GitHub - auth_token: $(GITHUB_TOKEN) - release: $(APPVEYOR_REPO_TAG_NAME) - on: - APPVEYOR_REPO_TAG: true - - # ====================================== - # Build Flet Client for macOS - # ====================================== - - - matrix: - only: - - job_name: Build Flet for macOS - - install: - - . ci/common.sh - - HOMEBREW_NO_AUTO_UPDATE=1 brew install cocoapods - - source ci/install_flutter.sh - - build_script: - # Flutter macOS client - - pushd client - - flutter build macos --build-name=$APPVEYOR_BUILD_VERSION - - tar -czvf flet-macos.tar.gz -C build/macos/Build/Products/Release Flet.app - - mkdir -p $flet_sdk_root/packages/flet-desktop/src/flet_desktop/app - - cp flet-macos.tar.gz $flet_sdk_root/packages/flet-desktop/src/flet_desktop/app - - popd - - # Python package - - patch_python_package_versions - - # build package - - cd $flet_sdk_root - - uv build --wheel --package flet-desktop - - sh: | - for file in dist/*-py3-none-any.whl; do - python $root/ci/repackage_wheel_with_tag.py $file "py3-none-macosx_12_0_arm64" - python $root/ci/repackage_wheel_with_tag.py $file "py3-none-macosx_10_14_x86_64" - rm $file - done - - # publish - - publish_to_pypi dist/*.whl - - artifacts: - - path: client/flet-macos.tar.gz - - path: sdk/python/dist/*.whl - - deploy: - provider: GitHub - auth_token: $(GITHUB_TOKEN) - release: $(APPVEYOR_REPO_TAG_NAME) - on: - APPVEYOR_REPO_TAG: true - - # ====================================== - # Build Flet Client for Linux - # ====================================== - - - matrix: - only: - - job_group: build_flet_linux - - install: - - . ci/common.sh - - sudo apt update --allow-releaseinfo-change - - sudo apt install -y clang libgtk-3-dev - - sh: | - if [[ "$PACKAGE_NAME" == "flet-desktop" ]]; then - sudo apt install -y libmpv-dev mpv libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio - fi - - sh: | - if [[ "$ARCH" == "arm64" ]]; then - git clone https://github.com/flutter/flutter.git -b stable "$HOME/flutter" - export PATH="$PATH:$HOME/flutter/bin" - fi - - source ci/install_flutter.sh - - build_script: - - pushd client - - sh: | - wheel_tags=( - "py3-none-manylinux_2_17_{arch},py3-none-manylinux2014_{arch}" - "py3-none-musllinux_1_2_{arch}" - ) - if [[ "$ARCH" == "amd64" ]]; then - build_arch="x64" - platform_arch="x86_64" - - else - build_arch="arm64" - platform_arch="aarch64" - fi - - - sh: | - if [[ "$PACKAGE_NAME" == "flet-desktop-light" ]]; then - sed -i '/--FAT_CLIENT_START--/,/--FAT_CLIENT_END--/d' pubspec.yaml - sed -i '/--FAT_CLIENT_START--/,/--FAT_CLIENT_END--/d' lib/main.dart - patch_flet_desktop_package_name "flet-desktop-light" - artifact_suffix="-light" - fi - - flutter build linux --build-name=$APPVEYOR_BUILD_VERSION - - mv build/linux/$build_arch/release/bundle build/linux/$build_arch/release/flet - - tar -czvf flet-linux$artifact_suffix-$ARCH.tar.gz -C build/linux/$build_arch/release flet - - mkdir -p $flet_sdk_root/packages/flet-desktop/src/flet_desktop/app - - cp flet-linux$artifact_suffix-$ARCH.tar.gz $flet_sdk_root/packages/flet-desktop/src/flet_desktop/app/flet-linux-$ARCH.tar.gz - - popd - - # Python package - - patch_python_package_versions - - # build package - - cd $flet_sdk_root - - sh: | - if [[ "$PACKAGE_NAME" == "flet-desktop-light" ]]; then - sed -i 's/flet-desktop/flet-desktop-light/g' pyproject.toml - fi - - uv build --wheel --package $PACKAGE_NAME - - sh: | - for file in dist/*-py3-none-any.whl; do - for tag in "${wheel_tags[@]}"; do - wheel_tag=$(echo "$tag" | sed "s/{arch}/$platform_arch/g") - python $root/ci/repackage_wheel_with_tag.py $file $wheel_tag - done - rm "$file" - done - - # publish - - publish_to_pypi dist/*.whl - - artifacts: - - path: client/flet-linux-*.tar.gz - - path: sdk/python/dist/*.whl - - deploy: - provider: GitHub - auth_token: $(GITHUB_TOKEN) - release: $(APPVEYOR_REPO_TAG_NAME) - on: - APPVEYOR_REPO_TAG: true - - # ====================================== - # Build Flet for web - # ====================================== - - - matrix: - only: - - job_name: Build Flet for web - - install: - - . ci/common.sh - - source ci/install_flutter.sh - - build_script: - # Flutter Web client - - pushd client - - flutter build web --release - - rm -rf build/web/canvaskit - - cp -R build/web $flet_sdk_root/packages/flet-web/src/flet_web - # fix on mobile Safari: https://github.com/flutter/flutter/issues/145111#issuecomment-2714599139 - - ls "$(dirname "$(command -v flutter)")/cache/flutter_web_sdk/flutter_js" - - cp "$(dirname "$(command -v flutter)")/cache/flutter_web_sdk/flutter_js/flutter.js.map" $flet_sdk_root/packages/flet-web/src/flet_web/web - - curl -L $PYODIDE_URL | tar -xj -C "$flet_sdk_root/packages/flet-web/src/flet_web/web" - - popd - - tar -czvf client/build/flet-web.tar.gz -C client/build/web . - - # Python package - - patch_python_package_versions - - # build package - - cd $flet_sdk_root - - uv build --wheel --package flet-web - - # publish - - publish_to_pypi dist/*.whl - - artifacts: - - path: client/build/flet-web.tar.gz - - path: sdk/python/dist/*.whl - - deploy: - provider: GitHub - auth_token: $(GITHUB_TOKEN) - release: $(APPVEYOR_REPO_TAG_NAME) - on: - APPVEYOR_REPO_TAG: true - - ###################### - # Python Tests # - ###################### - - matrix: - only: - - job_group: python_tests - - install: - - python --version - - cd sdk/python - - python -m ensurepip --upgrade - - pip3 install --upgrade setuptools pip - - curl -LsSf https://astral.sh/uv/install.sh | sh - - export PATH="$HOME/.local/bin:$PATH" - - build: off - - test_script: - - uv run pytest - - ###################### - # Python Build # - ###################### - - matrix: - only: - - job_group: python_build - - install: - - . ci/common.sh - - test: off - - build_script: - - patch_python_package_versions - - # build packages - - cd $flet_sdk_root - - uv build --wheel --package flet-cli - - uv build --wheel --package flet - - # update deps - - python $root/ci/update-flet-wheel-deps.py dist - - # publish packages - - publish_to_pypi dist/*.whl - - artifacts: - - path: sdk/python/dist/*.whl - - deploy: - provider: GitHub - auth_token: $(GITHUB_TOKEN) - release: $(APPVEYOR_REPO_TAG_NAME) - on: - APPVEYOR_REPO_TAG: true \ No newline at end of file diff --git a/.fvmrc b/.fvmrc new file mode 100644 index 0000000000..94d87f3405 --- /dev/null +++ b/.fvmrc @@ -0,0 +1,3 @@ +{ + "flutter": "3.41.7" +} diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.yml b/.github/ISSUE_TEMPLATE/01_bug_report.yml index 35f49f364e..4f6b82e3cb 100644 --- a/.github/ISSUE_TEMPLATE/01_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/01_bug_report.yml @@ -1,5 +1,7 @@ name: Bug Report description: "You found a bug in Flet causing your application to crash or behave abnormally? Help us know more about it by providing as much details as possible." +title: "bug: " +labels: ["bug"] body: - type: markdown @@ -32,21 +34,21 @@ body: description: | Please create a minimal reproducible and runnable sample that shows the problem and attach it below between the lines with the backticks. - + Alternatively, you can create a public GitHub repository or use an existing one to share your sample. - + Without this we will unlikely be able to progress on the issue, and because of that we regretfully will have to close it. - + Note: Please do not upload screenshots of text. Instead, use code blocks or the above mentioned ways to upload your code sample. value: |
Code - + ```python [Paste your code here] ``` - +
validations: required: true @@ -74,9 +76,9 @@ body: value: |
Captures - + [Upload media here] - +
validations: required: false @@ -84,7 +86,7 @@ body: id: "os" attributes: label: "Operating System" - multiple: false + multiple: true options: - macOS - Linux @@ -102,7 +104,7 @@ body: id: "flet-version" attributes: label: "Flet version" - description: "run `pip show flet` in your terminal to view your Flet version" + description: "Tip: you can run `flet doctor` or `pip show flet` in your terminal to view your Flet version." validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/02_feature_request.yml b/.github/ISSUE_TEMPLATE/02_feature_request.yml index 66223fae45..33fa9206d1 100644 --- a/.github/ISSUE_TEMPLATE/02_feature_request.yml +++ b/.github/ISSUE_TEMPLATE/02_feature_request.yml @@ -1,5 +1,7 @@ name: Feature Request -description: "You are about to create a feature request in Flet. We'd appreciate if you'd first search through our open issues and docs, to make sure the issue isn't already known." +description: "Suggest a new feature to be added to Flet." +title: "feature: " +labels: ["feature request"] body: - type: checkboxes @@ -22,11 +24,11 @@ body: label: "Suggest a solution" description: "Share with us your idea on how to solve the problem. If you have multiple solutions, please present each one separately." placeholder: "A concise description of your preferred solution. Things to address include: - + * Details of the technical implementation, e.g. Flutter widget solving the problem. * Tradeoffs made in design decisions * Caveats and considerations for the future - + If there are multiple solutions, please present each one separately. Save comparisons for the very end." - type: textarea id: "screenshots" @@ -42,5 +44,3 @@ body: description: "Add any other detail about the request here." validations: required: false - - diff --git a/.github/ISSUE_TEMPLATE/03_docs.yml b/.github/ISSUE_TEMPLATE/03_docs.yml new file mode 100644 index 0000000000..d5d842c314 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/03_docs.yml @@ -0,0 +1,39 @@ +name: Documentation update +about: Found some unclear, missing or outdated documentation? +title: "docs: " +labels: ["documentation"] + +body: + - type: textarea + id: "description" + attributes: + label: "Description" + description: "Is something unclear, missing or outdated in our documentation?" + placeholder: Tell us what feature you want... + validations: + required: true + + - type: textarea + id: "link" + attributes: + label: "Relevant documentation sections" + description: "Add a link to the relevant section of our documentation, or any addition context." + placeholder: https://flet.dev/docs/... + validations: + required: false + + - type: textarea + id: "code-snippet" + attributes: + label: "Relevant code snippets" + description: "If the documentation issue is related to code, please provide relevant code snippets here." + value: | +
Code + + ```python + [Paste your code here] + ``` + +
+ validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f9d7357d34..42c82b5fdb 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,7 +2,7 @@ blank_issues_enabled: true contact_links: - name: Flet Discord server url: https://discord.gg/dzWXP8SHG8 - about: Join our Discord server to chat with the community and the dev-team, with faster response times. + about: Join our interactive Discord server to chat with the community and the dev-team, with faster response times. - name: Flet Discussions url: https://github.com/flet-dev/flet/discussions about: Open a discussion to ask questions, share ideas, and connect with other community members. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7f1aa61dd8..14350e670e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -24,12 +24,13 @@ - [ ] I signed the CLA. - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code +- [ ] If this PR targets a `release/*` branch, I added a new record to the active root `CHANGELOG.md` section - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] My changes generate no new warnings - [ ] New and existing tests pass locally with my changes - [ ] I have made corresponding changes to the [documentation](https://github.com/flet-dev/website) (if applicable) -## Screenshots +## Screenshots diff --git a/.github/scripts/build_docs.sh b/.github/scripts/build_docs.sh new file mode 100644 index 0000000000..4eba3ec3ae --- /dev/null +++ b/.github/scripts/build_docs.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +# install uv +pip install uv + +# generate coverage report and badges +cd sdk/python +for pkg in packages/*; do + if [ -f "$pkg/pyproject.toml" ] && [ -d "$pkg/src" ]; then + pkg_name=$(basename "$pkg") + echo "====== $pkg ======" + uv run --group docs-coverage docstr-coverage -C .docstr.yaml "$pkg/src" \ + --badge="../../website/static/docs/assets/badges/docs-coverage/${pkg_name}.svg" + echo + fi +done +cd - + +# build website (includes verification checks via `yarn build`) +cd website +yarn install +yarn build +cd - diff --git a/.github/scripts/check_docs.py b/.github/scripts/check_docs.py new file mode 100644 index 0000000000..d2ea2387fb --- /dev/null +++ b/.github/scripts/check_docs.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +"""Check built Docusaurus docs for broken images, unresolved xrefs, and missing examples.""" + +import glob +import os +import re +import sys + + +def check_broken_images(build_dir: str) -> list[str]: + img_re = re.compile(r']+src="(/[^"]+)"', re.IGNORECASE) + errors = [] + for html_file in sorted( + glob.glob(f"{build_dir}/docs/**/index.html", recursive=True) + ): + page = ( + html_file.replace(build_dir + "/", "").replace("/index.html", "") + ) + content = open(html_file).read() + for match in img_re.finditer(content): + src = match.group(1) + if src.startswith("http") or src.startswith("data:"): + continue + file_path = os.path.join(build_dir, src.lstrip("/")) + if not os.path.exists(file_path): + errors.append(f" {page}: {src}") + return errors + + +def check_pattern(build_dir: str, pattern: str) -> list[str]: + errors = [] + for html_file in sorted( + glob.glob(f"{build_dir}/docs/**/index.html", recursive=True) + ): + content = open(html_file).read() + if pattern in content: + page = ( + html_file.replace(build_dir + "/", "") + .replace("/index.html", "") + ) + errors.append(f" {page}") + return errors + + +def check_unresolved_xrefs(build_dir: str) -> list[str]: + xref_re = re.compile(r":(?:attr|class|meth|func|data|mod|obj):") + errors = [] + for html_file in sorted( + glob.glob(f"{build_dir}/docs/**/index.html", recursive=True) + ): + content = open(html_file).read() + if xref_re.search(content): + page = ( + html_file.replace(build_dir + "/", "") + .replace("/index.html", "") + ) + errors.append(f" {page}") + return errors + + +def main() -> int: + build_dir = sys.argv[1] if len(sys.argv) > 1 else "website/build" + failed = False + + checks = [ + ("Checking broken images", lambda: check_broken_images(build_dir)), + ( + "Checking unresolved reST cross-references", + lambda: check_unresolved_xrefs(build_dir), + ), + ( + "Checking missing code examples", + lambda: check_pattern(build_dir, "Missing code example for"), + ), + ( + "Checking missing API entries", + lambda: check_pattern(build_dir, "Missing API entry for"), + ), + ] + + for label, check_fn in checks: + print(f"=== {label} ===") + errors = check_fn() + if errors: + print(f"FAILED: {len(errors)} issues found:") + print("\n".join(errors)) + failed = True + else: + print("OK") + print() + + if failed: + print("=== CHECKS FAILED ===") + return 1 + else: + print("=== All checks passed ===") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/scripts/check_docs.sh b/.github/scripts/check_docs.sh new file mode 100755 index 0000000000..73b6aac144 --- /dev/null +++ b/.github/scripts/check_docs.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail + +BUILD_DIR="${1:-website/build}" + +python3 .github/scripts/check_docs.py "$BUILD_DIR" diff --git a/.github/scripts/clean-pypi.sh b/.github/scripts/clean-pypi.sh new file mode 100644 index 0000000000..135da63195 --- /dev/null +++ b/.github/scripts/clean-pypi.sh @@ -0,0 +1,25 @@ +# set PYPI_CLEANUP_PASSWORD with pypi.org password + +VER="0\.8[12]\.3\.dev(?!7200)" +uv tool install pypi-cleanup +uvx pypi-cleanup -u flet -p flet -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-cli -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-desktop -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-web -y -r $VER --do-it + +# modules +uvx pypi-cleanup -u flet -p flet-ads -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-audio -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-audio-recorder -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-charts -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-color-pickers -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-datatable2 -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-flashlight -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-geolocator -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-lottie -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-map -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-permission-handler -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-rive -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-secure-storage -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-video -y -r $VER --do-it +uvx pypi-cleanup -u flet -p flet-webview -y -r $VER --do-it diff --git a/.github/scripts/common.ps1 b/.github/scripts/common.ps1 new file mode 100644 index 0000000000..521b880b9a --- /dev/null +++ b/.github/scripts/common.ps1 @@ -0,0 +1,96 @@ +function Start-ProcessWithOutput { + param( + $command, + [switch]$ignoreExitCode, + [switch]$ignoreStdOut + ) + $fileName = $command + $arguments = $null + + if ($command.startsWith('"')) { + $idx = $command.indexOf('"', 1) + $fileName = $command.substring(1, $idx - 1) + if ($idx -lt ($command.length - 2)) { + $arguments = $command.substring($idx + 2) + } + } + else { + $idx = $command.indexOf(' ') + if ($idx -ne -1) { + $fileName = $command.substring(0, $idx) + $arguments = $command.substring($idx + 1) + } + } + + # find tool in path + if (-not (Test-Path $fileName)) { + foreach ($pathPart in $($env:PATH).Split(';')) { + $searchPath = [IO.Path]::Combine($pathPart, "$fileName.bat") + if (Test-Path $searchPath) { + $fileName = $searchPath; break; + } + $searchPath = [IO.Path]::Combine($pathPart, "$fileName.cmd") + if (Test-Path $searchPath) { + $fileName = $searchPath; break; + } + $searchPath = [IO.Path]::Combine($pathPart, "$fileName.exe") + if (Test-Path $searchPath) { + $fileName = $searchPath; break; + } + $searchPath = [IO.Path]::Combine($pathPart, $fileName) + if (Test-Path $searchPath) { + $fileName = $searchPath; break; + } + } + } + + $psi = New-Object System.Diagnostics.ProcessStartInfo + $psi.FileName = $fileName + $psi.RedirectStandardError = $true + $psi.RedirectStandardOutput = $true + $psi.CreateNoWindow = $true + $psi.UseShellExecute = $false + $psi.Arguments = $arguments + $psi.WorkingDirectory = (pwd).Path + $process = New-Object System.Diagnostics.Process + $process.StartInfo = $psi + + # Adding event handers for stdout and stderr. + $outScripBlock = { + if (![String]::IsNullOrEmpty($EventArgs.Data)) { + Write-Host "$($EventArgs.Data)" + } + } + $errScripBlock = { + if (![String]::IsNullOrEmpty($EventArgs.Data)) { + Write-Host "$($EventArgs.Data)" -ForegroundColor Red + } + } + + if ($ignoreStdOut -eq $false) { + $stdOutEvent = Register-ObjectEvent -InputObject $process -Action $outScripBlock -EventName 'OutputDataReceived' + } + $stdErrEvent = Register-ObjectEvent -InputObject $process -Action $errScripBlock -EventName 'ErrorDataReceived' + + try { + $process.Start() | Out-Null + + $process.BeginOutputReadLine() + $process.BeginErrorReadLine() + [Void]$process.WaitForExit() + + # Unregistering events to retrieve process output. + if ($ignoreStdOut -eq $false) { + Unregister-Event -SourceIdentifier $stdOutEvent.Name + } + Unregister-Event -SourceIdentifier $stdErrEvent.Name + + if ($ignoreExitCode -eq $false -and $process.ExitCode -ne 0) { + exit $process.ExitCode + } + } + catch { + Write-Host "Error running '$($psi.FileName) $($psi.Arguments)' command: $($_.Exception.Message)" -ForegroundColor Red + throw $_ + } +} diff --git a/.github/scripts/common.sh b/.github/scripts/common.sh new file mode 100644 index 0000000000..4e43f4c781 --- /dev/null +++ b/.github/scripts/common.sh @@ -0,0 +1,39 @@ +function patch_python_package_versions() ( + set -euo pipefail + cd "$SDK_PYTHON" || exit 1 + + # Install dependencies + uv sync --no-default-groups || true + + # Update package versions in version.py and pyproject.toml files + for pkg in flet flet-cli flet-desktop flet-web; do + version_py="packages/$pkg/src/${pkg//-/_}/version.py" + if [[ -f "$version_py" ]]; then + sed -i -e "s/^flet_version = \"\"/flet_version = \"$PYPI_VER\"/g" "$version_py" + sed -i -e "s/^version = \"\"/version = \"$PYPI_VER\"/g" "$version_py" + else + echo "Skipping version patch: $version_py not found" + fi + uv version --package "$pkg" "$PYPI_VER" + uv run "$SCRIPTS/patch_toml_versions.py" "packages/$pkg/pyproject.toml" "$PYPI_VER" + echo "Patched version for $pkg to $PYPI_VER" + done + + # Get Flutter version from .fvmrc and set it in version.py + FLUTTER_VERSION="$( uv run "$SCRIPTS/read_fvmrc.py" "${ROOT}/.fvmrc" )" + sed -i -e "s/^flutter_version = \"\"/flutter_version = \"$FLUTTER_VERSION\"/g" packages/flet/src/flet/version.py + echo "Patched Flutter SDK version to $FLUTTER_VERSION" +) + + +repackage_wheel_with_tag() { + uv run "$SCRIPTS/repackage_wheel_with_tag.py" "$@" +} + +patch_toml_versions() { + uv run "$SCRIPTS/patch_toml_versions.py" "$@" +} + +patch_pubspec_version() { + uv run "$SCRIPTS/patch_pubspec_version.py" "$@" +} diff --git a/ci/download-web.py b/.github/scripts/download_web.py similarity index 100% rename from ci/download-web.py rename to .github/scripts/download_web.py diff --git a/.github/scripts/generate_icons.py b/.github/scripts/generate_icons.py new file mode 100644 index 0000000000..e75522ef30 --- /dev/null +++ b/.github/scripts/generate_icons.py @@ -0,0 +1,110 @@ +# /// script +# dependencies = [ +# "requests", +# "Jinja2", +# ] +# /// + +import json +import re +from pathlib import Path + +import requests +from jinja2 import Environment, FileSystemLoader + +# Regex for parsing icon definitions (handles multi-line IconData) +ICON_VAR_PATTERN = re.compile( + r"""^\s*static const IconData\s+(\w+)\s*=""", re.MULTILINE +) + +file_loader = FileSystemLoader(Path(__file__).parent / "templates") +templates = Environment(loader=file_loader) + + +def download_dart_file(url: str) -> str: + print(f"Downloading Dart file from: {url}") + response = requests.get(url) + response.raise_for_status() + return response.text + + +def parse_dart_icons(dart_content: str, set_id: int): + # Extract and sort icon names alphabetically + icon_names = sorted(ICON_VAR_PATTERN.findall(dart_content)) + + icons = [] + for i, icon_name in enumerate(icon_names): + packed_value = (set_id << 16) | i + icons.append((icon_name, packed_value)) + + print(f"🔍 Found {len(icons)} icons for set ID {set_id} (sorted).") + return icons + + +def generate_file(icons, template_name, output_file: str): + template = templates.get_template(template_name) + with open( + Path(__file__).parent.joinpath(output_file).resolve(), "w", encoding="utf-8" + ) as f: + f.write(template.render(icons=icons)) + print(f"✅ File written to {output_file}") + + +def generate_json(icons, output_file: str): + payload = {name.upper(): value for name, value in icons} + output_path = Path(__file__).parent.joinpath(output_file).resolve() + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(json.dumps(payload, separators=(",", ":")), encoding="utf-8") + print(f"✅ JSON written to {output_file}") + + +def main(): + # material icons + url = "https://raw.githubusercontent.com/flutter/flutter/refs/heads/stable/packages/flutter/lib/src/material/icons.dart" + set_id = 1 + dart_content = download_dart_file(url) + icons = parse_dart_icons(dart_content, set_id) + + generate_file( + icons, + "material_icons.dart", + "../../packages/flet/lib/src/utils/material_icons.dart", + ) + + generate_file( + icons, + "material_icons.pyi", + "../../sdk/python/packages/flet/src/flet/controls/material/icons.pyi", + ) + + generate_json( + icons, + "../../sdk/python/packages/flet/src/flet/controls/material/icons.json", + ) + + # cupertino icons + url = "https://raw.githubusercontent.com/flutter/flutter/refs/heads/stable/packages/flutter/lib/src/cupertino/icons.dart" + set_id = 2 + dart_content = download_dart_file(url) + icons = parse_dart_icons(dart_content, set_id) + + generate_file( + icons, + "cupertino_icons.dart", + "../../packages/flet/lib/src/utils/cupertino_icons.dart", + ) + + generate_file( + icons, + "cupertino_icons.pyi", + "../../sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.pyi", + ) + + generate_json( + icons, + "../../sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.json", + ) + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/patch_pubspec_version.py b/.github/scripts/patch_pubspec_version.py new file mode 100644 index 0000000000..1d3c48f3e2 --- /dev/null +++ b/.github/scripts/patch_pubspec_version.py @@ -0,0 +1,118 @@ +# /// script +# dependencies = ["pyyaml"] +# /// + +""" +Patches a Dart/Flutter `pubspec.yaml` file to: + - Optionally set the `version:` field to a given value. + - Pin selected dependencies in `dependencies:` and `dependency_overrides:`. + +Dependencies patched: + - flet + +Usage: + # Pin to a version: + uv run patch_pubspec_version.py [--dependencies-only] [--exact] + + # Pin to a git commit: + uv run patch_pubspec_version.py --dependencies-only \ + --git-ref --git-url --git-path + +Arguments: + pubspec Path to the pubspec.yaml file to patch. + version Version string to set (not required with --git-ref). + --dependencies-only Patch only dependencies without changing package `version:`. + --exact Pin to exact version (no ^ caret). Use for apps/templates. + --git-ref Pin flet dependency to a git commit SHA. + --git-url Git repository URL (used with --git-ref). + --git-path Path within the git repo (used with --git-ref). +""" + +import argparse +import sys +from pathlib import Path + +import yaml + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Patch pubspec version and/or selected dependencies." + ) + parser.add_argument("pubspec", help="Path to pubspec.yaml") + parser.add_argument("version", nargs="?", default=None, help="Version string to apply") + parser.add_argument( + "--dependencies-only", + action="store_true", + help="Patch only dependencies without changing package version.", + ) + parser.add_argument( + "--exact", + action="store_true", + help="Pin to exact version (no ^ caret). Use for apps/templates.", + ) + parser.add_argument( + "--git-ref", + help="Pin flet dependency to a git commit SHA.", + ) + parser.add_argument( + "--git-url", + help="Git repository URL (used with --git-ref).", + ) + parser.add_argument( + "--git-path", + help="Path within the git repo (used with --git-ref).", + ) + args = parser.parse_args() + + if not args.git_ref and not args.version: + parser.error("either version or --git-ref is required") + + pubspec_path = Path(args.pubspec).resolve() + + if not pubspec_path.exists(): + print(f"Error: File not found: {pubspec_path}") + sys.exit(1) + + with pubspec_path.open(encoding="utf-8") as f: + data = yaml.safe_load(f) + + if args.git_ref: + # Pin flet to a git commit + def make_git_dep(): + d = {"git": {"url": args.git_url, "ref": args.git_ref}} + if args.git_path: + d["git"]["path"] = args.git_path + return d + + print(f"Patching {pubspec_path} with git ref {args.git_ref[:12]}") + + for dep in ["flet"]: + if dep in data.get("dependencies", {}): + data["dependencies"][dep] = make_git_dep() + if dep in data.get("dependency_overrides", {}): + data["dependency_overrides"][dep] = make_git_dep() + else: + version = args.version + print(f"Patching {pubspec_path} with version {version}") + + # patch version + if not args.dependencies_only: + data["version"] = version + + # patch dependencies and dependency_overrides + pin = version if args.exact else f"^{version}" + for dep in ["flet"]: + if dep in data.get("dependencies", {}): + data["dependencies"][dep] = pin + if dep in data.get("dependency_overrides", {}): + data["dependency_overrides"][dep] = pin + + with pubspec_path.open("w", encoding="utf-8") as f: + yaml.dump(data, f, sort_keys=False) + + print(f"Successfully patched {pubspec_path}") + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/patch_toml_versions.py b/.github/scripts/patch_toml_versions.py new file mode 100644 index 0000000000..32723993f4 --- /dev/null +++ b/.github/scripts/patch_toml_versions.py @@ -0,0 +1,94 @@ +# /// script +# dependencies = ["tomlkit"] +# /// + +"""Patch TOML package versions and pin internal flet dependencies. + +This script updates: + - `[project].version` + - Internal flet dependencies in `[project].dependencies` + - Internal flet dependencies in `[project].optional-dependencies` + +Usage: + uv run patch_toml_versions.py +""" + +import sys +from pathlib import Path +import re + +import tomlkit + + +INTERNAL_DEPS = { + "flet", + "flet-cli", + "flet-desktop", + "flet-web", +} +REQ_RE = re.compile( + r"^(?P[A-Za-z0-9][A-Za-z0-9._-]*)(?P[^;]*)?(?P\s*;.*)?$" +) + + +def patch_dependency(req: str, version: str) -> str: + """Pin a single requirement string if it references an internal flet package.""" + m = REQ_RE.match(req.strip()) + if not m: + return req + + name = m.group("name") + if name not in INTERNAL_DEPS: + return req + + marker = m.group("marker") or "" + if marker: + return f"{name}=={version}{marker}" + return f"{name}=={version}" + + +def patch_dependency_list(deps: list[str], version: str) -> None: + """Patch dependencies list in-place.""" + for i, dep in enumerate(deps): + deps[i] = patch_dependency(dep, version) + + +def main() -> None: + if not (len(sys.argv) >= 3): + print("Usage: uv run patch_toml_versions.py ") + sys.exit(1) + + toml_path = Path(sys.argv[1]).resolve() + version = sys.argv[2] + + if not toml_path.exists(): + print(f"Error: File not found: {toml_path}") + sys.exit(1) + + print(f"Patching TOML file {toml_path} to version {version}") + + # read + with toml_path.open(encoding="utf-8") as f: + t = tomlkit.parse(f.read()) + + # patch version + t["project"]["version"] = version + + # patch dependencies + deps: list[str] = t["project"].get("dependencies", []) + patch_dependency_list(deps, version) + + # patch optional dependencies + optional = t["project"].get("optional-dependencies", {}) + for _, opt_deps in optional.items(): + patch_dependency_list(opt_deps, version) + + # save + with toml_path.open("w", encoding="utf-8") as f: + f.write(tomlkit.dumps(t)) + + print(f"Successfully patched TOML file {toml_path} to version {version}") + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/read_fvmrc.py b/.github/scripts/read_fvmrc.py new file mode 100644 index 0000000000..75d8421c29 --- /dev/null +++ b/.github/scripts/read_fvmrc.py @@ -0,0 +1,25 @@ +""" +Reads the Flutter version from a .fvmrc file and prints it. + +Usage: + uv run read_fvmrc.py +""" + +import json +import sys + + +def main() -> None: + try: + with open(sys.argv[1], encoding="utf-8") as f: + v = json.load(f)["flutter"].strip() + if not v: + raise ValueError("Empty or missing 'flutter' value") + print(v) + except Exception as e: + print(f"Error parsing {sys.argv[1]!r}: {e}", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/repackage_wheel_with_tag.py b/.github/scripts/repackage_wheel_with_tag.py new file mode 100644 index 0000000000..842a755211 --- /dev/null +++ b/.github/scripts/repackage_wheel_with_tag.py @@ -0,0 +1,80 @@ +# /// script +# requires-python = ">3.10" +# dependencies = ["wheel"] +# /// + +""" +Unpacks a wheel file, modifies its `.dist-info/WHEEL` metadata to set a new +tag, and repacks it in place. + +The original wheel is not deleted, but a new wheel with the modified metadata +is written alongside it. + +Typical use case: adjusting a wheel's supported tags (e.g. from "py3-none-any" +to platform-specific tags). + +Steps: + 1. Unpack the given wheel into a temporary directory. + 2. Rewrite the `Tag:` lines in `*.dist-info/WHEEL`. + 3. Repack the wheel into the same directory as the original. + +Usage: + uv run repackage_wheel_with_tag.py + +Arguments: + wheel_file Path to the `.whl` file. + new_tag Comma-separated list of tags (e.g., "cp310-cp310-manylinux_x86_64,cp310-cp310-win_amd64"). +""" + +import sys +import tempfile +from pathlib import Path + +import wheel._commands.pack +import wheel._commands.unpack + + +def repackage_wheel(wheel_path: str, new_tag: str) -> None: + wheel_path = Path(wheel_path).resolve() + print(f"Re-packaging wheel {wheel_path} with tag(s): {new_tag}") + + with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tmp_dir: + tmp_dir_path = Path(tmp_dir) + + # Unpack the wheel file + wheel._commands.unpack.unpack(str(wheel_path), tmp_dir) + + # Find the unpacked wheel directory + wheel_dirs = list(tmp_dir_path.glob("flet_*")) + if not wheel_dirs: + raise FileNotFoundError("Unpacked wheel directory not found.") + wheel_dir = wheel_dirs[0].resolve() + print(f"Wheel temp dir: {wheel_dir}") + + # Update WHEEL metadata file(s) + for metadata_file in wheel_dir.glob("*.dist-info/WHEEL"): + content = metadata_file.read_text(encoding="utf-8") + new_content = content.replace( + "Tag: py3-none-any", + "\n".join([f"Tag: {t}" for t in new_tag.split(",")]), + ) + metadata_file.write_text(new_content, encoding="utf-8") + print(f"Updated tags in {metadata_file}:\n{new_content}") + + # Repack the wheel + wheel._commands.pack.pack(str(wheel_dir), str(wheel_path.parent), None) + + print(f"Successfully generated wheel with new tag(s): {new_tag}") + + +def main() -> None: + if not (len(sys.argv) >= 3): + print("Usage: uv run repackage_wheel_with_tag.py ") + sys.exit(1) + + wheel_file, new_tag = sys.argv[1], sys.argv[2] + repackage_wheel(wheel_file, new_tag) + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/templates/cupertino_icons.dart b/.github/scripts/templates/cupertino_icons.dart new file mode 100644 index 0000000000..ac7eb8f2e8 --- /dev/null +++ b/.github/scripts/templates/cupertino_icons.dart @@ -0,0 +1,7 @@ +import 'package:flutter/cupertino.dart'; + +List cupertinoIcons = [ + {% for name, code in icons -%} + CupertinoIcons.{{ name }}, + {% endfor -%} +]; diff --git a/.github/scripts/templates/cupertino_icons.pyi b/.github/scripts/templates/cupertino_icons.pyi new file mode 100644 index 0000000000..0798f4d8ac --- /dev/null +++ b/.github/scripts/templates/cupertino_icons.pyi @@ -0,0 +1,18 @@ +""" +Flet Cupertino Icons Stub + +To generate/update this file run from the root of the repository: + +``` +uv run .github/scripts/generate_icons.py +``` +""" + +from flet.controls.icon_data import IconData + +__all__ = ["CupertinoIcons"] + +class CupertinoIcons: + {% for name, code in icons -%} + {{ name.upper() }}: IconData + {% endfor -%} diff --git a/.github/scripts/templates/material_icons.dart b/.github/scripts/templates/material_icons.dart new file mode 100644 index 0000000000..7065fb25db --- /dev/null +++ b/.github/scripts/templates/material_icons.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; + +List materialIcons = [ + {% for name, code in icons -%} + Icons.{{ name }}, + {% endfor -%} +]; diff --git a/.github/scripts/templates/material_icons.pyi b/.github/scripts/templates/material_icons.pyi new file mode 100644 index 0000000000..7fe8f9f6d1 --- /dev/null +++ b/.github/scripts/templates/material_icons.pyi @@ -0,0 +1,18 @@ +""" +Flet Material Icons Stub + +To generate/update this file run from the root of the repository: + +``` +uv run .github/scripts/generate_icons.py +``` +""" + +from flet.controls.icon_data import IconData + +__all__ = ["Icons"] + +class Icons: + {% for name, code in icons -%} + {{ name.upper() }}: IconData + {% endfor -%} diff --git a/.github/scripts/update_build_version.sh b/.github/scripts/update_build_version.sh new file mode 100755 index 0000000000..1005f5907b --- /dev/null +++ b/.github/scripts/update_build_version.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +set -e + +# ------------------------------------------------------------------------------ +# This script determines the version numbers used in builds and releases. +# +# It sets three environment variables: +# - PKG_VER → The package version (semantic version). +# - BUILD_NUM → The build number (github run number plus offset). +# - PYPI_VER → A PyPI-compatible version string for publishing. +# +# Behavior: +# - On a tagged commit (e.g. "v1.2.3"), it uses that tag as the version. +# - On an untagged commit, it generates a "next dev version" by: +# • Taking the latest tag (default v0.0.0 if none). +# • Incrementing the minor version. +# • Appending "+". +# +# This ensures that: +# - Release builds (tags) get clean versions like "1.2.3". +# - Development builds get versions like "1.3.0+45" (PyPI: "1.3.0.dev45"). +# ------------------------------------------------------------------------------ + +export BUILD_NUM="$((GITHUB_RUN_NUMBER + 6000))" # TODO: adjust offset as needed + +if [[ "$GITHUB_REF" == refs/tags/* ]]; then + # ------------------------------------------------------------- + # Case 1: This build is triggered by a Git tag + # ------------------------------------------------------------- + # Extract the tag name (strip "refs/tags/") + tag="${GITHUB_REF#refs/tags/}" + # Remove leading "v" if present (e.g. "v1.2.3" → "1.2.3") + ver="${tag#v}" + # Strip .devN suffix for Flutter package version (pubspec.yaml doesn't support dev versions) + export PKG_VER="${ver%.dev*}" + # PyPI version keeps the full version (e.g. "1.2.3.dev0" for pre-releases) + export PYPI_VER="$ver" +else + # ------------------------------------------------------------- + # Case 2: This is not a tagged build (e.g. main branch commit) + # ------------------------------------------------------------- + # Get the latest tag, or fall back to "v0.0.0" if none exist + cv=$(git describe --abbrev=0 2>/dev/null || echo "v0.0.0") + # Remove leading "v" if present + cv=${cv#v} + + # Split into major/minor/patch components + major=$(echo "$cv" | cut -d. -f1) + minor=$(echo "$cv" | cut -d. -f2) + patch=$(echo "$cv" | cut -d. -f3) + + # Increment patch version (e.g. "1.2.3" → "1.2.4") + patch=$((patch + 1)) + + # Construct the package version: .. + export PKG_VER="${major}.${minor}.${patch}" + # PyPI build version: .dev + export PYPI_VER="${PKG_VER}.dev${BUILD_NUM}" +fi + +# Print values for debugging in logs +echo "PKG_VER=$PKG_VER" +echo "BUILD_NUM=$BUILD_NUM" +echo "PYPI_VER=$PYPI_VER" + +# Export values as environment variables +echo "PKG_VER=$PKG_VER" >> $GITHUB_ENV +echo "BUILD_NUM=$BUILD_NUM" >> $GITHUB_ENV +echo "PYPI_VER=$PYPI_VER" >> $GITHUB_ENV + +# set GitHub Actions output variables for use in other jobs +{ + echo "PKG_VER=$PKG_VER" + echo "BUILD_NUM=$BUILD_NUM" + echo "PYPI_VER=$PYPI_VER" +} >> $GITHUB_OUTPUT diff --git a/ci/whats-new.ps1 b/.github/scripts/whats-new.ps1 similarity index 99% rename from ci/whats-new.ps1 rename to .github/scripts/whats-new.ps1 index 43b667e55e..1c36eaf3e7 100644 --- a/ci/whats-new.ps1 +++ b/.github/scripts/whats-new.ps1 @@ -33,4 +33,4 @@ foreach ($item in $sortedIssues) { $title = $issue.title.replace('fix: ', '') "* $prefix$($title) ([#$($issue.number)]($($issue.html_url)))" -} \ No newline at end of file +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..40ded6929f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,855 @@ +name: Build & Publish + +on: + push: + branches: + - '**' + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+.dev[0-9]+' + paths: + - '.github/workflows/ci.yml' + - '.github/scripts/**' + - 'client/**' + - 'sdk/python/packages/**' + - 'sdk/python/templates/**' + - 'packages/flet/**' + - 'tools/crocodocs/**' + - 'website/**' + - '.fvmrc' + pull_request: + paths: + - '.github/workflows/ci.yml' + - '.github/scripts/**' + - 'client/**' + - 'sdk/python/packages/**' + - 'sdk/python/templates/**' + - 'packages/flet/**' + - 'tools/crocodocs/**' + - 'website/**' + - '.fvmrc' + workflow_dispatch: + +permissions: + id-token: write + contents: write + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + ROOT: "${{ github.workspace }}" + SDK_PYTHON: "${{ github.workspace }}/sdk/python" + SCRIPTS: "${{ github.workspace }}/.github/scripts" + UV_PYTHON: "3.12.7" + +jobs: + # ============ + # Python tests + # ============ + python_tests: + name: Python ${{ matrix.python-version }} tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Run tests + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + uv run --no-dev --group test pytest packages/flet/tests + uv run --no-dev --group test pytest packages/flet-cli/tests + + - name: Run docs-coverage + if: matrix.python-version == '3.12' + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + exec > docstr_coverage.log 2>&1 + status=0 + for pkg in packages/*; do + if [ -f "$pkg/pyproject.toml" ] && [ -d "$pkg/src" ]; then + pkg_name=$(basename "$pkg") + echo "====== $pkg ======" + uv run --no-dev --group docs-coverage docstr-coverage -C .docstr.yaml "$pkg/src" --badge="../../website/static/docs/assets/badges/docs-coverage/${pkg_name}.svg" || status=$? + echo + fi + done + exit $status + + - name: Upload docs-coverage logs + if: matrix.python-version == '3.12' + uses: actions/upload-artifact@v4 + with: + name: docs-coverage + path: sdk/python/docstr_coverage.log + + # ========== + # Docs build + # ========== + docs_build: + name: Build Documentation + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Enable Corepack + run: corepack enable + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Build website + run: | + cd website + yarn install + yarn build + + # =========================== + # Build Flet Flutter package + # =========================== + build_flet_package: + name: Build Flet Flutter package + runs-on: ubuntu-latest + permissions: + id-token: write # Required for authentication using OIDC + outputs: + PKG_VER: ${{ steps.versions.outputs.PKG_VER }} + BUILD_NUM: ${{ steps.versions.outputs.BUILD_NUM }} + PYPI_VER: ${{ steps.versions.outputs.PYPI_VER }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # fetch all history + fetch-tags: true # ensure tags are available + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Compute versions + id: versions + run: source "${SCRIPTS}/update_build_version.sh" + + - name: Setup Dart (OIDC for pub.dev) + uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Run tests + shell: bash + working-directory: packages/flet + run: flutter test + + - name: Publish to pub.dev (Dry Run) + shell: bash + working-directory: packages/flet + run: dart pub publish --dry-run + + - name: Publish to pub.dev + if: ${{ github.ref_type == 'tag' && !contains(github.ref_name, '.dev') }} + shell: bash + working-directory: packages/flet + run: dart pub publish -f + + # ================== + # Package templates + # ================== + build_templates: + name: Package templates + runs-on: ubuntu-latest + needs: build_flet_package + env: + PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Patch build template flet version + shell: bash + run: | + PUBSPEC="sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml" + if [[ "$GITHUB_REF" == refs/tags/* && "$GITHUB_REF" != *".dev"* ]]; then + uv run "$SCRIPTS/patch_pubspec_version.py" \ + "$PUBSPEC" "$PKG_VER" --dependencies-only --exact + else + uv run "$SCRIPTS/patch_pubspec_version.py" \ + "$PUBSPEC" --dependencies-only \ + --git-ref "$GITHUB_SHA" \ + --git-url "https://github.com/flet-dev/flet.git" \ + --git-path "packages/flet" + fi + + - name: Create template zips + shell: bash + run: | + cd sdk/python/templates + zip -r "$GITHUB_WORKSPACE/flet-build-template.zip" build/ + zip -r "$GITHUB_WORKSPACE/flet-app-templates.zip" app/ + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: template-artifacts + path: | + flet-build-template.zip + flet-app-templates.zip + + # ============================= + # Build Flet Client for Windows + # ============================= + build_windows: + name: Build Flet Client for Windows + runs-on: windows-latest + needs: + - python_tests + - build_flet_package + env: + PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} + BUILD_NUM: ${{ needs.build_flet_package.outputs.BUILD_NUM }} + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Build Flutter Windows client + env: + RUNNER_DIR: ${{ env.ROOT }}/client/build/windows/x64/runner + RELEASE_DIR: ${{ env.ROOT }}/client/build/windows/x64/runner/Release + shell: bash + working-directory: client + run: | + flutter build windows --build-name="$PKG_VER" --build-number="$BUILD_NUM" + + # Copy needed runtime DLLs + cp "${WINDIR}/system32/msvcp140.dll" "$RELEASE_DIR" + cp "${WINDIR}/system32/vcruntime140.dll" "$RELEASE_DIR" + cp "${WINDIR}/system32/vcruntime140_1.dll" "$RELEASE_DIR" + + # Rename Release folder to flet + mv "$RELEASE_DIR" "${RUNNER_DIR}/flet" + + # Zip up the runner + cd "$RUNNER_DIR" + 7z a "${ROOT}/client/flet-windows.zip" "flet" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: windows-artifacts + if-no-files-found: error + path: | + client/flet-windows.zip + + # =========================== + # Build Flet Client for macOS + # =========================== + build_macos: + name: Build Flet Client for macOS + runs-on: macos-26 + needs: + - python_tests + - build_flet_package + env: + PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} + BUILD_NUM: ${{ needs.build_flet_package.outputs.BUILD_NUM }} + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Build Flutter macOS client + shell: bash + working-directory: client + run: | + flutter build macos --build-name="$PKG_VER" --build-number="$BUILD_NUM" + tar -czvf flet-macos.tar.gz -C build/macos/Build/Products/Release Flet.app + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: macos-artifacts + if-no-files-found: error + path: | + client/flet-macos.tar.gz + + # =========================== + # Build Flet Client for Linux + # =========================== + build_linux: + name: Build Flet Client for Linux ${{ matrix.title }} + runs-on: ${{ matrix.runner }} + container: + image: ${{ matrix.container }} + needs: + - python_tests + - build_flet_package + strategy: + matrix: + include: + - distro_id: debian10 + container: debian:10 + manylinux_tag: manylinux_2_28 + arch: amd64 + runner: ubuntu-24.04 + build_arch: x64 + platform_arch: x86_64 + rive_enabled: false + title: Debian 10 AMD64 + - distro_id: debian10 + container: debian:10 + manylinux_tag: manylinux_2_28 + arch: arm64 + runner: ubuntu-24.04-arm + build_arch: arm64 + platform_arch: aarch64 + rive_enabled: false + title: Debian 10 ARM64 + - distro_id: debian12 + container: debian:12 + manylinux_tag: manylinux_2_36 + arch: amd64 + runner: ubuntu-24.04 + build_arch: x64 + platform_arch: x86_64 + rive_enabled: false + title: Debian 12 AMD64 + - distro_id: debian12 + container: debian:12 + manylinux_tag: manylinux_2_36 + arch: arm64 + runner: ubuntu-24.04-arm + build_arch: arm64 + platform_arch: aarch64 + rive_enabled: false + title: Debian 12 ARM64 + - distro_id: ubuntu20.04 + container: ubuntu:20.04 + manylinux_tag: manylinux_2_31 + arch: amd64 + runner: ubuntu-24.04 + build_arch: x64 + platform_arch: x86_64 + rive_enabled: false + title: Ubuntu 20.04 AMD64 + - distro_id: ubuntu20.04 + container: ubuntu:20.04 + manylinux_tag: manylinux_2_31 + arch: arm64 + runner: ubuntu-24.04-arm + build_arch: arm64 + platform_arch: aarch64 + rive_enabled: false + title: Ubuntu 20.04 ARM64 + - distro_id: ubuntu22.04 + container: ubuntu:22.04 + manylinux_tag: manylinux_2_35 + arch: amd64 + runner: ubuntu-24.04 + build_arch: x64 + platform_arch: x86_64 + rive_enabled: false + title: Ubuntu 22.04 AMD64 + - distro_id: ubuntu22.04 + container: ubuntu:22.04 + manylinux_tag: manylinux_2_35 + arch: arm64 + runner: ubuntu-24.04-arm + build_arch: arm64 + platform_arch: aarch64 + rive_enabled: false + title: Ubuntu 22.04 ARM64 + - distro_id: ubuntu24.04 + container: ubuntu:24.04 + manylinux_tag: manylinux_2_39 + arch: amd64 + runner: ubuntu-24.04 + build_arch: x64 + platform_arch: x86_64 + rive_enabled: true + title: Ubuntu 24.04 AMD64 + - distro_id: ubuntu24.04 + container: ubuntu:24.04 + manylinux_tag: manylinux_2_39 + arch: arm64 + runner: ubuntu-24.04-arm + build_arch: arm64 + platform_arch: aarch64 + rive_enabled: false + title: Ubuntu 24.04 ARM64 + env: + PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} + BUILD_NUM: ${{ needs.build_flet_package.outputs.BUILD_NUM }} + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + ARCH: ${{ matrix.arch }} + BUILD_ARCH: ${{ matrix.build_arch }} + PLATFORM_ARCH: ${{ matrix.platform_arch }} + DISTRO_ID: ${{ matrix.distro_id }} + MANYLINUX_TAG: ${{ matrix.manylinux_tag }} + RIVE_ENABLED: ${{ matrix.rive_enabled }} + steps: + - name: Install base packages + shell: bash + run: | + export DEBIAN_FRONTEND=noninteractive + export TZ=Etc/UTC + if [[ "$DISTRO_ID" == "debian10" ]]; then + printf '%s\n' \ + 'deb http://archive.debian.org/debian buster main' \ + 'deb http://archive.debian.org/debian buster-updates main' \ + 'deb http://archive.debian.org/debian-security buster/updates main' \ + > /etc/apt/sources.list + echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/99no-check-valid-until + fi + apt-get update + apt-get install -y git curl unzip xz-utils zip ca-certificates jq tzdata + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Get Flutter version from ".fvmrc" + uses: kuhnroyal/flutter-fvm-config-action/config@v3 + id: fvm-config-action + with: + path: '.fvmrc' + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} + channel: ${{ matrix.arch == 'arm64' && 'master' || 'stable' }} # https://github.com/subosito/flutter-action/issues/345#issuecomment-2657332687 + cache: true + + - name: Mark git safe directories + shell: bash + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + if [[ -n "${FLUTTER_ROOT:-}" ]]; then + git config --global --add safe.directory "$FLUTTER_ROOT" + fi + + - name: Install dependencies + shell: bash + run: | + if [[ -f /etc/apt/sources.list ]]; then + sed -i.bak '/apt.postgresql.org/s/^/# /' /etc/apt/sources.list + fi + apt-get update --allow-releaseinfo-change + LINUX_DEPS="$(uv run --project sdk/python/packages/flet python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + apt-get install -y $LINUX_DEPS + + - name: Build Flutter Linux clients + shell: bash + working-directory: client + run: | + STAGING_DIR="${RUNNER_TEMP:-/tmp}/flet_tars_${ARCH}" + STAGING_DIR="${STAGING_DIR}_${DISTRO_ID}" + echo "STAGING_DIR=$STAGING_DIR" >> "$GITHUB_ENV" + mkdir -p "$STAGING_DIR" + + build_flutter() { + local PACKAGE_NAME="$1" + local SUFFIX="" + local FLAVOR="full" + if [[ "$PACKAGE_NAME" == "flet-desktop-light" ]]; then + SUFFIX="-light" + FLAVOR="light" + fi + + echo "::group::($PACKAGE_NAME) Preparing sources" + # Reset Flutter app files so light edits don't leak into full or vice-versa + git checkout -- pubspec.yaml lib/main.dart || true + + if [[ "$PACKAGE_NAME" == "flet-desktop-light" ]]; then + # Strip FAT_CLIENT blocks for the light flavor + sed -i '/--FAT_CLIENT_START--/,/--FAT_CLIENT_END--/d' pubspec.yaml + sed -i '/--FAT_CLIENT_START--/,/--FAT_CLIENT_END--/d' lib/main.dart + fi + + if [[ "$RIVE_ENABLED" != "true" ]]; then + # flet_rive is excluded unless explicitly enabled + sed -i '/--RIVE_CLIENT_START--/,/--RIVE_CLIENT_END--/d' pubspec.yaml + sed -i '/--RIVE_IMPORT_START--/,/--RIVE_IMPORT_END--/d' lib/main.dart + sed -i '/--RIVE_EXTENSION_START--/,/--RIVE_EXTENSION_END--/d' lib/main.dart + fi + echo "::endgroup::" + + echo "::group::($PACKAGE_NAME) Flutter build" + flutter build linux --build-name="$PKG_VER" --build-number="$BUILD_NUM" + + # Remove any previous build output, so mv below works as expected + rm -rf "build/linux/${BUILD_ARCH}/release/flet" + + # Rename Flutter's default "bundle" output directory to "flet" + mv "build/linux/${BUILD_ARCH}/release/bundle" "build/linux/${BUILD_ARCH}/release/flet" + + # Create a compressed tarball of the "flet" directory for distribution + tar -czvf "flet-linux-${DISTRO_ID}${SUFFIX}-${ARCH}.tar.gz" -C "build/linux/${BUILD_ARCH}/release" flet + + # Stage the archive + cp -f "flet-linux-${DISTRO_ID}${SUFFIX}-${ARCH}.tar.gz" "${STAGING_DIR}/flet-linux-${DISTRO_ID}-${FLAVOR}-${ARCH}.tar.gz" + + echo "::endgroup::" + } + + build_flutter "flet-desktop-light" + build_flutter "flet-desktop" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: linux-${{ matrix.distro_id }}-${{ matrix.arch }}-artifacts + if-no-files-found: error + path: | + client/flet-linux*.tar.gz + + # ========================= + # Build Flet Client for Web + # ========================= + build_web: + name: Build Flet Client for Web + runs-on: ubuntu-latest + needs: + - python_tests + - build_flet_package + env: + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Patch Python and Flutter versions + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + source "$SCRIPTS/common.sh" + patch_python_package_versions + + - name: Get Pyodide version + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + PYODIDE_VERSION="$( uv run python -c 'import flet.version; print(flet.version.pyodide_version)' )" + echo "PYODIDE_VERSION=$PYODIDE_VERSION" >> "$GITHUB_ENV" + echo "Pyodide version: $PYODIDE_VERSION" + + - name: Build Web client + shell: bash + working-directory: client + run: | + # Compute Pyodide URLs + PYODIDE_URL="https://github.com/pyodide/pyodide/releases/download/${PYODIDE_VERSION}/pyodide-core-${PYODIDE_VERSION}.tar.bz2" + PYODIDE_CDN_URL="https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full" + + FLET_WEB="${SDK_PYTHON}/packages/flet-web/src/flet_web" + + flutter build web --wasm + + cp -R "build/web" "${FLET_WEB}" + + # Safari mobile workaround: https://github.com/flutter/flutter/issues/145111#issuecomment-2714599139 + FLUTTER_JS_DIR="$(dirname "$(command -v flutter)")/cache/flutter_web_sdk/flutter_js" + cp "$FLUTTER_JS_DIR/flutter.js.map" "${FLET_WEB}/web" + + # Download the Pyodide tarball and extract its contents into the web build folder + curl -L "$PYODIDE_URL" | tar -xj -C "${FLET_WEB}/web" + + # Download the prebuilt pyodide wheels + for wheel in "packaging-24.2-py3-none-any.whl" "micropip-0.8.0-py3-none-any.whl"; do + curl -L "${PYODIDE_CDN_URL}/${wheel}" -o "${FLET_WEB}/web/pyodide/${wheel}" + done + + # Archive the web client into a gzipped tarball + tar -czvf "flet-web.tar.gz" -C "build/web" . + + - name: Build flet-web Python package + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + uv build --package flet-web --wheel + + rm -rf "packages/flet-web/src/flet_web/web" + uv build --package flet-web --sdist + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: web-artifacts + if-no-files-found: error + path: | + client/flet-web.tar.gz + sdk/python/dist/*.whl + sdk/python/dist/*.tar.gz + + # ============================================ + # Build Flet extension Python packages + # ============================================ + build_flet_extensions: + name: Build Flet extensions + runs-on: ubuntu-latest + needs: + - python_tests + - build_flet_package + env: + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + PKG_VER: ${{ needs.build_flet_package.outputs.PKG_VER }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Analyze and Build Flutter & Python packages + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + set -euo pipefail + + PACKAGES=( + flet-ads + flet-audio + flet-audio-recorder + flet-camera + flet-charts + flet-code-editor + flet-color-pickers + flet-datatable2 + flet-flashlight + flet-geolocator + flet-lottie + flet-map + flet-permission-handler + flet-rive + flet-secure-storage + flet-video + flet-webview + ) + + source "$SCRIPTS/common.sh" + + for PACKAGE in "${PACKAGES[@]}"; do + echo "::group::Processing ${PACKAGE}" + FLUTTER_PACKAGE="${PACKAGE//-/_}" + FLUTTER_DIR="${SDK_PYTHON}/packages/${PACKAGE}/src/flutter/${FLUTTER_PACKAGE}" + + pushd "$FLUTTER_DIR" + flutter pub get + dart analyze + popd + + patch_toml_versions "packages/${PACKAGE}/pyproject.toml" "$PYPI_VER" + uv build --package "$PACKAGE" + echo "::endgroup::" + done + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: flet-python-extensions + if-no-files-found: error + path: | + sdk/python/dist/*.whl + sdk/python/dist/*.tar.gz + + # ===================================== + # Build flet, flet-cli and flet-desktop + # ===================================== + build_flet_cli_desktop: + name: Build flet, flet-cli and flet-desktop Python packages + runs-on: ubuntu-latest + env: + PYPI_VER: ${{ needs.build_flet_package.outputs.PYPI_VER }} + needs: + - python_tests + - build_flet_package + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Build Python packages + shell: bash + working-directory: ${{ env.SDK_PYTHON }} + run: | + source "$SCRIPTS/common.sh" + patch_python_package_versions + uv build --package flet-cli + uv build --package flet + uv build --package flet-desktop + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: flet-cli-desktop-python-distribution + path: | + sdk/python/dist/*.whl + sdk/python/dist/*.tar.gz + + # ============== + # GitHub Release + # ============== + release: + name: Publish GitHub Release + runs-on: ubuntu-latest + needs: + - python_tests + - docs_build + - build_flet_package + - build_windows + - build_macos + - build_linux + - build_web + - build_templates + - build_flet_extensions + - build_flet_cli_desktop + if: ${{ startsWith(github.ref, 'refs/tags/') }} + steps: + - name: Detect pre-release + id: prerelease + run: | + if [[ "${{ github.ref_name }}" == *".dev"* ]]; then + echo "is_prerelease=true" >> $GITHUB_OUTPUT + else + echo "is_prerelease=false" >> $GITHUB_OUTPUT + fi + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Create/Update GitHub Release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: ${{ github.ref_name }} + tag_name: ${{ github.ref_name }} + prerelease: ${{ steps.prerelease.outputs.is_prerelease == 'true' }} + generate_release_notes: true + preserve_order: true + overwrite_files: true + fail_on_unmatched_files: true + files: | + dist/**/*.whl + dist/**/*.tar.gz + dist/**/*.zip + + # =============== + # Python publish + # =============== + py_publish: + name: Publish Python packages to PyPI + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/') + needs: + - release + steps: + - name: Setup uv + uses: astral-sh/setup-uv@v6 + with: + ignore-empty-workdir: true + cache-dependency-glob: "" + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: Publish packages to PyPI + run: | + # remove client to avoid glob conflicts with its contents + rm -rf dist/client + + for pkg in \ + flet \ + flet_cli \ + flet_desktop \ + flet_web \ + flet_ads \ + flet_audio \ + flet_audio_recorder \ + flet_camera \ + flet_charts \ + flet_code_editor \ + flet_color_pickers \ + flet_datatable2 \ + flet_flashlight \ + flet_geolocator \ + flet_lottie \ + flet_map \ + flet_permission_handler \ + flet_rive \ + flet_secure_storage \ + flet_video \ + flet_webview; do + uv publish dist/**/${pkg}-* + done diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000000..eb1b594afd --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,29 @@ +name: Build docs + +on: + workflow_dispatch: + +jobs: + build: + name: Build Documentation + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Enable Corepack + run: corepack enable + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Build website + run: | + cd website + yarn install + yarn build diff --git a/.github/workflows/flet-build-image.yml b/.github/workflows/flet-build-image.yml new file mode 100644 index 0000000000..f64a3f13ba --- /dev/null +++ b/.github/workflows/flet-build-image.yml @@ -0,0 +1,147 @@ +name: Build flet-build base image + +on: + workflow_dispatch: + inputs: + flutter_version: + description: "Flutter version (e.g. 3.41.7). Leave blank to read from .fvmrc." + required: false + push_latest: + description: "Also push :latest" + type: boolean + default: true + +permissions: + contents: read + packages: write + +env: + IMAGE: ghcr.io/${{ github.repository_owner }}/flet-build + +jobs: + resolve_version: + name: Resolve Flutter version + runs-on: ubuntu-latest + outputs: + flutter_version: ${{ steps.v.outputs.value }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Resolve version + id: v + run: | + if [ -n "${{ inputs.flutter_version }}" ]; then + v="${{ inputs.flutter_version }}" + else + v="$(jq -r .flutter .fvmrc)" + fi + echo "value=${v}" >> "$GITHUB_OUTPUT" + echo "Flutter version: ${v}" + + build: + name: Build (${{ matrix.platform }}) + needs: resolve_version + strategy: + fail-fast: false + matrix: + include: + - platform: linux/amd64 + runner: ubuntu-latest + - platform: linux/arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} + env: + FLUTTER_VERSION: ${{ needs.resolve_version.outputs.flutter_version }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Compute platform pair + id: pair + run: | + p="${{ matrix.platform }}" + echo "value=${p//\//-}" >> "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push by digest + id: build + uses: docker/build-push-action@v6 + with: + context: docker/flet-build + file: docker/flet-build/Dockerfile + platforms: ${{ matrix.platform }} + build-args: | + FLUTTER_VERSION=${{ env.FLUTTER_VERSION }} + outputs: type=image,name=${{ env.IMAGE }},push-by-digest=true,name-canonical=true,push=true + cache-from: type=gha,scope=flet-build-${{ steps.pair.outputs.value }} + cache-to: type=gha,mode=max,scope=flet-build-${{ steps.pair.outputs.value }} + provenance: false + + - name: Export digest + run: | + mkdir -p /tmp/digests + digest="${{ steps.build.outputs.digest }}" + touch "/tmp/digests/${digest#sha256:}" + + - name: Upload digest + uses: actions/upload-artifact@v4 + with: + name: flet-build-digests-${{ steps.pair.outputs.value }} + path: /tmp/digests/* + if-no-files-found: error + retention-days: 1 + + merge: + name: Merge & push manifest + needs: + - resolve_version + - build + runs-on: ubuntu-latest + env: + FLUTTER_VERSION: ${{ needs.resolve_version.outputs.flutter_version }} + steps: + - name: Download digests + uses: actions/download-artifact@v4 + with: + path: /tmp/digests + pattern: flet-build-digests-* + merge-multiple: true + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Compute tag flags + id: tags + run: | + MM="${FLUTTER_VERSION%.*}" + flags="-t ${IMAGE}:${FLUTTER_VERSION} -t ${IMAGE}:${MM}" + if [ "${{ inputs.push_latest }}" = "true" ]; then + flags="${flags} -t ${IMAGE}:latest" + fi + echo "flags=${flags}" >> "$GITHUB_OUTPUT" + + - name: Create & push manifest + working-directory: /tmp/digests + run: | + docker buildx imagetools create ${{ steps.tags.outputs.flags }} \ + $(printf "${IMAGE}@sha256:%s " *) + + - name: Inspect image + run: docker buildx imagetools inspect "${IMAGE}:${FLUTTER_VERSION}" diff --git a/.github/workflows/flet-build-test.yml b/.github/workflows/flet-build-test.yml new file mode 100644 index 0000000000..b241c29e62 --- /dev/null +++ b/.github/workflows/flet-build-test.yml @@ -0,0 +1,308 @@ +name: Flet Build Test + +on: + push: + branches-ignore: + - main + paths: + - '.github/workflows/flet-build-test.yml' + - '.fvmrc' + - 'client/**' + - 'sdk/python/packages/**' + - 'packages/flet/**' + - 'sdk/python/examples/apps/flet_build_test/**' + pull_request: + paths: + - '.github/workflows/flet-build-test.yml' + - '.fvmrc' + - 'client/**' + - 'sdk/python/packages/**' + - 'packages/flet/**' + - 'sdk/python/examples/apps/flet_build_test/**' + workflow_dispatch: + inputs: + extra_build_args: + description: "Extra CLI args appended to `flet build` command (ex: --template-ref 0.1.0)" + required: false + default: "" + + extra_pack_args: + description: "Extra CLI args appended to `flet pack` command (ex: --icon path/to/icon)" + required: false + default: "" + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref_name }} + cancel-in-progress: true + +env: + ROOT: "${{ github.workspace }}" + SDK_PYTHON: "${{ github.workspace }}/sdk/python" + SCRIPTS: "${{ github.workspace }}/.github/scripts" + UV_PYTHON: 3.12 + PYTHONUTF8: 1 + + # https://flet.dev/docs/reference/environment-variables + FLET_CLI_NO_RICH_OUTPUT: 1 + + # Extra args passed via workflow_dispatch (empty for push/PR) + FLET_BUILD_EXTRA_ARGS: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_build_args || '' }} + FLET_PACK_EXTRA_ARGS: ${{ github.event_name == 'workflow_dispatch' && inputs.extra_pack_args || '' }} + +jobs: + build: + name: Build (${{ matrix.name }}) + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + # -------- Desktop -------- + - name: linux + runner: ubuntu-latest + build_cmd: "flet build linux" + artifact_name: linux-build-artifact + artifact_path: build/linux + needs_linux_deps: true + + - name: macos + runner: macos-26 + build_cmd: "flet build macos" + artifact_name: macos-build-artifact + artifact_path: build/macos + needs_linux_deps: false + + - name: windows + runner: windows-latest + build_cmd: "flet build windows" + artifact_name: windows-build-artifact + artifact_path: build/windows + needs_linux_deps: false + + # -------- Android -------- + - name: aab-ubuntu + runner: ubuntu-latest + build_cmd: "flet build aab" + artifact_name: aab-build-ubuntu-artifact + artifact_path: build/aab + needs_linux_deps: false + + - name: aab-macos + runner: macos-26 + build_cmd: "flet build aab" + artifact_name: aab-build-macos-artifact + artifact_path: build/aab + needs_linux_deps: false + + - name: aab-windows + runner: windows-latest + build_cmd: "flet build aab" + artifact_name: aab-build-windows-artifact + artifact_path: build/aab + needs_linux_deps: false + + - name: apk-ubuntu + runner: ubuntu-latest + build_cmd: "flet build apk" + artifact_name: apk-build-ubuntu-artifact + artifact_path: build/apk + needs_linux_deps: false + + - name: apk-macos + runner: macos-26 + build_cmd: "flet build apk" + artifact_name: apk-build-macos-artifact + artifact_path: build/apk + needs_linux_deps: false + + - name: apk-windows + runner: windows-latest + build_cmd: "flet build apk" + artifact_name: apk-build-windows-artifact + artifact_path: build/apk + needs_linux_deps: false + + # -------- iOS -------- + - name: ipa + runner: macos-26 + build_cmd: "flet build ipa" + artifact_name: ipa-build-artifact + artifact_path: build/ipa + needs_linux_deps: false + + - name: ios-simulator + runner: macos-26 + build_cmd: "flet build ios-simulator" + artifact_name: ios-simulator-build-artifact + artifact_path: build/ios-simulator + needs_linux_deps: false + + # -------- Web -------- + - name: web-ubuntu + runner: ubuntu-latest + build_cmd: "flet build web" + artifact_name: web-build-ubuntu-artifact + artifact_path: build/web + needs_linux_deps: false + + - name: web-macos + runner: macos-26 + build_cmd: "flet build web" + artifact_name: web-build-macos-artifact + artifact_path: build/web + needs_linux_deps: false + + - name: web-windows + runner: windows-latest + build_cmd: "flet build web" + artifact_name: web-build-windows-artifact + artifact_path: build/web + needs_linux_deps: false + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Patch versions + shell: bash + run: | + source "${SCRIPTS}/update_build_version.sh" + source "${SCRIPTS}/common.sh" + patch_python_package_versions + + - name: Install Linux dependencies + if: matrix.needs_linux_deps + shell: bash + run: | + sudo apt update --allow-releaseinfo-change + LINUX_DEPS="$(uv run --project sdk/python/packages/flet python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + sudo apt-get install -y --no-install-recommends $LINUX_DEPS + sudo apt-get clean + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Build app + shell: bash + working-directory: sdk/python/examples/apps/flet_build_test + run: | + echo "FLET_BUILD_EXTRA_ARGS='${FLET_BUILD_EXTRA_ARGS}'" + uv run ${{ matrix.build_cmd }} --yes --verbose --build-number ${{ github.run_number }} $FLET_BUILD_EXTRA_ARGS + + - name: Upload Artifact + uses: actions/upload-artifact@v5.0.0 + with: + name: ${{ matrix.artifact_name }} + path: sdk/python/examples/apps/flet_build_test/${{ matrix.artifact_path }} + if-no-files-found: error + overwrite: false + + pack: + name: Pack (${{ matrix.name }}) + runs-on: ${{ matrix.runner }} + env: + FLET_DESKTOP_FLAVOR: full + strategy: + fail-fast: false + matrix: + include: + - name: linux + runner: ubuntu-latest + + - name: macos + runner: macos-26 + + - name: windows + runner: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Patch versions + shell: bash + run: | + source "${SCRIPTS}/update_build_version.sh" + source "${SCRIPTS}/common.sh" + patch_python_package_versions + + - name: Install Linux dependencies + if: matrix.name == 'linux' + shell: bash + run: | + sudo apt update --allow-releaseinfo-change + LINUX_DEPS="$(uv run --project sdk/python/packages/flet python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + sudo apt-get install -y --no-install-recommends $LINUX_DEPS + sudo apt-get clean + + - name: Prepare local desktop client archive + shell: bash + run: | + set -euo pipefail + APP_DIR="${SDK_PYTHON}/packages/flet-desktop/src/flet_desktop/app" + mkdir -p "${APP_DIR}" + rm -rf "${APP_DIR:?}"/* + + pushd client + case "${{ matrix.name }}" in + linux) + flutter build linux --build-name="$PKG_VER" --build-number="$BUILD_NUM" + rm -rf build/linux/x64/release/flet + mv build/linux/x64/release/bundle build/linux/x64/release/flet + tar -czvf "${APP_DIR}/flet-linux-ubuntu24.04-amd64.tar.gz" -C build/linux/x64/release flet + ;; + macos) + flutter build macos --build-name="$PKG_VER" --build-number="$BUILD_NUM" + tar -czvf "${APP_DIR}/flet-macos.tar.gz" -C build/macos/Build/Products/Release Flet.app + ;; + windows) + flutter build windows --build-name="$PKG_VER" --build-number="$BUILD_NUM" + RUNNER_DIR="${ROOT}/client/build/windows/x64/runner" + RELEASE_DIR="${RUNNER_DIR}/Release" + cp "${WINDIR}/system32/msvcp140.dll" "$RELEASE_DIR" + cp "${WINDIR}/system32/vcruntime140.dll" "$RELEASE_DIR" + cp "${WINDIR}/system32/vcruntime140_1.dll" "$RELEASE_DIR" + rm -rf "${RUNNER_DIR}/flet" + mv "$RELEASE_DIR" "${RUNNER_DIR}/flet" + pushd "${RUNNER_DIR}" + 7z a "${APP_DIR}/flet-windows.zip" "flet" + popd + ;; + esac + popd + + - name: Pack app + shell: bash + working-directory: sdk/python/examples/apps/flet_build_test + run: | + echo "FLET_PACK_EXTRA_ARGS='${FLET_PACK_EXTRA_ARGS}'" + uv run --with pyinstaller flet pack src/main.py --yes --name flet-pack-test --distpath dist $FLET_PACK_EXTRA_ARGS + + - name: Upload Artifact + uses: actions/upload-artifact@v5.0.0 + with: + name: ${{ matrix.name }}-pack-artifact + path: sdk/python/examples/apps/flet_build_test/dist + if-no-files-found: error + overwrite: false diff --git a/.github/workflows/macos-integration-tests.yml b/.github/workflows/macos-integration-tests.yml new file mode 100644 index 0000000000..e44ab80d04 --- /dev/null +++ b/.github/workflows/macos-integration-tests.yml @@ -0,0 +1,92 @@ +name: macOS Integration Tests + +on: + push: + branches-ignore: + - main + paths: + - '.github/workflows/macos-integration-tests.yml' + - 'sdk/python/packages/flet/src/**' + - 'sdk/python/packages/flet/integration_tests/**' + - 'packages/flet/**' + - 'client/**' + - '.fvmrc' + pull_request: + paths: + - '.github/workflows/macos-integration-tests.yml' + - 'sdk/python/packages/flet/src/**' + - 'sdk/python/packages/flet/integration_tests/**' + - 'packages/flet/**' + - 'client/**' + - '.fvmrc' + workflow_dispatch: + +# Ensure only one run per branch (PR or push), cancel older ones +concurrency: + group: macos-integration-tests-${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref_name }} + cancel-in-progress: true + +env: + FLET_TEST_SCREENSHOTS_PIXEL_RATIO: "2.0" + FLET_TEST_SCREENSHOTS_SIMILARITY_THRESHOLD: "99.0" + FLET_TEST_DISABLE_FVM: "1" + UV_PYTHON: "3.13" + +jobs: + test-macos: + runs-on: macos-26 + strategy: + fail-fast: false + matrix: + suite: + - apps + - examples/apps + - examples/controls/core + - examples/controls/cupertino + - examples/controls/material + - examples/extensions + - controls/core + - controls/cupertino + - controls/material + - controls/services + - controls/theme + - extensions + + name: ${{ matrix.suite }} Integration Tests + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v6 + + - name: Setup Flutter + uses: kuhnroyal/flutter-fvm-config-action/setup@v3 + with: + path: '.fvmrc' + cache: true + + - name: Show tool versions + run: | + uv --version && uv run python --version && pod --version && flutter --version + + - name: Run integration tests (${{ matrix.suite }}) + working-directory: sdk/python + run: | + uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/${{ matrix.suite }} + + - name: Prepare failure screenshots + if: failure() + run: | + SAFE_SUITE="${MATRIX_SUITE//\//-}" + echo "SAFE_SUITE=$SAFE_SUITE" >> $GITHUB_ENV + env: + MATRIX_SUITE: ${{ matrix.suite }} + + - name: Upload artifact + if: failure() + uses: actions/upload-artifact@v4 + with: + name: integration-test-failures-macos-${{ env.SAFE_SUITE }} + path: sdk/python/packages/flet/integration_tests/${{ matrix.suite }}/**/*_actual.png + if-no-files-found: ignore diff --git a/.github/workflows/release-pr-changelog.yml b/.github/workflows/release-pr-changelog.yml new file mode 100644 index 0000000000..81f47058a4 --- /dev/null +++ b/.github/workflows/release-pr-changelog.yml @@ -0,0 +1,42 @@ +name: Release PR Changelog + +on: + pull_request: + branches: + - 'release/**' + types: + - opened + - synchronize + - reopened + - edited + - ready_for_review + +jobs: + changelog_record: + name: Require changelog record + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Verify root changelog update + shell: bash + run: | + base_sha="${{ github.event.pull_request.base.sha }}" + head_sha="${{ github.event.pull_request.head.sha }}" + + changed_files=$(git diff --name-only "$base_sha...$head_sha") + + if ! grep -qx 'CHANGELOG.md' <<<"$changed_files"; then + echo "PRs targeting release branches must update the root CHANGELOG.md." + exit 1 + fi + + added_records=$(git diff --unified=0 "$base_sha...$head_sha" -- CHANGELOG.md | grep -E '^\+\* ' || true) + + if [[ -z "$added_records" ]]; then + echo "PRs targeting release branches must add at least one new changelog record to CHANGELOG.md." + exit 1 + fi diff --git a/.gitignore b/.gitignore index 6712a75aba..21e338bbec 100644 --- a/.gitignore +++ b/.gitignore @@ -21,9 +21,14 @@ # Pycharm Files .idea/ +# FVM +.fvm/ + # mac specific .DS_Store *.bkp .python-version vendor/ /client/android/app/.cxx +client/devtools_options.yaml +/.claude/worktrees diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000000..3620da2df1 --- /dev/null +++ b/.ruff.toml @@ -0,0 +1 @@ +exclude = ["ci/templates"] diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..b13058758f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +Skills are located in `.agents/skills`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 4092fe13e8..2e57ad5c5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,236 @@ -# Flet changelog +## 0.85.1 + +### Bug fixes + +* Fix `TooltipTheme.decoration` so it applies to controls using `ft.Tooltip(...)` when the tooltip does not explicitly set `decoration` or `bgcolor` ([#6432](https://github.com/flet-dev/flet/issues/6432), [#6482](https://github.com/flet-dev/flet/pull/6482)) by @ndonkoHenri. +* Fix `flet-geolocator.Geolocator` reliability on web and desktop: `get_last_known_position()` no longer crashes with `TypeError: argument after ** must be a mapping, not NoneType` and now returns `Optional[GeolocatorPosition]`; `get_current_position()` no longer hangs forever on web (Dart-side workaround for the upstream [`geolocator_web` 4.1.3](https://pub.dev/packages/geolocator_web) `inMicroseconds`/`inMilliseconds` timeout typo) and uses sensible web defaults (`time_limit: 30s`, `maximum_age: 5m`); the previously-dropped `configuration` argument now actually reaches `getCurrentPosition` on the Dart side; the position stream is gated behind a registered `on_position_change`/`on_error` handler (with cancel-on-update to prevent leaks); and platform exceptions (`LocationServiceDisabledException`, `PermissionDeniedException`, `PermissionDefinitionsNotFoundException`, `PermissionRequestInProgressException`, `PositionUpdateException`, `TimeoutException`) are now translated into actionable error messages and surfaced to Python as `RuntimeError` without the default `Exception:` prefix ([#6487](https://github.com/flet-dev/flet/pull/6487)) by @FeodorFitsner. +* Fix PEP 508 markers on `flet`'s `oauthlib`/`httpx` deps not actually excluding those packages under Pyodide: the `flet build web` package platform has been renamed from `Pyodide` to `Emscripten` to match `platform.system()` inside the Pyodide runtime, and the markers now use `platform_system != 'Emscripten'`, so the exclusion works both via `flet build` and a direct `micropip.install("flet")` in a Pyodide REPL. Requires `serious_python` `>= 1.0.0`, which is now pinned in the `flet build` template ([#6492](https://github.com/flet-dev/flet/pull/6492)) by @FeodorFitsner. + +## 0.85.0 + +### New features + +* Add configurable built-in, custom, hidden, and normal/fullscreen-specific controls to `flet-video`; `Video.take_screenshot()` for capturing video frames; and `Video.on_position_change`/`Video.on_duration_change` events ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. +* Add declarative `ft.Router` component for `@ft.component` apps with nested routes, layout routes with outlets, dynamic segments, optional segments, splats, custom regex constraints, data loaders, active link detection, authentication patterns, and `manage_views=True` mode for view-stack navigation with swipe-back gestures and `AppBar` back button on mobile ([#6406](https://github.com/flet-dev/flet/pull/6406)) by @FeodorFitsner. +* Add `ft.use_dialog()` hook for declarative dialog management from within `@ft.component` functions, with frozen-diff reactive updates and automatic open/close lifecycle ([#6335](https://github.com/flet-dev/flet/pull/6335)) by @FeodorFitsner. +* Add `scrollable`, `pin_leading_to_top`, and `pin_trailing_to_bottom` properties to `NavigationRail` for scrollable content with optional pinned leading/trailing controls ([#1923](https://github.com/flet-dev/flet/issues/1923), [#6356](https://github.com/flet-dev/flet/pull/6356)) by @ndonkoHenri. +* Add scroll support to `ResponsiveRow` for responsive layouts whose content exceeds the available height ([#2590](https://github.com/flet-dev/flet/issues/2590), [#6417](https://github.com/flet-dev/flet/pull/6417)) by @ndonkoHenri. +* Add `issues` property to `CodeEditor` (along with `Issue` and `IssueType` types) for displaying code analysis error markers in the gutter, with analysis performed on the Python side ([#6407](https://github.com/flet-dev/flet/pull/6407)) by @FeodorFitsner. +* Add `Page.pop_views_until()` to pop multiple views and return a result to the destination view ([#6326](https://github.com/flet-dev/flet/issues/6326), [#6347](https://github.com/flet-dev/flet/pull/6347)) by @brunobrown. +* Make `NavigationDrawerDestination.label` accept custom controls and add `NavigationDrawerTheme.icon_theme` ([#6379](https://github.com/flet-dev/flet/issues/6379), [#6395](https://github.com/flet-dev/flet/pull/6395)) by @ndonkoHenri. +* Add `local_position` and `global_position` to `DragTargetEvent`, deprecating `x`, `y`, and `offset` ([#6387](https://github.com/flet-dev/flet/issues/6387), [#6401](https://github.com/flet-dev/flet/pull/6401)) by @ndonkoHenri. +* Added PCM16 streaming to `AudioRecorder`, including `on_stream` chunks and direct upload support via `AudioRecorderUploadSettings` ([#5858](https://github.com/flet-dev/flet/issues/5858), [#6423](https://github.com/flet-dev/flet/pull/6423)) by @ndonkoHenri. +* Add `Page.theme_animation_style` for customizing the duration and curve of the theme cross-fade between `theme` and `dark_theme` (or disabling it with `AnimationStyle.no_animation()`), exposing Flutter's `MaterialApp.themeAnimationStyle` ([#6476](https://github.com/flet-dev/flet/pull/6476)) by @FeodorFitsner. + +### Improvements + +### Bug fixes + +* Fix control diffing for controls nested inside `@value` dataclass objects so they keep the nearest control parent/page context, and restore optional structured properties that are cleared to `None` and later set again ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. +* Fix `Page` and `View` vertical centering when scrolling is enabled, including hidden scrollbars, so short content remains centered in the viewport ([#6446](https://github.com/flet-dev/flet/issues/6446), [#6450](https://github.com/flet-dev/flet/pull/6450)) by @ndonkoHenri. +* Reduce Linux memory retention when repeatedly removing `flet_video.Video` controls by linking `media_kit` video apps against mimalloc in run and build flows ([#6164](https://github.com/flet-dev/flet/issues/6164), [#6416](https://github.com/flet-dev/flet/pull/6416)) by @ndonkoHenri. +* Fix `flet build` and `flet publish` dependency parsing for `project.dependencies` and Poetry constraints with `<`/`<=`, and add coverage for normalized requirement handling ([#6332](https://github.com/flet-dev/flet/issues/6332), [#6340](https://github.com/flet-dev/flet/pull/6340)) by @td3447. +* Fix `CodeEditor` background not filling the entire area when `expand=True` ([#6407](https://github.com/flet-dev/flet/pull/6407)) by @FeodorFitsner. +* Handle unbounded width in `ResponsiveRow` with an explicit error, treat child controls with `col=0` as hidden, and clarify `Container` expansion behavior when `alignment` is set ([#1951](https://github.com/flet-dev/flet/issues/1951), [#3805](https://github.com/flet-dev/flet/issues/3805), [#5209](https://github.com/flet-dev/flet/issues/5209), [#6354](https://github.com/flet-dev/flet/pull/6354)) by @ndonkoHenri. +* Fix `find_platform_image` selecting incompatible icon formats (e.g. `.icns` on Windows) by ranking glob results per target platform ([#6381](https://github.com/flet-dev/flet/pull/6381)) by @HG-ha. +* Fix `page.window.destroy()` taking several seconds to close Windows desktop apps when `prevent_close` is enabled ([#5459](https://github.com/flet-dev/flet/issues/5459), [#6428](https://github.com/flet-dev/flet/pull/6428)) by @ndonkoHenri. +* Fix `Page.show_drawer()`, `close_drawer()`, and root/top view accessors (`appbar`, `drawer`, `navigation_bar`, `controls`, ...) failing with `TypeError` under `Page.render_views()` by unwrapping component-wrapped views and normalizing single-view returns ([#6413](https://github.com/flet-dev/flet/issues/6413), [#6414](https://github.com/flet-dev/flet/pull/6414)) by @FeodorFitsner. +* Fix `auto_scroll` on scrollable controls silently doing nothing unless `scroll` was also explicitly set ([#6397](https://github.com/flet-dev/flet/issues/6397), [#6404](https://github.com/flet-dev/flet/pull/6404)) by @ndonkoHenri. +* Fix Flet web returning `index.html` with a `200 OK` for missing asset files; requests for paths with a file extension other than `.html` now return a proper `404`, while route-like paths still fall back to `index.html` for SPA routing ([#6425](https://github.com/flet-dev/flet/pull/6425)) by @ndonkoHenri. +* Fix `Lottie` failing to load local asset files on Windows desktop (and unreliably on other desktop platforms), so animations referenced by `src="file.json"` from the app's `assets/` directory now display correctly ([#6386](https://github.com/flet-dev/flet/issues/6386), [#6426](https://github.com/flet-dev/flet/pull/6426)) by @ndonkoHenri. +* Fix `Page.on_resize` and `Page.on_media_change` not firing after mobile orientation changes ([#6457](https://github.com/flet-dev/flet/issues/6457), [#6423](https://github.com/flet-dev/flet/pull/6423)) by @ndonkoHenri. +* Fix `flet pack` desktop packaging so Windows and Linux bundles include the expected client archive, and Windows taskbar pins point to the packed app instead of the cached `flet.exe` ([#5151](https://github.com/flet-dev/flet/issues/5151), [#6403](https://github.com/flet-dev/flet/pull/6403)) by @ndonkoHenri. +* Fix environment variable priority in `flet build` template: inherit from `Platform.environment` and use `putIfAbsent` for FLET_* variables so pre-set system env vars are not overwritten ([#6394](https://github.com/flet-dev/flet/pull/6394)) by @Bahtya. +* Fix `NavigationBarDestination.selected_icon` rendering wrongly when provided as an `Icon` control ([#6460](https://github.com/flet-dev/flet/issues/6460), [#6468](https://github.com/flet-dev/flet/pull/6468)) by @ndonkoHenri. +* Fix 3- and 4-digit hex color shorthand (e.g. `#c00`, `#fc00`) rendering as invisible by expanding them to their full 6/8-digit forms ([#6419](https://github.com/flet-dev/flet/issues/6419), [#6421](https://github.com/flet-dev/flet/pull/6421)) by @ndonkoHenri. +* Fix `LineChartEvent.spots` returning undecoded MessagePack extension values instead of `LineChartEventSpot` objects ([#6443](https://github.com/flet-dev/flet/issues/6443), [#6468](https://github.com/flet-dev/flet/pull/6468)) by @ndonkoHenri. +* Fix `LineChart` (and other charts) silently dropping custom `ChartAxisLabel` entries whose `value` matched a tick only after floating-point rounding (e.g. `0.1`, `0.2`, `0.3`) by switching label lookup to a tolerance-based comparison scaled to the axis interval ([#6445](https://github.com/flet-dev/flet/issues/6445), [#6459](https://github.com/flet-dev/flet/pull/6459)) by @KangZhaoKui. +* Fix absolute-path `src` (e.g. `Image(src="/images/foo.svg")`) breaking on web when the app is mounted at a non-root URL, pass `data:`/`blob:` URIs through the asset resolver unchanged, preserve origin-relative semantics when `assets_dir` is unset, and add a `window.flet.assetsDir` JS-interop bridge so embedding hosts can supply `assets_dir` to the top-level `FletApp` ([#6470](https://github.com/flet-dev/flet/pull/6470)) by @FeodorFitsner. +* Fix unbounded browser memory growth in `MatplotlibChart` on Flutter web (CanvasKit/WASM) during animations by replacing the `Canvas` + `capture()` rendering path with a dedicated `MatplotlibChartCanvas` widget that composites matplotlib diff frames in CPU memory; also fixes Safari async PNG decode (`EncodingError: Loading error.`), a render/`figure.savefig()` race that crashed the toolbar Download, and pan/zoom playback lag from buffered pointer events ([#6473](https://github.com/flet-dev/flet/pull/6473)) by @FeodorFitsner. +* Fix `Duration` fields (and other `int`-typed properties) silently decoding to `0` when given a Python `float` (e.g. `Duration(seconds=2.0)` causing `Page.theme_animation_style` to end instantly) by coercing `double` to `int` in the Dart-side `parseInt` ([#6478](https://github.com/flet-dev/flet/issues/6478), [#6480](https://github.com/flet-dev/flet/pull/6480)) by @FeodorFitsner. + +### Documentation + +* Improve CrocoDocs API reference rendering with formatted signatures, modern type annotations, and cleaner cross-reference labels for extension packages ([#6442](https://github.com/flet-dev/flet/pull/6442)) by @ndonkoHenri. +* Add `crocodocs watch` command for hot-reload docs development with file-watching, debounced regeneration, and optional child process management ([#6402](https://github.com/flet-dev/flet/pull/6402)) by @ndonkoHenri. + +### Other changes + +* Add a declarative `ReorderableListView` app example showing add, remove, and reorder flows with stable item identity ([#6374](https://github.com/flet-dev/flet/pull/6374)) by @FeodorFitsner. +* Remove deprecated module-level `margin`, `padding`, `border`, and `border_radius` helpers (`all()`, `symmetric()`, `only()`, `horizontal()`, `vertical()`) in favor of the corresponding `Margin`, `Padding`, `Border`, and `BorderRadius` classmethods ([#6425](https://github.com/flet-dev/flet/pull/6425)) by @ndonkoHenri. +* Centralize Linux apt dependencies in `flet.utils.linux_deps` and update CI workflows and publish docs to consume them dynamically ([#6357](https://github.com/flet-dev/flet/issues/6357), [#6383](https://github.com/flet-dev/flet/pull/6383)) by @ndonkoHenri. +* Bump `serious_python` to `0.9.12` in the `flet build` template ([#6461](https://github.com/flet-dev/flet/pull/6461)) by @FeodorFitsner. + +## 0.84.0 + +### Improvements + +* Migrate Flet docs from MkDocs to Docusaurus for a more maintainable documentation pipeline ([#6359](https://github.com/flet-dev/flet/pull/6359)) by @FeodorFitsner. +* Migrate examples into standalone projects with metadata, dependencies, and assets to improve discovery and make every sample runnable as-is ([#6281](https://github.com/flet-dev/flet/issues/6281), [#6355](https://github.com/flet-dev/flet/pull/6355)) by @InesaFitsner. + +### Bug fixes + +* Fix `flet pack` on macOS after the move to GitHub Releases by handling extracted app bundles, matching the cached tarball name, and cleaning up loose frameworks during packaging ([#6358](https://github.com/flet-dev/flet/issues/6358), [#6361](https://github.com/flet-dev/flet/pull/6361)) by @FeodorFitsner. + +## 0.83.1 + +### Bug fixes + +* Fix solitaire tutorial and drag examples to use `local_delta.x` and `local_delta.y` instead of removed `delta_x` and `delta_y` ([#6317](https://github.com/flet-dev/flet/issues/6317), [#6344](https://github.com/flet-dev/flet/pull/6344)) by @Krishnachaitanyakc. +* Fix inherited dataclass field validation rules applying to overridden subclass fields and breaking `flet-datatable2` on `0.83.0` ([#6349](https://github.com/flet-dev/flet/issues/6349), [#6350](https://github.com/flet-dev/flet/pull/6350)) by @ndonkoHenri. + +## 0.83.0 + +### New features + +* Add customizable scrollbars for scrollable controls and pages ([#5912](https://github.com/flet-dev/flet/issues/5912), [#6282](https://github.com/flet-dev/flet/pull/6282)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Add scrolling support and richer change events to `ExpansionPanelList` ([#6294](https://github.com/flet-dev/flet/pull/6294)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Expand `SharedPreferences` to support `int`, `float`, `bool`, and `list[str]` values ([#6304](https://github.com/flet-dev/flet/issues/6304), [#6267](https://github.com/flet-dev/flet/pull/6267)) by [@ndonkoHenri](https://github.com/ndonkoHenri). + +### Improvements + +* Speed up control diffing and nested value tracking with sparse `Prop` updates and `@value` types ([#6098](https://github.com/flet-dev/flet/issues/6098), [#6270](https://github.com/flet-dev/flet/issues/6270), [#6117](https://github.com/flet-dev/flet/issues/6117), [#6296](https://github.com/flet-dev/flet/pull/6296)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Consolidate app/build templates into the monorepo and publish pre-release `flet` packages and template artifacts from CI ([#6306](https://github.com/flet-dev/flet/issues/6306), [#6331](https://github.com/flet-dev/flet/pull/6331)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Move desktop client binaries from PyPI wheels to GitHub Releases and unify desktop packaging around `flet-desktop` ([#6290](https://github.com/flet-dev/flet/issues/6290), [#6309](https://github.com/flet-dev/flet/pull/6309)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Lightweight dataclass validation and deprecation with `Annotated` + auto-added deprecation admonitions in docs ([#6278](https://github.com/flet-dev/flet/pull/6278)) by [@ndonkoHenri](https://github.com/ndonkoHenri). + + +### Bug fixes + +* Align Dart-side default values with Python across core and extension packages ([#6329](https://github.com/flet-dev/flet/issues/6329), [#6330](https://github.com/flet-dev/flet/pull/6330)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Skip redundant page auto-updates after handlers call `.update()` explicitly ([#6236](https://github.com/flet-dev/flet/issues/6236), [#6298](https://github.com/flet-dev/flet/pull/6298)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Fix `ReorderableListView` reorder event deserialization for start/end callbacks ([#6177](https://github.com/flet-dev/flet/issues/6177), [#6315](https://github.com/flet-dev/flet/pull/6315)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Skip loading `micropip` for Pyodide apps that already define dependencies in `pyproject.toml` ([#6259](https://github.com/flet-dev/flet/issues/6259), [#6300](https://github.com/flet-dev/flet/pull/6300)) by [@FeodorFitsner](https://github.com/FeodorFitsner). + +## 0.82.2 + +### Bug fixes + +* Lazy-load optional auth dependencies to avoid import-time failures in web/Pyodide startup ([#6258](https://github.com/flet-dev/flet/issues/6258), [#6280](https://github.com/flet-dev/flet/pull/6280)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Pin `binaryornot` below `0.5` to fix build-template UTF-8 decode errors ([#6276](https://github.com/flet-dev/flet/issues/6276), [#6279](https://github.com/flet-dev/flet/pull/6279)) by [@ndonkoHenri](https://github.com/ndonkoHenri). + +## 0.82.0 + +### New features + +* Add Auth0 `audience` support through OAuth `authorization_params` ([#3775](https://github.com/flet-dev/flet/issues/3775), [#6205](https://github.com/flet-dev/flet/pull/6205)). +* Add `Map.get_camera()`, `MapEventType`, and richer `MapEvent` payloads in `flet-map` ([#6196](https://github.com/flet-dev/flet/issues/6196), [#6208](https://github.com/flet-dev/flet/pull/6208)). + +### Improvements + +* Refactor ads controls: `InterstitialAd` is now a `Service`, and `BannerAd` is now a `LayoutControl` ([#6194](https://github.com/flet-dev/flet/issues/6194), [#6235](https://github.com/flet-dev/flet/pull/6235)). +* Improve `CodeEditor` with Chinese pinyin input support and aligned gutter rendering ([#6211](https://github.com/flet-dev/flet/issues/6211), [#6243](https://github.com/flet-dev/flet/issues/6243), [#6244](https://github.com/flet-dev/flet/pull/6244)). +* Add the `Trolli` app declarative example rewrite ([#6242](https://github.com/flet-dev/flet/pull/6242)). + +### Bug fixes + +* Fix disabled-state handling across `Tabs`, `TabBar`, `Tab`, and `TabBarView` ([#6220](https://github.com/flet-dev/flet/issues/6220), [#6224](https://github.com/flet-dev/flet/pull/6224)). +* Fix a `WebView` null-check crash (`Null check operator used on a null value`) ([#6238](https://github.com/flet-dev/flet/pull/6238)). + +### Other changes + +* Pin internal Flet package dependencies across all Flet packages ([#6222](https://github.com/flet-dev/flet/issues/6222), [#6247](https://github.com/flet-dev/flet/pull/6247)). +* Update Flutter to 3.41.4 and refresh dependencies ([#6245](https://github.com/flet-dev/flet/issues/6245)). + +## 0.81.0 + +### New features + +* Add `Camera` control ([#6190](https://github.com/flet-dev/flet/issues/6190)). +* Add `CodeEditor` control ([#6162](https://github.com/flet-dev/flet/issues/6162)). +* Add `PageView` control ([#6158](https://github.com/flet-dev/flet/issues/6158)). +* Add color picker controls based on `flutter_colorpicker` ([#6109](https://github.com/flet-dev/flet/issues/6109)). +* Add Matrix4-based `LayoutControl.transform` and `RotatedBox` control ([#6198](https://github.com/flet-dev/flet/issues/6198)). +* Add `LayoutControl.on_size_change` event for size-aware layouts ([#6099](https://github.com/flet-dev/flet/issues/6099)). +* Add `Hero` animations ([#6157](https://github.com/flet-dev/flet/issues/6157)). +* Add clipboard image/file set and get APIs ([#6141](https://github.com/flet-dev/flet/issues/6141)). +* Add web `FilePicker` `with_data` support for file content ([#6199](https://github.com/flet-dev/flet/issues/6199)). +* Add platform locale info and locale change events ([#6191](https://github.com/flet-dev/flet/issues/6191)). +* Add `ignore_up_down_keys` to `TextField` and `CupertinoTextField` ([#6183](https://github.com/flet-dev/flet/issues/6183)). +* Add `flet build --artifact` and iOS simulator build targets ([#6074](https://github.com/flet-dev/flet/issues/6074), [#6188](https://github.com/flet-dev/flet/issues/6188)). + +### Improvements + +* Optimize `object_patch` memory churn ([#6204](https://github.com/flet-dev/flet/issues/6204)). +* Skip component migrate/diff when function signatures differ ([#6181](https://github.com/flet-dev/flet/issues/6181)). + +### Bug fixes + +* Fix memory leaks in Flet web app ([#6186](https://github.com/flet-dev/flet/issues/6186)). +* Fix desktop window frameless/titlebar update sync and progress bar clearing ([#6114](https://github.com/flet-dev/flet/issues/6114)). +* Fix first-time button `style` patching and clear stale style state ([#6119](https://github.com/flet-dev/flet/issues/6119)). +* Fix map layer rebuilds on marker updates ([#6113](https://github.com/flet-dev/flet/issues/6113)). +* Fix `AlertDialog` and `CupertinoAlertDialog` barrier color updates ([#6097](https://github.com/flet-dev/flet/issues/6097)). +* Fix `ControlEvent` runtime type hints ([#6102](https://github.com/flet-dev/flet/issues/6102)). + +### Other changes + +* Bump Flutter to 3.41.2. +* Register MIME types for `.mjs` and `.wasm` ([#6140](https://github.com/flet-dev/flet/issues/6140)). + +## 0.80.5 + +* Fix memory leak in Flet web apps ([#6089](https://github.com/flet-dev/flet/issues/6089)). +* feat: add LaTeX support in `ft.Markdown` ([#6069](https://github.com/flet-dev/flet/issues/6069)). +* Avoid `FletApp` control messing with root app routing ([#6086](https://github.com/flet-dev/flet/issues/6086)). +* Include material and cupertino icon data in PyInstaller hook ([#6072](https://github.com/flet-dev/flet/issues/6072)). + +## 0.80.4 + +* fix: Enable TextButton style and full-width Dropdown ([#6048](https://github.com/flet-dev/flet/issues/6048)). +* flet-video: add mpv_properties to VideoConfiguration ([#6041](https://github.com/flet-dev/flet/issues/6041)). +* Refactor `Icons` and `CupertinoIcons` proxies for member caching and iteration ([#6055](https://github.com/flet-dev/flet/issues/6055)). +* Flutter 3.38.7. + +## 0.80.3 + +* Lazy loading of icons, theme for faster app startup ([#6043](https://github.com/flet-dev/flet/issues/6043)). +* feat: add `locale` prop to `CupertinoDatePicker`, `DatePicker`, `DateRangePicker`, `TimePicker` ([#6030](https://github.com/flet-dev/flet/issues/6030)). +* Allow installing Flet packages in runtime with uv ([#6037](https://github.com/flet-dev/flet/issues/6037)). +* Python wheels for Ubuntu 20.04-24.04 ([#6035](https://github.com/flet-dev/flet/issues/6035)). +* Disable Rive in desktop client light ([#6032](https://github.com/flet-dev/flet/issues/6032)). +* Fix desktop light package versioning ([#6031](https://github.com/flet-dev/flet/issues/6031)). +* Rive 0.14.0 ([#6025](https://github.com/flet-dev/flet/issues/6025)). +* fix: Convert `datetime` instances to UTC while passing over the wire ([#6023](https://github.com/flet-dev/flet/issues/6023)). +* feat(flet-charts): Allow `badge_position` and `title_position` of `PieChartSection` accept values >= `1.0` ([#6024](https://github.com/flet-dev/flet/issues/6024)). +* Add position details to `GestureDetector.on_tap` event ([#6016](https://github.com/flet-dev/flet/issues/6016)). +* Fix Android platform check to exclude web ([#6013](https://github.com/flet-dev/flet/issues/6013)). + +## 0.80.2 + +* OAuth fixes and updated examples ([#5996](https://github.com/flet-dev/flet/issues/5996)). +* Examples cleanup ([#5997](https://github.com/flet-dev/flet/issues/5997)). +* Fix wrong `LinearGradient` alignment defaults + allow multiple use of `--exclude` option in `flet build` ([#5986](https://github.com/flet-dev/flet/issues/5986)). +* Update TypeVar definition for covariant typing in Ref class ([#5994](https://github.com/flet-dev/flet/issues/5994)). +* feat: add `on_long_press` and `on_hover` events to `IconButton` ([#5984](https://github.com/flet-dev/flet/issues/5984)). +* replace all `asyncio.iscoroutinefunction` with `inspect.iscoroutinefunction` ([#5928](https://github.com/flet-dev/flet/issues/5928)). +* Fix: Control with ID xxx is not registered for `flet_permission_handler` when using Python 3.14 ([#5896](https://github.com/flet-dev/flet/issues/5896)). + + +## 0.80.1 + +* Fix `flet publish` to sub-directories, Icons Browser and other Gallery examples updated [#5964](https://github.com/flet-dev/flet/pull/5964). + +## 0.80.0 + +* **Flet 1.0 Beta Release** – [Read the announcement](https://flet.dev/blog/flet-1-0-beta) + +## 0.70.0 + +* **Flet 1.0 Alpha Released** – [Read the announcement](https://flet.dev/blog/introducing-flet-1-0-alpha) +* **New:** Declarative and reactive programming style, alongside imperative +* **New:** Automatic page updates after event handler completion +* **New:** Service controls for non-visual functionality +* **New:** WebAssembly support for running web apps in the browser +* **New:** Offline mode support for web apps +* **New:** Ability to embed Flet web apps into multiple HTML elements on a page +* **New:** Modern, future-proof architecture: + * Controls in Python are now defined as plain dataclasses + * Unified diffing algorithm supports both imperative and declarative styles + * Refactored Flutter layer using inherited widgets and `Provider` +* Added a Shimmer control for building skeleton loaders and animated placeholders. +* Added `FletApp.appErrorMessage` template to customize loading screen errors. +* See the list of [breaking changes](https://github.com/flet-dev/flet/issues/5238) ## 0.28.3 @@ -31,7 +263,7 @@ * Fix `flet build`: allow dependencies with commas ([#5033](https://github.com/flet-dev/flet/issues/5033)) * Show app startup screen by default ([#5036](https://github.com/flet-dev/flet/issues/5036)) * fix: `Textfield` cursor position changes when modifying field content in `on_change` ([#5019](https://github.com/flet-dev/flet/issues/5019)) -* Remove deperecated `Control.update_async()` method ([#5005](https://github.com/flet-dev/flet/issues/5005)) +* Remove deprecated `Control.update_async()` method ([#5005](https://github.com/flet-dev/flet/issues/5005)) * fix: incorrect positioning of non-FAB controls assigned to page.floating_action_button ([#5049](https://github.com/flet-dev/flet/issues/5049)) ## 0.27.5 @@ -77,7 +309,7 @@ * disable markup for flet-cli stdout logs ([#4796](https://github.com/flet-dev/flet/pull/4796)) * Fixed: Disable rich's Markup for stdout logs ([#4795](https://github.com/flet-dev/flet/issues/4795)) * Fixed: Setting `SearchBar.bar_border_side` isn't visually honoured ([#4767](https://github.com/flet-dev/flet/issues/4767)) -* Fixed: Dropdown: Long options cause the down-arrow to oveflow ([#4838](https://github.com/flet-dev/flet/issues/4838)) +* Fixed: Dropdown: Long options cause the down-arrow to overflow ([#4838](https://github.com/flet-dev/flet/issues/4838)) * Fixed: CupertinoSlider initialisation does not allow values less then zero/greater then 1 ([#4853](https://github.com/flet-dev/flet/issues/4853)) * Fixed: Same code shows different appearance in Flet APP/Web/PC local. ([#4855](https://github.com/flet-dev/flet/issues/4855)) * Fixed: Transforming scale renders a grey screen ([#4759](https://github.com/flet-dev/flet/issues/4759)) @@ -91,7 +323,7 @@ * Migrated to Flutter 3.27.0 ([#4593](https://github.com/flet-dev/flet/pull/4593)) * New control properties, Flutter 3.27 fixes ([#4703](https://github.com/flet-dev/flet/pull/4703)) * Optional on-demand creation of `ListView.controls` ([#3931](https://github.com/flet-dev/flet/issues/3931)) -* Reset `InteractiveViewer` tranformations ([#4391](https://github.com/flet-dev/flet/issues/4391)) +* Reset `InteractiveViewer` transformations ([#4391](https://github.com/flet-dev/flet/issues/4391)) * Passthrough of mouse events from main window to other applications ([#1438](https://github.com/flet-dev/flet/issues/1438)) * Remove v0.26.0-related deprecations ([#4456](https://github.com/flet-dev/flet/issues/4456)) * Implemented `Window.ignore_mouse_events` ([#4465](https://github.com/flet-dev/flet/pull/4465)) @@ -327,7 +559,7 @@ ## 0.21.1 -* Python dependencies bumped and losen. +* Python dependencies bumped and loosen. * Fixed: "No supported WebSocket library detected." when running web app with Flet 0.21.0 ([#2818](https://github.com/flet-dev/flet/issues/2818)). * Fix `EventHandler`: do not call it when converter returned `None`. @@ -435,7 +667,7 @@ * `CupertinoSlider` control and `Slider.adaptive` ([#2224](https://github.com/flet-dev/flet/issues/2224)). * `CupertinoRadio` control and `Radio.adaptive` ([#2225](https://github.com/flet-dev/flet/issues/2225)). -* Fix `NavigationBar.label_bahavior` ([#2229](https://github.com/flet-dev/flet/issues/2229)). +* Fix `NavigationBar.label_behavior` ([#2229](https://github.com/flet-dev/flet/issues/2229)). * `CupertinoSwitch` control ([docs](https://flet.dev/docs/controls/cupertinoswitch)). * Disable fade-in effect on Flet app start. * Tab alignment bug fix ([#2208](https://github.com/flet-dev/flet/issues/2208)). @@ -481,7 +713,7 @@ ## 0.12.1 -* Ability to expand `ButtomSheet` to the top of the screen with `BottomSheet.is_scroll_controlled` property ([#2087](https://github.com/flet-dev/flet/issues/2087)). +* Ability to expand `BottomSheet` to the top of the screen with `BottomSheet.is_scroll_controlled` property ([#2087](https://github.com/flet-dev/flet/issues/2087)). * `BottomSheet.maintain_bottom_view_insets_padding` to avoid obstructing controls with on-screen keyboard ([#2010](https://github.com/flet-dev/flet/issues/2010)). * Fixed: `NavigationDrawer` disappears when you move the window and is not opening again ([#2062](https://github.com/flet-dev/flet/issues/2062)). * Fixed: alert dialog doesn't close ([#2011](https://github.com/flet-dev/flet/issues/2011)). @@ -688,7 +920,7 @@ from flet.auth.providers import GitHubOAuthProvider ## 0.4.1 * Slider.round to round slider value on a label -* Fix page.client_storage.get_keys() timeout +* Fix page.client_storage.get_keys() timeout * Fix encode() import in PyInstaller integration * Fix "ConnectionAbortedError" error on Windows * Consistent licensing across the code - Apache 2.0 @@ -705,12 +937,12 @@ from flet.auth.providers import GitHubOAuthProvider * Pyodide publishing fixes and improvements ([#953](https://github.com/flet-dev/flet/issues/953)) * feat: Add PaddingValue to __init__.py ([#936](https://github.com/flet-dev/flet/issues/936)) * Standalone Flet web apps with Pyodide ([#913](https://github.com/flet-dev/flet/issues/913)) -* modified `tooltip` attribute from `prefere*` to `prefer*` ([#909](https://github.com/flet-dev/flet/issues/909)) +* modified `tooltip` attribute from `prefer*` to `preferred*` ([#909](https://github.com/flet-dev/flet/issues/909)) * Fix unicode encoding in `FletTcpSocketServerProtocol` * Fix relative assets path in desktop app * PDM changed to Poetry * Add `--hidden-import` option to `flet pack` command -* Add transparancy to matplotlib ([#889](https://github.com/flet-dev/flet/issues/889)) +* Add transparency to matplotlib ([#889](https://github.com/flet-dev/flet/issues/889)) * Replace Fletd server for desktop apps with a light-weight Python shim ([#838](https://github.com/flet-dev/flet/issues/838)) * add default values in Border dataclass ([#883](https://github.com/flet-dev/flet/issues/883)) * Fix for issue in control.py when checking add command ([#835](https://github.com/flet-dev/flet/issues/835)) @@ -783,7 +1015,7 @@ from flet.auth.providers import GitHubOAuthProvider * Add an ability to change font family of `TextField` ([#511](https://github.com/flet-dev/flet/issues/511)) * Feature: Theming Switch and Checkbox component ([#523](https://github.com/flet-dev/flet/issues/523)) * Change shape of AlertDialog ([#537](https://github.com/flet-dev/flet/issues/537)) -* Fixed: Saving and retreiving a string value from client storage adds quotation marks ([#545](https://github.com/flet-dev/flet/issues/545)) +* Fixed: Saving and retrieving a string value from client storage adds quotation marks ([#545](https://github.com/flet-dev/flet/issues/545)) ## 0.1.63 @@ -1100,4 +1332,4 @@ Fix ElevatedButton regression ([9540beb](https://github.com/flet-dev/flet/commit ## 0.1.4 -* mkdir server/server/content \ No newline at end of file +* mkdir server/server/content diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..916282ac78 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at hello@flet.dev. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc319d51bd..60f68e536e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,31 @@ Thank you for your interest in contributing to Flet! +## Contents + +- [Clone repo](#clone-repo) +- [Python SDK](#python-sdk) + - [Install uv](#install-uv) + - [Open worker directory](#open-worker-directory) + - [Install dependencies](#install-dependencies) + - [Check the installation](#check-the-installation) + - [Running tests](#running-tests) + - [Code formatting](#code-formatting) + - [pre-commit](#pre-commit) +- [Flutter client](#flutter-client) + - [Building the Flutter client](#building-the-flutter-client) + - [Running the Flutter client](#running-the-flutter-client) + - [Restarting/Rebuilding](#restartingrebuilding) +- [Development & Release Workflow](#development--release-workflow) + - [Branching strategy](#branching-strategy) + - [Contributor guidelines](#contributor-guidelines) + - [Starting a release cycle](#starting-a-release-cycle) + - [Publishing a pre-release](#publishing-a-pre-release) + - [Publishing a stable release](#publishing-a-stable-release) + - [Hotfixes](#hotfixes) + - [Release preparation steps](#release-preparation-steps) +- [New macOS environment for Flet developer](#new-macos-environment-for-flet-developer) + ## Clone repo ``` @@ -72,6 +97,9 @@ Pytest should be run with `uv run`: uv run pytest ``` +For details on running and updating integration tests (including golden images), +see [integration tests README](sdk/python/packages/flet/integration_tests/README.md). + ### Code formatting The project uses [Black](https://github.com/psf/black) formatting style. All `.py` files in a PR must be black-formatted. @@ -147,7 +175,7 @@ First, run `printenv | grep FLET` (or `gci env:* | findstr FLET` on Windows) in - To build the Flutter client for Web, run the below command: ``` flutter build web - ``` + ``` When the build is complete, a directory `client/build/web` will be created. ### Running the Flutter client @@ -182,21 +210,55 @@ You will be able to see the debugging outputs of the flet client in this termina uv run flet run -w -p 8550 playground/ ``` -## Releasing Flet +## Development & Release Workflow + +### Branching strategy + +* **`main`** — always contains the latest stable release. Protected branch. +* **`release/v{version}`** — integration branch for the next release, for example `release/v0.85.0`. Created from `main` at the start of a release cycle. +* **`feature/*`**, **`fix/*`** — short-lived branches created from the release branch and merged back into it via PR. + +### Contributor guidelines + +* Target your PRs to the active `release/v{version}` branch (not `main`). +* Add a new changelog record to the active release section in the root `CHANGELOG.md` in every PR targeting `release/v{version}`. +* Assign the release milestone to all related issues and PRs. + +### Starting a release cycle + +1. Create a new GitHub milestone for the version (e.g., `0.85.0`). +2. Create a `release/v{version}` branch from `main`. +3. Update package version to `{version}` in `packages/flet/pubspec.yaml`. +4. Add `## {version}` into `CHANGELOG.md` and `packages/flet/CHANGELOG.md`. +5. Require every PR targeting `release/v{version}` to append a new record to the active root changelog section. + +### Publishing a pre-release + +1. On the release branch, create and push a tag with the format `vX.Y.Z.devN` (start from `dev0`, e.g., `v0.85.0.dev0`). +2. CI builds and runs all tests. If everything passes, it creates a pre-release GitHub Release and publishes pre-release packages to PyPI. Pre-releases are **not** published to pub.dev. +3. Increment `N` for each subsequent pre-release (`dev1`, `dev2`, ...). + +### Publishing a stable release + +1. Prepare the release on the release branch (see [Release preparation steps](#release-preparation-steps) below). +2. Create `Flet {version}` PR from `release/v{version}` into `main`. +3. Merge into `main` using a **regular merge** (not squash). +4. Create and push a `v{version}` tag on `main` (e.g., `v0.85.0`). +5. CI publishes to PyPI, pub.dev, and creates a GitHub Release. +6. Close the milestone — mark remaining issues as fixed. +7. Delete the `release/v{version}` branch. +8. Clean up pre-release GitHub Releases and pre-release versions on PyPI. + +### Hotfixes + +For patches to the current stable release, branch directly from `main`, fix, open a PR back to `main`, merge and tag. + +### Release preparation steps -* Create a new `prepare-{version}` branch in [flet-dev/flet](https://github.com/flet-dev/flet) repository. -* For every package in `packages/flet*` directory: - * Update package version to `{version}` in `pubspec.yaml`. - * Add `# {version}` with new/changed/fixed items into `CHANGELOG.md`. Only `packages/flet/CHANGELOG.md` should contain real items; other packages could have just a stub. -* Copy `# {version}` section from `packages/flet/CHANGELOG.md` to the root `CHANGELOG.md`. +* Keep the `## {version}` section in `packages/flet/CHANGELOG.md` in sync with the root `CHANGELOG.md` before tagging the release. +* Ensure every merged PR on `release/v{version}` added a new record to the active root `CHANGELOG.md` section. * Open terminal in `client` directory and run `flutter pub get` to update Flet dependency versions in `client/pubspec.lock`. -* Create a new `{version}` branch in [flet-dev/flet-app-templates](https://github.com/flet-dev/flet-app-templates) repository from a previously released `{current-version}` branch. -* Create a new `{version}` branch in [flet-dev/flet-build-template](https://github.com/flet-dev/flet-build-template) repository from a previously released `{current-version}` branch. -* Create `Prepare Flet {version}` PR to merge into `main` branch. -* In `Build Flet package for Flutter` job of [Flet CI build](https://ci.appveyor.com/project/flet-dev/flet) make sure analysis report of every `flet*` Flutter package has only 1 issue "Publishable packages can't have 'path' dependencies.". -* Merge `Prepare Flet {version}` PR. -* Create and push new `v{version}` tag (with `v` prefix). -* Update release notes at `https://github.com/flet-dev/flet/releases/tag/v{version}`. +* Templates are in `sdk/python/templates/` and automatically packaged as zip artifacts with the GitHub Release. No manual branch creation in external repos is needed. ## New macOS environment for Flet developer diff --git a/README.md b/README.md index a8bd90f0fd..8fdde30dc5 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,70 @@ -# Flet +

+ Flet logo +

- +

+ Build multi-platform apps in Python. No frontend experience required. +

-[![Build status](https://ci.appveyor.com/api/projects/status/xwablctxslvey576/branch/main?svg=true)](https://ci.appveyor.com/project/flet-dev/flet/branch/main) +

+ + License + + Package version + + Monthly downloads + + Python >= 3.10 + + Build status + + Docstring coverage +

-Flet is a framework that enables you to easily build real-time web, mobile, and desktop apps in your favorite language and securely share them with your team. No frontend experience is required. +--- -### ⚡From idea to app in minutes +Flet is a framework that allows building mobile, desktop and web applications +in Python only without prior experience in frontend development. -An internal tool or a dashboard for your team, weekend project, data entry form, kiosk app, or high-fidelity prototype - Flet is an ideal framework to quickly hack great-looking interactive apps to serve a group of users. +###    Single code base for any device -### 📐 Simple architecture +Your app will equally look great on iOS, Android, Windows, Linux, macOS and web. -No more complex architecture with JavaScript frontend, REST API backend, database, cache, etc. With Flet you just write a monolith stateful app in Python only and get multi-user, real-time Single-Page Application (SPA). +###    Build an entire app in Python -### 🔋Batteries included +Build a cross-platform app without knowledge of Dart, Swift, Kotlin, HTML or JavaScript - only Python! -To start developing with Flet, you just need your favorite IDE or text editor. No SDKs, no thousands of dependencies, no complex tooling - Flet has a built-in web server with assets hosting and desktop clients. +###    150+ built-in controls and services -###    Powered by Flutter +Beautiful UI widgets with Material and Cupertino design: layout, navigation, dialogs, charts - Flet uses Flutter to render UI. -Flet UI is built with [Flutter](https://flutter.dev/), so your app looks professional and could be delivered to any platform. Flet simplifies the Flutter model by combining smaller "widgets" to ready-to-use "controls" with an imperative programming model. +###    50+ Python packages for iOS and Android -### 🌐 Speaks your language +Numpy, pandas, pydantic, cryptography, opencv, pillow and other popular libraries. -Flet is language-agnostic, so anyone on your team could develop Flet apps in their favorite language. [Python](https://flet.dev/docs/guides/python/getting-started) is already supported, Go, C# and others are [coming next](https://flet.dev/roadmap). +###    Full web support -### 📱 Deliver to any device +Flet apps run natively in modern browsers using WebAssembly and Pyodide, with no server required. Prefer server-side? Deploy as a Python web app with real-time UI updates. -Deploy Flet app as a web app and view it in a browser. Package it as a standalone desktop app for Windows, macOS, and Linux. Install it on mobile as [PWA](https://web.dev/what-are-pwas/) or view via Flet app for iOS and Android. +###    Built-in packaging -## Flet app example +Build standalone executables or bundles for iOS, Android, Windows, Linux, macOS and web. Instantly deploy to App Store and Google Play. + +###    Test on iOS and Android + +Test your project on your own mobile device with Flet App. See your app updates as you make changes. + +###    Extensible + +Easily wrap any of thousands of Flutter packages to use with Flet or build new controls in pure Python using built-in UI primitives. + +###    Accessible + +Flet is built with Flutter which has solid accessibility foundations on Android, iOS, web, and desktop. -At the moment you can write Flet apps in Python and other languages will be added soon. +## Flet app example -Here is a sample "Counter" app: +Below is a simple "Counter" app, with a text field and two buttons to increment and decrement the counter value: ```python title="counter.py" import flet as ft @@ -43,78 +73,71 @@ def main(page: ft.Page): page.title = "Flet counter example" page.vertical_alignment = ft.MainAxisAlignment.CENTER - txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + input = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) def minus_click(e): - txt_number.value = str(int(txt_number.value) - 1) - page.update() + input.value = str(int(input.value) - 1) def plus_click(e): - txt_number.value = str(int(txt_number.value) + 1) - page.update() + input.value = str(int(input.value) + 1) page.add( ft.Row( - [ + alignment=ft.MainAxisAlignment.CENTER, + controls=[ ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), - txt_number, + input, ft.IconButton(ft.Icons.ADD, on_click=plus_click), ], - alignment=ft.alignment.center, ) ) -ft.app(main) +ft.run(main) ``` -To run the app install `flet` module: +To run the app, install `flet`: ```bash -pip install flet +pip install 'flet[all]' ``` -and run the program: +then launch the app: ```bash -python counter.py +flet run counter.py ``` -The app will be started in a native OS window - what a nice alternative to Electron! - - +This will open the app in a native OS window - what a nice alternative to Electron! 🙂 +

+ +

-Now, if you want to run the app as a web app, just replace the last line with: +To run the same app as a web app use `--web` option with `flet run` command: -```python -flet.app(target=main, view=flet.AppView.WEB_BROWSER) +```bash +flet run --web counter.py ``` -run again and now you instantly get a web app: - - - -## Getting started - -* [Creating Flet apps in Python](https://flet.dev/docs/guides/python/getting-started) -* [Controls reference](https://flet.dev/docs/controls) - -## Sample apps in Python +

+ +

-* [Greeter](https://github.com/flet-dev/examples/blob/main/python/apps/greeter/greeter.py) ([Online Demo](https://gallery.flet.dev/greeter/)) -* [Counter](https://github.com/flet-dev/examples/blob/main/python/apps/counter/counter.py) ([Online Demo](https://gallery.flet.dev/counter/)) -* [To-Do](https://github.com/flet-dev/examples/blob/main/python/apps/todo/todo.py) ([Online Demo](https://gallery.flet.dev/todo/)) -* [Icons Browser](https://github.com/flet-dev/examples/blob/main/python/apps/icons-browser/main.py) ([Online Demo](https://gallery.flet.dev/icons-browser/)) +## Learn more -More demo applications can be found in the [gallery](https://flet.dev/gallery/). +* [Website](https://flet.dev) +* [Documentation](https://flet.dev/docs/) +* [Roadmap](https://flet.dev/roadmap) +* [Apps Gallery](https://flet.dev/gallery) ## Community * [Discussions](https://github.com/flet-dev/flet/discussions) * [Discord](https://discord.gg/dzWXP8SHG8) -* [Twitter](https://twitter.com/fletdev) -* [Email](mailto:hello@flet.dev) +* [X (Twitter)](https://twitter.com/fletdev) +* [Bluesky](https://bsky.app/profile/fletdev.bsky.social) +* [Email us](mailto:hello@flet.dev) -## Contribute to this wonderful project +## Contributing -* Read the CONTRIBUTING.md file +Want to help improve Flet? Check out the [contribution guide](https://flet.dev/docs/contributing). diff --git a/ci/clean-pypi.sh b/ci/clean-pypi.sh deleted file mode 100644 index f05605302c..0000000000 --- a/ci/clean-pypi.sh +++ /dev/null @@ -1,7 +0,0 @@ -# set PYPI_CLEANUP_PASSWORD with pypi.org password -VER="0\.28\.0\.dev" -#VER="0\.21\.1" -pypi-cleanup -u flet -p flet -y -r $VER --do-it -pypi-cleanup -u flet -p flet-cli -y -r $VER --do-it -pypi-cleanup -u flet -p flet-desktop -y -r $VER --do-it -pypi-cleanup -u flet -p flet-web -y -r $VER --do-it \ No newline at end of file diff --git a/ci/common.sh b/ci/common.sh deleted file mode 100644 index 422bb0a315..0000000000 --- a/ci/common.sh +++ /dev/null @@ -1,34 +0,0 @@ -export root=$APPVEYOR_BUILD_FOLDER -export flet_sdk_root=$root/sdk/python -echo "flet_sdk_root: $flet_sdk_root" - -python --version -pip install --upgrade setuptools wheel twine tomlkit -curl -LsSf https://astral.sh/uv/install.sh | sh -export PATH="$HOME/.local/bin:$PATH" - -function patch_python_package_versions() { - PYPI_VER="${APPVEYOR_BUILD_VERSION/+/.dev}" - sed -i -e "s/version = \"\"/version = \"$PYPI_VER\"/g" $flet_sdk_root/packages/flet/src/flet/version.py - sed -i -e "s/version = \"\"/version = \"$PYPI_VER\"/g" $flet_sdk_root/packages/flet-cli/src/flet_cli/version.py - sed -i -e "s/version = \"\"/version = \"$PYPI_VER\"/g" $flet_sdk_root/packages/flet-desktop/src/flet_desktop/version.py - sed -i -e "s/version = \"\"/version = \"$PYPI_VER\"/g" $flet_sdk_root/packages/flet-web/src/flet_web/version.py - python3 $root/ci/patch_toml_versions.py $flet_sdk_root/packages/flet/pyproject.toml $PYPI_VER - python3 $root/ci/patch_toml_versions.py $flet_sdk_root/packages/flet-cli/pyproject.toml $PYPI_VER - python3 $root/ci/patch_toml_versions.py $flet_sdk_root/packages/flet-desktop/pyproject.toml $PYPI_VER - python3 $root/ci/patch_toml_versions.py $flet_sdk_root/packages/flet-web/pyproject.toml $PYPI_VER -} - -function patch_flet_desktop_package_name() { - python3 $root/ci/patch_toml_package_name.py $flet_sdk_root/packages/flet-desktop/pyproject.toml $1 -} - -function publish_to_pypi() { - if [[ ("$APPVEYOR_REPO_BRANCH" == "main" || "$APPVEYOR_REPO_TAG_NAME" != "") && "$APPVEYOR_PULL_REQUEST_NUMBER" == "" ]]; then - twine upload "$@" - elif [[ "$APPVEYOR_PULL_REQUEST_NUMBER" == "" ]]; then - for wheel in "$@"; do - curl -F package=@$wheel https://$GEMFURY_TOKEN@push.fury.io/flet/ - done - fi -} \ No newline at end of file diff --git a/ci/generate_cupertino_icons_dart.sh b/ci/generate_cupertino_icons_dart.sh deleted file mode 100644 index 0a80b1ae37..0000000000 --- a/ci/generate_cupertino_icons_dart.sh +++ /dev/null @@ -1,15 +0,0 @@ -url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/cupertino/icons.dart' -output_file="cupertino_icons.txt" - -echo "Map cupertinoIcons = {" > "$output_file" - -curl -s $url | python -c ' -import re - -for line in __import__("sys").stdin: - match = re.search(r"const IconData ([a-z0-9_]+)", line) - if match: - print("\"cupertino_{}\": CupertinoIcons.{}, ".format(match.group(1), match.group(1))) -' >> "$output_file" - -echo "};" >> "$output_file" \ No newline at end of file diff --git a/ci/generate_cupertino_icons_python.sh b/ci/generate_cupertino_icons_python.sh deleted file mode 100644 index c9fd2fca76..0000000000 --- a/ci/generate_cupertino_icons_python.sh +++ /dev/null @@ -1,11 +0,0 @@ -url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/cupertino/icons.dart' -output_file="cupertino_icons_python.txt" - -curl -s $url | python -c ' -import re - -for line in __import__("sys").stdin: - match = re.search(r"const IconData ([a-z0-9_]+)", line) - if match: - print("{} = \"cupertino_{}\"".format(match.group(1).upper(), match.group(1))) -' >> "$output_file" \ No newline at end of file diff --git a/ci/generate_material_icons_dart.sh b/ci/generate_material_icons_dart.sh deleted file mode 100644 index 5006b844bb..0000000000 --- a/ci/generate_material_icons_dart.sh +++ /dev/null @@ -1,15 +0,0 @@ -url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/material/icons.dart' -output_file="material-icons.txt" - -echo "Map materialIcons = {" > "$output_file" - -curl -s $url | python -c ' -import re - -for line in __import__("sys").stdin: - match = re.search(r"const IconData ([a-z0-9_]+)", line) - if match: - print("\"{}\": Icons.{}, ".format(match.group(1), match.group(1))) -' >> "$output_file" - -echo "};" >> "$output_file" \ No newline at end of file diff --git a/ci/generate_material_icons_python.sh b/ci/generate_material_icons_python.sh deleted file mode 100644 index b5974b470a..0000000000 --- a/ci/generate_material_icons_python.sh +++ /dev/null @@ -1,11 +0,0 @@ -url='https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/src/material/icons.dart' -output_file="material_icons_python.txt" - -curl -s $url | python -c ' -import re - -for line in __import__("sys").stdin: - match = re.search(r"const IconData ([a-z0-9_]+)", line) - if match: - print("{} = \"{}\"".format(match.group(1).upper(), match.group(1))) -' >> "$output_file" \ No newline at end of file diff --git a/ci/install_flutter.sh b/ci/install_flutter.sh deleted file mode 100644 index 36d1477167..0000000000 --- a/ci/install_flutter.sh +++ /dev/null @@ -1,5 +0,0 @@ -dart pub global activate fvm -export PATH=$HOME/.pub-cache/bin:$HOME/fvm/default/bin:$PATH -fvm install $FLUTTER_VERSION -fvm global $FLUTTER_VERSION -flutter --version \ No newline at end of file diff --git a/ci/patch_pubspec.py b/ci/patch_pubspec.py deleted file mode 100644 index 9a44c1792a..0000000000 --- a/ci/patch_pubspec.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -import pathlib -import sys - -import yaml - -if len(sys.argv) < 3: - print("Specify pubspec.yaml file and version to patch") - sys.exit(1) - -current_dir = pathlib.Path(os.getcwd()) -pubspec_path = current_dir.joinpath(current_dir, sys.argv[1]) -ver = sys.argv[2] -print(f"Patching pubspec.yaml file {pubspec_path} with {ver}") - -dependencies = [ - "flet", -] - -with open(pubspec_path, "r") as f: - data = yaml.safe_load(f) - - # patch version - data["version"] = ver - - # patch dependencies - for dep in data["dependencies"]: - if dep in dependencies: - data["dependencies"][dep] = f"^{ver}" - # print(dep) -with open(pubspec_path, "w") as file: - yaml.dump(data, file, sort_keys=False) diff --git a/ci/patch_toml_package_name.py b/ci/patch_toml_package_name.py deleted file mode 100644 index 9c7cb299f6..0000000000 --- a/ci/patch_toml_package_name.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import pathlib -import sys - -import tomlkit - -if len(sys.argv) < 2: - print("Specify toml file and a new package name") - sys.exit(1) - -current_dir = pathlib.Path(os.getcwd()) -toml_path = current_dir.joinpath(current_dir, sys.argv[1]) -package_name = sys.argv[2] -print(f"Patching TOML file {toml_path} to {package_name}") - -# read -with open(toml_path, "r") as f: - t = tomlkit.parse(f.read()) - -# patch name -t["project"]["name"] = package_name - -# save -with open(toml_path, "w") as f: - f.write(tomlkit.dumps(t)) diff --git a/ci/patch_toml_versions.py b/ci/patch_toml_versions.py deleted file mode 100644 index cf40bee2bb..0000000000 --- a/ci/patch_toml_versions.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -import pathlib -import sys - -import tomlkit - -if len(sys.argv) < 3: - print("Specify toml file and version to patch") - sys.exit(1) - -current_dir = pathlib.Path(os.getcwd()) -toml_path = current_dir.joinpath(current_dir, sys.argv[1]) -ver = sys.argv[2] -print(f"Patching TOML file {toml_path} to {ver}") - -# read -with open(toml_path, "r") as f: - t = tomlkit.parse(f.read()) - -# patch version -t["project"]["version"] = ver - -# patch dependencies -deps: list[str] = t["project"]["dependencies"] - - -def patch_dep(dep_name): - for i in range(0, len(deps)): - dep = deps[i] - if dep == dep_name: - deps[i] = f"{dep_name}=={ver}" - elif dep.startswith(f"{dep_name};"): - deps[i] = dep.replace(f"{dep_name};", f"{dep_name}=={ver};") - - -patch_dep("flet-cli") -patch_dep("flet-desktop") -patch_dep("flet-web") -patch_dep("flet") - -# save -with open(toml_path, "w") as f: - f.write(tomlkit.dumps(t)) diff --git a/ci/repackage_wheel_with_tag.py b/ci/repackage_wheel_with_tag.py deleted file mode 100644 index 111267113f..0000000000 --- a/ci/repackage_wheel_with_tag.py +++ /dev/null @@ -1,62 +0,0 @@ -import os -import sys -import tempfile -from pathlib import Path - -import wheel.cli.pack -import wheel.cli.unpack - - -def repackage_wheel(wheel_path, new_tag): - - wheel_path = os.path.realpath(wheel_path) - print(f"Re-packaging wheel {wheel_path} with {new_tag}") - - # Create temporary directory - with tempfile.TemporaryDirectory() as tmp_dir: - tmp_dir_path = Path(tmp_dir) - - # Unpack the wheel file - wheel.cli.unpack.unpack(wheel_path, tmp_dir) - - # Print directory structure - for root, dirs, files in os.walk(tmp_dir): - for name in files: - print(os.path.join(root, name)) - for name in dirs: - print(os.path.join(root, name)) - - # Get unpacked wheel directory - wheel_dirs = list(tmp_dir_path.glob("flet_*")) - if not wheel_dirs: - raise FileNotFoundError("Unpacked wheel directory not found.") - wheel_dir = wheel_dirs[0] - print(f"wheel temp dir: {wheel_dir}") - - # Change into the unpacked wheel directory - os.chdir(wheel_dir) - - # Process metadata files and replace the tag - metadata_files = list(wheel_dir.glob("*.dist-info/WHEEL")) - for metadata_file in metadata_files: - with open(metadata_file, "r") as f: - content = f.read() - new_content = content.replace( - "Tag: py3-none-any", - "\n".join([f"Tag: {t}" for t in new_tag.split(",")]), - ) - with open(metadata_file, "w") as f: - f.write(new_content) - print(new_content) - - # Repack the wheel - wheel.cli.pack.pack(".", str(Path(wheel_path).parent), None) - - print(f"Successfully generated {wheel_path} with {new_tag} tag.") - - -if len(sys.argv) < 3: - print("Specify path to wheel and a new tag") - sys.exit(1) - -repackage_wheel(sys.argv[1], sys.argv[2]) diff --git a/ci/update-flet-wheel-deps.py b/ci/update-flet-wheel-deps.py deleted file mode 100644 index b241c824da..0000000000 --- a/ci/update-flet-wheel-deps.py +++ /dev/null @@ -1,103 +0,0 @@ -import os -import re -import sys -import tempfile -from pathlib import Path - -import wheel.cli.pack -import wheel.cli.unpack - - -# Get all wheel file paths -def find_wheel_files(directory): - wheel_files = list(Path(directory).glob("flet-*.whl")) - if not wheel_files: - print("No files found matching the pattern flet-*.whl") - return [] - return [str(wheel_file.resolve()) for wheel_file in wheel_files] - - -# Extract version from the wheel file name -def extract_version(wheel_file): - match = re.search(r".*-([0-9]+[^-]+)-.*", wheel_file) - if match: - return match.group(1) - return None - - -# Process the METADATA file -def update_metadata(metadata_file, version): - with open(metadata_file, "r") as file: - lines = file.readlines() - - i = 0 - while i < len(lines): - # insert Requires-Dist: flet-desktop-light ... - if lines[i].startswith("Requires-Dist: flet-desktop=="): - lines.insert( - i + 1, - f'Requires-Dist: flet-desktop-light=={version}; platform_system == "Linux" and (extra == "all" or extra == "desktop")\n', - ) - lines[i] = re.sub( - r'platform_system != "desktop-light"', - "(platform_system == 'Darwin' or platform_system == 'Windows') and 'embedded' not in platform_version", - lines[i], - ) - lines[i] = re.sub( - r'platform_system != "embedded"', - "(platform_system == 'Darwin' or platform_system == 'Linux' or platform_system == 'Windows') and 'embedded' not in platform_version", - lines[i], - ) - i += 1 - - with open(metadata_file, "w") as file: - file.writelines(lines) - - -# Main logic -def process_wheels(directory): - # Find all wheel files - wheel_files = find_wheel_files(directory) - if not wheel_files: - return - - for wheel_file in wheel_files: - print(f"Found file: {wheel_file}") - - # Extract version from the wheel file name - version = extract_version(wheel_file) - if not version: - print(f"Unable to extract version from wheel file: {wheel_file}") - continue - - print(f"Version: {version}") - - # Create a temporary directory - with tempfile.TemporaryDirectory() as tmp_dir: - # Unpack the wheel file - wheel.cli.unpack.unpack(wheel_file, tmp_dir) - - # Get the unpacked wheel directory - unpacked_wheel_dir = next(Path(tmp_dir).glob("flet-*")).resolve() - print(f"Wheel temp dir: {unpacked_wheel_dir}") - - # Process the METADATA file - metadata_files = list(unpacked_wheel_dir.glob("*.dist-info/METADATA")) - for metadata_file in metadata_files: - update_metadata(metadata_file, version) - print(f"Updated METADATA file: {metadata_file}") - - # Remove the old wheel file - os.remove(wheel_file) - - # Repack the wheel - wheel.cli.pack.pack(unpacked_wheel_dir, os.path.dirname(wheel_file), None) - - print("Successfully updated flet-*.whl with platform-specific dependencies.") - - -if len(sys.argv) < 2: - print("Specify path to dist") - sys.exit(1) - -process_wheels(sys.argv[1]) diff --git a/client/.fvmrc b/client/.fvmrc deleted file mode 100644 index b987073ac6..0000000000 --- a/client/.fvmrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "flutter": "3.29.3" -} \ No newline at end of file diff --git a/client/.metadata b/client/.metadata index e724e168b0..9c601526af 100644 --- a/client/.metadata +++ b/client/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "5dcb86f68f239346676ceb1ed1ea385bd215fba1" + revision: "6fba2447e95c451518584c35e25f5433f14d888c" channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 - base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 - - platform: linux - create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 - base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1 + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c + - platform: android + create_revision: 6fba2447e95c451518584c35e25f5433f14d888c + base_revision: 6fba2447e95c451518584c35e25f5433f14d888c # User provided section diff --git a/client/android/.gitignore b/client/android/.gitignore index 6f568019d3..be3943c96d 100644 --- a/client/android/.gitignore +++ b/client/android/.gitignore @@ -5,9 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/client/android/app/build.gradle b/client/android/app/build.gradle deleted file mode 100644 index 5fea8634e2..0000000000 --- a/client/android/app/build.gradle +++ /dev/null @@ -1,68 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -android { - namespace "com.appveyor.flet" - compileSdkVersion flutter.compileSdkVersion - ndkVersion "25.1.8937393" - - packagingOptions { - jniLibs { - useLegacyPackaging true - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - applicationId "com.appveyor.flet" - minSdkVersion 23 - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - } - - buildTypes { - release { - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies {} diff --git a/client/android/app/build.gradle.kts b/client/android/app/build.gradle.kts new file mode 100644 index 0000000000..41100f0452 --- /dev/null +++ b/client/android/app/build.gradle.kts @@ -0,0 +1,42 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.appveyor.flet_client" + compileSdk = flutter.compileSdkVersion + ndkVersion = "27.0.12077973" + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + applicationId = "com.appveyor.flet_client" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/client/android/app/src/debug/AndroidManifest.xml b/client/android/app/src/debug/AndroidManifest.xml index ab62067855..3d830f96d6 100644 --- a/client/android/app/src/debug/AndroidManifest.xml +++ b/client/android/app/src/debug/AndroidManifest.xml @@ -1,9 +1,25 @@ - + - + + + + + + + + + + + + + + + + diff --git a/client/android/app/src/main/AndroidManifest.xml b/client/android/app/src/main/AndroidManifest.xml index 29ebfbb351..489daa779d 100644 --- a/client/android/app/src/main/AndroidManifest.xml +++ b/client/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,4 @@ - + - + android:icon="@mipmap/ic_launcher" + android:enableOnBackInvokedCallback="true"> + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> - - + + + + + - \ No newline at end of file + + + + + + + + diff --git a/client/android/app/src/main/kotlin/com/appveyor/flet/MainActivity.kt b/client/android/app/src/main/kotlin/com/appveyor/flet/MainActivity.kt deleted file mode 100644 index 2f1af7f7d4..0000000000 --- a/client/android/app/src/main/kotlin/com/appveyor/flet/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.appveyor.flet - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/client/android/app/src/main/kotlin/com/appveyor/flet_client/MainActivity.kt b/client/android/app/src/main/kotlin/com/appveyor/flet_client/MainActivity.kt new file mode 100644 index 0000000000..09f79c6fdf --- /dev/null +++ b/client/android/app/src/main/kotlin/com/appveyor/flet_client/MainActivity.kt @@ -0,0 +1,5 @@ +package com.appveyor.flet_client + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/client/android/app/src/main/res/xml/provider_paths.xml b/client/android/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000000..89a7e378cb --- /dev/null +++ b/client/android/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/client/android/app/src/profile/AndroidManifest.xml b/client/android/app/src/profile/AndroidManifest.xml index ab62067855..3d830f96d6 100644 --- a/client/android/app/src/profile/AndroidManifest.xml +++ b/client/android/app/src/profile/AndroidManifest.xml @@ -1,9 +1,25 @@ - + - + + + + + + + + + + + + + + + + diff --git a/client/android/build.gradle b/client/android/build.gradle deleted file mode 100644 index 52d31f3769..0000000000 --- a/client/android/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - ext.kotlin_version = '1.9.24' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/client/android/build.gradle.kts b/client/android/build.gradle.kts new file mode 100644 index 0000000000..89176ef44e --- /dev/null +++ b/client/android/build.gradle.kts @@ -0,0 +1,21 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/client/android/gradle.properties b/client/android/gradle.properties index 94adc3a3f9..f018a61817 100644 --- a/client/android/gradle.properties +++ b/client/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/client/android/gradle/wrapper/gradle-wrapper.properties b/client/android/gradle/wrapper/gradle-wrapper.properties index a35eb1fa3b..02767eb1ca 100644 --- a/client/android/gradle/wrapper/gradle-wrapper.properties +++ b/client/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/client/android/settings.gradle b/client/android/settings.gradle deleted file mode 100644 index b64b2eb734..0000000000 --- a/client/android/settings.gradle +++ /dev/null @@ -1,29 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - } - settings.ext.flutterSdkPath = flutterSdkPath() - - includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } - - plugins { - id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.3.1" apply false -} - -include ":app" diff --git a/client/android/settings.gradle.kts b/client/android/settings.gradle.kts new file mode 100644 index 0000000000..38573a4d5b --- /dev/null +++ b/client/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.12.1" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/client/integration_test/app_test.dart b/client/integration_test/app_test.dart index 219301a068..9659913c55 100644 --- a/client/integration_test/app_test.dart +++ b/client/integration_test/app_test.dart @@ -5,36 +5,41 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -void main() { - IntegrationTestWidgetsFlutterBinding.ensureInitialized(); +import 'flutter_tester.dart'; - tearDown(() { - debugPrint("TEAR DOWN"); - }); +void main() { + var binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); group('end-to-end test', () { - testWidgets('tap on the floating action button, verify counter', - (tester) async { + testWidgets('test app', (tester) async { var dir = Directory.current.path; debugPrint("Current dir: $dir"); - app.main(); - await tester.pumpAndSettle(const Duration(milliseconds: 100), - EnginePhase.sendSemanticsUpdate, const Duration(seconds: 20)); - // Verify the counter starts at 0. - expect(find.text('0'), findsOneWidget); + app.tester = FlutterWidgetTester(tester, binding); + + List args = []; + const fletTestAppUrl = String.fromEnvironment("FLET_TEST_APP_URL"); + if (fletTestAppUrl != "") { + args.add(fletTestAppUrl); + } - // Finds the floating action button to tap on. - final Finder fab = find.byTooltip('Increment'); + const fletTestPidFile = String.fromEnvironment("FLET_TEST_PID_FILE_PATH"); + if (fletTestPidFile != "") { + args.add(fletTestPidFile); + } - // Emulate a tap on the floating action button. - await tester.tap(fab); + const fletTestAssetsDir = String.fromEnvironment("FLET_TEST_ASSETS_DIR"); + if (fletTestAssetsDir != "") { + args.add(fletTestAssetsDir); + } - // Trigger a frame. - await tester.pumpAndSettle(); + app.main(args); - // Verify the counter increments by 1. - expect(find.text('1'), findsOneWidget); + await Future.delayed(const Duration(milliseconds: 500)); + await app.tester?.pump(duration: const Duration(seconds: 1)); + await app.tester + ?.pumpAndSettle(duration: const Duration(milliseconds: 100)); + await app.tester?.waitForTeardown(); }); }); } diff --git a/client/integration_test/flutter_test_finder.dart b/client/integration_test/flutter_test_finder.dart new file mode 100644 index 0000000000..645852a63f --- /dev/null +++ b/client/integration_test/flutter_test_finder.dart @@ -0,0 +1,14 @@ +import 'package:flet/flet.dart'; +import 'package:flutter_test/flutter_test.dart'; + +class FlutterTestFinder extends TestFinder { + final Finder finder; + + FlutterTestFinder(this.finder) : super(); + + @override + int get count => finder.evaluate().length; + + @override + Finder get raw => finder; +} diff --git a/client/integration_test/flutter_tester.dart b/client/integration_test/flutter_tester.dart new file mode 100644 index 0000000000..49bb544e4d --- /dev/null +++ b/client/integration_test/flutter_tester.dart @@ -0,0 +1,198 @@ +import 'dart:async'; +import 'package:flet/flet.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'flutter_test_finder.dart'; + +class FlutterWidgetTester implements Tester { + final WidgetTester _tester; + final IntegrationTestWidgetsFlutterBinding _binding; + final lock = Lock(); + final Completer _teardown = Completer(); + TestGesture? _gesture; + + FlutterWidgetTester(this._tester, this._binding); + + @override + Future pumpAndSettle({Duration? duration}) async { + await lock.acquire(); + try { + await _tester.pumpAndSettle( + duration ?? const Duration(milliseconds: 100), + ); + } finally { + lock.release(); + } + } + + @override + Future pump({Duration? duration}) async { + await lock.acquire(); + try { + await _tester.pump(duration); + } finally { + lock.release(); + } + } + + @override + TestFinder findByText(String text) => FlutterTestFinder(find.text(text)); + + @override + TestFinder findByTextContaining(String pattern) => + FlutterTestFinder(find.textContaining(RegExp(pattern))); + + @override + TestFinder findByKey(Key key) => FlutterTestFinder(find.byKey(key)); + + @override + TestFinder findByTooltip(String value) => + FlutterTestFinder(find.byTooltip(value)); + + @override + TestFinder findByIcon(IconData icon) => FlutterTestFinder(find.byIcon(icon)); + + @override + Future takeScreenshot(String name) async { + if (defaultTargetPlatform != TargetPlatform.android && + defaultTargetPlatform != TargetPlatform.iOS) { + throw Exception( + "Full app screenshots are only available on Android and iOS.", + ); + } + if (defaultTargetPlatform == TargetPlatform.android) { + await _binding.convertFlutterSurfaceToImage(); + await _tester.pump(); + } + var bytes = await _binding.takeScreenshot(name); + return Uint8List.fromList(bytes); + } + + @override + Future tap(TestFinder finder, int finderIndex) => + _tester.tap((finder as FlutterTestFinder).raw.at(finderIndex)); + + @override + Future mouseClick(TestFinder finder, int finderIndex) async { + final center = _tester.getCenter( + (finder as FlutterTestFinder).raw.at(finderIndex), + ); + await _mouseClickAt(center, kPrimaryButton); + } + + @override + Future mouseDoubleClick(TestFinder finder, int finderIndex) async { + final center = _tester.getCenter( + (finder as FlutterTestFinder).raw.at(finderIndex), + ); + await _mouseDoubleClickAt(center); + } + + @override + Future rightMouseClick(TestFinder finder, int finderIndex) async { + final center = _tester.getCenter( + (finder as FlutterTestFinder).raw.at(finderIndex), + ); + await _mouseClickAt(center, kSecondaryButton); + } + + @override + Future tapAt(Offset offset) => + _tester.tapAt(offset); + + @override + Future mouseClickAt(Offset offset) => _mouseClickAt(offset, kPrimaryButton); + + @override + Future mouseDoubleClickAt(Offset offset) => _mouseDoubleClickAt(offset); + + @override + Future rightMouseClickAt(Offset offset) => + _mouseClickAt(offset, kSecondaryButton); + + @override + Future drag(TestFinder finder, int finderIndex, Offset offset) async { + final center = _tester.getCenter( + (finder as FlutterTestFinder).raw.at(finderIndex), + ); + await _dragFrom(center, offset); + } + + @override + Future dragFrom(Offset start, Offset offset) => _dragFrom(start, offset); + + @override + Future longPress(TestFinder finder, int finderIndex) => + _tester.longPress((finder as FlutterTestFinder).raw.at(finderIndex)); + + @override + Future enterText( + TestFinder finder, int finderIndex, String text) => + _tester.enterText( + (finder as FlutterTestFinder).raw.at(finderIndex), + text, + ); + + @override + Future mouseHover(TestFinder finder, int finderIndex) async { + final center = _tester.getCenter( + (finder as FlutterTestFinder).raw.at(finderIndex), + ); + + await _mouseExit(); + _gesture = await _tester.createGesture(kind: PointerDeviceKind.mouse); + await _gesture?.addPointer(); + await _gesture?.moveTo(center); + } + + Future _mouseClickAt(Offset offset, int buttons) async { + await _mouseExit(); + _gesture = await _tester.createGesture( + kind: PointerDeviceKind.mouse, + buttons: buttons, + ); + await _gesture?.addPointer(); + await _gesture?.moveTo(offset); + await _gesture?.down(offset); + await _gesture?.up(); + await _mouseExit(); + } + + Future _mouseDoubleClickAt(Offset offset) async { + await _mouseExit(); + _gesture = await _tester.createGesture( + kind: PointerDeviceKind.mouse, + buttons: kPrimaryButton, + ); + await _gesture?.addPointer(); + await _gesture?.moveTo(offset); + await _gesture?.down(offset); + await _gesture?.up(); + await _tester.pump(const Duration(milliseconds: 50)); + await _gesture?.down(offset); + await _gesture?.up(); + await _mouseExit(); + } + + Future _dragFrom(Offset start, Offset offset) async { + await _mouseExit(); + await _tester.dragFrom(start, offset); + } + + @override + void teardown() => _teardown.complete(); + + @override + Future waitForTeardown() => _teardown.future; + + Future _mouseExit() async { + if (_gesture != null) { + await _gesture?.removePointer(); + _gesture = null; + } + } +} diff --git a/client/ios/Flutter/AppFrameworkInfo.plist b/client/ios/Flutter/AppFrameworkInfo.plist index 7c56964006..1dc6cf7652 100644 --- a/client/ios/Flutter/AppFrameworkInfo.plist +++ b/client/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/client/ios/Podfile b/client/ios/Podfile index 279576f388..1685edd78a 100644 --- a/client/ios/Podfile +++ b/client/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '12.0' +# platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -37,5 +37,23 @@ end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) + + target.build_configurations.each do |config| + # You can remove unused permissions here + # for more information: https://github.com/Baseflow/flutter-permission-handler/blob/main/permission_handler_apple/ios/Classes/PermissionHandlerEnums.h + # e.g. when you don't need camera permission, just add 'PERMISSION_CAMERA=0' + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + + ## dart: PermissionGroup.microphone + 'PERMISSION_MICROPHONE=1', + + ## dart: PermissionGroup.photos + 'PERMISSION_PHOTOS=1', + + ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] + 'PERMISSION_LOCATION_WHENINUSE=1', + ] + end end end diff --git a/client/ios/Podfile.lock b/client/ios/Podfile.lock index f8585860b3..217a9b152a 100644 --- a/client/ios/Podfile.lock +++ b/client/ios/Podfile.lock @@ -1,6 +1,13 @@ PODS: - audioplayers_darwin (0.0.1): - Flutter + - FlutterMacOS + - battery_plus (1.0.0): + - Flutter + - camera_avfoundation (0.0.1): + - Flutter + - connectivity_plus (0.0.1): + - Flutter - device_info_plus (0.0.1): - Flutter - DKImagePickerController/Core (4.3.9): @@ -38,34 +45,34 @@ PODS: - DKImagePickerController/PhotoGallery - Flutter - Flutter (1.0.0) + - flutter_secure_storage_darwin (10.0.0): + - Flutter + - FlutterMacOS - geolocator_apple (1.2.0): - Flutter - - Google-Mobile-Ads-SDK (11.10.0): + - FlutterMacOS + - Google-Mobile-Ads-SDK (12.14.0): - GoogleUserMessagingPlatform (>= 1.1) - - google_mobile_ads (5.2.0): + - google_mobile_ads (7.0.0): - Flutter - - Google-Mobile-Ads-SDK (~> 11.10.0) + - Google-Mobile-Ads-SDK (~> 12.14.0) - webview_flutter_wkwebview - - GoogleUserMessagingPlatform (2.7.0) + - GoogleUserMessagingPlatform (3.1.0) - integration_test (0.0.1): - Flutter - media_kit_libs_ios_video (1.0.4): - Flutter - - media_kit_native_event_loop (1.0.0): - - Flutter - media_kit_video (0.0.1): - Flutter - package_info_plus (0.4.5): - Flutter - - path_provider_foundation (0.0.1): + - pasteboard (0.0.1): - Flutter - - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - - record_darwin (1.0.0): + - record_ios (1.2.0): - Flutter - - FlutterMacOS - - rive_common (0.0.1): + - rive_native (0.0.1): - Flutter - screen_brightness_ios (0.1.0): - Flutter @@ -74,6 +81,8 @@ PODS: - SDWebImage/Core (5.20.0) - sensors_plus (0.0.1): - Flutter + - share_plus (0.0.1): + - Flutter - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -82,8 +91,6 @@ PODS: - Flutter - url_launcher_ios (0.0.1): - Flutter - - volume_controller (0.0.1): - - Flutter - wakelock_plus (0.0.1): - Flutter - webview_flutter_wkwebview (0.0.1): @@ -91,27 +98,30 @@ PODS: - FlutterMacOS DEPENDENCIES: - - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) + - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`) + - battery_plus (from `.symlinks/plugins/battery_plus/ios`) + - camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`) + - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`) + - flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) - google_mobile_ads (from `.symlinks/plugins/google_mobile_ads/ios`) - integration_test (from `.symlinks/plugins/integration_test/ios`) - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) - - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - pasteboard (from `.symlinks/plugins/pasteboard/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - record_darwin (from `.symlinks/plugins/record_darwin/ios`) - - rive_common (from `.symlinks/plugins/rive_common/ios`) + - record_ios (from `.symlinks/plugins/record_ios/ios`) + - rive_native (from `.symlinks/plugins/rive_native/ios`) - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - sensors_plus (from `.symlinks/plugins/sensors_plus/ios`) + - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - torch_light (from `.symlinks/plugins/torch_light/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - volume_controller (from `.symlinks/plugins/volume_controller/ios`) - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) @@ -126,83 +136,92 @@ SPEC REPOS: EXTERNAL SOURCES: audioplayers_darwin: - :path: ".symlinks/plugins/audioplayers_darwin/ios" + :path: ".symlinks/plugins/audioplayers_darwin/darwin" + battery_plus: + :path: ".symlinks/plugins/battery_plus/ios" + camera_avfoundation: + :path: ".symlinks/plugins/camera_avfoundation/ios" + connectivity_plus: + :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter + flutter_secure_storage_darwin: + :path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin" geolocator_apple: - :path: ".symlinks/plugins/geolocator_apple/ios" + :path: ".symlinks/plugins/geolocator_apple/darwin" google_mobile_ads: :path: ".symlinks/plugins/google_mobile_ads/ios" integration_test: :path: ".symlinks/plugins/integration_test/ios" media_kit_libs_ios_video: :path: ".symlinks/plugins/media_kit_libs_ios_video/ios" - media_kit_native_event_loop: - :path: ".symlinks/plugins/media_kit_native_event_loop/ios" media_kit_video: :path: ".symlinks/plugins/media_kit_video/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" + pasteboard: + :path: ".symlinks/plugins/pasteboard/ios" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" - record_darwin: - :path: ".symlinks/plugins/record_darwin/ios" - rive_common: - :path: ".symlinks/plugins/rive_common/ios" + record_ios: + :path: ".symlinks/plugins/record_ios/ios" + rive_native: + :path: ".symlinks/plugins/rive_native/ios" screen_brightness_ios: :path: ".symlinks/plugins/screen_brightness_ios/ios" sensors_plus: :path: ".symlinks/plugins/sensors_plus/ios" + share_plus: + :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" torch_light: :path: ".symlinks/plugins/torch_light/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" - volume_controller: - :path: ".symlinks/plugins/volume_controller/ios" wakelock_plus: :path: ".symlinks/plugins/wakelock_plus/ios" webview_flutter_wkwebview: :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" SPEC CHECKSUMS: - audioplayers_darwin: ccf9c770ee768abb07e26d90af093f7bab1c12ab + audioplayers_darwin: 4f9ca89d92d3d21cec7ec580e78ca888e5fb68bd + battery_plus: b42253f6d2dde71712f8c36fef456d99121c5977 + camera_avfoundation: 5675ca25298b6f81fa0a325188e7df62cc217741 + connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - geolocator_apple: d981750b9f47dbdb02427e1476d9a04397beb8d9 - Google-Mobile-Ads-SDK: 13e6e98edfd78ad8d8a791edb927658cc260a56f - google_mobile_ads: dc2b2a5884bef7ab2b4ff30022a513df5373e208 - GoogleUserMessagingPlatform: a8b56893477f67212fbc8411c139e61d463349f5 + file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23 + geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e + Google-Mobile-Ads-SDK: 4534fd2dfcd3f705c5485a6633c5188d03d4eed2 + google_mobile_ads: df3008bafbe1f2ad6862f87334e560d2f047f902 + GoogleUserMessagingPlatform: befe603da6501006420c206222acd449bba45a9c integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 - media_kit_native_event_loop: 5fba1a849a6c87a34985f1e178a0de5bd444a0cf media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 - package_info_plus: 580e9a5f1b6ca5594e7c9ed5f92d1dfb2a66b5e1 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + pasteboard: 49088aeb6119d51f976a421db60d8e1ab079b63c permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - record_darwin: 1630616226de4038fa17cec21b11403ca510ec3e - rive_common: dd421daaf9ae69f0125aa761dd96abd278399952 - screen_brightness_ios: 5ed898fa50fa82a26171c086ca5e28228f932576 + record_ios: 412daca2350b228e698fffcd08f1f94ceb1e3844 + rive_native: c9ed76ccf380f38205edcb8f552121aac8ec39da + screen_brightness_ios: 9953fd7da5bd480f1a93990daeec2eb42d4f3b52 SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 - sensors_plus: 1c5f0a01ce21c609a4df404c4e6879d62bce287f - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sensors_plus: 6a11ed0c2e1d0bd0b20b4029d3bad27d96e0c65b + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 torch_light: d093d579a221a59ef8a6b8c0eca20d52f7178087 - url_launcher_ios: 694010445543906933d732453a59da0a173ae33d - volume_controller: ca1cde542ee70fad77d388f82e9616488110942b - wakelock_plus: fd58c82b1388f4afe3fe8aa2c856503a262a5b03 - webview_flutter_wkwebview: 44d4dee7d7056d5ad185d25b38404436d56c547c + url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b + wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 + webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d -PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011 +PODFILE CHECKSUM: 462a5b249f9f1900cbd87af7b6af48272dc2df5a COCOAPODS: 1.16.2 diff --git a/client/ios/Runner.xcodeproj/project.pbxproj b/client/ios/Runner.xcodeproj/project.pbxproj index 51ef87bc74..00bb254787 100644 --- a/client/ios/Runner.xcodeproj/project.pbxproj +++ b/client/ios/Runner.xcodeproj/project.pbxproj @@ -139,7 +139,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 58A4996EE779406784CD4C79 /* [CP] Embed Pods Frameworks */, - 2297FE9C08FD9A4A6B4637CC /* [CP] Copy Pods Resources */, + 66843B3D06C83DEA7E765D27 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -198,23 +198,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 2297FE9C08FD9A4A6B4637CC /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -270,6 +253,23 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; + 66843B3D06C83DEA7E765D27 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -360,7 +360,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -441,7 +441,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -490,7 +490,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c53e2b314e..9c12df59c6 100644 --- a/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/client/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> CADisableMinimumFrameDurationOnPhone - + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -25,7 +25,7 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS - + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile @@ -44,23 +44,38 @@ UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance - + ITSAppUsesNonExemptEncryption - - NSPhotoLibraryUsageDescription - The app needs access to photo library, so that photos can be selected. - GADApplicationIdentifier - ca-app-pub-3940256099942544~1458002511 + + UIApplicationSupportsIndirectInputEvents NSAppTransportSecurity NSAllowsArbitraryLoads - + + + + NSPhotoLibraryUsageDescription + The app needs access to photo library, so that photos can be selected. + + + GADApplicationIdentifier + ca-app-pub-3940256099942544~1458002511 + + + NSMicrophoneUsageDescription - Audio Recording + This app needs access to microphone. + + + NSLocationWhenInUseUsageDescription - This app needs access to location when open. + This app needs access to location. + + + NSCameraUsageDescription + This app uses the camera to capture photos and video. - \ No newline at end of file + diff --git a/client/lib/main.dart b/client/lib/main.dart index 69b68dce41..131338e54a 100644 --- a/client/lib/main.dart +++ b/client/lib/main.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:flet/flet.dart'; import 'package:flet_ads/flet_ads.dart' as flet_ads; // --FAT_CLIENT_START-- @@ -7,23 +5,37 @@ import 'package:flet_audio/flet_audio.dart' as flet_audio; // --FAT_CLIENT_END-- import 'package:flet_audio_recorder/flet_audio_recorder.dart' as flet_audio_recorder; +import 'package:flet_camera/flet_camera.dart' as flet_camera; +import 'package:flet_charts/flet_charts.dart' as flet_charts; +import 'package:flet_code_editor/flet_code_editor.dart' as flet_code_editor; +import 'package:flet_color_pickers/flet_color_pickers.dart' + as flet_color_picker; +import 'package:flet_datatable2/flet_datatable2.dart' as flet_datatable2; import "package:flet_flashlight/flet_flashlight.dart" as flet_flashlight; import 'package:flet_geolocator/flet_geolocator.dart' as flet_geolocator; import 'package:flet_lottie/flet_lottie.dart' as flet_lottie; import 'package:flet_map/flet_map.dart' as flet_map; import 'package:flet_permission_handler/flet_permission_handler.dart' as flet_permission_handler; +// --FAT_CLIENT_START-- +// --RIVE_IMPORT_START-- import 'package:flet_rive/flet_rive.dart' as flet_rive; +// --RIVE_IMPORT_END-- +// --FAT_CLIENT_END-- +import 'package:flet_secure_storage/flet_secure_storage.dart' + as flet_secure_storage; // --FAT_CLIENT_START-- import 'package:flet_video/flet_video.dart' as flet_video; // --FAT_CLIENT_END-- import 'package:flet_webview/flet_webview.dart' as flet_webview; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:url_strategy/url_strategy.dart'; +import 'package:flutter_web_plugins/url_strategy.dart'; const bool isProduction = bool.fromEnvironment('dart.vm.product'); +Tester? tester; + void main([List? args]) async { if (isProduction) { // ignore: avoid_returning_null_for_void @@ -33,20 +45,35 @@ void main([List? args]) async { await setupDesktop(); WidgetsFlutterBinding.ensureInitialized(); + List extensions = [ + flet_ads.Extension(), + flet_audio_recorder.Extension(), + flet_camera.Extension(), + flet_charts.Extension(), + flet_code_editor.Extension(), + flet_color_picker.Extension(), + flet_datatable2.Extension(), + flet_flashlight.Extension(), + flet_geolocator.Extension(), + flet_lottie.Extension(), + flet_map.Extension(), + flet_permission_handler.Extension(), + flet_secure_storage.Extension(), + flet_webview.Extension(), + + // --FAT_CLIENT_START-- + // --RIVE_EXTENSION_START-- + flet_rive.Extension(), + // --RIVE_EXTENSION_END-- + flet_audio.Extension(), + flet_video.Extension(), + // --FAT_CLIENT_END-- + ]; - // --FAT_CLIENT_START-- - flet_audio.ensureInitialized(); - flet_video.ensureInitialized(); - // --FAT_CLIENT_END-- - flet_audio_recorder.ensureInitialized(); - flet_geolocator.ensureInitialized(); - flet_permission_handler.ensureInitialized(); - flet_lottie.ensureInitialized(); - flet_map.ensureInitialized(); - flet_ads.ensureInitialized(); - flet_rive.ensureInitialized(); - flet_webview.ensureInitialized(); - flet_flashlight.ensureInitialized(); + // initialize extensions + for (var extension in extensions) { + extension.ensureInitialized(); + } var pageUrl = Uri.base.toString(); var assetsDir = ""; @@ -61,25 +88,26 @@ void main([List? args]) async { var routeUrlStrategy = getFletRouteUrlStrategy(); debugPrint("URL Strategy: $routeUrlStrategy"); if (routeUrlStrategy == "path") { - setPathUrlStrategy(); + usePathUrlStrategy(); } - } else if ((Platform.isWindows || Platform.isMacOS || Platform.isLinux) && - !kDebugMode) { - debugPrint("Flet View is running in Desktop mode"); - // first argument must exist - if (args!.isEmpty) { - throw Exception('Page URL must be provided as a first argument.'); - } - pageUrl = args[0]; - if (args.length > 1) { - var pidFilePath = args[1]; - debugPrint("Args contain a path to PID file: $pidFilePath}"); - var pidFile = await File(pidFilePath).create(); - await pidFile.writeAsString("$pid"); - } - if (args.length > 2) { - assetsDir = args[2]; - debugPrint("Args contain a path assets directory: $assetsDir}"); + assetsDir = getAssetsDir(); + } else { + if (args!.isNotEmpty) { + pageUrl = args[0]; + if (args.length > 1) { + var pidFilePath = args[1]; + debugPrint("Args contain a path to PID file: $pidFilePath}"); + var pidFile = await File(pidFilePath).create(); + await pidFile.writeAsString("$pid"); + } + if (args.length > 2) { + assetsDir = args[2]; + debugPrint("Args contain a path assets directory: $assetsDir}"); + } + } else if (!kDebugMode && + (Platform.isWindows || Platform.isMacOS || Platform.isLinux)) { + throw Exception( + 'In desktop mode Flet app URL must be provided as a first argument.'); } } @@ -98,26 +126,23 @@ void main([List? args]) async { }; } - runApp(FletApp( + var app = FletApp( title: 'Flet', pageUrl: pageUrl, assetsDir: assetsDir, errorsHandler: errorsHandler, showAppStartupScreen: true, - createControlFactories: [ -// --FAT_CLIENT_START-- - flet_audio.createControl, - flet_video.createControl, -// --FAT_CLIENT_END-- - flet_audio_recorder.createControl, - flet_geolocator.createControl, - flet_permission_handler.createControl, - flet_lottie.createControl, - flet_map.createControl, - flet_ads.createControl, - flet_rive.createControl, - flet_webview.createControl, - flet_flashlight.createControl, - ], - )); + appStartupScreenMessage: "Working...", + appErrorMessage: "The application encountered an error: {message}", + extensions: extensions, + multiView: isMultiView(), + tester: tester, + ); + + if (app.multiView) { + debugPrint("Flet Web Multi-View mode"); + runWidget(app); + } else { + runApp(app); + } } diff --git a/client/linux/CMakeLists.txt b/client/linux/CMakeLists.txt index 8d67033545..6a1d46ecc6 100644 --- a/client/linux/CMakeLists.txt +++ b/client/linux/CMakeLists.txt @@ -91,6 +91,15 @@ set_target_properties(${BINARY_NAME} # them to the application. include(flutter/generated_plugins.cmake) +# Link mimalloc when media_kit_libs_linux exposes it. This must happen after +# generated plugins are included so MIMALLOC_LIB is initialized. +# mimalloc.o references pthread_*, so pair it with Threads::Threads — modern +# ld --as-needed won't pull libpthread in transitively through other DSOs. +if(MIMALLOC_LIB) + find_package(Threads REQUIRED) + target_link_libraries(${BINARY_NAME} PRIVATE ${MIMALLOC_LIB} Threads::Threads) +endif() + # === Installation === # By default, "installing" just makes a relocatable bundle in the build diff --git a/client/linux/flutter/generated_plugin_registrant.cc b/client/linux/flutter/generated_plugin_registrant.cc index ce73c487f9..486c5f4f54 100644 --- a/client/linux/flutter/generated_plugin_registrant.cc +++ b/client/linux/flutter/generated_plugin_registrant.cc @@ -7,10 +7,12 @@ #include "generated_plugin_registrant.h" #include +#include #include #include +#include #include -#include +#include #include #include #include @@ -20,18 +22,24 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); g_autoptr(FlPluginRegistrar) media_kit_video_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin"); media_kit_video_plugin_register_with_registrar(media_kit_video_registrar); + g_autoptr(FlPluginRegistrar) pasteboard_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin"); + pasteboard_plugin_register_with_registrar(pasteboard_registrar); g_autoptr(FlPluginRegistrar) record_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); record_linux_plugin_register_with_registrar(record_linux_registrar); - g_autoptr(FlPluginRegistrar) rive_common_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "RivePlugin"); - rive_plugin_register_with_registrar(rive_common_registrar); + g_autoptr(FlPluginRegistrar) rive_native_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "RiveNativePlugin"); + rive_native_plugin_register_with_registrar(rive_native_registrar); g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); diff --git a/client/linux/flutter/generated_plugins.cmake b/client/linux/flutter/generated_plugins.cmake index db550dddca..692e9fcd42 100644 --- a/client/linux/flutter/generated_plugins.cmake +++ b/client/linux/flutter/generated_plugins.cmake @@ -4,10 +4,12 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux + flutter_secure_storage_linux media_kit_libs_linux media_kit_video + pasteboard record_linux - rive_common + rive_native screen_retriever_linux url_launcher_linux window_manager @@ -15,7 +17,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - media_kit_native_event_loop + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/client/macos/Flutter/GeneratedPluginRegistrant.swift b/client/macos/Flutter/GeneratedPluginRegistrant.swift index ab5ba1dcdb..62e3cfcb94 100644 --- a/client/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/client/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,17 +6,21 @@ import FlutterMacOS import Foundation import audioplayers_darwin +import battery_plus +import connectivity_plus import device_info_plus import file_picker +import flutter_secure_storage_darwin import geolocator_apple import media_kit_libs_macos_video import media_kit_video import package_info_plus -import path_provider_foundation -import record_darwin -import rive_common +import pasteboard +import record_macos +import rive_native import screen_brightness_macos import screen_retriever_macos +import share_plus import shared_preferences_foundation import url_launcher_macos import wakelock_plus @@ -26,21 +30,25 @@ import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) + BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin")) + ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) + FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) - RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) + PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) + RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin")) + RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin")) ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) - FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin")) + WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) } diff --git a/client/macos/Podfile b/client/macos/Podfile index 9ec46f8cd5..8f21aafb63 100644 --- a/client/macos/Podfile +++ b/client/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.15' +platform :osx, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -34,7 +34,20 @@ target 'Runner' do end post_install do |installer| + # Ensure rive_native's setup script runs from the project root so pubspec.yaml is found in CI. installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) + next unless target.name == 'rive_native' + + target.shell_script_build_phases.each do |phase| + script = phase.shell_script + next unless script&.include?('rive_native:setup') + next if script.include?('PROJECT_ROOT="${SRCROOT}/../.."') + + phase.shell_script = script.sub( + "set -e\n", + "set -e\nPROJECT_ROOT=\"${SRCROOT}/../..\"\ncd \"$PROJECT_ROOT\"\n" + ) + end end end diff --git a/client/macos/Runner.xcodeproj/project.pbxproj b/client/macos/Runner.xcodeproj/project.pbxproj index 2d9fc43c47..7f045dcd00 100644 --- a/client/macos/Runner.xcodeproj/project.pbxproj +++ b/client/macos/Runner.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ isa = PBXAggregateTarget; buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; buildPhases = ( + B8C2A0D41E5F4A9CB1234E56 /* Rive Native Setup */, 33CC111E2044C6BF0003C045 /* ShellScript */, ); dependencies = ( @@ -253,6 +254,25 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + B8C2A0D41E5F4A9CB1234E56 /* Rive Native Setup */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Rive Native Setup"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\nPROJECT_ROOT=\"${PROJECT_DIR}/..\"\ncd \"$PROJECT_ROOT\"\nDART_BIN=\"${FLUTTER_ROOT}/bin/dart\"\nif [ ! -x \"$DART_BIN\" ]; then\n DART_BIN=\"$(command -v dart || true)\"\nfi\nif [ -z \"$DART_BIN\" ]; then\n echo \"error: dart not found; cannot run rive_native:setup\" >&2\n exit 1\nfi\necho \"Running rive_native setup for macos...\"\n\"$DART_BIN\" run rive_native:setup --verbose --clean --platform macos\n"; + }; 15125595ECCDEE56B3D8B7C4 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -404,7 +424,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -483,7 +503,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -530,7 +550,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/client/macos/Runner/Configs/AppInfo.xcconfig b/client/macos/Runner/Configs/AppInfo.xcconfig index 41ae1b6ee4..4c09de89f3 100644 --- a/client/macos/Runner/Configs/AppInfo.xcconfig +++ b/client/macos/Runner/Configs/AppInfo.xcconfig @@ -11,4 +11,4 @@ PRODUCT_NAME = Flet PRODUCT_BUNDLE_IDENTIFIER = com.appveyor.flet // The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2023 Appveyor Systems Inc. All rights reserved. Licensed under the Apache License, Version 2.0 +PRODUCT_COPYRIGHT = Copyright © 2023-2026 Appveyor Systems Inc. All rights reserved. Licensed under the Apache License, Version 2.0 diff --git a/client/macos/Runner/Info.plist b/client/macos/Runner/Info.plist index 4ceb1fd1fe..6fd83ba455 100644 --- a/client/macos/Runner/Info.plist +++ b/client/macos/Runner/Info.plist @@ -30,9 +30,13 @@ MainMenu NSPrincipalClass NSApplication + + NSMicrophoneUsageDescription - Audio Recording - NSLocationUsageDescription - This app needs access to location. + This app needs access to microphone. + + + NSLocationWhenInUseUsageDescription + This app needs access to location. \ No newline at end of file diff --git a/client/pubspec.lock b/client/pubspec.lock index 4a46277cf7..b514533567 100644 --- a/client/pubspec.lock +++ b/client/pubspec.lock @@ -5,82 +5,106 @@ packages: dependency: transitive description: name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "3.6.1" + version: "4.0.9" args: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" async: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.1" audioplayers: dependency: transitive description: name: audioplayers - sha256: c05c6147124cd63e725e861335a8b4d57300b80e6e92cea7c145c739223bbaef + sha256: a72dd459d1a48f61a6fb9c0134dba26597c9236af40639ff0eb70eb4e0baab70 url: "https://pub.dev" source: hosted - version: "5.2.1" + version: "6.6.0" audioplayers_android: dependency: transitive description: name: audioplayers_android - sha256: b00e1a0e11365d88576320ec2d8c192bc21f1afb6c0e5995d1c57ae63156acb5 + sha256: "60a6728277228413a85755bd3ffd6fab98f6555608923813ce383b190a360605" url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "5.2.1" audioplayers_darwin: dependency: transitive description: name: audioplayers_darwin - sha256: "3034e99a6df8d101da0f5082dcca0a2a99db62ab1d4ddb3277bed3f6f81afe08" + sha256: c994b3bb3a921e4904ac40e013fbc94488e824fd7c1de6326f549943b0b44a91 url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "6.4.0" audioplayers_linux: dependency: transitive description: name: audioplayers_linux - sha256: "60787e73fefc4d2e0b9c02c69885402177e818e4e27ef087074cf27c02246c9e" + sha256: f75bce1ce864170ef5e6a2c6a61cd3339e1a17ce11e99a25bae4474ea491d001 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.2.1" audioplayers_platform_interface: dependency: transitive description: name: audioplayers_platform_interface - sha256: "365c547f1bb9e77d94dd1687903a668d8f7ac3409e48e6e6a3668a1ac2982adb" + sha256: "0e2f6a919ab56d0fec272e801abc07b26ae7f31980f912f24af4748763e5a656" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "7.1.1" audioplayers_web: dependency: transitive description: name: audioplayers_web - sha256: "22cd0173e54d92bd9b2c80b1204eb1eb159ece87475ab58c9788a70ec43c2a62" + sha256: faa8fa6587f996a6f604433b53af44c57a1407d4fe8dff5766cf63d6875e8de9 url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "5.2.0" audioplayers_windows: dependency: transitive description: name: audioplayers_windows - sha256: "9536812c9103563644ada2ef45ae523806b0745f7a78e89d1b5fb1951de90e1a" + sha256: bafff2b38b6f6d331887558ba6e0a01c9c208d9dbb3ad0005234db065122a734 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.3.0" + autotrie: + dependency: transitive + description: + name: autotrie + sha256: "55da6faefb53cfcb0abb2f2ca8636123fb40e35286bb57440d2cf467568188f8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + battery_plus: + dependency: transitive + description: + name: battery_plus + sha256: ad16fcb55b7384be6b4bbc763d5e2031ac7ea62b2d9b6b661490c7b9741155bf + url: "https://pub.dev" + source: hosted + version: "7.0.0" + battery_plus_platform_interface: + dependency: transitive + description: + name: battery_plus_platform_interface + sha256: e8342c0f32de4b1dfd0223114b6785e48e579bfc398da9471c9179b907fa4910 + url: "https://pub.dev" + source: hosted + version: "2.0.1" boolean_selector: dependency: transitive description: @@ -89,11 +113,59 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + camera: + dependency: transitive + description: + name: camera + sha256: "034c38cb8014d29698dcae6d20276688a1bf74e6487dfeb274d70ea05d5f7777" + url: "https://pub.dev" + source: hosted + version: "0.12.0+1" + camera_android_camerax: + dependency: transitive + description: + name: camera_android_camerax + sha256: b5064cf25a2787d122d0bf12e77c7b1033a2b983d0730e3091f770ee376efde5 + url: "https://pub.dev" + source: hosted + version: "0.7.2" + camera_avfoundation: + dependency: transitive + description: + name: camera_avfoundation + sha256: "90e4cc3fde331581a3b2d35d83be41dbb7393af0ab857eb27b732174289cb96d" + url: "https://pub.dev" + source: hosted + version: "0.10.1" + camera_platform_interface: + dependency: transitive + description: + name: camera_platform_interface + sha256: "7ac852d77699acee79f0d438b793feee26721841e50973576419ff5c6d95e9b7" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + camera_web: + dependency: transitive + description: + name: camera_web + sha256: "57f49a635c8bf249d07fb95eb693d7e4dda6796dedb3777f9127fb54847beba7" + url: "https://pub.dev" + source: hosted + version: "0.3.5+3" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a url: "https://pub.dev" source: hosted version: "1.4.0" @@ -101,18 +173,18 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" cli_util: dependency: transitive description: name: cli_util - sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "0.4.1" + version: "0.4.2" clock: dependency: transitive description: @@ -121,6 +193,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" collection: dependency: transitive description: @@ -129,102 +209,118 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + connectivity_plus: + dependency: transitive + description: + name: connectivity_plus + sha256: "62ffa266d9a23b79fb3fcbc206afc00bb979417ba57b1324c546b5aab95ba057" + url: "https://pub.dev" + source: hosted + version: "7.1.1" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: "3c09627c536d22fd24691a905cdd8b14520de69da52c7a97499c8be5284a32ed" + url: "https://pub.dev" + source: hosted + version: "2.1.0" cross_file: dependency: transitive description: name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" url: "https://pub.dev" source: hosted - version: "0.3.4+2" + version: "0.3.5+2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.7" cupertino_icons: - dependency: "direct main" + dependency: transitive description: name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.9" dart_earcut: dependency: transitive description: name: dart_earcut - sha256: "41b493147e30a051efb2da1e3acb7f38fe0db60afba24ac1ea5684cee272721e" + sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b url: "https://pub.dev" source: hosted - version: "1.1.0" - dbus: + version: "1.2.0" + dart_polylabel2: dependency: transitive description: - name: dbus - sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + name: dart_polylabel2 + sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" url: "https://pub.dev" source: hosted - version: "0.7.10" - device_info_plus: + version: "1.0.0" + data_table_2: dependency: transitive description: - name: device_info_plus - sha256: b37d37c2f912ad4e8ec694187de87d05de2a3cb82b465ff1f65f65a2d05de544 + name: data_table_2 + sha256: cb31d465dcf1e1598a662d06d3d2c16c73700ae9e837a3d91588f1dda7519abc url: "https://pub.dev" source: hosted - version: "11.2.1" - device_info_plus_platform_interface: + version: "2.7.2" + dbus: dependency: transitive description: - name: device_info_plus_platform_interface - sha256: "0b04e02b30791224b31969eb1b50d723498f402971bff3630bca2ba839bd1ed2" + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 url: "https://pub.dev" source: hosted - version: "7.0.2" - dio: + version: "0.7.12" + device_info_plus: dependency: transitive description: - name: dio - sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" + name: device_info_plus + sha256: b4fed1b2835da9d670d7bed7db79ae2a94b0f5ad6312268158a9b5479abbacdd url: "https://pub.dev" source: hosted - version: "5.7.0" - dio_web_adapter: + version: "12.4.0" + device_info_plus_platform_interface: dependency: transitive description: - name: dio_web_adapter - sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "7.0.3" equatable: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.8" fake_async: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" ffi: dependency: transitive description: name: ffi - sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.2.0" file: dependency: transitive description: @@ -237,137 +333,174 @@ packages: dependency: transitive description: name: file_picker - sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a + sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343" url: "https://pub.dev" source: hosted - version: "10.2.0" + version: "10.3.10" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" fl_chart: dependency: transitive description: name: fl_chart - sha256: "94307bef3a324a0d329d3ab77b2f0c6e5ed739185ffc029ed28c0f9b019ea7ef" + sha256: b938f77d042cbcd822936a7a359a7235bad8bd72070de1f827efc2cc297ac888 url: "https://pub.dev" source: hosted - version: "0.69.0" + version: "1.2.0" flet: dependency: "direct overridden" description: path: "../packages/flet" relative: true source: path - version: "0.28.3" + version: "0.85.0" flet_ads: dependency: "direct main" description: - path: "src/flutter/flet_ads" - ref: "0.1.0" - resolved-ref: "01e7065fcbebb1317b3f16951e6cf0c5fcff658b" - url: "https://github.com/flet-dev/flet-ads.git" - source: git + path: "../sdk/python/packages/flet-ads/src/flutter/flet_ads" + relative: true + source: path version: "0.1.0" flet_audio: dependency: "direct main" description: - path: "src/flutter/flet_audio" - ref: "0.1.0" - resolved-ref: a146bf580a211c6d1f5c45070d15532ea2e92af7 - url: "https://github.com/flet-dev/flet-audio.git" - source: git + path: "../sdk/python/packages/flet-audio/src/flutter/flet_audio" + relative: true + source: path version: "0.1.0" flet_audio_recorder: dependency: "direct main" description: - path: "src/flutter/flet_audio_recorder" - ref: "0.1.0" - resolved-ref: eb186cd49fde3136f65d0d074bca5ca688260e53 - url: "https://github.com/flet-dev/flet-audio-recorder.git" - source: git + path: "../sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder" + relative: true + source: path + version: "0.1.0" + flet_camera: + dependency: "direct main" + description: + path: "../sdk/python/packages/flet-camera/src/flutter/flet_camera" + relative: true + source: path + version: "0.1.0" + flet_charts: + dependency: "direct main" + description: + path: "../sdk/python/packages/flet-charts/src/flutter/flet_charts" + relative: true + source: path + version: "0.1.0" + flet_code_editor: + dependency: "direct main" + description: + path: "../sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor" + relative: true + source: path + version: "0.1.0" + flet_color_pickers: + dependency: "direct main" + description: + path: "../sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers" + relative: true + source: path + version: "0.1.0" + flet_datatable2: + dependency: "direct main" + description: + path: "../sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2" + relative: true + source: path version: "0.1.0" flet_flashlight: dependency: "direct main" description: - path: "src/flutter/flet_flashlight" - ref: "0.1.0" - resolved-ref: a12a12259eaac801ee99d465727ec4a9fe50121e - url: "https://github.com/flet-dev/flet-flashlight.git" - source: git + path: "../sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight" + relative: true + source: path version: "0.1.0" flet_geolocator: dependency: "direct main" description: - path: "src/flutter/flet_geolocator" - ref: "0.1.0" - resolved-ref: "7b17d7aab169a7488da90fd73b3acd8e568f4f03" - url: "https://github.com/flet-dev/flet-geolocator.git" - source: git - version: "0.25.2" + path: "../sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator" + relative: true + source: path + version: "0.1.0" flet_lottie: dependency: "direct main" description: - path: "src/flutter/flet_lottie" - ref: "0.1.0" - resolved-ref: f28c767b5d43de650155a5a97e2d971fb833c9f8 - url: "https://github.com/flet-dev/flet-lottie.git" - source: git + path: "../sdk/python/packages/flet-lottie/src/flutter/flet_lottie" + relative: true + source: path version: "0.1.0" flet_map: dependency: "direct main" description: - path: "src/flutter/flet_map" - ref: "0.1.0" - resolved-ref: dfa3cf6776b0dc5f238227d5f378cda7be190eaf - url: "https://github.com/flet-dev/flet-map.git" - source: git + path: "../sdk/python/packages/flet-map/src/flutter/flet_map" + relative: true + source: path version: "0.1.0" flet_permission_handler: dependency: "direct main" description: - path: "src/flutter/flet_permission_handler" - ref: "0.1.0" - resolved-ref: "4ead86b6c7e54b914215b6087fcb17b7e921d75c" - url: "https://github.com/flet-dev/flet-permission-handler.git" - source: git + path: "../sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler" + relative: true + source: path version: "0.1.0" flet_rive: dependency: "direct main" description: - path: "src/flutter/flet_rive" - ref: "0.1.0" - resolved-ref: "089f7ad923f747ad764aa2781eca9a36382bb912" - url: "https://github.com/flet-dev/flet-rive.git" - source: git + path: "../sdk/python/packages/flet-rive/src/flutter/flet_rive" + relative: true + source: path + version: "0.1.0" + flet_secure_storage: + dependency: "direct main" + description: + path: "../sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage" + relative: true + source: path version: "0.1.0" flet_video: dependency: "direct main" description: - path: "src/flutter/flet_video" - ref: "0.1.0" - resolved-ref: "76f3f76f04c7573e047204648378ee2f31db7a15" - url: "https://github.com/flet-dev/flet-video.git" - source: git + path: "../sdk/python/packages/flet-video/src/flutter/flet_video" + relative: true + source: path version: "0.1.0" flet_webview: dependency: "direct main" description: - path: "src/flutter/flet_webview" - ref: "0.1.0" - resolved-ref: b1cfb3155469bc0a9a7578afcd58e7f32669b164 - url: "https://github.com/flet-dev/flet-webview.git" - source: git + path: "../sdk/python/packages/flet-webview/src/flutter/flet_webview" + relative: true + source: path version: "0.1.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_code_editor: + dependency: transitive + description: + path: "." + ref: pinyin-fix + resolved-ref: "9a6e13f012b34b8a0c219f165b87c6eeadf4c9a5" + url: "https://github.com/flet-dev/flutter-code-editor" + source: git + version: "0.3.5" + flutter_colorpicker: + dependency: transitive + description: + name: flutter_colorpicker + sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter_driver: dependency: transitive description: flutter @@ -385,10 +518,10 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" url: "https://pub.dev" source: hosted - version: "0.13.1" + version: "0.14.4" flutter_lints: dependency: "direct dev" description: @@ -406,65 +539,113 @@ packages: dependency: transitive description: name: flutter_map - sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da" + sha256: "03b71c02806ff20c3718d108cbbb3638142ebafe368d8ce2dd22a33344bcb02b" url: "https://pub.dev" source: hosted - version: "7.0.2" + version: "8.3.0" flutter_map_animations: dependency: transitive description: name: flutter_map_animations - sha256: "08233f89919049a3601e785d32e9d1d9e1faac6578190150f1d7495fc1050d36" + sha256: bf583863561861aaaf4854ae7ed8940d79bea7d32918bf7a85d309b25235a09e url: "https://pub.dev" source: hosted - version: "0.8.0" - flutter_map_cancellable_tile_provider: + version: "0.9.0" + flutter_markdown_plus: dependency: transitive description: - name: flutter_map_cancellable_tile_provider - sha256: "03662220ce0cd784ad2f2a45c36fc379b8b315c74f5c12b5ff4a0515eab1acd1" + name: flutter_markdown_plus + sha256: "039177906850278e8fb1cd364115ee0a46281135932fa8ecea8455522166d2de" url: "https://pub.dev" source: hosted - version: "3.0.2" - flutter_markdown: + version: "1.0.7" + flutter_markdown_plus_latex: dependency: transitive description: - name: flutter_markdown - sha256: f0e599ba89c9946c8e051780f0ec99aba4ba15895e0380a7ab68f420046fc44e + name: flutter_markdown_plus_latex + sha256: "2e7698b291f0657ca445efab730bb25a8c5851037e882cb7bf47d16a5c218de7" url: "https://pub.dev" source: hosted - version: "0.7.4+1" + version: "1.0.5" + flutter_math_fork: + dependency: transitive + description: + name: flutter_math_fork + sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407" + url: "https://pub.dev" + source: hosted + version: "0.7.4" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" + sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0" + url: "https://pub.dev" + source: hosted + version: "2.0.34" + flutter_secure_storage: + dependency: transitive + description: + name: flutter_secure_storage + sha256: da922f2aab2d733db7e011a6bcc4a825b844892d4edd6df83ff156b09a9b2e40 + url: "https://pub.dev" + source: hosted + version: "10.0.0" + flutter_secure_storage_darwin: + dependency: transitive + description: + name: flutter_secure_storage_darwin + sha256: "8878c25136a79def1668c75985e8e193d9d7d095453ec28730da0315dc69aee3" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: "2b5c76dce569ab752d55a1cee6a2242bcc11fdba927078fb88c503f150767cda" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: "8ceea1223bee3c6ac1a22dabd8feefc550e4729b3675de4b5900f55afcb435d6" url: "https://pub.dev" source: hosted - version: "2.0.24" - flutter_redux: + version: "2.0.1" + flutter_secure_storage_web: dependency: transitive description: - name: flutter_redux - sha256: "3b20be9e08d0038e1452fbfa1fdb1ea0a7c3738c997734530b3c6d0bb5fcdbdc" + name: flutter_secure_storage_web + sha256: "6a1137df62b84b54261dca582c1c09ea72f4f9a4b2fcee21b025964132d5d0c3" url: "https://pub.dev" source: hosted - version: "0.10.0" + version: "2.1.0" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613" + url: "https://pub.dev" + source: hosted + version: "4.1.0" flutter_svg: dependency: transitive description: name: flutter_svg - sha256: de82e6bf958cec7190fbc1c5298282c851228e35ae2b14e2b103e7f777818c64 + sha256: "1ded017b39c8e15c8948ea855070a5ff8ff8b3d5e83f3446e02d6bb12add7ad9" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.2.4" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: - dependency: transitive + dependency: "direct main" description: flutter source: sdk version: "0.0.0" @@ -473,62 +654,86 @@ packages: description: flutter source: sdk version: "0.0.0" + geoclue: + dependency: transitive + description: + name: geoclue + sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f + url: "https://pub.dev" + source: hosted + version: "0.1.1" geolocator: dependency: transitive description: name: geolocator - sha256: "0ec58b731776bc43097fcf751f79681b6a8f6d3bc737c94779fe9f1ad73c1a81" + sha256: "79939537046c9025be47ec645f35c8090ecadb6fe98eba146a0d25e8c1357516" url: "https://pub.dev" source: hosted - version: "13.0.1" + version: "14.0.2" geolocator_android: dependency: transitive description: name: geolocator_android - sha256: "7aefc530db47d90d0580b552df3242440a10fe60814496a979aa67aa98b1fd47" + sha256: "179c3cb66dfa674fc9ccbf2be872a02658724d1c067634e2c427cf6df7df901a" url: "https://pub.dev" source: hosted - version: "4.6.1" + version: "5.0.2" geolocator_apple: dependency: transitive description: name: geolocator_apple - sha256: bc2aca02423ad429cb0556121f56e60360a2b7d694c8570301d06ea0c00732fd + sha256: dbdd8789d5aaf14cf69f74d4925ad1336b4433a6efdf2fce91e8955dc921bf22 url: "https://pub.dev" source: hosted - version: "2.3.7" + version: "2.3.13" + geolocator_linux: + dependency: transitive + description: + name: geolocator_linux + sha256: d64112a205931926f4363bb6bd48f14cb38e7326833041d170615586cd143797 + url: "https://pub.dev" + source: hosted + version: "0.2.4" geolocator_platform_interface: dependency: transitive description: name: geolocator_platform_interface - sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012" + sha256: "30cb64f0b9adcc0fb36f628b4ebf4f731a2961a0ebd849f4b56200205056fe67" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "4.2.6" geolocator_web: dependency: transitive description: name: geolocator_web - sha256: "2ed69328e05cd94e7eb48bb0535f5fc0c0c44d1c4fa1e9737267484d05c29b5e" + sha256: b1ae9bdfd90f861fde8fd4f209c37b953d65e92823cb73c7dee1fa021b06f172 url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "4.1.3" geolocator_windows: dependency: transitive description: name: geolocator_windows - sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e" + sha256: "175435404d20278ffd220de83c2ca293b73db95eafbdc8131fe8609be1421eb6" url: "https://pub.dev" source: hosted - version: "0.2.3" + version: "0.2.5" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" google_mobile_ads: dependency: transitive description: name: google_mobile_ads - sha256: "4775006383a27a5d86d46f8fb452bfcb17794fc0a46c732979e49a8eb1c8963f" + sha256: "50549f6c945d7a445d53c04f34d025b1a1723fbd02719de9e67de432e2597f40" url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "8.0.0" graphs: dependency: transitive description: @@ -537,6 +742,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + gsettings: + dependency: transitive + description: + name: gsettings + sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" + url: "https://pub.dev" + source: hosted + version: "0.2.8" highlight: dependency: transitive description: @@ -545,30 +758,46 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" + hive: + dependency: transitive + description: + name: hive + sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: "025f060e86d2d4c3c47b56e33caf7f93bf9283340f26d23424ebcfccf34f621e" + url: "https://pub.dev" + source: hosted + version: "1.0.3" http: dependency: transitive description: name: http - sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "1.6.0" http_parser: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" image: dependency: transitive description: name: image - sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.8.0" integration_test: dependency: "direct main" description: flutter @@ -578,26 +807,34 @@ packages: dependency: transitive description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" url: "https://pub.dev" source: hosted - version: "0.19.0" - js: + version: "0.20.2" + jni: dependency: transitive description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + name: jni + sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "1.0.0" + jni_flutter: + dependency: transitive + description: + name: jni_flutter + sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" json_annotation: dependency: transitive description: name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.11.0" latlong2: dependency: transitive description: @@ -610,106 +847,98 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" - lints: + version: "3.0.2" + linked_scroll_controller: dependency: transitive description: - name: lints - sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c + name: linked_scroll_controller + sha256: e6020062bcf4ffc907ee7fd090fa971e65d8dfaac3c62baf601a3ced0b37986a url: "https://pub.dev" source: hosted - version: "1.0.1" - lists: + version: "0.2.0" + lints: dependency: transitive description: - name: lists - sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + name: lints + sha256: a2c3d198cb5ea2e179926622d433331d8b58374ab8f29cdda6e863bd62fd369c url: "https://pub.dev" source: hosted version: "1.0.1" - logger: - dependency: transitive - description: - name: logger - sha256: "697d067c60c20999686a0add96cf6aba723b3aa1f83ecf806a8097231529ec32" - url: "https://pub.dev" - source: hosted - version: "2.4.0" logging: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" lottie: dependency: transitive description: name: lottie - sha256: "6a24ade5d3d918c306bb1c21a6b9a04aab0489d51a2582522eea820b4093b62b" + sha256: "8b6359a7422167014aa73ce763fa133fb832065dcc0ac4d1dec1f603a5cef7d0" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.3.3" markdown: dependency: transitive description: name: markdown - sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "7.3.1" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.13.0" media_kit: dependency: transitive description: name: media_kit - sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a" + sha256: ae9e79597500c7ad6083a3c7b7b7544ddabfceacce7ae5c9709b0ec16a5d6643 url: "https://pub.dev" source: hosted - version: "1.1.10+1" + version: "1.2.6" media_kit_libs_android_video: dependency: transitive description: name: media_kit_libs_android_video - sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" + sha256: "3f6274e5ab2de512c286a25c327288601ee445ed8ac319e0ef0b66148bd8f76c" url: "https://pub.dev" source: hosted - version: "1.3.6" + version: "1.3.8" media_kit_libs_ios_video: dependency: transitive description: @@ -722,10 +951,10 @@ packages: dependency: transitive description: name: media_kit_libs_linux - sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 + sha256: "2b473399a49ec94452c4d4ae51cfc0f6585074398d74216092bf3d54aac37ecf" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.2.1" media_kit_libs_macos_video: dependency: transitive description: @@ -738,66 +967,130 @@ packages: dependency: transitive description: name: media_kit_libs_video - sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067" + sha256: "2b235b5dac79c6020e01eef5022c6cc85fedc0df1738aadc6ea489daa12a92a9" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.7" media_kit_libs_windows_video: dependency: transitive description: name: media_kit_libs_windows_video - sha256: "7bace5f35d9afcc7f9b5cdadb7541d2191a66bb3fc71bfa11c1395b3360f6122" - url: "https://pub.dev" - source: hosted - version: "1.0.9" - media_kit_native_event_loop: - dependency: transitive - description: - name: media_kit_native_event_loop - sha256: a605cf185499d14d58935b8784955a92a4bf0ff4e19a23de3d17a9106303930e + sha256: dff76da2778729ab650229e6b4ec6ec111eb5151431002cbd7ea304ff1f112ab url: "https://pub.dev" source: hosted - version: "1.0.8" + version: "1.0.11" media_kit_video: dependency: transitive description: name: media_kit_video - sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882 + sha256: afaa509e7b7e0bf247557a3a740cde903a52c34ace9810f94500e127bd7b043d url: "https://pub.dev" source: hosted - version: "1.2.4" + version: "2.0.1" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mgrs_dart: dependency: transitive description: name: mgrs_dart - sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + sha256: "385e7168ecc77eb545220223c49eef8ab249da7bf57f22781c40a04d23fb196f" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted version: "2.0.0" + mocktail: + dependency: transitive + description: + name: mocktail + sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + msgpack_dart: + dependency: transitive + description: + name: msgpack_dart + sha256: c2d235ed01f364719b5296aecf43ac330f0d7bc865fa134d0d7910a40454dffb + url: "https://pub.dev" + source: hosted + version: "1.0.1" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + url: "https://pub.dev" + source: hosted + version: "0.17.6" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" package_info_plus: dependency: transitive description: name: package_info_plus - sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918 + sha256: "468c26b4254ab01979fa5e4a98cb343ea3631b9acee6f21028997419a80e1a20" url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "9.0.1" package_info_plus_platform_interface: dependency: transitive description: name: package_info_plus_platform_interface - sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.2.1" + pasteboard: + dependency: transitive + description: + name: pasteboard + sha256: "9ff73ada33f79a59ff91f6c01881fd4ed0a0031cfc4ae2d86c0384471525fca1" + url: "https://pub.dev" + source: hosted + version: "0.4.0" path: dependency: transitive description: @@ -810,34 +1103,34 @@ packages: dependency: transitive description: name: path_parsing - sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.0" path_provider: dependency: transitive description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "490539678396d4c3c0b06efdaab75ae60675c3e0c66f72bc04c2e2c1e0e2abeb" + sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" url: "https://pub.dev" source: hosted - version: "2.2.9" + version: "2.3.1" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.0" path_provider_linux: dependency: transitive description: @@ -866,42 +1159,42 @@ packages: dependency: transitive description: name: permission_handler - sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" + sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 url: "https://pub.dev" source: hosted - version: "11.3.1" + version: "12.0.1" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: eaf2a1ec4472775451e88ca6a7b86559ef2f1d1ed903942ed135e38ea0097dca + sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" url: "https://pub.dev" source: hosted - version: "12.0.8" + version: "13.0.1" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0 + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 url: "https://pub.dev" source: hosted - version: "9.4.5" + version: "9.4.7" permission_handler_html: dependency: transitive description: name: permission_handler_html - sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851 + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" url: "https://pub.dev" source: hosted - version: "0.1.3+2" + version: "0.1.3+5" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 url: "https://pub.dev" source: hosted - version: "4.2.2" + version: "4.3.0" permission_handler_windows: dependency: transitive description: @@ -914,10 +1207,10 @@ packages: dependency: transitive description: name: petitparser - sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "7.0.2" platform: dependency: transitive description: @@ -934,166 +1227,198 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - polylabel: + posix: dependency: transitive description: - name: polylabel - sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + name: posix + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "6.5.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.5" proj4dart: dependency: transitive description: name: proj4dart - sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + sha256: ddcedc1f7876e62717de43ab3491e2829bdad0b028261805f94aa080967e5859 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "3.0.0" + provider: + dependency: transitive + description: + name: provider + sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" + url: "https://pub.dev" + source: hosted + version: "6.1.5+1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" record: dependency: transitive description: name: record - sha256: "4a5cf4d083d1ee49e0878823c4397d073f8eb0a775f31215d388e2bc47a9e867" + sha256: d5b6b334f3ab02460db6544e08583c942dbf23e3504bf1e14fd4cbe3d9409277 url: "https://pub.dev" source: hosted - version: "5.1.2" + version: "6.2.0" record_android: dependency: transitive description: name: record_android - sha256: "9ccf6a206dc72b486cf37893690e70c17610e8f05dba8da1a808e73dc2f49a04" + sha256: "94783f08403aed33ffb68797bf0715b0812eb852f3c7985644c945faea462ba1" url: "https://pub.dev" source: hosted - version: "1.2.4" - record_darwin: + version: "1.5.1" + record_ios: dependency: transitive description: - name: record_darwin - sha256: b038c26d1066eb81f4e7433bfb85f0d450ca3fac0002a7216b83a21b775ecf21 + name: record_ios + sha256: "8df7c136131bd05efc19256af29b2ba6ccc000ccc2c80d4b6b6d7a8d21a3b5a9" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.0" record_linux: dependency: transitive description: name: record_linux - sha256: "74d41a9ebb1eb498a38e9a813dd524e8f0b4fdd627270bda9756f437b110a3e3" + sha256: c31a35cc158cd666fc6395f7f56fc054f31685571684be6b97670a27649ce5c7 url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "1.3.0" + record_macos: + dependency: transitive + description: + name: record_macos + sha256: "084902e63fc9c0c224c29203d6c75f0bdf9b6a40536c9d916393c8f4c4256488" + url: "https://pub.dev" + source: hosted + version: "1.2.1" record_platform_interface: dependency: transitive description: name: record_platform_interface - sha256: "11f8b03ea8a0e279b0e306571dbe0db0202c0b8e866495c9fa1ad2281d5e4c15" + sha256: "8a81dbc4e14e1272a285bbfef6c9136d070a47d9b0d1f40aa6193516253ee2f6" url: "https://pub.dev" source: hosted - version: "1.1.0" - record_web: + version: "1.5.0" + record_use: dependency: transitive description: - name: record_web - sha256: "656b7a865f90651fab997c2a563364f5fd60a0b527d5dadbb915d62d84fc3867" + name: record_use + sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" url: "https://pub.dev" source: hosted - version: "1.1.3" - record_windows: + version: "0.6.0" + record_web: dependency: transitive description: - name: record_windows - sha256: e653555aa3fda168aded7c34e11bd82baf0c6ac84e7624553def3c77ffefd36f + name: record_web + sha256: "7e9846981c1f2d111d86f0ae3309071f5bba8b624d1c977316706f08fc31d16d" url: "https://pub.dev" source: hosted - version: "1.0.3" - redux: + version: "1.3.0" + record_windows: dependency: transitive description: - name: redux - sha256: "1e86ed5b1a9a717922d0a0ca41f9bf49c1a587d50050e9426fc65b14e85ec4d7" + name: record_windows + sha256: "223258060a1d25c62bae18282c16783f28581ec19401d17e56b5205b9f039d78" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "1.0.7" rive: dependency: transitive description: name: rive - sha256: "2551a44fa766a7ed3f52aa2b94feda6d18d00edc25dee5f66e72e9b365bb6d6c" + sha256: "61f37d2833730778d258e634d27eb7e447a354790a78287621833808e8c7cb28" url: "https://pub.dev" source: hosted - version: "0.13.20" - rive_common: + version: "0.14.5" + rive_native: dependency: transitive description: - name: rive_common - sha256: "2ba42f80d37a4efd0696fb715787c4785f8a13361e8aea9227c50f1e78cf763a" + name: rive_native + sha256: bfce5d976e1aa9a8ae53846c913ecc3a20805d918162965d67cad438b0090946 url: "https://pub.dev" source: hosted - version: "0.4.15" + version: "0.1.5" safe_local_storage: dependency: transitive description: name: safe_local_storage - sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440 + sha256: "287ea1f667c0b93cdc127dccc707158e2d81ee59fba0459c31a0c7da4d09c755" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.3" screen_brightness: dependency: transitive description: name: screen_brightness - sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd + sha256: "5f70754028f169f059fdc61112a19dcbee152f8b293c42c848317854d650cba3" url: "https://pub.dev" source: hosted - version: "0.2.2+1" + version: "2.1.7" screen_brightness_android: dependency: transitive description: name: screen_brightness_android - sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf" + sha256: d34f5321abd03bc3474f4c381f53d189117eba0b039eac1916aa92cca5fd0a96 url: "https://pub.dev" source: hosted - version: "0.1.0+2" + version: "2.1.3" screen_brightness_ios: dependency: transitive description: name: screen_brightness_ios - sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2" + sha256: "2493953340ecfe8f4f13f61db50ce72533a55b0bbd58ba1402893feecf3727f5" url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "2.1.2" screen_brightness_macos: dependency: transitive description: name: screen_brightness_macos - sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd" + sha256: "4edf330ad21078686d8bfaf89413325fbaf571dcebe1e89254d675a3f288b5b9" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + screen_brightness_ohos: + dependency: transitive + description: + name: screen_brightness_ohos + sha256: a93a263dcd39b5c56e589eb495bcd001ce65cdd96ff12ab1350683559d5c5bb7 url: "https://pub.dev" source: hosted - version: "0.1.0+1" + version: "2.1.2" screen_brightness_platform_interface: dependency: transitive description: name: screen_brightness_platform_interface - sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171 + sha256: "737bd47b57746bc4291cab1b8a5843ee881af499514881b0247ec77447ee769c" url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "2.1.0" screen_brightness_windows: dependency: transitive description: name: screen_brightness_windows - sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86" + sha256: d3518bf0f5d7a884cee2c14449ae0b36803802866de09f7ef74077874b6b2448 url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "2.1.0" screen_retriever: dependency: transitive description: @@ -1134,78 +1459,126 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + screenshot: + dependency: transitive + description: + name: screenshot + sha256: "63817697a7835e6ce82add4228e15d233b74d42975c143ad8cfe07009fab866b" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + scrollable_positioned_list: + dependency: transitive + description: + name: scrollable_positioned_list + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" + url: "https://pub.dev" + source: hosted + version: "0.3.8" sensors_plus: dependency: transitive description: name: sensors_plus - sha256: "8e7fa79b4940442bb595bfc0ee9da4af5a22a0fe6ebacc74998245ee9496a82d" + sha256: "56e8cd4260d9ed8e00ecd8da5d9fdc8a1b2ec12345a750dfa51ff83fcf12e3fa" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "7.0.0" sensors_plus_platform_interface: dependency: transitive description: name: sensors_plus_platform_interface - sha256: bc472d6cfd622acb4f020e726433ee31788b038056691ba433fec80e448a094f + sha256: "58815d2f5e46c0c41c40fb39375d3f127306f7742efe3b891c0b1c87e2b5cd5d" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.0.1" + share_plus: + dependency: transitive + description: + name: share_plus + sha256: "223873d106614442ea6f20db5a038685cc5b32a2fba81cdecaefbbae0523f7fa" + url: "https://pub.dev" + source: hosted + version: "12.0.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" + url: "https://pub.dev" + source: hosted + version: "6.1.0" shared_preferences: dependency: transitive description: name: shared_preferences - sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.5.5" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "041be4d9d2dc6079cf342bc8b761b03787e3b71192d658220a56cac9c04a0294" + sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.23" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833" + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.5.6" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "2ba0510d3017f91655b7543e9ee46d48619de2a2af38e5c790423f7007c7ccc1" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.3" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "398084b47b7f92110683cac45c6dc4aae853db47e470e5ddcd52cab7f7196ab2" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" + shimmer: + dependency: transitive + description: + name: shimmer + sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + simple_sparse_list: + dependency: transitive + description: + name: simple_sparse_list + sha256: aa648fd240fa39b49dcd11c19c266990006006de6699a412de485695910fbc1f + url: "https://pub.dev" + source: hosted + version: "0.1.4" sky_engine: dependency: transitive description: flutter @@ -1215,18 +1588,10 @@ packages: dependency: transitive description: name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "1.10.2" stack_trace: dependency: transitive description: @@ -1243,6 +1608,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" string_scanner: dependency: transitive description: @@ -1263,10 +1636,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + sha256: "63896c27e81b28f8cb4e69ead0d3e8f03f1d1e5fc531a3e579cabed6a2c7c9e5" url: "https://pub.dev" source: hosted - version: "3.1.0+1" + version: "3.4.0+1" term_glyph: dependency: transitive description: @@ -1279,10 +1652,10 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.10" torch_light: dependency: transitive description: @@ -1291,22 +1664,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + tuple: + dependency: transitive + description: + name: tuple + sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 + url: "https://pub.dev" + source: hosted + version: "2.0.2" typed_data: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" unicode: dependency: transitive description: name: unicode - sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + sha256: a6f7bcfc8ea1d5ce1f6c0b1c39117a9919f4953edd9fd7a64090a9796c499b57 url: "https://pub.dev" source: hosted - version: "0.3.1" + version: "1.1.9" universal_platform: dependency: transitive description: @@ -1315,54 +1696,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + upower: + dependency: transitive + description: + name: upower + sha256: cf042403154751180affa1d15614db7fa50234bc2373cd21c3db666c38543ebf + url: "https://pub.dev" + source: hosted + version: "0.7.0" uri_parser: dependency: transitive description: name: uri_parser - sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835" + sha256: "051c62e5f693de98ca9f130ee707f8916e2266945565926be3ff20659f7853ce" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "3.0.2" url_launcher: dependency: transitive description: name: url_launcher - sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "94d8ad05f44c6d4e2ffe5567ab4d741b82d62e3c8e288cc1fcea45965edf47c9" + sha256: "3bb000251e55d4a209aa0e2e563309dc9bb2befea2295fd0cec1f51760aac572" url: "https://pub.dev" source: hosted - version: "6.3.8" + version: "6.3.29" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.4.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.5" url_launcher_platform_interface: dependency: transitive description: @@ -1375,186 +1764,178 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.2" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" - url: "https://pub.dev" - source: hosted - version: "3.1.2" - url_strategy: - dependency: "direct main" - description: - name: url_strategy - sha256: "42b68b42a9864c4d710401add17ad06e28f1c1d5500c93b98c431f6b0ea4ab87" + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "3.1.5" uuid: dependency: transitive description: name: uuid - sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90" + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" url: "https://pub.dev" source: hosted - version: "4.4.2" + version: "4.5.3" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + sha256: "81da85e9ca8885ade47f9685b953cb098970d11be4821ac765580a6607ea4373" url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.1.21" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.1.13" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" url: "https://pub.dev" source: hosted - version: "1.1.11+1" + version: "1.2.0" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: "046d3928e16fa4dc46e8350415661755ab759d9fc97fc21b5ab295f71e4f0499" url: "https://pub.dev" source: hosted - version: "14.3.1" - volume_controller: - dependency: transitive - description: - name: volume_controller - sha256: "189bdc7a554f476b412e4c8b2f474562b09d74bc458c23667356bce3ca1d48c9" - url: "https://pub.dev" - source: hosted - version: "2.0.7" + version: "15.1.0" wakelock_plus: dependency: transitive description: name: wakelock_plus - sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + sha256: ddf3db70eaa10c37558ff817519b85d527dbd21034fd5d8e1c2e85f31588f1c1 url: "https://pub.dev" source: hosted - version: "1.2.8" + version: "1.5.2" wakelock_plus_platform_interface: dependency: transitive description: name: wakelock_plus_platform_interface - sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + sha256: "14b2e5b9e35c2631e656913c47adecdd71633ae92896a27a64c8f1fcfabc21cc" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.5.0" web: dependency: transitive description: name: web - sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "3.0.3" webdriver: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.1.0" webview_flutter: dependency: transitive description: name: webview_flutter - sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" + sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9 url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.13.1" webview_flutter_android: - dependency: "direct overridden" + dependency: transitive description: name: webview_flutter_android - sha256: "74693a212d990b32e0b7055d27db973a18abf31c53942063948cdfaaef9787ba" + sha256: f560f57d0f529c1dcdaf4edc3a3217b099560622f9f4a10b6bdbb566553c61ea url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.11.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.14.0" webview_flutter_web: dependency: transitive description: name: webview_flutter_web - sha256: cbe1efe45e1be8470fdef7ddb75e2e2998c7ca47b75c09b9354934d20eca146b + sha256: "18a7ccc1c31dd9a5c759a1b7217a2a1e04bd8f65712714a4070bfac19a23ca9e" url: "https://pub.dev" source: hosted - version: "0.2.3+2" + version: "0.2.3+4" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: "1942a12224ab31e9508cf00c0c6347b931b023b8a4f0811e5dec3b06f94f117d" + sha256: e15d8828e014291324a4d0cf6e272090167f4fa5673ffcf8fe446f4a4cd35861 url: "https://pub.dev" source: hosted - version: "3.15.0" + version: "3.24.3" win32: dependency: transitive description: name: win32 - sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e url: "https://pub.dev" source: hosted - version: "5.10.1" + version: "5.15.0" win32_registry: dependency: transitive description: name: win32_registry - sha256: "723b7f851e5724c55409bb3d5a32b203b3afe8587eaf5dafb93a5fed8ecda0d6" + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" url: "https://pub.dev" source: hosted - version: "1.1.4" + version: "2.1.0" window_manager: dependency: transitive description: name: window_manager - sha256: "732896e1416297c63c9e3fb95aea72d0355f61390263982a47fd519169dc5059" + sha256: "7eb6d6c4164ec08e1bf978d6e733f3cebe792e2a23fb07cbca25c2872bfdbdcd" url: "https://pub.dev" source: hosted - version: "0.4.3" + version: "0.5.1" window_to_front: dependency: transitive description: @@ -1575,26 +1956,26 @@ packages: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" xml: dependency: transitive description: name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.6.1" yaml: dependency: transitive description: name: yaml - sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" sdks: - dart: ">=3.7.0-0 <4.0.0" - flutter: ">=3.24.0" + dart: ">=3.11.0 <4.0.0" + flutter: ">=3.41.0" diff --git a/client/pubspec.yaml b/client/pubspec.yaml index c6f003aba9..79ebf5030c 100644 --- a/client/pubspec.yaml +++ b/client/pubspec.yaml @@ -27,83 +27,73 @@ environment: # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: - flutter: sdk: flutter + flutter_web_plugins: + sdk: flutter + + flet_ads: + path: ../sdk/python/packages/flet-ads/src/flutter/flet_ads # --FAT_CLIENT_START-- flet_audio: - git: - url: https://github.com/flet-dev/flet-audio.git - ref: 0.1.0 - path: src/flutter/flet_audio + path: ../sdk/python/packages/flet-audio/src/flutter/flet_audio + flet_video: - git: - url: https://github.com/flet-dev/flet-video.git - ref: 0.1.0 - path: src/flutter/flet_video -# --FAT_CLIENT_END-- - flet_lottie: - git: - url: https://github.com/flet-dev/flet-lottie.git - ref: 0.1.0 - path: src/flutter/flet_lottie - flet_map: - git: - url: https://github.com/flet-dev/flet-map.git - ref: 0.1.0 - path: src/flutter/flet_map - flet_ads: - git: - url: https://github.com/flet-dev/flet-ads.git - ref: 0.1.0 - path: src/flutter/flet_ads + path: ../sdk/python/packages/flet-video/src/flutter/flet_video + # --RIVE_CLIENT_START-- flet_rive: - git: - url: https://github.com/flet-dev/flet-rive.git - ref: 0.1.0 - path: src/flutter/flet_rive + path: ../sdk/python/packages/flet-rive/src/flutter/flet_rive + # --RIVE_CLIENT_END-- + +# --FAT_CLIENT_END-- flet_audio_recorder: - git: - url: https://github.com/flet-dev/flet-audio-recorder.git - ref: 0.1.0 - path: src/flutter/flet_audio_recorder + path: ../sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder + + flet_camera: + path: ../sdk/python/packages/flet-camera/src/flutter/flet_camera + + flet_charts: + path: ../sdk/python/packages/flet-charts/src/flutter/flet_charts + + flet_color_pickers: + path: ../sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers + + flet_datatable2: + path: ../sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2 + + flet_flashlight: + path: ../sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight - flet_permission_handler: - git: - url: https://github.com/flet-dev/flet-permission-handler.git - ref: 0.1.0 - path: src/flutter/flet_permission_handler - flet_geolocator: - git: - url: https://github.com/flet-dev/flet-geolocator.git - ref: 0.1.0 - path: src/flutter/flet_geolocator - + path: ../sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator + + flet_lottie: + path: ../sdk/python/packages/flet-lottie/src/flutter/flet_lottie + + flet_map: + path: ../sdk/python/packages/flet-map/src/flutter/flet_map + + flet_permission_handler: + path: ../sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler + + flet_secure_storage: + path: ../sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage + flet_webview: - git: - url: https://github.com/flet-dev/flet-webview.git - ref: 0.1.0 - path: src/flutter/flet_webview - flet_flashlight: - git: - url: https://github.com/flet-dev/flet-flashlight.git - ref: 0.1.0 - path: src/flutter/flet_flashlight - - url_strategy: ^0.2.0 - cupertino_icons: ^1.0.6 - + path: ../sdk/python/packages/flet-webview/src/flutter/flet_webview + + flet_code_editor: + path: ../sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor + integration_test: sdk: flutter dependency_overrides: flet: path: ../packages/flet - webview_flutter_android: ^4.0.0 dev_dependencies: flutter_test: @@ -117,7 +107,7 @@ dev_dependencies: flutter_lints: ^1.0.0 # Docs: https://pub.dev/packages/flutter_launcher_icons - flutter_launcher_icons: "^0.13.1" + flutter_launcher_icons: "^0.14.4" # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/client/web/assets/fonts/roboto.woff2 b/client/web/assets/fonts/roboto.woff2 new file mode 100644 index 0000000000..8fa8d2ae93 Binary files /dev/null and b/client/web/assets/fonts/roboto.woff2 differ diff --git a/client/web/flutter_bootstrap.js b/client/web/flutter_bootstrap.js index 01f933bc59..86f1279767 100644 --- a/client/web/flutter_bootstrap.js +++ b/client/web/flutter_bootstrap.js @@ -2,22 +2,35 @@ {{flutter_build_config}} var loading = document.querySelector('#loading'); + +var flutterConfig = { + multiViewEnabled: flet.multiView, + entrypointBaseUrl: flet.entrypointBaseUrl, + assetBase: flet.assetBase +}; +if (flet.webRenderer != "auto") { + flutterConfig.renderer = flet.webRenderer; +} +if (flet.noCdn) { + flutterConfig.canvasKitBaseUrl = flet.canvasKitBaseUrl; + flutterConfig.fontFallbackBaseUrl = flet.fontFallbackBaseUrl; +} + _flutter.loader.load({ - config: { - renderer: webRenderer - }, + config: flutterConfig, serviceWorkerSettings: { serviceWorkerVersion: {{flutter_service_worker_version}}, }, onEntrypointLoaded: async function (engineInitializer) { loading.classList.add('main_done'); - const appRunner = await engineInitializer.initializeEngine({useColorEmoji: useColorEmoji}); + const engine = await engineInitializer.initializeEngine(flutterConfig); loading.classList.add('init_done'); - await appRunner.runApp(); + flet.flutterApp = await engine.runApp(); + flet.flutterAppResolve(flet.flutterApp); window.setTimeout(function () { loading.remove(); }, 200); } -}); \ No newline at end of file +}); diff --git a/client/web/index.html b/client/web/index.html index 92f213416e..2e622c51af 100644 --- a/client/web/index.html +++ b/client/web/index.html @@ -17,23 +17,65 @@ - - - - - Flet - - + - + @@ -95,5 +137,10 @@ Loading... + + - \ No newline at end of file + diff --git a/client/web/python-worker.js b/client/web/python-worker.js index 76049195e5..40c6083afc 100644 --- a/client/web/python-worker.js +++ b/client/web/python-worker.js @@ -1,42 +1,225 @@ -importScripts("https://cdn.jsdelivr.net/pyodide/v0.27.2/full/pyodide.js"); - +self.pyodideUrl = null; +self.appPackageUrl = null; self.micropipIncludePre = false; self.pythonModuleName = null; +self.documentUrl = null; self.initialized = false; self.flet_js = {}; // namespace for Python global functions +// Flipped to true right before `runpy.run_module` runs the user app. +// Until then, stdout/stderr is bootstrap diagnostics ("Downloading app +// archive", micropip install logs, etc.) — those go to the dev console +// rather than the user-visible Console pane. +self.userAppRunning = false; +self.flet_js.userAppStarting = function () { + self.userAppRunning = true; +}; +self.sendPythonOutput = function (text, isStderr) { + // No bridge yet, or not in user-code mode — surface in dev console. + // The boot script registers `flet_js.send_python_output` after the + // user-app deps are installed (msgpack typically rides in via flet); + // if msgpack isn't available it stays unset and prints fall through + // to the dev console silently. + if (!self.userAppRunning || !(self.flet_js && self.flet_js.send_python_output)) { + if (isStderr) { + console.error(text); + } else { + console.log(text); + } + return; + } + // Pyodide invokes stdout/stderr hooks with the GIL released, so + // calling back into Python synchronously throws NoGilError. Defer + // to a microtask — by the time it runs, the GIL state is normal. + queueMicrotask(function () { + self.flet_js.send_python_output(text, isStderr); + }); +}; + self.initPyodide = async function () { - self.pyodide = await loadPyodide(); - self.pyodide.registerJsModule("flet_js", flet_js); - flet_js.documentUrl = documentUrl; - await self.pyodide.loadPackage("micropip"); - let pre = self.micropipIncludePre ? "True" : "False"; - await self.pyodide.runPythonAsync(` - import micropip - import os - from pyodide.http import pyfetch - response = await pyfetch("app.tar.gz") - await response.unpack_archive() - if os.path.exists("requirements.txt"): - with open("requirements.txt", "r") as f: - deps = [line.rstrip() for line in f] - print("Loading requirements.txt:", deps) - await micropip.install(deps, pre=${pre}) - `); - pyodide.pyimport(self.pythonModuleName); - await self.flet_js.start_connection(self.receiveCallback); - self.postMessage("initialized"); + try { + importScripts(self.pyodideUrl); + self.pyodide = await loadPyodide({ + stdout: (text) => self.sendPythonOutput(text, false), + stderr: (text) => self.sendPythonOutput(text, true), + }); + self.pyodide.registerJsModule("flet_js", flet_js); + self.pyodide.globals.set("app_package_url", self.appPackageUrl); + self.pyodide.globals.set("python_module_name", self.pythonModuleName); + self.pyodide.globals.set("micropip_include_pre", self.micropipIncludePre); + flet_js.documentUrl = documentUrl; + await self.pyodide.runPythonAsync(` + import flet_js, os, runpy, sys, traceback + from pyodide.http import pyfetch + + py_args = flet_js.args.to_py() if flet_js.args else None + + if "app_package_url" in py_args: + app_package_url = py_args["app_package_url"] + + if "python_module_name" in py_args: + python_module_name = py_args["python_module_name"] + + if python_module_name is None: + python_module_name = "main" + + if "micropip_include_pre" in py_args: + micropip_include_pre = py_args["micropip_include_pre"] + + if micropip_include_pre is None: + micropip_include_pre = False + + print("python_module_name:", python_module_name) + print("micropip_include_pre:", micropip_include_pre) + + if "script" not in py_args: + print("Downloading app archive") + response = await pyfetch(app_package_url) + # Pick format from the URL's path extension. Pyodide's + # filename-based sniff trips over query strings like + # ?v=42. We only support zip and tar.gz (matching what + # our server and "flet publish" emit). + from urllib.parse import urlparse + _archive_path = urlparse(app_package_url).path.lower() + if _archive_path.endswith(".zip"): + _archive_format = "zip" + elif _archive_path.endswith((".tar.gz", ".tgz")): + _archive_format = "gztar" + else: + raise ValueError( + f"Unsupported app package URL: {app_package_url} " + "(expected .zip or .tar.gz)" + ) + await response.unpack_archive(format=_archive_format) + else: + print("Saving script to a file") + with open(f"{python_module_name}.py", "w") as f: + f.write(py_args["script"]); + + pkgs_path = "__pypackages__" + if os.path.exists(pkgs_path): + print(f"Adding {pkgs_path} to sys.path") + sys.path.insert(0, pkgs_path) + + async def ensure_micropip(): + try: + import micropip + except ImportError: + import pyodide_js + await pyodide_js.loadPackage("micropip") + import micropip + return micropip + + if os.path.exists("requirements.txt"): + with open("requirements.txt", "r") as f: + deps = [ + line + for req in f + if (line := req.strip()) and not line.startswith("#") + ] + if deps: + micropip = await ensure_micropip() + print("Loading requirements.txt:", deps) + await micropip.install(deps, pre=micropip_include_pre) + + if os.path.exists("pyproject.toml"): + import tomllib + with open("pyproject.toml", "rb") as f: + pyproject = tomllib.load(f) + project_deps = list( + pyproject.get("project", {}).get("dependencies", []) or [] + ) + web_deps = list( + pyproject.get("tool", {}) + .get("flet", {}) + .get("web", {}) + .get("dependencies", []) + or [] + ) + # [tool.flet.web].dependencies overrides [project].dependencies + # by package name — install in order so the web-specific specs + # win through micropip's last-writer-wins dedupe. + pyproject_deps = project_deps + web_deps + if pyproject_deps: + micropip = await ensure_micropip() + print("Loading pyproject.toml deps:", pyproject_deps) + await micropip.install(pyproject_deps, pre=micropip_include_pre) + + if "dependencies" in py_args: + micropip = await ensure_micropip() + await micropip.install(py_args["dependencies"], pre=micropip_include_pre) + + # Install the python_output bridge. msgpack normally rides in + # with the user's flet dependency, but apps without a flet dep + # (or without a pyproject.toml at all) would otherwise leave the + # bridge unregistered and their prints stranded in the dev + # console. Pyodide ships msgpack as a prebuilt package, so we + # load it explicitly when it isn't already importable. + try: + import msgpack as _msgpack + except ImportError: + import pyodide_js + await pyodide_js.loadPackage("msgpack") + import msgpack as _msgpack + + def _send_python_output(text, is_stderr): + flet_js.receive_callback( + _msgpack.packb( + [7, {"text": text, "is_stderr": bool(is_stderr)}] + ) + ) + + flet_js.send_python_output = _send_python_output + + # Flip the worker into "user code" mode so stdout/stderr starts + # flowing to the host page's Console pane instead of dev console. + flet_js.userAppStarting() + + # Execute app. Treat a clean SystemExit (exit() / exit(0)) as + # normal termination so the no-UI path below kicks in instead + # of surfacing a Pyodide traceback. Non-zero codes propagate as + # Script errors. + try: + runpy.run_module(python_module_name, run_name="__main__") + except SystemExit as _exit: + if _exit.code not in (None, 0): + raise + `); + // `start_connection` is registered by `PyodideConnection.__init__`, + // which only runs when the user app calls `ft.run(...)`. If the + // script finished without it (e.g. a print-only test program), + // surface a friendly message instead of a cryptic TypeError. + // The `__flet_no_ui__:` sentinel lets host pages render a + // neutral message rather than a Script error panel. + if (typeof self.flet_js.start_connection !== "function") { + self.postMessage( + "__flet_no_ui__:Script finished without starting a Flet UI.\n" + + "Add ft.run(main) at the end of your script to display the app." + ); + return; + } + await self.flet_js.start_connection(self.receiveCallback); + self.postMessage("initialized"); + } catch (error) { + self.postMessage(error.toString()); + } }; self.receiveCallback = (message) => { - self.postMessage(message); + self.postMessage(message.toJs()); } +// Same channel as `receiveCallback`, exposed under `flet_js` so the +// Python python_output shim can post pre-encoded msgpack frames. +self.flet_js.receive_callback = self.receiveCallback; self.onmessage = async (event) => { // run only once if (!self.initialized) { self.initialized = true; + self.pyodideUrl = event.data.pyodideUrl; + self.flet_js.args = event.data.args; self.documentUrl = event.data.documentUrl; + self.appPackageUrl = event.data.appPackageUrl; self.micropipIncludePre = event.data.micropipIncludePre; self.pythonModuleName = event.data.pythonModuleName; await self.initPyodide(); @@ -44,4 +227,4 @@ self.onmessage = async (event) => { // message flet_js.send(event.data); } -}; \ No newline at end of file +}; diff --git a/client/web/python.js b/client/web/python.js index 21814aa8e0..4f785f3a50 100644 --- a/client/web/python.js +++ b/client/web/python.js @@ -1,28 +1,71 @@ -const pythonWorker = new Worker("python-worker.js"); +const defaultPyodideUrl = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js"; -let _onPythonInitialized = null; -let pythonInitialized = new Promise((onSuccess) => _onPythonInitialized = onSuccess); -let _onReceivedCallback = null; +let _apps = {}; +let _documentUrl = document.URL; -pythonWorker.onmessage = (event) => { - if (event.data == "initialized") { - _onPythonInitialized(); - } else { - _onReceivedCallback(event.data); - } -}; +// This method is called from Dart on backend.connect() +// dartOnMessage is called on backend.onMessage +// it accepts "data" of type JSUint8Array +globalThis.jsConnect = async function (appId, args, dartOnMessage) { + let app = { + "dartOnMessage": dartOnMessage + }; + console.log(`Starting up Python worker: ${appId}, args: ${args}`); + _apps[appId] = app; + app.worker = new Worker((flet.entrypointBaseUrl.endsWith("/") ? + flet.entrypointBaseUrl.slice(0, -1) : flet.entrypointBaseUrl) + "/python-worker.js"); + + var error; + app.worker.onmessage = (event) => { + if (typeof event.data === "string") { + if (event.data != "initialized") { + error = event.data; + } + app.onPythonInitialized(); + } else { + app.dartOnMessage(event.data); + } + }; -documentUrl = document.URL; + let pythonInitialized = new Promise((resolveCallback) => app.onPythonInitialized = resolveCallback); -// initialize worker -pythonWorker.postMessage({ documentUrl, micropipIncludePre, pythonModuleName }); + // initialize worker + app.worker.postMessage({ + pyodideUrl: flet.noCdn ? flet.pyodideUrl : defaultPyodideUrl, + args: args, + documentUrl: _documentUrl, + appPackageUrl: flet.appPackageUrl, + micropipIncludePre: flet.micropipIncludePre, + pythonModuleName: flet.pythonModuleName + }); -async function jsConnect(receiveCallback) { - _onReceivedCallback = receiveCallback; await pythonInitialized; - console.log("Python engine initialized!"); + + if (error) { + console.log("Python worker init error:", error); + throw error; + } else { + console.log(`Python worker initialized: ${appId}`); + } } -async function jsSend(data) { - pythonWorker.postMessage(data); -} \ No newline at end of file +// Called from Dart on backend.send +// data is a message serialized to JSUint8Array +globalThis.jsSend = async function (appId, data) { + if (appId in _apps) { + const app = _apps[appId]; + app.worker.postMessage(data); + } +} + +// Called from Dart on channel.disconnect +globalThis.jsDisconnect = async function (appId) { + if (appId in _apps) { + console.log(`Terminating Python worker: ${appId}`); + const app = _apps[appId]; + delete _apps[appId]; + app.worker.terminate(); + app.worker.onmessage = null; + app.worker.onerror = null; + } +} diff --git a/client/windows/flutter/generated_plugin_registrant.cc b/client/windows/flutter/generated_plugin_registrant.cc index be1578b395..00afa0a858 100644 --- a/client/windows/flutter/generated_plugin_registrant.cc +++ b/client/windows/flutter/generated_plugin_registrant.cc @@ -7,14 +7,19 @@ #include "generated_plugin_registrant.h" #include +#include +#include +#include #include #include #include +#include #include #include -#include +#include #include #include +#include #include #include #include @@ -22,22 +27,32 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { AudioplayersWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); + BatteryPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); GeolocatorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("GeolocatorWindows")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); MediaKitVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); + PasteboardPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PasteboardPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); RecordWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); - RivePluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("RivePlugin")); + RiveNativePluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RiveNativePlugin")); ScreenBrightnessWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowManagerPluginRegisterWithRegistrar( diff --git a/client/windows/flutter/generated_plugins.cmake b/client/windows/flutter/generated_plugins.cmake index 61e94283e8..c04e69f80e 100644 --- a/client/windows/flutter/generated_plugins.cmake +++ b/client/windows/flutter/generated_plugins.cmake @@ -4,21 +4,26 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows + battery_plus + connectivity_plus + flutter_secure_storage_windows geolocator_windows media_kit_libs_windows_video media_kit_video + pasteboard permission_handler_windows record_windows - rive_common + rive_native screen_brightness_windows screen_retriever_windows + share_plus url_launcher_windows window_manager window_to_front ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - media_kit_native_event_loop + jni ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/client/windows/runner/Runner.rc b/client/windows/runner/Runner.rc index 1745889da8..9ba0833f4f 100644 --- a/client/windows/runner/Runner.rc +++ b/client/windows/runner/Runner.rc @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "Flet description" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "Flet" "\0" - VALUE "LegalCopyright", "Copyright (C) 2023 Appveyor Systems Inc. All rights reserved. Licensed under the Apache License, Version 2.0" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023-2026 Appveyor Systems Inc. All rights reserved. Licensed under the Apache License, Version 2.0" "\0" VALUE "OriginalFilename", "flet.exe" "\0" VALUE "ProductName", "Flet" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" diff --git a/client/windows/runner/main.cpp b/client/windows/runner/main.cpp index b3fef51ff8..06f35f4802 100644 --- a/client/windows/runner/main.cpp +++ b/client/windows/runner/main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include "flutter_window.h" @@ -17,6 +18,18 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + // Set AppUserModelID so that Windows associates this window with the + // parent application (e.g. a PyInstaller-packaged exe) rather than + // this flet.exe binary. This ensures taskbar pins and shortcuts + // point to the correct executable. + wchar_t *aumid = nullptr; + size_t aumid_len = 0; + if (_wdupenv_s(&aumid, &aumid_len, L"FLET_APP_USER_MODEL_ID") == 0 && + aumid != nullptr && aumid[0] != L'\0') { + ::SetCurrentProcessExplicitAppUserModelID(aumid); + } + free(aumid); + flutter::DartProject project(L"data"); std::vector command_line_arguments = diff --git a/docker/flet-build/Dockerfile b/docker/flet-build/Dockerfile new file mode 100644 index 0000000000..f428f8dc40 --- /dev/null +++ b/docker/flet-build/Dockerfile @@ -0,0 +1,52 @@ +# syntax=docker/dockerfile:1.7 +# +# Base image for building Flet web apps. +# +# Bakes Python + uv + Flutter SDK on PATH. No Flet CLI, no app warmup — +# downstream Dockerfiles install the Flet version they need via uv and run +# `flet build web` themselves, picking up the pre-installed Flutter +# automatically (Flet validates Flutter major.minor only and falls back to +# `shutil.which("flutter")` for discovery). +# +# Built and published manually from .github/workflows/flet-build-image.yml +# for both linux/amd64 and linux/arm64. Image: ghcr.io/flet-dev/flet-build. + +FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim + +ARG TARGETARCH +ARG FLUTTER_VERSION + +ENV FLUTTER_VERSION=${FLUTTER_VERSION} \ + FLUTTER_HOME=/opt/flutter \ + PATH="/opt/flutter/bin:${PATH}" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates curl git unzip xz-utils zip \ + && rm -rf /var/lib/apt/lists/* + +RUN git config --global --add safe.directory '*' + +# linux/amd64: download prebuilt stable tarball. +# linux/arm64: clone Flutter repo at the version tag - the stable channel +# doesn't ship linux-arm64 binaries (same trick the existing Linux client CI +# uses via subosito/flutter-action's master channel, +# https://github.com/subosito/flutter-action/issues/345). +RUN set -eux; \ + mkdir -p /opt; \ + case "$TARGETARCH" in \ + amd64) \ + curl -fL "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \ + | tar -xJ -C /opt ;; \ + arm64) \ + git clone --depth 1 --branch "${FLUTTER_VERSION}" \ + https://github.com/flutter/flutter.git /opt/flutter ;; \ + *) echo "Unsupported TARGETARCH=$TARGETARCH"; exit 1 ;; \ + esac + +RUN flutter --version \ + && flutter config --no-analytics \ + && flutter precache --web \ + --no-android --no-ios --no-linux --no-windows --no-macos --no-fuchsia + +WORKDIR /app diff --git a/docs/flet.md b/docs/flet.md deleted file mode 100644 index ff549cb463..0000000000 --- a/docs/flet.md +++ /dev/null @@ -1,49 +0,0 @@ -# Flet - build real-time multi-platform apps in the language you know - -__Flet__ is the next iteration of [Pglet](https://github.com/pglet/pglet) project. - -Pglet demonostrated there is a strong interest to write web apps in Python. - -Unlike other cross-platform GUI frameworks for Python (Kivy, Beeware) Flet does not re-invent the wheel by making its own widgets, but instead it's based on [Flutter](https://flutter.dev/) by Google, so apps built with Flet look beautiful and professional without any efforts. Out-of-the-box Flutter implements [Material](https://docs.flutter.dev/development/ui/widgets/material) and [Cupertino](https://docs.flutter.dev/development/ui/widgets/cupertino) widgets for building Android and iOS UI respectively. While Material widgets work great for building Web and Desktop apps too there are platform-specific widgets available from 3rd-party developers: [Fluent UI](https://bdlukaa.github.io/fluent_ui/) for Windows, [macOS UI](https://pub.dev/packages/macos_ui#macoswindow) for macOS. We are going to implement them in the future versions of Flet in the form or "adaptive" controls. - -Multi-user always-connected apps. Look at apps on your phone... -With Flet we will try to explore a different model of building and delivering apps. - - - -## Why new project? - -Pglet is for web apps and is based on Fluent UI React components. - -Flet is for web, desktop and mobile platforms and is based on Flutter. - -Fluent UI is mostly an internal project... - -Flutter is fresh and awesome ... Flutter is [ideal for Single Page Apps (SPA)](https://docs.flutter.dev/development/platform-integration/web#what-scenarios-are-ideal-for-flutter-on-the-web). Many developers criticize Flutter for rendering everything on canvas making SEO impossible. But I personally see rendering on canvas as an advantage: 1) the app looks less clunky, 2) the app looks the same as on desktop and mobile. Non-selectable text? Have you ever tried to select something in AWS or Azure console? If you strongly need SEO then you should choose HTML-based framework such as Next.js or similar. You obviously don't need SEO for your internal dashboard, game or admin panel. - -Flutter is broader. We'll start with Material design and then add platform-specific controls: [Fluent UI](https://bdlukaa.github.io/fluent_ui/) for Windows, [macOS UI](https://pub.dev/packages/macos_ui#macoswindow) for macOS and [Cupertino widgets](https://docs.flutter.dev/development/ui/widgets/cupertino) for iOS. We could probably implement "adaptive" Fler controls which look-n-feel depends on the platform the app is running on. - -Flutter gives precise layout. No more hacks with vertical alignment or horizontal alignment in nested divs. - -Flutter will give access to mobile experiences: camera, location services, accelerometer, etc. - -Flet is language-agnostic. It includes DOM server (Fletd) which translates language-specific DOM changes to commands and then into Flutter widgets. - -Flet is an opinionated framework based on Flutter. Flutter is extremely powerful and flexible, but has a steep learning curve especially for developers without React experience. Flet hides that complexity by replacing Flutter's declarative model (re-build a UI tree on app state changes) with an imperative (modify UI tree as program progresses). - -A lot of renamings would create a mess in a project repo - it's easier to start over in a new repository. - -Less scope. - -A lot of functionality was added to support Bash: a custom protocol via named pipes with commands serialization/deserialization, CLI support with `pglet page` and `pglet app` commands. It's not necessary anymore with high level languages such as Python which communicate with Flet server via WebSockets directly. - -With Flet we are switching to monorepo storing Flet server, Flutter client and all language bindings (SDKs). Every CI build and release creates the same, unique version for all the apps and components. - -## Why changing name? - -* Confusing name. It's been almost a year and I haven't used to the name yet. Is it a "page-let", "p-g-let" or "piglet"? Is there connection to "PostgreSQL" or Paul Graham? On the other hand "flet" is short, simple and easy to pronounce. - -## Migration - -* All sizes are float numbers. Not "px", "pt", "rem", "%" or something else from CSS, but just numbers meaning "virtual pixels". -* All percentage values are rational numbers between 0 and 1, i.e. 0.5 means 50%. diff --git a/docs/roadmap.md b/docs/roadmap.md deleted file mode 100644 index f0fbe7200e..0000000000 --- a/docs/roadmap.md +++ /dev/null @@ -1,805 +0,0 @@ -# Flet Roadmap - -## Sprint 1 - -* Controls - * Common - * [ ] Control - * [x] Page - * Layout - * [x] Container - * [x] Row (flex - default mode, wrap) - * [x] Column (flex - default mode, wrap) - * [x] Stack - * [x] ListView - * [x] GridView - * [x] Divider - * [x] VerticalDivider - * App structure and navigation - * [x] Tabs - * [ ] AppBar - * [ ] NavigationRail - * Basic controls - * [x] Text - * [x] Icon - * [x] Image (+custom assets directory for Flet server [see here](https://docs.flutter.dev/development/platform-integration/web-images)). - * [x] CircleAvatar - * [x] ProgressBar - * [x] ProgressRing - * Buttons - * [x] ElevatedButton - * [x] FilledButton - * [x] FilledTonalButton - * [x] OutlinedButton - * [x] TextButton - * [x] IconButton - * [x] FloatingActionButton - * [x] PopupMenuButton - * Input and selections - * [x] TextField - * [x] Dropdown - * [x] Checkbox - * [x] RadioGroup and Radio - * [x] Slider - * [x] Switch - * Dialogs, alerts and panels - * [x] Banner - * [x] SnackBar - * [x] AlertDialog - -* Flet Client - * [x] Web - * [x] Windows ("client" mode - started from Python) - * [x] macOS ("client" mode - started from Python) - -* Flet Daemon - * [x] "assets" directory with static content - -* Samples apps - * [x] Counter - * [x] To-Do - * [x] Icon browser - * [ ] Chat - -* Website - * [ ] Controls S1 reference - * [x] Introduction - * [ ] Home page - * [ ] Blog post - * [ ] Python Guide - * Deployment (+how to change favicon.ico) - * [x] Deployment to Replit - * [x] Deployment to Fly.io - -## Sprint 2 - -* Authentication -* Controls - * Navigation - * NavigationDrawer - * NavigationBar - * Layout - * Row (responsive) - * Column (responsive) - * Behavior - * Visual Density ([more](https://api.flutter.dev/flutter/material/VisualDensity-class.html)) - * Early detection of layout issues (like enabling scrolling in unbounded controls) with [Layout Builder](https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html). - * Scroll speed on Windows Desktop [The issue](https://github.com/flutter/flutter/issues/67985) - -* Flet Client - * Web - * [Loading splash](https://docs.flutter.dev/development/platform-integration/web/initialization) - * [ ] Windows ("host" mode with hot reload) - * [ ] macOS ("host" mode with hot reload) - -## Year 2022 - -* Grids -* Charts -* Navigation controls and Routing -* Responsive layout -* Adaptive controls -* Animations -* PubSub -* DB - -## Controls - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
✓ StatusFletPgletSprint
Layout
ContainerStackS1
RowStack horizontal=TrueS1 (flex, wrap)
ColumnStack horizontal=FalseS1 (flex, wrap)
Stack-S1
ListViewStack horizontal=FalseS1
Divider-
Spacer-
GridView-S1
SplitViewSplitStack
Card-
Basic controls
TextTextS1
MarkdownText markdown=True
IconIconS1
ImageImageS1
CircleAvatarPersonaS1
Chip-
To-DoLink
ProgressBarProgressS1
ProgressRingSpinnerS1
Buttons
ElevatedButtonButton primary=TrueS1
OutlinedButtonButton primary=FalseS1
TextButtonButton action=TrueS1
IconButtonButton icon={icon_name}S1
PopupMenuButtonButton with MenuItems
FloatingActionButton-S1
Input and selections
CheckboxCheckboxS1
RadioChoiceGroupS1
DropdownDropdownS1
-ComboBox
DatePickerDatePicker
TimePicker-
[Example]SearchBox
SliderSliderS1
TextFieldTextboxS1
SwitchToggleS1
SpinBoxSpinButton
Dialogs, alerts, and panels
BannerMessageS1
SnackBar-S1
AlertDialogDialogS1
SimpleDialog-
BottomSheet-
ExpansionPanel-
App structure and navigation
Appbar
BottomNavigationBar
Drawer
TabBar
TabsTabs
Grids
DataTableGrid
Table-
Utility controls
-Html
-IFrame
-Persona
- -## Clients (Flet View) - -* Web - S1 -* Windows - S1 -* macOS - S1 -* iOS -* Android - -## Colors - -* [Full list of Material colors](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/colors.dart) -* [Themed colors](https://api.flutter.dev/flutter/material/ColorScheme-class.html) -* [Material color roles](https://m3.material.io/styles/color/the-color-system/color-roles) - -## Icons - -[Full list of Material icons](https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/src/material/icons.dart) - -## Control - -Base control class. - -Properties: - -- visible -- disabled - -- expand (int) - The control is forced to fill the available space inside Row or Column. Flex factor specified by the property. Default is 1. The property has affect only for direct descendants of Row and Column controls. (Wrap control into Expanded). -- flex (S2) (int) - The child can be at most as large as the available space (but is allowed to be smaller) inside Row or Column. Flex factor specified by the property. Default is 1. The property has affect only for direct descendants of Row and Column controls. (Wrap control into Flexible with fit=FlexFit.loose). - -The only difference if you use Flexible instead of Expanded, is that Flexible lets its child have the same or smaller width than the Flexible itself, while Expanded forces its child to have the exact same width of the Expanded. But both Expanded and Flexible ignore their children’s width when sizing themselves. - -- width - wrap into SizedBox -- height - wrap into SizedBox -- minHeight (S2) - wrap into ConstrainedBox -- maxHeight (S2) - wrap into ConstrainedBox -- minWidth (S2) - wrap into ConstrainedBox -- maxWidth (S2) - wrap into ConstrainedBox - -- fit (S2) -- fitAlign (S2) - Wrap into FittedBox - -- opacity - allows to specify transparency of the control, hide it completely or blend with another if used with Stack. 0.0 - hidden, 1.0 - fully visible. See https://api.flutter.dev/flutter/widgets/Opacity-class.html. - -More info: - -- https://api.flutter.dev/flutter/widgets/Expanded-class.html -- https://api.flutter.dev/flutter/widgets/Flexible-class.html - -## ListView - -Docs: - -* https://api.flutter.dev/flutter/widgets/ListView-class.html -* https://docs.flutter.dev/cookbook/lists/basic-list - -Properties: - -- scrollDirection - `vertical` (default), `horizontal`. -- padding -- spacing -- autoScroll - scroll to end on items update - -### ListTile (S2) - -Docs: https://api.flutter.dev/flutter/material/ListTile-class.html - -Properties: - -- contentPadding -- ... - -## GridView - -Docs: https://api.flutter.dev/flutter/widgets/GridView-class.html - -Properties: - -- scrollDirection - `vertical` (default), `horizontal`. -- padding -- runsCount -- spacing -- runSpacing - -## Card - -Docs: https://api.flutter.dev/flutter/widgets/Card-class.html - -## Divider - -Docs: https://api.flutter.dev/flutter/widgets/Divider-class.html - -Properties: - -- height -- thickness -- indent -- endIndent -- color - -## Text - -Docs: https://api.flutter.dev/flutter/material/Text-class.html - -Selectable text docs: https://api.flutter.dev/flutter/material/SelectableText-class.html - -TextTheme: https://api.flutter.dev/flutter/material/TextTheme-class.html - -- value -- textAlign - `center`, `end`, `justify`, `left`, `right`, `start` (for RTL and LTR texts) -- size -- weight - `bold`, `normal`, `w100`, `w200`, ... [see all](https://api.flutter.dev/flutter/dart-ui/FontWeight-class.html) -- italic -- style ([more details](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/text_theme.dart)) -- pre (S2) - [more info](https://stackoverflow.com/questions/64145307/full-list-of-font-families-provided-with-flutter) -- color -- bgColor -- overflow - (TextOverflow) `clip`, `ellipsis`, `fade`, `visible` -- selectable -- tooltip -- noWrap - -## Icon - -Docs: https://api.flutter.dev/flutter/widgets/Icon-class.html - -Icons list: https://raw.githubusercontent.com/flutter/flutter/master/packages/flutter/lib/src/material/icons.dart - -Properties: - -- semanticLabel (S2) - Text to announce in accessibility modes - -## Image - -Docs: https://api.flutter.dev/flutter/widgets/Image-class.html - -Properties: - -- opacity (S2) - override control's opacity -- semanticLabel (S2) - -## RadioGroup - -Properties: - -- value - selected value -- content - -Events: - -- change - -## Radio - -Docs: https://api.flutter.dev/flutter/material/Radio-class.html - -Properties: - -- label -- labelPosition -- value - radio's value -- tooltip -- autofocus - -Events: - -- focus -- blur - -## Slider - -Docs: https://api.flutter.dev/flutter/material/Switch-class.html - -Properties: - -- value -- label - use `{value}` -- min -- max -- divisions -- tooltip -- autofocus - -Events: - -- change -- focus -- blur - -## Switch - -Docs: https://api.flutter.dev/flutter/material/Switch-class.html - -Properties: - -- label -- labelPosition -- value -- tooltip -- autofocus - -Events: - -- change -- focus -- blur - -## Checkbox - -Docs: https://api.flutter.dev/flutter/material/Checkbox-class.html - -Properties: - -- value -- tristate -- label -- labelPosition -- tooltip -- autofocus - -Events: - -- change -- focus -- blur - -## Dropdown - -Docs: https://api.flutter.dev/flutter/material/DropdownButtonFormField-class.html - -Properties: - -- label -- icon -- border -- filled -- hintText -- helperText -- counterText -- errorText -- prefix: Control -- suffix: Control -- tooltip - -- value -- options -- autofocus - -Events: - -- change -- focus -- blur - -## TextField - -Docs: https://api.flutter.dev/flutter/material/TextFormField-class.html - -Properties: - -- label -- icon -- border -- filled -- hintText -- helperText -- counterText -- errorText -- prefix: Control -- suffix: Control -- tooltip -- autofocus - -- value -- keyboardType -- multiline -- minLines -- maxLines -- password -- canRevealPassword - true/false -- readOnly -- shiftEnter -- textAlign - -Events: - -- change -- focus -- blur - -## AlertDialog - -Docs: https://api.flutter.dev/flutter/material/AlertDialog-class.html - -Properties: - -- open - bool -- modal - true/false (barrierDismissible) -- title (Control) -- titlePadding -- content (Control) -- contentPadding -- actions (Controls) -- actionsPadding -- actionsAlignment (mainAxisAlignment) - -Events: - -- dismiss - fires when non-modal dialog is dismissed by clicking an area outside it. - -## Banner - -Docs: https://api.flutter.dev/flutter/material/MaterialBanner-class.html - -Properties: - -- open - bool -- leading (Control) -- leadingPadding -- content (Control) -- contentPadding -- actions (Controls) -- forceActionsBelow -- bgColor - -## SnackBar - -Docs: https://api.flutter.dev/flutter/material/SnackBar-class.html - -Properties: - -- open -- removeCurrentSnackBar -- content (Control) -- action - action button label -- duration (S2) -- behavior (S2) -- bgColor (S2) -- margin (S2) -- padding (S2) -- width (S2) - -Events: - -- action - when action button clicked - -## Tabs - -Properties: - -- tabs -- value -- animationDuration - in milliseconds - -Events: - -- change - -### Tab - -- key -- text -- tabContent -- content -- icon - -## SplitView - -Docs: https://pub.dev/packages/split_view \ No newline at end of file diff --git a/media/diagrams/chat-tutorial-layout.drawio b/media/diagrams/chat-tutorial-layout.drawio deleted file mode 100644 index f0040eb2c0..0000000000 --- a/media/diagrams/chat-tutorial-layout.drawio +++ /dev/null @@ -1 +0,0 @@ -7Vxbc5s4FP41ntl9iAcQAvwYO2l3Z5Jptu1ON/uyQ0C2NcXgBTl29tdX4mY4kgtxuWSTOpkMOkgCnct3LpIzQYvN4X3sbte3kU+CiaH5hwm6mhiG4yD+VxCeMoKNtYywiqmfkfQj4RP9j+TEotuO+iSpdWRRFDC6rRO9KAyJx2o0N46jfb3bMgrqT926KyIRPnluIFO/UJ+tc6quaccbvxG6WuePdor1bdyic05I1q4f7SskdD1BiziKWHa1OSxIIHhX8CUb9+7E3fLFYhKyNgM+vF9ffPnw7+Wdf//1Zrv9+/binz8u8lke3WCXLzh/WfZUcCCOdqFPxCTaBM33a8rIp63ribt7LnJOW7NNwFs6v8ynIzEjh5PvqZer51pDog1h8RPvUgwoGJZrDLLy9v7If1z0WVdYX3Z0c5mvyrmPbOEXOWeewSVD4tKdUBvIKb5mVmdHwuLoK1lEQRRzShiFvOd8SYMAkNyArkLe9DiPCKfPBQcp18LL/MaG+r54jJL/dQl1IQJUF4Exk0VgqSTQlwBQx2rqu8k67asDeUwMtMTiR9CjkFXo2UcSKr9jpZ9+WI9shfZrCt4buC/mm83MJ6F/KcBWqHDgJgn16vyuC4ccKPtLXE9x3rrP+4nrq0Ol29VT0Qj5UrJBuo0Lwn1K0DS9IBwHp63a6DsSU84RYV8VQyG+5ACArPhKo13skWaAYG68IqwJbmXZ12Qri7agxSRwGX2sv65K3PkT7iLKF1KqlgmA1YIaky0zH1X1JHAiG0ykgYkyPkgTpdpXLvt8hbQkhVxwU3VpyEVrLIRMD1s3FDN8jncnYfq52ByQJfseMiccbWi4ukm7XZlHysdckoIU8eHLIDWUNR9I+AzzreBTyjk857+clwthGfhKLAbP9WOb/4ruMYelkL++S1M9JW7C9iRhqZ0xl7kP6Uo78gUmbvYFujmkM7B7xCNj1h6ReKNHSLHGhAoELfxcqChdFXRnA0HFbMjAYbk0PE8VIPjWg4W7ChBMwFFHtkfTUQUIvRlkkatVuHxDE/ZIyT7D4+ufeNwZHlt2s/yHxWO9RRJ5NiBrdhWQp5pujwnKhaY3BnqzUdF7VlcRB4q+daAHsMZ2hkVvXU68e4TvF5X3WUg2a2Xe11vRQ2+RdD/TrIscrkzXsvytTOdOZG9dGrDZ0oAz1RvLgi0HGJ5+pgXb0IKNgS1YLh585OryhkOAGgR1EQ8AsMeKeEAVDvYXDuAWuBEEdJucqmdWAMRNtllVf0kPgmsQtH1MHN9UgbNjPKCuwBkDc7RMRcyt4LHZG4/lEkgv2NxYVzsGahaqBGoX2lRDBWGcSM1uC/T4RQE9LKW1Bnq7wWP0DfRyVeZ3LwrnO8ai8C3jfRcQD0pwtiI2HBbiHUnYn7lE31ES+G0y/mfF7BDxXeIslVUWy3PIw7KfKosS8dGgkD9oKavIhU7nPKeypC6YD/QdKUrOpmr/cdYX8w25xLFYu+yWJMl3NoLfArx1Hc7qddGbCqibDQl1hZV1X9wqdhcqOXCL3c965mwMmDqXx28aI6pRi18AuM1zM2eQVkmHS3qOp4zuqy9n6F3n6jOWVsxmU02bVT51JYGOo62SQE+FdTTF+rCK0uZ4Rlfp9tLxiHqL68HBYqe4Gx9gARvWjKmNJT9gGVMsK8yR2r0vUBw8oLEXkMtH7hPjtxwGdCB1UADHiqBv0CTHkJMcScKdBdzX6c9YATfkPZo5Eu/Lnfsq822jJ+YjOez6MxHHe7RfRKb5649JAljaKBmmgSHIyQiHVEVFoy94Q7InEQlOluG8Xr4rMns13/tzLKhFOfeV5vbm6Lk9anOe7P8dQOEXEkChUVzqKPv50KWa47tUuYD4yl0qHt2lFg8DLvV1e1T8Ajyq2duZtLHKJ3mI0Fh9y9zZWHUWuAsJD4y1LqyA7yrYMM3ruapiyvkHt57d5udW5g9uZYL9bnPs0yrmiznlVp6lGAdgCo1vBhhnTICxYGgLv1DQ+sAE2GnCA5+MM7v/Wt0rVzxjXMWzYUAPYpfWigdcGx7atbU5nzfgjua09m3OphNnY4RU2RbLWIoHo+uzQyqtL73jzeO/Mci6H/8XBLr+Bg== \ No newline at end of file diff --git a/media/diagrams/chat-tutorial-layout.svg b/media/diagrams/chat-tutorial-layout.svg deleted file mode 100644 index 65b6290371..0000000000 --- a/media/diagrams/chat-tutorial-layout.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
Page
Page
Container, expand=TrueListview, Expand=TrueRowIconButton
TextField, Expand=True
TextField, Expand=True
ChatMessageCircleAvatar
User (Text)
User (Text)
Messsage (Text)
Messsage (Text)
User (Text)
User (Text)
Message (Text)
Message (Text)
Column
Text is not SVG - cannot display
\ No newline at end of file diff --git a/media/diagrams/flet-highlevel-diagram-v2.drawio b/media/diagrams/flet-highlevel-diagram-v2.drawio deleted file mode 100644 index 024402b348..0000000000 --- a/media/diagrams/flet-highlevel-diagram-v2.drawio +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/media/diagrams/flet-highlevel-diagram.drawio b/media/diagrams/flet-highlevel-diagram.drawio deleted file mode 100644 index 74f6277697..0000000000 --- a/media/diagrams/flet-highlevel-diagram.drawio +++ /dev/null @@ -1 +0,0 @@ -7Vttd6I4GP01nrP7QQ8ERPxY32Y60+50x50zux8jRM0WCQux1f76TSAoedHaivZt2tMjPIQAz819cnOlDae/WH1KYTK/JiGKGsAKVw1n0ADAtv02++CRdRHxOt0iMEtxKBptA2P8gETQEtElDlEmNaSERBQncjAgcYwCKsVgmpJ7udmURPJVEzhDWmAcwEiP/sQhnZfPZVnbA58Rns3Fpf22OLCAZWMRyOYwJPeVkDNsOP2UEFpsLVZ9FPHklXkpzhvtOLq5sRTF9JATPl+R669o9ueX4d+Ujn58H1qdy6Yj0LiD0VI8sbhbui5TkJJlHCLei91wevdzTNE4gQE/es9AZ7E5XUTi8JTEVKBo830Y4VnMdiI0ZXfZy2hKblGfRCTNO3c8Z+CNRpsjZY5ZdnrizlBK0WrnM9ubTLIhiMgC0XTNmogTOh2R/PUGt2L/voKlJ2LzCoygDEIxfmabvrcpZhsiy0/IuGs/nnHWDRvf6PFswywpBv0UrzhCPRmrp2S7Cpwr9itntv3ecOjogNYAku+0JZAcRwfJMWDknAwi8BKkqIIB00C0900wjvz+sN+vJ/u2o1AEdLXsu76JIuBk+Xe1/P9EkzEJbhHNGoB1al3e9PdAYj0OyV4CdCsYBSyPKNVQiEmMdJYUPzyOo0hpWgNWwJexAgasbCNWNUA1inr/dp1gMfhG/X/Wg6/NbxcPTVuHSq9mcXjBZ2KezAhmGQ5kKHZkAVgolOZmPS2Vx24bnrqMpSiCFN/JM7opFeIKNwSzO9lk3bOUrFt+y/LlXjKyTAMkTqxOwkpfHRVBQ18UpjNEtb5yfDYP/3x2eQbEPLjg/IgnWZIDYn0Zf/uDfSyTEFImv7QG6r4KOUPuCk6YFpSnK5VTnA2Yia0LcWCBw5D30UtRhh/gJO+Psznh2cjz0+412gNDTY345XowuJ3ldaBCymn+s4+BQjyK620lW3VM7hn+O/natFpMgvgS4m4tYxIoU2arC+QuyHSaoZOMH/94xh+MlVIBDqqV5ykKGpE7Sok9tCJo1UXt6MTlwLQA0MrB8A5x+r2BMnAUx3eP9xegeFPheNM9F8MNk/rNms5JXGgv9ucUW59I8Ylo0NLAP0ohV/VTVfAaRdhWLYOa1o22q5CyaxBarqG6uKfSxHbn+LL72muq6ylZ97rPq6maTlY7OnFNtU1z5K+iqg3nD1VVy9y8ZwZrxDtiqaRVg/MvlYDJq9N4fMMt5De1VqqfzxVH+8wLIVfq9JwLIaDLpEuOVSwuZ3Z0szlMUM5vsgwfF0ayiqoCCR43qZhy6uW/Ow2vSkt3wH/r0U+eY7fkOmsSUKWmqRYiv7N7BBwloEqTuYLWNZngiFM3RHeY5V8FjT0/NbmGqgeoe32Hk9cEv2xkmoz5sbhJS4dxY9TXAKOvrE19TwfROpHdaHaGHQ3EMUrZM74P7Abd7qjr1YOdY8vY2Vb7pcHTGVi19XcuH9+rm685P+d0882qXAOoTxYJq5Ehi46iJeW5Y9dNEqZqIs6vSSqh5v235F9n54lsZnn6L1gD205WhRQSx9nWjH+20AoVFkILJrdiCydwz2g43kzoesNh5UvQ3WZCTVVUswrL/ZczE3QmVoDmrk6B8WtwdKx6QNBWEy/v6Ohz2Y8s51eSklkKF/Xlv1167jckwxQT4/R2pTTYTHOPToiUJBJmHWWmU+EXIGtatU4Fqjp4tnMg3sA6FeCOycITZbQsiPx1olaxkvzt9/Iou9qmAR8RKA6zhnh1qVx35ou3xQIWhyjJCzZfiLDmb0Qg7V2ZPgX5jrL2sDtWyyB+SidI8kG6pwJftwQHOEsgDebcM7CQMAML6Ng6nIER6aroA6EG2uBQ1MAG3/pFqwbbflr9qtHPn5NfQY3WhdFfKYyzqHD29pVcHOfMFS9OsGClUlfLcRBhFOsG0bsltutp5dgHL1yMgT4TfydLKhfiCQxuS+wgB32/OPtAAL6Oygz2U1UQUdByu3hldzwz+Q3vFr9Oaalu6Gdw8czYnUoLaciNRaGUVZAy01p3mPNwj2f0YTAEjn0+DM1vvu3SRTvmtw+miwxvs2oD4GDDyAYHGkbP0UVsd/s/KMVXY9v/5HGG/wM= \ No newline at end of file diff --git a/media/diagrams/flet-mobile-update.drawio b/media/diagrams/flet-mobile-update.drawio deleted file mode 100644 index b0d57a1604..0000000000 --- a/media/diagrams/flet-mobile-update.drawio +++ /dev/null @@ -1 +0,0 @@ -7Zpdc9o4FIZ/DTO7FzC2jG245LPdtmnS0t22VzuKLcAbGbmyINBfv5ItgWUZ8KSQkKRJp7GOPmyfR+eVZKnhDOL1GwqT+RUJEW4AK1w3nGEDgG7b4/8LwyY3eFY3N8xoFOYme2eYRD+RNFrSuoxClGoFGSGYRYluDMhigQKm2SCl5F4vNiVYv2sCZ8gwTAKITevXKGRzabUta5fxFkWzubx1x5UZMVSFpSGdw5DcF0zOqOEMKCEsv4rXA4SF75Rf8nrjPbnbB6NowepU+PoP6fS+vHF706kLP24GcLK6a4K8lRXES/nC8mHZRnmAkuUiRKIRu+H07+cRQ5MEBiL3niPntjmLscyekgWTEG3+hn1IA5l0eSpllNyhAcGEcsuCLHhGXz4Bogyt976avXUY72iIxIjRDS+iKnSljzeq88j0/Q6Z15G2eYEWULSg7Cazbds7T/IL6cxqx779QK7eo9mnd6NvjI3//jyy/L+adtvw7M2GzcmC2+hywaIYnc7TWTrCWHm2AZxxZzAaDPb5fIdFuLW/x98VVPYiAJaOAHS7BgK7XYGgfTYCBoABiZMIcwcDa4yXjCEq7pskDeBh/jT9W6rx8H4sRWxmnm6mmbt6vIBtJ+vMZyqfX83E3xZac6b8Ya0WTO7kVZTAs3LueqPReFyDs3Mazj54Qs5j3P+v6wTx8Jp1vm+G75vXvZ8VnMcYMTEk4Ei858m8LxQMw1uEb0gasYiHsjMM+B14N3L6woMRHzY+lArEURjiDAWOZpU1ejKDkUQj5qvby0cvw5eIde68R7SH4vc8tG2nJu2tHJw+rJ39wppQMqMw/o38hEJ+Acjb5lj6Fd1OSHCHWHoAtnUcdu5KNbMDOv5uFcNKnRWVCjzyn2p4J0DkuCUNBhWIrEpE59Jgk5DBBS3CnpiQC2dimKZRoKPg/qCbbxJblvguEi3gqvRwXcwdblRqHbFvqhF+XazGk7taIqEq7cWQkiUN0KHemJdjkM4QOz4uoVBbYJhQC9DcCmbKRhGGLFrpy5IqkPIONyQSg5/qM155fmZ1WlZHbyV/dVmxuJIoteV3jreVu8doK+td25d/uCR4Ff3Ng7GI7sVtmmSArXeT64/8zzIJIeNrSKNAOV3usJxcpu16Pz2q6lv9p4jPGuFt1p7oc4nwRuYft99whxWTu2ys6cPgbpapWEFSptlPZcc9HJHmukouleWDNYqr0Sq1afJY8v2ORrx9kj5p+1qjTVdvgEynKTpL7+n8ulrVIKV0ydJ0yT+sS1sVtHUV9I+pYC1BOyRURUE7JHwXImiGCPmlwa2umhnKWG7ozFLWrSNloxUS0vEMJMzshwdD8ILlqalkQX26fCx5Urr4S7OpyxOfurOpg8u+C1GftlcSDa/7MPUBZRkrN3Rm9bGrxsKXLz/bELto/XGfRn/UMvE1rOaUrjyz2Y8hG7+wnDO07PGXc8D8iFuhQjdir+5ZredqqtE24C5YjZ5ssdZ2jb7xqr/+efbxr3/dM338q5ZQE1Bhp+0NachNtr2kHnG38+BgUZ+BIZlPvtvpVK0Z5Lam2qAUZxVauXr+8afK5XfbFhCA+MCeNuS5CKW1mQ7FMcyzmCAq99hSRFdiG7XElruRVYVaOXDMAKmvxlU9Ro/+42r8gN0Rv6XPymzfUpYifDV308b+7rngm5P4YZQmkAVzMU5aSE7fc3R8SOEwsKmdr4gacEFdamDL9/QbWwY2EVbh/rj6vZH5cI2+gI1Mc6D8QuEixfl09pDm8qmYCF25o8GNBaku6vGeMw8vNrLbnqHHHfDEagzMofgzWTJdiW9hcKfYQQE9zU4j7TvB8IoAXoY0g8OhKgNRhuXuNBl/4lnVsuTF8vOBvi4EVm1255oMGeQmUij1aVBpBmutIhGHB5aWr4eh+kj1GAx/0N7nVfB9jtvhvyEnaF/d44ozfXPGkuz85Zj/s4Hfsvgvf/9eQujrHu/s2rAeIJY8uTuhnn/R2R3zd0b/Aw==7Vldj+MmFP01kdqHRDaOneQxySRTVbvbadNqd/tGbBKjxcbC5Gt+fcEGf0FmopnxaLXdZOSBC1zsew6HazLwlsn5nsEs/kgjRAbAic4D724AwGwciKs0XEpD4MxKw57hqDS5tWGDH5EyOsp6wBHKWx05pYTjrG0MaZqikLdskDF6anfbUdKeNYN7ZBg2ISSm9TOOeFxap75T239DeB/rmV1HtSRQd1aGPIYRPTVM3mrgLRmlvCwl5yUiMnY6LuW49ZXW6sYYSvktA06Abv+6n39chP+uXDR9vEP861B5OUJyUA+sbpZfdAQYPaQRkk7cgbc4xZijTQZD2XoSkAtbzBOimnc05QpEVzzhArJQVX1Ryzmj39CSEsqEJaWpaFioO0CMo/PVR3OrgAmiIZogzi6iix7gqRhfOvVTDZmvIYsbcFXgQEWTfeW7jqQoqGDaA3tMPuEPdD/cnkHM/ozP9xAchp4R2DVBXBKVYPlUbxZlGVcCt4g80BxzTFNhDMUMSIR4IaOKBZk/dDokOIrkzAtI8N46Yq4aOM1aME709OrWi9vBhGhQB8Db+fJrwC1aguKjPDTs5afiggG8hR5XueAbXJgZXHDHNi44fXFhbHDh4cJjAcRPEvREggrgJ0hQ4f0+JDCVVpPAYYeU4wSJ0i9ZYRuhM/r17dhhgWc9Xa6Wy2uSXCPt+f0AAmY3AjLuCw9gEegDl/wXk2WZBKN/GGbBarVePw8D6EkcbTBYxbE3GHSe91QGgtJoLlM5KVEE5jkO20FGZ8y/iLKjyl9leTTxVfXu3Gi7u+hKKm7/i/YgK81hsl6PK2p64FUYcnpgIXo+J+CQ7RF/fr9AUSs1NUFtZjcWzLSNIQI5PrYTWhuQaoYHimWCojkzDjqcmc7aLsrnVqOaCWjHEZh2HAUdR2VgDEcFr6rHfgXVbMluABO5ZNNtnhXYOqujwDU3G7r1LkcFWMUG26bms1trtQkzlONHuC38SZplMgxFYPzFwL+zaIlJxKdXmJlhq5cmNeug+V5iU4+hMwKTybQF4vhNODYEba96qWgPdLfLUT+kMPeBF+uP29IfcKP+OG39Af3pz/hG/fG+K/0xZMOZjpzpyySoq2VuV8v6liDztdAiQQ/yTAI4hyyCHP1QUqQX23csRdqNcuq/lxABc3f6m8E0JyUHnN83f3ySPlJOxb86VxWLUDA2N1ggAszbBLDmmM2EVKedNxPFlvzW6bFzE1FekMNOOnqgMGrmsBq39rvddS687lXC3EM2Ys+QqCGVTTgKteIIKEfsWGB3xFBcP6Pthobf/t8g+uaJ3TuDaEozD0Us5tItWLtgMnLEVzz/PKNMwBgQCc1W4BjsZemQ4nPVXfwdoWhai3d7cd0RZB75/bDgepPOjg1uXqEjvy94fQPef/JiEWaM7hlMDHhede7d42Fc3fPJ87g3wNH1O9nSxLZILZmf298qDQwYpahGP9Ez0OvmzTb0bGn7S8CTQlf9kFVmRPWvgd7qPw==7Zjvj5owGMf/GpLthYZSQe/lqXC325ZpLpdlL6sU6K5QVuv5469fCwVBcHoJLFkyNQrflrZ8P88DDxpwFu8fOEqjr8zH1LBMf2/AuWFZDgTyWwmHXBiZTi6EnPi5BE7CMzliLZpa3RIfb2odBWNUkLQurlmS4LWoaYhztqt3Cxitz5qiEDeE5zWiTfU78UWUqxPbPOmPmIRRMTMwdUuMis5a2ETIZ7uKBF0DzjhjIt+K9zNMlXeFL/lx3oXWcmEcJ+KWA3w8t1cRenlcOp/dqTtYuotvAz3KG6JbfcJ6seJQOMDZNvGxGgQYcLqLiMDPKVqr1p1ELrVIxFQ3BywRGiJQ+4iSMJE7FAdykdON4OwVzxhlPBscOnDueF7ZUlgszZnqlWEu8P7iKYPSSBmAmMVY8IPsog8Yj7X3h3pQ7U4kLUdrUYUiLESkoycshz4ZLDe0x+/we9zw26NYqPilRJ1UZ+bbcp+iFaYLtiGCMAVhLWfA0vipMpXIGP9y1iEmvq9mLrE1jrjXDYKpuRFfF/ONivn12rP1EEoL1glLcFsAjObq3Q3uiVnHPWrBbbbgnnRAe5eu0qdlvEz940IED+DpJ0wHVoP24iAiafW/inl8hbIEGtjq3Zrr2UuPUNHzVxkCDd4tUXFzCADnxhgAXaR8axDAi0Fg8m0iSIzl1oc004Z4jz92ewU+w+NNZu5s1sCj0/NEGtr9ACmT7RqQUV88QDMrXzYy+uWJchZyFHfnv9Vvdp56/jFBu6AIztLqrkkRWG2XVtAXxWZaqTup/x9eA97d6Do8uyd2rUVQMwEb1OQossLH14mhTZqX/QHZK8rTOu/3FJxV+EU5UznSnkxdFzZr2i4Kl4ldIwRhkxBsq1P7KlNHLcm1FSK7SqI0NSyHqlNf8Ro159dWPcxkxg02mZP3sgMA6T7zqWiXW6H6HaL01bDkCs0hSVGvt707x3Ur2C/f9ib9lKJ/8653XB1fnr6Ow4DjeOD8iNf3zGt50PO8T1WOOZJtQvYZNS//vCHZ5Mk6RX4H2ZPKGSRpkaiTaHW45VHg9itkG/pTcJgt9LsgCMfDelaClqwElt2EKOPZfjdGZXP5X0DWVvlDBbq/AQ== \ No newline at end of file diff --git a/media/diagrams/page-views.drawio b/media/diagrams/page-views.drawio deleted file mode 100644 index 96cf231edd..0000000000 --- a/media/diagrams/page-views.drawio +++ /dev/null @@ -1 +0,0 @@ -7Zhdb5swFIZ/DZeNwIZALpukaaVparVO23rpggPeDEbGaUh//exgEz7SJUuTJtJWVa05NsfmOe+xD1hwkpa3HOXJZxZhagE7Ki04tQBwXAAs9WtHq8oSOF5liDmJ9KCN4ZG8Ym20tXVBIly0BgrGqCB52xiyLMOhaNkQ52zZHjZntD1rjmLcMzyGiPat30kkEm11bHvTcYdJnOipA093pMgM1oYiQRFbNkzwxoITzpioWmk5wVTBM1yq+2Zv9NYL4zgT+9wwo+OfIxim03sRPK2mn67ur1+vtJcXRBf6gR8UkGrBYmUocLbIIqwc2RYcLxMi8GOOQtW7lHGXtkSkVF45sjlnmdCBlMGG4/5CzayYC1w2THrht5ilWPCVHGJ6hxqiVhEw+JeNmBjQSSMc9UCkdRDXvjeoZEPT+gty4ATkjkDKDdqkHP/spOBlkvLsDqmRf25Sbo/UN4KXF5eNHuhkI3DPTc4cFw1078RGKJ0wyvj6Xjifz0EYnhufeyJ63m54DTT1QaYwRqhIaqaIkjiT7VDCwZLcWEEh8jC91h0piSLlUfnIlee0jFXdMKiOalD9V24VG3vgu6qtuPkDF6iwUJLf6XVkTISJnvkoYQnaYYFOPyxuPyrOyTTdP2IuV9MHb6an0rT/X9MqLB1N21u2mg/VdL8YuFhNH15KnUrTTr9A6NHDWXRdCW4aUlQUJNyzcsJR602oj6Xx2N6WpzY2jikS5KX9/rQNhZ7hgRG5kpo6GLWpw27NULAFD7G+q/m+03Hk+jscCcRjLHqO1pGpH/sdweqfql9Zrgzrms4mhXotJkVO0UqqvRtHKVLRjlwhOPuFjdgzluGO/rVp/x1rW261s69ZPR5pTxp20gr6W44Ke2v1eKq02uOsaKSVxtyKDOLCdDPpxthmhJox0oEGCU1v4/pNrpXa/7B4vSVUYt5DjheS5l0VuIemuQ87cvI+OM2Dnni+qG86Js+HVKXxM5etWLVClGXr7mesIs7yfyr3h3scqc6H5v7o7LmPSyJ+mJGy/bQuEz19NS11ONYXq1214c79wlRguzeM4LI2DK+b56MBsBs/3oH7hzMcOCPb9Yf6b3uWwD/SbiIvN996q+GbL+bw5jc= \ No newline at end of file diff --git a/media/icons/macos/flet-png/app_icon_1024.png b/media/icons/macos/flet-png/app_icon_1024.png deleted file mode 100644 index cd0e222677..0000000000 Binary files a/media/icons/macos/flet-png/app_icon_1024.png and /dev/null differ diff --git a/media/icons/macos/flet-png/app_icon_128.png b/media/icons/macos/flet-png/app_icon_128.png deleted file mode 100644 index a7f8559d3c..0000000000 Binary files a/media/icons/macos/flet-png/app_icon_128.png and /dev/null differ diff --git a/media/icons/macos/flet-png/app_icon_16.png b/media/icons/macos/flet-png/app_icon_16.png deleted file mode 100644 index e6d5260711..0000000000 Binary files a/media/icons/macos/flet-png/app_icon_16.png and /dev/null differ diff --git a/media/icons/macos/flet-png/app_icon_256.png b/media/icons/macos/flet-png/app_icon_256.png deleted file mode 100644 index 117ff24147..0000000000 Binary files a/media/icons/macos/flet-png/app_icon_256.png and /dev/null differ diff --git a/media/icons/macos/flet-png/app_icon_32.png b/media/icons/macos/flet-png/app_icon_32.png deleted file mode 100644 index 541cd5d605..0000000000 Binary files a/media/icons/macos/flet-png/app_icon_32.png and /dev/null differ diff --git a/media/icons/macos/flet-png/app_icon_64.png b/media/icons/macos/flet-png/app_icon_64.png deleted file mode 100644 index 2a05709be4..0000000000 Binary files a/media/icons/macos/flet-png/app_icon_64.png and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-1024.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-1024.psd deleted file mode 100644 index d8e6d75dd8..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-1024.psd and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-128.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-128.psd deleted file mode 100644 index fb70ceabe4..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-128.psd and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-16.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-16.psd deleted file mode 100644 index c00c027eb0..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-16.psd and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-256.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-256.psd deleted file mode 100644 index f1c2e357f5..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-256.psd and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-32.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-32.psd deleted file mode 100644 index 81cd5f15b8..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-32.psd and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-512.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-512.psd deleted file mode 100644 index b19f52f4ce..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-512.psd and /dev/null differ diff --git a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-64.psd b/media/icons/macos/flet-psd/flet-macos-icon-white-bg-64.psd deleted file mode 100644 index a437d3dcd2..0000000000 Binary files a/media/icons/macos/flet-psd/flet-macos-icon-white-bg-64.psd and /dev/null differ diff --git a/media/icons/macos/templates/apple-original.7z b/media/icons/macos/templates/apple-original.7z deleted file mode 100644 index 7466021b07..0000000000 Binary files a/media/icons/macos/templates/apple-original.7z and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-1024.psd b/media/icons/macos/templates/macos-icon-white-bg-1024.psd deleted file mode 100644 index 6f6847fe59..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-1024.psd and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-128.psd b/media/icons/macos/templates/macos-icon-white-bg-128.psd deleted file mode 100644 index a4ea49a191..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-128.psd and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-16.psd b/media/icons/macos/templates/macos-icon-white-bg-16.psd deleted file mode 100644 index 53e6560a31..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-16.psd and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-256.psd b/media/icons/macos/templates/macos-icon-white-bg-256.psd deleted file mode 100644 index b7bceb6457..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-256.psd and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-32.psd b/media/icons/macos/templates/macos-icon-white-bg-32.psd deleted file mode 100644 index 548a985193..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-32.psd and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-512.psd b/media/icons/macos/templates/macos-icon-white-bg-512.psd deleted file mode 100644 index 432e726d46..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-512.psd and /dev/null differ diff --git a/media/icons/macos/templates/macos-icon-white-bg-64.psd b/media/icons/macos/templates/macos-icon-white-bg-64.psd deleted file mode 100644 index 6070bc0115..0000000000 Binary files a/media/icons/macos/templates/macos-icon-white-bg-64.psd and /dev/null differ diff --git a/media/logo/Icon-192.png b/media/logo/Icon-192.png deleted file mode 100644 index 07f9ac6039..0000000000 Binary files a/media/logo/Icon-192.png and /dev/null differ diff --git a/media/logo/Icon-512.png b/media/logo/Icon-512.png deleted file mode 100644 index aa29fc5437..0000000000 Binary files a/media/logo/Icon-512.png and /dev/null differ diff --git a/media/logo/app_icon_1024.png b/media/logo/app_icon_1024.png deleted file mode 100644 index c84ad9ad54..0000000000 Binary files a/media/logo/app_icon_1024.png and /dev/null differ diff --git a/media/logo/app_icon_128.png b/media/logo/app_icon_128.png deleted file mode 100644 index 330de989e4..0000000000 Binary files a/media/logo/app_icon_128.png and /dev/null differ diff --git a/media/logo/app_icon_16.png b/media/logo/app_icon_16.png deleted file mode 100644 index fd20b95c67..0000000000 Binary files a/media/logo/app_icon_16.png and /dev/null differ diff --git a/media/logo/app_icon_256.png b/media/logo/app_icon_256.png deleted file mode 100644 index 2d62b439f2..0000000000 Binary files a/media/logo/app_icon_256.png and /dev/null differ diff --git a/media/logo/app_icon_32.png b/media/logo/app_icon_32.png deleted file mode 100644 index c360b8ca99..0000000000 Binary files a/media/logo/app_icon_32.png and /dev/null differ diff --git a/media/logo/app_icon_512.png b/media/logo/app_icon_512.png deleted file mode 100644 index b1bc19abfd..0000000000 Binary files a/media/logo/app_icon_512.png and /dev/null differ diff --git a/media/logo/app_icon_64.png b/media/logo/app_icon_64.png deleted file mode 100644 index 7b4af64d82..0000000000 Binary files a/media/logo/app_icon_64.png and /dev/null differ diff --git a/media/logo/favicon.png b/media/logo/favicon.png deleted file mode 100644 index c360b8ca99..0000000000 Binary files a/media/logo/favicon.png and /dev/null differ diff --git a/media/logo/flet-logo-256x256.png b/media/logo/flet-logo-256x256.png deleted file mode 100644 index 99efba06a0..0000000000 Binary files a/media/logo/flet-logo-256x256.png and /dev/null differ diff --git a/media/logo/flet-logo-512x512.png b/media/logo/flet-logo-512x512.png deleted file mode 100644 index 97272a4e6b..0000000000 Binary files a/media/logo/flet-logo-512x512.png and /dev/null differ diff --git a/media/logo/flet-logo-no-text.svg b/media/logo/flet-logo-no-text.svg deleted file mode 100644 index e9c0bb9051..0000000000 --- a/media/logo/flet-logo-no-text.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/media/logo/flet-logo-v2-512-white.png b/media/logo/flet-logo-v2-512-white.png deleted file mode 100644 index 1318392b6a..0000000000 Binary files a/media/logo/flet-logo-v2-512-white.png and /dev/null differ diff --git a/media/logo/flet-logo-v2-512.png b/media/logo/flet-logo-v2-512.png deleted file mode 100644 index 3ac35c0208..0000000000 Binary files a/media/logo/flet-logo-v2-512.png and /dev/null differ diff --git a/media/logo/flet-logo-white-text.svg b/media/logo/flet-logo-white-text.svg deleted file mode 100644 index be12f4a02d..0000000000 --- a/media/logo/flet-logo-white-text.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/media/logo/flet-logo.cdr b/media/logo/flet-logo.cdr deleted file mode 100644 index cc3112ce63..0000000000 Binary files a/media/logo/flet-logo.cdr and /dev/null differ diff --git a/media/logo/flet-logo.png b/media/logo/flet-logo.png deleted file mode 100644 index c2846a07c5..0000000000 Binary files a/media/logo/flet-logo.png and /dev/null differ diff --git a/media/logo/logo-inkscape.svg b/media/logo/logo-inkscape.svg deleted file mode 100644 index 156b8ec1fb..0000000000 --- a/media/logo/logo-inkscape.svg +++ /dev/null @@ -1,549 +0,0 @@ - - - -white rounded squaremaskableFletFletfletFletFletfletApple touchTransparentFavicon transparentMaskableRound for WindowsDevelop Android apps in Python only diff --git a/media/pictures/plus-icon.svg b/media/pictures/plus-icon.svg deleted file mode 100644 index 55922d5749..0000000000 --- a/media/pictures/plus-icon.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - + - - diff --git a/media/website/homepage-icons.cdr b/media/website/homepage-icons.cdr deleted file mode 100644 index 50023ea592..0000000000 Binary files a/media/website/homepage-icons.cdr and /dev/null differ diff --git a/packages/flet/CHANGELOG.md b/packages/flet/CHANGELOG.md index f32cda3b8c..fcdf48a532 100644 --- a/packages/flet/CHANGELOG.md +++ b/packages/flet/CHANGELOG.md @@ -1,33 +1,216 @@ -# 0.28.3 +## 0.85.1 +_No changes in the `flet` Dart package; version bumped for release coordination with `flet-geolocator` fixes on the Python side._ + +## 0.85.0 + +### New features + +* Add `parseControlWidget()` and `parseControlWidgets()` utilities for converting Flet controls in protocol values to Flutter widgets ([#6463](https://github.com/flet-dev/flet/pull/6463)) by @ndonkoHenri. + +### Improvements + +### Bug fixes + +* Preserve viewport minimum constraints for short scrollable `View`, `Column`, and `Row` content so main-axis alignment still applies ([#6446](https://github.com/flet-dev/flet/issues/6446), [#6450](https://github.com/flet-dev/flet/pull/6450)) by @ndonkoHenri. +* Handle unbounded width in `ResponsiveRow` with an explicit error and treat child controls with `col=0` as hidden at the current breakpoint ([#1951](https://github.com/flet-dev/flet/issues/1951), [#3805](https://github.com/flet-dev/flet/issues/3805), [#6354](https://github.com/flet-dev/flet/pull/6354)) by @ndonkoHenri. +* Fix `page.window.destroy()` taking several seconds to close Windows desktop apps when `prevent_close` is enabled ([#5459](https://github.com/flet-dev/flet/issues/5459), [#6428](https://github.com/flet-dev/flet/pull/6428)) by @ndonkoHenri. +* Fix `flet pack` desktop packaging so Windows and Linux bundles include the expected client archive, and Windows taskbar pins point to the packed app instead of the cached `flet.exe` ([#5151](https://github.com/flet-dev/flet/issues/5151), [#6403](https://github.com/flet-dev/flet/pull/6403)) by @ndonkoHenri. +* Resolve absolute-path `src` (e.g. `Image(src="/images/foo.svg")`) against `assets_dir` on web so embedded apps mounted at non-root URLs load assets correctly, pass `data:`/`blob:` URIs through unchanged, preserve origin-relative semantics when `assets_dir` is unset, and add a `window.flet.assetsDir` JS-interop bridge so embedding hosts can supply `assets_dir` to the top-level `FletApp` ([#6470](https://github.com/flet-dev/flet/pull/6470)) by @FeodorFitsner. +* Coerce `double` to `int` in `parseInt` so float values passed into `int`-typed protocol fields (e.g. `Duration(seconds: 2.0)`) decode correctly instead of falling back to the default ([#6478](https://github.com/flet-dev/flet/issues/6478), [#6480](https://github.com/flet-dev/flet/pull/6480)) by @FeodorFitsner. + +### Other changes + +## 0.84.0 + +### Improvements + +* Migrate Flet docs from MkDocs to Docusaurus for a more maintainable documentation pipeline ([#6359](https://github.com/flet-dev/flet/pull/6359)) by @FeodorFitsner. +* Migrate examples into standalone projects with metadata, dependencies, and assets to improve discovery and make every sample runnable as-is ([#6281](https://github.com/flet-dev/flet/issues/6281), [#6355](https://github.com/flet-dev/flet/pull/6355)) by @InesaFitsner. + +### Bug fixes + +* Fix `flet pack` on macOS after the move to GitHub Releases by handling extracted app bundles, matching the cached tarball name, and cleaning up loose frameworks during packaging ([#6358](https://github.com/flet-dev/flet/issues/6358), [#6361](https://github.com/flet-dev/flet/pull/6361)) by @FeodorFitsner. + +## 0.83.1 + +### Bug fixes + +* Fix solitaire tutorial and drag examples to use `local_delta.x` and `local_delta.y` instead of removed `delta_x` and `delta_y` ([#6317](https://github.com/flet-dev/flet/issues/6317), [#6344](https://github.com/flet-dev/flet/pull/6344)) by @Krishnachaitanyakc. +* Fix inherited dataclass field validation rules applying to overridden subclass fields and breaking `flet-datatable2` on `0.83.0` ([#6349](https://github.com/flet-dev/flet/issues/6349), [#6350](https://github.com/flet-dev/flet/pull/6350)) by @ndonkoHenri. + +## 0.83.0 + +### New features + +* Add customizable scrollbars for scrollable controls and pages ([#5912](https://github.com/flet-dev/flet/issues/5912), [#6282](https://github.com/flet-dev/flet/pull/6282)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Add scrolling support and richer change events to `ExpansionPanelList` ([#6294](https://github.com/flet-dev/flet/pull/6294)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Expand `SharedPreferences` to support `int`, `float`, `bool`, and `list[str]` values ([#6304](https://github.com/flet-dev/flet/issues/6304), [#6267](https://github.com/flet-dev/flet/pull/6267)) by [@ndonkoHenri](https://github.com/ndonkoHenri). + +### Improvements + +* Speed up control diffing and nested value tracking with sparse `Prop` updates and `@value` types ([#6098](https://github.com/flet-dev/flet/issues/6098), [#6270](https://github.com/flet-dev/flet/issues/6270), [#6117](https://github.com/flet-dev/flet/issues/6117), [#6296](https://github.com/flet-dev/flet/pull/6296)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Consolidate app/build templates into the monorepo and publish pre-release `flet` packages and template artifacts from CI ([#6306](https://github.com/flet-dev/flet/issues/6306), [#6331](https://github.com/flet-dev/flet/pull/6331)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Move desktop client binaries from PyPI wheels to GitHub Releases and unify desktop packaging around `flet-desktop` ([#6290](https://github.com/flet-dev/flet/issues/6290), [#6309](https://github.com/flet-dev/flet/pull/6309)) by [@FeodorFitsner](https://github.com/FeodorFitsner). + +### Bug fixes + +* Align Dart-side default values with Python across core and extension packages ([#6329](https://github.com/flet-dev/flet/issues/6329), [#6330](https://github.com/flet-dev/flet/pull/6330)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Skip redundant page auto-updates after handlers call `.update()` explicitly ([#6236](https://github.com/flet-dev/flet/issues/6236), [#6298](https://github.com/flet-dev/flet/pull/6298)) by [@FeodorFitsner](https://github.com/FeodorFitsner). +* Fix `ReorderableListView` reorder event deserialization for start/end callbacks ([#6177](https://github.com/flet-dev/flet/issues/6177), [#6315](https://github.com/flet-dev/flet/pull/6315)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Skip loading `micropip` for Pyodide apps that already define dependencies in `pyproject.toml` ([#6259](https://github.com/flet-dev/flet/issues/6259), [#6300](https://github.com/flet-dev/flet/pull/6300)) by [@FeodorFitsner](https://github.com/FeodorFitsner). + +## 0.82.2 + +### Bug fixes + +* Lazy-load optional auth dependencies to avoid import-time failures in web/Pyodide startup ([#6258](https://github.com/flet-dev/flet/issues/6258), [#6280](https://github.com/flet-dev/flet/pull/6280)) by [@ndonkoHenri](https://github.com/ndonkoHenri). +* Pin `binaryornot` below `0.5` to fix build-template UTF-8 decode errors ([#6276](https://github.com/flet-dev/flet/issues/6276), [#6279](https://github.com/flet-dev/flet/pull/6279)) by [@ndonkoHenri](https://github.com/ndonkoHenri). + +## 0.82.0 + +### Improvements + +* Refactor ads controls: `InterstitialAd` is now a `Service`, and `BannerAd` is now a `LayoutControl` ([#6194](https://github.com/flet-dev/flet/issues/6194), [#6235](https://github.com/flet-dev/flet/pull/6235)). +* Improve `CodeEditor` with Chinese pinyin input support and aligned gutter rendering ([#6211](https://github.com/flet-dev/flet/issues/6211), [#6243](https://github.com/flet-dev/flet/issues/6243), [#6244](https://github.com/flet-dev/flet/pull/6244)). + +### Bug fixes + +* Fix disabled-state handling across `Tabs`, `TabBar`, `Tab`, and `TabBarView` ([#6220](https://github.com/flet-dev/flet/issues/6220), [#6224](https://github.com/flet-dev/flet/pull/6224)). + +## 0.81.0 + +### New features + +* Add `Camera` control ([#6190](https://github.com/flet-dev/flet/issues/6190)). +* Add `CodeEditor` control ([#6162](https://github.com/flet-dev/flet/issues/6162)). +* Add `PageView` control ([#6158](https://github.com/flet-dev/flet/issues/6158)). +* Add color picker controls based on `flutter_colorpicker` ([#6109](https://github.com/flet-dev/flet/issues/6109)). +* Add Matrix4-based `LayoutControl.transform` and `RotatedBox` control ([#6198](https://github.com/flet-dev/flet/issues/6198)). +* Add `LayoutControl.on_size_change` event for size-aware layouts ([#6099](https://github.com/flet-dev/flet/issues/6099)). +* Add `Hero` animations ([#6157](https://github.com/flet-dev/flet/issues/6157)). +* Add clipboard image/file set and get APIs ([#6141](https://github.com/flet-dev/flet/issues/6141)). +* Add web `FilePicker` `with_data` support for file content ([#6199](https://github.com/flet-dev/flet/issues/6199)). +* Add platform locale info and locale change events ([#6191](https://github.com/flet-dev/flet/issues/6191)). +* Add `ignore_up_down_keys` to `TextField` and `CupertinoTextField` ([#6183](https://github.com/flet-dev/flet/issues/6183)). + +### Improvements + +* Optimize `object_patch` memory churn ([#6204](https://github.com/flet-dev/flet/issues/6204)). +* Skip component migrate/diff when function signatures differ ([#6181](https://github.com/flet-dev/flet/issues/6181)). + +### Bug fixes + +* Fix memory leaks in Flet web app ([#6186](https://github.com/flet-dev/flet/issues/6186)). +* Fix desktop window frameless/titlebar update sync and progress bar clearing ([#6114](https://github.com/flet-dev/flet/issues/6114)). +* Fix first-time button `style` patching and clear stale style state ([#6119](https://github.com/flet-dev/flet/issues/6119)). +* Fix map layer rebuilds on marker updates ([#6113](https://github.com/flet-dev/flet/issues/6113)). +* Fix `AlertDialog` and `CupertinoAlertDialog` barrier color updates ([#6097](https://github.com/flet-dev/flet/issues/6097)). +* Fix `ControlEvent` runtime type hints ([#6102](https://github.com/flet-dev/flet/issues/6102)). + +### Other changes + +* Bump Flutter to 3.41.2. +* Register MIME types for `.mjs` and `.wasm` ([#6140](https://github.com/flet-dev/flet/issues/6140)). + +## 0.80.5 + +* Fix memory leak in Flet web apps ([#6089](https://github.com/flet-dev/flet/issues/6089)). +* feat: add LaTeX support in `ft.Markdown` ([#6069](https://github.com/flet-dev/flet/issues/6069)). +* Avoid `FletApp` control messing with root app routing ([#6086](https://github.com/flet-dev/flet/issues/6086)). +* Include material and cupertino icon data in PyInstaller hook ([#6072](https://github.com/flet-dev/flet/issues/6072)). + +## 0.80.4 + +* fix: Enable TextButton style and full-width Dropdown ([#6048](https://github.com/flet-dev/flet/issues/6048)). +* flet-video: add mpv_properties to VideoConfiguration ([#6041](https://github.com/flet-dev/flet/issues/6041)). +* Refactor `Icons` and `CupertinoIcons` proxies for member caching and iteration ([#6055](https://github.com/flet-dev/flet/issues/6055)). +* Flutter 3.38.7. + +## 0.80.3 + +* feat: add `locale` prop to `CupertinoDatePicker`, `DatePicker`, `DateRangePicker`, `TimePicker` ([#6030](https://github.com/flet-dev/flet/issues/6030)). +* Rive 0.14.0 ([#6025](https://github.com/flet-dev/flet/issues/6025)). +* feat(flet-charts): Allow `badge_position` and `title_position` of `PieChartSection` accept values >= `1.0` ([#6024](https://github.com/flet-dev/flet/issues/6024)). +* Add position details to `GestureDetector.on_tap` event ([#6016](https://github.com/flet-dev/flet/issues/6016)). +* Fix Android platform check to exclude web ([#6013](https://github.com/flet-dev/flet/issues/6013)). +* feat: `parseEnum` utility function. + +## 0.80.3 + +* Add position details to `GestureDetector.on_tap` event ([#6016](https://github.com/flet-dev/flet/issues/6016)). + +## 0.80.2 + +* OAuth fixes and updated examples ([#5996](https://github.com/flet-dev/flet/issues/5996)). +* Examples cleanup ([#5997](https://github.com/flet-dev/flet/issues/5997)). +* Fix wrong `LinearGradient` alignment defaults + allow multiple use of `--exclude` option in `flet build` ([#5986](https://github.com/flet-dev/flet/issues/5986)). +* Update TypeVar definition for covariant typing in Ref class ([#5994](https://github.com/flet-dev/flet/issues/5994)). +* feat: add `on_long_press` and `on_hover` events to `IconButton` ([#5984](https://github.com/flet-dev/flet/issues/5984)). +* replace all `asyncio.iscoroutinefunction` with `inspect.iscoroutinefunction` ([#5928](https://github.com/flet-dev/flet/issues/5928)). +* Fix: Control with ID xxx is not registered for `flet_permission_handler` when using Python 3.14 ([#5896](https://github.com/flet-dev/flet/issues/5896)). + + +## 0.80.1 + +* Fix `flet publish` to sub-directories, Icons Browser and other Gallery examples updated [#5964](https://github.com/flet-dev/flet/pull/5964). + +## 0.80.0 + +* **Flet 1.0 Beta Release** – [Read the announcement](https://flet.dev/blog/flet-1-0-beta) + +## 0.70.0 + +* **Flet 1.0 Alpha Released** – [Read the announcement](https://flet.dev/blog/introducing-flet-1-0-alpha) +* **New:** Declarative and reactive programming style, alongside imperative +* **New:** Automatic page updates after event handler completion +* **New:** Service controls for non-visual functionality +* **New:** WebAssembly support for running web apps in the browser +* **New:** Offline mode support for web apps +* **New:** Ability to embed Flet web apps into multiple HTML elements on a page +* **New:** Modern, future-proof architecture: + * Controls in Python are now defined as plain dataclasses + * Unified diffing algorithm supports both imperative and declarative styles + * Refactored Flutter layer using inherited widgets and `Provider` +* Added a Shimmer control for building skeleton loaders and animated placeholders. +* Added `FletApp.appErrorMessage` template to customize loading screen errors. +* See the list of [breaking changes](https://github.com/flet-dev/flet/issues/5238) + +## 0.28.3 + +* New: Multiple subscribers can subscribe to a published topic by `send_all_on_topic` ([#5303](https://github.com/flet-dev/flet/issues/5303)) * Fixed: Local Images Not Rendering in Android App using Flet 0.27.6 ([#5198](https://github.com/flet-dev/flet/issues/5198)) * Fixed: FilePicker.save_file() opens blank gray screen in APK build (works fine in VS) ([#5301](https://github.com/flet-dev/flet/issues/5301)) +* Fixed: Routing / Navigation broken since flet 0.28.2 ([#5302](https://github.com/flet-dev/flet/issues/5302)) -# 0.28.2 +## 0.28.2 * Fixed missing imports in `__init__.py` ([#5292](https://github.com/flet-dev/flet/pull/5292)). * Fixed: GestureDetector should have at least one event handler defined ([#5293](https://github.com/flet-dev/flet/pull/5293)). -# 0.28.0 +## 0.28.0 +* feat(cli): `flet -V` as alternative to `flet --version` ([#4791](https://github.com/flet-dev/flet/pull/4791)) * New Features and Flutter 3.29 ([#4891](https://github.com/flet-dev/flet/issues/4891)) * Fixed: `Dropdown.expand` has no effect ([#5042](https://github.com/flet-dev/flet/pull/5042)) +* feat: expose events (`on_double_tap`, `on_pan_start`) in `WindowDragArea` ([#5043](https://github.com/flet-dev/flet/pull/5043)) * feat: custom `ReorderableListView` drag handle listeners ([#5051](https://github.com/flet-dev/flet/pull/5051)) * Fixed: `LineChartDataPoint.tooltip` not properly rendered ([#5105](https://github.com/flet-dev/flet/pull/5105)) +* Fixed: broken code in `Page.__on_authorize_async` ([#5154](https://github.com/flet-dev/flet/pull/5154)) * Remove Flet v0.25 deprecations ([#5155](https://github.com/flet-dev/flet/pull/5155)) * Prevent platform back button from popping a route with pop confirmation event ([#5280](https://github.com/flet-dev/flet/issues/5280)) * Fixed: SearchBar does not handle capitalization correctly ([#5014](https://github.com/flet-dev/flet/issues/5014)) * Fixed: `FilePicker` upload fails if original filename is modified ([#5037](https://github.com/flet-dev/flet/issues/5037)) -# 0.27.6 +## 0.27.6 * Fix `flet build`: allow dependencies with commas ([#5033](https://github.com/flet-dev/flet/issues/5033)) * Show app startup screen by default ([#5036](https://github.com/flet-dev/flet/issues/5036)) * fix: `Textfield` cursor position changes when modifying field content in `on_change` ([#5019](https://github.com/flet-dev/flet/issues/5019)) -* Remove deperecated `Control.update_async()` method ([#5005](https://github.com/flet-dev/flet/issues/5005)) +* Remove deprecated `Control.update_async()` method ([#5005](https://github.com/flet-dev/flet/issues/5005)) * fix: incorrect positioning of non-FAB controls assigned to page.floating_action_button ([#5049](https://github.com/flet-dev/flet/issues/5049)) -# 0.27.5 +## 0.27.5 * Added `FletApp.showAppStartupScreen` and `FletApp.appStartupScreenMessage` properties. * Added `tool.flet.splash.icon_bgcolor` and `tool.flet.splash.icon_dark_bgcolor` settings for Android splash screen icon image. @@ -35,26 +218,26 @@ * feat: `Dropdown.menu_width` property ([#5007](https://github.com/flet-dev/flet/issues/5007)) * PBKDF2 iteration count increased to 600,000 ([#5023](https://github.com/flet-dev/flet/issues/5023)) -# 0.27.4 +## 0.27.4 * Fix: do not remove `flutter-packages` on re-build if `dev_packages` configured. -# 0.27.3 +## 0.27.3 * Fixes to make `flet build` work in CI environment ([#4993](https://github.com/flet-dev/flet/issues/4993)) -# 0.27.2 +## 0.27.2 * Error on second flet build run "Because {app} depends on flet_{package} from path which doesn't exist" ([#4955](https://github.com/flet-dev/flet/issues/4955)) * Editable packages in pyproject.toml to install from a path by flet build command ([#4963](https://github.com/flet-dev/flet/issues/4963)) * Setting Android manifest `` element properties in `pyproject.toml` ([#4977](https://github.com/flet-dev/flet/issues/4977)) * Fixed regression: Added back `Control.build()` method. -# 0.27.1 +## 0.27.1 * Fixed: binary file operations should not specify encoding. -# 0.27.0 +## 0.27.0 * `DropdownMenu` control ([#1088](https://github.com/flet-dev/flet/issues/1088)) * feat: `ReorderableListView` Control ([#4865](https://github.com/flet-dev/flet/pull/4865)) @@ -70,21 +253,21 @@ * disable markup for flet-cli stdout logs ([#4796](https://github.com/flet-dev/flet/pull/4796)) * Fixed: Disable rich's Markup for stdout logs ([#4795](https://github.com/flet-dev/flet/issues/4795)) * Fixed: Setting `SearchBar.bar_border_side` isn't visually honoured ([#4767](https://github.com/flet-dev/flet/issues/4767)) -* Fixed: Dropdown: Long options cause the down-arrow to oveflow ([#4838](https://github.com/flet-dev/flet/issues/4838)) +* Fixed: Dropdown: Long options cause the down-arrow to overflow ([#4838](https://github.com/flet-dev/flet/issues/4838)) * Fixed: CupertinoSlider initialisation does not allow values less then zero/greater then 1 ([#4853](https://github.com/flet-dev/flet/issues/4853)) * Fixed: Same code shows different appearance in Flet APP/Web/PC local. ([#4855](https://github.com/flet-dev/flet/issues/4855)) * Fixed: Transforming scale renders a grey screen ([#4759](https://github.com/flet-dev/flet/issues/4759)) * Fixed: UnicodeDecodeError when using accented characters in manifest.json ([#4713](https://github.com/flet-dev/flet/issues/4713)) * Fixed: Implement `SearchBar.blur()` to programmatically unfocus the bar ([#4827](https://github.com/flet-dev/flet/issues/4827)) -# 0.26.0 +## 0.26.0 * Flutter extensions: `flet_*` packages moved to separate repositories ([#4721](https://github.com/flet-dev/flet/pull/4721)) * Automatic installation of Flutter, JDK and Android SDK ([#4721](https://github.com/flet-dev/flet/pull/4721)) * Migrated to Flutter 3.27.0 ([#4593](https://github.com/flet-dev/flet/pull/4593)) * New control properties, Flutter 3.27 fixes ([#4703](https://github.com/flet-dev/flet/pull/4703)) * Optional on-demand creation of `ListView.controls` ([#3931](https://github.com/flet-dev/flet/issues/3931)) -* Reset `InteractiveViewer` tranformations ([#4391](https://github.com/flet-dev/flet/issues/4391)) +* Reset `InteractiveViewer` transformations ([#4391](https://github.com/flet-dev/flet/issues/4391)) * Passthrough of mouse events from main window to other applications ([#1438](https://github.com/flet-dev/flet/issues/1438)) * Remove v0.26.0-related deprecations ([#4456](https://github.com/flet-dev/flet/issues/4456)) * Implemented `Window.ignore_mouse_events` ([#4465](https://github.com/flet-dev/flet/pull/4465)) @@ -105,9 +288,9 @@ * Fixed: `Textfield` input border color considers user-specified `border_color` property ([#4735](https://github.com/flet-dev/flet/pull/4735)) * Fixed: make `Tooltip.message` a required parameter ([#4736](https://github.com/flet-dev/flet/pull/4736)) -# 0.25.2 +## 0.25.2 -## Bug fixes +### Bug fixes * Fix `flet publish` creates broken website if no `requirements.txt` or `pyproject.toml` found ([#4493](https://github.com/flet-dev/flet/pull/4493)). * Fix PyInstaller hook to avoid download Flet app bundle on first run ([#4549](https://github.com/flet-dev/flet/pull/4549)). @@ -118,30 +301,30 @@ * Fixed `ControlState should` be resolved based on user-defined order ([#4556](https://github.com/flet-dev/flet/pull/4556)). * Fixed broken `Dismissible.dismiss_direction` ([#4557](https://github.com/flet-dev/flet/pull/4557)). -# 0.25.1 +## 0.25.1 -## Changes +### Changes * Added InteractiveViewer programmatic transformations ([#4451](https://github.com/flet-dev/flet/pull/4451)). -## Bug fixes +### Bug fixes * Fixed `flet build` creates bundle but running it gives `ImportError: No module named main` error ([#4444](https://github.com/flet-dev/flet/pull/4444)). * Fixed hook-flet with wrong import module ([#4447](https://github.com/flet-dev/flet/pull/4447)). * Fixed "flutter/runtime/dart_vm_initializer.cc" error on Linux ([#4443](https://github.com/flet-dev/flet/pull/4443)). -# 0.25.0 +## 0.25.0 -## New controls +### New controls * Mobile Ads (`Banner` and `Interstitial`) ([details and example](https://github.com/flet-dev/flet/pull/3288)). * `Button` control ([#4265](https://github.com/flet-dev/flet/pull/4265)) - which is just an alias for `ElevatedButton` control. -## Breaking changes +### Breaking changes * Refactor `Badge` Control to a Dataclass; added new `badge` property to all controls ([#4077](https://github.com/flet-dev/flet/pull/4077)). -## Other changes +### Other changes * Added `{value_length}`, `{max_length}`, and `{symbols_left}` placeholders to `TextField.counter_text` ([#4403](https://github.com/flet-dev/flet/pull/4403)). * Added `--skip-flutter-doctor` to build cli command ([#4388](https://github.com/flet-dev/flet/pull/4388)). @@ -159,7 +342,7 @@ * Made SearchBar's view height adjustable; added new properties ([#4039](https://github.com/flet-dev/flet/pull/4039)). * Bumped Rive version and fixed Linux app build template for `rive_common`. -## Bug fixes +### Bug fixes * Fixed `Icon` rotation ([#4384](https://github.com/flet-dev/flet/pull/4384)). * Fixed regression in `Markdown.code_theme` when using `MarkdownCodeTheme` enum ([#4373](https://github.com/flet-dev/flet/pull/4373)). @@ -182,12 +365,12 @@ * Skip running flutter doctor on windows if `no_rich_output` is `True` ([#4108](https://github.com/flet-dev/flet/pull/4108)). * Fixed `TextField` freezes on Linux Mint #4422](https://github.com/flet-dev/flet/pull/4422)). -# 0.24.1 +## 0.24.1 * FIXED: `Tooltip` displays wrong message when used with `IconButton`, `FloatingActionButton` and `PopupMenuButton` ([#3922](https://github.com/flet-dev/flet/issues/3922)) * FIXED: `Image.src.base64` ([#3919](https://github.com/flet-dev/flet/issues/3919)) -# 0.24.0 +## 0.24.0 * NEW: `Placeholder` Control ([#3646](https://github.com/flet-dev/flet/issues/3646)) * NEW: `InteractiveViewer` Control ([#3645](https://github.com/flet-dev/flet/issues/3645)) @@ -226,7 +409,7 @@ * CHORE: Bump Flutter packages ([#3719](https://github.com/flet-dev/flet/issues/3719)) * CHORE: Cleanup ([#3640](https://github.com/flet-dev/flet/issues/3640)) -# 0.23.2 +## 0.23.2 * CHANGED: Enhance Typing of Event Handlers ([#3523](https://github.com/flet-dev/flet/issues/3523)) * CHANGED: Delete Page.window.on_resize | deprecate Page.on_resize in favor of Page.on_resized ([#3516](https://github.com/flet-dev/flet/issues/3516)) @@ -238,7 +421,7 @@ * FIXED: `Page.open()` breaking after multiple calls. * FIXED: Typo in on_resized setter decorator -# 0.23.1 +## 0.23.1 * FIX: Fix parseFloatingActionButtonLocation() to work on desktop ([#3496](https://github.com/flet-dev/flet/issues/3496)) * FIX: Flet 0.23 crashes on Ubuntu 22.04 ([#3495](https://github.com/flet-dev/flet/issues/3495)) @@ -247,7 +430,7 @@ * FIX: replace `len(list(filter(...)))` by `any(...)`. * FIX: Make window and browser_context_menu private, and expose respective getters. -# 0.23.0 +## 0.23.0 * NEW: `PermissionHandler` control ([#3276](https://github.com/flet-dev/flet/issues/3276)) * NEW: `Map` control ([#3093](https://github.com/flet-dev/flet/issues/3093)) @@ -276,7 +459,7 @@ * FIX: `Container.on_tap_down` not called when `on_click` is not provided ([#3442](https://github.com/flet-dev/flet/issues/3442)) * FIX: SnackBar bug #3311 ([#3313](https://github.com/flet-dev/flet/issues/3313)) -# 0.22.1 +## 0.22.1 * `AutoComplete` control ([#3003](https://github.com/flet-dev/flet/issues/3003)) * Added `--exclude` option to `flet build` command ([#3125](https://github.com/flet-dev/flet/issues/3125)) @@ -294,7 +477,7 @@ * Fixed ([#3035](https://github.com/flet-dev/flet/issues/3035)) switch Flutter RichText to Text.rich ([#3066](https://github.com/flet-dev/flet/issues/3066)) * Fixed: Markdown code block is not selectable ([#1753](https://github.com/flet-dev/flet/issues/1753)) -# 0.22.0 +## 0.22.0 * Controls enhancement (see [#2882](https://github.com/flet-dev/flet/issues/2882) for details). * `Theme` Enhancement ([#2955](https://github.com/flet-dev/flet/issues/2955)). @@ -308,16 +491,23 @@ * Web: patch html title with app_name ([#2909](https://github.com/flet-dev/flet/issues/2909)). * `Container`: fix triggered both `on_click` and `on_long_press` events ([#2914](https://github.com/flet-dev/flet/issues/2914)). -# 0.21.2 +## 0.21.2 +* Add `--android-adaptive-icon-background` to `flet build` command. * Fix for mobile Safari: Store session ID in SessionStorage instead of window.name. -* Bugfixing on Python side. +* Fix `_FletSocketServer__receive_loop_task` error on Linux. +* Replace deprecated (in Python 3.12) `datetime.utcnow()` with `datetime.now(timezone.utc)`. +* Fix a call to `self.__executor.shutdown` for Python 3.8. +* Add client IP and user agent to a session ID. +* Generate crypto-strong strings across the framework. -# 0.21.1 +## 0.21.1 -* Bugfixing. +* Python dependencies bumped and loosen. +* Fixed: "No supported WebSocket library detected." when running web app with Flet 0.21.0 ([#2818](https://github.com/flet-dev/flet/issues/2818)). +* Fix `EventHandler`: do not call it when converter returned `None`. -# 0.21.0 +## 0.21.0 * FastAPI instead of built-in Fletd server. Mixed async/sync apps. ([#2700](https://github.com/flet-dev/flet/issues/2700)). * `CupertinoActivityIndicator` Control ([#2762](https://github.com/flet-dev/flet/issues/2762)). @@ -335,20 +525,20 @@ * Additional properties ([#2736](https://github.com/flet-dev/flet/issues/2736)). * Reorder `__init__` ([#2724](https://github.com/flet-dev/flet/issues/2724)). -# 0.20.2 +## 0.20.2 * Move `system_overlay_style` from `AppBar` to `Theme` ([#2667](https://github.com/flet-dev/flet/issues/2667)). * `flet build` command checks minimal Flutter SDK version. * Buttons turn to `CupertinoDialogAction` controls inside adaptive dialogs. * `FletApp` control takes control create factories from a parent app. -# 0.20.1 +## 0.20.1 * Migrated to Flutter 3.19 * Fixed scrolling behavior changes in scrollable controls. * Remove `Page.design` and replace with `Page.adaptive` ([#2650](https://github.com/flet-dev/flet/issues/2650)). * Rename `Control.on_update` to `Control.before_update` ([#2642](https://github.com/flet-dev/flet/issues/2642)). -# 0.20.0 +## 0.20.0 * `AppBar.system_overlay_style` property ([#2615](https://github.com/flet-dev/flet/issues/2615)). * New `CupertinoButton` props: `filled`, `style.bgcolor`, `style.padding`, `text`, `icon`, `icon_color`. @@ -380,7 +570,7 @@ * `CupertinoTextfield` control ([#2417](https://github.com/flet-dev/flet/issues/2417)). * `FloatingActionButtonLocation` offset ([#2411](https://github.com/flet-dev/flet/issues/2411)). -# 0.19.0 +## 0.19.0 * `flet build` to apply Python SSL fix when packaging for iOS and Android ([#2349](https://github.com/flet-dev/flet/issues/2349)). * Upgrade Android Gradle in flet `build app` template ([#2350](https://github.com/flet-dev/flet/issues/2350)). @@ -401,7 +591,7 @@ * Fixed: PubSub is not shared between pages in the same FastAPI app ([#2368](https://github.com/flet-dev/flet/issues/2368)). * Fixed: check for `DISPLAY` instead of `XDG_CURRENT_DESKTOP` to check if linux machine is GUIless or not ([#2373](https://github.com/flet-dev/flet/issues/2373)). -# 0.18.0 +## 0.18.0 * `flet build` command to package Flet app for any platform ([docs](https://flet.dev/docs/guides/python/packaging-app-for-distribution)). * Added TextStyle for the Text control ([#2270](https://github.com/flet-dev/flet/issues/2270)). @@ -412,16 +602,16 @@ * `MenuBar`, `SubMenuButton` and `MenuItemButton` controls ([#2252](https://github.com/flet-dev/flet/issues/2252)). * convert 'key' to a super parameter ([#2258](https://github.com/flet-dev/flet/issues/2258)). -# 0.17.0 +## 0.17.0 * `SearchBar` control ([#2212](https://github.com/flet-dev/flet/issues/2212)). * `CupertinoNavigationBar` control ([#2241](https://github.com/flet-dev/flet/issues/2241)). -# 0.16.0 +## 0.16.0 * `CupertinoSlider` control and `Slider.adaptive` ([#2224](https://github.com/flet-dev/flet/issues/2224)). * `CupertinoRadio` control and `Radio.adaptive` ([#2225](https://github.com/flet-dev/flet/issues/2225)). -* Fix `NavigationBar.label_bahavior` ([#2229](https://github.com/flet-dev/flet/issues/2229)). +* Fix `NavigationBar.label_behavior` ([#2229](https://github.com/flet-dev/flet/issues/2229)). * `CupertinoSwitch` control ([docs](https://flet.dev/docs/controls/cupertinoswitch)). * Disable fade-in effect on Flet app start. * Tab alignment bug fix ([#2208](https://github.com/flet-dev/flet/issues/2208)). @@ -429,7 +619,7 @@ * Dark window title for Windows ([#2204](https://github.com/flet-dev/flet/issues/2204)). * Fix `ValueError` on web page resize ([#1564](https://github.com/flet-dev/flet/issues/1564)). -# 0.15.0 +## 0.15.0 * `ExpansionPanel` and `ExpansionPanelList` controls ([docs](https://flet.dev/docs/controls/expansionpanel)). * `CupertinoCheckBox` control, adaptive `CheckBox` ([docs](https://flet.dev/docs/controls/cupertinocheckbox)). @@ -441,7 +631,7 @@ * Added `Dropdown.Option.visible` property. * Fix AlertDialog broken content when testing in Flet app ([#2192](https://github.com/flet-dev/flet/issues/2192)). -# 0.14.0 +## 0.14.0 * `SelectionArea` control ([docs](https://flet.dev/docs/controls/selectionarea)). * `SegmentedButton` control ([docs](https://flet.dev/docs/controls/segmentedbutton)). @@ -451,7 +641,7 @@ * `--uac-admin` flag added to `flet pack` command ([#2149](https://github.com/flet-dev/flet/issues/2149)). * Bump Flutter dependencies. -# 0.13.0 +## 0.13.0 * `Dismissible` Control ([#2124](https://github.com/flet-dev/flet/issues/2124)). * `TimePicker` control ([#2129](https://github.com/flet-dev/flet/issues/2129)). @@ -459,15 +649,15 @@ * Added `thumb_icon` to `Switch` ([#2116](https://github.com/flet-dev/flet/issues/2116)). * Feature: `TextField` Input validation ([#2101](https://github.com/flet-dev/flet/issues/2101)). -# 0.12.2 +## 0.12.2 * Flutter 3.16.0 * Added ´__repr__´ to `Control` class ([#2091](https://github.com/flet-dev/flet/issues/2091)). * Added ´skip_route_change_event´ to ´page.go_async´ ([#2092](https://github.com/flet-dev/flet/issues/2092)). -# 0.12.1 +## 0.12.1 -* Ability to expand `ButtomSheet` to the top of the screen with `BottomSheet.is_scroll_controlled` property ([#2087](https://github.com/flet-dev/flet/issues/2087)). +* Ability to expand `BottomSheet` to the top of the screen with `BottomSheet.is_scroll_controlled` property ([#2087](https://github.com/flet-dev/flet/issues/2087)). * `BottomSheet.maintain_bottom_view_insets_padding` to avoid obstructing controls with on-screen keyboard ([#2010](https://github.com/flet-dev/flet/issues/2010)). * Fixed: `NavigationDrawer` disappears when you move the window and is not opening again ([#2062](https://github.com/flet-dev/flet/issues/2062)). * Fixed: alert dialog doesn't close ([#2011](https://github.com/flet-dev/flet/issues/2011)). @@ -477,7 +667,7 @@ * Fixed: routing regression. * Fixed: Multiple dialogs (AlertDialog) will create a ghost dialog ([#1670](https://github.com/flet-dev/flet/issues/1670)). -# 0.12.0 +## 0.12.0 * `NavigationDrawer` control ([docs](https://flet.dev/docs/controls/navigationdrawer)). * `Badge` control ([docs](https://flet.dev/docs/controls/badge)). @@ -495,7 +685,7 @@ * Fixed: `Chip.selected` property type changed to bool ([#2048](https://github.com/flet-dev/flet/issues/2048)). * Fixed: Unreliable detection of SVG images ([#2053](https://github.com/flet-dev/flet/issues/2053)). -# 0.11.0 +## 0.11.0 * `DatePicker` control ([docs](https://flet.dev/docs/controls/datepicker)). * `Chip` control ([docs](https://flet.dev/docs/controls/chip)). @@ -504,7 +694,7 @@ * Added `AlertDialog.inset_padding` property ([#1899](https://github.com/flet-dev/flet/issues/1899). * Embedded mode to work with [`serious_python`](https://pub.dev/packages/serious_python). -# 0.10.3 +## 0.10.3 * Add proxy_path parameter to flet_fastapi.app() ([#1882](https://github.com/flet-dev/flet/issues/1882)). * Fix `flet create` crashes with an empty project name. @@ -547,7 +737,7 @@ ## 0.8.2 -* Fix `flet pack` command on macOS ([#1580](https://github.com/flet-dev/flet/issues/1580)). +* Fix `flet pack` command on macOS ([#1580](https://github.com/flet-dev/flet/issues/1580)) * Fixed: Assets dir and manifest does not work ([#1573](https://github.com/flet-dev/flet/issues/1573)) * Fixed: Flet CLI crashes if `git` is not installed ([#1581](https://github.com/flet-dev/flet/issues/1581)) @@ -674,7 +864,7 @@ from flet.auth.providers import GitHubOAuthProvider ## 0.4.1 * Slider.round to round slider value on a label -* Fix page.client_storage.get_keys() timeout +* Fix page.client_storage.get_keys() timeout * Fix encode() import in PyInstaller integration * Fix "ConnectionAbortedError" error on Windows * Consistent licensing across the code - Apache 2.0 @@ -691,12 +881,12 @@ from flet.auth.providers import GitHubOAuthProvider * Pyodide publishing fixes and improvements ([#953](https://github.com/flet-dev/flet/issues/953)) * feat: Add PaddingValue to __init__.py ([#936](https://github.com/flet-dev/flet/issues/936)) * Standalone Flet web apps with Pyodide ([#913](https://github.com/flet-dev/flet/issues/913)) -* modified `tooltip` attribute from `prefere*` to `prefer*` ([#909](https://github.com/flet-dev/flet/issues/909)) +* modified `tooltip` attribute from `prefer*` to `preferred*` ([#909](https://github.com/flet-dev/flet/issues/909)) * Fix unicode encoding in `FletTcpSocketServerProtocol` * Fix relative assets path in desktop app * PDM changed to Poetry * Add `--hidden-import` option to `flet pack` command -* Add transparancy to matplotlib ([#889](https://github.com/flet-dev/flet/issues/889)) +* Add transparency to matplotlib ([#889](https://github.com/flet-dev/flet/issues/889)) * Replace Fletd server for desktop apps with a light-weight Python shim ([#838](https://github.com/flet-dev/flet/issues/838)) * add default values in Border dataclass ([#883](https://github.com/flet-dev/flet/issues/883)) * Fix for issue in control.py when checking add command ([#835](https://github.com/flet-dev/flet/issues/835)) @@ -753,6 +943,9 @@ from flet.auth.providers import GitHubOAuthProvider ## 0.1.65 * Fixed: Floating Action Button now showing on top left ([#567](https://github.com/flet-dev/flet/issues/567)) + +## 0.1.64 + * Using variable fonts ([#21](https://github.com/flet-dev/flet/issues/21)) * Old flet client app versions do not launch on Mac ([#161](https://github.com/flet-dev/flet/issues/161)) * NavigationBar control ([#193](https://github.com/flet-dev/flet/issues/193)) @@ -766,15 +959,321 @@ from flet.auth.providers import GitHubOAuthProvider * Add an ability to change font family of `TextField` ([#511](https://github.com/flet-dev/flet/issues/511)) * Feature: Theming Switch and Checkbox component ([#523](https://github.com/flet-dev/flet/issues/523)) * Change shape of AlertDialog ([#537](https://github.com/flet-dev/flet/issues/537)) -* Fixed: Saving and retreiving a string value from client storage adds quotation marks ([#545](https://github.com/flet-dev/flet/issues/545)) +* Fixed: Saving and retrieving a string value from client storage adds quotation marks ([#545](https://github.com/flet-dev/flet/issues/545)) + +## 0.1.63 + * Matplotlib and Plotly Charts ([#509](https://github.com/flet-dev/flet/issues/509)) * make control a cooperative object ([#490](https://github.com/flet-dev/flet/issues/490)) ## 0.1.62 -* Initial release of Flet Flutter package. * GestureDetector and other fixes ([#459](https://github.com/flet-dev/flet/issues/459)) * removed all problems except dart:html problem because it needs material html kind of thing ([#461](https://github.com/flet-dev/flet/issues/461)) * fix: ensure correct version is fetched in dev mode ([#443](https://github.com/flet-dev/flet/issues/443)) * Fix controls setter for empty list input ([#454](https://github.com/flet-dev/flet/issues/454)) -* make ink=True behavior consistent with ink=False ([#427](https://github.com/flet-dev/flet/issues/427)) \ No newline at end of file +* make ink=True behavior consistent with ink=False ([#427](https://github.com/flet-dev/flet/issues/427)) + +## 0.1.61 + +* Audio control ([#425](https://github.com/flet-dev/flet/issues/425)) + +## 0.1.60 + +* Authentication ([#335](https://github.com/flet-dev/flet/issues/335)) +* Fix Flutter/Dart warnings ([#401](https://github.com/flet-dev/flet/issues/401), [#369](https://github.com/flet-dev/flet/issues/369), [#372](https://github.com/flet-dev/flet/issues/372)) + +## 0.1.59 + +* Fixes for Gallery ([#351](https://github.com/flet-dev/flet/issues/351)) +* add data prop to PopupMenuItem [#327](https://github.com/flet-dev/flet/issues/327) + +## 0.1.58 + +* Client storage ([#288](https://github.com/flet-dev/flet/issues/288)) + +## 0.1.57 + +* Container fixes ([#275](https://github.com/flet-dev/flet/pull/275)) +* add error fix for those working with a source package ([#272](https://github.com/flet-dev/flet/pull/272)) + +## 0.1.56 + +* Windows: Clear FilePicker state before opening the dialog as it's blocking +* Reconnect with sessionID on desktop/mobile + +## 0.1.55 + +* FilePicker and uploads ([#258](https://github.com/flet-dev/flet/pull/258)) + +## 0.1.54 + +Fix ElevatedButton regression ([9540beb](https://github.com/flet-dev/flet/commit/9540beb259b6d84d36a31da6799bad390861999d)) + +## [0.1.53](https://github.com/flet-dev/flet/releases/tag/v0.1.53) + +* Desktop Flet app can be started with a hidden window +* New `page` properties to control window appearance and behavior +* New `Stack` properties +* Hot reload +* Platform details (`page.web`, `page.platform`) +* Customisable route transitions + +## 0.1.52 + +* `RouteChangeEvent`, `ViewPopEvent` + +## 0.1.51 + +* Fix container click event data object ([#198](https://github.com/flet-dev/flet/pull/198)) +* Fix #196 bgcolor has no effect if FAB has a custom content ([#196](https://github.com/flet-dev/flet/pull/196)) + +## 0.1.50 + +* Linux ARM64 support for Flet runner app ([#189](https://github.com/flet-dev/flet/pull/189)) +* Bugfix: Image control attribute src_base64 accepts str now ([#187](https://github.com/flet-dev/flet/pull/187)) +* `ContainerTapEventData` +* Accessibility fixes ([#179](https://github.com/flet-dev/flet/pull/179)) +* Fix button style updates + +## 0.1.49 + +* Fix #173 - ValueError: mutable default ([#173](https://github.com/flet-dev/flet/pull/173)) + +## 0.1.48 + +* Fix container blend mode + +## 0.1.47 + +* Remove `SnackBar.elevation` +* Implicit animations and AnimatedSwitcher control ([#162](https://github.com/flet-dev/flet/pull/162)) +* Markdown and ShaderMask controls ([#160](https://github.com/flet-dev/flet/pull/160)) +* Add slugify to utils ([#154](https://github.com/flet-dev/flet/pull/154)) + +## [0.1.46](https://github.com/flet-dev/flet/releases/tag/v0.1.46) + +* New `Container` properties. +* New `ElevatedButton`, `OutlinedButton`, `TextButton` properties. +* New `IconButton` properties. +* New `ListTile` properties. +* New `Theme` properties. +* `hidden` value for `Column`, `Page`, `View`, `Row` and `View` controls - to enable scrolling but hide a scrollbar. +* New `TextField` and `Dropdown` properties. +* New `TextField` properties +* Fixed https://github.com/flet-dev/flet/issues/138 page.width and page.height are 0 on the first page load +* Fixed https://github.com/flet-dev/flet/issues/77 Allow partial theme updates +* Fixed https://github.com/flet-dev/flet/issues/140 Container on_click callback breaks containers without explicit size +* Fixed https://github.com/flet-dev/flet/issues/30 Assertion "lookup_hash_table" fails on ToDo App example +* Flutter SDK switched to `beta` channel. +* Fixed https://github.com/flet-dev/flet/issues/98 Changing app host/IP binding + +## 0.1.43 + +* Switching between "hash" and "path" routing URL strategy ([#110](https://github.com/flet-dev/flet/pull/110)) + +## 0.1.42 + +* Navigation and Routing ([#95](https://github.com/flet-dev/flet/pull/95)) + +## 0.1.41 + +* Fix draggable.content_when_dragging + +## 0.1.40 + +* Drag and Drop (https://github.com/flet-dev/flet/issues/62) +* Any control can be positioned absolutely inside Stack (https://github.com/flet-dev/flet/issues/60) +* Clickable Container (https://github.com/flet-dev/flet/issues/59) +* Added `page.pwa` property to detect if an app is running as PWA (https://github.com/flet-dev/flet/issues/58) + +## 0.1.39 + +* Fix `UserControl._build()` call (https://github.com/flet-dev/flet/issues/52) + +## 0.1.38 + +* Window Manager fix for Linux (https://github.com/flet-dev/flet/issues/44) + +## 0.1.37 + +* Controlling application window (https://github.com/flet-dev/flet/issues/39) + +## 0.1.36 + +* Page events allow multiple subscribers (https://github.com/flet-dev/flet/issues/38) +* page.rtl to control text directionality (https://github.com/flet-dev/flet/issues/37) + +## 0.1.35 + +* Fix web_renderer arg +* Default webrenderer is canvaskit + +## 0.1.34 + +* support "assets" dir for "onefile" PyInstaller +* Try packaging bin as data +* PyInstaller integration (https://github.com/flet-dev/flet/issues/34) + +## 0.1.33 + +* Update control itself when isolated (https://github.com/flet-dev/flet/issues/31) + +## 0.1.32 + +* Linux runner (https://github.com/flet-dev/flet/issues/29) + +## 0.1.31 + +* User control (https://github.com/flet-dev/flet/issues/26) + +## 0.1.30 + +* Upgraded to Flutter 3.0.2 (https://github.com/flet-dev/flet/issues/23) +* Custom fonts (https://github.com/flet-dev/flet/issues/22) + +## 0.1.29 + +* PubSub (https://github.com/flet-dev/flet/issues/19) + +## 0.1.28 + +* Support for Python 3.7 (https://github.com/flet-dev/flet/issues/16) +* Update logo-inkscape.svg +* Add executables to artifacts again +* Upload Fletd archives only, without binaries +* Fix links in Python SDK README (https://github.com/flet-dev/flet/issues/15) + +## 0.1.27 + +* Fixed #10 (https://github.com/flet-dev/flet/issues/14) +* Row, Column and ListView spacing and scrolling improvements (https://github.com/flet-dev/flet/issues/13) +* Installing specific versions of Fletd and Flet apps for Python source distro (https://github.com/flet-dev/flet/issues/12) +* focus() method for TextField and Dropdown controls (https://github.com/flet-dev/flet/issues/11) + +## 0.1.26 + +* Upload Flet client app to GitHub releases +* .focus() method for TextField and Dropdown +* Update fletd name to get download working (https://github.com/flet-dev/flet/issues/7) + +## 0.1.25 + +* Sprint 1 (https://github.com/flet-dev/flet/pull/6) + +## 0.1.24 + +* Fix expand for TextField and Dropdown + +## 0.1.23 + +* app_store_connect_api_key with base64 key +* index.html with loading animation +* Upgrade Flutter 3.0.1 +* Update AndroidManifest.xml +* Build to client's "build" folder +* Update Fastlane +* Building and publishing iOS Flutter app on AppVeyor + +## 0.1.22 + +* TextField and Dropdown unlim size fix +* Python samples cleanup +* Merge pull request #5 from flet-dev/s1-ios +* Config flutter +* Fix FLET_PACKAGE_VERSION +* Fix iOS building for PR builds +* Restore complete yaml + +## 0.1.20 + +* Row python examples +* More control examples +* Text max_lines + +## 0.1.19 + +* Fix setting clipboard + +## 0.1.18 + +* ListTile +* Card control +* Slight protocol optimization +* Control._set_attr_json +* Tabs selected_index +* Check collection controls for visibility +* NavigationRail selected_index +* NavigationRail control +* AppBar, NavigationRail - Python + +## 0.1.17 + +* PopupMenuButton control +* Dividers example +* Filled buttons, dividers +* Filled elevated button +* Upgraded to Flutter 3.0 +* Progress indicator samples +* Fix page size parsing +* page.content -> page.controls +* Expand can be True +* FAB +* bgColor for ImageButton +* CircleAvatar control added +* PWA icons all good +* Temp remove icons +* Large logo on an icon +* Icons updated +* Exponential reconnection logic, PWA icons +* Re-connecting flow + +## 0.1.16 + +* Use canvaskit even on mobile for now +* Upgrade to Flutter 2.10.5 +* Multiline textboxes done right + +## 0.1.14 + +* Create a separate package for Alpine + +## 0.1.13 + +* Add package for Alpine distro + +## 0.1.12 + +* More general wheel package tags for Linux + +## 0.1.11 + +* Icon browser done +* autofocus, on_focus, on_blur to Python classes +* Default Flet color theme +* autofocus, focus, blur to all form controls +* Remove tooltip from iconbutton +* ignoreChange sometimes +* Update container.dart +* Clipboard +* Make tooltip delay longer +* Tooltip property added to all visible controls +* Icons browser with outlined buttons + +## 0.1.10 + +* GridView child_aspect_ratio +* Dynamic lazy building ListView and GridView controls +* Alignment parsing fixed + +## 0.1.7 + +* App icons changed for web, windows and macos + +## 0.1.5 + +* Open Flet client on Windows and MacOS only + +## 0.1.4 + +* mkdir server/server/content diff --git a/packages/flet/README.md b/packages/flet/README.md index 4f7c7594c0..2560cf3348 100644 --- a/packages/flet/README.md +++ b/packages/flet/README.md @@ -1,147 +1,129 @@ # Flet - +

+ +

-Flet is a framework for adding server-driven UI (SDUI) experiences to existing Flutter apps or building standalone web, mobile and desktop apps with Flutter UI. +

+ Build multi-platform apps in Python. No frontend experience required. +

-Add an interactive `FletApp` widget to your Flutter app whose content is controlled by a remote Python script. -It is an ideal solution for building non-core or frequently changing functionality such as product catalog, feedback form, in-app survey or support chat. Flet enables your team to ship new features faster by reducing the number of App Store validation cycles. Just re-deploy a web app hosting a Python script and your users will get an instant update! +Flet is a framework that allows building mobile, desktop and web applications +in Python only without prior experience in frontend development. -On the server side Flet provides an easy to learn programming model that enables Python developers without prior Flutter (or even front-end) experience to participate in development of your larger Flutter app or build their own apps with Flutter UI from scratch. +###    Single code base for any device -## Getting started with Flet +Your app will equally look great on iOS, Android, Windows, Linux, macOS and web. -### Install `flet` Python module +###    Build an entire app in Python -Flet requires Python 3.7 or above. To start with Flet, you need to install flet module first: +Build a cross-platform app without knowledge of Dart, Swift, Kotlin, HTML or JavaScript - only Python! -``` -pip install flet -``` +###    150+ built-in controls and services -### Create Python program +Beautiful UI widgets with Material and Cupertino design: layout, navigation, dialogs, charts - Flet uses Flutter to render UI. -Create a new Python program using Flet which will be driving the content of `FletApp` widget. +###    50+ Python packages for iOS and Android -Let's do a simple `counter.py` app similar to a Flutter new project template: +Numpy, pandas, pydantic, cryptography, opencv, pillow and other popular libraries. -```python -import flet -from flet import IconButton, Page, Row, TextField, icons +###    Full web support -def main(page: Page): - page.title = "Flet counter example" - page.vertical_alignment = "center" +Flet apps run natively in modern browsers using WebAssembly and Pyodide, with no server required. Prefer server-side? Deploy as a Python web app with real-time UI updates. - txt_number = TextField(value="0", text_align="right", width=100) +###    Built-in packaging - def minus_click(e): - txt_number.value = int(txt_number.value) - 1 - page.update() +Build standalone executables or bundles for iOS, Android, Windows, Linux, macOS and web. Instantly deploy to App Store and Google Play. - def plus_click(e): - txt_number.value = int(txt_number.value) + 1 - page.update() +###    Test on iOS and Android - page.add( - Row( - [ - IconButton(icons.REMOVE, on_click=minus_click), - txt_number, - IconButton(icons.ADD, on_click=plus_click), - ], - alignment="center", - ) - ) +Test your project on your own mobile device with Flet App. See your app updates as you make changes. -flet.app(target=main, port=8550) -``` +###    Extensible -Run the app: +Easily wrap any of thousands of Flutter packages to use with Flet or build new controls in pure Python using built-in UI primitives. -``` -python counter.py -``` +###    Accessible -You should see the app running in a native OS window. +Flet is built with Flutter which has solid accessibility foundations on Android, iOS, web, and desktop. -There is a web server (Fletd) running in the background on a fixed port `8550`. Fletd web server is a "bridge" between Python and Flutter. +## Flet app example -`FletApp` widget in your Flutter application will be communicating with Fletd web server via WebSockets to receive UI updates and send user-generated UI events. +Below is a simple "Counter" app, with a text field and two buttons to increment and decrement the counter value: -For production use Python app along with Fletd could be [deployed to a public web host](https://flet.dev/docs/guides/python/deploying-web-app) and be accessible via HTTPS with domain name. +```python title="counter.py" +import flet as ft -### Add Flet widget to a Flutter app +def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER -Create a new or open existing Flutter project. + input = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) -Install Flutter `flet` package: + def minus_click(e): + input.value = str(int(input.value) - 1) -``` -flutter pub add flet -``` + def plus_click(e): + input.value = str(int(input.value) + 1) -For a new project replace `main.dart` with the following: + page.add( + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + input, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], + ) + ) -```dart -import 'package:flet/flet.dart'; -import 'package:flutter/material.dart'; +ft.run(main) +``` + +To run the app, install `flet`: -void main() async { - await setupDesktop(); - runApp(const MyApp()); -} +```bash +pip install 'flet[all]' +``` -class MyApp extends StatelessWidget { - const MyApp({super.key}); +then launch the app: - @override - Widget build(BuildContext context) { - return const MaterialApp( - title: 'Flet Flutter Demo', - home: FletApp(pageUrl: "http://localhost:8550"), - ); - } -} +```bash +flet run counter.py ``` -In the app above `FletApp` widget is hosted inside `MaterialApp` widget. +This will open the app in a native OS window - what a nice alternative to Electron! 🙂 -If Flet app must be able to handle page route change events (web browser URL changes, mobile app deep linking) it must be the top most widget as it contains its own `MaterialApp` widget handling route changes: +

+ +

-```dart -import 'package:flet/flet.dart'; -import 'package:flutter/material.dart'; +To run the same app as a web app use `--web` option with `flet run` command: -void main() async { - await setupDesktop(); - runApp(const FletApp(pageUrl: "http://localhost:8550")); -} +```bash +flet run --web counter.py ``` -Run the program and see Flet app running inside a Flutter app. +

+ +

-When adding `FletApp` widget to the existing desktop Flutter app make sure `setupDesktop()` is called before `runApp()` to initialize Flet's built-in window manager. +## Learn more -## Flet learning resources +* [Website](https://flet.dev) +* [Documentation](https://flet.dev/docs/) +* [Roadmap](https://flet.dev/roadmap) +* [Apps Gallery](https://flet.dev/gallery) -* [Getting started for Python](https://flet.dev/docs/guides/python/getting-started/) -* [Controls reference](https://flet.dev/docs/controls) -* [Tutorials](https://flet.dev/docs/tutorials) -* [Examples](https://github.com/flet-dev/examples/tree/main/python) - -## Flet community +## Community * [Discussions](https://github.com/flet-dev/flet/discussions) * [Discord](https://discord.gg/dzWXP8SHG8) -* [Twitter](https://twitter.com/fletdev) -* [Email](mailto:hello@flet.dev) - -## FAQ - -Coming soon. +* [X (Twitter)](https://twitter.com/fletdev) +* [Bluesky](https://bsky.app/profile/fletdev.bsky.social) +* [Email us](mailto:hello@flet.dev) -## Adding custom Flutter widgets +## Contributing -Coming soon. \ No newline at end of file +Want to help improve Flet? Check out the [contribution guide](https://flet.dev/docs/contributing). diff --git a/packages/flet/lib/flet.dart b/packages/flet/lib/flet.dart index ec32a4a3f5..6c0933a2e1 100644 --- a/packages/flet/lib/flet.dart +++ b/packages/flet/lib/flet.dart @@ -1,21 +1,24 @@ library flet; -export 'src/control_factory.dart'; -export 'src/controls/create_control.dart'; -export 'src/controls/error.dart'; -export 'src/controls/flet_store_mixin.dart'; +export 'dart:io'; + +export 'package:flutter/cupertino.dart' show CupertinoIcons; +export 'package:flutter/material.dart' show Icons; + +export 'src/controls/base_controls.dart'; +export 'src/controls/control_widget.dart'; +export 'src/extensions/control.dart'; export 'src/flet_app.dart'; export 'src/flet_app_errors_handler.dart'; -export 'src/flet_control_backend.dart'; -export 'src/models/app_state.dart'; -export 'src/models/asset_src.dart'; +export 'src/flet_backend.dart'; +export 'src/flet_extension.dart'; +export 'src/flet_service.dart'; +export 'src/models/asset_source.dart'; export 'src/models/control.dart'; -export 'src/models/control_ancestor_view_model.dart'; -export 'src/models/control_tree_view_model.dart'; -export 'src/models/control_view_model.dart'; -export 'src/models/controls_view_model.dart'; -export 'src/models/page_args_model.dart'; export 'src/models/page_size_view_model.dart'; +export 'src/routing/deep_linking_bootstrap.dart'; +export 'src/testing/test_finder.dart'; +export 'src/testing/tester.dart'; export 'src/utils.dart'; export 'src/utils/alignment.dart'; export 'src/utils/animations.dart'; @@ -24,40 +27,41 @@ export 'src/utils/autofill.dart'; export 'src/utils/badge.dart'; export 'src/utils/borders.dart'; export 'src/utils/box.dart'; -export 'src/utils/browser_context_menu.dart'; export 'src/utils/buttons.dart'; -export 'src/utils/charts.dart'; -export 'src/utils/client_storage.dart'; -export 'src/utils/clipboard.dart'; export 'src/utils/collections.dart'; +export 'src/utils/control.dart'; export 'src/utils/colors.dart'; -export 'src/utils/cupertino_colors.dart'; -export 'src/utils/cupertino_icons.dart'; export 'src/utils/dash_path.dart'; export 'src/utils/debouncer.dart'; export 'src/utils/desktop.dart'; +export 'src/utils/device_info.dart'; export 'src/utils/dismissible.dart'; export 'src/utils/drawing.dart'; export 'src/utils/edge_insets.dart'; +export 'src/utils/enums.dart'; +export 'src/utils/events.dart'; export 'src/utils/form_field.dart'; +export 'src/utils/geometry.dart'; +export 'src/utils/gesture_detector.dart'; export 'src/utils/gradient.dart'; export 'src/utils/icons.dart'; export 'src/utils/images.dart'; export 'src/utils/launch_url.dart'; +export 'src/utils/layout.dart'; export 'src/utils/locale.dart'; +export 'src/utils/lock.dart'; export 'src/utils/markdown.dart'; -export 'src/utils/material_icons.dart'; -export 'src/utils/material_state.dart'; export 'src/utils/menu.dart'; +export 'src/utils/misc.dart'; export 'src/utils/mouse.dart'; export 'src/utils/networking.dart'; export 'src/utils/numbers.dart'; -export 'src/utils/others.dart'; export 'src/utils/overlay_style.dart'; export 'src/utils/platform.dart'; -export 'src/utils/platform_utils_non_web.dart' - if (dart.library.js) "src/utils/platform_utils_web.dart"; +export 'src/utils/platform_utils_web.dart' + if (dart.library.io) "src/utils/platform_utils_non_web.dart"; export 'src/utils/responsive.dart'; +export 'src/utils/scrollbar.dart'; export 'src/utils/strings.dart'; export 'src/utils/text.dart'; export 'src/utils/textfield.dart'; @@ -65,3 +69,7 @@ export 'src/utils/theme.dart'; export 'src/utils/time.dart'; export 'src/utils/tooltip.dart'; export 'src/utils/transforms.dart'; +export 'src/utils/uri.dart'; +export 'src/utils/widget_state.dart'; +export 'src/widgets/error.dart'; +export 'src/widgets/flet_store_mixin.dart'; diff --git a/packages/flet/lib/src/actions.dart b/packages/flet/lib/src/actions.dart deleted file mode 100644 index 52bbc43394..0000000000 --- a/packages/flet/lib/src/actions.dart +++ /dev/null @@ -1,126 +0,0 @@ -import 'dart:ui'; - -import 'flet_control_backend.dart'; -import 'flet_server.dart'; -import 'models/window_media_data.dart'; -import 'protocol/add_page_controls_payload.dart'; -import 'protocol/app_become_active_payload.dart'; -import 'protocol/app_become_inactive_payload.dart'; -import 'protocol/append_control_props_request.dart'; -import 'protocol/clean_control_payload.dart'; -import 'protocol/invoke_method_payload.dart'; -import 'protocol/page_controls_batch_payload.dart'; -import 'protocol/page_media_data.dart'; -import 'protocol/register_webclient_response.dart'; -import 'protocol/remove_control_payload.dart'; -import 'protocol/replace_page_controls_payload.dart'; -import 'protocol/session_crashed_payload.dart'; -import 'protocol/update_control_props_payload.dart'; - -class PageLoadAction { - final Uri pageUri; - final String assetsDir; - final FletControlBackend backend; - PageLoadAction(this.pageUri, this.assetsDir, this.backend); -} - -class PageReconnectingAction { - final String connectMessage; - final int nextReconnectDelayMs; - PageReconnectingAction(this.connectMessage, this.nextReconnectDelayMs); -} - -class PageSizeChangeAction { - final Size newPageSize; - final WindowMediaData? wmd; - final FletControlBackend backend; - PageSizeChangeAction(this.newPageSize, this.wmd, this.backend); -} - -class SetPageRouteAction { - final String route; - final FletServer server; - SetPageRouteAction(this.route, this.server); -} - -class WindowEventAction { - final String eventName; - final WindowMediaData wmd; - final FletControlBackend backend; - WindowEventAction(this.eventName, this.wmd, this.backend); -} - -class PageBrightnessChangeAction { - final Brightness brightness; - final FletControlBackend backend; - PageBrightnessChangeAction(this.brightness, this.backend); -} - -class PageMediaChangeAction { - final PageMediaData media; - final FletControlBackend backend; - PageMediaChangeAction(this.media, this.backend); -} - -class RegisterWebClientAction { - final RegisterWebClientResponse payload; - final FletControlBackend backend; - RegisterWebClientAction(this.payload, this.backend); -} - -class AppBecomeActiveAction { - final FletServer server; - final AppBecomeActivePayload payload; - AppBecomeActiveAction(this.server, this.payload); -} - -class AppBecomeInactiveAction { - final AppBecomeInactivePayload payload; - AppBecomeInactiveAction(this.payload); -} - -class SessionCrashedAction { - final SessionCrashedPayload payload; - SessionCrashedAction(this.payload); -} - -class InvokeMethodAction { - final InvokeMethodPayload payload; - final FletServer server; - InvokeMethodAction(this.payload, this.server); -} - -class AddPageControlsAction { - final AddPageControlsPayload payload; - AddPageControlsAction(this.payload); -} - -class ReplacePageControlsAction { - final ReplacePageControlsPayload payload; - ReplacePageControlsAction(this.payload); -} - -class PageControlsBatchAction { - final PageControlsBatchPayload payload; - PageControlsBatchAction(this.payload); -} - -class UpdateControlPropsAction { - final UpdateControlPropsPayload payload; - UpdateControlPropsAction(this.payload); -} - -class AppendControlPropsAction { - final AppendControlPropsPayload payload; - AppendControlPropsAction(this.payload); -} - -class CleanControlAction { - final CleanControlPayload payload; - CleanControlAction(this.payload); -} - -class RemoveControlAction { - final RemoveControlPayload payload; - RemoveControlAction(this.payload); -} diff --git a/packages/flet/lib/src/control_factory.dart b/packages/flet/lib/src/control_factory.dart deleted file mode 100644 index 03df38f032..0000000000 --- a/packages/flet/lib/src/control_factory.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:flutter/widgets.dart'; - -import 'flet_control_backend.dart'; -import 'models/control.dart'; - -class CreateControlArgs { - final Key? key; - final Control? parent; - final Control control; - final List children; - final Widget? nextChild; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - CreateControlArgs(this.key, this.parent, this.control, this.children, - this.nextChild, this.parentDisabled, this.parentAdaptive, this.backend); -} - -typedef CreateControlFactory = Widget? Function(CreateControlArgs args); diff --git a/packages/flet/lib/src/controls/adaptive_alert_dialog.dart b/packages/flet/lib/src/controls/adaptive_alert_dialog.dart new file mode 100644 index 0000000000..5918ed25e8 --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_alert_dialog.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../controls/alert_dialog.dart'; +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'cupertino_alert_dialog.dart'; + +class AdaptiveAlertDialogControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveAlertDialogControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveAlertDialog build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoAlertDialogControl(control: control); + } else { + return AlertDialogControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_app_bar.dart b/packages/flet/lib/src/controls/adaptive_app_bar.dart new file mode 100644 index 0000000000..de5350d72f --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_app_bar.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'app_bar.dart'; +import 'cupertino_app_bar.dart'; + +class AdaptiveAppBarControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveAppBarControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveAppBarControl build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoAppBarControl(control: control); + } else { + return AppBarControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_button.dart b/packages/flet/lib/src/controls/adaptive_button.dart new file mode 100644 index 0000000000..3f5afc8b02 --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_button.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'button.dart'; +import 'cupertino_button.dart'; +import 'cupertino_dialog_action.dart'; + +class AdaptiveButtonControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveButtonControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveButton build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return (control.parent?.type == "AlertDialog" || + control.parent?.type == "CupertinoAlertDialog") + ? CupertinoDialogActionControl( + control: control, + ) + : CupertinoButtonControl( + control: control, + ); + } else { + return ButtonControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_checkbox.dart b/packages/flet/lib/src/controls/adaptive_checkbox.dart new file mode 100644 index 0000000000..b28972d74c --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_checkbox.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'checkbox.dart'; +import 'cupertino_checkbox.dart'; + +class AdaptiveCheckboxControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveCheckboxControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveCheckboxControl build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoCheckboxControl(control: control); + } else { + return CheckboxControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_radio.dart b/packages/flet/lib/src/controls/adaptive_radio.dart new file mode 100644 index 0000000000..d7c43fb086 --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_radio.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'cupertino_radio.dart'; +import 'radio.dart'; + +class AdaptiveRadioControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveRadioControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveRadioControl build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoRadioControl(control: control); + } else { + return RadioControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_slider.dart b/packages/flet/lib/src/controls/adaptive_slider.dart new file mode 100644 index 0000000000..add4377e19 --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_slider.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'cupertino_slider.dart'; +import 'slider.dart'; + +class AdaptiveSliderControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveSliderControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveSlider build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoSliderControl(control: control); + } else { + return SliderControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_switch.dart b/packages/flet/lib/src/controls/adaptive_switch.dart new file mode 100644 index 0000000000..92d4f29dae --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_switch.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'cupertino_switch.dart'; +import 'switch.dart'; + +class AdaptiveSwitchControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveSwitchControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveSwitch build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoSwitchControl(control: control); + } else { + return SwitchControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/adaptive_texfield.dart b/packages/flet/lib/src/controls/adaptive_texfield.dart new file mode 100644 index 0000000000..99244eb837 --- /dev/null +++ b/packages/flet/lib/src/controls/adaptive_texfield.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'cupertino_textfield.dart'; +import 'textfield.dart'; + +class AdaptiveTextFieldControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const AdaptiveTextFieldControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("AdaptiveTextFieldControl build: ${control.id}"); + + return withPagePlatform((context, platform) { + if (control.adaptive == true && + (platform == TargetPlatform.iOS || + platform == TargetPlatform.macOS)) { + return CupertinoTextFieldControl(control: control); + } else { + return TextFieldControl(control: control); + } + }); + } +} diff --git a/packages/flet/lib/src/controls/alert_dialog.dart b/packages/flet/lib/src/controls/alert_dialog.dart index 1019ab5306..efe6358f52 100644 --- a/packages/flet/lib/src/controls/alert_dialog.dart +++ b/packages/flet/lib/src/controls/alert_dialog.dart @@ -1,182 +1,159 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'cupertino_alert_dialog.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../widgets/control_inherited_notifier.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class AlertDialogControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final Widget? nextChild; - final FletControlBackend backend; - const AlertDialogControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.nextChild, - required this.backend}); + const AlertDialogControl({super.key, required this.control}); @override State createState() => _AlertDialogControlState(); } -class _AlertDialogControlState extends State - with FletStoreMixin { - Widget _createAlertDialog() { - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - var titleCtrls = - widget.children.where((c) => c.name == "title" && c.isVisible); - String titleStr = widget.control.attrString("title", "")!; - var iconCtrls = - widget.children.where((c) => c.name == "icon" && c.isVisible); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - var actionCtrls = - widget.children.where((c) => c.name == "action" && c.isVisible); - final actionsAlignment = - parseMainAxisAlignment(widget.control.attrString("actionsAlignment")); - - if (titleCtrls.isEmpty && - titleStr == "" && - contentCtrls.isEmpty && - actionCtrls.isEmpty) { - return const ErrorControl( - "AlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions"); - } - - var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!; - - return AlertDialog( - title: titleCtrls.isNotEmpty - ? createControl(widget.control, titleCtrls.first.id, disabled, - parentAdaptive: adaptive) - : titleStr != "" - ? Text(titleStr) - : null, - titlePadding: parseEdgeInsets(widget.control, "titlePadding"), - content: contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - contentPadding: parseEdgeInsets(widget.control, "contentPadding", - const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0))!, - actions: actionCtrls - .map((c) => createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive)) - .toList(), - actionsPadding: parseEdgeInsets(widget.control, "actionsPadding"), - actionsAlignment: actionsAlignment, - shape: parseOutlinedBorder(widget.control, "shape"), - semanticLabel: widget.control.attrString("semanticsLabel"), - insetPadding: parseEdgeInsets(widget.control, "insetPadding", - const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0))!, - iconPadding: parseEdgeInsets(widget.control, "iconPadding"), - backgroundColor: widget.control.attrColor("bgcolor", context), - buttonPadding: parseEdgeInsets(widget.control, "actionButtonPadding"), - surfaceTintColor: widget.control.attrColor("surfaceTintColor", context), - shadowColor: widget.control.attrColor("shadowColor", context), - elevation: widget.control.attrDouble("elevation"), - clipBehavior: clipBehavior, - icon: iconCtrls.isNotEmpty - ? createControl(widget.control, iconCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - iconColor: widget.control.attrColor("iconColor", context), - scrollable: widget.control.attrBool("scrollable", false)!, - actionsOverflowButtonSpacing: - widget.control.attrDouble("actionsOverflowButtonSpacing"), - alignment: parseAlignment(widget.control, "alignment"), - contentTextStyle: - parseTextStyle(Theme.of(context), widget.control, "contentTextStyle"), - titleTextStyle: - parseTextStyle(Theme.of(context), widget.control, "titleTextStyle"), +class _AlertDialogControlState extends State { + // Route this widget pushed via `showDialog`. Kept as state so the + // dismiss path can pop *this* dialog specifically (via removeRoute) + // instead of relying on `Navigator.pop()` which targets the topmost + // route — that breaks when a sibling `use_dialog` host has already + // appended a newer dialog above ours. + ModalRoute? _dialogRoute; + + Control get control => widget.control; + + Widget _createAlertDialog(BuildContext context) { + return ControlInheritedNotifier( + notifier: control, + child: Builder(builder: (context) { + ControlInheritedNotifier.of(context); + final routeAnimation = ModalRoute.of(context)?.animation ?? + const AlwaysStoppedAnimation(1.0); + final dialog = AlertDialog( + title: control.buildTextOrWidget("title"), + titlePadding: control.getPadding("title_padding"), + content: control.buildWidget("content"), + contentPadding: control.getPadding("content_padding", + const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0))!, + actions: control.buildWidgets("actions"), + actionsPadding: control.getPadding("actions_padding"), + actionsAlignment: control.getMainAxisAlignment("actions_alignment"), + shape: control.getShape("shape", Theme.of(context)), + semanticLabel: control.getString("semantics_label"), + insetPadding: control.getPadding("inset_padding", + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0))!, + iconPadding: control.getPadding("icon_padding"), + backgroundColor: control.getColor("bgcolor", context), + buttonPadding: control.getPadding("action_button_padding"), + shadowColor: control.getColor("shadow_color", context), + elevation: control.getDouble("elevation"), + clipBehavior: + parseClip(control.getString("clip_behavior"), Clip.none)!, + icon: control.buildIconOrWidget("icon"), + iconColor: control.getColor("icon_color", context), + scrollable: control.getBool("scrollable", false)!, + actionsOverflowButtonSpacing: + control.getDouble("actions_overflow_button_spacing"), + alignment: control.getAlignment("alignment"), + contentTextStyle: + control.getTextStyle("content_text_style", Theme.of(context)), + titleTextStyle: + control.getTextStyle("title_text_style", Theme.of(context)), + ); + return Stack( + fit: StackFit.expand, + children: [ + IgnorePointer( + child: FadeTransition( + opacity: routeAnimation, + child: ColoredBox( + color: control.getColor("barrier_color", context) ?? + DialogTheme.of(context).barrierColor ?? + Theme.of(context).dialogTheme.barrierColor ?? + Colors.black54, + ), + ), + ), + SafeArea(child: BaseControl(control: control, child: dialog)), + ], + ); + }), ); } @override Widget build(BuildContext context) { - debugPrint("AlertDialog build ($hashCode): ${widget.control.id}"); - - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoAlertDialogControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - children: widget.children, - nextChild: widget.nextChild, - parentAdaptive: adaptive, - backend: widget.backend); + debugPrint("AlertDialog build: ${control.id}"); + + var open = control.getBool("open", false)!; + final lastOpen = control.getBool("_open", false)!; + var modal = control.getBool("modal", false)!; + + if (open && (open != lastOpen)) { + if (control.get("title") == null && + control.get("content") == null && + control.children("actions").isEmpty) { + return const ErrorControl( + "AlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions."); } - bool lastOpen = widget.control.state["open"] ?? false; - - debugPrint("AlertDialog build: ${widget.control.id}"); - - var open = widget.control.attrBool("open", false)!; - var modal = widget.control.attrBool("modal", false)!; - - debugPrint("Current open state: $lastOpen"); - debugPrint("New open state: $open"); - - if (open && (open != lastOpen)) { - var dialog = _createAlertDialog(); - if (dialog is ErrorControl) { - return dialog; - } - - // close previous dialog - if (ModalRoute.of(context)?.isCurrent != true) { - Navigator.of(context).pop(); - } - - widget.control.state["open"] = open; - - WidgetsBinding.instance.addPostFrameCallback((_) { - showDialog( - barrierDismissible: !modal, - barrierColor: widget.control.attrColor("barrierColor", context), - useRootNavigator: false, - context: context, - builder: (context) => _createAlertDialog()).then((value) { - lastOpen = widget.control.state["open"] ?? false; - debugPrint("Dialog should be dismissed ($hashCode): $lastOpen"); - bool shouldDismiss = lastOpen; - widget.control.state["open"] = false; - - if (shouldDismiss) { - widget.backend - .updateControlState(widget.control.id, {"open": "false"}); - widget.backend.triggerControlEvent(widget.control.id, "dismiss"); - } + control.updateProperties({"_open": open}, python: false); + + WidgetsBinding.instance.addPostFrameCallback((_) { + showDialog( + barrierDismissible: !modal, + // Render the barrier in the dialog widget so it updates live. + barrierColor: Colors.transparent, + useSafeArea: false, + useRootNavigator: false, + context: context, + builder: (context) { + _dialogRoute ??= ModalRoute.of(context); + return _createAlertDialog(context); + }).then((value) { + final route = _dialogRoute; + _dialogRoute = null; + // showDialog future completes on pop() — before the exit animation + // finishes. Wait for the route's transition to fully complete so + // the dismiss event fires after the closing animation ends. + (route?.completed ?? Future.value()).then((_) { + debugPrint("Dismissing AlertDialog(${control.id})"); + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"open": false}); + control.triggerEvent("dismiss"); }); }); - } else if (open != lastOpen && lastOpen) { + }); + } else if (!open && lastOpen) { + // Synchronous pop during build — Flutter schedules it for the end of + // the frame internally. Using `removeRoute` in a postFrame callback + // (the earlier sibling-host fix) raced with `View`'s on_confirm_pop + // path, which ALSO schedules a post-frame `Navigator.pop(context, + // true)`. Both callbacks fired in the same tick, and the view-pop + // callback ended up popping our just-finished-dismissing dialog + // instead of the target view — breaking the + // `test_pop_view_confirm` integration test. + control.updateProperties({"_open": false}, python: false); + final route = _dialogRoute; + if (route != null && route.isActive) { + debugPrint( + "AlertDialog(${control.id}): Closing dialog managed by this widget."); Navigator.of(context).pop(); + } else { + debugPrint( + "AlertDialog(${control.id}): Dialog was not opened by this widget, skipping pop."); } - - return widget.nextChild ?? const SizedBox.shrink(); - }); + } + return const SizedBox.shrink(); } } diff --git a/packages/flet/lib/src/controls/animated_switcher.dart b/packages/flet/lib/src/controls/animated_switcher.dart index e4344f6ce4..edc72e3e55 100644 --- a/packages/flet/lib/src/controls/animated_switcher.dart +++ b/packages/flet/lib/src/controls/animated_switcher.dart @@ -1,67 +1,49 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/animations.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class AnimatedSwitcherControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const AnimatedSwitcherControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const AnimatedSwitcherControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("AnimatedSwitcher build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - - var switchInCurve = - parseCurve(control.attrString("switchInCurve"), Curves.linear)!; - var switchOutCurve = - parseCurve(control.attrString("switchOutCurve"), Curves.linear)!; - var duration = control.attrInt("duration", 1000)!; - var reverseDuration = control.attrInt("reverseDuration", 1000)!; - bool disabled = control.isDisabled || parentDisabled; - - if (contentCtrls.isEmpty) { + var content = + control.buildWidget("content", notifyParent: true, key: UniqueKey()); + if (content == null) { return const ErrorControl( "AnimatedSwitcher.content must be provided and visible"); } - var child = createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive); - - return constrainedControl( - context, - AnimatedSwitcher( - duration: Duration(milliseconds: duration), - reverseDuration: Duration(milliseconds: reverseDuration), - switchInCurve: switchInCurve, - switchOutCurve: switchOutCurve, - transitionBuilder: (child, animation) { - switch (control.attrString("transition", "")!.toLowerCase()) { - case "rotation": - return RotationTransition(turns: animation, child: child); - case "scale": - return ScaleTransition(scale: animation, child: child); - default: - return FadeTransition(opacity: animation, child: child); - } - }, - child: child), - parent, - control); + return LayoutControl( + control: control, + child: AnimatedSwitcher( + duration: control.getDuration("duration", const Duration(seconds: 1))!, + reverseDuration: control.getDuration( + "reverse_duration", const Duration(seconds: 1))!, + switchInCurve: control.getCurve("switch_in_curve", Curves.linear)!, + switchOutCurve: control.getCurve("switch_out_curve", Curves.linear)!, + transitionBuilder: (Widget child, Animation animation) { + switch (control.getString("transition")?.toLowerCase()) { + case "rotation": + return RotationTransition(turns: animation, child: child); + case "scale": + return ScaleTransition(scale: animation, child: child); + default: + return FadeTransition(opacity: animation, child: child); + } + }, + child: content, + ), + ); } } diff --git a/packages/flet/lib/src/controls/app_bar.dart b/packages/flet/lib/src/controls/app_bar.dart index 0123438192..7fe958b549 100644 --- a/packages/flet/lib/src/controls/app_bar.dart +++ b/packages/flet/lib/src/controls/app_bar.dart @@ -1,103 +1,62 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; import '../utils/theme.dart'; -import 'create_control.dart'; -import 'cupertino_app_bar.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; -class AppBarControl extends StatelessWidget - with FletStoreMixin - implements PreferredSizeWidget { - final Control? parent; +class AppBarControl extends StatelessWidget implements PreferredSizeWidget { final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - final double height; - const AppBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.height}); + const AppBarControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("AppBar build: ${control.id}"); - return withPagePlatform((context, platform) { - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoAppBarControl( - control: control, - parentDisabled: parentDisabled, - parentAdaptive: adaptive, - children: children); - } - - var leadingCtrls = - children.where((c) => c.name == "leading" && c.isVisible); - var titleCtrls = children.where((c) => c.name == "title" && c.isVisible); - var actionCtrls = - children.where((c) => c.name == "action" && c.isVisible); - var isSecondary = control.attrBool("isSecondary", false)!; - - var appBar = AppBar( - leading: leadingCtrls.isNotEmpty - ? createControl(control, leadingCtrls.first.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - leadingWidth: control.attrDouble("leadingWidth"), - automaticallyImplyLeading: - control.attrBool("automaticallyImplyLeading", true)!, - title: titleCtrls.isNotEmpty - ? createControl(control, titleCtrls.first.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - centerTitle: control.attrBool("centerTitle", false)!, - toolbarHeight: preferredSize.height, - foregroundColor: control.attrColor("color", context), - backgroundColor: control.attrColor("bgcolor", context), - elevation: control.attrDouble("elevation"), - actions: actionCtrls - .map((c) => createControl(control, c.id, control.isDisabled, - parentAdaptive: adaptive)) - .toList(), - systemOverlayStyle: Theme.of(context) - .extension() - ?.systemUiOverlayStyle, - shadowColor: control.attrColor("shadowColor", context), - surfaceTintColor: control.attrColor("surfaceTintColor", context), - scrolledUnderElevation: control.attrDouble("elevationOnScroll"), - forceMaterialTransparency: - control.attrBool("forceMaterialTransparency", false)!, - primary: !isSecondary, - titleSpacing: control.attrDouble("titleSpacing"), - excludeHeaderSemantics: - control.attrBool("excludeHeaderSemantics", false)!, - clipBehavior: parseClip(control.attrString("clipBehavior")), - titleTextStyle: - parseTextStyle(Theme.of(context), control, "titleTextStyle"), - shape: parseOutlinedBorder(control, "shape"), - toolbarOpacity: control.attrDouble("toolbarOpacity", 1)!, - toolbarTextStyle: - parseTextStyle(Theme.of(context), control, "toolbarTextStyle"), - actionsPadding: parseEdgeInsets(control, "actionsPadding"), - ); - return baseControl(context, appBar, parent, control); - }); + var appBar = AppBar( + leading: control.buildWidget("leading"), + leadingWidth: control.getDouble("leading_width"), + automaticallyImplyLeading: + control.getBool("automatically_imply_leading", true)!, + title: control.buildTextOrWidget("title"), + centerTitle: control.getBool("center_title"), + toolbarHeight: preferredSize.height, + foregroundColor: control.getColor("color", context), + backgroundColor: control.getColor("bgcolor", context), + elevation: control.getDouble("elevation"), + actions: control.buildWidgets("actions"), + systemOverlayStyle: Theme.of(context) + .extension() + ?.systemUiOverlayStyle, + shadowColor: control.getColor("shadow_color", context), + scrolledUnderElevation: control.getDouble("elevation_on_scroll"), + forceMaterialTransparency: + control.getBool("force_material_transparency", false)!, + primary: !control.getBool("secondary", false)!, + titleSpacing: control.getDouble("title_spacing"), + excludeHeaderSemantics: + control.getBool("exclude_header_semantics", false)!, + clipBehavior: control.getClipBehavior("clip_behavior"), + titleTextStyle: + control.getTextStyle("title_text_style", Theme.of(context)), + shape: control.getShape("shape", Theme.of(context)), + toolbarOpacity: control.getDouble("toolbar_opacity", 1)!, + toolbarTextStyle: + control.getTextStyle("toolbar_text_style", Theme.of(context)), + actionsPadding: control.getPadding("actions_padding"), + ); + + return BaseControl(control: control, child: appBar); } @override - Size get preferredSize => Size.fromHeight(height); + Size get preferredSize => + Size.fromHeight(control.getDouble("toolbar_height", kToolbarHeight)!); } diff --git a/packages/flet/lib/src/controls/auto_complete.dart b/packages/flet/lib/src/controls/auto_complete.dart index 1175fc375f..c5e652dbe6 100644 --- a/packages/flet/lib/src/controls/auto_complete.dart +++ b/packages/flet/lib/src/controls/auto_complete.dart @@ -1,43 +1,84 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/auto_complete.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; -class AutoCompleteControl extends StatelessWidget { - final Control? parent; +class AutoCompleteControl extends StatefulWidget { final Control control; - final FletControlBackend backend; - const AutoCompleteControl( - {super.key, - required this.parent, - required this.control, - required this.backend}); + const AutoCompleteControl({super.key, required this.control}); + + @override + State createState() => _AutoCompleteControlState(); +} + +class _AutoCompleteControlState extends State { + TextEditingController? _controller; + bool _isSyncingController = false; + String _value = ""; + + @override + void dispose() { + _controller?.removeListener(_handleTextChanged); + super.dispose(); + } + + void _attachController(TextEditingController controller) { + if (identical(_controller, controller)) return; + _controller?.removeListener(_handleTextChanged); + _controller = controller; + _controller!.addListener(_handleTextChanged); + _syncController(); + } + + void _syncController() { + final controller = _controller; + if (controller == null || controller.text == _value) return; + + _isSyncingController = true; + controller.value = TextEditingValue( + text: _value, + selection: TextSelection.collapsed(offset: _value.length), + ); + _isSyncingController = false; + } + + void _handleTextChanged() { + final controller = _controller; + if (_isSyncingController || controller == null) return; + + final value = controller.text; + if (value == _value) return; + _value = value; + + widget.control.updateProperties({"value": value}); + widget.control.triggerEvent("change", value); + } @override Widget build(BuildContext context) { - debugPrint("AutoComplete build: ${control.id}"); + debugPrint("AutoComplete build: ${widget.control.id}"); - var suggestionsMaxHeight = control.attrDouble("suggestionsMaxHeight", 200)!; - var suggestions = parseAutoCompleteSuggestions(control, "suggestions"); + var suggestions = parseAutoCompleteSuggestions( + widget.control.get("suggestions"), const [])!; - var auto = Autocomplete( - optionsMaxHeight: suggestionsMaxHeight, + var controlValue = widget.control.getString("value", "")!; + if (_value != controlValue) { + _value = controlValue; + _syncController(); + } + + var autoComplete = Autocomplete( + optionsMaxHeight: + widget.control.getDouble("suggestions_max_height", 200)!, onSelected: (AutoCompleteSuggestion selection) { - backend.updateControlState(control.id, - {"selectedIndex": suggestions.indexOf(selection).toString()}); - backend.triggerControlEvent( - control.id, - "select", - json.encode(AutoCompleteSuggestion( - key: selection.key, value: selection.value) - .toJson())); + final index = suggestions.indexOf(selection); + widget.control.updateProperties({"_selected_index": index}); + widget.control.triggerEvent( + "select", {"index": index, "selection": selection.toMap()}); }, - // optionsViewBuilder: optionsViewBuilder, optionsBuilder: (TextEditingValue textEditingValue) { if (textEditingValue.text == '') { return const Iterable.empty(); @@ -49,8 +90,20 @@ class AutoCompleteControl extends StatelessWidget { .contains(textEditingValue.text.toLowerCase()); }); }, + fieldViewBuilder: (BuildContext context, + TextEditingController textEditingController, + FocusNode focusNode, + VoidCallback onFieldSubmitted) { + _attachController(textEditingController); + return TextField( + controller: textEditingController, + focusNode: focusNode, + onEditingComplete: onFieldSubmitted, + onSubmitted: (_) => onFieldSubmitted(), + ); + }, ); - return baseControl(context, auto, parent, control); + return LayoutControl(control: widget.control, child: autoComplete); } } diff --git a/packages/flet/lib/src/controls/autofill_group.dart b/packages/flet/lib/src/controls/autofill_group.dart index bb925a0e0b..07d6a50484 100644 --- a/packages/flet/lib/src/controls/autofill_group.dart +++ b/packages/flet/lib/src/controls/autofill_group.dart @@ -1,41 +1,28 @@ -import 'package:flet/src/utils/autofill.dart'; import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/autofill.dart'; +import '../widgets/error.dart'; class AutofillGroupControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const AutofillGroupControl( - {super.key, - required this.parent, - required this.control, - required this.children, - required this.parentDisabled, - this.parentAdaptive}); + const AutofillGroupControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("AutofillGroup build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; + var content = control.buildWidget("content"); - if (contentCtrls.isEmpty) { + if (content == null) { return const ErrorControl("AutofillGroup control has no content."); } return AutofillGroup( - onDisposeAction: parseAutofillContextAction( - control.attrString("disposeAction"), AutofillContextAction.commit)!, - child: createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive)); + onDisposeAction: control.getAutofillContextAction( + "dispose_action", AutofillContextAction.commit)!, + child: content); } } diff --git a/packages/flet/lib/src/controls/banner.dart b/packages/flet/lib/src/controls/banner.dart index 1eae443c10..e81f42bc41 100644 --- a/packages/flet/lib/src/controls/banner.dart +++ b/packages/flet/lib/src/controls/banner.dart @@ -1,112 +1,86 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; -class BannerControl extends StatefulWidget { - final Control? parent; +class BannerControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final Widget? nextChild; - final FletControlBackend backend; - const BannerControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.nextChild, - required this.backend}); - - @override - State createState() => _BannerControlState(); -} - -class _BannerControlState extends State { - bool _open = false; - - Widget _createBanner() { - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var leadingCtrls = - widget.children.where((c) => c.name == "leading" && c.isVisible); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - var actionCtrls = - widget.children.where((c) => c.name == "action" && c.isVisible); - - if (contentCtrls.isEmpty) { - return const ErrorControl("Banner.content must be provided and visible"); - } else if (actionCtrls.isEmpty) { - return const ErrorControl( - "Banner.actions must be provided and at least one action should be visible"); - } + const BannerControl({super.key, required this.control}); + MaterialBanner _createBanner(BuildContext context) { return MaterialBanner( - leading: leadingCtrls.isNotEmpty - ? createControl(widget.control, leadingCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - leadingPadding: parseEdgeInsets(widget.control, "leadingPadding"), - content: createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive), - padding: parseEdgeInsets(widget.control, "contentPadding"), - actions: actionCtrls - .map((c) => createControl(widget.control, c.id, disabled, - parentAdaptive: widget.parentAdaptive)) - .toList(), - forceActionsBelow: widget.control.attrBool("forceActionsBelow", false)!, - backgroundColor: widget.control.attrColor("bgcolor", context), + leading: control.buildIconOrWidget("leading"), + leadingPadding: control.getPadding("leading_padding"), + content: control.buildTextOrWidget("content")!, + padding: control.getPadding("content_padding"), + actions: control.buildWidgets("actions"), + forceActionsBelow: control.getBool("force_actions_below", false)!, + backgroundColor: control.getColor("bgcolor", context), contentTextStyle: - parseTextStyle(Theme.of(context), widget.control, "contentTextStyle"), - surfaceTintColor: widget.control.attrColor("surfaceTintColor", context), - shadowColor: widget.control.attrColor("shadowColor", context), - dividerColor: widget.control.attrColor("dividerColor", context), - elevation: widget.control.attrDouble("elevation"), - minActionBarHeight: - widget.control.attrDouble("minActionBarHeight", 52.0)!, - margin: parseEdgeInsets(widget.control, "margin"), + control.getTextStyle("content_text_style", Theme.of(context)), + shadowColor: control.getColor("shadow_color", context), + dividerColor: control.getColor("divider_color", context), + elevation: control.getDouble("elevation"), + minActionBarHeight: control.getDouble("min_action_bar_height", 52.0)!, + margin: control.getMargin("margin"), onVisible: () { - widget.backend.triggerControlEvent(widget.control.id, "visible"); + control.triggerEvent("visible"); }, ); } @override Widget build(BuildContext context) { - debugPrint("Banner build: ${widget.control.id}"); - - debugPrint("Banner build: ${widget.control.id}"); - - var open = widget.control.attrBool("open", false)!; - - if (open && (open != _open)) { - var banner = _createBanner(); - if (banner is ErrorControl) { - return banner; + final dismissed = control.getBool("_dismissed", false)!; + + debugPrint("Banner build: ${control.id}, _dismissed=$dismissed"); + + if (!dismissed) { + final lastOpen = control.getBool("_open", false)!; + var open = control.getBool("open", false)!; + + if (open && (open != lastOpen)) { + if (control.get("content") == null) { + return const ErrorControl( + "Banner.content must be provided and visible"); + } else if (control.children("actions").isEmpty) { + return const ErrorControl( + "Banner.actions must be provided and at least one action should be visible"); + } + + control.updateProperties({"_open": open}, python: false); + + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).removeCurrentMaterialBanner(); + ScaffoldMessenger.of(context) + .showMaterialBanner(_createBanner(context)) + .closed + .then((reason) { + debugPrint("Closing Banner(${control.id}) with reason: $reason"); + if (control.get("_dismissed") != true) { + control.updateProperties({"_dismissed": true}); + debugPrint( + "Dismissing Banner(${control.id}) with reason: $reason"); + //_open = false; + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"open": false}); + control.triggerEvent("dismiss"); + } + }); + }); + } else if (!open && lastOpen) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).hideCurrentMaterialBanner(); + control.updateProperties({"_open": false}, python: false); + }); } - - WidgetsBinding.instance.addPostFrameCallback((_) { - ScaffoldMessenger.of(context).removeCurrentMaterialBanner(); - - ScaffoldMessenger.of(context) - .showMaterialBanner(banner as MaterialBanner); - }); - } else if (open != _open && _open) { - WidgetsBinding.instance.addPostFrameCallback((_) { - ScaffoldMessenger.of(context).removeCurrentMaterialBanner(); - }); } - - _open = open; - - return widget.nextChild ?? const SizedBox.shrink(); + return const SizedBox.shrink(); } } diff --git a/packages/flet/lib/src/controls/barchart.dart b/packages/flet/lib/src/controls/barchart.dart deleted file mode 100644 index 2c2e86ead0..0000000000 --- a/packages/flet/lib/src/controls/barchart.dart +++ /dev/null @@ -1,425 +0,0 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; -import '../models/control.dart'; -import '../utils/animations.dart'; -import '../utils/borders.dart'; -import '../utils/charts.dart'; -import '../utils/edge_insets.dart'; -import '../utils/gradient.dart'; -import '../utils/text.dart'; -import 'charts.dart'; -import 'create_control.dart'; - -TooltipDirection? parseTooltipDirection(String? value, - [TooltipDirection? defValue]) { - if (value == null) { - return defValue; - } - return TooltipDirection.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -class BarChartEventData extends Equatable { - final String eventType; - final int? groupIndex; - final int? rodIndex; - final int? stackItemIndex; - - const BarChartEventData( - {required this.eventType, - required this.groupIndex, - required this.rodIndex, - required this.stackItemIndex}); - - Map toJson() => { - 'type': eventType, - 'group_index': groupIndex, - 'rod_index': rodIndex, - 'stack_item_index': stackItemIndex - }; - - @override - List get props => [eventType, groupIndex, rodIndex, stackItemIndex]; -} - -class BarChartGroupViewModel extends Equatable { - final Control control; - final List barRods; - - const BarChartGroupViewModel({required this.control, required this.barRods}); - - static BarChartGroupViewModel fromStore( - Store store, Control control) { - return BarChartGroupViewModel( - control: control, - barRods: store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.isVisible) - .map((c) => BarChartRodViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => [control, barRods]; -} - -class BarChartRodStackItemViewModel extends Equatable { - final Control control; - - const BarChartRodStackItemViewModel({required this.control}); - - static BarChartRodStackItemViewModel fromStore( - Store store, Control control) { - return BarChartRodStackItemViewModel(control: control); - } - - @override - List get props => [control]; -} - -class BarChartRodViewModel extends Equatable { - final Control control; - final List rodStackItems; - - const BarChartRodViewModel( - {required this.control, required this.rodStackItems}); - - static BarChartRodViewModel fromStore( - Store store, Control control) { - return BarChartRodViewModel( - control: control, - rodStackItems: store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.isVisible) - .map((c) => BarChartRodStackItemViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => [control, rodStackItems]; -} - -class BarChartViewModel extends Equatable { - final Control control; - final ChartAxisViewModel? leftAxis; - final ChartAxisViewModel? topAxis; - final ChartAxisViewModel? rightAxis; - final ChartAxisViewModel? bottomAxis; - final List barGroups; - - const BarChartViewModel( - {required this.control, - required this.leftAxis, - required this.topAxis, - required this.rightAxis, - required this.bottomAxis, - required this.barGroups}); - - static BarChartViewModel fromStore( - Store store, Control control, List children) { - var leftAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "l" && c.isVisible); - var topAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "t" && c.isVisible); - var rightAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "r" && c.isVisible); - var bottomAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "b" && c.isVisible); - return BarChartViewModel( - control: control, - leftAxis: leftAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, leftAxisCtrls.first) - : null, - topAxis: topAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, topAxisCtrls.first) - : null, - rightAxis: rightAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, rightAxisCtrls.first) - : null, - bottomAxis: bottomAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, bottomAxisCtrls.first) - : null, - barGroups: children - .where((c) => c.type == "group" && c.isVisible) - .map((c) => BarChartGroupViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => - [control, leftAxis, rightAxis, topAxis, bottomAxis, barGroups]; -} - -class BarChartControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - - const BarChartControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); - - @override - State createState() => _BarChartControlState(); -} - -class _BarChartControlState extends State { - BarChartEventData? _eventData; - - @override - Widget build(BuildContext context) { - debugPrint("BarChart build: ${widget.control.id}"); - - var animate = parseAnimation(widget.control, "animate"); - var border = parseBorder(Theme.of(context), widget.control, "border"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var result = StoreConnector( - distinct: true, - converter: (store) => - BarChartViewModel.fromStore(store, widget.control, widget.children), - builder: (context, viewModel) { - var leftTitles = - getAxisTitles(widget.control, viewModel.leftAxis, disabled); - var topTitles = - getAxisTitles(widget.control, viewModel.topAxis, disabled); - var rightTitles = - getAxisTitles(widget.control, viewModel.rightAxis, disabled); - var bottomTitles = - getAxisTitles(widget.control, viewModel.bottomAxis, disabled); - - var interactive = viewModel.control.attrBool("interactive", true)!; - - List barGroups = viewModel.barGroups - .map((g) => getGroupData( - Theme.of(context), widget.control, interactive, g)) - .toList(); - - var chart = BarChart( - BarChartData( - backgroundColor: widget.control.attrColor("bgcolor", context), - minY: widget.control.attrDouble("miny"), - maxY: widget.control.attrDouble("maxy"), - baselineY: widget.control.attrDouble("baseliney"), - titlesData: (leftTitles.sideTitles.showTitles || - topTitles.sideTitles.showTitles || - rightTitles.sideTitles.showTitles || - bottomTitles.sideTitles.showTitles) - ? FlTitlesData( - show: true, - leftTitles: leftTitles, - topTitles: topTitles, - rightTitles: rightTitles, - bottomTitles: bottomTitles, - ) - : const FlTitlesData(show: false), - borderData: border != null - ? FlBorderData(show: true, border: border) - : FlBorderData(show: false), - gridData: parseChartGridData(Theme.of(context), widget.control, - "horizontalGridLines", "verticalGridLines"), - groupsSpace: widget.control.attrDouble("groupsSpace"), - barTouchData: BarTouchData( - enabled: interactive, - touchTooltipData: BarTouchTooltipData( - getTooltipColor: (BarChartGroupData group) => widget.control - .attrColor("tooltipBgColor", context, - Theme.of(context).colorScheme.secondary)!, - tooltipRoundedRadius: - widget.control.attrDouble("tooltipRoundedRadius"), - tooltipMargin: widget.control.attrDouble("tooltipMargin"), - tooltipPadding: - parseEdgeInsets(widget.control, "tooltipPadding"), - maxContentWidth: widget.control.attrDouble("tooltipMaxWidth"), - rotateAngle: widget.control.attrDouble("tooltipRotateAngle"), - tooltipHorizontalOffset: - widget.control.attrDouble("tooltipHorizontalOffset"), - tooltipBorder: parseBorderSide( - Theme.of(context), widget.control, "tooltipBorderSide"), - fitInsideHorizontally: - widget.control.attrBool("tooltipFitInsideHorizontally"), - fitInsideVertically: - widget.control.attrBool("tooltipFitInsideVertically"), - direction: parseTooltipDirection( - widget.control.attrString("tooltipDirection")), - getTooltipItem: (group, groupIndex, rod, rodIndex) { - var dp = viewModel.barGroups[groupIndex].barRods[rodIndex]; - - var tooltip = dp.control.attrString("tooltip", - dp.control.attrDouble("toY", 0)!.toString())!; - var tooltipStyle = parseTextStyle( - Theme.of(context), dp.control, "tooltipStyle"); - tooltipStyle ??= const TextStyle(); - if (tooltipStyle.color == null) { - tooltipStyle = tooltipStyle.copyWith( - color: rod.gradient?.colors.first ?? - rod.color ?? - Colors.blueGrey); - } - TextAlign? tooltipAlign = parseTextAlign( - dp.control.attrString("tooltipAlign", ""), - TextAlign.center)!; - return dp.control.attrBool("showTooltip", true)! - ? BarTooltipItem(tooltip, tooltipStyle, - textAlign: tooltipAlign) - : null; - }, - ), - touchCallback: widget.control.attrBool("onChartEvent", false)! - ? (evt, resp) { - var eventData = resp != null && resp.spot != null - ? BarChartEventData( - eventType: evt.runtimeType - .toString() - .substring(2), // remove "Fl" - groupIndex: resp.spot!.touchedBarGroupIndex, - rodIndex: resp.spot!.touchedRodDataIndex, - stackItemIndex: - resp.spot!.touchedStackItemIndex) - : BarChartEventData( - eventType: evt.runtimeType - .toString() - .substring(2), // remove "Fl" - groupIndex: null, - rodIndex: null, - stackItemIndex: null); - if (eventData != _eventData) { - _eventData = eventData; - debugPrint( - "BarChart ${widget.control.id} ${eventData.eventType}"); - widget.backend.triggerControlEvent(widget.control.id, - "chart_event", json.encode(eventData)); - } - } - : null, - ), - barGroups: barGroups, - ), - swapAnimationDuration: animate != null - ? animate.duration - : const Duration(milliseconds: 150), // Optional - swapAnimationCurve: animate != null ? animate.curve : Curves.linear, - ); - - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return (constraints.maxHeight == double.infinity) - ? ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 300), - child: chart, - ) - : chart; - }); - }); - - return constrainedControl(context, result, widget.parent, widget.control); - } - - BarChartGroupData getGroupData(ThemeData theme, Control parent, - bool interactiveChart, BarChartGroupViewModel groupViewModel) { - return BarChartGroupData( - x: groupViewModel.control.attrInt("x", 0)!, - barsSpace: groupViewModel.control.attrDouble("barsSpace"), - groupVertically: groupViewModel.control.attrBool("groupVertically"), - showingTooltipIndicators: groupViewModel.barRods - .asMap() - .entries - .where((e) => - !interactiveChart && e.value.control.attrBool("selected", false)!) - .map((e) => e.key) - .toList(), - barRods: groupViewModel.barRods - .map((r) => - getRodData(theme, groupViewModel.control, interactiveChart, r)) - .toList(), - ); - } - - BarChartRodData getRodData(ThemeData theme, Control parent, - bool interactiveChart, BarChartRodViewModel rodViewModel) { - var bgFromY = rodViewModel.control.attrDouble("bgFromY"); - var bgToY = rodViewModel.control.attrDouble("bgToY"); - var bgColor = rodViewModel.control.attrColor("bgColor", context); - var bgGradient = parseGradient(theme, rodViewModel.control, "bgGradient"); - - return BarChartRodData( - fromY: rodViewModel.control.attrDouble("fromY"), - toY: rodViewModel.control.attrDouble("toY", 0)!, - width: rodViewModel.control.attrDouble("width"), - color: rodViewModel.control.attrColor("color", context), - gradient: parseGradient(theme, rodViewModel.control, "gradient"), - borderRadius: parseBorderRadius(rodViewModel.control, "borderRadius"), - borderSide: - parseBorderSide(theme, rodViewModel.control, "borderSide") ?? - BorderSide.none, - backDrawRodData: bgFromY != null || - bgToY != null || - bgColor != null || - bgGradient != null - ? BackgroundBarChartRodData( - show: true, - fromY: bgFromY, - toY: bgToY, - color: bgColor, - gradient: bgGradient) - : null, - rodStackItems: rodViewModel.rodStackItems - .map((item) => getRodStackItem( - theme, rodViewModel.control, interactiveChart, item)) - .toList()); - } - - BarChartRodStackItem getRodStackItem(ThemeData theme, Control parent, - bool interactiveChart, BarChartRodStackItemViewModel stackItemViewModel) { - return BarChartRodStackItem( - stackItemViewModel.control.attrDouble("fromY")!, - stackItemViewModel.control.attrDouble("toY", 0)!, - stackItemViewModel.control.attrColor("color", context)!, - parseBorderSide(theme, stackItemViewModel.control, "borderSide") ?? - BorderSide.none); - } - - AxisTitles getAxisTitles( - Control parent, ChartAxisViewModel? axisViewModel, bool disabled) { - if (axisViewModel == null) { - return const AxisTitles(sideTitles: SideTitles(showTitles: false)); - } - - return AxisTitles( - axisNameWidget: axisViewModel.title != null - ? createControl(parent, axisViewModel.title!.id, disabled) - : null, - axisNameSize: axisViewModel.control.attrDouble("titleSize") ?? 16, - sideTitles: SideTitles( - showTitles: axisViewModel.control.attrBool("showLabels", true)!, - reservedSize: axisViewModel.control.attrDouble("labelsSize") ?? 22, - interval: axisViewModel.control.attrDouble("labelsInterval"), - getTitlesWidget: axisViewModel.labels.isEmpty - ? defaultGetTitle - : (value, meta) { - return axisViewModel.labels.containsKey(value) - ? createControl( - parent, axisViewModel.labels[value]!.id, disabled) - : const SizedBox.shrink(); - }, - )); - } -} diff --git a/packages/flet/lib/src/controls/base_controls.dart b/packages/flet/lib/src/controls/base_controls.dart new file mode 100644 index 0000000000..d95d5c11d6 --- /dev/null +++ b/packages/flet/lib/src/controls/base_controls.dart @@ -0,0 +1,540 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/alignment.dart'; +import '../utils/animations.dart'; +import '../utils/badge.dart'; +import '../utils/edge_insets.dart'; +import '../utils/layout.dart'; +import '../utils/numbers.dart'; +import '../utils/tooltip.dart'; +import '../utils/transforms.dart'; +import '../widgets/error.dart'; + +class BaseControl extends StatelessWidget { + final Control control; + final Widget child; + + const BaseControl({super.key, required this.control, required this.child}); + + @override + Widget build(BuildContext context) { + Widget w = _opacity(context, child, control); + w = _tooltip(context, w, control); + w = _directionality(w, control); + return _expandable(w, control); + } +} + +class LayoutControl extends StatelessWidget { + final Control control; + final Widget child; + + const LayoutControl({ + super.key, + required this.control, + required this.child, + }); + + @override + Widget build(BuildContext context) { + Widget w = _opacity(context, child, control); + w = _tooltip(context, w, control); + w = _directionality(w, control); + w = _sizedControl(w, control); + w = _rotatedControl(context, w, control); + w = _scaledControl(context, w, control); + w = _offsetControl(context, w, control); + w = _flippedControl(w, control); + w = _transformedControl(w, control); + w = _aspectRatio(w, control); + w = _alignedControl(context, w, control); + w = _marginControl(context, w, control); + w = _positionedControl(context, w, control); + w = _badge(w, Theme.of(context), control); + w = _sizeChangeObserver(w, control); + return _expandable(w, control); + } +} + +Widget _tooltip(BuildContext context, Widget widget, Control control) { + final skipProps = control.internals?["skip_properties"] as List?; + if (skipProps?.contains("tooltip") == true) return widget; + + return parseTooltip(control.get("tooltip"), context, widget) ?? widget; +} + +Widget _badge(Widget widget, ThemeData theme, Control control) { + final skipProps = control.internals?["skip_properties"] as List?; + if (skipProps?.contains("badge") == true) return widget; + + return control.wrapWithBadge("badge", widget, theme); +} + +Widget _sizeChangeObserver(Widget widget, Control control) { + if (!control.getBool("on_size_change", false)!) return widget; + + // Opt-in size reporting to avoid extra layout work by default. + return SizeChangeObserver( + control: control, + interval: control.getInt("size_change_interval", 10)!, + child: widget, + ); +} + +Widget _aspectRatio(Widget widget, Control control) { + var aspectRatio = control.getDouble("aspect_ratio"); + return aspectRatio != null + ? AspectRatio(aspectRatio: aspectRatio, child: widget) + : widget; +} + +Widget _directionality(Widget widget, Control control) { + bool rtl = control.getBool("rtl", false)!; + return rtl + ? Directionality(textDirection: TextDirection.rtl, child: widget) + : widget; +} + +Widget _expandable(Widget widget, Control control) { + int? expand = control.getExpand("expand"); + if (expand != null && control.parent?.internals?["host_expanded"] == true) { + return (control.getBool("expand_loose") == true) + ? Flexible(flex: expand, child: widget) + : Expanded(flex: expand, child: widget); + } + return widget; +} + +Widget _opacity(BuildContext context, Widget widget, Control control) { + var opacity = control.getDouble("opacity"); + var animation = control.getAnimation("animate_opacity"); + if (animation != null) { + return AnimatedOpacity( + duration: animation.duration, + curve: animation.curve, + opacity: opacity ?? 1.0, + onEnd: control.getBool("on_animation_end", false)! + ? () { + control.triggerEvent("animation_end", "opacity"); + } + : null, + child: widget, + ); + } else if (opacity != null) { + return Opacity( + opacity: opacity, + child: widget, + ); + } + return widget; +} + +Widget _rotatedControl(BuildContext context, Widget widget, Control control) { + var rotationDetails = control.getRotationDetails("rotate"); + var animation = control.getAnimation("animate_rotation"); + if (animation != null) { + return TweenAnimationBuilder( + tween: Tween(end: rotationDetails?.angle ?? 0), + duration: animation.duration, + curve: animation.curve, + onEnd: control.getBool("on_animation_end", false)! + ? () { + control.triggerEvent("animation_end", "rotation"); + } + : null, + builder: (context, value, child) => Transform.rotate( + angle: value, + alignment: rotationDetails?.alignment ?? Alignment.center, + origin: rotationDetails?.origin, + transformHitTests: rotationDetails?.transformHitTests ?? true, + filterQuality: rotationDetails?.filterQuality, + child: child, + ), + child: widget, + ); + } else if (rotationDetails != null) { + return Transform.rotate( + angle: rotationDetails.angle, + alignment: rotationDetails.alignment, + origin: rotationDetails.origin, + transformHitTests: rotationDetails.transformHitTests, + filterQuality: rotationDetails.filterQuality, + child: widget, + ); + } + return widget; +} + +Widget _scaledControl(BuildContext context, Widget widget, Control control) { + var scaleDetails = control.getScale("scale"); + var animation = control.getAnimation("animate_scale"); + if (animation != null) { + return TweenAnimationBuilder( + tween: Tween(end: scaleDetails?.scale ?? 1.0), + duration: animation.duration, + curve: animation.curve, + onEnd: control.getBool("on_animation_end", false)! + ? () { + control.triggerEvent("animation_end", "scale"); + } + : null, + builder: (context, value, child) => Transform.scale( + scale: value, + scaleX: scaleDetails?.scaleX, + scaleY: scaleDetails?.scaleY, + alignment: scaleDetails?.alignment ?? Alignment.center, + origin: scaleDetails?.origin, + transformHitTests: scaleDetails?.transformHitTests ?? true, + filterQuality: scaleDetails?.filterQuality, + child: child, + ), + child: widget, + ); + } else if (scaleDetails != null) { + return Transform.scale( + scale: scaleDetails.scale, + scaleX: scaleDetails.scaleX, + scaleY: scaleDetails.scaleY, + alignment: scaleDetails.alignment, + origin: scaleDetails.origin, + transformHitTests: scaleDetails.transformHitTests, + filterQuality: scaleDetails.filterQuality, + child: widget, + ); + } + return widget; +} + +Widget _offsetControl(BuildContext context, Widget widget, Control control) { + var offsetDetails = control.getOffsetDetails("offset"); + var animation = control.getAnimation("animate_offset"); + if (offsetDetails != null && animation != null) { + return TweenAnimationBuilder( + tween: Tween(end: Offset(offsetDetails.x, offsetDetails.y)), + duration: animation.duration, + curve: animation.curve, + onEnd: control.getBool("on_animation_end", false)! + ? () { + control.triggerEvent("animation_end", "offset"); + } + : null, + builder: (context, value, child) => _fractionalTranslate( + child: child!, + offset: value, + transformHitTests: offsetDetails.transformHitTests, + filterQuality: offsetDetails.filterQuality, + ), + child: widget, + ); + } else if (offsetDetails != null) { + return _fractionalTranslate( + child: widget, + offset: Offset(offsetDetails.x, offsetDetails.y), + transformHitTests: offsetDetails.transformHitTests, + filterQuality: offsetDetails.filterQuality, + ); + } + return widget; +} + +Widget _flippedControl(Widget widget, Control control) { + var flipDetails = control.getFlipDetails("flip"); + if (flipDetails != null) { + return Transform.flip( + flipX: flipDetails.flipX, + flipY: flipDetails.flipY, + origin: flipDetails.origin, + transformHitTests: flipDetails.transformHitTests, + filterQuality: flipDetails.filterQuality, + child: widget, + ); + } + return widget; +} + +Widget _transformedControl(Widget widget, Control control) { + var transformDetails = control.getTransformDetails("transform"); + if (transformDetails != null) { + return Transform( + transform: transformDetails.matrix, + origin: transformDetails.origin, + alignment: transformDetails.alignment, + transformHitTests: transformDetails.transformHitTests, + filterQuality: transformDetails.filterQuality, + child: widget, + ); + } + return widget; +} + +Widget _fractionalTranslate({ + required Widget child, + required Offset offset, + required bool transformHitTests, + required FilterQuality? filterQuality, +}) { + // FractionalTranslation preserves existing offset semantics: + // translation values are scaled by the child's laid out size. + // `filterQuality` does not apply here because no bitmap transform is used. + return FractionalTranslation( + translation: offset, + transformHitTests: transformHitTests, + child: child, + ); +} + +Widget _alignedControl(BuildContext context, Widget widget, Control control) { + var alignment = control.getAlignment("align"); + var animation = control.getAnimation("animate_align"); + if (alignment != null && animation != null) { + return AnimatedAlign( + alignment: alignment, + duration: animation.duration, + curve: animation.curve, + onEnd: control.getBool("on_animation_end", false)! + ? () { + control.triggerEvent("animation_end", "align"); + } + : null, + child: widget, + ); + } else if (alignment != null) { + return Align( + alignment: alignment, + child: widget, + ); + } + return widget; +} + +Widget _marginControl(BuildContext context, Widget widget, Control control) { + final skipProps = control.internals?["skip_properties"] as List?; + if (skipProps?.contains("margin") == true) return widget; + + var margin = control.getEdgeInsets("margin"); + var animation = control.getAnimation("animate_margin"); + if (margin != null && animation != null) { + return AnimatedContainer( + margin: margin, + duration: animation.duration, + curve: animation.curve, + onEnd: control.getBool("on_animation_end", false)! + ? () { + control.triggerEvent("animation_end", "margin"); + } + : null, + child: widget, + ); + } else if (margin != null) { + return Container( + margin: margin, + child: widget, + ); + } + return widget; +} + +Widget _positionedControl( + BuildContext context, Widget widget, Control control) { + var left = control.getDouble("left", null); + var top = control.getDouble("top", null); + var right = control.getDouble("right", null); + var bottom = control.getDouble("bottom", null); + + var errorControl = ErrorControl("Error displaying ${control.type}", + description: + "Control can be positioned absolutely with \"left\", \"top\", \"right\" and \"bottom\" properties inside Stack control only and page.overlay."); + + var animation = control.getAnimation("animate_position"); + if (animation != null) { + if (control.parent?.internals?["host_positioned"] != true) { + return errorControl; + } + if (left == null && top == null && right == null && bottom == null) { + left = 0; + top = 0; + } + + return AnimatedPositioned( + duration: animation.duration, + curve: animation.curve, + left: left, + top: top, + right: right, + bottom: bottom, + onEnd: () => control.triggerEvent("animation_end", "position"), + child: widget, + ); + } else if (left != null || top != null || right != null || bottom != null) { + if (control.parent?.internals?["host_positioned"] != true) { + return errorControl; + } + return Positioned( + left: left, + top: top, + right: right, + bottom: bottom, + child: widget, + ); + } + return widget; +} + +Widget _sizedControl(Widget widget, Control control) { + final skipProps = control.internals?['skip_properties'] as List?; + if (skipProps != null && ['width', 'height'].any(skipProps.contains)) { + return widget; + } + + final width = control.getDouble("width"); + final height = control.getDouble("height"); + final animationSize = control.getAnimation("animate_size"); + + final hasFixedSize = width != null || height != null; + + if (animationSize != null) { + return hasFixedSize + ? AnimatedContainer( + duration: animationSize.duration, + curve: animationSize.curve, + width: width, + height: height, + child: widget, + ) + : AnimatedSize( + duration: animationSize.duration, + curve: animationSize.curve, + child: widget, + ); + } else { + return hasFixedSize + ? SizedBox(width: width, height: height, child: widget) + : widget; + } +} + +class SizeChangeObserver extends StatefulWidget { + final Control control; + final int interval; + final Widget child; + + const SizeChangeObserver({ + super.key, + required this.control, + required this.interval, + required this.child, + }); + + @override + State createState() => _SizeChangeObserverState(); +} + +class _SizeChangeObserverState extends State { + Size? _lastSize; + Size? _pendingSize; + int _lastDispatch = 0; + Timer? _timer; + + void _onSizeChanged(Size size) { + if (!mounted || widget.control.getBool("on_size_change", false) != true) { + return; + } + + final now = DateTime.now().millisecondsSinceEpoch; + final interval = widget.interval; + final sizeChanged = _lastSize != size; + + if (!sizeChanged) { + return; + } + + if (_lastSize != null && interval > 0 && (now - _lastDispatch) < interval) { + _pendingSize = size; + _schedulePending(interval, now); + return; + } + + _dispatchSize(size, now); + } + + void _dispatchSize(Size size, int now) { + _pendingSize = null; + _timer?.cancel(); + _lastSize = size; + _lastDispatch = now; + widget.control + .triggerEvent("size_change", {"w": size.width, "h": size.height}); + } + + void _schedulePending(int interval, int now) { + // Coalesce rapid changes into a trailing dispatch. + _timer?.cancel(); + final remaining = interval - (now - _lastDispatch); + final delay = Duration(milliseconds: remaining > 0 ? remaining : 0); + _timer = Timer(delay, () { + if (!mounted || !widget.control.getBool("on_size_change", false)!) { + return; + } + final size = _pendingSize; + if (size == null) { + return; + } + _dispatchSize(size, DateTime.now().millisecondsSinceEpoch); + }); + } + + @override + Widget build(BuildContext context) { + return MeasureSize(onChange: _onSizeChanged, child: widget.child); + } + + @override + void dispose() { + _timer?.cancel(); + super.dispose(); + } +} + +class MeasureSize extends SingleChildRenderObjectWidget { + final ValueChanged onChange; + + const MeasureSize({super.key, required this.onChange, required Widget child}) + : super(child: child); + + @override + RenderObject createRenderObject(BuildContext context) { + return _MeasureSizeRenderObject(onChange); + } + + @override + void updateRenderObject( + BuildContext context, covariant RenderObject renderObject) { + (renderObject as _MeasureSizeRenderObject).onChange = onChange; + } +} + +class _MeasureSizeRenderObject extends RenderProxyBox { + ValueChanged onChange; + Size? _lastSize; + + _MeasureSizeRenderObject(this.onChange); + + @override + void performLayout() { + super.performLayout(); + // Post-frame to avoid re-entrant layout callbacks. + final newSize = child?.size ?? size; + if (_lastSize == newSize) { + return; + } + _lastSize = newSize; + WidgetsBinding.instance.addPostFrameCallback((_) { + onChange(newSize); + }); + } +} diff --git a/packages/flet/lib/src/controls/bottom_app_bar.dart b/packages/flet/lib/src/controls/bottom_app_bar.dart index 7681ca269c..ddb8bedf4e 100644 --- a/packages/flet/lib/src/controls/bottom_app_bar.dart +++ b/packages/flet/lib/src/controls/bottom_app_bar.dart @@ -1,68 +1,52 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; -class BottomAppBarControl extends StatefulWidget { - final Control? parent; +class BottomAppBarControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const BottomAppBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const BottomAppBarControl({super.key, required this.control}); @override - State createState() => _BottomAppBarControlState(); -} - -class _BottomAppBarControlState extends State - with FletStoreMixin { - @override Widget build(BuildContext context) { - debugPrint("BottomAppBarControl build: ${widget.control.id}"); - - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - - var shape = parseNotchedShape(widget.control.attrString("shape")); - - var elevation = widget.control.attrDouble("elevation", 0)!; - - var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!; - var bottomAppBar = withControls( - widget.children - .where((c) => c.isVisible && c.name == null) - .map((c) => c.id), (content, viewModel) { - return BottomAppBar( - clipBehavior: clipBehavior, - padding: parseEdgeInsets(widget.control, "padding"), - height: widget.control.attrDouble("height"), - elevation: elevation, - shape: shape, - shadowColor: widget.control.attrColor("shadowColor", context), - surfaceTintColor: widget.control.attrColor("surfaceTintColor", context), - color: widget.control.attrColor("bgColor", context), - notchMargin: widget.control.attrDouble("notchMargin", 4.0)!, - child: contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, + debugPrint("BottomAppBarControl build: ${control.id}"); + + final theme = Theme.of(context); + var borderRadius = control.getBorderRadius("border_radius"); + final clipBehavior = control.getClipBehavior( + "clip_behavior", + borderRadius != null && borderRadius != BorderRadius.zero + ? Clip.antiAlias + : Clip.none)!; + + Widget bottomAppBar = BottomAppBar( + clipBehavior: clipBehavior, + padding: control.getPadding("padding"), + height: control.getDouble("height"), + elevation: control.getDouble("elevation"), + shape: control.getNotchedShape("shape", theme), + shadowColor: control.getColor("shadow_color", context), + color: control.getColor("bgcolor", context), + notchMargin: control.getDouble("notch_margin", 4.0)!, + child: control.buildWidget("content"), + ); + + if (borderRadius != null && borderRadius != BorderRadius.zero) { + bottomAppBar = ClipRRect( + borderRadius: borderRadius, + // can't use Clip.none here, so fallback to Clip.antiAlias in that case + clipBehavior: clipBehavior == Clip.none ? Clip.antiAlias : clipBehavior, + child: bottomAppBar, ); - }); + } - return constrainedControl( - context, bottomAppBar, widget.parent, widget.control); + return LayoutControl(control: control, child: bottomAppBar); } } diff --git a/packages/flet/lib/src/controls/bottom_sheet.dart b/packages/flet/lib/src/controls/bottom_sheet.dart index c8351ab28f..1f92ab7577 100644 --- a/packages/flet/lib/src/controls/bottom_sheet.dart +++ b/packages/flet/lib/src/controls/bottom_sheet.dart @@ -1,87 +1,51 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/animations.dart'; import '../utils/borders.dart'; import '../utils/box.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/colors.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; -class BottomSheetControl extends StatefulWidget { - final Control? parent; +class BottomSheetControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final Widget? nextChild; - final FletControlBackend backend; - const BottomSheetControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.nextChild, - required this.backend}); + BottomSheetControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); - @override - State createState() => _BottomSheetControlState(); -} - -class _BottomSheetControlState extends State { @override Widget build(BuildContext context) { - debugPrint("BottomSheet build: ${widget.control.id}"); + debugPrint("BottomSheet build: ${control.id}"); - bool lastOpen = widget.control.state["open"] ?? false; - bool disabled = widget.control.isDisabled || widget.parentDisabled; + bool lastOpen = control.getBool("_open", false)!; + var open = control.getBool("open", false)!; - var open = widget.control.attrBool("open", false)!; - //var modal = widget.control.attrBool("modal", true)!; - var dismissible = widget.control.attrBool("dismissible", true)!; - var enableDrag = widget.control.attrBool("enableDrag", false)!; - var showDragHandle = widget.control.attrBool("showDragHandle", false)!; - var useSafeArea = widget.control.attrBool("useSafeArea", true)!; - var isScrollControlled = - widget.control.attrBool("isScrollControlled", false)!; var maintainBottomViewInsetsPadding = - widget.control.attrBool("maintainBottomViewInsetsPadding", true)!; - - void resetOpenState() { - widget.backend.updateControlState(widget.control.id, {"open": "false"}); - } + control.getBool("maintain_bottom_view_insets_padding", true)!; + final fullscreen = control.getBool("fullscreen", false)!; + final scrollable = fullscreen || control.getBool("scrollable", false)!; + final draggable = control.getBool("draggable", false)!; if (open && !lastOpen) { - widget.control.state["open"] = open; + control.updateProperties({"_open": open}, python: false); WidgetsBinding.instance.addPostFrameCallback((_) { + ModalRoute? sheetRoute; showModalBottomSheet( context: context, builder: (context) { - var contentCtrls = widget.children - .where((c) => c.name == "content" && c.isVisible); + sheetRoute ??= ModalRoute.of(context); + var content = control.buildWidget("content"); - if (contentCtrls.isEmpty) { + if (content == null) { return const ErrorControl( - "BottomSheet.content must be provided and visible"); - } - - var content = createControl( - widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive); - - if (content is ErrorControl) { - return content; + "BottomSheet.content must be visible"); } if (maintainBottomViewInsetsPadding) { - var bottomPadding = - MediaQuery.of(context).viewInsets.bottom; - debugPrint("bottomPadding: $bottomPadding"); content = Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom), @@ -89,33 +53,33 @@ class _BottomSheetControlState extends State { ); } + if (fullscreen) { + content = SizedBox.expand(child: content); + } + return content; }, - isDismissible: dismissible, - backgroundColor: widget.control.attrColor("bgColor", context), - elevation: widget.control.attrDouble("elevation"), - isScrollControlled: isScrollControlled, - enableDrag: enableDrag, - barrierColor: widget.control.attrColor("barrierColor", context), + isDismissible: control.getBool("dismissible", true)!, + backgroundColor: control.getColor("bgcolor", context), + elevation: control.getDouble("elevation"), + isScrollControlled: scrollable, + enableDrag: draggable, + barrierColor: control.getColor("barrier_color", context), sheetAnimationStyle: - parseAnimationStyle(widget.control, "animationStyle"), - constraints: - parseBoxConstraints(widget.control, "sizeConstraints"), - showDragHandle: showDragHandle, - clipBehavior: - parseClip(widget.control.attrString("clipBehavior")), - shape: parseOutlinedBorder(widget.control, "shape"), - useSafeArea: useSafeArea) + control.getAnimationStyle("animation_style"), + constraints: fullscreen + ? null + : control.getBoxConstraints("size_constraints"), + showDragHandle: control.getBool("show_drag_handle", false)!, + clipBehavior: control.getClipBehavior("clip_behavior"), + shape: control.getOutlinedBorder("shape", Theme.of(context)), + useSafeArea: control.getBool("use_safe_area", true)!) .then((value) { - lastOpen = widget.control.state["open"] ?? false; - debugPrint("BottomSheet dismissed: $lastOpen"); - bool shouldDismiss = lastOpen; - widget.control.state["open"] = false; - - if (shouldDismiss) { - resetOpenState(); - widget.backend.triggerControlEvent(widget.control.id, "dismiss"); - } + (sheetRoute?.completed ?? Future.value()).then((_) { + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"open": false}); + control.triggerEvent("dismiss"); + }); }); }); } else if (open != lastOpen && lastOpen) { diff --git a/packages/flet/lib/src/controls/button.dart b/packages/flet/lib/src/controls/button.dart new file mode 100644 index 0000000000..3d2b276ad9 --- /dev/null +++ b/packages/flet/lib/src/controls/button.dart @@ -0,0 +1,234 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/buttons.dart'; +import '../utils/colors.dart'; +import '../utils/launch_url.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; + +class ButtonControl extends StatefulWidget { + final Control control; + + ButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _ButtonControlState(); +} + +class _ButtonControlState extends State with FletStoreMixin { + late final FocusNode _focusNode; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(); + _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + _focusNode.removeListener(_onFocusChange); + _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + void _onFocusChange() { + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Button.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown Button method: $name"); + } + } + + @override + Widget build(BuildContext context) { + debugPrint("Button build: ${widget.control.id}"); + + bool isFilledButton = widget.control.type == "FilledButton"; + bool isFilledTonalButton = widget.control.type == "FilledTonalButton"; + bool isTextButton = widget.control.type == "TextButton"; + bool isOutlinedButton = widget.control.type == "OutlinedButton"; + + var url = widget.control.getUrl("url"); + var iconColor = widget.control.getColor("icon_color", context); + var clipBehavior = + widget.control.getClipBehavior("clip_behavior", Clip.none)!; + var autofocus = widget.control.getBool("autofocus", false)!; + + var icon = widget.control.buildIconOrWidget("icon", color: iconColor); + var content = widget.control.buildTextOrWidget("content"); + + Function()? onPressed = !widget.control.disabled + ? () { + if (url != null) { + openWebBrowser(url); + } + widget.control.triggerEvent("click"); + } + : null; + + Function()? onLongPressHandler = !widget.control.disabled + ? () { + widget.control.triggerEvent("long_press"); + } + : null; + + Function(bool)? onHoverHandler = !widget.control.disabled + ? (state) { + widget.control.triggerEvent("hover", state); + } + : null; + + Widget? button; + + var theme = Theme.of(context); + + var style = parseButtonStyle( + widget.control.internals?["style"] ?? widget.control.get("style"), + theme, + defaultForegroundColor: + widget.control.getColor("color", context, theme.colorScheme.primary)!, + defaultBackgroundColor: widget.control + .getColor("bgcolor", context, theme.colorScheme.surface)!, + defaultOverlayColor: theme.colorScheme.primary.withValues(alpha: 0.08), + defaultShadowColor: theme.colorScheme.shadow, + defaultSurfaceTintColor: theme.colorScheme.surfaceTint, + defaultElevation: widget.control.getDouble("elevation", 1)!, + defaultPadding: const EdgeInsets.symmetric(horizontal: 8), + defaultBorderSide: BorderSide.none, + defaultShape: theme.useMaterial3 + ? const StadiumBorder() + : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)), + ); + + Widget error = const ErrorControl("Error displaying Button", + description: "\"icon\" must be specified together with \"content\""); + + if (icon != null) { + if (isFilledButton) { + button = FilledButton.icon( + style: style, + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + icon: icon, + label: content ?? error); + } else if (isFilledTonalButton) { + button = FilledButton.tonalIcon( + style: style, + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + icon: icon, + label: content ?? error); + } else if (isTextButton) { + button = TextButton.icon( + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + style: style, + clipBehavior: clipBehavior, + icon: icon, + label: content ?? error, + ); + } else if (isOutlinedButton) { + button = OutlinedButton.icon( + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + clipBehavior: clipBehavior, + style: style, + icon: icon, + label: content ?? error); + } else { + button = ElevatedButton.icon( + style: style, + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + icon: icon, + label: content ?? error); + } + } else { + if (isFilledButton) { + button = FilledButton( + style: style, + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + child: content); + } else if (isFilledTonalButton) { + button = FilledButton.tonal( + style: style, + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + child: content); + } else if (isTextButton) { + button = TextButton( + autofocus: autofocus, + focusNode: _focusNode, + style: style, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + child: content ?? const Text("")); + } else if (isOutlinedButton) { + button = OutlinedButton( + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + clipBehavior: clipBehavior, + onHover: onHoverHandler, + style: style, + child: content); + } else { + button = ElevatedButton( + style: style, + autofocus: autofocus, + focusNode: _focusNode, + onPressed: onPressed, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + clipBehavior: clipBehavior, + child: content); + } + } + + return LayoutControl(control: widget.control, child: button); + } +} diff --git a/packages/flet/lib/src/controls/canvas.dart b/packages/flet/lib/src/controls/canvas.dart index 50b48e35b8..8d6b73c6c9 100644 --- a/packages/flet/lib/src/controls/canvas.dart +++ b/packages/flet/lib/src/controls/canvas.dart @@ -1,71 +1,32 @@ -import 'dart:convert'; +import 'dart:async'; +import 'dart:io'; import 'dart:ui' as ui; -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; +import 'package:flutter/services.dart'; +import 'package:http/http.dart' as http; -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../models/control_tree_view_model.dart'; import '../utils/alignment.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/dash_path.dart'; import '../utils/drawing.dart'; +import '../utils/hashing.dart'; import '../utils/images.dart'; import '../utils/numbers.dart'; import '../utils/text.dart'; import '../utils/transforms.dart'; -import 'create_control.dart'; - -class CanvasViewModel extends Equatable { - final Control control; - final Control? child; - final List shapes; - - const CanvasViewModel( - {required this.control, required this.child, required this.shapes}); - - static CanvasViewModel fromStore( - Store store, Control control, List children) { - return CanvasViewModel( - control: control, - child: store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.name == "content" && c.isVisible) - .firstOrNull, - shapes: children - .where((c) => c.name != "content" && c.isVisible) - .map((c) => ControlTreeViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => [control, shapes]; -} +import 'base_controls.dart'; typedef CanvasControlOnPaintCallback = void Function(Size size); class CanvasControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const CanvasControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + CanvasControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CanvasControlState(); @@ -73,233 +34,388 @@ class CanvasControl extends StatefulWidget { class _CanvasControlState extends State { int _lastResize = DateTime.now().millisecondsSinceEpoch; - Size? _lastSize; + Size _lastSize = Size.zero; + ui.Image? _capturedImage; + Size _capturedSize = Size.zero; + double _dpr = 1.0; + bool _initialized = false; @override - Widget build(BuildContext context) { - debugPrint("CustomPaint build: ${widget.control.id}"); + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (!_initialized) { + _dpr = MediaQuery.devicePixelRatioOf(context); + _initialized = true; + } + } + + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + _capturedImage?.dispose(); + _capturedImage = null; + super.dispose(); + } + + Future _awaitImageLoads(List shapes) async { + final pending = []; + + for (final shape in shapes) { + if (shape.type == "Image") { + if (shape.get("_loading") != null) { + pending.add(shape.get("_loading").future); + } else if (shape.get("_image") == null || + shape.get("_hash") != getImageHash(shape)) { + final future = loadCanvasImage(shape); + pending.add(future); + } + } + } - var result = StoreConnector( - distinct: true, - ignoreChange: (state) { - return state.controls[widget.control.id] == null; + if (pending.isNotEmpty) { + await Future.wait(pending); + } + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Canvas.$name($args)"); + switch (name) { + case "capture": + final shapes = widget.control.children("shapes"); + if (_lastSize.isEmpty || shapes.isEmpty) { + return; + } + + var dpr = parseDouble(args["pixel_ratio"]) ?? _dpr; + + // Wait for all images to load + await _awaitImageLoads(shapes); + + if (!mounted) return; + + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + + var capturedSize = + _capturedSize != Size.zero ? _capturedSize : _lastSize; + + final painter = FletCustomPainter( + context: context, + theme: Theme.of(context), + shapes: shapes, + capturedImage: _capturedImage, + capturedSize: capturedSize, + onPaintCallback: (_) {}, + dpr: dpr); + + painter.paint(canvas, _lastSize); + + final picture = recorder.endRecording(); + final newImage = await picture.toImage( + (_lastSize.width * dpr).toInt(), + (_lastSize.height * dpr).toInt(), + ); + picture.dispose(); + final oldImage = _capturedImage; + _capturedImage = newImage; + _capturedSize = _lastSize; + if (oldImage != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + oldImage.dispose(); + }); + } + return; + + case "get_capture": + if (_capturedImage == null) return null; + final byteData = + await _capturedImage!.toByteData(format: ui.ImageByteFormat.png); + return byteData!.buffer.asUint8List(); + + case "clear_capture": + _capturedImage?.dispose(); + _capturedImage = null; + setState(() {}); + return; + + default: + throw Exception("Unknown Canvas method: $name"); + } + } + + @override + Widget build(BuildContext context) { + debugPrint("Canvas build: ${widget.control.id}"); + + var resizeInterval = widget.control.getInt("resize_interval", 10)!; + + var paint = CustomPaint( + painter: FletCustomPainter( + context: context, + theme: Theme.of(context), + shapes: widget.control.children("shapes"), + capturedImage: _capturedImage, + capturedSize: _capturedSize, + dpr: 1, + onPaintCallback: (size) { + var now = DateTime.now().millisecondsSinceEpoch; + if ((now - _lastResize > resizeInterval && _lastSize != size) || + _lastSize.isEmpty) { + _lastSize = size; + _lastResize = now; + widget.control + .triggerEvent("resize", {"w": size.width, "h": size.height}); + } }, - converter: (store) => - CanvasViewModel.fromStore(store, widget.control, widget.children), - builder: (context, viewModel) { - var onResize = viewModel.control.attrBool("onResize", false)!; - var resizeInterval = viewModel.control.attrInt("resizeInterval", 10)!; - - var paint = CustomPaint( - painter: FletCustomPainter( - context: context, - theme: Theme.of(context), - shapes: viewModel.shapes, - onPaintCallback: (size) { - if (onResize) { - var now = DateTime.now().millisecondsSinceEpoch; - if ((now - _lastResize > resizeInterval && - _lastSize != size) || - _lastSize == null) { - _lastResize = now; - _lastSize = size; - widget.backend.triggerControlEvent( - viewModel.control.id, - "resize", - json.encode({"w": size.width, "h": size.height})); - } - } - }, - ), - child: viewModel.child != null - ? createControl(viewModel.control, viewModel.child!.id, - viewModel.control.isDisabled, - parentAdaptive: widget.parentAdaptive) - : null, - ); - - return paint; - }); - - return constrainedControl(context, result, widget.parent, widget.control); + ), + child: widget.control.buildWidget("content"), + ); + + return LayoutControl(control: widget.control, child: paint); } } class FletCustomPainter extends CustomPainter { final BuildContext context; final ThemeData theme; - final List shapes; + final List shapes; final CanvasControlOnPaintCallback onPaintCallback; + final ui.Image? capturedImage; + final Size? capturedSize; + final double dpr; const FletCustomPainter( {required this.context, required this.theme, required this.shapes, - required this.onPaintCallback}); + required this.onPaintCallback, + required this.dpr, + this.capturedImage, + this.capturedSize}); @override void paint(Canvas canvas, Size size) { onPaintCallback(size); - //debugPrint("SHAPE CONTROLS: $shapes"); + canvas.save(); + canvas.scale(dpr); + canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height)); + + if (capturedImage != null && capturedSize != null) { + final src = Rect.fromLTWH(0, 0, capturedImage!.width.toDouble(), + capturedImage!.height.toDouble()); + final dst = + Rect.fromLTWH(0, 0, capturedSize!.width, capturedSize!.height); + canvas.drawImageRect(capturedImage!, src, dst, Paint()); + } for (var shape in shapes) { - if (shape.control.type == "line") { + shape.notifyParent = true; + if (shape.type == "Line") { drawLine(canvas, shape); - } else if (shape.control.type == "circle") { + } else if (shape.type == "Circle") { drawCircle(canvas, shape); - } else if (shape.control.type == "arc") { + } else if (shape.type == "Arc") { drawArc(canvas, shape); - } else if (shape.control.type == "color") { + } else if (shape.type == "Color") { drawColor(canvas, shape); - } else if (shape.control.type == "oval") { + } else if (shape.type == "Oval") { drawOval(canvas, shape); - } else if (shape.control.type == "fill") { + } else if (shape.type == "Fill") { drawFill(canvas, shape); - } else if (shape.control.type == "points") { + } else if (shape.type == "Points") { drawPoints(canvas, shape); - } else if (shape.control.type == "rect") { + } else if (shape.type == "Rect") { drawRect(canvas, shape); - } else if (shape.control.type == "path") { + } else if (shape.type == "Path") { drawPath(canvas, shape); - } else if (shape.control.type == "shadow") { + } else if (shape.type == "Shadow") { drawShadow(canvas, shape); - } else if (shape.control.type == "text") { + } else if (shape.type == "Text") { drawText(context, canvas, shape); + } else if (shape.type == "Image") { + drawImage(canvas, shape); } } + + canvas.restore(); } @override - bool shouldRepaint(FletCustomPainter oldDelegate) { + bool shouldRepaint(FletCustomPainter oldPainter) { return true; } - void drawLine(Canvas canvas, ControlTreeViewModel shape) { - Paint paint = parsePaint(theme, shape.control, "paint"); - var dashPattern = parsePaintStrokeDashPattern(shape.control, "paint"); + void drawLine(Canvas canvas, Control shape) { + Paint paint = shape.getPaint("paint", theme, Paint())!; + var dashPattern = shape.getPaintStrokeDashPattern("paint"); paint.style = ui.PaintingStyle.stroke; - var path = ui.Path(); - path.moveTo( - shape.control.attrDouble("x1")!, shape.control.attrDouble("y1")!); - path.lineTo( - shape.control.attrDouble("x2")!, shape.control.attrDouble("y2")!); - if (dashPattern != null) { + var p1 = Offset(shape.getDouble("x1")!, shape.getDouble("y1")!); + var p2 = Offset(shape.getDouble("x2")!, shape.getDouble("y2")!); + + if (dashPattern == null) { + canvas.drawLine(p1, p2, paint); + } else { + var path = ui.Path(); + path.moveTo(p1.dx, p1.dy); + path.lineTo(p2.dx, p2.dy); path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); + canvas.drawPath(path, paint); } - canvas.drawPath(path, paint); } - void drawCircle(Canvas canvas, ControlTreeViewModel shape) { - var radius = shape.control.attrDouble("radius", 0)!; - Paint paint = parsePaint(theme, shape.control, "paint"); - canvas.drawCircle( - Offset(shape.control.attrDouble("x")!, shape.control.attrDouble("y")!), - radius, - paint); + void drawCircle(Canvas canvas, Control shape) { + var x = shape.getDouble("x")!; + var y = shape.getDouble("y")!; + var radius = shape.getDouble("radius", 0)!; + Paint paint = shape.getPaint("paint", theme, Paint())!; + + var dashPattern = shape.getPaintStrokeDashPattern("paint"); + + if (dashPattern == null) { + canvas.drawCircle(Offset(x, y), radius, paint); + } else { + var path = ui.Path(); + path.addOval(Rect.fromCircle(center: Offset(x, y), radius: radius)); + path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); + canvas.drawPath(path, paint); + } } - void drawOval(Canvas canvas, ControlTreeViewModel shape) { - var width = shape.control.attrDouble("width", 0)!; - var height = shape.control.attrDouble("height", 0)!; - Paint paint = parsePaint(theme, shape.control, "paint"); - canvas.drawOval( - Rect.fromLTWH(shape.control.attrDouble("x")!, - shape.control.attrDouble("y")!, width, height), - paint); + void drawOval(Canvas canvas, Control shape) { + var x = shape.getDouble("x")!; + var y = shape.getDouble("y")!; + var width = shape.getDouble("width", 0)!; + var height = shape.getDouble("height", 0)!; + Paint paint = shape.getPaint("paint", theme, Paint())!; + var dashPattern = shape.getPaintStrokeDashPattern("paint"); + + if (dashPattern == null) { + canvas.drawOval(Rect.fromLTWH(x, y, width, height), paint); + } else { + var path = ui.Path(); + path.addOval(Rect.fromLTWH(x, y, width, height)); + path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); + canvas.drawPath(path, paint); + } } - void drawArc(Canvas canvas, ControlTreeViewModel shape) { - var width = shape.control.attrDouble("width", 0)!; - var height = shape.control.attrDouble("height", 0)!; - var startAngle = shape.control.attrDouble("startAngle", 0)!; - var sweepAngle = shape.control.attrDouble("sweepAngle", 0)!; - var useCenter = shape.control.attrBool("useCenter", false)!; - Paint paint = parsePaint(theme, shape.control, "paint"); - canvas.drawArc( - Rect.fromLTWH(shape.control.attrDouble("x")!, - shape.control.attrDouble("y")!, width, height), - startAngle, - sweepAngle, - useCenter, - paint); + void drawArc(Canvas canvas, Control shape) { + var x = shape.getDouble("x")!; + var y = shape.getDouble("y")!; + var width = shape.getDouble("width", 0)!; + var height = shape.getDouble("height", 0)!; + var startAngle = shape.getDouble("start_angle", 0)!; + var sweepAngle = shape.getDouble("sweep_angle", 0)!; + var useCenter = shape.getBool("use_center", false)!; + Paint paint = shape.getPaint("paint", theme, Paint())!; + + var dashPattern = shape.getPaintStrokeDashPattern("paint"); + if (dashPattern == null) { + canvas.drawArc(Rect.fromLTWH(x, y, width, height), startAngle, sweepAngle, + useCenter, paint); + } else { + var path = ui.Path(); + if (useCenter) { + path.moveTo(x + width / 2, y + height / 2); + path.arcTo( + Rect.fromLTWH(x, y, width, height), startAngle, sweepAngle, false); + path.close(); + } else { + path.addArc(Rect.fromLTWH(x, y, width, height), startAngle, sweepAngle); + } + path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); + canvas.drawPath(path, paint); + } } - void drawFill(Canvas canvas, ControlTreeViewModel shape) { - Paint paint = parsePaint(theme, shape.control, "paint"); + void drawFill(Canvas canvas, Control shape) { + Paint paint = shape.getPaint("paint", theme, Paint())!; canvas.drawPaint(paint); } - void drawColor(Canvas canvas, ControlTreeViewModel shape) { - var color = shape.control.attrColor("color", context) ?? Colors.black; - var blendMode = parseBlendMode( - shape.control.attrString("blendMode"), BlendMode.srcOver)!; + void drawColor(Canvas canvas, Control shape) { + var color = shape.getColor("color", context, Colors.black)!; + var blendMode = + parseBlendMode(shape.getString("blend_mode"), BlendMode.srcOver)!; canvas.drawColor(color, blendMode); } - void drawPoints(Canvas canvas, ControlTreeViewModel shape) { - var points = parseOffsetList(shape.control, "points")!; + void drawPoints(Canvas canvas, Control shape) { + var points = parseOffsetList(shape.get("points"))!; var pointMode = ui.PointMode.values.firstWhere( (e) => e.name.toLowerCase() == - shape.control.attrString("pointMode", "")!.toLowerCase(), + shape.getString("point_mode", "")!.toLowerCase(), orElse: () => ui.PointMode.points); - Paint paint = parsePaint(theme, shape.control, "paint"); + Paint paint = shape.getPaint("paint", theme, Paint())!; canvas.drawPoints(pointMode, points, paint); } - void drawRect(Canvas canvas, ControlTreeViewModel shape) { - var width = shape.control.attrDouble("width", 0)!; - var height = shape.control.attrDouble("height", 0)!; - var borderRadius = parseBorderRadius(shape.control, "borderRadius"); - Paint paint = parsePaint(theme, shape.control, "paint"); - canvas.drawRRect( - RRect.fromRectAndCorners( - Rect.fromLTWH(shape.control.attrDouble("x")!, - shape.control.attrDouble("y")!, width, height), - topLeft: borderRadius?.topLeft ?? Radius.zero, - topRight: borderRadius?.topRight ?? Radius.zero, - bottomLeft: borderRadius?.bottomLeft ?? Radius.zero, - bottomRight: borderRadius?.bottomRight ?? Radius.zero), - paint); + void drawRect(Canvas canvas, Control shape) { + var x = shape.getDouble("x")!; + var y = shape.getDouble("y")!; + var width = shape.getDouble("width", 0)!; + var height = shape.getDouble("height", 0)!; + var borderRadius = + shape.getBorderRadius("border_radius", BorderRadius.zero)!; + Paint paint = shape.getPaint("paint", theme, Paint())!; + var dashPattern = shape.getPaintStrokeDashPattern("paint"); + + if (dashPattern == null) { + canvas.drawRRect( + RRect.fromRectAndCorners(Rect.fromLTWH(x, y, width, height), + topLeft: borderRadius.topLeft, + topRight: borderRadius.topRight, + bottomLeft: borderRadius.bottomLeft, + bottomRight: borderRadius.bottomRight), + paint); + } else { + var path = ui.Path(); + path.addRRect(RRect.fromRectAndCorners(Rect.fromLTWH(x, y, width, height), + topLeft: borderRadius.topLeft, + topRight: borderRadius.topRight, + bottomLeft: borderRadius.bottomLeft, + bottomRight: borderRadius.bottomRight)); + path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); + canvas.drawPath(path, paint); + } } - void drawText( - BuildContext context, Canvas canvas, ControlTreeViewModel shape) { - var offset = - Offset(shape.control.attrDouble("x")!, shape.control.attrDouble("y")!); - var alignment = - parseAlignment(shape.control, "alignment", Alignment.topLeft)!; - var text = shape.control.attrString("text", "")!; - TextStyle style = parseTextStyle(theme, shape.control, "style") ?? - theme.textTheme.bodyMedium!; - + void drawText(BuildContext context, Canvas canvas, Control shape) { + var offset = Offset(shape.getDouble("x")!, shape.getDouble("y")!); + var alignment = shape.getAlignment("alignment", Alignment.topLeft)!; + var style = + shape.getTextStyle("style", theme, theme.textTheme.bodyMedium!)!; if (style.color == null) { style = style.copyWith(color: theme.textTheme.bodyMedium!.color); } - - TextAlign? textAlign = - parseTextAlign(shape.control.attrString("textAlign"), TextAlign.start)!; TextSpan span = TextSpan( - text: text, + text: shape.getString("value", "")!, style: style, - children: parseTextSpans(theme, shape, false, null)); + children: parseTextSpans(shape.children("spans"), theme)); - var maxLines = shape.control.attrInt("maxLines"); - var maxWidth = shape.control.attrDouble("maxWidth"); - var ellipsis = shape.control.attrString("ellipsis"); + var maxLines = shape.getInt("max_lines"); + var maxWidth = shape.getDouble("max_width"); + var ellipsis = shape.getString("ellipsis"); // paint TextPainter textPainter = TextPainter( text: span, - textAlign: textAlign, + textAlign: shape.getTextAlign("text_align", TextAlign.start)!, maxLines: maxLines, ellipsis: ellipsis, textDirection: Directionality.of(context)); textPainter.layout(maxWidth: maxWidth ?? double.infinity); - var angle = shape.control.attrDouble("rotate", 0)!; + var angle = shape.getDouble("rotate", 0)!; final delta = Offset( offset.dx - textPainter.size.width / 2 * (alignment.x + 1.0), @@ -314,38 +430,65 @@ class FletCustomPainter extends CustomPainter { canvas.restore(); } - void drawPath(Canvas canvas, ControlTreeViewModel shape) { - var path = - buildPath(json.decode(shape.control.attrString("elements", "[]")!)); - Paint paint = parsePaint(theme, shape.control, "paint"); - var dashPattern = parsePaintStrokeDashPattern(shape.control, "paint"); + void drawPath(Canvas canvas, Control shape) { + var path = buildPath(shape.get("elements", [])!); + Paint paint = shape.getPaint("paint", theme, Paint())!; + var dashPattern = shape.getPaintStrokeDashPattern("paint"); if (dashPattern != null) { path = dashPath(path, dashArray: CircularIntervalList(dashPattern)); } canvas.drawPath(path, paint); } - void drawShadow(Canvas canvas, ControlTreeViewModel shape) { - var path = buildPath(json.decode(shape.control.attrString("path", "[]")!)); - var color = shape.control.attrColor("color", context) ?? Colors.black; - var elevation = shape.control.attrDouble("elevation", 0)!; - var transparentOccluder = - shape.control.attrBool("transparentOccluder", false)!; + void drawShadow(Canvas canvas, Control shape) { + var path = buildPath(shape.get("path", [])!); + var color = shape.getColor("color", context, Colors.black)!; + var elevation = shape.getDouble("elevation", 0)!; + var transparentOccluder = shape.getBool("transparent_occluder", false)!; canvas.drawShadow(path, color, elevation, transparentOccluder); } + void drawImage(Canvas canvas, Control shape) { + final paint = shape.getPaint("paint", theme, Paint())!; + final x = shape.getDouble("x")!; + final y = shape.getDouble("y")!; + final width = shape.getDouble("width"); + final height = shape.getDouble("height"); + + final img = shape.get("_image") as ui.Image?; + final hashMatch = + img != null && shape.get("_hash") == getImageHash(shape); + + // Gapless playback: if we have a cached image, draw it even when the hash + // is stale. Without this, src updates leave a blank frame on screen while + // the new bytes decode asynchronously, causing visible flicker during + // rapid updates (e.g. matplotlib animations). + if (img != null) { + final srcRect = + Rect.fromLTWH(0, 0, img.width.toDouble(), img.height.toDouble()); + final dstRect = width != null && height != null + ? Rect.fromLTWH(x, y, width, height) + : Offset(x, y) & Size(img.width.toDouble(), img.height.toDouble()); + debugPrint("canvas.drawImageRect($srcRect, $dstRect)"); + canvas.drawImageRect(img, srcRect, dstRect, paint); + } + if (!hashMatch) { + loadCanvasImage(shape); + } + } + ui.Path buildPath(dynamic j) { var path = ui.Path(); if (j == null) { return path; } for (var elem in (j as List)) { - var type = elem["type"]; - if (type == "moveto") { + var type = elem["_type"]; + if (type == "MoveTo") { path.moveTo(parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!); - } else if (type == "lineto") { + } else if (type == "LineTo") { path.lineTo(parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!); - } else if (type == "arc") { + } else if (type == "Arc") { path.addArc( Rect.fromLTWH( parseDouble(elem["x"], 0)!, @@ -354,21 +497,21 @@ class FletCustomPainter extends CustomPainter { parseDouble(elem["height"], 0)!), parseDouble(elem["start_angle"], 0)!, parseDouble(elem["sweep_angle"], 0)!); - } else if (type == "arcto") { + } else if (type == "ArcTo") { path.arcToPoint( Offset(parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!), radius: Radius.circular(parseDouble(elem["radius"], 0)!), rotation: parseDouble(elem["rotation"], 0)!, largeArc: parseBool(elem["large_arc"], false)!, clockwise: parseBool(elem["clockwise"], true)!); - } else if (type == "oval") { + } else if (type == "Oval") { path.addOval(Rect.fromLTWH( parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!, parseDouble(elem["width"], 0)!, parseDouble(elem["height"], 0)!)); - } else if (type == "rect") { - var borderRadius = borderRadiusFromJSON(elem["border_radius"]); + } else if (type == "Rect") { + var borderRadius = parseBorderRadius(elem["border_radius"]); path.addRRect(RRect.fromRectAndCorners( Rect.fromLTWH( parseDouble(elem["x"], 0)!, @@ -379,14 +522,14 @@ class FletCustomPainter extends CustomPainter { topRight: borderRadius?.topRight ?? Radius.zero, bottomLeft: borderRadius?.bottomLeft ?? Radius.zero, bottomRight: borderRadius?.bottomRight ?? Radius.zero)); - } else if (type == "conicto") { + } else if (type == "QuadraticTo") { path.conicTo( parseDouble(elem["cp1x"], 0)!, parseDouble(elem["cp1y"], 0)!, parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!, parseDouble(elem["w"], 0)!); - } else if (type == "cubicto") { + } else if (type == "CubicTo") { path.cubicTo( parseDouble(elem["cp1x"], 0)!, parseDouble(elem["cp1y"], 0)!, @@ -394,13 +537,80 @@ class FletCustomPainter extends CustomPainter { parseDouble(elem["cp2y"], 0)!, parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!); - } else if (type == "subpath") { + } else if (type == "SubPath") { path.addPath(buildPath(elem["elements"]), Offset(parseDouble(elem["x"], 0)!, parseDouble(elem["y"], 0)!)); - } else if (type == "close") { + } else if (type == "Close") { path.close(); } } return path; } } + +Future loadCanvasImage(Control shape) async { + debugPrint("loadCanvasImage(${shape.id})"); + if (shape.get("_loading") != null) return; + final completer = Completer(); + shape.properties["_loading"] = completer; + + final src = shape.getSrc("src"); + + try { + Uint8List bytes; + + if (src.error != null) { + throw Exception("Error decoding src: ${src.error}"); + } + + if (src.hasBytes) { + bytes = src.bytes!; + } else if (src.hasUri) { + var assetSrc = shape.backend.getAssetSource(src.uri!); + if (assetSrc.isFile) { + final file = File(assetSrc.path); + bytes = await file.readAsBytes(); + } else { + final resp = await http.get(Uri.parse(assetSrc.path)); + if (resp.statusCode != 200) { + throw Exception("HTTP ${resp.statusCode}"); + } + bytes = resp.bodyBytes; + } + } else { + throw Exception("Missing image source: 'src'"); + } + + final codec = await ui.instantiateImageCodec(bytes, allowUpscaling: false); + final frame = await codec.getNextFrame(); + codec.dispose(); + final oldImage = shape.get("_image") as ui.Image?; + shape.properties["_image"] = frame.image; + shape.updateProperties({"_hash": getImageHash(shape)}, + python: false, notify: true); + if (oldImage != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + oldImage.dispose(); + }); + } + completer.complete(); + } catch (e) { + shape.properties["_image_error"] = e; + completer.completeError(e); + } finally { + shape.properties.remove("_loading"); + } +} + +/// Produces a fast hash for the `src` so Canvas can tell when it needs to +/// refetch the image. Inline strings and bytes use FNV to avoid massive hashes. +int getImageHash(Control shape) { + final src = shape.getSrc("src"); + if (src.hasUri) { + return src.uri!.hashCode; + } + if (src.hasBytes) { + return fnv1aHash(src.bytes!); + } + return 0; +} diff --git a/packages/flet/lib/src/controls/card.dart b/packages/flet/lib/src/controls/card.dart index 775acd972c..233ba2ad9f 100644 --- a/packages/flet/lib/src/controls/card.dart +++ b/packages/flet/lib/src/controls/card.dart @@ -2,52 +2,45 @@ import 'package:flutter/material.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; class CardControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const CardControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const CardControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("Card build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - var content = contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) + var contentCtrl = control.child("content"); + var contentWidget = contentCtrl != null + ? ControlWidget( + control: contentCtrl, + ) : null; - var clipBehavior = parseClip(control.attrString("clipBehavior")); - var elevation = control.attrDouble("elevation"); - var shape = parseOutlinedBorder(control, "shape"); - var margin = parseEdgeInsets(control, "margin"); - var isSemanticContainer = control.attrBool("isSemanticContainer", true)!; + var clipBehavior = control.getClipBehavior("clip_behavior"); + var elevation = control.getDouble("elevation"); + var shape = control.getShape("shape", Theme.of(context)); + var margin = control.getMargin("margin"); + var isSemanticContainer = control.getBool("semantic_container", true)!; var showBorderOnForeground = - control.attrBool("showBorderOnForeground", true)!; - var color = control.attrColor("color", context); - var shadowColor = control.attrColor("shadowColor", context); - var surfaceTintColor = control.attrColor("surfaceTintColor", context); + control.getBool("show_border_on_foreground", true)!; + var bgcolor = control.getColor("bgcolor", context); + var shadowColor = control.getColor("shadow_color", context); Widget? card; CardVariant variant = - parseCardVariant(control.attrString("variant"), CardVariant.elevated)!; + control.getCardVariant("variant", CardVariant.elevated)!; if (variant == CardVariant.outlined) { card = Card.outlined( @@ -57,10 +50,9 @@ class CardControl extends StatelessWidget { semanticContainer: isSemanticContainer, borderOnForeground: showBorderOnForeground, clipBehavior: clipBehavior, - color: color, + color: bgcolor, shadowColor: shadowColor, - surfaceTintColor: surfaceTintColor, - child: content); + child: contentWidget); } else if (variant == CardVariant.filled) { card = Card.filled( elevation: elevation, @@ -69,10 +61,9 @@ class CardControl extends StatelessWidget { semanticContainer: isSemanticContainer, borderOnForeground: showBorderOnForeground, clipBehavior: clipBehavior, - color: color, + color: bgcolor, shadowColor: shadowColor, - surfaceTintColor: surfaceTintColor, - child: content); + child: contentWidget); } else { card = Card( elevation: elevation, @@ -81,12 +72,11 @@ class CardControl extends StatelessWidget { semanticContainer: isSemanticContainer, borderOnForeground: showBorderOnForeground, clipBehavior: clipBehavior, - color: color, + color: bgcolor, shadowColor: shadowColor, - surfaceTintColor: surfaceTintColor, - child: content); + child: contentWidget); } - return constrainedControl(context, card, parent, control); + return LayoutControl(control: control, child: card); } } diff --git a/packages/flet/lib/src/controls/charts.dart b/packages/flet/lib/src/controls/charts.dart deleted file mode 100644 index d0cf391495..0000000000 --- a/packages/flet/lib/src/controls/charts.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import '../models/app_state.dart'; -import '../models/control.dart'; - -class ChartAxisLabelViewModel extends Equatable { - final double value; - final Control? control; - - const ChartAxisLabelViewModel({required this.value, required this.control}); - - static ChartAxisLabelViewModel fromStore( - Store store, Control control) { - return ChartAxisLabelViewModel( - value: control.attrDouble("value")!, - control: store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.isVisible) - .firstOrNull); - } - - @override - List get props => [value, control]; -} - -class ChartAxisViewModel extends Equatable { - final Control control; - final Control? title; - final Map labels; - - const ChartAxisViewModel( - {required this.control, required this.title, required this.labels}); - - static ChartAxisViewModel fromStore(Store store, Control control) { - var children = store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.isVisible); - - return ChartAxisViewModel( - control: control, - title: children.where((c) => c.name == "t" && c.isVisible).firstOrNull, - labels: { - for (var e in children - .where((c) => c.name == "l" && c.isVisible) - .map((c) => ChartAxisLabelViewModel.fromStore(store, c)) - .where((c) => c.control != null)) - e.value: e.control! - }); - } - - @override - List get props => [control, title, labels]; -} diff --git a/packages/flet/lib/src/controls/checkbox.dart b/packages/flet/lib/src/controls/checkbox.dart index 2fb6b55a63..aa8a2fc2e9 100644 --- a/packages/flet/lib/src/controls/checkbox.dart +++ b/packages/flet/lib/src/controls/checkbox.dart @@ -1,64 +1,64 @@ -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; import '../utils/colors.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; import '../utils/theme.dart'; -import 'create_control.dart'; -import 'cupertino_checkbox.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; import 'list_tile.dart'; class CheckboxControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - final List children; - - const CheckboxControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.parentAdaptive, - required this.children, - required this.backend}); + + CheckboxControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CheckboxControlState(); } -class _CheckboxControlState extends State with FletStoreMixin { +class _CheckboxControlState extends State { bool? _value; bool _tristate = false; late final FocusNode _focusNode; + Listenable? _tileClicksNotifier; @override void initState() { super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); + _focusNode = FocusNode()..addListener(_onFocusChange); } - void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final newNotifier = ListTileClicks.of(context)?.notifier; + + // If the inherited source changed, swap listeners + if (!identical(_tileClicksNotifier, newNotifier)) { + _tileClicksNotifier?.removeListener(_toggleValue); + _tileClicksNotifier = newNotifier; + _tileClicksNotifier?.addListener(_toggleValue); + } } @override void dispose() { _focusNode.removeListener(_onFocusChange); + _tileClicksNotifier?.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } + void _onFocusChange() { + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + void _toggleValue() { bool? newValue; if (!_tristate) { @@ -72,114 +72,79 @@ class _CheckboxControlState extends State with FletStoreMixin { } void _onChange(bool? value) { - var svalue = value != null ? value.toString() : ""; _value = value; - widget.backend.updateControlState(widget.control.id, {"value": svalue}); - widget.backend.triggerControlEvent(widget.control.id, "change", svalue); + widget.control.updateProperties({"value": value}, notify: true); + widget.control.triggerEvent("change", value); } @override Widget build(BuildContext context) { debugPrint("Checkbox build: ${widget.control.id}"); - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - double? width = widget.control.attrDouble("width"); - double? height = widget.control.attrDouble("height"); - - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoCheckboxControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - backend: widget.backend); - } - var label = widget.children.firstWhereOrNull((c) => c.isVisible); - String labelStr = widget.control.attrString("label", "")!; - LabelPosition labelPosition = parseLabelPosition( - widget.control.attrString("labelPosition"), LabelPosition.right)!; - _tristate = widget.control.attrBool("tristate", false)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool? value = widget.control.attrBool("value", _tristate ? null : false); - if (_value != value) { - _value = value; - } - - TextStyle? labelStyle = - parseTextStyle(Theme.of(context), widget.control, "labelStyle"); - if (disabled && labelStyle != null) { - labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); - } - - var checkbox = Checkbox( - autofocus: autofocus, - focusNode: _focusNode, - value: _value, - isError: widget.control.attrBool("isError", false)!, - semanticLabel: widget.control.attrString("semanticsLabel"), - shape: parseOutlinedBorder(widget.control, "shape"), - side: parseWidgetStateBorderSide( - Theme.of(context), widget.control, "borderSide"), - splashRadius: widget.control.attrDouble("splashRadius"), - activeColor: widget.control.attrColor("activeColor", context), - focusColor: widget.control.attrColor("focusColor", context), - hoverColor: widget.control.attrColor("hoverColor", context), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "overlayColor"), - checkColor: widget.control.attrColor("checkColor", context), - fillColor: parseWidgetStateColor( - Theme.of(context), widget.control, "fillColor"), - tristate: _tristate, - visualDensity: - parseVisualDensity(widget.control.attrString("visualDensity")), - mouseCursor: - parseMouseCursor(widget.control.attrString("mouseCursor")), - onChanged: !disabled - ? (bool? value) { - _onChange(value); - } - : null); - - ListTileClicks.of(context)?.notifier.addListener(() { - _toggleValue(); - }); - - Widget result = checkbox; - if (label != null || (labelStr != "")) { - Widget? labelWidget; - if (label != null) { - labelWidget = - createControl(widget.control, label.id, disabled); - } else { - labelWidget = disabled - ? Text(labelStr, style: labelStyle) - : MouseRegion( - cursor: SystemMouseCursors.click, - child: Text(labelStr, style: labelStyle)); - } - - result = MergeSemantics( - child: GestureDetector( - onTap: !disabled ? _toggleValue : null, - child: labelPosition == LabelPosition.right - ? Row(children: [checkbox, labelWidget]) - : Row(children: [labelWidget, checkbox]))); - } - if (width != null || height != null) { - result = SizedBox( + _tristate = widget.control.getBool("tristate", false)!; + var value = widget.control.getBool("value", _tristate ? null : false); + if (_value != value) { + _value = value; + } + + var checkbox = Checkbox( + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + value: _value, + isError: widget.control.getBool("error", false)!, + semanticLabel: widget.control.getString("semantics_label"), + shape: widget.control.getShape("shape", Theme.of(context)), + side: widget.control + .getWidgetStateBorderSide("border_side", Theme.of(context)), + splashRadius: widget.control.getDouble("splash_radius"), + activeColor: widget.control.getColor("active_color", context), + focusColor: widget.control.getColor("focus_color", context), + hoverColor: widget.control.getColor("hover_color", context), + overlayColor: widget.control + .getWidgetStateColor("overlay_color", Theme.of(context)), + checkColor: widget.control.getColor("check_color", context), + fillColor: + widget.control.getWidgetStateColor("fill_color", Theme.of(context)), + tristate: _tristate, + visualDensity: widget.control.getVisualDensity("visual_density"), + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + onChanged: !widget.control.disabled + ? (bool? value) => _onChange(value) + : null); + + Widget result = checkbox; + + var labelStyle = + widget.control.getTextStyle("label_style", Theme.of(context)); + if (widget.control.disabled && labelStyle != null) { + labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); + } + var label = + widget.control.buildTextOrWidget("label", textStyle: labelStyle); + if (label != null) { + label = widget.control.disabled + ? label + : MouseRegion(cursor: SystemMouseCursors.click, child: label); + var labelPosition = widget.control + .getLabelPosition("label_position", LabelPosition.right)!; + result = MergeSemantics( + child: GestureDetector( + onTap: !widget.control.disabled ? _toggleValue : null, + child: labelPosition == LabelPosition.right + ? Row(children: [checkbox, label]) + : Row(children: [label, checkbox]))); + } + + // Apply width and height if provided + var width = widget.control.getDouble("width"); + var height = widget.control.getDouble("height"); + if (width != null || height != null) { + result = SizedBox( width: width, height: height, - child: FittedBox( - fit: BoxFit.fill, - child: result, - ), - ); - } - - return constrainedControl(context, result, widget.parent, widget.control); - }); + child: FittedBox(fit: BoxFit.fill, child: result)); + } + + return LayoutControl(control: widget.control, child: result); } } diff --git a/packages/flet/lib/src/controls/chip.dart b/packages/flet/lib/src/controls/chip.dart index 7fe0b7cbd5..b460cb731c 100644 --- a/packages/flet/lib/src/controls/chip.dart +++ b/packages/flet/lib/src/controls/chip.dart @@ -1,34 +1,25 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/animations.dart'; import '../utils/borders.dart'; import '../utils/box.dart'; import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/mouse.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; import '../utils/theme.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class ChipControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const ChipControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + ChipControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _ChipControlState(); @@ -36,7 +27,6 @@ class ChipControl extends StatefulWidget { class _ChipControlState extends State { bool _selected = false; - late final FocusNode _focusNode; @override @@ -53,129 +43,99 @@ class _ChipControlState extends State { super.dispose(); } - void _onSelect(bool selected) { - var strSelected = selected.toString(); - debugPrint(strSelected); - _selected = selected; - widget.backend - .updateControlState(widget.control.id, {"selected": strSelected}); - widget.backend - .triggerControlEvent(widget.control.id, "select", strSelected); - } - void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @override Widget build(BuildContext context) { debugPrint("Chip build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; + bool disabled = widget.control.disabled; - var labelCtrls = - widget.children.where((c) => c.name == "label" && c.isVisible); - if (labelCtrls.isEmpty) { + var label = widget.control.buildTextOrWidget("label"); + if (label == null) { return const ErrorControl("Chip.label must be provided and visible"); } - var leadingCtrls = - widget.children.where((c) => c.name == "leading" && c.isVisible); - var deleteIconCtrls = - widget.children.where((c) => c.name == "deleteIcon" && c.isVisible); - - var onClick = widget.control.attrBool("onclick", false)!; - var onDelete = widget.control.attrBool("onDelete", false)!; - var onSelect = widget.control.attrBool("onSelect", false)!; + var onClick = widget.control.getBool("on_click", false)!; + var onDelete = widget.control.getBool("on_delete", false)!; + var onSelect = widget.control.getBool("on_select", false)!; if (onSelect && onClick) { return const ErrorControl( "Chip cannot have both on_select and on_click events specified"); } - bool selected = widget.control.attrBool("selected", false)!; + bool selected = widget.control.getBool("selected", false)!; if (_selected != selected) { _selected = selected; } - return constrainedControl( - context, - InputChip( - autofocus: widget.control.attrBool("autofocus", false)!, - focusNode: _focusNode, - label: createControl(widget.control, labelCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive), - avatar: leadingCtrls.isNotEmpty - ? createControl(widget.control, leadingCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - backgroundColor: widget.control.attrColor("bgcolor", context), - checkmarkColor: widget.control.attrColor("checkColor", context), - selected: _selected, - showCheckmark: widget.control.attrBool("showCheckmark", true)!, - deleteButtonTooltipMessage: - widget.control.attrString("deleteButtonTooltip"), - deleteIcon: deleteIconCtrls.isNotEmpty - ? createControl( - widget.control, deleteIconCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - deleteIconColor: widget.control.attrColor("deleteIconColor", context), - disabledColor: widget.control.attrColor("disabledColor", context), - elevation: widget.control.attrDouble("elevation"), - isEnabled: !disabled, - padding: parseEdgeInsets(widget.control, "padding"), - labelPadding: parseEdgeInsets(widget.control, "labelPadding"), - labelStyle: - parseTextStyle(Theme.of(context), widget.control, "labelStyle"), - selectedColor: widget.control.attrColor("selectedColor", context), - selectedShadowColor: - widget.control.attrColor("selectedShadowColor", context), - shadowColor: widget.control.attrColor("shadowColor", context), - shape: parseOutlinedBorder(widget.control, "shape"), - color: - parseWidgetStateColor(Theme.of(context), widget.control, "color"), - surfaceTintColor: - widget.control.attrColor("surfaceTintColor", context), - pressElevation: widget.control.attrDouble("clickElevation"), - side: - parseBorderSide(Theme.of(context), widget.control, "borderSide"), - clipBehavior: - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!, - visualDensity: - parseVisualDensity(widget.control.attrString("visualDensity")), - avatarBoxConstraints: - parseBoxConstraints(widget.control, "leadingSizeConstraints"), - deleteIconBoxConstraints: - parseBoxConstraints(widget.control, "deleteIconSizeConstraints"), - chipAnimationStyle: ChipAnimationStyle( - enableAnimation: - parseAnimationStyle(widget.control, "enableAnimationStyle"), - selectAnimation: - parseAnimationStyle(widget.control, "selectAnimationStyle"), - avatarDrawerAnimation: parseAnimationStyle( - widget.control, "leadingDrawerAnimationStyle"), - deleteDrawerAnimation: parseAnimationStyle( - widget.control, "deleteDrawerAnimationStyle"), - ), - onPressed: onClick && !disabled - ? () { - widget.backend - .triggerControlEvent(widget.control.id, "click"); - } - : null, - onDeleted: onDelete && !disabled - ? () { - widget.backend - .triggerControlEvent(widget.control.id, "delete"); - } - : null, - onSelected: onSelect && !disabled - ? (bool selected) { - _onSelect(selected); - } - : null, - ), - widget.parent, - widget.control); + final chip = InputChip( + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + label: label, + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + avatar: widget.control.buildWidget("leading"), + backgroundColor: widget.control.getColor("bgcolor", context), + checkmarkColor: widget.control.getColor("check_color", context), + selected: _selected, + showCheckmark: widget.control.getBool("show_checkmark", true)!, + deleteButtonTooltipMessage: + widget.control.getString("delete_button_tooltip"), + deleteIcon: widget.control.buildWidget("delete_icon"), + deleteIconColor: widget.control.getColor("delete_icon_color", context), + disabledColor: widget.control.getColor("disabled_color", context), + elevation: widget.control.getDouble("elevation"), + isEnabled: !disabled, + padding: widget.control.getPadding("padding"), + labelPadding: widget.control.getPadding("label_padding"), + labelStyle: + widget.control.getTextStyle("label_text_style", Theme.of(context)), + selectedColor: widget.control.getColor("selected_color", context), + selectedShadowColor: + widget.control.getColor("selected_shadow_color", context), + shadowColor: widget.control.getColor("shadow_color", context), + shape: widget.control.getShape("shape", Theme.of(context)), + color: widget.control.getWidgetStateColor("color", Theme.of(context)), + pressElevation: widget.control.getDouble("elevation_on_click"), + side: widget.control.getBorderSide("border_side", Theme.of(context)), + clipBehavior: + parseClip(widget.control.getString("clip_behavior"), Clip.none)!, + visualDensity: widget.control.getVisualDensity("visual_density"), + avatarBoxConstraints: + widget.control.getBoxConstraints("leading_size_constraints"), + deleteIconBoxConstraints: parseBoxConstraints( + widget.control.get("delete_icon_size_constraints")), + chipAnimationStyle: ChipAnimationStyle( + enableAnimation: + widget.control.getAnimationStyle("enable_animation_style"), + selectAnimation: + widget.control.getAnimationStyle("select_animation_style"), + avatarDrawerAnimation: parseAnimationStyle( + widget.control.get("leading_drawer_animation_style")), + deleteDrawerAnimation: parseAnimationStyle( + widget.control.get("delete_drawer_animation_style")), + ), + onPressed: onClick && !disabled + ? () { + widget.control.triggerEvent("click"); + } + : null, + onDeleted: onDelete && !disabled + ? () { + widget.control.triggerEvent("delete"); + } + : null, + onSelected: onSelect && !disabled + ? (bool selected) { + _selected = selected; + widget.control + .updateProperties({"selected": selected}, notify: true); + widget.control.triggerEvent("select", selected); + } + : null, + ); + + return LayoutControl(control: widget.control, child: chip); } } diff --git a/packages/flet/lib/src/controls/circle_avatar.dart b/packages/flet/lib/src/controls/circle_avatar.dart index 8dd1e25aea..0d4a1d36c9 100644 --- a/packages/flet/lib/src/controls/circle_avatar.dart +++ b/packages/flet/lib/src/controls/circle_avatar.dart @@ -1,92 +1,49 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/images.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; -class CircleAvatarControl extends StatelessWidget with FletStoreMixin { - final Control? parent; +class CircleAvatarControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - const CircleAvatarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); + const CircleAvatarControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("CircleAvatar build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - return withPageArgs((context, pageArgs) { - var foregroundImageSrc = control.attrString("foregroundImageSrc"); - var backgroundImageSrc = control.attrString("backgroundImageSrc"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - - ImageProvider? backgroundImage; - ImageProvider? foregroundImage; - - if (foregroundImageSrc != null || backgroundImageSrc != null) { - var assetSrc = getAssetSrc((foregroundImageSrc ?? backgroundImageSrc)!, - pageArgs.pageUri!, pageArgs.assetsDir); - - // foregroundImage - if (foregroundImageSrc != null) { - if (assetSrc.isFile) { - // from File - foregroundImage = AssetImage(assetSrc.path); - } else { - // URL - foregroundImage = NetworkImage(assetSrc.path); - } - } - - // backgroundImage - if (backgroundImageSrc != null) { - if (assetSrc.isFile) { - // from File - backgroundImage = AssetImage(assetSrc.path); - } else { - // URL - backgroundImage = NetworkImage(assetSrc.path); - } - } - } - - var avatar = CircleAvatar( - foregroundImage: foregroundImage, - backgroundImage: backgroundImage, - backgroundColor: control.attrColor("bgColor", context), - foregroundColor: control.attrColor("color", context), - radius: control.attrDouble("radius"), - minRadius: control.attrDouble("minRadius"), - maxRadius: control.attrDouble("maxRadius"), - onBackgroundImageError: backgroundImage != null - ? (object, trace) { - backend.triggerControlEvent( - control.id, "imageError", "background"); - } - : null, - onForegroundImageError: foregroundImage != null - ? (object, trace) { - backend.triggerControlEvent( - control.id, "imageError", "foreground"); - } - : null, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled) - : null); - - return constrainedControl(context, avatar, parent, control); - }); + var foregroundImage = + control.getImageProvider("foreground_image_src", context); + var backgroundImage = + control.getImageProvider("background_image_src", context); + + var avatar = CircleAvatar( + foregroundImage: foregroundImage, + backgroundImage: backgroundImage, + backgroundColor: control.getColor("bgcolor", context), + foregroundColor: control.getColor("color", context), + radius: control.getDouble("radius"), + minRadius: control.getDouble("min_radius"), + maxRadius: control.getDouble("max_radius"), + onBackgroundImageError: backgroundImage != null + ? (object, trace) { + control.triggerEvent("image_error", "background"); + } + : null, + onForegroundImageError: foregroundImage != null + ? (object, trace) { + control.triggerEvent("image_error", "foreground"); + } + : null, + child: control.buildTextOrWidget("content")); + + return LayoutControl(control: control, child: avatar); } } diff --git a/packages/flet/lib/src/controls/column.dart b/packages/flet/lib/src/controls/column.dart index ae7ca106fa..137ac6e800 100644 --- a/packages/flet/lib/src/controls/column.dart +++ b/packages/flet/lib/src/controls/column.dart @@ -1,53 +1,41 @@ import 'package:flutter/widgets.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; import 'scroll_notification_control.dart'; import 'scrollable_control.dart'; class ColumnControl extends StatelessWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - final FletControlBackend backend; - const ColumnControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const ColumnControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("Column build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - var spacing = control.attrDouble("spacing", 10)!; - var alignment = control.attrString("alignment"); - var tight = control.attrBool("tight", false)!; - var wrap = control.attrBool("wrap", false)!; - var horizontalAlignment = control.attrString("horizontalAlignment"); - - List controls = children.where((c) => c.isVisible).map((c) { - return createControl(control, c.id, disabled, parentAdaptive: adaptive); - }).toList(); + var spacing = control.getDouble("spacing", 10)!; + var alignment = control.getString("alignment"); + var tight = control.getBool("tight", false)!; + var wrap = control.getBool("wrap", false)!; + var horizontalAlignment = control.getString("horizontal_alignment"); + var intrinsicWidth = control.getBool("intrinsic_width", false)!; + var controls = control.buildWidgets("controls"); Widget child = wrap ? Wrap( direction: Axis.vertical, spacing: spacing, - runSpacing: control.attrDouble("runSpacing", 10)!, + runSpacing: control.getDouble("run_spacing", 10)!, alignment: parseWrapAlignment(alignment, WrapAlignment.start)!, runAlignment: parseWrapAlignment( - control.attrString("runAlignment"), WrapAlignment.start)!, + control.getString("run_alignment"), WrapAlignment.start)!, crossAxisAlignment: parseWrapCrossAlignment( horizontalAlignment, WrapCrossAlignment.start)!, children: controls, @@ -62,19 +50,21 @@ class ColumnControl extends StatelessWidget { children: controls, ); + if (intrinsicWidth) { + child = IntrinsicWidth(child: child); + } + child = ScrollableControl( control: control, scrollDirection: wrap ? Axis.horizontal : Axis.vertical, - backend: backend, - parentAdaptive: adaptive, + wrapIntoScrollableView: true, child: child, ); - if (control.attrBool("onScroll", false)!) { - child = ScrollNotificationControl( - control: control, backend: backend, child: child); + if (control.getBool("on_scroll", false)!) { + child = ScrollNotificationControl(control: control, child: child); } - return constrainedControl(context, child, parent, control); + return LayoutControl(control: control, child: child); } } diff --git a/packages/flet/lib/src/controls/container.dart b/packages/flet/lib/src/controls/container.dart index ffde07f334..6044b9cf8d 100644 --- a/packages/flet/lib/src/controls/container.dart +++ b/packages/flet/lib/src/controls/container.dart @@ -1,294 +1,220 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; import '../utils/animations.dart'; import '../utils/borders.dart'; import '../utils/box.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; +import '../utils/events.dart'; import '../utils/gradient.dart'; import '../utils/images.dart'; import '../utils/launch_url.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; - -class ContainerTapEvent { - final double localX; - final double localY; - final double globalX; - final double globalY; - - ContainerTapEvent( - {required this.localX, - required this.localY, - required this.globalX, - required this.globalY}); - - Map toJson() => { - 'lx': localX, - 'ly': localY, - 'gx': globalX, - 'gy': globalY - }; -} +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; class ContainerControl extends StatelessWidget with FletStoreMixin { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const ContainerControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const ContainerControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("Container build: ${control.id}"); - var bgColor = control.attrColor("bgColor", context); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool ink = control.attrBool("ink", false)!; - bool onClick = control.attrBool("onclick", false)!; - bool onTapDown = control.attrBool("onTapDown", false)!; - String url = control.attrString("url", "")!; - String? urlTarget = control.attrString("urlTarget"); - bool onLongPress = control.attrBool("onLongPress", false)!; - bool onHover = control.attrBool("onHover", false)!; - bool ignoreInteractions = control.attrBool("ignoreInteractions", false)!; - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - Widget? child = contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) + var bgColor = control.getColor("bgcolor", context); + var content = control.buildWidget("content"); + var ink = control.getBool("ink", false)!; + var onClick = control.getBool("on_click", false)!; + var onTapDown = control.getBool("on_tap_down", false)!; + var url = control.getUrl("url"); + var onLongPress = control.getBool("on_long_press", false)!; + var onHover = control.getBool("on_hover", false)!; + var ignoreInteractions = control.getBool("ignore_interactions", false)!; + var animation = control.getAnimation("animate"); + var blur = control.getBlur("blur"); + var colorFilter = control.getColorFilter("color_filter", Theme.of(context)); + var width = control.getDouble("width"); + var height = control.getDouble("height"); + var padding = control.getPadding("padding"); + var margin = control.getMargin("margin"); + var alignment = control.getAlignment("alignment"); + var borderRadius = control.getBorderRadius("border_radius"); + var clipBehavior = control.getClipBehavior( + "clip_behavior", borderRadius != null ? Clip.antiAlias : Clip.none)!; + var decorationImage = control.getDecorationImage("image", context); + var boxDecoration = boxDecorationFromDetails( + shape: control.getBoxShape("shape", BoxShape.rectangle)!, + color: bgColor, + gradient: parseGradient(control.get("gradient"), Theme.of(context)), + borderRadius: borderRadius, + border: control.getBorder("border", Theme.of(context), + defaultSideColor: Colors.black), + boxShadow: control.getBoxShadows("shadow", Theme.of(context)), + blendMode: control.getBlendMode("blend_mode"), + image: decorationImage, + ); + var boxForegroundDecoration = + parseBoxDecoration(control.get("foreground_decoration"), context); + Widget? container; + + var onAnimationEnd = control.getBool("on_animation_end", false)! + ? () => control.triggerEvent("animation_end", "container") : null; - - var animation = parseAnimation(control, "animate"); - var blur = parseBlur(control, "blur"); - var colorFilter = - parseColorFilter(control, "colorFilter", Theme.of(context)); - var width = control.attrDouble("width"); - var height = control.attrDouble("height"); - var padding = parseEdgeInsets(control, "padding"); - var margin = parseEdgeInsets(control, "margin"); - var alignment = parseAlignment(control, "alignment"); - - return withPageArgs((context, pageArgs) { - var borderRadius = parseBorderRadius(control, "borderRadius"); - var clipBehavior = parseClip(control.attrString("clipBehavior"), - borderRadius != null ? Clip.antiAlias : Clip.none)!; - var decorationImage = - parseDecorationImage(Theme.of(context), control, "image", pageArgs); - var boxDecoration = boxDecorationFromDetails( - shape: parseBoxShape(control.attrString("shape"), BoxShape.rectangle)!, - color: bgColor, - gradient: parseGradient(Theme.of(context), control, "gradient"), - borderRadius: borderRadius, - border: parseBorder(Theme.of(context), control, "border", - Theme.of(context).colorScheme.primary), - boxShadow: parseBoxShadow(Theme.of(context), control, "shadow"), - blendMode: parseBlendMode(control.attrString("blendMode")), - image: decorationImage, - ); - var boxForegroundDecoration = parseBoxDecoration( - Theme.of(context), control, "foregroundDecoration", pageArgs); - Widget? result; - - var onAnimationEnd = control.attrBool("onAnimationEnd", false)! - ? () { - backend.triggerControlEvent( - control.id, "animation_end", "container"); - } - : null; - if ((onClick || url != "" || onLongPress || onHover || onTapDown) && - ink && - !disabled) { - var ink = Material( - color: Colors.transparent, - borderRadius: boxDecoration!.borderRadius, - child: InkWell( - // Dummy callback to enable widget - // see https://github.com/flutter/flutter/issues/50116#issuecomment-582047374 - // and https://github.com/flutter/flutter/blob/eed80afe2c641fb14b82a22279d2d78c19661787/packages/flutter/lib/src/material/ink_well.dart#L1125-L1129 - onTap: onClick || url != "" || onTapDown - ? () { - debugPrint("Container ${control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - if (onClick) { - backend.triggerControlEvent(control.id, "click"); - } + if ((onClick || url != null || onLongPress || onHover || onTapDown) && + ink && + !control.disabled) { + var ink = Material( + color: Colors.transparent, + borderRadius: boxDecoration!.borderRadius, + child: InkWell( + // Dummy callback to enable widget + // see https://github.com/flutter/flutter/issues/50116#issuecomment-582047374 + // and https://github.com/flutter/flutter/blob/eed80afe2c641fb14b82a22279d2d78c19661787/packages/flutter/lib/src/material/ink_well.dart#L1125-L1129 + onTap: onClick || url != null || onTapDown + ? () { + if (url != null) { + openWebBrowser(url); } - : null, - onTapDown: onTapDown - ? (details) { - backend.triggerControlEvent( - control.id, - "tap_down", - json.encode(ContainerTapEvent( - localX: details.localPosition.dx, - localY: details.localPosition.dy, - globalX: details.globalPosition.dx, - globalY: details.globalPosition.dy) - .toJson())); + if (onClick) { + control.triggerEvent("click"); } - : null, - onLongPress: onLongPress - ? () { - debugPrint("Container ${control.id} long pressed!"); - backend.triggerControlEvent(control.id, "long_press"); - } - : null, - onHover: onHover - ? (value) { - debugPrint("Container ${control.id} hovered!"); - backend.triggerControlEvent( - control.id, "hover", value.toString()); - } - : null, - borderRadius: borderRadius, - splashColor: control.attrColor("inkColor", context), - child: Container( - padding: padding, - alignment: alignment, - clipBehavior: Clip.none, - child: child, - ), - )); - - result = animation == null - ? Container( - width: width, - height: height, - margin: margin, - clipBehavior: clipBehavior, - decoration: boxDecoration, - foregroundDecoration: boxForegroundDecoration, - child: ink, - ) - : AnimatedContainer( - duration: animation.duration, - curve: animation.curve, - width: width, - height: height, - margin: margin, - decoration: boxDecoration, - foregroundDecoration: boxForegroundDecoration, - clipBehavior: clipBehavior, - onEnd: onAnimationEnd, - child: ink); - } else { - result = animation == null - ? Container( - width: width, - height: height, - margin: margin, - padding: padding, - alignment: alignment, - decoration: boxDecoration, - foregroundDecoration: boxForegroundDecoration, - clipBehavior: clipBehavior, - child: child) - : AnimatedContainer( - duration: animation.duration, - curve: animation.curve, - width: width, - height: height, - margin: margin, - padding: padding, - alignment: alignment, - decoration: boxDecoration, - foregroundDecoration: boxForegroundDecoration, - clipBehavior: clipBehavior, - onEnd: onAnimationEnd, - child: child); - - if ((onClick || onLongPress || onHover || onTapDown || url != "") && - !disabled) { - result = MouseRegion( - cursor: onClick || onTapDown || url != "" - ? SystemMouseCursors.click - : MouseCursor.defer, - onEnter: onHover - ? (value) { - debugPrint( - "Container's mouse region ${control.id} entered!"); - backend.triggerControlEvent(control.id, "hover", "true"); } : null, - onExit: onHover - ? (value) { - debugPrint( - "Container's mouse region ${control.id} exited!"); - backend.triggerControlEvent(control.id, "hover", "false"); + onTapDown: onTapDown + ? (TapDownDetails details) { + control.triggerEvent("tap_down", details.toMap()); } : null, - child: GestureDetector( - onTap: onClick || url != "" - ? () { - debugPrint("Container ${control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - if (onClick) { - backend.triggerControlEvent(control.id, "click"); - } - } - : null, - onTapDown: onTapDown - ? (details) { - backend.triggerControlEvent( - control.id, - "tap_down", - json.encode(ContainerTapEvent( - localX: details.localPosition.dx, - localY: details.localPosition.dy, - globalX: details.globalPosition.dx, - globalY: details.globalPosition.dy) - .toJson())); + onLongPress: + onLongPress ? () => control.triggerEvent("long_press") : null, + onHover: onHover + ? (value) => control.triggerEvent("hover", value) + : null, + borderRadius: borderRadius, + splashColor: control.getColor("ink_color", context), + child: Container( + padding: padding, + alignment: alignment, + clipBehavior: Clip.none, + child: content, + ), + )); + + container = animation == null + ? Container( + width: width, + height: height, + margin: margin, + clipBehavior: clipBehavior, + decoration: boxDecoration, + foregroundDecoration: boxForegroundDecoration, + child: ink, + ) + : AnimatedContainer( + duration: animation.duration, + curve: animation.curve, + width: width, + height: height, + margin: margin, + alignment: alignment, + padding: padding, + decoration: boxDecoration, + foregroundDecoration: boxForegroundDecoration, + clipBehavior: clipBehavior, + onEnd: onAnimationEnd, + child: ink); + } else { + container = animation == null + ? Container( + width: width, + height: height, + margin: margin, + padding: padding, + alignment: alignment, + decoration: boxDecoration, + foregroundDecoration: boxForegroundDecoration, + clipBehavior: clipBehavior, + child: content) + : AnimatedContainer( + duration: animation.duration, + curve: animation.curve, + width: width, + height: height, + margin: margin, + padding: padding, + alignment: alignment, + decoration: boxDecoration, + foregroundDecoration: boxForegroundDecoration, + clipBehavior: clipBehavior, + onEnd: onAnimationEnd, + child: content); + + if ((onClick || onLongPress || onHover || onTapDown || url != null) && + !control.disabled) { + container = MouseRegion( + cursor: onClick || onTapDown || url != null + ? SystemMouseCursors.click + : MouseCursor.defer, + onEnter: onHover + ? (value) { + control.triggerEvent("hover", true); + } + : null, + onExit: onHover + ? (value) { + control.triggerEvent("hover", false); + } + : null, + child: GestureDetector( + onTap: onClick || url != null + ? () { + if (url != null) { + openWebBrowser(url); } - : null, - onLongPress: onLongPress - ? () { - debugPrint("Container ${control.id} clicked!"); - backend.triggerControlEvent(control.id, "long_press"); + if (onClick) { + control.triggerEvent("click"); } - : null, - child: result, - ), - ); - } - } - - if (blur != null) { - result = borderRadius != null - ? ClipRRect( - borderRadius: borderRadius, - child: BackdropFilter(filter: blur, child: result)) - : ClipRect(child: BackdropFilter(filter: blur, child: result)); - } - if (colorFilter != null) { - result = ColorFiltered(colorFilter: colorFilter, child: result); - } - - if (ignoreInteractions) { - result = IgnorePointer(child: result); + } + : null, + onTapDown: onTapDown + ? (TapDownDetails details) { + control.triggerEvent("tap_down", details.toMap()); + } + : null, + onLongPress: onLongPress + ? () { + control.triggerEvent("long_press"); + } + : null, + child: container, + ), + ); } + } - return constrainedControl(context, result, parent, control); - }); + if (blur != null) { + container = borderRadius != null + ? ClipRRect( + borderRadius: borderRadius, + child: BackdropFilter(filter: blur, child: container)) + : ClipRect(child: BackdropFilter(filter: blur, child: container)); + } + if (colorFilter != null) { + container = ColorFiltered(colorFilter: colorFilter, child: container); + } + + if (ignoreInteractions) { + container = IgnorePointer(child: container); + } + + return LayoutControl(control: control, child: container); } } diff --git a/packages/flet/lib/src/controls/context_menu.dart b/packages/flet/lib/src/controls/context_menu.dart new file mode 100644 index 0000000000..4755ed1394 --- /dev/null +++ b/packages/flet/lib/src/controls/context_menu.dart @@ -0,0 +1,308 @@ +import 'dart:async'; +import '../utils/enums.dart'; + +import 'package:collection/collection.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/numbers.dart'; +import '../utils/popup_menu.dart'; +import '../utils/transforms.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; + +class ContextMenuControl extends StatefulWidget { + final Control control; + + const ContextMenuControl({super.key, required this.control}); + + @override + State createState() => _ContextMenuControlState(); +} + +class _ContextMenuControlState extends State { + ContextMenuTrigger _primaryTrigger = ContextMenuTrigger.disabled; + ContextMenuTrigger _secondaryTrigger = ContextMenuTrigger.down; + ContextMenuTrigger _tertiaryTrigger = ContextMenuTrigger.down; + + Future? _pendingMenu; + + @override + void initState() { + super.initState(); + // Allow backend code to invoke methods on this control instance. + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("ContextMenu build: ${widget.control.id}"); + + var content = widget.control.buildWidget("content"); + if (content == null) { + return const ErrorControl("ContextMenu.content must be visible"); + } + + _primaryTrigger = parseContextMenuTrigger( + widget.control.getString("primary_trigger"), + ContextMenuTrigger.disabled)!; + _secondaryTrigger = parseContextMenuTrigger( + widget.control.getString("secondary_trigger"), + ContextMenuTrigger.down)!; + _tertiaryTrigger = parseContextMenuTrigger( + widget.control.getString("tertiary_trigger"), ContextMenuTrigger.down)!; + + Widget result = GestureDetector( + behavior: HitTestBehavior.deferToChild, + onLongPressStart: _primaryTrigger == ContextMenuTrigger.longPress + ? (LongPressStartDetails details) => _handleLongPress( + _MouseButton.primary, + details.globalPosition, + details.localPosition, + ) + : null, + onSecondaryLongPressStart: + _secondaryTrigger == ContextMenuTrigger.longPress + ? (LongPressStartDetails details) => _handleLongPress( + _MouseButton.secondary, + details.globalPosition, + details.localPosition, + ) + : null, + onTertiaryLongPressStart: _tertiaryTrigger == ContextMenuTrigger.longPress + ? (LongPressStartDetails details) => _handleLongPress( + _MouseButton.tertiary, + details.globalPosition, + details.localPosition, + ) + : null, + child: Listener( + behavior: HitTestBehavior.translucent, + onPointerDown: _handlePointerDown, + child: content, + ), + ); + + return LayoutControl(control: widget.control, child: result); + } + + /// Handles pointer down events to determine if a context menu should be shown. + /// Only responds to mouse events and triggers the menu if the configured trigger is `down`. + void _handlePointerDown(PointerDownEvent event) { + if (event.kind != PointerDeviceKind.mouse) return; + + final button = _mouseButtonFromEvent(event.buttons); + if (button == null) return; + + final trigger = _getTriggerFromButton(button); + if (trigger != ContextMenuTrigger.down) return; + + _showMenu( + button: button, + globalPosition: event.position, + localPosition: event.localPosition, + ); + } + + void _handleLongPress( + _MouseButton button, Offset globalPosition, Offset localPosition) { + final trigger = _getTriggerFromButton(button); + if (trigger != ContextMenuTrigger.longPress) return; + + _showMenu( + button: button, + globalPosition: globalPosition, + localPosition: localPosition, + ); + } + + ContextMenuTrigger? _getTriggerFromButton(_MouseButton? button) { + switch (button) { + case _MouseButton.primary: + return _primaryTrigger; + case _MouseButton.secondary: + return _secondaryTrigger; + case _MouseButton.tertiary: + return _tertiaryTrigger; + default: + return null; + } + } + + /// Returns the corresponding [_MouseButton] based on the + /// given button bitmask, and `null` if no recognized button is pressed. + _MouseButton? _mouseButtonFromEvent(int buttons) { + if ((buttons & kPrimaryButton) != 0) { + return _MouseButton.primary; + } else if ((buttons & kSecondaryMouseButton) != 0) { + return _MouseButton.secondary; + } else if ((buttons & kTertiaryButton) != 0) { + return _MouseButton.tertiary; + } + return null; + } + + /// Picks popup menu items configured for the provided button, falling back + /// to the shared `items` collection when a button-specific list is empty. + List _getPopupItemsFromButton(_MouseButton? button) { + switch (button) { + case _MouseButton.primary: + return widget.control.children("primary_items"); + case _MouseButton.secondary: + return widget.control.children("secondary_items"); + case _MouseButton.tertiary: + return widget.control.children("tertiary_items"); + default: + return widget.control.children("items"); + } + } + + /// Serialises menu event data to a compact payload sent to Python handlers. + Map _eventPayload( + _MouseButton? button, Offset globalPosition, Offset? localPosition, + {int? itemId, int? itemIndex, int? itemCount}) { + return { + "b": button?.name, + "tr": _getTriggerFromButton(button)?.name, + "id": itemId, + "idx": itemIndex, + "ic": itemCount, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "l": localPosition != null + ? {"x": localPosition.dx, "y": localPosition.dy} + : null, + }; + } + + /// Opens the context menu for a specific button at the requested position. + Future _showMenu( + {required Offset globalPosition, + Offset? localPosition, + _MouseButton? button}) async { + // If a menu is already open, close it and wait for it to finish. + if (_pendingMenu != null) { + Navigator.of(context).pop(); + await _pendingMenu; + if (!mounted) return; + } + + // Get the overlay state and its render box for positioning the menu. + final overlayState = Overlay.of(context, rootOverlay: true); + final overlayRenderBox = + overlayState.context.findRenderObject() as RenderBox?; + if (overlayRenderBox == null || !overlayRenderBox.hasSize) return; + + // Calculate the position for the popup menu relative to the overlay. + final overlayOffset = overlayRenderBox.globalToLocal(globalPosition); + final position = RelativeRect.fromLTRB( + overlayOffset.dx, + overlayOffset.dy, + overlayRenderBox.size.width - overlayOffset.dx, + overlayRenderBox.size.height - overlayOffset.dy, + ); + + // Build popup menu entries. + final popupItems = _getPopupItemsFromButton(button).toList(growable: false); + final entries = buildPopupMenuEntries(popupItems, context); + + // Prepare event payload for menu events. + final basePayload = _eventPayload(button, globalPosition, localPosition, + itemCount: entries.length); + + // If there are no menu entries, send dismiss event. + if (entries.isEmpty) { + widget.control.triggerEvent("dismiss", basePayload); + return; + } + + // Show the popup menu and wait for user selection. + final menuFuture = showMenu( + context: context, + position: position, + items: entries, + ); + _pendingMenu = menuFuture; + final selection = await menuFuture; + + if (!mounted) return; + _pendingMenu = null; + + // Handle the user's selection or dismissal. + if (selection != null) { + final selectedControl = popupItems + .firstWhereOrNull((item) => item.id.toString() == selection); + widget.control.triggerEvent( + "select", + _eventPayload( + button, + globalPosition, + localPosition, + itemId: parseInt(selection), + itemCount: popupItems.length, + itemIndex: selectedControl != null + ? popupItems.indexOf(selectedControl) + : null, + )); + } else { + widget.control.triggerEvent( + "dismiss", + _eventPayload( + button, + globalPosition, + localPosition, + itemCount: popupItems.length, + )); + } + } + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "open": + // Get the render box for positioning the context menu. + final renderBox = context.findRenderObject() as RenderBox?; + if (renderBox == null || !renderBox.hasSize) { + throw StateError( + "ContextMenu render box is not ready to display a menu."); + } + + var globalPosition = parseOffset(args["global_position"]); + var localPosition = parseOffset(args["local_position"]); + + // If only local position is provided, obtain global position from it. + if (globalPosition == null && localPosition != null) { + globalPosition = renderBox.localToGlobal(localPosition); + } + // If only global position is provided, obtain local position from it. + else if (globalPosition != null && localPosition == null) { + localPosition = renderBox.globalToLocal(globalPosition); + } + + // Default to center of the render box if positions are missing. + localPosition ??= renderBox.size.center(Offset.zero); + globalPosition ??= renderBox.localToGlobal(localPosition); + + // Show the context menu at the calculated position. + _showMenu(globalPosition: globalPosition, localPosition: localPosition); + return null; + default: + throw ArgumentError("Unsupported method: $name"); + } + } +} + +enum _MouseButton { primary, secondary, tertiary } + +enum ContextMenuTrigger { disabled, down, longPress } + +ContextMenuTrigger? parseContextMenuTrigger(String? value, + [ContextMenuTrigger? defaultValue]) { + return parseEnum(ContextMenuTrigger.values, value, defaultValue); +} diff --git a/packages/flet/lib/src/controls/control_widget.dart b/packages/flet/lib/src/controls/control_widget.dart new file mode 100644 index 0000000000..ae4db35a96 --- /dev/null +++ b/packages/flet/lib/src/controls/control_widget.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +import '../flet_backend.dart'; +import '../models/control.dart'; +import '../utils/keys.dart'; +import '../widgets/control_inherited_notifier.dart'; +import '../widgets/error.dart'; + +/// Builds the Flutter [Widget] for a [Control]. +/// +/// Responsibilities: +/// - Resolves a stable Flutter [Key] from the control's `key` property (including +/// registering a scroll [GlobalKey] with the backend). +/// - Delegates widget creation to registered extensions. +/// - Builds the result in this control's standard "control context": +/// [ControlInheritedNotifier] (reactivity) and per-control theme overrides. +class ControlWidget extends StatelessWidget { + final Control control; + + const ControlWidget({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + ControlKey? controlKey = control.getKey("key"); + Key? key; + if (controlKey is ControlScrollKey) { + // A scroll key needs to be a GlobalKey so the backend can access state. + key = GlobalKey(); + FletBackend.of(context).globalKeys[controlKey.toString()] = + key as GlobalKey; + } else if (controlKey != null) { + key = ValueKey(controlKey.value); + } + + return control.buildInControlContext((context) { + for (var extension in FletBackend.of(context).extensions) { + final widget = extension.createWidget(key, control); + if (widget != null) return widget; + } + return ErrorControl("Unknown control: ${control.type}"); + }); + } +} diff --git a/packages/flet/lib/src/controls/create_control.dart b/packages/flet/lib/src/controls/create_control.dart deleted file mode 100644 index 190d3ec215..0000000000 --- a/packages/flet/lib/src/controls/create_control.dart +++ /dev/null @@ -1,1298 +0,0 @@ -import 'dart:math'; - -import 'package:flet/src/utils/badge.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; - -import '../control_factory.dart'; -import '../flet_app_services.dart'; -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; -import '../models/control.dart'; -import '../models/control_view_model.dart'; -import '../models/page_media_view_model.dart'; -import '../utils/animations.dart'; -import '../utils/theme.dart'; -import '../utils/tooltip.dart'; -import '../utils/transforms.dart'; -import 'alert_dialog.dart'; -import 'animated_switcher.dart'; -import 'auto_complete.dart'; -import 'autofill_group.dart'; -import 'banner.dart'; -import 'barchart.dart'; -import 'bottom_app_bar.dart'; -import 'bottom_sheet.dart'; -import 'canvas.dart'; -import 'card.dart'; -import 'checkbox.dart'; -import 'chip.dart'; -import 'circle_avatar.dart'; -import 'column.dart'; -import 'container.dart'; -import 'cupertino_action_sheet.dart'; -import 'cupertino_action_sheet_action.dart'; -import 'cupertino_activity_indicator.dart'; -import 'cupertino_alert_dialog.dart'; -import 'cupertino_bottom_sheet.dart'; -import 'cupertino_button.dart'; -import 'cupertino_checkbox.dart'; -import 'cupertino_context_menu.dart'; -import 'cupertino_context_menu_action.dart'; -import 'cupertino_date_picker.dart'; -import 'cupertino_dialog_action.dart'; -import 'cupertino_list_tile.dart'; -import 'cupertino_navigation_bar.dart'; -import 'cupertino_picker.dart'; -import 'cupertino_radio.dart'; -import 'cupertino_segmented_button.dart'; -import 'cupertino_slider.dart'; -import 'cupertino_sliding_segmented_button.dart'; -import 'cupertino_switch.dart'; -import 'cupertino_textfield.dart'; -import 'cupertino_timer_picker.dart'; -import 'datatable.dart'; -import 'date_picker.dart'; -import 'dismissible.dart'; -import 'divider.dart'; -import 'drag_target.dart'; -import 'draggable.dart'; -import 'dropdown.dart'; -import 'dropdownm2.dart'; -import 'elevated_button.dart'; -import 'error.dart'; -import 'expansion_panel.dart'; -import 'expansion_tile.dart'; -import 'file_picker.dart'; -import 'flet_app_control.dart'; -import 'floating_action_button.dart'; -import 'gesture_detector.dart'; -import 'grid_view.dart'; -import 'haptic_feedback.dart'; -import 'icon.dart'; -import 'icon_button.dart'; -import 'image.dart'; -import 'interactive_viewer.dart'; -import 'linechart.dart'; -import 'list_tile.dart'; -import 'list_view.dart'; -import 'markdown.dart'; -import 'menu_bar.dart'; -import 'menu_item_button.dart'; -import 'merge_semantics.dart'; -import 'navigation_bar.dart'; -import 'navigation_rail.dart'; -import 'outlined_button.dart'; -import 'page.dart'; -import 'pagelet.dart'; -import 'piechart.dart'; -import 'placeholder.dart'; -import 'popup_menu_button.dart'; -import 'progress_bar.dart'; -import 'progress_ring.dart'; -import 'radio.dart'; -import 'radio_group.dart'; -import 'range_slider.dart'; -import 'reorderable_draggable.dart'; -import 'reorderable_list_view.dart'; -import 'responsive_row.dart'; -import 'row.dart'; -import 'safe_area.dart'; -import 'search_anchor.dart'; -import 'segmented_button.dart'; -import 'selection_area.dart'; -import 'semantics.dart'; -import 'semantics_service.dart'; -import 'shader_mask.dart'; -import 'shake_detector.dart'; -import 'slider.dart'; -import 'snack_bar.dart'; -import 'stack.dart'; -import 'submenu_button.dart'; -import 'switch.dart'; -import 'tabs.dart'; -import 'text.dart'; -import 'text_button.dart'; -import 'textfield.dart'; -import 'time_picker.dart'; -import 'transparent_pointer.dart'; -import 'vertical_divider.dart'; - -Widget createControl(Control? parent, String id, bool parentDisabled, - {Widget? nextChild, bool? parentAdaptive}) { - //debugPrint("createControl(): $id"); - return StoreConnector( - key: ValueKey(id), - distinct: true, - converter: (store) { - //debugPrint("ControlViewModel $id converter"); - return ControlViewModel.fromStore(store, id); - }, - // onWillChange: (prev, next) { - // debugPrint("onWillChange() $id: $prev, $next"); - // }, - ignoreChange: (state) { - //debugPrint("ignoreChange: $id"); - return state.controls[id] == null; - }, - builder: (context, controlView) { - if (controlView == null) { - return const SizedBox.shrink(); - } - - Key? controlKey; - var key = controlView.control.attrString("key", "")!; - if (key != "") { - if (key.startsWith("test:")) { - controlKey = Key(key.substring(5)); - } else { - var globalKey = controlKey = GlobalKey(); - FletAppServices.of(context).globalKeys[key] = globalKey; - } - } - - Widget? widget; - - for (var createControlFactory - in FletAppServices.of(context).createControlFactories) { - widget = createControlFactory(CreateControlArgs( - controlKey, - parent, - controlView.control, - controlView.children, - nextChild, - parentDisabled, - parentAdaptive, - FletAppServices.of(context).server)); - if (widget != null) { - break; - } - } - - // try creating Flet built-in widget - widget ??= createWidget(controlKey, controlView, parent, parentDisabled, - parentAdaptive, nextChild, FletAppServices.of(context).server); - - // no theme defined? return widget - var themeMode = - parseThemeMode(controlView.control.attrString("themeMode")); - if (id == "page" || - (controlView.control.attrString("theme") == null && - controlView.control.attrString("darkTheme") == null && - themeMode == null)) { - return widget; - } - - // wrap into theme widget - ThemeData? parentTheme = (themeMode == null) ? Theme.of(context) : null; - buildTheme(Brightness? brightness) { - return Theme( - data: parseTheme( - controlView.control, - brightness == Brightness.dark ? "darkTheme" : "theme", - brightness, - parentTheme: parentTheme), - child: widget!); - } - - if (themeMode == ThemeMode.system) { - return StoreConnector( - distinct: true, - converter: (store) => PageMediaViewModel.fromStore(store), - builder: (context, media) { - return buildTheme(media.displayBrightness); - }); - } else { - return buildTheme(themeMode == ThemeMode.light - ? Brightness.light - : themeMode == ThemeMode.dark - ? Brightness.dark - : parentTheme?.brightness); - } - }, - ); -} - -Widget createWidget( - Key? key, - ControlViewModel controlView, - Control? parent, - bool parentDisabled, - bool? parentAdaptive, - Widget? nextChild, - FletControlBackend backend) { - switch (controlView.control.type.toLowerCase()) { - case "page": - return PageControl( - control: controlView.control, - children: controlView.children, - dispatch: controlView.dispatch, - backend: backend); - case "text": - return TextControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "icon": - return IconControl( - key: key, parent: parent, control: controlView.control); - case "filepicker": - return FilePickerControl( - parent: parent, - control: controlView.control, - nextChild: nextChild, - backend: backend); - case "markdown": - return MarkdownControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "fletapp": - return FletAppControl( - key: key, parent: parent, control: controlView.control); - case "image": - return ImageControl( - key: key, - parent: parent, - children: controlView.children, - control: controlView.control, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "divider": - return DividerControl( - key: key, parent: parent, control: controlView.control); - case "selectionarea": - return SelectionAreaControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "hapticfeedback": - return HapticFeedbackControl( - parent: parent, - control: controlView.control, - nextChild: nextChild, - backend: backend); - case "shakedetector": - return ShakeDetectorControl( - parent: parent, - control: controlView.control, - nextChild: nextChild, - backend: backend); - case "verticaldivider": - return VerticalDividerControl( - key: key, parent: parent, control: controlView.control); - case "circleavatar": - return CircleAvatarControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "chip": - return ChipControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "pagelet": - return PageletControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "progressring": - return ProgressRingControl( - key: key, parent: parent, control: controlView.control); - case "progressbar": - return ProgressBarControl( - key: key, parent: parent, control: controlView.control); - case "elevatedbutton": - case "filledbutton": - case "filledtonalbutton": - return ElevatedButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinobutton": - return CupertinoButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "outlinedbutton": - return OutlinedButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "textbutton": - return TextButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinodialogaction": - return CupertinoDialogActionControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "iconbutton": - return IconButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "floatingactionbutton": - return FloatingActionButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "popupmenubutton": - return PopupMenuButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "column": - return ColumnControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "row": - return RowControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "responsiverow": - return ResponsiveRowControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "menubar": - return MenuBarControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "submenubutton": - return SubMenuButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "menuitembutton": - return MenuItemButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "placeholder": - return PlaceholderControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "cupertinoslidingsegmentedbutton": - return CupertinoSlidingSegmentedButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentAdaptive: parentAdaptive, - parentDisabled: parentDisabled, - backend: backend); - case "segmentedbutton": - return SegmentedButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "cupertinosegmentedbutton": - return CupertinoSegmentedButtonControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentAdaptive: parentAdaptive, - parentDisabled: parentDisabled, - backend: backend); - case "expansionpanellist": - return ExpansionPanelListControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "stack": - return StackControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "container": - return ContainerControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "datepicker": - return DatePickerControl( - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "cupertinodatepicker": - return CupertinoDatePickerControl( - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "timepicker": - return TimePickerControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "cupertinotimerpicker": - return CupertinoTimerPickerControl( - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "cupertinopicker": - return CupertinoPickerControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentAdaptive: parentAdaptive, - parentDisabled: parentDisabled, - backend: backend); - case "cupertinobottomsheet": - return CupertinoBottomSheetControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentAdaptive: parentAdaptive, - parentDisabled: parentDisabled, - nextChild: nextChild, - backend: backend); - case "draggable": - return DraggableControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "dragtarget": - return DragTargetControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "card": - return CardControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "safearea": - return SafeAreaControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "datatable": - return DataTableControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "transparentpointer": - return TransparentPointerControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "gesturedetector": - return GestureDetectorControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "semantics": - return SemanticsControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "mergesemantics": - return MergeSemanticsControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "semanticsservice": - return SemanticsServiceControl( - parent: parent, control: controlView.control, backend: backend); - case "shadermask": - return ShaderMaskControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "animatedswitcher": - return AnimatedSwitcherControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "listtile": - return ListTileControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "interactiveviewer": - return InteractiveViewerControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinolisttile": - return CupertinoListTileControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinoactionsheet": - return CupertinoActionSheetControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinoactionsheetaction": - return CupertinoActionSheetActionControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "expansiontile": - return ExpansionTileControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "listview": - return ListViewControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "reorderablelistview": - return ReorderableListViewControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "reorderabledraggable": - return ReorderableDraggableControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - ); - case "gridview": - return GridViewControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "autocomplete": - return AutoCompleteControl( - key: key, - parent: parent, - control: controlView.control, - backend: backend); - case "textfield": - return TextFieldControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinotextfield": - return CupertinoTextFieldControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "searchbar": - return SearchAnchorControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "checkbox": - return CheckboxControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - children: controlView.children, - backend: backend); - case "cupertinocheckbox": - return CupertinoCheckboxControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "switch": - return SwitchControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - children: controlView.children, - backend: backend); - case "cupertinoswitch": - return CupertinoSwitchControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "slider": - return SliderControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinoslider": - return CupertinoSliderControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "rangeslider": - return RangeSliderControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "radiogroup": - return RadioGroupControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "radio": - return RadioControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "autofillgroup": - return AutofillGroupControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive); - case "cupertinoradio": - return CupertinoRadioControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "dropdown": - return DropdownControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "dropdownm2": - return DropdownM2Control( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "snackbar": - return SnackBarControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - nextChild: nextChild, - backend: backend); - case "dismissible": - return DismissibleControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinoactivityindicator": - return CupertinoActivityIndicatorControl( - key: key, - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - backend: backend); - case "alertdialog": - return AlertDialogControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - nextChild: nextChild, - backend: backend); - case "cupertinocontextmenu": - return CupertinoContextMenuControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinocontextmenuaction": - return CupertinoContextMenuActionControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinoalertdialog": - return CupertinoAlertDialogControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - nextChild: nextChild, - backend: backend); - case "bottomsheet": - return BottomSheetControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - nextChild: nextChild, - backend: backend); - case "banner": - return BannerControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - nextChild: nextChild, - backend: backend); - case "tabs": - return TabsControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "navigationrail": - return NavigationRailControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "navigationbar": - return NavigationBarControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "cupertinonavigationbar": - return CupertinoNavigationBarControl( - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - case "bottomappbar": - return BottomAppBarControl( - parent: parent, - control: controlView.control, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - children: controlView.children, - ); - case "linechart": - return LineChartControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "barchart": - return BarChartControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "piechart": - return PieChartControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - backend: backend); - case "canvas": - return CanvasControl( - key: key, - parent: parent, - control: controlView.control, - children: controlView.children, - parentDisabled: parentDisabled, - parentAdaptive: parentAdaptive, - backend: backend); - default: - return ErrorControl("Unknown control: ${controlView.control.type}"); - } -} - -Widget baseControl( - BuildContext context, Widget widget, Control? parent, Control control) { - return _expandable( - _directionality( - _tooltip( - _opacity(context, widget, parent, control), - Theme.of(context), - parent, - control, - ), - parent, - control), - parent, - control); -} - -Widget constrainedControl( - BuildContext context, Widget widget, Control? parent, Control control) { - return _expandable( - _badge( - _positionedControl( - context, - _aspectRatio( - _offsetControl( - context, - _scaledControl( - context, - _rotatedControl( - context, - _sizedControl( - _directionality( - _tooltip( - _opacity( - context, widget, parent, control), - Theme.of(context), - parent, - control), - parent, - control), - parent, - control), - parent, - control), - parent, - control), - parent, - control), - parent, - control), - parent, - control), - Theme.of(context), - parent, - control), - parent, - control); -} - -Widget _opacity( - BuildContext context, Widget widget, Control? parent, Control control) { - var opacity = control.attrDouble("opacity"); - var animation = parseAnimation(control, "animateOpacity"); - if (animation != null) { - return AnimatedOpacity( - duration: animation.duration, - curve: animation.curve, - opacity: opacity ?? 1.0, - onEnd: control.attrBool("onAnimationEnd", false)! - ? () { - FletAppServices.of(context) - .server - .triggerControlEvent(control.id, "animation_end", "opacity"); - } - : null, - child: widget, - ); - } else if (opacity != null) { - return Opacity( - opacity: opacity, - child: widget, - ); - } - return widget; -} - -Widget _tooltip( - Widget widget, ThemeData theme, Control? parent, Control control) { - var tooltip = parseTooltip(control, "tooltip", widget, theme); - return tooltip ?? widget; -} - -Widget _badge( - Widget widget, ThemeData theme, Control? parent, Control control) { - var badge = parseBadge(control, "badge", widget, theme); - return badge ?? widget; -} - -Widget _aspectRatio(Widget widget, Control? parent, Control control) { - var aspectRatio = control.attrDouble("aspectRatio"); - return aspectRatio != null - ? AspectRatio( - aspectRatio: aspectRatio, - child: widget, - ) - : widget; -} - -Widget _rotatedControl( - BuildContext context, Widget widget, Control? parent, Control control) { - var rotationDetails = parseRotate(control, "rotate"); - var animation = parseAnimation(control, "animateRotation"); - if (animation != null) { - return AnimatedRotation( - turns: rotationDetails != null ? rotationDetails.angle / (2 * pi) : 0, - alignment: rotationDetails?.alignment ?? Alignment.center, - duration: animation.duration, - curve: animation.curve, - onEnd: control.attrBool("onAnimationEnd", false)! - ? () { - FletAppServices.of(context).server.triggerControlEvent( - control.id, "animation_end", "rotation"); - } - : null, - child: widget); - } else if (rotationDetails != null) { - return Transform.rotate( - angle: rotationDetails.angle, - alignment: rotationDetails.alignment, - child: widget); - } - return widget; -} - -Widget _scaledControl( - BuildContext context, Widget widget, Control? parent, Control control) { - var scaleDetails = parseScale(control, "scale"); - var animation = parseAnimation(control, "animateScale"); - if (animation != null) { - return AnimatedScale( - scale: scaleDetails?.scale ?? 1.0, - alignment: scaleDetails?.alignment ?? Alignment.center, - duration: animation.duration, - curve: animation.curve, - onEnd: control.attrBool("onAnimationEnd", false)! - ? () { - FletAppServices.of(context) - .server - .triggerControlEvent(control.id, "animation_end", "scale"); - } - : null, - child: widget); - } else if (scaleDetails != null) { - return Transform.scale( - scale: scaleDetails.scale, - scaleX: scaleDetails.scaleX, - scaleY: scaleDetails.scaleY, - alignment: scaleDetails.alignment, - child: widget); - } - return widget; -} - -Widget _offsetControl( - BuildContext context, Widget widget, Control? parent, Control control) { - var offset = parseOffset(control, "offset"); - var animation = parseAnimation(control, "animateOffset"); - if (offset != null && animation != null) { - return AnimatedSlide( - offset: offset, - duration: animation.duration, - curve: animation.curve, - onEnd: control.attrBool("onAnimationEnd", false)! - ? () { - FletAppServices.of(context) - .server - .triggerControlEvent(control.id, "animation_end", "offset"); - } - : null, - child: widget); - } else if (offset != null) { - return FractionalTranslation(translation: offset, child: widget); - } - return widget; -} - -Widget _positionedControl( - BuildContext context, Widget widget, Control? parent, Control control) { - var left = control.attrDouble("left", null); - var top = control.attrDouble("top", null); - var right = control.attrDouble("right", null); - var bottom = control.attrDouble("bottom", null); - - var animation = parseAnimation(control, "animatePosition"); - if (animation != null) { - if (left == null && top == null && right == null && bottom == null) { - left = 0; - top = 0; - } - - return AnimatedPositioned( - duration: animation.duration, - curve: animation.curve, - left: left, - top: top, - right: right, - bottom: bottom, - onEnd: control.attrBool("onAnimationEnd", false)! - ? () { - FletAppServices.of(context) - .server - .triggerControlEvent(control.id, "animation_end", "position"); - } - : null, - child: widget, - ); - } else if (left != null || top != null || right != null || bottom != null) { - if (parent?.type != "stack" && parent?.type != "page") { - return ErrorControl("Error displaying ${control.type}", - description: - "Control can be positioned absolutely with \"left\", \"top\", \"right\" and \"bottom\" properties inside Stack control only."); - } - return Positioned( - left: left, - top: top, - right: right, - bottom: bottom, - child: widget, - ); - } - return widget; -} - -Widget _sizedControl(Widget widget, Control? parent, Control control) { - var width = control.attrDouble("width"); - var height = control.attrDouble("height"); - if ((width != null || height != null) && - !["container", "image"].contains(control.type)) { - widget = ConstrainedBox( - constraints: BoxConstraints.tightFor(width: width, height: height), - child: widget, - ); - } - var animation = parseAnimation(control, "animateSize"); - if (animation != null) { - return AnimatedSize( - duration: animation.duration, curve: animation.curve, child: widget); - } - return widget; -} - -Widget _expandable(Widget widget, Control? parent, Control control) { - if (parent != null && ["view", "column", "row"].contains(parent.type)) { - int? expand = control.attrInt("expand"); - var expandLoose = control.attrBool("expandLoose"); - return expand != null - ? (expandLoose == true) - ? Flexible(flex: expand, child: widget) - : Expanded(flex: expand, child: widget) - : widget; - } - return widget; -} - -Widget _directionality(Widget widget, Control? parent, Control control) { - bool rtl = control.attrBool("rtl", false)!; - return rtl - ? Directionality(textDirection: TextDirection.rtl, child: widget) - : widget; -} diff --git a/packages/flet/lib/src/controls/cupertino_action_sheet.dart b/packages/flet/lib/src/controls/cupertino_action_sheet.dart index f0f5755a4d..0a26320c3f 100644 --- a/packages/flet/lib/src/controls/cupertino_action_sheet.dart +++ b/packages/flet/lib/src/controls/cupertino_action_sheet.dart @@ -1,69 +1,25 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import 'base_controls.dart'; -class CupertinoActionSheetControl extends StatefulWidget { - final Control? parent; +class CupertinoActionSheetControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoActionSheetControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const CupertinoActionSheetControl({super.key, required this.control}); @override - State createState() => - _CupertinoActionSheetControlState(); -} - -class _CupertinoActionSheetControlState - extends State { - @override Widget build(BuildContext context) { - debugPrint("CupertinoActionSheetControl build: ${widget.control.id}"); - - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var titleCtrls = - widget.children.where((c) => c.name == "title" && c.isVisible); - var messageCtrls = - widget.children.where((c) => c.name == "message" && c.isVisible); - var cancelButtonCtrls = - widget.children.where((c) => c.name == "cancel" && c.isVisible); - var actionCtrls = - widget.children.where((c) => c.name == "action" && c.isVisible); + debugPrint("CupertinoActionSheetControl build: ${control.id}"); var sheet = CupertinoActionSheet( - title: titleCtrls.isNotEmpty - ? createControl(widget.control, titleCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - message: messageCtrls.isNotEmpty - ? createControl(widget.control, messageCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - cancelButton: cancelButtonCtrls.isNotEmpty - ? createControl(widget.control, cancelButtonCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - actions: actionCtrls.isNotEmpty - ? actionCtrls - .map((c) => createControl(widget.control, c.id, disabled, - parentAdaptive: widget.parentAdaptive)) - .toList() - : null, + title: control.buildTextOrWidget("title"), + message: control.buildTextOrWidget("message"), + cancelButton: control.buildWidget("cancel"), + actions: control.buildWidgets("actions"), ); - return constrainedControl(context, sheet, widget.parent, widget.control); + return LayoutControl(control: control, child: sheet); } } diff --git a/packages/flet/lib/src/controls/cupertino_action_sheet_action.dart b/packages/flet/lib/src/controls/cupertino_action_sheet_action.dart index 99339b2774..131756545b 100644 --- a/packages/flet/lib/src/controls/cupertino_action_sheet_action.dart +++ b/packages/flet/lib/src/controls/cupertino_action_sheet_action.dart @@ -1,58 +1,39 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/mouse.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class CupertinoActionSheetActionControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoActionSheetActionControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const CupertinoActionSheetActionControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("CupertinoActionSheetActionControl build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - var text = control.attrString("text"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - if (contentCtrls.isEmpty && text == null) { + var content = control.buildTextOrWidget("content"); + if (content == null) { return const ErrorControl( - "CupertinoActionSheetAction must have at minimum text or (visible) content provided"); + "CupertinoActionSheetAction.content must be a string or visible Control"); } - return constrainedControl( - context, - CupertinoActionSheetAction( - isDefaultAction: control.attrBool("isDefaultAction", false)!, - isDestructiveAction: control.attrBool("isDestructiveAction", false)!, - onPressed: () { - if (!disabled) { - backend.triggerControlEvent(control.id, "click"); - } - }, - mouseCursor: parseMouseCursor(control.attrString("mouseCursor")), - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : Text(text!), - ), - parent, - control); + final actionSheet = CupertinoActionSheetAction( + isDefaultAction: control.getBool("default", false)!, + isDestructiveAction: control.getBool("destructive", false)!, + onPressed: () { + if (!control.disabled) { + control.triggerEvent("click"); + } + }, + mouseCursor: control.getMouseCursor("mouse_cursor"), + child: content, + ); + + return LayoutControl(control: control, child: actionSheet); } } diff --git a/packages/flet/lib/src/controls/cupertino_activity_indicator.dart b/packages/flet/lib/src/controls/cupertino_activity_indicator.dart index 7329cfa054..1d2cd4d87e 100644 --- a/packages/flet/lib/src/controls/cupertino_activity_indicator.dart +++ b/packages/flet/lib/src/controls/cupertino_activity_indicator.dart @@ -1,34 +1,38 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class CupertinoActivityIndicatorControl extends StatelessWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoActivityIndicatorControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + const CupertinoActivityIndicatorControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("CupertinoActivityIndicatorControl build: ${control.id}"); + final radius = control.getDouble("radius", 10)!; + final color = control.getColor("color", context); + final progress = control.getDouble("progress"); + final bool animating = + progress == null ? control.getBool("animating", true)! : false; - return constrainedControl( - context, - CupertinoActivityIndicator( - radius: control.attrDouble("radius", 10)!, - animating: control.attrBool("animating", true)!, - color: control.attrColor("color", context), - ), - parent, - control); + final activityIndicator = progress != null + ? CupertinoActivityIndicator.partiallyRevealed( + radius: radius, + color: color, + progress: progress, + ) + : CupertinoActivityIndicator( + radius: radius, + animating: animating, + color: color, + ); + return LayoutControl(control: control, child: activityIndicator); } } diff --git a/packages/flet/lib/src/controls/cupertino_alert_dialog.dart b/packages/flet/lib/src/controls/cupertino_alert_dialog.dart index 0ba0b23ef2..3c3326d614 100644 --- a/packages/flet/lib/src/controls/cupertino_alert_dialog.dart +++ b/packages/flet/lib/src/controls/cupertino_alert_dialog.dart @@ -1,125 +1,111 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/animations.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import '../widgets/control_inherited_notifier.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; -class CupertinoAlertDialogControl extends StatefulWidget { - final Control? parent; +class CupertinoAlertDialogControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final Widget? nextChild; - final FletControlBackend backend; - const CupertinoAlertDialogControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.nextChild, - required this.backend}); + const CupertinoAlertDialogControl({super.key, required this.control}); - @override - State createState() => - _CupertinoAlertDialogControlState(); -} - -class _CupertinoAlertDialogControlState - extends State { Widget _createCupertinoAlertDialog() { - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var titleCtrls = - widget.children.where((c) => c.name == "title" && c.isVisible); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - var actionCtrls = - widget.children.where((c) => c.name == "action" && c.isVisible); - if (titleCtrls.isEmpty && contentCtrls.isEmpty && actionCtrls.isEmpty) { - return const ErrorControl( - "CupertinoAlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions"); - } - var insetAnimation = parseAnimation( - widget.control, - "insetAnimation", - ImplicitAnimationDetails( - duration: const Duration(milliseconds: 100), - curve: Curves.decelerate))!; - - return CupertinoAlertDialog( - insetAnimationCurve: insetAnimation.curve, - insetAnimationDuration: insetAnimation.duration, - title: titleCtrls.isNotEmpty - ? createControl(widget.control, titleCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - content: contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - actions: actionCtrls - .map((c) => createControl(widget.control, c.id, disabled, - parentAdaptive: widget.parentAdaptive)) - .toList(), + return ControlInheritedNotifier( + notifier: control, + child: Builder(builder: (context) { + ControlInheritedNotifier.of(context); + final routeAnimation = ModalRoute.of(context)?.animation ?? + const AlwaysStoppedAnimation(1.0); + var insetAnimation = parseAnimation( + control.get("inset_animation"), + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 100), + curve: Curves.decelerate))!; + + final dialog = CupertinoAlertDialog( + insetAnimationCurve: insetAnimation.curve, + insetAnimationDuration: insetAnimation.duration, + title: control.buildTextOrWidget("title"), + content: control.buildWidget("content"), + actions: control.buildWidgets("actions"), + ); + return Stack( + fit: StackFit.expand, + children: [ + IgnorePointer( + child: FadeTransition( + opacity: routeAnimation, + child: ColoredBox( + color: control.getColor("barrier_color", context) ?? + DialogTheme.of(context).barrierColor ?? + Theme.of(context).dialogTheme.barrierColor ?? + Colors.black54, + ), + ), + ), + SafeArea(child: BaseControl(control: control, child: dialog)), + ], + ); + }), ); } @override Widget build(BuildContext context) { - debugPrint("CupertinoAlertDialog build ($hashCode): ${widget.control.id}"); - - bool lastOpen = widget.control.state["open"] ?? false; - - debugPrint("CupertinoAlertDialog build: ${widget.control.id}"); - - var open = widget.control.attrBool("open", false)!; - var modal = widget.control.attrBool("modal", false)!; + debugPrint("CupertinoAlertDialog build: ${control.id}"); - debugPrint("Current open state: $lastOpen"); - debugPrint("New open state: $open"); + final lastOpen = control.getBool("_open", false)!; + var open = control.getBool("open", false)!; + var modal = control.getBool("modal", false)!; if (open && (open != lastOpen)) { - var dialog = _createCupertinoAlertDialog(); - if (dialog is ErrorControl) { - return dialog; + if (control.get("title") == null && + control.get("content") == null && + control.children("actions").isEmpty) { + return const ErrorControl( + "CupertinoAlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions."); } - // close previous dialog - if (ModalRoute.of(context)?.isCurrent != true) { - Navigator.of(context).pop(); - } - - widget.control.state["open"] = open; + control.updateProperties({"_open": open}, python: false); WidgetsBinding.instance.addPostFrameCallback((_) { + ModalRoute? dialogRoute; showDialog( barrierDismissible: !modal, - barrierColor: widget.control.attrColor("barrierColor", context), + // Render the barrier in the dialog widget so it updates live. + barrierColor: Colors.transparent, + useSafeArea: false, useRootNavigator: false, context: context, - builder: (context) => dialog).then((value) { - lastOpen = widget.control.state["open"] ?? false; - debugPrint("Dialog should be dismissed ($hashCode): $lastOpen"); - bool shouldDismiss = lastOpen; - widget.control.state["open"] = false; - - if (shouldDismiss) { - widget.backend - .updateControlState(widget.control.id, {"open": "false"}); - widget.backend.triggerControlEvent(widget.control.id, "dismiss"); - } + builder: (context) { + dialogRoute ??= ModalRoute.of(context); + return _createCupertinoAlertDialog(); + }).then((value) { + (dialogRoute?.completed ?? Future.value()).then((_) { + debugPrint("Dismissing CupertinoAlertDialog(${control.id})"); + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"open": false}); + control.triggerEvent("dismiss"); + }); }); }); - } else if (open != lastOpen && lastOpen) { - Navigator.of(context).pop(); + } else if (!open && lastOpen) { + if (Navigator.of(context).canPop() == true) { + debugPrint( + "CupertinoAlertDialog(${control.id}): Closing dialog managed by this widget."); + Navigator.of(context).pop(); + control.updateProperties({"_open": false}, python: false); + } else { + debugPrint( + "CupertinoAlertDialog(${control.id}): Dialog was not opened by this widget, skipping pop."); + } } - - return widget.nextChild ?? const SizedBox.shrink(); + return const SizedBox.shrink(); } } diff --git a/packages/flet/lib/src/controls/cupertino_app_bar.dart b/packages/flet/lib/src/controls/cupertino_app_bar.dart index 8672de6432..cb24be4476 100644 --- a/packages/flet/lib/src/controls/cupertino_app_bar.dart +++ b/packages/flet/lib/src/controls/cupertino_app_bar.dart @@ -1,85 +1,58 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/overlay_style.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import '../utils/theme.dart'; +import 'base_controls.dart'; class CupertinoAppBarControl extends StatelessWidget implements ObstructingPreferredSizeWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - const CupertinoAppBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const CupertinoAppBarControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("CupertinoAppBar build: ${control.id}"); - var large = control.attrBool("large", false)!; - var leadingCtrls = - children.where((c) => c.name == "leading" && c.isVisible); - - // "middle" is deprecated in v0.27.0 and will be removed in v0.30.0, use "title" instead - var titleCtrls = children - .where((c) => (c.name == "title" || c.name == "middle") && c.isVisible); - - // if the material AppBar was used with adaptive=True, AppBar.actions[0] will be used as trailing control - var trailingCtrls = children.where( - (c) => (c.name == "trailing" || c.name == "action") && c.isVisible); - - var leading = leadingCtrls.isNotEmpty - ? createControl(control, leadingCtrls.first.id, control.isDisabled, - parentAdaptive: parentAdaptive) - : null; + var title = control.buildTextOrWidget("title"); + var leading = control.buildWidget("leading"); var automaticallyImplyLeading = - control.attrBool("automaticallyImplyLeading", true)!; + control.getBool("automatically_imply_leading", true)!; var automaticallyImplyTitle = - control.attrBool("automaticallyImplyTitle", control.attrBool("automaticallyImplyMiddle", true)!)!; + control.getBool("automatically_imply_title", true)!; var transitionBetweenRoutes = - control.attrBool("transitionBetweenRoutes", true)!; - var border = parseBorder(Theme.of(context), control, "border"); - var previousPageTitle = control.attrString("previousPageTitle"); - var padding = parseEdgeInsetsDirectional(control, "padding"); - var backgroundColor = control.attrColor("bgcolor", context); + control.getBool("transition_between_routes", true)!; + var border = control.getBorder("border", Theme.of(context)); + var previousPageTitle = control.getString("previous_page_title"); + var padding = control.getEdgeInsetsDirectional("padding"); + var backgroundColor = control.getColor("bgcolor", context); var automaticBackgroundVisibility = - control.attrBool("automaticBackgroundVisibility", true)!; + control.getBool("automatic_background_visibility", true)!; var enableBackgroundFilterBlur = - control.attrBool("backgroundFilterBlur", true)!; - var brightness = parseBrightness(control.attrString("brightness")); - var title = titleCtrls.isNotEmpty - ? createControl(control, titleCtrls.first.id, control.isDisabled, - parentAdaptive: parentAdaptive) - : null; - var trailing = trailingCtrls.length == 1 - ? createControl(control, trailingCtrls.first.id, control.isDisabled, - parentAdaptive: parentAdaptive) - : trailingCtrls.length > 1 - ? Row( - mainAxisSize: MainAxisSize.min, - children: trailingCtrls - .map((c) => createControl(control, c.id, control.isDisabled, - parentAdaptive: parentAdaptive)) - .toList(), - ) + control.getBool("background_filter_blur", true)!; + var brightness = control.getBrightness("brightness"); + + // "actions" if coming from material AppBar + var trailing = + control.buildWidget("trailing") ?? control.buildWidgets("actions"); + var trailingWidget = trailing is Widget + ? trailing + : trailing is List + ? Row(mainAxisSize: MainAxisSize.min, children: trailing) : null; - var bar = large + var bar = control.getBool("large", false)! ? CupertinoNavigationBar.large( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, + automaticallyImplyTitle: automaticallyImplyTitle, transitionBetweenRoutes: transitionBetweenRoutes, border: border, previousPageTitle: previousPageTitle, @@ -88,10 +61,8 @@ class CupertinoAppBarControl extends StatelessWidget automaticBackgroundVisibility: automaticBackgroundVisibility, enableBackgroundFilterBlur: enableBackgroundFilterBlur, brightness: brightness, - trailing: trailing, largeTitle: title, - automaticallyImplyTitle: automaticallyImplyTitle, - ) + trailing: trailingWidget) : CupertinoNavigationBar( leading: leading, automaticallyImplyLeading: automaticallyImplyLeading, @@ -105,9 +76,9 @@ class CupertinoAppBarControl extends StatelessWidget enableBackgroundFilterBlur: enableBackgroundFilterBlur, brightness: brightness, middle: title, - trailing: trailing, - ); - return baseControl(context, bar, parent, control); + trailing: trailingWidget); + + return BaseControl(control: control, child: bar); } @override @@ -118,8 +89,9 @@ class CupertinoAppBarControl extends StatelessWidget @override bool shouldFullyObstruct(BuildContext context) { final Color backgroundColor = CupertinoDynamicColor.maybeResolve( - control.attrColor("bgcolor", context), context) ?? + control.getColor("bgcolor", context), context) ?? CupertinoTheme.of(context).barBackgroundColor; - return backgroundColor.alpha == 0xFF; + final alpha8 = (backgroundColor.a * 255.0).round().clamp(0, 255); + return alpha8 == 0xFF; } } diff --git a/packages/flet/lib/src/controls/cupertino_bottom_sheet.dart b/packages/flet/lib/src/controls/cupertino_bottom_sheet.dart index c4dade1ab5..9c9d958fa7 100644 --- a/packages/flet/lib/src/controls/cupertino_bottom_sheet.dart +++ b/packages/flet/lib/src/controls/cupertino_bottom_sheet.dart @@ -1,120 +1,89 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../controls/control_widget.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; -class CupertinoBottomSheetControl extends StatefulWidget { - final Control? parent; +class CupertinoBottomSheetControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final Widget? nextChild; - final FletControlBackend backend; - const CupertinoBottomSheetControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentAdaptive, - required this.parentDisabled, - required this.nextChild, - required this.backend}); + const CupertinoBottomSheetControl({ + super.key, + required this.control, + }); - @override - State createState() => - _CupertinoBottomSheetControlState(); -} + Widget _createDialog(BuildContext context) { + Control? content = control.child("content"); -class _CupertinoBottomSheetControlState - extends State { - Widget _createDialog() { - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); + if (content == null) { + return const ErrorControl("CupertinoBottomSheet.content is empty."); + } - Widget content = contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : const SizedBox.shrink(); + Widget child = ControlWidget(control: content); - if (contentCtrls.isNotEmpty && - ["cupertinopicker", "cupertinotimerpicker", "cupertinodatepicker"] - .contains(contentCtrls.first.type)) { - content = Container( - height: widget.control.attrDouble("height", 220.0)!, - padding: parseEdgeInsets(widget.control, "padding"), + if (["CupertinoPicker", "CupertinoTimerPicker", "CupertinoDatePicker"] + .contains(content.type)) { + child = Container( + height: control.getDouble("height", 220.0)!, + padding: control.getPadding("padding"), // bottom margin is provided to align the popup above the system navigation bar margin: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), // popup background color - color: widget.control.attrColor("bgcolor", context, + color: control.getColor("bgcolor", context, CupertinoColors.systemBackground.resolveFrom(context))!, // Use SafeArea to avoid system overlaps child: SafeArea( top: false, - child: content, + child: child, ), ); } - return Material(child: content); + return Material(child: child); } @override Widget build(BuildContext context) { - debugPrint("CupertinoBottomSheet build: ${widget.control.id}"); + debugPrint("CupertinoBottomSheet build: ${control.id}"); - bool lastOpen = widget.control.state["open"] ?? false; + bool lastOpen = control.getBool("_open", false)!; - var open = widget.control.attrBool("open", false)!; - var modal = widget.control.attrBool("modal", false)!; - - debugPrint("Current open state: $lastOpen"); - debugPrint("New open state: $open"); + var open = control.getBool("open", false)!; if (open && (open != lastOpen)) { - var dialog = _createDialog(); + var dialog = _createDialog(context); if (dialog is ErrorControl) { return dialog; } - // close previous dialog - if (ModalRoute.of(context)?.isCurrent != true) { - Navigator.of(context).pop(); - } - - widget.control.state["open"] = open; + control.updateProperties({"_open": open}, python: false); WidgetsBinding.instance.addPostFrameCallback((_) { + ModalRoute? popupRoute; showCupertinoModalPopup( - barrierDismissible: !modal, + barrierDismissible: !control.getBool("modal", false)!, useRootNavigator: false, context: context, - builder: (context) => _createDialog()).then((value) { - lastOpen = widget.control.state["open"] ?? false; - debugPrint( - "CupertinoBottomSheet should be dismissed ($hashCode): $lastOpen"); - bool shouldDismiss = lastOpen; - widget.control.state["open"] = false; - - if (shouldDismiss) { - widget.backend - .updateControlState(widget.control.id, {"open": "false"}); - widget.backend.triggerControlEvent(widget.control.id, "dismiss"); - } + builder: (context) { + popupRoute ??= ModalRoute.of(context); + return dialog; + }).then((value) { + (popupRoute?.completed ?? Future.value()).then((_) { + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"open": false}); + control.triggerEvent("dismiss"); + }); }); }); - } else if (open != lastOpen && lastOpen) { + } else if (open != lastOpen && lastOpen && Navigator.of(context).canPop()) { Navigator.of(context).pop(); } - return widget.nextChild ?? const SizedBox.shrink(); + return const SizedBox.shrink(); } } diff --git a/packages/flet/lib/src/controls/cupertino_button.dart b/packages/flet/lib/src/controls/cupertino_button.dart index bf1d6d530d..11fe836cd3 100644 --- a/packages/flet/lib/src/controls/cupertino_button.dart +++ b/packages/flet/lib/src/controls/cupertino_button.dart @@ -1,188 +1,213 @@ import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; import '../utils/borders.dart'; import '../utils/buttons.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/icons.dart'; +import '../utils/geometry.dart'; import '../utils/launch_url.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/mouse.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class CupertinoButtonControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const CupertinoButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + CupertinoButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CupertinoButtonControlState(); } class _CupertinoButtonControlState extends State { + late final FocusNode _focusNode; + @override - Widget build(BuildContext context) { - debugPrint("CupertinoButton build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var theme = Theme.of(context); - - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - - String? text = widget.control.attrString("text"); - IconData? icon = parseIcon(widget.control.attrString("icon")); - Color? iconColor = widget.control.attrColor("iconColor", context); - - // IconButton props below - double? iconSize = widget.control.attrDouble("iconSize"); - bool selected = widget.control.attrBool("selected", false)!; - IconData? selectedIcon = - parseIcon(widget.control.attrString("selectedIcon")); - Color? selectedIconColor = - widget.control.attrColor("selectedIconColor", context); - - Widget? content; - List children = []; - if (icon != null) { - children.add(Icon( - selected ? selectedIcon : icon, - color: selected - ? selectedIconColor - : disabled - ? theme.disabledColor - : iconColor, - size: iconSize, - )); - } - if (text != null) { - children.add(Text(text)); - } + void initState() { + super.initState(); + _focusNode = FocusNode(); + _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); + } - if (contentCtrls.isNotEmpty) { - content = createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive); - } else if (children.isNotEmpty) { - if (children.length == 2) { - children.insert(1, const SizedBox(width: 8)); - content = Row( - mainAxisSize: MainAxisSize.min, - children: children, - ); - } else { - content = children.first; - } - } + @override + void dispose() { + _focusNode.removeListener(_onFocusChange); + _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } - if (content == null) { - return const ErrorControl( - "CupertinoButton has nothing to display", - description: "Provide at minimum text or (visible) content", - ); + void _onFocusChange() { + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("CupertinoButton.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown CupertinoButton method: $name"); } + } - double pressedOpacity = widget.control.attrDouble("opacityOnClick", 0.4)!; - double minSize = widget.control.attrDouble("minSize", 44.0)!; - String url = widget.control.attrString("url", "")!; - Color disabledColor = - widget.control.attrColor("disabledBgcolor", context) ?? - CupertinoColors.quaternarySystemFill; - Color? bgColor = widget.control.attrColor("bgColor", context); - Color? color = widget.control.attrColor("color", context); - AlignmentGeometry alignment = - parseAlignment(widget.control, "alignment", Alignment.center)!; - BorderRadius borderRadius = parseBorderRadius(widget.control, - "borderRadius", const BorderRadius.all(Radius.circular(8.0)))!; - - EdgeInsets? padding = parseEdgeInsets(widget.control, "padding"); - - var style = parseButtonStyle(Theme.of(context), widget.control, "style", - defaultForegroundColor: theme.colorScheme.primary, - defaultBackgroundColor: Colors.transparent, - defaultOverlayColor: Colors.transparent, - defaultShadowColor: Colors.transparent, - defaultSurfaceTintColor: Colors.transparent, - defaultElevation: 0, - defaultPadding: const EdgeInsets.all(8), - defaultBorderSide: BorderSide.none, - defaultShape: theme.useMaterial3 - ? const StadiumBorder() - : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - - if (style != null) { - Set widgetStates = selected ? {WidgetState.selected} : {}; - - // Check if the widget is disabled and update the foregroundColor accordingly - // backgroundColor is not updated here, as it is handled by disabledColor - if (disabled) { - style = style.copyWith( - foregroundColor: WidgetStatePropertyAll(theme.disabledColor), - ); - } + @override + Widget build(BuildContext context) { + debugPrint("CupertinoButton build: ${widget.control.id}"); + Color? iconColor = widget.control.getColor("icon_color", context); - // Resolve color, background color, and padding based on widget states - color = style.foregroundColor?.resolve(widgetStates); - bgColor = style.backgroundColor?.resolve(widgetStates); - padding = style.padding?.resolve({}) as EdgeInsets?; + Widget? icon = widget.control.buildIconOrWidget("icon", color: iconColor); + Widget? content = widget.control.buildTextOrWidget("content"); + + Widget child; + if (icon != null) { + if (content != null) { + child = Row( + mainAxisSize: MainAxisSize.min, + children: [icon, const SizedBox(width: 8), content]); + } else { + child = icon; + } + } else { + child = content ?? const Text(""); } + var pressedOpacity = widget.control.getDouble("opacity_on_click", 0.4)!; + var minSize = widget.control.getSize("min_size"); + var mouseCursor = widget.control.getMouseCursor("mouse_cursor"); + var autofocus = widget.control.getBool("autofocus", false)!; + var bgColor = widget.control.getColor("bgcolor", context); + var focusColor = widget.control.getColor("focus_color", context); + var size = widget.control + .getCupertinoButtonSize("size", CupertinoButtonSize.large)!; + + var alignment = widget.control.getAlignment("alignment", Alignment.center)!; + var borderRadius = widget.control.getBorderRadius( + "border_radius", const BorderRadius.all(Radius.circular(8.0)))!; + + var padding = widget.control.getPadding("padding"); + bool isFilledButton = + {"CupertinoFilledButton", "FilledButton"}.contains(widget.control.type); + bool isTintedButton = {"CupertinoTintedButton", "FilledTonalButton"} + .contains(widget.control.type); + + // var style = widget.control.getButtonStyle("style", Theme.of(context), + // defaultForegroundColor: theme.colorScheme.primary, + // defaultBackgroundColor: Colors.transparent, + // defaultOverlayColor: Colors.transparent, + // defaultShadowColor: Colors.transparent, + // defaultSurfaceTintColor: Colors.transparent, + // defaultElevation: 0, + // defaultPadding: const EdgeInsets.all(8), + // defaultBorderSide: BorderSide.none, + // defaultShape: theme.useMaterial3 + // ? const StadiumBorder() + // : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); + + // if (style != null) { + // Set widgetStates = selected ? {WidgetState.selected} : {}; + + // // Check if the widget is disabled and update the foregroundColor accordingly + // // backgroundColor is not updated here, as it is handled by disabledColor + // if (control.disabled) { + // style = style.copyWith( + // foregroundColor: WidgetStatePropertyAll(theme.disabledColor), + // ); + // } + + // // Resolve color, background color, and padding based on widget states + // color = style.foregroundColor?.resolve(widgetStates); + // bgColor = style.backgroundColor?.resolve(widgetStates); + // padding = style.padding?.resolve({}) as EdgeInsets?; + // } + var color = widget.control.getColor("color", context); + var disabledColor = widget.control.getColor( + "disabled_bgcolor", context, CupertinoColors.tertiarySystemFill)!; if (color != null) { - content = DefaultTextStyle( + child = DefaultTextStyle( style: CupertinoTheme.of(context) .textTheme .textStyle .copyWith(color: color), - child: content); + child: child); } - - Function()? onPressed = !disabled + var url = widget.control.getUrl("url"); + Function()? onPressed = !widget.control.disabled ? () { - debugPrint("CupertinoButton ${widget.control.id} clicked!"); - if (url != "") { - openWebBrowser(url, - webWindowName: widget.control.attrString("urlTarget")); + if (url != null) { + openWebBrowser(url); } - widget.backend.triggerControlEvent(widget.control.id, "click"); + widget.control.triggerEvent("click"); + } + : null; + Function()? onLongPressed = !widget.control.disabled + ? () { + widget.control.triggerEvent("long_press"); } : null; - CupertinoButton? button = CupertinoButton( - onPressed: onPressed, - disabledColor: disabledColor, - color: bgColor, - padding: padding, - borderRadius: borderRadius, - pressedOpacity: pressedOpacity, - alignment: alignment, - minSize: minSize, - autofocus: widget.control.attrBool("autofocus", false)!, - focusColor: widget.control.attrColor("focusColor", context), - onLongPress: !disabled - ? () { - widget.backend - .triggerControlEvent(widget.control.id, "longPress"); - } - : null, - onFocusChange: (focused) { - widget.backend - .triggerControlEvent(widget.control.id, focused ? "focus" : "blur"); - }, - child: content, - ); - - return constrainedControl(context, button, widget.parent, widget.control); + CupertinoButton? button; + if (isFilledButton) { + button = CupertinoButton.filled( + onPressed: onPressed, + disabledColor: disabledColor, + color: bgColor, + padding: padding, + borderRadius: borderRadius, + pressedOpacity: pressedOpacity, + alignment: alignment, + minimumSize: minSize, + sizeStyle: size, + autofocus: autofocus, + focusColor: focusColor, + onLongPress: onLongPressed, + focusNode: _focusNode, + mouseCursor: mouseCursor, + child: child, + ); + } else if (isTintedButton) { + button = CupertinoButton.tinted( + onPressed: onPressed, + disabledColor: disabledColor, + color: bgColor, + padding: padding, + borderRadius: borderRadius, + pressedOpacity: pressedOpacity, + alignment: alignment, + minimumSize: minSize, + sizeStyle: size, + autofocus: autofocus, + focusColor: focusColor, + onLongPress: onLongPressed, + focusNode: _focusNode, + mouseCursor: mouseCursor, + child: child, + ); + } else { + button = CupertinoButton( + onPressed: onPressed, + disabledColor: disabledColor, + color: bgColor, + padding: padding, + borderRadius: borderRadius, + pressedOpacity: pressedOpacity, + alignment: alignment, + minimumSize: minSize, + sizeStyle: size, + autofocus: autofocus, + focusColor: focusColor, + onLongPress: onLongPressed, + focusNode: _focusNode, + mouseCursor: mouseCursor, + child: child, + ); + } + + return LayoutControl(control: widget.control, child: button); } } diff --git a/packages/flet/lib/src/controls/cupertino_checkbox.dart b/packages/flet/lib/src/controls/cupertino_checkbox.dart index 135d831645..46019af455 100644 --- a/packages/flet/lib/src/controls/cupertino_checkbox.dart +++ b/packages/flet/lib/src/controls/cupertino_checkbox.dart @@ -1,27 +1,22 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; import '../utils/colors.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import '../utils/text.dart'; +import 'base_controls.dart'; import 'list_tile.dart'; class CupertinoCheckboxControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoCheckboxControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + CupertinoCheckboxControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CheckboxControlState(); @@ -31,26 +26,39 @@ class _CheckboxControlState extends State { bool? _value; bool _tristate = false; late final FocusNode _focusNode; + Listenable? _tileClicksNotifier; @override void initState() { super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); + _focusNode = FocusNode()..addListener(_onFocusChange); } - void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final newNotifier = ListTileClicks.of(context)?.notifier; + + // If the inherited source changed, swap listeners + if (!identical(_tileClicksNotifier, newNotifier)) { + _tileClicksNotifier?.removeListener(_toggleValue); + _tileClicksNotifier = newNotifier; + _tileClicksNotifier?.addListener(_toggleValue); + } } @override void dispose() { _focusNode.removeListener(_onFocusChange); + _tileClicksNotifier?.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } + void _onFocusChange() { + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + void _toggleValue() { bool? newValue; if (!_tristate) { @@ -64,68 +72,75 @@ class _CheckboxControlState extends State { } void _onChange(bool? value) { - var svalue = value != null ? value.toString() : ""; _value = value; - widget.backend.updateControlState(widget.control.id, {"value": svalue}); - widget.backend.triggerControlEvent(widget.control.id, "change", svalue); + widget.control.updateProperties({"value": value}, notify: true); + widget.control.triggerEvent("change", value); } @override Widget build(BuildContext context) { debugPrint("CupertinoCheckBox build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - String label = widget.control.attrString("label", "")!; - LabelPosition labelPosition = parseLabelPosition( - widget.control.attrString("labelPosition"), LabelPosition.right)!; - _tristate = widget.control.attrBool("tristate", false)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; - - bool? value = widget.control.attrBool("value", _tristate ? null : false); + _tristate = widget.control.getBool("tristate", false)!; + var value = widget.control.getBool("value", _tristate ? null : false); if (_value != value) { _value = value; } var cupertinoCheckbox = CupertinoCheckbox( - autofocus: autofocus, + autofocus: widget.control.getBool("autofocus", false)!, focusNode: _focusNode, value: _value, - activeColor: parseColor(Theme.of(context), - widget.control.attrString("activeColor", "primary")!), - checkColor: widget.control.attrColor("checkColor", context), - focusColor: widget.control.attrColor("focusColor", context), - shape: parseOutlinedBorder(widget.control, "shape"), - mouseCursor: parseMouseCursor(widget.control.attrString("mouseCursor")), - semanticLabel: widget.control.attrString("semanticsLabel"), - side: parseWidgetStateBorderSide( - Theme.of(context), widget.control, "borderSide"), - fillColor: parseWidgetStateColor( - Theme.of(context), widget.control, "fillColor"), + activeColor: widget.control.getColor("active_color", context), + checkColor: widget.control.getColor("check_color", context), + focusColor: widget.control.getColor("focus_color", context), + shape: widget.control.getShape("shape", Theme.of(context)), + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + semanticLabel: widget.control.getString("semantics_label"), + side: widget.control + .getWidgetStateBorderSide("border_side", Theme.of(context)), + fillColor: + widget.control.getWidgetStateColor("fill_color", Theme.of(context)), tristate: _tristate, - onChanged: !disabled - ? (bool? value) { - _onChange(value); - } + onChanged: !widget.control.disabled + ? (bool? value) => _onChange(value) : null); - ListTileClicks.of(context)?.notifier.addListener(() { - _toggleValue(); - }); - Widget result = cupertinoCheckbox; - if (label != "") { - var labelWidget = disabled - ? Text(label, - style: TextStyle(color: Theme.of(context).disabledColor)) - : MouseRegion(cursor: SystemMouseCursors.click, child: Text(label)); + + var labelStyle = + widget.control.getTextStyle("label_style", Theme.of(context)); + if (widget.control.disabled && labelStyle != null) { + labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); + } + var label = + widget.control.buildTextOrWidget("label", textStyle: labelStyle); + if (label != null) { + var spacing = widget.control.getDouble("spacing", 10)!; + label = widget.control.disabled + ? label + : MouseRegion(cursor: SystemMouseCursors.click, child: label); + var labelPosition = widget.control + .getLabelPosition("label_position", LabelPosition.right)!; result = MergeSemantics( child: GestureDetector( - onTap: !disabled ? _toggleValue : null, + onTap: !widget.control.disabled ? _toggleValue : null, child: labelPosition == LabelPosition.right - ? Row(children: [cupertinoCheckbox, labelWidget]) - : Row(children: [labelWidget, cupertinoCheckbox]))); + ? Row(spacing: spacing, children: [cupertinoCheckbox, label]) + : Row( + spacing: spacing, children: [label, cupertinoCheckbox]))); + } + + // Apply width and height if provided + var width = widget.control.getDouble("width"); + var height = widget.control.getDouble("height"); + if (width != null || height != null) { + result = SizedBox( + width: width, + height: height, + child: FittedBox(fit: BoxFit.fill, child: result)); } - return constrainedControl(context, result, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: result); } } diff --git a/packages/flet/lib/src/controls/cupertino_context_menu.dart b/packages/flet/lib/src/controls/cupertino_context_menu.dart index 1cee81748c..a1559967cd 100644 --- a/packages/flet/lib/src/controls/cupertino_context_menu.dart +++ b/packages/flet/lib/src/controls/cupertino_context_menu.dart @@ -1,27 +1,16 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; class CupertinoContextMenuControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoContextMenuControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + CupertinoContextMenuControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -34,32 +23,22 @@ class _CupertinoContextMenuControlState Widget build(BuildContext context) { debugPrint("CupertinoContextMenu build ($hashCode): ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - var actionCtrls = - widget.children.where((c) => c.name == "action" && c.isVisible); + var content = widget.control.buildWidget("content"); + var actions = widget.control.buildWidgets("actions"); - if (actionCtrls.isEmpty) { + if (actions.isEmpty) { return const ErrorControl( - "CupertinoContextMenu.actions must be provided and at least one action must be visible"); + "at least one action in CupertinoContextMenu.actions must be visible"); } - if (contentCtrls.isEmpty) { - return const ErrorControl( - "CupertinoContextMenu.content must be provided and visible"); + if (content == null) { + return const ErrorControl("CupertinoContextMenu.content must be visible"); } return CupertinoContextMenu( enableHapticFeedback: - widget.control.attrBool("enableHapticFeedback", false)!, - actions: actionCtrls.map((c) { - return createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive); - }).toList(), - child: createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive), + widget.control.getBool("enable_haptic_feedback", false)!, + actions: actions, + child: content, ); } } diff --git a/packages/flet/lib/src/controls/cupertino_context_menu_action.dart b/packages/flet/lib/src/controls/cupertino_context_menu_action.dart index e622ed8a70..07227e64fa 100644 --- a/packages/flet/lib/src/controls/cupertino_context_menu_action.dart +++ b/packages/flet/lib/src/controls/cupertino_context_menu_action.dart @@ -1,64 +1,34 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/icons.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; -class CupertinoContextMenuActionControl extends StatefulWidget { - final Control? parent; +class CupertinoContextMenuActionControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoContextMenuActionControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const CupertinoContextMenuActionControl({super.key, required this.control}); @override - State createState() => - _CupertinoContextMenuActionControlState(); -} - -class _CupertinoContextMenuActionControlState - extends State with FletStoreMixin { - @override Widget build(BuildContext context) { - debugPrint( - "CupertinoContextMenuAction build ($hashCode): ${widget.control.id}"); - - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - String text = widget.control.attrString("text", "")!; - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - IconData? trailingIcon = - parseIcon(widget.control.attrString("trailingIcon")); - + debugPrint("CupertinoContextMenuAction build ($hashCode): ${control.id}"); + var content = control.buildTextOrWidget("content", + textStyle: const TextStyle(overflow: TextOverflow.ellipsis)); + if (content == null) { + return ErrorWidget( + "content (string or visible Control) must be provided"); + } return CupertinoContextMenuAction( - isDefaultAction: widget.control.attrBool("isDefaultAction", false)!, - isDestructiveAction: - widget.control.attrBool("isDestructiveAction", false)!, - onPressed: () { - if (!disabled) { - widget.backend.triggerControlEvent(widget.control.id, "click"); - Navigator.of(context).pop(); - } - }, - trailingIcon: trailingIcon, - child: contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) - : Text(text, overflow: TextOverflow.ellipsis), - ); + isDefaultAction: control.getBool("default", false)!, + isDestructiveAction: control.getBool("destructive", false)!, + onPressed: () { + if (!control.disabled) { + control.triggerEvent("click"); + Navigator.of(context).pop(); // Close the context menu + } + }, + trailingIcon: control.getIconData("trailing_icon"), + child: content); } } diff --git a/packages/flet/lib/src/controls/cupertino_date_picker.dart b/packages/flet/lib/src/controls/cupertino_date_picker.dart index c3980ddbc8..f0e00bd0ed 100644 --- a/packages/flet/lib/src/controls/cupertino_date_picker.dart +++ b/packages/flet/lib/src/controls/cupertino_date_picker.dart @@ -1,23 +1,18 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/colors.dart'; +import '../utils/locale.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class CupertinoDatePickerControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoDatePickerControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + CupertinoDatePickerControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -26,42 +21,43 @@ class CupertinoDatePickerControl extends StatefulWidget { class _CupertinoDatePickerControlState extends State { - static const double _kItemExtent = 32.0; - @override Widget build(BuildContext context) { debugPrint("CupertinoDatePicker build: ${widget.control.id}"); + var locale = widget.control.getLocale("locale"); + Widget dialog; try { dialog = CupertinoDatePicker( - initialDateTime: widget.control.attrDateTime("value"), - showDayOfWeek: widget.control.attrBool("showDayOfWeek", false)!, - minimumDate: widget.control.attrDateTime("firstDate"), - maximumDate: widget.control.attrDateTime("lastDate"), - backgroundColor: widget.control.attrColor("bgcolor", context), - minimumYear: widget.control.attrInt("minimumYear", 1)!, - maximumYear: widget.control.attrInt("maximumYear"), - itemExtent: widget.control.attrDouble("itemExtent", _kItemExtent)!, - minuteInterval: widget.control.attrInt("minuteInterval", 1)!, - use24hFormat: widget.control.attrBool("use24hFormat", false)!, - dateOrder: - parseDatePickerDateOrder(widget.control.attrString("dateOrder")), - mode: parseCupertinoDatePickerMode( - widget.control.attrString("datePickerMode"), - CupertinoDatePickerMode.dateAndTime)!, + initialDateTime: widget.control.getDateTime("value"), + showDayOfWeek: widget.control.getBool("show_day_of_week", false)!, + minimumDate: widget.control.getDateTime("first_date"), + maximumDate: widget.control.getDateTime("last_date"), + backgroundColor: widget.control.getColor("bgcolor", context), + minimumYear: widget.control.getInt("minimum_year", 1)!, + maximumYear: widget.control.getInt("maximum_year"), + itemExtent: widget.control.getDouble("item_extent", 32.0)!, + minuteInterval: widget.control.getInt("minute_interval", 1)!, + use24hFormat: widget.control.getBool("use_24h_format", false)!, + dateOrder: widget.control.getDatePickerDateOrder("date_order"), + mode: widget.control.getCupertinoDatePickerMode( + "date_picker_mode", CupertinoDatePickerMode.dateAndTime)!, onDateTimeChanged: (DateTime value) { - String stringValue = value.toIso8601String(); - widget.backend - .updateControlState(widget.control.id, {"value": stringValue}); - widget.backend - .triggerControlEvent(widget.control.id, "change", stringValue); + widget.control.updateProperties({"value": value}); + widget.control.triggerEvent("change", value); }, ); } catch (e) { return ErrorControl("CupertinoDatePicker Error: ${e.toString()}"); } - return constrainedControl(context, dialog, widget.parent, widget.control); + return LayoutControl( + control: widget.control, + child: locale == null || !locale.isSupportedByDelegates() + ? dialog + : Localizations.override( + context: context, locale: locale, child: dialog), + ); } } diff --git a/packages/flet/lib/src/controls/cupertino_dialog_action.dart b/packages/flet/lib/src/controls/cupertino_dialog_action.dart index 4ce3c09069..9a37f84170 100644 --- a/packages/flet/lib/src/controls/cupertino_dialog_action.dart +++ b/packages/flet/lib/src/controls/cupertino_dialog_action.dart @@ -1,51 +1,36 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class CupertinoDialogActionControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoDialogActionControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const CupertinoDialogActionControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("CupertinoDialogAction build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); + var content = control.buildTextOrWidget("content"); + if (content == null) { + return const ErrorControl( + "CupertinoDialogAction.content must be a string or visible Control"); + } var cupertinoDialogAction = CupertinoDialogAction( - isDefaultAction: control.attrBool("isDefaultAction", false)!, - isDestructiveAction: control.attrBool("isDestructiveAction", false)!, - textStyle: parseTextStyle(Theme.of(context), control, "textStyle"), - onPressed: !disabled - ? () { - debugPrint("CupertinoDialogAction ${control.id} clicked!"); - backend.triggerControlEvent(control.id, "click"); - } - : null, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : Text(control.attrString("text", "")!)); + isDefaultAction: control.getBool("default", false)!, + isDestructiveAction: control.getBool("destructive", false)!, + textStyle: control.getTextStyle("text_style", Theme.of(context)), + onPressed: !control.disabled ? () => control.triggerEvent("click") : null, + child: content, + ); - return baseControl(context, cupertinoDialogAction, parent, control); + return BaseControl(control: control, child: cupertinoDialogAction); } } diff --git a/packages/flet/lib/src/controls/cupertino_list_tile.dart b/packages/flet/lib/src/controls/cupertino_list_tile.dart index c04a3dd587..c2f6d24756 100644 --- a/packages/flet/lib/src/controls/cupertino_list_tile.dart +++ b/packages/flet/lib/src/controls/cupertino_list_tile.dart @@ -1,120 +1,83 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/launch_url.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; import 'list_tile.dart'; class CupertinoListTileControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; final ListTileClickNotifier _clickNotifier = ListTileClickNotifier(); - CupertinoListTileControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + CupertinoListTileControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("CupertinoListTile build: ${control.id}"); - var leadingCtrls = - children.where((c) => c.name == "leading" && c.isVisible); - var titleCtrls = children.where((c) => c.name == "title" && c.isVisible); - var subtitleCtrls = - children.where((c) => c.name == "subtitle" && c.isVisible); - var trailingCtrls = - children.where((c) => c.name == "trailing" && c.isVisible); - var additionalInfoCtrls = - children.where((c) => c.name == "additionalInfo" && c.isVisible); - - bool notched = control.attrBool("notched", false)!; - bool onclick = control.attrBool("onclick", false)!; - bool toggleInputs = control.attrBool("toggleInputs", false)!; - String url = control.attrString("url", "")!; - String? urlTarget = control.attrString("urlTarget"); - bool disabled = control.isDisabled || parentDisabled; - - Widget? additionalInfo = additionalInfoCtrls.isNotEmpty - ? createControl(control, additionalInfoCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null; - Widget? leading = leadingCtrls.isNotEmpty - ? createControl(control, leadingCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null; - - Widget? title = titleCtrls.isNotEmpty - ? createControl(control, titleCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : const Text(""); - - Widget? subtitle = subtitleCtrls.isNotEmpty - ? createControl(control, subtitleCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null; - - Widget? trailing = trailingCtrls.isNotEmpty - ? createControl(control, trailingCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null; - - Color? backgroundColor = control.attrColor("bgcolor", context); - Color? bgcolorActivated = control.attrColor("bgcolorActivated", context); - - var padding = parseEdgeInsets(control, "contentPadding"); - var leadingSize = control.attrDouble("leadingSize"); - var leadingToTitle = control.attrDouble("leadingToTitle"); - - Function()? onPressed = (onclick || toggleInputs || url != "") && !disabled - ? () { - debugPrint("CupertinoListTile ${control.id} clicked!"); - if (toggleInputs) { - _clickNotifier.onClick(); - } - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - if (onclick) { - backend.triggerControlEvent(control.id, "click"); - } - } - : null; + var title = control.buildTextOrWidget("title"); + if (title == null) { + return const ErrorControl( + "CupertinoListTile.title must be provided and visible"); + } + var leading = control.buildIconOrWidget("leading"); + var additionalInfo = control.buildTextOrWidget("additional_info"); + var subtitle = control.buildTextOrWidget("subtitle"); + var trailing = control.buildIconOrWidget("trailing"); + var backgroundColor = control.getColor("bgcolor", context); + var bgcolorActivated = control.getColor("bgcolor_activated", context); + var padding = control.getPadding("content_padding"); + var notched = control.getBool("notched", false)!; + var leadingSize = control.getDouble("leading_size", notched ? 30.0 : 28.0)!; + var leadingToTitle = + control.getDouble("leading_to_title", notched ? 12.0 : 16.0)!; + var onclick = control.getBool("on_click", false)!; + var toggleInputs = control.getBool("toggle_inputs", false)!; + var url = control.getUrl("url"); + + Function()? onPressed = + (onclick || toggleInputs || url != null) && !control.disabled + ? () { + if (toggleInputs) { + _clickNotifier.onClick(); + } + if (url != null) { + openWebBrowser(url); + } + if (onclick) { + control.triggerEvent("click"); + } + } + : null; Widget tile; - !notched - ? tile = CupertinoListTile( + notched + ? tile = CupertinoListTile.notched( onTap: onPressed, additionalInfo: additionalInfo, backgroundColor: backgroundColor, backgroundColorActivated: bgcolorActivated, leading: leading, - leadingSize: leadingSize ?? 28.0, - leadingToTitle: leadingToTitle ?? 16.0, + leadingSize: leadingSize, + leadingToTitle: leadingToTitle, padding: padding, title: title, subtitle: subtitle, trailing: trailing, ) - : tile = CupertinoListTile.notched( + : tile = CupertinoListTile( onTap: onPressed, additionalInfo: additionalInfo, backgroundColor: backgroundColor, backgroundColorActivated: bgcolorActivated, leading: leading, - leadingSize: leadingSize ?? 30.0, - leadingToTitle: leadingToTitle ?? 12.0, + leadingSize: leadingSize, + leadingToTitle: leadingToTitle, padding: padding, title: title, subtitle: subtitle, @@ -125,6 +88,6 @@ class CupertinoListTileControl extends StatelessWidget { tile = ListTileClicks(notifier: _clickNotifier, child: tile); } - return constrainedControl(context, tile, parent, control); + return LayoutControl(control: control, child: tile); } } diff --git a/packages/flet/lib/src/controls/cupertino_navigation_bar.dart b/packages/flet/lib/src/controls/cupertino_navigation_bar.dart index c984a5d33f..008c8a776f 100644 --- a/packages/flet/lib/src/controls/cupertino_navigation_bar.dart +++ b/packages/flet/lib/src/controls/cupertino_navigation_bar.dart @@ -1,31 +1,19 @@ -import 'dart:convert'; - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; -import '../utils/icons.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; class CupertinoNavigationBarControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoNavigationBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + CupertinoNavigationBarControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -36,72 +24,42 @@ class _CupertinoNavigationBarControlState extends State with FletStoreMixin { int _selectedIndex = 0; - bool get disabled => widget.control.isDisabled || widget.parentDisabled; - void _onTap(int index) { _selectedIndex = index; - debugPrint("Selected index: $_selectedIndex"); - widget.backend.updateControlState( - widget.control.id, {"selectedindex": _selectedIndex.toString()}); - widget.backend.triggerControlEvent( - widget.control.id, "change", _selectedIndex.toString()); + widget.control + .updateProperties({"selected_index": _selectedIndex}, notify: true); + widget.control.triggerEvent("change", _selectedIndex); } @override Widget build(BuildContext context) { debugPrint("CupertinoNavigationBarControl build: ${widget.control.id}"); - var selectedIndex = widget.control.attrInt("selectedIndex", 0)!; - + var selectedIndex = widget.control.getInt("selected_index", 0)!; if (_selectedIndex != selectedIndex) { _selectedIndex = selectedIndex; } - var navBar = withControls( - widget.children - .where((c) => c.isVisible) - .map((c) => c.id), (content, viewModel) { - return CupertinoTabBar( - backgroundColor: widget.control.attrColor("bgColor", context), - activeColor: widget.control.attrColor("activeColor", context) ?? - widget.control.attrColor("indicatorColor", context), - inactiveColor: widget.control.attrColor("inactiveColor", context) ?? - CupertinoColors.inactiveGray, - iconSize: widget.control.attrDouble("iconSize", 30.0)!, - currentIndex: _selectedIndex, - border: parseBorder(Theme.of(context), widget.control, "border"), - onTap: disabled ? null : _onTap, - items: viewModel.controlViews.map((destView) { - var label = destView.control.attrString("label", "")!; - var iconStr = parseIcon(destView.control.attrString("icon")); - var iconCtrls = - destView.children.where((c) => c.name == "icon" && c.isVisible); - var selectedIconStr = - parseIcon(destView.control.attrString("selectedIcon")); - var selectedIconCtrls = destView.children - .where((c) => c.name == "selected_icon" && c.isVisible); - var destinationDisabled = disabled || destView.control.isDisabled; - var destinationTooltip = destView.control.attrString("tooltip"); - return BottomNavigationBarItem( - tooltip: !destinationDisabled && destinationTooltip != null - ? jsonDecode(destinationTooltip) - : null, - backgroundColor: widget.control.attrColor("bgColor", context), - icon: iconCtrls.isNotEmpty - ? createControl(destView.control, iconCtrls.first.id, - destinationDisabled, - parentAdaptive: widget.parentAdaptive) - : Icon(iconStr), - activeIcon: selectedIconCtrls.isNotEmpty - ? createControl(destView.control, - selectedIconCtrls.first.id, destinationDisabled, - parentAdaptive: widget.parentAdaptive) - : selectedIconStr != null - ? Icon(selectedIconStr) - : null, - label: label); - }).toList()); - }); + var navBar = CupertinoTabBar( + backgroundColor: widget.control.getColor("bgcolor", context), + // "indicator_color" from adaptive Material NavBar + activeColor: widget.control.getColor("active_color", context) ?? + widget.control.getColor("indicator_color", context), + inactiveColor: widget.control + .getColor("inactive_color", context, CupertinoColors.inactiveGray)!, + iconSize: widget.control.getDouble("icon_size", 30.0)!, + currentIndex: _selectedIndex, + border: widget.control.getBorder("border", Theme.of(context)), + onTap: widget.control.disabled ? null : _onTap, + items: widget.control.children("destinations").map((dest) { + dest.notifyParent = true; + return BottomNavigationBarItem( + tooltip: !dest.disabled ? dest.getString("tooltip") : null, + backgroundColor: dest.getColor("bgcolor", context), + icon: dest.buildIconOrWidget("icon")!, + activeIcon: dest.buildIconOrWidget("selected_icon"), + label: dest.getString("label", "")!); + }).toList()); - return constrainedControl(context, navBar, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: navBar); } } diff --git a/packages/flet/lib/src/controls/cupertino_picker.dart b/packages/flet/lib/src/controls/cupertino_picker.dart index 0a4435b53f..d4f7ea1de8 100644 --- a/packages/flet/lib/src/controls/cupertino_picker.dart +++ b/packages/flet/lib/src/controls/cupertino_picker.dart @@ -1,65 +1,30 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; - -const double _kItemExtent = 32.0; -const double _kDefaultDiameterRatio = 1.07; -const double _kSqueeze = 1.45; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; class CupertinoPickerControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const CupertinoPickerControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentAdaptive, - required this.parentDisabled, - required this.backend}); + CupertinoPickerControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CupertinoPickerControlState(); } class _CupertinoPickerControlState extends State { - int _index = 0; - int previousIndex = 0; - bool isScrollUp = false; - bool isScrollDown = true; FixedExtentScrollController scrollController = FixedExtentScrollController(); @override void initState() { super.initState(); scrollController = FixedExtentScrollController( - initialItem: widget.control.attrInt("selectedIndex", _index)!); - scrollController.addListener(_manageScroll); - } - - void _manageScroll() { - // https://stackoverflow.com/a/75283541 - // Fixes https://github.com/flet-dev/flet/issues/3649 - if (previousIndex != scrollController.selectedItem) { - isScrollDown = previousIndex < scrollController.selectedItem; - isScrollUp = previousIndex > scrollController.selectedItem; - - var previousIndexTemp = previousIndex; - previousIndex = scrollController.selectedItem; - - if (isScrollUp) { - scrollController.jumpToItem(previousIndexTemp - 1); - } else if (isScrollDown) { - scrollController.jumpToItem(previousIndexTemp + 1); - } - } + initialItem: widget.control.getInt("selected_index", 0)!); } @override @@ -72,48 +37,32 @@ class _CupertinoPickerControlState extends State { Widget build(BuildContext context) { debugPrint("CupertinoPicker build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - List ctrls = widget.children.where((c) => c.isVisible).map((c) { - return Center( - child: createControl(widget.control, c.id, disabled, - parentAdaptive: widget.parentAdaptive)); - }).toList(); - - var selectionOverlayCtrl = widget.children - .where((c) => c.isVisible && c.name == "selection_overlay"); - Widget picker = CupertinoPicker( scrollController: scrollController, - backgroundColor: widget.control.attrColor("bgColor", context), - diameterRatio: - widget.control.attrDouble("diameterRatio", _kDefaultDiameterRatio)!, - magnification: widget.control.attrDouble("magnification", 1.0)!, - squeeze: widget.control.attrDouble("squeeze", _kSqueeze)!, - offAxisFraction: widget.control.attrDouble("offAxisFraction", 0.0)!, - itemExtent: widget.control.attrDouble("itemExtent", _kItemExtent)!, - useMagnifier: widget.control.attrBool("useMagnifier", false)!, - looping: widget.control.attrBool("looping", false)!, - selectionOverlay: selectionOverlayCtrl.isNotEmpty - ? createControl( - widget.control, selectionOverlayCtrl.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : CupertinoPickerDefaultSelectionOverlay( - background: widget.control.attrColor( - "defaultSelectionOverlayBgcolor", - context, - CupertinoColors.tertiarySystemFill)!, - ), + backgroundColor: widget.control.getColor("bgcolor", context), + diameterRatio: widget.control.getDouble("diameter_ratio", 1.07)!, + magnification: widget.control.getDouble("magnification", 1.0)!, + squeeze: widget.control.getDouble("squeeze", 1.45)!, + offAxisFraction: widget.control.getDouble("off_axis_fraction", 0.0)!, + itemExtent: widget.control.getDouble("item_extent", 32.0)!, + useMagnifier: widget.control.getBool("use_magnifier", false)!, + looping: widget.control.getBool("looping", false)!, + selectionOverlay: widget.control.buildWidget("selection_overlay") ?? + CupertinoPickerDefaultSelectionOverlay( + background: widget.control.getColor( + "default_selection_overlay_bgcolor", + context, + CupertinoColors.tertiarySystemFill)!, + ), onSelectedItemChanged: (int index) { - _index = index; - widget.backend.updateControlState( - widget.control.id, {"selectedIndex": index.toString()}); - widget.backend - .triggerControlEvent(widget.control.id, "change", index.toString()); + widget.control.updateProperties({"selected_index": index}); + widget.control.triggerEvent("change", index); }, - children: ctrls, + children: widget.control.children("controls").map((c) { + return Center(child: ControlWidget(control: c)); + }).toList(), ); - return constrainedControl(context, picker, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: picker); } } diff --git a/packages/flet/lib/src/controls/cupertino_radio.dart b/packages/flet/lib/src/controls/cupertino_radio.dart index b8a641b0f6..66c442e907 100644 --- a/packages/flet/lib/src/controls/cupertino_radio.dart +++ b/packages/flet/lib/src/controls/cupertino_radio.dart @@ -1,28 +1,20 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/colors.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; -import 'list_tile.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; class CupertinoRadioControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoRadioControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + CupertinoRadioControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CupertinoRadioControlState(); @@ -40,8 +32,7 @@ class _CupertinoRadioControlState extends State } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @override @@ -51,80 +42,52 @@ class _CupertinoRadioControlState extends State super.dispose(); } - void _onChange(String ancestorId, String? value) { - var svalue = value ?? ""; - debugPrint(svalue); - widget.backend.updateControlState(ancestorId, {"value": svalue}); - widget.backend.triggerControlEvent(ancestorId, "change", svalue); - } - @override Widget build(BuildContext context) { debugPrint("CupertinoRadio build: ${widget.control.id}"); - String label = widget.control.attrString("label", "")!; - String value = widget.control.attrString("value", "")!; - LabelPosition labelPosition = parseLabelPosition( - widget.control.attrString("labelPosition"), LabelPosition.right)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - return withControlAncestor(widget.control.id, "radiogroup", - (context, viewModel) { - debugPrint("CupertinoRadio build: ${widget.control.id}"); - - if (viewModel.ancestor == null) { - return const ErrorControl( - "CupertinoRadio control must be enclosed with RadioGroup."); - } - - String groupValue = viewModel.ancestor!.attrString("value", "")!; - String ancestorId = viewModel.ancestor!.id; - - var cupertinoRadio = CupertinoRadio( - autofocus: autofocus, - focusNode: _focusNode, - groupValue: groupValue, - value: value, - useCheckmarkStyle: - widget.control.attrBool("useCheckmarkStyle", false)!, - fillColor: widget.control.attrColor("fillColor", context), - focusColor: widget.control.attrColor("focusColor", context), - toggleable: widget.control.attrBool("toggleable", false)!, - mouseCursor: - parseMouseCursor(widget.control.attrString("mouseCursor")), - activeColor: parseColor(Theme.of(context), - widget.control.attrString("activeColor", "primary")!), - inactiveColor: widget.control.attrColor("inactiveColor", context), - onChanged: !disabled - ? (String? value) { - _onChange(ancestorId, value); - } - : null); - - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(ancestorId, value); - }); - - Widget result = cupertinoRadio; - if (label != "") { - var labelWidget = disabled - ? Text(label, - style: TextStyle(color: Theme.of(context).disabledColor)) - : MouseRegion(cursor: SystemMouseCursors.click, child: Text(label)); - result = MergeSemantics( - child: GestureDetector( - onTap: !disabled - ? () { - _onChange(ancestorId, value); - } - : null, - child: labelPosition == LabelPosition.right - ? Row(children: [cupertinoRadio, labelWidget]) - : Row(children: [labelWidget, cupertinoRadio]))); - } - - return constrainedControl(context, result, widget.parent, widget.control); - }); + final radioGroup = RadioGroup.maybeOf(context); + if (radioGroup == null) { + return const ErrorControl( + "CupertinoRadio must be enclosed within RadioGroup"); + } + + var value = widget.control.getString("value", "")!; + + var cupertinoRadio = CupertinoRadio( + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + value: value, + useCheckmarkStyle: widget.control.getBool("use_checkmark_style", false)!, + fillColor: widget.control.getColor("fill_color", context), + focusColor: widget.control.getColor("focus_color", context), + toggleable: widget.control.getBool("toggleable", false)!, + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + activeColor: widget.control.getColor( + "active_color", context, Theme.of(context).colorScheme.primary)!, + inactiveColor: widget.control.getColor("inactive_color", context), + ); + + Widget result = cupertinoRadio; + + var label = widget.control.getString("label", "")!; + if (label != "") { + var labelPosition = widget.control + .getLabelPosition("label_position", LabelPosition.right)!; + var labelWidget = widget.control.disabled + ? Text(label, + style: TextStyle(color: Theme.of(context).disabledColor)) + : MouseRegion(cursor: SystemMouseCursors.click, child: Text(label)); + result = MergeSemantics( + child: GestureDetector( + onTap: !widget.control.disabled + ? () => radioGroup.onChanged(value) + : null, + child: labelPosition == LabelPosition.right + ? Row(children: [cupertinoRadio, labelWidget]) + : Row(children: [labelWidget, cupertinoRadio]))); + } + + return LayoutControl(control: widget.control, child: result); } } diff --git a/packages/flet/lib/src/controls/cupertino_segmented_button.dart b/packages/flet/lib/src/controls/cupertino_segmented_button.dart index 7c50175b42..8f3d670f5d 100644 --- a/packages/flet/lib/src/controls/cupertino_segmented_button.dart +++ b/packages/flet/lib/src/controls/cupertino_segmented_button.dart @@ -1,28 +1,18 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class CupertinoSegmentedButtonControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool? parentAdaptive; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoSegmentedButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentAdaptive, - required this.parentDisabled, - required this.backend}); + CupertinoSegmentedButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -30,51 +20,41 @@ class CupertinoSegmentedButtonControl extends StatefulWidget { } class _CupertinoSegmentedButtonControlState - extends State with FletStoreMixin { + extends State { @override Widget build(BuildContext context) { debugPrint("CupertinoSegmentedButtonControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - List ctrls = widget.children.where((c) => c.isVisible).toList(); - int? selectedIndex = widget.control.attrInt("selectedIndex"); + var controls = widget.control.buildWidgets("controls"); + var selectedIndex = widget.control.getInt("selected_index"); - if (ctrls.length < 2) { + if (controls.length < 2) { return const ErrorControl( "CupertinoSegmentedButton must have at minimum two visible controls"); } - var children = ctrls.asMap().map((i, c) => MapEntry( - i, - createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive))); - return constrainedControl( - context, - CupertinoSegmentedControl( - children: children, - groupValue: selectedIndex, - onValueChanged: (int index) { - if (!disabled) { - widget.backend.updateControlState( - widget.control.id, {"selectedIndex": index.toString()}); - widget.backend.triggerControlEvent( - widget.control.id, "change", index.toString()); - setState(() { - selectedIndex = index; - }); - } - }, - borderColor: widget.control.attrColor("borderColor", context), - selectedColor: widget.control.attrColor("selectedColor", context), - unselectedColor: widget.control.attrColor("unselectedColor", context), - pressedColor: widget.control.attrColor("clickColor", context), - disabledColor: widget.control.attrColor("disabledColor", context), - disabledTextColor: widget.control.attrColor("disabledTextColor", context), - padding: parseEdgeInsets(widget.control, "padding"), - ), - widget.parent, - widget.control); + var segmentedButton = CupertinoSegmentedControl( + groupValue: selectedIndex, + borderColor: widget.control.getColor("border_color", context), + selectedColor: widget.control.getColor("selected_color", context), + unselectedColor: widget.control.getColor("unselected_color", context), + pressedColor: widget.control.getColor("click_color", context), + disabledColor: widget.control.getColor("disabled_color", context), + disabledTextColor: + widget.control.getColor("disabled_text_color", context), + padding: widget.control.getPadding("padding"), + children: controls.asMap().map((i, c) => MapEntry(i, c)), + onValueChanged: (int index) { + if (!widget.control.disabled) { + widget.control.updateProperties({"selected_index": index}); + widget.control.triggerEvent("change", index); + setState(() { + selectedIndex = index; + }); + } + }, + ); + + return LayoutControl(control: widget.control, child: segmentedButton); } } diff --git a/packages/flet/lib/src/controls/cupertino_slider.dart b/packages/flet/lib/src/controls/cupertino_slider.dart index 2b6ca75b41..8da3545680 100644 --- a/packages/flet/lib/src/controls/cupertino_slider.dart +++ b/packages/flet/lib/src/controls/cupertino_slider.dart @@ -1,23 +1,16 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; -import '../utils/debouncer.dart'; -import '../utils/platform.dart'; -import 'create_control.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class CupertinoSliderControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoSliderControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + CupertinoSliderControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CupertinoSliderControlState(); @@ -25,37 +18,28 @@ class CupertinoSliderControl extends StatefulWidget { class _CupertinoSliderControlState extends State { double _value = 0; - final _debouncer = Debouncer(milliseconds: isDesktopPlatform() ? 10 : 100); + late FletBackend backend; @override void dispose() { - _debouncer.dispose(); super.dispose(); } void onChange(double value) { - var svalue = value.toString(); - debugPrint(svalue); _value = value; - var props = {"value": svalue}; - widget.backend.updateControlState(widget.control.id, props, server: false); - _debouncer.run(() { - widget.backend.updateControlState(widget.control.id, props); - widget.backend.triggerControlEvent(widget.control.id, "change"); - }); + var props = {"value": value}; + widget.control.updateProperties(props, notify: true); + widget.control.triggerEvent("change"); } @override Widget build(BuildContext context) { debugPrint("CupertinoSliderControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; + double min = widget.control.getDouble("min", 0.0)!; + double max = widget.control.getDouble("max", 1.0)!; - double min = widget.control.attrDouble("min", 0)!; - double max = widget.control.attrDouble("max", 1)!; - int? divisions = widget.control.attrInt("divisions"); - - double value = widget.control.attrDouble("value", min)!; + double value = widget.control.getDouble("value", min)!; if (_value != value) { // verify limits if (value < min) { @@ -71,29 +55,23 @@ class _CupertinoSliderControlState extends State { value: _value, min: min, max: max, - divisions: divisions, - activeColor: widget.control.attrColor("activeColor", context), - thumbColor: widget.control.attrColor("thumbColor", context) ?? - CupertinoColors.white, - onChanged: !disabled - ? (double value) { - onChange(value); - } - : null, - onChangeStart: !disabled + divisions: widget.control.getInt("divisions"), + activeColor: widget.control.getColor("active_color", context), + thumbColor: widget.control + .getColor("thumb_color", context, CupertinoColors.white)!, + onChanged: + !widget.control.disabled ? (double value) => onChange(value) : null, + onChangeStart: !widget.control.disabled ? (double value) { - widget.backend.triggerControlEvent( - widget.control.id, "change_start", value.toString()); + widget.control.triggerEvent("change_start", value); } : null, - onChangeEnd: !disabled + onChangeEnd: !widget.control.disabled ? (double value) { - widget.backend.triggerControlEvent( - widget.control.id, "change_end", value.toString()); + widget.control.triggerEvent("change_end", value); } : null); - return constrainedControl( - context, cupertinoSlider, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: cupertinoSlider); } } diff --git a/packages/flet/lib/src/controls/cupertino_sliding_segmented_button.dart b/packages/flet/lib/src/controls/cupertino_sliding_segmented_button.dart index 847e04baa8..35de6e6f99 100644 --- a/packages/flet/lib/src/controls/cupertino_sliding_segmented_button.dart +++ b/packages/flet/lib/src/controls/cupertino_sliding_segmented_button.dart @@ -1,80 +1,51 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; -class CupertinoSlidingSegmentedButtonControl extends StatefulWidget { - final Control? parent; +class CupertinoSlidingSegmentedButtonControl extends StatelessWidget { final Control control; - final List children; - final bool? parentAdaptive; - final bool parentDisabled; - final FletControlBackend backend; const CupertinoSlidingSegmentedButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentAdaptive, - required this.parentDisabled, - required this.backend}); + {super.key, required this.control}); @override - State createState() => - _CupertinoSlidingSegmentedButtonControlState(); -} - -class _CupertinoSlidingSegmentedButtonControlState - extends State with FletStoreMixin { - @override Widget build(BuildContext context) { - debugPrint( - "CupertinoSlidingSegmentedButtonControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - - List ctrls = widget.children.where((c) => c.isVisible).toList(); + debugPrint("CupertinoSlidingSegmentedButtonControl build: ${control.id}"); - if (ctrls.length < 2) { + var controls = control.buildWidgets("controls"); + if (controls.length < 2) { return const ErrorControl( "CupertinoSlidingSegmentedButton must have at minimum two visible controls"); } - Map children = ctrls.asMap().map((i, c) => MapEntry( - i, - createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive))); var button = CupertinoSlidingSegmentedControl( - children: children, - groupValue: widget.control.attrInt("selectedIndex"), + groupValue: control.getInt("selected_index", 0)!, + proportionalWidth: control.getBool("proportional_width", false)!, + backgroundColor: control.getColor( + "bgcolor", context, CupertinoColors.tertiarySystemFill)!, + padding: control.getPadding( + "padding", const EdgeInsets.symmetric(vertical: 2, horizontal: 3))!, + thumbColor: control.getColor( + "thumb_color", + context, + const CupertinoDynamicColor.withBrightness( + color: Color(0xFFFFFFFF), darkColor: Color(0xFF636366)))!, + children: controls.asMap().map((i, c) => MapEntry(i, c)), onValueChanged: (int? index) { - if (!disabled) { - widget.backend.updateControlState(widget.control.id, - {"selectedIndex": index != null ? index.toString() : ""}); - widget.backend.triggerControlEvent( - widget.control.id, "change", index?.toString()); + if (!control.disabled) { + index = index ?? 0; + control.updateProperties({"selected_index": index}, notify: true); + control.triggerEvent("change", index); } }, - proportionalWidth: widget.control.attrBool("proportionalWidth", false)!, - thumbColor: widget.control.attrColor( - "thumbColor", - context, - const CupertinoDynamicColor.withBrightness( - color: Color(0xFFFFFFFF), - darkColor: Color(0xFF636366), - ))!, - backgroundColor: widget.control - .attrColor("bgColor", context, CupertinoColors.tertiarySystemFill)!, - padding: parseEdgeInsets(widget.control, "padding", - const EdgeInsets.symmetric(vertical: 2, horizontal: 3))!, ); - return constrainedControl(context, button, widget.parent, widget.control); + return LayoutControl(control: control, child: button); } } diff --git a/packages/flet/lib/src/controls/cupertino_switch.dart b/packages/flet/lib/src/controls/cupertino_switch.dart index e2a5f52b27..9a8abf63ff 100644 --- a/packages/flet/lib/src/controls/cupertino_switch.dart +++ b/packages/flet/lib/src/controls/cupertino_switch.dart @@ -1,158 +1,153 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; -import '../utils/box.dart'; import '../utils/colors.dart'; import '../utils/icons.dart'; +import '../utils/images.dart'; +import '../utils/misc.dart'; import '../utils/numbers.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; import 'list_tile.dart'; class CupertinoSwitchControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const CupertinoSwitchControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + CupertinoSwitchControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CupertinoSwitchControlState(); } -class _CupertinoSwitchControlState extends State - with FletStoreMixin { +class _CupertinoSwitchControlState extends State { bool _value = false; late final FocusNode _focusNode; + Listenable? _tileClicksNotifier; @override void initState() { super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); + _focusNode = FocusNode()..addListener(_onFocusChange); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final newNotifier = ListTileClicks.of(context)?.notifier; + + // If the inherited source changed, swap listeners + if (!identical(_tileClicksNotifier, newNotifier)) { + _tileClicksNotifier?.removeListener(_toggleValue); + _tileClicksNotifier = newNotifier; + _tileClicksNotifier?.addListener(_toggleValue); + } } @override void dispose() { _focusNode.removeListener(_onFocusChange); + _tileClicksNotifier?.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } + void _toggleValue() { + _onChange(!_value); + } + void _onChange(bool value) { - var svalue = value.toString(); - debugPrint(svalue); _value = value; - widget.backend.updateControlState(widget.control.id, {"value": svalue}); - widget.backend.triggerControlEvent(widget.control.id, "change", svalue); + var props = {"value": value}; + widget.control.updateProperties(props, notify: true); + widget.control.triggerEvent("change"); } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @override Widget build(BuildContext context) { debugPrint("CupertinoSwitchControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - String label = widget.control.attrString("label", "")!; - LabelPosition labelPosition = parseLabelPosition( - widget.control.attrString("labelPosition"), LabelPosition.right)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; + String label = widget.control.getString("label", "")!; + LabelPosition labelPosition = + widget.control.getLabelPosition("label_position", LabelPosition.right)!; + bool autofocus = widget.control.getBool("autofocus", false)!; - bool value = widget.control.attrBool("value", false)!; + bool value = widget.control.getBool("value", false)!; if (_value != value) { _value = value; } + ThemeData theme = Theme.of(context); + var materialThumbColor = - parseWidgetStateColor(Theme.of(context), widget.control, "thumbColor"); - - var materialTrackColor = - parseWidgetStateColor(Theme.of(context), widget.control, "trackColor"); - var activeThumbImage = widget.control.attrString("activeThumbImage"); - var inactiveThumbImage = widget.control.attrString("inactiveThumbImage"); - - return withPageArgs((context, pageArgs) { - var swtch = CupertinoSwitch( - autofocus: autofocus, - focusNode: _focusNode, - activeTrackColor: - widget.control.attrColor("activeTrackColor", context) ?? - widget.control.attrColor("activeColor", context), - // TODO: deprecated in v0.26.0, remove in v0.29.0 - thumbColor: materialThumbColor?.resolve({}), - trackColor: materialTrackColor?.resolve({}), - focusColor: widget.control.attrColor("focusColor", context), - inactiveTrackColor: - widget.control.attrColor("inactiveTrackColor", context), - inactiveThumbColor: - widget.control.attrColor("inactiveThumbColor", context), - trackOutlineColor: parseWidgetStateColor( - Theme.of(context), widget.control, "trackOutlineColor"), - trackOutlineWidth: - parseWidgetStateDouble(widget.control, "trackOutlineWidth"), - thumbIcon: parseWidgetStateIcon( - Theme.of(context), widget.control, "thumbIcon"), - inactiveThumbImage: getImageProvider( - inactiveThumbImage, inactiveThumbImage, pageArgs), - activeThumbImage: - getImageProvider(activeThumbImage, activeThumbImage, pageArgs), - onActiveThumbImageError: activeThumbImage == null - ? null - : (Object exception, StackTrace? stackTrace) { - widget.backend.triggerControlEvent( - widget.control.id, "image_error", exception.toString()); - }, - onInactiveThumbImageError: inactiveThumbImage == null - ? null - : (Object exception, StackTrace? stackTrace) { - widget.backend.triggerControlEvent( - widget.control.id, "image_error", exception.toString()); - }, - value: _value, - offLabelColor: widget.control.attrColor("offLabelColor", context), - onLabelColor: widget.control.attrColor("onLabelColor", context), - onChanged: !disabled - ? (bool value) { - _onChange(value); - } - : null); - - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(!_value); - }); - - Widget result = swtch; - if (label != "") { - var labelWidget = disabled - ? Text(label, - style: TextStyle(color: Theme.of(context).disabledColor)) - : MouseRegion(cursor: SystemMouseCursors.click, child: Text(label)); - result = MergeSemantics( - child: GestureDetector( - onTap: !disabled - ? () { - _onChange(!_value); - } - : null, - child: labelPosition == LabelPosition.right - ? Row(children: [swtch, labelWidget]) - : Row(children: [labelWidget, swtch]))); - } - - return constrainedControl(context, result, widget.parent, widget.control); - }); + widget.control.getWidgetStateColor("thumb_color", theme); + var activeThumbImage = + widget.control.getImageProvider("active_thumb_image_src", context); + var inactiveThumbImage = + widget.control.getImageProvider("inactive_thumb_image_src", context); + + var swtch = CupertinoSwitch( + autofocus: autofocus, + focusNode: _focusNode, + activeTrackColor: + widget.control.getColor("active_track_color", context), + thumbColor: materialThumbColor?.resolve({}), + focusColor: widget.control.getColor("focusColor", context), + inactiveTrackColor: + widget.control.getColor("inactive_track_color", context), + inactiveThumbColor: + widget.control.getColor("inactive_thumb_color", context), + trackOutlineColor: + widget.control.getWidgetStateColor("track_outline_color", theme), + trackOutlineWidth: + widget.control.getWidgetStateDouble("track_outline_width"), + thumbIcon: widget.control.getWidgetStateIcon("thumb_icon", theme), + inactiveThumbImage: inactiveThumbImage, + activeThumbImage: activeThumbImage, + onActiveThumbImageError: activeThumbImage == null + ? null + : (Object exception, StackTrace? stackTrace) { + widget.control + .triggerEvent("image_error", exception.toString()); + }, + onInactiveThumbImageError: inactiveThumbImage == null + ? null + : (Object exception, StackTrace? stackTrace) { + widget.control + .triggerEvent("image_error", exception.toString()); + }, + value: _value, + offLabelColor: widget.control.getColor("off_label_color", context), + onLabelColor: widget.control.getColor("on_label_color", context), + onChanged: !widget.control.disabled + ? (bool value) { + _onChange(value); + } + : null); + + Widget result = swtch; + if (label != "") { + var labelWidget = widget.control.disabled + ? Text(label, + style: TextStyle(color: Theme.of(context).disabledColor)) + : MouseRegion(cursor: SystemMouseCursors.click, child: Text(label)); + result = MergeSemantics( + child: GestureDetector( + onTap: !widget.control.disabled + ? () { + _onChange(!_value); + } + : null, + child: labelPosition == LabelPosition.right + ? Row(children: [swtch, labelWidget]) + : Row(children: [labelWidget, swtch]))); + } + + return LayoutControl(control: widget.control, child: result); + //}); } } diff --git a/packages/flet/lib/src/controls/cupertino_textfield.dart b/packages/flet/lib/src/controls/cupertino_textfield.dart index 551a9b48de..62bdb0e163 100644 --- a/packages/flet/lib/src/controls/cupertino_textfield.dart +++ b/packages/flet/lib/src/controls/cupertino_textfield.dart @@ -2,47 +2,37 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/autofill.dart'; import '../utils/borders.dart'; import '../utils/box.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/form_field.dart'; import '../utils/gradient.dart'; import '../utils/images.dart'; -import '../utils/others.dart'; -import '../utils/overlay_style.dart'; +import '../utils/layout.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../utils/platform.dart'; import '../utils/text.dart'; import '../utils/textfield.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; -import 'textfield.dart'; +import '../utils/theme.dart'; +import 'base_controls.dart'; class CupertinoTextFieldControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const CupertinoTextFieldControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + CupertinoTextFieldControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _CupertinoTextFieldControlState(); } -class _CupertinoTextFieldControlState extends State - with FletStoreMixin { +class _CupertinoTextFieldControlState extends State { String _value = ""; bool _focused = false; bool _revealPassword = false; @@ -51,130 +41,166 @@ class _CupertinoTextFieldControlState extends State late final FocusNode _shiftEnterfocusNode; String? _lastFocusValue; String? _lastBlurValue; + TextSelection? _selection; + + KeyEventResult _handleTextFieldKeyEvent(KeyEvent event, + {required bool submitOnEnter}) { + // ignore up/down arrow keys if flag is set + if ((event is KeyDownEvent || event is KeyRepeatEvent) && + widget.control.getBool("ignore_up_down_keys", false)! && + (event.logicalKey == LogicalKeyboardKey.arrowUp || + event.logicalKey == LogicalKeyboardKey.arrowDown)) { + return KeyEventResult.handled; + } + + // submit on Enter if flag is set and shift is not pressed + if (submitOnEnter && + event is KeyDownEvent && + !HardwareKeyboard.instance.isShiftPressed && + (event.logicalKey == LogicalKeyboardKey.enter || + event.logicalKey == LogicalKeyboardKey.numpadEnter)) { + widget.control.triggerEvent("submit"); + return KeyEventResult.handled; + } + + // let the system handle other key events + return KeyEventResult.ignored; + } @override void initState() { super.initState(); _controller = TextEditingController(); + _controller.addListener(_handleControllerChange); _shiftEnterfocusNode = FocusNode( - onKeyEvent: (FocusNode node, KeyEvent evt) { - if (!HardwareKeyboard.instance.isShiftPressed && - evt.logicalKey.keyLabel == 'Enter') { - if (evt is KeyDownEvent) { - widget.backend.triggerControlEvent(widget.control.id, "submit"); - } - return KeyEventResult.handled; - } else { - return KeyEventResult.ignored; - } - }, + onKeyEvent: (FocusNode node, KeyEvent event) => + _handleTextFieldKeyEvent(event, submitOnEnter: true), ); _shiftEnterfocusNode.addListener(_onShiftEnterFocusChange); - _focusNode = FocusNode(); + _focusNode = FocusNode( + onKeyEvent: (FocusNode node, KeyEvent event) => + _handleTextFieldKeyEvent(event, submitOnEnter: false), + ); _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); } @override void dispose() { + _controller.removeListener(_handleControllerChange); _controller.dispose(); _shiftEnterfocusNode.removeListener(_onShiftEnterFocusChange); _shiftEnterfocusNode.dispose(); _focusNode.removeListener(_onFocusChange); + widget.control.removeInvokeMethodListener(_invokeMethod); _focusNode.dispose(); super.dispose(); } + Future _invokeMethod(String name, dynamic args) async { + debugPrint("CupertinoTextField.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown CupertinoTextField method: $name"); + } + } + void _onShiftEnterFocusChange() { setState(() { _focused = _shiftEnterfocusNode.hasFocus; }); - widget.backend.triggerControlEvent( - widget.control.id, _shiftEnterfocusNode.hasFocus ? "focus" : "blur"); + widget.control + .triggerEvent(_shiftEnterfocusNode.hasFocus ? "focus" : "blur"); } void _onFocusChange() { setState(() { _focused = _focusNode.hasFocus; }); - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + void _handleControllerChange() { + final selection = _controller.selection; + if (_selection == selection) return; + + _selection = selection; + + if (!selection.isValid || + !widget.control.getBool("on_selection_change", false)!) { + return; + } + + widget.control.updateProperties({"selection": selection.toMap()}); + widget.control.triggerEvent("selection_change", { + "selected_text": + _controller.text.substring(selection.start, selection.end), + "selection": selection.toMap() + }); } @override Widget build(BuildContext context) { debugPrint("CupertinoTextField build: ${widget.control.id}"); - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - debugPrint("CupertinoTextField StoreConnector build: ${widget.control.id}"); - - String value = widget.control.attrs["value"] ?? ""; + var autofocus = widget.control.getBool("autofocus", false)!; + var value = widget.control.getString("value", "")!; if (_value != value) { _value = value; - _controller.text = value; + _controller.value = TextEditingValue( + text: value, + // preserve cursor position at the end + selection: TextSelection.collapsed(offset: value.length), + ); + _selection = _controller.selection; } - var prefixControls = - widget.children.where((c) => c.name == "prefix" && c.isVisible); - var suffixControls = - widget.children.where((c) => c.name == "suffix" && c.isVisible); + var shiftEnter = widget.control.getBool("shift_enter", false)!; + var multiline = widget.control.getBool("multiline", false)! || shiftEnter; + var minLines = widget.control.getInt("min_lines", 1)!; + var maxLines = widget.control.getInt("max_lines", multiline ? null : 1); - bool shiftEnter = widget.control.attrBool("shiftEnter", false)!; - bool multiline = widget.control.attrBool("multiline", false)! || shiftEnter; - int minLines = widget.control.attrInt("minLines", 1)!; - int? maxLines = widget.control.attrInt("maxLines", multiline ? null : 1); + var readOnly = widget.control.getBool("read_only", false)!; + var password = widget.control.getBool("password", false)!; + var onChange = widget.control.getBool("on_change", false)!; - bool readOnly = widget.control.attrBool("readOnly", false)!; - bool password = widget.control.attrBool("password", false)!; - bool onChange = widget.control.attrBool("onChange", false)!; + var cursorColor = widget.control.getColor("cursor_color", context); + var selectionColor = widget.control.getColor("selection_color", context); - var cursorColor = widget.control.attrColor("cursorColor", context); - var selectionColor = widget.control.attrColor("selectionColor", context); + var maxLength = widget.control.getInt("max_length"); - int? maxLength = widget.control.attrInt("maxLength"); + var textSize = widget.control.getDouble("text_size"); - var textSize = widget.control.attrDouble("textSize"); + var color = widget.control.getColor("color", context); + var focusedColor = widget.control.getColor("focused_color", context); - var color = widget.control.attrColor("color", context); - var focusedColor = widget.control.attrColor("focusedColor", context); - - TextStyle? textStyle = - parseTextStyle(Theme.of(context), widget.control, "textStyle"); + var textStyle = + widget.control.getTextStyle("text_style", Theme.of(context)); if (textSize != null || color != null || focusedColor != null) { textStyle = (textStyle ?? const TextStyle()).copyWith( fontSize: textSize, color: _focused ? focusedColor ?? color : color); } - TextCapitalization textCapitalization = parseTextCapitalization( - widget.control.attrString("textCapitalization"), - TextCapitalization.none)!; - - FilteringTextInputFormatter? inputFilter = - parseInputFilter(widget.control, "inputFilter"); - - List? inputFormatters = []; - // add non-null input formatters + List inputFormatters = []; + var inputFilter = widget.control.getTextInputFormatter("input_filter"); if (inputFilter != null) { inputFormatters.add(inputFilter); } + var textCapitalization = widget.control + .getTextCapitalization("capitalization", TextCapitalization.none)!; if (textCapitalization != TextCapitalization.none) { inputFormatters.add(TextCapitalizationFormatter(textCapitalization)); } - - TextAlign textAlign = parseTextAlign( - widget.control.attrString("textAlign"), TextAlign.start)!; - - double? textVerticalAlign = widget.control.attrDouble("textVerticalAlign"); - - bool rtl = widget.control.attrBool("rtl", false)!; - bool autocorrect = widget.control.attrBool("autocorrect", true)!; - ; - + var textAlign = widget.control.getTextAlign("text_align", TextAlign.start)!; + var textVerticalAlign = widget.control.getDouble("text_vertical_align"); + var rtl = widget.control.getBool("rtl", false)!; + var autocorrect = widget.control.getBool("autocorrect", true)!; FocusNode focusNode = shiftEnter ? _shiftEnterfocusNode : _focusNode; - var focusValue = widget.control.attrString("focus"); - var blurValue = widget.control.attrString("blur"); + var focusValue = widget.control.getString("focus"); + var blurValue = widget.control.getString("blur"); if (focusValue != null && focusValue != _lastFocusValue) { _lastFocusValue = focusValue; focusNode.requestFocus(); @@ -184,20 +210,26 @@ class _CupertinoTextFieldControlState extends State _focusNode.unfocus(); } - BorderRadius? borderRadius = - parseBorderRadius(widget.control, "borderRadius"); + var selection = widget.control.getTextSelection("selection", + minOffset: 0, maxOffset: _controller.text.length); + if (selection != null && selection != _controller.selection) { + _controller.selection = selection; + _selection = selection; + } + + var borderRadius = widget.control.getBorderRadius("border_radius"); BoxBorder? border; - double borderWidth = widget.control.attrDouble("borderWidth") ?? 1.0; - Color borderColor = widget.control.attrColor("borderColor", context) ?? + var borderWidth = widget.control.getDouble("border_width", 1.0)!; + var borderColor = widget.control.getColor("border_color", context) ?? const Color(0xFF000000); try { - border = parseBorder(Theme.of(context), widget.control, "border"); + border = widget.control.getBorder("border", Theme.of(context)); // adaptive TextField is being created } catch (e) { FormFieldInputBorder inputBorder = parseFormFieldInputBorder( - widget.control.attrString("border"), + widget.control.getString("border"), FormFieldInputBorder.outline, )!; @@ -210,17 +242,17 @@ class _CupertinoTextFieldControlState extends State } } - bool canRevealPassword = - widget.control.attrBool("canRevealPassword", false)!; + var canRevealPassword = + widget.control.getBool("can_reveal_password", false)!; Widget? revealPasswordIcon; if (password && canRevealPassword) { revealPasswordIcon = Padding( padding: const EdgeInsets.only(right: 15.0), child: GestureDetector( - child: Icon( - _revealPassword ? CupertinoIcons.eye_slash : CupertinoIcons.eye, - ), + child: Icon(_revealPassword + ? CupertinoIcons.eye_slash + : CupertinoIcons.eye), onTap: () { setState(() { _revealPassword = !_revealPassword; @@ -228,145 +260,136 @@ class _CupertinoTextFieldControlState extends State }), ); } - var fitParentSize = widget.control.attrBool("fitParentSize", false)!; - BoxDecoration? defaultDecoration = const CupertinoTextField().decoration; - var gradient = parseGradient(Theme.of(context), widget.control, "gradient"); - var blendMode = parseBlendMode(widget.control.attrString("blendMode")); - - var bgColor = widget.control.attrColor("bgColor", context); - - return withPageArgs((context, pageArgs) { - Widget textField = CupertinoTextField( - style: textStyle, - textAlignVertical: textVerticalAlign != null - ? TextAlignVertical(y: textVerticalAlign) - : null, - placeholder: widget.control.attrString("placeholderText") ?? - widget.control.attrString("label"), - // use label for adaptive TextField - placeholderStyle: parseTextStyle(Theme.of(context), widget.control, "placeholderStyle") ?? - parseTextStyle(Theme.of(context), widget.control, "labelStyle"), - // labelStyle for adaptive TextField - autofocus: autofocus, - enabled: !disabled, - onSubmitted: !multiline - ? (String value) { - widget.backend - .triggerControlEvent(widget.control.id, "submit", value); - } - : null, - decoration: defaultDecoration?.copyWith( - color: bgColor, - gradient: gradient, - image: parseDecorationImage( - Theme.of(context), widget.control, "image", pageArgs), - backgroundBlendMode: - bgColor != null || gradient != null ? blendMode : null, - border: border, - borderRadius: borderRadius, - boxShadow: - parseBoxShadow(Theme.of(context), widget.control, "shadow")), - cursorHeight: widget.control.attrDouble("cursorHeight"), - showCursor: widget.control.attrBool("showCursor"), - cursorWidth: widget.control.attrDouble("cursorWidth", 2.0)!, - cursorRadius: parseRadius( - widget.control, "cursorRadius", const Radius.circular(2.0))!, - keyboardType: multiline - ? TextInputType.multiline - : parseTextInputType(widget.control.attrString("keyboardType"), - TextInputType.text)!, - clearButtonSemanticLabel: - widget.control.attrString("clearButtonSemanticsLabel"), - autocorrect: autocorrect, - enableSuggestions: - widget.control.attrBool("enableSuggestions", true)!, - smartDashesType: widget.control.attrBool("smartDashesType", true)! - ? SmartDashesType.enabled - : SmartDashesType.disabled, - smartQuotesType: widget.control.attrBool("smartQuotesType", true)! - ? SmartQuotesType.enabled - : SmartQuotesType.disabled, - suffixMode: parseVisibilityMode( - widget.control.attrString("suffixVisibilityMode"), - OverlayVisibilityMode.always)!, - prefixMode: parseVisibilityMode( - widget.control.attrString("prefixVisibilityMode"), - OverlayVisibilityMode.always)!, - textAlign: textAlign, - minLines: fitParentSize ? null : minLines, - maxLines: fitParentSize ? null : maxLines, - maxLength: maxLength, - prefix: prefixControls.isNotEmpty - ? createControl(widget.control, prefixControls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - suffix: revealPasswordIcon ?? (suffixControls.isNotEmpty ? createControl(widget.control, suffixControls.first.id, disabled, parentAdaptive: widget.parentAdaptive) : null), - readOnly: readOnly, - textDirection: rtl ? TextDirection.rtl : null, - inputFormatters: inputFormatters.isNotEmpty ? inputFormatters : null, - obscureText: password && !_revealPassword, - padding: parseEdgeInsets(widget.control, "padding", const EdgeInsets.all(7.0))!, - scribbleEnabled: widget.control.attrBool("enableScribble", true)!, - scrollPadding: parseEdgeInsets(widget.control, "scrollPadding", const EdgeInsets.all(20.0))!, - obscuringCharacter: widget.control.attrString("obscuringCharacter", '•')!, - cursorOpacityAnimates: widget.control.attrBool("animateCursorOpacity", Theme.of(context).platform == TargetPlatform.iOS)!, - expands: fitParentSize, - enableIMEPersonalizedLearning: widget.control.attrBool("enableIMEPersonalizedLearning", true)!, - clipBehavior: parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!, - cursorColor: cursorColor, - autofillHints: parseAutofillHints(widget.control, "autofillHints"), - keyboardAppearance: parseBrightness(widget.control.attrString("keyboardBrightness")), - enableInteractiveSelection: widget.control.attrBool("enableInteractiveSelection"), - clearButtonMode: parseVisibilityMode(widget.control.attrString("clearButtonVisibilityMode"), OverlayVisibilityMode.never)!, - strutStyle: parseStrutStyle(widget.control, "strutStyle"), - onTap: () { - widget.backend.triggerControlEvent(widget.control.id, "click"); - }, - controller: _controller, - focusNode: focusNode, - onTapOutside: widget.control.attrBool("onTapOutside", false)! - ? (PointerDownEvent? event) { - widget.backend - .triggerControlEvent(widget.control.id, "tapOutside"); - } - : null, - onChanged: (String value) { - //debugPrint(value); - _value = value; - widget.backend - .updateControlState(widget.control.id, {"value": value}); - if (onChange) { - widget.backend - .triggerControlEvent(widget.control.id, "change", value); - } - }); - - if (cursorColor != null || selectionColor != null) { - textField = TextSelectionTheme( - data: TextSelectionTheme.of(context).copyWith( - cursorColor: cursorColor, selectionColor: selectionColor), - child: textField); - } + var fitParentSize = widget.control.getBool("fit_parent_size", false)!; + var defaultDecoration = const CupertinoTextField().decoration; + var gradient = widget.control.getGradient("gradient", Theme.of(context)); + var blendMode = widget.control.getBlendMode("blend_mode"); + var bgcolor = widget.control.getColor("bgcolor", context); + var label = widget.control.get("label"); + String? labelStr; + if (label is String) { + labelStr = widget.control.getString("label"); + } + + Widget textField = CupertinoTextField( + style: textStyle, + textAlignVertical: textVerticalAlign != null + ? TextAlignVertical(y: textVerticalAlign) + : null, + placeholder: widget.control.getString("placeholder_text") ?? labelStr, + placeholderStyle: + widget.control.getTextStyle("placeholder_style", Theme.of(context)) ?? + widget.control.getTextStyle("label_style", Theme.of(context)), + // label_style for adaptive TextField + autofocus: autofocus, + enabled: !widget.control.disabled, + onSubmitted: !multiline + ? (String value) { + widget.control.triggerEvent("submit", value); + } + : null, + decoration: defaultDecoration?.copyWith( + color: bgcolor, + gradient: gradient, + image: widget.control.getDecorationImage("image", context), + backgroundBlendMode: + bgcolor != null || gradient != null ? blendMode : null, + border: border, + borderRadius: borderRadius, + boxShadow: + widget.control.getBoxShadows("shadows", Theme.of(context))), + cursorHeight: widget.control.getDouble("cursor_height"), + showCursor: widget.control.getBool("show_cursor"), + cursorWidth: widget.control.getDouble("cursor_width", 2.0)!, + cursorRadius: widget.control + .getRadius("cursor_radius", const Radius.circular(2.0))!, + keyboardType: multiline + ? TextInputType.multiline + : widget.control + .getTextInputType("keyboard_type", TextInputType.text)!, + clearButtonSemanticLabel: + widget.control.getString("clear_button_semantics_label"), + autocorrect: autocorrect, + enableSuggestions: widget.control.getBool("enable_suggestions", true)!, + smartDashesType: widget.control.getBool("smart_dashes_type", true)! + ? SmartDashesType.enabled + : SmartDashesType.disabled, + smartQuotesType: widget.control.getBool("smart_quotes_type", true)! + ? SmartQuotesType.enabled + : SmartQuotesType.disabled, + suffixMode: widget.control.getOverlayVisibilityMode( + "suffix_visibility_mode", OverlayVisibilityMode.always)!, + prefixMode: widget.control.getOverlayVisibilityMode( + "prefix_visibility_mode", OverlayVisibilityMode.always)!, + textAlign: textAlign, + minLines: fitParentSize ? null : minLines, + maxLines: fitParentSize ? null : maxLines, + maxLength: maxLength, + prefix: widget.control.buildTextOrWidget("prefix"), + suffix: + revealPasswordIcon ?? widget.control.buildTextOrWidget("suffix"), + readOnly: readOnly, + textDirection: rtl ? TextDirection.rtl : null, + inputFormatters: inputFormatters.isNotEmpty ? inputFormatters : null, + obscureText: password && !_revealPassword, + padding: + widget.control.getPadding("padding", const EdgeInsets.all(7.0))!, + stylusHandwritingEnabled: + widget.control.getBool("enable_stylus_handwriting", true)!, + scrollPadding: widget.control + .getPadding("scroll_padding", const EdgeInsets.all(20.0))!, + obscuringCharacter: + widget.control.getString("obscuring_character", '•')!, + cursorOpacityAnimates: + widget.control.getBool("animate_cursor_opacity", isIOSMobile())!, + expands: fitParentSize, + enableIMEPersonalizedLearning: + widget.control.getBool("enable_ime_personalized_learning", true)!, + clipBehavior: + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!, + cursorColor: cursorColor, + autofillHints: widget.control.getAutofillHints("autofill_hints"), + keyboardAppearance: widget.control.getBrightness("keyboard_brightness"), + enableInteractiveSelection: + widget.control.getBool("enable_interactive_selection"), + clearButtonMode: widget.control.getOverlayVisibilityMode("clear_button_visibility_mode", OverlayVisibilityMode.never)!, + strutStyle: widget.control.getStrutStyle("strut_style"), + onTap: () => widget.control.triggerEvent("click"), + controller: _controller, + focusNode: focusNode, + onTapOutside: widget.control.getBool("on_tap_outside", false)! + ? (PointerDownEvent? event) { + widget.control.triggerEvent("tap_outside"); + } + : null, + onChanged: (String value) { + _value = value; + widget.control.updateProperties({"value": value}); + if (onChange) { + widget.control.triggerEvent("change", value); + } + }); + + if (cursorColor != null || selectionColor != null) { + textField = TextSelectionTheme( + data: TextSelectionTheme.of(context).copyWith( + cursorColor: cursorColor, selectionColor: selectionColor), + child: textField); + } - if (widget.control.attrInt("expand", 0)! > 0) { - return constrainedControl( - context, textField, widget.parent, widget.control); - } else { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if (constraints.maxWidth == double.infinity && - widget.control.attrDouble("width") == null) { - textField = ConstrainedBox( + if (widget.control.getExpand("expand", 0)! > 0) { + return LayoutControl(control: widget.control, child: textField); + } else { + double? width = widget.control.getDouble("width"); + + return LayoutControl( + control: widget.control, + child: width == null + ? ConstrainedBox( constraints: const BoxConstraints.tightFor(width: 300), - child: textField, - ); - } - - return constrainedControl( - context, textField, widget.parent, widget.control); - }, - ); - } - }); + child: textField) + : textField, + ); + } } } diff --git a/packages/flet/lib/src/controls/cupertino_timer_picker.dart b/packages/flet/lib/src/controls/cupertino_timer_picker.dart index bde0d47db8..5d877f7026 100644 --- a/packages/flet/lib/src/controls/cupertino_timer_picker.dart +++ b/packages/flet/lib/src/controls/cupertino_timer_picker.dart @@ -1,24 +1,17 @@ import 'package:flutter/cupertino.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import 'base_controls.dart'; class CupertinoTimerPickerControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - - const CupertinoTimerPickerControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + CupertinoTimerPickerControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -31,26 +24,25 @@ class _CupertinoTimerPickerControlState Widget build(BuildContext context) { debugPrint("CupertinoTimerPicker build: ${widget.control.id}"); - int value = widget.control.attrInt("value", 0)!; - Duration initialTimerDuration = Duration(seconds: value); - Widget picker = CupertinoTimerPicker( - mode: parseCupertinoTimerPickerMode( - widget.control.attrString("mode"), CupertinoTimerPickerMode.hms)!, - initialTimerDuration: initialTimerDuration, - minuteInterval: widget.control.attrInt("minuteInterval", 1)!, - secondInterval: widget.control.attrInt("secondInterval", 1)!, - itemExtent: widget.control.attrDouble("itemExtent", 32.0)!, - alignment: parseAlignment(widget.control, "alignment", Alignment.center)!, - backgroundColor: widget.control.attrColor("bgColor", context), - onTimerDurationChanged: (Duration d) { - widget.backend.updateControlState( - widget.control.id, {"value": d.inSeconds.toString()}); - widget.backend.triggerControlEvent( - widget.control.id, "change", d.inSeconds.toString()); + mode: widget.control + .getCupertinoTimerPickerMode("mode", CupertinoTimerPickerMode.hms)!, + initialTimerDuration: widget.control + .getDuration("value", Duration.zero, DurationUnit.seconds)!, + minuteInterval: widget.control.getInt("minute_interval", 1)!, + secondInterval: widget.control.getInt("second_interval", 1)!, + itemExtent: widget.control.getDouble("item_extent", 32.0)!, + alignment: widget.control.getAlignment("alignment", Alignment.center)!, + backgroundColor: widget.control.getColor("bgcolor", context), + onTimerDurationChanged: (duration) { + // preserve (original) value's type + final d = + widget.control.get("value") is int ? duration.inSeconds : duration; + widget.control.updateProperties({"value": d}); + widget.control.triggerEvent("change", d); }, ); - return constrainedControl(context, picker, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: picker); } } diff --git a/packages/flet/lib/src/controls/datatable.dart b/packages/flet/lib/src/controls/datatable.dart index 2919888f3a..35a721523e 100644 --- a/packages/flet/lib/src/controls/datatable.dart +++ b/packages/flet/lib/src/controls/datatable.dart @@ -1,207 +1,133 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; import '../utils/borders.dart'; import '../utils/colors.dart'; +import '../utils/events.dart'; import '../utils/gradient.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/tooltip.dart'; +import 'base_controls.dart'; -class DataTableControl extends StatefulWidget { - final Control? parent; +class DataTableControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - - const DataTableControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); - @override - State createState() => _DataTableControlState(); -} + const DataTableControl({super.key, required this.control}); -class _DataTableControlState extends State - with FletStoreMixin { @override Widget build(BuildContext context) { - debugPrint("DataTableControl build: ${widget.control.id}"); + debugPrint("DataTableControl build: ${control.id}"); - bool tableDisabled = widget.control.isDisabled || widget.parentDisabled; + var theme = Theme.of(context); + var bgcolor = control.getString("bgcolor"); + var border = control.getBorder("border", theme); + var borderRadius = control.getBorderRadius("border_radius"); + var gradient = control.getGradient("gradient", theme); + var horizontalLines = control.getBorderSide("horizontal_lLines", theme); + var verticalLines = control.getBorderSide("vertical_lines", theme); + var defaultDecoration = theme.dataTableTheme.decoration as BoxDecoration? ?? + const BoxDecoration(); - var datatable = - withControls(widget.children.where((c) => c.isVisible).map((c) => c.id), - (content, viewModel) { - var bgColor = widget.control.attrString("bgColor"); - var border = parseBorder(Theme.of(context), widget.control, "border"); - var borderRadius = parseBorderRadius(widget.control, "borderRadius"); - var gradient = - parseGradient(Theme.of(context), widget.control, "gradient"); - var horizontalLines = - parseBorderSide(Theme.of(context), widget.control, "horizontalLines"); - var verticalLines = - parseBorderSide(Theme.of(context), widget.control, "verticalLines"); - var defaultDecoration = - Theme.of(context).dataTableTheme.decoration ?? const BoxDecoration(); + BoxDecoration? decoration; - BoxDecoration? decoration; - if (bgColor != null || - border != null || - borderRadius != null || - gradient != null) { - decoration = (defaultDecoration as BoxDecoration).copyWith( - color: parseColor(Theme.of(context), bgColor), - border: border, - borderRadius: borderRadius, - gradient: gradient); - } + if (bgcolor != null || + border != null || + borderRadius != null || + gradient != null) { + decoration = defaultDecoration.copyWith( + color: parseColor(bgcolor, theme), + border: border, + borderRadius: borderRadius, + gradient: gradient); + } - TableBorder? tableBorder; - if (horizontalLines != null || verticalLines != null) { - tableBorder = TableBorder( - horizontalInside: horizontalLines ?? BorderSide.none, - verticalInside: verticalLines ?? BorderSide.none); - } - - Clip clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!; - - return DataTable( - decoration: decoration, - border: tableBorder, - clipBehavior: clipBehavior, - checkboxHorizontalMargin: - widget.control.attrDouble("checkboxHorizontalMargin"), - columnSpacing: widget.control.attrDouble("columnSpacing"), - dataRowColor: parseWidgetStateColor( - Theme.of(context), widget.control, "dataRowColor"), - dataRowMinHeight: widget.control.attrDouble("dataRowMinHeight"), - dataRowMaxHeight: widget.control.attrDouble("dataRowMaxHeight"), - dataTextStyle: parseTextStyle( - Theme.of(context), widget.control, "dataTextStyle"), - headingRowColor: parseWidgetStateColor( - Theme.of(context), widget.control, "headingRowColor"), - headingRowHeight: widget.control.attrDouble("headingRowHeight"), - headingTextStyle: parseTextStyle( - Theme.of(context), widget.control, "headingTextStyle"), - dividerThickness: widget.control.attrDouble("dividerThickness"), - horizontalMargin: widget.control.attrDouble("horizontalMargin"), - showBottomBorder: widget.control.attrBool("showBottomBorder", false)!, - showCheckboxColumn: - widget.control.attrBool("showCheckboxColumn", false)!, - sortAscending: widget.control.attrBool("sortAscending", false)!, - sortColumnIndex: widget.control.attrInt("sortColumnIndex"), - onSelectAll: widget.control.attrBool("onSelectAll", false)! - ? (bool? selected) { - widget.backend.triggerControlEvent( - widget.control.id, "select_all", selected?.toString()); - } + var datatable = DataTable( + decoration: decoration ?? defaultDecoration, + border: (horizontalLines != null || verticalLines != null) + ? TableBorder( + horizontalInside: horizontalLines ?? BorderSide.none, + verticalInside: verticalLines ?? BorderSide.none) + : null, + clipBehavior: parseClip(control.getString("clip_behavior"), Clip.none)!, + checkboxHorizontalMargin: control.getDouble("checkbox_horizontal_margin"), + columnSpacing: control.getDouble("column_spacing"), + dataRowColor: control.getWidgetStateColor("data_row_color", theme), + dataRowMinHeight: control.getDouble("data_row_min_height"), + dataRowMaxHeight: control.getDouble("data_row_max_height"), + dataTextStyle: control.getTextStyle("data_text_style", theme), + headingRowColor: control.getWidgetStateColor("heading_row_color", theme), + headingRowHeight: control.getDouble("heading_row_height"), + headingTextStyle: control.getTextStyle("heading_text_style", theme), + dividerThickness: control.getDouble("divider_thickness"), + horizontalMargin: control.getDouble("horizontal_margin"), + showBottomBorder: control.getBool("show_bottom_border", false)!, + showCheckboxColumn: control.getBool("show_checkbox_column", false)!, + sortAscending: control.getBool("sort_ascending", false)!, + sortColumnIndex: control.getInt("sort_column_index"), + onSelectAll: control.getBool("on_select_all", false)! + ? (bool? selected) => control.triggerEvent("select_all", selected) + : null, + columns: control.children("columns").map((column) { + column.notifyParent = true; + var tooltip = + parseTooltip(column.get("tooltip"), context, const Placeholder()); + return DataColumn( + numeric: column.getBool("numeric", false)!, + tooltip: tooltip?.message, + headingRowAlignment: + column.getMainAxisAlignment("heading_row_alignment"), + mouseCursor: WidgetStateMouseCursor.clickable, + onSort: column.getBool("on_sort", false)! + ? (columnIndex, ascending) => column + .triggerEvent("sort", {"ci": columnIndex, "asc": ascending}) + : null, + label: column.buildTextOrWidget("label")!, + ); + }).toList(), + rows: control.children("rows").map((row) { + row.notifyParent = true; + return DataRow( + key: ValueKey(row.id), + selected: row.getBool("selected", false)!, + color: row.getWidgetStateColor("color", theme), + onSelectChanged: row.getBool("on_select_change", false)! + ? (selected) => row.triggerEvent("select_change", selected) + : null, + onLongPress: row.getBool("on_long_press", false)! + ? () => row.triggerEvent("long_press") : null, - columns: viewModel.controlViews - .where( - (c) => c.control.type == "datacolumn" && c.control.isVisible) - .map((column) { - var labelCtrls = - column.children.where((c) => c.name == "label" && c.isVisible); - return DataColumn( - numeric: column.control.attrBool("numeric", false)!, - tooltip: column.control.attrString("tooltip"), - headingRowAlignment: parseMainAxisAlignment( - column.control.attrString("headingRowAlignment")), - mouseCursor: WidgetStateMouseCursor.clickable, - onSort: column.control.attrBool("onSort", false)! - ? (columnIndex, ascending) { - widget.backend.triggerControlEvent( - column.control.id, - "sort", - json.encode({"i": columnIndex, "a": ascending})); - } - : null, - label: createControl(column.control, labelCtrls.first.id, - column.control.isDisabled || tableDisabled)); + cells: row.children("cells").map((cell) { + cell.notifyParent = true; + return DataCell( + cell.buildTextOrWidget("content")!, + placeholder: cell.getBool("placeholder", false)!, + showEditIcon: cell.getBool("show_edit_icon", false)!, + onDoubleTap: cell.getBool("on_double_tap", false)! + ? () => cell.triggerEvent("double_tap") + : null, + onLongPress: cell.getBool("on_long_press", false)! + ? () => cell.triggerEvent("long_press") + : null, + onTap: cell.getBool("on_tap", false)! + ? () => cell.triggerEvent("tap") + : null, + onTapCancel: cell.getBool("on_tap_cancel", false)! + ? () => cell.triggerEvent("tap_cancel") + : null, + onTapDown: cell.getBool("on_tap_down", false)! + ? (TapDownDetails details) => + cell.triggerEvent("tap_down", details.toMap()) + : null, + ); }).toList(), - rows: viewModel.controlViews - .where((c) => c.control.type == "datarow" && c.control.isVisible) - .map((row) { - return DataRow( - key: ValueKey(row.control.id), - selected: row.control.attrBool("selected", false)!, - color: parseWidgetStateColor( - Theme.of(context), row.control, "color"), - onSelectChanged: row.control.attrBool("onSelectChanged", false)! - ? (selected) { - widget.backend.triggerControlEvent(row.control.id, - "select_changed", selected?.toString()); - } - : null, - onLongPress: row.control.attrBool("onLongPress", false)! - ? () { - widget.backend - .triggerControlEvent(row.control.id, "long_press"); - } - : null, - cells: row.children - .where((c) => c.type == "datacell" && c.isVisible) - .map((cell) => DataCell( - createControl(row.control, cell.childIds.first, - row.control.isDisabled || tableDisabled), - placeholder: cell.attrBool("placeholder", false)!, - showEditIcon: cell.attrBool("showEditIcon", false)!, - onDoubleTap: cell.attrBool("onDoubleTap", false)! - ? () { - widget.backend.triggerControlEvent( - cell.id, "double_tap"); - } - : null, - onLongPress: cell.attrBool("onLongPress", false)! - ? () { - widget.backend.triggerControlEvent( - cell.id, "long_press"); - } - : null, - onTap: cell.attrBool("onTap", false)! - ? () { - widget.backend - .triggerControlEvent(cell.id, "tap"); - } - : null, - onTapCancel: cell.attrBool("onTapCancel", false)! - ? () { - widget.backend.triggerControlEvent( - cell.id, "tap_cancel"); - } - : null, - onTapDown: cell.attrBool("onTapDown", false)! - ? (details) { - widget.backend.triggerControlEvent( - cell.id, - "tap_down", - json.encode({ - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - })); - } - : null, - )) - .toList()); - }).toList()); - }); + ); + }).toList(), + ); - return constrainedControl( - context, datatable, widget.parent, widget.control); + return LayoutControl(control: control, child: datatable); } } diff --git a/packages/flet/lib/src/controls/date_picker.dart b/packages/flet/lib/src/controls/date_picker.dart index efb86b04ca..48c12bb332 100644 --- a/packages/flet/lib/src/controls/date_picker.dart +++ b/packages/flet/lib/src/controls/date_picker.dart @@ -1,84 +1,67 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; +import '../utils/edge_insets.dart'; import '../utils/form_field.dart'; import '../utils/icons.dart'; -import '../utils/others.dart'; +import '../utils/locale.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; -class DatePickerControl extends StatefulWidget { - final Control? parent; +class DatePickerControl extends StatelessWidget { final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const DatePickerControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + const DatePickerControl({super.key, required this.control}); - @override - State createState() => _DatePickerControlState(); -} - -class _DatePickerControlState extends State { @override Widget build(BuildContext context) { - debugPrint("DatePicker build: ${widget.control.id}"); + debugPrint("DatePicker build: ${control.id}"); - bool lastOpen = widget.control.state["open"] ?? false; + bool lastOpen = control.getBool("_open", false)!; - var open = widget.control.attrBool("open", false)!; - DateTime? value = widget.control.attrDateTime("value"); - DateTime? currentDate = widget.control.attrDateTime("currentDate"); - IconData? switchToCalendarEntryModeIcon = parseIcon( - widget.control.attrString("switchToCalendarEntryModeIcon", "")!); - IconData? switchToInputEntryModeIcon = - parseIcon(widget.control.attrString("switchToInputEntryModeIcon")); + var open = control.getBool("open", false)!; + var value = control.getDateTime("value"); + var currentDate = control.getDateTime("current_date"); + var switchToCalendarEntryModeIcon = + control.getIconData("switch_to_calendar_icon"); + var switchToInputEntryModeIcon = + control.getIconData("switch_to_input_icon"); + var locale = control.getLocale("locale"); void onClosed(DateTime? dateValue) { - String stringValue; - String eventName; - if (dateValue == null) { - stringValue = - value?.toIso8601String() ?? currentDate?.toIso8601String() ?? ""; - eventName = "dismiss"; - } else { - stringValue = dateValue.toIso8601String(); - eventName = "change"; + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"value": dateValue ?? value, "open": false}); + if (dateValue != null) { + control.triggerEvent("change", dateValue); } - widget.control.state["open"] = false; - widget.backend.updateControlState( - widget.control.id, {"value": stringValue, "open": "false"}); - widget.backend - .triggerControlEvent(widget.control.id, eventName, stringValue); + control.triggerEvent("dismiss", dateValue == null); } Widget createSelectDateDialog() { Widget dialog = DatePickerDialog( initialDate: value ?? currentDate ?? DateTime.now(), - firstDate: widget.control.attrDateTime("firstDate", DateTime(1900))!, - lastDate: widget.control.attrDateTime("lastDate", DateTime(2050))!, + firstDate: control.getDateTime("first_date", DateTime(1900, 1, 1))!, + lastDate: control.getDateTime("last_date", DateTime(2050, 1, 1))!, currentDate: currentDate ?? DateTime.now(), - helpText: widget.control.attrString("helpText"), - cancelText: widget.control.attrString("cancelText"), - confirmText: widget.control.attrString("confirmText"), - errorFormatText: widget.control.attrString("errorFormatText"), - errorInvalidText: widget.control.attrString("errorInvalidText"), + helpText: control.getString("help_text"), + cancelText: control.getString("cancel_text"), + confirmText: control.getString("confirm_text"), + errorFormatText: control.getString("error_format_text"), + errorInvalidText: control.getString("error_invalid_text"), keyboardType: parseTextInputType( - widget.control.attrString("keyboardType"), TextInputType.text)!, - initialCalendarMode: parseDatePickerMode( - widget.control.attrString("datePickerMode"), DatePickerMode.day)!, - initialEntryMode: parseDatePickerEntryMode( - widget.control.attrString("datePickerEntryMode"), - DatePickerEntryMode.calendar)!, - fieldHintText: widget.control.attrString("fieldHintText"), - fieldLabelText: widget.control.attrString("fieldLabelText"), + control.getString("keyboard_type"), TextInputType.text)!, + initialCalendarMode: + control.getDatePickerMode("date_picker_mode", DatePickerMode.day)!, + initialEntryMode: control.getDatePickerEntryMode( + "entry_mode", DatePickerEntryMode.calendar)!, + fieldHintText: control.getString("field_hint_text"), + fieldLabelText: control.getString("field_label_text"), + insetPadding: control.getPadding("inset_padding", + const EdgeInsets.symmetric(horizontal: 16.0, vertical: 24.0))!, onDatePickerModeChange: (DatePickerEntryMode mode) { - widget.backend.triggerControlEvent( - widget.control.id, "entryModeChange", mode.name); + control.updateProperties({"entry_mode": mode.name}); + control.triggerEvent("entry_mode_change", {"entry_mode": mode.name}); }, switchToCalendarEntryModeIcon: switchToCalendarEntryModeIcon != null ? Icon(switchToCalendarEntryModeIcon) @@ -88,20 +71,30 @@ class _DatePickerControlState extends State { : null, ); - return dialog; + return locale == null || !locale.isSupportedByDelegates() + ? dialog + : Localizations.override( + context: context, locale: locale, child: dialog); } if (open && (open != lastOpen)) { - widget.control.state["open"] = open; + control.updateProperties({"_open": open}, python: false); WidgetsBinding.instance.addPostFrameCallback((_) { + ModalRoute? dialogRoute; showDialog( - barrierColor: widget.control.attrColor("barrierColor", context), + barrierDismissible: !control.getBool("modal", false)!, + barrierColor: control.getColor("barrier_color", context), useRootNavigator: false, context: context, - builder: (context) => createSelectDateDialog()).then((result) { - debugPrint("pickDate() completed"); - onClosed(result); + builder: (context) { + dialogRoute ??= ModalRoute.of(context); + return createSelectDateDialog(); + }).then((result) { + (dialogRoute?.completed ?? Future.value()).then((_) { + debugPrint("pickDate() completed"); + onClosed(result); + }); }); }); } diff --git a/packages/flet/lib/src/controls/date_range_picker.dart b/packages/flet/lib/src/controls/date_range_picker.dart new file mode 100644 index 0000000000..ada8ed61eb --- /dev/null +++ b/packages/flet/lib/src/controls/date_range_picker.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import '../utils/colors.dart'; +import '../utils/form_field.dart'; +import '../utils/icons.dart'; +import '../utils/locale.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; + +class DateRangePickerControl extends StatelessWidget { + final Control control; + + const DateRangePickerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("DateRangePicker build: ${control.id}"); + + bool lastOpen = control.getBool("_open", false)!; + + var open = control.getBool("open", false)!; + var currentDate = control.getDateTime("current_date"); + var startValue = control.getDateTime("start_value"); + var endValue = control.getDateTime("end_value"); + var value = DateTimeRange( + start: startValue ?? currentDate ?? DateTime.now(), + end: endValue ?? currentDate ?? DateTime.now()); + + var switchToCalendarEntryModeIcon = + control.getIconData("switch_to_calendar_icon"); + var switchToInputEntryModeIcon = + control.getIconData("switch_to_input_icon"); + var locale = control.getLocale("locale"); + + void onClosed(DateTimeRange? dateRangeValue) { + control.updateProperties({"_open": false}, python: false); + var props = { + "start_value": dateRangeValue?.start ?? startValue, + "end_value": dateRangeValue?.end ?? endValue, + "open": false + }; + control.updateProperties(props); + if (dateRangeValue != null) { + control.triggerEvent("change", dateRangeValue); + } + control.triggerEvent("dismiss", dateRangeValue == null); + } + + Widget createSelectDateDialog() { + Widget dialog = DateRangePickerDialog( + initialDateRange: value, + firstDate: control.getDateTime("first_date", DateTime(1900))!, + lastDate: control.getDateTime("last_date", DateTime(2050))!, + currentDate: currentDate ?? DateTime.now(), + helpText: control.getString("help_text"), + cancelText: control.getString("cancel_text"), + confirmText: control.getString("confirm_text"), + saveText: control.getString("save_text"), + errorInvalidRangeText: control.getString("error_invalid_range_text"), + errorFormatText: control.getString("error_format_text"), + errorInvalidText: control.getString("error_invalid_text"), + fieldStartHintText: control.getString("field_start_hint_text"), + fieldEndHintText: control.getString("field_end_hint_text"), + fieldStartLabelText: control.getString("field_start_label_text"), + fieldEndLabelText: control.getString("field_end_label_text"), + keyboardType: parseTextInputType( + control.getString("keyboard_type"), TextInputType.text)!, + initialEntryMode: control.getDatePickerEntryMode( + "entry_mode", DatePickerEntryMode.calendar)!, + switchToCalendarEntryModeIcon: switchToCalendarEntryModeIcon != null + ? Icon(switchToCalendarEntryModeIcon) + : null, + switchToInputEntryModeIcon: switchToInputEntryModeIcon != null + ? Icon(switchToInputEntryModeIcon) + : null, + ); + + return locale == null || !locale.isSupportedByDelegates() + ? dialog + : Localizations.override( + context: context, locale: locale, child: dialog); + } + + if (open && (open != lastOpen)) { + control.updateProperties({"_open": open}, python: false); + + WidgetsBinding.instance.addPostFrameCallback((_) { + ModalRoute? dialogRoute; + showDialog>( + barrierDismissible: !control.getBool("modal", false)!, + barrierColor: control.getColor("barrier_color", context), + useRootNavigator: false, + context: context, + builder: (context) { + dialogRoute ??= ModalRoute.of(context); + return createSelectDateDialog(); + }).then((result) { + (dialogRoute?.completed ?? Future.value()).then((_) { + debugPrint("pickDate() completed"); + onClosed(result); + }); + }); + }); + } + return const SizedBox.shrink(); + } +} diff --git a/packages/flet/lib/src/controls/dismissible.dart b/packages/flet/lib/src/controls/dismissible.dart index c630541e39..a356f85db5 100644 --- a/packages/flet/lib/src/controls/dismissible.dart +++ b/packages/flet/lib/src/controls/dismissible.dart @@ -1,30 +1,20 @@ import 'dart:async'; -import 'dart:convert'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/dismissible.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class DismissibleControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const DismissibleControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + DismissibleControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _DismissibleControlState(); @@ -32,111 +22,87 @@ class DismissibleControl extends StatefulWidget { class _DismissibleControlState extends State { @override - Widget build(BuildContext context) { - debugPrint("Dismissible build: ${widget.control.id}"); + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } - if (contentCtrls.isEmpty) { - return const ErrorControl( - "Dismissible.content must be provided and visible"); + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Dismissible.$name($args)"); + switch (name) { + case "confirm_dismiss": + widget.control.properties + .remove("_completer") + ?.complete(args["dismiss"]); + default: + throw Exception("Unknown Dismissible method: $name"); } + } - var backgroundCtrls = - widget.children.where((c) => c.name == "background" && c.isVisible); - - var secondaryBackgroundCtrls = widget.children - .where((c) => c.name == "secondaryBackground" && c.isVisible); - - var dismissThresholds = - parseDismissThresholds(widget.control, "dismissThresholds"); - - DismissDirection direction = parseDismissDirection( - widget.control.attrString("dismissDirection"), - DismissDirection.horizontal)!; - - widget.backend.subscribeMethods(widget.control.id, - (methodName, args) async { - debugPrint("Dismissible.onMethod(${widget.control.id})"); - if (methodName == "confirm_dismiss") { - widget.control.state["confirm_dismiss"] - ?.complete(bool.tryParse(args["dismiss"] ?? "")); - widget.backend.unsubscribeMethods(widget.control.id); - } + @override + Widget build(BuildContext context) { + debugPrint("Dismissible build: ${widget.control.id}"); + var content = widget.control.buildWidget("content"); - return null; - }); + if (content == null) { + return const ErrorControl("Dismissible.content must be visible"); + } - return constrainedControl( - context, - Dismissible( - key: ValueKey(widget.control.id), - direction: direction, - background: backgroundCtrls.isNotEmpty - ? createControl( - widget.control, backgroundCtrls.first.id, disabled, - parentAdaptive: adaptive) - : Container(color: Colors.transparent), - secondaryBackground: secondaryBackgroundCtrls.isNotEmpty - ? createControl( - widget.control, secondaryBackgroundCtrls.first.id, disabled, - parentAdaptive: adaptive) - : Container(color: Colors.transparent), - onDismissed: widget.control.attrBool("onDismiss", false)! - ? (DismissDirection direction) { - widget.backend.triggerControlEvent( - widget.control.id, "dismiss", direction.name); - } - : null, - onResize: widget.control.attrBool("onResize", false)! - ? () { - widget.backend - .triggerControlEvent(widget.control.id, "resize"); - } - : null, - onUpdate: widget.control.attrBool("onUpdate", false)! - ? (DismissUpdateDetails details) { - widget.backend.triggerControlEvent( - widget.control.id, - "update", - json.encode(DismissibleUpdateEvent( - direction: details.direction.name, - previousReached: details.previousReached, - progress: details.progress, - reached: details.reached) - .toJson())); - } - : null, - confirmDismiss: widget.control.attrBool("onConfirmDismiss", false)! - ? (DismissDirection direction) { - debugPrint( - "Dismissible.confirmDismiss(${widget.control.id})"); - var completer = Completer(); - widget.control.state["confirm_dismiss"] = completer; - widget.backend.triggerControlEvent( - widget.control.id, "confirm_dismiss", direction.name); - return completer.future.timeout( - const Duration(minutes: 5), - onTimeout: () => false, - ); - } - : null, - movementDuration: Duration( - milliseconds: widget.control.attrInt("duration", 200)!), - resizeDuration: Duration( - milliseconds: widget.control.attrInt("resizeDuration", 300)!), - crossAxisEndOffset: - widget.control.attrDouble("crossAxisEndOffset", 0.0)!, - dismissThresholds: dismissThresholds ?? {}, - child: createControl( - widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive)), - widget.parent, - widget.control); + final dismissible = Dismissible( + key: ValueKey(widget.control.id), + direction: widget.control.getDismissDirection( + "dismiss_direction", DismissDirection.horizontal)!, + background: widget.control.buildWidget("background"), + secondaryBackground: widget.control.buildWidget("secondary_background"), + onDismissed: widget.control.getBool("on_dismiss", false)! + ? (DismissDirection direction) => widget.control + .triggerEvent("dismiss", {"direction": direction.name}) + : null, + onResize: widget.control.getBool("on_resize", false)! + ? () => widget.control.triggerEvent("resize") + : null, + onUpdate: widget.control.getBool("on_update", false)! + ? (DismissUpdateDetails details) { + widget.control.triggerEvent( + "update", + DismissibleUpdateEvent( + direction: details.direction.name, + previousReached: details.previousReached, + progress: details.progress, + reached: details.reached) + .toMap()); + } + : null, + confirmDismiss: widget.control.getBool("on_confirm_dismiss", false)! + ? (DismissDirection direction) { + var completer = Completer(); + widget.control + .updateProperties({"_completer": completer}, python: false); + widget.control.triggerEvent( + "confirm_dismiss", {"direction": direction.name}); + return completer.future.timeout( + const Duration(minutes: 5), + onTimeout: () => false, + ); + } + : null, + movementDuration: widget.control + .getDuration("movement_duration", const Duration(milliseconds: 200))!, + resizeDuration: widget.control + .getDuration("resize_duration", const Duration(milliseconds: 300))!, + crossAxisEndOffset: + widget.control.getDouble("cross_axis_end_offset", 0.0)!, + dismissThresholds: widget.control + .getDismissThresholds("dismiss_thresholds", const {})!, + child: content); + + return LayoutControl(control: widget.control, child: dismissible); } } @@ -152,7 +118,7 @@ class DismissibleUpdateEvent { required this.previousReached, required this.reached}); - Map toJson() => { + Map toMap() => { 'direction': direction, 'progress': progress, 'reached': reached, diff --git a/packages/flet/lib/src/controls/divider.dart b/packages/flet/lib/src/controls/divider.dart index 1459c8b022..e24564f46f 100644 --- a/packages/flet/lib/src/controls/divider.dart +++ b/packages/flet/lib/src/controls/divider.dart @@ -1,26 +1,29 @@ import 'package:flutter/material.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import '../utils/borders.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class DividerControl extends StatelessWidget { - final Control? parent; final Control control; - const DividerControl( - {super.key, required this.parent, required this.control}); + const DividerControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Divider build: ${control.id}"); var divider = Divider( - height: control.attrDouble("height"), - thickness: control.attrDouble("thickness"), - color: control.attrColor("color", context), - indent: control.attrDouble("leadingIndent"), - endIndent: control.attrDouble("trailingIndent"), + height: control.getDouble("height"), + thickness: control.getDouble("thickness"), + color: control.getColor("color", context), + indent: control.getDouble("leading_indent"), + endIndent: control.getDouble("trailing_indent"), + radius: control.getBorderRadius("radius"), ); - return baseControl(context, divider, parent, control); + + return BaseControl(control: control, child: divider); } } diff --git a/packages/flet/lib/src/controls/drag_target.dart b/packages/flet/lib/src/controls/drag_target.dart index 2619a4af49..95bc7f7366 100644 --- a/packages/flet/lib/src/controls/drag_target.dart +++ b/packages/flet/lib/src/controls/drag_target.dart @@ -1,120 +1,97 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'draggable.dart'; class DragTargetEvent { - final String srcId; - final double x; - final double y; + final int srcId; + final Offset localPosition; + final Offset globalPosition; DragTargetEvent({ required this.srcId, - required this.x, - required this.y, + required this.localPosition, + required this.globalPosition, }); - Map toJson() => { + Map toMap() => { 'src_id': srcId, - 'x': x, - 'y': y, + 'l': {'x': localPosition.dx, 'y': localPosition.dy}, + 'g': {'x': globalPosition.dx, 'y': globalPosition.dy}, }; } class DragTargetControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const DragTargetControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const DragTargetControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("DragTarget build: ${control.id}"); - var group = control.attrString("group", ""); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - - Widget? child = contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null; + var group = control.getString("group", "default")!; + var content = control.buildWidget("content"); - if (child == null) { - return const ErrorControl( - "DragTarget.content must be provided and visible"); + if (content == null) { + return const ErrorControl("DragTarget.content must be visible"); } - return DragTarget( + BuildContext? dragTargetContext; + + return DragTarget( builder: ( BuildContext context, List accepted, List rejected, ) { - debugPrint( - "DragTarget.builder ${control.id}: accepted=${accepted.length}, rejected=${rejected.length}"); - return child; + dragTargetContext = context; + return content; }, - onMove: (details) { - var data = details.data; - debugPrint("DragTarget.onMove ${control.id}: $data"); - var jd = json.decode(data); - var srcId = jd["id"] as String; - backend.triggerControlEvent( - control.id, + onMove: (DragTargetDetails details) { + final globalPosition = details.offset; + final localPosition = + _getLocalPosition(dragTargetContext, globalPosition); + control.triggerEvent( "move", - json.encode(DragTargetEvent( - srcId: srcId, x: details.offset.dx, y: details.offset.dy) - .toJson())); + DragTargetEvent( + srcId: details.data.id, + localPosition: localPosition, + globalPosition: globalPosition, + ).toMap()); }, - onWillAcceptWithDetails: (details) { - var data = details.data; - debugPrint("DragTarget.onWillAcceptWithDetails ${control.id}: $data"); - String srcGroup = ""; - var jd = json.decode(data); - srcGroup = jd["group"] as String; - var groupsEqual = srcGroup == group; - backend.triggerControlEvent( - control.id, "will_accept", groupsEqual.toString()); - return groupsEqual; + onWillAcceptWithDetails: (DragTargetDetails details) { + var groupMatch = details.data.group == group; + control.triggerEvent( + "will_accept", {"accept": groupMatch, "src_id": details.data.id}); + return groupMatch; }, - onAcceptWithDetails: (details) { - var data = details.data; - debugPrint("DragTarget.onAcceptWithDetails ${control.id}: $data"); - var jd = json.decode(data); - var srcId = jd["id"] as String; - backend.triggerControlEvent( - control.id, + onAcceptWithDetails: (DragTargetDetails details) { + final globalPosition = details.offset; + final localPosition = + _getLocalPosition(dragTargetContext, globalPosition); + control.triggerEvent( "accept", - json.encode(DragTargetEvent( - srcId: srcId, x: details.offset.dx, y: details.offset.dy) - .toJson())); + DragTargetEvent( + srcId: details.data.id, + localPosition: localPosition, + globalPosition: globalPosition, + ).toMap()); }, - onLeave: (data) { - debugPrint("DragTarget.onLeave ${control.id}: $data"); - String srcId = ""; - if (data != null) { - var jd = json.decode(data); - srcId = jd["id"] as String; - } - backend.triggerControlEvent(control.id, "leave", srcId); + onLeave: (DraggableData? data) { + control.triggerEvent("leave", {"src_id": data?.id}); }, ); } + + Offset _getLocalPosition(BuildContext? context, Offset globalPosition) { + final renderObject = context?.findRenderObject(); + if (renderObject is! RenderBox || !renderObject.hasSize) { + return globalPosition; + } + return renderObject.globalToLocal(globalPosition); + } } diff --git a/packages/flet/lib/src/controls/draggable.dart b/packages/flet/lib/src/controls/draggable.dart index c2d763afc0..46f7ea89ae 100644 --- a/packages/flet/lib/src/controls/draggable.dart +++ b/packages/flet/lib/src/controls/draggable.dart @@ -1,85 +1,49 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; + +class DraggableData { + final int id; + final String group; + + DraggableData({required this.id, required this.group}); +} class DraggableControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const DraggableControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const DraggableControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("DragTarget build: ${control.id}"); - var adaptive = control.isAdaptive ?? parentAdaptive; + var group = control.getString("group", "default")!; + var content = control.buildWidget("content"); - var group = control.attrString("group", ""); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - var contentWhenDraggingCtrls = - children.where((c) => c.name == "content_when_dragging" && c.isVisible); - var contentFeedbackCtrls = - children.where((c) => c.name == "content_feedback" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - - Widget? child = contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null; - - Widget? childFeedback = contentFeedbackCtrls.isNotEmpty - ? createControl(control, contentFeedbackCtrls.first.id, disabled, - parentAdaptive: adaptive) - : Opacity(opacity: 0.5, child: child); - - if (child == null) { - return const ErrorControl( - "Draggable.content must be provided and visible"); + if (content == null) { + return const ErrorControl("Draggable.content must be visible"); } - var data = json.encode({"id": control.id, "group": group}); - - return Draggable( - data: data, - axis: parseAxis(control.attrString("axis")), - affinity: parseAxis(control.attrString("affinity")), - maxSimultaneousDrags: control.attrInt("maxSimultaneousDrags"), - childWhenDragging: contentWhenDraggingCtrls.isNotEmpty - ? createControl(control, contentWhenDraggingCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, + return Draggable( + data: DraggableData(id: control.id, group: group), + axis: control.getAxis("axis"), + affinity: control.getAxis("affinity"), + maxSimultaneousDrags: control.getInt("max_simultaneous_drags"), + onDragStarted: () => control.triggerEvent("drag_start"), + onDragCompleted: () => control.triggerEvent("drag_complete", group), + childWhenDragging: control.buildWidget("content_when_dragging"), feedback: MouseRegion( cursor: SystemMouseCursors.grabbing, - child: childFeedback, + child: control.buildWidget("content_feedback") ?? + Opacity(opacity: 0.5, child: content), ), - onDragStarted: () { - debugPrint("Draggable.onDragStarted ${control.id}"); - backend.triggerControlEvent(control.id, "dragStart"); - }, - onDragCompleted: () { - debugPrint("Draggable.onDragCompleted ${control.id}"); - backend.triggerControlEvent(control.id, "dragComplete"); - }, child: MouseRegion( cursor: SystemMouseCursors.grab, - child: child, + child: content, ), ); } diff --git a/packages/flet/lib/src/controls/dropdown.dart b/packages/flet/lib/src/controls/dropdown.dart index 768852063c..71e9d48e5e 100644 --- a/packages/flet/lib/src/controls/dropdown.dart +++ b/packages/flet/lib/src/controls/dropdown.dart @@ -1,355 +1,329 @@ +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../models/control_view_model.dart'; import '../utils/borders.dart'; import '../utils/buttons.dart'; import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/form_field.dart'; -import '../utils/icons.dart'; +import '../utils/layout.dart'; +import '../utils/menu.dart'; import '../utils/numbers.dart'; import '../utils/text.dart'; import '../utils/textfield.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; -import 'textfield.dart'; +import 'base_controls.dart'; class DropdownControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const DropdownControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + DropdownControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _DropdownControlState(); } -class _DropdownControlState extends State with FletStoreMixin { - String? _value; +class _DropdownControlState extends State { late final FocusNode _focusNode; - String? _lastFocusValue; + late final TextEditingController _controller; + String? _value; + bool _suppressTextChange = false; @override void initState() { super.initState(); + + // initialize controller + _value = widget.control.getString("value"); + final text = widget.control.getString("text") ?? _value ?? ""; + _controller = TextEditingController(text: text); + _controller.addListener(_onTextChange); + _focusNode = FocusNode(); _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + void _onTextChange() { + if (_suppressTextChange) return; + + if (_controller.text != widget.control.getString("text")) { + widget.control.updateProperties({"text": _controller.text}); + widget.control.triggerEvent("text_change", _controller.text); + } } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + /// Updates text without triggering a text change event. + void _updateControllerText(String text) { + _suppressTextChange = true; + _controller.value = TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: text.length), + ); + _suppressTextChange = false; + widget.control.updateProperties({"text": text}, python: false); } @override void dispose() { _focusNode.removeListener(_onFocusChange); _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + _controller.dispose(); super.dispose(); } + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Dropdown.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown Dropdown method: $name"); + } + } + @override Widget build(BuildContext context) { debugPrint("DropdownMenu build: ${widget.control.id}"); - return withControls(widget.control.childIds, (context, itemsView) { - debugPrint("DropdownMenuFletControlState build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool editable = widget.control.attrBool("editable", false)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; - var textSize = widget.control.attrDouble("textSize"); - var label = widget.control.attrString("label"); - var trailingIconCtrl = widget.children - .where((c) => c.name == "trailing_icon" && c.isVisible); - var trailingIconStr = - parseIcon(widget.control.attrString("trailingIcon")); - - var leadingIconCtrl = - widget.children.where((c) => c.name == "leading_icon" && c.isVisible); - var leadingIconStr = parseIcon(widget.control.attrString("leadingIcon")); - - var selectIconCtrl = - widget.children.where((c) => c.name == "select_icon" && c.isVisible); - var selectIconStr = parseIcon(widget.control.attrString("selectIcon")); - - var selectedTrailingIconCtrl = widget.children - .where((c) => c.name == "selected_trailing_icon" && c.isVisible); - var selectedTrailingIconStr = - parseIcon(widget.control.attrString("selectedTrailingIcon")); - var prefixIconCtrl = - widget.children.where((c) => c.name == "prefix_icon" && c.isVisible); - var prefixIconStr = parseIcon(widget.control.attrString("prefixIcon")); - var labelCtrl = - widget.children.where((c) => c.name == "label" && c.isVisible); - var color = widget.control.attrColor("color", context); - - TextAlign textAlign = parseTextAlign( - widget.control.attrString("textAlign"), TextAlign.start)!; - - var fillColor = widget.control.attrColor("fillColor", context); - var borderColor = widget.control.attrColor("borderColor", context); - - var borderRadius = parseBorderRadius(widget.control, "borderRadius"); - var focusedBorderColor = - widget.control.attrColor("focusedBorderColor", context); - var borderWidth = widget.control.attrDouble("borderWidth"); - var focusedBorderWidth = widget.control.attrDouble("focusedBorderWidth"); - var menuWidth = widget.control.attrDouble("menuWidth") ?? double.infinity; - - FormFieldInputBorder inputBorder = parseFormFieldInputBorder( - widget.control.attrString("border"), - FormFieldInputBorder.outline, - )!; - - InputBorder? border; - - if (inputBorder == FormFieldInputBorder.underline) { - border = UnderlineInputBorder( - borderSide: BorderSide( - color: borderColor ?? const Color(0xFF000000), - width: borderWidth ?? 1.0)); - } else if (inputBorder == FormFieldInputBorder.none) { - border = InputBorder.none; - } else if (inputBorder == FormFieldInputBorder.outline || - borderRadius != null || - borderColor != null || - borderWidth != null) { - border = OutlineInputBorder( - borderSide: BorderSide( - color: borderColor ?? const Color(0xFF000000), - width: borderWidth ?? 1.0)); - if (borderRadius != null) { - border = (border as OutlineInputBorder) - .copyWith(borderRadius: borderRadius); - } - if (borderColor != null || borderWidth != null) { - border = (border as OutlineInputBorder).copyWith( - borderSide: borderWidth == 0 - ? BorderSide.none - : BorderSide( - color: borderColor ?? - Theme.of(context) - .colorScheme - .onSurface - .withOpacity(0.38), - width: borderWidth ?? 1.0)); - } - } - InputBorder? focusedBorder; - if (borderColor != null || - borderWidth != null || - focusedBorderColor != null || - focusedBorderWidth != null) { - focusedBorder = border?.copyWith( + var theme = Theme.of(context); + var editable = widget.control.getBool("editable", false)!; + var autofocus = widget.control.getBool("autofocus", false)!; + var textSize = widget.control.getDouble("text_size"); + var color = widget.control.getColor("color", context); + + var textAlign = widget.control.getTextAlign("text_align", TextAlign.start)!; + + var fillColor = widget.control.getColor("fill_color", context); + var borderColor = widget.control.getColor("border_color", context); + + var borderRadius = widget.control.getBorderRadius("border_radius"); + var focusedBorderColor = + widget.control.getColor("focused_border_color", context); + var borderWidth = widget.control.getDouble("border_width"); + var focusedBorderWidth = widget.control.getDouble("focused_border_width"); + var menuWidth = widget.control.getDouble("menu_width"); + var bgColor = widget.control.getWidgetStateColor("bgcolor", theme); + var elevation = widget.control.getWidgetStateDouble("elevation"); + + var inputBorder = widget.control + .getFormFieldInputBorder("border", FormFieldInputBorder.outline)!; + + InputBorder? border; + + if (inputBorder == FormFieldInputBorder.underline) { + border = UnderlineInputBorder( + borderSide: BorderSide( + color: borderColor ?? const Color(0xFF000000), + width: borderWidth ?? 1.0)); + } else if (inputBorder == FormFieldInputBorder.none) { + border = InputBorder.none; + } else if (inputBorder == FormFieldInputBorder.outline || + borderRadius != null || + borderColor != null || + borderWidth != null) { + border = OutlineInputBorder( + borderSide: BorderSide( + color: borderColor ?? const Color(0xFF000000), + width: borderWidth ?? 1.0)); + if (borderRadius != null) { + border = + (border as OutlineInputBorder).copyWith(borderRadius: borderRadius); + } + if (borderColor != null || borderWidth != null) { + border = (border as OutlineInputBorder).copyWith( borderSide: borderWidth == 0 ? BorderSide.none : BorderSide( - color: focusedBorderColor ?? - borderColor ?? - Theme.of(context).colorScheme.primary, - width: focusedBorderWidth ?? borderWidth ?? 2.0)); + color: borderColor ?? + theme.colorScheme.onSurface.withValues(alpha: 0.38), + width: borderWidth ?? 1.0)); } - - InputDecorationTheme inputDecorationTheme = InputDecorationTheme( - filled: widget.control.attrBool("filled", false)!, - fillColor: fillColor, - hintStyle: - parseTextStyle(Theme.of(context), widget.control, "hintStyle"), - errorStyle: - parseTextStyle(Theme.of(context), widget.control, "errorStyle"), - helperStyle: - parseTextStyle(Theme.of(context), widget.control, "helperStyle"), - border: border, - enabledBorder: border, - focusedBorder: focusedBorder, - isDense: widget.control.attrBool("dense") ?? false, - contentPadding: parseEdgeInsets(widget.control, "contentPadding"), - ); - - TextStyle? textStyle = - parseTextStyle(Theme.of(context), widget.control, "textStyle"); - if (textSize != null || color != null) { - textStyle = (textStyle ?? const TextStyle()).copyWith( - fontSize: textSize, - color: color ?? Theme.of(context).colorScheme.onSurface); - } - - var items = itemsView.controlViews - .where((c) => - c.control.name == null && - c.control.type == "dropdownoption" && - c.control.isVisible) - .map>((ControlViewModel itemCtrlView) { - var itemCtrl = itemCtrlView.control; - bool itemDisabled = disabled || itemCtrl.isDisabled; - ButtonStyle? style = - parseButtonStyle(Theme.of(context), itemCtrl, "style"); - - var contentCtrls = itemCtrlView.children - .where((c) => c.name == "content" && c.isVisible); - var leadingIconCtrls = itemCtrlView.children - .where((c) => c.name == "leadingIcon" && c.isVisible); - var trailingIconCtrls = itemCtrlView.children - .where((c) => c.name == "trailingIcon" && c.isVisible); - - return DropdownMenuEntry( - enabled: !itemDisabled, - value: itemCtrl.attrs["key"] ?? itemCtrl.attrs["text"] ?? itemCtrl.id, - label: itemCtrl.attrs["text"] ?? itemCtrl.attrs["key"] ?? itemCtrl.id, - labelWidget: contentCtrls.isNotEmpty - ? createControl( - itemCtrlView.control, contentCtrls.first.id, itemDisabled) - : null, - leadingIcon: leadingIconCtrls.isNotEmpty - ? createControl( - itemCtrlView.control, leadingIconCtrls.first.id, itemDisabled) - : itemCtrlView.control.attrString("leadingIcon") != null - ? Icon( - parseIcon(itemCtrlView.control.attrString("leadingIcon"))) - : null, - trailingIcon: trailingIconCtrls.isNotEmpty - ? createControl(itemCtrlView.control, trailingIconCtrls.first.id, - itemDisabled) - : itemCtrlView.control.attrString("trailingIcon") != null - ? Icon(parseIcon( - itemCtrlView.control.attrString("trailingIcon"))) - : null, - style: style, - ); - }).toList(); - - String? value = widget.control.attrString("value"); - if (_value != value) { - _value = value; - } - - if (items.where((item) => item.value == value).isEmpty) { - _value = null; - } - - var focusValue = widget.control.attrString("focus"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); - } - - TextCapitalization textCapitalization = parseTextCapitalization( - widget.control.attrString("capitalization"), - TextCapitalization.none)!; - - FilteringTextInputFormatter? inputFilter = - parseInputFilter(widget.control, "inputFilter"); - - List? inputFormatters = []; - // add non-null input formatters - if (inputFilter != null) { - inputFormatters.add(inputFilter); - } - if (textCapitalization != TextCapitalization.none) { - inputFormatters.add(TextCapitalizationFormatter(textCapitalization)); - } - - _focusNode.canRequestFocus = editable; - - Widget dropDown = DropdownMenu( - enabled: !disabled, - focusNode: _focusNode, - initialSelection: _value, - //controller: controller, - //requestFocusOnTap: editable, - enableFilter: widget.control.attrBool("enableFilter", false)!, - enableSearch: widget.control.attrBool("enableSearch", true)!, - menuHeight: widget.control.attrDouble("menuHeight"), - label: labelCtrl.isNotEmpty - ? createControl(widget.control, labelCtrl.first.id, disabled) - : label != null - ? Text(label, - style: parseTextStyle( - Theme.of(context), widget.control, "labelStyle")) - : null, - leadingIcon: leadingIconCtrl.isNotEmpty - ? createControl(widget.control, leadingIconCtrl.first.id, disabled) - : leadingIconStr != null - ? Icon(leadingIconStr) - : prefixIconCtrl.isNotEmpty - ? createControl( - widget.control, prefixIconCtrl.first.id, disabled) - : prefixIconStr != null - ? Icon(prefixIconStr) - : null, - trailingIcon: trailingIconCtrl.isNotEmpty - ? createControl(widget.control, trailingIconCtrl.first.id, disabled) - : trailingIconStr != null - ? Icon(trailingIconStr) - : selectIconCtrl.isNotEmpty - ? createControl( - widget.control, selectIconCtrl.first.id, disabled) - : selectIconStr != null - ? Icon(selectIconStr) - : null, - selectedTrailingIcon: selectedTrailingIconCtrl.isNotEmpty - ? createControl( - widget.control, selectedTrailingIconCtrl.first.id, disabled) - : selectedTrailingIconStr != null - ? Icon(selectedTrailingIconStr) - : null, - textStyle: textStyle, - textAlign: textAlign, - width: widget.control.attrDouble("width"), - errorText: widget.control.attrString("errorText"), - hintText: widget.control.attrString("hintText"), - helperText: widget.control.attrString("helperText"), - //inputFormatters: inputFormatters, - //expandedInsets: parseEdgeInsets(widget.control, "expandedInsets"), - expandedInsets: - widget.control.attrInt("expand") != null ? EdgeInsets.zero : null, - menuStyle: MenuStyle( - backgroundColor: parseWidgetStateColor( - Theme.of(context), widget.control, "bgcolor"), - elevation: parseWidgetStateDouble(widget.control, "elevation"), - fixedSize: WidgetStateProperty.all(Size.fromWidth(menuWidth)), - ), - - inputDecorationTheme: inputDecorationTheme, - onSelected: disabled - ? null - : (String? value) { - debugPrint("DropdownMenu selected value: $value"); - _value = value!; - widget.backend - .updateControlState(widget.control.id, {"value": value}); - widget.backend - .triggerControlEvent(widget.control.id, "change", value); - }, - dropdownMenuEntries: items, - ); - - var didAutoFocus = false; - - if (!didAutoFocus && autofocus) { - didAutoFocus = true; - SchedulerBinding.instance.addPostFrameCallback((_) { - FocusScope.of(context).autofocus(_focusNode); - }); + } + + InputBorder? focusedBorder; + if (borderColor != null || + borderWidth != null || + focusedBorderColor != null || + focusedBorderWidth != null) { + focusedBorder = border?.copyWith( + borderSide: borderWidth == 0 + ? BorderSide.none + : BorderSide( + color: focusedBorderColor ?? + borderColor ?? + theme.colorScheme.primary, + width: focusedBorderWidth ?? borderWidth ?? 2.0)); + } + + InputDecorationTheme inputDecorationTheme = InputDecorationTheme( + filled: widget.control.getBool("filled", false)!, + fillColor: fillColor, + hintStyle: widget.control.getTextStyle("hint_style", theme), + errorStyle: widget.control.getTextStyle("error_style", theme), + helperStyle: widget.control.getTextStyle("helper_style", theme), + border: border, + enabledBorder: border, + focusedBorder: focusedBorder, + isDense: widget.control.getBool("dense", false)!, + contentPadding: widget.control.getPadding("content_padding"), + ); + + TextStyle? textStyle = widget.control.getTextStyle("text_style", theme); + if (textSize != null || color != null) { + textStyle = + (textStyle ?? theme.dropdownMenuTheme.textStyle ?? const TextStyle()) + .copyWith( + fontSize: textSize, + color: color ?? theme.colorScheme.onSurface); + } + + MenuStyle? menuStyle = widget.control.getMenuStyle("menu_style", theme); + if (bgColor != null || elevation != null || menuWidth != null) { + menuStyle = + (menuStyle ?? theme.dropdownMenuTheme.menuStyle ?? const MenuStyle()) + .copyWith( + backgroundColor: bgColor, + elevation: elevation, + fixedSize: WidgetStateProperty.all( + Size.fromWidth(menuWidth ?? double.infinity))); + } + + if (textSize != null || color != null) { + textStyle = + (textStyle ?? theme.dropdownMenuTheme.textStyle ?? const TextStyle()) + .copyWith( + fontSize: textSize, + color: color ?? theme.colorScheme.onSurface); + } + + // build dropdown items + var options = widget.control + .children("options") + .map?>((Control itemCtrl) { + itemCtrl.notifyParent = true; + bool itemDisabled = widget.control.disabled || itemCtrl.disabled; + ButtonStyle? style = itemCtrl.getButtonStyle("style", theme); + + var optionKey = itemCtrl.getString("key"); + var optionText = itemCtrl.getString("text"); + + var optionValue = optionKey ?? optionText; + var optionLabel = optionText ?? optionKey; + if (optionValue == null || optionLabel == null) { + return null; + } + + return DropdownMenuEntry( + enabled: !itemDisabled, + value: optionValue, + label: optionLabel, + labelWidget: itemCtrl.buildWidget("content"), + leadingIcon: itemCtrl.buildIconOrWidget("leading_icon"), + trailingIcon: itemCtrl.buildIconOrWidget("trailing_icon"), + style: style, + ); + }) + .nonNulls + .toList(); + + var value = widget.control.getString("value"); + var selectedOption = options.firstWhereOrNull((o) => o.value == value); + value = selectedOption?.value; + + // Force DropdownMenu to rebuild when option set changes so it recalculates + // its intrinsic width (otherwise a long option added later can keep the + // old, narrower menu size). + final dropdownMenuKey = ValueKey( + Object.hashAll(options.map((o) => Object.hash(o.value, o.label)))); + + // keep controller text in sync with backend-driven value changes + if (_value != value) { + if (value == null) { + if (_value != null && _controller.text.isNotEmpty) { + // clears dropdown field + _updateControllerText(""); + } + } else { + final String entryLabel = + selectedOption?.label ?? widget.control.getString("text") ?? value; + if (_controller.text != entryLabel) { + _updateControllerText(entryLabel); + } } - - return constrainedControl( - context, dropDown, widget.parent, widget.control); - }); + _value = value; + } + + TextCapitalization textCapitalization = widget.control + .getTextCapitalization("capitalization", TextCapitalization.none)!; + FilteringTextInputFormatter? inputFilter = + widget.control.getTextInputFormatter("input_filter"); + + List? inputFormatters = []; + if (inputFilter != null) { + inputFormatters.add(inputFilter); + } + if (textCapitalization != TextCapitalization.none) { + inputFormatters.add(TextCapitalizationFormatter(textCapitalization)); + } + + _focusNode.canRequestFocus = editable; + + int expand = widget.control.getExpand("expand", 0)!; + EdgeInsets? expandedInsets = expand > 0 ? EdgeInsets.zero : null; + + Widget dropDown = DropdownMenu( + key: dropdownMenuKey, + enabled: !widget.control.disabled, + focusNode: _focusNode, + controller: _controller, + initialSelection: value, + enableFilter: widget.control.getBool("enable_filter", false)!, + enableSearch: widget.control.getBool("enable_search", true)!, + menuHeight: widget.control.getDouble("menu_height"), + label: widget.control.buildTextOrWidget("label", + textStyle: widget.control.getTextStyle("label_style", theme)), + leadingIcon: widget.control.buildIconOrWidget("leading_icon"), + trailingIcon: widget.control.buildIconOrWidget("trailing_icon"), + selectedTrailingIcon: + widget.control.buildIconOrWidget("selected_trailing_icon"), + textStyle: textStyle, + textAlign: textAlign, + width: widget.control.getDouble("width"), + errorText: widget.control.getString("error_text"), + hintText: widget.control.getString("hint_text"), + helperText: widget.control.getString("helper_text"), + menuStyle: menuStyle, + expandedInsets: expandedInsets, + inputDecorationTheme: inputDecorationTheme, + inputFormatters: inputFormatters.isEmpty ? null : inputFormatters, + onSelected: widget.control.disabled + ? null + : (String? selection) { + _value = selection; + widget.control.updateProperties({"value": selection}); + widget.control.triggerEvent("select", selection); + }, + dropdownMenuEntries: options, + ); + + var didAutoFocus = false; + if (!didAutoFocus && autofocus) { + didAutoFocus = true; + SchedulerBinding.instance.addPostFrameCallback((_) { + FocusScope.of(context).autofocus(_focusNode); + }); + } + + return LayoutControl(control: widget.control, child: dropDown); } } diff --git a/packages/flet/lib/src/controls/dropdownm2.dart b/packages/flet/lib/src/controls/dropdownm2.dart index fcee09c180..b1437a9b3a 100644 --- a/packages/flet/lib/src/controls/dropdownm2.dart +++ b/packages/flet/lib/src/controls/dropdownm2.dart @@ -1,267 +1,180 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../models/control_view_model.dart'; import '../utils/alignment.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/form_field.dart'; -import '../utils/icons.dart'; +import '../utils/layout.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; class DropdownM2Control extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const DropdownM2Control( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + DropdownM2Control({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _DropdownM2ControlState(); } -class _DropdownM2ControlState extends State - with FletStoreMixin { +class _DropdownM2ControlState extends State { String? _value; bool _focused = false; late final FocusNode _focusNode; - String? _lastFocusValue; @override void initState() { super.initState(); _focusNode = FocusNode(); _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); } void _onFocusChange() { setState(() { _focused = _focusNode.hasFocus; }); - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("DropdownM2.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown DropdownM2 method: $name"); + } } @override void dispose() { _focusNode.removeListener(_onFocusChange); _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); super.dispose(); } @override Widget build(BuildContext context) { - debugPrint("Dropdown build: ${widget.control.id}"); - - return withControls(widget.control.childIds, (context, itemsView) { - debugPrint("DropdownFletControlState build: ${widget.control.id}"); - - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var textSize = widget.control.attrDouble("textSize"); - var alignment = parseAlignment(widget.control, "alignment"); - var selectIconStr = parseIcon(widget.control.attrString("selectIcon")); - var selectIconCtrl = - widget.children.where((c) => c.name == "selectIcon" && c.isVisible); - var hintCtrl = - widget.children.where((c) => c.name == "hint" && c.isVisible); - var disabledHintCtrl = widget.children - .where((c) => c.name == "disabled_hint" && c.isVisible); - - var color = widget.control.attrColor("color", context); - var focusedColor = widget.control.attrColor("focusedColor", context); - var bgcolor = widget.control.attrColor("bgcolor", context); - var selectIconEnabledColor = - widget.control.attrColor("selectIconEnabledColor", context); - var selectIconDisabledColor = - widget.control.attrColor("selectIconDisabledColor", context); - - TextStyle? textStyle = - parseTextStyle(Theme.of(context), widget.control, "textStyle"); - if (textSize != null || color != null || focusedColor != null) { - textStyle = (textStyle ?? const TextStyle()).copyWith( - fontSize: textSize, - color: (_focused ? focusedColor ?? color : color) ?? - Theme.of(context).colorScheme.onSurface); - } - - var items = itemsView.controlViews - .where((c) => c.control.name == null && c.control.isVisible) - .map>((ControlViewModel itemCtrlView) { - var itemCtrl = itemCtrlView.control; - bool itemDisabled = disabled || itemCtrl.isDisabled; - TextStyle? textStyle = - parseTextStyle(Theme.of(context), itemCtrl, "textStyle"); - if (itemDisabled && textStyle != null) { - textStyle = textStyle.apply(color: Theme.of(context).disabledColor); - } - var contentCtrls = itemCtrlView.children - .where((c) => c.name == "content" && c.isVisible); - Widget? itemChild; - if (contentCtrls.isNotEmpty) { - // custom content - itemChild = createControl( - itemCtrlView.control, contentCtrls.first.id, itemDisabled); - } else { - itemChild = Text( - itemCtrl.attrs["text"] ?? itemCtrl.attrs["key"] ?? itemCtrl.id, - style: textStyle, - ); - } - var align = parseAlignment(itemCtrl, "alignment"); - if (align != null) { - itemChild = Container(alignment: align, child: itemChild); - } - return DropdownMenuItem( - enabled: !itemDisabled, - value: itemCtrl.attrs["key"] ?? itemCtrl.attrs["text"] ?? itemCtrl.id, - alignment: align ?? AlignmentDirectional.centerStart, - onTap: !(disabled || itemCtrl.isDisabled) - ? () { - widget.backend.triggerControlEvent(itemCtrl.id, "click"); - } - : null, - child: itemChild, - ); - }).toList(); - - String? value = widget.control.attrString("value"); - if (_value != value) { - _value = value; + debugPrint("DropdownM2 build: ${widget.control.id}"); + + var textSize = widget.control.getDouble("text_size"); + var color = widget.control.getColor("color", context); + var focusedColor = widget.control.getColor("focused_color", context); + + var textStyle = widget.control + .getTextStyle("text_style", Theme.of(context), const TextStyle())!; + + if (textSize != null) { + textStyle = textStyle.copyWith(fontSize: textSize); + } + + if (focusedColor != null) { + textStyle = textStyle.copyWith( + color: _focused ? focusedColor : (color ?? textStyle.color)); + } + + if (color != null) { + textStyle = textStyle.copyWith(color: color); + } + + if (textStyle.color == null) { + textStyle = + textStyle.copyWith(color: Theme.of(context).colorScheme.onSurface); + } + + var items = widget.control + .children("options") + .map>((Control item) { + item.notifyParent = true; + var textStyle = item.getTextStyle("text_style", Theme.of(context)); + if (item.disabled && textStyle != null) { + textStyle = textStyle.apply(color: Theme.of(context).disabledColor); } - - if (items.where((item) => item.value == value).isEmpty) { - _value = null; + var value = + item.getString("key") ?? item.getString("text") ?? item.id.toString(); + var content = + item.buildWidget("content") ?? Text(value, style: textStyle); + var alignment = item.getAlignment("alignment"); + if (alignment != null) { + content = Container(alignment: alignment, child: content); } - - var prefixControls = itemsView.controlViews - .where((c) => c.control.name == "prefix" && c.control.isVisible); - var prefixIconControls = itemsView.controlViews - .where((c) => c.control.name == "prefix_icon" && c.control.isVisible); - var suffixControls = itemsView.controlViews - .where((c) => c.control.name == "suffix" && c.control.isVisible); - var suffixIconControls = itemsView.controlViews - .where((c) => c.control.name == "suffix_icon" && c.control.isVisible); - var counterControls = itemsView.controlViews - .where((c) => c.control.name == "counter" && c.control.isVisible); - var iconControls = itemsView.controlViews - .where((c) => c.control.name == "icon" && c.control.isVisible); - var errorCtrl = itemsView.controlViews - .where((c) => c.control.name == "error" && c.control.isVisible); - var helperCtrl = itemsView.controlViews - .where((c) => c.control.name == "helper" && c.control.isVisible); - var labelCtrl = itemsView.controlViews - .where((c) => c.control.name == "label" && c.control.isVisible); - - var focusValue = widget.control.attrString("focus"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); - } - - var borderRadius = parseBorderRadius(widget.control, "borderRadius"); - - Widget dropDown = DropdownButtonFormField( - style: textStyle, - autofocus: autofocus, - focusNode: _focusNode, - value: _value, - dropdownColor: bgcolor, - enableFeedback: widget.control.attrBool("enableFeedback"), - elevation: widget.control.attrInt("elevation", 8)!, - padding: parseEdgeInsets(widget.control, "padding"), - itemHeight: widget.control.attrDouble("itemHeight"), - menuMaxHeight: widget.control.attrDouble("maxMenuHeight"), - iconEnabledColor: selectIconEnabledColor, - iconDisabledColor: selectIconDisabledColor, - iconSize: widget.control.attrDouble("selectIconSize", 24.0)!, - borderRadius: borderRadius, - alignment: alignment ?? AlignmentDirectional.centerStart, - isExpanded: widget.control.attrBool("optionsFillHorizontally", true)!, - icon: selectIconCtrl.isNotEmpty - ? createControl(widget.control, selectIconCtrl.first.id, disabled) - : selectIconStr != null - ? Icon(selectIconStr) - : null, - hint: hintCtrl.isNotEmpty - ? createControl(widget.control, hintCtrl.first.id, disabled) - : null, - disabledHint: disabledHintCtrl.isNotEmpty - ? createControl(widget.control, disabledHintCtrl.first.id, disabled) - : null, - decoration: buildInputDecoration(context, widget.control, - prefix: - prefixControls.isNotEmpty ? prefixControls.first.control : null, - prefixIcon: prefixIconControls.isNotEmpty - ? prefixIconControls.first.control - : null, - suffix: - suffixControls.isNotEmpty ? suffixControls.first.control : null, - suffixIcon: suffixIconControls.isNotEmpty - ? suffixIconControls.first.control - : null, - counter: counterControls.isNotEmpty - ? counterControls.first.control - : null, - icon: iconControls.isNotEmpty ? iconControls.first.control : null, - error: errorCtrl.isNotEmpty ? errorCtrl.first.control : null, - helper: helperCtrl.isNotEmpty ? helperCtrl.first.control : null, - label: labelCtrl.isNotEmpty ? labelCtrl.first.control : null, - customSuffix: null, - focused: _focused, - disabled: disabled, - adaptive: widget.parentAdaptive), - onTap: !disabled - ? () { - widget.backend.triggerControlEvent(widget.control.id, "click"); - } - : null, - onChanged: disabled - ? null - : (String? value) { - debugPrint("Dropdown selected value: $value"); - _value = value!; - widget.backend - .updateControlState(widget.control.id, {"value": value}); - widget.backend - .triggerControlEvent(widget.control.id, "change", value); - }, - items: items, - ); - - if (widget.control.attrInt("expand", 0)! > 0) { - return constrainedControl( - context, dropDown, widget.parent, widget.control); - } else { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if (constraints.maxWidth == double.infinity && - widget.control.attrDouble("width") == null) { - dropDown = ConstrainedBox( + return DropdownMenuItem( + enabled: !item.disabled, + value: value, + alignment: alignment ?? AlignmentDirectional.centerStart, + onTap: !item.disabled ? () => item.triggerEvent("click") : null, + child: content); + }).toList(); + + String? value = widget.control.getString("value"); + if (_value != value) { + _value = value; + } + + if (items.where((item) => item.value == value).isEmpty) { + _value = null; + } + + Widget dropDown = DropdownButtonFormField( + style: textStyle, + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + initialValue: _value, + dropdownColor: widget.control.getColor("bgcolor", context), + enableFeedback: widget.control.getBool("enable_feedback"), + elevation: widget.control.getInt("elevation", 8)!, + padding: widget.control.getPadding("padding"), + itemHeight: widget.control.getDouble("item_height"), + menuMaxHeight: widget.control.getDouble("max_menu_height"), + iconEnabledColor: + widget.control.getColor("select_icon_enabled_color", context), + iconDisabledColor: + widget.control.getColor("select_icon_disabled_color", context), + iconSize: widget.control.getDouble("select_icon_size", 24.0)!, + borderRadius: widget.control.getBorderRadius("border_radius"), + alignment: widget.control.getAlignment("alignment") ?? + AlignmentDirectional.centerStart, + isExpanded: widget.control.getBool("options_fill_horizontally", true)!, + icon: widget.control.buildIconOrWidget("select_icon"), + hint: widget.control.buildWidget("hint"), + disabledHint: widget.control.buildWidget("disabled_hint"), + decoration: buildInputDecoration(context, widget.control, + customSuffix: null, focused: _focused), + onTap: !widget.control.disabled + ? () => widget.control.triggerEvent("click") + : null, + onChanged: widget.control.disabled + ? null + : (String? value) { + _value = value!; + widget.control.updateProperties({"value": value}); + widget.control.triggerEvent("change", value); + }, + items: items, + ); + + if (widget.control.getExpand("expand", 0)! > 0) { + return LayoutControl(control: widget.control, child: dropDown); + } else { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (constraints.maxWidth == double.infinity && + widget.control.getDouble("width") == null) { + dropDown = ConstrainedBox( constraints: const BoxConstraints.tightFor(width: 300), - child: dropDown, - ); - } + child: dropDown); + } - return constrainedControl( - context, dropDown, widget.parent, widget.control); - }, - ); - } - }); + return LayoutControl(control: widget.control, child: dropDown); + }, + ); + } } } diff --git a/packages/flet/lib/src/controls/elevated_button.dart b/packages/flet/lib/src/controls/elevated_button.dart deleted file mode 100644 index a6adeb63e7..0000000000 --- a/packages/flet/lib/src/controls/elevated_button.dart +++ /dev/null @@ -1,245 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; -import '../utils/buttons.dart'; -import '../utils/icons.dart'; -import '../utils/launch_url.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'cupertino_button.dart'; -import 'cupertino_dialog_action.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; - -class ElevatedButtonControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const ElevatedButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); - - @override - State createState() => _ElevatedButtonControlState(); -} - -class _ElevatedButtonControlState extends State - with FletStoreMixin { - late final FocusNode _focusNode; - String? _lastFocusValue; - - @override - void initState() { - super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); - } - - @override - void dispose() { - _focusNode.removeListener(_onFocusChange); - _focusNode.dispose(); - super.dispose(); - } - - void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); - } - - @override - Widget build(BuildContext context) { - debugPrint("Button build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return widget.control.name == "action" && - (widget.parent?.type == "alertdialog" || - widget.parent?.type == "cupertinoalertdialog") - ? CupertinoDialogActionControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend) - : CupertinoButtonControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend); - } - - bool isFilledButton = widget.control.type == "filledbutton"; - bool isFilledTonalButton = widget.control.type == "filledtonalbutton"; - String text = widget.control.attrString("text", "")!; - String url = widget.control.attrString("url", "")!; - IconData? icon = parseIcon(widget.control.attrString("icon")); - Color? iconColor = widget.control.attrColor("iconColor", context); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!; - bool onHover = widget.control.attrBool("onHover", false)!; - bool onLongPress = widget.control.attrBool("onLongPress", false)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; - - Function()? onPressed = !disabled - ? () { - debugPrint("Button ${widget.control.id} clicked!"); - if (url != "") { - openWebBrowser(url, - webWindowName: widget.control.attrString("urlTarget")); - } - widget.backend.triggerControlEvent(widget.control.id, "click"); - } - : null; - - Function()? onLongPressHandler = onLongPress && !disabled - ? () { - debugPrint("Button ${widget.control.id} long pressed!"); - widget.backend - .triggerControlEvent(widget.control.id, "long_press"); - } - : null; - - Function(bool)? onHoverHandler = onHover && !disabled - ? (state) { - debugPrint("Button ${widget.control.id} hovered!"); - widget.backend.triggerControlEvent( - widget.control.id, "hover", state.toString()); - } - : null; - - Widget? button; - - var theme = Theme.of(context); - - var style = parseButtonStyle(Theme.of(context), widget.control, "style", - defaultForegroundColor: theme.colorScheme.primary, - defaultBackgroundColor: theme.colorScheme.surface, - defaultOverlayColor: theme.colorScheme.primary.withOpacity(0.08), - defaultShadowColor: theme.colorScheme.shadow, - defaultSurfaceTintColor: theme.colorScheme.surfaceTint, - defaultElevation: 1, - defaultPadding: const EdgeInsets.symmetric(horizontal: 8), - defaultBorderSide: BorderSide.none, - defaultShape: theme.useMaterial3 - ? const StadiumBorder() - : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - - if (icon != null) { - if (text == "") { - return const ErrorControl("Error displaying ElevatedButton", - description: - "\"icon\" must be specified together with \"text\"."); - } - if (isFilledButton) { - button = FilledButton.icon( - style: style, - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - icon: Icon( - icon, - color: iconColor, - ), - label: Text(text)); - } else if (isFilledTonalButton) { - button = FilledButton.tonalIcon( - style: style, - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - icon: Icon( - icon, - color: iconColor, - ), - label: Text(text)); - } else { - button = ElevatedButton.icon( - style: style, - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - icon: Icon( - icon, - color: iconColor, - ), - label: Text(text)); - } - } else { - Widget? child; - if (contentCtrls.isNotEmpty) { - child = createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive); - } else { - child = Text(text); - } - - if (isFilledButton) { - button = FilledButton( - style: style, - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - child: child); - } else if (isFilledTonalButton) { - button = FilledButton.tonal( - style: style, - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - child: child); - } else { - button = ElevatedButton( - style: style, - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - child: child); - } - } - - var focusValue = widget.control.attrString("focus"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); - } - return constrainedControl(context, button, widget.parent, widget.control); - }); - } -} diff --git a/packages/flet/lib/src/controls/expansion_panel.dart b/packages/flet/lib/src/controls/expansion_panel.dart index 6b6623d2ec..95be68a093 100644 --- a/packages/flet/lib/src/controls/expansion_panel.dart +++ b/packages/flet/lib/src/controls/expansion_panel.dart @@ -1,99 +1,71 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; +import 'scroll_notification_control.dart'; +import 'scrollable_control.dart'; -class ExpansionPanelListControl extends StatefulWidget { - final Control? parent; +class ExpansionPanelListControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const ExpansionPanelListControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const ExpansionPanelListControl({super.key, required this.control}); @override - State createState() => - _ExpansionPanelListControlState(); -} - -class _ExpansionPanelListControlState extends State - with FletStoreMixin { - @override Widget build(BuildContext context) { - debugPrint("ExpansionPanelList build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; + debugPrint("ExpansionPanelList build: ${control.id}"); - var panels = widget.children - .where((c) => c.name == "expansionpanel" && c.isVisible) - .toList(); - - void onChange(int index, bool isExpanded) { - widget.backend.updateControlState( - panels[index].id, {"expanded": isExpanded.toString().toLowerCase()}); - widget.backend.triggerControlEvent(widget.control.id, "change", "$index"); + void onChange(int index, bool expanded) { + final panel = control.children("controls")[index]; + panel.updateProperties({"expanded": expanded}, notify: true); + control.triggerEvent( + "change", {"index": index, "expanded": expanded, "data": index}); } - var panelList = - withControls(panels.map((p) => p.id), (content, panelViews) { - return ExpansionPanelList( - elevation: widget.control.attrDouble("elevation", 2)!, - materialGapSize: widget.control.attrDouble("spacing", 16)!, - dividerColor: widget.control.attrColor("dividerColor", context), - expandIconColor: - widget.control.attrColor("expandedIconColor", context), - expandedHeaderPadding: parseEdgeInsets( - widget.control, - "expandedHeaderPadding", - const EdgeInsets.symmetric(vertical: 16))!, - expansionCallback: !disabled - ? (int index, bool isExpanded) { - onChange(index, isExpanded); - } - : null, - children: panelViews.controlViews.map((panelView) { - var headerCtrls = panelView.children - .where((c) => c.name == "header" && c.isVisible); - var bodyCtrls = panelView.children - .where((c) => c.name == "content" && c.isVisible); + final panelList = ExpansionPanelList( + elevation: control.getDouble("elevation", 2)!, + materialGapSize: control.getDouble("spacing", 16)!, + dividerColor: control.getColor("divider_color", context), + expandIconColor: control.getColor("expand_icon_color", context), + expandedHeaderPadding: control.getEdgeInsets( + "expanded_header_padding", const EdgeInsets.symmetric(vertical: 16))!, + expansionCallback: !control.disabled + ? (int index, bool isExpanded) { + onChange(index, isExpanded); + } + : null, + children: control.children("controls").map((panelControl) { + panelControl.notifyParent = true; + return ExpansionPanel( + backgroundColor: panelControl.getColor("bgcolor", context), + isExpanded: panelControl.getBool("expanded", false)!, + highlightColor: panelControl.getColor("highlight_color", context), + splashColor: panelControl.getColor("splash_color", context), + canTapOnHeader: panelControl.getBool("can_tap_header", false)!, + headerBuilder: (BuildContext context, bool isExpanded) { + return panelControl.buildWidget("header") ?? + const ListTile(title: Text("Header Placeholder")); + }, + body: panelControl.buildWidget("content") ?? + const ListTile(title: Text("Body Placeholder")), + ); + }).toList(), + ); + + Widget result = ScrollableControl( + control: control, + scrollDirection: Axis.vertical, + wrapIntoScrollableView: true, + child: panelList, + ); - return ExpansionPanel( - backgroundColor: panelView.control.attrColor("bgColor", context), - isExpanded: panelView.control.attrBool("expanded", false)!, - highlightColor: - panelView.control.attrColor("highlightColor", context), - splashColor: panelView.control.attrColor("splashColor", context), - canTapOnHeader: - panelView.control.attrBool("canTapHeader", false)!, - headerBuilder: (BuildContext context, bool isExpanded) { - return headerCtrls.isNotEmpty - ? createControl( - widget.control, headerCtrls.first.id, disabled, - parentAdaptive: adaptive) - : const ListTile(title: Text("Header Placeholder")); - }, - body: bodyCtrls.isNotEmpty - ? createControl(widget.control, bodyCtrls.first.id, disabled, - parentAdaptive: adaptive) - : const ListTile(title: Text("Body Placeholder")), - ); - }).toList()); - }); + if (control.getBool("on_scroll", false)!) { + result = ScrollNotificationControl(control: control, child: result); + } - return constrainedControl( - context, panelList, widget.parent, widget.control); + return LayoutControl(control: control, child: result); } } diff --git a/packages/flet/lib/src/controls/expansion_tile.dart b/packages/flet/lib/src/controls/expansion_tile.dart index 1a0c43cd9a..b372d882ea 100644 --- a/packages/flet/lib/src/controls/expansion_tile.dart +++ b/packages/flet/lib/src/controls/expansion_tile.dart @@ -1,131 +1,126 @@ import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; +import '../utils/animations.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/theme.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; -class ExpansionTileControl extends StatelessWidget { - final Control? parent; +class ExpansionTileControl extends StatefulWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const ExpansionTileControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const ExpansionTileControl({super.key, required this.control}); @override - Widget build(BuildContext context) { - debugPrint("ExpansionTile build: ${control.id}"); + State createState() => _ExpansionTileControlState(); +} - var ctrls = children.where((c) => c.name == "controls" && c.isVisible); - var leadingCtrls = - children.where((c) => c.name == "leading" && c.isVisible); - var titleCtrls = children.where((c) => c.name == "title" && c.isVisible); - var subtitleCtrls = - children.where((c) => c.name == "subtitle" && c.isVisible); - var trailingCtrls = - children.where((c) => c.name == "trailing" && c.isVisible); +class _ExpansionTileControlState extends State { + late final ExpansibleController _controller; + bool _expanded = false; - if (titleCtrls.isEmpty) { - return const ErrorControl( - "ExpansionTile.title must be provided and visible"); - } + @override + void initState() { + super.initState(); + _controller = ExpansibleController(); + _expanded = widget.control.getBool("expanded", false)!; + } - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - bool onchange = control.attrBool("onchange", false)!; - bool maintainState = control.attrBool("maintainState", false)!; - bool initiallyExpanded = control.attrBool("initiallyExpanded", false)!; + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } - var iconColor = control.attrColor("iconColor", context); - var textColor = control.attrColor("textColor", context); - var bgColor = control.attrColor("bgColor", context); - var collapsedBgColor = control.attrColor("collapsedBgColor", context); - var collapsedIconColor = control.attrColor("collapsedIconColor", context); - var collapsedTextColor = control.attrColor("collapsedTextColor", context); + // Schedules an update to the controller after the current frame. + // This ensures the expansion/collapse animation is triggered safely. + void _scheduleControllerUpdate(bool expanded) { + SchedulerBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; // Prevents updates if the widget is disposed. - var affinity = parseListTileControlAffinity( - control.attrString("affinity"), ListTileControlAffinity.platform)!; - var clipBehavior = - parseClip(control.attrString("clipBehavior"), Clip.none)!; + if (expanded) { + _controller.expand(); + } else { + _controller.collapse(); + } + }); + } - var expandedCrossAxisAlignment = parseCrossAxisAlignment( - control.attrString("crossAxisAlignment"), CrossAxisAlignment.center)!; + @override + Widget build(BuildContext context) { + debugPrint("ExpansionTile build: ${widget.control.id}"); + final title = widget.control.buildTextOrWidget("title"); + if (title == null) { + return const ErrorControl( + "ExpansionTile.title must be provided and visible"); + } + + var expanded = widget.control.getBool("expanded", false)!; + if (_expanded != expanded) { + _expanded = expanded; + _scheduleControllerUpdate(expanded); + } + + var expandedCrossAxisAlignment = widget.control.getCrossAxisAlignment( + "expanded_cross_axis_alignment", CrossAxisAlignment.center)!; if (expandedCrossAxisAlignment == CrossAxisAlignment.baseline) { return const ErrorControl( - 'CrossAxisAlignment.baseline is not supported since the expanded ' + 'CrossAxisAlignment.BASELINE is not supported since the expanded ' 'controls are aligned in a column, not a row. ' 'Try aligning the controls differently.'); } - Function(bool)? onChange = (onchange) && !disabled - ? (expanded) { - debugPrint( - "ExpansionTile ${control.id} was ${expanded ? "expanded" : "collapsed"}"); - backend.triggerControlEvent(control.id, "change", "$expanded"); - } - : null; - - Widget tile = ExpansionTile( - controlAffinity: affinity, - childrenPadding: parseEdgeInsets(control, "controlsPadding"), - tilePadding: parseEdgeInsets(control, "tilePadding"), - expandedAlignment: parseAlignment(control, "expandedAlignment"), - expandedCrossAxisAlignment: - parseCrossAxisAlignment(control.attrString("crossAxisAlignment")), - backgroundColor: bgColor, - iconColor: iconColor, - textColor: textColor, - collapsedBackgroundColor: collapsedBgColor, - collapsedIconColor: collapsedIconColor, - collapsedTextColor: collapsedTextColor, - maintainState: maintainState, - initiallyExpanded: initiallyExpanded, - clipBehavior: clipBehavior, - shape: parseOutlinedBorder(control, "shape"), - collapsedShape: parseOutlinedBorder(control, "collapsedShape"), - onExpansionChanged: onChange, - visualDensity: parseVisualDensity(control.attrString("visualDensity")), - enableFeedback: control.attrBool("enableFeedback"), - showTrailingIcon: control.attrBool("showTrailingIcon", true)!, - enabled: !disabled, - minTileHeight: control.attrDouble("minTileHeight"), - dense: control.attrBool("dense"), - leading: leadingCtrls.isNotEmpty - ? createControl(control, leadingCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - title: createControl(control, titleCtrls.first.id, disabled, - parentAdaptive: adaptive), - subtitle: subtitleCtrls.isNotEmpty - ? createControl(control, subtitleCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - trailing: trailingCtrls.isNotEmpty - ? createControl(control, trailingCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - children: ctrls - .map((c) => - createControl(control, c.id, disabled, parentAdaptive: adaptive)) - .toList(), + final tile = ExpansionTile( + controller: _controller, + controlAffinity: widget.control.getListTileControlAffinity("affinity"), + childrenPadding: widget.control.getPadding("controls_padding"), + tilePadding: widget.control.getEdgeInsets("tile_padding"), + expandedAlignment: widget.control.getAlignment("expanded_alignment"), + expandedCrossAxisAlignment: expandedCrossAxisAlignment, + backgroundColor: widget.control.getColor("bgcolor", context), + iconColor: widget.control.getColor("icon_color", context), + textColor: widget.control.getColor("text_color", context), + collapsedBackgroundColor: + widget.control.getColor("collapsed_bgcolor", context), + collapsedIconColor: + widget.control.getColor("collapsed_icon_color", context), + collapsedTextColor: + widget.control.getColor("collapsed_text_color", context), + maintainState: widget.control.getBool("maintain_state", false)!, + initiallyExpanded: expanded, + clipBehavior: widget.control.getClipBehavior("clip_behavior"), + shape: widget.control.getShape("shape", Theme.of(context)), + collapsedShape: + widget.control.getShape("collapsed_shape", Theme.of(context)), + onExpansionChanged: (bool expanded) { + _expanded = expanded; + widget.control.updateProperties({"expanded": expanded}); + widget.control.triggerEvent("change", expanded); + }, + visualDensity: widget.control.getVisualDensity("visual_density"), + enableFeedback: widget.control.getBool("enable_feedback", true), + showTrailingIcon: widget.control.getBool("show_trailing_icon", true)!, + enabled: !widget.control.disabled, + minTileHeight: widget.control.getDouble("min_tile_height"), + dense: widget.control.getBool("dense"), + expansionAnimationStyle: + widget.control.getAnimationStyle("animation_style"), + leading: widget.control.buildIconOrWidget("leading"), + title: title, + subtitle: widget.control.buildTextOrWidget("subtitle"), + trailing: widget.control.buildIconOrWidget("trailing"), + children: widget.control.buildWidgets("controls"), ); - return constrainedControl(context, tile, parent, control); + return LayoutControl(control: widget.control, child: tile); } } diff --git a/packages/flet/lib/src/controls/file_picker.dart b/packages/flet/lib/src/controls/file_picker.dart deleted file mode 100644 index 320f17e723..0000000000 --- a/packages/flet/lib/src/controls/file_picker.dart +++ /dev/null @@ -1,337 +0,0 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:http/http.dart' as http; - -import '../flet_app_services.dart'; -import '../flet_control_backend.dart'; -import '../flet_server.dart'; -import '../models/control.dart'; -import '../utils/numbers.dart'; -import '../utils/platform.dart'; -import '../utils/strings.dart'; -import 'flet_store_mixin.dart'; - -class FilePickerResultEvent { - final String? path; - final List? files; - final String? error; - - FilePickerResultEvent( - {required this.path, required this.files, required this.error}); - - Map toJson() => { - 'path': path, - 'files': files?.map((f) => f.toJson()).toList(), - 'error': error - }; -} - -class FilePickerFile { - final int id; - final String name; - final String? path; - final int size; - - FilePickerFile( - {required this.id, - required this.name, - required this.path, - required this.size}); - - Map toJson() => - {'id': id, 'name': name, 'path': path, 'size': size}; -} - -class FilePickerUploadFile { - final int id; - final String name; - final String uploadUrl; - final String method; - - FilePickerUploadFile( - {required this.id, - required this.name, - required this.uploadUrl, - required this.method}); -} - -class FilePickerUploadProgressEvent { - final String name; - final double? progress; - final String? error; - - FilePickerUploadProgressEvent( - {required this.name, required this.progress, required this.error}); - - Map toJson() => { - 'file_name': name, - 'progress': progress, - 'error': error - }; -} - -class FilePickerControl extends StatefulWidget { - final Control? parent; - final Control control; - final Widget? nextChild; - final FletControlBackend backend; - - const FilePickerControl( - {super.key, - required this.parent, - required this.control, - required this.nextChild, - required this.backend}); - - @override - State createState() => _FilePickerControlState(); -} - -class _FilePickerControlState extends State - with FletStoreMixin { - String? _state; - String? _upload; - String? _path; - List? _files; - String? _error; - - @override - Widget build(BuildContext context) { - debugPrint("FilePicker build: ${widget.control.id}"); - - return withPageArgs((context, pageArgs) { - var state = widget.control.attrString("state"); - var upload = widget.control.attrString("upload"); - var dialogTitle = widget.control.attrString("dialogTitle"); - var fileName = widget.control.attrString("fileName"); - var initialDirectory = widget.control.attrString("initialDirectory"); - var allowMultiple = widget.control.attrBool("allowMultiple", false)!; - var allowedExtensions = - parseStringList(widget.control, "allowedExtensions"); - var srcBytesBase64 = widget.control.attrString("srcBytes"); - FileType fileType = FileType.values.firstWhere( - (m) => - m.name.toLowerCase() == - widget.control.attrString("fileType", "")!.toLowerCase(), - orElse: () => FileType.any); - if (allowedExtensions != null && allowedExtensions.isNotEmpty) { - fileType = FileType.custom; - } - - debugPrint("FilePicker _state: $_state, state: $state"); - - resetDialogState() { - _state = null; - widget.backend.updateControlState(widget.control.id, {"state": ""}); - } - - sendEvent() { - if (defaultTargetPlatform != TargetPlatform.windows || - !isDesktopPlatform()) { - resetDialogState(); - } - - widget.backend.triggerControlEvent( - widget.control.id, - "result", - json.encode(FilePickerResultEvent( - path: _path, - files: _files?.asMap().entries.map((entry) { - PlatformFile f = entry.value; - return FilePickerFile( - id: entry.key, // use entry's index as id - name: f.name, - path: kIsWeb ? null : f.path, - size: f.size, - ); - }).toList(), - error: _error)), - ); - } - - if (_state != state) { - _path = null; - _files = null; - _error = null; - _state = state; - - if (isDesktopPlatform() && - defaultTargetPlatform == TargetPlatform.windows) { - resetDialogState(); - } - - // pickFiles - if (state?.toLowerCase() == "pickfiles") { - FilePicker.platform - .pickFiles( - dialogTitle: dialogTitle, - initialDirectory: initialDirectory, - lockParentWindow: true, - type: fileType, - allowedExtensions: allowedExtensions, - allowMultiple: allowMultiple, - withData: false, - withReadStream: true) - .then((FilePickerResult? result) { - debugPrint("pickFiles() completed"); - _files = result?.files; - sendEvent(); - }); - } - // saveFile - else if (state?.toLowerCase() == "savefile" && !kIsWeb) { - if ((isAndroidPlatform() || isiOSPlatform()) && - srcBytesBase64 == null) { - _error = - '"src_bytes" is required on Android & iOS when saving a file.'; - sendEvent(); - } else { - FilePicker.platform - .saveFile( - dialogTitle: dialogTitle, - fileName: fileName != null || !isiOSPlatform() - ? fileName - : "new-file", - initialDirectory: initialDirectory, - lockParentWindow: true, - type: fileType, - allowedExtensions: allowedExtensions, - bytes: srcBytesBase64 != null - ? base64Decode(srcBytesBase64) - : null) - .then((result) { - debugPrint("saveFile() completed"); - _path = result; - sendEvent(); - }); - } - } - // getDirectoryPath - else if (state?.toLowerCase() == "getdirectorypath" && !kIsWeb) { - FilePicker.platform - .getDirectoryPath( - dialogTitle: dialogTitle, - initialDirectory: initialDirectory, - lockParentWindow: true, - ) - .then((result) { - debugPrint("getDirectoryPath() completed"); - _path = result; - sendEvent(); - }); - } - } - - // upload files - if (_upload != upload && upload != null && _files != null) { - _upload = upload; - uploadFiles( - upload, FletAppServices.of(context).server, pageArgs.pageUri!); - } - - return widget.nextChild ?? const SizedBox.shrink(); - }); - } - - Future uploadFiles(String filesJson, FletServer server, Uri pageUri) async { - var uj = json.decode(filesJson); - var uploadFiles = (uj as List).map((u) => FilePickerUploadFile( - id: parseInt(u["id"], -1)!, // -1 = invalid - name: u["name"], - uploadUrl: u["upload_url"], - method: u["method"])); - - for (var uf in uploadFiles) { - var file = ((uf.id >= 0 && uf.id < _files!.length) - ? _files![uf.id] - : null) // by id - ?? - _files!.firstWhereOrNull((f) => f.name == uf.name); // by name - - if (file != null) { - try { - await uploadFile( - file, server, getFullUploadUrl(pageUri, uf.uploadUrl), uf.method); - _files!.remove(file); // Remove the uploaded file - } catch (e) { - sendProgress(server, file.name, null, e.toString()); - } - } else { - debugPrint("Error: File '${uf.name}' (id: ${uf.id}) not found."); - } - } - } - - Future uploadFile(PlatformFile file, FletServer server, String uploadUrl, - String method) async { - final fileReadStream = file.readStream; - if (fileReadStream == null) { - throw Exception('Cannot read file from null stream'); - } - debugPrint("Uploading ${file.name}"); - final streamedRequest = http.StreamedRequest(method, Uri.parse(uploadUrl)) - ..headers.addAll({ - //'Cache-Control': 'no-cache', - }); - streamedRequest.contentLength = file.size; - - // send 0% - sendProgress(server, file.name, 0, null); - - double lastSent = 0; // send every 10% - double progress = 0; - int bytesSent = 0; - fileReadStream.listen((chunk) async { - //debugPrint(chunk.length); - streamedRequest.sink.add(chunk); - bytesSent += chunk.length; - progress = bytesSent / file.size; - if (progress >= lastSent) { - lastSent += 0.1; - if (progress != 1.0) { - sendProgress(server, file.name, progress, null); - } - } - }, onDone: () { - streamedRequest.sink.close(); - }); - - var streamedResponse = await streamedRequest.send(); - var response = await http.Response.fromStream(streamedResponse); - if (response.statusCode < 200 || response.statusCode > 204) { - sendProgress(server, file.name, null, - "Upload endpoint returned code ${response.statusCode}: ${response.body}"); - } else { - // send 100% - sendProgress(server, file.name, progress, null); - } - } - - void sendProgress( - FletServer server, String name, double? progress, String? error) { - widget.backend.triggerControlEvent( - widget.control.id, - "upload", - json.encode(FilePickerUploadProgressEvent( - name: name, progress: progress, error: error))); - } - - String getFullUploadUrl(Uri pageUri, String uploadUrl) { - Uri uploadUri = Uri.parse(uploadUrl); - if (!uploadUri.hasAuthority) { - return Uri( - scheme: pageUri.scheme, - host: pageUri.host, - port: pageUri.port, - path: uploadUri.path, - query: uploadUri.query) - .toString(); - } else { - return uploadUrl; - } - } -} diff --git a/packages/flet/lib/src/controls/flet_app_control.dart b/packages/flet/lib/src/controls/flet_app_control.dart index bdb5d7d072..34fbb0cc4d 100644 --- a/packages/flet/lib/src/controls/flet_app_control.dart +++ b/packages/flet/lib/src/controls/flet_app_control.dart @@ -2,16 +2,16 @@ import 'package:flutter/material.dart'; import '../flet_app.dart'; import '../flet_app_errors_handler.dart'; -import '../flet_app_services.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class FletAppControl extends StatefulWidget { - final Control? parent; final Control control; - const FletAppControl( - {super.key, required this.parent, required this.control}); + FletAppControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _FletAppControlState(); @@ -24,28 +24,40 @@ class _FletAppControlState extends State { Widget build(BuildContext context) { debugPrint("FletApp build: ${widget.control.id}"); - var url = widget.control.attrString("url", "")!; - var reconnectIntervalMs = widget.control.attrInt("reconnectIntervalMs"); - var reconnectTimeoutMs = widget.control.attrInt("reconnectTimeoutMs"); - var showAppStartupScreen = widget.control.attrBool("showAppStartupScreen"); + var url = widget.control.getString("url", "")!; + // Multiple embedded FletApps on the same page (e.g. a Preview inside + // another Flet app) each leave `url` empty, which collides in the + // JS-side worker registry keyed on `address`. Synthesize a unique + // address from the control id so each backend channel is its own. + if (url.isEmpty) { + url = "embedded:${widget.control.id}"; + } + var reconnectIntervalMs = widget.control.getInt("reconnect_interval_ms"); + var reconnectTimeoutMs = widget.control.getInt("reconnect_timeout_ms"); + var showAppStartupScreen = + widget.control.getBool("show_app_startup_screen"); var appStartupScreenMessage = - widget.control.attrString("appStartupScreenMessage"); - - return constrainedControl( - context, - FletApp( - controlId: widget.control.id, - reconnectIntervalMs: reconnectIntervalMs, - reconnectTimeoutMs: reconnectTimeoutMs, - showAppStartupScreen: showAppStartupScreen, - appStartupScreenMessage: appStartupScreenMessage, - pageUrl: url, - assetsDir: "", - errorsHandler: _errorsHandler, - createControlFactories: - FletAppServices.of(context).createControlFactories, - ), - widget.parent, - widget.control); + widget.control.getString("app_startup_screen_message"); + var appErrorMessage = widget.control.getString("app_error_message"); + + return LayoutControl( + control: widget.control, + child: FletApp( + controlId: widget.control.id, + reconnectIntervalMs: reconnectIntervalMs, + reconnectTimeoutMs: reconnectTimeoutMs, + showAppStartupScreen: showAppStartupScreen, + appStartupScreenMessage: appStartupScreenMessage, + appErrorMessage: appErrorMessage, + pageUrl: url, + assetsDir: widget.control.getString("assets_dir") ?? "", + errorsHandler: _errorsHandler, + extensions: FletBackend.of(context).extensions, + args: widget.control.get("args") != null + ? Map.from(widget.control.get("args")) + : null, + forcePyodide: widget.control.getBool("force_pyodide"), + ), + ); } } diff --git a/packages/flet/lib/src/controls/flet_store_mixin.dart b/packages/flet/lib/src/controls/flet_store_mixin.dart deleted file mode 100644 index 24a69de2d3..0000000000 --- a/packages/flet/lib/src/controls/flet_store_mixin.dart +++ /dev/null @@ -1,90 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_redux/flutter_redux.dart'; - -import '../models/app_state.dart'; -import '../models/control.dart'; -import '../models/control_ancestor_view_model.dart'; -import '../models/control_tree_view_model.dart'; -import '../models/control_view_model.dart'; -import '../models/controls_view_model.dart'; -import '../models/page_args_model.dart'; -import '../models/page_size_view_model.dart'; - -mixin FletStoreMixin { - Widget withPageArgs(Widget Function(BuildContext, PageArgsModel) build) { - return StoreConnector( - distinct: true, - converter: (store) => PageArgsModel.fromStore(store), - builder: build); - } - - Widget withPageSize(Widget Function(BuildContext, PageSizeViewModel) build) { - return StoreConnector( - distinct: true, - converter: (store) => PageSizeViewModel.fromStore(store), - builder: build); - } - - Widget withPagePlatform(Widget Function(BuildContext, TargetPlatform) build) { - return StoreConnector( - distinct: true, - converter: (store) => TargetPlatform.values.firstWhere( - (a) => - a.name.toLowerCase() == - store.state.controls["page"]! - .attrString("platform", "")! - .toLowerCase(), - orElse: () => defaultTargetPlatform), - builder: build); - } - - Widget withControl( - String id, Widget Function(BuildContext, ControlViewModel?) build) { - return StoreConnector( - distinct: true, - converter: (store) { - return ControlViewModel.fromStore(store, id); - }, - ignoreChange: (state) { - return state.controls[id] == null; - }, - builder: build); - } - - Widget withControlTree(Control control, - Widget Function(BuildContext, ControlTreeViewModel) build) { - return StoreConnector( - distinct: true, - converter: (store) => ControlTreeViewModel.fromStore(store, control), - builder: build); - } - - Widget withControlAncestor(String id, String ancestorType, - Widget Function(BuildContext, ControlAncestorViewModel) build) { - return StoreConnector( - distinct: true, - converter: (store) => - ControlAncestorViewModel.fromStore(store, id, ancestorType), - ignoreChange: (state) { - return state.controls[id] == null; - }, - builder: build); - } - - Widget withControls(Iterable controlIds, - Widget Function(BuildContext, ControlsViewModel) build) { - return StoreConnector( - distinct: true, - converter: (store) => ControlsViewModel.fromStore(store, controlIds), - ignoreChange: (state) { - for (var id in controlIds) { - if (state.controls[id] == null) { - return true; - } - } - return false; - }, - builder: build); - } -} diff --git a/packages/flet/lib/src/controls/floating_action_button.dart b/packages/flet/lib/src/controls/floating_action_button.dart index 967c714625..3a8eabbae1 100644 --- a/packages/flet/lib/src/controls/floating_action_button.dart +++ b/packages/flet/lib/src/controls/floating_action_button.dart @@ -1,84 +1,76 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; -import '../utils/icons.dart'; +import '../utils/colors.dart'; import '../utils/launch_url.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class FloatingActionButtonControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const FloatingActionButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const FloatingActionButtonControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("FloatingActionButtonControl build: ${control.id}"); - String? text = control.attrString("text"); - IconData? icon = parseIcon(control.attrString("icon")); - String url = control.attrString("url", "")!; - String? urlTarget = control.attrString("urlTarget"); - double? disabledElevation = control.attrDouble("disabledElevation"); - double? elevation = control.attrDouble("elevation"); - double? hoverElevation = control.attrDouble("hoverElevation"); - double? highlightElevation = control.attrDouble("highlightElevation"); - double? focusElevation = control.attrDouble("focusElevation"); - Color? bgColor = control.attrColor("bgColor", context); - Color? foregroundColor = control.attrColor("foregroundColor", context); - Color? splashColor = control.attrColor("splashColor", context); - Color? hoverColor = control.attrColor("hoverColor", context); - Color? focusColor = control.attrColor("focusColor", context); - OutlinedBorder? shape = parseOutlinedBorder(control, "shape"); + var content = control.buildTextOrWidget("content"); + var icon = control.buildIconOrWidget("icon"); + var url = control.getUrl("url"); + var disabledElevation = control.getDouble("disabled_elevation"); + var elevation = control.getDouble("elevation"); + var hoverElevation = control.getDouble("hover_elevation"); + var highlightElevation = control.getDouble("highlight_elevation"); + var focusElevation = control.getDouble("focus_elevation"); + var bgcolor = control.getColor("bgcolor", context); + var foregroundColor = control.getColor("foreground_color", context); + var splashColor = control.getColor("splash_color", context); + var hoverColor = control.getColor("hover_color", context); + var focusColor = control.getColor("focus_color", context); + var shape = control.getShape("shape", Theme.of(context)); var clipBehavior = - parseClip(control.attrString("clipBehavior"), Clip.none)!; - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool autofocus = control.attrBool("autofocus", false)!; - bool mini = control.attrBool("mini", false)!; - bool? enableFeedback = control.attrBool("enableFeedback"); - var mouseCursor = parseMouseCursor(control.attrString("mouseCursor")); - bool disabled = control.isDisabled || parentDisabled; + parseClip(control.getString("clip_behavior"), Clip.none)!; + var autofocus = control.getBool("autofocus", false)!; + var mini = control.getBool("mini", false)!; + var enableFeedback = control.getBool("enable_feedback"); + var mouseCursor = control.getMouseCursor("mouse_cursor"); - Function()? onPressed = disabled + Function()? onPressed = control.disabled ? null : () { - debugPrint("FloatingActionButtonControl ${control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); + if (url != null) { + openWebBrowser(url); } - backend.triggerControlEvent(control.id, "click"); + control.triggerEvent("click"); }; - if (text == null && icon == null && contentCtrls.isEmpty) { + if (icon == null && content == null) { return const ErrorControl( - "FloatingActionButton has nothing to display. Provide at minimum one of these: text, icon, content"); + "FloatingActionButton has nothing to display. Provide at minimum one of these: icon, content"); } + var child = icon != null + ? content == null + ? icon + : null + : content; Widget button; - if (contentCtrls.isNotEmpty) { + if (child != null) { button = FloatingActionButton( heroTag: control.id, autofocus: autofocus, onPressed: onPressed, mouseCursor: mouseCursor, - backgroundColor: bgColor, + backgroundColor: bgcolor, foregroundColor: foregroundColor, hoverColor: hoverColor, splashColor: splashColor, @@ -92,60 +84,16 @@ class FloatingActionButtonControl extends StatelessWidget { focusColor: focusColor, shape: shape, mini: mini, - child: createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive)); - } else if (icon != null && text == null) { - button = FloatingActionButton( - heroTag: control.id, - autofocus: autofocus, - onPressed: onPressed, - mouseCursor: mouseCursor, - backgroundColor: bgColor, - foregroundColor: foregroundColor, - hoverColor: hoverColor, - splashColor: splashColor, - elevation: elevation, - disabledElevation: disabledElevation, - focusElevation: focusElevation, - hoverElevation: hoverElevation, - highlightElevation: highlightElevation, - enableFeedback: enableFeedback, - clipBehavior: clipBehavior, - focusColor: focusColor, - shape: shape, - mini: mini, - child: Icon(icon)); - } else if (icon == null && text != null) { - button = FloatingActionButton( - heroTag: control.id, - autofocus: autofocus, - onPressed: onPressed, - mouseCursor: mouseCursor, - backgroundColor: bgColor, - foregroundColor: foregroundColor, - hoverColor: hoverColor, - splashColor: splashColor, - elevation: elevation, - disabledElevation: disabledElevation, - focusElevation: focusElevation, - hoverElevation: hoverElevation, - highlightElevation: highlightElevation, - enableFeedback: enableFeedback, - clipBehavior: clipBehavior, - focusColor: focusColor, - shape: shape, - mini: mini, - child: Text(text), - ); - } else if (icon != null && text != null) { + child: child); + } else if (content != null) { button = FloatingActionButton.extended( heroTag: control.id, autofocus: autofocus, onPressed: onPressed, mouseCursor: mouseCursor, - label: Text(text), - icon: Icon(icon), - backgroundColor: bgColor, + label: content, + icon: icon, + backgroundColor: bgcolor, foregroundColor: foregroundColor, hoverColor: hoverColor, splashColor: splashColor, @@ -161,9 +109,9 @@ class FloatingActionButtonControl extends StatelessWidget { ); } else { return const ErrorControl( - "FloatingActionButton has nothing to display. Provide at minimum one of these: text, icon, content"); + "FloatingActionButton has nothing to display. Provide at minimum icon or content."); } - return constrainedControl(context, button, parent, control); + return LayoutControl(control: control, child: button); } } diff --git a/packages/flet/lib/src/controls/gesture_detector.dart b/packages/flet/lib/src/controls/gesture_detector.dart index 0d4b91d352..1cee33ab56 100644 --- a/packages/flet/lib/src/controls/gesture_detector.dart +++ b/packages/flet/lib/src/controls/gesture_detector.dart @@ -1,32 +1,23 @@ import 'dart:async'; -import 'dart:convert'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/events.dart'; +import '../utils/gesture_detector.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class GestureDetectorControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const GestureDetectorControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + GestureDetectorControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _GestureDetectorControlState(); @@ -34,18 +25,21 @@ class GestureDetectorControl extends StatefulWidget { class _GestureDetectorControlState extends State { int _panTimestamp = DateTime.now().millisecondsSinceEpoch; - double _panX = 0; - double _panY = 0; + Offset _localPan = Offset.zero; + Offset _globalPan = Offset.zero; int _hDragTimestamp = DateTime.now().millisecondsSinceEpoch; - double _hDragX = 0; - double _hDragY = 0; + Offset _localHorizontalDrag = Offset.zero; + Offset _globalHorizontalDrag = Offset.zero; int _vDragTimestamp = DateTime.now().millisecondsSinceEpoch; - double _vDragX = 0; - double _vDragY = 0; + Offset _localVerticalDrag = Offset.zero; + Offset _globalVerticalDrag = Offset.zero; int _hoverTimestamp = DateTime.now().millisecondsSinceEpoch; - double _hoverX = 0; - double _hoverY = 0; + Offset _localHover = Offset.zero; Timer? _debounce; + bool _rightPanActive = false; + int _rightPanTimestamp = DateTime.now().millisecondsSinceEpoch; + Offset _rightPanStart = Offset.zero; + TapDownDetails? _tapDownDetails; @override void initState() { @@ -62,85 +56,120 @@ class _GestureDetectorControlState extends State { Widget build(BuildContext context) { debugPrint("GestureDetector build: ${widget.control.id}"); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - void sendEvent(String eventName, [dynamic eventData = ""]) { - var d = ""; - if (eventData is String) { - d = eventData; - } else if (eventData is Map) { - d = json.encode(eventData); - } - - debugPrint("GestureDetector ${widget.control.id} $eventName"); - widget.backend.triggerControlEvent(widget.control.id, eventName, d); - } - - var onHover = widget.control.attrBool("onHover", false)!; - var onEnter = widget.control.attrBool("onEnter", false)!; - var onExit = widget.control.attrBool("onExit", false)!; - var onTap = widget.control.attrBool("onTap", false)!; - var onTapDown = widget.control.attrBool("onTapDown", false)!; - var onTapUp = widget.control.attrBool("onTapUp", false)!; - var onSecondaryTap = widget.control.attrBool("onSecondaryTap", false)!; + var content = widget.control.buildWidget("content"); + + var onHover = widget.control.getBool("on_hover", false)!; + var onEnter = widget.control.getBool("on_enter", false)!; + var onExit = widget.control.getBool("on_exit", false)!; + var onTap = widget.control.getBool("on_tap", false)!; + var onTapDown = widget.control.getBool("on_tap_down", false)!; + var onTapUp = widget.control.getBool("on_tap_up", false)!; + var onTapMove = widget.control.getBool("on_tap_move", false)!; + var onTapCancel = widget.control.getBool("on_tap_cancel", false)!; + var onSecondaryTap = widget.control.getBool("on_secondary_tap", false)!; var onSecondaryTapDown = - widget.control.attrBool("onSecondaryTapDown", false)!; - var onSecondaryTapUp = widget.control.attrBool("onSecondaryTapUp", false)!; - var onLongPressStart = widget.control.attrBool("onLongPressStart", false)!; - var onLongPressEnd = widget.control.attrBool("onLongPressEnd", false)!; + widget.control.getBool("on_secondary_tap_down", false)!; + var onSecondaryTapUp = + widget.control.getBool("on_secondary_tap_up", false)!; + var onSecondaryTapCancel = + widget.control.getBool("on_secondary_tap_cancel", false)!; + var onTertiaryTapDown = + widget.control.getBool("on_tertiary_tap_down", false)!; + var onTertiaryTapUp = widget.control.getBool("on_tertiary_tap_up", false)!; + var onTertiaryTapCancel = + widget.control.getBool("on_tertiary_tap_cancel", false)!; + var onDoubleTap = widget.control.getBool("on_double_tap", false)!; + var onDoubleTapDown = widget.control.getBool("on_double_tap_down", false)!; + var onDoubleTapCancel = + widget.control.getBool("on_double_tap_cancel", false)!; + var onLongPressDown = widget.control.getBool("on_long_press_down", false)!; + var onLongPressCancel = + widget.control.getBool("on_long_press_cancel", false)!; + var onLongPress = widget.control.getBool("on_long_press", false)!; + var onLongPressStart = + widget.control.getBool("on_long_press_start", false)!; + var onLongPressMoveUpdate = + widget.control.getBool("on_long_press_move_update", false)!; + var onLongPressUp = widget.control.getBool("on_long_press_up", false)!; + var onLongPressEnd = widget.control.getBool("on_long_press_end", false)!; + var onSecondaryLongPressDown = + widget.control.getBool("on_secondary_long_press_down", false)!; + var onSecondaryLongPressCancel = + widget.control.getBool("on_secondary_long_press_cancel", false)!; + var onSecondaryLongPress = + widget.control.getBool("on_secondary_long_press", false)!; var onSecondaryLongPressStart = - widget.control.attrBool("onSecondaryLongPressStart", false)!; + widget.control.getBool("on_secondary_long_press_start", false)!; + var onSecondaryLongPressMoveUpdate = + widget.control.getBool("on_secondary_long_press_move_update", false)!; + var onSecondaryLongPressUp = + widget.control.getBool("on_secondary_long_press_up", false)!; var onSecondaryLongPressEnd = - widget.control.attrBool("onSecondaryLongPressEnd", false)!; - var onDoubleTap = widget.control.attrBool("onDoubleTap", false)!; - var onDoubleTapDown = widget.control.attrBool("onDoubleTapDown", false)!; + widget.control.getBool("on_secondary_long_press_end", false)!; + var onTertiaryLongPressDown = + widget.control.getBool("on_tertiary_long_press_down", false)!; + var onTertiaryLongPressCancel = + widget.control.getBool("on_tertiary_long_press_cancel", false)!; + var onTertiaryLongPress = + widget.control.getBool("on_tertiary_long_press", false)!; + var onTertiaryLongPressStart = + widget.control.getBool("on_tertiary_long_press_start", false)!; + var onTertiaryLongPressMoveUpdate = + widget.control.getBool("on_tertiary_long_press_move_update", false)!; + var onTertiaryLongPressUp = + widget.control.getBool("on_tertiary_long_press_up", false)!; + var onTertiaryLongPressEnd = + widget.control.getBool("on_tertiary_long_press_end", false)!; + var onHorizontalDragDown = + widget.control.getBool("on_horizontal_drag_down", false)!; var onHorizontalDragStart = - widget.control.attrBool("onHorizontalDragStart", false)!; + widget.control.getBool("on_horizontal_drag_start", false)!; var onHorizontalDragUpdate = - widget.control.attrBool("onHorizontalDragUpdate", false)!; + widget.control.getBool("on_horizontal_drag_update", false)!; var onHorizontalDragEnd = - widget.control.attrBool("onHorizontalDragEnd", false)!; + widget.control.getBool("on_horizontal_drag_end", false)!; + var onHorizontalDragCancel = + widget.control.getBool("on_horizontal_drag_cancel", false)!; + var onVerticalDragDown = + widget.control.getBool("on_vertical_drag_down", false)!; var onVerticalDragStart = - widget.control.attrBool("onVerticalDragStart", false)!; + widget.control.getBool("on_vertical_drag_start", false)!; var onVerticalDragUpdate = - widget.control.attrBool("onVerticalDragUpdate", false)!; + widget.control.getBool("on_vertical_drag_update", false)!; var onVerticalDragEnd = - widget.control.attrBool("onVerticalDragEnd", false)!; - var onPanStart = widget.control.attrBool("onPanStart", false)!; - var onPanUpdate = widget.control.attrBool("onPanUpdate", false)!; - var onPanEnd = widget.control.attrBool("onPanEnd", false)!; - var onScaleStart = widget.control.attrBool("onScaleStart", false)!; - var onScaleUpdate = widget.control.attrBool("onScaleUpdate", false)!; - var onScaleEnd = widget.control.attrBool("onScaleEnd", false)!; - var onMultiTap = widget.control.attrBool("onMultiTap", false)!; - var onMultiLongPress = widget.control.attrBool("onMultiLongPress", false)!; - var multiTapTouches = widget.control.attrInt("multiTapTouches", 0)!; - var onScroll = widget.control.attrBool("onScroll", false)!; - - var content = contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: - widget.control.attrBool("adaptive") ?? widget.parentAdaptive) - : null; + widget.control.getBool("on_vertical_drag_end", false)!; + var onVerticalDragCancel = + widget.control.getBool("on_vertical_drag_cancel", false)!; + var onPanDown = widget.control.getBool("on_pan_down", false)!; + var onPanStart = widget.control.getBool("on_pan_start", false)!; + var onPanUpdate = widget.control.getBool("on_pan_update", false)!; + var onPanEnd = widget.control.getBool("on_pan_end", false)!; + var onPanCancel = widget.control.getBool("on_pan_cancel", false)!; + var onScaleStart = widget.control.getBool("on_scale_start", false)!; + var onScaleUpdate = widget.control.getBool("on_scale_update", false)!; + var onScaleEnd = widget.control.getBool("on_scale_end", false)!; + var onForcePressStart = + widget.control.getBool("on_force_press_start", false)!; + var onForcePressPeak = + widget.control.getBool("on_force_press_peak", false)!; + var onForcePressUpdate = + widget.control.getBool("on_force_press_update", false)!; + var onForcePressEnd = widget.control.getBool("on_force_press_end", false)!; + var onMultiTap = widget.control.getBool("on_multi_tap", false)!; + var onMultiLongPress = + widget.control.getBool("on_multi_long_press", false)!; + var multiTapTouches = widget.control.getInt("multi_tap_touches", 0)!; + var onScroll = widget.control.getBool("on_scroll", false)!; Widget? result = content; - var dragInterval = widget.control.attrInt("dragInterval", 0)!; + var dragInterval = widget.control.getInt("drag_interval", 0)!; void handlePanStart(DragStartDetails details) { - _panX = details.localPosition.dx; - _panY = details.localPosition.dy; + _localPan = Offset(details.localPosition.dx, details.localPosition.dy); + _globalPan = Offset(details.globalPosition.dx, details.globalPosition.dy); if (onPanStart) { - sendEvent("pan_start", { - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "ts": details.sourceTimeStamp?.inMilliseconds - }); + widget.control.triggerEvent("pan_start", details.toMap()); } } @@ -148,35 +177,17 @@ class _GestureDetectorControlState extends State { var now = DateTime.now().millisecondsSinceEpoch; if (now - _panTimestamp > dragInterval) { _panTimestamp = now; - var dx = details.localPosition.dx - _panX; - var dy = details.localPosition.dy - _panY; - _panX = details.localPosition.dx; - _panY = details.localPosition.dy; - sendEvent("pan_update", { - "dx": dx, - "dy": dy, - "pd": details.primaryDelta, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "ts": details.sourceTimeStamp?.inMilliseconds - }); + widget.control + .triggerEvent("pan_update", details.toMap(_localPan, _globalPan)); + _localPan = details.localPosition; } } void handleHorizontalDragStart(DragStartDetails details) { - _hDragX = details.localPosition.dx; - _hDragY = details.localPosition.dy; + _localHorizontalDrag = details.localPosition; + _globalHorizontalDrag = details.globalPosition; if (onHorizontalDragStart) { - sendEvent("horizontal_drag_start", { - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "ts": details.sourceTimeStamp?.inMilliseconds - }); + widget.control.triggerEvent("horizontal_drag_start", details.toMap()); } } @@ -184,35 +195,18 @@ class _GestureDetectorControlState extends State { var now = DateTime.now().millisecondsSinceEpoch; if (now - _hDragTimestamp > dragInterval) { _hDragTimestamp = now; - var dx = details.localPosition.dx - _hDragX; - var dy = details.localPosition.dy - _hDragY; - _hDragX = details.localPosition.dx; - _hDragY = details.localPosition.dy; - sendEvent("horizontal_drag_update", { - "dx": dx, - "dy": dy, - "pd": details.primaryDelta, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "ts": details.sourceTimeStamp?.inMilliseconds - }); + widget.control.triggerEvent("horizontal_drag_update", + details.toMap(_localHorizontalDrag, _globalHorizontalDrag)); + _localHorizontalDrag = details.localPosition; + _globalHorizontalDrag = details.globalPosition; } } void handleVerticalDragStart(DragStartDetails details) { - _vDragX = details.localPosition.dx; - _vDragY = details.localPosition.dy; + _localVerticalDrag = details.localPosition; + _globalVerticalDrag = details.globalPosition; if (onVerticalDragStart) { - sendEvent("vertical_drag_start", { - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "ts": details.sourceTimeStamp?.inMilliseconds - }); + widget.control.triggerEvent("vertical_drag_start", details.toMap()); } } @@ -220,37 +214,19 @@ class _GestureDetectorControlState extends State { var now = DateTime.now().millisecondsSinceEpoch; if (now - _vDragTimestamp > dragInterval) { _vDragTimestamp = now; - var dx = details.localPosition.dx - _vDragX; - var dy = details.localPosition.dy - _vDragY; - _vDragX = details.localPosition.dx; - _vDragY = details.localPosition.dy; - sendEvent("vertical_drag_update", { - "dx": dx, - "dy": dy, - "pd": details.primaryDelta, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "ts": details.sourceTimeStamp?.inMilliseconds - }); + widget.control.triggerEvent("vertical_drag_update", + details.toMap(_localVerticalDrag, _globalVerticalDrag)); + _localVerticalDrag = details.localPosition; + _globalVerticalDrag = details.globalPosition; } } - var hoverInterval = widget.control.attrInt("hoverInterval", 0)!; + var hoverInterval = widget.control.getInt("hover_interval", 0)!; void handleEnter(PointerEnterEvent details) { - _hoverX = details.localPosition.dx; - _hoverY = details.localPosition.dy; + _localHover = details.localPosition; if (onEnter) { - sendEvent("enter", { - "ts": details.timeStamp.inMilliseconds, - "kind": details.kind.name, - "gx": details.position.dx, - "gy": details.position.dy, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy - }); + widget.control.triggerEvent("enter", details.toMap()); } } @@ -258,181 +234,282 @@ class _GestureDetectorControlState extends State { var now = DateTime.now().millisecondsSinceEpoch; if (now - _hoverTimestamp > hoverInterval) { _hoverTimestamp = now; - var dx = details.localPosition.dx - _hoverX; - var dy = details.localPosition.dy - _hoverY; - _hoverX = details.localPosition.dx; - _hoverY = details.localPosition.dy; - sendEvent("hover", { - "ts": details.timeStamp.inMilliseconds, - "kind": details.kind.name, - "gx": details.position.dx, - "gy": details.position.dy, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "dx": dx, - "dy": dy, - }); + widget.control.triggerEvent("hover", details.toMap(_localHover)); + _localHover = details.localPosition; } } result = (onTap | onTapDown | onTapUp | + onTapMove | + onTapCancel | onSecondaryTap | onSecondaryTapDown | onSecondaryTapUp | + onSecondaryTapCancel | + onTertiaryTapDown | + onTertiaryTapUp | + onTertiaryTapCancel | + onDoubleTap | + onDoubleTapDown | + onDoubleTapCancel | + onLongPressDown | + onLongPressCancel | + onLongPress | onLongPressStart | + onLongPressMoveUpdate | + onLongPressUp | onLongPressEnd | + onSecondaryLongPressDown | + onSecondaryLongPressCancel | + onSecondaryLongPress | onSecondaryLongPressStart | + onSecondaryLongPressMoveUpdate | + onSecondaryLongPressUp | onSecondaryLongPressEnd | - onDoubleTap | - onDoubleTapDown | + onTertiaryLongPressDown | + onTertiaryLongPressCancel | + onTertiaryLongPress | + onTertiaryLongPressStart | + onTertiaryLongPressMoveUpdate | + onTertiaryLongPressUp | + onTertiaryLongPressEnd | + onHorizontalDragDown | onHorizontalDragStart | onHorizontalDragUpdate | onHorizontalDragEnd | + onHorizontalDragCancel | + onVerticalDragDown | onVerticalDragStart | onVerticalDragUpdate | onVerticalDragEnd | + onVerticalDragCancel | + onPanDown | onPanStart | onPanUpdate | onPanEnd | + onPanCancel | onScaleStart | onScaleUpdate | - onScaleEnd) + onScaleEnd | + onForcePressStart | + onForcePressPeak | + onForcePressUpdate | + onForcePressEnd) ? GestureDetector( behavior: HitTestBehavior.translucent, excludeFromSemantics: - widget.control.attrBool("excludeFromSemantics", false)!, + widget.control.getBool("exclude_from_semantics", false)!, trackpadScrollCausesScale: - widget.control.attrBool("trackpadScrollCausesScale", false)!, + widget.control.getBool("trackpad_scroll_causes_scale", false)!, supportedDevices: () { - var supportedDevicesString = - widget.control.attrString("allowedDevices"); - var supportedDevicesJson = supportedDevicesString != null - ? jsonDecode(supportedDevicesString) - : null; - if (supportedDevicesJson != null && - (supportedDevicesJson is Iterable && - supportedDevicesJson is! Map)) { - return supportedDevicesJson - .map((d) => parsePointerDeviceKind(d)) - .nonNulls - .toSet(); - } - return null; + var supportedDevices = + widget.control.get>("allowed_devices"); + return supportedDevices + ?.map((d) => parsePointerDeviceKind(d)) + .nonNulls + .toSet(); }(), onTap: onTap - ? () { - sendEvent("tap"); - } + ? () => + widget.control.triggerEvent("tap", _tapDownDetails?.toMap()) : null, - onTapDown: onTapDown - ? (details) { - sendEvent("tap_down", { - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + onTapDown: onTapDown || onTap + ? (TapDownDetails details) { + _tapDownDetails = details; + if (onTapDown) { + widget.control.triggerEvent("tap_down", details.toMap()); + } } : null, onTapUp: onTapUp - ? (details) { - sendEvent("tap_up", { - "kind": details.kind.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + ? (TapUpDetails details) { + widget.control.triggerEvent("tap_up", details.toMap()); } : null, - onSecondaryTap: onSecondaryTap + onTapMove: onTapMove + ? (TapMoveDetails details) { + widget.control.triggerEvent("tap_move", details.toMap()); + } + : null, + onTapCancel: onTapCancel ? () { - sendEvent("secondary_tap"); + widget.control.triggerEvent("tap_cancel"); } : null, + onSecondaryTap: onSecondaryTap + ? () => widget.control.triggerEvent("secondary_tap") + : null, onSecondaryTapDown: onSecondaryTapDown - ? (details) { - sendEvent("secondary_tap_down", { - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + ? (TapDownDetails details) { + widget.control + .triggerEvent("secondary_tap_down", details.toMap()); } : null, onSecondaryTapUp: onSecondaryTapUp - ? (details) { - sendEvent("secondary_tap_up", { - "kind": details.kind.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + ? (TapUpDetails details) { + widget.control + .triggerEvent("secondary_tap_up", details.toMap()); + } + : null, + onSecondaryTapCancel: onSecondaryTapCancel + ? () { + widget.control.triggerEvent("secondary_tap_cancel"); + } + : null, + onTertiaryTapDown: onTertiaryTapDown + ? (TapDownDetails details) { + widget.control + .triggerEvent("tertiary_tap_down", details.toMap()); + } + : null, + onTertiaryTapUp: onTertiaryTapUp + ? (TapUpDetails details) { + widget.control + .triggerEvent("tertiary_tap_up", details.toMap()); + } + : null, + onTertiaryTapCancel: onTertiaryTapCancel + ? () { + widget.control.triggerEvent("tertiary_tap_cancel"); + } + : null, + onLongPressDown: onLongPressDown + ? (LongPressDownDetails details) { + widget.control + .triggerEvent("long_press_down", details.toMap()); + } + : null, + onLongPressCancel: onLongPressCancel + ? () { + widget.control.triggerEvent("long_press_cancel"); + } + : null, + onLongPress: onLongPress + ? () { + widget.control.triggerEvent("long_press"); } : null, onLongPressStart: onLongPressStart - ? (details) { - sendEvent("long_press_start", { - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + ? (LongPressStartDetails details) { + widget.control + .triggerEvent("long_press_start", details.toMap()); + } + : null, + onLongPressMoveUpdate: onLongPressMoveUpdate + ? (LongPressMoveUpdateDetails details) { + widget.control.triggerEvent( + "long_press_move_update", details.toMap()); + } + : null, + onLongPressUp: onLongPressUp + ? () { + widget.control.triggerEvent("long_press_up"); } : null, onLongPressEnd: onLongPressEnd - ? (details) { - sendEvent("long_press_end", { - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "vx": details.velocity.pixelsPerSecond.dx, - "vy": details.velocity.pixelsPerSecond.dy - }); + ? (LongPressEndDetails details) { + widget.control + .triggerEvent("long_press_end", details.toMap()); + } + : null, + onSecondaryLongPressDown: onSecondaryLongPressDown + ? (LongPressDownDetails details) { + widget.control.triggerEvent( + "secondary_long_press_down", details.toMap()); + } + : null, + onSecondaryLongPressCancel: onSecondaryLongPressCancel + ? () { + widget.control.triggerEvent("secondary_long_press_cancel"); + } + : null, + onSecondaryLongPress: onSecondaryLongPress + ? () { + widget.control.triggerEvent("secondary_long_press"); } : null, onSecondaryLongPressStart: onSecondaryLongPressStart - ? (details) { - sendEvent("secondary_long_press_start", { - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + ? (LongPressStartDetails details) { + widget.control.triggerEvent( + "secondary_long_press_start", details.toMap()); + } + : null, + onSecondaryLongPressMoveUpdate: onSecondaryLongPressMoveUpdate + ? (LongPressMoveUpdateDetails details) { + widget.control.triggerEvent( + "secondary_long_press_move_update", details.toMap()); + } + : null, + onSecondaryLongPressUp: onSecondaryLongPressUp + ? () { + widget.control.triggerEvent("secondary_long_press_up"); } : null, onSecondaryLongPressEnd: onSecondaryLongPressEnd - ? (details) { - sendEvent("secondary_long_press_end", { - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - "vx": details.velocity.pixelsPerSecond.dx, - "vy": details.velocity.pixelsPerSecond.dy - }); + ? (LongPressEndDetails details) { + widget.control.triggerEvent( + "secondary_long_press_end", details.toMap()); } : null, - onDoubleTap: onDoubleTap + onTertiaryLongPressDown: onTertiaryLongPressDown + ? (LongPressDownDetails details) { + widget.control.triggerEvent( + "tertiary_long_press_down", details.toMap()); + } + : null, + onTertiaryLongPressCancel: onTertiaryLongPressCancel + ? () { + widget.control.triggerEvent("tertiary_long_press_cancel"); + } + : null, + onTertiaryLongPress: onTertiaryLongPress + ? () { + widget.control.triggerEvent("tertiary_long_press"); + } + : null, + onTertiaryLongPressStart: onTertiaryLongPressStart + ? (LongPressStartDetails details) { + widget.control.triggerEvent( + "tertiary_long_press_start", details.toMap()); + } + : null, + onTertiaryLongPressMoveUpdate: onTertiaryLongPressMoveUpdate + ? (LongPressMoveUpdateDetails details) { + widget.control.triggerEvent( + "tertiary_long_press_move_update", details.toMap()); + } + : null, + onTertiaryLongPressUp: onTertiaryLongPressUp ? () { - sendEvent("double_tap"); + widget.control.triggerEvent("tertiary_long_press_up"); } : null, + onTertiaryLongPressEnd: onTertiaryLongPressEnd + ? (LongPressEndDetails details) { + widget.control.triggerEvent( + "tertiary_long_press_end", details.toMap()); + } + : null, + onDoubleTap: onDoubleTap + ? () => widget.control.triggerEvent("double_tap") + : null, onDoubleTapDown: onDoubleTapDown - ? (details) { - sendEvent("double_tap_down", { - "kind": details.kind?.name, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "gx": details.globalPosition.dx, - "gy": details.globalPosition.dy, - }); + ? (TapDownDetails details) { + widget.control + .triggerEvent("double_tap_down", details.toMap()); + } + : null, + onDoubleTapCancel: onDoubleTapCancel + ? () { + widget.control.triggerEvent("double_tap_cancel"); + } + : null, + onHorizontalDragDown: onHorizontalDragDown + ? (DragDownDetails details) { + widget.control + .triggerEvent("horizontal_drag_down", details.toMap()); } : null, onHorizontalDragStart: @@ -445,29 +522,42 @@ class _GestureDetectorControlState extends State { } : null, onHorizontalDragEnd: onHorizontalDragEnd - ? (details) { - sendEvent("horizontal_drag_end", { - "pv": details.primaryVelocity, - "vx": details.velocity.pixelsPerSecond.dx, - "vy": details.velocity.pixelsPerSecond.dy - }); + ? (DragEndDetails details) { + widget.control + .triggerEvent("horizontal_drag_end", details.toMap()); + } + : null, + onHorizontalDragCancel: onHorizontalDragCancel + ? () { + widget.control.triggerEvent("horizontal_drag_cancel"); + } + : null, + onVerticalDragDown: onVerticalDragDown + ? (DragDownDetails details) { + widget.control + .triggerEvent("vertical_drag_down", details.toMap()); } : null, onVerticalDragStart: (onVerticalDragStart || onVerticalDragUpdate) ? handleVerticalDragStart : null, onVerticalDragUpdate: onVerticalDragUpdate - ? (details) { - handleVerticalDragUpdate(details); - } + ? (details) => handleVerticalDragUpdate(details) : null, onVerticalDragEnd: onVerticalDragEnd ? (details) { - sendEvent("vertical_drag_end", { - "pv": details.primaryVelocity, - "vx": details.velocity.pixelsPerSecond.dx, - "vy": details.velocity.pixelsPerSecond.dy - }); + widget.control + .triggerEvent("vertical_drag_end", details.toMap()); + } + : null, + onVerticalDragCancel: onVerticalDragCancel + ? () { + widget.control.triggerEvent("vertical_drag_cancel"); + } + : null, + onPanDown: onPanDown + ? (DragDownDetails details) { + widget.control.triggerEvent("pan_down", details.toMap()); } : null, onPanStart: (onPanStart || onPanUpdate) ? handlePanStart : null, @@ -477,49 +567,53 @@ class _GestureDetectorControlState extends State { } : null, onPanEnd: onPanEnd - ? (details) { - sendEvent("pan_end", { - "pv": details.primaryVelocity, - "vx": details.velocity.pixelsPerSecond.dx, - "vy": details.velocity.pixelsPerSecond.dy - }); + ? (DragEndDetails details) { + widget.control.triggerEvent("pan_end", details.toMap()); + } + : null, + onPanCancel: onPanCancel + ? () { + widget.control.triggerEvent("pan_cancel"); + } + : null, + onForcePressStart: onForcePressStart + ? (ForcePressDetails details) { + widget.control + .triggerEvent("force_press_start", details.toMap()); + } + : null, + onForcePressPeak: onForcePressPeak + ? (ForcePressDetails details) { + widget.control + .triggerEvent("force_press_peak", details.toMap()); + } + : null, + onForcePressUpdate: onForcePressUpdate + ? (ForcePressDetails details) { + widget.control + .triggerEvent("force_press_update", details.toMap()); + } + : null, + onForcePressEnd: onForcePressEnd + ? (ForcePressDetails details) { + widget.control + .triggerEvent("force_press_end", details.toMap()); } : null, onScaleStart: onScaleStart - ? (details) { - sendEvent("scale_start", { - "fpx": details.focalPoint.dx, - "fpy": details.focalPoint.dy, - "lfpx": details.localFocalPoint.dx, - "lfpy": details.localFocalPoint.dy, - "pc": details.pointerCount - }); + ? (ScaleStartDetails details) { + widget.control.triggerEvent("scale_start", details.toMap()); } : null, onScaleUpdate: onScaleUpdate - ? (details) { - sendEvent("scale_update", { - "fpx": details.focalPoint.dx, - "fpy": details.focalPoint.dy, - "fpdx": details.focalPointDelta.dx, - "fpdy": details.focalPointDelta.dy, - "lfpx": details.localFocalPoint.dx, - "lfpy": details.localFocalPoint.dy, - "pc": details.pointerCount, - "hs": details.horizontalScale, - "vs": details.verticalScale, - "s": details.scale, - "r": details.rotation, - }); + ? (ScaleUpdateDetails details) { + widget.control + .triggerEvent("scale_update", details.toMap()); } : null, onScaleEnd: onScaleEnd - ? (details) { - sendEvent("scale_end", { - "pc": details.pointerCount, - "vx": details.velocity.pixelsPerSecond.dx, - "vy": details.velocity.pixelsPerSecond.dy - }); + ? (ScaleEndDetails details) { + widget.control.triggerEvent("scale_end", details.toMap()); } : null, child: result) @@ -536,13 +630,14 @@ class _GestureDetectorControlState extends State { instance.minNumberOfTouches = multiTapTouches; instance.onMultiTap = (correctNumberOfTouches) { if (onMultiTap) { - sendEvent("multi_tap", correctNumberOfTouches.toString()); + widget.control.triggerEvent( + "multi_tap", {"ct": correctNumberOfTouches}); } if (onMultiLongPress) { if (correctNumberOfTouches) { _debounce = Timer(const Duration(milliseconds: 1000), () { - sendEvent("multi_long_press"); + widget.control.triggerEvent("multi_long_press"); }); } else if (_debounce?.isActive ?? false) { _debounce!.cancel(); @@ -556,45 +651,66 @@ class _GestureDetectorControlState extends State { ) : result; - result = onScroll - ? Listener( - behavior: HitTestBehavior.translucent, - onPointerSignal: (details) { - if (details is PointerScrollEvent) { - sendEvent("scroll", { - "gx": details.position.dx, - "gy": details.position.dy, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy, - "dx": details.scrollDelta.dx, - "dy": details.scrollDelta.dy, - }); + var onRightPanStart = widget.control.getBool("on_right_pan_start", false)!; + var onRightPanUpdate = + widget.control.getBool("on_right_pan_update", false)!; + var onRightPanEnd = widget.control.getBool("on_right_pan_end", false)!; + + if (onScroll || onRightPanStart || onRightPanUpdate || onRightPanEnd) { + result = Listener( + behavior: HitTestBehavior.translucent, + onPointerSignal: onScroll + ? (details) { + if (details is PointerScrollEvent) { + widget.control.triggerEvent("scroll", details.toMap()); + } } - }, - child: result, - ) - : result; + : null, + onPointerDown: onRightPanStart + ? (event) { + if (event.kind == PointerDeviceKind.mouse && + event.buttons == kSecondaryMouseButton) { + _rightPanActive = true; + _rightPanStart = event.localPosition; + widget.control.triggerEvent("right_pan_start", event.toMap()); + } + } + : null, + onPointerMove: onRightPanUpdate + ? (event) { + if (_rightPanActive && event.buttons == kSecondaryMouseButton) { + var now = DateTime.now().millisecondsSinceEpoch; + if (now - _rightPanTimestamp > dragInterval) { + _rightPanTimestamp = now; + widget.control.triggerEvent( + "right_pan_update", event.toMap(_rightPanStart)); + _rightPanStart = event.localPosition; + } + } + } + : null, + onPointerUp: onRightPanEnd + ? (event) { + if (_rightPanActive) { + _rightPanActive = false; + widget.control.triggerEvent("right_pan_end", event.toMap()); + } + } + : null, + child: result, + ); + } - var mouseCursor = widget.control.attrString("mouseCursor"); + var mouseCursor = + parseMouseCursor(widget.control.getString("mouse_cursor")); result = ((mouseCursor != null) || onHover || onEnter || onExit) ? MouseRegion( - cursor: parseMouseCursor(mouseCursor, MouseCursor.defer)!, - onHover: onHover - ? (details) { - handleHover(details); - } - : null, + cursor: mouseCursor ?? MouseCursor.defer, + onHover: onHover ? (details) => handleHover(details) : null, onEnter: (onEnter || onHover) ? handleEnter : null, onExit: onExit - ? (details) { - sendEvent("exit", { - "ts": details.timeStamp.inMilliseconds, - "kind": details.kind.name, - "gx": details.position.dx, - "gy": details.position.dy, - "lx": details.localPosition.dx, - "ly": details.localPosition.dy - }); + ? (PointerExitEvent details) { + widget.control.triggerEvent("exit", details.toMap()); } : null, child: result, @@ -606,59 +722,6 @@ class _GestureDetectorControlState extends State { "GestureDetector should have at least one event handler defined"); } - return constrainedControl(context, result, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: result); } } - -class MultiTouchGestureRecognizer extends MultiTapGestureRecognizer { - late MultiTouchGestureRecognizerCallback onMultiTap; - var numberOfTouches = 0; - int minNumberOfTouches = 0; - - MultiTouchGestureRecognizer() { - super.onTapDown = (pointer, details) => addTouch(pointer, details); - super.onTapUp = (pointer, details) => removeTouch(pointer, details); - super.onTapCancel = (pointer) => cancelTouch(pointer); - super.onTap = (pointer) => captureDefaultTap(pointer); - } - - void addTouch(int pointer, TapDownDetails details) { - //debugPrint("Add touch: $pointer"); - numberOfTouches++; - if (numberOfTouches == minNumberOfTouches) { - onMultiTap(true); - numberOfTouches = 0; - } - } - - void removeTouch(int pointer, TapUpDetails details) { - onRemoveTouch(pointer); - } - - void cancelTouch(int pointer) { - onRemoveTouch(pointer); - } - - void onRemoveTouch(int pointer) { - //debugPrint("Remove touch: $pointer"); - onMultiTap(false); - numberOfTouches = 0; - } - - void captureDefaultTap(int pointer) {} - - @override - set onTapDown(onTapDown) {} - - @override - set onTapUp(onTapUp) {} - - @override - set onTapCancel(onTapCancel) {} - - @override - set onTap(onTap) {} -} - -typedef MultiTouchGestureRecognizerCallback = void Function( - bool correctNumberOfTouches); diff --git a/packages/flet/lib/src/controls/grid_view.dart b/packages/flet/lib/src/controls/grid_view.dart index 2b28181a16..481f5732a3 100644 --- a/packages/flet/lib/src/controls/grid_view.dart +++ b/packages/flet/lib/src/controls/grid_view.dart @@ -1,29 +1,22 @@ import 'package:flutter/widgets.dart'; -import '../flet_control_backend.dart'; +import '../controls/control_widget.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/keys.dart'; +import '../utils/layout.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; import 'scroll_notification_control.dart'; import 'scrollable_control.dart'; class GridViewControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - final FletControlBackend backend; - - const GridViewControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + GridViewControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _GridViewControlState(); @@ -48,31 +41,25 @@ class _GridViewControlState extends State { Widget build(BuildContext context) { debugPrint("GridViewControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - - final horizontal = widget.control.attrBool("horizontal", false)!; - final runsCount = widget.control.attrInt("runsCount", 1)!; - final maxExtent = widget.control.attrDouble("maxExtent"); - final spacing = widget.control.attrDouble("spacing", 10)!; - final semanticChildCount = widget.control.attrInt("semanticChildCount"); - final runSpacing = widget.control.attrDouble("runSpacing", 10)!; - final padding = parseEdgeInsets(widget.control, "padding"); - final childAspectRatio = widget.control.attrDouble("childAspectRatio", 1)!; - final reverse = widget.control.attrBool("reverse", false)!; - final cacheExtent = widget.control.attrDouble("cacheExtent"); + final horizontal = widget.control.getBool("horizontal", false)!; + final runsCount = widget.control.getInt("runs_count", 1)!; + final maxExtent = widget.control.getDouble("max_extent"); + final spacing = widget.control.getDouble("spacing", 10)!; + final semanticChildCount = widget.control.getInt("semantic_child_count"); + final runSpacing = widget.control.getDouble("run_spacing", 10)!; + final padding = widget.control.getPadding("padding"); + final childAspectRatio = widget.control.getDouble("child_aspect_ratio", 1)!; + final reverse = widget.control.getBool("reverse", false)!; + final cacheExtent = widget.control.getDouble("cache_extent"); + final controls = widget.control.children("controls"); var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!; - - List visibleControls = - widget.children.where((c) => c.isVisible).toList(); + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!; var gridView = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - debugPrint("GridView constraints.maxWidth: ${constraints.maxWidth}"); - debugPrint("GridView constraints.maxHeight: ${constraints.maxHeight}"); + // debugPrint("GridView constraints.maxWidth: ${constraints.maxWidth}"); + // debugPrint("GridView constraints.maxHeight: ${constraints.maxHeight}"); var shrinkWrap = (!horizontal && constraints.maxHeight == double.infinity) || @@ -91,7 +78,7 @@ class _GridViewControlState extends State { childAspectRatio: childAspectRatio); var buildControlsOnDemand = - widget.control.attrBool("buildControlsOnDemand", true)!; + widget.control.getBool("build_controls_on_demand", true)!; Widget child = !buildControlsOnDemand ? GridView( scrollDirection: horizontal ? Axis.horizontal : Axis.vertical, @@ -103,9 +90,11 @@ class _GridViewControlState extends State { shrinkWrap: shrinkWrap, padding: padding, gridDelegate: gridDelegate, - children: visibleControls - .map((c) => createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive)) + children: controls + .map((item) => ControlWidget( + key: ValueKey(item.getKey("key")?.value ?? item.id), + control: item, + )) .toList(), ) : GridView.builder( @@ -118,31 +107,42 @@ class _GridViewControlState extends State { shrinkWrap: shrinkWrap, padding: padding, gridDelegate: gridDelegate, - itemCount: visibleControls.length, + itemCount: controls.length, itemBuilder: (context, index) { - return createControl( - widget.control, visibleControls[index].id, disabled, - parentAdaptive: adaptive); + return ControlWidget( + key: ValueKey(controls[index].getKey("key")?.value ?? + controls[index].id), + control: controls[index], + ); }, ); + if (horizontal && + constraints.maxHeight == double.infinity && + widget.control.getDouble("height") == null && + widget.control.getExpand("expand", 0)! <= 0) { + return const ErrorControl( + "Error displaying GridViewControl: height is unbounded.", + description: + "Set a fixed height, a non-zero expand, or place inside " + "a control with bounded height."); + } + child = ScrollableControl( control: widget.control, scrollDirection: horizontal ? Axis.horizontal : Axis.vertical, scrollController: _controller, - backend: widget.backend, - parentAdaptive: adaptive, child: child); - if (widget.control.attrBool("onScroll", false)!) { - child = ScrollNotificationControl( - control: widget.control, backend: widget.backend, child: child); + if (widget.control.getBool("on_scroll", false)!) { + child = + ScrollNotificationControl(control: widget.control, child: child); } return child; }, ); - return constrainedControl(context, gridView, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: gridView); } } diff --git a/packages/flet/lib/src/controls/haptic_feedback.dart b/packages/flet/lib/src/controls/haptic_feedback.dart deleted file mode 100644 index 43dc53e328..0000000000 --- a/packages/flet/lib/src/controls/haptic_feedback.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; - -class HapticFeedbackControl extends StatefulWidget { - final Control? parent; - final Control control; - final Widget? nextChild; - final FletControlBackend backend; - - const HapticFeedbackControl( - {super.key, - required this.parent, - required this.control, - required this.nextChild, - required this.backend}); - - @override - State createState() => _HapticFeedbackControlState(); -} - -class _HapticFeedbackControlState extends State { - @override - void deactivate() { - widget.backend.unsubscribeMethods(widget.control.id); - super.deactivate(); - } - - @override - Widget build(BuildContext context) { - debugPrint("HapticFeedback build: ${widget.control.id}"); - - widget.backend.subscribeMethods(widget.control.id, - (methodName, args) async { - switch (methodName) { - case "heavy_impact": - HapticFeedback.heavyImpact(); - break; - case "light_impact": - HapticFeedback.lightImpact(); - break; - case "medium_impact": - HapticFeedback.mediumImpact(); - break; - case "vibrate": - HapticFeedback.vibrate(); - break; - } - return null; - }); - - return widget.nextChild ?? const SizedBox.shrink(); - } -} diff --git a/packages/flet/lib/src/controls/hero.dart b/packages/flet/lib/src/controls/hero.dart new file mode 100644 index 0000000000..a5f38eef69 --- /dev/null +++ b/packages/flet/lib/src/controls/hero.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; + +class HeroControl extends StatelessWidget { + final Control control; + + const HeroControl({super.key, required this.control}); + + Widget _buildFlightShuttle( + BuildContext flightContext, + Animation animation, + HeroFlightDirection flightDirection, + BuildContext fromHeroContext, + BuildContext toHeroContext, + ) { + final toHero = toHeroContext.widget as Hero; + return Material( + type: MaterialType.transparency, + child: DefaultTextStyle( + style: DefaultTextStyle.of(toHeroContext).style, + child: toHero.child, + ), + ); + } + + @override + Widget build(BuildContext context) { + debugPrint("Hero build: ${control.id}"); + + final content = control.buildWidget("content"); + if (content == null) { + return const ErrorControl("Hero.content must be provided and visible"); + } + + final tag = control.getString("tag"); + if (tag == null) { + return const ErrorControl("Hero.tag must be provided"); + } + + return LayoutControl( + control: control, + child: Hero( + tag: tag, + flightShuttleBuilder: _buildFlightShuttle, + transitionOnUserGestures: + control.getBool("transition_on_user_gestures", false)!, + child: content, + ), + ); + } +} diff --git a/packages/flet/lib/src/controls/icon.dart b/packages/flet/lib/src/controls/icon.dart index bdab3126ae..6a29dcce9f 100644 --- a/packages/flet/lib/src/controls/icon.dart +++ b/packages/flet/lib/src/controls/icon.dart @@ -1,37 +1,36 @@ -import 'package:flet/src/utils/box.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; +import '../utils/box.dart'; +import '../utils/colors.dart'; import '../utils/icons.dart'; import '../utils/images.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class IconControl extends StatelessWidget { - final Control? parent; final Control control; - const IconControl({super.key, required this.parent, required this.control}); + const IconControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Icon build: ${control.id}"); - return constrainedControl( - context, - Icon( - parseIcon(control.attrString("name", "")!), - size: control.attrDouble("size"), - color: control.attrColor("color", context), - blendMode: parseBlendMode(control.attrString("blendMode")), - semanticLabel: control.attrString("semanticsLabel"), - applyTextScaling: control.attrBool("applyTextScaling"), - fill: control.attrDouble("fill"), - grade: control.attrDouble("grade"), - weight: control.attrDouble("weight"), - opticalSize: control.attrDouble("opticalSize"), - shadows: parseBoxShadow(Theme.of(context), control, "shadows"), - ), - parent, - control); + return LayoutControl( + control: control, + child: Icon( + control.getIconData("icon"), + size: control.getDouble("size"), + color: control.getColor("color", context), + blendMode: control.getBlendMode("blend_mode"), + semanticLabel: control.getString("semantics_label"), + applyTextScaling: control.getBool("apply_text_scaling"), + fill: control.getDouble("fill"), + grade: control.getDouble("grade"), + weight: control.getDouble("weight"), + opticalSize: control.getDouble("optical_size"), + shadows: control.getBoxShadows("shadows", Theme.of(context)), + )); } } diff --git a/packages/flet/lib/src/controls/icon_button.dart b/packages/flet/lib/src/controls/icon_button.dart index 82e635815c..ac7e6b1be2 100644 --- a/packages/flet/lib/src/controls/icon_button.dart +++ b/packages/flet/lib/src/controls/icon_button.dart @@ -1,36 +1,28 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; import '../utils/box.dart'; import '../utils/buttons.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/icons.dart'; import '../utils/launch_url.dart'; import '../utils/mouse.dart'; -import '../utils/theme.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; import 'cupertino_button.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; class IconButtonControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const IconButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + IconButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _IconButtonControlState(); @@ -39,25 +31,35 @@ class IconButtonControl extends StatefulWidget { class _IconButtonControlState extends State with FletStoreMixin { late final FocusNode _focusNode; - String? _lastFocusValue; @override void initState() { super.initState(); _focusNode = FocusNode(); _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); } @override void dispose() { _focusNode.removeListener(_onFocusChange); _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); super.dispose(); } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("IconButton.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown IconButton method: $name"); + } } @override @@ -65,76 +67,60 @@ class _IconButtonControlState extends State debugPrint("IconButton build: ${widget.control.id}"); return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && + if (widget.control.adaptive == true && (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS)) { return CupertinoButtonControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend); + control: widget.control, + ); } - IconData? icon = parseIcon(widget.control.attrString("icon")); - IconData? selectedIcon = - parseIcon(widget.control.attrString("selectedIcon")); - Color? iconColor = widget.control.attrColor("iconColor", context); - Color? highlightColor = - widget.control.attrColor("highlightColor", context); - Color? selectedIconColor = - widget.control.attrColor("selectedIconColor", context); - Color? bgColor = widget.control.attrColor("bgColor", context); - Color? disabledColor = widget.control.attrColor("disabledColor", context); - Color? hoverColor = widget.control.attrColor("hoverColor", context); - Color? splashColor = widget.control.attrColor("splashColor", context); - Color? focusColor = widget.control.attrColor("focusColor", context); - double? iconSize = widget.control.attrDouble("iconSize"); - double? splashRadius = widget.control.attrDouble("splashRadius"); - var padding = parseEdgeInsets(widget.control, "padding"); - var alignment = parseAlignment(widget.control, "alignment"); + var icon = widget.control.get("icon"); + var selectedIcon = widget.control.get("selected_icon"); + var content = widget.control.child("content"); + var iconColor = widget.control.getColor("icon_color", context); + var highlightColor = widget.control.getColor("highlight_color", context); + var selectedIconColor = + widget.control.getColor("selected_icon_color", context); + var disabledColor = widget.control.getColor("disabled_color", context); + var hoverColor = widget.control.getColor("hover_color", context); + var splashColor = widget.control.getColor("splash_color", context); + var focusColor = widget.control.getColor("focus_color", context); + var iconSize = widget.control.getDouble("icon_size"); + var splashRadius = widget.control.getDouble("splash_radius"); + var padding = widget.control.getEdgeInsets("padding"); + var alignment = widget.control.getAlignment("alignment"); var sizeConstraints = - parseBoxConstraints(widget.control, "sizeConstraints"); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool enableFeedback = widget.control.attrBool("enableFeedback", true)!; - bool selected = widget.control.attrBool("selected", false)!; - String url = widget.control.attrString("url", "")!; - String? urlTarget = widget.control.attrString("urlTarget"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var mouseCursor = - parseMouseCursor(widget.control.attrString("mouseCursor")); - var visualDensity = - parseVisualDensity(widget.control.attrString("visualDensity")); - - Function()? onPressed = disabled - ? null - : () { - debugPrint("Button ${widget.control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); + widget.control.getBoxConstraints("size_constraints"); + var autofocus = widget.control.getBool("autofocus", false)!; + var enableFeedback = widget.control.getBool("enable_feedback", true)!; + var selected = widget.control.getBool("selected"); + var mouseCursor = widget.control.getMouseCursor("mouse_cursor"); + var url = widget.control.getUrl("url"); + + Function()? onPressed = !widget.control.disabled + ? () { + if (url != null) { + openWebBrowser(url); } - widget.backend.triggerControlEvent(widget.control.id, "click"); - }; + widget.control.triggerEvent("click"); + } + : null; - Function()? onLongPressHandler = !disabled - ? () => - widget.backend.triggerControlEvent(widget.control.id, "longPress") + Function()? onLongPressHandler = !widget.control.disabled + ? () => widget.control.triggerEvent("long_press") : null; - Function(bool)? onHoverHandler = !disabled - ? (bool hovered) => widget.backend.triggerControlEvent( - widget.control.id, "hover", hovered.toString()) + Function(bool)? onHoverHandler = !widget.control.disabled + ? (bool hovered) => FletBackend.of(context) + .triggerControlEvent(widget.control, "hover", hovered) : null; Widget? button; var theme = Theme.of(context); - - var style = parseButtonStyle(Theme.of(context), widget.control, "style", + var style = parseButtonStyle( + widget.control.internals?["style"], Theme.of(context), defaultForegroundColor: theme.colorScheme.primary, defaultBackgroundColor: Colors.transparent, defaultOverlayColor: Colors.transparent, @@ -147,8 +133,32 @@ class _IconButtonControlState extends State ? const StadiumBorder() : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - if (icon != null) { - button = IconButton( + Widget? iconWidget; + if (icon is Control) { + iconWidget = ControlWidget(control: icon); + } else if (icon is int) { + iconWidget = Icon(widget.control.getIconData("icon"), color: iconColor); + } else if (content != null) { + iconWidget = ControlWidget(control: content); + } + + Widget? selectedIconWidget; + if (selectedIcon is Control) { + selectedIconWidget = ControlWidget(control: selectedIcon); + } else if (selectedIcon is int) { + selectedIconWidget = Icon(widget.control.getIconData("selected_icon"), + color: selectedIconColor); + } + + if (iconWidget == null) { + return const ErrorControl( + "IconButton must have either icon or a visible content specified."); + } + + var variant = widget.control.type; + + if (variant == "FilledIconButton") { + button = IconButton.filled( autofocus: autofocus, focusNode: _focusNode, highlightColor: highlightColor, @@ -160,69 +170,88 @@ class _IconButtonControlState extends State focusColor: focusColor, splashColor: splashColor, splashRadius: splashRadius, - icon: Icon( - icon, - color: iconColor, - ), + icon: iconWidget, iconSize: iconSize, mouseCursor: mouseCursor, - visualDensity: visualDensity, style: style, isSelected: selected, constraints: sizeConstraints, onLongPress: onLongPressHandler, onHover: onHoverHandler, - selectedIcon: selectedIcon != null - ? Icon(selectedIcon, color: selectedIconColor) - : null, + selectedIcon: selectedIconWidget, onPressed: onPressed); - } else if (contentCtrls.isNotEmpty) { - button = IconButton( + } else if (variant == "FilledTonalIconButton") { + button = IconButton.filledTonal( autofocus: autofocus, focusNode: _focusNode, highlightColor: highlightColor, - disabledColor: highlightColor, - hoverColor: highlightColor, + disabledColor: disabledColor, + hoverColor: hoverColor, enableFeedback: enableFeedback, padding: padding, alignment: alignment, focusColor: focusColor, splashColor: splashColor, splashRadius: splashRadius, - onPressed: onPressed, + icon: iconWidget, iconSize: iconSize, mouseCursor: mouseCursor, - visualDensity: visualDensity, style: style, isSelected: selected, constraints: sizeConstraints, onLongPress: onLongPressHandler, onHover: onHoverHandler, - selectedIcon: selectedIcon != null - ? Icon(selectedIcon, color: selectedIconColor) - : null, - icon: createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive)); + selectedIcon: selectedIconWidget, + onPressed: onPressed); + } else if (variant == "OutlinedIconButton") { + button = IconButton.outlined( + autofocus: autofocus, + focusNode: _focusNode, + highlightColor: highlightColor, + disabledColor: disabledColor, + hoverColor: hoverColor, + enableFeedback: enableFeedback, + padding: padding, + alignment: alignment, + focusColor: focusColor, + splashColor: splashColor, + splashRadius: splashRadius, + icon: iconWidget, + iconSize: iconSize, + mouseCursor: mouseCursor, + style: style, + isSelected: selected, + constraints: sizeConstraints, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + selectedIcon: selectedIconWidget, + onPressed: onPressed); } else { - return const ErrorControl( - "IconButton must have either icon or a visible content specified."); - } - - if (bgColor != null) { - button = Container( - decoration: - ShapeDecoration(color: bgColor, shape: const CircleBorder()), - child: button, - ); - } - - var focusValue = widget.control.attrString("focus"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); + button = IconButton( + autofocus: autofocus, + focusNode: _focusNode, + highlightColor: highlightColor, + disabledColor: disabledColor, + hoverColor: hoverColor, + enableFeedback: enableFeedback, + padding: padding, + alignment: alignment, + focusColor: focusColor, + splashColor: splashColor, + splashRadius: splashRadius, + icon: iconWidget, + iconSize: iconSize, + mouseCursor: mouseCursor, + style: style, + isSelected: selected, + constraints: sizeConstraints, + onLongPress: onLongPressHandler, + onHover: onHoverHandler, + selectedIcon: selectedIconWidget, + onPressed: onPressed); } - return constrainedControl(context, button, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: button); }); } } diff --git a/packages/flet/lib/src/controls/image.dart b/packages/flet/lib/src/controls/image.dart index 694cb64560..d79acff0eb 100644 --- a/packages/flet/lib/src/controls/image.dart +++ b/packages/flet/lib/src/controls/image.dart @@ -1,87 +1,106 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/animations.dart'; import '../utils/borders.dart'; -import '../utils/box.dart'; +import '../utils/colors.dart'; import '../utils/images.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; -class ImageControl extends StatelessWidget with FletStoreMixin { - final Control? parent; - final List children; +class ImageControl extends StatelessWidget { final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; static const String svgTag = " xmlns=\"http://www.w3.org/2000/svg\""; - const ImageControl( - {super.key, - required this.parent, - required this.children, - required this.control, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const ImageControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Image build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - var src = control.attrString("src", "")!; - var srcBase64 = control.attrString("srcBase64", "")!; - if (src == "" && srcBase64 == "") { - return const ErrorControl( - "Image must have either \"src\" or \"src_base64\" specified."); + var rawSrc = control.get("src"); + if (rawSrc == null) { + return const ErrorControl("Image must have \"src\" specified."); } - var errorContentCtrls = - children.where((c) => c.name == "error_content" && c.isVisible); - return withPageArgs((context, pageArgs) { - Widget? image = buildImage( + final width = control.getDouble("width"); + final height = control.getDouble("height"); + final fit = control.getBoxFit("fit"); + final repeat = control.getImageRepeat("repeat", ImageRepeat.noRepeat)!; + final color = control.getColor("color", context); + final colorBlendMode = control.getBlendMode("color_blend_mode"); + final semanticsLabel = control.getString("semantics_label"); + final gaplessPlayback = control.getBool("gapless_playback", false)!; + final excludeFromSemantics = + control.getBool("exclude_from_semantics", false)!; + final filterQuality = + control.getFilterQuality("filter_quality", FilterQuality.medium)!; + final cacheWidth = control.getInt("cache_width"); + final cacheHeight = control.getInt("cache_height"); + final antiAlias = control.getBool("anti_alias", false)!; + final errorContent = control.buildWidget("error_content"); + + // Optional placeholder shown while the image is loading. + Widget? placeholder; + final placeholderSrc = control.get("placeholder_src"); + if (placeholderSrc != null) { + placeholder = buildImage( context: context, - control: control, - src: src, - srcBase64: srcBase64, - width: control.attrDouble("width"), - height: control.attrDouble("height"), - cacheWidth: control.attrInt("cacheWidth"), - cacheHeight: control.attrInt("cacheHeight"), - antiAlias: control.attrBool("antiAlias", false)!, - repeat: parseImageRepeat( - control.attrString("repeat"), ImageRepeat.noRepeat)!, - fit: parseBoxFit(control.attrString("fit")), - colorBlendMode: parseBlendMode(control.attrString("colorBlendMode")), - color: control.attrColor("color", context), - semanticsLabel: control.attrString("semanticsLabel"), - gaplessPlayback: control.attrBool("gaplessPlayback"), - excludeFromSemantics: control.attrBool("excludeFromSemantics", false)!, - filterQuality: parseFilterQuality( - control.attrString("filterQuality"), FilterQuality.medium)!, - disabled: disabled, - pageArgs: pageArgs, - errorCtrl: errorContentCtrls.isNotEmpty - ? createControl(control, errorContentCtrls.first.id, disabled, - parentAdaptive: control.isAdaptive ?? parentAdaptive) - : null, + src: placeholderSrc, + width: width, + height: height, + fit: control.getBoxFit("placeholder_fit", fit), + repeat: repeat, + color: color, + colorBlendMode: colorBlendMode, + semanticsLabel: semanticsLabel, + gaplessPlayback: gaplessPlayback, + excludeFromSemantics: excludeFromSemantics, + filterQuality: filterQuality, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + antiAlias: antiAlias, + errorCtrl: errorContent, ); - return constrainedControl( - context, _clipCorners(image, control), parent, control); - }); + } + + final fadeConfig = ImageFadeConfig( + placeholder: placeholder, + fadeInAnimation: control.getAnimation("fade_in_animation"), + placeholderFadeOutAnimation: + control.getAnimation("placeholder_fade_out_animation")); + + Widget? image = buildImage( + context: context, + src: rawSrc, + width: width, + height: height, + cacheWidth: cacheWidth, + cacheHeight: cacheHeight, + antiAlias: antiAlias, + repeat: repeat, + fit: fit, + colorBlendMode: colorBlendMode, + color: color, + semanticsLabel: semanticsLabel, + gaplessPlayback: gaplessPlayback, + excludeFromSemantics: excludeFromSemantics, + filterQuality: filterQuality, + disabled: control.disabled, + errorCtrl: errorContent, + fadeConfig: fadeConfig.enabled ? fadeConfig : null, + ); + return LayoutControl( + control: control, + child: _clipCorners(image, control.getBorderRadius("border_radius"))); } - Widget _clipCorners(Widget image, Control control) { - var borderRadius = parseBorderRadius(control, "borderRadius"); + Widget _clipCorners(Widget image, BorderRadius? borderRadius) { return borderRadius != null - ? ClipRRect( - borderRadius: borderRadius, - child: image, - ) + ? ClipRRect(borderRadius: borderRadius, child: image) : image; } } diff --git a/packages/flet/lib/src/controls/interactive_viewer.dart b/packages/flet/lib/src/controls/interactive_viewer.dart index bffdd04c3f..84fa56cd16 100644 --- a/packages/flet/lib/src/controls/interactive_viewer.dart +++ b/packages/flet/lib/src/controls/interactive_viewer.dart @@ -1,33 +1,24 @@ -import 'dart:convert'; +import 'dart:math' as math; +import 'package:flutter/foundation.dart' show clampDouble; import 'package:flutter/material.dart'; +import 'package:vector_math/vector_math_64.dart' show Matrix4, Quad, Vector3; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../utils/alignment.dart'; import '../utils/edge_insets.dart'; +import '../utils/events.dart'; +import '../utils/misc.dart'; import '../utils/numbers.dart'; -import '../utils/others.dart'; import '../utils/time.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class InteractiveViewerControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const InteractiveViewerControl( - {super.key, - required this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + InteractiveViewerControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -36,70 +27,91 @@ class InteractiveViewerControl extends StatefulWidget { class _InteractiveViewerControlState extends State with SingleTickerProviderStateMixin { + /// Controller shared with Flutter's InteractiveViewer to orchestrate + /// programmatic and gesture-driven transforms. final TransformationController _transformationController = TransformationController(); + + /// Keyed wrapper around the content so we can read its render box for + /// boundary calculations when clamping zoom/pan invoked from Python. + final GlobalKey _childKey = GlobalKey(); + + /// `InteractiveViewer` sits inside `LayoutControl` wrappers; this key lets us + /// grab the actual viewport size without the extra decoration. + final GlobalKey _viewerKey = GlobalKey(); late AnimationController _animationController; Animation? _animation; Matrix4? _savedMatrix; int _interactionUpdateTimestamp = DateTime.now().millisecondsSinceEpoch; + final double _currentRotation = 0.0; @override void initState() { super.initState(); _animationController = AnimationController(vsync: this, duration: Duration.zero); + widget.control.addInvokeMethodListener(_invokeMethod); + } - widget.backend.subscribeMethods(widget.control.id, - (methodName, args) async { - switch (methodName) { - case "zoom": - var factor = parseDouble(args["factor"]); - if (factor != null) { - _transformationController.value = - _transformationController.value.scaled(factor, factor); - } - break; - case "pan": - var dx = parseDouble(args["dx"]); - var dy = parseDouble(args["dy"]); - if (dx != null && dy != null) { - _transformationController.value = - _transformationController.value.clone()..translate(dx, dy); + /// Handles method channel calls from the Python side, mirroring the + /// user-driven gestures Flutter's [InteractiveViewer] supports. + Future _invokeMethod(String name, dynamic args) async { + debugPrint("InteractiveViewer.$name($args)"); + switch (name) { + case "zoom": + var factor = parseDouble(args["factor"]); + if (factor != null) { + _transformationController.value = + _matrixScale(_transformationController.value, factor); + } + break; + case "pan": + var dx = parseDouble(args["dx"]); + if (dx != null) { + final double dy = parseDouble(args["dy"], 0)!; + final double dz = parseDouble(args["dz"], 0)!; + final Matrix4 updated = + _matrixTranslate(_transformationController.value, Offset(dx, dy)); + if (dz != 0) { + updated.translateByDouble(0.0, 0.0, dz, 1.0); } - break; - case "reset": - var duration = durationFromString(args["duration"]); - if (duration == null) { - _transformationController.value = Matrix4.identity(); - } else { - _animationController.duration = duration; - _animation = Matrix4Tween( - begin: _transformationController.value, - end: Matrix4.identity(), - ).animate(_animationController) - ..addListener(() { - _transformationController.value = _animation!.value; - }); - _animationController.forward(from: 0); - } - break; - case "save_state": - _savedMatrix = _transformationController.value.clone(); - break; - case "restore_state": - if (_savedMatrix != null) { - _transformationController.value = _savedMatrix!; - } - break; - } - return null; - }); + _transformationController.value = updated; + } + break; + case "reset": + var animationDuration = parseDuration(args["animation_duration"]); + if (animationDuration == null) { + _transformationController.value = Matrix4.identity(); + } else { + _animationController.duration = animationDuration; + _animation = Matrix4Tween( + begin: _transformationController.value, + end: Matrix4.identity(), + ).animate(_animationController) + ..addListener(() { + _transformationController.value = _animation!.value; + }); + _animationController.forward(from: 0); + } + break; + case "save_state": + _savedMatrix = _transformationController.value.clone(); + break; + case "restore_state": + if (_savedMatrix != null) { + _transformationController.value = _savedMatrix!; + } + break; + default: + throw Exception("Unknown InteractiveViewer method: $name"); + } } @override void dispose() { _transformationController.dispose(); _animationController.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); super.dispose(); } @@ -107,92 +119,368 @@ class _InteractiveViewerControlState extends State Widget build(BuildContext context) { debugPrint("InteractiveViewer build: ${widget.control.id}"); - var contentCtrls = widget.children.where((c) => c.isVisible); - bool? adaptive = widget.control.isAdaptive ?? widget.parentAdaptive; - bool disabled = widget.control.isDisabled || widget.parentDisabled; + var content = widget.control.buildWidget("content"); + if (content == null) { + return const ErrorControl( + "InteractiveViewer.content must be provided and visible"); + } var interactiveViewer = InteractiveViewer( + key: _viewerKey, transformationController: _transformationController, - panEnabled: widget.control.attrBool("panEnabled", true)!, - scaleEnabled: widget.control.attrBool("scaleEnabled", true)!, + panEnabled: widget.control.getBool("pan_enabled", true)!, + scaleEnabled: widget.control.getBool("scale_enabled", true)!, trackpadScrollCausesScale: - widget.control.attrBool("trackpadScrollCausesScale", false)!, - constrained: widget.control.attrBool("constrained", true)!, - maxScale: widget.control.attrDouble("maxScale", 2.5)!, - minScale: widget.control.attrDouble("minScale", 0.8)!, + widget.control.getBool("trackpad_scroll_causes_scale", false)!, + constrained: widget.control.getBool("constrained", true)!, + maxScale: widget.control.getDouble("max_scale", 2.5)!, + minScale: widget.control.getDouble("min_scale", 0.8)!, interactionEndFrictionCoefficient: widget.control - .attrDouble("interactionEndFrictionCoefficient", 0.0000135)!, - scaleFactor: widget.control.attrDouble("scaleFactor", 200)!, + .getDouble("interaction_end_friction_coefficient", 0.0000135)!, + scaleFactor: widget.control.getDouble("scale_factor", 200)!, clipBehavior: - parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!, - alignment: parseAlignment(widget.control, "alignment"), + parseClip(widget.control.getString("clip_behavior"), Clip.hardEdge)!, + alignment: widget.control.get("alignment"), boundaryMargin: - parseEdgeInsets(widget.control, "boundaryMargin", EdgeInsets.zero)!, - onInteractionStart: !disabled + widget.control.getMargin("boundary_margin", EdgeInsets.zero)!, + onInteractionStart: !widget.control.disabled ? (ScaleStartDetails details) { - debugPrint( - "InteractiveViewer ${widget.control.id} onInteractionStart"); - widget.backend.triggerControlEvent( - widget.control.id, - "interaction_start", - jsonEncode({ - "pc": details.pointerCount, - "fp_x": details.focalPoint.dx, - "fp_y": details.focalPoint.dy, - "lfp_x": details.localFocalPoint.dx, - "lfp_y": details.localFocalPoint.dy - })); + widget.control.triggerEvent("interaction_start", details.toMap()); } : null, - onInteractionEnd: !disabled + onInteractionEnd: !widget.control.disabled ? (ScaleEndDetails details) { - debugPrint( - "InteractiveViewer ${widget.control.id} onInteractionEnd"); - widget.backend.triggerControlEvent( - widget.control.id, - "interaction_end", - jsonEncode({ - "pc": details.pointerCount, - "sv": details.scaleVelocity, - })); + widget.control.triggerEvent("interaction_end", details.toMap()); } : null, - onInteractionUpdate: !disabled + onInteractionUpdate: !widget.control.disabled ? (ScaleUpdateDetails details) { var interactionUpdateInterval = - widget.control.attrInt("interactionUpdateInterval", 200)!; + widget.control.getInt("interaction_update_interval", 200)!; var now = DateTime.now().millisecondsSinceEpoch; if (now - _interactionUpdateTimestamp > interactionUpdateInterval) { - debugPrint( - "InteractiveViewer ${widget.control.id} onInteractionUpdate"); _interactionUpdateTimestamp = now; - widget.backend.triggerControlEvent( - widget.control.id, - "interaction_update", - jsonEncode({ - "pc": details.pointerCount, - "fp_x": details.focalPoint.dx, - "fp_y": details.focalPoint.dy, - "lfp_x": details.localFocalPoint.dx, - "lfp_y": details.localFocalPoint.dy, - "s": details.scale, - "hs": details.horizontalScale, - "vs": details.verticalScale, - "rot": details.rotation, - })); - ; + widget.control + .triggerEvent("interaction_update", details.toMap()); } } : null, - child: contentCtrls.isNotEmpty - ? createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) - : const ErrorControl( - "InteractiveViewer.content must be provided and visible"), + child: KeyedSubtree(key: _childKey, child: content), ); - return constrainedControl( - context, interactiveViewer, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: interactiveViewer); + } + + /// Returns a copy of [matrix] scaled by [scale] while honoring the viewer's + /// min/max scale settings and ensuring the content still covers the viewport. + Matrix4 _matrixScale(Matrix4 matrix, double scale) { + if (scale == 1.0) { + return matrix.clone(); + } + + final double currentScale = matrix.getMaxScaleOnAxis(); + if (currentScale == 0) { + return matrix.clone(); + } + + final double minScale = widget.control.getDouble("min_scale", 0.8)!; + final double maxScale = widget.control.getDouble("max_scale", 2.5)!; + double totalScale = currentScale * scale; + + // Ensure we never shrink the content to a size where the viewport would + // extend beyond the boundaries – Flutter does the same during gestures. + final Rect? boundaryRect = _currentBoundaryRect(); + final Rect? viewportRect = _currentViewportRect(); + if (boundaryRect != null && + viewportRect != null && + boundaryRect.width > 0 && + boundaryRect.height > 0 && + boundaryRect.width.isFinite && + boundaryRect.height.isFinite && + viewportRect.width.isFinite && + viewportRect.height.isFinite) { + final double minFitScale = math.max( + viewportRect.width / boundaryRect.width, + viewportRect.height / boundaryRect.height, + ); + if (minFitScale.isFinite && minFitScale > 0) { + totalScale = math.max(totalScale, minFitScale); + } + } + + final double clampedTotalScale = + clampDouble(totalScale, minScale, maxScale); + final double clampedScale = clampedTotalScale / currentScale; + return matrix.clone() + ..scaleByDouble(clampedScale, clampedScale, clampedScale, 1.0); + } + + /// Returns a matrix translated by [translation] and clamped to the same + /// boundaries Flutter enforces for gesture-driven panning. + Matrix4 _matrixTranslate(Matrix4 matrix, Offset translation) { + if (translation == Offset.zero) { + return matrix.clone(); + } + + // Apply the requested translation optimistically; we’ll clamp below if it + // violates the viewer bounds. + final Matrix4 nextMatrix = matrix.clone() + ..translateByDouble(translation.dx, translation.dy, 0.0, 1.0); + + final Rect? boundaryRect = _currentBoundaryRect(); + final Rect? viewportRect = _currentViewportRect(); + if (boundaryRect == null || viewportRect == null) { + return nextMatrix; + } + + if (boundaryRect.isInfinite) { + return nextMatrix; + } + + final Quad nextViewport = _transformViewport(nextMatrix, viewportRect); + final Quad boundsQuad = + _axisAlignedBoundingBoxWithRotation(boundaryRect, _currentRotation); + final Offset offendingDistance = _exceedsBy(boundsQuad, nextViewport); + if (offendingDistance == Offset.zero) { + return nextMatrix; + } + + // Translation went out of bounds; pull it back so the viewport is fully + // inside the clamped area. + final Offset nextTotalTranslation = _getMatrixTranslation(nextMatrix); + final double currentScale = matrix.getMaxScaleOnAxis(); + if (currentScale == 0) { + return matrix.clone(); + } + final Offset correctedTotalTranslation = Offset( + nextTotalTranslation.dx - offendingDistance.dx * currentScale, + nextTotalTranslation.dy - offendingDistance.dy * currentScale, + ); + + final Matrix4 correctedMatrix = matrix.clone() + ..setTranslation(Vector3( + correctedTotalTranslation.dx, + correctedTotalTranslation.dy, + 0.0, + )); + + final Quad correctedViewport = + _transformViewport(correctedMatrix, viewportRect); + final Offset offendingCorrectedDistance = + _exceedsBy(boundsQuad, correctedViewport); + if (offendingCorrectedDistance == Offset.zero) { + return correctedMatrix; + } + + // If we still exceed in both axes the viewport is larger than the bounds, + // so do not permit the translation at all. + if (offendingCorrectedDistance.dx != 0.0 && + offendingCorrectedDistance.dy != 0.0) { + return matrix.clone(); + } + + // Otherwise allow motion in the one dimension that still fits. + final Offset unidirectionalCorrectedTotalTranslation = Offset( + offendingCorrectedDistance.dx == 0.0 ? correctedTotalTranslation.dx : 0.0, + offendingCorrectedDistance.dy == 0.0 ? correctedTotalTranslation.dy : 0.0, + ); + + return matrix.clone() + ..setTranslation(Vector3( + unidirectionalCorrectedTotalTranslation.dx, + unidirectionalCorrectedTotalTranslation.dy, + 0.0, + )); + } + + /// Computes the boundary rectangle, including margins, for the current child. + Rect? _currentBoundaryRect() { + final BuildContext? childContext = _childKey.currentContext; + if (childContext == null) { + return null; + } + final RenderObject? renderObject = childContext.findRenderObject(); + if (renderObject is! RenderBox) { + return null; + } + final Size childSize = renderObject.size; + final EdgeInsets boundaryMargin = + widget.control.getMargin("boundary_margin", EdgeInsets.zero)!; + return boundaryMargin.inflateRect(Offset.zero & childSize); + } + + /// Returns the visible viewport rectangle of the wrapped `InteractiveViewer`. + Rect? _currentViewportRect() { + final BuildContext? viewerContext = _viewerKey.currentContext; + if (viewerContext == null) { + return null; + } + final RenderObject? renderObject = viewerContext.findRenderObject(); + if (renderObject is! RenderBox) { + return null; + } + final Size size = renderObject.size; + return Offset.zero & size; + } + + /// Extracts the translation component from [matrix] as an [Offset]. + Offset _getMatrixTranslation(Matrix4 matrix) { + final Vector3 translation = matrix.getTranslation(); + return Offset(translation.x, translation.y); + } + + /// Applies the inverse transform of [matrix] to [viewport] to understand how + /// the viewport would move after the child transform is applied. + Quad _transformViewport(Matrix4 matrix, Rect viewport) { + final Matrix4 inverseMatrix = matrix.clone()..invert(); + return Quad.points( + inverseMatrix.transform3( + Vector3(viewport.topLeft.dx, viewport.topLeft.dy, 0.0), + ), + inverseMatrix.transform3( + Vector3(viewport.topRight.dx, viewport.topRight.dy, 0.0), + ), + inverseMatrix.transform3( + Vector3(viewport.bottomRight.dx, viewport.bottomRight.dy, 0.0), + ), + inverseMatrix.transform3( + Vector3(viewport.bottomLeft.dx, viewport.bottomLeft.dy, 0.0), + ), + ); + } + + /// Builds an axis-aligned bounding box for [rect] rotated by [rotation]. + Quad _axisAlignedBoundingBoxWithRotation(Rect rect, double rotation) { + final Matrix4 rotationMatrix = Matrix4.identity() + ..translateByDouble(rect.size.width / 2, rect.size.height / 2, 0.0, 1.0) + ..rotateZ(rotation) + ..translateByDouble( + -rect.size.width / 2, -rect.size.height / 2, 0.0, 1.0); + final Quad boundariesRotated = Quad.points( + rotationMatrix.transform3(Vector3(rect.left, rect.top, 0.0)), + rotationMatrix.transform3(Vector3(rect.right, rect.top, 0.0)), + rotationMatrix.transform3(Vector3(rect.right, rect.bottom, 0.0)), + rotationMatrix.transform3(Vector3(rect.left, rect.bottom, 0.0)), + ); + return _axisAlignedBoundingBox(boundariesRotated); + } + + /// Measures how far [viewport] spills outside [boundary], returning the + /// required correction as an [Offset]. + Offset _exceedsBy(Quad boundary, Quad viewport) { + final List viewportPoints = [ + viewport.point0, + viewport.point1, + viewport.point2, + viewport.point3, + ]; + Offset largestExcess = Offset.zero; + for (final Vector3 point in viewportPoints) { + final Vector3 pointInside = _nearestPointInside(point, boundary); + final Offset excess = + Offset(pointInside.x - point.x, pointInside.y - point.y); + if (excess.dx.abs() > largestExcess.dx.abs()) { + largestExcess = Offset(excess.dx, largestExcess.dy); + } + if (excess.dy.abs() > largestExcess.dy.abs()) { + largestExcess = Offset(largestExcess.dx, excess.dy); + } + } + + return _roundOffset(largestExcess); + } + + /// Rounds [offset] to trim floating point noise that accumulates during + /// transform calculations. + Offset _roundOffset(Offset offset) { + return Offset( + double.parse(offset.dx.toStringAsFixed(9)), + double.parse(offset.dy.toStringAsFixed(9)), + ); + } + + /// Returns the axis-aligned bounding box enclosing [quad]. + Quad _axisAlignedBoundingBox(Quad quad) { + final double minX = math.min( + quad.point0.x, + math.min(quad.point1.x, math.min(quad.point2.x, quad.point3.x)), + ); + final double minY = math.min( + quad.point0.y, + math.min(quad.point1.y, math.min(quad.point2.y, quad.point3.y)), + ); + final double maxX = math.max( + quad.point0.x, + math.max(quad.point1.x, math.max(quad.point2.x, quad.point3.x)), + ); + final double maxY = math.max( + quad.point0.y, + math.max(quad.point1.y, math.max(quad.point2.y, quad.point3.y)), + ); + return Quad.points( + Vector3(minX, minY, 0), + Vector3(maxX, minY, 0), + Vector3(maxX, maxY, 0), + Vector3(minX, maxY, 0), + ); + } + + /// Finds the closest point to [point] that still lies inside [quad]. + Vector3 _nearestPointInside(Vector3 point, Quad quad) { + if (_pointIsInside(point, quad)) { + return point; + } + + // Find the closest point on each edge and keep the minimum distance. + final List closestPoints = [ + _nearestPointOnLine(point, quad.point0, quad.point1), + _nearestPointOnLine(point, quad.point1, quad.point2), + _nearestPointOnLine(point, quad.point2, quad.point3), + _nearestPointOnLine(point, quad.point3, quad.point0), + ]; + double minDistance = double.infinity; + late Vector3 closestOverall; + for (final Vector3 closePoint in closestPoints) { + final double dx = point.x - closePoint.x; + final double dy = point.y - closePoint.y; + final double distance = math.sqrt(dx * dx + dy * dy); + if (distance < minDistance) { + minDistance = distance; + closestOverall = closePoint; + } + } + return closestOverall; + } + + /// Checks whether [point] is contained inside [quad] (inclusive). + bool _pointIsInside(Vector3 point, Quad quad) { + final Vector3 aM = point - quad.point0; + final Vector3 aB = quad.point1 - quad.point0; + final Vector3 aD = quad.point3 - quad.point0; + + final double aMAB = aM.dot(aB); + final double aBAB = aB.dot(aB); + final double aMAD = aM.dot(aD); + final double aDAD = aD.dot(aD); + + return 0 <= aMAB && aMAB <= aBAB && 0 <= aMAD && aMAD <= aDAD; + } + + /// Finds the closest point on the line segment [l1]-[l2] to [point]. + Vector3 _nearestPointOnLine(Vector3 point, Vector3 l1, Vector3 l2) { + final double dx = l2.x - l1.x; + final double dy = l2.y - l1.y; + final double lengthSquared = dx * dx + dy * dy; + + if (lengthSquared == 0) { + return l1; + } + + final Vector3 l1P = point - l1; + final Vector3 l1L2 = l2 - l1; + final double fraction = + clampDouble(l1P.dot(l1L2) / lengthSquared, 0.0, 1.0); + return l1 + l1L2 * fraction; } } diff --git a/packages/flet/lib/src/controls/keyboard_listener.dart b/packages/flet/lib/src/controls/keyboard_listener.dart new file mode 100644 index 0000000000..88f2dd9eeb --- /dev/null +++ b/packages/flet/lib/src/controls/keyboard_listener.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; + +class KeyboardListenerControl extends StatefulWidget { + final Control control; + + KeyboardListenerControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => + _KeyboardListenerControlState(); +} + +class _KeyboardListenerControlState extends State { + final FocusNode _focusNode = FocusNode(); + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("KeyboardListener.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown KeyboardListener method: $name"); + } + } + + @override + Widget build(BuildContext context) { + debugPrint("KeyboardListener build: ${widget.control.id}"); + + var content = widget.control.buildWidget("content"); + + if (content == null) { + return const ErrorControl("KeyboardListener control has no content."); + } + + return KeyboardListener( + focusNode: _focusNode, + autofocus: widget.control.getBool("autofocus", false)!, + includeSemantics: widget.control.getBool("include_semantics", true)!, + onKeyEvent: (keyEvent) { + if (keyEvent is KeyDownEvent) { + widget.control + .triggerEvent("key_down", {"key": keyEvent.logicalKey.keyLabel}); + } else if (keyEvent is KeyUpEvent) { + widget.control + .triggerEvent("key_up", {"key": keyEvent.logicalKey.keyLabel}); + } else if (keyEvent is KeyRepeatEvent) { + widget.control.triggerEvent( + "key_repeat", {"key": keyEvent.logicalKey.keyLabel}); + } + }, + child: content, + ); + } +} diff --git a/packages/flet/lib/src/controls/linechart.dart b/packages/flet/lib/src/controls/linechart.dart deleted file mode 100644 index 421c976ccd..0000000000 --- a/packages/flet/lib/src/controls/linechart.dart +++ /dev/null @@ -1,561 +0,0 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; -import '../models/control.dart'; -import '../utils/animations.dart'; -import '../utils/borders.dart'; -import '../utils/box.dart'; -import '../utils/charts.dart'; -import '../utils/colors.dart'; -import '../utils/edge_insets.dart'; -import '../utils/gradient.dart'; -import '../utils/numbers.dart'; -import '../utils/text.dart'; -import 'charts.dart'; -import 'create_control.dart'; - -class LineChartDataPointViewModel extends Equatable { - final Control control; - final double x; - final double y; - final String? tooltip; - - const LineChartDataPointViewModel( - {required this.control, - required this.x, - required this.y, - required this.tooltip}); - - static LineChartDataPointViewModel fromStore( - Store store, Control control) { - return LineChartDataPointViewModel( - control: control, - x: control.attrDouble("x")!, - y: control.attrDouble("y")!, - tooltip: control.attrString("tooltip")); - } - - @override - List get props => [control]; -} - -class LineChartDataViewModel extends Equatable { - final Control control; - final List dataPoints; - - const LineChartDataViewModel( - {required this.control, required this.dataPoints}); - - static LineChartDataViewModel fromStore( - Store store, Control control) { - return LineChartDataViewModel( - control: control, - dataPoints: store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.isVisible) - .map((c) => LineChartDataPointViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => [control, dataPoints]; -} - -class LineChartEventData extends Equatable { - final String eventType; - final List barSpots; - - const LineChartEventData({required this.eventType, required this.barSpots}); - - Map toJson() => { - 'type': eventType, - 'spots': barSpots, - }; - - @override - List get props => [eventType, barSpots]; -} - -class LineChartEventDataSpot extends Equatable { - final int barIndex; - final int spotIndex; - - const LineChartEventDataSpot( - {required this.barIndex, required this.spotIndex}); - - Map toJson() => { - 'bar_index': barIndex, - 'spot_index': spotIndex, - }; - - @override - List get props => [barIndex, spotIndex]; -} - -class LineChartViewModel extends Equatable { - final Control control; - final ChartAxisViewModel? leftAxis; - final ChartAxisViewModel? topAxis; - final ChartAxisViewModel? rightAxis; - final ChartAxisViewModel? bottomAxis; - final List dataSeries; - - const LineChartViewModel( - {required this.control, - required this.leftAxis, - required this.topAxis, - required this.rightAxis, - required this.bottomAxis, - required this.dataSeries}); - - static LineChartViewModel fromStore( - Store store, Control control, List children) { - var leftAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "l" && c.isVisible); - var topAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "t" && c.isVisible); - var rightAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "r" && c.isVisible); - var bottomAxisCtrls = - children.where((c) => c.type == "axis" && c.name == "b" && c.isVisible); - return LineChartViewModel( - control: control, - leftAxis: leftAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, leftAxisCtrls.first) - : null, - topAxis: topAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, topAxisCtrls.first) - : null, - rightAxis: rightAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, rightAxisCtrls.first) - : null, - bottomAxis: bottomAxisCtrls.isNotEmpty - ? ChartAxisViewModel.fromStore(store, bottomAxisCtrls.first) - : null, - dataSeries: children - .where((c) => c.type == "data" && c.isVisible) - .map((c) => LineChartDataViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => - [control, leftAxis, rightAxis, topAxis, bottomAxis, dataSeries]; -} - -class LineChartControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - - const LineChartControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); - - @override - State createState() => _LineChartControlState(); -} - -class _LineChartControlState extends State { - LineChartEventData? _eventData; - - @override - Widget build(BuildContext context) { - debugPrint("LineChart build: ${widget.control.id}"); - - var animate = parseAnimation(widget.control, "animate"); - var border = parseBorder(Theme.of(context), widget.control, "border"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var result = StoreConnector( - distinct: true, - converter: (store) => LineChartViewModel.fromStore( - store, widget.control, widget.children), - builder: (context, viewModel) { - var leftTitles = - getAxisTitles(widget.control, viewModel.leftAxis, disabled); - var topTitles = - getAxisTitles(widget.control, viewModel.topAxis, disabled); - var rightTitles = - getAxisTitles(widget.control, viewModel.rightAxis, disabled); - var bottomTitles = - getAxisTitles(widget.control, viewModel.bottomAxis, disabled); - - var interactive = viewModel.control.attrBool("interactive", true)!; - var pointLineStart = viewModel.control.attrDouble("pointLineStart"); - var pointLineEnd = viewModel.control.attrDouble("pointLineEnd"); - - List barsData = []; - List selectedPoints = []; - - var barIndex = 0; - for (var ds in viewModel.dataSeries) { - var barData = - getBarData(Theme.of(context), widget.control, interactive, ds); - barsData.add(barData); - - if (!interactive) { - var spotIndex = 0; - for (var p in ds.dataPoints) { - if (p.control.attrBool("selected", false)!) { - selectedPoints.add( - LineBarSpot(barData, barIndex, barData.spots[spotIndex])); - } - spotIndex++; - } - } - - barIndex++; - } - - var chart = LineChart( - LineChartData( - backgroundColor: parseColor( - Theme.of(context), widget.control.attrString("bgcolor")), - minX: widget.control.attrDouble("minx"), - maxX: widget.control.attrDouble("maxx"), - minY: widget.control.attrDouble("miny"), - maxY: widget.control.attrDouble("maxy"), - baselineX: widget.control.attrDouble("baselinex"), - baselineY: widget.control.attrDouble("baseliney"), - showingTooltipIndicators: groupBy(selectedPoints, (p) => p.x) - .values - .map((e) => ShowingTooltipIndicators(e)) - .toList(), - titlesData: (leftTitles.sideTitles.showTitles || - topTitles.sideTitles.showTitles || - rightTitles.sideTitles.showTitles || - bottomTitles.sideTitles.showTitles) - ? FlTitlesData( - show: true, - leftTitles: leftTitles, - topTitles: topTitles, - rightTitles: rightTitles, - bottomTitles: bottomTitles, - ) - : const FlTitlesData(show: false), - borderData: border != null - ? FlBorderData(show: true, border: border) - : FlBorderData(show: false), - gridData: parseChartGridData(Theme.of(context), widget.control, - "horizontalGridLines", "verticalGridLines"), - lineBarsData: barsData, - lineTouchData: LineTouchData( - enabled: interactive, - getTouchLineStart: pointLineStart != null - ? (barData, spotIndex) => pointLineStart - : defaultGetTouchLineStart, - getTouchLineEnd: pointLineEnd != null - ? (barData, spotIndex) => pointLineEnd - : defaultGetTouchLineEnd, - getTouchedSpotIndicator: - (LineChartBarData barData, List spotIndexes) { - var barIndex = interactive - ? barsData.indexWhere( - (b) => b == barData.copyWith(showingIndicators: [])) - : barsData.indexWhere((b) => b == barData); - - return spotIndexes.map((index) { - if (barIndex == -1) { - return null; - } - - FlLine? allDotsLine = parseSelectedFlLine( - Theme.of(context), - viewModel.dataSeries[barIndex].control, - "selectedBelowLine", - barData.color, - barData.gradient); - - FlLine? dotLine = parseSelectedFlLine( - Theme.of(context), - viewModel - .dataSeries[barIndex].dataPoints[index].control, - "selectedBelowLine", - barData.color, - barData.gradient); - - return TouchedSpotIndicatorData( - dotLine ?? - allDotsLine ?? - FlLine( - color: defaultGetPointColor( - barData.color, barData.gradient, 0), - strokeWidth: 3), - FlDotData( - show: true, - getDotPainter: (spot, percent, barData, index) { - var allDotsPainter = parseChartSelectedDotPainter( - Theme.of(context), - viewModel.dataSeries[barIndex].control, - "selectedPoint", - barData.color, - barData.gradient, - percent); - var dotPainter = parseChartSelectedDotPainter( - Theme.of(context), - viewModel.dataSeries[barIndex].dataPoints[index] - .control, - "selectedPoint", - barData.color, - barData.gradient, - percent); - return dotPainter ?? - allDotsPainter ?? - getDefaultSelectedPainter( - barData.color, barData.gradient, percent); - }, - ), - ); - }).toList(); - }, - touchTooltipData: LineTouchTooltipData( - getTooltipColor: (LineBarSpot spot) => widget.control - .attrColor("tooltipBgColor", context, - const Color.fromRGBO(96, 125, 139, 1))!, - tooltipRoundedRadius: - widget.control.attrDouble("tooltipRoundedRadius", 4)!, - tooltipMargin: - widget.control.attrDouble("tooltipMargin", 16)!, - tooltipPadding: parseEdgeInsets( - widget.control, - "tooltipPadding", - const EdgeInsets.symmetric( - horizontal: 16, vertical: 8))!, - maxContentWidth: widget.control - .attrDouble("tooltipMaxContentWidth", 120)!, - rotateAngle: - widget.control.attrDouble("tooltipRotateAngle", 0.0)!, - tooltipHorizontalOffset: widget.control - .attrDouble("tooltipHorizontalOffset", 0)!, - tooltipBorder: parseBorderSide(Theme.of(context), - widget.control, "tooltipBorderSide") ?? - BorderSide.none, - fitInsideHorizontally: widget.control - .attrBool("tooltipFitInsideHorizontally", false)!, - fitInsideVertically: widget.control - .attrBool("tooltipFitInsideVertically", false)!, - showOnTopOfTheChartBoxArea: widget.control - .attrBool("tooltipShowOnTopOfChartBoxArea", false)!, - getTooltipItems: (touchedSpots) { - return touchedSpots.map((spot) { - var dp = viewModel.dataSeries[spot.barIndex] - .dataPoints[spot.spotIndex]; - var tooltip = dp.tooltip ?? dp.y.toString(); - var tooltipStyle = parseTextStyle( - Theme.of(context), dp.control, "tooltipStyle"); - tooltipStyle ??= const TextStyle(); - if (tooltipStyle.color == null) { - tooltipStyle = tooltipStyle.copyWith( - color: spot.bar.gradient?.colors.first ?? - spot.bar.color ?? - Colors.blueGrey); - } - TextAlign? tooltipAlign = parseTextAlign( - dp.control.attrString("tooltipAlign"), - TextAlign.center)!; - return dp.control.attrBool("showTooltip", true)! - ? LineTooltipItem(tooltip, tooltipStyle, - textAlign: tooltipAlign) - : null; - }).toList(); - }, - ), - touchCallback: widget.control.attrBool("onChartEvent", false)! - ? (evt, resp) { - var eventData = LineChartEventData( - eventType: evt.runtimeType - .toString() - .substring(2), // remove "Fl" - barSpots: - resp != null && resp.lineBarSpots != null - ? resp.lineBarSpots! - .map((bs) => LineChartEventDataSpot( - barIndex: bs.barIndex, - spotIndex: bs.spotIndex)) - .toList() - : []); - if (eventData != _eventData) { - _eventData = eventData; - debugPrint( - "LineChart ${widget.control.id} ${eventData.eventType}"); - widget.backend.triggerControlEvent( - widget.control.id, - "chart_event", - json.encode(eventData)); - } - } - : null, - )), - duration: animate != null - ? animate.duration - : const Duration(milliseconds: 150), // Optional - curve: animate != null ? animate.curve : Curves.linear, - ); - - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return (constraints.maxHeight == double.infinity) - ? ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 300), - child: chart, - ) - : chart; - }); - }); - - return constrainedControl(context, result, widget.parent, widget.control); - } - - LineChartBarData getBarData(ThemeData theme, Control parent, - bool interactiveChart, LineChartDataViewModel dataViewModel) { - Color? aboveLineBgcolor = - dataViewModel.control.attrColor("aboveLineBgcolor", context); - Gradient? aboveLineGradient = - parseGradient(theme, dataViewModel.control, "aboveLineGradient"); - Color? belowLineBgcolor = - dataViewModel.control.attrColor("belowLineBgcolor", context); - Gradient? belowLineGradient = - parseGradient(theme, dataViewModel.control, "belowLineGradient"); - var dashPattern = dataViewModel.control.attrString("dashPattern"); - var shadow = - parseBoxShadow(Theme.of(context), dataViewModel.control, "shadow", [])!; - Color barColor = - dataViewModel.control.attrColor("color", context) ?? Colors.cyan; - Gradient? barGradient = - parseGradient(theme, dataViewModel.control, "gradient"); - FlLine? aboveLine = - parseFlLine(Theme.of(context), dataViewModel.control, "aboveLine"); - FlLine? belowLine = - parseFlLine(Theme.of(context), dataViewModel.control, "belowLine"); - double? aboveLineCutoffY = - dataViewModel.control.attrDouble("aboveLineCutoffY"); - double? belowLineCutoffY = - dataViewModel.control.attrDouble("belowLineCutoffY"); - - Map spots = { - for (var e in dataViewModel.dataPoints) FlSpot(e.x, e.y): e - }; - return LineChartBarData( - preventCurveOverShooting: - dataViewModel.control.attrBool("preventCurveOverShooting", false)!, - preventCurveOvershootingThreshold: dataViewModel.control - .attrDouble("preventCurveOverShootingThreshold", 10.0)!, - spots: dataViewModel.dataPoints.map((p) => FlSpot(p.x, p.y)).toList(), - showingIndicators: dataViewModel.dataPoints - .asMap() - .entries - .where((e) => - !interactiveChart && - e.value.control.attrBool("selected", false)!) - .map((e) => e.key) - .toList(), - isCurved: dataViewModel.control.attrBool("curved", false)!, - isStrokeCapRound: - dataViewModel.control.attrBool("strokeCapRound", false)!, - barWidth: dataViewModel.control.attrDouble("strokeWidth") ?? 2.0, - dashArray: dashPattern != null - ? (json.decode(dashPattern) as List) - .map((e) => parseInt(e)) - .nonNulls - .toList() - : null, - shadow: shadow.isNotEmpty - ? shadow[0] - : const Shadow(color: Colors.transparent), - dotData: FlDotData( - show: true, - getDotPainter: (spot, percent, barData, index) { - var allDotsPainter = parseChartDotPainter( - theme, - dataViewModel.control, - "point", - barColor, - barGradient, - percent); - var dotPainter = parseChartDotPainter( - theme, - dataViewModel.dataPoints[index].control, - "point", - barColor, - barGradient, - percent); - return dotPainter ?? allDotsPainter ?? getInvisiblePainter(); - }), - aboveBarData: aboveLineBgcolor != null || - aboveLineGradient != null || - aboveLine != null - ? BarAreaData( - show: true, - color: aboveLineBgcolor, - gradient: aboveLineGradient, - applyCutOffY: aboveLineCutoffY != null, - cutOffY: aboveLineCutoffY ?? 0, - spotsLine: BarAreaSpotsLine( - show: aboveLine != null, - flLineStyle: aboveLine ?? const FlLine(), - checkToShowSpotLine: (spot) => - spots[spot]!.control.attrBool("showAboveLine", true)!, - )) - : null, - belowBarData: belowLineBgcolor != null || - belowLineGradient != null || - belowLine != null - ? BarAreaData( - show: true, - color: belowLineBgcolor, - gradient: belowLineGradient, - applyCutOffY: belowLineCutoffY != null, - cutOffY: belowLineCutoffY ?? 0, - spotsLine: BarAreaSpotsLine( - show: belowLine != null, - flLineStyle: belowLine ?? const FlLine(), - checkToShowSpotLine: (spot) => - spots[spot]!.control.attrBool("showBelowLine", true)!, - )) - : null, - color: barColor, - gradient: barGradient); - } - - AxisTitles getAxisTitles( - Control parent, ChartAxisViewModel? axisViewModel, bool disabled) { - if (axisViewModel == null) { - return const AxisTitles(sideTitles: SideTitles(showTitles: false)); - } - - return AxisTitles( - axisNameWidget: axisViewModel.title != null - ? createControl(parent, axisViewModel.title!.id, disabled) - : null, - axisNameSize: axisViewModel.control.attrDouble("titleSize") ?? 16, - sideTitles: SideTitles( - showTitles: axisViewModel.control.attrBool("showLabels", true)!, - reservedSize: axisViewModel.control.attrDouble("labelsSize") ?? 22, - interval: axisViewModel.control.attrDouble("labelsInterval"), - getTitlesWidget: axisViewModel.labels.isEmpty - ? defaultGetTitle - : (value, meta) { - return axisViewModel.labels.containsKey(value) - ? createControl( - parent, axisViewModel.labels[value]!.id, disabled) - : const SizedBox.shrink(); - }, - )); - } -} diff --git a/packages/flet/lib/src/controls/list_tile.dart b/packages/flet/lib/src/controls/list_tile.dart index 1153fff0a7..629c7be3cc 100644 --- a/packages/flet/lib/src/controls/list_tile.dart +++ b/packages/flet/lib/src/controls/list_tile.dart @@ -1,17 +1,18 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/launch_url.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; import '../utils/theme.dart'; -import 'create_control.dart'; -import 'cupertino_list_tile.dart'; -import 'flet_store_mixin.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; class ListTileClicks extends InheritedWidget { const ListTileClicks({ @@ -31,141 +32,94 @@ class ListTileClicks extends InheritedWidget { } class ListTileControl extends StatelessWidget with FletStoreMixin { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; + final ListTileClickNotifier _clickNotifier = ListTileClickNotifier(); - ListTileControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + ListTileControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("ListTile build: ${control.id}"); - return withPagePlatform((context, platform) { - bool? adaptive = control.isAdaptive ?? parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoListTileControl( - control: control, - parent: parent, - parentDisabled: parentDisabled, - parentAdaptive: adaptive, - children: children, - backend: backend); - } - - var leadingCtrls = - children.where((c) => c.name == "leading" && c.isVisible); - var titleCtrls = children.where((c) => c.name == "title" && c.isVisible); - var subtitleCtrls = - children.where((c) => c.name == "subtitle" && c.isVisible); - var trailingCtrls = - children.where((c) => c.name == "trailing" && c.isVisible); - - bool onclick = control.attrBool("onclick", false)!; - bool toggleInputs = control.attrBool("toggleInputs", false)!; - bool onLongPressDefined = control.attrBool("onLongPress", false)!; - String url = control.attrString("url", "")!; - String? urlTarget = control.attrString("urlTarget"); - bool disabled = control.isDisabled || parentDisabled; - - Function()? onPressed = - (onclick || toggleInputs || url != "") && !disabled - ? () { - debugPrint("ListTile ${control.id} clicked!"); - if (toggleInputs) { - _clickNotifier.onClick(); - } - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - if (onclick) { - backend.triggerControlEvent(control.id, "click"); - } + var leading = control.buildIconOrWidget("leading"); + var title = control.buildTextOrWidget("title"); + var subtitle = control.buildTextOrWidget("subtitle"); + var trailing = control.buildIconOrWidget("trailing"); + var onClick = control.getBool("on_click", false)!; + var toggleInputs = control.getBool("toggle_inputs", false)!; + var url = control.getUrl("url"); + + Function()? onPressed = + (onClick || toggleInputs || url != null) && !control.disabled + ? () { + if (toggleInputs) { + _clickNotifier.onClick(); + } + if (url != null) { + openWebBrowser(url); + } + if (onClick) { + control.triggerEvent("click"); } - : null; - - Function()? onLongPress = onLongPressDefined && !disabled - ? () { - debugPrint("Button ${control.id} clicked!"); - backend.triggerControlEvent(control.id, "long_press"); - } - : null; - - Widget tile = ListTile( - autofocus: control.attrBool("autofocus", false)!, - contentPadding: parseEdgeInsets(control, "contentPadding"), - isThreeLine: control.attrBool("isThreeLine", false)!, - selected: control.attrBool("selected", false)!, - dense: control.attrBool("dense", false)!, - onTap: onPressed, - onLongPress: onLongPress, - enabled: !disabled, - horizontalTitleGap: control.attrDouble("horizontalSpacing"), - enableFeedback: control.attrBool("enableFeedback"), - minLeadingWidth: control.attrDouble("minLeadingWidth"), - minVerticalPadding: control.attrDouble("minVerticalPadding"), - minTileHeight: control.attrDouble("minHeight"), - selectedTileColor: control.attrColor("selectedTileColor", context), - selectedColor: control.attrColor("selectedColor", context), - focusColor: control.attrColor("focusColor", context), - tileColor: control.attrColor("bgcolor", context), - splashColor: control.attrColor("bgcolorActivated", context), - hoverColor: control.attrColor("hoverColor", context), - iconColor: control.attrColor("iconColor", context), - textColor: control.attrColor("textColor", context), - mouseCursor: parseMouseCursor(control.attrString("mouseCursor")), - visualDensity: parseVisualDensity(control.attrString("visualDensity")), - shape: parseOutlinedBorder(control, "shape"), - titleTextStyle: - parseTextStyle(Theme.of(context), control, "titleTextStyle"), - leadingAndTrailingTextStyle: parseTextStyle( - Theme.of(context), control, "leadingAndTrailingTextStyle"), - subtitleTextStyle: - parseTextStyle(Theme.of(context), control, "subtitleTextStyle"), - titleAlignment: - parseListTileTitleAlignment(control.attrString("titleAlignment")), - style: parseListTileStyle(control.attrString("style")), - onFocusChange: (bool hasFocus) { - backend.triggerControlEvent(control.id, hasFocus ? "focus" : "blur"); - }, - leading: leadingCtrls.isNotEmpty - ? createControl(control, leadingCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - title: titleCtrls.isNotEmpty - ? createControl(control, titleCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - subtitle: subtitleCtrls.isNotEmpty - ? createControl(control, subtitleCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - trailing: trailingCtrls.isNotEmpty - ? createControl(control, trailingCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - ); - - if (toggleInputs) { - tile = ListTileClicks(notifier: _clickNotifier, child: tile); - } - - tile = Material(color: Colors.transparent, child: tile); - - return constrainedControl(context, tile, parent, control); - }); + } + : null; + + Function()? onLongPress = + control.getBool("on_long_press", false)! && !control.disabled + ? () { + control.triggerEvent("long_press"); + } + : null; + + Widget tile = ListTile( + autofocus: control.getBool("autofocus", false)!, + contentPadding: control.getPadding("content_padding"), + isThreeLine: control.getBool("is_three_line"), + selected: control.getBool("selected", false)!, + dense: control.getBool("dense"), + onTap: onPressed, + onLongPress: onLongPress, + enabled: !control.disabled, + horizontalTitleGap: control.getDouble("horizontal_spacing"), + enableFeedback: control.getBool("enable_feedback"), + minLeadingWidth: control.getDouble("min_leading_width"), + minVerticalPadding: control.getDouble("min_vertical_padding"), + minTileHeight: control.getDouble("min_height"), + selectedTileColor: control.getColor("selected_tile_color", context), + selectedColor: control.getColor("selected_color", context), + focusColor: control.getColor("focus_color", context), + tileColor: control.getColor("bgcolor", context), + splashColor: control.getColor("splash_color", context), + hoverColor: control.getColor("hover_color", context), + iconColor: control.getColor("icon_color", context), + textColor: control.getColor("text_color", context), + mouseCursor: control.getMouseCursor("mouse_cursor"), + visualDensity: control.getVisualDensity("visual_density"), + shape: control.getShape("shape", Theme.of(context)), + titleTextStyle: + control.getTextStyle("title_text_style", Theme.of(context)), + leadingAndTrailingTextStyle: control.getTextStyle( + "leading_and_trailing_text_style", Theme.of(context)), + subtitleTextStyle: + control.getTextStyle("subtitle_text_style", Theme.of(context)), + titleAlignment: control.getListTileTitleAlignment("title_alignment"), + style: control.getListTileStyle("style"), + onFocusChange: (bool hasFocus) { + control.triggerEvent(hasFocus ? "focus" : "blur"); + }, + leading: leading, + title: title, + subtitle: subtitle, + trailing: trailing, + ); + + if (toggleInputs) { + tile = ListTileClicks(notifier: _clickNotifier, child: tile); + } + + tile = Material(type: MaterialType.transparency, child: tile); + + return LayoutControl(control: control, child: tile); } } diff --git a/packages/flet/lib/src/controls/list_view.dart b/packages/flet/lib/src/controls/list_view.dart index 484264f142..823515b394 100644 --- a/packages/flet/lib/src/controls/list_view.dart +++ b/packages/flet/lib/src/controls/list_view.dart @@ -1,29 +1,23 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/keys.dart'; +import '../utils/layout.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; import 'scroll_notification_control.dart'; import 'scrollable_control.dart'; class ListViewControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final List children; - final bool? parentAdaptive; - final FletControlBackend backend; - const ListViewControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + ListViewControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _ListViewControlState(); @@ -47,32 +41,26 @@ class _ListViewControlState extends State { @override Widget build(BuildContext context) { debugPrint("ListViewControl build: ${widget.control.id}"); - - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - - var horizontal = widget.control.attrBool("horizontal", false)!; - var spacing = widget.control.attrDouble("spacing", 0)!; - var dividerThickness = widget.control.attrDouble("dividerThickness", 0)!; - var itemExtent = widget.control.attrDouble("itemExtent"); - var cacheExtent = widget.control.attrDouble("cacheExtent"); - var semanticChildCount = widget.control.attrInt("semanticChildCount"); - var firstItemPrototype = - widget.control.attrBool("firstItemPrototype", false)!; - var padding = parseEdgeInsets(widget.control, "padding"); - var reverse = widget.control.attrBool("reverse", false)!; + var horizontal = widget.control.getBool("horizontal", false)!; + var spacing = widget.control.getDouble("spacing", 0)!; + var dividerThickness = widget.control.getDouble("divider_thickness", 0)!; + var itemExtent = widget.control.getDouble("item_extent"); + var cacheExtent = widget.control.getDouble("cache_extent"); + var semanticChildCount = widget.control.getInt("semantic_child_count"); + var padding = widget.control.getPadding("padding"); + var reverse = widget.control.getBool("reverse", false)!; var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!; - - List ctrls = widget.children.where((c) => c.isVisible).toList(); + parseClip(widget.control.getString("clip_behavior"), Clip.hardEdge)!; var scrollDirection = horizontal ? Axis.horizontal : Axis.vertical; var buildControlsOnDemand = - widget.control.attrBool("buildControlsOnDemand", true)!; - var prototypeItem = firstItemPrototype && widget.children.isNotEmpty - ? createControl(widget.control, ctrls[0].id, disabled, - parentAdaptive: adaptive) - : null; + widget.control.getBool("build_controls_on_demand", true)!; + var firstItemPrototype = + widget.control.getBool("first_item_prototype", false)!; + var controls = widget.control.children("controls"); + var prototypeItem = widget.control.buildWidget("prototype_item") ?? + (firstItemPrototype && controls.isNotEmpty + ? ControlWidget(control: controls.first) + : null); Widget listView = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -92,12 +80,31 @@ class _ListViewControlState extends State { shrinkWrap: shrinkWrap, padding: padding, semanticChildCount: semanticChildCount, - itemExtent: itemExtent, - prototypeItem: prototypeItem, - children: ctrls - .map((c) => createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive)) - .toList(), + itemExtent: spacing > 0 ? null : itemExtent, + prototypeItem: spacing > 0 ? null : prototypeItem, + children: () { + final childWidgets = []; + for (var index = 0; index < controls.length; index++) { + final item = controls[index]; + childWidgets.add(ControlWidget( + key: ValueKey(item.getKey("key")?.value ?? item.id), + control: item, + )); + if (spacing > 0 && index < controls.length - 1) { + childWidgets.add(horizontal + ? dividerThickness == 0 + ? SizedBox(width: spacing) + : VerticalDivider( + width: spacing, thickness: dividerThickness) + : dividerThickness == 0 + ? SizedBox(height: spacing) + : Divider( + height: spacing, + thickness: dividerThickness)); + } + } + return childWidgets; + }(), ) : spacing > 0 ? ListView.separated( @@ -108,11 +115,13 @@ class _ListViewControlState extends State { scrollDirection: scrollDirection, shrinkWrap: shrinkWrap, padding: padding, - itemCount: widget.children.length, + itemCount: controls.length, itemBuilder: (context, index) { - return createControl( - widget.control, ctrls[index].id, disabled, - parentAdaptive: adaptive); + return ControlWidget( + key: ValueKey(controls[index].getKey("key")?.value ?? + controls[index].id), + control: controls[index], + ); }, separatorBuilder: (context, index) { return horizontal @@ -135,33 +144,44 @@ class _ListViewControlState extends State { scrollDirection: scrollDirection, shrinkWrap: shrinkWrap, padding: padding, - itemCount: widget.children.length, + itemCount: controls.length, itemExtent: itemExtent, itemBuilder: (context, index) { - return createControl( - widget.control, ctrls[index].id, disabled, - parentAdaptive: adaptive); + return ControlWidget( + key: ValueKey(controls[index].getKey("key")?.value ?? + controls[index].id), + control: controls[index], + ); }, prototypeItem: prototypeItem, ); + if (horizontal && + constraints.maxHeight == double.infinity && + widget.control.getDouble("height") == null && + widget.control.getExpand("expand", 0)! <= 0) { + return const ErrorControl( + "Error displaying ListViewControl: height is unbounded.", + description: + "Set a fixed height, a non-zero expand, or place inside " + "a control with bounded height."); + } + child = ScrollableControl( control: widget.control, scrollDirection: horizontal ? Axis.horizontal : Axis.vertical, scrollController: _controller, - backend: widget.backend, - parentAdaptive: adaptive, child: child); - if (widget.control.attrBool("onScroll", false)!) { - child = ScrollNotificationControl( - control: widget.control, backend: widget.backend, child: child); + if (widget.control.getBool("on_scroll", false)!) { + child = + ScrollNotificationControl(control: widget.control, child: child); } return child; }, ); - return constrainedControl(context, listView, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: listView); } } diff --git a/packages/flet/lib/src/controls/markdown.dart b/packages/flet/lib/src/controls/markdown.dart index fd5007f764..793d7fc54a 100644 --- a/packages/flet/lib/src/controls/markdown.dart +++ b/packages/flet/lib/src/controls/markdown.dart @@ -1,146 +1,112 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:flutter_markdown_plus/flutter_markdown_plus.dart'; +import 'package:flutter_markdown_plus_latex/flutter_markdown_plus_latex.dart'; import 'package:markdown/markdown.dart' as md; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../utils/box.dart'; import '../utils/images.dart'; import '../utils/launch_url.dart'; import '../utils/markdown.dart'; +import '../utils/numbers.dart'; +import '../utils/text.dart'; import '../utils/uri.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; import 'highlight_view.dart'; -class MarkdownControl extends StatelessWidget with FletStoreMixin { - final Control? parent; - final List children; +class MarkdownControl extends StatelessWidget { final Control control; - final bool parentDisabled; - final FletControlBackend backend; - - static const String svgTag = " xmlns=\"http://www.w3.org/2000/svg\""; - const MarkdownControl( - {super.key, - required this.parent, - required this.children, - required this.control, - required this.parentDisabled, - required this.backend}); + const MarkdownControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Markdown build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - - var value = control.attrString("value", "")!; - md.ExtensionSet extensionSet = parseMarkdownExtensionSet( - control.attrString("extensionSet"), md.ExtensionSet.none)!; - - var autoFollowLinks = control.attrBool("autoFollowLinks", false)!; - var autoFollowLinksTarget = control.attrString("autoFollowLinksTarget"); - - return withPageArgs((context, pageArgs) { - bool selectable = control.attrBool("selectable", false)!; - var codeStyleSheet = parseMarkdownStyleSheet( - control, "codeStyleSheet", Theme.of(context), pageArgs) ?? - MarkdownStyleSheet.fromTheme(Theme.of(context)).copyWith( - code: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(fontFamily: "monospace")); - var mdStyleSheet = parseMarkdownStyleSheet( - control, "mdStyleSheet", Theme.of(context), pageArgs); - var codeTheme = - parseMarkdownCodeTheme(control, "codeTheme", Theme.of(context)); - Widget markdown = MarkdownBody( - data: value, - selectable: selectable, - imageDirectory: pageArgs.assetsDir != "" - ? pageArgs.assetsDir - : getBaseUri(pageArgs.pageUri!).toString(), - extensionSet: extensionSet, - builders: { - 'code': CodeElementBuilder(codeTheme, codeStyleSheet, selectable), - }, - styleSheet: mdStyleSheet, - imageBuilder: (Uri uri, String? title, String? alt) { - String s = uri.toString(); - var srcBase64 = isBase64ImageString(s) ? s : null; - var src = isUrlOrPath(s) ? s : null; - if (src == null && srcBase64 == null) { - return ErrorControl("Invalid image URI: $s"); - } - var errorContentCtrls = - children.where((c) => c.name == "error" && c.isVisible); - - var errorContent = errorContentCtrls.isNotEmpty - ? createControl(control, errorContentCtrls.first.id, disabled) - : null; - - return buildImage( + + final theme = Theme.of(context); + var value = control.getString("value", "")!; + var extensionSet = + control.getMarkdownExtensionSet("extension_set", md.ExtensionSet.none)!; + + var autoFollowLinks = control.getBool("auto_follow_links", false)!; + var autoFollowLinksTarget = control.getString("auto_follow_links_target"); + var selectable = control.getBool("selectable", false)!; + + var codeStyleSheet = control.getMarkdownStyleSheet( + "code_style_sheet", context) ?? + MarkdownStyleSheet.fromTheme(theme).copyWith( + code: + theme.textTheme.bodyMedium!.copyWith(fontFamily: "monospace")); + var mdStyleSheet = control.getMarkdownStyleSheet("md_style_sheet", context); + var codeTheme = control.getMarkdownCodeTheme("code_theme", theme); + var latexStyle = control.getTextStyle("latex_style", theme); + var latexScaleFactor = control.getDouble("latex_scale_factor"); + + Widget markdown = MarkdownBody( + data: value, + imageDirectory: control.backend.assetsDir != "" + ? control.backend.assetsDir + : getBaseUri(control.backend.pageUri).toString(), + extensionSet: md.ExtensionSet( + [...extensionSet.blockSyntaxes, LatexBlockSyntax()], + [...extensionSet.inlineSyntaxes, LatexInlineSyntax()], + ), + builders: { + 'code': CodeElementBuilder(codeTheme, codeStyleSheet), + 'latex': LatexElementBuilder( + textStyle: latexStyle, textScaleFactor: latexScaleFactor), + }, + styleSheet: mdStyleSheet, + imageBuilder: (Uri uri, String? title, String? alt) { + return buildImage( context: context, - control: control, - src: src, - srcBase64: srcBase64, + src: uri.toString(), semanticsLabel: alt, - disabled: disabled, - pageArgs: pageArgs, - errorCtrl: errorContent, - ); - }, - shrinkWrap: control.attrBool("shrinkWrap", true)!, - fitContent: control.attrBool("fitContent", true)!, - softLineBreak: control.attrBool("softLineBreak", false)!, - onSelectionChanged: (String? text, TextSelection selection, - SelectionChangedCause? cause) { - debugPrint("Markdown ${control.id} selection changed"); - backend.triggerControlEvent( - control.id, - "selection_change", - jsonEncode({ - "text": text ?? "", - "start": selection.start, - "end": selection.end, - "base_offset": selection.baseOffset, - "extent_offset": selection.extentOffset, - "affinity": selection.affinity.name, - "directional": selection.isDirectional, - "collapsed": selection.isCollapsed, - "valid": selection.isValid, - "normalized": selection.isNormalized, - "cause": cause?.name ?? "unknown", - })); - }, - onTapText: () { - debugPrint("Markdown ${control.id} text tapped"); - backend.triggerControlEvent(control.id, "tap_text"); - }, - onTapLink: (String text, String? href, String title) { - debugPrint("Markdown ${control.id} link tapped clicked"); - if (autoFollowLinks && href != null) { - openWebBrowser(href, webWindowName: autoFollowLinksTarget); - } - backend.triggerControlEvent( - control.id, "tap_link", href?.toString()); + disabled: control.disabled, + errorCtrl: control.buildWidget("image_error_content")); + }, + shrinkWrap: control.getBool("shrink_wrap", true)!, + fitContent: control.getBool("fit_content", true)!, + softLineBreak: control.getBool("soft_line_break", false)!, + onSelectionChanged: (String? text, TextSelection selection, + SelectionChangedCause? cause) { + control.triggerEvent("selection_change", { + "text": text ?? "", + "cause": cause?.name ?? "unknown", + "selection": { + "start": selection.start, + "end": selection.end, + "selection": text ?? "", + "base_offset": selection.baseOffset, + "extent_offset": selection.extentOffset, + "affinity": selection.affinity.name, + "directional": selection.isDirectional, + "collapsed": selection.isCollapsed, + "valid": selection.isValid, + "normalized": selection.isNormalized, + }, }); - - return constrainedControl(context, markdown, parent, control); - }); + }, + onTapText: () => control.triggerEvent("tap_text"), + onTapLink: (String text, String? href, String title) { + if (autoFollowLinks && href != null) { + openWebBrowser(Url(href, autoFollowLinksTarget)); + } + control.triggerEvent("tap_link", href); + }); + + return LayoutControl( + control: control, + child: selectable ? SelectionArea(child: markdown) : markdown, + ); } } class CodeElementBuilder extends MarkdownElementBuilder { final Map codeTheme; final MarkdownStyleSheet mdStyleSheet; - final bool selectable; - CodeElementBuilder(this.codeTheme, this.mdStyleSheet, this.selectable); + CodeElementBuilder(this.codeTheme, this.mdStyleSheet); @override Widget? visitElementAfter(md.Element element, TextStyle? preferredStyle) { @@ -163,8 +129,7 @@ class CodeElementBuilder extends MarkdownElementBuilder { // The original code to be highlighted element.textContent.substring(0, element.textContent.length - 1), - // Specify language - // It is recommended to give it a value for performance + // It is recommended to give a language for performance language: language, // Specify highlight theme @@ -173,8 +138,6 @@ class CodeElementBuilder extends MarkdownElementBuilder { padding: mdStyleSheet.codeblockPadding, decoration: mdStyleSheet.codeblockDecoration, textStyle: mdStyleSheet.code, - - selectable: selectable, ), ); }); diff --git a/packages/flet/lib/src/controls/menu_bar.dart b/packages/flet/lib/src/controls/menu_bar.dart index 3b15b3f6bc..de3319256f 100644 --- a/packages/flet/lib/src/controls/menu_bar.dart +++ b/packages/flet/lib/src/controls/menu_bar.dart @@ -1,25 +1,17 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/menu.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/misc.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class MenuBarControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const MenuBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + MenuBarControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _MenuBarControlState(); @@ -30,26 +22,17 @@ class _MenuBarControlState extends State { Widget build(BuildContext context) { debugPrint("MenuBar build: ${widget.control.id}"); - var ctrls = widget.children.where((c) => c.isVisible).toList(); - if (ctrls.isEmpty) { + var controls = widget.control.buildWidgets("controls"); + if (controls.isEmpty) { return const ErrorControl( "MenuBar must have at minimum one visible child control"); } + final menuBar = MenuBar( + style: widget.control.getMenuStyle("style", Theme.of(context)), + clipBehavior: + widget.control.getClipBehavior("clip_behavior", Clip.none)!, + children: controls); - return constrainedControl( - context, - MenuBar( - style: parseMenuStyle(Theme.of(context), widget.control, "style"), - clipBehavior: - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!, - children: ctrls - .map((c) => createControl(widget.control, c.id, - widget.control.isDisabled || widget.parentDisabled, - parentAdaptive: - widget.control.isAdaptive ?? widget.parentAdaptive)) - .toList(), - ), - widget.parent, - widget.control); + return LayoutControl(control: widget.control, child: menuBar); } } diff --git a/packages/flet/lib/src/controls/menu_item_button.dart b/packages/flet/lib/src/controls/menu_item_button.dart index 79c7159229..15892640ac 100644 --- a/packages/flet/lib/src/controls/menu_item_button.dart +++ b/packages/flet/lib/src/controls/menu_item_button.dart @@ -1,27 +1,17 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/buttons.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class MenuItemButtonControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const MenuItemButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + MenuItemButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _MenuItemButtonControlState(); @@ -46,24 +36,15 @@ class _MenuItemButtonControlState extends State { } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @override Widget build(BuildContext context) { debugPrint("MenuItemButton build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var content = - widget.children.where((c) => c.name == "content" && c.isVisible); - var leading = - widget.children.where((c) => c.name == "leading" && c.isVisible); - var trailing = - widget.children.where((c) => c.name == "trailing" && c.isVisible); var theme = Theme.of(context); - var style = parseButtonStyle(Theme.of(context), widget.control, "style", + var style = widget.control.getButtonStyle("style", Theme.of(context), defaultForegroundColor: theme.colorScheme.primary, defaultBackgroundColor: Colors.transparent, defaultOverlayColor: Colors.transparent, @@ -76,53 +57,35 @@ class _MenuItemButtonControlState extends State { ? const StadiumBorder() : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - bool onClick = widget.control.attrBool("onClick", false)!; - bool onHover = widget.control.attrBool("onHover", false)!; - - var adaptive = widget.control.isAdaptive ?? widget.parentAdaptive; + bool onClick = widget.control.getBool("on_click", false)!; + bool onHover = widget.control.getBool("on_hover", false)!; var menuItem = MenuItemButton( focusNode: _focusNode, - clipBehavior: - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!, + clipBehavior: widget.control.getClipBehavior("clip_behavior", Clip.none)!, style: style, - closeOnActivate: widget.control.attrBool("closeOnClick", true)!, - requestFocusOnHover: widget.control.attrBool("focusOnHover", true)!, - semanticsLabel: widget.control.attrString("semanticsLabel"), - autofocus: widget.control.attrBool("autofocus", false)!, - overflowAxis: parseAxis( - widget.control.attrString("overflowAxis"), Axis.horizontal)!, - onHover: onHover && !disabled - ? (bool value) { - widget.backend - .triggerControlEvent(widget.control.id, "hover", "$value"); - } - : null, - onPressed: onClick && !disabled - ? () { - widget.backend.triggerControlEvent(widget.control.id, "click"); - } - : null, - leadingIcon: leading.isNotEmpty - ? createControl(widget.control, leading.first.id, disabled, - parentAdaptive: adaptive) - : null, - trailingIcon: trailing.isNotEmpty - ? createControl(widget.control, trailing.first.id, disabled, - parentAdaptive: adaptive) + closeOnActivate: widget.control.getBool("close_on_click", true)!, + requestFocusOnHover: widget.control.getBool("focus_on_hover", true)!, + semanticsLabel: widget.control.getString("semantics_label"), + autofocus: widget.control.getBool("autofocus", false)!, + overflowAxis: widget.control.getAxis("overflow_axis", Axis.horizontal)!, + onHover: onHover && !widget.control.disabled + ? (bool value) => widget.control.triggerEvent("hover", value) : null, - child: content.isNotEmpty - ? createControl(widget.control, content.first.id, disabled, - parentAdaptive: adaptive) + onPressed: onClick && !widget.control.disabled + ? () => widget.control.triggerEvent("click") : null, + leadingIcon: widget.control.buildWidget("leading"), + trailingIcon: widget.control.buildWidget("trailing_icon"), + child: widget.control.buildTextOrWidget("content"), ); - var focusValue = widget.control.attrString("focus"); + var focusValue = widget.control.getString("focus"); if (focusValue != null && focusValue != _lastFocusValue) { _lastFocusValue = focusValue; _focusNode.requestFocus(); } - return constrainedControl(context, menuItem, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: menuItem); } } diff --git a/packages/flet/lib/src/controls/merge_semantics.dart b/packages/flet/lib/src/controls/merge_semantics.dart index 52ec645c1f..21acc3614a 100644 --- a/packages/flet/lib/src/controls/merge_semantics.dart +++ b/packages/flet/lib/src/controls/merge_semantics.dart @@ -1,37 +1,20 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import 'base_controls.dart'; class MergeSemanticsControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const MergeSemanticsControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const MergeSemanticsControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("MergeSemantics build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - - MergeSemantics mergeSemantics = MergeSemantics( - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null); - - return constrainedControl(context, mergeSemantics, parent, control); + return LayoutControl( + control: control, + child: MergeSemantics(child: control.buildWidget("content"))); } } diff --git a/packages/flet/lib/src/controls/navigation_bar.dart b/packages/flet/lib/src/controls/navigation_bar.dart index cd848c8571..5f88bee561 100644 --- a/packages/flet/lib/src/controls/navigation_bar.dart +++ b/packages/flet/lib/src/controls/navigation_bar.dart @@ -1,35 +1,22 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/icons.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/time.dart'; -import 'create_control.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; import 'cupertino_navigation_bar.dart'; -import 'flet_store_mixin.dart'; class NavigationBarControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const NavigationBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + NavigationBarControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _NavigationBarControlState(); @@ -41,11 +28,9 @@ class _NavigationBarControlState extends State void _destinationChanged(int index) { _selectedIndex = index; - debugPrint("Selected index: $_selectedIndex"); - widget.backend.updateControlState( - widget.control.id, {"selectedIndex": _selectedIndex.toString()}); - widget.backend.triggerControlEvent( - widget.control.id, "change", _selectedIndex.toString()); + widget.control + .updateProperties({"selected_index": _selectedIndex}, notify: true); + widget.control.triggerEvent("change", _selectedIndex); } @override @@ -53,81 +38,37 @@ class _NavigationBarControlState extends State debugPrint("NavigationBarControl build: ${widget.control.id}"); return withPagePlatform((context, platform) { - bool? adaptive = widget.control.isAdaptive ?? widget.parentAdaptive; - if (adaptive == true && + if (widget.control.adaptive == true && (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS)) { - return CupertinoNavigationBarControl( - control: widget.control, - children: widget.children, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - backend: widget.backend); + return CupertinoNavigationBarControl(control: widget.control); } - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var selectedIndex = widget.control.attrInt("selectedIndex", 0)!; + var selectedIndex = widget.control.getInt("selected_index", 0)!; if (_selectedIndex != selectedIndex) { _selectedIndex = selectedIndex; } - var navBar = withControls( - widget.children - .where((c) => c.isVisible && c.name == null) - .map((c) => c.id), (content, viewModel) { - return NavigationBar( - labelBehavior: parseNavigationDestinationLabelBehavior( - widget.control.attrString("labelBehavior")), - height: widget.control.attrDouble("height"), - animationDuration: - parseDuration(widget.control, "animationDuration"), - elevation: widget.control.attrDouble("elevation"), - labelPadding: parseEdgeInsets(widget.control, "labelPadding"), - shadowColor: widget.control.attrColor("shadowColor", context), - surfaceTintColor: - widget.control.attrColor("surfaceTintColor", context), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "overlayColor"), - indicatorColor: widget.control.attrColor("indicatorColor", context), - indicatorShape: - parseOutlinedBorder(widget.control, "indicatorShape"), - backgroundColor: widget.control.attrColor("bgColor", context), - selectedIndex: _selectedIndex, - onDestinationSelected: disabled ? null : _destinationChanged, - destinations: viewModel.controlViews.map((destView) { - var label = destView.control.attrString("label", "")!; - var iconStr = parseIcon(destView.control.attrString("icon")); - var iconCtrls = destView.children - .where((c) => c.name == "icon" && c.isVisible); - var selectedIconStr = - parseIcon(destView.control.attrString("selectedIcon")); - var selectedIconCtrls = destView.children - .where((c) => c.name == "selected_icon" && c.isVisible); - var destinationDisabled = disabled || destView.control.isDisabled; - var destinationAdaptive = destView.control.isAdaptive ?? adaptive; - var destinationTooltip = destView.control.attrString("tooltip"); - return NavigationDestination( - enabled: !destinationDisabled, - tooltip: !destinationDisabled && destinationTooltip != null - ? jsonDecode(destinationTooltip) - : null, - icon: iconCtrls.isNotEmpty - ? createControl(destView.control, iconCtrls.first.id, - destinationDisabled, - parentAdaptive: destinationAdaptive) - : Icon(iconStr), - selectedIcon: selectedIconCtrls.isNotEmpty - ? createControl(destView.control, - selectedIconCtrls.first.id, destinationDisabled, - parentAdaptive: destinationAdaptive) - : selectedIconStr != null - ? Icon(selectedIconStr) - : null, - label: label); - }).toList()); - }); + var navBar = NavigationBar( + labelBehavior: widget.control + .getNavigationDestinationLabelBehavior("label_behavior"), + height: widget.control.getDouble("height"), + animationDuration: widget.control.getDuration("animation_duration"), + elevation: widget.control.getDouble("elevation"), + labelPadding: widget.control.getPadding("label_padding"), + shadowColor: widget.control.getColor("shadow_color", context), + overlayColor: widget.control + .getWidgetStateColor("overlay_color", Theme.of(context)), + indicatorColor: widget.control.getColor("indicator_color", context), + indicatorShape: + widget.control.getShape("indicator_shape", Theme.of(context)), + backgroundColor: widget.control.getColor("bgcolor", context), + selectedIndex: _selectedIndex, + onDestinationSelected: + widget.control.disabled ? null : _destinationChanged, + destinations: widget.control.buildWidgets("destinations")); - return constrainedControl(context, navBar, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: navBar); }); } } diff --git a/packages/flet/lib/src/controls/navigation_bar_destination.dart b/packages/flet/lib/src/controls/navigation_bar_destination.dart new file mode 100644 index 0000000000..ab227eec87 --- /dev/null +++ b/packages/flet/lib/src/controls/navigation_bar_destination.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; + +class NavigationBarDestinationControl extends StatelessWidget { + final Control control; + + const NavigationBarDestinationControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("NavigationBarDestination build: ${control.id}"); + + var child = NavigationDestination( + enabled: !control.disabled, + tooltip: !control.disabled ? control.getString("tooltip") : null, + icon: control.buildIconOrWidget("icon")!, + selectedIcon: control.buildIconOrWidget("selected_icon"), + label: control.getString("label", "")!, + ); + + return BaseControl(control: control, child: child); + } +} diff --git a/packages/flet/lib/src/controls/navigation_drawer.dart b/packages/flet/lib/src/controls/navigation_drawer.dart index 8a23c7c7cc..1f61433138 100644 --- a/packages/flet/lib/src/controls/navigation_drawer.dart +++ b/packages/flet/lib/src/controls/navigation_drawer.dart @@ -1,111 +1,78 @@ +import 'package:flet/src/extensions/control.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/icons.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; class NavigationDrawerControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const NavigationDrawerControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + NavigationDrawerControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _NavigationDrawerControlState(); } -class _NavigationDrawerControlState extends State - with FletStoreMixin { +class _NavigationDrawerControlState extends State { int _selectedIndex = 0; void _destinationChanged(int index) { _selectedIndex = index; debugPrint("Selected index: $_selectedIndex"); - widget.backend.updateControlState( - widget.control.id, {"selectedindex": _selectedIndex.toString()}); - widget.backend.triggerControlEvent( - widget.control.id, "change", _selectedIndex.toString()); + widget.control + .updateProperties({"selected_index": _selectedIndex}, notify: true); + widget.control.triggerEvent("change", _selectedIndex); } @override Widget build(BuildContext context) { debugPrint("NavigationDrawerControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var selectedIndex = widget.control.attrInt("selectedIndex", 0)!; - + var selectedIndex = widget.control.getInt("selected_index", 0)!; if (_selectedIndex != selectedIndex) { _selectedIndex = selectedIndex; } - return withControls( - widget.children - .where((c) => c.isVisible && c.name == null) - .map((c) => c.id), (content, viewModel) { - List children = viewModel.controlViews.map((destView) { - if (destView.control.type == "navigationdrawerdestination") { - var iconStr = parseIcon(destView.control.attrString("icon")); - var iconCtrls = destView.children - .where((c) => c.name == "icon" && c.isVisible); - - var selectedIconStr = - parseIcon(destView.control.attrString("selectedIcon")); - var selectedIconCtrls = destView.children - .where((c) => c.name == "selected_icon" && c.isVisible); + final width = widget.control.getDouble("width"); + + var drawer = NavigationDrawer( + elevation: widget.control.getDouble("elevation"), + indicatorColor: widget.control.getColor("indicator_color", context), + indicatorShape: widget.control + .getOutlinedBorder("indicator_shape", Theme.of(context)), + backgroundColor: widget.control.getColor("bgcolor", context), + selectedIndex: _selectedIndex, + shadowColor: widget.control.getColor("shadow_color", context), + tilePadding: widget.control.getEdgeInsets( + "tile_padding", const EdgeInsets.symmetric(horizontal: 12.0))!, + onDestinationSelected: _destinationChanged, + children: widget.control.children("controls").map((dest) { + dest.notifyParent = true; + if (dest.type == "NavigationDrawerDestination") { return NavigationDrawerDestination( - enabled: !(disabled || destView.control.isDisabled), - backgroundColor: destView.control.attrColor("bgColor", context), - icon: iconCtrls.isNotEmpty - ? createControl( - destView.control, iconCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : Icon(iconStr), - label: Text(destView.control.attrString("label", "")!), - selectedIcon: selectedIconCtrls.isNotEmpty - ? createControl(destView.control, - selectedIconCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : selectedIconStr != null - ? Icon(selectedIconStr) - : null, + enabled: !dest.disabled, + label: dest.buildTextOrWidget("label") ?? const Text(""), + backgroundColor: dest.getColor("bgcolor", context), + icon: dest.buildIconOrWidget("icon", required: true)!, + selectedIcon: dest.buildIconOrWidget("selected_icon"), ); } else { - return createControl(widget.control, destView.control.id, disabled, - parentAdaptive: widget.parentAdaptive); + return ControlWidget(control: dest); } - }).toList(); + }).toList(), + ); - var drawer = NavigationDrawer( - elevation: widget.control.attrDouble("elevation"), - indicatorColor: widget.control.attrColor("indicatorColor", context), - indicatorShape: parseOutlinedBorder(widget.control, "indicatorShape"), - backgroundColor: widget.control.attrColor("bgColor", context), - selectedIndex: _selectedIndex, - shadowColor: widget.control.attrColor("shadowColor", context), - surfaceTintColor: widget.control.attrColor("surfaceTintColor", context), - tilePadding: parseEdgeInsets(widget.control, "tilePadding", - const EdgeInsets.symmetric(horizontal: 12.0))!, - onDestinationSelected: _destinationChanged, - children: children, - ); - - return baseControl(context, drawer, widget.parent, widget.control); - }); + Widget drawerWidget = drawer; + if (width != null) { + drawerWidget = SizedBox(width: width, child: drawer); + } + return BaseControl(control: widget.control, child: drawerWidget); } } diff --git a/packages/flet/lib/src/controls/navigation_rail.dart b/packages/flet/lib/src/controls/navigation_rail.dart index 96e771a827..08d7cc3d25 100644 --- a/packages/flet/lib/src/controls/navigation_rail.dart +++ b/packages/flet/lib/src/controls/navigation_rail.dart @@ -1,31 +1,22 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/icons.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; class NavigationRailControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const NavigationRailControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + NavigationRailControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _NavigationRailControlState(); @@ -37,125 +28,93 @@ class _NavigationRailControlState extends State void _destinationChanged(int index) { _selectedIndex = index; - debugPrint("NavigationRail selectedIndex: $_selectedIndex"); - widget.backend.updateControlState( - widget.control.id, {"selectedindex": _selectedIndex.toString()}); - widget.backend.triggerControlEvent( - widget.control.id, "change", _selectedIndex.toString()); + debugPrint("NavigationRail selected_index: $_selectedIndex"); + widget.control + .updateProperties({"selected_index": _selectedIndex}, notify: true); + widget.control.triggerEvent("change", _selectedIndex); } @override Widget build(BuildContext context) { debugPrint("NavigationRailControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var selectedIndex = widget.control.attrInt("selectedIndex"); + bool disabled = widget.control.disabled; + var selectedIndex = widget.control.getInt("selected_index"); if (_selectedIndex != selectedIndex) { _selectedIndex = selectedIndex; } - NavigationRailLabelType? labelType = NavigationRailLabelType.values - .firstWhere( - (a) => - a.name.toLowerCase() == - widget.control.attrString("labelType", "")!.toLowerCase(), - orElse: () => NavigationRailLabelType.all); - - var leadingCtrls = - widget.children.where((c) => c.name == "leading" && c.isVisible); - var trailingCtrls = - widget.children.where((c) => c.name == "trailing" && c.isVisible); - - var extended = widget.control.attrBool("extended", false)!; - - var rail = withControls( - widget.children - .where((c) => c.isVisible && c.name == null) - .map((c) => c.id), (content, viewModel) { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - debugPrint( - "NavigationRail constraints.maxWidth: ${constraints.maxWidth}"); - debugPrint( - "NavigationRail constraints.maxHeight: ${constraints.maxHeight}"); - - if (constraints.maxHeight == double.infinity && - widget.control.attrDouble("height") == null) { - return const ErrorControl("Error displaying NavigationRail", - description: - "Control's height is unbounded. Either set \"expand\" property, set a fixed \"height\" or nest NavigationRail inside another control with a fixed height."); - } - - return NavigationRail( - labelType: extended ? NavigationRailLabelType.none : labelType, - extended: extended, - elevation: widget.control.attrDouble("elevation"), - selectedLabelTextStyle: parseTextStyle( - Theme.of(context), widget.control, "selectedLabelTextStyle"), - unselectedLabelTextStyle: parseTextStyle(Theme.of(context), - widget.control, "unselectedLabelTextStyle"), - indicatorShape: - parseOutlinedBorder(widget.control, "indicatorShape"), - minWidth: widget.control.attrDouble("minWidth"), - minExtendedWidth: widget.control.attrDouble("minExtendedWidth"), - groupAlignment: widget.control.attrDouble("groupAlignment"), - backgroundColor: widget.control.attrColor("bgColor", context), - indicatorColor: - widget.control.attrColor("indicatorColor", context), - leading: leadingCtrls.isNotEmpty - ? createControl( - widget.control, leadingCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - trailing: trailingCtrls.isNotEmpty - ? createControl( - widget.control, trailingCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - selectedIndex: _selectedIndex, - onDestinationSelected: _destinationChanged, - destinations: viewModel.controlViews.map((destView) { - var label = destView.control.attrString("label", "")!; - var labelContentCtrls = destView.children - .where((c) => c.name == "label_content" && c.isVisible); - - var iconStr = parseIcon(destView.control.attrString("icon")); - var iconCtrls = destView.children - .where((c) => c.name == "icon" && c.isVisible); - var selectedIconStr = - parseIcon(destView.control.attrString("selectedIcon")); - var selectedIconCtrls = destView.children - .where((c) => c.name == "selected_icon" && c.isVisible); - return NavigationRailDestination( - disabled: disabled || destView.control.isDisabled, - padding: parseEdgeInsets(destView.control, "padding"), - indicatorColor: - destView.control.attrColor("indicatorColor", context), - indicatorShape: - parseOutlinedBorder(destView.control, "indicatorShape"), - icon: iconCtrls.isNotEmpty - ? createControl(destView.control, - iconCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : Icon(iconStr), - selectedIcon: selectedIconCtrls.isNotEmpty - ? createControl(destView.control, - selectedIconCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : selectedIconStr != null - ? Icon(selectedIconStr) - : null, - label: labelContentCtrls.isNotEmpty - ? createControl(destView.control, - labelContentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : Text(label)); - }).toList()); - }, - ); - }); - - return constrainedControl(context, rail, widget.parent, widget.control); + var labelType = parseNavigationRailLabelType( + widget.control.getString("label_type"), NavigationRailLabelType.all)!; + + var extended = widget.control.getBool("extended", false)!; + + var rail = LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + debugPrint( + "NavigationRail constraints.maxWidth: ${constraints.maxWidth}"); + debugPrint( + "NavigationRail constraints.maxHeight: ${constraints.maxHeight}"); + + if (constraints.maxHeight == double.infinity && + widget.control.getDouble("height") == null) { + return const ErrorControl( + "Error displaying NavigationRail: height is unbounded.", + description: + "Either set a fixed \"height\" or nest NavigationRail inside expanded control or control with a fixed height."); + } + + return NavigationRail( + labelType: extended ? NavigationRailLabelType.none : labelType, + extended: extended, + elevation: widget.control.getDouble("elevation"), + selectedLabelTextStyle: parseTextStyle( + widget.control.get("selected_label_text_style"), + Theme.of(context)), + unselectedLabelTextStyle: parseTextStyle( + widget.control.get("unselected_label_text_style"), + Theme.of(context)), + indicatorShape: widget.control + .getOutlinedBorder("indicator_shape", Theme.of(context)), + minWidth: widget.control.getDouble("min_width"), + minExtendedWidth: widget.control.getDouble("min_extended_width"), + groupAlignment: widget.control.getDouble("group_alignment"), + backgroundColor: widget.control.getColor("bgcolor", context), + indicatorColor: widget.control.getColor("indicator_color", context), + leading: widget.control.buildWidget("leading"), + leadingAtTop: widget.control.getBool("pin_leading_to_top", true)!, + trailing: widget.control.buildWidget("trailing"), + trailingAtBottom: + widget.control.getBool("pin_trailing_to_bottom", false)!, + scrollable: widget.control.getBool("scrollable", false)!, + selectedIndex: _selectedIndex, + useIndicator: widget.control.getBool("use_indicator"), + onDestinationSelected: _destinationChanged, + destinations: + widget.control.children("destinations").map((destinationControl) { + destinationControl.notifyParent = true; + var icon = destinationControl.buildIconOrWidget("icon")!; + Widget? selectedIcon = + destinationControl.buildIconOrWidget("selected_icon"); + return NavigationRailDestination( + disabled: disabled || destinationControl.disabled, + padding: destinationControl.getPadding("padding"), + indicatorColor: + destinationControl.getColor("indicator_color", context), + indicatorShape: destinationControl.getOutlinedBorder( + "indicator_shape", Theme.of(context)), + icon: icon, + selectedIcon: selectedIcon, + label: destinationControl.buildTextOrWidget("label", + required: true, + errorWidget: ErrorWidget( + "label (string or visible Control) must be provided"))!); + }).toList(), + ); + }, + ); + + return LayoutControl(control: widget.control, child: rail); } } diff --git a/packages/flet/lib/src/controls/outlined_button.dart b/packages/flet/lib/src/controls/outlined_button.dart deleted file mode 100644 index f655153be7..0000000000 --- a/packages/flet/lib/src/controls/outlined_button.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; -import '../utils/buttons.dart'; -import '../utils/icons.dart'; -import '../utils/launch_url.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'cupertino_button.dart'; -import 'cupertino_dialog_action.dart'; -import 'flet_store_mixin.dart'; - -class OutlinedButtonControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const OutlinedButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); - - @override - State createState() => _OutlinedButtonControlState(); -} - -class _OutlinedButtonControlState extends State - with FletStoreMixin { - late final FocusNode _focusNode; - String? _lastFocusValue; - - @override - void initState() { - super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); - } - - @override - void dispose() { - _focusNode.removeListener(_onFocusChange); - _focusNode.dispose(); - super.dispose(); - } - - void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); - } - - @override - Widget build(BuildContext context) { - debugPrint("Button build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - String text = widget.control.attrString("text", "")!; - IconData? icon = parseIcon(widget.control.attrString("icon")); - Color? iconColor = widget.control.attrColor("iconColor", context); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - String url = widget.control.attrString("url", "")!; - String? urlTarget = widget.control.attrString("urlTarget"); - bool onHover = widget.control.attrBool("onHover", false)!; - bool onLongPress = widget.control.attrBool("onLongPress", false)!; - bool autofocus = widget.control.attrBool("autofocus", false)!; - var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.none)!; - Function()? onPressed = !disabled - ? () { - debugPrint("Button ${widget.control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - widget.backend.triggerControlEvent(widget.control.id, "click"); - } - : null; - - Function()? onLongPressHandler = onLongPress && !disabled - ? () { - debugPrint("Button ${widget.control.id} long pressed!"); - widget.backend.triggerControlEvent(widget.control.id, "long_press"); - } - : null; - - Function(bool)? onHoverHandler = onHover && !disabled - ? (state) { - debugPrint("Button ${widget.control.id} hovered!"); - widget.backend.triggerControlEvent( - widget.control.id, "hover", state.toString()); - } - : null; - - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return widget.control.name == "action" && - (widget.parent?.type == "alertdialog" || - widget.parent?.type == "cupertinoalertdialog") - ? CupertinoDialogActionControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend) - : CupertinoButtonControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend); - } - - OutlinedButton? button; - - var theme = Theme.of(context); - - var style = parseButtonStyle(Theme.of(context), widget.control, "style", - defaultForegroundColor: theme.colorScheme.primary, - defaultBackgroundColor: Colors.transparent, - defaultOverlayColor: Colors.transparent, - defaultShadowColor: Colors.transparent, - defaultSurfaceTintColor: Colors.transparent, - defaultElevation: 0, - defaultPadding: const EdgeInsets.all(8), - defaultBorderSide: BorderSide(color: theme.colorScheme.outline), - defaultShape: theme.useMaterial3 - ? const StadiumBorder() - : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - - if (icon != null) { - button = OutlinedButton.icon( - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - clipBehavior: clipBehavior, - style: style, - icon: Icon( - icon, - color: iconColor, - ), - label: Text(text)); - } else if (contentCtrls.isNotEmpty) { - button = OutlinedButton( - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - clipBehavior: clipBehavior, - onHover: onHoverHandler, - style: style, - child: - createControl(widget.control, contentCtrls.first.id, disabled)); - } else { - button = OutlinedButton( - autofocus: autofocus, - focusNode: _focusNode, - style: style, - onPressed: onPressed, - onLongPress: onLongPressHandler, - clipBehavior: clipBehavior, - onHover: onHoverHandler, - child: Text(text)); - } - - var focusValue = widget.control.attrString("focus"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); - } - - return constrainedControl(context, button, widget.parent, widget.control); - }); - } -} diff --git a/packages/flet/lib/src/controls/page.dart b/packages/flet/lib/src/controls/page.dart index e0e9728d75..826535fa43 100644 --- a/packages/flet/lib/src/controls/page.dart +++ b/packages/flet/lib/src/controls/page.dart @@ -1,186 +1,109 @@ import 'dart:async'; -import 'dart:convert'; +import 'dart:ui' as ui; +import 'dart:ui'; import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flet/src/models/page_args_model.dart'; -import 'package:flet/src/utils/locale.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -import '../actions.dart'; -import '../flet_app_context.dart'; -import '../flet_app_services.dart'; -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; +import 'package:provider/provider.dart'; + +import '../extensions/control.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; -import '../models/control_view_model.dart'; -import '../models/page_media_view_model.dart'; +import '../models/keyboard_event.dart'; +import '../models/multi_view.dart'; +import '../models/page_design.dart'; +import '../routing/deep_linking_bootstrap.dart'; +import '../routing/route_information_provider.dart'; import '../routing/route_parser.dart'; import '../routing/route_state.dart'; import '../routing/router_delegate.dart'; -import '../utils/alignment.dart'; -import '../utils/box.dart'; -import '../utils/buttons.dart'; -import '../utils/desktop.dart'; -import '../utils/edge_insets.dart'; -import '../utils/images.dart'; +import '../services/service_binding.dart'; +import '../services/service_registry.dart'; +import '../utils/animations.dart'; +import '../utils/device_info.dart'; +import '../utils/locale.dart'; +import '../utils/numbers.dart'; import '../utils/platform.dart'; +import '../utils/platform_utils_web.dart' + if (dart.library.io) "../utils/platform_utils_non_web.dart"; +import '../utils/session_store_web.dart' + if (dart.library.io) "../utils/session_store_non_web.dart"; import '../utils/theme.dart'; +import '../utils/time.dart'; import '../utils/user_fonts.dart'; import '../widgets/animated_transition_page.dart'; import '../widgets/loading_page.dart'; +import '../widgets/page_context.dart'; import '../widgets/page_media.dart'; -import '../widgets/window_media.dart'; -import 'app_bar.dart'; -import 'create_control.dart'; -import 'cupertino_app_bar.dart'; -import 'flet_store_mixin.dart'; -import 'navigation_drawer.dart'; -import 'scroll_notification_control.dart'; -import 'scrollable_control.dart'; - -enum PageDesign { material, cupertino } - -class RoutesViewModel extends Equatable { - final Control page; - final bool isLoading; - final String error; - final List offstageControls; - final List views; - - const RoutesViewModel( - {required this.page, - required this.isLoading, - required this.error, - required this.offstageControls, - required this.views}); - - static RoutesViewModel fromStore(Store store) { - Control? offstageControl = store.state.controls["page"]!.childIds - .map((childId) => store.state.controls[childId]!) - .firstWhereOrNull((c) => c.type == "offstage"); - - return RoutesViewModel( - page: store.state.controls["page"]!, - isLoading: store.state.isLoading, - error: store.state.error, - offstageControls: offstageControl != null - ? store.state.controls[offstageControl.id]!.childIds - .map((childId) => store.state.controls[childId]!) - .where((c) => c.isVisible) - .toList() - : [], - views: store.state.controls["page"]!.childIds - .map((childId) => store.state.controls[childId]!) - .where((c) => c.type != "offstage" && c.isVisible) - .toList()); - } - - @override - List get props => [page, isLoading, error, offstageControls, views]; -} - -class KeyboardEvent { - final String key; - final bool isShiftPressed; - final bool isControlPressed; - final bool isAltPressed; - final bool isMetaPressed; - - KeyboardEvent( - {required this.key, - required this.isShiftPressed, - required this.isControlPressed, - required this.isAltPressed, - required this.isMetaPressed}); - - Map toJson() => { - 'key': key, - 'shift': isShiftPressed, - 'ctrl': isControlPressed, - 'alt': isAltPressed, - 'meta': isMetaPressed - }; -} +import 'control_widget.dart'; class PageControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final dynamic dispatch; - final FletControlBackend backend; - - const PageControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.dispatch, - required this.backend}); + + PageControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _PageControlState(); } -class _PageControlState extends State with FletStoreMixin { - bool? _adaptive; - PageDesign _widgetsDesign = PageDesign.material; - TargetPlatform _platform = defaultTargetPlatform; - Brightness? _brightness; - ThemeMode? _themeMode; - Map? _localeConfiguration; - String? _windowTitle; - Color? _windowBgcolor; - double? _windowWidth; - double? _windowHeight; - double? _windowMinWidth; - double? _windowMinHeight; - double? _windowMaxWidth; - double? _windowMaxHeight; - double? _windowTop; - double? _windowLeft; - double? _windowOpacity; - bool? _windowMinimizable; - bool? _windowMaximizable; - bool? _windowFullScreen; - bool? _windowMovable; - bool? _windowResizable; - bool? _windowAlwaysOnTop; - bool? _windowAlwaysOnBottom; - bool? _windowPreventClose; - bool? _windowMinimized; - bool? _windowMaximized; - Alignment? _windowAlignment; - String? _windowBadgeLabel; - String? _windowIcon; - bool? _windowHasShadow; - bool? _windowVisible; - bool? _windowFocused; - String? _windowCenter; - String? _windowClose; - bool? _windowFrameless; - bool? _windowTitleBarHidden; - bool? _windowSkipTaskBar; - double? _windowProgressBar; - bool? _windowIgnoreMouseEvents; +class _PageControlState extends State with WidgetsBindingObserver { final _navigatorKey = GlobalKey(); + final _rootKey = GlobalKey(); late final RouteState _routeState; late final SimpleRouterDelegate _routerDelegate; late final RouteParser _routeParser; + late final RouteInformationProvider _routeInformationProvider; late final AppLifecycleListener _appLifecycleListener; - String? _prevViewRoutes; + ServiceRegistry? _services; + String? _servicesUid; + ServiceBinding? _windowService; + Control? _windowControl; + bool? _prevOnKeyboardEvent; bool _keyboardHandlerSubscribed = false; + List? _locales; + String? _prevViewRoutes; + final Set _pendingPoppedViewRoutes = {}; + final Set _sentViewPopEventsForRoutes = {}; + + final Map _multiViews = {}; + bool _registeredFromMultiViews = false; @override void initState() { + debugPrint("Page.initState: ${widget.control.id}"); super.initState(); + + WidgetsBinding.instance.addObserver(this); + _updateMultiViews(); + _routeParser = RouteParser(); + final backend = FletBackend.of(context); + final isEmbedded = backend.controlId != null; + final defaultRouteName = + WidgetsBinding.instance.platformDispatcher.defaultRouteName; + final pendingInitial = isEmbedded + ? null + : FletDeepLinkingBootstrap.takePendingInitialRouteInformation(); + final initial = isEmbedded + ? RouteInformation(uri: Uri(path: '/')) + : FletRouteInformationProvider.normalize( + pendingInitial ?? + RouteInformation( + uri: Uri.tryParse(defaultRouteName) ?? Uri(path: '/'), + ), + ); + _routeInformationProvider = isEmbedded + ? FletLocalRouteInformationProvider(initialRouteInformation: initial) + : FletRouteInformationProvider(initialRouteInformation: initial); + if (!isEmbedded) { + FletDeepLinkingBootstrap.markRouterReady(); + } _routeState = RouteState(_routeParser); _routeState.addListener(_routeChanged); @@ -189,6 +112,7 @@ class _PageControlState extends State with FletStoreMixin { routeState: _routeState, navigatorKey: _navigatorKey, builder: (context) => _buildNavigator(context, _navigatorKey), + popRouteHandler: _handleSystemPopRoute, ); _appLifecycleListener = AppLifecycleListener( @@ -199,22 +123,284 @@ class _PageControlState extends State with FletStoreMixin { onPause: () => _handleAppLifecycleTransition('pause'), onDetach: () => _handleAppLifecycleTransition('detach'), onRestart: () => _handleAppLifecycleTransition('restart')); + + _attachKeyboardListenerIfNeeded(); + widget.control.addInvokeMethodListener(_invokeMethod); + widget.control.addListener(_onPageControlChanged); + _ensureServiceRegistries(); + } + + @override + void didChangeDependencies() { + debugPrint("Page.didChangeDependencies: ${widget.control.id}"); + super.didChangeDependencies(); + _ensureServiceRegistries(); + _loadFontsIfNeeded(FletBackend.of(context)); + } + + @override + void didUpdateWidget(covariant PageControl oldWidget) { + debugPrint("Page.didUpdateWidget: ${widget.control.id}"); + super.didUpdateWidget(oldWidget); + _updateMultiViews(); + _ensureServiceRegistries(); + _attachKeyboardListenerIfNeeded(); + _loadFontsIfNeeded(FletBackend.of(context)); + } + + @override + void didChangeMetrics() { + _updateMultiViews(); + } + + @override + void didChangeLocales(List? locales) { + super.didChangeLocales(locales); + + final effectiveLocales = + locales ?? WidgetsBinding.instance.platformDispatcher.locales; + final nextLocales = List.unmodifiable(effectiveLocales); + if (_locales != null && + const ListEquality().equals(_locales!, nextLocales)) { + return; + } + + _locales = nextLocales; + widget.control.triggerEvent( + 'locale_change', + {'locales': nextLocales.map((l) => l.toMap()).toList(growable: false)}, + ); } @override void dispose() { + debugPrint("Page.dispose: ${widget.control.id}"); + WidgetsBinding.instance.removeObserver(this); _routeState.removeListener(_routeChanged); - _routeState.dispose(); + _appLifecycleListener.dispose(); if (_keyboardHandlerSubscribed) { HardwareKeyboard.instance.removeHandler(_handleKeyDown); } - _appLifecycleListener.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + widget.control.removeListener(_onPageControlChanged); + _services?.dispose(); + _windowService?.dispose(); super.dispose(); } + void _onPageControlChanged() { + _ensureServiceRegistries(); + } + + void _ensureServiceRegistries() { + if (!mounted) { + return; + } + var backend = FletBackend.of(context); + + var servicesControl = widget.control.child("_services"); + if (servicesControl != null) { + var uid = servicesControl.internals?["uid"]; + if (_services == null || _servicesUid != uid) { + _services?.dispose(); + _services = ServiceRegistry( + control: servicesControl, + propertyName: "_services", + backend: backend); + _servicesUid = uid; + } + } else if (_services != null) { + _services?.dispose(); + _services = null; + _servicesUid = null; + } + + var windowControl = widget.control.child("window", visibleOnly: false); + if (windowControl != null) { + if (!identical(windowControl, _windowControl)) { + _windowService?.dispose(); + _windowService = + ServiceBinding(control: windowControl, backend: backend); + _windowControl = windowControl; + } + } else if (_windowService != null) { + _windowService?.dispose(); + _windowService = null; + _windowControl = null; + } + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Page.$name($args)"); + + switch (name) { + case "take_screenshot": + { + // Capture context up front + final ctx = _rootKey.currentContext; + if (ctx == null) return null; + + // Read everything you can before awaiting + final delay = + parseDuration(args["delay"], const Duration(milliseconds: 20))!; + final pixelRatio = parseDouble( + args["pixel_ratio"], MediaQuery.of(ctx).devicePixelRatio)!; + + // Wait, then ensure the widget is still mounted + await Future.delayed(delay); + if (!ctx.mounted) { + return null; + } + + // Use the same (still-mounted) context + final boundary = ctx.findRenderObject() as RenderRepaintBoundary?; + if (boundary == null) return null; + + final image = await boundary.toImage(pixelRatio: pixelRatio); + final data = await image.toByteData(format: ui.ImageByteFormat.png); + return data?.buffer.asUint8List(); + } + + case "take_animation": + { + final frameDelaysMs = + List.from(args["frame_delays_ms"] ?? const []); + final frames = []; + // In integration tests the scheduler doesn't advance animations on + // its own during Future.delayed — WidgetTester.pump is what drives + // the clock. Use it when available so in-flight animations progress + // between captures; fall back to Future.delayed outside test mode. + final tester = FletBackend.of(context).tester; + for (final delayMs in frameDelaysMs) { + final delay = Duration(milliseconds: delayMs); + if (tester != null) { + await tester.pump(duration: delay); + } else { + await Future.delayed(delay); + } + final ctx = _rootKey.currentContext; + if (ctx == null || !ctx.mounted) return frames; + final boundary = ctx.findRenderObject() as RenderRepaintBoundary?; + if (boundary == null) return frames; + final pixelRatio = parseDouble( + args["pixel_ratio"], MediaQuery.of(ctx).devicePixelRatio)!; + final image = await boundary.toImage(pixelRatio: pixelRatio); + final data = + await image.toByteData(format: ui.ImageByteFormat.png); + image.dispose(); + if (data == null) return frames; + frames.add(data.buffer.asUint8List()); + } + return frames; + } + + case "push_route": + _routeState.route = args["route"]; + break; + case "get_device_info": + return await getDeviceInfo(); + case "set_allowed_device_orientations": + if (isMobilePlatform()) { + var orientations = args["orientations"] + ?.map((o) => parseDeviceOrientation(o)) + .whereType() + .toList() ?? + List.from(DeviceOrientation.values); + await SystemChrome.setPreferredOrientations(orientations); + } + break; + + default: + throw Exception("Unknown Page method: $name"); + } + } + + void _updateMultiViews() { + if (!widget.control.backend.multiView) { + return; + } + bool changed = false; + + bool triggerAddViewEvent = + SessionStore.get("triggerAddViewEvent") == null || isPyodideMode(); + for (final FlutterView view + in WidgetsBinding.instance.platformDispatcher.views) { + if (!_multiViews.containsKey(view.viewId)) { + var initialData = getViewInitialData(view.viewId); + debugPrint("View initial data ${view.viewId}: $initialData"); + _multiViews[view.viewId] = MultiView( + viewId: view.viewId, flutterView: view, initialData: initialData); + if (triggerAddViewEvent) { + widget.control.triggerEventWithoutSubscribers("multi_view_add", + {"view_id": view.viewId, "initial_data": initialData}); + } + changed = true; + } + } + for (var viewId in _multiViews.keys.toList()) { + if (!WidgetsBinding.instance.platformDispatcher.views + .any((view) => view.viewId == viewId)) { + _multiViews.remove(viewId); + if (triggerAddViewEvent) { + widget.control + .triggerEventWithoutSubscribers("multi_view_remove", viewId); + } + changed = true; + } + } + if (!isPyodideMode()) { + SessionStore.set("triggerAddViewEvent", "true"); + } + if (changed && !_registeredFromMultiViews) { + _registeredFromMultiViews = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.control.backend.onRouteUpdated("/"); + }); + } else { + // re-draw + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() {}); + }); + } + } + void _routeChanged() { - widget.dispatch(SetPageRouteAction( - _routeState.route, FletAppServices.of(context).server)); + FletBackend.of(context).onRouteUpdated(_routeState.route); + } + + void _markViewAsPopped(String routeStr) { + if (_pendingPoppedViewRoutes.add(routeStr) && mounted) { + setState(() {}); + } + if (_sentViewPopEventsForRoutes.add(routeStr)) { + widget.control + .triggerEventWithoutSubscribers("view_pop", {"route": routeStr}); + } + } + + Future _handleSystemPopRoute() async { + debugPrint("Page._handleSystemPopRoute"); + final views = widget.control.children("views"); + if (views.length <= 1) { + return null; + } + + final topView = views.last; + final canPop = topView.getBool("can_pop", true) ?? true; + final requiresConfirm = topView.getBool("on_confirm_pop", false) ?? false; + if (!canPop || requiresConfirm) { + return null; + } + + final routeStr = topView.getString("route", topView.id.toString()) ?? + topView.id.toString(); + _markViewAsPopped(routeStr); + return true; + } + + void _handleAppLifecycleTransition(String state) { + widget.control.triggerEventWithoutSubscribers( + "app_lifecycle_state_change", {"state": state}); } bool _handleKeyDown(KeyEvent e) { @@ -234,994 +420,337 @@ class _PageControlState extends State with FletStoreMixin { LogicalKeyboardKey.shiftLeft, LogicalKeyboardKey.shiftRight ].contains(k)) { - widget.backend.triggerControlEvent( - "page", + widget.control.triggerEventWithoutSubscribers( "keyboard_event", - json.encode(KeyboardEvent( + KeyboardEvent( key: k.keyLabel, isAltPressed: HardwareKeyboard.instance.isAltPressed, isControlPressed: HardwareKeyboard.instance.isControlPressed, isShiftPressed: HardwareKeyboard.instance.isShiftPressed, isMetaPressed: HardwareKeyboard.instance.isMetaPressed) - .toJson())); + .toMap()); } } return false; } - void _handleAppLifecycleTransition(String state) { - widget.backend - .triggerControlEvent("page", "app_lifecycle_state_change", state); + void _attachKeyboardListenerIfNeeded() { + var onKeyboardEvent = widget.control.getBool("on_keyboard_event", false); + if (onKeyboardEvent != _prevOnKeyboardEvent) { + if (onKeyboardEvent == true && !_keyboardHandlerSubscribed) { + HardwareKeyboard.instance.addHandler(_handleKeyDown); + _keyboardHandlerSubscribed = true; + } else if (onKeyboardEvent == false && _keyboardHandlerSubscribed) { + HardwareKeyboard.instance.removeHandler(_handleKeyDown); + _keyboardHandlerSubscribed = false; + } + _prevOnKeyboardEvent = onKeyboardEvent; + } + } + + Future _loadFontsIfNeeded(FletBackend backend) async { + final fonts = widget.control.getFonts("fonts", {})!; + for (final entry in fonts.entries) { + final fontFamily = entry.key; + final fontUrl = entry.value; + var assetSrc = backend.getAssetSource(fontUrl); + try { + if (assetSrc.isFile) { + await UserFonts.loadFontFromFile(fontFamily, assetSrc.path); + } else { + await UserFonts.loadFontFromUrl(fontFamily, assetSrc.path); + } + } catch (e) { + debugPrint("Error loading font $fontFamily: $e"); + } + } } @override Widget build(BuildContext context) { - debugPrint("Page build: ${widget.control.id}"); - - //debugDumpRenderTree(); + debugPrint("Page.build: ${widget.control.id}"); // clear hrefs index - FletAppServices.of(context).globalKeys.clear(); + var backend = FletBackend.of(context); + backend.globalKeys.clear(); + + if (!widget.control.backend.multiView) { + // single page mode + return _buildApp(widget.control, null); + } else { + // multi-view mode + var appStatus = context + .select((backend) => + (isLoading: backend.isLoading, error: backend.error)); + var appStartupScreenMessage = backend.appStartupScreenMessage ?? ""; + var formattedErrorMessage = + backend.formatAppErrorMessage(appStatus.error); + + List views = []; + for (var view in _multiViews.entries) { + var multiViewControl = widget.control + .children("multi_views") + .firstWhereOrNull((v) => v.get("view_id") == view.key); + + var viewControl = multiViewControl?.children("views").firstOrNull; + + Widget viewChild = SizedBox( + width: 100, + height: 100, + child: viewControl != null + ? ControlWidget(control: viewControl) + : Stack(children: [ + PageMedia(view: multiViewControl), + LoadingPage( + isLoading: appStatus.isLoading, + message: appStatus.isLoading + ? appStartupScreenMessage + : formattedErrorMessage, + ) + ]), + ); - // page route - var route = widget.control.attrString("route"); - if (_routeState.route != route && route != null) { - // route updated - _routeState.route = route; + viewChild = _buildApp(multiViewControl ?? widget.control, viewChild); + views.add(View(view: view.value.flutterView, child: viewChild)); + } + return ViewCollection(views: views); } + } - _platform = TargetPlatform.values.firstWhere( + Widget _buildApp(Control control, Widget? home) { + var platform = TargetPlatform.values.firstWhere( (a) => a.name.toLowerCase() == - widget.control.attrString("platform", "")!.toLowerCase(), + control.getString("platform", "")!.toLowerCase(), orElse: () => defaultTargetPlatform); - _adaptive = widget.control.attrBool("adaptive"); - - _widgetsDesign = _adaptive == true && - (_platform == TargetPlatform.iOS || - _platform == TargetPlatform.macOS) + var widgetsDesign = control.adaptive == true && + (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS) ? PageDesign.cupertino : PageDesign.material; // theme - _themeMode = ThemeMode.values.firstWhereOrNull((t) => - t.name.toLowerCase() == - widget.control.attrString("themeMode", "")!.toLowerCase()) ?? - FletAppContext.of(context)?.themeMode; - - _localeConfiguration = - parseLocaleConfiguration(widget.control, "localeConfiguration"); - - // keyboard handler - var onKeyboardEvent = widget.control.attrBool("onKeyboardEvent", false)!; - if (onKeyboardEvent && !_keyboardHandlerSubscribed) { - HardwareKeyboard.instance.addHandler(_handleKeyDown); - _keyboardHandlerSubscribed = true; - } - - // window params - var windowTitle = widget.control.attrString("title", "")!; - var windowBgcolor = widget.control.attrColor("windowBgcolor", context); - var windowWidth = widget.control.attrDouble("windowWidth"); - var windowHeight = widget.control.attrDouble("windowHeight"); - var windowMinWidth = widget.control.attrDouble("windowMinWidth"); - var windowMinHeight = widget.control.attrDouble("windowMinHeight"); - var windowMaxWidth = widget.control.attrDouble("windowMaxWidth"); - var windowMaxHeight = widget.control.attrDouble("windowMaxHeight"); - var windowTop = widget.control.attrDouble("windowTop"); - var windowLeft = widget.control.attrDouble("windowLeft"); - var windowCenter = widget.control.attrString("windowCenter"); - var windowClose = widget.control.attrString("windowClose"); - var windowFullScreen = widget.control.attrBool("windowFullScreen"); - var windowMinimized = widget.control.attrBool("windowMinimized"); - var windowMaximized = widget.control.attrBool("windowMaximized"); - var windowAlignment = parseAlignment(widget.control, "windowAlignment"); - var windowBadgeLabel = widget.control.attrString("windowBadgeLabel"); - var windowIcon = widget.control.attrString("windowIcon"); - var windowHasShadow = widget.control.attrBool("windowShadow"); - var windowOpacity = widget.control.attrDouble("windowOpacity"); - var windowMinimizable = widget.control.attrBool("windowMinimizable"); - var windowMaximizable = widget.control.attrBool("windowMaximizable"); - var windowAlwaysOnTop = widget.control.attrBool("windowAlwaysOnTop"); - var windowAlwaysOnBottom = widget.control.attrBool("windowAlwaysOnBottom"); - var windowResizable = widget.control.attrBool("windowResizable"); - var windowMovable = widget.control.attrBool("windowMovable"); - var windowPreventClose = widget.control.attrBool("windowPreventClose"); - var windowTitleBarHidden = widget.control.attrBool("windowTitleBarHidden"); - var windowTitleBarButtonsHidden = - widget.control.attrBool("windowTitleBarButtonsHidden", false)!; - var windowVisible = widget.control.attrBool("windowVisible"); - var windowFocused = widget.control.attrBool("windowFocused"); - var windowDestroy = widget.control.attrBool("windowDestroy"); - var windowWaitUntilReadyToShow = - widget.control.attrBool("windowWaitUntilReadyToShow"); - var windowSkipTaskBar = widget.control.attrBool("windowSkipTaskBar"); - var windowFrameless = widget.control.attrBool("windowFrameless"); - var windowProgressBar = widget.control.attrDouble("windowProgressBar"); - var windowIgnoreMouseEvents = - widget.control.attrBool("windowIgnoreMouseEvents"); - - updateWindow(PageArgsModel? pageArgs) async { - try { - // windowTitle - if (_windowTitle != windowTitle) { - setWindowTitle(windowTitle); - _windowTitle = windowTitle; - } + var themeMode = control.getThemeMode("theme_mode") ?? + PageContext.of(context)?.themeMode; - // windowBgcolor - if (_windowBgcolor != windowBgcolor && windowBgcolor != null) { - setWindowBackgroundColor(windowBgcolor); - _windowBgcolor = windowBgcolor; - } + var themeAnimationStyle = + control.getAnimationStyle("theme_animation_style"); - // window size - if ((windowWidth != null || windowHeight != null) && - (windowWidth != _windowWidth || windowHeight != _windowHeight) && - windowFullScreen != true && - (defaultTargetPlatform != TargetPlatform.macOS || - (defaultTargetPlatform == TargetPlatform.macOS && - windowMaximized != true && - windowMinimized != true))) { - debugPrint("setWindowSize: $windowWidth, $windowHeight"); - await setWindowSize(windowWidth, windowHeight); - _windowWidth = windowWidth; - _windowHeight = windowHeight; - } + var localeConfiguration = + control.getLocaleConfiguration("locale_configuration"); - // window min size - if ((windowMinWidth != null || windowMinHeight != null) && - (windowMinWidth != _windowMinWidth || - windowMinHeight != _windowMinHeight)) { - debugPrint("setWindowMinSize: $windowMinWidth, $windowMinHeight"); - await setWindowMinSize(windowMinWidth, windowMinHeight); - _windowMinWidth = windowMinWidth; - _windowMinHeight = windowMinHeight; - } + var localizationsDelegates = const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ]; - // window max size - if ((windowMaxWidth != null || windowMaxHeight != null) && - (windowMaxWidth != _windowMaxWidth || - windowMaxHeight != _windowMaxHeight)) { - debugPrint("setWindowMaxSize: $windowMaxWidth, $windowMaxHeight"); - await setWindowMaxSize(windowMaxWidth, windowMaxHeight); - _windowMaxWidth = windowMaxWidth; - _windowMaxHeight = windowMaxHeight; - } + var brightness = context.select( + (backend) => backend.platformBrightness); - // window position - if ((windowTop != null || windowLeft != null) && - (windowTop != _windowTop || windowLeft != _windowLeft) && - windowFullScreen != true && - (windowCenter == null || windowCenter == "") && - (defaultTargetPlatform != TargetPlatform.macOS || - (defaultTargetPlatform == TargetPlatform.macOS && - windowMaximized != true && - windowMinimized != true))) { - debugPrint("setWindowPosition: $windowTop, $windowLeft"); - await setWindowPosition(windowTop, windowLeft); - _windowTop = windowTop; - _windowLeft = windowLeft; - } + var windowTitle = control.getString("title", "")!; - // windowOpacity - if (windowOpacity != null && windowOpacity != _windowOpacity) { - await setWindowOpacity(windowOpacity); - _windowOpacity = windowOpacity; - } - - // windowMinimizable - if (windowMinimizable != null && - windowMinimizable != _windowMinimizable) { - await setWindowMinimizability(windowMinimizable); - _windowMinimizable = windowMinimizable; - } - - // windowMinimized - if (windowMinimized != _windowMinimized) { - if (windowMinimized == true) { - await minimizeWindow(); - } else if (windowMinimized == false && windowMaximized == false) { - await restoreWindow(); - } - _windowMinimized = windowMinimized; - } + var newLightTheme = control.getTheme("theme", context, Brightness.light); + var newDarkTheme = control.getString("dark_theme") == null + ? control.getTheme("theme", context, Brightness.dark) + : control.getTheme("dark_theme", context, Brightness.dark); - // windowMaximizable - if (windowMaximizable != null && - windowMaximizable != _windowMaximizable) { - await setWindowMaximizability(windowMaximizable); - _windowMaximizable = windowMaximizable; - } - - // windowMaximized - if (windowMaximized != _windowMaximized) { - if (windowMaximized == true) { - await maximizeWindow(); - } else if (windowMaximized == false) { - await unmaximizeWindow(); - } - _windowMaximized = windowMaximized; - } - - // windowAlignment - if (windowAlignment != null && windowAlignment != _windowAlignment) { - await setWindowAlignment(windowAlignment); - _windowAlignment = windowAlignment; - } - - // windowBadgeLabel - if (windowBadgeLabel != null && windowBadgeLabel != _windowBadgeLabel) { - await setWindowBadgeLabel(windowBadgeLabel); - _windowBadgeLabel = windowBadgeLabel; - } - - // windowIcon - if (windowIcon != null && windowIcon != _windowIcon) { - if (pageArgs == null) { - await setWindowIcon(windowIcon); - } else { - var iconAssetSrc = - getAssetSrc(windowIcon, pageArgs.pageUri!, pageArgs.assetsDir); - await setWindowIcon(iconAssetSrc.path); - } - _windowIcon = windowIcon; - } - - // windowHasShadow - if (windowHasShadow != null && windowHasShadow != _windowHasShadow) { - await setWindowShadow(windowHasShadow); - _windowHasShadow = windowHasShadow; - } - - // windowResizable - if (windowResizable != null && windowResizable != _windowResizable) { - await setWindowResizability(windowResizable); - _windowResizable = windowResizable; - } - - // windowMovable - if (windowMovable != null && windowMovable != _windowMovable) { - await setWindowMovability(windowMovable); - _windowMovable = windowMovable; - } - - // windowFullScreen - if (windowFullScreen != null && windowFullScreen != _windowFullScreen) { - await setWindowFullScreen(windowFullScreen); - _windowFullScreen = windowFullScreen; - } - - // windowAlwaysOnTop - if (windowAlwaysOnTop != null && - windowAlwaysOnTop != _windowAlwaysOnTop) { - await setWindowAlwaysOnTop(windowAlwaysOnTop); - _windowAlwaysOnTop = windowAlwaysOnTop; - } - - // windowAlwaysOnBottom - if (windowAlwaysOnBottom != null && - windowAlwaysOnBottom != _windowAlwaysOnBottom) { - await setWindowAlwaysOnBottom(windowAlwaysOnBottom); - _windowAlwaysOnBottom = windowAlwaysOnBottom; - } - - // windowPreventClose - if (windowPreventClose != null && - windowPreventClose != _windowPreventClose) { - await setWindowPreventClose(windowPreventClose); - _windowPreventClose = windowPreventClose; - } - - // windowTitleBarHidden - if (windowTitleBarHidden != null && - windowTitleBarHidden != _windowTitleBarHidden) { - await setWindowTitleBarVisibility( - windowTitleBarHidden, windowTitleBarButtonsHidden); - _windowTitleBarHidden = windowTitleBarHidden; - } - - // windowVisible - if (windowVisible != _windowVisible) { - if (windowVisible == true) { - await showWindow(); - } else if (windowVisible == false) { - await hideWindow(); - } - _windowVisible = windowVisible; - } - - // windowFocused - if (windowFocused != _windowFocused) { - if (windowFocused == true) { - await focusWindow(); - } else if (windowFocused == false) { - await blurWindow(); - } - _windowFocused = windowFocused; - } - - // windowCenter - if (windowCenter != _windowCenter && windowFullScreen != true) { - await centerWindow(); - _windowCenter = windowCenter; - } - - // windowFrameless - if (windowFrameless != _windowFrameless && windowFrameless == true) { - await setWindowFrameless(); - _windowFrameless = windowFrameless; - } - - // windowProgressBar - if (windowProgressBar != null && - windowProgressBar != _windowProgressBar) { - await setWindowProgressBar(windowProgressBar); - _windowProgressBar = windowProgressBar; - } - - // windowSkipTaskBar - if (windowSkipTaskBar != null && - windowSkipTaskBar != _windowSkipTaskBar) { - await setWindowSkipTaskBar(windowSkipTaskBar); - _windowSkipTaskBar = windowSkipTaskBar; - } - - // windowClose - if (windowClose != _windowClose) { - await closeWindow(); - _windowClose = windowClose; - } - - // windowDestroy - if (windowDestroy == true) { - await destroyWindow(); - } - - // window waitUntilReadyToShow - if (windowWaitUntilReadyToShow == true) { - await waitUntilReadyToShow(); - } + var lightTheme = control.get("_lightTheme"); + if (lightTheme == null || newLightTheme != lightTheme) { + control.updateProperties({"_lightTheme": newLightTheme}, python: false); + lightTheme = newLightTheme; + } - // windowIgnoreMouseEvents - if (windowIgnoreMouseEvents != null && - windowIgnoreMouseEvents != _windowIgnoreMouseEvents) { - await setIgnoreMouseEvents(windowIgnoreMouseEvents); - _windowIgnoreMouseEvents = windowIgnoreMouseEvents; - } - } catch (e) { - debugPrint("ERROR updating window: $e"); - } + var darkTheme = control.get("_darkTheme"); + if (darkTheme == null || newDarkTheme != darkTheme) { + control.updateProperties({"_darkTheme": newDarkTheme}, python: false); + darkTheme = newDarkTheme; } - return withPageArgs((context, pageArgs) { - updateWindow(pageArgs); - debugPrint("Page fonts build: ${widget.control.id}"); + var cupertinoTheme = themeMode == ThemeMode.light || + ((themeMode == null || themeMode == ThemeMode.system) && + brightness == Brightness.light) + ? control.getCupertinoTheme("theme", context, Brightness.light) + : control.getString("dark_theme") != null + ? control.getCupertinoTheme("dark_theme", context, Brightness.dark) + : control.getCupertinoTheme("theme", context, Brightness.dark); + + var materialTheme = themeMode == ThemeMode.dark || + ((themeMode == null || themeMode == ThemeMode.system) && + brightness == Brightness.dark) + ? darkTheme + : lightTheme; + + Widget scaffoldMessengerBuilder(BuildContext context, Widget? child) { + return Theme( + data: materialTheme ?? lightTheme ?? ThemeData(), + child: ScaffoldMessenger(child: child ?? const SizedBox.shrink())); + } - // load custom fonts - parseFonts(widget.control, "fonts").forEach((fontFamily, fontUrl) { - var assetSrc = - getAssetSrc(fontUrl, pageArgs.pageUri!, pageArgs.assetsDir); + var showSemanticsDebugger = + control.getBool("show_semantics_debugger", false)!; + + Widget? app = widgetsDesign == PageDesign.cupertino + ? home != null + ? CupertinoApp( + debugShowCheckedModeBanner: false, + showSemanticsDebugger: showSemanticsDebugger, + title: windowTitle, + theme: cupertinoTheme, + builder: scaffoldMessengerBuilder, + supportedLocales: localeConfiguration.supportedLocales, + locale: localeConfiguration.locale, + localizationsDelegates: localizationsDelegates, + home: home, + ) + : CupertinoApp.router( + debugShowCheckedModeBanner: false, + showSemanticsDebugger: showSemanticsDebugger, + routerDelegate: _routerDelegate, + routeInformationParser: _routeParser, + routeInformationProvider: _routeInformationProvider, + title: windowTitle, + theme: cupertinoTheme, + builder: scaffoldMessengerBuilder, + localizationsDelegates: localizationsDelegates, + supportedLocales: localeConfiguration.supportedLocales, + locale: localeConfiguration.locale, + ) + : home != null + ? MaterialApp( + debugShowCheckedModeBanner: false, + showSemanticsDebugger: showSemanticsDebugger, + title: windowTitle, + theme: lightTheme, + darkTheme: darkTheme, + themeMode: themeMode, + themeAnimationStyle: themeAnimationStyle, + supportedLocales: localeConfiguration.supportedLocales, + locale: localeConfiguration.locale, + localizationsDelegates: localizationsDelegates, + home: home, + ) + : MaterialApp.router( + debugShowCheckedModeBanner: false, + showSemanticsDebugger: showSemanticsDebugger, + routerDelegate: _routerDelegate, + routeInformationParser: _routeParser, + routeInformationProvider: _routeInformationProvider, + title: windowTitle, + theme: lightTheme, + darkTheme: darkTheme, + themeMode: themeMode, + themeAnimationStyle: themeAnimationStyle, + localizationsDelegates: localizationsDelegates, + supportedLocales: localeConfiguration.supportedLocales, + locale: localeConfiguration.locale, + ); - if (assetSrc.isFile) { - UserFonts.loadFontFromFile(fontFamily, assetSrc.path); - } else { - UserFonts.loadFontFromUrl(fontFamily, assetSrc.path); - } - }); + if (control.getBool("enable_screenshots") == true) { + app = RepaintBoundary(key: _rootKey, child: app); + } - return StoreConnector( - distinct: true, - converter: (store) => PageMediaViewModel.fromStore(store), - builder: (context, media) { - debugPrint("MaterialApp.router build: ${widget.control.id}"); - - _brightness = media.displayBrightness; - - return FletAppContext( - themeMode: _themeMode, - child: _widgetsDesign == PageDesign.cupertino - ? CupertinoApp.router( - debugShowCheckedModeBanner: false, - showSemanticsDebugger: widget.control - .attrBool("showSemanticsDebugger", false)!, - routerDelegate: _routerDelegate, - routeInformationParser: _routeParser, - title: windowTitle, - theme: _themeMode == ThemeMode.light || - ((_themeMode == null || - _themeMode == ThemeMode.system) && - _brightness == Brightness.light) - ? parseCupertinoTheme( - widget.control, "theme", Brightness.light) - : widget.control.attrString("darkTheme") != null - ? parseCupertinoTheme(widget.control, - "darkTheme", Brightness.dark) - : parseCupertinoTheme( - widget.control, "theme", Brightness.dark), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: _localeConfiguration != null - ? _localeConfiguration!["supportedLocales"] - : [const Locale('en', 'US')], - locale: _localeConfiguration != null - ? (_localeConfiguration?["locale"]) - : null, - ) - : MaterialApp.router( - debugShowCheckedModeBanner: false, - showSemanticsDebugger: widget.control - .attrBool("showSemanticsDebugger", false)!, - routerDelegate: _routerDelegate, - routeInformationParser: _routeParser, - title: windowTitle, - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: _localeConfiguration != null - ? _localeConfiguration!["supportedLocales"] - : [const Locale('en', 'US')], - locale: _localeConfiguration != null - ? (_localeConfiguration?["locale"]) - : null, - theme: parseTheme( - widget.control, "theme", Brightness.light), - darkTheme: widget.control.attrString("darkTheme") == - null - ? parseTheme( - widget.control, "theme", Brightness.dark) - : parseTheme( - widget.control, "darkTheme", Brightness.dark), - themeMode: _themeMode, - )); - }); - }); + return PageContext( + themeMode: themeMode, + brightness: brightness, + widgetsDesign: widgetsDesign, + child: app, + ); } Widget _buildNavigator( BuildContext context, GlobalKey navigatorKey) { debugPrint("Page navigator build: ${widget.control.id}"); - return StoreConnector( - distinct: true, - converter: (store) => RoutesViewModel.fromStore(store), - // onWillChange: (prev, next) { - // debugPrint("Page navigator.onWillChange(): $prev, $next"); - // }, - builder: (context, routesView) { - debugPrint("_buildNavigator build"); - - var showAppStartupScreen = - FletAppServices.of(context).showAppStartupScreen ?? false; - var appStartupScreenMessage = - FletAppServices.of(context).appStartupScreenMessage ?? ""; - - List> pages = []; - if (routesView.views.isEmpty) { - pages.add(AnimatedTransitionPage( + var backend = FletBackend.of(context); + var showAppStartupScreen = backend.showAppStartupScreen ?? false; + var appStartupScreenMessage = backend.appStartupScreenMessage ?? ""; + + var appStatus = + context.select( + (backend) => (isLoading: backend.isLoading, error: backend.error)); + var formattedErrorMessage = backend.formatAppErrorMessage(appStatus.error); + + var views = widget.control.children("views"); + final viewRouteValues = views + .map((v) => v.getString("route", v.id.toString())) + .whereType() + .toSet(); + _pendingPoppedViewRoutes + .removeWhere((route) => !viewRouteValues.contains(route)); + _sentViewPopEventsForRoutes + .removeWhere((route) => !viewRouteValues.contains(route)); + + final effectiveViews = _pendingPoppedViewRoutes.isEmpty + ? views + : views + .where((v) => !_pendingPoppedViewRoutes + .contains(v.getString("route", v.id.toString()))) + .toList(); + + List> pages = []; + if (effectiveViews.isEmpty) { + pages.add(AnimatedTransitionPage( + fadeTransition: true, + duration: Duration.zero, + child: showAppStartupScreen + ? Stack(children: [ + const PageMedia(), + LoadingPage( + isLoading: appStatus.isLoading, + message: appStatus.isLoading + ? appStartupScreenMessage + : formattedErrorMessage, + ) + ]) + : const Scaffold( + body: PageMedia(), + ))); + } else { + String viewRoutes = effectiveViews + .map((v) => v.getString("route", v.id.toString())) + .join(); + + pages = effectiveViews.map((view) { + var key = ValueKey(view.getString("route", view.id.toString())); + var child = ControlWidget(control: view); + + //debugPrint("ROUTES: $_prevViewRoutes $viewRoutes"); + + return _prevViewRoutes == null + ? AnimatedTransitionPage( + key: key, + child: child, fadeTransition: true, duration: Duration.zero, - child: showAppStartupScreen - ? Stack(children: [ - const PageMedia(), - LoadingPage( - isLoading: routesView.isLoading, - message: routesView.isLoading - ? appStartupScreenMessage - : routesView.error, - ) - ]) - : const Scaffold( - body: PageMedia(), - ))); - } else { - Widget? loadingPage; - // offstage - overlayWidgets(String viewId) { - List overlayWidgets = []; - - if (viewId == routesView.views.last.id) { - overlayWidgets.addAll(routesView.offstageControls - .where((c) => !c.isNonVisual) - .map((c) => createControl( - routesView.page, c.id, routesView.page.isDisabled, - parentAdaptive: _adaptive))); - overlayWidgets.add(const PageMedia()); - } - - if (viewId == routesView.views.first.id && isDesktopPlatform()) { - overlayWidgets.add(WindowMedia(dispatch: widget.dispatch)); - } - - return overlayWidgets; - } - - if ((routesView.isLoading || routesView.error != "") && - showAppStartupScreen) { - loadingPage = LoadingPage( - isLoading: routesView.isLoading, - message: routesView.isLoading - ? appStartupScreenMessage - : routesView.error, - ); - } - - String viewRoutes = routesView.views - .map((v) => v.attrString("route") ?? v.id) - .join(); - - pages = routesView.views.map((view) { - var key = ValueKey(view.attrString("route") ?? view.id); - var child = ViewControl( - parent: routesView.page, - viewId: view.id, - overlayWidgets: overlayWidgets(view.id), - loadingPage: loadingPage, - backend: widget.backend, - parentAdaptive: _adaptive, - widgetsDesign: _widgetsDesign, - brightness: _brightness, - themeMode: _themeMode, - isRootView: view.id == routesView.views.first.id, - ); - - //debugPrint("ROUTES: $_prevViewRoutes $viewRoutes"); - - return _prevViewRoutes == null - ? AnimatedTransitionPage( - key: key, - child: child, - fadeTransition: true, - duration: Duration.zero, - ) - : AnimatedTransitionPage( - key: key, - child: child, - fullscreenDialog: - view.attrBool("fullscreenDialog", false)!); - }).toList(); - - _prevViewRoutes = viewRoutes; - } - - Widget nextChild = Navigator( - key: navigatorKey, - pages: pages, - onDidRemovePage: (page) { - if (page.key != null) { - widget.backend.triggerControlEvent( - "page", "view_pop", (page.key as ValueKey).value); - } - }); - - // wrap navigator into non-visual offstage controls - for (var c - in routesView.offstageControls.where((c) => c.isNonVisual)) { - nextChild = createControl( - routesView.page, c.id, routesView.page.isDisabled, - parentAdaptive: _adaptive, nextChild: nextChild); - } - - return nextChild; - }); - } -} - -class ViewControl extends StatefulWidget { - final Control parent; - final String viewId; - final List overlayWidgets; - final Widget? loadingPage; - final FletControlBackend backend; - final bool? parentAdaptive; - final PageDesign widgetsDesign; - final Brightness? brightness; - final ThemeMode? themeMode; - final bool isRootView; - - ViewControl( - {Key? key, - required this.parent, - required this.viewId, - required this.overlayWidgets, - required this.loadingPage, - required this.backend, - required this.parentAdaptive, - required this.widgetsDesign, - required this.brightness, - required this.themeMode, - required this.isRootView}) - : super(key: ValueKey("control_$viewId")); - - @override - State createState() => _ViewControlState(); -} - -class _ViewControlState extends State with FletStoreMixin { - final scaffoldKey = GlobalKey(); - Completer? _popCompleter; - - @override - Widget build(BuildContext context) { - return StoreConnector( - distinct: true, - converter: (store) { - return ControlViewModel.fromStore(store, widget.viewId); - }, - ignoreChange: (state) { - return state.controls[widget.viewId] == null; - }, - // onWillChange: (prev, next) { - // debugPrint("View StoreConnector.onWillChange(): $prev, $next"); - // }, - builder: (context, controlView) { - debugPrint("View build"); - - if (controlView == null) { - return const SizedBox.shrink(); - } - - var control = controlView.control; - var children = controlView.children; - - var adaptive = control.attrBool("adaptive") ?? widget.parentAdaptive; - - final spacing = control.attrDouble("spacing", 10)!; - final mainAlignment = parseMainAxisAlignment( - control.attrString("verticalAlignment"), - MainAxisAlignment.start)!; - final crossAlignment = parseCrossAxisAlignment( - control.attrString("horizontalAlignment"), - CrossAxisAlignment.start)!; - final fabLocation = parseFloatingActionButtonLocation( - control, "floatingActionButtonLocation"); - final canPop = control.attrBool("canPop", true)!; - - widget.backend.subscribeMethods(control.id, (methodName, args) async { - debugPrint("View.onMethod(${control.id})"); - if (methodName == "confirm_pop") { - _popCompleter?.complete(bool.tryParse(args["shouldPop"] ?? "")); - widget.backend.unsubscribeMethods(control.id); - } - return null; - }); - - Control? appBar; - Control? cupertinoAppBar; - Control? bottomAppBar; - Control? fab; - Control? navBar; - Control? drawer; - Control? endDrawer; - List controls = []; - bool firstControl = true; - - for (var ctrl in children.where((c) => c.isVisible)) { - if (ctrl.type == "appbar") { - appBar = ctrl; - continue; - } else if (ctrl.type == "cupertinoappbar") { - cupertinoAppBar = ctrl; - continue; - } else if (ctrl.type == "bottomappbar") { - bottomAppBar = ctrl; - continue; - } else if (ctrl.name == "fab") { - fab = ctrl; - continue; - } else if (ctrl.type == "navigationbar" || - ctrl.type == "cupertinonavigationbar") { - navBar = ctrl; - continue; - } else if (ctrl.type == "navigationdrawer" && - ctrl.name == "drawer_start") { - drawer = ctrl; - continue; - } else if (ctrl.type == "navigationdrawer" && - ctrl.name == "drawer_end") { - endDrawer = ctrl; - continue; - } - // spacer between displayed controls - else if (spacing > 0 && - !firstControl && - mainAlignment != MainAxisAlignment.spaceAround && - mainAlignment != MainAxisAlignment.spaceBetween && - mainAlignment != MainAxisAlignment.spaceEvenly) { - controls.add(SizedBox(height: spacing)); - } - firstControl = false; - - // displayed control - controls.add(createControl(control, ctrl.id, control.isDisabled, - parentAdaptive: adaptive)); - } - - List childIds = [ - appBar?.id, - cupertinoAppBar?.id, - drawer?.id, - endDrawer?.id - ].nonNulls.toList(); - - final textDirection = widget.parent.attrBool("rtl", false)! - ? TextDirection.rtl - : TextDirection.ltr; - - return withControls(childIds, (context, childrenViews) { - debugPrint("Route view build: ${widget.viewId}"); - - var appBarView = childrenViews.controlViews - .firstWhereOrNull((v) => v.control.id == (appBar?.id ?? "")); - var cupertinoAppBarView = childrenViews.controlViews - .firstWhereOrNull( - (v) => v.control.id == (cupertinoAppBar?.id ?? "")); - var drawerView = childrenViews.controlViews - .firstWhereOrNull((v) => v.control.id == (drawer?.id ?? "")); - var endDrawerView = childrenViews.controlViews - .firstWhereOrNull((v) => v.control.id == (endDrawer?.id ?? "")); - - var column = Column( - mainAxisAlignment: mainAlignment, - crossAxisAlignment: crossAlignment, - children: controls); - - Widget child = ScrollableControl( - control: control, - scrollDirection: Axis.vertical, - backend: widget.backend, - parentAdaptive: adaptive, - child: column); - - if (control.attrBool("onScroll", false)!) { - child = ScrollNotificationControl( - control: control, backend: widget.backend, child: child); - } - - final bool? drawerOpened = widget.parent.state["drawerOpened"]; - final bool? endDrawerOpened = - widget.parent.state["endDrawerOpened"]; - - void dismissDrawer(String id) { - widget.backend.updateControlState(id, {"open": "false"}); - widget.backend.triggerControlEvent(id, "dismiss"); - } + ) + : AnimatedTransitionPage( + key: key, + child: child, + fullscreenDialog: view.getBool("fullscreen_dialog", false)!); + }).toList(); + + _prevViewRoutes = viewRoutes; + } - WidgetsBinding.instance.addPostFrameCallback((_) { - if (drawerView != null) { - if (scaffoldKey.currentState?.isDrawerOpen == false && - drawerOpened == true) { - widget.parent.state["drawerOpened"] = false; - dismissDrawer(drawerView.control.id); - } - if (drawerView.control.attrBool("open", false)! && - drawerOpened != true) { - if (scaffoldKey.currentState?.isEndDrawerOpen == true) { - scaffoldKey.currentState?.closeEndDrawer(); - } - Future.delayed(const Duration(milliseconds: 1)).then((value) { - scaffoldKey.currentState?.openDrawer(); - widget.parent.state["drawerOpened"] = true; - }); - } else if (!drawerView.control.attrBool("open", false)! && - drawerOpened == true) { - scaffoldKey.currentState?.closeDrawer(); - widget.parent.state["drawerOpened"] = false; - } - } - if (endDrawerView != null) { - if (scaffoldKey.currentState?.isEndDrawerOpen == false && - endDrawerOpened == true) { - widget.parent.state["endDrawerOpened"] = false; - dismissDrawer(endDrawerView.control.id); - } - if (endDrawerView.control.attrBool("open", false)! && - endDrawerOpened != true) { - if (scaffoldKey.currentState?.isDrawerOpen == true) { - scaffoldKey.currentState?.closeDrawer(); - } - Future.delayed(const Duration(milliseconds: 1)).then((value) { - scaffoldKey.currentState?.openEndDrawer(); - widget.parent.state["endDrawerOpened"] = true; - }); - } else if (!endDrawerView.control.attrBool("open", false)! && - endDrawerOpened == true) { - scaffoldKey.currentState?.closeEndDrawer(); - widget.parent.state["endDrawerOpened"] = false; - } - } - }); - - var bnb = navBar ?? bottomAppBar; - - var bar = appBarView != null - ? widget.widgetsDesign == PageDesign.cupertino - ? CupertinoAppBarControl( - parent: control, - control: appBarView.control, - children: appBarView.children, - parentDisabled: control.isDisabled, - parentAdaptive: adaptive) - : AppBarControl( - parent: control, - control: appBarView.control, - children: appBarView.children, - parentDisabled: control.isDisabled, - parentAdaptive: adaptive, - height: appBarView.control - .attrDouble("toolbarHeight", kToolbarHeight)!) - : cupertinoAppBarView != null - ? CupertinoAppBarControl( - parent: control, - control: cupertinoAppBarView.control, - children: cupertinoAppBarView.children, - parentDisabled: control.isDisabled, - parentAdaptive: adaptive, - ) as ObstructingPreferredSizeWidget - : null; - - Widget body = Stack(children: [ - SizedBox.expand( - child: Container( - padding: parseEdgeInsets( - control, "padding", const EdgeInsets.all(10))!, - child: child)), - ...widget.overlayWidgets - ]); - - var materialTheme = widget.themeMode == ThemeMode.light || - ((widget.themeMode == null || - widget.themeMode == ThemeMode.system) && - widget.brightness == Brightness.light) - ? parseTheme(widget.parent, "theme", Brightness.light) - : widget.parent.attrString("darkTheme") != null - ? parseTheme(widget.parent, "darkTheme", Brightness.dark) - : parseTheme(widget.parent, "theme", Brightness.dark); - - Widget scaffold = Scaffold( - key: bar == null || bar is AppBarControl ? scaffoldKey : null, - backgroundColor: control.attrColor("bgcolor", context) ?? - CupertinoTheme.of(context).scaffoldBackgroundColor, - appBar: bar is AppBarControl ? bar : null, - drawer: drawerView != null - ? NavigationDrawerControl( - control: drawerView.control, - children: drawerView.children, - parentDisabled: control.isDisabled, - parentAdaptive: adaptive, - backend: widget.backend) - : null, - onDrawerChanged: (opened) { - if (drawerView != null && !opened) { - widget.parent.state["drawerOpened"] = false; - dismissDrawer(drawerView.control.id); - } - }, - endDrawer: endDrawerView != null - ? NavigationDrawerControl( - control: endDrawerView.control, - children: endDrawerView.children, - parentDisabled: control.isDisabled, - parentAdaptive: adaptive, - backend: widget.backend) - : null, - onEndDrawerChanged: (opened) { - if (endDrawerView != null && !opened) { - widget.parent.state["endDrawerOpened"] = false; - dismissDrawer(endDrawerView.control.id); - } - }, - body: body, - bottomNavigationBar: bnb != null - ? createControl(control, bnb.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - floatingActionButton: fab != null - ? createControl(control, fab.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - floatingActionButtonLocation: fabLocation, - ); - - var systemOverlayStyle = - materialTheme.extension(); - - if (systemOverlayStyle != null && - systemOverlayStyle.systemUiOverlayStyle != null && - bar == null) { - scaffold = AnnotatedRegion( - value: systemOverlayStyle.systemUiOverlayStyle!, - child: scaffold, - ); - } + return Navigator( + key: navigatorKey, + pages: pages, + onDidRemovePage: (page) { + if (pages.length <= 1) { + return; + } - if (bar is CupertinoAppBarControl) { - scaffold = CupertinoPageScaffold( - key: scaffoldKey, - backgroundColor: control.attrColor("bgcolor", context), - navigationBar: bar as ObstructingPreferredSizeWidget, - child: scaffold); - } + final pageKey = page.key; + final routeValue = pageKey is ValueKey ? pageKey.value : null; + if (routeValue == null) { + return; + } - if (widget.widgetsDesign == PageDesign.material) { - scaffold = CupertinoTheme( - data: widget.themeMode == ThemeMode.light || - ((widget.themeMode == null || - widget.themeMode == ThemeMode.system) && - widget.brightness == Brightness.light) - ? parseCupertinoTheme( - widget.parent, "theme", Brightness.light) - : widget.parent.attrString("darkTheme") != null - ? parseCupertinoTheme( - widget.parent, "darkTheme", Brightness.dark) - : parseCupertinoTheme( - widget.parent, "theme", Brightness.dark), - child: scaffold, - ); - } else if (widget.widgetsDesign == PageDesign.cupertino) { - scaffold = Theme( - data: materialTheme, - child: scaffold, - ); - } - Widget result = Directionality( - textDirection: textDirection, - child: widget.loadingPage != null - ? Stack( - children: [scaffold, widget.loadingPage!], - ) - : scaffold); - - result = PopScope( - canPop: canPop, - onPopInvokedWithResult: (didPop, result) { - if (didPop || !control.attrBool("onConfirmPop", false)!) { - return; - } - debugPrint("Page.onPopInvokedWithResult()"); - _popCompleter = Completer(); - widget.backend - .triggerControlEvent(widget.viewId, "confirm_pop"); - _popCompleter!.future - .timeout( - const Duration(minutes: 5), - onTimeout: () => false, - ) - .then((shouldPop) { - if (context.mounted && shouldPop) { - if (widget.isRootView) { - SystemNavigator.pop(); - } else { - Navigator.pop(context); - } - } - }); - }, - child: result); - - return withPageArgs((context, pageArgs) { - var backgroundDecoration = parseBoxDecoration( - Theme.of(context), control, "decoration", pageArgs); - var foregroundDecoration = parseBoxDecoration( - Theme.of(context), control, "foregroundDecoration", pageArgs); - if (backgroundDecoration != null || - foregroundDecoration != null) { - return Container( - decoration: backgroundDecoration, - foregroundDecoration: foregroundDecoration, - child: result, - ); - } - return result; - }); - }); - }); + final routeStr = routeValue.toString(); + _markViewAsPopped(routeStr); + }, + ); } } diff --git a/packages/flet/lib/src/controls/page_view.dart b/packages/flet/lib/src/controls/page_view.dart new file mode 100644 index 0000000000..1418b655c4 --- /dev/null +++ b/packages/flet/lib/src/controls/page_view.dart @@ -0,0 +1,181 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/animations.dart'; +import '../utils/layout.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; + +class PageViewControl extends StatefulWidget { + final Control control; + + PageViewControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _PageViewControlState(); +} + +class _PageViewControlState extends State { + late PageController _pageController; + late bool _keepPage; + late double _viewportFraction; + late int _selectedIndex; + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + _readControllerConfig(); + _pageController = _createController(initialPage: _selectedIndex); + } + + @override + void didUpdateWidget(PageViewControl oldWidget) { + super.didUpdateWidget(oldWidget); + + final newKeepPage = widget.control.getBool("keep_page", true)!; + final newViewportFraction = + widget.control.getDouble("viewport_fraction", 1.0)!; + final newSelectedIndex = widget.control.getInt("selected_index", 0)!; + + final requiresRebuild = + newKeepPage != _keepPage || newViewportFraction != _viewportFraction; + + if (requiresRebuild) { + _keepPage = newKeepPage; + _viewportFraction = newViewportFraction; + _selectedIndex = newSelectedIndex; + + final oldController = _pageController; + _pageController = _createController(initialPage: _selectedIndex); + oldController.dispose(); + } else if (newSelectedIndex != _selectedIndex && + _pageController.hasClients) { + _selectedIndex = newSelectedIndex; + _pageController.jumpToPage(newSelectedIndex); + } + } + + void _readControllerConfig() { + _keepPage = widget.control.getBool("keep_page", true)!; + _viewportFraction = widget.control.getDouble("viewport_fraction", 1.0)!; + _selectedIndex = widget.control.getInt("selected_index", 0)!; + } + + PageController _createController({required int initialPage}) { + return PageController( + initialPage: initialPage, + keepPage: _keepPage, + viewportFraction: _viewportFraction, + ); + } + + Future _invokeMethod(String name, dynamic args) async { + final defaultAnimationDuration = widget.control + .getDuration("animation_duration", const Duration(seconds: 1))!; + final defaultAnimationCurve = + widget.control.getCurve("animation_curve", Curves.linear)!; + + switch (name) { + case "go_to_page": + final index = parseInt(args["index"]); + if (index != null) { + await _pageController.animateToPage( + index, + duration: + parseDuration(args["duration"], defaultAnimationDuration)!, + curve: parseCurve(args["curve"], defaultAnimationCurve)!, + ); + } + break; + case "jump_to_page": + final index = parseInt(args["index"]); + if (index != null) { + _pageController.jumpToPage(index); + } + break; + case "jump_to": + final value = parseDouble(args["value"]); + if (value != null) { + _pageController.jumpTo(value); + } + break; + case "next_page": + await _pageController.nextPage( + duration: parseDuration(args["duration"], defaultAnimationDuration)!, + curve: parseCurve(args["curve"], defaultAnimationCurve)!, + ); + break; + case "previous_page": + await _pageController.previousPage( + duration: parseDuration(args["duration"], defaultAnimationDuration)!, + curve: parseCurve(args["curve"], defaultAnimationCurve)!, + ); + break; + default: + throw Exception("Unknown PageView method: $name"); + } + } + + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + _pageController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("PageViewControl build: ${widget.control.id}"); + + final horizontal = widget.control.getBool("horizontal", true)!; + final pageView = PageView( + controller: _pageController, + scrollDirection: horizontal ? Axis.horizontal : Axis.vertical, + reverse: widget.control.getBool("reverse", false)!, + clipBehavior: + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!, + padEnds: widget.control.getBool("pad_ends", true)!, + allowImplicitScrolling: + widget.control.getBool("implicit_scrolling", false)!, + pageSnapping: widget.control.getBool("snap", true)!, + onPageChanged: (int index) { + _selectedIndex = index; + widget.control.updateProperties({"selected_index": index}); + widget.control.triggerEvent("change", index); + }, + children: widget.control.buildWidgets("controls"), + ); + + Widget layoutChild = + LayoutControl(control: widget.control, child: pageView); + + if (widget.control.getExpand("expand", 0)! > 0) return layoutChild; + + return LayoutBuilder( + builder: (context, constraints) { + final unbounded = horizontal + ? (constraints.maxHeight == double.infinity && + widget.control.getDouble("height") == null) + : (constraints.maxWidth == double.infinity && + widget.control.getDouble("width") == null); + + if (unbounded) { + return ErrorControl( + "Error displaying PageView: ${horizontal ? "height" : "width"} is unbounded.", + description: + "Set a fixed ${horizontal ? "height" : "width"}, a non-zero expand," + " or place it inside a control with bounded ${horizontal ? "height" : "width"}.", + ); + } + + return layoutChild; + }, + ); + } +} diff --git a/packages/flet/lib/src/controls/pagelet.dart b/packages/flet/lib/src/controls/pagelet.dart index 52ca315539..4f6947a39c 100644 --- a/packages/flet/lib/src/controls/pagelet.dart +++ b/packages/flet/lib/src/controls/pagelet.dart @@ -1,268 +1,160 @@ -import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../models/controls_view_model.dart'; +import '../models/page_design.dart'; import '../utils/buttons.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import '../utils/platform.dart'; +import '../widgets/error.dart'; import 'app_bar.dart'; -import 'create_control.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; import 'cupertino_app_bar.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; -import 'navigation_drawer.dart'; -import 'page.dart'; class PageletControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const PageletControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + PageletControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _PageletControlState(); } -class _PageletControlState extends State with FletStoreMixin { - final scaffoldKey = GlobalKey(); +class _PageletControlState extends State { + final _materialScaffoldKey = GlobalKey(); + final _cupertinoPageScaffoldKey = GlobalKey(); @override - Widget build(BuildContext context) { - debugPrint("Pagelet build: ${widget.control.id}"); + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } - var appBarCtrls = - widget.children.where((c) => c.name == "appbar" && c.isVisible); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - var navigationBarCtrls = - widget.children.where((c) => c.name == "navigationbar" && c.isVisible); - var bottomAppBarCtrls = - widget.children.where((c) => c.name == "bottomappbar" && c.isVisible); - var bottomSheetCtrls = - widget.children.where((c) => c.name == "bottomsheet" && c.isVisible); - var drawerCtrls = - widget.children.where((c) => c.name == "drawer" && c.isVisible); - var endDrawerCtrls = - widget.children.where((c) => c.name == "enddrawer" && c.isVisible); - var fabCtrls = widget.children - .where((c) => c.name == "floatingactionbutton" && c.isVisible); + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } - if (contentCtrls.isEmpty) { - return const ErrorControl("Pagelet.content must be provided and visible"); + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Pagelet.$name($args)"); + switch (name) { + case "show_drawer": + _materialScaffoldKey.currentState?.openDrawer(); + break; + case "close_drawer": + _materialScaffoldKey.currentState?.closeDrawer(); + break; + case "show_end_drawer": + _materialScaffoldKey.currentState?.openEndDrawer(); + break; + case "close_end_drawer": + _materialScaffoldKey.currentState?.closeEndDrawer(); + break; + default: + throw Exception("Unknown Pagelet method: $name"); } + } - return withPagePlatform((context, platform) { - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - - var widgetsDesign = adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS) - ? PageDesign.cupertino - : PageDesign.material; - - List childIds = [ - appBarCtrls.firstOrNull?.id, - drawerCtrls.firstOrNull?.id, - endDrawerCtrls.firstOrNull?.id - ].nonNulls.toList(); - - return StoreConnector( - distinct: true, - converter: (store) => ControlsViewModel.fromStore(store, childIds), - ignoreChange: (state) { - //debugPrint("ignoreChange: $id"); - for (var id in childIds) { - if (state.controls[id] == null) { - return true; - } - } - return false; - }, - builder: (context, childrenViews) { - var navBar = navigationBarCtrls.isNotEmpty - ? createControl( - widget.control, navigationBarCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null; - var bottomAppBar = bottomAppBarCtrls.isNotEmpty - ? createControl( - widget.control, bottomAppBarCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null; - var bnb = navBar ?? bottomAppBar; + @override + Widget build(BuildContext context) { + debugPrint("Pagelet build: ${widget.control.id}"); - var appBarView = childrenViews.controlViews.firstWhereOrNull( - (v) => v.control.id == (appBarCtrls.firstOrNull?.id ?? "")); + var appBar = widget.control.child("appbar"); + var content = widget.control.buildWidget("content"); + var navigationBar = widget.control.buildWidget("navigation_bar"); + var bottomAppBar = widget.control.buildWidget("bottom_appbar"); + var bottomSheet = widget.control.buildWidget("bottom_sheet"); + var drawer = widget.control.child("drawer"); + var endDrawer = widget.control.child("end_drawer"); + var hasDrawer = drawer != null || endDrawer != null; + var fab = widget.control.buildWidget("floating_action_button"); + + if (content == null) { + return const ErrorControl("Pagelet.content must be provided and visible"); + } - var drawerView = childrenViews.controlViews.firstWhereOrNull( - (v) => v.control.id == (drawerCtrls.firstOrNull?.id ?? "")); - var endDrawerView = childrenViews.controlViews.firstWhereOrNull( - (v) => v.control.id == (endDrawerCtrls.firstOrNull?.id ?? "")); + var widgetsDesign = widget.control.adaptive == true && isApplePlatform() + ? PageDesign.cupertino + : PageDesign.material; - final bool? drawerOpened = widget.control.state["drawerOpened"]; - final bool? endDrawerOpened = - widget.control.state["endDrawerOpened"]; + var bnb = navigationBar ?? bottomAppBar; - final fabLocation = parseFloatingActionButtonLocation( - widget.control, - "floatingActionButtonLocation", - FloatingActionButtonLocation.endFloat); + void dismissDrawer(int id) { + widget.control.backend.triggerControlEventById(id, "dismiss"); + } - void dismissDrawer(String id) { - widget.backend.updateControlState(id, {"open": "false"}); - widget.backend.triggerControlEvent(id, "dismiss"); - } + var bar = appBar != null + ? appBar.type == "AppBar" + ? widgetsDesign == PageDesign.cupertino + ? CupertinoAppBarControl(control: appBar) + : AppBarControl(control: appBar) + : appBar.type == "CupertinoAppBar" + ? CupertinoAppBarControl(control: appBar) + as ObstructingPreferredSizeWidget + : null + : null; + + Widget scaffold = Scaffold( + key: _materialScaffoldKey, + backgroundColor: widget.control.getColor("bgcolor", context) ?? + CupertinoTheme.of(context).scaffoldBackgroundColor, + appBar: bar is AppBarControl ? bar : null, + drawer: drawer != null ? ControlWidget(control: drawer) : null, + onDrawerChanged: (opened) { + if (drawer != null && !opened) { + dismissDrawer(drawer.id); + } + }, + endDrawer: endDrawer != null ? ControlWidget(control: endDrawer) : null, + onEndDrawerChanged: (opened) { + if (endDrawer != null && !opened) { + dismissDrawer(endDrawer.id); + } + }, + body: content, + bottomNavigationBar: bnb, + bottomSheet: bottomSheet, + floatingActionButton: fab, + floatingActionButtonLocation: widget.control + .getFloatingActionButtonLocation("floating_action_button_location", + FloatingActionButtonLocation.endFloat)); + + if (hasDrawer) { + // Clip to page bounds so the drawer animation stays hidden outside the pagelet. + scaffold = ClipRect(child: scaffold); + } - WidgetsBinding.instance.addPostFrameCallback((_) { - if (drawerView != null) { - if (scaffoldKey.currentState?.isDrawerOpen == false && - drawerOpened == true) { - widget.control.state["drawerOpened"] = false; - dismissDrawer(drawerView.control.id); - } - if (drawerView.control.attrBool("open", false)! && - drawerOpened != true) { - if (scaffoldKey.currentState?.isEndDrawerOpen == true) { - scaffoldKey.currentState?.closeEndDrawer(); - } - Future.delayed(const Duration(milliseconds: 1)).then((value) { - scaffoldKey.currentState?.openDrawer(); - widget.control.state["drawerOpened"] = true; - }); - } else if (!drawerView.control.attrBool("open", false)! && - drawerOpened == true) { - scaffoldKey.currentState?.closeDrawer(); - widget.control.state["drawerOpened"] = false; - } - } - if (endDrawerView != null) { - if (scaffoldKey.currentState?.isEndDrawerOpen == false && - endDrawerOpened == true) { - widget.control.state["endDrawerOpened"] = false; - dismissDrawer(endDrawerView.control.id); - } - if (endDrawerView.control.attrBool("open", false)! && - endDrawerOpened != true) { - if (scaffoldKey.currentState?.isDrawerOpen == true) { - scaffoldKey.currentState?.closeDrawer(); - } - Future.delayed(const Duration(milliseconds: 1)).then((value) { - scaffoldKey.currentState?.openEndDrawer(); - widget.control.state["endDrawerOpened"] = true; - }); - } else if (!endDrawerView.control.attrBool("open", false)! && - endDrawerOpened == true) { - scaffoldKey.currentState?.closeEndDrawer(); - widget.control.state["endDrawerOpened"] = false; - } - } - }); + if (bar is CupertinoAppBarControl) { + scaffold = CupertinoPageScaffold( + key: _cupertinoPageScaffoldKey, + backgroundColor: widget.control.getColor("bgcolor", context), + navigationBar: bar as ObstructingPreferredSizeWidget, + child: scaffold); + } - var bar = appBarView != null - ? appBarView.control.type == "appbar" - ? widgetsDesign == PageDesign.cupertino - ? CupertinoAppBarControl( - parent: widget.control, - control: appBarView.control, - children: appBarView.children, - parentDisabled: widget.control.isDisabled, - parentAdaptive: adaptive) - : AppBarControl( - parent: widget.control, - control: appBarView.control, - children: appBarView.children, - parentDisabled: widget.control.isDisabled, - parentAdaptive: adaptive, - height: appBarView.control - .attrDouble("toolbarHeight", kToolbarHeight)!) - : appBarView.control.type == "cupertinoappbar" - ? CupertinoAppBarControl( - parent: widget.control, - control: appBarView.control, - children: appBarView.children, - parentDisabled: widget.control.isDisabled, - parentAdaptive: adaptive, - ) as ObstructingPreferredSizeWidget - : null - : null; + final scaffoldWithBoundsCheck = scaffold; - Widget scaffold = Scaffold( - key: bar == null || bar is AppBarControl ? scaffoldKey : null, - backgroundColor: widget.control.attrColor("bgcolor", context) ?? - CupertinoTheme.of(context).scaffoldBackgroundColor, - appBar: bar is AppBarControl ? bar : null, - drawer: drawerView != null - ? NavigationDrawerControl( - control: drawerView.control, - children: drawerView.children, - parentDisabled: widget.control.isDisabled, - parentAdaptive: adaptive, - backend: widget.backend) - : null, - onDrawerChanged: (opened) { - if (drawerView != null && !opened) { - widget.control.state["drawerOpened"] = false; - dismissDrawer(drawerView.control.id); - } - }, - endDrawer: endDrawerView != null - ? NavigationDrawerControl( - control: endDrawerView.control, - children: endDrawerView.children, - parentDisabled: widget.control.isDisabled, - parentAdaptive: adaptive, - backend: widget.backend) - : null, - onEndDrawerChanged: (opened) { - if (endDrawerView != null && !opened) { - widget.control.state["endDrawerOpened"] = false; - dismissDrawer(endDrawerView.control.id); - } - }, - body: contentCtrls.isNotEmpty - ? createControl( - widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - bottomNavigationBar: bnb, - bottomSheet: bottomSheetCtrls.isNotEmpty - ? createControl( - widget.control, bottomSheetCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - floatingActionButton: fabCtrls.isNotEmpty - ? createControl(widget.control, fabCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null, - floatingActionButtonLocation: fabLocation); + scaffold = LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + debugPrint("Pagelet constraints.maxWidth: ${constraints.maxWidth}"); + debugPrint("Pagelet constraints.maxHeight: ${constraints.maxHeight}"); - if (bar is CupertinoAppBarControl) { - scaffold = CupertinoPageScaffold( - key: scaffoldKey, - backgroundColor: widget.control.attrColor("bgcolor", context), - navigationBar: bar as ObstructingPreferredSizeWidget, - child: scaffold); - } + if (constraints.maxHeight == double.infinity && + widget.control.getDouble("height") == null) { + return const ErrorControl( + "Error displaying Pagelet: height is unbounded.", + description: + "Either set a fixed \"height\" or nest Pagelet inside expanded control or control with a fixed height."); + } - return constrainedControl( - context, scaffold, widget.parent, widget.control); - }); + return scaffoldWithBoundsCheck; }); + + return LayoutControl(control: widget.control, child: scaffold); } } diff --git a/packages/flet/lib/src/controls/piechart.dart b/packages/flet/lib/src/controls/piechart.dart deleted file mode 100644 index e25a3b4411..0000000000 --- a/packages/flet/lib/src/controls/piechart.dart +++ /dev/null @@ -1,211 +0,0 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import 'package:redux/redux.dart'; - -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; -import '../models/control.dart'; -import '../utils/animations.dart'; -import '../utils/borders.dart'; -import '../utils/text.dart'; -import 'create_control.dart'; - -const eventMap = { - "FlPointerEnterEvent": "pointerEnter", - "FlPointerExitEvent": "pointerExit", - "FlPointerHoverEvent": "pointerHover", - "FlPanCancelEvent": "panCancel", - "FlPanDownEvent": "panDown", - "FlPanEndEvent": "panEnd", - "FlPanStartEvent": "panStart", - "FlPanUpdateEvent": "panUpdate", - "FlLongPressEnd": "longPressEnd", - "FlLongPressMoveUpdate": "longPressMoveUpdate", - "FlLongPressStart": "longPressStart", - "FlTapCancelEvent": "tapCancel", - "FlTapDownEvent": "tapDown", - "FlTapUpEvent": "tapUp", -}; - -class PieChartEventData extends Equatable { - final String eventType; - final int? sectionIndex; - final Offset? localPosition; - - const PieChartEventData({required this.eventType, - required this.sectionIndex, - this.localPosition}); - - Map toJson() => { - 'type': eventType, - 'section_index': sectionIndex, - "lx": localPosition?.dx, - "ly": localPosition?.dy - }; - - @override - List get props => [eventType, sectionIndex]; -} - -class PieChartSectionViewModel extends Equatable { - final Control control; - final Control? badge; - - const PieChartSectionViewModel({required this.control, required this.badge}); - - static PieChartSectionViewModel fromStore( - Store store, Control control) { - var children = store.state.controls[control.id]!.childIds - .map((childId) => store.state.controls[childId]) - .nonNulls - .where((c) => c.isVisible); - - return PieChartSectionViewModel( - control: control, - badge: children.firstWhereOrNull((c) => c.name == "badge")); - } - - @override - List get props => [control, badge]; -} - -class PieChartViewModel extends Equatable { - final Control control; - final List sections; - - const PieChartViewModel({required this.control, required this.sections}); - - static PieChartViewModel fromStore( - Store store, Control control, List children) { - return PieChartViewModel( - control: control, - sections: children - .where((c) => c.type == "section" && c.isVisible) - .map((c) => PieChartSectionViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => [control, sections]; -} - -class PieChartControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - - const PieChartControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); - - @override - State createState() => _PieChartControlState(); -} - -class _PieChartControlState extends State { - PieChartEventData? _eventData; - - @override - Widget build(BuildContext context) { - debugPrint("PieChart build: ${widget.control.id}"); - - var animate = parseAnimation(widget.control, "animate"); - - var result = StoreConnector( - distinct: true, - converter: (store) => - PieChartViewModel.fromStore(store, widget.control, widget.children), - builder: (context, viewModel) { - List sections = viewModel.sections - .map((g) => getSectionData(Theme.of(context), widget.control, g)) - .toList(); - - Widget chart = PieChart( - PieChartData( - centerSpaceColor: - widget.control.attrColor("centerSpaceColor", context), - centerSpaceRadius: widget.control.attrDouble("centerSpaceRadius"), - sectionsSpace: widget.control.attrDouble("sectionsSpace"), - startDegreeOffset: widget.control.attrDouble("startDegreeOffset"), - pieTouchData: PieTouchData( - enabled: true, - touchCallback: widget.control.attrBool("onChartEvent", false)! - ? (FlTouchEvent evt, PieTouchResponse? resp) { - var type = evt.toString(); - var eventData = PieChartEventData( - // grab the event type found in between '' quotes - eventType: eventMap[type.substring( - type.indexOf("'") + 1, - type.lastIndexOf("'"))] ?? - "undefined", - sectionIndex: - resp?.touchedSection?.touchedSectionIndex, - localPosition: evt.localPosition, - ); - if (eventData != _eventData) { - _eventData = eventData; - debugPrint( - "PieChart ${widget.control.id} ${eventData.eventType}"); - widget.backend.triggerControlEvent(widget.control.id, - "chart_event", json.encode(eventData)); - } - } - : null, - ), - sections: sections, - ), - swapAnimationDuration: animate != null - ? animate.duration - : const Duration(milliseconds: 150), // Optional - swapAnimationCurve: animate != null ? animate.curve : Curves.linear, - ); - - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - return (constraints.maxHeight == double.infinity) - ? ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 300), - child: chart, - ) - : chart; - }); - }); - - return constrainedControl(context, result, widget.parent, widget.control); - } - - PieChartSectionData getSectionData(ThemeData theme, Control parent, - PieChartSectionViewModel sectionViewModel) { - return PieChartSectionData( - value: sectionViewModel.control.attrDouble("value"), - color: sectionViewModel.control.attrColor("color", context), - radius: sectionViewModel.control.attrDouble("radius"), - showTitle: sectionViewModel.control.attrString("title", "")! != "", - title: sectionViewModel.control.attrString("title"), - titleStyle: parseTextStyle( - Theme.of(context), sectionViewModel.control, "titleStyle"), - borderSide: - parseBorderSide(theme, sectionViewModel.control, "borderSide") ?? - BorderSide.none, - titlePositionPercentageOffset: - sectionViewModel.control.attrDouble("titlePosition"), - badgeWidget: sectionViewModel.badge != null - ? createControl(sectionViewModel.control, sectionViewModel.badge!.id, - sectionViewModel.control.isDisabled) - : null, - badgePositionPercentageOffset: - sectionViewModel.control.attrDouble("badgePosition"), - ); - } -} diff --git a/packages/flet/lib/src/controls/placeholder.dart b/packages/flet/lib/src/controls/placeholder.dart index ada287d4ac..c5c9e8e528 100644 --- a/packages/flet/lib/src/controls/placeholder.dart +++ b/packages/flet/lib/src/controls/placeholder.dart @@ -1,42 +1,27 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class PlaceholderControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const PlaceholderControl( - {super.key, - required this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const PlaceholderControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Placeholder build: ${control.id}"); - var contentCtrls = children.where((c) => c.isVisible); - return baseControl( - context, - Placeholder( - fallbackHeight: control.attrDouble("fallbackHeight", 400.0)!, - fallbackWidth: control.attrDouble("fallbackWidth", 400.0)!, - color: - control.attrColor("color", context, const Color(0xFF455A64))!, - strokeWidth: control.attrDouble("strokeWidth", 2.0)!, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, - control.isDisabled || parentDisabled, - parentAdaptive: control.isAdaptive ?? parentAdaptive) - : null), - parent, - control); + final placeholder = Placeholder( + fallbackHeight: control.getDouble("fallback_height", 400.0)!, + fallbackWidth: control.getDouble("fallback_width", 400.0)!, + color: control.getColor("color", context, const Color(0xFF455A64))!, + strokeWidth: control.getDouble("stroke_width", 2.0)!, + child: control.buildWidget("content")); + + return LayoutControl(control: control, child: placeholder); } } diff --git a/packages/flet/lib/src/controls/popup_menu_button.dart b/packages/flet/lib/src/controls/popup_menu_button.dart index 8f82b6f738..6b0c21e32a 100644 --- a/packages/flet/lib/src/controls/popup_menu_button.dart +++ b/packages/flet/lib/src/controls/popup_menu_button.dart @@ -1,151 +1,63 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/animations.dart'; import '../utils/borders.dart'; import '../utils/box.dart'; import '../utils/buttons.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/icons.dart'; -import '../utils/mouse.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../utils/popup_menu.dart'; +import 'base_controls.dart'; -class PopupMenuButtonControl extends StatelessWidget with FletStoreMixin { - final Control? parent; +class PopupMenuButtonControl extends StatelessWidget { final Control control; - final bool parentDisabled; - final List children; - final FletControlBackend backend; - const PopupMenuButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); + const PopupMenuButtonControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("PopupMenuButton build: ${control.id}"); - var icon = parseIcon(control.attrString("icon")); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - - Widget? child = contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled) - : null; - - var popupButton = withControls( - children - .where((c) => c.name != "content" && c.isVisible) - .map((c) => c.id), (content, viewModel) { - return PopupMenuButton( - enabled: !disabled, - tooltip: null, - icon: icon != null ? Icon(icon) : null, - iconSize: control.attrDouble("iconSize"), - splashRadius: control.attrDouble("splashRadius"), - shadowColor: control.attrColor("shadowColor", context), - surfaceTintColor: control.attrColor("surfaceTintColor", context), - iconColor: control.attrColor("iconColor", context), - elevation: control.attrDouble("elevation"), - enableFeedback: control.attrBool("enableFeedback"), - padding: - parseEdgeInsets(control, "padding", const EdgeInsets.all(8))!, - color: control.attrColor("bgcolor", context), - clipBehavior: - parseClip(control.attrString("clipBehavior"), Clip.none)!, - shape: parseOutlinedBorder(control, "shape") ?? - (Theme.of(context).useMaterial3 - ? RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10)) - : null), - constraints: parseBoxConstraints(control, "sizeConstraints"), - style: parseButtonStyle(Theme.of(context), control, "style"), - popUpAnimationStyle: - parseAnimationStyle(control, "popupAnimationStyle"), - menuPadding: parseEdgeInsets(control, "menuPadding"), - onSelected: (String selection) { - backend.triggerControlEvent(control.id, "select", selection); - }, - onCanceled: () { - backend.triggerControlEvent(control.id, "cancel"); - }, - onOpened: () { - backend.triggerControlEvent(control.id, "open"); - }, - position: parsePopupMenuPosition(control.attrString("menuPosition")), - itemBuilder: (BuildContext context) => - viewModel.controlViews.map((cv) { - var itemIcon = parseIcon(cv.control.attrString("icon")); - var text = cv.control.attrString("text", "")!; - var checked = cv.control.attrBool("checked"); - var height = cv.control.attrDouble("height", 48.0)!; - var padding = parseEdgeInsets(cv.control, "padding"); - var disabled = cv.control.isDisabled || parentDisabled; - var contentCtrls = cv.children - .where((c) => c.name == "content" && c.isVisible); - - Widget? child; - if (contentCtrls.isNotEmpty) { - // custom content - child = createControl( - cv.control, contentCtrls.first.id, parentDisabled); - } else if (itemIcon != null && text != "") { - // icon and text - child = Row(children: [ - Icon(itemIcon), - const SizedBox(width: 8), - Text(text) - ]); - } else if (text != "") { - child = Text(text); - } - - var item = checked != null - ? CheckedPopupMenuItem( - value: cv.control.id, - checked: checked, - height: height, - padding: padding, - enabled: !disabled || !cv.control.isDisabled, - mouseCursor: parseMouseCursor( - cv.control.attrString("mouseCursor")), - onTap: () { - backend.triggerControlEvent( - cv.control.id, "click", "${!checked}"); - }, - child: child, - ) - : PopupMenuItem( - value: cv.control.id, - height: height, - padding: padding, - enabled: !disabled || !cv.control.isDisabled, - mouseCursor: parseMouseCursor( - cv.control.attrString("mouseCursor")), - onTap: () { - backend.triggerControlEvent(cv.control.id, "click"); - }, - child: child); - - return child != null - ? item - : const PopupMenuDivider() as PopupMenuEntry; - }).toList(), - child: child); - }); - return constrainedControl( - context, - TooltipVisibility( - visible: control.attrString("tooltip") == null, child: popupButton), - parent, - control); + var content = control.buildTextOrWidget("content"); + + var popupMenuButton = PopupMenuButton( + enabled: !control.disabled, + tooltip: null, + icon: control.buildIconOrWidget("icon"), + iconSize: control.getDouble("icon_size"), + splashRadius: control.getDouble("splash_radius"), + shadowColor: control.getColor("shadow_color", context), + iconColor: control.getColor("icon_color", context), + elevation: control.getDouble("elevation"), + enableFeedback: control.getBool("enable_feedback"), + padding: control.getPadding("padding", const EdgeInsets.all(8))!, + color: control.getColor("bgcolor", context), + clipBehavior: control.getClipBehavior("clip_behavior", Clip.none)!, + shape: control.getShape( + "shape", + Theme.of(context), + ), + constraints: control.getBoxConstraints("size_constraints"), + style: control.getButtonStyle("style", Theme.of(context)), + popUpAnimationStyle: control.getAnimationStyle("popup_animation_style"), + menuPadding: control.getPadding("menu_padding"), + position: control.getPopupMenuPosition("menu_position"), + onSelected: (String selection) => + control.triggerEvent("select", selection), + onCanceled: () => control.triggerEvent("cancel"), + onOpened: () => control.triggerEvent("open"), + itemBuilder: (BuildContext context) => + buildPopupMenuEntries(control.children("items"), context), + child: content); + + return LayoutControl( + control: control, + child: TooltipVisibility( + visible: control.getString("tooltip") == null, + child: popupMenuButton)); } } diff --git a/packages/flet/lib/src/controls/progress_bar.dart b/packages/flet/lib/src/controls/progress_bar.dart index 7188fbf012..348c3e2783 100644 --- a/packages/flet/lib/src/controls/progress_bar.dart +++ b/packages/flet/lib/src/controls/progress_bar.dart @@ -2,36 +2,36 @@ import 'package:flutter/material.dart'; import '../models/control.dart'; import '../utils/borders.dart'; -import 'create_control.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class ProgressBarControl extends StatelessWidget { - final Control? parent; final Control control; - const ProgressBarControl( - {super.key, required this.parent, required this.control}); + const ProgressBarControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("ProgressBar build: ${control.id}"); - - return constrainedControl( - context, - LinearProgressIndicator( - value: control.attrDouble("value"), - minHeight: control.attrDouble("minHeight", 4)!, - color: control.attrColor("color", context), - backgroundColor: control.attrColor("bgColor", context), - semanticsLabel: control.attrString("semanticsLabel"), - semanticsValue: control.attrDouble("semanticsValue")?.toString(), - borderRadius: - parseBorderRadius(control, "borderRadius", BorderRadius.zero)!, - stopIndicatorColor: control.attrColor("stopIndicatorColor", context), - stopIndicatorRadius: control.attrDouble("stopIndicatorRadius"), - trackGap: control.attrDouble("trackGap"), - year2023: control.attrBool("year2023"), - ), - parent, - control); + final indicator = LinearProgressIndicator( + value: control.getDouble("value"), + minHeight: control.getDouble("bar_height"), + color: control.getColor("color", context), + backgroundColor: control.getColor("bgcolor", context), + semanticsLabel: control.getString("semantics_label"), + semanticsValue: control.getDouble("semantics_value")?.toString(), + borderRadius: control.getBorderRadius("border_radius"), + stopIndicatorColor: control.getColor("stop_indicator_color", context), + stopIndicatorRadius: control.getDouble("stop_indicator_radius"), + trackGap: control.getDouble("track_gap"), + // ignore: deprecated_member_use + year2023: control.getBool( + "year_2023"), // todo: deprecated and to be removed in future versions + ); + return LayoutControl(control: control, child: indicator); } } diff --git a/packages/flet/lib/src/controls/progress_ring.dart b/packages/flet/lib/src/controls/progress_ring.dart index b7da78e0f0..45efca077d 100644 --- a/packages/flet/lib/src/controls/progress_ring.dart +++ b/packages/flet/lib/src/controls/progress_ring.dart @@ -2,39 +2,39 @@ import 'package:flutter/material.dart'; import '../models/control.dart'; import '../utils/box.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class ProgressRingControl extends StatelessWidget { - final Control? parent; final Control control; - const ProgressRingControl( - {super.key, required this.parent, required this.control}); + const ProgressRingControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("ProgressRing build: ${control.id}"); - - return constrainedControl( - context, - CircularProgressIndicator( - value: control.attrDouble("value"), - strokeWidth: control.attrDouble("strokeWidth", 4)!, - color: control.attrColor("color", context), - backgroundColor: control.attrColor("bgColor", context), - semanticsLabel: control.attrString("semanticsLabel"), - strokeCap: parseStrokeCap(control.attrString("strokeCap")), - semanticsValue: control.attrDouble("semanticsValue")?.toString(), - strokeAlign: control.attrDouble("strokeAlign", 0)!, - trackGap: control.attrDouble("trackGap"), - constraints: parseBoxConstraints(control, "sizeConstraints"), - padding: parseEdgeInsets(control, "padding"), - // TODO: deprecated in v0.27.0, and will be removed in future versions - year2023: control.attrBool("year2023"), - ), - parent, - control); + final indicator = CircularProgressIndicator( + value: control.getDouble("value"), + strokeWidth: control.getDouble("stroke_width"), + color: control.getColor("color", context), + backgroundColor: control.getColor("bgcolor", context), + semanticsLabel: control.getString("semantics_label"), + strokeCap: control.getStrokeCap("stroke_cap"), + semanticsValue: control.getDouble("semantics_value")?.toString(), + strokeAlign: control.getDouble("stroke_align"), + trackGap: control.getDouble("track_gap"), + constraints: control.getBoxConstraints("size_constraints"), + padding: control.getPadding("padding"), + // ignore: deprecated_member_use + year2023: control.getBool( + "year2023"), // todo: deprecated and to be removed in future versions + ); + return LayoutControl(control: control, child: indicator); } } diff --git a/packages/flet/lib/src/controls/radio.dart b/packages/flet/lib/src/controls/radio.dart index ae5291843e..64ef533ddc 100644 --- a/packages/flet/lib/src/controls/radio.dart +++ b/packages/flet/lib/src/controls/radio.dart @@ -1,40 +1,29 @@ -import 'package:flet/src/utils/theme.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/colors.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; +import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'cupertino_radio.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../utils/theme.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; import 'list_tile.dart'; - class RadioControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const RadioControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + RadioControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _RadioControlState(); } -class _RadioControlState extends State with FletStoreMixin { +class _RadioControlState extends State { late final FocusNode _focusNode; + Listenable? _tileClicksNotifier; @override void initState() { @@ -43,115 +32,95 @@ class _RadioControlState extends State with FletStoreMixin { _focusNode.addListener(_onFocusChange); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final newNotifier = ListTileClicks.of(context)?.notifier; + + // If the inherited source changed, swap listeners + if (!identical(_tileClicksNotifier, newNotifier)) { + _tileClicksNotifier?.removeListener(_handleTileClick); + _tileClicksNotifier = newNotifier; + _tileClicksNotifier?.addListener(_handleTileClick); + } + } + void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + void _handleTileClick() { + if (widget.control.disabled) { + return; + } + final radioGroup = RadioGroup.maybeOf(context); + if (radioGroup != null) { + final value = widget.control.getString("value", "")!; + radioGroup.onChanged(value); + } } @override void dispose() { _focusNode.removeListener(_onFocusChange); + _tileClicksNotifier?.removeListener(_handleTileClick); _focusNode.dispose(); super.dispose(); } - void _onChange(String ancestorId, String? value) { - var svalue = value ?? ""; - debugPrint(svalue); - widget.backend.updateControlState(ancestorId, {"value": svalue}); - widget.backend.triggerControlEvent(ancestorId, "change", svalue); - } - @override Widget build(BuildContext context) { debugPrint("Radio build: ${widget.control.id}"); - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoRadioControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - backend: widget.backend); - } - - String label = widget.control.attrString("label", "")!; - String value = widget.control.attrString("value", "")!; - LabelPosition labelPosition = parseLabelPosition( - widget.control.attrString("labelPosition"), LabelPosition.right)!; - VisualDensity? visualDensity = - parseVisualDensity(widget.control.attrString("visualDensity")); - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - TextStyle? labelStyle = - parseTextStyle(Theme.of(context), widget.control, "labelStyle"); - if (disabled && labelStyle != null) { - labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); - } - - return withControlAncestor(widget.control.id, "radiogroup", - (context, viewModel) { - debugPrint("Radio StoreConnector build: ${widget.control.id}"); - - if (viewModel.ancestor == null) { - return const ErrorControl("Radio must be enclosed within RadioGroup"); - } - - String groupValue = viewModel.ancestor!.attrString("value", "")!; - String ancestorId = viewModel.ancestor!.id; - - var radio = Radio( - autofocus: autofocus, - focusNode: _focusNode, - groupValue: groupValue, - mouseCursor: parseMouseCursor(widget.control.attrString("mouseCursor")), - value: value, - activeColor: widget.control.attrColor("activeColor", context), - focusColor: widget.control.attrColor("focusColor", context), - hoverColor: widget.control.attrColor("hoverColor", context), - splashRadius: widget.control.attrDouble("splashRadius"), - toggleable: widget.control.attrBool("toggleable", false)!, - fillColor: parseWidgetStateColor( - Theme.of(context), widget.control, "fillColor"), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "overlayColor"), - visualDensity: visualDensity, - onChanged: !disabled - ? (String? value) { - _onChange(ancestorId, value); - } - : null); - - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(ancestorId, value); - }); - - Widget result = radio; - if (label != "") { - var labelWidget = disabled - ? Text(label, style: labelStyle) - : MouseRegion( - cursor: SystemMouseCursors.click, - child: Text(label, style: labelStyle)); - result = MergeSemantics( - child: GestureDetector( - onTap: !disabled - ? () { - _onChange(ancestorId, value); - } - : null, - child: labelPosition == LabelPosition.right - ? Row(children: [radio, labelWidget]) - : Row(children: [labelWidget, radio]))); - } - - return constrainedControl( - context, result, widget.parent, widget.control); - }); - }); + final radioGroup = RadioGroup.maybeOf(context); + if (radioGroup == null) { + return const ErrorControl("Radio must be enclosed within RadioGroup"); + } + + var value = widget.control.getString("value", "")!; + var label = widget.control.getString("label", "")!; + var labelPosition = + widget.control.getLabelPosition("label_position", LabelPosition.right)!; + var labelStyle = + widget.control.getTextStyle("label_style", Theme.of(context)); + if (widget.control.disabled && labelStyle != null) { + labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); + } + + var radio = Radio( + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + value: value, + activeColor: widget.control.getColor("active_color", context), + focusColor: widget.control.getColor("focus_color", context), + hoverColor: widget.control.getColor("hover_color", context), + splashRadius: widget.control.getDouble("splash_radius"), + toggleable: widget.control.getBool("toggleable", false)!, + fillColor: + widget.control.getWidgetStateColor("fill_color", Theme.of(context)), + overlayColor: widget.control + .getWidgetStateColor("overlay_color", Theme.of(context)), + visualDensity: widget.control.getVisualDensity("visual_density"), + ); + + Widget result = radio; + if (label != "") { + var labelWidget = widget.control.disabled + ? Text(label, style: labelStyle) + : MouseRegion( + cursor: SystemMouseCursors.click, + child: Text(label, style: labelStyle)); + result = MergeSemantics( + child: GestureDetector( + onTap: !widget.control.disabled + ? () => radioGroup.onChanged(value) + : null, + child: labelPosition == LabelPosition.right + ? Row(children: [radio, labelWidget]) + : Row(children: [labelWidget, radio]))); + } + + return LayoutControl(control: widget.control, child: result); } } diff --git a/packages/flet/lib/src/controls/radio_group.dart b/packages/flet/lib/src/controls/radio_group.dart index 41c0cef6ff..abf043c4bd 100644 --- a/packages/flet/lib/src/controls/radio_group.dart +++ b/packages/flet/lib/src/controls/radio_group.dart @@ -1,38 +1,28 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; class RadioGroupControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const RadioGroupControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const RadioGroupControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("RadioGroupControl build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - - if (contentCtrls.isEmpty) { - return const ErrorControl( - "RadioGroup.content must be provided and visible"); - } - - return createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive); + return RadioGroup( + groupValue: control.get("value"), + onChanged: (String? value) { + if (!control.disabled) { + control.updateProperties({"value": value}, notify: true); + control.triggerEvent("change", value); + } + }, + child: control.buildWidget("content") ?? + const ErrorControl("RadioGroup.content must be provided and visible"), + ); } } diff --git a/packages/flet/lib/src/controls/range_slider.dart b/packages/flet/lib/src/controls/range_slider.dart index 2d7a4de38c..0ec125cd1c 100644 --- a/packages/flet/lib/src/controls/range_slider.dart +++ b/packages/flet/lib/src/controls/range_slider.dart @@ -1,33 +1,22 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/colors.dart'; -import '../utils/debouncer.dart'; import '../utils/mouse.dart'; -import '../utils/platform.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class RangeSliderControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const RangeSliderControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + RangeSliderControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _SliderControlState(); } class _SliderControlState extends State { - final _debouncer = Debouncer(milliseconds: isDesktopPlatform() ? 10 : 100); - @override void initState() { super.initState(); @@ -35,70 +24,53 @@ class _SliderControlState extends State { @override void dispose() { - _debouncer.dispose(); super.dispose(); } void onChange(double startValue, double endValue) { - var props = { - "startvalue": startValue.toString(), - "endvalue": endValue.toString() - }; - widget.backend.updateControlState(widget.control.id, props, server: false); - _debouncer.run(() { - widget.backend.updateControlState(widget.control.id, props); - widget.backend.triggerControlEvent(widget.control.id, "change"); - }); + var props = {"start_value": startValue, "end_value": endValue}; + widget.control.updateProperties(props, notify: true); + widget.control.triggerEvent("change"); } @override Widget build(BuildContext context) { debugPrint("RangeSliderControl build: ${widget.control.id}"); - double startValue = widget.control.attrDouble("startValue", 0)!; - double endValue = widget.control.attrDouble("endValue", 0)!; - String label = widget.control.attrString("label", "")!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - double min = widget.control.attrDouble("min", 0)!; - double max = widget.control.attrDouble("max", 1)!; - - int round = widget.control.attrInt("round", 0)!; - - debugPrint("SliderControl build: ${widget.control.id}"); + double startValue = widget.control.getDouble("start_value", 0)!; + double endValue = widget.control.getDouble("end_value", 0)!; + String label = widget.control.getString("label", "")!; + int round = widget.control.getInt("round", 0)!; var rangeSlider = RangeSlider( values: RangeValues(startValue, endValue), labels: RangeLabels( (label).replaceAll("{value}", startValue.toStringAsFixed(round)), (label).replaceAll("{value}", endValue.toStringAsFixed(round))), - min: min, - max: max, - divisions: widget.control.attrInt("divisions"), - activeColor: widget.control.attrColor("activeColor", context), - inactiveColor: widget.control.attrColor("inactiveColor", context), - mouseCursor: parseWidgetStateMouseCursor(widget.control, "mouseCursor"), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "overlayColor"), - onChanged: !disabled + min: widget.control.getDouble("min", 0)!, + max: widget.control.getDouble("max", 1)!, + divisions: widget.control.getInt("divisions"), + activeColor: widget.control.getColor("active_color", context), + inactiveColor: widget.control.getColor("inactive_color", context), + mouseCursor: widget.control.getWidgetStateMouseCursor("mouse_cursor"), + overlayColor: widget.control + .getWidgetStateColor("overlay_color", Theme.of(context)), + onChanged: !widget.control.disabled ? (RangeValues newValues) { onChange(newValues.start, newValues.end); } : null, - onChangeStart: !disabled + onChangeStart: !widget.control.disabled ? (RangeValues newValues) { - widget.backend - .triggerControlEvent(widget.control.id, "change_start"); + widget.control.triggerEvent("change_start"); } : null, - onChangeEnd: !disabled + onChangeEnd: !widget.control.disabled ? (RangeValues newValues) { - widget.backend - .triggerControlEvent(widget.control.id, "change_end"); + widget.control.triggerEvent("change_end"); } : null); - return constrainedControl( - context, rangeSlider, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: rangeSlider); } } diff --git a/packages/flet/lib/src/controls/reorderable_drag_handle.dart b/packages/flet/lib/src/controls/reorderable_drag_handle.dart new file mode 100644 index 0000000000..574b2a633a --- /dev/null +++ b/packages/flet/lib/src/controls/reorderable_drag_handle.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/mouse.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import '../widgets/reorderable_item_scope.dart'; + +class ReorderableDragHandleControl extends StatelessWidget { + final Control control; + + const ReorderableDragHandleControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("ReorderableDragHandleControl build: ${control.id}"); + + var scope = ReorderableItemScope.of(context); + var index = scope?.index; + if (index == null) { + return const ErrorControl( + "ReorderableDragHandle must be placed inside ReorderableListView."); + } + Widget? content = control.buildWidget("content"); + if (content == null) { + return const ErrorControl( + "ReorderableDragHandle.content must be set and visible"); + } + + var mouseCursor = parseMouseCursor(control.getString("mouse_cursor")); + + if (mouseCursor != null) { + content = MouseRegion( + cursor: mouseCursor, + child: content, + ); + } + + return ReorderableDragStartListener( + index: index, enabled: !control.disabled, child: content); + } +} diff --git a/packages/flet/lib/src/controls/reorderable_draggable.dart b/packages/flet/lib/src/controls/reorderable_draggable.dart deleted file mode 100644 index c55562f0e6..0000000000 --- a/packages/flet/lib/src/controls/reorderable_draggable.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../models/control.dart'; -import 'create_control.dart'; -import 'error.dart'; - -class ReorderableDraggableControl extends StatefulWidget { - final Control? parent; - final Control control; - final bool parentDisabled; - final List children; - final bool? parentAdaptive; - - const ReorderableDraggableControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); - - @override - State createState() => _ListViewControlState(); -} - -class _ListViewControlState extends State { - @override - Widget build(BuildContext context) { - debugPrint("ReorderableDraggableControl build: ${widget.control.id}"); - - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - - var index = widget.control.attrInt("index"); - if (index == null) { - return const ErrorControl("ReorderableDraggable.index is invalid"); - } - var content = widget.children.where((c) => c.isVisible).firstOrNull; - if (content == null) { - return const ErrorControl( - "ReorderableDraggable.content must be set and visible"); - } - - return ReorderableDragStartListener( - index: index, - child: createControl(widget.control, content.id, widget.parentDisabled, - parentAdaptive: adaptive)); - } -} diff --git a/packages/flet/lib/src/controls/reorderable_list_view.dart b/packages/flet/lib/src/controls/reorderable_list_view.dart index 750bd1cec3..7bcc23afaa 100644 --- a/packages/flet/lib/src/controls/reorderable_list_view.dart +++ b/packages/flet/lib/src/controls/reorderable_list_view.dart @@ -1,32 +1,23 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; +import '../utils/keys.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import '../widgets/reorderable_item_scope.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; import 'scroll_notification_control.dart'; import 'scrollable_control.dart'; class ReorderableListViewControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final List children; - final bool? parentAdaptive; - final FletControlBackend backend; - - const ReorderableListViewControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + ReorderableListViewControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _ListViewControlState(); @@ -34,11 +25,43 @@ class ReorderableListViewControl extends StatefulWidget { class _ListViewControlState extends State { late final ScrollController _controller; + List _controls = []; + + Widget _buildItem(int index) { + final control = _controls[index]; + final keyValue = control.getKey("key")?.value ?? control.id; + return ReorderableItemScope( + key: ValueKey(keyValue), + index: index, + child: ControlWidget( + key: ValueKey(keyValue), + control: control, + ), + ); + } + + Widget _buildPrototypeItem() { + final control = _controls[0]; + return ReorderableItemScope( + index: 0, + child: ControlWidget( + key: ValueKey(control.id), + control: control, + ), + ); + } @override void initState() { super.initState(); _controller = ScrollController(); + _controls = [...widget.control.children("controls")]; + } + + @override + void didUpdateWidget(covariant ReorderableListViewControl oldWidget) { + _controls = [...widget.control.children("controls")]; + super.didUpdateWidget(oldWidget); } @override @@ -49,75 +72,53 @@ class _ListViewControlState extends State { @override Widget build(BuildContext context) { - debugPrint("ReorderableDraggableControl build: ${widget.control.id}"); - - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; + debugPrint("ReorderableListViewControl build: ${widget.control.id}"); - var horizontal = widget.control.attrBool("horizontal", false)!; + var horizontal = widget.control.getBool("horizontal", false)!; var buildControlsOnDemand = - widget.control.attrBool("buildControlsOnDemand", true)!; - var itemExtent = widget.control.attrDouble("itemExtent"); - var cacheExtent = widget.control.attrDouble("cacheExtent"); + widget.control.getBool("build_controls_on_demand", true)!; + var itemExtent = widget.control.getDouble("item_extent"); + var cacheExtent = widget.control.getDouble("cache_extent"); var firstItemPrototype = - widget.control.attrBool("firstItemPrototype", false)!; - var padding = parseEdgeInsets(widget.control, "padding"); - var reverse = widget.control.attrBool("reverse", false)!; + widget.control.getBool("first_item_prototype", false)!; + var padding = widget.control.getPadding("padding"); + var reverse = widget.control.getBool("reverse", false)!; var showDefaultDragHandles = - widget.control.attrBool("showDefaultDragHandles", true)!; - var anchor = widget.control.attrDouble("anchor", 0.0)!; - var mouseCursor = - parseMouseCursor(widget.control.attrString("mouseCursor")); + widget.control.getBool("show_default_drag_handles", true)!; + var anchor = widget.control.getDouble("anchor", 0.0)!; var clipBehavior = - parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!; - List ctrls = widget.children - .where((c) => c.name != "header" && c.name != "footer" && c.isVisible) - .toList(); + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!; var scrollDirection = horizontal ? Axis.horizontal : Axis.vertical; - var headerCtrls = - widget.children.where((c) => c.name == "header" && c.isVisible); - var header = headerCtrls.isNotEmpty - ? createControl(widget.control, headerCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null; - var footerCtrls = - widget.children.where((c) => c.name == "footer" && c.isVisible); - var footer = footerCtrls.isNotEmpty - ? createControl(widget.control, footerCtrls.first.id, disabled, - parentAdaptive: adaptive) - : null; - var prototypeItem = firstItemPrototype && widget.children.isNotEmpty - ? createControl(widget.control, ctrls[0].id, disabled, - parentAdaptive: adaptive) + var header = widget.control.buildWidget("header"); + var footer = widget.control.buildWidget("footer"); + var prototypeItem = firstItemPrototype && _controls.isNotEmpty + ? _buildPrototypeItem() : null; var autoScrollerVelocityScalar = - widget.control.attrDouble("autoScrollerVelocityScalar"); + widget.control.getDouble("auto_scroller_velocity_scalar"); + var mouseCursor = widget.control.getMouseCursor("mouse_cursor"); void onReorder(int oldIndex, int newIndex) { - debugPrint("onReorder: $oldIndex -> $newIndex"); - if (newIndex > oldIndex) { - newIndex -= 1; - } setState(() { - final Control movedControl = widget.children.removeAt(oldIndex); - widget.children.insert(newIndex, movedControl); + if (oldIndex < newIndex) { + newIndex -= 1; + } + final item = _controls.removeAt(oldIndex); + _controls.insert(newIndex, item); }); - widget.backend.triggerControlEvent(widget.control.id, "reorder", - jsonEncode({"old": oldIndex, "new": newIndex})); + widget.control.triggerEvent( + "reorder", {"old_index": oldIndex, "new_index": newIndex}); } void onReorderEnd(int newIndex) { - widget.backend.triggerControlEvent( - widget.control.id, "reorder_end", jsonEncode({"new": newIndex})); + widget.control.triggerEvent("reorder_end", {"new_index": newIndex}); } void onReorderStart(int oldIndex) { - widget.backend.triggerControlEvent( - widget.control.id, "reorder_start", jsonEncode({"old": oldIndex})); + widget.control.triggerEvent("reorder_start", {"old_index": oldIndex}); } - Widget listView = LayoutBuilder( + Widget result = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { var shrinkWrap = (!horizontal && constraints.maxHeight == double.infinity) || @@ -133,7 +134,7 @@ class _ListViewControlState extends State { scrollDirection: scrollDirection, shrinkWrap: shrinkWrap, padding: padding, - itemCount: ctrls.length, + itemCount: _controls.length, itemExtent: itemExtent, mouseCursor: mouseCursor, anchor: anchor, @@ -145,9 +146,7 @@ class _ListViewControlState extends State { onReorderEnd: onReorderEnd, onReorderStart: onReorderStart, itemBuilder: (context, index) { - return createControl( - widget.control, ctrls[index].id, disabled, - parentAdaptive: adaptive); + return _buildItem(index); }, ) : ReorderableListView( @@ -169,29 +168,24 @@ class _ListViewControlState extends State { onReorder: onReorder, onReorderEnd: onReorderEnd, onReorderStart: onReorderStart, - children: ctrls.map((c) { - return createControl(widget.control, c.id, disabled, - parentAdaptive: adaptive); - }).toList(), + children: List.generate(_controls.length, _buildItem), ); child = ScrollableControl( control: widget.control, scrollDirection: scrollDirection, scrollController: _controller, - backend: widget.backend, - parentAdaptive: adaptive, child: child); - if (widget.control.attrBool("onScroll", false)!) { - child = ScrollNotificationControl( - control: widget.control, backend: widget.backend, child: child); + if (widget.control.getBool("on_scroll", false)!) { + child = + ScrollNotificationControl(control: widget.control, child: child); } return child; }, ); - return constrainedControl(context, listView, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: result); } } diff --git a/packages/flet/lib/src/controls/responsive_row.dart b/packages/flet/lib/src/controls/responsive_row.dart index 9f78405734..381da535ce 100644 --- a/packages/flet/lib/src/controls/responsive_row.dart +++ b/packages/flet/lib/src/controls/responsive_row.dart @@ -1,112 +1,149 @@ import 'package:flutter/widgets.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; +import '../utils/numbers.dart'; import '../utils/responsive.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; +import 'scroll_notification_control.dart'; +import 'scrollable_control.dart'; class ResponsiveRowControl extends StatelessWidget with FletStoreMixin { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - final FletControlBackend backend; - - const ResponsiveRowControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + const ResponsiveRowControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("ResponsiveRowControl build: ${control.id}"); - final columns = parseResponsiveNumber(control, "columns", 12); - final spacing = parseResponsiveNumber(control, "spacing", 10); - final runSpacing = parseResponsiveNumber(control, "runSpacing", 10); - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; + final columns = control.getResponsiveNumber("columns", 12)!; + final spacing = control.getResponsiveNumber("spacing", 10)!; + final runSpacing = control.getResponsiveNumber("run_spacing", 10)!; + return withPageSize((context, view) { - var w = LayoutBuilder( + Widget result = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - debugPrint( - "ResponsiveRow constraints.maxWidth: ${constraints.maxWidth}"); - debugPrint( - "ResponsiveRow constraints.maxHeight: ${constraints.maxHeight}"); + if (!constraints.hasBoundedWidth) { + return const ErrorControl( + "Error displaying ResponsiveRow: width is unbounded.", + description: + "Set a fixed width, a non-zero expand, or place it inside a control with bounded width.", + ); + } + // Resolve the active breakpoint map once per layout pass. Responsive + // properties such as `columns`, `spacing`, and child `col` values are + // all interpreted against this map. + final rawBreakpoints = + control.get("breakpoints", view.breakpoints)!; + final breakpoints = {}; + rawBreakpoints.forEach((k, v) { + final val = parseDouble(v); + if (val != null) { + breakpoints[k.toString()] = val; + } + }); var bpSpacing = - getBreakpointNumber(spacing, view.size.width, view.breakpoints); - + getBreakpointNumber(spacing, view.size.width, breakpoints); var bpColumns = - getBreakpointNumber(columns, view.size.width, view.breakpoints); + getBreakpointNumber(columns, view.size.width, breakpoints); double totalCols = 0; List controls = []; - for (var ctrl in children.where((c) => c.isVisible)) { - final col = parseResponsiveNumber(ctrl, "col", 12); - var bpCol = - getBreakpointNumber(col, view.size.width, view.breakpoints); + for (var ctrl in control.children("controls")) { + final col = ctrl.getResponsiveNumber("col", 12)!; + var bpCol = getBreakpointNumber(col, view.size.width, breakpoints); + + // `col=0` means "do not occupy any columns" for the current + // breakpoint, so the child should not participate in layout. + if (bpCol <= 0) { + continue; + } + totalCols += bpCol; - // calculate child width + // Convert virtual columns into a fixed pixel width for this child. + // We first remove the total horizontal gaps from the available width, + // then divide the remaining width across the configured columns. var colWidth = (constraints.maxWidth - bpSpacing * (bpColumns - 1)) / bpColumns; var childWidth = colWidth * bpCol + bpSpacing * (bpCol - 1); + // Guard against tiny/invalid available widths so Flutter never sees + // negative box constraints. + if (childWidth < 0) { + childWidth = 0; + } + controls.add(ConstrainedBox( - constraints: BoxConstraints( - minWidth: childWidth, - maxWidth: childWidth, - ), - child: createControl(control, ctrl.id, disabled, - parentAdaptive: adaptive), + constraints: + BoxConstraints(minWidth: childWidth, maxWidth: childWidth), + child: ControlWidget(key: key, control: ctrl), )); } var wrap = (totalCols > bpColumns); try { - return wrap - ? Wrap( - direction: Axis.horizontal, - spacing: bpSpacing - 0.1, - runSpacing: getBreakpointNumber( - runSpacing, view.size.width, view.breakpoints), - alignment: parseWrapAlignment( - control.attrString("alignment"), WrapAlignment.start)!, - crossAxisAlignment: parseWrapCrossAlignment( - control.attrString("verticalAlignment"), - WrapCrossAlignment.start)!, - children: controls, - ) - : Row( - spacing: bpSpacing - 0.1, - mainAxisAlignment: parseMainAxisAlignment( - control.attrString("alignment"), - MainAxisAlignment.start)!, - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: parseCrossAxisAlignment( - control.attrString("verticalAlignment"), - CrossAxisAlignment.start)!, - children: controls, - ); - } catch (e) { - return ErrorControl( - "Error displaying ResponsiveRow", - description: e.toString(), + // Keep a single row when everything fits; otherwise switch to Wrap so + // children can continue on the next line. + if (wrap) { + return Wrap( + direction: Axis.horizontal, + spacing: bpSpacing - 0.1, + runSpacing: getBreakpointNumber( + runSpacing, view.size.width, breakpoints), + alignment: + control.getWrapAlignment("alignment", WrapAlignment.start)!, + crossAxisAlignment: control.getWrapCrossAlignment( + "vertical_alignment", WrapCrossAlignment.start)!, + children: controls, + ); + } + + final crossAxisAlignment = control.getCrossAxisAlignment( + "vertical_alignment", CrossAxisAlignment.start)!; + + Widget row = Row( + spacing: bpSpacing - 0.1, + mainAxisAlignment: control.getMainAxisAlignment( + "alignment", MainAxisAlignment.start)!, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: crossAxisAlignment, + children: controls, ); + + // `IntrinsicHeight` is only needed when the row is both vertically + // scrollable (unbounded height) and asked to stretch children + // cross-axis — otherwise the row sizes to its children naturally, + // so we avoid the extra intrinsic-sizing pass. + if (control.get("scroll") != null && + crossAxisAlignment == CrossAxisAlignment.stretch) { + row = IntrinsicHeight(child: row); + } + + return row; + } catch (e) { + return ErrorControl("Error displaying ResponsiveRow", + description: e.toString()); } }); - return constrainedControl(context, w, parent, control); + result = ScrollableControl( + control: control, + scrollDirection: Axis.vertical, + wrapIntoScrollableView: true, + child: result); + + if (control.hasEventHandler("scroll")) { + result = ScrollNotificationControl(control: control, child: result); + } + + return LayoutControl(control: control, child: result); }); } } diff --git a/packages/flet/lib/src/controls/rotated_box.dart b/packages/flet/lib/src/controls/rotated_box.dart new file mode 100644 index 0000000000..06ee8ec826 --- /dev/null +++ b/packages/flet/lib/src/controls/rotated_box.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; + +class RotatedBoxControl extends StatelessWidget { + final Control control; + + const RotatedBoxControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("RotatedBox build: ${control.id}"); + + return LayoutControl( + control: control, + child: RotatedBox( + quarterTurns: control.getInt("quarter_turns", 0)!, + child: control.buildWidget("content"), + ), + ); + } +} diff --git a/packages/flet/lib/src/controls/row.dart b/packages/flet/lib/src/controls/row.dart index f2f43c2875..fc0e3756b9 100644 --- a/packages/flet/lib/src/controls/row.dart +++ b/packages/flet/lib/src/controls/row.dart @@ -1,80 +1,65 @@ import 'package:flutter/widgets.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; import 'scroll_notification_control.dart'; import 'scrollable_control.dart'; class RowControl extends StatelessWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - final FletControlBackend backend; - const RowControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const RowControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Row build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - var spacing = control.attrDouble("spacing", 10)!; - var mainAlignment = parseMainAxisAlignment( - control.attrString("alignment"), MainAxisAlignment.start)!; - var tight = control.attrBool("tight", false)!; - var wrap = control.attrBool("wrap", false)!; - var verticalAlignment = control.attrString("verticalAlignment"); - - List controls = children.where((c) => c.isVisible).map((c) { - return createControl(control, c.id, disabled, parentAdaptive: adaptive); - }).toList(); + var spacing = control.getDouble("spacing", 10)!; + var wrap = control.getBool("wrap", false)!; + var controls = control.buildWidgets("controls"); Widget child = wrap ? Wrap( direction: Axis.horizontal, spacing: spacing, - runSpacing: control.attrDouble("runSpacing", 10)!, + runSpacing: control.getDouble("run_spacing", 10)!, alignment: parseWrapAlignment( - control.attrString("alignment"), WrapAlignment.start)!, + control.getString("alignment"), WrapAlignment.start)!, runAlignment: parseWrapAlignment( - control.attrString("runAlignment"), WrapAlignment.start)!, - crossAxisAlignment: parseWrapCrossAlignment( - verticalAlignment, WrapCrossAlignment.center)!, + control.getString("run_alignment"), WrapAlignment.start)!, + crossAxisAlignment: control.getWrapCrossAlignment( + "vertical_alignment", WrapCrossAlignment.center)!, children: controls, ) : Row( spacing: spacing, - mainAxisAlignment: mainAlignment, - mainAxisSize: tight ? MainAxisSize.min : MainAxisSize.max, - crossAxisAlignment: parseCrossAxisAlignment( - verticalAlignment, CrossAxisAlignment.center)!, + mainAxisSize: control.getBool("tight", false)! + ? MainAxisSize.min + : MainAxisSize.max, + mainAxisAlignment: control.getMainAxisAlignment( + "alignment", MainAxisAlignment.start)!, + crossAxisAlignment: control.getCrossAxisAlignment( + "vertical_alignment", CrossAxisAlignment.center)!, children: controls, ); + if (control.getBool("intrinsic_height", false)!) { + child = IntrinsicHeight(child: child); + } + child = ScrollableControl( control: control, scrollDirection: wrap ? Axis.vertical : Axis.horizontal, - backend: backend, - parentAdaptive: adaptive, + wrapIntoScrollableView: true, child: child); - if (control.attrBool("onScroll", false)!) { - child = ScrollNotificationControl( - control: control, backend: backend, child: child); + if (control.getBool("on_scroll", false)!) { + child = ScrollNotificationControl(control: control, child: child); } - return constrainedControl(context, child, parent, control); + return LayoutControl(control: control, child: child); } } diff --git a/packages/flet/lib/src/controls/safe_area.dart b/packages/flet/lib/src/controls/safe_area.dart index 2984dbc851..f42127477a 100644 --- a/packages/flet/lib/src/controls/safe_area.dart +++ b/packages/flet/lib/src/controls/safe_area.dart @@ -1,49 +1,33 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/edge_insets.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class SafeAreaControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const SafeAreaControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const SafeAreaControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("SafeArea build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - var safeArea = SafeArea( - left: control.attrBool("left", true)!, - top: control.attrBool("top", true)!, - right: control.attrBool("right", true)!, - bottom: control.attrBool("bottom", true)!, + final safeArea = SafeArea( + left: control.getBool("avoid_intrusions_left", true)!, + top: control.getBool("avoid_intrusions_top", true)!, + right: control.getBool("avoid_intrusions_right", true)!, + bottom: control.getBool("avoid_intrusions_bottom", true)!, maintainBottomViewPadding: - control.attrBool("maintainBottomViewPadding", false)!, - minimum: parseEdgeInsets(control, "minimumPadding") ?? - parseEdgeInsets(control, "minimum") ?? - EdgeInsets.zero, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive) - : const ErrorControl( + control.getBool("maintain_bottom_view_padding", false)!, + minimum: control.getEdgeInsets("minimum_padding", EdgeInsets.zero)!, + child: control.buildWidget("content") ?? + const ErrorControl( "SafeArea.content must be provided and visible")); - return constrainedControl(context, safeArea, parent, control); + return LayoutControl(control: control, child: safeArea); } } diff --git a/packages/flet/lib/src/controls/screenshot.dart b/packages/flet/lib/src/controls/screenshot.dart new file mode 100644 index 0000000000..d3ddbf2270 --- /dev/null +++ b/packages/flet/lib/src/controls/screenshot.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:screenshot/screenshot.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/time.dart'; +import 'base_controls.dart'; + +class ScreenshotControl extends StatefulWidget { + final Control control; + + ScreenshotControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _InteractiveViewerControlState(); +} + +class _InteractiveViewerControlState extends State { + final ScreenshotController _screenshotController = ScreenshotController(); + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Screenshot.$name($args)"); + switch (name) { + case "capture": + return await _screenshotController.capture( + pixelRatio: args["pixel_ratio"], + delay: parseDuration( + args["delay"], const Duration(milliseconds: 20))!); + default: + throw Exception("Unknown Screenshot method: $name"); + } + } + + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("Screenshot build: ${widget.control.id}"); + + var screenshot = Screenshot( + controller: _screenshotController, + child: widget.control.buildWidget("content")); + + return BaseControl(control: widget.control, child: screenshot); + } +} diff --git a/packages/flet/lib/src/controls/scroll_notification_control.dart b/packages/flet/lib/src/controls/scroll_notification_control.dart index 82f21e5092..57672eb9eb 100644 --- a/packages/flet/lib/src/controls/scroll_notification_control.dart +++ b/packages/flet/lib/src/controls/scroll_notification_control.dart @@ -1,20 +1,15 @@ -import 'dart:convert'; - import 'package:flutter/widgets.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; +import '../utils/numbers.dart'; class ScrollNotificationControl extends StatefulWidget { final Widget child; final Control control; - final FletControlBackend backend; - const ScrollNotificationControl( - {super.key, - required this.child, - required this.control, - required this.backend}); + ScrollNotificationControl( + {Key? key, required this.child, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => @@ -27,7 +22,7 @@ class _ScrollNotificationControlState extends State { @override Widget build(BuildContext context) { - _onScrollInterval = widget.control.attrInt("onScrollInterval", 10)!; + _onScrollInterval = widget.control.getInt("scroll_interval", 10)!; return NotificationListener( child: widget.child, @@ -36,52 +31,47 @@ class _ScrollNotificationControlState extends State { } bool _onNotification(ScrollNotification notification, BuildContext context) { - void sendEvent(dynamic eventData) { - var d = ""; - if (eventData is String) { - d = eventData; - } else if (eventData is Map) { - d = json.encode(eventData); - } + if (notification.depth != 0) return false; - debugPrint("ScrollNotification ${widget.control.id} event"); - widget.backend.triggerControlEvent(widget.control.id, "onScroll", d); + final eventType = notification.runtimeType.toString(); + final now = DateTime.now().millisecondsSinceEpoch; + final lastEventTimestamp = _lastEventTimestamps[eventType]; + + if (lastEventTimestamp != null && + now - lastEventTimestamp <= _onScrollInterval) { + return false; } - if (notification.depth == 0) { - var eventType = notification.runtimeType.toString(); - var now = DateTime.now().millisecondsSinceEpoch; - var lastEventTimestamp = _lastEventTimestamps[eventType]; - if (lastEventTimestamp == null || - now - lastEventTimestamp > _onScrollInterval) { - _lastEventTimestamps[eventType] = now; + _lastEventTimestamps[eventType] = now; - Map data = { - "p": notification.metrics.pixels, - "minse": notification.metrics.minScrollExtent, - "maxse": notification.metrics.maxScrollExtent, - "vd": notification.metrics.viewportDimension - }; - if (notification is ScrollStartNotification) { - data["t"] = "start"; - } else if (notification is ScrollUpdateNotification) { - data["t"] = "update"; - data["sd"] = notification.scrollDelta; - } else if (notification is ScrollEndNotification) { - data["t"] = "end"; - } else if (notification is UserScrollNotification) { - data["t"] = "user"; - data["dir"] = notification.direction.name; - } else if (notification is OverscrollNotification) { - data["t"] = "over"; - data["os"] = notification.overscroll; - data["v"] = notification.velocity; - } + final metrics = notification.metrics; + final Map fields = { + "pixels": metrics.pixels, + "min_scroll_extent": metrics.minScrollExtent, + "max_scroll_extent": metrics.maxScrollExtent, + "viewport_dimension": metrics.viewportDimension, + }; - if (data["t"] != null) { - sendEvent(data); - } - } + if (notification is ScrollStartNotification) { + fields["event_type"] = "start"; + } else if (notification is ScrollUpdateNotification) { + fields["event_type"] = "update"; + fields["scroll_delta"] = notification.scrollDelta; + } else if (notification is ScrollEndNotification) { + fields["event_type"] = "end"; + } else if (notification is UserScrollNotification) { + fields["event_type"] = "user"; + fields["direction"] = notification.direction.name; + } else if (notification is OverscrollNotification) { + fields["event_type"] = "overscroll"; + fields["overscroll"] = notification.overscroll; + fields["velocity"] = notification.velocity; + } + + // Check that event_type was set before triggering the event + if (fields["event_type"] != null) { + debugPrint("ScrollNotification ${widget.control.id} event"); + widget.control.triggerEvent("scroll", fields); } return false; diff --git a/packages/flet/lib/src/controls/scrollable_control.dart b/packages/flet/lib/src/controls/scrollable_control.dart index 5596c26a59..188a42122d 100644 --- a/packages/flet/lib/src/controls/scrollable_control.dart +++ b/packages/flet/lib/src/controls/scrollable_control.dart @@ -1,32 +1,29 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; -import '../flet_app_services.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/animations.dart'; +import '../utils/keys.dart'; import '../utils/numbers.dart'; -import '../utils/others.dart'; -import 'flet_store_mixin.dart'; +import '../utils/scrollbar.dart'; +import '../utils/time.dart'; +import '../widgets/flet_store_mixin.dart'; class ScrollableControl extends StatefulWidget { final Control control; final Widget child; final Axis scrollDirection; final ScrollController? scrollController; - final bool? parentAdaptive; - final FletControlBackend backend; + final bool wrapIntoScrollableView; - const ScrollableControl( - {super.key, + ScrollableControl( + {Key? key, required this.control, required this.child, required this.scrollDirection, this.scrollController, - required this.parentAdaptive, - required this.backend}); + this.wrapIntoScrollableView = false}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _ScrollableControlState(); @@ -36,11 +33,12 @@ class _ScrollableControlState extends State with FletStoreMixin { late final ScrollController _controller; late bool _ownController = false; - String? _method; + final _ConstraintsHolder _outerConstraints = _ConstraintsHolder(); @override void initState() { super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); if (widget.scrollController != null) { _controller = widget.scrollController!; } else { @@ -49,114 +47,222 @@ class _ScrollableControlState extends State } } + Future _invokeMethod(String name, dynamic args) async { + debugPrint("ScrollableControl.$name($args)"); + switch (name) { + case "scroll_to": + var offset = parseDouble(args["offset"]); + var delta = parseDouble(args["delta"]); + var scrollKey = parseKey(args["scroll_key"]); + var globalKey = scrollKey != null + ? widget.control.backend.globalKeys[scrollKey.toString()] + : null; + var duration = parseDuration(args["duration"], Duration.zero)!; + var curve = parseCurve(args["curve"], Curves.ease)!; + if (globalKey != null) { + var ctx = globalKey.currentContext; + if (ctx != null) { + Scrollable.ensureVisible(ctx, duration: duration, curve: curve); + } + } else if (offset != null) { + if (offset < 0) { + offset = _controller.position.maxScrollExtent + offset + 1; + } + if (duration.inMilliseconds < 1) { + _controller.jumpTo(offset); + } else { + _controller.animateTo(offset, duration: duration, curve: curve); + } + } else if (delta != null) { + var offset = _controller.position.pixels + delta; + if (duration.inMilliseconds < 1) { + _controller.jumpTo(offset); + } else { + _controller.animateTo(offset, duration: duration, curve: curve); + } + } + } + } + @override void dispose() { if (_ownController) { _controller.dispose(); } + widget.control.removeInvokeMethodListener(_invokeMethod); super.dispose(); } @override Widget build(BuildContext context) { - return withPagePlatform((context, platform) { - ScrollMode scrollMode = parseScrollMode( - widget.control.attrString("scroll"), ScrollMode.none)!; - - var method = widget.control.attrString("method"); - - if (widget.control.attrBool("autoScroll", false)!) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _controller.animateTo( - _controller.position.maxScrollExtent, - duration: const Duration(seconds: 1), - curve: Curves.ease, - ); - }); - } else if (method != null && method != _method) { - _method = method; - debugPrint("ScrollableControl JSON method: $method"); - widget.backend.updateControlState(widget.control.id, {"method": ""}); - - var mj = json.decode(method); - var name = mj["n"] as String; - var params = Map.from(mj["p"] as Map); - - if (name == "scroll_to") { - var duration = parseInt(params["duration"], 0)!; - var curve = parseCurve(params["curve"], Curves.ease)!; - if (params["key"] != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - var key = FletAppServices.of(context).globalKeys[params["key"]]; - if (key != null) { - var ctx = key.currentContext; - if (ctx != null) { - Scrollable.ensureVisible(ctx, - duration: duration > 0 - ? Duration(milliseconds: duration) - : Duration.zero, - curve: curve); - } - } - }); - } else if (params["offset"] != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - var offset = parseDouble(params["offset"], 0)!; - if (offset < 0) { - offset = _controller.position.maxScrollExtent + offset + 1; - } - if (duration < 1) { - _controller.jumpTo(offset); - } else { - _controller.animateTo( - offset, - duration: Duration(milliseconds: duration), - curve: curve, - ); - } - }); - } else if (params["delta"] != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - var delta = parseDouble(params["delta"], 0)!; - var offset = _controller.position.pixels + delta; - if (duration < 1) { - _controller.jumpTo(offset); - } else { - _controller.animateTo( - offset, - duration: Duration(milliseconds: duration), - curve: curve, - ); - } - }); - } - } - } + debugPrint("ScrollableControl build: ${widget.control.id}"); + final scrollConfiguration = + widget.control.getScrollbarConfiguration("scroll"); + + if (widget.control.getBool("auto_scroll", false)!) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _controller.animateTo( + _controller.position.maxScrollExtent, + duration: const Duration(seconds: 1), + curve: Curves.ease, + ); + }); + } + + if (scrollConfiguration == null) return widget.child; - return scrollMode != ScrollMode.none - ? Scrollbar( - thumbVisibility: scrollMode == ScrollMode.always || - (scrollMode == ScrollMode.adaptive && - !kIsWeb && - platform != TargetPlatform.iOS && - platform != TargetPlatform.android) - ? true - : false, - trackVisibility: scrollMode == ScrollMode.hidden ? false : null, - thickness: scrollMode == ScrollMode.hidden - ? 0 - : platform == TargetPlatform.iOS || - platform == TargetPlatform.android - ? 4.0 - : null, - //interactive: true, - controller: _controller, - child: SingleChildScrollView( - controller: _controller, - scrollDirection: widget.scrollDirection, - child: widget.child, - )) - : widget.child; - }); + Widget child = widget.child; + if (widget.wrapIntoScrollableView) { + // The pre-#6450 path used a plain SingleChildScrollView. PR #6450 added + // a LayoutBuilder + ConstrainedBox(minHeight: parentMaxHeight) wrapper + // so vertical alignment works in scrollable Page/View when content is + // shorter than the viewport. LayoutBuilder, however, reports 0 for + // intrinsic dimensions, which collapses any ancestor IntrinsicWidth / + // IntrinsicHeight and leaves the layout perpetually dirty. + // + // Replicate the behavior with two cooperating RenderProxyBoxes that + // forward intrinsic queries to their child. The outer reader captures + // the parent's constraints during performLayout; the inner enforcer + // reads them back and applies them as a min on the scroll-view child. + child = SingleChildScrollView( + controller: _controller, + scrollDirection: widget.scrollDirection, + child: _InnerConstraintsEnforcer( + holder: _outerConstraints, + scrollDirection: widget.scrollDirection, + child: widget.child, + ), + ); + } + + Widget result = Scrollbar( + thumbVisibility: scrollConfiguration.thumbVisibility, + trackVisibility: scrollConfiguration.trackVisibility, + thickness: scrollConfiguration.thickness, + radius: scrollConfiguration.radius, + interactive: scrollConfiguration.interactive, + scrollbarOrientation: scrollConfiguration.orientation, + controller: _controller, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), + child: child, + )); + + if (widget.wrapIntoScrollableView) { + result = _OuterConstraintsReader( + holder: _outerConstraints, + child: result, + ); + } + + return result; + } +} + +/// Carries box constraints from [_OuterConstraintsReader] (outside the scroll +/// view) to [_InnerConstraintsEnforcer] (inside it) within a single layout +/// pass. Holds a reference to the inner enforcer so the outer reader can +/// mark it dirty when its incoming constraints change — without that, the +/// inner enforcer would skip re-layout on window resize because the +/// constraints it sees from SingleChildScrollView (unbounded in scroll axis) +/// don't change. +class _ConstraintsHolder { + BoxConstraints? value; + RenderObject? listener; +} + +class _OuterConstraintsReader extends SingleChildRenderObjectWidget { + const _OuterConstraintsReader({required this.holder, super.child}); + final _ConstraintsHolder holder; + + @override + RenderObject createRenderObject(BuildContext context) => + _RenderOuterConstraintsReader(holder); + + @override + void updateRenderObject( + BuildContext context, _RenderOuterConstraintsReader renderObject) { + renderObject.holder = holder; + } +} + +class _RenderOuterConstraintsReader extends RenderProxyBox { + _RenderOuterConstraintsReader(this.holder); + _ConstraintsHolder holder; + + @override + void performLayout() { + final changed = holder.value != constraints; + holder.value = constraints; + if (changed && holder.listener != null) { + // Force the inner enforcer to re-run performLayout in this layout pass. + // invokeLayoutCallback enables mutations during layout — without it, + // markNeedsLayout asserts. + invokeLayoutCallback((_) { + holder.listener?.markNeedsLayout(); + }); + } + super.performLayout(); + } +} + +class _InnerConstraintsEnforcer extends SingleChildRenderObjectWidget { + const _InnerConstraintsEnforcer({ + required this.holder, + required this.scrollDirection, + super.child, + }); + final _ConstraintsHolder holder; + final Axis scrollDirection; + + @override + RenderObject createRenderObject(BuildContext context) => + _RenderInnerConstraintsEnforcer(holder, scrollDirection); + + @override + void updateRenderObject( + BuildContext context, _RenderInnerConstraintsEnforcer renderObject) { + renderObject + ..holder = holder + ..scrollDirection = scrollDirection; + } +} + +class _RenderInnerConstraintsEnforcer extends RenderProxyBox { + _RenderInnerConstraintsEnforcer(this.holder, this.scrollDirection); + _ConstraintsHolder holder; + Axis scrollDirection; + + @override + void attach(PipelineOwner owner) { + super.attach(owner); + holder.listener = this; + } + + @override + void detach() { + if (holder.listener == this) holder.listener = null; + super.detach(); + } + + @override + void performLayout() { + if (child == null) { + size = computeSizeForNoChild(constraints); + return; + } + BoxConstraints childConstraints = constraints; + final outer = holder.value; + if (outer != null) { + if (scrollDirection == Axis.vertical && outer.hasBoundedHeight) { + childConstraints = + childConstraints.copyWith(minHeight: outer.maxHeight); + } else if (scrollDirection == Axis.horizontal && outer.hasBoundedWidth) { + childConstraints = + childConstraints.copyWith(minWidth: outer.maxWidth); + } + } + child!.layout(childConstraints, parentUsesSize: true); + size = child!.size; } } diff --git a/packages/flet/lib/src/controls/search_anchor.dart b/packages/flet/lib/src/controls/search_anchor.dart deleted file mode 100644 index 500a2ed0d3..0000000000 --- a/packages/flet/lib/src/controls/search_anchor.dart +++ /dev/null @@ -1,317 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; -import '../utils/borders.dart'; -import '../utils/box.dart'; -import '../utils/colors.dart'; -import '../utils/edge_insets.dart'; -import '../utils/form_field.dart'; -import '../utils/numbers.dart'; -import '../utils/text.dart'; -import 'create_control.dart'; - -class SearchAnchorControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const SearchAnchorControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); - - @override - State createState() => _SearchAnchorControlState(); -} - -class _SearchAnchorControlState extends State { - late final SearchController _controller; - bool _focused = false; - TextCapitalization _textCapitalization = TextCapitalization.none; - late final FocusNode _focusNode; - String? _lastFocusValue; - String? _lastBlurValue; - - @override - void initState() { - super.initState(); - _controller = SearchController(); - _controller.addListener(_searchTextChanged); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); - } - - void _onFocusChange() { - setState(() { - _focused = _focusNode.hasFocus; - }); - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); - } - - @override - void dispose() { - _controller.removeListener(_searchTextChanged); - _controller.dispose(); - _focusNode.removeListener(_onFocusChange); - _focusNode.dispose(); - super.dispose(); - } - - void _searchTextChanged() { - _textCapitalization = parseTextCapitalization( - widget.control.attrString("capitalization"), TextCapitalization.none)!; - _updateValue(_controller.text); - } - - void _updateValue(String value) { - value = applyCapitalization(value); - if (_controller.value.text != value) { - _controller.value = TextEditingValue( - text: value, - selection: TextSelection.collapsed(offset: value.length), - ); - } - - widget.backend.updateControlState(widget.control.id, {"value": value}); - } - - String applyCapitalization(String text) { - switch (_textCapitalization) { - /// Capitalizes the first character of each word. - case TextCapitalization.words: - return text - .split(RegExp(r'\s+')) - .map((word) => word.isNotEmpty - ? word[0].toUpperCase() + word.substring(1).toLowerCase() - : word) - .join(' '); - - /// Capitalizes the first character of each sentence. - case TextCapitalization.sentences: - return text - .split('. ') - .map((sentence) => sentence.isNotEmpty - ? sentence.trimLeft()[0].toUpperCase() + - sentence.substring(1).toLowerCase() - : sentence) - .join('. '); - - /// Capitalizes all characters. - case TextCapitalization.characters: - return text.toUpperCase(); - - /// No change. - case TextCapitalization.none: - return text; - } - } - - @override - Widget build(BuildContext context) { - debugPrint("SearchAnchor build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var value = widget.control.attrString("value", ""); - if (value != null && value != _controller.text) { - WidgetsBinding.instance.addPostFrameCallback((_) { - _controller.text = value; - }); - } - - bool onChange = widget.control.attrBool("onChange", false)!; - bool onTap = widget.control.attrBool("onTap", false)!; - bool onSubmit = widget.control.attrBool("onSubmit", false)!; - - var suggestionCtrls = - widget.children.where((c) => c.name == "controls" && c.isVisible); - var barLeadingCtrls = - widget.children.where((c) => c.name == "barLeading" && c.isVisible); - var barTrailingCtrls = - widget.children.where((c) => c.name == "barTrailing" && c.isVisible); - var viewLeadingCtrls = - widget.children.where((c) => c.name == "viewLeading" && c.isVisible); - var viewTrailingCtrls = - widget.children.where((c) => c.name == "viewTrailing" && c.isVisible); - TextInputType keyboardType = parseTextInputType( - widget.control.attrString("keyboardType"), TextInputType.text)!; - - var focusValue = widget.control.attrString("focus"); - var blurValue = widget.control.attrString("blur"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); - } - if (blurValue != null && blurValue != _lastBlurValue) { - _lastBlurValue = blurValue; - _focusNode.unfocus(); - } - - var method = widget.control.attrString("method"); - - if (method != null) { - debugPrint("SearchAnchor JSON method: $method"); - - void resetMethod() { - widget.backend.updateControlState(widget.control.id, {"method": ""}); - } - - var mj = json.decode(method); - var name = mj["n"] as String; - var params = Map.from(mj["p"] as Map); - - if (name == "closeView") { - WidgetsBinding.instance.addPostFrameCallback((_) { - resetMethod(); - if (_controller.isOpen) { - var text = params["text"].toString(); - _updateValue(text); - _controller.closeView(text); - } - }); - } else if (name == "openView") { - WidgetsBinding.instance.addPostFrameCallback((_) { - resetMethod(); - if (!_controller.isOpen) { - _controller.openView(); - } - }); - } - } - - Widget anchor = SearchAnchor( - searchController: _controller, - headerHintStyle: parseTextStyle( - Theme.of(context), widget.control, "viewHintTextStyle"), - headerTextStyle: parseTextStyle( - Theme.of(context), widget.control, "viewHeaderTextStyle"), - viewSide: - parseBorderSide(Theme.of(context), widget.control, "viewSide"), - isFullScreen: widget.control.attrBool("fullScreen", false), - viewBackgroundColor: widget.control.attrColor("viewBgcolor", context), - dividerColor: widget.control.attrColor("dividerColor", context), - viewHintText: widget.control.attrString("viewHintText"), - viewElevation: widget.control.attrDouble("viewElevation"), - headerHeight: widget.control.attrDouble("viewHeaderHeight"), - viewConstraints: - parseBoxConstraints(widget.control, "viewSizeConstraints"), - viewShape: parseOutlinedBorder(widget.control, "viewShape"), - viewTrailing: viewTrailingCtrls.isNotEmpty - ? viewTrailingCtrls.map((ctrl) { - return createControl(widget.parent, ctrl.id, disabled, - parentAdaptive: widget.parentAdaptive); - }) - : null, - viewLeading: viewLeadingCtrls.isNotEmpty - ? createControl(widget.parent, viewLeadingCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - viewOnSubmitted: onSubmit - ? (String value) { - debugPrint("SearchBar.onSubmit: $value"); - _updateValue(value); - widget.backend - .triggerControlEvent(widget.control.id, "submit", value); - } - : null, - viewOnChanged: onChange - ? (String value) { - debugPrint("SearchBar.onChange: $value"); - _updateValue(value); - widget.backend - .triggerControlEvent(widget.control.id, "change", value); - } - : null, - viewSurfaceTintColor: - widget.control.attrColor("viewSurfaceTintColor", context), - textCapitalization: _textCapitalization, - keyboardType: keyboardType, - builder: (BuildContext context, SearchController controller) { - return SearchBar( - controller: controller, - keyboardType: keyboardType, - textCapitalization: _textCapitalization, - autoFocus: widget.control.attrBool("autoFocus", false)!, - focusNode: _focusNode, - hintText: widget.control.attrString("barHintText"), - elevation: parseWidgetStateDouble(widget.control, "barElevation"), - shape: parseWidgetStateOutlinedBorder(widget.control, "barShape"), - padding: parseWidgetStateEdgeInsets(widget.control, "barPadding"), - textStyle: parseWidgetStateTextStyle( - Theme.of(context), widget.control, "barTextStyle"), - hintStyle: parseWidgetStateTextStyle( - Theme.of(context), widget.control, "barHintTextStyle"), - shadowColor: parseWidgetStateColor( - Theme.of(context), widget.control, "barShadowColor"), - surfaceTintColor: parseWidgetStateColor( - Theme.of(context), widget.control, "barSurfaceTintColor"), - side: parseWidgetStateBorderSide( - Theme.of(context), widget.control, "barBorderSide"), - backgroundColor: parseWidgetStateColor( - Theme.of(context), widget.control, "barBgcolor"), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "barOverlayColor"), - scrollPadding: parseEdgeInsets(widget.control, "barScrollPadding", - const EdgeInsets.all(20.0))!, - leading: barLeadingCtrls.isNotEmpty - ? createControl( - widget.parent, barLeadingCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive) - : null, - trailing: barTrailingCtrls.isNotEmpty - ? barTrailingCtrls.map((ctrl) { - return createControl(widget.parent, ctrl.id, disabled, - parentAdaptive: widget.parentAdaptive); - }) - : null, - onTap: onTap - ? () { - widget.backend - .triggerControlEvent(widget.control.id, "tap"); - } - : null, - onTapOutside: widget.control.attrBool("onTapOutsideBar", false)! - ? (PointerDownEvent? event) { - widget.backend.triggerControlEvent( - widget.control.id, "tapOutsideBar"); - } - : null, - onSubmitted: onSubmit - ? (String value) { - debugPrint("SearchBar.onSubmit: $value"); - _updateValue(value); - widget.backend.triggerControlEvent( - widget.control.id, "submit", value); - } - : null, - onChanged: onChange - ? (String value) { - debugPrint("SearchBar.onChange: $value"); - _updateValue(value); - widget.backend.triggerControlEvent( - widget.control.id, "change", value); - } - : null, - ); - }, - suggestionsBuilder: - (BuildContext context, SearchController controller) { - return suggestionCtrls.map((ctrl) { - return createControl(widget.parent, ctrl.id, disabled, - parentAdaptive: widget.parentAdaptive); - }); - }); - - return constrainedControl(context, anchor, widget.parent, widget.control); - } -} diff --git a/packages/flet/lib/src/controls/search_bar.dart b/packages/flet/lib/src/controls/search_bar.dart new file mode 100644 index 0000000000..91f682f064 --- /dev/null +++ b/packages/flet/lib/src/controls/search_bar.dart @@ -0,0 +1,326 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/borders.dart'; +import '../utils/box.dart'; +import '../utils/colors.dart'; +import '../utils/edge_insets.dart'; +import '../utils/form_field.dart'; +import '../utils/numbers.dart'; +import '../utils/text.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; + +class SearchBarControl extends StatefulWidget { + final Control control; + + SearchBarControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _SearchBarControlState(); +} + +class _SearchBarControlState extends State { + late final SearchController _controller; + + TextCapitalization? _textCapitalization; + late final FocusNode _focusNode; + String? _lastFocusValue; + String? _lastBlurValue; + + @override + void initState() { + super.initState(); + _controller = SearchController(); + _controller.addListener(_searchTextChanged); + _focusNode = FocusNode(); + _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + void _onFocusChange() { + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + @override + void dispose() { + _controller.removeListener(_searchTextChanged); + _controller.dispose(); + _focusNode.removeListener(_onFocusChange); + _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + void _searchTextChanged() { + _updateValue(_controller.text); + } + + void _updateValue(String value) { + value = applyCapitalization(value); + if (_controller.value.text != value) { + _controller.value = TextEditingValue( + text: value, + selection: TextSelection.collapsed(offset: value.length), + ); + } + + widget.control.updateProperties({"value": value}); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("SearchBar.$name($args)"); + switch (name) { + case "close_view": + if (_controller.isOpen) { + var text = args["text"]; + _updateValue(text); + _controller.closeView(text); + } + break; + case "open_view": + if (!_controller.isOpen) { + _controller.openView(); + } + break; + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown SearchBar method: $name"); + } + } + + String applyCapitalization(String text) { + switch (_textCapitalization) { + /// Capitalizes the first character of each word. + case TextCapitalization.words: + return text + .split(RegExp(r'\s+')) + .map((word) => word.isNotEmpty + ? word[0].toUpperCase() + word.substring(1).toLowerCase() + : word) + .join(' '); + + /// Capitalizes the first character of each sentence. + case TextCapitalization.sentences: + return text + .split('. ') + .map((sentence) => sentence.isNotEmpty + ? sentence.trimLeft()[0].toUpperCase() + + sentence.substring(1).toLowerCase() + : sentence) + .join('. '); + + /// Capitalizes all characters. + case TextCapitalization.characters: + return text.toUpperCase(); + + /// No change. + case TextCapitalization.none: + return text; + case null: + return text; + } + } + + @override + Widget build(BuildContext context) { + var value = widget.control.getString("value", "")!; + if (value != _controller.text) { + WidgetsBinding.instance.addPostFrameCallback((_) { + _controller.text = value; + }); + } + + bool onChange = widget.control.getBool("on_change", false)!; + bool onTap = widget.control.getBool("on_tap", false)!; + bool onSubmit = widget.control.getBool("on_submit", false)!; + TextInputType keyboardType = + widget.control.getTextInputType("keyboard_type", TextInputType.text)!; + + var focusValue = widget.control.getString("focus"); + var blurValue = widget.control.getString("blur"); + if (focusValue != null && focusValue != _lastFocusValue) { + _lastFocusValue = focusValue; + _focusNode.requestFocus(); + } + if (blurValue != null && blurValue != _lastBlurValue) { + _lastBlurValue = blurValue; + _focusNode.unfocus(); + } + + var theme = Theme.of(context); + + _textCapitalization = parseTextCapitalization( + widget.control.getString("capitalization"), + theme.searchBarTheme.textCapitalization); + + Widget anchor = SearchAnchor( + searchController: _controller, + headerHintStyle: + widget.control.getTextStyle("view_hint_text_style", theme), + headerTextStyle: + widget.control.getTextStyle("view_header_text_style", theme), + viewSide: widget.control.getBorderSide("view_side", theme), + viewPadding: widget.control.getPadding("view_padding"), + viewBarPadding: widget.control.getPadding("view_bar_padding"), + shrinkWrap: widget.control.getBool("shrink_wrap"), + isFullScreen: widget.control.getBool("full_screen", false), + viewBackgroundColor: widget.control.getColor("view_bgcolor", context), + dividerColor: widget.control.getColor("divider_color", context), + viewHintText: widget.control.getString("view_hint_text"), + viewElevation: widget.control.getDouble("view_elevation"), + headerHeight: widget.control.getDouble("view_header_height"), + viewConstraints: + widget.control.getBoxConstraints("view_size_constraints"), + viewShape: widget.control.getShape("view_shape", theme), + viewTrailing: widget.control.buildWidgets("view_trailing"), + viewLeading: widget.control.buildWidget("view_leading"), + viewOnSubmitted: onSubmit + ? (String value) { + _updateValue(value); + widget.control.triggerEvent("submit", value); + } + : null, + viewOnChanged: onChange + ? (String value) { + _updateValue(value); + widget.control.triggerEvent("change", value); + } + : null, + textCapitalization: _textCapitalization, + keyboardType: keyboardType, + builder: (BuildContext context, SearchController controller) { + return SearchBar( + controller: controller, + keyboardType: keyboardType, + textCapitalization: _textCapitalization, + autoFocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + hintText: widget.control.getString("bar_hint_text"), + elevation: widget.control.getWidgetStateDouble("bar_elevation"), + shape: + widget.control.getWidgetStateOutlinedBorder("bar_shape", theme), + padding: widget.control.getWidgetStatePadding("bar_padding"), + constraints: + widget.control.getBoxConstraints("bar_size_constraints"), + textStyle: + widget.control.getWidgetStateTextStyle("bar_text_style", theme), + hintStyle: widget.control + .getWidgetStateTextStyle("bar_hint_text_style", theme), + shadowColor: + widget.control.getWidgetStateColor("bar_shadow_color", theme), + side: widget.control + .getWidgetStateBorderSide("bar_border_side", theme), + backgroundColor: + widget.control.getWidgetStateColor("bar_bgcolor", theme), + overlayColor: + widget.control.getWidgetStateColor("bar_overlay_color", theme), + scrollPadding: widget.control + .getPadding("bar_scroll_padding", const EdgeInsets.all(20.0))!, + leading: widget.control.buildWidget("bar_leading"), + trailing: widget.control.buildWidgets("bar_trailing"), + onTap: onTap ? () => widget.control.triggerEvent("tap") : null, + onTapOutside: widget.control.getBool("on_tap_outside_bar", false)! + ? (PointerDownEvent? event) => + widget.control.triggerEvent("tap_outside_bar") + : null, + onSubmitted: onSubmit + ? (String value) { + _updateValue(value); + widget.control.triggerEvent("submit", value); + } + : null, + onChanged: onChange + ? (String value) { + _updateValue(value); + widget.control.triggerEvent("change", value); + } + : null, + ); + }, + suggestionsBuilder: + (BuildContext context, SearchController controller) { + return [ + _SearchBarSuggestionsHost(control: widget.control), + ]; + }); + + return LayoutControl(control: widget.control, child: anchor); + } +} + +class _SearchBarSuggestionsHost extends StatefulWidget { + final Control control; + + const _SearchBarSuggestionsHost({required this.control}); + + @override + State<_SearchBarSuggestionsHost> createState() => + _SearchBarSuggestionsHostState(); +} + +class _SearchBarSuggestionsHostState extends State<_SearchBarSuggestionsHost> { + late List _controls; + + @override + void initState() { + super.initState(); + _controls = widget.control.children("controls"); + widget.control.addListener(_handleControlChange); + } + + @override + void didUpdateWidget(covariant _SearchBarSuggestionsHost oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.control != widget.control) { + oldWidget.control.removeListener(_handleControlChange); + _controls = widget.control.children("controls"); + widget.control.addListener(_handleControlChange); + } + } + + @override + void dispose() { + widget.control.removeListener(_handleControlChange); + super.dispose(); + } + + void _handleControlChange() { + if (!mounted) return; + + var controls = widget.control.children("controls"); + + // compare ids of current and next controls to avoid unnecessary rebuilds + var currentIds = _controls.map((c) => c.id).toList(growable: false); + var nextIds = controls.map((c) => c.id).toList(growable: false); + if (listEquals(currentIds, nextIds)) { + _controls = controls; + return; + } + + // ids differ, update state to trigger rebuild + setState(() { + _controls = controls; + }); + } + + @override + Widget build(BuildContext context) { + if (_controls.isEmpty) { + return const SizedBox.shrink(); + } + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: _controls + .map( + (child) => ControlWidget(key: ValueKey(child.id), control: child)) + .toList(growable: false), + ); + } +} diff --git a/packages/flet/lib/src/controls/segmented_button.dart b/packages/flet/lib/src/controls/segmented_button.dart index 2140eaf2bc..570eed51ac 100644 --- a/packages/flet/lib/src/controls/segmented_button.dart +++ b/packages/flet/lib/src/controls/segmented_button.dart @@ -1,30 +1,20 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/buttons.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; -import 'flet_store_mixin.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import '../widgets/flet_store_mixin.dart'; +import 'base_controls.dart'; class SegmentedButtonControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - const SegmentedButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); + SegmentedButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _SegmentedButtonControlState(); @@ -33,9 +23,10 @@ class SegmentedButtonControl extends StatefulWidget { class _SegmentedButtonControlState extends State with FletStoreMixin { void onChange(Set selection) { - var s = jsonEncode(selection.toList()); - widget.backend.updateControlState(widget.control.id, {"selected": s}); - widget.backend.triggerControlEvent(widget.control.id, "change", s); + var s = + selection.toList(); // TODO: should be sent as set (msgpack limitation) + widget.control.updateProperties({"selected": s}, notify: true); + widget.control.triggerEvent("change", s); } @override @@ -43,10 +34,10 @@ class _SegmentedButtonControlState extends State debugPrint("SegmentedButtonControl build: ${widget.control.id}"); var theme = Theme.of(context); - var style = parseButtonStyle(Theme.of(context), widget.control, "style", + var style = widget.control.getButtonStyle("style", Theme.of(context), defaultForegroundColor: theme.colorScheme.primary, defaultBackgroundColor: theme.colorScheme.surface, - defaultOverlayColor: theme.colorScheme.primary.withOpacity(0.08), + defaultOverlayColor: theme.colorScheme.primary.withValues(alpha: 0.08), defaultShadowColor: theme.colorScheme.shadow, defaultSurfaceTintColor: theme.colorScheme.surfaceTint, defaultElevation: 1, @@ -55,36 +46,31 @@ class _SegmentedButtonControlState extends State ? const StadiumBorder() : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - bool allowEmptySelection = - widget.control.attrBool("allowEmptySelection", false)!; - - bool allowMultipleSelection = - widget.control.attrBool("allowMultipleSelection", false)!; - - Set selected = - (jsonDecode(widget.control.attrString("selected", "[]")!) as List) - .map((e) => e.toString()) - .toSet(); - - List segments = widget.children - .where((c) => c.name == "segment" && c.isVisible) - .toList(); + var allowEmptySelection = + widget.control.getBool("allow_empty_selection", false)!; + var allowMultipleSelection = + widget.control.getBool("allow_multiple_selection", false)!; + var selected = widget.control + .get("selected", [])! + .map((e) => e.toString()) + .toSet(); + var segments = widget.control.children("segments"); if (segments.isEmpty) { return const ErrorControl( - "SegmentedButton.segments must be provided and contain at minimum one visible segment"); + "SegmentedButton.segments must be contain at least one visible segment"); } if (selected.isEmpty && !allowEmptySelection) { return const ErrorControl( - "SegmentedButton.selected must be provided and contain at minimum one value because allow_empty_selection=False"); + "SegmentedButton.selected must contain at least one value because allow_empty_selection=False"); } if (!allowMultipleSelection && selected.length != 1 && !allowEmptySelection) { return const ErrorControl( - "SegmentedButton.selected must be provided and contain exactly one value because allow_multiple_selection=False"); + "SegmentedButton.selected must contain exactly one value because allow_multiple_selection=False"); } if (allowMultipleSelection && selected.length > segments.length) { @@ -92,54 +78,28 @@ class _SegmentedButtonControlState extends State "The length of SegmentedButton.selected must be less than or equal to the number of visible segments"); } - var selectedIcon = - widget.children.where((c) => c.name == "selectedIcon" && c.isVisible); - - bool showSelectedIcon = widget.control.attrBool("showSelectedIcon", true)!; - - bool disabled = widget.control.isDisabled || widget.parentDisabled; - debugPrint("SegmentedButtonControl build: ${widget.control.id}"); - - var sb = withControls(segments.map((s) => s.id), (content, segmentViews) { - return SegmentedButton( - emptySelectionAllowed: allowEmptySelection, - multiSelectionEnabled: allowMultipleSelection, - selected: selected.isNotEmpty ? selected : {}, - showSelectedIcon: showSelectedIcon, - style: style, - selectedIcon: selectedIcon.isNotEmpty - ? createControl(widget.control, selectedIcon.first.id, disabled) - : null, - onSelectionChanged: !disabled - ? (newSelection) { - onChange(newSelection.toSet()); - } - : null, - direction: parseAxis( - widget.control.attrString("direction"), Axis.horizontal)!, - expandedInsets: parseEdgeInsets(widget.control, "padding"), - segments: segmentViews.controlViews.map((segmentView) { - var iconCtrls = segmentView.children - .where((c) => c.name == "icon" && c.isVisible); - var labelCtrls = segmentView.children - .where((c) => c.name == "label" && c.isVisible); - var segmentDisabled = segmentView.control.isDisabled || disabled; - var segmentTooltip = segmentView.control.attrString("tooltip"); - return ButtonSegment( - value: segmentView.control.attrString("value")!, - enabled: !segmentDisabled, - tooltip: segmentDisabled ? null : segmentTooltip, - icon: iconCtrls.isNotEmpty - ? createControl(segmentView.control, iconCtrls.first.id, - segmentDisabled) - : null, - label: labelCtrls.isNotEmpty - ? createControl(segmentView.control, labelCtrls.first.id, - segmentDisabled) - : null); - }).toList()); - }); - - return constrainedControl(context, sb, widget.parent, widget.control); + var segmentedButton = SegmentedButton( + emptySelectionAllowed: allowEmptySelection, + multiSelectionEnabled: allowMultipleSelection, + selected: selected, + showSelectedIcon: widget.control.getBool("show_selected_icon", true)!, + style: style, + selectedIcon: widget.control.buildIconOrWidget("selected_icon"), + onSelectionChanged: !widget.control.disabled + ? (newSelection) => onChange(newSelection) + : null, + direction: widget.control.getAxis("direction", Axis.horizontal)!, + expandedInsets: widget.control.getPadding("padding"), + segments: segments.map((segment) { + segment.notifyParent = true; + return ButtonSegment( + value: segment.getString("value")!, + enabled: !segment.disabled, + tooltip: segment.disabled ? null : segment.getString("tooltip"), + icon: segment.buildIconOrWidget("icon"), + label: segment.buildTextOrWidget("label")); + }).toList()); + + return LayoutControl(control: widget.control, child: segmentedButton); } } diff --git a/packages/flet/lib/src/controls/selection_area.dart b/packages/flet/lib/src/controls/selection_area.dart index ecdae11ff5..f826b2b2d2 100644 --- a/packages/flet/lib/src/controls/selection_area.dart +++ b/packages/flet/lib/src/controls/selection_area.dart @@ -1,47 +1,32 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class SelectionAreaControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const SelectionAreaControl( - {super.key, - required this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const SelectionAreaControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("SelectionArea build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - if (contentCtrls.isEmpty) { + var content = control.buildWidget("content"); + if (content == null) { return const ErrorControl( "SelectionArea.content must be provided and visible"); } - bool disabled = control.isDisabled || parentDisabled; var selectionArea = SelectionArea( - child: createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive), + child: content, onSelectionChanged: (SelectedContent? selection) { - backend.triggerControlEvent(control.id, "change", selection?.plainText); + control.triggerEvent("change", selection?.plainText); }, ); - return baseControl(context, selectionArea, parent, control); + return BaseControl(control: control, child: selectionArea); } } diff --git a/packages/flet/lib/src/controls/semantics.dart b/packages/flet/lib/src/controls/semantics.dart index 6f0b89292d..941ac0a3a8 100644 --- a/packages/flet/lib/src/controls/semantics.dart +++ b/packages/flet/lib/src/controls/semantics.dart @@ -1,165 +1,114 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class SemanticsControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const SemanticsControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + const SemanticsControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("Semantics build: ${control.id}"); - - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - + final content = control.buildWidget("content"); Semantics semantics = Semantics( - label: control.attrString("label"), - enabled: !disabled, - expanded: control.attrBool("expanded"), - hidden: control.attrBool("hidden"), - selected: control.attrBool("selected"), - checked: control.attrBool("checked"), - button: control.attrBool("button"), - slider: control.attrBool("slider"), - value: control.attrString("value"), - textField: control.attrBool("textField"), - image: control.attrBool("image"), - link: control.attrBool("link"), - header: control.attrBool("header"), - increasedValue: control.attrString("increasedValue"), - decreasedValue: control.attrString("decreasedValue"), - hint: control.attrString("hint"), - onTapHint: control.attrString("onTapHint"), - onLongPressHint: control.attrString("onLongPressHint"), - container: control.attrBool("container")!, - liveRegion: control.attrBool("liveRegion"), - obscured: control.attrBool("obscured"), - multiline: control.attrBool("multiline"), - focused: control.attrBool("focused"), - readOnly: control.attrBool("readOnly"), - focusable: control.attrBool("focusable"), - tooltip: control.attrString("tooltip"), - toggled: control.attrBool("toggled"), - maxValueLength: control.attrInt("maxValueLength"), - currentValueLength: control.attrInt("currentValueLength"), - headingLevel: control.attrInt("headingLevel"), - excludeSemantics: control.attrBool("excludeSemantics", false)!, - mixed: control.attrBool("mixed"), - onTap: control.attrBool("onclick", false)! - ? () { - backend.triggerControlEvent(control.id, "click"); - } - : null, - onIncrease: control.attrBool("onIncrease", false)! - ? () { - backend.triggerControlEvent(control.id, "increase"); - } - : null, - onDecrease: control.attrBool("onDecrease", false)! - ? () { - backend.triggerControlEvent(control.id, "decrease"); - } - : null, - onDismiss: control.attrBool("onDismiss", false)! - ? () { - backend.triggerControlEvent(control.id, "dismiss"); - } - : null, - onScrollLeft: control.attrBool("onScrollLeft", false)! - ? () { - backend.triggerControlEvent(control.id, "scrollLeft"); - } - : null, - onScrollRight: control.attrBool("onScrollRight", false)! - ? () { - backend.triggerControlEvent(control.id, "scrollRight"); - } - : null, - onScrollUp: control.attrBool("onScrollUp", false)! - ? () { - backend.triggerControlEvent(control.id, "scrollUp"); - } - : null, - onScrollDown: control.attrBool("onScrollDown", false)! - ? () { - backend.triggerControlEvent(control.id, "scrollDown"); - } - : null, - onCopy: control.attrBool("onCopy", false)! - ? () { - backend.triggerControlEvent(control.id, "copy"); - } - : null, - onCut: control.attrBool("onCut", false)! - ? () { - backend.triggerControlEvent(control.id, "cut"); - } - : null, - onPaste: control.attrBool("onPaste", false)! - ? () { - backend.triggerControlEvent(control.id, "paste"); - } - : null, - onLongPress: control.attrBool("onDismiss", false)! - ? () { - backend.triggerControlEvent(control.id, "dismiss"); - } - : null, - onMoveCursorForwardByCharacter: - control.attrBool("onMoveCursorForwardByCharacter", false)! - ? (bool value) { - backend.triggerControlEvent(control.id, - "move_cursor_forward_by_character", value.toString()); - } - : null, - onMoveCursorBackwardByCharacter: - control.attrBool("onMoveCursorBackwardByCharacter", false)! - ? (bool value) { - backend.triggerControlEvent(control.id, - "move_cursor_backward_by_character", value.toString()); - } - : null, - onDidGainAccessibilityFocus: - control.attrBool("onDidGainAccessibilityFocus", false)! - ? () { - backend.triggerControlEvent( - control.id, "did_gain_accessibility_focus"); - } - : null, - onDidLoseAccessibilityFocus: - control.attrBool("onDidLoseAccessibilityFocus", false)! - ? () { - backend.triggerControlEvent( - control.id, "did_lose_accessibility_focus"); - } - : null, - onSetText: control.attrBool("onSetText", false)! - ? (String text) { - backend.triggerControlEvent(control.id, "set_text", text); - } - : null, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null); + child: content ?? + const ErrorControl("Semantics.content must be provided and visible"), + label: control.getString("label"), + enabled: !control.disabled, + expanded: control.getBool("expanded"), + hidden: control.getBool("hidden"), + selected: control.getBool("selected"), + checked: control.getBool("checked"), + button: control.getBool("button"), + slider: control.getBool("slider"), + value: control.getString("value"), + textField: control.getBool("text_field"), + image: control.getBool("image"), + link: control.getBool("link"), + header: control.getBool("header"), + increasedValue: control.getString("increased_value"), + decreasedValue: control.getString("decreased_value"), + hint: control.getString("hint"), + onTapHint: control.getString("on_tap_hint"), + onLongPressHint: control.getString("on_long_press_hint"), + container: control.getBool("container", false)!, + liveRegion: control.getBool("live_region"), + obscured: control.getBool("obscured"), + multiline: control.getBool("multiline"), + focused: control.getBool("focused"), + readOnly: control.getBool("read_only"), + focusable: control.getBool("focusable"), + tooltip: control.getString("tooltip"), + toggled: control.getBool("toggled"), + maxValueLength: control.getInt("max_value_length"), + currentValueLength: control.getInt("current_value_length"), + headingLevel: control.getInt("heading_level"), + excludeSemantics: control.getBool("exclude_semantics", false)!, + mixed: control.getBool("mixed"), + onTap: control.getBool("on_click", false)! + ? () => control.triggerEvent("click") + : null, + onIncrease: control.getBool("on_increase", false)! + ? () => control.triggerEvent("increase") + : null, + onDecrease: control.getBool("on_decrease", false)! + ? () => control.triggerEvent("decrease") + : null, + onDismiss: control.getBool("on_dismiss", false)! + ? () => control.triggerEvent("dismiss") + : null, + onScrollLeft: control.getBool("on_scroll_left", false)! + ? () => control.triggerEvent("scroll_left") + : null, + onScrollRight: control.getBool("on_scroll_right", false)! + ? () => control.triggerEvent("scroll_right") + : null, + onScrollUp: control.getBool("on_scroll_up", false)! + ? () => control.triggerEvent("scroll_up") + : null, + onScrollDown: control.getBool("on_scroll_down", false)! + ? () => control.triggerEvent("scroll_down") + : null, + onCopy: control.getBool("on_copy", false)! + ? () => control.triggerEvent("copy") + : null, + onCut: control.getBool("on_cut", false)! + ? () => control.triggerEvent("cut") + : null, + onPaste: control.getBool("on_paste", false)! + ? () => control.triggerEvent("paste") + : null, + onLongPress: control.getBool("on_dismiss", false)! + ? () => control.triggerEvent("dismiss") + : null, + onMoveCursorForwardByCharacter: control.getBool( + "on_move_cursor_forward_by_character", false)! + ? (bool value) => + control.triggerEvent("move_cursor_forward_by_character", value) + : null, + onMoveCursorBackwardByCharacter: control.getBool( + "on_move_cursor_backward_by_character", false)! + ? (bool value) => + control.triggerEvent("move_cursor_backward_by_character", value) + : null, + onDidGainAccessibilityFocus: + control.getBool("on_did_gain_accessibility_focus", false)! + ? () => control.triggerEvent("did_gain_accessibility_focus") + : null, + onDidLoseAccessibilityFocus: + control.getBool("on_did_lose_accessibility_focus", false)! + ? () => control.triggerEvent("did_lose_accessibility_focus") + : null, + onSetText: control.getBool("on_set_text", false)! + ? (String text) => control.triggerEvent("set_text", text) + : null, + ); - return constrainedControl(context, semantics, parent, control); + return LayoutControl(control: control, child: semantics); } } diff --git a/packages/flet/lib/src/controls/semantics_service.dart b/packages/flet/lib/src/controls/semantics_service.dart deleted file mode 100644 index 3598649863..0000000000 --- a/packages/flet/lib/src/controls/semantics_service.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/semantics.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; -import '../utils/others.dart'; - -class SemanticsServiceControl extends StatelessWidget { - final Control? parent; - final Control control; - final FletControlBackend backend; - - const SemanticsServiceControl( - {super.key, this.parent, required this.control, required this.backend}); - - @override - Widget build(BuildContext context) { - debugPrint("SemanticsService build: ${control.id}"); - - backend.subscribeMethods(control.id, (methodName, args) async { - var message = args["message"].toString(); - switch (methodName) { - case "announce_message": - debugPrint("SemanticsService.announceMessage($message)"); - var rtl = args["rtl"] == "true"; - var assertiveness = parseAssertiveness( - args["assertiveness"].toString(), Assertiveness.polite)!; - SemanticsService.announce( - message, rtl ? TextDirection.rtl : TextDirection.ltr, - assertiveness: assertiveness); - break; - case "announce_tooltip": - debugPrint("SemanticsService.announceTooltip($message)"); - SemanticsService.tooltip(message); - break; - } - return null; - }); - - return const SizedBox.shrink(); - } -} diff --git a/packages/flet/lib/src/controls/shader_mask.dart b/packages/flet/lib/src/controls/shader_mask.dart index 16dec0618d..7854f65b0a 100644 --- a/packages/flet/lib/src/controls/shader_mask.dart +++ b/packages/flet/lib/src/controls/shader_mask.dart @@ -1,67 +1,38 @@ import 'package:flutter/material.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/borders.dart'; import '../utils/gradient.dart'; import '../utils/images.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; class ShaderMaskControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - const ShaderMaskControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const ShaderMaskControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("ShaderMask build: ${control.id}"); - - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - var blendMode = - parseBlendMode(control.attrString("blendMode"), BlendMode.modulate)!; - bool disabled = control.isDisabled || parentDisabled; - - var gradient = parseGradient(Theme.of(context), control, "shader"); + var gradient = control.getGradient("shader", Theme.of(context)); if (gradient == null) { return const ErrorControl("ShaderMask.shader must be provided"); } - - return constrainedControl( - context, - _clipCorners( - ShaderMask( - shaderCallback: (bounds) { - debugPrint("shaderCallback: $bounds, $gradient"); - return gradient.createShader(bounds); - }, - blendMode: blendMode, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null), - control), - parent, - control); + final shaderMask = ShaderMask( + shaderCallback: (bounds) => gradient.createShader(bounds), + blendMode: control.getBlendMode("blend_mode", BlendMode.modulate)!, + child: control.buildWidget("content")); + return LayoutControl( + control: control, + child: _clipCorners(shaderMask, + borderRadius: control.getBorderRadius("border_radius"))); } - Widget _clipCorners(Widget widget, Control control) { - var borderRadius = parseBorderRadius(control, "borderRadius"); + Widget _clipCorners(Widget widget, {BorderRadius? borderRadius}) { return borderRadius != null - ? ClipRRect( - borderRadius: borderRadius, - child: widget, - ) + ? ClipRRect(borderRadius: borderRadius, child: widget) : widget; } } diff --git a/packages/flet/lib/src/controls/shake_detector.dart b/packages/flet/lib/src/controls/shake_detector.dart deleted file mode 100644 index c3c4bfb1d4..0000000000 --- a/packages/flet/lib/src/controls/shake_detector.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:flutter/widgets.dart'; -import 'package:sensors_plus/sensors_plus.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; - -class ShakeDetectorControl extends StatefulWidget { - final Control? parent; - final Control control; - final Widget? nextChild; - final FletControlBackend backend; - - const ShakeDetectorControl( - {super.key, - required this.parent, - required this.control, - required this.nextChild, - required this.backend}); - - @override - State createState() => _ShakeDetectorControlState(); -} - -class _ShakeDetectorControlState extends State { - ShakeDetector? _shakeDetector; - int? _minimumShakeCount; - int? _shakeSlopTimeMs; - int? _shakeCountResetTimeMs; - double? _shakeThresholdGravity; - - @override - void dispose() { - _shakeDetector?.stopListening(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - debugPrint("ShakeDetector build: ${widget.control.id}"); - - var minimumShakeCount = widget.control.attrInt("minimumShakeCount", 1)!; - var shakeSlopTimeMs = widget.control.attrInt("shakeSlopTimeMs", 500)!; - var shakeCountResetTimeMs = - widget.control.attrInt("shakeCountResetTimeMs", 3000)!; - var shakeThresholdGravity = - widget.control.attrDouble("shakeThresholdGravity", 2.7)!; - - if (minimumShakeCount != _minimumShakeCount || - shakeSlopTimeMs != _shakeSlopTimeMs || - shakeCountResetTimeMs != _shakeCountResetTimeMs || - shakeThresholdGravity != _shakeThresholdGravity) { - _minimumShakeCount = minimumShakeCount; - _shakeSlopTimeMs = shakeSlopTimeMs; - _shakeCountResetTimeMs = shakeCountResetTimeMs; - _shakeThresholdGravity = shakeThresholdGravity; - - _shakeDetector?.stopListening(); - _shakeDetector = ShakeDetector.autoStart( - onPhoneShake: () { - widget.backend.triggerControlEvent(widget.control.id, "shake"); - }, - minimumShakeCount: minimumShakeCount, - shakeSlopTimeMS: shakeSlopTimeMs, - shakeCountResetTime: shakeCountResetTimeMs, - shakeThresholdGravity: shakeThresholdGravity, - ); - } - - return widget.nextChild ?? const SizedBox.shrink(); - } -} - -/* -Source: https://github.com/dieringe/shake/blob/master/lib/shake.dart - -Copyright 2019 Deven Joshi - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/// Callback for phone shakes -typedef PhoneShakeCallback = void Function(); - -/// ShakeDetector class for phone shake functionality -class ShakeDetector { - /// User callback for phone shake - final PhoneShakeCallback onPhoneShake; - - /// Shake detection threshold - final double shakeThresholdGravity; - - /// Minimum time between shake - final int shakeSlopTimeMS; - - /// Time before shake count resets - final int shakeCountResetTime; - - /// Number of shakes required before shake is triggered - final int minimumShakeCount; - - int mShakeTimestamp = DateTime.now().millisecondsSinceEpoch; - int mShakeCount = 0; - - /// StreamSubscription for Accelerometer events - StreamSubscription? streamSubscription; - - /// This constructor waits until [startListening] is called - ShakeDetector.waitForStart({ - required this.onPhoneShake, - this.shakeThresholdGravity = 2.7, - this.shakeSlopTimeMS = 500, - this.shakeCountResetTime = 3000, - this.minimumShakeCount = 1, - }); - - /// This constructor automatically calls [startListening] and starts detection and callbacks. - ShakeDetector.autoStart({ - required this.onPhoneShake, - this.shakeThresholdGravity = 2.7, - this.shakeSlopTimeMS = 500, - this.shakeCountResetTime = 3000, - this.minimumShakeCount = 1, - }) { - startListening(); - } - - /// Starts listening to accelerometer events - void startListening() { - streamSubscription = accelerometerEventStream().listen( - (AccelerometerEvent event) { - double x = event.x; - double y = event.y; - double z = event.z; - - double gX = x / 9.80665; - double gY = y / 9.80665; - double gZ = z / 9.80665; - - // gForce will be close to 1 when there is no movement. - double gForce = sqrt(gX * gX + gY * gY + gZ * gZ); - - if (gForce > shakeThresholdGravity) { - var now = DateTime.now().millisecondsSinceEpoch; - // ignore shake events too close to each other (500ms) - if (mShakeTimestamp + shakeSlopTimeMS > now) { - return; - } - - // reset the shake count after 3 seconds of no shakes - if (mShakeTimestamp + shakeCountResetTime < now) { - mShakeCount = 0; - } - - mShakeTimestamp = now; - mShakeCount++; - - if (mShakeCount >= minimumShakeCount) { - onPhoneShake(); - } - } - }, - ); - } - - /// Stops listening to accelerometer events - void stopListening() { - streamSubscription?.cancel(); - } -} diff --git a/packages/flet/lib/src/controls/shimmer.dart b/packages/flet/lib/src/controls/shimmer.dart new file mode 100644 index 0000000000..6f02855951 --- /dev/null +++ b/packages/flet/lib/src/controls/shimmer.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; +import '../utils/enums.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/colors.dart'; +import '../utils/gradient.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; + +class ShimmerControl extends StatelessWidget { + final Control control; + + const ShimmerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("Shimmer build: ${control.id}"); + + final content = control.buildWidget("content"); + if (content == null) { + return const ErrorControl("Shimmer.content must be specified"); + } + + final gradient = control.getGradient("gradient", Theme.of(context)); + final baseColor = control.getColor("base_color", context); + final highlightColor = control.getColor("highlight_color", context); + + if (gradient == null && (baseColor == null || highlightColor == null)) { + return const ErrorControl( + "Shimmer requires either gradient or base/highlight colors"); + } + + final direction = _parseDirection(control.getString("direction")); + final period = + control.getDuration("period", const Duration(milliseconds: 1500))!; + final loop = control.getInt("loop", 0)!; + + final shimmerWidget = gradient != null + ? Shimmer( + gradient: gradient, + direction: direction, + period: period, + loop: loop, + enabled: !control.disabled, + child: content, + ) + : Shimmer.fromColors( + baseColor: baseColor!, + highlightColor: highlightColor!, + direction: direction, + period: period, + loop: loop, + enabled: !control.disabled, + child: content, + ); + + return LayoutControl(control: control, child: shimmerWidget); + } +} + +ShimmerDirection _parseDirection(String? value, + [ShimmerDirection defaultValue = ShimmerDirection.ltr]) { + return parseEnum(ShimmerDirection.values, value, defaultValue)!; +} diff --git a/packages/flet/lib/src/controls/slider.dart b/packages/flet/lib/src/controls/slider.dart index b46934aaad..81e1c28fe0 100644 --- a/packages/flet/lib/src/controls/slider.dart +++ b/packages/flet/lib/src/controls/slider.dart @@ -1,39 +1,25 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/colors.dart'; -import '../utils/debouncer.dart'; import '../utils/edge_insets.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import '../utils/platform.dart'; -import 'create_control.dart'; -import 'cupertino_slider.dart'; -import 'flet_store_mixin.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class SliderControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - const SliderControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + SliderControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _SliderControlState(); } -class _SliderControlState extends State with FletStoreMixin { +class _SliderControlState extends State { double _value = 0; - final _debouncer = Debouncer(milliseconds: isDesktopPlatform() ? 10 : 100); late final FocusNode _focusNode; @override @@ -45,104 +31,81 @@ class _SliderControlState extends State with FletStoreMixin { @override void dispose() { - _debouncer.dispose(); _focusNode.removeListener(_onFocusChange); _focusNode.dispose(); super.dispose(); } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } void onChange(double value) { - var svalue = value.toString(); - debugPrint(svalue); _value = value; - var props = {"value": svalue}; - widget.backend.updateControlState(widget.control.id, props, server: false); - _debouncer.run(() { - widget.backend.updateControlState(widget.control.id, props); - widget.backend.triggerControlEvent(widget.control.id, "change"); - }); + var props = {"value": value}; + widget.control.updateProperties(props, notify: true); + widget.control.triggerEvent("change", value); } @override Widget build(BuildContext context) { debugPrint("SliderControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoSliderControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - backend: widget.backend); - } - - String? label = widget.control.attrString("label"); - double min = widget.control.attrDouble("min", 0)!; - double max = widget.control.attrDouble("max", 1)!; - int round = widget.control.attrInt("round", 0)!; + var label = widget.control.getString("label"); + var min = widget.control.getDouble("min", 0)!; + var max = widget.control.getDouble("max", 1)!; + var round = widget.control.getInt("round", 0)!; - double value = widget.control.attrDouble("value", min)!; - if (_value != value) { - // verify limits - if (value < min) { - _value = min; - } else if (value > max) { - _value = max; - } else { - _value = value; - } + double value = widget.control.getDouble("value", min)!; + if (_value != value) { + // verify limits + if (value < min) { + _value = min; + } else if (value > max) { + _value = max; + } else { + _value = value; } + } - var slider = Slider( - autofocus: widget.control.attrBool("autofocus", false)!, - focusNode: _focusNode, - value: _value, - min: min, - max: max, - year2023: widget.control.attrBool("year2023"), - divisions: widget.control.attrInt("divisions"), - label: label?.replaceAll("{value}", _value.toStringAsFixed(round)), - activeColor: widget.control.attrColor("activeColor", context), - inactiveColor: widget.control.attrColor("inactiveColor", context), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "overlayColor"), - allowedInteraction: - parseSliderInteraction(widget.control.attrString("interaction")), - thumbColor: widget.control.attrColor("thumbColor", context), - padding: parseEdgeInsets(widget.control, "padding"), - onChanged: !disabled - ? (double value) { - onChange(value); - } - : null, - mouseCursor: - parseMouseCursor(widget.control.attrString("mouseCursor")), - secondaryActiveColor: - widget.control.attrColor("secondaryActiveColor", context), - secondaryTrackValue: widget.control.attrDouble("secondaryTrackValue"), - onChangeStart: !disabled - ? (double value) { - widget.backend.triggerControlEvent( - widget.control.id, "change_start", value.toString()); - } - : null, - onChangeEnd: !disabled - ? (double value) { - widget.backend.triggerControlEvent( - widget.control.id, "change_end", value.toString()); - } - : null); + var slider = Slider( + autofocus: widget.control.getBool("autofocus", false)!, + focusNode: _focusNode, + value: _value, + min: min, + max: max, + // todo: remove deprecated property year2023 + // ignore: deprecated_member_use + year2023: widget.control.getBool("year_2023"), + divisions: widget.control.getInt("divisions"), + label: label?.replaceAll("{value}", _value.toStringAsFixed(round)), + activeColor: widget.control.getColor("active_color", context), + inactiveColor: widget.control.getColor("inactive_color", context), + overlayColor: widget.control + .getWidgetStateColor("overlay_color", Theme.of(context)), + allowedInteraction: widget.control.getSliderInteraction("interaction"), + thumbColor: widget.control.getColor("thumb_color", context), + padding: widget.control.getPadding("padding"), + onChanged: !widget.control.disabled + ? (double value) { + onChange(value); + } + : null, + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + secondaryActiveColor: + widget.control.getColor("secondary_active_color", context), + secondaryTrackValue: widget.control.getDouble("secondary_track_value"), + onChangeStart: !widget.control.disabled + ? (double value) { + widget.control.triggerEvent("change_start", value); + } + : null, + onChangeEnd: !widget.control.disabled + ? (double value) { + widget.control.triggerEvent("change_end", value); + } + : null); - return constrainedControl(context, slider, widget.parent, widget.control); - }); + return LayoutControl(control: widget.control, child: slider); } } diff --git a/packages/flet/lib/src/controls/snack_bar.dart b/packages/flet/lib/src/controls/snack_bar.dart index d545d39779..25fc295451 100644 --- a/packages/flet/lib/src/controls/snack_bar.dart +++ b/packages/flet/lib/src/controls/snack_bar.dart @@ -1,68 +1,56 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/dismissible.dart'; import '../utils/edge_insets.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'error.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; +import '../widgets/error.dart'; -class SnackBarControl extends StatefulWidget { - final Control? parent; +class SnackBarControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final Widget? nextChild; - final FletControlBackend backend; - - const SnackBarControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.nextChild, - required this.backend}); - @override - State createState() => _SnackBarControlState(); -} - -class _SnackBarControlState extends State { - bool _open = false; - - Widget _createSnackBar() { - bool disabled = widget.control.isDisabled || widget.parentDisabled; - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); + const SnackBarControl({super.key, required this.control}); - if (contentCtrls.isEmpty) { + Widget _createSnackBar(BuildContext context) { + var content = control.buildTextOrWidget("content"); + if (content == null) { return const ErrorControl( "SnackBar.content must be provided and visible"); } - var actionName = widget.control.attrString("action", "")!; - SnackBarAction? action = actionName != "" - ? SnackBarAction( - label: actionName, - textColor: widget.control.attrColor("actionColor", context), - onPressed: () { - debugPrint("SnackBar ${widget.control.id} clicked!"); - widget.backend.triggerControlEvent(widget.control.id, "action"); - }) - : null; - - SnackBarBehavior? behavior = - parseSnackBarBehavior(widget.control.attrString("behavior")); + var backend = FletBackend.of(context); + + final actionControl = control.get("action"); + SnackBarAction? action; + if (actionControl is Control) { + action = SnackBarAction( + label: actionControl.getString("label", "Action")!, + backgroundColor: actionControl.getColor("bgcolor", context), + textColor: actionControl.getColor("text_color", context), + disabledBackgroundColor: + actionControl.getColor("disabled_bgcolor", context), + disabledTextColor: + actionControl.getColor("disabled_text_color", context), + onPressed: () => actionControl.triggerEvent("click"), + ); + } else if (actionControl is String) { + action = SnackBarAction( + label: actionControl, + onPressed: () => control.triggerEvent("action"), + ); + } - var width = widget.control.attrDouble("width"); - var margin = parseEdgeInsets(widget.control, "margin"); + var width = control.getDouble("width"); + var margin = control.getMargin("margin"); // if behavior is not floating, ignore margin and width + SnackBarBehavior? behavior = control.getSnackBarBehavior("behavior"); if (behavior != SnackBarBehavior.floating) { margin = null; width = null; @@ -72,62 +60,74 @@ class _SnackBarControlState extends State { margin = (width != null && margin != null) ? null : margin; return SnackBar( - behavior: behavior, - clipBehavior: parseClip( - widget.control.attrString("clipBehavior"), Clip.hardEdge)!, - actionOverflowThreshold: - widget.control.attrDouble("actionOverflowThreshold"), - shape: parseOutlinedBorder(widget.control, "shape"), - onVisible: () { - debugPrint("SnackBar.onVisible(${widget.control.id})"); - widget.backend.triggerControlEvent(widget.control.id, "visible"); - }, - dismissDirection: parseDismissDirection( - widget.control.attrString("dismissDirection")), - showCloseIcon: widget.control.attrBool("showCloseIcon"), - closeIconColor: widget.control.attrColor("closeIconColor", context), - content: createControl(widget.control, contentCtrls.first.id, disabled, - parentAdaptive: widget.parentAdaptive), - backgroundColor: widget.control.attrColor("bgColor", context), - action: action, - margin: margin, - padding: parseEdgeInsets(widget.control, "padding"), - width: width, - elevation: widget.control.attrDouble("elevation"), - duration: - Duration(milliseconds: widget.control.attrInt("duration", 4000)!)); + behavior: behavior, + clipBehavior: control.getClipBehavior("clip_behavior", Clip.hardEdge)!, + actionOverflowThreshold: control.getDouble("action_overflow_threshold"), + shape: control.getOutlinedBorder("shape", Theme.of(context)), + onVisible: () { + backend.triggerControlEvent(control, "visible"); + }, + dismissDirection: control.getDismissDirection("dismiss_direction"), + showCloseIcon: control.getBool("show_close_icon"), + closeIconColor: control.getColor("close_icon_color", context), + content: content, + backgroundColor: control.getColor("bgcolor", context), + action: action, + margin: margin, + padding: control.getPadding("padding"), + width: width, + elevation: control.getDouble("elevation"), + duration: + control.getDuration("duration", const Duration(milliseconds: 4000))!, + persist: control.getBool("persist"), + ); } @override Widget build(BuildContext context) { - debugPrint("SnackBar build: ${widget.control.id}"); + final dismissed = control.getBool("_dismissed", false)!; - var open = widget.control.attrBool("open", false)!; - var removeCurrentSnackbar = true; + if (!dismissed) { + final open = control.getBool("open", false)!; + final lastOpen = control.getBool("_open", false)!; - //widget.control.attrBool("removeCurrentSnackBar", false)!; + debugPrint( + "SnackBar build: ${control.id}, open: $open, _open: $lastOpen"); - debugPrint("Current open state: $_open"); - debugPrint("New open state: $open"); - - if (open && (open != _open)) { - var snackBar = _createSnackBar(); - if (snackBar is ErrorControl) { - return snackBar; - } + if (open && (open != lastOpen)) { + var dialog = _createSnackBar(context); - WidgetsBinding.instance.addPostFrameCallback((_) { - if (removeCurrentSnackbar) { - ScaffoldMessenger.of(context).removeCurrentSnackBar(); + if (dialog is ErrorControl) { + debugPrint( + "SnackBar: ErrorControl, not showing dialog: ${dialog.message}"); + return dialog; } - ScaffoldMessenger.of(context).showSnackBar(snackBar as SnackBar); - - widget.backend.updateControlState(widget.control.id, {"open": "false"}); - }); - } - _open = open; + control.updateProperties({"_open": open}, python: false); - return widget.nextChild ?? const SizedBox.shrink(); + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).removeCurrentSnackBar(); + ScaffoldMessenger.of(context) + .showSnackBar(dialog as SnackBar) + .closed + .then((reason) { + if (!dismissed) { + control.updateProperties({"_dismissed": true}); + debugPrint( + "Dismissing SnackBar(${control.id}) with reason: $reason"); + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"open": false}); + control.triggerEvent("dismiss"); + } + }); + }); + } else if (!open && lastOpen) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).removeCurrentSnackBar(); + control.updateProperties({"_open": false}, python: false); + }); + } + } + return const SizedBox.shrink(); } } diff --git a/packages/flet/lib/src/controls/stack.dart b/packages/flet/lib/src/controls/stack.dart index f72d5a6e93..8540f8c4a1 100644 --- a/packages/flet/lib/src/controls/stack.dart +++ b/packages/flet/lib/src/controls/stack.dart @@ -1,51 +1,31 @@ import 'package:flutter/widgets.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/alignment.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class StackControl extends StatelessWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - const StackControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + const StackControl({ + super.key, + required this.control, + }); @override Widget build(BuildContext context) { debugPrint("Stack build: ${control.id}"); - bool disabled = control.isDisabled || parentDisabled; - bool? adaptive = control.attrBool("adaptive") ?? parentAdaptive; - - var clipBehavior = - parseClip(control.attrString("clipBehavior"), Clip.hardEdge)!; - - StackFit fit = parseStackFit(control.attrString("fit"), StackFit.loose)!; - var ctrls = children - .where((c) => c.isVisible) - .map((c) => - createControl(control, c.id, disabled, parentAdaptive: adaptive)) - .toList(); - - return constrainedControl( - context, - Stack( - clipBehavior: clipBehavior, - fit: fit, - alignment: parseAlignment(control, "alignment") ?? - AlignmentDirectional.topStart, - children: ctrls, - ), - parent, - control); + final stack = Stack( + clipBehavior: + parseClip(control.getString("clip_behavior"), Clip.hardEdge)!, + fit: control.getStackFit("fit", StackFit.loose)!, + alignment: + control.getAlignment("alignment") ?? AlignmentDirectional.topStart, + children: control.buildWidgets("controls"), + ); + return LayoutControl(control: control, child: stack); } } diff --git a/packages/flet/lib/src/controls/submenu_button.dart b/packages/flet/lib/src/controls/submenu_button.dart index 13648027bf..58ff77d05f 100644 --- a/packages/flet/lib/src/controls/submenu_button.dart +++ b/packages/flet/lib/src/controls/submenu_button.dart @@ -1,33 +1,25 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; import '../utils/buttons.dart'; import '../utils/menu.dart'; -import '../utils/others.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import '../utils/transforms.dart'; -import 'create_control.dart'; +import 'base_controls.dart'; -class SubMenuButtonControl extends StatefulWidget { - final Control? parent; +class SubmenuButtonControl extends StatefulWidget { final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - const SubMenuButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); + SubmenuButtonControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override - State createState() => _SubMenuButtonControlState(); + State createState() => _SubmenuButtonControlState(); } -class _SubMenuButtonControlState extends State { +class _SubmenuButtonControlState extends State { late final FocusNode _focusNode; String? _lastFocusValue; @@ -46,26 +38,15 @@ class _SubMenuButtonControlState extends State { } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @override Widget build(BuildContext context) { debugPrint("SubMenuButton build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - var content = - widget.children.where((c) => c.name == "content" && c.isVisible); - var ctrls = - widget.children.where((c) => c.name == "controls" && c.isVisible); - var leading = - widget.children.where((c) => c.name == "leading" && c.isVisible); - var trailing = - widget.children.where((c) => c.name == "trailing" && c.isVisible); var theme = Theme.of(context); - var style = parseButtonStyle(Theme.of(context), widget.control, "style", + var style = widget.control.getButtonStyle("style", Theme.of(context), defaultForegroundColor: theme.colorScheme.primary, defaultBackgroundColor: Colors.transparent, defaultOverlayColor: Colors.transparent, @@ -78,53 +59,38 @@ class _SubMenuButtonControlState extends State { ? const StadiumBorder() : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - bool onOpen = widget.control.attrBool("onOpen", false)!; - bool onClose = widget.control.attrBool("onClose", false)!; - bool onHover = widget.control.attrBool("onHover", false)!; + bool onOpen = widget.control.getBool("on_open", false)!; + bool onClose = widget.control.getBool("on_close", false)!; + bool onHover = widget.control.getBool("on_hover", false)!; - var subMenu = SubmenuButton( + var subMenuButton = SubmenuButton( focusNode: _focusNode, clipBehavior: - parseClip(widget.control.attrString("clipBehavior"), Clip.hardEdge)!, + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!, style: style, - menuStyle: parseMenuStyle(Theme.of(context), widget.control, "menuStyle"), - alignmentOffset: parseOffset(widget.control, "alignmentOffset"), - onClose: onClose && !disabled - ? () { - widget.backend.triggerControlEvent(widget.control.id, "close"); - } - : null, - onHover: onHover && !disabled - ? (bool value) { - widget.backend - .triggerControlEvent(widget.control.id, "hover", "$value"); - } - : null, - onOpen: onOpen && !disabled - ? () { - widget.backend.triggerControlEvent(widget.control.id, "open"); - } - : null, - leadingIcon: leading.isNotEmpty - ? createControl(widget.control, leading.first.id, disabled) + menuStyle: widget.control.getMenuStyle("menu_style", Theme.of(context)), + alignmentOffset: widget.control.getOffset("alignment_offset"), + onClose: onClose && !widget.control.disabled + ? () => widget.control.triggerEvent("close") : null, - trailingIcon: trailing.isNotEmpty - ? createControl(widget.control, trailing.first.id, disabled) + onHover: onHover && !widget.control.disabled + ? (bool value) => widget.control.triggerEvent("hover", value) : null, - menuChildren: ctrls.map((c) { - return createControl(widget.control, c.id, disabled); - }).toList(), - child: content.isNotEmpty - ? createControl(widget.control, content.first.id, disabled) + onOpen: onOpen && !widget.control.disabled + ? () => widget.control.triggerEvent("open") : null, + leadingIcon: widget.control.buildWidget("leading"), + trailingIcon: widget.control.buildWidget("trailing"), + menuChildren: widget.control.buildWidgets("controls"), + child: widget.control.buildTextOrWidget("content"), ); - var focusValue = widget.control.attrString("focus"); + var focusValue = widget.control.getString("focus"); if (focusValue != null && focusValue != _lastFocusValue) { _lastFocusValue = focusValue; _focusNode.requestFocus(); } - return constrainedControl(context, subMenu, widget.parent, widget.control); + return LayoutControl(control: widget.control, child: subMenuButton); } } diff --git a/packages/flet/lib/src/controls/switch.dart b/packages/flet/lib/src/controls/switch.dart index 9dd25e4aff..eb47a95ef6 100644 --- a/packages/flet/lib/src/controls/switch.dart +++ b/packages/flet/lib/src/controls/switch.dart @@ -1,191 +1,172 @@ -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/colors.dart'; +import '../utils/edge_insets.dart'; import '../utils/icons.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; import '../utils/numbers.dart'; -import '../utils/others.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'cupertino_switch.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; import 'list_tile.dart'; class SwitchControl extends StatefulWidget { - final Control? parent; final Control control; - final bool parentDisabled; - final bool? parentAdaptive; - final List children; - final FletControlBackend backend; - - const SwitchControl( - {super.key, - this.parent, - required this.control, - required this.parentDisabled, - required this.parentAdaptive, - required this.children, - required this.backend}); + + SwitchControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _SwitchControlState(); } -class _SwitchControlState extends State with FletStoreMixin { +class _SwitchControlState extends State { bool _value = false; late final FocusNode _focusNode; + Listenable? _tileClicksNotifier; @override void initState() { super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); + _focusNode = FocusNode()..addListener(_onFocusChange); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final newNotifier = ListTileClicks.of(context)?.notifier; + + // If the inherited source changed, swap listeners + if (!identical(_tileClicksNotifier, newNotifier)) { + _tileClicksNotifier?.removeListener(_toggleValue); + _tileClicksNotifier = newNotifier; + _tileClicksNotifier?.addListener(_toggleValue); + } } @override void dispose() { _focusNode.removeListener(_onFocusChange); + _tileClicksNotifier?.removeListener(_toggleValue); _focusNode.dispose(); super.dispose(); } + void _toggleValue() { + _onChange(!_value); + } + void _onChange(bool value) { - var svalue = value.toString(); - debugPrint(svalue); _value = value; - widget.backend.updateControlState(widget.control.id, {"value": svalue}); - widget.backend.triggerControlEvent(widget.control.id, "change", svalue); + var props = {"value": value}; + widget.control.updateProperties(props, notify: true); + widget.control.triggerEvent("change", value); } void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, - _focusNode.hasFocus ? "focus" : "blur", - _focusNode.hasPrimaryFocus.toString()); + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); } @override Widget build(BuildContext context) { debugPrint("SwitchControl build: ${widget.control.id}"); - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoSwitchControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - backend: widget.backend); + var label = widget.control.get("label"); + LabelPosition labelPosition = + widget.control.getLabelPosition("label_position", LabelPosition.right)!; + double? width = widget.control.getDouble("width"); + double? height = widget.control.getDouble("height"); + bool autofocus = widget.control.getBool("autofocus", false)!; + + TextStyle? labelStyle = + widget.control.getTextStyle("label_text_style", Theme.of(context)); + if (widget.control.disabled && labelStyle != null) { + labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); + } + + bool value = widget.control.getBool("value", false)!; + if (_value != value) { + _value = value; + } + ThemeData theme = Theme.of(context); + + var s = Switch( + autofocus: autofocus, + padding: widget.control.getPadding("padding"), + focusNode: _focusNode, + activeThumbColor: widget.control.getColor("active_color", context), + activeTrackColor: + widget.control.getColor("active_track_color", context), + inactiveThumbColor: + widget.control.getColor("inactive_thumb_color", context), + inactiveTrackColor: + widget.control.getColor("inactive_track_color", context), + thumbColor: widget.control.getWidgetStateColor("thumb_color", theme), + thumbIcon: widget.control.getWidgetStateIcon("thumb_icon", theme), + trackColor: widget.control.getWidgetStateColor("track_color", theme), + focusColor: widget.control.getColor("focus_color", context), + value: _value, + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + splashRadius: widget.control.getDouble("splash_radius"), + hoverColor: widget.control.getColor("hover_color", context), + overlayColor: + widget.control.getWidgetStateColor("overlay_color", theme), + trackOutlineColor: + widget.control.getWidgetStateColor("track_outline_color", theme), + trackOutlineWidth: + widget.control.getWidgetStateDouble("track_outline_width"), + onChanged: !widget.control.disabled + ? (bool value) { + _onChange(value); + } + : null); + + Widget result = s; + + if (label is Control || (label is String)) { + Widget? labelWidget; + if (label is Control) { + labelWidget = ControlWidget(control: label); + } else { + labelWidget = widget.control.disabled + ? Text(label, style: labelStyle) + : MouseRegion( + cursor: SystemMouseCursors.click, + child: Text(label, style: labelStyle)); } - var label = widget.children.firstWhereOrNull((c) => c.isVisible); - String labelStr = widget.control.attrString("label", "")!; - LabelPosition labelPosition = parseLabelPosition( - widget.control.attrString("labelPosition"), LabelPosition.right)!; - double? width = widget.control.attrDouble("width"); - double? height = widget.control.attrDouble("height"); - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - TextStyle? labelStyle = - parseTextStyle(Theme.of(context), widget.control, "labelStyle"); - if (disabled && labelStyle != null) { - labelStyle = labelStyle.apply(color: Theme.of(context).disabledColor); - } - - bool value = widget.control.attrBool("value", false)!; - if (_value != value) { - _value = value; - } - - var s = Switch( - autofocus: autofocus, - focusNode: _focusNode, - activeColor: widget.control.attrColor("activeColor", context), - activeTrackColor: - widget.control.attrColor("activeTrackColor", context), - inactiveThumbColor: - widget.control.attrColor("inactiveThumbColor", context), - inactiveTrackColor: - widget.control.attrColor("inactiveTrackColor", context), - thumbColor: parseWidgetStateColor( - Theme.of(context), widget.control, "thumbColor"), - thumbIcon: parseWidgetStateIcon( - Theme.of(context), widget.control, "thumbIcon"), - trackColor: parseWidgetStateColor( - Theme.of(context), widget.control, "trackColor"), - focusColor: widget.control.attrColor("focusColor", context), - value: _value, - mouseCursor: - parseMouseCursor(widget.control.attrString("mouseCursor")), - splashRadius: widget.control.attrDouble("splashRadius"), - hoverColor: widget.control.attrColor("hoverColor", context), - overlayColor: parseWidgetStateColor( - Theme.of(context), widget.control, "overlayColor"), - trackOutlineColor: parseWidgetStateColor( - Theme.of(context), widget.control, "trackOutlineColor"), - trackOutlineWidth: - parseWidgetStateDouble(widget.control, "trackOutlineWidth"), - onChanged: !disabled - ? (bool value) { - _onChange(value); + result = MergeSemantics( + child: GestureDetector( + onTap: !widget.control.disabled + ? () { + _onChange(!_value); } - : null); - - ListTileClicks.of(context)?.notifier.addListener(() { - _onChange(!_value); - }); - - Widget result = s; - if (label != null || (labelStr != "")) { - Widget? labelWidget; - if (label != null) { - labelWidget = createControl(widget.control, label.id, disabled); - } else { - labelWidget = disabled - ? Text(labelStr, style: labelStyle) - : MouseRegion( - cursor: SystemMouseCursors.click, - child: Text(labelStr, style: labelStyle)); - } - - result = MergeSemantics( - child: GestureDetector( - onTap: !disabled - ? () { - _onChange(!_value); - } - : null, - child: labelPosition == LabelPosition.right - ? Row( - // mainAxisSize: MainAxisSize.min, - children: [result, labelWidget], - ) - : Row( - mainAxisSize: MainAxisSize.min, - children: [labelWidget, result], - ), - ), - ); - } - if (width != null || height != null) { - result = SizedBox( - width: width, - height: height, - child: FittedBox( - fit: BoxFit.fill, - child: result, - ), - ); - } - - return constrainedControl(context, result, widget.parent, widget.control); - }); + : null, + child: labelPosition == LabelPosition.right + ? Row( + mainAxisSize: MainAxisSize.min, + children: [result, labelWidget], + ) + : Row( + mainAxisSize: MainAxisSize.min, + children: [labelWidget, result], + ), + ), + ); + } + + // a hack to size the switch + if (width != null || height != null) { + result = SizedBox( + width: width, + height: height, + child: FittedBox(fit: BoxFit.fill, child: result), + ); + } + + return LayoutControl(control: widget.control, child: result); + // }); } } diff --git a/packages/flet/lib/src/controls/tabs.dart b/packages/flet/lib/src/controls/tabs.dart index ba1752f25a..28ecd1523e 100644 --- a/packages/flet/lib/src/controls/tabs.dart +++ b/packages/flet/lib/src/controls/tabs.dart @@ -1,39 +1,33 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import '../flet_control_backend.dart'; -import '../models/app_state.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import '../models/controls_view_model.dart'; import '../utils/alignment.dart'; +import '../utils/animations.dart'; import '../utils/borders.dart'; import '../utils/colors.dart'; import '../utils/edge_insets.dart'; -import '../utils/icons.dart'; -import '../utils/material_state.dart'; +import '../utils/keys.dart'; +import '../utils/layout.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; +import '../utils/numbers.dart'; +import '../utils/tabs.dart'; import '../utils/text.dart'; -import 'create_control.dart'; +import '../utils/time.dart'; +import '../widgets/control_inherited_notifier.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; +import 'control_widget.dart'; + +/// Default duration for tab animation if none is provided. +const Duration kDefaultTabAnimationDuration = Duration(milliseconds: 100); class TabsControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const TabsControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + TabsControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _TabsControlState(); @@ -41,275 +35,387 @@ class TabsControl extends StatefulWidget { class _TabsControlState extends State with TickerProviderStateMixin { - String? _tabsSnapshot; - TabController? _tabController; - int _selectedIndex = 0; + late TabController _tabController; + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + _initTabController(); + } + + @override + void didUpdateWidget(TabsControl oldWidget) { + super.didUpdateWidget(oldWidget); + final animationDuration = widget.control + .getDuration("animation_duration", kDefaultTabAnimationDuration)!; + final newLength = widget.control.getInt("length", 0)!; + final newSelectedIndex = widget.control.getInt("selected_index", 0)!; + + // Resolve Python-style negative index (e.g., -1 means last tab) + final resolvedIndex = + newSelectedIndex < 0 ? newLength + newSelectedIndex : newSelectedIndex; + + // Clamp the index to ensure it's within [0, length - 1] + final selectedIndex = resolvedIndex.clamp(0, newLength - 1); + + // If the number of tabs has changed, we must recreate the controller + if (newLength != _tabController.length) { + // Save the current index before disposing the controller + int currentIndex = _tabController.index; + + // Dispose of the old controller + _tabController.dispose(); + + // Update selected_index so we can preserve the current selection + widget.control.updateProperties({"selected_index": currentIndex}); + + // Re-initialize the TabController with the new length + _initTabController(currentIndex); + } + + // If the selected tab has changed, animate to the new tab + else if (selectedIndex != _tabController.index) { + _tabController.animateTo( + selectedIndex, + duration: animationDuration, + curve: Curves.ease, + ); + } + } + + void _initTabController([int? index]) { + final animationDuration = widget.control + .getDuration("animation_duration", kDefaultTabAnimationDuration)!; + final length = widget.control.getInt("length", 0)!; + final selectedIndex = index ?? widget.control.getInt("selected_index", 0)!; + + // Support Python-style negative indices (e.g., -1 is the last tab) + final resolvedIndex = + selectedIndex < 0 ? length + selectedIndex : selectedIndex; + + // Clamp to ensure initialIndex is within [0, length - 1] + final initialIndex = resolvedIndex.clamp(0, length - 1); + + _tabController = TabController( + length: length, + initialIndex: initialIndex, + vsync: this, + animationDuration: animationDuration, + ); + _tabController.addListener(_handleTabSelection); + } + + void _handleTabSelection() { + if (!_tabController.indexIsChanging) { + // Update the selected_index property to reflect the current tab + widget.control.updateProperties({"selected_index": _tabController.index}); + widget.control.triggerEvent("change", _tabController.index); + } + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("TabsControl.$name($args)"); + switch (name) { + case "move_to": + return _tabController.animateTo( + args["index"], + curve: parseCurve(args["curve"], Curves.ease)!, + duration: + parseDuration(args["duration"], kDefaultTabAnimationDuration)!, + ); + default: + throw Exception("Unknown Tabs method: $name"); + } + } @override void dispose() { - _tabController?.removeListener(_tabChanged); - _tabController?.dispose(); + _tabController.removeListener(_handleTabSelection); + widget.control.removeInvokeMethodListener(_invokeMethod); + _tabController.dispose(); super.dispose(); } - void _tabChanged() { - if (_tabController!.indexIsChanging == true) { - return; + @override + Widget build(BuildContext context) { + debugPrint("TabsControl build: ${widget.control.id}"); + var content = widget.control.buildWidget("content"); + if (content == null) { + return const ErrorControl("Tabs.content must be provided and visible"); + } + + return LayoutControl(control: widget.control, child: content); + } +} + +class TabBarViewControl extends StatelessWidget { + final Control control; + + const TabBarViewControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("TabBarViewControl build: ${control.id}"); + + // Find the TabController from the nearest TabsControl ancestor + final tabsState = context.findAncestorStateOfType<_TabsControlState>(); + if (tabsState == null) { + return const ErrorControl( + "TabBarView must be used within a Tabs control"); + } + + final tabController = tabsState._tabController; + + Widget buildLayoutTabView() { + return LayoutControl( + control: control, + child: TabBarView( + controller: tabController, + clipBehavior: + control.getClipBehavior("clip_behavior", Clip.hardEdge)!, + viewportFraction: control.getDouble("viewport_fraction", 1.0)!, + physics: + control.disabled ? const NeverScrollableScrollPhysics() : null, + children: control.buildWidgets("controls"), + )); } - var index = _tabController!.index; - if (_selectedIndex != index) { - debugPrint("Selected index: $index"); - widget.backend.updateControlState( - widget.control.id, {"selectedindex": index.toString()}); - widget.backend - .triggerControlEvent(widget.control.id, "change", index.toString()); - _selectedIndex = index; + + // If expand property was set, we return the result directly. + // Because having Expanded as direct child of LayoutBuilder is not allowed. + if (control.getExpand("expand", 0)! > 0) { + return buildLayoutTabView(); } + + return LayoutBuilder( + builder: (context, constraints) { + final hasFixedHeight = control.getDouble("height") != null; + final hasUnboundedHeight = + constraints.maxHeight == double.infinity && !hasFixedHeight; + + if (hasUnboundedHeight) { + return const ErrorControl( + "Error displaying TabBarView: height is unbounded.", + description: + "Set a fixed height, a non-zero expand, or place it inside a control with bounded height.", + ); + } + + return buildLayoutTabView(); + }, + ); + } +} + +class TabControl extends Tab { + final Control control; + + TabControl({super.key, required this.control}) + : super( + // These values are *hints* for Flutter's TabBar heuristics. + // + // TabBar applies different sizing/ink behavior when items in `tabs:` + // are actual `Tab` instances (it literally checks `tab is Tab`). + // In Flet, the real content is built from `control` in `build()`, + // but providing `text`/`icon` here lets TabBar pick the correct + // default height (text vs text+icon) and ensures consistent hover/ + // splash overlay sizing (see issue #5599). + text: control.buildTextOrWidget("label") != null ? "" : null, + icon: control.buildIconOrWidget("icon"), + ); + + static Key? _keyFromControl(Control control) { + final controlKey = control.getKey("key"); + if (controlKey is ControlValueKey) { + return ValueKey(controlKey.value); + } + return null; } @override Widget build(BuildContext context) { - debugPrint("TabsControl build: ${widget.control.id}"); - bool disabled = widget.control.isDisabled || widget.parentDisabled; - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - - // keep only visible tabs - widget.children.retainWhere((c) => c.isVisible); - - var tabs = StoreConnector( - distinct: true, - converter: (store) => ControlsViewModel.fromStore( - store, widget.children.map((c) => c.id)), - builder: (content, viewModel) { - var tabsSnapshot = - viewModel.controlViews.map((c) => c.control.id).join(); - if (tabsSnapshot != _tabsSnapshot) { - _tabsSnapshot = tabsSnapshot; - - if (_tabController != null) { - _tabController!.removeListener(_tabChanged); - _tabController!.dispose(); - } - _tabController = TabController( - length: viewModel.controlViews.length, - animationDuration: Duration( - milliseconds: - widget.control.attrInt("animationDuration", 50)!), - vsync: this); - _tabController!.addListener(_tabChanged); - } + debugPrint("TabControl build: ${control.id}"); - var selectedIndex = widget.control.attrInt("selectedIndex", 0)!; + return control.buildInControlContext((context) { + return BaseControl( + control: control, + child: Tab( + key: _keyFromControl(control), + icon: control.buildIconOrWidget("icon"), + height: control.getDouble("height"), + iconMargin: control.getMargin("icon_margin"), + child: control.buildTextOrWidget("label"), + ), + ); + }); + } +} - if (selectedIndex > -1 && - selectedIndex < _tabController!.length && - _selectedIndex != selectedIndex) { - _selectedIndex = selectedIndex; - _tabController!.index = selectedIndex; - } +class TabBarControl extends StatefulWidget { + final Control control; - // check if all tabs have no content - bool emptyTabs = !viewModel.controlViews.any( - (t) => t.children.any((c) => c.name == "content" && c.isVisible)); - - var overlayColorStr = widget.control.attrString("overlayColor"); - dynamic overlayColor; - if (overlayColorStr != null) { - overlayColor = getWidgetStateProperty( - json.decode(overlayColorStr), - (jv) => parseColor(Theme.of(context), jv as String)) ?? - TabBarTheme.of(context).overlayColor; - } + const TabBarControl({super.key, required this.control}); - var indicatorBorderRadius = - parseBorderRadius(widget.control, "indicatorBorderRadius"); - var indicatorBorderSide = parseBorderSide( - Theme.of(context), widget.control, "indicatorBorderSide"); - var indicatorPadding = - parseEdgeInsets(widget.control, "indicatorPadding"); - - var indicatorColor = - widget.control.attrColor("indicatorColor", context) ?? - TabBarTheme.of(context).indicatorColor ?? - Theme.of(context).colorScheme.primary; - var labelColor = widget.control.attrColor("labelColor", context) ?? - TabBarTheme.of(context).labelColor ?? - Theme.of(context).colorScheme.primary; - var unselectedLabelColor = - widget.control.attrColor("unselectedLabelColor", context) ?? - TabBarTheme.of(context).unselectedLabelColor ?? - Theme.of(context).colorScheme.onSurface; - var dividerColor = - widget.control.attrColor("dividerColor", context) ?? - TabBarTheme.of(context).dividerColor; - - var themeIndicator = - TabBarTheme.of(context).indicator as UnderlineTabIndicator?; - var indicatorTabSize = widget.control.attrBool("indicatorTabSize"); - var isScrollable = widget.control.attrBool("scrollable", true)!; - var secondary = widget.control.attrBool("isSecondary", false)!; - var dividerHeight = widget.control.attrDouble("dividerHeight"); - var enableFeedback = widget.control.attrBool("enableFeedback"); - var indicatorWeight = - widget.control.attrDouble("indicatorThickness", 2.0)!; - var tabAlignment = parseTabAlignment( - widget.control.attrString("tabAlignment"), - isScrollable ? TabAlignment.start : TabAlignment.fill)!; - var mouseCursor = - parseMouseCursor(widget.control.attrString("mouseCursor")); - var clipBehavior = parseClip( - widget.control.attrString("clipBehavior"), Clip.hardEdge)!; - var padding = parseEdgeInsets(widget.control, "padding"); - var labelPadding = parseEdgeInsets(widget.control, "labelPadding"); - var labelStyle = parseTextStyle( - Theme.of(context), widget.control, "labelTextStyle"); - var unselectedLabelStyle = parseTextStyle( - Theme.of(context), widget.control, "unselectedLabelTextStyle"); - var splashBorderRadius = - parseBorderRadius(widget.control, "splashBorderRadius"); - - void onTap(int index) { - widget.backend.triggerControlEvent( - widget.control.id, "click", index.toString()); - } + @override + State createState() => _TabBarControlState(); +} - var indicator = indicatorBorderRadius != null || - indicatorBorderSide != null || - indicatorPadding != null - ? UnderlineTabIndicator( - borderRadius: indicatorBorderRadius ?? - themeIndicator?.borderRadius ?? - const BorderRadius.only( - topLeft: Radius.circular(2), - topRight: Radius.circular(2)), - borderSide: indicatorBorderSide ?? - themeIndicator?.borderSide ?? - BorderSide( - width: themeIndicator?.borderSide.width ?? 2, - color: themeIndicator?.borderSide.color ?? - indicatorColor), - insets: indicatorPadding ?? - themeIndicator?.insets ?? - EdgeInsets.zero) - : TabBarTheme.of(context).indicator; - var indicatorSize = indicatorTabSize != null - ? (indicatorTabSize - ? TabBarIndicatorSize.tab - : TabBarIndicatorSize.label) - : TabBarTheme.of(context).indicatorSize; - - var tabs = viewModel.controlViews.map((tabView) { - var iconString = parseIcon(tabView.control.attrString("icon")); - var iconCtrls = tabView.children - .where((c) => c.name == "icon" && c.isVisible); - - var icon = iconCtrls.isNotEmpty - ? createControl( - widget.control, iconCtrls.first.id, disabled, - parentAdaptive: adaptive) - : iconString != null - ? Icon(iconString) - : null; - var tabContentCtrls = tabView.children - .where((c) => c.name == "tab_content" && c.isVisible); - - if (tabContentCtrls.isNotEmpty) { - return Tab( - child: createControl( - widget.control, tabContentCtrls.first.id, disabled, - parentAdaptive: adaptive)); - } else { - return Tab( - text: tabView.control - .attrString("text", icon == null ? "" : null), - icon: icon, - height: tabView.control.attrDouble("height"), - iconMargin: parseEdgeInsets(tabView.control, "iconMargin"), - ); - } - }).toList(); - - TabBar? tabBar; - - if (secondary) { - tabBar = TabBar.secondary( - tabAlignment: tabAlignment, - controller: _tabController, - isScrollable: isScrollable, - dividerHeight: dividerHeight, - enableFeedback: enableFeedback, - mouseCursor: mouseCursor, - indicatorWeight: indicatorWeight, - dividerColor: dividerColor, - indicatorSize: indicatorSize, - indicator: indicator, - indicatorColor: indicatorColor, - labelColor: labelColor, - unselectedLabelColor: unselectedLabelColor, - overlayColor: overlayColor, - tabs: tabs, - padding: padding, - labelPadding: labelPadding, - labelStyle: labelStyle, - unselectedLabelStyle: unselectedLabelStyle, - splashBorderRadius: splashBorderRadius, - indicatorPadding: indicatorPadding ?? EdgeInsets.zero, - onTap: onTap); - } else { - tabBar = TabBar( - tabAlignment: tabAlignment, - controller: _tabController, - isScrollable: isScrollable, - dividerHeight: dividerHeight, - enableFeedback: enableFeedback, - mouseCursor: mouseCursor, - indicatorWeight: indicatorWeight, - dividerColor: dividerColor, - indicatorSize: indicatorSize, - indicator: indicator, - indicatorColor: indicatorColor, - labelColor: labelColor, - unselectedLabelColor: unselectedLabelColor, - overlayColor: overlayColor, - tabs: tabs, - padding: padding, - labelPadding: labelPadding, - labelStyle: labelStyle, - unselectedLabelStyle: unselectedLabelStyle, - splashBorderRadius: splashBorderRadius, - indicatorPadding: indicatorPadding ?? EdgeInsets.zero, - onTap: onTap); - } +class _TabBarControlState extends State { + @override + Widget build(BuildContext context) { + debugPrint("TabBarControl build: ${widget.control.id}"); + + // Find the TabController from the nearest TabsControl ancestor + final tabsState = context.findAncestorStateOfType<_TabsControlState>(); + if (tabsState != null) { + final tabController = tabsState._tabController; - debugPrint("tabs.length: ${tabBar.tabs.length}"); + var overlayColor = widget.control + .getWidgetStateColor("overlay_color", Theme.of(context)); + var indicatorPadding = + widget.control.getPadding("indicator_padding", EdgeInsets.zero)!; + var indicatorColor = widget.control.getColor("indicator_color", context); + var labelColor = widget.control.getColor("label_color", context); + var unselectedLabelColor = + widget.control.getColor("unselected_label_color", context); + var dividerColor = widget.control.getColor("divider_color", context); + var scrollable = widget.control.getBool("scrollable", true)!; + var secondary = widget.control.getBool("secondary", false)!; + var dividerHeight = widget.control.getDouble("divider_height"); + var enableFeedback = widget.control.getBool("enable_feedback"); + var indicatorWeight = + widget.control.getDouble("indicator_thickness", 2.0)!; + var tabAlignment = widget.control.getTabAlignment("tab_alignment", + scrollable ? TabAlignment.start : TabAlignment.fill)!; + var mouseCursor = + parseMouseCursor(widget.control.getString("mouse_cursor")); + var padding = parseEdgeInsets(widget.control.getPadding("padding")); + var labelPadding = widget.control.getPadding("label_padding"); + var labelStyle = + widget.control.getTextStyle("label_text_style", Theme.of(context)); + var unselectedLabelStyle = widget.control + .getTextStyle("unselected_label_text_style", Theme.of(context)); + var splashBorderRadius = + widget.control.getBorderRadius("splash_border_radius"); - if (emptyTabs) { - return tabBar; + final tabBarDisabled = widget.control.disabled; + final tabControls = widget.control.children("tabs"); + final tabs = tabControls.map((tab) { + // Ensure parent gets rebuilt when a tab becomes visible/invisible. + tab.notifyParent = true; + + if (tab.type == "Tab") { + return TabControl(control: tab); + } + + // TabBar applies consistent sizing/ink behavior only when `tab is Tab`. + // Wrapping arbitrary controls into a `Tab` keeps hover/splash sizes aligned + // with the tab bar. + return Tab(child: ControlWidget(control: tab)); + }).toList(); + + void onTap(int index) { + if (tabBarDisabled || + (index >= 0 && + index < tabControls.length && + tabControls[index].disabled)) { + final fallbackIndex = tabController.previousIndex + .clamp(0, tabController.length - 1) + .toInt(); + if (fallbackIndex != tabController.index) { + // TabBar already requested the tap target via controller.animateTo(). + // Restore the previous index so disabled tabs cannot be selected. + tabController.index = fallbackIndex; } + return; + } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - tabBar, - Expanded( - child: TabBarView( - controller: _tabController, - clipBehavior: clipBehavior, - children: viewModel.controlViews.map((tabView) { - var contentCtrls = tabView.children - .where((c) => c.name == "content" && c.isVisible); - if (contentCtrls.isEmpty) { - return const SizedBox.shrink(); - } - return createControl( - widget.control, contentCtrls.first.id, disabled, - parentAdaptive: adaptive); - }).toList())) - ], - ); - }); + widget.control.triggerEvent("click", index); + } + + void onHover(bool hovering, int? index) { + if (tabBarDisabled || + (index != null && + index >= 0 && + index < tabControls.length && + tabControls[index].disabled)) { + return; + } + widget.control + .triggerEvent("hover", {"hovering": hovering, "index": index}); + } - return constrainedControl(context, tabs, widget.parent, widget.control); + var indicator = widget.control + .getUnderlineTabIndicator("indicator", Theme.of(context)); + var indicatorSize = + widget.control.getTabBarIndicatorSize("indicator_size"); + var indicatorAnimation = + widget.control.getTabIndicatorAnimation("indicator_animation"); + + debugPrint("TabBar indicator: ${indicator?.borderSide}"); + + TabBar? tabBar; + + if (secondary) { + tabBar = TabBar.secondary( + controller: tabController, + tabAlignment: tabAlignment, + isScrollable: scrollable, + dividerHeight: dividerHeight, + enableFeedback: enableFeedback, + mouseCursor: mouseCursor, + indicatorWeight: indicatorWeight, + dividerColor: dividerColor, + indicatorSize: indicatorSize, + indicator: indicator, + indicatorColor: indicatorColor, + indicatorPadding: indicatorPadding, + indicatorAnimation: indicatorAnimation, + labelColor: labelColor, + unselectedLabelColor: unselectedLabelColor, + overlayColor: overlayColor, + tabs: tabs, + padding: padding, + labelPadding: labelPadding, + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + splashBorderRadius: splashBorderRadius, + onTap: onTap, + onHover: onHover); + } else { + tabBar = TabBar( + controller: tabController, + tabAlignment: tabAlignment, + isScrollable: scrollable, + dividerHeight: dividerHeight, + enableFeedback: enableFeedback, + mouseCursor: mouseCursor, + indicatorWeight: indicatorWeight, + dividerColor: dividerColor, + indicatorSize: indicatorSize, + indicator: indicator, + indicatorColor: indicatorColor, + indicatorPadding: indicatorPadding, + indicatorAnimation: indicatorAnimation, + labelColor: labelColor, + unselectedLabelColor: unselectedLabelColor, + overlayColor: overlayColor, + tabs: tabs, + padding: padding, + labelPadding: labelPadding, + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + splashBorderRadius: splashBorderRadius, + onTap: onTap, + onHover: onHover); + } + + return BaseControl( + control: widget.control, + child: IgnorePointer(ignoring: tabBarDisabled, child: tabBar), + ); + } else { + return const ErrorControl("TabBar must be used within a Tabs control"); + } } } diff --git a/packages/flet/lib/src/controls/text.dart b/packages/flet/lib/src/controls/text.dart index 6cf810e940..33eebee6f0 100644 --- a/packages/flet/lib/src/controls/text.dart +++ b/packages/flet/lib/src/controls/text.dart @@ -1,191 +1,133 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import '../utils/numbers.dart'; import '../utils/text.dart'; -import 'create_control.dart'; -import 'flet_store_mixin.dart'; +import 'base_controls.dart'; -class TextControl extends StatelessWidget with FletStoreMixin { - final Control? parent; +class TextControl extends StatelessWidget { final Control control; - final bool parentDisabled; - final FletControlBackend backend; - const TextControl( - {super.key, - required this.parent, - required this.control, - required this.parentDisabled, - required this.backend}); + const TextControl({super.key, required this.control}); @override Widget build(BuildContext context) { - var result = withControlTree(control, (context, viewModel) { - debugPrint("Text build: ${control.id}"); - - bool disabled = control.isDisabled || parentDisabled; - - String text = control.attrString("value", "")!; - var selectionCursorColor = - control.attrColor("selectionCursorColor", context); - var selectionCursorWidth = - control.attrDouble("selectionCursorWidth", 2.0)!; - var selectionCursorHeight = control.attrDouble("selectionCursorHeight"); - var showSelectionCursor = control.attrBool("showSelectionCursor", false)!; - var enableInteractiveSelection = - control.attrBool("enableInteractiveSelection", true)!; - - List? spans = parseTextSpans( - Theme.of(context), - viewModel, - disabled, - (String controlId, String eventName, String eventData) { - backend.triggerControlEvent(controlId, eventName, eventData); - }, - ); - String? semanticsLabel = control.attrString("semanticsLabel"); - bool noWrap = control.attrBool("noWrap", false)!; - int? maxLines = control.attrInt("maxLines"); - - TextStyle? style; - var styleNameOrData = control.attrString("style", null); - if (styleNameOrData != null) { - style = getTextStyle(context, styleNameOrData); - } - if (style == null && styleNameOrData != null) { - try { - style = parseTextStyle(Theme.of(context), control, "style"); - } on FormatException catch (_) { - style = null; - } - } - - TextStyle? themeStyle; - var styleName = control.attrString("theme_style", null); - if (styleName != null) { - themeStyle = getTextStyle(context, styleName); - } - - if (style == null && themeStyle != null) { - style = themeStyle; - } else if (style != null && themeStyle != null) { - style = themeStyle.merge(style); - } - - var fontWeight = control.attrString("weight", "")!; - - List variations = []; - if (fontWeight.startsWith("w")) { - variations.add( - FontVariation('wght', parseDouble(fontWeight.substring(1), 0)!)); - } - - style = (style ?? const TextStyle()).copyWith( - fontSize: control.attrDouble("size", null), - fontWeight: getFontWeight(fontWeight), - fontStyle: control.attrBool( - "italic", - false, - )! - ? FontStyle.italic - : null, - fontFamily: control.attrString("fontFamily"), - fontVariations: variations, - color: control.attrColor("color", context) ?? - (spans.isNotEmpty - ? DefaultTextStyle.of(context).style.color - : null), - backgroundColor: control.attrColor("bgcolor", context), - ); - - TextAlign textAlign = - parseTextAlign(control.attrString("textAlign"), TextAlign.start)!; - - TextOverflow overflow = - parseTextOverflow(control.attrString("overflow"), TextOverflow.clip)!; - - onSelectionChanged( - TextSelection selection, SelectionChangedCause? cause) { - debugPrint("Text ${control.id} selection changed"); - backend.triggerControlEvent( - control.id, - "selection_change", - jsonEncode({ - "text": text ?? "", - "start": selection.start, - "end": selection.end, - "base_offset": selection.baseOffset, - "extent_offset": selection.extentOffset, - "affinity": selection.affinity.name, - "directional": selection.isDirectional, - "collapsed": selection.isCollapsed, - "valid": selection.isValid, - "normalized": selection.isNormalized, - "cause": cause?.name ?? "unknown", - })); - } - - onTap() { - debugPrint("Text ${control.id} selection changed"); - backend.triggerControlEvent( - control.id, - "selection_change", - ); - } - - return control.attrBool("selectable", false)! - ? (spans.isNotEmpty) - ? SelectableText.rich( - TextSpan(text: text, style: style, children: spans), - maxLines: maxLines, - textAlign: textAlign, - cursorColor: selectionCursorColor, - cursorHeight: selectionCursorHeight, - cursorWidth: selectionCursorWidth, - semanticsLabel: semanticsLabel, - showCursor: showSelectionCursor, - enableInteractiveSelection: enableInteractiveSelection, - onSelectionChanged: onSelectionChanged, - onTap: onTap, - ) - : SelectableText( - text, - semanticsLabel: semanticsLabel, - maxLines: maxLines, - style: style, - textAlign: textAlign, - cursorColor: selectionCursorColor, - cursorHeight: selectionCursorHeight, - cursorWidth: selectionCursorWidth, - showCursor: showSelectionCursor, - enableInteractiveSelection: enableInteractiveSelection, - onSelectionChanged: onSelectionChanged, - onTap: onTap, - ) - : (spans.isNotEmpty) - ? Text.rich( - TextSpan(text: text, style: style, children: spans), - semanticsLabel: semanticsLabel, - maxLines: maxLines, - softWrap: !noWrap, - textAlign: textAlign, - overflow: overflow, - ) - : Text( - text, - semanticsLabel: semanticsLabel, - maxLines: maxLines, - softWrap: !noWrap, - style: style, - textAlign: textAlign, - overflow: overflow, - ); - }); - - return constrainedControl(context, result, parent, control); + debugPrint("Text build: ${control.id}"); + + final theme = Theme.of(context); + String text = control.getString("value", "")!; + var selectionCursorColor = + control.getColor("selection_cursor_color", context); + var selectionCursorWidth = + control.getDouble("selection_cursor_width", 2.0)!; + var selectionCursorHeight = control.getDouble("selection_cursor_height"); + var showSelectionCursor = control.getBool("show_selection_cursor", false)!; + var enableInteractiveSelection = + control.getBool("enable_interactive_selection", true)!; + + List? spans = parseTextSpans( + control.children("spans"), + theme, + (Control control, String eventName, [dynamic eventData]) { + control.triggerEvent(eventName, eventData); + }, + ); + var semanticsLabel = control.getString("semantics_label"); + var noWrap = control.getBool("no_wrap", false)!; + var maxLines = control.getInt("max_lines"); + + var style = control.getTextStyle("style", theme); + var themeStyle = + parseTextThemeStyle(control.getString("theme_style"), context); + if (style == null && themeStyle != null) { + style = themeStyle; + } else if (style != null && themeStyle != null) { + style = themeStyle.merge(style); + } + + var fontWeight = control.getString("weight", "")!; + List variations = []; + if (fontWeight.startsWith("w")) { + variations + .add(FontVariation('wght', parseDouble(fontWeight.substring(1), 0)!)); + } + + style = (style ?? const TextStyle()).copyWith( + overflow: control.getTextOverflow("overflow"), + fontSize: control.getDouble("size", null), + fontWeight: parseFontWeight(fontWeight), + fontStyle: control.getBool("italic", false)! ? FontStyle.italic : null, + fontFamily: control.getString("font_family"), + fontFamilyFallback: + control.getList("font_family_fallback", (e) => e.toString()), + fontVariations: variations, + color: control.getColor("color", context) ?? + (spans.isNotEmpty ? DefaultTextStyle.of(context).style.color : null), + backgroundColor: control.getColor("bgcolor", context), + ); + + var textAlign = + parseTextAlign(control.getString("text_align"), TextAlign.start)!; + + onSelectionChanged(TextSelection selection, SelectionChangedCause? cause) { + control.triggerEvent("selection_change", { + "selected_text": text, + "cause": cause?.name ?? "unknown", + "selection": selection.toMap(), + }); + } + + onTap() { + control.triggerEvent("tap"); + } + + var textWidget = control.getBool("selectable", false)! + ? (spans.isNotEmpty) + ? SelectableText.rich( + TextSpan(text: text, style: style, children: spans), + maxLines: maxLines, + textAlign: textAlign, + cursorColor: selectionCursorColor, + cursorHeight: selectionCursorHeight, + cursorWidth: selectionCursorWidth, + semanticsLabel: semanticsLabel, + showCursor: showSelectionCursor, + enableInteractiveSelection: enableInteractiveSelection, + onSelectionChanged: onSelectionChanged, + onTap: onTap, + ) + : SelectableText( + text, + semanticsLabel: semanticsLabel, + maxLines: maxLines, + style: style, + textAlign: textAlign, + cursorColor: selectionCursorColor, + cursorHeight: selectionCursorHeight, + cursorWidth: selectionCursorWidth, + showCursor: showSelectionCursor, + enableInteractiveSelection: enableInteractiveSelection, + onSelectionChanged: onSelectionChanged, + onTap: onTap, + ) + : (spans.isNotEmpty) + ? Text.rich( + TextSpan(text: text, style: style, children: spans), + semanticsLabel: semanticsLabel, + maxLines: maxLines, + softWrap: !noWrap, + textAlign: textAlign, + ) + : Text( + text, + semanticsLabel: semanticsLabel, + maxLines: maxLines, + softWrap: !noWrap, + style: style, + textAlign: textAlign, + ); + + return LayoutControl(control: control, child: textWidget); } } diff --git a/packages/flet/lib/src/controls/text_button.dart b/packages/flet/lib/src/controls/text_button.dart deleted file mode 100644 index 981ae752dc..0000000000 --- a/packages/flet/lib/src/controls/text_button.dart +++ /dev/null @@ -1,188 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../flet_control_backend.dart'; -import '../models/control.dart'; -import '../utils/buttons.dart'; -import '../utils/icons.dart'; -import '../utils/launch_url.dart'; -import '../utils/others.dart'; -import 'create_control.dart'; -import 'cupertino_button.dart'; -import 'cupertino_dialog_action.dart'; -import 'flet_store_mixin.dart'; - -class TextButtonControl extends StatefulWidget { - final Control? parent; - final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const TextButtonControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); - - @override - State createState() => _TextButtonControlState(); -} - -class _TextButtonControlState extends State - with FletStoreMixin { - late final FocusNode _focusNode; - String? _lastFocusValue; - - @override - void initState() { - super.initState(); - _focusNode = FocusNode(); - _focusNode.addListener(_onFocusChange); - } - - @override - void dispose() { - _focusNode.removeListener(_onFocusChange); - _focusNode.dispose(); - super.dispose(); - } - - void _onFocusChange() { - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); - } - - @override - Widget build(BuildContext context) { - debugPrint("Button build: ${widget.control.id}"); - - return withPagePlatform((context, platform) { - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return widget.control.name == "action" && - (widget.parent?.type == "alertdialog" || - widget.parent?.type == "cupertinoalertdialog") - ? CupertinoDialogActionControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend) - : CupertinoButtonControl( - control: widget.control, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - children: widget.children, - backend: widget.backend); - } - - String text = widget.control.attrString("text", "")!; - var clipBehavior = parseClip(widget.control.attrString("clipBehavior")); - IconData? icon = parseIcon(widget.control.attrString("icon")); - Color? iconColor = widget.control.attrColor("iconColor", context); - var contentCtrls = - widget.children.where((c) => c.name == "content" && c.isVisible); - bool onHover = widget.control.attrBool("onHover", false)!; - bool onLongPress = widget.control.attrBool("onLongPress", false)!; - String url = widget.control.attrString("url", "")!; - String? urlTarget = widget.control.attrString("urlTarget"); - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - Function()? onPressed = !disabled - ? () { - debugPrint("Button ${widget.control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - widget.backend.triggerControlEvent(widget.control.id, "click"); - } - : null; - - Function()? onLongPressHandler = onLongPress && !disabled - ? () { - debugPrint("Button ${widget.control.id} long pressed!"); - widget.backend - .triggerControlEvent(widget.control.id, "long_press"); - } - : null; - - Function(bool)? onHoverHandler = onHover && !disabled - ? (state) { - debugPrint("Button ${widget.control.id} hovered!"); - widget.backend.triggerControlEvent( - widget.control.id, "hover", state.toString()); - } - : null; - - TextButton? button; - - var theme = Theme.of(context); - - var style = parseButtonStyle(Theme.of(context), widget.control, "style", - defaultForegroundColor: theme.colorScheme.primary, - defaultBackgroundColor: Colors.transparent, - defaultOverlayColor: Colors.transparent, - defaultShadowColor: Colors.transparent, - defaultSurfaceTintColor: Colors.transparent, - defaultElevation: 0, - defaultPadding: const EdgeInsets.all(8), - defaultBorderSide: BorderSide.none, - defaultShape: theme.useMaterial3 - ? const StadiumBorder() - : RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))); - - if (icon != null) { - button = TextButton.icon( - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - style: style, - clipBehavior: clipBehavior, - icon: Icon( - icon, - color: iconColor, - ), - label: Text(text)); - } else if (contentCtrls.isNotEmpty) { - button = TextButton( - autofocus: autofocus, - focusNode: _focusNode, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - style: style, - child: - createControl(widget.control, contentCtrls.first.id, disabled)); - } else { - button = TextButton( - autofocus: autofocus, - focusNode: _focusNode, - style: style, - onPressed: onPressed, - onLongPress: onLongPressHandler, - onHover: onHoverHandler, - clipBehavior: clipBehavior, - child: Text(text)); - } - - var focusValue = widget.control.attrString("focus"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - _focusNode.requestFocus(); - } - - return constrainedControl(context, button, widget.parent, widget.control); - }); - } -} diff --git a/packages/flet/lib/src/controls/textfield.dart b/packages/flet/lib/src/controls/textfield.dart index 0912377beb..6ff83f4dc3 100644 --- a/packages/flet/lib/src/controls/textfield.dart +++ b/packages/flet/lib/src/controls/textfield.dart @@ -1,45 +1,33 @@ -import 'package:flet/src/utils/platform.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; import '../utils/autofill.dart'; import '../utils/borders.dart'; +import '../utils/colors.dart'; import '../utils/edge_insets.dart'; import '../utils/form_field.dart'; +import '../utils/layout.dart'; +import '../utils/misc.dart'; import '../utils/mouse.dart'; -import '../utils/others.dart'; -import '../utils/overlay_style.dart'; +import '../utils/numbers.dart'; +import '../utils/platform.dart'; import '../utils/text.dart'; import '../utils/textfield.dart'; -import 'create_control.dart'; -import 'cupertino_textfield.dart'; -import 'flet_store_mixin.dart'; +import '../utils/theme.dart'; +import 'base_controls.dart'; class TextFieldControl extends StatefulWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - final FletControlBackend backend; - - const TextFieldControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive, - required this.backend}); + + TextFieldControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); @override State createState() => _TextFieldControlState(); } -class _TextFieldControlState extends State - with FletStoreMixin { +class _TextFieldControlState extends State { String _value = ""; bool _revealPassword = false; bool _focused = false; @@ -48,397 +36,301 @@ class _TextFieldControlState extends State late final FocusNode _shiftEnterfocusNode; String? _lastFocusValue; String? _lastBlurValue; + TextSelection? _selection; + + KeyEventResult _handleTextFieldKeyEvent(KeyEvent event, + {required bool submitOnEnter}) { + // ignore up/down arrow keys if flag is set + if ((event is KeyDownEvent || event is KeyRepeatEvent) && + widget.control.getBool("ignore_up_down_keys", false)! && + (event.logicalKey == LogicalKeyboardKey.arrowUp || + event.logicalKey == LogicalKeyboardKey.arrowDown)) { + return KeyEventResult.handled; + } + + // submit on Enter if flag is set and shift is not pressed + if (submitOnEnter && + event is KeyDownEvent && + !HardwareKeyboard.instance.isShiftPressed && + (event.logicalKey == LogicalKeyboardKey.enter || + event.logicalKey == LogicalKeyboardKey.numpadEnter)) { + widget.control.triggerEvent("submit"); + return KeyEventResult.handled; + } + + // let the system handle other key events + return KeyEventResult.ignored; + } @override void initState() { super.initState(); _controller = TextEditingController(); + _controller.addListener(_handleControllerChange); _shiftEnterfocusNode = FocusNode( - onKeyEvent: (FocusNode node, KeyEvent evt) { - if (!HardwareKeyboard.instance.isShiftPressed && - evt.logicalKey.keyLabel == 'Enter') { - if (evt is KeyDownEvent) { - widget.backend.triggerControlEvent(widget.control.id, "submit"); - } - return KeyEventResult.handled; - } else { - return KeyEventResult.ignored; - } - }, + onKeyEvent: (FocusNode node, KeyEvent event) => + _handleTextFieldKeyEvent(event, submitOnEnter: true), ); _shiftEnterfocusNode.addListener(_onShiftEnterFocusChange); - _focusNode = FocusNode(); + _focusNode = FocusNode( + onKeyEvent: (FocusNode node, KeyEvent event) => + _handleTextFieldKeyEvent(event, submitOnEnter: false), + ); _focusNode.addListener(_onFocusChange); + widget.control.addInvokeMethodListener(_invokeMethod); } @override void dispose() { + _controller.removeListener(_handleControllerChange); _controller.dispose(); _shiftEnterfocusNode.removeListener(_onShiftEnterFocusChange); _shiftEnterfocusNode.dispose(); _focusNode.removeListener(_onFocusChange); + widget.control.removeInvokeMethodListener(_invokeMethod); _focusNode.dispose(); super.dispose(); } + Future _invokeMethod(String name, dynamic args) async { + debugPrint("TextField.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + default: + throw Exception("Unknown TextField method: $name"); + } + } + void _onShiftEnterFocusChange() { - setState(() { - _focused = _shiftEnterfocusNode.hasFocus; - }); - widget.backend.triggerControlEvent( - widget.control.id, _shiftEnterfocusNode.hasFocus ? "focus" : "blur"); + _focused = _shiftEnterfocusNode.hasFocus; + widget.control + .triggerEvent(_shiftEnterfocusNode.hasFocus ? "focus" : "blur"); } void _onFocusChange() { - setState(() { - _focused = _focusNode.hasFocus; + _focused = _focusNode.hasFocus; + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + void _handleControllerChange() { + final selection = _controller.selection; + if (_selection == selection) return; + + _selection = selection; + + if (!selection.isValid || + !widget.control.getBool("on_selection_change", false)!) { + return; + } + + widget.control.updateProperties({"selection": selection.toMap()}); + widget.control.triggerEvent("selection_change", { + "selected_text": + _controller.text.substring(selection.start, selection.end), + "selection": selection.toMap() }); - widget.backend.triggerControlEvent( - widget.control.id, _focusNode.hasFocus ? "focus" : "blur"); } @override Widget build(BuildContext context) { debugPrint("TextField build: ${widget.control.id}"); - return withPagePlatform((context, platform) { - bool autofocus = widget.control.attrBool("autofocus", false)!; - bool disabled = widget.control.isDisabled || widget.parentDisabled; - - bool? adaptive = - widget.control.attrBool("adaptive") ?? widget.parentAdaptive; - if (adaptive == true && - (platform == TargetPlatform.iOS || - platform == TargetPlatform.macOS)) { - return CupertinoTextFieldControl( - control: widget.control, - children: widget.children, - parent: widget.parent, - parentDisabled: widget.parentDisabled, - parentAdaptive: adaptive, - backend: widget.backend); - } - - debugPrint("TextField build: ${widget.control.id}"); - - String value = widget.control.attrs["value"] ?? ""; - if (_value != value) { - _value = value; - _controller.value = TextEditingValue( - text: value, - selection: TextSelection.collapsed( - offset: value.length), // preserve cursor position at the end - ); - } - - var prefixControls = - widget.children.where((c) => c.name == "prefix" && c.isVisible); - var prefixIconControls = - widget.children.where((c) => c.name == "prefix_icon" && c.isVisible); - var suffixControls = - widget.children.where((c) => c.name == "suffix" && c.isVisible); - var suffixIconControls = - widget.children.where((c) => c.name == "suffix_icon" && c.isVisible); - var iconControls = - widget.children.where((c) => c.name == "icon" && c.isVisible); - var counterControls = - widget.children.where((c) => c.name == "counter" && c.isVisible); - var errorCtrl = - widget.children.where((c) => c.name == "error" && c.isVisible); - var helperCtrl = - widget.children.where((c) => c.name == "helper" && c.isVisible); - var labelCtrl = - widget.children.where((c) => c.name == "label" && c.isVisible); - - bool shiftEnter = widget.control.attrBool("shiftEnter", false)!; - bool multiline = - widget.control.attrBool("multiline", false)! || shiftEnter; - int minLines = widget.control.attrInt("minLines", 1)!; - int? maxLines = widget.control.attrInt("maxLines", multiline ? null : 1); - - bool password = widget.control.attrBool("password", false)!; - bool canRevealPassword = - widget.control.attrBool("canRevealPassword", false)!; - var cursorColor = widget.control.attrColor("cursorColor", context); - var selectionColor = widget.control.attrColor("selectionColor", context); - var textSize = widget.control.attrDouble("textSize"); - var color = widget.control.attrColor("color", context); - var focusedColor = widget.control.attrColor("focusedColor", context); - - TextStyle? textStyle = - parseTextStyle(Theme.of(context), widget.control, "textStyle"); - if (textSize != null || color != null || focusedColor != null) { - textStyle = (textStyle ?? const TextStyle()).copyWith( - fontSize: textSize, - color: _focused ? focusedColor ?? color : color); - } - - TextCapitalization textCapitalization = parseTextCapitalization( - widget.control.attrString("capitalization"), - TextCapitalization.none)!; - - FilteringTextInputFormatter? inputFilter = - parseInputFilter(widget.control, "inputFilter"); - - List? inputFormatters = []; - // add non-null input formatters - if (inputFilter != null) { - inputFormatters.add(inputFilter); - } - if (textCapitalization != TextCapitalization.none) { - inputFormatters.add(TextCapitalizationFormatter(textCapitalization)); - } - - Widget? revealPasswordIcon; - if (password && canRevealPassword) { - revealPasswordIcon = GestureDetector( - child: Icon( - _revealPassword ? Icons.visibility_off : Icons.visibility, - ), - onTap: () { - setState(() { - _revealPassword = !_revealPassword; - }); - }); - } - - double? textVerticalAlign = - widget.control.attrDouble("textVerticalAlign"); - - FocusNode focusNode = shiftEnter ? _shiftEnterfocusNode : _focusNode; - - var focusValue = widget.control.attrString("focus"); - var blurValue = widget.control.attrString("blur"); - if (focusValue != null && focusValue != _lastFocusValue) { - _lastFocusValue = focusValue; - focusNode.requestFocus(); - } - if (blurValue != null && blurValue != _lastBlurValue) { - _lastBlurValue = blurValue; - _focusNode.unfocus(); - } - - var fitParentSize = widget.control.attrBool("fitParentSize", false)!; - - var maxLength = widget.control.attrInt("maxLength"); - - Widget textField = TextFormField( - style: textStyle, - autofocus: autofocus, - enabled: !disabled, - onFieldSubmitted: !multiline - ? (value) { - widget.backend - .triggerControlEvent(widget.control.id, "submit", value); - } - : null, - decoration: buildInputDecoration(context, widget.control, - prefix: prefixControls.isNotEmpty ? prefixControls.first : null, - prefixIcon: prefixIconControls.isNotEmpty - ? prefixIconControls.first - : null, - suffix: suffixControls.isNotEmpty ? suffixControls.first : null, - suffixIcon: suffixIconControls.isNotEmpty - ? suffixIconControls.first - : null, - icon: iconControls.isNotEmpty ? iconControls.first : null, - counter: - counterControls.isNotEmpty ? counterControls.first : null, - error: errorCtrl.isNotEmpty ? errorCtrl.first : null, - helper: helperCtrl.isNotEmpty ? helperCtrl.first : null, - label: labelCtrl.isNotEmpty ? labelCtrl.first : null, - customSuffix: revealPasswordIcon, - valueLength: _value.length, - maxLength: maxLength, - focused: _focused, - disabled: disabled, - adaptive: adaptive), - showCursor: widget.control.attrBool("showCursor"), - textAlignVertical: textVerticalAlign != null - ? TextAlignVertical(y: textVerticalAlign) - : null, - cursorHeight: widget.control.attrDouble("cursorHeight"), - cursorWidth: widget.control.attrDouble("cursorWidth", 2.0)!, - cursorRadius: parseRadius(widget.control, "cursorRadius"), - keyboardType: multiline - ? TextInputType.multiline - : parseTextInputType(widget.control.attrString("keyboardType"), - TextInputType.text)!, - autocorrect: widget.control.attrBool("autocorrect", true)!, - enableSuggestions: - widget.control.attrBool("enableSuggestions", true)!, - smartDashesType: widget.control.attrBool("smartDashesType", true)! - ? SmartDashesType.enabled - : SmartDashesType.disabled, - smartQuotesType: widget.control.attrBool("smartQuotesType", true)! - ? SmartQuotesType.enabled - : SmartQuotesType.disabled, - textAlign: parseTextAlign( - widget.control.attrString("textAlign"), TextAlign.start)!, - minLines: fitParentSize ? null : minLines, - maxLines: fitParentSize ? null : maxLines, - maxLength: maxLength, - readOnly: widget.control.attrBool("readOnly", false)!, - inputFormatters: inputFormatters.isNotEmpty ? inputFormatters : null, - obscureText: password && !_revealPassword, - controller: _controller, - focusNode: focusNode, - autofillHints: parseAutofillHints(widget.control, "autofillHints"), - expands: fitParentSize, - enableInteractiveSelection: - widget.control.attrBool("enableInteractiveSelection"), - canRequestFocus: widget.control.attrBool("canRequestFocus", true)!, - clipBehavior: parseClip( - widget.control.attrString("clipBehavior"), Clip.hardEdge)!, - cursorColor: cursorColor, - ignorePointers: widget.control.attrBool("ignorePointers"), - cursorErrorColor: - widget.control.attrColor("cursorErrorColor", context), - scribbleEnabled: widget.control.attrBool("enableScribble", true)!, - scrollPadding: parseEdgeInsets( - widget.control, "scrollPadding", const EdgeInsets.all(20.0))!, - keyboardAppearance: - parseBrightness(widget.control.attrString("keyboardBrightness")), - enableIMEPersonalizedLearning: - widget.control.attrBool("enableIMEPersonalizedLearning", true)!, - obscuringCharacter: - widget.control.attrString("obscuringCharacter", '•')!, - mouseCursor: - parseMouseCursor(widget.control.attrString("mouseCursor")), - cursorOpacityAnimates: widget.control.attrBool("animateCursorOpacity", - Theme.of(context).platform == TargetPlatform.iOS)!, - onTapAlwaysCalled: - widget.control.attrBool("animateCursorOpacity", false)!, - strutStyle: parseStrutStyle(widget.control, "strutStyle"), - onTap: () { - widget.backend.triggerControlEvent(widget.control.id, "click"); - }, - onTapOutside: widget.control.attrBool("onTapOutside", false)! - ? (PointerDownEvent? event) { - widget.backend - .triggerControlEvent(widget.control.id, "tapOutside"); - } - : null, - onChanged: (String value) { - _value = value; - widget.backend - .updateControlState(widget.control.id, {"value": value}); - if (widget.control.attrBool("onChange", false)!) { - widget.backend - .triggerControlEvent(widget.control.id, "change", value); - } - }); + bool autofocus = widget.control.getBool("autofocus", false)!; + + String value = widget.control.getString("value", "")!; + if (_value != value) { + _value = value; + _controller.value = TextEditingValue( + text: value, + // preserve cursor position at the end + selection: TextSelection.collapsed(offset: value.length), + ); + _selection = _controller.selection; + } - if (cursorColor != null || selectionColor != null) { - textField = TextSelectionTheme( - data: TextSelectionTheme.of(context).copyWith( - cursorColor: cursorColor, selectionColor: selectionColor), - child: textField); - } - - // linux workaround for https://github.com/flet-dev/flet/issues/3934 - textField = - isLinuxDesktop() ? ExcludeSemantics(child: textField) : textField; - - if (widget.control.attrInt("expand", 0)! > 0) { - return constrainedControl( - context, textField, widget.parent, widget.control); - } else { - return LayoutBuilder( - builder: (BuildContext context, BoxConstraints constraints) { - if (constraints.maxWidth == double.infinity && - widget.control.attrDouble("width") == null) { - textField = ConstrainedBox( - constraints: const BoxConstraints.tightFor(width: 300), - child: textField, - ); - } - - return constrainedControl( - context, textField, widget.parent, widget.control); - }, - ); - } - }); - } -} + var selection = widget.control.getTextSelection("selection", + minOffset: 0, maxOffset: _controller.text.length); + if (selection != null && selection != _controller.selection) { + _controller.selection = selection; + _selection = selection; + } + + var shiftEnter = widget.control.getBool("shift_enter", false)!; + var multiline = widget.control.getBool("multiline", false)! || shiftEnter; + var minLines = widget.control.getInt("min_lines", 1)!; + var maxLines = widget.control.getInt("max_lines", multiline ? null : 1); + + var password = widget.control.getBool("password", false)!; + var canRevealPassword = + widget.control.getBool("can_reveal_password", false)!; + var cursorColor = widget.control.getColor("cursor_color", context); + var selectionColor = widget.control.getColor("selection_color", context); + var textSize = widget.control.getDouble("text_size"); + var color = widget.control.getColor("color", context); + var focusedColor = widget.control.getColor("focused_color", context); + var textStyle = widget.control + .getTextStyle("text_style", Theme.of(context), const TextStyle())!; + if (textSize != null || color != null || focusedColor != null) { + textStyle = textStyle.copyWith( + fontSize: textSize, color: _focused ? focusedColor ?? color : color); + } -class TextCapitalizationFormatter extends TextInputFormatter { - final TextCapitalization capitalization; + TextCapitalization textCapitalization = widget.control + .getTextCapitalization("capitalization", TextCapitalization.none)!; - TextCapitalizationFormatter(this.capitalization); + FilteringTextInputFormatter? inputFilter = + parseInputFilter(widget.control.get("input_filter")); - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, TextEditingValue newValue) { - String text = ''; - - switch (capitalization) { - case TextCapitalization.words: - text = capitalizeFirstofEach(newValue.text); - break; - case TextCapitalization.sentences: - List sentences = newValue.text.split('.'); - for (int i = 0; i < sentences.length; i++) { - sentences[i] = inCaps(sentences[i]); - } - text = sentences.join('.'); - break; - case TextCapitalization.characters: - text = allInCaps(newValue.text); - break; - case TextCapitalization.none: - text = newValue.text; - break; + List? inputFormatters = []; + // add non-null input formatters + if (inputFilter != null) { + inputFormatters.add(inputFilter); + } + if (textCapitalization != TextCapitalization.none) { + inputFormatters.add(TextCapitalizationFormatter(textCapitalization)); } - return TextEditingValue( - text: text, - selection: newValue.selection, - ); - } + Widget? revealPasswordIcon; + if (password && canRevealPassword) { + revealPasswordIcon = GestureDetector( + child: Icon( + _revealPassword ? Icons.visibility_off : Icons.visibility, + ), + onTap: () { + setState(() { + _revealPassword = !_revealPassword; + }); + }); + } - /// 'Hello world' - static String inCaps(String text) { - if (text.isEmpty) { - return text; + var textVerticalAlign = widget.control.getDouble("text_vertical_align"); + + FocusNode focusNode = shiftEnter ? _shiftEnterfocusNode : _focusNode; + var focusValue = widget.control.getString("focus"); + var blurValue = widget.control.getString("blur"); + if (focusValue != null && focusValue != _lastFocusValue) { + _lastFocusValue = focusValue; + focusNode.requestFocus(); } - String result = ''; - for (int i = 0; i < text.length; i++) { - if (text[i] != ' ') { - result += '${text[i].toUpperCase()}${text.substring(i + 1)}'; - break; - } else { - result += text[i]; - } + if (blurValue != null && blurValue != _lastBlurValue) { + _lastBlurValue = blurValue; + _focusNode.unfocus(); } - return result; - } - /// 'HELLO WORLD' - static String allInCaps(String text) => text.toUpperCase(); + var fitParentSize = widget.control.getBool("fit_parent_size", false)!; + var maxLength = widget.control.getInt("max_length"); + + Widget textField = TextFormField( + style: textStyle, + autofocus: autofocus, + enabled: !widget.control.disabled, + onFieldSubmitted: !multiline + ? (value) { + widget.control.triggerEvent("submit", value); + } + : null, + decoration: buildInputDecoration( + context, + widget.control, + customSuffix: revealPasswordIcon, + valueLength: _value.length, + maxLength: maxLength, + focused: _focused, + ), + showCursor: widget.control.getBool("show_cursor"), + textAlignVertical: textVerticalAlign != null + ? TextAlignVertical(y: textVerticalAlign) + : null, + cursorHeight: widget.control.getDouble("cursor_height"), + cursorWidth: widget.control.getDouble("cursor_width", 2.0)!, + cursorRadius: widget.control.getRadius("cursor_radius"), + keyboardType: multiline + ? TextInputType.multiline + : widget.control + .getTextInputType("keyboard_type", TextInputType.text)!, + autocorrect: widget.control.getBool("autocorrect", true)!, + enableSuggestions: widget.control.getBool("enable_suggestions", true)!, + smartDashesType: widget.control.getBool("smart_dashes_type", true)! + ? SmartDashesType.enabled + : SmartDashesType.disabled, + smartQuotesType: widget.control.getBool("smart_quotes_type", true)! + ? SmartQuotesType.enabled + : SmartQuotesType.disabled, + textAlign: widget.control.getTextAlign("text_align", TextAlign.start)!, + minLines: fitParentSize ? null : minLines, + maxLines: fitParentSize ? null : maxLines, + maxLength: maxLength, + readOnly: widget.control.getBool("read_only", false)!, + inputFormatters: inputFormatters.isNotEmpty ? inputFormatters : null, + obscureText: password && !_revealPassword, + controller: _controller, + focusNode: focusNode, + autofillHints: widget.control.getAutofillHints("autofill_hints"), + expands: fitParentSize, + enableInteractiveSelection: + widget.control.getBool("enable_interactive_selection"), + canRequestFocus: widget.control.getBool("can_request_focus", true)!, + clipBehavior: + widget.control.getClipBehavior("clip_behavior", Clip.hardEdge)!, + cursorColor: cursorColor, + ignorePointers: widget.control.getBool("ignore_pointers"), + cursorErrorColor: + widget.control.getColor("cursor_error_color", context), + stylusHandwritingEnabled: + widget.control.getBool("enable_stylus_handwriting", true)!, + scrollPadding: widget.control + .getPadding("scroll_padding", const EdgeInsets.all(20.0))!, + keyboardAppearance: widget.control.getBrightness("keyboard_brightness"), + enableIMEPersonalizedLearning: + widget.control.getBool("enable_ime_personalized_learning", true)!, + obscuringCharacter: + widget.control.getString("obscuring_character", '•')!, + mouseCursor: widget.control.getMouseCursor("mouse_cursor"), + cursorOpacityAnimates: widget.control.getBool("animate_cursor_opacity", + Theme.of(context).platform == TargetPlatform.iOS)!, + onTapAlwaysCalled: widget.control.getBool("always_call_on_tap", false)!, + strutStyle: widget.control.getStrutStyle("strut_style"), + onTap: () { + widget.control.triggerEvent("click"); + }, + onTapOutside: widget.control.getBool("on_tap_outside", false)! + ? (PointerDownEvent? event) { + widget.control.triggerEvent("tap_outside"); + } + : null, + onChanged: (String value) { + _value = value; + widget.control.updateProperties({"value": value}); + if (widget.control.getBool("on_change", false)!) { + widget.control.triggerEvent("change", value); + } + }); - /// 'Hello World' - static String capitalizeFirstofEach(String text) => text - .replaceAll(RegExp(' +'), ' ') - .split(" ") - .map((str) => inCaps(str)) - .join(" "); -} + if (cursorColor != null || selectionColor != null) { + textField = TextSelectionTheme( + data: TextSelectionTheme.of(context).copyWith( + cursorColor: cursorColor, selectionColor: selectionColor), + child: textField); + } -class CustomNumberFormatter extends TextInputFormatter { - final String pattern; + // linux workaround for https://github.com/flet-dev/flet/issues/3934 + textField = + isLinuxDesktop() ? ExcludeSemantics(child: textField) : textField; - CustomNumberFormatter(this.pattern); + if (widget.control.getExpand("expand", 0)! > 0) { + return LayoutControl(control: widget.control, child: textField); + } else { + double? width = widget.control.getDouble("width"); - @override - TextEditingValue formatEditUpdate( - TextEditingValue oldValue, TextEditingValue newValue) { - final regExp = RegExp(pattern); - if (regExp.hasMatch(newValue.text)) { - return newValue; + return LayoutControl( + control: widget.control, + child: width == null + ? ConstrainedBox( + constraints: const BoxConstraints.tightFor(width: 300), + child: textField) + : textField, + ); } - // If newValue is invalid, keep the old value - return oldValue; } } diff --git a/packages/flet/lib/src/controls/time_picker.dart b/packages/flet/lib/src/controls/time_picker.dart index f584e0045b..c4b1c5ff6d 100644 --- a/packages/flet/lib/src/controls/time_picker.dart +++ b/packages/flet/lib/src/controls/time_picker.dart @@ -1,92 +1,94 @@ import 'package:flutter/material.dart'; -import '../flet_control_backend.dart'; import '../models/control.dart'; -import '../utils/others.dart'; +import '../utils/colors.dart'; +import '../utils/icons.dart'; +import '../utils/locale.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; -class TimePickerControl extends StatefulWidget { - final Control? parent; +class TimePickerControl extends StatelessWidget { final Control control; - final List children; - final bool parentDisabled; - final FletControlBackend backend; - const TimePickerControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.backend}); + const TimePickerControl({super.key, required this.control}); - @override - State createState() => _TimePickerControlState(); -} - -class _TimePickerControlState extends State { @override Widget build(BuildContext context) { - debugPrint("TimePicker build: ${widget.control.id}"); + debugPrint("TimePicker build: ${control.id}"); - bool lastOpen = widget.control.state["open"] ?? false; + bool lastOpen = control.getBool("_open", false)!; - var open = widget.control.attrBool("open", false)!; - TimeOfDay value = widget.control.attrTime("value", TimeOfDay.now())!; + var open = control.getBool("open", false)!; + var value = control.getTimeOfDay("value", TimeOfDay.now())!; + var hourFormat = control.getString("hour_format"); + var switchToTimerEntryModeIcon = + control.getIconData("switch_to_timer_icon"); + var switchToInputEntryModeIcon = + control.getIconData("switch_to_input_icon"); + var locale = control.getLocale("locale"); void onClosed(TimeOfDay? timeValue) { - String stringValue; - String eventName; - if (timeValue == null) { - String hourString = value.hour.toString(); - String minuteString = value.minute.toString(); - stringValue = '$hourString:$minuteString'; - eventName = "dismiss"; - } else { - String hourString = timeValue.hour.toString(); - String minuteString = timeValue.minute.toString(); - stringValue = '$hourString:$minuteString'; - eventName = "change"; + control.updateProperties({"_open": false}, python: false); + control.updateProperties({"value": timeValue ?? value, "open": false}); + if (timeValue != null) { + control.triggerEvent("change", timeValue); } - widget.control.state["open"] = false; - widget.backend.updateControlState( - widget.control.id, {"value": stringValue, "open": "false"}); - widget.backend - .triggerControlEvent(widget.control.id, eventName, stringValue); + control.triggerEvent("dismiss", timeValue == null); } Widget createSelectTimeDialog() { Widget dialog = TimePickerDialog( initialTime: value, - helpText: widget.control.attrString("helpText"), - cancelText: widget.control.attrString("cancelText"), - confirmText: widget.control.attrString("confirmText"), - hourLabelText: widget.control.attrString("hourLabelText"), - minuteLabelText: widget.control.attrString("minuteLabelText"), - errorInvalidText: widget.control.attrString("errorInvalidText"), - initialEntryMode: parseTimePickerEntryMode( - widget.control.attrString("timePickerEntryMode"), - TimePickerEntryMode.dial)!, - orientation: parseOrientation(widget.control.attrString("orientation")), + helpText: control.getString("help_text"), + cancelText: control.getString("cancel_text"), + confirmText: control.getString("confirm_text"), + hourLabelText: control.getString("hour_label_text"), + minuteLabelText: control.getString("minute_label_text"), + errorInvalidText: control.getString("error_invalid_text"), + initialEntryMode: control.getTimePickerEntryMode( + "entry_mode", TimePickerEntryMode.dial)!, + orientation: control.getOrientation("orientation"), + switchToTimerEntryModeIcon: switchToTimerEntryModeIcon != null + ? Icon(switchToTimerEntryModeIcon) + : null, + switchToInputEntryModeIcon: switchToInputEntryModeIcon != null + ? Icon(switchToInputEntryModeIcon) + : null, onEntryModeChanged: (TimePickerEntryMode mode) { - widget.backend.triggerControlEvent( - widget.control.id, "entryModeChange", mode.name); + control.updateProperties({"entry_mode": mode.name}); + control.triggerEvent("entry_mode_change", {"entry_mode": mode.name}); }, ); - return dialog; + final hourFormatMap = {"h12": false, "h24": true, "system": null}; + return MediaQuery( + data: MediaQuery.of(context) + .copyWith(alwaysUse24HourFormat: hourFormatMap[hourFormat]), + child: locale == null || !locale.isSupportedByDelegates() + ? dialog + : Localizations.override( + context: context, locale: locale, child: dialog), + ); } if (open && (open != lastOpen)) { - widget.control.state["open"] = open; + control.updateProperties({"_open": open}, python: false); WidgetsBinding.instance.addPostFrameCallback((_) { + ModalRoute? dialogRoute; showDialog( - barrierColor: widget.control.attrColor("barrierColor", context), + barrierColor: control.getColor("barrier_color", context), + barrierDismissible: !control.getBool("modal", false)!, useRootNavigator: false, context: context, - builder: (context) => createSelectTimeDialog()).then((result) { - debugPrint("pickTime() completed"); - onClosed(result); + builder: (context) { + dialogRoute ??= ModalRoute.of(context); + return createSelectTimeDialog(); + }).then((result) { + (dialogRoute?.completed ?? Future.value()).then((_) { + onClosed(result); + }); }); }); } diff --git a/packages/flet/lib/src/controls/transparent_pointer.dart b/packages/flet/lib/src/controls/transparent_pointer.dart index 20f60273f0..42dfc91e76 100644 --- a/packages/flet/lib/src/controls/transparent_pointer.dart +++ b/packages/flet/lib/src/controls/transparent_pointer.dart @@ -1,42 +1,23 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import 'base_controls.dart'; class TransparentPointerControl extends StatelessWidget { - final Control? parent; final Control control; - final List children; - final bool parentDisabled; - final bool? parentAdaptive; - - const TransparentPointerControl( - {super.key, - this.parent, - required this.control, - required this.children, - required this.parentDisabled, - required this.parentAdaptive}); + + const TransparentPointerControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("TransparentPointer build: ${control.id}"); - var contentCtrls = - children.where((c) => c.name == "content" && c.isVisible); - bool disabled = control.isDisabled || parentDisabled; - - return constrainedControl( - context, - TransparentPointer( - transparent: true, - child: contentCtrls.isNotEmpty - ? createControl(control, contentCtrls.first.id, disabled, - parentAdaptive: parentAdaptive) - : null), - parent, - control); + var pointer = TransparentPointer( + transparent: true, child: control.buildWidget("content")); + + return LayoutControl(control: control, child: pointer); } } diff --git a/packages/flet/lib/src/controls/vertical_divider.dart b/packages/flet/lib/src/controls/vertical_divider.dart index 5576f08895..52c1404377 100644 --- a/packages/flet/lib/src/controls/vertical_divider.dart +++ b/packages/flet/lib/src/controls/vertical_divider.dart @@ -1,26 +1,29 @@ import 'package:flutter/material.dart'; import '../models/control.dart'; -import 'create_control.dart'; +import '../utils/borders.dart'; +import '../utils/colors.dart'; +import '../utils/numbers.dart'; +import 'base_controls.dart'; class VerticalDividerControl extends StatelessWidget { - final Control? parent; final Control control; - const VerticalDividerControl( - {super.key, required this.parent, required this.control}); + const VerticalDividerControl({super.key, required this.control}); @override Widget build(BuildContext context) { debugPrint("VerticalDivider build: ${control.id}"); + var divider = VerticalDivider( - width: control.attrDouble("width"), - thickness: control.attrDouble("thickness"), - color: control.attrColor("color", context), - indent: control.attrDouble("leadingIndent"), - endIndent: control.attrDouble("trailingIndent"), + width: control.getDouble("width"), + thickness: control.getDouble("thickness"), + color: control.getColor("color", context), + indent: control.getDouble("leading_indent"), + endIndent: control.getDouble("trailing_indent"), + radius: control.getBorderRadius("radius"), ); - return baseControl(context, divider, parent, control); + return BaseControl(control: control, child: divider); } } diff --git a/packages/flet/lib/src/controls/view.dart b/packages/flet/lib/src/controls/view.dart new file mode 100644 index 0000000000..4c7bbcee62 --- /dev/null +++ b/packages/flet/lib/src/controls/view.dart @@ -0,0 +1,332 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; + +import '../controls/control_widget.dart'; +import '../extensions/control.dart'; +import '../flet_backend.dart'; +import '../models/control.dart'; +import '../models/page_design.dart'; +import '../utils/alignment.dart'; +import '../utils/box.dart'; +import '../utils/buttons.dart'; +import '../utils/colors.dart'; +import '../utils/edge_insets.dart'; +import '../utils/numbers.dart'; +import '../utils/theme.dart'; +import '../widgets/loading_page.dart'; +import '../widgets/page_context.dart'; +import '../widgets/page_media.dart'; +import 'app_bar.dart'; +import 'cupertino_app_bar.dart'; +import 'scroll_notification_control.dart'; +import 'scrollable_control.dart'; + +class ViewControl extends StatefulWidget { + final Control control; + + ViewControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + State createState() => _ViewControlState(); +} + +class _ViewControlState extends State { + final _materialScaffoldKey = GlobalKey(); + final _cupertinoPageScaffoldKey = GlobalKey(); + Control? _overlay; + Control? _dialogs; + Completer? _popCompleter; + bool _allowPop = false; + + @override + void initState() { + debugPrint("View.initState: ${widget.control.id}"); + super.initState(); + _overlay = widget.control.parent?.child("_overlay"); + _overlay?.addListener(_overlayOrDialogsChanged); + _dialogs = widget.control.parent?.child("_dialogs"); + _dialogs?.addListener(_overlayOrDialogsChanged); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void didUpdateWidget(covariant ViewControl oldWidget) { + debugPrint("View.didUpdateWidget: ${widget.control.id}"); + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + debugPrint("View.dispose: ${widget.control.id}"); + _overlay?.removeListener(_overlayOrDialogsChanged); + _dialogs?.removeListener(_overlayOrDialogsChanged); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("View.$name($args)"); + switch (name) { + case "show_drawer": + _materialScaffoldKey.currentState?.openDrawer(); + break; + case "close_drawer": + _materialScaffoldKey.currentState?.closeDrawer(); + break; + case "show_end_drawer": + _materialScaffoldKey.currentState?.openEndDrawer(); + break; + case "close_end_drawer": + _materialScaffoldKey.currentState?.closeEndDrawer(); + break; + case "confirm_pop": + if (_popCompleter != null && !_popCompleter!.isCompleted) { + _popCompleter?.complete(args["should_pop"]); + } + break; + } + } + + void _overlayOrDialogsChanged() { + if (!mounted) { + return; + } + setState(() {}); + } + + Future _dismissDrawer(int drawerId) async { + widget.control.backend.triggerControlEventById(drawerId, "dismiss"); + } + + @override + Widget build(BuildContext context) { + debugPrint("View.build: ${widget.control.id}"); + + var control = widget.control; + + final mainAlignment = parseMainAxisAlignment( + control.getString("vertical_alignment"), MainAxisAlignment.start)!; + final crossAlignment = parseCrossAxisAlignment( + control.getString("horizontal_alignment"), CrossAxisAlignment.start)!; + + final textDirection = control.parent!.getBool("rtl", false)! + ? TextDirection.rtl + : TextDirection.ltr; + + var column = Column( + mainAxisAlignment: mainAlignment, + crossAxisAlignment: crossAlignment, + spacing: control.getDouble("spacing", 10)!, + children: control + .children("controls") + .where((c) => c.visible) + .map((child) => + ControlWidget(control: child, key: ValueKey(child.id))) + .toList()); + + Widget child = ScrollableControl( + control: control, + scrollDirection: Axis.vertical, + wrapIntoScrollableView: true, + child: column, + ); + + if (control.getBool("on_scroll", false)!) { + child = ScrollNotificationControl(control: control, child: child); + } + + var pageData = PageContext.of(context); + + Control? appBar = control.child("appbar"); + Widget? appBarWidget; + if (appBar != null) { + appBar.notifyParent = true; + appBarWidget = pageData?.widgetsDesign == PageDesign.cupertino || + appBar.type == "CupertinoAppBar" + ? CupertinoAppBarControl(control: appBar) + as ObstructingPreferredSizeWidget + : AppBarControl(control: appBar); + } + + List overlayWidgets = []; + var pageViews = control.parent!.children("views"); + var overlayControls = _overlay?.children("controls"); + var dialogControls = _dialogs?.children("controls"); + + var drawer = widget.control.child("drawer"); + var endDrawer = widget.control.child("end_drawer"); + + var isRootView = control.id == pageViews.first.id; + + if (overlayControls != null && dialogControls != null) { + if (control.id == pageViews.last.id) { + // Key each ControlWidget by id so Flutter preserves Element identity + // when the list length changes. Without keys, adding or removing an + // entry can reconstruct the AlertDialogControl Element mid-dismiss + // and the `!open && lastOpen` branch that calls Navigator.pop() + // never matches, leaving the dialog stuck open. + overlayWidgets.addAll(overlayControls + .map((c) => ControlWidget(control: c, key: ValueKey(c.id)))); + overlayWidgets.addAll(dialogControls + .map((c) => ControlWidget(control: c, key: ValueKey(c.id)))); + overlayWidgets.add(PageMedia(view: widget.control.parent)); + } + } + + Widget body = Stack(children: [ + SizedBox.expand( + child: Container( + padding: control.getPadding("padding", const EdgeInsets.all(10))!, + child: child)), + ...overlayWidgets + ]); + + var materialTheme = pageData?.themeMode == ThemeMode.light || + ((pageData?.themeMode == null || + pageData?.themeMode == ThemeMode.system) && + pageData?.brightness == Brightness.light) + ? parseTheme(control.parent!.get("theme"), context, Brightness.light) + : control.parent!.getString("dark_theme") != null + ? parseTheme( + control.parent!.get("dark_theme"), context, Brightness.dark) + : parseTheme( + control.parent!.get("theme"), context, Brightness.dark); + + Widget scaffold = Scaffold( + key: _materialScaffoldKey, + backgroundColor: control.getColor("bgcolor", context) ?? + ((pageData?.widgetsDesign == PageDesign.cupertino) + ? CupertinoTheme.of(context).scaffoldBackgroundColor + : Theme.of(context).scaffoldBackgroundColor), + appBar: appBarWidget is AppBarControl ? appBarWidget : null, + drawer: drawer != null ? ControlWidget(control: drawer) : null, + onDrawerChanged: (opened) { + if (!opened) { + _dismissDrawer(drawer!.id); + } + }, + endDrawer: endDrawer != null ? ControlWidget(control: endDrawer) : null, + onEndDrawerChanged: (opened) { + if (!opened) { + _dismissDrawer(endDrawer!.id); + } + }, + body: body, + bottomNavigationBar: control.buildWidget("navigation_bar") ?? + control.buildWidget("bottom_appbar"), + floatingActionButton: control.buildWidget("floating_action_button"), + floatingActionButtonLocation: control.getFloatingActionButtonLocation( + "floating_action_button_location", + FloatingActionButtonLocation.endFloat), + ); + + var systemOverlayStyle = + materialTheme.extension(); + + if (systemOverlayStyle != null && + systemOverlayStyle.systemUiOverlayStyle != null && + appBarWidget == null) { + scaffold = AnnotatedRegion( + value: systemOverlayStyle.systemUiOverlayStyle!, + child: scaffold, + ); + } + + if (appBarWidget is CupertinoAppBarControl) { + scaffold = CupertinoPageScaffold( + key: _cupertinoPageScaffoldKey, + backgroundColor: control.getColor("bgcolor", context), + navigationBar: appBarWidget, + child: scaffold); + } + + var backend = FletBackend.of(context); + var showAppStartupScreen = backend.showAppStartupScreen ?? false; + var appStartupScreenMessage = backend.appStartupScreenMessage ?? ""; + + var appStatus = + context.select( + (backend) => (isLoading: backend.isLoading, error: backend.error)); + var formattedErrorMessage = backend.formatAppErrorMessage(appStatus.error); + + Widget? loadingPage; + if ((appStatus.isLoading || appStatus.error != "") && + showAppStartupScreen) { + loadingPage = LoadingPage( + isLoading: appStatus.isLoading, + message: appStatus.isLoading + ? appStartupScreenMessage + : formattedErrorMessage, + ); + } + + Widget result = Directionality( + textDirection: textDirection, + child: loadingPage != null + ? Stack( + children: [scaffold, loadingPage], + ) + : scaffold); + + var backgroundDecoration = control.getBoxDecoration("decoration", context); + var foregroundDecoration = + control.getBoxDecoration("foreground_decoration", context); + if (backgroundDecoration != null || foregroundDecoration != null) { + result = Container( + decoration: backgroundDecoration, + foregroundDecoration: foregroundDecoration, + child: result, + ); + } + + result = PopScope( + canPop: _allowPop || control.getBool("can_pop", true)!, + onPopInvokedWithResult: (didPop, result) { + if (didPop || !control.getBool("on_confirm_pop", false)!) { + return; + } + debugPrint("Page.onPopInvokedWithResult()"); + if (_popCompleter != null && !_popCompleter!.isCompleted) { + _popCompleter!.completeError("Aborted"); + } + _popCompleter = Completer(); + control.triggerEvent("confirm_pop"); + _popCompleter!.future + .timeout( + const Duration(minutes: 5), + onTimeout: () => false, + ) + .then((shouldPop) { + if (context.mounted && shouldPop) { + if (isRootView) { + SystemNavigator.pop(); + } else { + if (mounted) { + setState(() { + _allowPop = true; + }); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) { + return; + } + Navigator.pop(context, true); + if (mounted) { + setState(() { + _allowPop = false; + }); + } + }); + } + } + } + }).onError((e, st) {/* do nothing */}); + }, + child: result); + return result; + } +} diff --git a/packages/flet/lib/src/controls/window_drag_area.dart b/packages/flet/lib/src/controls/window_drag_area.dart new file mode 100644 index 0000000000..32b0b0b2e9 --- /dev/null +++ b/packages/flet/lib/src/controls/window_drag_area.dart @@ -0,0 +1,122 @@ +import 'dart:async'; + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:window_manager/window_manager.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/events.dart'; +import '../utils/numbers.dart'; +import '../widgets/error.dart'; +import 'base_controls.dart'; + +class WindowDragAreaControl extends StatefulWidget { + final Control control; + + const WindowDragAreaControl({super.key, required this.control}); + + @override + State createState() => _WindowDragAreaControlState(); +} + +class _WindowDragAreaControlState extends State { + /// Timestamp of the last tap-up event, used for double-tap detection. + DateTime? _lastTapUpTime; + + /// Position of the last tap-up event, used for double-tap detection. + Offset? _lastTapUpPosition; + + /// Whether double-tap-to-maximize behavior is enabled. + bool get _maximizable => widget.control.getBool("maximizable", true)!; + + /// Called when the user presses down inside the drag area. + /// + /// If a recent tap-up occurred close in time and space (within Flutter’s + /// [kDoubleTapTimeout] and [kDoubleTapSlop]), this is treated as a double-tap + /// and triggers a maximize/unmaximize toggle. + void _handlePointerDown(PointerDownEvent event) { + if (!_maximizable || _lastTapUpTime == null) return; + + final now = DateTime.now(); + final timeDiff = now.difference(_lastTapUpTime!); + final posDiff = (event.position - _lastTapUpPosition!).distance; + + // If tap timing and distance match Flutter's double-tap thresholds + // — treat this as a double-tap. + if (timeDiff <= kDoubleTapTimeout && posDiff <= kDoubleTapSlop) { + _resetDoubleTapState(); + unawaited(_toggleMaximize()); + } + } + + /// Called when the user lifts their finger or mouse button. + /// + /// Records the time and position so the next pointer down can detect + /// a double-tap sequence. + void _handlePointerUp(PointerUpEvent event) { + if (!_maximizable) return; + _lastTapUpTime = DateTime.now(); + _lastTapUpPosition = event.position; + } + + /// Clears any stored double-tap tracking information. + void _resetDoubleTapState() { + _lastTapUpTime = null; + _lastTapUpPosition = null; + } + + /// Toggles between maximized and restored window states. + Future _toggleMaximize() async { + final isMaximized = await windowManager.isMaximized(); + + if (isMaximized) { + await windowManager.unmaximize(); + } else { + await windowManager.maximize(); + } + + widget.control + .triggerEvent("double_tap", isMaximized ? "unmaximize" : "maximize"); + } + + @override + Widget build(BuildContext context) { + debugPrint("WindowDragArea build: ${widget.control.id}"); + + final content = widget.control.buildWidget("content"); + if (content == null) { + return const ErrorControl( + "WindowDragArea.content must be provided and visible"); + } + + Widget dragArea = GestureDetector( + behavior: HitTestBehavior.translucent, + onPanStart: (DragStartDetails details) { + // Start moving the window. + windowManager.startDragging(); + + widget.control.triggerEvent("drag_start", details.toMap()); + }, + onPanEnd: (DragEndDetails details) { + widget.control.triggerEvent("drag_end", details.toMap()); + }, + child: content, + ); + + // If maximization is enabled, wrap with a listener to detect double-taps. + // Using a [Listener] instead of the above [GestureDetector] ensures the + // widget doesn’t block or consume gestures from its children. + if (_maximizable) { + dragArea = Listener( + behavior: HitTestBehavior.translucent, + onPointerDown: _handlePointerDown, + onPointerUp: _handlePointerUp, + onPointerCancel: (_) => _resetDoubleTapState(), + child: dragArea, + ); + } + + return LayoutControl(control: widget.control, child: dragArea); + } +} diff --git a/packages/flet/lib/src/extensions/control.dart b/packages/flet/lib/src/extensions/control.dart new file mode 100644 index 0000000000..43e870d340 --- /dev/null +++ b/packages/flet/lib/src/extensions/control.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; + +import '../controls/control_widget.dart'; +import '../models/control.dart'; +import '../utils/icons.dart'; +import '../widgets/error.dart'; + +/// Extension on [Control] to easily convert child or children controls +/// into corresponding [Widget]s using [ControlWidget]. +extension WidgetFromControl on Control { + /// Returns a list of [Widget]s built from the children of this control + /// under the given [propertyName]. + /// + /// If [visibleOnly] is `true` (default), only includes children that are visible. + /// + /// If [notifyParent] is `true`, sets `notifyParent` on each child control. + List buildWidgets(String propertyName, + {bool visibleOnly = true, bool notifyParent = false}) { + return children(propertyName, visibleOnly: visibleOnly).map((child) { + child.notifyParent = notifyParent; + return ControlWidget(control: child); + }).toList(); + } + + /// Returns a single [Widget] built from the child of this control + /// under the given [propertyName], or `null` if not present or not visible. + /// + /// If [visibleOnly] is `true` (default), returns `null` for an invisible child. + /// + /// If [notifyParent] is `true`, sets `notifyParent` on the child control. + /// + /// If [key] is provided, applies it to the returned [ControlWidget]. + Widget? buildWidget(String propertyName, + {bool visibleOnly = true, bool notifyParent = false, Key? key}) { + final c = child(propertyName, visibleOnly: visibleOnly); + if (c == null) return null; + c.notifyParent = notifyParent; + return ControlWidget(key: key, control: c); + } + + Widget? buildIconOrWidget( + String propertyName, { + bool visibleOnly = true, + bool notifyParent = false, + Key? key, + Color? color, + bool required = false, + Widget? errorWidget, + }) { + var icon = get(propertyName); + + if (icon is Control) { + final widget = buildWidget( + propertyName, + visibleOnly: visibleOnly, + notifyParent: notifyParent, + key: key, + ); + if (widget != null) return widget; + } else if (icon is int) { + // Icon values are stored as raw integers (set_id << 16 | index) in this codebase. + return Icon(getIconData(propertyName), color: color); + } + + if (required) { + return errorWidget ?? + ErrorControl("Error displaying $type", + description: "$propertyName must be specified"); + } + + return null; + } + + Widget? buildTextOrWidget( + String propertyName, { + Key? key, + bool visibleOnly = true, + bool notifyParent = false, + TextStyle? textStyle, + bool required = false, + Widget? errorWidget, + }) { + var content = get(propertyName); + + if (content is Control) { + return buildWidget( + propertyName, + visibleOnly: visibleOnly, + notifyParent: notifyParent, + key: key, + ); + } else if (content is String) { + return Text(content, style: textStyle); + } + + if (required) { + return errorWidget ?? + ErrorControl("Error displaying $type", + description: "$propertyName must be specified"); + } + + return null; + } +} + +extension InternalConfiguration on Control { + /// The internal configuration of this control. + /// Represented on Python side by `BaseControl._internals` property. + Map? get internals { + return get("_internals") as Map?; + } +} diff --git a/packages/flet/lib/src/flet_app.dart b/packages/flet/lib/src/flet_app.dart index e9ecc6c0af..ee0873a934 100644 --- a/packages/flet/lib/src/flet_app.dart +++ b/packages/flet/lib/src/flet_app.dart @@ -1,21 +1,30 @@ import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; -import 'control_factory.dart'; +import 'controls/control_widget.dart'; import 'flet_app_errors_handler.dart'; -import 'flet_app_main.dart'; -import 'flet_app_services.dart'; +import 'flet_backend.dart'; +import 'flet_extension.dart'; +import 'models/control.dart'; +import 'testing/tester.dart'; +/// FletApp - The top-level widget that initializes everything class FletApp extends StatefulWidget { final String pageUrl; final String assetsDir; final bool? showAppStartupScreen; final String? appStartupScreenMessage; - final String? controlId; + final String? appErrorMessage; + final int? controlId; final String? title; final FletAppErrorsHandler? errorsHandler; final int? reconnectIntervalMs; final int? reconnectTimeoutMs; - final List? createControlFactories; + final List? extensions; + final Map? args; + final bool? forcePyodide; + final Tester? tester; + final bool multiView; const FletApp( {super.key, @@ -23,44 +32,57 @@ class FletApp extends StatefulWidget { required this.assetsDir, this.showAppStartupScreen, this.appStartupScreenMessage, + this.appErrorMessage, this.controlId, this.title, this.errorsHandler, this.reconnectIntervalMs, this.reconnectTimeoutMs, - this.createControlFactories}); + this.extensions, + this.args, + this.forcePyodide, + this.tester, + this.multiView = false}); @override State createState() => _FletAppState(); } class _FletAppState extends State { - String? _pageUrl; - FletAppServices? _appServices; + FletBackend? backend; @override void deactivate() { - _appServices?.close(); + backend?.dispose(); super.deactivate(); } @override Widget build(BuildContext context) { - if (widget.pageUrl != _pageUrl) { - _pageUrl = widget.pageUrl; - _appServices = FletAppServices( - parentAppServices: FletAppServices.maybeOf(context), - showAppStartupScreen: widget.showAppStartupScreen, - appStartupScreenMessage: widget.appStartupScreenMessage, - controlId: widget.controlId, - reconnectIntervalMs: widget.reconnectIntervalMs, - reconnectTimeoutMs: widget.reconnectTimeoutMs, - pageUrl: widget.pageUrl, - assetsDir: widget.assetsDir, - errorsHandler: widget.errorsHandler, - createControlFactories: widget.createControlFactories ?? [], - child: FletAppMain(title: widget.title ?? "Flet")); - } - return _appServices!; + return ChangeNotifierProvider( + create: (context) { + return FletBackend( + showAppStartupScreen: widget.showAppStartupScreen, + appStartupScreenMessage: widget.appStartupScreenMessage, + appErrorMessage: widget.appErrorMessage, + controlId: widget.controlId, + reconnectIntervalMs: widget.reconnectIntervalMs, + reconnectTimeoutMs: widget.reconnectTimeoutMs, + pageUri: Uri.parse(widget.pageUrl), + assetsDir: widget.assetsDir, + errorsHandler: widget.errorsHandler, + extensions: widget.extensions ?? [], + args: widget.args, + forcePyodide: widget.forcePyodide, + tester: widget.tester, + multiView: widget.multiView, + parentFletBackend: + Provider.of(context, listen: false)); + }, + child: Selector( + selector: (_, backend) => backend.page, + builder: (_, page, __) => ControlWidget(control: page), + ), + ); } } diff --git a/packages/flet/lib/src/flet_app_context.dart b/packages/flet/lib/src/flet_app_context.dart deleted file mode 100644 index 8a6e5e8213..0000000000 --- a/packages/flet/lib/src/flet_app_context.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/material.dart'; - -class FletAppContext extends InheritedWidget { - final ThemeMode? themeMode; - - const FletAppContext( - {super.key, required this.themeMode, required super.child}); - - @override - bool updateShouldNotify(covariant InheritedWidget oldWidget) { - return false; - } - - static FletAppContext? of(BuildContext context) => - context.dependOnInheritedWidgetOfExactType(); -} diff --git a/packages/flet/lib/src/flet_app_main.dart b/packages/flet/lib/src/flet_app_main.dart deleted file mode 100644 index d2cbe32a9b..0000000000 --- a/packages/flet/lib/src/flet_app_main.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; - -import 'controls/create_control.dart'; -import 'flet_app_services.dart'; -import 'models/app_state.dart'; - -class FletAppMain extends StatelessWidget { - final String title; - - const FletAppMain({ - super.key, - required this.title, - }); - - @override - Widget build(BuildContext context) { - return StoreProvider( - store: FletAppServices.of(context).store, - child: createControl(null, "page", false), - ); - } -} diff --git a/packages/flet/lib/src/flet_app_services.dart b/packages/flet/lib/src/flet_app_services.dart deleted file mode 100644 index d65c95bdae..0000000000 --- a/packages/flet/lib/src/flet_app_services.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:redux/redux.dart'; - -import 'actions.dart'; -import 'control_factory.dart'; -import 'flet_app_errors_handler.dart'; -import 'flet_server.dart'; -import 'flet_server_protocol.dart'; -import 'models/app_state.dart'; -import 'reducers.dart'; - -class FletAppServices extends InheritedWidget { - final FletAppServices? parentAppServices; - final bool? showAppStartupScreen; - final String? appStartupScreenMessage; - final String? controlId; - final int? reconnectIntervalMs; - final int? reconnectTimeoutMs; - final String pageUrl; - final String assetsDir; - final FletAppErrorsHandler? errorsHandler; - late final FletServer server; - late final Store store; - final Map globalKeys = {}; - final Map controlInvokeMethods = {}; - final List createControlFactories; - - FletAppServices( - {super.key, - required super.child, - required this.pageUrl, - required this.assetsDir, - this.errorsHandler, - this.parentAppServices, - this.showAppStartupScreen, - this.appStartupScreenMessage, - this.controlId, - this.reconnectIntervalMs, - this.reconnectTimeoutMs, - required this.createControlFactories}) { - store = Store(appReducer, initialState: AppState.initial()); - server = FletServer(store, controlInvokeMethods, - reconnectIntervalMs: reconnectIntervalMs, - reconnectTimeoutMs: reconnectTimeoutMs, - errorsHandler: errorsHandler); - if (errorsHandler != null) { - if (controlId == null) { - // root error handler - errorsHandler!.addListener(() { - if (store.state.isRegistered) { - server.triggerControlEvent("page", "error", errorsHandler!.error!); - } - }); - } else if (controlId != null && parentAppServices != null) { - // parent error handler - errorsHandler?.addListener(() { - parentAppServices?.server - .triggerControlEvent(controlId!, "error", errorsHandler!.error!); - }); - } - } - // connect to a page - var pageUri = Uri.parse(pageUrl); - store.dispatch(PageLoadAction(pageUri, assetsDir, server)); - } - - @override - bool updateShouldNotify(covariant InheritedWidget oldWidget) { - return false; - } - - void close() { - server.disconnect(); - } - - static FletAppServices? maybeOf(BuildContext context) => - context.dependOnInheritedWidgetOfExactType(); - - static FletAppServices of(BuildContext context) => maybeOf(context)!; -} diff --git a/packages/flet/lib/src/flet_backend.dart b/packages/flet/lib/src/flet_backend.dart new file mode 100644 index 0000000000..f173ee8584 --- /dev/null +++ b/packages/flet/lib/src/flet_backend.dart @@ -0,0 +1,576 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'flet_app_errors_handler.dart'; +import 'flet_core_extension.dart'; +import 'flet_extension.dart'; +import 'models/asset_source.dart'; +import 'models/control.dart'; +import 'models/window_state.dart'; +import 'protocol/control_event_body.dart'; +import 'protocol/invoke_method_request_body.dart'; +import 'protocol/invoke_method_response_body.dart'; +import 'protocol/message.dart'; +import 'protocol/page_media_data.dart'; +import 'protocol/patch_control_request_body.dart'; +import 'protocol/python_output_body.dart'; +import 'protocol/register_client_request_body.dart'; +import 'protocol/register_client_response_body.dart'; +import 'protocol/session_crashed_body.dart'; +import 'protocol/update_control_body.dart'; +import 'testing/tester.dart'; +import 'transport/flet_backend_channel.dart'; +import 'utils/desktop.dart'; +import 'utils/images.dart'; +import 'utils/numbers.dart'; +import 'utils/platform.dart'; +import 'utils/platform_utils_web.dart' + if (dart.library.io) "utils/platform_utils_non_web.dart"; +import 'utils/session_store_web.dart' + if (dart.library.io) "utils/session_store_non_web.dart"; +import 'utils/uri.dart'; +import 'utils/weak_value_map.dart'; + +/// FletBackend - Handles business logic, provides data, and acts as ChangeNotifier +class FletBackend extends ChangeNotifier { + static const String defaultAppErrorMessageTemplate = + "The application encountered an error: {message}\n\n{details}"; + bool multiView = false; + bool _disposed = false; + final WeakReference? _parentFletBackend; + final Uri pageUri; + final String assetsDir; + final bool? showAppStartupScreen; + final String? appStartupScreenMessage; + final String? appErrorMessage; + final int? controlId; + final FletAppErrorsHandler? errorsHandler; + late final List extensions; + final Map? args; + final bool? forcePyodide; + final Tester? tester; + final Map globalKeys = {}; + + final WeakValueMap controlsIndex = WeakValueMap(); + final int? _reconnectIntervalMs; + final int? _reconnectTimeoutMs; + int _reconnectStarted = 0; + int _reconnectDelayMs = 0; + FletBackendChannel? _backendChannel; + final List _sendQueue = []; + String route = ""; + bool isLoading = true; + final Completer pageSizeUpdated = Completer(); + String error = ""; + Size pageSize = Size.zero; + Map sizeBreakpoints = const { + "xs": 0, + "sm": 576, + "md": 768, + "lg": 992, + "xl": 1200, + "xxl": 1400 + }; + Brightness platformBrightness = Brightness.light; + PageMediaData media = PageMediaData( + padding: PaddingData(EdgeInsets.zero), + viewPadding: PaddingData(EdgeInsets.zero), + viewInsets: PaddingData(EdgeInsets.zero), + devicePixelRatio: 0, + orientation: Orientation.portrait, + alwaysUse24HourFormat: false, + ); + TargetPlatform platform = defaultTargetPlatform; + + late Control _page; + + FletBackend( + {required this.pageUri, + required this.assetsDir, + required this.multiView, + int? reconnectIntervalMs, + int? reconnectTimeoutMs, + this.errorsHandler, + this.showAppStartupScreen, + this.appStartupScreenMessage, + this.appErrorMessage, + this.controlId, + this.args, + this.forcePyodide, + this.tester, + required extensions, + FletBackend? parentFletBackend}) + : _parentFletBackend = + parentFletBackend != null ? WeakReference(parentFletBackend) : null, + _reconnectTimeoutMs = reconnectTimeoutMs, + _reconnectIntervalMs = reconnectIntervalMs { + // add Flet extension with core controls and services + this.extensions = [...extensions, FletCoreExtension()]; + + // initial "empty" page + _page = Control.fromMap({ + "_c": "Page", + "_i": 1, + "pwa": isProgressiveWebApp(), + "web": kIsWeb, + "debug": kDebugMode, + "wasm": const bool.fromEnvironment('dart.tool.dart2wasm'), + "test": tester != null, + "multi_view": multiView, + "pyodide": isPyodideMode(), + "window": { + "_c": "Window", + "_i": 2, + } + }, this); + + _page.addListener(_onPageUpdated); + _onPageUpdated(); + + if (errorsHandler != null) { + if (controlId == null) { + // root error handler + errorsHandler!.addListener(() { + triggerControlEvent(page, "error", errorsHandler!.error!); + }); + } else if (controlId != null && _parentFletBackend != null) { + // parent error handler + errorsHandler?.addListener(() { + _parentFletBackend?.target?.triggerControlEventById( + controlId!, "error", errorsHandler!.error!); + }); + } + } + } + + static FletBackend of(BuildContext context) { + return Provider.of(context, listen: false); + } + + Control get page => _page; + + void _onPageUpdated() { + var newPlatform = parseTargetPlatform( + _page.getString("platform"), defaultTargetPlatform)!; + debugPrint("Page updated: $newPlatform $platform"); + if (newPlatform != platform) { + platform = newPlatform; + notifyListeners(); + } + } + + @override + void dispose() { + debugPrint("Disposing Flet backend."); + _disposed = true; + _page.removeListener(_onPageUpdated); + _page.dispose(); + _backendChannel?.disconnect(); + super.dispose(); + } + + Future connect() async { + debugPrint("Connecting to Flet backend $pageUri..."); + try { + _backendChannel = FletBackendChannel( + address: pageUri.toString(), + args: args ?? {}, + forcePyodide: forcePyodide == true, + onDisconnect: _onDisconnect, + onMessage: _onMessage); + await _backendChannel!.connect(); + _registerClient(); + } catch (e) { + debugPrint("Error connecting to Flet backend: $e"); + error = e.toString(); + _onDisconnect(); + } + } + + _registerClient() { + debugPrint("Registering web client: $page"); + _send( + Message( + action: MessageAction.registerClient, + payload: RegisterClientRequestBody( + sessionId: SessionStore.getSessionId(), + pageName: getWebPageName(pageUri), + page: { + "route": page.get("route"), + "pwa": page.get("pwa"), + "web": page.get("web"), + "debug": page.get("debug"), + "wasm": page.get("wasm"), + "test": page.get("test"), + "multi_view": page.get("multi_view"), + "pyodide": page.get("pyodide"), + "platform_brightness": page.get("platform_brightness"), + "width": page.get("width"), + "height": page.get("height"), + "platform": page.get("platform"), + "window": page.child("window", visibleOnly: false)!.toMap(), + "media": page.get("media"), + }).toMap()), + unbuffered: true); + } + + _onClientRegistered(RegisterClientResponseBody resp) { + if (resp.error?.isEmpty ?? true) { + // all good! + // if a root FletApp, store session ID globally + if (controlId == null) { + SessionStore.setSessionId(resp.sessionId); + } + isLoading = false; + _reconnectDelayMs = 0; + error = ""; + + page.update(resp.patch, shouldNotify: true); + + // drain send queue + debugPrint("Send queue: ${_sendQueue.length}"); + for (var message in _sendQueue) { + _send(message); + } + _sendQueue.clear(); + } else { + // error response! + isLoading = false; + error = resp.error!; + _reconnectDelayMs = 0; + } + _reconnectDelayMs = 0; + notifyListeners(); + } + + void onRouteUpdated(String newRoute) { + debugPrint("Route changed: $newRoute"); + + if (route == "" && isLoading) { + () async { + await pageSizeUpdated.future; + debugPrint("Registering web client with route: $newRoute"); + String platform = defaultTargetPlatform.name.toLowerCase(); + if (platform == "android" && !kIsWeb) { + try { + DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); + AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; + if (androidInfo.systemFeatures + .contains('android.software.leanback')) { + platform = "android_tv"; + } + } on Exception catch (e) { + debugPrint(e.toString()); + } + } + + // update page details + page.update({"route": newRoute, "platform": platform}, + shouldNotify: false); + + // connect to the server + connect(); + }(); + } else { + // existing route change + debugPrint("New page route: $newRoute"); + _sendRouteChangeEvent(newRoute); + } + + route = newRoute; + notifyListeners(); + } + + /// Triggers a control event for the specified [control]. + /// + /// This method checks if the control has an event handler for the given + /// [eventName] and triggers the event if the application is not in a loading state. + /// + /// - [control]: The control for which the event is triggered. + /// - [eventName]: The name of the event to trigger. + /// - [eventData]: Optional data to pass along with the event. + void triggerControlEvent(Control control, String eventName, + [dynamic eventData]) { + if (control.get("on_$eventName") == true) { + debugPrint("${control.type}(${control.id}).on_$eventName($eventData)"); + triggerControlEventById(control.id, eventName, eventData); + } + } + + void triggerControlEventById(int controlId, String eventName, + [dynamic eventData]) { + _send(Message( + action: MessageAction.controlEvent, + payload: ControlEventBody( + target: controlId, name: eventName, data: eventData) + .toMap())); + } + + void _sendRouteChangeEvent(String route) { + updateControl(page.id, {"route": route}, notify: true); + triggerControlEventById(page.id, "route_change", {"route": route}); + } + + void onWindowEvent(String eventName, WindowState windowState) { + debugPrint("Window event - $eventName: $windowState"); + var window = page.get("window"); + if (window != null && window is Control) { + updateControl(window.id, windowState.toMap()); + triggerControlEvent(window, "event", {"type": eventName}); + notifyListeners(); + } + } + + void updatePageSize(Size newSize, {Control? view}) async { + debugPrint("Page size updated: $newSize"); + pageSize = newSize; + var newProps = {"width": newSize.width, "height": newSize.height}; + var ctrl = view ?? page; + updateControl(ctrl.id, newProps); + + // Initial page sizing should only hydrate Python state. Later size changes + // must reach Python even if no explicit "on_resize" handler is set. + if (pageSizeUpdated.isCompleted) { + triggerControlEventById(ctrl.id, "resize", newProps); + } + + if (isDesktopPlatform()) { + var windowState = await getWindowState(); + debugPrint("Window state updated: $windowState"); + var window = page.child("window", visibleOnly: false)!; + updateControl(window.id, windowState.toMap()); + triggerControlEvent(window, "event", {"type": "resized"}); + } + + if (!pageSizeUpdated.isCompleted) { + pageSizeUpdated.complete(); + } + notifyListeners(); + } + + void updateBrightness(Brightness newBrightness) { + debugPrint("Platform brightness updated: $newBrightness"); + platformBrightness = newBrightness; + updateControl(page.id, {"platform_brightness": newBrightness.name}); + triggerControlEventById( + page.id, "platform_brightness_change", newBrightness.name); + notifyListeners(); + } + + void updateMedia(PageMediaData newMedia, {Control? view}) { + debugPrint("Page media updated: $newMedia"); + media = newMedia; + var ctrl = view ?? page; + updateControl(ctrl.id, {"media": newMedia.toMap()}); + // Initial page media should only hydrate Python state. Later media changes + // must reach Python even if no explicit "on_media_change" handler is set. + if (pageSizeUpdated.isCompleted) { + triggerControlEventById(ctrl.id, "media_change", newMedia.toMap()); + } + notifyListeners(); + } + + /// Updates the properties of a control with the given [id]. + /// + /// This method takes a control's unique identifier [id] and a map of + /// properties [props] to update the control's state. The [props] map + /// contains key-value pairs where the key is the property name and the + /// value is the new value for that property. + /// + /// - [id]: The unique identifier of the control to be updated. + /// - [props]: A map of property names and their corresponding new values. + /// - [dart]: A boolean indicating whether to apply the patch in Dart. Defaults to `true`. + /// - [python]: A boolean indicating whether to send the update to the Python backend. Defaults to `true`. + /// - [notify]: A boolean indicating whether to notify listeners after applying the patch. Defaults to `false`. + /// + /// This method is typically used to modify the state of a control dynamically. + void updateControl(int id, Map props, + {bool dart = true, bool python = true, bool notify = false}) { + var control = controlsIndex.get(id); + if (control != null) { + if (dart) { + control.update(props, shouldNotify: notify); + } + if (python) { + _send(Message( + action: MessageAction.updateControl, + payload: UpdateControlBody(id: id, props: props).toMap())); + } + } + } + + /// Retrieves the asset source for a given [src]. + /// + /// This method determines the source of an asset based on the provided [src], + /// the current page URI, and the assets directory. It returns an [AssetSource] + /// object that represents the resolved asset source. + /// + /// - [src]: The relative or absolute path to the asset. + /// - Returns: An [AssetSource] object representing the resolved asset source. + AssetSource getAssetSource(String src) { + return getAssetSrc(src, pageUri, assetsDir); + } + + _onMessage(Message message) { + debugPrint("Received message: ${message.toList()}"); + //debugPrint("message.payload: ${message.payload}"); + switch (message.action) { + case MessageAction.registerClient: + _onClientRegistered( + RegisterClientResponseBody.fromJson(message.payload)); + break; + case MessageAction.sessionCrashed: + _onSessionCrashed(SessionCrashedBody.fromJson(message.payload)); + break; + case MessageAction.patchControl: + _onPatchControl(PatchControlRequestBody.fromJson(message.payload)); + break; + case MessageAction.invokeControlMethod: + _onInvokeMethod(InvokeMethodRequestBody.fromJson(message.payload)); + break; + case MessageAction.pythonOutput: + _onPythonOutput(PythonOutputBody.fromJson(message.payload)); + break; + default: + } + } + + void _onPythonOutput(PythonOutputBody body) { + // Nested FletApp: bubble the line to the outer backend so the + // host page can render it (same shape as errorsHandler bubbling + // at lines 135-148). Root FletApp: nothing to bubble to, so fall + // back to the browser console — preserves Pyodide's default + // visibility now that we've taken over its stdout/stderr hooks. + if (controlId != null && _parentFletBackend != null) { + _parentFletBackend?.target?.triggerControlEventById( + controlId!, + "python_output", + {"text": body.text, "is_stderr": body.isStderr}, + ); + } else { + // Use `print` rather than `debugPrint` — main.dart silences + // debugPrint in release builds, which would swallow this fallback. + final line = body.text.endsWith('\n') + ? body.text.substring(0, body.text.length - 1) + : body.text; + if (body.isStderr) { + // ignore: avoid_print + print("[stderr] $line"); + } else { + // ignore: avoid_print + print(line); + } + } + } + + _onPatchControl(PatchControlRequestBody req) { + var control = controlsIndex.get(req.id); + if (control != null) { + control.applyPatch(req.patch, this); + //debugPrint("patched control: $control"); + //debugPrint("_controlsIndex.length: ${_controlsIndex.length}"); + } + } + + _onInvokeMethod(InvokeMethodRequestBody req) async { + var control = controlsIndex.get(req.controlId); + dynamic result; + String? error; + if (control != null) { + try { + result = await control.invokeMethod(req.name, req.args, req.timeout); + } catch (e) { + error = e.toString(); + } + } else { + error = + "Calling ${req.name} method of inexistent control: ${req.controlId}"; + } + + _send(Message( + action: MessageAction.invokeControlMethod, + payload: InvokeMethodResponseBody( + controlId: req.controlId, + callId: req.callId, + result: result, + error: error) + .toMap())); + } + + _onSessionCrashed(SessionCrashedBody body) { + error = body.message; + notifyListeners(); + } + + String formatAppErrorMessage(String rawError) { + if (rawError.isEmpty) { + return ""; + } + var template = appErrorMessage ?? defaultAppErrorMessageTemplate; + final lines = const LineSplitter().convert(rawError); + final message = lines.isNotEmpty ? lines.first : ""; + final details = lines.length > 1 ? lines.sublist(1).join("\n") : ""; + template = template.replaceAll("{message}", message); + if (details.isEmpty) { + template = template.replaceAll(RegExp(r'(\r?\n)*\{details\}'), ""); + } else { + template = template.replaceAll("{details}", details); + } + return template.trimRight(); + } + + _reconnect(String message, int reconnectDelayMs) { + isLoading = true; + error = message; + _reconnectDelayMs = reconnectDelayMs; + notifyListeners(); + } + + _onDisconnect() { + if (_disposed) { + return; + } + + var nextReconnectDelayMs = _reconnectDelayMs; + if (nextReconnectDelayMs == 0) { + _reconnectStarted = DateTime.now().millisecondsSinceEpoch; + } + + // set/update timeout + nextReconnectDelayMs = nextReconnectDelayMs == 0 || + _backendChannel!.isLocalConnection + ? _reconnectIntervalMs ?? _backendChannel!.defaultReconnectIntervalMs + : nextReconnectDelayMs * 2; + + if (_reconnectTimeoutMs == null || + (DateTime.now().millisecondsSinceEpoch - _reconnectStarted) < + _reconnectTimeoutMs!) { + // re-connect + _reconnect(isUdsPath(pageUri) ? "" : "Loading...", nextReconnectDelayMs); + + debugPrint("Reconnect in $nextReconnectDelayMs milliseconds"); + Future.delayed(Duration(milliseconds: nextReconnectDelayMs)) + .then((value) async { + await connect(); + }); + } else { + errorsHandler?.onError(error != "" + ? error + : "Error connecting to a Flet service in a timely manner."); + } + } + + _send(Message message, {bool unbuffered = false}) { + if (unbuffered || !isLoading) { + debugPrint("_send: ${message.action} ${message.payload}"); + _backendChannel?.send(message); + } else { + _sendQueue.add(message); + } + } +} diff --git a/packages/flet/lib/src/flet_control_backend.dart b/packages/flet/lib/src/flet_control_backend.dart deleted file mode 100644 index 93b3be4b12..0000000000 --- a/packages/flet/lib/src/flet_control_backend.dart +++ /dev/null @@ -1,12 +0,0 @@ -abstract class FletControlBackend { - void updateControlState(String controlId, Map props, - {bool client = true, bool server = true}); - - void triggerControlEvent(String controlId, String eventName, - [String? eventData]); - - void subscribeMethods(String controlId, - Future Function(String, Map) methodHandler); - - void unsubscribeMethods(String controlId); -} diff --git a/packages/flet/lib/src/flet_core_extension.dart b/packages/flet/lib/src/flet_core_extension.dart new file mode 100644 index 0000000000..295b363f39 --- /dev/null +++ b/packages/flet/lib/src/flet_core_extension.dart @@ -0,0 +1,453 @@ +import 'package:flutter/widgets.dart'; + +import 'controls/adaptive_alert_dialog.dart'; +import 'controls/adaptive_button.dart'; +import 'controls/adaptive_checkbox.dart'; +import 'controls/adaptive_radio.dart'; +import 'controls/adaptive_slider.dart'; +import 'controls/adaptive_switch.dart'; +import 'controls/adaptive_texfield.dart'; +import 'controls/animated_switcher.dart'; +import 'controls/app_bar.dart'; +import 'controls/auto_complete.dart'; +import 'controls/autofill_group.dart'; +import 'controls/banner.dart'; +import 'controls/bottom_app_bar.dart'; +import 'controls/bottom_sheet.dart'; +import 'controls/canvas.dart'; +import 'controls/card.dart'; +import 'controls/chip.dart'; +import 'controls/circle_avatar.dart'; +import 'controls/column.dart'; +import 'controls/container.dart'; +import 'controls/context_menu.dart'; +import 'controls/cupertino_action_sheet.dart'; +import 'controls/cupertino_action_sheet_action.dart'; +import 'controls/cupertino_activity_indicator.dart'; +import 'controls/cupertino_alert_dialog.dart'; +import 'controls/cupertino_app_bar.dart'; +import 'controls/cupertino_bottom_sheet.dart'; +import 'controls/cupertino_button.dart'; +import 'controls/cupertino_checkbox.dart'; +import 'controls/cupertino_context_menu.dart'; +import 'controls/cupertino_context_menu_action.dart'; +import 'controls/cupertino_date_picker.dart'; +import 'controls/cupertino_dialog_action.dart'; +import 'controls/cupertino_list_tile.dart'; +import 'controls/cupertino_navigation_bar.dart'; +import 'controls/cupertino_picker.dart'; +import 'controls/cupertino_radio.dart'; +import 'controls/cupertino_segmented_button.dart'; +import 'controls/cupertino_slider.dart'; +import 'controls/cupertino_sliding_segmented_button.dart'; +import 'controls/cupertino_switch.dart'; +import 'controls/cupertino_textfield.dart'; +import 'controls/cupertino_timer_picker.dart'; +import 'controls/datatable.dart'; +import 'controls/date_picker.dart'; +import 'controls/date_range_picker.dart'; +import 'controls/dismissible.dart'; +import 'controls/divider.dart'; +import 'controls/drag_target.dart'; +import 'controls/draggable.dart'; +import 'controls/dropdown.dart'; +import 'controls/dropdownm2.dart'; +import 'controls/expansion_panel.dart'; +import 'controls/expansion_tile.dart'; +import 'controls/flet_app_control.dart'; +import 'controls/floating_action_button.dart'; +import 'controls/gesture_detector.dart'; +import 'controls/grid_view.dart'; +import 'controls/hero.dart'; +import 'controls/icon.dart'; +import 'controls/icon_button.dart'; +import 'controls/image.dart'; +import 'controls/interactive_viewer.dart'; +import 'controls/keyboard_listener.dart'; +import 'controls/list_tile.dart'; +import 'controls/list_view.dart'; +import 'controls/markdown.dart'; +import 'controls/menu_bar.dart'; +import 'controls/menu_item_button.dart'; +import 'controls/merge_semantics.dart'; +import 'controls/navigation_bar.dart'; +import 'controls/navigation_bar_destination.dart'; +import 'controls/navigation_drawer.dart'; +import 'controls/navigation_rail.dart'; +import 'controls/page.dart'; +import 'controls/page_view.dart'; +import 'controls/pagelet.dart'; +import 'controls/placeholder.dart'; +import 'controls/popup_menu_button.dart'; +import 'controls/progress_bar.dart'; +import 'controls/progress_ring.dart'; +import 'controls/radio_group.dart'; +import 'controls/range_slider.dart'; +import 'controls/reorderable_drag_handle.dart'; +import 'controls/reorderable_list_view.dart'; +import 'controls/responsive_row.dart'; +import 'controls/rotated_box.dart'; +import 'controls/row.dart'; +import 'controls/safe_area.dart'; +import 'controls/screenshot.dart'; +import 'controls/search_bar.dart'; +import 'controls/segmented_button.dart'; +import 'controls/selection_area.dart'; +import 'controls/semantics.dart'; +import 'controls/shader_mask.dart'; +import 'controls/shimmer.dart'; +import 'controls/snack_bar.dart'; +import 'controls/stack.dart'; +import 'controls/submenu_button.dart'; +import 'controls/tabs.dart'; +import 'controls/text.dart'; +import 'controls/time_picker.dart'; +import 'controls/transparent_pointer.dart'; +import 'controls/vertical_divider.dart'; +import 'controls/view.dart'; +import 'controls/window_drag_area.dart'; +import 'flet_extension.dart'; +import 'flet_service.dart'; +import 'models/control.dart'; +import 'services/browser_context_menu.dart'; +import 'services/battery.dart'; +import 'services/accelerometer.dart'; +import 'services/clipboard.dart'; +import 'services/connectivity.dart'; +import 'services/file_picker.dart'; +import 'services/barometer.dart'; +import 'services/haptic_feedback.dart'; +import 'services/gyroscope.dart'; +import 'services/magnetometer.dart'; +import 'services/share.dart'; +import 'services/semantics_service.dart'; +import 'services/shake_detector.dart'; +import 'services/shared_preferences.dart'; +import 'services/screen_brightness.dart'; +import 'services/storage_paths.dart'; +import 'services/tester.dart'; +import 'services/url_launcher.dart'; +import 'services/wakelock.dart'; +import 'services/window.dart'; +import 'services/user_accelerometer.dart'; +import 'utils/cupertino_icons.dart'; +import 'utils/material_icons.dart'; + +class FletCoreExtension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "AdaptiveAlertDialog": + return AdaptiveAlertDialogControl(key: key, control: control); + case "AdaptiveButton": + case "FilledButton": + case "FilledTonalButton": + case "OutlinedButton": + case "TextButton": + return AdaptiveButtonControl(key: key, control: control); + case "AdaptiveCheckbox": + return AdaptiveCheckboxControl(key: key, control: control); + case "AdaptiveRadio": + return AdaptiveRadioControl(key: key, control: control); + case "AdaptiveSlider": + return AdaptiveSliderControl(key: key, control: control); + case "AdaptiveSwitch": + return AdaptiveSwitchControl(key: key, control: control); + case "AdaptiveTextField": + return AdaptiveTextFieldControl(key: key, control: control); + case "AlertDialog": + return AdaptiveAlertDialogControl(key: key, control: control); + case "AnimatedSwitcher": + return AnimatedSwitcherControl(key: key, control: control); + case "AppBar": + return AppBarControl(key: key, control: control); + case "AutoComplete": + return AutoCompleteControl(key: key, control: control); + case "AutofillGroup": + return AutofillGroupControl(key: key, control: control); + case "Banner": + return BannerControl(key: key, control: control); + case "BottomAppBar": + return BottomAppBarControl(key: key, control: control); + case "BottomSheet": + return BottomSheetControl(key: key, control: control); + case "Button": + return AdaptiveButtonControl(key: key, control: control); + case "Canvas": + return CanvasControl(key: key, control: control); + case "Card": + return CardControl(key: key, control: control); + case "Checkbox": + return AdaptiveCheckboxControl(key: key, control: control); + case "Chip": + return ChipControl(key: key, control: control); + case "CircleAvatar": + return CircleAvatarControl(key: key, control: control); + case "Column": + return ColumnControl(key: key, control: control); + case "Container": + return ContainerControl(key: key, control: control); + case "ContextMenu": + return ContextMenuControl(key: key, control: control); + case "CupertinoActionSheet": + return CupertinoActionSheetControl(key: key, control: control); + case "CupertinoActionSheetAction": + return CupertinoActionSheetActionControl(key: key, control: control); + case "CupertinoActivityIndicator": + return CupertinoActivityIndicatorControl(key: key, control: control); + case "CupertinoAlertDialog": + return CupertinoAlertDialogControl(key: key, control: control); + case "CupertinoAppBar": + return CupertinoAppBarControl(key: key, control: control); + case "CupertinoBottomSheet": + return CupertinoBottomSheetControl(key: key, control: control); + case "CupertinoButton": + case "CupertinoFilledButton": + case "CupertinoTintedButton": + return CupertinoButtonControl(key: key, control: control); + case "CupertinoCheckbox": + return CupertinoCheckboxControl(key: key, control: control); + case "CupertinoContextMenu": + return CupertinoContextMenuControl(key: key, control: control); + case "CupertinoContextMenuAction": + return CupertinoContextMenuActionControl(key: key, control: control); + case "CupertinoDatePicker": + return CupertinoDatePickerControl(key: key, control: control); + case "CupertinoDialogAction": + return CupertinoDialogActionControl(key: key, control: control); + case "CupertinoListTile": + return CupertinoListTileControl(key: key, control: control); + case "CupertinoNavigationBar": + return CupertinoNavigationBarControl(key: key, control: control); + case "CupertinoPicker": + return CupertinoPickerControl(key: key, control: control); + case "CupertinoRadio": + return CupertinoRadioControl(key: key, control: control); + case "CupertinoSegmentedButton": + return CupertinoSegmentedButtonControl(key: key, control: control); + case "CupertinoSlider": + return CupertinoSliderControl(key: key, control: control); + case "CupertinoSlidingSegmentedButton": + return CupertinoSlidingSegmentedButtonControl( + key: key, control: control); + case "CupertinoSwitch": + return CupertinoSwitchControl(key: key, control: control); + case "CupertinoTextField": + return CupertinoTextFieldControl(key: key, control: control); + case "CupertinoTimerPicker": + return CupertinoTimerPickerControl(key: key, control: control); + case "DataTable": + return DataTableControl(key: key, control: control); + case "DatePicker": + return DatePickerControl(key: key, control: control); + case "DateRangePicker": + return DateRangePickerControl(key: key, control: control); + case "Dismissible": + return DismissibleControl(key: key, control: control); + case "Divider": + return DividerControl(key: key, control: control); + case "DragTarget": + return DragTargetControl(key: key, control: control); + case "Draggable": + return DraggableControl(key: key, control: control); + case "Dropdown": + return DropdownControl(key: key, control: control); + case "DropdownM2": + return DropdownM2Control(key: key, control: control); + case "ExpansionPanelList": + return ExpansionPanelListControl(key: key, control: control); + case "ExpansionTile": + return ExpansionTileControl(key: key, control: control); + case "FletApp": + return FletAppControl(key: key, control: control); + case "FloatingActionButton": + return FloatingActionButtonControl(key: key, control: control); + case "GestureDetector": + return GestureDetectorControl(key: key, control: control); + case "GridView": + return GridViewControl(key: key, control: control); + case "Hero": + return HeroControl(key: key, control: control); + case "Icon": + return IconControl(key: key, control: control); + case "IconButton": + case "FilledIconButton": + case "FilledTonalIconButton": + case "OutlinedIconButton": + return IconButtonControl(key: key, control: control); + case "Image": + return ImageControl(key: key, control: control); + case "InteractiveViewer": + return InteractiveViewerControl(key: key, control: control); + case "KeyboardListener": + return KeyboardListenerControl(key: key, control: control); + case "ListTile": + return ListTileControl(key: key, control: control); + case "ListView": + return ListViewControl(key: key, control: control); + case "Markdown": + return MarkdownControl(key: key, control: control); + case "MenuBar": + return MenuBarControl(key: key, control: control); + case "MenuItemButton": + return MenuItemButtonControl(key: key, control: control); + case "MergeSemantics": + return MergeSemanticsControl(key: key, control: control); + case "NavigationBar": + return NavigationBarControl(key: key, control: control); + case "NavigationBarDestination": + return NavigationBarDestinationControl(key: key, control: control); + case "NavigationDrawer": + return NavigationDrawerControl(key: key, control: control); + case "NavigationRail": + return NavigationRailControl(key: key, control: control); + case "Page": + return PageControl(key: key, control: control); + case "Pagelet": + return PageletControl(key: key, control: control); + case "PageView": + return PageViewControl(key: key, control: control); + case "Placeholder": + return PlaceholderControl(key: key, control: control); + case "PopupMenuButton": + return PopupMenuButtonControl(key: key, control: control); + case "ProgressBar": + return ProgressBarControl(key: key, control: control); + case "ProgressRing": + return ProgressRingControl(key: key, control: control); + case "Radio": + return AdaptiveRadioControl(key: key, control: control); + case "RadioGroup": + return RadioGroupControl(key: key, control: control); + case "RangeSlider": + return RangeSliderControl(key: key, control: control); + case "ReorderableDragHandle": + return ReorderableDragHandleControl(key: key, control: control); + case "ReorderableListView": + return ReorderableListViewControl(key: key, control: control); + case "ResponsiveRow": + return ResponsiveRowControl(key: key, control: control); + case "RotatedBox": + return RotatedBoxControl(key: key, control: control); + case "Row": + return RowControl(key: key, control: control); + case "SafeArea": + return SafeAreaControl(key: key, control: control); + case "Screenshot": + return ScreenshotControl(key: key, control: control); + case "SearchBar": + return SearchBarControl(key: key, control: control); + case "SegmentedButton": + return SegmentedButtonControl(key: key, control: control); + case "SelectionArea": + return SelectionAreaControl(key: key, control: control); + case "Semantics": + return SemanticsControl(key: key, control: control); + case "ShaderMask": + return ShaderMaskControl(key: key, control: control); + case "Shimmer": + return ShimmerControl(key: key, control: control); + case "Slider": + return AdaptiveSliderControl(key: key, control: control); + case "SnackBar": + return SnackBarControl(key: key, control: control); + case "Stack": + return StackControl(key: key, control: control); + case "SubmenuButton": + return SubmenuButtonControl(key: key, control: control); + case "Switch": + return AdaptiveSwitchControl(key: key, control: control); + case "Tab": + return TabControl(key: key, control: control); + case "TabBar": + return TabBarControl(key: key, control: control); + case "TabBarView": + return TabBarViewControl(key: key, control: control); + case "Tabs": + return TabsControl(key: key, control: control); + case "Text": + return TextControl(key: key, control: control); + case "TextField": + return AdaptiveTextFieldControl(key: key, control: control); + case "TimePicker": + return TimePickerControl(key: key, control: control); + case "TransparentPointer": + return TransparentPointerControl(key: key, control: control); + case "VerticalDivider": + return VerticalDividerControl(key: key, control: control); + case "View": + return ViewControl(key: key, control: control); + case "WindowDragArea": + return WindowDragAreaControl(key: key, control: control); + default: + return null; + } + } + + @override + FletService? createService(Control control) { + switch (control.type) { + case "BrowserContextMenu": + return BrowserContextMenuService(control: control); + case "Accelerometer": + return AccelerometerService(control: control); + case "Barometer": + return BarometerService(control: control); + case "Battery": + return BatteryService(control: control); + case "Clipboard": + return ClipboardService(control: control); + case "Connectivity": + return ConnectivityService(control: control); + case "Share": + return ShareService(control: control); + case "FilePicker": + return FilePickerService(control: control); + case "HapticFeedback": + return HapticFeedbackService(control: control); + case "Gyroscope": + return GyroscopeService(control: control); + case "ShakeDetector": + return ShakeDetectorService(control: control); + case "SharedPreferences": + return SharedPreferencesService(control: control); + case "SemanticsService": + return SemanticsServiceControl(control: control); + case "Magnetometer": + return MagnetometerService(control: control); + case "ScreenBrightness": + return ScreenBrightnessService(control: control); + case "StoragePaths": + return StoragePaths(control: control); + case "Window": + return WindowService(control: control); + case "Tester": + return TesterService(control: control); + case "UserAccelerometer": + return UserAccelerometerService(control: control); + case "UrlLauncher": + return UrlLauncherService(control: control); + case "Wakelock": + return WakelockService(control: control); + default: + return null; + } + } + + @override + IconData? createIconData(iconCode) { + int setId = (iconCode >> 16) & 0xFF; + int iconIndex = iconCode & 0xFFFF; + + if (setId == 1) { + return materialIcons[iconIndex]; + } else if (setId == 2) { + return cupertinoIcons[iconIndex]; + } else { + return null; + } + } + + @override + void ensureInitialized() {} +} diff --git a/packages/flet/lib/src/flet_extension.dart b/packages/flet/lib/src/flet_extension.dart new file mode 100644 index 0000000000..279fb7663f --- /dev/null +++ b/packages/flet/lib/src/flet_extension.dart @@ -0,0 +1,20 @@ +import 'package:flutter/widgets.dart'; + +import 'flet_service.dart'; +import 'models/control.dart'; + +abstract class FletExtension { + void ensureInitialized() {} + + Widget? createWidget(Key? key, Control control) { + return null; + } + + FletService? createService(Control control) { + return null; + } + + IconData? createIconData(int iconCode) { + return null; + } +} diff --git a/packages/flet/lib/src/flet_server.dart b/packages/flet/lib/src/flet_server.dart deleted file mode 100644 index 84a4dbd415..0000000000 --- a/packages/flet/lib/src/flet_server.dart +++ /dev/null @@ -1,282 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:redux/redux.dart'; - -import 'actions.dart'; -import 'flet_app_errors_handler.dart'; -import 'flet_control_backend.dart'; -import 'flet_server_protocol.dart'; -import 'models/app_state.dart'; -import 'protocol/add_page_controls_payload.dart'; -import 'protocol/app_become_active_payload.dart'; -import 'protocol/app_become_inactive_payload.dart'; -import 'protocol/append_control_props_request.dart'; -import 'protocol/clean_control_payload.dart'; -import 'protocol/invoke_method_payload.dart'; -import 'protocol/message.dart'; -import 'protocol/page_controls_batch_payload.dart'; -import 'protocol/page_event_from_web_request.dart'; -import 'protocol/register_webclient_request.dart'; -import 'protocol/register_webclient_response.dart'; -import 'protocol/remove_control_payload.dart'; -import 'protocol/replace_page_controls_payload.dart'; -import 'protocol/session_crashed_payload.dart'; -import 'protocol/update_control_props_payload.dart'; -import 'protocol/update_control_props_request.dart'; -import 'utils/uri.dart'; - -class FletServer implements FletControlBackend { - final Store _store; - final int? reconnectIntervalMs; - final int? reconnectTimeoutMs; - final FletAppErrorsHandler? errorsHandler; - - FletServerProtocol? _clientProtocol; - bool _disposed = false; - String _address = ""; - String _pageName = ""; - String _pageHash = ""; - String _pageWidth = ""; - String _pageHeight = ""; - String _windowWidth = ""; - String _windowHeight = ""; - String _windowTop = ""; - String _windowLeft = ""; - String _isPWA = ""; - String _isWeb = ""; - String _isDebug = ""; - String _platform = ""; - String _platformBrightness = ""; - String _media = ""; - int reconnectStarted = 0; - final Map controlInvokeMethods; - - FletServer(this._store, this.controlInvokeMethods, - {this.reconnectIntervalMs, this.reconnectTimeoutMs, this.errorsHandler}); - - Future connect({required String address}) async { - _address = address; - - debugPrint("Connecting to Flet server $address..."); - try { - _clientProtocol = FletServerProtocol( - address: _address, - onDisconnect: _onDisconnect, - onMessage: _onMessage); - await _clientProtocol!.connect(); - registerWebClientInternal(); - } catch (e) { - debugPrint("Error connecting to Flet server: $e"); - _onDisconnect(); - } - } - - _onDisconnect() { - if (_disposed) { - return; - } - - var nextReconnectDelayMs = _store.state.reconnectDelayMs; - if (nextReconnectDelayMs == 0) { - reconnectStarted = DateTime.now().millisecondsSinceEpoch; - } - - // set/update timeout - nextReconnectDelayMs = - nextReconnectDelayMs == 0 || _clientProtocol!.isLocalConnection - ? reconnectIntervalMs ?? _clientProtocol!.defaultReconnectIntervalMs - : nextReconnectDelayMs * 2; - - if (reconnectTimeoutMs == null || - (DateTime.now().millisecondsSinceEpoch - reconnectStarted) < - reconnectTimeoutMs!) { - // re-connect - _store.dispatch(PageReconnectingAction( - isUdsPath(_address) ? "" : "Loading...", nextReconnectDelayMs)); - - debugPrint("Reconnect in $nextReconnectDelayMs milliseconds"); - Future.delayed(Duration(milliseconds: nextReconnectDelayMs)) - .then((value) async { - await connect(address: _address); - }); - } else if (reconnectTimeoutMs != null) { - errorsHandler - ?.onError("Error connecting to a Flet service in a timely manner."); - } - } - - registerWebClient( - {required String pageName, - required String pageRoute, - required String pageWidth, - required String pageHeight, - required String windowWidth, - required String windowHeight, - required String windowTop, - required String windowLeft, - required String isPWA, - required String isWeb, - required String isDebug, - required String platform, - required String platformBrightness, - required String media}) { - _pageName = pageName; - _pageHash = pageRoute; - _pageWidth = pageWidth; - _pageHeight = pageHeight; - _windowWidth = windowWidth; - _windowHeight = windowHeight; - _windowTop = windowTop; - _windowLeft = windowLeft; - _isPWA = isPWA; - _isWeb = isWeb; - _isDebug = isDebug; - _platform = platform; - _platformBrightness = platformBrightness; - _media = media; - } - - registerWebClientInternal() { - debugPrint("registerWebClientInternal"); - var page = _store.state.controls["page"]; - send(Message( - action: MessageAction.registerWebClient, - payload: RegisterWebClientRequest( - pageName: _pageName, - pageRoute: _pageHash != "" ? _pageHash : _store.state.route, - pageWidth: page?.attrString("pageWidth") ?? _pageWidth, - pageHeight: page?.attrString("pageHeight") ?? _pageHeight, - windowLeft: page?.attrString("windowLeft") ?? _windowLeft, - windowTop: page?.attrString("windowTop") ?? _windowTop, - windowWidth: page?.attrString("windowWidth") ?? _windowWidth, - windowHeight: page?.attrString("windowHeight") ?? _windowHeight, - isPWA: _isPWA, - isWeb: _isWeb, - isDebug: _isDebug, - platform: _platform, - platformBrightness: _platformBrightness, - media: _media, - sessionId: _store.state.sessionId))); - _pageHash = ""; - } - - @override - void updateControlState(String id, Map props, - {bool client = true, bool server = true}) { - Map allProps = {"i": id}; - for (var entry in props.entries) { - allProps[entry.key.toLowerCase()] = entry.value; - } - if (client) { - _store.dispatch(UpdateControlPropsAction( - UpdateControlPropsPayload(props: [allProps]))); - } - if (server) { - _updateControlProps(props: [allProps]); - } - } - - @override - void triggerControlEvent(String controlId, String eventName, - [String? eventData]) { - _sendPageEvent( - eventTarget: controlId, eventName: eventName, eventData: eventData); - } - - @override - void subscribeMethods(String controlId, - Future Function(String, Map) methodHandler) { - controlInvokeMethods[controlId] = methodHandler; - } - - @override - void unsubscribeMethods(String controlId) { - controlInvokeMethods.remove(controlId); - } - - _sendPageEvent( - {required String eventTarget, - required String eventName, - String? eventData}) { - send(Message( - action: MessageAction.pageEventFromWeb, - payload: PageEventFromWebRequest( - eventTarget: eventTarget, - eventName: eventName, - eventData: eventData))); - } - - _updateControlProps({required List> props}) { - send(Message( - action: MessageAction.updateControlProps, - payload: UpdateControlPropsRequest(props: props))); - } - - _onMessage(message) { - debugPrint("WS message: $message"); - final msg = Message.fromJson(json.decode(message)); - switch (msg.action) { - case MessageAction.registerWebClient: - _store.dispatch(RegisterWebClientAction( - RegisterWebClientResponse.fromJson(msg.payload), this)); - break; - case MessageAction.appBecomeActive: - _store.dispatch(AppBecomeActiveAction( - this, AppBecomeActivePayload.fromJson(msg.payload))); - break; - case MessageAction.appBecomeInactive: - _store.dispatch(AppBecomeInactiveAction( - AppBecomeInactivePayload.fromJson(msg.payload))); - break; - case MessageAction.sessionCrashed: - _store.dispatch( - SessionCrashedAction(SessionCrashedPayload.fromJson(msg.payload))); - break; - case MessageAction.invokeMethod: - _store.dispatch(InvokeMethodAction( - InvokeMethodPayload.fromJson(msg.payload), this)); - break; - case MessageAction.addPageControls: - _store.dispatch(AddPageControlsAction( - AddPageControlsPayload.fromJson(msg.payload))); - break; - case MessageAction.appendControlProps: - _store.dispatch(AppendControlPropsAction( - AppendControlPropsPayload.fromJson(msg.payload))); - break; - case MessageAction.updateControlProps: - _store.dispatch(UpdateControlPropsAction( - UpdateControlPropsPayload.fromJson(msg.payload))); - break; - case MessageAction.replacePageControls: - _store.dispatch(ReplacePageControlsAction( - ReplacePageControlsPayload.fromJson(msg.payload))); - break; - case MessageAction.cleanControl: - _store.dispatch( - CleanControlAction(CleanControlPayload.fromJson(msg.payload))); - break; - case MessageAction.removeControl: - _store.dispatch( - RemoveControlAction(RemoveControlPayload.fromJson(msg.payload))); - break; - case MessageAction.pageControlsBatch: - _store.dispatch(PageControlsBatchAction( - PageControlsBatchPayload.fromJson(msg.payload))); - break; - default: - } - } - - send(Message message) { - final m = json.encode(message.toJson()); - _clientProtocol?.send(m); - } - - void disconnect() { - debugPrint("Disconnecting from Flet server."); - _disposed = true; - _clientProtocol?.disconnect(); - } -} diff --git a/packages/flet/lib/src/flet_server_protocol.dart b/packages/flet/lib/src/flet_server_protocol.dart deleted file mode 100644 index 18c7b8b908..0000000000 --- a/packages/flet/lib/src/flet_server_protocol.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'flet_server_protocol_javascript_io.dart' - if (dart.library.js) "flet_server_protocol_javascript_web.dart"; -import 'flet_server_protocol_tcp_socket.dart'; -import 'flet_server_protocol_web_socket.dart'; -import 'utils/platform_utils_non_web.dart' - if (dart.library.js) "utils/platform_utils_web.dart"; - -typedef FletServerProtocolOnDisconnectCallback = void Function(); -typedef FletServerProtocolOnMessageCallback = void Function(String message); -typedef ControlInvokeMethodCallback = Future Function( - String methodName, Map args); - -abstract class FletServerProtocol { - factory FletServerProtocol( - {required String address, - required FletServerProtocolOnDisconnectCallback onDisconnect, - required FletServerProtocolOnMessageCallback onMessage}) { - if (isFletWebPyodideMode()) { - // JavaScript - return FletJavaScriptServerProtocol( - address: address, onDisconnect: onDisconnect, onMessage: onMessage); - } else if (address.startsWith("http://") || - address.startsWith("https://")) { - // WebSocket - return FletWebSocketServerProtocol( - address: address, onDisconnect: onDisconnect, onMessage: onMessage); - } else { - // TCP or UDS - return FletTcpSocketServerProtocol( - address: address, onDisconnect: onDisconnect, onMessage: onMessage); - } - } - - Future connect(); - bool get isLocalConnection; - int get defaultReconnectIntervalMs; - void send(String message); - void disconnect(); -} diff --git a/packages/flet/lib/src/flet_server_protocol_javascript_io.dart b/packages/flet/lib/src/flet_server_protocol_javascript_io.dart deleted file mode 100644 index 6a536685ac..0000000000 --- a/packages/flet/lib/src/flet_server_protocol_javascript_io.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'flet_server_protocol.dart'; - -class FletJavaScriptServerProtocol implements FletServerProtocol { - final String address; - final FletServerProtocolOnMessageCallback onMessage; - final FletServerProtocolOnDisconnectCallback onDisconnect; - - FletJavaScriptServerProtocol( - {required this.address, - required this.onDisconnect, - required this.onMessage}); - - @override - connect() async {} - - @override - bool get isLocalConnection => true; - - @override - int get defaultReconnectIntervalMs => 10; - - @override - void send(String message) {} - - @override - void disconnect() {} -} diff --git a/packages/flet/lib/src/flet_server_protocol_javascript_web.dart b/packages/flet/lib/src/flet_server_protocol_javascript_web.dart deleted file mode 100644 index 77224ea8cf..0000000000 --- a/packages/flet/lib/src/flet_server_protocol_javascript_web.dart +++ /dev/null @@ -1,46 +0,0 @@ -@JS() -library script.js; - -import 'dart:js_util'; - -import 'package:flutter/foundation.dart'; -import 'package:js/js.dart'; - -import 'flet_server_protocol.dart'; - -@JS() -external dynamic jsConnect(FletServerProtocolOnMessageCallback onMessage); - -@JS() -external dynamic jsSend(String data); - -class FletJavaScriptServerProtocol implements FletServerProtocol { - final String address; - final FletServerProtocolOnMessageCallback onMessage; - final FletServerProtocolOnDisconnectCallback onDisconnect; - - FletJavaScriptServerProtocol( - {required this.address, - required this.onDisconnect, - required this.onMessage}); - - @override - connect() async { - debugPrint("Connecting to JavaScript server $address..."); - await promiseToFuture(jsConnect(allowInterop(onMessage))); - } - - @override - bool get isLocalConnection => true; - - @override - int get defaultReconnectIntervalMs => 10; - - @override - void send(String message) { - jsSend(message); - } - - @override - void disconnect() {} -} diff --git a/packages/flet/lib/src/flet_server_protocol_tcp_socket.dart b/packages/flet/lib/src/flet_server_protocol_tcp_socket.dart deleted file mode 100644 index 6257c23e32..0000000000 --- a/packages/flet/lib/src/flet_server_protocol_tcp_socket.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'dart:convert' show utf8; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; - -import 'flet_server_protocol.dart'; -import 'utils/networking.dart'; - -const int defaultLocalReconnectInterval = 200; -const int defaultPublicReconnectInterval = 500; - -class FletTcpSocketServerProtocol implements FletServerProtocol { - String address; - FletServerProtocolOnMessageCallback onMessage; - FletServerProtocolOnDisconnectCallback onDisconnect; - Socket? _socket; - late final bool _isLocalConnection; - late final int _defaultReconnectIntervalMs; - - FletTcpSocketServerProtocol( - {required this.address, - required this.onDisconnect, - required this.onMessage}); - - @override - connect() async { - debugPrint("Connecting to Socket server $address..."); - - if (address.startsWith("tcp://")) { - var u = Uri.parse(address); - _isLocalConnection = await isPrivateHost(u.host); - _defaultReconnectIntervalMs = _isLocalConnection - ? defaultLocalReconnectInterval - : defaultPublicReconnectInterval; - _socket = await Socket.connect(u.host, u.port); - debugPrint( - 'Connected to: ${_socket!.remoteAddress.address}:${_socket!.remotePort}'); - } else { - final udsPath = InternetAddress(address, type: InternetAddressType.unix); - _isLocalConnection = true; - _defaultReconnectIntervalMs = defaultLocalReconnectInterval; - _socket = await Socket.connect(udsPath, 0); - debugPrint('Connected to: $udsPath'); - } - - BytesBuilder buffer = BytesBuilder(); - int msgLen = 0; - - // listen for responses from the server - _socket!.listen( - // handle data from the server - (Uint8List data) { - debugPrint("Received packet: ${data.length}"); - int packetLen = data.length; - - // process packet - // it can contain multiple messages - int i = 0; - while (i < packetLen) { - // read message size - if (msgLen == 0) { - //print("Read message size: $i"); - int end = i + (4 - buffer.length); - if (end > packetLen) { - end = packetLen; - } - buffer.add(data.sublist(i, end)); - - i = end; - - if (buffer.length == 4) { - msgLen = ByteData.sublistView(buffer.toBytes()) - .getUint32(0, Endian.big); - //print("Message size: $msgLen"); - buffer.clear(); - } - } - - // read message body - if (msgLen > 0) { - //print("Read message body: $i"); - int end = i + (msgLen - buffer.length); - if (end > packetLen) { - end = packetLen; - } - buffer.add(data.sublist(i, end)); - - i = end; - - if (buffer.length == msgLen) { - String message = String.fromCharCodes(buffer.toBytes()); - debugPrint('Received message: ${message.length}'); - _onMessage(message); - buffer.clear(); - msgLen = 0; - } - } - } - }, - - // handle errors - onError: (error) { - debugPrint("Error: $error"); - _socket?.destroy(); - onDisconnect(); - }, - - // handle server ending connection - onDone: () { - debugPrint('Server left.'); - _socket?.destroy(); - onDisconnect(); - }, - ); - } - - @override - bool get isLocalConnection => _isLocalConnection; - - @override - int get defaultReconnectIntervalMs => _defaultReconnectIntervalMs; - - _onMessage(message) { - onMessage(message); - } - - Uint8List int32bytes(int value) => - Uint8List(4)..buffer.asInt32List()[0] = value; - - Uint8List int32BigEndianBytes(int value) => - Uint8List(4)..buffer.asByteData().setInt32(0, value, Endian.big); - - @override - void send(String message) { - var buffer = utf8.encode(message); - _socket!.add(int32BigEndianBytes(buffer.length)); - debugPrint('Sending: ${buffer.length}'); - _socket!.write(message); - } - - @override - void disconnect() { - _socket?.destroy(); - } -} diff --git a/packages/flet/lib/src/flet_server_protocol_web_socket.dart b/packages/flet/lib/src/flet_server_protocol_web_socket.dart deleted file mode 100644 index 8facdc0d75..0000000000 --- a/packages/flet/lib/src/flet_server_protocol_web_socket.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; - -import 'flet_server_protocol.dart'; -import 'utils/networking.dart'; -import 'utils/platform_utils_non_web.dart' - if (dart.library.js) "utils/platform_utils_web.dart"; -import 'utils/uri.dart'; - -class FletWebSocketServerProtocol implements FletServerProtocol { - late final String _wsUrl; - late final bool _isLocalConnection; - FletServerProtocolOnMessageCallback onMessage; - FletServerProtocolOnDisconnectCallback onDisconnect; - WebSocketChannel? _channel; - - FletWebSocketServerProtocol( - {required String address, - required this.onDisconnect, - required this.onMessage}) { - _wsUrl = getWebSocketEndpoint(Uri.parse(address)); - } - - @override - bool get isLocalConnection => _isLocalConnection; - - @override - int get defaultReconnectIntervalMs => 500; - - @override - Future connect() async { - debugPrint("Connecting to WebSocket server $_wsUrl..."); - try { - // todo - var uri = Uri.parse(_wsUrl); - if (kIsWeb) { - _isLocalConnection = isLocalhost(uri); - } else { - _isLocalConnection = await isPrivateHost(uri.host); - } - - _channel = WebSocketChannel.connect(Uri.parse(_wsUrl)); - } catch (e) { - throw Exception('WebSocket connect error: $e'); - } - _channel!.stream.listen(_onMessage, onDone: () async { - debugPrint("WebSocket stream closed"); - onDisconnect(); - }, onError: (error) async { - var socketError = error as WebSocketChannelException; - debugPrint("WebSocket stream error: ${socketError.message}"); - }); - } - - _onMessage(message) { - onMessage(message); - } - - @override - void send(String message) { - _channel?.sink.add(message); - } - - @override - void disconnect() { - _channel?.sink.close(); - } - - String getWebSocketEndpoint(Uri uri) { - final wsScheme = uri.scheme == "https" ? "wss" : "ws"; - final wsPath = getWebsocketEndpointPath(uri.path); - if (wsPath == "") { - throw Exception("WebSocket endpoint path cannot be empty."); - } - return "$wsScheme://${uri.authority}/$wsPath"; - } -} diff --git a/packages/flet/lib/src/flet_service.dart b/packages/flet/lib/src/flet_service.dart new file mode 100644 index 0000000000..55ef8fb140 --- /dev/null +++ b/packages/flet/lib/src/flet_service.dart @@ -0,0 +1,17 @@ +import 'package:flutter/foundation.dart'; + +import 'models/control.dart'; + +abstract class FletService { + Control control; + + FletService({required this.control}); + + @mustCallSuper + void init() {} + + void update() {} + + @mustCallSuper + void dispose() {} +} diff --git a/packages/flet/lib/src/models/app_state.dart b/packages/flet/lib/src/models/app_state.dart deleted file mode 100644 index fdd56415f3..0000000000 --- a/packages/flet/lib/src/models/app_state.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:flutter/cupertino.dart'; - -import '../protocol/page_media_data.dart'; -import 'control.dart'; - -class Counter { - int value; - Counter(this.value); -} - -class AppState extends Equatable { - final Uri? pageUri; - final String assetsDir; - final String route; - final String deepLinkingRoute; - final String sessionId; - final bool isLoading; - final bool isRegistered; - final int reconnectDelayMs; - final String error; - final Size size; - final Brightness displayBrightness; - final PageMediaData media; - final Map sizeBreakpoints; - final Map controls; - - const AppState( - {required this.pageUri, - required this.assetsDir, - required this.route, - required this.deepLinkingRoute, - required this.sessionId, - required this.isLoading, - required this.isRegistered, - required this.reconnectDelayMs, - required this.error, - required this.size, - required this.sizeBreakpoints, - required this.displayBrightness, - required this.media, - required this.controls}); - - factory AppState.initial() => AppState( - pageUri: null, - assetsDir: "", - route: "", - deepLinkingRoute: "", - sessionId: "", - isLoading: true, - isRegistered: false, - reconnectDelayMs: 0, - error: "", - size: const Size(0, 0), - sizeBreakpoints: const { - "xs": 0, - "sm": 576, - "md": 768, - "lg": 992, - "xl": 1200, - "xxl": 1400 - }, - displayBrightness: Brightness.light, - media: PageMediaData( - padding: PaddingData(EdgeInsets.zero), - viewPadding: PaddingData(EdgeInsets.zero), - viewInsets: PaddingData(EdgeInsets.zero)), - controls: { - "page": Control( - id: "page", - pid: "", - type: "page", - name: "", - childIds: const [], - attrs: const {}) - }); - - AppState copyWith( - {Uri? pageUri, - String? assetsDir, - String? route, - String? deepLinkingRoute, - String? sessionId, - bool? isLoading, - bool? isRegistered, - int? reconnectDelayMs, - String? error, - Size? size, - Map? sizeBreakpoints, - Brightness? displayBrightness, - PageMediaData? media, - Map? controls}) => - AppState( - pageUri: pageUri ?? this.pageUri, - assetsDir: assetsDir ?? this.assetsDir, - route: route ?? this.route, - deepLinkingRoute: deepLinkingRoute ?? this.deepLinkingRoute, - sessionId: sessionId ?? this.sessionId, - isLoading: isLoading ?? this.isLoading, - isRegistered: isRegistered ?? this.isRegistered, - reconnectDelayMs: reconnectDelayMs ?? this.reconnectDelayMs, - error: error ?? this.error, - size: size ?? this.size, - sizeBreakpoints: sizeBreakpoints ?? this.sizeBreakpoints, - displayBrightness: displayBrightness ?? this.displayBrightness, - media: media ?? this.media, - controls: controls ?? this.controls); - - @override - List get props => [isLoading, error, sessionId, controls]; -} diff --git a/packages/flet/lib/src/models/asset_source.dart b/packages/flet/lib/src/models/asset_source.dart new file mode 100644 index 0000000000..5227d65a18 --- /dev/null +++ b/packages/flet/lib/src/models/asset_source.dart @@ -0,0 +1,11 @@ +class AssetSource { + final String path; + final bool isFile; + + const AssetSource({required this.path, required this.isFile}); + + @override + String toString() { + return 'AssetSource(path: $path, isFile: $isFile)'; + } +} diff --git a/packages/flet/lib/src/models/asset_src.dart b/packages/flet/lib/src/models/asset_src.dart deleted file mode 100644 index 8f2feaa1eb..0000000000 --- a/packages/flet/lib/src/models/asset_src.dart +++ /dev/null @@ -1,6 +0,0 @@ -class AssetSrc { - final String path; - final bool isFile; - - const AssetSrc({required this.path, required this.isFile}); -} diff --git a/packages/flet/lib/src/models/control.dart b/packages/flet/lib/src/models/control.dart index 826f99bed9..f7a6977a40 100644 --- a/packages/flet/lib/src/models/control.dart +++ b/packages/flet/lib/src/models/control.dart @@ -1,165 +1,545 @@ -import 'dart:convert'; +import 'dart:async'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; +import 'package:collection/collection.dart'; +import 'package:flutter/foundation.dart'; -import '../utils/colors.dart'; +import '../flet_backend.dart'; -class Control extends Equatable { - static const reservedProps = ['i', 'p', 't', 'c', 'n']; +typedef InvokeControlMethodCallback = Future Function( + String name, dynamic args); - final String id; - final String pid; +const String componentType = "C"; +const String componentBodyProp = "_b"; + +enum OperationType { + unknown(-1), + replace(0), + add(1), + remove(2), + move(3); + + final int value; + + const OperationType(this.value); + + static OperationType? fromInt(int value) { + return OperationType.values.firstWhere( + (e) => e.value == value, + orElse: () => unknown, // return unknown if not found + ); + } +} + +class PatchTarget { + final dynamic obj; + final Control control; + + const PatchTarget(this.obj, this.control); +} + +/// Represents a node or control in the UI tree. +/// +/// This class extends `ChangeNotifier`, allowing it to notify listeners +/// whenever any part of its data changes. It uses a unified properties +/// map to store all nested data. Any value (or list element) in the +/// properties map that is a `Map` containing a "_c" key is automatically +/// transformed into a `Control`. +class Control extends ChangeNotifier { + static const DeepCollectionEquality _equality = DeepCollectionEquality(); + final int id; final String type; - final String? name; - final List childIds; - final Map attrs; - final Map state = {}; - final Set onRemove = {}; - - Control( - {required this.id, - required this.pid, - required this.type, - required this.name, - required this.childIds, - required this.attrs}); - - factory Control.fromJson(Map json) { - Map attrs = {}; - for (var key in json.keys) { - if (!reservedProps.contains(key)) { - attrs[key] = json[key] as String; + final Map properties; + bool notifyParent = false; + final List _notifyParentProperties = ["visible"]; + WeakReference? _parent; + late final WeakReference _backend; + Completer? _listenerAddedCompleter; + final List _invokeMethodListeners = []; + + Control({ + required this.id, + required this.type, + required this.properties, + required FletBackend backend, + Control? parent, + }) { + if (parent != null) { + _parent = WeakReference(parent); + } + _backend = WeakReference(backend); + } + + Control? get parent { + var current = _parent?.target; + while (current != null && current.type == componentType) { + current = current._parent?.target; + } + return current; + } + + FletBackend get backend => _backend.target!; + + bool get disabled => + get("disabled") == true || (parent?.disabled ?? false); + + bool? get adaptive => get("adaptive") ?? parent?.adaptive; + + bool get visible => get("visible", true)!; + + T? get(String propertyName, [T? defaultValue]) { + if (properties.containsKey(propertyName) && + properties[propertyName] != null) { + var v = properties[propertyName]; + if (v is Control && v.type == componentType) { + v = v.get(componentBodyProp); + if (v == null) { + return defaultValue; + } } + return T == double && v is int + ? v.toDouble() + : T == String + ? v.toString() + : v; } + return defaultValue; + } - return Control( - id: json['i'] as String, - pid: json['p'] as String, - type: (json['t'] as String).toLowerCase(), - name: json['n'] as String?, - childIds: List.from(json['c']), - attrs: attrs); + Control unwrapComponent() { + dynamic v = this; + while (v is Control && v.type == componentType) { + v = v.get(componentBodyProp); + } + return v; } - bool get isDisabled { - return attrBool("disabled", false)!; + /// Returns the [Control] for the given [propertyName], or `null` if not found, not a [Control], + /// or not visible when [visibleOnly] is `true` (default). + Control? child(String propertyName, {bool visibleOnly = true}) { + final child = get(propertyName); + if (child is! Control) return null; + return (visibleOnly && !child.visible) ? null : child; } - bool? get isAdaptive { - return attrBool("adaptive"); + /// Returns a list of [Control]s from the specified [propertyName]. + /// + /// If [visibleOnly] is `true` (default), only includes visible controls. + /// + /// Returns an empty list if the property is missing or null. + List children(String propertyName, {bool visibleOnly = true}) { + var elems = get(propertyName); + return List.from(elems is List + ? elems + : elems != null + ? [elems] + : []) + .map((c) => c.unwrapComponent()) + .where((c) => !visibleOnly || c.visible) + .toList(); } - bool get isVisible { - return attrBool("visible", true)!; + /// Triggers a control event. + /// + /// This method checks if the control has an event handler for the given + /// [eventName] and triggers the event if the application is not in a loading state. + /// + /// - [eventName]: The name of the event to trigger. + /// - [eventData]: Optional data to pass along with the event. + void triggerEvent(String eventName, [dynamic data]) { + return backend.triggerControlEvent(this, eventName, data); } - bool get isNonVisual { - return [ - //"alertdialog", - //"audio", - "banner", - //"bottomsheet", - "clipboard", - "filepicker", - "hapticfeedback", - "shakedetector", - "snackbar" - ].contains(type); + /// Whether this control currently has a handler subscribed to [eventName]. + /// + /// Accepts both `"event_name"` and `"on_event_name"` forms. + /// Internally this checks the boolean `on_` property. + bool hasEventHandler(String eventName) { + final String propName = + eventName.startsWith("on_") ? eventName : "on_$eventName"; + return get(propName, false)!; } - bool? attrBool(String name, [bool? defValue]) { - var r = attrs[name.toLowerCase()]; - return r != null ? r.toLowerCase() == "true" : defValue; + /// Triggers a control event without checking for subscribers. + /// + /// This method directly triggers the event for the control identified by its + /// [id] without verifying if there are any subscribers for the event. + /// + /// - [eventName]: The name of the event to trigger. + /// - [data]: Optional data to pass along with the event. + void triggerEventWithoutSubscribers(String eventName, [dynamic data]) { + return backend.triggerControlEventById(id, eventName, data); } - String? attrString(String name, [String? defValue]) { - return attrs[name.toLowerCase()] ?? defValue; + /// Updates the properties of this control. + /// + /// The [props] map contains key-value pairs where the key is the property + /// name and the value is the new value for that property. + /// + /// - [props]: A map of property names and their corresponding new values. + /// - [dart]: A boolean indicating whether to apply the patch in Dart. Defaults to `true`. + /// - [python]: A boolean indicating whether to send the update to the Python backend. Defaults to `true`. + /// - [notify]: A boolean indicating whether to notify listeners after applying the patch. Defaults to `false`. + /// + /// This method is typically used to modify the state of a control dynamically. + void updateProperties(Map props, + {bool dart = true, bool python = true, bool notify = false}) { + return backend.updateControl(id, props, + dart: dart, python: python, notify: notify); } - int? attrInt(String name, [int? defValue]) { - var r = attrs[name.toLowerCase()]; - if (r != null) { - var i = int.tryParse(r); - return i ?? defValue; + /// Creates a ControlNode from MessagePack–decoded data. + factory Control.fromMap(Map data, FletBackend backend, + {Control? parent}) { + if (!data.containsKey("_c")) { + throw Exception("Missing _c field in data: $data"); } - return defValue; + String type = data["_c"]; + int id = data["_i"]; + Map props = {}; + var newControl = Control( + id: id, + type: type, + properties: props, + backend: backend, + parent: parent); + backend.controlsIndex.set(newControl.id, newControl); + data.forEach((key, value) { + if (key == "_i" || key == "_c") return; + props[key] = _transformIfControl(value, newControl, backend); + }); + if (newControl.type == componentType) { + // components always notify their parent on changes + newControl.notifyParent = true; + } + return newControl; } - double? attrDouble(String name, [double? defValue]) { - var r = attrs[name.toLowerCase()]; - if (r != null && r.toLowerCase() == "inf") { - return double.infinity; - } else if (r != null) { - var i = double.tryParse(r); - return i ?? defValue; + bool update(Map props, {bool shouldNotify = false}) { + final changes = []; + final changedControls = []; + _mergeMaps(this, properties, props, changes, changedControls, ''); + if (shouldNotify) { + for (var c in changedControls) { + c.notify(); + } } - return defValue; + if (changes.any((prop) => _notifyParentProperties.contains(prop))) { + _parent?.target?.notify(); + } + return changes.isNotEmpty; } - DateTime? attrDateTime(String name, [DateTime? defValue]) { - var value = attrs[name.toLowerCase()]; - if (value == null) { - return defValue; + void _mergeMaps( + Control? parent, + Map dst, + Map src, + List changes, + List changedControls, + String prefix, + ) { + for (var entry in src.entries) { + final key = entry.key; + final fullKey = prefix.isEmpty ? key : '$prefix.$key'; + + if (dst[key] is Map && entry.value is Map) { + _mergeMaps( + parent, dst[key], entry.value, changes, changedControls, fullKey); + } else if (dst[key] is Control && + entry.value is Map && + (dst[key] as Control).id == entry.value["_i"]) { + _mergeMaps(dst[key], dst[key].properties, entry.value, changes, + changedControls, fullKey); + } else if (dst[key] != entry.value && !["_i", "_c"].contains(key)) { + dst[key] = _transformIfControl(entry.value, parent, backend); + changes.add(fullKey); + if (parent != null && !changedControls.any((c) => c.id == parent.id)) { + changedControls.add(parent); + } + } } - try { - return DateTime.parse(value); - } catch (e) { - return defValue; + } + + /// + /// Applies a patch (in MessagePack–decoded form) to this ControlNode. + /// It updates nested ControlNodes or plain data structures accordingly. + /// + /// Patch format: + /// patch := [[],, , ...] + /// + /// operation := | | + /// move_operation := [3, , , + /// , ] + /// remove_operation := [2, , ] + /// other_operation := [0|1, , , ] + /// + /// type: + /// Replace = 0 + /// Add = 1 + /// Remove = 2 + /// Move = 3 + /// + /// tree_index := [[0, {"property|position 1": [index, {"property|position 2"}], ...}] + /// + /// Example: + /// [ + /// 0, + /// { + /// "data_series":[ + /// 1, + /// { + /// 0:[ + /// 2, + /// { + /// "data_points":[ + /// 3, + /// { + /// 1:[ + /// 4 + /// ] + /// } + /// ] + /// } + /// ] + /// } + /// ], + /// } + /// ] + /// + /// Tree is converted to a Map with index as a key and Control, + /// or other object, or map, or list, as a value: + /// + /// 0: # root control .applyPatch is called against + /// 1: # "data_series" collection + /// 2: # "data_series[0]" DataSeries control + /// 3: # "data_series[0]["data_points"]" list of datapoints + /// 4: # "data_series[0]["data_points"][1]" DataPoint control + void applyPatch(List patch, FletBackend backend, + {bool shouldNotify = true}) { + debugPrint("Control($id).applyPatch: $patch, shouldNotify = $shouldNotify"); + + if (patch.length < 2) { + throw Exception( + "Patch must be a list with at least 2 elements: tree_index, operation"); + } + + Map> pathIndex = {}; + + buildPathIndex(List node, List path) { + // node[0] - index + // node[1] - map of child properties or indexes + pathIndex[node[0]] = path; + if (node.length > 1 && node[1] is Map) { + for (var entry in (node[1] as Map).entries) { + // key - property name or list index + // value - child node + buildPathIndex(entry.value, [...path, entry.key]); + } + } + } + + buildPathIndex(patch[0], []); + + //debugPrint("PATH INDEX: $pathIndex"); + + getPatchTarget(int index) { + var path = pathIndex[index]!; + dynamic obj = this; + Control? control = this; + for (var p in path) { + if (obj is Control) { + obj = obj.properties[p]; + } else if (obj is Map) { + obj = obj[p]; + } else if (obj is List) { + obj = obj[p]; + } + if (obj is Control) { + control = obj; + } + } + return PatchTarget(obj is Control ? obj.properties : obj, control!); + } + + // apply patch commands + for (int i = 1; i < patch.length; i++) { + var op = patch[i] as List; + var opType = OperationType.fromInt(op[0]); + if (opType == OperationType.replace) { + // REPLACE + var node = getPatchTarget(op[1]); + var key = op[2]; + var value = op[3]; + node.obj[key] = _transformIfControl(value, node.control, backend); + if (shouldNotify) { + node.control.notify(); + } + if (key is String) { + node.control.notifyParentIfPropertyChanged(key); + } + } else if (opType == OperationType.add) { + // ADD + var node = getPatchTarget(op[1]); + var index = op[2]; + var value = op[3]; + if (node.obj is Map) { + node.obj[index] = _transformIfControl(value, node.control, backend); + } else if (node.obj is List) { + node.obj + .insert(index, _transformIfControl(value, node.control, backend)); + } else { + throw Exception("Add operation can be applied to lists or maps: $op"); + } + if (shouldNotify) node.control.notify(); + } else if (opType == OperationType.remove) { + // REMOVE + var node = getPatchTarget(op[1]); + var index = op[2]; + if (node.obj is List) { + node.obj.removeAt(index); + } else if (node.obj is Map) { + node.obj.remove(index); + } else { + throw Exception( + "Remove operation can be applied to lists or maps: $op"); + } + if (shouldNotify) node.control.notify(); + } else if (opType == OperationType.move) { + // MOVE + var fromNode = getPatchTarget(op[1]); + var fromIndex = op[2]; + var toNode = getPatchTarget(op[3]); + var toIndex = op[4]; + if (fromNode.obj is List && toNode.obj is List) { + toNode.obj.insert(toIndex, fromNode.obj.removeAt(fromIndex)); + } else if (fromNode.obj is Map && toNode.obj is Map) { + toNode.obj[toIndex] = fromNode.obj.remove(fromIndex); + } else { + throw Exception( + "Move operation can only be applied to lists or maps: $op"); + } + if (shouldNotify) { + if (fromNode.control.id != toNode.control.id) { + fromNode.control.notify(); + toNode.control.notify(); + } else { + toNode.control.notify(); + } + } + } else { + throw Exception("Unknown patch operation: ${op[0]}"); + } } } - TimeOfDay? attrTime(String name, [TimeOfDay? defValue]) { - var value = attrs[name.toLowerCase()]; - if (value == null) { - return defValue; + void notify() { + debugPrint("Notify $type($id)"); + if (notifyParent) { + _parent?.target?.notify(); + } else { + notifyListeners(); } - List splitted = value.split(':'); - return TimeOfDay( - hour: int.parse(splitted[0]), minute: int.parse(splitted[1])); } - Color? attrColor(String name, BuildContext? context, [Color? defValue]) { - return parseColor( - context != null ? Theme.of(context) : null, attrString(name), defValue); + void notifyParentIfPropertyChanged(String name) { + if (_notifyParentProperties.contains(name)) { + debugPrint("notifyParentIfPropertyChanged: $type($id).$name"); + _parent?.target?.notify(); + } } - List? attrList(String name, [List? defValue = const []]) { - var l = attrString(name); - if (l == null) { - return defValue; - } else { - try { - return jsonDecode(l) as List; - } catch (e) { - debugPrint("attrList error while parsing $name: $e"); - return defValue; + static dynamic _transformIfControl( + dynamic value, Control? parent, FletBackend backend) { + //debugPrint("_transformIfControl: $value"); + if (value is Map) { + if (value.containsKey("_c")) { + return Control.fromMap(value, backend, parent: parent); } + return value.map( + (key, entryValue) => + MapEntry(key, _transformIfControl(entryValue, parent, backend)), + ); + } + if (value is List && value is! Uint8List) { + return value + .map((element) => _transformIfControl(element, parent, backend)) + .toList(growable: true); + } + return value; + } + + addInvokeMethodListener(InvokeControlMethodCallback listener) { + _invokeMethodListeners.add(listener); + + // If someone was waiting for a listener to be added, complete the future + if (_listenerAddedCompleter?.isCompleted == false) { + _listenerAddedCompleter!.complete(); + _listenerAddedCompleter = null; } } - Control copyWith( - {String? id, - String? pid, - String? type, - String? name, - List? childIds, - Map? attrs, - Map? state}) { - Control c = Control( - id: id ?? this.id, - pid: pid ?? this.pid, - type: type ?? this.type, - name: name ?? this.name, - childIds: childIds ?? this.childIds, - attrs: attrs ?? this.attrs); - for (var element in this.state.entries) { - c.state[element.key] = element.value; + removeInvokeMethodListener(InvokeControlMethodCallback listener) { + _invokeMethodListeners.remove(listener); + } + + Future invokeMethod( + String name, dynamic args, Duration timeout) async { + debugPrint("$type($id).$name($args)"); + + // If no listeners, wait until one is added or timeout occurs + if (_invokeMethodListeners.isEmpty) { + _listenerAddedCompleter ??= Completer(); + await _listenerAddedCompleter!.future.timeout(timeout, onTimeout: () { + throw TimeoutException( + "Timeout waiting for invoke method listener for $type($id).$name", + timeout); + }); + } + + if (_invokeMethodListeners.isEmpty) { + throw Exception("No invoke method listeners registered."); + } + List results = []; + for (var listener in _invokeMethodListeners) { + results.add(await listener(name, args)); } - c.onRemove.addAll(onRemove); - return c; + return results.length == 1 ? results[0] : results; + } + + Map toMap() { + return Map.fromEntries( + properties.entries.where((e) => e.value != null).map((e) { + if (e.value is Control) { + return MapEntry(e.key, (e.value as Control).toMap()); + } else if (e.value is List && + e.value.isNotEmpty && + e.value.first is Control) { + return MapEntry(e.key, + (e.value as List).map((c) => (c as Control).toMap()).toList()); + } else { + return MapEntry(e.key, e.value); + } + }), + ); + } + + @override + String toString() { + return toMap().toString(); + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + other is Control && + other.id == id && + other.type == type && + _equality.equals(other.properties, properties); } @override - List get props => [id, pid, type, name, childIds, attrs]; + int get hashCode => Object.hash( + id, + type, + _equality.hash(properties), + ); } diff --git a/packages/flet/lib/src/models/control_ancestor_view_model.dart b/packages/flet/lib/src/models/control_ancestor_view_model.dart deleted file mode 100644 index 600356cac4..0000000000 --- a/packages/flet/lib/src/models/control_ancestor_view_model.dart +++ /dev/null @@ -1,33 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; -import 'control.dart'; - -class ControlAncestorViewModel extends Equatable { - final Control? ancestor; - - const ControlAncestorViewModel({required this.ancestor}); - - static ControlAncestorViewModel fromStore( - Store store, String id, String ancestorType) { - Control? ancestor; - String controlId = id; - while (true) { - String parentId = store.state.controls[controlId]!.pid; - if (parentId == "") { - break; - } - ancestor = store.state.controls[parentId]!; - if (ancestor.type.toLowerCase() == ancestorType.toLowerCase()) { - break; - } - controlId = ancestor.id; - } - - return ControlAncestorViewModel(ancestor: ancestor); - } - - @override - List get props => [ancestor]; -} diff --git a/packages/flet/lib/src/models/control_tree_view_model.dart b/packages/flet/lib/src/models/control_tree_view_model.dart deleted file mode 100644 index bf1ca41da7..0000000000 --- a/packages/flet/lib/src/models/control_tree_view_model.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; -import 'control.dart'; - -class ControlTreeViewModel extends Equatable { - final Control control; - final List children; - - const ControlTreeViewModel({required this.control, required this.children}); - - static ControlTreeViewModel fromStore( - Store store, Control control) { - return ControlTreeViewModel( - control: control, - children: control.childIds - .map((childId) => store.state.controls[childId]) - .whereNotNull() - .where((c) => c.isVisible) - .map((c) => ControlTreeViewModel.fromStore(store, c)) - .toList()); - } - - @override - List get props => [control, children]; -} diff --git a/packages/flet/lib/src/models/control_view_model.dart b/packages/flet/lib/src/models/control_view_model.dart deleted file mode 100644 index 05b2a0f1f5..0000000000 --- a/packages/flet/lib/src/models/control_view_model.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; -import 'control.dart'; - -class ControlViewModel extends Equatable { - final Control control; - final List children; - final dynamic dispatch; - - const ControlViewModel( - {required this.control, required this.children, required this.dispatch}); - - static ControlViewModel? fromStore(Store store, String id) { - var control = store.state.controls[id]; - return control != null - ? ControlViewModel( - control: control, - children: control.childIds - .map((childId) => store.state.controls[childId]) - .whereNotNull() - .toList(), - dispatch: store.dispatch) - : null; - } - - @override - List get props => [control, children, dispatch]; -} diff --git a/packages/flet/lib/src/models/controls_view_model.dart b/packages/flet/lib/src/models/controls_view_model.dart deleted file mode 100644 index eb3e4cc3ba..0000000000 --- a/packages/flet/lib/src/models/controls_view_model.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; -import 'control_view_model.dart'; - -class ControlsViewModel extends Equatable { - final List controlViews; - - const ControlsViewModel({required this.controlViews}); - - static ControlsViewModel fromStore( - Store store, Iterable ids) { - return ControlsViewModel( - controlViews: ids - .map((id) => ControlViewModel.fromStore(store, id)) - .whereNotNull() - .toList()); - } - - @override - List get props => [controlViews]; -} diff --git a/packages/flet/lib/src/models/keyboard_event.dart b/packages/flet/lib/src/models/keyboard_event.dart new file mode 100644 index 0000000000..b689dd4d16 --- /dev/null +++ b/packages/flet/lib/src/models/keyboard_event.dart @@ -0,0 +1,22 @@ +class KeyboardEvent { + final String key; + final bool isShiftPressed; + final bool isControlPressed; + final bool isAltPressed; + final bool isMetaPressed; + + KeyboardEvent( + {required this.key, + required this.isShiftPressed, + required this.isControlPressed, + required this.isAltPressed, + required this.isMetaPressed}); + + Map toMap() => { + 'key': key, + 'shift': isShiftPressed, + 'ctrl': isControlPressed, + 'alt': isAltPressed, + 'meta': isMetaPressed + }; +} diff --git a/packages/flet/lib/src/models/multi_view.dart b/packages/flet/lib/src/models/multi_view.dart new file mode 100644 index 0000000000..5c09458fbc --- /dev/null +++ b/packages/flet/lib/src/models/multi_view.dart @@ -0,0 +1,16 @@ +import 'dart:ui'; + +class MultiView { + int viewId; + FlutterView flutterView; + Map initialData; + + MultiView( + {required this.viewId, + required this.flutterView, + required this.initialData}); + + Map toMap() { + return {"view_id": viewId, "initial_data": initialData}; + } +} diff --git a/packages/flet/lib/src/models/page_args_model.dart b/packages/flet/lib/src/models/page_args_model.dart deleted file mode 100644 index f2839c1c31..0000000000 --- a/packages/flet/lib/src/models/page_args_model.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; - -class PageArgsModel extends Equatable { - final Uri? pageUri; - final String assetsDir; - - const PageArgsModel({required this.pageUri, required this.assetsDir}); - - static PageArgsModel fromStore(Store store) { - return PageArgsModel( - pageUri: store.state.pageUri, assetsDir: store.state.assetsDir); - } - - @override - List get props => [pageUri, assetsDir]; -} diff --git a/packages/flet/lib/src/models/page_design.dart b/packages/flet/lib/src/models/page_design.dart new file mode 100644 index 0000000000..ed2fd2e396 --- /dev/null +++ b/packages/flet/lib/src/models/page_design.dart @@ -0,0 +1 @@ +enum PageDesign { material, cupertino } diff --git a/packages/flet/lib/src/models/page_load_view_model.dart b/packages/flet/lib/src/models/page_load_view_model.dart deleted file mode 100644 index 6b1385e483..0000000000 --- a/packages/flet/lib/src/models/page_load_view_model.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; -import 'page_media_view_model.dart'; - -class PageLoadViewModel extends Equatable { - final Uri? pageUri; - final String sessionId; - final PageMediaViewModel sizeViewModel; - - const PageLoadViewModel( - {required this.pageUri, - required this.sessionId, - required this.sizeViewModel}); - - static PageLoadViewModel fromStore(Store store) { - return PageLoadViewModel( - pageUri: store.state.pageUri, - sessionId: store.state.sessionId, - sizeViewModel: PageMediaViewModel.fromStore(store)); - } - - @override - List get props => [pageUri, sizeViewModel]; -} diff --git a/packages/flet/lib/src/models/page_media_view_model.dart b/packages/flet/lib/src/models/page_media_view_model.dart deleted file mode 100644 index 297e29488a..0000000000 --- a/packages/flet/lib/src/models/page_media_view_model.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'dart:ui'; - -import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import '../protocol/page_media_data.dart'; -import 'app_state.dart'; - -class PageMediaViewModel extends Equatable { - final bool isRegistered; - final Size size; - final Brightness displayBrightness; - final PageMediaData media; - final Function dispatch; - - const PageMediaViewModel( - {required this.isRegistered, - required this.size, - required this.displayBrightness, - required this.media, - required this.dispatch}); - - static PageMediaViewModel fromStore(Store store) { - return PageMediaViewModel( - isRegistered: store.state.isRegistered, - size: store.state.size, - displayBrightness: store.state.displayBrightness, - media: store.state.media, - dispatch: store.dispatch); - } - - @override - List get props => [size, displayBrightness, dispatch, isRegistered]; -} diff --git a/packages/flet/lib/src/models/page_size_view_model.dart b/packages/flet/lib/src/models/page_size_view_model.dart index 29ca278c3a..53f0f90592 100644 --- a/packages/flet/lib/src/models/page_size_view_model.dart +++ b/packages/flet/lib/src/models/page_size_view_model.dart @@ -1,9 +1,6 @@ import 'dart:ui'; import 'package:equatable/equatable.dart'; -import 'package:redux/redux.dart'; - -import 'app_state.dart'; class PageSizeViewModel extends Equatable { final Map breakpoints; @@ -11,11 +8,6 @@ class PageSizeViewModel extends Equatable { const PageSizeViewModel({required this.size, required this.breakpoints}); - static PageSizeViewModel fromStore(Store store) { - return PageSizeViewModel( - size: store.state.size, breakpoints: store.state.sizeBreakpoints); - } - @override List get props => [size, breakpoints]; } diff --git a/packages/flet/lib/src/models/window_media_data.dart b/packages/flet/lib/src/models/window_media_data.dart deleted file mode 100644 index b4be457fb7..0000000000 --- a/packages/flet/lib/src/models/window_media_data.dart +++ /dev/null @@ -1,18 +0,0 @@ -class WindowMediaData { - bool? isMaximized; - bool? isMinimized; - bool? isMinimizable; - bool? isFullScreen; - bool? isResizable; - bool? isMovable; - bool? isClosable; - bool? isAlwaysOnTop; - bool? isFocused; - bool? isPreventClose; - bool? isVisible; - double? width; - double? height; - double? top; - double? left; - double? opacity; -} diff --git a/packages/flet/lib/src/models/window_state.dart b/packages/flet/lib/src/models/window_state.dart new file mode 100644 index 0000000000..8a8771b618 --- /dev/null +++ b/packages/flet/lib/src/models/window_state.dart @@ -0,0 +1,56 @@ +class WindowState { + bool maximized; + bool minimized; + bool fullScreen; + bool alwaysOnTop; + bool focused; + bool visible; + bool minimizable; + bool maximizable; + bool resizable; + bool preventClose; + bool skipTaskBar; + double width; + double height; + double top; + double left; + double opacity; + + WindowState({ + required this.maximized, + required this.minimized, + required this.fullScreen, + required this.alwaysOnTop, + required this.focused, + required this.visible, + required this.minimizable, + required this.maximizable, + required this.resizable, + required this.preventClose, + required this.skipTaskBar, + required this.width, + required this.height, + required this.top, + required this.left, + required this.opacity, + }); + + Map toMap() => { + 'maximized': maximized, + 'minimized': minimized, + 'full_screen': fullScreen, + 'always_on_top': alwaysOnTop, + 'focused': focused, + 'visible': visible, + 'width': width, + 'height': height, + 'top': top, + 'left': left, + 'opacity': opacity, + }; + + @override + String toString() { + return toMap().toString(); + } +} diff --git a/packages/flet/lib/src/protocol/add_page_controls_payload.dart b/packages/flet/lib/src/protocol/add_page_controls_payload.dart deleted file mode 100644 index 71cb5c4f7b..0000000000 --- a/packages/flet/lib/src/protocol/add_page_controls_payload.dart +++ /dev/null @@ -1,15 +0,0 @@ -import '../models/control.dart'; - -class AddPageControlsPayload { - final List trimIDs; - final List controls; - - AddPageControlsPayload({required this.trimIDs, required this.controls}); - - factory AddPageControlsPayload.fromJson(Map json) { - var controlsJson = json['controls'] as List; - final controls = controlsJson.map((j) => Control.fromJson(j)).toList(); - return AddPageControlsPayload( - trimIDs: List.from(json['trimIDs']), controls: controls); - } -} diff --git a/packages/flet/lib/src/protocol/app_become_active_payload.dart b/packages/flet/lib/src/protocol/app_become_active_payload.dart deleted file mode 100644 index 1f1dccf1ee..0000000000 --- a/packages/flet/lib/src/protocol/app_become_active_payload.dart +++ /dev/null @@ -1,6 +0,0 @@ -class AppBecomeActivePayload { - AppBecomeActivePayload(); - - factory AppBecomeActivePayload.fromJson(Map json) => - AppBecomeActivePayload(); -} diff --git a/packages/flet/lib/src/protocol/app_become_inactive_payload.dart b/packages/flet/lib/src/protocol/app_become_inactive_payload.dart deleted file mode 100644 index 88105869ec..0000000000 --- a/packages/flet/lib/src/protocol/app_become_inactive_payload.dart +++ /dev/null @@ -1,8 +0,0 @@ -class AppBecomeInactivePayload { - final String message; - - AppBecomeInactivePayload({required this.message}); - - factory AppBecomeInactivePayload.fromJson(Map json) => - AppBecomeInactivePayload(message: json['message'] as String); -} diff --git a/packages/flet/lib/src/protocol/append_control_props_request.dart b/packages/flet/lib/src/protocol/append_control_props_request.dart deleted file mode 100644 index cca6e80fbe..0000000000 --- a/packages/flet/lib/src/protocol/append_control_props_request.dart +++ /dev/null @@ -1,13 +0,0 @@ -class AppendControlPropsPayload { - final List> props; - - AppendControlPropsPayload({required this.props}); - - factory AppendControlPropsPayload.fromJson(Map json) { - var propsJson = json['props'] as List; - var props = propsJson - .map((propJson) => Map.from(propJson)) - .toList(); - return AppendControlPropsPayload(props: props); - } -} diff --git a/packages/flet/lib/src/protocol/clean_control_payload.dart b/packages/flet/lib/src/protocol/clean_control_payload.dart deleted file mode 100644 index 2db178662c..0000000000 --- a/packages/flet/lib/src/protocol/clean_control_payload.dart +++ /dev/null @@ -1,8 +0,0 @@ -class CleanControlPayload { - final List ids; - - CleanControlPayload({required this.ids}); - - factory CleanControlPayload.fromJson(Map json) => - CleanControlPayload(ids: List.from(json['ids'])); -} diff --git a/packages/flet/lib/src/protocol/control_event_body.dart b/packages/flet/lib/src/protocol/control_event_body.dart new file mode 100644 index 0000000000..aa39f7c666 --- /dev/null +++ b/packages/flet/lib/src/protocol/control_event_body.dart @@ -0,0 +1,11 @@ +class ControlEventBody { + final int target; + final String name; + final dynamic data; + + ControlEventBody( + {required this.target, required this.name, required this.data}); + + Map toMap() => + {'target': target, 'name': name, 'data': data}; +} diff --git a/packages/flet/lib/src/protocol/invoke_method_payload.dart b/packages/flet/lib/src/protocol/invoke_method_payload.dart deleted file mode 100644 index d4e722e725..0000000000 --- a/packages/flet/lib/src/protocol/invoke_method_payload.dart +++ /dev/null @@ -1,22 +0,0 @@ -class InvokeMethodPayload { - final String methodId; - final String methodName; - final String controlId; - final Map args; - - InvokeMethodPayload( - {required this.methodId, - required this.methodName, - required this.controlId, - required this.args}); - - factory InvokeMethodPayload.fromJson(Map json) { - return InvokeMethodPayload( - methodId: json["methodId"], - methodName: json['methodName'], - controlId: json["controlId"], - args: json['arguments'] != null - ? Map.from(json['arguments']) - : {}); - } -} diff --git a/packages/flet/lib/src/protocol/invoke_method_request_body.dart b/packages/flet/lib/src/protocol/invoke_method_request_body.dart new file mode 100644 index 0000000000..4f4aaa7d13 --- /dev/null +++ b/packages/flet/lib/src/protocol/invoke_method_request_body.dart @@ -0,0 +1,24 @@ +class InvokeMethodRequestBody { + final int controlId; + final String callId; + final String name; + final dynamic args; + final Duration timeout; + + InvokeMethodRequestBody( + {required this.controlId, + required this.callId, + required this.name, + required this.args, + required this.timeout}); + + factory InvokeMethodRequestBody.fromJson(Map json) { + return InvokeMethodRequestBody( + controlId: json["control_id"], + callId: json["call_id"], + name: json['name'], + args: json['args'], + timeout: Duration( + seconds: json.containsKey("timeout") ? json['timeout'] : 10)); + } +} diff --git a/packages/flet/lib/src/protocol/invoke_method_response_body.dart b/packages/flet/lib/src/protocol/invoke_method_response_body.dart new file mode 100644 index 0000000000..6714678088 --- /dev/null +++ b/packages/flet/lib/src/protocol/invoke_method_response_body.dart @@ -0,0 +1,16 @@ +class InvokeMethodResponseBody { + final int controlId; + final String callId; + final dynamic result; + final String? error; + + InvokeMethodResponseBody( + {required this.controlId, required this.callId, this.result, this.error}); + + Map toMap() => { + 'control_id': controlId, + 'call_id': callId, + 'result': result, + 'error': error + }; +} diff --git a/packages/flet/lib/src/protocol/invoke_method_result.dart b/packages/flet/lib/src/protocol/invoke_method_result.dart deleted file mode 100644 index 8a3cc78831..0000000000 --- a/packages/flet/lib/src/protocol/invoke_method_result.dart +++ /dev/null @@ -1,13 +0,0 @@ -class InvokeMethodResult { - final String methodId; - final String? result; - final String? error; - - InvokeMethodResult({required this.methodId, this.result, this.error}); - - Map toJson() => { - 'method_id': methodId, - 'result': result, - 'error': error - }; -} diff --git a/packages/flet/lib/src/protocol/message.dart b/packages/flet/lib/src/protocol/message.dart index 79dca6dad7..d2afb63ecb 100644 --- a/packages/flet/lib/src/protocol/message.dart +++ b/packages/flet/lib/src/protocol/message.dart @@ -1,17 +1,17 @@ enum MessageAction { - registerWebClient, - pageEventFromWeb, - updateControlProps, - appBecomeActive, - appBecomeInactive, - sessionCrashed, - invokeMethod, - addPageControls, - replacePageControls, - pageControlsBatch, - appendControlProps, - cleanControl, - removeControl + registerClient(1), + patchControl(2), + controlEvent(3), + updateControl(4), + invokeControlMethod(5), + sessionCrashed(6), + // Worker → dart: one line of stdout/stderr from the embedded + // Pyodide runtime (only emitted when running inside a FletApp host + // that wired stdout/stderr at loadPyodide time). + pythonOutput(7); + + final int value; + const MessageAction(this.value); } class Message { @@ -20,13 +20,11 @@ class Message { Message({required this.action, required this.payload}); - Map toJson() => - {'action': action.name, 'payload': payload.toJson()}; + dynamic toList() => [action.value, payload]; - factory Message.fromJson(Map json) { + factory Message.fromList(List value) { return Message( - action: MessageAction.values - .firstWhere((e) => e.name == json['action'] as String), - payload: json['payload']); + action: MessageAction.values.firstWhere((e) => e.value == value[0]), + payload: value[1]); } } diff --git a/packages/flet/lib/src/protocol/page_controls_batch_payload.dart b/packages/flet/lib/src/protocol/page_controls_batch_payload.dart deleted file mode 100644 index e6e775c71e..0000000000 --- a/packages/flet/lib/src/protocol/page_controls_batch_payload.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'message.dart'; - -class PageControlsBatchPayload { - final List messages; - - PageControlsBatchPayload({required this.messages}); - - factory PageControlsBatchPayload.fromJson(dynamic json) { - var messagesJson = json as List; - return PageControlsBatchPayload( - messages: messagesJson.map((m) => Message.fromJson(m)).toList()); - } -} diff --git a/packages/flet/lib/src/protocol/page_event_from_web_request.dart b/packages/flet/lib/src/protocol/page_event_from_web_request.dart deleted file mode 100644 index fd54c71354..0000000000 --- a/packages/flet/lib/src/protocol/page_event_from_web_request.dart +++ /dev/null @@ -1,16 +0,0 @@ -class PageEventFromWebRequest { - final String eventTarget; - final String eventName; - final String? eventData; - - PageEventFromWebRequest( - {required this.eventTarget, - required this.eventName, - required this.eventData}); - - Map toJson() => { - 'eventTarget': eventTarget, - 'eventName': eventName, - 'eventData': eventData - }; -} diff --git a/packages/flet/lib/src/protocol/page_media_data.dart b/packages/flet/lib/src/protocol/page_media_data.dart index c164dc4542..52b63f8fce 100644 --- a/packages/flet/lib/src/protocol/page_media_data.dart +++ b/packages/flet/lib/src/protocol/page_media_data.dart @@ -5,20 +5,37 @@ class PageMediaData extends Equatable { final PaddingData padding; final PaddingData viewPadding; final PaddingData viewInsets; - - const PageMediaData( - {required this.padding, - required this.viewPadding, - required this.viewInsets}); - - Map toJson() => { - 'padding': padding, - 'view_padding': viewPadding, - 'view_insets': viewInsets, + final double devicePixelRatio; + final Orientation orientation; + final bool alwaysUse24HourFormat; + + const PageMediaData({ + required this.padding, + required this.viewPadding, + required this.viewInsets, + required this.devicePixelRatio, + required this.orientation, + required this.alwaysUse24HourFormat, + }); + + Map toMap() => { + 'padding': padding.toMap(), + 'view_padding': viewPadding.toMap(), + 'view_insets': viewInsets.toMap(), + 'device_pixel_ratio': devicePixelRatio, + 'orientation': orientation.name, + 'always_use_24_hour_format': alwaysUse24HourFormat, }; @override - List get props => [padding, viewPadding, viewInsets]; + List get props => [ + padding, + viewPadding, + viewInsets, + devicePixelRatio, + orientation, + alwaysUse24HourFormat, + ]; } class PaddingData extends Equatable { @@ -33,7 +50,7 @@ class PaddingData extends Equatable { bottom = insets.bottom, left = insets.left; - Map toJson() => { + Map toMap() => { 'top': top, 'right': right, 'bottom': bottom, diff --git a/packages/flet/lib/src/protocol/patch_control_request_body.dart b/packages/flet/lib/src/protocol/patch_control_request_body.dart new file mode 100644 index 0000000000..a96ca928f9 --- /dev/null +++ b/packages/flet/lib/src/protocol/patch_control_request_body.dart @@ -0,0 +1,16 @@ +class PatchControlRequestBody { + final int id; + final List patch; + + PatchControlRequestBody({ + required this.id, + required this.patch, + }); + + factory PatchControlRequestBody.fromJson(Map json) { + return PatchControlRequestBody( + id: json["id"], + patch: List.from(json['patch']), + ); + } +} diff --git a/packages/flet/lib/src/protocol/python_output_body.dart b/packages/flet/lib/src/protocol/python_output_body.dart new file mode 100644 index 0000000000..e1cf629dd8 --- /dev/null +++ b/packages/flet/lib/src/protocol/python_output_body.dart @@ -0,0 +1,12 @@ +class PythonOutputBody { + final String text; + final bool isStderr; + + PythonOutputBody({required this.text, required this.isStderr}); + + factory PythonOutputBody.fromJson(Map json) => + PythonOutputBody( + text: json['text'] as String, + isStderr: json['is_stderr'] as bool? ?? false, + ); +} diff --git a/packages/flet/lib/src/protocol/register_client_request_body.dart b/packages/flet/lib/src/protocol/register_client_request_body.dart new file mode 100644 index 0000000000..d12b499445 --- /dev/null +++ b/packages/flet/lib/src/protocol/register_client_request_body.dart @@ -0,0 +1,14 @@ +class RegisterClientRequestBody { + final String? sessionId; + final String pageName; + final Map page; + + RegisterClientRequestBody( + {required this.sessionId, required this.pageName, required this.page}); + + Map toMap() => { + 'session_id': sessionId, + 'page_name': pageName, + 'page': page + }; +} diff --git a/packages/flet/lib/src/protocol/register_client_response_body.dart b/packages/flet/lib/src/protocol/register_client_response_body.dart new file mode 100644 index 0000000000..928f8e514a --- /dev/null +++ b/packages/flet/lib/src/protocol/register_client_response_body.dart @@ -0,0 +1,15 @@ +class RegisterClientResponseBody { + final String? sessionId; + final Map patch; + final String? error; + + RegisterClientResponseBody( + {required this.sessionId, required this.patch, required this.error}); + + factory RegisterClientResponseBody.fromJson(Map json) { + return RegisterClientResponseBody( + sessionId: json["session_id"], + patch: Map.from(json["page_patch"]), + error: json['error'] as String?); + } +} diff --git a/packages/flet/lib/src/protocol/register_webclient_request.dart b/packages/flet/lib/src/protocol/register_webclient_request.dart deleted file mode 100644 index 0a629d988c..0000000000 --- a/packages/flet/lib/src/protocol/register_webclient_request.dart +++ /dev/null @@ -1,52 +0,0 @@ -class RegisterWebClientRequest { - final String pageName; - final String? pageRoute; - final String? pageWidth; - final String? pageHeight; - final String? windowWidth; - final String? windowHeight; - final String? windowTop; - final String? windowLeft; - final String? isPWA; - final String? isWeb; - final String? isDebug; - final String? platform; - final String? platformBrightness; - final String? media; - final String? sessionId; - - RegisterWebClientRequest( - {required this.pageName, - this.pageRoute, - this.pageWidth, - this.pageHeight, - this.windowWidth, - this.windowHeight, - this.windowTop, - this.windowLeft, - this.isPWA, - this.isWeb, - this.isDebug, - this.platform, - this.platformBrightness, - this.media, - this.sessionId}); - - Map toJson() => { - 'pageName': pageName, - 'pageRoute': pageRoute, - 'pageWidth': pageWidth, - 'pageHeight': pageHeight, - 'windowWidth': windowWidth, - 'windowHeight': windowHeight, - 'windowTop': windowTop, - 'windowLeft': windowLeft, - 'isPWA': isPWA, - 'isWeb': isWeb, - 'isDebug': isDebug, - 'platform': platform, - 'platformBrightness': platformBrightness, - 'media': media, - 'sessionId': sessionId - }; -} diff --git a/packages/flet/lib/src/protocol/register_webclient_response.dart b/packages/flet/lib/src/protocol/register_webclient_response.dart deleted file mode 100644 index df34d4cdf4..0000000000 --- a/packages/flet/lib/src/protocol/register_webclient_response.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'session_payload.dart'; - -class RegisterWebClientResponse { - final SessionPayload? session; - final bool appInactive; - final String? error; - - RegisterWebClientResponse( - {this.session, required this.appInactive, this.error}); - - factory RegisterWebClientResponse.fromJson(Map json) { - return RegisterWebClientResponse( - session: json['session'] != null - ? SessionPayload.fromJson(json['session']) - : null, - appInactive: json['appInactive'] as bool, - error: json['error'] as String?); - } -} diff --git a/packages/flet/lib/src/protocol/remove_control_payload.dart b/packages/flet/lib/src/protocol/remove_control_payload.dart deleted file mode 100644 index b70226cacc..0000000000 --- a/packages/flet/lib/src/protocol/remove_control_payload.dart +++ /dev/null @@ -1,8 +0,0 @@ -class RemoveControlPayload { - final List ids; - - RemoveControlPayload({required this.ids}); - - factory RemoveControlPayload.fromJson(Map json) => - RemoveControlPayload(ids: List.from(json['ids'] ?? [])); -} diff --git a/packages/flet/lib/src/protocol/replace_page_controls_payload.dart b/packages/flet/lib/src/protocol/replace_page_controls_payload.dart deleted file mode 100644 index 73dc4001ea..0000000000 --- a/packages/flet/lib/src/protocol/replace_page_controls_payload.dart +++ /dev/null @@ -1,19 +0,0 @@ -import '../models/control.dart'; - -class ReplacePageControlsPayload { - final List ids; - final List controls; - final bool remove; - - ReplacePageControlsPayload( - {required this.ids, required this.controls, required this.remove}); - - factory ReplacePageControlsPayload.fromJson(Map json) { - var controlsJson = json['controls'] as List; - final controls = controlsJson.map((j) => Control.fromJson(j)).toList(); - return ReplacePageControlsPayload( - ids: List.from(json['ids']), - controls: controls, - remove: json['remove'] as bool); - } -} diff --git a/packages/flet/lib/src/protocol/session_crashed_body.dart b/packages/flet/lib/src/protocol/session_crashed_body.dart new file mode 100644 index 0000000000..cbd3ccd4f8 --- /dev/null +++ b/packages/flet/lib/src/protocol/session_crashed_body.dart @@ -0,0 +1,8 @@ +class SessionCrashedBody { + final String message; + + SessionCrashedBody({required this.message}); + + factory SessionCrashedBody.fromJson(Map json) => + SessionCrashedBody(message: json['message'] as String); +} diff --git a/packages/flet/lib/src/protocol/session_crashed_payload.dart b/packages/flet/lib/src/protocol/session_crashed_payload.dart deleted file mode 100644 index d9b6911cb5..0000000000 --- a/packages/flet/lib/src/protocol/session_crashed_payload.dart +++ /dev/null @@ -1,8 +0,0 @@ -class SessionCrashedPayload { - final String message; - - SessionCrashedPayload({required this.message}); - - factory SessionCrashedPayload.fromJson(Map json) => - SessionCrashedPayload(message: json['message'] as String); -} diff --git a/packages/flet/lib/src/protocol/session_payload.dart b/packages/flet/lib/src/protocol/session_payload.dart index fdd58f53fb..1fbddd2c56 100644 --- a/packages/flet/lib/src/protocol/session_payload.dart +++ b/packages/flet/lib/src/protocol/session_payload.dart @@ -1,16 +1,14 @@ -import '../models/control.dart'; - class SessionPayload { final String id; - final Map controls; + //final Map controls; - SessionPayload({required this.id, required this.controls}); + SessionPayload({required this.id}); - factory SessionPayload.fromJson(Map json) { - Map controls = {}; - for (var key in json['controls'].keys) { - controls[key] = Control.fromJson(json['controls'][key]); - } - return SessionPayload(id: json['id'] as String, controls: controls); - } + // factory SessionPayload.fromJson(Map json) { + // Map controls = {}; + // for (var key in json['controls'].keys) { + // controls[key] = Control.fromJson(json['controls'][key]); + // } + // return SessionPayload(id: json['id'] as String, controls: controls); + // } } diff --git a/packages/flet/lib/src/protocol/update_control_body.dart b/packages/flet/lib/src/protocol/update_control_body.dart new file mode 100644 index 0000000000..8bb33409b3 --- /dev/null +++ b/packages/flet/lib/src/protocol/update_control_body.dart @@ -0,0 +1,8 @@ +class UpdateControlBody { + final int id; + final Map props; + + UpdateControlBody({required this.id, required this.props}); + + Map toMap() => {'id': id, 'props': props}; +} diff --git a/packages/flet/lib/src/protocol/update_control_props_payload.dart b/packages/flet/lib/src/protocol/update_control_props_payload.dart deleted file mode 100644 index bc21d1fe78..0000000000 --- a/packages/flet/lib/src/protocol/update_control_props_payload.dart +++ /dev/null @@ -1,13 +0,0 @@ -class UpdateControlPropsPayload { - final List> props; - - UpdateControlPropsPayload({required this.props}); - - factory UpdateControlPropsPayload.fromJson(Map json) { - var propsJson = json['props'] as List; - var props = propsJson - .map((propJson) => Map.from(propJson)) - .toList(); - return UpdateControlPropsPayload(props: props); - } -} diff --git a/packages/flet/lib/src/protocol/update_control_props_request.dart b/packages/flet/lib/src/protocol/update_control_props_request.dart deleted file mode 100644 index 1fd520ee08..0000000000 --- a/packages/flet/lib/src/protocol/update_control_props_request.dart +++ /dev/null @@ -1,7 +0,0 @@ -class UpdateControlPropsRequest { - final List> props; - - UpdateControlPropsRequest({required this.props}); - - Map toJson() => {'props': props}; -} diff --git a/packages/flet/lib/src/reducers.dart b/packages/flet/lib/src/reducers.dart deleted file mode 100644 index fead8e0840..0000000000 --- a/packages/flet/lib/src/reducers.dart +++ /dev/null @@ -1,553 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/utils/browser_context_menu.dart'; -import 'package:flutter/foundation.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:device_info_plus/device_info_plus.dart'; - -import 'actions.dart'; -import 'flet_control_backend.dart'; -import 'models/app_state.dart'; -import 'models/control.dart'; -import 'models/window_media_data.dart'; -import 'protocol/add_page_controls_payload.dart'; -import 'protocol/clean_control_payload.dart'; -import 'protocol/invoke_method_result.dart'; -import 'protocol/message.dart'; -import 'protocol/remove_control_payload.dart'; -import 'protocol/update_control_props_payload.dart'; -import 'utils/client_storage.dart'; -import 'utils/clipboard.dart'; -import 'utils/desktop.dart'; -import 'utils/launch_url.dart'; -import 'utils/platform_utils_non_web.dart' - if (dart.library.js) "utils/platform_utils_web.dart"; -import 'utils/session_store_non_web.dart' - if (dart.library.js) "utils/session_store_web.dart"; -import 'utils/uri.dart'; - -enum Actions { increment, setText, setError } - -AppState appReducer(AppState state, dynamic action) { - if (action is PageLoadAction) { - var sessionId = SessionStore.sessionId; - return state.copyWith( - pageUri: action.pageUri, - assetsDir: action.assetsDir, - sessionId: sessionId, - isLoading: true); - } else if (action is PageSizeChangeAction) { - // - // page size changed - // - debugPrint("New page size: ${action.newPageSize}"); - - var page = state.controls["page"]; - var controls = Map.of(state.controls); - if (page != null && !state.isLoading) { - var pageAttrs = Map.of(page.attrs); - pageAttrs["width"] = action.newPageSize.width.toString(); - pageAttrs["height"] = action.newPageSize.height.toString(); - - Map props = { - "width": action.newPageSize.width.toString(), - "height": action.newPageSize.height.toString() - }; - - if (action.wmd != null) { - addWindowMediaEventProps(action.wmd!, pageAttrs); - addWindowMediaEventProps(action.wmd!, props); - } - controls[page.id] = page.copyWith(attrs: pageAttrs); - action.backend.updateControlState("page", props, client: false); - action.backend.triggerControlEvent( - "page", - "resized", - jsonEncode({ - "width": action.newPageSize.width, - "height": action.newPageSize.height - })); - } - - return state.copyWith( - isRegistered: true, controls: controls, size: action.newPageSize); - } else if (action is SetPageRouteAction) { - // - // page route changed - // - var page = state.controls["page"]; - var controls = Map.of(state.controls); - String? deepLinkingRoute; - - if (page != null) { - var pageAttrs = Map.of(page.attrs); - pageAttrs["route"] = action.route; - controls[page.id] = page.copyWith(attrs: pageAttrs); - - if (state.route == "" && state.isLoading) { - // registering a client - debugPrint("Registering web client with route: ${action.route}"); - String pageName = getWebPageName(state.pageUri!); - - getWindowMediaData().then((wmd) async { - String platformValue = defaultTargetPlatform.name.toLowerCase(); - if (platformValue == "android") { - try { - DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); - AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; - if (androidInfo.systemFeatures - .contains('android.software.leanback')) { - platformValue = "android_tv"; - } - } on Exception catch (e) { - debugPrint(e.toString()); - } - } - action.server.registerWebClient( - pageName: pageName, - pageRoute: action.route, - pageWidth: state.size.width.toString(), - pageHeight: state.size.height.toString(), - windowWidth: wmd.width != null ? wmd.width.toString() : "", - windowHeight: wmd.height != null ? wmd.height.toString() : "", - windowTop: wmd.top != null ? wmd.top.toString() : "", - windowLeft: wmd.left != null ? wmd.left.toString() : "", - isPWA: isProgressiveWebApp().toString(), - isWeb: kIsWeb.toString(), - isDebug: kDebugMode.toString(), - platform: platformValue, - platformBrightness: state.displayBrightness.name.toString(), - media: json.encode(state.media)); - - action.server.connect(address: state.pageUri!.toString()); - }); - } else if (state.isLoading) { - // buffer route - deepLinkingRoute = action.route; - } else { - // existing route change - debugPrint("New page route: ${action.route}"); - sendRouteChangeEvent(action.server, action.route); - } - } - - return state.copyWith( - controls: controls, - route: action.route, - deepLinkingRoute: deepLinkingRoute); - } else if (action is WindowEventAction) { - // - // window event - // - - debugPrint("Window event: ${action.eventName}"); - - var page = state.controls["page"]; - var controls = Map.of(state.controls); - if (page != null && !state.isLoading) { - var pageAttrs = Map.of(page.attrs); - Map props = {}; - addWindowMediaEventProps(action.wmd, pageAttrs); - addWindowMediaEventProps(action.wmd, props); - - controls[page.id] = page.copyWith(attrs: pageAttrs); - action.backend.updateControlState("page", props, client: false); - action.backend - .triggerControlEvent("page", "window_event", action.eventName); - } - - return state.copyWith(controls: controls); - } else if (action is PageBrightnessChangeAction) { - // - // platform brightness changed - // - debugPrint("New platform brightness: ${action.brightness.name}"); - - var page = state.controls["page"]; - var controls = Map.of(state.controls); - if (page != null && !state.isLoading) { - var pageAttrs = Map.of(page.attrs); - pageAttrs["platformBrightness"] = action.brightness.name.toString(); - - controls[page.id] = page.copyWith(attrs: pageAttrs); - action.backend.updateControlState( - "page", {"platformBrightness": action.brightness.name.toString()}, - client: false); - action.backend.triggerControlEvent("page", "platformBrightnessChange", - action.brightness.name.toString()); - } - return state.copyWith(displayBrightness: action.brightness); - } else if (action is PageMediaChangeAction) { - // - // page media changed - // - debugPrint("New page media: ${action.media}"); - - var page = state.controls["page"]; - var controls = Map.of(state.controls); - if (page != null && !state.isLoading) { - var pageAttrs = Map.of(page.attrs); - var mj = json.encode(action.media); - pageAttrs["media"] = mj; - - controls[page.id] = page.copyWith(attrs: pageAttrs); - action.backend.updateControlState("page", {"media": mj}, client: false); - action.backend.triggerControlEvent("page", "mediaChange", mj); - } - return state.copyWith(media: action.media); - } else if (action is RegisterWebClientAction) { - // - // register web client - // - if (action.payload.error != null && action.payload.error!.isNotEmpty) { - // error or inactive app - return state.copyWith( - isLoading: action.payload.appInactive, - reconnectDelayMs: 0, - error: action.payload.error); - } else { - final sessionId = action.payload.session!.id; - - // store sessionId in a cookie - SessionStore.sessionId = sessionId; - - if (state.deepLinkingRoute != "") { - debugPrint( - "Sending buffered deep link route: ${state.deepLinkingRoute}"); - sendRouteChangeEvent(action.backend, state.deepLinkingRoute); - } - - // connected to the session - return state.copyWith( - isLoading: false, - deepLinkingRoute: "", - reconnectDelayMs: 0, - sessionId: sessionId, - error: "", - controls: action.payload.session!.controls); - } - } else if (action is PageReconnectingAction) { - // - // reconnecting WebSocket - // - return state.copyWith( - isLoading: true, - error: "", //action.connectMessage, - reconnectDelayMs: action.nextReconnectDelayMs); - } else if (action is AppBecomeActiveAction) { - // - // app become active - // - action.server.registerWebClientInternal(); - return state.copyWith(error: ""); - } else if (action is AppBecomeInactiveAction) { - // - // app become inactive - // - return state.copyWith(isLoading: true, error: ""); - } else if (action is SessionCrashedAction) { - // - // session crashed - // - return state.copyWith(error: action.payload.message); - } else if (action is InvokeMethodAction) { - debugPrint( - "InvokeMethodAction: ${action.payload.methodName} (controlId: ${action.payload.controlId}) (${action.payload.args})"); - - sendMethodResult({String? result, String? error}) { - action.server.triggerControlEvent( - "page", - "invoke_method_result", - json.encode(InvokeMethodResult( - methodId: action.payload.methodId, - result: result, - error: error))); - } - - if (action.payload.controlId != "") { - // control-specific method - var handler = - action.server.controlInvokeMethods[action.payload.controlId]; - debugPrint("Invoke method handler: $handler"); - if (handler != null) { - handler(action.payload.methodName, action.payload.args) - .then((result) => sendMethodResult(result: result.toString())) - .onError((error, stackTrace) => - sendMethodResult(error: error.toString())); - } - } else { - // global methods - switch (action.payload.methodName) { - case "closeInAppWebView": - closeInAppWebView(); - break; - case "launchUrl": - openWebBrowser(action.payload.args["url"]!, - webWindowName: action.payload.args["web_window_name"], - webPopupWindow: - action.payload.args["web_popup_window"]?.toLowerCase() == - "true", - windowWidth: - int.tryParse(action.payload.args["window_width"] ?? ""), - windowHeight: - int.tryParse(action.payload.args["window_height"] ?? "")); - break; - case "canLaunchUrl": - canLaunchUrl(Uri.parse(action.payload.args["url"]!)) - .then((result) => sendMethodResult(result: result.toString())); - break; - case "setClipboard": - String? data = action.payload.args["data"]; - if (data != null) { - try { - setClipboard(data); - } catch (e) { - sendMethodResult(error: e.toString()); - } - } - break; - case "getClipboard": - getClipboard() - .then((value) => sendMethodResult(result: value)) - .onError((error, stackTrace) => - sendMethodResult(error: error?.toString())); - break; - case "enableBrowserContextMenu": - enableBrowserContextMenu().onError((error, stackTrace) => - sendMethodResult(error: error?.toString())); - break; - case "disableBrowserContextMenu": - disableBrowserContextMenu().onError((error, stackTrace) => - sendMethodResult(error: error?.toString())); - break; - case "windowToFront": - windowToFront(); - break; - case "windowStartDragging": - windowStartDragging(); - break; - } - var clientStoragePrefix = "clientStorage:"; - if (action.payload.methodName.startsWith(clientStoragePrefix)) { - invokeClientStorage( - action.payload.methodId, - action.payload.methodName.substring(clientStoragePrefix.length), - action.payload.args, - action.server); - } - } - } else if (action is AddPageControlsAction) { - // - // add controls - // - var controls = Map.of(state.controls); - addControls(controls, action.payload.controls); - removeControls(controls, action.payload.trimIDs); - return state.copyWith(controls: controls); - } else if (action is ReplacePageControlsAction) { - // - // replace controls - // - var controls = Map.of(state.controls); - if (action.payload.remove) { - removeControls(controls, action.payload.ids); - } else { - cleanControls(controls, action.payload.ids); - } - addControls(controls, action.payload.controls); - return state.copyWith(controls: controls); - } else if (action is PageControlsBatchAction) { - // - // batch of commands - // - var controls = Map.of(state.controls); - for (var message in action.payload.messages) { - if (message.action == MessageAction.addPageControls) { - var payload = AddPageControlsPayload.fromJson(message.payload); - addControls(controls, payload.controls); - removeControls(controls, payload.trimIDs); - } else if (message.action == MessageAction.updateControlProps) { - var payload = UpdateControlPropsPayload.fromJson(message.payload); - changeProps(controls, payload.props); - } else if (message.action == MessageAction.cleanControl) { - var payload = CleanControlPayload.fromJson(message.payload); - cleanControls(controls, payload.ids); - } else if (message.action == MessageAction.removeControl) { - var payload = RemoveControlPayload.fromJson(message.payload); - removeControls(controls, payload.ids); - } - } - return state.copyWith(controls: controls); - } else if (action is UpdateControlPropsAction) { - // - // update control props - // - var controls = Map.of(state.controls); - changeProps(controls, action.payload.props); - return state.copyWith(controls: controls); - } else if (action is AppendControlPropsAction) { - // - // append control props - // - var controls = Map.of(state.controls); - appendProps(controls, action.payload.props); - return state.copyWith(controls: controls); - } else if (action is CleanControlAction) { - // - // clean controls - // - var controls = Map.of(state.controls); - cleanControls(controls, action.payload.ids); - return state.copyWith(controls: controls); - } else if (action is RemoveControlAction) { - // - // remove controls - // - var controls = Map.of(state.controls); - removeControls(controls, action.payload.ids); - return state.copyWith(controls: controls); - } - - return state; -} - -addWindowMediaEventProps(WindowMediaData wmd, Map props) { - props["windowwidth"] = wmd.width != null ? wmd.width.toString() : ""; - props["windowheight"] = wmd.height != null ? wmd.height.toString() : ""; - props["windowtop"] = wmd.top != null ? wmd.top.toString() : ""; - props["windowleft"] = wmd.left != null ? wmd.left.toString() : ""; - props["windowminimized"] = - wmd.isMinimized != null ? wmd.isMinimized.toString() : ""; - props["windowmaximized"] = - wmd.isMaximized != null ? wmd.isMaximized.toString() : ""; - props["windowfocused"] = - wmd.isFocused != null ? wmd.isFocused.toString() : ""; - props["windowfullscreen"] = - wmd.isFullScreen != null ? wmd.isFullScreen.toString() : ""; -} - -addControls(Map controls, List newControls) { - String firstParentId = ""; - for (var ctrl in newControls) { - if (firstParentId == "") { - firstParentId = ctrl.pid; - } - - final existingControl = controls[ctrl.id]; - controls[ctrl.id] = ctrl; - if (existingControl != null) { - controls[ctrl.id] = - ctrl.copyWith(childIds: List.from(existingControl.childIds)); - } - - if (ctrl.pid == firstParentId && existingControl == null) { - // root control - final parentCtrl = controls[ctrl.pid]!; - if (ctrl.attrs["at"] == null) { - // append to the end - controls[parentCtrl.id] = parentCtrl.copyWith( - childIds: List.from(parentCtrl.childIds)..add(ctrl.id)); - } else { - // insert at specified position - controls[parentCtrl.id] = parentCtrl.copyWith( - childIds: List.from(parentCtrl.childIds) - ..insert(int.parse(ctrl.attrs["at"]!), ctrl.id)); - } - } - } -} - -changeProps(Map controls, List> allProps) { - for (var props in allProps) { - final ctrl = controls[props["i"]]; - if (ctrl != null) { - var attrs = Map.of(ctrl.attrs); - for (var propName in props.keys) { - if (propName == "i") { - continue; - } - var v = props[propName]; - if (v == null || v == "") { - attrs.remove(propName); - } else { - attrs[propName] = v; - } - } - controls[ctrl.id] = ctrl.copyWith(attrs: attrs); - } - } -} - -appendProps(Map controls, List> allProps) { - for (var props in allProps) { - final ctrl = controls[props["i"]]; - if (ctrl != null) { - var attrs = Map.of(ctrl.attrs); - for (var propName in props.keys) { - if (propName == "i") { - continue; - } - var v = props[propName] ?? ""; - attrs[propName] = v + (props[propName] ?? ""); - } - controls[ctrl.id] = ctrl.copyWith(attrs: attrs); - } - } -} - -cleanControls(Map controls, List ids) { - for (var id in ids) { - // remove all children - final descendantIds = getAllDescendantIds(controls, id); - for (var descendantId in descendantIds) { - controls.remove(descendantId); - } - - // cleanup children collection - controls[id] = controls[id]!.copyWith(childIds: []); - } -} - -removeControls(Map controls, List ids) { - for (var id in ids) { - final ctrl = controls[id]; - - // remove all children - final descendantIds = getAllDescendantIds(controls, id); - for (var descendantId in descendantIds) { - controls.remove(descendantId); - } - - // delete control itself - if (ctrl != null) { - for (var handler in ctrl.onRemove) { - handler(); - } - } - controls.remove(id); - - // remove control's ID from parent's children collection - final parentCtrl = controls[ctrl!.pid]; - controls[parentCtrl!.id] = parentCtrl.copyWith( - childIds: - parentCtrl.childIds.where((childId) => childId != id).toList()); - } -} - -List getAllDescendantIds(Map controls, String id) { - if (controls[id] != null) { - List childIds = []; - for (String childId in controls[id]!.childIds) { - childIds - ..add(childId) - ..addAll(getAllDescendantIds(controls, childId)); - } - return childIds; - } - return []; -} - -void sendRouteChangeEvent(FletControlBackend backend, String route) { - backend.updateControlState("page", {"route": route}, client: false); - backend.triggerControlEvent("page", "route_change", route); -} diff --git a/packages/flet/lib/src/routing/deep_linking_bootstrap.dart b/packages/flet/lib/src/routing/deep_linking_bootstrap.dart new file mode 100644 index 0000000000..2aea82a822 --- /dev/null +++ b/packages/flet/lib/src/routing/deep_linking_bootstrap.dart @@ -0,0 +1,72 @@ +import 'package:flutter/widgets.dart'; + +/// Captures cold-start deep links delivered before Flet's `*.router` app is +/// mounted, and replays them as the initial route once the router is ready. +/// +/// Usage in a host app (before `runApp()`): +/// `FletDeepLinkingBootstrap.install();` +class FletDeepLinkingBootstrap { + static final _observer = _FletDeepLinkObserver(); + static bool _installed = false; + + static RouteInformation? _pendingInitialRouteInformation; + + /// Installs a `WidgetsBindingObserver` as early as possible (ideally right + /// after `WidgetsFlutterBinding.ensureInitialized()`). + static void install() { + if (_installed) return; + WidgetsFlutterBinding.ensureInitialized(); + WidgetsBinding.instance.addObserver(_observer); + _installed = true; + } + + /// Called by Flet once its Router (`MaterialApp.router`/`CupertinoApp.router`) + /// is ready to receive route updates. + static void markRouterReady() { + if (!_installed) return; + WidgetsBinding.instance.removeObserver(_observer); + _installed = false; + } + + static RouteInformation? takePendingInitialRouteInformation() { + final value = _pendingInitialRouteInformation; + _pendingInitialRouteInformation = null; + return value; + } + + static bool _capture(RouteInformation routeInformation) { + // Only capture the first pending route to avoid swallowing later deep links + // that the host app might want to handle while Flet isn't mounted yet. + if (_pendingInitialRouteInformation != null) { + return false; + } + + final uri = routeInformation.uri; + if (uri.toString().isEmpty) { + return false; + } + + _pendingInitialRouteInformation = routeInformation; + return true; + } +} + +class _FletDeepLinkObserver with WidgetsBindingObserver { + @override + Future didPushRouteInformation( + RouteInformation routeInformation, + ) async { + // Returning true prevents iOS from logging: + // "Failed to handle route information in Flutter." + return FletDeepLinkingBootstrap._capture(routeInformation); + } + + @override + Future didPushRoute(String route) async { + final uri = Uri.tryParse(route); + if (uri == null) { + return false; + } + return FletDeepLinkingBootstrap._capture(RouteInformation(uri: uri)); + } +} diff --git a/packages/flet/lib/src/routing/route_information_provider.dart b/packages/flet/lib/src/routing/route_information_provider.dart new file mode 100644 index 0000000000..12462f81de --- /dev/null +++ b/packages/flet/lib/src/routing/route_information_provider.dart @@ -0,0 +1,65 @@ +import 'package:flutter/widgets.dart'; + +/// Normalizes external URIs (e.g. `flet://flet-host/aaa`) into the path-based +/// form used by Flet routing (e.g. `/aaa`). +class FletRouteInformationProvider extends PlatformRouteInformationProvider { + FletRouteInformationProvider({ + required super.initialRouteInformation, + }); + + static RouteInformation normalize(RouteInformation routeInformation) { + final uri = routeInformation.uri; + return RouteInformation( + uri: Uri( + path: uri.path.isEmpty ? '/' : uri.path, + query: uri.hasQuery ? uri.query : null, + fragment: uri.hasFragment ? uri.fragment : null, + ), + state: routeInformation.state, + ); + } + + @override + Future didPushRouteInformation(RouteInformation routeInformation) { + final normalized = normalize(routeInformation); + debugPrint( + "FletRouteInformationProvider.didPushRouteInformation: ${routeInformation.uri} -> ${normalized.uri}"); + return super.didPushRouteInformation(normalized); + } +} + +class FletLocalRouteInformationProvider extends RouteInformationProvider + with ChangeNotifier { + RouteInformation _value; + + FletLocalRouteInformationProvider({ + required RouteInformation initialRouteInformation, + }) : _value = FletRouteInformationProvider.normalize( + initialRouteInformation, + ); + + @override + RouteInformation get value => _value; + + @override + void routerReportsNewRouteInformation( + RouteInformation routeInformation, { + RouteInformationReportingType type = RouteInformationReportingType.none, + }) { + _setValue(routeInformation); + } + + Future didPushRouteInformation(RouteInformation routeInformation) async { + _setValue(routeInformation); + return true; + } + + void _setValue(RouteInformation routeInformation) { + final normalized = FletRouteInformationProvider.normalize(routeInformation); + if (_value.uri == normalized.uri && _value.state == normalized.state) { + return; + } + _value = normalized; + notifyListeners(); + } +} diff --git a/packages/flet/lib/src/routing/route_state.dart b/packages/flet/lib/src/routing/route_state.dart index 0fc61a2961..869e437fe1 100644 --- a/packages/flet/lib/src/routing/route_state.dart +++ b/packages/flet/lib/src/routing/route_state.dart @@ -19,7 +19,6 @@ class RouteState extends ChangeNotifier { if (_route == route) return; _route = route; - debugPrint("Route changed to: $route"); notifyListeners(); } diff --git a/packages/flet/lib/src/routing/router_delegate.dart b/packages/flet/lib/src/routing/router_delegate.dart index 9b389e6ec7..3f8d557bc1 100644 --- a/packages/flet/lib/src/routing/router_delegate.dart +++ b/packages/flet/lib/src/routing/router_delegate.dart @@ -7,6 +7,7 @@ class SimpleRouterDelegate extends RouterDelegate with ChangeNotifier, PopNavigatorRouterDelegateMixin { final RouteState routeState; final WidgetBuilder builder; + final Future Function()? popRouteHandler; @override final GlobalKey navigatorKey; @@ -15,6 +16,7 @@ class SimpleRouterDelegate extends RouterDelegate required this.routeState, required this.builder, required this.navigatorKey, + this.popRouteHandler, }) { routeState.addListener(notifyListeners); } @@ -33,6 +35,18 @@ class SimpleRouterDelegate extends RouterDelegate return routeState.route; } + @override + Future popRoute() async { + final handler = popRouteHandler; + if (handler != null) { + final result = await handler(); + if (result != null) { + return result; + } + } + return super.popRoute(); + } + @override void dispose() { routeState.removeListener(notifyListeners); diff --git a/packages/flet/lib/src/services/accelerometer.dart b/packages/flet/lib/src/services/accelerometer.dart new file mode 100644 index 0000000000..3c35ac309b --- /dev/null +++ b/packages/flet/lib/src/services/accelerometer.dart @@ -0,0 +1,22 @@ +import 'package:sensors_plus/sensors_plus.dart'; + +import 'base_sensor.dart'; + +class AccelerometerService extends BaseSensorService { + AccelerometerService({required super.control}); + + @override + Stream sensorStream(Duration samplingPeriod) { + return accelerometerEventStream(samplingPeriod: samplingPeriod); + } + + @override + Map serializeEvent(AccelerometerEvent event) { + return { + "x": event.x, + "y": event.y, + "z": event.z, + "timestamp": event.timestamp, + }; + } +} diff --git a/packages/flet/lib/src/services/barometer.dart b/packages/flet/lib/src/services/barometer.dart new file mode 100644 index 0000000000..af99a0c40c --- /dev/null +++ b/packages/flet/lib/src/services/barometer.dart @@ -0,0 +1,20 @@ +import 'package:sensors_plus/sensors_plus.dart'; + +import 'base_sensor.dart'; + +class BarometerService extends BaseSensorService { + BarometerService({required super.control}); + + @override + Stream sensorStream(Duration samplingPeriod) { + return barometerEventStream(samplingPeriod: samplingPeriod); + } + + @override + Map serializeEvent(BarometerEvent event) { + return { + "pressure": event.pressure, + "timestamp": event.timestamp, + }; + } +} diff --git a/packages/flet/lib/src/services/base_sensor.dart b/packages/flet/lib/src/services/base_sensor.dart new file mode 100644 index 0000000000..f7b4831c4e --- /dev/null +++ b/packages/flet/lib/src/services/base_sensor.dart @@ -0,0 +1,104 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:sensors_plus/sensors_plus.dart'; + +import '../flet_service.dart'; +import '../utils/numbers.dart'; +import '../utils/time.dart'; + +abstract class BaseSensorService extends FletService { + BaseSensorService({required super.control}); + + StreamSubscription? _subscription; + bool _enabled = true; + bool _hasReadingSubscribers = false; + bool _hasErrorSubscribers = false; + Duration _interval = SensorInterval.normalInterval; + bool _cancelOnError = true; + + Duration get defaultInterval => SensorInterval.normalInterval; + + String get eventName => "reading"; + + Stream sensorStream(Duration samplingPeriod); + + Map serializeEvent(T event); + + @override + void init() { + super.init(); + _updateConfig(forceRestart: true); + } + + @override + void update() { + _updateConfig(); + } + + void _updateConfig({bool forceRestart = false}) { + var enabled = control.getBool("enabled", true) ?? true; + var interval = + control.getDuration("interval", defaultInterval) ?? defaultInterval; + if (interval.isNegative) { + interval = defaultInterval; + } + var hasReadingSubscribers = control.getBool("on_$eventName") == true; + var hasErrorSubscribers = control.getBool("on_error") == true; + var cancelOnError = control.getBool("cancel_on_error", true) ?? true; + + if (forceRestart || + enabled != _enabled || + interval != _interval || + hasReadingSubscribers != _hasReadingSubscribers || + hasErrorSubscribers != _hasErrorSubscribers || + cancelOnError != _cancelOnError) { + _enabled = enabled; + _interval = interval; + _hasReadingSubscribers = hasReadingSubscribers; + _hasErrorSubscribers = hasErrorSubscribers; + _cancelOnError = cancelOnError; + _restart(); + } + } + + void _restart() { + _subscription?.cancel(); + _subscription = null; + + if (!_enabled || (!_hasReadingSubscribers && !_hasErrorSubscribers)) { + return; + } + + final samplingPeriod = _interval; + try { + _subscription = sensorStream(samplingPeriod).listen( + (event) { + if (_hasReadingSubscribers) { + final payload = serializeEvent(event); + control.triggerEvent(eventName, payload); + } + }, + onError: (error, stackTrace) { + if (_hasErrorSubscribers) { + control.triggerEvent("error", + {"message": error?.toString() ?? "Unknown sensor error"}); + } else { + debugPrint( + "Error listening to ${control.type} sensor stream: $error"); + } + }, + cancelOnError: _cancelOnError, + ); + } catch (error) { + debugPrint("Failed to initialize ${control.type} sensor stream: $error"); + } + } + + @override + void dispose() { + _subscription?.cancel(); + _subscription = null; + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/battery.dart b/packages/flet/lib/src/services/battery.dart new file mode 100644 index 0000000000..86702986be --- /dev/null +++ b/packages/flet/lib/src/services/battery.dart @@ -0,0 +1,70 @@ +import 'dart:async'; + +import 'package:battery_plus/battery_plus.dart'; +import 'package:flutter/foundation.dart'; + +import '../flet_service.dart'; +import '../utils/numbers.dart'; + +class BatteryService extends FletService { + final Battery _battery = Battery(); + StreamSubscription? _stateSub; + + BatteryService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("BatteryService(${control.id}).init"); + control.addInvokeMethodListener(_invokeMethod); + _updateListeners(); + } + + @override + void update() { + _updateListeners(); + } + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "get_battery_level": + try { + return await _battery.batteryLevel; + } catch (e) { + debugPrint( + "BatteryService.get_battery_level: unavailable battery level ($e)"); + return null; + } + case "get_battery_state": + final state = await _battery.batteryState; + return state.name; + case "is_in_battery_save_mode": + return _battery.isInBatterySaveMode; + default: + throw Exception("Unknown Battery method: $name"); + } + } + + void _updateListeners() { + final listenState = control.getBool("on_state_change") == true; + if (listenState && _stateSub == null) { + _stateSub = _battery.onBatteryStateChanged.listen((state) { + control.triggerEvent("state_change", {"state": state.name}); + }, onError: (error) { + debugPrint("BatteryService: error listening to state changes: $error"); + }); + } else if (!listenState && _stateSub != null) { + _stateSub?.cancel(); + _stateSub = null; + } + } + + @override + void dispose() { + debugPrint("BatteryService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + _stateSub?.cancel(); + _stateSub = null; + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/browser_context_menu.dart b/packages/flet/lib/src/services/browser_context_menu.dart new file mode 100644 index 0000000000..3915a94b8c --- /dev/null +++ b/packages/flet/lib/src/services/browser_context_menu.dart @@ -0,0 +1,41 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; + +import '../flet_service.dart'; + +class BrowserContextMenuService extends FletService { + BrowserContextMenuService({required super.control}); + + @override + void init() { + super.init(); + debugPrint( + "BrowserContextMenuService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void update() { + debugPrint( + "BrowserContextMenuService(${control.id}).update: ${control.properties}"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("BrowserContextMenuService.$name($args)"); + switch (name) { + case "disable_menu": + return BrowserContextMenu.disableContextMenu(); + case "enable_menu": + return BrowserContextMenu.enableContextMenu(); + default: + throw Exception("Unknown BrowserContextMenu method: $name"); + } + } + + @override + void dispose() { + debugPrint("BrowserContextMenuService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/clipboard.dart b/packages/flet/lib/src/services/clipboard.dart new file mode 100644 index 0000000000..9fd464f2ff --- /dev/null +++ b/packages/flet/lib/src/services/clipboard.dart @@ -0,0 +1,55 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:pasteboard/pasteboard.dart'; + +import '../flet_service.dart'; +import '../utils/images.dart'; + +class ClipboardService extends FletService { + ClipboardService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("ClipboardService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void update() { + debugPrint("ClipboardService(${control.id}).update: ${control.properties}"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("ClipboardService.$name($args)"); + switch (name) { + case "set": + await Clipboard.setData(ClipboardData(text: args["data"])); + return; + case "get": + var data = await Clipboard.getData(Clipboard.kTextPlain); + return data?.text; + case "set_image": + await Pasteboard.writeImage(convertToUint8List(args["data"])); + return; + case "get_image": + return await Pasteboard.image; + case "set_files": + final files = (args["files"] as List) + .map((f) => f.toString()) + .toList(growable: false); + return await Pasteboard.writeFiles(files); + case "get_files": + return await Pasteboard.files(); + default: + throw Exception("Unknown Clipboard method: $name"); + } + } + + @override + void dispose() { + debugPrint("ClipboardService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/connectivity.dart b/packages/flet/lib/src/services/connectivity.dart new file mode 100644 index 0000000000..1fabe03b96 --- /dev/null +++ b/packages/flet/lib/src/services/connectivity.dart @@ -0,0 +1,63 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:flutter/foundation.dart'; + +import '../flet_service.dart'; +import '../utils/numbers.dart'; + +class ConnectivityService extends FletService { + final Connectivity _connectivity = Connectivity(); + StreamSubscription>? _subscription; + + ConnectivityService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("ConnectivityService(${control.id}).init"); + control.addInvokeMethodListener(_invokeMethod); + _updateListeners(); + } + + @override + void update() { + _updateListeners(); + } + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "get_connectivity": + final results = await _connectivity.checkConnectivity(); + return results.map((r) => r.name).toList(); + default: + throw Exception("Unknown Connectivity method: $name"); + } + } + + void _updateListeners() { + final listenChange = control.getBool("on_change") == true; + if (listenChange && _subscription == null) { + _subscription = _connectivity.onConnectivityChanged.listen( + (List result) { + control.triggerEvent( + "change", {"connectivity": result.map((r) => r.name).toList()}); + }, onError: (error) { + debugPrint( + "ConnectivityService: error listening to connectivity: $error"); + }); + } else if (!listenChange && _subscription != null) { + _subscription?.cancel(); + _subscription = null; + } + } + + @override + void dispose() { + debugPrint("ConnectivityService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + _subscription?.cancel(); + _subscription = null; + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/file_picker.dart b/packages/flet/lib/src/services/file_picker.dart new file mode 100644 index 0000000000..609ba20284 --- /dev/null +++ b/packages/flet/lib/src/services/file_picker.dart @@ -0,0 +1,201 @@ +import 'package:collection/collection.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart' as http; + +import '../flet_service.dart'; +import '../utils/file_picker.dart'; +import '../utils/numbers.dart'; +import '../utils/platform.dart'; + +class FilePickerService extends FletService { + FilePickerService({required super.control}); + + List? _files; + + @override + void init() { + super.init(); + debugPrint("FilePickerService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + debugPrint("FilePickerService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("FilePicker.$name($args)"); + var dialogTitle = args["dialog_title"]; + var fileType = parseFileType(args["file_type"], FileType.any)!; + var initialDirectory = args["initial_directory"]; + var allowedExtensions = (args["allowed_extensions"] as List?) + ?.map((e) => e.toString()) + .toList(); + var withData = parseBool(args["with_data"], false)!; + var srcBytes = args["src_bytes"]; + + if (allowedExtensions != null && allowedExtensions.isNotEmpty) { + fileType = FileType.custom; + } + switch (name) { + case "upload": + var files = args["files"]; + if (files != null && _files != null) { + uploadFiles(files, control.backend.pageUri); + } + case "pick_files": + _files = (await FilePicker.platform.pickFiles( + dialogTitle: dialogTitle, + initialDirectory: initialDirectory, + lockParentWindow: true, + type: fileType, + allowedExtensions: allowedExtensions, + allowMultiple: args["allow_multiple"], + withData: withData, + withReadStream: !withData)) + ?.files; + return _files != null + ? _files!.asMap().entries.map((file) { + return FilePickerFile( + id: file.key, // use entry's index as id + name: file.value.name, + path: kIsWeb ? null : file.value.path, + size: file.value.size, + bytes: withData ? file.value.bytes : null) + .toMap(); + }).toList() + : []; + case "save_file": + if ((kIsWeb || isAndroidMobile() || isIOSMobile()) && + srcBytes == null) { + throw Exception( + "\"src_bytes\" is required when saving a file on Web, Android and iOS."); + } + if (kIsWeb && args["file_name"] == null) { + throw Exception( + "\"file_name\" is required when saving a file on Web."); + } + return await FilePicker.platform.saveFile( + dialogTitle: dialogTitle, + fileName: args["file_name"] != null || !isIOSMobile() + ? args["file_name"] + : "new-file", + initialDirectory: initialDirectory, + lockParentWindow: true, + type: fileType, + allowedExtensions: allowedExtensions, + bytes: srcBytes); + case "get_directory_path": + if (kIsWeb) { + throw Exception("Get Directory Path dialog is not supported on web."); + } + return await FilePicker.platform.getDirectoryPath( + dialogTitle: dialogTitle, + initialDirectory: initialDirectory, + lockParentWindow: true, + ); + default: + throw Exception("Unknown FilePicker method: $name"); + } + } + + Future uploadFiles(List files, Uri pageUri) async { + var uploadFiles = files.map((u) => FilePickerUploadFile( + id: u["id"], + name: u["name"], + uploadUrl: u["upload_url"], + method: u["method"])); + + for (var uf in uploadFiles) { + var file = ((uf.id != null && uf.id! >= 0 && uf.id! < _files!.length) + ? _files![uf.id!] + : null) // by id + ?? + _files!.firstWhereOrNull((f) => f.name == uf.name); // by name + + if (file != null) { + try { + await uploadFile( + file, getFullUploadUrl(pageUri, uf.uploadUrl), uf.method); + _files!.remove(file); // Remove the uploaded file + } catch (e) { + sendProgress(file.name, null, e.toString()); + } + } else { + debugPrint( + "FilePicker Error: File '${uf.name}' (id: ${uf.id}) not found."); + } + } + } + + Future uploadFile(PlatformFile file, String uploadUrl, String method) async { + final fileReadStream = file.readStream; + if (fileReadStream == null) { + throw Exception('Cannot read file from null stream'); + } + debugPrint("Uploading ${file.name}"); + final streamedRequest = http.StreamedRequest(method, Uri.parse(uploadUrl)) + ..headers.addAll({ + //'Cache-Control': 'no-cache', + }); + streamedRequest.contentLength = file.size; + + // send 0% + sendProgress(file.name, 0, null); + + double lastSent = 0; // send every 10% + double progress = 0; + int bytesSent = 0; + fileReadStream.listen((chunk) async { + //debugPrint(chunk.length); + streamedRequest.sink.add(chunk); + bytesSent += chunk.length; + progress = bytesSent / file.size; + if (progress >= lastSent) { + lastSent += 0.1; + if (progress != 1.0) { + sendProgress(file.name, progress, null); + } + } + }, onDone: () { + streamedRequest.sink.close(); + }); + + var streamedResponse = await streamedRequest.send(); + var response = await http.Response.fromStream(streamedResponse); + if (response.statusCode < 200 || response.statusCode > 204) { + sendProgress(file.name, null, + "Upload endpoint returned code ${response.statusCode}: ${response.body}"); + } else { + // send 100% + sendProgress(file.name, progress, null); + } + } + + void sendProgress(String name, double? progress, String? error) { + control.triggerEvent( + "upload", + FilePickerUploadProgressEvent( + name: name, progress: progress, error: error) + .toMap()); + } + + String getFullUploadUrl(Uri pageUri, String uploadUrl) { + Uri uploadUri = Uri.parse(uploadUrl); + if (!uploadUri.hasAuthority) { + return Uri( + scheme: pageUri.scheme, + host: pageUri.host, + port: pageUri.port, + path: uploadUri.path, + query: uploadUri.query) + .toString(); + } else { + return uploadUrl; + } + } +} diff --git a/packages/flet/lib/src/services/gyroscope.dart b/packages/flet/lib/src/services/gyroscope.dart new file mode 100644 index 0000000000..5cb95f4670 --- /dev/null +++ b/packages/flet/lib/src/services/gyroscope.dart @@ -0,0 +1,22 @@ +import 'package:sensors_plus/sensors_plus.dart'; + +import 'base_sensor.dart'; + +class GyroscopeService extends BaseSensorService { + GyroscopeService({required super.control}); + + @override + Stream sensorStream(Duration samplingPeriod) { + return gyroscopeEventStream(samplingPeriod: samplingPeriod); + } + + @override + Map serializeEvent(GyroscopeEvent event) { + return { + "x": event.x, + "y": event.y, + "z": event.z, + "timestamp": event.timestamp, + }; + } +} diff --git a/packages/flet/lib/src/services/haptic_feedback.dart b/packages/flet/lib/src/services/haptic_feedback.dart new file mode 100644 index 0000000000..02ee8217b3 --- /dev/null +++ b/packages/flet/lib/src/services/haptic_feedback.dart @@ -0,0 +1,52 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; + +import '../flet_service.dart'; + +class HapticFeedbackService extends FletService { + HapticFeedbackService({required super.control}); + + @override + void init() { + super.init(); + debugPrint( + "HapticFeedbackService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void update() { + debugPrint( + "HapticFeedbackService(${control.id}).update: ${control.properties}"); + } + + @override + void dispose() { + debugPrint("HapticFeedbackService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("HapticFeedbackService.$name($args)"); + switch (name) { + case "heavy_impact": + await HapticFeedback.heavyImpact(); + break; + case "light_impact": + await HapticFeedback.lightImpact(); + break; + case "medium_impact": + await HapticFeedback.mediumImpact(); + break; + case "vibrate": + await HapticFeedback.vibrate(); + break; + case "selection_click": + await HapticFeedback.selectionClick(); + break; + default: + throw Exception("Unknown HapticFeedback method: $name"); + } + } +} diff --git a/packages/flet/lib/src/services/magnetometer.dart b/packages/flet/lib/src/services/magnetometer.dart new file mode 100644 index 0000000000..6d6124bde6 --- /dev/null +++ b/packages/flet/lib/src/services/magnetometer.dart @@ -0,0 +1,22 @@ +import 'package:sensors_plus/sensors_plus.dart'; + +import 'base_sensor.dart'; + +class MagnetometerService extends BaseSensorService { + MagnetometerService({required super.control}); + + @override + Stream sensorStream(Duration samplingPeriod) { + return magnetometerEventStream(samplingPeriod: samplingPeriod); + } + + @override + Map serializeEvent(MagnetometerEvent event) { + return { + "x": event.x, + "y": event.y, + "z": event.z, + "timestamp": event.timestamp, + }; + } +} diff --git a/packages/flet/lib/src/services/screen_brightness.dart b/packages/flet/lib/src/services/screen_brightness.dart new file mode 100644 index 0000000000..9b1b3ce290 --- /dev/null +++ b/packages/flet/lib/src/services/screen_brightness.dart @@ -0,0 +1,134 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:screen_brightness/screen_brightness.dart'; + +import '../flet_service.dart'; +import '../utils/numbers.dart'; +import '../utils/platform.dart'; + +class ScreenBrightnessService extends FletService { + final ScreenBrightness _screenBrightness = ScreenBrightness(); + StreamSubscription? _systemSubscription; + StreamSubscription? _applicationSubscription; + + ScreenBrightnessService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("ScreenBrightnessService(${control.id}).init"); + control.addInvokeMethodListener(_invokeMethod); + _updateListeners(); + } + + @override + void update() { + _updateListeners(); + } + + Future _invokeMethod(String name, dynamic args) async { + if (isWebPlatform()) { + return null; + } + + switch (name) { + case "get_system_screen_brightness": + return _screenBrightness.system; + case "can_change_system_screen_brightness": + return _screenBrightness.canChangeSystemBrightness; + case "set_system_screen_brightness": + final brightness = parseDouble(args["value"]); + if (brightness == null) { + throw ArgumentError.notNull("value"); + } + return _screenBrightness.setSystemScreenBrightness(brightness); + case "get_application_screen_brightness": + return _screenBrightness.application; + case "set_application_screen_brightness": + final brightness = parseDouble(args["value"]); + if (brightness == null) { + throw ArgumentError.notNull("value"); + } + return _screenBrightness.setApplicationScreenBrightness(brightness); + case "reset_application_screen_brightness": + return _screenBrightness.resetApplicationScreenBrightness(); + case "is_animate": + return _screenBrightness.isAnimate; + case "set_animate": + final isAnimate = parseBool(args["value"]); + if (isAnimate == null) { + throw ArgumentError.notNull("value"); + } + return _screenBrightness.setAnimate(isAnimate); + case "is_auto_reset": + return _screenBrightness.isAutoReset; + case "set_auto_reset": + final isAutoReset = parseBool(args["value"]); + if (isAutoReset == null) { + throw ArgumentError.notNull("value"); + } + return _screenBrightness.setAutoReset(isAutoReset); + default: + throw Exception("Unknown ScreenBrightness method: $name"); + } + } + + void _updateListeners() { + if (isWebPlatform()) { + _disposeSubscriptions(); + return; + } + + final listenSystem = + control.getBool("on_system_screen_brightness_change") == true; + final listenApplication = + control.getBool("on_application_screen_brightness_change") == true; + + if (listenSystem && _systemSubscription == null) { + _systemSubscription = _screenBrightness.onSystemScreenBrightnessChanged + .listen((value) { + control.triggerEvent( + "system_screen_brightness_change", {"brightness": value}); + }, onError: (error) { + debugPrint( + "ScreenBrightnessService: error listening for system changes: $error"); + }); + } else if (!listenSystem && _systemSubscription != null) { + _systemSubscription?.cancel(); + _systemSubscription = null; + } + + if (listenApplication && _applicationSubscription == null) { + _applicationSubscription = + _screenBrightness.onApplicationScreenBrightnessChanged.listen( + (value) { + control.triggerEvent( + "application_screen_brightness_change", {"brightness": value}); + }, + onError: (error) { + debugPrint( + "ScreenBrightnessService: error listening for application changes: $error"); + }, + ); + } else if (!listenApplication && _applicationSubscription != null) { + _applicationSubscription?.cancel(); + _applicationSubscription = null; + } + } + + void _disposeSubscriptions() { + _systemSubscription?.cancel(); + _systemSubscription = null; + _applicationSubscription?.cancel(); + _applicationSubscription = null; + } + + @override + void dispose() { + debugPrint("ScreenBrightnessService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + _disposeSubscriptions(); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/semantics_service.dart b/packages/flet/lib/src/services/semantics_service.dart new file mode 100644 index 0000000000..cc1a921831 --- /dev/null +++ b/packages/flet/lib/src/services/semantics_service.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/semantics.dart'; + +import '../flet_service.dart'; +import '../utils/misc.dart'; + +class SemanticsServiceControl extends FletService { + SemanticsServiceControl({required super.control}); + + @override + void init() { + super.init(); + debugPrint("SemanticsService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + debugPrint("SemanticsService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("SemanticsService.$name($args)"); + switch (name) { + case "announce_message": + var message = args["message"].toString(); + final view = WidgetsBinding.instance.platformDispatcher.implicitView; + if (view == null) { + return; + } + return SemanticsService.sendAnnouncement( + view, message, args["rtl"] ? TextDirection.rtl : TextDirection.ltr, + assertiveness: control.getAssertiveness( + args["assertiveness"], Assertiveness.polite)!); + case "announce_tooltip": + var message = args["message"].toString(); + return SemanticsService.tooltip(message); + case "get_accessibility_features": + var features = SemanticsBinding.instance.accessibilityFeatures; + return { + "accessible_navigation": features.accessibleNavigation, + "bold_text": features.boldText, + "disable_animations": features.disableAnimations, + "high_contrast": features.highContrast, + "invert_colors": features.invertColors, + "reduce_motion": features.reduceMotion, + "on_off_switch_labels": features.onOffSwitchLabels, + "supports_announcements": features.supportsAnnounce, + }; + default: + throw Exception("Unknown SemanticsService method: $name"); + } + } +} diff --git a/packages/flet/lib/src/services/service_binding.dart b/packages/flet/lib/src/services/service_binding.dart new file mode 100644 index 0000000000..e5527b3a19 --- /dev/null +++ b/packages/flet/lib/src/services/service_binding.dart @@ -0,0 +1,32 @@ +import '../flet_backend.dart'; +import '../flet_service.dart'; +import '../models/control.dart'; + +class ServiceBinding { + final Control control; + final FletBackend backend; + FletService? _service; + + ServiceBinding({required this.control, required this.backend}) { + for (var extension in backend.extensions) { + _service = extension.createService(control); + if (_service != null) { + break; + } + } + if (_service == null) { + throw Exception("Unknown service: ${control.type}"); + } + _service?.init(); + control.addListener(_onControlUpdated); + } + + void dispose() { + control.removeListener(_onControlUpdated); + _service?.dispose(); + } + + void _onControlUpdated() { + _service?.update(); + } +} diff --git a/packages/flet/lib/src/services/service_registry.dart b/packages/flet/lib/src/services/service_registry.dart new file mode 100644 index 0000000000..af57df691e --- /dev/null +++ b/packages/flet/lib/src/services/service_registry.dart @@ -0,0 +1,51 @@ +import 'package:flutter/cupertino.dart'; + +import '../flet_backend.dart'; +import '../models/control.dart'; +import 'service_binding.dart'; + +class ServiceRegistry { + final Control control; + final String propertyName; + final FletBackend backend; + final Map _services = {}; + + ServiceRegistry( + {required this.control, + required this.propertyName, + required this.backend}) { + debugPrint("Init service registry: ${control.id}"); + control.addListener(_onServicesUpdated); + _onServicesUpdated(); + } + + void _onServicesUpdated() { + var serviceControls = control.children(propertyName); + debugPrint("_onServicesUpdated(${serviceControls.length})"); + + // newly added services + for (var serviceControl in serviceControls) { + if (!_services.containsKey(serviceControl.id)) { + _services[serviceControl.id] = + ServiceBinding(control: serviceControl, backend: backend); + } + } + + // removed services + for (var serviceId in _services.keys.toList()) { + if (!serviceControls + .any((serviceControl) => serviceControl.id == serviceId)) { + _services[serviceId]!.dispose(); + _services.remove(serviceId); + } + } + } + + void dispose() { + control.removeListener(_onServicesUpdated); + for (var service in _services.values) { + service.dispose(); + } + _services.clear(); + } +} diff --git a/packages/flet/lib/src/services/shake_detector.dart b/packages/flet/lib/src/services/shake_detector.dart new file mode 100644 index 0000000000..a2d51ba329 --- /dev/null +++ b/packages/flet/lib/src/services/shake_detector.dart @@ -0,0 +1,124 @@ +import 'dart:async'; +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:sensors_plus/sensors_plus.dart'; + +import '../flet_service.dart'; +import '../utils/numbers.dart'; + +class ShakeDetectorService extends FletService { + ShakeDetectorService({required super.control}); + + StreamSubscription? _subscription; + + int _mShakeTimestamp = DateTime.now().millisecondsSinceEpoch; + int _mShakeCount = 0; + + int _minimumShakeCount = 1; + int _shakeSlopTimeMs = 500; + int _shakeCountResetTimeMs = 3000; + double _shakeThresholdGravity = 2.7; + + @override + void init() { + debugPrint("ShakeDetectorService(${control.id}).init()"); + super.init(); + update(); + } + + @override + void update() { + debugPrint( + "ShakeDetectorService(${control.id}).update: ${control.properties}"); + + var minimumShakeCount = control.getInt("minimum_shake_count", 1)!; + var shakeSlopTimeMs = control.getInt("shake_slop_time_ms", 500)!; + var shakeCountResetTimeMs = + control.getInt("shake_count_reset_time_ms", 3000)!; + var shakeThresholdGravity = + control.getDouble("shake_threshold_gravity", 2.7)!; + + // Update config if changed + if (minimumShakeCount != _minimumShakeCount || + shakeSlopTimeMs != _shakeSlopTimeMs || + shakeCountResetTimeMs != _shakeCountResetTimeMs || + shakeThresholdGravity != _shakeThresholdGravity) { + _minimumShakeCount = minimumShakeCount; + _shakeSlopTimeMs = shakeSlopTimeMs; + _shakeCountResetTimeMs = shakeCountResetTimeMs; + _shakeThresholdGravity = shakeThresholdGravity; + + _stopListening(); + _startListening(); + } + } + + void _startListening() { + _subscription = accelerometerEventStream().listen((event) { + final gX = event.x / 9.80665; + final gY = event.y / 9.80665; + final gZ = event.z / 9.80665; + + final gForce = sqrt(gX * gX + gY * gY + gZ * gZ); + + if (gForce > _shakeThresholdGravity) { + final now = DateTime.now().millisecondsSinceEpoch; + + if (_mShakeTimestamp + _shakeSlopTimeMs > now) { + return; + } + + if (_mShakeTimestamp + _shakeCountResetTimeMs < now) { + _mShakeCount = 0; + } + + _mShakeTimestamp = now; + _mShakeCount++; + + if (_mShakeCount >= _minimumShakeCount) { + control.triggerEvent("shake"); + } + } + }); + } + + void _stopListening() { + _subscription?.cancel(); + _subscription = null; + } + + @override + void dispose() { + debugPrint("ShakeDetectorService(${control.id}).dispose()"); + _stopListening(); + super.dispose(); + } +} + +/* +Source: https://github.com/dieringe/shake/blob/master/lib/shake.dart + +Copyright 2019 Deven Joshi + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. +*/ diff --git a/packages/flet/lib/src/services/share.dart b/packages/flet/lib/src/services/share.dart new file mode 100644 index 0000000000..6ca6ca87f5 --- /dev/null +++ b/packages/flet/lib/src/services/share.dart @@ -0,0 +1,189 @@ +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:path/path.dart' as p; +import 'package:share_plus/share_plus.dart'; + +import '../flet_service.dart'; +import '../utils/numbers.dart'; + +class ShareService extends FletService { + ShareService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("ShareService(${control.id}).init"); + control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "share_text": + return _share( + text: args["text"], + title: args["title"], + subject: args["subject"], + previewThumbnail: _parseShareFile(args["preview_thumbnail"]), + sharePositionOrigin: _parseRect(args["share_position_origin"]), + downloadFallbackEnabled: + parseBool(args["download_fallback_enabled"], true) ?? true, + mailToFallbackEnabled: + parseBool(args["mail_to_fallback_enabled"], true) ?? true, + excludedCupertinoActivities: _parseCupertinoActivityTypes( + args["excluded_cupertino_activities"]), + ); + case "share_uri": + return _share( + uri: args["uri"], + sharePositionOrigin: _parseRect(args["share_position_origin"]), + excludedCupertinoActivities: _parseCupertinoActivityTypes( + args["excluded_cupertino_activities"]), + ); + case "share_files": + return _share( + files: _parseShareFiles(args["files"]), + title: args["title"], + text: args["text"], + subject: args["subject"], + previewThumbnail: _parseShareFile(args["preview_thumbnail"]), + sharePositionOrigin: _parseRect(args["share_position_origin"]), + downloadFallbackEnabled: + parseBool(args["download_fallback_enabled"], true) ?? true, + mailToFallbackEnabled: + parseBool(args["mail_to_fallback_enabled"], true) ?? true, + excludedCupertinoActivities: _parseCupertinoActivityTypes( + args["excluded_cupertino_activities"]), + fileNameOverrides: _parseFileNameOverrides(args["files"]), + ); + default: + throw Exception("Unknown Share method: $name"); + } + } + + Future> _share({ + String? text, + String? title, + String? subject, + String? uri, + List? files, + XFile? previewThumbnail, + Rect? sharePositionOrigin, + bool downloadFallbackEnabled = true, + bool mailToFallbackEnabled = true, + List? excludedCupertinoActivities, + List? fileNameOverrides, + }) async { + final params = ShareParams( + text: text, + title: title, + subject: subject, + uri: uri != null ? Uri.parse(uri) : null, + files: files, + previewThumbnail: previewThumbnail, + sharePositionOrigin: sharePositionOrigin, + downloadFallbackEnabled: downloadFallbackEnabled, + mailToFallbackEnabled: mailToFallbackEnabled, + excludedCupertinoActivities: excludedCupertinoActivities, + fileNameOverrides: fileNameOverrides); + + final result = await SharePlus.instance.share(params); + return {"status": result.status.name, "raw": result.raw}; + } + + List? _parseShareFiles(dynamic value) { + if (value is List) { + return value.map((e) => _parseShareFile(e)!).toList(); + } + return null; + } + + List? _parseFileNameOverrides(dynamic value) { + if (value is List) { + final names = value.map((e) => _extractFileName(e)).toList(); + return names.isEmpty ? null : names; + } + return null; + } + + String _extractFileName(dynamic value) { + if (value is Map) { + final name = (value["name"] as String?)?.trim(); + if (name != null && name.isNotEmpty) { + return name; + } + final path = (value["path"] as String?)?.trim(); + if (path != null && path.isNotEmpty) { + final base = p.basename(path); + if (base.isNotEmpty) { + return base; + } + } + } + return "shared_file"; + } + + XFile? _parseShareFile(dynamic value) { + if (value is Map) { + final path = value["path"] as String?; + final data = value["data"]; + final mimeType = value["mime_type"] as String?; + final name = value["name"] as String?; + + if (path != null) { + final resolvedName = (name ?? p.basename(path)).trim().isNotEmpty + ? (name ?? p.basename(path)).trim() + : "shared_file"; + return XFile(path, name: resolvedName); + } + + if (data != null) { + Uint8List bytes; + if (data is Uint8List) { + bytes = data; + } else if (data is List) { + bytes = Uint8List.fromList(data); + } else { + throw ArgumentError("data must be Uint8List or List"); + } + final resolvedName = + name != null && name.isNotEmpty ? name : "shared_file"; + return XFile.fromData(bytes, mimeType: mimeType, name: resolvedName); + } + } + return null; + } + + Rect? _parseRect(dynamic value) { + if (value is Map) { + final x = parseDouble(value["x"], 0) ?? 0; + final y = parseDouble(value["y"], 0) ?? 0; + final width = parseDouble(value["width"], 0) ?? 0; + final height = parseDouble(value["height"], 0) ?? 0; + return Rect.fromLTWH(x, y, width, height); + } + return null; + } + + List? _parseCupertinoActivityTypes(dynamic value) { + if (value is List) { + final types = []; + for (final v in value) { + try { + final match = CupertinoActivityType.values + .firstWhere((e) => e.name == v || e.value == v); + types.add(match); + } catch (_) {} + } + return types.isEmpty ? null : types; + } + return null; + } + + @override + void dispose() { + debugPrint("ShareService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/shared_preferences.dart b/packages/flet/lib/src/services/shared_preferences.dart new file mode 100644 index 0000000000..858983618d --- /dev/null +++ b/packages/flet/lib/src/services/shared_preferences.dart @@ -0,0 +1,64 @@ +import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../flet_service.dart'; + +class SharedPreferencesService extends FletService { + SharedPreferencesService({required super.control}); + + @override + void init() { + super.init(); + debugPrint( + "SharedPreferencesService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void update() { + debugPrint( + "SharedPreferencesService(${control.id}).update: ${control.properties}"); + } + + Future _invokeMethod(String name, dynamic args) async { + var prefs = await SharedPreferences.getInstance(); + switch (name) { + case "set": + var key = args["key"]!; + var value = args["value"]!; + + if (value is String) return prefs.setString(key, value); + if (value is bool) return prefs.setBool(key, value); + if (value is int) return prefs.setInt(key, value); + if (value is double) return prefs.setDouble(key, value); + if (value is List && value.every((item) => item is String)) { + return prefs.setStringList(key, value.cast()); + } + throw UnsupportedError( + "Unsupported SharedPreferences value type: ${value.runtimeType}. " + "Supported: String, bool, int, double, List."); + case "get": + return prefs.get(args["key"]!); + case "contains_key": + return prefs.containsKey(args["key"]!); + case "get_keys": + return prefs + .getKeys() + .where((key) => key.startsWith(args["key_prefix"]!)) + .toList(); + case "remove": + return prefs.remove(args["key"]!); + case "clear": + return prefs.clear(); + default: + throw Exception("Unknown SharedPreferences method: $name"); + } + } + + @override + void dispose() { + debugPrint("SharedPreferencesService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/storage_paths.dart b/packages/flet/lib/src/services/storage_paths.dart new file mode 100644 index 0000000000..6d54575e7b --- /dev/null +++ b/packages/flet/lib/src/services/storage_paths.dart @@ -0,0 +1,66 @@ +import 'package:flutter/cupertino.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; + +import '../flet_service.dart'; +import '../utils/platform.dart'; + +class StoragePaths extends FletService { + StoragePaths({required super.control}); + + @override + void init() { + super.init(); + debugPrint("StoragePaths(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("StoragePaths.$name($args)"); + // path_provider doesn't support web + if (!isWebPlatform()) { + switch (name) { + case "get_application_cache_directory": + return (await getApplicationCacheDirectory()).path; + case "get_application_documents_directory": + return (await getApplicationDocumentsDirectory()).path; + case "get_application_support_directory": + return (await getApplicationSupportDirectory()).path; + case "get_downloads_directory": + return (await getDownloadsDirectory())?.path; + case "get_external_cache_directories": + return isAndroidMobile() + ? (await getExternalCacheDirectories()) + ?.map((e) => e.path) + .toList() + : null; + case "get_external_storage_directories": + return isAndroidMobile() + ? (await getExternalStorageDirectories()) + ?.map((e) => e.path) + .toList() + : null; + case "get_library_directory": + return isApplePlatform() ? (await getLibraryDirectory()).path : null; + case "get_external_storage_directory": + return isAndroidMobile() + ? (await getExternalStorageDirectory())?.path + : null; + case "get_temporary_directory": + return (await getTemporaryDirectory()).path; + case "get_console_log_filename": + return path.join( + (await getApplicationCacheDirectory()).path, "console.log"); + default: + throw Exception("Unknown StoragePaths method: $name"); + } + } + } + + @override + void dispose() { + debugPrint("StoragePaths(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/tester.dart b/packages/flet/lib/src/services/tester.dart new file mode 100644 index 0000000000..18dc410319 --- /dev/null +++ b/packages/flet/lib/src/services/tester.dart @@ -0,0 +1,173 @@ +import 'package:flutter/material.dart'; + +import '../flet_service.dart'; +import '../testing/test_finder.dart'; +import '../utils/icons.dart'; +import '../utils/keys.dart'; +import '../utils/time.dart'; +import 'package:flet/src/utils/transforms.dart'; + + +class TesterService extends FletService { + TesterService({required super.control}); + final Map _finders = {}; + + @override + void init() { + super.init(); + debugPrint("Tester(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + debugPrint("Tester(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Tester.$name($args)"); + switch (name) { + case "pump": + await control.backend.tester! + .pump(duration: parseDuration(args["duration"])); + + case "pump_and_settle": + await control.backend.tester! + .pumpAndSettle(duration: parseDuration(args["duration"])); + + case "find_by_text": + var finder = control.backend.tester!.findByText(args["text"]); + _finders[finder.id] = finder; + return finder.toMap(); + + case "find_by_text_containing": + var finder = + control.backend.tester!.findByTextContaining(args["pattern"]); + _finders[finder.id] = finder; + return finder.toMap(); + + case "find_by_key": + var controlKey = parseKey(args["key"])!; + var key = controlKey is ControlScrollKey + ? control.backend.globalKeys[controlKey.toString()] + : ValueKey(controlKey.value); + if (key == null) { + throw Exception("Key not found: $key"); + } + var finder = control.backend.tester!.findByKey(key); + _finders[finder.id] = finder; + return finder.toMap(); + + case "find_by_tooltip": + var finder = control.backend.tester!.findByTooltip(args["value"]); + _finders[finder.id] = finder; + return finder.toMap(); + + case "find_by_icon": + var iconCode = args["icon"]; + var icon = parseIconData(iconCode, control.backend); + if (icon == null) { + throw Exception("Icon not found: $iconCode"); + } + var finder = control.backend.tester!.findByIcon(icon); + _finders[finder.id] = finder; + return finder.toMap(); + + case "take_screenshot": + return await control.backend.tester!.takeScreenshot(args["name"]); + + case "tap": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester!.tap(finder, args["finder_index"]); + } + + case "mouse_click": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester!.mouseClick(finder, args["finder_index"]); + } + + case "mouse_double_click": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester! + .mouseDoubleClick(finder, args["finder_index"]); + } + + case "right_mouse_click": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester! + .rightMouseClick(finder, args["finder_index"]); + } + + case "tap_at": + var offset = parseOffset(args["offset"]); + if (offset != null) { + await control.backend.tester!.tapAt(offset); + } + + case "mouse_click_at": + var offset = parseOffset(args["offset"]); + if (offset != null) { + await control.backend.tester!.mouseClickAt(offset); + } + + case "mouse_double_click_at": + var offset = parseOffset(args["offset"]); + if (offset != null) { + await control.backend.tester!.mouseDoubleClickAt(offset); + } + + case "right_mouse_click_at": + var offset = parseOffset(args["offset"]); + if (offset != null) { + await control.backend.tester!.rightMouseClickAt(offset); + } + + case "drag": + var finder = _finders[args["finder_id"]]; + var offset = parseOffset(args["offset"]); + if (finder != null && offset != null) { + await control.backend.tester! + .drag(finder, args["finder_index"], offset); + } + + case "drag_from": + var start = parseOffset(args["start"]); + var offset = parseOffset(args["offset"]); + if (start != null && offset != null) { + await control.backend.tester!.dragFrom(start, offset); + } + + case "long_press": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester!.longPress(finder, args["finder_index"]); + } + + case "enter_text": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester! + .enterText(finder, args["finder_index"], args["text"]); + } + + case "mouse_hover": + var finder = _finders[args["finder_id"]]; + if (finder != null) { + await control.backend.tester! + .mouseHover(finder, args["finder_index"]); + } + + case "teardown": + control.backend.tester?.teardown(); + + default: + throw Exception("Unknown Tester method: $name"); + } + } +} diff --git a/packages/flet/lib/src/services/url_launcher.dart b/packages/flet/lib/src/services/url_launcher.dart new file mode 100644 index 0000000000..bb5ef6a94d --- /dev/null +++ b/packages/flet/lib/src/services/url_launcher.dart @@ -0,0 +1,89 @@ +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +import '../flet_service.dart'; +import '../utils/enums.dart'; +import '../utils/launch_url.dart'; +import '../utils/numbers.dart'; + +class UrlLauncherService extends FletService { + UrlLauncherService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("UrlLauncherService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + @override + void update() { + debugPrint( + "UrlLauncherService(${control.id}).update: ${control.properties}"); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("UrlLauncherService.$name($args)"); + switch (name) { + case "launch_url": + return openWebBrowser(parseUrl(args["url"]!)!, + mode: _parseLaunchMode(args["mode"]), + webViewConfiguration: + _parseWebViewConfiguration(args["web_view_configuration"]), + browserConfiguration: + _parseBrowserConfiguration(args["browser_configuration"]), + webOnlyWindowName: args["web_only_window_name"]); + case "can_launch_url": + return canLaunchUrl(Uri.parse(parseUrl(args["url"]!)!.url)); + case "close_in_app_web_view": + return closeInAppWebView(); + case "open_window": + return openWindow(parseUrl(args["url"]!)!, + title: args["title"], + width: parseDouble(args["width"]), + height: parseDouble(args["height"])); + case "supports_launch_mode": + return supportsLaunchMode(_parseLaunchMode(args["mode"])); + case "supports_close_for_launch_mode": + return supportsCloseForLaunchMode(_parseLaunchMode(args["mode"])); + default: + throw Exception("Unknown UrlLauncher method: $name"); + } + } + + @override + void dispose() { + debugPrint("UrlLauncherService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} + +LaunchMode _parseLaunchMode(dynamic value) { + return parseEnum(LaunchMode.values, value, LaunchMode.platformDefault)!; +} + +WebViewConfiguration? _parseWebViewConfiguration(dynamic value) { + if (value is Map) { + var enableJavaScript = parseBool(value["enable_javascript"], true)!; + var enableDomStorage = parseBool(value["enable_dom_storage"], true)!; + var headersValue = value["headers"]; + var headers = headersValue is Map + ? headersValue.map((key, headerValue) => + MapEntry(key.toString(), headerValue.toString())) + : {}; + return WebViewConfiguration( + enableJavaScript: enableJavaScript, + enableDomStorage: enableDomStorage, + headers: headers); + } + return null; +} + +BrowserConfiguration? _parseBrowserConfiguration(dynamic value) { + if (value is Map) { + var showTitle = parseBool(value["show_title"], false)!; + return BrowserConfiguration(showTitle: showTitle); + } + return null; +} diff --git a/packages/flet/lib/src/services/user_accelerometer.dart b/packages/flet/lib/src/services/user_accelerometer.dart new file mode 100644 index 0000000000..8ec5013911 --- /dev/null +++ b/packages/flet/lib/src/services/user_accelerometer.dart @@ -0,0 +1,23 @@ +import 'package:sensors_plus/sensors_plus.dart'; + +import 'base_sensor.dart'; + +class UserAccelerometerService + extends BaseSensorService { + UserAccelerometerService({required super.control}); + + @override + Stream sensorStream(Duration samplingPeriod) { + return userAccelerometerEventStream(samplingPeriod: samplingPeriod); + } + + @override + Map serializeEvent(UserAccelerometerEvent event) { + return { + "x": event.x, + "y": event.y, + "z": event.z, + "timestamp": event.timestamp.microsecondsSinceEpoch, + }; + } +} diff --git a/packages/flet/lib/src/services/wakelock.dart b/packages/flet/lib/src/services/wakelock.dart new file mode 100644 index 0000000000..d1184a22e2 --- /dev/null +++ b/packages/flet/lib/src/services/wakelock.dart @@ -0,0 +1,35 @@ +import 'package:flutter/foundation.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; + +import '../flet_service.dart'; + +class WakelockService extends FletService { + WakelockService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("WakelockService(${control.id}).init"); + control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "enable": + return WakelockPlus.enable(); + case "disable": + return WakelockPlus.disable(); + case "is_enabled": + return WakelockPlus.enabled; + default: + throw Exception("Unknown Wakelock method: $name"); + } + } + + @override + void dispose() { + debugPrint("WakelockService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/packages/flet/lib/src/services/window.dart b/packages/flet/lib/src/services/window.dart new file mode 100644 index 0000000000..d5fbd3c0a7 --- /dev/null +++ b/packages/flet/lib/src/services/window.dart @@ -0,0 +1,451 @@ +import 'dart:async'; + +import 'package:flutter/widgets.dart'; +import 'package:window_manager/window_manager.dart'; + +import '../flet_backend.dart'; +import '../flet_service.dart'; +import '../utils/alignment.dart'; +import '../utils/colors.dart'; +import '../utils/desktop.dart'; +import '../utils/numbers.dart'; +import '../utils/platform.dart'; +import '../utils/theme.dart'; +import '../utils/window.dart'; + +class WindowService extends FletService with WindowListener { + final Completer _initWindowStateCompleter = Completer(); + Future _pendingWindowUpdate = Future.value(); + String? _title; + Color? _bgColor; + double? _width; + double? _height; + double? _minWidth; + double? _minHeight; + double? _maxWidth; + double? _maxHeight; + double? _top; + double? _left; + double? _opacity; + double? _aspectRatio; + Brightness? _brightness; + bool? _minimizable; + bool? _maximizable; + bool? _fullScreen; + bool? _movable; + bool? _resizable; + bool? _alwaysOnTop; + bool? _alwaysOnBottom; + bool? _preventClose; + bool? _minimized; + bool? _maximized; + Alignment? _alignment; + String? _badgeLabel; + String? _icon; + bool? _hasShadow; + bool? _visible; + bool? _focused; + bool? _frameless; + bool? _titleBarHidden; + bool? _titleBarButtonsHidden; + bool? _skipTaskBar; + double? _progressBar; + bool? _ignoreMouseEvents; + bool _listenersAttached = false; + + WindowService({required super.control}); + + @override + void init() { + super.init(); + if (!isDesktopPlatform()) { + return; + } + debugPrint("WindowService(${control.id}).init"); + _initWindowState(); + } + + Future _initWindowState() async { + try { + final windowState = await getWindowState(); + _width = windowState.width; + _height = windowState.height; + _top = windowState.top; + _left = windowState.left; + _opacity = windowState.opacity; + _minimizable = windowState.minimizable; + _maximizable = windowState.maximizable; + _fullScreen = windowState.fullScreen; + _resizable = windowState.resizable; + _alwaysOnTop = windowState.alwaysOnTop; + _preventClose = windowState.preventClose; + _minimized = windowState.minimized; + _maximized = windowState.maximized; + _visible = windowState.visible; + _focused = windowState.focused; + _skipTaskBar = windowState.skipTaskBar; + + if (!_listenersAttached) { + windowManager.addListener(this); + control.addInvokeMethodListener(_invokeMethod); + control.parent?.addListener(_onPageChanged); + _listenersAttached = true; + } + + if (!_initWindowStateCompleter.isCompleted) { + _initWindowStateCompleter.complete(); + } + + _scheduleWindowUpdate(); + } catch (e) { + debugPrint("Error initializing window state: $e"); + } + } + + @override + void update() { + if (!isDesktopPlatform()) { + return; + } + _scheduleWindowUpdate(); + } + + void _onPageChanged() { + if (!isDesktopPlatform()) { + return; + } + final title = control.parent?.getString("title"); + if (title != null && title != _title) { + _scheduleWindowUpdate(); + } + } + + void _scheduleWindowUpdate() { + _pendingWindowUpdate = _pendingWindowUpdate.catchError((_) {}).then((_) { + if (_initWindowStateCompleter.isCompleted) { + return _updateWindow(control.backend); + } + return _initWindowStateCompleter.future + .then((_) => _updateWindow(control.backend)); + }); + } + + Future _updateWindow(FletBackend backend) async { + if (!isDesktopPlatform()) { + return; + } + try { + var parent = control.parent; + if (parent == null) { + return; + } + var title = parent.getString("title"); + var bgColor = control.getColor("bgcolor", null); + var width = control.getDouble("width"); + var height = control.getDouble("height"); + var minWidth = control.getDouble("min_width"); + var minHeight = control.getDouble("min_height"); + var maxWidth = control.getDouble("max_width"); + var maxHeight = control.getDouble("max_height"); + var top = control.getDouble("top"); + var left = control.getDouble("left"); + var fullScreen = control.getBool("full_screen"); + var minimized = control.getBool("minimized"); + var maximized = control.getBool("maximized"); + var alignment = control.getAlignment("alignment"); + var badgeLabel = control.getString("badge_label"); + var icon = control.getString("icon"); + var hasShadow = control.getBool("shadow"); + var opacity = control.getDouble("opacity"); + var aspectRatio = control.getDouble("aspect_ratio"); + var brightness = control.getBrightness("brightness"); + var minimizable = control.getBool("minimizable"); + var maximizable = control.getBool("maximizable"); + var alwaysOnTop = control.getBool("always_on_top"); + var alwaysOnBottom = control.getBool("always_on_bottom"); + var resizable = control.getBool("resizable"); + var movable = control.getBool("movable"); + var preventClose = control.getBool("prevent_close"); + var titleBarHidden = control.getBool("title_bar_hidden"); + var titleBarButtonsHidden = + control.getBool("title_bar_buttons_hidden", false)!; + var visible = control.getBool("visible"); + var focused = control.getBool("focused"); + var skipTaskBar = control.getBool("skip_task_bar"); + var frameless = control.getBool("frameless"); + var progressBar = control.getDouble("progress_bar"); + var ignoreMouseEvents = control.getBool("ignore_mouse_events"); + + if (title != null && title != _title) { + await setWindowTitle(title); + _title = title; + } + + if (bgColor != null && bgColor != _bgColor) { + await setWindowBackgroundColor(bgColor); + _bgColor = bgColor; + } + + if ((width != null || height != null) && + (width != _width || height != _height) && + fullScreen != true && + (!isMacOSDesktop() || + (isMacOSDesktop() && maximized != true && minimized != true))) { + await setWindowSize(width, height); + _width = width; + _height = height; + } + + if ((minWidth != null || minHeight != null) && + (minWidth != _minWidth || minHeight != _minHeight)) { + await setWindowMinSize(minWidth, minHeight); + _minWidth = minWidth; + _minHeight = minHeight; + } + + if ((maxWidth != null || maxHeight != null) && + (maxWidth != _maxWidth || maxHeight != _maxHeight)) { + await setWindowMaxSize(maxWidth, maxHeight); + _maxWidth = maxWidth; + _maxHeight = maxHeight; + } + + if ((top != null || left != null) && + (top != _top || left != _left) && + fullScreen != true && + (!isMacOSDesktop() || + (isMacOSDesktop() && maximized != true && minimized != true))) { + await setWindowPosition(top, left); + _top = top; + _left = left; + } + + if (opacity != null && opacity != _opacity) { + await setWindowOpacity(opacity); + _opacity = opacity; + } + + if (aspectRatio != null && aspectRatio != _aspectRatio) { + await setWindowAspectRatio(aspectRatio); + _aspectRatio = aspectRatio; + } + + if (brightness != null && brightness != _brightness) { + await setWindowBrightness(brightness); + _brightness = brightness; + } + + if (minimizable != null && minimizable != _minimizable) { + await setWindowMinimizability(minimizable); + _minimizable = minimizable; + } + + if (minimized != _minimized) { + if (minimized == true) { + await minimizeWindow(); + } else if (minimized == false && maximized != true) { + await restoreWindow(); + } + _minimized = minimized; + } + + if (maximizable != null && maximizable != _maximizable) { + await setWindowMaximizability(maximizable); + _maximizable = maximizable; + } + + if (maximized != _maximized) { + if (maximized == true) { + await maximizeWindow(); + } else if (maximized == false) { + await unmaximizeWindow(); + } + _maximized = maximized; + } + + if (alignment != null && alignment != _alignment) { + await setWindowAlignment(alignment); + _alignment = alignment; + } + + if (badgeLabel != null && badgeLabel != _badgeLabel) { + await setWindowBadgeLabel(badgeLabel); + _badgeLabel = badgeLabel; + } + + if (icon != null && icon != _icon) { + var iconAssetSrc = backend.getAssetSource(icon); + await setWindowIcon(iconAssetSrc.path); + _icon = icon; + } + + if (hasShadow != null && hasShadow != _hasShadow) { + await setWindowShadow(hasShadow); + _hasShadow = hasShadow; + } + + if (resizable != null && resizable != _resizable) { + await setWindowResizability(resizable); + _resizable = resizable; + } + + if (movable != null && movable != _movable) { + await setWindowMovability(movable); + _movable = movable; + } + + if (fullScreen != null && fullScreen != _fullScreen) { + await setWindowFullScreen(fullScreen); + _fullScreen = fullScreen; + } + + if (alwaysOnTop != null && alwaysOnTop != _alwaysOnTop) { + await setWindowAlwaysOnTop(alwaysOnTop); + _alwaysOnTop = alwaysOnTop; + } + + if (alwaysOnBottom != null && alwaysOnBottom != _alwaysOnBottom) { + await setWindowAlwaysOnBottom(alwaysOnBottom); + _alwaysOnBottom = alwaysOnBottom; + } + + if (preventClose != null && preventClose != _preventClose) { + await setWindowPreventClose(preventClose); + _preventClose = preventClose; + } + + final effectiveTitleBarHidden = + titleBarHidden ?? _titleBarHidden ?? false; + if (effectiveTitleBarHidden != _titleBarHidden || + titleBarButtonsHidden != _titleBarButtonsHidden) { + await setWindowTitleBarVisibility( + effectiveTitleBarHidden, titleBarButtonsHidden); + _titleBarHidden = effectiveTitleBarHidden; + _titleBarButtonsHidden = titleBarButtonsHidden; + } + + if (visible != null && visible != _visible) { + if (visible == true) { + await showWindow(); + } else { + await hideWindow(); + } + _visible = visible; + } + + if (focused != null && focused != _focused) { + if (focused == true) { + await focusWindow(); + } else { + await blurWindow(); + } + _focused = focused; + } + + if (frameless != null && frameless != _frameless) { + if (frameless) { + await setWindowFrameless(); + } else { + // Restore non-frameless window chrome using cached state + await setWindowTitleBarVisibility( + _titleBarHidden ?? false, + _titleBarButtonsHidden ?? false, + ); + } + _frameless = frameless; + } + + if (progressBar != _progressBar) { + // window_manager uses -1 to clear the native progress indicator. + await setWindowProgressBar(progressBar ?? -1); + _progressBar = progressBar; + } + + if (skipTaskBar != null && skipTaskBar != _skipTaskBar) { + await setWindowSkipTaskBar(skipTaskBar); + _skipTaskBar = skipTaskBar; + } + + if (ignoreMouseEvents != null && + ignoreMouseEvents != _ignoreMouseEvents) { + await setIgnoreMouseEvents(ignoreMouseEvents); + _ignoreMouseEvents = ignoreMouseEvents; + } + } catch (e) { + debugPrint("Error updating window: $e"); + } + } + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "wait_until_ready_to_show": + await waitUntilReadyToShow(); + break; + case "to_front": + windowToFront(); + break; + case "center": + await _pendingWindowUpdate; + await centerWindow(); + break; + case "close": + await closeWindow(); + break; + case "destroy": + await destroyWindow(); + break; + case "start_dragging": + await startDraggingWindow(); + break; + case "start_resizing": + var edge = parseWindowResizeEdge(args["edge"]); + if (edge != null) { + await startResizingWindow(edge); + } + break; + default: + throw Exception("Unknown method Window.$name"); + } + } + + @override + void dispose() { + if (_listenersAttached) { + windowManager.removeListener(this); + control.removeInvokeMethodListener(_invokeMethod); + control.parent?.removeListener(_onPageChanged); + _listenersAttached = false; + } + super.dispose(); + } + + @override + void onWindowEvent(String eventName) { + if (!isDesktopPlatform()) { + return; + } + if (["resize", "resized", "move"].contains(eventName)) { + return; + } + getWindowState().then((state) { + _width = state.width; + _height = state.height; + _top = state.top; + _left = state.left; + _opacity = state.opacity; + _minimized = state.minimized; + _maximized = state.maximized; + _minimizable = state.minimizable; + _maximizable = state.maximizable; + _fullScreen = state.fullScreen; + _resizable = state.resizable; + _alwaysOnTop = state.alwaysOnTop; + _preventClose = state.preventClose; + _visible = state.visible; + _focused = state.focused; + _skipTaskBar = state.skipTaskBar; + + control.backend.onWindowEvent(eventName, state); + }); + } +} diff --git a/packages/flet/lib/src/testing/test_finder.dart b/packages/flet/lib/src/testing/test_finder.dart new file mode 100644 index 0000000000..1a8d971d06 --- /dev/null +++ b/packages/flet/lib/src/testing/test_finder.dart @@ -0,0 +1,13 @@ +abstract class TestFinder { + static int _nextId = 0; + + final int id = _nextId++; + + Object get raw; + int get count; + + Map toMap() => { + "id": id, + "count": count, + }; +} diff --git a/packages/flet/lib/src/testing/tester.dart b/packages/flet/lib/src/testing/tester.dart new file mode 100644 index 0000000000..cd03bbd11d --- /dev/null +++ b/packages/flet/lib/src/testing/tester.dart @@ -0,0 +1,31 @@ +import 'dart:typed_data'; + +import 'package:flutter/widgets.dart'; + +import 'test_finder.dart'; + +abstract class Tester { + Future pumpAndSettle({Duration? duration}); + Future pump({Duration? duration}); + TestFinder findByText(String text); + TestFinder findByTextContaining(String pattern); + TestFinder findByKey(Key key); + TestFinder findByTooltip(String value); + TestFinder findByIcon(IconData icon); + Future takeScreenshot(String name); + Future tapAt(Offset offset); + Future tap(TestFinder finder, int finderIndex); + Future mouseClickAt(Offset offset); + Future mouseClick(TestFinder finder, int finderIndex); + Future mouseDoubleClickAt(Offset offset); + Future mouseDoubleClick(TestFinder finder, int finderIndex); + Future rightMouseClickAt(Offset offset); + Future rightMouseClick(TestFinder finder, int finderIndex); + Future drag(TestFinder finder, int finderIndex, Offset offset); + Future dragFrom(Offset start, Offset offset); + Future longPress(TestFinder finder, int finderIndex); + Future enterText(TestFinder finder, int finderIndex, String text); + Future mouseHover(TestFinder finder, int finderIndex); + void teardown(); + Future waitForTeardown(); +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel.dart b/packages/flet/lib/src/transport/flet_backend_channel.dart new file mode 100644 index 0000000000..b4f30c07d5 --- /dev/null +++ b/packages/flet/lib/src/transport/flet_backend_channel.dart @@ -0,0 +1,48 @@ +import '../protocol/message.dart'; +import '../utils/platform_utils_web.dart' + if (dart.library.io) "../utils/platform_utils_non_web.dart"; +import 'flet_backend_channel_javascript_web.dart' + if (dart.library.io) "flet_backend_channel_javascript_io.dart"; +import 'flet_backend_channel_mock.dart'; +import 'flet_backend_channel_socket.dart'; +import 'flet_backend_channel_web_socket.dart'; + +typedef FletBackendChannelOnDisconnectCallback = void Function(); +typedef FletBackendChannelOnMessageCallback = void Function(Message message); + +abstract class FletBackendChannel { + factory FletBackendChannel( + {required String address, + required Map args, + required bool forcePyodide, + required FletBackendChannelOnDisconnectCallback onDisconnect, + required FletBackendChannelOnMessageCallback onMessage}) { + if (isPyodideMode() || forcePyodide) { + // Pyodide/JavaScript + return FletJavaScriptBackendChannel( + address: address, + args: args, + onDisconnect: onDisconnect, + onMessage: onMessage); + } else if (address.startsWith("http://") || + address.startsWith("https://")) { + // WebSocket + return FletWebSocketBackendChannel( + address: address, onDisconnect: onDisconnect, onMessage: onMessage); + } else if (address == "mock") { + // Mock + return FletMockBackendChannel( + address: address, onDisconnect: onDisconnect, onMessage: onMessage); + } else { + // TCP or UDS + return FletSocketBackendChannel( + address: address, onDisconnect: onDisconnect, onMessage: onMessage); + } + } + + Future connect(); + bool get isLocalConnection; + int get defaultReconnectIntervalMs; + void send(Message message); + void disconnect(); +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart b/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart new file mode 100644 index 0000000000..65149e543f --- /dev/null +++ b/packages/flet/lib/src/transport/flet_backend_channel_javascript_io.dart @@ -0,0 +1,30 @@ +import '../protocol/message.dart'; +import 'flet_backend_channel.dart'; + +class FletJavaScriptBackendChannel implements FletBackendChannel { + final String address; + final Map args; + final FletBackendChannelOnMessageCallback onMessage; + final FletBackendChannelOnDisconnectCallback onDisconnect; + + FletJavaScriptBackendChannel( + {required this.address, + required this.args, + required this.onDisconnect, + required this.onMessage}); + + @override + connect() async {} + + @override + bool get isLocalConnection => true; + + @override + int get defaultReconnectIntervalMs => 10; + + @override + void send(Message data) {} + + @override + void disconnect() {} +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart b/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart new file mode 100644 index 0000000000..46a6933223 --- /dev/null +++ b/packages/flet/lib/src/transport/flet_backend_channel_javascript_web.dart @@ -0,0 +1,66 @@ +import 'dart:js_interop'; + +import 'package:flutter/foundation.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; + +import '../protocol/message.dart'; +import 'flet_backend_channel.dart'; +import 'flet_msgpack_decoder.dart'; +import 'flet_msgpack_encoder.dart'; + +@JS() +external JSPromise jsConnect( + String appId, JSAny args, JSExportedDartFunction onMessage); + +@JS() +external void jsSend(String appId, JSUint8Array data); + +@JS() +external void jsDisconnect(String appId); + +typedef FletBackendJavascriptChannelOnMessageCallback = void Function( + List message); + +class FletJavaScriptBackendChannel implements FletBackendChannel { + final String address; + final Map args; + final FletBackendChannelOnMessageCallback onMessage; + final FletBackendChannelOnDisconnectCallback onDisconnect; + + FletJavaScriptBackendChannel( + {required this.address, + required this.args, + required this.onDisconnect, + required this.onMessage}); + + @override + connect() async { + debugPrint("Connecting to Flet JavaScript channel $address..."); + await jsConnect(address, args.jsify()!, _onMessage.toJS).toDart; + } + + void _onMessage(JSUint8Array data) { + onMessage(Message.fromList( + msgpack.deserialize(data.toDart, extDecoder: FletMsgpackDecoder()))); + } + + @override + bool get isLocalConnection => true; + + @override + int get defaultReconnectIntervalMs => 10000; + + @override + void send(Message message) { + jsSend( + address, + msgpack + .serialize(message.toList(), extEncoder: FletMsgpackEncoder()) + .toJS); + } + + @override + void disconnect() { + jsDisconnect(address); + } +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel_mock.dart b/packages/flet/lib/src/transport/flet_backend_channel_mock.dart new file mode 100644 index 0000000000..f583f23819 --- /dev/null +++ b/packages/flet/lib/src/transport/flet_backend_channel_mock.dart @@ -0,0 +1,307 @@ +import 'dart:math'; + +import 'package:flutter/foundation.dart'; + +import '../protocol/message.dart'; +import 'flet_backend_channel.dart'; + +class FletMockBackendChannel implements FletBackendChannel { + FletBackendChannelOnMessageCallback onMessage; + FletBackendChannelOnDisconnectCallback onDisconnect; + + FletMockBackendChannel( + {required String address, + required this.onDisconnect, + required this.onMessage}); + @override + bool get isLocalConnection => true; + + @override + int get defaultReconnectIntervalMs => 500; + + @override + Future connect() async { + await Future.delayed( + const Duration(seconds: 1)); // Simulating async operation + debugPrint("Connected to the Mock Flet backend channel"); + // _scenarioLineChartSimple(); + _scenarioRegister(); + // _scenarioTestServices(); + // scenarioCallWindowMethods(); + } + + Future _scenarioRegister() async { + onMessage(Message(action: MessageAction.registerClient, payload: { + "id": 1, + "patch": { + "show_semantics_debugger": false, + "theme_mode": "system", + // "platform": "ios", + // "adaptive": true, + "fonts": { + "Kanit": + "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf", + "Open Sans": "/fonts/OpenSans-Regular.ttf" + }, + "offstage": { + "_c": "Offstage", + "_i": 8, + "controls": [ + {"_c": "Text", "_i": 20, "text": "OFF1"} + ] + }, + "_services": {"_c": "ServiceRegistry", "_i": 10, "services": []}, + "views": [ + { + "_c": "View", + "_i": 20, + "route": "/", + "controls": [ + {"_c": "Text", "_i": 3, "text": "Hello, world"}, + {"_c": "Text", "_i": 4, "text": "Second line"}, + { + "_c": "Row", + "_i": 5, + "controls": [ + {"_c": "Text", "_i": 6, "text": "1st in Row"}, + {"_c": "Text", "_i": 7, "text": "2nd in Row"} + ] + } + ] + } + ] + } + })); + + await Future.delayed(const Duration(seconds: 3)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 2, + "patch": {"width": 300, "height": 300} + })); + } + + // ignore: unused_element + Future _scenarioLineChartSimple() async { + onMessage(Message(action: MessageAction.registerClient, payload: { + "id": 1, + "patch": { + "views": [ + { + "_c": "View", + "_i": 20, + "route": "/", + "controls": [ + { + "_c": "LineChart", + "_i": 30, + "line_bars": [ + { + "_c": "LineChartBarData", + "_i": 31, + "spots": [ + {"x": 1, "y": 1}, + {"x": 2, "y": 0.5}, + {"x": 3, "y": 0.6}, + {"x": 4, "y": 0.7}, + {"x": 5, "y": 0.2}, + {"x": 6, "y": 0.4} + ] + }, + { + "_c": "LineChartBarData", + "_i": 32, + "spots": [ + {"x": 1, "y": 0.8}, + {"x": 2, "y": 0.45}, + {"x": 3, "y": 0.55}, + {"x": 4, "y": 0.65}, + {"x": 5, "y": 0.1}, + {"x": 6, "y": 0.3} + ] + } + ] + }, + ] + } + ] + } + })); + + var random = Random(); + + for (int i = 7; i < 100; i++) { + var y = random.nextDouble(); + await Future.delayed(const Duration(milliseconds: 200)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 30, + "patch": { + "line_bars": { + //"\$d": [1], + "0": { + "spots": { + "\$d": [0], + //"0": {"y": 0.8}, + "5": { + "\$a": {"x": i, "y": y} + } + } + }, + "1": { + "spots": { + "\$d": [0], + //"0": {"y": 0.8}, + "5": { + "\$a": {"x": i, "y": y - 0.1} + } + } + } + } + } + })); + } + + await Future.delayed(const Duration(seconds: 2)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 30, + "patch": {"a": 1} + })); + } + + // ignore: unused_element + Future _scenarioTestServices() async { + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 11, + "patch": { + "services": { + 0: { + "\$a": {"_c": "Clipboard", "_i": 31, "var1": "a"} + } + } + } + })); + + await Future.delayed(const Duration(seconds: 2)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 31, + "patch": {"var1": "b", "var2": "c"} + })); + + await Future.delayed(const Duration(seconds: 2)); + + onMessage(Message(action: MessageAction.invokeControlMethod, payload: { + "id": 31, + "name": "get", + "args": {"a": 1, "b": false} + })); + + await Future.delayed(const Duration(seconds: 2)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 10, + "patch": { + "services": { + "\$d": [0] + } + } + })); + + // onMessage(Message( + // action: MessageAction.invokeControlMethod, + // payload: {"id": 9, "name": "close", "args": {}})); + } + + Future scenarioCallWindowMethods() async { + onMessage(Message( + action: MessageAction.invokeControlMethod, + payload: {"id": 9, "name": "to_front", "args": {}})); + + await Future.delayed(const Duration(seconds: 3)); + + onMessage(Message( + action: MessageAction.invokeControlMethod, + payload: {"id": 9, "name": "close", "args": {}})); + } + + scenario_1() async { + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 1, + "patch": { + "title": "Hello, title!", + //"theme_mode": "light", + "window": {"width": 1024}, + "views": { + "0": { + "controls": { + "0": {"text": "Hello, world!!!"} + } + } + } + } + })); + + await Future.delayed(const Duration(seconds: 3)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 1, + "patch": { + "fonts": { + "aboreto": + "https://github.com/google/fonts/raw/refs/heads/main/ofl/aboreto/Aboreto-Regular.ttf", + "\$d": ["Open Sans"] + }, + // "offstage": { + // "controls": { + // 1: { + // "\$a": {"_c": "Text", "_i": 21, "text": "OFF2"} + // } + // } + // }, + "views": { + "0": { + "controls": { + "\$d": [0] + } + } + } + } + })); + + await Future.delayed(const Duration(seconds: 3)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 8, + "patch": { + "controls": { + 1: { + "\$a": {"_c": "Text", "_i": 21, "text": "ON2"} + } + } + } + })); + + await Future.delayed(const Duration(seconds: 3)); + + onMessage(Message(action: MessageAction.patchControl, payload: { + "id": 5, + "patch": { + "controls": { + "\$d": [1] + } + } + })); + } + + @override + void send(Message message) { + debugPrint("Send message: ${message.toList()}"); + } + + @override + void disconnect() { + debugPrint("Disconnected from the Mock Flet backend channel"); + } +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel_socket.dart b/packages/flet/lib/src/transport/flet_backend_channel_socket.dart new file mode 100644 index 0000000000..a1fcb79a01 --- /dev/null +++ b/packages/flet/lib/src/transport/flet_backend_channel_socket.dart @@ -0,0 +1,104 @@ +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; + +import '../protocol/message.dart'; +import '../utils/networking.dart'; +import 'flet_backend_channel.dart'; +import 'flet_msgpack_decoder.dart'; +import 'flet_msgpack_encoder.dart'; +import 'streaming_msgpack_deserializer.dart'; + +const int defaultLocalReconnectInterval = 200; +const int defaultPublicReconnectInterval = 500; + +class FletSocketBackendChannel implements FletBackendChannel { + String address; + FletBackendChannelOnMessageCallback onMessage; + FletBackendChannelOnDisconnectCallback onDisconnect; + Socket? _socket; + late final bool _isLocalConnection; + late final int _defaultReconnectIntervalMs; + + // Create an instance of the StreamingDeserializer. + // This object buffers incoming chunks and decodes complete MessagePack objects. + final StreamingMsgpackDeserializer _streamingDeserializer; + + FletSocketBackendChannel({ + required this.address, + required this.onDisconnect, + required this.onMessage, + }) : _streamingDeserializer = + StreamingMsgpackDeserializer(extDecoder: FletMsgpackDecoder()); + + @override + connect() async { + debugPrint("Connecting to Socket $address..."); + + if (address.startsWith("tcp://")) { + var u = Uri.parse(address); + _isLocalConnection = await isPrivateHost(u.host); + _defaultReconnectIntervalMs = _isLocalConnection + ? defaultLocalReconnectInterval + : defaultPublicReconnectInterval; + _socket = await Socket.connect(u.host, u.port); + debugPrint( + 'Connected to: ${_socket!.remoteAddress.address}:${_socket!.remotePort}'); + } else { + final udsPath = InternetAddress(address, type: InternetAddressType.unix); + _isLocalConnection = true; + _defaultReconnectIntervalMs = defaultLocalReconnectInterval; + _socket = await Socket.connect(udsPath, 0); + debugPrint('Connected to: $udsPath'); + } + + // Listen for incoming data. + _socket!.listen( + (Uint8List data) { + debugPrint("Received packet: ${data.length}"); + // Feed the incoming chunk into the streaming deserializer. + _streamingDeserializer.addChunk(data); + // Try to decode complete MessagePack messages from buffered data. + var messages = _streamingDeserializer.decodeMessages(); + for (var message in messages) { + //debugPrint('Decoded message: ${message.toString()}'); + _onMessage(message); + } + }, + onError: (error) { + debugPrint("Error: $error"); + _socket?.destroy(); + onDisconnect(); + }, + onDone: () { + debugPrint('Server disconnected.'); + _socket?.destroy(); + onDisconnect(); + }, + ); + } + + @override + bool get isLocalConnection => _isLocalConnection; + + @override + int get defaultReconnectIntervalMs => _defaultReconnectIntervalMs; + + // Note: At this point, the incoming message is already a decoded MessagePack object. + _onMessage(dynamic message) { + onMessage(Message.fromList(message)); + } + + @override + void send(Message message) { + // Serialize the message using MessagePack and send it. + _socket!.add( + msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); + } + + @override + void disconnect() { + _socket?.destroy(); + } +} diff --git a/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart b/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart new file mode 100644 index 0000000000..34cb16580c --- /dev/null +++ b/packages/flet/lib/src/transport/flet_backend_channel_web_socket.dart @@ -0,0 +1,83 @@ +import 'package:flutter/foundation.dart'; +import 'package:msgpack_dart/msgpack_dart.dart' as msgpack; +import 'package:web_socket_channel/web_socket_channel.dart'; + +import '../protocol/message.dart'; +import '../utils/networking.dart'; +import '../utils/platform_utils_web.dart' + if (dart.library.io) "../utils/platform_utils_non_web.dart"; +import '../utils/uri.dart'; +import 'flet_backend_channel.dart'; +import 'flet_msgpack_decoder.dart'; +import 'flet_msgpack_encoder.dart'; + +class FletWebSocketBackendChannel implements FletBackendChannel { + late final String _wsUrl; + late final bool _isLocalConnection; + FletBackendChannelOnMessageCallback onMessage; + FletBackendChannelOnDisconnectCallback onDisconnect; + WebSocketChannel? _channel; + + FletWebSocketBackendChannel( + {required String address, + required this.onDisconnect, + required this.onMessage}) { + _wsUrl = getWebSocketEndpoint(Uri.parse(address)); + } + + @override + bool get isLocalConnection => _isLocalConnection; + + @override + int get defaultReconnectIntervalMs => 500; + + @override + Future connect() async { + debugPrint("Connecting to WebSocket $_wsUrl..."); + try { + // todo + var uri = Uri.parse(_wsUrl); + if (kIsWeb) { + _isLocalConnection = isLocalhost(uri); + } else { + _isLocalConnection = await isPrivateHost(uri.host); + } + + _channel = WebSocketChannel.connect(Uri.parse(_wsUrl)); + } catch (e) { + throw Exception('WebSocket connect error: $e'); + } + _channel!.stream.listen(_onMessage, onDone: () async { + debugPrint("WebSocket stream closed"); + onDisconnect(); + }, onError: (error) async { + var socketError = error as WebSocketChannelException; + debugPrint("WebSocket stream error: ${socketError.message}"); + }); + } + + _onMessage(message) { + onMessage(Message.fromList( + msgpack.deserialize(message, extDecoder: FletMsgpackDecoder()))); + } + + @override + void send(Message message) { + _channel?.sink.add( + msgpack.serialize(message.toList(), extEncoder: FletMsgpackEncoder())); + } + + @override + void disconnect() { + _channel?.sink.close(); + } + + String getWebSocketEndpoint(Uri uri) { + final wsScheme = uri.scheme == "https" ? "wss" : "ws"; + final wsPath = getWebsocketEndpointPath(uri.path); + if (wsPath == "") { + throw Exception("WebSocket endpoint path cannot be empty."); + } + return "$wsScheme://${uri.authority}/$wsPath"; + } +} diff --git a/packages/flet/lib/src/transport/flet_msgpack_decoder.dart b/packages/flet/lib/src/transport/flet_msgpack_decoder.dart new file mode 100644 index 0000000000..d363ccafb7 --- /dev/null +++ b/packages/flet/lib/src/transport/flet_msgpack_decoder.dart @@ -0,0 +1,25 @@ +import 'dart:convert'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:msgpack_dart/msgpack_dart.dart'; + +class FletMsgpackDecoder extends ExtDecoder { + final codec = const Utf8Codec(); + + @override + dynamic decodeObject(int extType, Uint8List data) { + if (extType == 1) { + var isoDate = codec.decode(data); + return DateTime.parse(isoDate); + } else if (extType == 2) { + var parts = + codec.decode(data).split(":").map((s) => int.parse(s)).toList(); + return TimeOfDay(hour: parts[0], minute: parts[1]); + } else if (extType == 3) { + var microseconds = int.parse(codec.decode(data)); + return Duration(microseconds: microseconds); + } + return null; + } +} diff --git a/packages/flet/lib/src/transport/flet_msgpack_encoder.dart b/packages/flet/lib/src/transport/flet_msgpack_encoder.dart new file mode 100644 index 0000000000..699f04d35f --- /dev/null +++ b/packages/flet/lib/src/transport/flet_msgpack_encoder.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:msgpack_dart/msgpack_dart.dart'; + +import '../utils/strings.dart'; +import 'js_interop.dart' show JSAny; + +class FletMsgpackEncoder extends ExtEncoder { + final codec = const Utf8Codec(); + + @override + int extTypeForObject(dynamic object) { + if (object is DateTime) { + return 1; + } else if (object is TimeOfDay) { + return 2; + } else if (object is Duration) { + return 3; + } else if (object is JSAny) { + return 4; + } + debugPrint( + "FletMsgpackEncoder: unknown type: ${object.runtimeType}: $object"); + return 0; + } + + @override + Uint8List encodeObject(dynamic object) { + if (object is DateTime) { + var iso = object.toUtc().toIso8601String(); + // Z suffix is not supported by Python's `datetime.fromisoformat` + iso = iso.endsWith('Z') ? "${iso.trimEnd('Z')}+00:00" : iso; + return codec.encode(iso); + } else if (object is TimeOfDay) { + return codec.encode("${object.hour}:${object.minute}"); + } else if (object is Duration) { + return codec.encode(object.inMicroseconds.toString()); + } else if (object is JSAny) { + return codec.encode(object.toString()); + } + return Uint8List(0); + } +} diff --git a/packages/flet/lib/src/transport/js_interop.dart b/packages/flet/lib/src/transport/js_interop.dart new file mode 100644 index 0000000000..33d897bf44 --- /dev/null +++ b/packages/flet/lib/src/transport/js_interop.dart @@ -0,0 +1,2 @@ +export 'js_interop_stub.dart' + if (dart.library.js_interop) 'dart:js_interop'; diff --git a/packages/flet/lib/src/transport/js_interop_stub.dart b/packages/flet/lib/src/transport/js_interop_stub.dart new file mode 100644 index 0000000000..50fe9d3460 --- /dev/null +++ b/packages/flet/lib/src/transport/js_interop_stub.dart @@ -0,0 +1,2 @@ +/// Placeholder type used on non-web targets where `dart:js_interop` is absent. +class JSAny {} diff --git a/packages/flet/lib/src/transport/streaming_msgpack_deserializer.dart b/packages/flet/lib/src/transport/streaming_msgpack_deserializer.dart new file mode 100644 index 0000000000..41c8dff14b --- /dev/null +++ b/packages/flet/lib/src/transport/streaming_msgpack_deserializer.dart @@ -0,0 +1,291 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:msgpack_dart/msgpack_dart.dart'; + +/// Thrown when a complete MessagePack object cannot be decoded +/// because the data is incomplete. +class IncompleteDataError extends FormatError { + IncompleteDataError(super.message); +} + +class _Deserializer { + final ExtDecoder? _extDecoder; + final codec = const Utf8Codec(); + final Uint8List _list; + final ByteData _data; + int _offset = 0; + + /// If false, decoded binary data buffers will reference underlying input + /// buffer and thus may change when the content of input buffer changes. + /// If true, decoded buffers are copies and the underlying input buffer is + /// free to change after decoding. + final bool copyBinaryData; + + /// The current offset after decoding + int get offset => _offset; + + _Deserializer( + Uint8List list, { + ExtDecoder? extDecoder, + this.copyBinaryData = false, + int initialOffset = 0, + }) : _list = list, + _data = + ByteData.view(list.buffer, list.offsetInBytes, list.lengthInBytes), + _extDecoder = extDecoder { + _offset = initialOffset; + } + + // Checks that at least [required] bytes are available, + // or throws an IncompleteDataError. + void _ensureAvailable(int required) { + if (_offset + required > _list.length) { + throw IncompleteDataError( + "Not enough data: require $required more bytes, available ${_list.length - _offset}"); + } + } + + dynamic decode() { + _ensureAvailable(1); + final u = _list[_offset++]; + if (u <= 127) { + return u; + } else if ((u & 0xE0) == 0xE0) { + // negative small integer + return u - 256; + } else if ((u & 0xE0) == 0xA0) { + return _readString(u & 0x1F); + } else if ((u & 0xF0) == 0x90) { + return _readArray(u & 0xF); + } else if ((u & 0xF0) == 0x80) { + return _readMap(u & 0xF); + } + switch (u) { + case 0xc0: + return null; + case 0xc2: + return false; + case 0xc3: + return true; + case 0xcc: + return _readUInt8(); + case 0xcd: + return _readUInt16(); + case 0xce: + return _readUInt32(); + case 0xcf: + return _readUInt64(); + case 0xd0: + return _readInt8(); + case 0xd1: + return _readInt16(); + case 0xd2: + return _readInt32(); + case 0xd3: + return _readInt64(); + case 0xca: + return _readFloat(); + case 0xcb: + return _readDouble(); + case 0xd9: + return _readString(_readUInt8()); + case 0xda: + return _readString(_readUInt16()); + case 0xdb: + return _readString(_readUInt32()); + case 0xc4: + return _readBuffer(_readUInt8()); + case 0xc5: + return _readBuffer(_readUInt16()); + case 0xc6: + return _readBuffer(_readUInt32()); + case 0xdc: + return _readArray(_readUInt16()); + case 0xdd: + return _readArray(_readUInt32()); + case 0xde: + return _readMap(_readUInt16()); + case 0xdf: + return _readMap(_readUInt32()); + case 0xd4: + return _readExt(1); + case 0xd5: + return _readExt(2); + case 0xd6: + return _readExt(4); + case 0xd7: + return _readExt(8); + case 0xd8: + return _readExt(16); + case 0xc7: + return _readExt(_readUInt8()); + case 0xc8: + return _readExt(_readUInt16()); + case 0xc9: + return _readExt(_readUInt32()); + default: + throw FormatError("Invalid MessagePack format"); + } + } + + int _readInt8() { + _ensureAvailable(1); + return _data.getInt8(_offset++); + } + + int _readUInt8() { + _ensureAvailable(1); + return _data.getUint8(_offset++); + } + + int _readUInt16() { + _ensureAvailable(2); + final res = _data.getUint16(_offset); + _offset += 2; + return res; + } + + int _readInt16() { + _ensureAvailable(2); + final res = _data.getInt16(_offset); + _offset += 2; + return res; + } + + int _readUInt32() { + _ensureAvailable(4); + final res = _data.getUint32(_offset); + _offset += 4; + return res; + } + + int _readInt32() { + _ensureAvailable(4); + final res = _data.getInt32(_offset); + _offset += 4; + return res; + } + + int _readUInt64() { + _ensureAvailable(8); + final res = _data.getUint64(_offset); + _offset += 8; + return res; + } + + int _readInt64() { + _ensureAvailable(8); + final res = _data.getInt64(_offset); + _offset += 8; + return res; + } + + double _readFloat() { + _ensureAvailable(4); + final res = _data.getFloat32(_offset); + _offset += 4; + return res; + } + + double _readDouble() { + _ensureAvailable(8); + final res = _data.getFloat64(_offset); + _offset += 8; + return res; + } + + Uint8List _readBuffer(int length) { + _ensureAvailable(length); + final res = + Uint8List.view(_list.buffer, _list.offsetInBytes + _offset, length); + _offset += length; + return copyBinaryData ? Uint8List.fromList(res) : res; + } + + String _readString(int length) { + final list = _readBuffer(length); + final len = list.length; + for (int i = 0; i < len; ++i) { + if (list[i] > 127) { + return codec.decode(list); + } + } + return String.fromCharCodes(list); + } + + List _readArray(int length) { + final res = List.filled(length, null, growable: false); + for (int i = 0; i < length; ++i) { + res[i] = decode(); + } + return res; + } + + Map _readMap(int length) { + final res = {}; + while (length > 0) { + res[decode()] = decode(); + --length; + } + return res; + } + + dynamic _readExt(int length) { + final extType = _readUInt8(); + final data = _readBuffer(length); + return _extDecoder?.decodeObject(extType, data); + } +} + +/// A helper to decode MessagePack data as it arrives in chunks. +/// Call [addChunk] for every incoming piece of data, +/// then [decodeMessages] to retrieve complete messages. +class StreamingMsgpackDeserializer { + final ExtDecoder? _extDecoder; + final bool copyBinaryData; + final BytesBuilder _buffer = BytesBuilder(); + + StreamingMsgpackDeserializer( + {ExtDecoder? extDecoder, this.copyBinaryData = false}) + : _extDecoder = extDecoder; + + /// Adds a new chunk of MessagePack data. + void addChunk(Uint8List chunk) { + _buffer.add(chunk); + } + + /// Attempts to decode as many complete messages as possible + /// from the buffered data. Incomplete trailing data remains in the buffer. + List decodeMessages() { + List messages = []; + Uint8List data = _buffer.takeBytes(); + int offset = 0; + while (offset < data.length) { + try { + // Create a Deserializer using the current offset + _Deserializer d = _Deserializer( + data, + extDecoder: _extDecoder, + copyBinaryData: copyBinaryData, + initialOffset: offset, + ); + dynamic message = d.decode(); + messages.add(message); + offset = d.offset; + } on IncompleteDataError { + // Not enough data to decode a full message; break out of the loop. + break; + } on FormatError { + // For actual format errors (not just incomplete data), + // rethrow or handle as needed. + rethrow; + } + } + // If there is any leftover (incomplete) data, put it back into the buffer. + if (offset < data.length) { + _buffer.add(data.sublist(offset)); + } + return messages; + } +} diff --git a/packages/flet/lib/src/utils.dart b/packages/flet/lib/src/utils.dart index 89acfb2587..5926764776 100644 --- a/packages/flet/lib/src/utils.dart +++ b/packages/flet/lib/src/utils.dart @@ -6,17 +6,18 @@ import 'package:window_manager/window_manager.dart'; import 'utils/platform.dart'; -Future setupDesktop() async { +Future setupDesktop({bool hideWindowOnStart = false}) async { if (isDesktopPlatform()) { WidgetsFlutterBinding.ensureInitialized(); await windowManager.ensureInitialized(); Map env = Platform.environment; - var hideWindowOnStart = env["FLET_HIDE_WINDOW_ON_START"]; + var hideWindowOnStartEnv = env["FLET_HIDE_WINDOW_ON_START"]; debugPrint("hideWindowOnStart: $hideWindowOnStart"); + debugPrint("hideWindowOnStartEnv: $hideWindowOnStartEnv"); await windowManager.waitUntilReadyToShow(null, () async { - if (hideWindowOnStart == null) { + if (hideWindowOnStartEnv == null && !hideWindowOnStart) { await windowManager.show(); await windowManager.focus(); } diff --git a/packages/flet/lib/src/utils/alignment.dart b/packages/flet/lib/src/utils/alignment.dart index a5f20920b2..45c472b054 100644 --- a/packages/flet/lib/src/utils/alignment.dart +++ b/packages/flet/lib/src/utils/alignment.dart @@ -1,75 +1,65 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; +import 'enums.dart'; import 'numbers.dart'; -MainAxisAlignment? parseMainAxisAlignment(String? alignment, - [MainAxisAlignment? defValue]) { - if (alignment == null) { - return defValue; - } - return MainAxisAlignment.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == alignment.toLowerCase()) ?? - defValue; +MainAxisAlignment? parseMainAxisAlignment(String? value, + [MainAxisAlignment? defaultValue]) { + return parseEnum(MainAxisAlignment.values, value, defaultValue); } -CrossAxisAlignment? parseCrossAxisAlignment(String? alignment, - [CrossAxisAlignment? defValue]) { - if (alignment == null) { - return defValue; - } - return CrossAxisAlignment.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == alignment.toLowerCase()) ?? - defValue; +CrossAxisAlignment? parseCrossAxisAlignment(String? value, + [CrossAxisAlignment? defaultValue]) { + return parseEnum(CrossAxisAlignment.values, value, defaultValue); } -TabAlignment? parseTabAlignment(String? alignment, [TabAlignment? defValue]) { - if (alignment == null) { - return defValue; - } - return TabAlignment.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == alignment.toLowerCase()) ?? - defValue; +TabAlignment? parseTabAlignment(String? value, [TabAlignment? defaultValue]) { + return parseEnum(TabAlignment.values, value, defaultValue); } -WrapAlignment? parseWrapAlignment(String? alignment, - [WrapAlignment? defValue]) { - if (alignment == null) { - return defValue; - } - return WrapAlignment.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == alignment.toLowerCase()) ?? - defValue; +WrapAlignment? parseWrapAlignment(String? value, + [WrapAlignment? defaultValue]) { + return parseEnum(WrapAlignment.values, value, defaultValue); } -WrapCrossAlignment? parseWrapCrossAlignment(String? alignment, - [WrapCrossAlignment? defValue]) { - if (alignment == null) { - return defValue; - } - return WrapCrossAlignment.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == alignment.toLowerCase()) ?? - defValue; +WrapCrossAlignment? parseWrapCrossAlignment(String? value, + [WrapCrossAlignment? defaultValue]) { + return parseEnum(WrapCrossAlignment.values, value, defaultValue); +} + +Alignment? parseAlignment(dynamic value, [Alignment? defaultValue]) { + if (value == null) return defaultValue; + return Alignment(parseDouble(value['x'], 0)!, parseDouble(value['y'], 0)!); } -Alignment? parseAlignment(Control control, String propName, - [Alignment? defValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defValue; +extension AlignmentParsers on Control { + MainAxisAlignment? getMainAxisAlignment(String propertyName, + [MainAxisAlignment? defaultValue]) { + return parseMainAxisAlignment(get(propertyName), defaultValue); } - final j1 = json.decode(v); - return alignmentFromJson(j1, defValue); -} + CrossAxisAlignment? getCrossAxisAlignment(String propertyName, + [CrossAxisAlignment? defaultValue]) { + return parseCrossAxisAlignment(get(propertyName), defaultValue); + } + + TabAlignment? getTabAlignment(String propertyName, + [TabAlignment? defaultValue]) { + return parseTabAlignment(get(propertyName), defaultValue); + } + + WrapAlignment? getWrapAlignment(String propertyName, + [WrapAlignment? defaultValue]) { + return parseWrapAlignment(get(propertyName), defaultValue); + } + + WrapCrossAlignment? getWrapCrossAlignment(String propertyName, + [WrapCrossAlignment? defaultValue]) { + return parseWrapCrossAlignment(get(propertyName), defaultValue); + } -Alignment? alignmentFromJson(Map? json, - [Alignment? defValue]) { - if (json == null) { - return defValue; + Alignment? getAlignment(String propertyName, [Alignment? defaultValue]) { + return parseAlignment(get(propertyName), defaultValue); } - return Alignment(parseDouble(json['x'], 0)!, parseDouble(json['y'],0)!); } diff --git a/packages/flet/lib/src/utils/animations.dart b/packages/flet/lib/src/utils/animations.dart index 5498ef945c..e79ee349a9 100644 --- a/packages/flet/lib/src/utils/animations.dart +++ b/packages/flet/lib/src/utils/animations.dart @@ -1,33 +1,23 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import '../models/control.dart'; -import 'numbers.dart'; import 'time.dart'; -ImplicitAnimationDetails? parseAnimation(Control control, String propName, +ImplicitAnimationDetails? parseAnimation(dynamic value, [ImplicitAnimationDetails? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { + if (value == null) { return defaultValue; - } - - final j1 = json.decode(v); - return animationFromJSON(j1); -} - -ImplicitAnimationDetails animationFromJSON(dynamic json) { - if (json is int) { - return ImplicitAnimationDetails( - duration: Duration(milliseconds: parseInt(json, 0)!), - curve: Curves.linear); - } else if (json is bool && json == true) { + } else if (value is bool && value == true) { return ImplicitAnimationDetails( duration: const Duration(milliseconds: 1000), curve: Curves.linear); + } else if (value is int) { + return ImplicitAnimationDetails( + duration: parseDuration(value, const Duration())!, + curve: Curves.linear); } - - return ImplicitAnimationDetails.fromJson(json); + return ImplicitAnimationDetails( + duration: parseDuration(value["duration"], const Duration())!, + curve: parseCurve(value["curve"], Curves.linear)!); } class ImplicitAnimationDetails { @@ -35,123 +25,81 @@ class ImplicitAnimationDetails { final Curve curve; ImplicitAnimationDetails({required this.duration, required this.curve}); - - factory ImplicitAnimationDetails.fromJson(Map json) { - return ImplicitAnimationDetails( - duration: Duration(milliseconds: json["duration"] as int), - curve: parseCurve(json["curve"], Curves.linear)!); - } } -Curve? parseCurve(String? value, [Curve? defValue]) { - switch (value?.toLowerCase()) { - case "bouncein": - return Curves.bounceIn; - case "bounceinout": - return Curves.bounceInOut; - case "bounceout": - return Curves.bounceOut; - case "decelerate": - return Curves.decelerate; - case "ease": - return Curves.ease; - case "easein": - return Curves.easeIn; - case "easeinback": - return Curves.easeInBack; - case "easeincirc": - return Curves.easeInCirc; - case "easeincubic": - return Curves.easeInCubic; - case "easeinexpo": - return Curves.easeInExpo; - case "easeinout": - return Curves.easeInOut; - case "easeinoutback": - return Curves.easeInOutBack; - case "easeinoutcirc": - return Curves.easeInOutCirc; - case "easeinoutcubic": - return Curves.easeInOutCubic; - case "easeinoutcubicemphasized": - return Curves.easeInOutCubicEmphasized; - case "easeinoutexpo": - return Curves.easeInOutExpo; - case "easeinoutquad": - return Curves.easeInOutQuad; - case "easeinoutquart": - return Curves.easeInOutQuart; - case "easeinoutquint": - return Curves.easeInOutQuint; - case "easeinoutsine": - return Curves.easeInOutSine; - case "easeinquad": - return Curves.easeInQuad; - case "easeinquart": - return Curves.easeInQuart; - case "easeinquint": - return Curves.easeInQuint; - case "easeinsine": - return Curves.easeInSine; - case "easeintolinear": - return Curves.easeInToLinear; - case "easeout": - return Curves.easeOut; - case "easeoutback": - return Curves.easeOutBack; - case "easeoutcirc": - return Curves.easeOutCirc; - case "easeoutcubic": - return Curves.easeOutCubic; - case "easeoutexpo": - return Curves.easeOutExpo; - case "easeoutquad": - return Curves.easeOutQuad; - case "easeoutquart": - return Curves.easeOutQuart; - case "easeoutquint": - return Curves.easeOutQuint; - case "easeoutsine": - return Curves.easeOutSine; - case "elasticin": - return Curves.elasticIn; - case "elasticinout": - return Curves.elasticInOut; - case "elasticout": - return Curves.elasticOut; - case "fastlineartosloweasein": - return Curves.fastLinearToSlowEaseIn; - case "fastoutslowin": - return Curves.fastOutSlowIn; - case "lineartoeaseout": - return Curves.linearToEaseOut; - case "slowmiddle": - return Curves.slowMiddle; - default: - return defValue; - } +Curve? parseCurve(String? value, [Curve? defaultValue]) { + if (value == null) return defaultValue; + + const curves = { + "bouncein": Curves.bounceIn, + "bounceinout": Curves.bounceInOut, + "bounceout": Curves.bounceOut, + "decelerate": Curves.decelerate, + "ease": Curves.ease, + "easein": Curves.easeIn, + "easeinback": Curves.easeInBack, + "easeincirc": Curves.easeInCirc, + "easeincubic": Curves.easeInCubic, + "easeinexpo": Curves.easeInExpo, + "easeinout": Curves.easeInOut, + "easeinoutback": Curves.easeInOutBack, + "easeinoutcirc": Curves.easeInOutCirc, + "easeinoutcubic": Curves.easeInOutCubic, + "easeinoutcubicemphasized": Curves.easeInOutCubicEmphasized, + "easeinoutexpo": Curves.easeInOutExpo, + "easeinoutquad": Curves.easeInOutQuad, + "easeinoutquart": Curves.easeInOutQuart, + "easeinoutquint": Curves.easeInOutQuint, + "easeinoutsine": Curves.easeInOutSine, + "easeinquad": Curves.easeInQuad, + "easeinquart": Curves.easeInQuart, + "easeinquint": Curves.easeInQuint, + "easeinsine": Curves.easeInSine, + "easeintolinear": Curves.easeInToLinear, + "easeout": Curves.easeOut, + "easeoutback": Curves.easeOutBack, + "easeoutcirc": Curves.easeOutCirc, + "easeoutcubic": Curves.easeOutCubic, + "easeoutexpo": Curves.easeOutExpo, + "easeoutquad": Curves.easeOutQuad, + "easeoutquart": Curves.easeOutQuart, + "easeoutquint": Curves.easeOutQuint, + "easeoutsine": Curves.easeOutSine, + "elasticin": Curves.elasticIn, + "elasticinout": Curves.elasticInOut, + "elasticout": Curves.elasticOut, + "fastlineartosloweasein": Curves.fastLinearToSlowEaseIn, + "fastoutslowin": Curves.fastOutSlowIn, + "lineartoeaseout": Curves.linearToEaseOut, + "slowmiddle": Curves.slowMiddle, + }; + + return curves[value.toLowerCase()] ?? defaultValue; } -AnimationStyle? parseAnimationStyle(Control control, String propName, +AnimationStyle? parseAnimationStyle(dynamic value, [AnimationStyle? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; - } + if (value == null) return defaultValue; - final j1 = json.decode(v); - return animationStyleFromJSON(j1); + return AnimationStyle( + curve: parseCurve(value["curve"]), + reverseCurve: parseCurve(value["reverse_curve"]), + duration: parseDuration(value["duration"]), + reverseDuration: parseDuration(value["reverse_duration"])); } -AnimationStyle animationStyleFromJSON(dynamic json, - [AnimationStyle? defaultValue]) { - if (json == null) { - return defaultValue!; +extension AnimationParsers on Control { + ImplicitAnimationDetails? getAnimation(String propertyName, + [ImplicitAnimationDetails? defaultValue]) { + return parseAnimation(get(propertyName), defaultValue); } - return AnimationStyle( - curve: parseCurve(json["curve"]), - reverseCurve: parseCurve(json["reverse_curve"]), - duration: durationFromJSON(json["duration"]), - reverseDuration: durationFromJSON(json["reverse_duration"])); + Curve? getCurve(String propertyName, [Curve? defaultValue]) { + return parseCurve(get(propertyName), defaultValue); + } + + AnimationStyle? getAnimationStyle(String propertyName, + [AnimationStyle? defaultValue]) { + return parseAnimationStyle(get(propertyName), defaultValue); + } } diff --git a/packages/flet/lib/src/utils/auto_complete.dart b/packages/flet/lib/src/utils/auto_complete.dart index d678312360..a4a3ca5569 100644 --- a/packages/flet/lib/src/utils/auto_complete.dart +++ b/packages/flet/lib/src/utils/auto_complete.dart @@ -1,9 +1,5 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; -import '../models/control.dart'; - @immutable class AutoCompleteSuggestion { const AutoCompleteSuggestion({ @@ -23,10 +19,7 @@ class AutoCompleteSuggestion { return key; } - Map toJson() => { - 'key': key, - 'value': value, - }; + Map toMap() => {'key': key, 'value': value}; @override bool operator ==(Object other) { @@ -42,44 +35,33 @@ class AutoCompleteSuggestion { int get hashCode => Object.hash(key, value); } -List parseAutoCompleteSuggestions( - Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return []; - } - - final j1 = json.decode(v); - return autoCompleteSuggestionsFromJSON(j1); -} +List? parseAutoCompleteSuggestions( + dynamic value, [ + List? defaultValue, +]) { + if (value == null) return defaultValue; -List autoCompleteSuggestionsFromJSON(dynamic json) { List m = []; - if (json is List) { - json.map((e) => autoCompleteSuggestionFromJSON(e)).toList().forEach((e) { - if (e != null) { - m.add(e); + + if (value is List) { + for (var json in value) { + var key = json["key"]; + var val = json["value"]; + + if ((key == null || key.toString().isEmpty) && + (val == null || val.toString().isEmpty)) { + continue; } - }); - } - return m; -} -AutoCompleteSuggestion? autoCompleteSuggestionFromJSON(dynamic json) { - var key = json["key"]; - var value = json["value"]; - if ((key == null || key.toString().isEmpty) && - (value == null || value.toString().isEmpty)) { - return null; - } - if (key == null && value != null) { - key = value; - } - if (value == null && key != null) { - value = key; + key ??= val; + val ??= key; + + m.add(AutoCompleteSuggestion( + key: key.toString(), + value: val.toString(), + )); + } } - return AutoCompleteSuggestion( - key: key.toString(), - value: value.toString(), - ); -} + + return m; +} \ No newline at end of file diff --git a/packages/flet/lib/src/utils/autofill.dart b/packages/flet/lib/src/utils/autofill.dart index 32fe132d71..535ba8c632 100644 --- a/packages/flet/lib/src/utils/autofill.dart +++ b/packages/flet/lib/src/utils/autofill.dart @@ -1,180 +1,122 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import '../models/control.dart'; -List? parseAutofillHints(Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return autofillHintsFromJson(j1); -} - -List autofillHintsFromJson(dynamic json) { +List? parseAutofillHints(dynamic value, [List? defaultValue]) { + if (value == null) return defaultValue; List hints = []; - if (json is List) { - hints = json - .map((e) => autofillHintFromString(e.toString())) + if (value is List) { + hints = value + .map((e) => parseAutofillHint(e.toString())) .whereType() .toList(); - } else if (json is String) { - hints = [autofillHintFromString(json)].whereType().toList(); + } else if (value is String) { + hints = [parseAutofillHint(value)].whereType().toList(); } return hints; } -String? autofillHintFromString(String? hint, [String? defaultAutoFillHint]) { - switch (hint?.toLowerCase()) { - case 'addresscity': - return AutofillHints.addressCity; - case 'addresscityandstate': - return AutofillHints.addressCityAndState; - case 'addressstate': - return AutofillHints.addressState; - case 'birthday': - return AutofillHints.birthday; - case 'birthdayday': - return AutofillHints.birthdayDay; - case 'birthdayMonth': - return AutofillHints.birthdayMonth; - case 'birthdayyear': - return AutofillHints.birthdayYear; - case 'countrycode': - return AutofillHints.countryCode; - case 'countryname': - return AutofillHints.countryName; - case 'creditcardexpirationdate': - return AutofillHints.creditCardExpirationDate; - case 'creditcardexpirationday': - return AutofillHints.creditCardExpirationDay; - case 'creditcardexpirationmonth': - return AutofillHints.creditCardExpirationMonth; - case 'creditcardexpirationyear': - return AutofillHints.creditCardExpirationYear; - case 'creditcardfamilyname': - return AutofillHints.creditCardFamilyName; - case 'creditcardgivenname': - return AutofillHints.creditCardGivenName; - case 'creditcardmiddlename': - return AutofillHints.creditCardMiddleName; - case 'creditcardname': - return AutofillHints.creditCardName; - case 'creditcardnumber': - return AutofillHints.creditCardNumber; - case 'creditcardsecuritycode': - return AutofillHints.creditCardSecurityCode; - case 'creditcardtype': - return AutofillHints.creditCardType; - case 'email': - return AutofillHints.email; - case 'familyname': - return AutofillHints.familyName; - case 'fullstreetaddress': - return AutofillHints.fullStreetAddress; - case 'gender': - return AutofillHints.gender; - case 'givenname': - return AutofillHints.givenName; - case 'impp': - return AutofillHints.impp; - case 'jobtitle': - return AutofillHints.jobTitle; - case 'language': - return AutofillHints.language; - case 'location': - return AutofillHints.location; - case 'middleinitial': - return AutofillHints.middleInitial; - case 'middlename': - return AutofillHints.middleName; - case 'name': - return AutofillHints.name; - case 'nameprefix': - return AutofillHints.namePrefix; - case 'namesuffix': - return AutofillHints.nameSuffix; - case 'newpassword': - return AutofillHints.newPassword; - case 'newusername': - return AutofillHints.newUsername; - case 'nickname': - return AutofillHints.nickname; - case 'onetimecode': - return AutofillHints.oneTimeCode; - case 'organizationname': - return AutofillHints.organizationName; - case 'password': - return AutofillHints.password; - case 'photo': - return AutofillHints.photo; - case 'postaladdress': - return AutofillHints.postalAddress; - case 'postaladdressextended': - return AutofillHints.postalAddressExtended; - case 'postaladdressextendedpostalcode': - return AutofillHints.postalAddressExtendedPostalCode; - case 'postalcode': - return AutofillHints.postalCode; - case 'streetaddresslevel1': - return AutofillHints.streetAddressLevel1; - case 'streetaddresslevel2': - return AutofillHints.streetAddressLevel2; - case 'streetaddresslevel3': - return AutofillHints.streetAddressLevel3; - case 'streetaddresslevel4': - return AutofillHints.streetAddressLevel4; - case 'streetaddressline1': - return AutofillHints.streetAddressLine1; - case 'streetaddressline2': - return AutofillHints.streetAddressLine2; - case 'streetaddressline3': - return AutofillHints.streetAddressLine3; - case 'sublocality': - return AutofillHints.sublocality; - case 'telephonenumber': - return AutofillHints.telephoneNumber; - case 'telephonenumberareacode': - return AutofillHints.telephoneNumberAreaCode; - case 'telephonenumbercountrycode': - return AutofillHints.telephoneNumberCountryCode; - case 'telephonenumberdevice': - return AutofillHints.telephoneNumberDevice; - case 'telephonenumberextension': - return AutofillHints.telephoneNumberExtension; - case 'telephonenumberlocal': - return AutofillHints.telephoneNumberLocal; - case 'telephonenumberlocalprefix': - return AutofillHints.telephoneNumberLocalPrefix; - case 'telephonenumberlocalsuffix': - return AutofillHints.telephoneNumberLocalSuffix; - case 'telephonenumbernational': - return AutofillHints.telephoneNumberNational; - case 'transactionamount': - return AutofillHints.transactionAmount; - case 'transactioncurrency': - return AutofillHints.transactionCurrency; - case 'url': - return AutofillHints.url; - case 'username': - return AutofillHints.username; - default: - return defaultAutoFillHint; - } +String? parseAutofillHint(String? value, [String? defaultValue]) { + if (value == null) return defaultValue; + + const hints = { + 'addresscity': AutofillHints.addressCity, + 'addresscityandstate': AutofillHints.addressCityAndState, + 'addressstate': AutofillHints.addressState, + 'birthday': AutofillHints.birthday, + 'birthdayday': AutofillHints.birthdayDay, + 'birthdaymonth': AutofillHints.birthdayMonth, + 'birthdayyear': AutofillHints.birthdayYear, + 'countrycode': AutofillHints.countryCode, + 'countryname': AutofillHints.countryName, + 'creditcardexpirationdate': AutofillHints.creditCardExpirationDate, + 'creditcardexpirationday': AutofillHints.creditCardExpirationDay, + 'creditcardexpirationmonth': AutofillHints.creditCardExpirationMonth, + 'creditcardexpirationyear': AutofillHints.creditCardExpirationYear, + 'creditcardfamilyname': AutofillHints.creditCardFamilyName, + 'creditcardgivenname': AutofillHints.creditCardGivenName, + 'creditcardmiddlename': AutofillHints.creditCardMiddleName, + 'creditcardname': AutofillHints.creditCardName, + 'creditcardnumber': AutofillHints.creditCardNumber, + 'creditcardsecuritycode': AutofillHints.creditCardSecurityCode, + 'creditcardtype': AutofillHints.creditCardType, + 'email': AutofillHints.email, + 'familyname': AutofillHints.familyName, + 'fullstreetaddress': AutofillHints.fullStreetAddress, + 'gender': AutofillHints.gender, + 'givenname': AutofillHints.givenName, + 'impp': AutofillHints.impp, + 'jobtitle': AutofillHints.jobTitle, + 'language': AutofillHints.language, + 'location': AutofillHints.location, + 'middleinitial': AutofillHints.middleInitial, + 'middlename': AutofillHints.middleName, + 'name': AutofillHints.name, + 'nameprefix': AutofillHints.namePrefix, + 'namesuffix': AutofillHints.nameSuffix, + 'newpassword': AutofillHints.newPassword, + 'newusername': AutofillHints.newUsername, + 'nickname': AutofillHints.nickname, + 'onetimecode': AutofillHints.oneTimeCode, + 'organizationname': AutofillHints.organizationName, + 'password': AutofillHints.password, + 'photo': AutofillHints.photo, + 'postaladdress': AutofillHints.postalAddress, + 'postaladdressextended': AutofillHints.postalAddressExtended, + 'postaladdressextendedpostalcode': + AutofillHints.postalAddressExtendedPostalCode, + 'postalcode': AutofillHints.postalCode, + 'streetaddresslevel1': AutofillHints.streetAddressLevel1, + 'streetaddresslevel2': AutofillHints.streetAddressLevel2, + 'streetaddresslevel3': AutofillHints.streetAddressLevel3, + 'streetaddresslevel4': AutofillHints.streetAddressLevel4, + 'streetaddressline1': AutofillHints.streetAddressLine1, + 'streetaddressline2': AutofillHints.streetAddressLine2, + 'streetaddressline3': AutofillHints.streetAddressLine3, + 'sublocality': AutofillHints.sublocality, + 'telephonenumber': AutofillHints.telephoneNumber, + 'telephonenumberareacode': AutofillHints.telephoneNumberAreaCode, + 'telephonenumbercountrycode': AutofillHints.telephoneNumberCountryCode, + 'telephonenumberdevice': AutofillHints.telephoneNumberDevice, + 'telephonenumberextension': AutofillHints.telephoneNumberExtension, + 'telephonenumberlocal': AutofillHints.telephoneNumberLocal, + 'telephonenumberlocalprefix': AutofillHints.telephoneNumberLocalPrefix, + 'telephonenumberlocalsuffix': AutofillHints.telephoneNumberLocalSuffix, + 'telephonenumbernational': AutofillHints.telephoneNumberNational, + 'transactionamount': AutofillHints.transactionAmount, + 'transactioncurrency': AutofillHints.transactionCurrency, + 'url': AutofillHints.url, + 'username': AutofillHints.username, + }; + + return hints[value.toLowerCase()] ?? defaultValue; } -AutofillContextAction? parseAutofillContextAction(String? action, - [AutofillContextAction? defaultAction]) { - switch (action?.toLowerCase()) { +AutofillContextAction? parseAutofillContextAction(String? value, + [AutofillContextAction? defaultValue]) { + switch (value?.toLowerCase()) { case 'commit': return AutofillContextAction.commit; case 'cancel': return AutofillContextAction.cancel; default: - return defaultAction; + return defaultValue; + } +} + +extension AutofillParsers on Control { + List? getAutofillHints(String propertyName, + [List? defaultValue]) { + return parseAutofillHints(get(propertyName), defaultValue); + } + + String? getAutofillHint(String propertyName, [String? defaultValue]) { + return parseAutofillHint(get(propertyName), defaultValue); + } + + AutofillContextAction? getAutofillContextAction(String propertyName, + [AutofillContextAction? defaultValue]) { + return parseAutofillContextAction(get(propertyName), defaultValue); } } diff --git a/packages/flet/lib/src/utils/badge.dart b/packages/flet/lib/src/utils/badge.dart index 09cf306b1c..075c88919b 100644 --- a/packages/flet/lib/src/utils/badge.dart +++ b/packages/flet/lib/src/utils/badge.dart @@ -1,38 +1,36 @@ -import 'dart:convert'; - -import 'package:flet/flet.dart'; import 'package:flutter/material.dart'; -Badge? parseBadge( - Control control, String propName, Widget widget, ThemeData theme) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - final j = json.decode(v); - return badgeFromJSON(j, widget, theme); -} +import '../extensions/control.dart'; +import '../models/control.dart'; +import '../utils/alignment.dart'; +import '../utils/colors.dart'; +import '../utils/edge_insets.dart'; +import '../utils/numbers.dart'; +import '../utils/text.dart'; +import 'transforms.dart'; -Badge? badgeFromJSON(dynamic j, Widget widget, ThemeData theme) { - if (j == null) { - return null; - } else if (j is String) { - return Badge(label: Text(j), child: widget); +extension BadgeParsers on Control { + Widget wrapWithBadge(String propertyName, Widget child, ThemeData theme) { + var badge = get(propertyName); + if (badge == null) { + return child; + } else if (badge is Control) { + badge.notifyParent = true; + return Badge( + label: badge.buildTextOrWidget("label"), + isLabelVisible: badge.getBool("label_visible", true)!, + offset: badge.getOffset("offset"), + alignment: badge.getAlignment("alignment"), + backgroundColor: parseColor(badge.get("bgcolor"), theme), + largeSize: badge.getDouble("large_size"), + padding: badge.getPadding("padding"), + smallSize: badge.getDouble("small_size"), + textColor: parseColor(badge.get("text_color"), theme), + textStyle: badge.getTextStyle("text_style", theme), + child: child, + ); + } else { + return Badge(label: Text(badge.toString()), child: child); + } } - - String? label = j["text"]; - - return Badge( - label: label != null ? Text(label) : null, - isLabelVisible: parseBool(j["label_visible"]) ?? true, - offset: offsetFromJson(j["offset"]), - alignment: alignmentFromJson(j["alignment"]), - backgroundColor: parseColor(theme, j["bgcolor"]), - largeSize: parseDouble(j["large_size"]), - padding: edgeInsetsFromJson(j["padding"]), - smallSize: parseDouble(j["small_size"]), - textColor: parseColor(theme, j["text_color"]), - textStyle: textStyleFromJson(theme, j["text_style"]), - child: widget, - ); } diff --git a/packages/flet/lib/src/utils/borders.dart b/packages/flet/lib/src/utils/borders.dart index 992e9b699a..35bb0f8f7b 100644 --- a/packages/flet/lib/src/utils/borders.dart +++ b/packages/flet/lib/src/utils/borders.dart @@ -1,163 +1,147 @@ import 'dart:collection'; -import 'dart:convert'; import 'package:flutter/material.dart'; import '../models/control.dart'; import 'colors.dart'; -import 'material_state.dart'; +import 'enums.dart'; import 'numbers.dart'; +import 'widget_state.dart'; -BorderRadius? parseBorderRadius(Control control, String propName, - [BorderRadius? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; - } - - final j1 = json.decode(v); - return borderRadiusFromJSON(j1); -} +BorderRadius? parseBorderRadius(dynamic value, [BorderRadius? defaultValue]) { + if (value == null) return defaultValue; -Radius? parseRadius(Control control, String propName, [Radius? defaultValue]) { - var r = control.attrDouble(propName, null); - if (r == null) { - return defaultValue; + if (value is int || value is double) { + return BorderRadius.all(parseRadius(value)!); } - - return Radius.circular(r); + return BorderRadius.only( + topLeft: parseRadius(value['top_left'], Radius.zero)!, + topRight: parseRadius(value['top_right'], Radius.zero)!, + bottomLeft: parseRadius(value['bottom_left'], Radius.zero)!, + bottomRight: parseRadius(value['bottom_right'], Radius.zero)!, + ); } -Border? parseBorder(ThemeData theme, Control control, String propName, - [Color? defaultSideColor]) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } +Radius? parseRadius(dynamic value, [Radius? defaultValue]) { + var radius = parseDouble(value); + if (radius == null) return defaultValue; - final j1 = json.decode(v); - return borderFromJSON(theme, j1, defaultSideColor); + return Radius.circular(radius); } -BorderSide? parseBorderSide(ThemeData theme, Control control, String propName, - {Color? defaultSideColor}) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return borderSideFromJSON(theme, j1, defaultSideColor); +BorderStyle? parseBorderStyle(String? value, [BorderStyle? defaultValue]) { + return parseEnum(BorderStyle.values, value, defaultValue); } -OutlinedBorder? parseOutlinedBorder(Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return outlinedBorderFromJSON(j1); +Border? parseBorder(dynamic value, ThemeData? theme, + {Color defaultSideColor = Colors.black, + BorderSide? defaultBorderSide, + Border? defaultValue}) { + if (value == null) return defaultValue; + return Border( + top: parseBorderSide(value['top'], theme, + defaultSideColor: defaultSideColor, + defaultValue: defaultBorderSide ?? BorderSide.none)!, + right: parseBorderSide(value['right'], theme, + defaultSideColor: defaultSideColor, + defaultValue: defaultBorderSide ?? BorderSide.none)!, + bottom: parseBorderSide(value['bottom'], theme, + defaultSideColor: defaultSideColor, + defaultValue: defaultBorderSide ?? BorderSide.none)!, + left: parseBorderSide(value['left'], theme, + defaultSideColor: defaultSideColor, + defaultValue: defaultBorderSide ?? BorderSide.none)!); } -BorderRadius? borderRadiusFromJSON(dynamic json, [BorderRadius? defaultValue]) { - if (json == null) { - return defaultValue; - } - if (json is int || json is double) { - return BorderRadius.all(Radius.circular(parseDouble(json, 0)!)); - } - return BorderRadius.only( - topLeft: Radius.circular(parseDouble(json['tl'], 0)!), - topRight: Radius.circular(parseDouble(json['tr'], 0)!), - bottomLeft: Radius.circular(parseDouble(json['bl'], 0)!), - bottomRight: Radius.circular(parseDouble(json['br'], 0)!), +BorderSide? parseBorderSide(dynamic value, ThemeData? theme, + {Color defaultSideColor = Colors.black, BorderSide? defaultValue}) { + if (value == null) return defaultValue; + return BorderSide( + color: parseColor(value['color'], theme, defaultSideColor)!, + width: parseDouble(value['width'], 1)!, + strokeAlign: + parseDouble(value['stroke_align'], BorderSide.strokeAlignInside)!, + style: parseBorderStyle(value['style'], BorderStyle.solid)!, ); } -Border? borderFromJSON(ThemeData? theme, Map? json, - [Color? defaultSideColor, Border? defaultBorder]) { - if (json == null) { - return defaultBorder; - } - return Border( - top: borderSideFromJSON(theme, json['t'], defaultSideColor) ?? - BorderSide.none, - right: borderSideFromJSON(theme, json['r'], defaultSideColor) ?? - BorderSide.none, - bottom: borderSideFromJSON(theme, json['b'], defaultSideColor) ?? - BorderSide.none, - left: borderSideFromJSON(theme, json['l'], defaultSideColor) ?? - BorderSide.none); +ShapeBorder? parseShapeBorder(dynamic value, ThemeData? theme, + [ShapeBorder? defaultValue]) { + if (value == null) return defaultValue; + return parseOutlinedBorder(value, theme, + defaultValue: defaultValue as OutlinedBorder?); } -BorderSide? borderSideFromJSON(ThemeData? theme, dynamic json, - [Color? defaultSideColor]) { - return json != null - ? BorderSide( - color: - parseColor(theme, json['c'], defaultSideColor ?? Colors.black)!, - width: parseDouble(json['w'], 1)!, - strokeAlign: parseDouble(json['sa'], BorderSide.strokeAlignInside)!, - style: BorderStyle.solid) - : null; -} - -OutlinedBorder? outlinedBorderFromJSON(Map? json) { - if (json == null) { - return null; +OutlinedBorder? parseOutlinedBorder(dynamic value, ThemeData? theme, + {BorderSide defaultBorderSide = BorderSide.none, + BorderRadius defaultBorderRadius = BorderRadius.zero, + OutlinedBorder? defaultValue}) { + if (value == null) return defaultValue; + + var borderSide = + parseBorderSide(value["side"], theme, defaultValue: defaultBorderSide)!; + var borderRadius = parseBorderRadius(value["radius"], defaultBorderRadius)!; + + var type = value["_type"]; + switch (type.toLowerCase()) { + case "roundedrectangle": + return RoundedRectangleBorder( + side: borderSide, borderRadius: borderRadius); + case "stadium": + return StadiumBorder(side: borderSide); + case "circle": + return CircleBorder( + side: borderSide, + eccentricity: parseDouble(value["eccentricity"], 0.0)!); + case "beveledrectangle": + return BeveledRectangleBorder( + side: borderSide, borderRadius: borderRadius); + case "continuousrectangle": + return ContinuousRectangleBorder( + side: borderSide, borderRadius: borderRadius); + default: + return defaultValue; } +} - String type = json["type"]; - if (type == "roundedRectangle") { - return RoundedRectangleBorder( - borderRadius: borderRadiusFromJSON(json["radius"], BorderRadius.zero)!); - } else if (type == "stadium") { - return const StadiumBorder(); - } else if (type == "circle") { - return const CircleBorder(); - } else if (type == "beveledRectangle") { - return BeveledRectangleBorder( - borderRadius: borderRadiusFromJSON(json["radius"], BorderRadius.zero)!); - } else if (type == "continuousRectangle") { - return ContinuousRectangleBorder( - borderRadius: borderRadiusFromJSON(json["radius"], BorderRadius.zero)!); - } - return null; +OutlinedBorder? parseShape(dynamic value, ThemeData? theme, + {BorderSide defaultBorderSide = BorderSide.none, + BorderRadius defaultBorderRadius = BorderRadius.zero, + OutlinedBorder? defaultValue}) { + return parseOutlinedBorder(value, theme, + defaultBorderSide: defaultBorderSide, + defaultBorderRadius: defaultBorderRadius, + defaultValue: defaultValue); } WidgetStateBorderSide? parseWidgetStateBorderSide( - ThemeData theme, Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - var j = json.decode(v); - if (j is Map && (j.containsKey("w") || j.containsKey("c"))) { - j = {"default": j}; + dynamic value, ThemeData theme, + {BorderSide? defaultBorderSide = BorderSide.none, + WidgetStateBorderSide? defaultValue}) { + if (value == null) return defaultValue; + if (value is Map && + (value.containsKey("width") || value.containsKey("color"))) { + value = {"default": value}; } return WidgetStateBorderSideFromJSON( - j, (jv) => borderSideFromJSON(theme, jv), BorderSide.none); + value, (jv) => parseBorderSide(jv, theme), defaultBorderSide); } class WidgetStateBorderSideFromJSON extends WidgetStateBorderSide { - late final Map _states; - late final BorderSide _defaultValue; + late final Map _states; + late final BorderSide? _defaultValue; WidgetStateBorderSideFromJSON( - Map? jsonDictValue, + Map? jsonDictValue, BorderSide? Function(dynamic) converterFromJson, - BorderSide defaultValue) { + BorderSide? defaultValue) { _defaultValue = defaultValue; // preserve user-defined order _states = LinkedHashMap.from( jsonDictValue?.map((k, v) { var key = k.trim().toLowerCase(); - // "" is deprecated and renamed to "default" - if (key == "") key = "default"; return MapEntry(key, converterFromJson(v)); }) ?? {}, @@ -180,12 +164,80 @@ class WidgetStateBorderSideFromJSON extends WidgetStateBorderSide { } WidgetStateProperty? parseWidgetStateOutlinedBorder( - Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } + dynamic value, ThemeData? theme, + {OutlinedBorder? defaultOutlinedBorder, + WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; return getWidgetStateProperty( - jsonDecode(v), (jv) => outlinedBorderFromJSON(jv), null); + value, (jv) => parseOutlinedBorder(jv, theme), defaultOutlinedBorder); +} + +extension BorderParsers on Control { + BorderRadius? getBorderRadius(String propertyName, + [BorderRadius? defaultValue]) { + return parseBorderRadius(get(propertyName), defaultValue); + } + + Radius? getRadius(String propertyName, [Radius? defaultValue]) { + return parseRadius(get(propertyName), defaultValue); + } + + BorderStyle? getBorderStyle(String propertyName, + [BorderStyle? defaultValue]) { + return parseBorderStyle(get(propertyName), defaultValue); + } + + Border? getBorder(String propertyName, ThemeData theme, + {Color defaultSideColor = Colors.black, + BorderSide? defaultBorderSide, + Border? defaultValue}) { + return parseBorder(get(propertyName), theme, + defaultSideColor: defaultSideColor, + defaultBorderSide: defaultBorderSide, + defaultValue: defaultValue); + } + + BorderSide? getBorderSide(String propertyName, ThemeData theme, + {Color defaultSideColor = Colors.black, BorderSide? defaultValue}) { + return parseBorderSide(get(propertyName), theme, + defaultSideColor: defaultSideColor, defaultValue: defaultValue); + } + + OutlinedBorder? getOutlinedBorder(String propertyName, ThemeData? theme, + {BorderSide defaultBorderSide = BorderSide.none, + BorderRadius defaultBorderRadius = BorderRadius.zero, + OutlinedBorder? defaultValue}) { + return parseOutlinedBorder(get(propertyName), theme, + defaultBorderSide: defaultBorderSide, + defaultBorderRadius: defaultBorderRadius, + defaultValue: defaultValue); + } + + OutlinedBorder? getShape(String propertyName, ThemeData? theme, + {BorderSide defaultBorderSide = BorderSide.none, + BorderRadius defaultBorderRadius = BorderRadius.zero, + OutlinedBorder? defaultValue}) { + return parseOutlinedBorder(get(propertyName), theme, + defaultBorderSide: defaultBorderSide, + defaultBorderRadius: defaultBorderRadius, + defaultValue: defaultValue); + } + + WidgetStateBorderSide? getWidgetStateBorderSide( + String propertyName, ThemeData theme, + {BorderSide defaultBorderSide = BorderSide.none, + WidgetStateBorderSide? defaultValue}) { + return parseWidgetStateBorderSide(get(propertyName), theme, + defaultBorderSide: defaultBorderSide, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStateOutlinedBorder( + String propertyName, ThemeData? theme, + {OutlinedBorder? defaultOutlinedBorder, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateOutlinedBorder(get(propertyName), theme, + defaultOutlinedBorder: defaultOutlinedBorder, + defaultValue: defaultValue); + } } diff --git a/packages/flet/lib/src/utils/box.dart b/packages/flet/lib/src/utils/box.dart index bb358d7a80..a4c866581e 100644 --- a/packages/flet/lib/src/utils/box.dart +++ b/packages/flet/lib/src/utils/box.dart @@ -1,115 +1,69 @@ -import 'dart:convert'; -import 'dart:io' as io; -import 'dart:typed_data'; - import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import '../controls/error.dart'; import '../models/control.dart'; -import '../models/page_args_model.dart'; -import 'alignment.dart'; -import 'borders.dart'; -import 'collections.dart'; -import 'colors.dart'; -import 'gradient.dart'; -import 'images.dart'; -import 'numbers.dart'; -import 'others.dart'; +import '../utils/alignment.dart'; +import '../utils/borders.dart'; +import '../utils/colors.dart'; +import '../utils/gradient.dart'; +import '../utils/images.dart'; +import '../utils/misc.dart'; +import '../utils/numbers.dart'; import 'transforms.dart'; -BoxConstraints? parseBoxConstraints(Control control, String propName) { - var v = control.attrString(propName); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return boxConstraintsFromJSON(j1); -} +BoxConstraints? parseBoxConstraints(dynamic value, + [BoxConstraints? defaultValue]) { + if (value == null) return defaultValue; -BoxConstraints? boxConstraintsFromJSON(dynamic json, - [BoxConstraints? defValue]) { - if (json == null) { - return null; - } return BoxConstraints( - minHeight: parseDouble(json["min_height"], 0.0)!, - minWidth: parseDouble(json["min_width"], 0.0)!, - maxHeight: parseDouble(json["max_height"], double.infinity)!, - maxWidth: parseDouble(json["max_width"], double.infinity)!, + minHeight: parseDouble(value["min_height"], 0.0)!, + minWidth: parseDouble(value["min_width"], 0.0)!, + maxHeight: parseDouble(value["max_height"], double.infinity)!, + maxWidth: parseDouble(value["max_width"], double.infinity)!, ); } -List? parseBoxShadow( - ThemeData theme, Control control, String propName, - [List? defValue]) { - var v = control.attrString(propName); - if (v == null) { - return defValue; - } - - final j1 = json.decode(v); - return boxShadowsFromJSON(theme, j1); -} - -List? boxShadowsFromJSON(ThemeData theme, dynamic json, - [List? defValue]) { - if (json == null) { - return defValue; - } - if (json is List) { - return json.map((e) => boxShadowFromJSON(theme, e)).toList(); +List? parseBoxShadows(dynamic value, ThemeData theme, + [List? defaultValue]) { + if (value == null) return defaultValue; + if (value is List) { + return value.map((e) => parseBoxShadow(e, theme)!).toList(); } else { - return [boxShadowFromJSON(theme, json)]; + return [parseBoxShadow(value, theme)!]; } } -BoxShadow boxShadowFromJSON(ThemeData theme, dynamic json) { - var offset = - json["offset"] != null ? offsetDetailsFromJSON(json["offset"]) : null; +BoxShadow? parseBoxShadow(dynamic value, ThemeData theme, + [BoxShadow? defaultValue]) { + if (value == null) return defaultValue; + return BoxShadow( - color: parseColor(theme, json["color"], const Color(0xFF000000))!, - offset: offset != null ? Offset(offset.x, offset.y) : Offset.zero, - blurStyle: json["blur_style"] != null - ? BlurStyle.values - .firstWhere((e) => e.name.toLowerCase() == json["blur_style"]) - : BlurStyle.normal, - blurRadius: parseDouble(json["blur_radius"], 0)!, - spreadRadius: parseDouble(json["spread_radius"], 0)!); + color: parseColor(value["color"], theme, Colors.black)!, + offset: parseOffset(value["offset"], Offset.zero)!, + blurStyle: parseBlurStyle(value["blur_style"], BlurStyle.normal)!, + blurRadius: parseDouble(value["blur_radius"], 0)!, + spreadRadius: parseDouble(value["spread_radius"], 0)!); } -BoxDecoration? parseBoxDecoration(ThemeData theme, Control control, - String propName, PageArgsModel? pageArgs) { - var v = control.attrString(propName); - if (v == null) { - return null; - } +BoxDecoration? parseBoxDecoration(dynamic value, BuildContext context, + [BoxDecoration? defaultValue]) { + if (value == null) return defaultValue; + var theme = Theme.of(context); - final j1 = json.decode(v); - return boxDecorationFromJSON(theme, j1, pageArgs); -} - -BoxDecoration? boxDecorationFromJSON( - ThemeData theme, dynamic json, PageArgsModel? pageArgs) { - if (json == null) { - return null; - } - var shape = parseBoxShape(json["shape"], BoxShape.rectangle)!; - var borderRadius = borderRadiusFromJSON(json["border_radius"]); - var color = parseColor(theme, json["color"]); - var gradient = gradientFromJSON(theme, json["gradient"]); - var blendMode = parseBlendMode(json["blend_mode"]); + var shape = parseBoxShape(value["shape"], BoxShape.rectangle)!; + var borderRadius = parseBorderRadius(value["border_radius"]); + var color = parseColor(value["bgcolor"], theme); + var gradient = parseGradient(value["gradient"], theme); + var blendMode = parseBlendMode(value["blend_mode"]); return BoxDecoration( color: color, - border: borderFromJSON(theme, json["border"]), + border: parseBorder(value["border"], theme), shape: shape, borderRadius: shape == BoxShape.circle ? null : borderRadius, backgroundBlendMode: color != null || gradient != null ? blendMode : null, - boxShadow: boxShadowsFromJSON(theme, json["shadow"]), + boxShadow: parseBoxShadows(value["shadows"], theme), gradient: gradient, - image: decorationImageFromJSON(theme, json["image"], pageArgs), + image: parseDecorationImage(value["image"], context), ); } @@ -123,16 +77,14 @@ BoxDecoration? boxDecorationFromDetails({ Gradient? gradient, DecorationImage? image, }) { - bool hasCustomProperties = color != null || + // If no custom properties are provided, return null + if (!(color != null || border != null || borderRadius != null || gradient != null || shape != null || boxShadow != null || - image != null; - - // If no custom properties are provided, return null - if (!hasCustomProperties) { + image != null)) { return null; } @@ -148,209 +100,48 @@ BoxDecoration? boxDecorationFromDetails({ ); } -DecorationImage? parseDecorationImage(ThemeData theme, Control control, - String propName, PageArgsModel? pageArgs) { - var v = control.attrString(propName); - if (v == null) { - return null; - } +DecorationImage? parseDecorationImage(dynamic value, BuildContext context, + [DecorationImage? defaultValue]) { + if (value == null) return defaultValue; - final j1 = json.decode(v); - return decorationImageFromJSON(theme, j1, pageArgs); -} + var src = value["src"]; + ImageProvider? image = parseImageProvider(src, context); + if (image == null) return defaultValue; -DecorationImage? decorationImageFromJSON( - ThemeData theme, dynamic json, PageArgsModel? pageArgs) { - if (json == null) { - return null; - } - var src = json["src"]; - var srcBase64 = json["src_base64"]; - ImageProvider? image = getImageProvider(src, srcBase64, pageArgs); - if (image == null) { - return null; - } return DecorationImage( image: image, - colorFilter: colorFilterFromJSON(json["color_filter"], theme), - fit: parseBoxFit(json["fit"]), - alignment: alignmentFromJson(json["alignment"], Alignment.center)!, - repeat: parseImageRepeat(json["repeat"], ImageRepeat.noRepeat)!, - matchTextDirection: parseBool(json["match_text_direction"], false)!, - scale: parseDouble(json["scale"], 1.0)!, - opacity: parseDouble(json["opacity"], 1.0)!, + colorFilter: parseColorFilter(value["color_filter"], Theme.of(context)), + fit: parseBoxFit(value["fit"]), + alignment: parseAlignment(value["alignment"], Alignment.center)!, + repeat: parseImageRepeat(value["repeat"], ImageRepeat.noRepeat)!, + matchTextDirection: parseBool(value["match_text_direction"], false)!, + scale: parseDouble(value["scale"], 1.0)!, + opacity: parseDouble(value["opacity"], 1.0)!, filterQuality: - parseFilterQuality(json["filter_quality"], FilterQuality.medium)!, - invertColors: parseBool(json["invert_colors"], false)!, - isAntiAlias: parseBool(json["anti_alias"], false)!, + parseFilterQuality(value["filter_quality"], FilterQuality.medium)!, + invertColors: parseBool(value["invert_colors"], false)!, + isAntiAlias: parseBool(value["anti_alias"], false)!, ); } -ImageProvider? getImageProvider( - String? src, String? srcBase64, PageArgsModel? pageArgs) { - src = src?.trim(); - srcBase64 = srcBase64?.trim(); - - if (srcBase64 != null && srcBase64 != "") { - try { - Uint8List bytes = base64Decode(srcBase64); - return MemoryImage(bytes); - } catch (ex) { - debugPrint("getImageProvider failed decoding srcBase64"); - } +extension BoxParsers on Control { + BoxConstraints? getBoxConstraints(String propertyName, + [BoxConstraints? defaultValue]) { + return parseBoxConstraints(get(propertyName), defaultValue); } - if (src != null && src != "") { - if (pageArgs == null) { - return null; - } - var assetSrc = getAssetSrc(src, pageArgs.pageUri!, pageArgs.assetsDir); - return assetSrc.isFile - ? getFileImageProvider(assetSrc.path) - : NetworkImage(assetSrc.path); + List? getBoxShadows(String propertyName, ThemeData theme, + [List? defaultValue]) { + return parseBoxShadows(get(propertyName), theme, defaultValue); } - return null; -} -Widget buildImage({ - required BuildContext context, - required Control control, - required Widget? errorCtrl, - required String? src, - required String? srcBase64, - double? width, - double? height, - ImageRepeat repeat = ImageRepeat.noRepeat, - BoxFit? fit, - BlendMode? colorBlendMode, - Color? color, - String? semanticsLabel, - bool? gaplessPlayback, - int? cacheWidth, - int? cacheHeight, - bool antiAlias = false, - bool excludeFromSemantics = false, - FilterQuality filterQuality = FilterQuality.low, - bool disabled = false, - required PageArgsModel pageArgs, -}) { - Widget? image; - const String svgTag = " xmlns=\"http://www.w3.org/2000/svg\""; - - if (srcBase64 != null && srcBase64.isNotEmpty) { - try { - Uint8List bytes = base64Decode(srcBase64); - if (arrayIndexOf(bytes, Uint8List.fromList(utf8.encode(svgTag))) != -1) { - image = SvgPicture.memory(bytes, - width: width, - height: height, - fit: fit ?? BoxFit.contain, - colorFilter: color != null - ? ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn) - : null, - semanticsLabel: semanticsLabel); - } else { - image = Image.memory(bytes, - width: width, - height: height, - repeat: repeat, - fit: fit, - color: color, - cacheHeight: cacheHeight, - cacheWidth: cacheWidth, - filterQuality: filterQuality, - isAntiAlias: antiAlias, - colorBlendMode: colorBlendMode, - gaplessPlayback: gaplessPlayback ?? true, - semanticLabel: semanticsLabel); - } - return image; - } catch (ex) { - return ErrorControl("Error decoding base64: ${ex.toString()}"); - } - } else if (src != null && src.isNotEmpty) { - if (src.contains(svgTag)) { - image = SvgPicture.memory(Uint8List.fromList(utf8.encode(src)), - width: width, - height: height, - fit: fit ?? BoxFit.contain, - colorFilter: color != null - ? ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn) - : null, - semanticsLabel: semanticsLabel); - } else { - var assetSrc = getAssetSrc(src, pageArgs.pageUri!, pageArgs.assetsDir); + BoxDecoration? getBoxDecoration(String propertyName, BuildContext context, + [BoxDecoration? defaultValue]) { + return parseBoxDecoration(get(propertyName), context, defaultValue); + } - if (assetSrc.isFile) { - // from File - if (assetSrc.path.endsWith(".svg")) { - image = getSvgPictureFromFile( - src: assetSrc.path, - width: width, - height: height, - fit: fit ?? BoxFit.contain, - color: color, - blendMode: colorBlendMode ?? BlendMode.srcIn, - semanticsLabel: semanticsLabel); - } else { - image = Image.file( - io.File(assetSrc.path), - width: width, - height: height, - repeat: repeat, - filterQuality: filterQuality, - excludeFromSemantics: excludeFromSemantics, - fit: fit, - color: color, - isAntiAlias: antiAlias, - cacheHeight: cacheHeight, - cacheWidth: cacheWidth, - gaplessPlayback: gaplessPlayback ?? false, - colorBlendMode: colorBlendMode, - semanticLabel: semanticsLabel, - errorBuilder: errorCtrl != null - ? (context, error, stackTrace) { - return errorCtrl; - } - : null, - ); - } - } else { - // URL - if (assetSrc.path.endsWith(".svg")) { - image = SvgPicture.network(assetSrc.path, - width: width, - height: height, - excludeFromSemantics: excludeFromSemantics, - fit: fit ?? BoxFit.contain, - colorFilter: color != null - ? ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn) - : null, - semanticsLabel: semanticsLabel); - } else { - image = Image.network(assetSrc.path, - width: width, - height: height, - repeat: repeat, - filterQuality: filterQuality, - cacheHeight: cacheHeight, - cacheWidth: cacheWidth, - isAntiAlias: antiAlias, - excludeFromSemantics: excludeFromSemantics, - fit: fit, - color: color, - gaplessPlayback: gaplessPlayback ?? false, - colorBlendMode: colorBlendMode, - semanticLabel: semanticsLabel, - errorBuilder: errorCtrl != null - ? (context, error, stackTrace) { - return errorCtrl; - } - : null); - } - } - } - return image; + DecorationImage? getDecorationImage(String propertyName, BuildContext context, + [DecorationImage? defaultValue]) { + return parseDecorationImage(get(propertyName), context, defaultValue); } - return const ErrorControl("A valid src or src_base64 must be specified."); } diff --git a/packages/flet/lib/src/utils/browser_context_menu.dart b/packages/flet/lib/src/utils/browser_context_menu.dart deleted file mode 100644 index 13cf0982da..0000000000 --- a/packages/flet/lib/src/utils/browser_context_menu.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter/services.dart'; - -Future disableBrowserContextMenu() async { - return BrowserContextMenu.disableContextMenu(); -} - -Future enableBrowserContextMenu() async { - return BrowserContextMenu.enableContextMenu(); -} diff --git a/packages/flet/lib/src/utils/buttons.dart b/packages/flet/lib/src/utils/buttons.dart index 9a2449bab3..7284df917a 100644 --- a/packages/flet/lib/src/utils/buttons.dart +++ b/packages/flet/lib/src/utils/buttons.dart @@ -1,6 +1,4 @@ -import 'dart:convert'; - -import 'package:flet/src/utils/transforms.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; @@ -8,13 +6,17 @@ import 'alignment.dart'; import 'borders.dart'; import 'colors.dart'; import 'edge_insets.dart'; -import 'material_state.dart'; +import 'enums.dart'; +import 'geometry.dart'; import 'mouse.dart'; import 'numbers.dart'; import 'text.dart'; import 'theme.dart'; +import 'time.dart'; +import 'transforms.dart'; +import 'widget_state.dart'; -ButtonStyle? parseButtonStyle(ThemeData theme, Control control, String propName, +ButtonStyle? parseButtonStyle(dynamic value, ThemeData theme, {Color? defaultForegroundColor, Color? defaultBackgroundColor, Color? defaultOverlayColor, @@ -23,80 +25,64 @@ ButtonStyle? parseButtonStyle(ThemeData theme, Control control, String propName, double? defaultElevation, EdgeInsets? defaultPadding, BorderSide? defaultBorderSide, - OutlinedBorder? defaultShape}) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } + OutlinedBorder? defaultShape, + TextStyle? defaultTextStyle, + ButtonStyle? defaultValue}) { + if (value == null) return defaultValue; - final j1 = json.decode(v); - return buttonStyleFromJSON( - theme, - j1, - defaultForegroundColor, - defaultBackgroundColor, - defaultOverlayColor, - defaultShadowColor, - defaultSurfaceTintColor, - defaultElevation, - defaultPadding, - defaultBorderSide, - defaultShape); -} + WidgetStateProperty? parseButtonTextStyle( + dynamic value, ThemeData theme, + {TextStyle? defaultTextStyle}) { + final ts = parseWidgetStateTextStyle(value, theme, + defaultTextStyle: defaultTextStyle); + if (ts == null) return null; -ButtonStyle? buttonStyleFromJSON(ThemeData theme, Map? json, - [Color? defaultForegroundColor, - Color? defaultBackgroundColor, - Color? defaultOverlayColor, - Color? defaultShadowColor, - Color? defaultSurfaceTintColor, - double? defaultElevation, - EdgeInsets? defaultPadding, - BorderSide? defaultBorderSide, - OutlinedBorder? defaultShape]) { - if (json == null) { - return null; + // Match Material button defaults to avoid TextStyle.lerp assertions when + // animating between states. + return WidgetStateProperty.resolveWith((Set states) { + final resolved = ts.resolve(states); + return resolved?.copyWith(inherit: false); + }); } + return ButtonStyle( - foregroundColor: getWidgetStateProperty(json["color"], - (jv) => parseColor(theme, jv as String), defaultForegroundColor), - backgroundColor: getWidgetStateProperty(json["bgcolor"], - (jv) => parseColor(theme, jv as String), defaultBackgroundColor), - overlayColor: getWidgetStateProperty(json["overlay_color"], - (jv) => parseColor(theme, jv as String), defaultOverlayColor), - shadowColor: getWidgetStateProperty(json["shadow_color"], - (jv) => parseColor(theme, jv as String), defaultShadowColor), - surfaceTintColor: getWidgetStateProperty(json["surface_tint_color"], - (jv) => parseColor(theme, jv as String), defaultSurfaceTintColor), - elevation: getWidgetStateProperty( - json["elevation"], (jv) => parseDouble(jv, 0)!, defaultElevation), - animationDuration: json["animation_duration"] != null - ? Duration(milliseconds: parseInt(json["animation_duration"], 0)!) - : null, - padding: getWidgetStateProperty( - json["padding"], (jv) => edgeInsetsFromJson(jv), defaultPadding), + foregroundColor: parseWidgetStateColor(value["color"], theme, + defaultColor: defaultForegroundColor), + backgroundColor: parseWidgetStateColor(value["bgcolor"], theme, + defaultColor: defaultBackgroundColor), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme, + defaultColor: defaultOverlayColor), + shadowColor: parseWidgetStateColor(value["shadow_color"], theme, + defaultColor: defaultShadowColor), + elevation: parseWidgetStateDouble(value["elevation"], + defaultDouble: defaultElevation), + animationDuration: parseDuration(value["animation_duration"]), + padding: parseWidgetStatePadding(value["padding"], + defaultPadding: defaultPadding), side: getWidgetStateProperty( - json["side"], - (jv) => borderSideFromJSON(theme, jv, theme.colorScheme.outline), + value["side"], + (jv) => parseBorderSide(jv, theme, + defaultSideColor: theme.colorScheme.outline), defaultBorderSide), - shape: getWidgetStateProperty( - json["shape"], (jv) => outlinedBorderFromJSON(jv), defaultShape), - iconColor: getWidgetStateProperty(json["icon_color"], - (jv) => parseColor(theme, jv as String), defaultForegroundColor), - alignment: alignmentFromJson(json["alignment"]), - enableFeedback: parseBool(json["enable_feedback"]), - textStyle: getWidgetStateProperty( - json["text_style"], (jv) => textStyleFromJson(theme, jv)), - iconSize: getWidgetStateProperty( - json["icon_size"], (jv) => parseDouble(jv)), - visualDensity: parseVisualDensity(json["visual_density"]), - mouseCursor: getWidgetStateProperty( - json["mouse_cursor"], (jv) => parseMouseCursor(jv)), + shape: parseWidgetStateOutlinedBorder(value["shape"], theme, + defaultOutlinedBorder: defaultShape), + iconColor: parseWidgetStateColor(value["icon_color"], theme, + defaultColor: defaultForegroundColor), + alignment: parseAlignment(value["alignment"]), + enableFeedback: parseBool(value["enable_feedback"]), + textStyle: parseButtonTextStyle(value["text_style"], theme, + defaultTextStyle: defaultTextStyle), + iconSize: parseWidgetStateDouble(value["icon_size"]), + visualDensity: parseVisualDensity(value["visual_density"]), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + fixedSize: parseWidgetStateSize(value["fixed_size"]), + maximumSize: parseWidgetStateSize(value["maximum_size"]), + minimumSize: parseWidgetStateSize(value["minimum_size"]), ); } -FloatingActionButtonLocation? parseFloatingActionButtonLocation( - Control control, String propName, [FloatingActionButtonLocation? defValue]) { +FloatingActionButtonLocation? parseFloatingActionButtonLocation(dynamic value, + [FloatingActionButtonLocation? defaultValue]) { const Map fabLocations = { "centerdocked": FloatingActionButtonLocation.centerDocked, "centerfloat": FloatingActionButtonLocation.centerFloat, @@ -119,16 +105,15 @@ FloatingActionButtonLocation? parseFloatingActionButtonLocation( }; try { - var fabLocationOffset = parseOffset(control, propName); - if (fabLocationOffset != null) { - return CustomFloatingActionButtonLocation( - dx: fabLocationOffset.dx, dy: fabLocationOffset.dy); - } else { - return defValue; - } + var fabLocationOffset = parseOffset(value); + + return fabLocationOffset != null + ? CustomFloatingActionButtonLocation( + dx: fabLocationOffset.dx, dy: fabLocationOffset.dy) + : defaultValue; } catch (e) { - var key = control.attrString(propName, "")!.toLowerCase(); - return fabLocations.containsKey(key) ? fabLocations[key]! : defValue; + var key = value.toLowerCase(); + return fabLocations.containsKey(key) ? fabLocations[key]! : defaultValue; } } @@ -156,3 +141,45 @@ class CustomFloatingActionButtonLocation extends FloatingActionButtonLocation { @override String toString() => 'CustomFloatingActionButtonLocation(dx: $dx, dy: $dy)'; } + +CupertinoButtonSize? parseCupertinoButtonSize(String? value, + [CupertinoButtonSize? defaultValue]) { + return parseEnum(CupertinoButtonSize.values, value, defaultValue); +} + +extension ButtonParsers on Control { + ButtonStyle? getButtonStyle(String propertyName, ThemeData theme, + {Color? defaultForegroundColor, + Color? defaultBackgroundColor, + Color? defaultOverlayColor, + Color? defaultShadowColor, + Color? defaultSurfaceTintColor, + double? defaultElevation, + EdgeInsets? defaultPadding, + BorderSide? defaultBorderSide, + OutlinedBorder? defaultShape, + ButtonStyle? defaultValue}) { + return parseButtonStyle(get(propertyName), theme, + defaultForegroundColor: defaultForegroundColor, + defaultBackgroundColor: defaultBackgroundColor, + defaultOverlayColor: defaultOverlayColor, + defaultShadowColor: defaultShadowColor, + defaultSurfaceTintColor: defaultSurfaceTintColor, + defaultElevation: defaultElevation, + defaultPadding: defaultPadding, + defaultBorderSide: defaultBorderSide, + defaultShape: defaultShape, + defaultValue: defaultValue); + } + + FloatingActionButtonLocation? getFloatingActionButtonLocation( + String propertyName, + [FloatingActionButtonLocation? defaultValue]) { + return parseFloatingActionButtonLocation(get(propertyName), defaultValue); + } + + CupertinoButtonSize? getCupertinoButtonSize(String propertyName, + [CupertinoButtonSize? defaultValue]) { + return parseCupertinoButtonSize(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/charts.dart b/packages/flet/lib/src/utils/charts.dart deleted file mode 100644 index 48145ecbe0..0000000000 --- a/packages/flet/lib/src/utils/charts.dart +++ /dev/null @@ -1,224 +0,0 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; - -import '../models/control.dart'; -import '../utils/gradient.dart'; -import 'colors.dart'; -import 'numbers.dart'; - -FlGridData parseChartGridData(ThemeData theme, Control control, - String horizPropName, String vertPropName) { - var hv = control.attrString(horizPropName, null); - var vv = control.attrString(vertPropName, null); - if (hv == null && vv == null) { - return const FlGridData(show: false); - } - - var hj = hv != null ? json.decode(hv) : null; - var vj = vv != null ? json.decode(vv) : null; - var hLine = flineFromJSON(theme, hj); - var vLine = flineFromJSON(theme, vj); - - return FlGridData( - show: true, - drawHorizontalLine: hv != null, - horizontalInterval: hj != null && hj["interval"] != null - ? parseDouble(hj["interval"]) - : null, - getDrawingHorizontalLine: - hLine == null ? defaultGridLine : (value) => hLine, - drawVerticalLine: vv != null, - verticalInterval: vj != null && vj["interval"] != null - ? parseDouble(vj["interval"]) - : null, - getDrawingVerticalLine: vLine == null ? defaultGridLine : (value) => vLine, - ); -} - -FlLine? parseFlLine(ThemeData theme, Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j = json.decode(v); - return flineFromJSON(theme, j); -} - -FlLine? parseSelectedFlLine(ThemeData theme, Control control, String propName, - Color? color, Gradient? gradient) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j = json.decode(v); - if (j == false) { - return getInvisibleLine(); - } else if (j == true) { - return FlLine( - color: defaultGetPointColor(color, gradient, 0), strokeWidth: 3); - } - return FlLine( - color: j['color'] != null - ? parseColor(theme, j['color'] as String, Colors.black)! - : defaultGetPointColor(color, gradient, 0), - strokeWidth: parseDouble(j['width'], 2)!, - dashArray: j['dash_pattern'] != null - ? (j['dash_pattern'] as List) - .map((e) => parseInt(e)) - .whereNotNull() - .toList() - : null); -} - -FlLine? flineFromJSON(theme, j) { - if (j == null || - (j['color'] == null && j['width'] == null && j['dash_pattern'] == null)) { - return null; - } - return FlLine( - color: j['color'] != null - ? parseColor(theme, j['color'] as String) ?? Colors.black - : Colors.black, - strokeWidth: parseDouble(j['width'], 2)!, - dashArray: j['dash_pattern'] != null - ? (j['dash_pattern'] as List) - .map((e) => parseInt(e)) - .whereNotNull() - .toList() - : null); -} - -FlDotPainter? parseChartDotPainter( - ThemeData theme, - Control control, - String propName, - Color? barColor, - Gradient? barGradient, - double percentage) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j = json.decode(v); - if (j == false) { - return getInvisiblePainter(); - } else if (j == true) { - return getDefaultPainter(barColor, barGradient, percentage); - } - return chartDotPainterFromJSON(theme, j, barColor, barGradient, percentage); -} - -FlDotPainter? parseChartSelectedDotPainter( - ThemeData theme, - Control control, - String propName, - Color? barColor, - Gradient? barGradient, - double percentage) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j = json.decode(v); - if (j == false) { - return getInvisiblePainter(); - } else if (j == true) { - return getDefaultSelectedPainter(barColor, barGradient, percentage); - } - return chartDotPainterFromJSON(theme, j, barColor, barGradient, percentage); -} - -FlDotPainter? chartDotPainterFromJSON( - ThemeData theme, - Map json, - Color? barColor, - Gradient? barGradient, - double percentage) { - String type = json["type"]; - if (type == "circle") { - return FlDotCirclePainter( - color: json['color'] != null - ? parseColor(theme, json['color'] as String) ?? Colors.green - : defaultGetPointColor(barColor, barGradient, percentage), - radius: parseDouble(json["radius"]), - strokeColor: json['stroke_color'] != null - ? parseColor(theme, json['color'] as String) ?? - const Color.fromRGBO(76, 175, 80, 1) - : defaultGetDotStrokeColor(barColor, barGradient, percentage), - strokeWidth: parseDouble(json["stroke_width"], 1.0)!); - } else if (type == "square") { - return FlDotSquarePainter( - color: json['color'] != null - ? parseColor(theme, json['color'] as String) ?? Colors.green - : defaultGetPointColor(barColor, barGradient, percentage), - size: parseDouble(json["size"], 4.0)!, - strokeColor: json['stroke_color'] != null - ? parseColor(theme, json['color'] as String) ?? - const Color.fromRGBO(76, 175, 80, 1) - : defaultGetDotStrokeColor(barColor, barGradient, percentage), - strokeWidth: parseDouble(json["stroke_width"], 1.0)!); - } else if (type == "cross") { - return FlDotCrossPainter( - color: json['color'] != null - ? parseColor(theme, json['color'] as String) ?? Colors.green - : defaultGetDotStrokeColor(barColor, barGradient, percentage), - size: parseDouble(json["size"], 8.0)!, - width: parseDouble(json["width"], 2.0)!, - ); - } - return null; -} - -FlDotPainter getInvisiblePainter() { - return FlDotCirclePainter(radius: 0, strokeWidth: 0); -} - -FlLine getInvisibleLine() { - return const FlLine(strokeWidth: 0); -} - -FlDotPainter getDefaultPainter( - Color? barColor, Gradient? barGradient, double percentage) { - return FlDotCirclePainter( - radius: 4, - color: defaultGetPointColor(barColor, barGradient, percentage), - strokeColor: defaultGetDotStrokeColor(barColor, barGradient, percentage), - strokeWidth: 1); -} - -FlDotPainter getDefaultSelectedPainter( - Color? barColor, Gradient? barGradient, double percentage) { - return FlDotCirclePainter( - radius: 8, - color: defaultGetPointColor(barColor, barGradient, percentage), - strokeColor: defaultGetDotStrokeColor(barColor, barGradient, percentage), - strokeWidth: 2); -} - -Color defaultGetPointColor( - Color? barColor, Gradient? barGradient, double percentage) { - if (barGradient != null && barGradient is LinearGradient) { - return lerpGradient( - barGradient.colors, barGradient.getSafeColorStops(), percentage / 100); - } - return barGradient?.colors.first ?? barColor ?? Colors.blueGrey; -} - -Color defaultGetDotStrokeColor( - Color? barColor, Gradient? barGradient, double percentage) { - Color color; - if (barGradient != null && barGradient is LinearGradient) { - color = lerpGradient( - barGradient.colors, barGradient.getSafeColorStops(), percentage / 100); - } else { - color = barGradient?.colors.first ?? barColor ?? Colors.blueGrey; - } - return color.darken(); -} diff --git a/packages/flet/lib/src/utils/client_storage.dart b/packages/flet/lib/src/utils/client_storage.dart deleted file mode 100644 index d66fddc4d1..0000000000 --- a/packages/flet/lib/src/utils/client_storage.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'dart:convert'; - -import 'package:shared_preferences/shared_preferences.dart'; - -import '../flet_control_backend.dart'; -import '../protocol/invoke_method_result.dart'; - -void invokeClientStorage(String methodId, String methodName, - Map args, FletControlBackend backend) async { - sendResult(Object? result, String? error) { - backend.triggerControlEvent( - "page", - "invoke_method_result", - json.encode(InvokeMethodResult( - methodId: methodId, - result: result != null ? json.encode(result) : null, - error: error))); - } - - var prefs = await SharedPreferences.getInstance(); - switch (methodName) { - case "set": - var result = await prefs.setString(args["key"]!, args["value"]!); - sendResult(result, null); - break; - case "get": - sendResult(prefs.getString(args["key"]!), null); - break; - case "containskey": - sendResult(prefs.containsKey(args["key"]!), null); - break; - case "getkeys": - sendResult( - prefs - .getKeys() - .where((key) => key.startsWith(args["key_prefix"]!)) - .toList(), - null); - break; - case "remove": - sendResult(await prefs.remove(args["key"]!), null); - break; - case "clear": - sendResult(await prefs.clear(), null); - break; - } -} diff --git a/packages/flet/lib/src/utils/clipboard.dart b/packages/flet/lib/src/utils/clipboard.dart deleted file mode 100644 index 160d27ac60..0000000000 --- a/packages/flet/lib/src/utils/clipboard.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/services.dart'; - -void setClipboard(String data) async { - await Clipboard.setData(ClipboardData(text: data)); -} - -Future getClipboard() async { - var data = await Clipboard.getData(Clipboard.kTextPlain); - return data?.text; -} diff --git a/packages/flet/lib/src/utils/collections.dart b/packages/flet/lib/src/utils/collections.dart index 57fa2d8271..d26ff9e3f2 100644 --- a/packages/flet/lib/src/utils/collections.dart +++ b/packages/flet/lib/src/utils/collections.dart @@ -1,8 +1,18 @@ import 'dart:typed_data'; +/// Returns the first index of `needle` inside `haystack`, or `-1` if not found. +/// +/// This performs a naive byte-wise search (O(haystack.length * needle.length) +/// worst-case). If `needle` is empty the function returns `0`. +/// +/// Example: +/// ```dart +/// arrayIndexOf(Uint8List.fromList([1, 2, 3, 4]), Uint8List.fromList([2, 3])) == 1; +/// ``` int arrayIndexOf(Uint8List haystack, Uint8List needle) { - var len = needle.length; - var limit = haystack.length - len; + final len = needle.length; + if (len == 0) return 0; + final limit = haystack.length - len; for (var i = 0; i <= limit; i++) { var k = 0; for (; k < len; k++) { diff --git a/packages/flet/lib/src/utils/colors.dart b/packages/flet/lib/src/utils/colors.dart index 5083f33e1e..60376af2bb 100644 --- a/packages/flet/lib/src/utils/colors.dart +++ b/packages/flet/lib/src/utils/colors.dart @@ -1,15 +1,14 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import '../models/control.dart'; import 'cupertino_colors.dart'; -import 'material_state.dart'; import 'numbers.dart'; +import 'widget_state.dart'; Color? _getThemeColor(ThemeData theme, String colorName) { var scheme = theme.colorScheme; switch (colorName.toLowerCase()) { + // Primary colors case "primary": return scheme.primary; case "onprimary": @@ -18,6 +17,16 @@ Color? _getThemeColor(ThemeData theme, String colorName) { return scheme.primaryContainer; case "onprimarycontainer": return scheme.onPrimaryContainer; + case "primaryfixed": + return scheme.primaryFixed; + case "primaryfixeddim": + return scheme.primaryFixedDim; + case "onprimaryfixed": + return scheme.onPrimaryFixed; + case "onprimaryfixedvariant": + return scheme.onPrimaryFixedVariant; + + // Secondary colors case "secondary": return scheme.secondary; case "onsecondary": @@ -26,6 +35,16 @@ Color? _getThemeColor(ThemeData theme, String colorName) { return scheme.secondaryContainer; case "onsecondarycontainer": return scheme.onSecondaryContainer; + case "secondaryfixed": + return scheme.secondaryFixed; + case "secondaryfixeddim": + return scheme.secondaryFixedDim; + case "onsecondaryfixed": + return scheme.onSecondaryFixed; + case "onsecondaryfixedvariant": + return scheme.onSecondaryFixedVariant; + + // Tertiary colors case "tertiary": return scheme.tertiary; case "ontertiary": @@ -34,6 +53,16 @@ Color? _getThemeColor(ThemeData theme, String colorName) { return scheme.tertiaryContainer; case "ontertiarycontainer": return scheme.onTertiaryContainer; + case "tertiaryfixed": + return scheme.tertiaryFixed; + case "tertiaryfixeddim": + return scheme.tertiaryFixedDim; + case "ontertiaryfixed": + return scheme.onTertiaryFixed; + case "ontertiaryfixedvariant": + return scheme.onTertiaryFixedVariant; + + // Error colors case "error": return scheme.error; case "onerror": @@ -42,33 +71,48 @@ Color? _getThemeColor(ThemeData theme, String colorName) { return scheme.errorContainer; case "onerrorcontainer": return scheme.onErrorContainer; - case "outline": - return scheme.outline; - case "outlinevariant": - return scheme.outlineVariant; - case "background": + + // Surface colors case "surface": return scheme.surface; - case "onbackground": case "onsurface": return scheme.onSurface; - case "surfacevariant": + case "surfacebright": + return scheme.surfaceBright; + case "surfacedim": + return scheme.surfaceDim; + case "surfacecontainer": + return scheme.surfaceContainer; + case "surfacecontainerhigh": + return scheme.surfaceContainerHigh; + case "surfacecontainerlow": + return scheme.surfaceContainerLow; + case "surfacecontainerlowest": + return scheme.surfaceContainerLowest; case "surfacecontainerhighest": return scheme.surfaceContainerHighest; + + // Utility colors + case "outline": + return scheme.outline; + case "outlinevariant": + return scheme.outlineVariant; + case "shadow": + return scheme.shadow; + case "scrim": + return scheme.scrim; case "onsurfacevariant": return scheme.onSurfaceVariant; case "surfacetint": return scheme.surfaceTint; + + // Inverse colors case "inversesurface": return scheme.inverseSurface; case "oninversesurface": return scheme.onInverseSurface; case "inverseprimary": return scheme.inversePrimary; - case "shadow": - return scheme.shadow; - case "scrim": - return scheme.scrim; } return null; } @@ -156,7 +200,7 @@ extension HexColor on Color { } if (color != null && colorOpacity != null) { - color = color.withOpacity(parseDouble(colorOpacity, 1.0)!); + color = color.withValues(alpha: parseDouble(colorOpacity, 1.0)!); } return color ?? defaultColor; @@ -209,20 +253,37 @@ extension HexColor on Color { return null; } - /// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#". - static Color _fromHex(String hexString) { + /// String is in CSS hex format: "rgb", "argb", "rrggbb" or "aarrggbb" + /// (the leading "#" or "0x" is stripped by the caller). + /// Shorthand 3/4-digit forms are expanded by doubling each character + /// (e.g. "c00" -> "cc0000", "fc00" -> "ffcc0000"). + static Color? _fromHex(String hexString) { + if (hexString.length == 3 || hexString.length == 4) { + hexString = hexString.split('').map((c) => '$c$c').join(''); + } + if (hexString.length != 6 && hexString.length != 8) return null; final buffer = StringBuffer(); if (hexString.length == 6) buffer.write('ff'); buffer.write(hexString); - return Color(int.parse(buffer.toString(), radix: 16)); + final value = int.tryParse(buffer.toString(), radix: 16); + return value == null ? null : Color(value); } /// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`). - String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}' - '${alpha.toRadixString(16).padLeft(2, '0')}' - '${red.toRadixString(16).padLeft(2, '0')}' - '${green.toRadixString(16).padLeft(2, '0')}' - '${blue.toRadixString(16).padLeft(2, '0')}'; + String toHex({bool leadingHashSign = true}) { + int to8bit(double component) => (component * 255.0).round().clamp(0, 255); + + final alpha8 = to8bit(a); + final red8 = to8bit(r); + final green8 = to8bit(g); + final blue8 = to8bit(b); + + return '${leadingHashSign ? '#' : ''}' + '${alpha8.toRadixString(16).padLeft(2, '0')}' + '${red8.toRadixString(16).padLeft(2, '0')}' + '${green8.toRadixString(16).padLeft(2, '0')}' + '${blue8.toRadixString(16).padLeft(2, '0')}'; + } } extension ColorExtension on Color { @@ -230,27 +291,40 @@ extension ColorExtension on Color { Color darken([int percent = 40]) { assert(1 <= percent && percent <= 100); final value = 1 - percent / 100; + int to8bit(double component) => (component * 255.0).round().clamp(0, 255); + return Color.fromARGB( - alpha, - (red * value).round(), - (green * value).round(), - (blue * value).round(), + to8bit(a), + (to8bit(r) * value).round().clamp(0, 255), + (to8bit(g) * value).round().clamp(0, 255), + (to8bit(b) * value).round().clamp(0, 255), ); } } -WidgetStateProperty? parseWidgetStateColor(ThemeData theme, - Control control, String propName, - [Color? defaultValue]) { - var v = control.attrString(propName); - if (v == null) { - return null; - } +WidgetStateProperty? parseWidgetStateColor( + dynamic value, ThemeData theme, + {Color? defaultColor, WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; - return getWidgetStateProperty(jsonDecode(v), - (jv) => HexColor.fromString(theme, jv as String), defaultValue); + return getWidgetStateProperty( + value, (jv) => HexColor.fromString(theme, jv as String), defaultColor); } -Color? parseColor(ThemeData? theme, String? colorString, - [Color? defaultColor]) => - HexColor.fromString(theme, colorString, defaultColor); +Color? parseColor(String? value, ThemeData? theme, [Color? defaultColor]) => + HexColor.fromString(theme, value, defaultColor); + +extension ColorParsers on Control { + Color? getColor(String propertyName, BuildContext? context, + [Color? defaultValue]) { + return parseColor(getString(propertyName), + context != null ? Theme.of(context) : null, defaultValue); + } + + WidgetStateProperty? getWidgetStateColor( + String propertyName, ThemeData theme, + {Color? defaultColor, WidgetStateProperty? defaultValue}) { + return parseWidgetStateColor(get(propertyName), theme, + defaultColor: defaultColor, defaultValue: defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/control.dart b/packages/flet/lib/src/utils/control.dart new file mode 100644 index 0000000000..72e27aeeb2 --- /dev/null +++ b/packages/flet/lib/src/utils/control.dart @@ -0,0 +1,30 @@ +import 'package:flutter/widgets.dart'; + +import '../controls/control_widget.dart'; +import '../models/control.dart'; + +/// Converts a protocol value containing a Flet control into a Flutter widget. +/// +/// Returns `null` when [value] is not a control, or when [visibleOnly] is `true` +/// and the control is not visible. +Widget? parseControlWidget(dynamic value, {bool visibleOnly = true}) { + if (value is! Control) return null; + + final control = value.unwrapComponent(); + if (visibleOnly && !control.visible) return null; + + return ControlWidget(control: control); +} + +/// Converts a protocol value containing Flet controls into Flutter widgets. +/// +/// Returns `null` when [value] is not a list, allowing callers to distinguish a +/// missing field from an explicitly provided empty list. +List? parseControlWidgets(dynamic value, {bool visibleOnly = true}) { + if (value is! List) return null; + + return value + .map((value) => parseControlWidget(value, visibleOnly: visibleOnly)) + .nonNulls + .toList(); +} diff --git a/packages/flet/lib/src/utils/cupertino_icons.dart b/packages/flet/lib/src/utils/cupertino_icons.dart index 9ec551bb87..881b8ed488 100644 --- a/packages/flet/lib/src/utils/cupertino_icons.dart +++ b/packages/flet/lib/src/utils/cupertino_icons.dart @@ -1,1472 +1,1326 @@ import 'package:flutter/cupertino.dart'; -/* - -To generate update the list run: - -sh ci/generate_cupertino_icons_dart.sh - -*/ - -Map cupertinoIcons = { - "cupertino_left_chevron": CupertinoIcons.left_chevron, - "cupertino_right_chevron": CupertinoIcons.right_chevron, - "cupertino_share": CupertinoIcons.share, - "cupertino_share_solid": CupertinoIcons.share_solid, - "cupertino_book": CupertinoIcons.book, - "cupertino_book_solid": CupertinoIcons.book_solid, - "cupertino_bookmark": CupertinoIcons.bookmark, - "cupertino_bookmark_solid": CupertinoIcons.bookmark_solid, - "cupertino_info": CupertinoIcons.info, - "cupertino_reply": CupertinoIcons.reply, - "cupertino_conversation_bubble": CupertinoIcons.conversation_bubble, - "cupertino_profile_circled": CupertinoIcons.profile_circled, - "cupertino_plus_circled": CupertinoIcons.plus_circled, - "cupertino_minus_circled": CupertinoIcons.minus_circled, - "cupertino_flag": CupertinoIcons.flag, - "cupertino_search": CupertinoIcons.search, - "cupertino_check_mark": CupertinoIcons.check_mark, - "cupertino_check_mark_circled": CupertinoIcons.check_mark_circled, - "cupertino_check_mark_circled_solid": CupertinoIcons.check_mark_circled_solid, - "cupertino_circle": CupertinoIcons.circle, - "cupertino_circle_filled": CupertinoIcons.circle_filled, - "cupertino_back": CupertinoIcons.back, - "cupertino_forward": CupertinoIcons.forward, - "cupertino_home": CupertinoIcons.home, - "cupertino_shopping_cart": CupertinoIcons.shopping_cart, - "cupertino_ellipsis": CupertinoIcons.ellipsis, - "cupertino_phone": CupertinoIcons.phone, - "cupertino_phone_solid": CupertinoIcons.phone_solid, - "cupertino_down_arrow": CupertinoIcons.down_arrow, - "cupertino_up_arrow": CupertinoIcons.up_arrow, - "cupertino_battery_charging": CupertinoIcons.battery_charging, - "cupertino_battery_empty": CupertinoIcons.battery_empty, - "cupertino_battery_full": CupertinoIcons.battery_full, - "cupertino_battery_75_percent": CupertinoIcons.battery_75_percent, - "cupertino_battery_25_percent": CupertinoIcons.battery_25_percent, - "cupertino_bluetooth": CupertinoIcons.bluetooth, - "cupertino_restart": CupertinoIcons.restart, - "cupertino_reply_all": CupertinoIcons.reply_all, - "cupertino_reply_thick_solid": CupertinoIcons.reply_thick_solid, - "cupertino_share_up": CupertinoIcons.share_up, - "cupertino_shuffle": CupertinoIcons.shuffle, - "cupertino_shuffle_medium": CupertinoIcons.shuffle_medium, - "cupertino_shuffle_thick": CupertinoIcons.shuffle_thick, - "cupertino_photo_camera": CupertinoIcons.photo_camera, - "cupertino_photo_camera_solid": CupertinoIcons.photo_camera_solid, - "cupertino_video_camera": CupertinoIcons.video_camera, - "cupertino_video_camera_solid": CupertinoIcons.video_camera_solid, - "cupertino_switch_camera": CupertinoIcons.switch_camera, - "cupertino_switch_camera_solid": CupertinoIcons.switch_camera_solid, - "cupertino_collections": CupertinoIcons.collections, - "cupertino_collections_solid": CupertinoIcons.collections_solid, - "cupertino_folder": CupertinoIcons.folder, - "cupertino_folder_solid": CupertinoIcons.folder_solid, - "cupertino_folder_open": CupertinoIcons.folder_open, - "cupertino_delete": CupertinoIcons.delete, - "cupertino_delete_solid": CupertinoIcons.delete_solid, - "cupertino_delete_simple": CupertinoIcons.delete_simple, - "cupertino_pen": CupertinoIcons.pen, - "cupertino_pencil": CupertinoIcons.pencil, - "cupertino_create": CupertinoIcons.create, - "cupertino_create_solid": CupertinoIcons.create_solid, - "cupertino_refresh": CupertinoIcons.refresh, - "cupertino_refresh_circled": CupertinoIcons.refresh_circled, - "cupertino_refresh_circled_solid": CupertinoIcons.refresh_circled_solid, - "cupertino_refresh_thin": CupertinoIcons.refresh_thin, - "cupertino_refresh_thick": CupertinoIcons.refresh_thick, - "cupertino_refresh_bold": CupertinoIcons.refresh_bold, - "cupertino_clear_thick": CupertinoIcons.clear_thick, - "cupertino_clear_thick_circled": CupertinoIcons.clear_thick_circled, - "cupertino_clear": CupertinoIcons.clear, - "cupertino_clear_circled": CupertinoIcons.clear_circled, - "cupertino_clear_circled_solid": CupertinoIcons.clear_circled_solid, - "cupertino_add": CupertinoIcons.add, - "cupertino_add_circled": CupertinoIcons.add_circled, - "cupertino_add_circled_solid": CupertinoIcons.add_circled_solid, - "cupertino_gear": CupertinoIcons.gear, - "cupertino_gear_solid": CupertinoIcons.gear_solid, - "cupertino_gear_big": CupertinoIcons.gear_big, - "cupertino_settings": CupertinoIcons.settings, - "cupertino_settings_solid": CupertinoIcons.settings_solid, - "cupertino_music_note": CupertinoIcons.music_note, - "cupertino_double_music_note": CupertinoIcons.double_music_note, - "cupertino_play_arrow": CupertinoIcons.play_arrow, - "cupertino_play_arrow_solid": CupertinoIcons.play_arrow_solid, - "cupertino_pause": CupertinoIcons.pause, - "cupertino_pause_solid": CupertinoIcons.pause_solid, - "cupertino_loop": CupertinoIcons.loop, - "cupertino_loop_thick": CupertinoIcons.loop_thick, - "cupertino_volume_down": CupertinoIcons.volume_down, - "cupertino_volume_mute": CupertinoIcons.volume_mute, - "cupertino_volume_off": CupertinoIcons.volume_off, - "cupertino_volume_up": CupertinoIcons.volume_up, - "cupertino_fullscreen": CupertinoIcons.fullscreen, - "cupertino_fullscreen_exit": CupertinoIcons.fullscreen_exit, - "cupertino_mic_off": CupertinoIcons.mic_off, - "cupertino_mic": CupertinoIcons.mic, - "cupertino_mic_solid": CupertinoIcons.mic_solid, - "cupertino_clock": CupertinoIcons.clock, - "cupertino_clock_solid": CupertinoIcons.clock_solid, - "cupertino_time": CupertinoIcons.time, - "cupertino_time_solid": CupertinoIcons.time_solid, - "cupertino_padlock": CupertinoIcons.padlock, - "cupertino_padlock_solid": CupertinoIcons.padlock_solid, - "cupertino_eye": CupertinoIcons.eye, - "cupertino_eye_solid": CupertinoIcons.eye_solid, - "cupertino_person": CupertinoIcons.person, - "cupertino_person_solid": CupertinoIcons.person_solid, - "cupertino_person_add": CupertinoIcons.person_add, - "cupertino_person_add_solid": CupertinoIcons.person_add_solid, - "cupertino_group": CupertinoIcons.group, - "cupertino_group_solid": CupertinoIcons.group_solid, - "cupertino_mail": CupertinoIcons.mail, - "cupertino_mail_solid": CupertinoIcons.mail_solid, - "cupertino_location": CupertinoIcons.location, - "cupertino_location_solid": CupertinoIcons.location_solid, - "cupertino_tag": CupertinoIcons.tag, - "cupertino_tag_solid": CupertinoIcons.tag_solid, - "cupertino_tags": CupertinoIcons.tags, - "cupertino_tags_solid": CupertinoIcons.tags_solid, - "cupertino_bus": CupertinoIcons.bus, - "cupertino_car": CupertinoIcons.car, - "cupertino_car_detailed": CupertinoIcons.car_detailed, - "cupertino_train_style_one": CupertinoIcons.train_style_one, - "cupertino_train_style_two": CupertinoIcons.train_style_two, - "cupertino_paw": CupertinoIcons.paw, - "cupertino_paw_solid": CupertinoIcons.paw_solid, - "cupertino_game_controller": CupertinoIcons.game_controller, - "cupertino_game_controller_solid": CupertinoIcons.game_controller_solid, - "cupertino_lab_flask": CupertinoIcons.lab_flask, - "cupertino_lab_flask_solid": CupertinoIcons.lab_flask_solid, - "cupertino_heart": CupertinoIcons.heart, - "cupertino_heart_solid": CupertinoIcons.heart_solid, - "cupertino_bell": CupertinoIcons.bell, - "cupertino_bell_solid": CupertinoIcons.bell_solid, - "cupertino_news": CupertinoIcons.news, - "cupertino_news_solid": CupertinoIcons.news_solid, - "cupertino_brightness": CupertinoIcons.brightness, - "cupertino_brightness_solid": CupertinoIcons.brightness_solid, - "cupertino_airplane": CupertinoIcons.airplane, - "cupertino_alarm": CupertinoIcons.alarm, - "cupertino_alarm_fill": CupertinoIcons.alarm_fill, - "cupertino_alt": CupertinoIcons.alt, - "cupertino_ant": CupertinoIcons.ant, - "cupertino_ant_circle": CupertinoIcons.ant_circle, - "cupertino_ant_circle_fill": CupertinoIcons.ant_circle_fill, - "cupertino_ant_fill": CupertinoIcons.ant_fill, - "cupertino_antenna_radiowaves_left_right": - CupertinoIcons.antenna_radiowaves_left_right, - "cupertino_app": CupertinoIcons.app, - "cupertino_app_badge": CupertinoIcons.app_badge, - "cupertino_app_badge_fill": CupertinoIcons.app_badge_fill, - "cupertino_app_fill": CupertinoIcons.app_fill, - "cupertino_archivebox": CupertinoIcons.archivebox, - "cupertino_archivebox_fill": CupertinoIcons.archivebox_fill, - "cupertino_arrow_2_circlepath": CupertinoIcons.arrow_2_circlepath, - "cupertino_arrow_2_circlepath_circle": - CupertinoIcons.arrow_2_circlepath_circle, - "cupertino_arrow_2_circlepath_circle_fill": - CupertinoIcons.arrow_2_circlepath_circle_fill, - "cupertino_arrow_2_squarepath": CupertinoIcons.arrow_2_squarepath, - "cupertino_arrow_3_trianglepath": CupertinoIcons.arrow_3_trianglepath, - "cupertino_arrow_branch": CupertinoIcons.arrow_branch, - "cupertino_arrow_clockwise": CupertinoIcons.arrow_clockwise, - "cupertino_arrow_clockwise_circle": CupertinoIcons.arrow_clockwise_circle, - "cupertino_arrow_clockwise_circle_fill": - CupertinoIcons.arrow_clockwise_circle_fill, - "cupertino_arrow_counterclockwise": CupertinoIcons.arrow_counterclockwise, - "cupertino_arrow_counterclockwise_circle": - CupertinoIcons.arrow_counterclockwise_circle, - "cupertino_arrow_counterclockwise_circle_fill": - CupertinoIcons.arrow_counterclockwise_circle_fill, - "cupertino_arrow_down": CupertinoIcons.arrow_down, - "cupertino_arrow_down_circle": CupertinoIcons.arrow_down_circle, - "cupertino_arrow_down_circle_fill": CupertinoIcons.arrow_down_circle_fill, - "cupertino_arrow_down_doc": CupertinoIcons.arrow_down_doc, - "cupertino_arrow_down_doc_fill": CupertinoIcons.arrow_down_doc_fill, - "cupertino_arrow_down_left": CupertinoIcons.arrow_down_left, - "cupertino_arrow_down_left_circle": CupertinoIcons.arrow_down_left_circle, - "cupertino_arrow_down_left_circle_fill": - CupertinoIcons.arrow_down_left_circle_fill, - "cupertino_arrow_down_left_square": CupertinoIcons.arrow_down_left_square, - "cupertino_arrow_down_left_square_fill": - CupertinoIcons.arrow_down_left_square_fill, - "cupertino_arrow_down_right": CupertinoIcons.arrow_down_right, - "cupertino_arrow_down_right_arrow_up_left": - CupertinoIcons.arrow_down_right_arrow_up_left, - "cupertino_arrow_down_right_circle": CupertinoIcons.arrow_down_right_circle, - "cupertino_arrow_down_right_circle_fill": - CupertinoIcons.arrow_down_right_circle_fill, - "cupertino_arrow_down_right_square": CupertinoIcons.arrow_down_right_square, - "cupertino_arrow_down_right_square_fill": - CupertinoIcons.arrow_down_right_square_fill, - "cupertino_arrow_down_square": CupertinoIcons.arrow_down_square, - "cupertino_arrow_down_square_fill": CupertinoIcons.arrow_down_square_fill, - "cupertino_arrow_down_to_line": CupertinoIcons.arrow_down_to_line, - "cupertino_arrow_down_to_line_alt": CupertinoIcons.arrow_down_to_line_alt, - "cupertino_arrow_left": CupertinoIcons.arrow_left, - "cupertino_arrow_left_circle": CupertinoIcons.arrow_left_circle, - "cupertino_arrow_left_circle_fill": CupertinoIcons.arrow_left_circle_fill, - "cupertino_arrow_left_right": CupertinoIcons.arrow_left_right, - "cupertino_arrow_left_right_circle": CupertinoIcons.arrow_left_right_circle, - "cupertino_arrow_left_right_circle_fill": - CupertinoIcons.arrow_left_right_circle_fill, - "cupertino_arrow_left_right_square": CupertinoIcons.arrow_left_right_square, - "cupertino_arrow_left_right_square_fill": - CupertinoIcons.arrow_left_right_square_fill, - "cupertino_arrow_left_square": CupertinoIcons.arrow_left_square, - "cupertino_arrow_left_square_fill": CupertinoIcons.arrow_left_square_fill, - "cupertino_arrow_left_to_line": CupertinoIcons.arrow_left_to_line, - "cupertino_arrow_left_to_line_alt": CupertinoIcons.arrow_left_to_line_alt, - "cupertino_arrow_merge": CupertinoIcons.arrow_merge, - "cupertino_arrow_right": CupertinoIcons.arrow_right, - "cupertino_arrow_right_arrow_left": CupertinoIcons.arrow_right_arrow_left, - "cupertino_arrow_right_arrow_left_circle": - CupertinoIcons.arrow_right_arrow_left_circle, - "cupertino_arrow_right_arrow_left_circle_fill": - CupertinoIcons.arrow_right_arrow_left_circle_fill, - "cupertino_arrow_right_arrow_left_square": - CupertinoIcons.arrow_right_arrow_left_square, - "cupertino_arrow_right_arrow_left_square_fill": - CupertinoIcons.arrow_right_arrow_left_square_fill, - "cupertino_arrow_right_circle": CupertinoIcons.arrow_right_circle, - "cupertino_arrow_right_circle_fill": CupertinoIcons.arrow_right_circle_fill, - "cupertino_arrow_right_square": CupertinoIcons.arrow_right_square, - "cupertino_arrow_right_square_fill": CupertinoIcons.arrow_right_square_fill, - "cupertino_arrow_right_to_line": CupertinoIcons.arrow_right_to_line, - "cupertino_arrow_right_to_line_alt": CupertinoIcons.arrow_right_to_line_alt, - "cupertino_arrow_swap": CupertinoIcons.arrow_swap, - "cupertino_arrow_turn_down_left": CupertinoIcons.arrow_turn_down_left, - "cupertino_arrow_turn_down_right": CupertinoIcons.arrow_turn_down_right, - "cupertino_arrow_turn_left_down": CupertinoIcons.arrow_turn_left_down, - "cupertino_arrow_turn_left_up": CupertinoIcons.arrow_turn_left_up, - "cupertino_arrow_turn_right_down": CupertinoIcons.arrow_turn_right_down, - "cupertino_arrow_turn_right_up": CupertinoIcons.arrow_turn_right_up, - "cupertino_arrow_turn_up_left": CupertinoIcons.arrow_turn_up_left, - "cupertino_arrow_turn_up_right": CupertinoIcons.arrow_turn_up_right, - "cupertino_arrow_up": CupertinoIcons.arrow_up, - "cupertino_arrow_up_arrow_down": CupertinoIcons.arrow_up_arrow_down, - "cupertino_arrow_up_arrow_down_circle": - CupertinoIcons.arrow_up_arrow_down_circle, - "cupertino_arrow_up_arrow_down_circle_fill": - CupertinoIcons.arrow_up_arrow_down_circle_fill, - "cupertino_arrow_up_arrow_down_square": - CupertinoIcons.arrow_up_arrow_down_square, - "cupertino_arrow_up_arrow_down_square_fill": - CupertinoIcons.arrow_up_arrow_down_square_fill, - "cupertino_arrow_up_bin": CupertinoIcons.arrow_up_bin, - "cupertino_arrow_up_bin_fill": CupertinoIcons.arrow_up_bin_fill, - "cupertino_arrow_up_circle": CupertinoIcons.arrow_up_circle, - "cupertino_arrow_up_circle_fill": CupertinoIcons.arrow_up_circle_fill, - "cupertino_arrow_up_doc": CupertinoIcons.arrow_up_doc, - "cupertino_arrow_up_doc_fill": CupertinoIcons.arrow_up_doc_fill, - "cupertino_arrow_up_down": CupertinoIcons.arrow_up_down, - "cupertino_arrow_up_down_circle": CupertinoIcons.arrow_up_down_circle, - "cupertino_arrow_up_down_circle_fill": - CupertinoIcons.arrow_up_down_circle_fill, - "cupertino_arrow_up_down_square": CupertinoIcons.arrow_up_down_square, - "cupertino_arrow_up_down_square_fill": - CupertinoIcons.arrow_up_down_square_fill, - "cupertino_arrow_up_left": CupertinoIcons.arrow_up_left, - "cupertino_arrow_up_left_arrow_down_right": - CupertinoIcons.arrow_up_left_arrow_down_right, - "cupertino_arrow_up_left_circle": CupertinoIcons.arrow_up_left_circle, - "cupertino_arrow_up_left_circle_fill": - CupertinoIcons.arrow_up_left_circle_fill, - "cupertino_arrow_up_left_square": CupertinoIcons.arrow_up_left_square, - "cupertino_arrow_up_left_square_fill": - CupertinoIcons.arrow_up_left_square_fill, - "cupertino_arrow_up_right": CupertinoIcons.arrow_up_right, - "cupertino_arrow_up_right_circle": CupertinoIcons.arrow_up_right_circle, - "cupertino_arrow_up_right_circle_fill": - CupertinoIcons.arrow_up_right_circle_fill, - "cupertino_arrow_up_right_diamond": CupertinoIcons.arrow_up_right_diamond, - "cupertino_arrow_up_right_diamond_fill": - CupertinoIcons.arrow_up_right_diamond_fill, - "cupertino_arrow_up_right_square": CupertinoIcons.arrow_up_right_square, - "cupertino_arrow_up_right_square_fill": - CupertinoIcons.arrow_up_right_square_fill, - "cupertino_arrow_up_square": CupertinoIcons.arrow_up_square, - "cupertino_arrow_up_square_fill": CupertinoIcons.arrow_up_square_fill, - "cupertino_arrow_up_to_line": CupertinoIcons.arrow_up_to_line, - "cupertino_arrow_up_to_line_alt": CupertinoIcons.arrow_up_to_line_alt, - "cupertino_arrow_uturn_down": CupertinoIcons.arrow_uturn_down, - "cupertino_arrow_uturn_down_circle": CupertinoIcons.arrow_uturn_down_circle, - "cupertino_arrow_uturn_down_circle_fill": - CupertinoIcons.arrow_uturn_down_circle_fill, - "cupertino_arrow_uturn_down_square": CupertinoIcons.arrow_uturn_down_square, - "cupertino_arrow_uturn_down_square_fill": - CupertinoIcons.arrow_uturn_down_square_fill, - "cupertino_arrow_uturn_left": CupertinoIcons.arrow_uturn_left, - "cupertino_arrow_uturn_left_circle": CupertinoIcons.arrow_uturn_left_circle, - "cupertino_arrow_uturn_left_circle_fill": - CupertinoIcons.arrow_uturn_left_circle_fill, - "cupertino_arrow_uturn_left_square": CupertinoIcons.arrow_uturn_left_square, - "cupertino_arrow_uturn_left_square_fill": - CupertinoIcons.arrow_uturn_left_square_fill, - "cupertino_arrow_uturn_right": CupertinoIcons.arrow_uturn_right, - "cupertino_arrow_uturn_right_circle": CupertinoIcons.arrow_uturn_right_circle, - "cupertino_arrow_uturn_right_circle_fill": - CupertinoIcons.arrow_uturn_right_circle_fill, - "cupertino_arrow_uturn_right_square": CupertinoIcons.arrow_uturn_right_square, - "cupertino_arrow_uturn_right_square_fill": - CupertinoIcons.arrow_uturn_right_square_fill, - "cupertino_arrow_uturn_up": CupertinoIcons.arrow_uturn_up, - "cupertino_arrow_uturn_up_circle": CupertinoIcons.arrow_uturn_up_circle, - "cupertino_arrow_uturn_up_circle_fill": - CupertinoIcons.arrow_uturn_up_circle_fill, - "cupertino_arrow_uturn_up_square": CupertinoIcons.arrow_uturn_up_square, - "cupertino_arrow_uturn_up_square_fill": - CupertinoIcons.arrow_uturn_up_square_fill, - "cupertino_arrowshape_turn_up_left": CupertinoIcons.arrowshape_turn_up_left, - "cupertino_arrowshape_turn_up_left_2": - CupertinoIcons.arrowshape_turn_up_left_2, - "cupertino_arrowshape_turn_up_left_2_fill": - CupertinoIcons.arrowshape_turn_up_left_2_fill, - "cupertino_arrowshape_turn_up_left_circle": - CupertinoIcons.arrowshape_turn_up_left_circle, - "cupertino_arrowshape_turn_up_left_circle_fill": - CupertinoIcons.arrowshape_turn_up_left_circle_fill, - "cupertino_arrowshape_turn_up_left_fill": - CupertinoIcons.arrowshape_turn_up_left_fill, - "cupertino_arrowshape_turn_up_right": CupertinoIcons.arrowshape_turn_up_right, - "cupertino_arrowshape_turn_up_right_circle": - CupertinoIcons.arrowshape_turn_up_right_circle, - "cupertino_arrowshape_turn_up_right_circle_fill": - CupertinoIcons.arrowshape_turn_up_right_circle_fill, - "cupertino_arrowshape_turn_up_right_fill": - CupertinoIcons.arrowshape_turn_up_right_fill, - "cupertino_arrowtriangle_down": CupertinoIcons.arrowtriangle_down, - "cupertino_arrowtriangle_down_circle": - CupertinoIcons.arrowtriangle_down_circle, - "cupertino_arrowtriangle_down_circle_fill": - CupertinoIcons.arrowtriangle_down_circle_fill, - "cupertino_arrowtriangle_down_fill": CupertinoIcons.arrowtriangle_down_fill, - "cupertino_arrowtriangle_down_square": - CupertinoIcons.arrowtriangle_down_square, - "cupertino_arrowtriangle_down_square_fill": - CupertinoIcons.arrowtriangle_down_square_fill, - "cupertino_arrowtriangle_left": CupertinoIcons.arrowtriangle_left, - "cupertino_arrowtriangle_left_circle": - CupertinoIcons.arrowtriangle_left_circle, - "cupertino_arrowtriangle_left_circle_fill": - CupertinoIcons.arrowtriangle_left_circle_fill, - "cupertino_arrowtriangle_left_fill": CupertinoIcons.arrowtriangle_left_fill, - "cupertino_arrowtriangle_left_square": - CupertinoIcons.arrowtriangle_left_square, - "cupertino_arrowtriangle_left_square_fill": - CupertinoIcons.arrowtriangle_left_square_fill, - "cupertino_arrowtriangle_right": CupertinoIcons.arrowtriangle_right, - "cupertino_arrowtriangle_right_circle": - CupertinoIcons.arrowtriangle_right_circle, - "cupertino_arrowtriangle_right_circle_fill": - CupertinoIcons.arrowtriangle_right_circle_fill, - "cupertino_arrowtriangle_right_fill": CupertinoIcons.arrowtriangle_right_fill, - "cupertino_arrowtriangle_right_square": - CupertinoIcons.arrowtriangle_right_square, - "cupertino_arrowtriangle_right_square_fill": - CupertinoIcons.arrowtriangle_right_square_fill, - "cupertino_arrowtriangle_up": CupertinoIcons.arrowtriangle_up, - "cupertino_arrowtriangle_up_circle": CupertinoIcons.arrowtriangle_up_circle, - "cupertino_arrowtriangle_up_circle_fill": - CupertinoIcons.arrowtriangle_up_circle_fill, - "cupertino_arrowtriangle_up_fill": CupertinoIcons.arrowtriangle_up_fill, - "cupertino_arrowtriangle_up_square": CupertinoIcons.arrowtriangle_up_square, - "cupertino_arrowtriangle_up_square_fill": - CupertinoIcons.arrowtriangle_up_square_fill, - "cupertino_asterisk_circle": CupertinoIcons.asterisk_circle, - "cupertino_asterisk_circle_fill": CupertinoIcons.asterisk_circle_fill, - "cupertino_at": CupertinoIcons.at, - "cupertino_at_badge_minus": CupertinoIcons.at_badge_minus, - "cupertino_at_badge_plus": CupertinoIcons.at_badge_plus, - "cupertino_at_circle": CupertinoIcons.at_circle, - "cupertino_at_circle_fill": CupertinoIcons.at_circle_fill, - "cupertino_backward": CupertinoIcons.backward, - "cupertino_backward_end": CupertinoIcons.backward_end, - "cupertino_backward_end_alt": CupertinoIcons.backward_end_alt, - "cupertino_backward_end_alt_fill": CupertinoIcons.backward_end_alt_fill, - "cupertino_backward_end_fill": CupertinoIcons.backward_end_fill, - "cupertino_backward_fill": CupertinoIcons.backward_fill, - "cupertino_badge_plus_radiowaves_right": - CupertinoIcons.badge_plus_radiowaves_right, - "cupertino_bag": CupertinoIcons.bag, - "cupertino_bag_badge_minus": CupertinoIcons.bag_badge_minus, - "cupertino_bag_badge_plus": CupertinoIcons.bag_badge_plus, - "cupertino_bag_fill": CupertinoIcons.bag_fill, - "cupertino_bag_fill_badge_minus": CupertinoIcons.bag_fill_badge_minus, - "cupertino_bag_fill_badge_plus": CupertinoIcons.bag_fill_badge_plus, - "cupertino_bandage": CupertinoIcons.bandage, - "cupertino_bandage_fill": CupertinoIcons.bandage_fill, - "cupertino_barcode": CupertinoIcons.barcode, - "cupertino_barcode_viewfinder": CupertinoIcons.barcode_viewfinder, - "cupertino_bars": CupertinoIcons.bars, - "cupertino_battery_0": CupertinoIcons.battery_0, - "cupertino_battery_100": CupertinoIcons.battery_100, - "cupertino_battery_25": CupertinoIcons.battery_25, - "cupertino_bed_double": CupertinoIcons.bed_double, - "cupertino_bed_double_fill": CupertinoIcons.bed_double_fill, - "cupertino_bell_circle": CupertinoIcons.bell_circle, - "cupertino_bell_circle_fill": CupertinoIcons.bell_circle_fill, - "cupertino_bell_fill": CupertinoIcons.bell_fill, - "cupertino_bell_slash": CupertinoIcons.bell_slash, - "cupertino_bell_slash_fill": CupertinoIcons.bell_slash_fill, - "cupertino_bin_xmark": CupertinoIcons.bin_xmark, - "cupertino_bin_xmark_fill": CupertinoIcons.bin_xmark_fill, - "cupertino_bitcoin": CupertinoIcons.bitcoin, - "cupertino_bitcoin_circle": CupertinoIcons.bitcoin_circle, - "cupertino_bitcoin_circle_fill": CupertinoIcons.bitcoin_circle_fill, - "cupertino_bold": CupertinoIcons.bold, - "cupertino_bold_italic_underline": CupertinoIcons.bold_italic_underline, - "cupertino_bold_underline": CupertinoIcons.bold_underline, - "cupertino_bolt": CupertinoIcons.bolt, - "cupertino_bolt_badge_a": CupertinoIcons.bolt_badge_a, - "cupertino_bolt_badge_a_fill": CupertinoIcons.bolt_badge_a_fill, - "cupertino_bolt_circle": CupertinoIcons.bolt_circle, - "cupertino_bolt_circle_fill": CupertinoIcons.bolt_circle_fill, - "cupertino_bolt_fill": CupertinoIcons.bolt_fill, - "cupertino_bolt_horizontal": CupertinoIcons.bolt_horizontal, - "cupertino_bolt_horizontal_circle": CupertinoIcons.bolt_horizontal_circle, - "cupertino_bolt_horizontal_circle_fill": - CupertinoIcons.bolt_horizontal_circle_fill, - "cupertino_bolt_horizontal_fill": CupertinoIcons.bolt_horizontal_fill, - "cupertino_bolt_slash": CupertinoIcons.bolt_slash, - "cupertino_bolt_slash_fill": CupertinoIcons.bolt_slash_fill, - "cupertino_book_circle": CupertinoIcons.book_circle, - "cupertino_book_circle_fill": CupertinoIcons.book_circle_fill, - "cupertino_book_fill": CupertinoIcons.book_fill, - "cupertino_bookmark_fill": CupertinoIcons.bookmark_fill, - "cupertino_briefcase": CupertinoIcons.briefcase, - "cupertino_briefcase_fill": CupertinoIcons.briefcase_fill, - "cupertino_bubble_left": CupertinoIcons.bubble_left, - "cupertino_bubble_left_bubble_right": CupertinoIcons.bubble_left_bubble_right, - "cupertino_bubble_left_bubble_right_fill": - CupertinoIcons.bubble_left_bubble_right_fill, - "cupertino_bubble_left_fill": CupertinoIcons.bubble_left_fill, - "cupertino_bubble_middle_bottom": CupertinoIcons.bubble_middle_bottom, - "cupertino_bubble_middle_bottom_fill": - CupertinoIcons.bubble_middle_bottom_fill, - "cupertino_bubble_middle_top": CupertinoIcons.bubble_middle_top, - "cupertino_bubble_middle_top_fill": CupertinoIcons.bubble_middle_top_fill, - "cupertino_bubble_right": CupertinoIcons.bubble_right, - "cupertino_bubble_right_fill": CupertinoIcons.bubble_right_fill, - "cupertino_building_2_fill": CupertinoIcons.building_2_fill, - "cupertino_burn": CupertinoIcons.burn, - "cupertino_burst": CupertinoIcons.burst, - "cupertino_burst_fill": CupertinoIcons.burst_fill, - "cupertino_calendar": CupertinoIcons.calendar, - "cupertino_calendar_badge_minus": CupertinoIcons.calendar_badge_minus, - "cupertino_calendar_badge_plus": CupertinoIcons.calendar_badge_plus, - "cupertino_calendar_circle": CupertinoIcons.calendar_circle, - "cupertino_calendar_circle_fill": CupertinoIcons.calendar_circle_fill, - "cupertino_calendar_today": CupertinoIcons.calendar_today, - "cupertino_camera": CupertinoIcons.camera, - "cupertino_camera_circle": CupertinoIcons.camera_circle, - "cupertino_camera_circle_fill": CupertinoIcons.camera_circle_fill, - "cupertino_camera_fill": CupertinoIcons.camera_fill, - "cupertino_camera_on_rectangle": CupertinoIcons.camera_on_rectangle, - "cupertino_camera_on_rectangle_fill": CupertinoIcons.camera_on_rectangle_fill, - "cupertino_camera_rotate": CupertinoIcons.camera_rotate, - "cupertino_camera_rotate_fill": CupertinoIcons.camera_rotate_fill, - "cupertino_camera_viewfinder": CupertinoIcons.camera_viewfinder, - "cupertino_capslock": CupertinoIcons.capslock, - "cupertino_capslock_fill": CupertinoIcons.capslock_fill, - "cupertino_capsule": CupertinoIcons.capsule, - "cupertino_capsule_fill": CupertinoIcons.capsule_fill, - "cupertino_captions_bubble": CupertinoIcons.captions_bubble, - "cupertino_captions_bubble_fill": CupertinoIcons.captions_bubble_fill, - "cupertino_car_fill": CupertinoIcons.car_fill, - "cupertino_cart": CupertinoIcons.cart, - "cupertino_cart_badge_minus": CupertinoIcons.cart_badge_minus, - "cupertino_cart_badge_plus": CupertinoIcons.cart_badge_plus, - "cupertino_cart_fill": CupertinoIcons.cart_fill, - "cupertino_cart_fill_badge_minus": CupertinoIcons.cart_fill_badge_minus, - "cupertino_cart_fill_badge_plus": CupertinoIcons.cart_fill_badge_plus, - "cupertino_chart_bar": CupertinoIcons.chart_bar, - "cupertino_chart_bar_alt_fill": CupertinoIcons.chart_bar_alt_fill, - "cupertino_chart_bar_circle": CupertinoIcons.chart_bar_circle, - "cupertino_chart_bar_circle_fill": CupertinoIcons.chart_bar_circle_fill, - "cupertino_chart_bar_fill": CupertinoIcons.chart_bar_fill, - "cupertino_chart_bar_square": CupertinoIcons.chart_bar_square, - "cupertino_chart_bar_square_fill": CupertinoIcons.chart_bar_square_fill, - "cupertino_chart_pie": CupertinoIcons.chart_pie, - "cupertino_chart_pie_fill": CupertinoIcons.chart_pie_fill, - "cupertino_chat_bubble": CupertinoIcons.chat_bubble, - "cupertino_chat_bubble_2": CupertinoIcons.chat_bubble_2, - "cupertino_chat_bubble_2_fill": CupertinoIcons.chat_bubble_2_fill, - "cupertino_chat_bubble_fill": CupertinoIcons.chat_bubble_fill, - "cupertino_chat_bubble_text": CupertinoIcons.chat_bubble_text, - "cupertino_chat_bubble_text_fill": CupertinoIcons.chat_bubble_text_fill, - "cupertino_checkmark": CupertinoIcons.checkmark, - "cupertino_checkmark_alt": CupertinoIcons.checkmark_alt, - "cupertino_checkmark_alt_circle": CupertinoIcons.checkmark_alt_circle, - "cupertino_checkmark_alt_circle_fill": - CupertinoIcons.checkmark_alt_circle_fill, - "cupertino_checkmark_circle": CupertinoIcons.checkmark_circle, - "cupertino_checkmark_circle_fill": CupertinoIcons.checkmark_circle_fill, - "cupertino_checkmark_rectangle": CupertinoIcons.checkmark_rectangle, - "cupertino_checkmark_rectangle_fill": CupertinoIcons.checkmark_rectangle_fill, - "cupertino_checkmark_seal": CupertinoIcons.checkmark_seal, - "cupertino_checkmark_seal_fill": CupertinoIcons.checkmark_seal_fill, - "cupertino_checkmark_shield": CupertinoIcons.checkmark_shield, - "cupertino_checkmark_shield_fill": CupertinoIcons.checkmark_shield_fill, - "cupertino_checkmark_square": CupertinoIcons.checkmark_square, - "cupertino_checkmark_square_fill": CupertinoIcons.checkmark_square_fill, - "cupertino_chevron_back": CupertinoIcons.chevron_back, - "cupertino_chevron_compact_down": CupertinoIcons.chevron_compact_down, - "cupertino_chevron_compact_left": CupertinoIcons.chevron_compact_left, - "cupertino_chevron_compact_right": CupertinoIcons.chevron_compact_right, - "cupertino_chevron_compact_up": CupertinoIcons.chevron_compact_up, - "cupertino_chevron_down": CupertinoIcons.chevron_down, - "cupertino_chevron_down_circle": CupertinoIcons.chevron_down_circle, - "cupertino_chevron_down_circle_fill": CupertinoIcons.chevron_down_circle_fill, - "cupertino_chevron_down_square": CupertinoIcons.chevron_down_square, - "cupertino_chevron_down_square_fill": CupertinoIcons.chevron_down_square_fill, - "cupertino_chevron_forward": CupertinoIcons.chevron_forward, - "cupertino_chevron_left": CupertinoIcons.chevron_left, - "cupertino_chevron_left_2": CupertinoIcons.chevron_left_2, - "cupertino_chevron_left_circle": CupertinoIcons.chevron_left_circle, - "cupertino_chevron_left_circle_fill": CupertinoIcons.chevron_left_circle_fill, - "cupertino_chevron_left_slash_chevron_right": - CupertinoIcons.chevron_left_slash_chevron_right, - "cupertino_chevron_left_square": CupertinoIcons.chevron_left_square, - "cupertino_chevron_left_square_fill": CupertinoIcons.chevron_left_square_fill, - "cupertino_chevron_right": CupertinoIcons.chevron_right, - "cupertino_chevron_right_2": CupertinoIcons.chevron_right_2, - "cupertino_chevron_right_circle": CupertinoIcons.chevron_right_circle, - "cupertino_chevron_right_circle_fill": - CupertinoIcons.chevron_right_circle_fill, - "cupertino_chevron_right_square": CupertinoIcons.chevron_right_square, - "cupertino_chevron_right_square_fill": - CupertinoIcons.chevron_right_square_fill, - "cupertino_chevron_up": CupertinoIcons.chevron_up, - "cupertino_chevron_up_chevron_down": CupertinoIcons.chevron_up_chevron_down, - "cupertino_chevron_up_circle": CupertinoIcons.chevron_up_circle, - "cupertino_chevron_up_circle_fill": CupertinoIcons.chevron_up_circle_fill, - "cupertino_chevron_up_square": CupertinoIcons.chevron_up_square, - "cupertino_chevron_up_square_fill": CupertinoIcons.chevron_up_square_fill, - "cupertino_circle_bottomthird_split": CupertinoIcons.circle_bottomthird_split, - "cupertino_circle_fill": CupertinoIcons.circle_fill, - "cupertino_circle_grid_3x3": CupertinoIcons.circle_grid_3x3, - "cupertino_circle_grid_3x3_fill": CupertinoIcons.circle_grid_3x3_fill, - "cupertino_circle_grid_hex": CupertinoIcons.circle_grid_hex, - "cupertino_circle_grid_hex_fill": CupertinoIcons.circle_grid_hex_fill, - "cupertino_circle_lefthalf_fill": CupertinoIcons.circle_lefthalf_fill, - "cupertino_circle_righthalf_fill": CupertinoIcons.circle_righthalf_fill, - "cupertino_clear_fill": CupertinoIcons.clear_fill, - "cupertino_clock_fill": CupertinoIcons.clock_fill, - "cupertino_cloud": CupertinoIcons.cloud, - "cupertino_cloud_bolt": CupertinoIcons.cloud_bolt, - "cupertino_cloud_bolt_fill": CupertinoIcons.cloud_bolt_fill, - "cupertino_cloud_bolt_rain": CupertinoIcons.cloud_bolt_rain, - "cupertino_cloud_bolt_rain_fill": CupertinoIcons.cloud_bolt_rain_fill, - "cupertino_cloud_download": CupertinoIcons.cloud_download, - "cupertino_cloud_download_fill": CupertinoIcons.cloud_download_fill, - "cupertino_cloud_drizzle": CupertinoIcons.cloud_drizzle, - "cupertino_cloud_drizzle_fill": CupertinoIcons.cloud_drizzle_fill, - "cupertino_cloud_fill": CupertinoIcons.cloud_fill, - "cupertino_cloud_fog": CupertinoIcons.cloud_fog, - "cupertino_cloud_fog_fill": CupertinoIcons.cloud_fog_fill, - "cupertino_cloud_hail": CupertinoIcons.cloud_hail, - "cupertino_cloud_hail_fill": CupertinoIcons.cloud_hail_fill, - "cupertino_cloud_heavyrain": CupertinoIcons.cloud_heavyrain, - "cupertino_cloud_heavyrain_fill": CupertinoIcons.cloud_heavyrain_fill, - "cupertino_cloud_moon": CupertinoIcons.cloud_moon, - "cupertino_cloud_moon_bolt": CupertinoIcons.cloud_moon_bolt, - "cupertino_cloud_moon_bolt_fill": CupertinoIcons.cloud_moon_bolt_fill, - "cupertino_cloud_moon_fill": CupertinoIcons.cloud_moon_fill, - "cupertino_cloud_moon_rain": CupertinoIcons.cloud_moon_rain, - "cupertino_cloud_moon_rain_fill": CupertinoIcons.cloud_moon_rain_fill, - "cupertino_cloud_rain": CupertinoIcons.cloud_rain, - "cupertino_cloud_rain_fill": CupertinoIcons.cloud_rain_fill, - "cupertino_cloud_sleet": CupertinoIcons.cloud_sleet, - "cupertino_cloud_sleet_fill": CupertinoIcons.cloud_sleet_fill, - "cupertino_cloud_snow": CupertinoIcons.cloud_snow, - "cupertino_cloud_snow_fill": CupertinoIcons.cloud_snow_fill, - "cupertino_cloud_sun": CupertinoIcons.cloud_sun, - "cupertino_cloud_sun_bolt": CupertinoIcons.cloud_sun_bolt, - "cupertino_cloud_sun_bolt_fill": CupertinoIcons.cloud_sun_bolt_fill, - "cupertino_cloud_sun_fill": CupertinoIcons.cloud_sun_fill, - "cupertino_cloud_sun_rain": CupertinoIcons.cloud_sun_rain, - "cupertino_cloud_sun_rain_fill": CupertinoIcons.cloud_sun_rain_fill, - "cupertino_cloud_upload": CupertinoIcons.cloud_upload, - "cupertino_cloud_upload_fill": CupertinoIcons.cloud_upload_fill, - "cupertino_color_filter": CupertinoIcons.color_filter, - "cupertino_color_filter_fill": CupertinoIcons.color_filter_fill, - "cupertino_command": CupertinoIcons.command, - "cupertino_compass": CupertinoIcons.compass, - "cupertino_compass_fill": CupertinoIcons.compass_fill, - "cupertino_control": CupertinoIcons.control, - "cupertino_creditcard": CupertinoIcons.creditcard, - "cupertino_creditcard_fill": CupertinoIcons.creditcard_fill, - "cupertino_crop": CupertinoIcons.crop, - "cupertino_crop_rotate": CupertinoIcons.crop_rotate, - "cupertino_cube": CupertinoIcons.cube, - "cupertino_cube_box": CupertinoIcons.cube_box, - "cupertino_cube_box_fill": CupertinoIcons.cube_box_fill, - "cupertino_cube_fill": CupertinoIcons.cube_fill, - "cupertino_cursor_rays": CupertinoIcons.cursor_rays, - "cupertino_decrease_indent": CupertinoIcons.decrease_indent, - "cupertino_decrease_quotelevel": CupertinoIcons.decrease_quotelevel, - "cupertino_delete_left": CupertinoIcons.delete_left, - "cupertino_delete_left_fill": CupertinoIcons.delete_left_fill, - "cupertino_delete_right": CupertinoIcons.delete_right, - "cupertino_delete_right_fill": CupertinoIcons.delete_right_fill, - "cupertino_desktopcomputer": CupertinoIcons.desktopcomputer, - "cupertino_device_desktop": CupertinoIcons.device_desktop, - "cupertino_device_laptop": CupertinoIcons.device_laptop, - "cupertino_device_phone_landscape": CupertinoIcons.device_phone_landscape, - "cupertino_device_phone_portrait": CupertinoIcons.device_phone_portrait, - "cupertino_dial": CupertinoIcons.dial, - "cupertino_dial_fill": CupertinoIcons.dial_fill, - "cupertino_divide": CupertinoIcons.divide, - "cupertino_divide_circle": CupertinoIcons.divide_circle, - "cupertino_divide_circle_fill": CupertinoIcons.divide_circle_fill, - "cupertino_divide_square": CupertinoIcons.divide_square, - "cupertino_divide_square_fill": CupertinoIcons.divide_square_fill, - "cupertino_doc": CupertinoIcons.doc, - "cupertino_doc_append": CupertinoIcons.doc_append, - "cupertino_doc_chart": CupertinoIcons.doc_chart, - "cupertino_doc_chart_fill": CupertinoIcons.doc_chart_fill, - "cupertino_doc_checkmark": CupertinoIcons.doc_checkmark, - "cupertino_doc_checkmark_fill": CupertinoIcons.doc_checkmark_fill, - "cupertino_doc_circle": CupertinoIcons.doc_circle, - "cupertino_doc_circle_fill": CupertinoIcons.doc_circle_fill, - "cupertino_doc_fill": CupertinoIcons.doc_fill, - "cupertino_doc_on_clipboard": CupertinoIcons.doc_on_clipboard, - "cupertino_doc_on_clipboard_fill": CupertinoIcons.doc_on_clipboard_fill, - "cupertino_doc_on_doc": CupertinoIcons.doc_on_doc, - "cupertino_doc_on_doc_fill": CupertinoIcons.doc_on_doc_fill, - "cupertino_doc_person": CupertinoIcons.doc_person, - "cupertino_doc_person_fill": CupertinoIcons.doc_person_fill, - "cupertino_doc_plaintext": CupertinoIcons.doc_plaintext, - "cupertino_doc_richtext": CupertinoIcons.doc_richtext, - "cupertino_doc_text": CupertinoIcons.doc_text, - "cupertino_doc_text_fill": CupertinoIcons.doc_text_fill, - "cupertino_doc_text_search": CupertinoIcons.doc_text_search, - "cupertino_doc_text_viewfinder": CupertinoIcons.doc_text_viewfinder, - "cupertino_dot_radiowaves_left_right": - CupertinoIcons.dot_radiowaves_left_right, - "cupertino_dot_radiowaves_right": CupertinoIcons.dot_radiowaves_right, - "cupertino_dot_square": CupertinoIcons.dot_square, - "cupertino_dot_square_fill": CupertinoIcons.dot_square_fill, - "cupertino_download_circle": CupertinoIcons.download_circle, - "cupertino_download_circle_fill": CupertinoIcons.download_circle_fill, - "cupertino_drop": CupertinoIcons.drop, - "cupertino_drop_fill": CupertinoIcons.drop_fill, - "cupertino_drop_triangle": CupertinoIcons.drop_triangle, - "cupertino_drop_triangle_fill": CupertinoIcons.drop_triangle_fill, - "cupertino_ear": CupertinoIcons.ear, - "cupertino_eject": CupertinoIcons.eject, - "cupertino_eject_fill": CupertinoIcons.eject_fill, - "cupertino_ellipses_bubble": CupertinoIcons.ellipses_bubble, - "cupertino_ellipses_bubble_fill": CupertinoIcons.ellipses_bubble_fill, - "cupertino_ellipsis_circle": CupertinoIcons.ellipsis_circle, - "cupertino_ellipsis_circle_fill": CupertinoIcons.ellipsis_circle_fill, - "cupertino_ellipsis_vertical": CupertinoIcons.ellipsis_vertical, - "cupertino_ellipsis_vertical_circle": CupertinoIcons.ellipsis_vertical_circle, - "cupertino_ellipsis_vertical_circle_fill": - CupertinoIcons.ellipsis_vertical_circle_fill, - "cupertino_envelope": CupertinoIcons.envelope, - "cupertino_envelope_badge": CupertinoIcons.envelope_badge, - "cupertino_envelope_badge_fill": CupertinoIcons.envelope_badge_fill, - "cupertino_envelope_circle": CupertinoIcons.envelope_circle, - "cupertino_envelope_circle_fill": CupertinoIcons.envelope_circle_fill, - "cupertino_envelope_fill": CupertinoIcons.envelope_fill, - "cupertino_envelope_open": CupertinoIcons.envelope_open, - "cupertino_envelope_open_fill": CupertinoIcons.envelope_open_fill, - "cupertino_equal": CupertinoIcons.equal, - "cupertino_equal_circle": CupertinoIcons.equal_circle, - "cupertino_equal_circle_fill": CupertinoIcons.equal_circle_fill, - "cupertino_equal_square": CupertinoIcons.equal_square, - "cupertino_equal_square_fill": CupertinoIcons.equal_square_fill, - "cupertino_escape": CupertinoIcons.escape, - "cupertino_exclamationmark": CupertinoIcons.exclamationmark, - "cupertino_exclamationmark_bubble": CupertinoIcons.exclamationmark_bubble, - "cupertino_exclamationmark_bubble_fill": - CupertinoIcons.exclamationmark_bubble_fill, - "cupertino_exclamationmark_circle": CupertinoIcons.exclamationmark_circle, - "cupertino_exclamationmark_circle_fill": - CupertinoIcons.exclamationmark_circle_fill, - "cupertino_exclamationmark_octagon": CupertinoIcons.exclamationmark_octagon, - "cupertino_exclamationmark_octagon_fill": - CupertinoIcons.exclamationmark_octagon_fill, - "cupertino_exclamationmark_shield": CupertinoIcons.exclamationmark_shield, - "cupertino_exclamationmark_shield_fill": - CupertinoIcons.exclamationmark_shield_fill, - "cupertino_exclamationmark_square": CupertinoIcons.exclamationmark_square, - "cupertino_exclamationmark_square_fill": - CupertinoIcons.exclamationmark_square_fill, - "cupertino_exclamationmark_triangle": CupertinoIcons.exclamationmark_triangle, - "cupertino_exclamationmark_triangle_fill": - CupertinoIcons.exclamationmark_triangle_fill, - "cupertino_eye_fill": CupertinoIcons.eye_fill, - "cupertino_eye_slash": CupertinoIcons.eye_slash, - "cupertino_eye_slash_fill": CupertinoIcons.eye_slash_fill, - "cupertino_eyedropper": CupertinoIcons.eyedropper, - "cupertino_eyedropper_full": CupertinoIcons.eyedropper_full, - "cupertino_eyedropper_halffull": CupertinoIcons.eyedropper_halffull, - "cupertino_eyeglasses": CupertinoIcons.eyeglasses, - "cupertino_f_cursive": CupertinoIcons.f_cursive, - "cupertino_f_cursive_circle": CupertinoIcons.f_cursive_circle, - "cupertino_f_cursive_circle_fill": CupertinoIcons.f_cursive_circle_fill, - "cupertino_film": CupertinoIcons.film, - "cupertino_film_fill": CupertinoIcons.film_fill, - "cupertino_flag_circle": CupertinoIcons.flag_circle, - "cupertino_flag_circle_fill": CupertinoIcons.flag_circle_fill, - "cupertino_flag_fill": CupertinoIcons.flag_fill, - "cupertino_flag_slash": CupertinoIcons.flag_slash, - "cupertino_flag_slash_fill": CupertinoIcons.flag_slash_fill, - "cupertino_flame": CupertinoIcons.flame, - "cupertino_flame_fill": CupertinoIcons.flame_fill, - "cupertino_floppy_disk": CupertinoIcons.floppy_disk, - "cupertino_flowchart": CupertinoIcons.flowchart, - "cupertino_flowchart_fill": CupertinoIcons.flowchart_fill, - "cupertino_folder_badge_minus": CupertinoIcons.folder_badge_minus, - "cupertino_folder_badge_person_crop": CupertinoIcons.folder_badge_person_crop, - "cupertino_folder_badge_plus": CupertinoIcons.folder_badge_plus, - "cupertino_folder_circle": CupertinoIcons.folder_circle, - "cupertino_folder_circle_fill": CupertinoIcons.folder_circle_fill, - "cupertino_folder_fill": CupertinoIcons.folder_fill, - "cupertino_folder_fill_badge_minus": CupertinoIcons.folder_fill_badge_minus, - "cupertino_folder_fill_badge_person_crop": - CupertinoIcons.folder_fill_badge_person_crop, - "cupertino_folder_fill_badge_plus": CupertinoIcons.folder_fill_badge_plus, - "cupertino_forward_end": CupertinoIcons.forward_end, - "cupertino_forward_end_alt": CupertinoIcons.forward_end_alt, - "cupertino_forward_end_alt_fill": CupertinoIcons.forward_end_alt_fill, - "cupertino_forward_end_fill": CupertinoIcons.forward_end_fill, - "cupertino_forward_fill": CupertinoIcons.forward_fill, - "cupertino_function": CupertinoIcons.function, - "cupertino_fx": CupertinoIcons.fx, - "cupertino_gamecontroller": CupertinoIcons.gamecontroller, - "cupertino_gamecontroller_alt_fill": CupertinoIcons.gamecontroller_alt_fill, - "cupertino_gamecontroller_fill": CupertinoIcons.gamecontroller_fill, - "cupertino_gauge": CupertinoIcons.gauge, - "cupertino_gauge_badge_minus": CupertinoIcons.gauge_badge_minus, - "cupertino_gauge_badge_plus": CupertinoIcons.gauge_badge_plus, - "cupertino_gear_alt": CupertinoIcons.gear_alt, - "cupertino_gear_alt_fill": CupertinoIcons.gear_alt_fill, - "cupertino_gift": CupertinoIcons.gift, - "cupertino_gift_alt": CupertinoIcons.gift_alt, - "cupertino_gift_alt_fill": CupertinoIcons.gift_alt_fill, - "cupertino_gift_fill": CupertinoIcons.gift_fill, - "cupertino_globe": CupertinoIcons.globe, - "cupertino_gobackward": CupertinoIcons.gobackward, - "cupertino_gobackward_10": CupertinoIcons.gobackward_10, - "cupertino_gobackward_15": CupertinoIcons.gobackward_15, - "cupertino_gobackward_30": CupertinoIcons.gobackward_30, - "cupertino_gobackward_45": CupertinoIcons.gobackward_45, - "cupertino_gobackward_60": CupertinoIcons.gobackward_60, - "cupertino_gobackward_75": CupertinoIcons.gobackward_75, - "cupertino_gobackward_90": CupertinoIcons.gobackward_90, - "cupertino_gobackward_minus": CupertinoIcons.gobackward_minus, - "cupertino_goforward": CupertinoIcons.goforward, - "cupertino_goforward_10": CupertinoIcons.goforward_10, - "cupertino_goforward_15": CupertinoIcons.goforward_15, - "cupertino_goforward_30": CupertinoIcons.goforward_30, - "cupertino_goforward_45": CupertinoIcons.goforward_45, - "cupertino_goforward_60": CupertinoIcons.goforward_60, - "cupertino_goforward_75": CupertinoIcons.goforward_75, - "cupertino_goforward_90": CupertinoIcons.goforward_90, - "cupertino_goforward_plus": CupertinoIcons.goforward_plus, - "cupertino_graph_circle": CupertinoIcons.graph_circle, - "cupertino_graph_circle_fill": CupertinoIcons.graph_circle_fill, - "cupertino_graph_square": CupertinoIcons.graph_square, - "cupertino_graph_square_fill": CupertinoIcons.graph_square_fill, - "cupertino_greaterthan": CupertinoIcons.greaterthan, - "cupertino_greaterthan_circle": CupertinoIcons.greaterthan_circle, - "cupertino_greaterthan_circle_fill": CupertinoIcons.greaterthan_circle_fill, - "cupertino_greaterthan_square": CupertinoIcons.greaterthan_square, - "cupertino_greaterthan_square_fill": CupertinoIcons.greaterthan_square_fill, - "cupertino_grid": CupertinoIcons.grid, - "cupertino_grid_circle": CupertinoIcons.grid_circle, - "cupertino_grid_circle_fill": CupertinoIcons.grid_circle_fill, - "cupertino_guitars": CupertinoIcons.guitars, - "cupertino_hammer": CupertinoIcons.hammer, - "cupertino_hammer_fill": CupertinoIcons.hammer_fill, - "cupertino_hand_draw": CupertinoIcons.hand_draw, - "cupertino_hand_draw_fill": CupertinoIcons.hand_draw_fill, - "cupertino_hand_point_left": CupertinoIcons.hand_point_left, - "cupertino_hand_point_left_fill": CupertinoIcons.hand_point_left_fill, - "cupertino_hand_point_right": CupertinoIcons.hand_point_right, - "cupertino_hand_point_right_fill": CupertinoIcons.hand_point_right_fill, - "cupertino_hand_raised": CupertinoIcons.hand_raised, - "cupertino_hand_raised_fill": CupertinoIcons.hand_raised_fill, - "cupertino_hand_raised_slash": CupertinoIcons.hand_raised_slash, - "cupertino_hand_raised_slash_fill": CupertinoIcons.hand_raised_slash_fill, - "cupertino_hand_thumbsdown": CupertinoIcons.hand_thumbsdown, - "cupertino_hand_thumbsdown_fill": CupertinoIcons.hand_thumbsdown_fill, - "cupertino_hand_thumbsup": CupertinoIcons.hand_thumbsup, - "cupertino_hand_thumbsup_fill": CupertinoIcons.hand_thumbsup_fill, - "cupertino_hare": CupertinoIcons.hare, - "cupertino_hare_fill": CupertinoIcons.hare_fill, - "cupertino_headphones": CupertinoIcons.headphones, - "cupertino_heart_circle": CupertinoIcons.heart_circle, - "cupertino_heart_circle_fill": CupertinoIcons.heart_circle_fill, - "cupertino_heart_fill": CupertinoIcons.heart_fill, - "cupertino_heart_slash": CupertinoIcons.heart_slash, - "cupertino_heart_slash_circle": CupertinoIcons.heart_slash_circle, - "cupertino_heart_slash_circle_fill": CupertinoIcons.heart_slash_circle_fill, - "cupertino_heart_slash_fill": CupertinoIcons.heart_slash_fill, - "cupertino_helm": CupertinoIcons.helm, - "cupertino_hexagon": CupertinoIcons.hexagon, - "cupertino_hexagon_fill": CupertinoIcons.hexagon_fill, - "cupertino_hifispeaker": CupertinoIcons.hifispeaker, - "cupertino_hifispeaker_fill": CupertinoIcons.hifispeaker_fill, - "cupertino_hourglass": CupertinoIcons.hourglass, - "cupertino_hourglass_bottomhalf_fill": - CupertinoIcons.hourglass_bottomhalf_fill, - "cupertino_hourglass_tophalf_fill": CupertinoIcons.hourglass_tophalf_fill, - "cupertino_house": CupertinoIcons.house, - "cupertino_house_alt": CupertinoIcons.house_alt, - "cupertino_house_alt_fill": CupertinoIcons.house_alt_fill, - "cupertino_house_fill": CupertinoIcons.house_fill, - "cupertino_hurricane": CupertinoIcons.hurricane, - "cupertino_increase_indent": CupertinoIcons.increase_indent, - "cupertino_increase_quotelevel": CupertinoIcons.increase_quotelevel, - "cupertino_infinite": CupertinoIcons.infinite, - "cupertino_info_circle": CupertinoIcons.info_circle, - "cupertino_info_circle_fill": CupertinoIcons.info_circle_fill, - "cupertino_italic": CupertinoIcons.italic, - "cupertino_keyboard": CupertinoIcons.keyboard, - "cupertino_keyboard_chevron_compact_down": - CupertinoIcons.keyboard_chevron_compact_down, - "cupertino_largecircle_fill_circle": CupertinoIcons.largecircle_fill_circle, - "cupertino_lasso": CupertinoIcons.lasso, - "cupertino_layers": CupertinoIcons.layers, - "cupertino_layers_alt": CupertinoIcons.layers_alt, - "cupertino_layers_alt_fill": CupertinoIcons.layers_alt_fill, - "cupertino_layers_fill": CupertinoIcons.layers_fill, - "cupertino_leaf_arrow_circlepath": CupertinoIcons.leaf_arrow_circlepath, - "cupertino_lessthan": CupertinoIcons.lessthan, - "cupertino_lessthan_circle": CupertinoIcons.lessthan_circle, - "cupertino_lessthan_circle_fill": CupertinoIcons.lessthan_circle_fill, - "cupertino_lessthan_square": CupertinoIcons.lessthan_square, - "cupertino_lessthan_square_fill": CupertinoIcons.lessthan_square_fill, - "cupertino_light_max": CupertinoIcons.light_max, - "cupertino_light_min": CupertinoIcons.light_min, - "cupertino_lightbulb": CupertinoIcons.lightbulb, - "cupertino_lightbulb_fill": CupertinoIcons.lightbulb_fill, - "cupertino_lightbulb_slash": CupertinoIcons.lightbulb_slash, - "cupertino_lightbulb_slash_fill": CupertinoIcons.lightbulb_slash_fill, - "cupertino_line_horizontal_3": CupertinoIcons.line_horizontal_3, - "cupertino_line_horizontal_3_decrease": - CupertinoIcons.line_horizontal_3_decrease, - "cupertino_line_horizontal_3_decrease_circle": - CupertinoIcons.line_horizontal_3_decrease_circle, - "cupertino_line_horizontal_3_decrease_circle_fill": - CupertinoIcons.line_horizontal_3_decrease_circle_fill, - "cupertino_link": CupertinoIcons.link, - "cupertino_link_circle": CupertinoIcons.link_circle, - "cupertino_link_circle_fill": CupertinoIcons.link_circle_fill, - "cupertino_list_bullet": CupertinoIcons.list_bullet, - "cupertino_list_bullet_below_rectangle": - CupertinoIcons.list_bullet_below_rectangle, - "cupertino_list_bullet_indent": CupertinoIcons.list_bullet_indent, - "cupertino_list_dash": CupertinoIcons.list_dash, - "cupertino_list_number": CupertinoIcons.list_number, - "cupertino_list_number_rtl": CupertinoIcons.list_number_rtl, - "cupertino_location_circle": CupertinoIcons.location_circle, - "cupertino_location_circle_fill": CupertinoIcons.location_circle_fill, - "cupertino_location_fill": CupertinoIcons.location_fill, - "cupertino_location_north": CupertinoIcons.location_north, - "cupertino_location_north_fill": CupertinoIcons.location_north_fill, - "cupertino_location_north_line": CupertinoIcons.location_north_line, - "cupertino_location_north_line_fill": CupertinoIcons.location_north_line_fill, - "cupertino_location_slash": CupertinoIcons.location_slash, - "cupertino_location_slash_fill": CupertinoIcons.location_slash_fill, - "cupertino_lock": CupertinoIcons.lock, - "cupertino_lock_circle": CupertinoIcons.lock_circle, - "cupertino_lock_circle_fill": CupertinoIcons.lock_circle_fill, - "cupertino_lock_fill": CupertinoIcons.lock_fill, - "cupertino_lock_open": CupertinoIcons.lock_open, - "cupertino_lock_open_fill": CupertinoIcons.lock_open_fill, - "cupertino_lock_rotation": CupertinoIcons.lock_rotation, - "cupertino_lock_rotation_open": CupertinoIcons.lock_rotation_open, - "cupertino_lock_shield": CupertinoIcons.lock_shield, - "cupertino_lock_shield_fill": CupertinoIcons.lock_shield_fill, - "cupertino_lock_slash": CupertinoIcons.lock_slash, - "cupertino_lock_slash_fill": CupertinoIcons.lock_slash_fill, - "cupertino_macwindow": CupertinoIcons.macwindow, - "cupertino_map": CupertinoIcons.map, - "cupertino_map_fill": CupertinoIcons.map_fill, - "cupertino_map_pin": CupertinoIcons.map_pin, - "cupertino_map_pin_ellipse": CupertinoIcons.map_pin_ellipse, - "cupertino_map_pin_slash": CupertinoIcons.map_pin_slash, - "cupertino_memories": CupertinoIcons.memories, - "cupertino_memories_badge_minus": CupertinoIcons.memories_badge_minus, - "cupertino_memories_badge_plus": CupertinoIcons.memories_badge_plus, - "cupertino_metronome": CupertinoIcons.metronome, - "cupertino_mic_circle": CupertinoIcons.mic_circle, - "cupertino_mic_circle_fill": CupertinoIcons.mic_circle_fill, - "cupertino_mic_fill": CupertinoIcons.mic_fill, - "cupertino_mic_slash": CupertinoIcons.mic_slash, - "cupertino_mic_slash_fill": CupertinoIcons.mic_slash_fill, - "cupertino_minus": CupertinoIcons.minus, - "cupertino_minus_circle": CupertinoIcons.minus_circle, - "cupertino_minus_circle_fill": CupertinoIcons.minus_circle_fill, - "cupertino_minus_rectangle": CupertinoIcons.minus_rectangle, - "cupertino_minus_rectangle_fill": CupertinoIcons.minus_rectangle_fill, - "cupertino_minus_slash_plus": CupertinoIcons.minus_slash_plus, - "cupertino_minus_square": CupertinoIcons.minus_square, - "cupertino_minus_square_fill": CupertinoIcons.minus_square_fill, - "cupertino_money_dollar": CupertinoIcons.money_dollar, - "cupertino_money_dollar_circle": CupertinoIcons.money_dollar_circle, - "cupertino_money_dollar_circle_fill": CupertinoIcons.money_dollar_circle_fill, - "cupertino_money_euro": CupertinoIcons.money_euro, - "cupertino_money_euro_circle": CupertinoIcons.money_euro_circle, - "cupertino_money_euro_circle_fill": CupertinoIcons.money_euro_circle_fill, - "cupertino_money_pound": CupertinoIcons.money_pound, - "cupertino_money_pound_circle": CupertinoIcons.money_pound_circle, - "cupertino_money_pound_circle_fill": CupertinoIcons.money_pound_circle_fill, - "cupertino_money_rubl": CupertinoIcons.money_rubl, - "cupertino_money_rubl_circle": CupertinoIcons.money_rubl_circle, - "cupertino_money_rubl_circle_fill": CupertinoIcons.money_rubl_circle_fill, - "cupertino_money_yen": CupertinoIcons.money_yen, - "cupertino_money_yen_circle": CupertinoIcons.money_yen_circle, - "cupertino_money_yen_circle_fill": CupertinoIcons.money_yen_circle_fill, - "cupertino_moon": CupertinoIcons.moon, - "cupertino_moon_circle": CupertinoIcons.moon_circle, - "cupertino_moon_circle_fill": CupertinoIcons.moon_circle_fill, - "cupertino_moon_fill": CupertinoIcons.moon_fill, - "cupertino_moon_stars": CupertinoIcons.moon_stars, - "cupertino_moon_stars_fill": CupertinoIcons.moon_stars_fill, - "cupertino_moon_zzz": CupertinoIcons.moon_zzz, - "cupertino_moon_zzz_fill": CupertinoIcons.moon_zzz_fill, - "cupertino_move": CupertinoIcons.move, - "cupertino_multiply": CupertinoIcons.multiply, - "cupertino_multiply_circle": CupertinoIcons.multiply_circle, - "cupertino_multiply_circle_fill": CupertinoIcons.multiply_circle_fill, - "cupertino_multiply_square": CupertinoIcons.multiply_square, - "cupertino_multiply_square_fill": CupertinoIcons.multiply_square_fill, - "cupertino_music_albums": CupertinoIcons.music_albums, - "cupertino_music_albums_fill": CupertinoIcons.music_albums_fill, - "cupertino_music_house": CupertinoIcons.music_house, - "cupertino_music_house_fill": CupertinoIcons.music_house_fill, - "cupertino_music_mic": CupertinoIcons.music_mic, - "cupertino_music_note_2": CupertinoIcons.music_note_2, - "cupertino_music_note_list": CupertinoIcons.music_note_list, - "cupertino_nosign": CupertinoIcons.nosign, - "cupertino_number": CupertinoIcons.number, - "cupertino_number_circle": CupertinoIcons.number_circle, - "cupertino_number_circle_fill": CupertinoIcons.number_circle_fill, - "cupertino_number_square": CupertinoIcons.number_square, - "cupertino_number_square_fill": CupertinoIcons.number_square_fill, - "cupertino_option": CupertinoIcons.option, - "cupertino_paintbrush": CupertinoIcons.paintbrush, - "cupertino_paintbrush_fill": CupertinoIcons.paintbrush_fill, - "cupertino_pano": CupertinoIcons.pano, - "cupertino_pano_fill": CupertinoIcons.pano_fill, - "cupertino_paperclip": CupertinoIcons.paperclip, - "cupertino_paperplane": CupertinoIcons.paperplane, - "cupertino_paperplane_fill": CupertinoIcons.paperplane_fill, - "cupertino_paragraph": CupertinoIcons.paragraph, - "cupertino_pause_circle": CupertinoIcons.pause_circle, - "cupertino_pause_circle_fill": CupertinoIcons.pause_circle_fill, - "cupertino_pause_fill": CupertinoIcons.pause_fill, - "cupertino_pause_rectangle": CupertinoIcons.pause_rectangle, - "cupertino_pause_rectangle_fill": CupertinoIcons.pause_rectangle_fill, - "cupertino_pencil_circle": CupertinoIcons.pencil_circle, - "cupertino_pencil_circle_fill": CupertinoIcons.pencil_circle_fill, - "cupertino_pencil_ellipsis_rectangle": - CupertinoIcons.pencil_ellipsis_rectangle, - "cupertino_pencil_outline": CupertinoIcons.pencil_outline, - "cupertino_pencil_slash": CupertinoIcons.pencil_slash, - "cupertino_percent": CupertinoIcons.percent, - "cupertino_person_2": CupertinoIcons.person_2, - "cupertino_person_2_alt": CupertinoIcons.person_2_alt, - "cupertino_person_2_fill": CupertinoIcons.person_2_fill, - "cupertino_person_2_square_stack": CupertinoIcons.person_2_square_stack, - "cupertino_person_2_square_stack_fill": - CupertinoIcons.person_2_square_stack_fill, - "cupertino_person_3": CupertinoIcons.person_3, - "cupertino_person_3_fill": CupertinoIcons.person_3_fill, - "cupertino_person_alt": CupertinoIcons.person_alt, - "cupertino_person_alt_circle": CupertinoIcons.person_alt_circle, - "cupertino_person_alt_circle_fill": CupertinoIcons.person_alt_circle_fill, - "cupertino_person_badge_minus": CupertinoIcons.person_badge_minus, - "cupertino_person_badge_minus_fill": CupertinoIcons.person_badge_minus_fill, - "cupertino_person_badge_plus": CupertinoIcons.person_badge_plus, - "cupertino_person_badge_plus_fill": CupertinoIcons.person_badge_plus_fill, - "cupertino_person_circle": CupertinoIcons.person_circle, - "cupertino_person_circle_fill": CupertinoIcons.person_circle_fill, - "cupertino_person_crop_circle": CupertinoIcons.person_crop_circle, - "cupertino_person_crop_circle_badge_checkmark": - CupertinoIcons.person_crop_circle_badge_checkmark, - "cupertino_person_crop_circle_badge_exclam": - CupertinoIcons.person_crop_circle_badge_exclam, - "cupertino_person_crop_circle_badge_minus": - CupertinoIcons.person_crop_circle_badge_minus, - "cupertino_person_crop_circle_badge_plus": - CupertinoIcons.person_crop_circle_badge_plus, - "cupertino_person_crop_circle_badge_xmark": - CupertinoIcons.person_crop_circle_badge_xmark, - "cupertino_person_crop_circle_fill": CupertinoIcons.person_crop_circle_fill, - "cupertino_person_crop_circle_fill_badge_checkmark": - CupertinoIcons.person_crop_circle_fill_badge_checkmark, - "cupertino_person_crop_circle_fill_badge_exclam": - CupertinoIcons.person_crop_circle_fill_badge_exclam, - "cupertino_person_crop_circle_fill_badge_minus": - CupertinoIcons.person_crop_circle_fill_badge_minus, - "cupertino_person_crop_circle_fill_badge_plus": - CupertinoIcons.person_crop_circle_fill_badge_plus, - "cupertino_person_crop_circle_fill_badge_xmark": - CupertinoIcons.person_crop_circle_fill_badge_xmark, - "cupertino_person_crop_rectangle": CupertinoIcons.person_crop_rectangle, - "cupertino_person_crop_rectangle_fill": - CupertinoIcons.person_crop_rectangle_fill, - "cupertino_person_crop_square": CupertinoIcons.person_crop_square, - "cupertino_person_crop_square_fill": CupertinoIcons.person_crop_square_fill, - "cupertino_person_fill": CupertinoIcons.person_fill, - "cupertino_personalhotspot": CupertinoIcons.personalhotspot, - "cupertino_perspective": CupertinoIcons.perspective, - "cupertino_phone_arrow_down_left": CupertinoIcons.phone_arrow_down_left, - "cupertino_phone_arrow_right": CupertinoIcons.phone_arrow_right, - "cupertino_phone_arrow_up_right": CupertinoIcons.phone_arrow_up_right, - "cupertino_phone_badge_plus": CupertinoIcons.phone_badge_plus, - "cupertino_phone_circle": CupertinoIcons.phone_circle, - "cupertino_phone_circle_fill": CupertinoIcons.phone_circle_fill, - "cupertino_phone_down": CupertinoIcons.phone_down, - "cupertino_phone_down_circle": CupertinoIcons.phone_down_circle, - "cupertino_phone_down_circle_fill": CupertinoIcons.phone_down_circle_fill, - "cupertino_phone_down_fill": CupertinoIcons.phone_down_fill, - "cupertino_phone_fill": CupertinoIcons.phone_fill, - "cupertino_phone_fill_arrow_down_left": - CupertinoIcons.phone_fill_arrow_down_left, - "cupertino_phone_fill_arrow_right": CupertinoIcons.phone_fill_arrow_right, - "cupertino_phone_fill_arrow_up_right": - CupertinoIcons.phone_fill_arrow_up_right, - "cupertino_phone_fill_badge_plus": CupertinoIcons.phone_fill_badge_plus, - "cupertino_photo": CupertinoIcons.photo, - "cupertino_photo_fill": CupertinoIcons.photo_fill, - "cupertino_photo_fill_on_rectangle_fill": - CupertinoIcons.photo_fill_on_rectangle_fill, - "cupertino_photo_on_rectangle": CupertinoIcons.photo_on_rectangle, - "cupertino_piano": CupertinoIcons.piano, - "cupertino_pin": CupertinoIcons.pin, - "cupertino_pin_fill": CupertinoIcons.pin_fill, - "cupertino_pin_slash": CupertinoIcons.pin_slash, - "cupertino_pin_slash_fill": CupertinoIcons.pin_slash_fill, - "cupertino_placemark": CupertinoIcons.placemark, - "cupertino_placemark_fill": CupertinoIcons.placemark_fill, - "cupertino_play": CupertinoIcons.play, - "cupertino_play_circle": CupertinoIcons.play_circle, - "cupertino_play_circle_fill": CupertinoIcons.play_circle_fill, - "cupertino_play_fill": CupertinoIcons.play_fill, - "cupertino_play_rectangle": CupertinoIcons.play_rectangle, - "cupertino_play_rectangle_fill": CupertinoIcons.play_rectangle_fill, - "cupertino_playpause": CupertinoIcons.playpause, - "cupertino_playpause_fill": CupertinoIcons.playpause_fill, - "cupertino_plus": CupertinoIcons.plus, - "cupertino_plus_app": CupertinoIcons.plus_app, - "cupertino_plus_app_fill": CupertinoIcons.plus_app_fill, - "cupertino_plus_bubble": CupertinoIcons.plus_bubble, - "cupertino_plus_bubble_fill": CupertinoIcons.plus_bubble_fill, - "cupertino_plus_circle": CupertinoIcons.plus_circle, - "cupertino_plus_circle_fill": CupertinoIcons.plus_circle_fill, - "cupertino_plus_rectangle": CupertinoIcons.plus_rectangle, - "cupertino_plus_rectangle_fill": CupertinoIcons.plus_rectangle_fill, - "cupertino_plus_rectangle_fill_on_rectangle_fill": - CupertinoIcons.plus_rectangle_fill_on_rectangle_fill, - "cupertino_plus_rectangle_on_rectangle": - CupertinoIcons.plus_rectangle_on_rectangle, - "cupertino_plus_slash_minus": CupertinoIcons.plus_slash_minus, - "cupertino_plus_square": CupertinoIcons.plus_square, - "cupertino_plus_square_fill": CupertinoIcons.plus_square_fill, - "cupertino_plus_square_fill_on_square_fill": - CupertinoIcons.plus_square_fill_on_square_fill, - "cupertino_plus_square_on_square": CupertinoIcons.plus_square_on_square, - "cupertino_plusminus": CupertinoIcons.plusminus, - "cupertino_plusminus_circle": CupertinoIcons.plusminus_circle, - "cupertino_plusminus_circle_fill": CupertinoIcons.plusminus_circle_fill, - "cupertino_power": CupertinoIcons.power, - "cupertino_printer": CupertinoIcons.printer, - "cupertino_printer_fill": CupertinoIcons.printer_fill, - "cupertino_projective": CupertinoIcons.projective, - "cupertino_purchased": CupertinoIcons.purchased, - "cupertino_purchased_circle": CupertinoIcons.purchased_circle, - "cupertino_purchased_circle_fill": CupertinoIcons.purchased_circle_fill, - "cupertino_qrcode": CupertinoIcons.qrcode, - "cupertino_qrcode_viewfinder": CupertinoIcons.qrcode_viewfinder, - "cupertino_question": CupertinoIcons.question, - "cupertino_question_circle": CupertinoIcons.question_circle, - "cupertino_question_circle_fill": CupertinoIcons.question_circle_fill, - "cupertino_question_diamond": CupertinoIcons.question_diamond, - "cupertino_question_diamond_fill": CupertinoIcons.question_diamond_fill, - "cupertino_question_square": CupertinoIcons.question_square, - "cupertino_question_square_fill": CupertinoIcons.question_square_fill, - "cupertino_quote_bubble": CupertinoIcons.quote_bubble, - "cupertino_quote_bubble_fill": CupertinoIcons.quote_bubble_fill, - "cupertino_radiowaves_left": CupertinoIcons.radiowaves_left, - "cupertino_radiowaves_right": CupertinoIcons.radiowaves_right, - "cupertino_rays": CupertinoIcons.rays, - "cupertino_recordingtape": CupertinoIcons.recordingtape, - "cupertino_rectangle": CupertinoIcons.rectangle, - "cupertino_rectangle_3_offgrid": CupertinoIcons.rectangle_3_offgrid, - "cupertino_rectangle_3_offgrid_fill": CupertinoIcons.rectangle_3_offgrid_fill, - "cupertino_rectangle_arrow_up_right_arrow_down_left": - CupertinoIcons.rectangle_arrow_up_right_arrow_down_left, - "cupertino_rectangle_arrow_up_right_arrow_down_left_slash": - CupertinoIcons.rectangle_arrow_up_right_arrow_down_left_slash, - "cupertino_rectangle_badge_checkmark": - CupertinoIcons.rectangle_badge_checkmark, - "cupertino_rectangle_badge_xmark": CupertinoIcons.rectangle_badge_xmark, - "cupertino_rectangle_compress_vertical": - CupertinoIcons.rectangle_compress_vertical, - "cupertino_rectangle_dock": CupertinoIcons.rectangle_dock, - "cupertino_rectangle_expand_vertical": - CupertinoIcons.rectangle_expand_vertical, - "cupertino_rectangle_fill": CupertinoIcons.rectangle_fill, - "cupertino_rectangle_fill_badge_checkmark": - CupertinoIcons.rectangle_fill_badge_checkmark, - "cupertino_rectangle_fill_badge_xmark": - CupertinoIcons.rectangle_fill_badge_xmark, - "cupertino_rectangle_fill_on_rectangle_angled_fill": - CupertinoIcons.rectangle_fill_on_rectangle_angled_fill, - "cupertino_rectangle_fill_on_rectangle_fill": - CupertinoIcons.rectangle_fill_on_rectangle_fill, - "cupertino_rectangle_grid_1x2": CupertinoIcons.rectangle_grid_1x2, - "cupertino_rectangle_grid_1x2_fill": CupertinoIcons.rectangle_grid_1x2_fill, - "cupertino_rectangle_grid_2x2": CupertinoIcons.rectangle_grid_2x2, - "cupertino_rectangle_grid_2x2_fill": CupertinoIcons.rectangle_grid_2x2_fill, - "cupertino_rectangle_grid_3x2": CupertinoIcons.rectangle_grid_3x2, - "cupertino_rectangle_grid_3x2_fill": CupertinoIcons.rectangle_grid_3x2_fill, - "cupertino_rectangle_on_rectangle": CupertinoIcons.rectangle_on_rectangle, - "cupertino_rectangle_on_rectangle_angled": - CupertinoIcons.rectangle_on_rectangle_angled, - "cupertino_rectangle_paperclip": CupertinoIcons.rectangle_paperclip, - "cupertino_rectangle_split_3x1": CupertinoIcons.rectangle_split_3x1, - "cupertino_rectangle_split_3x1_fill": CupertinoIcons.rectangle_split_3x1_fill, - "cupertino_rectangle_split_3x3": CupertinoIcons.rectangle_split_3x3, - "cupertino_rectangle_split_3x3_fill": CupertinoIcons.rectangle_split_3x3_fill, - "cupertino_rectangle_stack": CupertinoIcons.rectangle_stack, - "cupertino_rectangle_stack_badge_minus": - CupertinoIcons.rectangle_stack_badge_minus, - "cupertino_rectangle_stack_badge_person_crop": - CupertinoIcons.rectangle_stack_badge_person_crop, - "cupertino_rectangle_stack_badge_plus": - CupertinoIcons.rectangle_stack_badge_plus, - "cupertino_rectangle_stack_fill": CupertinoIcons.rectangle_stack_fill, - "cupertino_rectangle_stack_fill_badge_minus": - CupertinoIcons.rectangle_stack_fill_badge_minus, - "cupertino_rectangle_stack_fill_badge_person_crop": - CupertinoIcons.rectangle_stack_fill_badge_person_crop, - "cupertino_rectangle_stack_fill_badge_plus": - CupertinoIcons.rectangle_stack_fill_badge_plus, - "cupertino_rectangle_stack_person_crop": - CupertinoIcons.rectangle_stack_person_crop, - "cupertino_rectangle_stack_person_crop_fill": - CupertinoIcons.rectangle_stack_person_crop_fill, - "cupertino_repeat": CupertinoIcons.repeat, - "cupertino_repeat_1": CupertinoIcons.repeat_1, - "cupertino_resize": CupertinoIcons.resize, - "cupertino_resize_h": CupertinoIcons.resize_h, - "cupertino_resize_v": CupertinoIcons.resize_v, - "cupertino_return_icon": CupertinoIcons.return_icon, - "cupertino_rhombus": CupertinoIcons.rhombus, - "cupertino_rhombus_fill": CupertinoIcons.rhombus_fill, - "cupertino_rocket": CupertinoIcons.rocket, - "cupertino_rocket_fill": CupertinoIcons.rocket_fill, - "cupertino_rosette": CupertinoIcons.rosette, - "cupertino_rotate_left": CupertinoIcons.rotate_left, - "cupertino_rotate_left_fill": CupertinoIcons.rotate_left_fill, - "cupertino_rotate_right": CupertinoIcons.rotate_right, - "cupertino_rotate_right_fill": CupertinoIcons.rotate_right_fill, - "cupertino_scissors": CupertinoIcons.scissors, - "cupertino_scissors_alt": CupertinoIcons.scissors_alt, - "cupertino_scope": CupertinoIcons.scope, - "cupertino_scribble": CupertinoIcons.scribble, - "cupertino_search_circle": CupertinoIcons.search_circle, - "cupertino_search_circle_fill": CupertinoIcons.search_circle_fill, - "cupertino_selection_pin_in_out": CupertinoIcons.selection_pin_in_out, - "cupertino_shield": CupertinoIcons.shield, - "cupertino_shield_fill": CupertinoIcons.shield_fill, - "cupertino_shield_lefthalf_fill": CupertinoIcons.shield_lefthalf_fill, - "cupertino_shield_slash": CupertinoIcons.shield_slash, - "cupertino_shield_slash_fill": CupertinoIcons.shield_slash_fill, - "cupertino_shift": CupertinoIcons.shift, - "cupertino_shift_fill": CupertinoIcons.shift_fill, - "cupertino_sidebar_left": CupertinoIcons.sidebar_left, - "cupertino_sidebar_right": CupertinoIcons.sidebar_right, - "cupertino_signature": CupertinoIcons.signature, - "cupertino_skew": CupertinoIcons.skew, - "cupertino_slash_circle": CupertinoIcons.slash_circle, - "cupertino_slash_circle_fill": CupertinoIcons.slash_circle_fill, - "cupertino_slider_horizontal_3": CupertinoIcons.slider_horizontal_3, - "cupertino_slider_horizontal_below_rectangle": - CupertinoIcons.slider_horizontal_below_rectangle, - "cupertino_slowmo": CupertinoIcons.slowmo, - "cupertino_smallcircle_circle": CupertinoIcons.smallcircle_circle, - "cupertino_smallcircle_circle_fill": CupertinoIcons.smallcircle_circle_fill, - "cupertino_smallcircle_fill_circle": CupertinoIcons.smallcircle_fill_circle, - "cupertino_smallcircle_fill_circle_fill": - CupertinoIcons.smallcircle_fill_circle_fill, - "cupertino_smiley": CupertinoIcons.smiley, - "cupertino_smiley_fill": CupertinoIcons.smiley_fill, - "cupertino_smoke": CupertinoIcons.smoke, - "cupertino_smoke_fill": CupertinoIcons.smoke_fill, - "cupertino_snow": CupertinoIcons.snow, - "cupertino_sort_down": CupertinoIcons.sort_down, - "cupertino_sort_down_circle": CupertinoIcons.sort_down_circle, - "cupertino_sort_down_circle_fill": CupertinoIcons.sort_down_circle_fill, - "cupertino_sort_up": CupertinoIcons.sort_up, - "cupertino_sort_up_circle": CupertinoIcons.sort_up_circle, - "cupertino_sort_up_circle_fill": CupertinoIcons.sort_up_circle_fill, - "cupertino_sparkles": CupertinoIcons.sparkles, - "cupertino_speaker": CupertinoIcons.speaker, - "cupertino_speaker_1": CupertinoIcons.speaker_1, - "cupertino_speaker_1_fill": CupertinoIcons.speaker_1_fill, - "cupertino_speaker_2": CupertinoIcons.speaker_2, - "cupertino_speaker_2_fill": CupertinoIcons.speaker_2_fill, - "cupertino_speaker_3": CupertinoIcons.speaker_3, - "cupertino_speaker_3_fill": CupertinoIcons.speaker_3_fill, - "cupertino_speaker_fill": CupertinoIcons.speaker_fill, - "cupertino_speaker_slash": CupertinoIcons.speaker_slash, - "cupertino_speaker_slash_fill": CupertinoIcons.speaker_slash_fill, - "cupertino_speaker_slash_fill_rtl": CupertinoIcons.speaker_slash_fill_rtl, - "cupertino_speaker_slash_rtl": CupertinoIcons.speaker_slash_rtl, - "cupertino_speaker_zzz": CupertinoIcons.speaker_zzz, - "cupertino_speaker_zzz_fill": CupertinoIcons.speaker_zzz_fill, - "cupertino_speaker_zzz_fill_rtl": CupertinoIcons.speaker_zzz_fill_rtl, - "cupertino_speaker_zzz_rtl": CupertinoIcons.speaker_zzz_rtl, - "cupertino_speedometer": CupertinoIcons.speedometer, - "cupertino_sportscourt": CupertinoIcons.sportscourt, - "cupertino_sportscourt_fill": CupertinoIcons.sportscourt_fill, - "cupertino_square": CupertinoIcons.square, - "cupertino_square_arrow_down": CupertinoIcons.square_arrow_down, - "cupertino_square_arrow_down_fill": CupertinoIcons.square_arrow_down_fill, - "cupertino_square_arrow_down_on_square": - CupertinoIcons.square_arrow_down_on_square, - "cupertino_square_arrow_down_on_square_fill": - CupertinoIcons.square_arrow_down_on_square_fill, - "cupertino_square_arrow_left": CupertinoIcons.square_arrow_left, - "cupertino_square_arrow_left_fill": CupertinoIcons.square_arrow_left_fill, - "cupertino_square_arrow_right": CupertinoIcons.square_arrow_right, - "cupertino_square_arrow_right_fill": CupertinoIcons.square_arrow_right_fill, - "cupertino_square_arrow_up": CupertinoIcons.square_arrow_up, - "cupertino_square_arrow_up_fill": CupertinoIcons.square_arrow_up_fill, - "cupertino_square_arrow_up_on_square": - CupertinoIcons.square_arrow_up_on_square, - "cupertino_square_arrow_up_on_square_fill": - CupertinoIcons.square_arrow_up_on_square_fill, - "cupertino_square_favorites": CupertinoIcons.square_favorites, - "cupertino_square_favorites_alt": CupertinoIcons.square_favorites_alt, - "cupertino_square_favorites_alt_fill": - CupertinoIcons.square_favorites_alt_fill, - "cupertino_square_favorites_fill": CupertinoIcons.square_favorites_fill, - "cupertino_square_fill": CupertinoIcons.square_fill, - "cupertino_square_fill_line_vertical_square": - CupertinoIcons.square_fill_line_vertical_square, - "cupertino_square_fill_line_vertical_square_fill": - CupertinoIcons.square_fill_line_vertical_square_fill, - "cupertino_square_fill_on_circle_fill": - CupertinoIcons.square_fill_on_circle_fill, - "cupertino_square_fill_on_square_fill": - CupertinoIcons.square_fill_on_square_fill, - "cupertino_square_grid_2x2": CupertinoIcons.square_grid_2x2, - "cupertino_square_grid_2x2_fill": CupertinoIcons.square_grid_2x2_fill, - "cupertino_square_grid_3x2": CupertinoIcons.square_grid_3x2, - "cupertino_square_grid_3x2_fill": CupertinoIcons.square_grid_3x2_fill, - "cupertino_square_grid_4x3_fill": CupertinoIcons.square_grid_4x3_fill, - "cupertino_square_lefthalf_fill": CupertinoIcons.square_lefthalf_fill, - "cupertino_square_line_vertical_square": - CupertinoIcons.square_line_vertical_square, - "cupertino_square_line_vertical_square_fill": - CupertinoIcons.square_line_vertical_square_fill, - "cupertino_square_list": CupertinoIcons.square_list, - "cupertino_square_list_fill": CupertinoIcons.square_list_fill, - "cupertino_square_on_circle": CupertinoIcons.square_on_circle, - "cupertino_square_on_square": CupertinoIcons.square_on_square, - "cupertino_square_pencil": CupertinoIcons.square_pencil, - "cupertino_square_pencil_fill": CupertinoIcons.square_pencil_fill, - "cupertino_square_righthalf_fill": CupertinoIcons.square_righthalf_fill, - "cupertino_square_split_1x2": CupertinoIcons.square_split_1x2, - "cupertino_square_split_1x2_fill": CupertinoIcons.square_split_1x2_fill, - "cupertino_square_split_2x1": CupertinoIcons.square_split_2x1, - "cupertino_square_split_2x1_fill": CupertinoIcons.square_split_2x1_fill, - "cupertino_square_split_2x2": CupertinoIcons.square_split_2x2, - "cupertino_square_split_2x2_fill": CupertinoIcons.square_split_2x2_fill, - "cupertino_square_stack": CupertinoIcons.square_stack, - "cupertino_square_stack_3d_down_dottedline": - CupertinoIcons.square_stack_3d_down_dottedline, - "cupertino_square_stack_3d_down_right": - CupertinoIcons.square_stack_3d_down_right, - "cupertino_square_stack_3d_down_right_fill": - CupertinoIcons.square_stack_3d_down_right_fill, - "cupertino_square_stack_3d_up": CupertinoIcons.square_stack_3d_up, - "cupertino_square_stack_3d_up_fill": CupertinoIcons.square_stack_3d_up_fill, - "cupertino_square_stack_3d_up_slash": CupertinoIcons.square_stack_3d_up_slash, - "cupertino_square_stack_3d_up_slash_fill": - CupertinoIcons.square_stack_3d_up_slash_fill, - "cupertino_square_stack_fill": CupertinoIcons.square_stack_fill, - "cupertino_squares_below_rectangle": CupertinoIcons.squares_below_rectangle, - "cupertino_star": CupertinoIcons.star, - "cupertino_star_circle": CupertinoIcons.star_circle, - "cupertino_star_circle_fill": CupertinoIcons.star_circle_fill, - "cupertino_star_fill": CupertinoIcons.star_fill, - "cupertino_star_lefthalf_fill": CupertinoIcons.star_lefthalf_fill, - "cupertino_star_slash": CupertinoIcons.star_slash, - "cupertino_star_slash_fill": CupertinoIcons.star_slash_fill, - "cupertino_staroflife": CupertinoIcons.staroflife, - "cupertino_staroflife_fill": CupertinoIcons.staroflife_fill, - "cupertino_stop": CupertinoIcons.stop, - "cupertino_stop_circle": CupertinoIcons.stop_circle, - "cupertino_stop_circle_fill": CupertinoIcons.stop_circle_fill, - "cupertino_stop_fill": CupertinoIcons.stop_fill, - "cupertino_stopwatch": CupertinoIcons.stopwatch, - "cupertino_stopwatch_fill": CupertinoIcons.stopwatch_fill, - "cupertino_strikethrough": CupertinoIcons.strikethrough, - "cupertino_suit_club": CupertinoIcons.suit_club, - "cupertino_suit_club_fill": CupertinoIcons.suit_club_fill, - "cupertino_suit_diamond": CupertinoIcons.suit_diamond, - "cupertino_suit_diamond_fill": CupertinoIcons.suit_diamond_fill, - "cupertino_suit_heart": CupertinoIcons.suit_heart, - "cupertino_suit_heart_fill": CupertinoIcons.suit_heart_fill, - "cupertino_suit_spade": CupertinoIcons.suit_spade, - "cupertino_suit_spade_fill": CupertinoIcons.suit_spade_fill, - "cupertino_sum": CupertinoIcons.sum, - "cupertino_sun_dust": CupertinoIcons.sun_dust, - "cupertino_sun_dust_fill": CupertinoIcons.sun_dust_fill, - "cupertino_sun_haze": CupertinoIcons.sun_haze, - "cupertino_sun_haze_fill": CupertinoIcons.sun_haze_fill, - "cupertino_sun_max": CupertinoIcons.sun_max, - "cupertino_sun_max_fill": CupertinoIcons.sun_max_fill, - "cupertino_sun_min": CupertinoIcons.sun_min, - "cupertino_sun_min_fill": CupertinoIcons.sun_min_fill, - "cupertino_sunrise": CupertinoIcons.sunrise, - "cupertino_sunrise_fill": CupertinoIcons.sunrise_fill, - "cupertino_sunset": CupertinoIcons.sunset, - "cupertino_sunset_fill": CupertinoIcons.sunset_fill, - "cupertino_t_bubble": CupertinoIcons.t_bubble, - "cupertino_t_bubble_fill": CupertinoIcons.t_bubble_fill, - "cupertino_table": CupertinoIcons.table, - "cupertino_table_badge_more": CupertinoIcons.table_badge_more, - "cupertino_table_badge_more_fill": CupertinoIcons.table_badge_more_fill, - "cupertino_table_fill": CupertinoIcons.table_fill, - "cupertino_tag_circle": CupertinoIcons.tag_circle, - "cupertino_tag_circle_fill": CupertinoIcons.tag_circle_fill, - "cupertino_tag_fill": CupertinoIcons.tag_fill, - "cupertino_text_aligncenter": CupertinoIcons.text_aligncenter, - "cupertino_text_alignleft": CupertinoIcons.text_alignleft, - "cupertino_text_alignright": CupertinoIcons.text_alignright, - "cupertino_text_append": CupertinoIcons.text_append, - "cupertino_text_badge_checkmark": CupertinoIcons.text_badge_checkmark, - "cupertino_text_badge_minus": CupertinoIcons.text_badge_minus, - "cupertino_text_badge_plus": CupertinoIcons.text_badge_plus, - "cupertino_text_badge_star": CupertinoIcons.text_badge_star, - "cupertino_text_badge_xmark": CupertinoIcons.text_badge_xmark, - "cupertino_text_bubble": CupertinoIcons.text_bubble, - "cupertino_text_bubble_fill": CupertinoIcons.text_bubble_fill, - "cupertino_text_cursor": CupertinoIcons.text_cursor, - "cupertino_text_insert": CupertinoIcons.text_insert, - "cupertino_text_justify": CupertinoIcons.text_justify, - "cupertino_text_justifyleft": CupertinoIcons.text_justifyleft, - "cupertino_text_justifyright": CupertinoIcons.text_justifyright, - "cupertino_text_quote": CupertinoIcons.text_quote, - "cupertino_textbox": CupertinoIcons.textbox, - "cupertino_textformat": CupertinoIcons.textformat, - "cupertino_textformat_123": CupertinoIcons.textformat_123, - "cupertino_textformat_abc": CupertinoIcons.textformat_abc, - "cupertino_textformat_abc_dottedunderline": - CupertinoIcons.textformat_abc_dottedunderline, - "cupertino_textformat_alt": CupertinoIcons.textformat_alt, - "cupertino_textformat_size": CupertinoIcons.textformat_size, - "cupertino_textformat_subscript": CupertinoIcons.textformat_subscript, - "cupertino_textformat_superscript": CupertinoIcons.textformat_superscript, - "cupertino_thermometer": CupertinoIcons.thermometer, - "cupertino_thermometer_snowflake": CupertinoIcons.thermometer_snowflake, - "cupertino_thermometer_sun": CupertinoIcons.thermometer_sun, - "cupertino_ticket": CupertinoIcons.ticket, - "cupertino_ticket_fill": CupertinoIcons.ticket_fill, - "cupertino_tickets": CupertinoIcons.tickets, - "cupertino_tickets_fill": CupertinoIcons.tickets_fill, - "cupertino_timelapse": CupertinoIcons.timelapse, - "cupertino_timer": CupertinoIcons.timer, - "cupertino_timer_fill": CupertinoIcons.timer_fill, - "cupertino_today": CupertinoIcons.today, - "cupertino_today_fill": CupertinoIcons.today_fill, - "cupertino_tornado": CupertinoIcons.tornado, - "cupertino_tortoise": CupertinoIcons.tortoise, - "cupertino_tortoise_fill": CupertinoIcons.tortoise_fill, - "cupertino_tram_fill": CupertinoIcons.tram_fill, - "cupertino_trash": CupertinoIcons.trash, - "cupertino_trash_circle": CupertinoIcons.trash_circle, - "cupertino_trash_circle_fill": CupertinoIcons.trash_circle_fill, - "cupertino_trash_fill": CupertinoIcons.trash_fill, - "cupertino_trash_slash": CupertinoIcons.trash_slash, - "cupertino_trash_slash_fill": CupertinoIcons.trash_slash_fill, - "cupertino_tray": CupertinoIcons.tray, - "cupertino_tray_2": CupertinoIcons.tray_2, - "cupertino_tray_2_fill": CupertinoIcons.tray_2_fill, - "cupertino_tray_arrow_down": CupertinoIcons.tray_arrow_down, - "cupertino_tray_arrow_down_fill": CupertinoIcons.tray_arrow_down_fill, - "cupertino_tray_arrow_up": CupertinoIcons.tray_arrow_up, - "cupertino_tray_arrow_up_fill": CupertinoIcons.tray_arrow_up_fill, - "cupertino_tray_fill": CupertinoIcons.tray_fill, - "cupertino_tray_full": CupertinoIcons.tray_full, - "cupertino_tray_full_fill": CupertinoIcons.tray_full_fill, - "cupertino_tree": CupertinoIcons.tree, - "cupertino_triangle": CupertinoIcons.triangle, - "cupertino_triangle_fill": CupertinoIcons.triangle_fill, - "cupertino_triangle_lefthalf_fill": CupertinoIcons.triangle_lefthalf_fill, - "cupertino_triangle_righthalf_fill": CupertinoIcons.triangle_righthalf_fill, - "cupertino_tropicalstorm": CupertinoIcons.tropicalstorm, - "cupertino_tuningfork": CupertinoIcons.tuningfork, - "cupertino_tv": CupertinoIcons.tv, - "cupertino_tv_circle": CupertinoIcons.tv_circle, - "cupertino_tv_circle_fill": CupertinoIcons.tv_circle_fill, - "cupertino_tv_fill": CupertinoIcons.tv_fill, - "cupertino_tv_music_note": CupertinoIcons.tv_music_note, - "cupertino_tv_music_note_fill": CupertinoIcons.tv_music_note_fill, - "cupertino_uiwindow_split_2x1": CupertinoIcons.uiwindow_split_2x1, - "cupertino_umbrella": CupertinoIcons.umbrella, - "cupertino_umbrella_fill": CupertinoIcons.umbrella_fill, - "cupertino_underline": CupertinoIcons.underline, - "cupertino_upload_circle": CupertinoIcons.upload_circle, - "cupertino_upload_circle_fill": CupertinoIcons.upload_circle_fill, - "cupertino_videocam": CupertinoIcons.videocam, - "cupertino_videocam_circle": CupertinoIcons.videocam_circle, - "cupertino_videocam_circle_fill": CupertinoIcons.videocam_circle_fill, - "cupertino_videocam_fill": CupertinoIcons.videocam_fill, - "cupertino_view_2d": CupertinoIcons.view_2d, - "cupertino_view_3d": CupertinoIcons.view_3d, - "cupertino_viewfinder": CupertinoIcons.viewfinder, - "cupertino_viewfinder_circle": CupertinoIcons.viewfinder_circle, - "cupertino_viewfinder_circle_fill": CupertinoIcons.viewfinder_circle_fill, - "cupertino_wand_rays": CupertinoIcons.wand_rays, - "cupertino_wand_rays_inverse": CupertinoIcons.wand_rays_inverse, - "cupertino_wand_stars": CupertinoIcons.wand_stars, - "cupertino_wand_stars_inverse": CupertinoIcons.wand_stars_inverse, - "cupertino_waveform": CupertinoIcons.waveform, - "cupertino_waveform_circle": CupertinoIcons.waveform_circle, - "cupertino_waveform_circle_fill": CupertinoIcons.waveform_circle_fill, - "cupertino_waveform_path": CupertinoIcons.waveform_path, - "cupertino_waveform_path_badge_minus": - CupertinoIcons.waveform_path_badge_minus, - "cupertino_waveform_path_badge_plus": CupertinoIcons.waveform_path_badge_plus, - "cupertino_waveform_path_ecg": CupertinoIcons.waveform_path_ecg, - "cupertino_wifi": CupertinoIcons.wifi, - "cupertino_wifi_exclamationmark": CupertinoIcons.wifi_exclamationmark, - "cupertino_wifi_slash": CupertinoIcons.wifi_slash, - "cupertino_wind": CupertinoIcons.wind, - "cupertino_wind_snow": CupertinoIcons.wind_snow, - "cupertino_wrench": CupertinoIcons.wrench, - "cupertino_wrench_fill": CupertinoIcons.wrench_fill, - "cupertino_xmark": CupertinoIcons.xmark, - "cupertino_xmark_circle": CupertinoIcons.xmark_circle, - "cupertino_xmark_circle_fill": CupertinoIcons.xmark_circle_fill, - "cupertino_xmark_octagon": CupertinoIcons.xmark_octagon, - "cupertino_xmark_octagon_fill": CupertinoIcons.xmark_octagon_fill, - "cupertino_xmark_rectangle": CupertinoIcons.xmark_rectangle, - "cupertino_xmark_rectangle_fill": CupertinoIcons.xmark_rectangle_fill, - "cupertino_xmark_seal": CupertinoIcons.xmark_seal, - "cupertino_xmark_seal_fill": CupertinoIcons.xmark_seal_fill, - "cupertino_xmark_shield": CupertinoIcons.xmark_shield, - "cupertino_xmark_shield_fill": CupertinoIcons.xmark_shield_fill, - "cupertino_xmark_square": CupertinoIcons.xmark_square, - "cupertino_xmark_square_fill": CupertinoIcons.xmark_square_fill, - "cupertino_zoom_in": CupertinoIcons.zoom_in, - "cupertino_zoom_out": CupertinoIcons.zoom_out, - "cupertino_zzz": CupertinoIcons.zzz, -}; +List cupertinoIcons = [ + CupertinoIcons.add, + CupertinoIcons.add_circled, + CupertinoIcons.add_circled_solid, + CupertinoIcons.airplane, + CupertinoIcons.alarm, + CupertinoIcons.alarm_fill, + CupertinoIcons.alt, + CupertinoIcons.ant, + CupertinoIcons.ant_circle, + CupertinoIcons.ant_circle_fill, + CupertinoIcons.ant_fill, + CupertinoIcons.antenna_radiowaves_left_right, + CupertinoIcons.app, + CupertinoIcons.app_badge, + CupertinoIcons.app_badge_fill, + CupertinoIcons.app_fill, + CupertinoIcons.archivebox, + CupertinoIcons.archivebox_fill, + CupertinoIcons.arrow_2_circlepath, + CupertinoIcons.arrow_2_circlepath_circle, + CupertinoIcons.arrow_2_circlepath_circle_fill, + CupertinoIcons.arrow_2_squarepath, + CupertinoIcons.arrow_3_trianglepath, + CupertinoIcons.arrow_branch, + CupertinoIcons.arrow_clockwise, + CupertinoIcons.arrow_clockwise_circle, + CupertinoIcons.arrow_clockwise_circle_fill, + CupertinoIcons.arrow_counterclockwise, + CupertinoIcons.arrow_counterclockwise_circle, + CupertinoIcons.arrow_counterclockwise_circle_fill, + CupertinoIcons.arrow_down, + CupertinoIcons.arrow_down_circle, + CupertinoIcons.arrow_down_circle_fill, + CupertinoIcons.arrow_down_doc, + CupertinoIcons.arrow_down_doc_fill, + CupertinoIcons.arrow_down_left, + CupertinoIcons.arrow_down_left_circle, + CupertinoIcons.arrow_down_left_circle_fill, + CupertinoIcons.arrow_down_left_square, + CupertinoIcons.arrow_down_left_square_fill, + CupertinoIcons.arrow_down_right, + CupertinoIcons.arrow_down_right_arrow_up_left, + CupertinoIcons.arrow_down_right_circle, + CupertinoIcons.arrow_down_right_circle_fill, + CupertinoIcons.arrow_down_right_square, + CupertinoIcons.arrow_down_right_square_fill, + CupertinoIcons.arrow_down_square, + CupertinoIcons.arrow_down_square_fill, + CupertinoIcons.arrow_down_to_line, + CupertinoIcons.arrow_down_to_line_alt, + CupertinoIcons.arrow_left, + CupertinoIcons.arrow_left_circle, + CupertinoIcons.arrow_left_circle_fill, + CupertinoIcons.arrow_left_right, + CupertinoIcons.arrow_left_right_circle, + CupertinoIcons.arrow_left_right_circle_fill, + CupertinoIcons.arrow_left_right_square, + CupertinoIcons.arrow_left_right_square_fill, + CupertinoIcons.arrow_left_square, + CupertinoIcons.arrow_left_square_fill, + CupertinoIcons.arrow_left_to_line, + CupertinoIcons.arrow_left_to_line_alt, + CupertinoIcons.arrow_merge, + CupertinoIcons.arrow_right, + CupertinoIcons.arrow_right_arrow_left, + CupertinoIcons.arrow_right_arrow_left_circle, + CupertinoIcons.arrow_right_arrow_left_circle_fill, + CupertinoIcons.arrow_right_arrow_left_square, + CupertinoIcons.arrow_right_arrow_left_square_fill, + CupertinoIcons.arrow_right_circle, + CupertinoIcons.arrow_right_circle_fill, + CupertinoIcons.arrow_right_square, + CupertinoIcons.arrow_right_square_fill, + CupertinoIcons.arrow_right_to_line, + CupertinoIcons.arrow_right_to_line_alt, + CupertinoIcons.arrow_swap, + CupertinoIcons.arrow_turn_down_left, + CupertinoIcons.arrow_turn_down_right, + CupertinoIcons.arrow_turn_left_down, + CupertinoIcons.arrow_turn_left_up, + CupertinoIcons.arrow_turn_right_down, + CupertinoIcons.arrow_turn_right_up, + CupertinoIcons.arrow_turn_up_left, + CupertinoIcons.arrow_turn_up_right, + CupertinoIcons.arrow_up, + CupertinoIcons.arrow_up_arrow_down, + CupertinoIcons.arrow_up_arrow_down_circle, + CupertinoIcons.arrow_up_arrow_down_circle_fill, + CupertinoIcons.arrow_up_arrow_down_square, + CupertinoIcons.arrow_up_arrow_down_square_fill, + CupertinoIcons.arrow_up_bin, + CupertinoIcons.arrow_up_bin_fill, + CupertinoIcons.arrow_up_circle, + CupertinoIcons.arrow_up_circle_fill, + CupertinoIcons.arrow_up_doc, + CupertinoIcons.arrow_up_doc_fill, + CupertinoIcons.arrow_up_down, + CupertinoIcons.arrow_up_down_circle, + CupertinoIcons.arrow_up_down_circle_fill, + CupertinoIcons.arrow_up_down_square, + CupertinoIcons.arrow_up_down_square_fill, + CupertinoIcons.arrow_up_left, + CupertinoIcons.arrow_up_left_arrow_down_right, + CupertinoIcons.arrow_up_left_circle, + CupertinoIcons.arrow_up_left_circle_fill, + CupertinoIcons.arrow_up_left_square, + CupertinoIcons.arrow_up_left_square_fill, + CupertinoIcons.arrow_up_right, + CupertinoIcons.arrow_up_right_circle, + CupertinoIcons.arrow_up_right_circle_fill, + CupertinoIcons.arrow_up_right_diamond, + CupertinoIcons.arrow_up_right_diamond_fill, + CupertinoIcons.arrow_up_right_square, + CupertinoIcons.arrow_up_right_square_fill, + CupertinoIcons.arrow_up_square, + CupertinoIcons.arrow_up_square_fill, + CupertinoIcons.arrow_up_to_line, + CupertinoIcons.arrow_up_to_line_alt, + CupertinoIcons.arrow_uturn_down, + CupertinoIcons.arrow_uturn_down_circle, + CupertinoIcons.arrow_uturn_down_circle_fill, + CupertinoIcons.arrow_uturn_down_square, + CupertinoIcons.arrow_uturn_down_square_fill, + CupertinoIcons.arrow_uturn_left, + CupertinoIcons.arrow_uturn_left_circle, + CupertinoIcons.arrow_uturn_left_circle_fill, + CupertinoIcons.arrow_uturn_left_square, + CupertinoIcons.arrow_uturn_left_square_fill, + CupertinoIcons.arrow_uturn_right, + CupertinoIcons.arrow_uturn_right_circle, + CupertinoIcons.arrow_uturn_right_circle_fill, + CupertinoIcons.arrow_uturn_right_square, + CupertinoIcons.arrow_uturn_right_square_fill, + CupertinoIcons.arrow_uturn_up, + CupertinoIcons.arrow_uturn_up_circle, + CupertinoIcons.arrow_uturn_up_circle_fill, + CupertinoIcons.arrow_uturn_up_square, + CupertinoIcons.arrow_uturn_up_square_fill, + CupertinoIcons.arrowshape_turn_up_left, + CupertinoIcons.arrowshape_turn_up_left_2, + CupertinoIcons.arrowshape_turn_up_left_2_fill, + CupertinoIcons.arrowshape_turn_up_left_circle, + CupertinoIcons.arrowshape_turn_up_left_circle_fill, + CupertinoIcons.arrowshape_turn_up_left_fill, + CupertinoIcons.arrowshape_turn_up_right, + CupertinoIcons.arrowshape_turn_up_right_circle, + CupertinoIcons.arrowshape_turn_up_right_circle_fill, + CupertinoIcons.arrowshape_turn_up_right_fill, + CupertinoIcons.arrowtriangle_down, + CupertinoIcons.arrowtriangle_down_circle, + CupertinoIcons.arrowtriangle_down_circle_fill, + CupertinoIcons.arrowtriangle_down_fill, + CupertinoIcons.arrowtriangle_down_square, + CupertinoIcons.arrowtriangle_down_square_fill, + CupertinoIcons.arrowtriangle_left, + CupertinoIcons.arrowtriangle_left_circle, + CupertinoIcons.arrowtriangle_left_circle_fill, + CupertinoIcons.arrowtriangle_left_fill, + CupertinoIcons.arrowtriangle_left_square, + CupertinoIcons.arrowtriangle_left_square_fill, + CupertinoIcons.arrowtriangle_right, + CupertinoIcons.arrowtriangle_right_circle, + CupertinoIcons.arrowtriangle_right_circle_fill, + CupertinoIcons.arrowtriangle_right_fill, + CupertinoIcons.arrowtriangle_right_square, + CupertinoIcons.arrowtriangle_right_square_fill, + CupertinoIcons.arrowtriangle_up, + CupertinoIcons.arrowtriangle_up_circle, + CupertinoIcons.arrowtriangle_up_circle_fill, + CupertinoIcons.arrowtriangle_up_fill, + CupertinoIcons.arrowtriangle_up_square, + CupertinoIcons.arrowtriangle_up_square_fill, + CupertinoIcons.asterisk_circle, + CupertinoIcons.asterisk_circle_fill, + CupertinoIcons.at, + CupertinoIcons.at_badge_minus, + CupertinoIcons.at_badge_plus, + CupertinoIcons.at_circle, + CupertinoIcons.at_circle_fill, + CupertinoIcons.back, + CupertinoIcons.backward, + CupertinoIcons.backward_end, + CupertinoIcons.backward_end_alt, + CupertinoIcons.backward_end_alt_fill, + CupertinoIcons.backward_end_fill, + CupertinoIcons.backward_fill, + CupertinoIcons.badge_plus_radiowaves_right, + CupertinoIcons.bag, + CupertinoIcons.bag_badge_minus, + CupertinoIcons.bag_badge_plus, + CupertinoIcons.bag_fill, + CupertinoIcons.bag_fill_badge_minus, + CupertinoIcons.bag_fill_badge_plus, + CupertinoIcons.bandage, + CupertinoIcons.bandage_fill, + CupertinoIcons.barcode, + CupertinoIcons.barcode_viewfinder, + CupertinoIcons.bars, + CupertinoIcons.battery_0, + CupertinoIcons.battery_100, + CupertinoIcons.battery_25, + CupertinoIcons.battery_25_percent, + CupertinoIcons.battery_75_percent, + CupertinoIcons.battery_charging, + CupertinoIcons.battery_empty, + CupertinoIcons.battery_full, + CupertinoIcons.bed_double, + CupertinoIcons.bed_double_fill, + CupertinoIcons.bell, + CupertinoIcons.bell_circle, + CupertinoIcons.bell_circle_fill, + CupertinoIcons.bell_fill, + CupertinoIcons.bell_slash, + CupertinoIcons.bell_slash_fill, + CupertinoIcons.bell_solid, + CupertinoIcons.bin_xmark, + CupertinoIcons.bin_xmark_fill, + CupertinoIcons.bitcoin, + CupertinoIcons.bitcoin_circle, + CupertinoIcons.bitcoin_circle_fill, + CupertinoIcons.bluetooth, + CupertinoIcons.bold, + CupertinoIcons.bold_italic_underline, + CupertinoIcons.bold_underline, + CupertinoIcons.bolt, + CupertinoIcons.bolt_badge_a, + CupertinoIcons.bolt_badge_a_fill, + CupertinoIcons.bolt_circle, + CupertinoIcons.bolt_circle_fill, + CupertinoIcons.bolt_fill, + CupertinoIcons.bolt_horizontal, + CupertinoIcons.bolt_horizontal_circle, + CupertinoIcons.bolt_horizontal_circle_fill, + CupertinoIcons.bolt_horizontal_fill, + CupertinoIcons.bolt_slash, + CupertinoIcons.bolt_slash_fill, + CupertinoIcons.book, + CupertinoIcons.book_circle, + CupertinoIcons.book_circle_fill, + CupertinoIcons.book_fill, + CupertinoIcons.book_solid, + CupertinoIcons.bookmark, + CupertinoIcons.bookmark_fill, + CupertinoIcons.bookmark_solid, + CupertinoIcons.briefcase, + CupertinoIcons.briefcase_fill, + CupertinoIcons.brightness, + CupertinoIcons.brightness_solid, + CupertinoIcons.bubble_left, + CupertinoIcons.bubble_left_bubble_right, + CupertinoIcons.bubble_left_bubble_right_fill, + CupertinoIcons.bubble_left_fill, + CupertinoIcons.bubble_middle_bottom, + CupertinoIcons.bubble_middle_bottom_fill, + CupertinoIcons.bubble_middle_top, + CupertinoIcons.bubble_middle_top_fill, + CupertinoIcons.bubble_right, + CupertinoIcons.bubble_right_fill, + CupertinoIcons.building_2_fill, + CupertinoIcons.burn, + CupertinoIcons.burst, + CupertinoIcons.burst_fill, + CupertinoIcons.bus, + CupertinoIcons.calendar, + CupertinoIcons.calendar_badge_minus, + CupertinoIcons.calendar_badge_plus, + CupertinoIcons.calendar_circle, + CupertinoIcons.calendar_circle_fill, + CupertinoIcons.calendar_today, + CupertinoIcons.camera, + CupertinoIcons.camera_circle, + CupertinoIcons.camera_circle_fill, + CupertinoIcons.camera_fill, + CupertinoIcons.camera_on_rectangle, + CupertinoIcons.camera_on_rectangle_fill, + CupertinoIcons.camera_rotate, + CupertinoIcons.camera_rotate_fill, + CupertinoIcons.camera_viewfinder, + CupertinoIcons.capslock, + CupertinoIcons.capslock_fill, + CupertinoIcons.capsule, + CupertinoIcons.capsule_fill, + CupertinoIcons.captions_bubble, + CupertinoIcons.captions_bubble_fill, + CupertinoIcons.car, + CupertinoIcons.car_detailed, + CupertinoIcons.car_fill, + CupertinoIcons.cart, + CupertinoIcons.cart_badge_minus, + CupertinoIcons.cart_badge_plus, + CupertinoIcons.cart_fill, + CupertinoIcons.cart_fill_badge_minus, + CupertinoIcons.cart_fill_badge_plus, + CupertinoIcons.chart_bar, + CupertinoIcons.chart_bar_alt_fill, + CupertinoIcons.chart_bar_circle, + CupertinoIcons.chart_bar_circle_fill, + CupertinoIcons.chart_bar_fill, + CupertinoIcons.chart_bar_square, + CupertinoIcons.chart_bar_square_fill, + CupertinoIcons.chart_pie, + CupertinoIcons.chart_pie_fill, + CupertinoIcons.chat_bubble, + CupertinoIcons.chat_bubble_2, + CupertinoIcons.chat_bubble_2_fill, + CupertinoIcons.chat_bubble_fill, + CupertinoIcons.chat_bubble_text, + CupertinoIcons.chat_bubble_text_fill, + CupertinoIcons.check_mark, + CupertinoIcons.check_mark_circled, + CupertinoIcons.check_mark_circled_solid, + CupertinoIcons.checkmark, + CupertinoIcons.checkmark_alt, + CupertinoIcons.checkmark_alt_circle, + CupertinoIcons.checkmark_alt_circle_fill, + CupertinoIcons.checkmark_circle, + CupertinoIcons.checkmark_circle_fill, + CupertinoIcons.checkmark_rectangle, + CupertinoIcons.checkmark_rectangle_fill, + CupertinoIcons.checkmark_seal, + CupertinoIcons.checkmark_seal_fill, + CupertinoIcons.checkmark_shield, + CupertinoIcons.checkmark_shield_fill, + CupertinoIcons.checkmark_square, + CupertinoIcons.checkmark_square_fill, + CupertinoIcons.chevron_back, + CupertinoIcons.chevron_compact_down, + CupertinoIcons.chevron_compact_left, + CupertinoIcons.chevron_compact_right, + CupertinoIcons.chevron_compact_up, + CupertinoIcons.chevron_down, + CupertinoIcons.chevron_down_circle, + CupertinoIcons.chevron_down_circle_fill, + CupertinoIcons.chevron_down_square, + CupertinoIcons.chevron_down_square_fill, + CupertinoIcons.chevron_forward, + CupertinoIcons.chevron_left, + CupertinoIcons.chevron_left_2, + CupertinoIcons.chevron_left_circle, + CupertinoIcons.chevron_left_circle_fill, + CupertinoIcons.chevron_left_slash_chevron_right, + CupertinoIcons.chevron_left_square, + CupertinoIcons.chevron_left_square_fill, + CupertinoIcons.chevron_right, + CupertinoIcons.chevron_right_2, + CupertinoIcons.chevron_right_circle, + CupertinoIcons.chevron_right_circle_fill, + CupertinoIcons.chevron_right_square, + CupertinoIcons.chevron_right_square_fill, + CupertinoIcons.chevron_up, + CupertinoIcons.chevron_up_chevron_down, + CupertinoIcons.chevron_up_circle, + CupertinoIcons.chevron_up_circle_fill, + CupertinoIcons.chevron_up_square, + CupertinoIcons.chevron_up_square_fill, + CupertinoIcons.circle, + CupertinoIcons.circle_bottomthird_split, + CupertinoIcons.circle_fill, + CupertinoIcons.circle_filled, + CupertinoIcons.circle_grid_3x3, + CupertinoIcons.circle_grid_3x3_fill, + CupertinoIcons.circle_grid_hex, + CupertinoIcons.circle_grid_hex_fill, + CupertinoIcons.circle_lefthalf_fill, + CupertinoIcons.circle_righthalf_fill, + CupertinoIcons.clear, + CupertinoIcons.clear_circled, + CupertinoIcons.clear_circled_solid, + CupertinoIcons.clear_fill, + CupertinoIcons.clear_thick, + CupertinoIcons.clear_thick_circled, + CupertinoIcons.clock, + CupertinoIcons.clock_fill, + CupertinoIcons.clock_solid, + CupertinoIcons.cloud, + CupertinoIcons.cloud_bolt, + CupertinoIcons.cloud_bolt_fill, + CupertinoIcons.cloud_bolt_rain, + CupertinoIcons.cloud_bolt_rain_fill, + CupertinoIcons.cloud_download, + CupertinoIcons.cloud_download_fill, + CupertinoIcons.cloud_drizzle, + CupertinoIcons.cloud_drizzle_fill, + CupertinoIcons.cloud_fill, + CupertinoIcons.cloud_fog, + CupertinoIcons.cloud_fog_fill, + CupertinoIcons.cloud_hail, + CupertinoIcons.cloud_hail_fill, + CupertinoIcons.cloud_heavyrain, + CupertinoIcons.cloud_heavyrain_fill, + CupertinoIcons.cloud_moon, + CupertinoIcons.cloud_moon_bolt, + CupertinoIcons.cloud_moon_bolt_fill, + CupertinoIcons.cloud_moon_fill, + CupertinoIcons.cloud_moon_rain, + CupertinoIcons.cloud_moon_rain_fill, + CupertinoIcons.cloud_rain, + CupertinoIcons.cloud_rain_fill, + CupertinoIcons.cloud_sleet, + CupertinoIcons.cloud_sleet_fill, + CupertinoIcons.cloud_snow, + CupertinoIcons.cloud_snow_fill, + CupertinoIcons.cloud_sun, + CupertinoIcons.cloud_sun_bolt, + CupertinoIcons.cloud_sun_bolt_fill, + CupertinoIcons.cloud_sun_fill, + CupertinoIcons.cloud_sun_rain, + CupertinoIcons.cloud_sun_rain_fill, + CupertinoIcons.cloud_upload, + CupertinoIcons.cloud_upload_fill, + CupertinoIcons.collections, + CupertinoIcons.collections_solid, + CupertinoIcons.color_filter, + CupertinoIcons.color_filter_fill, + CupertinoIcons.command, + CupertinoIcons.compass, + CupertinoIcons.compass_fill, + CupertinoIcons.control, + CupertinoIcons.conversation_bubble, + CupertinoIcons.create, + CupertinoIcons.create_solid, + CupertinoIcons.creditcard, + CupertinoIcons.creditcard_fill, + CupertinoIcons.crop, + CupertinoIcons.crop_rotate, + CupertinoIcons.cube, + CupertinoIcons.cube_box, + CupertinoIcons.cube_box_fill, + CupertinoIcons.cube_fill, + CupertinoIcons.cursor_rays, + CupertinoIcons.decrease_indent, + CupertinoIcons.decrease_quotelevel, + CupertinoIcons.delete, + CupertinoIcons.delete_left, + CupertinoIcons.delete_left_fill, + CupertinoIcons.delete_right, + CupertinoIcons.delete_right_fill, + CupertinoIcons.delete_simple, + CupertinoIcons.delete_solid, + CupertinoIcons.desktopcomputer, + CupertinoIcons.device_desktop, + CupertinoIcons.device_laptop, + CupertinoIcons.device_phone_landscape, + CupertinoIcons.device_phone_portrait, + CupertinoIcons.dial, + CupertinoIcons.dial_fill, + CupertinoIcons.divide, + CupertinoIcons.divide_circle, + CupertinoIcons.divide_circle_fill, + CupertinoIcons.divide_square, + CupertinoIcons.divide_square_fill, + CupertinoIcons.doc, + CupertinoIcons.doc_append, + CupertinoIcons.doc_chart, + CupertinoIcons.doc_chart_fill, + CupertinoIcons.doc_checkmark, + CupertinoIcons.doc_checkmark_fill, + CupertinoIcons.doc_circle, + CupertinoIcons.doc_circle_fill, + CupertinoIcons.doc_fill, + CupertinoIcons.doc_on_clipboard, + CupertinoIcons.doc_on_clipboard_fill, + CupertinoIcons.doc_on_doc, + CupertinoIcons.doc_on_doc_fill, + CupertinoIcons.doc_person, + CupertinoIcons.doc_person_fill, + CupertinoIcons.doc_plaintext, + CupertinoIcons.doc_richtext, + CupertinoIcons.doc_text, + CupertinoIcons.doc_text_fill, + CupertinoIcons.doc_text_search, + CupertinoIcons.doc_text_viewfinder, + CupertinoIcons.dot_radiowaves_left_right, + CupertinoIcons.dot_radiowaves_right, + CupertinoIcons.dot_square, + CupertinoIcons.dot_square_fill, + CupertinoIcons.double_music_note, + CupertinoIcons.down_arrow, + CupertinoIcons.download_circle, + CupertinoIcons.download_circle_fill, + CupertinoIcons.drop, + CupertinoIcons.drop_fill, + CupertinoIcons.drop_triangle, + CupertinoIcons.drop_triangle_fill, + CupertinoIcons.ear, + CupertinoIcons.eject, + CupertinoIcons.eject_fill, + CupertinoIcons.ellipses_bubble, + CupertinoIcons.ellipses_bubble_fill, + CupertinoIcons.ellipsis, + CupertinoIcons.ellipsis_circle, + CupertinoIcons.ellipsis_circle_fill, + CupertinoIcons.ellipsis_vertical, + CupertinoIcons.ellipsis_vertical_circle, + CupertinoIcons.ellipsis_vertical_circle_fill, + CupertinoIcons.envelope, + CupertinoIcons.envelope_badge, + CupertinoIcons.envelope_badge_fill, + CupertinoIcons.envelope_circle, + CupertinoIcons.envelope_circle_fill, + CupertinoIcons.envelope_fill, + CupertinoIcons.envelope_open, + CupertinoIcons.envelope_open_fill, + CupertinoIcons.equal, + CupertinoIcons.equal_circle, + CupertinoIcons.equal_circle_fill, + CupertinoIcons.equal_square, + CupertinoIcons.equal_square_fill, + CupertinoIcons.escape, + CupertinoIcons.exclamationmark, + CupertinoIcons.exclamationmark_bubble, + CupertinoIcons.exclamationmark_bubble_fill, + CupertinoIcons.exclamationmark_circle, + CupertinoIcons.exclamationmark_circle_fill, + CupertinoIcons.exclamationmark_octagon, + CupertinoIcons.exclamationmark_octagon_fill, + CupertinoIcons.exclamationmark_shield, + CupertinoIcons.exclamationmark_shield_fill, + CupertinoIcons.exclamationmark_square, + CupertinoIcons.exclamationmark_square_fill, + CupertinoIcons.exclamationmark_triangle, + CupertinoIcons.exclamationmark_triangle_fill, + CupertinoIcons.eye, + CupertinoIcons.eye_fill, + CupertinoIcons.eye_slash, + CupertinoIcons.eye_slash_fill, + CupertinoIcons.eye_solid, + CupertinoIcons.eyedropper, + CupertinoIcons.eyedropper_full, + CupertinoIcons.eyedropper_halffull, + CupertinoIcons.eyeglasses, + CupertinoIcons.f_cursive, + CupertinoIcons.f_cursive_circle, + CupertinoIcons.f_cursive_circle_fill, + CupertinoIcons.film, + CupertinoIcons.film_fill, + CupertinoIcons.flag, + CupertinoIcons.flag_circle, + CupertinoIcons.flag_circle_fill, + CupertinoIcons.flag_fill, + CupertinoIcons.flag_slash, + CupertinoIcons.flag_slash_fill, + CupertinoIcons.flame, + CupertinoIcons.flame_fill, + CupertinoIcons.floppy_disk, + CupertinoIcons.flowchart, + CupertinoIcons.flowchart_fill, + CupertinoIcons.folder, + CupertinoIcons.folder_badge_minus, + CupertinoIcons.folder_badge_person_crop, + CupertinoIcons.folder_badge_plus, + CupertinoIcons.folder_circle, + CupertinoIcons.folder_circle_fill, + CupertinoIcons.folder_fill, + CupertinoIcons.folder_fill_badge_minus, + CupertinoIcons.folder_fill_badge_person_crop, + CupertinoIcons.folder_fill_badge_plus, + CupertinoIcons.folder_open, + CupertinoIcons.folder_solid, + CupertinoIcons.forward, + CupertinoIcons.forward_end, + CupertinoIcons.forward_end_alt, + CupertinoIcons.forward_end_alt_fill, + CupertinoIcons.forward_end_fill, + CupertinoIcons.forward_fill, + CupertinoIcons.fullscreen, + CupertinoIcons.fullscreen_exit, + CupertinoIcons.function, + CupertinoIcons.fx, + CupertinoIcons.game_controller, + CupertinoIcons.game_controller_solid, + CupertinoIcons.gamecontroller, + CupertinoIcons.gamecontroller_alt_fill, + CupertinoIcons.gamecontroller_fill, + CupertinoIcons.gauge, + CupertinoIcons.gauge_badge_minus, + CupertinoIcons.gauge_badge_plus, + CupertinoIcons.gear, + CupertinoIcons.gear_alt, + CupertinoIcons.gear_alt_fill, + CupertinoIcons.gear_big, + CupertinoIcons.gear_solid, + CupertinoIcons.gift, + CupertinoIcons.gift_alt, + CupertinoIcons.gift_alt_fill, + CupertinoIcons.gift_fill, + CupertinoIcons.globe, + CupertinoIcons.gobackward, + CupertinoIcons.gobackward_10, + CupertinoIcons.gobackward_15, + CupertinoIcons.gobackward_30, + CupertinoIcons.gobackward_45, + CupertinoIcons.gobackward_60, + CupertinoIcons.gobackward_75, + CupertinoIcons.gobackward_90, + CupertinoIcons.gobackward_minus, + CupertinoIcons.goforward, + CupertinoIcons.goforward_10, + CupertinoIcons.goforward_15, + CupertinoIcons.goforward_30, + CupertinoIcons.goforward_45, + CupertinoIcons.goforward_60, + CupertinoIcons.goforward_75, + CupertinoIcons.goforward_90, + CupertinoIcons.goforward_plus, + CupertinoIcons.graph_circle, + CupertinoIcons.graph_circle_fill, + CupertinoIcons.graph_square, + CupertinoIcons.graph_square_fill, + CupertinoIcons.greaterthan, + CupertinoIcons.greaterthan_circle, + CupertinoIcons.greaterthan_circle_fill, + CupertinoIcons.greaterthan_square, + CupertinoIcons.greaterthan_square_fill, + CupertinoIcons.grid, + CupertinoIcons.grid_circle, + CupertinoIcons.grid_circle_fill, + CupertinoIcons.group, + CupertinoIcons.group_solid, + CupertinoIcons.guitars, + CupertinoIcons.hammer, + CupertinoIcons.hammer_fill, + CupertinoIcons.hand_draw, + CupertinoIcons.hand_draw_fill, + CupertinoIcons.hand_point_left, + CupertinoIcons.hand_point_left_fill, + CupertinoIcons.hand_point_right, + CupertinoIcons.hand_point_right_fill, + CupertinoIcons.hand_raised, + CupertinoIcons.hand_raised_fill, + CupertinoIcons.hand_raised_slash, + CupertinoIcons.hand_raised_slash_fill, + CupertinoIcons.hand_thumbsdown, + CupertinoIcons.hand_thumbsdown_fill, + CupertinoIcons.hand_thumbsup, + CupertinoIcons.hand_thumbsup_fill, + CupertinoIcons.hare, + CupertinoIcons.hare_fill, + CupertinoIcons.headphones, + CupertinoIcons.heart, + CupertinoIcons.heart_circle, + CupertinoIcons.heart_circle_fill, + CupertinoIcons.heart_fill, + CupertinoIcons.heart_slash, + CupertinoIcons.heart_slash_circle, + CupertinoIcons.heart_slash_circle_fill, + CupertinoIcons.heart_slash_fill, + CupertinoIcons.heart_solid, + CupertinoIcons.helm, + CupertinoIcons.hexagon, + CupertinoIcons.hexagon_fill, + CupertinoIcons.hifispeaker, + CupertinoIcons.hifispeaker_fill, + CupertinoIcons.home, + CupertinoIcons.hourglass, + CupertinoIcons.hourglass_bottomhalf_fill, + CupertinoIcons.hourglass_tophalf_fill, + CupertinoIcons.house, + CupertinoIcons.house_alt, + CupertinoIcons.house_alt_fill, + CupertinoIcons.house_fill, + CupertinoIcons.hurricane, + CupertinoIcons.increase_indent, + CupertinoIcons.increase_quotelevel, + CupertinoIcons.infinite, + CupertinoIcons.info, + CupertinoIcons.info_circle, + CupertinoIcons.info_circle_fill, + CupertinoIcons.italic, + CupertinoIcons.keyboard, + CupertinoIcons.keyboard_chevron_compact_down, + CupertinoIcons.lab_flask, + CupertinoIcons.lab_flask_solid, + CupertinoIcons.largecircle_fill_circle, + CupertinoIcons.lasso, + CupertinoIcons.layers, + CupertinoIcons.layers_alt, + CupertinoIcons.layers_alt_fill, + CupertinoIcons.layers_fill, + CupertinoIcons.leaf_arrow_circlepath, + CupertinoIcons.left_chevron, + CupertinoIcons.lessthan, + CupertinoIcons.lessthan_circle, + CupertinoIcons.lessthan_circle_fill, + CupertinoIcons.lessthan_square, + CupertinoIcons.lessthan_square_fill, + CupertinoIcons.light_max, + CupertinoIcons.light_min, + CupertinoIcons.lightbulb, + CupertinoIcons.lightbulb_fill, + CupertinoIcons.lightbulb_slash, + CupertinoIcons.lightbulb_slash_fill, + CupertinoIcons.line_horizontal_3, + CupertinoIcons.line_horizontal_3_decrease, + CupertinoIcons.line_horizontal_3_decrease_circle, + CupertinoIcons.line_horizontal_3_decrease_circle_fill, + CupertinoIcons.link, + CupertinoIcons.link_circle, + CupertinoIcons.link_circle_fill, + CupertinoIcons.list_bullet, + CupertinoIcons.list_bullet_below_rectangle, + CupertinoIcons.list_bullet_indent, + CupertinoIcons.list_dash, + CupertinoIcons.list_number, + CupertinoIcons.list_number_rtl, + CupertinoIcons.location, + CupertinoIcons.location_circle, + CupertinoIcons.location_circle_fill, + CupertinoIcons.location_fill, + CupertinoIcons.location_north, + CupertinoIcons.location_north_fill, + CupertinoIcons.location_north_line, + CupertinoIcons.location_north_line_fill, + CupertinoIcons.location_slash, + CupertinoIcons.location_slash_fill, + CupertinoIcons.location_solid, + CupertinoIcons.lock, + CupertinoIcons.lock_circle, + CupertinoIcons.lock_circle_fill, + CupertinoIcons.lock_fill, + CupertinoIcons.lock_open, + CupertinoIcons.lock_open_fill, + CupertinoIcons.lock_rotation, + CupertinoIcons.lock_rotation_open, + CupertinoIcons.lock_shield, + CupertinoIcons.lock_shield_fill, + CupertinoIcons.lock_slash, + CupertinoIcons.lock_slash_fill, + CupertinoIcons.loop, + CupertinoIcons.loop_thick, + CupertinoIcons.macwindow, + CupertinoIcons.mail, + CupertinoIcons.mail_solid, + CupertinoIcons.map, + CupertinoIcons.map_fill, + CupertinoIcons.map_pin, + CupertinoIcons.map_pin_ellipse, + CupertinoIcons.map_pin_slash, + CupertinoIcons.memories, + CupertinoIcons.memories_badge_minus, + CupertinoIcons.memories_badge_plus, + CupertinoIcons.metronome, + CupertinoIcons.mic, + CupertinoIcons.mic_circle, + CupertinoIcons.mic_circle_fill, + CupertinoIcons.mic_fill, + CupertinoIcons.mic_off, + CupertinoIcons.mic_slash, + CupertinoIcons.mic_slash_fill, + CupertinoIcons.mic_solid, + CupertinoIcons.minus, + CupertinoIcons.minus_circle, + CupertinoIcons.minus_circle_fill, + CupertinoIcons.minus_circled, + CupertinoIcons.minus_rectangle, + CupertinoIcons.minus_rectangle_fill, + CupertinoIcons.minus_slash_plus, + CupertinoIcons.minus_square, + CupertinoIcons.minus_square_fill, + CupertinoIcons.money_dollar, + CupertinoIcons.money_dollar_circle, + CupertinoIcons.money_dollar_circle_fill, + CupertinoIcons.money_euro, + CupertinoIcons.money_euro_circle, + CupertinoIcons.money_euro_circle_fill, + CupertinoIcons.money_pound, + CupertinoIcons.money_pound_circle, + CupertinoIcons.money_pound_circle_fill, + CupertinoIcons.money_rubl, + CupertinoIcons.money_rubl_circle, + CupertinoIcons.money_rubl_circle_fill, + CupertinoIcons.money_yen, + CupertinoIcons.money_yen_circle, + CupertinoIcons.money_yen_circle_fill, + CupertinoIcons.moon, + CupertinoIcons.moon_circle, + CupertinoIcons.moon_circle_fill, + CupertinoIcons.moon_fill, + CupertinoIcons.moon_stars, + CupertinoIcons.moon_stars_fill, + CupertinoIcons.moon_zzz, + CupertinoIcons.moon_zzz_fill, + CupertinoIcons.move, + CupertinoIcons.multiply, + CupertinoIcons.multiply_circle, + CupertinoIcons.multiply_circle_fill, + CupertinoIcons.multiply_square, + CupertinoIcons.multiply_square_fill, + CupertinoIcons.music_albums, + CupertinoIcons.music_albums_fill, + CupertinoIcons.music_house, + CupertinoIcons.music_house_fill, + CupertinoIcons.music_mic, + CupertinoIcons.music_note, + CupertinoIcons.music_note_2, + CupertinoIcons.music_note_list, + CupertinoIcons.news, + CupertinoIcons.news_solid, + CupertinoIcons.nosign, + CupertinoIcons.number, + CupertinoIcons.number_circle, + CupertinoIcons.number_circle_fill, + CupertinoIcons.number_square, + CupertinoIcons.number_square_fill, + CupertinoIcons.option, + CupertinoIcons.padlock, + CupertinoIcons.padlock_solid, + CupertinoIcons.paintbrush, + CupertinoIcons.paintbrush_fill, + CupertinoIcons.pano, + CupertinoIcons.pano_fill, + CupertinoIcons.paperclip, + CupertinoIcons.paperplane, + CupertinoIcons.paperplane_fill, + CupertinoIcons.paragraph, + CupertinoIcons.pause, + CupertinoIcons.pause_circle, + CupertinoIcons.pause_circle_fill, + CupertinoIcons.pause_fill, + CupertinoIcons.pause_rectangle, + CupertinoIcons.pause_rectangle_fill, + CupertinoIcons.pause_solid, + CupertinoIcons.paw, + CupertinoIcons.paw_solid, + CupertinoIcons.pen, + CupertinoIcons.pencil, + CupertinoIcons.pencil_circle, + CupertinoIcons.pencil_circle_fill, + CupertinoIcons.pencil_ellipsis_rectangle, + CupertinoIcons.pencil_outline, + CupertinoIcons.pencil_slash, + CupertinoIcons.percent, + CupertinoIcons.person, + CupertinoIcons.person_2, + CupertinoIcons.person_2_alt, + CupertinoIcons.person_2_fill, + CupertinoIcons.person_2_square_stack, + CupertinoIcons.person_2_square_stack_fill, + CupertinoIcons.person_3, + CupertinoIcons.person_3_fill, + CupertinoIcons.person_add, + CupertinoIcons.person_add_solid, + CupertinoIcons.person_alt, + CupertinoIcons.person_alt_circle, + CupertinoIcons.person_alt_circle_fill, + CupertinoIcons.person_badge_minus, + CupertinoIcons.person_badge_minus_fill, + CupertinoIcons.person_badge_plus, + CupertinoIcons.person_badge_plus_fill, + CupertinoIcons.person_circle, + CupertinoIcons.person_circle_fill, + CupertinoIcons.person_crop_circle, + CupertinoIcons.person_crop_circle_badge_checkmark, + CupertinoIcons.person_crop_circle_badge_exclam, + CupertinoIcons.person_crop_circle_badge_minus, + CupertinoIcons.person_crop_circle_badge_plus, + CupertinoIcons.person_crop_circle_badge_xmark, + CupertinoIcons.person_crop_circle_fill, + CupertinoIcons.person_crop_circle_fill_badge_checkmark, + CupertinoIcons.person_crop_circle_fill_badge_exclam, + CupertinoIcons.person_crop_circle_fill_badge_minus, + CupertinoIcons.person_crop_circle_fill_badge_plus, + CupertinoIcons.person_crop_circle_fill_badge_xmark, + CupertinoIcons.person_crop_rectangle, + CupertinoIcons.person_crop_rectangle_fill, + CupertinoIcons.person_crop_square, + CupertinoIcons.person_crop_square_fill, + CupertinoIcons.person_fill, + CupertinoIcons.person_solid, + CupertinoIcons.personalhotspot, + CupertinoIcons.perspective, + CupertinoIcons.phone, + CupertinoIcons.phone_arrow_down_left, + CupertinoIcons.phone_arrow_right, + CupertinoIcons.phone_arrow_up_right, + CupertinoIcons.phone_badge_plus, + CupertinoIcons.phone_circle, + CupertinoIcons.phone_circle_fill, + CupertinoIcons.phone_down, + CupertinoIcons.phone_down_circle, + CupertinoIcons.phone_down_circle_fill, + CupertinoIcons.phone_down_fill, + CupertinoIcons.phone_fill, + CupertinoIcons.phone_fill_arrow_down_left, + CupertinoIcons.phone_fill_arrow_right, + CupertinoIcons.phone_fill_arrow_up_right, + CupertinoIcons.phone_fill_badge_plus, + CupertinoIcons.phone_solid, + CupertinoIcons.photo, + CupertinoIcons.photo_camera, + CupertinoIcons.photo_camera_solid, + CupertinoIcons.photo_fill, + CupertinoIcons.photo_fill_on_rectangle_fill, + CupertinoIcons.photo_on_rectangle, + CupertinoIcons.piano, + CupertinoIcons.pin, + CupertinoIcons.pin_fill, + CupertinoIcons.pin_slash, + CupertinoIcons.pin_slash_fill, + CupertinoIcons.placemark, + CupertinoIcons.placemark_fill, + CupertinoIcons.play, + CupertinoIcons.play_arrow, + CupertinoIcons.play_arrow_solid, + CupertinoIcons.play_circle, + CupertinoIcons.play_circle_fill, + CupertinoIcons.play_fill, + CupertinoIcons.play_rectangle, + CupertinoIcons.play_rectangle_fill, + CupertinoIcons.playpause, + CupertinoIcons.playpause_fill, + CupertinoIcons.plus, + CupertinoIcons.plus_app, + CupertinoIcons.plus_app_fill, + CupertinoIcons.plus_bubble, + CupertinoIcons.plus_bubble_fill, + CupertinoIcons.plus_circle, + CupertinoIcons.plus_circle_fill, + CupertinoIcons.plus_circled, + CupertinoIcons.plus_rectangle, + CupertinoIcons.plus_rectangle_fill, + CupertinoIcons.plus_rectangle_fill_on_rectangle_fill, + CupertinoIcons.plus_rectangle_on_rectangle, + CupertinoIcons.plus_slash_minus, + CupertinoIcons.plus_square, + CupertinoIcons.plus_square_fill, + CupertinoIcons.plus_square_fill_on_square_fill, + CupertinoIcons.plus_square_on_square, + CupertinoIcons.plusminus, + CupertinoIcons.plusminus_circle, + CupertinoIcons.plusminus_circle_fill, + CupertinoIcons.power, + CupertinoIcons.printer, + CupertinoIcons.printer_fill, + CupertinoIcons.profile_circled, + CupertinoIcons.projective, + CupertinoIcons.purchased, + CupertinoIcons.purchased_circle, + CupertinoIcons.purchased_circle_fill, + CupertinoIcons.qrcode, + CupertinoIcons.qrcode_viewfinder, + CupertinoIcons.question, + CupertinoIcons.question_circle, + CupertinoIcons.question_circle_fill, + CupertinoIcons.question_diamond, + CupertinoIcons.question_diamond_fill, + CupertinoIcons.question_square, + CupertinoIcons.question_square_fill, + CupertinoIcons.quote_bubble, + CupertinoIcons.quote_bubble_fill, + CupertinoIcons.radiowaves_left, + CupertinoIcons.radiowaves_right, + CupertinoIcons.rays, + CupertinoIcons.recordingtape, + CupertinoIcons.rectangle, + CupertinoIcons.rectangle_3_offgrid, + CupertinoIcons.rectangle_3_offgrid_fill, + CupertinoIcons.rectangle_arrow_up_right_arrow_down_left, + CupertinoIcons.rectangle_arrow_up_right_arrow_down_left_slash, + CupertinoIcons.rectangle_badge_checkmark, + CupertinoIcons.rectangle_badge_xmark, + CupertinoIcons.rectangle_compress_vertical, + CupertinoIcons.rectangle_dock, + CupertinoIcons.rectangle_expand_vertical, + CupertinoIcons.rectangle_fill, + CupertinoIcons.rectangle_fill_badge_checkmark, + CupertinoIcons.rectangle_fill_badge_xmark, + CupertinoIcons.rectangle_fill_on_rectangle_angled_fill, + CupertinoIcons.rectangle_fill_on_rectangle_fill, + CupertinoIcons.rectangle_grid_1x2, + CupertinoIcons.rectangle_grid_1x2_fill, + CupertinoIcons.rectangle_grid_2x2, + CupertinoIcons.rectangle_grid_2x2_fill, + CupertinoIcons.rectangle_grid_3x2, + CupertinoIcons.rectangle_grid_3x2_fill, + CupertinoIcons.rectangle_on_rectangle, + CupertinoIcons.rectangle_on_rectangle_angled, + CupertinoIcons.rectangle_paperclip, + CupertinoIcons.rectangle_split_3x1, + CupertinoIcons.rectangle_split_3x1_fill, + CupertinoIcons.rectangle_split_3x3, + CupertinoIcons.rectangle_split_3x3_fill, + CupertinoIcons.rectangle_stack, + CupertinoIcons.rectangle_stack_badge_minus, + CupertinoIcons.rectangle_stack_badge_person_crop, + CupertinoIcons.rectangle_stack_badge_plus, + CupertinoIcons.rectangle_stack_fill, + CupertinoIcons.rectangle_stack_fill_badge_minus, + CupertinoIcons.rectangle_stack_fill_badge_person_crop, + CupertinoIcons.rectangle_stack_fill_badge_plus, + CupertinoIcons.rectangle_stack_person_crop, + CupertinoIcons.rectangle_stack_person_crop_fill, + CupertinoIcons.refresh, + CupertinoIcons.refresh_bold, + CupertinoIcons.refresh_circled, + CupertinoIcons.refresh_circled_solid, + CupertinoIcons.refresh_thick, + CupertinoIcons.refresh_thin, + CupertinoIcons.repeat, + CupertinoIcons.repeat_1, + CupertinoIcons.reply, + CupertinoIcons.reply_all, + CupertinoIcons.reply_thick_solid, + CupertinoIcons.resize, + CupertinoIcons.resize_h, + CupertinoIcons.resize_v, + CupertinoIcons.restart, + CupertinoIcons.return_icon, + CupertinoIcons.rhombus, + CupertinoIcons.rhombus_fill, + CupertinoIcons.right_chevron, + CupertinoIcons.rocket, + CupertinoIcons.rocket_fill, + CupertinoIcons.rosette, + CupertinoIcons.rotate_left, + CupertinoIcons.rotate_left_fill, + CupertinoIcons.rotate_right, + CupertinoIcons.rotate_right_fill, + CupertinoIcons.scissors, + CupertinoIcons.scissors_alt, + CupertinoIcons.scope, + CupertinoIcons.scribble, + CupertinoIcons.search, + CupertinoIcons.search_circle, + CupertinoIcons.search_circle_fill, + CupertinoIcons.selection_pin_in_out, + CupertinoIcons.settings, + CupertinoIcons.settings_solid, + CupertinoIcons.share, + CupertinoIcons.share_solid, + CupertinoIcons.share_up, + CupertinoIcons.shield, + CupertinoIcons.shield_fill, + CupertinoIcons.shield_lefthalf_fill, + CupertinoIcons.shield_slash, + CupertinoIcons.shield_slash_fill, + CupertinoIcons.shift, + CupertinoIcons.shift_fill, + CupertinoIcons.shopping_cart, + CupertinoIcons.shuffle, + CupertinoIcons.shuffle_medium, + CupertinoIcons.shuffle_thick, + CupertinoIcons.sidebar_left, + CupertinoIcons.sidebar_right, + CupertinoIcons.signature, + CupertinoIcons.skew, + CupertinoIcons.slash_circle, + CupertinoIcons.slash_circle_fill, + CupertinoIcons.slider_horizontal_3, + CupertinoIcons.slider_horizontal_below_rectangle, + CupertinoIcons.slowmo, + CupertinoIcons.smallcircle_circle, + CupertinoIcons.smallcircle_circle_fill, + CupertinoIcons.smallcircle_fill_circle, + CupertinoIcons.smallcircle_fill_circle_fill, + CupertinoIcons.smiley, + CupertinoIcons.smiley_fill, + CupertinoIcons.smoke, + CupertinoIcons.smoke_fill, + CupertinoIcons.snow, + CupertinoIcons.sort_down, + CupertinoIcons.sort_down_circle, + CupertinoIcons.sort_down_circle_fill, + CupertinoIcons.sort_up, + CupertinoIcons.sort_up_circle, + CupertinoIcons.sort_up_circle_fill, + CupertinoIcons.sparkles, + CupertinoIcons.speaker, + CupertinoIcons.speaker_1, + CupertinoIcons.speaker_1_fill, + CupertinoIcons.speaker_2, + CupertinoIcons.speaker_2_fill, + CupertinoIcons.speaker_3, + CupertinoIcons.speaker_3_fill, + CupertinoIcons.speaker_fill, + CupertinoIcons.speaker_slash, + CupertinoIcons.speaker_slash_fill, + CupertinoIcons.speaker_slash_fill_rtl, + CupertinoIcons.speaker_slash_rtl, + CupertinoIcons.speaker_zzz, + CupertinoIcons.speaker_zzz_fill, + CupertinoIcons.speaker_zzz_fill_rtl, + CupertinoIcons.speaker_zzz_rtl, + CupertinoIcons.speedometer, + CupertinoIcons.sportscourt, + CupertinoIcons.sportscourt_fill, + CupertinoIcons.square, + CupertinoIcons.square_arrow_down, + CupertinoIcons.square_arrow_down_fill, + CupertinoIcons.square_arrow_down_on_square, + CupertinoIcons.square_arrow_down_on_square_fill, + CupertinoIcons.square_arrow_left, + CupertinoIcons.square_arrow_left_fill, + CupertinoIcons.square_arrow_right, + CupertinoIcons.square_arrow_right_fill, + CupertinoIcons.square_arrow_up, + CupertinoIcons.square_arrow_up_fill, + CupertinoIcons.square_arrow_up_on_square, + CupertinoIcons.square_arrow_up_on_square_fill, + CupertinoIcons.square_favorites, + CupertinoIcons.square_favorites_alt, + CupertinoIcons.square_favorites_alt_fill, + CupertinoIcons.square_favorites_fill, + CupertinoIcons.square_fill, + CupertinoIcons.square_fill_line_vertical_square, + CupertinoIcons.square_fill_line_vertical_square_fill, + CupertinoIcons.square_fill_on_circle_fill, + CupertinoIcons.square_fill_on_square_fill, + CupertinoIcons.square_grid_2x2, + CupertinoIcons.square_grid_2x2_fill, + CupertinoIcons.square_grid_3x2, + CupertinoIcons.square_grid_3x2_fill, + CupertinoIcons.square_grid_4x3_fill, + CupertinoIcons.square_lefthalf_fill, + CupertinoIcons.square_line_vertical_square, + CupertinoIcons.square_line_vertical_square_fill, + CupertinoIcons.square_list, + CupertinoIcons.square_list_fill, + CupertinoIcons.square_on_circle, + CupertinoIcons.square_on_square, + CupertinoIcons.square_pencil, + CupertinoIcons.square_pencil_fill, + CupertinoIcons.square_righthalf_fill, + CupertinoIcons.square_split_1x2, + CupertinoIcons.square_split_1x2_fill, + CupertinoIcons.square_split_2x1, + CupertinoIcons.square_split_2x1_fill, + CupertinoIcons.square_split_2x2, + CupertinoIcons.square_split_2x2_fill, + CupertinoIcons.square_stack, + CupertinoIcons.square_stack_3d_down_dottedline, + CupertinoIcons.square_stack_3d_down_right, + CupertinoIcons.square_stack_3d_down_right_fill, + CupertinoIcons.square_stack_3d_up, + CupertinoIcons.square_stack_3d_up_fill, + CupertinoIcons.square_stack_3d_up_slash, + CupertinoIcons.square_stack_3d_up_slash_fill, + CupertinoIcons.square_stack_fill, + CupertinoIcons.squares_below_rectangle, + CupertinoIcons.star, + CupertinoIcons.star_circle, + CupertinoIcons.star_circle_fill, + CupertinoIcons.star_fill, + CupertinoIcons.star_lefthalf_fill, + CupertinoIcons.star_slash, + CupertinoIcons.star_slash_fill, + CupertinoIcons.staroflife, + CupertinoIcons.staroflife_fill, + CupertinoIcons.stop, + CupertinoIcons.stop_circle, + CupertinoIcons.stop_circle_fill, + CupertinoIcons.stop_fill, + CupertinoIcons.stopwatch, + CupertinoIcons.stopwatch_fill, + CupertinoIcons.strikethrough, + CupertinoIcons.suit_club, + CupertinoIcons.suit_club_fill, + CupertinoIcons.suit_diamond, + CupertinoIcons.suit_diamond_fill, + CupertinoIcons.suit_heart, + CupertinoIcons.suit_heart_fill, + CupertinoIcons.suit_spade, + CupertinoIcons.suit_spade_fill, + CupertinoIcons.sum, + CupertinoIcons.sun_dust, + CupertinoIcons.sun_dust_fill, + CupertinoIcons.sun_haze, + CupertinoIcons.sun_haze_fill, + CupertinoIcons.sun_max, + CupertinoIcons.sun_max_fill, + CupertinoIcons.sun_min, + CupertinoIcons.sun_min_fill, + CupertinoIcons.sunrise, + CupertinoIcons.sunrise_fill, + CupertinoIcons.sunset, + CupertinoIcons.sunset_fill, + CupertinoIcons.switch_camera, + CupertinoIcons.switch_camera_solid, + CupertinoIcons.t_bubble, + CupertinoIcons.t_bubble_fill, + CupertinoIcons.table, + CupertinoIcons.table_badge_more, + CupertinoIcons.table_badge_more_fill, + CupertinoIcons.table_fill, + CupertinoIcons.tag, + CupertinoIcons.tag_circle, + CupertinoIcons.tag_circle_fill, + CupertinoIcons.tag_fill, + CupertinoIcons.tag_solid, + CupertinoIcons.tags, + CupertinoIcons.tags_solid, + CupertinoIcons.text_aligncenter, + CupertinoIcons.text_alignleft, + CupertinoIcons.text_alignright, + CupertinoIcons.text_append, + CupertinoIcons.text_badge_checkmark, + CupertinoIcons.text_badge_minus, + CupertinoIcons.text_badge_plus, + CupertinoIcons.text_badge_star, + CupertinoIcons.text_badge_xmark, + CupertinoIcons.text_bubble, + CupertinoIcons.text_bubble_fill, + CupertinoIcons.text_cursor, + CupertinoIcons.text_insert, + CupertinoIcons.text_justify, + CupertinoIcons.text_justifyleft, + CupertinoIcons.text_justifyright, + CupertinoIcons.text_quote, + CupertinoIcons.textbox, + CupertinoIcons.textformat, + CupertinoIcons.textformat_123, + CupertinoIcons.textformat_abc, + CupertinoIcons.textformat_abc_dottedunderline, + CupertinoIcons.textformat_alt, + CupertinoIcons.textformat_size, + CupertinoIcons.textformat_subscript, + CupertinoIcons.textformat_superscript, + CupertinoIcons.thermometer, + CupertinoIcons.thermometer_snowflake, + CupertinoIcons.thermometer_sun, + CupertinoIcons.ticket, + CupertinoIcons.ticket_fill, + CupertinoIcons.tickets, + CupertinoIcons.tickets_fill, + CupertinoIcons.time, + CupertinoIcons.time_solid, + CupertinoIcons.timelapse, + CupertinoIcons.timer, + CupertinoIcons.timer_fill, + CupertinoIcons.today, + CupertinoIcons.today_fill, + CupertinoIcons.tornado, + CupertinoIcons.tortoise, + CupertinoIcons.tortoise_fill, + CupertinoIcons.train_style_one, + CupertinoIcons.train_style_two, + CupertinoIcons.tram_fill, + CupertinoIcons.trash, + CupertinoIcons.trash_circle, + CupertinoIcons.trash_circle_fill, + CupertinoIcons.trash_fill, + CupertinoIcons.trash_slash, + CupertinoIcons.trash_slash_fill, + CupertinoIcons.tray, + CupertinoIcons.tray_2, + CupertinoIcons.tray_2_fill, + CupertinoIcons.tray_arrow_down, + CupertinoIcons.tray_arrow_down_fill, + CupertinoIcons.tray_arrow_up, + CupertinoIcons.tray_arrow_up_fill, + CupertinoIcons.tray_fill, + CupertinoIcons.tray_full, + CupertinoIcons.tray_full_fill, + CupertinoIcons.tree, + CupertinoIcons.triangle, + CupertinoIcons.triangle_fill, + CupertinoIcons.triangle_lefthalf_fill, + CupertinoIcons.triangle_righthalf_fill, + CupertinoIcons.tropicalstorm, + CupertinoIcons.tuningfork, + CupertinoIcons.tv, + CupertinoIcons.tv_circle, + CupertinoIcons.tv_circle_fill, + CupertinoIcons.tv_fill, + CupertinoIcons.tv_music_note, + CupertinoIcons.tv_music_note_fill, + CupertinoIcons.uiwindow_split_2x1, + CupertinoIcons.umbrella, + CupertinoIcons.umbrella_fill, + CupertinoIcons.underline, + CupertinoIcons.up_arrow, + CupertinoIcons.upload_circle, + CupertinoIcons.upload_circle_fill, + CupertinoIcons.video_camera, + CupertinoIcons.video_camera_solid, + CupertinoIcons.videocam, + CupertinoIcons.videocam_circle, + CupertinoIcons.videocam_circle_fill, + CupertinoIcons.videocam_fill, + CupertinoIcons.view_2d, + CupertinoIcons.view_3d, + CupertinoIcons.viewfinder, + CupertinoIcons.viewfinder_circle, + CupertinoIcons.viewfinder_circle_fill, + CupertinoIcons.volume_down, + CupertinoIcons.volume_mute, + CupertinoIcons.volume_off, + CupertinoIcons.volume_up, + CupertinoIcons.wand_rays, + CupertinoIcons.wand_rays_inverse, + CupertinoIcons.wand_stars, + CupertinoIcons.wand_stars_inverse, + CupertinoIcons.waveform, + CupertinoIcons.waveform_circle, + CupertinoIcons.waveform_circle_fill, + CupertinoIcons.waveform_path, + CupertinoIcons.waveform_path_badge_minus, + CupertinoIcons.waveform_path_badge_plus, + CupertinoIcons.waveform_path_ecg, + CupertinoIcons.wifi, + CupertinoIcons.wifi_exclamationmark, + CupertinoIcons.wifi_slash, + CupertinoIcons.wind, + CupertinoIcons.wind_snow, + CupertinoIcons.wrench, + CupertinoIcons.wrench_fill, + CupertinoIcons.xmark, + CupertinoIcons.xmark_circle, + CupertinoIcons.xmark_circle_fill, + CupertinoIcons.xmark_octagon, + CupertinoIcons.xmark_octagon_fill, + CupertinoIcons.xmark_rectangle, + CupertinoIcons.xmark_rectangle_fill, + CupertinoIcons.xmark_seal, + CupertinoIcons.xmark_seal_fill, + CupertinoIcons.xmark_shield, + CupertinoIcons.xmark_shield_fill, + CupertinoIcons.xmark_square, + CupertinoIcons.xmark_square_fill, + CupertinoIcons.zoom_in, + CupertinoIcons.zoom_out, + CupertinoIcons.zzz, + ]; diff --git a/packages/flet/lib/src/utils/debouncer.dart b/packages/flet/lib/src/utils/debouncer.dart index 7597269976..59d893c1a9 100644 --- a/packages/flet/lib/src/utils/debouncer.dart +++ b/packages/flet/lib/src/utils/debouncer.dart @@ -1,6 +1,7 @@ -import 'package:flutter/widgets.dart'; import 'dart:async'; +import 'package:flutter/widgets.dart'; + class Debouncer { final int milliseconds; Timer? _timer; diff --git a/packages/flet/lib/src/utils/desktop.dart b/packages/flet/lib/src/utils/desktop.dart index 6dfefcb01b..34d44b696b 100644 --- a/packages/flet/lib/src/utils/desktop.dart +++ b/packages/flet/lib/src/utils/desktop.dart @@ -1,10 +1,10 @@ -import 'package:flet/src/utils/platform.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:window_manager/window_manager.dart'; import 'package:window_to_front/window_to_front.dart'; -import '../models/window_media_data.dart'; +import '../models/window_state.dart'; +import 'platform.dart'; Future setWindowTitle(String title) async { if (isDesktopPlatform()) { @@ -105,7 +105,7 @@ Future setWindowAlwaysOnTop(bool alwaysOnTop) async { } Future setWindowAlwaysOnBottom(bool alwaysOnBottom) async { - if (isDesktopPlatform()) { + if (isLinuxDesktop() || isWindowsDesktop()) { debugPrint("setWindowAlwaysOnBottom($alwaysOnBottom)"); await windowManager.setAlwaysOnBottom(alwaysOnBottom); } @@ -178,6 +178,18 @@ Future setWindowAlignment(Alignment alignment, [bool animate = true]) async { } } +Future setWindowAspectRatio(double value) async { + if (isDesktopPlatform()) { + await windowManager.setAspectRatio(value); + } +} + +Future setWindowBrightness(Brightness value) async { + if (isDesktopPlatform()) { + await windowManager.setBrightness(value); + } +} + Future minimizeWindow() async { if (isDesktopPlatform() && !await windowManager.isMinimized()) { debugPrint("minimizeWindow()"); @@ -235,12 +247,18 @@ Future windowToFront() async { } } -Future windowStartDragging() async { +Future startDraggingWindow() async { if (isDesktopPlatform()) { await windowManager.startDragging(); } } +Future startResizingWindow(ResizeEdge edge) async { + if (isWindowsDesktop() || isLinuxDesktop()) { + await windowManager.startResizing(edge); + } +} + Future blurWindow() async { if (isDesktopPlatform() && (defaultTargetPlatform == TargetPlatform.windows || @@ -254,6 +272,15 @@ Future blurWindow() async { Future destroyWindow() async { if (isDesktopPlatform()) { debugPrint("destroyWindow()"); + if (isWindowsDesktop()) { + // Work around window_manager.destroy() stalling on Windows: + // https://github.com/leanflutter/window_manager/issues/478#issuecomment-2423413104 + if (await windowManager.isPreventClose()) { + await windowManager.setPreventClose(false); + } + await windowManager.close(); + return; + } await windowManager.destroy(); } } @@ -296,22 +323,31 @@ Future setIgnoreMouseEvents(bool ignore) async { } } -Future getWindowMediaData() async { - var m = WindowMediaData(); +Future getWindowState() async { if (isDesktopPlatform()) { - m.isMaximized = await windowManager.isMaximized(); - m.isMinimized = await windowManager.isMinimized(); - m.isFocused = await isFocused(); - m.isFullScreen = await windowManager.isFullScreen(); - m.isVisible = await windowManager.isVisible(); - var size = await windowManager.getSize(); - m.width = size.width; - m.height = size.height; - var pos = await windowManager.getPosition(); - m.left = pos.dx; - m.top = pos.dy; - return m; + final size = await windowManager.getSize(); + final pos = await windowManager.getPosition(); + + return WindowState( + maximized: await windowManager.isMaximized(), + minimized: await windowManager.isMinimized(), + fullScreen: await windowManager.isFullScreen(), + alwaysOnTop: await windowManager.isAlwaysOnTop(), + focused: await isFocused(), + visible: await windowManager.isVisible(), + opacity: await windowManager.getOpacity(), + minimizable: await windowManager.isMinimizable(), + maximizable: await windowManager.isMaximizable(), + resizable: await windowManager.isResizable(), + preventClose: await windowManager.isPreventClose(), + skipTaskBar: await windowManager.isSkipTaskbar(), + width: size.width.toDouble(), + height: size.height.toDouble(), + top: pos.dy.toDouble(), + left: pos.dx.toDouble(), + ); } else { - return Future.value(m); + throw Exception( + "getWindowState() can be called on desktop platforms only."); } -} \ No newline at end of file +} diff --git a/packages/flet/lib/src/utils/device_info.dart b/packages/flet/lib/src/utils/device_info.dart new file mode 100644 index 0000000000..25de2a4392 --- /dev/null +++ b/packages/flet/lib/src/utils/device_info.dart @@ -0,0 +1,184 @@ +import 'dart:ui'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flet/src/utils/locale.dart'; +import 'package:flutter/services.dart'; + +import 'enums.dart'; +import 'platform.dart'; + +/// Returns device information as a Map. +Future> getDeviceInfo() async { + BaseDeviceInfo deviceInfo = await DeviceInfoPlugin().deviceInfo; + return deviceInfo.asMap(); +} + +List> getDeviceLocales() => + PlatformDispatcher.instance.locales + .map((locale) => locale.toMap()) + .toList(); + +extension DeviceInfoExtension on BaseDeviceInfo { + Map asMap() { + var deviceInfo = this; + final deviceLocales = getDeviceLocales(); + if (isWebPlatform()) { + deviceInfo = (deviceInfo as WebBrowserInfo); + return { + "browser_name": deviceInfo.browserName.name, + "app_code_name": deviceInfo.appCodeName, + "app_name": deviceInfo.appName, + "app_version": deviceInfo.appVersion, + "device_memory": deviceInfo.deviceMemory, + "language": deviceInfo.language, + "languages": deviceInfo.languages, + "platform": deviceInfo.platform, + "product": deviceInfo.product, + "product_sub": deviceInfo.productSub, + "user_agent": deviceInfo.userAgent, + "vendor": deviceInfo.vendor, + "vendor_sub": deviceInfo.vendorSub, + "max_touch_points": deviceInfo.maxTouchPoints, + "hardware_concurrency": deviceInfo.hardwareConcurrency, + "locales": deviceLocales, + }; + } else { + if (isAndroidMobile()) { + deviceInfo = (deviceInfo as AndroidDeviceInfo); + return { + "available_ram_size": deviceInfo.availableRamSize, + "board": deviceInfo.board, + "bootloader": deviceInfo.bootloader, + "brand": deviceInfo.brand, + "device": deviceInfo.device, + "display": deviceInfo.display, + "fingerprint": deviceInfo.fingerprint, + "free_disk_size": deviceInfo.freeDiskSize, + "hardware": deviceInfo.hardware, + "host": deviceInfo.host, + "id": deviceInfo.id, + "is_low_ram_device": deviceInfo.isLowRamDevice, + "is_physical_device": deviceInfo.isPhysicalDevice, + "manufacturer": deviceInfo.manufacturer, + "model": deviceInfo.model, + "name": deviceInfo.name, + "physical_ram_size": deviceInfo.physicalRamSize, + "product": deviceInfo.product, + "supported_32_bit_abis": deviceInfo.supported32BitAbis, + "supported_64_bit_abis": deviceInfo.supported64BitAbis, + "supported_abis": deviceInfo.supportedAbis, + "system_features": deviceInfo.systemFeatures, + "tags": deviceInfo.tags, + "total_disk_size": deviceInfo.totalDiskSize, + "type": deviceInfo.type, + "version": { + 'base_os': deviceInfo.version.baseOS, + 'sdk': deviceInfo.version.sdkInt, + 'release': deviceInfo.version.release, + 'code_name': deviceInfo.version.codename, + 'incremental': deviceInfo.version.incremental, + 'preview_sdk': deviceInfo.version.previewSdkInt, + 'security_patch': deviceInfo.version.securityPatch, + }, + "locales": deviceLocales, + }; + } else if (isIOSMobile()) { + deviceInfo = (deviceInfo as IosDeviceInfo); + return { + "available_ram_size": deviceInfo.availableRamSize, + "free_disk_size": deviceInfo.freeDiskSize, + "is_ios_app_on_mac": deviceInfo.isiOSAppOnMac, + "is_physical_device": deviceInfo.isPhysicalDevice, + "localized_model": deviceInfo.localizedModel, + "model": deviceInfo.model, + "model_name": deviceInfo.modelName, + "name": deviceInfo.name, + "physical_ram_size": deviceInfo.physicalRamSize, + "system_name": deviceInfo.systemName, + "system_version": deviceInfo.systemVersion, + "total_disk_size": deviceInfo.totalDiskSize, + "utsname": { + "machine": deviceInfo.utsname.machine, + "node_name": deviceInfo.utsname.nodename, + "release": deviceInfo.utsname.release, + "sys_name": deviceInfo.utsname.sysname, + "version": deviceInfo.utsname.version, + }, + "identifier_for_vendor": deviceInfo.identifierForVendor, + "locales": deviceLocales, + }; + } else if (isLinuxDesktop()) { + deviceInfo = (deviceInfo as LinuxDeviceInfo); + return { + "name": deviceInfo.name, + "id": deviceInfo.id, + "pretty_name": deviceInfo.prettyName, + "version": deviceInfo.version, + "id_like": deviceInfo.idLike, + "version_code_name": deviceInfo.versionCodename, + "version_id": deviceInfo.versionId, + "build_id": deviceInfo.buildId, + "variant": deviceInfo.variant, + "variant_id": deviceInfo.variantId, + "machine_id": deviceInfo.machineId, + "locales": deviceLocales, + }; + } else if (isMacOSDesktop()) { + deviceInfo = (deviceInfo as MacOsDeviceInfo); + return { + "active_cpus": deviceInfo.activeCPUs, + "arch": deviceInfo.arch, + "computer_name": deviceInfo.computerName, + "cpu_frequency": deviceInfo.cpuFrequency, + "host_name": deviceInfo.hostName, + "kernel_version": deviceInfo.kernelVersion, + "major_version": deviceInfo.majorVersion, + "memory_size": deviceInfo.memorySize, + "minor_version": deviceInfo.minorVersion, + "model": deviceInfo.model, + "model_name": deviceInfo.modelName, + "os_release": deviceInfo.osRelease, + "patch_version": deviceInfo.patchVersion, + "system_guid": deviceInfo.systemGUID, + "locales": deviceLocales, + }; + } else if (isWindowsDesktop()) { + deviceInfo = (deviceInfo as WindowsDeviceInfo); + return { + "computer_name": deviceInfo.computerName, + "number_of_cores": deviceInfo.numberOfCores, + "system_memory": deviceInfo.systemMemoryInMegabytes, + "user_name": deviceInfo.userName, + "major_version": deviceInfo.majorVersion, + "minor_version": deviceInfo.minorVersion, + "build_number": deviceInfo.buildNumber, + "platform_id": deviceInfo.platformId, + "csd_version": deviceInfo.csdVersion, + "service_pack_major": deviceInfo.servicePackMajor, + "service_pack_minor": deviceInfo.servicePackMinor, + "suit_mask": deviceInfo.suitMask, + "product_type": deviceInfo.productType, + "reserved": deviceInfo.reserved, + "build_lab": deviceInfo.buildLab, + "build_lab_ex": deviceInfo.buildLabEx, + // "digital_product_id": deviceInfo.digitalProductId, + "display_version": deviceInfo.displayVersion, + "edition_id": deviceInfo.editionId, + "install_date": deviceInfo.installDate, + "product_id": deviceInfo.productId, + "product_name": deviceInfo.productName, + "registered_owner": deviceInfo.registeredOwner, + "release_id": deviceInfo.releaseId, + "device_id": deviceInfo.deviceId, + "locales": deviceLocales, + }; + } + return {}; + } + } +} + +DeviceOrientation? parseDeviceOrientation(String? value, + [DeviceOrientation? defaultValue]) { + return parseEnum(DeviceOrientation.values, value, defaultValue); +} diff --git a/packages/flet/lib/src/utils/dismissible.dart b/packages/flet/lib/src/utils/dismissible.dart index ecc5f70b2e..3fa8161fc5 100644 --- a/packages/flet/lib/src/utils/dismissible.dart +++ b/packages/flet/lib/src/utils/dismissible.dart @@ -1,63 +1,38 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'enums.dart'; import '../models/control.dart'; import '../utils/numbers.dart'; DismissDirection? parseDismissDirection(String? value, - [DismissDirection? defValue]) { - if (value == null) { - return defValue; - } - return DismissDirection.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; + [DismissDirection? defaultValue]) { + return parseEnum(DismissDirection.values, value, defaultValue); } -Map? parseDismissThresholds( - Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return getDismissThresholds(j1, (jv) => parseDouble(jv, 0)!); -} +Map? parseDismissThresholds(dynamic value, + [Map? defaultValue]) { + if (value == null) return defaultValue; -Map? getDismissThresholds( - dynamic jsonDictValue, T Function(dynamic) converterFromJson) { - if (jsonDictValue == null) { - return null; - } - var j = jsonDictValue; - if (j is! Map) { - j = {"": j}; - } + Map result = {}; + value.forEach((d, t) { + var direction = parseDismissDirection(d, DismissDirection.none)!; + if (direction != DismissDirection.none) { + var threshold = parseDouble(t, 0.0)!; + result[direction] = threshold; + } + }); - return getDismissThresholdsFromJSON(j, converterFromJson); + return result; } -Map getDismissThresholdsFromJSON( - Map? jsonDictValue, Function(dynamic) converterFromJson) { - Map dismissDirectionMap = {}; - - if (jsonDictValue != null) { - jsonDictValue.forEach((directionStr, jv) { - directionStr - .split(",") - .map((s) => s.trim().toLowerCase()) - .forEach((state) { - DismissDirection d = - parseDismissDirection(state, DismissDirection.none)!; - if (d != DismissDirection.none) { - dismissDirectionMap[d] = converterFromJson(jv); - } - }); - }); +extension DismissibleParsers on Control { + DismissDirection? getDismissDirection(String propertyName, + [DismissDirection? defaultValue]) { + return parseDismissDirection(get(propertyName), defaultValue); } - return dismissDirectionMap; -} \ No newline at end of file + Map? getDismissThresholds(String propertyName, + [Map? defaultValue]) { + return parseDismissThresholds(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/drawing.dart b/packages/flet/lib/src/utils/drawing.dart index 9b26ccd1db..e40510cbe4 100644 --- a/packages/flet/lib/src/utils/drawing.dart +++ b/packages/flet/lib/src/utils/drawing.dart @@ -1,114 +1,99 @@ -import 'dart:convert'; +import 'dart:math' as math; import 'dart:ui' as ui; +import 'enums.dart'; -import 'package:collection/collection.dart'; -import 'package:flet/src/utils/others.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; import '../utils/numbers.dart'; +import '../utils/transforms.dart'; import 'colors.dart'; import 'gradient.dart'; import 'images.dart'; +import 'misc.dart'; -Paint parsePaint(ThemeData theme, Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return Paint(); - } - - final j1 = json.decode(v); +Paint? parsePaint(dynamic value, ThemeData theme, [Paint? defaultValue]) { + if (value == null) return defaultValue; - return paintFromJSON(theme, j1); + var paint = Paint(); + paint.color = parseColor(value["color"] as String?, theme, Colors.black)!; + paint.blendMode = parseBlendMode(value["blend_mode"], BlendMode.srcOver)!; + paint.isAntiAlias = parseBool(value["anti_alias"], true)!; + paint.imageFilter = parseBlur(value["blur_image"]); + paint.shader = parsePaintGradient(value["gradient"], theme); + paint.strokeMiterLimit = parseDouble(value["stroke_miter_limit"], 4)!; + paint.strokeWidth = parseDouble(value["stroke_width"], 0)!; + paint.strokeCap = parseStrokeCap(value["stroke_cap"], StrokeCap.butt)!; + paint.strokeJoin = parseStrokeJoin(value["stroke_join"], StrokeJoin.miter)!; + paint.style = parsePaintingStyle(value["style"], PaintingStyle.fill)!; + return paint; } -PaintingStyle? parsePaintingStyle(String? value, [PaintingStyle? defValue]) { - if (value == null) { - return defValue; - } - return PaintingStyle.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; +PaintingStyle? parsePaintingStyle(String? value, + [PaintingStyle? defaultValue]) { + return parseEnum(PaintingStyle.values, value, defaultValue); } -List? parsePaintStrokeDashPattern(Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); +List? parsePaintStrokeDashPattern(dynamic value, + [List? defaultValue]) { + if (value == null) return defaultValue; - return j1["stroke_dash_pattern"] != null - ? (j1["stroke_dash_pattern"] as List) - .map((e) => parseDouble(e)) - .whereNotNull() - .toList() - : null; + return (value["stroke_dash_pattern"] as List?) + ?.map((e) => parseDouble(e)) + .nonNulls + .toList() ?? + defaultValue; } -Paint paintFromJSON(ThemeData? theme, Map json) { - var paint = Paint(); - if (json["color"] != null) { - paint.color = parseColor(theme, json["color"] as String, Colors.black)!; - } - paint.blendMode = parseBlendMode(json["blend_mode"], BlendMode.srcOver)!; - paint.isAntiAlias = parseBool(json["anti_alias"], true)!; - paint.imageFilter = blurImageFilterFromJSON(json["blur_image"]); - paint.shader = paintGradientFromJSON(theme, json["gradient"]); - paint.strokeMiterLimit = parseDouble(json["stroke_miter_limit"], 4)!; - paint.strokeWidth = parseDouble(json["stroke_width"], 0)!; - paint.strokeCap = parseStrokeCap(json["stroke_cap"], StrokeCap.butt)!; - paint.strokeJoin = parseStrokeJoin(json["stroke_join"], StrokeJoin.miter)!; - paint.style = parsePaintingStyle(json["style"], PaintingStyle.fill)!; - return paint; -} +ui.Gradient? parsePaintGradient(Map? value, ThemeData? theme, + [ui.Gradient? defaultValue]) { + if (value == null) return defaultValue; -ui.Gradient? paintGradientFromJSON( - ThemeData? theme, Map? json) { - if (json == null) { - return null; - } - String type = json["type"]; + var type = value["_type"]; + var colorStops = parseGradientStops(value["color_stops"]); + var colors = parseColors(value["colors"], theme); + var tileMode = parseTileMode(value["tile_mode"], TileMode.clamp)!; if (type == "linear") { - return ui.Gradient.linear( - offsetFromJson(json["begin"])!, - offsetFromJson(json["end"])!, - parseColors(theme, json["colors"]), - parseStops(json["color_stops"]), - parseTileMode(json["tile_mode"], TileMode.clamp)!); + return ui.Gradient.linear(parseOffset(value["begin"])!, + parseOffset(value["end"])!, colors, colorStops, tileMode); } else if (type == "radial") { return ui.Gradient.radial( - offsetFromJson(json["center"])!, - parseDouble(json["radius"], 0)!, - parseColors(theme, json["colors"]), - parseStops(json["color_stops"]), - parseTileMode(json["tile_mode"], TileMode.clamp)!, + parseOffset(value["center"])!, + parseDouble(value["radius"], 0)!, + colors, + colorStops, + tileMode, null, - offsetFromJson(json["focal"]), - parseDouble(json["focal_radius"], 0)!, + parseOffset(value["focal"]), + parseDouble(value["focal_radius"], 0)!, ); } else if (type == "sweep") { - Offset center = offsetFromJson(json["center"])!; + Offset center = parseOffset(value["center"])!; return ui.Gradient.sweep( center, - parseColors(theme, json["colors"]), - parseStops(json["color_stops"]), - parseTileMode(json["tile_mode"], TileMode.clamp)!, - parseDouble(json["start_angle"], 0)!, - parseDouble(json["end_angle"], 0)!, + colors, + colorStops, + tileMode, + parseDouble(value["start_angle"], 0)!, + parseDouble(value["end_angle"], 2 * math.pi)!, parseRotationToMatrix4( - json["rotation"], Rect.fromCircle(center: center, radius: 10))); + value["rotation"], Rect.fromCircle(center: center, radius: 10))); } - return null; + return defaultValue; } -Offset? offsetFromJson(dynamic json) { - if (json == null) { - return null; - } else if (json is List && json.length > 1) { - return Offset(parseDouble(json[0], 0)!, parseDouble(json[1], 0)!); - } else { - return Offset(parseDouble(json["x"], 0)!, parseDouble(json["y"], 0)!); +extension DrawingParsers on Control { + Paint? getPaint(String propertyName, ThemeData theme, [Paint? defaultValue]) { + return parsePaint(get(propertyName), theme, defaultValue); + } + + PaintingStyle? getPaintingStyle(String propertyName, + [PaintingStyle? defaultValue]) { + return parsePaintingStyle(get(propertyName), defaultValue); + } + + List? getPaintStrokeDashPattern(String propertyName, + [List? defaultValue]) { + return parsePaintStrokeDashPattern(get(propertyName), defaultValue); } } diff --git a/packages/flet/lib/src/utils/edge_insets.dart b/packages/flet/lib/src/utils/edge_insets.dart index 0a562b0618..58b294b506 100644 --- a/packages/flet/lib/src/utils/edge_insets.dart +++ b/packages/flet/lib/src/utils/edge_insets.dart @@ -1,69 +1,102 @@ -import 'dart:convert'; - import 'package:flutter/widgets.dart'; import '../models/control.dart'; -import 'material_state.dart'; import 'numbers.dart'; +import 'widget_state.dart'; -EdgeInsets? parseEdgeInsets(Control control, String propName, - [EdgeInsets? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; +EdgeInsets? parseEdgeInsets(dynamic value, [EdgeInsets? defaultValue]) { + if (value == null) return defaultValue; + if (value is int || value is double) { + return EdgeInsets.all(parseDouble(value, 0)!); } + return EdgeInsets.fromLTRB( + parseDouble(value['left'], 0)!, + parseDouble(value['top'], 0)!, + parseDouble(value['right'], 0)!, + parseDouble(value['bottom'], 0)!); +} - final j1 = json.decode(v); - return edgeInsetsFromJson(j1, defaultValue); +EdgeInsets? parseMargin(dynamic value, [EdgeInsets? defaultValue]) { + return parseEdgeInsets(value, defaultValue); } -EdgeInsets? edgeInsetsFromJson(dynamic json, [EdgeInsets? defaultValue]) { - if (json == null) { - return defaultValue; - } else if (json is int || json is double) { - return EdgeInsets.all(parseDouble(json, 0)!); - } - return EdgeInsets.fromLTRB( - parseDouble(json['l'], 0)!, - parseDouble(json['t'], 0)!, - parseDouble(json['r'], 0)!, - parseDouble(json['b'], 0)!); +EdgeInsets? parsePadding(dynamic value, [EdgeInsets? defaultValue]) { + return parseEdgeInsets(value, defaultValue); } -EdgeInsetsDirectional? parseEdgeInsetsDirectional( - Control control, String propName, +EdgeInsetsDirectional? parseEdgeInsetsDirectional(dynamic value, [EdgeInsetsDirectional? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; + if (value == null) return defaultValue; + if (value is int || value is double) { + return EdgeInsetsDirectional.all(parseDouble(value, 0)!); } + return EdgeInsetsDirectional.fromSTEB( + parseDouble(value['left'], 0)!, + parseDouble(value['top'], 0)!, + parseDouble(value['right'], 0)!, + parseDouble(value['bottom'], 0)!); +} - final j1 = json.decode(v); - return edgeInsetsDirectionalFromJson(j1, defaultValue); +WidgetStateProperty? parseWidgetStateEdgeInsets(dynamic value, + {EdgeInsets? defaultEdgeInsets, + WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; + + return getWidgetStateProperty( + value, (jv) => parseEdgeInsets(jv), defaultEdgeInsets); } -EdgeInsetsDirectional? edgeInsetsDirectionalFromJson(dynamic json, - [EdgeInsetsDirectional? defaultValue]) { - if (json == null) { - return defaultValue; - } else if (json is int || json is double) { - return EdgeInsetsDirectional.all(parseDouble(json, 0)!); - } - return EdgeInsetsDirectional.fromSTEB( - parseDouble(json['l'], 0)!, - parseDouble(json['t'], 0)!, - parseDouble(json['r'], 0)!, - parseDouble(json['b'], 0)!); +WidgetStateProperty? parseWidgetStatePadding(dynamic value, + {EdgeInsets? defaultPadding, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateEdgeInsets(value, + defaultEdgeInsets: defaultPadding, defaultValue: defaultValue); +} + +WidgetStateProperty? parseWidgetStateMargin(dynamic value, + {EdgeInsets? defaultEdgeInsets, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateEdgeInsets(value, + defaultEdgeInsets: defaultEdgeInsets, defaultValue: defaultValue); } -WidgetStateProperty? parseWidgetStateEdgeInsets( - Control control, String propName, - [EdgeInsets? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return null; +extension EdgeInsetsParsers on Control { + EdgeInsets? getEdgeInsets(String propertyName, [EdgeInsets? defaultValue]) { + return parseEdgeInsets(get(propertyName), defaultValue); } - return getWidgetStateProperty( - jsonDecode(v), (jv) => edgeInsetsFromJson(jv), defaultValue); + EdgeInsets? getMargin(String propertyName, [EdgeInsets? defaultValue]) { + return parseMargin(get(propertyName), defaultValue); + } + + EdgeInsets? getPadding(String propertyName, [EdgeInsets? defaultValue]) { + return parsePadding(get(propertyName), defaultValue); + } + + EdgeInsetsDirectional? getEdgeInsetsDirectional(String propertyName, + [EdgeInsetsDirectional? defaultValue]) { + return parseEdgeInsetsDirectional(get(propertyName), defaultValue); + } + + WidgetStateProperty? getWidgetStateEdgeInsets( + String propertyName, + {EdgeInsets? defaultEdgeInsets, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateEdgeInsets(get(propertyName), + defaultEdgeInsets: defaultEdgeInsets, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStatePadding(String propertyName, + {EdgeInsets? defaultPadding, + WidgetStateProperty? defaultValue}) { + return parseWidgetStatePadding(get(propertyName), + defaultPadding: defaultPadding, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStateMargin(String propertyName, + {EdgeInsets? defaultEdgeInsets, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateMargin(get(propertyName), + defaultEdgeInsets: defaultEdgeInsets, defaultValue: defaultValue); + } } diff --git a/packages/flet/lib/src/utils/enums.dart b/packages/flet/lib/src/utils/enums.dart new file mode 100644 index 0000000000..3b4bc7005c --- /dev/null +++ b/packages/flet/lib/src/utils/enums.dart @@ -0,0 +1,9 @@ +import 'package:collection/collection.dart'; + +T? parseEnum(List values, String? value, [T? defaultValue]) { + if (value == null) return defaultValue; + + return values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} diff --git a/packages/flet/lib/src/utils/events.dart b/packages/flet/lib/src/utils/events.dart new file mode 100644 index 0000000000..7c845c554c --- /dev/null +++ b/packages/flet/lib/src/utils/events.dart @@ -0,0 +1,192 @@ +import 'package:flutter/gestures.dart'; + +extension ScaleEndDetailsExtension on ScaleEndDetails { + Map toMap() => { + "pc": pointerCount, + "v": { + "x": velocity.pixelsPerSecond.dx, + "y": velocity.pixelsPerSecond.dy + }, + }; +} + +extension ScaleUpdateDetailsExtension on ScaleUpdateDetails { + Map toMap() => { + "gfp": {"x": focalPoint.dx, "y": focalPoint.dy}, + "fpd": {"x": focalPointDelta.dx, "y": focalPointDelta.dy}, + "lfp": {"x": localFocalPoint.dx, "y": localFocalPoint.dy}, + "pc": pointerCount, + "hs": horizontalScale, + "vs": verticalScale, + "s": scale, + "rot": rotation, + "ts": sourceTimeStamp, + }; +} + +extension ScaleStartDetailsExtension on ScaleStartDetails { + Map toMap() => { + "gfp": {"x": focalPoint.dx, "y": focalPoint.dy}, + "lfp": {"x": localFocalPoint.dx, "y": localFocalPoint.dy}, + "pc": pointerCount, + "ts": sourceTimeStamp, + }; +} + +extension DragEndDetailsExtension on DragEndDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "v": { + "x": velocity.pixelsPerSecond.dx, + "y": velocity.pixelsPerSecond.dy + }, + "pv": primaryVelocity, + }; +} + +extension LongPressEndDetailsExtension on LongPressEndDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "v": { + "x": velocity.pixelsPerSecond.dx, + "y": velocity.pixelsPerSecond.dy + }, + }; +} + +extension LongPressStartDetailsExtension on LongPressStartDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + }; +} + +extension LongPressDownDetailsExtension on LongPressDownDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "k": kind?.name, + }; +} + +extension LongPressMoveUpdateDetailsExtension on LongPressMoveUpdateDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "ofo": { + "x": offsetFromOrigin.dx, + "y": offsetFromOrigin.dy, + }, + "lofo": { + "x": localOffsetFromOrigin.dx, + "y": localOffsetFromOrigin.dy, + }, + }; +} + +extension TapDownDetailsExtension on TapDownDetails { + Map toMap() => { + "k": kind?.name, + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + }; +} + +extension TapUpDetailsExtension on TapUpDetails { + Map toMap() => { + "k": kind.name, + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + }; +} + +extension DragStartDetailsExtension on DragStartDetails { + Map toMap() => { + "k": kind?.name, + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "ts": sourceTimeStamp, + }; +} + +extension DragUpdateDetailsExtension on DragUpdateDetails { + Map toMap( + [Offset? previousLocalPosition, Offset? previousGlobalPosition]) { + final localDelta = previousLocalPosition != null + ? localPosition - previousLocalPosition + : null; + final globalDelta = previousGlobalPosition != null + ? globalPosition - previousGlobalPosition + : null; + return { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "ld": {"x": localDelta?.dx, "y": localDelta?.dy}, + "gd": {"x": globalDelta?.dx, "y": globalDelta?.dy}, + "pd": primaryDelta, + "ts": sourceTimeStamp, + }; + } +} + +extension DragDownDetailsExtension on DragDownDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + }; +} + +extension TapMoveDetailsExtension on TapMoveDetails { + Map toMap() => { + "k": kind.name, + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "d": {"x": delta.dx, "y": delta.dy}, + }; +} + +extension PointerEventExtension on PointerEvent { + Map toMap([Offset? previousLocalPosition]) { + var localDelta = previousLocalPosition != null + ? localPosition - previousLocalPosition + : null; + return { + "k": kind.name, + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": position.dx, "y": position.dy}, + "ts": timeStamp, + "dev": device, + "ps": pressure, + "pMin": pressureMin, + "pMax": pressureMax, + "dist": distance, + "distMax": distanceMax, + "size": size, + "rMj": radiusMajor, + "rMn": radiusMinor, + "rMin": radiusMin, + "rMax": radiusMax, + "or": orientation, + "tilt": tilt, + "ld": {"x": localDelta?.dx, "y": localDelta?.dy}, + }; + } +} + +extension ForcePressDetailsExtension on ForcePressDetails { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": globalPosition.dx, "y": globalPosition.dy}, + "p": pressure, + }; +} + +extension PointerScrollEventExtension on PointerScrollEvent { + Map toMap() => { + "l": {"x": localPosition.dx, "y": localPosition.dy}, + "g": {"x": position.dx, "y": position.dy}, + "sd": {"x": scrollDelta.dx, "y": scrollDelta.dy}, + }; +} diff --git a/packages/flet/lib/src/utils/file_picker.dart b/packages/flet/lib/src/utils/file_picker.dart new file mode 100644 index 0000000000..e65e67adfd --- /dev/null +++ b/packages/flet/lib/src/utils/file_picker.dart @@ -0,0 +1,79 @@ +import 'dart:typed_data'; + +import 'package:file_picker/file_picker.dart'; +import 'enums.dart'; + +import '../models/control.dart'; + +class FilePickerResultEvent { + final String? path; + final List? files; + + FilePickerResultEvent({required this.path, required this.files}); + + Map toMap() => { + 'path': path, + 'files': files?.map((FilePickerFile f) => f.toMap()).toList() + }; +} + +class FilePickerFile { + final int id; + final String name; + final String? path; + final int size; + final Uint8List? bytes; + + FilePickerFile( + {required this.id, + required this.name, + required this.path, + required this.size, + required this.bytes}); + + Map toMap() => { + 'id': id, + 'name': name, + 'path': path, + 'size': size, + 'bytes': bytes + }; +} + +class FilePickerUploadFile { + final int? id; + final String? name; + final String uploadUrl; + final String method; + + FilePickerUploadFile( + {required this.id, + required this.name, + required this.uploadUrl, + required this.method}); +} + +class FilePickerUploadProgressEvent { + final String name; + final double? progress; + final String? error; + + FilePickerUploadProgressEvent( + {required this.name, required this.progress, required this.error}); + + Map toMap() => { + 'file_name': name, + 'progress': progress, + 'error': error + }; +} + +FileType? parseFileType(String? value, [FileType? defaultValue]) { + return parseEnum(FileType.values, value, defaultValue); +} + +extension FilePickerParsers on Control { + FileType? getFileType(String propertyName, [FileType? defaultValue]) { + return parseFileType(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/form_field.dart b/packages/flet/lib/src/utils/form_field.dart index 246a2ceedf..26aa00aa4e 100644 --- a/packages/flet/lib/src/utils/form_field.dart +++ b/packages/flet/lib/src/utils/form_field.dart @@ -1,15 +1,13 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'enums.dart'; -import '../controls/create_control.dart'; +import '../extensions/control.dart'; import '../models/control.dart'; +import '../utils/colors.dart'; import 'borders.dart'; import 'box.dart'; import 'edge_insets.dart'; -import 'icons.dart'; import 'numbers.dart'; import 'text.dart'; import 'time.dart'; @@ -17,101 +15,111 @@ import 'time.dart'; enum FormFieldInputBorder { outline, underline, none } FormFieldInputBorder? parseFormFieldInputBorder(String? value, - [FormFieldInputBorder? defValue]) { - if (value == null) { - return defValue; - } - return FormFieldInputBorder.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; + [FormFieldInputBorder? defaultValue]) { + return parseEnum(FormFieldInputBorder.values, value, defaultValue); } -TextInputType? parseTextInputType(String? value, [TextInputType? defValue]) { - switch (value?.toLowerCase()) { - case "datetime": - return TextInputType.datetime; - case "email": - return TextInputType.emailAddress; - case "multiline": - return TextInputType.multiline; - case "name": - return TextInputType.name; - case "none": - return TextInputType.none; - case "number": - return TextInputType.number; - case "phone": - return TextInputType.phone; - case "streetaddress": - return TextInputType.streetAddress; - case "text": - return TextInputType.text; - case "url": - return TextInputType.url; - case "visiblepassword": - return TextInputType.visiblePassword; - default: - return defValue; - } +TextInputType? parseTextInputType(String? value, + [TextInputType? defaultValue]) { + const typeMap = { + "datetime": TextInputType.datetime, + "email": TextInputType.emailAddress, + "multiline": TextInputType.multiline, + "name": TextInputType.name, + "none": TextInputType.none, + "number": TextInputType.number, + "phone": TextInputType.phone, + "streetaddress": TextInputType.streetAddress, + "text": TextInputType.text, + "url": TextInputType.url, + "visiblepassword": TextInputType.visiblePassword, + "websearch": TextInputType.webSearch, + "twitter": TextInputType.twitter, + }; + return typeMap[value?.toLowerCase()] ?? defaultValue; } -InputDecoration buildInputDecoration(BuildContext context, Control control, - {Control? prefix, - Control? prefixIcon, - Control? suffix, - Control? suffixIcon, - Control? icon, - Control? counter, - Control? error, - Control? helper, - Control? label, - Widget? customSuffix, - int? valueLength, - int? maxLength, - bool focused = false, - bool disabled = false, - bool? adaptive}) { +InputDecoration buildInputDecoration( + BuildContext context, + Control control, { + Widget? customSuffix, + int? valueLength, + int? maxLength, + bool focused = false, +}) { FormFieldInputBorder inputBorder = parseFormFieldInputBorder( - control.attrString("border"), + control.getString("border"), FormFieldInputBorder.outline, )!; - var iconStr = parseIcon(control.attrString("icon")); - var prefixIconData = parseIcon(control.attrString("prefixIcon")); - var prefixIconWidget = prefixIcon != null - ? createControl(control, prefixIcon.id, control.isDisabled, - parentAdaptive: adaptive) - : (prefixIconData != null ? Icon(prefixIconData) : null); - var suffixIconData = parseIcon(control.attrString("suffixIcon")); - var suffixIconWidget = suffixIcon != null - ? createControl(control, suffixIcon.id, control.isDisabled, - parentAdaptive: adaptive) - : (suffixIconData != null ? Icon(suffixIconData) : null); - var prefixText = control.attrString("prefixText"); - var suffixText = control.attrString("suffixText"); + var bgcolor = control.getColor("bgcolor", context); + var focusedBgcolor = control.getColor("focused_bgcolor", context); + var fillColor = control.getColor("fill_color", context); + var hoverColor = control.getColor("hover_color", context); + var borderColor = control.getColor("border_color", context); + var borderRadius = control.getBorderRadius("border_radius"); + var focusedBorderColor = control.getColor("focused_border_color", context); + var borderWidth = control.getDouble("border_width"); + var focusedBorderWidth = control.getDouble("focused_border_width"); - var bgcolor = control.attrColor("bgcolor", context); - var focusedBgcolor = control.attrColor("focusedBgcolor", context); - var fillColor = control.attrColor("fillColor", context); - var hoverColor = control.attrColor("hoverColor", context); - var borderColor = control.attrColor("borderColor", context); + //counter + String? counterText; + Widget? counterWidget; + var counter = control.get("counter"); + if (counter is Control) { + counterWidget = control.buildWidget("counter"); + } else { + counterText = control + .getString("counter") + ?.replaceAll("{value_length}", valueLength.toString()) + .replaceAll("{max_length}", maxLength?.toString() ?? "None") + .replaceAll("{symbols_left}", + "${maxLength == null ? 'None' : (maxLength - (valueLength ?? 0))}"); + } - var borderRadius = parseBorderRadius(control, "borderRadius"); - var focusedBorderColor = control.attrColor("focusedBorderColor", context); - var borderWidth = control.attrDouble("borderWidth"); - var focusedBorderWidth = control.attrDouble("focusedBorderWidth"); + // error + String? errorText; + Widget? errorWidget; + var error = control.get("error"); + if (error is Control) { + errorWidget = control.buildWidget("error"); + } else { + errorText = control.getString("error"); + } + // helper + String? helperText; + Widget? helperWidget; + var helper = control.get("helper"); + if (helper is Control) { + helperWidget = control.buildWidget("helper"); + } else { + helperText = control.getString("helper"); + } - var counterText = control - .attrString("counterText", "") - ?.replaceAll("{value_length}", valueLength.toString()) - .replaceAll("{max_length}", maxLength?.toString() ?? "None") - .replaceAll("{symbols_left}", - "${maxLength == null ? 'None' : (maxLength - (valueLength ?? 0))}"); + // prefix + String? prefixText; + Widget? prefixWidget; + var prefix = control.get("prefix"); + if (prefix is Control) { + prefixWidget = control.buildWidget("prefix"); + } else { + prefixText = control.getString("prefix"); + } + + // suffix + String? suffixText; + Widget? suffixWidget; + var suffix = control.get("suffix"); + if (suffix is Control) { + suffixWidget = control.buildWidget("suffix"); + } else { + suffixText = control.getString("suffix"); + } InputBorder? border; if (inputBorder == FormFieldInputBorder.underline) { border = UnderlineInputBorder( borderSide: BorderSide( - color: borderColor ?? Color(0xFF000000), + color: borderColor ?? const Color(0xFF000000), width: borderWidth ?? 1.0)); } else if (inputBorder == FormFieldInputBorder.none) { border = InputBorder.none; @@ -121,7 +129,7 @@ InputDecoration buildInputDecoration(BuildContext context, Control control, borderWidth != null) { border = OutlineInputBorder( borderSide: BorderSide( - color: borderColor ?? Color(0xFF000000), + color: borderColor ?? const Color(0xFF000000), width: borderWidth ?? 1.0)); if (borderRadius != null) { border = @@ -133,7 +141,10 @@ InputDecoration buildInputDecoration(BuildContext context, Control control, ? BorderSide.none : BorderSide( color: borderColor ?? - Theme.of(context).colorScheme.onSurface.withOpacity(0.38), + Theme.of(context) + .colorScheme + .onSurface + .withAlpha((255.0 * 0.38).round()), width: borderWidth ?? 1.0)); } } @@ -154,115 +165,93 @@ InputDecoration buildInputDecoration(BuildContext context, Control control, } return InputDecoration( - enabled: !disabled, - contentPadding: parseEdgeInsets(control, "contentPadding"), - isDense: control.attrBool("dense"), - label: label != null - ? createControl(control, label.id, control.isDisabled, - parentAdaptive: adaptive) - : control.attrString("label") != null - ? Text(control.attrString("label")!) - : null, - labelStyle: parseTextStyle(Theme.of(context), control, "labelStyle"), + enabled: !control.disabled, + contentPadding: control.getEdgeInsets("content_padding"), + isDense: control.getBool("dense"), + label: control.buildTextOrWidget("label"), + labelStyle: control.getTextStyle("label_style", Theme.of(context)), border: border, enabledBorder: border, focusedBorder: focusedBorder, hoverColor: hoverColor, - icon: icon != null - ? createControl(control, icon.id, control.isDisabled, - parentAdaptive: adaptive) - : iconStr != null - ? Icon(iconStr) - : null, - filled: control.attrBool("filled", false)!, - fillColor: fillColor ?? (focused ? focusedBgcolor ?? bgcolor : bgcolor), - hintText: control.attrString("hintText"), - hintStyle: parseTextStyle(Theme.of(context), control, "hintStyle"), - helperText: control.attrString("helperText"), - helperStyle: parseTextStyle(Theme.of(context), control, "helperStyle"), + icon: control.buildIconOrWidget("icon"), + filled: control.getBool("filled", false)!, + fillColor: fillColor ?? (focused ? (focusedBgcolor ?? bgcolor) : bgcolor), + //hint + hintText: control.getString("hint_text"), + hintStyle: control.getTextStyle("hint_style", Theme.of(context)), + hintFadeDuration: control.getDuration("hint_fade_duration"), + hintMaxLines: control.getInt("hint_max_lines"), + //helper + helper: helperWidget, + helperText: helperText, + helperStyle: control.getTextStyle("helper_style", Theme.of(context)), + helperMaxLines: control.getInt("helper_max_lines"), + //counter + counter: counterWidget, counterText: counterText, - counterStyle: parseTextStyle(Theme.of(context), control, "counterStyle"), - counter: counter != null - ? createControl(control, counter.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - error: error != null - ? createControl(control, error.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - helper: helper != null - ? createControl(control, helper.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - constraints: parseBoxConstraints(control, "sizeConstraints"), - isCollapsed: control.attrBool("collapsed"), + counterStyle: control.getTextStyle("counter_style", Theme.of(context)), + //error + error: errorWidget, + errorText: errorText, + errorStyle: control.getTextStyle("error_style", Theme.of(context)), + errorMaxLines: control.getInt("error_max_lines"), + constraints: control.getBoxConstraints("size_constraints"), + isCollapsed: control.getBool("collapsed"), prefixIconConstraints: - parseBoxConstraints(control, "prefixIconConstraints"), + control.getBoxConstraints("prefix_icon_constraints"), suffixIconConstraints: - parseBoxConstraints(control, "suffixIconConstraints"), - focusColor: control.attrColor("focusColor", context), - errorMaxLines: control.attrInt("errorMaxLines"), - alignLabelWithHint: control.attrBool("alignLabelWithHint"), - errorText: control.attrString("errorText"), - errorStyle: parseTextStyle(Theme.of(context), control, "errorStyle"), - prefixIcon: prefixIconWidget, - prefixText: - prefix == null ? prefixText : null, // ignored if prefix is set - hintFadeDuration: parseDuration(control, "hintFadeDuration"), - hintMaxLines: control.attrInt("hintMaxLines"), - helperMaxLines: control.attrInt("helperMaxLines"), - prefixStyle: parseTextStyle(Theme.of(context), control, "prefixStyle"), - prefix: prefix != null - ? createControl(control, prefix.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - suffix: suffix != null - ? createControl(control, suffix.id, control.isDisabled, - parentAdaptive: adaptive) - : null, - suffixIcon: suffixIconWidget ?? customSuffix, - suffixText: - suffix == null ? suffixText : null, // ignored if suffix is set - suffixStyle: parseTextStyle(Theme.of(context), control, "suffixStyle")); + control.getBoxConstraints("suffix_icon_constraints"), + focusColor: control.getColor("focus_color", context), + alignLabelWithHint: control.getBool("align_label_with_hint"), + prefixIcon: control.buildIconOrWidget("prefix_icon"), + //prefix + prefix: prefixWidget, + prefixText: prefixText, + prefixStyle: control.getTextStyle("prefix_style", Theme.of(context)), + suffixIcon: control.buildIconOrWidget("suffix_icon") ?? customSuffix, + //suffix + suffix: suffixWidget, + suffixText: suffixText, + suffixStyle: control.getTextStyle("suffix_style", Theme.of(context))); } -OverlayVisibilityMode? parseVisibilityMode(String? value, - [OverlayVisibilityMode? defValue]) { - switch (value?.toLowerCase()) { - case "never": - return OverlayVisibilityMode.never; - case "notediting": - return OverlayVisibilityMode.notEditing; - case "editing": - return OverlayVisibilityMode.editing; - case "always": - return OverlayVisibilityMode.always; - } - return defValue; +OverlayVisibilityMode? parseOverlayVisibilityMode(String? value, + [OverlayVisibilityMode? defaultValue]) { + return parseEnum(OverlayVisibilityMode.values, value, defaultValue); } -StrutStyle? parseStrutStyle(Control control, String propName) { - dynamic j; - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - j = json.decode(v); - return strutStyleFromJson(j); +StrutStyle? parseStrutStyle(dynamic value, [StrutStyle? defaultValue]) { + if (value == null) return defaultValue; + + return StrutStyle( + fontSize: parseDouble(value["size"]), + fontWeight: parseFontWeight(value["weight"]), + fontStyle: parseBool(value["italic"], false)! ? FontStyle.italic : null, + fontFamily: value["font_family"], + height: parseDouble(value["height"]), + leading: parseDouble(value["leading"]), + forceStrutHeight: parseBool(value["force_strut_height"]), + ); } -StrutStyle? strutStyleFromJson(Map? json) { - if (json == null) { - return null; +extension FormFieldParsers on Control { + FormFieldInputBorder? getFormFieldInputBorder(String propertyName, + [FormFieldInputBorder? defaultValue]) { + return parseFormFieldInputBorder(get(propertyName), defaultValue); } - return StrutStyle( - fontSize: parseDouble(json["size"]), - fontWeight: getFontWeight(json["weight"]), - fontStyle: parseBool(json["italic"], false)! ? FontStyle.italic : null, - fontFamily: json["font_family"], - height: parseDouble(json["height"]), - leading: parseDouble(json["leading"]), - forceStrutHeight: parseBool(json["force_strut_height"]), - ); + TextInputType? getTextInputType(String propertyName, + [TextInputType? defaultValue]) { + return parseTextInputType(get(propertyName), defaultValue); + } + + OverlayVisibilityMode? getOverlayVisibilityMode(String propertyName, + [OverlayVisibilityMode? defaultValue]) { + return parseOverlayVisibilityMode(get(propertyName), defaultValue); + } + + StrutStyle? getStrutStyle(String propertyName, [StrutStyle? defaultValue]) { + return parseStrutStyle(get(propertyName), defaultValue); + } } diff --git a/packages/flet/lib/src/utils/geometry.dart b/packages/flet/lib/src/utils/geometry.dart new file mode 100644 index 0000000000..c43959515d --- /dev/null +++ b/packages/flet/lib/src/utils/geometry.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import 'numbers.dart'; +import 'widget_state.dart'; + +Size? parseSize(dynamic value, [Size? defaultValue]) { + if (value == null) return defaultValue; + + final width = parseDouble(value['width']); + final height = parseDouble(value['height']); + + if (width == null || height == null) return defaultValue; + + return Size(width, height); +} + +WidgetStateProperty? parseWidgetStateSize(dynamic value, + {Size? defaultSize, WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; + + return getWidgetStateProperty( + value, (jv) => parseSize(jv), defaultSize); +} + +Rect? parseRect(dynamic value, [Rect? defaultValue]) { + if (value == null) return defaultValue; + + final left = parseDouble(value['left']); + final top = parseDouble(value['top']); + final right = parseDouble(value['right']); + final bottom = parseDouble(value['bottom']); + + if (left == null || top == null || right == null || bottom == null) { + return defaultValue; + } + + return Rect.fromLTRB(left, top, right, bottom); +} + +extension GeometryParsers on Control { + Size? getSize(String propertyName, [Size? defaultValue]) { + return parseSize(get(propertyName), defaultValue); + } + + WidgetStateProperty? getWidgetStateSize(String propertyName, + {Size? defaultSize, WidgetStateProperty? defaultValue}) { + return parseWidgetStateSize(get(propertyName), + defaultSize: defaultSize, defaultValue: defaultValue); + } + + Rect? getRect(String propertyName, [Rect? defaultValue]) { + return parseRect(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/gesture_detector.dart b/packages/flet/lib/src/utils/gesture_detector.dart new file mode 100644 index 0000000000..e1d4df68e7 --- /dev/null +++ b/packages/flet/lib/src/utils/gesture_detector.dart @@ -0,0 +1,54 @@ +import 'package:flutter/gestures.dart'; + +class MultiTouchGestureRecognizer extends MultiTapGestureRecognizer { + late MultiTouchGestureRecognizerCallback onMultiTap; + var numberOfTouches = 0; + int minNumberOfTouches = 0; + + MultiTouchGestureRecognizer() { + super.onTapDown = (pointer, details) => addTouch(pointer, details); + super.onTapUp = (pointer, details) => removeTouch(pointer, details); + super.onTapCancel = (pointer) => cancelTouch(pointer); + super.onTap = (pointer) => captureDefaultTap(pointer); + } + + void addTouch(int pointer, TapDownDetails details) { + //debugPrint("Add touch: $pointer"); + numberOfTouches++; + if (numberOfTouches == minNumberOfTouches) { + onMultiTap(true); + numberOfTouches = 0; + } + } + + void removeTouch(int pointer, TapUpDetails details) { + onRemoveTouch(pointer); + } + + void cancelTouch(int pointer) { + onRemoveTouch(pointer); + } + + void onRemoveTouch(int pointer) { + //debugPrint("Remove touch: $pointer"); + onMultiTap(false); + numberOfTouches = 0; + } + + void captureDefaultTap(int pointer) {} + + @override + set onTapDown(onTapDown) {} + + @override + set onTapUp(onTapUp) {} + + @override + set onTapCancel(onTapCancel) {} + + @override + set onTap(onTap) {} +} + +typedef MultiTouchGestureRecognizerCallback = void Function( + bool correctNumberOfTouches); diff --git a/packages/flet/lib/src/utils/gradient.dart b/packages/flet/lib/src/utils/gradient.dart index b148c77a34..83fd631053 100644 --- a/packages/flet/lib/src/utils/gradient.dart +++ b/packages/flet/lib/src/utils/gradient.dart @@ -1,7 +1,7 @@ -import 'dart:convert'; +import 'dart:math' as math; import 'dart:typed_data'; +import 'enums.dart'; -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; @@ -9,85 +9,69 @@ import 'alignment.dart'; import 'colors.dart'; import 'numbers.dart'; -Gradient? parseGradient(ThemeData theme, Control control, String propName) { - var v = control.attrString(propName); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return gradientFromJSON(theme, j1); -} +Gradient? parseGradient(dynamic value, ThemeData theme, + [Gradient? defaultValue]) { + if (value == null) return defaultValue; -Gradient? gradientFromJSON(ThemeData? theme, Map? json) { - if (json == null) { - return null; - } - String type = json["type"]; + var type = value["_type"]; + var colors = parseColors(value["colors"], theme); + var stops = parseGradientStops(value["stops"]); + var rotation = parseRotation(value["rotation"]); if (type == "linear") { return LinearGradient( - colors: parseColors(theme, json["colors"]), - stops: parseStops(json["stops"]), - begin: alignmentFromJson(json["begin"], Alignment.centerLeft)!, - end: alignmentFromJson(json["end"], Alignment.centerRight)!, - tileMode: parseTileMode(json["tile_mode"], TileMode.clamp)!, - transform: parseRotation(json["rotation"])); + colors: colors, + stops: stops, + begin: parseAlignment(value["begin"], Alignment.centerLeft)!, + end: parseAlignment(value["end"], Alignment.centerRight)!, + tileMode: parseTileMode(value["tile_mode"], TileMode.clamp)!, + transform: rotation); } else if (type == "radial") { return RadialGradient( - colors: parseColors(theme, json["colors"]), - stops: parseStops(json["stops"]), - center: alignmentFromJson(json["center"], Alignment.center)!, - radius: parseDouble(json["radius"], 0.5)!, - focalRadius: parseDouble(json["focal_radius"], 0)!, - focal: alignmentFromJson(json["focal"]), - tileMode: parseTileMode(json["tile_mode"], TileMode.clamp)!, - transform: parseRotation(json["rotation"])); + colors: colors, + stops: stops, + center: parseAlignment(value["center"], Alignment.center)!, + radius: parseDouble(value["radius"], 0.5)!, + focalRadius: parseDouble(value["focal_radius"], 0)!, + focal: parseAlignment(value["focal"]), + tileMode: parseTileMode(value["tile_mode"], TileMode.clamp)!, + transform: rotation); } else if (type == "sweep") { return SweepGradient( - colors: parseColors(theme, json["colors"]), - center: alignmentFromJson(json["center"], Alignment.center)!, - startAngle: parseDouble(json["start_angle"], 0)!, - endAngle: parseDouble(json["end_angle"], 0)!, - stops: parseStops(json["stops"]), - tileMode: parseTileMode(json["tile_mode"], TileMode.clamp)!, - transform: parseRotation(json["rotation"])); + colors: colors, + center: parseAlignment(value["center"], Alignment.center)!, + startAngle: parseDouble(value["start_angle"], 0)!, + endAngle: parseDouble(value["end_angle"], 2 * math.pi)!, + stops: stops, + tileMode: parseTileMode(value["tile_mode"], TileMode.clamp)!, + transform: rotation); } - return null; + return defaultValue; } -List parseColors(ThemeData? theme, dynamic jv) { - return (jv as List).map((c) => parseColor(theme, c as String)!).toList(); +List parseColors(dynamic value, ThemeData? theme) { + return (value as List).map((c) => parseColor(c as String, theme)!).toList(); } -List? parseStops(dynamic jv) { - if (jv == null) { - return null; - } - List? list = jv as List; - if (list.isEmpty) { - return null; - } - return list.map((v) => parseDouble(v)).whereNotNull().toList(); +List? parseGradientStops(dynamic value, [List? defaultValue]) { + if (value == null) return defaultValue; + List? valueAsList = value as List; + if (valueAsList.isEmpty) return defaultValue; + return valueAsList.map((v) => parseDouble(v)).nonNulls.toList(); } -TileMode? parseTileMode(dynamic jv, [TileMode? defValue]) { - return TileMode.values - .firstWhereOrNull((e) => e.name.toLowerCase() == jv.toLowerCase()) ?? - defValue; +TileMode? parseTileMode(String? value, [TileMode? defaultValue]) { + return parseEnum(TileMode.values, value, defaultValue); } -GradientRotation? parseRotation(dynamic jv, [GradientRotation? defValue]) { - if (jv == null) { - return defValue; - } - return GradientRotation(parseDouble(jv, 0)!); +GradientRotation? parseRotation(dynamic value, + [GradientRotation? defaultValue]) { + if (value == null) return defaultValue; + return GradientRotation(parseDouble(value, 0)!); } -Float64List? parseRotationToMatrix4(dynamic jv, Rect bounds) { - if (jv == null) { - return null; - } - return GradientRotation(parseDouble(jv, 0)!).transform(bounds).storage; +Float64List? parseRotationToMatrix4(dynamic value, Rect bounds) { + if (value == null) return null; + return GradientRotation(parseDouble(value, 0)!).transform(bounds).storage; } extension GradientExtension on Gradient { @@ -138,3 +122,27 @@ Color lerpGradient(List colors, List stops, double t) { } return colors.last; } + +extension GradientParsers on Control { + Gradient? getGradient(String propertyName, ThemeData theme) { + return parseGradient(get(propertyName), theme); + } + + List getColors(String propertyName, ThemeData theme) { + return parseColors(get(propertyName), theme); + } + + List? getGradientStops(String propertyName, + [List? defaultValue]) { + return parseGradientStops(get(propertyName), defaultValue); + } + + TileMode? getTileMode(String propertyName, [TileMode? defaultValue]) { + return parseTileMode(get(propertyName), defaultValue); + } + + GradientRotation? getGradientRotation(String propertyName, + [GradientRotation? defaultValue]) { + return parseRotation(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/hashing.dart b/packages/flet/lib/src/utils/hashing.dart new file mode 100644 index 0000000000..f9d5423c2a --- /dev/null +++ b/packages/flet/lib/src/utils/hashing.dart @@ -0,0 +1,13 @@ +import 'dart:typed_data'; + +int fnv1aHash(Uint8List bytes) { + const int fnvOffset = 0x811C9DC5; + const int fnvPrime = 0x01000193; + + int hash = fnvOffset; + for (final byte in bytes) { + hash ^= byte; + hash = (hash * fnvPrime) & 0xFFFFFFFF; // 32-bit overflow + } + return hash; +} diff --git a/packages/flet/lib/src/utils/icons.dart b/packages/flet/lib/src/utils/icons.dart index 2d2b82af9f..49b42c5fce 100644 --- a/packages/flet/lib/src/utils/icons.dart +++ b/packages/flet/lib/src/utils/icons.dart @@ -1,28 +1,44 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; -import 'cupertino_icons.dart'; -import 'material_icons.dart'; -import 'material_state.dart'; +import 'widget_state.dart'; + +IconData? parseIconData(int? value, FletBackend backend, + [IconData? defaultValue]) { + if (value == null) return defaultValue; -IconData? parseIcon(String? iconName, [IconData? defaultIcon]) { - if (iconName == null) { - return defaultIcon; + for (var extension in backend.extensions) { + var iconData = extension.createIconData(value); + if (iconData != null) { + return iconData; + } } - return materialIcons[iconName.toLowerCase()] ?? cupertinoIcons[iconName.toLowerCase()]; + + return defaultValue; } WidgetStateProperty? parseWidgetStateIcon( - ThemeData theme, Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } + dynamic value, + FletBackend backend, + ThemeData theme, { + Icon? defaultIcon, + WidgetStateProperty? defaultValue, +}) { + if (value == null) return defaultValue; + return getWidgetStateProperty( + value, (jv) => Icon(parseIconData(jv as int, backend)), defaultIcon); +} - final j1 = json.decode(v); +extension IconParsers on Control { + IconData? getIconData(String propertyName, [IconData? defaultValue]) { + return parseIconData(get(propertyName), backend, defaultValue); + } - return getWidgetStateProperty( - j1, (jv) => Icon(parseIcon(jv as String))); + WidgetStateProperty? getWidgetStateIcon( + String propertyName, ThemeData theme, + {Icon? defaultIcon, WidgetStateProperty? defaultValue}) { + return parseWidgetStateIcon(get(propertyName), backend, theme, + defaultIcon: defaultIcon, defaultValue: defaultValue); + } } diff --git a/packages/flet/lib/src/utils/images.dart b/packages/flet/lib/src/utils/images.dart index b4602abf34..7722ced013 100644 --- a/packages/flet/lib/src/utils/images.dart +++ b/packages/flet/lib/src/utils/images.dart @@ -1,140 +1,468 @@ import 'dart:convert'; +import 'dart:io' as io; +import 'dart:typed_data'; import 'dart:ui'; +import 'enums.dart'; -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; +import '../utils/animations.dart'; +import '../utils/strings.dart'; +import '../utils/uri.dart'; +import '../widgets/error.dart'; +import 'collections.dart'; import 'colors.dart'; import 'gradient.dart'; +import 'images.dart'; import 'numbers.dart'; -export 'images_io.dart' if (dart.library.js) "images_web.dart"; +export "images_web.dart" if (dart.library.io) 'images_io.dart'; -ImageRepeat? parseImageRepeat(String? repeat, [ImageRepeat? defValue]) { - if (repeat == null) { - return defValue; - } - return ImageRepeat.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == repeat.toLowerCase()) ?? - defValue; +ImageRepeat? parseImageRepeat(String? value, [ImageRepeat? defaultValue]) { + return parseEnum(ImageRepeat.values, value, defaultValue); } -BlendMode? parseBlendMode(String? mode, [BlendMode? defValue]) { - if (mode == null) { - return defValue; - } - return BlendMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == mode.toLowerCase()) ?? - defValue; +BlendMode? parseBlendMode(String? value, [BlendMode? defaultValue]) { + return parseEnum(BlendMode.values, value, defaultValue); } -BoxFit? parseBoxFit(String? fit, [BoxFit? defValue]) { - if (fit == null) { - return defValue; - } - return BoxFit.values - .firstWhereOrNull((e) => e.name.toLowerCase() == fit.toLowerCase()) ?? - defValue; +BoxFit? parseBoxFit(String? value, [BoxFit? defaultValue]) { + return parseEnum(BoxFit.values, value, defaultValue); } -ImageFilter? parseBlur(Control control, String propName, - [ImageFilter? defValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defValue; - } - - final j1 = json.decode(v); - return blurImageFilterFromJSON(j1); -} - -ImageFilter? blurImageFilterFromJSON(dynamic json) { - if (json == null) return null; +ImageFilter? parseBlur(dynamic value, [ImageFilter? defaultValue]) { + if (value == null) return defaultValue; double sigmaX = 0.0, sigmaY = 0.0; TileMode? tileMode; - - if (json is num) { - sigmaX = sigmaY = parseDouble(json, 0)!; - } else if (json is List) { - sigmaX = parseDouble(json.isNotEmpty ? json[0] : 0, 0)!; - sigmaY = parseDouble(json.length > 1 ? json[1] : json[0], 0)!; - } else if (json is Map) { - sigmaX = parseDouble(json["sigma_x"], 0)!; - sigmaY = parseDouble(json["sigma_y"], 0)!; - tileMode = parseTileMode(json["tile_mode"]); + if (value is num) { + sigmaX = sigmaY = parseDouble(value, 0)!; + } else if (value is List) { + sigmaX = parseDouble(value.isNotEmpty ? value[0] : 0, 0)!; + sigmaY = parseDouble(value.length > 1 ? value[1] : value[0], 0)!; + } else if (value is Map) { + sigmaX = parseDouble(value["sigma_x"], 0)!; + sigmaY = parseDouble(value["sigma_y"], 0)!; + tileMode = parseTileMode(value["tile_mode"]); } return ImageFilter.blur(sigmaX: sigmaX, sigmaY: sigmaY, tileMode: tileMode); } -ColorFilter? parseColorFilter(Control control, String propName, ThemeData theme, - [ColorFilter? defValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defValue; - } +ColorFilter? parseColorFilter(dynamic value, ThemeData theme, + [ColorFilter? defaultValue]) { + if (value == null) return defaultValue; + Color? color = parseColor(value["color"], theme); + BlendMode? blendMode = parseBlendMode(value["blend_mode"]); + if (color == null || blendMode == null) return defaultValue; + return ColorFilter.mode(color, blendMode); +} - final j1 = json.decode(v); - return colorFilterFromJSON(j1, theme); +FilterQuality? parseFilterQuality(String? value, + [FilterQuality? defaultValue]) { + return parseEnum(FilterQuality.values, value, defaultValue); } -ColorFilter? colorFilterFromJSON(dynamic json, ThemeData theme, - [ColorFilter? defValue]) { - if (json == null) { - return defValue; +/// Returns a Flutter [ImageProvider] +/// for anything supported by [ResolvedAssetSource]. +ImageProvider? parseImageProvider(dynamic src, BuildContext context) { + final resolvedSrc = + src is ResolvedAssetSource ? src : ResolvedAssetSource.from(src); + + if (resolvedSrc.error != null) { + debugPrint("getImageProvider failed decoding src: ${resolvedSrc.error}"); + return null; } - Color? color = parseColor(theme, json["color"]); - BlendMode? blendMode = parseBlendMode(json["blend_mode"]); - if (color == null || blendMode == null) { - return defValue; + + // bytes + if (resolvedSrc.hasBytes) { + try { + return MemoryImage(resolvedSrc.bytes!); + } catch (ex) { + debugPrint("getImageProvider failed decoding bytes"); + return null; + } } - return ColorFilter.mode(color, blendMode); -} -FilterQuality? parseFilterQuality(String? quality, [FilterQuality? defValue]) { - if (quality == null) { - return defValue; + // URL or asset path + if (resolvedSrc.hasUri) { + var assetSrc = FletBackend.of(context).getAssetSource(resolvedSrc.uri!); + return assetSrc.isFile + ? getFileImageProvider(assetSrc.path) + : NetworkImage(assetSrc.path); } - return FilterQuality.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == quality.toLowerCase()) ?? - defValue; + + return null; } -bool isBase64ImageString(String s) { - // Check for base64 prefix - final base64PrefixPattern = RegExp(r'^data:image\/[a-zA-Z]+;base64,'); - if (base64PrefixPattern.hasMatch(s)) { - return true; +/// Builds the correct image widget ([Image] or [SvgPicture]) +/// for any supported `src`. +Widget buildImage({ + required BuildContext context, + required Widget? errorCtrl, + required dynamic src, + double? width, + double? height, + ImageRepeat repeat = ImageRepeat.noRepeat, + BoxFit? fit, + BlendMode? colorBlendMode, + Color? color, + String? semanticsLabel, + bool? gaplessPlayback, + int? cacheWidth, + int? cacheHeight, + bool antiAlias = false, + bool excludeFromSemantics = false, + FilterQuality filterQuality = FilterQuality.low, + bool disabled = false, + ImageFadeConfig? fadeConfig, +}) { + const String svgTag = " xmlns=\"http://www.w3.org/2000/svg\""; + + final resolvedSrc = ResolvedAssetSource.from(src); + if (resolvedSrc.error != null) { + return errorCtrl ?? + ErrorControl("Error decoding src", description: resolvedSrc.error); } - // Check if string contains only valid base64 characters and has a valid length (multiple of 4) - final base64CharPattern = RegExp(r'^[A-Za-z0-9+/=]+$'); - if (base64CharPattern.hasMatch(s) && s.length % 4 == 0) { + if (resolvedSrc.hasBytes) { + Uint8List bytes = resolvedSrc.bytes!; try { - base64.decode(s); - return true; - } catch (e) { - return false; + // SVG bytes + if (arrayIndexOf(bytes, Uint8List.fromList(utf8.encode(svgTag))) != -1) { + return SvgPicture.memory( + bytes, + width: width, + height: height, + excludeFromSemantics: excludeFromSemantics, + fit: fit ?? BoxFit.contain, + colorFilter: color != null + ? ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn) + : null, + semanticsLabel: semanticsLabel, + ); + } else { + // other image bytes + return Image.memory( + bytes, + width: width, + height: height, + repeat: repeat, + fit: fit, + color: color, + cacheHeight: cacheHeight, + cacheWidth: cacheWidth, + filterQuality: filterQuality, + isAntiAlias: antiAlias, + colorBlendMode: colorBlendMode, + gaplessPlayback: gaplessPlayback ?? false, + excludeFromSemantics: excludeFromSemantics, + semanticLabel: semanticsLabel, + frameBuilder: (BuildContext context, Widget child, int? frame, + bool wasSyncLoaded) => + fadeConfig != null && fadeConfig.enabled + ? fadeConfig.wrapFrame(child, frame, wasSyncLoaded, + width: width, height: height) + : child, + ); + } + } catch (ex) { + return ErrorControl("Error decoding base64: ${ex.toString()}"); + } + } else if (resolvedSrc.hasUri) { + var stringSrc = resolvedSrc.uri!; + if (stringSrc.contains(svgTag)) { + return SvgPicture.memory( + Uint8List.fromList(utf8.encode(stringSrc)), + width: width, + height: height, + fit: fit ?? BoxFit.contain, + excludeFromSemantics: excludeFromSemantics, + colorFilter: color != null + ? ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn) + : null, + semanticsLabel: semanticsLabel, + errorBuilder: errorCtrl != null + ? (context, error, stackTrace) => errorCtrl + : null, + ); + } else { + var assetSrc = FletBackend.of(context).getAssetSource(stringSrc); + if (assetSrc.isFile) { + // SVG File + if (assetSrc.path.endsWith(".svg")) { + return getSvgPictureFromFile( + src: assetSrc.path, + width: width, + height: height, + fit: fit ?? BoxFit.contain, + color: color, + blendMode: colorBlendMode ?? BlendMode.srcIn, + semanticsLabel: semanticsLabel); + } else { + // other image File + return Image.file( + io.File(assetSrc.path), + width: width, + height: height, + repeat: repeat, + filterQuality: filterQuality, + excludeFromSemantics: excludeFromSemantics, + fit: fit, + color: color, + isAntiAlias: antiAlias, + cacheHeight: cacheHeight, + cacheWidth: cacheWidth, + gaplessPlayback: gaplessPlayback ?? false, + colorBlendMode: colorBlendMode, + semanticLabel: semanticsLabel, + frameBuilder: (BuildContext context, Widget child, int? frame, + bool wasSyncLoaded) => + fadeConfig != null && fadeConfig.enabled + ? fadeConfig.wrapFrame(child, frame, wasSyncLoaded, + width: width, height: height) + : child, + errorBuilder: errorCtrl != null + ? (context, error, stackTrace) => errorCtrl + : null, + ); + } + } else { + // SVG URL + if (assetSrc.path.endsWith(".svg")) { + return SvgPicture.network( + assetSrc.path, + width: width, + height: height, + excludeFromSemantics: excludeFromSemantics, + fit: fit ?? BoxFit.contain, + colorFilter: color != null + ? ColorFilter.mode(color, colorBlendMode ?? BlendMode.srcIn) + : null, + semanticsLabel: semanticsLabel, + errorBuilder: errorCtrl != null + ? (context, error, stackTrace) => errorCtrl + : null, + ); + } else { + // other image URL + return Image.network( + assetSrc.path, + width: width, + height: height, + repeat: repeat, + filterQuality: filterQuality, + cacheHeight: cacheHeight, + cacheWidth: cacheWidth, + isAntiAlias: antiAlias, + excludeFromSemantics: excludeFromSemantics, + fit: fit, + color: color, + gaplessPlayback: gaplessPlayback ?? false, + colorBlendMode: colorBlendMode, + semanticLabel: semanticsLabel, + frameBuilder: (BuildContext context, Widget child, int? frame, + bool wasSyncLoaded) => + fadeConfig != null && fadeConfig.enabled + ? fadeConfig.wrapFrame(child, frame, wasSyncLoaded, + width: width, height: height) + : child, + errorBuilder: errorCtrl != null + ? (context, error, stackTrace) => errorCtrl + : null, + ); + } + } } } - return false; + return const ErrorControl("A valid src value must be specified."); } -bool isUrlOrPath(String s) { - // Check for URL pattern - final urlPattern = RegExp(r'^(http:\/\/|https:\/\/|www\.)'); - if (urlPattern.hasMatch(s)) { - return true; +class ImageFadeConfig { + const ImageFadeConfig( + {this.placeholder, + this.fadeInAnimation, + this.placeholderFadeOutAnimation}); + + final Widget? placeholder; + final ImplicitAnimationDetails? fadeInAnimation; + final ImplicitAnimationDetails? placeholderFadeOutAnimation; + + /// Returns true if any fade-related option is set. + bool get enabled => + placeholder != null || + fadeInAnimation != null || + placeholderFadeOutAnimation != null; + + /// Wraps an [Image] frame with a placeholder-to-image fade transition. + /// + /// - Shows [placeholder] (or a transparent placeholder that preserves layout) + /// until the first frame is available. + /// - Fades the loaded image in using [fadeInDuration]/[fadeInCurve]. + /// - Fades the placeholder out using [fadeOutDuration]/[fadeOutCurve]. + Widget wrapFrame(Widget image, int? frame, bool wasSyncLoaded, + {double? width, double? height}) { + if (!enabled) { + return image; + } + + final isLoaded = frame != null || wasSyncLoaded; + final effectiveFadeInCurve = fadeInAnimation?.curve ?? Curves.easeInOut; + final effectiveFadeInDuration = + fadeInAnimation?.duration ?? const Duration(milliseconds: 250); + final effectiveFadeOutCurve = + placeholderFadeOutAnimation?.curve ?? Curves.easeOut; + final effectiveFadeOutDuration = placeholderFadeOutAnimation?.duration ?? + const Duration(milliseconds: 150); + final placeholderWidget = placeholder != null + ? SizedBox(width: width, height: height, child: placeholder) + // invisible version to preserve layout + : SizedBox( + width: width, + height: height, + child: Opacity(opacity: 0, child: image)); + + return AnimatedSwitcher( + duration: isLoaded ? effectiveFadeInDuration : effectiveFadeOutDuration, + switchInCurve: effectiveFadeInCurve, + switchOutCurve: effectiveFadeOutCurve, + layoutBuilder: (Widget? current, List previousChildren) => + Stack( + alignment: Alignment.center, + children: [ + ...previousChildren, + if (current != null) current, + ], + ), + child: isLoaded + ? KeyedSubtree(key: const ValueKey("image-loaded"), child: image) + : KeyedSubtree( + key: const ValueKey("image-placeholder"), + child: placeholderWidget)); } +} + +class ResolvedAssetSource { + const ResolvedAssetSource({this.bytes, this.uri, this.error}); + + /// Raw bytes (ex: base64-decoded payload). + final Uint8List? bytes; + + /// String representation (ex: URL, asset path). + final String? uri; + + /// Optional error message describing a resolution failure. + final String? error; + + /// True if the instance contains non-empty bytes. + bool get hasBytes => bytes != null && bytes!.isNotEmpty; + + /// True if the instance contains a non-empty string value. + bool get hasUri => uri != null && uri!.isNotEmpty; - // Check for common file path characters + /// True if both bytes and string are missing or empty. + bool get isEmpty => !hasBytes && !hasUri; + + /// Factory that normalizes any supported image source into + /// a [ResolvedAssetSource]. + /// + /// Supports: + /// - `Uint8List`, `List` → interpreted as raw bytes + /// - `String` → URL, asset path, or Base64-encoded data + factory ResolvedAssetSource.from(dynamic src) { + // bytes + final listBytes = convertToUint8List(src); + if (listBytes != null) { + return listBytes.isEmpty + ? const ResolvedAssetSource() + : ResolvedAssetSource(bytes: listBytes); + } + + // string sources + if (src is String) { + src = src.trim(); + + // empty string + if (src.isEmpty) return const ResolvedAssetSource(); + + // URL + if (isUrl(src)) return ResolvedAssetSource(uri: src); + + // asset path + if (src.contains(".")) return ResolvedAssetSource(uri: src); + + // Base64 + try { + final srcAsBytes = base64.decode(src.stripBase64DataHeader()); + return ResolvedAssetSource(bytes: srcAsBytes); + } catch (_) {} + + // asset path + return ResolvedAssetSource(uri: src); + } + + // unknown or unsupported source type + return ResolvedAssetSource( + error: "${src.runtimeType} is not a supported source type."); + } +} + +/// Converts various list-like inputs into a Uint8List, +/// or returns null if unsupported. +Uint8List? convertToUint8List(dynamic value) { + if (value is Uint8List) { + return value; + } else if (value is List) { + return Uint8List.fromList(value); + } else if (value is List && value.every((e) => e is int)) { + return Uint8List.fromList(value.cast()); + } + + return null; +} + +bool isFilePath(String value) { final filePathPattern = RegExp(r'^[a-zA-Z0-9_\-/\\\.]+$'); - if (filePathPattern.hasMatch(s)) { - return true; + return filePathPattern.hasMatch(value); +} + +extension ImageParsers on Control { + ImageRepeat? getImageRepeat(String propertyName, + [ImageRepeat? defaultValue]) { + return parseImageRepeat(get(propertyName), defaultValue); + } + + BlendMode? getBlendMode(String propertyName, [BlendMode? defaultValue]) { + return parseBlendMode(get(propertyName), defaultValue); + } + + BoxFit? getBoxFit(String propertyName, [BoxFit? defaultValue]) { + return parseBoxFit(get(propertyName), defaultValue); + } + + ImageFilter? getBlur(String propertyName, [ImageFilter? defaultValue]) { + return parseBlur(get(propertyName), defaultValue); + } + + ColorFilter? getColorFilter(String propertyName, ThemeData theme, + [ColorFilter? defaultValue]) { + return parseColorFilter(get(propertyName), theme, defaultValue); + } + + FilterQuality? getFilterQuality(String propertyName, + [FilterQuality? defaultValue]) { + return parseFilterQuality(get(propertyName), defaultValue); + } + + ResolvedAssetSource getSrc(String propertyName) { + return ResolvedAssetSource.from(get(propertyName)); } - return false; + ImageProvider? getImageProvider(String propertyName, BuildContext context) { + return parseImageProvider(get(propertyName), context); + } } diff --git a/packages/flet/lib/src/utils/images_io.dart b/packages/flet/lib/src/utils/images_io.dart index 2aa2e14844..7b0ad1e4a2 100644 --- a/packages/flet/lib/src/utils/images_io.dart +++ b/packages/flet/lib/src/utils/images_io.dart @@ -4,9 +4,35 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:path/path.dart' as p; -import '../models/asset_src.dart'; +import '../models/asset_source.dart'; +import 'lru_cache.dart'; import 'uri.dart'; +String _fileKey(String path) { + // absolute + normalized; case-insensitive on Windows + final abs = io.File(path).absolute.path; + final norm = p.normalize(abs); + return io.Platform.isWindows ? norm.toLowerCase() : norm; +} + +class _FileLru { + _FileLru({this.capacity = 512}) + : _cache = LruCache(capacity); + final int capacity; + final LruCache _cache; + + io.File get(String path) { + final key = _fileKey(path); + final cached = _cache.get(key); + if (cached != null) return cached; + final f = io.File(key); // already absolute/normalized + _cache.set(key, f); + return f; + } +} + +final _fileLru = _FileLru(capacity: 1024); + SvgPicture getSvgPictureFromFile( {required String src, required double? width, @@ -15,7 +41,8 @@ SvgPicture getSvgPictureFromFile( required Color? color, required BlendMode blendMode, required String? semanticsLabel}) { - return SvgPicture.file(io.File(src), + final file = _fileLru.get(src); + return SvgPicture.file(file, width: width, height: height, fit: fit, @@ -23,21 +50,26 @@ SvgPicture getSvgPictureFromFile( semanticsLabel: semanticsLabel); } -AssetSrc getAssetSrc(String src, Uri pageUri, String assetsDir) { - if (src.startsWith("http://") || src.startsWith("https://")) { - return AssetSrc(path: src, isFile: false); - } else if (io.File(src).existsSync()) { - return AssetSrc(path: src, isFile: true); +AssetSource getAssetSrc(String src, Uri pageUri, String assetsDir) { + // Pass through any value that already carries a URL scheme (http, https, + // data, blob, rtsp, rtmp, srt, udp, ...). Single-letter schemes are + // ignored so Windows-style "C:\..." paths fall into the file branch. + final parsed = Uri.tryParse(src); + if (parsed != null && parsed.scheme.length > 1) { + return AssetSource(path: src, isFile: false); + } + if (io.File(src).existsSync()) { + return AssetSource(path: src, isFile: true); } else if (assetsDir != "") { var filePath = normalizePath(src); if (filePath.startsWith(p.separator)) { filePath = filePath.substring(1); } - return AssetSrc( + return AssetSource( path: p.join(normalizePath(assetsDir), filePath), isFile: true); } else { var uri = Uri.parse(src); - return AssetSrc( + return AssetSource( path: uri.hasAuthority ? src : getAssetUri(pageUri, src).toString(), isFile: false); } diff --git a/packages/flet/lib/src/utils/images_web.dart b/packages/flet/lib/src/utils/images_web.dart index 16705fbe1a..cfb6dedb12 100644 --- a/packages/flet/lib/src/utils/images_web.dart +++ b/packages/flet/lib/src/utils/images_web.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; -import '../models/asset_src.dart'; +import '../models/asset_source.dart'; SvgPicture getSvgPictureFromFile( {required String src, @@ -14,9 +14,20 @@ SvgPicture getSvgPictureFromFile( return SvgPicture.string(""); } -AssetSrc getAssetSrc(String src, Uri pageUri, String assetsDir) { - return AssetSrc( - path: src.startsWith("/") ? src.substring(1) : src, isFile: false); +AssetSource getAssetSrc(String src, Uri pageUri, String assetsDir) { + // Pass through any value that already carries a URL scheme (http, https, + // data, blob, file, rtsp, rtmp, srt, udp, ...). Single-letter schemes are + // ignored so Windows-style "C:\..." paths fall into the relative branch. + final parsed = Uri.tryParse(src); + if (parsed != null && parsed.scheme.length > 1) { + return AssetSource(path: src, isFile: false); + } + if (assetsDir.isNotEmpty) { + final cleaned = src.startsWith("/") ? src.substring(1) : src; + final base = assetsDir.endsWith("/") ? assetsDir : "$assetsDir/"; + return AssetSource(path: "$base$cleaned", isFile: false); + } + return AssetSource(path: src, isFile: false); } ImageProvider getFileImageProvider(String path) { diff --git a/packages/flet/lib/src/utils/keys.dart b/packages/flet/lib/src/utils/keys.dart new file mode 100644 index 0000000000..703cdcbac3 --- /dev/null +++ b/packages/flet/lib/src/utils/keys.dart @@ -0,0 +1,53 @@ +import '../models/control.dart'; + +abstract class ControlKey { + final Object value; + + const ControlKey(this.value) + : assert( + value is int || value is String || value is bool || value is double, + 'Key value value must be int, String, bool, or double'); + + @override + bool operator ==(Object other) => + identical(this, other) || + other.runtimeType == runtimeType && + other is ControlKey && + other.value == value; + + @override + int get hashCode => value.hashCode; + + @override + String toString() => value.toString(); +} + +class ControlScrollKey extends ControlKey { + const ControlScrollKey(super.value); +} + +class ControlValueKey extends ControlKey { + const ControlValueKey(super.value); +} + +ControlKey? parseKey(dynamic value) { + if (value == null) return null; + + if (value is Map) { + var type = value["_type"]; + if (type == "value") { + return ControlValueKey(value["value"]); + } else if (type == "scroll") { + return ControlScrollKey(value["value"]); + } + throw Exception("Unknown key type: $type"); + } else { + return ControlValueKey(value); + } +} + +extension KeysParsers on Control { + ControlKey? getKey(String propertyName) { + return parseKey(get(propertyName)); + } +} diff --git a/packages/flet/lib/src/utils/launch_url.dart b/packages/flet/lib/src/utils/launch_url.dart index 8ac11e5af9..01f2614cfb 100644 --- a/packages/flet/lib/src/utils/launch_url.dart +++ b/packages/flet/lib/src/utils/launch_url.dart @@ -1,24 +1,75 @@ import 'package:url_launcher/url_launcher.dart'; -import 'platform_utils_non_web.dart' - if (dart.library.js) "platform_utils_web.dart"; - -Future openWebBrowser(String url, - {String? webWindowName, - bool? webPopupWindow, - int? windowWidth, - int? windowHeight}) async { - if (webPopupWindow == true) { - openPopupBrowserWindow( - url, webWindowName ?? "Flet", windowWidth ?? 1200, windowHeight ?? 800); +import '../models/control.dart'; +import 'platform_utils_web.dart' + if (dart.library.io) "platform_utils_non_web.dart"; + +/// A simple class representing a URL and an optional target. +/// +/// The [url] is the full string representation of the link. +/// The [target] specifies how the link should be opened (e.g., "_blank" for a new tab). +class Url { + /// The full URL to be opened. + final String url; + + /// The optional target for opening the URL (e.g., "_blank", "_self"). + final String? target; + + /// Creates a [Url] object with a required [url] and an optional [target]. + Url(this.url, [this.target]); +} + +/// Opens a web browser or popup window to a given [Url]. +/// +/// Example usage: +/// ```dart +/// final url = Url("https://example.com", "_blank"); +/// await openWebBrowser(url); +/// ``` +Future openWebBrowser( + Url urlObj, { + LaunchMode mode = LaunchMode.platformDefault, + WebViewConfiguration? webViewConfiguration, + BrowserConfiguration? browserConfiguration, + String? webOnlyWindowName, +}) async { + // Open the URL in the default browser or app + var target = urlObj.target ?? webOnlyWindowName; + var resolvedMode = (target == "_blank" && mode == LaunchMode.platformDefault) + ? LaunchMode.externalApplication + : mode; + await launchUrl( + Uri.parse(urlObj.url), + mode: resolvedMode, + webViewConfiguration: webViewConfiguration ?? const WebViewConfiguration(), + browserConfiguration: + browserConfiguration ?? const BrowserConfiguration(), + webOnlyWindowName: target, + ); +} + +Future openWindow( + Url urlObj, { + String? title, + double? width, + double? height, +}) async { + openPopupBrowserWindow(urlObj.url, title ?? "Flet", (width ?? 1200).round(), + (height ?? 800).round()); +} + +Url? parseUrl(dynamic value, [Url? defaultValue]) { + if (value is String) { + return Url(value); + } else if (value is Map) { + return Url(value["url"], value["target"]); } else { - LaunchMode? mode; - if (webWindowName == "_blank") { - mode = LaunchMode.externalApplication; - } - - await launchUrl(Uri.parse(url), - webOnlyWindowName: webWindowName, - mode: mode ?? LaunchMode.platformDefault); + return defaultValue; + } +} + +extension UrlParsers on Control { + Url? getUrl(String propertyName, [Url? defaultValue]) { + return parseUrl(get(propertyName), defaultValue); } } diff --git a/packages/flet/lib/src/utils/layout.dart b/packages/flet/lib/src/utils/layout.dart new file mode 100644 index 0000000000..b911453fef --- /dev/null +++ b/packages/flet/lib/src/utils/layout.dart @@ -0,0 +1,16 @@ +import '../models/control.dart'; +import 'numbers.dart'; + +int? parseExpand(dynamic value, [int? defaultValue]) { + return value == true + ? 1 + : value == false + ? 0 + : parseInt(value) ?? defaultValue; +} + +extension LayoutParsers on Control { + int? getExpand(String propertyName, [int? defaultValue]) { + return parseExpand(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/locale.dart b/packages/flet/lib/src/utils/locale.dart index 7d02acac2a..b1260ca332 100644 --- a/packages/flet/lib/src/utils/locale.dart +++ b/packages/flet/lib/src/utils/locale.dart @@ -1,49 +1,83 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import '../models/control.dart'; -Map? parseLocaleConfiguration( - Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } +class LocaleConfiguration { + final List supportedLocales; + final Locale? locale; - final j1 = json.decode(v); - return localeConfigurationFromJSON(j1); + const LocaleConfiguration( + {required this.supportedLocales, required this.locale}); } -Map localeConfigurationFromJSON(dynamic json) { - List? supportedLocales; - var sl = json["supported_locales"]; - Locale? locale = json["current_locale"] != null - ? localeFromJSON(json["current_locale"]) - : null; - if (sl != null) { - supportedLocales = - sl.map((e) => localeFromJSON(e)).whereType().toList(); +LocaleConfiguration parseLocaleConfiguration(dynamic value) { + List supportedLocales = []; + Locale? locale; + + if (value != null) { + var sl = value["supported_locales"]; + if (sl != null) { + supportedLocales = sl + .map((e) { + final l = parseLocale(e); + return l?.isSupportedByDelegates() == true ? l : null; + }) + .whereType() + .toList(); + } + locale = parseLocale(value["current_locale"]); } - return { - "supportedLocales": supportedLocales != null && supportedLocales.isNotEmpty + return LocaleConfiguration( + supportedLocales: supportedLocales.isNotEmpty ? supportedLocales - : [const Locale("en", "US")], // American locale as fallback - "locale": locale - }; + : [const Locale("en", "US")], + locale: locale, + ); } -Locale localeFromJSON(dynamic json) { - var languageCode = json["language_code"]?.trim(); - var countryCode = json["country_code"]?.trim(); - var scriptCode = json["script_code"]?.trim(); +Locale? parseLocale(dynamic value, [Locale? defaultValue]) { + if (value == null) return defaultValue; + var languageCode = value["language_code"]?.trim(); + var countryCode = value["country_code"]?.trim(); + var scriptCode = value["script_code"]?.trim(); return Locale.fromSubtags( languageCode: (languageCode != null && languageCode.isNotEmpty) ? languageCode - : "und", // und = undefined language code + : "und", // undefined language code countryCode: (countryCode != null && countryCode.isNotEmpty) ? countryCode : null, scriptCode: (scriptCode != null && scriptCode.isNotEmpty) ? scriptCode : null); } + +extension LocaleParsers on Control { + LocaleConfiguration getLocaleConfiguration(String propertyName, + [LocaleConfiguration? defaultValue]) { + return parseLocaleConfiguration(get(propertyName)); + } + + Locale? getLocale(String propertyName, [Locale? defaultValue]) { + return parseLocale(get(propertyName), defaultValue); + } +} + +extension LocaleExtention on Locale { + bool isSupportedByDelegates( + [List> delegates = const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate + ]]) { + return delegates.every((d) => d.isSupported(this)); + } + + Map toMap() { + return { + "language_code": languageCode, + "country_code": countryCode, + "script_code": scriptCode, + }; + } +} diff --git a/packages/flet/lib/src/utils/lock.dart b/packages/flet/lib/src/utils/lock.dart new file mode 100644 index 0000000000..736223217a --- /dev/null +++ b/packages/flet/lib/src/utils/lock.dart @@ -0,0 +1,22 @@ +import 'dart:async'; + +class Lock { + Completer? _completer; + + /// Lock is considered acquired if completer is not null. + bool get isLocked => _completer != null; + + /// Acquires the lock. Waits if already locked. + Future acquire() async { + while (_completer != null) { + await _completer!.future; // Wait for the current lock to release + } + _completer = Completer(); + } + + /// Releases the lock. + void release() { + _completer?.complete(); + _completer = null; + } +} diff --git a/packages/flet/lib/src/utils/lru_cache.dart b/packages/flet/lib/src/utils/lru_cache.dart new file mode 100644 index 0000000000..2709e31867 --- /dev/null +++ b/packages/flet/lib/src/utils/lru_cache.dart @@ -0,0 +1,20 @@ +class LruCache { + LruCache(this.capacity) : assert(capacity > 0); + final int capacity; + final _map = {}; + + V? get(K key) { + final val = _map.remove(key); + if (val != null) _map[key] = val; // mark MRU + return val; + } + + void set(K key, V value) { + if (_map.containsKey(key)) { + _map.remove(key); + } else if (_map.length >= capacity) { + _map.remove(_map.keys.first); // evict LRU + } + _map[key] = value; + } +} diff --git a/packages/flet/lib/src/utils/markdown.dart b/packages/flet/lib/src/utils/markdown.dart index bec42e62a1..91e04c0599 100644 --- a/packages/flet/lib/src/utils/markdown.dart +++ b/packages/flet/lib/src/utils/markdown.dart @@ -1,12 +1,9 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter_highlight/theme_map.dart'; -import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:flutter_markdown_plus/flutter_markdown_plus.dart'; import 'package:markdown/markdown.dart' as md; import '../models/control.dart'; -import '../models/page_args_model.dart'; import 'alignment.dart'; import 'box.dart'; import 'edge_insets.dart'; @@ -14,10 +11,8 @@ import 'numbers.dart'; import 'text.dart'; md.ExtensionSet? parseMarkdownExtensionSet(String? value, - [md.ExtensionSet? defValue]) { - if (value == null) { - return defValue; - } + [md.ExtensionSet? defaultValue]) { + if (value == null) return defaultValue; switch (value.toLowerCase()) { case "commonmark": return md.ExtensionSet.commonMark; @@ -26,23 +21,14 @@ md.ExtensionSet? parseMarkdownExtensionSet(String? value, case "githubflavored": return md.ExtensionSet.gitHubFlavored; default: - return defValue; + return defaultValue; } } -Map parseMarkdownCodeTheme( - Control control, - String propName, - ThemeData theme, -) { - final v = control.attrString(propName); - if (v == null) { - return {}; - } - dynamic j = json.decode(v); - if (j is String) { - return themeMap[j.toLowerCase()] ?? {}; - } else if (j is Map) { +Map parseMarkdownCodeTheme(dynamic value, ThemeData theme) { + if (value == null) return {}; + if (value is String) return themeMap[value.toLowerCase()] ?? {}; + if (value is Map) { String transformKey(String key) { switch (key) { case 'class_name': @@ -55,7 +41,7 @@ Map parseMarkdownCodeTheme( } final resultMap = - j.map((key, value) => MapEntry(key, textStyleFromJson(theme, value))); + value.map((key, value) => MapEntry(key, parseTextStyle(value, theme))); resultMap.removeWhere( (key, value) => value == null); // remove entries with null values return resultMap.map((key, value) => MapEntry(transformKey(key), value!)); @@ -63,116 +49,122 @@ Map parseMarkdownCodeTheme( return {}; } -MarkdownStyleSheet? parseMarkdownStyleSheet(Control control, String propName, - ThemeData theme, PageArgsModel? pageArgs) { - var v = control.attrString(propName); - if (v == null) { - return null; - } - dynamic j = json.decode(v); - return markdownStyleSheetFromJson(theme, j, pageArgs); -} - -MarkdownStyleSheet markdownStyleSheetFromJson( - ThemeData theme, Map j, PageArgsModel? pageArgs) { - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } - +MarkdownStyleSheet? parseMarkdownStyleSheet(dynamic value, BuildContext context, + [MarkdownStyleSheet? defaultValue]) { + if (value == null) return null; + var theme = Theme.of(context); return MarkdownStyleSheet.fromTheme(theme).copyWith( - a: parseTextStyle("a_text_style") ?? const TextStyle(color: Colors.blue), - p: parseTextStyle("p_text_style") ?? theme.textTheme.bodyMedium, - pPadding: edgeInsetsFromJson(j["p_padding"], EdgeInsets.zero)!, - code: parseTextStyle("code_text_style") ?? - theme.textTheme.bodyMedium!.copyWith(fontFamily: "monospace"), - h1: parseTextStyle("h1_text_style") ?? theme.textTheme.headlineSmall, - h1Padding: edgeInsetsFromJson(j["h1_padding"], EdgeInsets.zero)!, - h2: parseTextStyle("h2_text_style") ?? theme.textTheme.titleLarge, - h2Padding: edgeInsetsFromJson(j["h2_padding"], EdgeInsets.zero)!, - h3: parseTextStyle("h3_text_style") ?? theme.textTheme.titleMedium, - h3Padding: edgeInsetsFromJson(j["h3_padding"], EdgeInsets.zero)!, - h4: parseTextStyle("h4_text_style") ?? theme.textTheme.bodyLarge, - h4Padding: edgeInsetsFromJson(j["h4_padding"], EdgeInsets.zero)!, - h5: parseTextStyle("h5_text_style") ?? theme.textTheme.bodyLarge, - h5Padding: edgeInsetsFromJson(j["h5_padding"], EdgeInsets.zero)!, - h6: parseTextStyle("h6_text_style") ?? theme.textTheme.bodyLarge, - h6Padding: edgeInsetsFromJson(j["h6_padding"], EdgeInsets.zero)!, - em: parseTextStyle("em_text_style") ?? - const TextStyle(fontStyle: FontStyle.italic), - strong: parseTextStyle("strong_text_style") ?? - const TextStyle(fontWeight: FontWeight.bold), - del: parseTextStyle("del_text_style") ?? - const TextStyle(decoration: TextDecoration.lineThrough), - blockquote: - parseTextStyle("blockquote_text_style") ?? theme.textTheme.bodyMedium, - img: parseTextStyle("img_text_style") ?? theme.textTheme.bodyMedium, - checkbox: parseTextStyle("checkbox_text_style") ?? - theme.textTheme.bodyMedium!.copyWith( - color: theme.primaryColor, - ), - blockSpacing: parseDouble(j["block_spacing"], 8.0)!, - listIndent: parseDouble(j["list_indent"], 24.0)!, - listBullet: - parseTextStyle("list_bullet_text_style") ?? theme.textTheme.bodyMedium, - listBulletPadding: edgeInsetsFromJson( - j["list_bullet_padding"], const EdgeInsets.only(right: 4))!, - tableHead: parseTextStyle("table_head_text_style") ?? - const TextStyle(fontWeight: FontWeight.w600), - tableBody: - parseTextStyle("table_body_text_style") ?? theme.textTheme.bodyMedium, + a: parseTextStyle( + value["a_text_style"], theme, const TextStyle(color: Colors.blue))!, + p: parseTextStyle(value["p_text_style"], theme, theme.textTheme.bodyMedium), + pPadding: parsePadding(value["p_padding"], EdgeInsets.zero)!, + code: parseTextStyle(value["code_text_style"], theme, + theme.textTheme.bodyMedium!.copyWith(fontFamily: "monospace")), + h1: parseTextStyle(value["h1_text_style"], theme) ?? + theme.textTheme.headlineSmall, + h1Padding: parsePadding(value["h1_padding"], EdgeInsets.zero)!, + h2: parseTextStyle( + value["h2_text_style"], theme, theme.textTheme.titleLarge), + h2Padding: parsePadding(value["h2_padding"], EdgeInsets.zero)!, + h3: parseTextStyle( + value["h3_text_style"], theme, theme.textTheme.titleMedium), + h3Padding: parsePadding(value["h3_padding"], EdgeInsets.zero)!, + h4: parseTextStyle( + value["h4_text_style"], theme, theme.textTheme.bodyLarge), + h4Padding: parsePadding(value["h4_padding"], EdgeInsets.zero)!, + h5: parseTextStyle( + value["h5_text_style"], theme, theme.textTheme.bodyLarge), + h5Padding: parsePadding(value["h5_padding"], EdgeInsets.zero)!, + h6: parseTextStyle( + value["h6_text_style"], theme, theme.textTheme.bodyLarge), + h6Padding: parsePadding(value["h6_padding"], EdgeInsets.zero)!, + em: parseTextStyle(value["em_text_style"], theme, + const TextStyle(fontStyle: FontStyle.italic))!, + strong: parseTextStyle(value["strong_text_style"], theme, + const TextStyle(fontWeight: FontWeight.bold))!, + del: parseTextStyle(value["del_text_style"], theme, + const TextStyle(decoration: TextDecoration.lineThrough)), + blockquote: parseTextStyle( + value["blockquote_text_style"], theme, theme.textTheme.bodyMedium), + img: parseTextStyle( + value["img_text_style"], theme, theme.textTheme.bodyMedium), + checkbox: parseTextStyle(value["checkbox_text_style"], theme, + theme.textTheme.bodyMedium!.copyWith(color: theme.primaryColor)), + blockSpacing: parseDouble(value["block_spacing"], 8.0)!, + listIndent: parseDouble(value["list_indent"], 24.0)!, + listBullet: parseTextStyle( + value["list_bullet_text_style"], theme, theme.textTheme.bodyMedium), + listBulletPadding: parsePadding( + value["list_bullet_padding"], const EdgeInsets.only(right: 4))!, + tableHead: parseTextStyle(value["table_head_text_style"], theme, + const TextStyle(fontWeight: FontWeight.w600))!, + tableBody: parseTextStyle( + value["table_body_text_style"], theme, theme.textTheme.bodyMedium), tableHeadAlign: - parseTextAlign(j["table_head_text_align"], TextAlign.center)!, - tablePadding: edgeInsetsFromJson( - j["table_padding"], const EdgeInsets.only(bottom: 4.0))!, - tableBorder: TableBorder.all( - color: theme.dividerColor, - ), + parseTextAlign(value["table_head_text_align"], TextAlign.center)!, + tablePadding: parsePadding( + value["table_padding"], const EdgeInsets.only(bottom: 4.0))!, + tableBorder: TableBorder.all(color: theme.dividerColor), tableColumnWidth: const FlexColumnWidth(), - tableCellsPadding: edgeInsetsFromJson( - j["table_cells_padding"], const EdgeInsets.fromLTRB(16, 8, 16, 8))!, - tableCellsDecoration: - boxDecorationFromJSON(theme, j["table_cells_decoration"], pageArgs) ?? - const BoxDecoration(), - blockquotePadding: edgeInsetsFromJson(j["blockquote_padding"]) ?? - const EdgeInsets.all(8.0), - blockquoteDecoration: - boxDecorationFromJSON(theme, j["blockquote_decoration"], pageArgs) ?? - BoxDecoration( - color: Colors.blue.shade100, - borderRadius: BorderRadius.circular(2.0), - ), + tableCellsPadding: parsePadding( + value["table_cells_padding"], const EdgeInsets.fromLTRB(16, 8, 16, 8))!, + tableCellsDecoration: parseBoxDecoration( + value["table_cells_decoration"], context, const BoxDecoration()), + blockquotePadding: + parsePadding(value["blockquote_padding"], const EdgeInsets.all(8.0))!, + blockquoteDecoration: parseBoxDecoration( + value["blockquote_decoration"], + context, + BoxDecoration( + color: Colors.blue.shade100, + borderRadius: BorderRadius.circular(2.0)))!, codeblockPadding: - edgeInsetsFromJson(j["codeblock_padding"], const EdgeInsets.all(8.0))!, - codeblockDecoration: - boxDecorationFromJSON(theme, j["codeblock_decoration"], pageArgs) ?? - BoxDecoration( - color: theme.cardTheme.color ?? theme.cardColor, - borderRadius: BorderRadius.circular(2.0), - ), - horizontalRuleDecoration: boxDecorationFromJSON( - theme, j["horizontal_rule_decoration"], pageArgs) ?? + parsePadding(value["codeblock_padding"], const EdgeInsets.all(8.0))!, + codeblockDecoration: parseBoxDecoration( + value["codeblock_decoration"], + context, BoxDecoration( - border: Border( - top: BorderSide( - width: 5.0, - color: theme.dividerColor, - ), - ), - ), + color: theme.cardTheme.color ?? theme.cardColor, + borderRadius: BorderRadius.circular(2.0)))!, + horizontalRuleDecoration: parseBoxDecoration( + value["horizontal_rule_decoration"], + context, + BoxDecoration( + border: Border( + top: BorderSide(width: 5.0, color: theme.dividerColor))))!, blockquoteAlign: - parseWrapAlignment(j["blockquote_alignment"], WrapAlignment.start)!, + parseWrapAlignment(value["blockquote_alignment"], WrapAlignment.start)!, codeblockAlign: - parseWrapAlignment(j["codeblock_alignment"], WrapAlignment.start)!, - h1Align: parseWrapAlignment(j["h1_alignment"], WrapAlignment.start)!, - h2Align: parseWrapAlignment(j["h2_alignment"], WrapAlignment.start)!, - h3Align: parseWrapAlignment(j["h3_alignment"], WrapAlignment.start)!, - h4Align: parseWrapAlignment(j["h4_alignment"], WrapAlignment.start)!, - h5Align: parseWrapAlignment(j["h5_alignment"], WrapAlignment.start)!, - h6Align: parseWrapAlignment(j["h6_alignment"], WrapAlignment.start)!, - textAlign: parseWrapAlignment(j["text_alignment"], WrapAlignment.start)!, - orderedListAlign: - parseWrapAlignment(j["ordered_list_alignment"], WrapAlignment.start)!, - unorderedListAlign: - parseWrapAlignment(j["unordered_list_alignment"], WrapAlignment.start)!, + parseWrapAlignment(value["codeblock_alignment"], WrapAlignment.start)!, + h1Align: parseWrapAlignment(value["h1_alignment"], WrapAlignment.start)!, + h2Align: parseWrapAlignment(value["h2_alignment"], WrapAlignment.start)!, + h3Align: parseWrapAlignment(value["h3_alignment"], WrapAlignment.start)!, + h4Align: parseWrapAlignment(value["h4_alignment"], WrapAlignment.start)!, + h5Align: parseWrapAlignment(value["h5_alignment"], WrapAlignment.start)!, + h6Align: parseWrapAlignment(value["h6_alignment"], WrapAlignment.start)!, + textAlign: + parseWrapAlignment(value["text_alignment"], WrapAlignment.start)!, + orderedListAlign: parseWrapAlignment( + value["ordered_list_alignment"], WrapAlignment.start)!, + unorderedListAlign: parseWrapAlignment( + value["unordered_list_alignment"], WrapAlignment.start)!, ); } + +extension MarkdownParsers on Control { + Map getMarkdownCodeTheme( + String propertyName, ThemeData theme) { + return parseMarkdownCodeTheme(get(propertyName), theme); + } + + md.ExtensionSet? getMarkdownExtensionSet(String propertyName, + [md.ExtensionSet? defaultValue]) { + return parseMarkdownExtensionSet(get(propertyName), defaultValue); + } + + MarkdownStyleSheet? getMarkdownStyleSheet( + String propertyName, BuildContext context, + [MarkdownStyleSheet? defaultValue]) { + return parseMarkdownStyleSheet(get(propertyName), context, defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/material_icons.dart b/packages/flet/lib/src/utils/material_icons.dart index eb5e9e9104..61148f24e0 100644 --- a/packages/flet/lib/src/utils/material_icons.dart +++ b/packages/flet/lib/src/utils/material_icons.dart @@ -1,8913 +1,8829 @@ import 'package:flutter/material.dart'; -/* - -To generate update the list run: - -sh ci/generate_material_icons_dart.sh - -*/ - -Map materialIcons = { - "ten_k": Icons.ten_k, - "ten_k_sharp": Icons.ten_k_sharp, - "ten_k_rounded": Icons.ten_k_rounded, - "ten_k_outlined": Icons.ten_k_outlined, - "ten_mp": Icons.ten_mp, - "ten_mp_sharp": Icons.ten_mp_sharp, - "ten_mp_rounded": Icons.ten_mp_rounded, - "ten_mp_outlined": Icons.ten_mp_outlined, - "eleven_mp": Icons.eleven_mp, - "eleven_mp_sharp": Icons.eleven_mp_sharp, - "eleven_mp_rounded": Icons.eleven_mp_rounded, - "eleven_mp_outlined": Icons.eleven_mp_outlined, - "onetwothree": Icons.onetwothree, - "onetwothree_sharp": Icons.onetwothree_sharp, - "onetwothree_rounded": Icons.onetwothree_rounded, - "onetwothree_outlined": Icons.onetwothree_outlined, - "twelve_mp": Icons.twelve_mp, - "twelve_mp_sharp": Icons.twelve_mp_sharp, - "twelve_mp_rounded": Icons.twelve_mp_rounded, - "twelve_mp_outlined": Icons.twelve_mp_outlined, - "thirteen_mp": Icons.thirteen_mp, - "thirteen_mp_sharp": Icons.thirteen_mp_sharp, - "thirteen_mp_rounded": Icons.thirteen_mp_rounded, - "thirteen_mp_outlined": Icons.thirteen_mp_outlined, - "fourteen_mp": Icons.fourteen_mp, - "fourteen_mp_sharp": Icons.fourteen_mp_sharp, - "fourteen_mp_rounded": Icons.fourteen_mp_rounded, - "fourteen_mp_outlined": Icons.fourteen_mp_outlined, - "fifteen_mp": Icons.fifteen_mp, - "fifteen_mp_sharp": Icons.fifteen_mp_sharp, - "fifteen_mp_rounded": Icons.fifteen_mp_rounded, - "fifteen_mp_outlined": Icons.fifteen_mp_outlined, - "sixteen_mp": Icons.sixteen_mp, - "sixteen_mp_sharp": Icons.sixteen_mp_sharp, - "sixteen_mp_rounded": Icons.sixteen_mp_rounded, - "sixteen_mp_outlined": Icons.sixteen_mp_outlined, - "seventeen_mp": Icons.seventeen_mp, - "seventeen_mp_sharp": Icons.seventeen_mp_sharp, - "seventeen_mp_rounded": Icons.seventeen_mp_rounded, - "seventeen_mp_outlined": Icons.seventeen_mp_outlined, - "eighteen_up_rating": Icons.eighteen_up_rating, - "eighteen_up_rating_sharp": Icons.eighteen_up_rating_sharp, - "eighteen_up_rating_rounded": Icons.eighteen_up_rating_rounded, - "eighteen_up_rating_outlined": Icons.eighteen_up_rating_outlined, - "eighteen_mp": Icons.eighteen_mp, - "eighteen_mp_sharp": Icons.eighteen_mp_sharp, - "eighteen_mp_rounded": Icons.eighteen_mp_rounded, - "eighteen_mp_outlined": Icons.eighteen_mp_outlined, - "nineteen_mp": Icons.nineteen_mp, - "nineteen_mp_sharp": Icons.nineteen_mp_sharp, - "nineteen_mp_rounded": Icons.nineteen_mp_rounded, - "nineteen_mp_outlined": Icons.nineteen_mp_outlined, - "one_k": Icons.one_k, - "one_k_sharp": Icons.one_k_sharp, - "one_k_rounded": Icons.one_k_rounded, - "one_k_outlined": Icons.one_k_outlined, - "one_k_plus": Icons.one_k_plus, - "one_k_plus_sharp": Icons.one_k_plus_sharp, - "one_k_plus_rounded": Icons.one_k_plus_rounded, - "one_k_plus_outlined": Icons.one_k_plus_outlined, - "one_x_mobiledata": Icons.one_x_mobiledata, - "one_x_mobiledata_sharp": Icons.one_x_mobiledata_sharp, - "one_x_mobiledata_rounded": Icons.one_x_mobiledata_rounded, - "one_x_mobiledata_outlined": Icons.one_x_mobiledata_outlined, - "twenty_mp": Icons.twenty_mp, - "twenty_mp_sharp": Icons.twenty_mp_sharp, - "twenty_mp_rounded": Icons.twenty_mp_rounded, - "twenty_mp_outlined": Icons.twenty_mp_outlined, - "twenty_one_mp": Icons.twenty_one_mp, - "twenty_one_mp_sharp": Icons.twenty_one_mp_sharp, - "twenty_one_mp_rounded": Icons.twenty_one_mp_rounded, - "twenty_one_mp_outlined": Icons.twenty_one_mp_outlined, - "twenty_two_mp": Icons.twenty_two_mp, - "twenty_two_mp_sharp": Icons.twenty_two_mp_sharp, - "twenty_two_mp_rounded": Icons.twenty_two_mp_rounded, - "twenty_two_mp_outlined": Icons.twenty_two_mp_outlined, - "twenty_three_mp": Icons.twenty_three_mp, - "twenty_three_mp_sharp": Icons.twenty_three_mp_sharp, - "twenty_three_mp_rounded": Icons.twenty_three_mp_rounded, - "twenty_three_mp_outlined": Icons.twenty_three_mp_outlined, - "twenty_four_mp": Icons.twenty_four_mp, - "twenty_four_mp_sharp": Icons.twenty_four_mp_sharp, - "twenty_four_mp_rounded": Icons.twenty_four_mp_rounded, - "twenty_four_mp_outlined": Icons.twenty_four_mp_outlined, - "two_k": Icons.two_k, - "two_k_sharp": Icons.two_k_sharp, - "two_k_rounded": Icons.two_k_rounded, - "two_k_outlined": Icons.two_k_outlined, - "two_k_plus": Icons.two_k_plus, - "two_k_plus_sharp": Icons.two_k_plus_sharp, - "two_k_plus_rounded": Icons.two_k_plus_rounded, - "two_k_plus_outlined": Icons.two_k_plus_outlined, - "two_mp": Icons.two_mp, - "two_mp_sharp": Icons.two_mp_sharp, - "two_mp_rounded": Icons.two_mp_rounded, - "two_mp_outlined": Icons.two_mp_outlined, - "thirty_fps": Icons.thirty_fps, - "thirty_fps_sharp": Icons.thirty_fps_sharp, - "thirty_fps_rounded": Icons.thirty_fps_rounded, - "thirty_fps_outlined": Icons.thirty_fps_outlined, - "thirty_fps_select": Icons.thirty_fps_select, - "thirty_fps_select_sharp": Icons.thirty_fps_select_sharp, - "thirty_fps_select_rounded": Icons.thirty_fps_select_rounded, - "thirty_fps_select_outlined": Icons.thirty_fps_select_outlined, - "threesixty": Icons.threesixty, - "threesixty_sharp": Icons.threesixty_sharp, - "threesixty_rounded": Icons.threesixty_rounded, - "threesixty_outlined": Icons.threesixty_outlined, - "threed_rotation": Icons.threed_rotation, - "threed_rotation_sharp": Icons.threed_rotation_sharp, - "threed_rotation_rounded": Icons.threed_rotation_rounded, - "threed_rotation_outlined": Icons.threed_rotation_outlined, - "three_g_mobiledata": Icons.three_g_mobiledata, - "three_g_mobiledata_sharp": Icons.three_g_mobiledata_sharp, - "three_g_mobiledata_rounded": Icons.three_g_mobiledata_rounded, - "three_g_mobiledata_outlined": Icons.three_g_mobiledata_outlined, - "three_k": Icons.three_k, - "three_k_sharp": Icons.three_k_sharp, - "three_k_rounded": Icons.three_k_rounded, - "three_k_outlined": Icons.three_k_outlined, - "three_k_plus": Icons.three_k_plus, - "three_k_plus_sharp": Icons.three_k_plus_sharp, - "three_k_plus_rounded": Icons.three_k_plus_rounded, - "three_k_plus_outlined": Icons.three_k_plus_outlined, - "three_mp": Icons.three_mp, - "three_mp_sharp": Icons.three_mp_sharp, - "three_mp_rounded": Icons.three_mp_rounded, - "three_mp_outlined": Icons.three_mp_outlined, - "three_p": Icons.three_p, - "three_p_sharp": Icons.three_p_sharp, - "three_p_rounded": Icons.three_p_rounded, - "three_p_outlined": Icons.three_p_outlined, - "four_g_mobiledata": Icons.four_g_mobiledata, - "four_g_mobiledata_sharp": Icons.four_g_mobiledata_sharp, - "four_g_mobiledata_rounded": Icons.four_g_mobiledata_rounded, - "four_g_mobiledata_outlined": Icons.four_g_mobiledata_outlined, - "four_g_plus_mobiledata": Icons.four_g_plus_mobiledata, - "four_g_plus_mobiledata_sharp": Icons.four_g_plus_mobiledata_sharp, - "four_g_plus_mobiledata_rounded": Icons.four_g_plus_mobiledata_rounded, - "four_g_plus_mobiledata_outlined": Icons.four_g_plus_mobiledata_outlined, - "four_k": Icons.four_k, - "four_k_sharp": Icons.four_k_sharp, - "four_k_rounded": Icons.four_k_rounded, - "four_k_outlined": Icons.four_k_outlined, - "four_k_plus": Icons.four_k_plus, - "four_k_plus_sharp": Icons.four_k_plus_sharp, - "four_k_plus_rounded": Icons.four_k_plus_rounded, - "four_k_plus_outlined": Icons.four_k_plus_outlined, - "four_mp": Icons.four_mp, - "four_mp_sharp": Icons.four_mp_sharp, - "four_mp_rounded": Icons.four_mp_rounded, - "four_mp_outlined": Icons.four_mp_outlined, - "five_g": Icons.five_g, - "five_g_sharp": Icons.five_g_sharp, - "five_g_rounded": Icons.five_g_rounded, - "five_g_outlined": Icons.five_g_outlined, - "five_k": Icons.five_k, - "five_k_sharp": Icons.five_k_sharp, - "five_k_rounded": Icons.five_k_rounded, - "five_k_outlined": Icons.five_k_outlined, - "five_k_plus": Icons.five_k_plus, - "five_k_plus_sharp": Icons.five_k_plus_sharp, - "five_k_plus_rounded": Icons.five_k_plus_rounded, - "five_k_plus_outlined": Icons.five_k_plus_outlined, - "five_mp": Icons.five_mp, - "five_mp_sharp": Icons.five_mp_sharp, - "five_mp_rounded": Icons.five_mp_rounded, - "five_mp_outlined": Icons.five_mp_outlined, - "sixty_fps": Icons.sixty_fps, - "sixty_fps_sharp": Icons.sixty_fps_sharp, - "sixty_fps_rounded": Icons.sixty_fps_rounded, - "sixty_fps_outlined": Icons.sixty_fps_outlined, - "sixty_fps_select": Icons.sixty_fps_select, - "sixty_fps_select_sharp": Icons.sixty_fps_select_sharp, - "sixty_fps_select_rounded": Icons.sixty_fps_select_rounded, - "sixty_fps_select_outlined": Icons.sixty_fps_select_outlined, - "six_ft_apart": Icons.six_ft_apart, - "six_ft_apart_sharp": Icons.six_ft_apart_sharp, - "six_ft_apart_rounded": Icons.six_ft_apart_rounded, - "six_ft_apart_outlined": Icons.six_ft_apart_outlined, - "six_k": Icons.six_k, - "six_k_sharp": Icons.six_k_sharp, - "six_k_rounded": Icons.six_k_rounded, - "six_k_outlined": Icons.six_k_outlined, - "six_k_plus": Icons.six_k_plus, - "six_k_plus_sharp": Icons.six_k_plus_sharp, - "six_k_plus_rounded": Icons.six_k_plus_rounded, - "six_k_plus_outlined": Icons.six_k_plus_outlined, - "six_mp": Icons.six_mp, - "six_mp_sharp": Icons.six_mp_sharp, - "six_mp_rounded": Icons.six_mp_rounded, - "six_mp_outlined": Icons.six_mp_outlined, - "seven_k": Icons.seven_k, - "seven_k_sharp": Icons.seven_k_sharp, - "seven_k_rounded": Icons.seven_k_rounded, - "seven_k_outlined": Icons.seven_k_outlined, - "seven_k_plus": Icons.seven_k_plus, - "seven_k_plus_sharp": Icons.seven_k_plus_sharp, - "seven_k_plus_rounded": Icons.seven_k_plus_rounded, - "seven_k_plus_outlined": Icons.seven_k_plus_outlined, - "seven_mp": Icons.seven_mp, - "seven_mp_sharp": Icons.seven_mp_sharp, - "seven_mp_rounded": Icons.seven_mp_rounded, - "seven_mp_outlined": Icons.seven_mp_outlined, - "eight_k": Icons.eight_k, - "eight_k_sharp": Icons.eight_k_sharp, - "eight_k_rounded": Icons.eight_k_rounded, - "eight_k_outlined": Icons.eight_k_outlined, - "eight_k_plus": Icons.eight_k_plus, - "eight_k_plus_sharp": Icons.eight_k_plus_sharp, - "eight_k_plus_rounded": Icons.eight_k_plus_rounded, - "eight_k_plus_outlined": Icons.eight_k_plus_outlined, - "eight_mp": Icons.eight_mp, - "eight_mp_sharp": Icons.eight_mp_sharp, - "eight_mp_rounded": Icons.eight_mp_rounded, - "eight_mp_outlined": Icons.eight_mp_outlined, - "nine_k": Icons.nine_k, - "nine_k_sharp": Icons.nine_k_sharp, - "nine_k_rounded": Icons.nine_k_rounded, - "nine_k_outlined": Icons.nine_k_outlined, - "nine_k_plus": Icons.nine_k_plus, - "nine_k_plus_sharp": Icons.nine_k_plus_sharp, - "nine_k_plus_rounded": Icons.nine_k_plus_rounded, - "nine_k_plus_outlined": Icons.nine_k_plus_outlined, - "nine_mp": Icons.nine_mp, - "nine_mp_sharp": Icons.nine_mp_sharp, - "nine_mp_rounded": Icons.nine_mp_rounded, - "nine_mp_outlined": Icons.nine_mp_outlined, - "abc": Icons.abc, - "abc_sharp": Icons.abc_sharp, - "abc_rounded": Icons.abc_rounded, - "abc_outlined": Icons.abc_outlined, - "ac_unit": Icons.ac_unit, - "ac_unit_sharp": Icons.ac_unit_sharp, - "ac_unit_rounded": Icons.ac_unit_rounded, - "ac_unit_outlined": Icons.ac_unit_outlined, - "access_alarm": Icons.access_alarm, - "access_alarm_sharp": Icons.access_alarm_sharp, - "access_alarm_rounded": Icons.access_alarm_rounded, - "access_alarm_outlined": Icons.access_alarm_outlined, - "access_alarms": Icons.access_alarms, - "access_alarms_sharp": Icons.access_alarms_sharp, - "access_alarms_rounded": Icons.access_alarms_rounded, - "access_alarms_outlined": Icons.access_alarms_outlined, - "access_time": Icons.access_time, - "access_time_sharp": Icons.access_time_sharp, - "access_time_rounded": Icons.access_time_rounded, - "access_time_outlined": Icons.access_time_outlined, - "access_time_filled": Icons.access_time_filled, - "access_time_filled_sharp": Icons.access_time_filled_sharp, - "access_time_filled_rounded": Icons.access_time_filled_rounded, - "access_time_filled_outlined": Icons.access_time_filled_outlined, - "accessibility": Icons.accessibility, - "accessibility_sharp": Icons.accessibility_sharp, - "accessibility_rounded": Icons.accessibility_rounded, - "accessibility_outlined": Icons.accessibility_outlined, - "accessibility_new": Icons.accessibility_new, - "accessibility_new_sharp": Icons.accessibility_new_sharp, - "accessibility_new_rounded": Icons.accessibility_new_rounded, - "accessibility_new_outlined": Icons.accessibility_new_outlined, - "accessible": Icons.accessible, - "accessible_sharp": Icons.accessible_sharp, - "accessible_rounded": Icons.accessible_rounded, - "accessible_outlined": Icons.accessible_outlined, - "accessible_forward": Icons.accessible_forward, - "accessible_forward_sharp": Icons.accessible_forward_sharp, - "accessible_forward_rounded": Icons.accessible_forward_rounded, - "accessible_forward_outlined": Icons.accessible_forward_outlined, - "account_balance": Icons.account_balance, - "account_balance_sharp": Icons.account_balance_sharp, - "account_balance_rounded": Icons.account_balance_rounded, - "account_balance_outlined": Icons.account_balance_outlined, - "account_balance_wallet": Icons.account_balance_wallet, - "account_balance_wallet_sharp": Icons.account_balance_wallet_sharp, - "account_balance_wallet_rounded": Icons.account_balance_wallet_rounded, - "account_balance_wallet_outlined": Icons.account_balance_wallet_outlined, - "account_box": Icons.account_box, - "account_box_sharp": Icons.account_box_sharp, - "account_box_rounded": Icons.account_box_rounded, - "account_box_outlined": Icons.account_box_outlined, - "account_circle": Icons.account_circle, - "account_circle_sharp": Icons.account_circle_sharp, - "account_circle_rounded": Icons.account_circle_rounded, - "account_circle_outlined": Icons.account_circle_outlined, - "account_tree": Icons.account_tree, - "account_tree_sharp": Icons.account_tree_sharp, - "account_tree_rounded": Icons.account_tree_rounded, - "account_tree_outlined": Icons.account_tree_outlined, - "ad_units": Icons.ad_units, - "ad_units_sharp": Icons.ad_units_sharp, - "ad_units_rounded": Icons.ad_units_rounded, - "ad_units_outlined": Icons.ad_units_outlined, - "adb": Icons.adb, - "adb_sharp": Icons.adb_sharp, - "adb_rounded": Icons.adb_rounded, - "adb_outlined": Icons.adb_outlined, - "add": Icons.add, - "add_sharp": Icons.add_sharp, - "add_rounded": Icons.add_rounded, - "add_outlined": Icons.add_outlined, - "add_a_photo": Icons.add_a_photo, - "add_a_photo_sharp": Icons.add_a_photo_sharp, - "add_a_photo_rounded": Icons.add_a_photo_rounded, - "add_a_photo_outlined": Icons.add_a_photo_outlined, - "add_alarm": Icons.add_alarm, - "add_alarm_sharp": Icons.add_alarm_sharp, - "add_alarm_rounded": Icons.add_alarm_rounded, - "add_alarm_outlined": Icons.add_alarm_outlined, - "add_alert": Icons.add_alert, - "add_alert_sharp": Icons.add_alert_sharp, - "add_alert_rounded": Icons.add_alert_rounded, - "add_alert_outlined": Icons.add_alert_outlined, - "add_box": Icons.add_box, - "add_box_sharp": Icons.add_box_sharp, - "add_box_rounded": Icons.add_box_rounded, - "add_box_outlined": Icons.add_box_outlined, - "add_business": Icons.add_business, - "add_business_sharp": Icons.add_business_sharp, - "add_business_rounded": Icons.add_business_rounded, - "add_business_outlined": Icons.add_business_outlined, - "add_call": Icons.add_call, - "add_card": Icons.add_card, - "add_card_sharp": Icons.add_card_sharp, - "add_card_rounded": Icons.add_card_rounded, - "add_card_outlined": Icons.add_card_outlined, - "add_chart": Icons.add_chart, - "add_chart_sharp": Icons.add_chart_sharp, - "add_chart_rounded": Icons.add_chart_rounded, - "add_chart_outlined": Icons.add_chart_outlined, - "add_circle": Icons.add_circle, - "add_circle_sharp": Icons.add_circle_sharp, - "add_circle_rounded": Icons.add_circle_rounded, - "add_circle_outlined": Icons.add_circle_outlined, - "add_circle_outline": Icons.add_circle_outline, - "add_circle_outline_sharp": Icons.add_circle_outline_sharp, - "add_circle_outline_rounded": Icons.add_circle_outline_rounded, - "add_circle_outline_outlined": Icons.add_circle_outline_outlined, - "add_comment": Icons.add_comment, - "add_comment_sharp": Icons.add_comment_sharp, - "add_comment_rounded": Icons.add_comment_rounded, - "add_comment_outlined": Icons.add_comment_outlined, - "add_home": Icons.add_home, - "add_home_sharp": Icons.add_home_sharp, - "add_home_rounded": Icons.add_home_rounded, - "add_home_outlined": Icons.add_home_outlined, - "add_home_work": Icons.add_home_work, - "add_home_work_sharp": Icons.add_home_work_sharp, - "add_home_work_rounded": Icons.add_home_work_rounded, - "add_home_work_outlined": Icons.add_home_work_outlined, - "add_ic_call": Icons.add_ic_call, - "add_ic_call_sharp": Icons.add_ic_call_sharp, - "add_ic_call_rounded": Icons.add_ic_call_rounded, - "add_ic_call_outlined": Icons.add_ic_call_outlined, - "add_link": Icons.add_link, - "add_link_sharp": Icons.add_link_sharp, - "add_link_rounded": Icons.add_link_rounded, - "add_link_outlined": Icons.add_link_outlined, - "add_location": Icons.add_location, - "add_location_sharp": Icons.add_location_sharp, - "add_location_rounded": Icons.add_location_rounded, - "add_location_outlined": Icons.add_location_outlined, - "add_location_alt": Icons.add_location_alt, - "add_location_alt_sharp": Icons.add_location_alt_sharp, - "add_location_alt_rounded": Icons.add_location_alt_rounded, - "add_location_alt_outlined": Icons.add_location_alt_outlined, - "add_moderator": Icons.add_moderator, - "add_moderator_sharp": Icons.add_moderator_sharp, - "add_moderator_rounded": Icons.add_moderator_rounded, - "add_moderator_outlined": Icons.add_moderator_outlined, - "add_photo_alternate": Icons.add_photo_alternate, - "add_photo_alternate_sharp": Icons.add_photo_alternate_sharp, - "add_photo_alternate_rounded": Icons.add_photo_alternate_rounded, - "add_photo_alternate_outlined": Icons.add_photo_alternate_outlined, - "add_reaction": Icons.add_reaction, - "add_reaction_sharp": Icons.add_reaction_sharp, - "add_reaction_rounded": Icons.add_reaction_rounded, - "add_reaction_outlined": Icons.add_reaction_outlined, - "add_road": Icons.add_road, - "add_road_sharp": Icons.add_road_sharp, - "add_road_rounded": Icons.add_road_rounded, - "add_road_outlined": Icons.add_road_outlined, - "add_shopping_cart": Icons.add_shopping_cart, - "add_shopping_cart_sharp": Icons.add_shopping_cart_sharp, - "add_shopping_cart_rounded": Icons.add_shopping_cart_rounded, - "add_shopping_cart_outlined": Icons.add_shopping_cart_outlined, - "add_task": Icons.add_task, - "add_task_sharp": Icons.add_task_sharp, - "add_task_rounded": Icons.add_task_rounded, - "add_task_outlined": Icons.add_task_outlined, - "add_to_drive": Icons.add_to_drive, - "add_to_drive_sharp": Icons.add_to_drive_sharp, - "add_to_drive_rounded": Icons.add_to_drive_rounded, - "add_to_drive_outlined": Icons.add_to_drive_outlined, - "add_to_home_screen": Icons.add_to_home_screen, - "add_to_home_screen_sharp": Icons.add_to_home_screen_sharp, - "add_to_home_screen_rounded": Icons.add_to_home_screen_rounded, - "add_to_home_screen_outlined": Icons.add_to_home_screen_outlined, - "add_to_photos": Icons.add_to_photos, - "add_to_photos_sharp": Icons.add_to_photos_sharp, - "add_to_photos_rounded": Icons.add_to_photos_rounded, - "add_to_photos_outlined": Icons.add_to_photos_outlined, - "add_to_queue": Icons.add_to_queue, - "add_to_queue_sharp": Icons.add_to_queue_sharp, - "add_to_queue_rounded": Icons.add_to_queue_rounded, - "add_to_queue_outlined": Icons.add_to_queue_outlined, - "addchart": Icons.addchart, - "addchart_sharp": Icons.addchart_sharp, - "addchart_rounded": Icons.addchart_rounded, - "addchart_outlined": Icons.addchart_outlined, - "adf_scanner": Icons.adf_scanner, - "adf_scanner_sharp": Icons.adf_scanner_sharp, - "adf_scanner_rounded": Icons.adf_scanner_rounded, - "adf_scanner_outlined": Icons.adf_scanner_outlined, - "adjust": Icons.adjust, - "adjust_sharp": Icons.adjust_sharp, - "adjust_rounded": Icons.adjust_rounded, - "adjust_outlined": Icons.adjust_outlined, - "admin_panel_settings": Icons.admin_panel_settings, - "admin_panel_settings_sharp": Icons.admin_panel_settings_sharp, - "admin_panel_settings_rounded": Icons.admin_panel_settings_rounded, - "admin_panel_settings_outlined": Icons.admin_panel_settings_outlined, - "adobe": Icons.adobe, - "adobe_sharp": Icons.adobe_sharp, - "adobe_rounded": Icons.adobe_rounded, - "adobe_outlined": Icons.adobe_outlined, - "ads_click": Icons.ads_click, - "ads_click_sharp": Icons.ads_click_sharp, - "ads_click_rounded": Icons.ads_click_rounded, - "ads_click_outlined": Icons.ads_click_outlined, - "agriculture": Icons.agriculture, - "agriculture_sharp": Icons.agriculture_sharp, - "agriculture_rounded": Icons.agriculture_rounded, - "agriculture_outlined": Icons.agriculture_outlined, - "air": Icons.air, - "air_sharp": Icons.air_sharp, - "air_rounded": Icons.air_rounded, - "air_outlined": Icons.air_outlined, - "airline_seat_flat": Icons.airline_seat_flat, - "airline_seat_flat_sharp": Icons.airline_seat_flat_sharp, - "airline_seat_flat_rounded": Icons.airline_seat_flat_rounded, - "airline_seat_flat_outlined": Icons.airline_seat_flat_outlined, - "airline_seat_flat_angled": Icons.airline_seat_flat_angled, - "airline_seat_flat_angled_sharp": Icons.airline_seat_flat_angled_sharp, - "airline_seat_flat_angled_rounded": Icons.airline_seat_flat_angled_rounded, - "airline_seat_flat_angled_outlined": Icons.airline_seat_flat_angled_outlined, - "airline_seat_individual_suite": Icons.airline_seat_individual_suite, - "airline_seat_individual_suite_sharp": - Icons.airline_seat_individual_suite_sharp, - "airline_seat_individual_suite_rounded": - Icons.airline_seat_individual_suite_rounded, - "airline_seat_individual_suite_outlined": - Icons.airline_seat_individual_suite_outlined, - "airline_seat_legroom_extra": Icons.airline_seat_legroom_extra, - "airline_seat_legroom_extra_sharp": Icons.airline_seat_legroom_extra_sharp, - "airline_seat_legroom_extra_rounded": - Icons.airline_seat_legroom_extra_rounded, - "airline_seat_legroom_extra_outlined": - Icons.airline_seat_legroom_extra_outlined, - "airline_seat_legroom_normal": Icons.airline_seat_legroom_normal, - "airline_seat_legroom_normal_sharp": Icons.airline_seat_legroom_normal_sharp, - "airline_seat_legroom_normal_rounded": - Icons.airline_seat_legroom_normal_rounded, - "airline_seat_legroom_normal_outlined": - Icons.airline_seat_legroom_normal_outlined, - "airline_seat_legroom_reduced": Icons.airline_seat_legroom_reduced, - "airline_seat_legroom_reduced_sharp": - Icons.airline_seat_legroom_reduced_sharp, - "airline_seat_legroom_reduced_rounded": - Icons.airline_seat_legroom_reduced_rounded, - "airline_seat_legroom_reduced_outlined": - Icons.airline_seat_legroom_reduced_outlined, - "airline_seat_recline_extra": Icons.airline_seat_recline_extra, - "airline_seat_recline_extra_sharp": Icons.airline_seat_recline_extra_sharp, - "airline_seat_recline_extra_rounded": - Icons.airline_seat_recline_extra_rounded, - "airline_seat_recline_extra_outlined": - Icons.airline_seat_recline_extra_outlined, - "airline_seat_recline_normal": Icons.airline_seat_recline_normal, - "airline_seat_recline_normal_sharp": Icons.airline_seat_recline_normal_sharp, - "airline_seat_recline_normal_rounded": - Icons.airline_seat_recline_normal_rounded, - "airline_seat_recline_normal_outlined": - Icons.airline_seat_recline_normal_outlined, - "airline_stops": Icons.airline_stops, - "airline_stops_sharp": Icons.airline_stops_sharp, - "airline_stops_rounded": Icons.airline_stops_rounded, - "airline_stops_outlined": Icons.airline_stops_outlined, - "airlines": Icons.airlines, - "airlines_sharp": Icons.airlines_sharp, - "airlines_rounded": Icons.airlines_rounded, - "airlines_outlined": Icons.airlines_outlined, - "airplane_ticket": Icons.airplane_ticket, - "airplane_ticket_sharp": Icons.airplane_ticket_sharp, - "airplane_ticket_rounded": Icons.airplane_ticket_rounded, - "airplane_ticket_outlined": Icons.airplane_ticket_outlined, - "airplanemode_active": Icons.airplanemode_active, - "airplanemode_active_sharp": Icons.airplanemode_active_sharp, - "airplanemode_active_rounded": Icons.airplanemode_active_rounded, - "airplanemode_active_outlined": Icons.airplanemode_active_outlined, - "airplanemode_inactive": Icons.airplanemode_inactive, - "airplanemode_inactive_sharp": Icons.airplanemode_inactive_sharp, - "airplanemode_inactive_rounded": Icons.airplanemode_inactive_rounded, - "airplanemode_inactive_outlined": Icons.airplanemode_inactive_outlined, - "airplanemode_off": Icons.airplanemode_off, - "airplanemode_off_sharp": Icons.airplanemode_off_sharp, - "airplanemode_off_rounded": Icons.airplanemode_off_rounded, - "airplanemode_off_outlined": Icons.airplanemode_off_outlined, - "airplanemode_on": Icons.airplanemode_on, - "airplanemode_on_sharp": Icons.airplanemode_on_sharp, - "airplanemode_on_rounded": Icons.airplanemode_on_rounded, - "airplanemode_on_outlined": Icons.airplanemode_on_outlined, - "airplay": Icons.airplay, - "airplay_sharp": Icons.airplay_sharp, - "airplay_rounded": Icons.airplay_rounded, - "airplay_outlined": Icons.airplay_outlined, - "airport_shuttle": Icons.airport_shuttle, - "airport_shuttle_sharp": Icons.airport_shuttle_sharp, - "airport_shuttle_rounded": Icons.airport_shuttle_rounded, - "airport_shuttle_outlined": Icons.airport_shuttle_outlined, - "alarm": Icons.alarm, - "alarm_sharp": Icons.alarm_sharp, - "alarm_rounded": Icons.alarm_rounded, - "alarm_outlined": Icons.alarm_outlined, - "alarm_add": Icons.alarm_add, - "alarm_add_sharp": Icons.alarm_add_sharp, - "alarm_add_rounded": Icons.alarm_add_rounded, - "alarm_add_outlined": Icons.alarm_add_outlined, - "alarm_off": Icons.alarm_off, - "alarm_off_sharp": Icons.alarm_off_sharp, - "alarm_off_rounded": Icons.alarm_off_rounded, - "alarm_off_outlined": Icons.alarm_off_outlined, - "alarm_on": Icons.alarm_on, - "alarm_on_sharp": Icons.alarm_on_sharp, - "alarm_on_rounded": Icons.alarm_on_rounded, - "alarm_on_outlined": Icons.alarm_on_outlined, - "album": Icons.album, - "album_sharp": Icons.album_sharp, - "album_rounded": Icons.album_rounded, - "album_outlined": Icons.album_outlined, - "align_horizontal_center": Icons.align_horizontal_center, - "align_horizontal_center_sharp": Icons.align_horizontal_center_sharp, - "align_horizontal_center_rounded": Icons.align_horizontal_center_rounded, - "align_horizontal_center_outlined": Icons.align_horizontal_center_outlined, - "align_horizontal_left": Icons.align_horizontal_left, - "align_horizontal_left_sharp": Icons.align_horizontal_left_sharp, - "align_horizontal_left_rounded": Icons.align_horizontal_left_rounded, - "align_horizontal_left_outlined": Icons.align_horizontal_left_outlined, - "align_horizontal_right": Icons.align_horizontal_right, - "align_horizontal_right_sharp": Icons.align_horizontal_right_sharp, - "align_horizontal_right_rounded": Icons.align_horizontal_right_rounded, - "align_horizontal_right_outlined": Icons.align_horizontal_right_outlined, - "align_vertical_bottom": Icons.align_vertical_bottom, - "align_vertical_bottom_sharp": Icons.align_vertical_bottom_sharp, - "align_vertical_bottom_rounded": Icons.align_vertical_bottom_rounded, - "align_vertical_bottom_outlined": Icons.align_vertical_bottom_outlined, - "align_vertical_center": Icons.align_vertical_center, - "align_vertical_center_sharp": Icons.align_vertical_center_sharp, - "align_vertical_center_rounded": Icons.align_vertical_center_rounded, - "align_vertical_center_outlined": Icons.align_vertical_center_outlined, - "align_vertical_top": Icons.align_vertical_top, - "align_vertical_top_sharp": Icons.align_vertical_top_sharp, - "align_vertical_top_rounded": Icons.align_vertical_top_rounded, - "align_vertical_top_outlined": Icons.align_vertical_top_outlined, - "all_inbox": Icons.all_inbox, - "all_inbox_sharp": Icons.all_inbox_sharp, - "all_inbox_rounded": Icons.all_inbox_rounded, - "all_inbox_outlined": Icons.all_inbox_outlined, - "all_inclusive": Icons.all_inclusive, - "all_inclusive_sharp": Icons.all_inclusive_sharp, - "all_inclusive_rounded": Icons.all_inclusive_rounded, - "all_inclusive_outlined": Icons.all_inclusive_outlined, - "all_out": Icons.all_out, - "all_out_sharp": Icons.all_out_sharp, - "all_out_rounded": Icons.all_out_rounded, - "all_out_outlined": Icons.all_out_outlined, - "alt_route": Icons.alt_route, - "alt_route_sharp": Icons.alt_route_sharp, - "alt_route_rounded": Icons.alt_route_rounded, - "alt_route_outlined": Icons.alt_route_outlined, - "alternate_email": Icons.alternate_email, - "alternate_email_sharp": Icons.alternate_email_sharp, - "alternate_email_rounded": Icons.alternate_email_rounded, - "alternate_email_outlined": Icons.alternate_email_outlined, - "amp_stories": Icons.amp_stories, - "amp_stories_sharp": Icons.amp_stories_sharp, - "amp_stories_rounded": Icons.amp_stories_rounded, - "amp_stories_outlined": Icons.amp_stories_outlined, - "analytics": Icons.analytics, - "analytics_sharp": Icons.analytics_sharp, - "analytics_rounded": Icons.analytics_rounded, - "analytics_outlined": Icons.analytics_outlined, - "anchor": Icons.anchor, - "anchor_sharp": Icons.anchor_sharp, - "anchor_rounded": Icons.anchor_rounded, - "anchor_outlined": Icons.anchor_outlined, - "android": Icons.android, - "android_sharp": Icons.android_sharp, - "android_rounded": Icons.android_rounded, - "android_outlined": Icons.android_outlined, - "animation": Icons.animation, - "animation_sharp": Icons.animation_sharp, - "animation_rounded": Icons.animation_rounded, - "animation_outlined": Icons.animation_outlined, - "announcement": Icons.announcement, - "announcement_sharp": Icons.announcement_sharp, - "announcement_rounded": Icons.announcement_rounded, - "announcement_outlined": Icons.announcement_outlined, - "aod": Icons.aod, - "aod_sharp": Icons.aod_sharp, - "aod_rounded": Icons.aod_rounded, - "aod_outlined": Icons.aod_outlined, - "apartment": Icons.apartment, - "apartment_sharp": Icons.apartment_sharp, - "apartment_rounded": Icons.apartment_rounded, - "apartment_outlined": Icons.apartment_outlined, - "api": Icons.api, - "api_sharp": Icons.api_sharp, - "api_rounded": Icons.api_rounded, - "api_outlined": Icons.api_outlined, - "app_blocking": Icons.app_blocking, - "app_blocking_sharp": Icons.app_blocking_sharp, - "app_blocking_rounded": Icons.app_blocking_rounded, - "app_blocking_outlined": Icons.app_blocking_outlined, - "app_registration": Icons.app_registration, - "app_registration_sharp": Icons.app_registration_sharp, - "app_registration_rounded": Icons.app_registration_rounded, - "app_registration_outlined": Icons.app_registration_outlined, - "app_settings_alt": Icons.app_settings_alt, - "app_settings_alt_sharp": Icons.app_settings_alt_sharp, - "app_settings_alt_rounded": Icons.app_settings_alt_rounded, - "app_settings_alt_outlined": Icons.app_settings_alt_outlined, - "app_shortcut": Icons.app_shortcut, - "app_shortcut_sharp": Icons.app_shortcut_sharp, - "app_shortcut_rounded": Icons.app_shortcut_rounded, - "app_shortcut_outlined": Icons.app_shortcut_outlined, - "apple": Icons.apple, - "apple_sharp": Icons.apple_sharp, - "apple_rounded": Icons.apple_rounded, - "apple_outlined": Icons.apple_outlined, - "approval": Icons.approval, - "approval_sharp": Icons.approval_sharp, - "approval_rounded": Icons.approval_rounded, - "approval_outlined": Icons.approval_outlined, - "apps": Icons.apps, - "apps_sharp": Icons.apps_sharp, - "apps_rounded": Icons.apps_rounded, - "apps_outlined": Icons.apps_outlined, - "apps_outage": Icons.apps_outage, - "apps_outage_sharp": Icons.apps_outage_sharp, - "apps_outage_rounded": Icons.apps_outage_rounded, - "apps_outage_outlined": Icons.apps_outage_outlined, - "architecture": Icons.architecture, - "architecture_sharp": Icons.architecture_sharp, - "architecture_rounded": Icons.architecture_rounded, - "architecture_outlined": Icons.architecture_outlined, - "archive": Icons.archive, - "archive_sharp": Icons.archive_sharp, - "archive_rounded": Icons.archive_rounded, - "archive_outlined": Icons.archive_outlined, - "area_chart": Icons.area_chart, - "area_chart_sharp": Icons.area_chart_sharp, - "area_chart_rounded": Icons.area_chart_rounded, - "area_chart_outlined": Icons.area_chart_outlined, - "arrow_back": Icons.arrow_back, - "arrow_back_sharp": Icons.arrow_back_sharp, - "arrow_back_rounded": Icons.arrow_back_rounded, - "arrow_back_outlined": Icons.arrow_back_outlined, - "arrow_back_ios": Icons.arrow_back_ios, - "arrow_back_ios_sharp": Icons.arrow_back_ios_sharp, - "arrow_back_ios_rounded": Icons.arrow_back_ios_rounded, - "arrow_back_ios_outlined": Icons.arrow_back_ios_outlined, - "arrow_back_ios_new": Icons.arrow_back_ios_new, - "arrow_back_ios_new_sharp": Icons.arrow_back_ios_new_sharp, - "arrow_back_ios_new_rounded": Icons.arrow_back_ios_new_rounded, - "arrow_back_ios_new_outlined": Icons.arrow_back_ios_new_outlined, - "arrow_circle_down": Icons.arrow_circle_down, - "arrow_circle_down_sharp": Icons.arrow_circle_down_sharp, - "arrow_circle_down_rounded": Icons.arrow_circle_down_rounded, - "arrow_circle_down_outlined": Icons.arrow_circle_down_outlined, - "arrow_circle_left": Icons.arrow_circle_left, - "arrow_circle_left_sharp": Icons.arrow_circle_left_sharp, - "arrow_circle_left_rounded": Icons.arrow_circle_left_rounded, - "arrow_circle_left_outlined": Icons.arrow_circle_left_outlined, - "arrow_circle_right": Icons.arrow_circle_right, - "arrow_circle_right_sharp": Icons.arrow_circle_right_sharp, - "arrow_circle_right_rounded": Icons.arrow_circle_right_rounded, - "arrow_circle_right_outlined": Icons.arrow_circle_right_outlined, - "arrow_circle_up": Icons.arrow_circle_up, - "arrow_circle_up_sharp": Icons.arrow_circle_up_sharp, - "arrow_circle_up_rounded": Icons.arrow_circle_up_rounded, - "arrow_circle_up_outlined": Icons.arrow_circle_up_outlined, - "arrow_downward": Icons.arrow_downward, - "arrow_downward_sharp": Icons.arrow_downward_sharp, - "arrow_downward_rounded": Icons.arrow_downward_rounded, - "arrow_downward_outlined": Icons.arrow_downward_outlined, - "arrow_drop_down": Icons.arrow_drop_down, - "arrow_drop_down_sharp": Icons.arrow_drop_down_sharp, - "arrow_drop_down_rounded": Icons.arrow_drop_down_rounded, - "arrow_drop_down_outlined": Icons.arrow_drop_down_outlined, - "arrow_drop_down_circle": Icons.arrow_drop_down_circle, - "arrow_drop_down_circle_sharp": Icons.arrow_drop_down_circle_sharp, - "arrow_drop_down_circle_rounded": Icons.arrow_drop_down_circle_rounded, - "arrow_drop_down_circle_outlined": Icons.arrow_drop_down_circle_outlined, - "arrow_drop_up": Icons.arrow_drop_up, - "arrow_drop_up_sharp": Icons.arrow_drop_up_sharp, - "arrow_drop_up_rounded": Icons.arrow_drop_up_rounded, - "arrow_drop_up_outlined": Icons.arrow_drop_up_outlined, - "arrow_forward": Icons.arrow_forward, - "arrow_forward_sharp": Icons.arrow_forward_sharp, - "arrow_forward_rounded": Icons.arrow_forward_rounded, - "arrow_forward_outlined": Icons.arrow_forward_outlined, - "arrow_forward_ios": Icons.arrow_forward_ios, - "arrow_forward_ios_sharp": Icons.arrow_forward_ios_sharp, - "arrow_forward_ios_rounded": Icons.arrow_forward_ios_rounded, - "arrow_forward_ios_outlined": Icons.arrow_forward_ios_outlined, - "arrow_left": Icons.arrow_left, - "arrow_left_sharp": Icons.arrow_left_sharp, - "arrow_left_rounded": Icons.arrow_left_rounded, - "arrow_left_outlined": Icons.arrow_left_outlined, - "arrow_outward": Icons.arrow_outward, - "arrow_outward_sharp": Icons.arrow_outward_sharp, - "arrow_outward_rounded": Icons.arrow_outward_rounded, - "arrow_outward_outlined": Icons.arrow_outward_outlined, - "arrow_right": Icons.arrow_right, - "arrow_right_sharp": Icons.arrow_right_sharp, - "arrow_right_rounded": Icons.arrow_right_rounded, - "arrow_right_outlined": Icons.arrow_right_outlined, - "arrow_right_alt": Icons.arrow_right_alt, - "arrow_right_alt_sharp": Icons.arrow_right_alt_sharp, - "arrow_right_alt_rounded": Icons.arrow_right_alt_rounded, - "arrow_right_alt_outlined": Icons.arrow_right_alt_outlined, - "arrow_upward": Icons.arrow_upward, - "arrow_upward_sharp": Icons.arrow_upward_sharp, - "arrow_upward_rounded": Icons.arrow_upward_rounded, - "arrow_upward_outlined": Icons.arrow_upward_outlined, - "art_track": Icons.art_track, - "art_track_sharp": Icons.art_track_sharp, - "art_track_rounded": Icons.art_track_rounded, - "art_track_outlined": Icons.art_track_outlined, - "article": Icons.article, - "article_sharp": Icons.article_sharp, - "article_rounded": Icons.article_rounded, - "article_outlined": Icons.article_outlined, - "aspect_ratio": Icons.aspect_ratio, - "aspect_ratio_sharp": Icons.aspect_ratio_sharp, - "aspect_ratio_rounded": Icons.aspect_ratio_rounded, - "aspect_ratio_outlined": Icons.aspect_ratio_outlined, - "assessment": Icons.assessment, - "assessment_sharp": Icons.assessment_sharp, - "assessment_rounded": Icons.assessment_rounded, - "assessment_outlined": Icons.assessment_outlined, - "assignment": Icons.assignment, - "assignment_sharp": Icons.assignment_sharp, - "assignment_rounded": Icons.assignment_rounded, - "assignment_outlined": Icons.assignment_outlined, - "assignment_add": Icons.assignment_add, - "assignment_ind": Icons.assignment_ind, - "assignment_ind_sharp": Icons.assignment_ind_sharp, - "assignment_ind_rounded": Icons.assignment_ind_rounded, - "assignment_ind_outlined": Icons.assignment_ind_outlined, - "assignment_late": Icons.assignment_late, - "assignment_late_sharp": Icons.assignment_late_sharp, - "assignment_late_rounded": Icons.assignment_late_rounded, - "assignment_late_outlined": Icons.assignment_late_outlined, - "assignment_return": Icons.assignment_return, - "assignment_return_sharp": Icons.assignment_return_sharp, - "assignment_return_rounded": Icons.assignment_return_rounded, - "assignment_return_outlined": Icons.assignment_return_outlined, - "assignment_returned": Icons.assignment_returned, - "assignment_returned_sharp": Icons.assignment_returned_sharp, - "assignment_returned_rounded": Icons.assignment_returned_rounded, - "assignment_returned_outlined": Icons.assignment_returned_outlined, - "assignment_turned_in": Icons.assignment_turned_in, - "assignment_turned_in_sharp": Icons.assignment_turned_in_sharp, - "assignment_turned_in_rounded": Icons.assignment_turned_in_rounded, - "assignment_turned_in_outlined": Icons.assignment_turned_in_outlined, - "assist_walker": Icons.assist_walker, - "assist_walker_sharp": Icons.assist_walker_sharp, - "assist_walker_rounded": Icons.assist_walker_rounded, - "assist_walker_outlined": Icons.assist_walker_outlined, - "assistant": Icons.assistant, - "assistant_sharp": Icons.assistant_sharp, - "assistant_rounded": Icons.assistant_rounded, - "assistant_outlined": Icons.assistant_outlined, - "assistant_direction": Icons.assistant_direction, - "assistant_direction_sharp": Icons.assistant_direction_sharp, - "assistant_direction_rounded": Icons.assistant_direction_rounded, - "assistant_direction_outlined": Icons.assistant_direction_outlined, - "assistant_navigation": Icons.assistant_navigation, - "assistant_photo": Icons.assistant_photo, - "assistant_photo_sharp": Icons.assistant_photo_sharp, - "assistant_photo_rounded": Icons.assistant_photo_rounded, - "assistant_photo_outlined": Icons.assistant_photo_outlined, - "assured_workload": Icons.assured_workload, - "assured_workload_sharp": Icons.assured_workload_sharp, - "assured_workload_rounded": Icons.assured_workload_rounded, - "assured_workload_outlined": Icons.assured_workload_outlined, - "atm": Icons.atm, - "atm_sharp": Icons.atm_sharp, - "atm_rounded": Icons.atm_rounded, - "atm_outlined": Icons.atm_outlined, - "attach_email": Icons.attach_email, - "attach_email_sharp": Icons.attach_email_sharp, - "attach_email_rounded": Icons.attach_email_rounded, - "attach_email_outlined": Icons.attach_email_outlined, - "attach_file": Icons.attach_file, - "attach_file_sharp": Icons.attach_file_sharp, - "attach_file_rounded": Icons.attach_file_rounded, - "attach_file_outlined": Icons.attach_file_outlined, - "attach_money": Icons.attach_money, - "attach_money_sharp": Icons.attach_money_sharp, - "attach_money_rounded": Icons.attach_money_rounded, - "attach_money_outlined": Icons.attach_money_outlined, - "attachment": Icons.attachment, - "attachment_sharp": Icons.attachment_sharp, - "attachment_rounded": Icons.attachment_rounded, - "attachment_outlined": Icons.attachment_outlined, - "attractions": Icons.attractions, - "attractions_sharp": Icons.attractions_sharp, - "attractions_rounded": Icons.attractions_rounded, - "attractions_outlined": Icons.attractions_outlined, - "attribution": Icons.attribution, - "attribution_sharp": Icons.attribution_sharp, - "attribution_rounded": Icons.attribution_rounded, - "attribution_outlined": Icons.attribution_outlined, - "audio_file": Icons.audio_file, - "audio_file_sharp": Icons.audio_file_sharp, - "audio_file_rounded": Icons.audio_file_rounded, - "audio_file_outlined": Icons.audio_file_outlined, - "audiotrack": Icons.audiotrack, - "audiotrack_sharp": Icons.audiotrack_sharp, - "audiotrack_rounded": Icons.audiotrack_rounded, - "audiotrack_outlined": Icons.audiotrack_outlined, - "auto_awesome": Icons.auto_awesome, - "auto_awesome_sharp": Icons.auto_awesome_sharp, - "auto_awesome_rounded": Icons.auto_awesome_rounded, - "auto_awesome_outlined": Icons.auto_awesome_outlined, - "auto_awesome_mosaic": Icons.auto_awesome_mosaic, - "auto_awesome_mosaic_sharp": Icons.auto_awesome_mosaic_sharp, - "auto_awesome_mosaic_rounded": Icons.auto_awesome_mosaic_rounded, - "auto_awesome_mosaic_outlined": Icons.auto_awesome_mosaic_outlined, - "auto_awesome_motion": Icons.auto_awesome_motion, - "auto_awesome_motion_sharp": Icons.auto_awesome_motion_sharp, - "auto_awesome_motion_rounded": Icons.auto_awesome_motion_rounded, - "auto_awesome_motion_outlined": Icons.auto_awesome_motion_outlined, - "auto_delete": Icons.auto_delete, - "auto_delete_sharp": Icons.auto_delete_sharp, - "auto_delete_rounded": Icons.auto_delete_rounded, - "auto_delete_outlined": Icons.auto_delete_outlined, - "auto_fix_high": Icons.auto_fix_high, - "auto_fix_high_sharp": Icons.auto_fix_high_sharp, - "auto_fix_high_rounded": Icons.auto_fix_high_rounded, - "auto_fix_high_outlined": Icons.auto_fix_high_outlined, - "auto_fix_normal": Icons.auto_fix_normal, - "auto_fix_normal_sharp": Icons.auto_fix_normal_sharp, - "auto_fix_normal_rounded": Icons.auto_fix_normal_rounded, - "auto_fix_normal_outlined": Icons.auto_fix_normal_outlined, - "auto_fix_off": Icons.auto_fix_off, - "auto_fix_off_sharp": Icons.auto_fix_off_sharp, - "auto_fix_off_rounded": Icons.auto_fix_off_rounded, - "auto_fix_off_outlined": Icons.auto_fix_off_outlined, - "auto_graph": Icons.auto_graph, - "auto_graph_sharp": Icons.auto_graph_sharp, - "auto_graph_rounded": Icons.auto_graph_rounded, - "auto_graph_outlined": Icons.auto_graph_outlined, - "auto_mode": Icons.auto_mode, - "auto_mode_sharp": Icons.auto_mode_sharp, - "auto_mode_rounded": Icons.auto_mode_rounded, - "auto_mode_outlined": Icons.auto_mode_outlined, - "auto_stories": Icons.auto_stories, - "auto_stories_sharp": Icons.auto_stories_sharp, - "auto_stories_rounded": Icons.auto_stories_rounded, - "auto_stories_outlined": Icons.auto_stories_outlined, - "autofps_select": Icons.autofps_select, - "autofps_select_sharp": Icons.autofps_select_sharp, - "autofps_select_rounded": Icons.autofps_select_rounded, - "autofps_select_outlined": Icons.autofps_select_outlined, - "autorenew": Icons.autorenew, - "autorenew_sharp": Icons.autorenew_sharp, - "autorenew_rounded": Icons.autorenew_rounded, - "autorenew_outlined": Icons.autorenew_outlined, - "av_timer": Icons.av_timer, - "av_timer_sharp": Icons.av_timer_sharp, - "av_timer_rounded": Icons.av_timer_rounded, - "av_timer_outlined": Icons.av_timer_outlined, - "baby_changing_station": Icons.baby_changing_station, - "baby_changing_station_sharp": Icons.baby_changing_station_sharp, - "baby_changing_station_rounded": Icons.baby_changing_station_rounded, - "baby_changing_station_outlined": Icons.baby_changing_station_outlined, - "back_hand": Icons.back_hand, - "back_hand_sharp": Icons.back_hand_sharp, - "back_hand_rounded": Icons.back_hand_rounded, - "back_hand_outlined": Icons.back_hand_outlined, - "backpack": Icons.backpack, - "backpack_sharp": Icons.backpack_sharp, - "backpack_rounded": Icons.backpack_rounded, - "backpack_outlined": Icons.backpack_outlined, - "backspace": Icons.backspace, - "backspace_sharp": Icons.backspace_sharp, - "backspace_rounded": Icons.backspace_rounded, - "backspace_outlined": Icons.backspace_outlined, - "backup": Icons.backup, - "backup_sharp": Icons.backup_sharp, - "backup_rounded": Icons.backup_rounded, - "backup_outlined": Icons.backup_outlined, - "backup_table": Icons.backup_table, - "backup_table_sharp": Icons.backup_table_sharp, - "backup_table_rounded": Icons.backup_table_rounded, - "backup_table_outlined": Icons.backup_table_outlined, - "badge": Icons.badge, - "badge_sharp": Icons.badge_sharp, - "badge_rounded": Icons.badge_rounded, - "badge_outlined": Icons.badge_outlined, - "bakery_dining": Icons.bakery_dining, - "bakery_dining_sharp": Icons.bakery_dining_sharp, - "bakery_dining_rounded": Icons.bakery_dining_rounded, - "bakery_dining_outlined": Icons.bakery_dining_outlined, - "balance": Icons.balance, - "balance_sharp": Icons.balance_sharp, - "balance_rounded": Icons.balance_rounded, - "balance_outlined": Icons.balance_outlined, - "balcony": Icons.balcony, - "balcony_sharp": Icons.balcony_sharp, - "balcony_rounded": Icons.balcony_rounded, - "balcony_outlined": Icons.balcony_outlined, - "ballot": Icons.ballot, - "ballot_sharp": Icons.ballot_sharp, - "ballot_rounded": Icons.ballot_rounded, - "ballot_outlined": Icons.ballot_outlined, - "bar_chart": Icons.bar_chart, - "bar_chart_sharp": Icons.bar_chart_sharp, - "bar_chart_rounded": Icons.bar_chart_rounded, - "bar_chart_outlined": Icons.bar_chart_outlined, - "barcode_reader": Icons.barcode_reader, - "batch_prediction": Icons.batch_prediction, - "batch_prediction_sharp": Icons.batch_prediction_sharp, - "batch_prediction_rounded": Icons.batch_prediction_rounded, - "batch_prediction_outlined": Icons.batch_prediction_outlined, - "bathroom": Icons.bathroom, - "bathroom_sharp": Icons.bathroom_sharp, - "bathroom_rounded": Icons.bathroom_rounded, - "bathroom_outlined": Icons.bathroom_outlined, - "bathtub": Icons.bathtub, - "bathtub_sharp": Icons.bathtub_sharp, - "bathtub_rounded": Icons.bathtub_rounded, - "bathtub_outlined": Icons.bathtub_outlined, - "battery_0_bar": Icons.battery_0_bar, - "battery_0_bar_sharp": Icons.battery_0_bar_sharp, - "battery_0_bar_rounded": Icons.battery_0_bar_rounded, - "battery_0_bar_outlined": Icons.battery_0_bar_outlined, - "battery_1_bar": Icons.battery_1_bar, - "battery_1_bar_sharp": Icons.battery_1_bar_sharp, - "battery_1_bar_rounded": Icons.battery_1_bar_rounded, - "battery_1_bar_outlined": Icons.battery_1_bar_outlined, - "battery_2_bar": Icons.battery_2_bar, - "battery_2_bar_sharp": Icons.battery_2_bar_sharp, - "battery_2_bar_rounded": Icons.battery_2_bar_rounded, - "battery_2_bar_outlined": Icons.battery_2_bar_outlined, - "battery_3_bar": Icons.battery_3_bar, - "battery_3_bar_sharp": Icons.battery_3_bar_sharp, - "battery_3_bar_rounded": Icons.battery_3_bar_rounded, - "battery_3_bar_outlined": Icons.battery_3_bar_outlined, - "battery_4_bar": Icons.battery_4_bar, - "battery_4_bar_sharp": Icons.battery_4_bar_sharp, - "battery_4_bar_rounded": Icons.battery_4_bar_rounded, - "battery_4_bar_outlined": Icons.battery_4_bar_outlined, - "battery_5_bar": Icons.battery_5_bar, - "battery_5_bar_sharp": Icons.battery_5_bar_sharp, - "battery_5_bar_rounded": Icons.battery_5_bar_rounded, - "battery_5_bar_outlined": Icons.battery_5_bar_outlined, - "battery_6_bar": Icons.battery_6_bar, - "battery_6_bar_sharp": Icons.battery_6_bar_sharp, - "battery_6_bar_rounded": Icons.battery_6_bar_rounded, - "battery_6_bar_outlined": Icons.battery_6_bar_outlined, - "battery_alert": Icons.battery_alert, - "battery_alert_sharp": Icons.battery_alert_sharp, - "battery_alert_rounded": Icons.battery_alert_rounded, - "battery_alert_outlined": Icons.battery_alert_outlined, - "battery_charging_full": Icons.battery_charging_full, - "battery_charging_full_sharp": Icons.battery_charging_full_sharp, - "battery_charging_full_rounded": Icons.battery_charging_full_rounded, - "battery_charging_full_outlined": Icons.battery_charging_full_outlined, - "battery_full": Icons.battery_full, - "battery_full_sharp": Icons.battery_full_sharp, - "battery_full_rounded": Icons.battery_full_rounded, - "battery_full_outlined": Icons.battery_full_outlined, - "battery_saver": Icons.battery_saver, - "battery_saver_sharp": Icons.battery_saver_sharp, - "battery_saver_rounded": Icons.battery_saver_rounded, - "battery_saver_outlined": Icons.battery_saver_outlined, - "battery_std": Icons.battery_std, - "battery_std_sharp": Icons.battery_std_sharp, - "battery_std_rounded": Icons.battery_std_rounded, - "battery_std_outlined": Icons.battery_std_outlined, - "battery_unknown": Icons.battery_unknown, - "battery_unknown_sharp": Icons.battery_unknown_sharp, - "battery_unknown_rounded": Icons.battery_unknown_rounded, - "battery_unknown_outlined": Icons.battery_unknown_outlined, - "beach_access": Icons.beach_access, - "beach_access_sharp": Icons.beach_access_sharp, - "beach_access_rounded": Icons.beach_access_rounded, - "beach_access_outlined": Icons.beach_access_outlined, - "bed": Icons.bed, - "bed_sharp": Icons.bed_sharp, - "bed_rounded": Icons.bed_rounded, - "bed_outlined": Icons.bed_outlined, - "bedroom_baby": Icons.bedroom_baby, - "bedroom_baby_sharp": Icons.bedroom_baby_sharp, - "bedroom_baby_rounded": Icons.bedroom_baby_rounded, - "bedroom_baby_outlined": Icons.bedroom_baby_outlined, - "bedroom_child": Icons.bedroom_child, - "bedroom_child_sharp": Icons.bedroom_child_sharp, - "bedroom_child_rounded": Icons.bedroom_child_rounded, - "bedroom_child_outlined": Icons.bedroom_child_outlined, - "bedroom_parent": Icons.bedroom_parent, - "bedroom_parent_sharp": Icons.bedroom_parent_sharp, - "bedroom_parent_rounded": Icons.bedroom_parent_rounded, - "bedroom_parent_outlined": Icons.bedroom_parent_outlined, - "bedtime": Icons.bedtime, - "bedtime_sharp": Icons.bedtime_sharp, - "bedtime_rounded": Icons.bedtime_rounded, - "bedtime_outlined": Icons.bedtime_outlined, - "bedtime_off": Icons.bedtime_off, - "bedtime_off_sharp": Icons.bedtime_off_sharp, - "bedtime_off_rounded": Icons.bedtime_off_rounded, - "bedtime_off_outlined": Icons.bedtime_off_outlined, - "beenhere": Icons.beenhere, - "beenhere_sharp": Icons.beenhere_sharp, - "beenhere_rounded": Icons.beenhere_rounded, - "beenhere_outlined": Icons.beenhere_outlined, - "bento": Icons.bento, - "bento_sharp": Icons.bento_sharp, - "bento_rounded": Icons.bento_rounded, - "bento_outlined": Icons.bento_outlined, - "bike_scooter": Icons.bike_scooter, - "bike_scooter_sharp": Icons.bike_scooter_sharp, - "bike_scooter_rounded": Icons.bike_scooter_rounded, - "bike_scooter_outlined": Icons.bike_scooter_outlined, - "biotech": Icons.biotech, - "biotech_sharp": Icons.biotech_sharp, - "biotech_rounded": Icons.biotech_rounded, - "biotech_outlined": Icons.biotech_outlined, - "blender": Icons.blender, - "blender_sharp": Icons.blender_sharp, - "blender_rounded": Icons.blender_rounded, - "blender_outlined": Icons.blender_outlined, - "blind": Icons.blind, - "blind_sharp": Icons.blind_sharp, - "blind_rounded": Icons.blind_rounded, - "blind_outlined": Icons.blind_outlined, - "blinds": Icons.blinds, - "blinds_sharp": Icons.blinds_sharp, - "blinds_rounded": Icons.blinds_rounded, - "blinds_outlined": Icons.blinds_outlined, - "blinds_closed": Icons.blinds_closed, - "blinds_closed_sharp": Icons.blinds_closed_sharp, - "blinds_closed_rounded": Icons.blinds_closed_rounded, - "blinds_closed_outlined": Icons.blinds_closed_outlined, - "block": Icons.block, - "block_sharp": Icons.block_sharp, - "block_rounded": Icons.block_rounded, - "block_outlined": Icons.block_outlined, - "block_flipped": Icons.block_flipped, - "bloodtype": Icons.bloodtype, - "bloodtype_sharp": Icons.bloodtype_sharp, - "bloodtype_rounded": Icons.bloodtype_rounded, - "bloodtype_outlined": Icons.bloodtype_outlined, - "bluetooth": Icons.bluetooth, - "bluetooth_sharp": Icons.bluetooth_sharp, - "bluetooth_rounded": Icons.bluetooth_rounded, - "bluetooth_outlined": Icons.bluetooth_outlined, - "bluetooth_audio": Icons.bluetooth_audio, - "bluetooth_audio_sharp": Icons.bluetooth_audio_sharp, - "bluetooth_audio_rounded": Icons.bluetooth_audio_rounded, - "bluetooth_audio_outlined": Icons.bluetooth_audio_outlined, - "bluetooth_connected": Icons.bluetooth_connected, - "bluetooth_connected_sharp": Icons.bluetooth_connected_sharp, - "bluetooth_connected_rounded": Icons.bluetooth_connected_rounded, - "bluetooth_connected_outlined": Icons.bluetooth_connected_outlined, - "bluetooth_disabled": Icons.bluetooth_disabled, - "bluetooth_disabled_sharp": Icons.bluetooth_disabled_sharp, - "bluetooth_disabled_rounded": Icons.bluetooth_disabled_rounded, - "bluetooth_disabled_outlined": Icons.bluetooth_disabled_outlined, - "bluetooth_drive": Icons.bluetooth_drive, - "bluetooth_drive_sharp": Icons.bluetooth_drive_sharp, - "bluetooth_drive_rounded": Icons.bluetooth_drive_rounded, - "bluetooth_drive_outlined": Icons.bluetooth_drive_outlined, - "bluetooth_searching": Icons.bluetooth_searching, - "bluetooth_searching_sharp": Icons.bluetooth_searching_sharp, - "bluetooth_searching_rounded": Icons.bluetooth_searching_rounded, - "bluetooth_searching_outlined": Icons.bluetooth_searching_outlined, - "blur_circular": Icons.blur_circular, - "blur_circular_sharp": Icons.blur_circular_sharp, - "blur_circular_rounded": Icons.blur_circular_rounded, - "blur_circular_outlined": Icons.blur_circular_outlined, - "blur_linear": Icons.blur_linear, - "blur_linear_sharp": Icons.blur_linear_sharp, - "blur_linear_rounded": Icons.blur_linear_rounded, - "blur_linear_outlined": Icons.blur_linear_outlined, - "blur_off": Icons.blur_off, - "blur_off_sharp": Icons.blur_off_sharp, - "blur_off_rounded": Icons.blur_off_rounded, - "blur_off_outlined": Icons.blur_off_outlined, - "blur_on": Icons.blur_on, - "blur_on_sharp": Icons.blur_on_sharp, - "blur_on_rounded": Icons.blur_on_rounded, - "blur_on_outlined": Icons.blur_on_outlined, - "bolt": Icons.bolt, - "bolt_sharp": Icons.bolt_sharp, - "bolt_rounded": Icons.bolt_rounded, - "bolt_outlined": Icons.bolt_outlined, - "book": Icons.book, - "book_sharp": Icons.book_sharp, - "book_rounded": Icons.book_rounded, - "book_outlined": Icons.book_outlined, - "book_online": Icons.book_online, - "book_online_sharp": Icons.book_online_sharp, - "book_online_rounded": Icons.book_online_rounded, - "book_online_outlined": Icons.book_online_outlined, - "bookmark": Icons.bookmark, - "bookmark_sharp": Icons.bookmark_sharp, - "bookmark_rounded": Icons.bookmark_rounded, - "bookmark_outlined": Icons.bookmark_outlined, - "bookmark_add": Icons.bookmark_add, - "bookmark_add_sharp": Icons.bookmark_add_sharp, - "bookmark_add_rounded": Icons.bookmark_add_rounded, - "bookmark_add_outlined": Icons.bookmark_add_outlined, - "bookmark_added": Icons.bookmark_added, - "bookmark_added_sharp": Icons.bookmark_added_sharp, - "bookmark_added_rounded": Icons.bookmark_added_rounded, - "bookmark_added_outlined": Icons.bookmark_added_outlined, - "bookmark_border": Icons.bookmark_border, - "bookmark_border_sharp": Icons.bookmark_border_sharp, - "bookmark_border_rounded": Icons.bookmark_border_rounded, - "bookmark_border_outlined": Icons.bookmark_border_outlined, - "bookmark_outline": Icons.bookmark_outline, - "bookmark_outline_sharp": Icons.bookmark_outline_sharp, - "bookmark_outline_rounded": Icons.bookmark_outline_rounded, - "bookmark_outline_outlined": Icons.bookmark_outline_outlined, - "bookmark_remove": Icons.bookmark_remove, - "bookmark_remove_sharp": Icons.bookmark_remove_sharp, - "bookmark_remove_rounded": Icons.bookmark_remove_rounded, - "bookmark_remove_outlined": Icons.bookmark_remove_outlined, - "bookmarks": Icons.bookmarks, - "bookmarks_sharp": Icons.bookmarks_sharp, - "bookmarks_rounded": Icons.bookmarks_rounded, - "bookmarks_outlined": Icons.bookmarks_outlined, - "border_all": Icons.border_all, - "border_all_sharp": Icons.border_all_sharp, - "border_all_rounded": Icons.border_all_rounded, - "border_all_outlined": Icons.border_all_outlined, - "border_bottom": Icons.border_bottom, - "border_bottom_sharp": Icons.border_bottom_sharp, - "border_bottom_rounded": Icons.border_bottom_rounded, - "border_bottom_outlined": Icons.border_bottom_outlined, - "border_clear": Icons.border_clear, - "border_clear_sharp": Icons.border_clear_sharp, - "border_clear_rounded": Icons.border_clear_rounded, - "border_clear_outlined": Icons.border_clear_outlined, - "border_color": Icons.border_color, - "border_color_sharp": Icons.border_color_sharp, - "border_color_rounded": Icons.border_color_rounded, - "border_color_outlined": Icons.border_color_outlined, - "border_horizontal": Icons.border_horizontal, - "border_horizontal_sharp": Icons.border_horizontal_sharp, - "border_horizontal_rounded": Icons.border_horizontal_rounded, - "border_horizontal_outlined": Icons.border_horizontal_outlined, - "border_inner": Icons.border_inner, - "border_inner_sharp": Icons.border_inner_sharp, - "border_inner_rounded": Icons.border_inner_rounded, - "border_inner_outlined": Icons.border_inner_outlined, - "border_left": Icons.border_left, - "border_left_sharp": Icons.border_left_sharp, - "border_left_rounded": Icons.border_left_rounded, - "border_left_outlined": Icons.border_left_outlined, - "border_outer": Icons.border_outer, - "border_outer_sharp": Icons.border_outer_sharp, - "border_outer_rounded": Icons.border_outer_rounded, - "border_outer_outlined": Icons.border_outer_outlined, - "border_right": Icons.border_right, - "border_right_sharp": Icons.border_right_sharp, - "border_right_rounded": Icons.border_right_rounded, - "border_right_outlined": Icons.border_right_outlined, - "border_style": Icons.border_style, - "border_style_sharp": Icons.border_style_sharp, - "border_style_rounded": Icons.border_style_rounded, - "border_style_outlined": Icons.border_style_outlined, - "border_top": Icons.border_top, - "border_top_sharp": Icons.border_top_sharp, - "border_top_rounded": Icons.border_top_rounded, - "border_top_outlined": Icons.border_top_outlined, - "border_vertical": Icons.border_vertical, - "border_vertical_sharp": Icons.border_vertical_sharp, - "border_vertical_rounded": Icons.border_vertical_rounded, - "border_vertical_outlined": Icons.border_vertical_outlined, - "boy": Icons.boy, - "boy_sharp": Icons.boy_sharp, - "boy_rounded": Icons.boy_rounded, - "boy_outlined": Icons.boy_outlined, - "branding_watermark": Icons.branding_watermark, - "branding_watermark_sharp": Icons.branding_watermark_sharp, - "branding_watermark_rounded": Icons.branding_watermark_rounded, - "branding_watermark_outlined": Icons.branding_watermark_outlined, - "breakfast_dining": Icons.breakfast_dining, - "breakfast_dining_sharp": Icons.breakfast_dining_sharp, - "breakfast_dining_rounded": Icons.breakfast_dining_rounded, - "breakfast_dining_outlined": Icons.breakfast_dining_outlined, - "brightness_1": Icons.brightness_1, - "brightness_1_sharp": Icons.brightness_1_sharp, - "brightness_1_rounded": Icons.brightness_1_rounded, - "brightness_1_outlined": Icons.brightness_1_outlined, - "brightness_2": Icons.brightness_2, - "brightness_2_sharp": Icons.brightness_2_sharp, - "brightness_2_rounded": Icons.brightness_2_rounded, - "brightness_2_outlined": Icons.brightness_2_outlined, - "brightness_3": Icons.brightness_3, - "brightness_3_sharp": Icons.brightness_3_sharp, - "brightness_3_rounded": Icons.brightness_3_rounded, - "brightness_3_outlined": Icons.brightness_3_outlined, - "brightness_4": Icons.brightness_4, - "brightness_4_sharp": Icons.brightness_4_sharp, - "brightness_4_rounded": Icons.brightness_4_rounded, - "brightness_4_outlined": Icons.brightness_4_outlined, - "brightness_5": Icons.brightness_5, - "brightness_5_sharp": Icons.brightness_5_sharp, - "brightness_5_rounded": Icons.brightness_5_rounded, - "brightness_5_outlined": Icons.brightness_5_outlined, - "brightness_6": Icons.brightness_6, - "brightness_6_sharp": Icons.brightness_6_sharp, - "brightness_6_rounded": Icons.brightness_6_rounded, - "brightness_6_outlined": Icons.brightness_6_outlined, - "brightness_7": Icons.brightness_7, - "brightness_7_sharp": Icons.brightness_7_sharp, - "brightness_7_rounded": Icons.brightness_7_rounded, - "brightness_7_outlined": Icons.brightness_7_outlined, - "brightness_auto": Icons.brightness_auto, - "brightness_auto_sharp": Icons.brightness_auto_sharp, - "brightness_auto_rounded": Icons.brightness_auto_rounded, - "brightness_auto_outlined": Icons.brightness_auto_outlined, - "brightness_high": Icons.brightness_high, - "brightness_high_sharp": Icons.brightness_high_sharp, - "brightness_high_rounded": Icons.brightness_high_rounded, - "brightness_high_outlined": Icons.brightness_high_outlined, - "brightness_low": Icons.brightness_low, - "brightness_low_sharp": Icons.brightness_low_sharp, - "brightness_low_rounded": Icons.brightness_low_rounded, - "brightness_low_outlined": Icons.brightness_low_outlined, - "brightness_medium": Icons.brightness_medium, - "brightness_medium_sharp": Icons.brightness_medium_sharp, - "brightness_medium_rounded": Icons.brightness_medium_rounded, - "brightness_medium_outlined": Icons.brightness_medium_outlined, - "broadcast_on_home": Icons.broadcast_on_home, - "broadcast_on_home_sharp": Icons.broadcast_on_home_sharp, - "broadcast_on_home_rounded": Icons.broadcast_on_home_rounded, - "broadcast_on_home_outlined": Icons.broadcast_on_home_outlined, - "broadcast_on_personal": Icons.broadcast_on_personal, - "broadcast_on_personal_sharp": Icons.broadcast_on_personal_sharp, - "broadcast_on_personal_rounded": Icons.broadcast_on_personal_rounded, - "broadcast_on_personal_outlined": Icons.broadcast_on_personal_outlined, - "broken_image": Icons.broken_image, - "broken_image_sharp": Icons.broken_image_sharp, - "broken_image_rounded": Icons.broken_image_rounded, - "broken_image_outlined": Icons.broken_image_outlined, - "browse_gallery": Icons.browse_gallery, - "browse_gallery_sharp": Icons.browse_gallery_sharp, - "browse_gallery_rounded": Icons.browse_gallery_rounded, - "browse_gallery_outlined": Icons.browse_gallery_outlined, - "browser_not_supported": Icons.browser_not_supported, - "browser_not_supported_sharp": Icons.browser_not_supported_sharp, - "browser_not_supported_rounded": Icons.browser_not_supported_rounded, - "browser_not_supported_outlined": Icons.browser_not_supported_outlined, - "browser_updated": Icons.browser_updated, - "browser_updated_sharp": Icons.browser_updated_sharp, - "browser_updated_rounded": Icons.browser_updated_rounded, - "browser_updated_outlined": Icons.browser_updated_outlined, - "brunch_dining": Icons.brunch_dining, - "brunch_dining_sharp": Icons.brunch_dining_sharp, - "brunch_dining_rounded": Icons.brunch_dining_rounded, - "brunch_dining_outlined": Icons.brunch_dining_outlined, - "brush": Icons.brush, - "brush_sharp": Icons.brush_sharp, - "brush_rounded": Icons.brush_rounded, - "brush_outlined": Icons.brush_outlined, - "bubble_chart": Icons.bubble_chart, - "bubble_chart_sharp": Icons.bubble_chart_sharp, - "bubble_chart_rounded": Icons.bubble_chart_rounded, - "bubble_chart_outlined": Icons.bubble_chart_outlined, - "bug_report": Icons.bug_report, - "bug_report_sharp": Icons.bug_report_sharp, - "bug_report_rounded": Icons.bug_report_rounded, - "bug_report_outlined": Icons.bug_report_outlined, - "build": Icons.build, - "build_sharp": Icons.build_sharp, - "build_rounded": Icons.build_rounded, - "build_outlined": Icons.build_outlined, - "build_circle": Icons.build_circle, - "build_circle_sharp": Icons.build_circle_sharp, - "build_circle_rounded": Icons.build_circle_rounded, - "build_circle_outlined": Icons.build_circle_outlined, - "bungalow": Icons.bungalow, - "bungalow_sharp": Icons.bungalow_sharp, - "bungalow_rounded": Icons.bungalow_rounded, - "bungalow_outlined": Icons.bungalow_outlined, - "burst_mode": Icons.burst_mode, - "burst_mode_sharp": Icons.burst_mode_sharp, - "burst_mode_rounded": Icons.burst_mode_rounded, - "burst_mode_outlined": Icons.burst_mode_outlined, - "bus_alert": Icons.bus_alert, - "bus_alert_sharp": Icons.bus_alert_sharp, - "bus_alert_rounded": Icons.bus_alert_rounded, - "bus_alert_outlined": Icons.bus_alert_outlined, - "business": Icons.business, - "business_sharp": Icons.business_sharp, - "business_rounded": Icons.business_rounded, - "business_outlined": Icons.business_outlined, - "business_center": Icons.business_center, - "business_center_sharp": Icons.business_center_sharp, - "business_center_rounded": Icons.business_center_rounded, - "business_center_outlined": Icons.business_center_outlined, - "cabin": Icons.cabin, - "cabin_sharp": Icons.cabin_sharp, - "cabin_rounded": Icons.cabin_rounded, - "cabin_outlined": Icons.cabin_outlined, - "cable": Icons.cable, - "cable_sharp": Icons.cable_sharp, - "cable_rounded": Icons.cable_rounded, - "cable_outlined": Icons.cable_outlined, - "cached": Icons.cached, - "cached_sharp": Icons.cached_sharp, - "cached_rounded": Icons.cached_rounded, - "cached_outlined": Icons.cached_outlined, - "cake": Icons.cake, - "cake_sharp": Icons.cake_sharp, - "cake_rounded": Icons.cake_rounded, - "cake_outlined": Icons.cake_outlined, - "calculate": Icons.calculate, - "calculate_sharp": Icons.calculate_sharp, - "calculate_rounded": Icons.calculate_rounded, - "calculate_outlined": Icons.calculate_outlined, - "calendar_month": Icons.calendar_month, - "calendar_month_sharp": Icons.calendar_month_sharp, - "calendar_month_rounded": Icons.calendar_month_rounded, - "calendar_month_outlined": Icons.calendar_month_outlined, - "calendar_today": Icons.calendar_today, - "calendar_today_sharp": Icons.calendar_today_sharp, - "calendar_today_rounded": Icons.calendar_today_rounded, - "calendar_today_outlined": Icons.calendar_today_outlined, - "calendar_view_day": Icons.calendar_view_day, - "calendar_view_day_sharp": Icons.calendar_view_day_sharp, - "calendar_view_day_rounded": Icons.calendar_view_day_rounded, - "calendar_view_day_outlined": Icons.calendar_view_day_outlined, - "calendar_view_month": Icons.calendar_view_month, - "calendar_view_month_sharp": Icons.calendar_view_month_sharp, - "calendar_view_month_rounded": Icons.calendar_view_month_rounded, - "calendar_view_month_outlined": Icons.calendar_view_month_outlined, - "calendar_view_week": Icons.calendar_view_week, - "calendar_view_week_sharp": Icons.calendar_view_week_sharp, - "calendar_view_week_rounded": Icons.calendar_view_week_rounded, - "calendar_view_week_outlined": Icons.calendar_view_week_outlined, - "call": Icons.call, - "call_sharp": Icons.call_sharp, - "call_rounded": Icons.call_rounded, - "call_outlined": Icons.call_outlined, - "call_end": Icons.call_end, - "call_end_sharp": Icons.call_end_sharp, - "call_end_rounded": Icons.call_end_rounded, - "call_end_outlined": Icons.call_end_outlined, - "call_made": Icons.call_made, - "call_made_sharp": Icons.call_made_sharp, - "call_made_rounded": Icons.call_made_rounded, - "call_made_outlined": Icons.call_made_outlined, - "call_merge": Icons.call_merge, - "call_merge_sharp": Icons.call_merge_sharp, - "call_merge_rounded": Icons.call_merge_rounded, - "call_merge_outlined": Icons.call_merge_outlined, - "call_missed": Icons.call_missed, - "call_missed_sharp": Icons.call_missed_sharp, - "call_missed_rounded": Icons.call_missed_rounded, - "call_missed_outlined": Icons.call_missed_outlined, - "call_missed_outgoing": Icons.call_missed_outgoing, - "call_missed_outgoing_sharp": Icons.call_missed_outgoing_sharp, - "call_missed_outgoing_rounded": Icons.call_missed_outgoing_rounded, - "call_missed_outgoing_outlined": Icons.call_missed_outgoing_outlined, - "call_received": Icons.call_received, - "call_received_sharp": Icons.call_received_sharp, - "call_received_rounded": Icons.call_received_rounded, - "call_received_outlined": Icons.call_received_outlined, - "call_split": Icons.call_split, - "call_split_sharp": Icons.call_split_sharp, - "call_split_rounded": Icons.call_split_rounded, - "call_split_outlined": Icons.call_split_outlined, - "call_to_action": Icons.call_to_action, - "call_to_action_sharp": Icons.call_to_action_sharp, - "call_to_action_rounded": Icons.call_to_action_rounded, - "call_to_action_outlined": Icons.call_to_action_outlined, - "camera": Icons.camera, - "camera_sharp": Icons.camera_sharp, - "camera_rounded": Icons.camera_rounded, - "camera_outlined": Icons.camera_outlined, - "camera_alt": Icons.camera_alt, - "camera_alt_sharp": Icons.camera_alt_sharp, - "camera_alt_rounded": Icons.camera_alt_rounded, - "camera_alt_outlined": Icons.camera_alt_outlined, - "camera_enhance": Icons.camera_enhance, - "camera_enhance_sharp": Icons.camera_enhance_sharp, - "camera_enhance_rounded": Icons.camera_enhance_rounded, - "camera_enhance_outlined": Icons.camera_enhance_outlined, - "camera_front": Icons.camera_front, - "camera_front_sharp": Icons.camera_front_sharp, - "camera_front_rounded": Icons.camera_front_rounded, - "camera_front_outlined": Icons.camera_front_outlined, - "camera_indoor": Icons.camera_indoor, - "camera_indoor_sharp": Icons.camera_indoor_sharp, - "camera_indoor_rounded": Icons.camera_indoor_rounded, - "camera_indoor_outlined": Icons.camera_indoor_outlined, - "camera_outdoor": Icons.camera_outdoor, - "camera_outdoor_sharp": Icons.camera_outdoor_sharp, - "camera_outdoor_rounded": Icons.camera_outdoor_rounded, - "camera_outdoor_outlined": Icons.camera_outdoor_outlined, - "camera_rear": Icons.camera_rear, - "camera_rear_sharp": Icons.camera_rear_sharp, - "camera_rear_rounded": Icons.camera_rear_rounded, - "camera_rear_outlined": Icons.camera_rear_outlined, - "camera_roll": Icons.camera_roll, - "camera_roll_sharp": Icons.camera_roll_sharp, - "camera_roll_rounded": Icons.camera_roll_rounded, - "camera_roll_outlined": Icons.camera_roll_outlined, - "cameraswitch": Icons.cameraswitch, - "cameraswitch_sharp": Icons.cameraswitch_sharp, - "cameraswitch_rounded": Icons.cameraswitch_rounded, - "cameraswitch_outlined": Icons.cameraswitch_outlined, - "campaign": Icons.campaign, - "campaign_sharp": Icons.campaign_sharp, - "campaign_rounded": Icons.campaign_rounded, - "campaign_outlined": Icons.campaign_outlined, - "cancel": Icons.cancel, - "cancel_sharp": Icons.cancel_sharp, - "cancel_rounded": Icons.cancel_rounded, - "cancel_outlined": Icons.cancel_outlined, - "cancel_presentation": Icons.cancel_presentation, - "cancel_presentation_sharp": Icons.cancel_presentation_sharp, - "cancel_presentation_rounded": Icons.cancel_presentation_rounded, - "cancel_presentation_outlined": Icons.cancel_presentation_outlined, - "cancel_schedule_send": Icons.cancel_schedule_send, - "cancel_schedule_send_sharp": Icons.cancel_schedule_send_sharp, - "cancel_schedule_send_rounded": Icons.cancel_schedule_send_rounded, - "cancel_schedule_send_outlined": Icons.cancel_schedule_send_outlined, - "candlestick_chart": Icons.candlestick_chart, - "candlestick_chart_sharp": Icons.candlestick_chart_sharp, - "candlestick_chart_rounded": Icons.candlestick_chart_rounded, - "candlestick_chart_outlined": Icons.candlestick_chart_outlined, - "car_crash": Icons.car_crash, - "car_crash_sharp": Icons.car_crash_sharp, - "car_crash_rounded": Icons.car_crash_rounded, - "car_crash_outlined": Icons.car_crash_outlined, - "car_rental": Icons.car_rental, - "car_rental_sharp": Icons.car_rental_sharp, - "car_rental_rounded": Icons.car_rental_rounded, - "car_rental_outlined": Icons.car_rental_outlined, - "car_repair": Icons.car_repair, - "car_repair_sharp": Icons.car_repair_sharp, - "car_repair_rounded": Icons.car_repair_rounded, - "car_repair_outlined": Icons.car_repair_outlined, - "card_giftcard": Icons.card_giftcard, - "card_giftcard_sharp": Icons.card_giftcard_sharp, - "card_giftcard_rounded": Icons.card_giftcard_rounded, - "card_giftcard_outlined": Icons.card_giftcard_outlined, - "card_membership": Icons.card_membership, - "card_membership_sharp": Icons.card_membership_sharp, - "card_membership_rounded": Icons.card_membership_rounded, - "card_membership_outlined": Icons.card_membership_outlined, - "card_travel": Icons.card_travel, - "card_travel_sharp": Icons.card_travel_sharp, - "card_travel_rounded": Icons.card_travel_rounded, - "card_travel_outlined": Icons.card_travel_outlined, - "carpenter": Icons.carpenter, - "carpenter_sharp": Icons.carpenter_sharp, - "carpenter_rounded": Icons.carpenter_rounded, - "carpenter_outlined": Icons.carpenter_outlined, - "cases": Icons.cases, - "cases_sharp": Icons.cases_sharp, - "cases_rounded": Icons.cases_rounded, - "cases_outlined": Icons.cases_outlined, - "casino": Icons.casino, - "casino_sharp": Icons.casino_sharp, - "casino_rounded": Icons.casino_rounded, - "casino_outlined": Icons.casino_outlined, - "cast": Icons.cast, - "cast_sharp": Icons.cast_sharp, - "cast_rounded": Icons.cast_rounded, - "cast_outlined": Icons.cast_outlined, - "cast_connected": Icons.cast_connected, - "cast_connected_sharp": Icons.cast_connected_sharp, - "cast_connected_rounded": Icons.cast_connected_rounded, - "cast_connected_outlined": Icons.cast_connected_outlined, - "cast_for_education": Icons.cast_for_education, - "cast_for_education_sharp": Icons.cast_for_education_sharp, - "cast_for_education_rounded": Icons.cast_for_education_rounded, - "cast_for_education_outlined": Icons.cast_for_education_outlined, - "castle": Icons.castle, - "castle_sharp": Icons.castle_sharp, - "castle_rounded": Icons.castle_rounded, - "castle_outlined": Icons.castle_outlined, - "catching_pokemon": Icons.catching_pokemon, - "catching_pokemon_sharp": Icons.catching_pokemon_sharp, - "catching_pokemon_rounded": Icons.catching_pokemon_rounded, - "catching_pokemon_outlined": Icons.catching_pokemon_outlined, - "category": Icons.category, - "category_sharp": Icons.category_sharp, - "category_rounded": Icons.category_rounded, - "category_outlined": Icons.category_outlined, - "celebration": Icons.celebration, - "celebration_sharp": Icons.celebration_sharp, - "celebration_rounded": Icons.celebration_rounded, - "celebration_outlined": Icons.celebration_outlined, - "cell_tower": Icons.cell_tower, - "cell_tower_sharp": Icons.cell_tower_sharp, - "cell_tower_rounded": Icons.cell_tower_rounded, - "cell_tower_outlined": Icons.cell_tower_outlined, - "cell_wifi": Icons.cell_wifi, - "cell_wifi_sharp": Icons.cell_wifi_sharp, - "cell_wifi_rounded": Icons.cell_wifi_rounded, - "cell_wifi_outlined": Icons.cell_wifi_outlined, - "center_focus_strong": Icons.center_focus_strong, - "center_focus_strong_sharp": Icons.center_focus_strong_sharp, - "center_focus_strong_rounded": Icons.center_focus_strong_rounded, - "center_focus_strong_outlined": Icons.center_focus_strong_outlined, - "center_focus_weak": Icons.center_focus_weak, - "center_focus_weak_sharp": Icons.center_focus_weak_sharp, - "center_focus_weak_rounded": Icons.center_focus_weak_rounded, - "center_focus_weak_outlined": Icons.center_focus_weak_outlined, - "chair": Icons.chair, - "chair_sharp": Icons.chair_sharp, - "chair_rounded": Icons.chair_rounded, - "chair_outlined": Icons.chair_outlined, - "chair_alt": Icons.chair_alt, - "chair_alt_sharp": Icons.chair_alt_sharp, - "chair_alt_rounded": Icons.chair_alt_rounded, - "chair_alt_outlined": Icons.chair_alt_outlined, - "chalet": Icons.chalet, - "chalet_sharp": Icons.chalet_sharp, - "chalet_rounded": Icons.chalet_rounded, - "chalet_outlined": Icons.chalet_outlined, - "change_circle": Icons.change_circle, - "change_circle_sharp": Icons.change_circle_sharp, - "change_circle_rounded": Icons.change_circle_rounded, - "change_circle_outlined": Icons.change_circle_outlined, - "change_history": Icons.change_history, - "change_history_sharp": Icons.change_history_sharp, - "change_history_rounded": Icons.change_history_rounded, - "change_history_outlined": Icons.change_history_outlined, - "charging_station": Icons.charging_station, - "charging_station_sharp": Icons.charging_station_sharp, - "charging_station_rounded": Icons.charging_station_rounded, - "charging_station_outlined": Icons.charging_station_outlined, - "chat": Icons.chat, - "chat_sharp": Icons.chat_sharp, - "chat_rounded": Icons.chat_rounded, - "chat_outlined": Icons.chat_outlined, - "chat_bubble": Icons.chat_bubble, - "chat_bubble_sharp": Icons.chat_bubble_sharp, - "chat_bubble_rounded": Icons.chat_bubble_rounded, - "chat_bubble_outlined": Icons.chat_bubble_outlined, - "chat_bubble_outline": Icons.chat_bubble_outline, - "chat_bubble_outline_sharp": Icons.chat_bubble_outline_sharp, - "chat_bubble_outline_rounded": Icons.chat_bubble_outline_rounded, - "chat_bubble_outline_outlined": Icons.chat_bubble_outline_outlined, - "check": Icons.check, - "check_sharp": Icons.check_sharp, - "check_rounded": Icons.check_rounded, - "check_outlined": Icons.check_outlined, - "check_box": Icons.check_box, - "check_box_sharp": Icons.check_box_sharp, - "check_box_rounded": Icons.check_box_rounded, - "check_box_outlined": Icons.check_box_outlined, - "check_box_outline_blank": Icons.check_box_outline_blank, - "check_box_outline_blank_sharp": Icons.check_box_outline_blank_sharp, - "check_box_outline_blank_rounded": Icons.check_box_outline_blank_rounded, - "check_box_outline_blank_outlined": Icons.check_box_outline_blank_outlined, - "check_circle": Icons.check_circle, - "check_circle_sharp": Icons.check_circle_sharp, - "check_circle_rounded": Icons.check_circle_rounded, - "check_circle_outlined": Icons.check_circle_outlined, - "check_circle_outline": Icons.check_circle_outline, - "check_circle_outline_sharp": Icons.check_circle_outline_sharp, - "check_circle_outline_rounded": Icons.check_circle_outline_rounded, - "check_circle_outline_outlined": Icons.check_circle_outline_outlined, - "checklist": Icons.checklist, - "checklist_sharp": Icons.checklist_sharp, - "checklist_rounded": Icons.checklist_rounded, - "checklist_outlined": Icons.checklist_outlined, - "checklist_rtl": Icons.checklist_rtl, - "checklist_rtl_sharp": Icons.checklist_rtl_sharp, - "checklist_rtl_rounded": Icons.checklist_rtl_rounded, - "checklist_rtl_outlined": Icons.checklist_rtl_outlined, - "checkroom": Icons.checkroom, - "checkroom_sharp": Icons.checkroom_sharp, - "checkroom_rounded": Icons.checkroom_rounded, - "checkroom_outlined": Icons.checkroom_outlined, - "chevron_left": Icons.chevron_left, - "chevron_left_sharp": Icons.chevron_left_sharp, - "chevron_left_rounded": Icons.chevron_left_rounded, - "chevron_left_outlined": Icons.chevron_left_outlined, - "chevron_right": Icons.chevron_right, - "chevron_right_sharp": Icons.chevron_right_sharp, - "chevron_right_rounded": Icons.chevron_right_rounded, - "chevron_right_outlined": Icons.chevron_right_outlined, - "child_care": Icons.child_care, - "child_care_sharp": Icons.child_care_sharp, - "child_care_rounded": Icons.child_care_rounded, - "child_care_outlined": Icons.child_care_outlined, - "child_friendly": Icons.child_friendly, - "child_friendly_sharp": Icons.child_friendly_sharp, - "child_friendly_rounded": Icons.child_friendly_rounded, - "child_friendly_outlined": Icons.child_friendly_outlined, - "chrome_reader_mode": Icons.chrome_reader_mode, - "chrome_reader_mode_sharp": Icons.chrome_reader_mode_sharp, - "chrome_reader_mode_rounded": Icons.chrome_reader_mode_rounded, - "chrome_reader_mode_outlined": Icons.chrome_reader_mode_outlined, - "church": Icons.church, - "church_sharp": Icons.church_sharp, - "church_rounded": Icons.church_rounded, - "church_outlined": Icons.church_outlined, - "circle": Icons.circle, - "circle_sharp": Icons.circle_sharp, - "circle_rounded": Icons.circle_rounded, - "circle_outlined": Icons.circle_outlined, - "circle_notifications": Icons.circle_notifications, - "circle_notifications_sharp": Icons.circle_notifications_sharp, - "circle_notifications_rounded": Icons.circle_notifications_rounded, - "circle_notifications_outlined": Icons.circle_notifications_outlined, - "class_": Icons.class_, - "class_sharp": Icons.class_sharp, - "class_rounded": Icons.class_rounded, - "class_outlined": Icons.class_outlined, - "clean_hands": Icons.clean_hands, - "clean_hands_sharp": Icons.clean_hands_sharp, - "clean_hands_rounded": Icons.clean_hands_rounded, - "clean_hands_outlined": Icons.clean_hands_outlined, - "cleaning_services": Icons.cleaning_services, - "cleaning_services_sharp": Icons.cleaning_services_sharp, - "cleaning_services_rounded": Icons.cleaning_services_rounded, - "cleaning_services_outlined": Icons.cleaning_services_outlined, - "clear": Icons.clear, - "clear_sharp": Icons.clear_sharp, - "clear_rounded": Icons.clear_rounded, - "clear_outlined": Icons.clear_outlined, - "clear_all": Icons.clear_all, - "clear_all_sharp": Icons.clear_all_sharp, - "clear_all_rounded": Icons.clear_all_rounded, - "clear_all_outlined": Icons.clear_all_outlined, - "close": Icons.close, - "close_sharp": Icons.close_sharp, - "close_rounded": Icons.close_rounded, - "close_outlined": Icons.close_outlined, - "close_fullscreen": Icons.close_fullscreen, - "close_fullscreen_sharp": Icons.close_fullscreen_sharp, - "close_fullscreen_rounded": Icons.close_fullscreen_rounded, - "close_fullscreen_outlined": Icons.close_fullscreen_outlined, - "closed_caption": Icons.closed_caption, - "closed_caption_sharp": Icons.closed_caption_sharp, - "closed_caption_rounded": Icons.closed_caption_rounded, - "closed_caption_outlined": Icons.closed_caption_outlined, - "closed_caption_disabled": Icons.closed_caption_disabled, - "closed_caption_disabled_sharp": Icons.closed_caption_disabled_sharp, - "closed_caption_disabled_rounded": Icons.closed_caption_disabled_rounded, - "closed_caption_disabled_outlined": Icons.closed_caption_disabled_outlined, - "closed_caption_off": Icons.closed_caption_off, - "closed_caption_off_sharp": Icons.closed_caption_off_sharp, - "closed_caption_off_rounded": Icons.closed_caption_off_rounded, - "closed_caption_off_outlined": Icons.closed_caption_off_outlined, - "cloud": Icons.cloud, - "cloud_sharp": Icons.cloud_sharp, - "cloud_rounded": Icons.cloud_rounded, - "cloud_outlined": Icons.cloud_outlined, - "cloud_circle": Icons.cloud_circle, - "cloud_circle_sharp": Icons.cloud_circle_sharp, - "cloud_circle_rounded": Icons.cloud_circle_rounded, - "cloud_circle_outlined": Icons.cloud_circle_outlined, - "cloud_done": Icons.cloud_done, - "cloud_done_sharp": Icons.cloud_done_sharp, - "cloud_done_rounded": Icons.cloud_done_rounded, - "cloud_done_outlined": Icons.cloud_done_outlined, - "cloud_download": Icons.cloud_download, - "cloud_download_sharp": Icons.cloud_download_sharp, - "cloud_download_rounded": Icons.cloud_download_rounded, - "cloud_download_outlined": Icons.cloud_download_outlined, - "cloud_off": Icons.cloud_off, - "cloud_off_sharp": Icons.cloud_off_sharp, - "cloud_off_rounded": Icons.cloud_off_rounded, - "cloud_off_outlined": Icons.cloud_off_outlined, - "cloud_queue": Icons.cloud_queue, - "cloud_queue_sharp": Icons.cloud_queue_sharp, - "cloud_queue_rounded": Icons.cloud_queue_rounded, - "cloud_queue_outlined": Icons.cloud_queue_outlined, - "cloud_sync": Icons.cloud_sync, - "cloud_sync_sharp": Icons.cloud_sync_sharp, - "cloud_sync_rounded": Icons.cloud_sync_rounded, - "cloud_sync_outlined": Icons.cloud_sync_outlined, - "cloud_upload": Icons.cloud_upload, - "cloud_upload_sharp": Icons.cloud_upload_sharp, - "cloud_upload_rounded": Icons.cloud_upload_rounded, - "cloud_upload_outlined": Icons.cloud_upload_outlined, - "cloudy_snowing": Icons.cloudy_snowing, - "co2": Icons.co2, - "co2_sharp": Icons.co2_sharp, - "co2_rounded": Icons.co2_rounded, - "co2_outlined": Icons.co2_outlined, - "co_present": Icons.co_present, - "co_present_sharp": Icons.co_present_sharp, - "co_present_rounded": Icons.co_present_rounded, - "co_present_outlined": Icons.co_present_outlined, - "code": Icons.code, - "code_sharp": Icons.code_sharp, - "code_rounded": Icons.code_rounded, - "code_outlined": Icons.code_outlined, - "code_off": Icons.code_off, - "code_off_sharp": Icons.code_off_sharp, - "code_off_rounded": Icons.code_off_rounded, - "code_off_outlined": Icons.code_off_outlined, - "coffee": Icons.coffee, - "coffee_sharp": Icons.coffee_sharp, - "coffee_rounded": Icons.coffee_rounded, - "coffee_outlined": Icons.coffee_outlined, - "coffee_maker": Icons.coffee_maker, - "coffee_maker_sharp": Icons.coffee_maker_sharp, - "coffee_maker_rounded": Icons.coffee_maker_rounded, - "coffee_maker_outlined": Icons.coffee_maker_outlined, - "collections": Icons.collections, - "collections_sharp": Icons.collections_sharp, - "collections_rounded": Icons.collections_rounded, - "collections_outlined": Icons.collections_outlined, - "collections_bookmark": Icons.collections_bookmark, - "collections_bookmark_sharp": Icons.collections_bookmark_sharp, - "collections_bookmark_rounded": Icons.collections_bookmark_rounded, - "collections_bookmark_outlined": Icons.collections_bookmark_outlined, - "color_lens": Icons.color_lens, - "color_lens_sharp": Icons.color_lens_sharp, - "color_lens_rounded": Icons.color_lens_rounded, - "color_lens_outlined": Icons.color_lens_outlined, - "colorize": Icons.colorize, - "colorize_sharp": Icons.colorize_sharp, - "colorize_rounded": Icons.colorize_rounded, - "colorize_outlined": Icons.colorize_outlined, - "comment": Icons.comment, - "comment_sharp": Icons.comment_sharp, - "comment_rounded": Icons.comment_rounded, - "comment_outlined": Icons.comment_outlined, - "comment_bank": Icons.comment_bank, - "comment_bank_sharp": Icons.comment_bank_sharp, - "comment_bank_rounded": Icons.comment_bank_rounded, - "comment_bank_outlined": Icons.comment_bank_outlined, - "comments_disabled": Icons.comments_disabled, - "comments_disabled_sharp": Icons.comments_disabled_sharp, - "comments_disabled_rounded": Icons.comments_disabled_rounded, - "comments_disabled_outlined": Icons.comments_disabled_outlined, - "commit": Icons.commit, - "commit_sharp": Icons.commit_sharp, - "commit_rounded": Icons.commit_rounded, - "commit_outlined": Icons.commit_outlined, - "commute": Icons.commute, - "commute_sharp": Icons.commute_sharp, - "commute_rounded": Icons.commute_rounded, - "commute_outlined": Icons.commute_outlined, - "compare": Icons.compare, - "compare_sharp": Icons.compare_sharp, - "compare_rounded": Icons.compare_rounded, - "compare_outlined": Icons.compare_outlined, - "compare_arrows": Icons.compare_arrows, - "compare_arrows_sharp": Icons.compare_arrows_sharp, - "compare_arrows_rounded": Icons.compare_arrows_rounded, - "compare_arrows_outlined": Icons.compare_arrows_outlined, - "compass_calibration": Icons.compass_calibration, - "compass_calibration_sharp": Icons.compass_calibration_sharp, - "compass_calibration_rounded": Icons.compass_calibration_rounded, - "compass_calibration_outlined": Icons.compass_calibration_outlined, - "compost": Icons.compost, - "compost_sharp": Icons.compost_sharp, - "compost_rounded": Icons.compost_rounded, - "compost_outlined": Icons.compost_outlined, - "compress": Icons.compress, - "compress_sharp": Icons.compress_sharp, - "compress_rounded": Icons.compress_rounded, - "compress_outlined": Icons.compress_outlined, - "computer": Icons.computer, - "computer_sharp": Icons.computer_sharp, - "computer_rounded": Icons.computer_rounded, - "computer_outlined": Icons.computer_outlined, - "confirmation_num": Icons.confirmation_num, - "confirmation_num_sharp": Icons.confirmation_num_sharp, - "confirmation_num_rounded": Icons.confirmation_num_rounded, - "confirmation_num_outlined": Icons.confirmation_num_outlined, - "confirmation_number": Icons.confirmation_number, - "confirmation_number_sharp": Icons.confirmation_number_sharp, - "confirmation_number_rounded": Icons.confirmation_number_rounded, - "confirmation_number_outlined": Icons.confirmation_number_outlined, - "connect_without_contact": Icons.connect_without_contact, - "connect_without_contact_sharp": Icons.connect_without_contact_sharp, - "connect_without_contact_rounded": Icons.connect_without_contact_rounded, - "connect_without_contact_outlined": Icons.connect_without_contact_outlined, - "connected_tv": Icons.connected_tv, - "connected_tv_sharp": Icons.connected_tv_sharp, - "connected_tv_rounded": Icons.connected_tv_rounded, - "connected_tv_outlined": Icons.connected_tv_outlined, - "connecting_airports": Icons.connecting_airports, - "connecting_airports_sharp": Icons.connecting_airports_sharp, - "connecting_airports_rounded": Icons.connecting_airports_rounded, - "connecting_airports_outlined": Icons.connecting_airports_outlined, - "construction": Icons.construction, - "construction_sharp": Icons.construction_sharp, - "construction_rounded": Icons.construction_rounded, - "construction_outlined": Icons.construction_outlined, - "contact_emergency": Icons.contact_emergency, - "contact_emergency_sharp": Icons.contact_emergency_sharp, - "contact_emergency_rounded": Icons.contact_emergency_rounded, - "contact_emergency_outlined": Icons.contact_emergency_outlined, - "contact_mail": Icons.contact_mail, - "contact_mail_sharp": Icons.contact_mail_sharp, - "contact_mail_rounded": Icons.contact_mail_rounded, - "contact_mail_outlined": Icons.contact_mail_outlined, - "contact_page": Icons.contact_page, - "contact_page_sharp": Icons.contact_page_sharp, - "contact_page_rounded": Icons.contact_page_rounded, - "contact_page_outlined": Icons.contact_page_outlined, - "contact_phone": Icons.contact_phone, - "contact_phone_sharp": Icons.contact_phone_sharp, - "contact_phone_rounded": Icons.contact_phone_rounded, - "contact_phone_outlined": Icons.contact_phone_outlined, - "contact_support": Icons.contact_support, - "contact_support_sharp": Icons.contact_support_sharp, - "contact_support_rounded": Icons.contact_support_rounded, - "contact_support_outlined": Icons.contact_support_outlined, - "contactless": Icons.contactless, - "contactless_sharp": Icons.contactless_sharp, - "contactless_rounded": Icons.contactless_rounded, - "contactless_outlined": Icons.contactless_outlined, - "contacts": Icons.contacts, - "contacts_sharp": Icons.contacts_sharp, - "contacts_rounded": Icons.contacts_rounded, - "contacts_outlined": Icons.contacts_outlined, - "content_copy": Icons.content_copy, - "content_copy_sharp": Icons.content_copy_sharp, - "content_copy_rounded": Icons.content_copy_rounded, - "content_copy_outlined": Icons.content_copy_outlined, - "content_cut": Icons.content_cut, - "content_cut_sharp": Icons.content_cut_sharp, - "content_cut_rounded": Icons.content_cut_rounded, - "content_cut_outlined": Icons.content_cut_outlined, - "content_paste": Icons.content_paste, - "content_paste_sharp": Icons.content_paste_sharp, - "content_paste_rounded": Icons.content_paste_rounded, - "content_paste_outlined": Icons.content_paste_outlined, - "content_paste_go": Icons.content_paste_go, - "content_paste_go_sharp": Icons.content_paste_go_sharp, - "content_paste_go_rounded": Icons.content_paste_go_rounded, - "content_paste_go_outlined": Icons.content_paste_go_outlined, - "content_paste_off": Icons.content_paste_off, - "content_paste_off_sharp": Icons.content_paste_off_sharp, - "content_paste_off_rounded": Icons.content_paste_off_rounded, - "content_paste_off_outlined": Icons.content_paste_off_outlined, - "content_paste_search": Icons.content_paste_search, - "content_paste_search_sharp": Icons.content_paste_search_sharp, - "content_paste_search_rounded": Icons.content_paste_search_rounded, - "content_paste_search_outlined": Icons.content_paste_search_outlined, - "contrast": Icons.contrast, - "contrast_sharp": Icons.contrast_sharp, - "contrast_rounded": Icons.contrast_rounded, - "contrast_outlined": Icons.contrast_outlined, - "control_camera": Icons.control_camera, - "control_camera_sharp": Icons.control_camera_sharp, - "control_camera_rounded": Icons.control_camera_rounded, - "control_camera_outlined": Icons.control_camera_outlined, - "control_point": Icons.control_point, - "control_point_sharp": Icons.control_point_sharp, - "control_point_rounded": Icons.control_point_rounded, - "control_point_outlined": Icons.control_point_outlined, - "control_point_duplicate": Icons.control_point_duplicate, - "control_point_duplicate_sharp": Icons.control_point_duplicate_sharp, - "control_point_duplicate_rounded": Icons.control_point_duplicate_rounded, - "control_point_duplicate_outlined": Icons.control_point_duplicate_outlined, - "conveyor_belt": Icons.conveyor_belt, - "cookie": Icons.cookie, - "cookie_sharp": Icons.cookie_sharp, - "cookie_rounded": Icons.cookie_rounded, - "cookie_outlined": Icons.cookie_outlined, - "copy": Icons.copy, - "copy_sharp": Icons.copy_sharp, - "copy_rounded": Icons.copy_rounded, - "copy_outlined": Icons.copy_outlined, - "copy_all": Icons.copy_all, - "copy_all_sharp": Icons.copy_all_sharp, - "copy_all_rounded": Icons.copy_all_rounded, - "copy_all_outlined": Icons.copy_all_outlined, - "copyright": Icons.copyright, - "copyright_sharp": Icons.copyright_sharp, - "copyright_rounded": Icons.copyright_rounded, - "copyright_outlined": Icons.copyright_outlined, - "coronavirus": Icons.coronavirus, - "coronavirus_sharp": Icons.coronavirus_sharp, - "coronavirus_rounded": Icons.coronavirus_rounded, - "coronavirus_outlined": Icons.coronavirus_outlined, - "corporate_fare": Icons.corporate_fare, - "corporate_fare_sharp": Icons.corporate_fare_sharp, - "corporate_fare_rounded": Icons.corporate_fare_rounded, - "corporate_fare_outlined": Icons.corporate_fare_outlined, - "cottage": Icons.cottage, - "cottage_sharp": Icons.cottage_sharp, - "cottage_rounded": Icons.cottage_rounded, - "cottage_outlined": Icons.cottage_outlined, - "countertops": Icons.countertops, - "countertops_sharp": Icons.countertops_sharp, - "countertops_rounded": Icons.countertops_rounded, - "countertops_outlined": Icons.countertops_outlined, - "create": Icons.create, - "create_sharp": Icons.create_sharp, - "create_rounded": Icons.create_rounded, - "create_outlined": Icons.create_outlined, - "create_new_folder": Icons.create_new_folder, - "create_new_folder_sharp": Icons.create_new_folder_sharp, - "create_new_folder_rounded": Icons.create_new_folder_rounded, - "create_new_folder_outlined": Icons.create_new_folder_outlined, - "credit_card": Icons.credit_card, - "credit_card_sharp": Icons.credit_card_sharp, - "credit_card_rounded": Icons.credit_card_rounded, - "credit_card_outlined": Icons.credit_card_outlined, - "credit_card_off": Icons.credit_card_off, - "credit_card_off_sharp": Icons.credit_card_off_sharp, - "credit_card_off_rounded": Icons.credit_card_off_rounded, - "credit_card_off_outlined": Icons.credit_card_off_outlined, - "credit_score": Icons.credit_score, - "credit_score_sharp": Icons.credit_score_sharp, - "credit_score_rounded": Icons.credit_score_rounded, - "credit_score_outlined": Icons.credit_score_outlined, - "crib": Icons.crib, - "crib_sharp": Icons.crib_sharp, - "crib_rounded": Icons.crib_rounded, - "crib_outlined": Icons.crib_outlined, - "crisis_alert": Icons.crisis_alert, - "crisis_alert_sharp": Icons.crisis_alert_sharp, - "crisis_alert_rounded": Icons.crisis_alert_rounded, - "crisis_alert_outlined": Icons.crisis_alert_outlined, - "crop": Icons.crop, - "crop_sharp": Icons.crop_sharp, - "crop_rounded": Icons.crop_rounded, - "crop_outlined": Icons.crop_outlined, - "crop_16_9": Icons.crop_16_9, - "crop_16_9_sharp": Icons.crop_16_9_sharp, - "crop_16_9_rounded": Icons.crop_16_9_rounded, - "crop_16_9_outlined": Icons.crop_16_9_outlined, - "crop_3_2": Icons.crop_3_2, - "crop_3_2_sharp": Icons.crop_3_2_sharp, - "crop_3_2_rounded": Icons.crop_3_2_rounded, - "crop_3_2_outlined": Icons.crop_3_2_outlined, - "crop_5_4": Icons.crop_5_4, - "crop_5_4_sharp": Icons.crop_5_4_sharp, - "crop_5_4_rounded": Icons.crop_5_4_rounded, - "crop_5_4_outlined": Icons.crop_5_4_outlined, - "crop_7_5": Icons.crop_7_5, - "crop_7_5_sharp": Icons.crop_7_5_sharp, - "crop_7_5_rounded": Icons.crop_7_5_rounded, - "crop_7_5_outlined": Icons.crop_7_5_outlined, - "crop_din": Icons.crop_din, - "crop_din_sharp": Icons.crop_din_sharp, - "crop_din_rounded": Icons.crop_din_rounded, - "crop_din_outlined": Icons.crop_din_outlined, - "crop_free": Icons.crop_free, - "crop_free_sharp": Icons.crop_free_sharp, - "crop_free_rounded": Icons.crop_free_rounded, - "crop_free_outlined": Icons.crop_free_outlined, - "crop_landscape": Icons.crop_landscape, - "crop_landscape_sharp": Icons.crop_landscape_sharp, - "crop_landscape_rounded": Icons.crop_landscape_rounded, - "crop_landscape_outlined": Icons.crop_landscape_outlined, - "crop_original": Icons.crop_original, - "crop_original_sharp": Icons.crop_original_sharp, - "crop_original_rounded": Icons.crop_original_rounded, - "crop_original_outlined": Icons.crop_original_outlined, - "crop_portrait": Icons.crop_portrait, - "crop_portrait_sharp": Icons.crop_portrait_sharp, - "crop_portrait_rounded": Icons.crop_portrait_rounded, - "crop_portrait_outlined": Icons.crop_portrait_outlined, - "crop_rotate": Icons.crop_rotate, - "crop_rotate_sharp": Icons.crop_rotate_sharp, - "crop_rotate_rounded": Icons.crop_rotate_rounded, - "crop_rotate_outlined": Icons.crop_rotate_outlined, - "crop_square": Icons.crop_square, - "crop_square_sharp": Icons.crop_square_sharp, - "crop_square_rounded": Icons.crop_square_rounded, - "crop_square_outlined": Icons.crop_square_outlined, - "cruelty_free": Icons.cruelty_free, - "cruelty_free_sharp": Icons.cruelty_free_sharp, - "cruelty_free_rounded": Icons.cruelty_free_rounded, - "cruelty_free_outlined": Icons.cruelty_free_outlined, - "css": Icons.css, - "css_sharp": Icons.css_sharp, - "css_rounded": Icons.css_rounded, - "css_outlined": Icons.css_outlined, - "currency_bitcoin": Icons.currency_bitcoin, - "currency_bitcoin_sharp": Icons.currency_bitcoin_sharp, - "currency_bitcoin_rounded": Icons.currency_bitcoin_rounded, - "currency_bitcoin_outlined": Icons.currency_bitcoin_outlined, - "currency_exchange": Icons.currency_exchange, - "currency_exchange_sharp": Icons.currency_exchange_sharp, - "currency_exchange_rounded": Icons.currency_exchange_rounded, - "currency_exchange_outlined": Icons.currency_exchange_outlined, - "currency_franc": Icons.currency_franc, - "currency_franc_sharp": Icons.currency_franc_sharp, - "currency_franc_rounded": Icons.currency_franc_rounded, - "currency_franc_outlined": Icons.currency_franc_outlined, - "currency_lira": Icons.currency_lira, - "currency_lira_sharp": Icons.currency_lira_sharp, - "currency_lira_rounded": Icons.currency_lira_rounded, - "currency_lira_outlined": Icons.currency_lira_outlined, - "currency_pound": Icons.currency_pound, - "currency_pound_sharp": Icons.currency_pound_sharp, - "currency_pound_rounded": Icons.currency_pound_rounded, - "currency_pound_outlined": Icons.currency_pound_outlined, - "currency_ruble": Icons.currency_ruble, - "currency_ruble_sharp": Icons.currency_ruble_sharp, - "currency_ruble_rounded": Icons.currency_ruble_rounded, - "currency_ruble_outlined": Icons.currency_ruble_outlined, - "currency_rupee": Icons.currency_rupee, - "currency_rupee_sharp": Icons.currency_rupee_sharp, - "currency_rupee_rounded": Icons.currency_rupee_rounded, - "currency_rupee_outlined": Icons.currency_rupee_outlined, - "currency_yen": Icons.currency_yen, - "currency_yen_sharp": Icons.currency_yen_sharp, - "currency_yen_rounded": Icons.currency_yen_rounded, - "currency_yen_outlined": Icons.currency_yen_outlined, - "currency_yuan": Icons.currency_yuan, - "currency_yuan_sharp": Icons.currency_yuan_sharp, - "currency_yuan_rounded": Icons.currency_yuan_rounded, - "currency_yuan_outlined": Icons.currency_yuan_outlined, - "curtains": Icons.curtains, - "curtains_sharp": Icons.curtains_sharp, - "curtains_rounded": Icons.curtains_rounded, - "curtains_outlined": Icons.curtains_outlined, - "curtains_closed": Icons.curtains_closed, - "curtains_closed_sharp": Icons.curtains_closed_sharp, - "curtains_closed_rounded": Icons.curtains_closed_rounded, - "curtains_closed_outlined": Icons.curtains_closed_outlined, - "cut": Icons.cut, - "cut_sharp": Icons.cut_sharp, - "cut_rounded": Icons.cut_rounded, - "cut_outlined": Icons.cut_outlined, - "cyclone": Icons.cyclone, - "cyclone_sharp": Icons.cyclone_sharp, - "cyclone_rounded": Icons.cyclone_rounded, - "cyclone_outlined": Icons.cyclone_outlined, - "dangerous": Icons.dangerous, - "dangerous_sharp": Icons.dangerous_sharp, - "dangerous_rounded": Icons.dangerous_rounded, - "dangerous_outlined": Icons.dangerous_outlined, - "dark_mode": Icons.dark_mode, - "dark_mode_sharp": Icons.dark_mode_sharp, - "dark_mode_rounded": Icons.dark_mode_rounded, - "dark_mode_outlined": Icons.dark_mode_outlined, - "dashboard": Icons.dashboard, - "dashboard_sharp": Icons.dashboard_sharp, - "dashboard_rounded": Icons.dashboard_rounded, - "dashboard_outlined": Icons.dashboard_outlined, - "dashboard_customize": Icons.dashboard_customize, - "dashboard_customize_sharp": Icons.dashboard_customize_sharp, - "dashboard_customize_rounded": Icons.dashboard_customize_rounded, - "dashboard_customize_outlined": Icons.dashboard_customize_outlined, - "data_array": Icons.data_array, - "data_array_sharp": Icons.data_array_sharp, - "data_array_rounded": Icons.data_array_rounded, - "data_array_outlined": Icons.data_array_outlined, - "data_exploration": Icons.data_exploration, - "data_exploration_sharp": Icons.data_exploration_sharp, - "data_exploration_rounded": Icons.data_exploration_rounded, - "data_exploration_outlined": Icons.data_exploration_outlined, - "data_object": Icons.data_object, - "data_object_sharp": Icons.data_object_sharp, - "data_object_rounded": Icons.data_object_rounded, - "data_object_outlined": Icons.data_object_outlined, - "data_saver_off": Icons.data_saver_off, - "data_saver_off_sharp": Icons.data_saver_off_sharp, - "data_saver_off_rounded": Icons.data_saver_off_rounded, - "data_saver_off_outlined": Icons.data_saver_off_outlined, - "data_saver_on": Icons.data_saver_on, - "data_saver_on_sharp": Icons.data_saver_on_sharp, - "data_saver_on_rounded": Icons.data_saver_on_rounded, - "data_saver_on_outlined": Icons.data_saver_on_outlined, - "data_thresholding": Icons.data_thresholding, - "data_thresholding_sharp": Icons.data_thresholding_sharp, - "data_thresholding_rounded": Icons.data_thresholding_rounded, - "data_thresholding_outlined": Icons.data_thresholding_outlined, - "data_usage": Icons.data_usage, - "data_usage_sharp": Icons.data_usage_sharp, - "data_usage_rounded": Icons.data_usage_rounded, - "data_usage_outlined": Icons.data_usage_outlined, - "dataset": Icons.dataset, - "dataset_sharp": Icons.dataset_sharp, - "dataset_rounded": Icons.dataset_rounded, - "dataset_outlined": Icons.dataset_outlined, - "dataset_linked": Icons.dataset_linked, - "dataset_linked_sharp": Icons.dataset_linked_sharp, - "dataset_linked_rounded": Icons.dataset_linked_rounded, - "dataset_linked_outlined": Icons.dataset_linked_outlined, - "date_range": Icons.date_range, - "date_range_sharp": Icons.date_range_sharp, - "date_range_rounded": Icons.date_range_rounded, - "date_range_outlined": Icons.date_range_outlined, - "deblur": Icons.deblur, - "deblur_sharp": Icons.deblur_sharp, - "deblur_rounded": Icons.deblur_rounded, - "deblur_outlined": Icons.deblur_outlined, - "deck": Icons.deck, - "deck_sharp": Icons.deck_sharp, - "deck_rounded": Icons.deck_rounded, - "deck_outlined": Icons.deck_outlined, - "dehaze": Icons.dehaze, - "dehaze_sharp": Icons.dehaze_sharp, - "dehaze_rounded": Icons.dehaze_rounded, - "dehaze_outlined": Icons.dehaze_outlined, - "delete": Icons.delete, - "delete_sharp": Icons.delete_sharp, - "delete_rounded": Icons.delete_rounded, - "delete_outlined": Icons.delete_outlined, - "delete_forever": Icons.delete_forever, - "delete_forever_sharp": Icons.delete_forever_sharp, - "delete_forever_rounded": Icons.delete_forever_rounded, - "delete_forever_outlined": Icons.delete_forever_outlined, - "delete_outline": Icons.delete_outline, - "delete_outline_sharp": Icons.delete_outline_sharp, - "delete_outline_rounded": Icons.delete_outline_rounded, - "delete_outline_outlined": Icons.delete_outline_outlined, - "delete_sweep": Icons.delete_sweep, - "delete_sweep_sharp": Icons.delete_sweep_sharp, - "delete_sweep_rounded": Icons.delete_sweep_rounded, - "delete_sweep_outlined": Icons.delete_sweep_outlined, - "delivery_dining": Icons.delivery_dining, - "delivery_dining_sharp": Icons.delivery_dining_sharp, - "delivery_dining_rounded": Icons.delivery_dining_rounded, - "delivery_dining_outlined": Icons.delivery_dining_outlined, - "density_large": Icons.density_large, - "density_large_sharp": Icons.density_large_sharp, - "density_large_rounded": Icons.density_large_rounded, - "density_large_outlined": Icons.density_large_outlined, - "density_medium": Icons.density_medium, - "density_medium_sharp": Icons.density_medium_sharp, - "density_medium_rounded": Icons.density_medium_rounded, - "density_medium_outlined": Icons.density_medium_outlined, - "density_small": Icons.density_small, - "density_small_sharp": Icons.density_small_sharp, - "density_small_rounded": Icons.density_small_rounded, - "density_small_outlined": Icons.density_small_outlined, - "departure_board": Icons.departure_board, - "departure_board_sharp": Icons.departure_board_sharp, - "departure_board_rounded": Icons.departure_board_rounded, - "departure_board_outlined": Icons.departure_board_outlined, - "description": Icons.description, - "description_sharp": Icons.description_sharp, - "description_rounded": Icons.description_rounded, - "description_outlined": Icons.description_outlined, - "deselect": Icons.deselect, - "deselect_sharp": Icons.deselect_sharp, - "deselect_rounded": Icons.deselect_rounded, - "deselect_outlined": Icons.deselect_outlined, - "design_services": Icons.design_services, - "design_services_sharp": Icons.design_services_sharp, - "design_services_rounded": Icons.design_services_rounded, - "design_services_outlined": Icons.design_services_outlined, - "desk": Icons.desk, - "desk_sharp": Icons.desk_sharp, - "desk_rounded": Icons.desk_rounded, - "desk_outlined": Icons.desk_outlined, - "desktop_access_disabled": Icons.desktop_access_disabled, - "desktop_access_disabled_sharp": Icons.desktop_access_disabled_sharp, - "desktop_access_disabled_rounded": Icons.desktop_access_disabled_rounded, - "desktop_access_disabled_outlined": Icons.desktop_access_disabled_outlined, - "desktop_mac": Icons.desktop_mac, - "desktop_mac_sharp": Icons.desktop_mac_sharp, - "desktop_mac_rounded": Icons.desktop_mac_rounded, - "desktop_mac_outlined": Icons.desktop_mac_outlined, - "desktop_windows": Icons.desktop_windows, - "desktop_windows_sharp": Icons.desktop_windows_sharp, - "desktop_windows_rounded": Icons.desktop_windows_rounded, - "desktop_windows_outlined": Icons.desktop_windows_outlined, - "details": Icons.details, - "details_sharp": Icons.details_sharp, - "details_rounded": Icons.details_rounded, - "details_outlined": Icons.details_outlined, - "developer_board": Icons.developer_board, - "developer_board_sharp": Icons.developer_board_sharp, - "developer_board_rounded": Icons.developer_board_rounded, - "developer_board_outlined": Icons.developer_board_outlined, - "developer_board_off": Icons.developer_board_off, - "developer_board_off_sharp": Icons.developer_board_off_sharp, - "developer_board_off_rounded": Icons.developer_board_off_rounded, - "developer_board_off_outlined": Icons.developer_board_off_outlined, - "developer_mode": Icons.developer_mode, - "developer_mode_sharp": Icons.developer_mode_sharp, - "developer_mode_rounded": Icons.developer_mode_rounded, - "developer_mode_outlined": Icons.developer_mode_outlined, - "device_hub": Icons.device_hub, - "device_hub_sharp": Icons.device_hub_sharp, - "device_hub_rounded": Icons.device_hub_rounded, - "device_hub_outlined": Icons.device_hub_outlined, - "device_thermostat": Icons.device_thermostat, - "device_thermostat_sharp": Icons.device_thermostat_sharp, - "device_thermostat_rounded": Icons.device_thermostat_rounded, - "device_thermostat_outlined": Icons.device_thermostat_outlined, - "device_unknown": Icons.device_unknown, - "device_unknown_sharp": Icons.device_unknown_sharp, - "device_unknown_rounded": Icons.device_unknown_rounded, - "device_unknown_outlined": Icons.device_unknown_outlined, - "devices": Icons.devices, - "devices_sharp": Icons.devices_sharp, - "devices_rounded": Icons.devices_rounded, - "devices_outlined": Icons.devices_outlined, - "devices_fold": Icons.devices_fold, - "devices_fold_sharp": Icons.devices_fold_sharp, - "devices_fold_rounded": Icons.devices_fold_rounded, - "devices_fold_outlined": Icons.devices_fold_outlined, - "devices_other": Icons.devices_other, - "devices_other_sharp": Icons.devices_other_sharp, - "devices_other_rounded": Icons.devices_other_rounded, - "devices_other_outlined": Icons.devices_other_outlined, - "dew_point": Icons.dew_point, - "dialer_sip": Icons.dialer_sip, - "dialer_sip_sharp": Icons.dialer_sip_sharp, - "dialer_sip_rounded": Icons.dialer_sip_rounded, - "dialer_sip_outlined": Icons.dialer_sip_outlined, - "dialpad": Icons.dialpad, - "dialpad_sharp": Icons.dialpad_sharp, - "dialpad_rounded": Icons.dialpad_rounded, - "dialpad_outlined": Icons.dialpad_outlined, - "diamond": Icons.diamond, - "diamond_sharp": Icons.diamond_sharp, - "diamond_rounded": Icons.diamond_rounded, - "diamond_outlined": Icons.diamond_outlined, - "difference": Icons.difference, - "difference_sharp": Icons.difference_sharp, - "difference_rounded": Icons.difference_rounded, - "difference_outlined": Icons.difference_outlined, - "dining": Icons.dining, - "dining_sharp": Icons.dining_sharp, - "dining_rounded": Icons.dining_rounded, - "dining_outlined": Icons.dining_outlined, - "dinner_dining": Icons.dinner_dining, - "dinner_dining_sharp": Icons.dinner_dining_sharp, - "dinner_dining_rounded": Icons.dinner_dining_rounded, - "dinner_dining_outlined": Icons.dinner_dining_outlined, - "directions": Icons.directions, - "directions_sharp": Icons.directions_sharp, - "directions_rounded": Icons.directions_rounded, - "directions_outlined": Icons.directions_outlined, - "directions_bike": Icons.directions_bike, - "directions_bike_sharp": Icons.directions_bike_sharp, - "directions_bike_rounded": Icons.directions_bike_rounded, - "directions_bike_outlined": Icons.directions_bike_outlined, - "directions_boat": Icons.directions_boat, - "directions_boat_sharp": Icons.directions_boat_sharp, - "directions_boat_rounded": Icons.directions_boat_rounded, - "directions_boat_outlined": Icons.directions_boat_outlined, - "directions_boat_filled": Icons.directions_boat_filled, - "directions_boat_filled_sharp": Icons.directions_boat_filled_sharp, - "directions_boat_filled_rounded": Icons.directions_boat_filled_rounded, - "directions_boat_filled_outlined": Icons.directions_boat_filled_outlined, - "directions_bus": Icons.directions_bus, - "directions_bus_sharp": Icons.directions_bus_sharp, - "directions_bus_rounded": Icons.directions_bus_rounded, - "directions_bus_outlined": Icons.directions_bus_outlined, - "directions_bus_filled": Icons.directions_bus_filled, - "directions_bus_filled_sharp": Icons.directions_bus_filled_sharp, - "directions_bus_filled_rounded": Icons.directions_bus_filled_rounded, - "directions_bus_filled_outlined": Icons.directions_bus_filled_outlined, - "directions_car": Icons.directions_car, - "directions_car_sharp": Icons.directions_car_sharp, - "directions_car_rounded": Icons.directions_car_rounded, - "directions_car_outlined": Icons.directions_car_outlined, - "directions_car_filled": Icons.directions_car_filled, - "directions_car_filled_sharp": Icons.directions_car_filled_sharp, - "directions_car_filled_rounded": Icons.directions_car_filled_rounded, - "directions_car_filled_outlined": Icons.directions_car_filled_outlined, - "directions_ferry": Icons.directions_ferry, - "directions_ferry_sharp": Icons.directions_ferry_sharp, - "directions_ferry_rounded": Icons.directions_ferry_rounded, - "directions_ferry_outlined": Icons.directions_ferry_outlined, - "directions_off": Icons.directions_off, - "directions_off_sharp": Icons.directions_off_sharp, - "directions_off_rounded": Icons.directions_off_rounded, - "directions_off_outlined": Icons.directions_off_outlined, - "directions_railway": Icons.directions_railway, - "directions_railway_sharp": Icons.directions_railway_sharp, - "directions_railway_rounded": Icons.directions_railway_rounded, - "directions_railway_outlined": Icons.directions_railway_outlined, - "directions_railway_filled": Icons.directions_railway_filled, - "directions_railway_filled_sharp": Icons.directions_railway_filled_sharp, - "directions_railway_filled_rounded": Icons.directions_railway_filled_rounded, - "directions_railway_filled_outlined": - Icons.directions_railway_filled_outlined, - "directions_run": Icons.directions_run, - "directions_run_sharp": Icons.directions_run_sharp, - "directions_run_rounded": Icons.directions_run_rounded, - "directions_run_outlined": Icons.directions_run_outlined, - "directions_subway": Icons.directions_subway, - "directions_subway_sharp": Icons.directions_subway_sharp, - "directions_subway_rounded": Icons.directions_subway_rounded, - "directions_subway_outlined": Icons.directions_subway_outlined, - "directions_subway_filled": Icons.directions_subway_filled, - "directions_subway_filled_sharp": Icons.directions_subway_filled_sharp, - "directions_subway_filled_rounded": Icons.directions_subway_filled_rounded, - "directions_subway_filled_outlined": Icons.directions_subway_filled_outlined, - "directions_train": Icons.directions_train, - "directions_train_sharp": Icons.directions_train_sharp, - "directions_train_rounded": Icons.directions_train_rounded, - "directions_train_outlined": Icons.directions_train_outlined, - "directions_transit": Icons.directions_transit, - "directions_transit_sharp": Icons.directions_transit_sharp, - "directions_transit_rounded": Icons.directions_transit_rounded, - "directions_transit_outlined": Icons.directions_transit_outlined, - "directions_transit_filled": Icons.directions_transit_filled, - "directions_transit_filled_sharp": Icons.directions_transit_filled_sharp, - "directions_transit_filled_rounded": Icons.directions_transit_filled_rounded, - "directions_transit_filled_outlined": - Icons.directions_transit_filled_outlined, - "directions_walk": Icons.directions_walk, - "directions_walk_sharp": Icons.directions_walk_sharp, - "directions_walk_rounded": Icons.directions_walk_rounded, - "directions_walk_outlined": Icons.directions_walk_outlined, - "dirty_lens": Icons.dirty_lens, - "dirty_lens_sharp": Icons.dirty_lens_sharp, - "dirty_lens_rounded": Icons.dirty_lens_rounded, - "dirty_lens_outlined": Icons.dirty_lens_outlined, - "disabled_by_default": Icons.disabled_by_default, - "disabled_by_default_sharp": Icons.disabled_by_default_sharp, - "disabled_by_default_rounded": Icons.disabled_by_default_rounded, - "disabled_by_default_outlined": Icons.disabled_by_default_outlined, - "disabled_visible": Icons.disabled_visible, - "disabled_visible_sharp": Icons.disabled_visible_sharp, - "disabled_visible_rounded": Icons.disabled_visible_rounded, - "disabled_visible_outlined": Icons.disabled_visible_outlined, - "disc_full": Icons.disc_full, - "disc_full_sharp": Icons.disc_full_sharp, - "disc_full_rounded": Icons.disc_full_rounded, - "disc_full_outlined": Icons.disc_full_outlined, - "discord": Icons.discord, - "discord_sharp": Icons.discord_sharp, - "discord_rounded": Icons.discord_rounded, - "discord_outlined": Icons.discord_outlined, - "discount": Icons.discount, - "discount_sharp": Icons.discount_sharp, - "discount_rounded": Icons.discount_rounded, - "discount_outlined": Icons.discount_outlined, - "display_settings": Icons.display_settings, - "display_settings_sharp": Icons.display_settings_sharp, - "display_settings_rounded": Icons.display_settings_rounded, - "display_settings_outlined": Icons.display_settings_outlined, - "diversity_1": Icons.diversity_1, - "diversity_1_sharp": Icons.diversity_1_sharp, - "diversity_1_rounded": Icons.diversity_1_rounded, - "diversity_1_outlined": Icons.diversity_1_outlined, - "diversity_2": Icons.diversity_2, - "diversity_2_sharp": Icons.diversity_2_sharp, - "diversity_2_rounded": Icons.diversity_2_rounded, - "diversity_2_outlined": Icons.diversity_2_outlined, - "diversity_3": Icons.diversity_3, - "diversity_3_sharp": Icons.diversity_3_sharp, - "diversity_3_rounded": Icons.diversity_3_rounded, - "diversity_3_outlined": Icons.diversity_3_outlined, - "dnd_forwardslash": Icons.dnd_forwardslash, - "dnd_forwardslash_sharp": Icons.dnd_forwardslash_sharp, - "dnd_forwardslash_rounded": Icons.dnd_forwardslash_rounded, - "dnd_forwardslash_outlined": Icons.dnd_forwardslash_outlined, - "dns": Icons.dns, - "dns_sharp": Icons.dns_sharp, - "dns_rounded": Icons.dns_rounded, - "dns_outlined": Icons.dns_outlined, - "do_disturb": Icons.do_disturb, - "do_disturb_sharp": Icons.do_disturb_sharp, - "do_disturb_rounded": Icons.do_disturb_rounded, - "do_disturb_outlined": Icons.do_disturb_outlined, - "do_disturb_alt": Icons.do_disturb_alt, - "do_disturb_alt_sharp": Icons.do_disturb_alt_sharp, - "do_disturb_alt_rounded": Icons.do_disturb_alt_rounded, - "do_disturb_alt_outlined": Icons.do_disturb_alt_outlined, - "do_disturb_off": Icons.do_disturb_off, - "do_disturb_off_sharp": Icons.do_disturb_off_sharp, - "do_disturb_off_rounded": Icons.do_disturb_off_rounded, - "do_disturb_off_outlined": Icons.do_disturb_off_outlined, - "do_disturb_on": Icons.do_disturb_on, - "do_disturb_on_sharp": Icons.do_disturb_on_sharp, - "do_disturb_on_rounded": Icons.do_disturb_on_rounded, - "do_disturb_on_outlined": Icons.do_disturb_on_outlined, - "do_not_disturb": Icons.do_not_disturb, - "do_not_disturb_sharp": Icons.do_not_disturb_sharp, - "do_not_disturb_rounded": Icons.do_not_disturb_rounded, - "do_not_disturb_outlined": Icons.do_not_disturb_outlined, - "do_not_disturb_alt": Icons.do_not_disturb_alt, - "do_not_disturb_alt_sharp": Icons.do_not_disturb_alt_sharp, - "do_not_disturb_alt_rounded": Icons.do_not_disturb_alt_rounded, - "do_not_disturb_alt_outlined": Icons.do_not_disturb_alt_outlined, - "do_not_disturb_off": Icons.do_not_disturb_off, - "do_not_disturb_off_sharp": Icons.do_not_disturb_off_sharp, - "do_not_disturb_off_rounded": Icons.do_not_disturb_off_rounded, - "do_not_disturb_off_outlined": Icons.do_not_disturb_off_outlined, - "do_not_disturb_on": Icons.do_not_disturb_on, - "do_not_disturb_on_sharp": Icons.do_not_disturb_on_sharp, - "do_not_disturb_on_rounded": Icons.do_not_disturb_on_rounded, - "do_not_disturb_on_outlined": Icons.do_not_disturb_on_outlined, - "do_not_disturb_on_total_silence": Icons.do_not_disturb_on_total_silence, - "do_not_disturb_on_total_silence_sharp": - Icons.do_not_disturb_on_total_silence_sharp, - "do_not_disturb_on_total_silence_rounded": - Icons.do_not_disturb_on_total_silence_rounded, - "do_not_disturb_on_total_silence_outlined": - Icons.do_not_disturb_on_total_silence_outlined, - "do_not_step": Icons.do_not_step, - "do_not_step_sharp": Icons.do_not_step_sharp, - "do_not_step_rounded": Icons.do_not_step_rounded, - "do_not_step_outlined": Icons.do_not_step_outlined, - "do_not_touch": Icons.do_not_touch, - "do_not_touch_sharp": Icons.do_not_touch_sharp, - "do_not_touch_rounded": Icons.do_not_touch_rounded, - "do_not_touch_outlined": Icons.do_not_touch_outlined, - "dock": Icons.dock, - "dock_sharp": Icons.dock_sharp, - "dock_rounded": Icons.dock_rounded, - "dock_outlined": Icons.dock_outlined, - "document_scanner": Icons.document_scanner, - "document_scanner_sharp": Icons.document_scanner_sharp, - "document_scanner_rounded": Icons.document_scanner_rounded, - "document_scanner_outlined": Icons.document_scanner_outlined, - "domain": Icons.domain, - "domain_sharp": Icons.domain_sharp, - "domain_rounded": Icons.domain_rounded, - "domain_outlined": Icons.domain_outlined, - "domain_add": Icons.domain_add, - "domain_add_sharp": Icons.domain_add_sharp, - "domain_add_rounded": Icons.domain_add_rounded, - "domain_add_outlined": Icons.domain_add_outlined, - "domain_disabled": Icons.domain_disabled, - "domain_disabled_sharp": Icons.domain_disabled_sharp, - "domain_disabled_rounded": Icons.domain_disabled_rounded, - "domain_disabled_outlined": Icons.domain_disabled_outlined, - "domain_verification": Icons.domain_verification, - "domain_verification_sharp": Icons.domain_verification_sharp, - "domain_verification_rounded": Icons.domain_verification_rounded, - "domain_verification_outlined": Icons.domain_verification_outlined, - "done": Icons.done, - "done_sharp": Icons.done_sharp, - "done_rounded": Icons.done_rounded, - "done_outlined": Icons.done_outlined, - "done_all": Icons.done_all, - "done_all_sharp": Icons.done_all_sharp, - "done_all_rounded": Icons.done_all_rounded, - "done_all_outlined": Icons.done_all_outlined, - "done_outline": Icons.done_outline, - "done_outline_sharp": Icons.done_outline_sharp, - "done_outline_rounded": Icons.done_outline_rounded, - "done_outline_outlined": Icons.done_outline_outlined, - "donut_large": Icons.donut_large, - "donut_large_sharp": Icons.donut_large_sharp, - "donut_large_rounded": Icons.donut_large_rounded, - "donut_large_outlined": Icons.donut_large_outlined, - "donut_small": Icons.donut_small, - "donut_small_sharp": Icons.donut_small_sharp, - "donut_small_rounded": Icons.donut_small_rounded, - "donut_small_outlined": Icons.donut_small_outlined, - "door_back_door": Icons.door_back_door, - "door_back_door_sharp": Icons.door_back_door_sharp, - "door_back_door_rounded": Icons.door_back_door_rounded, - "door_back_door_outlined": Icons.door_back_door_outlined, - "door_front_door": Icons.door_front_door, - "door_front_door_sharp": Icons.door_front_door_sharp, - "door_front_door_rounded": Icons.door_front_door_rounded, - "door_front_door_outlined": Icons.door_front_door_outlined, - "door_sliding": Icons.door_sliding, - "door_sliding_sharp": Icons.door_sliding_sharp, - "door_sliding_rounded": Icons.door_sliding_rounded, - "door_sliding_outlined": Icons.door_sliding_outlined, - "doorbell": Icons.doorbell, - "doorbell_sharp": Icons.doorbell_sharp, - "doorbell_rounded": Icons.doorbell_rounded, - "doorbell_outlined": Icons.doorbell_outlined, - "double_arrow": Icons.double_arrow, - "double_arrow_sharp": Icons.double_arrow_sharp, - "double_arrow_rounded": Icons.double_arrow_rounded, - "double_arrow_outlined": Icons.double_arrow_outlined, - "downhill_skiing": Icons.downhill_skiing, - "downhill_skiing_sharp": Icons.downhill_skiing_sharp, - "downhill_skiing_rounded": Icons.downhill_skiing_rounded, - "downhill_skiing_outlined": Icons.downhill_skiing_outlined, - "download": Icons.download, - "download_sharp": Icons.download_sharp, - "download_rounded": Icons.download_rounded, - "download_outlined": Icons.download_outlined, - "download_done": Icons.download_done, - "download_done_sharp": Icons.download_done_sharp, - "download_done_rounded": Icons.download_done_rounded, - "download_done_outlined": Icons.download_done_outlined, - "download_for_offline": Icons.download_for_offline, - "download_for_offline_sharp": Icons.download_for_offline_sharp, - "download_for_offline_rounded": Icons.download_for_offline_rounded, - "download_for_offline_outlined": Icons.download_for_offline_outlined, - "downloading": Icons.downloading, - "downloading_sharp": Icons.downloading_sharp, - "downloading_rounded": Icons.downloading_rounded, - "downloading_outlined": Icons.downloading_outlined, - "drafts": Icons.drafts, - "drafts_sharp": Icons.drafts_sharp, - "drafts_rounded": Icons.drafts_rounded, - "drafts_outlined": Icons.drafts_outlined, - "drag_handle": Icons.drag_handle, - "drag_handle_sharp": Icons.drag_handle_sharp, - "drag_handle_rounded": Icons.drag_handle_rounded, - "drag_handle_outlined": Icons.drag_handle_outlined, - "drag_indicator": Icons.drag_indicator, - "drag_indicator_sharp": Icons.drag_indicator_sharp, - "drag_indicator_rounded": Icons.drag_indicator_rounded, - "drag_indicator_outlined": Icons.drag_indicator_outlined, - "draw": Icons.draw, - "draw_sharp": Icons.draw_sharp, - "draw_rounded": Icons.draw_rounded, - "draw_outlined": Icons.draw_outlined, - "drive_eta": Icons.drive_eta, - "drive_eta_sharp": Icons.drive_eta_sharp, - "drive_eta_rounded": Icons.drive_eta_rounded, - "drive_eta_outlined": Icons.drive_eta_outlined, - "drive_file_move": Icons.drive_file_move, - "drive_file_move_sharp": Icons.drive_file_move_sharp, - "drive_file_move_rounded": Icons.drive_file_move_rounded, - "drive_file_move_outlined": Icons.drive_file_move_outlined, - "drive_file_move_outline": Icons.drive_file_move_outline, - "drive_file_move_rtl": Icons.drive_file_move_rtl, - "drive_file_move_rtl_sharp": Icons.drive_file_move_rtl_sharp, - "drive_file_move_rtl_rounded": Icons.drive_file_move_rtl_rounded, - "drive_file_move_rtl_outlined": Icons.drive_file_move_rtl_outlined, - "drive_file_rename_outline": Icons.drive_file_rename_outline, - "drive_file_rename_outline_sharp": Icons.drive_file_rename_outline_sharp, - "drive_file_rename_outline_rounded": Icons.drive_file_rename_outline_rounded, - "drive_file_rename_outline_outlined": - Icons.drive_file_rename_outline_outlined, - "drive_folder_upload": Icons.drive_folder_upload, - "drive_folder_upload_sharp": Icons.drive_folder_upload_sharp, - "drive_folder_upload_rounded": Icons.drive_folder_upload_rounded, - "drive_folder_upload_outlined": Icons.drive_folder_upload_outlined, - "dry": Icons.dry, - "dry_sharp": Icons.dry_sharp, - "dry_rounded": Icons.dry_rounded, - "dry_outlined": Icons.dry_outlined, - "dry_cleaning": Icons.dry_cleaning, - "dry_cleaning_sharp": Icons.dry_cleaning_sharp, - "dry_cleaning_rounded": Icons.dry_cleaning_rounded, - "dry_cleaning_outlined": Icons.dry_cleaning_outlined, - "duo": Icons.duo, - "duo_sharp": Icons.duo_sharp, - "duo_rounded": Icons.duo_rounded, - "duo_outlined": Icons.duo_outlined, - "dvr": Icons.dvr, - "dvr_sharp": Icons.dvr_sharp, - "dvr_rounded": Icons.dvr_rounded, - "dvr_outlined": Icons.dvr_outlined, - "dynamic_feed": Icons.dynamic_feed, - "dynamic_feed_sharp": Icons.dynamic_feed_sharp, - "dynamic_feed_rounded": Icons.dynamic_feed_rounded, - "dynamic_feed_outlined": Icons.dynamic_feed_outlined, - "dynamic_form": Icons.dynamic_form, - "dynamic_form_sharp": Icons.dynamic_form_sharp, - "dynamic_form_rounded": Icons.dynamic_form_rounded, - "dynamic_form_outlined": Icons.dynamic_form_outlined, - "e_mobiledata": Icons.e_mobiledata, - "e_mobiledata_sharp": Icons.e_mobiledata_sharp, - "e_mobiledata_rounded": Icons.e_mobiledata_rounded, - "e_mobiledata_outlined": Icons.e_mobiledata_outlined, - "earbuds": Icons.earbuds, - "earbuds_sharp": Icons.earbuds_sharp, - "earbuds_rounded": Icons.earbuds_rounded, - "earbuds_outlined": Icons.earbuds_outlined, - "earbuds_battery": Icons.earbuds_battery, - "earbuds_battery_sharp": Icons.earbuds_battery_sharp, - "earbuds_battery_rounded": Icons.earbuds_battery_rounded, - "earbuds_battery_outlined": Icons.earbuds_battery_outlined, - "east": Icons.east, - "east_sharp": Icons.east_sharp, - "east_rounded": Icons.east_rounded, - "east_outlined": Icons.east_outlined, - "eco": Icons.eco, - "eco_sharp": Icons.eco_sharp, - "eco_rounded": Icons.eco_rounded, - "eco_outlined": Icons.eco_outlined, - "edgesensor_high": Icons.edgesensor_high, - "edgesensor_high_sharp": Icons.edgesensor_high_sharp, - "edgesensor_high_rounded": Icons.edgesensor_high_rounded, - "edgesensor_high_outlined": Icons.edgesensor_high_outlined, - "edgesensor_low": Icons.edgesensor_low, - "edgesensor_low_sharp": Icons.edgesensor_low_sharp, - "edgesensor_low_rounded": Icons.edgesensor_low_rounded, - "edgesensor_low_outlined": Icons.edgesensor_low_outlined, - "edit": Icons.edit, - "edit_sharp": Icons.edit_sharp, - "edit_rounded": Icons.edit_rounded, - "edit_outlined": Icons.edit_outlined, - "edit_attributes": Icons.edit_attributes, - "edit_attributes_sharp": Icons.edit_attributes_sharp, - "edit_attributes_rounded": Icons.edit_attributes_rounded, - "edit_attributes_outlined": Icons.edit_attributes_outlined, - "edit_calendar": Icons.edit_calendar, - "edit_calendar_sharp": Icons.edit_calendar_sharp, - "edit_calendar_rounded": Icons.edit_calendar_rounded, - "edit_calendar_outlined": Icons.edit_calendar_outlined, - "edit_document": Icons.edit_document, - "edit_location": Icons.edit_location, - "edit_location_sharp": Icons.edit_location_sharp, - "edit_location_rounded": Icons.edit_location_rounded, - "edit_location_outlined": Icons.edit_location_outlined, - "edit_location_alt": Icons.edit_location_alt, - "edit_location_alt_sharp": Icons.edit_location_alt_sharp, - "edit_location_alt_rounded": Icons.edit_location_alt_rounded, - "edit_location_alt_outlined": Icons.edit_location_alt_outlined, - "edit_note": Icons.edit_note, - "edit_note_sharp": Icons.edit_note_sharp, - "edit_note_rounded": Icons.edit_note_rounded, - "edit_note_outlined": Icons.edit_note_outlined, - "edit_notifications": Icons.edit_notifications, - "edit_notifications_sharp": Icons.edit_notifications_sharp, - "edit_notifications_rounded": Icons.edit_notifications_rounded, - "edit_notifications_outlined": Icons.edit_notifications_outlined, - "edit_off": Icons.edit_off, - "edit_off_sharp": Icons.edit_off_sharp, - "edit_off_rounded": Icons.edit_off_rounded, - "edit_off_outlined": Icons.edit_off_outlined, - "edit_road": Icons.edit_road, - "edit_road_sharp": Icons.edit_road_sharp, - "edit_road_rounded": Icons.edit_road_rounded, - "edit_road_outlined": Icons.edit_road_outlined, - "edit_square": Icons.edit_square, - "egg": Icons.egg, - "egg_sharp": Icons.egg_sharp, - "egg_rounded": Icons.egg_rounded, - "egg_outlined": Icons.egg_outlined, - "egg_alt": Icons.egg_alt, - "egg_alt_sharp": Icons.egg_alt_sharp, - "egg_alt_rounded": Icons.egg_alt_rounded, - "egg_alt_outlined": Icons.egg_alt_outlined, - "eject": Icons.eject, - "eject_sharp": Icons.eject_sharp, - "eject_rounded": Icons.eject_rounded, - "eject_outlined": Icons.eject_outlined, - "elderly": Icons.elderly, - "elderly_sharp": Icons.elderly_sharp, - "elderly_rounded": Icons.elderly_rounded, - "elderly_outlined": Icons.elderly_outlined, - "elderly_woman": Icons.elderly_woman, - "elderly_woman_sharp": Icons.elderly_woman_sharp, - "elderly_woman_rounded": Icons.elderly_woman_rounded, - "elderly_woman_outlined": Icons.elderly_woman_outlined, - "electric_bike": Icons.electric_bike, - "electric_bike_sharp": Icons.electric_bike_sharp, - "electric_bike_rounded": Icons.electric_bike_rounded, - "electric_bike_outlined": Icons.electric_bike_outlined, - "electric_bolt": Icons.electric_bolt, - "electric_bolt_sharp": Icons.electric_bolt_sharp, - "electric_bolt_rounded": Icons.electric_bolt_rounded, - "electric_bolt_outlined": Icons.electric_bolt_outlined, - "electric_car": Icons.electric_car, - "electric_car_sharp": Icons.electric_car_sharp, - "electric_car_rounded": Icons.electric_car_rounded, - "electric_car_outlined": Icons.electric_car_outlined, - "electric_meter": Icons.electric_meter, - "electric_meter_sharp": Icons.electric_meter_sharp, - "electric_meter_rounded": Icons.electric_meter_rounded, - "electric_meter_outlined": Icons.electric_meter_outlined, - "electric_moped": Icons.electric_moped, - "electric_moped_sharp": Icons.electric_moped_sharp, - "electric_moped_rounded": Icons.electric_moped_rounded, - "electric_moped_outlined": Icons.electric_moped_outlined, - "electric_rickshaw": Icons.electric_rickshaw, - "electric_rickshaw_sharp": Icons.electric_rickshaw_sharp, - "electric_rickshaw_rounded": Icons.electric_rickshaw_rounded, - "electric_rickshaw_outlined": Icons.electric_rickshaw_outlined, - "electric_scooter": Icons.electric_scooter, - "electric_scooter_sharp": Icons.electric_scooter_sharp, - "electric_scooter_rounded": Icons.electric_scooter_rounded, - "electric_scooter_outlined": Icons.electric_scooter_outlined, - "electrical_services": Icons.electrical_services, - "electrical_services_sharp": Icons.electrical_services_sharp, - "electrical_services_rounded": Icons.electrical_services_rounded, - "electrical_services_outlined": Icons.electrical_services_outlined, - "elevator": Icons.elevator, - "elevator_sharp": Icons.elevator_sharp, - "elevator_rounded": Icons.elevator_rounded, - "elevator_outlined": Icons.elevator_outlined, - "email": Icons.email, - "email_sharp": Icons.email_sharp, - "email_rounded": Icons.email_rounded, - "email_outlined": Icons.email_outlined, - "emergency": Icons.emergency, - "emergency_sharp": Icons.emergency_sharp, - "emergency_rounded": Icons.emergency_rounded, - "emergency_outlined": Icons.emergency_outlined, - "emergency_recording": Icons.emergency_recording, - "emergency_recording_sharp": Icons.emergency_recording_sharp, - "emergency_recording_rounded": Icons.emergency_recording_rounded, - "emergency_recording_outlined": Icons.emergency_recording_outlined, - "emergency_share": Icons.emergency_share, - "emergency_share_sharp": Icons.emergency_share_sharp, - "emergency_share_rounded": Icons.emergency_share_rounded, - "emergency_share_outlined": Icons.emergency_share_outlined, - "emoji_emotions": Icons.emoji_emotions, - "emoji_emotions_sharp": Icons.emoji_emotions_sharp, - "emoji_emotions_rounded": Icons.emoji_emotions_rounded, - "emoji_emotions_outlined": Icons.emoji_emotions_outlined, - "emoji_events": Icons.emoji_events, - "emoji_events_sharp": Icons.emoji_events_sharp, - "emoji_events_rounded": Icons.emoji_events_rounded, - "emoji_events_outlined": Icons.emoji_events_outlined, - "emoji_flags": Icons.emoji_flags, - "emoji_flags_sharp": Icons.emoji_flags_sharp, - "emoji_flags_rounded": Icons.emoji_flags_rounded, - "emoji_flags_outlined": Icons.emoji_flags_outlined, - "emoji_food_beverage": Icons.emoji_food_beverage, - "emoji_food_beverage_sharp": Icons.emoji_food_beverage_sharp, - "emoji_food_beverage_rounded": Icons.emoji_food_beverage_rounded, - "emoji_food_beverage_outlined": Icons.emoji_food_beverage_outlined, - "emoji_nature": Icons.emoji_nature, - "emoji_nature_sharp": Icons.emoji_nature_sharp, - "emoji_nature_rounded": Icons.emoji_nature_rounded, - "emoji_nature_outlined": Icons.emoji_nature_outlined, - "emoji_objects": Icons.emoji_objects, - "emoji_objects_sharp": Icons.emoji_objects_sharp, - "emoji_objects_rounded": Icons.emoji_objects_rounded, - "emoji_objects_outlined": Icons.emoji_objects_outlined, - "emoji_people": Icons.emoji_people, - "emoji_people_sharp": Icons.emoji_people_sharp, - "emoji_people_rounded": Icons.emoji_people_rounded, - "emoji_people_outlined": Icons.emoji_people_outlined, - "emoji_symbols": Icons.emoji_symbols, - "emoji_symbols_sharp": Icons.emoji_symbols_sharp, - "emoji_symbols_rounded": Icons.emoji_symbols_rounded, - "emoji_symbols_outlined": Icons.emoji_symbols_outlined, - "emoji_transportation": Icons.emoji_transportation, - "emoji_transportation_sharp": Icons.emoji_transportation_sharp, - "emoji_transportation_rounded": Icons.emoji_transportation_rounded, - "emoji_transportation_outlined": Icons.emoji_transportation_outlined, - "energy_savings_leaf": Icons.energy_savings_leaf, - "energy_savings_leaf_sharp": Icons.energy_savings_leaf_sharp, - "energy_savings_leaf_rounded": Icons.energy_savings_leaf_rounded, - "energy_savings_leaf_outlined": Icons.energy_savings_leaf_outlined, - "engineering": Icons.engineering, - "engineering_sharp": Icons.engineering_sharp, - "engineering_rounded": Icons.engineering_rounded, - "engineering_outlined": Icons.engineering_outlined, - "enhance_photo_translate": Icons.enhance_photo_translate, - "enhance_photo_translate_sharp": Icons.enhance_photo_translate_sharp, - "enhance_photo_translate_rounded": Icons.enhance_photo_translate_rounded, - "enhance_photo_translate_outlined": Icons.enhance_photo_translate_outlined, - "enhanced_encryption": Icons.enhanced_encryption, - "enhanced_encryption_sharp": Icons.enhanced_encryption_sharp, - "enhanced_encryption_rounded": Icons.enhanced_encryption_rounded, - "enhanced_encryption_outlined": Icons.enhanced_encryption_outlined, - "equalizer": Icons.equalizer, - "equalizer_sharp": Icons.equalizer_sharp, - "equalizer_rounded": Icons.equalizer_rounded, - "equalizer_outlined": Icons.equalizer_outlined, - "error": Icons.error, - "error_sharp": Icons.error_sharp, - "error_rounded": Icons.error_rounded, - "error_outlined": Icons.error_outlined, - "error_outline": Icons.error_outline, - "error_outline_sharp": Icons.error_outline_sharp, - "error_outline_rounded": Icons.error_outline_rounded, - "error_outline_outlined": Icons.error_outline_outlined, - "escalator": Icons.escalator, - "escalator_sharp": Icons.escalator_sharp, - "escalator_rounded": Icons.escalator_rounded, - "escalator_outlined": Icons.escalator_outlined, - "escalator_warning": Icons.escalator_warning, - "escalator_warning_sharp": Icons.escalator_warning_sharp, - "escalator_warning_rounded": Icons.escalator_warning_rounded, - "escalator_warning_outlined": Icons.escalator_warning_outlined, - "euro": Icons.euro, - "euro_sharp": Icons.euro_sharp, - "euro_rounded": Icons.euro_rounded, - "euro_outlined": Icons.euro_outlined, - "euro_symbol": Icons.euro_symbol, - "euro_symbol_sharp": Icons.euro_symbol_sharp, - "euro_symbol_rounded": Icons.euro_symbol_rounded, - "euro_symbol_outlined": Icons.euro_symbol_outlined, - "ev_station": Icons.ev_station, - "ev_station_sharp": Icons.ev_station_sharp, - "ev_station_rounded": Icons.ev_station_rounded, - "ev_station_outlined": Icons.ev_station_outlined, - "event": Icons.event, - "event_sharp": Icons.event_sharp, - "event_rounded": Icons.event_rounded, - "event_outlined": Icons.event_outlined, - "event_available": Icons.event_available, - "event_available_sharp": Icons.event_available_sharp, - "event_available_rounded": Icons.event_available_rounded, - "event_available_outlined": Icons.event_available_outlined, - "event_busy": Icons.event_busy, - "event_busy_sharp": Icons.event_busy_sharp, - "event_busy_rounded": Icons.event_busy_rounded, - "event_busy_outlined": Icons.event_busy_outlined, - "event_note": Icons.event_note, - "event_note_sharp": Icons.event_note_sharp, - "event_note_rounded": Icons.event_note_rounded, - "event_note_outlined": Icons.event_note_outlined, - "event_repeat": Icons.event_repeat, - "event_repeat_sharp": Icons.event_repeat_sharp, - "event_repeat_rounded": Icons.event_repeat_rounded, - "event_repeat_outlined": Icons.event_repeat_outlined, - "event_seat": Icons.event_seat, - "event_seat_sharp": Icons.event_seat_sharp, - "event_seat_rounded": Icons.event_seat_rounded, - "event_seat_outlined": Icons.event_seat_outlined, - "exit_to_app": Icons.exit_to_app, - "exit_to_app_sharp": Icons.exit_to_app_sharp, - "exit_to_app_rounded": Icons.exit_to_app_rounded, - "exit_to_app_outlined": Icons.exit_to_app_outlined, - "expand": Icons.expand, - "expand_sharp": Icons.expand_sharp, - "expand_rounded": Icons.expand_rounded, - "expand_outlined": Icons.expand_outlined, - "expand_circle_down": Icons.expand_circle_down, - "expand_circle_down_sharp": Icons.expand_circle_down_sharp, - "expand_circle_down_rounded": Icons.expand_circle_down_rounded, - "expand_circle_down_outlined": Icons.expand_circle_down_outlined, - "expand_less": Icons.expand_less, - "expand_less_sharp": Icons.expand_less_sharp, - "expand_less_rounded": Icons.expand_less_rounded, - "expand_less_outlined": Icons.expand_less_outlined, - "expand_more": Icons.expand_more, - "expand_more_sharp": Icons.expand_more_sharp, - "expand_more_rounded": Icons.expand_more_rounded, - "expand_more_outlined": Icons.expand_more_outlined, - "explicit": Icons.explicit, - "explicit_sharp": Icons.explicit_sharp, - "explicit_rounded": Icons.explicit_rounded, - "explicit_outlined": Icons.explicit_outlined, - "explore": Icons.explore, - "explore_sharp": Icons.explore_sharp, - "explore_rounded": Icons.explore_rounded, - "explore_outlined": Icons.explore_outlined, - "explore_off": Icons.explore_off, - "explore_off_sharp": Icons.explore_off_sharp, - "explore_off_rounded": Icons.explore_off_rounded, - "explore_off_outlined": Icons.explore_off_outlined, - "exposure": Icons.exposure, - "exposure_sharp": Icons.exposure_sharp, - "exposure_rounded": Icons.exposure_rounded, - "exposure_outlined": Icons.exposure_outlined, - "exposure_minus_1": Icons.exposure_minus_1, - "exposure_minus_1_sharp": Icons.exposure_minus_1_sharp, - "exposure_minus_1_rounded": Icons.exposure_minus_1_rounded, - "exposure_minus_1_outlined": Icons.exposure_minus_1_outlined, - "exposure_minus_2": Icons.exposure_minus_2, - "exposure_minus_2_sharp": Icons.exposure_minus_2_sharp, - "exposure_minus_2_rounded": Icons.exposure_minus_2_rounded, - "exposure_minus_2_outlined": Icons.exposure_minus_2_outlined, - "exposure_neg_1": Icons.exposure_neg_1, - "exposure_neg_1_sharp": Icons.exposure_neg_1_sharp, - "exposure_neg_1_rounded": Icons.exposure_neg_1_rounded, - "exposure_neg_1_outlined": Icons.exposure_neg_1_outlined, - "exposure_neg_2": Icons.exposure_neg_2, - "exposure_neg_2_sharp": Icons.exposure_neg_2_sharp, - "exposure_neg_2_rounded": Icons.exposure_neg_2_rounded, - "exposure_neg_2_outlined": Icons.exposure_neg_2_outlined, - "exposure_plus_1": Icons.exposure_plus_1, - "exposure_plus_1_sharp": Icons.exposure_plus_1_sharp, - "exposure_plus_1_rounded": Icons.exposure_plus_1_rounded, - "exposure_plus_1_outlined": Icons.exposure_plus_1_outlined, - "exposure_plus_2": Icons.exposure_plus_2, - "exposure_plus_2_sharp": Icons.exposure_plus_2_sharp, - "exposure_plus_2_rounded": Icons.exposure_plus_2_rounded, - "exposure_plus_2_outlined": Icons.exposure_plus_2_outlined, - "exposure_zero": Icons.exposure_zero, - "exposure_zero_sharp": Icons.exposure_zero_sharp, - "exposure_zero_rounded": Icons.exposure_zero_rounded, - "exposure_zero_outlined": Icons.exposure_zero_outlined, - "extension": Icons.extension, - "extension_sharp": Icons.extension_sharp, - "extension_rounded": Icons.extension_rounded, - "extension_outlined": Icons.extension_outlined, - "extension_off": Icons.extension_off, - "extension_off_sharp": Icons.extension_off_sharp, - "extension_off_rounded": Icons.extension_off_rounded, - "extension_off_outlined": Icons.extension_off_outlined, - "face": Icons.face, - "face_sharp": Icons.face_sharp, - "face_rounded": Icons.face_rounded, - "face_outlined": Icons.face_outlined, - "face_2": Icons.face_2, - "face_2_sharp": Icons.face_2_sharp, - "face_2_rounded": Icons.face_2_rounded, - "face_2_outlined": Icons.face_2_outlined, - "face_3": Icons.face_3, - "face_3_sharp": Icons.face_3_sharp, - "face_3_rounded": Icons.face_3_rounded, - "face_3_outlined": Icons.face_3_outlined, - "face_4": Icons.face_4, - "face_4_sharp": Icons.face_4_sharp, - "face_4_rounded": Icons.face_4_rounded, - "face_4_outlined": Icons.face_4_outlined, - "face_5": Icons.face_5, - "face_5_sharp": Icons.face_5_sharp, - "face_5_rounded": Icons.face_5_rounded, - "face_5_outlined": Icons.face_5_outlined, - "face_6": Icons.face_6, - "face_6_sharp": Icons.face_6_sharp, - "face_6_rounded": Icons.face_6_rounded, - "face_6_outlined": Icons.face_6_outlined, - "face_retouching_natural": Icons.face_retouching_natural, - "face_retouching_natural_sharp": Icons.face_retouching_natural_sharp, - "face_retouching_natural_rounded": Icons.face_retouching_natural_rounded, - "face_retouching_natural_outlined": Icons.face_retouching_natural_outlined, - "face_retouching_off": Icons.face_retouching_off, - "face_retouching_off_sharp": Icons.face_retouching_off_sharp, - "face_retouching_off_rounded": Icons.face_retouching_off_rounded, - "face_retouching_off_outlined": Icons.face_retouching_off_outlined, - "face_unlock_sharp": Icons.face_unlock_sharp, - "face_unlock_rounded": Icons.face_unlock_rounded, - "face_unlock_outlined": Icons.face_unlock_outlined, - "facebook": Icons.facebook, - "facebook_sharp": Icons.facebook_sharp, - "facebook_rounded": Icons.facebook_rounded, - "facebook_outlined": Icons.facebook_outlined, - "fact_check": Icons.fact_check, - "fact_check_sharp": Icons.fact_check_sharp, - "fact_check_rounded": Icons.fact_check_rounded, - "fact_check_outlined": Icons.fact_check_outlined, - "factory": Icons.factory, - "factory_sharp": Icons.factory_sharp, - "factory_rounded": Icons.factory_rounded, - "factory_outlined": Icons.factory_outlined, - "family_restroom": Icons.family_restroom, - "family_restroom_sharp": Icons.family_restroom_sharp, - "family_restroom_rounded": Icons.family_restroom_rounded, - "family_restroom_outlined": Icons.family_restroom_outlined, - "fast_forward": Icons.fast_forward, - "fast_forward_sharp": Icons.fast_forward_sharp, - "fast_forward_rounded": Icons.fast_forward_rounded, - "fast_forward_outlined": Icons.fast_forward_outlined, - "fast_rewind": Icons.fast_rewind, - "fast_rewind_sharp": Icons.fast_rewind_sharp, - "fast_rewind_rounded": Icons.fast_rewind_rounded, - "fast_rewind_outlined": Icons.fast_rewind_outlined, - "fastfood": Icons.fastfood, - "fastfood_sharp": Icons.fastfood_sharp, - "fastfood_rounded": Icons.fastfood_rounded, - "fastfood_outlined": Icons.fastfood_outlined, - "favorite": Icons.favorite, - "favorite_sharp": Icons.favorite_sharp, - "favorite_rounded": Icons.favorite_rounded, - "favorite_outlined": Icons.favorite_outlined, - "favorite_border": Icons.favorite_border, - "favorite_border_sharp": Icons.favorite_border_sharp, - "favorite_border_rounded": Icons.favorite_border_rounded, - "favorite_border_outlined": Icons.favorite_border_outlined, - "favorite_outline": Icons.favorite_outline, - "favorite_outline_sharp": Icons.favorite_outline_sharp, - "favorite_outline_rounded": Icons.favorite_outline_rounded, - "favorite_outline_outlined": Icons.favorite_outline_outlined, - "fax": Icons.fax, - "fax_sharp": Icons.fax_sharp, - "fax_rounded": Icons.fax_rounded, - "fax_outlined": Icons.fax_outlined, - "featured_play_list": Icons.featured_play_list, - "featured_play_list_sharp": Icons.featured_play_list_sharp, - "featured_play_list_rounded": Icons.featured_play_list_rounded, - "featured_play_list_outlined": Icons.featured_play_list_outlined, - "featured_video": Icons.featured_video, - "featured_video_sharp": Icons.featured_video_sharp, - "featured_video_rounded": Icons.featured_video_rounded, - "featured_video_outlined": Icons.featured_video_outlined, - "feed": Icons.feed, - "feed_sharp": Icons.feed_sharp, - "feed_rounded": Icons.feed_rounded, - "feed_outlined": Icons.feed_outlined, - "feedback": Icons.feedback, - "feedback_sharp": Icons.feedback_sharp, - "feedback_rounded": Icons.feedback_rounded, - "feedback_outlined": Icons.feedback_outlined, - "female": Icons.female, - "female_sharp": Icons.female_sharp, - "female_rounded": Icons.female_rounded, - "female_outlined": Icons.female_outlined, - "fence": Icons.fence, - "fence_sharp": Icons.fence_sharp, - "fence_rounded": Icons.fence_rounded, - "fence_outlined": Icons.fence_outlined, - "festival": Icons.festival, - "festival_sharp": Icons.festival_sharp, - "festival_rounded": Icons.festival_rounded, - "festival_outlined": Icons.festival_outlined, - "fiber_dvr": Icons.fiber_dvr, - "fiber_dvr_sharp": Icons.fiber_dvr_sharp, - "fiber_dvr_rounded": Icons.fiber_dvr_rounded, - "fiber_dvr_outlined": Icons.fiber_dvr_outlined, - "fiber_manual_record": Icons.fiber_manual_record, - "fiber_manual_record_sharp": Icons.fiber_manual_record_sharp, - "fiber_manual_record_rounded": Icons.fiber_manual_record_rounded, - "fiber_manual_record_outlined": Icons.fiber_manual_record_outlined, - "fiber_new": Icons.fiber_new, - "fiber_new_sharp": Icons.fiber_new_sharp, - "fiber_new_rounded": Icons.fiber_new_rounded, - "fiber_new_outlined": Icons.fiber_new_outlined, - "fiber_pin": Icons.fiber_pin, - "fiber_pin_sharp": Icons.fiber_pin_sharp, - "fiber_pin_rounded": Icons.fiber_pin_rounded, - "fiber_pin_outlined": Icons.fiber_pin_outlined, - "fiber_smart_record": Icons.fiber_smart_record, - "fiber_smart_record_sharp": Icons.fiber_smart_record_sharp, - "fiber_smart_record_rounded": Icons.fiber_smart_record_rounded, - "fiber_smart_record_outlined": Icons.fiber_smart_record_outlined, - "file_copy": Icons.file_copy, - "file_copy_sharp": Icons.file_copy_sharp, - "file_copy_rounded": Icons.file_copy_rounded, - "file_copy_outlined": Icons.file_copy_outlined, - "file_download": Icons.file_download, - "file_download_sharp": Icons.file_download_sharp, - "file_download_rounded": Icons.file_download_rounded, - "file_download_outlined": Icons.file_download_outlined, - "file_download_done": Icons.file_download_done, - "file_download_done_sharp": Icons.file_download_done_sharp, - "file_download_done_rounded": Icons.file_download_done_rounded, - "file_download_done_outlined": Icons.file_download_done_outlined, - "file_download_off": Icons.file_download_off, - "file_download_off_sharp": Icons.file_download_off_sharp, - "file_download_off_rounded": Icons.file_download_off_rounded, - "file_download_off_outlined": Icons.file_download_off_outlined, - "file_open": Icons.file_open, - "file_open_sharp": Icons.file_open_sharp, - "file_open_rounded": Icons.file_open_rounded, - "file_open_outlined": Icons.file_open_outlined, - "file_present": Icons.file_present, - "file_present_sharp": Icons.file_present_sharp, - "file_present_rounded": Icons.file_present_rounded, - "file_present_outlined": Icons.file_present_outlined, - "file_upload": Icons.file_upload, - "file_upload_sharp": Icons.file_upload_sharp, - "file_upload_rounded": Icons.file_upload_rounded, - "file_upload_outlined": Icons.file_upload_outlined, - "file_upload_off": Icons.file_upload_off, - "filter": Icons.filter, - "filter_sharp": Icons.filter_sharp, - "filter_rounded": Icons.filter_rounded, - "filter_outlined": Icons.filter_outlined, - "filter_1": Icons.filter_1, - "filter_1_sharp": Icons.filter_1_sharp, - "filter_1_rounded": Icons.filter_1_rounded, - "filter_1_outlined": Icons.filter_1_outlined, - "filter_2": Icons.filter_2, - "filter_2_sharp": Icons.filter_2_sharp, - "filter_2_rounded": Icons.filter_2_rounded, - "filter_2_outlined": Icons.filter_2_outlined, - "filter_3": Icons.filter_3, - "filter_3_sharp": Icons.filter_3_sharp, - "filter_3_rounded": Icons.filter_3_rounded, - "filter_3_outlined": Icons.filter_3_outlined, - "filter_4": Icons.filter_4, - "filter_4_sharp": Icons.filter_4_sharp, - "filter_4_rounded": Icons.filter_4_rounded, - "filter_4_outlined": Icons.filter_4_outlined, - "filter_5": Icons.filter_5, - "filter_5_sharp": Icons.filter_5_sharp, - "filter_5_rounded": Icons.filter_5_rounded, - "filter_5_outlined": Icons.filter_5_outlined, - "filter_6": Icons.filter_6, - "filter_6_sharp": Icons.filter_6_sharp, - "filter_6_rounded": Icons.filter_6_rounded, - "filter_6_outlined": Icons.filter_6_outlined, - "filter_7": Icons.filter_7, - "filter_7_sharp": Icons.filter_7_sharp, - "filter_7_rounded": Icons.filter_7_rounded, - "filter_7_outlined": Icons.filter_7_outlined, - "filter_8": Icons.filter_8, - "filter_8_sharp": Icons.filter_8_sharp, - "filter_8_rounded": Icons.filter_8_rounded, - "filter_8_outlined": Icons.filter_8_outlined, - "filter_9": Icons.filter_9, - "filter_9_sharp": Icons.filter_9_sharp, - "filter_9_rounded": Icons.filter_9_rounded, - "filter_9_outlined": Icons.filter_9_outlined, - "filter_9_plus": Icons.filter_9_plus, - "filter_9_plus_sharp": Icons.filter_9_plus_sharp, - "filter_9_plus_rounded": Icons.filter_9_plus_rounded, - "filter_9_plus_outlined": Icons.filter_9_plus_outlined, - "filter_alt": Icons.filter_alt, - "filter_alt_sharp": Icons.filter_alt_sharp, - "filter_alt_rounded": Icons.filter_alt_rounded, - "filter_alt_outlined": Icons.filter_alt_outlined, - "filter_alt_off": Icons.filter_alt_off, - "filter_alt_off_sharp": Icons.filter_alt_off_sharp, - "filter_alt_off_rounded": Icons.filter_alt_off_rounded, - "filter_alt_off_outlined": Icons.filter_alt_off_outlined, - "filter_b_and_w": Icons.filter_b_and_w, - "filter_b_and_w_sharp": Icons.filter_b_and_w_sharp, - "filter_b_and_w_rounded": Icons.filter_b_and_w_rounded, - "filter_b_and_w_outlined": Icons.filter_b_and_w_outlined, - "filter_center_focus": Icons.filter_center_focus, - "filter_center_focus_sharp": Icons.filter_center_focus_sharp, - "filter_center_focus_rounded": Icons.filter_center_focus_rounded, - "filter_center_focus_outlined": Icons.filter_center_focus_outlined, - "filter_drama": Icons.filter_drama, - "filter_drama_sharp": Icons.filter_drama_sharp, - "filter_drama_rounded": Icons.filter_drama_rounded, - "filter_drama_outlined": Icons.filter_drama_outlined, - "filter_frames": Icons.filter_frames, - "filter_frames_sharp": Icons.filter_frames_sharp, - "filter_frames_rounded": Icons.filter_frames_rounded, - "filter_frames_outlined": Icons.filter_frames_outlined, - "filter_hdr": Icons.filter_hdr, - "filter_hdr_sharp": Icons.filter_hdr_sharp, - "filter_hdr_rounded": Icons.filter_hdr_rounded, - "filter_hdr_outlined": Icons.filter_hdr_outlined, - "filter_list": Icons.filter_list, - "filter_list_sharp": Icons.filter_list_sharp, - "filter_list_rounded": Icons.filter_list_rounded, - "filter_list_outlined": Icons.filter_list_outlined, - "filter_list_alt": Icons.filter_list_alt, - "filter_list_off": Icons.filter_list_off, - "filter_list_off_sharp": Icons.filter_list_off_sharp, - "filter_list_off_rounded": Icons.filter_list_off_rounded, - "filter_list_off_outlined": Icons.filter_list_off_outlined, - "filter_none": Icons.filter_none, - "filter_none_sharp": Icons.filter_none_sharp, - "filter_none_rounded": Icons.filter_none_rounded, - "filter_none_outlined": Icons.filter_none_outlined, - "filter_tilt_shift": Icons.filter_tilt_shift, - "filter_tilt_shift_sharp": Icons.filter_tilt_shift_sharp, - "filter_tilt_shift_rounded": Icons.filter_tilt_shift_rounded, - "filter_tilt_shift_outlined": Icons.filter_tilt_shift_outlined, - "filter_vintage": Icons.filter_vintage, - "filter_vintage_sharp": Icons.filter_vintage_sharp, - "filter_vintage_rounded": Icons.filter_vintage_rounded, - "filter_vintage_outlined": Icons.filter_vintage_outlined, - "find_in_page": Icons.find_in_page, - "find_in_page_sharp": Icons.find_in_page_sharp, - "find_in_page_rounded": Icons.find_in_page_rounded, - "find_in_page_outlined": Icons.find_in_page_outlined, - "find_replace": Icons.find_replace, - "find_replace_sharp": Icons.find_replace_sharp, - "find_replace_rounded": Icons.find_replace_rounded, - "find_replace_outlined": Icons.find_replace_outlined, - "fingerprint": Icons.fingerprint, - "fingerprint_sharp": Icons.fingerprint_sharp, - "fingerprint_rounded": Icons.fingerprint_rounded, - "fingerprint_outlined": Icons.fingerprint_outlined, - "fire_extinguisher": Icons.fire_extinguisher, - "fire_extinguisher_sharp": Icons.fire_extinguisher_sharp, - "fire_extinguisher_rounded": Icons.fire_extinguisher_rounded, - "fire_extinguisher_outlined": Icons.fire_extinguisher_outlined, - "fire_hydrant": Icons.fire_hydrant, - "fire_hydrant_alt": Icons.fire_hydrant_alt, - "fire_hydrant_alt_sharp": Icons.fire_hydrant_alt_sharp, - "fire_hydrant_alt_rounded": Icons.fire_hydrant_alt_rounded, - "fire_hydrant_alt_outlined": Icons.fire_hydrant_alt_outlined, - "fire_truck": Icons.fire_truck, - "fire_truck_sharp": Icons.fire_truck_sharp, - "fire_truck_rounded": Icons.fire_truck_rounded, - "fire_truck_outlined": Icons.fire_truck_outlined, - "fireplace": Icons.fireplace, - "fireplace_sharp": Icons.fireplace_sharp, - "fireplace_rounded": Icons.fireplace_rounded, - "fireplace_outlined": Icons.fireplace_outlined, - "first_page": Icons.first_page, - "first_page_sharp": Icons.first_page_sharp, - "first_page_rounded": Icons.first_page_rounded, - "first_page_outlined": Icons.first_page_outlined, - "fit_screen": Icons.fit_screen, - "fit_screen_sharp": Icons.fit_screen_sharp, - "fit_screen_rounded": Icons.fit_screen_rounded, - "fit_screen_outlined": Icons.fit_screen_outlined, - "fitbit": Icons.fitbit, - "fitbit_sharp": Icons.fitbit_sharp, - "fitbit_rounded": Icons.fitbit_rounded, - "fitbit_outlined": Icons.fitbit_outlined, - "fitness_center": Icons.fitness_center, - "fitness_center_sharp": Icons.fitness_center_sharp, - "fitness_center_rounded": Icons.fitness_center_rounded, - "fitness_center_outlined": Icons.fitness_center_outlined, - "flag": Icons.flag, - "flag_sharp": Icons.flag_sharp, - "flag_rounded": Icons.flag_rounded, - "flag_outlined": Icons.flag_outlined, - "flag_circle": Icons.flag_circle, - "flag_circle_sharp": Icons.flag_circle_sharp, - "flag_circle_rounded": Icons.flag_circle_rounded, - "flag_circle_outlined": Icons.flag_circle_outlined, - "flaky": Icons.flaky, - "flaky_sharp": Icons.flaky_sharp, - "flaky_rounded": Icons.flaky_rounded, - "flaky_outlined": Icons.flaky_outlined, - "flare": Icons.flare, - "flare_sharp": Icons.flare_sharp, - "flare_rounded": Icons.flare_rounded, - "flare_outlined": Icons.flare_outlined, - "flash_auto": Icons.flash_auto, - "flash_auto_sharp": Icons.flash_auto_sharp, - "flash_auto_rounded": Icons.flash_auto_rounded, - "flash_auto_outlined": Icons.flash_auto_outlined, - "flash_off": Icons.flash_off, - "flash_off_sharp": Icons.flash_off_sharp, - "flash_off_rounded": Icons.flash_off_rounded, - "flash_off_outlined": Icons.flash_off_outlined, - "flash_on": Icons.flash_on, - "flash_on_sharp": Icons.flash_on_sharp, - "flash_on_rounded": Icons.flash_on_rounded, - "flash_on_outlined": Icons.flash_on_outlined, - "flashlight_off": Icons.flashlight_off, - "flashlight_off_sharp": Icons.flashlight_off_sharp, - "flashlight_off_rounded": Icons.flashlight_off_rounded, - "flashlight_off_outlined": Icons.flashlight_off_outlined, - "flashlight_on": Icons.flashlight_on, - "flashlight_on_sharp": Icons.flashlight_on_sharp, - "flashlight_on_rounded": Icons.flashlight_on_rounded, - "flashlight_on_outlined": Icons.flashlight_on_outlined, - "flatware": Icons.flatware, - "flatware_sharp": Icons.flatware_sharp, - "flatware_rounded": Icons.flatware_rounded, - "flatware_outlined": Icons.flatware_outlined, - "flight": Icons.flight, - "flight_sharp": Icons.flight_sharp, - "flight_rounded": Icons.flight_rounded, - "flight_outlined": Icons.flight_outlined, - "flight_class": Icons.flight_class, - "flight_class_sharp": Icons.flight_class_sharp, - "flight_class_rounded": Icons.flight_class_rounded, - "flight_class_outlined": Icons.flight_class_outlined, - "flight_land": Icons.flight_land, - "flight_land_sharp": Icons.flight_land_sharp, - "flight_land_rounded": Icons.flight_land_rounded, - "flight_land_outlined": Icons.flight_land_outlined, - "flight_takeoff": Icons.flight_takeoff, - "flight_takeoff_sharp": Icons.flight_takeoff_sharp, - "flight_takeoff_rounded": Icons.flight_takeoff_rounded, - "flight_takeoff_outlined": Icons.flight_takeoff_outlined, - "flip": Icons.flip, - "flip_sharp": Icons.flip_sharp, - "flip_rounded": Icons.flip_rounded, - "flip_outlined": Icons.flip_outlined, - "flip_camera_android": Icons.flip_camera_android, - "flip_camera_android_sharp": Icons.flip_camera_android_sharp, - "flip_camera_android_rounded": Icons.flip_camera_android_rounded, - "flip_camera_android_outlined": Icons.flip_camera_android_outlined, - "flip_camera_ios": Icons.flip_camera_ios, - "flip_camera_ios_sharp": Icons.flip_camera_ios_sharp, - "flip_camera_ios_rounded": Icons.flip_camera_ios_rounded, - "flip_camera_ios_outlined": Icons.flip_camera_ios_outlined, - "flip_to_back": Icons.flip_to_back, - "flip_to_back_sharp": Icons.flip_to_back_sharp, - "flip_to_back_rounded": Icons.flip_to_back_rounded, - "flip_to_back_outlined": Icons.flip_to_back_outlined, - "flip_to_front": Icons.flip_to_front, - "flip_to_front_sharp": Icons.flip_to_front_sharp, - "flip_to_front_rounded": Icons.flip_to_front_rounded, - "flip_to_front_outlined": Icons.flip_to_front_outlined, - "flood": Icons.flood, - "flood_sharp": Icons.flood_sharp, - "flood_rounded": Icons.flood_rounded, - "flood_outlined": Icons.flood_outlined, - "flourescent": Icons.flourescent, - "flourescent_sharp": Icons.flourescent_sharp, - "flourescent_rounded": Icons.flourescent_rounded, - "flourescent_outlined": Icons.flourescent_outlined, - "fluorescent": Icons.fluorescent, - "fluorescent_sharp": Icons.fluorescent_sharp, - "fluorescent_rounded": Icons.fluorescent_rounded, - "fluorescent_outlined": Icons.fluorescent_outlined, - "flutter_dash": Icons.flutter_dash, - "flutter_dash_sharp": Icons.flutter_dash_sharp, - "flutter_dash_rounded": Icons.flutter_dash_rounded, - "flutter_dash_outlined": Icons.flutter_dash_outlined, - "fmd_bad": Icons.fmd_bad, - "fmd_bad_sharp": Icons.fmd_bad_sharp, - "fmd_bad_rounded": Icons.fmd_bad_rounded, - "fmd_bad_outlined": Icons.fmd_bad_outlined, - "fmd_good": Icons.fmd_good, - "fmd_good_sharp": Icons.fmd_good_sharp, - "fmd_good_rounded": Icons.fmd_good_rounded, - "fmd_good_outlined": Icons.fmd_good_outlined, - "foggy": Icons.foggy, - "folder": Icons.folder, - "folder_sharp": Icons.folder_sharp, - "folder_rounded": Icons.folder_rounded, - "folder_outlined": Icons.folder_outlined, - "folder_copy": Icons.folder_copy, - "folder_copy_sharp": Icons.folder_copy_sharp, - "folder_copy_rounded": Icons.folder_copy_rounded, - "folder_copy_outlined": Icons.folder_copy_outlined, - "folder_delete": Icons.folder_delete, - "folder_delete_sharp": Icons.folder_delete_sharp, - "folder_delete_rounded": Icons.folder_delete_rounded, - "folder_delete_outlined": Icons.folder_delete_outlined, - "folder_off": Icons.folder_off, - "folder_off_sharp": Icons.folder_off_sharp, - "folder_off_rounded": Icons.folder_off_rounded, - "folder_off_outlined": Icons.folder_off_outlined, - "folder_open": Icons.folder_open, - "folder_open_sharp": Icons.folder_open_sharp, - "folder_open_rounded": Icons.folder_open_rounded, - "folder_open_outlined": Icons.folder_open_outlined, - "folder_shared": Icons.folder_shared, - "folder_shared_sharp": Icons.folder_shared_sharp, - "folder_shared_rounded": Icons.folder_shared_rounded, - "folder_shared_outlined": Icons.folder_shared_outlined, - "folder_special": Icons.folder_special, - "folder_special_sharp": Icons.folder_special_sharp, - "folder_special_rounded": Icons.folder_special_rounded, - "folder_special_outlined": Icons.folder_special_outlined, - "folder_zip": Icons.folder_zip, - "folder_zip_sharp": Icons.folder_zip_sharp, - "folder_zip_rounded": Icons.folder_zip_rounded, - "folder_zip_outlined": Icons.folder_zip_outlined, - "follow_the_signs": Icons.follow_the_signs, - "follow_the_signs_sharp": Icons.follow_the_signs_sharp, - "follow_the_signs_rounded": Icons.follow_the_signs_rounded, - "follow_the_signs_outlined": Icons.follow_the_signs_outlined, - "font_download": Icons.font_download, - "font_download_sharp": Icons.font_download_sharp, - "font_download_rounded": Icons.font_download_rounded, - "font_download_outlined": Icons.font_download_outlined, - "font_download_off": Icons.font_download_off, - "font_download_off_sharp": Icons.font_download_off_sharp, - "font_download_off_rounded": Icons.font_download_off_rounded, - "font_download_off_outlined": Icons.font_download_off_outlined, - "food_bank": Icons.food_bank, - "food_bank_sharp": Icons.food_bank_sharp, - "food_bank_rounded": Icons.food_bank_rounded, - "food_bank_outlined": Icons.food_bank_outlined, - "forest": Icons.forest, - "forest_sharp": Icons.forest_sharp, - "forest_rounded": Icons.forest_rounded, - "forest_outlined": Icons.forest_outlined, - "fork_left": Icons.fork_left, - "fork_left_sharp": Icons.fork_left_sharp, - "fork_left_rounded": Icons.fork_left_rounded, - "fork_left_outlined": Icons.fork_left_outlined, - "fork_right": Icons.fork_right, - "fork_right_sharp": Icons.fork_right_sharp, - "fork_right_rounded": Icons.fork_right_rounded, - "fork_right_outlined": Icons.fork_right_outlined, - "forklift": Icons.forklift, - "format_align_center": Icons.format_align_center, - "format_align_center_sharp": Icons.format_align_center_sharp, - "format_align_center_rounded": Icons.format_align_center_rounded, - "format_align_center_outlined": Icons.format_align_center_outlined, - "format_align_justify": Icons.format_align_justify, - "format_align_justify_sharp": Icons.format_align_justify_sharp, - "format_align_justify_rounded": Icons.format_align_justify_rounded, - "format_align_justify_outlined": Icons.format_align_justify_outlined, - "format_align_left": Icons.format_align_left, - "format_align_left_sharp": Icons.format_align_left_sharp, - "format_align_left_rounded": Icons.format_align_left_rounded, - "format_align_left_outlined": Icons.format_align_left_outlined, - "format_align_right": Icons.format_align_right, - "format_align_right_sharp": Icons.format_align_right_sharp, - "format_align_right_rounded": Icons.format_align_right_rounded, - "format_align_right_outlined": Icons.format_align_right_outlined, - "format_bold": Icons.format_bold, - "format_bold_sharp": Icons.format_bold_sharp, - "format_bold_rounded": Icons.format_bold_rounded, - "format_bold_outlined": Icons.format_bold_outlined, - "format_clear": Icons.format_clear, - "format_clear_sharp": Icons.format_clear_sharp, - "format_clear_rounded": Icons.format_clear_rounded, - "format_clear_outlined": Icons.format_clear_outlined, - "format_color_fill": Icons.format_color_fill, - "format_color_fill_sharp": Icons.format_color_fill_sharp, - "format_color_fill_rounded": Icons.format_color_fill_rounded, - "format_color_fill_outlined": Icons.format_color_fill_outlined, - "format_color_reset": Icons.format_color_reset, - "format_color_reset_sharp": Icons.format_color_reset_sharp, - "format_color_reset_rounded": Icons.format_color_reset_rounded, - "format_color_reset_outlined": Icons.format_color_reset_outlined, - "format_color_text": Icons.format_color_text, - "format_color_text_sharp": Icons.format_color_text_sharp, - "format_color_text_rounded": Icons.format_color_text_rounded, - "format_color_text_outlined": Icons.format_color_text_outlined, - "format_indent_decrease": Icons.format_indent_decrease, - "format_indent_decrease_sharp": Icons.format_indent_decrease_sharp, - "format_indent_decrease_rounded": Icons.format_indent_decrease_rounded, - "format_indent_decrease_outlined": Icons.format_indent_decrease_outlined, - "format_indent_increase": Icons.format_indent_increase, - "format_indent_increase_sharp": Icons.format_indent_increase_sharp, - "format_indent_increase_rounded": Icons.format_indent_increase_rounded, - "format_indent_increase_outlined": Icons.format_indent_increase_outlined, - "format_italic": Icons.format_italic, - "format_italic_sharp": Icons.format_italic_sharp, - "format_italic_rounded": Icons.format_italic_rounded, - "format_italic_outlined": Icons.format_italic_outlined, - "format_line_spacing": Icons.format_line_spacing, - "format_line_spacing_sharp": Icons.format_line_spacing_sharp, - "format_line_spacing_rounded": Icons.format_line_spacing_rounded, - "format_line_spacing_outlined": Icons.format_line_spacing_outlined, - "format_list_bulleted": Icons.format_list_bulleted, - "format_list_bulleted_sharp": Icons.format_list_bulleted_sharp, - "format_list_bulleted_rounded": Icons.format_list_bulleted_rounded, - "format_list_bulleted_outlined": Icons.format_list_bulleted_outlined, - "format_list_bulleted_add": Icons.format_list_bulleted_add, - "format_list_numbered": Icons.format_list_numbered, - "format_list_numbered_sharp": Icons.format_list_numbered_sharp, - "format_list_numbered_rounded": Icons.format_list_numbered_rounded, - "format_list_numbered_outlined": Icons.format_list_numbered_outlined, - "format_list_numbered_rtl": Icons.format_list_numbered_rtl, - "format_list_numbered_rtl_sharp": Icons.format_list_numbered_rtl_sharp, - "format_list_numbered_rtl_rounded": Icons.format_list_numbered_rtl_rounded, - "format_list_numbered_rtl_outlined": Icons.format_list_numbered_rtl_outlined, - "format_overline": Icons.format_overline, - "format_overline_sharp": Icons.format_overline_sharp, - "format_overline_rounded": Icons.format_overline_rounded, - "format_overline_outlined": Icons.format_overline_outlined, - "format_paint": Icons.format_paint, - "format_paint_sharp": Icons.format_paint_sharp, - "format_paint_rounded": Icons.format_paint_rounded, - "format_paint_outlined": Icons.format_paint_outlined, - "format_quote": Icons.format_quote, - "format_quote_sharp": Icons.format_quote_sharp, - "format_quote_rounded": Icons.format_quote_rounded, - "format_quote_outlined": Icons.format_quote_outlined, - "format_shapes": Icons.format_shapes, - "format_shapes_sharp": Icons.format_shapes_sharp, - "format_shapes_rounded": Icons.format_shapes_rounded, - "format_shapes_outlined": Icons.format_shapes_outlined, - "format_size": Icons.format_size, - "format_size_sharp": Icons.format_size_sharp, - "format_size_rounded": Icons.format_size_rounded, - "format_size_outlined": Icons.format_size_outlined, - "format_strikethrough": Icons.format_strikethrough, - "format_strikethrough_sharp": Icons.format_strikethrough_sharp, - "format_strikethrough_rounded": Icons.format_strikethrough_rounded, - "format_strikethrough_outlined": Icons.format_strikethrough_outlined, - "format_textdirection_l_to_r": Icons.format_textdirection_l_to_r, - "format_textdirection_l_to_r_sharp": Icons.format_textdirection_l_to_r_sharp, - "format_textdirection_l_to_r_rounded": - Icons.format_textdirection_l_to_r_rounded, - "format_textdirection_l_to_r_outlined": - Icons.format_textdirection_l_to_r_outlined, - "format_textdirection_r_to_l": Icons.format_textdirection_r_to_l, - "format_textdirection_r_to_l_sharp": Icons.format_textdirection_r_to_l_sharp, - "format_textdirection_r_to_l_rounded": - Icons.format_textdirection_r_to_l_rounded, - "format_textdirection_r_to_l_outlined": - Icons.format_textdirection_r_to_l_outlined, - "format_underline": Icons.format_underline, - "format_underline_sharp": Icons.format_underline_sharp, - "format_underline_rounded": Icons.format_underline_rounded, - "format_underline_outlined": Icons.format_underline_outlined, - "format_underlined": Icons.format_underlined, - "format_underlined_sharp": Icons.format_underlined_sharp, - "format_underlined_rounded": Icons.format_underlined_rounded, - "format_underlined_outlined": Icons.format_underlined_outlined, - "fort": Icons.fort, - "fort_sharp": Icons.fort_sharp, - "fort_rounded": Icons.fort_rounded, - "fort_outlined": Icons.fort_outlined, - "forum": Icons.forum, - "forum_sharp": Icons.forum_sharp, - "forum_rounded": Icons.forum_rounded, - "forum_outlined": Icons.forum_outlined, - "forward": Icons.forward, - "forward_sharp": Icons.forward_sharp, - "forward_rounded": Icons.forward_rounded, - "forward_outlined": Icons.forward_outlined, - "forward_10": Icons.forward_10, - "forward_10_sharp": Icons.forward_10_sharp, - "forward_10_rounded": Icons.forward_10_rounded, - "forward_10_outlined": Icons.forward_10_outlined, - "forward_30": Icons.forward_30, - "forward_30_sharp": Icons.forward_30_sharp, - "forward_30_rounded": Icons.forward_30_rounded, - "forward_30_outlined": Icons.forward_30_outlined, - "forward_5": Icons.forward_5, - "forward_5_sharp": Icons.forward_5_sharp, - "forward_5_rounded": Icons.forward_5_rounded, - "forward_5_outlined": Icons.forward_5_outlined, - "forward_to_inbox": Icons.forward_to_inbox, - "forward_to_inbox_sharp": Icons.forward_to_inbox_sharp, - "forward_to_inbox_rounded": Icons.forward_to_inbox_rounded, - "forward_to_inbox_outlined": Icons.forward_to_inbox_outlined, - "foundation": Icons.foundation, - "foundation_sharp": Icons.foundation_sharp, - "foundation_rounded": Icons.foundation_rounded, - "foundation_outlined": Icons.foundation_outlined, - "free_breakfast": Icons.free_breakfast, - "free_breakfast_sharp": Icons.free_breakfast_sharp, - "free_breakfast_rounded": Icons.free_breakfast_rounded, - "free_breakfast_outlined": Icons.free_breakfast_outlined, - "free_cancellation": Icons.free_cancellation, - "free_cancellation_sharp": Icons.free_cancellation_sharp, - "free_cancellation_rounded": Icons.free_cancellation_rounded, - "free_cancellation_outlined": Icons.free_cancellation_outlined, - "front_hand": Icons.front_hand, - "front_hand_sharp": Icons.front_hand_sharp, - "front_hand_rounded": Icons.front_hand_rounded, - "front_hand_outlined": Icons.front_hand_outlined, - "front_loader": Icons.front_loader, - "fullscreen": Icons.fullscreen, - "fullscreen_sharp": Icons.fullscreen_sharp, - "fullscreen_rounded": Icons.fullscreen_rounded, - "fullscreen_outlined": Icons.fullscreen_outlined, - "fullscreen_exit": Icons.fullscreen_exit, - "fullscreen_exit_sharp": Icons.fullscreen_exit_sharp, - "fullscreen_exit_rounded": Icons.fullscreen_exit_rounded, - "fullscreen_exit_outlined": Icons.fullscreen_exit_outlined, - "functions": Icons.functions, - "functions_sharp": Icons.functions_sharp, - "functions_rounded": Icons.functions_rounded, - "functions_outlined": Icons.functions_outlined, - "g_mobiledata": Icons.g_mobiledata, - "g_mobiledata_sharp": Icons.g_mobiledata_sharp, - "g_mobiledata_rounded": Icons.g_mobiledata_rounded, - "g_mobiledata_outlined": Icons.g_mobiledata_outlined, - "g_translate": Icons.g_translate, - "g_translate_sharp": Icons.g_translate_sharp, - "g_translate_rounded": Icons.g_translate_rounded, - "g_translate_outlined": Icons.g_translate_outlined, - "gamepad": Icons.gamepad, - "gamepad_sharp": Icons.gamepad_sharp, - "gamepad_rounded": Icons.gamepad_rounded, - "gamepad_outlined": Icons.gamepad_outlined, - "games": Icons.games, - "games_sharp": Icons.games_sharp, - "games_rounded": Icons.games_rounded, - "games_outlined": Icons.games_outlined, - "garage": Icons.garage, - "garage_sharp": Icons.garage_sharp, - "garage_rounded": Icons.garage_rounded, - "garage_outlined": Icons.garage_outlined, - "gas_meter": Icons.gas_meter, - "gas_meter_sharp": Icons.gas_meter_sharp, - "gas_meter_rounded": Icons.gas_meter_rounded, - "gas_meter_outlined": Icons.gas_meter_outlined, - "gavel": Icons.gavel, - "gavel_sharp": Icons.gavel_sharp, - "gavel_rounded": Icons.gavel_rounded, - "gavel_outlined": Icons.gavel_outlined, - "generating_tokens": Icons.generating_tokens, - "generating_tokens_sharp": Icons.generating_tokens_sharp, - "generating_tokens_rounded": Icons.generating_tokens_rounded, - "generating_tokens_outlined": Icons.generating_tokens_outlined, - "gesture": Icons.gesture, - "gesture_sharp": Icons.gesture_sharp, - "gesture_rounded": Icons.gesture_rounded, - "gesture_outlined": Icons.gesture_outlined, - "get_app": Icons.get_app, - "get_app_sharp": Icons.get_app_sharp, - "get_app_rounded": Icons.get_app_rounded, - "get_app_outlined": Icons.get_app_outlined, - "gif": Icons.gif, - "gif_sharp": Icons.gif_sharp, - "gif_rounded": Icons.gif_rounded, - "gif_outlined": Icons.gif_outlined, - "gif_box": Icons.gif_box, - "gif_box_sharp": Icons.gif_box_sharp, - "gif_box_rounded": Icons.gif_box_rounded, - "gif_box_outlined": Icons.gif_box_outlined, - "girl": Icons.girl, - "girl_sharp": Icons.girl_sharp, - "girl_rounded": Icons.girl_rounded, - "girl_outlined": Icons.girl_outlined, - "gite": Icons.gite, - "gite_sharp": Icons.gite_sharp, - "gite_rounded": Icons.gite_rounded, - "gite_outlined": Icons.gite_outlined, - "golf_course": Icons.golf_course, - "golf_course_sharp": Icons.golf_course_sharp, - "golf_course_rounded": Icons.golf_course_rounded, - "golf_course_outlined": Icons.golf_course_outlined, - "gpp_bad": Icons.gpp_bad, - "gpp_bad_sharp": Icons.gpp_bad_sharp, - "gpp_bad_rounded": Icons.gpp_bad_rounded, - "gpp_bad_outlined": Icons.gpp_bad_outlined, - "gpp_good": Icons.gpp_good, - "gpp_good_sharp": Icons.gpp_good_sharp, - "gpp_good_rounded": Icons.gpp_good_rounded, - "gpp_good_outlined": Icons.gpp_good_outlined, - "gpp_maybe": Icons.gpp_maybe, - "gpp_maybe_sharp": Icons.gpp_maybe_sharp, - "gpp_maybe_rounded": Icons.gpp_maybe_rounded, - "gpp_maybe_outlined": Icons.gpp_maybe_outlined, - "gps_fixed": Icons.gps_fixed, - "gps_fixed_sharp": Icons.gps_fixed_sharp, - "gps_fixed_rounded": Icons.gps_fixed_rounded, - "gps_fixed_outlined": Icons.gps_fixed_outlined, - "gps_not_fixed": Icons.gps_not_fixed, - "gps_not_fixed_sharp": Icons.gps_not_fixed_sharp, - "gps_not_fixed_rounded": Icons.gps_not_fixed_rounded, - "gps_not_fixed_outlined": Icons.gps_not_fixed_outlined, - "gps_off": Icons.gps_off, - "gps_off_sharp": Icons.gps_off_sharp, - "gps_off_rounded": Icons.gps_off_rounded, - "gps_off_outlined": Icons.gps_off_outlined, - "grade": Icons.grade, - "grade_sharp": Icons.grade_sharp, - "grade_rounded": Icons.grade_rounded, - "grade_outlined": Icons.grade_outlined, - "gradient": Icons.gradient, - "gradient_sharp": Icons.gradient_sharp, - "gradient_rounded": Icons.gradient_rounded, - "gradient_outlined": Icons.gradient_outlined, - "grading": Icons.grading, - "grading_sharp": Icons.grading_sharp, - "grading_rounded": Icons.grading_rounded, - "grading_outlined": Icons.grading_outlined, - "grain": Icons.grain, - "grain_sharp": Icons.grain_sharp, - "grain_rounded": Icons.grain_rounded, - "grain_outlined": Icons.grain_outlined, - "graphic_eq": Icons.graphic_eq, - "graphic_eq_sharp": Icons.graphic_eq_sharp, - "graphic_eq_rounded": Icons.graphic_eq_rounded, - "graphic_eq_outlined": Icons.graphic_eq_outlined, - "grass": Icons.grass, - "grass_sharp": Icons.grass_sharp, - "grass_rounded": Icons.grass_rounded, - "grass_outlined": Icons.grass_outlined, - "grid_3x3": Icons.grid_3x3, - "grid_3x3_sharp": Icons.grid_3x3_sharp, - "grid_3x3_rounded": Icons.grid_3x3_rounded, - "grid_3x3_outlined": Icons.grid_3x3_outlined, - "grid_4x4": Icons.grid_4x4, - "grid_4x4_sharp": Icons.grid_4x4_sharp, - "grid_4x4_rounded": Icons.grid_4x4_rounded, - "grid_4x4_outlined": Icons.grid_4x4_outlined, - "grid_goldenratio": Icons.grid_goldenratio, - "grid_goldenratio_sharp": Icons.grid_goldenratio_sharp, - "grid_goldenratio_rounded": Icons.grid_goldenratio_rounded, - "grid_goldenratio_outlined": Icons.grid_goldenratio_outlined, - "grid_off": Icons.grid_off, - "grid_off_sharp": Icons.grid_off_sharp, - "grid_off_rounded": Icons.grid_off_rounded, - "grid_off_outlined": Icons.grid_off_outlined, - "grid_on": Icons.grid_on, - "grid_on_sharp": Icons.grid_on_sharp, - "grid_on_rounded": Icons.grid_on_rounded, - "grid_on_outlined": Icons.grid_on_outlined, - "grid_view": Icons.grid_view, - "grid_view_sharp": Icons.grid_view_sharp, - "grid_view_rounded": Icons.grid_view_rounded, - "grid_view_outlined": Icons.grid_view_outlined, - "group": Icons.group, - "group_sharp": Icons.group_sharp, - "group_rounded": Icons.group_rounded, - "group_outlined": Icons.group_outlined, - "group_add": Icons.group_add, - "group_add_sharp": Icons.group_add_sharp, - "group_add_rounded": Icons.group_add_rounded, - "group_add_outlined": Icons.group_add_outlined, - "group_off": Icons.group_off, - "group_off_sharp": Icons.group_off_sharp, - "group_off_rounded": Icons.group_off_rounded, - "group_off_outlined": Icons.group_off_outlined, - "group_remove": Icons.group_remove, - "group_remove_sharp": Icons.group_remove_sharp, - "group_remove_rounded": Icons.group_remove_rounded, - "group_remove_outlined": Icons.group_remove_outlined, - "group_work": Icons.group_work, - "group_work_sharp": Icons.group_work_sharp, - "group_work_rounded": Icons.group_work_rounded, - "group_work_outlined": Icons.group_work_outlined, - "groups": Icons.groups, - "groups_sharp": Icons.groups_sharp, - "groups_rounded": Icons.groups_rounded, - "groups_outlined": Icons.groups_outlined, - "groups_2": Icons.groups_2, - "groups_2_sharp": Icons.groups_2_sharp, - "groups_2_rounded": Icons.groups_2_rounded, - "groups_2_outlined": Icons.groups_2_outlined, - "groups_3": Icons.groups_3, - "groups_3_sharp": Icons.groups_3_sharp, - "groups_3_rounded": Icons.groups_3_rounded, - "groups_3_outlined": Icons.groups_3_outlined, - "h_mobiledata": Icons.h_mobiledata, - "h_mobiledata_sharp": Icons.h_mobiledata_sharp, - "h_mobiledata_rounded": Icons.h_mobiledata_rounded, - "h_mobiledata_outlined": Icons.h_mobiledata_outlined, - "h_plus_mobiledata": Icons.h_plus_mobiledata, - "h_plus_mobiledata_sharp": Icons.h_plus_mobiledata_sharp, - "h_plus_mobiledata_rounded": Icons.h_plus_mobiledata_rounded, - "h_plus_mobiledata_outlined": Icons.h_plus_mobiledata_outlined, - "hail": Icons.hail, - "hail_sharp": Icons.hail_sharp, - "hail_rounded": Icons.hail_rounded, - "hail_outlined": Icons.hail_outlined, - "handshake": Icons.handshake, - "handshake_sharp": Icons.handshake_sharp, - "handshake_rounded": Icons.handshake_rounded, - "handshake_outlined": Icons.handshake_outlined, - "handyman": Icons.handyman, - "handyman_sharp": Icons.handyman_sharp, - "handyman_rounded": Icons.handyman_rounded, - "handyman_outlined": Icons.handyman_outlined, - "hardware": Icons.hardware, - "hardware_sharp": Icons.hardware_sharp, - "hardware_rounded": Icons.hardware_rounded, - "hardware_outlined": Icons.hardware_outlined, - "hd": Icons.hd, - "hd_sharp": Icons.hd_sharp, - "hd_rounded": Icons.hd_rounded, - "hd_outlined": Icons.hd_outlined, - "hdr_auto": Icons.hdr_auto, - "hdr_auto_sharp": Icons.hdr_auto_sharp, - "hdr_auto_rounded": Icons.hdr_auto_rounded, - "hdr_auto_outlined": Icons.hdr_auto_outlined, - "hdr_auto_select": Icons.hdr_auto_select, - "hdr_auto_select_sharp": Icons.hdr_auto_select_sharp, - "hdr_auto_select_rounded": Icons.hdr_auto_select_rounded, - "hdr_auto_select_outlined": Icons.hdr_auto_select_outlined, - "hdr_enhanced_select": Icons.hdr_enhanced_select, - "hdr_enhanced_select_sharp": Icons.hdr_enhanced_select_sharp, - "hdr_enhanced_select_rounded": Icons.hdr_enhanced_select_rounded, - "hdr_enhanced_select_outlined": Icons.hdr_enhanced_select_outlined, - "hdr_off": Icons.hdr_off, - "hdr_off_sharp": Icons.hdr_off_sharp, - "hdr_off_rounded": Icons.hdr_off_rounded, - "hdr_off_outlined": Icons.hdr_off_outlined, - "hdr_off_select": Icons.hdr_off_select, - "hdr_off_select_sharp": Icons.hdr_off_select_sharp, - "hdr_off_select_rounded": Icons.hdr_off_select_rounded, - "hdr_off_select_outlined": Icons.hdr_off_select_outlined, - "hdr_on": Icons.hdr_on, - "hdr_on_sharp": Icons.hdr_on_sharp, - "hdr_on_rounded": Icons.hdr_on_rounded, - "hdr_on_outlined": Icons.hdr_on_outlined, - "hdr_on_select": Icons.hdr_on_select, - "hdr_on_select_sharp": Icons.hdr_on_select_sharp, - "hdr_on_select_rounded": Icons.hdr_on_select_rounded, - "hdr_on_select_outlined": Icons.hdr_on_select_outlined, - "hdr_plus": Icons.hdr_plus, - "hdr_plus_sharp": Icons.hdr_plus_sharp, - "hdr_plus_rounded": Icons.hdr_plus_rounded, - "hdr_plus_outlined": Icons.hdr_plus_outlined, - "hdr_strong": Icons.hdr_strong, - "hdr_strong_sharp": Icons.hdr_strong_sharp, - "hdr_strong_rounded": Icons.hdr_strong_rounded, - "hdr_strong_outlined": Icons.hdr_strong_outlined, - "hdr_weak": Icons.hdr_weak, - "hdr_weak_sharp": Icons.hdr_weak_sharp, - "hdr_weak_rounded": Icons.hdr_weak_rounded, - "hdr_weak_outlined": Icons.hdr_weak_outlined, - "headphones": Icons.headphones, - "headphones_sharp": Icons.headphones_sharp, - "headphones_rounded": Icons.headphones_rounded, - "headphones_outlined": Icons.headphones_outlined, - "headphones_battery": Icons.headphones_battery, - "headphones_battery_sharp": Icons.headphones_battery_sharp, - "headphones_battery_rounded": Icons.headphones_battery_rounded, - "headphones_battery_outlined": Icons.headphones_battery_outlined, - "headset": Icons.headset, - "headset_sharp": Icons.headset_sharp, - "headset_rounded": Icons.headset_rounded, - "headset_outlined": Icons.headset_outlined, - "headset_mic": Icons.headset_mic, - "headset_mic_sharp": Icons.headset_mic_sharp, - "headset_mic_rounded": Icons.headset_mic_rounded, - "headset_mic_outlined": Icons.headset_mic_outlined, - "headset_off": Icons.headset_off, - "headset_off_sharp": Icons.headset_off_sharp, - "headset_off_rounded": Icons.headset_off_rounded, - "headset_off_outlined": Icons.headset_off_outlined, - "healing": Icons.healing, - "healing_sharp": Icons.healing_sharp, - "healing_rounded": Icons.healing_rounded, - "healing_outlined": Icons.healing_outlined, - "health_and_safety": Icons.health_and_safety, - "health_and_safety_sharp": Icons.health_and_safety_sharp, - "health_and_safety_rounded": Icons.health_and_safety_rounded, - "health_and_safety_outlined": Icons.health_and_safety_outlined, - "hearing": Icons.hearing, - "hearing_sharp": Icons.hearing_sharp, - "hearing_rounded": Icons.hearing_rounded, - "hearing_outlined": Icons.hearing_outlined, - "hearing_disabled": Icons.hearing_disabled, - "hearing_disabled_sharp": Icons.hearing_disabled_sharp, - "hearing_disabled_rounded": Icons.hearing_disabled_rounded, - "hearing_disabled_outlined": Icons.hearing_disabled_outlined, - "heart_broken": Icons.heart_broken, - "heart_broken_sharp": Icons.heart_broken_sharp, - "heart_broken_rounded": Icons.heart_broken_rounded, - "heart_broken_outlined": Icons.heart_broken_outlined, - "heat_pump": Icons.heat_pump, - "heat_pump_sharp": Icons.heat_pump_sharp, - "heat_pump_rounded": Icons.heat_pump_rounded, - "heat_pump_outlined": Icons.heat_pump_outlined, - "height": Icons.height, - "height_sharp": Icons.height_sharp, - "height_rounded": Icons.height_rounded, - "height_outlined": Icons.height_outlined, - "help": Icons.help, - "help_sharp": Icons.help_sharp, - "help_rounded": Icons.help_rounded, - "help_outlined": Icons.help_outlined, - "help_center": Icons.help_center, - "help_center_sharp": Icons.help_center_sharp, - "help_center_rounded": Icons.help_center_rounded, - "help_center_outlined": Icons.help_center_outlined, - "help_outline": Icons.help_outline, - "help_outline_sharp": Icons.help_outline_sharp, - "help_outline_rounded": Icons.help_outline_rounded, - "help_outline_outlined": Icons.help_outline_outlined, - "hevc": Icons.hevc, - "hevc_sharp": Icons.hevc_sharp, - "hevc_rounded": Icons.hevc_rounded, - "hevc_outlined": Icons.hevc_outlined, - "hexagon": Icons.hexagon, - "hexagon_sharp": Icons.hexagon_sharp, - "hexagon_rounded": Icons.hexagon_rounded, - "hexagon_outlined": Icons.hexagon_outlined, - "hide_image": Icons.hide_image, - "hide_image_sharp": Icons.hide_image_sharp, - "hide_image_rounded": Icons.hide_image_rounded, - "hide_image_outlined": Icons.hide_image_outlined, - "hide_source": Icons.hide_source, - "hide_source_sharp": Icons.hide_source_sharp, - "hide_source_rounded": Icons.hide_source_rounded, - "hide_source_outlined": Icons.hide_source_outlined, - "high_quality": Icons.high_quality, - "high_quality_sharp": Icons.high_quality_sharp, - "high_quality_rounded": Icons.high_quality_rounded, - "high_quality_outlined": Icons.high_quality_outlined, - "highlight": Icons.highlight, - "highlight_sharp": Icons.highlight_sharp, - "highlight_rounded": Icons.highlight_rounded, - "highlight_outlined": Icons.highlight_outlined, - "highlight_alt": Icons.highlight_alt, - "highlight_alt_sharp": Icons.highlight_alt_sharp, - "highlight_alt_rounded": Icons.highlight_alt_rounded, - "highlight_alt_outlined": Icons.highlight_alt_outlined, - "highlight_off": Icons.highlight_off, - "highlight_off_sharp": Icons.highlight_off_sharp, - "highlight_off_rounded": Icons.highlight_off_rounded, - "highlight_off_outlined": Icons.highlight_off_outlined, - "highlight_remove": Icons.highlight_remove, - "highlight_remove_sharp": Icons.highlight_remove_sharp, - "highlight_remove_rounded": Icons.highlight_remove_rounded, - "highlight_remove_outlined": Icons.highlight_remove_outlined, - "hiking": Icons.hiking, - "hiking_sharp": Icons.hiking_sharp, - "hiking_rounded": Icons.hiking_rounded, - "hiking_outlined": Icons.hiking_outlined, - "history": Icons.history, - "history_sharp": Icons.history_sharp, - "history_rounded": Icons.history_rounded, - "history_outlined": Icons.history_outlined, - "history_edu": Icons.history_edu, - "history_edu_sharp": Icons.history_edu_sharp, - "history_edu_rounded": Icons.history_edu_rounded, - "history_edu_outlined": Icons.history_edu_outlined, - "history_toggle_off": Icons.history_toggle_off, - "history_toggle_off_sharp": Icons.history_toggle_off_sharp, - "history_toggle_off_rounded": Icons.history_toggle_off_rounded, - "history_toggle_off_outlined": Icons.history_toggle_off_outlined, - "hive": Icons.hive, - "hive_sharp": Icons.hive_sharp, - "hive_rounded": Icons.hive_rounded, - "hive_outlined": Icons.hive_outlined, - "hls": Icons.hls, - "hls_sharp": Icons.hls_sharp, - "hls_rounded": Icons.hls_rounded, - "hls_outlined": Icons.hls_outlined, - "hls_off": Icons.hls_off, - "hls_off_sharp": Icons.hls_off_sharp, - "hls_off_rounded": Icons.hls_off_rounded, - "hls_off_outlined": Icons.hls_off_outlined, - "holiday_village": Icons.holiday_village, - "holiday_village_sharp": Icons.holiday_village_sharp, - "holiday_village_rounded": Icons.holiday_village_rounded, - "holiday_village_outlined": Icons.holiday_village_outlined, - "home": Icons.home, - "home_sharp": Icons.home_sharp, - "home_rounded": Icons.home_rounded, - "home_outlined": Icons.home_outlined, - "home_filled": Icons.home_filled, - "home_max": Icons.home_max, - "home_max_sharp": Icons.home_max_sharp, - "home_max_rounded": Icons.home_max_rounded, - "home_max_outlined": Icons.home_max_outlined, - "home_mini": Icons.home_mini, - "home_mini_sharp": Icons.home_mini_sharp, - "home_mini_rounded": Icons.home_mini_rounded, - "home_mini_outlined": Icons.home_mini_outlined, - "home_repair_service": Icons.home_repair_service, - "home_repair_service_sharp": Icons.home_repair_service_sharp, - "home_repair_service_rounded": Icons.home_repair_service_rounded, - "home_repair_service_outlined": Icons.home_repair_service_outlined, - "home_work": Icons.home_work, - "home_work_sharp": Icons.home_work_sharp, - "home_work_rounded": Icons.home_work_rounded, - "home_work_outlined": Icons.home_work_outlined, - "horizontal_distribute": Icons.horizontal_distribute, - "horizontal_distribute_sharp": Icons.horizontal_distribute_sharp, - "horizontal_distribute_rounded": Icons.horizontal_distribute_rounded, - "horizontal_distribute_outlined": Icons.horizontal_distribute_outlined, - "horizontal_rule": Icons.horizontal_rule, - "horizontal_rule_sharp": Icons.horizontal_rule_sharp, - "horizontal_rule_rounded": Icons.horizontal_rule_rounded, - "horizontal_rule_outlined": Icons.horizontal_rule_outlined, - "horizontal_split": Icons.horizontal_split, - "horizontal_split_sharp": Icons.horizontal_split_sharp, - "horizontal_split_rounded": Icons.horizontal_split_rounded, - "horizontal_split_outlined": Icons.horizontal_split_outlined, - "hot_tub": Icons.hot_tub, - "hot_tub_sharp": Icons.hot_tub_sharp, - "hot_tub_rounded": Icons.hot_tub_rounded, - "hot_tub_outlined": Icons.hot_tub_outlined, - "hotel": Icons.hotel, - "hotel_sharp": Icons.hotel_sharp, - "hotel_rounded": Icons.hotel_rounded, - "hotel_outlined": Icons.hotel_outlined, - "hotel_class": Icons.hotel_class, - "hotel_class_sharp": Icons.hotel_class_sharp, - "hotel_class_rounded": Icons.hotel_class_rounded, - "hotel_class_outlined": Icons.hotel_class_outlined, - "hourglass_bottom": Icons.hourglass_bottom, - "hourglass_bottom_sharp": Icons.hourglass_bottom_sharp, - "hourglass_bottom_rounded": Icons.hourglass_bottom_rounded, - "hourglass_bottom_outlined": Icons.hourglass_bottom_outlined, - "hourglass_disabled": Icons.hourglass_disabled, - "hourglass_disabled_sharp": Icons.hourglass_disabled_sharp, - "hourglass_disabled_rounded": Icons.hourglass_disabled_rounded, - "hourglass_disabled_outlined": Icons.hourglass_disabled_outlined, - "hourglass_empty": Icons.hourglass_empty, - "hourglass_empty_sharp": Icons.hourglass_empty_sharp, - "hourglass_empty_rounded": Icons.hourglass_empty_rounded, - "hourglass_empty_outlined": Icons.hourglass_empty_outlined, - "hourglass_full": Icons.hourglass_full, - "hourglass_full_sharp": Icons.hourglass_full_sharp, - "hourglass_full_rounded": Icons.hourglass_full_rounded, - "hourglass_full_outlined": Icons.hourglass_full_outlined, - "hourglass_top": Icons.hourglass_top, - "hourglass_top_sharp": Icons.hourglass_top_sharp, - "hourglass_top_rounded": Icons.hourglass_top_rounded, - "hourglass_top_outlined": Icons.hourglass_top_outlined, - "house": Icons.house, - "house_sharp": Icons.house_sharp, - "house_rounded": Icons.house_rounded, - "house_outlined": Icons.house_outlined, - "house_siding": Icons.house_siding, - "house_siding_sharp": Icons.house_siding_sharp, - "house_siding_rounded": Icons.house_siding_rounded, - "house_siding_outlined": Icons.house_siding_outlined, - "houseboat": Icons.houseboat, - "houseboat_sharp": Icons.houseboat_sharp, - "houseboat_rounded": Icons.houseboat_rounded, - "houseboat_outlined": Icons.houseboat_outlined, - "how_to_reg": Icons.how_to_reg, - "how_to_reg_sharp": Icons.how_to_reg_sharp, - "how_to_reg_rounded": Icons.how_to_reg_rounded, - "how_to_reg_outlined": Icons.how_to_reg_outlined, - "how_to_vote": Icons.how_to_vote, - "how_to_vote_sharp": Icons.how_to_vote_sharp, - "how_to_vote_rounded": Icons.how_to_vote_rounded, - "how_to_vote_outlined": Icons.how_to_vote_outlined, - "html": Icons.html, - "html_sharp": Icons.html_sharp, - "html_rounded": Icons.html_rounded, - "html_outlined": Icons.html_outlined, - "http": Icons.http, - "http_sharp": Icons.http_sharp, - "http_rounded": Icons.http_rounded, - "http_outlined": Icons.http_outlined, - "https": Icons.https, - "https_sharp": Icons.https_sharp, - "https_rounded": Icons.https_rounded, - "https_outlined": Icons.https_outlined, - "hub": Icons.hub, - "hub_sharp": Icons.hub_sharp, - "hub_rounded": Icons.hub_rounded, - "hub_outlined": Icons.hub_outlined, - "hvac": Icons.hvac, - "hvac_sharp": Icons.hvac_sharp, - "hvac_rounded": Icons.hvac_rounded, - "hvac_outlined": Icons.hvac_outlined, - "ice_skating": Icons.ice_skating, - "ice_skating_sharp": Icons.ice_skating_sharp, - "ice_skating_rounded": Icons.ice_skating_rounded, - "ice_skating_outlined": Icons.ice_skating_outlined, - "icecream": Icons.icecream, - "icecream_sharp": Icons.icecream_sharp, - "icecream_rounded": Icons.icecream_rounded, - "icecream_outlined": Icons.icecream_outlined, - "image": Icons.image, - "image_sharp": Icons.image_sharp, - "image_rounded": Icons.image_rounded, - "image_outlined": Icons.image_outlined, - "image_aspect_ratio": Icons.image_aspect_ratio, - "image_aspect_ratio_sharp": Icons.image_aspect_ratio_sharp, - "image_aspect_ratio_rounded": Icons.image_aspect_ratio_rounded, - "image_aspect_ratio_outlined": Icons.image_aspect_ratio_outlined, - "image_not_supported": Icons.image_not_supported, - "image_not_supported_sharp": Icons.image_not_supported_sharp, - "image_not_supported_rounded": Icons.image_not_supported_rounded, - "image_not_supported_outlined": Icons.image_not_supported_outlined, - "image_search": Icons.image_search, - "image_search_sharp": Icons.image_search_sharp, - "image_search_rounded": Icons.image_search_rounded, - "image_search_outlined": Icons.image_search_outlined, - "imagesearch_roller": Icons.imagesearch_roller, - "imagesearch_roller_sharp": Icons.imagesearch_roller_sharp, - "imagesearch_roller_rounded": Icons.imagesearch_roller_rounded, - "imagesearch_roller_outlined": Icons.imagesearch_roller_outlined, - "import_contacts": Icons.import_contacts, - "import_contacts_sharp": Icons.import_contacts_sharp, - "import_contacts_rounded": Icons.import_contacts_rounded, - "import_contacts_outlined": Icons.import_contacts_outlined, - "import_export": Icons.import_export, - "import_export_sharp": Icons.import_export_sharp, - "import_export_rounded": Icons.import_export_rounded, - "import_export_outlined": Icons.import_export_outlined, - "important_devices": Icons.important_devices, - "important_devices_sharp": Icons.important_devices_sharp, - "important_devices_rounded": Icons.important_devices_rounded, - "important_devices_outlined": Icons.important_devices_outlined, - "inbox": Icons.inbox, - "inbox_sharp": Icons.inbox_sharp, - "inbox_rounded": Icons.inbox_rounded, - "inbox_outlined": Icons.inbox_outlined, - "incomplete_circle": Icons.incomplete_circle, - "incomplete_circle_sharp": Icons.incomplete_circle_sharp, - "incomplete_circle_rounded": Icons.incomplete_circle_rounded, - "incomplete_circle_outlined": Icons.incomplete_circle_outlined, - "indeterminate_check_box": Icons.indeterminate_check_box, - "indeterminate_check_box_sharp": Icons.indeterminate_check_box_sharp, - "indeterminate_check_box_rounded": Icons.indeterminate_check_box_rounded, - "indeterminate_check_box_outlined": Icons.indeterminate_check_box_outlined, - "info": Icons.info, - "info_sharp": Icons.info_sharp, - "info_rounded": Icons.info_rounded, - "info_outlined": Icons.info_outlined, - "info_outline": Icons.info_outline, - "info_outline_sharp": Icons.info_outline_sharp, - "info_outline_rounded": Icons.info_outline_rounded, - "input": Icons.input, - "input_sharp": Icons.input_sharp, - "input_rounded": Icons.input_rounded, - "input_outlined": Icons.input_outlined, - "insert_chart": Icons.insert_chart, - "insert_chart_sharp": Icons.insert_chart_sharp, - "insert_chart_rounded": Icons.insert_chart_rounded, - "insert_chart_outlined": Icons.insert_chart_outlined, - "insert_chart_outlined_sharp": Icons.insert_chart_outlined_sharp, - "insert_chart_outlined_rounded": Icons.insert_chart_outlined_rounded, - "insert_chart_outlined_outlined": Icons.insert_chart_outlined_outlined, - "insert_comment": Icons.insert_comment, - "insert_comment_sharp": Icons.insert_comment_sharp, - "insert_comment_rounded": Icons.insert_comment_rounded, - "insert_comment_outlined": Icons.insert_comment_outlined, - "insert_drive_file": Icons.insert_drive_file, - "insert_drive_file_sharp": Icons.insert_drive_file_sharp, - "insert_drive_file_rounded": Icons.insert_drive_file_rounded, - "insert_drive_file_outlined": Icons.insert_drive_file_outlined, - "insert_emoticon": Icons.insert_emoticon, - "insert_emoticon_sharp": Icons.insert_emoticon_sharp, - "insert_emoticon_rounded": Icons.insert_emoticon_rounded, - "insert_emoticon_outlined": Icons.insert_emoticon_outlined, - "insert_invitation": Icons.insert_invitation, - "insert_invitation_sharp": Icons.insert_invitation_sharp, - "insert_invitation_rounded": Icons.insert_invitation_rounded, - "insert_invitation_outlined": Icons.insert_invitation_outlined, - "insert_link": Icons.insert_link, - "insert_link_sharp": Icons.insert_link_sharp, - "insert_link_rounded": Icons.insert_link_rounded, - "insert_link_outlined": Icons.insert_link_outlined, - "insert_page_break": Icons.insert_page_break, - "insert_page_break_sharp": Icons.insert_page_break_sharp, - "insert_page_break_rounded": Icons.insert_page_break_rounded, - "insert_page_break_outlined": Icons.insert_page_break_outlined, - "insert_photo": Icons.insert_photo, - "insert_photo_sharp": Icons.insert_photo_sharp, - "insert_photo_rounded": Icons.insert_photo_rounded, - "insert_photo_outlined": Icons.insert_photo_outlined, - "insights": Icons.insights, - "insights_sharp": Icons.insights_sharp, - "insights_rounded": Icons.insights_rounded, - "insights_outlined": Icons.insights_outlined, - "install_desktop": Icons.install_desktop, - "install_desktop_sharp": Icons.install_desktop_sharp, - "install_desktop_rounded": Icons.install_desktop_rounded, - "install_desktop_outlined": Icons.install_desktop_outlined, - "install_mobile": Icons.install_mobile, - "install_mobile_sharp": Icons.install_mobile_sharp, - "install_mobile_rounded": Icons.install_mobile_rounded, - "install_mobile_outlined": Icons.install_mobile_outlined, - "integration_instructions": Icons.integration_instructions, - "integration_instructions_sharp": Icons.integration_instructions_sharp, - "integration_instructions_rounded": Icons.integration_instructions_rounded, - "integration_instructions_outlined": Icons.integration_instructions_outlined, - "interests": Icons.interests, - "interests_sharp": Icons.interests_sharp, - "interests_rounded": Icons.interests_rounded, - "interests_outlined": Icons.interests_outlined, - "interpreter_mode": Icons.interpreter_mode, - "interpreter_mode_sharp": Icons.interpreter_mode_sharp, - "interpreter_mode_rounded": Icons.interpreter_mode_rounded, - "interpreter_mode_outlined": Icons.interpreter_mode_outlined, - "inventory": Icons.inventory, - "inventory_sharp": Icons.inventory_sharp, - "inventory_rounded": Icons.inventory_rounded, - "inventory_outlined": Icons.inventory_outlined, - "inventory_2": Icons.inventory_2, - "inventory_2_sharp": Icons.inventory_2_sharp, - "inventory_2_rounded": Icons.inventory_2_rounded, - "inventory_2_outlined": Icons.inventory_2_outlined, - "invert_colors": Icons.invert_colors, - "invert_colors_sharp": Icons.invert_colors_sharp, - "invert_colors_rounded": Icons.invert_colors_rounded, - "invert_colors_outlined": Icons.invert_colors_outlined, - "invert_colors_off": Icons.invert_colors_off, - "invert_colors_off_sharp": Icons.invert_colors_off_sharp, - "invert_colors_off_rounded": Icons.invert_colors_off_rounded, - "invert_colors_off_outlined": Icons.invert_colors_off_outlined, - "invert_colors_on": Icons.invert_colors_on, - "invert_colors_on_sharp": Icons.invert_colors_on_sharp, - "invert_colors_on_rounded": Icons.invert_colors_on_rounded, - "invert_colors_on_outlined": Icons.invert_colors_on_outlined, - "ios_share": Icons.ios_share, - "ios_share_sharp": Icons.ios_share_sharp, - "ios_share_rounded": Icons.ios_share_rounded, - "ios_share_outlined": Icons.ios_share_outlined, - "iron": Icons.iron, - "iron_sharp": Icons.iron_sharp, - "iron_rounded": Icons.iron_rounded, - "iron_outlined": Icons.iron_outlined, - "iso": Icons.iso, - "iso_sharp": Icons.iso_sharp, - "iso_rounded": Icons.iso_rounded, - "iso_outlined": Icons.iso_outlined, - "javascript": Icons.javascript, - "javascript_sharp": Icons.javascript_sharp, - "javascript_rounded": Icons.javascript_rounded, - "javascript_outlined": Icons.javascript_outlined, - "join_full": Icons.join_full, - "join_full_sharp": Icons.join_full_sharp, - "join_full_rounded": Icons.join_full_rounded, - "join_full_outlined": Icons.join_full_outlined, - "join_inner": Icons.join_inner, - "join_inner_sharp": Icons.join_inner_sharp, - "join_inner_rounded": Icons.join_inner_rounded, - "join_inner_outlined": Icons.join_inner_outlined, - "join_left": Icons.join_left, - "join_left_sharp": Icons.join_left_sharp, - "join_left_rounded": Icons.join_left_rounded, - "join_left_outlined": Icons.join_left_outlined, - "join_right": Icons.join_right, - "join_right_sharp": Icons.join_right_sharp, - "join_right_rounded": Icons.join_right_rounded, - "join_right_outlined": Icons.join_right_outlined, - "kayaking": Icons.kayaking, - "kayaking_sharp": Icons.kayaking_sharp, - "kayaking_rounded": Icons.kayaking_rounded, - "kayaking_outlined": Icons.kayaking_outlined, - "kebab_dining": Icons.kebab_dining, - "kebab_dining_sharp": Icons.kebab_dining_sharp, - "kebab_dining_rounded": Icons.kebab_dining_rounded, - "kebab_dining_outlined": Icons.kebab_dining_outlined, - "key": Icons.key, - "key_sharp": Icons.key_sharp, - "key_rounded": Icons.key_rounded, - "key_outlined": Icons.key_outlined, - "key_off": Icons.key_off, - "key_off_sharp": Icons.key_off_sharp, - "key_off_rounded": Icons.key_off_rounded, - "key_off_outlined": Icons.key_off_outlined, - "keyboard": Icons.keyboard, - "keyboard_sharp": Icons.keyboard_sharp, - "keyboard_rounded": Icons.keyboard_rounded, - "keyboard_outlined": Icons.keyboard_outlined, - "keyboard_alt": Icons.keyboard_alt, - "keyboard_alt_sharp": Icons.keyboard_alt_sharp, - "keyboard_alt_rounded": Icons.keyboard_alt_rounded, - "keyboard_alt_outlined": Icons.keyboard_alt_outlined, - "keyboard_arrow_down": Icons.keyboard_arrow_down, - "keyboard_arrow_down_sharp": Icons.keyboard_arrow_down_sharp, - "keyboard_arrow_down_rounded": Icons.keyboard_arrow_down_rounded, - "keyboard_arrow_down_outlined": Icons.keyboard_arrow_down_outlined, - "keyboard_arrow_left": Icons.keyboard_arrow_left, - "keyboard_arrow_left_sharp": Icons.keyboard_arrow_left_sharp, - "keyboard_arrow_left_rounded": Icons.keyboard_arrow_left_rounded, - "keyboard_arrow_left_outlined": Icons.keyboard_arrow_left_outlined, - "keyboard_arrow_right": Icons.keyboard_arrow_right, - "keyboard_arrow_right_sharp": Icons.keyboard_arrow_right_sharp, - "keyboard_arrow_right_rounded": Icons.keyboard_arrow_right_rounded, - "keyboard_arrow_right_outlined": Icons.keyboard_arrow_right_outlined, - "keyboard_arrow_up": Icons.keyboard_arrow_up, - "keyboard_arrow_up_sharp": Icons.keyboard_arrow_up_sharp, - "keyboard_arrow_up_rounded": Icons.keyboard_arrow_up_rounded, - "keyboard_arrow_up_outlined": Icons.keyboard_arrow_up_outlined, - "keyboard_backspace": Icons.keyboard_backspace, - "keyboard_backspace_sharp": Icons.keyboard_backspace_sharp, - "keyboard_backspace_rounded": Icons.keyboard_backspace_rounded, - "keyboard_backspace_outlined": Icons.keyboard_backspace_outlined, - "keyboard_capslock": Icons.keyboard_capslock, - "keyboard_capslock_sharp": Icons.keyboard_capslock_sharp, - "keyboard_capslock_rounded": Icons.keyboard_capslock_rounded, - "keyboard_capslock_outlined": Icons.keyboard_capslock_outlined, - "keyboard_command_key": Icons.keyboard_command_key, - "keyboard_command_key_sharp": Icons.keyboard_command_key_sharp, - "keyboard_command_key_rounded": Icons.keyboard_command_key_rounded, - "keyboard_command_key_outlined": Icons.keyboard_command_key_outlined, - "keyboard_control": Icons.keyboard_control, - "keyboard_control_sharp": Icons.keyboard_control_sharp, - "keyboard_control_rounded": Icons.keyboard_control_rounded, - "keyboard_control_outlined": Icons.keyboard_control_outlined, - "keyboard_control_key": Icons.keyboard_control_key, - "keyboard_control_key_sharp": Icons.keyboard_control_key_sharp, - "keyboard_control_key_rounded": Icons.keyboard_control_key_rounded, - "keyboard_control_key_outlined": Icons.keyboard_control_key_outlined, - "keyboard_double_arrow_down": Icons.keyboard_double_arrow_down, - "keyboard_double_arrow_down_sharp": Icons.keyboard_double_arrow_down_sharp, - "keyboard_double_arrow_down_rounded": - Icons.keyboard_double_arrow_down_rounded, - "keyboard_double_arrow_down_outlined": - Icons.keyboard_double_arrow_down_outlined, - "keyboard_double_arrow_left": Icons.keyboard_double_arrow_left, - "keyboard_double_arrow_left_sharp": Icons.keyboard_double_arrow_left_sharp, - "keyboard_double_arrow_left_rounded": - Icons.keyboard_double_arrow_left_rounded, - "keyboard_double_arrow_left_outlined": - Icons.keyboard_double_arrow_left_outlined, - "keyboard_double_arrow_right": Icons.keyboard_double_arrow_right, - "keyboard_double_arrow_right_sharp": Icons.keyboard_double_arrow_right_sharp, - "keyboard_double_arrow_right_rounded": - Icons.keyboard_double_arrow_right_rounded, - "keyboard_double_arrow_right_outlined": - Icons.keyboard_double_arrow_right_outlined, - "keyboard_double_arrow_up": Icons.keyboard_double_arrow_up, - "keyboard_double_arrow_up_sharp": Icons.keyboard_double_arrow_up_sharp, - "keyboard_double_arrow_up_rounded": Icons.keyboard_double_arrow_up_rounded, - "keyboard_double_arrow_up_outlined": Icons.keyboard_double_arrow_up_outlined, - "keyboard_hide": Icons.keyboard_hide, - "keyboard_hide_sharp": Icons.keyboard_hide_sharp, - "keyboard_hide_rounded": Icons.keyboard_hide_rounded, - "keyboard_hide_outlined": Icons.keyboard_hide_outlined, - "keyboard_option_key": Icons.keyboard_option_key, - "keyboard_option_key_sharp": Icons.keyboard_option_key_sharp, - "keyboard_option_key_rounded": Icons.keyboard_option_key_rounded, - "keyboard_option_key_outlined": Icons.keyboard_option_key_outlined, - "keyboard_return": Icons.keyboard_return, - "keyboard_return_sharp": Icons.keyboard_return_sharp, - "keyboard_return_rounded": Icons.keyboard_return_rounded, - "keyboard_return_outlined": Icons.keyboard_return_outlined, - "keyboard_tab": Icons.keyboard_tab, - "keyboard_tab_sharp": Icons.keyboard_tab_sharp, - "keyboard_tab_rounded": Icons.keyboard_tab_rounded, - "keyboard_tab_outlined": Icons.keyboard_tab_outlined, - "keyboard_voice": Icons.keyboard_voice, - "keyboard_voice_sharp": Icons.keyboard_voice_sharp, - "keyboard_voice_rounded": Icons.keyboard_voice_rounded, - "keyboard_voice_outlined": Icons.keyboard_voice_outlined, - "king_bed": Icons.king_bed, - "king_bed_sharp": Icons.king_bed_sharp, - "king_bed_rounded": Icons.king_bed_rounded, - "king_bed_outlined": Icons.king_bed_outlined, - "kitchen": Icons.kitchen, - "kitchen_sharp": Icons.kitchen_sharp, - "kitchen_rounded": Icons.kitchen_rounded, - "kitchen_outlined": Icons.kitchen_outlined, - "kitesurfing": Icons.kitesurfing, - "kitesurfing_sharp": Icons.kitesurfing_sharp, - "kitesurfing_rounded": Icons.kitesurfing_rounded, - "kitesurfing_outlined": Icons.kitesurfing_outlined, - "label": Icons.label, - "label_sharp": Icons.label_sharp, - "label_rounded": Icons.label_rounded, - "label_outlined": Icons.label_outlined, - "label_important": Icons.label_important, - "label_important_sharp": Icons.label_important_sharp, - "label_important_rounded": Icons.label_important_rounded, - "label_important_outlined": Icons.label_important_outlined, - "label_important_outline": Icons.label_important_outline, - "label_important_outline_sharp": Icons.label_important_outline_sharp, - "label_important_outline_rounded": Icons.label_important_outline_rounded, - "label_off": Icons.label_off, - "label_off_sharp": Icons.label_off_sharp, - "label_off_rounded": Icons.label_off_rounded, - "label_off_outlined": Icons.label_off_outlined, - "label_outline": Icons.label_outline, - "label_outline_sharp": Icons.label_outline_sharp, - "label_outline_rounded": Icons.label_outline_rounded, - "lan": Icons.lan, - "lan_sharp": Icons.lan_sharp, - "lan_rounded": Icons.lan_rounded, - "lan_outlined": Icons.lan_outlined, - "landscape": Icons.landscape, - "landscape_sharp": Icons.landscape_sharp, - "landscape_rounded": Icons.landscape_rounded, - "landscape_outlined": Icons.landscape_outlined, - "landslide": Icons.landslide, - "landslide_sharp": Icons.landslide_sharp, - "landslide_rounded": Icons.landslide_rounded, - "landslide_outlined": Icons.landslide_outlined, - "language": Icons.language, - "language_sharp": Icons.language_sharp, - "language_rounded": Icons.language_rounded, - "language_outlined": Icons.language_outlined, - "laptop": Icons.laptop, - "laptop_sharp": Icons.laptop_sharp, - "laptop_rounded": Icons.laptop_rounded, - "laptop_outlined": Icons.laptop_outlined, - "laptop_chromebook": Icons.laptop_chromebook, - "laptop_chromebook_sharp": Icons.laptop_chromebook_sharp, - "laptop_chromebook_rounded": Icons.laptop_chromebook_rounded, - "laptop_chromebook_outlined": Icons.laptop_chromebook_outlined, - "laptop_mac": Icons.laptop_mac, - "laptop_mac_sharp": Icons.laptop_mac_sharp, - "laptop_mac_rounded": Icons.laptop_mac_rounded, - "laptop_mac_outlined": Icons.laptop_mac_outlined, - "laptop_windows": Icons.laptop_windows, - "laptop_windows_sharp": Icons.laptop_windows_sharp, - "laptop_windows_rounded": Icons.laptop_windows_rounded, - "laptop_windows_outlined": Icons.laptop_windows_outlined, - "last_page": Icons.last_page, - "last_page_sharp": Icons.last_page_sharp, - "last_page_rounded": Icons.last_page_rounded, - "last_page_outlined": Icons.last_page_outlined, - "launch": Icons.launch, - "launch_sharp": Icons.launch_sharp, - "launch_rounded": Icons.launch_rounded, - "launch_outlined": Icons.launch_outlined, - "layers": Icons.layers, - "layers_sharp": Icons.layers_sharp, - "layers_rounded": Icons.layers_rounded, - "layers_outlined": Icons.layers_outlined, - "layers_clear": Icons.layers_clear, - "layers_clear_sharp": Icons.layers_clear_sharp, - "layers_clear_rounded": Icons.layers_clear_rounded, - "layers_clear_outlined": Icons.layers_clear_outlined, - "leaderboard": Icons.leaderboard, - "leaderboard_sharp": Icons.leaderboard_sharp, - "leaderboard_rounded": Icons.leaderboard_rounded, - "leaderboard_outlined": Icons.leaderboard_outlined, - "leak_add": Icons.leak_add, - "leak_add_sharp": Icons.leak_add_sharp, - "leak_add_rounded": Icons.leak_add_rounded, - "leak_add_outlined": Icons.leak_add_outlined, - "leak_remove": Icons.leak_remove, - "leak_remove_sharp": Icons.leak_remove_sharp, - "leak_remove_rounded": Icons.leak_remove_rounded, - "leak_remove_outlined": Icons.leak_remove_outlined, - "leave_bags_at_home": Icons.leave_bags_at_home, - "leave_bags_at_home_sharp": Icons.leave_bags_at_home_sharp, - "leave_bags_at_home_rounded": Icons.leave_bags_at_home_rounded, - "leave_bags_at_home_outlined": Icons.leave_bags_at_home_outlined, - "legend_toggle": Icons.legend_toggle, - "legend_toggle_sharp": Icons.legend_toggle_sharp, - "legend_toggle_rounded": Icons.legend_toggle_rounded, - "legend_toggle_outlined": Icons.legend_toggle_outlined, - "lens": Icons.lens, - "lens_sharp": Icons.lens_sharp, - "lens_rounded": Icons.lens_rounded, - "lens_outlined": Icons.lens_outlined, - "lens_blur": Icons.lens_blur, - "lens_blur_sharp": Icons.lens_blur_sharp, - "lens_blur_rounded": Icons.lens_blur_rounded, - "lens_blur_outlined": Icons.lens_blur_outlined, - "library_add": Icons.library_add, - "library_add_sharp": Icons.library_add_sharp, - "library_add_rounded": Icons.library_add_rounded, - "library_add_outlined": Icons.library_add_outlined, - "library_add_check": Icons.library_add_check, - "library_add_check_sharp": Icons.library_add_check_sharp, - "library_add_check_rounded": Icons.library_add_check_rounded, - "library_add_check_outlined": Icons.library_add_check_outlined, - "library_books": Icons.library_books, - "library_books_sharp": Icons.library_books_sharp, - "library_books_rounded": Icons.library_books_rounded, - "library_books_outlined": Icons.library_books_outlined, - "library_music": Icons.library_music, - "library_music_sharp": Icons.library_music_sharp, - "library_music_rounded": Icons.library_music_rounded, - "library_music_outlined": Icons.library_music_outlined, - "light": Icons.light, - "light_sharp": Icons.light_sharp, - "light_rounded": Icons.light_rounded, - "light_outlined": Icons.light_outlined, - "light_mode": Icons.light_mode, - "light_mode_sharp": Icons.light_mode_sharp, - "light_mode_rounded": Icons.light_mode_rounded, - "light_mode_outlined": Icons.light_mode_outlined, - "lightbulb": Icons.lightbulb, - "lightbulb_sharp": Icons.lightbulb_sharp, - "lightbulb_rounded": Icons.lightbulb_rounded, - "lightbulb_outlined": Icons.lightbulb_outlined, - "lightbulb_circle": Icons.lightbulb_circle, - "lightbulb_circle_sharp": Icons.lightbulb_circle_sharp, - "lightbulb_circle_rounded": Icons.lightbulb_circle_rounded, - "lightbulb_circle_outlined": Icons.lightbulb_circle_outlined, - "lightbulb_outline": Icons.lightbulb_outline, - "lightbulb_outline_sharp": Icons.lightbulb_outline_sharp, - "lightbulb_outline_rounded": Icons.lightbulb_outline_rounded, - "line_axis": Icons.line_axis, - "line_axis_sharp": Icons.line_axis_sharp, - "line_axis_rounded": Icons.line_axis_rounded, - "line_axis_outlined": Icons.line_axis_outlined, - "line_style": Icons.line_style, - "line_style_sharp": Icons.line_style_sharp, - "line_style_rounded": Icons.line_style_rounded, - "line_style_outlined": Icons.line_style_outlined, - "line_weight": Icons.line_weight, - "line_weight_sharp": Icons.line_weight_sharp, - "line_weight_rounded": Icons.line_weight_rounded, - "line_weight_outlined": Icons.line_weight_outlined, - "linear_scale": Icons.linear_scale, - "linear_scale_sharp": Icons.linear_scale_sharp, - "linear_scale_rounded": Icons.linear_scale_rounded, - "linear_scale_outlined": Icons.linear_scale_outlined, - "link": Icons.link, - "link_sharp": Icons.link_sharp, - "link_rounded": Icons.link_rounded, - "link_outlined": Icons.link_outlined, - "link_off": Icons.link_off, - "link_off_sharp": Icons.link_off_sharp, - "link_off_rounded": Icons.link_off_rounded, - "link_off_outlined": Icons.link_off_outlined, - "linked_camera": Icons.linked_camera, - "linked_camera_sharp": Icons.linked_camera_sharp, - "linked_camera_rounded": Icons.linked_camera_rounded, - "linked_camera_outlined": Icons.linked_camera_outlined, - "liquor": Icons.liquor, - "liquor_sharp": Icons.liquor_sharp, - "liquor_rounded": Icons.liquor_rounded, - "liquor_outlined": Icons.liquor_outlined, - "list": Icons.list, - "list_sharp": Icons.list_sharp, - "list_rounded": Icons.list_rounded, - "list_outlined": Icons.list_outlined, - "list_alt": Icons.list_alt, - "list_alt_sharp": Icons.list_alt_sharp, - "list_alt_rounded": Icons.list_alt_rounded, - "list_alt_outlined": Icons.list_alt_outlined, - "live_help": Icons.live_help, - "live_help_sharp": Icons.live_help_sharp, - "live_help_rounded": Icons.live_help_rounded, - "live_help_outlined": Icons.live_help_outlined, - "live_tv": Icons.live_tv, - "live_tv_sharp": Icons.live_tv_sharp, - "live_tv_rounded": Icons.live_tv_rounded, - "live_tv_outlined": Icons.live_tv_outlined, - "living": Icons.living, - "living_sharp": Icons.living_sharp, - "living_rounded": Icons.living_rounded, - "living_outlined": Icons.living_outlined, - "local_activity": Icons.local_activity, - "local_activity_sharp": Icons.local_activity_sharp, - "local_activity_rounded": Icons.local_activity_rounded, - "local_activity_outlined": Icons.local_activity_outlined, - "local_airport": Icons.local_airport, - "local_airport_sharp": Icons.local_airport_sharp, - "local_airport_rounded": Icons.local_airport_rounded, - "local_airport_outlined": Icons.local_airport_outlined, - "local_atm": Icons.local_atm, - "local_atm_sharp": Icons.local_atm_sharp, - "local_atm_rounded": Icons.local_atm_rounded, - "local_atm_outlined": Icons.local_atm_outlined, - "local_attraction": Icons.local_attraction, - "local_attraction_sharp": Icons.local_attraction_sharp, - "local_attraction_rounded": Icons.local_attraction_rounded, - "local_attraction_outlined": Icons.local_attraction_outlined, - "local_bar": Icons.local_bar, - "local_bar_sharp": Icons.local_bar_sharp, - "local_bar_rounded": Icons.local_bar_rounded, - "local_bar_outlined": Icons.local_bar_outlined, - "local_cafe": Icons.local_cafe, - "local_cafe_sharp": Icons.local_cafe_sharp, - "local_cafe_rounded": Icons.local_cafe_rounded, - "local_cafe_outlined": Icons.local_cafe_outlined, - "local_car_wash": Icons.local_car_wash, - "local_car_wash_sharp": Icons.local_car_wash_sharp, - "local_car_wash_rounded": Icons.local_car_wash_rounded, - "local_car_wash_outlined": Icons.local_car_wash_outlined, - "local_convenience_store": Icons.local_convenience_store, - "local_convenience_store_sharp": Icons.local_convenience_store_sharp, - "local_convenience_store_rounded": Icons.local_convenience_store_rounded, - "local_convenience_store_outlined": Icons.local_convenience_store_outlined, - "local_dining": Icons.local_dining, - "local_dining_sharp": Icons.local_dining_sharp, - "local_dining_rounded": Icons.local_dining_rounded, - "local_dining_outlined": Icons.local_dining_outlined, - "local_drink": Icons.local_drink, - "local_drink_sharp": Icons.local_drink_sharp, - "local_drink_rounded": Icons.local_drink_rounded, - "local_drink_outlined": Icons.local_drink_outlined, - "local_fire_department": Icons.local_fire_department, - "local_fire_department_sharp": Icons.local_fire_department_sharp, - "local_fire_department_rounded": Icons.local_fire_department_rounded, - "local_fire_department_outlined": Icons.local_fire_department_outlined, - "local_florist": Icons.local_florist, - "local_florist_sharp": Icons.local_florist_sharp, - "local_florist_rounded": Icons.local_florist_rounded, - "local_florist_outlined": Icons.local_florist_outlined, - "local_gas_station": Icons.local_gas_station, - "local_gas_station_sharp": Icons.local_gas_station_sharp, - "local_gas_station_rounded": Icons.local_gas_station_rounded, - "local_gas_station_outlined": Icons.local_gas_station_outlined, - "local_grocery_store": Icons.local_grocery_store, - "local_grocery_store_sharp": Icons.local_grocery_store_sharp, - "local_grocery_store_rounded": Icons.local_grocery_store_rounded, - "local_grocery_store_outlined": Icons.local_grocery_store_outlined, - "local_hospital": Icons.local_hospital, - "local_hospital_sharp": Icons.local_hospital_sharp, - "local_hospital_rounded": Icons.local_hospital_rounded, - "local_hospital_outlined": Icons.local_hospital_outlined, - "local_hotel": Icons.local_hotel, - "local_hotel_sharp": Icons.local_hotel_sharp, - "local_hotel_rounded": Icons.local_hotel_rounded, - "local_hotel_outlined": Icons.local_hotel_outlined, - "local_laundry_service": Icons.local_laundry_service, - "local_laundry_service_sharp": Icons.local_laundry_service_sharp, - "local_laundry_service_rounded": Icons.local_laundry_service_rounded, - "local_laundry_service_outlined": Icons.local_laundry_service_outlined, - "local_library": Icons.local_library, - "local_library_sharp": Icons.local_library_sharp, - "local_library_rounded": Icons.local_library_rounded, - "local_library_outlined": Icons.local_library_outlined, - "local_mall": Icons.local_mall, - "local_mall_sharp": Icons.local_mall_sharp, - "local_mall_rounded": Icons.local_mall_rounded, - "local_mall_outlined": Icons.local_mall_outlined, - "local_movies": Icons.local_movies, - "local_movies_sharp": Icons.local_movies_sharp, - "local_movies_rounded": Icons.local_movies_rounded, - "local_movies_outlined": Icons.local_movies_outlined, - "local_offer": Icons.local_offer, - "local_offer_sharp": Icons.local_offer_sharp, - "local_offer_rounded": Icons.local_offer_rounded, - "local_offer_outlined": Icons.local_offer_outlined, - "local_parking": Icons.local_parking, - "local_parking_sharp": Icons.local_parking_sharp, - "local_parking_rounded": Icons.local_parking_rounded, - "local_parking_outlined": Icons.local_parking_outlined, - "local_pharmacy": Icons.local_pharmacy, - "local_pharmacy_sharp": Icons.local_pharmacy_sharp, - "local_pharmacy_rounded": Icons.local_pharmacy_rounded, - "local_pharmacy_outlined": Icons.local_pharmacy_outlined, - "local_phone": Icons.local_phone, - "local_phone_sharp": Icons.local_phone_sharp, - "local_phone_rounded": Icons.local_phone_rounded, - "local_phone_outlined": Icons.local_phone_outlined, - "local_pizza": Icons.local_pizza, - "local_pizza_sharp": Icons.local_pizza_sharp, - "local_pizza_rounded": Icons.local_pizza_rounded, - "local_pizza_outlined": Icons.local_pizza_outlined, - "local_play": Icons.local_play, - "local_play_sharp": Icons.local_play_sharp, - "local_play_rounded": Icons.local_play_rounded, - "local_play_outlined": Icons.local_play_outlined, - "local_police": Icons.local_police, - "local_police_sharp": Icons.local_police_sharp, - "local_police_rounded": Icons.local_police_rounded, - "local_police_outlined": Icons.local_police_outlined, - "local_post_office": Icons.local_post_office, - "local_post_office_sharp": Icons.local_post_office_sharp, - "local_post_office_rounded": Icons.local_post_office_rounded, - "local_post_office_outlined": Icons.local_post_office_outlined, - "local_print_shop": Icons.local_print_shop, - "local_print_shop_sharp": Icons.local_print_shop_sharp, - "local_print_shop_rounded": Icons.local_print_shop_rounded, - "local_print_shop_outlined": Icons.local_print_shop_outlined, - "local_printshop": Icons.local_printshop, - "local_printshop_sharp": Icons.local_printshop_sharp, - "local_printshop_rounded": Icons.local_printshop_rounded, - "local_printshop_outlined": Icons.local_printshop_outlined, - "local_restaurant": Icons.local_restaurant, - "local_restaurant_sharp": Icons.local_restaurant_sharp, - "local_restaurant_rounded": Icons.local_restaurant_rounded, - "local_restaurant_outlined": Icons.local_restaurant_outlined, - "local_see": Icons.local_see, - "local_see_sharp": Icons.local_see_sharp, - "local_see_rounded": Icons.local_see_rounded, - "local_see_outlined": Icons.local_see_outlined, - "local_shipping": Icons.local_shipping, - "local_shipping_sharp": Icons.local_shipping_sharp, - "local_shipping_rounded": Icons.local_shipping_rounded, - "local_shipping_outlined": Icons.local_shipping_outlined, - "local_taxi": Icons.local_taxi, - "local_taxi_sharp": Icons.local_taxi_sharp, - "local_taxi_rounded": Icons.local_taxi_rounded, - "local_taxi_outlined": Icons.local_taxi_outlined, - "location_city": Icons.location_city, - "location_city_sharp": Icons.location_city_sharp, - "location_city_rounded": Icons.location_city_rounded, - "location_city_outlined": Icons.location_city_outlined, - "location_disabled": Icons.location_disabled, - "location_disabled_sharp": Icons.location_disabled_sharp, - "location_disabled_rounded": Icons.location_disabled_rounded, - "location_disabled_outlined": Icons.location_disabled_outlined, - "location_history": Icons.location_history, - "location_history_sharp": Icons.location_history_sharp, - "location_history_rounded": Icons.location_history_rounded, - "location_history_outlined": Icons.location_history_outlined, - "location_off": Icons.location_off, - "location_off_sharp": Icons.location_off_sharp, - "location_off_rounded": Icons.location_off_rounded, - "location_off_outlined": Icons.location_off_outlined, - "location_on": Icons.location_on, - "location_on_sharp": Icons.location_on_sharp, - "location_on_rounded": Icons.location_on_rounded, - "location_on_outlined": Icons.location_on_outlined, - "location_pin": Icons.location_pin, - "location_searching": Icons.location_searching, - "location_searching_sharp": Icons.location_searching_sharp, - "location_searching_rounded": Icons.location_searching_rounded, - "location_searching_outlined": Icons.location_searching_outlined, - "lock": Icons.lock, - "lock_sharp": Icons.lock_sharp, - "lock_rounded": Icons.lock_rounded, - "lock_outlined": Icons.lock_outlined, - "lock_clock": Icons.lock_clock, - "lock_clock_sharp": Icons.lock_clock_sharp, - "lock_clock_rounded": Icons.lock_clock_rounded, - "lock_clock_outlined": Icons.lock_clock_outlined, - "lock_open": Icons.lock_open, - "lock_open_sharp": Icons.lock_open_sharp, - "lock_open_rounded": Icons.lock_open_rounded, - "lock_open_outlined": Icons.lock_open_outlined, - "lock_outline": Icons.lock_outline, - "lock_outline_sharp": Icons.lock_outline_sharp, - "lock_outline_rounded": Icons.lock_outline_rounded, - "lock_person": Icons.lock_person, - "lock_person_sharp": Icons.lock_person_sharp, - "lock_person_rounded": Icons.lock_person_rounded, - "lock_person_outlined": Icons.lock_person_outlined, - "lock_reset": Icons.lock_reset, - "lock_reset_sharp": Icons.lock_reset_sharp, - "lock_reset_rounded": Icons.lock_reset_rounded, - "lock_reset_outlined": Icons.lock_reset_outlined, - "login": Icons.login, - "login_sharp": Icons.login_sharp, - "login_rounded": Icons.login_rounded, - "login_outlined": Icons.login_outlined, - "logo_dev": Icons.logo_dev, - "logo_dev_sharp": Icons.logo_dev_sharp, - "logo_dev_rounded": Icons.logo_dev_rounded, - "logo_dev_outlined": Icons.logo_dev_outlined, - "logout": Icons.logout, - "logout_sharp": Icons.logout_sharp, - "logout_rounded": Icons.logout_rounded, - "logout_outlined": Icons.logout_outlined, - "looks": Icons.looks, - "looks_sharp": Icons.looks_sharp, - "looks_rounded": Icons.looks_rounded, - "looks_outlined": Icons.looks_outlined, - "looks_3": Icons.looks_3, - "looks_3_sharp": Icons.looks_3_sharp, - "looks_3_rounded": Icons.looks_3_rounded, - "looks_3_outlined": Icons.looks_3_outlined, - "looks_4": Icons.looks_4, - "looks_4_sharp": Icons.looks_4_sharp, - "looks_4_rounded": Icons.looks_4_rounded, - "looks_4_outlined": Icons.looks_4_outlined, - "looks_5": Icons.looks_5, - "looks_5_sharp": Icons.looks_5_sharp, - "looks_5_rounded": Icons.looks_5_rounded, - "looks_5_outlined": Icons.looks_5_outlined, - "looks_6": Icons.looks_6, - "looks_6_sharp": Icons.looks_6_sharp, - "looks_6_rounded": Icons.looks_6_rounded, - "looks_6_outlined": Icons.looks_6_outlined, - "looks_one": Icons.looks_one, - "looks_one_sharp": Icons.looks_one_sharp, - "looks_one_rounded": Icons.looks_one_rounded, - "looks_one_outlined": Icons.looks_one_outlined, - "looks_two": Icons.looks_two, - "looks_two_sharp": Icons.looks_two_sharp, - "looks_two_rounded": Icons.looks_two_rounded, - "looks_two_outlined": Icons.looks_two_outlined, - "loop": Icons.loop, - "loop_sharp": Icons.loop_sharp, - "loop_rounded": Icons.loop_rounded, - "loop_outlined": Icons.loop_outlined, - "loupe": Icons.loupe, - "loupe_sharp": Icons.loupe_sharp, - "loupe_rounded": Icons.loupe_rounded, - "loupe_outlined": Icons.loupe_outlined, - "low_priority": Icons.low_priority, - "low_priority_sharp": Icons.low_priority_sharp, - "low_priority_rounded": Icons.low_priority_rounded, - "low_priority_outlined": Icons.low_priority_outlined, - "loyalty": Icons.loyalty, - "loyalty_sharp": Icons.loyalty_sharp, - "loyalty_rounded": Icons.loyalty_rounded, - "loyalty_outlined": Icons.loyalty_outlined, - "lte_mobiledata": Icons.lte_mobiledata, - "lte_mobiledata_sharp": Icons.lte_mobiledata_sharp, - "lte_mobiledata_rounded": Icons.lte_mobiledata_rounded, - "lte_mobiledata_outlined": Icons.lte_mobiledata_outlined, - "lte_plus_mobiledata": Icons.lte_plus_mobiledata, - "lte_plus_mobiledata_sharp": Icons.lte_plus_mobiledata_sharp, - "lte_plus_mobiledata_rounded": Icons.lte_plus_mobiledata_rounded, - "lte_plus_mobiledata_outlined": Icons.lte_plus_mobiledata_outlined, - "luggage": Icons.luggage, - "luggage_sharp": Icons.luggage_sharp, - "luggage_rounded": Icons.luggage_rounded, - "luggage_outlined": Icons.luggage_outlined, - "lunch_dining": Icons.lunch_dining, - "lunch_dining_sharp": Icons.lunch_dining_sharp, - "lunch_dining_rounded": Icons.lunch_dining_rounded, - "lunch_dining_outlined": Icons.lunch_dining_outlined, - "lyrics": Icons.lyrics, - "lyrics_sharp": Icons.lyrics_sharp, - "lyrics_rounded": Icons.lyrics_rounded, - "lyrics_outlined": Icons.lyrics_outlined, - "macro_off": Icons.macro_off, - "macro_off_sharp": Icons.macro_off_sharp, - "macro_off_rounded": Icons.macro_off_rounded, - "macro_off_outlined": Icons.macro_off_outlined, - "mail": Icons.mail, - "mail_sharp": Icons.mail_sharp, - "mail_rounded": Icons.mail_rounded, - "mail_outlined": Icons.mail_outlined, - "mail_lock": Icons.mail_lock, - "mail_lock_sharp": Icons.mail_lock_sharp, - "mail_lock_rounded": Icons.mail_lock_rounded, - "mail_lock_outlined": Icons.mail_lock_outlined, - "mail_outline": Icons.mail_outline, - "mail_outline_sharp": Icons.mail_outline_sharp, - "mail_outline_rounded": Icons.mail_outline_rounded, - "mail_outline_outlined": Icons.mail_outline_outlined, - "male": Icons.male, - "male_sharp": Icons.male_sharp, - "male_rounded": Icons.male_rounded, - "male_outlined": Icons.male_outlined, - "man": Icons.man, - "man_sharp": Icons.man_sharp, - "man_rounded": Icons.man_rounded, - "man_outlined": Icons.man_outlined, - "man_2": Icons.man_2, - "man_2_sharp": Icons.man_2_sharp, - "man_2_rounded": Icons.man_2_rounded, - "man_2_outlined": Icons.man_2_outlined, - "man_3": Icons.man_3, - "man_3_sharp": Icons.man_3_sharp, - "man_3_rounded": Icons.man_3_rounded, - "man_3_outlined": Icons.man_3_outlined, - "man_4": Icons.man_4, - "man_4_sharp": Icons.man_4_sharp, - "man_4_rounded": Icons.man_4_rounded, - "man_4_outlined": Icons.man_4_outlined, - "manage_accounts": Icons.manage_accounts, - "manage_accounts_sharp": Icons.manage_accounts_sharp, - "manage_accounts_rounded": Icons.manage_accounts_rounded, - "manage_accounts_outlined": Icons.manage_accounts_outlined, - "manage_history": Icons.manage_history, - "manage_history_sharp": Icons.manage_history_sharp, - "manage_history_rounded": Icons.manage_history_rounded, - "manage_history_outlined": Icons.manage_history_outlined, - "manage_search": Icons.manage_search, - "manage_search_sharp": Icons.manage_search_sharp, - "manage_search_rounded": Icons.manage_search_rounded, - "manage_search_outlined": Icons.manage_search_outlined, - "map": Icons.map, - "map_sharp": Icons.map_sharp, - "map_rounded": Icons.map_rounded, - "map_outlined": Icons.map_outlined, - "maps_home_work": Icons.maps_home_work, - "maps_home_work_sharp": Icons.maps_home_work_sharp, - "maps_home_work_rounded": Icons.maps_home_work_rounded, - "maps_home_work_outlined": Icons.maps_home_work_outlined, - "maps_ugc": Icons.maps_ugc, - "maps_ugc_sharp": Icons.maps_ugc_sharp, - "maps_ugc_rounded": Icons.maps_ugc_rounded, - "maps_ugc_outlined": Icons.maps_ugc_outlined, - "margin": Icons.margin, - "margin_sharp": Icons.margin_sharp, - "margin_rounded": Icons.margin_rounded, - "margin_outlined": Icons.margin_outlined, - "mark_as_unread": Icons.mark_as_unread, - "mark_as_unread_sharp": Icons.mark_as_unread_sharp, - "mark_as_unread_rounded": Icons.mark_as_unread_rounded, - "mark_as_unread_outlined": Icons.mark_as_unread_outlined, - "mark_chat_read": Icons.mark_chat_read, - "mark_chat_read_sharp": Icons.mark_chat_read_sharp, - "mark_chat_read_rounded": Icons.mark_chat_read_rounded, - "mark_chat_read_outlined": Icons.mark_chat_read_outlined, - "mark_chat_unread": Icons.mark_chat_unread, - "mark_chat_unread_sharp": Icons.mark_chat_unread_sharp, - "mark_chat_unread_rounded": Icons.mark_chat_unread_rounded, - "mark_chat_unread_outlined": Icons.mark_chat_unread_outlined, - "mark_email_read": Icons.mark_email_read, - "mark_email_read_sharp": Icons.mark_email_read_sharp, - "mark_email_read_rounded": Icons.mark_email_read_rounded, - "mark_email_read_outlined": Icons.mark_email_read_outlined, - "mark_email_unread": Icons.mark_email_unread, - "mark_email_unread_sharp": Icons.mark_email_unread_sharp, - "mark_email_unread_rounded": Icons.mark_email_unread_rounded, - "mark_email_unread_outlined": Icons.mark_email_unread_outlined, - "mark_unread_chat_alt": Icons.mark_unread_chat_alt, - "mark_unread_chat_alt_sharp": Icons.mark_unread_chat_alt_sharp, - "mark_unread_chat_alt_rounded": Icons.mark_unread_chat_alt_rounded, - "mark_unread_chat_alt_outlined": Icons.mark_unread_chat_alt_outlined, - "markunread": Icons.markunread, - "markunread_sharp": Icons.markunread_sharp, - "markunread_rounded": Icons.markunread_rounded, - "markunread_outlined": Icons.markunread_outlined, - "markunread_mailbox": Icons.markunread_mailbox, - "markunread_mailbox_sharp": Icons.markunread_mailbox_sharp, - "markunread_mailbox_rounded": Icons.markunread_mailbox_rounded, - "markunread_mailbox_outlined": Icons.markunread_mailbox_outlined, - "masks": Icons.masks, - "masks_sharp": Icons.masks_sharp, - "masks_rounded": Icons.masks_rounded, - "masks_outlined": Icons.masks_outlined, - "maximize": Icons.maximize, - "maximize_sharp": Icons.maximize_sharp, - "maximize_rounded": Icons.maximize_rounded, - "maximize_outlined": Icons.maximize_outlined, - "media_bluetooth_off": Icons.media_bluetooth_off, - "media_bluetooth_off_sharp": Icons.media_bluetooth_off_sharp, - "media_bluetooth_off_rounded": Icons.media_bluetooth_off_rounded, - "media_bluetooth_off_outlined": Icons.media_bluetooth_off_outlined, - "media_bluetooth_on": Icons.media_bluetooth_on, - "media_bluetooth_on_sharp": Icons.media_bluetooth_on_sharp, - "media_bluetooth_on_rounded": Icons.media_bluetooth_on_rounded, - "media_bluetooth_on_outlined": Icons.media_bluetooth_on_outlined, - "mediation": Icons.mediation, - "mediation_sharp": Icons.mediation_sharp, - "mediation_rounded": Icons.mediation_rounded, - "mediation_outlined": Icons.mediation_outlined, - "medical_information": Icons.medical_information, - "medical_information_sharp": Icons.medical_information_sharp, - "medical_information_rounded": Icons.medical_information_rounded, - "medical_information_outlined": Icons.medical_information_outlined, - "medical_services": Icons.medical_services, - "medical_services_sharp": Icons.medical_services_sharp, - "medical_services_rounded": Icons.medical_services_rounded, - "medical_services_outlined": Icons.medical_services_outlined, - "medication": Icons.medication, - "medication_sharp": Icons.medication_sharp, - "medication_rounded": Icons.medication_rounded, - "medication_outlined": Icons.medication_outlined, - "medication_liquid": Icons.medication_liquid, - "medication_liquid_sharp": Icons.medication_liquid_sharp, - "medication_liquid_rounded": Icons.medication_liquid_rounded, - "medication_liquid_outlined": Icons.medication_liquid_outlined, - "meeting_room": Icons.meeting_room, - "meeting_room_sharp": Icons.meeting_room_sharp, - "meeting_room_rounded": Icons.meeting_room_rounded, - "meeting_room_outlined": Icons.meeting_room_outlined, - "memory": Icons.memory, - "memory_sharp": Icons.memory_sharp, - "memory_rounded": Icons.memory_rounded, - "memory_outlined": Icons.memory_outlined, - "menu": Icons.menu, - "menu_sharp": Icons.menu_sharp, - "menu_rounded": Icons.menu_rounded, - "menu_outlined": Icons.menu_outlined, - "menu_book": Icons.menu_book, - "menu_book_sharp": Icons.menu_book_sharp, - "menu_book_rounded": Icons.menu_book_rounded, - "menu_book_outlined": Icons.menu_book_outlined, - "menu_open": Icons.menu_open, - "menu_open_sharp": Icons.menu_open_sharp, - "menu_open_rounded": Icons.menu_open_rounded, - "menu_open_outlined": Icons.menu_open_outlined, - "merge": Icons.merge, - "merge_sharp": Icons.merge_sharp, - "merge_rounded": Icons.merge_rounded, - "merge_outlined": Icons.merge_outlined, - "merge_type": Icons.merge_type, - "merge_type_sharp": Icons.merge_type_sharp, - "merge_type_rounded": Icons.merge_type_rounded, - "merge_type_outlined": Icons.merge_type_outlined, - "message": Icons.message, - "message_sharp": Icons.message_sharp, - "message_rounded": Icons.message_rounded, - "message_outlined": Icons.message_outlined, - "messenger": Icons.messenger, - "messenger_sharp": Icons.messenger_sharp, - "messenger_rounded": Icons.messenger_rounded, - "messenger_outlined": Icons.messenger_outlined, - "messenger_outline": Icons.messenger_outline, - "messenger_outline_sharp": Icons.messenger_outline_sharp, - "messenger_outline_rounded": Icons.messenger_outline_rounded, - "messenger_outline_outlined": Icons.messenger_outline_outlined, - "mic": Icons.mic, - "mic_sharp": Icons.mic_sharp, - "mic_rounded": Icons.mic_rounded, - "mic_outlined": Icons.mic_outlined, - "mic_external_off": Icons.mic_external_off, - "mic_external_off_sharp": Icons.mic_external_off_sharp, - "mic_external_off_rounded": Icons.mic_external_off_rounded, - "mic_external_off_outlined": Icons.mic_external_off_outlined, - "mic_external_on": Icons.mic_external_on, - "mic_external_on_sharp": Icons.mic_external_on_sharp, - "mic_external_on_rounded": Icons.mic_external_on_rounded, - "mic_external_on_outlined": Icons.mic_external_on_outlined, - "mic_none": Icons.mic_none, - "mic_none_sharp": Icons.mic_none_sharp, - "mic_none_rounded": Icons.mic_none_rounded, - "mic_none_outlined": Icons.mic_none_outlined, - "mic_off": Icons.mic_off, - "mic_off_sharp": Icons.mic_off_sharp, - "mic_off_rounded": Icons.mic_off_rounded, - "mic_off_outlined": Icons.mic_off_outlined, - "microwave": Icons.microwave, - "microwave_sharp": Icons.microwave_sharp, - "microwave_rounded": Icons.microwave_rounded, - "microwave_outlined": Icons.microwave_outlined, - "military_tech": Icons.military_tech, - "military_tech_sharp": Icons.military_tech_sharp, - "military_tech_rounded": Icons.military_tech_rounded, - "military_tech_outlined": Icons.military_tech_outlined, - "minimize": Icons.minimize, - "minimize_sharp": Icons.minimize_sharp, - "minimize_rounded": Icons.minimize_rounded, - "minimize_outlined": Icons.minimize_outlined, - "minor_crash": Icons.minor_crash, - "minor_crash_sharp": Icons.minor_crash_sharp, - "minor_crash_rounded": Icons.minor_crash_rounded, - "minor_crash_outlined": Icons.minor_crash_outlined, - "miscellaneous_services": Icons.miscellaneous_services, - "miscellaneous_services_sharp": Icons.miscellaneous_services_sharp, - "miscellaneous_services_rounded": Icons.miscellaneous_services_rounded, - "miscellaneous_services_outlined": Icons.miscellaneous_services_outlined, - "missed_video_call": Icons.missed_video_call, - "missed_video_call_sharp": Icons.missed_video_call_sharp, - "missed_video_call_rounded": Icons.missed_video_call_rounded, - "missed_video_call_outlined": Icons.missed_video_call_outlined, - "mms": Icons.mms, - "mms_sharp": Icons.mms_sharp, - "mms_rounded": Icons.mms_rounded, - "mms_outlined": Icons.mms_outlined, - "mobile_friendly": Icons.mobile_friendly, - "mobile_friendly_sharp": Icons.mobile_friendly_sharp, - "mobile_friendly_rounded": Icons.mobile_friendly_rounded, - "mobile_friendly_outlined": Icons.mobile_friendly_outlined, - "mobile_off": Icons.mobile_off, - "mobile_off_sharp": Icons.mobile_off_sharp, - "mobile_off_rounded": Icons.mobile_off_rounded, - "mobile_off_outlined": Icons.mobile_off_outlined, - "mobile_screen_share": Icons.mobile_screen_share, - "mobile_screen_share_sharp": Icons.mobile_screen_share_sharp, - "mobile_screen_share_rounded": Icons.mobile_screen_share_rounded, - "mobile_screen_share_outlined": Icons.mobile_screen_share_outlined, - "mobiledata_off": Icons.mobiledata_off, - "mobiledata_off_sharp": Icons.mobiledata_off_sharp, - "mobiledata_off_rounded": Icons.mobiledata_off_rounded, - "mobiledata_off_outlined": Icons.mobiledata_off_outlined, - "mode": Icons.mode, - "mode_sharp": Icons.mode_sharp, - "mode_rounded": Icons.mode_rounded, - "mode_outlined": Icons.mode_outlined, - "mode_comment": Icons.mode_comment, - "mode_comment_sharp": Icons.mode_comment_sharp, - "mode_comment_rounded": Icons.mode_comment_rounded, - "mode_comment_outlined": Icons.mode_comment_outlined, - "mode_edit": Icons.mode_edit, - "mode_edit_sharp": Icons.mode_edit_sharp, - "mode_edit_rounded": Icons.mode_edit_rounded, - "mode_edit_outlined": Icons.mode_edit_outlined, - "mode_edit_outline": Icons.mode_edit_outline, - "mode_edit_outline_sharp": Icons.mode_edit_outline_sharp, - "mode_edit_outline_rounded": Icons.mode_edit_outline_rounded, - "mode_edit_outline_outlined": Icons.mode_edit_outline_outlined, - "mode_fan_off": Icons.mode_fan_off, - "mode_fan_off_sharp": Icons.mode_fan_off_sharp, - "mode_fan_off_rounded": Icons.mode_fan_off_rounded, - "mode_fan_off_outlined": Icons.mode_fan_off_outlined, - "mode_night": Icons.mode_night, - "mode_night_sharp": Icons.mode_night_sharp, - "mode_night_rounded": Icons.mode_night_rounded, - "mode_night_outlined": Icons.mode_night_outlined, - "mode_of_travel": Icons.mode_of_travel, - "mode_of_travel_sharp": Icons.mode_of_travel_sharp, - "mode_of_travel_rounded": Icons.mode_of_travel_rounded, - "mode_of_travel_outlined": Icons.mode_of_travel_outlined, - "mode_standby": Icons.mode_standby, - "mode_standby_sharp": Icons.mode_standby_sharp, - "mode_standby_rounded": Icons.mode_standby_rounded, - "mode_standby_outlined": Icons.mode_standby_outlined, - "model_training": Icons.model_training, - "model_training_sharp": Icons.model_training_sharp, - "model_training_rounded": Icons.model_training_rounded, - "model_training_outlined": Icons.model_training_outlined, - "monetization_on": Icons.monetization_on, - "monetization_on_sharp": Icons.monetization_on_sharp, - "monetization_on_rounded": Icons.monetization_on_rounded, - "monetization_on_outlined": Icons.monetization_on_outlined, - "money": Icons.money, - "money_sharp": Icons.money_sharp, - "money_rounded": Icons.money_rounded, - "money_outlined": Icons.money_outlined, - "money_off": Icons.money_off, - "money_off_sharp": Icons.money_off_sharp, - "money_off_rounded": Icons.money_off_rounded, - "money_off_outlined": Icons.money_off_outlined, - "money_off_csred": Icons.money_off_csred, - "money_off_csred_sharp": Icons.money_off_csred_sharp, - "money_off_csred_rounded": Icons.money_off_csred_rounded, - "money_off_csred_outlined": Icons.money_off_csred_outlined, - "monitor": Icons.monitor, - "monitor_sharp": Icons.monitor_sharp, - "monitor_rounded": Icons.monitor_rounded, - "monitor_outlined": Icons.monitor_outlined, - "monitor_heart": Icons.monitor_heart, - "monitor_heart_sharp": Icons.monitor_heart_sharp, - "monitor_heart_rounded": Icons.monitor_heart_rounded, - "monitor_heart_outlined": Icons.monitor_heart_outlined, - "monitor_weight": Icons.monitor_weight, - "monitor_weight_sharp": Icons.monitor_weight_sharp, - "monitor_weight_rounded": Icons.monitor_weight_rounded, - "monitor_weight_outlined": Icons.monitor_weight_outlined, - "monochrome_photos": Icons.monochrome_photos, - "monochrome_photos_sharp": Icons.monochrome_photos_sharp, - "monochrome_photos_rounded": Icons.monochrome_photos_rounded, - "monochrome_photos_outlined": Icons.monochrome_photos_outlined, - "mood": Icons.mood, - "mood_sharp": Icons.mood_sharp, - "mood_rounded": Icons.mood_rounded, - "mood_outlined": Icons.mood_outlined, - "mood_bad": Icons.mood_bad, - "mood_bad_sharp": Icons.mood_bad_sharp, - "mood_bad_rounded": Icons.mood_bad_rounded, - "mood_bad_outlined": Icons.mood_bad_outlined, - "moped": Icons.moped, - "moped_sharp": Icons.moped_sharp, - "moped_rounded": Icons.moped_rounded, - "moped_outlined": Icons.moped_outlined, - "more": Icons.more, - "more_sharp": Icons.more_sharp, - "more_rounded": Icons.more_rounded, - "more_outlined": Icons.more_outlined, - "more_horiz": Icons.more_horiz, - "more_horiz_sharp": Icons.more_horiz_sharp, - "more_horiz_rounded": Icons.more_horiz_rounded, - "more_horiz_outlined": Icons.more_horiz_outlined, - "more_time": Icons.more_time, - "more_time_sharp": Icons.more_time_sharp, - "more_time_rounded": Icons.more_time_rounded, - "more_time_outlined": Icons.more_time_outlined, - "more_vert": Icons.more_vert, - "more_vert_sharp": Icons.more_vert_sharp, - "more_vert_rounded": Icons.more_vert_rounded, - "more_vert_outlined": Icons.more_vert_outlined, - "mosque": Icons.mosque, - "mosque_sharp": Icons.mosque_sharp, - "mosque_rounded": Icons.mosque_rounded, - "mosque_outlined": Icons.mosque_outlined, - "motion_photos_auto": Icons.motion_photos_auto, - "motion_photos_auto_sharp": Icons.motion_photos_auto_sharp, - "motion_photos_auto_rounded": Icons.motion_photos_auto_rounded, - "motion_photos_auto_outlined": Icons.motion_photos_auto_outlined, - "motion_photos_off": Icons.motion_photos_off, - "motion_photos_off_sharp": Icons.motion_photos_off_sharp, - "motion_photos_off_rounded": Icons.motion_photos_off_rounded, - "motion_photos_off_outlined": Icons.motion_photos_off_outlined, - "motion_photos_on": Icons.motion_photos_on, - "motion_photos_on_sharp": Icons.motion_photos_on_sharp, - "motion_photos_on_rounded": Icons.motion_photos_on_rounded, - "motion_photos_on_outlined": Icons.motion_photos_on_outlined, - "motion_photos_pause": Icons.motion_photos_pause, - "motion_photos_pause_sharp": Icons.motion_photos_pause_sharp, - "motion_photos_pause_rounded": Icons.motion_photos_pause_rounded, - "motion_photos_pause_outlined": Icons.motion_photos_pause_outlined, - "motion_photos_paused": Icons.motion_photos_paused, - "motion_photos_paused_sharp": Icons.motion_photos_paused_sharp, - "motion_photos_paused_rounded": Icons.motion_photos_paused_rounded, - "motion_photos_paused_outlined": Icons.motion_photos_paused_outlined, - "motorcycle": Icons.motorcycle, - "motorcycle_sharp": Icons.motorcycle_sharp, - "motorcycle_rounded": Icons.motorcycle_rounded, - "motorcycle_outlined": Icons.motorcycle_outlined, - "mouse": Icons.mouse, - "mouse_sharp": Icons.mouse_sharp, - "mouse_rounded": Icons.mouse_rounded, - "mouse_outlined": Icons.mouse_outlined, - "move_down": Icons.move_down, - "move_down_sharp": Icons.move_down_sharp, - "move_down_rounded": Icons.move_down_rounded, - "move_down_outlined": Icons.move_down_outlined, - "move_to_inbox": Icons.move_to_inbox, - "move_to_inbox_sharp": Icons.move_to_inbox_sharp, - "move_to_inbox_rounded": Icons.move_to_inbox_rounded, - "move_to_inbox_outlined": Icons.move_to_inbox_outlined, - "move_up": Icons.move_up, - "move_up_sharp": Icons.move_up_sharp, - "move_up_rounded": Icons.move_up_rounded, - "move_up_outlined": Icons.move_up_outlined, - "movie": Icons.movie, - "movie_sharp": Icons.movie_sharp, - "movie_rounded": Icons.movie_rounded, - "movie_outlined": Icons.movie_outlined, - "movie_creation": Icons.movie_creation, - "movie_creation_sharp": Icons.movie_creation_sharp, - "movie_creation_rounded": Icons.movie_creation_rounded, - "movie_creation_outlined": Icons.movie_creation_outlined, - "movie_edit": Icons.movie_edit, - "movie_filter": Icons.movie_filter, - "movie_filter_sharp": Icons.movie_filter_sharp, - "movie_filter_rounded": Icons.movie_filter_rounded, - "movie_filter_outlined": Icons.movie_filter_outlined, - "moving": Icons.moving, - "moving_sharp": Icons.moving_sharp, - "moving_rounded": Icons.moving_rounded, - "moving_outlined": Icons.moving_outlined, - "mp": Icons.mp, - "mp_sharp": Icons.mp_sharp, - "mp_rounded": Icons.mp_rounded, - "mp_outlined": Icons.mp_outlined, - "multiline_chart": Icons.multiline_chart, - "multiline_chart_sharp": Icons.multiline_chart_sharp, - "multiline_chart_rounded": Icons.multiline_chart_rounded, - "multiline_chart_outlined": Icons.multiline_chart_outlined, - "multiple_stop": Icons.multiple_stop, - "multiple_stop_sharp": Icons.multiple_stop_sharp, - "multiple_stop_rounded": Icons.multiple_stop_rounded, - "multiple_stop_outlined": Icons.multiple_stop_outlined, - "multitrack_audio": Icons.multitrack_audio, - "multitrack_audio_sharp": Icons.multitrack_audio_sharp, - "multitrack_audio_rounded": Icons.multitrack_audio_rounded, - "multitrack_audio_outlined": Icons.multitrack_audio_outlined, - "museum": Icons.museum, - "museum_sharp": Icons.museum_sharp, - "museum_rounded": Icons.museum_rounded, - "museum_outlined": Icons.museum_outlined, - "music_note": Icons.music_note, - "music_note_sharp": Icons.music_note_sharp, - "music_note_rounded": Icons.music_note_rounded, - "music_note_outlined": Icons.music_note_outlined, - "music_off": Icons.music_off, - "music_off_sharp": Icons.music_off_sharp, - "music_off_rounded": Icons.music_off_rounded, - "music_off_outlined": Icons.music_off_outlined, - "music_video": Icons.music_video, - "music_video_sharp": Icons.music_video_sharp, - "music_video_rounded": Icons.music_video_rounded, - "music_video_outlined": Icons.music_video_outlined, - "my_library_add": Icons.my_library_add, - "my_library_add_sharp": Icons.my_library_add_sharp, - "my_library_add_rounded": Icons.my_library_add_rounded, - "my_library_add_outlined": Icons.my_library_add_outlined, - "my_library_books": Icons.my_library_books, - "my_library_books_sharp": Icons.my_library_books_sharp, - "my_library_books_rounded": Icons.my_library_books_rounded, - "my_library_books_outlined": Icons.my_library_books_outlined, - "my_library_music": Icons.my_library_music, - "my_library_music_sharp": Icons.my_library_music_sharp, - "my_library_music_rounded": Icons.my_library_music_rounded, - "my_library_music_outlined": Icons.my_library_music_outlined, - "my_location": Icons.my_location, - "my_location_sharp": Icons.my_location_sharp, - "my_location_rounded": Icons.my_location_rounded, - "my_location_outlined": Icons.my_location_outlined, - "nat": Icons.nat, - "nat_sharp": Icons.nat_sharp, - "nat_rounded": Icons.nat_rounded, - "nat_outlined": Icons.nat_outlined, - "nature": Icons.nature, - "nature_sharp": Icons.nature_sharp, - "nature_rounded": Icons.nature_rounded, - "nature_outlined": Icons.nature_outlined, - "nature_people": Icons.nature_people, - "nature_people_sharp": Icons.nature_people_sharp, - "nature_people_rounded": Icons.nature_people_rounded, - "nature_people_outlined": Icons.nature_people_outlined, - "navigate_before": Icons.navigate_before, - "navigate_before_sharp": Icons.navigate_before_sharp, - "navigate_before_rounded": Icons.navigate_before_rounded, - "navigate_before_outlined": Icons.navigate_before_outlined, - "navigate_next": Icons.navigate_next, - "navigate_next_sharp": Icons.navigate_next_sharp, - "navigate_next_rounded": Icons.navigate_next_rounded, - "navigate_next_outlined": Icons.navigate_next_outlined, - "navigation": Icons.navigation, - "navigation_sharp": Icons.navigation_sharp, - "navigation_rounded": Icons.navigation_rounded, - "navigation_outlined": Icons.navigation_outlined, - "near_me": Icons.near_me, - "near_me_sharp": Icons.near_me_sharp, - "near_me_rounded": Icons.near_me_rounded, - "near_me_outlined": Icons.near_me_outlined, - "near_me_disabled": Icons.near_me_disabled, - "near_me_disabled_sharp": Icons.near_me_disabled_sharp, - "near_me_disabled_rounded": Icons.near_me_disabled_rounded, - "near_me_disabled_outlined": Icons.near_me_disabled_outlined, - "nearby_error": Icons.nearby_error, - "nearby_error_sharp": Icons.nearby_error_sharp, - "nearby_error_rounded": Icons.nearby_error_rounded, - "nearby_error_outlined": Icons.nearby_error_outlined, - "nearby_off": Icons.nearby_off, - "nearby_off_sharp": Icons.nearby_off_sharp, - "nearby_off_rounded": Icons.nearby_off_rounded, - "nearby_off_outlined": Icons.nearby_off_outlined, - "nest_cam_wired_stand": Icons.nest_cam_wired_stand, - "nest_cam_wired_stand_sharp": Icons.nest_cam_wired_stand_sharp, - "nest_cam_wired_stand_rounded": Icons.nest_cam_wired_stand_rounded, - "nest_cam_wired_stand_outlined": Icons.nest_cam_wired_stand_outlined, - "network_cell": Icons.network_cell, - "network_cell_sharp": Icons.network_cell_sharp, - "network_cell_rounded": Icons.network_cell_rounded, - "network_cell_outlined": Icons.network_cell_outlined, - "network_check": Icons.network_check, - "network_check_sharp": Icons.network_check_sharp, - "network_check_rounded": Icons.network_check_rounded, - "network_check_outlined": Icons.network_check_outlined, - "network_locked": Icons.network_locked, - "network_locked_sharp": Icons.network_locked_sharp, - "network_locked_rounded": Icons.network_locked_rounded, - "network_locked_outlined": Icons.network_locked_outlined, - "network_ping": Icons.network_ping, - "network_ping_sharp": Icons.network_ping_sharp, - "network_ping_rounded": Icons.network_ping_rounded, - "network_ping_outlined": Icons.network_ping_outlined, - "network_wifi": Icons.network_wifi, - "network_wifi_sharp": Icons.network_wifi_sharp, - "network_wifi_rounded": Icons.network_wifi_rounded, - "network_wifi_outlined": Icons.network_wifi_outlined, - "network_wifi_1_bar": Icons.network_wifi_1_bar, - "network_wifi_1_bar_sharp": Icons.network_wifi_1_bar_sharp, - "network_wifi_1_bar_rounded": Icons.network_wifi_1_bar_rounded, - "network_wifi_1_bar_outlined": Icons.network_wifi_1_bar_outlined, - "network_wifi_2_bar": Icons.network_wifi_2_bar, - "network_wifi_2_bar_sharp": Icons.network_wifi_2_bar_sharp, - "network_wifi_2_bar_rounded": Icons.network_wifi_2_bar_rounded, - "network_wifi_2_bar_outlined": Icons.network_wifi_2_bar_outlined, - "network_wifi_3_bar": Icons.network_wifi_3_bar, - "network_wifi_3_bar_sharp": Icons.network_wifi_3_bar_sharp, - "network_wifi_3_bar_rounded": Icons.network_wifi_3_bar_rounded, - "network_wifi_3_bar_outlined": Icons.network_wifi_3_bar_outlined, - "new_label": Icons.new_label, - "new_label_sharp": Icons.new_label_sharp, - "new_label_rounded": Icons.new_label_rounded, - "new_label_outlined": Icons.new_label_outlined, - "new_releases": Icons.new_releases, - "new_releases_sharp": Icons.new_releases_sharp, - "new_releases_rounded": Icons.new_releases_rounded, - "new_releases_outlined": Icons.new_releases_outlined, - "newspaper": Icons.newspaper, - "newspaper_sharp": Icons.newspaper_sharp, - "newspaper_rounded": Icons.newspaper_rounded, - "newspaper_outlined": Icons.newspaper_outlined, - "next_plan": Icons.next_plan, - "next_plan_sharp": Icons.next_plan_sharp, - "next_plan_rounded": Icons.next_plan_rounded, - "next_plan_outlined": Icons.next_plan_outlined, - "next_week": Icons.next_week, - "next_week_sharp": Icons.next_week_sharp, - "next_week_rounded": Icons.next_week_rounded, - "next_week_outlined": Icons.next_week_outlined, - "nfc": Icons.nfc, - "nfc_sharp": Icons.nfc_sharp, - "nfc_rounded": Icons.nfc_rounded, - "nfc_outlined": Icons.nfc_outlined, - "night_shelter": Icons.night_shelter, - "night_shelter_sharp": Icons.night_shelter_sharp, - "night_shelter_rounded": Icons.night_shelter_rounded, - "night_shelter_outlined": Icons.night_shelter_outlined, - "nightlife": Icons.nightlife, - "nightlife_sharp": Icons.nightlife_sharp, - "nightlife_rounded": Icons.nightlife_rounded, - "nightlife_outlined": Icons.nightlife_outlined, - "nightlight": Icons.nightlight, - "nightlight_sharp": Icons.nightlight_sharp, - "nightlight_rounded": Icons.nightlight_rounded, - "nightlight_outlined": Icons.nightlight_outlined, - "nightlight_round": Icons.nightlight_round, - "nightlight_round_sharp": Icons.nightlight_round_sharp, - "nightlight_round_rounded": Icons.nightlight_round_rounded, - "nightlight_round_outlined": Icons.nightlight_round_outlined, - "nights_stay": Icons.nights_stay, - "nights_stay_sharp": Icons.nights_stay_sharp, - "nights_stay_rounded": Icons.nights_stay_rounded, - "nights_stay_outlined": Icons.nights_stay_outlined, - "no_accounts": Icons.no_accounts, - "no_accounts_sharp": Icons.no_accounts_sharp, - "no_accounts_rounded": Icons.no_accounts_rounded, - "no_accounts_outlined": Icons.no_accounts_outlined, - "no_adult_content": Icons.no_adult_content, - "no_adult_content_sharp": Icons.no_adult_content_sharp, - "no_adult_content_rounded": Icons.no_adult_content_rounded, - "no_adult_content_outlined": Icons.no_adult_content_outlined, - "no_backpack": Icons.no_backpack, - "no_backpack_sharp": Icons.no_backpack_sharp, - "no_backpack_rounded": Icons.no_backpack_rounded, - "no_backpack_outlined": Icons.no_backpack_outlined, - "no_cell": Icons.no_cell, - "no_cell_sharp": Icons.no_cell_sharp, - "no_cell_rounded": Icons.no_cell_rounded, - "no_cell_outlined": Icons.no_cell_outlined, - "no_crash": Icons.no_crash, - "no_crash_sharp": Icons.no_crash_sharp, - "no_crash_rounded": Icons.no_crash_rounded, - "no_crash_outlined": Icons.no_crash_outlined, - "no_drinks": Icons.no_drinks, - "no_drinks_sharp": Icons.no_drinks_sharp, - "no_drinks_rounded": Icons.no_drinks_rounded, - "no_drinks_outlined": Icons.no_drinks_outlined, - "no_encryption": Icons.no_encryption, - "no_encryption_sharp": Icons.no_encryption_sharp, - "no_encryption_rounded": Icons.no_encryption_rounded, - "no_encryption_outlined": Icons.no_encryption_outlined, - "no_encryption_gmailerrorred": Icons.no_encryption_gmailerrorred, - "no_encryption_gmailerrorred_sharp": Icons.no_encryption_gmailerrorred_sharp, - "no_encryption_gmailerrorred_rounded": - Icons.no_encryption_gmailerrorred_rounded, - "no_encryption_gmailerrorred_outlined": - Icons.no_encryption_gmailerrorred_outlined, - "no_flash": Icons.no_flash, - "no_flash_sharp": Icons.no_flash_sharp, - "no_flash_rounded": Icons.no_flash_rounded, - "no_flash_outlined": Icons.no_flash_outlined, - "no_food": Icons.no_food, - "no_food_sharp": Icons.no_food_sharp, - "no_food_rounded": Icons.no_food_rounded, - "no_food_outlined": Icons.no_food_outlined, - "no_luggage": Icons.no_luggage, - "no_luggage_sharp": Icons.no_luggage_sharp, - "no_luggage_rounded": Icons.no_luggage_rounded, - "no_luggage_outlined": Icons.no_luggage_outlined, - "no_meals": Icons.no_meals, - "no_meals_sharp": Icons.no_meals_sharp, - "no_meals_rounded": Icons.no_meals_rounded, - "no_meals_outlined": Icons.no_meals_outlined, - "no_meals_ouline": Icons.no_meals_ouline, - "no_meeting_room": Icons.no_meeting_room, - "no_meeting_room_sharp": Icons.no_meeting_room_sharp, - "no_meeting_room_rounded": Icons.no_meeting_room_rounded, - "no_meeting_room_outlined": Icons.no_meeting_room_outlined, - "no_photography": Icons.no_photography, - "no_photography_sharp": Icons.no_photography_sharp, - "no_photography_rounded": Icons.no_photography_rounded, - "no_photography_outlined": Icons.no_photography_outlined, - "no_sim": Icons.no_sim, - "no_sim_sharp": Icons.no_sim_sharp, - "no_sim_rounded": Icons.no_sim_rounded, - "no_sim_outlined": Icons.no_sim_outlined, - "no_stroller": Icons.no_stroller, - "no_stroller_sharp": Icons.no_stroller_sharp, - "no_stroller_rounded": Icons.no_stroller_rounded, - "no_stroller_outlined": Icons.no_stroller_outlined, - "no_transfer": Icons.no_transfer, - "no_transfer_sharp": Icons.no_transfer_sharp, - "no_transfer_rounded": Icons.no_transfer_rounded, - "no_transfer_outlined": Icons.no_transfer_outlined, - "noise_aware": Icons.noise_aware, - "noise_aware_sharp": Icons.noise_aware_sharp, - "noise_aware_rounded": Icons.noise_aware_rounded, - "noise_aware_outlined": Icons.noise_aware_outlined, - "noise_control_off": Icons.noise_control_off, - "noise_control_off_sharp": Icons.noise_control_off_sharp, - "noise_control_off_rounded": Icons.noise_control_off_rounded, - "noise_control_off_outlined": Icons.noise_control_off_outlined, - "nordic_walking": Icons.nordic_walking, - "nordic_walking_sharp": Icons.nordic_walking_sharp, - "nordic_walking_rounded": Icons.nordic_walking_rounded, - "nordic_walking_outlined": Icons.nordic_walking_outlined, - "north": Icons.north, - "north_sharp": Icons.north_sharp, - "north_rounded": Icons.north_rounded, - "north_outlined": Icons.north_outlined, - "north_east": Icons.north_east, - "north_east_sharp": Icons.north_east_sharp, - "north_east_rounded": Icons.north_east_rounded, - "north_east_outlined": Icons.north_east_outlined, - "north_west": Icons.north_west, - "north_west_sharp": Icons.north_west_sharp, - "north_west_rounded": Icons.north_west_rounded, - "north_west_outlined": Icons.north_west_outlined, - "not_accessible": Icons.not_accessible, - "not_accessible_sharp": Icons.not_accessible_sharp, - "not_accessible_rounded": Icons.not_accessible_rounded, - "not_accessible_outlined": Icons.not_accessible_outlined, - "not_interested": Icons.not_interested, - "not_interested_sharp": Icons.not_interested_sharp, - "not_interested_rounded": Icons.not_interested_rounded, - "not_interested_outlined": Icons.not_interested_outlined, - "not_listed_location": Icons.not_listed_location, - "not_listed_location_sharp": Icons.not_listed_location_sharp, - "not_listed_location_rounded": Icons.not_listed_location_rounded, - "not_listed_location_outlined": Icons.not_listed_location_outlined, - "not_started": Icons.not_started, - "not_started_sharp": Icons.not_started_sharp, - "not_started_rounded": Icons.not_started_rounded, - "not_started_outlined": Icons.not_started_outlined, - "note": Icons.note, - "note_sharp": Icons.note_sharp, - "note_rounded": Icons.note_rounded, - "note_outlined": Icons.note_outlined, - "note_add": Icons.note_add, - "note_add_sharp": Icons.note_add_sharp, - "note_add_rounded": Icons.note_add_rounded, - "note_add_outlined": Icons.note_add_outlined, - "note_alt": Icons.note_alt, - "note_alt_sharp": Icons.note_alt_sharp, - "note_alt_rounded": Icons.note_alt_rounded, - "note_alt_outlined": Icons.note_alt_outlined, - "notes": Icons.notes, - "notes_sharp": Icons.notes_sharp, - "notes_rounded": Icons.notes_rounded, - "notes_outlined": Icons.notes_outlined, - "notification_add": Icons.notification_add, - "notification_add_sharp": Icons.notification_add_sharp, - "notification_add_rounded": Icons.notification_add_rounded, - "notification_add_outlined": Icons.notification_add_outlined, - "notification_important": Icons.notification_important, - "notification_important_sharp": Icons.notification_important_sharp, - "notification_important_rounded": Icons.notification_important_rounded, - "notification_important_outlined": Icons.notification_important_outlined, - "notifications": Icons.notifications, - "notifications_sharp": Icons.notifications_sharp, - "notifications_rounded": Icons.notifications_rounded, - "notifications_outlined": Icons.notifications_outlined, - "notifications_active": Icons.notifications_active, - "notifications_active_sharp": Icons.notifications_active_sharp, - "notifications_active_rounded": Icons.notifications_active_rounded, - "notifications_active_outlined": Icons.notifications_active_outlined, - "notifications_none": Icons.notifications_none, - "notifications_none_sharp": Icons.notifications_none_sharp, - "notifications_none_rounded": Icons.notifications_none_rounded, - "notifications_none_outlined": Icons.notifications_none_outlined, - "notifications_off": Icons.notifications_off, - "notifications_off_sharp": Icons.notifications_off_sharp, - "notifications_off_rounded": Icons.notifications_off_rounded, - "notifications_off_outlined": Icons.notifications_off_outlined, - "notifications_on": Icons.notifications_on, - "notifications_on_sharp": Icons.notifications_on_sharp, - "notifications_on_rounded": Icons.notifications_on_rounded, - "notifications_on_outlined": Icons.notifications_on_outlined, - "notifications_paused": Icons.notifications_paused, - "notifications_paused_sharp": Icons.notifications_paused_sharp, - "notifications_paused_rounded": Icons.notifications_paused_rounded, - "notifications_paused_outlined": Icons.notifications_paused_outlined, - "now_wallpaper": Icons.now_wallpaper, - "now_wallpaper_sharp": Icons.now_wallpaper_sharp, - "now_wallpaper_rounded": Icons.now_wallpaper_rounded, - "now_wallpaper_outlined": Icons.now_wallpaper_outlined, - "now_widgets": Icons.now_widgets, - "now_widgets_sharp": Icons.now_widgets_sharp, - "now_widgets_rounded": Icons.now_widgets_rounded, - "now_widgets_outlined": Icons.now_widgets_outlined, - "numbers": Icons.numbers, - "numbers_sharp": Icons.numbers_sharp, - "numbers_rounded": Icons.numbers_rounded, - "numbers_outlined": Icons.numbers_outlined, - "offline_bolt": Icons.offline_bolt, - "offline_bolt_sharp": Icons.offline_bolt_sharp, - "offline_bolt_rounded": Icons.offline_bolt_rounded, - "offline_bolt_outlined": Icons.offline_bolt_outlined, - "offline_pin": Icons.offline_pin, - "offline_pin_sharp": Icons.offline_pin_sharp, - "offline_pin_rounded": Icons.offline_pin_rounded, - "offline_pin_outlined": Icons.offline_pin_outlined, - "offline_share": Icons.offline_share, - "offline_share_sharp": Icons.offline_share_sharp, - "offline_share_rounded": Icons.offline_share_rounded, - "offline_share_outlined": Icons.offline_share_outlined, - "oil_barrel": Icons.oil_barrel, - "oil_barrel_sharp": Icons.oil_barrel_sharp, - "oil_barrel_rounded": Icons.oil_barrel_rounded, - "oil_barrel_outlined": Icons.oil_barrel_outlined, - "on_device_training": Icons.on_device_training, - "on_device_training_sharp": Icons.on_device_training_sharp, - "on_device_training_rounded": Icons.on_device_training_rounded, - "on_device_training_outlined": Icons.on_device_training_outlined, - "ondemand_video": Icons.ondemand_video, - "ondemand_video_sharp": Icons.ondemand_video_sharp, - "ondemand_video_rounded": Icons.ondemand_video_rounded, - "ondemand_video_outlined": Icons.ondemand_video_outlined, - "online_prediction": Icons.online_prediction, - "online_prediction_sharp": Icons.online_prediction_sharp, - "online_prediction_rounded": Icons.online_prediction_rounded, - "online_prediction_outlined": Icons.online_prediction_outlined, - "opacity": Icons.opacity, - "opacity_sharp": Icons.opacity_sharp, - "opacity_rounded": Icons.opacity_rounded, - "opacity_outlined": Icons.opacity_outlined, - "open_in_browser": Icons.open_in_browser, - "open_in_browser_sharp": Icons.open_in_browser_sharp, - "open_in_browser_rounded": Icons.open_in_browser_rounded, - "open_in_browser_outlined": Icons.open_in_browser_outlined, - "open_in_full": Icons.open_in_full, - "open_in_full_sharp": Icons.open_in_full_sharp, - "open_in_full_rounded": Icons.open_in_full_rounded, - "open_in_full_outlined": Icons.open_in_full_outlined, - "open_in_new": Icons.open_in_new, - "open_in_new_sharp": Icons.open_in_new_sharp, - "open_in_new_rounded": Icons.open_in_new_rounded, - "open_in_new_outlined": Icons.open_in_new_outlined, - "open_in_new_off": Icons.open_in_new_off, - "open_in_new_off_sharp": Icons.open_in_new_off_sharp, - "open_in_new_off_rounded": Icons.open_in_new_off_rounded, - "open_in_new_off_outlined": Icons.open_in_new_off_outlined, - "open_with": Icons.open_with, - "open_with_sharp": Icons.open_with_sharp, - "open_with_rounded": Icons.open_with_rounded, - "open_with_outlined": Icons.open_with_outlined, - "other_houses": Icons.other_houses, - "other_houses_sharp": Icons.other_houses_sharp, - "other_houses_rounded": Icons.other_houses_rounded, - "other_houses_outlined": Icons.other_houses_outlined, - "outbond": Icons.outbond, - "outbond_sharp": Icons.outbond_sharp, - "outbond_rounded": Icons.outbond_rounded, - "outbond_outlined": Icons.outbond_outlined, - "outbound": Icons.outbound, - "outbound_sharp": Icons.outbound_sharp, - "outbound_rounded": Icons.outbound_rounded, - "outbound_outlined": Icons.outbound_outlined, - "outbox": Icons.outbox, - "outbox_sharp": Icons.outbox_sharp, - "outbox_rounded": Icons.outbox_rounded, - "outbox_outlined": Icons.outbox_outlined, - "outdoor_grill": Icons.outdoor_grill, - "outdoor_grill_sharp": Icons.outdoor_grill_sharp, - "outdoor_grill_rounded": Icons.outdoor_grill_rounded, - "outdoor_grill_outlined": Icons.outdoor_grill_outlined, - "outgoing_mail": Icons.outgoing_mail, - "outlet": Icons.outlet, - "outlet_sharp": Icons.outlet_sharp, - "outlet_rounded": Icons.outlet_rounded, - "outlet_outlined": Icons.outlet_outlined, - "outlined_flag": Icons.outlined_flag, - "outlined_flag_sharp": Icons.outlined_flag_sharp, - "outlined_flag_rounded": Icons.outlined_flag_rounded, - "outlined_flag_outlined": Icons.outlined_flag_outlined, - "output": Icons.output, - "output_sharp": Icons.output_sharp, - "output_rounded": Icons.output_rounded, - "output_outlined": Icons.output_outlined, - "padding": Icons.padding, - "padding_sharp": Icons.padding_sharp, - "padding_rounded": Icons.padding_rounded, - "padding_outlined": Icons.padding_outlined, - "pages": Icons.pages, - "pages_sharp": Icons.pages_sharp, - "pages_rounded": Icons.pages_rounded, - "pages_outlined": Icons.pages_outlined, - "pageview": Icons.pageview, - "pageview_sharp": Icons.pageview_sharp, - "pageview_rounded": Icons.pageview_rounded, - "pageview_outlined": Icons.pageview_outlined, - "paid": Icons.paid, - "paid_sharp": Icons.paid_sharp, - "paid_rounded": Icons.paid_rounded, - "paid_outlined": Icons.paid_outlined, - "palette": Icons.palette, - "palette_sharp": Icons.palette_sharp, - "palette_rounded": Icons.palette_rounded, - "palette_outlined": Icons.palette_outlined, - "pallet": Icons.pallet, - "pan_tool": Icons.pan_tool, - "pan_tool_sharp": Icons.pan_tool_sharp, - "pan_tool_rounded": Icons.pan_tool_rounded, - "pan_tool_outlined": Icons.pan_tool_outlined, - "pan_tool_alt": Icons.pan_tool_alt, - "pan_tool_alt_sharp": Icons.pan_tool_alt_sharp, - "pan_tool_alt_rounded": Icons.pan_tool_alt_rounded, - "pan_tool_alt_outlined": Icons.pan_tool_alt_outlined, - "panorama": Icons.panorama, - "panorama_sharp": Icons.panorama_sharp, - "panorama_rounded": Icons.panorama_rounded, - "panorama_outlined": Icons.panorama_outlined, - "panorama_fish_eye": Icons.panorama_fish_eye, - "panorama_fish_eye_sharp": Icons.panorama_fish_eye_sharp, - "panorama_fish_eye_rounded": Icons.panorama_fish_eye_rounded, - "panorama_fish_eye_outlined": Icons.panorama_fish_eye_outlined, - "panorama_fisheye": Icons.panorama_fisheye, - "panorama_fisheye_sharp": Icons.panorama_fisheye_sharp, - "panorama_fisheye_rounded": Icons.panorama_fisheye_rounded, - "panorama_fisheye_outlined": Icons.panorama_fisheye_outlined, - "panorama_horizontal": Icons.panorama_horizontal, - "panorama_horizontal_sharp": Icons.panorama_horizontal_sharp, - "panorama_horizontal_rounded": Icons.panorama_horizontal_rounded, - "panorama_horizontal_outlined": Icons.panorama_horizontal_outlined, - "panorama_horizontal_select": Icons.panorama_horizontal_select, - "panorama_horizontal_select_sharp": Icons.panorama_horizontal_select_sharp, - "panorama_horizontal_select_rounded": - Icons.panorama_horizontal_select_rounded, - "panorama_horizontal_select_outlined": - Icons.panorama_horizontal_select_outlined, - "panorama_photosphere": Icons.panorama_photosphere, - "panorama_photosphere_sharp": Icons.panorama_photosphere_sharp, - "panorama_photosphere_rounded": Icons.panorama_photosphere_rounded, - "panorama_photosphere_outlined": Icons.panorama_photosphere_outlined, - "panorama_photosphere_select": Icons.panorama_photosphere_select, - "panorama_photosphere_select_sharp": Icons.panorama_photosphere_select_sharp, - "panorama_photosphere_select_rounded": - Icons.panorama_photosphere_select_rounded, - "panorama_photosphere_select_outlined": - Icons.panorama_photosphere_select_outlined, - "panorama_vertical": Icons.panorama_vertical, - "panorama_vertical_sharp": Icons.panorama_vertical_sharp, - "panorama_vertical_rounded": Icons.panorama_vertical_rounded, - "panorama_vertical_outlined": Icons.panorama_vertical_outlined, - "panorama_vertical_select": Icons.panorama_vertical_select, - "panorama_vertical_select_sharp": Icons.panorama_vertical_select_sharp, - "panorama_vertical_select_rounded": Icons.panorama_vertical_select_rounded, - "panorama_vertical_select_outlined": Icons.panorama_vertical_select_outlined, - "panorama_wide_angle": Icons.panorama_wide_angle, - "panorama_wide_angle_sharp": Icons.panorama_wide_angle_sharp, - "panorama_wide_angle_rounded": Icons.panorama_wide_angle_rounded, - "panorama_wide_angle_outlined": Icons.panorama_wide_angle_outlined, - "panorama_wide_angle_select": Icons.panorama_wide_angle_select, - "panorama_wide_angle_select_sharp": Icons.panorama_wide_angle_select_sharp, - "panorama_wide_angle_select_rounded": - Icons.panorama_wide_angle_select_rounded, - "panorama_wide_angle_select_outlined": - Icons.panorama_wide_angle_select_outlined, - "paragliding": Icons.paragliding, - "paragliding_sharp": Icons.paragliding_sharp, - "paragliding_rounded": Icons.paragliding_rounded, - "paragliding_outlined": Icons.paragliding_outlined, - "park": Icons.park, - "park_sharp": Icons.park_sharp, - "park_rounded": Icons.park_rounded, - "park_outlined": Icons.park_outlined, - "party_mode": Icons.party_mode, - "party_mode_sharp": Icons.party_mode_sharp, - "party_mode_rounded": Icons.party_mode_rounded, - "party_mode_outlined": Icons.party_mode_outlined, - "password": Icons.password, - "password_sharp": Icons.password_sharp, - "password_rounded": Icons.password_rounded, - "password_outlined": Icons.password_outlined, - "paste": Icons.paste, - "paste_sharp": Icons.paste_sharp, - "paste_rounded": Icons.paste_rounded, - "paste_outlined": Icons.paste_outlined, - "pattern": Icons.pattern, - "pattern_sharp": Icons.pattern_sharp, - "pattern_rounded": Icons.pattern_rounded, - "pattern_outlined": Icons.pattern_outlined, - "pause": Icons.pause, - "pause_sharp": Icons.pause_sharp, - "pause_rounded": Icons.pause_rounded, - "pause_outlined": Icons.pause_outlined, - "pause_circle": Icons.pause_circle, - "pause_circle_sharp": Icons.pause_circle_sharp, - "pause_circle_rounded": Icons.pause_circle_rounded, - "pause_circle_outlined": Icons.pause_circle_outlined, - "pause_circle_filled": Icons.pause_circle_filled, - "pause_circle_filled_sharp": Icons.pause_circle_filled_sharp, - "pause_circle_filled_rounded": Icons.pause_circle_filled_rounded, - "pause_circle_filled_outlined": Icons.pause_circle_filled_outlined, - "pause_circle_outline": Icons.pause_circle_outline, - "pause_circle_outline_sharp": Icons.pause_circle_outline_sharp, - "pause_circle_outline_rounded": Icons.pause_circle_outline_rounded, - "pause_circle_outline_outlined": Icons.pause_circle_outline_outlined, - "pause_presentation": Icons.pause_presentation, - "pause_presentation_sharp": Icons.pause_presentation_sharp, - "pause_presentation_rounded": Icons.pause_presentation_rounded, - "pause_presentation_outlined": Icons.pause_presentation_outlined, - "payment": Icons.payment, - "payment_sharp": Icons.payment_sharp, - "payment_rounded": Icons.payment_rounded, - "payment_outlined": Icons.payment_outlined, - "payments": Icons.payments, - "payments_sharp": Icons.payments_sharp, - "payments_rounded": Icons.payments_rounded, - "payments_outlined": Icons.payments_outlined, - "paypal": Icons.paypal, - "paypal_sharp": Icons.paypal_sharp, - "paypal_rounded": Icons.paypal_rounded, - "paypal_outlined": Icons.paypal_outlined, - "pedal_bike": Icons.pedal_bike, - "pedal_bike_sharp": Icons.pedal_bike_sharp, - "pedal_bike_rounded": Icons.pedal_bike_rounded, - "pedal_bike_outlined": Icons.pedal_bike_outlined, - "pending": Icons.pending, - "pending_sharp": Icons.pending_sharp, - "pending_rounded": Icons.pending_rounded, - "pending_outlined": Icons.pending_outlined, - "pending_actions": Icons.pending_actions, - "pending_actions_sharp": Icons.pending_actions_sharp, - "pending_actions_rounded": Icons.pending_actions_rounded, - "pending_actions_outlined": Icons.pending_actions_outlined, - "pentagon": Icons.pentagon, - "pentagon_sharp": Icons.pentagon_sharp, - "pentagon_rounded": Icons.pentagon_rounded, - "pentagon_outlined": Icons.pentagon_outlined, - "people": Icons.people, - "people_sharp": Icons.people_sharp, - "people_rounded": Icons.people_rounded, - "people_outlined": Icons.people_outlined, - "people_alt": Icons.people_alt, - "people_alt_sharp": Icons.people_alt_sharp, - "people_alt_rounded": Icons.people_alt_rounded, - "people_alt_outlined": Icons.people_alt_outlined, - "people_outline": Icons.people_outline, - "people_outline_sharp": Icons.people_outline_sharp, - "people_outline_rounded": Icons.people_outline_rounded, - "people_outline_outlined": Icons.people_outline_outlined, - "percent": Icons.percent, - "percent_sharp": Icons.percent_sharp, - "percent_rounded": Icons.percent_rounded, - "percent_outlined": Icons.percent_outlined, - "perm_camera_mic": Icons.perm_camera_mic, - "perm_camera_mic_sharp": Icons.perm_camera_mic_sharp, - "perm_camera_mic_rounded": Icons.perm_camera_mic_rounded, - "perm_camera_mic_outlined": Icons.perm_camera_mic_outlined, - "perm_contact_cal": Icons.perm_contact_cal, - "perm_contact_cal_sharp": Icons.perm_contact_cal_sharp, - "perm_contact_cal_rounded": Icons.perm_contact_cal_rounded, - "perm_contact_cal_outlined": Icons.perm_contact_cal_outlined, - "perm_contact_calendar": Icons.perm_contact_calendar, - "perm_contact_calendar_sharp": Icons.perm_contact_calendar_sharp, - "perm_contact_calendar_rounded": Icons.perm_contact_calendar_rounded, - "perm_contact_calendar_outlined": Icons.perm_contact_calendar_outlined, - "perm_data_setting": Icons.perm_data_setting, - "perm_data_setting_sharp": Icons.perm_data_setting_sharp, - "perm_data_setting_rounded": Icons.perm_data_setting_rounded, - "perm_data_setting_outlined": Icons.perm_data_setting_outlined, - "perm_device_info": Icons.perm_device_info, - "perm_device_info_sharp": Icons.perm_device_info_sharp, - "perm_device_info_rounded": Icons.perm_device_info_rounded, - "perm_device_info_outlined": Icons.perm_device_info_outlined, - "perm_device_information": Icons.perm_device_information, - "perm_device_information_sharp": Icons.perm_device_information_sharp, - "perm_device_information_rounded": Icons.perm_device_information_rounded, - "perm_device_information_outlined": Icons.perm_device_information_outlined, - "perm_identity": Icons.perm_identity, - "perm_identity_sharp": Icons.perm_identity_sharp, - "perm_identity_rounded": Icons.perm_identity_rounded, - "perm_identity_outlined": Icons.perm_identity_outlined, - "perm_media": Icons.perm_media, - "perm_media_sharp": Icons.perm_media_sharp, - "perm_media_rounded": Icons.perm_media_rounded, - "perm_media_outlined": Icons.perm_media_outlined, - "perm_phone_msg": Icons.perm_phone_msg, - "perm_phone_msg_sharp": Icons.perm_phone_msg_sharp, - "perm_phone_msg_rounded": Icons.perm_phone_msg_rounded, - "perm_phone_msg_outlined": Icons.perm_phone_msg_outlined, - "perm_scan_wifi": Icons.perm_scan_wifi, - "perm_scan_wifi_sharp": Icons.perm_scan_wifi_sharp, - "perm_scan_wifi_rounded": Icons.perm_scan_wifi_rounded, - "perm_scan_wifi_outlined": Icons.perm_scan_wifi_outlined, - "person": Icons.person, - "person_sharp": Icons.person_sharp, - "person_rounded": Icons.person_rounded, - "person_outlined": Icons.person_outlined, - "person_2": Icons.person_2, - "person_2_sharp": Icons.person_2_sharp, - "person_2_rounded": Icons.person_2_rounded, - "person_2_outlined": Icons.person_2_outlined, - "person_3": Icons.person_3, - "person_3_sharp": Icons.person_3_sharp, - "person_3_rounded": Icons.person_3_rounded, - "person_3_outlined": Icons.person_3_outlined, - "person_4": Icons.person_4, - "person_4_sharp": Icons.person_4_sharp, - "person_4_rounded": Icons.person_4_rounded, - "person_4_outlined": Icons.person_4_outlined, - "person_add": Icons.person_add, - "person_add_sharp": Icons.person_add_sharp, - "person_add_rounded": Icons.person_add_rounded, - "person_add_outlined": Icons.person_add_outlined, - "person_add_alt": Icons.person_add_alt, - "person_add_alt_sharp": Icons.person_add_alt_sharp, - "person_add_alt_rounded": Icons.person_add_alt_rounded, - "person_add_alt_outlined": Icons.person_add_alt_outlined, - "person_add_alt_1": Icons.person_add_alt_1, - "person_add_alt_1_sharp": Icons.person_add_alt_1_sharp, - "person_add_alt_1_rounded": Icons.person_add_alt_1_rounded, - "person_add_alt_1_outlined": Icons.person_add_alt_1_outlined, - "person_add_disabled": Icons.person_add_disabled, - "person_add_disabled_sharp": Icons.person_add_disabled_sharp, - "person_add_disabled_rounded": Icons.person_add_disabled_rounded, - "person_add_disabled_outlined": Icons.person_add_disabled_outlined, - "person_off": Icons.person_off, - "person_off_sharp": Icons.person_off_sharp, - "person_off_rounded": Icons.person_off_rounded, - "person_off_outlined": Icons.person_off_outlined, - "person_outline": Icons.person_outline, - "person_outline_sharp": Icons.person_outline_sharp, - "person_outline_rounded": Icons.person_outline_rounded, - "person_outline_outlined": Icons.person_outline_outlined, - "person_pin": Icons.person_pin, - "person_pin_sharp": Icons.person_pin_sharp, - "person_pin_rounded": Icons.person_pin_rounded, - "person_pin_outlined": Icons.person_pin_outlined, - "person_pin_circle": Icons.person_pin_circle, - "person_pin_circle_sharp": Icons.person_pin_circle_sharp, - "person_pin_circle_rounded": Icons.person_pin_circle_rounded, - "person_pin_circle_outlined": Icons.person_pin_circle_outlined, - "person_remove": Icons.person_remove, - "person_remove_sharp": Icons.person_remove_sharp, - "person_remove_rounded": Icons.person_remove_rounded, - "person_remove_outlined": Icons.person_remove_outlined, - "person_remove_alt_1": Icons.person_remove_alt_1, - "person_remove_alt_1_sharp": Icons.person_remove_alt_1_sharp, - "person_remove_alt_1_rounded": Icons.person_remove_alt_1_rounded, - "person_remove_alt_1_outlined": Icons.person_remove_alt_1_outlined, - "person_search": Icons.person_search, - "person_search_sharp": Icons.person_search_sharp, - "person_search_rounded": Icons.person_search_rounded, - "person_search_outlined": Icons.person_search_outlined, - "personal_injury": Icons.personal_injury, - "personal_injury_sharp": Icons.personal_injury_sharp, - "personal_injury_rounded": Icons.personal_injury_rounded, - "personal_injury_outlined": Icons.personal_injury_outlined, - "personal_video": Icons.personal_video, - "personal_video_sharp": Icons.personal_video_sharp, - "personal_video_rounded": Icons.personal_video_rounded, - "personal_video_outlined": Icons.personal_video_outlined, - "pest_control": Icons.pest_control, - "pest_control_sharp": Icons.pest_control_sharp, - "pest_control_rounded": Icons.pest_control_rounded, - "pest_control_outlined": Icons.pest_control_outlined, - "pest_control_rodent": Icons.pest_control_rodent, - "pest_control_rodent_sharp": Icons.pest_control_rodent_sharp, - "pest_control_rodent_rounded": Icons.pest_control_rodent_rounded, - "pest_control_rodent_outlined": Icons.pest_control_rodent_outlined, - "pets": Icons.pets, - "pets_sharp": Icons.pets_sharp, - "pets_rounded": Icons.pets_rounded, - "pets_outlined": Icons.pets_outlined, - "phishing": Icons.phishing, - "phishing_sharp": Icons.phishing_sharp, - "phishing_rounded": Icons.phishing_rounded, - "phishing_outlined": Icons.phishing_outlined, - "phone": Icons.phone, - "phone_sharp": Icons.phone_sharp, - "phone_rounded": Icons.phone_rounded, - "phone_outlined": Icons.phone_outlined, - "phone_android": Icons.phone_android, - "phone_android_sharp": Icons.phone_android_sharp, - "phone_android_rounded": Icons.phone_android_rounded, - "phone_android_outlined": Icons.phone_android_outlined, - "phone_bluetooth_speaker": Icons.phone_bluetooth_speaker, - "phone_bluetooth_speaker_sharp": Icons.phone_bluetooth_speaker_sharp, - "phone_bluetooth_speaker_rounded": Icons.phone_bluetooth_speaker_rounded, - "phone_bluetooth_speaker_outlined": Icons.phone_bluetooth_speaker_outlined, - "phone_callback": Icons.phone_callback, - "phone_callback_sharp": Icons.phone_callback_sharp, - "phone_callback_rounded": Icons.phone_callback_rounded, - "phone_callback_outlined": Icons.phone_callback_outlined, - "phone_disabled": Icons.phone_disabled, - "phone_disabled_sharp": Icons.phone_disabled_sharp, - "phone_disabled_rounded": Icons.phone_disabled_rounded, - "phone_disabled_outlined": Icons.phone_disabled_outlined, - "phone_enabled": Icons.phone_enabled, - "phone_enabled_sharp": Icons.phone_enabled_sharp, - "phone_enabled_rounded": Icons.phone_enabled_rounded, - "phone_enabled_outlined": Icons.phone_enabled_outlined, - "phone_forwarded": Icons.phone_forwarded, - "phone_forwarded_sharp": Icons.phone_forwarded_sharp, - "phone_forwarded_rounded": Icons.phone_forwarded_rounded, - "phone_forwarded_outlined": Icons.phone_forwarded_outlined, - "phone_in_talk": Icons.phone_in_talk, - "phone_in_talk_sharp": Icons.phone_in_talk_sharp, - "phone_in_talk_rounded": Icons.phone_in_talk_rounded, - "phone_in_talk_outlined": Icons.phone_in_talk_outlined, - "phone_iphone": Icons.phone_iphone, - "phone_iphone_sharp": Icons.phone_iphone_sharp, - "phone_iphone_rounded": Icons.phone_iphone_rounded, - "phone_iphone_outlined": Icons.phone_iphone_outlined, - "phone_locked": Icons.phone_locked, - "phone_locked_sharp": Icons.phone_locked_sharp, - "phone_locked_rounded": Icons.phone_locked_rounded, - "phone_locked_outlined": Icons.phone_locked_outlined, - "phone_missed": Icons.phone_missed, - "phone_missed_sharp": Icons.phone_missed_sharp, - "phone_missed_rounded": Icons.phone_missed_rounded, - "phone_missed_outlined": Icons.phone_missed_outlined, - "phone_paused": Icons.phone_paused, - "phone_paused_sharp": Icons.phone_paused_sharp, - "phone_paused_rounded": Icons.phone_paused_rounded, - "phone_paused_outlined": Icons.phone_paused_outlined, - "phonelink": Icons.phonelink, - "phonelink_sharp": Icons.phonelink_sharp, - "phonelink_rounded": Icons.phonelink_rounded, - "phonelink_outlined": Icons.phonelink_outlined, - "phonelink_erase": Icons.phonelink_erase, - "phonelink_erase_sharp": Icons.phonelink_erase_sharp, - "phonelink_erase_rounded": Icons.phonelink_erase_rounded, - "phonelink_erase_outlined": Icons.phonelink_erase_outlined, - "phonelink_lock": Icons.phonelink_lock, - "phonelink_lock_sharp": Icons.phonelink_lock_sharp, - "phonelink_lock_rounded": Icons.phonelink_lock_rounded, - "phonelink_lock_outlined": Icons.phonelink_lock_outlined, - "phonelink_off": Icons.phonelink_off, - "phonelink_off_sharp": Icons.phonelink_off_sharp, - "phonelink_off_rounded": Icons.phonelink_off_rounded, - "phonelink_off_outlined": Icons.phonelink_off_outlined, - "phonelink_ring": Icons.phonelink_ring, - "phonelink_ring_sharp": Icons.phonelink_ring_sharp, - "phonelink_ring_rounded": Icons.phonelink_ring_rounded, - "phonelink_ring_outlined": Icons.phonelink_ring_outlined, - "phonelink_setup": Icons.phonelink_setup, - "phonelink_setup_sharp": Icons.phonelink_setup_sharp, - "phonelink_setup_rounded": Icons.phonelink_setup_rounded, - "phonelink_setup_outlined": Icons.phonelink_setup_outlined, - "photo": Icons.photo, - "photo_sharp": Icons.photo_sharp, - "photo_rounded": Icons.photo_rounded, - "photo_outlined": Icons.photo_outlined, - "photo_album": Icons.photo_album, - "photo_album_sharp": Icons.photo_album_sharp, - "photo_album_rounded": Icons.photo_album_rounded, - "photo_album_outlined": Icons.photo_album_outlined, - "photo_camera": Icons.photo_camera, - "photo_camera_sharp": Icons.photo_camera_sharp, - "photo_camera_rounded": Icons.photo_camera_rounded, - "photo_camera_outlined": Icons.photo_camera_outlined, - "photo_camera_back": Icons.photo_camera_back, - "photo_camera_back_sharp": Icons.photo_camera_back_sharp, - "photo_camera_back_rounded": Icons.photo_camera_back_rounded, - "photo_camera_back_outlined": Icons.photo_camera_back_outlined, - "photo_camera_front": Icons.photo_camera_front, - "photo_camera_front_sharp": Icons.photo_camera_front_sharp, - "photo_camera_front_rounded": Icons.photo_camera_front_rounded, - "photo_camera_front_outlined": Icons.photo_camera_front_outlined, - "photo_filter": Icons.photo_filter, - "photo_filter_sharp": Icons.photo_filter_sharp, - "photo_filter_rounded": Icons.photo_filter_rounded, - "photo_filter_outlined": Icons.photo_filter_outlined, - "photo_library": Icons.photo_library, - "photo_library_sharp": Icons.photo_library_sharp, - "photo_library_rounded": Icons.photo_library_rounded, - "photo_library_outlined": Icons.photo_library_outlined, - "photo_size_select_actual": Icons.photo_size_select_actual, - "photo_size_select_actual_sharp": Icons.photo_size_select_actual_sharp, - "photo_size_select_actual_rounded": Icons.photo_size_select_actual_rounded, - "photo_size_select_actual_outlined": Icons.photo_size_select_actual_outlined, - "photo_size_select_large": Icons.photo_size_select_large, - "photo_size_select_large_sharp": Icons.photo_size_select_large_sharp, - "photo_size_select_large_rounded": Icons.photo_size_select_large_rounded, - "photo_size_select_large_outlined": Icons.photo_size_select_large_outlined, - "photo_size_select_small": Icons.photo_size_select_small, - "photo_size_select_small_sharp": Icons.photo_size_select_small_sharp, - "photo_size_select_small_rounded": Icons.photo_size_select_small_rounded, - "photo_size_select_small_outlined": Icons.photo_size_select_small_outlined, - "php": Icons.php, - "php_sharp": Icons.php_sharp, - "php_rounded": Icons.php_rounded, - "php_outlined": Icons.php_outlined, - "piano": Icons.piano, - "piano_sharp": Icons.piano_sharp, - "piano_rounded": Icons.piano_rounded, - "piano_outlined": Icons.piano_outlined, - "piano_off": Icons.piano_off, - "piano_off_sharp": Icons.piano_off_sharp, - "piano_off_rounded": Icons.piano_off_rounded, - "piano_off_outlined": Icons.piano_off_outlined, - "picture_as_pdf": Icons.picture_as_pdf, - "picture_as_pdf_sharp": Icons.picture_as_pdf_sharp, - "picture_as_pdf_rounded": Icons.picture_as_pdf_rounded, - "picture_as_pdf_outlined": Icons.picture_as_pdf_outlined, - "picture_in_picture": Icons.picture_in_picture, - "picture_in_picture_sharp": Icons.picture_in_picture_sharp, - "picture_in_picture_rounded": Icons.picture_in_picture_rounded, - "picture_in_picture_outlined": Icons.picture_in_picture_outlined, - "picture_in_picture_alt": Icons.picture_in_picture_alt, - "picture_in_picture_alt_sharp": Icons.picture_in_picture_alt_sharp, - "picture_in_picture_alt_rounded": Icons.picture_in_picture_alt_rounded, - "picture_in_picture_alt_outlined": Icons.picture_in_picture_alt_outlined, - "pie_chart": Icons.pie_chart, - "pie_chart_sharp": Icons.pie_chart_sharp, - "pie_chart_rounded": Icons.pie_chart_rounded, - "pie_chart_outline": Icons.pie_chart_outline, - "pie_chart_outline_sharp": Icons.pie_chart_outline_sharp, - "pie_chart_outline_rounded": Icons.pie_chart_outline_rounded, - "pie_chart_outline_outlined": Icons.pie_chart_outline_outlined, - "pin": Icons.pin, - "pin_sharp": Icons.pin_sharp, - "pin_rounded": Icons.pin_rounded, - "pin_outlined": Icons.pin_outlined, - "pin_drop": Icons.pin_drop, - "pin_drop_sharp": Icons.pin_drop_sharp, - "pin_drop_rounded": Icons.pin_drop_rounded, - "pin_drop_outlined": Icons.pin_drop_outlined, - "pin_end": Icons.pin_end, - "pin_end_sharp": Icons.pin_end_sharp, - "pin_end_rounded": Icons.pin_end_rounded, - "pin_end_outlined": Icons.pin_end_outlined, - "pin_invoke": Icons.pin_invoke, - "pin_invoke_sharp": Icons.pin_invoke_sharp, - "pin_invoke_rounded": Icons.pin_invoke_rounded, - "pin_invoke_outlined": Icons.pin_invoke_outlined, - "pinch": Icons.pinch, - "pinch_sharp": Icons.pinch_sharp, - "pinch_rounded": Icons.pinch_rounded, - "pinch_outlined": Icons.pinch_outlined, - "pivot_table_chart": Icons.pivot_table_chart, - "pivot_table_chart_sharp": Icons.pivot_table_chart_sharp, - "pivot_table_chart_rounded": Icons.pivot_table_chart_rounded, - "pivot_table_chart_outlined": Icons.pivot_table_chart_outlined, - "pix": Icons.pix, - "pix_sharp": Icons.pix_sharp, - "pix_rounded": Icons.pix_rounded, - "pix_outlined": Icons.pix_outlined, - "place": Icons.place, - "place_sharp": Icons.place_sharp, - "place_rounded": Icons.place_rounded, - "place_outlined": Icons.place_outlined, - "plagiarism": Icons.plagiarism, - "plagiarism_sharp": Icons.plagiarism_sharp, - "plagiarism_rounded": Icons.plagiarism_rounded, - "plagiarism_outlined": Icons.plagiarism_outlined, - "play_arrow": Icons.play_arrow, - "play_arrow_sharp": Icons.play_arrow_sharp, - "play_arrow_rounded": Icons.play_arrow_rounded, - "play_arrow_outlined": Icons.play_arrow_outlined, - "play_circle": Icons.play_circle, - "play_circle_sharp": Icons.play_circle_sharp, - "play_circle_rounded": Icons.play_circle_rounded, - "play_circle_outlined": Icons.play_circle_outlined, - "play_circle_fill": Icons.play_circle_fill, - "play_circle_fill_sharp": Icons.play_circle_fill_sharp, - "play_circle_fill_rounded": Icons.play_circle_fill_rounded, - "play_circle_fill_outlined": Icons.play_circle_fill_outlined, - "play_circle_filled": Icons.play_circle_filled, - "play_circle_filled_sharp": Icons.play_circle_filled_sharp, - "play_circle_filled_rounded": Icons.play_circle_filled_rounded, - "play_circle_filled_outlined": Icons.play_circle_filled_outlined, - "play_circle_outline": Icons.play_circle_outline, - "play_circle_outline_sharp": Icons.play_circle_outline_sharp, - "play_circle_outline_rounded": Icons.play_circle_outline_rounded, - "play_circle_outline_outlined": Icons.play_circle_outline_outlined, - "play_disabled": Icons.play_disabled, - "play_disabled_sharp": Icons.play_disabled_sharp, - "play_disabled_rounded": Icons.play_disabled_rounded, - "play_disabled_outlined": Icons.play_disabled_outlined, - "play_for_work": Icons.play_for_work, - "play_for_work_sharp": Icons.play_for_work_sharp, - "play_for_work_rounded": Icons.play_for_work_rounded, - "play_for_work_outlined": Icons.play_for_work_outlined, - "play_lesson": Icons.play_lesson, - "play_lesson_sharp": Icons.play_lesson_sharp, - "play_lesson_rounded": Icons.play_lesson_rounded, - "play_lesson_outlined": Icons.play_lesson_outlined, - "playlist_add": Icons.playlist_add, - "playlist_add_sharp": Icons.playlist_add_sharp, - "playlist_add_rounded": Icons.playlist_add_rounded, - "playlist_add_outlined": Icons.playlist_add_outlined, - "playlist_add_check": Icons.playlist_add_check, - "playlist_add_check_sharp": Icons.playlist_add_check_sharp, - "playlist_add_check_rounded": Icons.playlist_add_check_rounded, - "playlist_add_check_outlined": Icons.playlist_add_check_outlined, - "playlist_add_check_circle": Icons.playlist_add_check_circle, - "playlist_add_check_circle_sharp": Icons.playlist_add_check_circle_sharp, - "playlist_add_check_circle_rounded": Icons.playlist_add_check_circle_rounded, - "playlist_add_check_circle_outlined": - Icons.playlist_add_check_circle_outlined, - "playlist_add_circle": Icons.playlist_add_circle, - "playlist_add_circle_sharp": Icons.playlist_add_circle_sharp, - "playlist_add_circle_rounded": Icons.playlist_add_circle_rounded, - "playlist_add_circle_outlined": Icons.playlist_add_circle_outlined, - "playlist_play": Icons.playlist_play, - "playlist_play_sharp": Icons.playlist_play_sharp, - "playlist_play_rounded": Icons.playlist_play_rounded, - "playlist_play_outlined": Icons.playlist_play_outlined, - "playlist_remove": Icons.playlist_remove, - "playlist_remove_sharp": Icons.playlist_remove_sharp, - "playlist_remove_rounded": Icons.playlist_remove_rounded, - "playlist_remove_outlined": Icons.playlist_remove_outlined, - "plumbing": Icons.plumbing, - "plumbing_sharp": Icons.plumbing_sharp, - "plumbing_rounded": Icons.plumbing_rounded, - "plumbing_outlined": Icons.plumbing_outlined, - "plus_one": Icons.plus_one, - "plus_one_sharp": Icons.plus_one_sharp, - "plus_one_rounded": Icons.plus_one_rounded, - "plus_one_outlined": Icons.plus_one_outlined, - "podcasts": Icons.podcasts, - "podcasts_sharp": Icons.podcasts_sharp, - "podcasts_rounded": Icons.podcasts_rounded, - "podcasts_outlined": Icons.podcasts_outlined, - "point_of_sale": Icons.point_of_sale, - "point_of_sale_sharp": Icons.point_of_sale_sharp, - "point_of_sale_rounded": Icons.point_of_sale_rounded, - "point_of_sale_outlined": Icons.point_of_sale_outlined, - "policy": Icons.policy, - "policy_sharp": Icons.policy_sharp, - "policy_rounded": Icons.policy_rounded, - "policy_outlined": Icons.policy_outlined, - "poll": Icons.poll, - "poll_sharp": Icons.poll_sharp, - "poll_rounded": Icons.poll_rounded, - "poll_outlined": Icons.poll_outlined, - "polyline": Icons.polyline, - "polyline_sharp": Icons.polyline_sharp, - "polyline_rounded": Icons.polyline_rounded, - "polyline_outlined": Icons.polyline_outlined, - "polymer": Icons.polymer, - "polymer_sharp": Icons.polymer_sharp, - "polymer_rounded": Icons.polymer_rounded, - "polymer_outlined": Icons.polymer_outlined, - "pool": Icons.pool, - "pool_sharp": Icons.pool_sharp, - "pool_rounded": Icons.pool_rounded, - "pool_outlined": Icons.pool_outlined, - "portable_wifi_off": Icons.portable_wifi_off, - "portable_wifi_off_sharp": Icons.portable_wifi_off_sharp, - "portable_wifi_off_rounded": Icons.portable_wifi_off_rounded, - "portable_wifi_off_outlined": Icons.portable_wifi_off_outlined, - "portrait": Icons.portrait, - "portrait_sharp": Icons.portrait_sharp, - "portrait_rounded": Icons.portrait_rounded, - "portrait_outlined": Icons.portrait_outlined, - "post_add": Icons.post_add, - "post_add_sharp": Icons.post_add_sharp, - "post_add_rounded": Icons.post_add_rounded, - "post_add_outlined": Icons.post_add_outlined, - "power": Icons.power, - "power_sharp": Icons.power_sharp, - "power_rounded": Icons.power_rounded, - "power_outlined": Icons.power_outlined, - "power_input": Icons.power_input, - "power_input_sharp": Icons.power_input_sharp, - "power_input_rounded": Icons.power_input_rounded, - "power_input_outlined": Icons.power_input_outlined, - "power_off": Icons.power_off, - "power_off_sharp": Icons.power_off_sharp, - "power_off_rounded": Icons.power_off_rounded, - "power_off_outlined": Icons.power_off_outlined, - "power_settings_new": Icons.power_settings_new, - "power_settings_new_sharp": Icons.power_settings_new_sharp, - "power_settings_new_rounded": Icons.power_settings_new_rounded, - "power_settings_new_outlined": Icons.power_settings_new_outlined, - "precision_manufacturing": Icons.precision_manufacturing, - "precision_manufacturing_sharp": Icons.precision_manufacturing_sharp, - "precision_manufacturing_rounded": Icons.precision_manufacturing_rounded, - "precision_manufacturing_outlined": Icons.precision_manufacturing_outlined, - "pregnant_woman": Icons.pregnant_woman, - "pregnant_woman_sharp": Icons.pregnant_woman_sharp, - "pregnant_woman_rounded": Icons.pregnant_woman_rounded, - "pregnant_woman_outlined": Icons.pregnant_woman_outlined, - "present_to_all": Icons.present_to_all, - "present_to_all_sharp": Icons.present_to_all_sharp, - "present_to_all_rounded": Icons.present_to_all_rounded, - "present_to_all_outlined": Icons.present_to_all_outlined, - "preview": Icons.preview, - "preview_sharp": Icons.preview_sharp, - "preview_rounded": Icons.preview_rounded, - "preview_outlined": Icons.preview_outlined, - "price_change": Icons.price_change, - "price_change_sharp": Icons.price_change_sharp, - "price_change_rounded": Icons.price_change_rounded, - "price_change_outlined": Icons.price_change_outlined, - "price_check": Icons.price_check, - "price_check_sharp": Icons.price_check_sharp, - "price_check_rounded": Icons.price_check_rounded, - "price_check_outlined": Icons.price_check_outlined, - "print": Icons.print, - "print_sharp": Icons.print_sharp, - "print_rounded": Icons.print_rounded, - "print_outlined": Icons.print_outlined, - "print_disabled": Icons.print_disabled, - "print_disabled_sharp": Icons.print_disabled_sharp, - "print_disabled_rounded": Icons.print_disabled_rounded, - "print_disabled_outlined": Icons.print_disabled_outlined, - "priority_high": Icons.priority_high, - "priority_high_sharp": Icons.priority_high_sharp, - "priority_high_rounded": Icons.priority_high_rounded, - "priority_high_outlined": Icons.priority_high_outlined, - "privacy_tip": Icons.privacy_tip, - "privacy_tip_sharp": Icons.privacy_tip_sharp, - "privacy_tip_rounded": Icons.privacy_tip_rounded, - "privacy_tip_outlined": Icons.privacy_tip_outlined, - "private_connectivity": Icons.private_connectivity, - "private_connectivity_sharp": Icons.private_connectivity_sharp, - "private_connectivity_rounded": Icons.private_connectivity_rounded, - "private_connectivity_outlined": Icons.private_connectivity_outlined, - "production_quantity_limits": Icons.production_quantity_limits, - "production_quantity_limits_sharp": Icons.production_quantity_limits_sharp, - "production_quantity_limits_rounded": - Icons.production_quantity_limits_rounded, - "production_quantity_limits_outlined": - Icons.production_quantity_limits_outlined, - "propane": Icons.propane, - "propane_sharp": Icons.propane_sharp, - "propane_rounded": Icons.propane_rounded, - "propane_outlined": Icons.propane_outlined, - "propane_tank": Icons.propane_tank, - "propane_tank_sharp": Icons.propane_tank_sharp, - "propane_tank_rounded": Icons.propane_tank_rounded, - "propane_tank_outlined": Icons.propane_tank_outlined, - "psychology": Icons.psychology, - "psychology_sharp": Icons.psychology_sharp, - "psychology_rounded": Icons.psychology_rounded, - "psychology_outlined": Icons.psychology_outlined, - "psychology_alt": Icons.psychology_alt, - "psychology_alt_sharp": Icons.psychology_alt_sharp, - "psychology_alt_rounded": Icons.psychology_alt_rounded, - "psychology_alt_outlined": Icons.psychology_alt_outlined, - "public": Icons.public, - "public_sharp": Icons.public_sharp, - "public_rounded": Icons.public_rounded, - "public_outlined": Icons.public_outlined, - "public_off": Icons.public_off, - "public_off_sharp": Icons.public_off_sharp, - "public_off_rounded": Icons.public_off_rounded, - "public_off_outlined": Icons.public_off_outlined, - "publish": Icons.publish, - "publish_sharp": Icons.publish_sharp, - "publish_rounded": Icons.publish_rounded, - "publish_outlined": Icons.publish_outlined, - "published_with_changes": Icons.published_with_changes, - "published_with_changes_sharp": Icons.published_with_changes_sharp, - "published_with_changes_rounded": Icons.published_with_changes_rounded, - "published_with_changes_outlined": Icons.published_with_changes_outlined, - "punch_clock": Icons.punch_clock, - "punch_clock_sharp": Icons.punch_clock_sharp, - "punch_clock_rounded": Icons.punch_clock_rounded, - "punch_clock_outlined": Icons.punch_clock_outlined, - "push_pin": Icons.push_pin, - "push_pin_sharp": Icons.push_pin_sharp, - "push_pin_rounded": Icons.push_pin_rounded, - "push_pin_outlined": Icons.push_pin_outlined, - "qr_code": Icons.qr_code, - "qr_code_sharp": Icons.qr_code_sharp, - "qr_code_rounded": Icons.qr_code_rounded, - "qr_code_outlined": Icons.qr_code_outlined, - "qr_code_2": Icons.qr_code_2, - "qr_code_2_sharp": Icons.qr_code_2_sharp, - "qr_code_2_rounded": Icons.qr_code_2_rounded, - "qr_code_2_outlined": Icons.qr_code_2_outlined, - "qr_code_scanner": Icons.qr_code_scanner, - "qr_code_scanner_sharp": Icons.qr_code_scanner_sharp, - "qr_code_scanner_rounded": Icons.qr_code_scanner_rounded, - "qr_code_scanner_outlined": Icons.qr_code_scanner_outlined, - "query_builder": Icons.query_builder, - "query_builder_sharp": Icons.query_builder_sharp, - "query_builder_rounded": Icons.query_builder_rounded, - "query_builder_outlined": Icons.query_builder_outlined, - "query_stats": Icons.query_stats, - "query_stats_sharp": Icons.query_stats_sharp, - "query_stats_rounded": Icons.query_stats_rounded, - "query_stats_outlined": Icons.query_stats_outlined, - "question_answer": Icons.question_answer, - "question_answer_sharp": Icons.question_answer_sharp, - "question_answer_rounded": Icons.question_answer_rounded, - "question_answer_outlined": Icons.question_answer_outlined, - "question_mark": Icons.question_mark, - "question_mark_sharp": Icons.question_mark_sharp, - "question_mark_rounded": Icons.question_mark_rounded, - "question_mark_outlined": Icons.question_mark_outlined, - "queue": Icons.queue, - "queue_sharp": Icons.queue_sharp, - "queue_rounded": Icons.queue_rounded, - "queue_outlined": Icons.queue_outlined, - "queue_music": Icons.queue_music, - "queue_music_sharp": Icons.queue_music_sharp, - "queue_music_rounded": Icons.queue_music_rounded, - "queue_music_outlined": Icons.queue_music_outlined, - "queue_play_next": Icons.queue_play_next, - "queue_play_next_sharp": Icons.queue_play_next_sharp, - "queue_play_next_rounded": Icons.queue_play_next_rounded, - "queue_play_next_outlined": Icons.queue_play_next_outlined, - "quick_contacts_dialer": Icons.quick_contacts_dialer, - "quick_contacts_dialer_sharp": Icons.quick_contacts_dialer_sharp, - "quick_contacts_dialer_rounded": Icons.quick_contacts_dialer_rounded, - "quick_contacts_dialer_outlined": Icons.quick_contacts_dialer_outlined, - "quick_contacts_mail": Icons.quick_contacts_mail, - "quick_contacts_mail_sharp": Icons.quick_contacts_mail_sharp, - "quick_contacts_mail_rounded": Icons.quick_contacts_mail_rounded, - "quick_contacts_mail_outlined": Icons.quick_contacts_mail_outlined, - "quickreply": Icons.quickreply, - "quickreply_sharp": Icons.quickreply_sharp, - "quickreply_rounded": Icons.quickreply_rounded, - "quickreply_outlined": Icons.quickreply_outlined, - "quiz": Icons.quiz, - "quiz_sharp": Icons.quiz_sharp, - "quiz_rounded": Icons.quiz_rounded, - "quiz_outlined": Icons.quiz_outlined, - "quora": Icons.quora, - "quora_sharp": Icons.quora_sharp, - "quora_rounded": Icons.quora_rounded, - "quora_outlined": Icons.quora_outlined, - "r_mobiledata": Icons.r_mobiledata, - "r_mobiledata_sharp": Icons.r_mobiledata_sharp, - "r_mobiledata_rounded": Icons.r_mobiledata_rounded, - "r_mobiledata_outlined": Icons.r_mobiledata_outlined, - "radar": Icons.radar, - "radar_sharp": Icons.radar_sharp, - "radar_rounded": Icons.radar_rounded, - "radar_outlined": Icons.radar_outlined, - "radio": Icons.radio, - "radio_sharp": Icons.radio_sharp, - "radio_rounded": Icons.radio_rounded, - "radio_outlined": Icons.radio_outlined, - "radio_button_checked": Icons.radio_button_checked, - "radio_button_checked_sharp": Icons.radio_button_checked_sharp, - "radio_button_checked_rounded": Icons.radio_button_checked_rounded, - "radio_button_checked_outlined": Icons.radio_button_checked_outlined, - "radio_button_off": Icons.radio_button_off, - "radio_button_off_sharp": Icons.radio_button_off_sharp, - "radio_button_off_rounded": Icons.radio_button_off_rounded, - "radio_button_off_outlined": Icons.radio_button_off_outlined, - "radio_button_on": Icons.radio_button_on, - "radio_button_on_sharp": Icons.radio_button_on_sharp, - "radio_button_on_rounded": Icons.radio_button_on_rounded, - "radio_button_on_outlined": Icons.radio_button_on_outlined, - "radio_button_unchecked": Icons.radio_button_unchecked, - "radio_button_unchecked_sharp": Icons.radio_button_unchecked_sharp, - "radio_button_unchecked_rounded": Icons.radio_button_unchecked_rounded, - "radio_button_unchecked_outlined": Icons.radio_button_unchecked_outlined, - "railway_alert": Icons.railway_alert, - "railway_alert_sharp": Icons.railway_alert_sharp, - "railway_alert_rounded": Icons.railway_alert_rounded, - "railway_alert_outlined": Icons.railway_alert_outlined, - "ramen_dining": Icons.ramen_dining, - "ramen_dining_sharp": Icons.ramen_dining_sharp, - "ramen_dining_rounded": Icons.ramen_dining_rounded, - "ramen_dining_outlined": Icons.ramen_dining_outlined, - "ramp_left": Icons.ramp_left, - "ramp_left_sharp": Icons.ramp_left_sharp, - "ramp_left_rounded": Icons.ramp_left_rounded, - "ramp_left_outlined": Icons.ramp_left_outlined, - "ramp_right": Icons.ramp_right, - "ramp_right_sharp": Icons.ramp_right_sharp, - "ramp_right_rounded": Icons.ramp_right_rounded, - "ramp_right_outlined": Icons.ramp_right_outlined, - "rate_review": Icons.rate_review, - "rate_review_sharp": Icons.rate_review_sharp, - "rate_review_rounded": Icons.rate_review_rounded, - "rate_review_outlined": Icons.rate_review_outlined, - "raw_off": Icons.raw_off, - "raw_off_sharp": Icons.raw_off_sharp, - "raw_off_rounded": Icons.raw_off_rounded, - "raw_off_outlined": Icons.raw_off_outlined, - "raw_on": Icons.raw_on, - "raw_on_sharp": Icons.raw_on_sharp, - "raw_on_rounded": Icons.raw_on_rounded, - "raw_on_outlined": Icons.raw_on_outlined, - "read_more": Icons.read_more, - "read_more_sharp": Icons.read_more_sharp, - "read_more_rounded": Icons.read_more_rounded, - "read_more_outlined": Icons.read_more_outlined, - "real_estate_agent": Icons.real_estate_agent, - "real_estate_agent_sharp": Icons.real_estate_agent_sharp, - "real_estate_agent_rounded": Icons.real_estate_agent_rounded, - "real_estate_agent_outlined": Icons.real_estate_agent_outlined, - "rebase_edit": Icons.rebase_edit, - "receipt": Icons.receipt, - "receipt_sharp": Icons.receipt_sharp, - "receipt_rounded": Icons.receipt_rounded, - "receipt_outlined": Icons.receipt_outlined, - "receipt_long": Icons.receipt_long, - "receipt_long_sharp": Icons.receipt_long_sharp, - "receipt_long_rounded": Icons.receipt_long_rounded, - "receipt_long_outlined": Icons.receipt_long_outlined, - "recent_actors": Icons.recent_actors, - "recent_actors_sharp": Icons.recent_actors_sharp, - "recent_actors_rounded": Icons.recent_actors_rounded, - "recent_actors_outlined": Icons.recent_actors_outlined, - "recommend": Icons.recommend, - "recommend_sharp": Icons.recommend_sharp, - "recommend_rounded": Icons.recommend_rounded, - "recommend_outlined": Icons.recommend_outlined, - "record_voice_over": Icons.record_voice_over, - "record_voice_over_sharp": Icons.record_voice_over_sharp, - "record_voice_over_rounded": Icons.record_voice_over_rounded, - "record_voice_over_outlined": Icons.record_voice_over_outlined, - "rectangle": Icons.rectangle, - "rectangle_sharp": Icons.rectangle_sharp, - "rectangle_rounded": Icons.rectangle_rounded, - "rectangle_outlined": Icons.rectangle_outlined, - "recycling": Icons.recycling, - "recycling_sharp": Icons.recycling_sharp, - "recycling_rounded": Icons.recycling_rounded, - "recycling_outlined": Icons.recycling_outlined, - "reddit": Icons.reddit, - "reddit_sharp": Icons.reddit_sharp, - "reddit_rounded": Icons.reddit_rounded, - "reddit_outlined": Icons.reddit_outlined, - "redeem": Icons.redeem, - "redeem_sharp": Icons.redeem_sharp, - "redeem_rounded": Icons.redeem_rounded, - "redeem_outlined": Icons.redeem_outlined, - "redo": Icons.redo, - "redo_sharp": Icons.redo_sharp, - "redo_rounded": Icons.redo_rounded, - "redo_outlined": Icons.redo_outlined, - "reduce_capacity": Icons.reduce_capacity, - "reduce_capacity_sharp": Icons.reduce_capacity_sharp, - "reduce_capacity_rounded": Icons.reduce_capacity_rounded, - "reduce_capacity_outlined": Icons.reduce_capacity_outlined, - "refresh": Icons.refresh, - "refresh_sharp": Icons.refresh_sharp, - "refresh_rounded": Icons.refresh_rounded, - "refresh_outlined": Icons.refresh_outlined, - "remember_me": Icons.remember_me, - "remember_me_sharp": Icons.remember_me_sharp, - "remember_me_rounded": Icons.remember_me_rounded, - "remember_me_outlined": Icons.remember_me_outlined, - "remove": Icons.remove, - "remove_sharp": Icons.remove_sharp, - "remove_rounded": Icons.remove_rounded, - "remove_outlined": Icons.remove_outlined, - "remove_circle": Icons.remove_circle, - "remove_circle_sharp": Icons.remove_circle_sharp, - "remove_circle_rounded": Icons.remove_circle_rounded, - "remove_circle_outlined": Icons.remove_circle_outlined, - "remove_circle_outline": Icons.remove_circle_outline, - "remove_circle_outline_sharp": Icons.remove_circle_outline_sharp, - "remove_circle_outline_rounded": Icons.remove_circle_outline_rounded, - "remove_circle_outline_outlined": Icons.remove_circle_outline_outlined, - "remove_done": Icons.remove_done, - "remove_done_sharp": Icons.remove_done_sharp, - "remove_done_rounded": Icons.remove_done_rounded, - "remove_done_outlined": Icons.remove_done_outlined, - "remove_from_queue": Icons.remove_from_queue, - "remove_from_queue_sharp": Icons.remove_from_queue_sharp, - "remove_from_queue_rounded": Icons.remove_from_queue_rounded, - "remove_from_queue_outlined": Icons.remove_from_queue_outlined, - "remove_moderator": Icons.remove_moderator, - "remove_moderator_sharp": Icons.remove_moderator_sharp, - "remove_moderator_rounded": Icons.remove_moderator_rounded, - "remove_moderator_outlined": Icons.remove_moderator_outlined, - "remove_red_eye": Icons.remove_red_eye, - "remove_red_eye_sharp": Icons.remove_red_eye_sharp, - "remove_red_eye_rounded": Icons.remove_red_eye_rounded, - "remove_red_eye_outlined": Icons.remove_red_eye_outlined, - "remove_road": Icons.remove_road, - "remove_road_sharp": Icons.remove_road_sharp, - "remove_road_rounded": Icons.remove_road_rounded, - "remove_road_outlined": Icons.remove_road_outlined, - "remove_shopping_cart": Icons.remove_shopping_cart, - "remove_shopping_cart_sharp": Icons.remove_shopping_cart_sharp, - "remove_shopping_cart_rounded": Icons.remove_shopping_cart_rounded, - "remove_shopping_cart_outlined": Icons.remove_shopping_cart_outlined, - "reorder": Icons.reorder, - "reorder_sharp": Icons.reorder_sharp, - "reorder_rounded": Icons.reorder_rounded, - "reorder_outlined": Icons.reorder_outlined, - "repartition": Icons.repartition, - "repartition_sharp": Icons.repartition_sharp, - "repartition_rounded": Icons.repartition_rounded, - "repartition_outlined": Icons.repartition_outlined, - "repeat": Icons.repeat, - "repeat_sharp": Icons.repeat_sharp, - "repeat_rounded": Icons.repeat_rounded, - "repeat_outlined": Icons.repeat_outlined, - "repeat_on": Icons.repeat_on, - "repeat_on_sharp": Icons.repeat_on_sharp, - "repeat_on_rounded": Icons.repeat_on_rounded, - "repeat_on_outlined": Icons.repeat_on_outlined, - "repeat_one": Icons.repeat_one, - "repeat_one_sharp": Icons.repeat_one_sharp, - "repeat_one_rounded": Icons.repeat_one_rounded, - "repeat_one_outlined": Icons.repeat_one_outlined, - "repeat_one_on": Icons.repeat_one_on, - "repeat_one_on_sharp": Icons.repeat_one_on_sharp, - "repeat_one_on_rounded": Icons.repeat_one_on_rounded, - "repeat_one_on_outlined": Icons.repeat_one_on_outlined, - "replay": Icons.replay, - "replay_sharp": Icons.replay_sharp, - "replay_rounded": Icons.replay_rounded, - "replay_outlined": Icons.replay_outlined, - "replay_10": Icons.replay_10, - "replay_10_sharp": Icons.replay_10_sharp, - "replay_10_rounded": Icons.replay_10_rounded, - "replay_10_outlined": Icons.replay_10_outlined, - "replay_30": Icons.replay_30, - "replay_30_sharp": Icons.replay_30_sharp, - "replay_30_rounded": Icons.replay_30_rounded, - "replay_30_outlined": Icons.replay_30_outlined, - "replay_5": Icons.replay_5, - "replay_5_sharp": Icons.replay_5_sharp, - "replay_5_rounded": Icons.replay_5_rounded, - "replay_5_outlined": Icons.replay_5_outlined, - "replay_circle_filled": Icons.replay_circle_filled, - "replay_circle_filled_sharp": Icons.replay_circle_filled_sharp, - "replay_circle_filled_rounded": Icons.replay_circle_filled_rounded, - "replay_circle_filled_outlined": Icons.replay_circle_filled_outlined, - "reply": Icons.reply, - "reply_sharp": Icons.reply_sharp, - "reply_rounded": Icons.reply_rounded, - "reply_outlined": Icons.reply_outlined, - "reply_all": Icons.reply_all, - "reply_all_sharp": Icons.reply_all_sharp, - "reply_all_rounded": Icons.reply_all_rounded, - "reply_all_outlined": Icons.reply_all_outlined, - "report": Icons.report, - "report_sharp": Icons.report_sharp, - "report_rounded": Icons.report_rounded, - "report_outlined": Icons.report_outlined, - "report_gmailerrorred": Icons.report_gmailerrorred, - "report_gmailerrorred_sharp": Icons.report_gmailerrorred_sharp, - "report_gmailerrorred_rounded": Icons.report_gmailerrorred_rounded, - "report_gmailerrorred_outlined": Icons.report_gmailerrorred_outlined, - "report_off": Icons.report_off, - "report_off_sharp": Icons.report_off_sharp, - "report_off_rounded": Icons.report_off_rounded, - "report_off_outlined": Icons.report_off_outlined, - "report_problem": Icons.report_problem, - "report_problem_sharp": Icons.report_problem_sharp, - "report_problem_rounded": Icons.report_problem_rounded, - "report_problem_outlined": Icons.report_problem_outlined, - "request_page": Icons.request_page, - "request_page_sharp": Icons.request_page_sharp, - "request_page_rounded": Icons.request_page_rounded, - "request_page_outlined": Icons.request_page_outlined, - "request_quote": Icons.request_quote, - "request_quote_sharp": Icons.request_quote_sharp, - "request_quote_rounded": Icons.request_quote_rounded, - "request_quote_outlined": Icons.request_quote_outlined, - "reset_tv": Icons.reset_tv, - "reset_tv_sharp": Icons.reset_tv_sharp, - "reset_tv_rounded": Icons.reset_tv_rounded, - "reset_tv_outlined": Icons.reset_tv_outlined, - "restart_alt": Icons.restart_alt, - "restart_alt_sharp": Icons.restart_alt_sharp, - "restart_alt_rounded": Icons.restart_alt_rounded, - "restart_alt_outlined": Icons.restart_alt_outlined, - "restaurant": Icons.restaurant, - "restaurant_sharp": Icons.restaurant_sharp, - "restaurant_rounded": Icons.restaurant_rounded, - "restaurant_outlined": Icons.restaurant_outlined, - "restaurant_menu": Icons.restaurant_menu, - "restaurant_menu_sharp": Icons.restaurant_menu_sharp, - "restaurant_menu_rounded": Icons.restaurant_menu_rounded, - "restaurant_menu_outlined": Icons.restaurant_menu_outlined, - "restore": Icons.restore, - "restore_sharp": Icons.restore_sharp, - "restore_rounded": Icons.restore_rounded, - "restore_outlined": Icons.restore_outlined, - "restore_from_trash": Icons.restore_from_trash, - "restore_from_trash_sharp": Icons.restore_from_trash_sharp, - "restore_from_trash_rounded": Icons.restore_from_trash_rounded, - "restore_from_trash_outlined": Icons.restore_from_trash_outlined, - "restore_page": Icons.restore_page, - "restore_page_sharp": Icons.restore_page_sharp, - "restore_page_rounded": Icons.restore_page_rounded, - "restore_page_outlined": Icons.restore_page_outlined, - "reviews": Icons.reviews, - "reviews_sharp": Icons.reviews_sharp, - "reviews_rounded": Icons.reviews_rounded, - "reviews_outlined": Icons.reviews_outlined, - "rice_bowl": Icons.rice_bowl, - "rice_bowl_sharp": Icons.rice_bowl_sharp, - "rice_bowl_rounded": Icons.rice_bowl_rounded, - "rice_bowl_outlined": Icons.rice_bowl_outlined, - "ring_volume": Icons.ring_volume, - "ring_volume_sharp": Icons.ring_volume_sharp, - "ring_volume_rounded": Icons.ring_volume_rounded, - "ring_volume_outlined": Icons.ring_volume_outlined, - "rocket": Icons.rocket, - "rocket_sharp": Icons.rocket_sharp, - "rocket_rounded": Icons.rocket_rounded, - "rocket_outlined": Icons.rocket_outlined, - "rocket_launch": Icons.rocket_launch, - "rocket_launch_sharp": Icons.rocket_launch_sharp, - "rocket_launch_rounded": Icons.rocket_launch_rounded, - "rocket_launch_outlined": Icons.rocket_launch_outlined, - "roller_shades": Icons.roller_shades, - "roller_shades_sharp": Icons.roller_shades_sharp, - "roller_shades_rounded": Icons.roller_shades_rounded, - "roller_shades_outlined": Icons.roller_shades_outlined, - "roller_shades_closed": Icons.roller_shades_closed, - "roller_shades_closed_sharp": Icons.roller_shades_closed_sharp, - "roller_shades_closed_rounded": Icons.roller_shades_closed_rounded, - "roller_shades_closed_outlined": Icons.roller_shades_closed_outlined, - "roller_skating": Icons.roller_skating, - "roller_skating_sharp": Icons.roller_skating_sharp, - "roller_skating_rounded": Icons.roller_skating_rounded, - "roller_skating_outlined": Icons.roller_skating_outlined, - "roofing": Icons.roofing, - "roofing_sharp": Icons.roofing_sharp, - "roofing_rounded": Icons.roofing_rounded, - "roofing_outlined": Icons.roofing_outlined, - "room": Icons.room, - "room_sharp": Icons.room_sharp, - "room_rounded": Icons.room_rounded, - "room_outlined": Icons.room_outlined, - "room_preferences": Icons.room_preferences, - "room_preferences_sharp": Icons.room_preferences_sharp, - "room_preferences_rounded": Icons.room_preferences_rounded, - "room_preferences_outlined": Icons.room_preferences_outlined, - "room_service": Icons.room_service, - "room_service_sharp": Icons.room_service_sharp, - "room_service_rounded": Icons.room_service_rounded, - "room_service_outlined": Icons.room_service_outlined, - "rotate_90_degrees_ccw": Icons.rotate_90_degrees_ccw, - "rotate_90_degrees_ccw_sharp": Icons.rotate_90_degrees_ccw_sharp, - "rotate_90_degrees_ccw_rounded": Icons.rotate_90_degrees_ccw_rounded, - "rotate_90_degrees_ccw_outlined": Icons.rotate_90_degrees_ccw_outlined, - "rotate_90_degrees_cw": Icons.rotate_90_degrees_cw, - "rotate_90_degrees_cw_sharp": Icons.rotate_90_degrees_cw_sharp, - "rotate_90_degrees_cw_rounded": Icons.rotate_90_degrees_cw_rounded, - "rotate_90_degrees_cw_outlined": Icons.rotate_90_degrees_cw_outlined, - "rotate_left": Icons.rotate_left, - "rotate_left_sharp": Icons.rotate_left_sharp, - "rotate_left_rounded": Icons.rotate_left_rounded, - "rotate_left_outlined": Icons.rotate_left_outlined, - "rotate_right": Icons.rotate_right, - "rotate_right_sharp": Icons.rotate_right_sharp, - "rotate_right_rounded": Icons.rotate_right_rounded, - "rotate_right_outlined": Icons.rotate_right_outlined, - "roundabout_left": Icons.roundabout_left, - "roundabout_left_sharp": Icons.roundabout_left_sharp, - "roundabout_left_rounded": Icons.roundabout_left_rounded, - "roundabout_left_outlined": Icons.roundabout_left_outlined, - "roundabout_right": Icons.roundabout_right, - "roundabout_right_sharp": Icons.roundabout_right_sharp, - "roundabout_right_rounded": Icons.roundabout_right_rounded, - "roundabout_right_outlined": Icons.roundabout_right_outlined, - "rounded_corner": Icons.rounded_corner, - "rounded_corner_sharp": Icons.rounded_corner_sharp, - "rounded_corner_rounded": Icons.rounded_corner_rounded, - "rounded_corner_outlined": Icons.rounded_corner_outlined, - "route": Icons.route, - "route_sharp": Icons.route_sharp, - "route_rounded": Icons.route_rounded, - "route_outlined": Icons.route_outlined, - "router": Icons.router, - "router_sharp": Icons.router_sharp, - "router_rounded": Icons.router_rounded, - "router_outlined": Icons.router_outlined, - "rowing": Icons.rowing, - "rowing_sharp": Icons.rowing_sharp, - "rowing_rounded": Icons.rowing_rounded, - "rowing_outlined": Icons.rowing_outlined, - "rss_feed": Icons.rss_feed, - "rss_feed_sharp": Icons.rss_feed_sharp, - "rss_feed_rounded": Icons.rss_feed_rounded, - "rss_feed_outlined": Icons.rss_feed_outlined, - "rsvp": Icons.rsvp, - "rsvp_sharp": Icons.rsvp_sharp, - "rsvp_rounded": Icons.rsvp_rounded, - "rsvp_outlined": Icons.rsvp_outlined, - "rtt": Icons.rtt, - "rtt_sharp": Icons.rtt_sharp, - "rtt_rounded": Icons.rtt_rounded, - "rtt_outlined": Icons.rtt_outlined, - "rule": Icons.rule, - "rule_sharp": Icons.rule_sharp, - "rule_rounded": Icons.rule_rounded, - "rule_outlined": Icons.rule_outlined, - "rule_folder": Icons.rule_folder, - "rule_folder_sharp": Icons.rule_folder_sharp, - "rule_folder_rounded": Icons.rule_folder_rounded, - "rule_folder_outlined": Icons.rule_folder_outlined, - "run_circle": Icons.run_circle, - "run_circle_sharp": Icons.run_circle_sharp, - "run_circle_rounded": Icons.run_circle_rounded, - "run_circle_outlined": Icons.run_circle_outlined, - "running_with_errors": Icons.running_with_errors, - "running_with_errors_sharp": Icons.running_with_errors_sharp, - "running_with_errors_rounded": Icons.running_with_errors_rounded, - "running_with_errors_outlined": Icons.running_with_errors_outlined, - "rv_hookup": Icons.rv_hookup, - "rv_hookup_sharp": Icons.rv_hookup_sharp, - "rv_hookup_rounded": Icons.rv_hookup_rounded, - "rv_hookup_outlined": Icons.rv_hookup_outlined, - "safety_check": Icons.safety_check, - "safety_check_sharp": Icons.safety_check_sharp, - "safety_check_rounded": Icons.safety_check_rounded, - "safety_check_outlined": Icons.safety_check_outlined, - "safety_divider": Icons.safety_divider, - "safety_divider_sharp": Icons.safety_divider_sharp, - "safety_divider_rounded": Icons.safety_divider_rounded, - "safety_divider_outlined": Icons.safety_divider_outlined, - "sailing": Icons.sailing, - "sailing_sharp": Icons.sailing_sharp, - "sailing_rounded": Icons.sailing_rounded, - "sailing_outlined": Icons.sailing_outlined, - "sanitizer": Icons.sanitizer, - "sanitizer_sharp": Icons.sanitizer_sharp, - "sanitizer_rounded": Icons.sanitizer_rounded, - "sanitizer_outlined": Icons.sanitizer_outlined, - "satellite": Icons.satellite, - "satellite_sharp": Icons.satellite_sharp, - "satellite_rounded": Icons.satellite_rounded, - "satellite_outlined": Icons.satellite_outlined, - "satellite_alt": Icons.satellite_alt, - "satellite_alt_sharp": Icons.satellite_alt_sharp, - "satellite_alt_rounded": Icons.satellite_alt_rounded, - "satellite_alt_outlined": Icons.satellite_alt_outlined, - "save": Icons.save, - "save_sharp": Icons.save_sharp, - "save_rounded": Icons.save_rounded, - "save_outlined": Icons.save_outlined, - "save_alt": Icons.save_alt, - "save_alt_sharp": Icons.save_alt_sharp, - "save_alt_rounded": Icons.save_alt_rounded, - "save_alt_outlined": Icons.save_alt_outlined, - "save_as": Icons.save_as, - "save_as_sharp": Icons.save_as_sharp, - "save_as_rounded": Icons.save_as_rounded, - "save_as_outlined": Icons.save_as_outlined, - "saved_search": Icons.saved_search, - "saved_search_sharp": Icons.saved_search_sharp, - "saved_search_rounded": Icons.saved_search_rounded, - "saved_search_outlined": Icons.saved_search_outlined, - "savings": Icons.savings, - "savings_sharp": Icons.savings_sharp, - "savings_rounded": Icons.savings_rounded, - "savings_outlined": Icons.savings_outlined, - "scale": Icons.scale, - "scale_sharp": Icons.scale_sharp, - "scale_rounded": Icons.scale_rounded, - "scale_outlined": Icons.scale_outlined, - "scanner": Icons.scanner, - "scanner_sharp": Icons.scanner_sharp, - "scanner_rounded": Icons.scanner_rounded, - "scanner_outlined": Icons.scanner_outlined, - "scatter_plot": Icons.scatter_plot, - "scatter_plot_sharp": Icons.scatter_plot_sharp, - "scatter_plot_rounded": Icons.scatter_plot_rounded, - "scatter_plot_outlined": Icons.scatter_plot_outlined, - "schedule": Icons.schedule, - "schedule_sharp": Icons.schedule_sharp, - "schedule_rounded": Icons.schedule_rounded, - "schedule_outlined": Icons.schedule_outlined, - "schedule_send": Icons.schedule_send, - "schedule_send_sharp": Icons.schedule_send_sharp, - "schedule_send_rounded": Icons.schedule_send_rounded, - "schedule_send_outlined": Icons.schedule_send_outlined, - "schema": Icons.schema, - "schema_sharp": Icons.schema_sharp, - "schema_rounded": Icons.schema_rounded, - "schema_outlined": Icons.schema_outlined, - "school": Icons.school, - "school_sharp": Icons.school_sharp, - "school_rounded": Icons.school_rounded, - "school_outlined": Icons.school_outlined, - "science": Icons.science, - "science_sharp": Icons.science_sharp, - "science_rounded": Icons.science_rounded, - "science_outlined": Icons.science_outlined, - "score": Icons.score, - "score_sharp": Icons.score_sharp, - "score_rounded": Icons.score_rounded, - "score_outlined": Icons.score_outlined, - "scoreboard": Icons.scoreboard, - "scoreboard_sharp": Icons.scoreboard_sharp, - "scoreboard_rounded": Icons.scoreboard_rounded, - "scoreboard_outlined": Icons.scoreboard_outlined, - "screen_lock_landscape": Icons.screen_lock_landscape, - "screen_lock_landscape_sharp": Icons.screen_lock_landscape_sharp, - "screen_lock_landscape_rounded": Icons.screen_lock_landscape_rounded, - "screen_lock_landscape_outlined": Icons.screen_lock_landscape_outlined, - "screen_lock_portrait": Icons.screen_lock_portrait, - "screen_lock_portrait_sharp": Icons.screen_lock_portrait_sharp, - "screen_lock_portrait_rounded": Icons.screen_lock_portrait_rounded, - "screen_lock_portrait_outlined": Icons.screen_lock_portrait_outlined, - "screen_lock_rotation": Icons.screen_lock_rotation, - "screen_lock_rotation_sharp": Icons.screen_lock_rotation_sharp, - "screen_lock_rotation_rounded": Icons.screen_lock_rotation_rounded, - "screen_lock_rotation_outlined": Icons.screen_lock_rotation_outlined, - "screen_rotation": Icons.screen_rotation, - "screen_rotation_sharp": Icons.screen_rotation_sharp, - "screen_rotation_rounded": Icons.screen_rotation_rounded, - "screen_rotation_outlined": Icons.screen_rotation_outlined, - "screen_rotation_alt": Icons.screen_rotation_alt, - "screen_rotation_alt_sharp": Icons.screen_rotation_alt_sharp, - "screen_rotation_alt_rounded": Icons.screen_rotation_alt_rounded, - "screen_rotation_alt_outlined": Icons.screen_rotation_alt_outlined, - "screen_search_desktop": Icons.screen_search_desktop, - "screen_search_desktop_sharp": Icons.screen_search_desktop_sharp, - "screen_search_desktop_rounded": Icons.screen_search_desktop_rounded, - "screen_search_desktop_outlined": Icons.screen_search_desktop_outlined, - "screen_share": Icons.screen_share, - "screen_share_sharp": Icons.screen_share_sharp, - "screen_share_rounded": Icons.screen_share_rounded, - "screen_share_outlined": Icons.screen_share_outlined, - "screenshot": Icons.screenshot, - "screenshot_sharp": Icons.screenshot_sharp, - "screenshot_rounded": Icons.screenshot_rounded, - "screenshot_outlined": Icons.screenshot_outlined, - "screenshot_monitor": Icons.screenshot_monitor, - "screenshot_monitor_sharp": Icons.screenshot_monitor_sharp, - "screenshot_monitor_rounded": Icons.screenshot_monitor_rounded, - "screenshot_monitor_outlined": Icons.screenshot_monitor_outlined, - "scuba_diving": Icons.scuba_diving, - "scuba_diving_sharp": Icons.scuba_diving_sharp, - "scuba_diving_rounded": Icons.scuba_diving_rounded, - "scuba_diving_outlined": Icons.scuba_diving_outlined, - "sd": Icons.sd, - "sd_sharp": Icons.sd_sharp, - "sd_rounded": Icons.sd_rounded, - "sd_outlined": Icons.sd_outlined, - "sd_card": Icons.sd_card, - "sd_card_sharp": Icons.sd_card_sharp, - "sd_card_rounded": Icons.sd_card_rounded, - "sd_card_outlined": Icons.sd_card_outlined, - "sd_card_alert": Icons.sd_card_alert, - "sd_card_alert_sharp": Icons.sd_card_alert_sharp, - "sd_card_alert_rounded": Icons.sd_card_alert_rounded, - "sd_card_alert_outlined": Icons.sd_card_alert_outlined, - "sd_storage": Icons.sd_storage, - "sd_storage_sharp": Icons.sd_storage_sharp, - "sd_storage_rounded": Icons.sd_storage_rounded, - "sd_storage_outlined": Icons.sd_storage_outlined, - "search": Icons.search, - "search_sharp": Icons.search_sharp, - "search_rounded": Icons.search_rounded, - "search_outlined": Icons.search_outlined, - "search_off": Icons.search_off, - "search_off_sharp": Icons.search_off_sharp, - "search_off_rounded": Icons.search_off_rounded, - "search_off_outlined": Icons.search_off_outlined, - "security": Icons.security, - "security_sharp": Icons.security_sharp, - "security_rounded": Icons.security_rounded, - "security_outlined": Icons.security_outlined, - "security_update": Icons.security_update, - "security_update_sharp": Icons.security_update_sharp, - "security_update_rounded": Icons.security_update_rounded, - "security_update_outlined": Icons.security_update_outlined, - "security_update_good": Icons.security_update_good, - "security_update_good_sharp": Icons.security_update_good_sharp, - "security_update_good_rounded": Icons.security_update_good_rounded, - "security_update_good_outlined": Icons.security_update_good_outlined, - "security_update_warning": Icons.security_update_warning, - "security_update_warning_sharp": Icons.security_update_warning_sharp, - "security_update_warning_rounded": Icons.security_update_warning_rounded, - "security_update_warning_outlined": Icons.security_update_warning_outlined, - "segment": Icons.segment, - "segment_sharp": Icons.segment_sharp, - "segment_rounded": Icons.segment_rounded, - "segment_outlined": Icons.segment_outlined, - "select_all": Icons.select_all, - "select_all_sharp": Icons.select_all_sharp, - "select_all_rounded": Icons.select_all_rounded, - "select_all_outlined": Icons.select_all_outlined, - "self_improvement": Icons.self_improvement, - "self_improvement_sharp": Icons.self_improvement_sharp, - "self_improvement_rounded": Icons.self_improvement_rounded, - "self_improvement_outlined": Icons.self_improvement_outlined, - "sell": Icons.sell, - "sell_sharp": Icons.sell_sharp, - "sell_rounded": Icons.sell_rounded, - "sell_outlined": Icons.sell_outlined, - "send": Icons.send, - "send_sharp": Icons.send_sharp, - "send_rounded": Icons.send_rounded, - "send_outlined": Icons.send_outlined, - "send_and_archive": Icons.send_and_archive, - "send_and_archive_sharp": Icons.send_and_archive_sharp, - "send_and_archive_rounded": Icons.send_and_archive_rounded, - "send_and_archive_outlined": Icons.send_and_archive_outlined, - "send_time_extension": Icons.send_time_extension, - "send_time_extension_sharp": Icons.send_time_extension_sharp, - "send_time_extension_rounded": Icons.send_time_extension_rounded, - "send_time_extension_outlined": Icons.send_time_extension_outlined, - "send_to_mobile": Icons.send_to_mobile, - "send_to_mobile_sharp": Icons.send_to_mobile_sharp, - "send_to_mobile_rounded": Icons.send_to_mobile_rounded, - "send_to_mobile_outlined": Icons.send_to_mobile_outlined, - "sensor_door": Icons.sensor_door, - "sensor_door_sharp": Icons.sensor_door_sharp, - "sensor_door_rounded": Icons.sensor_door_rounded, - "sensor_door_outlined": Icons.sensor_door_outlined, - "sensor_occupied": Icons.sensor_occupied, - "sensor_occupied_sharp": Icons.sensor_occupied_sharp, - "sensor_occupied_rounded": Icons.sensor_occupied_rounded, - "sensor_occupied_outlined": Icons.sensor_occupied_outlined, - "sensor_window": Icons.sensor_window, - "sensor_window_sharp": Icons.sensor_window_sharp, - "sensor_window_rounded": Icons.sensor_window_rounded, - "sensor_window_outlined": Icons.sensor_window_outlined, - "sensors": Icons.sensors, - "sensors_sharp": Icons.sensors_sharp, - "sensors_rounded": Icons.sensors_rounded, - "sensors_outlined": Icons.sensors_outlined, - "sensors_off": Icons.sensors_off, - "sensors_off_sharp": Icons.sensors_off_sharp, - "sensors_off_rounded": Icons.sensors_off_rounded, - "sensors_off_outlined": Icons.sensors_off_outlined, - "sentiment_dissatisfied": Icons.sentiment_dissatisfied, - "sentiment_dissatisfied_sharp": Icons.sentiment_dissatisfied_sharp, - "sentiment_dissatisfied_rounded": Icons.sentiment_dissatisfied_rounded, - "sentiment_dissatisfied_outlined": Icons.sentiment_dissatisfied_outlined, - "sentiment_neutral": Icons.sentiment_neutral, - "sentiment_neutral_sharp": Icons.sentiment_neutral_sharp, - "sentiment_neutral_rounded": Icons.sentiment_neutral_rounded, - "sentiment_neutral_outlined": Icons.sentiment_neutral_outlined, - "sentiment_satisfied": Icons.sentiment_satisfied, - "sentiment_satisfied_sharp": Icons.sentiment_satisfied_sharp, - "sentiment_satisfied_rounded": Icons.sentiment_satisfied_rounded, - "sentiment_satisfied_outlined": Icons.sentiment_satisfied_outlined, - "sentiment_satisfied_alt": Icons.sentiment_satisfied_alt, - "sentiment_satisfied_alt_sharp": Icons.sentiment_satisfied_alt_sharp, - "sentiment_satisfied_alt_rounded": Icons.sentiment_satisfied_alt_rounded, - "sentiment_satisfied_alt_outlined": Icons.sentiment_satisfied_alt_outlined, - "sentiment_very_dissatisfied": Icons.sentiment_very_dissatisfied, - "sentiment_very_dissatisfied_sharp": Icons.sentiment_very_dissatisfied_sharp, - "sentiment_very_dissatisfied_rounded": - Icons.sentiment_very_dissatisfied_rounded, - "sentiment_very_dissatisfied_outlined": - Icons.sentiment_very_dissatisfied_outlined, - "sentiment_very_satisfied": Icons.sentiment_very_satisfied, - "sentiment_very_satisfied_sharp": Icons.sentiment_very_satisfied_sharp, - "sentiment_very_satisfied_rounded": Icons.sentiment_very_satisfied_rounded, - "sentiment_very_satisfied_outlined": Icons.sentiment_very_satisfied_outlined, - "set_meal": Icons.set_meal, - "set_meal_sharp": Icons.set_meal_sharp, - "set_meal_rounded": Icons.set_meal_rounded, - "set_meal_outlined": Icons.set_meal_outlined, - "settings": Icons.settings, - "settings_sharp": Icons.settings_sharp, - "settings_rounded": Icons.settings_rounded, - "settings_outlined": Icons.settings_outlined, - "settings_accessibility": Icons.settings_accessibility, - "settings_accessibility_sharp": Icons.settings_accessibility_sharp, - "settings_accessibility_rounded": Icons.settings_accessibility_rounded, - "settings_accessibility_outlined": Icons.settings_accessibility_outlined, - "settings_applications": Icons.settings_applications, - "settings_applications_sharp": Icons.settings_applications_sharp, - "settings_applications_rounded": Icons.settings_applications_rounded, - "settings_applications_outlined": Icons.settings_applications_outlined, - "settings_backup_restore": Icons.settings_backup_restore, - "settings_backup_restore_sharp": Icons.settings_backup_restore_sharp, - "settings_backup_restore_rounded": Icons.settings_backup_restore_rounded, - "settings_backup_restore_outlined": Icons.settings_backup_restore_outlined, - "settings_bluetooth": Icons.settings_bluetooth, - "settings_bluetooth_sharp": Icons.settings_bluetooth_sharp, - "settings_bluetooth_rounded": Icons.settings_bluetooth_rounded, - "settings_bluetooth_outlined": Icons.settings_bluetooth_outlined, - "settings_brightness": Icons.settings_brightness, - "settings_brightness_sharp": Icons.settings_brightness_sharp, - "settings_brightness_rounded": Icons.settings_brightness_rounded, - "settings_brightness_outlined": Icons.settings_brightness_outlined, - "settings_cell": Icons.settings_cell, - "settings_cell_sharp": Icons.settings_cell_sharp, - "settings_cell_rounded": Icons.settings_cell_rounded, - "settings_cell_outlined": Icons.settings_cell_outlined, - "settings_display": Icons.settings_display, - "settings_display_sharp": Icons.settings_display_sharp, - "settings_display_rounded": Icons.settings_display_rounded, - "settings_display_outlined": Icons.settings_display_outlined, - "settings_ethernet": Icons.settings_ethernet, - "settings_ethernet_sharp": Icons.settings_ethernet_sharp, - "settings_ethernet_rounded": Icons.settings_ethernet_rounded, - "settings_ethernet_outlined": Icons.settings_ethernet_outlined, - "settings_input_antenna": Icons.settings_input_antenna, - "settings_input_antenna_sharp": Icons.settings_input_antenna_sharp, - "settings_input_antenna_rounded": Icons.settings_input_antenna_rounded, - "settings_input_antenna_outlined": Icons.settings_input_antenna_outlined, - "settings_input_component": Icons.settings_input_component, - "settings_input_component_sharp": Icons.settings_input_component_sharp, - "settings_input_component_rounded": Icons.settings_input_component_rounded, - "settings_input_component_outlined": Icons.settings_input_component_outlined, - "settings_input_composite": Icons.settings_input_composite, - "settings_input_composite_sharp": Icons.settings_input_composite_sharp, - "settings_input_composite_rounded": Icons.settings_input_composite_rounded, - "settings_input_composite_outlined": Icons.settings_input_composite_outlined, - "settings_input_hdmi": Icons.settings_input_hdmi, - "settings_input_hdmi_sharp": Icons.settings_input_hdmi_sharp, - "settings_input_hdmi_rounded": Icons.settings_input_hdmi_rounded, - "settings_input_hdmi_outlined": Icons.settings_input_hdmi_outlined, - "settings_input_svideo": Icons.settings_input_svideo, - "settings_input_svideo_sharp": Icons.settings_input_svideo_sharp, - "settings_input_svideo_rounded": Icons.settings_input_svideo_rounded, - "settings_input_svideo_outlined": Icons.settings_input_svideo_outlined, - "settings_overscan": Icons.settings_overscan, - "settings_overscan_sharp": Icons.settings_overscan_sharp, - "settings_overscan_rounded": Icons.settings_overscan_rounded, - "settings_overscan_outlined": Icons.settings_overscan_outlined, - "settings_phone": Icons.settings_phone, - "settings_phone_sharp": Icons.settings_phone_sharp, - "settings_phone_rounded": Icons.settings_phone_rounded, - "settings_phone_outlined": Icons.settings_phone_outlined, - "settings_power": Icons.settings_power, - "settings_power_sharp": Icons.settings_power_sharp, - "settings_power_rounded": Icons.settings_power_rounded, - "settings_power_outlined": Icons.settings_power_outlined, - "settings_remote": Icons.settings_remote, - "settings_remote_sharp": Icons.settings_remote_sharp, - "settings_remote_rounded": Icons.settings_remote_rounded, - "settings_remote_outlined": Icons.settings_remote_outlined, - "settings_suggest": Icons.settings_suggest, - "settings_suggest_sharp": Icons.settings_suggest_sharp, - "settings_suggest_rounded": Icons.settings_suggest_rounded, - "settings_suggest_outlined": Icons.settings_suggest_outlined, - "settings_system_daydream": Icons.settings_system_daydream, - "settings_system_daydream_sharp": Icons.settings_system_daydream_sharp, - "settings_system_daydream_rounded": Icons.settings_system_daydream_rounded, - "settings_system_daydream_outlined": Icons.settings_system_daydream_outlined, - "settings_voice": Icons.settings_voice, - "settings_voice_sharp": Icons.settings_voice_sharp, - "settings_voice_rounded": Icons.settings_voice_rounded, - "settings_voice_outlined": Icons.settings_voice_outlined, - "severe_cold": Icons.severe_cold, - "severe_cold_sharp": Icons.severe_cold_sharp, - "severe_cold_rounded": Icons.severe_cold_rounded, - "severe_cold_outlined": Icons.severe_cold_outlined, - "shape_line": Icons.shape_line, - "shape_line_sharp": Icons.shape_line_sharp, - "shape_line_rounded": Icons.shape_line_rounded, - "shape_line_outlined": Icons.shape_line_outlined, - "share": Icons.share, - "share_sharp": Icons.share_sharp, - "share_rounded": Icons.share_rounded, - "share_outlined": Icons.share_outlined, - "share_arrival_time": Icons.share_arrival_time, - "share_arrival_time_sharp": Icons.share_arrival_time_sharp, - "share_arrival_time_rounded": Icons.share_arrival_time_rounded, - "share_arrival_time_outlined": Icons.share_arrival_time_outlined, - "share_location": Icons.share_location, - "share_location_sharp": Icons.share_location_sharp, - "share_location_rounded": Icons.share_location_rounded, - "share_location_outlined": Icons.share_location_outlined, - "shelves": Icons.shelves, - "shield": Icons.shield, - "shield_sharp": Icons.shield_sharp, - "shield_rounded": Icons.shield_rounded, - "shield_outlined": Icons.shield_outlined, - "shield_moon": Icons.shield_moon, - "shield_moon_sharp": Icons.shield_moon_sharp, - "shield_moon_rounded": Icons.shield_moon_rounded, - "shield_moon_outlined": Icons.shield_moon_outlined, - "shop": Icons.shop, - "shop_sharp": Icons.shop_sharp, - "shop_rounded": Icons.shop_rounded, - "shop_outlined": Icons.shop_outlined, - "shop_2": Icons.shop_2, - "shop_2_sharp": Icons.shop_2_sharp, - "shop_2_rounded": Icons.shop_2_rounded, - "shop_2_outlined": Icons.shop_2_outlined, - "shop_two": Icons.shop_two, - "shop_two_sharp": Icons.shop_two_sharp, - "shop_two_rounded": Icons.shop_two_rounded, - "shop_two_outlined": Icons.shop_two_outlined, - "shopify": Icons.shopify, - "shopify_sharp": Icons.shopify_sharp, - "shopify_rounded": Icons.shopify_rounded, - "shopify_outlined": Icons.shopify_outlined, - "shopping_bag": Icons.shopping_bag, - "shopping_bag_sharp": Icons.shopping_bag_sharp, - "shopping_bag_rounded": Icons.shopping_bag_rounded, - "shopping_bag_outlined": Icons.shopping_bag_outlined, - "shopping_basket": Icons.shopping_basket, - "shopping_basket_sharp": Icons.shopping_basket_sharp, - "shopping_basket_rounded": Icons.shopping_basket_rounded, - "shopping_basket_outlined": Icons.shopping_basket_outlined, - "shopping_cart": Icons.shopping_cart, - "shopping_cart_sharp": Icons.shopping_cart_sharp, - "shopping_cart_rounded": Icons.shopping_cart_rounded, - "shopping_cart_outlined": Icons.shopping_cart_outlined, - "shopping_cart_checkout": Icons.shopping_cart_checkout, - "shopping_cart_checkout_sharp": Icons.shopping_cart_checkout_sharp, - "shopping_cart_checkout_rounded": Icons.shopping_cart_checkout_rounded, - "shopping_cart_checkout_outlined": Icons.shopping_cart_checkout_outlined, - "short_text": Icons.short_text, - "short_text_sharp": Icons.short_text_sharp, - "short_text_rounded": Icons.short_text_rounded, - "short_text_outlined": Icons.short_text_outlined, - "shortcut": Icons.shortcut, - "shortcut_sharp": Icons.shortcut_sharp, - "shortcut_rounded": Icons.shortcut_rounded, - "shortcut_outlined": Icons.shortcut_outlined, - "show_chart": Icons.show_chart, - "show_chart_sharp": Icons.show_chart_sharp, - "show_chart_rounded": Icons.show_chart_rounded, - "show_chart_outlined": Icons.show_chart_outlined, - "shower": Icons.shower, - "shower_sharp": Icons.shower_sharp, - "shower_rounded": Icons.shower_rounded, - "shower_outlined": Icons.shower_outlined, - "shuffle": Icons.shuffle, - "shuffle_sharp": Icons.shuffle_sharp, - "shuffle_rounded": Icons.shuffle_rounded, - "shuffle_outlined": Icons.shuffle_outlined, - "shuffle_on": Icons.shuffle_on, - "shuffle_on_sharp": Icons.shuffle_on_sharp, - "shuffle_on_rounded": Icons.shuffle_on_rounded, - "shuffle_on_outlined": Icons.shuffle_on_outlined, - "shutter_speed": Icons.shutter_speed, - "shutter_speed_sharp": Icons.shutter_speed_sharp, - "shutter_speed_rounded": Icons.shutter_speed_rounded, - "shutter_speed_outlined": Icons.shutter_speed_outlined, - "sick": Icons.sick, - "sick_sharp": Icons.sick_sharp, - "sick_rounded": Icons.sick_rounded, - "sick_outlined": Icons.sick_outlined, - "sign_language": Icons.sign_language, - "sign_language_sharp": Icons.sign_language_sharp, - "sign_language_rounded": Icons.sign_language_rounded, - "sign_language_outlined": Icons.sign_language_outlined, - "signal_cellular_0_bar": Icons.signal_cellular_0_bar, - "signal_cellular_0_bar_sharp": Icons.signal_cellular_0_bar_sharp, - "signal_cellular_0_bar_rounded": Icons.signal_cellular_0_bar_rounded, - "signal_cellular_0_bar_outlined": Icons.signal_cellular_0_bar_outlined, - "signal_cellular_4_bar": Icons.signal_cellular_4_bar, - "signal_cellular_4_bar_sharp": Icons.signal_cellular_4_bar_sharp, - "signal_cellular_4_bar_rounded": Icons.signal_cellular_4_bar_rounded, - "signal_cellular_4_bar_outlined": Icons.signal_cellular_4_bar_outlined, - "signal_cellular_alt": Icons.signal_cellular_alt, - "signal_cellular_alt_sharp": Icons.signal_cellular_alt_sharp, - "signal_cellular_alt_rounded": Icons.signal_cellular_alt_rounded, - "signal_cellular_alt_outlined": Icons.signal_cellular_alt_outlined, - "signal_cellular_alt_1_bar": Icons.signal_cellular_alt_1_bar, - "signal_cellular_alt_1_bar_sharp": Icons.signal_cellular_alt_1_bar_sharp, - "signal_cellular_alt_1_bar_rounded": Icons.signal_cellular_alt_1_bar_rounded, - "signal_cellular_alt_1_bar_outlined": - Icons.signal_cellular_alt_1_bar_outlined, - "signal_cellular_alt_2_bar": Icons.signal_cellular_alt_2_bar, - "signal_cellular_alt_2_bar_sharp": Icons.signal_cellular_alt_2_bar_sharp, - "signal_cellular_alt_2_bar_rounded": Icons.signal_cellular_alt_2_bar_rounded, - "signal_cellular_alt_2_bar_outlined": - Icons.signal_cellular_alt_2_bar_outlined, - "signal_cellular_connected_no_internet_0_bar": - Icons.signal_cellular_connected_no_internet_0_bar, - "signal_cellular_connected_no_internet_0_bar_sharp": - Icons.signal_cellular_connected_no_internet_0_bar_sharp, - "signal_cellular_connected_no_internet_0_bar_rounded": - Icons.signal_cellular_connected_no_internet_0_bar_rounded, - "signal_cellular_connected_no_internet_0_bar_outlined": - Icons.signal_cellular_connected_no_internet_0_bar_outlined, - "signal_cellular_connected_no_internet_4_bar": - Icons.signal_cellular_connected_no_internet_4_bar, - "signal_cellular_connected_no_internet_4_bar_sharp": - Icons.signal_cellular_connected_no_internet_4_bar_sharp, - "signal_cellular_connected_no_internet_4_bar_rounded": - Icons.signal_cellular_connected_no_internet_4_bar_rounded, - "signal_cellular_connected_no_internet_4_bar_outlined": - Icons.signal_cellular_connected_no_internet_4_bar_outlined, - "signal_cellular_no_sim": Icons.signal_cellular_no_sim, - "signal_cellular_no_sim_sharp": Icons.signal_cellular_no_sim_sharp, - "signal_cellular_no_sim_rounded": Icons.signal_cellular_no_sim_rounded, - "signal_cellular_no_sim_outlined": Icons.signal_cellular_no_sim_outlined, - "signal_cellular_nodata": Icons.signal_cellular_nodata, - "signal_cellular_nodata_sharp": Icons.signal_cellular_nodata_sharp, - "signal_cellular_nodata_rounded": Icons.signal_cellular_nodata_rounded, - "signal_cellular_nodata_outlined": Icons.signal_cellular_nodata_outlined, - "signal_cellular_null": Icons.signal_cellular_null, - "signal_cellular_null_sharp": Icons.signal_cellular_null_sharp, - "signal_cellular_null_rounded": Icons.signal_cellular_null_rounded, - "signal_cellular_null_outlined": Icons.signal_cellular_null_outlined, - "signal_cellular_off": Icons.signal_cellular_off, - "signal_cellular_off_sharp": Icons.signal_cellular_off_sharp, - "signal_cellular_off_rounded": Icons.signal_cellular_off_rounded, - "signal_cellular_off_outlined": Icons.signal_cellular_off_outlined, - "signal_wifi_0_bar": Icons.signal_wifi_0_bar, - "signal_wifi_0_bar_sharp": Icons.signal_wifi_0_bar_sharp, - "signal_wifi_0_bar_rounded": Icons.signal_wifi_0_bar_rounded, - "signal_wifi_0_bar_outlined": Icons.signal_wifi_0_bar_outlined, - "signal_wifi_4_bar": Icons.signal_wifi_4_bar, - "signal_wifi_4_bar_sharp": Icons.signal_wifi_4_bar_sharp, - "signal_wifi_4_bar_rounded": Icons.signal_wifi_4_bar_rounded, - "signal_wifi_4_bar_outlined": Icons.signal_wifi_4_bar_outlined, - "signal_wifi_4_bar_lock": Icons.signal_wifi_4_bar_lock, - "signal_wifi_4_bar_lock_sharp": Icons.signal_wifi_4_bar_lock_sharp, - "signal_wifi_4_bar_lock_rounded": Icons.signal_wifi_4_bar_lock_rounded, - "signal_wifi_4_bar_lock_outlined": Icons.signal_wifi_4_bar_lock_outlined, - "signal_wifi_bad": Icons.signal_wifi_bad, - "signal_wifi_bad_sharp": Icons.signal_wifi_bad_sharp, - "signal_wifi_bad_rounded": Icons.signal_wifi_bad_rounded, - "signal_wifi_bad_outlined": Icons.signal_wifi_bad_outlined, - "signal_wifi_connected_no_internet_4": - Icons.signal_wifi_connected_no_internet_4, - "signal_wifi_connected_no_internet_4_sharp": - Icons.signal_wifi_connected_no_internet_4_sharp, - "signal_wifi_connected_no_internet_4_rounded": - Icons.signal_wifi_connected_no_internet_4_rounded, - "signal_wifi_connected_no_internet_4_outlined": - Icons.signal_wifi_connected_no_internet_4_outlined, - "signal_wifi_off": Icons.signal_wifi_off, - "signal_wifi_off_sharp": Icons.signal_wifi_off_sharp, - "signal_wifi_off_rounded": Icons.signal_wifi_off_rounded, - "signal_wifi_off_outlined": Icons.signal_wifi_off_outlined, - "signal_wifi_statusbar_4_bar": Icons.signal_wifi_statusbar_4_bar, - "signal_wifi_statusbar_4_bar_sharp": Icons.signal_wifi_statusbar_4_bar_sharp, - "signal_wifi_statusbar_4_bar_rounded": - Icons.signal_wifi_statusbar_4_bar_rounded, - "signal_wifi_statusbar_4_bar_outlined": - Icons.signal_wifi_statusbar_4_bar_outlined, - "signal_wifi_statusbar_connected_no_internet_4": - Icons.signal_wifi_statusbar_connected_no_internet_4, - "signal_wifi_statusbar_connected_no_internet_4_sharp": - Icons.signal_wifi_statusbar_connected_no_internet_4_sharp, - "signal_wifi_statusbar_connected_no_internet_4_rounded": - Icons.signal_wifi_statusbar_connected_no_internet_4_rounded, - "signal_wifi_statusbar_connected_no_internet_4_outlined": - Icons.signal_wifi_statusbar_connected_no_internet_4_outlined, - "signal_wifi_statusbar_null": Icons.signal_wifi_statusbar_null, - "signal_wifi_statusbar_null_sharp": Icons.signal_wifi_statusbar_null_sharp, - "signal_wifi_statusbar_null_rounded": - Icons.signal_wifi_statusbar_null_rounded, - "signal_wifi_statusbar_null_outlined": - Icons.signal_wifi_statusbar_null_outlined, - "signpost": Icons.signpost, - "signpost_sharp": Icons.signpost_sharp, - "signpost_rounded": Icons.signpost_rounded, - "signpost_outlined": Icons.signpost_outlined, - "sim_card": Icons.sim_card, - "sim_card_sharp": Icons.sim_card_sharp, - "sim_card_rounded": Icons.sim_card_rounded, - "sim_card_outlined": Icons.sim_card_outlined, - "sim_card_alert": Icons.sim_card_alert, - "sim_card_alert_sharp": Icons.sim_card_alert_sharp, - "sim_card_alert_rounded": Icons.sim_card_alert_rounded, - "sim_card_alert_outlined": Icons.sim_card_alert_outlined, - "sim_card_download": Icons.sim_card_download, - "sim_card_download_sharp": Icons.sim_card_download_sharp, - "sim_card_download_rounded": Icons.sim_card_download_rounded, - "sim_card_download_outlined": Icons.sim_card_download_outlined, - "single_bed": Icons.single_bed, - "single_bed_sharp": Icons.single_bed_sharp, - "single_bed_rounded": Icons.single_bed_rounded, - "single_bed_outlined": Icons.single_bed_outlined, - "sip": Icons.sip, - "sip_sharp": Icons.sip_sharp, - "sip_rounded": Icons.sip_rounded, - "sip_outlined": Icons.sip_outlined, - "skateboarding": Icons.skateboarding, - "skateboarding_sharp": Icons.skateboarding_sharp, - "skateboarding_rounded": Icons.skateboarding_rounded, - "skateboarding_outlined": Icons.skateboarding_outlined, - "skip_next": Icons.skip_next, - "skip_next_sharp": Icons.skip_next_sharp, - "skip_next_rounded": Icons.skip_next_rounded, - "skip_next_outlined": Icons.skip_next_outlined, - "skip_previous": Icons.skip_previous, - "skip_previous_sharp": Icons.skip_previous_sharp, - "skip_previous_rounded": Icons.skip_previous_rounded, - "skip_previous_outlined": Icons.skip_previous_outlined, - "sledding": Icons.sledding, - "sledding_sharp": Icons.sledding_sharp, - "sledding_rounded": Icons.sledding_rounded, - "sledding_outlined": Icons.sledding_outlined, - "slideshow": Icons.slideshow, - "slideshow_sharp": Icons.slideshow_sharp, - "slideshow_rounded": Icons.slideshow_rounded, - "slideshow_outlined": Icons.slideshow_outlined, - "slow_motion_video": Icons.slow_motion_video, - "slow_motion_video_sharp": Icons.slow_motion_video_sharp, - "slow_motion_video_rounded": Icons.slow_motion_video_rounded, - "slow_motion_video_outlined": Icons.slow_motion_video_outlined, - "smart_button": Icons.smart_button, - "smart_button_sharp": Icons.smart_button_sharp, - "smart_button_rounded": Icons.smart_button_rounded, - "smart_button_outlined": Icons.smart_button_outlined, - "smart_display": Icons.smart_display, - "smart_display_sharp": Icons.smart_display_sharp, - "smart_display_rounded": Icons.smart_display_rounded, - "smart_display_outlined": Icons.smart_display_outlined, - "smart_screen": Icons.smart_screen, - "smart_screen_sharp": Icons.smart_screen_sharp, - "smart_screen_rounded": Icons.smart_screen_rounded, - "smart_screen_outlined": Icons.smart_screen_outlined, - "smart_toy": Icons.smart_toy, - "smart_toy_sharp": Icons.smart_toy_sharp, - "smart_toy_rounded": Icons.smart_toy_rounded, - "smart_toy_outlined": Icons.smart_toy_outlined, - "smartphone": Icons.smartphone, - "smartphone_sharp": Icons.smartphone_sharp, - "smartphone_rounded": Icons.smartphone_rounded, - "smartphone_outlined": Icons.smartphone_outlined, - "smoke_free": Icons.smoke_free, - "smoke_free_sharp": Icons.smoke_free_sharp, - "smoke_free_rounded": Icons.smoke_free_rounded, - "smoke_free_outlined": Icons.smoke_free_outlined, - "smoking_rooms": Icons.smoking_rooms, - "smoking_rooms_sharp": Icons.smoking_rooms_sharp, - "smoking_rooms_rounded": Icons.smoking_rooms_rounded, - "smoking_rooms_outlined": Icons.smoking_rooms_outlined, - "sms": Icons.sms, - "sms_sharp": Icons.sms_sharp, - "sms_rounded": Icons.sms_rounded, - "sms_outlined": Icons.sms_outlined, - "sms_failed": Icons.sms_failed, - "sms_failed_sharp": Icons.sms_failed_sharp, - "sms_failed_rounded": Icons.sms_failed_rounded, - "sms_failed_outlined": Icons.sms_failed_outlined, - "snapchat": Icons.snapchat, - "snapchat_sharp": Icons.snapchat_sharp, - "snapchat_rounded": Icons.snapchat_rounded, - "snapchat_outlined": Icons.snapchat_outlined, - "snippet_folder": Icons.snippet_folder, - "snippet_folder_sharp": Icons.snippet_folder_sharp, - "snippet_folder_rounded": Icons.snippet_folder_rounded, - "snippet_folder_outlined": Icons.snippet_folder_outlined, - "snooze": Icons.snooze, - "snooze_sharp": Icons.snooze_sharp, - "snooze_rounded": Icons.snooze_rounded, - "snooze_outlined": Icons.snooze_outlined, - "snowboarding": Icons.snowboarding, - "snowboarding_sharp": Icons.snowboarding_sharp, - "snowboarding_rounded": Icons.snowboarding_rounded, - "snowboarding_outlined": Icons.snowboarding_outlined, - "snowing": Icons.snowing, - "snowmobile": Icons.snowmobile, - "snowmobile_sharp": Icons.snowmobile_sharp, - "snowmobile_rounded": Icons.snowmobile_rounded, - "snowmobile_outlined": Icons.snowmobile_outlined, - "snowshoeing": Icons.snowshoeing, - "snowshoeing_sharp": Icons.snowshoeing_sharp, - "snowshoeing_rounded": Icons.snowshoeing_rounded, - "snowshoeing_outlined": Icons.snowshoeing_outlined, - "soap": Icons.soap, - "soap_sharp": Icons.soap_sharp, - "soap_rounded": Icons.soap_rounded, - "soap_outlined": Icons.soap_outlined, - "social_distance": Icons.social_distance, - "social_distance_sharp": Icons.social_distance_sharp, - "social_distance_rounded": Icons.social_distance_rounded, - "social_distance_outlined": Icons.social_distance_outlined, - "solar_power": Icons.solar_power, - "solar_power_sharp": Icons.solar_power_sharp, - "solar_power_rounded": Icons.solar_power_rounded, - "solar_power_outlined": Icons.solar_power_outlined, - "sort": Icons.sort, - "sort_sharp": Icons.sort_sharp, - "sort_rounded": Icons.sort_rounded, - "sort_outlined": Icons.sort_outlined, - "sort_by_alpha": Icons.sort_by_alpha, - "sort_by_alpha_sharp": Icons.sort_by_alpha_sharp, - "sort_by_alpha_rounded": Icons.sort_by_alpha_rounded, - "sort_by_alpha_outlined": Icons.sort_by_alpha_outlined, - "sos": Icons.sos, - "sos_sharp": Icons.sos_sharp, - "sos_rounded": Icons.sos_rounded, - "sos_outlined": Icons.sos_outlined, - "soup_kitchen": Icons.soup_kitchen, - "soup_kitchen_sharp": Icons.soup_kitchen_sharp, - "soup_kitchen_rounded": Icons.soup_kitchen_rounded, - "soup_kitchen_outlined": Icons.soup_kitchen_outlined, - "source": Icons.source, - "source_sharp": Icons.source_sharp, - "source_rounded": Icons.source_rounded, - "source_outlined": Icons.source_outlined, - "south": Icons.south, - "south_sharp": Icons.south_sharp, - "south_rounded": Icons.south_rounded, - "south_outlined": Icons.south_outlined, - "south_america": Icons.south_america, - "south_america_sharp": Icons.south_america_sharp, - "south_america_rounded": Icons.south_america_rounded, - "south_america_outlined": Icons.south_america_outlined, - "south_east": Icons.south_east, - "south_east_sharp": Icons.south_east_sharp, - "south_east_rounded": Icons.south_east_rounded, - "south_east_outlined": Icons.south_east_outlined, - "south_west": Icons.south_west, - "south_west_sharp": Icons.south_west_sharp, - "south_west_rounded": Icons.south_west_rounded, - "south_west_outlined": Icons.south_west_outlined, - "spa": Icons.spa, - "spa_sharp": Icons.spa_sharp, - "spa_rounded": Icons.spa_rounded, - "spa_outlined": Icons.spa_outlined, - "space_bar": Icons.space_bar, - "space_bar_sharp": Icons.space_bar_sharp, - "space_bar_rounded": Icons.space_bar_rounded, - "space_bar_outlined": Icons.space_bar_outlined, - "space_dashboard": Icons.space_dashboard, - "space_dashboard_sharp": Icons.space_dashboard_sharp, - "space_dashboard_rounded": Icons.space_dashboard_rounded, - "space_dashboard_outlined": Icons.space_dashboard_outlined, - "spatial_audio": Icons.spatial_audio, - "spatial_audio_sharp": Icons.spatial_audio_sharp, - "spatial_audio_rounded": Icons.spatial_audio_rounded, - "spatial_audio_outlined": Icons.spatial_audio_outlined, - "spatial_audio_off": Icons.spatial_audio_off, - "spatial_audio_off_sharp": Icons.spatial_audio_off_sharp, - "spatial_audio_off_rounded": Icons.spatial_audio_off_rounded, - "spatial_audio_off_outlined": Icons.spatial_audio_off_outlined, - "spatial_tracking": Icons.spatial_tracking, - "spatial_tracking_sharp": Icons.spatial_tracking_sharp, - "spatial_tracking_rounded": Icons.spatial_tracking_rounded, - "spatial_tracking_outlined": Icons.spatial_tracking_outlined, - "speaker": Icons.speaker, - "speaker_sharp": Icons.speaker_sharp, - "speaker_rounded": Icons.speaker_rounded, - "speaker_outlined": Icons.speaker_outlined, - "speaker_group": Icons.speaker_group, - "speaker_group_sharp": Icons.speaker_group_sharp, - "speaker_group_rounded": Icons.speaker_group_rounded, - "speaker_group_outlined": Icons.speaker_group_outlined, - "speaker_notes": Icons.speaker_notes, - "speaker_notes_sharp": Icons.speaker_notes_sharp, - "speaker_notes_rounded": Icons.speaker_notes_rounded, - "speaker_notes_outlined": Icons.speaker_notes_outlined, - "speaker_notes_off": Icons.speaker_notes_off, - "speaker_notes_off_sharp": Icons.speaker_notes_off_sharp, - "speaker_notes_off_rounded": Icons.speaker_notes_off_rounded, - "speaker_notes_off_outlined": Icons.speaker_notes_off_outlined, - "speaker_phone": Icons.speaker_phone, - "speaker_phone_sharp": Icons.speaker_phone_sharp, - "speaker_phone_rounded": Icons.speaker_phone_rounded, - "speaker_phone_outlined": Icons.speaker_phone_outlined, - "speed": Icons.speed, - "speed_sharp": Icons.speed_sharp, - "speed_rounded": Icons.speed_rounded, - "speed_outlined": Icons.speed_outlined, - "spellcheck": Icons.spellcheck, - "spellcheck_sharp": Icons.spellcheck_sharp, - "spellcheck_rounded": Icons.spellcheck_rounded, - "spellcheck_outlined": Icons.spellcheck_outlined, - "splitscreen": Icons.splitscreen, - "splitscreen_sharp": Icons.splitscreen_sharp, - "splitscreen_rounded": Icons.splitscreen_rounded, - "splitscreen_outlined": Icons.splitscreen_outlined, - "spoke": Icons.spoke, - "spoke_sharp": Icons.spoke_sharp, - "spoke_rounded": Icons.spoke_rounded, - "spoke_outlined": Icons.spoke_outlined, - "sports": Icons.sports, - "sports_sharp": Icons.sports_sharp, - "sports_rounded": Icons.sports_rounded, - "sports_outlined": Icons.sports_outlined, - "sports_bar": Icons.sports_bar, - "sports_bar_sharp": Icons.sports_bar_sharp, - "sports_bar_rounded": Icons.sports_bar_rounded, - "sports_bar_outlined": Icons.sports_bar_outlined, - "sports_baseball": Icons.sports_baseball, - "sports_baseball_sharp": Icons.sports_baseball_sharp, - "sports_baseball_rounded": Icons.sports_baseball_rounded, - "sports_baseball_outlined": Icons.sports_baseball_outlined, - "sports_basketball": Icons.sports_basketball, - "sports_basketball_sharp": Icons.sports_basketball_sharp, - "sports_basketball_rounded": Icons.sports_basketball_rounded, - "sports_basketball_outlined": Icons.sports_basketball_outlined, - "sports_cricket": Icons.sports_cricket, - "sports_cricket_sharp": Icons.sports_cricket_sharp, - "sports_cricket_rounded": Icons.sports_cricket_rounded, - "sports_cricket_outlined": Icons.sports_cricket_outlined, - "sports_esports": Icons.sports_esports, - "sports_esports_sharp": Icons.sports_esports_sharp, - "sports_esports_rounded": Icons.sports_esports_rounded, - "sports_esports_outlined": Icons.sports_esports_outlined, - "sports_football": Icons.sports_football, - "sports_football_sharp": Icons.sports_football_sharp, - "sports_football_rounded": Icons.sports_football_rounded, - "sports_football_outlined": Icons.sports_football_outlined, - "sports_golf": Icons.sports_golf, - "sports_golf_sharp": Icons.sports_golf_sharp, - "sports_golf_rounded": Icons.sports_golf_rounded, - "sports_golf_outlined": Icons.sports_golf_outlined, - "sports_gymnastics": Icons.sports_gymnastics, - "sports_gymnastics_sharp": Icons.sports_gymnastics_sharp, - "sports_gymnastics_rounded": Icons.sports_gymnastics_rounded, - "sports_gymnastics_outlined": Icons.sports_gymnastics_outlined, - "sports_handball": Icons.sports_handball, - "sports_handball_sharp": Icons.sports_handball_sharp, - "sports_handball_rounded": Icons.sports_handball_rounded, - "sports_handball_outlined": Icons.sports_handball_outlined, - "sports_hockey": Icons.sports_hockey, - "sports_hockey_sharp": Icons.sports_hockey_sharp, - "sports_hockey_rounded": Icons.sports_hockey_rounded, - "sports_hockey_outlined": Icons.sports_hockey_outlined, - "sports_kabaddi": Icons.sports_kabaddi, - "sports_kabaddi_sharp": Icons.sports_kabaddi_sharp, - "sports_kabaddi_rounded": Icons.sports_kabaddi_rounded, - "sports_kabaddi_outlined": Icons.sports_kabaddi_outlined, - "sports_martial_arts": Icons.sports_martial_arts, - "sports_martial_arts_sharp": Icons.sports_martial_arts_sharp, - "sports_martial_arts_rounded": Icons.sports_martial_arts_rounded, - "sports_martial_arts_outlined": Icons.sports_martial_arts_outlined, - "sports_mma": Icons.sports_mma, - "sports_mma_sharp": Icons.sports_mma_sharp, - "sports_mma_rounded": Icons.sports_mma_rounded, - "sports_mma_outlined": Icons.sports_mma_outlined, - "sports_motorsports": Icons.sports_motorsports, - "sports_motorsports_sharp": Icons.sports_motorsports_sharp, - "sports_motorsports_rounded": Icons.sports_motorsports_rounded, - "sports_motorsports_outlined": Icons.sports_motorsports_outlined, - "sports_rugby": Icons.sports_rugby, - "sports_rugby_sharp": Icons.sports_rugby_sharp, - "sports_rugby_rounded": Icons.sports_rugby_rounded, - "sports_rugby_outlined": Icons.sports_rugby_outlined, - "sports_score": Icons.sports_score, - "sports_score_sharp": Icons.sports_score_sharp, - "sports_score_rounded": Icons.sports_score_rounded, - "sports_score_outlined": Icons.sports_score_outlined, - "sports_soccer": Icons.sports_soccer, - "sports_soccer_sharp": Icons.sports_soccer_sharp, - "sports_soccer_rounded": Icons.sports_soccer_rounded, - "sports_soccer_outlined": Icons.sports_soccer_outlined, - "sports_tennis": Icons.sports_tennis, - "sports_tennis_sharp": Icons.sports_tennis_sharp, - "sports_tennis_rounded": Icons.sports_tennis_rounded, - "sports_tennis_outlined": Icons.sports_tennis_outlined, - "sports_volleyball": Icons.sports_volleyball, - "sports_volleyball_sharp": Icons.sports_volleyball_sharp, - "sports_volleyball_rounded": Icons.sports_volleyball_rounded, - "sports_volleyball_outlined": Icons.sports_volleyball_outlined, - "square": Icons.square, - "square_sharp": Icons.square_sharp, - "square_rounded": Icons.square_rounded, - "square_outlined": Icons.square_outlined, - "square_foot": Icons.square_foot, - "square_foot_sharp": Icons.square_foot_sharp, - "square_foot_rounded": Icons.square_foot_rounded, - "square_foot_outlined": Icons.square_foot_outlined, - "ssid_chart": Icons.ssid_chart, - "ssid_chart_sharp": Icons.ssid_chart_sharp, - "ssid_chart_rounded": Icons.ssid_chart_rounded, - "ssid_chart_outlined": Icons.ssid_chart_outlined, - "stacked_bar_chart": Icons.stacked_bar_chart, - "stacked_bar_chart_sharp": Icons.stacked_bar_chart_sharp, - "stacked_bar_chart_rounded": Icons.stacked_bar_chart_rounded, - "stacked_bar_chart_outlined": Icons.stacked_bar_chart_outlined, - "stacked_line_chart": Icons.stacked_line_chart, - "stacked_line_chart_sharp": Icons.stacked_line_chart_sharp, - "stacked_line_chart_rounded": Icons.stacked_line_chart_rounded, - "stacked_line_chart_outlined": Icons.stacked_line_chart_outlined, - "stadium": Icons.stadium, - "stadium_sharp": Icons.stadium_sharp, - "stadium_rounded": Icons.stadium_rounded, - "stadium_outlined": Icons.stadium_outlined, - "stairs": Icons.stairs, - "stairs_sharp": Icons.stairs_sharp, - "stairs_rounded": Icons.stairs_rounded, - "stairs_outlined": Icons.stairs_outlined, - "star": Icons.star, - "star_sharp": Icons.star_sharp, - "star_rounded": Icons.star_rounded, - "star_outlined": Icons.star_outlined, - "star_border": Icons.star_border, - "star_border_sharp": Icons.star_border_sharp, - "star_border_rounded": Icons.star_border_rounded, - "star_border_outlined": Icons.star_border_outlined, - "star_border_purple500": Icons.star_border_purple500, - "star_border_purple500_sharp": Icons.star_border_purple500_sharp, - "star_border_purple500_rounded": Icons.star_border_purple500_rounded, - "star_border_purple500_outlined": Icons.star_border_purple500_outlined, - "star_half": Icons.star_half, - "star_half_sharp": Icons.star_half_sharp, - "star_half_rounded": Icons.star_half_rounded, - "star_half_outlined": Icons.star_half_outlined, - "star_outline": Icons.star_outline, - "star_outline_sharp": Icons.star_outline_sharp, - "star_outline_rounded": Icons.star_outline_rounded, - "star_outline_outlined": Icons.star_outline_outlined, - "star_purple500": Icons.star_purple500, - "star_purple500_sharp": Icons.star_purple500_sharp, - "star_purple500_rounded": Icons.star_purple500_rounded, - "star_purple500_outlined": Icons.star_purple500_outlined, - "star_rate": Icons.star_rate, - "star_rate_sharp": Icons.star_rate_sharp, - "star_rate_rounded": Icons.star_rate_rounded, - "star_rate_outlined": Icons.star_rate_outlined, - "stars": Icons.stars, - "stars_sharp": Icons.stars_sharp, - "stars_rounded": Icons.stars_rounded, - "stars_outlined": Icons.stars_outlined, - "start": Icons.start, - "start_sharp": Icons.start_sharp, - "start_rounded": Icons.start_rounded, - "start_outlined": Icons.start_outlined, - "stay_current_landscape": Icons.stay_current_landscape, - "stay_current_landscape_sharp": Icons.stay_current_landscape_sharp, - "stay_current_landscape_rounded": Icons.stay_current_landscape_rounded, - "stay_current_landscape_outlined": Icons.stay_current_landscape_outlined, - "stay_current_portrait": Icons.stay_current_portrait, - "stay_current_portrait_sharp": Icons.stay_current_portrait_sharp, - "stay_current_portrait_rounded": Icons.stay_current_portrait_rounded, - "stay_current_portrait_outlined": Icons.stay_current_portrait_outlined, - "stay_primary_landscape": Icons.stay_primary_landscape, - "stay_primary_landscape_sharp": Icons.stay_primary_landscape_sharp, - "stay_primary_landscape_rounded": Icons.stay_primary_landscape_rounded, - "stay_primary_landscape_outlined": Icons.stay_primary_landscape_outlined, - "stay_primary_portrait": Icons.stay_primary_portrait, - "stay_primary_portrait_sharp": Icons.stay_primary_portrait_sharp, - "stay_primary_portrait_rounded": Icons.stay_primary_portrait_rounded, - "stay_primary_portrait_outlined": Icons.stay_primary_portrait_outlined, - "sticky_note_2": Icons.sticky_note_2, - "sticky_note_2_sharp": Icons.sticky_note_2_sharp, - "sticky_note_2_rounded": Icons.sticky_note_2_rounded, - "sticky_note_2_outlined": Icons.sticky_note_2_outlined, - "stop": Icons.stop, - "stop_sharp": Icons.stop_sharp, - "stop_rounded": Icons.stop_rounded, - "stop_outlined": Icons.stop_outlined, - "stop_circle": Icons.stop_circle, - "stop_circle_sharp": Icons.stop_circle_sharp, - "stop_circle_rounded": Icons.stop_circle_rounded, - "stop_circle_outlined": Icons.stop_circle_outlined, - "stop_screen_share": Icons.stop_screen_share, - "stop_screen_share_sharp": Icons.stop_screen_share_sharp, - "stop_screen_share_rounded": Icons.stop_screen_share_rounded, - "stop_screen_share_outlined": Icons.stop_screen_share_outlined, - "storage": Icons.storage, - "storage_sharp": Icons.storage_sharp, - "storage_rounded": Icons.storage_rounded, - "storage_outlined": Icons.storage_outlined, - "store": Icons.store, - "store_sharp": Icons.store_sharp, - "store_rounded": Icons.store_rounded, - "store_outlined": Icons.store_outlined, - "store_mall_directory": Icons.store_mall_directory, - "store_mall_directory_sharp": Icons.store_mall_directory_sharp, - "store_mall_directory_rounded": Icons.store_mall_directory_rounded, - "store_mall_directory_outlined": Icons.store_mall_directory_outlined, - "storefront": Icons.storefront, - "storefront_sharp": Icons.storefront_sharp, - "storefront_rounded": Icons.storefront_rounded, - "storefront_outlined": Icons.storefront_outlined, - "storm": Icons.storm, - "storm_sharp": Icons.storm_sharp, - "storm_rounded": Icons.storm_rounded, - "storm_outlined": Icons.storm_outlined, - "straight": Icons.straight, - "straight_sharp": Icons.straight_sharp, - "straight_rounded": Icons.straight_rounded, - "straight_outlined": Icons.straight_outlined, - "straighten": Icons.straighten, - "straighten_sharp": Icons.straighten_sharp, - "straighten_rounded": Icons.straighten_rounded, - "straighten_outlined": Icons.straighten_outlined, - "stream": Icons.stream, - "stream_sharp": Icons.stream_sharp, - "stream_rounded": Icons.stream_rounded, - "stream_outlined": Icons.stream_outlined, - "streetview": Icons.streetview, - "streetview_sharp": Icons.streetview_sharp, - "streetview_rounded": Icons.streetview_rounded, - "streetview_outlined": Icons.streetview_outlined, - "strikethrough_s": Icons.strikethrough_s, - "strikethrough_s_sharp": Icons.strikethrough_s_sharp, - "strikethrough_s_rounded": Icons.strikethrough_s_rounded, - "strikethrough_s_outlined": Icons.strikethrough_s_outlined, - "stroller": Icons.stroller, - "stroller_sharp": Icons.stroller_sharp, - "stroller_rounded": Icons.stroller_rounded, - "stroller_outlined": Icons.stroller_outlined, - "style": Icons.style, - "style_sharp": Icons.style_sharp, - "style_rounded": Icons.style_rounded, - "style_outlined": Icons.style_outlined, - "subdirectory_arrow_left": Icons.subdirectory_arrow_left, - "subdirectory_arrow_left_sharp": Icons.subdirectory_arrow_left_sharp, - "subdirectory_arrow_left_rounded": Icons.subdirectory_arrow_left_rounded, - "subdirectory_arrow_left_outlined": Icons.subdirectory_arrow_left_outlined, - "subdirectory_arrow_right": Icons.subdirectory_arrow_right, - "subdirectory_arrow_right_sharp": Icons.subdirectory_arrow_right_sharp, - "subdirectory_arrow_right_rounded": Icons.subdirectory_arrow_right_rounded, - "subdirectory_arrow_right_outlined": Icons.subdirectory_arrow_right_outlined, - "subject": Icons.subject, - "subject_sharp": Icons.subject_sharp, - "subject_rounded": Icons.subject_rounded, - "subject_outlined": Icons.subject_outlined, - "subscript": Icons.subscript, - "subscript_sharp": Icons.subscript_sharp, - "subscript_rounded": Icons.subscript_rounded, - "subscript_outlined": Icons.subscript_outlined, - "subscriptions": Icons.subscriptions, - "subscriptions_sharp": Icons.subscriptions_sharp, - "subscriptions_rounded": Icons.subscriptions_rounded, - "subscriptions_outlined": Icons.subscriptions_outlined, - "subtitles": Icons.subtitles, - "subtitles_sharp": Icons.subtitles_sharp, - "subtitles_rounded": Icons.subtitles_rounded, - "subtitles_outlined": Icons.subtitles_outlined, - "subtitles_off": Icons.subtitles_off, - "subtitles_off_sharp": Icons.subtitles_off_sharp, - "subtitles_off_rounded": Icons.subtitles_off_rounded, - "subtitles_off_outlined": Icons.subtitles_off_outlined, - "subway": Icons.subway, - "subway_sharp": Icons.subway_sharp, - "subway_rounded": Icons.subway_rounded, - "subway_outlined": Icons.subway_outlined, - "summarize": Icons.summarize, - "summarize_sharp": Icons.summarize_sharp, - "summarize_rounded": Icons.summarize_rounded, - "summarize_outlined": Icons.summarize_outlined, - "sunny": Icons.sunny, - "sunny_snowing": Icons.sunny_snowing, - "superscript": Icons.superscript, - "superscript_sharp": Icons.superscript_sharp, - "superscript_rounded": Icons.superscript_rounded, - "superscript_outlined": Icons.superscript_outlined, - "supervised_user_circle": Icons.supervised_user_circle, - "supervised_user_circle_sharp": Icons.supervised_user_circle_sharp, - "supervised_user_circle_rounded": Icons.supervised_user_circle_rounded, - "supervised_user_circle_outlined": Icons.supervised_user_circle_outlined, - "supervisor_account": Icons.supervisor_account, - "supervisor_account_sharp": Icons.supervisor_account_sharp, - "supervisor_account_rounded": Icons.supervisor_account_rounded, - "supervisor_account_outlined": Icons.supervisor_account_outlined, - "support": Icons.support, - "support_sharp": Icons.support_sharp, - "support_rounded": Icons.support_rounded, - "support_outlined": Icons.support_outlined, - "support_agent": Icons.support_agent, - "support_agent_sharp": Icons.support_agent_sharp, - "support_agent_rounded": Icons.support_agent_rounded, - "support_agent_outlined": Icons.support_agent_outlined, - "surfing": Icons.surfing, - "surfing_sharp": Icons.surfing_sharp, - "surfing_rounded": Icons.surfing_rounded, - "surfing_outlined": Icons.surfing_outlined, - "surround_sound": Icons.surround_sound, - "surround_sound_sharp": Icons.surround_sound_sharp, - "surround_sound_rounded": Icons.surround_sound_rounded, - "surround_sound_outlined": Icons.surround_sound_outlined, - "swap_calls": Icons.swap_calls, - "swap_calls_sharp": Icons.swap_calls_sharp, - "swap_calls_rounded": Icons.swap_calls_rounded, - "swap_calls_outlined": Icons.swap_calls_outlined, - "swap_horiz": Icons.swap_horiz, - "swap_horiz_sharp": Icons.swap_horiz_sharp, - "swap_horiz_rounded": Icons.swap_horiz_rounded, - "swap_horiz_outlined": Icons.swap_horiz_outlined, - "swap_horizontal_circle": Icons.swap_horizontal_circle, - "swap_horizontal_circle_sharp": Icons.swap_horizontal_circle_sharp, - "swap_horizontal_circle_rounded": Icons.swap_horizontal_circle_rounded, - "swap_horizontal_circle_outlined": Icons.swap_horizontal_circle_outlined, - "swap_vert": Icons.swap_vert, - "swap_vert_sharp": Icons.swap_vert_sharp, - "swap_vert_rounded": Icons.swap_vert_rounded, - "swap_vert_outlined": Icons.swap_vert_outlined, - "swap_vert_circle": Icons.swap_vert_circle, - "swap_vert_circle_sharp": Icons.swap_vert_circle_sharp, - "swap_vert_circle_rounded": Icons.swap_vert_circle_rounded, - "swap_vert_circle_outlined": Icons.swap_vert_circle_outlined, - "swap_vertical_circle": Icons.swap_vertical_circle, - "swap_vertical_circle_sharp": Icons.swap_vertical_circle_sharp, - "swap_vertical_circle_rounded": Icons.swap_vertical_circle_rounded, - "swap_vertical_circle_outlined": Icons.swap_vertical_circle_outlined, - "swipe": Icons.swipe, - "swipe_sharp": Icons.swipe_sharp, - "swipe_rounded": Icons.swipe_rounded, - "swipe_outlined": Icons.swipe_outlined, - "swipe_down": Icons.swipe_down, - "swipe_down_sharp": Icons.swipe_down_sharp, - "swipe_down_rounded": Icons.swipe_down_rounded, - "swipe_down_outlined": Icons.swipe_down_outlined, - "swipe_down_alt": Icons.swipe_down_alt, - "swipe_down_alt_sharp": Icons.swipe_down_alt_sharp, - "swipe_down_alt_rounded": Icons.swipe_down_alt_rounded, - "swipe_down_alt_outlined": Icons.swipe_down_alt_outlined, - "swipe_left": Icons.swipe_left, - "swipe_left_sharp": Icons.swipe_left_sharp, - "swipe_left_rounded": Icons.swipe_left_rounded, - "swipe_left_outlined": Icons.swipe_left_outlined, - "swipe_left_alt": Icons.swipe_left_alt, - "swipe_left_alt_sharp": Icons.swipe_left_alt_sharp, - "swipe_left_alt_rounded": Icons.swipe_left_alt_rounded, - "swipe_left_alt_outlined": Icons.swipe_left_alt_outlined, - "swipe_right": Icons.swipe_right, - "swipe_right_sharp": Icons.swipe_right_sharp, - "swipe_right_rounded": Icons.swipe_right_rounded, - "swipe_right_outlined": Icons.swipe_right_outlined, - "swipe_right_alt": Icons.swipe_right_alt, - "swipe_right_alt_sharp": Icons.swipe_right_alt_sharp, - "swipe_right_alt_rounded": Icons.swipe_right_alt_rounded, - "swipe_right_alt_outlined": Icons.swipe_right_alt_outlined, - "swipe_up": Icons.swipe_up, - "swipe_up_sharp": Icons.swipe_up_sharp, - "swipe_up_rounded": Icons.swipe_up_rounded, - "swipe_up_outlined": Icons.swipe_up_outlined, - "swipe_up_alt": Icons.swipe_up_alt, - "swipe_up_alt_sharp": Icons.swipe_up_alt_sharp, - "swipe_up_alt_rounded": Icons.swipe_up_alt_rounded, - "swipe_up_alt_outlined": Icons.swipe_up_alt_outlined, - "swipe_vertical": Icons.swipe_vertical, - "swipe_vertical_sharp": Icons.swipe_vertical_sharp, - "swipe_vertical_rounded": Icons.swipe_vertical_rounded, - "swipe_vertical_outlined": Icons.swipe_vertical_outlined, - "switch_access_shortcut": Icons.switch_access_shortcut, - "switch_access_shortcut_sharp": Icons.switch_access_shortcut_sharp, - "switch_access_shortcut_rounded": Icons.switch_access_shortcut_rounded, - "switch_access_shortcut_outlined": Icons.switch_access_shortcut_outlined, - "switch_access_shortcut_add": Icons.switch_access_shortcut_add, - "switch_access_shortcut_add_sharp": Icons.switch_access_shortcut_add_sharp, - "switch_access_shortcut_add_rounded": - Icons.switch_access_shortcut_add_rounded, - "switch_access_shortcut_add_outlined": - Icons.switch_access_shortcut_add_outlined, - "switch_account": Icons.switch_account, - "switch_account_sharp": Icons.switch_account_sharp, - "switch_account_rounded": Icons.switch_account_rounded, - "switch_account_outlined": Icons.switch_account_outlined, - "switch_camera": Icons.switch_camera, - "switch_camera_sharp": Icons.switch_camera_sharp, - "switch_camera_rounded": Icons.switch_camera_rounded, - "switch_camera_outlined": Icons.switch_camera_outlined, - "switch_left": Icons.switch_left, - "switch_left_sharp": Icons.switch_left_sharp, - "switch_left_rounded": Icons.switch_left_rounded, - "switch_left_outlined": Icons.switch_left_outlined, - "switch_right": Icons.switch_right, - "switch_right_sharp": Icons.switch_right_sharp, - "switch_right_rounded": Icons.switch_right_rounded, - "switch_right_outlined": Icons.switch_right_outlined, - "switch_video": Icons.switch_video, - "switch_video_sharp": Icons.switch_video_sharp, - "switch_video_rounded": Icons.switch_video_rounded, - "switch_video_outlined": Icons.switch_video_outlined, - "synagogue": Icons.synagogue, - "synagogue_sharp": Icons.synagogue_sharp, - "synagogue_rounded": Icons.synagogue_rounded, - "synagogue_outlined": Icons.synagogue_outlined, - "sync": Icons.sync, - "sync_sharp": Icons.sync_sharp, - "sync_rounded": Icons.sync_rounded, - "sync_outlined": Icons.sync_outlined, - "sync_alt": Icons.sync_alt, - "sync_alt_sharp": Icons.sync_alt_sharp, - "sync_alt_rounded": Icons.sync_alt_rounded, - "sync_alt_outlined": Icons.sync_alt_outlined, - "sync_disabled": Icons.sync_disabled, - "sync_disabled_sharp": Icons.sync_disabled_sharp, - "sync_disabled_rounded": Icons.sync_disabled_rounded, - "sync_disabled_outlined": Icons.sync_disabled_outlined, - "sync_lock": Icons.sync_lock, - "sync_lock_sharp": Icons.sync_lock_sharp, - "sync_lock_rounded": Icons.sync_lock_rounded, - "sync_lock_outlined": Icons.sync_lock_outlined, - "sync_problem": Icons.sync_problem, - "sync_problem_sharp": Icons.sync_problem_sharp, - "sync_problem_rounded": Icons.sync_problem_rounded, - "sync_problem_outlined": Icons.sync_problem_outlined, - "system_security_update": Icons.system_security_update, - "system_security_update_sharp": Icons.system_security_update_sharp, - "system_security_update_rounded": Icons.system_security_update_rounded, - "system_security_update_outlined": Icons.system_security_update_outlined, - "system_security_update_good": Icons.system_security_update_good, - "system_security_update_good_sharp": Icons.system_security_update_good_sharp, - "system_security_update_good_rounded": - Icons.system_security_update_good_rounded, - "system_security_update_good_outlined": - Icons.system_security_update_good_outlined, - "system_security_update_warning": Icons.system_security_update_warning, - "system_security_update_warning_sharp": - Icons.system_security_update_warning_sharp, - "system_security_update_warning_rounded": - Icons.system_security_update_warning_rounded, - "system_security_update_warning_outlined": - Icons.system_security_update_warning_outlined, - "system_update": Icons.system_update, - "system_update_sharp": Icons.system_update_sharp, - "system_update_rounded": Icons.system_update_rounded, - "system_update_outlined": Icons.system_update_outlined, - "system_update_alt": Icons.system_update_alt, - "system_update_alt_sharp": Icons.system_update_alt_sharp, - "system_update_alt_rounded": Icons.system_update_alt_rounded, - "system_update_alt_outlined": Icons.system_update_alt_outlined, - "system_update_tv": Icons.system_update_tv, - "system_update_tv_sharp": Icons.system_update_tv_sharp, - "system_update_tv_rounded": Icons.system_update_tv_rounded, - "system_update_tv_outlined": Icons.system_update_tv_outlined, - "tab": Icons.tab, - "tab_sharp": Icons.tab_sharp, - "tab_rounded": Icons.tab_rounded, - "tab_outlined": Icons.tab_outlined, - "tab_unselected": Icons.tab_unselected, - "tab_unselected_sharp": Icons.tab_unselected_sharp, - "tab_unselected_rounded": Icons.tab_unselected_rounded, - "tab_unselected_outlined": Icons.tab_unselected_outlined, - "table_bar": Icons.table_bar, - "table_bar_sharp": Icons.table_bar_sharp, - "table_bar_rounded": Icons.table_bar_rounded, - "table_bar_outlined": Icons.table_bar_outlined, - "table_chart": Icons.table_chart, - "table_chart_sharp": Icons.table_chart_sharp, - "table_chart_rounded": Icons.table_chart_rounded, - "table_chart_outlined": Icons.table_chart_outlined, - "table_restaurant": Icons.table_restaurant, - "table_restaurant_sharp": Icons.table_restaurant_sharp, - "table_restaurant_rounded": Icons.table_restaurant_rounded, - "table_restaurant_outlined": Icons.table_restaurant_outlined, - "table_rows": Icons.table_rows, - "table_rows_sharp": Icons.table_rows_sharp, - "table_rows_rounded": Icons.table_rows_rounded, - "table_rows_outlined": Icons.table_rows_outlined, - "table_view": Icons.table_view, - "table_view_sharp": Icons.table_view_sharp, - "table_view_rounded": Icons.table_view_rounded, - "table_view_outlined": Icons.table_view_outlined, - "tablet": Icons.tablet, - "tablet_sharp": Icons.tablet_sharp, - "tablet_rounded": Icons.tablet_rounded, - "tablet_outlined": Icons.tablet_outlined, - "tablet_android": Icons.tablet_android, - "tablet_android_sharp": Icons.tablet_android_sharp, - "tablet_android_rounded": Icons.tablet_android_rounded, - "tablet_android_outlined": Icons.tablet_android_outlined, - "tablet_mac": Icons.tablet_mac, - "tablet_mac_sharp": Icons.tablet_mac_sharp, - "tablet_mac_rounded": Icons.tablet_mac_rounded, - "tablet_mac_outlined": Icons.tablet_mac_outlined, - "tag": Icons.tag, - "tag_sharp": Icons.tag_sharp, - "tag_rounded": Icons.tag_rounded, - "tag_outlined": Icons.tag_outlined, - "tag_faces": Icons.tag_faces, - "tag_faces_sharp": Icons.tag_faces_sharp, - "tag_faces_rounded": Icons.tag_faces_rounded, - "tag_faces_outlined": Icons.tag_faces_outlined, - "takeout_dining": Icons.takeout_dining, - "takeout_dining_sharp": Icons.takeout_dining_sharp, - "takeout_dining_rounded": Icons.takeout_dining_rounded, - "takeout_dining_outlined": Icons.takeout_dining_outlined, - "tap_and_play": Icons.tap_and_play, - "tap_and_play_sharp": Icons.tap_and_play_sharp, - "tap_and_play_rounded": Icons.tap_and_play_rounded, - "tap_and_play_outlined": Icons.tap_and_play_outlined, - "tapas": Icons.tapas, - "tapas_sharp": Icons.tapas_sharp, - "tapas_rounded": Icons.tapas_rounded, - "tapas_outlined": Icons.tapas_outlined, - "task": Icons.task, - "task_sharp": Icons.task_sharp, - "task_rounded": Icons.task_rounded, - "task_outlined": Icons.task_outlined, - "task_alt": Icons.task_alt, - "task_alt_sharp": Icons.task_alt_sharp, - "task_alt_rounded": Icons.task_alt_rounded, - "task_alt_outlined": Icons.task_alt_outlined, - "taxi_alert": Icons.taxi_alert, - "taxi_alert_sharp": Icons.taxi_alert_sharp, - "taxi_alert_rounded": Icons.taxi_alert_rounded, - "taxi_alert_outlined": Icons.taxi_alert_outlined, - "telegram": Icons.telegram, - "telegram_sharp": Icons.telegram_sharp, - "telegram_rounded": Icons.telegram_rounded, - "telegram_outlined": Icons.telegram_outlined, - "temple_buddhist": Icons.temple_buddhist, - "temple_buddhist_sharp": Icons.temple_buddhist_sharp, - "temple_buddhist_rounded": Icons.temple_buddhist_rounded, - "temple_buddhist_outlined": Icons.temple_buddhist_outlined, - "temple_hindu": Icons.temple_hindu, - "temple_hindu_sharp": Icons.temple_hindu_sharp, - "temple_hindu_rounded": Icons.temple_hindu_rounded, - "temple_hindu_outlined": Icons.temple_hindu_outlined, - "terminal": Icons.terminal, - "terminal_sharp": Icons.terminal_sharp, - "terminal_rounded": Icons.terminal_rounded, - "terminal_outlined": Icons.terminal_outlined, - "terrain": Icons.terrain, - "terrain_sharp": Icons.terrain_sharp, - "terrain_rounded": Icons.terrain_rounded, - "terrain_outlined": Icons.terrain_outlined, - "text_decrease": Icons.text_decrease, - "text_decrease_sharp": Icons.text_decrease_sharp, - "text_decrease_rounded": Icons.text_decrease_rounded, - "text_decrease_outlined": Icons.text_decrease_outlined, - "text_fields": Icons.text_fields, - "text_fields_sharp": Icons.text_fields_sharp, - "text_fields_rounded": Icons.text_fields_rounded, - "text_fields_outlined": Icons.text_fields_outlined, - "text_format": Icons.text_format, - "text_format_sharp": Icons.text_format_sharp, - "text_format_rounded": Icons.text_format_rounded, - "text_format_outlined": Icons.text_format_outlined, - "text_increase": Icons.text_increase, - "text_increase_sharp": Icons.text_increase_sharp, - "text_increase_rounded": Icons.text_increase_rounded, - "text_increase_outlined": Icons.text_increase_outlined, - "text_rotate_up": Icons.text_rotate_up, - "text_rotate_up_sharp": Icons.text_rotate_up_sharp, - "text_rotate_up_rounded": Icons.text_rotate_up_rounded, - "text_rotate_up_outlined": Icons.text_rotate_up_outlined, - "text_rotate_vertical": Icons.text_rotate_vertical, - "text_rotate_vertical_sharp": Icons.text_rotate_vertical_sharp, - "text_rotate_vertical_rounded": Icons.text_rotate_vertical_rounded, - "text_rotate_vertical_outlined": Icons.text_rotate_vertical_outlined, - "text_rotation_angledown": Icons.text_rotation_angledown, - "text_rotation_angledown_sharp": Icons.text_rotation_angledown_sharp, - "text_rotation_angledown_rounded": Icons.text_rotation_angledown_rounded, - "text_rotation_angledown_outlined": Icons.text_rotation_angledown_outlined, - "text_rotation_angleup": Icons.text_rotation_angleup, - "text_rotation_angleup_sharp": Icons.text_rotation_angleup_sharp, - "text_rotation_angleup_rounded": Icons.text_rotation_angleup_rounded, - "text_rotation_angleup_outlined": Icons.text_rotation_angleup_outlined, - "text_rotation_down": Icons.text_rotation_down, - "text_rotation_down_sharp": Icons.text_rotation_down_sharp, - "text_rotation_down_rounded": Icons.text_rotation_down_rounded, - "text_rotation_down_outlined": Icons.text_rotation_down_outlined, - "text_rotation_none": Icons.text_rotation_none, - "text_rotation_none_sharp": Icons.text_rotation_none_sharp, - "text_rotation_none_rounded": Icons.text_rotation_none_rounded, - "text_rotation_none_outlined": Icons.text_rotation_none_outlined, - "text_snippet": Icons.text_snippet, - "text_snippet_sharp": Icons.text_snippet_sharp, - "text_snippet_rounded": Icons.text_snippet_rounded, - "text_snippet_outlined": Icons.text_snippet_outlined, - "textsms": Icons.textsms, - "textsms_sharp": Icons.textsms_sharp, - "textsms_rounded": Icons.textsms_rounded, - "textsms_outlined": Icons.textsms_outlined, - "texture": Icons.texture, - "texture_sharp": Icons.texture_sharp, - "texture_rounded": Icons.texture_rounded, - "texture_outlined": Icons.texture_outlined, - "theater_comedy": Icons.theater_comedy, - "theater_comedy_sharp": Icons.theater_comedy_sharp, - "theater_comedy_rounded": Icons.theater_comedy_rounded, - "theater_comedy_outlined": Icons.theater_comedy_outlined, - "theaters": Icons.theaters, - "theaters_sharp": Icons.theaters_sharp, - "theaters_rounded": Icons.theaters_rounded, - "theaters_outlined": Icons.theaters_outlined, - "thermostat": Icons.thermostat, - "thermostat_sharp": Icons.thermostat_sharp, - "thermostat_rounded": Icons.thermostat_rounded, - "thermostat_outlined": Icons.thermostat_outlined, - "thermostat_auto": Icons.thermostat_auto, - "thermostat_auto_sharp": Icons.thermostat_auto_sharp, - "thermostat_auto_rounded": Icons.thermostat_auto_rounded, - "thermostat_auto_outlined": Icons.thermostat_auto_outlined, - "thumb_down": Icons.thumb_down, - "thumb_down_sharp": Icons.thumb_down_sharp, - "thumb_down_rounded": Icons.thumb_down_rounded, - "thumb_down_outlined": Icons.thumb_down_outlined, - "thumb_down_alt": Icons.thumb_down_alt, - "thumb_down_alt_sharp": Icons.thumb_down_alt_sharp, - "thumb_down_alt_rounded": Icons.thumb_down_alt_rounded, - "thumb_down_alt_outlined": Icons.thumb_down_alt_outlined, - "thumb_down_off_alt": Icons.thumb_down_off_alt, - "thumb_down_off_alt_sharp": Icons.thumb_down_off_alt_sharp, - "thumb_down_off_alt_rounded": Icons.thumb_down_off_alt_rounded, - "thumb_down_off_alt_outlined": Icons.thumb_down_off_alt_outlined, - "thumb_up": Icons.thumb_up, - "thumb_up_sharp": Icons.thumb_up_sharp, - "thumb_up_rounded": Icons.thumb_up_rounded, - "thumb_up_outlined": Icons.thumb_up_outlined, - "thumb_up_alt": Icons.thumb_up_alt, - "thumb_up_alt_sharp": Icons.thumb_up_alt_sharp, - "thumb_up_alt_rounded": Icons.thumb_up_alt_rounded, - "thumb_up_alt_outlined": Icons.thumb_up_alt_outlined, - "thumb_up_off_alt": Icons.thumb_up_off_alt, - "thumb_up_off_alt_sharp": Icons.thumb_up_off_alt_sharp, - "thumb_up_off_alt_rounded": Icons.thumb_up_off_alt_rounded, - "thumb_up_off_alt_outlined": Icons.thumb_up_off_alt_outlined, - "thumbs_up_down": Icons.thumbs_up_down, - "thumbs_up_down_sharp": Icons.thumbs_up_down_sharp, - "thumbs_up_down_rounded": Icons.thumbs_up_down_rounded, - "thumbs_up_down_outlined": Icons.thumbs_up_down_outlined, - "thunderstorm": Icons.thunderstorm, - "thunderstorm_sharp": Icons.thunderstorm_sharp, - "thunderstorm_rounded": Icons.thunderstorm_rounded, - "thunderstorm_outlined": Icons.thunderstorm_outlined, - "tiktok": Icons.tiktok, - "tiktok_sharp": Icons.tiktok_sharp, - "tiktok_rounded": Icons.tiktok_rounded, - "tiktok_outlined": Icons.tiktok_outlined, - "time_to_leave": Icons.time_to_leave, - "time_to_leave_sharp": Icons.time_to_leave_sharp, - "time_to_leave_rounded": Icons.time_to_leave_rounded, - "time_to_leave_outlined": Icons.time_to_leave_outlined, - "timelapse": Icons.timelapse, - "timelapse_sharp": Icons.timelapse_sharp, - "timelapse_rounded": Icons.timelapse_rounded, - "timelapse_outlined": Icons.timelapse_outlined, - "timeline": Icons.timeline, - "timeline_sharp": Icons.timeline_sharp, - "timeline_rounded": Icons.timeline_rounded, - "timeline_outlined": Icons.timeline_outlined, - "timer": Icons.timer, - "timer_sharp": Icons.timer_sharp, - "timer_rounded": Icons.timer_rounded, - "timer_outlined": Icons.timer_outlined, - "timer_10": Icons.timer_10, - "timer_10_sharp": Icons.timer_10_sharp, - "timer_10_rounded": Icons.timer_10_rounded, - "timer_10_outlined": Icons.timer_10_outlined, - "timer_10_select": Icons.timer_10_select, - "timer_10_select_sharp": Icons.timer_10_select_sharp, - "timer_10_select_rounded": Icons.timer_10_select_rounded, - "timer_10_select_outlined": Icons.timer_10_select_outlined, - "timer_3": Icons.timer_3, - "timer_3_sharp": Icons.timer_3_sharp, - "timer_3_rounded": Icons.timer_3_rounded, - "timer_3_outlined": Icons.timer_3_outlined, - "timer_3_select": Icons.timer_3_select, - "timer_3_select_sharp": Icons.timer_3_select_sharp, - "timer_3_select_rounded": Icons.timer_3_select_rounded, - "timer_3_select_outlined": Icons.timer_3_select_outlined, - "timer_off": Icons.timer_off, - "timer_off_sharp": Icons.timer_off_sharp, - "timer_off_rounded": Icons.timer_off_rounded, - "timer_off_outlined": Icons.timer_off_outlined, - "tips_and_updates": Icons.tips_and_updates, - "tips_and_updates_sharp": Icons.tips_and_updates_sharp, - "tips_and_updates_rounded": Icons.tips_and_updates_rounded, - "tips_and_updates_outlined": Icons.tips_and_updates_outlined, - "tire_repair": Icons.tire_repair, - "tire_repair_sharp": Icons.tire_repair_sharp, - "tire_repair_rounded": Icons.tire_repair_rounded, - "tire_repair_outlined": Icons.tire_repair_outlined, - "title": Icons.title, - "title_sharp": Icons.title_sharp, - "title_rounded": Icons.title_rounded, - "title_outlined": Icons.title_outlined, - "toc": Icons.toc, - "toc_sharp": Icons.toc_sharp, - "toc_rounded": Icons.toc_rounded, - "toc_outlined": Icons.toc_outlined, - "today": Icons.today, - "today_sharp": Icons.today_sharp, - "today_rounded": Icons.today_rounded, - "today_outlined": Icons.today_outlined, - "toggle_off": Icons.toggle_off, - "toggle_off_sharp": Icons.toggle_off_sharp, - "toggle_off_rounded": Icons.toggle_off_rounded, - "toggle_off_outlined": Icons.toggle_off_outlined, - "toggle_on": Icons.toggle_on, - "toggle_on_sharp": Icons.toggle_on_sharp, - "toggle_on_rounded": Icons.toggle_on_rounded, - "toggle_on_outlined": Icons.toggle_on_outlined, - "token": Icons.token, - "token_sharp": Icons.token_sharp, - "token_rounded": Icons.token_rounded, - "token_outlined": Icons.token_outlined, - "toll": Icons.toll, - "toll_sharp": Icons.toll_sharp, - "toll_rounded": Icons.toll_rounded, - "toll_outlined": Icons.toll_outlined, - "tonality": Icons.tonality, - "tonality_sharp": Icons.tonality_sharp, - "tonality_rounded": Icons.tonality_rounded, - "tonality_outlined": Icons.tonality_outlined, - "topic": Icons.topic, - "topic_sharp": Icons.topic_sharp, - "topic_rounded": Icons.topic_rounded, - "topic_outlined": Icons.topic_outlined, - "tornado": Icons.tornado, - "tornado_sharp": Icons.tornado_sharp, - "tornado_rounded": Icons.tornado_rounded, - "tornado_outlined": Icons.tornado_outlined, - "touch_app": Icons.touch_app, - "touch_app_sharp": Icons.touch_app_sharp, - "touch_app_rounded": Icons.touch_app_rounded, - "touch_app_outlined": Icons.touch_app_outlined, - "tour": Icons.tour, - "tour_sharp": Icons.tour_sharp, - "tour_rounded": Icons.tour_rounded, - "tour_outlined": Icons.tour_outlined, - "toys": Icons.toys, - "toys_sharp": Icons.toys_sharp, - "toys_rounded": Icons.toys_rounded, - "toys_outlined": Icons.toys_outlined, - "track_changes": Icons.track_changes, - "track_changes_sharp": Icons.track_changes_sharp, - "track_changes_rounded": Icons.track_changes_rounded, - "track_changes_outlined": Icons.track_changes_outlined, - "traffic": Icons.traffic, - "traffic_sharp": Icons.traffic_sharp, - "traffic_rounded": Icons.traffic_rounded, - "traffic_outlined": Icons.traffic_outlined, - "train": Icons.train, - "train_sharp": Icons.train_sharp, - "train_rounded": Icons.train_rounded, - "train_outlined": Icons.train_outlined, - "tram": Icons.tram, - "tram_sharp": Icons.tram_sharp, - "tram_rounded": Icons.tram_rounded, - "tram_outlined": Icons.tram_outlined, - "transcribe": Icons.transcribe, - "transcribe_sharp": Icons.transcribe_sharp, - "transcribe_rounded": Icons.transcribe_rounded, - "transcribe_outlined": Icons.transcribe_outlined, - "transfer_within_a_station": Icons.transfer_within_a_station, - "transfer_within_a_station_sharp": Icons.transfer_within_a_station_sharp, - "transfer_within_a_station_rounded": Icons.transfer_within_a_station_rounded, - "transfer_within_a_station_outlined": - Icons.transfer_within_a_station_outlined, - "transform": Icons.transform, - "transform_sharp": Icons.transform_sharp, - "transform_rounded": Icons.transform_rounded, - "transform_outlined": Icons.transform_outlined, - "transgender": Icons.transgender, - "transgender_sharp": Icons.transgender_sharp, - "transgender_rounded": Icons.transgender_rounded, - "transgender_outlined": Icons.transgender_outlined, - "transit_enterexit": Icons.transit_enterexit, - "transit_enterexit_sharp": Icons.transit_enterexit_sharp, - "transit_enterexit_rounded": Icons.transit_enterexit_rounded, - "transit_enterexit_outlined": Icons.transit_enterexit_outlined, - "translate": Icons.translate, - "translate_sharp": Icons.translate_sharp, - "translate_rounded": Icons.translate_rounded, - "translate_outlined": Icons.translate_outlined, - "travel_explore": Icons.travel_explore, - "travel_explore_sharp": Icons.travel_explore_sharp, - "travel_explore_rounded": Icons.travel_explore_rounded, - "travel_explore_outlined": Icons.travel_explore_outlined, - "trending_down": Icons.trending_down, - "trending_down_sharp": Icons.trending_down_sharp, - "trending_down_rounded": Icons.trending_down_rounded, - "trending_down_outlined": Icons.trending_down_outlined, - "trending_flat": Icons.trending_flat, - "trending_flat_sharp": Icons.trending_flat_sharp, - "trending_flat_rounded": Icons.trending_flat_rounded, - "trending_flat_outlined": Icons.trending_flat_outlined, - "trending_neutral": Icons.trending_neutral, - "trending_neutral_sharp": Icons.trending_neutral_sharp, - "trending_neutral_rounded": Icons.trending_neutral_rounded, - "trending_neutral_outlined": Icons.trending_neutral_outlined, - "trending_up": Icons.trending_up, - "trending_up_sharp": Icons.trending_up_sharp, - "trending_up_rounded": Icons.trending_up_rounded, - "trending_up_outlined": Icons.trending_up_outlined, - "trip_origin": Icons.trip_origin, - "trip_origin_sharp": Icons.trip_origin_sharp, - "trip_origin_rounded": Icons.trip_origin_rounded, - "trip_origin_outlined": Icons.trip_origin_outlined, - "trolley": Icons.trolley, - "troubleshoot": Icons.troubleshoot, - "troubleshoot_sharp": Icons.troubleshoot_sharp, - "troubleshoot_rounded": Icons.troubleshoot_rounded, - "troubleshoot_outlined": Icons.troubleshoot_outlined, - "try_sms_star": Icons.try_sms_star, - "try_sms_star_sharp": Icons.try_sms_star_sharp, - "try_sms_star_rounded": Icons.try_sms_star_rounded, - "try_sms_star_outlined": Icons.try_sms_star_outlined, - "tsunami": Icons.tsunami, - "tsunami_sharp": Icons.tsunami_sharp, - "tsunami_rounded": Icons.tsunami_rounded, - "tsunami_outlined": Icons.tsunami_outlined, - "tty": Icons.tty, - "tty_sharp": Icons.tty_sharp, - "tty_rounded": Icons.tty_rounded, - "tty_outlined": Icons.tty_outlined, - "tune": Icons.tune, - "tune_sharp": Icons.tune_sharp, - "tune_rounded": Icons.tune_rounded, - "tune_outlined": Icons.tune_outlined, - "tungsten": Icons.tungsten, - "tungsten_sharp": Icons.tungsten_sharp, - "tungsten_rounded": Icons.tungsten_rounded, - "tungsten_outlined": Icons.tungsten_outlined, - "turn_left": Icons.turn_left, - "turn_left_sharp": Icons.turn_left_sharp, - "turn_left_rounded": Icons.turn_left_rounded, - "turn_left_outlined": Icons.turn_left_outlined, - "turn_right": Icons.turn_right, - "turn_right_sharp": Icons.turn_right_sharp, - "turn_right_rounded": Icons.turn_right_rounded, - "turn_right_outlined": Icons.turn_right_outlined, - "turn_sharp_left": Icons.turn_sharp_left, - "turn_sharp_left_sharp": Icons.turn_sharp_left_sharp, - "turn_sharp_left_rounded": Icons.turn_sharp_left_rounded, - "turn_sharp_left_outlined": Icons.turn_sharp_left_outlined, - "turn_sharp_right": Icons.turn_sharp_right, - "turn_sharp_right_sharp": Icons.turn_sharp_right_sharp, - "turn_sharp_right_rounded": Icons.turn_sharp_right_rounded, - "turn_sharp_right_outlined": Icons.turn_sharp_right_outlined, - "turn_slight_left": Icons.turn_slight_left, - "turn_slight_left_sharp": Icons.turn_slight_left_sharp, - "turn_slight_left_rounded": Icons.turn_slight_left_rounded, - "turn_slight_left_outlined": Icons.turn_slight_left_outlined, - "turn_slight_right": Icons.turn_slight_right, - "turn_slight_right_sharp": Icons.turn_slight_right_sharp, - "turn_slight_right_rounded": Icons.turn_slight_right_rounded, - "turn_slight_right_outlined": Icons.turn_slight_right_outlined, - "turned_in": Icons.turned_in, - "turned_in_sharp": Icons.turned_in_sharp, - "turned_in_rounded": Icons.turned_in_rounded, - "turned_in_outlined": Icons.turned_in_outlined, - "turned_in_not": Icons.turned_in_not, - "turned_in_not_sharp": Icons.turned_in_not_sharp, - "turned_in_not_rounded": Icons.turned_in_not_rounded, - "turned_in_not_outlined": Icons.turned_in_not_outlined, - "tv": Icons.tv, - "tv_sharp": Icons.tv_sharp, - "tv_rounded": Icons.tv_rounded, - "tv_outlined": Icons.tv_outlined, - "tv_off": Icons.tv_off, - "tv_off_sharp": Icons.tv_off_sharp, - "tv_off_rounded": Icons.tv_off_rounded, - "tv_off_outlined": Icons.tv_off_outlined, - "two_wheeler": Icons.two_wheeler, - "two_wheeler_sharp": Icons.two_wheeler_sharp, - "two_wheeler_rounded": Icons.two_wheeler_rounded, - "two_wheeler_outlined": Icons.two_wheeler_outlined, - "type_specimen": Icons.type_specimen, - "type_specimen_sharp": Icons.type_specimen_sharp, - "type_specimen_rounded": Icons.type_specimen_rounded, - "type_specimen_outlined": Icons.type_specimen_outlined, - "u_turn_left": Icons.u_turn_left, - "u_turn_left_sharp": Icons.u_turn_left_sharp, - "u_turn_left_rounded": Icons.u_turn_left_rounded, - "u_turn_left_outlined": Icons.u_turn_left_outlined, - "u_turn_right": Icons.u_turn_right, - "u_turn_right_sharp": Icons.u_turn_right_sharp, - "u_turn_right_rounded": Icons.u_turn_right_rounded, - "u_turn_right_outlined": Icons.u_turn_right_outlined, - "umbrella": Icons.umbrella, - "umbrella_sharp": Icons.umbrella_sharp, - "umbrella_rounded": Icons.umbrella_rounded, - "umbrella_outlined": Icons.umbrella_outlined, - "unarchive": Icons.unarchive, - "unarchive_sharp": Icons.unarchive_sharp, - "unarchive_rounded": Icons.unarchive_rounded, - "unarchive_outlined": Icons.unarchive_outlined, - "undo": Icons.undo, - "undo_sharp": Icons.undo_sharp, - "undo_rounded": Icons.undo_rounded, - "undo_outlined": Icons.undo_outlined, - "unfold_less": Icons.unfold_less, - "unfold_less_sharp": Icons.unfold_less_sharp, - "unfold_less_rounded": Icons.unfold_less_rounded, - "unfold_less_outlined": Icons.unfold_less_outlined, - "unfold_less_double": Icons.unfold_less_double, - "unfold_less_double_sharp": Icons.unfold_less_double_sharp, - "unfold_less_double_rounded": Icons.unfold_less_double_rounded, - "unfold_less_double_outlined": Icons.unfold_less_double_outlined, - "unfold_more": Icons.unfold_more, - "unfold_more_sharp": Icons.unfold_more_sharp, - "unfold_more_rounded": Icons.unfold_more_rounded, - "unfold_more_outlined": Icons.unfold_more_outlined, - "unfold_more_double": Icons.unfold_more_double, - "unfold_more_double_sharp": Icons.unfold_more_double_sharp, - "unfold_more_double_rounded": Icons.unfold_more_double_rounded, - "unfold_more_double_outlined": Icons.unfold_more_double_outlined, - "unpublished": Icons.unpublished, - "unpublished_sharp": Icons.unpublished_sharp, - "unpublished_rounded": Icons.unpublished_rounded, - "unpublished_outlined": Icons.unpublished_outlined, - "unsubscribe": Icons.unsubscribe, - "unsubscribe_sharp": Icons.unsubscribe_sharp, - "unsubscribe_rounded": Icons.unsubscribe_rounded, - "unsubscribe_outlined": Icons.unsubscribe_outlined, - "upcoming": Icons.upcoming, - "upcoming_sharp": Icons.upcoming_sharp, - "upcoming_rounded": Icons.upcoming_rounded, - "upcoming_outlined": Icons.upcoming_outlined, - "update": Icons.update, - "update_sharp": Icons.update_sharp, - "update_rounded": Icons.update_rounded, - "update_outlined": Icons.update_outlined, - "update_disabled": Icons.update_disabled, - "update_disabled_sharp": Icons.update_disabled_sharp, - "update_disabled_rounded": Icons.update_disabled_rounded, - "update_disabled_outlined": Icons.update_disabled_outlined, - "upgrade": Icons.upgrade, - "upgrade_sharp": Icons.upgrade_sharp, - "upgrade_rounded": Icons.upgrade_rounded, - "upgrade_outlined": Icons.upgrade_outlined, - "upload": Icons.upload, - "upload_sharp": Icons.upload_sharp, - "upload_rounded": Icons.upload_rounded, - "upload_outlined": Icons.upload_outlined, - "upload_file": Icons.upload_file, - "upload_file_sharp": Icons.upload_file_sharp, - "upload_file_rounded": Icons.upload_file_rounded, - "upload_file_outlined": Icons.upload_file_outlined, - "usb": Icons.usb, - "usb_sharp": Icons.usb_sharp, - "usb_rounded": Icons.usb_rounded, - "usb_outlined": Icons.usb_outlined, - "usb_off": Icons.usb_off, - "usb_off_sharp": Icons.usb_off_sharp, - "usb_off_rounded": Icons.usb_off_rounded, - "usb_off_outlined": Icons.usb_off_outlined, - "vaccines": Icons.vaccines, - "vaccines_sharp": Icons.vaccines_sharp, - "vaccines_rounded": Icons.vaccines_rounded, - "vaccines_outlined": Icons.vaccines_outlined, - "vape_free": Icons.vape_free, - "vape_free_sharp": Icons.vape_free_sharp, - "vape_free_rounded": Icons.vape_free_rounded, - "vape_free_outlined": Icons.vape_free_outlined, - "vaping_rooms": Icons.vaping_rooms, - "vaping_rooms_sharp": Icons.vaping_rooms_sharp, - "vaping_rooms_rounded": Icons.vaping_rooms_rounded, - "vaping_rooms_outlined": Icons.vaping_rooms_outlined, - "verified": Icons.verified, - "verified_sharp": Icons.verified_sharp, - "verified_rounded": Icons.verified_rounded, - "verified_outlined": Icons.verified_outlined, - "verified_user": Icons.verified_user, - "verified_user_sharp": Icons.verified_user_sharp, - "verified_user_rounded": Icons.verified_user_rounded, - "verified_user_outlined": Icons.verified_user_outlined, - "vertical_align_bottom": Icons.vertical_align_bottom, - "vertical_align_bottom_sharp": Icons.vertical_align_bottom_sharp, - "vertical_align_bottom_rounded": Icons.vertical_align_bottom_rounded, - "vertical_align_bottom_outlined": Icons.vertical_align_bottom_outlined, - "vertical_align_center": Icons.vertical_align_center, - "vertical_align_center_sharp": Icons.vertical_align_center_sharp, - "vertical_align_center_rounded": Icons.vertical_align_center_rounded, - "vertical_align_center_outlined": Icons.vertical_align_center_outlined, - "vertical_align_top": Icons.vertical_align_top, - "vertical_align_top_sharp": Icons.vertical_align_top_sharp, - "vertical_align_top_rounded": Icons.vertical_align_top_rounded, - "vertical_align_top_outlined": Icons.vertical_align_top_outlined, - "vertical_distribute": Icons.vertical_distribute, - "vertical_distribute_sharp": Icons.vertical_distribute_sharp, - "vertical_distribute_rounded": Icons.vertical_distribute_rounded, - "vertical_distribute_outlined": Icons.vertical_distribute_outlined, - "vertical_shades": Icons.vertical_shades, - "vertical_shades_sharp": Icons.vertical_shades_sharp, - "vertical_shades_rounded": Icons.vertical_shades_rounded, - "vertical_shades_outlined": Icons.vertical_shades_outlined, - "vertical_shades_closed": Icons.vertical_shades_closed, - "vertical_shades_closed_sharp": Icons.vertical_shades_closed_sharp, - "vertical_shades_closed_rounded": Icons.vertical_shades_closed_rounded, - "vertical_shades_closed_outlined": Icons.vertical_shades_closed_outlined, - "vertical_split": Icons.vertical_split, - "vertical_split_sharp": Icons.vertical_split_sharp, - "vertical_split_rounded": Icons.vertical_split_rounded, - "vertical_split_outlined": Icons.vertical_split_outlined, - "vibration": Icons.vibration, - "vibration_sharp": Icons.vibration_sharp, - "vibration_rounded": Icons.vibration_rounded, - "vibration_outlined": Icons.vibration_outlined, - "video_call": Icons.video_call, - "video_call_sharp": Icons.video_call_sharp, - "video_call_rounded": Icons.video_call_rounded, - "video_call_outlined": Icons.video_call_outlined, - "video_camera_back": Icons.video_camera_back, - "video_camera_back_sharp": Icons.video_camera_back_sharp, - "video_camera_back_rounded": Icons.video_camera_back_rounded, - "video_camera_back_outlined": Icons.video_camera_back_outlined, - "video_camera_front": Icons.video_camera_front, - "video_camera_front_sharp": Icons.video_camera_front_sharp, - "video_camera_front_rounded": Icons.video_camera_front_rounded, - "video_camera_front_outlined": Icons.video_camera_front_outlined, - "video_chat": Icons.video_chat, - "video_chat_sharp": Icons.video_chat_sharp, - "video_chat_rounded": Icons.video_chat_rounded, - "video_chat_outlined": Icons.video_chat_outlined, - "video_collection": Icons.video_collection, - "video_collection_sharp": Icons.video_collection_sharp, - "video_collection_rounded": Icons.video_collection_rounded, - "video_collection_outlined": Icons.video_collection_outlined, - "video_file": Icons.video_file, - "video_file_sharp": Icons.video_file_sharp, - "video_file_rounded": Icons.video_file_rounded, - "video_file_outlined": Icons.video_file_outlined, - "video_label": Icons.video_label, - "video_label_sharp": Icons.video_label_sharp, - "video_label_rounded": Icons.video_label_rounded, - "video_label_outlined": Icons.video_label_outlined, - "video_library": Icons.video_library, - "video_library_sharp": Icons.video_library_sharp, - "video_library_rounded": Icons.video_library_rounded, - "video_library_outlined": Icons.video_library_outlined, - "video_settings": Icons.video_settings, - "video_settings_sharp": Icons.video_settings_sharp, - "video_settings_rounded": Icons.video_settings_rounded, - "video_settings_outlined": Icons.video_settings_outlined, - "video_stable": Icons.video_stable, - "video_stable_sharp": Icons.video_stable_sharp, - "video_stable_rounded": Icons.video_stable_rounded, - "video_stable_outlined": Icons.video_stable_outlined, - "videocam": Icons.videocam, - "videocam_sharp": Icons.videocam_sharp, - "videocam_rounded": Icons.videocam_rounded, - "videocam_outlined": Icons.videocam_outlined, - "videocam_off": Icons.videocam_off, - "videocam_off_sharp": Icons.videocam_off_sharp, - "videocam_off_rounded": Icons.videocam_off_rounded, - "videocam_off_outlined": Icons.videocam_off_outlined, - "videogame_asset": Icons.videogame_asset, - "videogame_asset_sharp": Icons.videogame_asset_sharp, - "videogame_asset_rounded": Icons.videogame_asset_rounded, - "videogame_asset_outlined": Icons.videogame_asset_outlined, - "videogame_asset_off": Icons.videogame_asset_off, - "videogame_asset_off_sharp": Icons.videogame_asset_off_sharp, - "videogame_asset_off_rounded": Icons.videogame_asset_off_rounded, - "videogame_asset_off_outlined": Icons.videogame_asset_off_outlined, - "view_agenda": Icons.view_agenda, - "view_agenda_sharp": Icons.view_agenda_sharp, - "view_agenda_rounded": Icons.view_agenda_rounded, - "view_agenda_outlined": Icons.view_agenda_outlined, - "view_array": Icons.view_array, - "view_array_sharp": Icons.view_array_sharp, - "view_array_rounded": Icons.view_array_rounded, - "view_array_outlined": Icons.view_array_outlined, - "view_carousel": Icons.view_carousel, - "view_carousel_sharp": Icons.view_carousel_sharp, - "view_carousel_rounded": Icons.view_carousel_rounded, - "view_carousel_outlined": Icons.view_carousel_outlined, - "view_column": Icons.view_column, - "view_column_sharp": Icons.view_column_sharp, - "view_column_rounded": Icons.view_column_rounded, - "view_column_outlined": Icons.view_column_outlined, - "view_comfortable": Icons.view_comfortable, - "view_comfortable_sharp": Icons.view_comfortable_sharp, - "view_comfortable_rounded": Icons.view_comfortable_rounded, - "view_comfortable_outlined": Icons.view_comfortable_outlined, - "view_comfy": Icons.view_comfy, - "view_comfy_sharp": Icons.view_comfy_sharp, - "view_comfy_rounded": Icons.view_comfy_rounded, - "view_comfy_outlined": Icons.view_comfy_outlined, - "view_comfy_alt": Icons.view_comfy_alt, - "view_comfy_alt_sharp": Icons.view_comfy_alt_sharp, - "view_comfy_alt_rounded": Icons.view_comfy_alt_rounded, - "view_comfy_alt_outlined": Icons.view_comfy_alt_outlined, - "view_compact": Icons.view_compact, - "view_compact_sharp": Icons.view_compact_sharp, - "view_compact_rounded": Icons.view_compact_rounded, - "view_compact_outlined": Icons.view_compact_outlined, - "view_compact_alt": Icons.view_compact_alt, - "view_compact_alt_sharp": Icons.view_compact_alt_sharp, - "view_compact_alt_rounded": Icons.view_compact_alt_rounded, - "view_compact_alt_outlined": Icons.view_compact_alt_outlined, - "view_cozy": Icons.view_cozy, - "view_cozy_sharp": Icons.view_cozy_sharp, - "view_cozy_rounded": Icons.view_cozy_rounded, - "view_cozy_outlined": Icons.view_cozy_outlined, - "view_day": Icons.view_day, - "view_day_sharp": Icons.view_day_sharp, - "view_day_rounded": Icons.view_day_rounded, - "view_day_outlined": Icons.view_day_outlined, - "view_headline": Icons.view_headline, - "view_headline_sharp": Icons.view_headline_sharp, - "view_headline_rounded": Icons.view_headline_rounded, - "view_headline_outlined": Icons.view_headline_outlined, - "view_in_ar": Icons.view_in_ar, - "view_in_ar_sharp": Icons.view_in_ar_sharp, - "view_in_ar_rounded": Icons.view_in_ar_rounded, - "view_in_ar_outlined": Icons.view_in_ar_outlined, - "view_kanban": Icons.view_kanban, - "view_kanban_sharp": Icons.view_kanban_sharp, - "view_kanban_rounded": Icons.view_kanban_rounded, - "view_kanban_outlined": Icons.view_kanban_outlined, - "view_list": Icons.view_list, - "view_list_sharp": Icons.view_list_sharp, - "view_list_rounded": Icons.view_list_rounded, - "view_list_outlined": Icons.view_list_outlined, - "view_module": Icons.view_module, - "view_module_sharp": Icons.view_module_sharp, - "view_module_rounded": Icons.view_module_rounded, - "view_module_outlined": Icons.view_module_outlined, - "view_quilt": Icons.view_quilt, - "view_quilt_sharp": Icons.view_quilt_sharp, - "view_quilt_rounded": Icons.view_quilt_rounded, - "view_quilt_outlined": Icons.view_quilt_outlined, - "view_sidebar": Icons.view_sidebar, - "view_sidebar_sharp": Icons.view_sidebar_sharp, - "view_sidebar_rounded": Icons.view_sidebar_rounded, - "view_sidebar_outlined": Icons.view_sidebar_outlined, - "view_stream": Icons.view_stream, - "view_stream_sharp": Icons.view_stream_sharp, - "view_stream_rounded": Icons.view_stream_rounded, - "view_stream_outlined": Icons.view_stream_outlined, - "view_timeline": Icons.view_timeline, - "view_timeline_sharp": Icons.view_timeline_sharp, - "view_timeline_rounded": Icons.view_timeline_rounded, - "view_timeline_outlined": Icons.view_timeline_outlined, - "view_week": Icons.view_week, - "view_week_sharp": Icons.view_week_sharp, - "view_week_rounded": Icons.view_week_rounded, - "view_week_outlined": Icons.view_week_outlined, - "vignette": Icons.vignette, - "vignette_sharp": Icons.vignette_sharp, - "vignette_rounded": Icons.vignette_rounded, - "vignette_outlined": Icons.vignette_outlined, - "villa": Icons.villa, - "villa_sharp": Icons.villa_sharp, - "villa_rounded": Icons.villa_rounded, - "villa_outlined": Icons.villa_outlined, - "visibility": Icons.visibility, - "visibility_sharp": Icons.visibility_sharp, - "visibility_rounded": Icons.visibility_rounded, - "visibility_outlined": Icons.visibility_outlined, - "visibility_off": Icons.visibility_off, - "visibility_off_sharp": Icons.visibility_off_sharp, - "visibility_off_rounded": Icons.visibility_off_rounded, - "visibility_off_outlined": Icons.visibility_off_outlined, - "voice_chat": Icons.voice_chat, - "voice_chat_sharp": Icons.voice_chat_sharp, - "voice_chat_rounded": Icons.voice_chat_rounded, - "voice_chat_outlined": Icons.voice_chat_outlined, - "voice_over_off": Icons.voice_over_off, - "voice_over_off_sharp": Icons.voice_over_off_sharp, - "voice_over_off_rounded": Icons.voice_over_off_rounded, - "voice_over_off_outlined": Icons.voice_over_off_outlined, - "voicemail": Icons.voicemail, - "voicemail_sharp": Icons.voicemail_sharp, - "voicemail_rounded": Icons.voicemail_rounded, - "voicemail_outlined": Icons.voicemail_outlined, - "volcano": Icons.volcano, - "volcano_sharp": Icons.volcano_sharp, - "volcano_rounded": Icons.volcano_rounded, - "volcano_outlined": Icons.volcano_outlined, - "volume_down": Icons.volume_down, - "volume_down_sharp": Icons.volume_down_sharp, - "volume_down_rounded": Icons.volume_down_rounded, - "volume_down_outlined": Icons.volume_down_outlined, - "volume_down_alt": Icons.volume_down_alt, - "volume_mute": Icons.volume_mute, - "volume_mute_sharp": Icons.volume_mute_sharp, - "volume_mute_rounded": Icons.volume_mute_rounded, - "volume_mute_outlined": Icons.volume_mute_outlined, - "volume_off": Icons.volume_off, - "volume_off_sharp": Icons.volume_off_sharp, - "volume_off_rounded": Icons.volume_off_rounded, - "volume_off_outlined": Icons.volume_off_outlined, - "volume_up": Icons.volume_up, - "volume_up_sharp": Icons.volume_up_sharp, - "volume_up_rounded": Icons.volume_up_rounded, - "volume_up_outlined": Icons.volume_up_outlined, - "volunteer_activism": Icons.volunteer_activism, - "volunteer_activism_sharp": Icons.volunteer_activism_sharp, - "volunteer_activism_rounded": Icons.volunteer_activism_rounded, - "volunteer_activism_outlined": Icons.volunteer_activism_outlined, - "vpn_key": Icons.vpn_key, - "vpn_key_sharp": Icons.vpn_key_sharp, - "vpn_key_rounded": Icons.vpn_key_rounded, - "vpn_key_outlined": Icons.vpn_key_outlined, - "vpn_key_off": Icons.vpn_key_off, - "vpn_key_off_sharp": Icons.vpn_key_off_sharp, - "vpn_key_off_rounded": Icons.vpn_key_off_rounded, - "vpn_key_off_outlined": Icons.vpn_key_off_outlined, - "vpn_lock": Icons.vpn_lock, - "vpn_lock_sharp": Icons.vpn_lock_sharp, - "vpn_lock_rounded": Icons.vpn_lock_rounded, - "vpn_lock_outlined": Icons.vpn_lock_outlined, - "vrpano": Icons.vrpano, - "vrpano_sharp": Icons.vrpano_sharp, - "vrpano_rounded": Icons.vrpano_rounded, - "vrpano_outlined": Icons.vrpano_outlined, - "wallet": Icons.wallet, - "wallet_sharp": Icons.wallet_sharp, - "wallet_rounded": Icons.wallet_rounded, - "wallet_outlined": Icons.wallet_outlined, - "wallet_giftcard": Icons.wallet_giftcard, - "wallet_giftcard_sharp": Icons.wallet_giftcard_sharp, - "wallet_giftcard_rounded": Icons.wallet_giftcard_rounded, - "wallet_giftcard_outlined": Icons.wallet_giftcard_outlined, - "wallet_membership": Icons.wallet_membership, - "wallet_membership_sharp": Icons.wallet_membership_sharp, - "wallet_membership_rounded": Icons.wallet_membership_rounded, - "wallet_membership_outlined": Icons.wallet_membership_outlined, - "wallet_travel": Icons.wallet_travel, - "wallet_travel_sharp": Icons.wallet_travel_sharp, - "wallet_travel_rounded": Icons.wallet_travel_rounded, - "wallet_travel_outlined": Icons.wallet_travel_outlined, - "wallpaper": Icons.wallpaper, - "wallpaper_sharp": Icons.wallpaper_sharp, - "wallpaper_rounded": Icons.wallpaper_rounded, - "wallpaper_outlined": Icons.wallpaper_outlined, - "warehouse": Icons.warehouse, - "warehouse_sharp": Icons.warehouse_sharp, - "warehouse_rounded": Icons.warehouse_rounded, - "warehouse_outlined": Icons.warehouse_outlined, - "warning": Icons.warning, - "warning_sharp": Icons.warning_sharp, - "warning_rounded": Icons.warning_rounded, - "warning_outlined": Icons.warning_outlined, - "warning_amber": Icons.warning_amber, - "warning_amber_sharp": Icons.warning_amber_sharp, - "warning_amber_rounded": Icons.warning_amber_rounded, - "warning_amber_outlined": Icons.warning_amber_outlined, - "wash": Icons.wash, - "wash_sharp": Icons.wash_sharp, - "wash_rounded": Icons.wash_rounded, - "wash_outlined": Icons.wash_outlined, - "watch": Icons.watch, - "watch_sharp": Icons.watch_sharp, - "watch_rounded": Icons.watch_rounded, - "watch_outlined": Icons.watch_outlined, - "watch_later": Icons.watch_later, - "watch_later_sharp": Icons.watch_later_sharp, - "watch_later_rounded": Icons.watch_later_rounded, - "watch_later_outlined": Icons.watch_later_outlined, - "watch_off": Icons.watch_off, - "watch_off_sharp": Icons.watch_off_sharp, - "watch_off_rounded": Icons.watch_off_rounded, - "watch_off_outlined": Icons.watch_off_outlined, - "water": Icons.water, - "water_sharp": Icons.water_sharp, - "water_rounded": Icons.water_rounded, - "water_outlined": Icons.water_outlined, - "water_damage": Icons.water_damage, - "water_damage_sharp": Icons.water_damage_sharp, - "water_damage_rounded": Icons.water_damage_rounded, - "water_damage_outlined": Icons.water_damage_outlined, - "water_drop": Icons.water_drop, - "water_drop_sharp": Icons.water_drop_sharp, - "water_drop_rounded": Icons.water_drop_rounded, - "water_drop_outlined": Icons.water_drop_outlined, - "waterfall_chart": Icons.waterfall_chart, - "waterfall_chart_sharp": Icons.waterfall_chart_sharp, - "waterfall_chart_rounded": Icons.waterfall_chart_rounded, - "waterfall_chart_outlined": Icons.waterfall_chart_outlined, - "waves": Icons.waves, - "waves_sharp": Icons.waves_sharp, - "waves_rounded": Icons.waves_rounded, - "waves_outlined": Icons.waves_outlined, - "waving_hand": Icons.waving_hand, - "waving_hand_sharp": Icons.waving_hand_sharp, - "waving_hand_rounded": Icons.waving_hand_rounded, - "waving_hand_outlined": Icons.waving_hand_outlined, - "wb_auto": Icons.wb_auto, - "wb_auto_sharp": Icons.wb_auto_sharp, - "wb_auto_rounded": Icons.wb_auto_rounded, - "wb_auto_outlined": Icons.wb_auto_outlined, - "wb_cloudy": Icons.wb_cloudy, - "wb_cloudy_sharp": Icons.wb_cloudy_sharp, - "wb_cloudy_rounded": Icons.wb_cloudy_rounded, - "wb_cloudy_outlined": Icons.wb_cloudy_outlined, - "wb_incandescent": Icons.wb_incandescent, - "wb_incandescent_sharp": Icons.wb_incandescent_sharp, - "wb_incandescent_rounded": Icons.wb_incandescent_rounded, - "wb_incandescent_outlined": Icons.wb_incandescent_outlined, - "wb_iridescent": Icons.wb_iridescent, - "wb_iridescent_sharp": Icons.wb_iridescent_sharp, - "wb_iridescent_rounded": Icons.wb_iridescent_rounded, - "wb_iridescent_outlined": Icons.wb_iridescent_outlined, - "wb_shade": Icons.wb_shade, - "wb_shade_sharp": Icons.wb_shade_sharp, - "wb_shade_rounded": Icons.wb_shade_rounded, - "wb_shade_outlined": Icons.wb_shade_outlined, - "wb_sunny": Icons.wb_sunny, - "wb_sunny_sharp": Icons.wb_sunny_sharp, - "wb_sunny_rounded": Icons.wb_sunny_rounded, - "wb_sunny_outlined": Icons.wb_sunny_outlined, - "wb_twighlight": Icons.wb_twighlight, - "wb_twilight": Icons.wb_twilight, - "wb_twilight_sharp": Icons.wb_twilight_sharp, - "wb_twilight_rounded": Icons.wb_twilight_rounded, - "wb_twilight_outlined": Icons.wb_twilight_outlined, - "wc": Icons.wc, - "wc_sharp": Icons.wc_sharp, - "wc_rounded": Icons.wc_rounded, - "wc_outlined": Icons.wc_outlined, - "web": Icons.web, - "web_sharp": Icons.web_sharp, - "web_rounded": Icons.web_rounded, - "web_outlined": Icons.web_outlined, - "web_asset": Icons.web_asset, - "web_asset_sharp": Icons.web_asset_sharp, - "web_asset_rounded": Icons.web_asset_rounded, - "web_asset_outlined": Icons.web_asset_outlined, - "web_asset_off": Icons.web_asset_off, - "web_asset_off_sharp": Icons.web_asset_off_sharp, - "web_asset_off_rounded": Icons.web_asset_off_rounded, - "web_asset_off_outlined": Icons.web_asset_off_outlined, - "web_stories": Icons.web_stories, - "web_stories_sharp": Icons.web_stories_sharp, - "web_stories_rounded": Icons.web_stories_rounded, - "web_stories_outlined": Icons.web_stories_outlined, - "webhook": Icons.webhook, - "webhook_sharp": Icons.webhook_sharp, - "webhook_rounded": Icons.webhook_rounded, - "webhook_outlined": Icons.webhook_outlined, - "wechat": Icons.wechat, - "wechat_sharp": Icons.wechat_sharp, - "wechat_rounded": Icons.wechat_rounded, - "wechat_outlined": Icons.wechat_outlined, - "weekend": Icons.weekend, - "weekend_sharp": Icons.weekend_sharp, - "weekend_rounded": Icons.weekend_rounded, - "weekend_outlined": Icons.weekend_outlined, - "west": Icons.west, - "west_sharp": Icons.west_sharp, - "west_rounded": Icons.west_rounded, - "west_outlined": Icons.west_outlined, - "whatshot": Icons.whatshot, - "whatshot_sharp": Icons.whatshot_sharp, - "whatshot_rounded": Icons.whatshot_rounded, - "whatshot_outlined": Icons.whatshot_outlined, - "wheelchair_pickup": Icons.wheelchair_pickup, - "wheelchair_pickup_sharp": Icons.wheelchair_pickup_sharp, - "wheelchair_pickup_rounded": Icons.wheelchair_pickup_rounded, - "wheelchair_pickup_outlined": Icons.wheelchair_pickup_outlined, - "where_to_vote": Icons.where_to_vote, - "where_to_vote_sharp": Icons.where_to_vote_sharp, - "where_to_vote_rounded": Icons.where_to_vote_rounded, - "where_to_vote_outlined": Icons.where_to_vote_outlined, - "widgets": Icons.widgets, - "widgets_sharp": Icons.widgets_sharp, - "widgets_rounded": Icons.widgets_rounded, - "widgets_outlined": Icons.widgets_outlined, - "width_full": Icons.width_full, - "width_full_sharp": Icons.width_full_sharp, - "width_full_rounded": Icons.width_full_rounded, - "width_full_outlined": Icons.width_full_outlined, - "width_normal": Icons.width_normal, - "width_normal_sharp": Icons.width_normal_sharp, - "width_normal_rounded": Icons.width_normal_rounded, - "width_normal_outlined": Icons.width_normal_outlined, - "width_wide": Icons.width_wide, - "width_wide_sharp": Icons.width_wide_sharp, - "width_wide_rounded": Icons.width_wide_rounded, - "width_wide_outlined": Icons.width_wide_outlined, - "wifi": Icons.wifi, - "wifi_sharp": Icons.wifi_sharp, - "wifi_rounded": Icons.wifi_rounded, - "wifi_outlined": Icons.wifi_outlined, - "wifi_1_bar": Icons.wifi_1_bar, - "wifi_1_bar_sharp": Icons.wifi_1_bar_sharp, - "wifi_1_bar_rounded": Icons.wifi_1_bar_rounded, - "wifi_1_bar_outlined": Icons.wifi_1_bar_outlined, - "wifi_2_bar": Icons.wifi_2_bar, - "wifi_2_bar_sharp": Icons.wifi_2_bar_sharp, - "wifi_2_bar_rounded": Icons.wifi_2_bar_rounded, - "wifi_2_bar_outlined": Icons.wifi_2_bar_outlined, - "wifi_calling": Icons.wifi_calling, - "wifi_calling_sharp": Icons.wifi_calling_sharp, - "wifi_calling_rounded": Icons.wifi_calling_rounded, - "wifi_calling_outlined": Icons.wifi_calling_outlined, - "wifi_calling_3": Icons.wifi_calling_3, - "wifi_calling_3_sharp": Icons.wifi_calling_3_sharp, - "wifi_calling_3_rounded": Icons.wifi_calling_3_rounded, - "wifi_calling_3_outlined": Icons.wifi_calling_3_outlined, - "wifi_channel": Icons.wifi_channel, - "wifi_channel_sharp": Icons.wifi_channel_sharp, - "wifi_channel_rounded": Icons.wifi_channel_rounded, - "wifi_channel_outlined": Icons.wifi_channel_outlined, - "wifi_find": Icons.wifi_find, - "wifi_find_sharp": Icons.wifi_find_sharp, - "wifi_find_rounded": Icons.wifi_find_rounded, - "wifi_find_outlined": Icons.wifi_find_outlined, - "wifi_lock": Icons.wifi_lock, - "wifi_lock_sharp": Icons.wifi_lock_sharp, - "wifi_lock_rounded": Icons.wifi_lock_rounded, - "wifi_lock_outlined": Icons.wifi_lock_outlined, - "wifi_off": Icons.wifi_off, - "wifi_off_sharp": Icons.wifi_off_sharp, - "wifi_off_rounded": Icons.wifi_off_rounded, - "wifi_off_outlined": Icons.wifi_off_outlined, - "wifi_password": Icons.wifi_password, - "wifi_password_sharp": Icons.wifi_password_sharp, - "wifi_password_rounded": Icons.wifi_password_rounded, - "wifi_password_outlined": Icons.wifi_password_outlined, - "wifi_protected_setup": Icons.wifi_protected_setup, - "wifi_protected_setup_sharp": Icons.wifi_protected_setup_sharp, - "wifi_protected_setup_rounded": Icons.wifi_protected_setup_rounded, - "wifi_protected_setup_outlined": Icons.wifi_protected_setup_outlined, - "wifi_tethering": Icons.wifi_tethering, - "wifi_tethering_sharp": Icons.wifi_tethering_sharp, - "wifi_tethering_rounded": Icons.wifi_tethering_rounded, - "wifi_tethering_outlined": Icons.wifi_tethering_outlined, - "wifi_tethering_error": Icons.wifi_tethering_error, - "wifi_tethering_error_sharp": Icons.wifi_tethering_error_sharp, - "wifi_tethering_error_rounded": Icons.wifi_tethering_error_rounded, - "wifi_tethering_error_outlined": Icons.wifi_tethering_error_outlined, - "wifi_tethering_error_rounded_sharp": - Icons.wifi_tethering_error_rounded_sharp, - "wifi_tethering_error_rounded_rounded": - Icons.wifi_tethering_error_rounded_rounded, - "wifi_tethering_error_rounded_outlined": - Icons.wifi_tethering_error_rounded_outlined, - "wifi_tethering_off": Icons.wifi_tethering_off, - "wifi_tethering_off_sharp": Icons.wifi_tethering_off_sharp, - "wifi_tethering_off_rounded": Icons.wifi_tethering_off_rounded, - "wifi_tethering_off_outlined": Icons.wifi_tethering_off_outlined, - "wind_power": Icons.wind_power, - "wind_power_sharp": Icons.wind_power_sharp, - "wind_power_rounded": Icons.wind_power_rounded, - "wind_power_outlined": Icons.wind_power_outlined, - "window": Icons.window, - "window_sharp": Icons.window_sharp, - "window_rounded": Icons.window_rounded, - "window_outlined": Icons.window_outlined, - "wine_bar": Icons.wine_bar, - "wine_bar_sharp": Icons.wine_bar_sharp, - "wine_bar_rounded": Icons.wine_bar_rounded, - "wine_bar_outlined": Icons.wine_bar_outlined, - "woman": Icons.woman, - "woman_sharp": Icons.woman_sharp, - "woman_rounded": Icons.woman_rounded, - "woman_outlined": Icons.woman_outlined, - "woman_2": Icons.woman_2, - "woman_2_sharp": Icons.woman_2_sharp, - "woman_2_rounded": Icons.woman_2_rounded, - "woman_2_outlined": Icons.woman_2_outlined, - "woo_commerce": Icons.woo_commerce, - "woo_commerce_sharp": Icons.woo_commerce_sharp, - "woo_commerce_rounded": Icons.woo_commerce_rounded, - "woo_commerce_outlined": Icons.woo_commerce_outlined, - "wordpress": Icons.wordpress, - "wordpress_sharp": Icons.wordpress_sharp, - "wordpress_rounded": Icons.wordpress_rounded, - "wordpress_outlined": Icons.wordpress_outlined, - "work": Icons.work, - "work_sharp": Icons.work_sharp, - "work_rounded": Icons.work_rounded, - "work_outlined": Icons.work_outlined, - "work_history": Icons.work_history, - "work_history_sharp": Icons.work_history_sharp, - "work_history_rounded": Icons.work_history_rounded, - "work_history_outlined": Icons.work_history_outlined, - "work_off": Icons.work_off, - "work_off_sharp": Icons.work_off_sharp, - "work_off_rounded": Icons.work_off_rounded, - "work_off_outlined": Icons.work_off_outlined, - "work_outline": Icons.work_outline, - "work_outline_sharp": Icons.work_outline_sharp, - "work_outline_rounded": Icons.work_outline_rounded, - "work_outline_outlined": Icons.work_outline_outlined, - "workspace_premium": Icons.workspace_premium, - "workspace_premium_sharp": Icons.workspace_premium_sharp, - "workspace_premium_rounded": Icons.workspace_premium_rounded, - "workspace_premium_outlined": Icons.workspace_premium_outlined, - "workspaces": Icons.workspaces, - "workspaces_sharp": Icons.workspaces_sharp, - "workspaces_rounded": Icons.workspaces_rounded, - "workspaces_outlined": Icons.workspaces_outlined, - "workspaces_filled": Icons.workspaces_filled, - "workspaces_outline": Icons.workspaces_outline, - "wrap_text": Icons.wrap_text, - "wrap_text_sharp": Icons.wrap_text_sharp, - "wrap_text_rounded": Icons.wrap_text_rounded, - "wrap_text_outlined": Icons.wrap_text_outlined, - "wrong_location": Icons.wrong_location, - "wrong_location_sharp": Icons.wrong_location_sharp, - "wrong_location_rounded": Icons.wrong_location_rounded, - "wrong_location_outlined": Icons.wrong_location_outlined, - "wysiwyg": Icons.wysiwyg, - "wysiwyg_sharp": Icons.wysiwyg_sharp, - "wysiwyg_rounded": Icons.wysiwyg_rounded, - "wysiwyg_outlined": Icons.wysiwyg_outlined, - "yard": Icons.yard, - "yard_sharp": Icons.yard_sharp, - "yard_rounded": Icons.yard_rounded, - "yard_outlined": Icons.yard_outlined, - "youtube_searched_for": Icons.youtube_searched_for, - "youtube_searched_for_sharp": Icons.youtube_searched_for_sharp, - "youtube_searched_for_rounded": Icons.youtube_searched_for_rounded, - "youtube_searched_for_outlined": Icons.youtube_searched_for_outlined, - "zoom_in": Icons.zoom_in, - "zoom_in_sharp": Icons.zoom_in_sharp, - "zoom_in_rounded": Icons.zoom_in_rounded, - "zoom_in_outlined": Icons.zoom_in_outlined, - "zoom_in_map": Icons.zoom_in_map, - "zoom_in_map_sharp": Icons.zoom_in_map_sharp, - "zoom_in_map_rounded": Icons.zoom_in_map_rounded, - "zoom_in_map_outlined": Icons.zoom_in_map_outlined, - "zoom_out": Icons.zoom_out, - "zoom_out_sharp": Icons.zoom_out_sharp, - "zoom_out_rounded": Icons.zoom_out_rounded, - "zoom_out_outlined": Icons.zoom_out_outlined, - "zoom_out_map": Icons.zoom_out_map, - "zoom_out_map_sharp": Icons.zoom_out_map_sharp, - "zoom_out_map_rounded": Icons.zoom_out_map_rounded, - "zoom_out_map_outlined": Icons.zoom_out_map_outlined, -}; +List materialIcons = [ + Icons.abc, + Icons.abc_outlined, + Icons.abc_rounded, + Icons.abc_sharp, + Icons.ac_unit, + Icons.ac_unit_outlined, + Icons.ac_unit_rounded, + Icons.ac_unit_sharp, + Icons.access_alarm, + Icons.access_alarm_outlined, + Icons.access_alarm_rounded, + Icons.access_alarm_sharp, + Icons.access_alarms, + Icons.access_alarms_outlined, + Icons.access_alarms_rounded, + Icons.access_alarms_sharp, + Icons.access_time, + Icons.access_time_filled, + Icons.access_time_filled_outlined, + Icons.access_time_filled_rounded, + Icons.access_time_filled_sharp, + Icons.access_time_outlined, + Icons.access_time_rounded, + Icons.access_time_sharp, + Icons.accessibility, + Icons.accessibility_new, + Icons.accessibility_new_outlined, + Icons.accessibility_new_rounded, + Icons.accessibility_new_sharp, + Icons.accessibility_outlined, + Icons.accessibility_rounded, + Icons.accessibility_sharp, + Icons.accessible, + Icons.accessible_forward, + Icons.accessible_forward_outlined, + Icons.accessible_forward_rounded, + Icons.accessible_forward_sharp, + Icons.accessible_outlined, + Icons.accessible_rounded, + Icons.accessible_sharp, + Icons.account_balance, + Icons.account_balance_outlined, + Icons.account_balance_rounded, + Icons.account_balance_sharp, + Icons.account_balance_wallet, + Icons.account_balance_wallet_outlined, + Icons.account_balance_wallet_rounded, + Icons.account_balance_wallet_sharp, + Icons.account_box, + Icons.account_box_outlined, + Icons.account_box_rounded, + Icons.account_box_sharp, + Icons.account_circle, + Icons.account_circle_outlined, + Icons.account_circle_rounded, + Icons.account_circle_sharp, + Icons.account_tree, + Icons.account_tree_outlined, + Icons.account_tree_rounded, + Icons.account_tree_sharp, + Icons.ad_units, + Icons.ad_units_outlined, + Icons.ad_units_rounded, + Icons.ad_units_sharp, + Icons.adb, + Icons.adb_outlined, + Icons.adb_rounded, + Icons.adb_sharp, + Icons.add, + Icons.add_a_photo, + Icons.add_a_photo_outlined, + Icons.add_a_photo_rounded, + Icons.add_a_photo_sharp, + Icons.add_alarm, + Icons.add_alarm_outlined, + Icons.add_alarm_rounded, + Icons.add_alarm_sharp, + Icons.add_alert, + Icons.add_alert_outlined, + Icons.add_alert_rounded, + Icons.add_alert_sharp, + Icons.add_box, + Icons.add_box_outlined, + Icons.add_box_rounded, + Icons.add_box_sharp, + Icons.add_business, + Icons.add_business_outlined, + Icons.add_business_rounded, + Icons.add_business_sharp, + Icons.add_call, + Icons.add_card, + Icons.add_card_outlined, + Icons.add_card_rounded, + Icons.add_card_sharp, + Icons.add_chart, + Icons.add_chart_outlined, + Icons.add_chart_rounded, + Icons.add_chart_sharp, + Icons.add_circle, + Icons.add_circle_outline, + Icons.add_circle_outline_outlined, + Icons.add_circle_outline_rounded, + Icons.add_circle_outline_sharp, + Icons.add_circle_outlined, + Icons.add_circle_rounded, + Icons.add_circle_sharp, + Icons.add_comment, + Icons.add_comment_outlined, + Icons.add_comment_rounded, + Icons.add_comment_sharp, + Icons.add_home, + Icons.add_home_outlined, + Icons.add_home_rounded, + Icons.add_home_sharp, + Icons.add_home_work, + Icons.add_home_work_outlined, + Icons.add_home_work_rounded, + Icons.add_home_work_sharp, + Icons.add_ic_call, + Icons.add_ic_call_outlined, + Icons.add_ic_call_rounded, + Icons.add_ic_call_sharp, + Icons.add_link, + Icons.add_link_outlined, + Icons.add_link_rounded, + Icons.add_link_sharp, + Icons.add_location, + Icons.add_location_alt, + Icons.add_location_alt_outlined, + Icons.add_location_alt_rounded, + Icons.add_location_alt_sharp, + Icons.add_location_outlined, + Icons.add_location_rounded, + Icons.add_location_sharp, + Icons.add_moderator, + Icons.add_moderator_outlined, + Icons.add_moderator_rounded, + Icons.add_moderator_sharp, + Icons.add_outlined, + Icons.add_photo_alternate, + Icons.add_photo_alternate_outlined, + Icons.add_photo_alternate_rounded, + Icons.add_photo_alternate_sharp, + Icons.add_reaction, + Icons.add_reaction_outlined, + Icons.add_reaction_rounded, + Icons.add_reaction_sharp, + Icons.add_road, + Icons.add_road_outlined, + Icons.add_road_rounded, + Icons.add_road_sharp, + Icons.add_rounded, + Icons.add_sharp, + Icons.add_shopping_cart, + Icons.add_shopping_cart_outlined, + Icons.add_shopping_cart_rounded, + Icons.add_shopping_cart_sharp, + Icons.add_task, + Icons.add_task_outlined, + Icons.add_task_rounded, + Icons.add_task_sharp, + Icons.add_to_drive, + Icons.add_to_drive_outlined, + Icons.add_to_drive_rounded, + Icons.add_to_drive_sharp, + Icons.add_to_home_screen, + Icons.add_to_home_screen_outlined, + Icons.add_to_home_screen_rounded, + Icons.add_to_home_screen_sharp, + Icons.add_to_photos, + Icons.add_to_photos_outlined, + Icons.add_to_photos_rounded, + Icons.add_to_photos_sharp, + Icons.add_to_queue, + Icons.add_to_queue_outlined, + Icons.add_to_queue_rounded, + Icons.add_to_queue_sharp, + Icons.addchart, + Icons.addchart_outlined, + Icons.addchart_rounded, + Icons.addchart_sharp, + Icons.adf_scanner, + Icons.adf_scanner_outlined, + Icons.adf_scanner_rounded, + Icons.adf_scanner_sharp, + Icons.adjust, + Icons.adjust_outlined, + Icons.adjust_rounded, + Icons.adjust_sharp, + Icons.admin_panel_settings, + Icons.admin_panel_settings_outlined, + Icons.admin_panel_settings_rounded, + Icons.admin_panel_settings_sharp, + Icons.adobe, + Icons.adobe_outlined, + Icons.adobe_rounded, + Icons.adobe_sharp, + Icons.ads_click, + Icons.ads_click_outlined, + Icons.ads_click_rounded, + Icons.ads_click_sharp, + Icons.agriculture, + Icons.agriculture_outlined, + Icons.agriculture_rounded, + Icons.agriculture_sharp, + Icons.air, + Icons.air_outlined, + Icons.air_rounded, + Icons.air_sharp, + Icons.airline_seat_flat, + Icons.airline_seat_flat_angled, + Icons.airline_seat_flat_angled_outlined, + Icons.airline_seat_flat_angled_rounded, + Icons.airline_seat_flat_angled_sharp, + Icons.airline_seat_flat_outlined, + Icons.airline_seat_flat_rounded, + Icons.airline_seat_flat_sharp, + Icons.airline_seat_individual_suite, + Icons.airline_seat_individual_suite_outlined, + Icons.airline_seat_individual_suite_rounded, + Icons.airline_seat_individual_suite_sharp, + Icons.airline_seat_legroom_extra, + Icons.airline_seat_legroom_extra_outlined, + Icons.airline_seat_legroom_extra_rounded, + Icons.airline_seat_legroom_extra_sharp, + Icons.airline_seat_legroom_normal, + Icons.airline_seat_legroom_normal_outlined, + Icons.airline_seat_legroom_normal_rounded, + Icons.airline_seat_legroom_normal_sharp, + Icons.airline_seat_legroom_reduced, + Icons.airline_seat_legroom_reduced_outlined, + Icons.airline_seat_legroom_reduced_rounded, + Icons.airline_seat_legroom_reduced_sharp, + Icons.airline_seat_recline_extra, + Icons.airline_seat_recline_extra_outlined, + Icons.airline_seat_recline_extra_rounded, + Icons.airline_seat_recline_extra_sharp, + Icons.airline_seat_recline_normal, + Icons.airline_seat_recline_normal_outlined, + Icons.airline_seat_recline_normal_rounded, + Icons.airline_seat_recline_normal_sharp, + Icons.airline_stops, + Icons.airline_stops_outlined, + Icons.airline_stops_rounded, + Icons.airline_stops_sharp, + Icons.airlines, + Icons.airlines_outlined, + Icons.airlines_rounded, + Icons.airlines_sharp, + Icons.airplane_ticket, + Icons.airplane_ticket_outlined, + Icons.airplane_ticket_rounded, + Icons.airplane_ticket_sharp, + Icons.airplanemode_active, + Icons.airplanemode_active_outlined, + Icons.airplanemode_active_rounded, + Icons.airplanemode_active_sharp, + Icons.airplanemode_inactive, + Icons.airplanemode_inactive_outlined, + Icons.airplanemode_inactive_rounded, + Icons.airplanemode_inactive_sharp, + Icons.airplanemode_off, + Icons.airplanemode_off_outlined, + Icons.airplanemode_off_rounded, + Icons.airplanemode_off_sharp, + Icons.airplanemode_on, + Icons.airplanemode_on_outlined, + Icons.airplanemode_on_rounded, + Icons.airplanemode_on_sharp, + Icons.airplay, + Icons.airplay_outlined, + Icons.airplay_rounded, + Icons.airplay_sharp, + Icons.airport_shuttle, + Icons.airport_shuttle_outlined, + Icons.airport_shuttle_rounded, + Icons.airport_shuttle_sharp, + Icons.alarm, + Icons.alarm_add, + Icons.alarm_add_outlined, + Icons.alarm_add_rounded, + Icons.alarm_add_sharp, + Icons.alarm_off, + Icons.alarm_off_outlined, + Icons.alarm_off_rounded, + Icons.alarm_off_sharp, + Icons.alarm_on, + Icons.alarm_on_outlined, + Icons.alarm_on_rounded, + Icons.alarm_on_sharp, + Icons.alarm_outlined, + Icons.alarm_rounded, + Icons.alarm_sharp, + Icons.album, + Icons.album_outlined, + Icons.album_rounded, + Icons.album_sharp, + Icons.align_horizontal_center, + Icons.align_horizontal_center_outlined, + Icons.align_horizontal_center_rounded, + Icons.align_horizontal_center_sharp, + Icons.align_horizontal_left, + Icons.align_horizontal_left_outlined, + Icons.align_horizontal_left_rounded, + Icons.align_horizontal_left_sharp, + Icons.align_horizontal_right, + Icons.align_horizontal_right_outlined, + Icons.align_horizontal_right_rounded, + Icons.align_horizontal_right_sharp, + Icons.align_vertical_bottom, + Icons.align_vertical_bottom_outlined, + Icons.align_vertical_bottom_rounded, + Icons.align_vertical_bottom_sharp, + Icons.align_vertical_center, + Icons.align_vertical_center_outlined, + Icons.align_vertical_center_rounded, + Icons.align_vertical_center_sharp, + Icons.align_vertical_top, + Icons.align_vertical_top_outlined, + Icons.align_vertical_top_rounded, + Icons.align_vertical_top_sharp, + Icons.all_inbox, + Icons.all_inbox_outlined, + Icons.all_inbox_rounded, + Icons.all_inbox_sharp, + Icons.all_inclusive, + Icons.all_inclusive_outlined, + Icons.all_inclusive_rounded, + Icons.all_inclusive_sharp, + Icons.all_out, + Icons.all_out_outlined, + Icons.all_out_rounded, + Icons.all_out_sharp, + Icons.alt_route, + Icons.alt_route_outlined, + Icons.alt_route_rounded, + Icons.alt_route_sharp, + Icons.alternate_email, + Icons.alternate_email_outlined, + Icons.alternate_email_rounded, + Icons.alternate_email_sharp, + Icons.amp_stories, + Icons.amp_stories_outlined, + Icons.amp_stories_rounded, + Icons.amp_stories_sharp, + Icons.analytics, + Icons.analytics_outlined, + Icons.analytics_rounded, + Icons.analytics_sharp, + Icons.anchor, + Icons.anchor_outlined, + Icons.anchor_rounded, + Icons.anchor_sharp, + Icons.android, + Icons.android_outlined, + Icons.android_rounded, + Icons.android_sharp, + Icons.animation, + Icons.animation_outlined, + Icons.animation_rounded, + Icons.animation_sharp, + Icons.announcement, + Icons.announcement_outlined, + Icons.announcement_rounded, + Icons.announcement_sharp, + Icons.aod, + Icons.aod_outlined, + Icons.aod_rounded, + Icons.aod_sharp, + Icons.apartment, + Icons.apartment_outlined, + Icons.apartment_rounded, + Icons.apartment_sharp, + Icons.api, + Icons.api_outlined, + Icons.api_rounded, + Icons.api_sharp, + Icons.app_blocking, + Icons.app_blocking_outlined, + Icons.app_blocking_rounded, + Icons.app_blocking_sharp, + Icons.app_registration, + Icons.app_registration_outlined, + Icons.app_registration_rounded, + Icons.app_registration_sharp, + Icons.app_settings_alt, + Icons.app_settings_alt_outlined, + Icons.app_settings_alt_rounded, + Icons.app_settings_alt_sharp, + Icons.app_shortcut, + Icons.app_shortcut_outlined, + Icons.app_shortcut_rounded, + Icons.app_shortcut_sharp, + Icons.apple, + Icons.apple_outlined, + Icons.apple_rounded, + Icons.apple_sharp, + Icons.approval, + Icons.approval_outlined, + Icons.approval_rounded, + Icons.approval_sharp, + Icons.apps, + Icons.apps_outage, + Icons.apps_outage_outlined, + Icons.apps_outage_rounded, + Icons.apps_outage_sharp, + Icons.apps_outlined, + Icons.apps_rounded, + Icons.apps_sharp, + Icons.architecture, + Icons.architecture_outlined, + Icons.architecture_rounded, + Icons.architecture_sharp, + Icons.archive, + Icons.archive_outlined, + Icons.archive_rounded, + Icons.archive_sharp, + Icons.area_chart, + Icons.area_chart_outlined, + Icons.area_chart_rounded, + Icons.area_chart_sharp, + Icons.arrow_back, + Icons.arrow_back_ios, + Icons.arrow_back_ios_new, + Icons.arrow_back_ios_new_outlined, + Icons.arrow_back_ios_new_rounded, + Icons.arrow_back_ios_new_sharp, + Icons.arrow_back_ios_outlined, + Icons.arrow_back_ios_rounded, + Icons.arrow_back_ios_sharp, + Icons.arrow_back_outlined, + Icons.arrow_back_rounded, + Icons.arrow_back_sharp, + Icons.arrow_circle_down, + Icons.arrow_circle_down_outlined, + Icons.arrow_circle_down_rounded, + Icons.arrow_circle_down_sharp, + Icons.arrow_circle_left, + Icons.arrow_circle_left_outlined, + Icons.arrow_circle_left_rounded, + Icons.arrow_circle_left_sharp, + Icons.arrow_circle_right, + Icons.arrow_circle_right_outlined, + Icons.arrow_circle_right_rounded, + Icons.arrow_circle_right_sharp, + Icons.arrow_circle_up, + Icons.arrow_circle_up_outlined, + Icons.arrow_circle_up_rounded, + Icons.arrow_circle_up_sharp, + Icons.arrow_downward, + Icons.arrow_downward_outlined, + Icons.arrow_downward_rounded, + Icons.arrow_downward_sharp, + Icons.arrow_drop_down, + Icons.arrow_drop_down_circle, + Icons.arrow_drop_down_circle_outlined, + Icons.arrow_drop_down_circle_rounded, + Icons.arrow_drop_down_circle_sharp, + Icons.arrow_drop_down_outlined, + Icons.arrow_drop_down_rounded, + Icons.arrow_drop_down_sharp, + Icons.arrow_drop_up, + Icons.arrow_drop_up_outlined, + Icons.arrow_drop_up_rounded, + Icons.arrow_drop_up_sharp, + Icons.arrow_forward, + Icons.arrow_forward_ios, + Icons.arrow_forward_ios_outlined, + Icons.arrow_forward_ios_rounded, + Icons.arrow_forward_ios_sharp, + Icons.arrow_forward_outlined, + Icons.arrow_forward_rounded, + Icons.arrow_forward_sharp, + Icons.arrow_left, + Icons.arrow_left_outlined, + Icons.arrow_left_rounded, + Icons.arrow_left_sharp, + Icons.arrow_outward, + Icons.arrow_outward_outlined, + Icons.arrow_outward_rounded, + Icons.arrow_outward_sharp, + Icons.arrow_right, + Icons.arrow_right_alt, + Icons.arrow_right_alt_outlined, + Icons.arrow_right_alt_rounded, + Icons.arrow_right_alt_sharp, + Icons.arrow_right_outlined, + Icons.arrow_right_rounded, + Icons.arrow_right_sharp, + Icons.arrow_upward, + Icons.arrow_upward_outlined, + Icons.arrow_upward_rounded, + Icons.arrow_upward_sharp, + Icons.art_track, + Icons.art_track_outlined, + Icons.art_track_rounded, + Icons.art_track_sharp, + Icons.article, + Icons.article_outlined, + Icons.article_rounded, + Icons.article_sharp, + Icons.aspect_ratio, + Icons.aspect_ratio_outlined, + Icons.aspect_ratio_rounded, + Icons.aspect_ratio_sharp, + Icons.assessment, + Icons.assessment_outlined, + Icons.assessment_rounded, + Icons.assessment_sharp, + Icons.assignment, + Icons.assignment_add, + Icons.assignment_ind, + Icons.assignment_ind_outlined, + Icons.assignment_ind_rounded, + Icons.assignment_ind_sharp, + Icons.assignment_late, + Icons.assignment_late_outlined, + Icons.assignment_late_rounded, + Icons.assignment_late_sharp, + Icons.assignment_outlined, + Icons.assignment_return, + Icons.assignment_return_outlined, + Icons.assignment_return_rounded, + Icons.assignment_return_sharp, + Icons.assignment_returned, + Icons.assignment_returned_outlined, + Icons.assignment_returned_rounded, + Icons.assignment_returned_sharp, + Icons.assignment_rounded, + Icons.assignment_sharp, + Icons.assignment_turned_in, + Icons.assignment_turned_in_outlined, + Icons.assignment_turned_in_rounded, + Icons.assignment_turned_in_sharp, + Icons.assist_walker, + Icons.assist_walker_outlined, + Icons.assist_walker_rounded, + Icons.assist_walker_sharp, + Icons.assistant, + Icons.assistant_direction, + Icons.assistant_direction_outlined, + Icons.assistant_direction_rounded, + Icons.assistant_direction_sharp, + Icons.assistant_navigation, + Icons.assistant_outlined, + Icons.assistant_photo, + Icons.assistant_photo_outlined, + Icons.assistant_photo_rounded, + Icons.assistant_photo_sharp, + Icons.assistant_rounded, + Icons.assistant_sharp, + Icons.assured_workload, + Icons.assured_workload_outlined, + Icons.assured_workload_rounded, + Icons.assured_workload_sharp, + Icons.atm, + Icons.atm_outlined, + Icons.atm_rounded, + Icons.atm_sharp, + Icons.attach_email, + Icons.attach_email_outlined, + Icons.attach_email_rounded, + Icons.attach_email_sharp, + Icons.attach_file, + Icons.attach_file_outlined, + Icons.attach_file_rounded, + Icons.attach_file_sharp, + Icons.attach_money, + Icons.attach_money_outlined, + Icons.attach_money_rounded, + Icons.attach_money_sharp, + Icons.attachment, + Icons.attachment_outlined, + Icons.attachment_rounded, + Icons.attachment_sharp, + Icons.attractions, + Icons.attractions_outlined, + Icons.attractions_rounded, + Icons.attractions_sharp, + Icons.attribution, + Icons.attribution_outlined, + Icons.attribution_rounded, + Icons.attribution_sharp, + Icons.audio_file, + Icons.audio_file_outlined, + Icons.audio_file_rounded, + Icons.audio_file_sharp, + Icons.audiotrack, + Icons.audiotrack_outlined, + Icons.audiotrack_rounded, + Icons.audiotrack_sharp, + Icons.auto_awesome, + Icons.auto_awesome_mosaic, + Icons.auto_awesome_mosaic_outlined, + Icons.auto_awesome_mosaic_rounded, + Icons.auto_awesome_mosaic_sharp, + Icons.auto_awesome_motion, + Icons.auto_awesome_motion_outlined, + Icons.auto_awesome_motion_rounded, + Icons.auto_awesome_motion_sharp, + Icons.auto_awesome_outlined, + Icons.auto_awesome_rounded, + Icons.auto_awesome_sharp, + Icons.auto_delete, + Icons.auto_delete_outlined, + Icons.auto_delete_rounded, + Icons.auto_delete_sharp, + Icons.auto_fix_high, + Icons.auto_fix_high_outlined, + Icons.auto_fix_high_rounded, + Icons.auto_fix_high_sharp, + Icons.auto_fix_normal, + Icons.auto_fix_normal_outlined, + Icons.auto_fix_normal_rounded, + Icons.auto_fix_normal_sharp, + Icons.auto_fix_off, + Icons.auto_fix_off_outlined, + Icons.auto_fix_off_rounded, + Icons.auto_fix_off_sharp, + Icons.auto_graph, + Icons.auto_graph_outlined, + Icons.auto_graph_rounded, + Icons.auto_graph_sharp, + Icons.auto_mode, + Icons.auto_mode_outlined, + Icons.auto_mode_rounded, + Icons.auto_mode_sharp, + Icons.auto_stories, + Icons.auto_stories_outlined, + Icons.auto_stories_rounded, + Icons.auto_stories_sharp, + Icons.autofps_select, + Icons.autofps_select_outlined, + Icons.autofps_select_rounded, + Icons.autofps_select_sharp, + Icons.autorenew, + Icons.autorenew_outlined, + Icons.autorenew_rounded, + Icons.autorenew_sharp, + Icons.av_timer, + Icons.av_timer_outlined, + Icons.av_timer_rounded, + Icons.av_timer_sharp, + Icons.baby_changing_station, + Icons.baby_changing_station_outlined, + Icons.baby_changing_station_rounded, + Icons.baby_changing_station_sharp, + Icons.back_hand, + Icons.back_hand_outlined, + Icons.back_hand_rounded, + Icons.back_hand_sharp, + Icons.backpack, + Icons.backpack_outlined, + Icons.backpack_rounded, + Icons.backpack_sharp, + Icons.backspace, + Icons.backspace_outlined, + Icons.backspace_rounded, + Icons.backspace_sharp, + Icons.backup, + Icons.backup_outlined, + Icons.backup_rounded, + Icons.backup_sharp, + Icons.backup_table, + Icons.backup_table_outlined, + Icons.backup_table_rounded, + Icons.backup_table_sharp, + Icons.badge, + Icons.badge_outlined, + Icons.badge_rounded, + Icons.badge_sharp, + Icons.bakery_dining, + Icons.bakery_dining_outlined, + Icons.bakery_dining_rounded, + Icons.bakery_dining_sharp, + Icons.balance, + Icons.balance_outlined, + Icons.balance_rounded, + Icons.balance_sharp, + Icons.balcony, + Icons.balcony_outlined, + Icons.balcony_rounded, + Icons.balcony_sharp, + Icons.ballot, + Icons.ballot_outlined, + Icons.ballot_rounded, + Icons.ballot_sharp, + Icons.bar_chart, + Icons.bar_chart_outlined, + Icons.bar_chart_rounded, + Icons.bar_chart_sharp, + Icons.barcode_reader, + Icons.batch_prediction, + Icons.batch_prediction_outlined, + Icons.batch_prediction_rounded, + Icons.batch_prediction_sharp, + Icons.bathroom, + Icons.bathroom_outlined, + Icons.bathroom_rounded, + Icons.bathroom_sharp, + Icons.bathtub, + Icons.bathtub_outlined, + Icons.bathtub_rounded, + Icons.bathtub_sharp, + Icons.battery_0_bar, + Icons.battery_0_bar_outlined, + Icons.battery_0_bar_rounded, + Icons.battery_0_bar_sharp, + Icons.battery_1_bar, + Icons.battery_1_bar_outlined, + Icons.battery_1_bar_rounded, + Icons.battery_1_bar_sharp, + Icons.battery_2_bar, + Icons.battery_2_bar_outlined, + Icons.battery_2_bar_rounded, + Icons.battery_2_bar_sharp, + Icons.battery_3_bar, + Icons.battery_3_bar_outlined, + Icons.battery_3_bar_rounded, + Icons.battery_3_bar_sharp, + Icons.battery_4_bar, + Icons.battery_4_bar_outlined, + Icons.battery_4_bar_rounded, + Icons.battery_4_bar_sharp, + Icons.battery_5_bar, + Icons.battery_5_bar_outlined, + Icons.battery_5_bar_rounded, + Icons.battery_5_bar_sharp, + Icons.battery_6_bar, + Icons.battery_6_bar_outlined, + Icons.battery_6_bar_rounded, + Icons.battery_6_bar_sharp, + Icons.battery_alert, + Icons.battery_alert_outlined, + Icons.battery_alert_rounded, + Icons.battery_alert_sharp, + Icons.battery_charging_full, + Icons.battery_charging_full_outlined, + Icons.battery_charging_full_rounded, + Icons.battery_charging_full_sharp, + Icons.battery_full, + Icons.battery_full_outlined, + Icons.battery_full_rounded, + Icons.battery_full_sharp, + Icons.battery_saver, + Icons.battery_saver_outlined, + Icons.battery_saver_rounded, + Icons.battery_saver_sharp, + Icons.battery_std, + Icons.battery_std_outlined, + Icons.battery_std_rounded, + Icons.battery_std_sharp, + Icons.battery_unknown, + Icons.battery_unknown_outlined, + Icons.battery_unknown_rounded, + Icons.battery_unknown_sharp, + Icons.beach_access, + Icons.beach_access_outlined, + Icons.beach_access_rounded, + Icons.beach_access_sharp, + Icons.bed, + Icons.bed_outlined, + Icons.bed_rounded, + Icons.bed_sharp, + Icons.bedroom_baby, + Icons.bedroom_baby_outlined, + Icons.bedroom_baby_rounded, + Icons.bedroom_baby_sharp, + Icons.bedroom_child, + Icons.bedroom_child_outlined, + Icons.bedroom_child_rounded, + Icons.bedroom_child_sharp, + Icons.bedroom_parent, + Icons.bedroom_parent_outlined, + Icons.bedroom_parent_rounded, + Icons.bedroom_parent_sharp, + Icons.bedtime, + Icons.bedtime_off, + Icons.bedtime_off_outlined, + Icons.bedtime_off_rounded, + Icons.bedtime_off_sharp, + Icons.bedtime_outlined, + Icons.bedtime_rounded, + Icons.bedtime_sharp, + Icons.beenhere, + Icons.beenhere_outlined, + Icons.beenhere_rounded, + Icons.beenhere_sharp, + Icons.bento, + Icons.bento_outlined, + Icons.bento_rounded, + Icons.bento_sharp, + Icons.bike_scooter, + Icons.bike_scooter_outlined, + Icons.bike_scooter_rounded, + Icons.bike_scooter_sharp, + Icons.biotech, + Icons.biotech_outlined, + Icons.biotech_rounded, + Icons.biotech_sharp, + Icons.blender, + Icons.blender_outlined, + Icons.blender_rounded, + Icons.blender_sharp, + Icons.blind, + Icons.blind_outlined, + Icons.blind_rounded, + Icons.blind_sharp, + Icons.blinds, + Icons.blinds_closed, + Icons.blinds_closed_outlined, + Icons.blinds_closed_rounded, + Icons.blinds_closed_sharp, + Icons.blinds_outlined, + Icons.blinds_rounded, + Icons.blinds_sharp, + Icons.block, + Icons.block_flipped, + Icons.block_outlined, + Icons.block_rounded, + Icons.block_sharp, + Icons.bloodtype, + Icons.bloodtype_outlined, + Icons.bloodtype_rounded, + Icons.bloodtype_sharp, + Icons.bluetooth, + Icons.bluetooth_audio, + Icons.bluetooth_audio_outlined, + Icons.bluetooth_audio_rounded, + Icons.bluetooth_audio_sharp, + Icons.bluetooth_connected, + Icons.bluetooth_connected_outlined, + Icons.bluetooth_connected_rounded, + Icons.bluetooth_connected_sharp, + Icons.bluetooth_disabled, + Icons.bluetooth_disabled_outlined, + Icons.bluetooth_disabled_rounded, + Icons.bluetooth_disabled_sharp, + Icons.bluetooth_drive, + Icons.bluetooth_drive_outlined, + Icons.bluetooth_drive_rounded, + Icons.bluetooth_drive_sharp, + Icons.bluetooth_outlined, + Icons.bluetooth_rounded, + Icons.bluetooth_searching, + Icons.bluetooth_searching_outlined, + Icons.bluetooth_searching_rounded, + Icons.bluetooth_searching_sharp, + Icons.bluetooth_sharp, + Icons.blur_circular, + Icons.blur_circular_outlined, + Icons.blur_circular_rounded, + Icons.blur_circular_sharp, + Icons.blur_linear, + Icons.blur_linear_outlined, + Icons.blur_linear_rounded, + Icons.blur_linear_sharp, + Icons.blur_off, + Icons.blur_off_outlined, + Icons.blur_off_rounded, + Icons.blur_off_sharp, + Icons.blur_on, + Icons.blur_on_outlined, + Icons.blur_on_rounded, + Icons.blur_on_sharp, + Icons.bolt, + Icons.bolt_outlined, + Icons.bolt_rounded, + Icons.bolt_sharp, + Icons.book, + Icons.book_online, + Icons.book_online_outlined, + Icons.book_online_rounded, + Icons.book_online_sharp, + Icons.book_outlined, + Icons.book_rounded, + Icons.book_sharp, + Icons.bookmark, + Icons.bookmark_add, + Icons.bookmark_add_outlined, + Icons.bookmark_add_rounded, + Icons.bookmark_add_sharp, + Icons.bookmark_added, + Icons.bookmark_added_outlined, + Icons.bookmark_added_rounded, + Icons.bookmark_added_sharp, + Icons.bookmark_border, + Icons.bookmark_border_outlined, + Icons.bookmark_border_rounded, + Icons.bookmark_border_sharp, + Icons.bookmark_outline, + Icons.bookmark_outline_outlined, + Icons.bookmark_outline_rounded, + Icons.bookmark_outline_sharp, + Icons.bookmark_outlined, + Icons.bookmark_remove, + Icons.bookmark_remove_outlined, + Icons.bookmark_remove_rounded, + Icons.bookmark_remove_sharp, + Icons.bookmark_rounded, + Icons.bookmark_sharp, + Icons.bookmarks, + Icons.bookmarks_outlined, + Icons.bookmarks_rounded, + Icons.bookmarks_sharp, + Icons.border_all, + Icons.border_all_outlined, + Icons.border_all_rounded, + Icons.border_all_sharp, + Icons.border_bottom, + Icons.border_bottom_outlined, + Icons.border_bottom_rounded, + Icons.border_bottom_sharp, + Icons.border_clear, + Icons.border_clear_outlined, + Icons.border_clear_rounded, + Icons.border_clear_sharp, + Icons.border_color, + Icons.border_color_outlined, + Icons.border_color_rounded, + Icons.border_color_sharp, + Icons.border_horizontal, + Icons.border_horizontal_outlined, + Icons.border_horizontal_rounded, + Icons.border_horizontal_sharp, + Icons.border_inner, + Icons.border_inner_outlined, + Icons.border_inner_rounded, + Icons.border_inner_sharp, + Icons.border_left, + Icons.border_left_outlined, + Icons.border_left_rounded, + Icons.border_left_sharp, + Icons.border_outer, + Icons.border_outer_outlined, + Icons.border_outer_rounded, + Icons.border_outer_sharp, + Icons.border_right, + Icons.border_right_outlined, + Icons.border_right_rounded, + Icons.border_right_sharp, + Icons.border_style, + Icons.border_style_outlined, + Icons.border_style_rounded, + Icons.border_style_sharp, + Icons.border_top, + Icons.border_top_outlined, + Icons.border_top_rounded, + Icons.border_top_sharp, + Icons.border_vertical, + Icons.border_vertical_outlined, + Icons.border_vertical_rounded, + Icons.border_vertical_sharp, + Icons.boy, + Icons.boy_outlined, + Icons.boy_rounded, + Icons.boy_sharp, + Icons.branding_watermark, + Icons.branding_watermark_outlined, + Icons.branding_watermark_rounded, + Icons.branding_watermark_sharp, + Icons.breakfast_dining, + Icons.breakfast_dining_outlined, + Icons.breakfast_dining_rounded, + Icons.breakfast_dining_sharp, + Icons.brightness_1, + Icons.brightness_1_outlined, + Icons.brightness_1_rounded, + Icons.brightness_1_sharp, + Icons.brightness_2, + Icons.brightness_2_outlined, + Icons.brightness_2_rounded, + Icons.brightness_2_sharp, + Icons.brightness_3, + Icons.brightness_3_outlined, + Icons.brightness_3_rounded, + Icons.brightness_3_sharp, + Icons.brightness_4, + Icons.brightness_4_outlined, + Icons.brightness_4_rounded, + Icons.brightness_4_sharp, + Icons.brightness_5, + Icons.brightness_5_outlined, + Icons.brightness_5_rounded, + Icons.brightness_5_sharp, + Icons.brightness_6, + Icons.brightness_6_outlined, + Icons.brightness_6_rounded, + Icons.brightness_6_sharp, + Icons.brightness_7, + Icons.brightness_7_outlined, + Icons.brightness_7_rounded, + Icons.brightness_7_sharp, + Icons.brightness_auto, + Icons.brightness_auto_outlined, + Icons.brightness_auto_rounded, + Icons.brightness_auto_sharp, + Icons.brightness_high, + Icons.brightness_high_outlined, + Icons.brightness_high_rounded, + Icons.brightness_high_sharp, + Icons.brightness_low, + Icons.brightness_low_outlined, + Icons.brightness_low_rounded, + Icons.brightness_low_sharp, + Icons.brightness_medium, + Icons.brightness_medium_outlined, + Icons.brightness_medium_rounded, + Icons.brightness_medium_sharp, + Icons.broadcast_on_home, + Icons.broadcast_on_home_outlined, + Icons.broadcast_on_home_rounded, + Icons.broadcast_on_home_sharp, + Icons.broadcast_on_personal, + Icons.broadcast_on_personal_outlined, + Icons.broadcast_on_personal_rounded, + Icons.broadcast_on_personal_sharp, + Icons.broken_image, + Icons.broken_image_outlined, + Icons.broken_image_rounded, + Icons.broken_image_sharp, + Icons.browse_gallery, + Icons.browse_gallery_outlined, + Icons.browse_gallery_rounded, + Icons.browse_gallery_sharp, + Icons.browser_not_supported, + Icons.browser_not_supported_outlined, + Icons.browser_not_supported_rounded, + Icons.browser_not_supported_sharp, + Icons.browser_updated, + Icons.browser_updated_outlined, + Icons.browser_updated_rounded, + Icons.browser_updated_sharp, + Icons.brunch_dining, + Icons.brunch_dining_outlined, + Icons.brunch_dining_rounded, + Icons.brunch_dining_sharp, + Icons.brush, + Icons.brush_outlined, + Icons.brush_rounded, + Icons.brush_sharp, + Icons.bubble_chart, + Icons.bubble_chart_outlined, + Icons.bubble_chart_rounded, + Icons.bubble_chart_sharp, + Icons.bug_report, + Icons.bug_report_outlined, + Icons.bug_report_rounded, + Icons.bug_report_sharp, + Icons.build, + Icons.build_circle, + Icons.build_circle_outlined, + Icons.build_circle_rounded, + Icons.build_circle_sharp, + Icons.build_outlined, + Icons.build_rounded, + Icons.build_sharp, + Icons.bungalow, + Icons.bungalow_outlined, + Icons.bungalow_rounded, + Icons.bungalow_sharp, + Icons.burst_mode, + Icons.burst_mode_outlined, + Icons.burst_mode_rounded, + Icons.burst_mode_sharp, + Icons.bus_alert, + Icons.bus_alert_outlined, + Icons.bus_alert_rounded, + Icons.bus_alert_sharp, + Icons.business, + Icons.business_center, + Icons.business_center_outlined, + Icons.business_center_rounded, + Icons.business_center_sharp, + Icons.business_outlined, + Icons.business_rounded, + Icons.business_sharp, + Icons.cabin, + Icons.cabin_outlined, + Icons.cabin_rounded, + Icons.cabin_sharp, + Icons.cable, + Icons.cable_outlined, + Icons.cable_rounded, + Icons.cable_sharp, + Icons.cached, + Icons.cached_outlined, + Icons.cached_rounded, + Icons.cached_sharp, + Icons.cake, + Icons.cake_outlined, + Icons.cake_rounded, + Icons.cake_sharp, + Icons.calculate, + Icons.calculate_outlined, + Icons.calculate_rounded, + Icons.calculate_sharp, + Icons.calendar_month, + Icons.calendar_month_outlined, + Icons.calendar_month_rounded, + Icons.calendar_month_sharp, + Icons.calendar_today, + Icons.calendar_today_outlined, + Icons.calendar_today_rounded, + Icons.calendar_today_sharp, + Icons.calendar_view_day, + Icons.calendar_view_day_outlined, + Icons.calendar_view_day_rounded, + Icons.calendar_view_day_sharp, + Icons.calendar_view_month, + Icons.calendar_view_month_outlined, + Icons.calendar_view_month_rounded, + Icons.calendar_view_month_sharp, + Icons.calendar_view_week, + Icons.calendar_view_week_outlined, + Icons.calendar_view_week_rounded, + Icons.calendar_view_week_sharp, + Icons.call, + Icons.call_end, + Icons.call_end_outlined, + Icons.call_end_rounded, + Icons.call_end_sharp, + Icons.call_made, + Icons.call_made_outlined, + Icons.call_made_rounded, + Icons.call_made_sharp, + Icons.call_merge, + Icons.call_merge_outlined, + Icons.call_merge_rounded, + Icons.call_merge_sharp, + Icons.call_missed, + Icons.call_missed_outgoing, + Icons.call_missed_outgoing_outlined, + Icons.call_missed_outgoing_rounded, + Icons.call_missed_outgoing_sharp, + Icons.call_missed_outlined, + Icons.call_missed_rounded, + Icons.call_missed_sharp, + Icons.call_outlined, + Icons.call_received, + Icons.call_received_outlined, + Icons.call_received_rounded, + Icons.call_received_sharp, + Icons.call_rounded, + Icons.call_sharp, + Icons.call_split, + Icons.call_split_outlined, + Icons.call_split_rounded, + Icons.call_split_sharp, + Icons.call_to_action, + Icons.call_to_action_outlined, + Icons.call_to_action_rounded, + Icons.call_to_action_sharp, + Icons.camera, + Icons.camera_alt, + Icons.camera_alt_outlined, + Icons.camera_alt_rounded, + Icons.camera_alt_sharp, + Icons.camera_enhance, + Icons.camera_enhance_outlined, + Icons.camera_enhance_rounded, + Icons.camera_enhance_sharp, + Icons.camera_front, + Icons.camera_front_outlined, + Icons.camera_front_rounded, + Icons.camera_front_sharp, + Icons.camera_indoor, + Icons.camera_indoor_outlined, + Icons.camera_indoor_rounded, + Icons.camera_indoor_sharp, + Icons.camera_outdoor, + Icons.camera_outdoor_outlined, + Icons.camera_outdoor_rounded, + Icons.camera_outdoor_sharp, + Icons.camera_outlined, + Icons.camera_rear, + Icons.camera_rear_outlined, + Icons.camera_rear_rounded, + Icons.camera_rear_sharp, + Icons.camera_roll, + Icons.camera_roll_outlined, + Icons.camera_roll_rounded, + Icons.camera_roll_sharp, + Icons.camera_rounded, + Icons.camera_sharp, + Icons.cameraswitch, + Icons.cameraswitch_outlined, + Icons.cameraswitch_rounded, + Icons.cameraswitch_sharp, + Icons.campaign, + Icons.campaign_outlined, + Icons.campaign_rounded, + Icons.campaign_sharp, + Icons.cancel, + Icons.cancel_outlined, + Icons.cancel_presentation, + Icons.cancel_presentation_outlined, + Icons.cancel_presentation_rounded, + Icons.cancel_presentation_sharp, + Icons.cancel_rounded, + Icons.cancel_schedule_send, + Icons.cancel_schedule_send_outlined, + Icons.cancel_schedule_send_rounded, + Icons.cancel_schedule_send_sharp, + Icons.cancel_sharp, + Icons.candlestick_chart, + Icons.candlestick_chart_outlined, + Icons.candlestick_chart_rounded, + Icons.candlestick_chart_sharp, + Icons.car_crash, + Icons.car_crash_outlined, + Icons.car_crash_rounded, + Icons.car_crash_sharp, + Icons.car_rental, + Icons.car_rental_outlined, + Icons.car_rental_rounded, + Icons.car_rental_sharp, + Icons.car_repair, + Icons.car_repair_outlined, + Icons.car_repair_rounded, + Icons.car_repair_sharp, + Icons.card_giftcard, + Icons.card_giftcard_outlined, + Icons.card_giftcard_rounded, + Icons.card_giftcard_sharp, + Icons.card_membership, + Icons.card_membership_outlined, + Icons.card_membership_rounded, + Icons.card_membership_sharp, + Icons.card_travel, + Icons.card_travel_outlined, + Icons.card_travel_rounded, + Icons.card_travel_sharp, + Icons.carpenter, + Icons.carpenter_outlined, + Icons.carpenter_rounded, + Icons.carpenter_sharp, + Icons.cases, + Icons.cases_outlined, + Icons.cases_rounded, + Icons.cases_sharp, + Icons.casino, + Icons.casino_outlined, + Icons.casino_rounded, + Icons.casino_sharp, + Icons.cast, + Icons.cast_connected, + Icons.cast_connected_outlined, + Icons.cast_connected_rounded, + Icons.cast_connected_sharp, + Icons.cast_for_education, + Icons.cast_for_education_outlined, + Icons.cast_for_education_rounded, + Icons.cast_for_education_sharp, + Icons.cast_outlined, + Icons.cast_rounded, + Icons.cast_sharp, + Icons.castle, + Icons.castle_outlined, + Icons.castle_rounded, + Icons.castle_sharp, + Icons.catching_pokemon, + Icons.catching_pokemon_outlined, + Icons.catching_pokemon_rounded, + Icons.catching_pokemon_sharp, + Icons.category, + Icons.category_outlined, + Icons.category_rounded, + Icons.category_sharp, + Icons.celebration, + Icons.celebration_outlined, + Icons.celebration_rounded, + Icons.celebration_sharp, + Icons.cell_tower, + Icons.cell_tower_outlined, + Icons.cell_tower_rounded, + Icons.cell_tower_sharp, + Icons.cell_wifi, + Icons.cell_wifi_outlined, + Icons.cell_wifi_rounded, + Icons.cell_wifi_sharp, + Icons.center_focus_strong, + Icons.center_focus_strong_outlined, + Icons.center_focus_strong_rounded, + Icons.center_focus_strong_sharp, + Icons.center_focus_weak, + Icons.center_focus_weak_outlined, + Icons.center_focus_weak_rounded, + Icons.center_focus_weak_sharp, + Icons.chair, + Icons.chair_alt, + Icons.chair_alt_outlined, + Icons.chair_alt_rounded, + Icons.chair_alt_sharp, + Icons.chair_outlined, + Icons.chair_rounded, + Icons.chair_sharp, + Icons.chalet, + Icons.chalet_outlined, + Icons.chalet_rounded, + Icons.chalet_sharp, + Icons.change_circle, + Icons.change_circle_outlined, + Icons.change_circle_rounded, + Icons.change_circle_sharp, + Icons.change_history, + Icons.change_history_outlined, + Icons.change_history_rounded, + Icons.change_history_sharp, + Icons.charging_station, + Icons.charging_station_outlined, + Icons.charging_station_rounded, + Icons.charging_station_sharp, + Icons.chat, + Icons.chat_bubble, + Icons.chat_bubble_outline, + Icons.chat_bubble_outline_outlined, + Icons.chat_bubble_outline_rounded, + Icons.chat_bubble_outline_sharp, + Icons.chat_bubble_outlined, + Icons.chat_bubble_rounded, + Icons.chat_bubble_sharp, + Icons.chat_outlined, + Icons.chat_rounded, + Icons.chat_sharp, + Icons.check, + Icons.check_box, + Icons.check_box_outline_blank, + Icons.check_box_outline_blank_outlined, + Icons.check_box_outline_blank_rounded, + Icons.check_box_outline_blank_sharp, + Icons.check_box_outlined, + Icons.check_box_rounded, + Icons.check_box_sharp, + Icons.check_circle, + Icons.check_circle_outline, + Icons.check_circle_outline_outlined, + Icons.check_circle_outline_rounded, + Icons.check_circle_outline_sharp, + Icons.check_circle_outlined, + Icons.check_circle_rounded, + Icons.check_circle_sharp, + Icons.check_outlined, + Icons.check_rounded, + Icons.check_sharp, + Icons.checklist, + Icons.checklist_outlined, + Icons.checklist_rounded, + Icons.checklist_rtl, + Icons.checklist_rtl_outlined, + Icons.checklist_rtl_rounded, + Icons.checklist_rtl_sharp, + Icons.checklist_sharp, + Icons.checkroom, + Icons.checkroom_outlined, + Icons.checkroom_rounded, + Icons.checkroom_sharp, + Icons.chevron_left, + Icons.chevron_left_outlined, + Icons.chevron_left_rounded, + Icons.chevron_left_sharp, + Icons.chevron_right, + Icons.chevron_right_outlined, + Icons.chevron_right_rounded, + Icons.chevron_right_sharp, + Icons.child_care, + Icons.child_care_outlined, + Icons.child_care_rounded, + Icons.child_care_sharp, + Icons.child_friendly, + Icons.child_friendly_outlined, + Icons.child_friendly_rounded, + Icons.child_friendly_sharp, + Icons.chrome_reader_mode, + Icons.chrome_reader_mode_outlined, + Icons.chrome_reader_mode_rounded, + Icons.chrome_reader_mode_sharp, + Icons.church, + Icons.church_outlined, + Icons.church_rounded, + Icons.church_sharp, + Icons.circle, + Icons.circle_notifications, + Icons.circle_notifications_outlined, + Icons.circle_notifications_rounded, + Icons.circle_notifications_sharp, + Icons.circle_outlined, + Icons.circle_rounded, + Icons.circle_sharp, + Icons.class_, + Icons.class_outlined, + Icons.class_rounded, + Icons.class_sharp, + Icons.clean_hands, + Icons.clean_hands_outlined, + Icons.clean_hands_rounded, + Icons.clean_hands_sharp, + Icons.cleaning_services, + Icons.cleaning_services_outlined, + Icons.cleaning_services_rounded, + Icons.cleaning_services_sharp, + Icons.clear, + Icons.clear_all, + Icons.clear_all_outlined, + Icons.clear_all_rounded, + Icons.clear_all_sharp, + Icons.clear_outlined, + Icons.clear_rounded, + Icons.clear_sharp, + Icons.close, + Icons.close_fullscreen, + Icons.close_fullscreen_outlined, + Icons.close_fullscreen_rounded, + Icons.close_fullscreen_sharp, + Icons.close_outlined, + Icons.close_rounded, + Icons.close_sharp, + Icons.closed_caption, + Icons.closed_caption_disabled, + Icons.closed_caption_disabled_outlined, + Icons.closed_caption_disabled_rounded, + Icons.closed_caption_disabled_sharp, + Icons.closed_caption_off, + Icons.closed_caption_off_outlined, + Icons.closed_caption_off_rounded, + Icons.closed_caption_off_sharp, + Icons.closed_caption_outlined, + Icons.closed_caption_rounded, + Icons.closed_caption_sharp, + Icons.cloud, + Icons.cloud_circle, + Icons.cloud_circle_outlined, + Icons.cloud_circle_rounded, + Icons.cloud_circle_sharp, + Icons.cloud_done, + Icons.cloud_done_outlined, + Icons.cloud_done_rounded, + Icons.cloud_done_sharp, + Icons.cloud_download, + Icons.cloud_download_outlined, + Icons.cloud_download_rounded, + Icons.cloud_download_sharp, + Icons.cloud_off, + Icons.cloud_off_outlined, + Icons.cloud_off_rounded, + Icons.cloud_off_sharp, + Icons.cloud_outlined, + Icons.cloud_queue, + Icons.cloud_queue_outlined, + Icons.cloud_queue_rounded, + Icons.cloud_queue_sharp, + Icons.cloud_rounded, + Icons.cloud_sharp, + Icons.cloud_sync, + Icons.cloud_sync_outlined, + Icons.cloud_sync_rounded, + Icons.cloud_sync_sharp, + Icons.cloud_upload, + Icons.cloud_upload_outlined, + Icons.cloud_upload_rounded, + Icons.cloud_upload_sharp, + Icons.cloudy_snowing, + Icons.co2, + Icons.co2_outlined, + Icons.co2_rounded, + Icons.co2_sharp, + Icons.co_present, + Icons.co_present_outlined, + Icons.co_present_rounded, + Icons.co_present_sharp, + Icons.code, + Icons.code_off, + Icons.code_off_outlined, + Icons.code_off_rounded, + Icons.code_off_sharp, + Icons.code_outlined, + Icons.code_rounded, + Icons.code_sharp, + Icons.coffee, + Icons.coffee_maker, + Icons.coffee_maker_outlined, + Icons.coffee_maker_rounded, + Icons.coffee_maker_sharp, + Icons.coffee_outlined, + Icons.coffee_rounded, + Icons.coffee_sharp, + Icons.collections, + Icons.collections_bookmark, + Icons.collections_bookmark_outlined, + Icons.collections_bookmark_rounded, + Icons.collections_bookmark_sharp, + Icons.collections_outlined, + Icons.collections_rounded, + Icons.collections_sharp, + Icons.color_lens, + Icons.color_lens_outlined, + Icons.color_lens_rounded, + Icons.color_lens_sharp, + Icons.colorize, + Icons.colorize_outlined, + Icons.colorize_rounded, + Icons.colorize_sharp, + Icons.comment, + Icons.comment_bank, + Icons.comment_bank_outlined, + Icons.comment_bank_rounded, + Icons.comment_bank_sharp, + Icons.comment_outlined, + Icons.comment_rounded, + Icons.comment_sharp, + Icons.comments_disabled, + Icons.comments_disabled_outlined, + Icons.comments_disabled_rounded, + Icons.comments_disabled_sharp, + Icons.commit, + Icons.commit_outlined, + Icons.commit_rounded, + Icons.commit_sharp, + Icons.commute, + Icons.commute_outlined, + Icons.commute_rounded, + Icons.commute_sharp, + Icons.compare, + Icons.compare_arrows, + Icons.compare_arrows_outlined, + Icons.compare_arrows_rounded, + Icons.compare_arrows_sharp, + Icons.compare_outlined, + Icons.compare_rounded, + Icons.compare_sharp, + Icons.compass_calibration, + Icons.compass_calibration_outlined, + Icons.compass_calibration_rounded, + Icons.compass_calibration_sharp, + Icons.compost, + Icons.compost_outlined, + Icons.compost_rounded, + Icons.compost_sharp, + Icons.compress, + Icons.compress_outlined, + Icons.compress_rounded, + Icons.compress_sharp, + Icons.computer, + Icons.computer_outlined, + Icons.computer_rounded, + Icons.computer_sharp, + Icons.confirmation_num, + Icons.confirmation_num_outlined, + Icons.confirmation_num_rounded, + Icons.confirmation_num_sharp, + Icons.confirmation_number, + Icons.confirmation_number_outlined, + Icons.confirmation_number_rounded, + Icons.confirmation_number_sharp, + Icons.connect_without_contact, + Icons.connect_without_contact_outlined, + Icons.connect_without_contact_rounded, + Icons.connect_without_contact_sharp, + Icons.connected_tv, + Icons.connected_tv_outlined, + Icons.connected_tv_rounded, + Icons.connected_tv_sharp, + Icons.connecting_airports, + Icons.connecting_airports_outlined, + Icons.connecting_airports_rounded, + Icons.connecting_airports_sharp, + Icons.construction, + Icons.construction_outlined, + Icons.construction_rounded, + Icons.construction_sharp, + Icons.contact_emergency, + Icons.contact_emergency_outlined, + Icons.contact_emergency_rounded, + Icons.contact_emergency_sharp, + Icons.contact_mail, + Icons.contact_mail_outlined, + Icons.contact_mail_rounded, + Icons.contact_mail_sharp, + Icons.contact_page, + Icons.contact_page_outlined, + Icons.contact_page_rounded, + Icons.contact_page_sharp, + Icons.contact_phone, + Icons.contact_phone_outlined, + Icons.contact_phone_rounded, + Icons.contact_phone_sharp, + Icons.contact_support, + Icons.contact_support_outlined, + Icons.contact_support_rounded, + Icons.contact_support_sharp, + Icons.contactless, + Icons.contactless_outlined, + Icons.contactless_rounded, + Icons.contactless_sharp, + Icons.contacts, + Icons.contacts_outlined, + Icons.contacts_rounded, + Icons.contacts_sharp, + Icons.content_copy, + Icons.content_copy_outlined, + Icons.content_copy_rounded, + Icons.content_copy_sharp, + Icons.content_cut, + Icons.content_cut_outlined, + Icons.content_cut_rounded, + Icons.content_cut_sharp, + Icons.content_paste, + Icons.content_paste_go, + Icons.content_paste_go_outlined, + Icons.content_paste_go_rounded, + Icons.content_paste_go_sharp, + Icons.content_paste_off, + Icons.content_paste_off_outlined, + Icons.content_paste_off_rounded, + Icons.content_paste_off_sharp, + Icons.content_paste_outlined, + Icons.content_paste_rounded, + Icons.content_paste_search, + Icons.content_paste_search_outlined, + Icons.content_paste_search_rounded, + Icons.content_paste_search_sharp, + Icons.content_paste_sharp, + Icons.contrast, + Icons.contrast_outlined, + Icons.contrast_rounded, + Icons.contrast_sharp, + Icons.control_camera, + Icons.control_camera_outlined, + Icons.control_camera_rounded, + Icons.control_camera_sharp, + Icons.control_point, + Icons.control_point_duplicate, + Icons.control_point_duplicate_outlined, + Icons.control_point_duplicate_rounded, + Icons.control_point_duplicate_sharp, + Icons.control_point_outlined, + Icons.control_point_rounded, + Icons.control_point_sharp, + Icons.conveyor_belt, + Icons.cookie, + Icons.cookie_outlined, + Icons.cookie_rounded, + Icons.cookie_sharp, + Icons.copy, + Icons.copy_all, + Icons.copy_all_outlined, + Icons.copy_all_rounded, + Icons.copy_all_sharp, + Icons.copy_outlined, + Icons.copy_rounded, + Icons.copy_sharp, + Icons.copyright, + Icons.copyright_outlined, + Icons.copyright_rounded, + Icons.copyright_sharp, + Icons.coronavirus, + Icons.coronavirus_outlined, + Icons.coronavirus_rounded, + Icons.coronavirus_sharp, + Icons.corporate_fare, + Icons.corporate_fare_outlined, + Icons.corporate_fare_rounded, + Icons.corporate_fare_sharp, + Icons.cottage, + Icons.cottage_outlined, + Icons.cottage_rounded, + Icons.cottage_sharp, + Icons.countertops, + Icons.countertops_outlined, + Icons.countertops_rounded, + Icons.countertops_sharp, + Icons.create, + Icons.create_new_folder, + Icons.create_new_folder_outlined, + Icons.create_new_folder_rounded, + Icons.create_new_folder_sharp, + Icons.create_outlined, + Icons.create_rounded, + Icons.create_sharp, + Icons.credit_card, + Icons.credit_card_off, + Icons.credit_card_off_outlined, + Icons.credit_card_off_rounded, + Icons.credit_card_off_sharp, + Icons.credit_card_outlined, + Icons.credit_card_rounded, + Icons.credit_card_sharp, + Icons.credit_score, + Icons.credit_score_outlined, + Icons.credit_score_rounded, + Icons.credit_score_sharp, + Icons.crib, + Icons.crib_outlined, + Icons.crib_rounded, + Icons.crib_sharp, + Icons.crisis_alert, + Icons.crisis_alert_outlined, + Icons.crisis_alert_rounded, + Icons.crisis_alert_sharp, + Icons.crop, + Icons.crop_16_9, + Icons.crop_16_9_outlined, + Icons.crop_16_9_rounded, + Icons.crop_16_9_sharp, + Icons.crop_3_2, + Icons.crop_3_2_outlined, + Icons.crop_3_2_rounded, + Icons.crop_3_2_sharp, + Icons.crop_5_4, + Icons.crop_5_4_outlined, + Icons.crop_5_4_rounded, + Icons.crop_5_4_sharp, + Icons.crop_7_5, + Icons.crop_7_5_outlined, + Icons.crop_7_5_rounded, + Icons.crop_7_5_sharp, + Icons.crop_din, + Icons.crop_din_outlined, + Icons.crop_din_rounded, + Icons.crop_din_sharp, + Icons.crop_free, + Icons.crop_free_outlined, + Icons.crop_free_rounded, + Icons.crop_free_sharp, + Icons.crop_landscape, + Icons.crop_landscape_outlined, + Icons.crop_landscape_rounded, + Icons.crop_landscape_sharp, + Icons.crop_original, + Icons.crop_original_outlined, + Icons.crop_original_rounded, + Icons.crop_original_sharp, + Icons.crop_outlined, + Icons.crop_portrait, + Icons.crop_portrait_outlined, + Icons.crop_portrait_rounded, + Icons.crop_portrait_sharp, + Icons.crop_rotate, + Icons.crop_rotate_outlined, + Icons.crop_rotate_rounded, + Icons.crop_rotate_sharp, + Icons.crop_rounded, + Icons.crop_sharp, + Icons.crop_square, + Icons.crop_square_outlined, + Icons.crop_square_rounded, + Icons.crop_square_sharp, + Icons.cruelty_free, + Icons.cruelty_free_outlined, + Icons.cruelty_free_rounded, + Icons.cruelty_free_sharp, + Icons.css, + Icons.css_outlined, + Icons.css_rounded, + Icons.css_sharp, + Icons.currency_bitcoin, + Icons.currency_bitcoin_outlined, + Icons.currency_bitcoin_rounded, + Icons.currency_bitcoin_sharp, + Icons.currency_exchange, + Icons.currency_exchange_outlined, + Icons.currency_exchange_rounded, + Icons.currency_exchange_sharp, + Icons.currency_franc, + Icons.currency_franc_outlined, + Icons.currency_franc_rounded, + Icons.currency_franc_sharp, + Icons.currency_lira, + Icons.currency_lira_outlined, + Icons.currency_lira_rounded, + Icons.currency_lira_sharp, + Icons.currency_pound, + Icons.currency_pound_outlined, + Icons.currency_pound_rounded, + Icons.currency_pound_sharp, + Icons.currency_ruble, + Icons.currency_ruble_outlined, + Icons.currency_ruble_rounded, + Icons.currency_ruble_sharp, + Icons.currency_rupee, + Icons.currency_rupee_outlined, + Icons.currency_rupee_rounded, + Icons.currency_rupee_sharp, + Icons.currency_yen, + Icons.currency_yen_outlined, + Icons.currency_yen_rounded, + Icons.currency_yen_sharp, + Icons.currency_yuan, + Icons.currency_yuan_outlined, + Icons.currency_yuan_rounded, + Icons.currency_yuan_sharp, + Icons.curtains, + Icons.curtains_closed, + Icons.curtains_closed_outlined, + Icons.curtains_closed_rounded, + Icons.curtains_closed_sharp, + Icons.curtains_outlined, + Icons.curtains_rounded, + Icons.curtains_sharp, + Icons.cut, + Icons.cut_outlined, + Icons.cut_rounded, + Icons.cut_sharp, + Icons.cyclone, + Icons.cyclone_outlined, + Icons.cyclone_rounded, + Icons.cyclone_sharp, + Icons.dangerous, + Icons.dangerous_outlined, + Icons.dangerous_rounded, + Icons.dangerous_sharp, + Icons.dark_mode, + Icons.dark_mode_outlined, + Icons.dark_mode_rounded, + Icons.dark_mode_sharp, + Icons.dashboard, + Icons.dashboard_customize, + Icons.dashboard_customize_outlined, + Icons.dashboard_customize_rounded, + Icons.dashboard_customize_sharp, + Icons.dashboard_outlined, + Icons.dashboard_rounded, + Icons.dashboard_sharp, + Icons.data_array, + Icons.data_array_outlined, + Icons.data_array_rounded, + Icons.data_array_sharp, + Icons.data_exploration, + Icons.data_exploration_outlined, + Icons.data_exploration_rounded, + Icons.data_exploration_sharp, + Icons.data_object, + Icons.data_object_outlined, + Icons.data_object_rounded, + Icons.data_object_sharp, + Icons.data_saver_off, + Icons.data_saver_off_outlined, + Icons.data_saver_off_rounded, + Icons.data_saver_off_sharp, + Icons.data_saver_on, + Icons.data_saver_on_outlined, + Icons.data_saver_on_rounded, + Icons.data_saver_on_sharp, + Icons.data_thresholding, + Icons.data_thresholding_outlined, + Icons.data_thresholding_rounded, + Icons.data_thresholding_sharp, + Icons.data_usage, + Icons.data_usage_outlined, + Icons.data_usage_rounded, + Icons.data_usage_sharp, + Icons.dataset, + Icons.dataset_linked, + Icons.dataset_linked_outlined, + Icons.dataset_linked_rounded, + Icons.dataset_linked_sharp, + Icons.dataset_outlined, + Icons.dataset_rounded, + Icons.dataset_sharp, + Icons.date_range, + Icons.date_range_outlined, + Icons.date_range_rounded, + Icons.date_range_sharp, + Icons.deblur, + Icons.deblur_outlined, + Icons.deblur_rounded, + Icons.deblur_sharp, + Icons.deck, + Icons.deck_outlined, + Icons.deck_rounded, + Icons.deck_sharp, + Icons.dehaze, + Icons.dehaze_outlined, + Icons.dehaze_rounded, + Icons.dehaze_sharp, + Icons.delete, + Icons.delete_forever, + Icons.delete_forever_outlined, + Icons.delete_forever_rounded, + Icons.delete_forever_sharp, + Icons.delete_outline, + Icons.delete_outline_outlined, + Icons.delete_outline_rounded, + Icons.delete_outline_sharp, + Icons.delete_outlined, + Icons.delete_rounded, + Icons.delete_sharp, + Icons.delete_sweep, + Icons.delete_sweep_outlined, + Icons.delete_sweep_rounded, + Icons.delete_sweep_sharp, + Icons.delivery_dining, + Icons.delivery_dining_outlined, + Icons.delivery_dining_rounded, + Icons.delivery_dining_sharp, + Icons.density_large, + Icons.density_large_outlined, + Icons.density_large_rounded, + Icons.density_large_sharp, + Icons.density_medium, + Icons.density_medium_outlined, + Icons.density_medium_rounded, + Icons.density_medium_sharp, + Icons.density_small, + Icons.density_small_outlined, + Icons.density_small_rounded, + Icons.density_small_sharp, + Icons.departure_board, + Icons.departure_board_outlined, + Icons.departure_board_rounded, + Icons.departure_board_sharp, + Icons.description, + Icons.description_outlined, + Icons.description_rounded, + Icons.description_sharp, + Icons.deselect, + Icons.deselect_outlined, + Icons.deselect_rounded, + Icons.deselect_sharp, + Icons.design_services, + Icons.design_services_outlined, + Icons.design_services_rounded, + Icons.design_services_sharp, + Icons.desk, + Icons.desk_outlined, + Icons.desk_rounded, + Icons.desk_sharp, + Icons.desktop_access_disabled, + Icons.desktop_access_disabled_outlined, + Icons.desktop_access_disabled_rounded, + Icons.desktop_access_disabled_sharp, + Icons.desktop_mac, + Icons.desktop_mac_outlined, + Icons.desktop_mac_rounded, + Icons.desktop_mac_sharp, + Icons.desktop_windows, + Icons.desktop_windows_outlined, + Icons.desktop_windows_rounded, + Icons.desktop_windows_sharp, + Icons.details, + Icons.details_outlined, + Icons.details_rounded, + Icons.details_sharp, + Icons.developer_board, + Icons.developer_board_off, + Icons.developer_board_off_outlined, + Icons.developer_board_off_rounded, + Icons.developer_board_off_sharp, + Icons.developer_board_outlined, + Icons.developer_board_rounded, + Icons.developer_board_sharp, + Icons.developer_mode, + Icons.developer_mode_outlined, + Icons.developer_mode_rounded, + Icons.developer_mode_sharp, + Icons.device_hub, + Icons.device_hub_outlined, + Icons.device_hub_rounded, + Icons.device_hub_sharp, + Icons.device_thermostat, + Icons.device_thermostat_outlined, + Icons.device_thermostat_rounded, + Icons.device_thermostat_sharp, + Icons.device_unknown, + Icons.device_unknown_outlined, + Icons.device_unknown_rounded, + Icons.device_unknown_sharp, + Icons.devices, + Icons.devices_fold, + Icons.devices_fold_outlined, + Icons.devices_fold_rounded, + Icons.devices_fold_sharp, + Icons.devices_other, + Icons.devices_other_outlined, + Icons.devices_other_rounded, + Icons.devices_other_sharp, + Icons.devices_outlined, + Icons.devices_rounded, + Icons.devices_sharp, + Icons.dew_point, + Icons.dialer_sip, + Icons.dialer_sip_outlined, + Icons.dialer_sip_rounded, + Icons.dialer_sip_sharp, + Icons.dialpad, + Icons.dialpad_outlined, + Icons.dialpad_rounded, + Icons.dialpad_sharp, + Icons.diamond, + Icons.diamond_outlined, + Icons.diamond_rounded, + Icons.diamond_sharp, + Icons.difference, + Icons.difference_outlined, + Icons.difference_rounded, + Icons.difference_sharp, + Icons.dining, + Icons.dining_outlined, + Icons.dining_rounded, + Icons.dining_sharp, + Icons.dinner_dining, + Icons.dinner_dining_outlined, + Icons.dinner_dining_rounded, + Icons.dinner_dining_sharp, + Icons.directions, + Icons.directions_bike, + Icons.directions_bike_outlined, + Icons.directions_bike_rounded, + Icons.directions_bike_sharp, + Icons.directions_boat, + Icons.directions_boat_filled, + Icons.directions_boat_filled_outlined, + Icons.directions_boat_filled_rounded, + Icons.directions_boat_filled_sharp, + Icons.directions_boat_outlined, + Icons.directions_boat_rounded, + Icons.directions_boat_sharp, + Icons.directions_bus, + Icons.directions_bus_filled, + Icons.directions_bus_filled_outlined, + Icons.directions_bus_filled_rounded, + Icons.directions_bus_filled_sharp, + Icons.directions_bus_outlined, + Icons.directions_bus_rounded, + Icons.directions_bus_sharp, + Icons.directions_car, + Icons.directions_car_filled, + Icons.directions_car_filled_outlined, + Icons.directions_car_filled_rounded, + Icons.directions_car_filled_sharp, + Icons.directions_car_outlined, + Icons.directions_car_rounded, + Icons.directions_car_sharp, + Icons.directions_ferry, + Icons.directions_ferry_outlined, + Icons.directions_ferry_rounded, + Icons.directions_ferry_sharp, + Icons.directions_off, + Icons.directions_off_outlined, + Icons.directions_off_rounded, + Icons.directions_off_sharp, + Icons.directions_outlined, + Icons.directions_railway, + Icons.directions_railway_filled, + Icons.directions_railway_filled_outlined, + Icons.directions_railway_filled_rounded, + Icons.directions_railway_filled_sharp, + Icons.directions_railway_outlined, + Icons.directions_railway_rounded, + Icons.directions_railway_sharp, + Icons.directions_rounded, + Icons.directions_run, + Icons.directions_run_outlined, + Icons.directions_run_rounded, + Icons.directions_run_sharp, + Icons.directions_sharp, + Icons.directions_subway, + Icons.directions_subway_filled, + Icons.directions_subway_filled_outlined, + Icons.directions_subway_filled_rounded, + Icons.directions_subway_filled_sharp, + Icons.directions_subway_outlined, + Icons.directions_subway_rounded, + Icons.directions_subway_sharp, + Icons.directions_train, + Icons.directions_train_outlined, + Icons.directions_train_rounded, + Icons.directions_train_sharp, + Icons.directions_transit, + Icons.directions_transit_filled, + Icons.directions_transit_filled_outlined, + Icons.directions_transit_filled_rounded, + Icons.directions_transit_filled_sharp, + Icons.directions_transit_outlined, + Icons.directions_transit_rounded, + Icons.directions_transit_sharp, + Icons.directions_walk, + Icons.directions_walk_outlined, + Icons.directions_walk_rounded, + Icons.directions_walk_sharp, + Icons.dirty_lens, + Icons.dirty_lens_outlined, + Icons.dirty_lens_rounded, + Icons.dirty_lens_sharp, + Icons.disabled_by_default, + Icons.disabled_by_default_outlined, + Icons.disabled_by_default_rounded, + Icons.disabled_by_default_sharp, + Icons.disabled_visible, + Icons.disabled_visible_outlined, + Icons.disabled_visible_rounded, + Icons.disabled_visible_sharp, + Icons.disc_full, + Icons.disc_full_outlined, + Icons.disc_full_rounded, + Icons.disc_full_sharp, + Icons.discord, + Icons.discord_outlined, + Icons.discord_rounded, + Icons.discord_sharp, + Icons.discount, + Icons.discount_outlined, + Icons.discount_rounded, + Icons.discount_sharp, + Icons.display_settings, + Icons.display_settings_outlined, + Icons.display_settings_rounded, + Icons.display_settings_sharp, + Icons.diversity_1, + Icons.diversity_1_outlined, + Icons.diversity_1_rounded, + Icons.diversity_1_sharp, + Icons.diversity_2, + Icons.diversity_2_outlined, + Icons.diversity_2_rounded, + Icons.diversity_2_sharp, + Icons.diversity_3, + Icons.diversity_3_outlined, + Icons.diversity_3_rounded, + Icons.diversity_3_sharp, + Icons.dnd_forwardslash, + Icons.dnd_forwardslash_outlined, + Icons.dnd_forwardslash_rounded, + Icons.dnd_forwardslash_sharp, + Icons.dns, + Icons.dns_outlined, + Icons.dns_rounded, + Icons.dns_sharp, + Icons.do_disturb, + Icons.do_disturb_alt, + Icons.do_disturb_alt_outlined, + Icons.do_disturb_alt_rounded, + Icons.do_disturb_alt_sharp, + Icons.do_disturb_off, + Icons.do_disturb_off_outlined, + Icons.do_disturb_off_rounded, + Icons.do_disturb_off_sharp, + Icons.do_disturb_on, + Icons.do_disturb_on_outlined, + Icons.do_disturb_on_rounded, + Icons.do_disturb_on_sharp, + Icons.do_disturb_outlined, + Icons.do_disturb_rounded, + Icons.do_disturb_sharp, + Icons.do_not_disturb, + Icons.do_not_disturb_alt, + Icons.do_not_disturb_alt_outlined, + Icons.do_not_disturb_alt_rounded, + Icons.do_not_disturb_alt_sharp, + Icons.do_not_disturb_off, + Icons.do_not_disturb_off_outlined, + Icons.do_not_disturb_off_rounded, + Icons.do_not_disturb_off_sharp, + Icons.do_not_disturb_on, + Icons.do_not_disturb_on_outlined, + Icons.do_not_disturb_on_rounded, + Icons.do_not_disturb_on_sharp, + Icons.do_not_disturb_on_total_silence, + Icons.do_not_disturb_on_total_silence_outlined, + Icons.do_not_disturb_on_total_silence_rounded, + Icons.do_not_disturb_on_total_silence_sharp, + Icons.do_not_disturb_outlined, + Icons.do_not_disturb_rounded, + Icons.do_not_disturb_sharp, + Icons.do_not_step, + Icons.do_not_step_outlined, + Icons.do_not_step_rounded, + Icons.do_not_step_sharp, + Icons.do_not_touch, + Icons.do_not_touch_outlined, + Icons.do_not_touch_rounded, + Icons.do_not_touch_sharp, + Icons.dock, + Icons.dock_outlined, + Icons.dock_rounded, + Icons.dock_sharp, + Icons.document_scanner, + Icons.document_scanner_outlined, + Icons.document_scanner_rounded, + Icons.document_scanner_sharp, + Icons.domain, + Icons.domain_add, + Icons.domain_add_outlined, + Icons.domain_add_rounded, + Icons.domain_add_sharp, + Icons.domain_disabled, + Icons.domain_disabled_outlined, + Icons.domain_disabled_rounded, + Icons.domain_disabled_sharp, + Icons.domain_outlined, + Icons.domain_rounded, + Icons.domain_sharp, + Icons.domain_verification, + Icons.domain_verification_outlined, + Icons.domain_verification_rounded, + Icons.domain_verification_sharp, + Icons.done, + Icons.done_all, + Icons.done_all_outlined, + Icons.done_all_rounded, + Icons.done_all_sharp, + Icons.done_outline, + Icons.done_outline_outlined, + Icons.done_outline_rounded, + Icons.done_outline_sharp, + Icons.done_outlined, + Icons.done_rounded, + Icons.done_sharp, + Icons.donut_large, + Icons.donut_large_outlined, + Icons.donut_large_rounded, + Icons.donut_large_sharp, + Icons.donut_small, + Icons.donut_small_outlined, + Icons.donut_small_rounded, + Icons.donut_small_sharp, + Icons.door_back_door, + Icons.door_back_door_outlined, + Icons.door_back_door_rounded, + Icons.door_back_door_sharp, + Icons.door_front_door, + Icons.door_front_door_outlined, + Icons.door_front_door_rounded, + Icons.door_front_door_sharp, + Icons.door_sliding, + Icons.door_sliding_outlined, + Icons.door_sliding_rounded, + Icons.door_sliding_sharp, + Icons.doorbell, + Icons.doorbell_outlined, + Icons.doorbell_rounded, + Icons.doorbell_sharp, + Icons.double_arrow, + Icons.double_arrow_outlined, + Icons.double_arrow_rounded, + Icons.double_arrow_sharp, + Icons.downhill_skiing, + Icons.downhill_skiing_outlined, + Icons.downhill_skiing_rounded, + Icons.downhill_skiing_sharp, + Icons.download, + Icons.download_done, + Icons.download_done_outlined, + Icons.download_done_rounded, + Icons.download_done_sharp, + Icons.download_for_offline, + Icons.download_for_offline_outlined, + Icons.download_for_offline_rounded, + Icons.download_for_offline_sharp, + Icons.download_outlined, + Icons.download_rounded, + Icons.download_sharp, + Icons.downloading, + Icons.downloading_outlined, + Icons.downloading_rounded, + Icons.downloading_sharp, + Icons.drafts, + Icons.drafts_outlined, + Icons.drafts_rounded, + Icons.drafts_sharp, + Icons.drag_handle, + Icons.drag_handle_outlined, + Icons.drag_handle_rounded, + Icons.drag_handle_sharp, + Icons.drag_indicator, + Icons.drag_indicator_outlined, + Icons.drag_indicator_rounded, + Icons.drag_indicator_sharp, + Icons.draw, + Icons.draw_outlined, + Icons.draw_rounded, + Icons.draw_sharp, + Icons.drive_eta, + Icons.drive_eta_outlined, + Icons.drive_eta_rounded, + Icons.drive_eta_sharp, + Icons.drive_file_move, + Icons.drive_file_move_outline, + Icons.drive_file_move_outlined, + Icons.drive_file_move_rounded, + Icons.drive_file_move_rtl, + Icons.drive_file_move_rtl_outlined, + Icons.drive_file_move_rtl_rounded, + Icons.drive_file_move_rtl_sharp, + Icons.drive_file_move_sharp, + Icons.drive_file_rename_outline, + Icons.drive_file_rename_outline_outlined, + Icons.drive_file_rename_outline_rounded, + Icons.drive_file_rename_outline_sharp, + Icons.drive_folder_upload, + Icons.drive_folder_upload_outlined, + Icons.drive_folder_upload_rounded, + Icons.drive_folder_upload_sharp, + Icons.dry, + Icons.dry_cleaning, + Icons.dry_cleaning_outlined, + Icons.dry_cleaning_rounded, + Icons.dry_cleaning_sharp, + Icons.dry_outlined, + Icons.dry_rounded, + Icons.dry_sharp, + Icons.duo, + Icons.duo_outlined, + Icons.duo_rounded, + Icons.duo_sharp, + Icons.dvr, + Icons.dvr_outlined, + Icons.dvr_rounded, + Icons.dvr_sharp, + Icons.dynamic_feed, + Icons.dynamic_feed_outlined, + Icons.dynamic_feed_rounded, + Icons.dynamic_feed_sharp, + Icons.dynamic_form, + Icons.dynamic_form_outlined, + Icons.dynamic_form_rounded, + Icons.dynamic_form_sharp, + Icons.e_mobiledata, + Icons.e_mobiledata_outlined, + Icons.e_mobiledata_rounded, + Icons.e_mobiledata_sharp, + Icons.earbuds, + Icons.earbuds_battery, + Icons.earbuds_battery_outlined, + Icons.earbuds_battery_rounded, + Icons.earbuds_battery_sharp, + Icons.earbuds_outlined, + Icons.earbuds_rounded, + Icons.earbuds_sharp, + Icons.east, + Icons.east_outlined, + Icons.east_rounded, + Icons.east_sharp, + Icons.eco, + Icons.eco_outlined, + Icons.eco_rounded, + Icons.eco_sharp, + Icons.edgesensor_high, + Icons.edgesensor_high_outlined, + Icons.edgesensor_high_rounded, + Icons.edgesensor_high_sharp, + Icons.edgesensor_low, + Icons.edgesensor_low_outlined, + Icons.edgesensor_low_rounded, + Icons.edgesensor_low_sharp, + Icons.edit, + Icons.edit_attributes, + Icons.edit_attributes_outlined, + Icons.edit_attributes_rounded, + Icons.edit_attributes_sharp, + Icons.edit_calendar, + Icons.edit_calendar_outlined, + Icons.edit_calendar_rounded, + Icons.edit_calendar_sharp, + Icons.edit_document, + Icons.edit_location, + Icons.edit_location_alt, + Icons.edit_location_alt_outlined, + Icons.edit_location_alt_rounded, + Icons.edit_location_alt_sharp, + Icons.edit_location_outlined, + Icons.edit_location_rounded, + Icons.edit_location_sharp, + Icons.edit_note, + Icons.edit_note_outlined, + Icons.edit_note_rounded, + Icons.edit_note_sharp, + Icons.edit_notifications, + Icons.edit_notifications_outlined, + Icons.edit_notifications_rounded, + Icons.edit_notifications_sharp, + Icons.edit_off, + Icons.edit_off_outlined, + Icons.edit_off_rounded, + Icons.edit_off_sharp, + Icons.edit_outlined, + Icons.edit_road, + Icons.edit_road_outlined, + Icons.edit_road_rounded, + Icons.edit_road_sharp, + Icons.edit_rounded, + Icons.edit_sharp, + Icons.edit_square, + Icons.egg, + Icons.egg_alt, + Icons.egg_alt_outlined, + Icons.egg_alt_rounded, + Icons.egg_alt_sharp, + Icons.egg_outlined, + Icons.egg_rounded, + Icons.egg_sharp, + Icons.eight_k, + Icons.eight_k_outlined, + Icons.eight_k_plus, + Icons.eight_k_plus_outlined, + Icons.eight_k_plus_rounded, + Icons.eight_k_plus_sharp, + Icons.eight_k_rounded, + Icons.eight_k_sharp, + Icons.eight_mp, + Icons.eight_mp_outlined, + Icons.eight_mp_rounded, + Icons.eight_mp_sharp, + Icons.eighteen_mp, + Icons.eighteen_mp_outlined, + Icons.eighteen_mp_rounded, + Icons.eighteen_mp_sharp, + Icons.eighteen_up_rating, + Icons.eighteen_up_rating_outlined, + Icons.eighteen_up_rating_rounded, + Icons.eighteen_up_rating_sharp, + Icons.eject, + Icons.eject_outlined, + Icons.eject_rounded, + Icons.eject_sharp, + Icons.elderly, + Icons.elderly_outlined, + Icons.elderly_rounded, + Icons.elderly_sharp, + Icons.elderly_woman, + Icons.elderly_woman_outlined, + Icons.elderly_woman_rounded, + Icons.elderly_woman_sharp, + Icons.electric_bike, + Icons.electric_bike_outlined, + Icons.electric_bike_rounded, + Icons.electric_bike_sharp, + Icons.electric_bolt, + Icons.electric_bolt_outlined, + Icons.electric_bolt_rounded, + Icons.electric_bolt_sharp, + Icons.electric_car, + Icons.electric_car_outlined, + Icons.electric_car_rounded, + Icons.electric_car_sharp, + Icons.electric_meter, + Icons.electric_meter_outlined, + Icons.electric_meter_rounded, + Icons.electric_meter_sharp, + Icons.electric_moped, + Icons.electric_moped_outlined, + Icons.electric_moped_rounded, + Icons.electric_moped_sharp, + Icons.electric_rickshaw, + Icons.electric_rickshaw_outlined, + Icons.electric_rickshaw_rounded, + Icons.electric_rickshaw_sharp, + Icons.electric_scooter, + Icons.electric_scooter_outlined, + Icons.electric_scooter_rounded, + Icons.electric_scooter_sharp, + Icons.electrical_services, + Icons.electrical_services_outlined, + Icons.electrical_services_rounded, + Icons.electrical_services_sharp, + Icons.elevator, + Icons.elevator_outlined, + Icons.elevator_rounded, + Icons.elevator_sharp, + Icons.eleven_mp, + Icons.eleven_mp_outlined, + Icons.eleven_mp_rounded, + Icons.eleven_mp_sharp, + Icons.email, + Icons.email_outlined, + Icons.email_rounded, + Icons.email_sharp, + Icons.emergency, + Icons.emergency_outlined, + Icons.emergency_recording, + Icons.emergency_recording_outlined, + Icons.emergency_recording_rounded, + Icons.emergency_recording_sharp, + Icons.emergency_rounded, + Icons.emergency_share, + Icons.emergency_share_outlined, + Icons.emergency_share_rounded, + Icons.emergency_share_sharp, + Icons.emergency_sharp, + Icons.emoji_emotions, + Icons.emoji_emotions_outlined, + Icons.emoji_emotions_rounded, + Icons.emoji_emotions_sharp, + Icons.emoji_events, + Icons.emoji_events_outlined, + Icons.emoji_events_rounded, + Icons.emoji_events_sharp, + Icons.emoji_flags, + Icons.emoji_flags_outlined, + Icons.emoji_flags_rounded, + Icons.emoji_flags_sharp, + Icons.emoji_food_beverage, + Icons.emoji_food_beverage_outlined, + Icons.emoji_food_beverage_rounded, + Icons.emoji_food_beverage_sharp, + Icons.emoji_nature, + Icons.emoji_nature_outlined, + Icons.emoji_nature_rounded, + Icons.emoji_nature_sharp, + Icons.emoji_objects, + Icons.emoji_objects_outlined, + Icons.emoji_objects_rounded, + Icons.emoji_objects_sharp, + Icons.emoji_people, + Icons.emoji_people_outlined, + Icons.emoji_people_rounded, + Icons.emoji_people_sharp, + Icons.emoji_symbols, + Icons.emoji_symbols_outlined, + Icons.emoji_symbols_rounded, + Icons.emoji_symbols_sharp, + Icons.emoji_transportation, + Icons.emoji_transportation_outlined, + Icons.emoji_transportation_rounded, + Icons.emoji_transportation_sharp, + Icons.energy_savings_leaf, + Icons.energy_savings_leaf_outlined, + Icons.energy_savings_leaf_rounded, + Icons.energy_savings_leaf_sharp, + Icons.engineering, + Icons.engineering_outlined, + Icons.engineering_rounded, + Icons.engineering_sharp, + Icons.enhance_photo_translate, + Icons.enhance_photo_translate_outlined, + Icons.enhance_photo_translate_rounded, + Icons.enhance_photo_translate_sharp, + Icons.enhanced_encryption, + Icons.enhanced_encryption_outlined, + Icons.enhanced_encryption_rounded, + Icons.enhanced_encryption_sharp, + Icons.equalizer, + Icons.equalizer_outlined, + Icons.equalizer_rounded, + Icons.equalizer_sharp, + Icons.error, + Icons.error_outline, + Icons.error_outline_outlined, + Icons.error_outline_rounded, + Icons.error_outline_sharp, + Icons.error_outlined, + Icons.error_rounded, + Icons.error_sharp, + Icons.escalator, + Icons.escalator_outlined, + Icons.escalator_rounded, + Icons.escalator_sharp, + Icons.escalator_warning, + Icons.escalator_warning_outlined, + Icons.escalator_warning_rounded, + Icons.escalator_warning_sharp, + Icons.euro, + Icons.euro_outlined, + Icons.euro_rounded, + Icons.euro_sharp, + Icons.euro_symbol, + Icons.euro_symbol_outlined, + Icons.euro_symbol_rounded, + Icons.euro_symbol_sharp, + Icons.ev_station, + Icons.ev_station_outlined, + Icons.ev_station_rounded, + Icons.ev_station_sharp, + Icons.event, + Icons.event_available, + Icons.event_available_outlined, + Icons.event_available_rounded, + Icons.event_available_sharp, + Icons.event_busy, + Icons.event_busy_outlined, + Icons.event_busy_rounded, + Icons.event_busy_sharp, + Icons.event_note, + Icons.event_note_outlined, + Icons.event_note_rounded, + Icons.event_note_sharp, + Icons.event_outlined, + Icons.event_repeat, + Icons.event_repeat_outlined, + Icons.event_repeat_rounded, + Icons.event_repeat_sharp, + Icons.event_rounded, + Icons.event_seat, + Icons.event_seat_outlined, + Icons.event_seat_rounded, + Icons.event_seat_sharp, + Icons.event_sharp, + Icons.exit_to_app, + Icons.exit_to_app_outlined, + Icons.exit_to_app_rounded, + Icons.exit_to_app_sharp, + Icons.expand, + Icons.expand_circle_down, + Icons.expand_circle_down_outlined, + Icons.expand_circle_down_rounded, + Icons.expand_circle_down_sharp, + Icons.expand_less, + Icons.expand_less_outlined, + Icons.expand_less_rounded, + Icons.expand_less_sharp, + Icons.expand_more, + Icons.expand_more_outlined, + Icons.expand_more_rounded, + Icons.expand_more_sharp, + Icons.expand_outlined, + Icons.expand_rounded, + Icons.expand_sharp, + Icons.explicit, + Icons.explicit_outlined, + Icons.explicit_rounded, + Icons.explicit_sharp, + Icons.explore, + Icons.explore_off, + Icons.explore_off_outlined, + Icons.explore_off_rounded, + Icons.explore_off_sharp, + Icons.explore_outlined, + Icons.explore_rounded, + Icons.explore_sharp, + Icons.exposure, + Icons.exposure_minus_1, + Icons.exposure_minus_1_outlined, + Icons.exposure_minus_1_rounded, + Icons.exposure_minus_1_sharp, + Icons.exposure_minus_2, + Icons.exposure_minus_2_outlined, + Icons.exposure_minus_2_rounded, + Icons.exposure_minus_2_sharp, + Icons.exposure_neg_1, + Icons.exposure_neg_1_outlined, + Icons.exposure_neg_1_rounded, + Icons.exposure_neg_1_sharp, + Icons.exposure_neg_2, + Icons.exposure_neg_2_outlined, + Icons.exposure_neg_2_rounded, + Icons.exposure_neg_2_sharp, + Icons.exposure_outlined, + Icons.exposure_plus_1, + Icons.exposure_plus_1_outlined, + Icons.exposure_plus_1_rounded, + Icons.exposure_plus_1_sharp, + Icons.exposure_plus_2, + Icons.exposure_plus_2_outlined, + Icons.exposure_plus_2_rounded, + Icons.exposure_plus_2_sharp, + Icons.exposure_rounded, + Icons.exposure_sharp, + Icons.exposure_zero, + Icons.exposure_zero_outlined, + Icons.exposure_zero_rounded, + Icons.exposure_zero_sharp, + Icons.extension, + Icons.extension_off, + Icons.extension_off_outlined, + Icons.extension_off_rounded, + Icons.extension_off_sharp, + Icons.extension_outlined, + Icons.extension_rounded, + Icons.extension_sharp, + Icons.face, + Icons.face_2, + Icons.face_2_outlined, + Icons.face_2_rounded, + Icons.face_2_sharp, + Icons.face_3, + Icons.face_3_outlined, + Icons.face_3_rounded, + Icons.face_3_sharp, + Icons.face_4, + Icons.face_4_outlined, + Icons.face_4_rounded, + Icons.face_4_sharp, + Icons.face_5, + Icons.face_5_outlined, + Icons.face_5_rounded, + Icons.face_5_sharp, + Icons.face_6, + Icons.face_6_outlined, + Icons.face_6_rounded, + Icons.face_6_sharp, + Icons.face_outlined, + Icons.face_retouching_natural, + Icons.face_retouching_natural_outlined, + Icons.face_retouching_natural_rounded, + Icons.face_retouching_natural_sharp, + Icons.face_retouching_off, + Icons.face_retouching_off_outlined, + Icons.face_retouching_off_rounded, + Icons.face_retouching_off_sharp, + Icons.face_rounded, + Icons.face_sharp, + Icons.face_unlock_outlined, + Icons.face_unlock_rounded, + Icons.face_unlock_sharp, + Icons.facebook, + Icons.facebook_outlined, + Icons.facebook_rounded, + Icons.facebook_sharp, + Icons.fact_check, + Icons.fact_check_outlined, + Icons.fact_check_rounded, + Icons.fact_check_sharp, + Icons.factory, + Icons.factory_outlined, + Icons.factory_rounded, + Icons.factory_sharp, + Icons.family_restroom, + Icons.family_restroom_outlined, + Icons.family_restroom_rounded, + Icons.family_restroom_sharp, + Icons.fast_forward, + Icons.fast_forward_outlined, + Icons.fast_forward_rounded, + Icons.fast_forward_sharp, + Icons.fast_rewind, + Icons.fast_rewind_outlined, + Icons.fast_rewind_rounded, + Icons.fast_rewind_sharp, + Icons.fastfood, + Icons.fastfood_outlined, + Icons.fastfood_rounded, + Icons.fastfood_sharp, + Icons.favorite, + Icons.favorite_border, + Icons.favorite_border_outlined, + Icons.favorite_border_rounded, + Icons.favorite_border_sharp, + Icons.favorite_outline, + Icons.favorite_outline_outlined, + Icons.favorite_outline_rounded, + Icons.favorite_outline_sharp, + Icons.favorite_outlined, + Icons.favorite_rounded, + Icons.favorite_sharp, + Icons.fax, + Icons.fax_outlined, + Icons.fax_rounded, + Icons.fax_sharp, + Icons.featured_play_list, + Icons.featured_play_list_outlined, + Icons.featured_play_list_rounded, + Icons.featured_play_list_sharp, + Icons.featured_video, + Icons.featured_video_outlined, + Icons.featured_video_rounded, + Icons.featured_video_sharp, + Icons.feed, + Icons.feed_outlined, + Icons.feed_rounded, + Icons.feed_sharp, + Icons.feedback, + Icons.feedback_outlined, + Icons.feedback_rounded, + Icons.feedback_sharp, + Icons.female, + Icons.female_outlined, + Icons.female_rounded, + Icons.female_sharp, + Icons.fence, + Icons.fence_outlined, + Icons.fence_rounded, + Icons.fence_sharp, + Icons.festival, + Icons.festival_outlined, + Icons.festival_rounded, + Icons.festival_sharp, + Icons.fiber_dvr, + Icons.fiber_dvr_outlined, + Icons.fiber_dvr_rounded, + Icons.fiber_dvr_sharp, + Icons.fiber_manual_record, + Icons.fiber_manual_record_outlined, + Icons.fiber_manual_record_rounded, + Icons.fiber_manual_record_sharp, + Icons.fiber_new, + Icons.fiber_new_outlined, + Icons.fiber_new_rounded, + Icons.fiber_new_sharp, + Icons.fiber_pin, + Icons.fiber_pin_outlined, + Icons.fiber_pin_rounded, + Icons.fiber_pin_sharp, + Icons.fiber_smart_record, + Icons.fiber_smart_record_outlined, + Icons.fiber_smart_record_rounded, + Icons.fiber_smart_record_sharp, + Icons.fifteen_mp, + Icons.fifteen_mp_outlined, + Icons.fifteen_mp_rounded, + Icons.fifteen_mp_sharp, + Icons.file_copy, + Icons.file_copy_outlined, + Icons.file_copy_rounded, + Icons.file_copy_sharp, + Icons.file_download, + Icons.file_download_done, + Icons.file_download_done_outlined, + Icons.file_download_done_rounded, + Icons.file_download_done_sharp, + Icons.file_download_off, + Icons.file_download_off_outlined, + Icons.file_download_off_rounded, + Icons.file_download_off_sharp, + Icons.file_download_outlined, + Icons.file_download_rounded, + Icons.file_download_sharp, + Icons.file_open, + Icons.file_open_outlined, + Icons.file_open_rounded, + Icons.file_open_sharp, + Icons.file_present, + Icons.file_present_outlined, + Icons.file_present_rounded, + Icons.file_present_sharp, + Icons.file_upload, + Icons.file_upload_off, + Icons.file_upload_outlined, + Icons.file_upload_rounded, + Icons.file_upload_sharp, + Icons.filter, + Icons.filter_1, + Icons.filter_1_outlined, + Icons.filter_1_rounded, + Icons.filter_1_sharp, + Icons.filter_2, + Icons.filter_2_outlined, + Icons.filter_2_rounded, + Icons.filter_2_sharp, + Icons.filter_3, + Icons.filter_3_outlined, + Icons.filter_3_rounded, + Icons.filter_3_sharp, + Icons.filter_4, + Icons.filter_4_outlined, + Icons.filter_4_rounded, + Icons.filter_4_sharp, + Icons.filter_5, + Icons.filter_5_outlined, + Icons.filter_5_rounded, + Icons.filter_5_sharp, + Icons.filter_6, + Icons.filter_6_outlined, + Icons.filter_6_rounded, + Icons.filter_6_sharp, + Icons.filter_7, + Icons.filter_7_outlined, + Icons.filter_7_rounded, + Icons.filter_7_sharp, + Icons.filter_8, + Icons.filter_8_outlined, + Icons.filter_8_rounded, + Icons.filter_8_sharp, + Icons.filter_9, + Icons.filter_9_outlined, + Icons.filter_9_plus, + Icons.filter_9_plus_outlined, + Icons.filter_9_plus_rounded, + Icons.filter_9_plus_sharp, + Icons.filter_9_rounded, + Icons.filter_9_sharp, + Icons.filter_alt, + Icons.filter_alt_off, + Icons.filter_alt_off_outlined, + Icons.filter_alt_off_rounded, + Icons.filter_alt_off_sharp, + Icons.filter_alt_outlined, + Icons.filter_alt_rounded, + Icons.filter_alt_sharp, + Icons.filter_b_and_w, + Icons.filter_b_and_w_outlined, + Icons.filter_b_and_w_rounded, + Icons.filter_b_and_w_sharp, + Icons.filter_center_focus, + Icons.filter_center_focus_outlined, + Icons.filter_center_focus_rounded, + Icons.filter_center_focus_sharp, + Icons.filter_drama, + Icons.filter_drama_outlined, + Icons.filter_drama_rounded, + Icons.filter_drama_sharp, + Icons.filter_frames, + Icons.filter_frames_outlined, + Icons.filter_frames_rounded, + Icons.filter_frames_sharp, + Icons.filter_hdr, + Icons.filter_hdr_outlined, + Icons.filter_hdr_rounded, + Icons.filter_hdr_sharp, + Icons.filter_list, + Icons.filter_list_alt, + Icons.filter_list_off, + Icons.filter_list_off_outlined, + Icons.filter_list_off_rounded, + Icons.filter_list_off_sharp, + Icons.filter_list_outlined, + Icons.filter_list_rounded, + Icons.filter_list_sharp, + Icons.filter_none, + Icons.filter_none_outlined, + Icons.filter_none_rounded, + Icons.filter_none_sharp, + Icons.filter_outlined, + Icons.filter_rounded, + Icons.filter_sharp, + Icons.filter_tilt_shift, + Icons.filter_tilt_shift_outlined, + Icons.filter_tilt_shift_rounded, + Icons.filter_tilt_shift_sharp, + Icons.filter_vintage, + Icons.filter_vintage_outlined, + Icons.filter_vintage_rounded, + Icons.filter_vintage_sharp, + Icons.find_in_page, + Icons.find_in_page_outlined, + Icons.find_in_page_rounded, + Icons.find_in_page_sharp, + Icons.find_replace, + Icons.find_replace_outlined, + Icons.find_replace_rounded, + Icons.find_replace_sharp, + Icons.fingerprint, + Icons.fingerprint_outlined, + Icons.fingerprint_rounded, + Icons.fingerprint_sharp, + Icons.fire_extinguisher, + Icons.fire_extinguisher_outlined, + Icons.fire_extinguisher_rounded, + Icons.fire_extinguisher_sharp, + Icons.fire_hydrant, + Icons.fire_hydrant_alt, + Icons.fire_hydrant_alt_outlined, + Icons.fire_hydrant_alt_rounded, + Icons.fire_hydrant_alt_sharp, + Icons.fire_truck, + Icons.fire_truck_outlined, + Icons.fire_truck_rounded, + Icons.fire_truck_sharp, + Icons.fireplace, + Icons.fireplace_outlined, + Icons.fireplace_rounded, + Icons.fireplace_sharp, + Icons.first_page, + Icons.first_page_outlined, + Icons.first_page_rounded, + Icons.first_page_sharp, + Icons.fit_screen, + Icons.fit_screen_outlined, + Icons.fit_screen_rounded, + Icons.fit_screen_sharp, + Icons.fitbit, + Icons.fitbit_outlined, + Icons.fitbit_rounded, + Icons.fitbit_sharp, + Icons.fitness_center, + Icons.fitness_center_outlined, + Icons.fitness_center_rounded, + Icons.fitness_center_sharp, + Icons.five_g, + Icons.five_g_outlined, + Icons.five_g_rounded, + Icons.five_g_sharp, + Icons.five_k, + Icons.five_k_outlined, + Icons.five_k_plus, + Icons.five_k_plus_outlined, + Icons.five_k_plus_rounded, + Icons.five_k_plus_sharp, + Icons.five_k_rounded, + Icons.five_k_sharp, + Icons.five_mp, + Icons.five_mp_outlined, + Icons.five_mp_rounded, + Icons.five_mp_sharp, + Icons.flag, + Icons.flag_circle, + Icons.flag_circle_outlined, + Icons.flag_circle_rounded, + Icons.flag_circle_sharp, + Icons.flag_outlined, + Icons.flag_rounded, + Icons.flag_sharp, + Icons.flaky, + Icons.flaky_outlined, + Icons.flaky_rounded, + Icons.flaky_sharp, + Icons.flare, + Icons.flare_outlined, + Icons.flare_rounded, + Icons.flare_sharp, + Icons.flash_auto, + Icons.flash_auto_outlined, + Icons.flash_auto_rounded, + Icons.flash_auto_sharp, + Icons.flash_off, + Icons.flash_off_outlined, + Icons.flash_off_rounded, + Icons.flash_off_sharp, + Icons.flash_on, + Icons.flash_on_outlined, + Icons.flash_on_rounded, + Icons.flash_on_sharp, + Icons.flashlight_off, + Icons.flashlight_off_outlined, + Icons.flashlight_off_rounded, + Icons.flashlight_off_sharp, + Icons.flashlight_on, + Icons.flashlight_on_outlined, + Icons.flashlight_on_rounded, + Icons.flashlight_on_sharp, + Icons.flatware, + Icons.flatware_outlined, + Icons.flatware_rounded, + Icons.flatware_sharp, + Icons.flight, + Icons.flight_class, + Icons.flight_class_outlined, + Icons.flight_class_rounded, + Icons.flight_class_sharp, + Icons.flight_land, + Icons.flight_land_outlined, + Icons.flight_land_rounded, + Icons.flight_land_sharp, + Icons.flight_outlined, + Icons.flight_rounded, + Icons.flight_sharp, + Icons.flight_takeoff, + Icons.flight_takeoff_outlined, + Icons.flight_takeoff_rounded, + Icons.flight_takeoff_sharp, + Icons.flip, + Icons.flip_camera_android, + Icons.flip_camera_android_outlined, + Icons.flip_camera_android_rounded, + Icons.flip_camera_android_sharp, + Icons.flip_camera_ios, + Icons.flip_camera_ios_outlined, + Icons.flip_camera_ios_rounded, + Icons.flip_camera_ios_sharp, + Icons.flip_outlined, + Icons.flip_rounded, + Icons.flip_sharp, + Icons.flip_to_back, + Icons.flip_to_back_outlined, + Icons.flip_to_back_rounded, + Icons.flip_to_back_sharp, + Icons.flip_to_front, + Icons.flip_to_front_outlined, + Icons.flip_to_front_rounded, + Icons.flip_to_front_sharp, + Icons.flood, + Icons.flood_outlined, + Icons.flood_rounded, + Icons.flood_sharp, + Icons.flourescent, + Icons.flourescent_outlined, + Icons.flourescent_rounded, + Icons.flourescent_sharp, + Icons.fluorescent, + Icons.fluorescent_outlined, + Icons.fluorescent_rounded, + Icons.fluorescent_sharp, + Icons.flutter_dash, + Icons.flutter_dash_outlined, + Icons.flutter_dash_rounded, + Icons.flutter_dash_sharp, + Icons.fmd_bad, + Icons.fmd_bad_outlined, + Icons.fmd_bad_rounded, + Icons.fmd_bad_sharp, + Icons.fmd_good, + Icons.fmd_good_outlined, + Icons.fmd_good_rounded, + Icons.fmd_good_sharp, + Icons.foggy, + Icons.folder, + Icons.folder_copy, + Icons.folder_copy_outlined, + Icons.folder_copy_rounded, + Icons.folder_copy_sharp, + Icons.folder_delete, + Icons.folder_delete_outlined, + Icons.folder_delete_rounded, + Icons.folder_delete_sharp, + Icons.folder_off, + Icons.folder_off_outlined, + Icons.folder_off_rounded, + Icons.folder_off_sharp, + Icons.folder_open, + Icons.folder_open_outlined, + Icons.folder_open_rounded, + Icons.folder_open_sharp, + Icons.folder_outlined, + Icons.folder_rounded, + Icons.folder_shared, + Icons.folder_shared_outlined, + Icons.folder_shared_rounded, + Icons.folder_shared_sharp, + Icons.folder_sharp, + Icons.folder_special, + Icons.folder_special_outlined, + Icons.folder_special_rounded, + Icons.folder_special_sharp, + Icons.folder_zip, + Icons.folder_zip_outlined, + Icons.folder_zip_rounded, + Icons.folder_zip_sharp, + Icons.follow_the_signs, + Icons.follow_the_signs_outlined, + Icons.follow_the_signs_rounded, + Icons.follow_the_signs_sharp, + Icons.font_download, + Icons.font_download_off, + Icons.font_download_off_outlined, + Icons.font_download_off_rounded, + Icons.font_download_off_sharp, + Icons.font_download_outlined, + Icons.font_download_rounded, + Icons.font_download_sharp, + Icons.food_bank, + Icons.food_bank_outlined, + Icons.food_bank_rounded, + Icons.food_bank_sharp, + Icons.forest, + Icons.forest_outlined, + Icons.forest_rounded, + Icons.forest_sharp, + Icons.fork_left, + Icons.fork_left_outlined, + Icons.fork_left_rounded, + Icons.fork_left_sharp, + Icons.fork_right, + Icons.fork_right_outlined, + Icons.fork_right_rounded, + Icons.fork_right_sharp, + Icons.forklift, + Icons.format_align_center, + Icons.format_align_center_outlined, + Icons.format_align_center_rounded, + Icons.format_align_center_sharp, + Icons.format_align_justify, + Icons.format_align_justify_outlined, + Icons.format_align_justify_rounded, + Icons.format_align_justify_sharp, + Icons.format_align_left, + Icons.format_align_left_outlined, + Icons.format_align_left_rounded, + Icons.format_align_left_sharp, + Icons.format_align_right, + Icons.format_align_right_outlined, + Icons.format_align_right_rounded, + Icons.format_align_right_sharp, + Icons.format_bold, + Icons.format_bold_outlined, + Icons.format_bold_rounded, + Icons.format_bold_sharp, + Icons.format_clear, + Icons.format_clear_outlined, + Icons.format_clear_rounded, + Icons.format_clear_sharp, + Icons.format_color_fill, + Icons.format_color_fill_outlined, + Icons.format_color_fill_rounded, + Icons.format_color_fill_sharp, + Icons.format_color_reset, + Icons.format_color_reset_outlined, + Icons.format_color_reset_rounded, + Icons.format_color_reset_sharp, + Icons.format_color_text, + Icons.format_color_text_outlined, + Icons.format_color_text_rounded, + Icons.format_color_text_sharp, + Icons.format_indent_decrease, + Icons.format_indent_decrease_outlined, + Icons.format_indent_decrease_rounded, + Icons.format_indent_decrease_sharp, + Icons.format_indent_increase, + Icons.format_indent_increase_outlined, + Icons.format_indent_increase_rounded, + Icons.format_indent_increase_sharp, + Icons.format_italic, + Icons.format_italic_outlined, + Icons.format_italic_rounded, + Icons.format_italic_sharp, + Icons.format_line_spacing, + Icons.format_line_spacing_outlined, + Icons.format_line_spacing_rounded, + Icons.format_line_spacing_sharp, + Icons.format_list_bulleted, + Icons.format_list_bulleted_add, + Icons.format_list_bulleted_outlined, + Icons.format_list_bulleted_rounded, + Icons.format_list_bulleted_sharp, + Icons.format_list_numbered, + Icons.format_list_numbered_outlined, + Icons.format_list_numbered_rounded, + Icons.format_list_numbered_rtl, + Icons.format_list_numbered_rtl_outlined, + Icons.format_list_numbered_rtl_rounded, + Icons.format_list_numbered_rtl_sharp, + Icons.format_list_numbered_sharp, + Icons.format_overline, + Icons.format_overline_outlined, + Icons.format_overline_rounded, + Icons.format_overline_sharp, + Icons.format_paint, + Icons.format_paint_outlined, + Icons.format_paint_rounded, + Icons.format_paint_sharp, + Icons.format_quote, + Icons.format_quote_outlined, + Icons.format_quote_rounded, + Icons.format_quote_sharp, + Icons.format_shapes, + Icons.format_shapes_outlined, + Icons.format_shapes_rounded, + Icons.format_shapes_sharp, + Icons.format_size, + Icons.format_size_outlined, + Icons.format_size_rounded, + Icons.format_size_sharp, + Icons.format_strikethrough, + Icons.format_strikethrough_outlined, + Icons.format_strikethrough_rounded, + Icons.format_strikethrough_sharp, + Icons.format_textdirection_l_to_r, + Icons.format_textdirection_l_to_r_outlined, + Icons.format_textdirection_l_to_r_rounded, + Icons.format_textdirection_l_to_r_sharp, + Icons.format_textdirection_r_to_l, + Icons.format_textdirection_r_to_l_outlined, + Icons.format_textdirection_r_to_l_rounded, + Icons.format_textdirection_r_to_l_sharp, + Icons.format_underline, + Icons.format_underline_outlined, + Icons.format_underline_rounded, + Icons.format_underline_sharp, + Icons.format_underlined, + Icons.format_underlined_outlined, + Icons.format_underlined_rounded, + Icons.format_underlined_sharp, + Icons.fort, + Icons.fort_outlined, + Icons.fort_rounded, + Icons.fort_sharp, + Icons.forum, + Icons.forum_outlined, + Icons.forum_rounded, + Icons.forum_sharp, + Icons.forward, + Icons.forward_10, + Icons.forward_10_outlined, + Icons.forward_10_rounded, + Icons.forward_10_sharp, + Icons.forward_30, + Icons.forward_30_outlined, + Icons.forward_30_rounded, + Icons.forward_30_sharp, + Icons.forward_5, + Icons.forward_5_outlined, + Icons.forward_5_rounded, + Icons.forward_5_sharp, + Icons.forward_outlined, + Icons.forward_rounded, + Icons.forward_sharp, + Icons.forward_to_inbox, + Icons.forward_to_inbox_outlined, + Icons.forward_to_inbox_rounded, + Icons.forward_to_inbox_sharp, + Icons.foundation, + Icons.foundation_outlined, + Icons.foundation_rounded, + Icons.foundation_sharp, + Icons.four_g_mobiledata, + Icons.four_g_mobiledata_outlined, + Icons.four_g_mobiledata_rounded, + Icons.four_g_mobiledata_sharp, + Icons.four_g_plus_mobiledata, + Icons.four_g_plus_mobiledata_outlined, + Icons.four_g_plus_mobiledata_rounded, + Icons.four_g_plus_mobiledata_sharp, + Icons.four_k, + Icons.four_k_outlined, + Icons.four_k_plus, + Icons.four_k_plus_outlined, + Icons.four_k_plus_rounded, + Icons.four_k_plus_sharp, + Icons.four_k_rounded, + Icons.four_k_sharp, + Icons.four_mp, + Icons.four_mp_outlined, + Icons.four_mp_rounded, + Icons.four_mp_sharp, + Icons.fourteen_mp, + Icons.fourteen_mp_outlined, + Icons.fourteen_mp_rounded, + Icons.fourteen_mp_sharp, + Icons.free_breakfast, + Icons.free_breakfast_outlined, + Icons.free_breakfast_rounded, + Icons.free_breakfast_sharp, + Icons.free_cancellation, + Icons.free_cancellation_outlined, + Icons.free_cancellation_rounded, + Icons.free_cancellation_sharp, + Icons.front_hand, + Icons.front_hand_outlined, + Icons.front_hand_rounded, + Icons.front_hand_sharp, + Icons.front_loader, + Icons.fullscreen, + Icons.fullscreen_exit, + Icons.fullscreen_exit_outlined, + Icons.fullscreen_exit_rounded, + Icons.fullscreen_exit_sharp, + Icons.fullscreen_outlined, + Icons.fullscreen_rounded, + Icons.fullscreen_sharp, + Icons.functions, + Icons.functions_outlined, + Icons.functions_rounded, + Icons.functions_sharp, + Icons.g_mobiledata, + Icons.g_mobiledata_outlined, + Icons.g_mobiledata_rounded, + Icons.g_mobiledata_sharp, + Icons.g_translate, + Icons.g_translate_outlined, + Icons.g_translate_rounded, + Icons.g_translate_sharp, + Icons.gamepad, + Icons.gamepad_outlined, + Icons.gamepad_rounded, + Icons.gamepad_sharp, + Icons.games, + Icons.games_outlined, + Icons.games_rounded, + Icons.games_sharp, + Icons.garage, + Icons.garage_outlined, + Icons.garage_rounded, + Icons.garage_sharp, + Icons.gas_meter, + Icons.gas_meter_outlined, + Icons.gas_meter_rounded, + Icons.gas_meter_sharp, + Icons.gavel, + Icons.gavel_outlined, + Icons.gavel_rounded, + Icons.gavel_sharp, + Icons.generating_tokens, + Icons.generating_tokens_outlined, + Icons.generating_tokens_rounded, + Icons.generating_tokens_sharp, + Icons.gesture, + Icons.gesture_outlined, + Icons.gesture_rounded, + Icons.gesture_sharp, + Icons.get_app, + Icons.get_app_outlined, + Icons.get_app_rounded, + Icons.get_app_sharp, + Icons.gif, + Icons.gif_box, + Icons.gif_box_outlined, + Icons.gif_box_rounded, + Icons.gif_box_sharp, + Icons.gif_outlined, + Icons.gif_rounded, + Icons.gif_sharp, + Icons.girl, + Icons.girl_outlined, + Icons.girl_rounded, + Icons.girl_sharp, + Icons.gite, + Icons.gite_outlined, + Icons.gite_rounded, + Icons.gite_sharp, + Icons.golf_course, + Icons.golf_course_outlined, + Icons.golf_course_rounded, + Icons.golf_course_sharp, + Icons.gpp_bad, + Icons.gpp_bad_outlined, + Icons.gpp_bad_rounded, + Icons.gpp_bad_sharp, + Icons.gpp_good, + Icons.gpp_good_outlined, + Icons.gpp_good_rounded, + Icons.gpp_good_sharp, + Icons.gpp_maybe, + Icons.gpp_maybe_outlined, + Icons.gpp_maybe_rounded, + Icons.gpp_maybe_sharp, + Icons.gps_fixed, + Icons.gps_fixed_outlined, + Icons.gps_fixed_rounded, + Icons.gps_fixed_sharp, + Icons.gps_not_fixed, + Icons.gps_not_fixed_outlined, + Icons.gps_not_fixed_rounded, + Icons.gps_not_fixed_sharp, + Icons.gps_off, + Icons.gps_off_outlined, + Icons.gps_off_rounded, + Icons.gps_off_sharp, + Icons.grade, + Icons.grade_outlined, + Icons.grade_rounded, + Icons.grade_sharp, + Icons.gradient, + Icons.gradient_outlined, + Icons.gradient_rounded, + Icons.gradient_sharp, + Icons.grading, + Icons.grading_outlined, + Icons.grading_rounded, + Icons.grading_sharp, + Icons.grain, + Icons.grain_outlined, + Icons.grain_rounded, + Icons.grain_sharp, + Icons.graphic_eq, + Icons.graphic_eq_outlined, + Icons.graphic_eq_rounded, + Icons.graphic_eq_sharp, + Icons.grass, + Icons.grass_outlined, + Icons.grass_rounded, + Icons.grass_sharp, + Icons.grid_3x3, + Icons.grid_3x3_outlined, + Icons.grid_3x3_rounded, + Icons.grid_3x3_sharp, + Icons.grid_4x4, + Icons.grid_4x4_outlined, + Icons.grid_4x4_rounded, + Icons.grid_4x4_sharp, + Icons.grid_goldenratio, + Icons.grid_goldenratio_outlined, + Icons.grid_goldenratio_rounded, + Icons.grid_goldenratio_sharp, + Icons.grid_off, + Icons.grid_off_outlined, + Icons.grid_off_rounded, + Icons.grid_off_sharp, + Icons.grid_on, + Icons.grid_on_outlined, + Icons.grid_on_rounded, + Icons.grid_on_sharp, + Icons.grid_view, + Icons.grid_view_outlined, + Icons.grid_view_rounded, + Icons.grid_view_sharp, + Icons.group, + Icons.group_add, + Icons.group_add_outlined, + Icons.group_add_rounded, + Icons.group_add_sharp, + Icons.group_off, + Icons.group_off_outlined, + Icons.group_off_rounded, + Icons.group_off_sharp, + Icons.group_outlined, + Icons.group_remove, + Icons.group_remove_outlined, + Icons.group_remove_rounded, + Icons.group_remove_sharp, + Icons.group_rounded, + Icons.group_sharp, + Icons.group_work, + Icons.group_work_outlined, + Icons.group_work_rounded, + Icons.group_work_sharp, + Icons.groups, + Icons.groups_2, + Icons.groups_2_outlined, + Icons.groups_2_rounded, + Icons.groups_2_sharp, + Icons.groups_3, + Icons.groups_3_outlined, + Icons.groups_3_rounded, + Icons.groups_3_sharp, + Icons.groups_outlined, + Icons.groups_rounded, + Icons.groups_sharp, + Icons.h_mobiledata, + Icons.h_mobiledata_outlined, + Icons.h_mobiledata_rounded, + Icons.h_mobiledata_sharp, + Icons.h_plus_mobiledata, + Icons.h_plus_mobiledata_outlined, + Icons.h_plus_mobiledata_rounded, + Icons.h_plus_mobiledata_sharp, + Icons.hail, + Icons.hail_outlined, + Icons.hail_rounded, + Icons.hail_sharp, + Icons.handshake, + Icons.handshake_outlined, + Icons.handshake_rounded, + Icons.handshake_sharp, + Icons.handyman, + Icons.handyman_outlined, + Icons.handyman_rounded, + Icons.handyman_sharp, + Icons.hardware, + Icons.hardware_outlined, + Icons.hardware_rounded, + Icons.hardware_sharp, + Icons.hd, + Icons.hd_outlined, + Icons.hd_rounded, + Icons.hd_sharp, + Icons.hdr_auto, + Icons.hdr_auto_outlined, + Icons.hdr_auto_rounded, + Icons.hdr_auto_select, + Icons.hdr_auto_select_outlined, + Icons.hdr_auto_select_rounded, + Icons.hdr_auto_select_sharp, + Icons.hdr_auto_sharp, + Icons.hdr_enhanced_select, + Icons.hdr_enhanced_select_outlined, + Icons.hdr_enhanced_select_rounded, + Icons.hdr_enhanced_select_sharp, + Icons.hdr_off, + Icons.hdr_off_outlined, + Icons.hdr_off_rounded, + Icons.hdr_off_select, + Icons.hdr_off_select_outlined, + Icons.hdr_off_select_rounded, + Icons.hdr_off_select_sharp, + Icons.hdr_off_sharp, + Icons.hdr_on, + Icons.hdr_on_outlined, + Icons.hdr_on_rounded, + Icons.hdr_on_select, + Icons.hdr_on_select_outlined, + Icons.hdr_on_select_rounded, + Icons.hdr_on_select_sharp, + Icons.hdr_on_sharp, + Icons.hdr_plus, + Icons.hdr_plus_outlined, + Icons.hdr_plus_rounded, + Icons.hdr_plus_sharp, + Icons.hdr_strong, + Icons.hdr_strong_outlined, + Icons.hdr_strong_rounded, + Icons.hdr_strong_sharp, + Icons.hdr_weak, + Icons.hdr_weak_outlined, + Icons.hdr_weak_rounded, + Icons.hdr_weak_sharp, + Icons.headphones, + Icons.headphones_battery, + Icons.headphones_battery_outlined, + Icons.headphones_battery_rounded, + Icons.headphones_battery_sharp, + Icons.headphones_outlined, + Icons.headphones_rounded, + Icons.headphones_sharp, + Icons.headset, + Icons.headset_mic, + Icons.headset_mic_outlined, + Icons.headset_mic_rounded, + Icons.headset_mic_sharp, + Icons.headset_off, + Icons.headset_off_outlined, + Icons.headset_off_rounded, + Icons.headset_off_sharp, + Icons.headset_outlined, + Icons.headset_rounded, + Icons.headset_sharp, + Icons.healing, + Icons.healing_outlined, + Icons.healing_rounded, + Icons.healing_sharp, + Icons.health_and_safety, + Icons.health_and_safety_outlined, + Icons.health_and_safety_rounded, + Icons.health_and_safety_sharp, + Icons.hearing, + Icons.hearing_disabled, + Icons.hearing_disabled_outlined, + Icons.hearing_disabled_rounded, + Icons.hearing_disabled_sharp, + Icons.hearing_outlined, + Icons.hearing_rounded, + Icons.hearing_sharp, + Icons.heart_broken, + Icons.heart_broken_outlined, + Icons.heart_broken_rounded, + Icons.heart_broken_sharp, + Icons.heat_pump, + Icons.heat_pump_outlined, + Icons.heat_pump_rounded, + Icons.heat_pump_sharp, + Icons.height, + Icons.height_outlined, + Icons.height_rounded, + Icons.height_sharp, + Icons.help, + Icons.help_center, + Icons.help_center_outlined, + Icons.help_center_rounded, + Icons.help_center_sharp, + Icons.help_outline, + Icons.help_outline_outlined, + Icons.help_outline_rounded, + Icons.help_outline_sharp, + Icons.help_outlined, + Icons.help_rounded, + Icons.help_sharp, + Icons.hevc, + Icons.hevc_outlined, + Icons.hevc_rounded, + Icons.hevc_sharp, + Icons.hexagon, + Icons.hexagon_outlined, + Icons.hexagon_rounded, + Icons.hexagon_sharp, + Icons.hide_image, + Icons.hide_image_outlined, + Icons.hide_image_rounded, + Icons.hide_image_sharp, + Icons.hide_source, + Icons.hide_source_outlined, + Icons.hide_source_rounded, + Icons.hide_source_sharp, + Icons.high_quality, + Icons.high_quality_outlined, + Icons.high_quality_rounded, + Icons.high_quality_sharp, + Icons.highlight, + Icons.highlight_alt, + Icons.highlight_alt_outlined, + Icons.highlight_alt_rounded, + Icons.highlight_alt_sharp, + Icons.highlight_off, + Icons.highlight_off_outlined, + Icons.highlight_off_rounded, + Icons.highlight_off_sharp, + Icons.highlight_outlined, + Icons.highlight_remove, + Icons.highlight_remove_outlined, + Icons.highlight_remove_rounded, + Icons.highlight_remove_sharp, + Icons.highlight_rounded, + Icons.highlight_sharp, + Icons.hiking, + Icons.hiking_outlined, + Icons.hiking_rounded, + Icons.hiking_sharp, + Icons.history, + Icons.history_edu, + Icons.history_edu_outlined, + Icons.history_edu_rounded, + Icons.history_edu_sharp, + Icons.history_outlined, + Icons.history_rounded, + Icons.history_sharp, + Icons.history_toggle_off, + Icons.history_toggle_off_outlined, + Icons.history_toggle_off_rounded, + Icons.history_toggle_off_sharp, + Icons.hive, + Icons.hive_outlined, + Icons.hive_rounded, + Icons.hive_sharp, + Icons.hls, + Icons.hls_off, + Icons.hls_off_outlined, + Icons.hls_off_rounded, + Icons.hls_off_sharp, + Icons.hls_outlined, + Icons.hls_rounded, + Icons.hls_sharp, + Icons.holiday_village, + Icons.holiday_village_outlined, + Icons.holiday_village_rounded, + Icons.holiday_village_sharp, + Icons.home, + Icons.home_filled, + Icons.home_max, + Icons.home_max_outlined, + Icons.home_max_rounded, + Icons.home_max_sharp, + Icons.home_mini, + Icons.home_mini_outlined, + Icons.home_mini_rounded, + Icons.home_mini_sharp, + Icons.home_outlined, + Icons.home_repair_service, + Icons.home_repair_service_outlined, + Icons.home_repair_service_rounded, + Icons.home_repair_service_sharp, + Icons.home_rounded, + Icons.home_sharp, + Icons.home_work, + Icons.home_work_outlined, + Icons.home_work_rounded, + Icons.home_work_sharp, + Icons.horizontal_distribute, + Icons.horizontal_distribute_outlined, + Icons.horizontal_distribute_rounded, + Icons.horizontal_distribute_sharp, + Icons.horizontal_rule, + Icons.horizontal_rule_outlined, + Icons.horizontal_rule_rounded, + Icons.horizontal_rule_sharp, + Icons.horizontal_split, + Icons.horizontal_split_outlined, + Icons.horizontal_split_rounded, + Icons.horizontal_split_sharp, + Icons.hot_tub, + Icons.hot_tub_outlined, + Icons.hot_tub_rounded, + Icons.hot_tub_sharp, + Icons.hotel, + Icons.hotel_class, + Icons.hotel_class_outlined, + Icons.hotel_class_rounded, + Icons.hotel_class_sharp, + Icons.hotel_outlined, + Icons.hotel_rounded, + Icons.hotel_sharp, + Icons.hourglass_bottom, + Icons.hourglass_bottom_outlined, + Icons.hourglass_bottom_rounded, + Icons.hourglass_bottom_sharp, + Icons.hourglass_disabled, + Icons.hourglass_disabled_outlined, + Icons.hourglass_disabled_rounded, + Icons.hourglass_disabled_sharp, + Icons.hourglass_empty, + Icons.hourglass_empty_outlined, + Icons.hourglass_empty_rounded, + Icons.hourglass_empty_sharp, + Icons.hourglass_full, + Icons.hourglass_full_outlined, + Icons.hourglass_full_rounded, + Icons.hourglass_full_sharp, + Icons.hourglass_top, + Icons.hourglass_top_outlined, + Icons.hourglass_top_rounded, + Icons.hourglass_top_sharp, + Icons.house, + Icons.house_outlined, + Icons.house_rounded, + Icons.house_sharp, + Icons.house_siding, + Icons.house_siding_outlined, + Icons.house_siding_rounded, + Icons.house_siding_sharp, + Icons.houseboat, + Icons.houseboat_outlined, + Icons.houseboat_rounded, + Icons.houseboat_sharp, + Icons.how_to_reg, + Icons.how_to_reg_outlined, + Icons.how_to_reg_rounded, + Icons.how_to_reg_sharp, + Icons.how_to_vote, + Icons.how_to_vote_outlined, + Icons.how_to_vote_rounded, + Icons.how_to_vote_sharp, + Icons.html, + Icons.html_outlined, + Icons.html_rounded, + Icons.html_sharp, + Icons.http, + Icons.http_outlined, + Icons.http_rounded, + Icons.http_sharp, + Icons.https, + Icons.https_outlined, + Icons.https_rounded, + Icons.https_sharp, + Icons.hub, + Icons.hub_outlined, + Icons.hub_rounded, + Icons.hub_sharp, + Icons.hvac, + Icons.hvac_outlined, + Icons.hvac_rounded, + Icons.hvac_sharp, + Icons.ice_skating, + Icons.ice_skating_outlined, + Icons.ice_skating_rounded, + Icons.ice_skating_sharp, + Icons.icecream, + Icons.icecream_outlined, + Icons.icecream_rounded, + Icons.icecream_sharp, + Icons.image, + Icons.image_aspect_ratio, + Icons.image_aspect_ratio_outlined, + Icons.image_aspect_ratio_rounded, + Icons.image_aspect_ratio_sharp, + Icons.image_not_supported, + Icons.image_not_supported_outlined, + Icons.image_not_supported_rounded, + Icons.image_not_supported_sharp, + Icons.image_outlined, + Icons.image_rounded, + Icons.image_search, + Icons.image_search_outlined, + Icons.image_search_rounded, + Icons.image_search_sharp, + Icons.image_sharp, + Icons.imagesearch_roller, + Icons.imagesearch_roller_outlined, + Icons.imagesearch_roller_rounded, + Icons.imagesearch_roller_sharp, + Icons.import_contacts, + Icons.import_contacts_outlined, + Icons.import_contacts_rounded, + Icons.import_contacts_sharp, + Icons.import_export, + Icons.import_export_outlined, + Icons.import_export_rounded, + Icons.import_export_sharp, + Icons.important_devices, + Icons.important_devices_outlined, + Icons.important_devices_rounded, + Icons.important_devices_sharp, + Icons.inbox, + Icons.inbox_outlined, + Icons.inbox_rounded, + Icons.inbox_sharp, + Icons.incomplete_circle, + Icons.incomplete_circle_outlined, + Icons.incomplete_circle_rounded, + Icons.incomplete_circle_sharp, + Icons.indeterminate_check_box, + Icons.indeterminate_check_box_outlined, + Icons.indeterminate_check_box_rounded, + Icons.indeterminate_check_box_sharp, + Icons.info, + Icons.info_outline, + Icons.info_outline_rounded, + Icons.info_outline_sharp, + Icons.info_outlined, + Icons.info_rounded, + Icons.info_sharp, + Icons.input, + Icons.input_outlined, + Icons.input_rounded, + Icons.input_sharp, + Icons.insert_chart, + Icons.insert_chart_outlined, + Icons.insert_chart_outlined_outlined, + Icons.insert_chart_outlined_rounded, + Icons.insert_chart_outlined_sharp, + Icons.insert_chart_rounded, + Icons.insert_chart_sharp, + Icons.insert_comment, + Icons.insert_comment_outlined, + Icons.insert_comment_rounded, + Icons.insert_comment_sharp, + Icons.insert_drive_file, + Icons.insert_drive_file_outlined, + Icons.insert_drive_file_rounded, + Icons.insert_drive_file_sharp, + Icons.insert_emoticon, + Icons.insert_emoticon_outlined, + Icons.insert_emoticon_rounded, + Icons.insert_emoticon_sharp, + Icons.insert_invitation, + Icons.insert_invitation_outlined, + Icons.insert_invitation_rounded, + Icons.insert_invitation_sharp, + Icons.insert_link, + Icons.insert_link_outlined, + Icons.insert_link_rounded, + Icons.insert_link_sharp, + Icons.insert_page_break, + Icons.insert_page_break_outlined, + Icons.insert_page_break_rounded, + Icons.insert_page_break_sharp, + Icons.insert_photo, + Icons.insert_photo_outlined, + Icons.insert_photo_rounded, + Icons.insert_photo_sharp, + Icons.insights, + Icons.insights_outlined, + Icons.insights_rounded, + Icons.insights_sharp, + Icons.install_desktop, + Icons.install_desktop_outlined, + Icons.install_desktop_rounded, + Icons.install_desktop_sharp, + Icons.install_mobile, + Icons.install_mobile_outlined, + Icons.install_mobile_rounded, + Icons.install_mobile_sharp, + Icons.integration_instructions, + Icons.integration_instructions_outlined, + Icons.integration_instructions_rounded, + Icons.integration_instructions_sharp, + Icons.interests, + Icons.interests_outlined, + Icons.interests_rounded, + Icons.interests_sharp, + Icons.interpreter_mode, + Icons.interpreter_mode_outlined, + Icons.interpreter_mode_rounded, + Icons.interpreter_mode_sharp, + Icons.inventory, + Icons.inventory_2, + Icons.inventory_2_outlined, + Icons.inventory_2_rounded, + Icons.inventory_2_sharp, + Icons.inventory_outlined, + Icons.inventory_rounded, + Icons.inventory_sharp, + Icons.invert_colors, + Icons.invert_colors_off, + Icons.invert_colors_off_outlined, + Icons.invert_colors_off_rounded, + Icons.invert_colors_off_sharp, + Icons.invert_colors_on, + Icons.invert_colors_on_outlined, + Icons.invert_colors_on_rounded, + Icons.invert_colors_on_sharp, + Icons.invert_colors_outlined, + Icons.invert_colors_rounded, + Icons.invert_colors_sharp, + Icons.ios_share, + Icons.ios_share_outlined, + Icons.ios_share_rounded, + Icons.ios_share_sharp, + Icons.iron, + Icons.iron_outlined, + Icons.iron_rounded, + Icons.iron_sharp, + Icons.iso, + Icons.iso_outlined, + Icons.iso_rounded, + Icons.iso_sharp, + Icons.javascript, + Icons.javascript_outlined, + Icons.javascript_rounded, + Icons.javascript_sharp, + Icons.join_full, + Icons.join_full_outlined, + Icons.join_full_rounded, + Icons.join_full_sharp, + Icons.join_inner, + Icons.join_inner_outlined, + Icons.join_inner_rounded, + Icons.join_inner_sharp, + Icons.join_left, + Icons.join_left_outlined, + Icons.join_left_rounded, + Icons.join_left_sharp, + Icons.join_right, + Icons.join_right_outlined, + Icons.join_right_rounded, + Icons.join_right_sharp, + Icons.kayaking, + Icons.kayaking_outlined, + Icons.kayaking_rounded, + Icons.kayaking_sharp, + Icons.kebab_dining, + Icons.kebab_dining_outlined, + Icons.kebab_dining_rounded, + Icons.kebab_dining_sharp, + Icons.key, + Icons.key_off, + Icons.key_off_outlined, + Icons.key_off_rounded, + Icons.key_off_sharp, + Icons.key_outlined, + Icons.key_rounded, + Icons.key_sharp, + Icons.keyboard, + Icons.keyboard_alt, + Icons.keyboard_alt_outlined, + Icons.keyboard_alt_rounded, + Icons.keyboard_alt_sharp, + Icons.keyboard_arrow_down, + Icons.keyboard_arrow_down_outlined, + Icons.keyboard_arrow_down_rounded, + Icons.keyboard_arrow_down_sharp, + Icons.keyboard_arrow_left, + Icons.keyboard_arrow_left_outlined, + Icons.keyboard_arrow_left_rounded, + Icons.keyboard_arrow_left_sharp, + Icons.keyboard_arrow_right, + Icons.keyboard_arrow_right_outlined, + Icons.keyboard_arrow_right_rounded, + Icons.keyboard_arrow_right_sharp, + Icons.keyboard_arrow_up, + Icons.keyboard_arrow_up_outlined, + Icons.keyboard_arrow_up_rounded, + Icons.keyboard_arrow_up_sharp, + Icons.keyboard_backspace, + Icons.keyboard_backspace_outlined, + Icons.keyboard_backspace_rounded, + Icons.keyboard_backspace_sharp, + Icons.keyboard_capslock, + Icons.keyboard_capslock_outlined, + Icons.keyboard_capslock_rounded, + Icons.keyboard_capslock_sharp, + Icons.keyboard_command_key, + Icons.keyboard_command_key_outlined, + Icons.keyboard_command_key_rounded, + Icons.keyboard_command_key_sharp, + Icons.keyboard_control, + Icons.keyboard_control_key, + Icons.keyboard_control_key_outlined, + Icons.keyboard_control_key_rounded, + Icons.keyboard_control_key_sharp, + Icons.keyboard_control_outlined, + Icons.keyboard_control_rounded, + Icons.keyboard_control_sharp, + Icons.keyboard_double_arrow_down, + Icons.keyboard_double_arrow_down_outlined, + Icons.keyboard_double_arrow_down_rounded, + Icons.keyboard_double_arrow_down_sharp, + Icons.keyboard_double_arrow_left, + Icons.keyboard_double_arrow_left_outlined, + Icons.keyboard_double_arrow_left_rounded, + Icons.keyboard_double_arrow_left_sharp, + Icons.keyboard_double_arrow_right, + Icons.keyboard_double_arrow_right_outlined, + Icons.keyboard_double_arrow_right_rounded, + Icons.keyboard_double_arrow_right_sharp, + Icons.keyboard_double_arrow_up, + Icons.keyboard_double_arrow_up_outlined, + Icons.keyboard_double_arrow_up_rounded, + Icons.keyboard_double_arrow_up_sharp, + Icons.keyboard_hide, + Icons.keyboard_hide_outlined, + Icons.keyboard_hide_rounded, + Icons.keyboard_hide_sharp, + Icons.keyboard_option_key, + Icons.keyboard_option_key_outlined, + Icons.keyboard_option_key_rounded, + Icons.keyboard_option_key_sharp, + Icons.keyboard_outlined, + Icons.keyboard_return, + Icons.keyboard_return_outlined, + Icons.keyboard_return_rounded, + Icons.keyboard_return_sharp, + Icons.keyboard_rounded, + Icons.keyboard_sharp, + Icons.keyboard_tab, + Icons.keyboard_tab_outlined, + Icons.keyboard_tab_rounded, + Icons.keyboard_tab_sharp, + Icons.keyboard_voice, + Icons.keyboard_voice_outlined, + Icons.keyboard_voice_rounded, + Icons.keyboard_voice_sharp, + Icons.king_bed, + Icons.king_bed_outlined, + Icons.king_bed_rounded, + Icons.king_bed_sharp, + Icons.kitchen, + Icons.kitchen_outlined, + Icons.kitchen_rounded, + Icons.kitchen_sharp, + Icons.kitesurfing, + Icons.kitesurfing_outlined, + Icons.kitesurfing_rounded, + Icons.kitesurfing_sharp, + Icons.label, + Icons.label_important, + Icons.label_important_outline, + Icons.label_important_outline_rounded, + Icons.label_important_outline_sharp, + Icons.label_important_outlined, + Icons.label_important_rounded, + Icons.label_important_sharp, + Icons.label_off, + Icons.label_off_outlined, + Icons.label_off_rounded, + Icons.label_off_sharp, + Icons.label_outline, + Icons.label_outline_rounded, + Icons.label_outline_sharp, + Icons.label_outlined, + Icons.label_rounded, + Icons.label_sharp, + Icons.lan, + Icons.lan_outlined, + Icons.lan_rounded, + Icons.lan_sharp, + Icons.landscape, + Icons.landscape_outlined, + Icons.landscape_rounded, + Icons.landscape_sharp, + Icons.landslide, + Icons.landslide_outlined, + Icons.landslide_rounded, + Icons.landslide_sharp, + Icons.language, + Icons.language_outlined, + Icons.language_rounded, + Icons.language_sharp, + Icons.laptop, + Icons.laptop_chromebook, + Icons.laptop_chromebook_outlined, + Icons.laptop_chromebook_rounded, + Icons.laptop_chromebook_sharp, + Icons.laptop_mac, + Icons.laptop_mac_outlined, + Icons.laptop_mac_rounded, + Icons.laptop_mac_sharp, + Icons.laptop_outlined, + Icons.laptop_rounded, + Icons.laptop_sharp, + Icons.laptop_windows, + Icons.laptop_windows_outlined, + Icons.laptop_windows_rounded, + Icons.laptop_windows_sharp, + Icons.last_page, + Icons.last_page_outlined, + Icons.last_page_rounded, + Icons.last_page_sharp, + Icons.launch, + Icons.launch_outlined, + Icons.launch_rounded, + Icons.launch_sharp, + Icons.layers, + Icons.layers_clear, + Icons.layers_clear_outlined, + Icons.layers_clear_rounded, + Icons.layers_clear_sharp, + Icons.layers_outlined, + Icons.layers_rounded, + Icons.layers_sharp, + Icons.leaderboard, + Icons.leaderboard_outlined, + Icons.leaderboard_rounded, + Icons.leaderboard_sharp, + Icons.leak_add, + Icons.leak_add_outlined, + Icons.leak_add_rounded, + Icons.leak_add_sharp, + Icons.leak_remove, + Icons.leak_remove_outlined, + Icons.leak_remove_rounded, + Icons.leak_remove_sharp, + Icons.leave_bags_at_home, + Icons.leave_bags_at_home_outlined, + Icons.leave_bags_at_home_rounded, + Icons.leave_bags_at_home_sharp, + Icons.legend_toggle, + Icons.legend_toggle_outlined, + Icons.legend_toggle_rounded, + Icons.legend_toggle_sharp, + Icons.lens, + Icons.lens_blur, + Icons.lens_blur_outlined, + Icons.lens_blur_rounded, + Icons.lens_blur_sharp, + Icons.lens_outlined, + Icons.lens_rounded, + Icons.lens_sharp, + Icons.library_add, + Icons.library_add_check, + Icons.library_add_check_outlined, + Icons.library_add_check_rounded, + Icons.library_add_check_sharp, + Icons.library_add_outlined, + Icons.library_add_rounded, + Icons.library_add_sharp, + Icons.library_books, + Icons.library_books_outlined, + Icons.library_books_rounded, + Icons.library_books_sharp, + Icons.library_music, + Icons.library_music_outlined, + Icons.library_music_rounded, + Icons.library_music_sharp, + Icons.light, + Icons.light_mode, + Icons.light_mode_outlined, + Icons.light_mode_rounded, + Icons.light_mode_sharp, + Icons.light_outlined, + Icons.light_rounded, + Icons.light_sharp, + Icons.lightbulb, + Icons.lightbulb_circle, + Icons.lightbulb_circle_outlined, + Icons.lightbulb_circle_rounded, + Icons.lightbulb_circle_sharp, + Icons.lightbulb_outline, + Icons.lightbulb_outline_rounded, + Icons.lightbulb_outline_sharp, + Icons.lightbulb_outlined, + Icons.lightbulb_rounded, + Icons.lightbulb_sharp, + Icons.line_axis, + Icons.line_axis_outlined, + Icons.line_axis_rounded, + Icons.line_axis_sharp, + Icons.line_style, + Icons.line_style_outlined, + Icons.line_style_rounded, + Icons.line_style_sharp, + Icons.line_weight, + Icons.line_weight_outlined, + Icons.line_weight_rounded, + Icons.line_weight_sharp, + Icons.linear_scale, + Icons.linear_scale_outlined, + Icons.linear_scale_rounded, + Icons.linear_scale_sharp, + Icons.link, + Icons.link_off, + Icons.link_off_outlined, + Icons.link_off_rounded, + Icons.link_off_sharp, + Icons.link_outlined, + Icons.link_rounded, + Icons.link_sharp, + Icons.linked_camera, + Icons.linked_camera_outlined, + Icons.linked_camera_rounded, + Icons.linked_camera_sharp, + Icons.liquor, + Icons.liquor_outlined, + Icons.liquor_rounded, + Icons.liquor_sharp, + Icons.list, + Icons.list_alt, + Icons.list_alt_outlined, + Icons.list_alt_rounded, + Icons.list_alt_sharp, + Icons.list_outlined, + Icons.list_rounded, + Icons.list_sharp, + Icons.live_help, + Icons.live_help_outlined, + Icons.live_help_rounded, + Icons.live_help_sharp, + Icons.live_tv, + Icons.live_tv_outlined, + Icons.live_tv_rounded, + Icons.live_tv_sharp, + Icons.living, + Icons.living_outlined, + Icons.living_rounded, + Icons.living_sharp, + Icons.local_activity, + Icons.local_activity_outlined, + Icons.local_activity_rounded, + Icons.local_activity_sharp, + Icons.local_airport, + Icons.local_airport_outlined, + Icons.local_airport_rounded, + Icons.local_airport_sharp, + Icons.local_atm, + Icons.local_atm_outlined, + Icons.local_atm_rounded, + Icons.local_atm_sharp, + Icons.local_attraction, + Icons.local_attraction_outlined, + Icons.local_attraction_rounded, + Icons.local_attraction_sharp, + Icons.local_bar, + Icons.local_bar_outlined, + Icons.local_bar_rounded, + Icons.local_bar_sharp, + Icons.local_cafe, + Icons.local_cafe_outlined, + Icons.local_cafe_rounded, + Icons.local_cafe_sharp, + Icons.local_car_wash, + Icons.local_car_wash_outlined, + Icons.local_car_wash_rounded, + Icons.local_car_wash_sharp, + Icons.local_convenience_store, + Icons.local_convenience_store_outlined, + Icons.local_convenience_store_rounded, + Icons.local_convenience_store_sharp, + Icons.local_dining, + Icons.local_dining_outlined, + Icons.local_dining_rounded, + Icons.local_dining_sharp, + Icons.local_drink, + Icons.local_drink_outlined, + Icons.local_drink_rounded, + Icons.local_drink_sharp, + Icons.local_fire_department, + Icons.local_fire_department_outlined, + Icons.local_fire_department_rounded, + Icons.local_fire_department_sharp, + Icons.local_florist, + Icons.local_florist_outlined, + Icons.local_florist_rounded, + Icons.local_florist_sharp, + Icons.local_gas_station, + Icons.local_gas_station_outlined, + Icons.local_gas_station_rounded, + Icons.local_gas_station_sharp, + Icons.local_grocery_store, + Icons.local_grocery_store_outlined, + Icons.local_grocery_store_rounded, + Icons.local_grocery_store_sharp, + Icons.local_hospital, + Icons.local_hospital_outlined, + Icons.local_hospital_rounded, + Icons.local_hospital_sharp, + Icons.local_hotel, + Icons.local_hotel_outlined, + Icons.local_hotel_rounded, + Icons.local_hotel_sharp, + Icons.local_laundry_service, + Icons.local_laundry_service_outlined, + Icons.local_laundry_service_rounded, + Icons.local_laundry_service_sharp, + Icons.local_library, + Icons.local_library_outlined, + Icons.local_library_rounded, + Icons.local_library_sharp, + Icons.local_mall, + Icons.local_mall_outlined, + Icons.local_mall_rounded, + Icons.local_mall_sharp, + Icons.local_movies, + Icons.local_movies_outlined, + Icons.local_movies_rounded, + Icons.local_movies_sharp, + Icons.local_offer, + Icons.local_offer_outlined, + Icons.local_offer_rounded, + Icons.local_offer_sharp, + Icons.local_parking, + Icons.local_parking_outlined, + Icons.local_parking_rounded, + Icons.local_parking_sharp, + Icons.local_pharmacy, + Icons.local_pharmacy_outlined, + Icons.local_pharmacy_rounded, + Icons.local_pharmacy_sharp, + Icons.local_phone, + Icons.local_phone_outlined, + Icons.local_phone_rounded, + Icons.local_phone_sharp, + Icons.local_pizza, + Icons.local_pizza_outlined, + Icons.local_pizza_rounded, + Icons.local_pizza_sharp, + Icons.local_play, + Icons.local_play_outlined, + Icons.local_play_rounded, + Icons.local_play_sharp, + Icons.local_police, + Icons.local_police_outlined, + Icons.local_police_rounded, + Icons.local_police_sharp, + Icons.local_post_office, + Icons.local_post_office_outlined, + Icons.local_post_office_rounded, + Icons.local_post_office_sharp, + Icons.local_print_shop, + Icons.local_print_shop_outlined, + Icons.local_print_shop_rounded, + Icons.local_print_shop_sharp, + Icons.local_printshop, + Icons.local_printshop_outlined, + Icons.local_printshop_rounded, + Icons.local_printshop_sharp, + Icons.local_restaurant, + Icons.local_restaurant_outlined, + Icons.local_restaurant_rounded, + Icons.local_restaurant_sharp, + Icons.local_see, + Icons.local_see_outlined, + Icons.local_see_rounded, + Icons.local_see_sharp, + Icons.local_shipping, + Icons.local_shipping_outlined, + Icons.local_shipping_rounded, + Icons.local_shipping_sharp, + Icons.local_taxi, + Icons.local_taxi_outlined, + Icons.local_taxi_rounded, + Icons.local_taxi_sharp, + Icons.location_city, + Icons.location_city_outlined, + Icons.location_city_rounded, + Icons.location_city_sharp, + Icons.location_disabled, + Icons.location_disabled_outlined, + Icons.location_disabled_rounded, + Icons.location_disabled_sharp, + Icons.location_history, + Icons.location_history_outlined, + Icons.location_history_rounded, + Icons.location_history_sharp, + Icons.location_off, + Icons.location_off_outlined, + Icons.location_off_rounded, + Icons.location_off_sharp, + Icons.location_on, + Icons.location_on_outlined, + Icons.location_on_rounded, + Icons.location_on_sharp, + Icons.location_pin, + Icons.location_searching, + Icons.location_searching_outlined, + Icons.location_searching_rounded, + Icons.location_searching_sharp, + Icons.lock, + Icons.lock_clock, + Icons.lock_clock_outlined, + Icons.lock_clock_rounded, + Icons.lock_clock_sharp, + Icons.lock_open, + Icons.lock_open_outlined, + Icons.lock_open_rounded, + Icons.lock_open_sharp, + Icons.lock_outline, + Icons.lock_outline_rounded, + Icons.lock_outline_sharp, + Icons.lock_outlined, + Icons.lock_person, + Icons.lock_person_outlined, + Icons.lock_person_rounded, + Icons.lock_person_sharp, + Icons.lock_reset, + Icons.lock_reset_outlined, + Icons.lock_reset_rounded, + Icons.lock_reset_sharp, + Icons.lock_rounded, + Icons.lock_sharp, + Icons.login, + Icons.login_outlined, + Icons.login_rounded, + Icons.login_sharp, + Icons.logo_dev, + Icons.logo_dev_outlined, + Icons.logo_dev_rounded, + Icons.logo_dev_sharp, + Icons.logout, + Icons.logout_outlined, + Icons.logout_rounded, + Icons.logout_sharp, + Icons.looks, + Icons.looks_3, + Icons.looks_3_outlined, + Icons.looks_3_rounded, + Icons.looks_3_sharp, + Icons.looks_4, + Icons.looks_4_outlined, + Icons.looks_4_rounded, + Icons.looks_4_sharp, + Icons.looks_5, + Icons.looks_5_outlined, + Icons.looks_5_rounded, + Icons.looks_5_sharp, + Icons.looks_6, + Icons.looks_6_outlined, + Icons.looks_6_rounded, + Icons.looks_6_sharp, + Icons.looks_one, + Icons.looks_one_outlined, + Icons.looks_one_rounded, + Icons.looks_one_sharp, + Icons.looks_outlined, + Icons.looks_rounded, + Icons.looks_sharp, + Icons.looks_two, + Icons.looks_two_outlined, + Icons.looks_two_rounded, + Icons.looks_two_sharp, + Icons.loop, + Icons.loop_outlined, + Icons.loop_rounded, + Icons.loop_sharp, + Icons.loupe, + Icons.loupe_outlined, + Icons.loupe_rounded, + Icons.loupe_sharp, + Icons.low_priority, + Icons.low_priority_outlined, + Icons.low_priority_rounded, + Icons.low_priority_sharp, + Icons.loyalty, + Icons.loyalty_outlined, + Icons.loyalty_rounded, + Icons.loyalty_sharp, + Icons.lte_mobiledata, + Icons.lte_mobiledata_outlined, + Icons.lte_mobiledata_rounded, + Icons.lte_mobiledata_sharp, + Icons.lte_plus_mobiledata, + Icons.lte_plus_mobiledata_outlined, + Icons.lte_plus_mobiledata_rounded, + Icons.lte_plus_mobiledata_sharp, + Icons.luggage, + Icons.luggage_outlined, + Icons.luggage_rounded, + Icons.luggage_sharp, + Icons.lunch_dining, + Icons.lunch_dining_outlined, + Icons.lunch_dining_rounded, + Icons.lunch_dining_sharp, + Icons.lyrics, + Icons.lyrics_outlined, + Icons.lyrics_rounded, + Icons.lyrics_sharp, + Icons.macro_off, + Icons.macro_off_outlined, + Icons.macro_off_rounded, + Icons.macro_off_sharp, + Icons.mail, + Icons.mail_lock, + Icons.mail_lock_outlined, + Icons.mail_lock_rounded, + Icons.mail_lock_sharp, + Icons.mail_outline, + Icons.mail_outline_outlined, + Icons.mail_outline_rounded, + Icons.mail_outline_sharp, + Icons.mail_outlined, + Icons.mail_rounded, + Icons.mail_sharp, + Icons.male, + Icons.male_outlined, + Icons.male_rounded, + Icons.male_sharp, + Icons.man, + Icons.man_2, + Icons.man_2_outlined, + Icons.man_2_rounded, + Icons.man_2_sharp, + Icons.man_3, + Icons.man_3_outlined, + Icons.man_3_rounded, + Icons.man_3_sharp, + Icons.man_4, + Icons.man_4_outlined, + Icons.man_4_rounded, + Icons.man_4_sharp, + Icons.man_outlined, + Icons.man_rounded, + Icons.man_sharp, + Icons.manage_accounts, + Icons.manage_accounts_outlined, + Icons.manage_accounts_rounded, + Icons.manage_accounts_sharp, + Icons.manage_history, + Icons.manage_history_outlined, + Icons.manage_history_rounded, + Icons.manage_history_sharp, + Icons.manage_search, + Icons.manage_search_outlined, + Icons.manage_search_rounded, + Icons.manage_search_sharp, + Icons.map, + Icons.map_outlined, + Icons.map_rounded, + Icons.map_sharp, + Icons.maps_home_work, + Icons.maps_home_work_outlined, + Icons.maps_home_work_rounded, + Icons.maps_home_work_sharp, + Icons.maps_ugc, + Icons.maps_ugc_outlined, + Icons.maps_ugc_rounded, + Icons.maps_ugc_sharp, + Icons.margin, + Icons.margin_outlined, + Icons.margin_rounded, + Icons.margin_sharp, + Icons.mark_as_unread, + Icons.mark_as_unread_outlined, + Icons.mark_as_unread_rounded, + Icons.mark_as_unread_sharp, + Icons.mark_chat_read, + Icons.mark_chat_read_outlined, + Icons.mark_chat_read_rounded, + Icons.mark_chat_read_sharp, + Icons.mark_chat_unread, + Icons.mark_chat_unread_outlined, + Icons.mark_chat_unread_rounded, + Icons.mark_chat_unread_sharp, + Icons.mark_email_read, + Icons.mark_email_read_outlined, + Icons.mark_email_read_rounded, + Icons.mark_email_read_sharp, + Icons.mark_email_unread, + Icons.mark_email_unread_outlined, + Icons.mark_email_unread_rounded, + Icons.mark_email_unread_sharp, + Icons.mark_unread_chat_alt, + Icons.mark_unread_chat_alt_outlined, + Icons.mark_unread_chat_alt_rounded, + Icons.mark_unread_chat_alt_sharp, + Icons.markunread, + Icons.markunread_mailbox, + Icons.markunread_mailbox_outlined, + Icons.markunread_mailbox_rounded, + Icons.markunread_mailbox_sharp, + Icons.markunread_outlined, + Icons.markunread_rounded, + Icons.markunread_sharp, + Icons.masks, + Icons.masks_outlined, + Icons.masks_rounded, + Icons.masks_sharp, + Icons.maximize, + Icons.maximize_outlined, + Icons.maximize_rounded, + Icons.maximize_sharp, + Icons.media_bluetooth_off, + Icons.media_bluetooth_off_outlined, + Icons.media_bluetooth_off_rounded, + Icons.media_bluetooth_off_sharp, + Icons.media_bluetooth_on, + Icons.media_bluetooth_on_outlined, + Icons.media_bluetooth_on_rounded, + Icons.media_bluetooth_on_sharp, + Icons.mediation, + Icons.mediation_outlined, + Icons.mediation_rounded, + Icons.mediation_sharp, + Icons.medical_information, + Icons.medical_information_outlined, + Icons.medical_information_rounded, + Icons.medical_information_sharp, + Icons.medical_services, + Icons.medical_services_outlined, + Icons.medical_services_rounded, + Icons.medical_services_sharp, + Icons.medication, + Icons.medication_liquid, + Icons.medication_liquid_outlined, + Icons.medication_liquid_rounded, + Icons.medication_liquid_sharp, + Icons.medication_outlined, + Icons.medication_rounded, + Icons.medication_sharp, + Icons.meeting_room, + Icons.meeting_room_outlined, + Icons.meeting_room_rounded, + Icons.meeting_room_sharp, + Icons.memory, + Icons.memory_outlined, + Icons.memory_rounded, + Icons.memory_sharp, + Icons.menu, + Icons.menu_book, + Icons.menu_book_outlined, + Icons.menu_book_rounded, + Icons.menu_book_sharp, + Icons.menu_open, + Icons.menu_open_outlined, + Icons.menu_open_rounded, + Icons.menu_open_sharp, + Icons.menu_outlined, + Icons.menu_rounded, + Icons.menu_sharp, + Icons.merge, + Icons.merge_outlined, + Icons.merge_rounded, + Icons.merge_sharp, + Icons.merge_type, + Icons.merge_type_outlined, + Icons.merge_type_rounded, + Icons.merge_type_sharp, + Icons.message, + Icons.message_outlined, + Icons.message_rounded, + Icons.message_sharp, + Icons.messenger, + Icons.messenger_outline, + Icons.messenger_outline_outlined, + Icons.messenger_outline_rounded, + Icons.messenger_outline_sharp, + Icons.messenger_outlined, + Icons.messenger_rounded, + Icons.messenger_sharp, + Icons.mic, + Icons.mic_external_off, + Icons.mic_external_off_outlined, + Icons.mic_external_off_rounded, + Icons.mic_external_off_sharp, + Icons.mic_external_on, + Icons.mic_external_on_outlined, + Icons.mic_external_on_rounded, + Icons.mic_external_on_sharp, + Icons.mic_none, + Icons.mic_none_outlined, + Icons.mic_none_rounded, + Icons.mic_none_sharp, + Icons.mic_off, + Icons.mic_off_outlined, + Icons.mic_off_rounded, + Icons.mic_off_sharp, + Icons.mic_outlined, + Icons.mic_rounded, + Icons.mic_sharp, + Icons.microwave, + Icons.microwave_outlined, + Icons.microwave_rounded, + Icons.microwave_sharp, + Icons.military_tech, + Icons.military_tech_outlined, + Icons.military_tech_rounded, + Icons.military_tech_sharp, + Icons.minimize, + Icons.minimize_outlined, + Icons.minimize_rounded, + Icons.minimize_sharp, + Icons.minor_crash, + Icons.minor_crash_outlined, + Icons.minor_crash_rounded, + Icons.minor_crash_sharp, + Icons.miscellaneous_services, + Icons.miscellaneous_services_outlined, + Icons.miscellaneous_services_rounded, + Icons.miscellaneous_services_sharp, + Icons.missed_video_call, + Icons.missed_video_call_outlined, + Icons.missed_video_call_rounded, + Icons.missed_video_call_sharp, + Icons.mms, + Icons.mms_outlined, + Icons.mms_rounded, + Icons.mms_sharp, + Icons.mobile_friendly, + Icons.mobile_friendly_outlined, + Icons.mobile_friendly_rounded, + Icons.mobile_friendly_sharp, + Icons.mobile_off, + Icons.mobile_off_outlined, + Icons.mobile_off_rounded, + Icons.mobile_off_sharp, + Icons.mobile_screen_share, + Icons.mobile_screen_share_outlined, + Icons.mobile_screen_share_rounded, + Icons.mobile_screen_share_sharp, + Icons.mobiledata_off, + Icons.mobiledata_off_outlined, + Icons.mobiledata_off_rounded, + Icons.mobiledata_off_sharp, + Icons.mode, + Icons.mode_comment, + Icons.mode_comment_outlined, + Icons.mode_comment_rounded, + Icons.mode_comment_sharp, + Icons.mode_edit, + Icons.mode_edit_outline, + Icons.mode_edit_outline_outlined, + Icons.mode_edit_outline_rounded, + Icons.mode_edit_outline_sharp, + Icons.mode_edit_outlined, + Icons.mode_edit_rounded, + Icons.mode_edit_sharp, + Icons.mode_fan_off, + Icons.mode_fan_off_outlined, + Icons.mode_fan_off_rounded, + Icons.mode_fan_off_sharp, + Icons.mode_night, + Icons.mode_night_outlined, + Icons.mode_night_rounded, + Icons.mode_night_sharp, + Icons.mode_of_travel, + Icons.mode_of_travel_outlined, + Icons.mode_of_travel_rounded, + Icons.mode_of_travel_sharp, + Icons.mode_outlined, + Icons.mode_rounded, + Icons.mode_sharp, + Icons.mode_standby, + Icons.mode_standby_outlined, + Icons.mode_standby_rounded, + Icons.mode_standby_sharp, + Icons.model_training, + Icons.model_training_outlined, + Icons.model_training_rounded, + Icons.model_training_sharp, + Icons.monetization_on, + Icons.monetization_on_outlined, + Icons.monetization_on_rounded, + Icons.monetization_on_sharp, + Icons.money, + Icons.money_off, + Icons.money_off_csred, + Icons.money_off_csred_outlined, + Icons.money_off_csred_rounded, + Icons.money_off_csred_sharp, + Icons.money_off_outlined, + Icons.money_off_rounded, + Icons.money_off_sharp, + Icons.money_outlined, + Icons.money_rounded, + Icons.money_sharp, + Icons.monitor, + Icons.monitor_heart, + Icons.monitor_heart_outlined, + Icons.monitor_heart_rounded, + Icons.monitor_heart_sharp, + Icons.monitor_outlined, + Icons.monitor_rounded, + Icons.monitor_sharp, + Icons.monitor_weight, + Icons.monitor_weight_outlined, + Icons.monitor_weight_rounded, + Icons.monitor_weight_sharp, + Icons.monochrome_photos, + Icons.monochrome_photos_outlined, + Icons.monochrome_photos_rounded, + Icons.monochrome_photos_sharp, + Icons.mood, + Icons.mood_bad, + Icons.mood_bad_outlined, + Icons.mood_bad_rounded, + Icons.mood_bad_sharp, + Icons.mood_outlined, + Icons.mood_rounded, + Icons.mood_sharp, + Icons.moped, + Icons.moped_outlined, + Icons.moped_rounded, + Icons.moped_sharp, + Icons.more, + Icons.more_horiz, + Icons.more_horiz_outlined, + Icons.more_horiz_rounded, + Icons.more_horiz_sharp, + Icons.more_outlined, + Icons.more_rounded, + Icons.more_sharp, + Icons.more_time, + Icons.more_time_outlined, + Icons.more_time_rounded, + Icons.more_time_sharp, + Icons.more_vert, + Icons.more_vert_outlined, + Icons.more_vert_rounded, + Icons.more_vert_sharp, + Icons.mosque, + Icons.mosque_outlined, + Icons.mosque_rounded, + Icons.mosque_sharp, + Icons.motion_photos_auto, + Icons.motion_photos_auto_outlined, + Icons.motion_photos_auto_rounded, + Icons.motion_photos_auto_sharp, + Icons.motion_photos_off, + Icons.motion_photos_off_outlined, + Icons.motion_photos_off_rounded, + Icons.motion_photos_off_sharp, + Icons.motion_photos_on, + Icons.motion_photos_on_outlined, + Icons.motion_photos_on_rounded, + Icons.motion_photos_on_sharp, + Icons.motion_photos_pause, + Icons.motion_photos_pause_outlined, + Icons.motion_photos_pause_rounded, + Icons.motion_photos_pause_sharp, + Icons.motion_photos_paused, + Icons.motion_photos_paused_outlined, + Icons.motion_photos_paused_rounded, + Icons.motion_photos_paused_sharp, + Icons.motorcycle, + Icons.motorcycle_outlined, + Icons.motorcycle_rounded, + Icons.motorcycle_sharp, + Icons.mouse, + Icons.mouse_outlined, + Icons.mouse_rounded, + Icons.mouse_sharp, + Icons.move_down, + Icons.move_down_outlined, + Icons.move_down_rounded, + Icons.move_down_sharp, + Icons.move_to_inbox, + Icons.move_to_inbox_outlined, + Icons.move_to_inbox_rounded, + Icons.move_to_inbox_sharp, + Icons.move_up, + Icons.move_up_outlined, + Icons.move_up_rounded, + Icons.move_up_sharp, + Icons.movie, + Icons.movie_creation, + Icons.movie_creation_outlined, + Icons.movie_creation_rounded, + Icons.movie_creation_sharp, + Icons.movie_edit, + Icons.movie_filter, + Icons.movie_filter_outlined, + Icons.movie_filter_rounded, + Icons.movie_filter_sharp, + Icons.movie_outlined, + Icons.movie_rounded, + Icons.movie_sharp, + Icons.moving, + Icons.moving_outlined, + Icons.moving_rounded, + Icons.moving_sharp, + Icons.mp, + Icons.mp_outlined, + Icons.mp_rounded, + Icons.mp_sharp, + Icons.multiline_chart, + Icons.multiline_chart_outlined, + Icons.multiline_chart_rounded, + Icons.multiline_chart_sharp, + Icons.multiple_stop, + Icons.multiple_stop_outlined, + Icons.multiple_stop_rounded, + Icons.multiple_stop_sharp, + Icons.multitrack_audio, + Icons.multitrack_audio_outlined, + Icons.multitrack_audio_rounded, + Icons.multitrack_audio_sharp, + Icons.museum, + Icons.museum_outlined, + Icons.museum_rounded, + Icons.museum_sharp, + Icons.music_note, + Icons.music_note_outlined, + Icons.music_note_rounded, + Icons.music_note_sharp, + Icons.music_off, + Icons.music_off_outlined, + Icons.music_off_rounded, + Icons.music_off_sharp, + Icons.music_video, + Icons.music_video_outlined, + Icons.music_video_rounded, + Icons.music_video_sharp, + Icons.my_library_add, + Icons.my_library_add_outlined, + Icons.my_library_add_rounded, + Icons.my_library_add_sharp, + Icons.my_library_books, + Icons.my_library_books_outlined, + Icons.my_library_books_rounded, + Icons.my_library_books_sharp, + Icons.my_library_music, + Icons.my_library_music_outlined, + Icons.my_library_music_rounded, + Icons.my_library_music_sharp, + Icons.my_location, + Icons.my_location_outlined, + Icons.my_location_rounded, + Icons.my_location_sharp, + Icons.nat, + Icons.nat_outlined, + Icons.nat_rounded, + Icons.nat_sharp, + Icons.nature, + Icons.nature_outlined, + Icons.nature_people, + Icons.nature_people_outlined, + Icons.nature_people_rounded, + Icons.nature_people_sharp, + Icons.nature_rounded, + Icons.nature_sharp, + Icons.navigate_before, + Icons.navigate_before_outlined, + Icons.navigate_before_rounded, + Icons.navigate_before_sharp, + Icons.navigate_next, + Icons.navigate_next_outlined, + Icons.navigate_next_rounded, + Icons.navigate_next_sharp, + Icons.navigation, + Icons.navigation_outlined, + Icons.navigation_rounded, + Icons.navigation_sharp, + Icons.near_me, + Icons.near_me_disabled, + Icons.near_me_disabled_outlined, + Icons.near_me_disabled_rounded, + Icons.near_me_disabled_sharp, + Icons.near_me_outlined, + Icons.near_me_rounded, + Icons.near_me_sharp, + Icons.nearby_error, + Icons.nearby_error_outlined, + Icons.nearby_error_rounded, + Icons.nearby_error_sharp, + Icons.nearby_off, + Icons.nearby_off_outlined, + Icons.nearby_off_rounded, + Icons.nearby_off_sharp, + Icons.nest_cam_wired_stand, + Icons.nest_cam_wired_stand_outlined, + Icons.nest_cam_wired_stand_rounded, + Icons.nest_cam_wired_stand_sharp, + Icons.network_cell, + Icons.network_cell_outlined, + Icons.network_cell_rounded, + Icons.network_cell_sharp, + Icons.network_check, + Icons.network_check_outlined, + Icons.network_check_rounded, + Icons.network_check_sharp, + Icons.network_locked, + Icons.network_locked_outlined, + Icons.network_locked_rounded, + Icons.network_locked_sharp, + Icons.network_ping, + Icons.network_ping_outlined, + Icons.network_ping_rounded, + Icons.network_ping_sharp, + Icons.network_wifi, + Icons.network_wifi_1_bar, + Icons.network_wifi_1_bar_outlined, + Icons.network_wifi_1_bar_rounded, + Icons.network_wifi_1_bar_sharp, + Icons.network_wifi_2_bar, + Icons.network_wifi_2_bar_outlined, + Icons.network_wifi_2_bar_rounded, + Icons.network_wifi_2_bar_sharp, + Icons.network_wifi_3_bar, + Icons.network_wifi_3_bar_outlined, + Icons.network_wifi_3_bar_rounded, + Icons.network_wifi_3_bar_sharp, + Icons.network_wifi_outlined, + Icons.network_wifi_rounded, + Icons.network_wifi_sharp, + Icons.new_label, + Icons.new_label_outlined, + Icons.new_label_rounded, + Icons.new_label_sharp, + Icons.new_releases, + Icons.new_releases_outlined, + Icons.new_releases_rounded, + Icons.new_releases_sharp, + Icons.newspaper, + Icons.newspaper_outlined, + Icons.newspaper_rounded, + Icons.newspaper_sharp, + Icons.next_plan, + Icons.next_plan_outlined, + Icons.next_plan_rounded, + Icons.next_plan_sharp, + Icons.next_week, + Icons.next_week_outlined, + Icons.next_week_rounded, + Icons.next_week_sharp, + Icons.nfc, + Icons.nfc_outlined, + Icons.nfc_rounded, + Icons.nfc_sharp, + Icons.night_shelter, + Icons.night_shelter_outlined, + Icons.night_shelter_rounded, + Icons.night_shelter_sharp, + Icons.nightlife, + Icons.nightlife_outlined, + Icons.nightlife_rounded, + Icons.nightlife_sharp, + Icons.nightlight, + Icons.nightlight_outlined, + Icons.nightlight_round, + Icons.nightlight_round_outlined, + Icons.nightlight_round_rounded, + Icons.nightlight_round_sharp, + Icons.nightlight_rounded, + Icons.nightlight_sharp, + Icons.nights_stay, + Icons.nights_stay_outlined, + Icons.nights_stay_rounded, + Icons.nights_stay_sharp, + Icons.nine_k, + Icons.nine_k_outlined, + Icons.nine_k_plus, + Icons.nine_k_plus_outlined, + Icons.nine_k_plus_rounded, + Icons.nine_k_plus_sharp, + Icons.nine_k_rounded, + Icons.nine_k_sharp, + Icons.nine_mp, + Icons.nine_mp_outlined, + Icons.nine_mp_rounded, + Icons.nine_mp_sharp, + Icons.nineteen_mp, + Icons.nineteen_mp_outlined, + Icons.nineteen_mp_rounded, + Icons.nineteen_mp_sharp, + Icons.no_accounts, + Icons.no_accounts_outlined, + Icons.no_accounts_rounded, + Icons.no_accounts_sharp, + Icons.no_adult_content, + Icons.no_adult_content_outlined, + Icons.no_adult_content_rounded, + Icons.no_adult_content_sharp, + Icons.no_backpack, + Icons.no_backpack_outlined, + Icons.no_backpack_rounded, + Icons.no_backpack_sharp, + Icons.no_cell, + Icons.no_cell_outlined, + Icons.no_cell_rounded, + Icons.no_cell_sharp, + Icons.no_crash, + Icons.no_crash_outlined, + Icons.no_crash_rounded, + Icons.no_crash_sharp, + Icons.no_drinks, + Icons.no_drinks_outlined, + Icons.no_drinks_rounded, + Icons.no_drinks_sharp, + Icons.no_encryption, + Icons.no_encryption_gmailerrorred, + Icons.no_encryption_gmailerrorred_outlined, + Icons.no_encryption_gmailerrorred_rounded, + Icons.no_encryption_gmailerrorred_sharp, + Icons.no_encryption_outlined, + Icons.no_encryption_rounded, + Icons.no_encryption_sharp, + Icons.no_flash, + Icons.no_flash_outlined, + Icons.no_flash_rounded, + Icons.no_flash_sharp, + Icons.no_food, + Icons.no_food_outlined, + Icons.no_food_rounded, + Icons.no_food_sharp, + Icons.no_luggage, + Icons.no_luggage_outlined, + Icons.no_luggage_rounded, + Icons.no_luggage_sharp, + Icons.no_meals, + Icons.no_meals_ouline, + Icons.no_meals_outlined, + Icons.no_meals_rounded, + Icons.no_meals_sharp, + Icons.no_meeting_room, + Icons.no_meeting_room_outlined, + Icons.no_meeting_room_rounded, + Icons.no_meeting_room_sharp, + Icons.no_photography, + Icons.no_photography_outlined, + Icons.no_photography_rounded, + Icons.no_photography_sharp, + Icons.no_sim, + Icons.no_sim_outlined, + Icons.no_sim_rounded, + Icons.no_sim_sharp, + Icons.no_stroller, + Icons.no_stroller_outlined, + Icons.no_stroller_rounded, + Icons.no_stroller_sharp, + Icons.no_transfer, + Icons.no_transfer_outlined, + Icons.no_transfer_rounded, + Icons.no_transfer_sharp, + Icons.noise_aware, + Icons.noise_aware_outlined, + Icons.noise_aware_rounded, + Icons.noise_aware_sharp, + Icons.noise_control_off, + Icons.noise_control_off_outlined, + Icons.noise_control_off_rounded, + Icons.noise_control_off_sharp, + Icons.nordic_walking, + Icons.nordic_walking_outlined, + Icons.nordic_walking_rounded, + Icons.nordic_walking_sharp, + Icons.north, + Icons.north_east, + Icons.north_east_outlined, + Icons.north_east_rounded, + Icons.north_east_sharp, + Icons.north_outlined, + Icons.north_rounded, + Icons.north_sharp, + Icons.north_west, + Icons.north_west_outlined, + Icons.north_west_rounded, + Icons.north_west_sharp, + Icons.not_accessible, + Icons.not_accessible_outlined, + Icons.not_accessible_rounded, + Icons.not_accessible_sharp, + Icons.not_interested, + Icons.not_interested_outlined, + Icons.not_interested_rounded, + Icons.not_interested_sharp, + Icons.not_listed_location, + Icons.not_listed_location_outlined, + Icons.not_listed_location_rounded, + Icons.not_listed_location_sharp, + Icons.not_started, + Icons.not_started_outlined, + Icons.not_started_rounded, + Icons.not_started_sharp, + Icons.note, + Icons.note_add, + Icons.note_add_outlined, + Icons.note_add_rounded, + Icons.note_add_sharp, + Icons.note_alt, + Icons.note_alt_outlined, + Icons.note_alt_rounded, + Icons.note_alt_sharp, + Icons.note_outlined, + Icons.note_rounded, + Icons.note_sharp, + Icons.notes, + Icons.notes_outlined, + Icons.notes_rounded, + Icons.notes_sharp, + Icons.notification_add, + Icons.notification_add_outlined, + Icons.notification_add_rounded, + Icons.notification_add_sharp, + Icons.notification_important, + Icons.notification_important_outlined, + Icons.notification_important_rounded, + Icons.notification_important_sharp, + Icons.notifications, + Icons.notifications_active, + Icons.notifications_active_outlined, + Icons.notifications_active_rounded, + Icons.notifications_active_sharp, + Icons.notifications_none, + Icons.notifications_none_outlined, + Icons.notifications_none_rounded, + Icons.notifications_none_sharp, + Icons.notifications_off, + Icons.notifications_off_outlined, + Icons.notifications_off_rounded, + Icons.notifications_off_sharp, + Icons.notifications_on, + Icons.notifications_on_outlined, + Icons.notifications_on_rounded, + Icons.notifications_on_sharp, + Icons.notifications_outlined, + Icons.notifications_paused, + Icons.notifications_paused_outlined, + Icons.notifications_paused_rounded, + Icons.notifications_paused_sharp, + Icons.notifications_rounded, + Icons.notifications_sharp, + Icons.now_wallpaper, + Icons.now_wallpaper_outlined, + Icons.now_wallpaper_rounded, + Icons.now_wallpaper_sharp, + Icons.now_widgets, + Icons.now_widgets_outlined, + Icons.now_widgets_rounded, + Icons.now_widgets_sharp, + Icons.numbers, + Icons.numbers_outlined, + Icons.numbers_rounded, + Icons.numbers_sharp, + Icons.offline_bolt, + Icons.offline_bolt_outlined, + Icons.offline_bolt_rounded, + Icons.offline_bolt_sharp, + Icons.offline_pin, + Icons.offline_pin_outlined, + Icons.offline_pin_rounded, + Icons.offline_pin_sharp, + Icons.offline_share, + Icons.offline_share_outlined, + Icons.offline_share_rounded, + Icons.offline_share_sharp, + Icons.oil_barrel, + Icons.oil_barrel_outlined, + Icons.oil_barrel_rounded, + Icons.oil_barrel_sharp, + Icons.on_device_training, + Icons.on_device_training_outlined, + Icons.on_device_training_rounded, + Icons.on_device_training_sharp, + Icons.ondemand_video, + Icons.ondemand_video_outlined, + Icons.ondemand_video_rounded, + Icons.ondemand_video_sharp, + Icons.one_k, + Icons.one_k_outlined, + Icons.one_k_plus, + Icons.one_k_plus_outlined, + Icons.one_k_plus_rounded, + Icons.one_k_plus_sharp, + Icons.one_k_rounded, + Icons.one_k_sharp, + Icons.one_x_mobiledata, + Icons.one_x_mobiledata_outlined, + Icons.one_x_mobiledata_rounded, + Icons.one_x_mobiledata_sharp, + Icons.onetwothree, + Icons.onetwothree_outlined, + Icons.onetwothree_rounded, + Icons.onetwothree_sharp, + Icons.online_prediction, + Icons.online_prediction_outlined, + Icons.online_prediction_rounded, + Icons.online_prediction_sharp, + Icons.opacity, + Icons.opacity_outlined, + Icons.opacity_rounded, + Icons.opacity_sharp, + Icons.open_in_browser, + Icons.open_in_browser_outlined, + Icons.open_in_browser_rounded, + Icons.open_in_browser_sharp, + Icons.open_in_full, + Icons.open_in_full_outlined, + Icons.open_in_full_rounded, + Icons.open_in_full_sharp, + Icons.open_in_new, + Icons.open_in_new_off, + Icons.open_in_new_off_outlined, + Icons.open_in_new_off_rounded, + Icons.open_in_new_off_sharp, + Icons.open_in_new_outlined, + Icons.open_in_new_rounded, + Icons.open_in_new_sharp, + Icons.open_with, + Icons.open_with_outlined, + Icons.open_with_rounded, + Icons.open_with_sharp, + Icons.other_houses, + Icons.other_houses_outlined, + Icons.other_houses_rounded, + Icons.other_houses_sharp, + Icons.outbond, + Icons.outbond_outlined, + Icons.outbond_rounded, + Icons.outbond_sharp, + Icons.outbound, + Icons.outbound_outlined, + Icons.outbound_rounded, + Icons.outbound_sharp, + Icons.outbox, + Icons.outbox_outlined, + Icons.outbox_rounded, + Icons.outbox_sharp, + Icons.outdoor_grill, + Icons.outdoor_grill_outlined, + Icons.outdoor_grill_rounded, + Icons.outdoor_grill_sharp, + Icons.outgoing_mail, + Icons.outlet, + Icons.outlet_outlined, + Icons.outlet_rounded, + Icons.outlet_sharp, + Icons.outlined_flag, + Icons.outlined_flag_outlined, + Icons.outlined_flag_rounded, + Icons.outlined_flag_sharp, + Icons.output, + Icons.output_outlined, + Icons.output_rounded, + Icons.output_sharp, + Icons.padding, + Icons.padding_outlined, + Icons.padding_rounded, + Icons.padding_sharp, + Icons.pages, + Icons.pages_outlined, + Icons.pages_rounded, + Icons.pages_sharp, + Icons.pageview, + Icons.pageview_outlined, + Icons.pageview_rounded, + Icons.pageview_sharp, + Icons.paid, + Icons.paid_outlined, + Icons.paid_rounded, + Icons.paid_sharp, + Icons.palette, + Icons.palette_outlined, + Icons.palette_rounded, + Icons.palette_sharp, + Icons.pallet, + Icons.pan_tool, + Icons.pan_tool_alt, + Icons.pan_tool_alt_outlined, + Icons.pan_tool_alt_rounded, + Icons.pan_tool_alt_sharp, + Icons.pan_tool_outlined, + Icons.pan_tool_rounded, + Icons.pan_tool_sharp, + Icons.panorama, + Icons.panorama_fish_eye, + Icons.panorama_fish_eye_outlined, + Icons.panorama_fish_eye_rounded, + Icons.panorama_fish_eye_sharp, + Icons.panorama_fisheye, + Icons.panorama_fisheye_outlined, + Icons.panorama_fisheye_rounded, + Icons.panorama_fisheye_sharp, + Icons.panorama_horizontal, + Icons.panorama_horizontal_outlined, + Icons.panorama_horizontal_rounded, + Icons.panorama_horizontal_select, + Icons.panorama_horizontal_select_outlined, + Icons.panorama_horizontal_select_rounded, + Icons.panorama_horizontal_select_sharp, + Icons.panorama_horizontal_sharp, + Icons.panorama_outlined, + Icons.panorama_photosphere, + Icons.panorama_photosphere_outlined, + Icons.panorama_photosphere_rounded, + Icons.panorama_photosphere_select, + Icons.panorama_photosphere_select_outlined, + Icons.panorama_photosphere_select_rounded, + Icons.panorama_photosphere_select_sharp, + Icons.panorama_photosphere_sharp, + Icons.panorama_rounded, + Icons.panorama_sharp, + Icons.panorama_vertical, + Icons.panorama_vertical_outlined, + Icons.panorama_vertical_rounded, + Icons.panorama_vertical_select, + Icons.panorama_vertical_select_outlined, + Icons.panorama_vertical_select_rounded, + Icons.panorama_vertical_select_sharp, + Icons.panorama_vertical_sharp, + Icons.panorama_wide_angle, + Icons.panorama_wide_angle_outlined, + Icons.panorama_wide_angle_rounded, + Icons.panorama_wide_angle_select, + Icons.panorama_wide_angle_select_outlined, + Icons.panorama_wide_angle_select_rounded, + Icons.panorama_wide_angle_select_sharp, + Icons.panorama_wide_angle_sharp, + Icons.paragliding, + Icons.paragliding_outlined, + Icons.paragliding_rounded, + Icons.paragliding_sharp, + Icons.park, + Icons.park_outlined, + Icons.park_rounded, + Icons.park_sharp, + Icons.party_mode, + Icons.party_mode_outlined, + Icons.party_mode_rounded, + Icons.party_mode_sharp, + Icons.password, + Icons.password_outlined, + Icons.password_rounded, + Icons.password_sharp, + Icons.paste, + Icons.paste_outlined, + Icons.paste_rounded, + Icons.paste_sharp, + Icons.pattern, + Icons.pattern_outlined, + Icons.pattern_rounded, + Icons.pattern_sharp, + Icons.pause, + Icons.pause_circle, + Icons.pause_circle_filled, + Icons.pause_circle_filled_outlined, + Icons.pause_circle_filled_rounded, + Icons.pause_circle_filled_sharp, + Icons.pause_circle_outline, + Icons.pause_circle_outline_outlined, + Icons.pause_circle_outline_rounded, + Icons.pause_circle_outline_sharp, + Icons.pause_circle_outlined, + Icons.pause_circle_rounded, + Icons.pause_circle_sharp, + Icons.pause_outlined, + Icons.pause_presentation, + Icons.pause_presentation_outlined, + Icons.pause_presentation_rounded, + Icons.pause_presentation_sharp, + Icons.pause_rounded, + Icons.pause_sharp, + Icons.payment, + Icons.payment_outlined, + Icons.payment_rounded, + Icons.payment_sharp, + Icons.payments, + Icons.payments_outlined, + Icons.payments_rounded, + Icons.payments_sharp, + Icons.paypal, + Icons.paypal_outlined, + Icons.paypal_rounded, + Icons.paypal_sharp, + Icons.pedal_bike, + Icons.pedal_bike_outlined, + Icons.pedal_bike_rounded, + Icons.pedal_bike_sharp, + Icons.pending, + Icons.pending_actions, + Icons.pending_actions_outlined, + Icons.pending_actions_rounded, + Icons.pending_actions_sharp, + Icons.pending_outlined, + Icons.pending_rounded, + Icons.pending_sharp, + Icons.pentagon, + Icons.pentagon_outlined, + Icons.pentagon_rounded, + Icons.pentagon_sharp, + Icons.people, + Icons.people_alt, + Icons.people_alt_outlined, + Icons.people_alt_rounded, + Icons.people_alt_sharp, + Icons.people_outline, + Icons.people_outline_outlined, + Icons.people_outline_rounded, + Icons.people_outline_sharp, + Icons.people_outlined, + Icons.people_rounded, + Icons.people_sharp, + Icons.percent, + Icons.percent_outlined, + Icons.percent_rounded, + Icons.percent_sharp, + Icons.perm_camera_mic, + Icons.perm_camera_mic_outlined, + Icons.perm_camera_mic_rounded, + Icons.perm_camera_mic_sharp, + Icons.perm_contact_cal, + Icons.perm_contact_cal_outlined, + Icons.perm_contact_cal_rounded, + Icons.perm_contact_cal_sharp, + Icons.perm_contact_calendar, + Icons.perm_contact_calendar_outlined, + Icons.perm_contact_calendar_rounded, + Icons.perm_contact_calendar_sharp, + Icons.perm_data_setting, + Icons.perm_data_setting_outlined, + Icons.perm_data_setting_rounded, + Icons.perm_data_setting_sharp, + Icons.perm_device_info, + Icons.perm_device_info_outlined, + Icons.perm_device_info_rounded, + Icons.perm_device_info_sharp, + Icons.perm_device_information, + Icons.perm_device_information_outlined, + Icons.perm_device_information_rounded, + Icons.perm_device_information_sharp, + Icons.perm_identity, + Icons.perm_identity_outlined, + Icons.perm_identity_rounded, + Icons.perm_identity_sharp, + Icons.perm_media, + Icons.perm_media_outlined, + Icons.perm_media_rounded, + Icons.perm_media_sharp, + Icons.perm_phone_msg, + Icons.perm_phone_msg_outlined, + Icons.perm_phone_msg_rounded, + Icons.perm_phone_msg_sharp, + Icons.perm_scan_wifi, + Icons.perm_scan_wifi_outlined, + Icons.perm_scan_wifi_rounded, + Icons.perm_scan_wifi_sharp, + Icons.person, + Icons.person_2, + Icons.person_2_outlined, + Icons.person_2_rounded, + Icons.person_2_sharp, + Icons.person_3, + Icons.person_3_outlined, + Icons.person_3_rounded, + Icons.person_3_sharp, + Icons.person_4, + Icons.person_4_outlined, + Icons.person_4_rounded, + Icons.person_4_sharp, + Icons.person_add, + Icons.person_add_alt, + Icons.person_add_alt_1, + Icons.person_add_alt_1_outlined, + Icons.person_add_alt_1_rounded, + Icons.person_add_alt_1_sharp, + Icons.person_add_alt_outlined, + Icons.person_add_alt_rounded, + Icons.person_add_alt_sharp, + Icons.person_add_disabled, + Icons.person_add_disabled_outlined, + Icons.person_add_disabled_rounded, + Icons.person_add_disabled_sharp, + Icons.person_add_outlined, + Icons.person_add_rounded, + Icons.person_add_sharp, + Icons.person_off, + Icons.person_off_outlined, + Icons.person_off_rounded, + Icons.person_off_sharp, + Icons.person_outline, + Icons.person_outline_outlined, + Icons.person_outline_rounded, + Icons.person_outline_sharp, + Icons.person_outlined, + Icons.person_pin, + Icons.person_pin_circle, + Icons.person_pin_circle_outlined, + Icons.person_pin_circle_rounded, + Icons.person_pin_circle_sharp, + Icons.person_pin_outlined, + Icons.person_pin_rounded, + Icons.person_pin_sharp, + Icons.person_remove, + Icons.person_remove_alt_1, + Icons.person_remove_alt_1_outlined, + Icons.person_remove_alt_1_rounded, + Icons.person_remove_alt_1_sharp, + Icons.person_remove_outlined, + Icons.person_remove_rounded, + Icons.person_remove_sharp, + Icons.person_rounded, + Icons.person_search, + Icons.person_search_outlined, + Icons.person_search_rounded, + Icons.person_search_sharp, + Icons.person_sharp, + Icons.personal_injury, + Icons.personal_injury_outlined, + Icons.personal_injury_rounded, + Icons.personal_injury_sharp, + Icons.personal_video, + Icons.personal_video_outlined, + Icons.personal_video_rounded, + Icons.personal_video_sharp, + Icons.pest_control, + Icons.pest_control_outlined, + Icons.pest_control_rodent, + Icons.pest_control_rodent_outlined, + Icons.pest_control_rodent_rounded, + Icons.pest_control_rodent_sharp, + Icons.pest_control_rounded, + Icons.pest_control_sharp, + Icons.pets, + Icons.pets_outlined, + Icons.pets_rounded, + Icons.pets_sharp, + Icons.phishing, + Icons.phishing_outlined, + Icons.phishing_rounded, + Icons.phishing_sharp, + Icons.phone, + Icons.phone_android, + Icons.phone_android_outlined, + Icons.phone_android_rounded, + Icons.phone_android_sharp, + Icons.phone_bluetooth_speaker, + Icons.phone_bluetooth_speaker_outlined, + Icons.phone_bluetooth_speaker_rounded, + Icons.phone_bluetooth_speaker_sharp, + Icons.phone_callback, + Icons.phone_callback_outlined, + Icons.phone_callback_rounded, + Icons.phone_callback_sharp, + Icons.phone_disabled, + Icons.phone_disabled_outlined, + Icons.phone_disabled_rounded, + Icons.phone_disabled_sharp, + Icons.phone_enabled, + Icons.phone_enabled_outlined, + Icons.phone_enabled_rounded, + Icons.phone_enabled_sharp, + Icons.phone_forwarded, + Icons.phone_forwarded_outlined, + Icons.phone_forwarded_rounded, + Icons.phone_forwarded_sharp, + Icons.phone_in_talk, + Icons.phone_in_talk_outlined, + Icons.phone_in_talk_rounded, + Icons.phone_in_talk_sharp, + Icons.phone_iphone, + Icons.phone_iphone_outlined, + Icons.phone_iphone_rounded, + Icons.phone_iphone_sharp, + Icons.phone_locked, + Icons.phone_locked_outlined, + Icons.phone_locked_rounded, + Icons.phone_locked_sharp, + Icons.phone_missed, + Icons.phone_missed_outlined, + Icons.phone_missed_rounded, + Icons.phone_missed_sharp, + Icons.phone_outlined, + Icons.phone_paused, + Icons.phone_paused_outlined, + Icons.phone_paused_rounded, + Icons.phone_paused_sharp, + Icons.phone_rounded, + Icons.phone_sharp, + Icons.phonelink, + Icons.phonelink_erase, + Icons.phonelink_erase_outlined, + Icons.phonelink_erase_rounded, + Icons.phonelink_erase_sharp, + Icons.phonelink_lock, + Icons.phonelink_lock_outlined, + Icons.phonelink_lock_rounded, + Icons.phonelink_lock_sharp, + Icons.phonelink_off, + Icons.phonelink_off_outlined, + Icons.phonelink_off_rounded, + Icons.phonelink_off_sharp, + Icons.phonelink_outlined, + Icons.phonelink_ring, + Icons.phonelink_ring_outlined, + Icons.phonelink_ring_rounded, + Icons.phonelink_ring_sharp, + Icons.phonelink_rounded, + Icons.phonelink_setup, + Icons.phonelink_setup_outlined, + Icons.phonelink_setup_rounded, + Icons.phonelink_setup_sharp, + Icons.phonelink_sharp, + Icons.photo, + Icons.photo_album, + Icons.photo_album_outlined, + Icons.photo_album_rounded, + Icons.photo_album_sharp, + Icons.photo_camera, + Icons.photo_camera_back, + Icons.photo_camera_back_outlined, + Icons.photo_camera_back_rounded, + Icons.photo_camera_back_sharp, + Icons.photo_camera_front, + Icons.photo_camera_front_outlined, + Icons.photo_camera_front_rounded, + Icons.photo_camera_front_sharp, + Icons.photo_camera_outlined, + Icons.photo_camera_rounded, + Icons.photo_camera_sharp, + Icons.photo_filter, + Icons.photo_filter_outlined, + Icons.photo_filter_rounded, + Icons.photo_filter_sharp, + Icons.photo_library, + Icons.photo_library_outlined, + Icons.photo_library_rounded, + Icons.photo_library_sharp, + Icons.photo_outlined, + Icons.photo_rounded, + Icons.photo_sharp, + Icons.photo_size_select_actual, + Icons.photo_size_select_actual_outlined, + Icons.photo_size_select_actual_rounded, + Icons.photo_size_select_actual_sharp, + Icons.photo_size_select_large, + Icons.photo_size_select_large_outlined, + Icons.photo_size_select_large_rounded, + Icons.photo_size_select_large_sharp, + Icons.photo_size_select_small, + Icons.photo_size_select_small_outlined, + Icons.photo_size_select_small_rounded, + Icons.photo_size_select_small_sharp, + Icons.php, + Icons.php_outlined, + Icons.php_rounded, + Icons.php_sharp, + Icons.piano, + Icons.piano_off, + Icons.piano_off_outlined, + Icons.piano_off_rounded, + Icons.piano_off_sharp, + Icons.piano_outlined, + Icons.piano_rounded, + Icons.piano_sharp, + Icons.picture_as_pdf, + Icons.picture_as_pdf_outlined, + Icons.picture_as_pdf_rounded, + Icons.picture_as_pdf_sharp, + Icons.picture_in_picture, + Icons.picture_in_picture_alt, + Icons.picture_in_picture_alt_outlined, + Icons.picture_in_picture_alt_rounded, + Icons.picture_in_picture_alt_sharp, + Icons.picture_in_picture_outlined, + Icons.picture_in_picture_rounded, + Icons.picture_in_picture_sharp, + Icons.pie_chart, + Icons.pie_chart_outline, + Icons.pie_chart_outline_outlined, + Icons.pie_chart_outline_rounded, + Icons.pie_chart_outline_sharp, + Icons.pie_chart_rounded, + Icons.pie_chart_sharp, + Icons.pin, + Icons.pin_drop, + Icons.pin_drop_outlined, + Icons.pin_drop_rounded, + Icons.pin_drop_sharp, + Icons.pin_end, + Icons.pin_end_outlined, + Icons.pin_end_rounded, + Icons.pin_end_sharp, + Icons.pin_invoke, + Icons.pin_invoke_outlined, + Icons.pin_invoke_rounded, + Icons.pin_invoke_sharp, + Icons.pin_outlined, + Icons.pin_rounded, + Icons.pin_sharp, + Icons.pinch, + Icons.pinch_outlined, + Icons.pinch_rounded, + Icons.pinch_sharp, + Icons.pivot_table_chart, + Icons.pivot_table_chart_outlined, + Icons.pivot_table_chart_rounded, + Icons.pivot_table_chart_sharp, + Icons.pix, + Icons.pix_outlined, + Icons.pix_rounded, + Icons.pix_sharp, + Icons.place, + Icons.place_outlined, + Icons.place_rounded, + Icons.place_sharp, + Icons.plagiarism, + Icons.plagiarism_outlined, + Icons.plagiarism_rounded, + Icons.plagiarism_sharp, + Icons.play_arrow, + Icons.play_arrow_outlined, + Icons.play_arrow_rounded, + Icons.play_arrow_sharp, + Icons.play_circle, + Icons.play_circle_fill, + Icons.play_circle_fill_outlined, + Icons.play_circle_fill_rounded, + Icons.play_circle_fill_sharp, + Icons.play_circle_filled, + Icons.play_circle_filled_outlined, + Icons.play_circle_filled_rounded, + Icons.play_circle_filled_sharp, + Icons.play_circle_outline, + Icons.play_circle_outline_outlined, + Icons.play_circle_outline_rounded, + Icons.play_circle_outline_sharp, + Icons.play_circle_outlined, + Icons.play_circle_rounded, + Icons.play_circle_sharp, + Icons.play_disabled, + Icons.play_disabled_outlined, + Icons.play_disabled_rounded, + Icons.play_disabled_sharp, + Icons.play_for_work, + Icons.play_for_work_outlined, + Icons.play_for_work_rounded, + Icons.play_for_work_sharp, + Icons.play_lesson, + Icons.play_lesson_outlined, + Icons.play_lesson_rounded, + Icons.play_lesson_sharp, + Icons.playlist_add, + Icons.playlist_add_check, + Icons.playlist_add_check_circle, + Icons.playlist_add_check_circle_outlined, + Icons.playlist_add_check_circle_rounded, + Icons.playlist_add_check_circle_sharp, + Icons.playlist_add_check_outlined, + Icons.playlist_add_check_rounded, + Icons.playlist_add_check_sharp, + Icons.playlist_add_circle, + Icons.playlist_add_circle_outlined, + Icons.playlist_add_circle_rounded, + Icons.playlist_add_circle_sharp, + Icons.playlist_add_outlined, + Icons.playlist_add_rounded, + Icons.playlist_add_sharp, + Icons.playlist_play, + Icons.playlist_play_outlined, + Icons.playlist_play_rounded, + Icons.playlist_play_sharp, + Icons.playlist_remove, + Icons.playlist_remove_outlined, + Icons.playlist_remove_rounded, + Icons.playlist_remove_sharp, + Icons.plumbing, + Icons.plumbing_outlined, + Icons.plumbing_rounded, + Icons.plumbing_sharp, + Icons.plus_one, + Icons.plus_one_outlined, + Icons.plus_one_rounded, + Icons.plus_one_sharp, + Icons.podcasts, + Icons.podcasts_outlined, + Icons.podcasts_rounded, + Icons.podcasts_sharp, + Icons.point_of_sale, + Icons.point_of_sale_outlined, + Icons.point_of_sale_rounded, + Icons.point_of_sale_sharp, + Icons.policy, + Icons.policy_outlined, + Icons.policy_rounded, + Icons.policy_sharp, + Icons.poll, + Icons.poll_outlined, + Icons.poll_rounded, + Icons.poll_sharp, + Icons.polyline, + Icons.polyline_outlined, + Icons.polyline_rounded, + Icons.polyline_sharp, + Icons.polymer, + Icons.polymer_outlined, + Icons.polymer_rounded, + Icons.polymer_sharp, + Icons.pool, + Icons.pool_outlined, + Icons.pool_rounded, + Icons.pool_sharp, + Icons.portable_wifi_off, + Icons.portable_wifi_off_outlined, + Icons.portable_wifi_off_rounded, + Icons.portable_wifi_off_sharp, + Icons.portrait, + Icons.portrait_outlined, + Icons.portrait_rounded, + Icons.portrait_sharp, + Icons.post_add, + Icons.post_add_outlined, + Icons.post_add_rounded, + Icons.post_add_sharp, + Icons.power, + Icons.power_input, + Icons.power_input_outlined, + Icons.power_input_rounded, + Icons.power_input_sharp, + Icons.power_off, + Icons.power_off_outlined, + Icons.power_off_rounded, + Icons.power_off_sharp, + Icons.power_outlined, + Icons.power_rounded, + Icons.power_settings_new, + Icons.power_settings_new_outlined, + Icons.power_settings_new_rounded, + Icons.power_settings_new_sharp, + Icons.power_sharp, + Icons.precision_manufacturing, + Icons.precision_manufacturing_outlined, + Icons.precision_manufacturing_rounded, + Icons.precision_manufacturing_sharp, + Icons.pregnant_woman, + Icons.pregnant_woman_outlined, + Icons.pregnant_woman_rounded, + Icons.pregnant_woman_sharp, + Icons.present_to_all, + Icons.present_to_all_outlined, + Icons.present_to_all_rounded, + Icons.present_to_all_sharp, + Icons.preview, + Icons.preview_outlined, + Icons.preview_rounded, + Icons.preview_sharp, + Icons.price_change, + Icons.price_change_outlined, + Icons.price_change_rounded, + Icons.price_change_sharp, + Icons.price_check, + Icons.price_check_outlined, + Icons.price_check_rounded, + Icons.price_check_sharp, + Icons.print, + Icons.print_disabled, + Icons.print_disabled_outlined, + Icons.print_disabled_rounded, + Icons.print_disabled_sharp, + Icons.print_outlined, + Icons.print_rounded, + Icons.print_sharp, + Icons.priority_high, + Icons.priority_high_outlined, + Icons.priority_high_rounded, + Icons.priority_high_sharp, + Icons.privacy_tip, + Icons.privacy_tip_outlined, + Icons.privacy_tip_rounded, + Icons.privacy_tip_sharp, + Icons.private_connectivity, + Icons.private_connectivity_outlined, + Icons.private_connectivity_rounded, + Icons.private_connectivity_sharp, + Icons.production_quantity_limits, + Icons.production_quantity_limits_outlined, + Icons.production_quantity_limits_rounded, + Icons.production_quantity_limits_sharp, + Icons.propane, + Icons.propane_outlined, + Icons.propane_rounded, + Icons.propane_sharp, + Icons.propane_tank, + Icons.propane_tank_outlined, + Icons.propane_tank_rounded, + Icons.propane_tank_sharp, + Icons.psychology, + Icons.psychology_alt, + Icons.psychology_alt_outlined, + Icons.psychology_alt_rounded, + Icons.psychology_alt_sharp, + Icons.psychology_outlined, + Icons.psychology_rounded, + Icons.psychology_sharp, + Icons.public, + Icons.public_off, + Icons.public_off_outlined, + Icons.public_off_rounded, + Icons.public_off_sharp, + Icons.public_outlined, + Icons.public_rounded, + Icons.public_sharp, + Icons.publish, + Icons.publish_outlined, + Icons.publish_rounded, + Icons.publish_sharp, + Icons.published_with_changes, + Icons.published_with_changes_outlined, + Icons.published_with_changes_rounded, + Icons.published_with_changes_sharp, + Icons.punch_clock, + Icons.punch_clock_outlined, + Icons.punch_clock_rounded, + Icons.punch_clock_sharp, + Icons.push_pin, + Icons.push_pin_outlined, + Icons.push_pin_rounded, + Icons.push_pin_sharp, + Icons.qr_code, + Icons.qr_code_2, + Icons.qr_code_2_outlined, + Icons.qr_code_2_rounded, + Icons.qr_code_2_sharp, + Icons.qr_code_outlined, + Icons.qr_code_rounded, + Icons.qr_code_scanner, + Icons.qr_code_scanner_outlined, + Icons.qr_code_scanner_rounded, + Icons.qr_code_scanner_sharp, + Icons.qr_code_sharp, + Icons.query_builder, + Icons.query_builder_outlined, + Icons.query_builder_rounded, + Icons.query_builder_sharp, + Icons.query_stats, + Icons.query_stats_outlined, + Icons.query_stats_rounded, + Icons.query_stats_sharp, + Icons.question_answer, + Icons.question_answer_outlined, + Icons.question_answer_rounded, + Icons.question_answer_sharp, + Icons.question_mark, + Icons.question_mark_outlined, + Icons.question_mark_rounded, + Icons.question_mark_sharp, + Icons.queue, + Icons.queue_music, + Icons.queue_music_outlined, + Icons.queue_music_rounded, + Icons.queue_music_sharp, + Icons.queue_outlined, + Icons.queue_play_next, + Icons.queue_play_next_outlined, + Icons.queue_play_next_rounded, + Icons.queue_play_next_sharp, + Icons.queue_rounded, + Icons.queue_sharp, + Icons.quick_contacts_dialer, + Icons.quick_contacts_dialer_outlined, + Icons.quick_contacts_dialer_rounded, + Icons.quick_contacts_dialer_sharp, + Icons.quick_contacts_mail, + Icons.quick_contacts_mail_outlined, + Icons.quick_contacts_mail_rounded, + Icons.quick_contacts_mail_sharp, + Icons.quickreply, + Icons.quickreply_outlined, + Icons.quickreply_rounded, + Icons.quickreply_sharp, + Icons.quiz, + Icons.quiz_outlined, + Icons.quiz_rounded, + Icons.quiz_sharp, + Icons.quora, + Icons.quora_outlined, + Icons.quora_rounded, + Icons.quora_sharp, + Icons.r_mobiledata, + Icons.r_mobiledata_outlined, + Icons.r_mobiledata_rounded, + Icons.r_mobiledata_sharp, + Icons.radar, + Icons.radar_outlined, + Icons.radar_rounded, + Icons.radar_sharp, + Icons.radio, + Icons.radio_button_checked, + Icons.radio_button_checked_outlined, + Icons.radio_button_checked_rounded, + Icons.radio_button_checked_sharp, + Icons.radio_button_off, + Icons.radio_button_off_outlined, + Icons.radio_button_off_rounded, + Icons.radio_button_off_sharp, + Icons.radio_button_on, + Icons.radio_button_on_outlined, + Icons.radio_button_on_rounded, + Icons.radio_button_on_sharp, + Icons.radio_button_unchecked, + Icons.radio_button_unchecked_outlined, + Icons.radio_button_unchecked_rounded, + Icons.radio_button_unchecked_sharp, + Icons.radio_outlined, + Icons.radio_rounded, + Icons.radio_sharp, + Icons.railway_alert, + Icons.railway_alert_outlined, + Icons.railway_alert_rounded, + Icons.railway_alert_sharp, + Icons.ramen_dining, + Icons.ramen_dining_outlined, + Icons.ramen_dining_rounded, + Icons.ramen_dining_sharp, + Icons.ramp_left, + Icons.ramp_left_outlined, + Icons.ramp_left_rounded, + Icons.ramp_left_sharp, + Icons.ramp_right, + Icons.ramp_right_outlined, + Icons.ramp_right_rounded, + Icons.ramp_right_sharp, + Icons.rate_review, + Icons.rate_review_outlined, + Icons.rate_review_rounded, + Icons.rate_review_sharp, + Icons.raw_off, + Icons.raw_off_outlined, + Icons.raw_off_rounded, + Icons.raw_off_sharp, + Icons.raw_on, + Icons.raw_on_outlined, + Icons.raw_on_rounded, + Icons.raw_on_sharp, + Icons.read_more, + Icons.read_more_outlined, + Icons.read_more_rounded, + Icons.read_more_sharp, + Icons.real_estate_agent, + Icons.real_estate_agent_outlined, + Icons.real_estate_agent_rounded, + Icons.real_estate_agent_sharp, + Icons.rebase_edit, + Icons.receipt, + Icons.receipt_long, + Icons.receipt_long_outlined, + Icons.receipt_long_rounded, + Icons.receipt_long_sharp, + Icons.receipt_outlined, + Icons.receipt_rounded, + Icons.receipt_sharp, + Icons.recent_actors, + Icons.recent_actors_outlined, + Icons.recent_actors_rounded, + Icons.recent_actors_sharp, + Icons.recommend, + Icons.recommend_outlined, + Icons.recommend_rounded, + Icons.recommend_sharp, + Icons.record_voice_over, + Icons.record_voice_over_outlined, + Icons.record_voice_over_rounded, + Icons.record_voice_over_sharp, + Icons.rectangle, + Icons.rectangle_outlined, + Icons.rectangle_rounded, + Icons.rectangle_sharp, + Icons.recycling, + Icons.recycling_outlined, + Icons.recycling_rounded, + Icons.recycling_sharp, + Icons.reddit, + Icons.reddit_outlined, + Icons.reddit_rounded, + Icons.reddit_sharp, + Icons.redeem, + Icons.redeem_outlined, + Icons.redeem_rounded, + Icons.redeem_sharp, + Icons.redo, + Icons.redo_outlined, + Icons.redo_rounded, + Icons.redo_sharp, + Icons.reduce_capacity, + Icons.reduce_capacity_outlined, + Icons.reduce_capacity_rounded, + Icons.reduce_capacity_sharp, + Icons.refresh, + Icons.refresh_outlined, + Icons.refresh_rounded, + Icons.refresh_sharp, + Icons.remember_me, + Icons.remember_me_outlined, + Icons.remember_me_rounded, + Icons.remember_me_sharp, + Icons.remove, + Icons.remove_circle, + Icons.remove_circle_outline, + Icons.remove_circle_outline_outlined, + Icons.remove_circle_outline_rounded, + Icons.remove_circle_outline_sharp, + Icons.remove_circle_outlined, + Icons.remove_circle_rounded, + Icons.remove_circle_sharp, + Icons.remove_done, + Icons.remove_done_outlined, + Icons.remove_done_rounded, + Icons.remove_done_sharp, + Icons.remove_from_queue, + Icons.remove_from_queue_outlined, + Icons.remove_from_queue_rounded, + Icons.remove_from_queue_sharp, + Icons.remove_moderator, + Icons.remove_moderator_outlined, + Icons.remove_moderator_rounded, + Icons.remove_moderator_sharp, + Icons.remove_outlined, + Icons.remove_red_eye, + Icons.remove_red_eye_outlined, + Icons.remove_red_eye_rounded, + Icons.remove_red_eye_sharp, + Icons.remove_road, + Icons.remove_road_outlined, + Icons.remove_road_rounded, + Icons.remove_road_sharp, + Icons.remove_rounded, + Icons.remove_sharp, + Icons.remove_shopping_cart, + Icons.remove_shopping_cart_outlined, + Icons.remove_shopping_cart_rounded, + Icons.remove_shopping_cart_sharp, + Icons.reorder, + Icons.reorder_outlined, + Icons.reorder_rounded, + Icons.reorder_sharp, + Icons.repartition, + Icons.repartition_outlined, + Icons.repartition_rounded, + Icons.repartition_sharp, + Icons.repeat, + Icons.repeat_on, + Icons.repeat_on_outlined, + Icons.repeat_on_rounded, + Icons.repeat_on_sharp, + Icons.repeat_one, + Icons.repeat_one_on, + Icons.repeat_one_on_outlined, + Icons.repeat_one_on_rounded, + Icons.repeat_one_on_sharp, + Icons.repeat_one_outlined, + Icons.repeat_one_rounded, + Icons.repeat_one_sharp, + Icons.repeat_outlined, + Icons.repeat_rounded, + Icons.repeat_sharp, + Icons.replay, + Icons.replay_10, + Icons.replay_10_outlined, + Icons.replay_10_rounded, + Icons.replay_10_sharp, + Icons.replay_30, + Icons.replay_30_outlined, + Icons.replay_30_rounded, + Icons.replay_30_sharp, + Icons.replay_5, + Icons.replay_5_outlined, + Icons.replay_5_rounded, + Icons.replay_5_sharp, + Icons.replay_circle_filled, + Icons.replay_circle_filled_outlined, + Icons.replay_circle_filled_rounded, + Icons.replay_circle_filled_sharp, + Icons.replay_outlined, + Icons.replay_rounded, + Icons.replay_sharp, + Icons.reply, + Icons.reply_all, + Icons.reply_all_outlined, + Icons.reply_all_rounded, + Icons.reply_all_sharp, + Icons.reply_outlined, + Icons.reply_rounded, + Icons.reply_sharp, + Icons.report, + Icons.report_gmailerrorred, + Icons.report_gmailerrorred_outlined, + Icons.report_gmailerrorred_rounded, + Icons.report_gmailerrorred_sharp, + Icons.report_off, + Icons.report_off_outlined, + Icons.report_off_rounded, + Icons.report_off_sharp, + Icons.report_outlined, + Icons.report_problem, + Icons.report_problem_outlined, + Icons.report_problem_rounded, + Icons.report_problem_sharp, + Icons.report_rounded, + Icons.report_sharp, + Icons.request_page, + Icons.request_page_outlined, + Icons.request_page_rounded, + Icons.request_page_sharp, + Icons.request_quote, + Icons.request_quote_outlined, + Icons.request_quote_rounded, + Icons.request_quote_sharp, + Icons.reset_tv, + Icons.reset_tv_outlined, + Icons.reset_tv_rounded, + Icons.reset_tv_sharp, + Icons.restart_alt, + Icons.restart_alt_outlined, + Icons.restart_alt_rounded, + Icons.restart_alt_sharp, + Icons.restaurant, + Icons.restaurant_menu, + Icons.restaurant_menu_outlined, + Icons.restaurant_menu_rounded, + Icons.restaurant_menu_sharp, + Icons.restaurant_outlined, + Icons.restaurant_rounded, + Icons.restaurant_sharp, + Icons.restore, + Icons.restore_from_trash, + Icons.restore_from_trash_outlined, + Icons.restore_from_trash_rounded, + Icons.restore_from_trash_sharp, + Icons.restore_outlined, + Icons.restore_page, + Icons.restore_page_outlined, + Icons.restore_page_rounded, + Icons.restore_page_sharp, + Icons.restore_rounded, + Icons.restore_sharp, + Icons.reviews, + Icons.reviews_outlined, + Icons.reviews_rounded, + Icons.reviews_sharp, + Icons.rice_bowl, + Icons.rice_bowl_outlined, + Icons.rice_bowl_rounded, + Icons.rice_bowl_sharp, + Icons.ring_volume, + Icons.ring_volume_outlined, + Icons.ring_volume_rounded, + Icons.ring_volume_sharp, + Icons.rocket, + Icons.rocket_launch, + Icons.rocket_launch_outlined, + Icons.rocket_launch_rounded, + Icons.rocket_launch_sharp, + Icons.rocket_outlined, + Icons.rocket_rounded, + Icons.rocket_sharp, + Icons.roller_shades, + Icons.roller_shades_closed, + Icons.roller_shades_closed_outlined, + Icons.roller_shades_closed_rounded, + Icons.roller_shades_closed_sharp, + Icons.roller_shades_outlined, + Icons.roller_shades_rounded, + Icons.roller_shades_sharp, + Icons.roller_skating, + Icons.roller_skating_outlined, + Icons.roller_skating_rounded, + Icons.roller_skating_sharp, + Icons.roofing, + Icons.roofing_outlined, + Icons.roofing_rounded, + Icons.roofing_sharp, + Icons.room, + Icons.room_outlined, + Icons.room_preferences, + Icons.room_preferences_outlined, + Icons.room_preferences_rounded, + Icons.room_preferences_sharp, + Icons.room_rounded, + Icons.room_service, + Icons.room_service_outlined, + Icons.room_service_rounded, + Icons.room_service_sharp, + Icons.room_sharp, + Icons.rotate_90_degrees_ccw, + Icons.rotate_90_degrees_ccw_outlined, + Icons.rotate_90_degrees_ccw_rounded, + Icons.rotate_90_degrees_ccw_sharp, + Icons.rotate_90_degrees_cw, + Icons.rotate_90_degrees_cw_outlined, + Icons.rotate_90_degrees_cw_rounded, + Icons.rotate_90_degrees_cw_sharp, + Icons.rotate_left, + Icons.rotate_left_outlined, + Icons.rotate_left_rounded, + Icons.rotate_left_sharp, + Icons.rotate_right, + Icons.rotate_right_outlined, + Icons.rotate_right_rounded, + Icons.rotate_right_sharp, + Icons.roundabout_left, + Icons.roundabout_left_outlined, + Icons.roundabout_left_rounded, + Icons.roundabout_left_sharp, + Icons.roundabout_right, + Icons.roundabout_right_outlined, + Icons.roundabout_right_rounded, + Icons.roundabout_right_sharp, + Icons.rounded_corner, + Icons.rounded_corner_outlined, + Icons.rounded_corner_rounded, + Icons.rounded_corner_sharp, + Icons.route, + Icons.route_outlined, + Icons.route_rounded, + Icons.route_sharp, + Icons.router, + Icons.router_outlined, + Icons.router_rounded, + Icons.router_sharp, + Icons.rowing, + Icons.rowing_outlined, + Icons.rowing_rounded, + Icons.rowing_sharp, + Icons.rss_feed, + Icons.rss_feed_outlined, + Icons.rss_feed_rounded, + Icons.rss_feed_sharp, + Icons.rsvp, + Icons.rsvp_outlined, + Icons.rsvp_rounded, + Icons.rsvp_sharp, + Icons.rtt, + Icons.rtt_outlined, + Icons.rtt_rounded, + Icons.rtt_sharp, + Icons.rule, + Icons.rule_folder, + Icons.rule_folder_outlined, + Icons.rule_folder_rounded, + Icons.rule_folder_sharp, + Icons.rule_outlined, + Icons.rule_rounded, + Icons.rule_sharp, + Icons.run_circle, + Icons.run_circle_outlined, + Icons.run_circle_rounded, + Icons.run_circle_sharp, + Icons.running_with_errors, + Icons.running_with_errors_outlined, + Icons.running_with_errors_rounded, + Icons.running_with_errors_sharp, + Icons.rv_hookup, + Icons.rv_hookup_outlined, + Icons.rv_hookup_rounded, + Icons.rv_hookup_sharp, + Icons.safety_check, + Icons.safety_check_outlined, + Icons.safety_check_rounded, + Icons.safety_check_sharp, + Icons.safety_divider, + Icons.safety_divider_outlined, + Icons.safety_divider_rounded, + Icons.safety_divider_sharp, + Icons.sailing, + Icons.sailing_outlined, + Icons.sailing_rounded, + Icons.sailing_sharp, + Icons.sanitizer, + Icons.sanitizer_outlined, + Icons.sanitizer_rounded, + Icons.sanitizer_sharp, + Icons.satellite, + Icons.satellite_alt, + Icons.satellite_alt_outlined, + Icons.satellite_alt_rounded, + Icons.satellite_alt_sharp, + Icons.satellite_outlined, + Icons.satellite_rounded, + Icons.satellite_sharp, + Icons.save, + Icons.save_alt, + Icons.save_alt_outlined, + Icons.save_alt_rounded, + Icons.save_alt_sharp, + Icons.save_as, + Icons.save_as_outlined, + Icons.save_as_rounded, + Icons.save_as_sharp, + Icons.save_outlined, + Icons.save_rounded, + Icons.save_sharp, + Icons.saved_search, + Icons.saved_search_outlined, + Icons.saved_search_rounded, + Icons.saved_search_sharp, + Icons.savings, + Icons.savings_outlined, + Icons.savings_rounded, + Icons.savings_sharp, + Icons.scale, + Icons.scale_outlined, + Icons.scale_rounded, + Icons.scale_sharp, + Icons.scanner, + Icons.scanner_outlined, + Icons.scanner_rounded, + Icons.scanner_sharp, + Icons.scatter_plot, + Icons.scatter_plot_outlined, + Icons.scatter_plot_rounded, + Icons.scatter_plot_sharp, + Icons.schedule, + Icons.schedule_outlined, + Icons.schedule_rounded, + Icons.schedule_send, + Icons.schedule_send_outlined, + Icons.schedule_send_rounded, + Icons.schedule_send_sharp, + Icons.schedule_sharp, + Icons.schema, + Icons.schema_outlined, + Icons.schema_rounded, + Icons.schema_sharp, + Icons.school, + Icons.school_outlined, + Icons.school_rounded, + Icons.school_sharp, + Icons.science, + Icons.science_outlined, + Icons.science_rounded, + Icons.science_sharp, + Icons.score, + Icons.score_outlined, + Icons.score_rounded, + Icons.score_sharp, + Icons.scoreboard, + Icons.scoreboard_outlined, + Icons.scoreboard_rounded, + Icons.scoreboard_sharp, + Icons.screen_lock_landscape, + Icons.screen_lock_landscape_outlined, + Icons.screen_lock_landscape_rounded, + Icons.screen_lock_landscape_sharp, + Icons.screen_lock_portrait, + Icons.screen_lock_portrait_outlined, + Icons.screen_lock_portrait_rounded, + Icons.screen_lock_portrait_sharp, + Icons.screen_lock_rotation, + Icons.screen_lock_rotation_outlined, + Icons.screen_lock_rotation_rounded, + Icons.screen_lock_rotation_sharp, + Icons.screen_rotation, + Icons.screen_rotation_alt, + Icons.screen_rotation_alt_outlined, + Icons.screen_rotation_alt_rounded, + Icons.screen_rotation_alt_sharp, + Icons.screen_rotation_outlined, + Icons.screen_rotation_rounded, + Icons.screen_rotation_sharp, + Icons.screen_search_desktop, + Icons.screen_search_desktop_outlined, + Icons.screen_search_desktop_rounded, + Icons.screen_search_desktop_sharp, + Icons.screen_share, + Icons.screen_share_outlined, + Icons.screen_share_rounded, + Icons.screen_share_sharp, + Icons.screenshot, + Icons.screenshot_monitor, + Icons.screenshot_monitor_outlined, + Icons.screenshot_monitor_rounded, + Icons.screenshot_monitor_sharp, + Icons.screenshot_outlined, + Icons.screenshot_rounded, + Icons.screenshot_sharp, + Icons.scuba_diving, + Icons.scuba_diving_outlined, + Icons.scuba_diving_rounded, + Icons.scuba_diving_sharp, + Icons.sd, + Icons.sd_card, + Icons.sd_card_alert, + Icons.sd_card_alert_outlined, + Icons.sd_card_alert_rounded, + Icons.sd_card_alert_sharp, + Icons.sd_card_outlined, + Icons.sd_card_rounded, + Icons.sd_card_sharp, + Icons.sd_outlined, + Icons.sd_rounded, + Icons.sd_sharp, + Icons.sd_storage, + Icons.sd_storage_outlined, + Icons.sd_storage_rounded, + Icons.sd_storage_sharp, + Icons.search, + Icons.search_off, + Icons.search_off_outlined, + Icons.search_off_rounded, + Icons.search_off_sharp, + Icons.search_outlined, + Icons.search_rounded, + Icons.search_sharp, + Icons.security, + Icons.security_outlined, + Icons.security_rounded, + Icons.security_sharp, + Icons.security_update, + Icons.security_update_good, + Icons.security_update_good_outlined, + Icons.security_update_good_rounded, + Icons.security_update_good_sharp, + Icons.security_update_outlined, + Icons.security_update_rounded, + Icons.security_update_sharp, + Icons.security_update_warning, + Icons.security_update_warning_outlined, + Icons.security_update_warning_rounded, + Icons.security_update_warning_sharp, + Icons.segment, + Icons.segment_outlined, + Icons.segment_rounded, + Icons.segment_sharp, + Icons.select_all, + Icons.select_all_outlined, + Icons.select_all_rounded, + Icons.select_all_sharp, + Icons.self_improvement, + Icons.self_improvement_outlined, + Icons.self_improvement_rounded, + Icons.self_improvement_sharp, + Icons.sell, + Icons.sell_outlined, + Icons.sell_rounded, + Icons.sell_sharp, + Icons.send, + Icons.send_and_archive, + Icons.send_and_archive_outlined, + Icons.send_and_archive_rounded, + Icons.send_and_archive_sharp, + Icons.send_outlined, + Icons.send_rounded, + Icons.send_sharp, + Icons.send_time_extension, + Icons.send_time_extension_outlined, + Icons.send_time_extension_rounded, + Icons.send_time_extension_sharp, + Icons.send_to_mobile, + Icons.send_to_mobile_outlined, + Icons.send_to_mobile_rounded, + Icons.send_to_mobile_sharp, + Icons.sensor_door, + Icons.sensor_door_outlined, + Icons.sensor_door_rounded, + Icons.sensor_door_sharp, + Icons.sensor_occupied, + Icons.sensor_occupied_outlined, + Icons.sensor_occupied_rounded, + Icons.sensor_occupied_sharp, + Icons.sensor_window, + Icons.sensor_window_outlined, + Icons.sensor_window_rounded, + Icons.sensor_window_sharp, + Icons.sensors, + Icons.sensors_off, + Icons.sensors_off_outlined, + Icons.sensors_off_rounded, + Icons.sensors_off_sharp, + Icons.sensors_outlined, + Icons.sensors_rounded, + Icons.sensors_sharp, + Icons.sentiment_dissatisfied, + Icons.sentiment_dissatisfied_outlined, + Icons.sentiment_dissatisfied_rounded, + Icons.sentiment_dissatisfied_sharp, + Icons.sentiment_neutral, + Icons.sentiment_neutral_outlined, + Icons.sentiment_neutral_rounded, + Icons.sentiment_neutral_sharp, + Icons.sentiment_satisfied, + Icons.sentiment_satisfied_alt, + Icons.sentiment_satisfied_alt_outlined, + Icons.sentiment_satisfied_alt_rounded, + Icons.sentiment_satisfied_alt_sharp, + Icons.sentiment_satisfied_outlined, + Icons.sentiment_satisfied_rounded, + Icons.sentiment_satisfied_sharp, + Icons.sentiment_very_dissatisfied, + Icons.sentiment_very_dissatisfied_outlined, + Icons.sentiment_very_dissatisfied_rounded, + Icons.sentiment_very_dissatisfied_sharp, + Icons.sentiment_very_satisfied, + Icons.sentiment_very_satisfied_outlined, + Icons.sentiment_very_satisfied_rounded, + Icons.sentiment_very_satisfied_sharp, + Icons.set_meal, + Icons.set_meal_outlined, + Icons.set_meal_rounded, + Icons.set_meal_sharp, + Icons.settings, + Icons.settings_accessibility, + Icons.settings_accessibility_outlined, + Icons.settings_accessibility_rounded, + Icons.settings_accessibility_sharp, + Icons.settings_applications, + Icons.settings_applications_outlined, + Icons.settings_applications_rounded, + Icons.settings_applications_sharp, + Icons.settings_backup_restore, + Icons.settings_backup_restore_outlined, + Icons.settings_backup_restore_rounded, + Icons.settings_backup_restore_sharp, + Icons.settings_bluetooth, + Icons.settings_bluetooth_outlined, + Icons.settings_bluetooth_rounded, + Icons.settings_bluetooth_sharp, + Icons.settings_brightness, + Icons.settings_brightness_outlined, + Icons.settings_brightness_rounded, + Icons.settings_brightness_sharp, + Icons.settings_cell, + Icons.settings_cell_outlined, + Icons.settings_cell_rounded, + Icons.settings_cell_sharp, + Icons.settings_display, + Icons.settings_display_outlined, + Icons.settings_display_rounded, + Icons.settings_display_sharp, + Icons.settings_ethernet, + Icons.settings_ethernet_outlined, + Icons.settings_ethernet_rounded, + Icons.settings_ethernet_sharp, + Icons.settings_input_antenna, + Icons.settings_input_antenna_outlined, + Icons.settings_input_antenna_rounded, + Icons.settings_input_antenna_sharp, + Icons.settings_input_component, + Icons.settings_input_component_outlined, + Icons.settings_input_component_rounded, + Icons.settings_input_component_sharp, + Icons.settings_input_composite, + Icons.settings_input_composite_outlined, + Icons.settings_input_composite_rounded, + Icons.settings_input_composite_sharp, + Icons.settings_input_hdmi, + Icons.settings_input_hdmi_outlined, + Icons.settings_input_hdmi_rounded, + Icons.settings_input_hdmi_sharp, + Icons.settings_input_svideo, + Icons.settings_input_svideo_outlined, + Icons.settings_input_svideo_rounded, + Icons.settings_input_svideo_sharp, + Icons.settings_outlined, + Icons.settings_overscan, + Icons.settings_overscan_outlined, + Icons.settings_overscan_rounded, + Icons.settings_overscan_sharp, + Icons.settings_phone, + Icons.settings_phone_outlined, + Icons.settings_phone_rounded, + Icons.settings_phone_sharp, + Icons.settings_power, + Icons.settings_power_outlined, + Icons.settings_power_rounded, + Icons.settings_power_sharp, + Icons.settings_remote, + Icons.settings_remote_outlined, + Icons.settings_remote_rounded, + Icons.settings_remote_sharp, + Icons.settings_rounded, + Icons.settings_sharp, + Icons.settings_suggest, + Icons.settings_suggest_outlined, + Icons.settings_suggest_rounded, + Icons.settings_suggest_sharp, + Icons.settings_system_daydream, + Icons.settings_system_daydream_outlined, + Icons.settings_system_daydream_rounded, + Icons.settings_system_daydream_sharp, + Icons.settings_voice, + Icons.settings_voice_outlined, + Icons.settings_voice_rounded, + Icons.settings_voice_sharp, + Icons.seven_k, + Icons.seven_k_outlined, + Icons.seven_k_plus, + Icons.seven_k_plus_outlined, + Icons.seven_k_plus_rounded, + Icons.seven_k_plus_sharp, + Icons.seven_k_rounded, + Icons.seven_k_sharp, + Icons.seven_mp, + Icons.seven_mp_outlined, + Icons.seven_mp_rounded, + Icons.seven_mp_sharp, + Icons.seventeen_mp, + Icons.seventeen_mp_outlined, + Icons.seventeen_mp_rounded, + Icons.seventeen_mp_sharp, + Icons.severe_cold, + Icons.severe_cold_outlined, + Icons.severe_cold_rounded, + Icons.severe_cold_sharp, + Icons.shape_line, + Icons.shape_line_outlined, + Icons.shape_line_rounded, + Icons.shape_line_sharp, + Icons.share, + Icons.share_arrival_time, + Icons.share_arrival_time_outlined, + Icons.share_arrival_time_rounded, + Icons.share_arrival_time_sharp, + Icons.share_location, + Icons.share_location_outlined, + Icons.share_location_rounded, + Icons.share_location_sharp, + Icons.share_outlined, + Icons.share_rounded, + Icons.share_sharp, + Icons.shelves, + Icons.shield, + Icons.shield_moon, + Icons.shield_moon_outlined, + Icons.shield_moon_rounded, + Icons.shield_moon_sharp, + Icons.shield_outlined, + Icons.shield_rounded, + Icons.shield_sharp, + Icons.shop, + Icons.shop_2, + Icons.shop_2_outlined, + Icons.shop_2_rounded, + Icons.shop_2_sharp, + Icons.shop_outlined, + Icons.shop_rounded, + Icons.shop_sharp, + Icons.shop_two, + Icons.shop_two_outlined, + Icons.shop_two_rounded, + Icons.shop_two_sharp, + Icons.shopify, + Icons.shopify_outlined, + Icons.shopify_rounded, + Icons.shopify_sharp, + Icons.shopping_bag, + Icons.shopping_bag_outlined, + Icons.shopping_bag_rounded, + Icons.shopping_bag_sharp, + Icons.shopping_basket, + Icons.shopping_basket_outlined, + Icons.shopping_basket_rounded, + Icons.shopping_basket_sharp, + Icons.shopping_cart, + Icons.shopping_cart_checkout, + Icons.shopping_cart_checkout_outlined, + Icons.shopping_cart_checkout_rounded, + Icons.shopping_cart_checkout_sharp, + Icons.shopping_cart_outlined, + Icons.shopping_cart_rounded, + Icons.shopping_cart_sharp, + Icons.short_text, + Icons.short_text_outlined, + Icons.short_text_rounded, + Icons.short_text_sharp, + Icons.shortcut, + Icons.shortcut_outlined, + Icons.shortcut_rounded, + Icons.shortcut_sharp, + Icons.show_chart, + Icons.show_chart_outlined, + Icons.show_chart_rounded, + Icons.show_chart_sharp, + Icons.shower, + Icons.shower_outlined, + Icons.shower_rounded, + Icons.shower_sharp, + Icons.shuffle, + Icons.shuffle_on, + Icons.shuffle_on_outlined, + Icons.shuffle_on_rounded, + Icons.shuffle_on_sharp, + Icons.shuffle_outlined, + Icons.shuffle_rounded, + Icons.shuffle_sharp, + Icons.shutter_speed, + Icons.shutter_speed_outlined, + Icons.shutter_speed_rounded, + Icons.shutter_speed_sharp, + Icons.sick, + Icons.sick_outlined, + Icons.sick_rounded, + Icons.sick_sharp, + Icons.sign_language, + Icons.sign_language_outlined, + Icons.sign_language_rounded, + Icons.sign_language_sharp, + Icons.signal_cellular_0_bar, + Icons.signal_cellular_0_bar_outlined, + Icons.signal_cellular_0_bar_rounded, + Icons.signal_cellular_0_bar_sharp, + Icons.signal_cellular_4_bar, + Icons.signal_cellular_4_bar_outlined, + Icons.signal_cellular_4_bar_rounded, + Icons.signal_cellular_4_bar_sharp, + Icons.signal_cellular_alt, + Icons.signal_cellular_alt_1_bar, + Icons.signal_cellular_alt_1_bar_outlined, + Icons.signal_cellular_alt_1_bar_rounded, + Icons.signal_cellular_alt_1_bar_sharp, + Icons.signal_cellular_alt_2_bar, + Icons.signal_cellular_alt_2_bar_outlined, + Icons.signal_cellular_alt_2_bar_rounded, + Icons.signal_cellular_alt_2_bar_sharp, + Icons.signal_cellular_alt_outlined, + Icons.signal_cellular_alt_rounded, + Icons.signal_cellular_alt_sharp, + Icons.signal_cellular_connected_no_internet_0_bar, + Icons.signal_cellular_connected_no_internet_0_bar_outlined, + Icons.signal_cellular_connected_no_internet_0_bar_rounded, + Icons.signal_cellular_connected_no_internet_0_bar_sharp, + Icons.signal_cellular_connected_no_internet_4_bar, + Icons.signal_cellular_connected_no_internet_4_bar_outlined, + Icons.signal_cellular_connected_no_internet_4_bar_rounded, + Icons.signal_cellular_connected_no_internet_4_bar_sharp, + Icons.signal_cellular_no_sim, + Icons.signal_cellular_no_sim_outlined, + Icons.signal_cellular_no_sim_rounded, + Icons.signal_cellular_no_sim_sharp, + Icons.signal_cellular_nodata, + Icons.signal_cellular_nodata_outlined, + Icons.signal_cellular_nodata_rounded, + Icons.signal_cellular_nodata_sharp, + Icons.signal_cellular_null, + Icons.signal_cellular_null_outlined, + Icons.signal_cellular_null_rounded, + Icons.signal_cellular_null_sharp, + Icons.signal_cellular_off, + Icons.signal_cellular_off_outlined, + Icons.signal_cellular_off_rounded, + Icons.signal_cellular_off_sharp, + Icons.signal_wifi_0_bar, + Icons.signal_wifi_0_bar_outlined, + Icons.signal_wifi_0_bar_rounded, + Icons.signal_wifi_0_bar_sharp, + Icons.signal_wifi_4_bar, + Icons.signal_wifi_4_bar_lock, + Icons.signal_wifi_4_bar_lock_outlined, + Icons.signal_wifi_4_bar_lock_rounded, + Icons.signal_wifi_4_bar_lock_sharp, + Icons.signal_wifi_4_bar_outlined, + Icons.signal_wifi_4_bar_rounded, + Icons.signal_wifi_4_bar_sharp, + Icons.signal_wifi_bad, + Icons.signal_wifi_bad_outlined, + Icons.signal_wifi_bad_rounded, + Icons.signal_wifi_bad_sharp, + Icons.signal_wifi_connected_no_internet_4, + Icons.signal_wifi_connected_no_internet_4_outlined, + Icons.signal_wifi_connected_no_internet_4_rounded, + Icons.signal_wifi_connected_no_internet_4_sharp, + Icons.signal_wifi_off, + Icons.signal_wifi_off_outlined, + Icons.signal_wifi_off_rounded, + Icons.signal_wifi_off_sharp, + Icons.signal_wifi_statusbar_4_bar, + Icons.signal_wifi_statusbar_4_bar_outlined, + Icons.signal_wifi_statusbar_4_bar_rounded, + Icons.signal_wifi_statusbar_4_bar_sharp, + Icons.signal_wifi_statusbar_connected_no_internet_4, + Icons.signal_wifi_statusbar_connected_no_internet_4_outlined, + Icons.signal_wifi_statusbar_connected_no_internet_4_rounded, + Icons.signal_wifi_statusbar_connected_no_internet_4_sharp, + Icons.signal_wifi_statusbar_null, + Icons.signal_wifi_statusbar_null_outlined, + Icons.signal_wifi_statusbar_null_rounded, + Icons.signal_wifi_statusbar_null_sharp, + Icons.signpost, + Icons.signpost_outlined, + Icons.signpost_rounded, + Icons.signpost_sharp, + Icons.sim_card, + Icons.sim_card_alert, + Icons.sim_card_alert_outlined, + Icons.sim_card_alert_rounded, + Icons.sim_card_alert_sharp, + Icons.sim_card_download, + Icons.sim_card_download_outlined, + Icons.sim_card_download_rounded, + Icons.sim_card_download_sharp, + Icons.sim_card_outlined, + Icons.sim_card_rounded, + Icons.sim_card_sharp, + Icons.single_bed, + Icons.single_bed_outlined, + Icons.single_bed_rounded, + Icons.single_bed_sharp, + Icons.sip, + Icons.sip_outlined, + Icons.sip_rounded, + Icons.sip_sharp, + Icons.six_ft_apart, + Icons.six_ft_apart_outlined, + Icons.six_ft_apart_rounded, + Icons.six_ft_apart_sharp, + Icons.six_k, + Icons.six_k_outlined, + Icons.six_k_plus, + Icons.six_k_plus_outlined, + Icons.six_k_plus_rounded, + Icons.six_k_plus_sharp, + Icons.six_k_rounded, + Icons.six_k_sharp, + Icons.six_mp, + Icons.six_mp_outlined, + Icons.six_mp_rounded, + Icons.six_mp_sharp, + Icons.sixteen_mp, + Icons.sixteen_mp_outlined, + Icons.sixteen_mp_rounded, + Icons.sixteen_mp_sharp, + Icons.sixty_fps, + Icons.sixty_fps_outlined, + Icons.sixty_fps_rounded, + Icons.sixty_fps_select, + Icons.sixty_fps_select_outlined, + Icons.sixty_fps_select_rounded, + Icons.sixty_fps_select_sharp, + Icons.sixty_fps_sharp, + Icons.skateboarding, + Icons.skateboarding_outlined, + Icons.skateboarding_rounded, + Icons.skateboarding_sharp, + Icons.skip_next, + Icons.skip_next_outlined, + Icons.skip_next_rounded, + Icons.skip_next_sharp, + Icons.skip_previous, + Icons.skip_previous_outlined, + Icons.skip_previous_rounded, + Icons.skip_previous_sharp, + Icons.sledding, + Icons.sledding_outlined, + Icons.sledding_rounded, + Icons.sledding_sharp, + Icons.slideshow, + Icons.slideshow_outlined, + Icons.slideshow_rounded, + Icons.slideshow_sharp, + Icons.slow_motion_video, + Icons.slow_motion_video_outlined, + Icons.slow_motion_video_rounded, + Icons.slow_motion_video_sharp, + Icons.smart_button, + Icons.smart_button_outlined, + Icons.smart_button_rounded, + Icons.smart_button_sharp, + Icons.smart_display, + Icons.smart_display_outlined, + Icons.smart_display_rounded, + Icons.smart_display_sharp, + Icons.smart_screen, + Icons.smart_screen_outlined, + Icons.smart_screen_rounded, + Icons.smart_screen_sharp, + Icons.smart_toy, + Icons.smart_toy_outlined, + Icons.smart_toy_rounded, + Icons.smart_toy_sharp, + Icons.smartphone, + Icons.smartphone_outlined, + Icons.smartphone_rounded, + Icons.smartphone_sharp, + Icons.smoke_free, + Icons.smoke_free_outlined, + Icons.smoke_free_rounded, + Icons.smoke_free_sharp, + Icons.smoking_rooms, + Icons.smoking_rooms_outlined, + Icons.smoking_rooms_rounded, + Icons.smoking_rooms_sharp, + Icons.sms, + Icons.sms_failed, + Icons.sms_failed_outlined, + Icons.sms_failed_rounded, + Icons.sms_failed_sharp, + Icons.sms_outlined, + Icons.sms_rounded, + Icons.sms_sharp, + Icons.snapchat, + Icons.snapchat_outlined, + Icons.snapchat_rounded, + Icons.snapchat_sharp, + Icons.snippet_folder, + Icons.snippet_folder_outlined, + Icons.snippet_folder_rounded, + Icons.snippet_folder_sharp, + Icons.snooze, + Icons.snooze_outlined, + Icons.snooze_rounded, + Icons.snooze_sharp, + Icons.snowboarding, + Icons.snowboarding_outlined, + Icons.snowboarding_rounded, + Icons.snowboarding_sharp, + Icons.snowing, + Icons.snowmobile, + Icons.snowmobile_outlined, + Icons.snowmobile_rounded, + Icons.snowmobile_sharp, + Icons.snowshoeing, + Icons.snowshoeing_outlined, + Icons.snowshoeing_rounded, + Icons.snowshoeing_sharp, + Icons.soap, + Icons.soap_outlined, + Icons.soap_rounded, + Icons.soap_sharp, + Icons.social_distance, + Icons.social_distance_outlined, + Icons.social_distance_rounded, + Icons.social_distance_sharp, + Icons.solar_power, + Icons.solar_power_outlined, + Icons.solar_power_rounded, + Icons.solar_power_sharp, + Icons.sort, + Icons.sort_by_alpha, + Icons.sort_by_alpha_outlined, + Icons.sort_by_alpha_rounded, + Icons.sort_by_alpha_sharp, + Icons.sort_outlined, + Icons.sort_rounded, + Icons.sort_sharp, + Icons.sos, + Icons.sos_outlined, + Icons.sos_rounded, + Icons.sos_sharp, + Icons.soup_kitchen, + Icons.soup_kitchen_outlined, + Icons.soup_kitchen_rounded, + Icons.soup_kitchen_sharp, + Icons.source, + Icons.source_outlined, + Icons.source_rounded, + Icons.source_sharp, + Icons.south, + Icons.south_america, + Icons.south_america_outlined, + Icons.south_america_rounded, + Icons.south_america_sharp, + Icons.south_east, + Icons.south_east_outlined, + Icons.south_east_rounded, + Icons.south_east_sharp, + Icons.south_outlined, + Icons.south_rounded, + Icons.south_sharp, + Icons.south_west, + Icons.south_west_outlined, + Icons.south_west_rounded, + Icons.south_west_sharp, + Icons.spa, + Icons.spa_outlined, + Icons.spa_rounded, + Icons.spa_sharp, + Icons.space_bar, + Icons.space_bar_outlined, + Icons.space_bar_rounded, + Icons.space_bar_sharp, + Icons.space_dashboard, + Icons.space_dashboard_outlined, + Icons.space_dashboard_rounded, + Icons.space_dashboard_sharp, + Icons.spatial_audio, + Icons.spatial_audio_off, + Icons.spatial_audio_off_outlined, + Icons.spatial_audio_off_rounded, + Icons.spatial_audio_off_sharp, + Icons.spatial_audio_outlined, + Icons.spatial_audio_rounded, + Icons.spatial_audio_sharp, + Icons.spatial_tracking, + Icons.spatial_tracking_outlined, + Icons.spatial_tracking_rounded, + Icons.spatial_tracking_sharp, + Icons.speaker, + Icons.speaker_group, + Icons.speaker_group_outlined, + Icons.speaker_group_rounded, + Icons.speaker_group_sharp, + Icons.speaker_notes, + Icons.speaker_notes_off, + Icons.speaker_notes_off_outlined, + Icons.speaker_notes_off_rounded, + Icons.speaker_notes_off_sharp, + Icons.speaker_notes_outlined, + Icons.speaker_notes_rounded, + Icons.speaker_notes_sharp, + Icons.speaker_outlined, + Icons.speaker_phone, + Icons.speaker_phone_outlined, + Icons.speaker_phone_rounded, + Icons.speaker_phone_sharp, + Icons.speaker_rounded, + Icons.speaker_sharp, + Icons.speed, + Icons.speed_outlined, + Icons.speed_rounded, + Icons.speed_sharp, + Icons.spellcheck, + Icons.spellcheck_outlined, + Icons.spellcheck_rounded, + Icons.spellcheck_sharp, + Icons.splitscreen, + Icons.splitscreen_outlined, + Icons.splitscreen_rounded, + Icons.splitscreen_sharp, + Icons.spoke, + Icons.spoke_outlined, + Icons.spoke_rounded, + Icons.spoke_sharp, + Icons.sports, + Icons.sports_bar, + Icons.sports_bar_outlined, + Icons.sports_bar_rounded, + Icons.sports_bar_sharp, + Icons.sports_baseball, + Icons.sports_baseball_outlined, + Icons.sports_baseball_rounded, + Icons.sports_baseball_sharp, + Icons.sports_basketball, + Icons.sports_basketball_outlined, + Icons.sports_basketball_rounded, + Icons.sports_basketball_sharp, + Icons.sports_cricket, + Icons.sports_cricket_outlined, + Icons.sports_cricket_rounded, + Icons.sports_cricket_sharp, + Icons.sports_esports, + Icons.sports_esports_outlined, + Icons.sports_esports_rounded, + Icons.sports_esports_sharp, + Icons.sports_football, + Icons.sports_football_outlined, + Icons.sports_football_rounded, + Icons.sports_football_sharp, + Icons.sports_golf, + Icons.sports_golf_outlined, + Icons.sports_golf_rounded, + Icons.sports_golf_sharp, + Icons.sports_gymnastics, + Icons.sports_gymnastics_outlined, + Icons.sports_gymnastics_rounded, + Icons.sports_gymnastics_sharp, + Icons.sports_handball, + Icons.sports_handball_outlined, + Icons.sports_handball_rounded, + Icons.sports_handball_sharp, + Icons.sports_hockey, + Icons.sports_hockey_outlined, + Icons.sports_hockey_rounded, + Icons.sports_hockey_sharp, + Icons.sports_kabaddi, + Icons.sports_kabaddi_outlined, + Icons.sports_kabaddi_rounded, + Icons.sports_kabaddi_sharp, + Icons.sports_martial_arts, + Icons.sports_martial_arts_outlined, + Icons.sports_martial_arts_rounded, + Icons.sports_martial_arts_sharp, + Icons.sports_mma, + Icons.sports_mma_outlined, + Icons.sports_mma_rounded, + Icons.sports_mma_sharp, + Icons.sports_motorsports, + Icons.sports_motorsports_outlined, + Icons.sports_motorsports_rounded, + Icons.sports_motorsports_sharp, + Icons.sports_outlined, + Icons.sports_rounded, + Icons.sports_rugby, + Icons.sports_rugby_outlined, + Icons.sports_rugby_rounded, + Icons.sports_rugby_sharp, + Icons.sports_score, + Icons.sports_score_outlined, + Icons.sports_score_rounded, + Icons.sports_score_sharp, + Icons.sports_sharp, + Icons.sports_soccer, + Icons.sports_soccer_outlined, + Icons.sports_soccer_rounded, + Icons.sports_soccer_sharp, + Icons.sports_tennis, + Icons.sports_tennis_outlined, + Icons.sports_tennis_rounded, + Icons.sports_tennis_sharp, + Icons.sports_volleyball, + Icons.sports_volleyball_outlined, + Icons.sports_volleyball_rounded, + Icons.sports_volleyball_sharp, + Icons.square, + Icons.square_foot, + Icons.square_foot_outlined, + Icons.square_foot_rounded, + Icons.square_foot_sharp, + Icons.square_outlined, + Icons.square_rounded, + Icons.square_sharp, + Icons.ssid_chart, + Icons.ssid_chart_outlined, + Icons.ssid_chart_rounded, + Icons.ssid_chart_sharp, + Icons.stacked_bar_chart, + Icons.stacked_bar_chart_outlined, + Icons.stacked_bar_chart_rounded, + Icons.stacked_bar_chart_sharp, + Icons.stacked_line_chart, + Icons.stacked_line_chart_outlined, + Icons.stacked_line_chart_rounded, + Icons.stacked_line_chart_sharp, + Icons.stadium, + Icons.stadium_outlined, + Icons.stadium_rounded, + Icons.stadium_sharp, + Icons.stairs, + Icons.stairs_outlined, + Icons.stairs_rounded, + Icons.stairs_sharp, + Icons.star, + Icons.star_border, + Icons.star_border_outlined, + Icons.star_border_purple500, + Icons.star_border_purple500_outlined, + Icons.star_border_purple500_rounded, + Icons.star_border_purple500_sharp, + Icons.star_border_rounded, + Icons.star_border_sharp, + Icons.star_half, + Icons.star_half_outlined, + Icons.star_half_rounded, + Icons.star_half_sharp, + Icons.star_outline, + Icons.star_outline_outlined, + Icons.star_outline_rounded, + Icons.star_outline_sharp, + Icons.star_outlined, + Icons.star_purple500, + Icons.star_purple500_outlined, + Icons.star_purple500_rounded, + Icons.star_purple500_sharp, + Icons.star_rate, + Icons.star_rate_outlined, + Icons.star_rate_rounded, + Icons.star_rate_sharp, + Icons.star_rounded, + Icons.star_sharp, + Icons.stars, + Icons.stars_outlined, + Icons.stars_rounded, + Icons.stars_sharp, + Icons.start, + Icons.start_outlined, + Icons.start_rounded, + Icons.start_sharp, + Icons.stay_current_landscape, + Icons.stay_current_landscape_outlined, + Icons.stay_current_landscape_rounded, + Icons.stay_current_landscape_sharp, + Icons.stay_current_portrait, + Icons.stay_current_portrait_outlined, + Icons.stay_current_portrait_rounded, + Icons.stay_current_portrait_sharp, + Icons.stay_primary_landscape, + Icons.stay_primary_landscape_outlined, + Icons.stay_primary_landscape_rounded, + Icons.stay_primary_landscape_sharp, + Icons.stay_primary_portrait, + Icons.stay_primary_portrait_outlined, + Icons.stay_primary_portrait_rounded, + Icons.stay_primary_portrait_sharp, + Icons.sticky_note_2, + Icons.sticky_note_2_outlined, + Icons.sticky_note_2_rounded, + Icons.sticky_note_2_sharp, + Icons.stop, + Icons.stop_circle, + Icons.stop_circle_outlined, + Icons.stop_circle_rounded, + Icons.stop_circle_sharp, + Icons.stop_outlined, + Icons.stop_rounded, + Icons.stop_screen_share, + Icons.stop_screen_share_outlined, + Icons.stop_screen_share_rounded, + Icons.stop_screen_share_sharp, + Icons.stop_sharp, + Icons.storage, + Icons.storage_outlined, + Icons.storage_rounded, + Icons.storage_sharp, + Icons.store, + Icons.store_mall_directory, + Icons.store_mall_directory_outlined, + Icons.store_mall_directory_rounded, + Icons.store_mall_directory_sharp, + Icons.store_outlined, + Icons.store_rounded, + Icons.store_sharp, + Icons.storefront, + Icons.storefront_outlined, + Icons.storefront_rounded, + Icons.storefront_sharp, + Icons.storm, + Icons.storm_outlined, + Icons.storm_rounded, + Icons.storm_sharp, + Icons.straight, + Icons.straight_outlined, + Icons.straight_rounded, + Icons.straight_sharp, + Icons.straighten, + Icons.straighten_outlined, + Icons.straighten_rounded, + Icons.straighten_sharp, + Icons.stream, + Icons.stream_outlined, + Icons.stream_rounded, + Icons.stream_sharp, + Icons.streetview, + Icons.streetview_outlined, + Icons.streetview_rounded, + Icons.streetview_sharp, + Icons.strikethrough_s, + Icons.strikethrough_s_outlined, + Icons.strikethrough_s_rounded, + Icons.strikethrough_s_sharp, + Icons.stroller, + Icons.stroller_outlined, + Icons.stroller_rounded, + Icons.stroller_sharp, + Icons.style, + Icons.style_outlined, + Icons.style_rounded, + Icons.style_sharp, + Icons.subdirectory_arrow_left, + Icons.subdirectory_arrow_left_outlined, + Icons.subdirectory_arrow_left_rounded, + Icons.subdirectory_arrow_left_sharp, + Icons.subdirectory_arrow_right, + Icons.subdirectory_arrow_right_outlined, + Icons.subdirectory_arrow_right_rounded, + Icons.subdirectory_arrow_right_sharp, + Icons.subject, + Icons.subject_outlined, + Icons.subject_rounded, + Icons.subject_sharp, + Icons.subscript, + Icons.subscript_outlined, + Icons.subscript_rounded, + Icons.subscript_sharp, + Icons.subscriptions, + Icons.subscriptions_outlined, + Icons.subscriptions_rounded, + Icons.subscriptions_sharp, + Icons.subtitles, + Icons.subtitles_off, + Icons.subtitles_off_outlined, + Icons.subtitles_off_rounded, + Icons.subtitles_off_sharp, + Icons.subtitles_outlined, + Icons.subtitles_rounded, + Icons.subtitles_sharp, + Icons.subway, + Icons.subway_outlined, + Icons.subway_rounded, + Icons.subway_sharp, + Icons.summarize, + Icons.summarize_outlined, + Icons.summarize_rounded, + Icons.summarize_sharp, + Icons.sunny, + Icons.sunny_snowing, + Icons.superscript, + Icons.superscript_outlined, + Icons.superscript_rounded, + Icons.superscript_sharp, + Icons.supervised_user_circle, + Icons.supervised_user_circle_outlined, + Icons.supervised_user_circle_rounded, + Icons.supervised_user_circle_sharp, + Icons.supervisor_account, + Icons.supervisor_account_outlined, + Icons.supervisor_account_rounded, + Icons.supervisor_account_sharp, + Icons.support, + Icons.support_agent, + Icons.support_agent_outlined, + Icons.support_agent_rounded, + Icons.support_agent_sharp, + Icons.support_outlined, + Icons.support_rounded, + Icons.support_sharp, + Icons.surfing, + Icons.surfing_outlined, + Icons.surfing_rounded, + Icons.surfing_sharp, + Icons.surround_sound, + Icons.surround_sound_outlined, + Icons.surround_sound_rounded, + Icons.surround_sound_sharp, + Icons.swap_calls, + Icons.swap_calls_outlined, + Icons.swap_calls_rounded, + Icons.swap_calls_sharp, + Icons.swap_horiz, + Icons.swap_horiz_outlined, + Icons.swap_horiz_rounded, + Icons.swap_horiz_sharp, + Icons.swap_horizontal_circle, + Icons.swap_horizontal_circle_outlined, + Icons.swap_horizontal_circle_rounded, + Icons.swap_horizontal_circle_sharp, + Icons.swap_vert, + Icons.swap_vert_circle, + Icons.swap_vert_circle_outlined, + Icons.swap_vert_circle_rounded, + Icons.swap_vert_circle_sharp, + Icons.swap_vert_outlined, + Icons.swap_vert_rounded, + Icons.swap_vert_sharp, + Icons.swap_vertical_circle, + Icons.swap_vertical_circle_outlined, + Icons.swap_vertical_circle_rounded, + Icons.swap_vertical_circle_sharp, + Icons.swipe, + Icons.swipe_down, + Icons.swipe_down_alt, + Icons.swipe_down_alt_outlined, + Icons.swipe_down_alt_rounded, + Icons.swipe_down_alt_sharp, + Icons.swipe_down_outlined, + Icons.swipe_down_rounded, + Icons.swipe_down_sharp, + Icons.swipe_left, + Icons.swipe_left_alt, + Icons.swipe_left_alt_outlined, + Icons.swipe_left_alt_rounded, + Icons.swipe_left_alt_sharp, + Icons.swipe_left_outlined, + Icons.swipe_left_rounded, + Icons.swipe_left_sharp, + Icons.swipe_outlined, + Icons.swipe_right, + Icons.swipe_right_alt, + Icons.swipe_right_alt_outlined, + Icons.swipe_right_alt_rounded, + Icons.swipe_right_alt_sharp, + Icons.swipe_right_outlined, + Icons.swipe_right_rounded, + Icons.swipe_right_sharp, + Icons.swipe_rounded, + Icons.swipe_sharp, + Icons.swipe_up, + Icons.swipe_up_alt, + Icons.swipe_up_alt_outlined, + Icons.swipe_up_alt_rounded, + Icons.swipe_up_alt_sharp, + Icons.swipe_up_outlined, + Icons.swipe_up_rounded, + Icons.swipe_up_sharp, + Icons.swipe_vertical, + Icons.swipe_vertical_outlined, + Icons.swipe_vertical_rounded, + Icons.swipe_vertical_sharp, + Icons.switch_access_shortcut, + Icons.switch_access_shortcut_add, + Icons.switch_access_shortcut_add_outlined, + Icons.switch_access_shortcut_add_rounded, + Icons.switch_access_shortcut_add_sharp, + Icons.switch_access_shortcut_outlined, + Icons.switch_access_shortcut_rounded, + Icons.switch_access_shortcut_sharp, + Icons.switch_account, + Icons.switch_account_outlined, + Icons.switch_account_rounded, + Icons.switch_account_sharp, + Icons.switch_camera, + Icons.switch_camera_outlined, + Icons.switch_camera_rounded, + Icons.switch_camera_sharp, + Icons.switch_left, + Icons.switch_left_outlined, + Icons.switch_left_rounded, + Icons.switch_left_sharp, + Icons.switch_right, + Icons.switch_right_outlined, + Icons.switch_right_rounded, + Icons.switch_right_sharp, + Icons.switch_video, + Icons.switch_video_outlined, + Icons.switch_video_rounded, + Icons.switch_video_sharp, + Icons.synagogue, + Icons.synagogue_outlined, + Icons.synagogue_rounded, + Icons.synagogue_sharp, + Icons.sync, + Icons.sync_alt, + Icons.sync_alt_outlined, + Icons.sync_alt_rounded, + Icons.sync_alt_sharp, + Icons.sync_disabled, + Icons.sync_disabled_outlined, + Icons.sync_disabled_rounded, + Icons.sync_disabled_sharp, + Icons.sync_lock, + Icons.sync_lock_outlined, + Icons.sync_lock_rounded, + Icons.sync_lock_sharp, + Icons.sync_outlined, + Icons.sync_problem, + Icons.sync_problem_outlined, + Icons.sync_problem_rounded, + Icons.sync_problem_sharp, + Icons.sync_rounded, + Icons.sync_sharp, + Icons.system_security_update, + Icons.system_security_update_good, + Icons.system_security_update_good_outlined, + Icons.system_security_update_good_rounded, + Icons.system_security_update_good_sharp, + Icons.system_security_update_outlined, + Icons.system_security_update_rounded, + Icons.system_security_update_sharp, + Icons.system_security_update_warning, + Icons.system_security_update_warning_outlined, + Icons.system_security_update_warning_rounded, + Icons.system_security_update_warning_sharp, + Icons.system_update, + Icons.system_update_alt, + Icons.system_update_alt_outlined, + Icons.system_update_alt_rounded, + Icons.system_update_alt_sharp, + Icons.system_update_outlined, + Icons.system_update_rounded, + Icons.system_update_sharp, + Icons.system_update_tv, + Icons.system_update_tv_outlined, + Icons.system_update_tv_rounded, + Icons.system_update_tv_sharp, + Icons.tab, + Icons.tab_outlined, + Icons.tab_rounded, + Icons.tab_sharp, + Icons.tab_unselected, + Icons.tab_unselected_outlined, + Icons.tab_unselected_rounded, + Icons.tab_unselected_sharp, + Icons.table_bar, + Icons.table_bar_outlined, + Icons.table_bar_rounded, + Icons.table_bar_sharp, + Icons.table_chart, + Icons.table_chart_outlined, + Icons.table_chart_rounded, + Icons.table_chart_sharp, + Icons.table_restaurant, + Icons.table_restaurant_outlined, + Icons.table_restaurant_rounded, + Icons.table_restaurant_sharp, + Icons.table_rows, + Icons.table_rows_outlined, + Icons.table_rows_rounded, + Icons.table_rows_sharp, + Icons.table_view, + Icons.table_view_outlined, + Icons.table_view_rounded, + Icons.table_view_sharp, + Icons.tablet, + Icons.tablet_android, + Icons.tablet_android_outlined, + Icons.tablet_android_rounded, + Icons.tablet_android_sharp, + Icons.tablet_mac, + Icons.tablet_mac_outlined, + Icons.tablet_mac_rounded, + Icons.tablet_mac_sharp, + Icons.tablet_outlined, + Icons.tablet_rounded, + Icons.tablet_sharp, + Icons.tag, + Icons.tag_faces, + Icons.tag_faces_outlined, + Icons.tag_faces_rounded, + Icons.tag_faces_sharp, + Icons.tag_outlined, + Icons.tag_rounded, + Icons.tag_sharp, + Icons.takeout_dining, + Icons.takeout_dining_outlined, + Icons.takeout_dining_rounded, + Icons.takeout_dining_sharp, + Icons.tap_and_play, + Icons.tap_and_play_outlined, + Icons.tap_and_play_rounded, + Icons.tap_and_play_sharp, + Icons.tapas, + Icons.tapas_outlined, + Icons.tapas_rounded, + Icons.tapas_sharp, + Icons.task, + Icons.task_alt, + Icons.task_alt_outlined, + Icons.task_alt_rounded, + Icons.task_alt_sharp, + Icons.task_outlined, + Icons.task_rounded, + Icons.task_sharp, + Icons.taxi_alert, + Icons.taxi_alert_outlined, + Icons.taxi_alert_rounded, + Icons.taxi_alert_sharp, + Icons.telegram, + Icons.telegram_outlined, + Icons.telegram_rounded, + Icons.telegram_sharp, + Icons.temple_buddhist, + Icons.temple_buddhist_outlined, + Icons.temple_buddhist_rounded, + Icons.temple_buddhist_sharp, + Icons.temple_hindu, + Icons.temple_hindu_outlined, + Icons.temple_hindu_rounded, + Icons.temple_hindu_sharp, + Icons.ten_k, + Icons.ten_k_outlined, + Icons.ten_k_rounded, + Icons.ten_k_sharp, + Icons.ten_mp, + Icons.ten_mp_outlined, + Icons.ten_mp_rounded, + Icons.ten_mp_sharp, + Icons.terminal, + Icons.terminal_outlined, + Icons.terminal_rounded, + Icons.terminal_sharp, + Icons.terrain, + Icons.terrain_outlined, + Icons.terrain_rounded, + Icons.terrain_sharp, + Icons.text_decrease, + Icons.text_decrease_outlined, + Icons.text_decrease_rounded, + Icons.text_decrease_sharp, + Icons.text_fields, + Icons.text_fields_outlined, + Icons.text_fields_rounded, + Icons.text_fields_sharp, + Icons.text_format, + Icons.text_format_outlined, + Icons.text_format_rounded, + Icons.text_format_sharp, + Icons.text_increase, + Icons.text_increase_outlined, + Icons.text_increase_rounded, + Icons.text_increase_sharp, + Icons.text_rotate_up, + Icons.text_rotate_up_outlined, + Icons.text_rotate_up_rounded, + Icons.text_rotate_up_sharp, + Icons.text_rotate_vertical, + Icons.text_rotate_vertical_outlined, + Icons.text_rotate_vertical_rounded, + Icons.text_rotate_vertical_sharp, + Icons.text_rotation_angledown, + Icons.text_rotation_angledown_outlined, + Icons.text_rotation_angledown_rounded, + Icons.text_rotation_angledown_sharp, + Icons.text_rotation_angleup, + Icons.text_rotation_angleup_outlined, + Icons.text_rotation_angleup_rounded, + Icons.text_rotation_angleup_sharp, + Icons.text_rotation_down, + Icons.text_rotation_down_outlined, + Icons.text_rotation_down_rounded, + Icons.text_rotation_down_sharp, + Icons.text_rotation_none, + Icons.text_rotation_none_outlined, + Icons.text_rotation_none_rounded, + Icons.text_rotation_none_sharp, + Icons.text_snippet, + Icons.text_snippet_outlined, + Icons.text_snippet_rounded, + Icons.text_snippet_sharp, + Icons.textsms, + Icons.textsms_outlined, + Icons.textsms_rounded, + Icons.textsms_sharp, + Icons.texture, + Icons.texture_outlined, + Icons.texture_rounded, + Icons.texture_sharp, + Icons.theater_comedy, + Icons.theater_comedy_outlined, + Icons.theater_comedy_rounded, + Icons.theater_comedy_sharp, + Icons.theaters, + Icons.theaters_outlined, + Icons.theaters_rounded, + Icons.theaters_sharp, + Icons.thermostat, + Icons.thermostat_auto, + Icons.thermostat_auto_outlined, + Icons.thermostat_auto_rounded, + Icons.thermostat_auto_sharp, + Icons.thermostat_outlined, + Icons.thermostat_rounded, + Icons.thermostat_sharp, + Icons.thirteen_mp, + Icons.thirteen_mp_outlined, + Icons.thirteen_mp_rounded, + Icons.thirteen_mp_sharp, + Icons.thirty_fps, + Icons.thirty_fps_outlined, + Icons.thirty_fps_rounded, + Icons.thirty_fps_select, + Icons.thirty_fps_select_outlined, + Icons.thirty_fps_select_rounded, + Icons.thirty_fps_select_sharp, + Icons.thirty_fps_sharp, + Icons.three_g_mobiledata, + Icons.three_g_mobiledata_outlined, + Icons.three_g_mobiledata_rounded, + Icons.three_g_mobiledata_sharp, + Icons.three_k, + Icons.three_k_outlined, + Icons.three_k_plus, + Icons.three_k_plus_outlined, + Icons.three_k_plus_rounded, + Icons.three_k_plus_sharp, + Icons.three_k_rounded, + Icons.three_k_sharp, + Icons.three_mp, + Icons.three_mp_outlined, + Icons.three_mp_rounded, + Icons.three_mp_sharp, + Icons.three_p, + Icons.three_p_outlined, + Icons.three_p_rounded, + Icons.three_p_sharp, + Icons.threed_rotation, + Icons.threed_rotation_outlined, + Icons.threed_rotation_rounded, + Icons.threed_rotation_sharp, + Icons.threesixty, + Icons.threesixty_outlined, + Icons.threesixty_rounded, + Icons.threesixty_sharp, + Icons.thumb_down, + Icons.thumb_down_alt, + Icons.thumb_down_alt_outlined, + Icons.thumb_down_alt_rounded, + Icons.thumb_down_alt_sharp, + Icons.thumb_down_off_alt, + Icons.thumb_down_off_alt_outlined, + Icons.thumb_down_off_alt_rounded, + Icons.thumb_down_off_alt_sharp, + Icons.thumb_down_outlined, + Icons.thumb_down_rounded, + Icons.thumb_down_sharp, + Icons.thumb_up, + Icons.thumb_up_alt, + Icons.thumb_up_alt_outlined, + Icons.thumb_up_alt_rounded, + Icons.thumb_up_alt_sharp, + Icons.thumb_up_off_alt, + Icons.thumb_up_off_alt_outlined, + Icons.thumb_up_off_alt_rounded, + Icons.thumb_up_off_alt_sharp, + Icons.thumb_up_outlined, + Icons.thumb_up_rounded, + Icons.thumb_up_sharp, + Icons.thumbs_up_down, + Icons.thumbs_up_down_outlined, + Icons.thumbs_up_down_rounded, + Icons.thumbs_up_down_sharp, + Icons.thunderstorm, + Icons.thunderstorm_outlined, + Icons.thunderstorm_rounded, + Icons.thunderstorm_sharp, + Icons.tiktok, + Icons.tiktok_outlined, + Icons.tiktok_rounded, + Icons.tiktok_sharp, + Icons.time_to_leave, + Icons.time_to_leave_outlined, + Icons.time_to_leave_rounded, + Icons.time_to_leave_sharp, + Icons.timelapse, + Icons.timelapse_outlined, + Icons.timelapse_rounded, + Icons.timelapse_sharp, + Icons.timeline, + Icons.timeline_outlined, + Icons.timeline_rounded, + Icons.timeline_sharp, + Icons.timer, + Icons.timer_10, + Icons.timer_10_outlined, + Icons.timer_10_rounded, + Icons.timer_10_select, + Icons.timer_10_select_outlined, + Icons.timer_10_select_rounded, + Icons.timer_10_select_sharp, + Icons.timer_10_sharp, + Icons.timer_3, + Icons.timer_3_outlined, + Icons.timer_3_rounded, + Icons.timer_3_select, + Icons.timer_3_select_outlined, + Icons.timer_3_select_rounded, + Icons.timer_3_select_sharp, + Icons.timer_3_sharp, + Icons.timer_off, + Icons.timer_off_outlined, + Icons.timer_off_rounded, + Icons.timer_off_sharp, + Icons.timer_outlined, + Icons.timer_rounded, + Icons.timer_sharp, + Icons.tips_and_updates, + Icons.tips_and_updates_outlined, + Icons.tips_and_updates_rounded, + Icons.tips_and_updates_sharp, + Icons.tire_repair, + Icons.tire_repair_outlined, + Icons.tire_repair_rounded, + Icons.tire_repair_sharp, + Icons.title, + Icons.title_outlined, + Icons.title_rounded, + Icons.title_sharp, + Icons.toc, + Icons.toc_outlined, + Icons.toc_rounded, + Icons.toc_sharp, + Icons.today, + Icons.today_outlined, + Icons.today_rounded, + Icons.today_sharp, + Icons.toggle_off, + Icons.toggle_off_outlined, + Icons.toggle_off_rounded, + Icons.toggle_off_sharp, + Icons.toggle_on, + Icons.toggle_on_outlined, + Icons.toggle_on_rounded, + Icons.toggle_on_sharp, + Icons.token, + Icons.token_outlined, + Icons.token_rounded, + Icons.token_sharp, + Icons.toll, + Icons.toll_outlined, + Icons.toll_rounded, + Icons.toll_sharp, + Icons.tonality, + Icons.tonality_outlined, + Icons.tonality_rounded, + Icons.tonality_sharp, + Icons.topic, + Icons.topic_outlined, + Icons.topic_rounded, + Icons.topic_sharp, + Icons.tornado, + Icons.tornado_outlined, + Icons.tornado_rounded, + Icons.tornado_sharp, + Icons.touch_app, + Icons.touch_app_outlined, + Icons.touch_app_rounded, + Icons.touch_app_sharp, + Icons.tour, + Icons.tour_outlined, + Icons.tour_rounded, + Icons.tour_sharp, + Icons.toys, + Icons.toys_outlined, + Icons.toys_rounded, + Icons.toys_sharp, + Icons.track_changes, + Icons.track_changes_outlined, + Icons.track_changes_rounded, + Icons.track_changes_sharp, + Icons.traffic, + Icons.traffic_outlined, + Icons.traffic_rounded, + Icons.traffic_sharp, + Icons.train, + Icons.train_outlined, + Icons.train_rounded, + Icons.train_sharp, + Icons.tram, + Icons.tram_outlined, + Icons.tram_rounded, + Icons.tram_sharp, + Icons.transcribe, + Icons.transcribe_outlined, + Icons.transcribe_rounded, + Icons.transcribe_sharp, + Icons.transfer_within_a_station, + Icons.transfer_within_a_station_outlined, + Icons.transfer_within_a_station_rounded, + Icons.transfer_within_a_station_sharp, + Icons.transform, + Icons.transform_outlined, + Icons.transform_rounded, + Icons.transform_sharp, + Icons.transgender, + Icons.transgender_outlined, + Icons.transgender_rounded, + Icons.transgender_sharp, + Icons.transit_enterexit, + Icons.transit_enterexit_outlined, + Icons.transit_enterexit_rounded, + Icons.transit_enterexit_sharp, + Icons.translate, + Icons.translate_outlined, + Icons.translate_rounded, + Icons.translate_sharp, + Icons.travel_explore, + Icons.travel_explore_outlined, + Icons.travel_explore_rounded, + Icons.travel_explore_sharp, + Icons.trending_down, + Icons.trending_down_outlined, + Icons.trending_down_rounded, + Icons.trending_down_sharp, + Icons.trending_flat, + Icons.trending_flat_outlined, + Icons.trending_flat_rounded, + Icons.trending_flat_sharp, + Icons.trending_neutral, + Icons.trending_neutral_outlined, + Icons.trending_neutral_rounded, + Icons.trending_neutral_sharp, + Icons.trending_up, + Icons.trending_up_outlined, + Icons.trending_up_rounded, + Icons.trending_up_sharp, + Icons.trip_origin, + Icons.trip_origin_outlined, + Icons.trip_origin_rounded, + Icons.trip_origin_sharp, + Icons.trolley, + Icons.troubleshoot, + Icons.troubleshoot_outlined, + Icons.troubleshoot_rounded, + Icons.troubleshoot_sharp, + Icons.try_sms_star, + Icons.try_sms_star_outlined, + Icons.try_sms_star_rounded, + Icons.try_sms_star_sharp, + Icons.tsunami, + Icons.tsunami_outlined, + Icons.tsunami_rounded, + Icons.tsunami_sharp, + Icons.tty, + Icons.tty_outlined, + Icons.tty_rounded, + Icons.tty_sharp, + Icons.tune, + Icons.tune_outlined, + Icons.tune_rounded, + Icons.tune_sharp, + Icons.tungsten, + Icons.tungsten_outlined, + Icons.tungsten_rounded, + Icons.tungsten_sharp, + Icons.turn_left, + Icons.turn_left_outlined, + Icons.turn_left_rounded, + Icons.turn_left_sharp, + Icons.turn_right, + Icons.turn_right_outlined, + Icons.turn_right_rounded, + Icons.turn_right_sharp, + Icons.turn_sharp_left, + Icons.turn_sharp_left_outlined, + Icons.turn_sharp_left_rounded, + Icons.turn_sharp_left_sharp, + Icons.turn_sharp_right, + Icons.turn_sharp_right_outlined, + Icons.turn_sharp_right_rounded, + Icons.turn_sharp_right_sharp, + Icons.turn_slight_left, + Icons.turn_slight_left_outlined, + Icons.turn_slight_left_rounded, + Icons.turn_slight_left_sharp, + Icons.turn_slight_right, + Icons.turn_slight_right_outlined, + Icons.turn_slight_right_rounded, + Icons.turn_slight_right_sharp, + Icons.turned_in, + Icons.turned_in_not, + Icons.turned_in_not_outlined, + Icons.turned_in_not_rounded, + Icons.turned_in_not_sharp, + Icons.turned_in_outlined, + Icons.turned_in_rounded, + Icons.turned_in_sharp, + Icons.tv, + Icons.tv_off, + Icons.tv_off_outlined, + Icons.tv_off_rounded, + Icons.tv_off_sharp, + Icons.tv_outlined, + Icons.tv_rounded, + Icons.tv_sharp, + Icons.twelve_mp, + Icons.twelve_mp_outlined, + Icons.twelve_mp_rounded, + Icons.twelve_mp_sharp, + Icons.twenty_four_mp, + Icons.twenty_four_mp_outlined, + Icons.twenty_four_mp_rounded, + Icons.twenty_four_mp_sharp, + Icons.twenty_mp, + Icons.twenty_mp_outlined, + Icons.twenty_mp_rounded, + Icons.twenty_mp_sharp, + Icons.twenty_one_mp, + Icons.twenty_one_mp_outlined, + Icons.twenty_one_mp_rounded, + Icons.twenty_one_mp_sharp, + Icons.twenty_three_mp, + Icons.twenty_three_mp_outlined, + Icons.twenty_three_mp_rounded, + Icons.twenty_three_mp_sharp, + Icons.twenty_two_mp, + Icons.twenty_two_mp_outlined, + Icons.twenty_two_mp_rounded, + Icons.twenty_two_mp_sharp, + Icons.two_k, + Icons.two_k_outlined, + Icons.two_k_plus, + Icons.two_k_plus_outlined, + Icons.two_k_plus_rounded, + Icons.two_k_plus_sharp, + Icons.two_k_rounded, + Icons.two_k_sharp, + Icons.two_mp, + Icons.two_mp_outlined, + Icons.two_mp_rounded, + Icons.two_mp_sharp, + Icons.two_wheeler, + Icons.two_wheeler_outlined, + Icons.two_wheeler_rounded, + Icons.two_wheeler_sharp, + Icons.type_specimen, + Icons.type_specimen_outlined, + Icons.type_specimen_rounded, + Icons.type_specimen_sharp, + Icons.u_turn_left, + Icons.u_turn_left_outlined, + Icons.u_turn_left_rounded, + Icons.u_turn_left_sharp, + Icons.u_turn_right, + Icons.u_turn_right_outlined, + Icons.u_turn_right_rounded, + Icons.u_turn_right_sharp, + Icons.umbrella, + Icons.umbrella_outlined, + Icons.umbrella_rounded, + Icons.umbrella_sharp, + Icons.unarchive, + Icons.unarchive_outlined, + Icons.unarchive_rounded, + Icons.unarchive_sharp, + Icons.undo, + Icons.undo_outlined, + Icons.undo_rounded, + Icons.undo_sharp, + Icons.unfold_less, + Icons.unfold_less_double, + Icons.unfold_less_double_outlined, + Icons.unfold_less_double_rounded, + Icons.unfold_less_double_sharp, + Icons.unfold_less_outlined, + Icons.unfold_less_rounded, + Icons.unfold_less_sharp, + Icons.unfold_more, + Icons.unfold_more_double, + Icons.unfold_more_double_outlined, + Icons.unfold_more_double_rounded, + Icons.unfold_more_double_sharp, + Icons.unfold_more_outlined, + Icons.unfold_more_rounded, + Icons.unfold_more_sharp, + Icons.unpublished, + Icons.unpublished_outlined, + Icons.unpublished_rounded, + Icons.unpublished_sharp, + Icons.unsubscribe, + Icons.unsubscribe_outlined, + Icons.unsubscribe_rounded, + Icons.unsubscribe_sharp, + Icons.upcoming, + Icons.upcoming_outlined, + Icons.upcoming_rounded, + Icons.upcoming_sharp, + Icons.update, + Icons.update_disabled, + Icons.update_disabled_outlined, + Icons.update_disabled_rounded, + Icons.update_disabled_sharp, + Icons.update_outlined, + Icons.update_rounded, + Icons.update_sharp, + Icons.upgrade, + Icons.upgrade_outlined, + Icons.upgrade_rounded, + Icons.upgrade_sharp, + Icons.upload, + Icons.upload_file, + Icons.upload_file_outlined, + Icons.upload_file_rounded, + Icons.upload_file_sharp, + Icons.upload_outlined, + Icons.upload_rounded, + Icons.upload_sharp, + Icons.usb, + Icons.usb_off, + Icons.usb_off_outlined, + Icons.usb_off_rounded, + Icons.usb_off_sharp, + Icons.usb_outlined, + Icons.usb_rounded, + Icons.usb_sharp, + Icons.vaccines, + Icons.vaccines_outlined, + Icons.vaccines_rounded, + Icons.vaccines_sharp, + Icons.vape_free, + Icons.vape_free_outlined, + Icons.vape_free_rounded, + Icons.vape_free_sharp, + Icons.vaping_rooms, + Icons.vaping_rooms_outlined, + Icons.vaping_rooms_rounded, + Icons.vaping_rooms_sharp, + Icons.verified, + Icons.verified_outlined, + Icons.verified_rounded, + Icons.verified_sharp, + Icons.verified_user, + Icons.verified_user_outlined, + Icons.verified_user_rounded, + Icons.verified_user_sharp, + Icons.vertical_align_bottom, + Icons.vertical_align_bottom_outlined, + Icons.vertical_align_bottom_rounded, + Icons.vertical_align_bottom_sharp, + Icons.vertical_align_center, + Icons.vertical_align_center_outlined, + Icons.vertical_align_center_rounded, + Icons.vertical_align_center_sharp, + Icons.vertical_align_top, + Icons.vertical_align_top_outlined, + Icons.vertical_align_top_rounded, + Icons.vertical_align_top_sharp, + Icons.vertical_distribute, + Icons.vertical_distribute_outlined, + Icons.vertical_distribute_rounded, + Icons.vertical_distribute_sharp, + Icons.vertical_shades, + Icons.vertical_shades_closed, + Icons.vertical_shades_closed_outlined, + Icons.vertical_shades_closed_rounded, + Icons.vertical_shades_closed_sharp, + Icons.vertical_shades_outlined, + Icons.vertical_shades_rounded, + Icons.vertical_shades_sharp, + Icons.vertical_split, + Icons.vertical_split_outlined, + Icons.vertical_split_rounded, + Icons.vertical_split_sharp, + Icons.vibration, + Icons.vibration_outlined, + Icons.vibration_rounded, + Icons.vibration_sharp, + Icons.video_call, + Icons.video_call_outlined, + Icons.video_call_rounded, + Icons.video_call_sharp, + Icons.video_camera_back, + Icons.video_camera_back_outlined, + Icons.video_camera_back_rounded, + Icons.video_camera_back_sharp, + Icons.video_camera_front, + Icons.video_camera_front_outlined, + Icons.video_camera_front_rounded, + Icons.video_camera_front_sharp, + Icons.video_chat, + Icons.video_chat_outlined, + Icons.video_chat_rounded, + Icons.video_chat_sharp, + Icons.video_collection, + Icons.video_collection_outlined, + Icons.video_collection_rounded, + Icons.video_collection_sharp, + Icons.video_file, + Icons.video_file_outlined, + Icons.video_file_rounded, + Icons.video_file_sharp, + Icons.video_label, + Icons.video_label_outlined, + Icons.video_label_rounded, + Icons.video_label_sharp, + Icons.video_library, + Icons.video_library_outlined, + Icons.video_library_rounded, + Icons.video_library_sharp, + Icons.video_settings, + Icons.video_settings_outlined, + Icons.video_settings_rounded, + Icons.video_settings_sharp, + Icons.video_stable, + Icons.video_stable_outlined, + Icons.video_stable_rounded, + Icons.video_stable_sharp, + Icons.videocam, + Icons.videocam_off, + Icons.videocam_off_outlined, + Icons.videocam_off_rounded, + Icons.videocam_off_sharp, + Icons.videocam_outlined, + Icons.videocam_rounded, + Icons.videocam_sharp, + Icons.videogame_asset, + Icons.videogame_asset_off, + Icons.videogame_asset_off_outlined, + Icons.videogame_asset_off_rounded, + Icons.videogame_asset_off_sharp, + Icons.videogame_asset_outlined, + Icons.videogame_asset_rounded, + Icons.videogame_asset_sharp, + Icons.view_agenda, + Icons.view_agenda_outlined, + Icons.view_agenda_rounded, + Icons.view_agenda_sharp, + Icons.view_array, + Icons.view_array_outlined, + Icons.view_array_rounded, + Icons.view_array_sharp, + Icons.view_carousel, + Icons.view_carousel_outlined, + Icons.view_carousel_rounded, + Icons.view_carousel_sharp, + Icons.view_column, + Icons.view_column_outlined, + Icons.view_column_rounded, + Icons.view_column_sharp, + Icons.view_comfortable, + Icons.view_comfortable_outlined, + Icons.view_comfortable_rounded, + Icons.view_comfortable_sharp, + Icons.view_comfy, + Icons.view_comfy_alt, + Icons.view_comfy_alt_outlined, + Icons.view_comfy_alt_rounded, + Icons.view_comfy_alt_sharp, + Icons.view_comfy_outlined, + Icons.view_comfy_rounded, + Icons.view_comfy_sharp, + Icons.view_compact, + Icons.view_compact_alt, + Icons.view_compact_alt_outlined, + Icons.view_compact_alt_rounded, + Icons.view_compact_alt_sharp, + Icons.view_compact_outlined, + Icons.view_compact_rounded, + Icons.view_compact_sharp, + Icons.view_cozy, + Icons.view_cozy_outlined, + Icons.view_cozy_rounded, + Icons.view_cozy_sharp, + Icons.view_day, + Icons.view_day_outlined, + Icons.view_day_rounded, + Icons.view_day_sharp, + Icons.view_headline, + Icons.view_headline_outlined, + Icons.view_headline_rounded, + Icons.view_headline_sharp, + Icons.view_in_ar, + Icons.view_in_ar_outlined, + Icons.view_in_ar_rounded, + Icons.view_in_ar_sharp, + Icons.view_kanban, + Icons.view_kanban_outlined, + Icons.view_kanban_rounded, + Icons.view_kanban_sharp, + Icons.view_list, + Icons.view_list_outlined, + Icons.view_list_rounded, + Icons.view_list_sharp, + Icons.view_module, + Icons.view_module_outlined, + Icons.view_module_rounded, + Icons.view_module_sharp, + Icons.view_quilt, + Icons.view_quilt_outlined, + Icons.view_quilt_rounded, + Icons.view_quilt_sharp, + Icons.view_sidebar, + Icons.view_sidebar_outlined, + Icons.view_sidebar_rounded, + Icons.view_sidebar_sharp, + Icons.view_stream, + Icons.view_stream_outlined, + Icons.view_stream_rounded, + Icons.view_stream_sharp, + Icons.view_timeline, + Icons.view_timeline_outlined, + Icons.view_timeline_rounded, + Icons.view_timeline_sharp, + Icons.view_week, + Icons.view_week_outlined, + Icons.view_week_rounded, + Icons.view_week_sharp, + Icons.vignette, + Icons.vignette_outlined, + Icons.vignette_rounded, + Icons.vignette_sharp, + Icons.villa, + Icons.villa_outlined, + Icons.villa_rounded, + Icons.villa_sharp, + Icons.visibility, + Icons.visibility_off, + Icons.visibility_off_outlined, + Icons.visibility_off_rounded, + Icons.visibility_off_sharp, + Icons.visibility_outlined, + Icons.visibility_rounded, + Icons.visibility_sharp, + Icons.voice_chat, + Icons.voice_chat_outlined, + Icons.voice_chat_rounded, + Icons.voice_chat_sharp, + Icons.voice_over_off, + Icons.voice_over_off_outlined, + Icons.voice_over_off_rounded, + Icons.voice_over_off_sharp, + Icons.voicemail, + Icons.voicemail_outlined, + Icons.voicemail_rounded, + Icons.voicemail_sharp, + Icons.volcano, + Icons.volcano_outlined, + Icons.volcano_rounded, + Icons.volcano_sharp, + Icons.volume_down, + Icons.volume_down_alt, + Icons.volume_down_outlined, + Icons.volume_down_rounded, + Icons.volume_down_sharp, + Icons.volume_mute, + Icons.volume_mute_outlined, + Icons.volume_mute_rounded, + Icons.volume_mute_sharp, + Icons.volume_off, + Icons.volume_off_outlined, + Icons.volume_off_rounded, + Icons.volume_off_sharp, + Icons.volume_up, + Icons.volume_up_outlined, + Icons.volume_up_rounded, + Icons.volume_up_sharp, + Icons.volunteer_activism, + Icons.volunteer_activism_outlined, + Icons.volunteer_activism_rounded, + Icons.volunteer_activism_sharp, + Icons.vpn_key, + Icons.vpn_key_off, + Icons.vpn_key_off_outlined, + Icons.vpn_key_off_rounded, + Icons.vpn_key_off_sharp, + Icons.vpn_key_outlined, + Icons.vpn_key_rounded, + Icons.vpn_key_sharp, + Icons.vpn_lock, + Icons.vpn_lock_outlined, + Icons.vpn_lock_rounded, + Icons.vpn_lock_sharp, + Icons.vrpano, + Icons.vrpano_outlined, + Icons.vrpano_rounded, + Icons.vrpano_sharp, + Icons.wallet, + Icons.wallet_giftcard, + Icons.wallet_giftcard_outlined, + Icons.wallet_giftcard_rounded, + Icons.wallet_giftcard_sharp, + Icons.wallet_membership, + Icons.wallet_membership_outlined, + Icons.wallet_membership_rounded, + Icons.wallet_membership_sharp, + Icons.wallet_outlined, + Icons.wallet_rounded, + Icons.wallet_sharp, + Icons.wallet_travel, + Icons.wallet_travel_outlined, + Icons.wallet_travel_rounded, + Icons.wallet_travel_sharp, + Icons.wallpaper, + Icons.wallpaper_outlined, + Icons.wallpaper_rounded, + Icons.wallpaper_sharp, + Icons.warehouse, + Icons.warehouse_outlined, + Icons.warehouse_rounded, + Icons.warehouse_sharp, + Icons.warning, + Icons.warning_amber, + Icons.warning_amber_outlined, + Icons.warning_amber_rounded, + Icons.warning_amber_sharp, + Icons.warning_outlined, + Icons.warning_rounded, + Icons.warning_sharp, + Icons.wash, + Icons.wash_outlined, + Icons.wash_rounded, + Icons.wash_sharp, + Icons.watch, + Icons.watch_later, + Icons.watch_later_outlined, + Icons.watch_later_rounded, + Icons.watch_later_sharp, + Icons.watch_off, + Icons.watch_off_outlined, + Icons.watch_off_rounded, + Icons.watch_off_sharp, + Icons.watch_outlined, + Icons.watch_rounded, + Icons.watch_sharp, + Icons.water, + Icons.water_damage, + Icons.water_damage_outlined, + Icons.water_damage_rounded, + Icons.water_damage_sharp, + Icons.water_drop, + Icons.water_drop_outlined, + Icons.water_drop_rounded, + Icons.water_drop_sharp, + Icons.water_outlined, + Icons.water_rounded, + Icons.water_sharp, + Icons.waterfall_chart, + Icons.waterfall_chart_outlined, + Icons.waterfall_chart_rounded, + Icons.waterfall_chart_sharp, + Icons.waves, + Icons.waves_outlined, + Icons.waves_rounded, + Icons.waves_sharp, + Icons.waving_hand, + Icons.waving_hand_outlined, + Icons.waving_hand_rounded, + Icons.waving_hand_sharp, + Icons.wb_auto, + Icons.wb_auto_outlined, + Icons.wb_auto_rounded, + Icons.wb_auto_sharp, + Icons.wb_cloudy, + Icons.wb_cloudy_outlined, + Icons.wb_cloudy_rounded, + Icons.wb_cloudy_sharp, + Icons.wb_incandescent, + Icons.wb_incandescent_outlined, + Icons.wb_incandescent_rounded, + Icons.wb_incandescent_sharp, + Icons.wb_iridescent, + Icons.wb_iridescent_outlined, + Icons.wb_iridescent_rounded, + Icons.wb_iridescent_sharp, + Icons.wb_shade, + Icons.wb_shade_outlined, + Icons.wb_shade_rounded, + Icons.wb_shade_sharp, + Icons.wb_sunny, + Icons.wb_sunny_outlined, + Icons.wb_sunny_rounded, + Icons.wb_sunny_sharp, + Icons.wb_twighlight, + Icons.wb_twilight, + Icons.wb_twilight_outlined, + Icons.wb_twilight_rounded, + Icons.wb_twilight_sharp, + Icons.wc, + Icons.wc_outlined, + Icons.wc_rounded, + Icons.wc_sharp, + Icons.web, + Icons.web_asset, + Icons.web_asset_off, + Icons.web_asset_off_outlined, + Icons.web_asset_off_rounded, + Icons.web_asset_off_sharp, + Icons.web_asset_outlined, + Icons.web_asset_rounded, + Icons.web_asset_sharp, + Icons.web_outlined, + Icons.web_rounded, + Icons.web_sharp, + Icons.web_stories, + Icons.web_stories_outlined, + Icons.web_stories_rounded, + Icons.web_stories_sharp, + Icons.webhook, + Icons.webhook_outlined, + Icons.webhook_rounded, + Icons.webhook_sharp, + Icons.wechat, + Icons.wechat_outlined, + Icons.wechat_rounded, + Icons.wechat_sharp, + Icons.weekend, + Icons.weekend_outlined, + Icons.weekend_rounded, + Icons.weekend_sharp, + Icons.west, + Icons.west_outlined, + Icons.west_rounded, + Icons.west_sharp, + Icons.whatshot, + Icons.whatshot_outlined, + Icons.whatshot_rounded, + Icons.whatshot_sharp, + Icons.wheelchair_pickup, + Icons.wheelchair_pickup_outlined, + Icons.wheelchair_pickup_rounded, + Icons.wheelchair_pickup_sharp, + Icons.where_to_vote, + Icons.where_to_vote_outlined, + Icons.where_to_vote_rounded, + Icons.where_to_vote_sharp, + Icons.widgets, + Icons.widgets_outlined, + Icons.widgets_rounded, + Icons.widgets_sharp, + Icons.width_full, + Icons.width_full_outlined, + Icons.width_full_rounded, + Icons.width_full_sharp, + Icons.width_normal, + Icons.width_normal_outlined, + Icons.width_normal_rounded, + Icons.width_normal_sharp, + Icons.width_wide, + Icons.width_wide_outlined, + Icons.width_wide_rounded, + Icons.width_wide_sharp, + Icons.wifi, + Icons.wifi_1_bar, + Icons.wifi_1_bar_outlined, + Icons.wifi_1_bar_rounded, + Icons.wifi_1_bar_sharp, + Icons.wifi_2_bar, + Icons.wifi_2_bar_outlined, + Icons.wifi_2_bar_rounded, + Icons.wifi_2_bar_sharp, + Icons.wifi_calling, + Icons.wifi_calling_3, + Icons.wifi_calling_3_outlined, + Icons.wifi_calling_3_rounded, + Icons.wifi_calling_3_sharp, + Icons.wifi_calling_outlined, + Icons.wifi_calling_rounded, + Icons.wifi_calling_sharp, + Icons.wifi_channel, + Icons.wifi_channel_outlined, + Icons.wifi_channel_rounded, + Icons.wifi_channel_sharp, + Icons.wifi_find, + Icons.wifi_find_outlined, + Icons.wifi_find_rounded, + Icons.wifi_find_sharp, + Icons.wifi_lock, + Icons.wifi_lock_outlined, + Icons.wifi_lock_rounded, + Icons.wifi_lock_sharp, + Icons.wifi_off, + Icons.wifi_off_outlined, + Icons.wifi_off_rounded, + Icons.wifi_off_sharp, + Icons.wifi_outlined, + Icons.wifi_password, + Icons.wifi_password_outlined, + Icons.wifi_password_rounded, + Icons.wifi_password_sharp, + Icons.wifi_protected_setup, + Icons.wifi_protected_setup_outlined, + Icons.wifi_protected_setup_rounded, + Icons.wifi_protected_setup_sharp, + Icons.wifi_rounded, + Icons.wifi_sharp, + Icons.wifi_tethering, + Icons.wifi_tethering_error, + Icons.wifi_tethering_error_outlined, + Icons.wifi_tethering_error_rounded, + Icons.wifi_tethering_error_rounded_outlined, + Icons.wifi_tethering_error_rounded_rounded, + Icons.wifi_tethering_error_rounded_sharp, + Icons.wifi_tethering_error_sharp, + Icons.wifi_tethering_off, + Icons.wifi_tethering_off_outlined, + Icons.wifi_tethering_off_rounded, + Icons.wifi_tethering_off_sharp, + Icons.wifi_tethering_outlined, + Icons.wifi_tethering_rounded, + Icons.wifi_tethering_sharp, + Icons.wind_power, + Icons.wind_power_outlined, + Icons.wind_power_rounded, + Icons.wind_power_sharp, + Icons.window, + Icons.window_outlined, + Icons.window_rounded, + Icons.window_sharp, + Icons.wine_bar, + Icons.wine_bar_outlined, + Icons.wine_bar_rounded, + Icons.wine_bar_sharp, + Icons.woman, + Icons.woman_2, + Icons.woman_2_outlined, + Icons.woman_2_rounded, + Icons.woman_2_sharp, + Icons.woman_outlined, + Icons.woman_rounded, + Icons.woman_sharp, + Icons.woo_commerce, + Icons.woo_commerce_outlined, + Icons.woo_commerce_rounded, + Icons.woo_commerce_sharp, + Icons.wordpress, + Icons.wordpress_outlined, + Icons.wordpress_rounded, + Icons.wordpress_sharp, + Icons.work, + Icons.work_history, + Icons.work_history_outlined, + Icons.work_history_rounded, + Icons.work_history_sharp, + Icons.work_off, + Icons.work_off_outlined, + Icons.work_off_rounded, + Icons.work_off_sharp, + Icons.work_outline, + Icons.work_outline_outlined, + Icons.work_outline_rounded, + Icons.work_outline_sharp, + Icons.work_outlined, + Icons.work_rounded, + Icons.work_sharp, + Icons.workspace_premium, + Icons.workspace_premium_outlined, + Icons.workspace_premium_rounded, + Icons.workspace_premium_sharp, + Icons.workspaces, + Icons.workspaces_filled, + Icons.workspaces_outline, + Icons.workspaces_outlined, + Icons.workspaces_rounded, + Icons.workspaces_sharp, + Icons.wrap_text, + Icons.wrap_text_outlined, + Icons.wrap_text_rounded, + Icons.wrap_text_sharp, + Icons.wrong_location, + Icons.wrong_location_outlined, + Icons.wrong_location_rounded, + Icons.wrong_location_sharp, + Icons.wysiwyg, + Icons.wysiwyg_outlined, + Icons.wysiwyg_rounded, + Icons.wysiwyg_sharp, + Icons.yard, + Icons.yard_outlined, + Icons.yard_rounded, + Icons.yard_sharp, + Icons.youtube_searched_for, + Icons.youtube_searched_for_outlined, + Icons.youtube_searched_for_rounded, + Icons.youtube_searched_for_sharp, + Icons.zoom_in, + Icons.zoom_in_map, + Icons.zoom_in_map_outlined, + Icons.zoom_in_map_rounded, + Icons.zoom_in_map_sharp, + Icons.zoom_in_outlined, + Icons.zoom_in_rounded, + Icons.zoom_in_sharp, + Icons.zoom_out, + Icons.zoom_out_map, + Icons.zoom_out_map_outlined, + Icons.zoom_out_map_rounded, + Icons.zoom_out_map_sharp, + Icons.zoom_out_outlined, + Icons.zoom_out_rounded, + Icons.zoom_out_sharp, + ]; diff --git a/packages/flet/lib/src/utils/material_state.dart b/packages/flet/lib/src/utils/material_state.dart deleted file mode 100644 index 65421197c6..0000000000 --- a/packages/flet/lib/src/utils/material_state.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:collection'; -import 'package:flutter/material.dart'; - -WidgetStateProperty? getWidgetStateProperty( - dynamic jsonDictValue, T Function(dynamic) converterFromJson, - [T? defaultValue]) { - if (jsonDictValue == null) { - return null; - } - var j = jsonDictValue; - if (j is! Map) { - j = {"default": j}; - } - return WidgetStateFromJSON(j, converterFromJson, defaultValue); -} - -class WidgetStateFromJSON extends WidgetStateProperty { - late final LinkedHashMap _states; - late final T? _defaultValue; - - WidgetStateFromJSON(Map? jsonDictValue, - T Function(dynamic) converterFromJson, T? defaultValue) { - _defaultValue = defaultValue; - - // preserve user-defined order - _states = LinkedHashMap.from( - jsonDictValue?.map((k, v) { - var key = k.trim().toLowerCase(); - // "" is deprecated and renamed to "default" - if (key == "") key = "default"; - return MapEntry(key, converterFromJson(v)); - }) ?? - {}, - ); - } - - @override - T? resolve(Set states) { - // Resolve using user-defined order in _states - for (var stateName in _states.keys) { - if (stateName == "default") continue; // Skip "default"; handled last - if (states.any((state) => state.name == stateName)) { - return _states[stateName]; - } - } - - // Default state - return _states["default"] ?? _defaultValue; - } -} diff --git a/packages/flet/lib/src/utils/menu.dart b/packages/flet/lib/src/utils/menu.dart index 8760f5eb23..a2ed9c53c3 100644 --- a/packages/flet/lib/src/utils/menu.dart +++ b/packages/flet/lib/src/utils/menu.dart @@ -1,17 +1,17 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import '../models/control.dart'; +import '../utils/theme.dart'; import 'alignment.dart'; import 'borders.dart'; import 'colors.dart'; import 'edge_insets.dart'; -import 'material_state.dart'; +import 'geometry.dart'; import 'mouse.dart'; import 'numbers.dart'; +import 'widget_state.dart'; -MenuStyle? parseMenuStyle(ThemeData theme, Control control, String propName, +MenuStyle? parseMenuStyle(dynamic value, ThemeData theme, {Color? defaultBackgroundColor, Color? defaultShadowColor, Color? defaultSurfaceTintColor, @@ -20,59 +20,65 @@ MenuStyle? parseMenuStyle(ThemeData theme, Control control, String propName, MouseCursor? defaultMouseCursor, EdgeInsets? defaultPadding, BorderSide? defaultBorderSide, - OutlinedBorder? defaultShape}) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return menuStyleFromJSON( - theme, - j1, - defaultBackgroundColor, - defaultShadowColor, - defaultSurfaceTintColor, - defaultElevation, - defaultAlignment, - defaultMouseCursor, - defaultPadding, - defaultBorderSide, - defaultShape); -} + OutlinedBorder? defaultShape, + Size? defaultMinimumSize, + Size? defaultMaximumSize, + Size? defaultFixedSize, + VisualDensity? defaultVisualDensity, + MenuStyle? defaultValue}) { + if (value == null) return defaultValue; -MenuStyle? menuStyleFromJSON(ThemeData theme, Map? json, - [Color? defaultBackgroundColor, - Color? defaultShadowColor, - Color? defaultSurfaceTintColor, - double? defaultElevation, - Alignment? defaultAlignment, - MouseCursor? defaultMouseCursor, - EdgeInsets? defaultPadding, - BorderSide? defaultBorderSide, - OutlinedBorder? defaultShape]) { - if (json == null) { - return null; - } return MenuStyle( - alignment: alignmentFromJson(json["alignment"], defaultAlignment)!, - backgroundColor: getWidgetStateProperty(json["bgcolor"], - (jv) => parseColor(theme, jv as String), defaultBackgroundColor), - shadowColor: getWidgetStateProperty(json["shadow_color"], - (jv) => parseColor(theme, jv as String), defaultShadowColor), - surfaceTintColor: getWidgetStateProperty(json["surface_tint_color"], - (jv) => parseColor(theme, jv as String), defaultSurfaceTintColor), - elevation: getWidgetStateProperty( - json["elevation"], (jv) => parseDouble(jv, 0)!, defaultElevation), + alignment: parseAlignment(value["alignment"], defaultAlignment), + backgroundColor: parseWidgetStateColor(value["bgcolor"], theme, + defaultColor: defaultBackgroundColor), + shadowColor: parseWidgetStateColor(value["shadow_color"], theme, + defaultColor: defaultShadowColor), + elevation: parseWidgetStateDouble(value["elevation"], + defaultDouble: defaultElevation), padding: getWidgetStateProperty( - json["padding"], (jv) => edgeInsetsFromJson(jv), defaultPadding), + value["padding"], (jv) => parseEdgeInsets(jv), defaultPadding), side: getWidgetStateProperty( - json["side"], - (jv) => borderSideFromJSON(theme, jv, theme.colorScheme.outline), + value["side"], + (jv) => parseBorderSide(jv, theme, defaultSideColor: Colors.black), defaultBorderSide), - shape: getWidgetStateProperty( - json["shape"], (jv) => outlinedBorderFromJSON(jv), defaultShape), - mouseCursor: getWidgetStateProperty(json["mouse_cursor"], - (jv) => parseMouseCursor(jv as String), defaultMouseCursor), + shape: parseWidgetStateOutlinedBorder(value["shape"], theme, + defaultOutlinedBorder: defaultShape), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"], + defaultMouseCursor: defaultMouseCursor), + minimumSize: parseWidgetStateSize(value["min_size"], + defaultSize: defaultMinimumSize), + maximumSize: parseWidgetStateSize(value["max_size"], + defaultSize: defaultMaximumSize), + fixedSize: parseWidgetStateSize(value["fixed_size"], + defaultSize: defaultFixedSize), + visualDensity: + parseVisualDensity(value["visual_density"], defaultVisualDensity), ); } + +extension MenuParsers on Control { + MenuStyle? getMenuStyle(String propertyName, ThemeData theme, + {Color? defaultBackgroundColor, + Color? defaultShadowColor, + Color? defaultSurfaceTintColor, + double? defaultElevation, + Alignment? defaultAlignment, + MouseCursor? defaultMouseCursor, + EdgeInsets? defaultPadding, + BorderSide? defaultBorderSide, + OutlinedBorder? defaultShape, + MenuStyle? defaultValue}) { + return parseMenuStyle(get(propertyName), theme, + defaultBackgroundColor: defaultBackgroundColor, + defaultShadowColor: defaultShadowColor, + defaultSurfaceTintColor: defaultSurfaceTintColor, + defaultElevation: defaultElevation, + defaultAlignment: defaultAlignment, + defaultMouseCursor: defaultMouseCursor, + defaultPadding: defaultPadding, + defaultBorderSide: defaultBorderSide, + defaultShape: defaultShape, + defaultValue: defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/misc.dart b/packages/flet/lib/src/utils/misc.dart new file mode 100644 index 0000000000..f6ce430ffa --- /dev/null +++ b/packages/flet/lib/src/utils/misc.dart @@ -0,0 +1,236 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +import '../models/control.dart'; +import 'borders.dart'; +import 'enums.dart'; +import 'numbers.dart'; + +Clip? parseClip(String? value, [Clip? defaultValue]) { + return parseEnum(Clip.values, value, defaultValue); +} + +Orientation? parseOrientation(String? value, [Orientation? defaultValue]) { + return parseEnum(Orientation.values, value, defaultValue); +} + +StrokeCap? parseStrokeCap(String? value, [StrokeCap? defaultValue]) { + return parseEnum(StrokeCap.values, value, defaultValue); +} + +StrokeJoin? parseStrokeJoin(String? value, [StrokeJoin? defaultValue]) { + return parseEnum(StrokeJoin.values, value, defaultValue); +} + +BoxShape? parseBoxShape(String? value, [BoxShape? defaultValue]) { + return parseEnum(BoxShape.values, value, defaultValue); +} + +NotchedShape? parseNotchedShape(dynamic value, ThemeData? theme, + [NotchedShape? defaultValue]) { + if (value == null) return defaultValue; + + var type = value["_type"]; + if (type == "circular") { + return CircularNotchedRectangle( + inverted: parseBool(value["inverted"], false)!); + } else if (type == "auto") { + return AutomaticNotchedShape( + parseShapeBorder( + value["host"], theme, const ContinuousRectangleBorder())!, + parseShapeBorder(value["guest"], theme)); + } else { + return defaultValue; + } +} + +SliderInteraction? parseSliderInteraction(String? value, + [SliderInteraction? defaultValue]) { + return parseEnum(SliderInteraction.values, value, defaultValue); +} + +SnackBarBehavior? parseSnackBarBehavior(String? value, + [SnackBarBehavior? defaultValue]) { + return parseEnum(SnackBarBehavior.values, value, defaultValue); +} + +StackFit? parseStackFit(String? value, [StackFit? defaultValue]) { + return parseEnum(StackFit.values, value, defaultValue); +} + +enum CardVariant { elevated, filled, outlined } + +CardVariant? parseCardVariant(String? value, [CardVariant? defaultValue]) { + return parseEnum(CardVariant.values, value, defaultValue); +} + +enum LabelPosition { right, left } + +LabelPosition? parseLabelPosition(String? value, + [LabelPosition? defaultValue]) { + return parseEnum(LabelPosition.values, value, defaultValue); +} + +ListTileControlAffinity? parseListTileControlAffinity(String? value, + [ListTileControlAffinity? defaultValue]) { + return parseEnum(ListTileControlAffinity.values, value, defaultValue); +} + +ListTileStyle? parseListTileStyle(String? value, + [ListTileStyle? defaultValue]) { + return parseEnum(ListTileStyle.values, value, defaultValue); +} + +NavigationDestinationLabelBehavior? parseNavigationDestinationLabelBehavior( + String? value, + [NavigationDestinationLabelBehavior? defaultValue]) { + return parseEnum( + NavigationDestinationLabelBehavior.values, value, defaultValue); +} + +PopupMenuPosition? parsePopupMenuPosition(String? value, + [PopupMenuPosition? defaultValue]) { + return parseEnum(PopupMenuPosition.values, value, defaultValue); +} + +Assertiveness? parseAssertiveness(String? value, + [Assertiveness? defaultValue]) { + return parseEnum(Assertiveness.values, value, defaultValue); +} + +ListTileTitleAlignment? parseListTileTitleAlignment(String? value, + [ListTileTitleAlignment? defaultValue]) { + return parseEnum(ListTileTitleAlignment.values, value, defaultValue); +} + +Axis? parseAxis(String? value, [Axis? defaultValue]) { + return parseEnum(Axis.values, value, defaultValue); +} + +PointerDeviceKind? parsePointerDeviceKind(String? value, + [PointerDeviceKind? defaultValue]) { + return parseEnum(PointerDeviceKind.values, value, defaultValue); +} + +NavigationRailLabelType? parseNavigationRailLabelType(String? value, + [NavigationRailLabelType? defaultValue]) { + return parseEnum(NavigationRailLabelType.values, value, defaultValue); +} + +BlurStyle? parseBlurStyle(String? value, [BlurStyle? defaultValue]) { + return parseEnum(BlurStyle.values, value, defaultValue); +} + +FloatingLabelBehavior? parseFloatingLabelBehavior(String? value, + [FloatingLabelBehavior? defaultValue]) { + return parseEnum(FloatingLabelBehavior.values, value, defaultValue); +} + +extension MiscParsers on Control { + Clip? getClipBehavior(String propertyName, [Clip? defaultValue]) { + return parseClip(get(propertyName), defaultValue); + } + + Orientation? getOrientation(String propertyName, + [Orientation? defaultValue]) { + return parseOrientation(get(propertyName), defaultValue); + } + + StrokeCap? getStrokeCap(String propertyName, [StrokeCap? defaultValue]) { + return parseStrokeCap(get(propertyName), defaultValue); + } + + StrokeJoin? getStrokeJoin(String propertyName, [StrokeJoin? defaultValue]) { + return parseStrokeJoin(get(propertyName), defaultValue); + } + + BoxShape? getBoxShape(String propertyName, [BoxShape? defaultValue]) { + return parseBoxShape(get(propertyName), defaultValue); + } + + NotchedShape? getNotchedShape(String propertyName, ThemeData? theme, + [NotchedShape? defaultValue]) { + return parseNotchedShape(get(propertyName), theme, defaultValue); + } + + SliderInteraction? getSliderInteraction(String propertyName, + [SliderInteraction? defaultValue]) { + return parseSliderInteraction(get(propertyName), defaultValue); + } + + SnackBarBehavior? getSnackBarBehavior(String propertyName, + [SnackBarBehavior? defaultValue]) { + return parseSnackBarBehavior(get(propertyName), defaultValue); + } + + StackFit? getStackFit(String propertyName, [StackFit? defaultValue]) { + return parseStackFit(get(propertyName), defaultValue); + } + + CardVariant? getCardVariant(String propertyName, + [CardVariant? defaultValue]) { + return parseCardVariant(get(propertyName), defaultValue); + } + + LabelPosition? getLabelPosition(String propertyName, + [LabelPosition? defaultValue]) { + return parseLabelPosition(get(propertyName), defaultValue); + } + + ListTileControlAffinity? getListTileControlAffinity(String propertyName, + [ListTileControlAffinity? defaultValue]) { + return parseListTileControlAffinity(get(propertyName), defaultValue); + } + + ListTileStyle? getListTileStyle(String propertyName, + [ListTileStyle? defaultValue]) { + return parseListTileStyle(get(propertyName), defaultValue); + } + + NavigationDestinationLabelBehavior? getNavigationDestinationLabelBehavior( + String propertyName, + [NavigationDestinationLabelBehavior? defaultValue]) { + return parseNavigationDestinationLabelBehavior( + get(propertyName), defaultValue); + } + + PopupMenuPosition? getPopupMenuPosition(String propertyName, + [PopupMenuPosition? defaultValue]) { + return parsePopupMenuPosition(get(propertyName), defaultValue); + } + + Assertiveness? getAssertiveness(String propertyName, + [Assertiveness? defaultValue]) { + return parseAssertiveness(get(propertyName), defaultValue); + } + + ListTileTitleAlignment? getListTileTitleAlignment(String propertyName, + [ListTileTitleAlignment? defaultValue]) { + return parseListTileTitleAlignment(get(propertyName), defaultValue); + } + + Axis? getAxis(String propertyName, [Axis? defaultValue]) { + return parseAxis(get(propertyName), defaultValue); + } + + PointerDeviceKind? getPointerDeviceKind(String propertyName, + [PointerDeviceKind? defaultValue]) { + return parsePointerDeviceKind(get(propertyName), defaultValue); + } + + NavigationRailLabelType? getNavigationRailLabelType(String propertyName, + [NavigationRailLabelType? defaultValue]) { + return parseNavigationRailLabelType(get(propertyName), defaultValue); + } + + BlurStyle? getBlurStyle(String propertyName, [BlurStyle? defaultValue]) { + return parseBlurStyle(get(propertyName), defaultValue); + } + + FloatingLabelBehavior? getFloatingLabelBehavior(String propertyName, + [FloatingLabelBehavior? defaultValue]) { + return parseFloatingLabelBehavior(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/mouse.dart b/packages/flet/lib/src/utils/mouse.dart index 73fc449f21..ccad30a17a 100644 --- a/packages/flet/lib/src/utils/mouse.dart +++ b/packages/flet/lib/src/utils/mouse.dart @@ -1,98 +1,71 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import '../models/control.dart'; -import 'material_state.dart'; +import 'widget_state.dart'; -MouseCursor? parseMouseCursor(String? cursor, - [MouseCursor? defaultMouseCursor]) { - switch (cursor?.toLowerCase()) { - case "alias": - return SystemMouseCursors.alias; - case "allscroll": - return SystemMouseCursors.allScroll; - case "basic": - return SystemMouseCursors.basic; - case "cell": - return SystemMouseCursors.cell; - case "click": - return SystemMouseCursors.click; - case "contextmenu": - return SystemMouseCursors.contextMenu; - case "copy": - return SystemMouseCursors.copy; - case "disappearing": - return SystemMouseCursors.disappearing; - case "forbidden": - return SystemMouseCursors.forbidden; - case "grab": - return SystemMouseCursors.grab; - case "grabbing": - return SystemMouseCursors.grabbing; - case "help": - return SystemMouseCursors.help; - case "move": - return SystemMouseCursors.move; - case "nodrop": - return SystemMouseCursors.noDrop; - case "none": - return SystemMouseCursors.none; - case "precise": - return SystemMouseCursors.precise; - case "progress": - return SystemMouseCursors.progress; - case "resizecolumn": - return SystemMouseCursors.resizeColumn; - case "resizedown": - return SystemMouseCursors.resizeDown; - case "resizedownleft": - return SystemMouseCursors.resizeDownLeft; - case "resizedownright": - return SystemMouseCursors.resizeDownRight; - case "resizeleft": - return SystemMouseCursors.resizeLeft; - case "resizeleftright": - return SystemMouseCursors.resizeLeftRight; - case "resizeright": - return SystemMouseCursors.resizeRight; - case "resizerow": - return SystemMouseCursors.resizeRow; - case "resizeup": - return SystemMouseCursors.resizeUp; - case "resizeupdown": - return SystemMouseCursors.resizeUpDown; - case "resizeupleft": - return SystemMouseCursors.resizeUpLeft; - case "resizeupleftdownright": - return SystemMouseCursors.resizeUpLeftDownRight; - case "resizeupright": - return SystemMouseCursors.resizeUpRight; - case "resizeuprightdownleft": - return SystemMouseCursors.resizeUpRightDownLeft; - case "text": - return SystemMouseCursors.text; - case "verticaltext": - return SystemMouseCursors.verticalText; - case "wait": - return SystemMouseCursors.wait; - case "zoomin": - return SystemMouseCursors.zoomIn; - case "zoomout": - return SystemMouseCursors.zoomOut; - default: - return defaultMouseCursor; - } +MouseCursor? parseMouseCursor(String? cursor, [MouseCursor? defaultValue]) { + const cursorMap = { + "alias": SystemMouseCursors.alias, + "allscroll": SystemMouseCursors.allScroll, + "basic": SystemMouseCursors.basic, + "cell": SystemMouseCursors.cell, + "click": SystemMouseCursors.click, + "contextmenu": SystemMouseCursors.contextMenu, + "copy": SystemMouseCursors.copy, + "disappearing": SystemMouseCursors.disappearing, + "forbidden": SystemMouseCursors.forbidden, + "grab": SystemMouseCursors.grab, + "grabbing": SystemMouseCursors.grabbing, + "help": SystemMouseCursors.help, + "move": SystemMouseCursors.move, + "nodrop": SystemMouseCursors.noDrop, + "none": SystemMouseCursors.none, + "precise": SystemMouseCursors.precise, + "progress": SystemMouseCursors.progress, + "resizecolumn": SystemMouseCursors.resizeColumn, + "resizedown": SystemMouseCursors.resizeDown, + "resizedownleft": SystemMouseCursors.resizeDownLeft, + "resizedownright": SystemMouseCursors.resizeDownRight, + "resizeleft": SystemMouseCursors.resizeLeft, + "resizeleftright": SystemMouseCursors.resizeLeftRight, + "resizeright": SystemMouseCursors.resizeRight, + "resizerow": SystemMouseCursors.resizeRow, + "resizeup": SystemMouseCursors.resizeUp, + "resizeupdown": SystemMouseCursors.resizeUpDown, + "resizeupleft": SystemMouseCursors.resizeUpLeft, + "resizeupleftdownright": SystemMouseCursors.resizeUpLeftDownRight, + "resizeupright": SystemMouseCursors.resizeUpRight, + "resizeuprightdownleft": SystemMouseCursors.resizeUpRightDownLeft, + "text": SystemMouseCursors.text, + "verticaltext": SystemMouseCursors.verticalText, + "wait": SystemMouseCursors.wait, + "zoomin": SystemMouseCursors.zoomIn, + "zoomout": SystemMouseCursors.zoomOut, + }; + + return cursorMap[cursor?.toLowerCase() ?? ""] ?? defaultValue; } -WidgetStateProperty? parseWidgetStateMouseCursor( - Control control, String propName, - [MouseCursor? defaultValue]) { - var v = control.attrString(propName); - if (v == null) { - return null; - } +WidgetStateProperty? parseWidgetStateMouseCursor(dynamic value, + {MouseCursor? defaultMouseCursor, + WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; return getWidgetStateProperty( - jsonDecode(v), (jv) => parseMouseCursor(jv as String), defaultValue); + value, (jv) => parseMouseCursor(jv as String), defaultMouseCursor); +} + +extension MouseParsers on Control { + MouseCursor? getMouseCursor(String propertyName, + [MouseCursor? defaultValue]) { + return parseMouseCursor(get(propertyName), defaultValue); + } + + WidgetStateProperty? getWidgetStateMouseCursor( + String propertyName, + {MouseCursor? defaultMouseCursor, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateMouseCursor(get(propertyName), + defaultMouseCursor: defaultMouseCursor, defaultValue: defaultValue); + } } diff --git a/packages/flet/lib/src/utils/numbers.dart b/packages/flet/lib/src/utils/numbers.dart index bb3e142b10..0d0d36139a 100644 --- a/packages/flet/lib/src/utils/numbers.dart +++ b/packages/flet/lib/src/utils/numbers.dart @@ -1,70 +1,110 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import '../models/control.dart'; -import 'material_state.dart'; +import 'widget_state.dart'; + +typedef ListValueMapper = T Function(dynamic value); -double? parseDouble(dynamic v, [double? defValue]) { - if (v is double) { - return v; - } else if (v is String && v.toLowerCase() == "inf") { +double? parseDouble(dynamic value, [double? defaultValue]) { + if (value is double) { + return value; + } else if (value is String && value.toLowerCase() == "inf") { return double.infinity; - } else if (v == null) { - return defValue; + } else if (value == null) { + return defaultValue; + } else if (value is int) { + return value.toDouble(); } else { - return double.tryParse(v.toString()) ?? defValue; + return double.tryParse(value.toString()) ?? defaultValue; } } -WidgetStateProperty? parseWidgetStateDouble( - Control control, String propName, - [double? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } +WidgetStateProperty? parseWidgetStateDouble(dynamic value, + {double? defaultDouble, WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; return getWidgetStateProperty( - jsonDecode(v), (jv) => parseDouble(jv), defaultValue); + value, (jv) => parseDouble(jv), defaultDouble); } -int? parseInt(dynamic v, [int? defValue]) { - if (v is int) { - return v; - } else if (v == null) { - return defValue; +int? parseInt(dynamic value, [int? defaultValue]) { + if (value is int) { + return value; + } else if (value is double) { + return value.toInt(); + } else if (value == null) { + return defaultValue; } else { - return int.tryParse(v.toString()) ?? defValue; + return int.tryParse(value.toString()) ?? defaultValue; } } -WidgetStateProperty? parseWidgetStateInt(Control control, String propName, - [int? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - return getWidgetStateProperty( - jsonDecode(v), (jv) => parseInt(jv), defaultValue); +WidgetStateProperty? parseWidgetStateInt(dynamic value, + {int? defaultInt, WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; + return getWidgetStateProperty(value, (jv) => parseInt(jv), defaultInt); } -bool? parseBool(dynamic v, [bool? defValue]) { - if (v is bool) { - return v; - } else if (v == null) { - return defValue; +bool? parseBool(dynamic value, [bool? defaultValue]) { + if (value is bool) { + return value; + } else if (value == null) { + return defaultValue; } else { - return "true" == v.toString().toLowerCase(); + return "true" == value.toString().toLowerCase(); } } -WidgetStateProperty? parseWidgetStateBool( - Control control, String propName, - [bool? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } +WidgetStateProperty? parseWidgetStateBool(dynamic value, + {bool? defaultBool, WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; return getWidgetStateProperty( - jsonDecode(v), (jv) => parseBool(jv), defaultValue); + value, (jv) => parseBool(jv), defaultBool); +} + +List? parseList(dynamic value, ListValueMapper map, + {List? defaultValue}) { + if (value == null) return defaultValue; + if (value is! List) return defaultValue; + return value.map(map).toList(); +} + +extension LiteralParsers on Control { + bool? getBool(String propertyName, [bool? defaultValue]) { + return get(propertyName, defaultValue); + } + + String? getString(String propertyName, [String? defaultValue]) { + return get(propertyName, defaultValue); + } + + int? getInt(String propertyName, [int? defaultValue]) { + return get(propertyName, defaultValue); + } + + double? getDouble(String propertyName, [double? defaultValue]) { + return get(propertyName, defaultValue); + } + + List? getList(String propertyName, ListValueMapper map, + {List? defaultValue}) { + return parseList(get(propertyName), map, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStateDouble(String propertyName, + {double? defaultDouble, WidgetStateProperty? defaultValue}) { + return parseWidgetStateDouble(get(propertyName), + defaultDouble: defaultDouble, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStateInt(String propertyName, + {int? defaultInt, WidgetStateProperty? defaultValue}) { + return parseWidgetStateInt(get(propertyName), + defaultInt: defaultInt, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStateBool(String propertyName, + {bool? defaultBool, WidgetStateProperty? defaultValue}) { + return parseWidgetStateBool(get(propertyName), + defaultBool: defaultBool, defaultValue: defaultValue); + } } diff --git a/packages/flet/lib/src/utils/others.dart b/packages/flet/lib/src/utils/others.dart deleted file mode 100644 index 6727e01be3..0000000000 --- a/packages/flet/lib/src/utils/others.dart +++ /dev/null @@ -1,288 +0,0 @@ -import 'dart:convert'; -import 'dart:ui'; - -import 'package:collection/collection.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; - -import '../models/control.dart'; -import 'numbers.dart'; - -Clip? parseClip(String? value, [Clip? defaultValue]) { - if (value == null) { - return defaultValue; - } - return Clip.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defaultValue; -} - -Orientation? parseOrientation(String? value, - [Orientation? defaultOrientation]) { - if (value == null) { - return defaultOrientation; - } - return Orientation.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defaultOrientation; -} - -StrokeCap? parseStrokeCap(String? value, [StrokeCap? defValue]) { - if (value == null) { - return defValue; - } - return StrokeCap.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -StrokeJoin? parseStrokeJoin(String? value, [StrokeJoin? defValue]) { - if (value == null) { - return defValue; - } - return StrokeJoin.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -BoxShape? parseBoxShape(String? value, [BoxShape? defValue]) { - if (value == null) { - return defValue; - } - return BoxShape.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -NotchedShape? parseNotchedShape(String? value, [NotchedShape? defValue]) { - if (value == null) { - return defValue; - } else if (value == "circular") { - return const CircularNotchedRectangle(); - } else if (value == "auto") { - return const AutomaticNotchedShape(ContinuousRectangleBorder()); - } else { - return defValue; - } -} - -SliderInteraction? parseSliderInteraction(String? value, - [SliderInteraction? defValue]) { - if (value == null) { - return defValue; - } - return SliderInteraction.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -Size? parseSize(Control control, String propName, [Size? defValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defValue; - } - - final j1 = json.decode(v); - return sizeFromJson(j1, defValue); -} - -Size? sizeFromJson(Map? json, [Size? defValue]) { - if (json == null) return defValue; - - final width = parseDouble(json['width']); - final height = parseDouble(json['height']); - - if (width == null || height == null) return defValue; - - return Size(width, height); -} - -SnackBarBehavior? parseSnackBarBehavior(String? value, - [SnackBarBehavior? defValue]) { - if (value == null) { - return defValue; - } - return SnackBarBehavior.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -StackFit? parseStackFit(String? value, [StackFit? defValue]) { - if (value == null) { - return defValue; - } - return StackFit.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -DatePickerMode? parseDatePickerMode(String? value, [DatePickerMode? defValue]) { - if (value == null) { - return defValue; - } - return DatePickerMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -DatePickerEntryMode? parseDatePickerEntryMode(String? value, - [DatePickerEntryMode? defValue]) { - if (value == null) { - return defValue; - } - return DatePickerEntryMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -enum CardVariant { elevated, filled, outlined } - -CardVariant? parseCardVariant(String? value, [CardVariant? defValue]) { - if (value == null) { - return defValue; - } - return CardVariant.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -enum ScrollMode { none, auto, adaptive, always, hidden } - -ScrollMode? parseScrollMode(String? value, [ScrollMode? defValue]) { - if (value == null) { - return defValue; - } - return ScrollMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -enum LabelPosition { right, left } - -LabelPosition? parseLabelPosition(String? value, [LabelPosition? defValue]) { - if (value == null) { - return defValue; - } - return LabelPosition.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -CupertinoTimerPickerMode? parseCupertinoTimerPickerMode(String? value, - [CupertinoTimerPickerMode? defValue]) { - if (value == null) { - return defValue; - } - return CupertinoTimerPickerMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -ListTileControlAffinity? parseListTileControlAffinity(String? value, - [ListTileControlAffinity? defValue]) { - if (value == null) { - return defValue; - } - return ListTileControlAffinity.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -ListTileStyle? parseListTileStyle(String? value, [ListTileStyle? defValue]) { - if (value == null) { - return defValue; - } - return ListTileStyle.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -NavigationDestinationLabelBehavior? parseNavigationDestinationLabelBehavior( - String? value, - [NavigationDestinationLabelBehavior? defValue]) { - if (value == null) { - return defValue; - } - return NavigationDestinationLabelBehavior.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -PopupMenuPosition? parsePopupMenuPosition(String? value, - [PopupMenuPosition? defValue]) { - if (value == null) { - return defValue; - } - return PopupMenuPosition.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -Assertiveness? parseAssertiveness(String? value, [Assertiveness? defValue]) { - if (value == null) { - return defValue; - } - return Assertiveness.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -DatePickerDateOrder? parseDatePickerDateOrder(String? value, - [DatePickerDateOrder? defValue]) { - if (value == null) { - return defValue; - } - return DatePickerDateOrder.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -CupertinoDatePickerMode? parseCupertinoDatePickerMode(String? value, - [CupertinoDatePickerMode? defValue]) { - if (value == null) { - return defValue; - } - return CupertinoDatePickerMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -ListTileTitleAlignment? parseListTileTitleAlignment(String? value, - [ListTileTitleAlignment? defValue]) { - if (value == null) { - return defValue; - } - return ListTileTitleAlignment.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -TimePickerEntryMode? parseTimePickerEntryMode(String? value, - [TimePickerEntryMode? defValue]) { - if (value == null) { - return defValue; - } - return TimePickerEntryMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -Axis? parseAxis(String? value, [Axis? defValue]) { - if (value == null) { - return defValue; - } - return Axis.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} - -PointerDeviceKind? parsePointerDeviceKind(String? value, - [PointerDeviceKind? defValue]) { - if (value == null) { - return defValue; - } - return PointerDeviceKind.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; -} diff --git a/packages/flet/lib/src/utils/overlay_style.dart b/packages/flet/lib/src/utils/overlay_style.dart index b0ec38f0d2..be4c063b4d 100644 --- a/packages/flet/lib/src/utils/overlay_style.dart +++ b/packages/flet/lib/src/utils/overlay_style.dart @@ -1,12 +1,15 @@ -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import '../models/control.dart'; import '../utils/numbers.dart'; +import '../utils/theme.dart'; import 'colors.dart'; -SystemUiOverlayStyle overlayStyleFromJson( - ThemeData? theme, Map json, Brightness? brightness) { +SystemUiOverlayStyle? parseSystemUiOverlayStyle( + dynamic value, ThemeData? theme, Brightness? brightness, + [SystemUiOverlayStyle? defaultValue]) { + if (value == null) return defaultValue; Brightness? invertedBrightness = brightness != null ? brightness == Brightness.light ? Brightness.dark @@ -14,28 +17,28 @@ SystemUiOverlayStyle overlayStyleFromJson( : null; return SystemUiOverlayStyle( - statusBarColor: parseColor(theme, json["status_bar_color"]), + statusBarColor: parseColor(value["status_bar_color"], theme), systemNavigationBarColor: - parseColor(theme, json["system_navigation_bar_color"]), + parseColor(value["system_navigation_bar_color"], theme), systemNavigationBarDividerColor: - parseColor(theme, json["system_navigation_bar_divider_color"]), + parseColor(value["system_navigation_bar_divider_color"], theme), systemStatusBarContrastEnforced: - parseBool(json["enforce_system_status_bar_contrast"]), + parseBool(value["enforce_system_status_bar_contrast"]), systemNavigationBarContrastEnforced: - parseBool(json["enforce_system_navigation_bar_contrast"]), + parseBool(value["enforce_system_navigation_bar_contrast"]), systemNavigationBarIconBrightness: parseBrightness( - json["system_navigation_bar_icon_brightness"], invertedBrightness), + value["system_navigation_bar_icon_brightness"], invertedBrightness), statusBarBrightness: - parseBrightness(json["status_bar_brightness"], brightness), + parseBrightness(value["status_bar_brightness"], brightness), statusBarIconBrightness: parseBrightness( - json["status_bar_icon_brightness"], invertedBrightness)); + value["status_bar_icon_brightness"], invertedBrightness)); } -Brightness? parseBrightness(String? value, [Brightness? defValue]) { - if (value == null) { - return defValue; +extension SystemUiParsers on Control { + SystemUiOverlayStyle? getSystemUiOverlayStyle( + String propertyName, ThemeData? theme, Brightness? brightness, + [SystemUiOverlayStyle? defaultValue]) { + return parseSystemUiOverlayStyle( + get(propertyName), theme, brightness, defaultValue); } - return Brightness.values - .firstWhereOrNull((e) => e.toString() == value.toLowerCase()) ?? - defValue; } diff --git a/packages/flet/lib/src/utils/platform.dart b/packages/flet/lib/src/utils/platform.dart index 0a5989461a..2ef9c8a2f1 100644 --- a/packages/flet/lib/src/utils/platform.dart +++ b/packages/flet/lib/src/utils/platform.dart @@ -1,4 +1,7 @@ import 'package:flutter/foundation.dart'; +import 'enums.dart'; + +import '../models/control.dart'; /// Checks if the current platform is a desktop platform. bool isDesktopPlatform() { @@ -8,23 +11,6 @@ bool isDesktopPlatform() { defaultTargetPlatform == TargetPlatform.linux); } -/// Checks if the current platform is a mobile (iOS or Android) platform. -bool isMobilePlatform() { - return !kIsWeb && - (defaultTargetPlatform == TargetPlatform.iOS || - defaultTargetPlatform == TargetPlatform.android); -} - -/// Checks if the current platform is iOS -bool isiOSPlatform() { - return !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS; -} - -/// Checks if the current platform is Android -bool isAndroidPlatform() { - return !kIsWeb && defaultTargetPlatform == TargetPlatform.android; -} - /// Checks if the current platform is Windows desktop. bool isWindowsDesktop() { return !kIsWeb && (defaultTargetPlatform == TargetPlatform.windows); @@ -40,7 +26,43 @@ bool isLinuxDesktop() { return !kIsWeb && (defaultTargetPlatform == TargetPlatform.linux); } +/// Checks if the current platform is a mobile (iOS or Android) platform. +bool isMobilePlatform() { + return !kIsWeb && + (defaultTargetPlatform == TargetPlatform.iOS || + defaultTargetPlatform == TargetPlatform.android); +} + +/// Checks if the current platform is iOS mobile. +bool isIOSMobile() { + return !kIsWeb && (defaultTargetPlatform == TargetPlatform.iOS); +} + +/// Checks if the current platform is Android mobile. +bool isAndroidMobile() { + return !kIsWeb && (defaultTargetPlatform == TargetPlatform.android); +} + +/// Checks if the current platform is an Apple platform (iOS or macOS). +bool isApplePlatform() { + return !kIsWeb && + (defaultTargetPlatform == TargetPlatform.iOS || + defaultTargetPlatform == TargetPlatform.macOS); +} + /// Checks if the current platform is a web platform. bool isWebPlatform() { return kIsWeb == true; } + +TargetPlatform? parseTargetPlatform(String? value, + [TargetPlatform? defaultValue]) { + return parseEnum(TargetPlatform.values, value, defaultValue); +} + +extension PlatformParsers on Control { + TargetPlatform? getTargetPlatform(String propertyName, + [TargetPlatform? defaultValue]) { + return parseTargetPlatform(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/platform_utils_non_web.dart b/packages/flet/lib/src/utils/platform_utils_non_web.dart index 873cde5eaf..a94f6a8ba4 100644 --- a/packages/flet/lib/src/utils/platform_utils_non_web.dart +++ b/packages/flet/lib/src/utils/platform_utils_non_web.dart @@ -5,7 +5,7 @@ bool isProgressiveWebApp() { } String getWebsocketEndpointPath(String uriPath) { - var pagePath = trim(uriPath, "/"); + var pagePath = uriPath.trimSymbol("/"); if (pagePath != "") { pagePath = "$pagePath/"; } @@ -16,9 +16,21 @@ String getFletRouteUrlStrategy() { return ""; } -bool isFletWebPyodideMode() { +String getAssetsDir() { + return ""; +} + +bool isPyodideMode() { + return false; +} + +bool isMultiView() { return false; } +Map getViewInitialData(int viewId) { + return {}; +} + void openPopupBrowserWindow( String url, String windowName, int minWidth, int minHeight) {} diff --git a/packages/flet/lib/src/utils/platform_utils_web.dart b/packages/flet/lib/src/utils/platform_utils_web.dart index 7ee905d3e5..295f933e28 100644 --- a/packages/flet/lib/src/utils/platform_utils_web.dart +++ b/packages/flet/lib/src/utils/platform_utils_web.dart @@ -1,43 +1,79 @@ // ignore: avoid_web_libraries_in_flutter -import 'dart:html' as html; +import 'dart:js_interop'; +import 'dart:ui_web'; + +import 'package:web/web.dart' as web; import 'strings.dart'; bool isProgressiveWebApp() { - return html.window.matchMedia('(display-mode: standalone)').matches || - html.window.matchMedia('(display-mode: fullscreen)').matches || - html.window.matchMedia('(display-mode: minimal-ui)').matches; + return web.window.matchMedia('(display-mode: standalone)').matches || + web.window.matchMedia('(display-mode: fullscreen)').matches || + web.window.matchMedia('(display-mode: minimal-ui)').matches; } String getWebsocketEndpointPath(String uriPath) { - var meta = html.document.head - ?.querySelector("meta[name='flet-websocket-endpoint-path']"); - return trim(meta?.attributes["content"] ?? "ws", "/"); + return fletJS?.webSocketEndpoint.trimSymbol("/") ?? "ws"; } String getFletRouteUrlStrategy() { - var meta = - html.document.head?.querySelector("meta[name='flet-route-url-strategy']"); - return meta != null ? meta.attributes["content"]! : ""; + return fletJS?.routeUrlStrategy ?? ""; +} + +String getAssetsDir() { + return fletJS?.assetsDir ?? ""; +} + +bool isPyodideMode() { + return fletJS?.pyodide == true; +} + +bool isMultiView() { + return fletJS?.multiView == true; } -bool isFletWebPyodideMode() { - var meta = html.document.head?.querySelector("meta[name='flet-web-pyodide']"); - return meta != null - ? meta.attributes["content"]?.toLowerCase() == "true" - : false; +String? getHeadMetaContent(String metaName) { + var meta = web.document.head?.querySelector("meta[name='$metaName']"); + return meta?.attributes.getNamedItem("content")?.value; } +Map getViewInitialData(int viewId) { + return (views.getInitialData(viewId)?.dartify() ?? {}) as Map; +} + +@JS() +@anonymous +@staticInterop +class FletJS { + external factory FletJS(); +} + +extension FletJSExtension on FletJS { + external bool get pyodide; + external bool get multiView; + external bool get noCdn; + external String get webSocketEndpoint; + external String get routeUrlStrategy; + external String get canvasKitBaseUrl; + external String get pyodideUrl; + external String get webRenderer; + external String? get appPackageUrl; + external String? get assetsDir; +} + +@JS('flet') +external FletJS? get fletJS; + void openPopupBrowserWindow( String url, String windowName, int width, int height) { - int screenWidth = html.window.screen!.width!; - int screenHeight = html.window.screen!.height!; - final dualScreenLeft = html.window.screenLeft! < 0 ? -screenWidth : 0; - var toolbarHeight = html.window.outerHeight - html.window.innerHeight!; + int screenWidth = web.window.screen.width; + int screenHeight = web.window.screen.height; + final dualScreenLeft = web.window.screenLeft < 0 ? -screenWidth : 0; + var toolbarHeight = web.window.outerHeight - web.window.innerHeight; //var width = max(minWidth, screenWidth - 300); //var height = max(minHeight, screenHeight - 300); var left = (screenWidth / 2) - (width / 2) + dualScreenLeft; var top = (screenHeight / 2) - (height / 2) - toolbarHeight; - html.window.open(url, windowName, + web.window.open(url, windowName, "top=$top,left=$left,width=$width,height=$height,scrollbars=yes"); } diff --git a/packages/flet/lib/src/utils/popup_menu.dart b/packages/flet/lib/src/utils/popup_menu.dart new file mode 100644 index 0000000000..94425f4da8 --- /dev/null +++ b/packages/flet/lib/src/utils/popup_menu.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +import '../extensions/control.dart'; +import '../models/control.dart'; +import 'edge_insets.dart'; +import 'mouse.dart'; +import 'numbers.dart'; +import 'text.dart'; + +/// Builds a list of [PopupMenuEntry] widgets from a collection of Flet controls. +/// +/// Only controls with type `PopupMenuItem` are converted. Controls without any +/// visible content are treated as menu dividers. +List> buildPopupMenuEntries( + Iterable items, BuildContext context) { + return items.where((item) => item.type == "PopupMenuItem").map((item) { + var checked = item.getBool("checked"); + var height = item.getDouble("height", 48.0)!; + var padding = item.getPadding("padding"); + var itemContent = item.buildTextOrWidget("content"); + var itemIcon = item.buildIconOrWidget("icon"); + var mouseCursor = item.getMouseCursor("mouse_cursor"); + var labelTextStyle = + item.getWidgetStateTextStyle("label_text_style", Theme.of(context)); + + Widget? child; + if (itemContent != null && itemIcon == null) { + child = itemContent; + } else if (itemContent == null && itemIcon != null) { + child = itemIcon; + } else if (itemContent != null && itemIcon != null) { + child = Row(children: [ + itemIcon, + const SizedBox(width: 8), + itemContent, + ]); + } + + var entry = checked != null + ? CheckedPopupMenuItem( + value: item.id.toString(), + checked: checked, + height: height, + padding: padding, + enabled: !item.disabled, + mouseCursor: mouseCursor, + labelTextStyle: labelTextStyle, + onTap: () => item.triggerEvent("click", !checked), + child: child, + ) + : PopupMenuItem( + value: item.id.toString(), + height: height, + padding: padding, + labelTextStyle: labelTextStyle, + enabled: !item.disabled, + mouseCursor: mouseCursor, + onTap: () => item.triggerEvent("click"), + child: child, + ); + + return child != null + ? entry + : const PopupMenuDivider() as PopupMenuEntry; + }).toList(); +} diff --git a/packages/flet/lib/src/utils/responsive.dart b/packages/flet/lib/src/utils/responsive.dart index bd442d13e4..18ff2a14d5 100644 --- a/packages/flet/lib/src/utils/responsive.dart +++ b/packages/flet/lib/src/utils/responsive.dart @@ -1,52 +1,56 @@ -import 'dart:convert'; - import '../models/control.dart'; import '../utils/numbers.dart'; -Map parseResponsiveNumber( - Control control, String propName, double defaultValue) { - var v = control.attrString(propName, null); +Map? parseResponsiveNumber(dynamic value, double defaultValue) { Map result = {}; - if (v != null) { - var j = json.decode(v); - if (j is! Map) { - j = {"": j}; + + if (value != null) { + if (value is Map) { + result = value.map( + (key, val) => MapEntry(key.toString(), parseDouble(val, 0)!), + ); + } else { + result[""] = parseDouble(value, 0)!; } - result = responsiveNumberFromJson(j); } + if (result[""] == null) { result[""] = defaultValue; } + return result; } -Map responsiveNumberFromJson(Map json) { - return json.map((key, value) => MapEntry(key, parseDouble(value, 0)!)); -} +double getBreakpointNumber( + Map value, double width, Map breakpoints) { + // Defaults + double? selectedValue = value[""]; + double highestMatchedBreakpoint = 0; -double getBreakpointNumber(Map responsiveNumber, double width, - Map breakpoints) { - // default value - double? result = responsiveNumber[""]; + for (final entry in value.entries) { + final bpName = entry.key; + final v = entry.value; - double maxBpWidth = 0; - responsiveNumber.forEach((bpName, respValue) { - if (bpName == "") { - return; - } - var bpWidth = breakpoints[bpName]; - if (bpWidth == null) { - throw Exception("Unknown breakpoint: $bpName"); - } - if (width >= bpWidth && bpWidth >= maxBpWidth) { - maxBpWidth = bpWidth; - result = respValue; + if (bpName.isEmpty) continue; + + final bpWidth = breakpoints[bpName]; + if (bpWidth == null) continue; + + if (width >= bpWidth && bpWidth >= highestMatchedBreakpoint) { + highestMatchedBreakpoint = bpWidth; + selectedValue = v; } - }); + } + + if (selectedValue == null) { + throw Exception("Responsive number not found for width=$width: $value"); + } + return selectedValue; +} - if (result == null) { - throw Exception( - "Responsive number not found for width=$width: $responsiveNumber"); +extension ResponsiveParsers on Control { + Map? getResponsiveNumber( + String propertyName, double defaultValue) { + return parseResponsiveNumber(get(propertyName), defaultValue); } - return result!; } diff --git a/packages/flet/lib/src/utils/scrollbar.dart b/packages/flet/lib/src/utils/scrollbar.dart new file mode 100644 index 0000000000..48a8a83bf9 --- /dev/null +++ b/packages/flet/lib/src/utils/scrollbar.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; + +import '../models/control.dart'; +import 'borders.dart'; +import 'enums.dart'; +import 'numbers.dart'; +import 'platform.dart'; + +enum ScrollMode { auto, adaptive, always, hidden } + +ScrollMode? parseScrollMode(String? value, [ScrollMode? defaultValue]) { + return parseEnum(ScrollMode.values, value, defaultValue); +} + +class ScrollbarConfiguration { + final bool? thumbVisibility; + final bool? trackVisibility; + final double? thickness; + final Radius? radius; + final bool? interactive; + final ScrollbarOrientation? orientation; + + const ScrollbarConfiguration({ + this.thumbVisibility, + this.trackVisibility, + this.thickness, + this.radius, + this.interactive, + this.orientation, + }); + + factory ScrollbarConfiguration.fromScrollMode(ScrollMode mode) { + final defaultThickness = isMobilePlatform() ? 4.0 : null; + + switch (mode) { + case ScrollMode.auto: + return ScrollbarConfiguration(thickness: defaultThickness); + case ScrollMode.adaptive: + return ScrollbarConfiguration( + thumbVisibility: !isMobilePlatform(), thickness: defaultThickness); + case ScrollMode.always: + return ScrollbarConfiguration( + thumbVisibility: true, thickness: defaultThickness); + case ScrollMode.hidden: + return const ScrollbarConfiguration(thickness: 0); + } + } +} + +ScrollbarOrientation? parseScrollbarOrientation(String? value, + [ScrollbarOrientation? defaultValue]) { + return parseEnum(ScrollbarOrientation.values, value, defaultValue); +} + +ScrollbarConfiguration? parseScrollbarConfiguration(dynamic value, + [ScrollbarConfiguration? defaultValue]) { + if (value == null) return defaultValue; + if (value is! Map) { + final mode = parseScrollMode(value); + return mode == null + ? defaultValue + : ScrollbarConfiguration.fromScrollMode(mode); + } + + final baseConfiguration = ScrollbarConfiguration.fromScrollMode( + parseScrollMode(value["mode"], ScrollMode.auto)!); + + return ScrollbarConfiguration( + thumbVisibility: + parseBool(value["thumb_visibility"], baseConfiguration.thumbVisibility), + trackVisibility: + parseBool(value["track_visibility"], baseConfiguration.trackVisibility), + thickness: parseDouble(value["thickness"], baseConfiguration.thickness), + radius: parseRadius(value["radius"], baseConfiguration.radius), + interactive: parseBool(value["interactive"], baseConfiguration.interactive), + orientation: parseScrollbarOrientation( + value["orientation"], baseConfiguration.orientation), + ); +} + +extension ScrollbarParsers on Control { + ScrollMode? getScrollMode(String propertyName, [ScrollMode? defaultValue]) { + return parseScrollMode(get(propertyName), defaultValue); + } + + ScrollbarConfiguration? getScrollbarConfiguration(String propertyName, + [ScrollbarConfiguration? defaultValue]) { + return parseScrollbarConfiguration(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/session_store_non_web.dart b/packages/flet/lib/src/utils/session_store_non_web.dart index ffbe51e34e..dc94cf9a5b 100644 --- a/packages/flet/lib/src/utils/session_store_non_web.dart +++ b/packages/flet/lib/src/utils/session_store_non_web.dart @@ -1,12 +1,14 @@ import 'package:flutter/foundation.dart'; class SessionStore { - static String? get sessionId { - return null; + static String? sessionId; + + static String? getSessionId() { + return get("sessionId"); } - static set sessionId(String? value) { - // nothing to do + static setSessionId(String? value) { + set("sessionId", value ?? ""); } static String? get(String name) { diff --git a/packages/flet/lib/src/utils/session_store_web.dart b/packages/flet/lib/src/utils/session_store_web.dart index d1624041fb..256172dbac 100644 --- a/packages/flet/lib/src/utils/session_store_web.dart +++ b/packages/flet/lib/src/utils/session_store_web.dart @@ -1,26 +1,24 @@ -// ignore: avoid_web_libraries_in_flutter -import 'dart:html' as html; - import 'package:flutter/foundation.dart'; +import 'package:web/web.dart' as web; const String _sessionIdKey = "_flet_session_id"; class SessionStore { - static String? get sessionId { + static String? getSessionId() { return get(_sessionIdKey); } - static set sessionId(String? value) { + static setSessionId(String? value) { set(_sessionIdKey, value ?? ""); } static String? get(String name) { debugPrint("Get session storage $name"); - return html.window.sessionStorage[name]; + return web.window.sessionStorage.getItem(name); } static void set(String name, String value) { debugPrint("Set session storage $name"); - html.window.sessionStorage[name] = value; + web.window.sessionStorage.setItem(name, value); } } diff --git a/packages/flet/lib/src/utils/strings.dart b/packages/flet/lib/src/utils/strings.dart index 14a46a5b5a..b847a008cd 100644 --- a/packages/flet/lib/src/utils/strings.dart +++ b/packages/flet/lib/src/utils/strings.dart @@ -1,33 +1,47 @@ import 'dart:convert'; -import '../models/control.dart'; - -List? parseStringList(Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; +extension StringExtension on String { + /// Trims the [symbol] from the start of the string. + String trimStart(String symbol) { + return startsWith(symbol) ? substring(symbol.length) : this; } - final jv = json.decode(v); - return (jv as List).map((c) => c as String).toList(); -} + /// Trims the [symbol] from the end of the string. + String trimEnd(String symbol) { + return endsWith(symbol) ? substring(0, length - symbol.length) : this; + } -String trimStart(String str, String symbol) { - if (str.startsWith(symbol)) { - return str.substring(symbol.length); - } else { - return str; + /// Trims the [symbol] from both the start and end of the string. + String trimSymbol(String symbol) { + return trimStart(symbol).trimEnd(symbol); } -} -String trimEnd(String str, String symbol) { - if (str.endsWith(symbol)) { - return str.substring(0, str.length - symbol.length); - } else { - return str; + /// Returns `true` if the string contains valid Base64-encoded data. + /// + /// The string is first cleaned by removing data URI prefixes + /// (using [stripBase64DataHeader]) if present, then validated by + /// attempting to decode it using [base64.decode]. + /// + /// If decoding succeeds, the string is considered valid Base64. + bool get isBase64 { + try { + base64.decode(stripBase64DataHeader()); + return true; + } catch (_) { + return false; + } } -} -String trim(String str, String symbol) { - return trimEnd(trimStart(str, symbol), symbol); + /// Removes a leading Base64 data URI header (e.g. `data:*;base64,`) + /// if present, and returns only the Base64 payload. + String stripBase64DataHeader() { + var s = this; + if (s.startsWith('data:')) { + final comma = s.indexOf(','); + if (comma != -1) { + return s.substring(comma + 1); + } + } + return s; + } } diff --git a/packages/flet/lib/src/utils/tabs.dart b/packages/flet/lib/src/utils/tabs.dart new file mode 100644 index 0000000000..eafd2b9e96 --- /dev/null +++ b/packages/flet/lib/src/utils/tabs.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'enums.dart'; + +import '../models/control.dart'; +import 'borders.dart'; +import 'edge_insets.dart'; + +TabBarIndicatorSize? parseTabBarIndicatorSize(String? value, + [TabBarIndicatorSize? defaultValue]) { + return parseEnum(TabBarIndicatorSize.values, value, defaultValue); +} + +TabIndicatorAnimation? parseTabIndicatorAnimation(String? value, + [TabIndicatorAnimation? defaultValue]) { + return parseEnum(TabIndicatorAnimation.values, value, defaultValue); +} + +UnderlineTabIndicator? parseUnderlineTabIndicator( + dynamic value, ThemeData theme, + [UnderlineTabIndicator? defaultValue]) { + if (value == null) return defaultValue; + return UnderlineTabIndicator( + insets: parseEdgeInsets(value['insets'], EdgeInsets.zero)!, + borderSide: parseBorderSide(value['border_side'], theme, + defaultValue: const BorderSide(width: 2.0, color: Colors.white))!, + borderRadius: parseBorderRadius(value['border_radius']), + ); +} + +extension TabParsers on Control { + TabBarIndicatorSize? getTabBarIndicatorSize(String propertyName, + [TabBarIndicatorSize? defaultValue]) { + return parseTabBarIndicatorSize(get(propertyName), defaultValue); + } + + TabIndicatorAnimation? getTabIndicatorAnimation(String propertyName, + [TabIndicatorAnimation? defaultValue]) { + return parseTabIndicatorAnimation(get(propertyName), defaultValue); + } + + UnderlineTabIndicator? getUnderlineTabIndicator( + String propertyName, ThemeData theme, + [UnderlineTabIndicator? defaultValue]) { + return parseUnderlineTabIndicator(get(propertyName), theme, defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/text.dart b/packages/flet/lib/src/utils/text.dart index 1bb494ab1a..bf0519f047 100644 --- a/packages/flet/lib/src/utils/text.dart +++ b/packages/flet/lib/src/utils/text.dart @@ -1,212 +1,140 @@ -import 'dart:convert'; +import 'dart:math'; -import 'package:collection/collection.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; -import '../models/control_tree_view_model.dart'; import '../utils/box.dart'; import '../utils/drawing.dart'; import '../utils/numbers.dart'; import 'colors.dart'; +import 'enums.dart'; import 'launch_url.dart'; -import 'material_state.dart'; +import 'widget_state.dart'; -TextStyle? getTextStyle(BuildContext context, String styleName) { +TextStyle? parseTextThemeStyle(String? styleName, BuildContext context) { var textTheme = Theme.of(context).textTheme; - switch (styleName.toLowerCase()) { - case "displaylarge": - return textTheme.displayLarge; - case "displaymedium": - return textTheme.displayMedium; - case "displaysmall": - return textTheme.displaySmall; - case "headlinelarge": - return textTheme.headlineLarge; - case "headlinemedium": - return textTheme.headlineMedium; - case "headlinesmall": - return textTheme.headlineSmall; - case "titlelarge": - return textTheme.titleLarge; - case "titlemedium": - return textTheme.titleMedium; - case "titlesmall": - return textTheme.titleSmall; - case "labellarge": - return textTheme.labelLarge; - case "labelmedium": - return textTheme.labelMedium; - case "labelsmall": - return textTheme.labelSmall; - case "bodylarge": - return textTheme.bodyLarge; - case "bodymedium": - return textTheme.bodyMedium; - case "bodysmall": - return textTheme.bodySmall; - } - return null; + final styles = { + "displaylarge": textTheme.displayLarge, + "displaymedium": textTheme.displayMedium, + "displaysmall": textTheme.displaySmall, + "headlinelarge": textTheme.headlineLarge, + "headlinemedium": textTheme.headlineMedium, + "headlinesmall": textTheme.headlineSmall, + "titlelarge": textTheme.titleLarge, + "titlemedium": textTheme.titleMedium, + "titlesmall": textTheme.titleSmall, + "labellarge": textTheme.labelLarge, + "labelmedium": textTheme.labelMedium, + "labelsmall": textTheme.labelSmall, + "bodylarge": textTheme.bodyLarge, + "bodymedium": textTheme.bodyMedium, + "bodysmall": textTheme.bodySmall, + }; + return styles[styleName?.toLowerCase()]; } -FontWeight? getFontWeight(String? weightName, [FontWeight? defaultWeight]) { - switch (weightName?.toLowerCase()) { - case "normal": - return FontWeight.normal; - case "bold": - return FontWeight.bold; - case "w100": - return FontWeight.w100; - case "w200": - return FontWeight.w200; - case "w300": - return FontWeight.w300; - case "w400": - return FontWeight.w400; - case "w500": - return FontWeight.w500; - case "w600": - return FontWeight.w600; - case "w700": - return FontWeight.w700; - case "w800": - return FontWeight.w800; - case "w900": - return FontWeight.w900; - default: - return defaultWeight; - } +FontWeight? parseFontWeight(String? weightName, [FontWeight? defaultWeight]) { + if (weightName == null) return defaultWeight; + final weights = { + "normal": FontWeight.normal, + "bold": FontWeight.bold, + "w100": FontWeight.w100, + "w200": FontWeight.w200, + "w300": FontWeight.w300, + "w400": FontWeight.w400, + "w500": FontWeight.w500, + "w600": FontWeight.w600, + "w700": FontWeight.w700, + "w800": FontWeight.w800, + "w900": FontWeight.w900, + }; + return weights[weightName.toLowerCase()] ?? defaultWeight; } -List parseTextSpans( - ThemeData theme, - ControlTreeViewModel viewModel, - bool parentDisabled, - void Function(String, String, String)? sendControlEvent) { - return viewModel.children - .map((c) => parseInlineSpan(theme, c, parentDisabled, sendControlEvent)) - .whereNotNull() +List parseTextSpans(List spans, ThemeData theme, + [void Function(Control, String, [dynamic eventData])? sendControlEvent]) { + return spans + .map((span) => parseInlineSpan(span, theme, sendControlEvent)) + .nonNulls .toList(); } -InlineSpan? parseInlineSpan( - ThemeData theme, - ControlTreeViewModel spanViewModel, - bool parentDisabled, - void Function(String, String, String)? sendControlEvent) { - if (spanViewModel.control.type == "textspan") { - bool disabled = spanViewModel.control.isDisabled || parentDisabled; - var onClick = spanViewModel.control.attrBool("onClick", false)!; - String url = spanViewModel.control.attrString("url", "")!; - String? urlTarget = spanViewModel.control.attrString("urlTarget"); - return TextSpan( - text: spanViewModel.control.attrString("text"), - style: parseTextStyle(theme, spanViewModel.control, "style"), - spellOut: spanViewModel.control.attrBool("spellOut"), - semanticsLabel: spanViewModel.control.attrString("semanticsLabel"), - children: parseTextSpans( - theme, spanViewModel, parentDisabled, sendControlEvent), - mouseCursor: onClick && !disabled && sendControlEvent != null - ? SystemMouseCursors.click - : null, - recognizer: - (onClick || url != "") && !disabled && sendControlEvent != null - ? (TapGestureRecognizer() - ..onTap = () { - debugPrint("TextSpan ${spanViewModel.control.id} clicked!"); - if (url != "") { - openWebBrowser(url, webWindowName: urlTarget); - } - if (onClick) { - sendControlEvent(spanViewModel.control.id, "click", ""); - } - }) - : null, - onEnter: spanViewModel.control.attrBool("onEnter", false)! && - !disabled && - sendControlEvent != null - ? (event) { - debugPrint("TextSpan ${spanViewModel.control.id} entered!"); - sendControlEvent(spanViewModel.control.id, "enter", ""); - } - : null, - onExit: spanViewModel.control.attrBool("onExit", false)! && - !disabled && - sendControlEvent != null - ? (event) { - debugPrint("TextSpan ${spanViewModel.control.id} exited!"); - sendControlEvent(spanViewModel.control.id, "exit", ""); - } - : null, - ); - } - return null; +TextSpan? parseInlineSpan(Control span, ThemeData theme, + [void Function(Control, String, [dynamic eventData])? sendControlEvent]) { + span.notifyParent = true; + var onClick = span.getBool("on_click", false)!; + var url = span.getUrl("url"); + + return TextSpan( + text: span.getString("text"), + style: parseTextStyle(span.get("style"), theme), + spellOut: span.getBool("spell_out"), + semanticsLabel: span.getString("semantics_label"), + children: parseTextSpans(span.children("spans"), theme, sendControlEvent), + mouseCursor: onClick && !span.disabled && sendControlEvent != null + ? SystemMouseCursors.click + : null, + recognizer: + (onClick || url != null) && !span.disabled && sendControlEvent != null + ? (TapGestureRecognizer() + ..onTap = () { + if (url != null) openWebBrowser(url); + if (onClick) sendControlEvent(span, "click"); + }) + : null, + onEnter: span.getBool("on_enter", false)! && + !span.disabled && + sendControlEvent != null + ? (event) => sendControlEvent(span, "enter") + : null, + onExit: span.getBool("on_exit", false)! && + !span.disabled && + sendControlEvent != null + ? (event) => sendControlEvent(span, "exit") + : null, + ); } TextAlign? parseTextAlign(String? value, [TextAlign? defaultValue]) { - if (value == null) { - return defaultValue; - } - return TextAlign.values.firstWhereOrNull( - (a) => a.name.toLowerCase() == value.toLowerCase()) ?? - defaultValue; + return parseEnum(TextAlign.values, value, defaultValue); } TextOverflow? parseTextOverflow(String? value, [TextOverflow? defaultValue]) { - if (value == null) { - return defaultValue; - } - return TextOverflow.values.firstWhereOrNull( - (a) => a.name.toLowerCase() == value.toLowerCase()) ?? - defaultValue; + return parseEnum(TextOverflow.values, value, defaultValue); +} + +TextDecorationStyle? parseTextDecorationStyle(String? value, + [TextDecorationStyle? defaultValue]) { + return parseEnum(TextDecorationStyle.values, value, defaultValue); } TextCapitalization? parseTextCapitalization(String? value, [TextCapitalization? defaultValue]) { - if (value == null) { - return defaultValue; - } - return TextCapitalization.values.firstWhereOrNull( - (a) => a.name.toLowerCase() == value.toLowerCase()) ?? - defaultValue; + return parseEnum(TextCapitalization.values, value, defaultValue); } TextBaseline? parseTextBaseline(String? value, [TextBaseline? defaultValue]) { - if (value == null) { - return defaultValue; - } - return TextBaseline.values.firstWhereOrNull( - (a) => a.name.toLowerCase() == value.toLowerCase()) ?? - defaultValue; + return parseEnum(TextBaseline.values, value, defaultValue); } -TextStyle? parseTextStyle(ThemeData theme, Control control, String propName) { - dynamic j; - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - j = json.decode(v); - return textStyleFromJson(theme, j); +TextAffinity? parseTextAffinity(String? value, [TextAffinity? defaultValue]) { + return parseEnum(TextAffinity.values, value, defaultValue); } -TextStyle? textStyleFromJson(ThemeData theme, Map? json) { - if (json == null) { - return null; - } - - var fontWeight = json["weight"]; - - List? variations; - if (fontWeight != null && fontWeight.startsWith("w")) { - variations = [ - FontVariation('wght', parseDouble(fontWeight.substring(1), 0)!) - ]; +List? parseFontVariations(dynamic fontWeight, + [List? defaultValue]) { + if (fontWeight != null && + fontWeight is String && + fontWeight.startsWith("w")) { + return [FontVariation('wght', parseDouble(fontWeight.substring(1), 0)!)]; } + return defaultValue; +} +List parseTextDecorations(dynamic decorationValue) { List decorations = []; - var decor = parseInt(json["decoration"], 0)!; + var decor = parseInt(decorationValue, 0)!; if (decor & 0x1 > 0) { decorations.add(TextDecoration.underline); } @@ -216,43 +144,139 @@ TextStyle? textStyleFromJson(ThemeData theme, Map? json) { if (decor & 0x4 > 0) { decorations.add(TextDecoration.lineThrough); } + return decorations; +} + +TextStyle? parseTextStyle(dynamic value, ThemeData theme, + [TextStyle? defaultValue]) { + if (value == null) return defaultValue; + + var fontWeight = value["weight"]; + List? variations = parseFontVariations(fontWeight); + List decorations = parseTextDecorations(value["decoration"]); return TextStyle( - fontSize: parseDouble(json["size"]), - fontWeight: getFontWeight(fontWeight), - fontStyle: parseBool(json["italic"], false)! ? FontStyle.italic : null, - fontFamily: json["font_family"], + fontSize: parseDouble(value["size"]), + fontWeight: parseFontWeight(fontWeight), + fontStyle: parseBool(value["italic"], false)! ? FontStyle.italic : null, + fontFamily: value["font_family"], + fontFamilyFallback: + parseList(value["font_family_fallback"], (e) => e.toString()), fontVariations: variations, - height: parseDouble(json["height"]), + height: parseDouble(value["height"]), decoration: decorations.isNotEmpty ? TextDecoration.combine(decorations) : null, - decorationStyle: json["decoration_style"] != null - ? TextDecorationStyle.values.firstWhereOrNull((v) => - v.name.toLowerCase() == json["decoration_style"].toLowerCase()) - : null, - decorationColor: parseColor(theme, json["decoration_color"]), - decorationThickness: parseDouble(json["decoration_thickness"]), - color: parseColor(theme, json["color"]), - backgroundColor: parseColor(theme, json["bgcolor"]), - shadows: json["shadow"] != null - ? boxShadowsFromJSON(theme, json["shadow"]) - : null, - foreground: json["foreground"] != null - ? paintFromJSON(theme, json["foreground"]) - : null, - letterSpacing: parseDouble(json['letter_spacing']), - overflow: parseTextOverflow(json['overflow']), - wordSpacing: parseDouble(json['word_spacing']), - textBaseline: parseTextBaseline(json['text_baseline']), + decorationStyle: parseTextDecorationStyle(value["decoration_style"]), + decorationColor: parseColor(value["decoration_color"], theme), + decorationThickness: parseDouble(value["decoration_thickness"]), + color: parseColor(value["color"], theme), + backgroundColor: parseColor(value["bgcolor"], theme), + shadows: parseBoxShadows(value["shadow"], theme), + foreground: parsePaint(value["foreground"], theme), + letterSpacing: parseDouble(value['letter_spacing']), + overflow: parseTextOverflow(value['overflow']), + wordSpacing: parseDouble(value['word_spacing']), + textBaseline: parseTextBaseline(value['text_baseline']), ); } WidgetStateProperty? parseWidgetStateTextStyle( - ThemeData theme, Control control, String propName) { - var v = control.attrString(propName); - if (v == null) { - return null; - } + dynamic value, ThemeData theme, + {TextStyle? defaultTextStyle, + WidgetStateProperty? defaultValue}) { + if (value == null) return defaultValue; return getWidgetStateProperty( - jsonDecode(v), (jv) => textStyleFromJson(theme, jv), null); + value, (jv) => parseTextStyle(jv, theme), defaultTextStyle); +} + +TextSelection? parseTextSelection( + dynamic value, { + int? minOffset, + int? maxOffset, + TextSelection? defaultValue, +}) { + if (value == null) return defaultValue; + + int baseOffset = parseInt(value['base_offset'], 0)!; + int extentOffset = parseInt(value['extent_offset'], 0)!; + + // Clamp values if limits are provided + if (minOffset != null) { + baseOffset = max(baseOffset, minOffset); + extentOffset = max(extentOffset, minOffset); + } + if (maxOffset != null) { + baseOffset = min(baseOffset, maxOffset); + extentOffset = min(extentOffset, maxOffset); + } + + return TextSelection( + baseOffset: baseOffset, + extentOffset: extentOffset, + affinity: parseTextAffinity(value['affinity'], TextAffinity.downstream)!, + isDirectional: parseBool(value['directional'], false)!, + ); +} + +extension TextParsers on Control { + TextStyle? getTextStyle(String propertyName, ThemeData theme, + [TextStyle? defaultValue]) { + return parseTextStyle(get(propertyName), theme, defaultValue); + } + + TextAlign? getTextAlign(String propertyName, [TextAlign? defaultValue]) { + return parseTextAlign(get(propertyName), defaultValue); + } + + TextOverflow? getTextOverflow(String propertyName, + [TextOverflow? defaultValue]) { + return parseTextOverflow(get(propertyName), defaultValue); + } + + TextDecorationStyle? getTextDecorationStyle(String propertyName, + [TextDecorationStyle? defaultValue]) { + return parseTextDecorationStyle(get(propertyName), defaultValue); + } + + TextCapitalization? getTextCapitalization(String propertyName, + [TextCapitalization? defaultValue]) { + return parseTextCapitalization(get(propertyName), defaultValue); + } + + TextBaseline? getTextBaseline(String propertyName, + [TextBaseline? defaultValue]) { + return parseTextBaseline(get(propertyName), defaultValue); + } + + TextAffinity? getTextAffinity(String propertyName, + [TextAffinity? defaultValue]) { + return parseTextAffinity(get(propertyName), defaultValue); + } + + TextSelection? getTextSelection( + String propertyName, { + int? minOffset, + int? maxOffset, + TextSelection? defaultValue, + }) { + return parseTextSelection(get(propertyName), + minOffset: minOffset, maxOffset: maxOffset, defaultValue: defaultValue); + } + + WidgetStateProperty? getWidgetStateTextStyle( + String propertyName, ThemeData theme, + {TextStyle? defaultTextStyle, + WidgetStateProperty? defaultValue}) { + return parseWidgetStateTextStyle(get(propertyName), theme, + defaultTextStyle: defaultTextStyle, defaultValue: defaultValue); + } +} + +extension TextSelectionExtension on TextSelection { + Map toMap() => { + "base_offset": baseOffset, + "extent_offset": extentOffset, + "affinity": affinity.name, + "directional": isDirectional, + }; } diff --git a/packages/flet/lib/src/utils/textfield.dart b/packages/flet/lib/src/utils/textfield.dart index 133faf5405..d0e764c69f 100644 --- a/packages/flet/lib/src/utils/textfield.dart +++ b/packages/flet/lib/src/utils/textfield.dart @@ -1,27 +1,14 @@ -import 'dart:convert'; - import 'package:flutter/services.dart'; import '../models/control.dart'; import '../utils/numbers.dart'; -FilteringTextInputFormatter? parseInputFilter( - Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return null; - } - - final j1 = json.decode(v); - return inputFilterFromJSON(j1); -} - -FilteringTextInputFormatter? inputFilterFromJSON(dynamic json) { - var regexString = json["regex_string"]?.toString(); - if (json == null || regexString == null) { - return null; - } - return CustomFilteringTextInputFormatter.fromJSON(json); +FilteringTextInputFormatter? parseInputFilter(dynamic value, + [FilteringTextInputFormatter? defaultValue]) { + if (value == null) return defaultValue; + var regexString = value["regex_string"]?.toString(); + if (regexString == null) return defaultValue; + return CustomFilteringTextInputFormatter.fromMap(value); } class CustomFilteringTextInputFormatter extends FilteringTextInputFormatter { @@ -31,20 +18,20 @@ class CustomFilteringTextInputFormatter extends FilteringTextInputFormatter { {bool allow = true, String replacementString = ""}) : super(_pattern, allow: allow, replacementString: replacementString); - // Factory constructor to create an instance from JSON - factory CustomFilteringTextInputFormatter.fromJSON( - Map json) { + // Factory constructor to create an instance from a map + factory CustomFilteringTextInputFormatter.fromMap( + Map value) { final pattern = RegExp( - json["regex_string"]?.toString() ?? "", - multiLine: parseBool(json["multiline"], false)!, - unicode: parseBool(json["unicode"], false)!, - caseSensitive: parseBool(json["case_sensitive"], true)!, - dotAll: parseBool(json["dot_all"], false)!, + value["regex_string"]?.toString() ?? "", + multiLine: parseBool(value["multiline"], false)!, + unicode: parseBool(value["unicode"], false)!, + caseSensitive: parseBool(value["case_sensitive"], true)!, + dotAll: parseBool(value["dot_all"], false)!, ); return CustomFilteringTextInputFormatter._(pattern, - allow: parseBool(json["allow"], true)!, - replacementString: json["replacement_string"]?.toString() ?? ""); + allow: parseBool(value["allow"], true)!, + replacementString: value["replacement_string"]?.toString() ?? ""); } @override @@ -57,3 +44,90 @@ class CustomFilteringTextInputFormatter extends FilteringTextInputFormatter { return oldValue; } } + +class TextCapitalizationFormatter extends TextInputFormatter { + final TextCapitalization capitalization; + + TextCapitalizationFormatter(this.capitalization); + + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + String text = ''; + + switch (capitalization) { + case TextCapitalization.words: + text = capitalizeFirstofEach(newValue.text); + break; + case TextCapitalization.sentences: + List sentences = newValue.text.split('.'); + for (int i = 0; i < sentences.length; i++) { + sentences[i] = inCaps(sentences[i]); + } + text = sentences.join('.'); + break; + case TextCapitalization.characters: + text = allInCaps(newValue.text); + break; + case TextCapitalization.none: + text = newValue.text; + break; + } + + return TextEditingValue( + text: text, + selection: newValue.selection, + ); + } + + /// 'Hello world' + static String inCaps(String text) { + if (text.isEmpty) { + return text; + } + String result = ''; + for (int i = 0; i < text.length; i++) { + if (text[i] != ' ') { + result += '${text[i].toUpperCase()}${text.substring(i + 1)}'; + break; + } else { + result += text[i]; + } + } + return result; + } + + /// 'HELLO WORLD' + static String allInCaps(String text) => text.toUpperCase(); + + /// 'Hello World' + static String capitalizeFirstofEach(String text) => text + .replaceAll(RegExp(' +'), ' ') + .split(" ") + .map((str) => inCaps(str)) + .join(" "); +} + +class CustomNumberFormatter extends TextInputFormatter { + final String pattern; + + CustomNumberFormatter(this.pattern); + + @override + TextEditingValue formatEditUpdate( + TextEditingValue oldValue, TextEditingValue newValue) { + final regExp = RegExp(pattern); + if (regExp.hasMatch(newValue.text)) { + return newValue; + } + // If newValue is invalid, keep the old value + return oldValue; + } +} + +extension InputFormatterParsers on Control { + FilteringTextInputFormatter? getTextInputFormatter(String propertyName, + [FilteringTextInputFormatter? defaultValue]) { + return parseInputFilter(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/theme.dart b/packages/flet/lib/src/utils/theme.dart index 5514035d8b..06b71e916e 100644 --- a/packages/flet/lib/src/utils/theme.dart +++ b/packages/flet/lib/src/utils/theme.dart @@ -1,30 +1,31 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:flet/src/utils/locale.dart'; -import 'package:flet/src/utils/others.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import '../flet_backend.dart'; import '../models/control.dart'; +import '../utils/tabs.dart'; +import '../utils/transforms.dart'; import 'alignment.dart'; +import 'animations.dart'; import 'borders.dart'; import 'box.dart'; import 'buttons.dart'; import 'colors.dart'; import 'dismissible.dart'; -import 'drawing.dart'; import 'edge_insets.dart'; +import 'enums.dart'; +import 'geometry.dart'; import 'icons.dart'; -import 'material_state.dart'; import 'menu.dart'; +import 'misc.dart'; import 'mouse.dart'; import 'numbers.dart'; import 'overlay_style.dart'; import 'text.dart'; import 'time.dart'; import 'tooltip.dart'; +import 'widget_state.dart'; class SystemUiOverlayStyleTheme extends ThemeExtension { @@ -32,1467 +33,1078 @@ class SystemUiOverlayStyleTheme SystemUiOverlayStyleTheme(this.systemUiOverlayStyle); @override - ThemeExtension copyWith() { + SystemUiOverlayStyleTheme copyWith() { return SystemUiOverlayStyleTheme(systemUiOverlayStyle); } @override - ThemeExtension lerp( - covariant ThemeExtension? other, double t) { - return this; + SystemUiOverlayStyleTheme lerp( + covariant SystemUiOverlayStyleTheme? other, double t) { + if (other is! SystemUiOverlayStyleTheme) { + return this; + } + return other; + } + + @override + bool operator ==(Object other) { + return systemUiOverlayStyle == + (other as SystemUiOverlayStyleTheme).systemUiOverlayStyle; } + + @override + int get hashCode => systemUiOverlayStyle.hashCode; } CupertinoThemeData parseCupertinoTheme( - Control control, String propName, Brightness? brightness, + dynamic value, BuildContext context, Brightness? brightness, {ThemeData? parentTheme}) { - var theme = parseTheme(control, propName, brightness); + var theme = parseTheme(value, context, brightness); var cupertinoTheme = MaterialBasedCupertinoThemeData(materialTheme: theme); return fixCupertinoTheme(cupertinoTheme, theme); } CupertinoThemeData fixCupertinoTheme( CupertinoThemeData cupertinoTheme, ThemeData theme) { - return cupertinoTheme.copyWith( + var r = cupertinoTheme.copyWith( applyThemeToAll: true, barBackgroundColor: theme.colorScheme.surface, textTheme: cupertinoTheme.textTheme.copyWith( navTitleTextStyle: cupertinoTheme.textTheme.navTitleTextStyle .copyWith(color: theme.colorScheme.onSurface))); + return r; } -ThemeMode? parseThemeMode(String? value, [ThemeMode? defValue]) { - if (value == null) { - return defValue; - } - return ThemeMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defValue; +Brightness? parseBrightness(String? value, [Brightness? defaultValue]) { + return parseEnum(Brightness.values, value, defaultValue); } -ThemeData parseTheme(Control control, String propName, Brightness? brightness, - {ThemeData? parentTheme}) { - dynamic j; - var v = control.attrString(propName); - if (v != null) { - j = json.decode(v); - } - return themeFromJson(j, brightness, parentTheme); +ThemeMode? parseThemeMode(String? value, [ThemeMode? defaultValue]) { + return parseEnum(ThemeMode.values, value, defaultValue); } -ThemeData themeFromJson(Map? json, Brightness? brightness, - ThemeData? parentTheme) { +ThemeData parseTheme( + dynamic value, BuildContext context, Brightness? brightness, + {ThemeData? parentTheme}) { ThemeData? theme = parentTheme; - var primarySwatch = parseColor(theme, json?["primary_swatch"]); - var colorSchemeSeed = parseColor(theme, json?["color_scheme_seed"]); - - if (colorSchemeSeed != null) { - primarySwatch = null; - } - - if (colorSchemeSeed == null && primarySwatch == null) { - colorSchemeSeed = Colors.blue; - } + var colorSchemeSeed = + parseColor(value?["color_scheme_seed"], theme) ?? Colors.blue; // create new theme theme ??= ThemeData( - primarySwatch: - primarySwatch != null ? primarySwatch as MaterialColor : null, - colorSchemeSeed: colorSchemeSeed, - fontFamily: json?["font_family"], - brightness: brightness, - useMaterial3: json?["use_material3"] ?? primarySwatch == null); + colorSchemeSeed: colorSchemeSeed, + fontFamily: value?["font_family"], + brightness: brightness, + useMaterial3: value?["use_material3"], + ); + + ColorScheme? colorScheme = parseColorScheme(value?["color_scheme"], theme); + DividerThemeData? dividerTheme = + parseDividerTheme(value?["divider_theme"], theme); theme = theme.copyWith( + extensions: { + SystemUiOverlayStyleTheme(value?["system_overlay_style"] != null + ? parseSystemUiOverlayStyle( + value?["system_overlay_style"], theme, brightness) + : null) + }, visualDensity: - parseVisualDensity(json?["visual_density"], theme.visualDensity)!, + parseVisualDensity(value?["visual_density"], theme.visualDensity)!, pageTransitionsTheme: parsePageTransitions( - json?["page_transitions"], theme.pageTransitionsTheme)!, - colorScheme: parseColorScheme(theme, json?["color_scheme"]), - textTheme: parseTextTheme(theme, theme.textTheme, json?["text_theme"]), + value?["page_transitions"], theme.pageTransitionsTheme)!, + colorScheme: colorScheme, + textTheme: parseTextTheme(value?["text_theme"], theme, theme.textTheme), primaryTextTheme: parseTextTheme( - theme, theme.primaryTextTheme, json?["primary_text_theme"]), - scrollbarTheme: parseScrollBarTheme(theme, json?["scrollbar_theme"]), - tabBarTheme: parseTabBarTheme(theme, json?["tabs_theme"]), - splashColor: parseColor(theme, json?["splash_color"]), - highlightColor: parseColor(theme, json?["highlight_color"]), - hoverColor: parseColor(theme, json?["hover_color"]), - focusColor: parseColor(theme, json?["focus_color"]), - unselectedWidgetColor: parseColor(theme, json?["unselected_control_color"]), - disabledColor: parseColor(theme, json?["disabled_color"]), - canvasColor: parseColor(theme, json?["canvas_color"]), - scaffoldBackgroundColor: parseColor(theme, json?["scaffold_bgcolor"]), - cardColor: parseColor(theme, json?["card_color"]), - dividerColor: parseColor(theme, json?["divider_color"]), - // TODO: deprecated in v0.27.0, and to be removed in v0.30.0 - dialogBackgroundColor: parseColor(theme, json?["dialog_bgcolor"]), - indicatorColor: parseColor(theme, json?["indicator_color"]), - hintColor: parseColor(theme, json?["hint_color"]), - shadowColor: parseColor(theme, json?["shadow_color"]), - secondaryHeaderColor: parseColor(theme, json?["secondary_header_color"]), - primaryColor: parseColor(theme, json?["primary_color"]), - primaryColorLight: parseColor(theme, json?["primary_color_light"]), - primaryColorDark: parseColor(theme, json?["primary_color_dark"]), - dialogTheme: parseDialogTheme(theme, json?["dialog_theme"]), - bottomSheetTheme: parseBottomSheetTheme(theme, json?["bottom_sheet_theme"]), - cardTheme: parseCardTheme(theme, json?["card_theme"]), - chipTheme: parseChipTheme(theme, json?["chip_theme"]), + value?["primary_text_theme"], theme, theme.primaryTextTheme), + scrollbarTheme: parseScrollBarTheme(value?["scrollbar_theme"], theme), + tabBarTheme: parseTabBarTheme(value?["tab_bar_theme"], theme), + splashColor: parseColor(value?["splash_color"], theme), + highlightColor: parseColor(value?["highlight_color"], theme), + hoverColor: parseColor(value?["hover_color"], theme), + focusColor: parseColor(value?["focus_color"], theme), + unselectedWidgetColor: + parseColor(value?["unselected_control_color"], theme), + disabledColor: parseColor(value?["disabled_color"], theme), + canvasColor: parseColor(value?["canvas_color"], theme), + scaffoldBackgroundColor: parseColor(value?["scaffold_bgcolor"], theme), + cardColor: parseColor(value?["card_bgcolor"], theme), + dividerColor: parseColor(value?["divider_color"], theme), + hintColor: parseColor(value?["hint_color"], theme), + shadowColor: colorScheme?.shadow, + secondaryHeaderColor: parseColor(value?["secondary_header_color"], theme), + dialogTheme: parseDialogTheme(value?["dialog_theme"], theme), + bottomSheetTheme: + parseBottomSheetTheme(value?["bottom_sheet_theme"], theme), + cardTheme: parseCardTheme(value?["card_theme"], theme), + chipTheme: parseChipTheme(value?["chip_theme"], theme), floatingActionButtonTheme: parseFloatingActionButtonTheme( - theme, json?["floating_action_button_theme"]), + value?["floating_action_button_theme"], theme), bottomAppBarTheme: - parseBottomAppBarTheme(theme, json?["bottom_app_bar_theme"]), - checkboxTheme: parseCheckboxTheme(theme, json?["checkbox_theme"]), - radioTheme: parseRadioTheme(theme, json?["radio_theme"]), - badgeTheme: parseBadgeTheme(theme, json?["badge_theme"]), - switchTheme: parseSwitchTheme(theme, json?["switch_theme"]), - dividerTheme: parseDividerTheme(theme, json?["divider_theme"]), - snackBarTheme: parseSnackBarTheme(theme, json?["snackbar_theme"]), - bannerTheme: parseBannerTheme(theme, json?["banner_theme"]), - datePickerTheme: parseDatePickerTheme(theme, json?["date_picker_theme"]), + parseBottomAppBarTheme(value?["bottom_app_bar_theme"], theme), + checkboxTheme: parseCheckboxTheme(value?["checkbox_theme"], theme), + radioTheme: parseRadioTheme(value?["radio_theme"], theme), + badgeTheme: parseBadgeTheme(value?["badge_theme"], theme), + switchTheme: parseSwitchTheme(value?["switch_theme"], context), + dividerTheme: dividerTheme, + snackBarTheme: parseSnackBarTheme(value?["snackbar_theme"], theme), + bannerTheme: parseBannerTheme(value?["banner_theme"], theme), + datePickerTheme: parseDatePickerTheme(value?["date_picker_theme"], theme), navigationRailTheme: - parseNavigationRailTheme(theme, json?["navigation_rail_theme"]), - appBarTheme: parseAppBarTheme(theme, json?["appbar_theme"]), - dropdownMenuTheme: - parseDropdownMenuTheme(theme, json?["dropdown_menu_theme"]), - listTileTheme: parseListTileTheme(theme, json?["list_tile_theme"]), - tooltipTheme: parseTooltipTheme(theme, json?["tooltip_theme"]), + parseNavigationRailTheme(value?["navigation_rail_theme"], theme), + appBarTheme: parseAppBarTheme(value?["appbar_theme"], theme), + dropdownMenuTheme: parseDropdownMenuTheme(value?["dropdown_theme"], theme), + listTileTheme: parseListTileTheme(value?["list_tile_theme"], theme), + tooltipTheme: parseTooltipTheme(value?["tooltip_theme"], context), expansionTileTheme: - parseExpansionTileTheme(theme, json?["expansion_tile_theme"]), - sliderTheme: parseSliderTheme(theme, json?["slider_theme"]), + parseExpansionTileTheme(value?["expansion_tile_theme"], theme), + sliderTheme: parseSliderTheme(value?["slider_theme"], theme), progressIndicatorTheme: - parseProgressIndicatorTheme(theme, json?["progress_indicator_theme"]), - popupMenuTheme: parsePopupMenuTheme(theme, json?["popup_menu_theme"]), - searchBarTheme: parseSearchBarTheme(theme, json?["search_bar_theme"]), - searchViewTheme: parseSearchViewTheme(theme, json?["search_view_theme"]), + parseProgressIndicatorTheme(value?["progress_indicator_theme"], theme), + popupMenuTheme: parsePopupMenuTheme(value?["popup_menu_theme"], theme), + searchBarTheme: parseSearchBarTheme(value?["search_bar_theme"], theme), + searchViewTheme: parseSearchViewTheme(value?["search_view_theme"], theme), navigationDrawerTheme: - parseNavigationDrawerTheme(theme, json?["navigation_drawer_theme"]), - navigationBarTheme: parseNavigationBarTheme( - theme, - json?["navigation_bar_theme"], - ), - dataTableTheme: parseDataTableTheme(theme, json?["data_table_theme"]), - buttonTheme: parseButtonTheme(theme, json?["button_theme"]), - elevatedButtonTheme: - parseElevatedButtonTheme(theme, json?["elevated_button_theme"]), + parseNavigationDrawerTheme(value?["navigation_drawer_theme"], theme), + navigationBarTheme: + parseNavigationBarTheme(value?["navigation_bar_theme"], theme), + dataTableTheme: parseDataTableTheme(value?["data_table_theme"], context), + elevatedButtonTheme: parseButtonTheme(value?["button_theme"], theme), outlinedButtonTheme: - parseOutlinedButtonTheme(theme, json?["outlined_button_theme"]), - textButtonTheme: parseTextButtonTheme(theme, json?["text_button_theme"]), + parseOutlinedButtonTheme(value?["outlined_button_theme"], theme), + textButtonTheme: parseTextButtonTheme(value?["text_button_theme"], theme), filledButtonTheme: - parseFilledButtonTheme(theme, json?["filled_button_theme"]), - iconButtonTheme: parseIconButtonTheme(theme, json?["icon_button_theme"]), + parseFilledButtonTheme(value?["filled_button_theme"], theme), + iconButtonTheme: parseIconButtonTheme(value?["icon_button_theme"], theme), segmentedButtonTheme: parseSegmentedButtonTheme( - theme, - json?["segmented_button_theme"], - ), - iconTheme: parseIconTheme(theme, json?["icon_theme"]), - timePickerTheme: parseTimePickerTheme(theme, json?["time_picker_theme"]), + value?["segmented_button_theme"], theme, context), + iconTheme: parseIconTheme(value?["icon_theme"], theme), + timePickerTheme: parseTimePickerTheme(value?["time_picker_theme"], theme), ); - var systemOverlayStyle = json?["system_overlay_style"] != null - ? overlayStyleFromJson(theme, json?["system_overlay_style"], brightness) - : null; - return theme.copyWith( - extensions: {SystemUiOverlayStyleTheme(systemOverlayStyle)}, cupertinoOverrideTheme: fixCupertinoTheme( MaterialBasedCupertinoThemeData(materialTheme: theme), theme)); } -ColorScheme? parseColorScheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +ColorScheme? parseColorScheme(Map? value, ThemeData theme, + [ColorScheme? defaultValue]) { + if (value == null) return defaultValue; return theme.colorScheme.copyWith( - primary: parseColor(theme, j["primary"]), - onPrimary: parseColor(theme, j["on_primary"]), - primaryContainer: parseColor(theme, j["primary_container"]), - onPrimaryContainer: parseColor(theme, j["on_primary_container"]), - secondary: parseColor(theme, j["secondary"]), - onSecondary: parseColor(theme, j["on_secondary"]), - secondaryContainer: parseColor(theme, j["secondary_container"]), - onSecondaryContainer: parseColor(theme, j["on_secondary_container"]), - tertiary: parseColor(theme, j["tertiary"]), - onTertiary: parseColor(theme, j["on_tertiary"]), - tertiaryContainer: parseColor(theme, j["tertiary_container"]), - onTertiaryContainer: parseColor(theme, j["on_tertiary_container"]), - error: parseColor(theme, j["error"]), - onError: parseColor(theme, j["on_error"]), - errorContainer: parseColor(theme, j["error_container"]), - onErrorContainer: parseColor(theme, j["on_error_container"]), - surface: parseColor(theme, j["surface"]), - onSurface: parseColor(theme, j["on_surface"]), - surfaceContainerHighest: parseColor(theme, j["surface_variant"]), - onSurfaceVariant: parseColor(theme, j["on_surface_variant"]), - outline: parseColor(theme, j["outline"]), - outlineVariant: parseColor(theme, j["outline_variant"]), - shadow: parseColor(theme, j["shadow"]), - scrim: parseColor(theme, j["scrim"]), - inverseSurface: parseColor(theme, j["inverse_surface"]), - onInverseSurface: parseColor(theme, j["on_inverse_surface"]), - inversePrimary: parseColor(theme, j["inverse_primary"]), - surfaceTint: parseColor(theme, j["surface_tint"]), - onPrimaryFixed: parseColor(theme, j["on_primary_fixed"]), - onSecondaryFixed: parseColor(theme, j["on_secondary_fixed"]), - onTertiaryFixed: parseColor(theme, j["on_tertiary_fixed"]), - onPrimaryFixedVariant: parseColor(theme, j["on_primary_fixed_variant"]), - onSecondaryFixedVariant: parseColor(theme, j["on_secondary_fixed_variant"]), - onTertiaryFixedVariant: parseColor(theme, j["on_tertiary_fixed_variant"]), - primaryFixed: parseColor(theme, j["primary_fixed"]), - secondaryFixed: parseColor(theme, j["secondary_fixed"]), - tertiaryFixed: parseColor(theme, j["tertiary_fixed"]), - primaryFixedDim: parseColor(theme, j["primary_fixed_dim"]), - secondaryFixedDim: parseColor(theme, j["secondary_fixed_dim"]), - surfaceBright: parseColor(theme, j["surface_bright"]), - surfaceContainer: parseColor(theme, j["surface_container"]), - surfaceContainerHigh: parseColor(theme, j["surface_container_high"]), - surfaceContainerLow: parseColor(theme, j["surface_container_low"]), - surfaceContainerLowest: parseColor(theme, j["surface_container_lowest"]), - surfaceDim: parseColor(theme, j["surface_dim"]), - tertiaryFixedDim: parseColor(theme, j["tertiary_fixed_dim"]), + primary: parseColor(value["primary"], theme), + onPrimary: parseColor(value["on_primary"], theme), + primaryContainer: parseColor(value["primary_container"], theme), + onPrimaryContainer: parseColor(value["on_primary_container"], theme), + secondary: parseColor(value["secondary"], theme), + onSecondary: parseColor(value["on_secondary"], theme), + secondaryContainer: parseColor(value["secondary_container"], theme), + onSecondaryContainer: parseColor(value["on_secondary_container"], theme), + tertiary: parseColor(value["tertiary"], theme), + onTertiary: parseColor(value["on_tertiary"], theme), + tertiaryContainer: parseColor(value["tertiary_container"], theme), + onTertiaryContainer: parseColor(value["on_tertiary_container"], theme), + error: parseColor(value["error"], theme), + onError: parseColor(value["on_error"], theme), + errorContainer: parseColor(value["error_container"], theme), + onErrorContainer: parseColor(value["on_error_container"], theme), + surface: parseColor(value["surface"], theme), + onSurface: parseColor(value["on_surface"], theme), + onSurfaceVariant: parseColor(value["on_surface_variant"], theme), + outline: parseColor(value["outline"], theme), + outlineVariant: parseColor(value["outline_variant"], theme), + shadow: parseColor(value["shadow"], theme), + scrim: parseColor(value["scrim"], theme), + inverseSurface: parseColor(value["inverse_surface"], theme), + onInverseSurface: parseColor(value["on_inverse_surface"], theme), + inversePrimary: parseColor(value["inverse_primary"], theme), + surfaceTint: parseColor(value["surface_tint"], theme), + onPrimaryFixed: parseColor(value["on_primary_fixed"], theme), + onSecondaryFixed: parseColor(value["on_secondary_fixed"], theme), + onTertiaryFixed: parseColor(value["on_tertiary_fixed"], theme), + onPrimaryFixedVariant: parseColor(value["on_primary_fixed_variant"], theme), + onSecondaryFixedVariant: + parseColor(value["on_secondary_fixed_variant"], theme), + onTertiaryFixedVariant: + parseColor(value["on_tertiary_fixed_variant"], theme), + primaryFixed: parseColor(value["primary_fixed"], theme), + secondaryFixed: parseColor(value["secondary_fixed"], theme), + tertiaryFixed: parseColor(value["tertiary_fixed"], theme), + primaryFixedDim: parseColor(value["primary_fixed_dim"], theme), + secondaryFixedDim: parseColor(value["secondary_fixed_dim"], theme), + surfaceBright: parseColor(value["surface_bright"], theme), + surfaceContainer: parseColor(value["surface_container"], theme), + surfaceContainerHigh: parseColor(value["surface_container_high"], theme), + surfaceContainerHighest: + parseColor(value["surface_container_highest"], theme), + surfaceContainerLow: parseColor(value["surface_container_low"], theme), + surfaceContainerLowest: + parseColor(value["surface_container_lowest"], theme), + surfaceDim: parseColor(value["surface_dim"], theme), + tertiaryFixedDim: parseColor(value["tertiary_fixed_dim"], theme), ); } TextTheme? parseTextTheme( - ThemeData theme, TextTheme textTheme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, TextTheme textTheme, + [TextTheme? defaultValue]) { + if (value == null) return defaultValue; return textTheme.copyWith( - bodyLarge: parseTextStyle("body_large"), - bodyMedium: parseTextStyle("body_medium"), - bodySmall: parseTextStyle("body_small"), - displayLarge: parseTextStyle("display_large"), - displayMedium: parseTextStyle("display_medium"), - displaySmall: parseTextStyle("display_small"), - headlineLarge: parseTextStyle("headline_large"), - headlineMedium: parseTextStyle("headline_medium"), - headlineSmall: parseTextStyle("headline_small"), - labelLarge: parseTextStyle("label_large"), - labelMedium: parseTextStyle("label_medium"), - labelSmall: parseTextStyle("label_small"), - titleLarge: parseTextStyle("title_large"), - titleMedium: parseTextStyle("title_medium"), - titleSmall: parseTextStyle("title_small"), + bodyLarge: parseTextStyle(value["body_large"], theme), + bodyMedium: parseTextStyle(value["body_medium"], theme), + bodySmall: parseTextStyle(value["body_small"], theme), + displayLarge: parseTextStyle(value["display_large"], theme), + displayMedium: parseTextStyle(value["display_medium"], theme), + displaySmall: parseTextStyle(value["display_small"], theme), + headlineLarge: parseTextStyle(value["headline_large"], theme), + headlineMedium: parseTextStyle(value["headline_medium"], theme), + headlineSmall: parseTextStyle(value["headline_small"], theme), + labelLarge: parseTextStyle(value["label_large"], theme), + labelMedium: parseTextStyle(value["label_medium"], theme), + labelSmall: parseTextStyle(value["label_small"], theme), + titleLarge: parseTextStyle(value["title_large"], theme), + titleMedium: parseTextStyle(value["title_medium"], theme), + titleSmall: parseTextStyle(value["title_small"], theme), ); } -ButtonThemeData? parseButtonTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - return theme.buttonTheme.copyWith( - buttonColor: parseColor(theme, j["button_color"]), - disabledColor: parseColor(theme, j["disabled_color"]), - hoverColor: parseColor(theme, j["hover_color"]), - focusColor: parseColor(theme, j["focus_color"]), - highlightColor: parseColor(theme, j["highlight_color"]), - splashColor: parseColor(theme, j["splash_color"]), - colorScheme: parseColorScheme(theme, j["color_scheme"]), - alignedDropdown: parseBool(j["aligned_dropdown"]), - height: parseDouble(j["height"]), - minWidth: parseDouble(j["min_width"]), - shape: outlinedBorderFromJSON(j["shape"]), - padding: edgeInsetsFromJson(j["padding"]), - ); -} - -ElevatedButtonThemeData? parseElevatedButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } +ElevatedButtonThemeData? parseButtonTheme( + Map? value, ThemeData theme, + [ElevatedButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; return ElevatedButtonThemeData( - style: ElevatedButton.styleFrom( - iconColor: parseColor(theme, j["icon_color"]), - foregroundColor: parseColor(theme, j["foreground_color"]), - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - disabledBackgroundColor: parseColor(theme, j["disabled_bgcolor"]), - disabledForegroundColor: parseColor(theme, j["disabled_foreground_color"]), - disabledIconColor: parseColor(theme, j["disabled_icon_color"]), - overlayColor: parseColor(theme, j["overlay_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - padding: edgeInsetsFromJson(j["padding"]), - enableFeedback: parseBool(j["enable_feedback"]), - disabledMouseCursor: parseMouseCursor(j["disabled_mouse_cursor"]), - enabledMouseCursor: parseMouseCursor(j["enabled_mouse_cursor"]), - shape: outlinedBorderFromJSON(j["shape"]), - textStyle: parseTextStyle("text_style"), - visualDensity: parseVisualDensity(j["visual_density"]), - side: borderSideFromJSON(theme, j["border_side"]), - animationDuration: durationFromJSON(j["animation_duration"]), - alignment: alignmentFromJson(j["alignment"]), - iconSize: parseDouble(j["icon_size"]), - fixedSize: sizeFromJson(j["fixed_size"]), - maximumSize: sizeFromJson(j["maximum_size"]), - minimumSize: sizeFromJson(j["minimum_size"]), - )); + style: parseButtonStyle(value["style"], theme)); } OutlinedButtonThemeData? parseOutlinedButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [OutlinedButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; return OutlinedButtonThemeData( - style: OutlinedButton.styleFrom( - iconColor: parseColor(theme, j["icon_color"]), - foregroundColor: parseColor(theme, j["foreground_color"]), - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - disabledBackgroundColor: parseColor(theme, j["disabled_bgcolor"]), - disabledForegroundColor: parseColor(theme, j["disabled_foreground_color"]), - disabledIconColor: parseColor(theme, j["disabled_icon_color"]), - overlayColor: parseColor(theme, j["overlay_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - padding: edgeInsetsFromJson(j["padding"]), - enableFeedback: parseBool(j["enable_feedback"]), - disabledMouseCursor: parseMouseCursor(j["disabled_mouse_cursor"]), - enabledMouseCursor: parseMouseCursor(j["enabled_mouse_cursor"]), - shape: outlinedBorderFromJSON(j["shape"]), - textStyle: parseTextStyle("text_style"), - visualDensity: parseVisualDensity(j["visual_density"]), - side: borderSideFromJSON(theme, j["border_side"]), - animationDuration: durationFromJSON(j["animation_duration"]), - alignment: alignmentFromJson(j["alignment"]), - iconSize: parseDouble(j["icon_size"]), - fixedSize: sizeFromJson(j["fixed_size"]), - maximumSize: sizeFromJson(j["maximum_size"]), - minimumSize: sizeFromJson(j["minimum_size"]), - )); + style: parseButtonStyle(value["style"], theme)); } TextButtonThemeData? parseTextButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [TextButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } - - return TextButtonThemeData( - style: TextButton.styleFrom( - iconColor: parseColor(theme, j["icon_color"]), - foregroundColor: parseColor(theme, j["foreground_color"]), - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - disabledBackgroundColor: parseColor(theme, j["disabled_bgcolor"]), - disabledForegroundColor: parseColor(theme, j["disabled_foreground_color"]), - disabledIconColor: parseColor(theme, j["disabled_icon_color"]), - overlayColor: parseColor(theme, j["overlay_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - padding: edgeInsetsFromJson(j["padding"]), - enableFeedback: parseBool(j["enable_feedback"]), - disabledMouseCursor: parseMouseCursor(j["disabled_mouse_cursor"]), - enabledMouseCursor: parseMouseCursor(j["enabled_mouse_cursor"]), - shape: outlinedBorderFromJSON(j["shape"]), - textStyle: parseTextStyle("text_style"), - visualDensity: parseVisualDensity(j["visual_density"]), - side: borderSideFromJSON(theme, j["border_side"]), - animationDuration: durationFromJSON(j["animation_duration"]), - alignment: alignmentFromJson(j["alignment"]), - iconSize: parseDouble(j["icon_size"]), - fixedSize: sizeFromJson(j["fixed_size"]), - maximumSize: sizeFromJson(j["maximum_size"]), - minimumSize: sizeFromJson(j["minimum_size"]), - )); + return TextButtonThemeData(style: parseButtonStyle(value["style"], theme)); } FilledButtonThemeData? parseFilledButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [FilledButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } - - return FilledButtonThemeData( - style: FilledButton.styleFrom( - iconColor: parseColor(theme, j["icon_color"]), - foregroundColor: parseColor(theme, j["foreground_color"]), - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - disabledBackgroundColor: parseColor(theme, j["disabled_bgcolor"]), - disabledForegroundColor: parseColor(theme, j["disabled_foreground_color"]), - disabledIconColor: parseColor(theme, j["disabled_icon_color"]), - overlayColor: parseColor(theme, j["overlay_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - padding: edgeInsetsFromJson(j["padding"]), - enableFeedback: parseBool(j["enable_feedback"]), - disabledMouseCursor: parseMouseCursor(j["disabled_mouse_cursor"]), - enabledMouseCursor: parseMouseCursor(j["enabled_mouse_cursor"]), - shape: outlinedBorderFromJSON(j["shape"]), - textStyle: parseTextStyle("text_style"), - visualDensity: parseVisualDensity(j["visual_density"]), - side: borderSideFromJSON(theme, j["border_side"]), - animationDuration: durationFromJSON(j["animation_duration"]), - alignment: alignmentFromJson(j["alignment"]), - iconSize: parseDouble(j["icon_size"]), - fixedSize: sizeFromJson(j["fixed_size"]), - maximumSize: sizeFromJson(j["maximum_size"]), - minimumSize: sizeFromJson(j["minimum_size"]), - )); + return FilledButtonThemeData(style: parseButtonStyle(value["style"], theme)); } IconButtonThemeData? parseIconButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [IconButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } - - return IconButtonThemeData( - style: IconButton.styleFrom( - foregroundColor: parseColor(theme, j["foreground_color"]), - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - disabledBackgroundColor: parseColor(theme, j["disabled_bgcolor"]), - disabledForegroundColor: parseColor(theme, j["disabled_foreground_color"]), - overlayColor: parseColor(theme, j["overlay_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - focusColor: parseColor(theme, j["focus_color"]), - highlightColor: parseColor(theme, j["highlight_color"]), - hoverColor: parseColor(theme, j["hover_color"]), - elevation: parseDouble(j["elevation"]), - padding: edgeInsetsFromJson(j["padding"]), - enableFeedback: parseBool(j["enable_feedback"]), - disabledMouseCursor: parseMouseCursor(j["disabled_mouse_cursor"]), - enabledMouseCursor: parseMouseCursor(j["enabled_mouse_cursor"]), - shape: outlinedBorderFromJSON(j["shape"]), - visualDensity: parseVisualDensity(j["visual_density"]), - side: borderSideFromJSON(theme, j["border_side"]), - animationDuration: durationFromJSON(j["animation_duration"]), - alignment: alignmentFromJson(j["alignment"]), - iconSize: parseDouble(j["icon_size"]), - fixedSize: sizeFromJson(j["fixed_size"]), - maximumSize: sizeFromJson(j["maximum_size"]), - minimumSize: sizeFromJson(j["minimum_size"]), - )); + return IconButtonThemeData(style: parseButtonStyle(value["style"], theme)); } DataTableThemeData? parseDataTableTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, BuildContext context, + [DataTableThemeData? defaultValue]) { + if (value == null) return defaultValue; + var theme = Theme.of(context); return theme.dataTableTheme.copyWith( - checkboxHorizontalMargin: parseDouble(j["checkbox_horizontal_margin"]), - columnSpacing: parseDouble(j["column_spacing"]), - dataRowMaxHeight: parseDouble(j["data_row_max_height"]), - dataRowMinHeight: parseDouble(j["data_row_min_height"]), - dataRowColor: getWidgetStateProperty( - j["data_row_color"], (jv) => parseColor(theme, jv as String)), - dataTextStyle: parseTextStyle("data_text_style"), - dividerThickness: parseDouble(j["divider_thickness"]), - horizontalMargin: parseDouble(j["horizontal_margin"]), - headingTextStyle: parseTextStyle("heading_text_style"), - headingRowColor: getWidgetStateProperty( - j["heading_row_color"], (jv) => parseColor(theme, jv as String)), - headingRowHeight: parseDouble(j["heading_row_height"]), - dataRowCursor: getWidgetStateProperty( - j["data_row_cursor"], (jv) => parseMouseCursor(jv)), - decoration: boxDecorationFromJSON(theme, j["decoration"], null), - // TODO: replace null with a proper PageArgsModel - headingRowAlignment: parseMainAxisAlignment(j["heading_row_alignment"]), - headingCellCursor: getWidgetStateProperty( - j["heading_cell_cursor"], (jv) => parseMouseCursor(jv)), + checkboxHorizontalMargin: parseDouble(value["checkbox_horizontal_margin"]), + columnSpacing: parseDouble(value["column_spacing"]), + dataRowMaxHeight: parseDouble(value["data_row_max_height"]), + dataRowMinHeight: parseDouble(value["data_row_min_height"]), + dataRowColor: parseWidgetStateColor(value["data_row_color"], theme), + dataTextStyle: parseTextStyle(value["data_text_style"], theme), + dividerThickness: parseDouble(value["divider_thickness"]), + horizontalMargin: parseDouble(value["horizontal_margin"]), + headingTextStyle: parseTextStyle(value["heading_text_style"], theme), + headingRowColor: parseWidgetStateColor(value["heading_row_color"], theme), + headingRowHeight: parseDouble(value["heading_row_height"]), + dataRowCursor: parseWidgetStateMouseCursor(value["data_row_cursor"]), + decoration: parseBoxDecoration(value["decoration"], context), + headingRowAlignment: parseMainAxisAlignment(value["heading_row_alignment"]), + headingCellCursor: + parseWidgetStateMouseCursor(value["heading_cell_cursor"]), ); } ScrollbarThemeData? parseScrollBarTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [ScrollbarThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.scrollbarTheme.copyWith( - trackVisibility: getWidgetStateProperty( - j["track_visibility"], (jv) => parseBool(jv)), - trackColor: getWidgetStateProperty( - j["track_color"], (jv) => parseColor(theme, jv as String)), - trackBorderColor: getWidgetStateProperty( - j["track_border_color"], (jv) => parseColor(theme, jv as String)), - thumbVisibility: getWidgetStateProperty( - j["thumb_visibility"], (jv) => parseBool(jv)), - thumbColor: getWidgetStateProperty( - j["thumb_color"], (jv) => parseColor(theme, jv as String)), - thickness: getWidgetStateProperty( - j["thickness"], (jv) => parseDouble(jv, 0)!), - radius: j["radius"] != null - ? Radius.circular(parseDouble(j["radius"], 0)!) - : null, - crossAxisMargin: parseDouble(j["cross_axis_margin"]), - mainAxisMargin: parseDouble(j["main_axis_margin"]), - minThumbLength: parseDouble(j["min_thumb_length"]), - interactive: parseBool(j["interactive"]), + trackVisibility: parseWidgetStateBool(value["track_visibility"]), + trackColor: parseWidgetStateColor(value["track_color"], theme), + trackBorderColor: parseWidgetStateColor(value["track_border_color"], theme), + thumbVisibility: parseWidgetStateBool(value["thumb_visibility"]), + thumbColor: parseWidgetStateColor(value["thumb_color"], theme), + thickness: parseWidgetStateDouble(value["thickness"]), + radius: parseRadius(value["radius"]), + crossAxisMargin: parseDouble(value["cross_axis_margin"]), + mainAxisMargin: parseDouble(value["main_axis_margin"]), + minThumbLength: parseDouble(value["min_thumb_length"]), + interactive: parseBool(value["interactive"]), ); } -TabBarThemeData? parseTabBarTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +TabBarThemeData? parseTabBarTheme(Map? value, ThemeData theme, + [TabBarThemeData? defaultValue]) { + if (value == null) return defaultValue; - var indicatorColor = parseColor(theme, j["indicator_color"]); + var indicatorColor = + parseColor(value["indicator_color"], theme, theme.colorScheme.primary)!; return theme.tabBarTheme.copyWith( - overlayColor: getWidgetStateProperty( - j["overlay_color"], (jv) => parseColor(theme, jv as String)), - dividerColor: parseColor(theme, j["divider_color"]), - indicatorColor: indicatorColor, - labelColor: parseColor(theme, j["label_color"]), - unselectedLabelColor: parseColor(theme, j["unselected_label_color"]), - indicatorSize: parseBool(j["indicator_tab_size"], false)! - ? TabBarIndicatorSize.tab - : TabBarIndicatorSize.label, - indicator: j["indicator_border_radius"] != null || - j["indicator_border_side"] != null || - j["indicator_padding"] != null - ? UnderlineTabIndicator( - borderRadius: borderRadiusFromJSON( - j["indicator_border_radius"], - const BorderRadius.only( - topLeft: Radius.circular(2), - topRight: Radius.circular(2)))!, - borderSide: borderSideFromJSON( - theme, j["indicator_border_side"], indicatorColor) ?? - BorderSide( - width: 2.0, - color: indicatorColor ?? theme.colorScheme.primary), - insets: - edgeInsetsFromJson(j["indicator_padding"]) ?? EdgeInsets.zero) - : null, - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), - labelPadding: edgeInsetsFromJson(j["label_padding"]), - dividerHeight: parseDouble(j["divider_height"]), - labelStyle: j["label_text_style"] != null - ? textStyleFromJson(theme, j["label_text_style"]) - : null, - unselectedLabelStyle: j["unselected_label_text_style"] != null - ? textStyleFromJson(theme, j["unselected_label_text_style"]) - : null, - ); + indicatorSize: parseTabBarIndicatorSize(value["indicator_size"]), + indicator: parseUnderlineTabIndicator(value["indicator"], theme), + indicatorAnimation: + parseTabIndicatorAnimation(value["indicator_animation"]), + splashBorderRadius: parseBorderRadius(value["splash_border_radius"]), + tabAlignment: parseTabAlignment(value["tab_alignment"]), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme), + dividerColor: parseColor(value["divider_color"], theme), + indicatorColor: indicatorColor, + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + dividerHeight: parseDouble(value["divider_height"]), + labelColor: parseColor(value["label_color"], theme), + unselectedLabelColor: parseColor(value["unselected_label_color"], theme), + labelPadding: parsePadding(value["label_padding"]), + labelStyle: parseTextStyle(value["label_text_style"], theme), + unselectedLabelStyle: + parseTextStyle(value["unselected_label_text_style"], theme)); } -VisualDensity? parseVisualDensity(String? density, [VisualDensity? defValue]) { - switch (density?.toLowerCase()) { - case "adaptiveplatformdensity": - return VisualDensity.adaptivePlatformDensity; - case "comfortable": - return VisualDensity.comfortable; - case "compact": - return VisualDensity.compact; - case "standard": - return VisualDensity.standard; - default: - return defValue; - } +VisualDensity? parseVisualDensity(String? density, + [VisualDensity? defaultValue]) { + final visualDensityMap = { + "adaptiveplatformdensity": VisualDensity.adaptivePlatformDensity, + "comfortable": VisualDensity.comfortable, + "compact": VisualDensity.compact, + "standard": VisualDensity.standard, + }; + + return visualDensityMap[density?.toLowerCase()] ?? defaultValue; } -PageTransitionsTheme? parsePageTransitions(Map? json, - [PageTransitionsTheme? defValue]) { - if (json == null) { - return defValue; +PageTransitionsTheme? parsePageTransitions(Map? value, + [PageTransitionsTheme? defaultValue]) { + if (value == null) { + return defaultValue; } return PageTransitionsTheme(builders: { TargetPlatform.android: parseTransitionsBuilder( - json["android"], const FadeUpwardsPageTransitionsBuilder()), + value["android"], const FadeUpwardsPageTransitionsBuilder())!, TargetPlatform.iOS: parseTransitionsBuilder( - json["ios"], const CupertinoPageTransitionsBuilder()), + value["ios"], const CupertinoPageTransitionsBuilder())!, TargetPlatform.linux: parseTransitionsBuilder( - json["linux"], const ZoomPageTransitionsBuilder()), + value["linux"], const ZoomPageTransitionsBuilder())!, TargetPlatform.macOS: parseTransitionsBuilder( - json["macos"], const ZoomPageTransitionsBuilder()), + value["macos"], const ZoomPageTransitionsBuilder())!, TargetPlatform.windows: parseTransitionsBuilder( - json["windows"], const ZoomPageTransitionsBuilder()), + value["windows"], const ZoomPageTransitionsBuilder())!, }); } -DialogThemeData? parseDialogTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } +DialogThemeData? parseDialogTheme(Map? value, ThemeData theme, + [DialogThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.dialogTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - iconColor: parseColor(theme, j["icon_color"]), - elevation: parseDouble(j["elevation"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - titleTextStyle: parseTextStyle("title_text_style"), - contentTextStyle: parseTextStyle("content_text_style"), - alignment: alignmentFromJson(j["alignment"]), - actionsPadding: edgeInsetsFromJson(j["actions_padding"]), - clipBehavior: parseClip(j["clip_behavior"]), - barrierColor: parseColor(theme, j["barrier_color"]), - insetPadding: edgeInsetsFromJson(j["inset_padding"]), + backgroundColor: parseColor(value["bgcolor"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + iconColor: parseColor(value["icon_color"], theme), + elevation: parseDouble(value["elevation"]), + shape: parseShape(value["shape"], theme), + titleTextStyle: parseTextStyle(value["title_text_style"], theme), + contentTextStyle: parseTextStyle(value["content_text_style"], theme), + alignment: parseAlignment(value["alignment"]), + actionsPadding: parsePadding(value["actions_padding"]), + clipBehavior: parseClip(value["clip_behavior"]), + barrierColor: parseColor(value["barrier_color"], theme), + insetPadding: parsePadding(value["inset_padding"]), ); } BottomSheetThemeData? parseBottomSheetTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [BottomSheetThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.bottomSheetTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - dragHandleColor: parseColor(theme, j["drag_handle_color"]), - elevation: parseDouble(j["elevation"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - showDragHandle: parseBool(j["show_drag_handle"]), - modalBackgroundColor: parseColor(theme, j["modal_bgcolor"]), - modalElevation: parseDouble(j["modal_elevation"]), - clipBehavior: parseClip(j["clip_behavior"]), - constraints: boxConstraintsFromJSON(j["size_constraints"]), - modalBarrierColor: parseColor(theme, j["modal_barrier_color"]), + backgroundColor: parseColor(value["bgcolor"], theme), + modalBackgroundColor: parseColor(value["bgcolor"], theme), + shape: parseShape(value["shape"], theme), + showDragHandle: parseBool(value["show_drag_handle"]), + clipBehavior: parseClip(value["clip_behavior"]), + constraints: parseBoxConstraints(value["size_constraints"]), + modalBarrierColor: parseColor(value["barrier_color"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + dragHandleColor: parseColor(value["drag_handle_color"], theme), + modalElevation: parseDouble(value["elevation"]), + // elevation: parseDouble(value["elevation"]), ); } -CardThemeData? parseCardTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +CardThemeData? parseCardTheme(Map? value, ThemeData theme, + [CardThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.cardTheme.copyWith( - color: parseColor(theme, j["color"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - clipBehavior: parseClip(j["clip_behavior"]), - margin: edgeInsetsFromJson(j["margin"])); + color: parseColor(value["color"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + elevation: parseDouble(value["elevation"]), + shape: parseShape(value["shape"], theme), + clipBehavior: parseClip(value["clip_behavior"]), + margin: parseMargin(value["margin"])); } -ChipThemeData? parseChipTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } +ChipThemeData? parseChipTheme(Map? value, ThemeData theme, + [ChipThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.chipTheme.copyWith( - color: getWidgetStateProperty( - j["color"], (jv) => parseColor(theme, jv as String)), - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - padding: edgeInsetsFromJson(j["padding"]), - labelPadding: edgeInsetsFromJson(j["label_padding"]), - labelStyle: parseTextStyle("label_text_style"), - secondaryLabelStyle: parseTextStyle("secondary_label_text_style"), - disabledColor: parseColor(theme, j["disabled_color"]), - selectedColor: parseColor(theme, j["selected_color"]), - checkmarkColor: parseColor(theme, j["check_color"]), - deleteIconColor: parseColor(theme, j["delete_icon_color"]), - side: j["border_side"] != null - ? borderSideFromJSON(theme, j["border_side"], null) - : null, - secondarySelectedColor: parseColor(theme, j["secondary_selected_color"]), - brightness: j["brightness"] != null - ? Brightness.values.firstWhereOrNull( - (b) => b.name.toLowerCase() == j["brightness"].toLowerCase()) - : null, - selectedShadowColor: parseColor(theme, j["selected_shadow_color"]), - showCheckmark: parseBool(j["show_checkmark"]), - pressElevation: parseDouble(j["click_elevation"]), - avatarBoxConstraints: boxConstraintsFromJSON(j["avatar_constraints"]), + color: parseWidgetStateColor(value["color"], theme), + backgroundColor: parseColor(value["bgcolor"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + elevation: parseDouble(value["elevation"]), + shape: parseShape(value["shape"], theme), + padding: parsePadding(value["padding"]), + labelPadding: parsePadding(value["label_padding"]), + labelStyle: parseTextStyle(value["label_text_style"], theme), + disabledColor: parseColor(value["disabled_color"], theme), + selectedColor: parseColor(value["selected_color"], theme), + checkmarkColor: parseColor(value["check_color"], theme), + deleteIconColor: parseColor(value["delete_icon_color"], theme), + side: parseBorderSide(value["border_side"], theme), + brightness: parseBrightness(value["brightness"]), + selectedShadowColor: parseColor(value["selected_shadow_color"], theme), + showCheckmark: parseBool(value["show_checkmark"]), + pressElevation: parseDouble(value["elevation_on_click"]), + avatarBoxConstraints: + parseBoxConstraints(value["leading_size_constraints"]), deleteIconBoxConstraints: - boxConstraintsFromJSON(j["delete_icon_size_constraints"]), + parseBoxConstraints(value["delete_icon_size_constraints"]), + // below props are for [ChoiceChip], which is not supported yet + // secondaryLabelStyle: + // parseTextStyle(value["secondary_label_text_style"], theme), + // secondarySelectedColor: + // parseColor(value["secondary_selected_color"], theme), ); } FloatingActionButtonThemeData? parseFloatingActionButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [FloatingActionButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.floatingActionButtonTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - hoverColor: parseColor(theme, j["hover_color"]), - focusColor: parseColor(theme, j["focus_color"]), - foregroundColor: parseColor(theme, j["foreground_color"]), - splashColor: parseColor(theme, j["splash_color"]), - elevation: parseDouble(j["elevation"]), - focusElevation: parseDouble(j["focus_elevation"]), - hoverElevation: parseDouble(j["hover_elevation"]), - highlightElevation: parseDouble(j["highlight_elevation"]), - disabledElevation: parseDouble(j["disabled_elevation"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - enableFeedback: parseBool(j["enable_feedback"]), - extendedPadding: edgeInsetsFromJson(j["extended_padding"]), - extendedTextStyle: parseTextStyle("extended_text_style"), - extendedIconLabelSpacing: parseDouble(j["extended_icon_label_spacing"]), - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), - iconSize: parseDouble(j["icon_size"]), + backgroundColor: parseColor(value["bgcolor"], theme), + hoverColor: parseColor(value["hover_color"], theme), + focusColor: parseColor(value["focus_color"], theme), + foregroundColor: parseColor(value["foreground_color"], theme), + splashColor: parseColor(value["splash_color"], theme), + elevation: parseDouble(value["elevation"]), + focusElevation: parseDouble(value["focus_elevation"]), + hoverElevation: parseDouble(value["hover_elevation"]), + highlightElevation: parseDouble(value["highlight_elevation"]), + disabledElevation: parseDouble(value["disabled_elevation"]), + shape: parseShape(value["shape"], theme), + enableFeedback: parseBool(value["enable_feedback"]), + extendedPadding: parsePadding(value["extended_padding"]), + extendedTextStyle: parseTextStyle(value["text_style"], theme), + extendedIconLabelSpacing: parseDouble(value["icon_label_spacing"]), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + iconSize: parseDouble(value["icon_size"]), extendedSizeConstraints: - boxConstraintsFromJSON(j["extended_size_constraints"]), - sizeConstraints: boxConstraintsFromJSON(j["size_constraints"]), - smallSizeConstraints: boxConstraintsFromJSON(j["small_size_constraints"]), - largeSizeConstraints: boxConstraintsFromJSON(j["large_size_constraints"]), + parseBoxConstraints(value["extended_size_constraints"]), + sizeConstraints: parseBoxConstraints(value["size_constraints"]), + // smallSizeConstraints: parseBoxConstraints(value["small_size_constraints"]), + // largeSizeConstraints: parseBoxConstraints(value["large_size_constraints"]), ); } NavigationRailThemeData? parseNavigationRailTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [NavigationRailThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.navigationRailTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - elevation: parseDouble(j["elevation"]), - indicatorColor: parseColor(theme, j["indicator_color"]), - unselectedLabelTextStyle: parseTextStyle("unselected_label_text_style"), - selectedLabelTextStyle: parseTextStyle("selected_label_text_style"), - minWidth: parseDouble(j["min_width"]), - labelType: j["label_type"] != null - ? NavigationRailLabelType.values - .firstWhereOrNull((c) => c.name == j["label_type"]) - : null, - groupAlignment: parseDouble(j["group_alignment"]), - indicatorShape: j["indicator_shape"] != null - ? outlinedBorderFromJSON(j["indicator_shape"]) - : null, - minExtendedWidth: parseDouble(j["min_extended_width"]), - useIndicator: parseBool(j["use_indicator"]), + backgroundColor: parseColor(value["bgcolor"], theme), + elevation: parseDouble(value["elevation"]), + indicatorColor: parseColor(value["indicator_color"], theme), + unselectedLabelTextStyle: + parseTextStyle(value["unselected_label_text_style"], theme), + selectedLabelTextStyle: + parseTextStyle(value["selected_label_text_style"], theme), + minWidth: parseDouble(value["min_width"]), + labelType: parseNavigationRailLabelType(value["label_type"]), + groupAlignment: parseDouble(value["group_alignment"]), + indicatorShape: parseShape(value["indicator_shape"], theme), + minExtendedWidth: parseDouble(value["min_extended_width"]), + useIndicator: parseBool(value["use_indicator"]), ); } -AppBarTheme? parseAppBarTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } +AppBarThemeData? parseAppBarTheme(Map? value, ThemeData theme, + [AppBarThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.appBarTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - color: parseColor(theme, j["color"]), - shadowColor: parseColor(theme, j["shadow_color"]), - foregroundColor: parseColor(theme, j["foreground_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - titleTextStyle: parseTextStyle("title_text_style"), - toolbarTextStyle: parseTextStyle("toolbar_text_style"), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - elevation: parseDouble(j["elevation"]), - centerTitle: parseBool(j["center_title"]), - titleSpacing: parseDouble(j["title_spacing"]), - scrolledUnderElevation: parseDouble(j["scroll_elevation"]), - toolbarHeight: parseDouble(j["toolbar_height"]), - actionsPadding: edgeInsetsFromJson(j["actions_padding"]), + backgroundColor: parseColor(value["bgcolor"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + foregroundColor: parseColor(value["color"], theme), + titleTextStyle: parseTextStyle(value["title_text_style"], theme), + toolbarTextStyle: parseTextStyle(value["toolbar_text_style"], theme), + shape: parseShape(value["shape"], theme), + elevation: parseDouble(value["elevation"]), + centerTitle: parseBool(value["center_title"]), + titleSpacing: parseDouble(value["title_spacing"]), + scrolledUnderElevation: parseDouble(value["elevation_on_scroll"]), + toolbarHeight: parseDouble(value["toolbar_height"]), + actionsPadding: parsePadding(value["actions_padding"]), ); } -BottomAppBarTheme? parseBottomAppBarTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } +BottomAppBarThemeData? parseBottomAppBarTheme( + Map? value, ThemeData theme, + [BottomAppBarThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.bottomAppBarTheme.copyWith( - color: parseColor(theme, j["color"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - elevation: parseDouble(j["elevation"]), - height: parseDouble(j["height"]), - padding: edgeInsetsFromJson(j["padding"]), - shape: parseNotchedShape(j["shape"]), + color: parseColor(value["color"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + elevation: parseDouble(value["elevation"]), + height: parseDouble(value["height"]), + padding: parsePadding(value["padding"]), + shape: parseNotchedShape(value["shape"], theme), ); } -RadioThemeData? parseRadioTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +RadioThemeData? parseRadioTheme(Map? value, ThemeData theme, + [RadioThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.radioTheme.copyWith( - fillColor: getWidgetStateProperty( - j["fill_color"], (jv) => parseColor(theme, jv as String)), - splashRadius: parseDouble(j["splash_radius"]), - overlayColor: getWidgetStateProperty( - j["overlay_color"], (jv) => parseColor(theme, jv as String)), - visualDensity: parseVisualDensity(j["visual_density"]), - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), + fillColor: parseWidgetStateColor(value["fill_color"], theme), + splashRadius: parseDouble(value["splash_radius"]), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme), + visualDensity: parseVisualDensity(value["visual_density"]), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), ); } CheckboxThemeData? parseCheckboxTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [CheckboxThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.checkboxTheme.copyWith( - fillColor: getWidgetStateProperty( - j["fill_color"], (jv) => parseColor(theme, jv as String)), - splashRadius: parseDouble(j["splash_radius"]), - overlayColor: getWidgetStateProperty( - j["overlay_color"], (jv) => parseColor(theme, jv as String)), - visualDensity: parseVisualDensity(j["visual_density"]), - checkColor: getWidgetStateProperty( - j["check_color"], (jv) => parseColor(theme, jv as String)), - side: j["border_side"] != null - ? borderSideFromJSON(theme, j["border_side"], null) - : null, - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), + fillColor: parseWidgetStateColor(value["fill_color"], theme), + splashRadius: parseDouble(value["splash_radius"]), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme), + visualDensity: parseVisualDensity(value["visual_density"]), + checkColor: parseWidgetStateColor(value["check_color"], theme), + side: parseBorderSide(value["border_side"], theme), + shape: parseShape(value["shape"], theme), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), ); } -BadgeThemeData? parseBadgeTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } +BadgeThemeData? parseBadgeTheme(Map? value, ThemeData theme, + [BadgeThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.badgeTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - textStyle: parseTextStyle("text_style"), - padding: edgeInsetsFromJson(j["padding"]), - alignment: alignmentFromJson(j["alignment"]), - textColor: parseColor(theme, j["text_color"]), - offset: j["offset"] != null ? offsetFromJson(j["offset"]) : null, - smallSize: parseDouble(j["small_size"]), - largeSize: parseDouble(j["large_size"]), + backgroundColor: parseColor(value["bgcolor"], theme), + textStyle: parseTextStyle(value["text_style"], theme), + padding: parsePadding(value["padding"]), + alignment: parseAlignment(value["alignment"]), + textColor: parseColor(value["text_color"], theme), + offset: parseOffset(value["offset"]), + smallSize: parseDouble(value["small_size"]), + largeSize: parseDouble(value["large_size"]), ); } -SwitchThemeData? parseSwitchTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - +SwitchThemeData? parseSwitchTheme( + Map? value, BuildContext context, + [SwitchThemeData? defaultValue]) { + if (value == null) return defaultValue; + var theme = Theme.of(context); return theme.switchTheme.copyWith( - thumbColor: getWidgetStateProperty( - j["thumb_color"], (jv) => parseColor(theme, jv as String)), - trackColor: getWidgetStateProperty( - j["track_color"], (jv) => parseColor(theme, jv as String)), - overlayColor: getWidgetStateProperty( - j["overlay_color"], (jv) => parseColor(theme, jv as String)), - splashRadius: - j["splash_radius"] != null ? parseDouble(j["splash_radius"]) : null, - thumbIcon: getWidgetStateProperty( - j["thumb_icon"], (jv) => Icon(parseIcon(jv as String))), - trackOutlineColor: getWidgetStateProperty(j["track_outline_color"], - (jv) => parseColor(theme, jv as String), null), - trackOutlineWidth: getWidgetStateProperty( - j["track_outline_width"], (jv) => parseDouble(jv)), - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), - padding: edgeInsetsFromJson(j["padding"]), + thumbColor: parseWidgetStateColor(value["thumb_color"], theme), + trackColor: parseWidgetStateColor(value["track_color"], theme), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme), + splashRadius: parseDouble(value["splash_radius"]), + thumbIcon: parseWidgetStateIcon( + value["thumb_icon"], FletBackend.of(context), theme), + trackOutlineColor: + parseWidgetStateColor(value["track_outline_color"], theme), + trackOutlineWidth: parseWidgetStateDouble(value["track_outline_width"]), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + padding: parsePadding(value["padding"]), ); } -DividerThemeData? parseDividerTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +DividerThemeData? parseDividerTheme( + Map? value, ThemeData theme, + [DividerThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.dividerTheme.copyWith( - color: parseColor(theme, j["color"]), - space: parseDouble(j["space"]), - thickness: parseDouble(j["thickness"]), - indent: parseDouble(j["leading_indent"]), - endIndent: parseDouble(j["trailing_indent"]), + color: parseColor(value["color"], theme), + space: parseDouble(value["space"]), + thickness: parseDouble(value["thickness"]), + indent: parseDouble(value["leading_indent"]), + endIndent: parseDouble(value["trailing_indent"]), ); } SnackBarThemeData? parseSnackBarTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [SnackBarThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.snackBarTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - actionTextColor: parseColor(theme, j["action_text_color"]), - actionBackgroundColor: parseColor(theme, j["action_bgcolor"]), - closeIconColor: parseColor(theme, j["close_icon_color"]), - disabledActionTextColor: parseColor(theme, j["disabled_action_text_color"]), + backgroundColor: parseColor(value["bgcolor"], theme), + actionTextColor: parseColor(value["action_text_color"], theme), + actionBackgroundColor: parseColor(value["action_bgcolor"], theme), + closeIconColor: parseColor(value["close_icon_color"], theme), + disabledActionTextColor: + parseColor(value["disabled_action_text_color"], theme), disabledActionBackgroundColor: - parseColor(theme, j["disabled_action_bgcolor"]), - elevation: parseDouble(j["elevation"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - behavior: parseSnackBarBehavior(j["behavior"]), - contentTextStyle: parseTextStyle("content_text_style"), - width: parseDouble(j["width"]), - insetPadding: edgeInsetsFromJson(j["inset_padding"]), - dismissDirection: parseDismissDirection(j["dismiss_direction"]), - showCloseIcon: parseBool(j["show_close_icon"]), - actionOverflowThreshold: parseDouble(j["action_overflow_threshold"]), + parseColor(value["disabled_action_bgcolor"], theme), + elevation: parseDouble(value["elevation"]), + shape: parseShape(value["shape"], theme), + behavior: parseSnackBarBehavior(value["behavior"]), + contentTextStyle: parseTextStyle(value["content_text_style"], theme), + width: parseDouble(value["width"]), + insetPadding: parsePadding(value["inset_padding"]), + dismissDirection: parseDismissDirection(value["dismiss_direction"]), + showCloseIcon: parseBool(value["show_close_icon"]), + actionOverflowThreshold: parseDouble(value["action_overflow_threshold"]), ); } MaterialBannerThemeData? parseBannerTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [MaterialBannerThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.bannerTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - elevation: parseDouble(j["elevation"]), - dividerColor: parseColor(theme, j["divider_color"]), - padding: edgeInsetsFromJson(j["padding"]), - leadingPadding: edgeInsetsFromJson(j["leading_padding"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - shadowColor: parseColor(theme, j["shadow_color"]), - contentTextStyle: parseTextStyle("content_text_style"), + backgroundColor: parseColor(value["bgcolor"], theme), + elevation: parseDouble(value["elevation"]), + dividerColor: parseColor(value["divider_color"], theme), + padding: parsePadding(value["padding"]), + leadingPadding: parsePadding(value["leading_padding"]), + shadowColor: parseColor(value["shadow_color"], theme), + contentTextStyle: parseTextStyle(value["content_text_style"], theme), ); } DatePickerThemeData? parseDatePickerTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [DatePickerThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.datePickerTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - elevation: parseDouble(j["elevation"]), - dividerColor: parseColor(theme, j["divider_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - shadowColor: parseColor(theme, j["shadow_color"]), - cancelButtonStyle: buttonStyleFromJSON(theme, j["cancel_button_style"]), - confirmButtonStyle: buttonStyleFromJSON(theme, j["confirm_button_style"]), - dayBackgroundColor: getWidgetStateProperty( - j["day_bgcolor"], (jv) => parseColor(theme, jv as String)), - yearStyle: parseTextStyle("year_text_style"), - dayStyle: parseTextStyle("day_text_style"), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - dayOverlayColor: getWidgetStateProperty( - j["day_overlay_color"], (jv) => parseColor(theme, jv as String)), - headerBackgroundColor: parseColor(theme, j["header_bgcolor"]), - dayForegroundColor: getWidgetStateProperty( - j["day_foreground_color"], (jv) => parseColor(theme, jv as String)), - rangePickerElevation: parseDouble(j["range_picker_elevation"]), - todayBackgroundColor: getWidgetStateProperty( - j["today_bgcolor"], (jv) => parseColor(theme, jv as String)), - headerForegroundColor: parseColor(theme, j["header_foreground_color"]), - headerHeadlineStyle: parseTextStyle("header_headline_text_style"), - headerHelpStyle: parseTextStyle("header_help_text_style"), - rangePickerBackgroundColor: parseColor(theme, j["range_picker_bgcolor"]), + backgroundColor: parseColor(value["bgcolor"], theme), + elevation: parseDouble(value["elevation"]), + dividerColor: parseColor(value["divider_color"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + cancelButtonStyle: parseButtonStyle(value["cancel_button_style"], theme), + confirmButtonStyle: parseButtonStyle(value["confirm_button_style"], theme), + dayBackgroundColor: parseWidgetStateColor(value["day_bgcolor"], theme), + yearStyle: parseTextStyle(value["year_text_style"], theme), + dayStyle: parseTextStyle(value["day_text_style"], theme), + shape: parseShape(value["shape"], theme), + dayOverlayColor: parseWidgetStateColor(value["day_overlay_color"], theme), + headerBackgroundColor: parseColor(value["header_bgcolor"], theme), + dayForegroundColor: + parseWidgetStateColor(value["day_foreground_color"], theme), + rangePickerElevation: parseDouble(value["range_picker_elevation"]), + todayBackgroundColor: parseWidgetStateColor(value["today_bgcolor"], theme), + headerForegroundColor: parseColor(value["header_foreground_color"], theme), + headerHeadlineStyle: + parseTextStyle(value["header_headline_text_style"], theme), + headerHelpStyle: parseTextStyle(value["header_help_text_style"], theme), + rangePickerBackgroundColor: + parseColor(value["range_picker_bgcolor"], theme), rangePickerHeaderBackgroundColor: - parseColor(theme, j["range_picker_header_bgcolor"]), + parseColor(value["range_picker_header_bgcolor"], theme), rangePickerHeaderForegroundColor: - parseColor(theme, j["range_picker_header_foreground_color"]), - rangePickerShadowColor: parseColor(theme, j["range_picker_shadow_color"]), - todayForegroundColor: getWidgetStateProperty( - j["today_foreground_color"], (jv) => parseColor(theme, jv as String)), - rangePickerShape: j["range_picker_shape"] != null - ? outlinedBorderFromJSON(j["range_picker_shape"]) - : null, + parseColor(value["range_picker_header_foreground_color"], theme), + rangePickerShadowColor: + parseColor(value["range_picker_shadow_color"], theme), + todayForegroundColor: + parseWidgetStateColor(value["today_foreground_color"], theme), + rangePickerShape: parseShape(value["range_picker_shape"], theme), rangePickerHeaderHelpStyle: - parseTextStyle("range_picker_header_help_text_style"), + parseTextStyle(value["range_picker_header_help_text_style"], theme), rangePickerHeaderHeadlineStyle: - parseTextStyle("range_picker_header_headline_text_style"), - rangePickerSurfaceTintColor: - parseColor(theme, j["range_picker_surface_tint_color"]), + parseTextStyle(value["range_picker_header_headline_text_style"], theme), rangeSelectionBackgroundColor: - parseColor(theme, j["range_selection_bgcolor"]), - rangeSelectionOverlayColor: getWidgetStateProperty( - j["range_selection_overlay_color"], - (jv) => parseColor(theme, jv as String)), - todayBorder: j["today_border_side"] != null - ? borderSideFromJSON(theme, j["today_border_side"]) - : null, - yearBackgroundColor: getWidgetStateProperty( - j["year_bgcolor"], (jv) => parseColor(theme, jv as String)), - yearForegroundColor: getWidgetStateProperty( - j["year_foreground_color"], (jv) => parseColor(theme, jv as String)), - yearOverlayColor: getWidgetStateProperty( - j["year_overlay_color"], (jv) => parseColor(theme, jv as String)), - weekdayStyle: parseTextStyle("weekday_text_style"), - dayShape: getWidgetStateProperty( - j["day_shape"], (jv) => outlinedBorderFromJSON(jv)), - locale: localeFromJSON(j["locale"]), + parseColor(value["range_selection_bgcolor"], theme), + rangeSelectionOverlayColor: + parseWidgetStateColor(value["range_selection_overlay_color"], theme), + todayBorder: parseBorderSide(value["today_border_side"], theme), + yearBackgroundColor: parseWidgetStateColor(value["year_bgcolor"], theme), + yearForegroundColor: + parseWidgetStateColor(value["year_foreground_color"], theme), + yearOverlayColor: parseWidgetStateColor(value["year_overlay_color"], theme), + weekdayStyle: parseTextStyle(value["weekday_text_style"], theme), + dayShape: parseWidgetStateOutlinedBorder(value["day_shape"], theme), + //locale: parseLocale(value["locale"]), ); } TimePickerThemeData? parseTimePickerTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [TimePickerThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.timePickerTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - elevation: parseDouble(j["elevation"]), - padding: edgeInsetsFromJson(j["padding"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - dayPeriodBorderSide: j["day_period_border_side"] != null - ? borderSideFromJSON(theme, j["day_period_border_side"]) - : null, + backgroundColor: parseColor(value["bgcolor"], theme), + elevation: parseDouble(value["elevation"]), + padding: parsePadding(value["padding"]), + shape: parseShape(value["shape"], theme), + dayPeriodBorderSide: + parseBorderSide(value["day_period_border_side"], theme), dayPeriodButtonStyle: - buttonStyleFromJSON(theme, j["day_period_button_style"]), - dayPeriodColor: parseColor(theme, j["day_period_color"]), - dayPeriodShape: j["day_period_shape"] != null - ? outlinedBorderFromJSON(j["day_period_shape"]) - : null, - dayPeriodTextColor: parseColor(theme, j["day_period_text_color"]), - dayPeriodTextStyle: parseTextStyle("day_period_text_style"), - dialBackgroundColor: parseColor(theme, j["dial_bgcolor"]), - dialHandColor: parseColor(theme, j["dial_hand_color"]), - dialTextColor: parseColor(theme, j["dial_text_color"]), - dialTextStyle: parseTextStyle("dial_text_style"), - entryModeIconColor: parseColor(theme, j["entry_mode_icon_color"]), - helpTextStyle: parseTextStyle("help_text_style"), - hourMinuteColor: parseColor(theme, j["hour_minute_color"]), - hourMinuteTextColor: parseColor(theme, j["hour_minute_text_color"]), - hourMinuteTextStyle: parseTextStyle("hour_minute_text_style"), - hourMinuteShape: j["hour_minute_shape"] != null - ? outlinedBorderFromJSON(j["hour_minute_shape"]) - : null, - cancelButtonStyle: buttonStyleFromJSON(theme, j["cancel_button_style"]), - confirmButtonStyle: buttonStyleFromJSON(theme, j["confirm_button_style"]), - timeSelectorSeparatorColor: getWidgetStateProperty( - j["time_selector_separator_color"], - (jv) => parseColor(theme, jv as String)), - timeSelectorSeparatorTextStyle: getWidgetStateProperty( - j["time_selector_separator_text_style"], - (jv) => textStyleFromJson(theme, jv)), + parseButtonStyle(value["day_period_button_style"], theme), + dayPeriodColor: parseColor(value["day_period_color"], theme), + dayPeriodShape: parseShape(value["day_period_shape"], theme), + dayPeriodTextColor: parseColor(value["day_period_text_color"], theme), + dayPeriodTextStyle: parseTextStyle(value["day_period_text_style"], theme), + dialBackgroundColor: parseColor(value["dial_bgcolor"], theme), + dialHandColor: parseColor(value["dial_hand_color"], theme), + dialTextColor: parseColor(value["dial_text_color"], theme), + dialTextStyle: parseTextStyle(value["dial_text_style"], theme), + entryModeIconColor: parseColor(value["entry_mode_icon_color"], theme), + helpTextStyle: parseTextStyle(value["help_text_style"], theme), + hourMinuteColor: parseColor(value["hour_minute_color"], theme), + hourMinuteTextColor: parseColor(value["hour_minute_text_color"], theme), + hourMinuteTextStyle: parseTextStyle(value["hour_minute_text_style"], theme), + hourMinuteShape: parseShape(value["hour_minute_shape"], theme), + cancelButtonStyle: parseButtonStyle(value["cancel_button_style"], theme), + confirmButtonStyle: parseButtonStyle(value["confirm_button_style"], theme), + timeSelectorSeparatorColor: + parseWidgetStateColor(value["time_selector_separator_color"], theme), + timeSelectorSeparatorTextStyle: parseWidgetStateTextStyle( + value["time_selector_separator_text_style"], theme), ); } DropdownMenuThemeData? parseDropdownMenuTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [DropdownMenuThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.dropdownMenuTheme.copyWith( - menuStyle: menuStyleFromJSON(theme, j["menu_style"]), - textStyle: parseTextStyle("text_style"), + menuStyle: parseMenuStyle(value["menu_style"], theme), + textStyle: parseTextStyle(value["text_style"], theme), ); } ListTileThemeData? parseListTileTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [ListTileThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.listTileTheme.copyWith( - iconColor: parseColor(theme, j["icon_color"]), - textColor: parseColor(theme, j["text_color"]), - tileColor: parseColor(theme, j["bgcolor"]), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - contentPadding: edgeInsetsFromJson(j["content_padding"]), - selectedColor: parseColor(theme, j["selected_color"]), - selectedTileColor: parseColor(theme, j["selected_tile_color"]), - isThreeLine: parseBool(j["is_three_line"]), - visualDensity: parseVisualDensity(j["visual_density"]), - titleTextStyle: parseTextStyle("title_text_style"), - subtitleTextStyle: parseTextStyle("subtitle_text_style"), - minVerticalPadding: parseDouble(j["min_vertical_padding"]), - enableFeedback: parseBool(j["enable_feedback"]), - dense: parseBool(j["dense"]), - horizontalTitleGap: parseDouble(j["horizontal_spacing"]), - minLeadingWidth: parseDouble(j["min_leading_width"]), + iconColor: parseColor(value["icon_color"], theme), + textColor: parseColor(value["text_color"], theme), + tileColor: parseColor(value["bgcolor"], theme), + shape: parseShape(value["shape"], theme), + contentPadding: parsePadding(value["content_padding"]), + selectedColor: parseColor(value["selected_color"], theme), + selectedTileColor: parseColor(value["selected_tile_color"], theme), + isThreeLine: parseBool(value["is_three_line"]), + visualDensity: parseVisualDensity(value["visual_density"]), + titleTextStyle: parseTextStyle(value["title_text_style"], theme), + subtitleTextStyle: parseTextStyle(value["subtitle_text_style"], theme), + minVerticalPadding: parseDouble(value["min_vertical_padding"]), + enableFeedback: parseBool(value["enable_feedback"]), + dense: parseBool(value["dense"]), + horizontalTitleGap: parseDouble(value["horizontal_spacing"]), + minLeadingWidth: parseDouble(value["min_leading_width"]), leadingAndTrailingTextStyle: - parseTextStyle("leading_and_trailing_text_style"), - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), - minTileHeight: parseDouble(j["min_tile_height"]), + parseTextStyle(value["leading_and_trailing_text_style"], theme), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + minTileHeight: parseDouble(value["min_height"]), + controlAffinity: parseListTileControlAffinity(value["affinity"]), + style: parseListTileStyle(value["style"]), + titleAlignment: parseListTileTitleAlignment(value["title_alignment"]), ); } -TooltipThemeData? parseTooltipTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +TooltipThemeData? parseTooltipTheme( + Map? value, BuildContext context, + [TooltipThemeData? defaultValue]) { + if (value == null) return defaultValue; - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + var theme = Theme.of(context); return theme.tooltipTheme.copyWith( - enableFeedback: parseBool(j["enable_feedback"]), - height: parseDouble(j["height"]), - excludeFromSemantics: parseBool(j["exclude_from_semantics"]), - textStyle: parseTextStyle("text_style"), - preferBelow: parseBool(j["prefer_below"]), - verticalOffset: parseDouble(j["vertical_offset"]), - padding: edgeInsetsFromJson(j["padding"]), - waitDuration: durationFromJSON(j["wait_duration"]), - exitDuration: durationFromJSON(j["exit_duration"]), - showDuration: durationFromJSON(j["show_duration"]), - margin: edgeInsetsFromJson(j["margin"]), - textAlign: parseTextAlign(j["text_align"]), - triggerMode: parseTooltipTriggerMode(j["trigger_mode"]), - // TODO: replace null with PageArgsModel - decoration: boxDecorationFromJSON(theme, j["decoration"], null), + enableFeedback: parseBool(value["enable_feedback"]), + constraints: parseBoxConstraints(value["size_constraints"]), + excludeFromSemantics: parseBool(value["exclude_from_semantics"]), + textStyle: parseTextStyle(value["text_style"], theme), + preferBelow: parseBool(value["prefer_below"]), + verticalOffset: parseDouble(value["vertical_offset"]), + padding: parsePadding(value["padding"]), + waitDuration: parseDuration(value["wait_duration"]), + exitDuration: parseDuration(value["exit_duration"]), + showDuration: parseDuration(value["show_duration"]), + margin: parseMargin(value["margin"]), + textAlign: parseTextAlign(value["text_align"]), + triggerMode: parseTooltipTriggerMode(value["trigger_mode"]), + decoration: parseBoxDecoration(value["decoration"], context), ); } ExpansionTileThemeData? parseExpansionTileTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [ExpansionTileThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.expansionTileTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - iconColor: parseColor(theme, j["icon_color"]), - textColor: parseColor(theme, j["text_color"]), - collapsedBackgroundColor: parseColor(theme, j["collapsed_bgcolor"]), - collapsedIconColor: parseColor(theme, j["collapsed_icon_color"]), - clipBehavior: parseClip(j["clip_behavior"]), - collapsedTextColor: parseColor(theme, j["collapsed_text_color"]), - tilePadding: edgeInsetsFromJson(j["tile_padding"]), - expandedAlignment: alignmentFromJson(j["expanded_alignment"]), - childrenPadding: edgeInsetsFromJson(j["controls_padding"]), + backgroundColor: parseColor(value["bgcolor"], theme), + iconColor: parseColor(value["icon_color"], theme), + textColor: parseColor(value["text_color"], theme), + collapsedBackgroundColor: parseColor(value["collapsed_bgcolor"], theme), + collapsedIconColor: parseColor(value["collapsed_icon_color"], theme), + clipBehavior: parseClip(value["clip_behavior"]), + collapsedTextColor: parseColor(value["collapsed_text_color"], theme), + tilePadding: parsePadding(value["tile_padding"]), + expandedAlignment: parseAlignment(value["expanded_alignment"]), + childrenPadding: parsePadding(value["controls_padding"]), + shape: parseShape(value["shape"], theme), + collapsedShape: parseShape(value["collapsed_shape"], theme), + expansionAnimationStyle: + parseAnimationStyle(value["expansion_animation_style"]), ); } -SliderThemeData? parseSliderTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } +SliderThemeData? parseSliderTheme(Map? value, ThemeData theme, + [SliderThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.sliderTheme.copyWith( - activeTrackColor: parseColor(theme, j["active_track_color"]), - inactiveTrackColor: parseColor(theme, j["inactive_track_color"]), - thumbColor: parseColor(theme, j["thumb_color"]), - overlayColor: parseColor(theme, j["overlay_color"]), - valueIndicatorColor: parseColor(theme, j["value_indicator_color"]), - disabledThumbColor: parseColor(theme, j["disabled_thumb_color"]), - valueIndicatorTextStyle: parseTextStyle("value_indicator_text_style"), - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), - activeTickMarkColor: parseColor(theme, j["active_tick_mark_color"]), + activeTrackColor: parseColor(value["active_track_color"], theme), + inactiveTrackColor: parseColor(value["inactive_track_color"], theme), + thumbColor: parseColor(value["thumb_color"], theme), + overlayColor: parseColor(value["overlay_color"], theme), + valueIndicatorColor: parseColor(value["value_indicator_color"], theme), + disabledThumbColor: parseColor(value["disabled_thumb_color"], theme), + valueIndicatorTextStyle: + parseTextStyle(value["value_indicator_text_style"], theme), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + activeTickMarkColor: parseColor(value["active_tick_mark_color"], theme), disabledActiveTickMarkColor: - parseColor(theme, j["disabled_active_tick_mark_color"]), + parseColor(value["disabled_active_tick_mark_color"], theme), disabledActiveTrackColor: - parseColor(theme, j["disabled_active_track_color"]), + parseColor(value["disabled_active_track_color"], theme), disabledInactiveTickMarkColor: - parseColor(theme, j["disabled_inactive_tick_mark_color"]), + parseColor(value["disabled_inactive_tick_mark_color"], theme), disabledInactiveTrackColor: - parseColor(theme, j["disabled_inactive_track_color"]), + parseColor(value["disabled_inactive_track_color"], theme), disabledSecondaryActiveTrackColor: - parseColor(theme, j["disabled_secondary_active_track_color"]), - inactiveTickMarkColor: parseColor(theme, j["inactive_tick_mark_color"]), + parseColor(value["disabled_secondary_active_track_color"], theme), + inactiveTickMarkColor: parseColor(value["inactive_tick_mark_color"], theme), overlappingShapeStrokeColor: - parseColor(theme, j["overlapping_shape_stroke_color"]), - minThumbSeparation: parseDouble(j["min_thumb_separation"]), + parseColor(value["overlapping_shape_stroke_color"], theme), + minThumbSeparation: parseDouble(value["min_thumb_separation"]), secondaryActiveTrackColor: - parseColor(theme, j["secondary_active_track_color"]), - trackHeight: parseDouble(j["track_height"]), + parseColor(value["secondary_active_track_color"], theme), + trackHeight: parseDouble(value["track_height"]), valueIndicatorStrokeColor: - parseColor(theme, j["value_indicator_stroke_color"]), - allowedInteraction: parseSliderInteraction(j["interaction"]), - padding: edgeInsetsFromJson(j["padding"]), - trackGap: parseDouble(j["track_gap"]), + parseColor(value["value_indicator_stroke_color"], theme), + allowedInteraction: parseSliderInteraction(value["interaction"]), + padding: parsePadding(value["padding"]), + trackGap: parseDouble(value["track_gap"]), thumbSize: getWidgetStateProperty( - j["thumb_size"], (jv) => sizeFromJson(jv)), + value["thumb_size"], (jv) => parseSize(jv)), // TODO: deprecated in v0.27.0, to be removed in future versions - year2023: parseBool(j["year_2023"]), + year2023: parseBool(value["year_2023"]), ); } ProgressIndicatorThemeData? parseProgressIndicatorTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [ProgressIndicatorThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.progressIndicatorTheme.copyWith( - color: parseColor(theme, j["color"]), - circularTrackColor: parseColor(theme, j["circular_track_color"]), - linearTrackColor: parseColor(theme, j["linear_track_color"]), - refreshBackgroundColor: parseColor(theme, j["refresh_bgcolor"]), - linearMinHeight: parseDouble(j["linear_min_height"]), - borderRadius: borderRadiusFromJSON(j["border_radius"]), - trackGap: parseDouble(j["track_gap"]), - circularTrackPadding: edgeInsetsFromJson(j["circular_track_padding"]), - constraints: boxConstraintsFromJSON(j["size_constraints"]), - stopIndicatorColor: parseColor(theme, j["stop_indicator_color"]), - stopIndicatorRadius: parseDouble(j["stop_indicator_radius"]), - strokeAlign: parseDouble(j["stroke_align"]), - strokeCap: parseStrokeCap(j["stroke_cap"]), - strokeWidth: parseDouble(j["stroke_width"]), - year2023: parseBool(j["year_2023"]), + color: parseColor(value["color"], theme), + circularTrackColor: parseColor(value["circular_track_color"], theme), + linearTrackColor: parseColor(value["linear_track_color"], theme), + refreshBackgroundColor: parseColor(value["refresh_bgcolor"], theme), + linearMinHeight: parseDouble(value["linear_min_height"]), + borderRadius: parseBorderRadius(value["border_radius"]), + trackGap: parseDouble(value["track_gap"]), + circularTrackPadding: parsePadding(value["circular_track_padding"]), + constraints: parseBoxConstraints(value["size_constraints"]), + stopIndicatorColor: parseColor(value["stop_indicator_color"], theme), + stopIndicatorRadius: parseDouble(value["stop_indicator_radius"]), + strokeAlign: parseDouble(value["stroke_align"]), + strokeCap: parseStrokeCap(value["stroke_cap"]), + strokeWidth: parseDouble(value["stroke_width"]), + year2023: parseBool(value["year_2023"], false), ); } PopupMenuThemeData? parsePopupMenuTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [PopupMenuThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.popupMenuTheme.copyWith( - color: parseColor(theme, j["color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - shadowColor: parseColor(theme, j["shadow_color"]), - iconColor: parseColor(theme, j["icon_color"]), - textStyle: parseTextStyle("text_style"), - labelTextStyle: getWidgetStateProperty( - j["label_text_style"], (jv) => textStyleFromJson(theme, jv)), - enableFeedback: parseBool(j["enable_feedback"]), - elevation: parseDouble(j["elevation"]), - iconSize: parseDouble(j["icon_size"]), - position: j["menu_position"] != null - ? PopupMenuPosition.values.firstWhereOrNull( - (c) => c.name.toLowerCase() == j["menu_position"].toLowerCase()) - : null, - mouseCursor: getWidgetStateProperty( - j["mouse_cursor"], (jv) => parseMouseCursor(jv)), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - menuPadding: edgeInsetsFromJson(j["menu_padding"]), + color: parseColor(value["color"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + iconColor: parseColor(value["icon_color"], theme), + labelTextStyle: parseWidgetStateTextStyle(value["label_text_style"], theme), + enableFeedback: parseBool(value["enable_feedback"]), + elevation: parseDouble(value["elevation"]), + iconSize: parseDouble(value["icon_size"]), + position: parsePopupMenuPosition(value["menu_position"]), + mouseCursor: parseWidgetStateMouseCursor(value["mouse_cursor"]), + shape: parseShape(value["shape"], theme), + menuPadding: parsePadding(value["menu_padding"]), ); } SearchBarThemeData? parseSearchBarTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [SearchBarThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.searchBarTheme.copyWith( - surfaceTintColor: getWidgetStateProperty( - j["surface_tint_color"], (jv) => parseColor(theme, jv as String)), - shadowColor: getWidgetStateProperty( - j["shadow_color"], (jv) => parseColor(theme, jv as String)), - elevation: getWidgetStateProperty( - j["elevation"], (jv) => parseDouble(jv)), - backgroundColor: getWidgetStateProperty( - j["bgcolor"], (jv) => parseColor(theme, jv as String)), - overlayColor: getWidgetStateProperty( - j["overlay_color"], (jv) => parseColor(theme, jv as String)), - textStyle: getWidgetStateProperty( - j["text_style"], (jv) => textStyleFromJson(theme, jv)), - hintStyle: getWidgetStateProperty( - j["hint_style"], (jv) => textStyleFromJson(theme, jv)), - shape: getWidgetStateProperty( - j["shape"], (jv) => outlinedBorderFromJSON(jv)), - textCapitalization: j["text_capitalization"] != null - ? TextCapitalization.values.firstWhereOrNull((c) => - c.name.toLowerCase() == j["text_capitalization"].toLowerCase()) - : null, - padding: getWidgetStateProperty( - j["padding"], (jv) => edgeInsetsFromJson(jv)), - constraints: boxConstraintsFromJSON(j["size_constraints"]), - side: getWidgetStateProperty( - j["border_side"], (jv) => borderSideFromJSON(theme, jv)), + shadowColor: parseWidgetStateColor(value["shadow_color"], theme), + elevation: parseWidgetStateDouble(value["elevation"]), + backgroundColor: parseWidgetStateColor(value["bgcolor"], theme), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme), + textStyle: parseWidgetStateTextStyle(value["text_style"], theme), + hintStyle: parseWidgetStateTextStyle(value["hint_style"], theme), + shape: parseWidgetStateOutlinedBorder(value["shape"], theme), + textCapitalization: parseTextCapitalization(value["text_capitalization"]), + padding: parseWidgetStatePadding(value["padding"]), + constraints: parseBoxConstraints(value["size_constraints"]), + side: parseWidgetStateBorderSide(value["border_side"], theme), ); } SearchViewThemeData? parseSearchViewTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - - TextStyle? parseTextStyle(String propName) { - return j[propName] != null ? textStyleFromJson(theme, j[propName]) : null; - } + Map? value, ThemeData theme, + [SearchViewThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.searchViewTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - dividerColor: parseColor(theme, j["divider_color"]), - elevation: parseDouble(j["elevation"]), - headerHintStyle: parseTextStyle("header_hint_text_style"), - headerTextStyle: parseTextStyle("header_text_style"), - shape: j["shape"] != null ? outlinedBorderFromJSON(j["shape"]) : null, - side: borderSideFromJSON(theme, j["border_side"]), - constraints: boxConstraintsFromJSON(j["size_constraints"]), - headerHeight: parseDouble(j["header_height"]), - padding: edgeInsetsFromJson(j["padding"]), - barPadding: edgeInsetsFromJson(j["bar_padding"]), - shrinkWrap: parseBool(j["shrink_wrap"]), + backgroundColor: parseColor(value["bgcolor"], theme), + dividerColor: parseColor(value["divider_color"], theme), + elevation: parseDouble(value["elevation"]), + headerHintStyle: parseTextStyle(value["header_hint_text_style"], theme), + headerTextStyle: parseTextStyle(value["header_text_style"], theme), + shape: parseShape(value["shape"], theme), + side: parseBorderSide(value["border_side"], theme), + constraints: parseBoxConstraints(value["size_constraints"]), + headerHeight: parseDouble(value["header_height"]), + padding: parsePadding(value["padding"]), + barPadding: parsePadding(value["bar_padding"]), + shrinkWrap: parseBool(value["shrink_wrap"]), ); } NavigationDrawerThemeData? parseNavigationDrawerTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [NavigationDrawerThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.navigationDrawerTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - indicatorColor: parseColor(theme, j["indicator_color"]), - elevation: parseDouble(j["elevation"]), - indicatorSize: sizeFromJson(j["indicator_size"]), - tileHeight: parseDouble(j["tile_height"]), - labelTextStyle: getWidgetStateProperty( - j["label_text_style"], (jv) => textStyleFromJson(theme, jv)), - indicatorShape: j["indicator_shape"] != null - ? outlinedBorderFromJSON(j["indicator_shape"]) - : null, + backgroundColor: parseColor(value["bgcolor"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + indicatorColor: parseColor(value["indicator_color"], theme), + elevation: parseDouble(value["elevation"]), + indicatorSize: parseSize(value["indicator_size"]), + tileHeight: parseDouble(value["tile_height"]), + labelTextStyle: parseWidgetStateTextStyle(value["label_text_style"], theme), + indicatorShape: parseShape(value["indicator_shape"], theme), + iconTheme: getWidgetStateProperty( + value["icon_theme"], (jv) => parseIconTheme(jv, theme)), ); } NavigationBarThemeData? parseNavigationBarTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } + Map? value, ThemeData theme, + [NavigationBarThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.navigationBarTheme.copyWith( - backgroundColor: parseColor(theme, j["bgcolor"]), - shadowColor: parseColor(theme, j["shadow_color"]), - surfaceTintColor: parseColor(theme, j["surface_tint_color"]), - indicatorColor: parseColor(theme, j["indicator_color"]), - overlayColor: getWidgetStateProperty( - j["overlay_color"], (jv) => parseColor(theme, jv as String)), - elevation: parseDouble(j["elevation"]), - height: parseDouble(j["height"]), - labelTextStyle: getWidgetStateProperty( - j["label_text_style"], (jv) => textStyleFromJson(theme, jv)), - indicatorShape: j["indicator_shape"] != null - ? outlinedBorderFromJSON(j["indicator_shape"]) - : null, - labelBehavior: j["label_behavior"] != null - ? NavigationDestinationLabelBehavior.values.firstWhereOrNull( - (c) => c.name.toLowerCase() == j["label_behavior"].toLowerCase()) - : null, - labelPadding: edgeInsetsFromJson(j["label_padding"]), + backgroundColor: parseColor(value["bgcolor"], theme), + shadowColor: parseColor(value["shadow_color"], theme), + indicatorColor: parseColor(value["indicator_color"], theme), + overlayColor: parseWidgetStateColor(value["overlay_color"], theme), + elevation: parseDouble(value["elevation"]), + height: parseDouble(value["height"]), + labelTextStyle: parseWidgetStateTextStyle(value["label_text_style"], theme), + indicatorShape: parseShape(value["indicator_shape"], theme), + labelBehavior: + parseNavigationDestinationLabelBehavior(value["label_behavior"]), + labelPadding: parsePadding(value["label_padding"]), ); } SegmentedButtonThemeData? parseSegmentedButtonTheme( - ThemeData theme, Map? j) { - if (j == null) { - return null; - } - var selected_icon = parseIcon(j["selected_icon"]); + Map? value, ThemeData theme, BuildContext context, + [SegmentedButtonThemeData? defaultValue]) { + if (value == null) return defaultValue; + var selectedIcon = + parseIconData(value["selected_icon"], FletBackend.of(context)); return theme.segmentedButtonTheme.copyWith( - selectedIcon: selected_icon != null ? Icon(selected_icon) : null, - style: buttonStyleFromJSON(theme, j["style"]), + selectedIcon: selectedIcon != null ? Icon(selectedIcon) : null, + style: parseButtonStyle(value["style"], theme), ); } -IconThemeData? parseIconTheme(ThemeData theme, Map? j) { - if (j == null) { - return null; - } +IconThemeData? parseIconTheme(Map? value, ThemeData theme, + [IconThemeData? defaultValue]) { + if (value == null) return defaultValue; return theme.iconTheme.copyWith( - color: parseColor(theme, j["color"]), - applyTextScaling: parseBool(j["apply_text_scaling"]), - fill: parseDouble(j["fill"]), - opacity: parseDouble(j["opacity"]), - size: parseDouble(j["size"]), - opticalSize: parseDouble(j["optical_size"]), - grade: parseDouble(j["grade"]), - weight: parseDouble(j["weight"]), - shadows: - j["shadows"] != null ? boxShadowsFromJSON(theme, j["shadows"]) : null, + color: parseColor(value["color"], theme), + applyTextScaling: parseBool(value["apply_text_scaling"]), + fill: parseDouble(value["fill"]), + opacity: parseDouble(value["opacity"]), + size: parseDouble(value["size"]), + opticalSize: parseDouble(value["optical_size"]), + grade: parseDouble(value["grade"]), + weight: parseDouble(value["weight"]), + shadows: parseBoxShadows(value["shadows"], theme), ); } -PageTransitionsBuilder parseTransitionsBuilder( - String? tb, PageTransitionsBuilder defaultBuilder) { - switch (tb?.toLowerCase()) { - case "fadeupwards": - return const FadeUpwardsPageTransitionsBuilder(); - case "openupwards": - return const OpenUpwardsPageTransitionsBuilder(); - case "cupertino": - return const CupertinoPageTransitionsBuilder(); - case "zoom": - return const ZoomPageTransitionsBuilder(); - case "none": - return const NoPageTransitionsBuilder(); - case "predictive": - return const PredictiveBackPageTransitionsBuilder(); - case "fadeforwards": - return const FadeForwardsPageTransitionsBuilder(); - default: - return defaultBuilder; - } +PageTransitionsBuilder? parseTransitionsBuilder(String? value, + [PageTransitionsBuilder? defaultValue]) { + var buildersMap = { + "fadeupwards": const FadeUpwardsPageTransitionsBuilder(), + "openupwards": const OpenUpwardsPageTransitionsBuilder(), + "cupertino": const CupertinoPageTransitionsBuilder(), + "zoom": const ZoomPageTransitionsBuilder(), + "none": const NoPageTransitionsBuilder(), + "predictive": const PredictiveBackPageTransitionsBuilder(), + "fadeforwards": const FadeForwardsPageTransitionsBuilder(), + }; + return buildersMap[value?.toLowerCase()] ?? defaultValue; } class NoPageTransitionsBuilder extends PageTransitionsBuilder { @@ -1500,13 +1112,271 @@ class NoPageTransitionsBuilder extends PageTransitionsBuilder { @override Widget buildTransitions( - PageRoute? route, - BuildContext? context, - Animation animation, - Animation secondaryAnimation, - Widget? child, - ) { + PageRoute? route, + BuildContext? context, + Animation animation, + Animation secondaryAnimation, + Widget? child) { // only return the child without warping it with animations return child!; } } + +extension ThemeParsers on Control { + Brightness? getBrightness(String propertyName, [Brightness? defaultValue]) { + return parseBrightness(get(propertyName), defaultValue); + } + + ThemeData getTheme( + String propertyName, BuildContext context, Brightness? brightness, + {ThemeData? parentTheme}) { + return parseTheme(get(propertyName), context, brightness, + parentTheme: parentTheme); + } + + ThemeMode? getThemeMode(String propertyName, [ThemeMode? defaultValue]) { + return parseThemeMode(get(propertyName), defaultValue); + } + + CupertinoThemeData? getCupertinoTheme( + String propertyName, BuildContext context, Brightness? brightness, + {ThemeData? parentTheme}) { + return parseCupertinoTheme(get(propertyName), context, brightness, + parentTheme: parentTheme); + } + + ColorScheme? getColorScheme(String propertyName, ThemeData theme, + [ColorScheme? defaultValue]) { + return parseColorScheme(get(propertyName), theme, defaultValue); + } + + TextTheme? getTextTheme( + String propertyName, ThemeData theme, TextTheme textTheme, + [TextTheme? defaultValue]) { + return parseTextTheme(get(propertyName), theme, textTheme, defaultValue); + } + + VisualDensity? getVisualDensity(String propertyName, + [VisualDensity? defaultValue]) { + return parseVisualDensity(get(propertyName), defaultValue); + } + + PageTransitionsTheme? getPageTransitionsTheme(String propertyName, + [PageTransitionsTheme? defaultValue]) { + return parsePageTransitions(get(propertyName), defaultValue); + } + + SystemUiOverlayStyleTheme getSystemUiOverlayStyleTheme( + String propertyName, ThemeData theme, Brightness? brightness) { + return SystemUiOverlayStyleTheme( + get(propertyName) != null + ? parseSystemUiOverlayStyle(get(propertyName), theme, brightness) + : null, + ); + } + + ElevatedButtonThemeData? getButtonTheme(String propertyName, ThemeData theme, + [ElevatedButtonThemeData? defaultValue]) { + return parseButtonTheme(get(propertyName), theme, defaultValue); + } + + OutlinedButtonThemeData? getOutlinedButtonTheme( + String propertyName, ThemeData theme, + [OutlinedButtonThemeData? defaultValue]) { + return parseOutlinedButtonTheme(get(propertyName), theme, defaultValue); + } + + TextButtonThemeData? getTextButtonTheme(String propertyName, ThemeData theme, + [TextButtonThemeData? defaultValue]) { + return parseTextButtonTheme(get(propertyName), theme, defaultValue); + } + + FilledButtonThemeData? getFilledButtonTheme( + String propertyName, ThemeData theme, + [FilledButtonThemeData? defaultValue]) { + return parseFilledButtonTheme(get(propertyName), theme, defaultValue); + } + + IconButtonThemeData? getIconButtonTheme(String propertyName, ThemeData theme, + [IconButtonThemeData? defaultValue]) { + return parseIconButtonTheme(get(propertyName), theme, defaultValue); + } + + DataTableThemeData? getDataTableTheme( + String propertyName, BuildContext context, + [DataTableThemeData? defaultValue]) { + return parseDataTableTheme(get(propertyName), context, defaultValue); + } + + ScrollbarThemeData? getScrollbarTheme(String propertyName, ThemeData theme, + [ScrollbarThemeData? defaultValue]) { + return parseScrollBarTheme(get(propertyName), theme, defaultValue); + } + + TabBarThemeData? getTabBarTheme(String propertyName, ThemeData theme, + [TabBarThemeData? defaultValue]) { + return parseTabBarTheme(get(propertyName), theme, defaultValue); + } + + DialogThemeData? getDialogTheme(String propertyName, ThemeData theme, + [DialogThemeData? defaultValue]) { + return parseDialogTheme(get(propertyName), theme, defaultValue); + } + + BottomSheetThemeData? getBottomSheetTheme( + String propertyName, ThemeData theme, + [BottomSheetThemeData? defaultValue]) { + return parseBottomSheetTheme(get(propertyName), theme, defaultValue); + } + + CardThemeData? getCardTheme(String propertyName, ThemeData theme, + [CardThemeData? defaultValue]) { + return parseCardTheme(get(propertyName), theme, defaultValue); + } + + ChipThemeData? getChipTheme(String propertyName, ThemeData theme, + [ChipThemeData? defaultValue]) { + return parseChipTheme(get(propertyName), theme, defaultValue); + } + + FloatingActionButtonThemeData? getFloatingActionButtonTheme( + String propertyName, ThemeData theme, + [FloatingActionButtonThemeData? defaultValue]) { + return parseFloatingActionButtonTheme( + get(propertyName), theme, defaultValue); + } + + NavigationRailThemeData? getNavigationRailTheme( + String propertyName, ThemeData theme, + [NavigationRailThemeData? defaultValue]) { + return parseNavigationRailTheme(get(propertyName), theme, defaultValue); + } + + AppBarThemeData? getAppBarTheme(String propertyName, ThemeData theme, + [AppBarThemeData? defaultValue]) { + return parseAppBarTheme(get(propertyName), theme, defaultValue); + } + + BottomAppBarThemeData? getBottomAppBarTheme( + String propertyName, ThemeData theme, + [BottomAppBarThemeData? defaultValue]) { + return parseBottomAppBarTheme(get(propertyName), theme, defaultValue); + } + + RadioThemeData? getRadioTheme(String propertyName, ThemeData theme, + [RadioThemeData? defaultValue]) { + return parseRadioTheme(get(propertyName), theme, defaultValue); + } + + CheckboxThemeData? getCheckboxTheme(String propertyName, ThemeData theme, + [CheckboxThemeData? defaultValue]) { + return parseCheckboxTheme(get(propertyName), theme, defaultValue); + } + + BadgeThemeData? getBadgeTheme(String propertyName, ThemeData theme, + [BadgeThemeData? defaultValue]) { + return parseBadgeTheme(get(propertyName), theme, defaultValue); + } + + SwitchThemeData? getSwitchTheme(String propertyName, BuildContext context, + [SwitchThemeData? defaultValue]) { + return parseSwitchTheme(get(propertyName), context, defaultValue); + } + + DividerThemeData? getDividerTheme(String propertyName, ThemeData theme, + [DividerThemeData? defaultValue]) { + return parseDividerTheme(get(propertyName), theme, defaultValue); + } + + SnackBarThemeData? getSnackBarTheme(String propertyName, ThemeData theme, + [SnackBarThemeData? defaultValue]) { + return parseSnackBarTheme(get(propertyName), theme, defaultValue); + } + + MaterialBannerThemeData? getBannerTheme(String propertyName, ThemeData theme, + [MaterialBannerThemeData? defaultValue]) { + return parseBannerTheme(get(propertyName), theme, defaultValue); + } + + DatePickerThemeData? getDatePickerTheme(String propertyName, ThemeData theme, + [DatePickerThemeData? defaultValue]) { + return parseDatePickerTheme(get(propertyName), theme, defaultValue); + } + + TimePickerThemeData? getTimePickerTheme(String propertyName, ThemeData theme, + [TimePickerThemeData? defaultValue]) { + return parseTimePickerTheme(get(propertyName), theme, defaultValue); + } + + DropdownMenuThemeData? getDropdownMenuTheme( + String propertyName, ThemeData theme, + [DropdownMenuThemeData? defaultValue]) { + return parseDropdownMenuTheme(get(propertyName), theme, defaultValue); + } + + ListTileThemeData? getListTileTheme(String propertyName, ThemeData theme, + [ListTileThemeData? defaultValue]) { + return parseListTileTheme(get(propertyName), theme, defaultValue); + } + + TooltipThemeData? getTooltipTheme(String propertyName, BuildContext context, + [TooltipThemeData? defaultValue]) { + return parseTooltipTheme(get(propertyName), context, defaultValue); + } + + ExpansionTileThemeData? getExpansionTileTheme( + String propertyName, ThemeData theme, + [ExpansionTileThemeData? defaultValue]) { + return parseExpansionTileTheme(get(propertyName), theme, defaultValue); + } + + SliderThemeData? getSliderTheme(String propertyName, ThemeData theme, + [SliderThemeData? defaultValue]) { + return parseSliderTheme(get(propertyName), theme, defaultValue); + } + + ProgressIndicatorThemeData? getProgressIndicatorTheme( + String propertyName, ThemeData theme, + [ProgressIndicatorThemeData? defaultValue]) { + return parseProgressIndicatorTheme(get(propertyName), theme, defaultValue); + } + + PopupMenuThemeData? getPopupMenuTheme(String propertyName, ThemeData theme, + [PopupMenuThemeData? defaultValue]) { + return parsePopupMenuTheme(get(propertyName), theme, defaultValue); + } + + SearchBarThemeData? getSearchBarTheme(String propertyName, ThemeData theme, + [SearchBarThemeData? defaultValue]) { + return parseSearchBarTheme(get(propertyName), theme, defaultValue); + } + + SearchViewThemeData? getSearchViewTheme(String propertyName, ThemeData theme, + [SearchViewThemeData? defaultValue]) { + return parseSearchViewTheme(get(propertyName), theme, defaultValue); + } + + NavigationDrawerThemeData? getNavigationDrawerTheme( + String propertyName, ThemeData theme, + [NavigationDrawerThemeData? defaultValue]) { + return parseNavigationDrawerTheme(get(propertyName), theme, defaultValue); + } + + NavigationBarThemeData? getNavigationBarTheme( + String propertyName, ThemeData theme, + [NavigationBarThemeData? defaultValue]) { + return parseNavigationBarTheme(get(propertyName), theme, defaultValue); + } + + SegmentedButtonThemeData? getSegmentedButtonTheme( + String propertyName, ThemeData theme, BuildContext context, + [SegmentedButtonThemeData? defaultValue]) { + return parseSegmentedButtonTheme( + get(propertyName), theme, context, defaultValue); + } + + IconThemeData? getIconTheme(String propertyName, ThemeData theme, + [IconThemeData? defaultValue]) { + return parseIconTheme(get(propertyName), theme, defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/time.dart b/packages/flet/lib/src/utils/time.dart index 57e69d23cb..22d4047b35 100644 --- a/packages/flet/lib/src/utils/time.dart +++ b/packages/flet/lib/src/utils/time.dart @@ -1,37 +1,134 @@ -import 'dart:convert'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'enums.dart'; import '../models/control.dart'; import 'numbers.dart'; -Duration? parseDuration(Control control, String propName, - [Duration? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; +enum DurationUnit { microseconds, milliseconds, seconds, minutes, hours, days } + +/// Parses a dynamic [value] into a [Duration] object. +/// +/// Supported input types: +/// - `null`: Returns [defaultValue]. +/// - `num` (int or double): Interpreted as a single time unit specified by [treatNumAs]. +/// - `Map`: Must contain one or more of the following keys with numeric values: +/// `days`, `hours`, `minutes`, `seconds`, `milliseconds`, `microseconds`. +/// +/// Parameters: +/// - [value]: The input to parse. Can be `null`, `num`, or `Map`. +/// - [defaultValue]: The value to return if [value] is `null`. +/// - [treatNumAs]: Specifies the unit of time for numeric input. Defaults to `DurationUnit.milliseconds`. +/// +/// Returns: +/// A [Duration] constructed from the parsed input, or [defaultValue] if input is `null`. +Duration? parseDuration(dynamic value, + [Duration? defaultValue, + DurationUnit treatNumAs = DurationUnit.milliseconds]) { + if (value == null) return defaultValue; + if (value is num) { + final v = parseInt(value, 0)!; + return Duration( + microseconds: treatNumAs == DurationUnit.microseconds ? v : 0, + milliseconds: treatNumAs == DurationUnit.milliseconds ? v : 0, + seconds: treatNumAs == DurationUnit.seconds ? v : 0, + minutes: treatNumAs == DurationUnit.minutes ? v : 0, + hours: treatNumAs == DurationUnit.hours ? v : 0, + days: treatNumAs == DurationUnit.days ? v : 0, + ); } + return Duration( + days: parseInt(value["days"], 0)!, + hours: parseInt(value["hours"], 0)!, + minutes: parseInt(value["minutes"], 0)!, + seconds: parseInt(value["seconds"], 0)!, + milliseconds: parseInt(value["milliseconds"], 0)!, + microseconds: parseInt(value["microseconds"], 0)!); +} + +TimePickerEntryMode? parseTimePickerEntryMode(String? value, + [TimePickerEntryMode? defaultValue]) { + return parseEnum(TimePickerEntryMode.values, value, defaultValue); +} + +CupertinoDatePickerMode? parseCupertinoDatePickerMode(String? value, + [CupertinoDatePickerMode? defaultValue]) { + return parseEnum(CupertinoDatePickerMode.values, value, defaultValue); +} - final j1 = json.decode(v); - return durationFromJSON(j1); +CupertinoTimerPickerMode? parseCupertinoTimerPickerMode(String? value, + [CupertinoTimerPickerMode? defaultValue]) { + return parseEnum(CupertinoTimerPickerMode.values, value, defaultValue); } -Duration? durationFromJSON(dynamic json, [Duration? defaultValue]) { - if (json == null) { - return defaultValue; +DatePickerDateOrder? parseDatePickerDateOrder(String? value, + [DatePickerDateOrder? defaultValue]) { + return parseEnum(DatePickerDateOrder.values, value, defaultValue); +} + +DatePickerEntryMode? parseDatePickerEntryMode(String? value, + [DatePickerEntryMode? defaultValue]) { + return parseEnum(DatePickerEntryMode.values, value, defaultValue); +} + +DatePickerMode? parseDatePickerMode(String? value, + [DatePickerMode? defaultValue]) { + return parseEnum(DatePickerMode.values, value, defaultValue); +} + +extension TimeParsers on Control { + /// Retrieves and parses a duration value from the control's properties. + /// + /// Parameters: + /// - [propertyName]: The name of the property to retrieve the value from. + /// - [defaultValue]: The value to return if the property is not set or is `null`. + /// - [treatNumAs]: Specifies the unit of time for numeric input. Defaults to `DurationUnit.milliseconds`. + /// + /// + /// Returns: + /// A [Duration] based on the property's value, or [defaultValue] if the value is `null`. + Duration? getDuration(String propertyName, + [Duration? defaultValue, + DurationUnit treatNumAs = DurationUnit.milliseconds]) { + return parseDuration(get(propertyName), defaultValue, treatNumAs); } - if (json is int || json is double) { - return Duration(milliseconds: parseInt(json, 0)!); + + DatePickerDateOrder? getDatePickerDateOrder(String propertyName, + [DatePickerDateOrder? defaultValue]) { + return parseDatePickerDateOrder(get(propertyName), defaultValue); } - return Duration( - days: parseInt(json["days"], 0)!, - hours: parseInt(json["hours"], 0)!, - minutes: parseInt(json["minutes"], 0)!, - seconds: parseInt(json["seconds"], 0)!, - milliseconds: parseInt(json["milliseconds"], 0)!, - microseconds: parseInt(json["microseconds"], 0)!); -} - -Duration? durationFromString(String? duration, [Duration? defaultValue]) { - return duration != null - ? durationFromJSON(json.decode(duration), defaultValue) - : defaultValue; -} \ No newline at end of file + + TimePickerEntryMode? getTimePickerEntryMode(String propertyName, + [TimePickerEntryMode? defaultValue]) { + return parseTimePickerEntryMode(get(propertyName), defaultValue); + } + + CupertinoDatePickerMode? getCupertinoDatePickerMode(String propertyName, + [CupertinoDatePickerMode? defaultValue]) { + return parseCupertinoDatePickerMode(get(propertyName), defaultValue); + } + + CupertinoTimerPickerMode? getCupertinoTimerPickerMode(String propertyName, + [CupertinoTimerPickerMode? defaultValue]) { + return parseCupertinoTimerPickerMode(get(propertyName), defaultValue); + } + + DatePickerMode? getDatePickerMode(String propertyName, + [DatePickerMode? defaultValue]) { + return parseDatePickerMode(get(propertyName), defaultValue); + } + + DatePickerEntryMode? getDatePickerEntryMode(String propertyName, + [DatePickerEntryMode? defaultValue]) { + return parseDatePickerEntryMode(get(propertyName), defaultValue); + } + + DateTime? getDateTime(String propertyName, [DateTime? defaultValue]) { + final value = get(propertyName, defaultValue); // UTC time + return value?.toLocal(); + } + + TimeOfDay? getTimeOfDay(String propertyName, [TimeOfDay? defaultValue]) { + return get(propertyName, defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/tooltip.dart b/packages/flet/lib/src/utils/tooltip.dart index a3aafd7da9..ffec4bc4a3 100644 --- a/packages/flet/lib/src/utils/tooltip.dart +++ b/packages/flet/lib/src/utils/tooltip.dart @@ -1,84 +1,84 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; -import 'borders.dart'; import 'box.dart'; import 'colors.dart'; import 'edge_insets.dart'; -import 'gradient.dart'; -import 'images.dart'; +import 'enums.dart'; +import 'mouse.dart'; import 'numbers.dart'; -import 'others.dart'; import 'text.dart'; import 'time.dart'; TooltipTriggerMode? parseTooltipTriggerMode(String? value, [TooltipTriggerMode? defaultValue]) { - if (value == null) { - return defaultValue; - } - return TooltipTriggerMode.values.firstWhereOrNull( - (e) => e.name.toLowerCase() == value.toLowerCase()) ?? - defaultValue; + return parseEnum(TooltipTriggerMode.values, value, defaultValue); } -Tooltip? parseTooltip( - Control control, String propName, Widget widget, ThemeData theme) { - var v = control.attrString(propName, null); - if (v == null) { +Tooltip? parseTooltip(dynamic value, BuildContext context, Widget widget) { + if (value == null) { return null; + } else if (value is String) { + return Tooltip( + message: value, + waitDuration: const Duration(milliseconds: 800), + child: widget); } - final j = json.decode(v); - return tooltipFromJSON(j, widget, theme); -} -Tooltip? tooltipFromJSON(dynamic j, Widget widget, ThemeData theme) { - if (j == null) { - return null; - } else if (j is String) { - return Tooltip( - message: j, - padding: const EdgeInsets.all(4.0), - waitDuration: const Duration(milliseconds: 800), - child: widget, + var theme = Theme.of(context); + + var hasDecoration = value["decoration"] != null || value["bgcolor"] != null; + BoxDecoration? finalDecoration; + if (hasDecoration) { + /// The tooltip has the following defaults: rounded rectangle shape, + /// border radius of 4.0, opacity of 90%. + var defaultDecoration = BoxDecoration( + borderRadius: BorderRadius.circular(4.0), + color: parseColor( + value["bgcolor"], + theme, + (theme.brightness == Brightness.light + ? Colors.grey[700]! + : Colors.white) + .withValues(alpha: 0.9))!, + ); + var decoration = parseBoxDecoration(value["decoration"], context); + finalDecoration = defaultDecoration.copyWith( + color: decoration?.color, + borderRadius: decoration?.borderRadius, + border: decoration?.border, + boxShadow: decoration?.boxShadow, + gradient: decoration?.gradient, + image: decoration?.image, + shape: decoration?.shape, + backgroundBlendMode: decoration?.backgroundBlendMode, ); } - - /// The tooltip shape defaults to a rounded rectangle with a border radius of - /// 4.0. Tooltips will also default to an opacity of 90% - var decoration = boxDecorationFromDetails( - gradient: gradientFromJSON(theme, j["gradient"]), - border: borderFromJSON(theme, j["border"]), - borderRadius: - borderRadiusFromJSON(j["border_radius"], BorderRadius.circular(4.0)), - shape: parseBoxShape(j["shape"]), - color: parseColor(theme, j["bgcolor"], - theme.brightness == Brightness.light ? Colors.grey[700] : Colors.white), - blendMode: parseBlendMode(j["blend_mode"]), - boxShadow: boxShadowsFromJSON(theme, j["box_shadow"]), - image: decorationImageFromJSON( - theme, j["image"], null), // TODO: replace null with PageArgsModel - ); return Tooltip( - message: j["message"], - enableFeedback: parseBool(j["enable_feedback"]), - enableTapToDismiss: parseBool(j["enable_tap_to_dismiss"], true)!, - excludeFromSemantics: parseBool(j["exclude_from_semantics"]), - height: parseDouble(j["height"]), - exitDuration: durationFromJSON(j["exit_duration"]), - preferBelow: parseBool(j["prefer_below"]), - padding: edgeInsetsFromJson(j["padding"]), - decoration: decoration, - textStyle: textStyleFromJson(theme, j["text_style"]), - verticalOffset: parseDouble(j["vertical_offset"]), - margin: edgeInsetsFromJson(j["margin"]), - textAlign: parseTextAlign(j["text_align"]), - showDuration: durationFromJSON(j["show_duration"]), - waitDuration: durationFromJSON(j["wait_duration"]), - triggerMode: parseTooltipTriggerMode(j["trigger_mode"]), + message: value["message"], + enableFeedback: parseBool(value["enable_feedback"]), + enableTapToDismiss: parseBool(value["tap_to_dismiss"], true)!, + excludeFromSemantics: parseBool(value["exclude_from_semantics"]), + constraints: parseBoxConstraints(value["size_constraints"]), + exitDuration: parseDuration(value["exit_duration"]), + preferBelow: parseBool(value["prefer_below"]), + padding: parseEdgeInsets(value["padding"]), + decoration: finalDecoration, + textStyle: parseTextStyle(value["text_style"], theme), + verticalOffset: parseDouble(value["vertical_offset"]), + margin: parseEdgeInsets(value["margin"]), + mouseCursor: parseMouseCursor(value["mouse_cursor"]), + textAlign: parseTextAlign(value["text_align"]), + showDuration: parseDuration(value["show_duration"]), + waitDuration: parseDuration(value["wait_duration"]), + triggerMode: parseTooltipTriggerMode(value["trigger_mode"]), child: widget, ); } + +extension TooltipParsers on Control { + TooltipTriggerMode? getTooltipTriggerMode(String propertyName, + [TooltipTriggerMode? defaultValue]) { + return parseTooltipTriggerMode(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/transforms.dart b/packages/flet/lib/src/utils/transforms.dart index 02eb1491e9..e677066c93 100644 --- a/packages/flet/lib/src/utils/transforms.dart +++ b/packages/flet/lib/src/utils/transforms.dart @@ -1,104 +1,84 @@ -import 'dart:convert'; - -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import '../models/control.dart'; import 'alignment.dart'; +import 'images.dart'; import 'numbers.dart'; -RotationDetails? parseRotate(Control control, String propName, +RotationDetails? parseRotationDetails(dynamic value, [RotationDetails? defaultValue]) { - var v = control.attrString(propName); - if (v == null) { - return defaultValue; - } - - final j1 = json.decode(v); - return rotateFromJSON(j1, defaultValue); -} - -RotationDetails rotateFromJSON(dynamic json, [RotationDetails? defaultValue]) { - if (json == null) { - return defaultValue!; - } - if (json is int || json is double) { + if (value == null) return defaultValue; + if (value is int || value is double) { return RotationDetails( - angle: parseDouble(json, 0)!, alignment: Alignment.center); + angle: parseDouble(value, 0)!, + ); } - return RotationDetails.fromJson(json); + return RotationDetails.fromJson(value); } -ScaleDetails? parseScale(Control control, String propName, - [ScaleDetails? defaultValue]) { - var v = control.attrString(propName); - if (v == null) { - return defaultValue; - } - - final j1 = json.decode(v); - return scaleFromJSON(j1, defaultValue); -} - -ScaleDetails? scaleFromJSON(dynamic json, [ScaleDetails? defaultValue]) { - if (json == null) { - return defaultValue; - } - if (json is int || json is double) { +ScaleDetails? parseScale(dynamic value, [ScaleDetails? defaultValue]) { + if (value == null) return defaultValue; + if (value is int || value is double) { return ScaleDetails( - scale: parseDouble(json), - scaleX: null, - scaleY: null, - alignment: Alignment.center); + scale: parseDouble(value), + ); } - return ScaleDetails.fromJson(json); + return ScaleDetails.fromJson(value); } -Offset? parseOffset(Control control, String propName, [Offset? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; - } - - final j1 = json.decode(v); - return offsetFromJSON(j1, defaultValue); +OffsetDetails? parseOffsetDetails(dynamic value, + [OffsetDetails? defaultValue]) { + if (value == null) return defaultValue; + return OffsetDetails.fromValue(value); } -Offset? offsetFromJSON(dynamic json, [Offset? defaultValue]) { - if (json == null) { - return defaultValue; - } - var details = offsetDetailsFromJSON(json); +Offset? parseOffset(dynamic value, [Offset? defaultValue]) { + if (value == null) return defaultValue; + var details = OffsetDetails.fromValue(value); return Offset(details.x, details.y); } -List? parseOffsetList(Control control, String propName, - [List? defaultValue]) { - var v = control.attrString(propName, null); - if (v == null) { - return defaultValue; - } +List? parseOffsetList(dynamic value, [List? defaultValue]) { + if (value == null) return defaultValue; + return (value as List).map((e) => parseOffset(e)).nonNulls.toList(); +} - final j1 = json.decode(v); - return (j1 as List).map((e) => offsetFromJSON(e)).whereNotNull().toList(); +FlipDetails? parseFlipDetails(dynamic value, [FlipDetails? defaultValue]) { + if (value == null) return defaultValue; + return FlipDetails.fromJson(value); } -OffsetDetails offsetDetailsFromJSON(dynamic json) { - return OffsetDetails.fromJson(json); +TransformDetails? parseTransformDetails(dynamic value, + [TransformDetails? defaultValue]) { + if (value == null) return defaultValue; + return TransformDetails.fromJson(value); } class RotationDetails { final double angle; final Alignment alignment; + final Offset? origin; + final bool transformHitTests; + final FilterQuality? filterQuality; - RotationDetails({required this.angle, required this.alignment}); + RotationDetails({ + required this.angle, + this.alignment = Alignment.center, + this.origin, + this.transformHitTests = true, + this.filterQuality, + }); - factory RotationDetails.fromJson(Map json) { + factory RotationDetails.fromJson(Map value) { return RotationDetails( - angle: parseDouble(json["angle"], 0)!, - alignment: alignmentFromJson(json["alignment"], Alignment.center)!); + angle: parseDouble(value["angle"], 0)!, + alignment: parseAlignment(value["alignment"], Alignment.center)!, + origin: parseOffset(value["origin"]), + transformHitTests: parseBool(value["transform_hit_tests"], true)!, + filterQuality: parseFilterQuality(value["filter_quality"]), + ); } } @@ -107,35 +87,277 @@ class ScaleDetails { final double? scaleX; final double? scaleY; final Alignment alignment; + final Offset? origin; + final bool transformHitTests; + final FilterQuality? filterQuality; - ScaleDetails( - {required this.scale, - required this.scaleX, - required this.scaleY, - required this.alignment}); + ScaleDetails({ + this.scale, + this.scaleX, + this.scaleY, + this.alignment = Alignment.center, + this.origin, + this.transformHitTests = true, + this.filterQuality, + }); - factory ScaleDetails.fromJson(Map json) { + factory ScaleDetails.fromJson(Map value) { return ScaleDetails( - scale: parseDouble(json["scale"]), - scaleX: parseDouble(json["scale_x"]), - scaleY: parseDouble(json["scale_y"]), - alignment: alignmentFromJson(json["alignment"], Alignment.center)!); + scale: parseDouble(value["scale"]), + scaleX: parseDouble(value["scale_x"]), + scaleY: parseDouble(value["scale_y"]), + alignment: parseAlignment(value["alignment"], Alignment.center)!, + origin: parseOffset(value["origin"]), + transformHitTests: parseBool(value["transform_hit_tests"], true)!, + filterQuality: parseFilterQuality(value["filter_quality"]), + ); } } class OffsetDetails { final double x; final double y; + final bool transformHitTests; + final FilterQuality? filterQuality; - OffsetDetails({required this.x, required this.y}); + OffsetDetails({ + required this.x, + required this.y, + this.transformHitTests = true, + this.filterQuality, + }); - factory OffsetDetails.fromJson(dynamic json) { - if (json is List && json.length > 1) { - return OffsetDetails( - x: parseDouble(json[0], 0)!, y: parseDouble(json[1], 0)!); - } else { + factory OffsetDetails.fromValue(dynamic value) { + if (value is List && value.length > 1) { return OffsetDetails( - x: parseDouble(json["x"], 0)!, y: parseDouble(json["y"], 0)!); + x: parseDouble(value[0], 0)!, + y: parseDouble(value[1], 0)!, + ); + } + + return OffsetDetails( + x: parseDouble(value["x"], 0)!, + y: parseDouble(value["y"], 0)!, + transformHitTests: parseBool(value["transform_hit_tests"], true)!, + filterQuality: parseFilterQuality(value["filter_quality"]), + ); + } +} + +class FlipDetails { + final bool flipX; + final bool flipY; + final Offset? origin; + final bool transformHitTests; + final FilterQuality? filterQuality; + + FlipDetails({ + required this.flipX, + required this.flipY, + required this.origin, + required this.transformHitTests, + required this.filterQuality, + }); + + factory FlipDetails.fromJson(Map value) { + return FlipDetails( + flipX: parseBool(value["flip_x"], false)!, + flipY: parseBool(value["flip_y"], false)!, + origin: parseOffset(value["origin"]), + transformHitTests: parseBool(value["transform_hit_tests"], true)!, + filterQuality: parseFilterQuality(value["filter_quality"]), + ); + } +} + +class TransformDetails { + final Matrix4 matrix; + final Offset? origin; + final Alignment? alignment; + final bool transformHitTests; + final FilterQuality? filterQuality; + + TransformDetails({ + required this.matrix, + required this.origin, + required this.alignment, + required this.transformHitTests, + required this.filterQuality, + }); + + factory TransformDetails.fromJson(Map value) { + return TransformDetails( + matrix: Matrix4Recording.fromJson(value["matrix"]).replay(), + origin: parseOffset(value["origin"]), + alignment: parseAlignment(value["alignment"]), + transformHitTests: parseBool(value["transform_hit_tests"], true)!, + filterQuality: parseFilterQuality(value["filter_quality"]), + ); + } +} + +class Matrix4Call { + final String name; + final List args; + + Matrix4Call({required this.name, required this.args}); + + factory Matrix4Call.fromJson(Map value) { + return Matrix4Call( + name: value["name"], + args: value["args"] is List ? List.from(value["args"]) : [], + ); + } +} + +class Matrix4Recording { + final Matrix4Call ctor; + final List ops; + + Matrix4Recording({required this.ctor, required this.ops}); + + factory Matrix4Recording.fromJson(dynamic value) { + if (value is! Map) { + throw ArgumentError("matrix must be a map"); } + + return Matrix4Recording( + ctor: Matrix4Call.fromJson( + value["ctor"] is Map ? value["ctor"] : {"name": "identity"}), + ops: value["ops"] is List + ? (value["ops"] as List) + .whereType() + .map((e) => Matrix4Call.fromJson(e)) + .toList() + : [], + ); + } + + Matrix4 replay() { + final matrix = _createMatrix(ctor); + for (final op in ops) { + _applyOperation(matrix, op); + } + return matrix; + } + + Matrix4 _createMatrix(Matrix4Call call) { + switch (call.name) { + case "identity": + return Matrix4.identity(); + case "translation_values": + return Matrix4.translationValues( + parseDouble(_arg(call.args, 0), 0)!, + parseDouble(_arg(call.args, 1), 0)!, + parseDouble(_arg(call.args, 2), 0)!, + ); + case "diagonal3_values": + return Matrix4.diagonal3Values( + parseDouble(_arg(call.args, 0), 1)!, + parseDouble(_arg(call.args, 1), 1)!, + parseDouble(_arg(call.args, 2), 1)!, + ); + case "rotation_z": + return Matrix4.rotationZ(parseDouble(_arg(call.args, 0), 0)!); + case "skew_x": + return Matrix4.skewX(parseDouble(_arg(call.args, 0), 0)!); + case "skew_y": + return Matrix4.skewY(parseDouble(_arg(call.args, 0), 0)!); + default: + throw UnsupportedError("Unsupported Matrix4 constructor: ${call.name}"); + } + } + + void _applyOperation(Matrix4 matrix, Matrix4Call call) { + switch (call.name) { + case "translate": + matrix.translateByDouble( + parseDouble(_arg(call.args, 0), 0)!, + parseDouble(_arg(call.args, 1), 0)!, + parseDouble(_arg(call.args, 2), 0)!, + 1.0, + ); + return; + case "scale": + if (call.args.length <= 1) { + final s = parseDouble(_arg(call.args, 0), 1)!; + matrix.scaleByDouble(s, s, s, 1.0); + } else if (call.args.length == 2) { + matrix.scaleByDouble( + parseDouble(_arg(call.args, 0), 1)!, + parseDouble(_arg(call.args, 1), 1)!, + 1.0, + 1.0, + ); + } else { + matrix.scaleByDouble( + parseDouble(_arg(call.args, 0), 1)!, + parseDouble(_arg(call.args, 1), 1)!, + parseDouble(_arg(call.args, 2), 1)!, + 1.0, + ); + } + return; + case "rotate_z": + matrix.rotateZ(parseDouble(_arg(call.args, 0), 0)!); + return; + case "rotate_x": + matrix.rotateX(parseDouble(_arg(call.args, 0), 0)!); + return; + case "rotate_y": + matrix.rotateY(parseDouble(_arg(call.args, 0), 0)!); + return; + case "set_entry": + matrix.setEntry( + parseInt(_arg(call.args, 0), 0)!, + parseInt(_arg(call.args, 1), 0)!, + parseDouble(_arg(call.args, 2), 0)!, + ); + return; + case "multiply": + matrix.multiply(Matrix4Recording.fromJson(_arg(call.args, 0)).replay()); + return; + default: + throw UnsupportedError("Unsupported Matrix4 operation: ${call.name}"); + } + } + + dynamic _arg(List args, int index, [dynamic defaultValue]) { + return args.length > index ? args[index] : defaultValue; + } +} + +extension TransformParsers on Control { + RotationDetails? getRotationDetails(String propertyName, + [RotationDetails? defaultValue]) { + return parseRotationDetails(get(propertyName), defaultValue); + } + + ScaleDetails? getScale(String propertyName, [ScaleDetails? defaultValue]) { + return parseScale(get(propertyName), defaultValue); + } + + OffsetDetails? getOffsetDetails(String propertyName, + [OffsetDetails? defaultValue]) { + return parseOffsetDetails(get(propertyName), defaultValue); + } + + Offset? getOffset(String propertyName, [Offset? defaultValue]) { + return parseOffset(get(propertyName), defaultValue); + } + + List? getOffsetList(String propertyName, + [List? defaultValue]) { + return parseOffsetList(get(propertyName), defaultValue); + } + + FlipDetails? getFlipDetails(String propertyName, + [FlipDetails? defaultValue]) { + return parseFlipDetails(get(propertyName), defaultValue); + } + + TransformDetails? getTransformDetails(String propertyName, + [TransformDetails? defaultValue]) { + return parseTransformDetails(get(propertyName), defaultValue); } } diff --git a/packages/flet/lib/src/utils/uri.dart b/packages/flet/lib/src/utils/uri.dart index f0724a0e5f..659322437c 100644 --- a/packages/flet/lib/src/utils/uri.dart +++ b/packages/flet/lib/src/utils/uri.dart @@ -1,7 +1,7 @@ import 'strings.dart'; String getWebPageName(Uri uri) { - var urlPath = trim(uri.path, "/"); + var urlPath = uri.path.trimSymbol("/"); if (urlPath != "") { var pathParts = urlPath.split("/"); if (pathParts.length > 1) { @@ -27,7 +27,11 @@ bool isLocalhost(Uri uri) { return uri.host == "localhost" || uri.host == "127.0.0.1"; } -bool isUdsPath(String address) { - var uri = Uri.tryParse(address); - return uri == null || !uri.hasScheme; +bool isUdsPath(Uri address) { + return !address.hasScheme; +} + +bool isUrl(String value) { + final urlPattern = RegExp(r'^(https?:\/\/|www\.)'); + return urlPattern.hasMatch(value); } diff --git a/packages/flet/lib/src/utils/user_fonts.dart b/packages/flet/lib/src/utils/user_fonts.dart index 9f4b4b15a7..ec4c5bb3f4 100644 --- a/packages/flet/lib/src/utils/user_fonts.dart +++ b/packages/flet/lib/src/utils/user_fonts.dart @@ -1,38 +1,34 @@ -import 'dart:convert'; - import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import '../models/control.dart'; - -import 'user_fonts_io.dart' if (dart.library.js) "user_fonts_web.dart"; +import 'user_fonts_web.dart' if (dart.library.io) "user_fonts_io.dart"; class UserFonts { static Map fontLoaders = {}; - static void loadFontFromUrl(String fontFamily, String fontUrl) { - debugPrint("Load font from URL: $fontUrl"); + static Future loadFontFromUrl(String fontFamily, String fontUrl) async { var key = "$fontFamily$fontUrl"; - if (fontLoaders.containsKey(key)) { - return; - } + if (fontLoaders.containsKey(key)) return; + debugPrint("Load font from URL: $fontUrl"); var fontLoader = FontLoader(fontFamily); fontLoaders[key] = fontLoader; fontLoader.addFont(fetchFontFromUrl(fontUrl)); - fontLoader.load(); + await fontLoader.load(); + debugPrint("Font loaded from URL: $fontUrl"); } - static void loadFontFromFile(String fontFamily, String fontPath) { - debugPrint("Load font from file: $fontPath"); + static Future loadFontFromFile( + String fontFamily, String fontPath) async { var key = "$fontFamily$fontPath"; - if (fontLoaders.containsKey(key)) { - return; - } + if (fontLoaders.containsKey(key)) return; + debugPrint("Load font from file: $fontPath"); var fontLoader = FontLoader(fontFamily); fontLoaders[key] = fontLoader; fontLoader.addFont(fetchFontFromFile(fontPath)); - fontLoader.load(); + await fontLoader.load(); + debugPrint("Font loaded from file: $fontPath"); } static Future fetchFontFromUrl(String url) async { @@ -47,16 +43,15 @@ class UserFonts { } } -Map parseFonts(Control control, String propName) { - var v = control.attrString(propName, null); - if (v == null) { - return {}; - } - - final j1 = json.decode(v); - return fontsFromJson(j1); +Map? parseFonts(dynamic value, + [Map? defaultValue]) { + if (value == null) return {}; + return Map.from(value); } -Map fontsFromJson(Map json) { - return json.map((key, value) => MapEntry(key, value)); +extension UserFontParsers on Control { + Map? getFonts(String propertyName, + [Map? defaultValue]) { + return parseFonts(get(propertyName), defaultValue); + } } diff --git a/packages/flet/lib/src/utils/weak_value_map.dart b/packages/flet/lib/src/utils/weak_value_map.dart new file mode 100644 index 0000000000..ff4efb3b75 --- /dev/null +++ b/packages/flet/lib/src/utils/weak_value_map.dart @@ -0,0 +1,48 @@ +import 'dart:core'; + +import 'package:flutter/material.dart'; + +class WeakValueMap { + final Map> _map = {}; + late final Finalizer _finalizer; + + WeakValueMap() { + _finalizer = Finalizer((key) { + debugPrint("WeakValueMap.finalizer: $key"); + _map.remove(key); + }); + } + + void set(K key, V value) { + // Detach old value if present + final existing = _map[key]; + if (existing != null) { + _finalizer.detach(existing.detachToken); + } + + final tracked = _TrackedValue(value); + _map[key] = tracked; + + // Attach finalizer to the actual object, using a unique token + _finalizer.attach(value, key, detach: tracked.detachToken); + } + + V? get(K key) => _map[key]?.ref.target; + + void remove(K key) { + debugPrint("WeakValueMap.remove: $key"); + final tracked = _map.remove(key); + if (tracked != null) { + _finalizer.detach(tracked.detachToken); + } + } + + int get length => _map.length; +} + +class _TrackedValue { + final WeakReference ref; + final Object detachToken = Object(); + + _TrackedValue(V value) : ref = WeakReference(value); +} diff --git a/packages/flet/lib/src/utils/widget_state.dart b/packages/flet/lib/src/utils/widget_state.dart new file mode 100644 index 0000000000..616ca81bed --- /dev/null +++ b/packages/flet/lib/src/utils/widget_state.dart @@ -0,0 +1,68 @@ +import 'dart:collection'; + +import 'package:flutter/material.dart'; + +import '../models/control.dart'; + +WidgetStateProperty? getWidgetStateProperty( + dynamic value, T Function(dynamic) converterFromJson, + [T? defaultValue]) { + if (value == null) return null; + var j = value; + if (j is! Map || j.isEmpty) { + j = {"default": j}; + } + if (j.containsKey("")) { + j["default"] = j.remove(""); + } + if (!j.keys.every( + (k) => k == "default" || WidgetState.values.any((v) => v.name == k))) { + // wrap into another dict + j = {"default": j}; + } + return WidgetStateFromJSON(j, converterFromJson, defaultValue); +} + +class WidgetStateFromJSON extends WidgetStateProperty { + late final LinkedHashMap _states; + late final T? _defaultValue; + + WidgetStateFromJSON(Map? jsonDictValue, + T Function(dynamic) converterFromJson, T? defaultValue) { + _defaultValue = defaultValue; + + // preserve user-defined order + _states = LinkedHashMap.from( + jsonDictValue?.map((k, v) { + var key = k.trim().toLowerCase(); + // "" is deprecated and renamed to "default" + if (key == "") key = "default"; + return MapEntry(key, converterFromJson(v)); + }) ?? + {}, + ); + } + + @override + T? resolve(Set states) { + // Resolve using user-defined order in _states + for (var stateName in _states.keys) { + if (stateName == "default") continue; // Skip "default"; handled last + if (states.any((state) => state.name == stateName)) { + return _states[stateName]; + } + } + + // Default state + return _states["default"] ?? _defaultValue; + } +} + +extension WidgetStatePropertyParsers on Control { + WidgetStateProperty? getWidgetStateProperty( + String propertyName, T Function(dynamic) converterFromJson, + [T? defaultValue]) { + return getWidgetStateProperty( + get(propertyName), converterFromJson, defaultValue); + } +} diff --git a/packages/flet/lib/src/utils/window.dart b/packages/flet/lib/src/utils/window.dart new file mode 100644 index 0000000000..4ae723eb27 --- /dev/null +++ b/packages/flet/lib/src/utils/window.dart @@ -0,0 +1,15 @@ +import 'package:window_manager/window_manager.dart'; +import 'enums.dart'; + +import '../models/control.dart'; + +ResizeEdge? parseWindowResizeEdge(String? value, [ResizeEdge? defaultValue]) { + return parseEnum(ResizeEdge.values, value, defaultValue); +} + +extension WindowParsers on Control { + ResizeEdge? getWindowResizeEdge(String propertyName, + [ResizeEdge? defaultValue]) { + return parseWindowResizeEdge(get(propertyName), defaultValue); + } +} diff --git a/packages/flet/lib/src/widgets/control_inherited_notifier.dart b/packages/flet/lib/src/widgets/control_inherited_notifier.dart new file mode 100644 index 0000000000..75a546de0c --- /dev/null +++ b/packages/flet/lib/src/widgets/control_inherited_notifier.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../extensions/control.dart'; +import '../flet_backend.dart'; +import '../models/control.dart'; +import '../utils/theme.dart'; + +/// InheritedNotifier for a [Control]. +/// +/// Used to rebuild a control subtree when the +/// corresponding [Control] (a [ChangeNotifier]) changes. +class ControlInheritedNotifier extends InheritedNotifier { + const ControlInheritedNotifier({ + super.key, + super.notifier, + required super.child, + }) : super(); + + /// Establishes a dependency on the nearest [ControlInheritedNotifier] and + /// returns its [Control]. + static Control? of(BuildContext context) { + return context + .dependOnInheritedWidgetOfExactType() + ?.notifier; + } + + @override + bool updateShouldNotify(ControlInheritedNotifier oldWidget) { + return notifier != oldWidget.notifier; + } +} + +/// Wraps [builder] with [ControlInheritedNotifier], unless the control opts out. +/// +/// If `"skip_inherited_notifier"` internal is `true`, this returns +/// [builder] without a [ControlInheritedNotifier] wrapper. +Widget withControlInheritedNotifier(Control control, WidgetBuilder builder) { + if (control.internals?["skip_inherited_notifier"] == true) { + return Builder(builder: builder); + } + + return ControlInheritedNotifier( + notifier: control, + child: Builder(builder: (context) { + ControlInheritedNotifier.of(context); + return builder(context); + }), + ); +} + +/// Convenience wrapper that applies both: +/// - [withControlInheritedNotifier] +/// - [withControlTheme] +Widget withControlContext( + Control control, + WidgetBuilder builder, +) { + // Avoid stacking Builders for controls that opt out of the inherited notifier + // pattern. `withControlTheme()` is also a no-op for these controls. + if (control.internals?["skip_inherited_notifier"] == true) { + return Builder(builder: builder); + } + + return Builder(builder: (context) { + final child = withControlInheritedNotifier(control, builder); + return withControlTheme(control, context, child); + }); +} + +/// Applies per-control theming (`theme`, `dark_theme`, `theme_mode`) to `child`. +/// +/// Returns `child` unchanged when: +/// - `control` is the page/root control +/// - `"skip_inherited_notifier"` internal is `true` +/// - no `theme`/`dark_theme` is set and `theme_mode` is `null` +/// +/// Parameters: +/// - `control`: the control whose per-control theme (if any) will be applied. +/// - `context`: used to access `FletBackend` and the ambient `Theme`. +/// - `child`: the widget subtree to wrap with the per-control `Theme`. +Widget withControlTheme(Control control, BuildContext context, Widget child) { + if (control == FletBackend.of(context).page) return child; + + if (control.internals?["skip_inherited_notifier"] == true) return child; + + final hasNoThemes = + control.get("theme") == null && control.get("dark_theme") == null; + final themeMode = control.getThemeMode("theme_mode"); + if (hasNoThemes && themeMode == null) return child; + + final ThemeData? parentTheme = (themeMode == null) ? Theme.of(context) : null; + + /// Converts [ThemeMode] to [Brightness] used by [Control.getTheme]. + Brightness? themeModeToBrightness(ThemeMode? mode) { + switch (mode) { + case ThemeMode.light: + return Brightness.light; + case ThemeMode.dark: + return Brightness.dark; + case ThemeMode.system: + return context.select( + (backend) => backend.platformBrightness, + ); + case null: + return parentTheme?.brightness; + } + } + + Widget buildTheme(Brightness? brightness) { + final themeData = control.getTheme( + brightness == Brightness.dark ? "dark_theme" : "theme", + context, + brightness, + parentTheme: parentTheme, + ); + return Theme(data: themeData, child: child); + } + + return buildTheme(themeModeToBrightness(themeMode)); +} + +extension ControlContextBuilder on Control { + /// Builds a widget under this control's standard "control context": + /// [ControlInheritedNotifier] + per-control theme wrapping. + /// + /// This is primarily used by [ControlWidget] and any "special" controls that + /// must subclass a Flutter widget (e.g. a control that must be a `Tab`) but + /// still need the same wrapper behavior as a normal `ControlWidget`. + Widget buildInControlContext(WidgetBuilder builder) { + return withControlContext(this, builder); + } +} diff --git a/packages/flet/lib/src/controls/error.dart b/packages/flet/lib/src/widgets/error.dart similarity index 94% rename from packages/flet/lib/src/controls/error.dart rename to packages/flet/lib/src/widgets/error.dart index 6ba848062a..d1037d3df8 100644 --- a/packages/flet/lib/src/controls/error.dart +++ b/packages/flet/lib/src/widgets/error.dart @@ -8,7 +8,7 @@ class ErrorControl extends StatelessWidget { @override Widget build(BuildContext context) { - debugPrint("ErrorControl build"); + debugPrint("ErrorControl build: $message"); List lines = [ Text(message, style: const TextStyle(color: Colors.white, fontSize: 12)) ]; diff --git a/packages/flet/lib/src/widgets/flet_store_mixin.dart b/packages/flet/lib/src/widgets/flet_store_mixin.dart new file mode 100644 index 0000000000..bf4df85001 --- /dev/null +++ b/packages/flet/lib/src/widgets/flet_store_mixin.dart @@ -0,0 +1,22 @@ +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +import '../flet_backend.dart'; +import '../models/page_size_view_model.dart'; + +mixin FletStoreMixin { + Widget withPageSize(Widget Function(BuildContext, PageSizeViewModel) build) { + return Selector( + selector: (_, backend) => PageSizeViewModel( + size: backend.pageSize, breakpoints: backend.sizeBreakpoints), + builder: (context, view, _) => build(context, view), + ); + } + + Widget withPagePlatform(Widget Function(BuildContext, TargetPlatform) build) { + return Selector( + selector: (_, backend) => backend.platform, + builder: (context, platform, _) => build(context, platform), + ); + } +} diff --git a/packages/flet/lib/src/widgets/loading_page.dart b/packages/flet/lib/src/widgets/loading_page.dart index bbec144b8f..34e90d0452 100644 --- a/packages/flet/lib/src/widgets/loading_page.dart +++ b/packages/flet/lib/src/widgets/loading_page.dart @@ -48,14 +48,15 @@ class LoadingPage extends StatelessWidget { color: theme.colorScheme.onErrorContainer, size: 30), const SizedBox(width: 8), Flexible( - child: Text( + child: SelectionArea( + child: Text( message, softWrap: true, style: Theme.of(context) .textTheme .bodySmall! .copyWith(color: theme.colorScheme.onErrorContainer), - )) + ))) ]), ); } diff --git a/packages/flet/lib/src/widgets/page_context.dart b/packages/flet/lib/src/widgets/page_context.dart new file mode 100644 index 0000000000..39a8f9ce47 --- /dev/null +++ b/packages/flet/lib/src/widgets/page_context.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +import '../models/page_design.dart'; + +class PageContext extends InheritedWidget { + final PageDesign widgetsDesign; + final ThemeMode? themeMode; + final Brightness? brightness; + + const PageContext( + {required this.themeMode, + required this.brightness, + required this.widgetsDesign, + required super.child, + super.key}); + + @override + bool updateShouldNotify(covariant PageContext oldWidget) { + return themeMode != oldWidget.themeMode || + brightness != oldWidget.brightness || + widgetsDesign != oldWidget.widgetsDesign; + } + + static PageContext? of(BuildContext context) => + context.dependOnInheritedWidgetOfExactType(); +} diff --git a/packages/flet/lib/src/widgets/page_media.dart b/packages/flet/lib/src/widgets/page_media.dart index 846c037702..16429cb1c7 100644 --- a/packages/flet/lib/src/widgets/page_media.dart +++ b/packages/flet/lib/src/widgets/page_media.dart @@ -1,24 +1,20 @@ import 'package:flutter/material.dart'; -import 'package:flutter_redux/flutter_redux.dart'; -import '../actions.dart'; -import '../flet_app_services.dart'; -import '../models/app_state.dart'; -import '../models/page_media_view_model.dart'; +import '../flet_backend.dart'; +import '../models/control.dart'; import '../protocol/page_media_data.dart'; import '../utils/debouncer.dart'; -import '../utils/desktop.dart'; class PageMedia extends StatefulWidget { - const PageMedia({super.key}); + final Control? view; + const PageMedia({super.key, this.view}); @override State createState() => _PageMediaState(); } class _PageMediaState extends State { - final _debouncer = Debouncer(milliseconds: 250); - int _pageMediaTimestamp = 0; + final _debouncer = Debouncer(milliseconds: 100); @override void dispose() { @@ -26,70 +22,57 @@ class _PageMediaState extends State { super.dispose(); } - _onScreenSizeChanged(bool isRegistered, Size newSize, Function dispatch) { - if (isRegistered) { + _onPageSizeChanged(bool pageSizeUpdated, Size newSize) { + var backend = FletBackend.of(context); + if (pageSizeUpdated) { _debouncer.run(() { - debugPrint("Send current size to reducer: $newSize"); - getWindowMediaData().then((wmd) { - dispatch(PageSizeChangeAction( - newSize, wmd, FletAppServices.of(context).server)); - }); + backend.updatePageSize(newSize, view: widget.view); }); } else { - dispatch(PageSizeChangeAction( - newSize, null, FletAppServices.of(context).server)); + backend.updatePageSize(newSize, view: widget.view); } } - _onScreenBrightnessChanged(Brightness brightness, Function dispatch) { - debugPrint("Send new brightness to reducer: $brightness"); - dispatch(PageBrightnessChangeAction( - brightness, FletAppServices.of(context).server)); + _onPlatformBrightnessChanged(Brightness newBrightness) { + FletBackend.of(context).updateBrightness(newBrightness); } - _onMediaChanged(PageMediaData media, Function dispatch) { - var now = DateTime.now().millisecondsSinceEpoch; - if (now - _pageMediaTimestamp > 50) { - _pageMediaTimestamp = now; - debugPrint("Send new page media data to reducer: $media"); - dispatch( - PageMediaChangeAction(media, FletAppServices.of(context).server)); - } + _onMediaChanged(PageMediaData newMedia) { + FletBackend.of(context).updateMedia(newMedia, view: widget.view); } @override Widget build(BuildContext context) { - debugPrint("Page media build"); + FletBackend backend = FletBackend.of(context); + + WidgetsBinding.instance.addPostFrameCallback((_) { + var pageSizeUpdated = backend.pageSizeUpdated.isCompleted; + + var platformBrightness = MediaQuery.platformBrightnessOf(context); + if (platformBrightness != backend.platformBrightness || + !pageSizeUpdated) { + _onPlatformBrightnessChanged(platformBrightness); + } + + var newMedia = PageMediaData( + padding: PaddingData(MediaQuery.paddingOf(context)), + viewPadding: PaddingData(MediaQuery.viewPaddingOf(context)), + viewInsets: PaddingData(MediaQuery.viewInsetsOf(context)), + devicePixelRatio: MediaQuery.devicePixelRatioOf(context), + orientation: MediaQuery.orientationOf(context), + alwaysUse24HourFormat: MediaQuery.alwaysUse24HourFormatOf(context), + ); - return StoreConnector( - distinct: true, - converter: (store) => PageMediaViewModel.fromStore(store), - builder: (context, viewModel) { - MediaQueryData media = MediaQuery.of(context); - if (media.size != viewModel.size) { - _onScreenSizeChanged( - viewModel.isRegistered, media.size, viewModel.dispatch); - } else { - debugPrint("Page size did not change."); - } - if (media.platformBrightness != viewModel.displayBrightness) { - _onScreenBrightnessChanged( - media.platformBrightness, viewModel.dispatch); - } else { - debugPrint("Page brightness did not change."); - } + if (newMedia != backend.media || !pageSizeUpdated) { + _onMediaChanged(newMedia); + } - var newMdeia = PageMediaData( - padding: PaddingData(media.padding), - viewPadding: PaddingData(media.viewPadding), - viewInsets: PaddingData(media.viewInsets)); + var pageSize = MediaQuery.sizeOf(context); + if (pageSize != backend.pageSize) { + _onPageSizeChanged(pageSizeUpdated, pageSize); + } + }); - if (newMdeia != viewModel.media) { - _onMediaChanged(newMdeia, viewModel.dispatch); - } else { - debugPrint("Page media data did not change."); - } - return const SizedBox.shrink(); - }); + return const SizedBox.shrink(); } } diff --git a/packages/flet/lib/src/widgets/reorderable_item_scope.dart b/packages/flet/lib/src/widgets/reorderable_item_scope.dart new file mode 100644 index 0000000000..3ed2243e75 --- /dev/null +++ b/packages/flet/lib/src/widgets/reorderable_item_scope.dart @@ -0,0 +1,19 @@ +import 'package:flutter/widgets.dart'; + +class ReorderableItemScope extends InheritedWidget { + const ReorderableItemScope({ + super.key, + required this.index, + required super.child, + }); + + final int index; + + static ReorderableItemScope? of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + @override + bool updateShouldNotify(ReorderableItemScope oldWidget) => + oldWidget.index != index; +} diff --git a/packages/flet/lib/src/widgets/skip_inherited_notifier.dart b/packages/flet/lib/src/widgets/skip_inherited_notifier.dart new file mode 100644 index 0000000000..762220d6cc --- /dev/null +++ b/packages/flet/lib/src/widgets/skip_inherited_notifier.dart @@ -0,0 +1 @@ +abstract class SkipInheritedNotifier {} diff --git a/packages/flet/lib/src/widgets/window_media.dart b/packages/flet/lib/src/widgets/window_media.dart deleted file mode 100644 index 750b7ceec4..0000000000 --- a/packages/flet/lib/src/widgets/window_media.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:window_manager/window_manager.dart'; - -import '../actions.dart'; -import '../flet_app_services.dart'; -import '../utils/desktop.dart'; - -class WindowMedia extends StatefulWidget { - final dynamic dispatch; - const WindowMedia({super.key, required this.dispatch}); - - @override - // ignore: library_private_types_in_public_api - WindowMediaState createState() => WindowMediaState(); -} - -class WindowMediaState extends State with WindowListener { - @override - void initState() { - super.initState(); - windowManager.addListener(this); - } - - @override - void dispose() { - windowManager.removeListener(this); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return const SizedBox.shrink(); - } - - @override - void onWindowEvent(String eventName) { - //debugPrint('START [WindowManager] onWindowEvent: $eventName'); - - if (eventName == "resize" || eventName == "move") { - return; - } - - debugPrint('[WindowManager] onWindowEvent: $eventName'); - getWindowMediaData().then((wmd) { - debugPrint("WindowMediaData: $wmd"); - widget.dispatch!(WindowEventAction( - eventName, wmd, FletAppServices.of(context).server)); - }); - } -} diff --git a/packages/flet/pubspec.yaml b/packages/flet/pubspec.yaml index c941386330..798d5eb018 100644 --- a/packages/flet/pubspec.yaml +++ b/packages/flet/pubspec.yaml @@ -1,10 +1,10 @@ name: flet description: Write entire Flutter app in Python or add server-driven UI experience into existing Flutter app. homepage: https://flet.dev -repository: https://github.com/flet-dev/flet/packages/flet -version: 0.28.3 +repository: https://github.com/flet-dev/flet/tree/main/packages/flet +version: 0.85.1 -# This package supports all platforms listed below. +# Supported platforms platforms: android: ios: @@ -21,37 +21,41 @@ dependencies: sdk: flutter flutter_localizations: sdk: flutter - - redux: ^5.0.0 - flutter_redux: ^0.10.0 + battery_plus: ^7.0.0 + collection: ^1.19.0 + connectivity_plus: ^7.0.0 + cupertino_icons: ^1.0.6 + device_info_plus: ^12.3.0 equatable: ^2.0.3 - web_socket_channel: ^2.4.0 - window_manager: ^0.4.3 - http: ^1.2.2 - collection: ^1.16.0 - url_launcher: ^6.3.1 - flutter_markdown: ^0.7.4+1 + file_picker: ^10.3.10 flutter_highlight: ^0.7.0 + flutter_markdown_plus: ^1.0.7 + flutter_markdown_plus_latex: ^1.0.5 + flutter_svg: ^2.2.1 highlight: ^0.7.0 - markdown: ^7.2.2 - file_picker: ^10.1.9 - shared_preferences: ^2.3.2 - flutter_svg: ^2.0.13 + http: ^1.5.0 + markdown: ^7.3.0 + msgpack_dart: ^1.0.1 + package_info_plus: ^9.0.0 + path: ^1.9.0 + path_provider: ^2.1.5 + pasteboard: ^0.4.0 + provider: ^6.1.2 + screenshot: ^3.0.0 + screen_brightness: ^2.1.7 + sensors_plus: ^7.0.0 + shared_preferences: ^2.5.3 + share_plus: ^12.0.1 + shimmer: ^3.0.0 + url_launcher: ^6.3.2 + vector_math: ^2.2.0 + web: ^1.1.1 + web_socket_channel: ^3.0.2 + window_manager: ^0.5.1 window_to_front: ^0.0.3 - sensors_plus: ^4.0.2 - path: ^1.8.2 - js: ^0.6.5 - fl_chart: ^0.69.0 - device_info_plus: ^11.2.0 + wakelock_plus: ^1.4.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^3.0.1 - -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg diff --git a/packages/flet/test/controls/control_test.dart b/packages/flet/test/controls/control_test.dart deleted file mode 100644 index ae83a59118..0000000000 --- a/packages/flet/test/controls/control_test.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/models/control.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("Two controls are equal", () { - Control c1 = Control( - id: "i1", - pid: "p1", - type: "stack", - name: null, - childIds: const ["txt1", "btn1"], - attrs: const {"text": "Hello!", "width": "200"}); - - Control c2 = Control( - id: "i1", - pid: "p1", - type: "stack", - name: null, - childIds: const ["txt1", "btn1"], - attrs: const {"width": "200", "text": "Hello!"}); - - expect(c1 == c2, true); - }); - - test('Deserialize control', () { - const t1 = '''{ - "t": "stack", - "p": "", - "i": "s1", - "n": "content", - "c": ["txt1", "txt2"], - "at": "0", - "value": "Hello, world!" - }'''; - - final j1 = json.decode(t1); - final c1 = Control.fromJson(j1); - - expect(c1.id, "s1"); - expect(c1.pid, ""); - expect(c1.type, "stack"); - expect(c1.name, "content"); - expect(c1.childIds, ["txt1", "txt2"]); - expect(c1.attrs.length, 2); - expect(c1.attrs["at"], "0"); - expect(c1.attrs["value"], "Hello, world!"); - }); -} diff --git a/packages/flet/test/models/linechart_event_data_test.dart b/packages/flet/test/models/linechart_event_data_test.dart deleted file mode 100644 index 9cff525e26..0000000000 --- a/packages/flet/test/models/linechart_event_data_test.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/controls/linechart.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("Test LinechartEventData equality", () { - var e1 = const LineChartEventData(eventType: "Hover", barSpots: [ - LineChartEventDataSpot(barIndex: 0, spotIndex: 1), - LineChartEventDataSpot(barIndex: 1, spotIndex: 1) - ]); - var e2 = const LineChartEventData(eventType: "Hover", barSpots: [ - LineChartEventDataSpot(barIndex: 0, spotIndex: 1), - LineChartEventDataSpot(barIndex: 1, spotIndex: 1) - ]); - expect(e1 == e2, true); - }); - - test("Test LinechartEventData inequality", () { - var e1 = const LineChartEventData(eventType: "Hover", barSpots: [ - LineChartEventDataSpot(barIndex: 0, spotIndex: 0), - LineChartEventDataSpot(barIndex: 1, spotIndex: 0) - ]); - var e2 = const LineChartEventData(eventType: "Hover", barSpots: [ - LineChartEventDataSpot(barIndex: 0, spotIndex: 1), - LineChartEventDataSpot(barIndex: 1, spotIndex: 1) - ]); - expect(e1 == e2, false); - }); - - test("LinechartEventData serialize to json", () { - var e = const LineChartEventData(eventType: "Hover", barSpots: [ - LineChartEventDataSpot(barIndex: 0, spotIndex: 1), - LineChartEventDataSpot(barIndex: 1, spotIndex: 1) - ]); - - final j = json.encode(e); - - expect(j, - '{"type":"Hover","spots":[{"bar_index":0,"spot_index":1},{"bar_index":1,"spot_index":1}]}'); - }); -} diff --git a/packages/flet/test/protocol/add_page_controls_payload_test.dart b/packages/flet/test/protocol/add_page_controls_payload_test.dart deleted file mode 100644 index 0ecaf5bfc3..0000000000 --- a/packages/flet/test/protocol/add_page_controls_payload_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/add_page_controls_payload.dart'; - -void main() { - test("AddPageControlsPayload payload deserialized", () { - const myJsonAsString = '''{ - "trimIDs": ["c1", "c2"], - "controls": [ - { - "i": "txt1", - "t": "text", - "p": "page", - "c": [], - "value": "Text A" - }, - { - "i": "stack1", - "t": "stack", - "p": "page", - "c": ["txt2"], - "align": "center" - } - ]}'''; - - final s = AddPageControlsPayload.fromJson(json.decode(myJsonAsString)); - expect(s.trimIDs.length, 2); - expect(s.controls.length, 2); - }); -} diff --git a/packages/flet/test/protocol/app_become_inactive_payload_test.dart b/packages/flet/test/protocol/app_become_inactive_payload_test.dart deleted file mode 100644 index 80c3fda579..0000000000 --- a/packages/flet/test/protocol/app_become_inactive_payload_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/app_become_inactive_payload.dart'; - -void main() { - test("AppBecomeInactivePayload payload deserialized", () { - const myJsonAsString = '''{ - "message": "Application is inactive." - }'''; - - final s = AppBecomeInactivePayload.fromJson(json.decode(myJsonAsString)); - expect(s.message, "Application is inactive."); - }); -} diff --git a/packages/flet/test/protocol/append_control_props_payload_test.dart b/packages/flet/test/protocol/append_control_props_payload_test.dart deleted file mode 100644 index 344f27b2ff..0000000000 --- a/packages/flet/test/protocol/append_control_props_payload_test.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/append_control_props_request.dart'; - -void main() { - test("AppendControlPropsPayload payload deserialized", () { - const myJsonAsString = '''{ - "props": [ - { - "i": "txt1", - "value": "Text A" - }, - { - "i": "stack1", - "align": "center" - } - ]}'''; - - final s = AppendControlPropsPayload.fromJson(json.decode(myJsonAsString)); - expect(s.props.length, 2); - }); -} diff --git a/packages/flet/test/protocol/clean_control_payload_test.dart b/packages/flet/test/protocol/clean_control_payload_test.dart deleted file mode 100644 index a2141592b9..0000000000 --- a/packages/flet/test/protocol/clean_control_payload_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/clean_control_payload.dart'; - -void main() { - test("CleanControlPayload payload deserialized", () { - const myJsonAsString = '''{ - "ids": ["c1", "c2"] - }'''; - - final s = CleanControlPayload.fromJson(json.decode(myJsonAsString)); - expect(s.ids.length, 2); - }); -} diff --git a/packages/flet/test/protocol/message_test.dart b/packages/flet/test/protocol/message_test.dart deleted file mode 100644 index 6c49345a1e..0000000000 --- a/packages/flet/test/protocol/message_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/message.dart'; -import 'package:flet/src/protocol/remove_control_payload.dart'; - -void main() { - test("Message parse from JSON", () { - const s = ''' - { - "action": "removeControl", - "payload": { - "ids": ["i1", "i2"] - } - } -'''; - - final m = Message.fromJson(json.decode(s)); - expect(m.action, MessageAction.removeControl); - - if (m.action == MessageAction.removeControl) { - final payload = RemoveControlPayload.fromJson(m.payload); - expect(payload.ids.length, 2); - } - }); -} diff --git a/packages/flet/test/protocol/page_controls_batch_payload_test.dart b/packages/flet/test/protocol/page_controls_batch_payload_test.dart deleted file mode 100644 index f9a15494c1..0000000000 --- a/packages/flet/test/protocol/page_controls_batch_payload_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/protocol/page_controls_batch_payload.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("PageControlsBatchPayload serialize to message", () { - const myJsonAsString = '''[ - {"action":"updateControlProps","payload":{"props":[{"i":"page","width":"100","height":"200"},{"i":"txt1","value":"Hello, world!"}]}}, - {"action":"removeControl","payload":{"ids":["a1", "b2"]}} - ] - '''; - - final s = PageControlsBatchPayload.fromJson(json.decode(myJsonAsString)); - expect(s.messages.length, 2); - }); -} diff --git a/packages/flet/test/protocol/page_event_from_web_request_test.dart b/packages/flet/test/protocol/page_event_from_web_request_test.dart deleted file mode 100644 index 410a465257..0000000000 --- a/packages/flet/test/protocol/page_event_from_web_request_test.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/message.dart'; -import 'package:flet/src/protocol/page_event_from_web_request.dart'; - -void main() { - test("PageEventFromWebRequest serialize to message", () { - final m = Message( - action: MessageAction.pageEventFromWeb, - payload: PageEventFromWebRequest( - eventTarget: "page", eventName: "resize", eventData: "100x200")); - - final j = json.encode(m); - - expect(j, - '{"action":"pageEventFromWeb","payload":{"eventTarget":"page","eventName":"resize","eventData":"100x200"}}'); - }); -} diff --git a/packages/flet/test/protocol/register_webclient_payload_test.dart b/packages/flet/test/protocol/register_webclient_payload_test.dart deleted file mode 100644 index 255aa33d4d..0000000000 --- a/packages/flet/test/protocol/register_webclient_payload_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/session_payload.dart'; - -void main() { - test("Session payload deserialized", () { - const myJsonAsString = '''{ - "id": "session-1234", - "controls": { - "page": { - "t": "page", - "p": "", - "i": "page", - "c": [] - } - }}'''; - - final s = SessionPayload.fromJson(json.decode(myJsonAsString)); - expect(s.id, 'session-1234'); - }); -} diff --git a/packages/flet/test/protocol/register_webclient_request_test.dart b/packages/flet/test/protocol/register_webclient_request_test.dart deleted file mode 100644 index 278637896e..0000000000 --- a/packages/flet/test/protocol/register_webclient_request_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/protocol/message.dart'; -import 'package:flet/src/protocol/register_webclient_request.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("RegisterWebClientRequest serialize to message", () { - final m = Message( - action: MessageAction.registerWebClient, - payload: RegisterWebClientRequest(pageName: "test-page1")); - - final j = json.encode(m); - expect(j, - '{"action":"registerWebClient","payload":{"pageName":"test-page1","pageRoute":null,"pageWidth":null,"pageHeight":null,"windowWidth":null,"windowHeight":null,"windowTop":null,"windowLeft":null,"isPWA":null,"isWeb":null,"isDebug":null,"platform":null,"platformBrightness":null,"media":null,"sessionId":null}}'); - }); -} diff --git a/packages/flet/test/protocol/register_webclient_response_test.dart b/packages/flet/test/protocol/register_webclient_response_test.dart deleted file mode 100644 index c34da02701..0000000000 --- a/packages/flet/test/protocol/register_webclient_response_test.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/protocol/register_webclient_response.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("RegisterWebClientResponse with session deserialized", () { - const myJsonAsString = '''{ - "appInactive": false, - "session": { - "id": "session-1234", - "controls": { - "page": { - "i": "page", - "t": "page", - "p": "", - "c": ["txt1", "stack1"], - "hash": "aaa" - } - } - }}'''; - - final s = RegisterWebClientResponse.fromJson(json.decode(myJsonAsString)); - expect(s.session!.id, 'session-1234'); - expect(s.session!.controls.length, 1); - }); - - test("RegisterWebClientResponse with error deserialized", () { - const myJsonAsString = '''{ - "error": "Page does not exist", - "appInactive": false, - "session": null - }'''; - - final s = RegisterWebClientResponse.fromJson(json.decode(myJsonAsString)); - expect(s.session == null, true); - expect(s.error, "Page does not exist"); - }); -} diff --git a/packages/flet/test/protocol/remove_control_payload_test.dart b/packages/flet/test/protocol/remove_control_payload_test.dart deleted file mode 100644 index cdbfc76bd1..0000000000 --- a/packages/flet/test/protocol/remove_control_payload_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/remove_control_payload.dart'; - -void main() { - test("RemoveControlPayload payload deserialized", () { - const myJsonAsString = '''{ - "ids": ["c1", "c2"] - }'''; - - final s = RemoveControlPayload.fromJson(json.decode(myJsonAsString)); - expect(s.ids.length, 2); - }); -} diff --git a/packages/flet/test/protocol/replace_page_controls_payload_test.dart b/packages/flet/test/protocol/replace_page_controls_payload_test.dart deleted file mode 100644 index 5c584160a3..0000000000 --- a/packages/flet/test/protocol/replace_page_controls_payload_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/replace_page_controls_payload.dart'; - -void main() { - test("ReplacePageControlsPayload payload deserialized", () { - const myJsonAsString = '''{ - "remove": true, - "ids": ["c1", "c2"], - "controls": [ - { - "i": "txt1", - "t": "text", - "p": "page", - "c": [], - "value": "Text A" - }, - { - "i": "stack1", - "t": "stack", - "p": "page", - "c": ["txt2"], - "align": "center" - } - ]}'''; - - final s = ReplacePageControlsPayload.fromJson(json.decode(myJsonAsString)); - expect(s.ids.length, 2); - expect(s.controls.length, 2); - expect(s.remove, true); - }); -} diff --git a/packages/flet/test/protocol/session_crashed_payload_test.dart b/packages/flet/test/protocol/session_crashed_payload_test.dart deleted file mode 100644 index 2e85be44f1..0000000000 --- a/packages/flet/test/protocol/session_crashed_payload_test.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/session_crashed_payload.dart'; - -void main() { - test("SessionCrashedPayload payload deserialized", () { - const myJsonAsString = '''{ - "message": "Error while processing request!" - }'''; - - final s = SessionCrashedPayload.fromJson(json.decode(myJsonAsString)); - expect(s.message, "Error while processing request!"); - }); -} diff --git a/packages/flet/test/protocol/session_payload_test.dart b/packages/flet/test/protocol/session_payload_test.dart deleted file mode 100644 index 16bd52a8f8..0000000000 --- a/packages/flet/test/protocol/session_payload_test.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/session_payload.dart'; - -void main() { - test("Session payload deserialized", () { - const myJsonAsString = '''{ - "id": "session-1234", - "controls": { - "page": { - "i": "page", - "t": "page", - "p": "", - "c": ["txt1", "stack1"], - "hash": "aaa" - }, - "txt1": { - "i": "txt1", - "t": "text", - "p": "page", - "c": [], - "value": "Text A" - }, - "stack1": { - "i": "stack1", - "t": "stack", - "p": "page", - "c": ["txt2"], - "align": "center" - }, - "txt2": { - "i": "txt2", - "t": "text", - "p": "stack1", - "c": [], - "value": "Text B", - "color": "red" - } - }}'''; - - final s = SessionPayload.fromJson(json.decode(myJsonAsString)); - expect(s.id, 'session-1234'); - expect(s.controls.length, 4); - expect(s.controls['page']!.attrs.length, 1); - expect(s.controls['txt1']!.attrs.length, 1); - expect(s.controls['stack1']!.attrs.length, 1); - expect(s.controls['txt2']!.attrs.length, 2); - expect(s.controls['txt2']!.attrs["color"], "red"); - expect(s.controls['txt2']!.attrs["value"], "Text B"); - }); -} diff --git a/packages/flet/test/protocol/update_control_props_payload_test.dart b/packages/flet/test/protocol/update_control_props_payload_test.dart deleted file mode 100644 index 1b578c7534..0000000000 --- a/packages/flet/test/protocol/update_control_props_payload_test.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:flet/src/protocol/update_control_props_payload.dart'; - -void main() { - test("UpdateControlPropsPayload payload deserialized", () { - const myJsonAsString = '''{ - "props": [ - { - "i": "txt1", - "value": "Text A" - }, - { - "i": "stack1", - "align": "center" - } - ]}'''; - - final s = UpdateControlPropsPayload.fromJson(json.decode(myJsonAsString)); - expect(s.props.length, 2); - }); -} diff --git a/packages/flet/test/protocol/update_control_props_request_test.dart b/packages/flet/test/protocol/update_control_props_request_test.dart deleted file mode 100644 index 4ef30d02c9..0000000000 --- a/packages/flet/test/protocol/update_control_props_request_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/protocol/message.dart'; -import 'package:flet/src/protocol/update_control_props_request.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("UpdateControlPropsRequest serialize to message", () { - final m = Message( - action: MessageAction.updateControlProps, - payload: UpdateControlPropsRequest(props: [ - {"i": "page", "width": "100", "height": "200"}, - {"i": "txt1", "value": "Hello, world!"}, - ])); - - final j = json.encode(m); - - expect(j, - '{"action":"updateControlProps","payload":{"props":[{"i":"page","width":"100","height":"200"},{"i":"txt1","value":"Hello, world!"}]}}'); - }); -} diff --git a/packages/flet/test/utils/control_test.dart b/packages/flet/test/utils/control_test.dart new file mode 100644 index 0000000000..7e7acedeaf --- /dev/null +++ b/packages/flet/test/utils/control_test.dart @@ -0,0 +1,99 @@ +import 'package:flet/flet.dart'; +import 'package:flutter_test/flutter_test.dart'; + +var backend = FletBackend( + pageUri: Uri.parse("uri"), assetsDir: "", extensions: [], multiView: false); + +void main() { + test("Both controls must be equal", () { + var c1 = Control( + id: 1, + type: "Button", + properties: { + "a": 1, + "b": 2, + "c": {"c_0": "test"} + }, + backend: backend); + var c2 = Control( + id: 1, + type: "Button", + properties: { + "a": 1, + "b": 2, + "c": {"c_0": "test"} + }, + backend: backend); + expect(c1 == c2, true); + }); + + test("Update control with a Map", () { + var c1 = Control( + id: 1, + type: "Button", + properties: { + "a": 1, + "b": 2, + "c": {"c_0": "test"} + }, + backend: backend); + bool changed = c1.update({ + "a": 10, + "d": true, + "c": {"c_0": "test_2", "sub_1": "something"} + }); + expect(changed, true); + expect(c1.properties["a"] == 10, true); + expect(c1.properties["b"] == 2, true); + expect(c1.properties["d"], true); + expect(c1.properties["c"]["c_0"] == "test_2", true); + expect(c1.properties["c"]["sub_1"] == "something", true); + }); + + test("updateControl did not change control", () { + var a1 = Control( + id: 1, + type: "Button", + properties: { + "a": 1, + "b": 2, + "c": {"c_0": "test"} + }, + backend: backend); + bool changed = a1.update({ + "a": 1, + "b": 2, + "c": {"c_0": "test"} + }); + expect(changed, false); + }); + + test("updateControl on 1st level changed control", () { + var a1 = Control( + id: 1, + type: "Button", + properties: { + "a": 1, + }, + backend: backend); + bool changed = a1.update({ + "a": 2, + }); + expect(changed, true); + }); + + test("updateControl on 2nd level changed control", () { + var a1 = Control( + id: 1, + type: "Button", + properties: { + "a": 1, + "c": {"c_0": "test"} + }, + backend: backend); + bool changed = a1.update({ + "c": {"c_0": "changed!"} + }); + expect(changed, true); + }); +} diff --git a/packages/flet/test/utils/images_test.dart b/packages/flet/test/utils/images_test.dart new file mode 100644 index 0000000000..f74064d150 --- /dev/null +++ b/packages/flet/test/utils/images_test.dart @@ -0,0 +1,64 @@ +import 'package:flet/src/utils/images_web.dart' as web; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group("getAssetSrc (web) — URL scheme pass-through", () { + final pageUri = Uri.parse("http://localhost:8550/"); + const assetsDir = "/assets"; + + test("http URLs pass through", () { + expect(web.getAssetSrc("http://example.com/a.png", pageUri, assetsDir).path, + "http://example.com/a.png"); + }); + + test("https URLs pass through", () { + expect( + web.getAssetSrc("https://example.com/a.png", pageUri, assetsDir).path, + "https://example.com/a.png"); + }); + + test("data URLs pass through", () { + expect(web.getAssetSrc("data:image/png;base64,iVBO", pageUri, assetsDir).path, + "data:image/png;base64,iVBO"); + }); + + test("blob URLs pass through", () { + expect(web.getAssetSrc("blob:http://x/abc", pageUri, assetsDir).path, + "blob:http://x/abc"); + }); + + test("rtsp URLs pass through (media_kit streaming)", () { + expect(web.getAssetSrc("rtsp://cam.local/stream", pageUri, assetsDir).path, + "rtsp://cam.local/stream"); + }); + + test("rtmp URLs pass through", () { + expect(web.getAssetSrc("rtmp://x/y", pageUri, assetsDir).path, "rtmp://x/y"); + }); + + test("srt URLs pass through", () { + expect(web.getAssetSrc("srt://x:1234", pageUri, assetsDir).path, + "srt://x:1234"); + }); + + test("udp URLs pass through", () { + expect(web.getAssetSrc("udp://239.0.0.1:5000", pageUri, assetsDir).path, + "udp://239.0.0.1:5000"); + }); + + test("file URLs pass through", () { + expect(web.getAssetSrc("file:///tmp/x.mp4", pageUri, assetsDir).path, + "file:///tmp/x.mp4"); + }); + + test("relative paths are resolved against assetsDir", () { + expect(web.getAssetSrc("images/a.png", pageUri, assetsDir).path, + "/assets/images/a.png"); + }); + + test("leading-slash relative paths are resolved against assetsDir", () { + expect(web.getAssetSrc("/images/a.png", pageUri, assetsDir).path, + "/assets/images/a.png"); + }); + }); +} diff --git a/packages/flet/test/utils/theme_test.dart b/packages/flet/test/utils/theme_test.dart deleted file mode 100644 index 60e40ccb67..0000000000 --- a/packages/flet/test/utils/theme_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:convert'; - -import 'package:flet/src/utils/theme.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test("Light theme is parsed correctly from JSON", () { - const t1 = '''{ - "color_scheme_seed": "red", - "brightness": "light", - "use_material3": false - }'''; - - final j1 = json.decode(t1); - var theme = themeFromJson(j1, Brightness.light, null); - - expect(theme.brightness, Brightness.light); - expect(theme.useMaterial3, false); - expect(theme.primaryColor, const Color(0xff904a42)); - }); - - test("Dark theme is parsed correctly from JSON", () { - const t1 = '''{ - "color_scheme_seed": "cyan", - "brightness": "dark" - }'''; - - final j1 = json.decode(t1); - var theme = themeFromJson(j1, Brightness.dark, null); - - expect(theme.brightness, Brightness.dark); - expect(theme.useMaterial3, true); - expect(theme.primaryColor, const Color(0xff0e1416)); - }); -} diff --git a/packages/flet/test/utils/user_fonts_test.dart b/packages/flet/test/utils/user_fonts_test.dart index 6491406117..3e21adc958 100644 --- a/packages/flet/test/utils/user_fonts_test.dart +++ b/packages/flet/test/utils/user_fonts_test.dart @@ -1,17 +1,14 @@ -import 'dart:convert'; - import 'package:flet/src/utils/user_fonts.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { test("Custom fonts are parsed from JSON", () { - const t1 = '''{ - "font1": "https://fonts.com/font1.ttf", - "font2": "https://fonts.com/font2.ttf" - }'''; + const t1 = { + "font1": "https://fonts.com/font1.ttf", + "font2": "https://fonts.com/font2.ttf" + }; - final j1 = json.decode(t1); - var fonts = fontsFromJson(j1); + var fonts = parseFonts(t1)!; expect(fonts.length, 2); expect(fonts["font1"], "https://fonts.com/font1.ttf"); diff --git a/sdk/python/.docstr.yaml b/sdk/python/.docstr.yaml new file mode 100644 index 0000000000..48d28acc12 --- /dev/null +++ b/sdk/python/.docstr.yaml @@ -0,0 +1,13 @@ +skip_magic: true # Ignore __*__ methods except __init__ +skip_init: true # Also ignore __init__ +skip_file_doc: true +skip_private: false +ignore_patterns: + .*: + - init + - before_update + - before_event + - build + - main + - _migrate_state +fail_under: 50 diff --git a/sdk/python/.gitignore b/sdk/python/.gitignore index c69beef22e..95e258d640 100644 --- a/sdk/python/.gitignore +++ b/sdk/python/.gitignore @@ -9,6 +9,7 @@ __pycache__/ # Distribution / packaging .Python build/ +!templates/build/ develop-eggs/ dist/ downloads/ @@ -90,6 +91,7 @@ ipython_config.py # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock +uv.lock # celery beat schedule file celerybeat-schedule @@ -113,9 +115,6 @@ venv.bak/ # Rope project settings .ropeproject -# mkdocs documentation -/site - # mypy .mypy_cache/ .dmypy.json @@ -134,4 +133,6 @@ __pypackages__/ # bin flet/bin/ -playground/ \ No newline at end of file +# flet +playground/ +packages/flet/site/ diff --git a/sdk/python/.pre-commit-config.yaml b/sdk/python/.pre-commit-config.yaml index 63597e2671..9a0bd650d0 100644 --- a/sdk/python/.pre-commit-config.yaml +++ b/sdk/python/.pre-commit-config.yaml @@ -1,15 +1,31 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.7 + rev: v0.14.13 hooks: # Run the linter. - id: ruff args: [ --fix ] + exclude: (^\.github/|/templates/) # Run the formatter. - id: ruff-format + exclude: (^\.github/|/templates/) + + - repo: https://github.com/aio-libs/sort-all + rev: v1.3.0 + hooks: + - id: sort-all - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: end-of-file-fixer + exclude: /templates/ - id: trailing-whitespace + exclude: /templates/ + + - repo: https://github.com/crate-ci/typos + rev: v1.43.4 + hooks: + - id: typos + args: [ --config, sdk/python/_typos.toml ] + exclude: /templates/ diff --git a/sdk/python/README.md b/sdk/python/README.md index 583c0c4b05..e9b9b67745 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -4,8 +4,7 @@ Package relationships: ```mermaid graph TD; - flet-core-->flet-runtime; - flet-core-->flet-pyodide; - flet-runtime-->flet-embed; - flet-runtime-->flet; -``` \ No newline at end of file + flet --> flet-cli; + flet --> flet-desktop; + flet --> flet-web; +``` diff --git a/sdk/python/Taskfile.yml b/sdk/python/Taskfile.yml new file mode 100644 index 0000000000..7fefbec623 --- /dev/null +++ b/sdk/python/Taskfile.yml @@ -0,0 +1,111 @@ +# Docs: https://taskfile.dev/installation/ + +version: '3' +# includes: +tasks: + list: + desc: "Lists all available tasks." + aliases: + - ls + - help + - tasks + cmds: + - task --list + + setup: + desc: "Setup/Sync environment by installing all Python dependencies and pre-commit hooks." + aliases: + - sync + cmds: + - uv sync --group all + - task: pre-commit + + venv: + desc: "Initialize virtual environment." + cmds: + - uv venv + + pre-commit: + desc: "Install pre-commit hooks." + aliases: + - pc + - sync-pc + cmds: + - uv run pre-commit install + + pre-commit-run: + desc: "Run pre-commit hooks on all files of the repo." + aliases: + - run-pc + cmds: + - uv run pre-commit run --all-files + + pre-commit-update: + desc: "Upgrade versions of repos in .pre-commit-config.yaml to their latest." + aliases: + - update-pc + cmds: + - uv run pre-commit autoupdate + + unit-tests: + desc: "Run all unit tests." + aliases: + - test + - utest + - unit-test + cmds: + - uv run --group test pytest packages/flet/tests + + integration-tests: + desc: "Run all integration tests. (can take a long while)" + aliases: + - itest + - integration-test + cmds: + - uv run --group test pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests + + serve-docs: + desc: "Start Docusaurus dev server for the documentation website with hot reload." + aliases: + - docs + cmds: + - cd ../../website && yarn install --immutable + - cd ../../website && yarn start + + serve-docs-fast: + desc: "Same as serve-docs, but skips Ruff signature formatting (FLET_DOCS_FAST=1) for faster iteration." + aliases: + - docs-fast + env: + FLET_DOCS_FAST: "1" + cmds: + - cd ../../website && yarn install --immutable + - cd ../../website && yarn start + + docs-coverage: + desc: "Run docstring coverage report for all SDK Python packages." + cmds: + - | + status=0 + for pkg in packages/*; do + if [ -f "$pkg/pyproject.toml" ] && [ -d "$pkg/src" ]; then + pkg_name=$(basename "$pkg") + echo "====== $pkg ======" + uv run --group docs-coverage docstr-coverage -C .docstr.yaml "$pkg/src" --badge="../../website/static/docs/assets/badges/docs-coverage/${pkg_name}.svg" || status=$? + echo + fi + done + exit $status + + docs-coverage-flet: + desc: "Run docstring coverage report for 'flet' package only." + cmds: + - uv run --group docs-coverage docstr-coverage -C .docstr.yaml packages/flet/src --badge="../../website/static/docs/assets/badges/docs-coverage/flet.svg" + + free-port-8550: + desc: "Frees Unix port 8550 by killing any process using it. Useful when you receive 'Address already in use' error." + prompt: "This will kill any process using port 8550. Do you want to continue?" + aliases: + - free-8550 + cmds: + - kill -9 $(lsof -ti :8550) diff --git a/sdk/python/_typos.toml b/sdk/python/_typos.toml new file mode 100644 index 0000000000..e68027a320 --- /dev/null +++ b/sdk/python/_typos.toml @@ -0,0 +1,6 @@ +[default.extend-words] +# AAC High Efficiency audio codec enum member name +AACHE = "AACHE" +ROUTEROS = "ROUTEROS" +# OpenType variable font axis tag for width +wdth = "wdth" diff --git a/sdk/python/examples/.gitignore b/sdk/python/examples/.gitignore new file mode 100644 index 0000000000..4badf06e0b --- /dev/null +++ b/sdk/python/examples/.gitignore @@ -0,0 +1,134 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# VS Code +.vscode/ + +# PDM +.pdm.toml +__pypackages__/ + +# bin +flet/bin/ + +/playground diff --git a/sdk/python/examples/README.md b/sdk/python/examples/README.md new file mode 100644 index 0000000000..88ef9e9e26 --- /dev/null +++ b/sdk/python/examples/README.md @@ -0,0 +1,10 @@ +# Flet examples + +Contains Flet sample applications you can use to learn Flet or +as a starting point for your own great apps. + +## Commands + +``` +uv run flet run controls/buttons/elevated-button/basic-elevated-buttons.py +``` diff --git a/sdk/python/examples/__init__.py b/sdk/python/examples/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/examples/apps/7guis/cells/main.py b/sdk/python/examples/apps/7guis/cells/main.py new file mode 100644 index 0000000000..def7ceac2f --- /dev/null +++ b/sdk/python/examples/apps/7guis/cells/main.py @@ -0,0 +1,232 @@ +import ast +import re + +import flet as ft + +ROWS = range(1, 5) +COLUMNS = ("A", "B", "C", "D") +CELL_REF_RE = re.compile(r"\b([A-D][1-4])\b") + + +INITIAL_FORMULAS = { + "A1": "12", + "B1": "8", + "C1": "=A1+B1", + "A2": "3", + "B2": "=C1/2", + "D4": "=A1+A2+B1", +} + + +class FormulaError(Exception): + pass + + +def format_value(value: object) -> str: + if value == "": + return "" + if isinstance(value, (int, float)): + rounded = round(float(value), 2) + if rounded.is_integer(): + return str(int(rounded)) + return f"{rounded:.2f}".rstrip("0").rstrip(".") + return str(value) + + +def evaluate_expression(node: ast.AST) -> float: + if isinstance(node, ast.Expression): + return evaluate_expression(node.body) + if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)): + return float(node.value) + if isinstance(node, ast.UnaryOp) and isinstance(node.op, (ast.UAdd, ast.USub)): + value = evaluate_expression(node.operand) + return value if isinstance(node.op, ast.UAdd) else -value + if isinstance(node, ast.BinOp) and isinstance( + node.op, (ast.Add, ast.Sub, ast.Mult, ast.Div) + ): + left = evaluate_expression(node.left) + right = evaluate_expression(node.right) + if isinstance(node.op, ast.Add): + return left + right + if isinstance(node.op, ast.Sub): + return left - right + if isinstance(node.op, ast.Mult): + return left * right + return left / right + raise FormulaError("Only +, -, *, / and parentheses are supported.") + + +def main(page: ft.Page): + page.title = "7GUIs - Cells" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.scroll = ft.ScrollMode.AUTO + page.theme_mode = ft.ThemeMode.LIGHT + + formulas = INITIAL_FORMULAS.copy() + selected_cell = "A1" + + def evaluate_cell( + cell_id: str, cache: dict[str, object], stack: set[str] + ) -> object: + if cell_id in cache: + return cache[cell_id] + if cell_id in stack: + raise FormulaError("Circular reference detected.") + + raw = formulas.get(cell_id, "").strip() + if raw == "": + cache[cell_id] = "" + return "" + + if not raw.startswith("="): + try: + value = float(raw) + except ValueError: + value = raw + cache[cell_id] = value + return value + + expression = raw[1:].upper() + + def replace_reference(match: re.Match[str]) -> str: + ref = match.group(1) + value = evaluate_cell(ref, cache, stack | {cell_id}) + if value == "": + return "0" + if isinstance(value, (int, float)): + return str(value) + raise FormulaError(f"{ref} is not numeric.") + + replaced = CELL_REF_RE.sub(replace_reference, expression) + try: + parsed = ast.parse(replaced, mode="eval") + except SyntaxError as exc: + raise FormulaError("Formula syntax is invalid.") from exc + + value = evaluate_expression(parsed) + cache[cell_id] = value + return value + + def display_value(cell_id: str) -> str: + try: + return format_value(evaluate_cell(cell_id, {}, set())) + except FormulaError: + return "#ERR" + except ZeroDivisionError: + return "#DIV/0" + + def select_cell(cell_id: str): + nonlocal selected_cell + selected_cell = cell_id + formula_field.value = formulas.get(cell_id, "") + refresh_ui() + + def apply_formula(e): + formulas[selected_cell] = formula_field.value.strip() + refresh_ui() + + def build_data_cell(cell_id: str) -> ft.DataCell: + is_selected = cell_id == selected_cell + return ft.DataCell( + show_edit_icon=True, + on_tap=lambda e, cell_id=cell_id: select_cell(cell_id), + content=ft.Container( + width=90, + padding=10, + border_radius=10, + bgcolor=ft.Colors.BLUE_100 if is_selected else ft.Colors.WHITE, + border=ft.Border.all( + 2 if is_selected else 1, + ft.Colors.BLUE_500 if is_selected else ft.Colors.BLACK_12, + ), + content=ft.Text( + display_value(cell_id) or " ", + weight=ft.FontWeight.W_600 if is_selected else None, + ), + ), + ) + + def build_table() -> ft.DataTable: + columns = [ft.DataColumn(label=ft.Text(""))] + columns.extend(ft.DataColumn(label=ft.Text(column)) for column in COLUMNS) + + rows: list[ft.DataRow] = [] + for row in ROWS: + cells = [ft.DataCell(ft.Text(str(row), weight=ft.FontWeight.W_600))] + for column in COLUMNS: + cell_id = f"{column}{row}" + cells.append(build_data_cell(cell_id)) + rows.append(ft.DataRow(cells=cells)) + + return ft.DataTable( + heading_row_color=ft.Colors.BLUE_GREY_50, + horizontal_lines=ft.border.BorderSide(1, ft.Colors.BLACK_12), + columns=columns, + rows=rows, + ) + + def refresh_ui(): + selected_label.value = f"Selected cell: {selected_cell}" + computed_label.value = f"Computed value: {display_value(selected_cell)}" + formula_field.value = formulas.get(selected_cell, "") + table_host.content = build_table() + page.update() + + page.add( + ft.SafeArea( + content=ft.Container( + width=760, + padding=28, + border_radius=24, + bgcolor=ft.Colors.GREEN_50, + alignment=ft.Alignment.CENTER, + content=ft.Column( + tight=True, + spacing=18, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text("Cells", size=28, weight=ft.FontWeight.W_700), + ft.Text( + "A small spreadsheet with cell references and live " + "recalculation.", + color=ft.Colors.BLUE_GREY_700, + ), + ft.Row( + vertical_alignment=ft.CrossAxisAlignment.END, + controls=[ + formula_field := ft.TextField( + label="Formula", + width=320, + value=formulas.get(selected_cell, ""), + on_submit=apply_formula, + ), + ft.FilledButton( + "Apply", + icon=ft.Icons.CHECK, + on_click=apply_formula, + ), + ], + ), + selected_label := ft.Text(weight=ft.FontWeight.W_700), + computed_label := ft.Text(color=ft.Colors.BLUE_GREY_700), + ft.Text( + "Use plain text, numbers, or expressions like =A1+B2/2.", + color=ft.Colors.BLUE_GREY_700, + ), + ft.Container( + padding=16, + border_radius=20, + bgcolor=ft.Colors.WHITE, + content=(table_host := ft.Container()), + ), + ], + ), + ) + ) + ) + refresh_ui() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/cells/pyproject.toml b/sdk/python/examples/apps/7guis/cells/pyproject.toml new file mode 100644 index 0000000000..715d573f36 --- /dev/null +++ b/sdk/python/examples/apps/7guis/cells/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-cells" +version = "1.0.0" +description = "7GUIs spreadsheet app with formula editing, cell references, and live recalculation." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "cells", "spreadsheet", "formulas"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs"] + +[tool.flet.metadata] +title = "Cells" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "TextField", "FilledButton", "DataTable", "DataColumn", "DataRow", "DataCell"] +layout_pattern = "data-grid" +complexity = "intermediate" +features = ["formula editing", "cell references", "live recalculation", "error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/7guis/circle_drawer/main.py b/sdk/python/examples/apps/7guis/circle_drawer/main.py new file mode 100644 index 0000000000..5466b7f912 --- /dev/null +++ b/sdk/python/examples/apps/7guis/circle_drawer/main.py @@ -0,0 +1,198 @@ +from dataclasses import dataclass + +import flet as ft + +DEFAULT_RADIUS = 28.0 +MIN_RADIUS = 12 +MAX_RADIUS = 90 + + +@dataclass +class Circle: + x: float + y: float + radius: float + + +def clone_circles(circles: list[Circle]) -> list[Circle]: + return [Circle(circle.x, circle.y, circle.radius) for circle in circles] + + +def main(page: ft.Page): + page.title = "7GUIs - Circle Drawer" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + history: list[list[Circle]] = [[]] + history_index = 0 + selected_index: int | None = None + + def get_circles() -> list[Circle]: + return history[history_index] + + def push_snapshot(new_state: list[Circle], select: int | None): + nonlocal history, history_index, selected_index + history = history[: history_index + 1] + history.append(clone_circles(new_state)) + history_index += 1 + selected_index = select + refresh_ui() + + def build_circle_control(index: int, circle: Circle) -> ft.Container: + diameter = circle.radius * 2 + is_selected = index == selected_index + return ft.Container( + left=circle.x - circle.radius, + top=circle.y - circle.radius, + width=diameter, + height=diameter, + border_radius=circle.radius, + bgcolor=ft.Colors.AMBER_100 if is_selected else ft.Colors.BLUE_100, + border=ft.Border.all( + 3 if is_selected else 2, + ft.Colors.AMBER_700 if is_selected else ft.Colors.BLUE_400, + ), + alignment=ft.Alignment.CENTER, + on_click=lambda e, i=index: open_editor(i), + content=ft.Text( + str(index + 1), + size=12, + weight=ft.FontWeight.W_700, + color=ft.Colors.BLUE_GREY_900, + ), + ) + + def refresh_ui(): + undo_button.disabled = history_index == 0 + redo_button.disabled = history_index >= len(history) - 1 + + canvas_host.content = ft.Stack( + height=295, + controls=[ + ft.GestureDetector( + on_tap_down=add_circle, + content=ft.Container(border_radius=18, bgcolor=ft.Colors.WHITE), + ), + *[ + build_circle_control(index, circle) + for index, circle in enumerate(get_circles()) + ], + ], + ) + page.update() + + def add_circle(e: ft.TapEvent): + if e.local_position is None: + return + + new_circles = clone_circles(get_circles()) + new_circles.append( + Circle(x=e.local_position.x, y=e.local_position.y, radius=DEFAULT_RADIUS) + ) + push_snapshot(new_circles, len(new_circles) - 1) + + def open_editor(index: int): + nonlocal selected_index + selected_index = index + circle = get_circles()[index] + + def apply_radius(e: ft.Event[ft.Button]): + new_circles = clone_circles(get_circles()) + new_circles[index].radius = float(rslider.value) + page.pop_dialog() + push_snapshot(new_circles, index) + + def handle_radius_change(e: ft.Event[ft.Slider]): + rlabel.value = f"Radius: {int(float(rslider.value))} px" + rlabel.update() + + refresh_ui() + page.show_dialog( + ft.AlertDialog( + title=ft.Text(f"Resize Circle {index + 1}"), + content=ft.Column( + tight=True, + spacing=14, + controls=[ + ft.Text("Use the slider to set a new radius."), + rlabel := ft.Text(f"Radius: {int(circle.radius)} px"), + rslider := ft.Slider( + min=MIN_RADIUS, + max=MAX_RADIUS, + value=circle.radius, + divisions=MAX_RADIUS - MIN_RADIUS, + label="{value}", + on_change=handle_radius_change, + ), + ], + ), + actions=[ + ft.TextButton("Cancel", on_click=lambda e: page.pop_dialog()), + ft.FilledButton("Apply", on_click=apply_radius), + ], + ) + ) + + def undo(e: ft.Event[ft.OutlinedButton]): + nonlocal history_index, selected_index + if history_index == 0: + return + history_index -= 1 + selected_index = None + refresh_ui() + + def redo(e: ft.Event[ft.OutlinedButton]): + nonlocal history_index, selected_index + if history_index >= len(history) - 1: + return + history_index += 1 + selected_index = None + refresh_ui() + + page.add( + ft.SafeArea( + content=ft.Container( + width=700, + height=500, + padding=28, + border_radius=24, + bgcolor=ft.Colors.ORANGE_50, + content=ft.Column( + tight=True, + spacing=18, + controls=[ + ft.Text("Circle Drawer", size=28, weight=ft.FontWeight.W_700), + ft.Text( + "Add circles with a click, resize them in a dialog, " + "and step through history.", + color=ft.Colors.BLUE_GREY_700, + ), + canvas_host := ft.Container( + border_radius=24, + bgcolor=ft.Colors.WHITE, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + undo_button := ft.OutlinedButton( + "Undo", + icon=ft.Icons.UNDO, + on_click=undo, + ), + redo_button := ft.OutlinedButton( + "Redo", + icon=ft.Icons.REDO, + on_click=redo, + ), + ], + ), + ], + ), + ), + ) + ) + refresh_ui() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/circle_drawer/pyproject.toml b/sdk/python/examples/apps/7guis/circle_drawer/pyproject.toml new file mode 100644 index 0000000000..2cf8fce103 --- /dev/null +++ b/sdk/python/examples/apps/7guis/circle_drawer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-circle-drawer" +version = "1.0.0" +description = "7GUIs circle drawer app with tap-created circles, radius editing, and undo-redo history." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "circle drawer", "canvas", "undo", "redo"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs", "Displays/Canvas"] + +[tool.flet.metadata] +title = "Circle drawer" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "Stack", "GestureDetector", "AlertDialog", "Slider", "TextButton", "FilledButton", "OutlinedButton"] +layout_pattern = "canvas-tools" +complexity = "intermediate" +features = ["tap handling", "dialog editing", "undo", "redo"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/7guis/counter/main.py b/sdk/python/examples/apps/7guis/counter/main.py new file mode 100644 index 0000000000..3936f376ef --- /dev/null +++ b/sdk/python/examples/apps/7guis/counter/main.py @@ -0,0 +1,63 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "7GUIs - Counter" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + count = 0 + + def increment(e: ft.Event[ft.Button]): + nonlocal count + count += 1 + field.value = str(count) + field.update() + + page.add( + ft.SafeArea( + content=ft.Container( + width=420, + padding=28, + border_radius=24, + bgcolor=ft.Colors.BLUE_GREY_50, + content=ft.Column( + tight=True, + spacing=20, + controls=[ + ft.Text( + "Counter", + size=28, + weight=ft.FontWeight.W_700, + ), + ft.Text( + "A minimal counter with a read-only value and one action.", + color=ft.Colors.BLUE_GREY_700, + ), + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + field := ft.TextField( + value=str(count), + read_only=True, + width=120, + text_align=ft.TextAlign.RIGHT, + bgcolor=ft.Colors.SURFACE, + border_radius=14, + ), + ft.FilledButton( + "Increment", + icon=ft.Icons.ADD, + on_click=increment, + ), + ], + ), + ], + ), + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/counter/pyproject.toml b/sdk/python/examples/apps/7guis/counter/pyproject.toml new file mode 100644 index 0000000000..fc24449e86 --- /dev/null +++ b/sdk/python/examples/apps/7guis/counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-counter" +version = "1.0.0" +description = "7GUIs counter app with a read-only value and one increment action." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "counter", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs"] + +[tool.flet.metadata] +title = "Counter" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "TextField", "FilledButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates", "click handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/7guis/crud/main.py b/sdk/python/examples/apps/7guis/crud/main.py new file mode 100644 index 0000000000..4fca7a5c42 --- /dev/null +++ b/sdk/python/examples/apps/7guis/crud/main.py @@ -0,0 +1,237 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +class Person: + id: int + first_name: str + last_name: str + + +def main(page: ft.Page): + page.title = "7GUIs - CRUD" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + people = [ + Person(id=1, first_name="Ada", last_name="Lovelace"), + Person(id=2, first_name="Grace", last_name="Hopper"), + Person(id=3, first_name="Katherine", last_name="Johnson"), + Person(id=4, first_name="Alan", last_name="Turing"), + ] + next_id = max(person.id for person in people) + 1 + selected_id: int | None = people[0].id + + def get_selected_person() -> Person | None: + for person in people: + if person.id == selected_id: + return person + return None + + def filtered_people() -> list[Person]: + prefix = filter_field.value.strip().lower() + if not prefix: + return people + return [ + person for person in people if person.last_name.lower().startswith(prefix) + ] + + def set_selection(person_id: int | None): + nonlocal selected_id + selected_id = person_id + refresh_ui() + + def person_label(person: Person) -> str: + return f"{person.last_name}, {person.first_name}" + + def build_person_item(person: Person) -> ft.Container: + is_selected = person.id == selected_id + return ft.Container( + padding=14, + border_radius=16, + bgcolor=ft.Colors.BLUE_100 if is_selected else ft.Colors.WHITE, + border=ft.Border.all( + 2 if is_selected else 1, + ft.Colors.BLUE_400 if is_selected else ft.Colors.BLACK_12, + ), + on_click=lambda e, person_id=person.id: set_selection(person_id), + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Text( + person_label(person), + weight=ft.FontWeight.W_600, + overflow=ft.TextOverflow.ELLIPSIS, + expand=True, + ), + ft.Icon(ft.Icons.CHEVRON_RIGHT, color=ft.Colors.BLUE_GREY_400), + ], + ), + ) + + def refresh_ui(): + selected_person = get_selected_person() + if selected_person: + first_name.value = selected_person.first_name + last_name.value = selected_person.last_name + update_button.disabled = False + delete_button.disabled = False + else: + first_name.value = "" + last_name.value = "" + update_button.disabled = True + delete_button.disabled = True + + people_list.controls = [ + build_person_item(person) for person in filtered_people() + ] + page.update() + + def validate_form() -> bool: + first_name.error = None + last_name.error = None + ok = True + if not first_name.value.strip(): + first_name.error = "Required" + ok = False + if not last_name.value.strip(): + last_name.error = "Required" + ok = False + if not ok: + page.update() + return ok + + def create_person(e: ft.Event[ft.IconButton]): + nonlocal next_id, selected_id + if not validate_form(): + return + people.append( + Person( + id=next_id, + first_name=first_name.value.strip(), + last_name=last_name.value.strip(), + ) + ) + selected_id = next_id + next_id += 1 + refresh_ui() + + def update_person(e: ft.Event[ft.IconButton]): + person = get_selected_person() + if person is None or not validate_form(): + return + person.first_name = first_name.value.strip() + person.last_name = last_name.value.strip() + refresh_ui() + + def delete_person(e: ft.Event[ft.IconButton]): + nonlocal selected_id + if selected_id is None: + return + visible = filtered_people() + remaining = [person for person in people if person.id != selected_id] + people[:] = remaining + selected_id = remaining[0].id if remaining else None + if visible and visible[0].id == selected_id: + selected_id = visible[0].id + refresh_ui() + + page.add( + ft.SafeArea( + content=ft.Container( + padding=28, + border_radius=24, + bgcolor=ft.Colors.INDIGO_50, + content=ft.Column( + tight=True, + spacing=20, + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Text("CRUD", size=28, weight=ft.FontWeight.W_700), + ft.Text( + "Filter by surname, select a person, then create, update, " + "or remove records.", + color=ft.Colors.BLUE_GREY_700, + ), + ft.Row( + wrap=True, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Container( + width=250, + height=360, + padding=16, + border_radius=20, + bgcolor=ft.Colors.WHITE, + content=ft.Column( + spacing=14, + controls=[ + filter_field := ft.TextField( + label="Filter by last name", + width=220, + on_change=lambda e: refresh_ui(), + ), + ft.Divider(height=1), + people_list := ft.ListView( + expand=True, spacing=10 + ), + ], + ), + ), + ft.Container( + width=250, + padding=16, + border_radius=20, + bgcolor=ft.Colors.WHITE, + content=ft.Column( + spacing=14, + controls=[ + first_name := ft.TextField( + label="First name", + width=220, + ), + last_name := ft.TextField( + label="Last name", + width=220, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton( + ft.Icons.PERSON_ADD, + icon_color=ft.Colors.BLUE, + tooltip="Create", + on_click=create_person, + ), + update_button := ft.IconButton( + ft.Icons.EDIT_SQUARE, + tooltip="Update", + on_click=update_person, + ), + delete_button := ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete", + style=ft.ButtonStyle( + color=ft.Colors.RED, + ), + on_click=delete_person, + ), + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ) + ) + refresh_ui() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/crud/pyproject.toml b/sdk/python/examples/apps/7guis/crud/pyproject.toml new file mode 100644 index 0000000000..0874f5ebc5 --- /dev/null +++ b/sdk/python/examples/apps/7guis/crud/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-crud" +version = "1.0.0" +description = "7GUIs CRUD app for filtering, selecting, creating, editing, and deleting records." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "crud", "forms", "filtering", "records"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs"] + +[tool.flet.metadata] +title = "CRUD" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "TextField", "IconButton", "ListView", "Divider", "Icon"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["live filtering", "record selection", "record editing", "create update delete"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/7guis/flight_booker/main.py b/sdk/python/examples/apps/7guis/flight_booker/main.py new file mode 100644 index 0000000000..10507cbcd2 --- /dev/null +++ b/sdk/python/examples/apps/7guis/flight_booker/main.py @@ -0,0 +1,153 @@ +from datetime import date, datetime, time, timedelta + +import flet as ft + +ONE_WAY_FLIGHT = "one-way flight" +RETURN_FLIGHT = "return flight" + + +def as_datetime(value: date) -> datetime: + """Convert a `date` to a `datetime` with no time.""" + return datetime.combine(value, time.min) + + +def format_date(value: date) -> str: + """Format a `date` as 'Mon DD, YYYY'.""" + return value.strftime("%b %d, %Y") + + +def main(page: ft.Page): + page.title = "7GUIs - Flight Booker" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + today = date.today() + departure_date = today + timedelta(days=1) + return_date = departure_date + timedelta(days=2) + + def handle_departure_picker_change(e: ft.Event[ft.DatePicker]): + nonlocal departure_date + if e.control.value is not None: + departure_date = e.control.value.date() + refresh_ui() + + def handle_return_picker_change(e: ft.Event[ft.DatePicker]): + nonlocal return_date + if e.control.value is not None: + return_date = e.control.value.date() + refresh_ui() + + def is_return_trip() -> bool: + return booking_mode.value == RETURN_FLIGHT + + def is_valid() -> bool: + return not is_return_trip() or return_date >= departure_date + + def show_departure_picker(e: ft.Event[ft.OutlinedButton]): + page.show_dialog( + ft.DatePicker( + value=as_datetime(departure_date), + first_date=as_datetime(today), + last_date=as_datetime(today + timedelta(days=365)), + on_change=handle_departure_picker_change, + ) + ) + + def show_return_picker(e: ft.Event[ft.OutlinedButton]): + page.show_dialog( + ft.DatePicker( + value=as_datetime(return_date), + first_date=as_datetime(today), + last_date=as_datetime(today + timedelta(days=365)), + on_change=handle_return_picker_change, + ) + ) + + def refresh_ui(): + departure_button.content = format_date(departure_date) + return_button.content = format_date(return_date) + return_button.disabled = not is_return_trip() + book_button.disabled = not is_valid() + + if not is_valid(): + page.show_dialog( + ft.SnackBar("Return date must be on or after the departure date."), + ) + + page.update() + + def get_booking_confirmation_message() -> str: + if not is_return_trip(): + return f"One-way flight booked for {format_date(departure_date)}." + return ( + f"Return flight booked: {format_date(departure_date)} to " + f"{format_date(return_date)}." + ) + + def book(e: ft.Event[ft.Button]): + page.show_dialog(ft.SnackBar(get_booking_confirmation_message(), action="OK")) + + page.add( + ft.SafeArea( + content=ft.Container( + width=500, + padding=28, + border_radius=24, + bgcolor=ft.Colors.LIGHT_BLUE_50, + content=ft.Column( + tight=True, + spacing=18, + controls=[ + ft.Text("Flight Booker", size=28, weight=ft.FontWeight.W_700), + ft.Text( + "Switch between one-way and return flights and book.", + color=ft.Colors.BLUE_GREY_700, + ), + booking_mode := ft.Dropdown( + width=220, + value=ONE_WAY_FLIGHT, + on_select=lambda e: refresh_ui(), + options=[ + ft.DropdownOption( + key=ONE_WAY_FLIGHT, text=ONE_WAY_FLIGHT + ), + ft.DropdownOption( + key=RETURN_FLIGHT, text=RETURN_FLIGHT + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + departure_button := ft.OutlinedButton( + width=180, + icon=ft.Icons.CALENDAR_MONTH, + on_click=show_departure_picker, + ), + return_button := ft.OutlinedButton( + width=180, + icon=ft.Icons.EVENT_REPEAT, + on_click=show_return_picker, + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + book_button := ft.FilledButton( + "Book", + icon=ft.Icons.FLIGHT_TAKEOFF, + on_click=book, + ) + ], + ), + ], + ), + ) + ) + ) + refresh_ui() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/flight_booker/pyproject.toml b/sdk/python/examples/apps/7guis/flight_booker/pyproject.toml new file mode 100644 index 0000000000..3eb311aae1 --- /dev/null +++ b/sdk/python/examples/apps/7guis/flight_booker/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-flight-booker" +version = "1.0.0" +description = "7GUIs flight booking form with trip mode selection, date picking, and booking validation." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "flight booker", "forms", "date picker", "validation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs"] + +[tool.flet.metadata] +title = "Flight booker" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "Dropdown", "OutlinedButton", "FilledButton", "DatePicker", "SnackBar"] +layout_pattern = "form" +complexity = "basic" +features = ["date picking", "form validation", "dialog feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/7guis/temperature_converter/main.py b/sdk/python/examples/apps/7guis/temperature_converter/main.py new file mode 100644 index 0000000000..340210090c --- /dev/null +++ b/sdk/python/examples/apps/7guis/temperature_converter/main.py @@ -0,0 +1,110 @@ +import flet as ft + +FIELD_INPUT_FILTER = ft.InputFilter( + regex_string=r"^-?[0-9]*\.?[0-9]*$", # numeric input only with optional "-" and "." + allow=True, + replacement_string="", +) + + +def format_temperature(value: float) -> str: + """Format a temperature value for display. + + Rounds to 2 decimal places. If the rounded value is an integer, returns + the integer without a decimal point (e.g. 5). Otherwise trims trailing + zeros and a trailing decimal point (e.g. 5.20 -> 5.2, 5.00 -> 5). + """ + rounded = round(value, 2) + if rounded.is_integer(): + return str(int(rounded)) + return f"{rounded:.2f}".rstrip("0").rstrip(".") + + +def celsius_to_fahrenheit(value: float) -> float: + """Convert a temperature from Celsius to Fahrenheit.""" + return value * 9 / 5 + 32 + + +def fahrenheit_to_celsius(value: float) -> float: + """Convert a temperature from Fahrenheit to Celsius.""" + return (value - 32) * 5 / 9 + + +def main(page: ft.Page): + page.title = "7GUIs - Temperature Converter" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def sync_fields(source: ft.TextField, target: ft.TextField, convert): + value = source.value.strip() + if not value: + target.value = "" + target.update() + return + + try: + source_value = float(value) + except ValueError: + return + target_value = convert(source_value) + + target.value = format_temperature(target_value) + page.update() + + def handle_celsius_change(e: ft.Event[ft.TextField]): + sync_fields(celsius, fahrenheit, celsius_to_fahrenheit) + + def handle_fahrenheit_change(e: ft.Event[ft.TextField]): + sync_fields(fahrenheit, celsius, fahrenheit_to_celsius) + + page.add( + ft.SafeArea( + content=ft.Container( + width=460, + padding=28, + border_radius=24, + bgcolor=ft.Colors.AMBER_50, + content=ft.Column( + tight=True, + spacing=18, + controls=[ + ft.Text( + "Temperature Converter", + size=28, + weight=ft.FontWeight.W_700, + ), + ft.Text( + "Edit either field and the other one updates immediately.", + color=ft.Colors.BLUE_GREY_700, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + celsius := ft.TextField( + label="Celsius", + suffix="°C", + expand=True, + keyboard_type=ft.KeyboardType.NUMBER, + input_filter=FIELD_INPUT_FILTER, + on_change=handle_celsius_change, + ), + ft.Text("="), + fahrenheit := ft.TextField( + label="Fahrenheit", + suffix="°F", + expand=True, + keyboard_type=ft.KeyboardType.NUMBER, + input_filter=FIELD_INPUT_FILTER, + on_change=handle_fahrenheit_change, + ), + ], + ), + ], + ), + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/temperature_converter/pyproject.toml b/sdk/python/examples/apps/7guis/temperature_converter/pyproject.toml new file mode 100644 index 0000000000..c8c7c7a307 --- /dev/null +++ b/sdk/python/examples/apps/7guis/temperature_converter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-temperature-converter" +version = "1.0.0" +description = "7GUIs temperature converter with synchronized Celsius and Fahrenheit fields." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "temperature converter", "forms", "validation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs", "Tools"] + +[tool.flet.metadata] +title = "Temperature converter" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "TextField"] +layout_pattern = "inline-form" +complexity = "basic" +features = ["live conversion", "input filtering", "form validation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/7guis/timer/main.py b/sdk/python/examples/apps/7guis/timer/main.py new file mode 100644 index 0000000000..60e08e45b2 --- /dev/null +++ b/sdk/python/examples/apps/7guis/timer/main.py @@ -0,0 +1,103 @@ +import asyncio +import time + +import flet as ft + + +def main(page: ft.Page): + page.title = "7GUIs - Timer" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + duration_seconds = 15.0 + elapsed_seconds = 0.0 + last_tick = time.monotonic() + + def refresh_ui(): + progress.value = ( + 0 if duration_seconds == 0 else elapsed_seconds / duration_seconds + ) + elapsed_label.value = f"{elapsed_seconds:0.1f}s elapsed" + duration_label.value = f"Duration: {duration_seconds:0.1f}s" + page.update() + + async def ticker(): + nonlocal elapsed_seconds, last_tick + while True: + await asyncio.sleep(0.1) + now = time.monotonic() + delta = now - last_tick + last_tick = now + if elapsed_seconds < duration_seconds: + elapsed_seconds = min(duration_seconds, elapsed_seconds + delta) + refresh_ui() + + def handle_duration_change(e: ft.Event[ft.Slider]): + nonlocal duration_seconds, elapsed_seconds + duration_seconds = round(float(e.control.value), 1) + elapsed_seconds = min(elapsed_seconds, duration_seconds) + refresh_ui() + + def reset(e: ft.Event[ft.TextButton]): + nonlocal elapsed_seconds, last_tick + elapsed_seconds = 0.0 + last_tick = time.monotonic() + refresh_ui() + + page.add( + ft.SafeArea( + content=ft.Container( + width=500, + padding=28, + border_radius=24, + bgcolor=ft.Colors.TEAL_50, + content=ft.Column( + tight=True, + spacing=18, + controls=[ + ft.Text("Timer", size=28, weight=ft.FontWeight.W_700), + ft.Text( + "The timer starts immediately, fills the bar, and can be " + "reset or resized.", + color=ft.Colors.BLUE_GREY_700, + ), + elapsed_label := ft.Text(size=34, weight=ft.FontWeight.W_600), + progress := ft.ProgressBar( + width=420, + value=0, + bar_height=16, + border_radius=12, + color=ft.Colors.TEAL_500, + bgcolor=ft.Colors.TEAL_50, + ), + duration_label := ft.Text(color=ft.Colors.BLUE_GREY_700), + ft.Slider( + min=1, + max=30, + divisions=58, + round=1, + value=duration_seconds, + label="{value}s", + on_change=handle_duration_change, + ), + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.TextButton( + "Reset timer", + icon=ft.Icons.RESTART_ALT, + on_click=reset, + ) + ], + ), + ], + ), + ) + ) + ) + refresh_ui() + page.run_task(ticker) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/7guis/timer/pyproject.toml b/sdk/python/examples/apps/7guis/timer/pyproject.toml new file mode 100644 index 0000000000..106f002966 --- /dev/null +++ b/sdk/python/examples/apps/7guis/timer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-7guis-timer" +version = "1.0.0" +description = "7GUIs timer app with automatic progress updates, duration control, and reset handling." +requires-python = ">=3.10" +keywords = ["apps", "7guis", "timer", "progress", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured/7GUIs", "Cookbook"] + +[tool.flet.metadata] +title = "Timer" +controls = ["SafeArea", "Container", "Column", "Row", "Text", "ProgressBar", "Slider", "TextButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["async", "timer progress", "slider input", "reset handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/main.py b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/main.py new file mode 100644 index 0000000000..e522d44aa7 --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/main.py @@ -0,0 +1,58 @@ +# +# Run this example with: +# export GITHUB_CLIENT_ID= +# export GITHUB_CLIENT_SECRET= +# flet run --web --port 8550 main.py +# +import os + +import flet as ft +from flet.auth.providers import GitHubOAuthProvider + + +def get_env_variable(name: str) -> str: + value = os.getenv(name) + assert value, f"set {name} environment variable" + return value + + +def main(page: ft.Page): + provider = GitHubOAuthProvider( + client_id=get_env_variable("GITHUB_CLIENT_ID"), + client_secret=get_env_variable("GITHUB_CLIENT_SECRET"), + redirect_url="http://127.0.0.1:8550/oauth_callback", + ) + + async def login_button_click(e): + await page.login(provider, scope=["public_repo"]) + + def on_login(e: ft.LoginEvent): + if not e.error: + toggle_login_buttons() + + def logout_button_click(e): + page.logout() + + def on_logout(e): + toggle_login_buttons() + + def toggle_login_buttons(): + login_button.visible = page.auth is None + logout_button.visible = page.auth is not None + + login_button = ft.Button("Login with GitHub", on_click=login_button_click) + logout_button = ft.Button("Logout", on_click=logout_button_click) + toggle_login_buttons() + page.on_login = on_login + page.on_logout = on_logout + page.add( + ft.SafeArea( + content=ft.Column( + controls=[login_button, logout_button], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml new file mode 100644 index 0000000000..5e1304278c --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_check_auth_results_and_toggle_ui/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "apps-authentication-github-check-auth-results-and-toggle-ui" +version = "1.0.0" +description = "Toggles GitHub sign-in and sign-out buttons based on authentication events." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "login", "web", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "GitHub auth button toggle" +controls = ["SafeArea", "Column", "Button", "GitHubOAuthProvider"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["oauth login", "oauth logout", "auth-aware UI"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/authentication/github_login_same_page/main.py b/sdk/python/examples/apps/authentication/github_login_same_page/main.py new file mode 100644 index 0000000000..b7602104e6 --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_login_same_page/main.py @@ -0,0 +1,52 @@ +# +# Run this example with: +# export GITHUB_CLIENT_ID= +# export GITHUB_CLIENT_SECRET= +# flet run --web --port 8550 main.py +# +import os + +import flet as ft +from flet.auth.providers import GitHubOAuthProvider + + +def get_env_variable(name: str) -> str: + value = os.getenv(name) + assert value, f"set {name} environment variable" + return value + + +def main(page: ft.Page): + provider = GitHubOAuthProvider( + client_id=get_env_variable("GITHUB_CLIENT_ID"), + client_secret=get_env_variable("GITHUB_CLIENT_SECRET"), + redirect_url="http://127.0.0.1:8550/oauth_callback", + ) + + async def login_click(e): + await page.login( + provider, + redirect_to_page=True, + on_open_authorization_url=lambda url: ft.UrlLauncher().launch_url( + ft.Url(url, target=ft.UrlTarget.SELF) + ), + ) + + async def on_login(e): + if e.error: + page.add(ft.Text(f"Login error: {e.error}")) + else: + page.add(ft.Text(f"User ID: {page.auth.user.id}")) + + page.on_login = on_login + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Login with GitHub", on_click=login_click)], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml b/sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml new file mode 100644 index 0000000000..934006cfc2 --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_login_same_page/pyproject.toml @@ -0,0 +1,24 @@ +[project] +name = "apps-authentication-github-login-same-page" +version = "1.0.0" +description = "Runs GitHub OAuth in the same browser tab and displays the authenticated user ID." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "redirect", "web", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "GitHub login in same page" +controls = ["SafeArea", "Column", "Button", "Text", "GitHubOAuthProvider", "UrlLauncher"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["oauth login", "same-tab redirect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/apps/authentication/github_minimal/main.py b/sdk/python/examples/apps/authentication/github_minimal/main.py new file mode 100644 index 0000000000..1c08ff2aed --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_minimal/main.py @@ -0,0 +1,50 @@ +# +# Run this example with: +# export GITHUB_CLIENT_ID= +# export GITHUB_CLIENT_SECRET= +# flet run --web --port 8550 main.py +# +import os + +import flet as ft +from flet.auth.providers import GitHubOAuthProvider + + +def get_env_variable(name: str) -> str: + value = os.getenv(name) + assert value, f"set {name} environment variable" + return value + + +def main(page: ft.Page): + provider = GitHubOAuthProvider( + client_id=get_env_variable("GITHUB_CLIENT_ID"), + client_secret=get_env_variable("GITHUB_CLIENT_SECRET"), + redirect_url="http://127.0.0.1:8550/oauth_callback", + ) + + async def login_click(e): + await page.login(provider) + + async def on_login(e): + if e.error: + page.add(ft.Text(f"Login error: {e.error}")) + else: + access_token = (await page.auth.get_token()).access_token + page.add( + ft.Text(f"Access token: {access_token}"), + ft.Text(f"User ID: {page.auth.user.id}"), + ) + + page.on_login = on_login + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Login with GitHub", on_click=login_click)], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_minimal/pyproject.toml b/sdk/python/examples/apps/authentication/github_minimal/pyproject.toml new file mode 100644 index 0000000000..49720c941e --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_minimal/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "apps-authentication-github-minimal" +version = "1.0.0" +description = "Shows a minimal GitHub OAuth login flow and prints the access token and user ID." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "login", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "Minimal GitHub login" +controls = ["SafeArea", "Column", "Button", "Text", "GitHubOAuthProvider"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["oauth login", "access token display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/authentication/github_repos_browser/main.py b/sdk/python/examples/apps/authentication/github_repos_browser/main.py new file mode 100644 index 0000000000..6b5c7a19dc --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_repos_browser/main.py @@ -0,0 +1,130 @@ +# +# Run this example with: +# export GITHUB_CLIENT_ID= +# export GITHUB_CLIENT_SECRET= +# export MY_APP_SECRET_KEY= +# flet run --web --port 8550 main.py +# +import json +import logging +import os + +import httpx + +import flet as ft +from flet.auth.providers import GitHubOAuthProvider +from flet.security import decrypt, encrypt + +logging.basicConfig(level=logging.INFO) + + +def get_env_variable(name: str) -> str: + value = os.getenv(name) + assert value, f"set {name} environment variable" + return value + + +async def main(page: ft.Page): + secret_key = get_env_variable("MY_APP_SECRET_KEY") + + provider = GitHubOAuthProvider( + client_id=get_env_variable("GITHUB_CLIENT_ID"), + client_secret=get_env_variable("GITHUB_CLIENT_SECRET"), + redirect_url="http://127.0.0.1:8550/oauth_callback", + ) + + auth_token_key = "myapp.auth_token" + + async def perform_login(e): + login_button.disabled = True + login_button.update() + + saved_token = None + ejt = await ft.SharedPreferences().get(auth_token_key) + if ejt: + saved_token = decrypt(ejt, secret_key) + if e is not None or saved_token is not None: + await page.login( + provider, + redirect_to_page=True, + on_open_authorization_url=lambda url: ft.UrlLauncher().launch_url( + ft.Url(url, target=ft.UrlTarget.SELF) + ), + saved_token=saved_token, + scope=["public_repo"], + ) + + async def on_login(e: ft.LoginEvent): + if e.error: + raise Exception(e.error) + + assert page.auth + + jt = (await page.auth.get_token()).to_json() + ejt = encrypt(jt, secret_key) + await ft.SharedPreferences().set(auth_token_key, ejt) + + logged_user.value = f"Hello, {page.auth.user['name']}!" + toggle_login_buttons() + await list_github_repositories() + + async def list_github_repositories(): + repos_view.controls.clear() + if page.auth: + headers = { + "User-Agent": "Flet", + "Authorization": f"Bearer {(await page.auth.get_token()).access_token}", + } + async with httpx.AsyncClient() as client: + repos_resp = await client.get( + "https://api.github.com/user/repos", headers=headers + ) + repos_resp.raise_for_status() + user_repos = json.loads(repos_resp.text) + for repo in user_repos: + repos_view.controls.append( + ft.ListTile( + leading=ft.Icon(ft.Icons.FOLDER_ROUNDED), + title=ft.Text(repo["full_name"]), + ) + ) + + async def logout_button_click(e): + await ft.SharedPreferences().remove(auth_token_key) + page.logout() + + async def on_logout(e): + toggle_login_buttons() + await list_github_repositories() + + def toggle_login_buttons(): + login_button.visible = page.auth is None + login_button.disabled = False + logged_user.visible = logout_button.visible = page.auth is not None + + logged_user = ft.Text() + login_button = ft.Button("Login with GitHub", on_click=perform_login) + logout_button = ft.Button("Logout", on_click=logout_button_click) + repos_view = ft.ListView(expand=True) + page.on_login = on_login + page.on_logout = on_logout + toggle_login_buttons() + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Row( + controls=[logged_user, login_button, logout_button], + ), + repos_view, + ], + ), + ) + ) + await perform_login(None) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml b/sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml new file mode 100644 index 0000000000..baa57310af --- /dev/null +++ b/sdk/python/examples/apps/authentication/github_repos_browser/pyproject.toml @@ -0,0 +1,24 @@ +[project] +name = "apps-authentication-github-repos-browser" +version = "1.0.0" +description = "Logs in with GitHub, restores a saved token, and lists the signed-in user's repositories." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "github", "oauth", "repositories", "web", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "httpx"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "GitHub repos browser" +controls = ["SafeArea", "Column", "Row", "Text", "Button", "ListView", "ListTile", "GitHubOAuthProvider"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["oauth login", "saved token restore", "github api request"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/apps/authentication/linkedin_login/main.py b/sdk/python/examples/apps/authentication/linkedin_login/main.py new file mode 100644 index 0000000000..5c059b63ce --- /dev/null +++ b/sdk/python/examples/apps/authentication/linkedin_login/main.py @@ -0,0 +1,55 @@ +# +# Run this example with: +# export LINKEDIN_CLIENT_ID= +# export LINKEDIN_CLIENT_SECRET= +# flet run --web --port 8550 main.py +# +import os + +import flet as ft +from flet.auth import OAuthProvider + + +def get_env_variable(name: str) -> str: + value = os.getenv(name) + assert value, f"set {name} environment variable" + return value + + +def main(page: ft.Page): + provider = OAuthProvider( + client_id=get_env_variable("LINKEDIN_CLIENT_ID"), + client_secret=get_env_variable("LINKEDIN_CLIENT_SECRET"), + authorization_endpoint="https://www.linkedin.com/oauth/v2/authorization", + token_endpoint="https://www.linkedin.com/oauth/v2/accessToken", + user_endpoint="https://api.linkedin.com/v2/me", + user_scopes=["r_liteprofile", "r_emailaddress"], + user_id_fn=lambda u: u["id"], + redirect_url="http://127.0.0.1:8550/oauth_callback", + ) + + async def login_click(e): + await page.login(provider) + + async def on_login(e): + if e.error: + page.add(ft.Text(f"Login error: {e.error}")) + else: + access_token = (await page.auth.get_token()).access_token + page.add( + ft.Text(f"Access token: {access_token}"), + ft.Text(f"User ID: {page.auth.user.id}"), + ) + + page.on_login = on_login + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Login with LinkedIn", on_click=login_click)], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml b/sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml new file mode 100644 index 0000000000..6ddd137857 --- /dev/null +++ b/sdk/python/examples/apps/authentication/linkedin_login/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "apps-authentication-linkedin-login" +version = "1.0.0" +description = "Authenticates with a custom LinkedIn OAuth provider and displays the token and user ID." +requires-python = ">=3.10" +keywords = ["apps", "authentication", "linkedin", "oauth", "login", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "LinkedIn login" +controls = ["SafeArea", "Column", "Button", "Text", "OAuthProvider"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom oauth provider", "access token display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/autocomplete_searcher/basic/main.py b/sdk/python/examples/apps/autocomplete_searcher/basic/main.py new file mode 100644 index 0000000000..75fd7dda27 --- /dev/null +++ b/sdk/python/examples/apps/autocomplete_searcher/basic/main.py @@ -0,0 +1,64 @@ +import flet as ft + +NAMES = [ + "Adam", + "William", + "Emma", + "Alexander", + "Julia", + "Elias", + "Hugo", + "Alice", + "Emil", + "Anton", + "Ebba", + "Elin", + "Oliver", + "Axel", + "Maja", + "Ella", + "Alva", + "Liam", + "Albin", + "Elsa", + "Erik", + "Ida", + "Oscar", + "Wilma", +] + + +def main(page: ft.Page): + page.title = "Autocomplete search names" + + def textbox_changed(string): + str_lower = string.control.value.lower() + list_view.controls = ( + [list_items.get(n) for n in NAMES if str_lower in n.lower()] + if str_lower + else [] + ) + + list_items = { + name: ft.ListTile( + title=ft.Text(name), + leading=ft.Icon(ft.Icons.ACCESSIBILITY), + ) + for name in NAMES + } + + text_field = ft.TextField(label="Search name:", on_change=textbox_changed) + list_view = ft.ListView(expand=1, spacing=10, padding=20) + + page.add( + ft.SafeArea( + content=ft.Column( + expand=True, + controls=[text_field, list_view], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml b/sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml new file mode 100644 index 0000000000..6c5a6748c3 --- /dev/null +++ b/sdk/python/examples/apps/autocomplete_searcher/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-autocomplete-searcher-basic" +version = "1.0.0" +description = "Filters a list of names as the user types into an autocomplete-style search field." +requires-python = ">=3.10" +keywords = ["apps", "autocomplete", "search", "list filtering", "text field"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ListView", "Cookbook"] + +[tool.flet.metadata] +title = "Autocomplete searcher" +controls = ["SafeArea", "Column", "TextField", "ListView", "ListTile", "Text", "Icon"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["live filtering", "search suggestions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/calculator/main.py b/sdk/python/examples/apps/calculator/main.py new file mode 100644 index 0000000000..f699fead6a --- /dev/null +++ b/sdk/python/examples/apps/calculator/main.py @@ -0,0 +1,172 @@ +from dataclasses import field + +import flet as ft + + +@ft.control +class CalcButton(ft.Button): + expand: int = field(default_factory=lambda: 1) + + +@ft.control +class DigitButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.WHITE_24 + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.ORANGE + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ExtraActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + color: ft.Colors = ft.Colors.BLACK + + +@ft.control +class CalculatorApp(ft.Container): + def init(self): + self.reset() + self.width = 350 + self.bgcolor = ft.Colors.BLACK + self.border_radius = ft.BorderRadius.all(20) + self.padding = 20 + self.result = ft.Text(value="0", color=ft.Colors.WHITE, size=20) + + self.content = ft.Column( + controls=[ + ft.Row( + controls=[self.result], + alignment=ft.MainAxisAlignment.END, + ), + ft.Row( + controls=[ + ExtraActionButton(content="AC", on_click=self.button_clicked), + ExtraActionButton(content="+/-", on_click=self.button_clicked), + ExtraActionButton(content="%", on_click=self.button_clicked), + ActionButton(content="/", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="7", on_click=self.button_clicked), + DigitButton(content="8", on_click=self.button_clicked), + DigitButton(content="9", on_click=self.button_clicked), + ActionButton(content="*", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="4", on_click=self.button_clicked), + DigitButton(content="5", on_click=self.button_clicked), + DigitButton(content="6", on_click=self.button_clicked), + ActionButton(content="-", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="1", on_click=self.button_clicked), + DigitButton(content="2", on_click=self.button_clicked), + DigitButton(content="3", on_click=self.button_clicked), + ActionButton(content="+", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton( + content="0", expand=2, on_click=self.button_clicked + ), + DigitButton(content=".", on_click=self.button_clicked), + ActionButton(content="=", on_click=self.button_clicked), + ] + ), + ] + ) + + def button_clicked(self, e): + data = e.control.content + print(f"Button clicked with data = {data}") + if self.result.value == "Error" or data == "AC": + self.result.value = "0" + self.reset() + + elif data in ("1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "."): + if self.result.value == "0" or self.new_operand: + self.result.value = data + self.new_operand = False + else: + self.result.value = self.result.value + data + + elif data in ("+", "-", "*", "/"): + self.result.value = self.calculate( + self.operand1, float(self.result.value), self.operator + ) + self.operator = data + if self.result.value == "Error": + self.operand1 = "0" + else: + self.operand1 = float(self.result.value) + self.new_operand = True + + elif data in ("="): + self.result.value = self.calculate( + self.operand1, float(self.result.value), self.operator + ) + self.reset() + + elif data in ("%"): + self.result.value = float(self.result.value) / 100 + self.reset() + + elif data in ("+/-"): + if float(self.result.value) > 0: + self.result.value = "-" + str(self.result.value) + + elif float(self.result.value) < 0: + self.result.value = str( + self.format_number(abs(float(self.result.value))) + ) + + self.update() + + def format_number(self, num): + if num % 1 == 0: + return int(num) + else: + return num + + def calculate(self, operand1, operand2, operator): + if operator == "+": + return self.format_number(operand1 + operand2) + + elif operator == "-": + return self.format_number(operand1 - operand2) + + elif operator == "*": + return self.format_number(operand1 * operand2) + + elif operator == "/": + if operand2 == 0: + return "Error" + else: + return self.format_number(operand1 / operand2) + + def reset(self): + self.operator = "+" + self.operand1 = 0 + self.new_operand = True + + +def main(page: ft.Page): + page.title = "Calc App" + # create application instance + calc = CalculatorApp() + + # add application's root control to the page + page.add(calc) + + +ft.run(main) diff --git a/sdk/python/examples/apps/calculator/pyproject.toml b/sdk/python/examples/apps/calculator/pyproject.toml new file mode 100644 index 0000000000..f35be6310b --- /dev/null +++ b/sdk/python/examples/apps/calculator/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tutorials-calculator" +version = "1.0.0" +description = "Builds an iOS-style calculator app with custom button controls and arithmetic operations." +requires-python = ">=3.10" +keywords = ["tutorials", "calculator", "productivity", "custom controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Getting Started", "Featured", "Tools"] + +[tool.flet.metadata] +title = "Calculator" +controls = ["Container", "Column", "Row", "Text", "Button"] +layout_pattern = "center-stage" +complexity = "beginner" +features = ["custom controls", "arithmetic", "state management"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/counter/accessible/main.py b/sdk/python/examples/apps/counter/accessible/main.py new file mode 100644 index 0000000000..77fbed7129 --- /dev/null +++ b/sdk/python/examples/apps/counter/accessible/main.py @@ -0,0 +1,73 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Counter" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + txt_number = ft.TextField( + value="0", + text_align=ft.TextAlign.RIGHT, + width=100, + label="Counter value", + ) + + def toggle_semantics_debugger(e): + page.show_semantics_debugger = not page.show_semantics_debugger + page.update() + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + txt_number.label = f"Counter value, {txt_number.value}" + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + txt_number.label = f"Counter value, {txt_number.value}" + page.update() + + page.on_keyboard_event = toggle_semantics_debugger + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Semantics( + label=( + "Press plus button to increase counter, " + "or minus button to decrease counter." + ), + hint_text=( + "Press CONTROL plus ALT plus S to show semantics debugger" + ), + button=True, + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton( + icon=ft.Icons.REMOVE, + tooltip="Decrease number", + on_click=minus_click, + ), + txt_number, + ft.IconButton( + icon=ft.Icons.ADD, + tooltip="Increase number", + on_click=plus_click, + ), + ], + ), + ), + ft.Text( + value=( + "Press CONTROL plus ALT plus S to show semantics debugger" + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/counter/accessible/pyproject.toml b/sdk/python/examples/apps/counter/accessible/pyproject.toml new file mode 100644 index 0000000000..1184ba0bdb --- /dev/null +++ b/sdk/python/examples/apps/counter/accessible/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-counter-accessible" +version = "1.0.0" +description = "Accessible counter app with semantics labels and a keyboard shortcut for the semantics debugger." +requires-python = ">=3.10" +keywords = ["apps", "counter", "accessibility", "semantics", "keyboard"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Accessibility"] + +[tool.flet.metadata] +title = "Accessible counter" +controls = ["SafeArea", "Column", "Row", "IconButton", "TextField", "Semantics", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["accessible semantics", "keyboard shortcut", "counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/counter/editable/main.py b/sdk/python/examples/apps/counter/editable/main.py new file mode 100644 index 0000000000..c70e8b234e --- /dev/null +++ b/sdk/python/examples/apps/counter/editable/main.py @@ -0,0 +1,36 @@ +import flet as ft + +ft.context.disable_auto_update() + + +def main(page: ft.Page): + page.title = "Counter" + txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + txt_number, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ] + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/counter/editable/pyproject.toml b/sdk/python/examples/apps/counter/editable/pyproject.toml new file mode 100644 index 0000000000..317d50c5ac --- /dev/null +++ b/sdk/python/examples/apps/counter/editable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "flet-app-editable-counter" +version = "1.0.0" +description = "Classic counter app with increment and decrement buttons around a numeric text field." +requires-python = ">=3.10" +keywords = ["apps", "counter", "buttons", "text field", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Getting Started"] + +[tool.flet.metadata] +title = "Editable plus/minus counter" +controls = ["SafeArea", "Column", "Row", "IconButton", "TextField"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/counter_test_ios/Dockerfile b/sdk/python/examples/apps/counter_test_ios/Dockerfile new file mode 100644 index 0000000000..5bf082ae12 --- /dev/null +++ b/sdk/python/examples/apps/counter_test_ios/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3-alpine + +WORKDIR /app + +COPY pyproject.toml ./ +RUN pip install --no-cache-dir . + +COPY . . + +EXPOSE 8080 + +CMD ["python", "./main.py"] diff --git a/sdk/python/examples/apps/counter_test_ios/assets/favicon.png b/sdk/python/examples/apps/counter_test_ios/assets/favicon.png new file mode 100644 index 0000000000..022e3a8e4b Binary files /dev/null and b/sdk/python/examples/apps/counter_test_ios/assets/favicon.png differ diff --git a/sdk/python/examples/apps/counter_test_ios/assets/icon.png b/sdk/python/examples/apps/counter_test_ios/assets/icon.png new file mode 100644 index 0000000000..060a18ba00 Binary files /dev/null and b/sdk/python/examples/apps/counter_test_ios/assets/icon.png differ diff --git a/sdk/python/examples/apps/counter_test_ios/assets/manifest.json b/sdk/python/examples/apps/counter_test_ios/assets/manifest.json new file mode 100644 index 0000000000..d1d57e4acc --- /dev/null +++ b/sdk/python/examples/apps/counter_test_ios/assets/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "Counter", + "short_name": "Counter", + "description": "Testing Flet on mobile devices", + "start_url": ".", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#0175C2", + "orientation": "natural", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/sdk/python/examples/apps/counter_test_ios/fly.toml b/sdk/python/examples/apps/counter_test_ios/fly.toml new file mode 100644 index 0000000000..b58e146859 --- /dev/null +++ b/sdk/python/examples/apps/counter_test_ios/fly.toml @@ -0,0 +1,39 @@ +app = "flet-counter-test-ios" + +[build] + dockerfile = "Dockerfile" + +[env] + FLET_SERVER_PORT = "8080" + FLET_FORCE_WEB_SERVER = "true" + +[experimental] + allowed_public_ports = [] + auto_rollback = true + +[[services]] + http_checks = [] + internal_port = 8080 + processes = ["app"] + protocol = "tcp" + script_checks = [] + + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + type = "connections" + + [[services.ports]] + force_https = true + handlers = ["http"] + port = 80 + + [[services.ports]] + handlers = ["tls", "http"] + port = 443 + + [[services.tcp_checks]] + grace_period = "1s" + interval = "15s" + restart_limit = 0 + timeout = "2s" diff --git a/sdk/python/examples/apps/counter_test_ios/main.py b/sdk/python/examples/apps/counter_test_ios/main.py new file mode 100644 index 0000000000..8dc1980490 --- /dev/null +++ b/sdk/python/examples/apps/counter_test_ios/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +class State: + counter = 0 + + +def main(page: ft.Page): + state = State() + counter = ft.Text("0", size=50) + + def add_click(e): + state.counter += 1 + counter.value = str(state.counter) + counter.update() + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=add_click + ) + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + alignment=ft.Alignment.CENTER, + content=counter, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/counter_test_ios/pyproject.toml b/sdk/python/examples/apps/counter_test_ios/pyproject.toml new file mode 100644 index 0000000000..3c1471f7ad --- /dev/null +++ b/sdk/python/examples/apps/counter_test_ios/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "apps-counter-test-ios" +version = "1.0.0" +description = "Minimal floating-action-button counter app used for testing Flet on mobile devices." +requires-python = ">=3.10" +keywords = ["apps", "counter", "mobile", "floating action button", "ios"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "Counter test iOS" +controls = ["SafeArea", "Container", "Text", "FloatingActionButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["counter updates", "mobile testing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/custom_controls/custom_buttons/main.py b/sdk/python/examples/apps/custom_controls/custom_buttons/main.py new file mode 100644 index 0000000000..ae42752145 --- /dev/null +++ b/sdk/python/examples/apps/custom_controls/custom_buttons/main.py @@ -0,0 +1,52 @@ +from dataclasses import dataclass, field +from typing import Any + +import flet as ft + + +def main(page: ft.Page): + @ft.control + class MyButton(ft.Button): + expand: int = field(default_factory=lambda: 1) + style: ft.ButtonStyle = field( + default_factory=lambda: ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10) + ) + ) + bgcolor: ft.Colors = ft.Colors.BLUE_ACCENT + icon: Any = ft.Icons.HEADPHONES + + @dataclass + class MyButton2(ft.Button): + expand: Any = 1 + bgcolor: ft.Colors = ft.Colors.GREEN_ACCENT + style: ft.ButtonStyle = field( + default_factory=lambda: ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=20) + ) + ) + icon: ft.IconDataOrControl = ft.Icons.HEADPHONES + + @ft.control + class MyButton3(ft.Button): + def init(self): + self.expand = 1 + self.bgcolor = ft.Colors.RED_ACCENT + self.style = ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=30)) + self.icon = ft.Icons.HEADPHONES + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row(controls=[MyButton(content="1")]), + ft.Row(controls=[MyButton2(content="2")]), + ft.Row(controls=[MyButton3(content="3")]), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml b/sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml new file mode 100644 index 0000000000..0605df742c --- /dev/null +++ b/sdk/python/examples/apps/custom_controls/custom_buttons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-custom-controls-custom-buttons" +version = "1.0.0" +description = "Shows three ways to define reusable custom button controls with predefined styling." +requires-python = ">=3.10" +keywords = ["apps", "custom controls", "buttons", "control decorator", "dataclass"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Cookbook"] + +[tool.flet.metadata] +title = "Custom buttons" +controls = ["SafeArea", "Column", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom controls", "button styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/component_dialog/main.py b/sdk/python/examples/apps/declarative/component_dialog/main.py new file mode 100644 index 0000000000..f1c583f55e --- /dev/null +++ b/sdk/python/examples/apps/declarative/component_dialog/main.py @@ -0,0 +1,93 @@ +import asyncio +from typing import Callable, Optional, cast + +import httpx + +import flet as ft + + +# ---------- REUSABLE DIALOG HOOK ---------- +def use_dialog(dialog_factory: Callable[[], ft.AlertDialog]) -> Callable[[], None]: + dlg_ref = ft.use_ref(cast(Optional[ft.AlertDialog], None)) + + if dlg_ref.current is None: + dlg_ref.current = dialog_factory() + + def open_dialog(): + if dlg_ref.current: + ft.context.page.show_dialog(dlg_ref.current) + + return open_dialog + + +# ---------- DIALOG COMPONENT ---------- +@ft.component +def UserDialogContent(): + """Component that loads and displays user data""" + loading, set_loading = ft.use_state(True) + name, set_name = ft.use_state("") + email, set_email = ft.use_state("") + error, set_error = ft.use_state("") + + async def load_user(): + set_loading(True) + set_error("") + try: + await asyncio.sleep(2) # Simulate network delay + async with httpx.AsyncClient(timeout=5) as client: + r = await client.get("https://jsonplaceholder.typicode.com/users/1") + r.raise_for_status() + data = r.json() + set_name(data["name"]) + set_email(data["email"]) + except Exception as e: + set_error(str(e)) + finally: + set_loading(False) + + # Load data when component mounts + ft.use_effect(lambda: asyncio.create_task(load_user()), []) + + return ft.Column( + tight=True, + controls=[ + ft.Text("User Panel", weight=ft.FontWeight.BOLD, size=18), + ft.ProgressRing(visible=loading), + ft.Text(f"Name: {name}"), + ft.Text(f"Email: {email}"), + ft.Text(error, color=ft.Colors.RED) if error else ft.Container(), + ], + ) + + +# ---------- PARENT COMPONENT ---------- +@ft.component +def App(): + open_user_dialog = use_dialog( + lambda: ft.AlertDialog( + modal=True, + title=ft.Text("User Information"), + content=UserDialogContent(), + actions=[ft.TextButton("Close", on_click=lambda e: e.page.pop_dialog())], + actions_alignment=ft.MainAxisAlignment.END, + ) + ) + + return ft.SafeArea( + content=ft.Container( + padding=20, + content=ft.Column( + controls=[ + ft.Text("Main App", size=22, weight=ft.FontWeight.BOLD), + ft.Button( + "Open User Panel", + on_click=open_user_dialog, + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/component_dialog/pyproject.toml b/sdk/python/examples/apps/declarative/component_dialog/pyproject.toml new file mode 100644 index 0000000000..7201bdffc6 --- /dev/null +++ b/sdk/python/examples/apps/declarative/component_dialog/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-component-dialog" +version = "1.0.0" +description = "Opens a declarative alert dialog that loads user data asynchronously before rendering it." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "dialog", "async", "httpx"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "httpx"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Component dialog" +controls = ["SafeArea", "Container", "Column", "Text", "ElevatedButton", "AlertDialog", "ProgressRing"] +layout_pattern = "center-stage" +complexity = "intermediate" +features = ["dialog management", "async", "data loading"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/counter/main.py b/sdk/python/examples/apps/declarative/counter/main.py new file mode 100644 index 0000000000..6c20d0ef93 --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +@ft.component +def App(): + count, set_count = ft.use_state(0) + + return ft.View( + floating_action_button=ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=lambda: set_count(count + 1) + ), + controls=[ + ft.SafeArea( + expand=True, + content=ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text(value=f"{count}", size=50), + ), + ) + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/counter/pyproject.toml b/sdk/python/examples/apps/declarative/counter/pyproject.toml new file mode 100644 index 0000000000..5457832306 --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-counter" +version = "1.0.0" +description = "Declarative counter app that updates a centered value from a floating action button." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "counter", "floating action button", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "Counter (declarative)" +controls = ["View", "SafeArea", "Container", "Text", "FloatingActionButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/counter_minimal/main.py b/sdk/python/examples/apps/declarative/counter_minimal/main.py new file mode 100644 index 0000000000..fc86ecac99 --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter_minimal/main.py @@ -0,0 +1,19 @@ +import flet as ft + + +@ft.component +def App(): + count, set_count = ft.use_state(0) + + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Text(value=f"{count}"), + ft.Button("Add", on_click=lambda: set_count(count + 1)), + ], + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml b/sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml new file mode 100644 index 0000000000..5828ca53a6 --- /dev/null +++ b/sdk/python/examples/apps/declarative/counter_minimal/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-counter-minimal" +version = "1.0.0" +description = "Small declarative counter showing the minimum state hook pattern for updating text." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "counter", "minimal", "state hooks"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Counter minimal (declarative)" +controls = ["SafeArea", "Row", "Text", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py b/sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py new file mode 100644 index 0000000000..59fb64005b --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_containers/main.py @@ -0,0 +1,92 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class TargetState: + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + is_drag_over: bool = False + + +@ft.component +def App(): + target, _ = ft.use_state(lambda: TargetState()) + + def on_will_accept(e: ft.DragWillAcceptEvent): + target.is_drag_over = True + + def on_accept(e: ft.DragTargetEvent): + target.bgcolor = e.src.data + target.is_drag_over = False + + def on_leave(e: ft.DragTargetLeaveEvent): + target.is_drag_over = False + + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + controls=[ + ft.Draggable( + group="color", + data=ft.Colors.CYAN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN, + border_radius=5, + ), + content_feedback=ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.CYAN, + border_radius=3, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.YELLOW, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.GREEN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ] + ), + ft.Container(width=100), + ft.DragTarget( + group="color", + on_will_accept=on_will_accept, + on_accept=on_accept, + on_leave=on_leave, + content=ft.Container( + width=50, + height=50, + bgcolor=target.bgcolor, + border=ft.Border.all(2, ft.Colors.BLACK_45) + if target.is_drag_over + else None, + border_radius=5, + ), + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml b/sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml new file mode 100644 index 0000000000..54846238e2 --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_containers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-drag-and-drop-containers" +version = "1.0.0" +description = "Drag colored squares onto a target container to update its background color declaratively." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "drag and drop", "containers", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "Drag and drop containers" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["drag and drop", "live state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_ordering/main.py b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/main.py new file mode 100644 index 0000000000..eccf9c3139 --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/main.py @@ -0,0 +1,261 @@ +import logging +from dataclasses import dataclass, field + +import flet as ft + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet_object_patch").setLevel(logging.INFO) +logging.getLogger("flet_components").setLevel(logging.INFO) + +ItemID = ft.IdCounter() + + +@ft.observable +@dataclass +class AppState: + groups: list["Group"] = field(default_factory=list) + + def move_group(self, src: "Group", dst: "Group"): + src_index = self.groups.index(src) + dst_index = self.groups.index(dst) + if src_index != dst_index: + print("Move group", src.title, "to position of", dst.title) + self.groups.insert(dst_index, self.groups.pop(src_index)) + + +@ft.observable +@dataclass +class Group: + title: str + color: ft.Colors + items: list["Item"] = field(default_factory=list) + + def add_item(self, text: str): + self.items.append(Item(text=text, group=self)) + + def move_item_into(self, item: "Item"): + print("Move item", item.text, "from", item.group.title, "to", self.title) + item.group.items.remove(item) + item.group = self + self.items.append(item) + + +@ft.observable +@dataclass +class Item: + text: str + group: Group + id: int = field(default_factory=ItemID) + + def move_item_at(self, item: "Item", to_item: "Item"): + if item == to_item: + return + print( + f"Move item {item.text} from {item.group.title} " + f"to {to_item.group.title} at position of {to_item.text}" + ) + item.group.items.remove(item) + item.group = to_item.group + to_index = to_item.group.items.index(to_item) + to_item.group.items.insert(to_index, item) + + +@ft.component +def ItemView(item: Item, **kwargs): + is_item_over, set_is_item_over = ft.use_state(False) + + def on_accept(e: ft.DragTargetEvent): + item.move_item_at(e.src.data, item) + set_is_item_over(False) + + return ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Divider( + color=ft.Colors.BLACK_38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_item_over else 0.0, + ), + ft.Draggable( + group="items", + data=item, + content=ft.DragTarget( + group="items", + data=item, + on_will_accept=lambda e: set_is_item_over( + e.accept and e.src.data != item + ), + on_accept=on_accept, + on_leave=lambda: set_is_item_over(False), + content=ft.Card( + content=ft.Container( + padding=7, + width=200, + content=ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Icon(ft.Icons.CIRCLE_OUTLINED), + ft.Text(value=item.text), + ], + ), + ), + ), + ), + ), + ], + ) + + +@ft.component +def GroupView(group: Group, move_group, **kwargs): + is_group_over, set_is_group_over = ft.use_state(False) + is_item_over, set_is_item_over = ft.use_state(False) + new_item_text, set_new_item_text = ft.use_state("") + + def on_item_accept(e: ft.DragTargetEvent): + group.move_item_into(e.src.data) + set_is_item_over(False) + + def on_group_accept(e: ft.DragTargetEvent): + move_group(e.src.data, group) + set_is_group_over(False) + + def on_add_item(self): + if stripped_text := new_item_text.strip(): + group.add_item(stripped_text) + set_new_item_text("") + + return ft.Row( + spacing=4, + intrinsic_height=True, + controls=[ + ft.VerticalDivider( + color=ft.Colors.BLACK_54, + width=2, + thickness=2, + radius=2, + leading_indent=15, + trailing_indent=15, + opacity=1.0 if is_group_over else 0.0, + ), + ft.Draggable( + group="groups", + data=group, + content=ft.DragTarget( + group="items", + data=group, + on_will_accept=lambda e: set_is_item_over(e.accept), + on_accept=on_item_accept, + on_leave=lambda: set_is_item_over(False), + content=ft.DragTarget( + group="groups", + data=group, + on_will_accept=lambda e: set_is_group_over( + e.accept and e.src.data != group + ), + on_accept=on_group_accept, + on_leave=lambda: set_is_group_over(False), + content=ft.Container( + border=ft.Border.all(2, ft.Colors.BLACK_12) + if not is_group_over + else ft.Border.all(2, ft.Colors.BLACK_38), + border_radius=ft.BorderRadius.all(15), + bgcolor=group.color, + padding=ft.Padding.all(20), + width=220, + content=ft.Column( + spacing=4, + controls=[ + ft.Text( + group.title, + theme_style=ft.TextThemeStyle.TITLE_LARGE, + ), + ft.TextField( + label="New item", + bgcolor=ft.Colors.WHITE, + value=new_item_text, + on_change=lambda e: set_new_item_text( + e.control.value + ), + on_submit=on_add_item, + ), + ft.TextButton( + content="Add", + icon=ft.Icons.ADD, + on_click=on_add_item, + ), + ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + *[ + ItemView(item, key=item.id) + for item in group.items + ], + ft.Divider( + color=ft.Colors.BLACK_38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_item_over else 0.0, + ), + ], + ), + ], + ), + ), + ), + ), + ), + ], + ) + + +@ft.component +def App(): + group_1 = Group(title="Group 1", color=ft.Colors.DEEP_ORANGE_400) + group_1.add_item("Item 1") + group_1.add_item("Item 2") + + group_2 = Group(title="Group 2", color=ft.Colors.PINK_400) + group_2.add_item("Item 3") + + group_3 = Group(title="Group 3", color=ft.Colors.CYAN_400) + group_3.add_item("Item 4") + + # group_4 = Group(title="Group 4", color=ft.Colors.GREEN_400) + # group_4.add_item("Item 5") + + app, _ = ft.use_state( + lambda: AppState( + groups=[ + group_1, + group_2, + group_3, + # group_4, + ] + ) + ) + + def on_mounted(): + ft.context.page.theme_mode = ft.ThemeMode.LIGHT + + ft.on_mounted(on_mounted) + + return ft.SafeArea( + content=ft.Row( + spacing=4, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + GroupView(group, move_group=app.move_group, key=group.title) + for group in app.groups + ], + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml new file mode 100644 index 0000000000..592915b49e --- /dev/null +++ b/sdk/python/examples/apps/declarative/drag_and_drop_ordering/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-drag-and-drop-ordering" +version = "1.0.0" +description = "Reorders groups and items declaratively with nested drag-and-drop targets." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "drag and drop", "reordering", "kanban"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Drag and drop ordering" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "TextField", "TextButton"] +layout_pattern = "dashboard" +complexity = "intermediate" +features = ["drag and drop", "reordering", "nested state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/edit_form/main.py b/sdk/python/examples/apps/declarative/edit_form/main.py new file mode 100644 index 0000000000..f27c70d34f --- /dev/null +++ b/sdk/python/examples/apps/declarative/edit_form/main.py @@ -0,0 +1,64 @@ +from dataclasses import dataclass +from typing import cast + +import flet as ft + + +@dataclass +@ft.observable +class Form: + first_name: str = "" + last_name: str = "" + + def set_first_name(self, value): + self.first_name = value + + def set_last_name(self, value): + self.last_name = value + + async def submit(self, e: ft.Event[ft.Button]): + e.page.show_dialog( + ft.AlertDialog( + title="Hello", + content=ft.Text(f"{self.first_name} {self.last_name}!"), + ) + ) + + async def reset(self): + self.first_name = "" + self.last_name = "" + + +@ft.component +def App(): + form, _ = ft.use_state(Form()) + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="First name", + value=form.first_name, + on_change=lambda e: form.set_first_name(e.control.value), + ), + ft.TextField( + label="Last name", + value=form.last_name, + on_change=lambda e: form.set_last_name(e.control.value), + ), + ft.Row( + cast( + list[ft.Control], + [ + ft.FilledButton("Submit", on_click=form.submit), + ft.FilledTonalButton("Reset", on_click=form.reset), + ], + ) + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/edit_form/pyproject.toml b/sdk/python/examples/apps/declarative/edit_form/pyproject.toml new file mode 100644 index 0000000000..8e64f4be53 --- /dev/null +++ b/sdk/python/examples/apps/declarative/edit_form/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-edit-form" +version = "1.0.0" +description = "Edits a small form declaratively and submits or resets the fields through observable state." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "form", "text fields", "observable state", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "Edit form" +controls = ["SafeArea", "Column", "Row", "TextField", "FilledButton", "FilledTonalButton", "AlertDialog"] +layout_pattern = "form" +complexity = "basic" +features = ["form editing", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/minesweeper/main.py b/sdk/python/examples/apps/declarative/minesweeper/main.py new file mode 100644 index 0000000000..5c27e7a2fe --- /dev/null +++ b/sdk/python/examples/apps/declarative/minesweeper/main.py @@ -0,0 +1,353 @@ +# Step 1: Basic drag-and-drop of rectangles (cards) within a bounded area. + +import asyncio +import random +from dataclasses import dataclass +from typing import Optional + +import flet as ft + +# ----------- Visual constants ---------- +SQUARE_SIZE = 30 + +LIGHT = ft.Colors.WHITE_70 +DARK = ft.Colors.BLACK_38 + +BEVEL_RAISED = ft.Border( + bottom=ft.BorderSide(4, DARK), + right=ft.BorderSide(4, DARK), + top=ft.BorderSide(4, LIGHT), + left=ft.BorderSide(4, LIGHT), +) + +BEVEL_SUNKEN = ft.Border( + bottom=ft.BorderSide(4, LIGHT), + right=ft.BorderSide(4, LIGHT), + top=ft.BorderSide(4, DARK), + left=ft.BorderSide(4, DARK), +) + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Square: + top: float = 0 + left: float = 0 + mine: bool = False + revealed: bool = False + flagged: bool = False + # tapped: bool = False + exploded: bool = False + adjacent_mines: int = 0 + + +@ft.observable +@dataclass +class Game: + squares: Optional[list[Square]] = None # to be initialized in __post_init__ + rows: int = 9 + cols: int = 9 + mine_count: int = 10 + mines_left: int = 10 + over = False + won = False + # timer + seconds: int = 0 # elapsed time + running: bool = False # ticking or not + first_click_done: bool = False + + def __post_init__(self): + """Initialize the grid of squares.""" + self.squares = [] + for r in range(self.rows): + for c in range(self.cols): + self.squares.append(Square(left=c * SQUARE_SIZE, top=r * SQUARE_SIZE)) + + # place mines + mine_positions = random.sample(range(len(self.squares)), self.mine_count) + for pos in mine_positions: + self.squares[pos].mine = True + + # calculate adjacent mine counts + for r in range(self.rows): + for c in range(self.cols): + idx = r * self.cols + c + if self.squares[idx].mine: + continue + count = 0 + for dr in (-1, 0, 1): + for dc in (-1, 0, 1): + if dr == 0 and dc == 0: + continue + nr, nc = r + dr, c + dc + if 0 <= nr < self.rows and 0 <= nc < self.cols: + nidx = nr * self.cols + nc + if self.squares[nidx].mine: + count += 1 + self.squares[idx].adjacent_mines = count + + def square_revealed(self, square: Square): + square.revealed = True + # square.tapped = True + if square.mine: + square.exploded = True + self.over = True + for sq in self.squares: + if sq.mine: + sq.revealed = True + print("Game Over!") + elif square.adjacent_mines == 0: + # reveal adjacent squares + r = int(square.top / SQUARE_SIZE) + c = int(square.left / SQUARE_SIZE) + for dr in (-1, 0, 1): + for dc in (-1, 0, 1): + if dr == 0 and dc == 0: + continue + nr, nc = r + dr, c + dc + if 0 <= nr < self.rows and 0 <= nc < self.cols: + nidx = nr * self.cols + nc + nsq = self.squares[nidx] + if not nsq.revealed and not nsq.mine and not nsq.flagged: + self.square_revealed(nsq) + # check for win + if all(sq.revealed or sq.mine for sq in self.squares): + self.over = True + self.won = True + for sq in self.squares: + if sq.mine and not sq.flagged: + sq.flagged = True + print("You Win!") + + def square_flagged(self, square: Square): + if not square.revealed: + square.flagged = not square.flagged + self.mines_left += -1 if square.flagged else 1 + + +# ---------- View (pure) ---------- +@ft.component +def SquareView(square: Square) -> ft.Control: + # Pure view: just render from state + return ft.Container( + bgcolor=( + ft.Colors.RED_900 + # if (square.revealed and square.mine and square.tapped) + if square.exploded + else ft.Colors.GREY_300 + # ft.Colors.GREY_300 + if square.revealed + else ft.Colors.GREY_400 + ), + alignment=ft.Alignment.CENTER, + foreground_decoration=ft.BoxDecoration( + border=BEVEL_RAISED if not square.revealed else None + ), + content=ft.Text( + "💥" + if square.exploded + else "💣" + if square.revealed and square.mine + else "🚩" + if square.flagged + else str(square.adjacent_mines) + if square.revealed and square.adjacent_mines > 0 + else "", + size=SQUARE_SIZE * 0.6, + # text_align=ft.TextAlign.CENTER, + # align=ft.Alignment.CENTER, + weight=ft.FontWeight.BOLD, + color=( + ft.Colors.BLUE + if square.adjacent_mines == 1 + else ft.Colors.GREEN + if square.adjacent_mines == 2 + else ft.Colors.RED + if square.adjacent_mines == 3 + else ft.Colors.ORANGE + if square.adjacent_mines == 4 + else ft.Colors.PURPLE + if square.adjacent_mines == 5 + else ft.Colors.BROWN + if square.adjacent_mines == 6 + else ft.Colors.TEAL + if square.adjacent_mines == 7 + else ft.Colors.BLACK + if square.adjacent_mines == 8 + else ft.Colors.BLACK + ), + ), + left=square.left, + top=square.top, + border=ft.Border.all(1, ft.Colors.GREY_500) if square.revealed else None, + width=SQUARE_SIZE, + height=SQUARE_SIZE, + # on_click=lambda _e: square_revealed(square), + ) + + +# ---------- App ---------- +@ft.component +def App(): + game, set_game = ft.use_state(lambda: Game()) + new_game_tapped, set_new_game_tapped = ft.use_state(False) + + ticker_task, set_ticker_task = ft.use_state(None) + + async def tick_loop(): + try: + while True: + await asyncio.sleep(1) + if not game.running or game.over: + break + game.seconds += 1 + print("Timer:", game.seconds) + except asyncio.CancelledError: + pass + + if ft.context.page.web: + ft.on_mounted( + lambda: asyncio.create_task(ft.BrowserContextMenu().disable()) + ) # disable right-click context menu + + def ensure_ticker(): + # call with the function, not tick_loop() + if ticker_task is None or ticker_task.done(): + t = ft.context.page.run_task(tick_loop) # <-- no parentheses + set_ticker_task(t) + + def on_tap_down(e: ft.TapEvent): + # e.local_position.x / e.local_position.y are relative to the GestureDetector + # content (the Stack) + if game.over: + return + + if not game.first_click_done: + game.first_click_done = True + game.running = True # <-- start ticking + ensure_ticker() + print("Timer started") + + for s in game.squares: + if ( + s.left <= e.local_position.x <= s.left + SQUARE_SIZE + and s.top <= e.local_position.y <= s.top + SQUARE_SIZE + ): + if s.flagged: + print("square is flagged, cannot reveal") + return + game.square_revealed(s) + break + + def on_right_pan_start(e): + if game.over: + return + if not game.first_click_done: + game.first_click_done = True + game.running = True # <-- start ticking + print("Timer started") + for s in game.squares: + if ( + s.left <= e.local_position.x <= s.left + SQUARE_SIZE + and s.top <= e.local_position.y <= s.top + SQUARE_SIZE + ): + game.square_flagged(s) + break + + board = ft.GestureDetector( + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + on_tap_down=on_tap_down, + on_right_pan_start=on_right_pan_start, + content=ft.Stack( + controls=[SquareView(c) for c in game.squares], + # width=300, + # height=300, + ), + ) + + top_menu = ft.Row( + controls=[ + ft.Container( + height=50, + width=90, + alignment=ft.Alignment.CENTER, + content=ft.Text( + f"{game.mines_left:03d}", + size=25, + weight=ft.FontWeight.BOLD, + color=ft.Colors.RED, + ), + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + ), + ft.Container( + content=ft.Text( + "🙂" if not game.over else "😎" if game.won else "😵", size=35 + ), + # 😎 😵😢 + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.GREY_400, + on_tap_down=lambda e: set_new_game_tapped(True), + on_click=lambda e: ( + set_game(Game()), + set_new_game_tapped(False), + ticker_task.cancel() + if ticker_task and not ticker_task.done() + else None, + ), + width=50, + height=50, + foreground_decoration=ft.BoxDecoration( + border=BEVEL_RAISED if not new_game_tapped else None + ), + ), + ft.Container( + height=50, + width=90, + alignment=ft.Alignment.CENTER, + content=ft.Text( + f"{game.seconds:03d}", + size=25, + weight=ft.FontWeight.BOLD, + color=ft.Colors.RED, + ), + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + ), + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + expand=True, + ) + + return ft.SafeArea( + content=ft.Container( + content=ft.Column( + controls=[ + ft.Container( + content=top_menu, + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + padding=10, + ), + ft.Container( + content=board, + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + padding=5, + height=SQUARE_SIZE * game.rows + 10, + width=SQUARE_SIZE * game.cols + 10, + ), + ], + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.START, + spacing=10, + ), + bgcolor=ft.Colors.GREY_400, + foreground_decoration=ft.BoxDecoration(border=BEVEL_RAISED), + width=SQUARE_SIZE * (game.cols + 1), + height=SQUARE_SIZE * (game.rows + 1) + 100, + padding=10, + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/minesweeper/pyproject.toml b/sdk/python/examples/apps/declarative/minesweeper/pyproject.toml new file mode 100644 index 0000000000..ef52e4cb8d --- /dev/null +++ b/sdk/python/examples/apps/declarative/minesweeper/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-minesweeper" +version = "1.0.0" +description = "Implements a declarative Minesweeper board with timer, flagging, and win-loss state." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "minesweeper", "game", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Games", "Declarative"] + +[tool.flet.metadata] +title = "Minesweeper" +controls = ["SafeArea", "Container", "Column", "Row", "GestureDetector", "Stack", "Text"] +layout_pattern = "center-stage" +complexity = "advanced" +features = ["game state", "async", "timer", "gesture input"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/minimal_reactive/main.py b/sdk/python/examples/apps/declarative/minimal_reactive/main.py new file mode 100644 index 0000000000..4bfcf17c48 --- /dev/null +++ b/sdk/python/examples/apps/declarative/minimal_reactive/main.py @@ -0,0 +1,10 @@ +import flet as ft + + +@ft.component +def App(): + return ft.SafeArea(content=ft.Text("Hello, world!")) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml b/sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml new file mode 100644 index 0000000000..9c3888c282 --- /dev/null +++ b/sdk/python/examples/apps/declarative/minimal_reactive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-minimal-reactive" +version = "1.0.0" +description = "Renders a minimal declarative component to show the smallest reactive app structure." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "minimal", "reactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "Minimal reactive" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["reactive rendering"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/navigation_drawer/main.py b/sdk/python/examples/apps/declarative/navigation_drawer/main.py new file mode 100644 index 0000000000..f3c0f83f50 --- /dev/null +++ b/sdk/python/examples/apps/declarative/navigation_drawer/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +@ft.component +def App(): + selected, set_selected = ft.use_state(0) + + pages = [ + ("Home", ft.Icons.HOME_OUTLINED, ft.Icons.HOME), + ("Store", ft.Icons.STORE_OUTLINED, ft.Icons.STORE), + ("About", ft.Icons.INFO_OUTLINED, ft.Icons.INFO), + ] + + async def show_drawer(): + await ft.context.page.show_drawer() + + async def handle_change(e: ft.Event[ft.NavigationDrawer]): + set_selected(e.control.selected_index) + await ft.context.page.close_drawer() + + return ft.View( + appbar=ft.AppBar( + title=ft.Text(pages[selected][0]), + leading=ft.IconButton(ft.Icons.MENU, on_click=show_drawer), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + ), + drawer=ft.NavigationDrawer( + selected_index=selected, + on_change=handle_change, + controls=[ + ft.Container(height=12), + *[ + ft.NavigationDrawerDestination( + label=label, icon=icon, selected_icon=sel + ) + for label, icon, sel in pages + ], + ], + ), + controls=[ + ft.SafeArea(content=ft.Text(f"Welcome to {pages[selected][0]}", size=24)) + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(App)) diff --git a/sdk/python/examples/apps/declarative/navigation_drawer/pyproject.toml b/sdk/python/examples/apps/declarative/navigation_drawer/pyproject.toml new file mode 100644 index 0000000000..7db3d23e7b --- /dev/null +++ b/sdk/python/examples/apps/declarative/navigation_drawer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-navigation-drawer" +version = "1.0.0" +description = "Declarative app with a NavigationDrawer whose selected destination drives the page content." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "navigation drawer", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Declarative navigation drawer" +controls = ["View", "AppBar", "NavigationDrawer", "NavigationDrawerDestination", "SafeArea", "Text", "IconButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["drawer navigation", "state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/progress_bar/main.py b/sdk/python/examples/apps/declarative/progress_bar/main.py new file mode 100644 index 0000000000..9bc767f657 --- /dev/null +++ b/sdk/python/examples/apps/declarative/progress_bar/main.py @@ -0,0 +1,34 @@ +import asyncio +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class AppState: + counter: float + + async def start_counter(self): + self.counter = 0 + for _ in range(0, 10): + self.counter += 0.1 + await asyncio.sleep(0.5) + + +@ft.component +def App(): + state, _ = ft.use_state(AppState(counter=0)) + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.ProgressBar(state.counter), + ft.Button("Run!", on_click=state.start_counter), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/progress_bar/pyproject.toml b/sdk/python/examples/apps/declarative/progress_bar/pyproject.toml new file mode 100644 index 0000000000..c480465f4a --- /dev/null +++ b/sdk/python/examples/apps/declarative/progress_bar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-progress-bar" +version = "1.0.0" +description = "Runs an async counter that fills a progress bar over time in a declarative app." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "progress bar", "async", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "Progress bar" +controls = ["SafeArea", "Column", "ProgressBar", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["async", "progress updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/reorderable_list/main.py b/sdk/python/examples/apps/declarative/reorderable_list/main.py new file mode 100644 index 0000000000..9b6f2005f7 --- /dev/null +++ b/sdk/python/examples/apps/declarative/reorderable_list/main.py @@ -0,0 +1,108 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass(frozen=True) +class Item: + id: str + label: str + + +@ft.observable +@dataclass +class AppState: + items: list[Item] + next_item_index: int = 0 + + def add_items(self, items: Item | list[Item]): + items_to_add = items if isinstance(items, list) else [items] + self.items = self.items + items_to_add + + def add_new_item(self): + item = Item( + id=f"item-{self.next_item_index}", + label=f"Item {self.next_item_index}", + ) + self.next_item_index += 1 + self.add_items(item) + + def remove_items(self, items: Item | list[Item]): + items_to_remove = items if isinstance(items, list) else [items] + removal_set = set(items_to_remove) + self.items = [item for item in self.items if item not in removal_set] + + def drag_reorder(self, e: ft.OnReorderEvent): + if e.old_index is not None and e.new_index is not None: + dragged_item = self.items.pop(e.old_index) + self.items.insert(e.new_index, dragged_item) + + +@ft.component +def ItemView(item: Item, on_remove, allow_add_remove: bool = True) -> ft.Control: + return ft.ListTile( + leading=ft.ReorderableDragHandle( + content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), + mouse_cursor=ft.MouseCursor.GRAB, + ), + width=300, + bgcolor="#5E6063", + title=ft.Row( + controls=[ + ft.Container( + expand=True, + height=40, + bgcolor="#8DA6C6", + content=ft.Text(item.label), + ), + ft.Container( + visible=allow_add_remove, + on_click=lambda _: on_remove(item), + content=ft.Icon( + icon=ft.Icons.REMOVE, + color=ft.Colors.AMBER, + ), + ), + ] + ), + ) + + +@ft.component +def App(items: list[Item] | None = None, allow_add_remove: bool = True): + if items is None: + items = [Item(id=f"item-{i}", label=f"Item {i}") for i in range(3)] + + state, _ = ft.use_state( + lambda: AppState(items=list(items), next_item_index=len(items)) + ) + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.FilledButton( + content="Add item", + visible=allow_add_remove, + on_click=lambda _: state.add_new_item(), + ), + ft.ReorderableListView( + spacing=0, + show_default_drag_handles=False, + on_reorder=state.drag_reorder, + controls=[ + ItemView( + item, + on_remove=state.remove_items, + allow_add_remove=allow_add_remove, + key=item.id, + ) + for item in state.items + ], + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/reorderable_list/pyproject.toml b/sdk/python/examples/apps/declarative/reorderable_list/pyproject.toml new file mode 100644 index 0000000000..e99b2ad75b --- /dev/null +++ b/sdk/python/examples/apps/declarative/reorderable_list/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-reorderable-list" +version = "1.0.0" +description = "Adds, removes, and reorders list items declaratively with stable item identity." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "reorderable list", "list state", "drag and drop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Reorderable list" +controls = ["SafeArea", "Column", "FilledButton", "ReorderableListView", "ListTile", "ReorderableDragHandle"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["drag and drop", "reordering", "list state updates", "add/remove items"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/routing_two_pages/main.py b/sdk/python/examples/apps/declarative/routing_two_pages/main.py new file mode 100644 index 0000000000..6f9f12d702 --- /dev/null +++ b/sdk/python/examples/apps/declarative/routing_two_pages/main.py @@ -0,0 +1,148 @@ +import asyncio +import logging +from collections.abc import Callable +from dataclasses import dataclass + +import flet as ft + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet_components").setLevel(logging.INFO) +# logging.getLogger("flet_object_patch").setLevel(logging.DEBUG) + + +@dataclass(frozen=True) +class ThemeContextValue: + mode: ft.ThemeMode + toggle: Callable[[], None] + + +ThemeContext = ft.create_context(ThemeContextValue(ft.ThemeMode.LIGHT, lambda: None)) + + +@ft.observable +@dataclass +class AppModel: + route: str + theme_mode: ft.ThemeMode = ft.ThemeMode.LIGHT + + def route_change(self, e: ft.RouteChangeEvent): + print("Route changed from:", self.route, "to:", e.route) + self.route = e.route + + async def view_popped(self, e: ft.ViewPopEvent): + print("View popped") + views = ft.unwrap_component(ft.context.page.views) + if len(views) > 1: + await ft.context.page.push_route(views[-2].route) + + def toggle_theme(self): + self.theme_mode = ( + ft.ThemeMode.DARK + if self.theme_mode == ft.ThemeMode.LIGHT + else ft.ThemeMode.LIGHT + ) + + +@ft.component +def ThemeToggle(): + theme = ft.use_context(ThemeContext) + return ft.Switch( + label="Dark mode" if theme.mode == ft.ThemeMode.LIGHT else "Light mode", + value=theme.mode == ft.ThemeMode.DARK, + on_change=lambda: theme.toggle(), + ) + + +@ft.component +def AppBar(): + return ft.AppBar( + title=ft.Text("Flet app"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + actions=[ThemeToggle()], + ) + + +@ft.component +def RoutingExample(): + app, _ = ft.use_state(AppModel(route=ft.context.page.route)) + + # subscribe to page events as soon as possible + ft.context.page.on_route_change = app.route_change + ft.context.page.on_view_pop = app.view_popped + + # stable callback (doesn’t change identity each render) + toggle = ft.use_callback(lambda: app.toggle_theme(), dependencies=[app.theme_mode]) + + # memoize the provided value so its identity changes only when mode changes + theme_value = ft.use_memo( + lambda: ThemeContextValue(mode=app.theme_mode, toggle=toggle), + dependencies=[app.theme_mode, toggle], + ) + + ft.on_mounted( + lambda: print("Page size:", ft.context.page.width, ft.context.page.height) + ) + + def update_theme_mode(): + print("Theme mode changed to:", app.theme_mode) + ft.context.page.theme_mode = app.theme_mode + + ft.on_updated(update_theme_mode, [app.theme_mode]) + + return ThemeContext( + theme_value, + lambda: [ + ft.View( + route="/", + appbar=AppBar(), + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Visit Store", + on_click=lambda _: asyncio.create_task( + ft.context.page.push_route("/store") + ), + ), + ft.Button( + "Do something", + on_click=lambda _: asyncio.create_task( + ft.context.page.push_route("/do-something") + ), + ), + ] + ), + ), + ], + ), + *( + [ + ft.View( + route="/store", + appbar=AppBar(), + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Go Home", + on_click=lambda _: asyncio.create_task( + ft.context.page.push_route("/") + ), + ), + ] + ), + ), + ], + ) + ] + if app.route == "/store" + else [] + ), + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(RoutingExample)) diff --git a/sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml b/sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml new file mode 100644 index 0000000000..99aa6fc269 --- /dev/null +++ b/sdk/python/examples/apps/declarative/routing_two_pages/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-routing-two-pages" +version = "1.0.0" +description = "Demonstrates declarative view routing with theme context shared across two pages." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "routing", "views", "context", "theme"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Navigation/Routing", "Featured"] + +[tool.flet.metadata] +title = "Routing two pages" +controls = ["View", "SafeArea", "Column", "Button", "AppBar", "Switch"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["routing", "context", "theme switching"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/set_state_with_list/main.py b/sdk/python/examples/apps/declarative/set_state_with_list/main.py new file mode 100644 index 0000000000..cecb7adf74 --- /dev/null +++ b/sdk/python/examples/apps/declarative/set_state_with_list/main.py @@ -0,0 +1,39 @@ +import asyncio + +import flet as ft + + +@ft.component +def App(): + items, set_items = ft.use_state(list(range(60))) + + async def auto_scroll(e): + for i in range(60, 120): + await asyncio.sleep(1) + set_items(lambda cur, i=i: cur + [i]) + print(f"Scrolling to line {i}") + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.ListView( + spacing=10, + padding=20, + auto_scroll=True, + height=300, + controls=[ + ft.Text( + key=i, + value=f"Line {i + 1}", + ) + for i in items + ], + ), + ft.OutlinedButton("Start auto-scrolling", on_click=auto_scroll), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml b/sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml new file mode 100644 index 0000000000..a52a71d2ec --- /dev/null +++ b/sdk/python/examples/apps/declarative/set_state_with_list/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-set-state-with-list" +version = "1.0.0" +description = "Appends rows to a scrolling list over time to demonstrate list state updates." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "list view", "auto scroll", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Set state with list" +controls = ["SafeArea", "Column", "ListView", "Text", "OutlinedButton"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["async", "auto scroll", "list state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/shape_drawer/main.py b/sdk/python/examples/apps/declarative/shape_drawer/main.py new file mode 100644 index 0000000000..1a458f5ab8 --- /dev/null +++ b/sdk/python/examples/apps/declarative/shape_drawer/main.py @@ -0,0 +1,107 @@ +from dataclasses import dataclass, field + +import flet as ft +from flet import canvas + +POINT_RADIUS = 4 +PAINT = ft.Paint( + style=ft.PaintingStyle.STROKE, + color=ft.Colors.RED, + stroke_width=2, +) + + +@dataclass +class Point: + x: float = 0 + y: float = 0 + + +@dataclass +@ft.observable +class Polygon: + points: list[Point] = field(default_factory=list) + + +@dataclass +@ft.observable +class State: + polygons: list[Polygon] = field(default_factory=list[Polygon]) + + +@ft.component +def PolygonView(polygon: Polygon) -> canvas.Path: + return canvas.Path( + elements=[ + canvas.Path.MoveTo( + point.x, + point.y, + ) + if i == 0 + else canvas.Path.LineTo( + point.x, + point.y, + ) + for i, point in enumerate(polygon.points) + ] + + [canvas.Path.Close()], + paint=PAINT, + ) + + +@ft.component +def App(): + state, _ = ft.use_state( + State( + polygons=[ + Polygon([Point(50, 50), Point(150, 50), Point(100, 150)]), + ] + ) + ) + # state, _ = ft.use_state(State(polygons=[Polygon()])) + + def handle_tap_down(e: ft.TapEvent): + # add point to the top polygon + if e.local_position is not None: + state.polygons[-1].points.append( + Point(x=e.local_position.x, y=e.local_position.y) + ) + if len(state.polygons[-1].points) == 1: + # add a temporary point to be updated on hover + state.polygons[-1].points.append( + Point(x=e.local_position.x, y=e.local_position.y) + ) + + def handle_hover(e: ft.HoverEvent): + # update position of the last point in the top polygon + if e.local_position is not None and len(state.polygons[-1].points) > 0: + state.polygons[-1].points[-1].x = e.local_position.x + state.polygons[-1].points[-1].y = e.local_position.y + state.notify() + + def handle_secondary_tap_down(e: ft.TapEvent): + # add new polygon + state.polygons.append(Polygon()) + + return ft.SafeArea( + content=ft.GestureDetector( + on_tap_down=handle_tap_down, + on_secondary_tap_down=handle_secondary_tap_down, + on_hover=handle_hover, + content=ft.Container( + content=canvas.Canvas( + width=float("inf"), + height=float("inf"), + shapes=[PolygonView(polygon) for polygon in state.polygons], + ), + width=500, + height=500, + bgcolor=ft.Colors.GREY_300, + alignment=ft.Alignment.TOP_LEFT, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml b/sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml new file mode 100644 index 0000000000..79781490d8 --- /dev/null +++ b/sdk/python/examples/apps/declarative/shape_drawer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-shape-drawer" +version = "1.0.0" +description = "Draws polygons on a canvas declaratively in response to tap and hover gestures." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "canvas", "drawing", "gestures"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Displays/Canvas"] + +[tool.flet.metadata] +title = "Shape drawer" +controls = ["SafeArea", "GestureDetector", "Container", "Canvas"] +layout_pattern = "center-stage" +complexity = "intermediate" +features = ["canvas drawing", "gesture input"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/sunflower/main.py b/sdk/python/examples/apps/declarative/sunflower/main.py new file mode 100644 index 0000000000..f973acaaee --- /dev/null +++ b/sdk/python/examples/apps/declarative/sunflower/main.py @@ -0,0 +1,128 @@ +import logging +import math +import random +from dataclasses import dataclass, field +from typing import cast + +import flet as ft + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet_components").setLevel(logging.INFO) + +MAX_SEEDS = 250 + +rnd = random.Random() + + +@dataclass +class Seed: + key: int + x: float + y: float + inner: bool = False + + +@dataclass +class AppModel(ft.Observable): + seeds_count: float = MAX_SEEDS // 2 + seeds: list[Seed] = field(default_factory=list) + + def __post_init__(self): + ft.context.page.title = "Sunflower" + self.compute_seeds() + + def update_seeds_count(self, new_seeds_count: float): + self.seeds_count = new_seeds_count + self.compute_seeds() + + def compute_seeds(self): + count = round(self.seeds_count) + self.seeds.clear() + tau = math.pi * 2 + scale_factor = 1 / 40 + phi = (math.sqrt(5) + 1) / 2 + + # inner orange seeds + for i in range(0, count): + theta = i * tau / phi + r = math.sqrt(i) * scale_factor + self.seeds.append( + Seed( + key=i, x=r * math.cos(theta), y=-1 * r * math.sin(theta), inner=True + ) + ) + + # outer gray seeds + for j in range(count, MAX_SEEDS): + x = math.cos(tau * j / (MAX_SEEDS - 1)) * 0.9 + y = math.sin(tau * j / (MAX_SEEDS - 1)) * 0.9 + self.seeds.append(Seed(key=j, x=x, y=y, inner=False)) + + +@ft.component +def SeedView(seed: Seed, key=None) -> ft.Control: + return ft.Container( + width=5, + height=5, + bgcolor=ft.Colors.ORANGE if seed.inner else ft.Colors.GREY_700, + align=ft.Alignment(seed.x, seed.y), + animate_align=ft.Animation(round(rnd.random() * 500) + 250), + border_radius=2.5, + ) + + +@ft.component +def Sunflower(): + app, _ = ft.use_state(lambda: AppModel()) + MemoSeedView = ft.memo(SeedView) + return ft.View( + appbar=ft.AppBar(title=ft.Text("Sunflower")), + controls=[ + ft.SafeArea( + expand=True, + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + expand=True, + controls=[ + ft.Container( + content=ft.Stack( + controls=[ + MemoSeedView(s, key=s.key) for s in app.seeds + ], + aspect_ratio=1.0, + ), + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.Row( + [ + ft.Text( + f"Showing {round(app.seeds_count)} " + f"seed{'s' if app.seeds_count != 1 else ''}" + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Row( + [ + ft.Slider( + min=1, + max=MAX_SEEDS, + value=app.seeds_count, + width=300, + on_change=lambda e: app.update_seeds_count( + cast(float, e.control.value) + ), + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + ), + ], + ), + ) + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(Sunflower)) diff --git a/sdk/python/examples/apps/declarative/sunflower/pyproject.toml b/sdk/python/examples/apps/declarative/sunflower/pyproject.toml new file mode 100644 index 0000000000..81cef19e5f --- /dev/null +++ b/sdk/python/examples/apps/declarative/sunflower/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-sunflower" +version = "1.0.0" +description = "Animates a sunflower seed pattern with a slider that recomputes declarative layout." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "animation", "slider", "visualization"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Featured"] + +[tool.flet.metadata] +title = "Sunflower" +controls = ["View", "SafeArea", "Column", "Stack", "Slider", "Text", "AppBar"] +layout_pattern = "center-stage" +complexity = "intermediate" +features = ["animation", "data visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/tic_tac_toe/main.py b/sdk/python/examples/apps/declarative/tic_tac_toe/main.py new file mode 100644 index 0000000000..21cf47fe3b --- /dev/null +++ b/sdk/python/examples/apps/declarative/tic_tac_toe/main.py @@ -0,0 +1,108 @@ +import flet as ft + + +@ft.component +def Square(value: str, on_click): + return ft.Button( + ft.Icon(ft.Icons.CIRCLE_OUTLINED) + if value == "O" + else ft.Icon(ft.Icons.CLOSE) + if value == "X" + else "", + width=50, + height=50, + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=5), padding=0), + on_click=on_click, + ) + + +@ft.component +def Board(x_is_next: bool, squares: list[str], on_play): + def handle_click(i: int): + if squares[i] or calculate_winner(squares): + return + next_squares = squares[:] + next_squares[i] = "X" if x_is_next else "O" + on_play(next_squares) + + winner = calculate_winner(squares) + + return ft.Column( + [ + ft.Text( + f"Winner: {winner}" + if winner + else f"Next player: {'X' if x_is_next else 'O'}" + ), + ft.Row( + [Square(squares[i], lambda e, i=i: handle_click(i)) for i in range(3)] + ), + ft.Row( + [ + Square(squares[i], lambda e, i=i: handle_click(i)) + for i in range(3, 6) + ] + ), + ft.Row( + [ + Square(squares[i], lambda e, i=i: handle_click(i)) + for i in range(6, 9) + ] + ), + ] + ) + + +@ft.component +def Game(): + history, set_history = ft.use_state([[""] * 9]) + current_move, set_current_move = ft.use_state(0) + x_is_next = current_move % 2 == 0 + + def handle_play(next_squares: list[str]): + next_history = history[: current_move + 1] + [next_squares] + set_history(next_history) + set_current_move(len(next_history) - 1) + + def jump_to(move: int): + set_current_move(move) + + moves: list[ft.Control] = [ + ft.TextButton( + ft.Text(f"Go to move #{move}" if move > 0 else "Go to game start"), + on_click=lambda e, m=move: jump_to(m), + ) + for move, _ in enumerate(history) + ] + + return ft.SafeArea( + content=ft.Row( + [ + Board(x_is_next, history[current_move], handle_play), + ft.Column(moves), + ], + vertical_alignment=ft.CrossAxisAlignment.START, + ) + ) + + +def calculate_winner(squares: list[str]): + lines = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [0, 3, 6], + [1, 4, 7], + [2, 5, 8], + [0, 4, 8], + [2, 4, 6], + ] + for line in lines: + a, b, c = line + if squares[a] and squares[a] == squares[b] == squares[c]: + return squares[a] + return None + + +if __name__ == "__main__": + ft.run(lambda page: page.render(Game)) diff --git a/sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml b/sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml new file mode 100644 index 0000000000..79b08feb1d --- /dev/null +++ b/sdk/python/examples/apps/declarative/tic_tac_toe/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-tic-tac-toe" +version = "1.0.0" +description = "Plays tic-tac-toe declaratively with move history and winner detection." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "game", "tic tac toe", "history"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Games", "Declarative", "Featured"] + +[tool.flet.metadata] +title = "Tic tac toe" +controls = ["SafeArea", "Row", "Column", "Button", "Icon", "Text", "TextButton"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["game state", "move history"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/timer/main.py b/sdk/python/examples/apps/declarative/timer/main.py new file mode 100644 index 0000000000..19853b2adf --- /dev/null +++ b/sdk/python/examples/apps/declarative/timer/main.py @@ -0,0 +1,107 @@ +import asyncio +import time +from dataclasses import dataclass + +import flet as ft + + +def format_hhmmss(seconds: int) -> str: + """Format elapsed seconds as HH:MM:SS.""" + h = seconds // 3600 + m = (seconds % 3600) // 60 + s = seconds % 60 + return f"{h:02}:{m:02}:{s:02}" + + +@ft.observable +@dataclass +class TimerState: + running: bool = False + paused: bool = False + elapsed: int = 0 + + _base_elapsed: int = 0 + _started_at: float = 0.0 + _task: asyncio.Task | None = None + + async def _ticker(self): + while self.running: + if not self.paused: + self.elapsed = self._base_elapsed + int(time.time() - self._started_at) + await asyncio.sleep(1) + self._task = None + + def toggle(self): + if not self.running: + self.running = True + self.paused = False + self._base_elapsed = self.elapsed + self._started_at = time.time() + if self._task is None or self._task.done(): + self._task = asyncio.create_task(self._ticker()) + return + + if not self.paused: + self._base_elapsed += int(time.time() - self._started_at) + self.elapsed = self._base_elapsed + self.paused = True + return + + self.paused = False + self._started_at = time.time() + + def stop(self): + self.running = False + self.paused = False + self.elapsed = 0 + self._base_elapsed = 0 + self._started_at = 0.0 + + +@ft.component +def App(): + state, _ = ft.use_state(TimerState()) + + label = "Pause" if state.running and not state.paused else "Start" + icon = ft.Icons.PAUSE if state.running and not state.paused else ft.Icons.PLAY_ARROW + + return ft.SafeArea( + content=ft.Column( + spacing=20, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + format_hhmmss(state.elapsed), + size=30, + weight=ft.FontWeight.BOLD, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.FilledButton( + label, + icon=icon, + on_click=state.toggle, + ), + ft.TextButton( + "Stop", + icon=ft.Icons.STOP, + on_click=state.stop, + disabled=not state.running and state.elapsed == 0, + ), + ], + ), + ], + ) + ) + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/timer/pyproject.toml b/sdk/python/examples/apps/declarative/timer/pyproject.toml new file mode 100644 index 0000000000..608d955dec --- /dev/null +++ b/sdk/python/examples/apps/declarative/timer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-timer" +version = "1.0.0" +description = "Declarative stopwatch example driven by observable timer state and async ticking." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "timer", "stopwatch", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Declarative timer" +controls = ["SafeArea", "Column", "Row", "Text", "FilledButton", "TextButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["async", "timer controls", "observable state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/todo/main.py b/sdk/python/examples/apps/declarative/todo/main.py new file mode 100644 index 0000000000..a74eee47c1 --- /dev/null +++ b/sdk/python/examples/apps/declarative/todo/main.py @@ -0,0 +1,236 @@ +import logging +from dataclasses import dataclass, field +from typing import Callable, cast + +import flet as ft + +logging.basicConfig(level=logging.INFO) + +TaskID = ft.IdCounter() + + +@ft.observable +@dataclass +class TaskItem: + name: str + completed: bool = False + id: int = field(default_factory=TaskID) + on_status_changed: Callable | None = None + + def update_task(self, new_name: str): + self.name = new_name + + def toggle_task_status(self): + self.completed = not self.completed + if self.on_status_changed: + self.on_status_changed() + + +@ft.observable +@dataclass +class TodoAppState: + tasks: list[TaskItem] = field(default_factory=list) + statuses: list[str] = field(default_factory=lambda: ["all", "active", "completed"]) + status: str = "all" + + def get_tasks(self) -> list[TaskItem]: + return list( + filter( + lambda task: ( + self.status == "all" + or self.status == "active" + and not task.completed + or self.status == "completed" + and task.completed + ), + self.tasks, + ) + ) + + @property + def active_tasks_number(self) -> int: + return len([task for task in self.tasks if not task.completed]) + + def status_changed(self, e: ft.Event[ft.Tabs]): + self.status = self.statuses[e.control.selected_index] + + def on_task_status_changed(self): + cast(ft.Observable, self).notify() + + def add_task(self, new_task_event: str): + self.tasks.append( + TaskItem(new_task_event, on_status_changed=self.on_task_status_changed) + ) + + def delete_task(self, task: TaskItem): + self.tasks.remove(task) + + def clear_completed(self): + self.tasks = list(filter(lambda task: not task.completed, self.tasks)) + + +@ft.component +def TodoAppView(): + state, _ = ft.use_state(lambda: TodoAppState()) + new_task_name, set_new_task_name = ft.use_state("") + new_task_field: ft.Ref = ft.Ref() + + async def add_task(): + state.add_task(new_task_name) + set_new_task_name("") + await cast(ft.TextField, new_task_field.current).focus() + + return ft.View( + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.SafeArea( + content=ft.Column( + [ + Header(), + ft.Row( + controls=[ + ft.TextField( + ref=new_task_field, + hint_text="What needs to be done?", + on_submit=add_task, + value=new_task_name, + on_change=lambda e: set_new_task_name( + e.control.value + ), + autofocus=True, + expand=True, + ), + ft.FloatingActionButton( + icon=ft.Icons.ADD, + on_click=add_task, + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + ft.Tabs( + selected_index=state.statuses.index(state.status), + length=len(state.statuses), + on_change=state.status_changed, + content=ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label=tab) for tab in state.statuses + ], + ), + ), + ft.Column( + [ + TaskItemView( + task, + state.delete_task, + key=task.id, + ) + for task in state.get_tasks() + ] + ), + Footer( + active_tasks_number=state.active_tasks_number, + clear_completed=state.clear_completed, + ), + ], + ), + ] + ) + ) + ], + ) + + +@ft.component +def TaskItemView(task: TaskItem, delete_task, key=None) -> ft.Control: + edit_mode, set_edit_mode = ft.use_state(False) + new_name, set_new_name = ft.use_state("") + + def edit(): + set_edit_mode(True) + set_new_name(task.name) + + def complete_edit(): + task.update_task(new_name) + set_edit_mode(False) + + return ( + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Checkbox( + value=task.completed, + label=task.name, + on_change=lambda: task.toggle_task_status(), + ), + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=edit, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=lambda: delete_task(task), + ), + ], + ), + ], + ) + if not edit_mode + else ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.TextField( + value=new_name, + on_change=lambda e: set_new_name(e.control.value), + expand=1, + ), + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=complete_edit, + ), + ], + ) + ) + + +@ft.component +def Header(): + return ft.Row( + [ + ft.Text( + value="Todos", + theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM, + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + + +@ft.component +def Footer(active_tasks_number: int, clear_completed): + return ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(f"{active_tasks_number} items left"), + ft.OutlinedButton( + content="Clear completed", + on_click=clear_completed, + ), + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(TodoAppView)) diff --git a/sdk/python/examples/apps/declarative/todo/pyproject.toml b/sdk/python/examples/apps/declarative/todo/pyproject.toml new file mode 100644 index 0000000000..c131cc6762 --- /dev/null +++ b/sdk/python/examples/apps/declarative/todo/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-todo" +version = "1.0.0" +description = "Tracks, filters, edits, and clears tasks in a declarative to-do application." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "todo", "tabs", "forms"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "To-do (declarative)" +controls = ["View", "SafeArea", "Column", "Row", "TextField", "Tabs", "Checkbox", "IconButton", "FloatingActionButton"] +layout_pattern = "form" +complexity = "intermediate" +features = ["task filtering", "editing", "list state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/trolli/assets/Pacifico-Regular.ttf b/sdk/python/examples/apps/declarative/trolli/assets/Pacifico-Regular.ttf new file mode 100644 index 0000000000..e7def95d3f Binary files /dev/null and b/sdk/python/examples/apps/declarative/trolli/assets/Pacifico-Regular.ttf differ diff --git a/sdk/python/examples/apps/declarative/trolli/components/__init__.py b/sdk/python/examples/apps/declarative/trolli/components/__init__.py new file mode 100644 index 0000000000..5ee7e0bd85 --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/__init__.py @@ -0,0 +1,11 @@ +from .app_bar import TrolliAppBar +from .board import BoardView +from .boards import BoardsView +from .sidebar import Sidebar + +__all__ = [ + "BoardView", + "BoardsView", + "Sidebar", + "TrolliAppBar", +] diff --git a/sdk/python/examples/apps/declarative/trolli/components/app_bar.py b/sdk/python/examples/apps/declarative/trolli/components/app_bar.py new file mode 100644 index 0000000000..d1ec9585d3 --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/app_bar.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +from models import TrolliState + +import flet as ft + +from .dialogs import show_login_dialog, show_settings_dialog + + +@ft.component +def TrolliAppBar(app: TrolliState): + profile_label = "Log in" if not app.user else f"{app.user}'s Profile" + + return ft.AppBar( + leading=ft.Icon(ft.Icons.GRID_GOLDENRATIO_ROUNDED), + leading_width=65, + title=ft.Text( + "Trolli", + font_family="Pacifico", + size=32, + text_align=ft.TextAlign.LEFT, + ), + center_title=False, + toolbar_height=60, + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_700, + actions=[ + ft.Container( + margin=ft.Margin.only(left=50, right=25), + content=ft.PopupMenuButton( + items=[ + ft.PopupMenuItem( + content=profile_label, + on_click=( + (lambda _: show_login_dialog(app)) + if not app.user + else None + ), + ), + ft.PopupMenuItem(), + ft.PopupMenuItem( + content="Settings", + on_click=lambda _: show_settings_dialog(app), + ), + ] + ), + ) + ], + ) diff --git a/sdk/python/examples/apps/declarative/trolli/components/board.py b/sdk/python/examples/apps/declarative/trolli/components/board.py new file mode 100644 index 0000000000..8024ad5b1c --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/board.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from models import Board + +import flet as ft + +from .board_list import BoardListView +from .dialogs import show_new_list_dialog + + +@ft.component +def BoardView(board: Board): + return ft.Column( + expand=True, + spacing=10, + controls=[ + ft.Row( + # height=30, + expand_loose=True, + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.FilledButton( + "Add list", + icon=ft.Icons.ADD, + on_click=lambda _: show_new_list_dialog(board), + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Text(board.name, theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM), + ], + ), + ft.Row( + expand=True, + scroll=ft.ScrollMode.AUTO, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + *[ + BoardListView(bl, move_list=board.move_list) + for bl in board.lists + ], + ], + ), + ], + ) diff --git a/sdk/python/examples/apps/declarative/trolli/components/board_list.py b/sdk/python/examples/apps/declarative/trolli/components/board_list.py new file mode 100644 index 0000000000..0863c0a983 --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/board_list.py @@ -0,0 +1,137 @@ +# from __future__ import annotations + +from models import BoardList + +import flet as ft + +from .card import CardView + + +@ft.component +def BoardListView(board_list: BoardList, move_list): + is_list_over, set_is_list_over = ft.use_state(False) + is_end_over, set_is_end_over = ft.use_state(False) + new_card_text, set_new_card_text = ft.use_state("") + card_list: list[ft.Control] = [CardView(card) for card in board_list.cards] + + def on_add_card_click(_: ft.Event[ft.TextButton]): + if stripped := new_card_text.strip(): + board_list.add_card(stripped) + set_new_card_text("") + + def on_add_card_submit(_: ft.Event[ft.TextField]): + if stripped := new_card_text.strip(): + board_list.add_card(stripped) + set_new_card_text("") + + def on_delete(_: ft.Event[ft.PopupMenuItem]): + board_list.board.remove_list(board_list) + + def change_card_text(e: ft.Event[ft.TextField]): + set_new_card_text(e.control.value) + + def on_end_accept(e: ft.DragTargetEvent): + board_list.move_card_into(e.src.data) + set_is_end_over(False) + + def on_list_accept(e: ft.DragTargetEvent): + move_list(e.src.data, board_list) + set_is_list_over(False) + + return ft.Row( + spacing=4, + intrinsic_height=True, + controls=[ + ft.VerticalDivider( + color=ft.Colors.BLACK_54, + width=2, + thickness=2, + radius=2, + leading_indent=15, + trailing_indent=15, + opacity=1.0 if is_list_over else 0.0, + ), + ft.Draggable( + group="lists", + data=board_list, + content=ft.DragTarget( + group="cards", + data=board_list, + on_will_accept=lambda e: set_is_end_over(e.accept), + on_accept=on_end_accept, + on_leave=lambda: set_is_end_over(False), + content=ft.DragTarget( + group="lists", + data=board_list, + on_will_accept=lambda e: set_is_list_over( + e.accept and e.src.data != board_list + ), + on_accept=on_list_accept, + on_leave=lambda: set_is_list_over(False), + content=ft.Container( + border=ft.Border.all( + 2, + ( + ft.Colors.BLACK_38 + if is_list_over + else ft.Colors.BLACK_12 + ), + ), + border_radius=ft.BorderRadius.all(8), + bgcolor=board_list.color, + padding=ft.Padding.all(10), + width=240, + content=ft.Column( + spacing=6, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Text( + board_list.title, + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.PopupMenuButton( + items=[ + ft.PopupMenuItem( + content=ft.Text("Delete"), + on_click=on_delete, + ) + ] + ), + ], + ), + ft.TextField( + label="New card", + bgcolor=ft.Colors.WHITE, + value=new_card_text, + on_change=change_card_text, + on_submit=on_add_card_submit, + ), + ft.TextButton( + content="Add card", + icon=ft.Icons.ADD, + on_click=on_add_card_click, + ), + ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + *card_list, + ft.Divider( + color=ft.Colors.BLACK_38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_end_over else 0.0, + ), + ], + ), + ], + ), + ), + ), + ), + ), + ], + ) diff --git a/sdk/python/examples/apps/declarative/trolli/components/boards.py b/sdk/python/examples/apps/declarative/trolli/components/boards.py new file mode 100644 index 0000000000..8229269b50 --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/boards.py @@ -0,0 +1,70 @@ +import asyncio + +from models import TrolliState + +import flet as ft + +from .dialogs import show_new_board_dialog + + +@ft.component +def BoardsView(app: TrolliState): + return ft.Column( + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.FilledButton( + "Add new board", + icon=ft.Icons.ADD, + on_click=lambda _: show_new_board_dialog(app), + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Text( + "Your Boards", theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM + ), + ], + ), + ft.Row( + wrap=True, + controls=[ + ft.Container( + width=260, + padding=ft.Padding.all(10), + border=ft.Border.all(1, ft.Colors.BLACK_38), + border_radius=ft.BorderRadius.all(8), + bgcolor=ft.Colors.WHITE_60, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.TextButton( + b.name, + # on_click=lambda _, b=b: ft.context.page.go( + # f"/board/{b.board_id}" + # ), + on_click=lambda _, b=b: asyncio.create_task( + ft.context.page.push_route( + f"/board/{b.board_id}" + ) + ), + ), + ft.PopupMenuButton( + items=[ + ft.PopupMenuItem( + content=ft.Text("Delete"), + on_click=lambda _, b=b: app.delete_board(b), + ) + ] + ), + ], + ), + ) + for b in app.boards + ], + ), + ], + ) diff --git a/sdk/python/examples/apps/declarative/trolli/components/card.py b/sdk/python/examples/apps/declarative/trolli/components/card.py new file mode 100644 index 0000000000..77811cbdce --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/card.py @@ -0,0 +1,60 @@ +from models import Card + +import flet as ft + + +@ft.component +def CardView(card: Card): + is_over, set_is_over = ft.use_state(False) + + def on_accept(e: ft.DragTargetEvent): + card.board_list.move_card_at(e.src.data, card) + set_is_over(False) + + return ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Divider( + color=ft.Colors.BLACK_38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_over else 0.0, + ), + ft.Draggable( + group="cards", + data=card, + content=ft.DragTarget( + group="cards", + data=card, + on_will_accept=lambda e: set_is_over( + e.accept and e.src.data != card + ), + on_accept=on_accept, + on_leave=lambda: set_is_over(False), + content=ft.Card( + elevation=1, + content=ft.Container( + padding=7, + width=200, + content=ft.Row( + spacing=8, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Icon(ft.Icons.CIRCLE_OUTLINED), + ft.Container( + expand=True, + content=ft.Text( + value=card.text, + no_wrap=False, + ), + ), + ], + ), + ), + ), + ), + ), + ], + ) diff --git a/sdk/python/examples/apps/declarative/trolli/components/dialogs.py b/sdk/python/examples/apps/declarative/trolli/components/dialogs.py new file mode 100644 index 0000000000..9db842bb2c --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/dialogs.py @@ -0,0 +1,182 @@ +from __future__ import annotations + +import asyncio +from dataclasses import dataclass +from typing import cast + +from models import Board, TrolliState + +import flet as ft + + +@dataclass(frozen=True) +class _ColorOption: + value: str + + +LIST_COLORS: list[_ColorOption] = [ + _ColorOption(ft.Colors.LIGHT_GREEN), + _ColorOption(ft.Colors.RED_200), + _ColorOption(ft.Colors.AMBER_500), + _ColorOption(ft.Colors.PINK_300), + _ColorOption(ft.Colors.ORANGE_300), + _ColorOption(ft.Colors.LIGHT_BLUE), + _ColorOption(ft.Colors.DEEP_ORANGE_300), + _ColorOption(ft.Colors.PURPLE_100), + _ColorOption(ft.Colors.RED_700), + _ColorOption(ft.Colors.TEAL_500), + _ColorOption(ft.Colors.YELLOW_400), + _ColorOption(ft.Colors.PURPLE_400), + _ColorOption(ft.Colors.BROWN_300), + _ColorOption(ft.Colors.CYAN_500), + _ColorOption(ft.Colors.BLUE_GREY_500), +] + + +def show_login_dialog(app: TrolliState) -> None: + user_field = ft.TextField(label="User name") + password_field = ft.TextField(label="Password", password=True) + error_text = ft.Text(value="", color=ft.Colors.RED) + + async def do_login(_: ft.Event): + user = user_field.value.strip() + pwd = password_field.value.strip() + if not user or not pwd: + error_text.value = "Please provide username and password" + ft.context.page.update() + return + await ft.context.page.shared_preferences.set("current_user", user) + app.user = user + ft.context.page.pop_dialog() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Log in"), + content=ft.Column( + tight=True, + controls=[ + user_field, + password_field, + error_text, + ft.FilledButton("Login", on_click=do_login), + ], + ), + actions=[ + ft.TextButton("Cancel", on_click=lambda _: ft.context.page.pop_dialog()) + ], + ) + ft.context.page.show_dialog(dlg) + # ft.context.page.update() + + +def show_settings_dialog(app: TrolliState) -> None: + placeholder = ft.Text("Settings Placeholder") + + async def save_settings(_: ft.Event): + ft.context.page.pop_dialog() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Save"), + content=ft.Column( + tight=True, + controls=[ + placeholder, + ft.FilledButton("Save Settings", on_click=save_settings), + ], + ), + actions=[ + ft.TextButton("Cancel", on_click=lambda _: ft.context.page.pop_dialog()) + ], + ) + ft.context.page.show_dialog(dlg) + # ft.context.page.update() + + +def show_new_board_dialog(app: TrolliState) -> None: + name_field = ft.TextField(label="New board name") + error_text = ft.Text(value="", color=ft.Colors.RED) + + def on_submit(_: ft.Event): + name = name_field.value.strip() + if not name: + error_text.value = "Please enter a name" + ft.context.page.update() + return + board = app.create_board(name) + ft.context.page.pop_dialog() + asyncio.create_task(ft.context.page.push_route(f"/board/{board.board_id}")) + # ft.context.page.go(f"/board/{board.board_id}") + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Create board"), + content=ft.Column(tight=True, controls=[name_field, error_text]), + actions=[ + ft.TextButton("Cancel", on_click=lambda _: ft.context.page.pop_dialog()), + ft.FilledButton("Create", on_click=on_submit), + ], + actions_alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + ) + ft.context.page.show_dialog(dlg) + ft.context.page.update() + + +def show_new_list_dialog(board: Board) -> None: + title_field = ft.TextField(label="New list name") + error_text = ft.Text(value="", color=ft.Colors.RED) + color_grid = ft.GridView( + max_extent=40, + height=150, + ) + + def set_selected_color(e: ft.Event[ft.Container]): + color_grid.data = e.control.data + for option_control in color_grid.controls: + option = cast(ft.Container, option_control) + option.border = ( + ft.Border.all(3, ft.Colors.BLACK_26) + if option.data == color_grid.data + else None + ) + ft.context.page.update() + + def create(_: ft.Event[ft.Button]): + title = title_field.value.strip() + if not title: + error_text.value = "Please enter a list name" + ft.context.page.update() + return + board.add_list(title=title, color=color_grid.data) + ft.context.page.pop_dialog() + + for option in LIST_COLORS: + color_grid.controls.append( + ft.Container( + bgcolor=option.value, + width=36, + height=36, + border_radius=ft.BorderRadius.all(999), + data=option.value, + on_click=set_selected_color, + ) + ) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Create list"), + content=ft.Column( + tight=True, + controls=[ + title_field, + color_grid, + error_text, + ], + ), + actions=[ + ft.TextButton("Cancel", on_click=lambda _: ft.context.page.pop_dialog()), + ft.FilledButton("Create", on_click=create), + ], + actions_alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + ) + ft.context.page.show_dialog(dlg) diff --git a/sdk/python/examples/apps/declarative/trolli/components/sidebar.py b/sdk/python/examples/apps/declarative/trolli/components/sidebar.py new file mode 100644 index 0000000000..e6292d5e1a --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/components/sidebar.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +import asyncio + +from models import TrolliState + +import flet as ft + + +@ft.component +def Sidebar(app: TrolliState): + board_id = app.current_board_id + active_board_index = ( + next((i for i, b in enumerate(app.boards) if b.board_id == board_id), None) + if board_id is not None + else None + ) + top_index = ( + 0 + if app.active_screen == "boards" + else 1 + if app.active_screen == "members" + else None + ) + + def top_nav_change(e: ft.Event[ft.NavigationRail]): + if e.control.selected_index == 0: + asyncio.create_task(ft.context.page.push_route("/boards")) + # ft.context.page.go("/boards") + elif e.control.selected_index == 1: + asyncio.create_task(ft.context.page.push_route("/members")) + # ft.context.page.go("/members") + + def bottom_nav_change(e: ft.Event[ft.NavigationRail]): + idx = e.control.selected_index + if idx is None: + return + asyncio.create_task( + ft.context.page.push_route(f"/board/{app.boards[idx].board_id}") + ) + # ft.context.page.go(f"/board/{app.boards[idx].board_id}") + + return ft.Container( + width=200, + bgcolor=ft.Colors.BLUE_GREY, + padding=ft.Padding.all(15), + visible=app.nav_visible, + content=ft.Column( + tight=True, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ft.Text("Workspace")], + ), + ft.Divider(height=1, thickness=1, color=ft.Colors.BLACK_26), + ft.NavigationRail( + selected_index=top_index, + label_type=ft.NavigationRailLabelType.ALL, + bgcolor=ft.Colors.BLUE_GREY, + extended=True, + height=110, + on_change=top_nav_change, + destinations=[ + ft.NavigationRailDestination( + label="Boards", + icon=ft.Icons.BOOK_OUTLINED, + selected_icon=ft.Icons.BOOK_OUTLINED, + ), + ft.NavigationRailDestination( + label="Members", + icon=ft.Icons.PERSON, + selected_icon=ft.Icons.PERSON, + ), + ], + ), + ft.Divider(height=1, thickness=1, color=ft.Colors.BLACK_26), + ft.NavigationRail( + selected_index=active_board_index, + label_type=ft.NavigationRailLabelType.ALL, + bgcolor=ft.Colors.BLUE_GREY, + extended=True, + expand=True, + on_change=bottom_nav_change, + destinations=[ + ft.NavigationRailDestination( + label=b.name, + icon=ft.Icons.CHEVRON_RIGHT_OUTLINED, + selected_icon=ft.Icons.CHEVRON_RIGHT_ROUNDED, + ) + for b in app.boards + ], + ), + ], + ), + ) diff --git a/sdk/python/examples/apps/declarative/trolli/main.py b/sdk/python/examples/apps/declarative/trolli/main.py new file mode 100644 index 0000000000..98f3745246 --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/main.py @@ -0,0 +1,152 @@ +import asyncio +import logging +from typing import Optional + +from components import BoardsView, BoardView, Sidebar, TrolliAppBar +from models import TrolliState + +import flet as ft + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet_components").setLevel(logging.INFO) + + +def _init_demo_data(app: TrolliState) -> None: + if app.boards: + return + board = app.create_board("My First Board") + board.add_list("To Do", ft.Colors.AMBER_200) + board.add_list("Doing", ft.Colors.LIGHT_BLUE_200) + board.add_list("Done", ft.Colors.LIGHT_GREEN_200) + board.lists[0].add_card("Drag cards between lists") + board.lists[0].add_card("Drag lists to reorder") + board.lists[1].add_card("Add a list from the button") + + +@ft.component +def App(): + app, _ = ft.use_state(lambda: TrolliState(route=ft.context.page.route)) + ft.context.page.padding = 0 + ft.context.page.theme_mode = ft.ThemeMode.LIGHT + ft.context.page.fonts = {"Pacifico": "Pacifico-Regular.ttf"} + ft.context.page.bgcolor = ft.Colors.BLUE_GREY_200 + if ft.context.page.route == "/": + asyncio.create_task(ft.context.page.push_route("/boards")) + # ft.context.page.go("/boards") + + def parse_board_id_from_route(route: str) -> Optional[int]: + troute = ft.TemplateRoute(route) + if not troute.match("/board/:id"): + return None + + raw = getattr(troute, "id", None) + if not isinstance(raw, str): + return None + try: + return int(raw) + except ValueError: + return None + + def route_change(e: ft.RouteChangeEvent): + # Keep route as the single source of truth for navigation-related UI. + app.route = e.route + + if e.route.startswith("/board/"): + board_id = parse_board_id_from_route(e.route) + if board_id is None or app.get_board_by_id(board_id) is None: + asyncio.create_task(ft.context.page.push_route("/boards")) + app.active_screen = "boards" + app.current_board_id = None + app.route = "/boards" + return + + if e.route in ("/", "/boards"): + app.active_screen = "boards" + app.current_board_id = None + elif e.route == "/members": + app.active_screen = "members" + app.current_board_id = None + elif e.route == "/settings": + app.active_screen = "settings" + app.current_board_id = None + elif e.route.startswith("/board/"): + app.active_screen = "board" + app.current_board_id = board_id + else: + asyncio.create_task(ft.context.page.push_route("/boards")) + app.active_screen = "boards" + app.current_board_id = None + app.route = "/boards" + return + + ft.context.page.on_route_change = route_change + + def redirect_unknown_board(): + if not app.route.startswith("/board/"): + return + board_id = parse_board_id_from_route(app.route) + if board_id is None or app.get_board_by_id(board_id) is None: + asyncio.create_task(ft.context.page.push_route("/boards")) + + # ft.on_updated(redirect_unknown_board, [app.route]) + + ft.on_mounted(lambda: _init_demo_data(app)) + + def toggle_sidebar(_: ft.Event[ft.IconButton]): + app.nav_visible = not app.nav_visible + + board_id = parse_board_id_from_route(app.route) + board = app.get_board_by_id(board_id) if board_id is not None else None + + if app.active_screen == "boards": + content: ft.Control = BoardsView(app) + elif app.active_screen == "members": + content = ft.Text("Members view placeholder", align=ft.Alignment.CENTER) + elif app.active_screen == "settings": + content = ft.Text("Settings view placeholder", align=ft.Alignment.CENTER) + else: + board = ( + app.get_board_by_id(app.current_board_id) if app.current_board_id else None + ) + content = BoardView(board) if board else BoardsView(app) + + return ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + spacing=0, + controls=[ + TrolliAppBar(app), + ft.Row( + expand=True, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + Sidebar(app), + ft.Stack( + fit=ft.StackFit.LOOSE, + expand=True, + controls=[ + ft.Container( + padding=ft.Padding.only(left=10, right=10, top=10), + content=content, + ), + ft.IconButton( + icon=ft.Icons.ARROW_CIRCLE_LEFT, + selected=not app.nav_visible, + selected_icon=ft.Icons.ARROW_CIRCLE_RIGHT, + icon_color=ft.Colors.BLUE_GREY_400, + icon_size=20, + padding=0, + on_click=toggle_sidebar, + ), + ], + ), + ], + ), + ], + ), + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/trolli/models.py b/sdk/python/examples/apps/declarative/trolli/models.py new file mode 100644 index 0000000000..0dbc6e31de --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/models.py @@ -0,0 +1,113 @@ +from dataclasses import dataclass, field +from typing import Literal, Optional + +import flet as ft + +ScreenType = Literal["boards", "board", "members", "settings"] + + +@ft.observable +@dataclass +class Card: + text: str + board_list: "BoardList" + + def __post_init__(self): + self.card_id = id(self) + + def move_to_list(self, dst: "BoardList", *, index: Optional[int] = None) -> None: + if self.board_list == dst and index is None: + return + self.board_list.cards.remove(self) + self.board_list = dst + if index is None: + dst.cards.append(self) + else: + dst.cards.insert(index, self) + + +@ft.observable +@dataclass +class BoardList: + title: str + color: str + board: "Board" + cards: list[Card] = field(default_factory=list) + + def __post_init__(self): + self.board_list_id = id(self) + + def add_card(self, text: str) -> None: + text = text.strip() + if not text: + return + self.cards.append(Card(text=text, board_list=self)) + + def remove_card(self, card: Card) -> None: + self.cards.remove(card) + + def move_card_at(self, card: Card, to_card: Card) -> None: + if card == to_card: + return + dst_list = to_card.board_list + to_index = dst_list.cards.index(to_card) + card.move_to_list(dst_list, index=to_index) + + def move_card_into(self, card: Card) -> None: + card.move_to_list(self) + + +@ft.observable +@dataclass +class Board: + name: str + lists: list[BoardList] = field(default_factory=list) + + def __post_init__(self): + self.board_id = id(self) + + def add_list(self, title: str, color: str) -> None: + title = title.strip() + if not title: + return + self.lists.append(BoardList(title=title, color=color, board=self)) + + def remove_list(self, board_list: BoardList) -> None: + self.lists.remove(board_list) + + def move_list(self, src: BoardList, dst: BoardList) -> None: + src_index = self.lists.index(src) + dst_index = self.lists.index(dst) + if src_index != dst_index: + self.lists.insert(dst_index, self.lists.pop(src_index)) + + +@ft.observable +@dataclass +class TrolliState: + route: str + active_screen: ScreenType = "boards" + current_board_id: Optional[int] = None + user: Optional[str] = None + nav_visible: bool = True + boards: list[Board] = field(default_factory=list) + + def route_change(self, e: ft.RouteChangeEvent): + self.route = e.route + + def get_board_by_id(self, board_id: int) -> Optional[Board]: + for b in self.boards: + if b.board_id == board_id: + return b + return None + + def create_board(self, name: str) -> Board: + name = name.strip() + if not name: + name = "Untitled board" + board = Board(name=name) + self.boards.append(board) + return board + + def delete_board(self, board: Board) -> None: + self.boards.remove(board) diff --git a/sdk/python/examples/apps/declarative/trolli/pyproject.toml b/sdk/python/examples/apps/declarative/trolli/pyproject.toml new file mode 100644 index 0000000000..18c3fc4a9e --- /dev/null +++ b/sdk/python/examples/apps/declarative/trolli/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-trolli" +version = "1.0.0" +description = "Declarative Trello-style board app with draggable lists, cards, dialogs, and route-based navigation." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "kanban", "drag and drop", "routing", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Featured"] + +[tool.flet.metadata] +title = "Trolli" +controls = ["SafeArea", "Column", "Row", "Stack", "AppBar", "NavigationRail", "Draggable", "DragTarget", "TextField", "AlertDialog"] +layout_pattern = "dashboard" +complexity = "advanced" +features = ["drag and drop", "routing", "dialogs", "async", "kanban board"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py b/sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py new file mode 100644 index 0000000000..7701d60ae9 --- /dev/null +++ b/sdk/python/examples/apps/declarative/uncontrolled_textfield/main.py @@ -0,0 +1,46 @@ +import random +from typing import cast + +import flet as ft + + +@ft.component +def App(): + state, set_state = ft.use_state("") + + async def submit(e: ft.Event[ft.Button]): + e.page.show_dialog( + ft.AlertDialog( + title="Hello", + content=ft.Text(f"{first_name.value} {last_name.value}!"), + ) + ) + + def reset(): + set_state("reset" + str(random.randint(1, 1000))) + + return ft.SafeArea( + content=ft.Column( + controls=[ + first_name := ft.TextField( + label="First name", + ), + last_name := ft.TextField( + label="Last name", + ), + ft.Row( + cast( + list[ft.Control], + [ + ft.FilledButton("Submit", on_click=submit), + ft.FilledTonalButton("Reset", on_click=reset), + ], + ) + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml b/sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml new file mode 100644 index 0000000000..c1ea83cd30 --- /dev/null +++ b/sdk/python/examples/apps/declarative/uncontrolled_textfield/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-uncontrolled-textfield" +version = "1.0.0" +description = "Shows how uncontrolled text fields behave in a declarative form with submit and reset actions." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "textfield", "form", "uncontrolled"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Uncontrolled textfield" +controls = ["SafeArea", "Column", "Row", "TextField", "FilledButton", "FilledTonalButton", "AlertDialog"] +layout_pattern = "form" +complexity = "basic" +features = ["form submission", "uncontrolled inputs"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/use_dialog_basic/main.py b/sdk/python/examples/apps/declarative/use_dialog_basic/main.py new file mode 100644 index 0000000000..59df7b72ea --- /dev/null +++ b/sdk/python/examples/apps/declarative/use_dialog_basic/main.py @@ -0,0 +1,61 @@ +import asyncio + +import flet as ft + + +@ft.component +def App(): + show, set_show = ft.use_state(False) + deleting, set_deleting = ft.use_state(False) + + async def handle_delete(): + set_deleting(True) + # Simulate async operation + await asyncio.sleep(2) + set_deleting(False) + set_show(False) + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete report.pdf?"), + content=ft.Text( + "Deleting, please wait..." if deleting else "This cannot be undone." + ), + actions=[ + ft.Button( + "Deleting..." if deleting else "Delete", + disabled=deleting, + on_click=handle_delete, + ), + ft.TextButton( + "Cancel", + on_click=lambda: set_show(False), + disabled=deleting, + ), + ], + on_dismiss=lambda: set_show(False), + ) + if show + else None + ) + + return ft.Column( + controls=[ + ft.Text("Declarative Dialog Example", size=24, weight=ft.FontWeight.BOLD), + ft.Text("Click the button to open a confirmation dialog."), + ft.Button( + "Delete File", + icon=ft.Icons.DELETE, + on_click=lambda: set_show(True), + ), + ], + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/use_dialog_basic/pyproject.toml b/sdk/python/examples/apps/declarative/use_dialog_basic/pyproject.toml new file mode 100644 index 0000000000..b2ef22c347 --- /dev/null +++ b/sdk/python/examples/apps/declarative/use_dialog_basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-use-dialog-basic" +version = "1.0.0" +description = "Single declarative AlertDialog driven by `use_dialog` with an async delete and loading state." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "dialog", "use_dialog", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative", "Getting Started/Declarative"] + +[tool.flet.metadata] +title = "Use dialog basic" +controls = ["Column", "Text", "Button", "TextButton", "AlertDialog"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog management", "use_dialog", "async", "loading state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/use_dialog_chained/main.py b/sdk/python/examples/apps/declarative/use_dialog_chained/main.py new file mode 100644 index 0000000000..c16b2aa30e --- /dev/null +++ b/sdk/python/examples/apps/declarative/use_dialog_chained/main.py @@ -0,0 +1,86 @@ +import asyncio + +import flet as ft + + +@ft.component +def App(): + show_confirm, set_show_confirm = ft.use_state(False) + show_success, set_show_success = ft.use_state(False) + deleting, set_deleting = ft.use_state(False) + deleted, set_deleted = ft.use_state(False) + # Ref avoids stale closure — always holds the current value + should_chain = ft.use_ref(False) + + async def handle_delete(): + set_deleting(True) + await asyncio.sleep(2) + set_deleting(False) + set_deleted(True) + should_chain.current = True + set_show_confirm(False) + + def on_confirm_dismiss(): + if should_chain.current: + should_chain.current = False + set_show_success(True) + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete report.pdf?"), + content=ft.Text( + "Deleting, please wait..." if deleting else "This cannot be undone." + ), + actions=[ + ft.Button( + "Deleting..." if deleting else "Delete", + disabled=deleting, + on_click=handle_delete, + ), + ft.TextButton( + "Cancel", + on_click=lambda: set_show_confirm(False), + disabled=deleting, + ), + ], + on_dismiss=on_confirm_dismiss, + ) + if show_confirm + else None + ) + + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("Done!"), + content=ft.Text("report.pdf has been deleted."), + actions=[ + ft.FilledButton("OK", on_click=lambda: set_show_success(False)), + ], + ) + if show_success + else None + ) + + return ft.Column( + controls=[ + ft.Text("Chained Dialogs Example", size=24, weight=ft.FontWeight.BOLD), + ft.Text( + "File deleted." if deleted else "Click the button to delete the file." + ), + ft.Button( + "Delete File", + icon=ft.Icons.DELETE, + on_click=lambda: set_show_confirm(True), + disabled=deleted, + ), + ], + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/use_dialog_chained/pyproject.toml b/sdk/python/examples/apps/declarative/use_dialog_chained/pyproject.toml new file mode 100644 index 0000000000..cc37c873c7 --- /dev/null +++ b/sdk/python/examples/apps/declarative/use_dialog_chained/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-use-dialog-chained" +version = "1.0.0" +description = "Chains two declarative AlertDialogs — opens a success dialog after the confirm dialog dismisses." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "dialog", "use_dialog", "chained"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Use dialog chained" +controls = ["Column", "Text", "Button", "TextButton", "FilledButton", "AlertDialog"] +layout_pattern = "inline-actions" +complexity = "intermediate" +features = ["dialog management", "use_dialog", "chained dialogs", "use_ref", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py b/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py new file mode 100644 index 0000000000..a6ff382560 --- /dev/null +++ b/sdk/python/examples/apps/declarative/use_dialog_multiple/main.py @@ -0,0 +1,153 @@ +import asyncio + +import flet as ft + + +def build_rename_dialog(current_name, new_name, on_name_change, on_save, on_cancel): + return ft.AlertDialog( + modal=True, + title=ft.Text(f"Rename {current_name}"), + content=ft.TextField( + label="New name", + value=new_name, + on_change=on_name_change, + autofocus=True, + ), + actions=[ + ft.FilledButton("Save", on_click=on_save), + ft.TextButton("Cancel", on_click=on_cancel), + ], + ) + + +def build_delete_dialog(item_name, deleting, on_delete, on_cancel): + return ft.AlertDialog( + modal=True, + title=ft.Text(f"Delete {item_name}?"), + content=ft.Text( + "Deleting, please wait..." if deleting else "This action cannot be undone." + ), + actions=[ + ft.Button( + "Deleting..." if deleting else "Delete", + color=ft.Colors.WHITE, + bgcolor=ft.Colors.RED if not deleting else ft.Colors.GREY, + disabled=deleting, + on_click=on_delete, + ), + ft.TextButton("Cancel", on_click=on_cancel, disabled=deleting), + ], + ) + + +@ft.component +def FileItem(name, on_rename, on_delete): + return ft.Card( + content=ft.Container( + padding=20, + content=ft.Row( + controls=[ + ft.Icon(ft.Icons.DESCRIPTION), + ft.Text(name, size=16, expand=True), + ft.IconButton( + ft.Icons.EDIT, + tooltip="Rename", + on_click=on_rename, + ), + ft.IconButton( + ft.Icons.DELETE, + tooltip="Delete", + icon_color=ft.Colors.RED, + on_click=on_delete, + ), + ], + alignment=ft.MainAxisAlignment.START, + ), + ), + ) + + +INITIAL_FILES = ["report.pdf", "photo.jpg", "notes.txt"] + + +@ft.component +def App(): + files, set_files = ft.use_state(INITIAL_FILES) + target, set_target = ft.use_state(None) # file being acted on + new_name, set_new_name = ft.use_state("") + show_rename, set_show_rename = ft.use_state(False) + show_delete, set_show_delete = ft.use_state(False) + deleting, set_deleting = ft.use_state(False) + + async def handle_delete(): + set_deleting(True) + await asyncio.sleep(1) + set_files([f for f in files if f != target]) + set_deleting(False) + set_show_delete(False) + + def handle_rename_save(): + if new_name.strip(): + set_files([new_name.strip() if f == target else f for f in files]) + set_show_rename(False) + + def open_rename(name): + def handler(): + set_target(name) + set_new_name(name) + set_show_rename(True) + + return handler + + def open_delete(name): + def handler(): + set_target(name) + set_show_delete(True) + + return handler + + ft.use_dialog( + build_rename_dialog( + target, + new_name, + on_name_change=lambda e: set_new_name(e.control.value), + on_save=handle_rename_save, + on_cancel=lambda: set_show_rename(False), + ) + if show_rename + else None + ) + + ft.use_dialog( + build_delete_dialog( + target, + deleting, + on_delete=handle_delete, + on_cancel=lambda: set_show_delete(False), + ) + if show_delete + else None + ) + + return ft.Column( + controls=[ + ft.Text("Multiple Dialogs Example", size=24, weight=ft.FontWeight.BOLD), + ft.Text("Each file can be renamed or deleted."), + ] + + [ + FileItem( + name=f, + on_rename=open_rename(f), + on_delete=open_delete(f), + ) + for f in files + ], + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/declarative/use_dialog_multiple/pyproject.toml b/sdk/python/examples/apps/declarative/use_dialog_multiple/pyproject.toml new file mode 100644 index 0000000000..21d3ded177 --- /dev/null +++ b/sdk/python/examples/apps/declarative/use_dialog_multiple/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-declarative-use-dialog-multiple" +version = "1.0.0" +description = "Per-item rename and delete AlertDialogs on a file list, each driven by its own `use_dialog` hook." +requires-python = ">=3.10" +keywords = ["apps", "declarative", "dialog", "use_dialog", "multiple"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Use dialog multiple" +controls = ["Column", "Row", "Card", "Container", "Text", "Icon", "IconButton", "TextField", "Button", "TextButton", "FilledButton", "AlertDialog"] +layout_pattern = "list" +complexity = "intermediate" +features = ["dialog management", "use_dialog", "multiple dialogs", "async", "list item actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/dialogs/multi_host/main.py b/sdk/python/examples/apps/dialogs/multi_host/main.py new file mode 100644 index 0000000000..2528f2fe38 --- /dev/null +++ b/sdk/python/examples/apps/dialogs/multi_host/main.py @@ -0,0 +1,145 @@ +"""Repro for the ``use_dialog`` multi-host race. + +Two sibling components each own a dialog via ``ft.use_dialog``: an +``AlertHost`` shows an AlertDialog while a ``ToastHost`` shows a SnackBar. +A single click handler flips both in the same scheduler tick — the +AlertDialog is dismissed while the SnackBar is shown. Before the fix the +AlertDialog stays stuck open because the two hosts emit conflicting patches +(an immediate ``patch_control(prev)`` for dismissal and a deferred +``schedule_update(_dialogs)`` for show) and the Flutter overlay rebuild +recreates the AlertDialog Element mid-dismiss. + +Run with ``uv run flet run path/to/multi_host``. +""" + +from __future__ import annotations + +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class Session: + alert_open: bool = False + toast: str | None = None + toast_nonce: int = 0 + + +session = Session() +SessionContext = ft.create_context(session) + + +def use_session() -> Session: + return ft.use_context(SessionContext) + + +def show_toast(text: str) -> None: + session.toast = text + session.toast_nonce += 1 + + +def _log(msg: str): + with open("/tmp/multi_host.log", "a") as f: + f.write(msg + "\n") + + +@ft.component +def AlertHost(): + s = use_session() + + def cancel(_): + _log(f"[CLICK] cancel; alert_open={s.alert_open}") + s.alert_open = False + + def delete(_): + _log(f"[CLICK] delete; alert_open={s.alert_open}") + s.alert_open = False + show_toast("Deleted") + + dialog = ( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete item?"), + content=ft.Text( + "Clicking 'Delete' dismisses this dialog and shows a " + "snackbar in the same scheduler tick." + ), + actions=[ + ft.TextButton("Cancel", on_click=cancel), + ft.FilledButton("Delete", on_click=delete), + ], + on_dismiss=cancel, + ) + if s.alert_open + else None + ) + ft.use_dialog(dialog) + return ft.Container(width=0, height=0) + + +@ft.component +def ToastHost(): + s = use_session() + text = s.toast + _ = s.toast_nonce # subscribe so duplicate toasts re-fire + + def clear(_): + s.toast = None + + dialog = ft.SnackBar(content=ft.Text(text), on_dismiss=clear) if text else None + ft.use_dialog(dialog) + return ft.Container(width=0, height=0) + + +@ft.component +def Body(): + s = use_session() + + def open_dialog(): + _log(f"[CLICK] open_dialog; alert_open={s.alert_open}") + s.alert_open = True + + return ft.View( + route="/", + appbar=ft.AppBar(title=ft.Text("use_dialog multi-host race")), + controls=[ + AlertHost(), + ToastHost(), + ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=ft.Column( + tight=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "1. Click 'Open dialog' to show an AlertDialog with a\n" + " Delete button.\n" + "2. Click 'Delete' inside the dialog — its on_click\n" + " dismisses the dialog AND fires a snackbar in the\n" + " same scheduler tick (two `use_dialog` hosts).\n\n" + "Before the fix the dialog stays stuck on step 2.", + text_align=ft.TextAlign.CENTER, + ), + ft.FilledButton("Open dialog", on_click=open_dialog), + ], + ), + ), + ], + ) + + +@ft.component +def App(): + return SessionContext(session, Body) + + +def main(page: ft.Page): + page.render_views(lambda: [App()]) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/dialogs/multi_host/pyproject.toml b/sdk/python/examples/apps/dialogs/multi_host/pyproject.toml new file mode 100644 index 0000000000..6a7e622b77 --- /dev/null +++ b/sdk/python/examples/apps/dialogs/multi_host/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-dialogs-multi-host" +version = "1.0.0" +description = "Repro for use_dialog multi-host race: AlertDialog and SnackBar hosted by sibling components dismiss/show in the same tick." +requires-python = ">=3.10" +keywords = ["apps", "dialog", "snackbar", "use_dialog", "regression"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Declarative"] + +[tool.flet.metadata] +title = "Multi-host dialog race" +controls = ["AlertDialog", "SnackBar", "AppBar", "FilledButton"] +layout_pattern = "center-stage" +complexity = "advanced" +features = ["use_dialog", "observable state", "context"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/flet_animation/main.py b/sdk/python/examples/apps/flet_animation/main.py new file mode 100644 index 0000000000..e8a756732a --- /dev/null +++ b/sdk/python/examples/apps/flet_animation/main.py @@ -0,0 +1,148 @@ +import random +from math import pi + +import flet as ft + + +def main(page: ft.Page): + size = 40 + gap = 6 + duration = 2000 + + c1 = ft.Colors.PINK_500 + c2 = ft.Colors.AMBER_500 + c3 = ft.Colors.LIGHT_GREEN_500 + c4 = ft.Colors.DEEP_PURPLE_500 + + all_colors = [ + ft.Colors.AMBER_400, + ft.Colors.AMBER_ACCENT_400, + ft.Colors.BLUE_400, + ft.Colors.BROWN_400, + ft.Colors.CYAN_700, + ft.Colors.DEEP_ORANGE_500, + ft.Colors.CYAN_500, + ft.Colors.INDIGO_600, + ft.Colors.ORANGE_ACCENT_100, + ft.Colors.PINK, + ft.Colors.RED_600, + ft.Colors.GREEN_400, + ft.Colors.GREEN_ACCENT_200, + ft.Colors.TEAL_ACCENT_200, + ft.Colors.LIGHT_BLUE_500, + ] + + parts = [ + # F + (0, 0, c1), + (0, 1, c1), + (0, 2, c1), + (0, 3, c1), + (0, 4, c1), + (1, 0, c1), + (1, 2, c1), + (2, 0, c1), + # L + (4, 0, c2), + (4, 1, c2), + (4, 2, c2), + (4, 3, c2), + (4, 4, c2), + (5, 4, c2), + (6, 4, c2), + # E + (8, 0, c3), + (9, 0, c3), + (10, 0, c3), + (8, 1, c3), + (8, 2, c3), + (9, 2, c3), + (10, 2, c3), + (8, 3, c3), + (8, 4, c3), + (9, 4, c3), + (10, 4, c3), + # T + (12, 0, c4), + (13, 0, c4), + (14, 0, c4), + (13, 1, c4), + (13, 2, c4), + (13, 3, c4), + (13, 4, c4), + ] + + width = 16 * (size + gap) + height = 5 * (size + gap) + + canvas = ft.Stack( + width=width, + height=height, + animate_scale=duration, + animate_opacity=duration, + ) + + # spread parts randomly + for _ in range(len(parts)): + canvas.controls.append( + ft.Container( + animate=duration, + animate_position=duration, + animate_rotation=duration, + ) + ) + + def randomize(e): + random.seed() + for i in range(len(parts)): + c = canvas.controls[i] + part_size = random.randrange(int(size / 2), int(size * 3)) + c.left = random.randrange(0, width) + c.top = random.randrange(0, height) + c.bgcolor = all_colors[random.randrange(0, len(all_colors))] + c.width = part_size + c.height = part_size + c.border_radius = random.randrange(0, int(size / 2)) + c.rotate = random.randrange(0, 90) * 2 * pi / 360 + canvas.scale = 5 + canvas.opacity = 0.3 + go_button.visible = True + again_button.visible = False + page.update() + + def assemble(e): + for i, (left, top, bgcolor) in enumerate(parts): + c = canvas.controls[i] + c.left = left * (size + gap) + c.top = top * (size + gap) + c.bgcolor = bgcolor + c.width = size + c.height = size + c.border_radius = 5 + c.rotate = 0 + canvas.scale = 1 + canvas.opacity = 1 + go_button.visible = False + again_button.visible = True + page.update() + + go_button = ft.Button("Go!", on_click=assemble) + again_button = ft.Button("Again!", on_click=randomize) + + randomize(None) + + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.spacing = 30 + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[canvas, go_button, again_button], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/flet_animation/pyproject.toml b/sdk/python/examples/apps/flet_animation/pyproject.toml new file mode 100644 index 0000000000..21139316a5 --- /dev/null +++ b/sdk/python/examples/apps/flet_animation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-flet-animation" +version = "1.0.0" +description = "Animates scattered blocks into the FLET logo with randomized colors, size, and rotation." +requires-python = ">=3.10" +keywords = ["apps", "animation", "logo", "stack", "implicit animations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/Apps", "Featured"] + +[tool.flet.metadata] +title = "Flet animation" +controls = ["SafeArea", "Column", "Stack", "Container", "Button"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["implicit animations", "randomized layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/flet_build_test/README.md b/sdk/python/examples/apps/flet_build_test/README.md new file mode 100644 index 0000000000..c166066aec --- /dev/null +++ b/sdk/python/examples/apps/flet_build_test/README.md @@ -0,0 +1,3 @@ +# flet-build-test + +A minimal Flet app used to validate the [`flet build`](https://flet.dev/docs/cli/flet-build/) across platforms. diff --git a/sdk/python/examples/apps/flet_build_test/pyproject.toml b/sdk/python/examples/apps/flet_build_test/pyproject.toml new file mode 100644 index 0000000000..ae7ce40bb4 --- /dev/null +++ b/sdk/python/examples/apps/flet_build_test/pyproject.toml @@ -0,0 +1,95 @@ +[project] +name = "flet_build_test" +version = "0.1.0" +description = "App to test flet build." +requires-python = ">=3.10" +authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }] + +dependencies = [ + "numpy", + "pillow", + "flet", + "flet-ads", + "flet-audio", + "flet-audio-recorder", + "flet-camera", + "flet-charts", + "flet-datatable2", + "flet-flashlight", + "flet-geolocator", + "flet-lottie", + "flet-map", + "flet-permission-handler", + "flet-rive", + "flet-secure-storage", + "flet-video", + "flet-webview", +] + +[dependency-groups] +dev = [ + "flet-cli", + "flet-desktop", + "flet-web", +] + +[tool.uv.sources] +flet = { path = "../../../packages/flet", editable = true } +flet-cli = { path = "../../../packages/flet-cli", editable = true } +flet-desktop = { path = "../../../packages/flet-desktop", editable = true } +flet-web = { path = "../../../packages/flet-web", editable = true } +flet-ads = { path = "../../../packages/flet-ads", editable = true } +flet-audio = { path = "../../../packages/flet-audio", editable = true } +flet-audio-recorder = { path = "../../../packages/flet-audio-recorder", editable = true } +flet-camera = { path = "../../../packages/flet-camera", editable = true } +flet-charts = { path = "../../../packages/flet-charts", editable = true } +flet-datatable2 = { path = "../../../packages/flet-datatable2", editable = true } +flet-flashlight = { path = "../../../packages/flet-flashlight", editable = true } +flet-geolocator = { path = "../../../packages/flet-geolocator", editable = true } +flet-lottie = { path = "../../../packages/flet-lottie", editable = true } +flet-map = { path = "../../../packages/flet-map", editable = true } +flet-permission-handler = { path = "../../../packages/flet-permission-handler", editable = true } +flet-rive = { path = "../../../packages/flet-rive", editable = true } +flet-secure-storage = { path = "../../../packages/flet-secure-storage", editable = true } +flet-video = { path = "../../../packages/flet-video", editable = true } +flet-webview = { path = "../../../packages/flet-webview", editable = true } + +[tool.flet.dev_packages] +flet = "../../../packages/flet" +flet-ads = "../../../packages/flet-ads" +flet-audio = "../../../packages/flet-audio" +flet-audio-recorder = "../../../packages/flet-audio-recorder" +flet-camera = "../../../packages/flet-camera" +flet-charts = "../../../packages/flet-charts" +flet-datatable2 = "../../../packages/flet-datatable2" +flet-flashlight = "../../../packages/flet-flashlight" +flet-geolocator = "../../../packages/flet-geolocator" +flet-lottie = "../../../packages/flet-lottie" +flet-map = "../../../packages/flet-map" +flet-permission-handler = "../../../packages/flet-permission-handler" +flet-rive = "../../../packages/flet-rive" +flet-secure-storage = "../../../packages/flet-secure-storage" +flet-video = "../../../packages/flet-video" +flet-webview = "../../../packages/flet-webview" + +# Docs: https://flet.dev/docs/publish/ +[tool.flet] +product = "Flet Build Test" +artifact = "flet-build-test" +project = "flet_build_test" +company = "Flet" +org = "com.flet" +copyright = "Copyright (C) 2025 by Flet" +build_number = 1 + +[tool.flet.app] +path = "src" + +[tool.flet.android.meta_data] +"com.google.android.gms.ads.APPLICATION_ID" = "ca-app-pub-3940256099942544~3347511713" + +[tool.flet.ios.info] +GADApplicationIdentifier = "ca-app-pub-3940256099942544~3347511713" + +[tool.flet.flutter.pubspec.dependency_overrides] +flet = { path = "../../../../../../../packages/flet" } diff --git a/sdk/python/examples/apps/flet_build_test/src/main.py b/sdk/python/examples/apps/flet_build_test/src/main.py new file mode 100644 index 0000000000..5eb53b1e05 --- /dev/null +++ b/sdk/python/examples/apps/flet_build_test/src/main.py @@ -0,0 +1,75 @@ +import sys + +import numpy +import PIL +from modules.utils import greet + +import flet as ft +import flet.version as fv +import flet_ads # noqa: F401 +import flet_audio # noqa: F401 +import flet_audio_recorder # noqa: F401 +import flet_charts # noqa: F401 +import flet_datatable2 # noqa: F401 +import flet_flashlight # noqa: F401 +import flet_geolocator # noqa: F401 +import flet_lottie # noqa: F401 +import flet_map # noqa: F401 +import flet_permission_handler # noqa: F401 +import flet_rive # noqa: F401 +import flet_secure_storage # noqa: F401 +import flet_video # noqa: F401 +import flet_webview # noqa: F401 + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.SYSTEM + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.appbar = ft.AppBar( + title=ft.Text("Flet Build Test"), + # center_title=True, + actions=[ + ft.Container( + content=ft.Text(f"v{ft.__version__}", weight=ft.FontWeight.BOLD), + padding=ft.Padding.only(right=15), + ) + ], + ) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.INFO, + bgcolor=ft.Colors.BLUE, + on_click=lambda: page.show_dialog( + ft.AlertDialog( + title="Debug Info", + scrollable=True, + content=ft.Column( + controls=[ + ft.Text(f"Python: v{sys.version}"), + ft.Text(f"Flet: v{ft.__version__}"), + ft.Text(f"Flutter: v{fv.flutter_version}"), + ft.Text(f"Numpy: v{numpy.__version__}"), + ft.Text(f"Numpy: v{numpy.__version__}"), + ft.Text(f"Pillow: v{PIL.__version__}"), + ft.Text(f"sys.path: {sys.path}"), + ] + ), + ) + ), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text(greet("Flet"), size=20, weight=ft.FontWeight.BOLD), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/flet_build_test/src/modules/utils.py b/sdk/python/examples/apps/flet_build_test/src/modules/utils.py new file mode 100644 index 0000000000..382d8c8b2a --- /dev/null +++ b/sdk/python/examples/apps/flet_build_test/src/modules/utils.py @@ -0,0 +1,3 @@ +def greet(name: str) -> str: + """A simple utility function that returns a greeting message.""" + return f"Hello, {name}!" diff --git a/sdk/python/examples/apps/greeter/basic/main.py b/sdk/python/examples/apps/greeter/basic/main.py new file mode 100644 index 0000000000..645930807f --- /dev/null +++ b/sdk/python/examples/apps/greeter/basic/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + greeting = ft.Text() + txt_name = ft.TextField(label="Your name") + + def btn_click(e): + if not txt_name.value: + txt_name.error_text = "Please enter your name" + greeting.value = "" + else: + txt_name.error_text = None + greeting.value = f"Hello, {txt_name.value}!" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + txt_name, + ft.Button("Say hello!", on_click=btn_click), + greeting, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/greeter/basic/pyproject.toml b/sdk/python/examples/apps/greeter/basic/pyproject.toml new file mode 100644 index 0000000000..05cb2f0757 --- /dev/null +++ b/sdk/python/examples/apps/greeter/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-greeter-basic" +version = "1.0.0" +description = "Prompts for a name and greets the user while validating an empty text field." +requires-python = ">=3.10" +keywords = ["apps", "greeter", "form", "text field", "validation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Getting Started"] + +[tool.flet.metadata] +title = "Basic greeter" +controls = ["SafeArea", "Column", "TextField", "Button", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["form validation", "text updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/hello_world/basic/main.py b/sdk/python/examples/apps/hello_world/basic/main.py new file mode 100644 index 0000000000..4c60595784 --- /dev/null +++ b/sdk/python/examples/apps/hello_world/basic/main.py @@ -0,0 +1,9 @@ +import flet as ft + + +def main(page: ft.Page): + page.add(ft.SafeArea(content=ft.Text("Hello, world!"))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/hello_world/basic/pyproject.toml b/sdk/python/examples/apps/hello_world/basic/pyproject.toml new file mode 100644 index 0000000000..8982987711 --- /dev/null +++ b/sdk/python/examples/apps/hello_world/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-hello-world-basic" +version = "1.0.0" +description = "Minimal app that renders a single hello-world text message." +requires-python = ">=3.10" +keywords = ["apps", "hello world", "minimal", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Getting Started"] + +[tool.flet.metadata] +title = "Hello world" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["minimal app"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/icons_browser/main.py b/sdk/python/examples/apps/icons_browser/main.py new file mode 100644 index 0000000000..836f24860f --- /dev/null +++ b/sdk/python/examples/apps/icons_browser/main.py @@ -0,0 +1,180 @@ +import asyncio +from itertools import islice + +import flet as ft + +# logging.basicConfig(level=logging.INFO) +ft.context.disable_auto_update() + + +class IconBrowser(ft.Container): + def __init__(self, icon_set, expand=False, height=500): + super().__init__() + self.icon_set = icon_set + if expand: + self.expand = expand + else: + self.height = height + + def build(self): + def batches(iterable, batch_size): + iterator = iter(iterable) + while batch := list(islice(iterator, batch_size)): + yield batch + + # fetch all icon constants from icons.py module + icons_list = list(self.icon_set) + + search_icon = ( + self.icon_set.SEARCH + if hasattr(self.icon_set, "SEARCH") + else ft.Icons.SEARCH + ) + + async def search_click(): + await display_icons(search_txt.value) + + search_txt = ft.TextField( + expand=1, + hint_text="Enter keyword and press search button. " + "To view all icons enter *", + autofocus=True, + on_submit=search_click, + ) + + search_query = ft.Row( + [search_txt, ft.IconButton(icon=search_icon, on_click=search_click)] + ) + + search_results = ft.GridView( + expand=1, + runs_count=10, + max_extent=150, + spacing=5, + run_spacing=5, + child_aspect_ratio=1, + ) + status_bar = ft.Text() + + async def copy_to_clipboard(e): + icon_key = e.control.data + print("Copy to clipboard:", icon_key) + await ft.Clipboard().set(icon_key) + self.page.show_dialog(ft.SnackBar(ft.Text(f"Copied {icon_key}"))) + + def search_icons(search_term: str): + # switch variable to allow empty search, which shows all icons + all_icons = 0 + for icon in icons_list: + icon_name = icon.name + if all_icons == 1 or search_term != "": + # match search to query + if search_term != "" and search_term in icon_name: + all_icons = 0 + yield icon + # turn on switch, empty search, and yield to not skip 1st icon + elif search_term == "*": + all_icons = 1 + search_term = "" + yield icon + # all_icons is 1, which allows for empty search, which shows all + elif search_term == "" and all_icons == 1: + yield icon + else: + all_icons = 0 + + async def display_icons(search_term: str): + # clean search results + search_query.disabled = True + self.update() + + search_results.controls.clear() + search_results.update() + + print("Searching for icons with term:", search_term) + + for batch in batches(search_icons(search_term.upper()), 500): + for icon in batch: + icon_name = icon.name + icon_key = f"ft.{icon.__class__.__name__}.{icon_name}" + # print("Found icon:", icon_key) + search_results.controls.append( + ft.TextButton( + content=ft.Container( + content=ft.Column( + [ + ft.Icon(icon=icon, size=30), + ft.Text( + value=f"{icon_name}", + size=12, + width=100, + no_wrap=True, + text_align=ft.TextAlign.CENTER, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + spacing=5, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + alignment=ft.Alignment.CENTER, + ), + tooltip=f"{icon_key}\nClick to copy to a clipboard", + on_click=copy_to_clipboard, + data=icon_key, + ) + ) + status_bar.value = f"Icons found: {len(search_results.controls)}" + self.update() + print(f"Displayed {len(search_results.controls)} icons so far...") + await asyncio.sleep(0.1) # allow UI to update + + if len(search_results.controls) == 0: + self.page.show_dialog(ft.SnackBar(ft.Text("No icons found"))) + search_query.disabled = False + self.update() + + self.content = ft.Column( + [ + search_query, + search_results, + status_bar, + ], + expand=True, + ) + + +def main(page: ft.Page): + page.title = "Flet icons browser" + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + selected_index=0, + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Material"), + ft.Tab(label="Cupertino"), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + IconBrowser(ft.Icons, expand=True), + IconBrowser(ft.CupertinoIcons, expand=True), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/icons_browser/pyproject.toml b/sdk/python/examples/apps/icons_browser/pyproject.toml new file mode 100644 index 0000000000..53640f6057 --- /dev/null +++ b/sdk/python/examples/apps/icons_browser/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-icons-browser" +version = "1.0.0" +description = "Searches Material and Cupertino icon sets and copies selected icon constants to the clipboard." +requires-python = ">=3.10" +keywords = ["apps", "icons", "search", "clipboard", "tabs", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured", "Tools"] + +[tool.flet.metadata] +title = "Icons browser" +controls = ["SafeArea", "Tabs", "TabBar", "TabBarView", "TextField", "IconButton", "GridView", "TextButton", "SnackBar"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["icon search", "clipboard copy", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/palette_editor/main.py b/sdk/python/examples/apps/palette_editor/main.py new file mode 100644 index 0000000000..3123513c5c --- /dev/null +++ b/sdk/python/examples/apps/palette_editor/main.py @@ -0,0 +1,708 @@ +from datetime import time + +from palette_constants import ( + COLOR_ROLE_BY_LABEL, + LEFT_PANE_ROLE_TABS, + LIGHT_SEED_COLOR, + MATERIAL_COLORS, + ROLE_DESCRIPTION_BY_ATTR, + SEED_COLOR_OPTIONS, + THEME_COLOR_ROLE_NAMES, +) +from palette_theme_io import build_export_code, parse_import_theme_code +from palette_ui import ( + build_left_pane_controls, + build_preview_tabs, + material_color_circle, + material_shade_swatch, +) + +import flet as ft +from flet_color_pickers import HueRingPicker + +ft.context.disable_auto_update() + + +def main(page: ft.Page): + page.title = "Palette Editor" + page.bgcolor = ft.Colors.SURFACE + page.padding = 14 + page.theme_mode = ft.ThemeMode.LIGHT + # page.window.width = 420 + # page.window.height = 460 + left_pane_width = 250 + swatch_width = 250 + swatch_height = 40 + preview_heading = "Palette preview" + preview_body = ( + "Controls on this side use the current theme so you can compare " + "tokens with real UI." + ) + selected_color_heading = ft.Text("Color editor", weight=ft.FontWeight.W_600) + selected_color_text = ft.Text("Choose a color role to edit.") + selected_color_status = ft.Text("", size=12, color=ft.Colors.ON_SURFACE_VARIANT) + selected_role = {"label": None, "attr": None} + selected_material_color = {"label": None, "value": None} + selected_shade = {"label": None, "value": None} + selected_left_tab_index = {"value": 0} + selected_preview_tab_index = {"value": 0} + preview_theme_mode = {"value": ft.ThemeMode.LIGHT} + light_theme_color_overrides: dict[str, ft.ColorValue] = {} + dark_theme_color_overrides: dict[str, ft.ColorValue] = {} + theme_seed_colors = { + ft.ThemeMode.LIGHT: LIGHT_SEED_COLOR, + ft.ThemeMode.DARK: LIGHT_SEED_COLOR, + } + left_pane_host = ft.Container(expand=True) + preview_pane_host = ft.Container(expand=True) + + def split_theme_overrides( + overrides: dict[str, ft.ColorValue], + ) -> tuple[dict[str, ft.ColorValue], dict[str, ft.ColorValue]]: + theme_overrides = { + key: value + for key, value in overrides.items() + if key in THEME_COLOR_ROLE_NAMES + } + color_scheme_overrides = { + key: value + for key, value in overrides.items() + if key not in THEME_COLOR_ROLE_NAMES + } + return theme_overrides, color_scheme_overrides + + def build_light_theme() -> ft.Theme: + light_theme_overrides, light_color_scheme_overrides = split_theme_overrides( + light_theme_color_overrides + ) + return ft.Theme( + color_scheme_seed=theme_seed_colors[ft.ThemeMode.LIGHT], + color_scheme=ft.ColorScheme(**light_color_scheme_overrides), + **light_theme_overrides, + ) + + def build_dark_theme() -> ft.Theme: + dark_theme_overrides, dark_color_scheme_overrides = split_theme_overrides( + dark_theme_color_overrides + ) + return ft.Theme( + color_scheme_seed=theme_seed_colors[ft.ThemeMode.DARK], + color_scheme=ft.ColorScheme(**dark_color_scheme_overrides), + **dark_theme_overrides, + ) + + def close_color_editor(_): + color_editor_pane.visible = False + page.update() + + def rebuild_theme(): + scaffold_bgcolor = ( + get_current_role_color_value("scaffold_bgcolor") or ft.Colors.SURFACE + ) + preview_pane_host.content = ft.Container( + expand=True, + bgcolor=scaffold_bgcolor, + padding=16, + theme=build_light_theme(), + dark_theme=build_dark_theme(), + theme_mode=preview_theme_mode["value"], + content=build_preview_tabs( + preview_heading=preview_heading, + preview_body=preview_body, + preview_time_text=preview_time_text, + scaffold_bgcolor=scaffold_bgcolor, + selected_tab_index=selected_preview_tab_index["value"], + on_tab_change=on_preview_tab_change, + open_preview_time_picker=open_preview_time_picker, + ), + ) + if preview_pane_host.page is not None: + preview_pane_host.update() + + def current_theme_color_overrides() -> dict[str, ft.ColorValue]: + return ( + light_theme_color_overrides + if preview_theme_mode["value"] == ft.ThemeMode.LIGHT + else dark_theme_color_overrides + ) + + def current_seed_color() -> ft.ColorValue: + return theme_seed_colors[preview_theme_mode["value"]] + + def update_selected_color_heading(): + if selected_role["label"] is None: + selected_color_heading.value = "Color editor" + return + mode_label = ( + "dark theme" + if preview_theme_mode["value"] == ft.ThemeMode.DARK + else "light theme" + ) + selected_color_heading.value = ( + f"{selected_role['label']} editor for {mode_label}" + ) + + def update_selected_color_text(): + if selected_role["label"] is None: + selected_color_text.value = "Choose a color role to edit." + selected_color_status.value = "" + return + description = ROLE_DESCRIPTION_BY_ATTR.get(selected_role["attr"]) + if description is not None: + selected_color_text.value = description + selected_color_status.value = "" + return + selected_color_text.value = "" + selected_color_status.value = "" + + def get_role_value(role_label: str) -> ft.ColorValue: + role_attr = COLOR_ROLE_BY_LABEL[role_label] + return get_current_role_color_value(role_attr) + + def format_role_value(color_value: ft.ColorValue) -> str: + if hasattr(color_value, "name"): + return color_value.name + return str(color_value) + + def update_hex_picker(color_value: ft.ColorValue | None): + hex_color_picker.color = color_value + + def get_current_role_color_value(role_attr: str | None) -> ft.ColorValue | None: + if role_attr is None: + return None + override = current_theme_color_overrides().get(role_attr) + if override is not None: + return override + if role_attr == "scaffold_bgcolor": + return ft.Colors.SURFACE + token_name = role_attr.upper() + if hasattr(ft.Colors, token_name): + return getattr(ft.Colors, token_name) + return None + + def set_selected_material_from_value(color_value: ft.ColorValue | None): + if color_value is None: + selected_material_color["label"] = None + selected_material_color["value"] = None + selected_shade["label"] = None + selected_shade["value"] = None + update_hex_picker(None) + return + + for label, value in MATERIAL_COLORS: + if value == color_value: + selected_material_color["label"] = label + selected_material_color["value"] = value + selected_shade["label"] = None + selected_shade["value"] = None + update_hex_picker(color_value) + return + + for material_label, material_value in MATERIAL_COLORS: + for shade_label, shade_value in get_shades(material_label): + if shade_value == color_value: + selected_material_color["label"] = material_label + selected_material_color["value"] = material_value + selected_shade["label"] = shade_label + selected_shade["value"] = shade_value + update_hex_picker(color_value) + return + + selected_material_color["label"] = None + selected_material_color["value"] = None + selected_shade["label"] = None + selected_shade["value"] = None + update_hex_picker(color_value) + + def get_shades(color_label: str | None) -> list[tuple[str, ft.ColorValue]]: + if color_label is None or color_label in {"BLACK", "WHITE", "TRANSPARENT"}: + return [] + shades: list[tuple[str, ft.ColorValue]] = [] + for shade in [ + "50", + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + ]: + shades.append((shade, getattr(ft.Colors, f"{color_label}_{shade}"))) + accent_name = f"{color_label}_ACCENT" + if hasattr(ft.Colors, accent_name): + for shade in ["100", "200", "400", "700"]: + shades.append( + (f"A{shade}", getattr(ft.Colors, f"{accent_name}_{shade}")) + ) + return shades + + def rebuild_material_color_controls(): + material_color_row.controls = [ + material_color_circle( + color, + label, + selected=selected_material_color["label"] == label, + on_click=on_material_color_click(label, color), + ) + for label, color in MATERIAL_COLORS + ] + + def rebuild_left_pane_controls(): + left_pane_controls.controls = build_left_pane_controls( + selected_label=selected_role["label"], + swatch_width=swatch_width, + swatch_height=swatch_height, + theme_mode=preview_theme_mode["value"], + role_tabs=LEFT_PANE_ROLE_TABS, + selected_tab_index=selected_left_tab_index["value"], + seed_color_options=SEED_COLOR_OPTIONS, + selected_seed_color=current_seed_color(), + swatch_theme=build_light_theme(), + swatch_dark_theme=build_dark_theme(), + swatch_theme_mode=preview_theme_mode["value"], + get_role_value=get_role_value, + format_role_value=format_role_value, + on_color_click=on_color_click, + on_tab_change=on_left_tab_change, + on_select_seed=select_seed_color, + on_toggle_theme=toggle_theme_mode, + on_export=export_theme, + on_import=open_import_dialog, + ) + left_pane_host.content = left_pane_controls + + def rebuild_shade_controls(): + shades = get_shades(selected_material_color["label"]) + shade_row.visible = len(shades) > 0 + shade_row.controls = [ + material_shade_swatch( + color, + label, + selected=selected_shade["label"] == label, + on_click=on_shade_click(label, color), + ) + for label, color in shades + ] + + def on_material_color_click(color_label: str, color_value: ft.ColorValue): + def handler(_): + selected_material_color["label"] = color_label + selected_material_color["value"] = color_value + selected_shade["label"] = None + selected_shade["value"] = None + update_hex_picker(color_value) + rebuild_material_color_controls() + rebuild_shade_controls() + if selected_role["attr"] is None or selected_role["label"] is None: + return + current_theme_color_overrides()[selected_role["attr"]] = color_value + rebuild_theme() + rebuild_left_pane_controls() + selected_color_status.value = ( + f"{selected_role['label']} color changed to {color_label}." + ) + page.update() + + return handler + + def on_shade_click(shade_label: str, shade_value: ft.ColorValue): + def handler(_): + selected_shade["label"] = shade_label + selected_shade["value"] = shade_value + update_hex_picker(shade_value) + rebuild_shade_controls() + if selected_role["attr"] is None or selected_role["label"] is None: + return + current_theme_color_overrides()[selected_role["attr"]] = shade_value + rebuild_theme() + rebuild_left_pane_controls() + selected_color_status.value = ( + f"{selected_role['label']} color changed to " + f"{selected_material_color['label']} {shade_label}." + ) + page.update() + + return handler + + def on_hex_color_change(e: ft.ControlEvent): + if selected_role["attr"] is None or selected_role["label"] is None: + return + current_theme_color_overrides()[selected_role["attr"]] = e.data + set_selected_material_from_value(e.data) + rebuild_material_color_controls() + rebuild_shade_controls() + rebuild_theme() + rebuild_left_pane_controls() + selected_color_status.value = ( + f"{selected_role['label']} color changed to {e.data}." + ) + page.update() + + material_color_row = ft.Row( + wrap=True, + spacing=8, + run_spacing=8, + controls=[], + ) + shade_row = ft.Row( + visible=False, + scroll=ft.ScrollMode.AUTO, + spacing=0, + controls=[], + ) + left_pane_controls = ft.Column( + scroll=ft.ScrollMode.AUTO, + spacing=8, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[], + ) + hex_color_picker = HueRingPicker( + color=None, + on_color_change=on_hex_color_change, + color_picker_height=220, + enable_alpha=False, + hue_ring_stroke_width=18, + picker_area_border_radius=ft.BorderRadius.all(12), + ) + rebuild_material_color_controls() + rebuild_shade_controls() + + color_editor_pane = ft.Container( + visible=False, + width=swatch_width * 2, + padding=ft.Padding.only(left=8, right=8), + content=ft.Container( + expand=True, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + padding=16, + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + spacing=12, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + selected_color_heading, + ft.IconButton( + icon=ft.Icons.CLOSE, + icon_size=16, + tooltip="Close color editor", + on_click=close_color_editor, + ), + ], + ), + selected_color_text, + selected_color_status, + material_color_row, + shade_row, + hex_color_picker, + ], + ), + ), + ) + preview_time_text = ft.Text( + value="19:30", + ) + + def handle_preview_time_change(e: ft.Event[ft.TimePicker]): + preview_time_text.value = str(preview_time_picker.value.strftime("%H:%M")) + page.update() + + preview_time_picker = ft.TimePicker( + value=time(hour=19, minute=30), + confirm_text="Confirm", + error_invalid_text="Time out of range", + help_text="Pick your time slot", + entry_mode=ft.TimePickerEntryMode.DIAL, + on_change=handle_preview_time_change, + ) + import_format_hint = ( + "Use this format:\n" + "ft.Theme(\n" + " scaffold_bgcolor='#fff8f3ec',\n" + " color_scheme=ft.ColorScheme(\n" + " primary='#ff87581b',\n" + " on_primary=ft.Colors.WHITE,\n" + " )\n" + ")" + ) + + def on_color_click(label: str): + def handler(_): + selected_role["label"] = label + selected_role["attr"] = COLOR_ROLE_BY_LABEL[label] + set_selected_material_from_value( + get_current_role_color_value(selected_role["attr"]) + ) + update_selected_color_heading() + update_selected_color_text() + color_editor_pane.visible = True + rebuild_left_pane_controls() + rebuild_material_color_controls() + rebuild_shade_controls() + page.update() + + return handler + + def clear_editor_selection(): + current_theme_color_overrides().clear() + selected_role["label"] = None + selected_role["attr"] = None + selected_material_color["label"] = None + selected_material_color["value"] = None + selected_shade["label"] = None + selected_shade["value"] = None + update_selected_color_heading() + update_selected_color_text() + color_editor_pane.visible = False + + pending_seed_selection = {"color": None, "label": None} + + def close_seed_confirm_dialog(_): + page.pop_dialog() + page.update() + + def apply_seed_selection(_): + seed_color = pending_seed_selection["color"] + if seed_color is None: + page.pop_dialog() + page.update() + return + theme_seed_colors[preview_theme_mode["value"]] = seed_color + current_theme_color_overrides().clear() + clear_editor_selection() + rebuild_left_pane_controls() + rebuild_material_color_controls() + rebuild_shade_controls() + rebuild_theme() + page.pop_dialog() + page.update() + + seed_confirm_text = ft.Text("") + seed_confirm_dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Rebuild from seed"), + content=seed_confirm_text, + actions=[ + ft.TextButton("Cancel", on_click=close_seed_confirm_dialog), + ft.TextButton("Rebuild", on_click=apply_seed_selection), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + + def select_seed_color(seed_color: ft.ColorValue): + def handler(_): + seed_label = next( + (label for label, color in SEED_COLOR_OPTIONS if color == seed_color), + "selected seed", + ) + pending_seed_selection["color"] = seed_color + pending_seed_selection["label"] = seed_label + seed_confirm_text.value = ( + f"Rebuild the current {preview_theme_mode['value'].value} theme " + f"from {seed_label} and clear its overrides?" + ) + page.show_dialog(seed_confirm_dialog) + page.update() + + return handler + + async def copy_export_theme(_): + export_code = build_export_code(current_theme_color_overrides()) + print(export_code) + await ft.Clipboard().set(export_code) + export_copy_button.icon = ft.Icons.CHECK + page.update() + + export_code_text = ft.TextField( + multiline=True, + min_lines=12, + max_lines=16, + read_only=True, + value="", + ) + export_copy_button = ft.IconButton( + icon=ft.Icons.CONTENT_COPY, + tooltip="Copy to clipboard", + on_click=copy_export_theme, + ) + export_dialog_title = ft.Text("Export palette") + export_dialog = ft.AlertDialog( + modal=True, + title=export_dialog_title, + content=ft.Container( + width=520, + content=export_code_text, + ), + actions=[ + export_copy_button, + ft.TextButton("Close", on_click=lambda _: page.pop_dialog()), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + + import_code_text = ft.TextField( + multiline=True, + min_lines=12, + max_lines=16, + value="", + hint_text=import_format_hint, + autofocus=True, + ) + import_error_text = ft.Text( + "", + color=ft.Colors.ERROR, + visible=False, + ) + + def close_import_dialog(_): + page.pop_dialog() + page.update() + + def import_theme(_): + try: + parsed_overrides = parse_import_theme_code(import_code_text.value or "") + except ValueError: + import_error_text.value = ( + f"Couldn't parse theme code.\n\n{import_format_hint}" + ) + import_error_text.visible = True + page.update() + return + + current_overrides = current_theme_color_overrides() + current_overrides.clear() + current_overrides.update(parsed_overrides) + rebuild_theme() + if selected_role["attr"] is not None: + set_selected_material_from_value( + get_current_role_color_value(selected_role["attr"]) + ) + else: + selected_material_color["label"] = None + selected_material_color["value"] = None + selected_shade["label"] = None + selected_shade["value"] = None + update_hex_picker(None) + rebuild_left_pane_controls() + rebuild_material_color_controls() + rebuild_shade_controls() + import_error_text.visible = False + page.pop_dialog() + page.update() + + import_dialog_title = ft.Text("Import palette") + import_dialog = ft.AlertDialog( + modal=True, + title=import_dialog_title, + content=ft.Container( + width=520, + content=ft.Column( + tight=True, + spacing=12, + controls=[import_code_text, import_error_text], + ), + ), + actions=[ + ft.TextButton("Import", on_click=import_theme), + ft.TextButton("Close", on_click=close_import_dialog), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + + def export_theme(_): + mode_label = ( + "dark theme" + if preview_theme_mode["value"] == ft.ThemeMode.DARK + else "light theme" + ) + export_dialog_title.value = f"Export palette for {mode_label}" + export_code_text.value = build_export_code(current_theme_color_overrides()) + export_copy_button.icon = ft.Icons.CONTENT_COPY + page.show_dialog(export_dialog) + page.update() + + def open_import_dialog(_): + mode_label = ( + "dark theme" + if preview_theme_mode["value"] == ft.ThemeMode.DARK + else "light theme" + ) + import_dialog_title.value = f"Import palette for {mode_label}" + import_code_text.value = "" + import_error_text.value = "" + import_error_text.visible = False + page.show_dialog(import_dialog) + page.update() + + def open_preview_time_picker(_): + page.show_dialog(preview_time_picker) + page.update() + + def toggle_theme_mode(_): + preview_theme_mode["value"] = ( + ft.ThemeMode.DARK + if preview_theme_mode["value"] == ft.ThemeMode.LIGHT + else ft.ThemeMode.LIGHT + ) + page.theme_mode = preview_theme_mode["value"] + rebuild_theme() + if selected_role["attr"] is not None: + set_selected_material_from_value( + get_current_role_color_value(selected_role["attr"]) + ) + update_selected_color_heading() + update_selected_color_text() + rebuild_material_color_controls() + rebuild_shade_controls() + rebuild_left_pane_controls() + page.update() + + def on_left_tab_change(e: ft.ControlEvent): + selected_left_tab_index["value"] = e.control.selected_index + rebuild_left_pane_controls() + page.update() + + def on_preview_tab_change(e: ft.ControlEvent): + selected_preview_tab_index["value"] = e.control.selected_index + + rebuild_left_pane_controls() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + expand=True, + content=ft.Row( + expand=True, + spacing=0, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Container( + width=left_pane_width, + alignment=ft.Alignment.TOP_LEFT, + content=left_pane_host, + ), + color_editor_pane, + ft.VerticalDivider( + width=24, thickness=1, color=ft.Colors.OUTLINE_VARIANT + ), + ft.Container( + expand=True, + padding=ft.Padding.only(left=4), + content=preview_pane_host, + ), + ], + ), + ), + ) + ) + rebuild_theme() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/palette_editor/palette_constants.py b/sdk/python/examples/apps/palette_editor/palette_constants.py new file mode 100644 index 0000000000..7283724a10 --- /dev/null +++ b/sdk/python/examples/apps/palette_editor/palette_constants.py @@ -0,0 +1,446 @@ +import flet as ft + +LIGHT_SEED_COLOR = ft.Colors.BLUE + +MATERIAL_COLORS = [ + ("AMBER", ft.Colors.AMBER), + ("BLACK", ft.Colors.BLACK), + ("BLUE", ft.Colors.BLUE), + ("BLUE_GREY", ft.Colors.BLUE_GREY), + ("BROWN", ft.Colors.BROWN), + ("CYAN", ft.Colors.CYAN), + ("DEEP_ORANGE", ft.Colors.DEEP_ORANGE), + ("DEEP_PURPLE", ft.Colors.DEEP_PURPLE), + ("GREEN", ft.Colors.GREEN), + ("GREY", ft.Colors.GREY), + ("INDIGO", ft.Colors.INDIGO), + ("LIGHT_BLUE", ft.Colors.LIGHT_BLUE), + ("LIGHT_GREEN", ft.Colors.LIGHT_GREEN), + ("LIME", ft.Colors.LIME), + ("ORANGE", ft.Colors.ORANGE), + ("PINK", ft.Colors.PINK), + ("PURPLE", ft.Colors.PURPLE), + ("RED", ft.Colors.RED), + ("TEAL", ft.Colors.TEAL), + ("TRANSPARENT", ft.Colors.TRANSPARENT), + ("WHITE", ft.Colors.WHITE), + ("YELLOW", ft.Colors.YELLOW), +] + +COLOR_ROLE_BY_LABEL = { + "PRIMARY": "primary", + "ON_PRIMARY": "on_primary", + "PRIMARY_CONTAINER": "primary_container", + "ON_PRIMARY_CONTAINER": "on_primary_container", + "PRIMARY_FIXED": "primary_fixed", + "PRIMARY_FIXED_DIM": "primary_fixed_dim", + "ON_PRIMARY_FIXED": "on_primary_fixed", + "ON_PRIMARY_FIXED_VARIANT": "on_primary_fixed_variant", + "SECONDARY": "secondary", + "ON_SECONDARY": "on_secondary", + "SECONDARY_CONTAINER": "secondary_container", + "ON_SECONDARY_CONTAINER": "on_secondary_container", + "SECONDARY_FIXED": "secondary_fixed", + "SECONDARY_FIXED_DIM": "secondary_fixed_dim", + "ON_SECONDARY_FIXED": "on_secondary_fixed", + "ON_SECONDARY_FIXED_VARIANT": "on_secondary_fixed_variant", + "TERTIARY": "tertiary", + "ON_TERTIARY": "on_tertiary", + "TERTIARY_CONTAINER": "tertiary_container", + "ON_TERTIARY_CONTAINER": "on_tertiary_container", + "TERTIARY_FIXED": "tertiary_fixed", + "TERTIARY_FIXED_DIM": "tertiary_fixed_dim", + "ON_TERTIARY_FIXED": "on_tertiary_fixed", + "ON_TERTIARY_FIXED_VARIANT": "on_tertiary_fixed_variant", + "ERROR": "error", + "ON_ERROR": "on_error", + "ERROR_CONTAINER": "error_container", + "ON_ERROR_CONTAINER": "on_error_container", + "SURFACE": "surface", + "ON_SURFACE": "on_surface", + "ON_SURFACE_VARIANT": "on_surface_variant", + "SURFACE_TINT": "surface_tint", + "SURFACE_DIM": "surface_dim", + "SURFACE_BRIGHT": "surface_bright", + "SURFACE_CONTAINER": "surface_container", + "SURFACE_CONTAINER_LOW": "surface_container_low", + "SURFACE_CONTAINER_LOWEST": "surface_container_lowest", + "SURFACE_CONTAINER_HIGH": "surface_container_high", + "SURFACE_CONTAINER_HIGHEST": "surface_container_highest", + "SCAFFOLD_BGCOLOR": "scaffold_bgcolor", + "OUTLINE": "outline", + "OUTLINE_VARIANT": "outline_variant", + "SHADOW": "shadow", + "SCRIM": "scrim", + "INVERSE_SURFACE": "inverse_surface", + "ON_INVERSE_SURFACE": "on_inverse_surface", + "INVERSE_PRIMARY": "inverse_primary", +} + +THEME_COLOR_ROLE_NAMES = {"scaffold_bgcolor"} + +ROLE_DESCRIPTION_BY_ATTR = { + "primary": "High-emphasis fills, texts, and icons against surface.", + "on_primary": "Text and icons against primary.", + "primary_container": ( + "Standout fill color against surface, for key components like FAB." + ), + "on_primary_container": "Text and icons against primary container.", + "secondary": "Less prominent fills, text, and icons against surface.", + "on_secondary": "Text and icons against secondary.", + "secondary_container": ( + "Less prominent fill color against surface, for recessive " + "components like tonal buttons." + ), + "on_secondary_container": "Text and icons against secondary container.", + "tertiary": "Complementary fills, text, and icons against surface.", + "on_tertiary": "Text and icons against tertiary.", + "tertiary_container": ( + "Complementary container color against surface, for components " + "like input fields." + ), + "on_tertiary_container": "Text and icons against tertiary container.", + "error": ( + "Attention-grabbing color against surface for fills, icons, and " + "text, indicating urgency." + ), + "on_error": "Text and icons against error.", + "error_container": "Attention-grabbing fill color against surface.", + "on_error_container": "Text and icons against error container.", + "surface": "Default color for backgrounds.", + "on_surface": "Text and icons against any surface or surface container color.", + "on_surface_variant": ( + "Lower-emphasis color for text and icons against any surface " + "or surface container color." + ), + "surface_dim": "Dimmest surface color in light and dark themes.", + "surface_bright": "Brightest surface color in light and dark themes.", + "surface_container_lowest": "Lowest-emphasis container color.", + "surface_container_low": "Low-emphasis container color.", + "surface_container": "Default container color.", + "surface_container_high": "High-emphasis container color.", + "surface_container_highest": "Highest-emphasis container color.", + "primary_fixed": ( + "Fill color used against surface that maintains the same tone " + "in light and dark themes." + ), + "primary_fixed_dim": ( + "A stronger, more emphasized tone than primary fixed with the " + "same fixed behavior." + ), + "on_primary_fixed": "Text and icons against primary fixed.", + "on_primary_fixed_variant": ( + "Lower-emphasis text and icons against primary fixed." + ), + "secondary_fixed": ( + "Fill color used against surface that maintains the same tone " + "in light and dark themes." + ), + "secondary_fixed_dim": ( + "A stronger, more emphasized tone than secondary fixed with the " + "same fixed behavior." + ), + "on_secondary_fixed": "Text and icons against secondary fixed.", + "on_secondary_fixed_variant": ( + "Lower-emphasis text and icons against secondary fixed." + ), + "tertiary_fixed": ( + "Fill color used against surface that maintains the same tone " + "in light and dark themes." + ), + "tertiary_fixed_dim": ( + "A stronger, more emphasized tone than tertiary fixed with the " + "same fixed behavior." + ), + "on_tertiary_fixed": "Text and icons against tertiary fixed.", + "on_tertiary_fixed_variant": ( + "Lower-emphasis text and icons against tertiary fixed." + ), + "inverse_surface": ( + "Background fills for elements which contrast against surface." + ), + "on_inverse_surface": "Text and icons against inverse surface.", + "inverse_primary": ( + "Actionable elements, such as text buttons, against inverse surface." + ), + "outline": "Important boundaries, such as a text field outline.", + "outline_variant": ( + "Decorative elements, such as dividers, and when other elements " + "provide 4.5:1 contrast." + ), + "shadow": "Color used for drop shadows of elevated components.", + "scrim": "Color used for the scrim around modal components.", + "scaffold_bgcolor": "Customizes the page background color.", +} + +COLOR_ROLE_EXPORT_ORDER = list(dict.fromkeys(COLOR_ROLE_BY_LABEL.values())) + +SEED_COLOR_OPTIONS = [ + ("Deep purple", ft.Colors.DEEP_PURPLE), + ("Indigo", ft.Colors.INDIGO), + ("Blue (default)", ft.Colors.BLUE), + ("Teal", ft.Colors.TEAL), + ("Green", ft.Colors.GREEN), + ("Yellow", ft.Colors.YELLOW), + ("Orange", ft.Colors.ORANGE), + ("Deep orange", ft.Colors.DEEP_ORANGE), + ("Pink", ft.Colors.PINK), +] + +LEFT_PANE_ROLE_TABS = [ + { + "label": "Accent", + "groups": [ + { + "title": "Primary", + "hint": ( + "Use primary roles for the most\n" + "prominent components across the UI,\n" + "such as the FAB,\n" + "high-emphasis buttons, and active states." + ), + "items": [ + ("PRIMARY", "PRIMARY", "ON_PRIMARY"), + ("ON_PRIMARY", "ON_PRIMARY", "PRIMARY"), + ( + "PRIMARY_CONTAINER", + "PRIMARY_CONTAINER", + "ON_PRIMARY_CONTAINER", + ), + ( + "ON_PRIMARY_CONTAINER", + "ON_PRIMARY_CONTAINER", + "PRIMARY_CONTAINER", + ), + ], + }, + { + "title": "Secondary", + "hint": ( + "Use secondary roles for less prominent\n" + "components in the UI such as filter chips." + ), + "items": [ + ("SECONDARY", "SECONDARY", "ON_SECONDARY"), + ("ON_SECONDARY", "ON_SECONDARY", "SECONDARY"), + ( + "SECONDARY_CONTAINER", + "SECONDARY_CONTAINER", + "ON_SECONDARY_CONTAINER", + ), + ( + "ON_SECONDARY_CONTAINER", + "ON_SECONDARY_CONTAINER", + "SECONDARY_CONTAINER", + ), + ], + }, + { + "title": "Tertiary", + "hint": ( + "Use tertiary roles for contrasting accents\n" + "that balance primary and secondary colors\n" + "or bring heightened attention to an element\n" + "such as an input field." + ), + "items": [ + ("TERTIARY", "TERTIARY", "ON_TERTIARY"), + ("ON_TERTIARY", "ON_TERTIARY", "TERTIARY"), + ( + "TERTIARY_CONTAINER", + "TERTIARY_CONTAINER", + "ON_TERTIARY_CONTAINER", + ), + ( + "ON_TERTIARY_CONTAINER", + "ON_TERTIARY_CONTAINER", + "TERTIARY_CONTAINER", + ), + ], + }, + { + "title": "Error", + "hint": ( + "Use error roles to communicate error states,\n" + "such as an incorrect password entered\n" + "into a text field." + ), + "items": [ + ("ERROR", "ERROR", "ON_ERROR"), + ("ON_ERROR", "ON_ERROR", "ERROR"), + ("ERROR_CONTAINER", "ERROR_CONTAINER", "ON_ERROR_CONTAINER"), + ("ON_ERROR_CONTAINER", "ON_ERROR_CONTAINER", "ERROR_CONTAINER"), + ], + }, + ], + }, + { + "label": "Surface", + "groups": [ + { + "title": "Surface", + "hint": ( + "Use surface roles for more neutral\n" + "backgrounds, and container colors for\n" + "components like cards, sheets, and dialogs." + ), + "items": [ + ("SURFACE", "SURFACE", "ON_SURFACE"), + ("ON_SURFACE", "ON_SURFACE", "SURFACE"), + ("SURFACE_TINT", "SURFACE_TINT", "ON_SURFACE"), + ("ON_SURFACE_VARIANT", "ON_SURFACE_VARIANT", "SURFACE"), + ], + }, + { + "title": "Surface containers", + "hint": ( + "Five surface container roles are named\n" + "based on their level of emphasis." + ), + "items": [ + ("SURFACE_CONTAINER", "SURFACE_CONTAINER", "ON_SURFACE"), + ("SURFACE_CONTAINER_LOW", "SURFACE_CONTAINER_LOW", "ON_SURFACE"), + ( + "SURFACE_CONTAINER_LOWEST", + "SURFACE_CONTAINER_LOWEST", + "ON_SURFACE", + ), + ("SURFACE_CONTAINER_HIGH", "SURFACE_CONTAINER_HIGH", "ON_SURFACE"), + ( + "SURFACE_CONTAINER_HIGHEST", + "SURFACE_CONTAINER_HIGHEST", + "ON_SURFACE", + ), + ], + }, + { + "title": "Page background", + "hint": "Customizes the page background color.", + "items": [ + ("SCAFFOLD_BGCOLOR", "SCAFFOLD_BGCOLOR", "ON_SURFACE"), + ], + }, + { + "title": "Outline", + "hint": "Outline colors to be used against a surface.", + "items": [ + ("OUTLINE", "OUTLINE", "SURFACE"), + ("OUTLINE_VARIANT", "OUTLINE_VARIANT", "ON_SURFACE"), + ], + }, + { + "title": "Inverse colors", + "hint": ( + "Inverse roles are applied selectively to\n" + "components to achieve colors that are the\n" + "reverse of those in the surrounding UI,\n" + "creating a contrasting effect." + ), + "items": [ + ("INVERSE_SURFACE", "INVERSE_SURFACE", "ON_INVERSE_SURFACE"), + ("ON_INVERSE_SURFACE", "ON_INVERSE_SURFACE", "INVERSE_SURFACE"), + ("INVERSE_PRIMARY", "INVERSE_PRIMARY", "ON_PRIMARY"), + ], + }, + ], + }, + { + "label": "Add-on", + "groups": [ + { + "title": "Primary fixed", + "hint": ( + "Most products won't need add-on roles.\n" + "Fixed colors maintain the same tone in\n" + "light and dark themes and may be used\n" + "instead of container roles when fixed\n" + "behavior is desired." + ), + "items": [ + ("PRIMARY_FIXED", "PRIMARY_FIXED", "ON_PRIMARY_FIXED"), + ("PRIMARY_FIXED_DIM", "PRIMARY_FIXED_DIM", "ON_PRIMARY_FIXED"), + ("ON_PRIMARY_FIXED", "ON_PRIMARY_FIXED", "PRIMARY_FIXED"), + ( + "ON_PRIMARY_FIXED_VARIANT", + "ON_PRIMARY_FIXED_VARIANT", + "PRIMARY_FIXED", + ), + ], + }, + { + "title": "Secondary fixed", + "hint": ( + "Most products won't need add-on roles.\n" + "Fixed colors maintain the same tone in\n" + "light and dark themes and may be used\n" + "instead of container roles when fixed\n" + "behavior is desired." + ), + "items": [ + ("SECONDARY_FIXED", "SECONDARY_FIXED", "ON_SECONDARY_FIXED"), + ( + "SECONDARY_FIXED_DIM", + "SECONDARY_FIXED_DIM", + "ON_SECONDARY_FIXED", + ), + ("ON_SECONDARY_FIXED", "ON_SECONDARY_FIXED", "SECONDARY_FIXED"), + ( + "ON_SECONDARY_FIXED_VARIANT", + "ON_SECONDARY_FIXED_VARIANT", + "SECONDARY_FIXED", + ), + ], + }, + { + "title": "Tertiary fixed", + "hint": ( + "Most products won't need add-on roles.\n" + "Fixed colors maintain the same tone in\n" + "light and dark themes and may be used\n" + "instead of container roles when fixed\n" + "behavior is desired." + ), + "items": [ + ("TERTIARY_FIXED", "TERTIARY_FIXED", "ON_TERTIARY_FIXED"), + ( + "TERTIARY_FIXED_DIM", + "TERTIARY_FIXED_DIM", + "ON_TERTIARY_FIXED", + ), + ("ON_TERTIARY_FIXED", "ON_TERTIARY_FIXED", "TERTIARY_FIXED"), + ( + "ON_TERTIARY_FIXED_VARIANT", + "ON_TERTIARY_FIXED_VARIANT", + "TERTIARY_FIXED", + ), + ], + }, + { + "title": "Surface add-ons", + "hint": ( + "Most products won't need add-on roles.\n" + "Surface bright and surface dim provide\n" + "specialized surface tones that keep their\n" + "relative brightness across light and dark\n" + "themes." + ), + "items": [ + ("SURFACE_DIM", "SURFACE_DIM", "ON_SURFACE"), + ("SURFACE_BRIGHT", "SURFACE_BRIGHT", "ON_SURFACE"), + ], + }, + { + "title": "Effects", + "hint": ( + "Colors used for elevation and modal\n" + "layering effects, such as shadows and\n" + "scrims." + ), + "items": [ + ("SHADOW", "SHADOW", "SURFACE"), + ("SCRIM", "SCRIM", "SURFACE"), + ], + }, + ], + }, +] diff --git a/sdk/python/examples/apps/palette_editor/palette_theme_io.py b/sdk/python/examples/apps/palette_editor/palette_theme_io.py new file mode 100644 index 0000000000..0770802469 --- /dev/null +++ b/sdk/python/examples/apps/palette_editor/palette_theme_io.py @@ -0,0 +1,128 @@ +import ast + +from palette_constants import COLOR_ROLE_EXPORT_ORDER, THEME_COLOR_ROLE_NAMES + +import flet as ft + + +def normalize_import_theme_code(code: str) -> str: + normalized = code.strip() + if normalized.startswith("```"): + lines = normalized.splitlines() + if lines and lines[0].startswith("```"): + lines = lines[1:] + if lines and lines[-1].strip() == "```": + lines = lines[:-1] + normalized = "\n".join(lines).strip() + return normalized + + +def parse_theme_code_ast(code: str) -> ast.Module: + normalized = normalize_import_theme_code(code) + last_error: SyntaxError | None = None + for _ in range(4): + try: + return ast.parse(normalized) + except SyntaxError as exc: + last_error = exc + if not normalized.endswith(")"): + break + normalized = normalized[:-1].rstrip() + assert last_error is not None + raise ValueError from last_error + + +def format_color_value(color_value: ft.ColorValue) -> str: + if hasattr(color_value, "name"): + return f"ft.Colors.{color_value.name}" + return repr(color_value) + + +def build_export_code(theme_color_overrides: dict[str, ft.ColorValue]) -> str: + lines = ["ft.Theme("] + for color_role in COLOR_ROLE_EXPORT_ORDER: + if color_role not in THEME_COLOR_ROLE_NAMES: + continue + color_value = theme_color_overrides.get(color_role) + if color_value is None: + continue + lines.append(f" {color_role}={format_color_value(color_value)},") + + color_scheme_lines: list[str] = [] + for color_role in COLOR_ROLE_EXPORT_ORDER: + if color_role in THEME_COLOR_ROLE_NAMES: + continue + color_value = theme_color_overrides.get(color_role) + if color_value is None: + continue + color_scheme_lines.append( + f" {color_role}={format_color_value(color_value)}," + ) + + if color_scheme_lines: + lines.append(" color_scheme=ft.ColorScheme(") + lines.extend(color_scheme_lines) + lines.append(" )") + lines.append(")") + return "\n".join(lines) + + +def get_attribute_path(node: ast.AST) -> list[str] | None: + parts: list[str] = [] + current = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + return list(reversed(parts)) + return None + + +def parse_import_color_value(node: ast.AST) -> ft.ColorValue: + if isinstance(node, ast.Constant) and isinstance(node.value, str): + return node.value + attr_path = get_attribute_path(node) + if attr_path and len(attr_path) == 3 and attr_path[:2] == ["ft", "Colors"]: + color_name = attr_path[2] + if hasattr(ft.Colors, color_name): + return getattr(ft.Colors, color_name) + raise ValueError + + +def parse_import_theme_code(code: str) -> dict[str, ft.ColorValue]: + tree = parse_theme_code_ast(code) + + if len(tree.body) != 1 or not isinstance(tree.body[0], ast.Expr): + raise ValueError + + theme_call = tree.body[0].value + if not isinstance(theme_call, ast.Call): + raise ValueError + + theme_path = get_attribute_path(theme_call.func) + if theme_path != ["ft", "Theme"]: + raise ValueError + + parsed_overrides: dict[str, ft.ColorValue] = {} + color_scheme_call: ast.Call | None = None + for keyword in theme_call.keywords: + if keyword.arg in THEME_COLOR_ROLE_NAMES: + parsed_overrides[keyword.arg] = parse_import_color_value(keyword.value) + continue + if keyword.arg == "color_scheme" and isinstance(keyword.value, ast.Call): + color_scheme_call = keyword.value + if color_scheme_call is None and not parsed_overrides: + raise ValueError + + if color_scheme_call is not None: + color_scheme_path = get_attribute_path(color_scheme_call.func) + if color_scheme_path != ["ft", "ColorScheme"]: + raise ValueError + + for keyword in color_scheme_call.keywords: + if keyword.arg not in COLOR_ROLE_EXPORT_ORDER: + raise ValueError + parsed_overrides[keyword.arg] = parse_import_color_value(keyword.value) + + return parsed_overrides diff --git a/sdk/python/examples/apps/palette_editor/palette_ui.py b/sdk/python/examples/apps/palette_editor/palette_ui.py new file mode 100644 index 0000000000..fbc1c34924 --- /dev/null +++ b/sdk/python/examples/apps/palette_editor/palette_ui.py @@ -0,0 +1,1316 @@ +import flet as ft + + +def resolve_theme_token(token_name: str) -> ft.ColorValue: + return getattr(ft.Colors, token_name) + + +def color_band( + role_label: str, + display_label: str, + background: ft.ColorValue, + foreground: ft.ColorValue, + *, + width: int, + height: int, + selected: bool = False, + on_click=None, +) -> ft.Container: + swatch_size = max(24, height - 8) + return ft.Container( + width=width, + height=height, + padding=ft.Padding.symmetric(horizontal=8), + ink=True, + on_click=on_click, + content=ft.Row( + spacing=10, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Container( + width=swatch_size, + height=swatch_size, + bgcolor=background, + border_radius=8, + border=ft.Border.all( + 2 if selected else 1, + ft.Colors.BLACK if selected else ft.Colors.OUTLINE_VARIANT, + ), + ), + ft.Container( + content=ft.Text( + display_label, + size=12, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ), + ], + ), + ) + + +def color_group( + items: list[tuple[str, str, ft.ColorValue, ft.ColorValue]], + *, + width: int, + height: int, + title: str | None = None, + hint: str | None = None, + swatch_theme: ft.Theme, + swatch_dark_theme: ft.Theme, + swatch_theme_mode: ft.ThemeMode, + selected_label: str | None = None, + on_color_click=None, +) -> ft.Container: + return ft.Container( + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + content=ft.Column( + spacing=4, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Container( + visible=title is not None or hint is not None, + height=25, + padding=ft.Padding.only(left=8, right=2), + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(title or "", weight=ft.FontWeight.W_600), + ft.Container( + visible=hint is not None, + content=ft.IconButton( + icon=ft.Icons.INFO_OUTLINE, + icon_size=14, + tooltip=ft.Tooltip( + message=hint or "", + bgcolor=ft.Colors.SURFACE_BRIGHT, + padding=ft.Padding.symmetric( + horizontal=12, vertical=8 + ), + prefer_below=False, + vertical_offset=8, + text_style=ft.TextStyle( + color=ft.Colors.ON_SURFACE + ), + ), + ), + ), + ], + ), + ), + *[ + ft.Container( + theme=swatch_theme, + dark_theme=swatch_dark_theme, + theme_mode=swatch_theme_mode, + content=color_band( + role_label, + display_label, + background, + foreground, + width=width, + height=height, + selected=selected_label == role_label, + on_click=( + on_color_click(role_label) if on_color_click else None + ), + ), + ) + for role_label, display_label, background, foreground in items + ], + ], + ), + ) + + +def showcase_section(title: str, *controls: ft.Control) -> ft.Container: + return ft.Container( + margin=ft.Margin.only(bottom=16), + content=ft.Column(spacing=8, controls=[ft.Text(title), *controls]), + ) + + +def material_color_circle( + color: ft.ColorValue, label: str, *, selected: bool = False, on_click=None +) -> ft.Container: + selected_border_color = ( + getattr(ft.Colors, f"{label}_900") + if hasattr(ft.Colors, f"{label}_900") + else ft.Colors.BLACK + ) + return ft.Container( + width=28, + height=28, + border_radius=14, + bgcolor=color, + border=ft.Border.all( + 2 if selected else 1, + selected_border_color if selected else ft.Colors.OUTLINE_VARIANT, + ), + tooltip=label, + ink=True, + on_click=on_click, + ) + + +def material_shade_swatch( + color: ft.ColorValue, label: str, *, selected: bool = False, on_click=None +) -> ft.Container: + return ft.Container( + width=32, + height=44, + border_radius=22 if selected else 0, + bgcolor=color, + alignment=ft.Alignment.TOP_CENTER, + padding=ft.Padding.only(top=5), + tooltip=label, + ink=True, + on_click=on_click, + content=ft.Text( + label, + size=11, + color=ft.Colors.BLACK if label in {"50", "100", "200"} else ft.Colors.WHITE, + ), + ) + + +def build_left_pane_controls( + *, + selected_label: str | None, + swatch_width: int, + swatch_height: int, + theme_mode: ft.ThemeMode, + role_tabs: list[dict], + selected_tab_index: int, + seed_color_options: list[tuple[str, ft.ColorValue]], + selected_seed_color: ft.ColorValue, + swatch_theme: ft.Theme, + swatch_dark_theme: ft.Theme, + swatch_theme_mode: ft.ThemeMode, + get_role_value, + format_role_value, + on_color_click, + on_tab_change, + on_select_seed, + on_toggle_theme, + on_export, + on_import, +) -> list[ft.Control]: + active_tab = role_tabs[selected_tab_index] + return [ + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Row( + spacing=8, + controls=[ + ft.PopupMenuButton( + icon=ft.Icons.PALETTE, + tooltip="Rebuild from seed", + menu_position=ft.PopupMenuPosition.UNDER, + items=[ + ft.PopupMenuItem( + checked=color == selected_seed_color, + content=ft.Row( + spacing=12, + controls=[ + ft.Icon( + ft.Icons.PALETTE_OUTLINED, + color=color, + ), + ft.Text(label), + ], + ), + on_click=on_select_seed(color), + ) + for label, color in seed_color_options + ], + ), + ft.IconButton( + icon=ft.Icons.DOWNLOAD, + tooltip="Export", + on_click=on_export, + ), + ft.IconButton( + icon=ft.Icons.UPLOAD, + tooltip="Import", + on_click=on_import, + ), + ], + ), + ft.IconButton( + icon=( + ft.Icons.DARK_MODE + if theme_mode == ft.ThemeMode.LIGHT + else ft.Icons.LIGHT_MODE + ), + tooltip=( + "Switch to dark mode" + if theme_mode == ft.ThemeMode.LIGHT + else "Switch to light mode" + ), + on_click=on_toggle_theme, + ), + ], + ), + ft.Tabs( + length=len(role_tabs), + selected_index=selected_tab_index, + on_change=on_tab_change, + content=ft.TabBar( + tab_alignment=ft.TabAlignment.START, + scrollable=True, + tabs=[ft.Tab(label=tab["label"]) for tab in role_tabs], + ), + ), + *[ + color_group( + [ + ( + label, + label, + get_role_value(background_token), + get_role_value(foreground_token), + ) + for label, background_token, foreground_token in group["items"] + ], + width=swatch_width, + height=swatch_height, + title=group.get("title"), + hint=group.get("hint"), + swatch_theme=swatch_theme, + swatch_dark_theme=swatch_dark_theme, + swatch_theme_mode=swatch_theme_mode, + selected_label=selected_label, + on_color_click=on_color_click, + ) + for group in active_tab["groups"] + ], + ] + + +def preview_role_block( + label: str, background: ft.ColorValue, foreground: ft.ColorValue +) -> ft.Container: + return ft.Container( + bgcolor=background, + padding=12, + border_radius=12, + content=ft.Text(label, color=foreground), + ) + + +def surface_sample_card( + label: str, + background: ft.ColorValue, + foreground: ft.ColorValue, + *, + outline_label: str, + outline_color: ft.ColorValue, + text_label: str, +) -> ft.Container: + subtitle = f"{outline_label}, {text_label}" if outline_label else text_label + return ft.Container( + width=300, + height=132, + bgcolor=background, + border_radius=16, + border=ft.Border.all(2, outline_color), + padding=16, + content=ft.Column( + spacing=8, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Text( + label, + color=foreground, + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.Text( + subtitle, + color=foreground, + size=13, + ), + ], + ), + ) + + +def inverse_surface_card() -> ft.Container: + return ft.Container( + width=300, + height=132, + bgcolor=ft.Colors.INVERSE_SURFACE, + border_radius=16, + padding=16, + content=ft.Column( + spacing=12, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Text( + "INVERSE_SURFACE", + color=ft.Colors.ON_INVERSE_SURFACE, + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.Text( + "On inverse surface, Inverse primary", + color=ft.Colors.ON_INVERSE_SURFACE, + size=13, + ), + ft.Container( + bgcolor=ft.Colors.INVERSE_PRIMARY, + border_radius=999, + padding=ft.Padding.symmetric(horizontal=16, vertical=8), + content=ft.Text( + "OK", + color=ft.Colors.ON_PRIMARY, + weight=ft.FontWeight.W_600, + ), + ), + ], + ), + ) + + +def noop(_): + return None + + +def build_preview_chip_row() -> ft.Row: + return ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + ft.Chip(label=ft.Text("Filter chip"), on_select=noop), + ft.Chip( + label=ft.Text("Assist chip"), + leading=ft.Icon(ft.Icons.MAP_SHARP), + on_click=noop, + ), + ft.Chip(label=ft.Text("Selected"), selected=True, on_select=noop), + ], + ) + + +def build_selected_chip_row() -> ft.Row: + return ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + ft.Chip(label=ft.Text("Filter chip"), on_select=noop), + ft.Chip(label=ft.Text("Selected"), selected=True, on_select=noop), + ], + ) + + +def build_primary_button_row() -> ft.Row: + return ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + ft.FilledButton("Filled button"), + ft.OutlinedButton("Outlined button"), + ft.TextButton("Text button"), + ft.Button("Button"), + ], + ) + + +def build_segmented_button() -> ft.SegmentedButton: + return ft.SegmentedButton( + selected=["grid"], + segments=[ + ft.Segment( + value="list", + icon=ft.Icon(ft.Icons.VIEW_LIST), + label=ft.Text("List"), + ), + ft.Segment( + value="grid", + icon=ft.Icon(ft.Icons.GRID_VIEW), + label=ft.Text("Grid"), + ), + ], + ) + + +def build_tonal_button() -> ft.FilledTonalButton: + return ft.FilledTonalButton("Filled tonal button") + + +def build_selection_row() -> ft.Row: + return ft.Row( + wrap=True, + spacing=16, + run_spacing=12, + controls=[ + ft.Switch(label="Use dark mode", value=True), + ft.Checkbox(label="Enable accents", value=True), + ], + ) + + +def build_error_examples() -> list[ft.Control]: + password_field = ft.TextField( + label="Password", + password=True, + can_reveal_password=True, + value="hunter2", + ) + password_field.error_text = "Incorrect password" + return [ + password_field, + ft.Text("Please correct the highlighted fields.", color=ft.Colors.ERROR), + ] + + +def build_all_preview_pagelet( + *, + preview_heading: str, + preview_body: str, + preview_time_text: ft.Text, + open_preview_time_picker, +) -> ft.Pagelet: + return ft.Pagelet( + height=760, + bgcolor=ft.Colors.SURFACE, + appbar=ft.AppBar( + leading=ft.Icon(ft.Icons.PALETTE), + title=ft.Row( + spacing=16, + controls=[ + ft.Text("Palette preview"), + ft.Container( + width=280, + height=40, + bgcolor=ft.Colors.SURFACE, + border_radius=999, + padding=ft.Padding.symmetric(horizontal=14), + content=ft.Row( + spacing=10, + controls=[ + ft.Icon( + ft.Icons.SEARCH, + size=18, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Text( + "Search palettes and roles", + size=13, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ), + ], + ), + bgcolor=ft.Colors.SURFACE_CONTAINER, + actions=[ + ft.IconButton(icon=ft.Icons.HELP_OUTLINE), + ft.IconButton(icon=ft.Icons.SETTINGS_OUTLINED), + ft.IconButton(icon=ft.Icons.MORE_VERT), + ], + ), + content=ft.Container( + padding=ft.Padding.only(top=12, bottom=12), + content=ft.Row( + expand=True, + spacing=12, + controls=[ + ft.NavigationRail( + selected_index=1, + bgcolor=ft.Colors.SURFACE_CONTAINER, + label_type=ft.NavigationRailLabelType.ALL, + min_width=76, + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.HOME_OUTLINED, + selected_icon=ft.Icons.HOME, + label="Home", + ), + ft.NavigationRailDestination( + icon=ft.Icons.PALETTE_OUTLINED, + selected_icon=ft.Icons.PALETTE, + label="Theme", + ), + ft.NavigationRailDestination( + icon=ft.Icons.SCHEDULE_OUTLINED, + selected_icon=ft.Icons.SCHEDULE, + label="Time", + ), + ], + ), + ft.Container( + width=220, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + border_radius=20, + padding=16, + content=ft.Column( + spacing=14, + controls=[ + ft.FilledTonalButton("New palette", icon=ft.Icons.ADD), + ft.Text( + "Recent palettes", + weight=ft.FontWeight.W_600, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Column( + spacing=8, + controls=[ + ft.Container( + bgcolor=ft.Colors.SECONDARY_CONTAINER, + border_radius=14, + padding=12, + content=ft.Row( + spacing=10, + controls=[ + ft.Icon( + ft.Icons.PALETTE, + color=ft.Colors.ON_SECONDARY_CONTAINER, + ), + ft.Text( + "Studio theme", + color=ft.Colors.ON_SECONDARY_CONTAINER, + ), + ], + ), + ), + ft.Row( + spacing=10, + controls=[ + ft.CircleAvatar( + content=ft.Text("A"), + bgcolor=ft.Colors.PRIMARY_CONTAINER, + color=ft.Colors.ON_PRIMARY_CONTAINER, + ), + ft.Column( + spacing=2, + controls=[ + ft.Text("Accent set"), + ft.Text( + "Primary and secondary", + size=12, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ], + ), + ft.Row( + spacing=10, + controls=[ + ft.CircleAvatar( + content=ft.Text("S"), + bgcolor=ft.Colors.TERTIARY_CONTAINER, + color=ft.Colors.ON_TERTIARY_CONTAINER, + ), + ft.Column( + spacing=2, + controls=[ + ft.Text("Surface study"), + ft.Text( + "Containers and outline", + size=12, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ], + ), + ft.Row( + spacing=10, + controls=[ + ft.CircleAvatar( + content=ft.Text("E"), + bgcolor=ft.Colors.ERROR_CONTAINER, + color=ft.Colors.ON_ERROR_CONTAINER, + ), + ft.Column( + spacing=2, + controls=[ + ft.Text("Errors and states"), + ft.Text( + "Validation colors", + size=12, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ], + ), + ], + ), + ], + ), + ), + ft.Container( + expand=2, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOWEST, + border_radius=20, + padding=18, + content=ft.Column( + spacing=14, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Column( + spacing=4, + controls=[ + ft.Text( + preview_heading, + theme_style=ft.TextThemeStyle.TITLE_LARGE, + ), + ft.Text( + "Theme collaboration space", + size=12, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + build_selected_chip_row(), + ], + ), + ft.Container( + bgcolor=ft.Colors.SURFACE, + border_radius=18, + padding=16, + content=ft.Column( + spacing=14, + controls=[ + ft.Row( + spacing=10, + controls=[ + ft.CircleAvatar( + content=ft.Text("P"), + bgcolor=ft.Colors.PRIMARY, + color=ft.Colors.ON_PRIMARY, + ), + ft.Column( + spacing=2, + controls=[ + ft.Text("Palette review"), + ft.Text( + "22 members", + size=12, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ], + ), + ft.Text(preview_body), + ft.Container( + bgcolor=ft.Colors.PRIMARY_CONTAINER, + border_radius=16, + padding=14, + content=ft.Column( + spacing=6, + controls=[ + ft.Text( + "Primary spotlight", + color=ft.Colors.ON_PRIMARY_CONTAINER, + weight=ft.FontWeight.W_600, + ), + ft.Text( + "Use this space to " + "compare strong accents " + "against calmer surfaces.", + color=ft.Colors.ON_PRIMARY_CONTAINER, + size=12, + ), + ], + ), + ), + ft.Row( + spacing=12, + controls=[ + ft.FilledButton("Apply"), + ft.FilledTonalButton("Share"), + ft.OutlinedButton("Inspect"), + ], + ), + ], + ), + ), + ft.Row( + wrap=True, + spacing=16, + run_spacing=12, + controls=[ + ft.Switch(label="Use dark mode", value=True), + ft.Checkbox(label="Enable accents", value=True), + ], + ), + *build_error_examples(), + ], + ), + ), + ft.Container( + width=240, + bgcolor=ft.Colors.SURFACE_CONTAINER, + border_radius=20, + padding=16, + content=ft.Column( + spacing=14, + controls=[ + ft.Text( + "Today", + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.Container( + bgcolor=ft.Colors.TERTIARY_CONTAINER, + border_radius=18, + padding=14, + content=ft.Column( + spacing=6, + controls=[ + ft.Text( + "Teaching workshop", + color=ft.Colors.ON_TERTIARY_CONTAINER, + weight=ft.FontWeight.W_600, + ), + ft.Text( + "9:00 AM - 12:00 PM", + color=ft.Colors.ON_TERTIARY_CONTAINER, + size=12, + ), + ], + ), + ), + ft.Container( + bgcolor=ft.Colors.SECONDARY_CONTAINER, + border_radius=18, + padding=14, + content=ft.Column( + spacing=6, + controls=[ + ft.Text( + "Lunch", + color=ft.Colors.ON_SECONDARY_CONTAINER, + weight=ft.FontWeight.W_600, + ), + ft.Text( + "1:00 PM - 2:00 PM", + color=ft.Colors.ON_SECONDARY_CONTAINER, + size=12, + ), + ], + ), + ), + ft.Container( + bgcolor=ft.Colors.ERROR_CONTAINER, + border_radius=18, + padding=14, + content=ft.Column( + spacing=6, + controls=[ + ft.Text( + "Review alerts", + color=ft.Colors.ON_ERROR_CONTAINER, + weight=ft.FontWeight.W_600, + ), + ft.Text( + "2 palette issues need attention", + color=ft.Colors.ON_ERROR_CONTAINER, + size=12, + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + bottom_appbar=ft.BottomAppBar( + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Row( + spacing=4, + controls=[ + ft.IconButton(icon=ft.Icons.MENU), + ft.IconButton(icon=ft.Icons.TUNE), + ], + ), + ft.Row( + spacing=4, + controls=[ + ft.IconButton(icon=ft.Icons.CHAT_BUBBLE_OUTLINE), + ft.IconButton(icon=ft.Icons.PERSON_OUTLINE), + ], + ), + ], + ) + ), + floating_action_button=ft.FloatingActionButton(icon=ft.Icons.ADD), + floating_action_button_location=ft.FloatingActionButtonLocation.END_FLOAT, + ) + + +def build_preview_tabs( + *, + preview_heading: str, + preview_body: str, + preview_time_text: ft.Text, + scaffold_bgcolor: ft.ColorValue, + selected_tab_index: int, + on_tab_change, + open_preview_time_picker, +) -> ft.Tabs: + return ft.Tabs( + selected_index=selected_tab_index, + on_change=on_tab_change, + length=4, + expand=True, + content=ft.Column( + expand=True, + spacing=12, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Text("Example", color=ft.Colors.ON_SURFACE), + ], + ), + ft.TabBar( + tabs=[ + ft.Tab(label="All"), + ft.Tab(label="Accent"), + ft.Tab(label="Surface"), + ft.Tab(label="Add-on"), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + padding=ft.Padding.only(top=4), + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + spacing=0, + controls=[ + build_all_preview_pagelet( + preview_heading=preview_heading, + preview_body=preview_body, + preview_time_text=preview_time_text, + open_preview_time_picker=open_preview_time_picker, + ), + ], + ), + ), + ft.Container( + padding=ft.Padding.only(top=4), + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + spacing=0, + controls=[ + showcase_section( + "Primary", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "PRIMARY", + ft.Colors.PRIMARY, + ft.Colors.ON_PRIMARY, + outline_label="", + outline_color=None, + text_label="On primary", + ), + surface_sample_card( + "PRIMARY_CONTAINER", + ft.Colors.PRIMARY_CONTAINER, + ft.Colors.ON_PRIMARY_CONTAINER, + outline_label="", + outline_color=None, + text_label="On primary container", + ), + ], + ), + build_primary_button_row(), + ft.FloatingActionButton(icon=ft.Icons.PALETTE), + ), + showcase_section( + "Secondary", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "SECONDARY", + ft.Colors.SECONDARY, + ft.Colors.ON_SECONDARY, + outline_label="", + outline_color=None, + text_label="On secondary", + ), + surface_sample_card( + "SECONDARY_CONTAINER", + ft.Colors.SECONDARY_CONTAINER, + ft.Colors.ON_SECONDARY_CONTAINER, + outline_label="", + outline_color=None, + text_label="On secondary container", + ), + ], + ), + build_tonal_button(), + build_preview_chip_row(), + build_segmented_button(), + ), + showcase_section( + "Tertiary", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "TERTIARY", + ft.Colors.TERTIARY, + ft.Colors.ON_TERTIARY, + outline_label="", + outline_color=None, + text_label="On tertiary", + ), + surface_sample_card( + "TERTIARY_CONTAINER", + ft.Colors.TERTIARY_CONTAINER, + ft.Colors.ON_TERTIARY_CONTAINER, + outline_label="", + outline_color=None, + text_label="On tertiary container", + ), + ], + ), + ), + showcase_section( + "Error", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "ERROR", + ft.Colors.ERROR, + ft.Colors.ON_ERROR, + outline_label="", + outline_color=None, + text_label="On error", + ), + surface_sample_card( + "ERROR_CONTAINER", + ft.Colors.ERROR_CONTAINER, + ft.Colors.ON_ERROR_CONTAINER, + outline_label="", + outline_color=None, + text_label="On error container", + ), + ], + ), + *build_error_examples(), + ), + ], + ), + ), + ft.Container( + padding=ft.Padding.only(top=4), + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + spacing=12, + controls=[ + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "SURFACE", + ft.Colors.SURFACE, + ft.Colors.ON_SURFACE, + outline_label="Outline", + outline_color=ft.Colors.OUTLINE, + text_label="On surface", + ), + surface_sample_card( + "SURFACE_CONTAINER", + ft.Colors.SURFACE_CONTAINER, + ft.Colors.ON_SURFACE_VARIANT, + outline_label="Outline variant", + outline_color=ft.Colors.OUTLINE_VARIANT, + text_label="On surface variant", + ), + surface_sample_card( + "SURFACE_CONTAINER_LOW", + ft.Colors.SURFACE_CONTAINER_LOW, + ft.Colors.ON_SURFACE, + outline_label="Outline", + outline_color=ft.Colors.OUTLINE, + text_label="On surface", + ), + surface_sample_card( + "SURFACE_CONTAINER_LOWEST", + ft.Colors.SURFACE_CONTAINER_LOWEST, + ft.Colors.ON_SURFACE_VARIANT, + outline_label="Outline variant", + outline_color=ft.Colors.OUTLINE_VARIANT, + text_label="On surface variant", + ), + surface_sample_card( + "SURFACE_CONTAINER_HIGH", + ft.Colors.SURFACE_CONTAINER_HIGH, + ft.Colors.ON_SURFACE, + outline_label="Outline", + outline_color=ft.Colors.OUTLINE, + text_label="On surface", + ), + surface_sample_card( + "SURFACE_CONTAINER_HIGHEST", + ft.Colors.SURFACE_CONTAINER_HIGHEST, + ft.Colors.ON_SURFACE_VARIANT, + outline_label="Outline variant", + outline_color=ft.Colors.OUTLINE_VARIANT, + text_label="On surface variant", + ), + ], + ), + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + ft.Container( + width=300, + height=132, + bgcolor=scaffold_bgcolor, + border_radius=16, + border=ft.Border.all( + 2, ft.Colors.OUTLINE_VARIANT + ), + padding=16, + content=ft.Column( + spacing=12, + controls=[ + ft.Text( + "SCAFFOLD_BGCOLOR", + color=ft.Colors.ON_SURFACE, + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.Text( + ( + "Outline variant, " + "On surface variant" + ), + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ), + inverse_surface_card(), + ], + ), + ], + ), + ), + ft.Container( + padding=ft.Padding.only(top=4), + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + spacing=0, + controls=[ + showcase_section( + "Primary fixed", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "PRIMARY_FIXED", + ft.Colors.PRIMARY_FIXED, + ft.Colors.ON_PRIMARY_FIXED, + outline_label="", + outline_color=None, + text_label="On primary fixed", + ), + surface_sample_card( + "PRIMARY_FIXED_DIM", + ft.Colors.PRIMARY_FIXED_DIM, + ft.Colors.ON_PRIMARY_FIXED_VARIANT, + outline_label="", + outline_color=None, + text_label=( + "On primary fixed variant" + ), + ), + ], + ), + ), + showcase_section( + "Secondary fixed", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "SECONDARY_FIXED", + ft.Colors.SECONDARY_FIXED, + ft.Colors.ON_SECONDARY_FIXED, + outline_label="", + outline_color=None, + text_label="On secondary fixed", + ), + surface_sample_card( + "SECONDARY_FIXED_DIM", + ft.Colors.SECONDARY_FIXED_DIM, + ft.Colors.ON_SECONDARY_FIXED_VARIANT, + outline_label="", + outline_color=None, + text_label=( + "On secondary fixed variant" + ), + ), + ], + ), + ), + showcase_section( + "Tertiary fixed", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "TERTIARY_FIXED", + ft.Colors.TERTIARY_FIXED, + ft.Colors.ON_TERTIARY_FIXED, + outline_label="", + outline_color=None, + text_label="On tertiary fixed", + ), + surface_sample_card( + "TERTIARY_FIXED_DIM", + ft.Colors.TERTIARY_FIXED_DIM, + ft.Colors.ON_TERTIARY_FIXED_VARIANT, + outline_label="", + outline_color=None, + text_label=( + "On tertiary fixed variant" + ), + ), + ], + ), + ), + showcase_section( + "Surface add-ons", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + surface_sample_card( + "SURFACE_DIM", + ft.Colors.SURFACE_DIM, + ft.Colors.ON_SURFACE, + outline_label="", + outline_color=None, + text_label="On surface", + ), + surface_sample_card( + "SURFACE_BRIGHT", + ft.Colors.SURFACE_BRIGHT, + ft.Colors.ON_SURFACE_VARIANT, + outline_label="", + outline_color=None, + text_label="On surface variant", + ), + ], + ), + ), + showcase_section( + "Effects", + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + controls=[ + ft.Container( + width=300, + height=132, + bgcolor=ft.Colors.SURFACE_CONTAINER, + border_radius=16, + shadow=ft.BoxShadow( + spread_radius=4, + blur_radius=28, + color=ft.Colors.SHADOW, + offset=ft.Offset(0, 12), + ), + padding=16, + content=ft.Column( + spacing=8, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Text( + "Container with Shadow", + color=ft.Colors.ON_SURFACE, + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.Text( + "Surface container, " + "Shadow", + color=ft.Colors.ON_SURFACE_VARIANT, + size=13, + ), + ], + ), + ), + ft.Container( + width=300, + height=132, + bgcolor=ft.Colors.SCRIM, + border_radius=16, + padding=16, + content=ft.Column( + spacing=8, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Text( + "SCRIM", + color=ft.Colors.ON_INVERSE_SURFACE, + theme_style=ft.TextThemeStyle.TITLE_MEDIUM, + ), + ft.Text( + "On inverse surface", + color=ft.Colors.ON_INVERSE_SURFACE, + size=13, + ), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ], + ), + ) diff --git a/sdk/python/examples/apps/palette_editor/pyproject.toml b/sdk/python/examples/apps/palette_editor/pyproject.toml new file mode 100644 index 0000000000..119de0ed3c --- /dev/null +++ b/sdk/python/examples/apps/palette_editor/pyproject.toml @@ -0,0 +1,43 @@ +[project] +name = "apps-palette-editor" +version = "1.0.0" +description = "Interactive editor for Material theme colors and role previews." +requires-python = ">=3.10" +keywords = ["apps", "theme", "material design", "color scheme", "palette"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Tools"] + +[tool.flet.metadata] +title = "Palette Editor" +controls = [ + "SafeArea", + "Container", + "Column", + "Row", + "Tabs", + "TabBar", + "IconButton", + "PopupMenuButton", + "TextField", + "AlertDialog", + "TimePicker", +] +layout_pattern = "dashboard" +complexity = "intermediate" +features = [ + "theme editing", + "color role preview", + "light and dark mode", + "palette import and export", +] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/active_links/main.py b/sdk/python/examples/apps/router/active_links/main.py new file mode 100644 index 0000000000..8b6e1d4e56 --- /dev/null +++ b/sdk/python/examples/apps/router/active_links/main.py @@ -0,0 +1,76 @@ +"""Active links — nav highlighting with is_route_active().""" + +import flet as ft + + +@ft.component +def Home(): + return ft.Text("Home page", size=24) + + +@ft.component +def Products(): + return ft.Text("Products page", size=24) + + +@ft.component +def Settings(): + return ft.Text("Settings page", size=24) + + +@ft.component +def NavLink(label, path): + """A navigation link that highlights when its path is active.""" + active = ft.is_route_active(path) + return ft.Container( + content=ft.Text( + label, + weight=ft.FontWeight.BOLD if active else ft.FontWeight.NORMAL, + color=ft.Colors.BLUE if active else ft.Colors.ON_SURFACE, + ), + bgcolor=ft.Colors.BLUE_50 if active else None, + padding=ft.Padding.symmetric(horizontal=16, vertical=8), + border_radius=8, + on_click=lambda: ft.context.page.navigate(path), + ) + + +@ft.component +def AppLayout(): + """Layout route — NavLink must be inside Router to use is_route_active().""" + outlet = ft.use_route_outlet() + return ft.Column( + [ + ft.Row( + [ + NavLink("Home", "/"), + NavLink("Products", "/products"), + NavLink("Settings", "/settings"), + ] + ), + ft.Divider(), + outlet, + ] + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Router( + [ + ft.Route( + component=AppLayout, + children=[ + ft.Route(index=True, component=Home), + ft.Route(path="products", component=Products), + ft.Route(path="settings", component=Settings), + ], + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/active_links/pyproject.toml b/sdk/python/examples/apps/router/active_links/pyproject.toml new file mode 100644 index 0000000000..04a0f1a608 --- /dev/null +++ b/sdk/python/examples/apps/router/active_links/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-active-links" +version = "1.0.0" +description = "Navigation link highlighting using is_route_active() with bold text and background color." +requires-python = ">=3.10" +keywords = ["router", "active", "navigation", "links", "highlight"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Active links" +controls = ["SafeArea", "Column", "Row", "Container", "Text", "Divider", "Router", "Route"] +layout_pattern = "app-shell" +complexity = "basic" +features = ["is_route_active", "active link styling", "use_route_outlet"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/app_drawer/README.md b/sdk/python/examples/apps/router/app_drawer/README.md new file mode 100644 index 0000000000..229664deac --- /dev/null +++ b/sdk/python/examples/apps/router/app_drawer/README.md @@ -0,0 +1,34 @@ +# App Settings Drawer + +Demonstrates a NavigationDrawer with deep-linkable tabs, driven by nested routes. + +## Routes + +- `/` — Home +- `/apps` — Apps list +- `/apps/:app_id` — App details (drawer closed) +- `/apps/:app_id/settings/general` — App details with drawer open on General tab +- `/apps/:app_id/settings/permissions` — App details with drawer open on Permissions tab + +## How it works + +The `:app_id` route has `outlet=True` and two child routes for the settings tabs. +`AppDetails` always renders as a single View. Inside it: + +- `use_route_outlet()` returns the matched tab component (or `None` if just `/apps/:app_id`) +- A `use_effect` watches whether the outlet is set and calls `page.open(drawer)` / + `page.close(drawer)` accordingly +- The drawer's `on_dismiss` navigates back to `/apps/:app_id` when the user swipes + the drawer away +- Tab buttons inside the drawer use `is_route_active(..., exact=True)` to highlight + the current tab and navigate between tabs +- The View's `route` is the same (`/apps/:app_id`) regardless of the active tab, + so Flutter's Navigator doesn't animate the View when switching tabs + +## View stack + +- `/` — 1 view (Home) +- `/apps` — 2 views (Home, AppsList) +- `/apps/2` — 3 views (Home, AppsList, AppDetails); back button to AppsList +- `/apps/2/settings/general` — same 3 views; drawer slides open on top +- `/apps/2/settings/permissions` — same 3 views; drawer stays open, tab content swaps diff --git a/sdk/python/examples/apps/router/app_drawer/main.py b/sdk/python/examples/apps/router/app_drawer/main.py new file mode 100644 index 0000000000..4dd279b7cc --- /dev/null +++ b/sdk/python/examples/apps/router/app_drawer/main.py @@ -0,0 +1,227 @@ +import asyncio + +import flet as ft + +APPS = { + "1": "Acme Web", + "2": "Beta API", + "3": "Gamma Mobile", +} + + +@ft.component +def Home(): + return ft.View( + route="/", + can_pop=False, + appbar=ft.AppBar(title=ft.Text("Home")), + controls=[ + ft.Text("Welcome", size=24), + ft.Button( + "Browse Apps", + on_click=lambda: ft.context.page.navigate("/apps"), + ), + ], + ) + + +@ft.component +def AppsList(): + return ft.View( + route="/apps", + appbar=ft.AppBar(title=ft.Text("Apps")), + controls=[ + ft.Text("Your apps", size=24), + *[ + ft.Button( + name, + data=app_id, + on_click=lambda e: ft.context.page.navigate( + f"/apps/{e.control.data}" + ), + ) + for app_id, name in APPS.items() + ], + ], + ) + + +@ft.component +def GeneralTab(): + params = ft.use_route_params() + return ft.Column( + [ + ft.Text("General Settings", size=20), + ft.TextField(label="App name", value=APPS.get(params["app_id"], "")), + ft.Switch(label="Public"), + ft.Switch(label="Maintenance mode"), + ] + ) + + +@ft.component +def PermissionsTab(): + return ft.Column( + [ + ft.Text("Permissions", size=20), + ft.Switch(label="Read access for guests"), + ft.Switch(label="Allow API tokens"), + ft.Switch(label="Require 2FA for admins"), + ] + ) + + +@ft.component +def AppDetails(): + """App details view with a settings drawer. + + The drawer's open state and selected tab are derived from the URL: + - /apps/:app_id — drawer closed + - /apps/:app_id/settings/general — drawer open, General tab + - /apps/:app_id/settings/permissions — drawer open, Permissions tab + """ + params = ft.use_route_params() + app_id = params["app_id"] + name = APPS.get(app_id, "Unknown") + + # If a settings child route matched, this is non-None — the drawer + # should be open and `outlet` is the rendered tab content. + outlet = ft.use_route_outlet() + drawer_open = outlet is not None + + page = ft.context.page + + def on_dismiss(e): + # User swiped the drawer away — sync URL back to /apps/:app_id + page.navigate(f"/apps/{app_id}") + + location = ft.use_route_location() + tab_routes = [ + f"/apps/{app_id}/settings/general", + f"/apps/{app_id}/settings/permissions", + ] + # Pure string comparison — don't call is_route_active() here because + # it uses a context hook and varying call counts break hook ordering. + route_tab = next( + (i for i, r in enumerate(tab_routes) if location == r), + 0, + ) + selected_tab, set_selected_tab = ft.use_state(route_tab) + + def sync_tab(): + if route_tab != selected_tab: + set_selected_tab(route_tab) + + ft.use_effect(sync_tab, dependencies=[location]) + + def on_tab_change(e): + idx = e.control.selected_index + # Skip programmatic echoes: Tabs fires on_change after its own + # animation completes, including when we set selected_index via + # state. If idx matches our current state, it's not a user tap. + if idx == selected_tab: + return + set_selected_tab(idx) + page.navigate(tab_routes[idx]) + + drawer = ft.NavigationDrawer( + on_dismiss=on_dismiss, + controls=[ + ft.Container( + content=ft.Text("App settings", size=22, weight=ft.FontWeight.BOLD), + padding=20, + ), + ft.Tabs( + length=2, + selected_index=selected_tab, + on_change=on_tab_change, + content=ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label="General"), + ft.Tab(label="Permissions"), + ], + ), + ), + ft.Container(content=outlet, padding=20, expand=True), + ], + ) + + # Imperatively open/close the drawer when the route changes. + def sync_drawer(): + if drawer_open: + asyncio.create_task(page.show_end_drawer()) + else: + asyncio.create_task(page.close_end_drawer()) + + ft.use_effect(sync_drawer, dependencies=[drawer_open]) + + return ft.View( + route=f"/apps/{app_id}", + appbar=ft.AppBar( + title=ft.Text(name), + actions=[ + ft.IconButton( + icon=ft.Icons.SETTINGS, + tooltip="Settings", + on_click=lambda: page.navigate(f"/apps/{app_id}/settings/general"), + ), + ], + ), + end_drawer=drawer, + controls=[ + ft.Text(name, size=28, weight=ft.FontWeight.BOLD), + ft.Text(f"App ID: {app_id}", size=16), + ft.Text("Welcome to the app dashboard.", size=14), + ft.Divider(height=30), + ft.Button( + "Open Settings", + icon=ft.Icons.SETTINGS, + on_click=lambda: page.navigate(f"/apps/{app_id}/settings/general"), + ), + ft.Button( + "Direct link to Permissions", + icon=ft.Icons.SECURITY, + on_click=lambda: page.navigate(f"/apps/{app_id}/settings/permissions"), + ), + ], + ) + + +@ft.component +def App(): + return ft.Router( + [ + ft.Route( + component=Home, + children=[ + ft.Route( + path="apps", + component=AppsList, + children=[ + ft.Route( + path=":app_id", + component=AppDetails, + outlet=True, + children=[ + ft.Route( + path="settings/general", + component=GeneralTab, + ), + ft.Route( + path="settings/permissions", + component=PermissionsTab, + ), + ], + ), + ], + ), + ], + ), + ], + manage_views=True, + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(App)) diff --git a/sdk/python/examples/apps/router/app_drawer/pyproject.toml b/sdk/python/examples/apps/router/app_drawer/pyproject.toml new file mode 100644 index 0000000000..f615db7816 --- /dev/null +++ b/sdk/python/examples/apps/router/app_drawer/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-app-drawer" +version = "1.0.0" +description = "Apps list, app details, and a deep-linkable settings NavigationDrawer driven by nested routes." +requires-python = ">=3.10" +keywords = ["router", "drawer", "navigation", "outlet", "manage_views", "tabs"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "App settings drawer" +controls = ["View", "AppBar", "NavigationDrawer", "Column", "Row", "Container", "Button", "TextField", "Switch", "Text", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "intermediate" +features = ["manage_views", "outlet", "nested routes", "NavigationDrawer", "deep linking", "is_route_active"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/auth_dialog/main.py b/sdk/python/examples/apps/router/auth_dialog/main.py new file mode 100644 index 0000000000..5fd4f3d7ed --- /dev/null +++ b/sdk/python/examples/apps/router/auth_dialog/main.py @@ -0,0 +1,98 @@ +"""Auth with AlertDialog — shows a modal login dialog when not authenticated.""" + +from dataclasses import dataclass + +import flet as ft + + +@ft.observable +@dataclass +class AuthState: + is_authenticated: bool = False + username: str = "" + + def login(self, username): + self.username = username + self.is_authenticated = True + + def logout(self): + self.username = "" + self.is_authenticated = False + + +AuthContext: ft.ContextProvider[AuthState | None] = ft.create_context(None) + + +@ft.component +def Home(): + auth = ft.use_context(AuthContext) + if auth is None: + return ft.ProgressRing() + return ft.Column( + [ + ft.Text(f"Home — Hello, {auth.username}!", size=24), + ft.Button("Logout", on_click=auth.logout), + ] + ) + + +@ft.component +def AuthGuard(): + """Layout route that shows a modal AlertDialog when not authenticated.""" + auth = ft.use_context(AuthContext) + outlet = ft.use_route_outlet() + username_ref = ft.use_ref(None) + page = ft.context.page + + def do_login(): + if auth is not None: + auth.login(username_ref.current.value or "user") + page.pop_dialog() + + def show_login(): + page.show_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Please log in"), + content=ft.TextField( + label="Username", + value="admin", + ref=username_ref, + ), + actions=[ + ft.TextButton("Login", on_click=do_login), + ], + ) + ) + + ft.use_effect( + lambda: show_login() if auth is None or not auth.is_authenticated else None, + [auth.is_authenticated if auth else None], + ) + + return outlet + + +@ft.component +def App(): + auth, _ = ft.use_state(AuthState) + + return ft.SafeArea( + content=AuthContext( + auth, + lambda: ft.Router( + [ + ft.Route( + component=AuthGuard, + children=[ + ft.Route(index=True, component=Home), + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/auth_dialog/pyproject.toml b/sdk/python/examples/apps/router/auth_dialog/pyproject.toml new file mode 100644 index 0000000000..c8191e7a41 --- /dev/null +++ b/sdk/python/examples/apps/router/auth_dialog/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-auth-dialog" +version = "1.0.0" +description = "Route protection with a modal AlertDialog login prompt instead of a redirect." +requires-python = ">=3.10" +keywords = ["router", "auth", "dialog", "modal", "guard"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Auth dialog" +controls = ["SafeArea", "Column", "Button", "Text", "TextField", "AlertDialog", "TextButton", "ProgressRing", "Router", "Route"] +layout_pattern = "auth-guard" +complexity = "intermediate" +features = ["auth guard", "modal dialog", "context", "observable state", "use_effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/auth_page/main.py b/sdk/python/examples/apps/router/auth_page/main.py new file mode 100644 index 0000000000..9161cc62b7 --- /dev/null +++ b/sdk/python/examples/apps/router/auth_page/main.py @@ -0,0 +1,100 @@ +"""Auth with page redirect — guards protected routes behind a login page.""" + +from dataclasses import dataclass + +import flet as ft + + +@ft.observable +@dataclass +class AuthState: + is_authenticated: bool = False + username: str = "" + + def login(self, username): + self.username = username + self.is_authenticated = True + + def logout(self): + self.username = "" + self.is_authenticated = False + + +AuthContext: ft.ContextProvider[AuthState | None] = ft.create_context(None) + + +@ft.component +def LoginPage(): + auth = ft.use_context(AuthContext) + username_ref = ft.use_ref("") + + def handle_login(): + auth.login(username_ref.current.value or "user") + ft.context.page.navigate("/dashboard") + + return ft.Column( + [ + ft.Text("Login", size=24), + ft.TextField(label="Username", value="admin", ref=username_ref), + ft.Button("Sign In", on_click=handle_login), + ] + ) + + +@ft.component +def Dashboard(): + auth = ft.use_context(AuthContext) + if auth is None: + return ft.ProgressRing() + return ft.Column( + [ + ft.Text(f"Dashboard — Welcome, {auth.username}!", size=24), + ft.Button( + "Logout", + on_click=lambda: ( + auth.logout(), + ft.context.page.navigate("/login"), + ), + ), + ] + ) + + +@ft.component +def ProtectedRoute(): + """Layout route that redirects to /login when not authenticated.""" + auth = ft.use_context(AuthContext) + outlet = ft.use_route_outlet() + + if auth is None or not auth.is_authenticated: + ft.use_effect(lambda: ft.context.page.navigate("/login"), []) + return ft.Text("Redirecting to login...") + + return outlet + + +@ft.component +def App(): + auth, _ = ft.use_state(AuthState) + + return ft.SafeArea( + content=AuthContext( + auth, + lambda: ft.Router( + [ + ft.Route(path="login", component=LoginPage), + ft.Route( + component=ProtectedRoute, + children=[ + ft.Route(index=True, component=Dashboard), + ft.Route(path="dashboard", component=Dashboard), + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/auth_page/pyproject.toml b/sdk/python/examples/apps/router/auth_page/pyproject.toml new file mode 100644 index 0000000000..6a5c8f9381 --- /dev/null +++ b/sdk/python/examples/apps/router/auth_page/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-auth-page" +version = "1.0.0" +description = "Route protection using a dedicated login page that redirects unauthenticated users." +requires-python = ">=3.10" +keywords = ["router", "auth", "login", "redirect", "guard"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Auth page redirect" +controls = ["SafeArea", "Column", "Button", "Text", "TextField", "ProgressRing", "Router", "Route"] +layout_pattern = "auth-guard" +complexity = "intermediate" +features = ["auth guard", "route redirect", "context", "observable state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/basic/main.py b/sdk/python/examples/apps/router/basic/main.py new file mode 100644 index 0000000000..11c7162e86 --- /dev/null +++ b/sdk/python/examples/apps/router/basic/main.py @@ -0,0 +1,45 @@ +"""Basic Router — simplest example with flat routes.""" + +import flet as ft + + +@ft.component +def Home(): + return ft.Text("Home page", size=24) + + +@ft.component +def About(): + return ft.Text("About page", size=24) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Column( + [ + ft.Row( + [ + ft.Button( + "Home", + on_click=lambda: ft.context.page.navigate("/"), + ), + ft.Button( + "About", + on_click=lambda: ft.context.page.navigate("/about"), + ), + ] + ), + ft.Router( + [ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ] + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/basic/pyproject.toml b/sdk/python/examples/apps/router/basic/pyproject.toml new file mode 100644 index 0000000000..608eb54d0a --- /dev/null +++ b/sdk/python/examples/apps/router/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-basic" +version = "1.0.0" +description = "Simplest Router example with two flat routes and navigation buttons." +requires-python = ">=3.10" +keywords = ["router", "routes", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Basic routing" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "basic" +features = ["flat routes", "navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/dynamic_segments/main.py b/sdk/python/examples/apps/router/dynamic_segments/main.py new file mode 100644 index 0000000000..31a83de7cc --- /dev/null +++ b/sdk/python/examples/apps/router/dynamic_segments/main.py @@ -0,0 +1,78 @@ +"""Dynamic segments — :param paths with use_route_params().""" + +import flet as ft + + +@ft.component +def UserProfile(): + params = ft.use_route_params() + return ft.Column( + [ + ft.Text(f"User: {params['userId']}", size=24), + ft.Text(f"All params: {params}"), + ft.Button( + "View post #10", + on_click=lambda: ft.context.page.navigate( + f"/users/{params['userId']}/posts/10" + ), + ), + ft.Button( + "Back to users", + on_click=lambda: ft.context.page.navigate("/"), + ), + ] + ) + + +@ft.component +def UserPost(): + params = ft.use_route_params() + return ft.Column( + [ + ft.Text(f"User: {params['userId']}, Post: {params['postId']}", size=24), + ft.Text(f"All params: {params}"), + ft.Button( + "Back to user", + on_click=lambda: ft.context.page.navigate(f"/users/{params['userId']}"), + ), + ] + ) + + +@ft.component +def UserList(): + return ft.Column( + [ + ft.Text("Users", size=24), + ft.Button( + "User alice", + on_click=lambda: ft.context.page.navigate("/users/alice"), + ), + ft.Button( + "User bob", + on_click=lambda: ft.context.page.navigate("/users/bob"), + ), + ] + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Router( + [ + ft.Route(index=True, component=UserList), + ft.Route( + path="users/:userId", + children=[ + ft.Route(index=True, component=UserProfile), + ft.Route(path="posts/:postId", component=UserPost), + ], + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/dynamic_segments/pyproject.toml b/sdk/python/examples/apps/router/dynamic_segments/pyproject.toml new file mode 100644 index 0000000000..fd53fdd199 --- /dev/null +++ b/sdk/python/examples/apps/router/dynamic_segments/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-dynamic-segments" +version = "1.0.0" +description = "Dynamic route segments with use_route_params() to extract URL parameters like :userId and :postId." +requires-python = ">=3.10" +keywords = ["router", "dynamic", "params", "segments"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Dynamic segments" +controls = ["SafeArea", "Column", "Button", "Text", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "basic" +features = ["dynamic segments", "use_route_params", "nested params"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/featured/main.py b/sdk/python/examples/apps/router/featured/main.py new file mode 100644 index 0000000000..cd8dd8330c --- /dev/null +++ b/sdk/python/examples/apps/router/featured/main.py @@ -0,0 +1,349 @@ +"""Featured Router example — layout, nav, nested routes, params, loaders, auth.""" + +from dataclasses import dataclass + +import flet as ft + +# --------------------------------------------------------------------------- +# Auth context +# --------------------------------------------------------------------------- + + +@ft.observable +@dataclass +class AuthState: + is_authenticated: bool = False + username: str = "" + is_admin: bool = False + + def login(self, username, admin=False): + self.username = username + self.is_authenticated = True + self.is_admin = admin + + def logout(self): + self.username = "" + self.is_authenticated = False + self.is_admin = False + + +AuthContext: ft.ContextProvider[AuthState | None] = ft.create_context(None) + + +# --------------------------------------------------------------------------- +# Data loaders +# --------------------------------------------------------------------------- + + +def home_loader(params): + return {"greeting": "Welcome to the Router Demo!", "featured_count": 3} + + +def projects_loader(params): + return [ + {"id": 1, "name": "Flet", "status": "Active"}, + {"id": 2, "name": "Flutter", "status": "Active"}, + {"id": 3, "name": "FastAPI", "status": "Maintenance"}, + ] + + +def project_detail_loader(params): + projects = { + "1": {"id": 1, "name": "Flet", "description": "Build apps in Python"}, + "2": {"id": 2, "name": "Flutter", "description": "UI toolkit by Google"}, + "3": {"id": 3, "name": "FastAPI", "description": "Modern Python web framework"}, + } + return projects.get(params.get("projectId"), {"name": "Unknown", "description": ""}) + + +def settings_loader(params): + return {"sections": ["Profile", "Security", "Notifications"]} + + +# --------------------------------------------------------------------------- +# Auth components +# --------------------------------------------------------------------------- + + +@ft.component +def LoginPage(): + auth = ft.use_context(AuthContext) + username_ref = ft.use_ref(None) + + def handle_login(): + auth.login(username_ref.current.value or "user") + ft.context.page.navigate("/") + + def handle_admin_login(): + auth.login(username_ref.current.value or "admin", admin=True) + ft.context.page.navigate("/") + + return ft.Column( + [ + ft.Text("Sign In", size=28), + ft.TextField(label="Username", value="admin", ref=username_ref), + ft.Row( + [ + ft.Button("Login", on_click=handle_login), + ft.Button("Login as Admin", on_click=handle_admin_login), + ] + ), + ], + width=300, + ) + + +@ft.component +def ProtectedRoute(): + auth = ft.use_context(AuthContext) + outlet = ft.use_route_outlet() + + if not auth.is_authenticated: + ft.context.page.navigate("/login") + return ft.ProgressRing() + + return outlet + + +# --------------------------------------------------------------------------- +# Navigation +# --------------------------------------------------------------------------- + + +@ft.component +def NavLink(label, path): + active = ft.is_route_active(path) + return ft.Container( + content=ft.Text( + label, + weight=ft.FontWeight.BOLD if active else ft.FontWeight.NORMAL, + color=ft.Colors.PRIMARY if active else ft.Colors.ON_SURFACE, + ), + bgcolor=ft.Colors.PRIMARY_CONTAINER if active else None, + padding=ft.Padding.symmetric(horizontal=16, vertical=8), + border_radius=8, + on_click=lambda: ft.context.page.navigate(path), + ) + + +@ft.component +def AppLayout(): + auth = ft.use_context(AuthContext) + outlet = ft.use_route_outlet() + + if auth is None: + return ft.ProgressRing() + + return ft.Column( + [ + # Header + ft.Container( + content=ft.Row( + [ + ft.Text("Router Demo", size=20, weight=ft.FontWeight.BOLD), + NavLink("Home", "/"), + NavLink("Projects", "/projects"), + NavLink("Settings", "/settings"), + ft.Text(f"Hi, {auth.username}"), + ft.IconButton( + ft.Icons.LOGOUT, + on_click=lambda: ( + auth.logout(), + ft.context.page.navigate("/login"), + ), + ), + ], + ), + padding=10, + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Divider(height=1), + # Content + ft.Container(content=outlet, padding=20), + ], + ) + + +# --------------------------------------------------------------------------- +# Page components +# --------------------------------------------------------------------------- + + +@ft.component +def Home(): + data = ft.use_route_loader_data() + return ft.Column( + [ + ft.Text(data["greeting"], size=24), + ft.Text(f"{data['featured_count']} featured projects available"), + ft.Button( + "Browse projects", + on_click=lambda: ft.context.page.navigate("/projects"), + ), + ] + ) + + +@ft.component +def ProjectsList(): + data = ft.use_route_loader_data() + return ft.Column( + [ + ft.Text("Projects", size=24), + *[ + ft.ListTile( + title=ft.Text(p["name"]), + subtitle=ft.Text(p["status"]), + on_click=lambda _, pid=p["id"]: ft.context.page.navigate( + f"/projects/{pid}" + ), + ) + for p in data + ], + ] + ) + + +@ft.component +def ProjectDetails(): + data = ft.use_route_loader_data() + params = ft.use_route_params() + location = ft.use_route_location() + + return ft.Column( + [ + ft.Text(data["name"], size=24), + ft.Text(data["description"]), + ft.Text(f"Project ID: {params['projectId']}", italic=True), + ft.Text(f"Location: {location}", italic=True, size=12), + ft.Button( + "Back to projects", + on_click=lambda: ft.context.page.navigate("/projects"), + ), + ] + ) + + +@ft.component +def ProjectsLayout(): + outlet = ft.use_route_outlet() + return ft.Column( + [ + ft.Container( + content=ft.Text( + "PROJECTS", + weight=ft.FontWeight.BOLD, + color=ft.Colors.ON_SECONDARY_CONTAINER, + ), + bgcolor=ft.Colors.SECONDARY_CONTAINER, + padding=ft.Padding.symmetric(horizontal=12, vertical=4), + border_radius=4, + ), + outlet, + ] + ) + + +@ft.component +def SettingsHome(): + data = ft.use_route_loader_data() + return ft.Column( + [ + ft.Text("Settings", size=24), + ft.Text("Available sections:"), + *[ + ft.ListTile( + title=ft.Text(section), + on_click=lambda _, s=section: ft.context.page.navigate( + f"/settings/{s.lower()}" + ), + ) + for section in data["sections"] + ], + ] + ) + + +@ft.component +def SettingsSection(): + params = ft.use_route_params() + return ft.Column( + [ + ft.Text(f"{params['section'].title()} Settings", size=24), + ft.Text(f"Configure your {params['section']} preferences here."), + ft.Button( + "Back to settings", + on_click=lambda: ft.context.page.navigate("/settings"), + ), + ] + ) + + +# --------------------------------------------------------------------------- +# App +# --------------------------------------------------------------------------- + + +@ft.component +def App(): + auth, _ = ft.use_state(AuthState) + + return ft.SafeArea( + content=AuthContext( + auth, + lambda: ft.Router( + [ + ft.Route(path="login", component=LoginPage), + ft.Route( + component=ProtectedRoute, + children=[ + ft.Route( + component=AppLayout, + children=[ + ft.Route( + index=True, + component=Home, + loader=home_loader, + ), + ft.Route( + path="projects", + component=ProjectsLayout, + children=[ + ft.Route( + index=True, + component=ProjectsList, + loader=projects_loader, + ), + ft.Route( + path=":projectId", + component=ProjectDetails, + loader=project_detail_loader, + ), + ], + ), + ft.Route( + path="settings", + children=[ + ft.Route( + index=True, + component=SettingsHome, + loader=settings_loader, + ), + ft.Route( + path=":section", + component=SettingsSection, + ), + ], + ), + ], + ), + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/featured/pyproject.toml b/sdk/python/examples/apps/router/featured/pyproject.toml new file mode 100644 index 0000000000..1723d616a7 --- /dev/null +++ b/sdk/python/examples/apps/router/featured/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-featured" +version = "1.0.0" +description = "Full-featured Router app combining layout, nav, nested routes, params, loaders, and auth." +requires-python = ">=3.10" +keywords = ["router", "layout", "auth", "loaders", "nested", "params", "featured"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router", "Featured"] + +[tool.flet.metadata] +title = "Router featured app (declarative)" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "Text", "TextField", "IconButton", "ListTile", "Divider", "ProgressRing", "Router", "Route"] +layout_pattern = "app-shell" +complexity = "advanced" +features = ["nested routes", "layout outlet", "auth guard", "route loaders", "active links", "dynamic segments", "context", "observable state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/featured_views/README.md b/sdk/python/examples/apps/router/featured_views/README.md new file mode 100644 index 0000000000..c3fd43fc01 --- /dev/null +++ b/sdk/python/examples/apps/router/featured_views/README.md @@ -0,0 +1,18 @@ +# Full App with Managed Views and NavigationRail + +Demonstrates a complete app structure with `manage_views=True`, NavigationRail, and multiple layout patterns. + +## Structure + +- **RootLayout** — pathless `outlet=True` layout with NavigationRail. Returns a View with fixed `route="/"` to avoid transition animation between top-level pages. +- **Home** — simple content, rendered in RootLayout's outlet. +- **Projects** — stacked views. List → Details pushes a new view (back button works). Components return regular controls; RootLayout provides the View. +- **Settings** — tabbed layout using `outlet=True`. General/Account are sibling routes under SettingsLayout. Switching tabs swaps outlet content within the same view (no transition). + +## View Stack + +- `/` → 1 view: RootLayout(Home) +- `/projects` → 1 view: RootLayout(ProjectsList) — nav rail switches, no animation +- `/projects/1` → 2 views: RootLayout(ProjectsList), RootLayout(ProjectDetails) — slide transition, back button +- `/settings/general` → 1 view: RootLayout(SettingsLayout(General)) — nav rail switches +- `/settings/account` → 1 view: RootLayout(SettingsLayout(Account)) — tab swap, no animation diff --git a/sdk/python/examples/apps/router/featured_views/main.py b/sdk/python/examples/apps/router/featured_views/main.py new file mode 100644 index 0000000000..a62443be34 --- /dev/null +++ b/sdk/python/examples/apps/router/featured_views/main.py @@ -0,0 +1,225 @@ +import flet as ft + +# --------------------------------------------------------------------------- +# Home +# --------------------------------------------------------------------------- + + +@ft.component +def HomeContent(): + return ft.Column( + [ + ft.Text("Home", size=28, weight=ft.FontWeight.BOLD), + ft.Text("Welcome to the app!", size=16), + ] + ) + + +# --------------------------------------------------------------------------- +# Projects +# --------------------------------------------------------------------------- + +PROJECTS = { + "1": "Landing Page Redesign", + "2": "Mobile App v2", + "3": "API Migration", +} + + +@ft.component +def ProjectsList(): + return ft.Column( + [ + ft.Text("All Projects", size=24), + *[ + ft.Button( + name, + on_click=lambda _, pid=pid: ft.context.page.navigate( + f"/projects/{pid}" + ), + ) + for pid, name in PROJECTS.items() + ], + ] + ) + + +@ft.component +def ProjectDetails(): + params = ft.use_route_params() + pid = params.get("pid", "?") + name = PROJECTS.get(pid, "Unknown") + return ft.Column( + [ + ft.Text(name, size=24, weight=ft.FontWeight.BOLD), + ft.Text(f"Project ID: {pid}", size=16), + ft.Text( + "This is where project details, tasks, and team info would go.", + size=14, + ), + ] + ) + + +# --------------------------------------------------------------------------- +# Settings +# --------------------------------------------------------------------------- + + +@ft.component +def GeneralSettings(): + return ft.Column( + [ + ft.Text("General Settings", size=24), + ft.Switch(label="Dark mode"), + ft.Switch(label="Notifications"), + ft.Switch(label="Auto-save"), + ] + ) + + +@ft.component +def AccountSettings(): + return ft.Column( + [ + ft.Text("Account Settings", size=24), + ft.TextField(label="Display name", value="Feodor"), + ft.TextField(label="Email", value="feodor@example.com"), + ft.Button("Save changes"), + ] + ) + + +@ft.component +def SettingsLayout(): + """Tab navigation for settings — returns controls, not a View.""" + outlet = ft.use_route_outlet() + return ft.Column( + [ + ft.Text("Settings", size=28, weight=ft.FontWeight.BOLD), + ft.Row( + [ + ft.Button( + "General", + style=ft.ButtonStyle( + bgcolor=ft.Colors.PRIMARY_CONTAINER + if ft.is_route_active("/settings/general", exact=True) + else None, + ), + on_click=lambda: ft.context.page.navigate("/settings/general"), + ), + ft.Button( + "Account", + style=ft.ButtonStyle( + bgcolor=ft.Colors.PRIMARY_CONTAINER + if ft.is_route_active("/settings/account", exact=True) + else None, + ), + on_click=lambda: ft.context.page.navigate("/settings/account"), + ), + ], + ), + ft.Divider(), + ft.Container(content=outlet, expand=True), + ], + expand=True, + ) + + +# --------------------------------------------------------------------------- +# Root layout with NavigationRail +# --------------------------------------------------------------------------- + +NAV_ROUTES = ["/", "/projects", "/settings/general"] + + +@ft.component +def RootLayout(): + """Root layout — returns a View with NavigationRail + outlet.""" + outlet = ft.use_route_outlet() + + selected = 0 + if ft.is_route_active("/projects"): + selected = 1 + elif ft.is_route_active("/settings"): + selected = 2 + + def on_nav_change(e): + ft.context.page.navigate(NAV_ROUTES[e.control.selected_index]) + + return ft.View( + route="/", # fixed key — no transition animation between top-level pages + can_pop=False, + controls=[ + ft.Row( + [ + ft.NavigationRail( + selected_index=selected, + label_type=ft.NavigationRailLabelType.ALL, + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.HOME_OUTLINED, + selected_icon=ft.Icons.HOME, + label="Home", + ), + ft.NavigationRailDestination( + icon=ft.Icons.FOLDER_OUTLINED, + selected_icon=ft.Icons.FOLDER, + label="Projects", + ), + ft.NavigationRailDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + selected_icon=ft.Icons.SETTINGS, + label="Settings", + ), + ], + on_change=on_nav_change, + ), + ft.VerticalDivider(width=1), + ft.Container(content=outlet, expand=True, padding=20), + ], + expand=True, + ), + ], + ) + + +# --------------------------------------------------------------------------- +# App +# --------------------------------------------------------------------------- + + +@ft.component +def App(): + return ft.Router( + [ + ft.Route( + component=RootLayout, + outlet=True, + children=[ + ft.Route(index=True, component=HomeContent), + ft.Route( + path="projects", + component=ProjectsList, + children=[ + ft.Route(path=":pid", component=ProjectDetails), + ], + ), + ft.Route( + path="settings", + component=SettingsLayout, + outlet=True, + children=[ + ft.Route(path="general", component=GeneralSettings), + ft.Route(path="account", component=AccountSettings), + ], + ), + ], + ), + ], + manage_views=True, + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(App)) diff --git a/sdk/python/examples/apps/router/featured_views/pyproject.toml b/sdk/python/examples/apps/router/featured_views/pyproject.toml new file mode 100644 index 0000000000..59f4737c11 --- /dev/null +++ b/sdk/python/examples/apps/router/featured_views/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-featured-views" +version = "1.0.0" +description = "Full app with managed views: Home, Projects (list/details), Settings (tabs) with shared layouts and back navigation." +requires-python = ">=3.10" +keywords = ["router", "views", "manage_views", "outlet", "layout", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Featured views" +controls = ["View", "AppBar", "Column", "Row", "Container", "Button", "Switch", "TextField", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "intermediate" +features = ["manage_views", "outlet", "nested routes", "view stack", "back navigation", "tabs", "is_route_active"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/index_routes/main.py b/sdk/python/examples/apps/router/index_routes/main.py new file mode 100644 index 0000000000..f3bd5362bc --- /dev/null +++ b/sdk/python/examples/apps/router/index_routes/main.py @@ -0,0 +1,92 @@ +"""Index routes — default child routes with index=True.""" + +import flet as ft + + +@ft.component +def Dashboard(): + return ft.Text("Dashboard (index route for /)", size=24) + + +@ft.component +def SettingsHome(): + return ft.Text("Settings Home (index route for /settings)", size=20) + + +@ft.component +def ProfileSettings(): + return ft.Text("Profile Settings", size=20) + + +@ft.component +def SecuritySettings(): + return ft.Text("Security Settings", size=20) + + +@ft.component +def SettingsLayout(): + outlet = ft.use_route_outlet() + return ft.Column( + [ + ft.Text("Settings", size=24), + ft.Row( + [ + ft.Button( + "General", + on_click=lambda: ft.context.page.navigate("/settings"), + ), + ft.Button( + "Profile", + on_click=lambda: ft.context.page.navigate("/settings/profile"), + ), + ft.Button( + "Security", + on_click=lambda: ft.context.page.navigate("/settings/security"), + ), + ] + ), + ft.Divider(), + outlet, + ] + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Column( + [ + ft.Row( + [ + ft.Button( + "Home", + on_click=lambda: ft.context.page.navigate("/"), + ), + ft.Button( + "Settings", + on_click=lambda: ft.context.page.navigate("/settings"), + ), + ] + ), + ft.Divider(), + ft.Router( + [ + ft.Route(index=True, component=Dashboard), + ft.Route( + path="settings", + component=SettingsLayout, + children=[ + ft.Route(index=True, component=SettingsHome), + ft.Route(path="profile", component=ProfileSettings), + ft.Route(path="security", component=SecuritySettings), + ], + ), + ] + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/index_routes/pyproject.toml b/sdk/python/examples/apps/router/index_routes/pyproject.toml new file mode 100644 index 0000000000..0def038ed4 --- /dev/null +++ b/sdk/python/examples/apps/router/index_routes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-index-routes" +version = "1.0.0" +description = "Index routes that render default content when parent path matches without a sub-path." +requires-python = ">=3.10" +keywords = ["router", "index", "default", "routes"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Index routes" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "Divider", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "basic" +features = ["index routes", "default child routes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/layout_outlet/main.py b/sdk/python/examples/apps/router/layout_outlet/main.py new file mode 100644 index 0000000000..efa51f0e5e --- /dev/null +++ b/sdk/python/examples/apps/router/layout_outlet/main.py @@ -0,0 +1,72 @@ +"""Layout routes with Outlet — shared layout wrapping child routes.""" + +import flet as ft + + +@ft.component +def Home(): + return ft.Text("Welcome home!", size=24) + + +@ft.component +def About(): + return ft.Text("About us", size=24) + + +@ft.component +def Contact(): + return ft.Text("Contact page", size=24) + + +@ft.component +def AppLayout(): + outlet = ft.use_route_outlet() + return ft.Column( + [ + ft.Container( + content=ft.Row( + [ + ft.Text("My App", size=20, weight=ft.FontWeight.BOLD), + ft.Button( + "Home", + on_click=lambda: ft.context.page.navigate("/"), + ), + ft.Button( + "About", + on_click=lambda: ft.context.page.navigate("/about"), + ), + ft.Button( + "Contact", + on_click=lambda: ft.context.page.navigate("/contact"), + ), + ] + ), + bgcolor=ft.Colors.SURFACE_BRIGHT, + padding=10, + ), + ft.Container(content=outlet, padding=20), + ft.Text("Footer - (c) 2026", text_align=ft.TextAlign.CENTER), + ], + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Router( + [ + ft.Route( + component=AppLayout, + children=[ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ft.Route(path="contact", component=Contact), + ], + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/layout_outlet/pyproject.toml b/sdk/python/examples/apps/router/layout_outlet/pyproject.toml new file mode 100644 index 0000000000..0a7f558a36 --- /dev/null +++ b/sdk/python/examples/apps/router/layout_outlet/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-layout-outlet" +version = "1.0.0" +description = "Layout routes with use_route_outlet() providing shared AppBar and footer around page content." +requires-python = ">=3.10" +keywords = ["router", "layout", "outlet", "appbar", "shared-layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Layout outlet" +controls = ["SafeArea", "Column", "AppBar", "Button", "Text", "Container", "Router", "Route"] +layout_pattern = "app-shell" +complexity = "basic" +features = ["layout routes", "use_route_outlet", "shared layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/loaders/main.py b/sdk/python/examples/apps/router/loaders/main.py new file mode 100644 index 0000000000..acd9daee7a --- /dev/null +++ b/sdk/python/examples/apps/router/loaders/main.py @@ -0,0 +1,125 @@ +"""Loaders — data loading with loader and use_route_loader_data().""" + +import flet as ft + + +# Simulated data loaders +def home_loader(params): + return {"title": "Home", "message": "Welcome to the app!"} + + +def products_loader(params): + return { + "products": [ + {"id": 1, "name": "Widget A", "price": 9.99}, + {"id": 2, "name": "Gadget B", "price": 24.99}, + {"id": 3, "name": "Doohickey C", "price": 4.99}, + ] + } + + +def product_detail_loader(params): + pid = params.get("pid", "?") + # In a real app, you'd fetch from a database or API + products = { + "1": {"id": 1, "name": "Widget A", "price": 9.99, "stock": 42}, + "2": {"id": 2, "name": "Gadget B", "price": 24.99, "stock": 7}, + "3": {"id": 3, "name": "Doohickey C", "price": 4.99, "stock": 100}, + } + return products.get(pid, {"id": pid, "name": "Unknown", "price": 0, "stock": 0}) + + +@ft.component +def Home(): + data = ft.use_route_loader_data() + return ft.Column( + [ + ft.Text(data["title"], size=24), + ft.Text(data["message"]), + ] + ) + + +@ft.component +def ProductsList(): + data = ft.use_route_loader_data() + return ft.Column( + [ + ft.Text("Products", size=24), + *[ + ft.ListTile( + title=ft.Text(p["name"]), + subtitle=ft.Text(f"${p['price']:.2f}"), + on_click=lambda _, pid=p["id"]: ft.context.page.navigate( + f"/products/{pid}" + ), + ) + for p in data["products"] + ], + ] + ) + + +@ft.component +def ProductDetails(): + data = ft.use_route_loader_data() + params = ft.use_route_params() + return ft.Column( + [ + ft.Text(data["name"], size=24), + ft.Text(f"Price: ${data['price']:.2f}"), + ft.Text(f"In stock: {data['stock']}"), + ft.Text(f"Product ID (from params): {params['pid']}"), + ft.Button( + "Back to products", + on_click=lambda: ft.context.page.navigate("/products"), + ), + ] + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Column( + [ + ft.Row( + [ + ft.Button( + "Home", + on_click=lambda: ft.context.page.navigate("/"), + ), + ft.Button( + "Products", + on_click=lambda: ft.context.page.navigate("/products"), + ), + ] + ), + ft.Divider(), + ft.Router( + [ + ft.Route(index=True, component=Home, loader=home_loader), + ft.Route( + path="products", + children=[ + ft.Route( + index=True, + component=ProductsList, + loader=products_loader, + ), + ft.Route( + path=":pid", + component=ProductDetails, + loader=product_detail_loader, + ), + ], + ), + ] + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/loaders/pyproject.toml b/sdk/python/examples/apps/router/loaders/pyproject.toml new file mode 100644 index 0000000000..5563cdf919 --- /dev/null +++ b/sdk/python/examples/apps/router/loaders/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-loaders" +version = "1.0.0" +description = "Route loaders that pre-fetch data for routes, accessed via use_route_loader_data() hook." +requires-python = ">=3.10" +keywords = ["router", "loader", "data", "prefetch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Route loaders" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "ListTile", "Router", "Route"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["route loaders", "use_route_loader_data", "use_route_params"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/nested_outlet_views/README.md b/sdk/python/examples/apps/router/nested_outlet_views/README.md new file mode 100644 index 0000000000..6918e95e8d --- /dev/null +++ b/sdk/python/examples/apps/router/nested_outlet_views/README.md @@ -0,0 +1,11 @@ +# Nested Routes with Shared Layout + +Demonstrates `manage_views=True` combined with `outlet=True` for shared layouts. + +ProductsLayout wraps both ProductsList and ProductDetails via outlet. Each child is its own View with the shared layout (AppBar + footer), so AppBar back works: Details → List → Home. + +- `outlet=True` on ProductsLayout makes it a layout that wraps each child view +- Leaf components return regular controls (not Views) — the layout provides the View +- `/` → 1 view (Home) +- `/products` → 2 views (Home, ProductsLayout wrapping ProductsList) +- `/products/1` → 3 views (Home, ProductsLayout wrapping ProductsList, ProductsLayout wrapping ProductDetails) diff --git a/sdk/python/examples/apps/router/nested_outlet_views/main.py b/sdk/python/examples/apps/router/nested_outlet_views/main.py new file mode 100644 index 0000000000..32474430d0 --- /dev/null +++ b/sdk/python/examples/apps/router/nested_outlet_views/main.py @@ -0,0 +1,94 @@ +import flet as ft + + +@ft.component +def Home(): + return ft.View( + route="/", + can_pop=False, + appbar=ft.AppBar(title=ft.Text("Home")), + controls=[ + ft.Text("Welcome!", size=24), + ft.Button( + "Browse Products", + on_click=lambda: ft.context.page.navigate("/products"), + ), + ], + ) + + +@ft.component +def ProductsList(): + """Returns a regular control — the layout provides the View.""" + return ft.Column( + [ + ft.Text("All Products", size=24), + ft.Button( + "View Product #1", + on_click=lambda: ft.context.page.navigate("/products/1"), + ), + ft.Button( + "View Product #2", + on_click=lambda: ft.context.page.navigate("/products/2"), + ), + ] + ) + + +@ft.component +def ProductDetails(): + """Returns a regular control — the layout provides the View.""" + params = ft.use_route_params() + return ft.Text(f"Product #{params['pid']}", size=24) + + +@ft.component +def ProductsLayout(): + """Shared layout — wraps each child route in a View with AppBar + footer.""" + outlet = ft.use_route_outlet() + return ft.View( + # use_view_path() returns the per-view resolved URL (unique per level) + # — required for Flutter Navigator keying when the layout wraps + # multiple child routes. + route=ft.use_view_path(), + appbar=ft.AppBar( + title=ft.Text("Products"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + controls=[ + ft.Container(content=outlet, padding=20, expand=True), + ft.Divider(), + ft.Text("Products Footer", text_align=ft.TextAlign.CENTER), + ], + ) + + +@ft.component +def App(): + return ft.Router( + [ + ft.Route( + component=Home, + children=[ + ft.Route( + path="products", + component=ProductsLayout, + outlet=True, + children=[ + ft.Route( + component=ProductsList, + children=[ + ft.Route(path=":pid", component=ProductDetails), + ], + ), + ], + ), + ], + ), + ], + manage_views=True, + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(App)) diff --git a/sdk/python/examples/apps/router/nested_outlet_views/pyproject.toml b/sdk/python/examples/apps/router/nested_outlet_views/pyproject.toml new file mode 100644 index 0000000000..4644b43bf2 --- /dev/null +++ b/sdk/python/examples/apps/router/nested_outlet_views/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-nested-outlet-views" +version = "1.0.0" +description = "Nested routes with outlet layout wrapping child routes in a shared View with back navigation." +requires-python = ">=3.10" +keywords = ["router", "nested", "outlet", "views", "manage_views"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Nested outlet views" +controls = ["View", "AppBar", "Column", "Container", "Button", "Text", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "intermediate" +features = ["nested routes", "outlet", "manage_views", "view stack", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/nested_routes/README.md b/sdk/python/examples/apps/router/nested_routes/README.md new file mode 100644 index 0000000000..60ab8ec50e --- /dev/null +++ b/sdk/python/examples/apps/router/nested_routes/README.md @@ -0,0 +1,9 @@ +# Nested Routes with View Stack + +Demonstrates `manage_views=True` with nested route hierarchy. Each route component returns a `View` with its own AppBar. + +- Swipe-back and AppBar back button work automatically +- Home is a pathless root, so it's always in the view stack +- `/` → 1 view (Home) +- `/products` → 2 views (Home, Products) — back to Home +- `/products/1` → 3 views (Home, Products, Product Details) — back to Products diff --git a/sdk/python/examples/apps/router/nested_routes/main.py b/sdk/python/examples/apps/router/nested_routes/main.py new file mode 100644 index 0000000000..401010c5d5 --- /dev/null +++ b/sdk/python/examples/apps/router/nested_routes/main.py @@ -0,0 +1,73 @@ +import flet as ft + + +@ft.component +def Home(): + return ft.View( + route="/", + can_pop=False, + appbar=ft.AppBar(title=ft.Text("Home")), + controls=[ + ft.Text("Home", size=24), + ft.Button( + "Go to Products", + on_click=lambda: ft.context.page.navigate("/products"), + ), + ], + ) + + +@ft.component +def ProductsList(): + return ft.View( + route="/products", + appbar=ft.AppBar(title=ft.Text("Products")), + controls=[ + ft.Text("All Products", size=24), + ft.Button( + "View Product #1", + on_click=lambda: ft.context.page.navigate("/products/1"), + ), + ft.Button( + "View Product #2", + on_click=lambda: ft.context.page.navigate("/products/2"), + ), + ], + ) + + +@ft.component +def ProductDetails(): + params = ft.use_route_params() + return ft.View( + route=f"/products/{params['pid']}", + appbar=ft.AppBar(title=ft.Text(f"Product #{params['pid']}")), + controls=[ + ft.Text(f"Details for product #{params['pid']}", size=24), + ], + ) + + +@ft.component +def App(): + return ft.Router( + [ + ft.Route( + component=Home, + children=[ + ft.Route( + path="products", + component=ProductsList, + children=[ + ft.Route(path=":pid", component=ProductDetails), + ], + ), + ], + ), + ], + manage_views=True, + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render_views(App)) diff --git a/sdk/python/examples/apps/router/nested_routes/pyproject.toml b/sdk/python/examples/apps/router/nested_routes/pyproject.toml new file mode 100644 index 0000000000..d3fd7fd7fe --- /dev/null +++ b/sdk/python/examples/apps/router/nested_routes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-nested-routes" +version = "1.0.0" +description = "Parent/child route hierarchy with dynamic segments for product detail views." +requires-python = ">=3.10" +keywords = ["router", "nested", "routes", "hierarchy", "params"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Nested routes" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "basic" +features = ["nested routes", "dynamic segments", "use_route_params"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/prefix_routes/main.py b/sdk/python/examples/apps/router/prefix_routes/main.py new file mode 100644 index 0000000000..77a267d7af --- /dev/null +++ b/sdk/python/examples/apps/router/prefix_routes/main.py @@ -0,0 +1,107 @@ +"""Prefix routes — pathless layouts and path-only grouping.""" + +import flet as ft + + +@ft.component +def Users(): + return ft.Text("Users page", size=24) + + +@ft.component +def Settings(): + return ft.Text("Settings page", size=24) + + +@ft.component +def ApiUsers(): + return ft.Text("API: Users endpoint", size=24) + + +@ft.component +def ApiProducts(): + return ft.Text("API: Products endpoint", size=24) + + +@ft.component +def AdminLayout(): + """Pathless layout — wraps children without adding a path segment.""" + outlet = ft.use_route_outlet() + return ft.Column( + [ + ft.Container( + content=ft.Text("ADMIN PANEL", weight=ft.FontWeight.BOLD), + bgcolor=ft.Colors.RED_100, + padding=10, + ), + outlet, + ] + ) + + +@ft.component +def Home(): + return ft.Text("Select a section above", size=20, italic=True) + + +@ft.component +def App(): + page = ft.context.page + + return ft.SafeArea( + content=ft.Column( + [ + ft.Text("Prefix Routes Demo", size=24), + ft.Row( + [ + ft.Button( + "Home", + on_click=lambda: page.navigate("/"), + ), + ft.Button( + "Users", + on_click=lambda: page.navigate("/users"), + ), + ft.Button( + "Settings", + on_click=lambda: page.navigate("/settings"), + ), + ft.Button( + "API Users", + on_click=lambda: page.navigate("/api/users"), + ), + ft.Button( + "API Products", + on_click=lambda: page.navigate("/api/products"), + ), + ] + ), + ft.Divider(), + ft.Router( + [ + ft.Route(index=True, component=Home), + # Pathless layout route — children share AdminLayout + ft.Route( + component=AdminLayout, + children=[ + ft.Route(path="users", component=Users), + ft.Route(path="settings", component=Settings), + ], + ), + # Path-only grouping — /api prefix without a layout component + ft.Route( + path="api", + children=[ + ft.Route(path="users", component=ApiUsers), + ft.Route(path="products", component=ApiProducts), + ], + ), + ] + ), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/prefix_routes/pyproject.toml b/sdk/python/examples/apps/router/prefix_routes/pyproject.toml new file mode 100644 index 0000000000..b5192a17a5 --- /dev/null +++ b/sdk/python/examples/apps/router/prefix_routes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-prefix-routes" +version = "1.0.0" +description = "Pathless layout routes and path-only grouping for URL prefix organization." +requires-python = ">=3.10" +keywords = ["router", "prefix", "pathless", "layout", "grouping"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Prefix routes" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "Container", "Divider", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "basic" +features = ["pathless layouts", "path-only grouping", "use_route_outlet"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/runtime_routes/main.py b/sdk/python/examples/apps/router/runtime_routes/main.py new file mode 100644 index 0000000000..74a29cbf66 --- /dev/null +++ b/sdk/python/examples/apps/router/runtime_routes/main.py @@ -0,0 +1,88 @@ +"""Runtime routes — adding and removing routes dynamically.""" + +import flet as ft + + +@ft.component +def Home(): + return ft.Text("Home page", size=24) + + +@ft.component +def About(): + return ft.Text("About page", size=24) + + +@ft.component +def Admin(): + return ft.Text("Admin panel (dynamically added!)", size=24) + + +@ft.component +def App(): + routes, set_routes = ft.use_state( + [ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ] + ) + + admin_added, set_admin_added = ft.use_state(False) + + def add_admin(): + set_routes(lambda r: r + [ft.Route(path="admin", component=Admin)]) + set_admin_added(True) + + def remove_admin(): + ft.context.page.navigate("/") + set_routes(lambda r: [route for route in r if route.path != "admin"]) + set_admin_added(False) + + return ft.SafeArea( + content=ft.Column( + [ + ft.Row( + [ + ft.Button( + "Home", + on_click=lambda: ft.context.page.navigate("/"), + ), + ft.Button( + "About", + on_click=lambda: ft.context.page.navigate("/about"), + ), + *( + [ + ft.Button( + "Admin", + on_click=lambda: ft.context.page.navigate("/admin"), + ) + ] + if admin_added + else [] + ), + ] + ), + ft.Row( + [ + ft.Button( + "Add Admin Route", + on_click=lambda: add_admin(), + disabled=admin_added, + ), + ft.Button( + "Remove Admin Route", + on_click=lambda: remove_admin(), + disabled=not admin_added, + ), + ] + ), + ft.Divider(), + ft.Router(routes), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/runtime_routes/pyproject.toml b/sdk/python/examples/apps/router/runtime_routes/pyproject.toml new file mode 100644 index 0000000000..4e97023086 --- /dev/null +++ b/sdk/python/examples/apps/router/runtime_routes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-runtime-routes" +version = "1.0.0" +description = "Dynamically adding and removing routes at runtime using component state." +requires-python = ">=3.10" +keywords = ["router", "dynamic", "runtime", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Runtime routes" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "Divider", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "intermediate" +features = ["dynamic routes", "use_state", "add routes", "remove routes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/router/splats/main.py b/sdk/python/examples/apps/router/splats/main.py new file mode 100644 index 0000000000..a2ede2d2f4 --- /dev/null +++ b/sdk/python/examples/apps/router/splats/main.py @@ -0,0 +1,57 @@ +"""Splats — catch-all routes with :path*.""" + +import flet as ft + + +@ft.component +def Home(): + return ft.Column( + [ + ft.Text("File Browser Demo", size=24), + ft.Button( + "Browse /files/docs/readme.md", + on_click=lambda: ft.context.page.navigate("/files/docs/readme.md"), + ), + ft.Button( + "Browse /files/images/photo.png", + on_click=lambda: ft.context.page.navigate("/files/images/photo.png"), + ), + ft.Button( + "Browse /files", + on_click=lambda: ft.context.page.navigate("/files"), + ), + ] + ) + + +@ft.component +def FileBrowser(): + params = ft.use_route_params() + file_path = params.get("path", "(root)") + return ft.Column( + [ + ft.Text("File Browser", size=24), + ft.Text(f"Current path: {file_path}"), + ft.Text(f"All params: {params}"), + ft.Button( + "Home", + on_click=lambda: ft.context.page.navigate("/"), + ), + ] + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Router( + [ + ft.Route(index=True, component=Home), + ft.Route(path="files/:path*", component=FileBrowser), + ] + ) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/router/splats/pyproject.toml b/sdk/python/examples/apps/router/splats/pyproject.toml new file mode 100644 index 0000000000..f7bcfa906c --- /dev/null +++ b/sdk/python/examples/apps/router/splats/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "router-splats" +version = "1.0.0" +description = "Catch-all (splat) routes using :path* to capture remaining URL segments." +requires-python = ">=3.10" +keywords = ["router", "splat", "catch-all", "wildcard"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Router"] + +[tool.flet.metadata] +title = "Splat routes" +controls = ["SafeArea", "Column", "Button", "Text", "Router", "Route"] +layout_pattern = "page-navigation" +complexity = "basic" +features = ["catch-all routes", "splat segments", "use_route_params"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py new file mode 100644 index 0000000000..1831fb8f40 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/main.py @@ -0,0 +1,94 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Routes Example" + + print("Initial route:", page.route) + + async def open_mail_settings(e): + await page.push_route("/settings/mail") + + async def open_settings(e): + await page.push_route("/settings") + + def route_change(): + print("Route change:", page.route) + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar(title=ft.Text("Flet app")), + ft.Button("Go to settings", on_click=open_settings), + ] + ) + ) + ], + ) + ) + if page.route == "/settings" or page.route == "/settings/mail": + page.views.append( + ft.View( + route="/settings", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Settings"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + ), + ft.Text( + "Settings!", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.Button( + content="Go to mail settings", + on_click=open_mail_settings, + ), + ] + ) + ) + ], + ) + ) + if page.route == "/settings/mail": + page.views.append( + ft.View( + route="/settings/mail", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Mail Settings"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + ), + ft.Text("Mail settings!"), + ] + ) + ) + ], + ) + ) + page.update() + + async def view_pop(e): + if e.view is not None: + print("View pop:", e.view) + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + + route_change() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml new file mode 100644 index 0000000000..7a7b5086c6 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/building_views_on_route_change/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-building-views-on-route-change" +version = "1.0.0" +description = "Builds a navigation stack from the current route and handles nested settings routes." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "views", "route change"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing"] + +[tool.flet.metadata] +title = "Building views on route change" +controls = ["View", "SafeArea", "Column", "AppBar", "Button", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "nested routes", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py b/sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py new file mode 100644 index 0000000000..a378907d3a --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/drawer_navigation/main.py @@ -0,0 +1,143 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.title = "Drawer navigation" + + async def handle_change(e): + if e.control.selected_index == 0: + await page.push_route("/") + elif e.control.selected_index == 1: + await page.push_route("/store") + elif e.control.selected_index == 2: + await page.push_route("/about") + + def create_drawer(selected_index=0): + return ft.NavigationDrawer( + selected_index=selected_index, + on_change=handle_change, + controls=[ + ft.Container(height=12), + ft.NavigationDrawerDestination( + label="Home", + icon=ft.Icons.HOME_OUTLINED, + selected_icon=ft.Icon(ft.Icons.HOME), + ), + ft.Divider(thickness=2), + ft.NavigationDrawerDestination( + label="Store", + icon=ft.Icon(ft.Icons.STORE_OUTLINED), + selected_icon=ft.Icon(ft.Icons.STORE), + ), + ft.NavigationDrawerDestination( + label="About", + icon=ft.Icon(ft.Icons.PHONE_OUTLINED), + selected_icon=ft.Icons.PHONE, + ), + ], + ) + + async def show_drawer(): + await page.show_drawer() + + def route_change(route): + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Home", expand=True), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + leading=ft.IconButton( + ft.Icons.MENU, on_click=show_drawer + ), + ), + ft.Text("Welcome to Home Page"), + ] + ) + ) + ], + drawer=create_drawer(selected_index=0) if page.route == "/" else None, + ) + ) + + if page.route == "/store": + page.views.append( + ft.View( + route="/store", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Store", expand=True), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + leading=ft.IconButton( + ft.Icons.MENU, on_click=show_drawer + ), + automatically_imply_leading=False, + ), + ft.Text("Welcome to Store Page"), + ft.Button( + "Go About", + on_click=lambda _: asyncio.create_task( + page.push_route("/about") + ), + ), + ] + ) + ) + ], + drawer=create_drawer(selected_index=1), + ) + ) + + if page.route == "/about": + page.views.append( + ft.View( + route="/about", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("About", expand=True), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + leading=ft.IconButton( + ft.Icons.MENU, on_click=show_drawer + ), + automatically_imply_leading=False, + ), + ft.Text("Welcome to About Page"), + ft.Button( + "Go Store", + on_click=lambda _: asyncio.create_task( + page.push_route("/store") + ), + ), + ] + ) + ) + ], + drawer=create_drawer(selected_index=2), + ) + ) + + async def view_pop(view): + page.views.pop() + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + route_change(page.route) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml b/sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml new file mode 100644 index 0000000000..1241409f32 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/drawer_navigation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-drawer-navigation" +version = "1.0.0" +description = "Connects a navigation drawer to route changes across home, store, and about views." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation drawer", "views", "destinations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing"] + +[tool.flet.metadata] +title = "Drawer navigation" +controls = ["View", "SafeArea", "Column", "AppBar", "NavigationDrawer", "NavigationDrawerDestination", "Button", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "drawer navigation", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/home_store/main.py b/sdk/python/examples/apps/routing_navigation/home_store/main.py new file mode 100644 index 0000000000..429490774d --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/home_store/main.py @@ -0,0 +1,74 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.title = "Routes Example" + + def route_change(): + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Flet app"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Button( + "Visit Store", + on_click=lambda: asyncio.create_task( + page.push_route("/store") + ), + ), + ] + ) + ) + ], + ) + ) + if page.route == "/store": + page.views.append( + ft.View( + route="/store", + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar( + title=ft.Text("Store"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Button( + "Go Home", + on_click=lambda: asyncio.create_task( + page.push_route("/") + ), + ), + ] + ) + ) + ], + ) + ) + page.update() + + async def view_pop(e): + if e.view is not None: + print("View pop:", e.view) + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + + route_change() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml b/sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml new file mode 100644 index 0000000000..517ed2fbdd --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/home_store/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-home-store" +version = "1.0.0" +description = "Shows a minimal route-driven home and store flow using view stack navigation." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "home", "store", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing", "Getting Started"] + +[tool.flet.metadata] +title = "Routing with two pages" +controls = ["View", "SafeArea", "Column", "AppBar", "Button"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "view stack", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/initial_route/main.py b/sdk/python/examples/apps/routing_navigation/initial_route/main.py new file mode 100644 index 0000000000..40dfb1a96a --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/initial_route/main.py @@ -0,0 +1,9 @@ +import flet as ft + + +def main(page: ft.Page): + page.add(ft.SafeArea(content=ft.Text(f"Initial route: {page.route}"))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml b/sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml new file mode 100644 index 0000000000..7007ea7526 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/initial_route/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-initial-route" +version = "1.0.0" +description = "Displays the initial route string passed into a Flet app." +requires-python = ">=3.10" +keywords = ["apps", "routing", "route", "text", "minimal"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing"] + +[tool.flet.metadata] +title = "Initial route" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["routing basics"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/pop_view_confirm/main.py b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/main.py new file mode 100644 index 0000000000..d4a0b096ff --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/main.py @@ -0,0 +1,92 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Routes Example" + + def route_change(): + page.views.clear() + page.views.append(MainView("/")) + if page.route == "/store": + page.views.append(PermissionView("/store")) + page.update() + + async def view_pop(e: ft.ViewPopEvent): + if e.view is not None: + print("View pop:", e.view) + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + + route_change() + + +class MainView(ft.View): + def __init__(self, path): + super().__init__( + route=path, + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AppBar(title=ft.Text("Flet app")), + ft.Button("Go to store", on_click=self.open_store), + ] + ) + ) + ], + ) + + async def open_store(self, e): + await self.page.push_route("/store") + + +class PermissionView(ft.View): + def __init__(self, path): + super().__init__( + route=path, + controls=[ + ft.SafeArea( + content=ft.Column( + controls=[ft.AppBar(title=ft.Text(f"{path} View"))] + ) + ) + ], + can_pop=False, + on_confirm_pop=self.ask_pop_permission, + ) + + async def ask_pop_permission(self, e): + async def on_dlg_yes(e): + self.page.pop_dialog() + await self.confirm_pop(True) + + async def on_dlg_no(e): + self.page.pop_dialog() + await self.confirm_pop(False) + + dlg_modal = ft.AlertDialog( + title=ft.Text("Please confirm"), + content=ft.Text("Go home?"), + actions=[ + ft.TextButton( + "Yes", + on_click=on_dlg_yes, + ), + ft.TextButton( + "No", + on_click=on_dlg_no, + ), + ], + actions_alignment=ft.MainAxisAlignment.END, + on_dismiss=lambda e: print("Modal dialog dismissed!"), + ) + + self.page.show_dialog(dlg_modal) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml new file mode 100644 index 0000000000..699ac098b1 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/pop_view_confirm/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-pop-view-confirm" +version = "1.0.0" +description = "Confirms whether a view is allowed to pop before returning from the store route." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "confirmation dialog", "view pop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing"] + +[tool.flet.metadata] +title = "Pop view confirm" +controls = ["View", "SafeArea", "Column", "AppBar", "Button", "AlertDialog", "TextButton", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["routing", "confirmation dialog", "back navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/pop_views_until/main.py b/sdk/python/examples/apps/routing_navigation/pop_views_until/main.py new file mode 100644 index 0000000000..a4251c14e2 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/pop_views_until/main.py @@ -0,0 +1,112 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.title = "Routes Example" + + result_text = ft.Text("No result yet", size=18) + + def route_change(): + page.views.clear() + + # Home View (/) + page.views.append( + ft.View( + route="/", + controls=[ + ft.AppBar(title=ft.Text("Home"), bgcolor=ft.Colors.SURFACE_BRIGHT), + result_text, + ft.Button( + "Start flow", + on_click=lambda _: asyncio.create_task( + page.push_route("/step1") + ), + ), + ], + ) + ) + + if page.route == "/step1" or page.route == "/step2" or page.route == "/step3": + page.views.append( + ft.View( + route="/step1", + controls=[ + ft.AppBar( + title=ft.Text("Step 1"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Text("Step 1 of the flow"), + ft.Button( + "Go to Step 2", + on_click=lambda _: asyncio.create_task( + page.push_route("/step2") + ), + ), + ], + ) + ) + + if page.route == "/step2" or page.route == "/step3": + page.views.append( + ft.View( + route="/step2", + controls=[ + ft.AppBar( + title=ft.Text("Step 2"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Text("Step 2 of the flow"), + ft.Button( + "Go to Step 3", + on_click=lambda _: asyncio.create_task( + page.push_route("/step3") + ), + ), + ], + ) + ) + + if page.route == "/step3": + page.views.append( + ft.View( + route="/step3", + controls=[ + ft.AppBar( + title=ft.Text("Step 3 (Final)"), + bgcolor=ft.Colors.SURFACE_BRIGHT, + ), + ft.Text("Flow complete!"), + ft.Button( + "Finish and go Home", + on_click=lambda _: asyncio.create_task( + page.pop_views_until("/", result="Flow completed!") + ), + ), + ], + ) + ) + + page.update() + + def on_pop_result(e: ft.ViewsPopUntilEvent): + result_text.value = f"Result: {e.result}" + page.show_dialog(ft.SnackBar(ft.Text(f"Got result: {e.result}"))) + page.update() + + async def view_pop(e: ft.ViewPopEvent): + if e.view is not None: + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + page.on_views_pop_until = on_pop_result + + route_change() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/pop_views_until/pyproject.toml b/sdk/python/examples/apps/routing_navigation/pop_views_until/pyproject.toml new file mode 100644 index 0000000000..77ecfadc9c --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/pop_views_until/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-pop-views-until" +version = "1.0.0" +description = "Pops multiple views from the navigation stack and returns a result to the destination view." +requires-python = ">=3.10" +keywords = ["apps", "routing", "navigation", "pop", "views", "result", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing"] + +[tool.flet.metadata] +title = "Pop views until" +controls = ["View", "AppBar", "Button", "Text", "SnackBar"] +layout_pattern = "multi-step-flow" +complexity = "intermediate" +features = ["routing", "view stack", "pop views until", "result passing", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/routing_navigation/route_change_event/main.py b/sdk/python/examples/apps/routing_navigation/route_change_event/main.py new file mode 100644 index 0000000000..c18bfb0cda --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/route_change_event/main.py @@ -0,0 +1,16 @@ +import flet as ft + + +def main(page: ft.Page): + route_log = ft.Column(controls=[ft.Text(f"Initial route: {page.route}")]) + page.add(ft.SafeArea(content=route_log)) + + def route_change(e): + route_log.controls.append(ft.Text(f"New route: {e.route}")) + + page.on_route_change = route_change + page.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml b/sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml new file mode 100644 index 0000000000..90767dad44 --- /dev/null +++ b/sdk/python/examples/apps/routing_navigation/route_change_event/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-routing-navigation-route-change-event" +version = "1.0.0" +description = "Logs each route change by appending the new route string to the page." +requires-python = ">=3.10" +keywords = ["apps", "routing", "events", "route change", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Routing"] + +[tool.flet.metadata] +title = "Route change event" +controls = ["SafeArea", "Text"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["routing basics", "route change event"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/studio_gallery/audio_player.py b/sdk/python/examples/apps/studio_gallery/audio_player.py new file mode 100644 index 0000000000..b08919f0e2 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/audio_player.py @@ -0,0 +1,43 @@ +import flet as ft +import flet_audio as fta + + +@ft.component +def App(): + duration, set_duration = ft.use_state(0.0) + position, set_position = ft.use_state(0.0) + + print("Rendering Audio Player component") + audio, _ = ft.use_state( + lambda: fta.Audio( + src="https://github.com/flet-dev/media/raw/refs/heads/main/sounds/sweet-life-luxury-chill-438146.mp3", + autoplay=False, + on_duration_change=lambda e: set_duration(e.duration.in_milliseconds), + on_position_change=lambda e: set_position(e.position), + ) + ) + + print("duration:", duration) + print("position:", position) + + async def play(): + await audio.play() + + async def pause(): + await audio.pause() + + async def resume(): + await audio.resume() + + return ft.Column( + [ + ft.ProgressBar(position / duration if duration > 0 else 0), + ft.Button("Play", disabled=duration == 0, on_click=play), + ft.Button("Pause", disabled=duration == 0, on_click=pause), + ft.Button("Resume", disabled=duration == 0, on_click=resume), + ] + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/calculator.py b/sdk/python/examples/apps/studio_gallery/calculator.py new file mode 100644 index 0000000000..980586d599 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/calculator.py @@ -0,0 +1,193 @@ +import flet as ft + + +@ft.component +def App(): + display, set_display = ft.use_state("0") + operand1, set_operand1 = ft.use_state(0.0) + operator, set_operator = ft.use_state("+") + new_operand, set_new_operand = ft.use_state(True) + + def format_number(num: float): + if num % 1 == 0: + return int(num) + return num + + def calculate(op1: float, op2: float, op: str): + try: + if op == "+": + return format_number(op1 + op2) + if op == "-": + return format_number(op1 - op2) + if op == "*": + return format_number(op1 * op2) + if op == "/": + if op2 == 0: + return "Error" + return format_number(op1 / op2) + except Exception: + return "Error" + + def parse_float(v, fallback=0.0): + try: + return float(v) + except Exception: + try: + return float(fallback) + except Exception: + return 0.0 + + def on_button(data: str): + nonlocal display, operand1, operator, new_operand + # update via setters so UI re-renders + if display == "Error" or data == "AC": + set_display("0") + set_operand1(0.0) + set_operator("+") + set_new_operand(True) + return + + if data in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."): + if display == "0" or new_operand: + set_display(data) + set_new_operand(False) + else: + set_display(str(display) + data) + return + + if data in ("+", "-", "*", "/"): + val = calculate(operand1, parse_float(display), operator) + # set result and operator + set_display(str(val)) + set_operator(data) + if val == "Error": + set_operand1(0.0) + else: + set_operand1(parse_float(val)) + set_new_operand(True) + return + + if data == "=": + val = calculate(operand1, parse_float(display), operator) + set_display(str(val)) + # reset for next input + set_operand1(0.0) + set_operator("+") + set_new_operand(True) + return + + if data == "%": + set_display(str(parse_float(display) / 100)) + set_operand1(0.0) + set_operator("+") + set_new_operand(True) + return + + if data == "+/-": + v = parse_float(display) + if v > 0: + set_display("-" + str(display)) + elif v < 0: + set_display(str(format_number(abs(v)))) + return + + def make_btn(label: str, bgcolor=None, color=None, expand: int = 1): + return ft.Button( + label, + expand=expand, + bgcolor=bgcolor, + color=color, + on_click=lambda e, d=label: on_button(d), + ) + + # build rows like the original layout + return ft.Container( + width=350, + bgcolor=ft.Colors.BLACK, + border_radius=ft.BorderRadius.all(20), + padding=20, + content=ft.Column( + controls=[ + ft.Row( + [ft.Text(value=str(display), color=ft.Colors.WHITE, size=20)], + alignment=ft.MainAxisAlignment.END, + ), + ft.Row( + controls=[ + make_btn( + "AC", bgcolor=ft.Colors.BLUE_GREY_100, color=ft.Colors.BLACK + ), + make_btn( + "+/-", + bgcolor=ft.Colors.BLUE_GREY_100, + color=ft.Colors.BLACK, + ), + make_btn( + "%", bgcolor=ft.Colors.BLUE_GREY_100, color=ft.Colors.BLACK + ), + make_btn("/", bgcolor=ft.Colors.ORANGE, color=ft.Colors.WHITE), + ] + ), + ft.Row( + controls=[ + make_btn( + "7", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn( + "8", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn( + "9", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn("*", bgcolor=ft.Colors.ORANGE, color=ft.Colors.WHITE), + ] + ), + ft.Row( + controls=[ + make_btn( + "4", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn( + "5", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn( + "6", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn("-", bgcolor=ft.Colors.ORANGE, color=ft.Colors.WHITE), + ] + ), + ft.Row( + controls=[ + make_btn( + "1", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn( + "2", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn( + "3", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn("+", bgcolor=ft.Colors.ORANGE, color=ft.Colors.WHITE), + ] + ), + ft.Row( + controls=[ + make_btn( + "0", + bgcolor=ft.Colors.WHITE_24, + color=ft.Colors.WHITE, + expand=2, + ), + make_btn( + ".", bgcolor=ft.Colors.WHITE_24, color=ft.Colors.WHITE + ), + make_btn("=", bgcolor=ft.Colors.ORANGE, color=ft.Colors.WHITE), + ] + ), + ] + ), + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/charts/barchart.py b/sdk/python/examples/apps/studio_gallery/charts/barchart.py new file mode 100644 index 0000000000..eab655bbcd --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/barchart.py @@ -0,0 +1,92 @@ +import flet as ft +import flet_charts as fch + + +@ft.component +def BarChart(): + return fch.BarChart( + expand=True, + interactive=True, + max_y=110, + border=ft.Border.all(1, ft.Colors.GREY_400), + horizontal_grid_lines=fch.ChartGridLines( + color=ft.Colors.GREY_300, width=1, dash_pattern=[3, 3] + ), + tooltip=fch.BarChartTooltip( + bgcolor=ft.Colors.with_opacity(0.5, ft.Colors.GREY_300), + border_radius=ft.BorderRadius.all(20), + ), + left_axis=fch.ChartAxis( + label_size=40, title=ft.Text("Fruit supply"), title_size=40 + ), + right_axis=fch.ChartAxis(show_labels=False), + bottom_axis=fch.ChartAxis( + label_size=40, + labels=[ + fch.ChartAxisLabel( + value=0, label=ft.Container(ft.Text("Apple"), padding=10) + ), + fch.ChartAxisLabel( + value=1, label=ft.Container(ft.Text("Blueberry"), padding=10) + ), + fch.ChartAxisLabel( + value=2, label=ft.Container(ft.Text("Cherry"), padding=10) + ), + fch.ChartAxisLabel( + value=3, label=ft.Container(ft.Text("Orange"), padding=10) + ), + ], + ), + groups=[ + fch.BarChartGroup( + x=0, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=40, + width=40, + color=ft.Colors.GREEN, + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=1, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=100, + width=40, + color=ft.Colors.BLUE, + tooltip=fch.BarChartRodTooltip("Blueberry"), + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=2, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=30, + width=40, + color=ft.Colors.RED, + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=3, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=60, + width=40, + color=ft.Colors.ORANGE, + tooltip=fch.BarChartRodTooltip("Orange"), + border_radius=0, + ), + ], + ), + ], + ) diff --git a/sdk/python/examples/apps/studio_gallery/charts/candlestickchart.py b/sdk/python/examples/apps/studio_gallery/charts/candlestickchart.py new file mode 100644 index 0000000000..2493f78694 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/candlestickchart.py @@ -0,0 +1,119 @@ +import flet as ft +import flet_charts as fch + +CANDLE_DATA = [ + ("Mon", 24.8, 28.6, 23.9, 27.2), + ("Tue", 27.2, 30.1, 25.8, 28.4), + ("Wed", 28.4, 31.2, 26.5, 29.1), + ("Thu", 29.1, 32.4, 27.9, 31.8), + ("Fri", 31.8, 34.0, 29.7, 30.2), + ("Sat", 30.2, 33.6, 28.3, 32.7), + ("Sun", 32.7, 35.5, 30.1, 34.6), +] + + +@ft.component +def CandlestickChart(): + info_value, set_info_value = ft.use_state( + "Interact with the chart to see event details." + ) + + def build_spots() -> list[fch.CandlestickChartSpot]: + """Create candlestick spots from the static data.""" + spots: list[fch.CandlestickChartSpot] = [] + for index, (label, open_, high, low, close) in enumerate(CANDLE_DATA): + spots.append( + fch.CandlestickChartSpot( + x=float(index), + open=open_, + high=high, + low=low, + close=close, + selected=index == len(CANDLE_DATA) - 1, + tooltip=fch.CandlestickChartSpotTooltip( + text=( + f"{label}\n" + f"Open: {open_:0.1f}\n" + f"High: {high:0.1f}\n" + f"Low : {low:0.1f}\n" + f"Close: {close:0.1f}" + ), + bottom_margin=12, + ), + ) + ) + return spots + + spots = build_spots() + min_x = -0.5 + max_x = len(spots) - 0.5 + min_y = min(low for _, _, _, low, _ in CANDLE_DATA) - 1 + max_y = max(high for _, _, _, _, high in CANDLE_DATA) + 1 + + def handle_event(e: fch.CandlestickChartEvent): + if e.spot_index is not None and e.spot_index >= 0: + label, open_, high, low, close = CANDLE_DATA[e.spot_index] + set_info_value( + f"{e.type.value} • {label}: " + f"O {open_:0.1f} H {high:0.1f} L {low:0.1f} C {close:0.1f}" + ) + else: + set_info_value(f"{e.type.value} • outside candlesticks") + + chart = fch.CandlestickChart( + expand=True, + min_x=min_x, + max_x=max_x, + min_y=min_y, + max_y=max_y, + baseline_x=0, + baseline_y=min_y, + bgcolor=ft.Colors.with_opacity(0.2, ft.Colors.BLUE_GREY_900), + horizontal_grid_lines=fch.ChartGridLines(interval=2, dash_pattern=[2, 2]), + vertical_grid_lines=fch.ChartGridLines(interval=1, dash_pattern=[2, 2]), + left_axis=fch.ChartAxis( + label_spacing=2, + label_size=60, + title=ft.Text("Price (k USD)", color=ft.Colors.GREY_300), + show_min=False, + ), + bottom_axis=fch.ChartAxis( + labels=[ + fch.ChartAxisLabel( + value=index, + label=ft.Text(name, color=ft.Colors.GREY_300), + ) + for index, (name, *_rest) in enumerate(CANDLE_DATA) + ], + label_spacing=1, + label_size=40, + show_min=False, + show_max=False, + ), + spots=spots, + tooltip=fch.CandlestickChartTooltip( + bgcolor=ft.Colors.BLUE_GREY_800, + horizontal_alignment=fch.HorizontalAlignment.CENTER, + fit_inside_horizontally=True, + ), + on_event=handle_event, + ) + + return ft.Container( + expand=True, + border_radius=16, + padding=20, + content=ft.Column( + expand=True, + spacing=20, + controls=[ + ft.Text( + "Weekly OHLC snapshot (demo data)", + size=20, + weight=ft.FontWeight.BOLD, + ), + chart, + ft.Text(info_value, size=14), + ], + ), + ) diff --git a/sdk/python/examples/apps/studio_gallery/charts/charts.py b/sdk/python/examples/apps/studio_gallery/charts/charts.py new file mode 100644 index 0000000000..affc2fb473 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/charts.py @@ -0,0 +1,80 @@ +from gallery.charts.barchart import BarChart +from gallery.charts.candlestickchart import CandlestickChart +from gallery.charts.linechart import LineChart +from gallery.charts.piechart import PieChart +from gallery.charts.radarchart import RadarChart +from gallery.charts.scatterchart import ScatterChart + +import flet as ft + +charts_map = { + "BarChart": BarChart, + "LineChart": LineChart, + "PieChart": PieChart, + "CandlestickChart": CandlestickChart, + "RadarChart": RadarChart, + "ScatterChart": ScatterChart, +} + + +@ft.component +def ChartView(chart_type: str, on_click_back: ft.EventHandler) -> ft.Control: + return ft.Column( + [ + ft.TextButton( + "All charts", icon=ft.Icons.ARROW_BACK, on_click=on_click_back + ), + charts_map.get(chart_type, lambda: ft.Text("Something went wrong..."))(), + ] + ) + + +@ft.component +def App(): + selected_chart, set_selected_chart = ft.use_state(None) + + def on_click_back(e): + set_selected_chart(None) + + return ( + ft.Column( + controls=[ + ft.ListTile( + leading=ft.Icon(ft.Icons.STACKED_LINE_CHART), + title=ft.Text("LineChart"), + on_click=lambda e: set_selected_chart("LineChart"), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.BAR_CHART), + title=ft.Text("BarChart"), + on_click=lambda e: set_selected_chart("BarChart"), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.PIE_CHART), + title=ft.Text("PieChart"), + on_click=lambda e: set_selected_chart("PieChart"), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.SCATTER_PLOT), + title=ft.Text("ScatterChart"), + on_click=lambda e: set_selected_chart("ScatterChart"), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.CANDLESTICK_CHART), + title=ft.Text("CandlestickChart"), + on_click=lambda e: set_selected_chart("CandlestickChart"), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.RADAR), + title=ft.Text("RadarChart"), + on_click=lambda e: set_selected_chart("RadarChart"), + ), + ], + ) + if selected_chart is None + else ChartView(selected_chart, on_click_back) + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/charts/linechart.py b/sdk/python/examples/apps/studio_gallery/charts/linechart.py new file mode 100644 index 0000000000..52410db1cc --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/linechart.py @@ -0,0 +1,192 @@ +import flet as ft +import flet_charts as fch + + +@ft.component +def LineChart(): + toggle, set_toggle = ft.use_state(True) + + data_1 = [ + fch.LineChartData( + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 1.5), + fch.LineChartDataPoint(5, 1.4), + fch.LineChartDataPoint(7, 3.4), + fch.LineChartDataPoint(10, 2), + fch.LineChartDataPoint(12, 2.2), + fch.LineChartDataPoint(13, 1.8), + ], + stroke_width=8, + color=ft.Colors.LIGHT_GREEN, + curved=True, + rounded_stroke_cap=True, + ), + fch.LineChartData( + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 2.8), + fch.LineChartDataPoint(7, 1.2), + fch.LineChartDataPoint(10, 2.8), + fch.LineChartDataPoint(12, 2.6), + fch.LineChartDataPoint(13, 3.9), + ], + color=ft.Colors.PINK, + below_line_bgcolor=ft.Colors.with_opacity(0, ft.Colors.PINK), + stroke_width=8, + curved=True, + rounded_stroke_cap=True, + ), + fch.LineChartData( + points=[ + fch.LineChartDataPoint(1, 2.8), + fch.LineChartDataPoint(3, 1.9), + fch.LineChartDataPoint(6, 3), + fch.LineChartDataPoint(10, 1.3), + fch.LineChartDataPoint(13, 2.5), + ], + color=ft.Colors.CYAN, + stroke_width=8, + curved=True, + rounded_stroke_cap=True, + ), + ] + + data_2 = [ + fch.LineChartData( + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 4), + fch.LineChartDataPoint(5, 1.8), + fch.LineChartDataPoint(7, 5), + fch.LineChartDataPoint(10, 2), + fch.LineChartDataPoint(12, 2.2), + fch.LineChartDataPoint(13, 1.8), + ], + stroke_width=4, + color=ft.Colors.with_opacity(0.5, ft.Colors.LIGHT_GREEN), + rounded_stroke_cap=True, + ), + fch.LineChartData( + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 2.8), + fch.LineChartDataPoint(7, 1.2), + fch.LineChartDataPoint(10, 2.8), + fch.LineChartDataPoint(12, 2.6), + fch.LineChartDataPoint(13, 3.9), + ], + color=ft.Colors.with_opacity(0.5, ft.Colors.PINK), + below_line_bgcolor=ft.Colors.with_opacity(0.2, ft.Colors.PINK), + stroke_width=4, + curved=True, + rounded_stroke_cap=True, + ), + fch.LineChartData( + point=True if not toggle else None, + points=[ + fch.LineChartDataPoint(1, 3.8), + fch.LineChartDataPoint(3, 1.9), + fch.LineChartDataPoint(6, 5), + fch.LineChartDataPoint(10, 3.3), + fch.LineChartDataPoint(13, 4.5), + ], + color=ft.Colors.with_opacity(0.5, ft.Colors.CYAN), + stroke_width=4, + rounded_stroke_cap=True, + ), + ] + + chart = fch.LineChart( + data_series=data_1 if toggle else data_2, + border=ft.Border( + bottom=ft.BorderSide(4, ft.Colors.with_opacity(0.5, ft.Colors.PRIMARY)) + ), + left_axis=fch.ChartAxis( + labels=[ + fch.ChartAxisLabel( + value=1, + label=ft.Text("1m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=2, + label=ft.Text("2m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=3, + label=ft.Text("3m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=4, + label=ft.Text("4m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=5, + label=ft.Text("5m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=6, + label=ft.Text("6m", size=14, weight=ft.FontWeight.BOLD), + ), + ], + label_size=40, + ), + bottom_axis=fch.ChartAxis( + labels=[ + fch.ChartAxisLabel( + value=2, + label=ft.Container( + ft.Text( + "SEP", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.PRIMARY), + ), + margin=ft.Margin.only(top=10), + ), + ), + fch.ChartAxisLabel( + value=7, + label=ft.Container( + ft.Text( + "OCT", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.PRIMARY), + ), + margin=ft.Margin.only(top=10), + ), + ), + fch.ChartAxisLabel( + value=12, + label=ft.Container( + ft.Text( + "DEC", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.PRIMARY), + ), + margin=ft.Margin.only(top=10), + ), + ), + ], + label_size=32, + ), + tooltip=fch.LineChartTooltip( + bgcolor=ft.Colors.with_opacity(0.8, ft.Colors.BLUE_GREY) + ), + min_y=0, + max_y=4 if toggle else 6, + min_x=0, + max_x=14, + interactive=toggle, + width=700, + height=500, + ) + + return ft.Column( + controls=[ + ft.IconButton(ft.Icons.REFRESH, on_click=lambda e: set_toggle(not toggle)), + chart, + ] + ) diff --git a/sdk/python/examples/apps/studio_gallery/charts/piechart.py b/sdk/python/examples/apps/studio_gallery/charts/piechart.py new file mode 100644 index 0000000000..c133fe9510 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/piechart.py @@ -0,0 +1,113 @@ +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft +import flet_charts as fch + +name = "PieChart 3" + + +normal_radius = 100 +hover_radius = 110 + +normal_title_style = ft.TextStyle( + size=12, color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD +) +hover_title_style = ft.TextStyle( + size=16, + color=ft.Colors.WHITE, + weight=ft.FontWeight.BOLD, + shadow=ft.BoxShadow(blur_radius=2, color=ft.Colors.BLACK_54), +) +normal_badge_size = 40 +hover_badge_size = 50 + + +@dataclass +@ft.observable +class SectionData: + value: int + radius: int + color: ft.ColorValue + badge_icon: Optional[ft.IconData] = None + badge_size: int = normal_badge_size + badge_position: float = 0.98 + hovered: bool = False + + +@dataclass +class ChartData: + sections: list[SectionData] = field(default_factory=list) + + +@ft.component +def PieChartSection(section: SectionData) -> fch.PieChartSection: + badge = None + if section.badge_icon: + s = section.badge_size if not section.hovered else hover_badge_size + badge = ft.Container( + ft.Icon(section.badge_icon), + width=s, + height=s, + border=ft.Border.all(1, ft.Colors.BROWN), + border_radius=s / 2, + bgcolor=ft.Colors.WHITE, + ) + + return fch.PieChartSection( + section.value, + title=f"{section.value}%", + title_style=hover_title_style if section.hovered else normal_title_style, + color=section.color, + radius=section.radius + 10 if section.hovered else section.radius, + badge=badge, + badge_position=section.badge_position, + ) + + +@ft.component +def PieChart(): + chart_data, _ = ft.use_state( + ChartData( + sections=[ + SectionData( + value=40, + radius=normal_radius, + color=ft.Colors.BLUE, + badge_icon=ft.Icons.AC_UNIT, + ), + SectionData( + value=30, + radius=normal_radius, + color=ft.Colors.YELLOW, + badge_icon=ft.Icons.ACCESS_ALARM, + ), + SectionData( + value=15, + radius=normal_radius, + color=ft.Colors.PURPLE, + badge_icon=ft.Icons.APPLE, + ), + SectionData( + value=15, + radius=normal_radius, + color=ft.Colors.GREEN, + badge_icon=ft.Icons.PEDAL_BIKE, + ), + ] + ) + ) + + def on_chart_event(e): + for idx, section in enumerate(chart_data.sections): + section.hovered = idx == e.section_index + + chart = fch.PieChart( + sections=[PieChartSection(section=section) for section in chart_data.sections], + sections_space=0, + center_space_radius=0, + on_event=on_chart_event, + expand=True, + ) + + return chart diff --git a/sdk/python/examples/apps/studio_gallery/charts/radarchart.py b/sdk/python/examples/apps/studio_gallery/charts/radarchart.py new file mode 100644 index 0000000000..736944664d --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/radarchart.py @@ -0,0 +1,51 @@ +import flet as ft +import flet_charts as fch + + +@ft.component +def RadarChart(): + categories = ["macOS", "Linux", "Windows"] + + return fch.RadarChart( + expand=True, + titles=[fch.RadarChartTitle(text=label) for label in categories], + center_min_value=True, + tick_count=4, + ticks_text_style=ft.TextStyle(size=20, color=ft.Colors.ON_SURFACE), + title_text_style=ft.TextStyle( + size=24, weight=ft.FontWeight.BOLD, color=ft.Colors.ON_SURFACE + ), + on_event=lambda e: print(e.type), + data_sets=[ + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.2, ft.Colors.DEEP_PURPLE), + border_color=ft.Colors.DEEP_PURPLE, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(300), + fch.RadarDataSetEntry(50), + fch.RadarDataSetEntry(250), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.15, ft.Colors.PINK), + border_color=ft.Colors.PINK, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(250), + fch.RadarDataSetEntry(100), + fch.RadarDataSetEntry(200), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.12, ft.Colors.CYAN), + border_color=ft.Colors.CYAN, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(200), + fch.RadarDataSetEntry(150), + fch.RadarDataSetEntry(50), + ], + ), + ], + ) diff --git a/sdk/python/examples/apps/studio_gallery/charts/scatterchart.py b/sdk/python/examples/apps/studio_gallery/charts/scatterchart.py new file mode 100644 index 0000000000..ccfceff943 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/charts/scatterchart.py @@ -0,0 +1,159 @@ +import random +from dataclasses import dataclass + +import flet as ft +import flet_charts as fch + + +@dataclass +class MySpot: + x: float + y: float + radius: float = 8.0 + + +flutter_logo_spots = [ + MySpot(20, 14.5), + MySpot(20, 14.5), + MySpot(22, 16.5), + MySpot(24, 18.5), + MySpot(22, 12.5), + MySpot(24, 14.5), + MySpot(26, 16.5), + MySpot(24, 10.5), + MySpot(26, 12.5), + MySpot(28, 14.5), + MySpot(26, 8.5), + MySpot(28, 10.5), + MySpot(30, 12.5), + MySpot(28, 6.5), + MySpot(30, 8.5), + MySpot(32, 10.5), + MySpot(30, 4.5), + MySpot(32, 6.5), + MySpot(34, 8.5), + MySpot(34, 4.5), + MySpot(36, 6.5), + MySpot(38, 4.5), + # section 2 + MySpot(20, 14.5), + MySpot(22, 12.5), + MySpot(24, 10.5), + MySpot(22, 16.5), + MySpot(24, 14.5), + MySpot(26, 12.5), + MySpot(24, 18.5), + MySpot(26, 16.5), + MySpot(28, 14.5), + MySpot(26, 20.5), + MySpot(28, 18.5), + MySpot(30, 16.5), + MySpot(28, 22.5), + MySpot(30, 20.5), + MySpot(32, 18.5), + MySpot(30, 24.5), + MySpot(32, 22.5), + MySpot(34, 20.5), + MySpot(34, 24.5), + MySpot(36, 22.5), + MySpot(38, 24.5), + # section 3 + MySpot(10, 25), + MySpot(12, 23), + MySpot(14, 21), + MySpot(12, 27), + MySpot(14, 25), + MySpot(16, 23), + MySpot(14, 29), + MySpot(16, 27), + MySpot(18, 25), + MySpot(16, 31), + MySpot(18, 29), + MySpot(20, 27), + MySpot(18, 33), + MySpot(20, 31), + MySpot(22, 29), + MySpot(20, 35), + MySpot(22, 33), + MySpot(24, 31), + MySpot(22, 37), + MySpot(24, 35), + MySpot(26, 33), + MySpot(24, 39), + MySpot(26, 37), + MySpot(28, 35), + MySpot(26, 41), + MySpot(28, 39), + MySpot(30, 37), + MySpot(28, 43), + MySpot(30, 41), + MySpot(32, 39), + MySpot(30, 45), + MySpot(32, 43), + MySpot(34, 41), + MySpot(34, 45), + MySpot(36, 43), + MySpot(38, 45), +] + + +def get_random_spots(): + """Generates random spots for the scatter chart.""" + return [ + MySpot( + x=random.uniform(4, 50), + y=random.uniform(4, 50), + radius=random.uniform(4, 20), + ) + for _ in range(len(flutter_logo_spots)) + ] + + +@ft.component +def ScatterChart(): + spots, set_spots = ft.use_state(lambda: flutter_logo_spots) + + def handle_event(e: fch.ScatterChartEvent): + if e.type == fch.ChartEventType.TAP_DOWN: + set_spots( + flutter_logo_spots + if (spots != flutter_logo_spots) + else get_random_spots() + ) + + return ft.Column( + [ + ft.Text( + "Tap on the chart to toggle between random spots and Flutter logo spots." # noqa: E501 + ), + fch.ScatterChart( + expand=True, + aspect_ratio=1.0, + min_x=0.0, + max_x=50.0, + min_y=0.0, + max_y=50.0, + left_axis=fch.ChartAxis(show_labels=False), + right_axis=fch.ChartAxis(show_labels=False), + top_axis=fch.ChartAxis(show_labels=False), + bottom_axis=fch.ChartAxis(show_labels=False), + show_tooltips_for_selected_spots_only=False, + on_event=handle_event, + animation=ft.Animation( + duration=ft.Duration(milliseconds=600), + curve=ft.AnimationCurve.FAST_OUT_SLOWIN, + ), + spots=[ + fch.ScatterChartSpot( + x=spot.x, + y=spot.y, + radius=spot.radius, + color=ft.Colors.random(), + show_tooltip=True, + selected=spot.x == 43, + ) + for spot in spots + ], + ), + ] + ) diff --git a/sdk/python/examples/apps/studio_gallery/counter.py b/sdk/python/examples/apps/studio_gallery/counter.py new file mode 100644 index 0000000000..b1c7d5d889 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/counter.py @@ -0,0 +1,45 @@ +import flet as ft + + +@ft.component +def App(): + # keep the state as a string so it maps cleanly to TextField.value + count, set_count = ft.use_state("0") + + txt_number = ft.TextField(value=count, text_align=ft.TextAlign.RIGHT, width=100) + + def parse_int_or_fallback(value, fallback): + try: + return int(value) + except (TypeError, ValueError): + try: + return int(fallback) + except (TypeError, ValueError): + return 0 + + def minus_click(e): + n = parse_int_or_fallback(txt_number.value, count) + set_count(str(n - 1)) + + def plus_click(e): + n = parse_int_or_fallback(txt_number.value, count) + set_count(str(n + 1)) + + return ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Row( + [ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + txt_number, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/cupertino_controls.py b/sdk/python/examples/apps/studio_gallery/cupertino_controls.py new file mode 100644 index 0000000000..c58b994862 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/cupertino_controls.py @@ -0,0 +1,148 @@ +import flet as ft + +FRUITS = [ + "Apple", + "Mango", + "Banana", + "Orange", + "Pineapple", + "Strawberry", +] + + +@ft.component +def GroupTitle(title: str): + """Small component that renders a title row for a group.""" + return ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + title, + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=16, + color=ft.CupertinoColors.LABEL, + ), + ) + ], + ) + + +@ft.component +def App(): + cupertino_picker = ft.CupertinoPicker( + selected_index=3, + magnification=1.22, + squeeze=1.2, + use_magnifier=True, + controls=[ft.Text(value=f) for f in FRUITS], + ) + + return ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.START, + controls=[ + GroupTitle("Input Controls"), + ft.CupertinoCheckbox(label="Checkbox"), + ft.CupertinoSwitch(label="Switch"), + ft.CupertinoSlider(min=0, max=100, divisions=10, value=50), + ft.RadioGroup( + content=ft.Column( + controls=[ + ft.CupertinoRadio(label="Radio 1", value="r1"), + ft.CupertinoRadio(label="Radio 2", value="r2"), + ] + ) + ), + ft.CupertinoTextField(label="Text Field"), + GroupTitle("Dialogs"), + ft.Row( + controls=[ + ft.CupertinoButton( + "Show Dialog", + on_click=lambda e: e.page.show_dialog( + ft.CupertinoAlertDialog( + title=ft.Text("Hello from Flet!"), + actions=[ + ft.CupertinoDialogAction( + "OK", + on_click=lambda ev: ev.page.pop_dialog(), + ) + ], + ) + ), + ), + ft.CupertinoButton( + "Show Picker", + on_click=lambda e: e.page.show_dialog( + ft.CupertinoBottomSheet( + content=cupertino_picker, + height=216, + padding=ft.Padding.only(top=6), + ) + # ), + ), + ), + ] + ), + ft.Row( + controls=[ + ft.CupertinoButton( + "Show DatePicker", + on_click=lambda e: e.page.show_dialog( + ft.CupertinoBottomSheet( + content=ft.CupertinoDatePicker(), + height=216, + padding=ft.Padding.only(top=6), + ) + ), + ), + ft.CupertinoButton( + "Show TimerPicker", + on_click=lambda e: e.page.show_dialog( + ft.CupertinoBottomSheet( + content=ft.CupertinoTimerPicker(), + height=216, + padding=ft.Padding.only(top=6), + ) + ), + ), + ] + ), + GroupTitle("Buttons"), + ft.Row( + controls=[ + ft.CupertinoButton("CupertinoButton", expand=1), + ft.CupertinoButton( + content="CupertinoButton", + disabled=True, + expand=1, + ), + ] + ), + ft.Row( + controls=[ + ft.CupertinoFilledButton("Filled", expand=1), + ft.CupertinoFilledButton( + content="Filled", + disabled=True, + expand=1, + ), + ] + ), + ft.Row( + controls=[ + ft.CupertinoTintedButton("Tinted", expand=1), + ft.CupertinoTintedButton( + content="Tinted", + disabled=True, + expand=1, + ), + ] + ), + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/drawing_tool.py b/sdk/python/examples/apps/studio_gallery/drawing_tool.py new file mode 100644 index 0000000000..f89b5f56d6 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/drawing_tool.py @@ -0,0 +1,130 @@ +from dataclasses import dataclass, field + +import flet as ft + +ItemID = ft.IdCounter() + +MAX_SHAPES_PER_CAPTURE = 30 + +colors = [ + ft.Colors.RED, + ft.Colors.YELLOW, + ft.Colors.BLUE, + ft.Colors.GREEN, + ft.Colors.ORANGE, + ft.Colors.PURPLE, + ft.Colors.PINK, + ft.Colors.LIME, + ft.Colors.BLACK, + ft.Colors.WHITE, +] + + +@ft.observable +@dataclass +class Item: + x1: float + y1: float + x2: float + y2: float + color: ft.Colors + id: int = field(default_factory=ItemID) + + +@ft.component +def App(): + import flet.canvas as cv + + items, set_items = ft.use_state([]) + _, set_last_pos = ft.use_state(None) + color, set_color = ft.use_state(ft.Colors.BLACK) + + def pan_start(e: ft.DragStartEvent): + set_last_pos((e.local_position.x, e.local_position.y)) + + async def pan_update(e: ft.DragUpdateEvent): + def update_last_pos(prev): + if prev is not None: + set_items( + lambda cur: cur + + [ + Item( + prev[0], + prev[1], + e.local_position.x, + e.local_position.y, + color=color, + ) + ] + ) + return (e.local_position.x, e.local_position.y) + + set_last_pos(update_last_pos) + + async def on_updated(): + if len(items) > MAX_SHAPES_PER_CAPTURE: + await canvas.capture() + set_items([]) + + ft.on_updated(on_updated) + + async def clear_canvas(): + await canvas.clear_capture() + set_items([]) + + canvas = cv.Canvas( + shapes=[ + cv.Line( + item.x1, + item.y1, + item.x2, + item.y2, + paint=ft.Paint(stroke_width=3, color=item.color), + key=item.id, + ) + for item in items + ], + content=ft.GestureDetector( + on_pan_start=pan_start, + on_pan_update=pan_update, + drag_interval=10, + ), + expand=False, + ) + + def color_clicked(e): + set_color(e.control.bgcolor) + + return ft.Column( + controls=[ + ft.Button("Clear", on_click=clear_canvas), + ft.Row( + controls=[ + ft.Container( + width=25, + height=25, + border_radius=25, + bgcolor=c, + border=ft.Border.all( + width=3 if c == color else 1, + color=ft.Colors.BLACK_12, + ), + on_click=color_clicked, + ) + for c in colors + ] + ), + ft.Container( + canvas, + border=ft.Border.all(2, ft.Colors.BLACK_54), + border_radius=5, + bgcolor=ft.Colors.SURFACE_CONTAINER, + width=500, + height=500, + ), + ] + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/flashlight.py b/sdk/python/examples/apps/studio_gallery/flashlight.py new file mode 100644 index 0000000000..34a5f4849c --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/flashlight.py @@ -0,0 +1,22 @@ +import flet as ft +import flet_flashlight as ffl + + +@ft.component +def App(): + async def turn_on_flashlight(e): + await ffl.Flashlight().on() + + async def turn_off_flashlight(e): + await ffl.Flashlight().off() + + return ft.Row( + controls=[ + ft.TextButton("On", on_click=turn_on_flashlight), + ft.TextButton("Off", on_click=turn_off_flashlight), + ] + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/flet_animation.py b/sdk/python/examples/apps/studio_gallery/flet_animation.py new file mode 100644 index 0000000000..88e607faaf --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/flet_animation.py @@ -0,0 +1,135 @@ +import random +from math import pi + +import flet as ft + + +@ft.component +def App(): + scattered, set_scattered = ft.use_state(True) + size = 15 + gap = 3 + duration = 2000 + + c1 = ft.Colors.PINK_500 + c2 = ft.Colors.AMBER_500 + c3 = ft.Colors.LIGHT_GREEN_500 + c4 = ft.Colors.DEEP_PURPLE_500 + + all_colors = [ + ft.Colors.AMBER_400, + ft.Colors.AMBER_ACCENT_400, + ft.Colors.BLUE_400, + ft.Colors.BROWN_400, + ft.Colors.CYAN_700, + ft.Colors.DEEP_ORANGE_500, + ft.Colors.CYAN_500, + ft.Colors.INDIGO_600, + ft.Colors.ORANGE_ACCENT_100, + ft.Colors.PINK, + ft.Colors.RED_600, + ft.Colors.GREEN_400, + ft.Colors.GREEN_ACCENT_200, + ft.Colors.TEAL_ACCENT_200, + ft.Colors.LIGHT_BLUE_500, + ] + + parts = [ + # F + (0, 0, c1), + (0, 1, c1), + (0, 2, c1), + (0, 3, c1), + (0, 4, c1), + (1, 0, c1), + (1, 2, c1), + (2, 0, c1), + # L + (4, 0, c2), + (4, 1, c2), + (4, 2, c2), + (4, 3, c2), + (4, 4, c2), + (5, 4, c2), + (6, 4, c2), + # E + (8, 0, c3), + (9, 0, c3), + (10, 0, c3), + (8, 1, c3), + (8, 2, c3), + (9, 2, c3), + (10, 2, c3), + (8, 3, c3), + (8, 4, c3), + (9, 4, c3), + (10, 4, c3), + # T + (12, 0, c4), + (13, 0, c4), + (14, 0, c4), + (13, 1, c4), + (13, 2, c4), + (13, 3, c4), + (13, 4, c4), + ] + + width = 16 * (size + gap) + height = 15 * (size + gap) + + canvas = ft.Stack( + width=width, + height=height, + animate_scale=duration, + animate_opacity=duration, + scale=5 if scattered else 1, + opacity=0.3 if scattered else 1, + ) + + # spread parts randomly + for i in range(len(parts)): + canvas.controls.append( + ft.Container( + animate=duration, + animate_position=duration, + animate_rotation=duration, + left=random.randrange(0, width) + if scattered + else parts[i][0] * (size + gap), + top=random.randrange(0, height) + if scattered + else parts[i][1] * (size + gap), + bgcolor=all_colors[random.randrange(0, len(all_colors))] + if scattered + else parts[i][2], + width=random.randrange(int(size / 2), int(size * 3)) + if scattered + else size, + height=random.randrange(int(size / 2), int(size * 3)) + if scattered + else size, + border_radius=random.randrange(0, int(size / 2)) if scattered else 5, + rotate=random.randrange(0, 90) * 2 * pi / 360 if scattered else 0, + ) + ) + + go_button = ft.Button("Go!", on_click=lambda e: set_scattered(False)) + again_button = ft.Button("Again!", on_click=lambda e: set_scattered(True)) + + return ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + tight=True, + controls=[ + canvas, + go_button if scattered else again_button, + ], + ), + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/material_controls.py b/sdk/python/examples/apps/studio_gallery/material_controls.py new file mode 100644 index 0000000000..e8cc07893a --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/material_controls.py @@ -0,0 +1,225 @@ +import flet as ft + + +@ft.component +def GroupCard( + title: str = "Group Title", + controls: list | None = None, + elevation: int = 5, + margin=None, + padding: int = 20, +): + """Reusable card that groups a list of controls with an optional title. + + Args: + title: Optional title shown at the top of the card. + controls: A list of `ft.Control` instances to display inside the card. + elevation: Card elevation. + margin: Card margin. + padding: Inner padding for the card content container. + """ + if margin is None: + margin = ft.Margin.all(10) + if controls is None: + controls = [] + content_controls = [] + if title: + content_controls.append( + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + title, + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=16, + color=ft.Colors.PRIMARY, + ), + ) + ], + ) + ) + if controls: + content_controls.extend(controls) + + return ft.Card( + content=ft.Container( + expand=True, + padding=padding, + content=ft.Column(controls=content_controls, expand=True), + ), + elevation=elevation, + margin=margin, + expand=True, + ) + + +@ft.component +def App(): + return ft.Column( + scroll=ft.ScrollMode.AUTO, + expand=True, + alignment=ft.MainAxisAlignment.START, + controls=[ + GroupCard( + title="Input Controls", + controls=[ + ft.Checkbox(label="Checkbox"), + ft.Switch(label="Switch"), + ft.RadioGroup( + content=ft.Column( + controls=[ + ft.Radio(label="Radio 1", value="r1"), + ft.Radio(label="Radio 2", value="r2"), + ] + ) + ), + ft.Slider(min=0, max=100, divisions=10, label="{value}"), + ft.TextField(label="Text Field"), + ft.Dropdown( + label="Dropdown", + options=[ + ft.dropdown.Option("Option 1"), + ft.dropdown.Option("Option 2"), + ft.dropdown.Option("Option 3"), + ], + ), + ], + ), + GroupCard( + title="Dialogs", + controls=[ + ft.Row( + controls=[ + ft.TextButton( + "Show Dialog", + on_click=lambda e: e.page.show_dialog( + ft.AlertDialog( + content=ft.Text("Hello from Flet!"), + actions=[ + ft.TextButton( + "OK", + on_click=lambda ev: ev.page.pop_dialog(), # noqa: E501 + ) + ], + ) + ), + ), + ft.TextButton( + "Show Banner", + on_click=lambda e: e.page.show_dialog( + ft.Banner( + leading=ft.Icon( + ft.Icons.INFO_OUTLINED, + color=ft.Colors.PRIMARY, + ), + content=ft.Text( + "Backup completed successfully." + ), + actions=[ + ft.TextButton( + "Dismiss", + on_click=lambda ev: ev.page.pop_dialog(), # noqa: E501 + ) + ], + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + open=True, + ), + ), + ), + ], + ), + ft.Row( + controls=[ + ft.TextButton( + "Show DatePicker", + on_click=lambda e: e.page.show_dialog( + ft.DatePicker(), + ), + ), + ft.TextButton( + "Show TimePicker", + on_click=lambda e: e.page.show_dialog( + ft.TimePicker(), + ), + ), + ], + ), + ], + ), + GroupCard( + title="Buttons", + controls=[ + ft.Row( + [ + ft.Button( + content="Button", + expand=1, + ), + ft.Button( + content="Button", + disabled=True, + expand=1, + ), + ] + ), + ft.Row( + [ + ft.FilledButton( + content="Filled", + expand=1, + ), + ft.FilledButton( + content="Filled", + disabled=True, + expand=1, + ), + ] + ), + ft.Row( + [ + ft.FilledTonalButton( + content="FilledTonal", + expand=1, + ), + ft.FilledTonalButton( + content="FilledTonal", + disabled=True, + expand=1, + ), + ] + ), + ft.Row( + [ + ft.OutlinedButton( + content="Outlined", + expand=1, + ), + ft.OutlinedButton( + content="Outlined", + disabled=True, + expand=1, + ), + ] + ), + ft.Row( + [ + ft.TextButton( + content="Text Button", + expand=1, + ), + ft.TextButton( + content="Text Button", + disabled=True, + expand=1, + ), + ] + ), + ], + ), + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/minesweeper.py b/sdk/python/examples/apps/studio_gallery/minesweeper.py new file mode 100644 index 0000000000..94246e2903 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/minesweeper.py @@ -0,0 +1,348 @@ +import asyncio +import random +from dataclasses import dataclass +from typing import Optional + +import flet as ft + +SQUARE_SIZE = 30 + +LIGHT = ft.Colors.WHITE_70 +DARK = ft.Colors.BLACK_38 + +BEVEL_RAISED = ft.Border( + bottom=ft.BorderSide(4, DARK), + right=ft.BorderSide(4, DARK), + top=ft.BorderSide(4, LIGHT), + left=ft.BorderSide(4, LIGHT), +) + +BEVEL_SUNKEN = ft.Border( + bottom=ft.BorderSide(4, LIGHT), + right=ft.BorderSide(4, LIGHT), + top=ft.BorderSide(4, DARK), + left=ft.BorderSide(4, DARK), +) + + +@ft.observable +@dataclass +class Square: + top: float = 0 + left: float = 0 + mine: bool = False + revealed: bool = False + flagged: bool = False + exploded: bool = False + adjacent_mines: int = 0 + + +@ft.observable +@dataclass +class Game: + squares: Optional[list[Square]] = None # to be initialized in __post_init__ + rows: int = 9 + cols: int = 9 + mine_count: int = 10 + mines_left: int = 10 + over = False + won = False + # timer + seconds: int = 0 # elapsed time + running: bool = False # ticking or not + first_click_done: bool = False + + def __post_init__(self): + """Initialize the grid of squares.""" + self.squares = [] + for r in range(self.rows): + for c in range(self.cols): + self.squares.append(Square(left=c * SQUARE_SIZE, top=r * SQUARE_SIZE)) + + # place mines + mine_positions = random.sample(range(len(self.squares)), self.mine_count) + for pos in mine_positions: + self.squares[pos].mine = True + + # calculate adjacent mine counts + for r in range(self.rows): + for c in range(self.cols): + idx = r * self.cols + c + if self.squares[idx].mine: + continue + count = 0 + for dr in (-1, 0, 1): + for dc in (-1, 0, 1): + if dr == 0 and dc == 0: + continue + nr, nc = r + dr, c + dc + if 0 <= nr < self.rows and 0 <= nc < self.cols: + nidx = nr * self.cols + nc + if self.squares[nidx].mine: + count += 1 + self.squares[idx].adjacent_mines = count + + def square_revealed(self, square: Square): + square.revealed = True + if square.mine: + square.exploded = True + self.over = True + for sq in self.squares: + if sq.mine: + sq.revealed = True + print("Game Over!") + elif square.adjacent_mines == 0: + # reveal adjacent squares + r = int(square.top / SQUARE_SIZE) + c = int(square.left / SQUARE_SIZE) + for dr in (-1, 0, 1): + for dc in (-1, 0, 1): + if dr == 0 and dc == 0: + continue + nr, nc = r + dr, c + dc + if 0 <= nr < self.rows and 0 <= nc < self.cols: + nidx = nr * self.cols + nc + nsq = self.squares[nidx] + if not nsq.revealed and not nsq.mine and not nsq.flagged: + self.square_revealed(nsq) + # check for win + if all(sq.revealed or sq.mine for sq in self.squares): + self.over = True + self.won = True + for sq in self.squares: + if sq.mine and not sq.flagged: + sq.flagged = True + print("You Win!") + + def square_flagged(self, square: Square): + if not square.revealed: + square.flagged = not square.flagged + self.mines_left += -1 if square.flagged else 1 + + +@ft.component +def SquareView(square: Square) -> ft.Control: + return ft.Container( + bgcolor=( + ft.Colors.RED_900 + if square.exploded + else ft.Colors.GREY_300 + if square.revealed + else ft.Colors.GREY_400 + ), + alignment=ft.Alignment.CENTER, + foreground_decoration=ft.BoxDecoration( + border=BEVEL_RAISED if not square.revealed else None + ), + content=ft.Text( + "💥" + if square.exploded + else "💣" + if square.revealed and square.mine + else "🚩" + if square.flagged + else str(square.adjacent_mines) + if square.revealed and square.adjacent_mines > 0 + else "", + size=SQUARE_SIZE * 0.6, + weight=ft.FontWeight.BOLD, + color=( + ft.Colors.BLUE + if square.adjacent_mines == 1 + else ft.Colors.GREEN + if square.adjacent_mines == 2 + else ft.Colors.RED + if square.adjacent_mines == 3 + else ft.Colors.ORANGE + if square.adjacent_mines == 4 + else ft.Colors.PURPLE + if square.adjacent_mines == 5 + else ft.Colors.BROWN + if square.adjacent_mines == 6 + else ft.Colors.TEAL + if square.adjacent_mines == 7 + else ft.Colors.BLACK + if square.adjacent_mines == 8 + else ft.Colors.BLACK + ), + ), + left=square.left, + top=square.top, + border=ft.Border.all(1, ft.Colors.GREY_500) if square.revealed else None, + width=SQUARE_SIZE, + height=SQUARE_SIZE, + ) + + +@ft.component +def App(): + game, set_game = ft.use_state(lambda: Game()) + new_game_tapped, set_new_game_tapped = ft.use_state(False) + + ticker_task, set_ticker_task = ft.use_state(None) + is_mobile = ft.context.page.platform in ( + ft.PagePlatform.ANDROID, + ft.PagePlatform.IOS, + ) + + def end_game(): + game.running = False + if ticker_task and not ticker_task.done(): + ticker_task.cancel() + + ft.on_unmounted(end_game) + + async def tick_loop(): + try: + while True: + await asyncio.sleep(1) + if not game.running or game.over: + break + game.seconds += 1 + print("Timer:", game.seconds) + except asyncio.CancelledError: + pass + + def ensure_ticker(): + if ticker_task is None or ticker_task.done(): + t = ft.context.page.run_task(tick_loop) + set_ticker_task(t) + + last_tap_pos_ref = ft.use_ref(None) + + def on_tap_down(e: ft.TapEvent): + last_tap_pos_ref.current = (e.local_position.x, e.local_position.y) + + def on_tap(e: ft.TapEvent): + if game.over: + return + + x, y = last_tap_pos_ref.current + + if not game.first_click_done: + game.first_click_done = True + game.running = True + ensure_ticker() + print("Timer started") + + for s in game.squares: + if ( + s.left <= x <= s.left + SQUARE_SIZE + and s.top <= y <= s.top + SQUARE_SIZE + ): + if s.flagged: + print("square is flagged, cannot reveal") + return + game.square_revealed(s) + break + + def on_right_pan_start(e): + if game.over: + return + if not game.first_click_done: + game.first_click_done = True + game.running = True + print("Timer started") + for s in game.squares: + if ( + s.left <= e.local_position.x <= s.left + SQUARE_SIZE + and s.top <= e.local_position.y <= s.top + SQUARE_SIZE + ): + game.square_flagged(s) + break + + board = ft.GestureDetector( + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + on_tap_down=on_tap_down, + on_tap=on_tap, + on_right_pan_start=on_right_pan_start if not is_mobile else None, + on_long_press_start=on_right_pan_start if is_mobile else None, + content=ft.Stack( + controls=[SquareView(c) for c in game.squares], + ), + ) + + top_menu = ft.Row( + controls=[ + ft.Container( + height=50, + width=90, + alignment=ft.Alignment.CENTER, + content=ft.Text( + f"{game.mines_left:03d}", + size=25, + weight=ft.FontWeight.BOLD, + color=ft.Colors.RED, + ), + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + ), + ft.Container( + content=ft.Text( + "🙂" if not game.over else "😎" if game.won else "😵", size=35 + ), + # 😎 😵😢 + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.GREY_400, + on_tap_down=lambda e: set_new_game_tapped(True), + on_click=lambda e: ( + set_game(Game()), + set_new_game_tapped(False), + ticker_task.cancel() + if ticker_task and not ticker_task.done() + else None, + ), + width=50, + height=50, + foreground_decoration=ft.BoxDecoration( + border=BEVEL_RAISED if not new_game_tapped else None + ), + ), + ft.Container( + height=50, + width=90, + alignment=ft.Alignment.CENTER, + content=ft.Text( + f"{game.seconds:03d}", + size=25, + weight=ft.FontWeight.BOLD, + color=ft.Colors.RED, + ), + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + ), + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + expand=True, + ) + + return ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Column( + controls=[ + ft.Container( + content=top_menu, + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + padding=10, + ), + ft.Container( + content=board, + foreground_decoration=ft.BoxDecoration(border=BEVEL_SUNKEN), + padding=5, + height=SQUARE_SIZE * game.rows + 10, + width=SQUARE_SIZE * game.cols + 10, + ), + ], + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.START, + spacing=10, + ), + bgcolor=ft.Colors.GREY_400, + foreground_decoration=ft.BoxDecoration(border=BEVEL_RAISED), + width=SQUARE_SIZE * (game.cols + 1), + height=SQUARE_SIZE * (game.rows + 1) + 100, + padding=10, + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/todo.py b/sdk/python/examples/apps/studio_gallery/todo.py new file mode 100644 index 0000000000..fc3e661ab9 --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/todo.py @@ -0,0 +1,216 @@ +from dataclasses import dataclass, field +from typing import Callable, cast + +import flet as ft + +TaskID = ft.IdCounter() + + +@ft.observable +@dataclass +class TaskItem: + name: str + completed: bool = False + id: int = field(default_factory=TaskID) + on_status_changed: Callable | None = None + + def update_task(self, new_name: str): + self.name = new_name + + def toggle_task_status(self): + self.completed = not self.completed + if self.on_status_changed: + self.on_status_changed() + + +@ft.observable +@dataclass +class TodoAppState: + tasks: list[TaskItem] = field(default_factory=list) + statuses: list[str] = field(default_factory=lambda: ["all", "active", "completed"]) + status: str = "all" + + def get_tasks(self) -> list[TaskItem]: + return list( + filter( + lambda task: self.status == "all" + or self.status == "active" + and not task.completed + or self.status == "completed" + and task.completed, + self.tasks, + ) + ) + + @property + def active_tasks_number(self) -> int: + return len([task for task in self.tasks if not task.completed]) + + def status_changed(self, e: ft.Event[ft.Tabs]): + self.status = self.statuses[e.control.selected_index] + + def on_task_status_changed(self): + cast(ft.Observable, self).notify() + + def add_task(self, new_task_event: str): + self.tasks.append( + TaskItem(new_task_event, on_status_changed=self.on_task_status_changed) + ) + + def delete_task(self, task: TaskItem): + self.tasks.remove(task) + + def clear_completed(self): + self.tasks = list(filter(lambda task: not task.completed, self.tasks)) + + +@ft.component +def Header(): + return ft.Row( + [ + ft.Text( + value="Todos", + theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM, + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + + +@ft.component +def TaskItemView(task: TaskItem, delete_task, key=None) -> ft.Control: + edit_mode, set_edit_mode = ft.use_state(False) + new_name, set_new_name = ft.use_state("") + + def edit(): + set_edit_mode(True) + set_new_name(task.name) + + def complete_edit(): + task.update_task(new_name) + set_edit_mode(False) + + return ( + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Checkbox( + value=task.completed, + label=task.name, + on_change=lambda: task.toggle_task_status(), + ), + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=edit, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=lambda: delete_task(task), + ), + ], + ), + ], + ) + if not edit_mode + else ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.TextField( + value=new_name, + on_change=lambda e: set_new_name(e.control.value), + expand=1, + ), + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=complete_edit, + ), + ], + ) + ) + + +@ft.component +def Footer(active_tasks_number: int, clear_completed): + return ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(f"{active_tasks_number} items left"), + ft.OutlinedButton( + content="Clear completed", + on_click=clear_completed, + ), + ], + ) + + +@ft.component +def App(): + state, _ = ft.use_state(lambda: TodoAppState()) + new_task_name, set_new_task_name = ft.use_state("") + new_task_field: ft.Ref = ft.Ref() + + async def add_task(): + state.add_task(new_task_name) + set_new_task_name("") + await cast(ft.TextField, new_task_field.current).focus() + + return ft.Column( + [ + Header(), + ft.Row( + controls=[ + ft.TextField( + ref=new_task_field, + hint_text="What needs to be done?", + on_submit=add_task, + value=new_task_name, + on_change=lambda e: set_new_task_name(e.control.value), + autofocus=True, + expand=True, + ), + ft.FloatingActionButton( + icon=ft.Icons.ADD, + on_click=add_task, + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + ft.Tabs( + selected_index=state.statuses.index(state.status), + length=len(state.statuses), + on_change=state.status_changed, + content=ft.TabBar( + scrollable=False, + tabs=[ft.Tab(label=tab) for tab in state.statuses], + ), + ), + ft.Column( + [ + TaskItemView(task, state.delete_task, key=task.id) + for task in state.get_tasks() + ] + ), + Footer( + active_tasks_number=state.active_tasks_number, + clear_completed=state.clear_completed, + ), + ], + ), + ] + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/studio_gallery/video_player.py b/sdk/python/examples/apps/studio_gallery/video_player.py new file mode 100644 index 0000000000..a14ffcdfac --- /dev/null +++ b/sdk/python/examples/apps/studio_gallery/video_player.py @@ -0,0 +1,125 @@ +import flet as ft +import flet_video as ftv + + +@ft.component +def App(): + fullscreen, set_fullscreen = ft.use_state(False) + volume, set_volume = ft.use_state(100) + playback_rate, set_playback_rate = ft.use_state(1.0) + + sample_media = [ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4", + extras={ + "artist": "Thousand Foot Krutch", + "album": "The End Is Where We Begin", + }, + http_headers={ + "Foo": "Bar", + "Accept": "*/*", + }, + ), + ] + + async def handle_pause(e: ft.Event[ft.Button]): + await video.pause() + + async def handle_play_or_pause(e: ft.Event[ft.Button]): + await video.play_or_pause() + + async def handle_play(e: ft.Event[ft.Button]): + await video.play() + + async def handle_stop(e: ft.Event[ft.Button]): + await video.stop() + + async def handle_next(e: ft.Event[ft.Button]): + await video.next() + + async def handle_previous(e: ft.Event[ft.Button]): + await video.previous() + + def handle_volume_change(e: ft.Event[ft.Slider]): + set_volume(e.control.value) + + def handle_playback_rate_change(e: ft.Event[ft.Slider]): + set_playback_rate(e.control.value) + + async def handle_seek(e: ft.Event[ft.Button]): + await video.seek(10000) + + async def handle_fullscreen(e: ft.Event[ft.Button]): + set_fullscreen(True) + + return ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + video := ftv.Video( + expand=True, + fullscreen=fullscreen, + playlist=sample_media[0:2], + playlist_mode=ftv.PlaylistMode.LOOP, + aspect_ratio=16 / 9, + volume=volume, + playback_rate=playback_rate, + autoplay=False, + filter_quality=ft.FilterQuality.HIGH, + muted=False, + on_load=lambda e: print("Video loaded successfully!"), + on_enter_fullscreen=lambda e: set_fullscreen(True), + on_exit_fullscreen=lambda e: set_fullscreen(False), + ), + ft.Row( + wrap=True, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button("Play", on_click=handle_play), + ft.Button("Pause", on_click=handle_pause), + ft.Button("Play Or Pause", on_click=handle_play_or_pause), + ft.Button("Stop", on_click=handle_stop), + ft.Button("Next", on_click=handle_next), + ft.Button("Previous", on_click=handle_previous), + ft.Button("Seek s=10", on_click=handle_seek), + ft.Button("Enter Fullscreen", on_click=handle_fullscreen), + ], + ), + ft.Slider( + min=0, + value=volume, + max=100, + label="Volume = {value}%", + divisions=10, + width=400, + on_change=handle_volume_change, + ), + ft.Slider( + min=1, + value=playback_rate, + max=3, + label="Playback rate = {value}X", + divisions=6, + width=400, + on_change=handle_playback_rate_change, + ), + ], + ), + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/apps/templates/basic_counter/.gitignore b/sdk/python/examples/apps/templates/basic_counter/.gitignore new file mode 100644 index 0000000000..b85f2b72cb --- /dev/null +++ b/sdk/python/examples/apps/templates/basic_counter/.gitignore @@ -0,0 +1,220 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[codz] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py.cover +*.lcov +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +# Pipfile.lock + +# UV +# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# uv.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +# poetry.lock +# poetry.toml + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. +# https://pdm-project.org/en/latest/usage/project/#working-with-version-control +# pdm.lock +# pdm.toml +.pdm-python +.pdm-build/ + +# pixi +# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. +# pixi.lock +# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one +# in the .venv directory. It is recommended not to include this directory in version control. +.pixi/* +!.pixi/config.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule* +celerybeat.pid + +# Redis +*.rdb +*.aof +*.pid + +# RabbitMQ +mnesia/ +rabbitmq/ +rabbitmq-data/ + +# ActiveMQ +activemq-data/ + +# SageMath parsed files +*.sage.py + +# Environments +.env +.envrc +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +# .idea/ + +# Abstra +# Abstra is an AI-powered process automation framework. +# Ignore directories containing user credentials, local state, and settings. +# Learn more at https://abstra.io/docs +.abstra/ + +# Visual Studio Code +# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore +# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore +# and can be added to the global gitignore or merged into this file. However, if you prefer, +# you could uncomment the following to ignore the entire vscode folder +# .vscode/ +# Temporary file for partial code execution +tempCodeRunnerFile.py + +# Ruff stuff: +.ruff_cache/ + +# PyPI configuration file +.pypirc + +# Marimo +marimo/_static/ +marimo/_lsp/ +__marimo__/ + +# Streamlit +.streamlit/secrets.toml \ No newline at end of file diff --git a/sdk/python/examples/apps/templates/basic_counter/main.py b/sdk/python/examples/apps/templates/basic_counter/main.py new file mode 100644 index 0000000000..f8dda08180 --- /dev/null +++ b/sdk/python/examples/apps/templates/basic_counter/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + counter = ft.Text("0", size=50, data=0) + + def increment_click(e): + counter.data += 1 + counter.value = str(counter.data) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=increment_click + ) + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + content=counter, + alignment=ft.Alignment.CENTER, + ), + ) + ) + + +ft.run(main) diff --git a/sdk/python/examples/apps/templates/basic_counter/pyproject.toml b/sdk/python/examples/apps/templates/basic_counter/pyproject.toml new file mode 100644 index 0000000000..d3fdd90a02 --- /dev/null +++ b/sdk/python/examples/apps/templates/basic_counter/pyproject.toml @@ -0,0 +1,29 @@ +[project] +name = "flet-app" +version = "1.0.0" +description = "A simple counter with increment button." +requires-python = ">=3.10" +authors = [ + { name = "Flet developer", email = "you@example.com" } +] +dependencies = [ + "flet" +] + +[dependency-groups] +dev = [ + "flet-cli", + "flet-desktop", + "flet-web" +] + +[tool.flet.metadata] +title = "Basic Counter" + +[tool.flet.gallery] +categories = ["Getting Started"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/timer/basic/main.py b/sdk/python/examples/apps/timer/basic/main.py new file mode 100644 index 0000000000..1db6e6adab --- /dev/null +++ b/sdk/python/examples/apps/timer/basic/main.py @@ -0,0 +1,113 @@ +import asyncio +import time + +import flet as ft + + +def format_hhmmss(seconds: int) -> str: + """Convert elapsed seconds into HH:MM:SS string.""" + h = seconds // 3600 + m = (seconds % 3600) // 60 + s = seconds % 60 + return f"{h:02}:{m:02}:{s:02}" + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + running = False + paused = False + elapsed = 0 + base_elapsed = 0 + started_at = 0.0 + + def sync_ui(): + nonlocal elapsed + timer.value = format_hhmmss(elapsed) + + if running and not paused: + toggle_btn.text = "Pause" + toggle_btn.icon = ft.Icons.PAUSE + else: + toggle_btn.text = "Start" + toggle_btn.icon = ft.Icons.PLAY_ARROW + + stop_btn.disabled = (not running) and (elapsed == 0) + page.update() + + async def ticker(): + nonlocal elapsed + while running: + if not paused: + elapsed = base_elapsed + int(time.time() - started_at) + timer.value = format_hhmmss(elapsed) + timer.update() + await asyncio.sleep(1) + + def handle_toggle(): + nonlocal running, paused, elapsed, base_elapsed, started_at + + if not running: + running = True + paused = False + base_elapsed = elapsed + started_at = time.time() + page.run_task(ticker) + sync_ui() + return + + if not paused: + base_elapsed += int(time.time() - started_at) + elapsed = base_elapsed + paused = True + sync_ui() + return + + paused = False + started_at = time.time() + sync_ui() + + def handle_stop(): + nonlocal running, paused, elapsed, base_elapsed, started_at + running = False + paused = False + elapsed = 0 + base_elapsed = 0 + started_at = 0.0 + sync_ui() + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=20, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + timer := ft.Text("00:00:00", size=30, weight=ft.FontWeight.BOLD), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + toggle_btn := ft.FilledButton( + "Start", + icon=ft.Icons.PLAY_ARROW, + on_click=handle_toggle, + ), + stop_btn := ft.TextButton( + "Stop", + icon=ft.Icons.STOP, + disabled=True, + on_click=handle_stop, + ), + ], + ), + ], + ) + ) + ) + + sync_ui() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/timer/basic/pyproject.toml b/sdk/python/examples/apps/timer/basic/pyproject.toml new file mode 100644 index 0000000000..1f13eac98f --- /dev/null +++ b/sdk/python/examples/apps/timer/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-timer-basic" +version = "1.0.0" +description = "Stopwatch example with start, pause, resume, and stop controls." +requires-python = ">=3.10" +keywords = ["apps", "timer", "stopwatch", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Cookbook"] + +[tool.flet.metadata] +title = "Basic timer" +controls = ["SafeArea", "Column", "Row", "Text", "FilledButton", "TextButton"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["async", "timer controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/apps/todo/basic/main.py b/sdk/python/examples/apps/todo/basic/main.py new file mode 100644 index 0000000000..39c6ec80ce --- /dev/null +++ b/sdk/python/examples/apps/todo/basic/main.py @@ -0,0 +1,168 @@ +import flet as ft + + +class Task(ft.Column): + def __init__(self, task_name, task_delete): + super().__init__() + self.completed = False + self.task_name = task_name + self.task_delete = task_delete + + def build(self): + self.display_task = ft.Checkbox( + value=False, label=self.task_name, on_change=self.status_changed + ) + self.edit_name = ft.TextField(expand=1) + + self.display_view = ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.display_task, + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=self.edit_clicked, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=self.delete_clicked, + ), + ], + ), + ], + ) + + self.edit_view = ft.Row( + visible=False, + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.edit_name, + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=self.save_clicked, + ), + ], + ) + self.controls = [self.display_view, self.edit_view] + + def edit_clicked(self, e): + self.edit_name.value = self.display_task.label + self.display_view.visible = False + self.edit_view.visible = True + + def save_clicked(self, e): + self.display_task.label = self.edit_name.value + self.display_view.visible = True + self.edit_view.visible = False + + def status_changed(self, e): + self.completed = self.display_task.value + + def delete_clicked(self, e): + self.task_delete(self) + + +class TodoApp(ft.Column): + def build(self): + self.new_task = ft.TextField( + hint_text="What needs to be done?", on_submit=self.add_clicked, expand=True + ) + self.tasks = ft.Column() + + self.filter = ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label="all"), + ft.Tab(label="active"), + ft.Tab(label="completed"), + ], + ) + + self.filter_tabs = ft.Tabs( + length=3, + selected_index=0, + on_change=lambda e: self.update(), + content=self.filter, + ) + + self.items_left = ft.Text("0 items left") + + self.width = 600 + self.controls = [ + ft.Row( + [ft.Text(value="Todos", theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM)], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Row( + controls=[ + self.new_task, + ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=self.add_clicked + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + self.filter_tabs, + self.tasks, + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.items_left, + ft.OutlinedButton( + content="Clear completed", on_click=self.clear_clicked + ), + ], + ), + ], + ), + ] + + async def add_clicked(self, e): + if self.new_task.value: + task = Task(self.new_task.value, self.task_delete) + self.tasks.controls.append(task) + self.new_task.value = "" + await self.new_task.focus() + + def task_delete(self, task): + self.tasks.controls.remove(task) + + def clear_clicked(self, e): + for task in self.tasks.controls[:]: + if task.completed: + self.task_delete(task) + + def before_update(self): + status = self.filter.tabs[self.filter_tabs.selected_index].label + count = 0 + for task in self.tasks.controls: + task.visible = ( + status == "all" + or (status == "active" and not task.completed) + or (status == "completed" and task.completed) + ) + if not task.completed: + count += 1 + self.items_left.value = f"{count} active item(s) left" + + +def main(page: ft.Page): + page.title = "ToDo App" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.ADAPTIVE + page.add(ft.SafeArea(content=TodoApp())) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/apps/todo/basic/pyproject.toml b/sdk/python/examples/apps/todo/basic/pyproject.toml new file mode 100644 index 0000000000..45bf5d9f65 --- /dev/null +++ b/sdk/python/examples/apps/todo/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "apps-todo-classic" +version = "1.0.0" +description = "Classic to-do app with add, edit, delete, and filter interactions inspired by TodoMVC." +requires-python = ">=3.10" +keywords = ["apps", "todo", "tasks", "tabs", "forms"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured", "Getting Started"] + +[tool.flet.metadata] +title = "Classic To-Do" +controls = ["SafeArea", "Column", "Row", "TextField", "Tabs", "TabBar", "Checkbox", "IconButton", "FloatingActionButton", "OutlinedButton", "Text"] +layout_pattern = "form" +complexity = "intermediate" +features = ["task editing", "task filtering", "list state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/community/mind_queue/README.md b/sdk/python/examples/community/mind_queue/README.md new file mode 100644 index 0000000000..d2a81e4c17 --- /dev/null +++ b/sdk/python/examples/community/mind_queue/README.md @@ -0,0 +1,126 @@ +# **Mind Queue** + +Mind Queue is a minimalist productivity app built with **Flet (Python + Flutter UI)**. +It helps you organize your life into **Systems → Headers → Tasks**, with a focus on simplicity, speed, and clarity. + +--- + +## **Features** + +* Create / edit / delete multiple **systems** +* Add / rename / delete **headers** +* Add / edit / delete **tasks** +* Mark tasks **done / undone** +* Confirmation dialog before deleting a system +* Clean dark UI +* Persistent local storage using `data.json` (for now) + +--- + +## **Controls** + +| Action | Location | +| ------------- | ----------------------------------- | +| Add system | Dashboard | +| Open system | Click a system card | +| Add header | Bottom of system page | +| Add task | At the end of each header | +| Edit | Pencil icon | +| Delete | Trash icon | +| Delete system | Bottom red button with confirmation | +| Toggle done | Checkbox | + +--- + +## **How It Works** + +| Level | Example | Purpose | +| ------ | --------------------------- | --------------------------- | +| System | *Daily Routine* | Entire workflow | +| Header | *Morning / Work / Night* | Sections inside a system | +| Task | *Exercise, Coding, Reading* | Individual actionable items | + +--- + +## **Data Storage** + +All data is stored locally in `assets/data.json`: + +```json +{ + "SystemName": { + "HeaderName": [ + ["TaskTitle", "Description", false] + ] + } +} +``` + +Make sure a `data.json` file exists. If not, create a demo one: + +```json +{ + "Daily Routine": { + "Morning": [ + ["7:00 AM", "Wake up & Meditation", false], + ["7:15 AM", "Walk", true], + ["7:45 AM", "Breakfast", false], + ["8:00 AM", "Cooking & Cleaning", true], + ["9:00 AM", "Bath & Ready for office", false] + ], + "Work": [ + ["10:00 AM", "Log in", true], + ["2:00 PM", "Lunch", false], + ["7:00 PM", "Log out", false] + ], + "Night": [ + ["8:30 PM", "Reach Home", false], + ["9:00 PM", "Dinner", false], + ["9:30 PM", "Productivity", true], + ["11:00 PM", "No phone, self-care, meditation", false], + ["12:00 AM", "Sleep", false] + ] + } +} +``` + +--- + +## **Run the App** + +### **Install dependencies** + +```bash +pip install uv +uv sync +``` + +### **Run** + +```bash +uv run python main.py +``` + +### **Run on Mobile** + +1. [Install Flet App for Mobile](https://flet.dev/docs/getting-started/testing-on-mobile/) +2. Then, run +``` +uv run flet run --android +uv run flet run --ios +``` + +--- + +## **Future Enhancements** + +* Daily auto reset +* Progress tracking & statistics +* Cloud sync / login +* Store data to sqlite3 + +--- + +## **License** + +Free to use, customize, and improve. diff --git a/sdk/python/examples/community/mind_queue/assets/data.json b/sdk/python/examples/community/mind_queue/assets/data.json new file mode 100644 index 0000000000..fe159da64e --- /dev/null +++ b/sdk/python/examples/community/mind_queue/assets/data.json @@ -0,0 +1,64 @@ +{ + "House Chores": { + "Monday": [ + [ + "Morning", + "Cook Meal", + true + ], + [ + "Evening", + "Vacuum", + false + ] + ], + "Tuesday": [ + [ + "Morning", + "Cook Meal", + false + ], + [ + "Evening", + "Mopping", + true + ] + ], + "Wednesday": [ + [ + "Morning", + "Washing Clothes", + false + ], + [ + "Evening", + "Vacuum", + false + ] + ], + "Thursday": [ + [ + "Morning", + "Cook Meal", + true + ], + [ + "Evening", + "Mopping", + true + ] + ], + "Friday": [ + [ + "Morning", + "Washing Clothes", + true + ], + [ + "Evening", + "Deep Cleaning", + false + ] + ] + } +} diff --git a/sdk/python/examples/community/mind_queue/main.py b/sdk/python/examples/community/mind_queue/main.py new file mode 100644 index 0000000000..53f785787c --- /dev/null +++ b/sdk/python/examples/community/mind_queue/main.py @@ -0,0 +1,711 @@ +import asyncio +import copy +import json +from pathlib import Path + +import flet as ft + +APP_NAME = "Mind Queue" +DATA_FILE = Path(__file__).resolve().parent / "assets" / "data.json" + + +def load_data(): + if not DATA_FILE.exists(): + raise FileNotFoundError(f"{DATA_FILE} not found") + with DATA_FILE.open("r", encoding="utf-8") as f: + return json.load(f) + + +def save_data(data): + with DATA_FILE.open("w", encoding="utf-8") as f: + json.dump(data, f, indent=4) + + +def main(page: ft.Page): + page.title = APP_NAME + page.theme_mode = ft.ThemeMode.DARK + page.bgcolor = "#111111" + page.padding = ft.Padding.symmetric(horizontal=24, vertical=24) + page.horizontal_alignment = ft.CrossAxisAlignment.START + page.vertical_alignment = ft.MainAxisAlignment.START + page.scroll = ft.ScrollMode.HIDDEN + + data = load_data() + current_system: str | None = None + + def handle_keyboard_event(e: ft.KeyboardEvent): + if e.key == "Escape" and current_system is not None: + show_dashboard() + + page.on_keyboard_event = handle_keyboard_event + + # ---------- Dialog helpers ---------- + def confirm_delete_system(system_name: str): + def do_delete(ev): + close_current_dialog() + delete_system(system_name) + + def do_cancel(ev): + close_current_dialog() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Confirm delete"), + content=ft.Text( + f"Delete '{system_name}' permanently?\n\nThis action cannot be undone." + ), + actions=[ + ft.TextButton("Cancel", on_click=do_cancel), + ft.TextButton( + "Delete", + icon=ft.Icons.DELETE_FOREVER, + icon_color="red", + on_click=do_delete, + ), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + open_dialog(dlg) + + def close_current_dialog(): + for ctl in page.overlay: + if isinstance(ctl, ft.AlertDialog): + ctl.open = False + page.update() + + def open_dialog(dialog: ft.AlertDialog): + if dialog not in page.overlay: + page.overlay.append(dialog) + dialog.open = True + page.update() + + # ---------- System ---------- + def clone_system(system_name: str): + if system_name not in data: + return + + base_name = f"Copy of {system_name}" + new_name = base_name + counter = 2 + + while new_name in data: + new_name = f"{base_name} ({counter})" + counter += 1 + + # deep copy to avoid shared references + data[new_name] = copy.deepcopy(data[system_name]) + save_data(data) + + def delete_system(system_name: str): + nonlocal current_system + if len(data.keys()) == 1: + return + data.pop(system_name, None) + save_data(data) + current_system = None + show_dashboard() + + # ---------- Dashboard ---------- + + def show_dashboard(e=None): + nonlocal current_system + current_system = None + + page.appbar = None + page.clean() + + title = ft.Row( + [ft.Text(APP_NAME, size=32, weight=ft.FontWeight.BOLD)], + alignment=ft.MainAxisAlignment.CENTER, + ) + + systems_list: list[ft.Control] = [] + + def open_system(system_name: str): + show_system(system_name) + + def open_system_actions(system_name: str): + def do_open(e): + close_current_dialog() + show_system(system_name) + + async def do_clone(e): + close_current_dialog() + clone_system(system_name) + await asyncio.sleep(0) + show_dashboard() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text(system_name), + actions=[ + # ft.TextButton("Open", on_click=do_open), + ft.TextButton( + "Clone", + icon=ft.Icons.CONTENT_COPY, + on_click=do_clone, + ), + ft.TextButton( + "Delete", + icon=ft.Icons.DELETE_OUTLINE, + icon_color=ft.Colors.RED, + disabled=len(data) == 1, + on_click=lambda e: confirm_delete_system(system_name), + ), + ft.TextButton("Cancel", on_click=lambda e: close_current_dialog()), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + open_dialog(dlg) + + for system_name in data: + gesture = ft.GestureDetector( + content=ft.Container( + ft.Row( + [ft.Text(system_name, size=18, weight=ft.FontWeight.W_600)], + ), + padding=10, + margin=ft.Margin.only(bottom=8), + border_radius=8, + bgcolor="#1c1c1c", + ), + on_tap=lambda e, n=system_name: open_system(n), + on_long_press_start=lambda e, n=system_name: open_system_actions(n), + mouse_cursor=ft.MouseCursor.CLICK, + ) + systems_list.append(gesture) + + def open_add_system_dialog(e): + name_field = ft.TextField(label="System name") + + def on_add(ev): + try: + name = name_field.value.strip() + + # simple validation instead of silently doing nothing + if not name: + name_field.error_text = "Name is required" + page.update() + return + + if name in data: + name_field.error_text = "System already exists" + page.update() + return + + # create system and persist + data[name] = {} + save_data(data) + + # close dialog and redraw dashboard + close_current_dialog() + show_dashboard() + + except Exception as ex: + # if *anything* goes wrong, don't freeze – log it + print("add_system error:", ex) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Add system"), + content=name_field, + actions=[ + ft.TextButton("Cancel", on_click=close_current_dialog), + ft.TextButton("Add", on_click=on_add), + ], + ) + open_dialog(dlg) + + add_system_btn = ft.FilledButton( + "Add system", icon=ft.Icons.ADD, on_click=open_add_system_dialog + ) + + page.add( + ft.SafeArea( + content=ft.Column( + [ + title, + ft.Column(systems_list, spacing=4), + ft.Container(height=14), + add_system_btn, + ], + spacing=12, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ) + ) + ) + page.update() + + # ---------- System View ---------- + + def show_system(system_name: str): + nonlocal current_system + current_system = system_name + system_data: dict[str, list[list]] = data.get(system_name, {}) + + def edit_system_name(): + name_field = ft.TextField(label="System name", value=system_name) + + def on_save(ev): + new_name = name_field.value.strip() + if not new_name or new_name == system_name or new_name in data: + close_current_dialog() + return + + data[new_name] = data.pop(system_name) + save_data(data) + close_current_dialog() + show_system(new_name) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Rename system"), + content=name_field, + actions=[ + ft.TextButton("Cancel", on_click=close_current_dialog), + ft.TextButton("Save", on_click=on_save), + ], + ) + open_dialog(dlg) + + page.appbar = ft.AppBar( + leading=ft.IconButton(icon=ft.Icons.ARROW_BACK, on_click=show_dashboard), + title=ft.Text(system_name, size=32, weight=ft.FontWeight.BOLD), + bgcolor=page.bgcolor, + center_title=True, + actions=[ + ft.IconButton( + icon=ft.Icons.EDIT, + tooltip="Rename", + on_click=lambda e: edit_system_name(), + ) + ], + ) + + page.clean() + content_controls: list[ft.Control] = [] + + # ---------- Task helpers ---------- + + def clone_task(header: str, index: int): + if header not in system_data: + return + tasks = system_data[header] + if index < 0 or index >= len(tasks): + return + + title, label, done = tasks[index] + + # Clone task (reset done) + cloned = [f"{title} (copy)", label, False] + + tasks.insert(index + 1, cloned) + save_data(data) + + def toggle_task(header: str, index: int, value: bool): + if header not in system_data: + return + if index < 0 or index >= len(system_data[header]): + return + try: + system_data[header][index][2] = value + save_data(data) + close_current_dialog() + show_system(system_name) + except Exception as ex: + print("toggle_task error:", ex) + + def delete_task(header: str, index: int): + if header not in system_data: + return + if index < 0 or index >= len(system_data[header]): + return + try: + system_data[header].pop(index) + save_data(data) + close_current_dialog() + show_system(system_name) + except Exception as ex: + print("delete_task error:", ex) + + def edit_task(header: str, index: int): + if header not in system_data: + return + if index < 0 or index >= len(system_data[header]): + return + + try: + title_val, label_val, done_val = system_data[header][index] + except Exception as ex: + print("edit_task load error:", ex) + return + + title_field = ft.TextField(label="Title", value=title_val) + label_field = ft.TextField(label="Task", value=label_val) + + def on_save(ev): + tl = title_field.value.strip() + lb = label_field.value.strip() + if not tl or not lb: + return + + if header not in system_data: + return + if index < 0 or index >= len(system_data[header]): + return + + try: + system_data[header][index][0] = tl + system_data[header][index][1] = lb + save_data(data) + close_current_dialog() + show_system(system_name) + except Exception as ex: + print("edit_task save error:", ex) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Edit task"), + content=ft.Column([title_field, label_field], tight=True), + actions=[ + ft.TextButton("Cancel", on_click=close_current_dialog), + ft.TextButton("Save", on_click=on_save), + ], + ) + open_dialog(dlg) + + def move_task(header: str, index: int, direction: int): + """Move a task up or down within its header (no UI calls here).""" + if header not in system_data: + return + tasks = system_data[header] + new_index = index + direction + if new_index < 0 or new_index >= len(tasks): + return + try: + tasks[index], tasks[new_index] = tasks[new_index], tasks[index] + save_data(data) + except Exception as ex: + print("move_task error:", ex) + + def open_task_actions(header: str, index: int): + """Long-press menu: Move up / Move down / Edit / Delete.""" + total = len(system_data.get(header, [])) + is_first = index == 0 + is_last = index == total - 1 + + def do_clone(ev): + close_current_dialog() + clone_task(header, index) + show_system(system_name) + + def do_move_up(ev): + close_current_dialog() + move_task(header, index, -1) + show_system(system_name) + + def do_move_down(ev): + close_current_dialog() + move_task(header, index, +1) + show_system(system_name) + + def do_edit(ev): + close_current_dialog() + edit_task(header, index) + + def do_delete(ev): + close_current_dialog() + delete_task(header, index) + + def do_cancel(ev): + close_current_dialog() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Task actions"), + actions=[ + ft.TextButton( + "Move up", + icon=ft.Icons.ARROW_UPWARD, + on_click=do_move_up, + disabled=is_first, + ), + ft.TextButton( + "Move down", + icon=ft.Icons.ARROW_DOWNWARD, + on_click=do_move_down, + disabled=is_last, + ), + ft.TextButton("Edit", on_click=do_edit), + ft.TextButton( + "Clone", + icon=ft.Icons.CONTENT_COPY, + on_click=do_clone, + ), + ft.TextButton( + "Delete", + icon=ft.Icons.DELETE_OUTLINE, + on_click=do_delete, + ), + ft.TextButton("Cancel", on_click=do_cancel), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + open_dialog(dlg) + + def add_task(header: str): + title_field = ft.TextField(label="Title") + label_field = ft.TextField(label="Task") + + def on_add(ev): + tl = title_field.value.strip() + lb = label_field.value.strip() + if not tl or not lb: + return + system_data.setdefault(header, []).append([tl, lb, False]) + save_data(data) + close_current_dialog() + show_system(system_name) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text(f"Add task to {header}"), + content=ft.Column([title_field, label_field], tight=True), + actions=[ + ft.TextButton("Cancel", on_click=close_current_dialog), + ft.TextButton("Add", on_click=on_add), + ], + ) + open_dialog(dlg) + + # ---------- Header helpers ---------- + + def delete_header(header: str): + system_data.pop(header, None) + save_data(data) + show_system(system_name) + + def edit_header(header: str): + name_field = ft.TextField(label="Header name", value=header) + + def on_save(ev): + new_name = name_field.value.strip() + if not new_name or new_name == header or new_name in system_data: + close_current_dialog() + return + + system_data[new_name] = system_data.pop(header) + save_data(data) + close_current_dialog() + show_system(system_name) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Rename header"), + content=name_field, + actions=[ + ft.TextButton("Cancel", on_click=close_current_dialog), + ft.TextButton("Save", on_click=on_save), + ], + ) + open_dialog(dlg) + + def add_header(): + name_field = ft.TextField(label="Header name") + + def on_add(ev): + name = name_field.value.strip() + if not name: + return + system_data[name] = [] + save_data(data) + close_current_dialog() + show_system(system_name) + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Add header"), + content=name_field, + actions=[ + ft.TextButton("Cancel", on_click=close_current_dialog), + ft.TextButton("Add", on_click=on_add), + ], + ) + open_dialog(dlg) + + # ---------- Draw headers + tasks ---------- + + def confirm_delete_header(header_name: str): + txt = ft.Text( + f"Delete '{header_name}' permanently?\nThis cannot be undone." + ) + + def do_delete(ev): + close_current_dialog() + delete_header(header_name) + + def do_cancel(ev): + close_current_dialog() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Confirm delete"), + content=txt, + actions=[ + ft.TextButton("Cancel", on_click=do_cancel), + ft.TextButton( + "Delete", icon=ft.Icons.DELETE_FOREVER, on_click=do_delete + ), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + open_dialog(dlg) + + for header_name, tasks in system_data.items(): + content_controls.append(ft.Container(height=10)) + + # header row + content_controls.append( + ft.Row( + [ + ft.Text(header_name, size=20, weight=ft.FontWeight.BOLD), + ft.Row( + [ + ft.IconButton( + icon=ft.Icons.EDIT, + tooltip="Rename", + on_click=lambda e, h=header_name: edit_header(h), + ), + ft.IconButton( + icon=ft.Icons.DELETE_OUTLINE, + icon_color="red", + tooltip="Delete", + on_click=lambda e, h=header_name: ( + confirm_delete_header(h) + ), + ), + ] + ), + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + ) + ) + + # tasks + for idx, (title_str, label, done) in enumerate(tasks): + current_index = idx # capture for lambdas + + color = ft.Colors.WHITE_70 if done else ft.Colors.WHITE + deco = ( + ft.TextDecoration.LINE_THROUGH if done else ft.TextDecoration.NONE + ) + + row = ft.Row( + [ + ft.Checkbox( + value=done, + width=24, + height=24, + on_change=lambda e, s=header_name, i=current_index: ( + toggle_task(s, i, e.control.value) + ), + ), + ft.Text( + title_str, + size=16, + weight=ft.FontWeight.BOLD, + color=color, + style=ft.TextStyle(decoration=deco), + ), + ft.Container(width=8), + ft.Text( + label, + size=16, + color=color, + style=ft.TextStyle(decoration=deco), + ), + ft.Container(expand=True), + ], + alignment=ft.MainAxisAlignment.START, + spacing=6, + ) + + gesture = ft.GestureDetector( + content=row, + on_tap=lambda e, s=header_name, i=current_index: edit_task(s, i), + on_long_press_start=lambda e, s=header_name, i=current_index: ( + open_task_actions(s, i) + ), + mouse_cursor=ft.MouseCursor.CLICK, + ) + content_controls.append(gesture) + + # add task button under this header + content_controls.append( + ft.FilledButton( + "Add task", + icon=ft.Icons.ADD, + on_click=lambda e, s=header_name: add_task(s), + ) + ) + + # bottom: add header + delete system + content_controls.append(ft.Container(height=16)) + + def confirm_delete_system(): + txt = ft.Text( + f"Delete '{system_name}' permanently?\nThis cannot be undone." + ) + + def do_delete(ev): + close_current_dialog() + delete_system(system_name) + + def do_cancel(ev): + close_current_dialog() + + dlg = ft.AlertDialog( + modal=True, + title=ft.Text("Confirm delete"), + content=txt, + actions=[ + ft.TextButton("Cancel", on_click=do_cancel), + ft.TextButton( + "Delete", icon=ft.Icons.DELETE_FOREVER, on_click=do_delete + ), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + open_dialog(dlg) + + content_controls.append( + ft.Row( + [ + ft.FilledButton( + "Add Header", + icon=ft.Icons.ADD, + on_click=lambda e: add_header(), + ), + ft.FilledButton( + "Delete System", + icon=ft.Icons.DELETE_FOREVER, + bgcolor="red", + color="white", + on_click=lambda e: confirm_delete_system(), + ), + ], + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + ) + ) + + page.add( + ft.SafeArea(content=ft.Column(content_controls, spacing=6, expand=True)) + ) + page.update() + + # start at dashboard + show_dashboard() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/community/mind_queue/pyproject.toml b/sdk/python/examples/community/mind_queue/pyproject.toml new file mode 100644 index 0000000000..154de61273 --- /dev/null +++ b/sdk/python/examples/community/mind_queue/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "community-mind-queue" +version = "1.0.0" +description = "Community productivity app for organizing systems, headers, and tasks with local JSON storage." +requires-python = ">=3.10" +keywords = ["community", "productivity", "tasks", "json storage", "dialogs"] +authors = [{ name = "Flet community", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Community"] + +[tool.flet.metadata] +title = "Mind Queue" +controls = ["SafeArea", "Column", "Row", "Text", "TextField", "Checkbox", "FilledButton", "IconButton", "AlertDialog", "AppBar"] +layout_pattern = "list-detail" +complexity = "intermediate" +features = ["task organization", "local persistence", "dialogs"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/animated_switcher/image_switch/main.py b/sdk/python/examples/controls/core/animated_switcher/image_switch/main.py new file mode 100644 index 0000000000..400b957016 --- /dev/null +++ b/sdk/python/examples/controls/core/animated_switcher/image_switch/main.py @@ -0,0 +1,38 @@ +import time + +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + switcher.content = ft.Image( + src=f"https://picsum.photos/200/300?{time.time()}", + width=200, + height=300, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + switcher := ft.AnimatedSwitcher( + content=ft.Image( + src="https://picsum.photos/200/300", + width=200, + height=300, + ), + transition=ft.AnimatedSwitcherTransition.SCALE, + duration=500, + reverse_duration=100, + switch_in_curve=ft.AnimationCurve.BOUNCE_OUT, + switch_out_curve=ft.AnimationCurve.BOUNCE_IN, + ), + ft.Button("Animate!", on_click=animate), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/animated_switcher/image_switch/pyproject.toml b/sdk/python/examples/controls/core/animated_switcher/image_switch/pyproject.toml new file mode 100644 index 0000000000..1c92219c45 --- /dev/null +++ b/sdk/python/examples/controls/core/animated_switcher/image_switch/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "animated-switcher-image-switch" +version = "1.0.0" +description = "Animated image switching with scale transition." +requires-python = ">=3.10" +keywords = ["animated switcher", "animation", "image", "transition", "scale"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/AnimatedSwitcher"] + +[tool.flet.metadata] +title = "Animate image switch" +controls = ["SafeArea", "Column", "AnimatedSwitcher", "Image", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dynamic image source", "scale transition", "button-triggered animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/animated_switcher/image_switch_buffered/main.py b/sdk/python/examples/controls/core/animated_switcher/image_switch_buffered/main.py new file mode 100644 index 0000000000..436f5867dd --- /dev/null +++ b/sdk/python/examples/controls/core/animated_switcher/image_switch_buffered/main.py @@ -0,0 +1,78 @@ +import base64 +import time +from dataclasses import field + +import httpx + +import flet as ft + + +@ft.control +class BufferingSwitcher(ft.AnimatedSwitcher): + content: ft.Image | None = None + image_queue: list[str] = field(default_factory=list) + + def init(self): + self.transition = ft.AnimatedSwitcherTransition.SCALE + self.duration = 500 + self.reverse_duration = 100 + self.switch_in_curve = ft.AnimationCurve.EASE_IN + self.switch_out_curve = ft.AnimationCurve.EASE_OUT + if self.content and self.content.src: + self.image_queue.append(self.content.src) + + def animate(self, e): + self.content = ft.Image( + src=self.image_queue.pop(), + width=200, + height=300, + gapless_playback=True, + ) + self.update() + + async def fill_queue(self): + while len(self.image_queue) < 10: + image_base64 = await self.image_to_base64( + f"https://picsum.photos/200/300?{time.time()}" + ) + if image_base64: + self.image_queue.append(image_base64) + + async def image_to_base64(self, url): + response = await httpx.AsyncClient(follow_redirects=True).get(url) + if response.status_code == 200: + base64_str = ( + base64.standard_b64encode(response.content).decode("utf-8").strip() + ) + return base64_str + else: + print(f"Image request failed with {response.status_code}") + return None + + def before_update(self): + self.page.run_task(self.fill_queue) + + +def main(page: ft.Page): + switcher = BufferingSwitcher( + content=ft.Image( + src=f"https://picsum.photos/200/300?{time.time()}", + width=200, + height=300, + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + switcher, + ft.Button("Animate!", on_click=switcher.animate), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/animated_switcher/image_switch_buffered/pyproject.toml b/sdk/python/examples/controls/core/animated_switcher/image_switch_buffered/pyproject.toml new file mode 100644 index 0000000000..4096f8f44a --- /dev/null +++ b/sdk/python/examples/controls/core/animated_switcher/image_switch_buffered/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "animated-switcher-image-switch-buffered" +version = "1.0.0" +description = "Buffered AnimatedSwitcher image transitions with preloaded base64 images." +requires-python = ">=3.10" +keywords = ["animated switcher", "animation", "image", "buffering", "async", "httpx"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "httpx"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/AnimatedSwitcher"] + +[tool.flet.metadata] +title = "Animate image switch buffered" +controls = ["SafeArea", "Column", "AnimatedSwitcher", "Image", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["@ft.control custom switcher", "buffered image queue", "async preloading", "gapless playback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/animated_switcher/media/scale_effect.gif b/sdk/python/examples/controls/core/animated_switcher/media/scale_effect.gif new file mode 100644 index 0000000000..70010844ea Binary files /dev/null and b/sdk/python/examples/controls/core/animated_switcher/media/scale_effect.gif differ diff --git a/sdk/python/examples/controls/core/animated_switcher/scale_effect/main.py b/sdk/python/examples/controls/core/animated_switcher/scale_effect/main.py new file mode 100644 index 0000000000..b0b4bb72ec --- /dev/null +++ b/sdk/python/examples/controls/core/animated_switcher/scale_effect/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + c1 = ft.Container( + content=ft.Text("Hello!", theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM), + alignment=ft.Alignment.CENTER, + width=200, + height=200, + bgcolor=ft.Colors.GREEN, + ) + c2 = ft.Container( + content=ft.Text("Bye!", size=50), + alignment=ft.Alignment.CENTER, + width=200, + height=200, + bgcolor=ft.Colors.YELLOW, + ) + switcher = ft.AnimatedSwitcher( + content=c1, + transition=ft.AnimatedSwitcherTransition.SCALE, + duration=500, + reverse_duration=100, + switch_in_curve=ft.AnimationCurve.BOUNCE_OUT, + switch_out_curve=ft.AnimationCurve.BOUNCE_IN, + ) + + def scale(e): + switcher.content = c2 if switcher.content == c1 else c1 + switcher.transition = ft.AnimatedSwitcherTransition.SCALE + switcher.update() + + def fade(e): + switcher.content = c2 if switcher.content == c1 else c1 + switcher.transition = ft.AnimatedSwitcherTransition.FADE + switcher.update() + + def rotate(e): + switcher.content = c2 if switcher.content == c1 else c1 + switcher.transition = ft.AnimatedSwitcherTransition.ROTATION + switcher.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + switcher, + ft.Button("Scale", on_click=scale), + ft.Button("Fade", on_click=fade), + ft.Button("Rotate", on_click=rotate), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/animated_switcher/scale_effect/pyproject.toml b/sdk/python/examples/controls/core/animated_switcher/scale_effect/pyproject.toml new file mode 100644 index 0000000000..e8f25dc950 --- /dev/null +++ b/sdk/python/examples/controls/core/animated_switcher/scale_effect/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "animated-switcher-scale-effect" +version = "1.0.0" +description = "AnimatedSwitcher transitions between two containers with multiple effects." +requires-python = ">=3.10" +keywords = ["animated switcher", "animation", "scale", "fade", "rotation", "transition"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Animations/AnimatedSwitcher"] + +[tool.flet.metadata] +title = "Scale, fade, and rotate effects" +controls = ["SafeArea", "Column", "Container", "Text", "AnimatedSwitcher", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["multiple transitions", "animated content swap", "button-triggered effects"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/bezier_curves/main.py b/sdk/python/examples/controls/core/canvas/bezier_curves/main.py new file mode 100644 index 0000000000..84c048382e --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/bezier_curves/main.py @@ -0,0 +1,66 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + cp = cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + paint=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE), + elements=[ + cv.Path.MoveTo(x=75, y=25), + cv.Path.QuadraticTo(cp1x=25, cp1y=25, x=25, y=62.5), + cv.Path.QuadraticTo(cp1x=25, cp1y=100, x=50, y=100), + cv.Path.QuadraticTo(cp1x=50, cp1y=120, x=30, y=125), + cv.Path.QuadraticTo(cp1x=60, cp1y=120, x=65, y=100), + cv.Path.QuadraticTo(cp1x=125, cp1y=100, x=125, y=62.5), + cv.Path.QuadraticTo(cp1x=125, cp1y=25, x=75, y=25), + ], + ), + cv.Path( + elements=[ + cv.Path.SubPath( + x=100, + y=100, + elements=[ + cv.Path.MoveTo(x=75, y=40), + cv.Path.CubicTo( + cp1x=75, cp1y=37, cp2x=70, cp2y=25, x=50, y=25 + ), + cv.Path.CubicTo( + cp1x=20, cp1y=25, cp2x=20, cp2y=62.5, x=20, y=62.5 + ), + cv.Path.CubicTo( + cp1x=20, cp1y=80, cp2x=40, cp2y=102, x=75, y=120 + ), + cv.Path.CubicTo( + cp1x=110, cp1y=102, cp2x=130, cp2y=80, x=130, y=62.5 + ), + cv.Path.CubicTo( + cp1x=130, cp1y=62.5, cp2x=130, cp2y=25, x=100, y=25 + ), + cv.Path.CubicTo( + cp1x=85, cp1y=25, cp2x=75, cp2y=37, x=75, y=40 + ), + ], + ) + ], + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + center=ft.Offset(150, 150), + radius=50, + colors=[ft.Colors.PINK_100, ft.Colors.PINK], + ), + ), + ), + ], + ) + + page.add(ft.SafeArea(content=cp)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/bezier_curves/pyproject.toml b/sdk/python/examples/controls/core/canvas/bezier_curves/pyproject.toml new file mode 100644 index 0000000000..1a60ab3282 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/bezier_curves/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-bezier-curves" +version = "1.0.0" +description = "Canvas bezier curve drawing with gradient fills." +requires-python = ">=3.10" +keywords = ["canvas", "bezier", "path", "gradient"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Bezier curves" +controls = ["SafeArea", "Canvas", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["quadratic and cubic paths", "radial gradient fill"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/brush/main.py b/sdk/python/examples/controls/core/canvas/brush/main.py new file mode 100644 index 0000000000..52ef91dff7 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/brush/main.py @@ -0,0 +1,99 @@ +from dataclasses import dataclass + +import flet as ft +import flet.canvas as cv + +MAX_SHAPES_PER_CAPTURE = 30 + + +@dataclass +class State: + x: float = 0 + y: float = 0 + shapes_count: int = 1 + + +state = State() + + +def main(page: ft.Page): + page.title = "Canvas Example" + + file_picker = ft.FilePicker() + + def handle_pan_start(e: ft.DragStartEvent): + state.x = e.local_position.x + state.y = e.local_position.y + + async def handle_pan_update(e: ft.DragUpdateEvent): + # ft.context.disable_auto_update() + canvas.shapes.append( + cv.Line( + x1=state.x, + y1=state.y, + x2=e.local_position.x, + y2=e.local_position.y, + paint=ft.Paint(stroke_width=3), + ) + ) + canvas.update() + state.shapes_count += 1 + + if state.shapes_count == MAX_SHAPES_PER_CAPTURE: + await canvas.capture() + canvas.shapes.clear() + canvas.update() + state.shapes_count = 0 + + state.x = e.local_position.x + state.y = e.local_position.y + + canvas = cv.Canvas( + expand=False, + shapes=[ + cv.Fill(ft.Paint(color=ft.Colors.WHITE)), + ], + content=ft.GestureDetector( + on_pan_start=handle_pan_start, + on_pan_update=handle_pan_update, + drag_interval=10, + ), + ) + + async def save_image(): + await canvas.capture() + capture = await canvas.get_capture() + if capture: + file_path = await file_picker.save_file( + file_name="flet_picture.png", src_bytes=capture + ) + if file_path and page.platform in [ + ft.PagePlatform.MACOS, + ft.PagePlatform.WINDOWS, + ft.PagePlatform.LINUX, + ]: + with open(file_path, "wb") as f: + f.write(capture) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + controls=[ + ft.Button("Save image", on_click=save_image), + ft.Container( + border_radius=5, + border=ft.Border.all(2), + bgcolor=ft.Colors.WHITE, + width=float("inf"), + expand=True, + content=canvas, + ), + ] + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/brush/pyproject.toml b/sdk/python/examples/controls/core/canvas/brush/pyproject.toml new file mode 100644 index 0000000000..dd044beb09 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/brush/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-brush" +version = "1.0.0" +description = "Free-hand canvas drawing with capture and save support." +requires-python = ">=3.10" +keywords = ["canvas", "brush", "gesture", "capture", "save"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Brush" +controls = ["SafeArea", "Column", "Button", "Container", "Canvas", "GestureDetector", "Line", "Fill"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["pan drawing", "canvas capture", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/brush_on_image/main.py b/sdk/python/examples/controls/core/canvas/brush_on_image/main.py new file mode 100644 index 0000000000..abbd2eacd7 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/brush_on_image/main.py @@ -0,0 +1,64 @@ +import flet as ft +import flet.canvas as cv + + +class State: + x: float + y: float + + +state = State() + + +def main(page: ft.Page): + page.title = "Flet Brush" + + def handle_pan_start(e: ft.DragStartEvent): + state.x = e.local_position.x + state.y = e.local_position.y + + def handle_pan_update(e: ft.DragUpdateEvent): + canvas.shapes.append( + cv.Line( + x1=state.x, + y1=state.y, + x2=e.local_position.x, + y2=e.local_position.y, + paint=ft.Paint(stroke_width=3), + ) + ) + canvas.update() + state.x = e.local_position.x + state.y = e.local_position.y + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + border_radius=5, + expand=True, + content=ft.Stack( + expand=True, + controls=[ + ft.Image( + src="https://picsum.photos/200/300", + fit=ft.BoxFit.FILL, + width=float("inf"), + ), + canvas := cv.Canvas( + expand=False, + content=ft.GestureDetector( + on_pan_start=handle_pan_start, + on_pan_update=handle_pan_update, + drag_interval=10, + ), + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/brush_on_image/pyproject.toml b/sdk/python/examples/controls/core/canvas/brush_on_image/pyproject.toml new file mode 100644 index 0000000000..9873b3fefc --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/brush_on_image/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-brush-on-image" +version = "1.0.0" +description = "Draw free-hand strokes over an image using Canvas." +requires-python = ">=3.10" +keywords = ["canvas", "brush", "image", "gesture", "overlay"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Brush on image" +controls = ["SafeArea", "Container", "Stack", "Image", "Canvas", "GestureDetector", "Line"] +layout_pattern = "overlay" +complexity = "basic" +features = ["drawing on image", "pan gesture handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/dash_strokes/main.py b/sdk/python/examples/controls/core/canvas/dash_strokes/main.py new file mode 100644 index 0000000000..edcf4bdaf4 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/dash_strokes/main.py @@ -0,0 +1,118 @@ +import math +from dataclasses import dataclass + +import flet as ft +import flet.canvas as fc + + +@ft.observable +@dataclass +class AppState: + strokes: bool + + def toggle_strokes(self): + self.strokes = not self.strokes + + +@ft.component +def App(): + state, _ = ft.use_state(lambda: AppState(strokes=True)) + return ft.SafeArea( + expand=True, + content=ft.Column( + controls=[ + ft.Button("Toggle strokes", on_click=state.toggle_strokes), + fc.Canvas( + width=300, + height=300, + shapes=[ + fc.Line( + x1=30, + y1=30, + x2=200, + y2=100, + paint=ft.Paint( + color=ft.Colors.BLACK, + stroke_width=3, + stroke_dash_pattern=[4, 4] if state.strokes else None, + style=ft.PaintingStyle.STROKE, + ), + ), + fc.Circle( + x=150, + y=150, + radius=130, + paint=ft.Paint( + color=ft.Colors.BLUE, + stroke_width=4, + stroke_dash_pattern=[4, 4] if state.strokes else None, + style=ft.PaintingStyle.STROKE, + ), + ), + fc.Oval( + x=10, + y=10, + width=240, + height=140, + paint=ft.Paint( + color=ft.Colors.GREEN, + stroke_width=4, + stroke_dash_pattern=[10, 10] if state.strokes else None, + style=ft.PaintingStyle.STROKE, + ), + ), + fc.Arc( + x=20, + y=20, + width=220, + height=220, + start_angle=0, + sweep_angle=math.pi, + paint=ft.Paint( + color=ft.Colors.RED, + stroke_width=4, + stroke_dash_pattern=[7, 7] if state.strokes else None, + style=ft.PaintingStyle.STROKE, + ), + ), + fc.Rect( + x=40, + y=60, + width=60, + height=70, + border_radius=0, + paint=ft.Paint( + color=ft.Colors.RED, + stroke_width=4, + stroke_dash_pattern=[7, 7] if state.strokes else None, + style=ft.PaintingStyle.STROKE, + ), + ), + fc.Arc( + x=50, + y=50, + width=170, + height=140, + start_angle=math.pi * 0.1, + sweep_angle=math.pi * 0.4, + paint=ft.Paint( + color=ft.Colors.YELLOW, + stroke_width=4, + stroke_dash_pattern=[7, 7] if state.strokes else None, + style=ft.PaintingStyle.STROKE, + ), + use_center=True, + ), + ], + ), + ] + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/dash_strokes/pyproject.toml b/sdk/python/examples/controls/core/canvas/dash_strokes/pyproject.toml new file mode 100644 index 0000000000..d2296c763d --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/dash_strokes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-dash-strokes" +version = "1.0.0" +description = "Toggle dashed stroke patterns across multiple canvas shapes." +requires-python = ">=3.10" +keywords = ["canvas", "stroke", "dash", "reactive", "shapes"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Dash strokes" +controls = ["SafeArea", "Column", "Button", "Canvas", "Line", "Circle", "Oval", "Arc", "Rect"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["reactive state", "dash stroke toggle", "multiple shape styles"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/flet_logo/main.py b/sdk/python/examples/controls/core/canvas/flet_logo/main.py new file mode 100644 index 0000000000..820c46011f --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/flet_logo/main.py @@ -0,0 +1,49 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + elements=[ + cv.Path.MoveTo(x=25, y=125), + cv.Path.QuadraticTo(cp1x=50, cp1y=25, x=135, y=35, w=0.35), + cv.Path.QuadraticTo(cp1x=75, cp1y=115, x=135, y=215, w=0.6), + cv.Path.QuadraticTo(cp1x=50, cp1y=225, x=25, y=125, w=0.35), + ], + paint=ft.Paint( + stroke_width=2, + style=ft.PaintingStyle.FILL, + color=ft.Colors.PINK_400, + ), + ), + cv.Path( + elements=[ + cv.Path.MoveTo(x=85, y=125), + cv.Path.QuadraticTo(cp1x=120, cp1y=85, x=165, y=75, w=0.5), + cv.Path.QuadraticTo( + cp1x=120, cp1y=115, x=165, y=175, w=0.3 + ), + cv.Path.QuadraticTo(cp1x=120, cp1y=165, x=85, y=125, w=0.5), + ], + paint=ft.Paint( + stroke_width=2, + style=ft.PaintingStyle.FILL, + color=ft.Colors.with_opacity(0.5, ft.Colors.BLUE_400), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/flet_logo/pyproject.toml b/sdk/python/examples/controls/core/canvas/flet_logo/pyproject.toml new file mode 100644 index 0000000000..22a0b75e00 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/flet_logo/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-flet-logo" +version = "1.0.0" +description = "Canvas drawing of the Flet logo using quadratic paths." +requires-python = ">=3.10" +keywords = ["canvas", "logo", "path", "quadratic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Flet logo" +controls = ["SafeArea", "Canvas", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["path drawing", "filled vector shapes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/gradients/main.py b/sdk/python/examples/controls/core/canvas/gradients/main.py new file mode 100644 index 0000000000..744b7b2f91 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/gradients/main.py @@ -0,0 +1,74 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + cv.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + cv.Path( + elements=[ + cv.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/gradients/pyproject.toml b/sdk/python/examples/controls/core/canvas/gradients/pyproject.toml new file mode 100644 index 0000000000..11ee8446f5 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/gradients/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-gradients" +version = "1.0.0" +description = "Canvas gradient fills with linear, radial, and sweep gradients." +requires-python = ">=3.10" +keywords = ["canvas", "gradients", "linear", "radial", "sweep"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Gradients" +controls = ["SafeArea", "Canvas", "Rect", "Circle", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["linear gradient", "radial gradient", "sweep gradient"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/media/bezier_curves.png b/sdk/python/examples/controls/core/canvas/media/bezier_curves.png new file mode 100644 index 0000000000..874240904a Binary files /dev/null and b/sdk/python/examples/controls/core/canvas/media/bezier_curves.png differ diff --git a/sdk/python/examples/controls/core/canvas/media/flet_logo.png b/sdk/python/examples/controls/core/canvas/media/flet_logo.png new file mode 100644 index 0000000000..d03648c657 Binary files /dev/null and b/sdk/python/examples/controls/core/canvas/media/flet_logo.png differ diff --git a/sdk/python/examples/controls/core/canvas/media/smiling_face.png b/sdk/python/examples/controls/core/canvas/media/smiling_face.png new file mode 100644 index 0000000000..024cff9cec Binary files /dev/null and b/sdk/python/examples/controls/core/canvas/media/smiling_face.png differ diff --git a/sdk/python/examples/controls/core/canvas/media/text.png b/sdk/python/examples/controls/core/canvas/media/text.png new file mode 100644 index 0000000000..e046b77a16 Binary files /dev/null and b/sdk/python/examples/controls/core/canvas/media/text.png differ diff --git a/sdk/python/examples/controls/core/canvas/media/triangles.png b/sdk/python/examples/controls/core/canvas/media/triangles.png new file mode 100644 index 0000000000..593913dfa6 Binary files /dev/null and b/sdk/python/examples/controls/core/canvas/media/triangles.png differ diff --git a/sdk/python/examples/controls/core/canvas/resize/main.py b/sdk/python/examples/controls/core/canvas/resize/main.py new file mode 100644 index 0000000000..ec403efc6f --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/resize/main.py @@ -0,0 +1,36 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + def paint_resize(e: cv.CanvasResizeEvent): + print("On resize:", e.width, e.height) + canvas.shapes[0].x2 = e.width + canvas.shapes[0].y2 = e.height + canvas.shapes[1].y1 = e.height + canvas.shapes[1].x2 = e.width + canvas.update() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + width=float("inf"), + expand=True, + content=( + canvas := cv.Canvas( + resize_interval=10, + on_resize=paint_resize, + shapes=[ + cv.Line(x1=0, y1=0, x2=100, y2=100), + cv.Line(x1=0, y1=100, x2=100, y2=0), + ], + ) + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/resize/pyproject.toml b/sdk/python/examples/controls/core/canvas/resize/pyproject.toml new file mode 100644 index 0000000000..eeb2e8e3c8 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/resize/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-resize" +version = "1.0.0" +description = "Canvas resize handling with dynamic shape updates." +requires-python = ">=3.10" +keywords = ["canvas", "resize", "events", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Canvas resize" +controls = ["SafeArea", "Container", "Canvas", "Line"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["on_resize event", "responsive line drawing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/smiling_face/main.py b/sdk/python/examples/controls/core/canvas/smiling_face/main.py new file mode 100644 index 0000000000..e7d6724cbc --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/smiling_face/main.py @@ -0,0 +1,38 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + stroke_paint = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE) + fill_paint = ft.Paint(style=ft.PaintingStyle.FILL) + + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Circle(x=100, y=100, radius=50, paint=stroke_paint), + cv.Circle(x=80, y=90, radius=10, paint=stroke_paint), + cv.Circle(x=84, y=87, radius=5, paint=fill_paint), + cv.Circle(x=120, y=90, radius=10, paint=stroke_paint), + cv.Circle(x=124, y=87, radius=5, paint=fill_paint), + cv.Arc( + x=70, + y=95, + width=60, + height=40, + start_angle=0, + sweep_angle=math.pi, + paint=stroke_paint, + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/smiling_face/pyproject.toml b/sdk/python/examples/controls/core/canvas/smiling_face/pyproject.toml new file mode 100644 index 0000000000..fa9778fffc --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/smiling_face/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-smiling-face" +version = "1.0.0" +description = "Canvas drawing example of a smiling face." +requires-python = ">=3.10" +keywords = ["canvas", "drawing", "shapes", "arc", "circle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Smiling face" +controls = ["SafeArea", "Canvas", "Circle", "Arc"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["shape drawing", "stroke and fill paints"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/text/main.py b/sdk/python/examples/controls/core/canvas/text/main.py new file mode 100644 index 0000000000..565910117a --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/text/main.py @@ -0,0 +1,111 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Text(x=0, y=0, value="Just a text"), + cv.Circle( + x=200, y=100, radius=2, paint=ft.Paint(color=ft.Colors.RED) + ), + cv.Text( + x=200, + y=100, + style=ft.TextStyle(weight=ft.FontWeight.BOLD, size=30), + alignment=ft.Alignment.TOP_CENTER, + rotate=math.pi * 0.15, + value="Rotated", + spans=[ + ft.TextSpan( + text="around top_center", + style=ft.TextStyle( + italic=True, color=ft.Colors.GREEN, size=20 + ), + ) + ], + ), + cv.Circle( + x=400, y=100, radius=2, paint=ft.Paint(color=ft.Colors.RED) + ), + cv.Text( + x=400, + y=100, + value="Rotated around top_left", + style=ft.TextStyle(size=20), + alignment=ft.Alignment.TOP_LEFT, + rotate=math.pi * -0.15, + ), + cv.Circle( + x=600, y=200, radius=2, paint=ft.Paint(color=ft.Colors.RED) + ), + cv.Text( + x=600, + y=200, + value="Rotated around center", + style=ft.TextStyle(size=20), + alignment=ft.Alignment.CENTER, + rotate=math.pi / 2, + ), + cv.Text( + x=300, + y=400, + value=( + "Limited to max_width and right-aligned.\n" + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore " + "magna aliqua. Ut enim ad minim veniam, quis nostrud " + "exercitation " + "ullamco laboris nisi ut aliquip ex ea commodo consequat." + ), + text_align=ft.TextAlign.RIGHT, + max_width=400, + ), + cv.Text( + x=200, + y=200, + value="WOW!", + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=100, + foreground=ft.Paint( + color=ft.Colors.PINK, + stroke_width=6, + style=ft.PaintingStyle.STROKE, + stroke_join=ft.StrokeJoin.ROUND, + stroke_cap=ft.StrokeCap.ROUND, + ), + ), + ), + cv.Text( + x=200, + y=200, + value="WOW!", + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=100, + foreground=ft.Paint( + gradient=ft.PaintLinearGradient( + begin=(200, 200), + end=(300, 300), + colors=[ft.Colors.YELLOW, ft.Colors.RED], + ), + stroke_join=ft.StrokeJoin.ROUND, + stroke_cap=ft.StrokeCap.ROUND, + ), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/text/pyproject.toml b/sdk/python/examples/controls/core/canvas/text/pyproject.toml new file mode 100644 index 0000000000..a706829050 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/text/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-text" +version = "1.0.0" +description = "Canvas text rendering with transforms, spans, and paint effects." +requires-python = ">=3.10" +keywords = ["canvas", "text", "rotation", "gradient", "spans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Canvas text" +controls = ["SafeArea", "Canvas", "Text", "TextStyle", "TextSpan", "Circle"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["rotated text", "text spans", "stroke and gradient paint"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/canvas/triangles/main.py b/sdk/python/examples/controls/core/canvas/triangles/main.py new file mode 100644 index 0000000000..ce074c4c58 --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/triangles/main.py @@ -0,0 +1,36 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + paint=ft.Paint(style=ft.PaintingStyle.FILL), + elements=[ + cv.Path.MoveTo(x=25, y=25), + cv.Path.LineTo(x=105, y=25), + cv.Path.LineTo(x=25, y=105), + ], + ), + cv.Path( + paint=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE), + elements=[ + cv.Path.MoveTo(x=125, y=125), + cv.Path.LineTo(x=125, y=45), + cv.Path.LineTo(x=45, y=125), + cv.Path.Close(), + ], + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/canvas/triangles/pyproject.toml b/sdk/python/examples/controls/core/canvas/triangles/pyproject.toml new file mode 100644 index 0000000000..8167e855dd --- /dev/null +++ b/sdk/python/examples/controls/core/canvas/triangles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "canvas-triangles" +version = "1.0.0" +description = "Canvas triangles with fill and stroke path styles." +requires-python = ">=3.10" +keywords = ["canvas", "triangles", "path", "stroke", "fill"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Triangles" +controls = ["SafeArea", "Canvas", "Path"] +layout_pattern = "free-canvas" +complexity = "basic" +features = ["path drawing", "filled and outlined shapes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/alignment/main.py b/sdk/python/examples/controls/core/column/alignment/main.py new file mode 100644 index 0000000000..eb9ae5dd90 --- /dev/null +++ b/sdk/python/examples/controls/core/column/alignment/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +@ft.control +class ColumnFromVerticalAlignment(ft.Column): + alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.START + + def init(self): + self.controls = [ + ft.Text(str(self.alignment), size=10), + ft.Container( + content=ft.Column(self.generate_items(3), alignment=self.alignment), + bgcolor=ft.Colors.AMBER_100, + height=400, + ), + ] + + @staticmethod + def generate_items(count: int): + """Generates a list of custom Containers with length `count`.""" + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER_500, + ) + for i in range(1, count + 1) + ] + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + spacing=30, + alignment=ft.MainAxisAlignment.START, + scroll=ft.ScrollMode.AUTO, + controls=[ + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.START), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.CENTER), + ColumnFromVerticalAlignment(alignment=ft.MainAxisAlignment.END), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN + ), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_AROUND + ), + ColumnFromVerticalAlignment( + alignment=ft.MainAxisAlignment.SPACE_EVENLY + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/alignment/pyproject.toml b/sdk/python/examples/controls/core/column/alignment/pyproject.toml new file mode 100644 index 0000000000..59f3b1f6fb --- /dev/null +++ b/sdk/python/examples/controls/core/column/alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-alignment" +version = "1.0.0" +description = "Column vertical alignment modes demonstrated side by side." +requires-python = ">=3.10" +keywords = ["column", "layout", "alignment", "mainaxisalignment", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column vertical alignment" +controls = ["Row", "Column", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["main axis alignment", "layout comparison", "horizontal scrolling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/custom_scrollbar/main.py b/sdk/python/examples/controls/core/column/custom_scrollbar/main.py new file mode 100644 index 0000000000..f0376fdfba --- /dev/null +++ b/sdk/python/examples/controls/core/column/custom_scrollbar/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme = ft.Theme( + scrollbar_theme=ft.ScrollbarTheme( + track_color={ + ft.ControlState.HOVERED: ft.Colors.AMBER, + ft.ControlState.DEFAULT: ft.Colors.TRANSPARENT, + }, + track_visibility=True, + track_border_color=ft.Colors.BLUE, + thumb_visibility=True, + thumb_color={ + ft.ControlState.HOVERED: ft.Colors.RED, + ft.ControlState.DEFAULT: ft.Colors.GREY_300, + }, + thickness=30, + radius=15, + main_axis_margin=5, + cross_axis_margin=10, + ) + ) + + fake_messages = [ + ft.Container( + ft.Text(f"Message {i}", size=16, weight=ft.FontWeight.W_500), + bgcolor=ft.Colors.with_opacity(0.15, ft.Colors.BLUE_200), + border_radius=8, + padding=10, + ) + for i in range(1, 31) + ] + + page.add( + ft.SafeArea( + content=ft.Row( + [ + ft.Container( + content=ft.Column( + controls=fake_messages, + spacing=10, + scroll=ft.ScrollMode.ALWAYS, + expand=True, + ), + width=320, + height=420, + bgcolor=ft.Colors.with_opacity(0.15, ft.Colors.AMBER_200), + padding=15, + border_radius=12, + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + expand=True, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/custom_scrollbar/pyproject.toml b/sdk/python/examples/controls/core/column/custom_scrollbar/pyproject.toml new file mode 100644 index 0000000000..b459a8ca61 --- /dev/null +++ b/sdk/python/examples/controls/core/column/custom_scrollbar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-custom-scrollbar" +version = "1.0.0" +description = "Column with a customized scrollbar theme and styled message list." +requires-python = ">=3.10" +keywords = ["column", "layout", "scrollbar", "theme", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column custom scrollbar" +controls = ["Theme", "ScrollbarTheme", "Row", "Column", "Container", "Text"] +layout_pattern = "chat-list" +complexity = "basic" +features = ["custom scrollbar styling", "themed scroll behavior", "scrollable message list"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/horizontal_alignment/main.py b/sdk/python/examples/controls/core/column/horizontal_alignment/main.py new file mode 100644 index 0000000000..dcd9b92f36 --- /dev/null +++ b/sdk/python/examples/controls/core/column/horizontal_alignment/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +@ft.control +class ColumnFromHorizontalAlignment(ft.Column): + alignment: ft.CrossAxisAlignment = ft.CrossAxisAlignment.START + + def init(self): + self.controls = [ + ft.Text(str(self.alignment), size=16), + ft.Container( + bgcolor=ft.Colors.AMBER_100, + width=100, + content=ft.Column( + controls=self.generate_items(3), + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=self.alignment, + ), + ), + ] + + @staticmethod + def generate_items(count: int): + """Generates a list of custom Containers with length `count`.""" + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER_500, + ) + for i in range(1, count + 1) + ] + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + spacing=30, + alignment=ft.MainAxisAlignment.START, + controls=[ + ColumnFromHorizontalAlignment( + alignment=ft.CrossAxisAlignment.START + ), + ColumnFromHorizontalAlignment( + alignment=ft.CrossAxisAlignment.CENTER + ), + ColumnFromHorizontalAlignment(alignment=ft.CrossAxisAlignment.END), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/horizontal_alignment/pyproject.toml b/sdk/python/examples/controls/core/column/horizontal_alignment/pyproject.toml new file mode 100644 index 0000000000..3d6cbf3e84 --- /dev/null +++ b/sdk/python/examples/controls/core/column/horizontal_alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-horizontal-alignment" +version = "1.0.0" +description = "Column cross-axis alignment modes with visual comparison." +requires-python = ">=3.10" +keywords = ["column", "layout", "crossaxisalignment", "alignment"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column horizontal alignment" +controls = ["Row", "Column", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["cross axis alignment", "layout comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/infinite_scrolling/main.py b/sdk/python/examples/controls/core/column/infinite_scrolling/main.py new file mode 100644 index 0000000000..22f3212983 --- /dev/null +++ b/sdk/python/examples/controls/core/column/infinite_scrolling/main.py @@ -0,0 +1,41 @@ +import threading + +import flet as ft + + +class State: + i = 0 + + +s = State() +sem = threading.Semaphore() + + +def main(page: ft.Page): + def on_scroll(e: ft.OnScrollEvent): + if e.pixels >= e.max_scroll_extent - 100 and sem.acquire(blocking=False): + try: + for _i in range(0, 10): + cl.controls.append(ft.Text(f"Text line {s.i}", key=str(s.i))) + s.i += 1 + cl.update() + finally: + sem.release() + + cl = ft.Column( + spacing=10, + height=200, + width=200, + scroll=ft.ScrollMode.ALWAYS, + scroll_interval=0, + on_scroll=on_scroll, + ) + for _i in range(0, 50): + cl.controls.append(ft.Text(f"Text line {s.i}", key=str(s.i))) + s.i += 1 + + page.add(ft.SafeArea(content=ft.Container(cl, border=ft.Border.all(1)))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/infinite_scrolling/pyproject.toml b/sdk/python/examples/controls/core/column/infinite_scrolling/pyproject.toml new file mode 100644 index 0000000000..943e45b564 --- /dev/null +++ b/sdk/python/examples/controls/core/column/infinite_scrolling/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-infinite-scrolling" +version = "1.0.0" +description = "Infinite scrolling in a column by appending items on scroll." +requires-python = ">=3.10" +keywords = ["column", "layout", "infinite scrolling", "on_scroll", "lazy loading"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column infinite scrolling" +controls = ["Container", "Column", "Text"] +layout_pattern = "infinite-list" +complexity = "basic" +features = ["on_scroll handling", "dynamic item appending", "semaphore guard"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/media/alignment.png b/sdk/python/examples/controls/core/column/media/alignment.png new file mode 100644 index 0000000000..5cb61b6d94 Binary files /dev/null and b/sdk/python/examples/controls/core/column/media/alignment.png differ diff --git a/sdk/python/examples/controls/core/column/media/horizontal_alignment.png b/sdk/python/examples/controls/core/column/media/horizontal_alignment.png new file mode 100644 index 0000000000..ff255796dd Binary files /dev/null and b/sdk/python/examples/controls/core/column/media/horizontal_alignment.png differ diff --git a/sdk/python/examples/controls/core/column/media/programmatic_scroll.png b/sdk/python/examples/controls/core/column/media/programmatic_scroll.png new file mode 100644 index 0000000000..45f1dbd6f5 Binary files /dev/null and b/sdk/python/examples/controls/core/column/media/programmatic_scroll.png differ diff --git a/sdk/python/examples/controls/core/column/media/scroll_to_key.gif b/sdk/python/examples/controls/core/column/media/scroll_to_key.gif new file mode 100644 index 0000000000..fcacc70114 Binary files /dev/null and b/sdk/python/examples/controls/core/column/media/scroll_to_key.gif differ diff --git a/sdk/python/examples/controls/core/column/media/spacing.gif b/sdk/python/examples/controls/core/column/media/spacing.gif new file mode 100644 index 0000000000..c826330f66 Binary files /dev/null and b/sdk/python/examples/controls/core/column/media/spacing.gif differ diff --git a/sdk/python/examples/controls/core/column/media/wrap.gif b/sdk/python/examples/controls/core/column/media/wrap.gif new file mode 100644 index 0000000000..15bbf7b16c Binary files /dev/null and b/sdk/python/examples/controls/core/column/media/wrap.gif differ diff --git a/sdk/python/examples/controls/core/column/programmatic_scroll/main.py b/sdk/python/examples/controls/core/column/programmatic_scroll/main.py new file mode 100644 index 0000000000..1e5f5026fd --- /dev/null +++ b/sdk/python/examples/controls/core/column/programmatic_scroll/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def main(page: ft.Page): + column = ft.Column( + spacing=10, + height=200, + width=float("inf"), + scroll=ft.ScrollMode.ALWAYS, + controls=[ + ft.Text(f"Text line {i}", key=ft.ScrollKey(i)) for i in range(0, 100) + ], + ) + + async def scroll_to_offset(e): + await column.scroll_to(offset=500, duration=1000) + + async def scroll_to_start(e): + await column.scroll_to(offset=0, duration=1000) + + async def scroll_to_end(e): + await column.scroll_to( + offset=-1, duration=2000, curve=ft.AnimationCurve.EASE_IN_OUT + ) + + async def scroll_to_key(e): + await column.scroll_to(scroll_key="20", duration=1000) + + async def scroll_to_delta(e): + await column.scroll_to(delta=100, duration=200) + + async def scroll_to_minus_delta(e): + await column.scroll_to(delta=-100, duration=200) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container(content=column, border=ft.Border.all(1)), + ft.Button("Scroll to offset 500", on_click=scroll_to_offset), + ft.Row( + controls=[ + ft.Button("Scroll -100", on_click=scroll_to_minus_delta), + ft.Button("Scroll +100", on_click=scroll_to_delta), + ] + ), + ft.Button("Scroll to key '20'", on_click=scroll_to_key), + ft.Row( + controls=[ + ft.Button("Scroll to start", on_click=scroll_to_start), + ft.Button("Scroll to end", on_click=scroll_to_end), + ] + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/programmatic_scroll/pyproject.toml b/sdk/python/examples/controls/core/column/programmatic_scroll/pyproject.toml new file mode 100644 index 0000000000..7a75ab126e --- /dev/null +++ b/sdk/python/examples/controls/core/column/programmatic_scroll/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-programmatic-scroll" +version = "1.0.0" +description = "Programmatic scrolling of a column using offsets, keys, and deltas." +requires-python = ">=3.10" +keywords = ["column", "layout", "scroll_to", "scroll key", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column programmatic scroll" +controls = ["Container", "Column", "Row", "Button", "Text"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["async scroll_to", "offset and delta scrolling", "scroll key targeting"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/scroll/main.py b/sdk/python/examples/controls/core/column/scroll/main.py new file mode 100644 index 0000000000..b39090274c --- /dev/null +++ b/sdk/python/examples/controls/core/column/scroll/main.py @@ -0,0 +1,90 @@ +import flet as ft + + +def main(page: ft.Page): + def add_text_box(e: ft.Event[ft.Button]): + text_field = ft.TextField( + label=f"Text Box {len(left_column.controls)}", + label_style=ft.TextStyle(color=ft.Colors.GREEN), + color=ft.Colors.GREEN, + value=str(len(left_column.controls)), + ) + left_column.controls.append(text_field) + + def remove_text_box(e: ft.Event[ft.Button]): + if left_column.controls: + left_column.controls.pop() + + def scroll_generator(scroll_mode_list: list): + while True: + yield from scroll_mode_list + + def change_scroll(_): + left_column.scroll = next(scroll_mode) + scroll_mode_text.value = str(left_column.scroll) + + add_text_box_button = ft.Button("Add TextBox", on_click=add_text_box) + remove_text_box_button = ft.Button( + content="Remove TextBox", + on_click=remove_text_box, + ) + scroll_change_button = ft.Button( + content="Change Scroll Mode", + on_click=change_scroll, + ) + + scroll_mode = scroll_generator( + [ + None, + ft.ScrollMode.AUTO, + ft.ScrollMode.ADAPTIVE, + ft.ScrollMode.ALWAYS, + ft.ScrollMode.HIDDEN, + ] + ) + + left_column = ft.Column( + controls=[ft.Text("THIS IS COL 1", color=ft.Colors.RED_400)], + scroll=next(scroll_mode), + ) + scroll_mode_text = ft.Text(str(left_column.scroll)) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Row( + expand=True, + controls=[ + ft.Container( + content=left_column, + expand=True, + margin=10, + padding=10, + bgcolor=ft.Colors.AMBER_100, + border_radius=10, + alignment=ft.Alignment.TOP_CENTER, + ), + ft.Container( + margin=10, + padding=10, + bgcolor=ft.Colors.CYAN_500, + border_radius=10, + expand=True, + alignment=ft.Alignment.TOP_LEFT, + content=ft.Column( + controls=[ + add_text_box_button, + remove_text_box_button, + scroll_change_button, + scroll_mode_text, + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/scroll/pyproject.toml b/sdk/python/examples/controls/core/column/scroll/pyproject.toml new file mode 100644 index 0000000000..605d832631 --- /dev/null +++ b/sdk/python/examples/controls/core/column/scroll/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-scroll" +version = "1.0.0" +description = "Interactive column scrolling with dynamic controls and scroll mode switching." +requires-python = ">=3.10" +keywords = ["column", "layout", "scroll mode", "dynamic controls", "text field"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column scrolling" +controls = ["Row", "Column", "Container", "Button", "Text", "TextField"] +layout_pattern = "split-panel" +complexity = "basic" +features = ["dynamic add/remove", "scroll mode cycling", "interactive control panel"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/scroll_events/main.py b/sdk/python/examples/controls/core/column/scroll_events/main.py new file mode 100644 index 0000000000..741ff6f31e --- /dev/null +++ b/sdk/python/examples/controls/core/column/scroll_events/main.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_column_scroll(e: ft.OnScrollEvent): + print(e) + + page.add( + ft.SafeArea( + content=ft.Container( + border=ft.Border.all(1), + content=ft.Column( + spacing=10, + height=200, + width=200, + scroll=ft.ScrollMode.ALWAYS, + on_scroll=handle_column_scroll, + controls=[ + ft.Text(f"Text line {i}", key=ft.ScrollKey(str(i))) + for i in range(0, 50) + ], + ), + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/scroll_events/pyproject.toml b/sdk/python/examples/controls/core/column/scroll_events/pyproject.toml new file mode 100644 index 0000000000..d956025ba2 --- /dev/null +++ b/sdk/python/examples/controls/core/column/scroll_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-scroll-events" +version = "1.0.0" +description = "Column on_scroll event handling example." +requires-python = ">=3.10" +keywords = ["column", "layout", "on_scroll", "events", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column scroll events" +controls = ["Container", "Column", "Text"] +layout_pattern = "event-monitor" +complexity = "basic" +features = ["on_scroll callback", "scroll event inspection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/scroll_to_key/main.py b/sdk/python/examples/controls/core/column/scroll_to_key/main.py new file mode 100644 index 0000000000..5592e09f2f --- /dev/null +++ b/sdk/python/examples/controls/core/column/scroll_to_key/main.py @@ -0,0 +1,102 @@ +import flet as ft + + +def main(page: ft.Page): + async def scroll_a(): + await column1.scroll_to(scroll_key=ft.ScrollKey("A"), duration=1000) + + async def scroll_b(): + await column1.scroll_to(scroll_key=ft.ScrollKey("B"), duration=1000) + + async def scroll_c(): + await column1.scroll_to(scroll_key=ft.ScrollKey("C"), duration=1000) + + async def scroll_d(): + await column1.scroll_to(scroll_key=ft.ScrollKey("D"), duration=1000) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + border=ft.Border.all(1), + content=( + column1 := ft.Column( + spacing=10, + height=200, + width=300, + scroll=ft.ScrollMode.ALWAYS, + controls=[ + ft.Container( + content=ft.Text( + "Section A", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.YELLOW_200, + height=100, + key=ft.ScrollKey("A"), + ), + ft.Container( + content=ft.Text( + "Section B", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.GREEN_200, + height=100, + key=ft.ScrollKey("B"), + ), + ft.Container( + content=ft.Text( + "Section C", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.BLUE_200, + height=100, + key=ft.ScrollKey("C"), + ), + ft.Container( + content=ft.Text( + "Section D", color=ft.Colors.BLACK + ), + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.PINK_200, + height=100, + key=ft.ScrollKey("D"), + ), + ], + ) + ), + ), + ft.Column( + controls=[ + ft.Text("Scroll to:"), + ft.Row( + controls=[ + ft.Button( + content="Section A", + on_click=scroll_a, + ), + ft.Button( + content="Section B", + on_click=scroll_b, + ), + ft.Button( + content="Section C", + on_click=scroll_c, + ), + ft.Button( + content="Section D", + on_click=scroll_d, + ), + ] + ), + ] + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/scroll_to_key/pyproject.toml b/sdk/python/examples/controls/core/column/scroll_to_key/pyproject.toml new file mode 100644 index 0000000000..54749c767b --- /dev/null +++ b/sdk/python/examples/controls/core/column/scroll_to_key/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-scroll-to-key" +version = "1.0.0" +description = "Scroll a column to keyed sections using action buttons." +requires-python = ">=3.10" +keywords = ["column", "layout", "scroll_to", "scroll key", "sections"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column scroll to key" +controls = ["Container", "Column", "Row", "Button", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["scroll key navigation", "async button actions", "section anchors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/spacing/main.py b/sdk/python/examples/controls/core/column/spacing/main.py new file mode 100644 index 0000000000..aa3bc60204 --- /dev/null +++ b/sdk/python/examples/controls/core/column/spacing/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + def generate_items(count: int): + """Generates a list of custom Containers with length `count`.""" + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER, + border_radius=ft.BorderRadius.all(5), + ) + for i in range(1, count + 1) + ] + + def handle_slider_change(e: ft.Event[ft.Slider]): + """Updates the spacing between items based on slider value.""" + column.spacing = int(e.control.value) + column.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text("Spacing between items"), + ft.Slider( + min=0, + max=100, + divisions=10, + value=0, + label="{value}", + width=500, + on_change=handle_slider_change, + ), + ] + ), + column := ft.Column(spacing=0, controls=generate_items(5)), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/spacing/pyproject.toml b/sdk/python/examples/controls/core/column/spacing/pyproject.toml new file mode 100644 index 0000000000..273a2a7d02 --- /dev/null +++ b/sdk/python/examples/controls/core/column/spacing/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-spacing" +version = "1.0.0" +description = "Adjust column spacing interactively with a slider." +requires-python = ">=3.10" +keywords = ["column", "layout", "spacing", "slider", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column spacing" +controls = ["Column", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["slider-driven spacing", "dynamic layout updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/column/wrap/main.py b/sdk/python/examples/controls/core/column/wrap/main.py new file mode 100644 index 0000000000..b7e581963a --- /dev/null +++ b/sdk/python/examples/controls/core/column/wrap/main.py @@ -0,0 +1,64 @@ +import flet as ft + +HEIGHT = 400 + + +def main(page: ft.Page): + def items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=30, + height=30, + bgcolor=ft.Colors.AMBER, + border_radius=ft.BorderRadius.all(5), + ) + for i in range(1, count + 1) + ] + + def handle_slider_change(e: ft.Event[ft.Slider]): + col.height = float(e.control.value) + col.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text( + "Change the column height to see how child items " + "wrap onto multiple columns:" + ), + ft.Slider( + min=0, + max=HEIGHT, + divisions=20, + value=HEIGHT, + label="{value}", + width=500, + on_change=handle_slider_change, + ), + ] + ), + ft.Container( + bgcolor=ft.Colors.TRANSPARENT, + content=( + col := ft.Column( + wrap=True, + spacing=10, + run_spacing=10, + controls=items(10), + height=HEIGHT, + ) + ), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/column/wrap/pyproject.toml b/sdk/python/examples/controls/core/column/wrap/pyproject.toml new file mode 100644 index 0000000000..45c393b6d2 --- /dev/null +++ b/sdk/python/examples/controls/core/column/wrap/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "column-wrap" +version = "1.0.0" +description = "Column wrapping behavior controlled by dynamic height." +requires-python = ">=3.10" +keywords = ["column", "layout", "wrap", "slider", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Column"] + +[tool.flet.metadata] +title = "Column wrapping" +controls = ["Column", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["wrap behavior", "height-driven layout", "slider interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/animate_1/main.py b/sdk/python/examples/controls/core/container/animate_1/main.py new file mode 100644 index 0000000000..561c987a34 --- /dev/null +++ b/sdk/python/examples/controls/core/container/animate_1/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_container(e: ft.Event[ft.Button]): + container.width = 100 if container.width == 150 else 150 + container.height = 50 if container.height == 150 else 150 + container.bgcolor = ( + ft.Colors.BLUE if container.bgcolor == ft.Colors.RED else ft.Colors.RED + ) + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=150, + height=150, + bgcolor=ft.Colors.RED, + animate=ft.Animation( + duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT + ), + ), + ft.Button("Animate container", on_click=animate_container), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/animate_1/pyproject.toml b/sdk/python/examples/controls/core/container/animate_1/pyproject.toml new file mode 100644 index 0000000000..699896a5b5 --- /dev/null +++ b/sdk/python/examples/controls/core/container/animate_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-animate-1" +version = "1.0.0" +description = "Animated container size and color transitions triggered by button clicks." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animate 1" +controls = ["SafeArea", "Column", "Container", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["size animation", "color animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/animate_2/main.py b/sdk/python/examples/controls/core/container/animate_2/main.py new file mode 100644 index 0000000000..558639d188 --- /dev/null +++ b/sdk/python/examples/controls/core/container/animate_2/main.py @@ -0,0 +1,64 @@ +import flet as ft + + +def main(page: ft.Page): + gradient1 = ft.LinearGradient( + begin=ft.Alignment.TOP_CENTER, + end=ft.Alignment.BOTTOM_CENTER, + colors=[ft.Colors.GREEN, ft.Colors.BLUE], + stops=[0.5, 1.0], + ) + gradient2 = ft.RadialGradient( + center=ft.Alignment.TOP_LEFT, + radius=1.0, + colors=[ft.Colors.YELLOW, ft.Colors.DEEP_ORANGE_900], + tile_mode=ft.GradientTileMode.CLAMP, + ) + + message = ft.Text("Animate me!") + + def animate_container(e: ft.Event[ft.Button]): + message.value = ( + "Animate me back!" if message.value == "Animate me!" else "Animate me!" + ) + container.width = 150 if container.width == 250 else 250 + container.height = 150 if container.height == 250 else 250 + container.gradient = gradient2 if container.gradient == gradient1 else gradient1 + if container.alignment == ft.Alignment.TOP_LEFT: + container.alignment = ft.Alignment.BOTTOM_RIGHT + else: + container.alignment = ft.Alignment.TOP_LEFT + container.border_radius = 30 if container.border_radius == 10 else 10 + container.border = ( + ft.Border.all(width=2, color=ft.Colors.BLACK) + if container.border == ft.Border.all(width=2, color=ft.Colors.BLUE) + else ft.Border.all(width=2, color=ft.Colors.BLUE) + ) + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=250, + height=250, + gradient=gradient2, + alignment=ft.Alignment.TOP_LEFT, + animate=ft.Animation( + duration=1000, curve=ft.AnimationCurve.BOUNCE_OUT + ), + border=ft.Border.all(width=2, color=ft.Colors.BLUE), + border_radius=10, + padding=10, + content=message, + ), + ft.Button("Animate container", on_click=animate_container), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/animate_2/pyproject.toml b/sdk/python/examples/controls/core/container/animate_2/pyproject.toml new file mode 100644 index 0000000000..299edf9de9 --- /dev/null +++ b/sdk/python/examples/controls/core/container/animate_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-animate-2" +version = "1.0.0" +description = "Animated container with gradient, border, alignment, and shape transitions." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animate 2" +controls = ["SafeArea", "Column", "Container", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["gradient animation", "border animation", "alignment animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/animate_3/main.py b/sdk/python/examples/controls/core/container/animate_3/main.py new file mode 100644 index 0000000000..56ab86c552 --- /dev/null +++ b/sdk/python/examples/controls/core/container/animate_3/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +def main(page: ft.Page): + def show_menu(e: ft.Event[ft.Button]): + container.offset = ft.Offset(0, 0) + container.update() + + def hide_menu(e: ft.Event[ft.IconButton]): + container.offset = ft.Offset(-2, 0) + container.update() + + page.overlay.append( + container := ft.Container( + left=10, + top=10, + width=200, + height=300, + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + border_radius=5, + offset=ft.Offset(-2, 0), + animate_offset=ft.Animation(300, ft.AnimationCurve.EASE_IN), + content=ft.Column( + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.IconButton(icon=ft.Icons.CLOSE, on_click=hide_menu) + ], + ), + ft.ListTile( + title=ft.Text("Menu A"), + on_click=lambda _: print("Menu A clicked"), + ), + ft.ListTile( + title=ft.Text("Menu B"), + on_click=lambda _: print("Menu B clicked"), + ), + ] + ), + ) + ) + + page.add(ft.SafeArea(content=ft.Button("Show menu", on_click=show_menu))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/animate_3/pyproject.toml b/sdk/python/examples/controls/core/container/animate_3/pyproject.toml new file mode 100644 index 0000000000..a93d8a6de2 --- /dev/null +++ b/sdk/python/examples/controls/core/container/animate_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-animate-3" +version = "1.0.0" +description = "Slide-in side menu built with animated container offset and overlay controls." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animate 3" +controls = ["SafeArea", "Button", "Container", "Column", "Row", "IconButton", "ListTile"] +layout_pattern = "overlay" +complexity = "basic" +features = ["overlay menu", "offset animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/clickable/main.py b/sdk/python/examples/controls/core/container/clickable/main.py new file mode 100644 index 0000000000..9fa4d0824c --- /dev/null +++ b/sdk/python/examples/controls/core/container/clickable/main.py @@ -0,0 +1,68 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Container Example" + page.theme_mode = ft.ThemeMode.LIGHT + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.AMBER, + width=150, + height=150, + border_radius=10, + content=ft.Text("Non clickable"), + ), + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.GREEN_200, + width=150, + height=150, + border_radius=10, + on_click=lambda e: print("Clickable without Ink clicked!"), + content=ft.Text("Clickable without Ink"), + ), + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.CYAN_200, + width=150, + height=150, + border_radius=10, + ink=True, + on_click=lambda e: print("Clickable with Ink clicked!"), + content=ft.Text("Clickable with Ink"), + ), + ft.Container( + margin=10, + padding=10, + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=10, + ink=True, + on_click=lambda e: print( + "Clickable transparent with Ink clicked!" + ), + content=ft.Text("Clickable transparent with Ink"), + ), + ], + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/clickable/pyproject.toml b/sdk/python/examples/controls/core/container/clickable/pyproject.toml new file mode 100644 index 0000000000..8152121403 --- /dev/null +++ b/sdk/python/examples/controls/core/container/clickable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-clickable" +version = "1.0.0" +description = "Container clickability showcase with non-clickable, clickable, and ink-enabled variants." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Clickable" +controls = ["SafeArea", "Row", "Container", "Text"] +layout_pattern = "row-showcase" +complexity = "basic" +features = ["click handling", "ink effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/handling_clicks/main.py b/sdk/python/examples/controls/core/container/handling_clicks/main.py new file mode 100644 index 0000000000..97eff47a73 --- /dev/null +++ b/sdk/python/examples/controls/core/container/handling_clicks/main.py @@ -0,0 +1,107 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + lp_counter = 0 + cl_counter = 0 + td_counter = 0 + + def on_click(e): + nonlocal cl_counter + cl_counter += 1 + t1.spans[-1] = ft.TextSpan( + text=f" {cl_counter} ", + style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), + ) + t1.update() + + def on_long_press(e): + nonlocal lp_counter + lp_counter += 1 + t3.spans[-1] = ft.TextSpan( + text=f" {lp_counter} ", + style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), + ) + t3.update() + + def on_tap_down(e): + nonlocal td_counter + td_counter += 1 + t2.spans[-1] = ft.TextSpan( + text=f" {td_counter} ", + style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), + ) + t2.update() + + c = ft.Container( + bgcolor=ft.Colors.PINK_900, + alignment=ft.Alignment.CENTER, + padding=ft.Padding.all(10), + height=150, + width=150, + on_click=on_click, + on_long_press=on_long_press, + on_tap_down=on_tap_down, + content=ft.Text( + "Press Me!", + text_align=ft.TextAlign.CENTER, + style=ft.TextStyle( + size=30, + # weight=ft.FontWeight.BOLD, + foreground=ft.Paint( + color=ft.Colors.BLUE_700, + stroke_cap=ft.StrokeCap.BUTT, + stroke_width=2, + stroke_join=ft.StrokeJoin.BEVEL, + style=ft.PaintingStyle.STROKE, + ), + ), + theme_style=ft.TextThemeStyle.DISPLAY_MEDIUM, + ), + ) + t1 = ft.Text( + spans=[ + ft.TextSpan( + text="On Click", style=ft.TextStyle(size=16, weight=ft.FontWeight.BOLD) + ), + ft.TextSpan(text=" counter: ", style=ft.TextStyle(size=16, italic=True)), + ft.TextSpan( + text=f" {cl_counter} ", + style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), + ), + ] + ) + t2 = ft.Text( + spans=[ + ft.TextSpan( + text="Tap Down", style=ft.TextStyle(size=16, weight=ft.FontWeight.BOLD) + ), + ft.TextSpan(text=" counter: ", style=ft.TextStyle(size=16, italic=True)), + ft.TextSpan( + text=f" {td_counter} ", + style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), + ), + ] + ) + t3 = ft.Text( + spans=[ + ft.TextSpan( + text="Long Press", + style=ft.TextStyle(size=16, weight=ft.FontWeight.BOLD), + ), + ft.TextSpan(text=" counter: ", style=ft.TextStyle(size=16, italic=True)), + ft.TextSpan( + text=f" {lp_counter} ", + style=ft.TextStyle(size=16, bgcolor=ft.Colors.TEAL_300), + ), + ] + ) + + page.add(ft.SafeArea(content=ft.Column(controls=[c, t1, t3, t2]))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/handling_clicks/pyproject.toml b/sdk/python/examples/controls/core/container/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..221a4caddb --- /dev/null +++ b/sdk/python/examples/controls/core/container/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-handling-clicks" +version = "1.0.0" +description = "Container gesture handling demo with click, tap-down, and long-press counters." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "Container", "Text", "TextSpan"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["on_click", "on_tap_down", "on_long_press"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/handling_hovers/main.py b/sdk/python/examples/controls/core/container/handling_hovers/main.py new file mode 100644 index 0000000000..f054fb970a --- /dev/null +++ b/sdk/python/examples/controls/core/container/handling_hovers/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_hover(e: ft.Event[ft.Container]): + e.control.bgcolor = ft.Colors.BLUE if e.data else ft.Colors.RED + e.control.update() + + page.add( + ft.SafeArea( + content=ft.Container( + width=200, + height=200, + bgcolor=ft.Colors.RED, + ink=False, + on_hover=handle_hover, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/handling_hovers/pyproject.toml b/sdk/python/examples/controls/core/container/handling_hovers/pyproject.toml new file mode 100644 index 0000000000..2c34612d4d --- /dev/null +++ b/sdk/python/examples/controls/core/container/handling_hovers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-handling-hovers" +version = "1.0.0" +description = "Container hover example that changes background color on pointer enter and leave." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Handling hovers" +controls = ["SafeArea", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["hover handling", "dynamic styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/media/animate_1.gif b/sdk/python/examples/controls/core/container/media/animate_1.gif new file mode 100644 index 0000000000..445264a5f9 Binary files /dev/null and b/sdk/python/examples/controls/core/container/media/animate_1.gif differ diff --git a/sdk/python/examples/controls/core/container/media/clickable.gif b/sdk/python/examples/controls/core/container/media/clickable.gif new file mode 100644 index 0000000000..0af1500d48 Binary files /dev/null and b/sdk/python/examples/controls/core/container/media/clickable.gif differ diff --git a/sdk/python/examples/controls/core/container/media/handling_clicks.gif b/sdk/python/examples/controls/core/container/media/handling_clicks.gif new file mode 100644 index 0000000000..99c1e5e343 Binary files /dev/null and b/sdk/python/examples/controls/core/container/media/handling_clicks.gif differ diff --git a/sdk/python/examples/controls/core/container/media/handling_hovers.gif b/sdk/python/examples/controls/core/container/media/handling_hovers.gif new file mode 100644 index 0000000000..708aa9703a Binary files /dev/null and b/sdk/python/examples/controls/core/container/media/handling_hovers.gif differ diff --git a/sdk/python/examples/controls/core/container/media/nested_themes_3.gif b/sdk/python/examples/controls/core/container/media/nested_themes_3.gif new file mode 100644 index 0000000000..6428366e01 Binary files /dev/null and b/sdk/python/examples/controls/core/container/media/nested_themes_3.gif differ diff --git a/sdk/python/examples/controls/core/container/media/overview_padding_margin_border.png b/sdk/python/examples/controls/core/container/media/overview_padding_margin_border.png new file mode 100644 index 0000000000..d27a86646f Binary files /dev/null and b/sdk/python/examples/controls/core/container/media/overview_padding_margin_border.png differ diff --git a/sdk/python/examples/controls/core/container/nested_themes_1/main.py b/sdk/python/examples/controls/core/container/nested_themes_1/main.py new file mode 100644 index 0000000000..18669a08c7 --- /dev/null +++ b/sdk/python/examples/controls/core/container/nested_themes_1/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + # Yellow page theme with SYSTEM (default) mode + page.theme = ft.Theme( + color_scheme_seed=ft.Colors.YELLOW, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # Page theme + ft.Container( + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Page theme button"), + ), + # Inherited theme with primary color overridden + ft.Container( + theme=ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.PINK) + ), + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Inherited theme button"), + ), + # Unique always DARK theme + ft.Container( + theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), + theme_mode=ft.ThemeMode.DARK, + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Unique theme button"), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/nested_themes_1/pyproject.toml b/sdk/python/examples/controls/core/container/nested_themes_1/pyproject.toml new file mode 100644 index 0000000000..73c0393525 --- /dev/null +++ b/sdk/python/examples/controls/core/container/nested_themes_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-nested-themes-1" +version = "1.0.0" +description = "Nested theme containers demonstrating inherited and overridden button color schemes." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Nested themes 1" +controls = ["SafeArea", "Column", "Container", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["nested themes", "theme override"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/nested_themes_2/main.py b/sdk/python/examples/controls/core/container/nested_themes_2/main.py new file mode 100644 index 0000000000..e32cf9ad85 --- /dev/null +++ b/sdk/python/examples/controls/core/container/nested_themes_2/main.py @@ -0,0 +1,85 @@ +import flet as ft + + +def main(page: ft.Page): + # page.theme = ft.Theme( + # color_scheme_seed=ft.Colors.YELLOW, + # color_scheme=ft.ColorScheme( + # primary=ft.Colors.GREEN, primary_container=ft.Colors.GREEN_200 + # ), + # ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Button("Page theme"), + ft.TextButton("Page theme text button"), + ft.Text( + "Text in primary container color", + color=ft.Colors.PRIMARY_CONTAINER, + ), + ] + ), + ft.Container( + height=100, + theme=ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.PINK) + ), + content=ft.Row( + controls=[ + ft.Button( + "Inherited theme with primary color overridden" + ), + ft.TextButton("Button 2"), + ] + ), + ), + ft.Container( + padding=20, + bgcolor=ft.Colors.SURFACE_TINT, + theme_mode=ft.ThemeMode.DARK, + theme=ft.Theme( + color_scheme_seed=ft.Colors.GREEN, + color_scheme=ft.ColorScheme( + primary_container=ft.Colors.BLUE + ), + ), + content=ft.Row( + controls=[ + ft.Button("Always DARK theme"), + ft.TextButton("Text button"), + ft.Text( + "Text in primary container color", + color=ft.Colors.PRIMARY_CONTAINER, + ), + ] + ), + ), + ft.Container( + padding=20, + bgcolor=ft.Colors.SURFACE_TINT, + border=ft.Border.all(3, ft.Colors.OUTLINE), + theme_mode=ft.ThemeMode.LIGHT, + theme=ft.Theme(), + content=ft.Row( + controls=[ + ft.Button("Always LIGHT theme"), + ft.TextButton("Text button"), + ft.Text( + "Text in primary container color", + color=ft.Colors.PRIMARY_CONTAINER, + ), + ] + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/nested_themes_2/pyproject.toml b/sdk/python/examples/controls/core/container/nested_themes_2/pyproject.toml new file mode 100644 index 0000000000..9ff856560c --- /dev/null +++ b/sdk/python/examples/controls/core/container/nested_themes_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-nested-themes-2" +version = "1.0.0" +description = "Multiple nested containers comparing page, dark, and light theme behaviors." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Nested themes 2" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "TextButton", "Text"] +layout_pattern = "stacked-sections" +complexity = "basic" +features = ["nested themes", "theme mode override"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/nested_themes_3/main.py b/sdk/python/examples/controls/core/container/nested_themes_3/main.py new file mode 100644 index 0000000000..a10153dc68 --- /dev/null +++ b/sdk/python/examples/controls/core/container/nested_themes_3/main.py @@ -0,0 +1,68 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.DARK + + def handle_switch_change(e: ft.Event[ft.Switch]): + if page.theme_mode == ft.ThemeMode.DARK: + page.theme_mode = ft.ThemeMode.LIGHT + switch.thumb_icon = ft.Icons.LIGHT_MODE + else: + switch.thumb_icon = ft.Icons.DARK_MODE + page.theme_mode = ft.ThemeMode.DARK + page.update() + + # Yellow page theme with SYSTEM (default) mode + page.theme = ft.Theme(color_scheme_seed=ft.Colors.YELLOW) + + switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=handle_switch_change) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # Page theme + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Container( + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Page theme button"), + ), + ft.Container( + padding=ft.Padding.only(bottom=50), + alignment=ft.Alignment.TOP_RIGHT, + content=switch, + ), + ], + ), + # Inherited theme with primary color overridden + ft.Container( + theme=ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.PINK) + ), + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Inherited theme button"), + ), + # Unique always DARK theme + ft.Container( + theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), + theme_mode=ft.ThemeMode.DARK, + bgcolor=ft.Colors.SURFACE_TINT, + padding=20, + width=300, + content=ft.Button("Unique theme button"), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/nested_themes_3/pyproject.toml b/sdk/python/examples/controls/core/container/nested_themes_3/pyproject.toml new file mode 100644 index 0000000000..78d8336e09 --- /dev/null +++ b/sdk/python/examples/controls/core/container/nested_themes_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-nested-themes-3" +version = "1.0.0" +description = "Theme toggle example using a switch to change page mode across nested containers." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Nested themes 3" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "Switch"] +layout_pattern = "stacked-sections" +complexity = "basic" +features = ["theme mode toggle", "nested themes"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/container/size_aware/main.py b/sdk/python/examples/controls/core/container/size_aware/main.py new file mode 100644 index 0000000000..3be1915288 --- /dev/null +++ b/sdk/python/examples/controls/core/container/size_aware/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_size_change(e: ft.LayoutSizeChangeEvent[ft.Container]): + e.control.content.value = f"{int(e.width)} x {int(e.height)}" + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.BLUE_ACCENT, + size_change_interval=100, + on_size_change=handle_size_change, + content=ft.Text(color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/container/size_aware/pyproject.toml b/sdk/python/examples/controls/core/container/size_aware/pyproject.toml new file mode 100644 index 0000000000..3f543b3ea3 --- /dev/null +++ b/sdk/python/examples/controls/core/container/size_aware/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "container-size-aware" +version = "1.0.0" +description = "Size-aware container displaying live width and height updates on resize events." +requires-python = ">=3.10" +keywords = ["container", "layout", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Size aware" +controls = ["SafeArea", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["on_size_change", "responsive text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/control/expand_loose_chat_messages/main.py b/sdk/python/examples/controls/core/control/expand_loose_chat_messages/main.py new file mode 100644 index 0000000000..2c23e6dca7 --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_loose_chat_messages/main.py @@ -0,0 +1,90 @@ +from dataclasses import field + +import flet as ft + + +@ft.control +class Message(ft.Container): + author: str = "" + body: str = "" + border: ft.Border = field(default_factory=lambda: ft.Border.all(1, ft.Colors.BLACK)) + border_radius: ft.BorderRadius = field( + default_factory=lambda: ft.BorderRadius.all(10) + ) + bgcolor: ft.Colors = ft.Colors.GREEN_200 + padding: ft.PaddingValue = 10 + expand: bool = True + expand_loose: bool = True + + def init(self): + self.content = ft.Column( + controls=[ + ft.Text(self.author, weight=ft.FontWeight.BOLD), + ft.Text(self.body), + ], + ) + + +def main(page: ft.Page): + chat = ft.ListView( + padding=10, + spacing=10, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + Message( + author="John", + body="Hi, how are you?", + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + Message( + author="Jake", + body="Hi I am good thanks, how about you?", + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + Message( + author="John", + body=( + "Lorem Ipsum is simply dummy text of the printing and " + "typesetting industry. Lorem Ipsum has been the industry's " + "standard dummy text ever since the 1500s, when an unknown " + "printer took a galley of type and scrambled it to make a " + "type specimen book." + ), + ), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + Message( + author="Jake", + body="Thank you!", + ), + ], + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Container( + width=300, + height=500, + content=chat, + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/control/expand_loose_chat_messages/pyproject.toml b/sdk/python/examples/controls/core/control/expand_loose_chat_messages/pyproject.toml new file mode 100644 index 0000000000..027409c582 --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_loose_chat_messages/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-loose-chat-messages" +version = "1.0.0" +description = "Chat message layout demo using expand_loose for flexible message bubble sizing in rows." +requires-python = ">=3.10" +keywords = ["control", "expand_loose", "chat", "row", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand loose chat messages" +controls = ["SafeArea", "Container", "ListView", "Row", "Text", "Column"] +layout_pattern = "chat" +complexity = "basic" +features = ["expand_loose behavior", "chat message bubbles"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/control/expand_row_equal_split/main.py b/sdk/python/examples/controls/core/control/expand_row_equal_split/main.py new file mode 100644 index 0000000000..624934537d --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_row_equal_split/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Container( + width=500, + height=180, + padding=10, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=10, + content=ft.Row( + spacing=8, + controls=[ + ft.Container( + expand=True, + bgcolor=ft.Colors.ORANGE_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Card 1"), + ), + ft.Container( + expand=True, + bgcolor=ft.Colors.GREEN_200, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Card 2"), + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/control/expand_row_equal_split/pyproject.toml b/sdk/python/examples/controls/core/control/expand_row_equal_split/pyproject.toml new file mode 100644 index 0000000000..09355576dd --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_row_equal_split/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-row-equal-split" +version = "1.0.0" +description = "Row example where two containers equally split available horizontal space with expand=True." +requires-python = ">=3.10" +keywords = ["control", "expand", "row", "equal split", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand row equal split" +controls = ["SafeArea", "Container", "Row", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["equal expand split", "row layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/control/expand_row_proportional_1_3_1/main.py b/sdk/python/examples/controls/core/control/expand_row_proportional_1_3_1/main.py new file mode 100644 index 0000000000..65e1f27dd9 --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_row_proportional_1_3_1/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Container( + width=500, + padding=10, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=10, + content=ft.Row( + spacing=8, + controls=[ + ft.Container( + expand=1, + height=60, + bgcolor=ft.Colors.CYAN_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("1"), + ), + ft.Container( + expand=3, + height=60, + bgcolor=ft.Colors.AMBER_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("3"), + ), + ft.Container( + expand=1, + height=60, + bgcolor=ft.Colors.PINK_200, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("1"), + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/control/expand_row_proportional_1_3_1/pyproject.toml b/sdk/python/examples/controls/core/control/expand_row_proportional_1_3_1/pyproject.toml new file mode 100644 index 0000000000..d49c520dfa --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_row_proportional_1_3_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-row-proportional-1-3-1" +version = "1.0.0" +description = "Row example using proportional expand values (1:3:1) for responsive width distribution." +requires-python = ">=3.10" +keywords = ["control", "expand", "row", "proportional", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand row proportional 1 3 1" +controls = ["SafeArea", "Container", "Row", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["proportional expand", "row space distribution"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/control/expand_textfield_in_row/main.py b/sdk/python/examples/controls/core/control/expand_textfield_in_row/main.py new file mode 100644 index 0000000000..e890745122 --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_textfield_in_row/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Container( + width=480, + padding=10, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=10, + content=ft.Row( + controls=[ + ft.TextField(hint_text="Enter your name", expand=True), + ft.Button("Join chat"), + ] + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/control/expand_textfield_in_row/pyproject.toml b/sdk/python/examples/controls/core/control/expand_textfield_in_row/pyproject.toml new file mode 100644 index 0000000000..34e1114ea1 --- /dev/null +++ b/sdk/python/examples/controls/core/control/expand_textfield_in_row/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "control-expand-textfield-in-row" +version = "1.0.0" +description = "Row layout with an expanding TextField and fixed-size action button." +requires-python = ">=3.10" +keywords = ["control", "expand", "row", "textfield", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Control"] + +[tool.flet.metadata] +title = "Expand textfield in row" +controls = ["SafeArea", "Container", "Row", "TextField", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["expand in row", "mixed flexible and fixed controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/dismissible/dismissible_list_tiles/main.py b/sdk/python/examples/controls/core/dismissible/dismissible_list_tiles/main.py new file mode 100644 index 0000000000..cbda275343 --- /dev/null +++ b/sdk/python/examples/controls/core/dismissible/dismissible_list_tiles/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def main(page: ft.Page): + async def handle_dialog_action_click(e: ft.Event[ft.TextButton]): + page.pop_dialog() + await dialog.data.confirm_dismiss(e.control.data) + + dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Please confirm"), + content=ft.Text("Do you really want to delete this item?"), + actions=[ + ft.TextButton("Yes", data=True, on_click=handle_dialog_action_click), + ft.TextButton("No", data=False, on_click=handle_dialog_action_click), + ], + actions_alignment=ft.MainAxisAlignment.CENTER, + ) + + async def handle_confirm_dismiss(e: ft.DismissibleDismissEvent): + if e.direction == ft.DismissDirection.END_TO_START: + dialog.data = e.control + page.show_dialog(dialog) + else: + await e.control.confirm_dismiss(True) + + def handle_dismiss(e: ft.Event[ft.Dismissible]): + e.control.parent.controls.remove(e.control) + e.control.parent.update() + + def handle_update(e: ft.DismissibleUpdateEvent): + print(e) + + page.add( + ft.SafeArea( + content=ft.ListView( + expand=True, + controls=[ + ft.Dismissible( + dismiss_direction=ft.DismissDirection.HORIZONTAL, + background=ft.Container(bgcolor=ft.Colors.GREEN), + secondary_background=ft.Container(bgcolor=ft.Colors.RED), + on_dismiss=handle_dismiss, + on_update=handle_update, + on_confirm_dismiss=handle_confirm_dismiss, + dismiss_thresholds={ + ft.DismissDirection.END_TO_START: 0.2, + ft.DismissDirection.START_TO_END: 0.2, + }, + content=ft.ListTile(title=ft.Text(f"Item {i}")), + ) + for i in range(10) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/dismissible/dismissible_list_tiles/pyproject.toml b/sdk/python/examples/controls/core/dismissible/dismissible_list_tiles/pyproject.toml new file mode 100644 index 0000000000..1f6138ddd9 --- /dev/null +++ b/sdk/python/examples/controls/core/dismissible/dismissible_list_tiles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dismissible-list-tiles" +version = "1.0.0" +description = "Demonstrates dismissible ListTile items with per-direction backgrounds and confirm-dismiss dialog." +requires-python = ">=3.10" +keywords = ["dismissible", "list", "swipe", "confirmation", "dialog"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Dismissible"] + +[tool.flet.metadata] +title = "Dismissible ListTiles" +controls = ["SafeArea", "ListView", "Dismissible", "ListTile", "AlertDialog", "TextButton", "Container", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["swipe to dismiss", "confirm dismiss callback", "dismiss progress callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/dismissible/media/dismissible_list_tiles.gif b/sdk/python/examples/controls/core/dismissible/media/dismissible_list_tiles.gif new file mode 100644 index 0000000000..bce1e45322 Binary files /dev/null and b/sdk/python/examples/controls/core/dismissible/media/dismissible_list_tiles.gif differ diff --git a/sdk/python/examples/controls/core/dismissible/remove_on_dismiss_declarative/main.py b/sdk/python/examples/controls/core/dismissible/remove_on_dismiss_declarative/main.py new file mode 100644 index 0000000000..809c235a3d --- /dev/null +++ b/sdk/python/examples/controls/core/dismissible/remove_on_dismiss_declarative/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +@ft.component +def App(): + items, set_items = ft.use_state(list(range(5))) + + return ft.SafeArea( + content=ft.ListView( + controls=[ + ft.Dismissible( + key=i, + dismiss_direction=ft.DismissDirection.HORIZONTAL, + background=ft.Container(bgcolor=ft.Colors.GREEN), + secondary_background=ft.Container(bgcolor=ft.Colors.RED), + on_dismiss=lambda _, index=i: set_items( + [item for item in items if item != index] + ), + dismiss_thresholds={ + ft.DismissDirection.HORIZONTAL: 0.1, + ft.DismissDirection.START_TO_END: 0.1, + }, + content=ft.ListTile(title=ft.Text(f"Item {i}")), + ) + for i in items + ], + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/dismissible/remove_on_dismiss_declarative/pyproject.toml b/sdk/python/examples/controls/core/dismissible/remove_on_dismiss_declarative/pyproject.toml new file mode 100644 index 0000000000..a4f3eebd5b --- /dev/null +++ b/sdk/python/examples/controls/core/dismissible/remove_on_dismiss_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dismissible-remove-on-dismiss-declarative" +version = "1.0.0" +description = "Shows declarative Dismissible list updates by removing items from component state on dismiss." +requires-python = ">=3.10" +keywords = ["dismissible", "declarative", "component", "state", "list"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Dismissible"] + +[tool.flet.metadata] +title = "Remove on dismiss declarative" +controls = ["SafeArea", "ListView", "Dismissible", "ListTile"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["declarative state updates", "swipe to dismiss", "stable dismissible keys"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers/main.py b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers/main.py new file mode 100644 index 0000000000..6d173f788b --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers/main.py @@ -0,0 +1,82 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_drag_will_accept(e: ft.DragWillAcceptEvent): + e.control.content.border = ft.Border.all( + 2, + ft.Colors.BLACK_45 if e.accept else ft.Colors.RED, + ) + e.control.update() + + def handle_drag_accept(e: ft.DragTargetEvent): + e.control.content.bgcolor = e.src.content.bgcolor + e.control.content.border = None + e.control.update() + + def handle_drag_leave(e: ft.DragTargetLeaveEvent): + e.control.content.border = None + e.control.update() + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + controls=[ + ft.Draggable( + group="color", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN, + border_radius=5, + ), + content_feedback=ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.CYAN, + border_radius=3, + ), + ), + ft.Draggable( + group="color", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + ), + ), + ft.Draggable( + group="color", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ], + ), + ft.Container(width=100), + ft.DragTarget( + group="color", + on_will_accept=handle_drag_will_accept, + on_accept=handle_drag_accept, + on_leave=handle_drag_leave, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.BLUE_GREY_100, + border_radius=5, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml new file mode 100644 index 0000000000..14cad26d66 --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-and-drop-containers" +version = "1.0.0" +description = "Implements imperative drag-and-drop between Draggable color chips and a DragTarget box." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "drag and drop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "Drag and drop containers" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["drag and drop", "drop acceptance feedback", "target color update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers_declarative/main.py b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers_declarative/main.py new file mode 100644 index 0000000000..d3be31fe82 --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers_declarative/main.py @@ -0,0 +1,98 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class TargetState: + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + is_drag_over: bool = False + + +@ft.component +def App(): + target, _ = ft.use_state(lambda: TargetState()) + + def on_will_accept(_: ft.DragWillAcceptEvent): + target.is_drag_over = True + + def on_accept(e: ft.DragTargetEvent): + target.bgcolor = e.src.data + target.is_drag_over = False + + def on_leave(_: ft.DragTargetLeaveEvent): + target.is_drag_over = False + + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + controls=[ + ft.Draggable( + group="color", + data=ft.Colors.CYAN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN, + border_radius=5, + ), + content_feedback=ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.CYAN, + border_radius=3, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.YELLOW, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + ), + ), + ft.Draggable( + group="color", + data=ft.Colors.GREEN, + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ], + ), + ft.Container(width=100), + ft.DragTarget( + group="color", + on_will_accept=on_will_accept, + on_accept=on_accept, + on_leave=on_leave, + content=ft.Container( + width=50, + height=50, + bgcolor=target.bgcolor, + border=( + ft.Border.all(2, ft.Colors.BLACK_45) + if target.is_drag_over + else None + ), + border_radius=5, + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml new file mode 100644 index 0000000000..be5ff96a5a --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_containers_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-and-drop-containers-declarative" +version = "1.0.0" +description = "Builds declarative drag-and-drop containers with observable target state and hover feedback." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "drag and drop", "declarative", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "Drag and drop containers declarative" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["declarative state", "drag and drop", "hover border feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_ordering_declarative/main.py b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_ordering_declarative/main.py new file mode 100644 index 0000000000..4c0051dec8 --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_ordering_declarative/main.py @@ -0,0 +1,258 @@ +from dataclasses import dataclass, field + +import flet as ft + +ItemID = ft.IdCounter() + + +@ft.observable +@dataclass +class AppState: + groups: list["Group"] = field(default_factory=list) + + def move_group(self, src: "Group", dst: "Group"): + src_index = self.groups.index(src) + dst_index = self.groups.index(dst) + if src_index != dst_index: + print("Move group", src.title, "to position of", dst.title) + self.groups.insert(dst_index, self.groups.pop(src_index)) + + +@ft.observable +@dataclass +class Group: + title: str + color: ft.Colors + items: list["Item"] = field(default_factory=list) + + def add_item(self, text: str): + self.items.append(Item(text=text, group=self)) + + def move_item_into(self, item: "Item"): + print("Move item", item.text, "from", item.group.title, "to", self.title) + item.group.items.remove(item) + item.group = self + self.items.append(item) + + +@ft.observable +@dataclass +class Item: + text: str + group: Group + id: int = field(default_factory=ItemID) + + def move_item_at(self, item: "Item", to_item: "Item"): + if item == to_item: + return + print( + f"Move item {item.text} from {item.group.title} " + f"to {to_item.group.title} at position of {to_item.text}" + ) + item.group.items.remove(item) + item.group = to_item.group + to_index = to_item.group.items.index(to_item) + to_item.group.items.insert(to_index, item) + + +@ft.component +def ItemView(item: Item, **kwargs): + is_item_over, set_is_item_over = ft.use_state(False) + + def on_accept(e: ft.DragTargetEvent): + item.move_item_at(e.src.data, item) + set_is_item_over(False) + + return ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Divider( + color=ft.Colors.BLACK38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_item_over else 0.0, + ), + ft.Draggable( + group="items", + data=item, + content=ft.DragTarget( + group="items", + data=item, + on_will_accept=lambda e: set_is_item_over( + e.accept and e.src.data != item + ), + on_accept=on_accept, + on_leave=lambda _: set_is_item_over(False), + content=ft.Card( + content=ft.Container( + padding=7, + width=200, + content=ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Icon(ft.Icons.CIRCLE_OUTLINED), + ft.Text(value=item.text), + ], + ), + ), + ), + ), + ), + ], + ) + + +@ft.component +def GroupView(group: Group, move_group, **kwargs): + is_group_over, set_is_group_over = ft.use_state(False) + is_item_over, set_is_item_over = ft.use_state(False) + new_item_text, set_new_item_text = ft.use_state("") + + def on_item_accept(e: ft.DragTargetEvent): + group.move_item_into(e.src.data) + set_is_item_over(False) + + def on_group_accept(e: ft.DragTargetEvent): + move_group(e.src.data, group) + set_is_group_over(False) + + def on_add_item(_: ft.Event[ft.TextButton] | None = None): + if stripped_text := new_item_text.strip(): + group.add_item(stripped_text) + set_new_item_text("") + + return ft.Row( + spacing=4, + intrinsic_height=True, + controls=[ + ft.VerticalDivider( + color=ft.Colors.BLACK_54, + width=2, + thickness=2, + radius=2, + leading_indent=15, + trailing_indent=15, + opacity=1.0 if is_group_over else 0.0, + ), + ft.Draggable( + group="groups", + data=group, + content=ft.DragTarget( + group="items", + data=group, + on_will_accept=lambda e: set_is_item_over(e.accept), + on_accept=on_item_accept, + on_leave=lambda _: set_is_item_over(False), + content=ft.DragTarget( + group="groups", + data=group, + on_will_accept=lambda e: set_is_group_over( + e.accept and e.src.data != group + ), + on_accept=on_group_accept, + on_leave=lambda _: set_is_group_over(False), + content=ft.Container( + border=( + ft.Border.all(2, ft.Colors.BLACK12) + if not is_group_over + else ft.Border.all(2, ft.Colors.BLACK38) + ), + border_radius=ft.BorderRadius.all(15), + bgcolor=group.color, + padding=ft.Padding.all(20), + width=220, + content=ft.Column( + spacing=4, + controls=[ + ft.Text( + group.title, + theme_style=ft.TextThemeStyle.TITLE_LARGE, + ), + ft.TextField( + label="New item", + bgcolor=ft.Colors.WHITE, + value=new_item_text, + on_change=lambda e: set_new_item_text( + e.control.value + ), + on_submit=on_add_item, + ), + ft.TextButton( + icon=ft.Icons.ADD, + on_click=on_add_item, + content="Add", + ), + ft.Column( + spacing=2, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + *[ + ItemView(item, key=item.id) + for item in group.items + ], + ft.Divider( + color=ft.Colors.BLACK38, + thickness=2, + height=2, + radius=2, + opacity=1.0 if is_item_over else 0.0, + ), + ], + ), + ], + ), + ), + ), + ), + ), + ], + ) + + +@ft.component +def App(): + group_1 = Group(title="Group 1", color=ft.Colors.DEEP_ORANGE_400) + group_1.add_item("Item 1") + group_1.add_item("Item 2") + + group_2 = Group(title="Group 2", color=ft.Colors.PINK_400) + group_2.add_item("Item 3") + + group_3 = Group(title="Group 3", color=ft.Colors.CYAN_400) + group_3.add_item("Item 4") + + app, _ = ft.use_state( + lambda: AppState( + groups=[ + group_1, + group_2, + group_3, + ] + ) + ) + + def on_mounted(): + ft.context.page.theme_mode = ft.ThemeMode.LIGHT + + ft.on_mounted(on_mounted) + + return ft.SafeArea( + content=ft.Row( + spacing=4, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + GroupView(group, move_group=app.move_group, key=group.title) + for group in app.groups + ], + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml new file mode 100644 index 0000000000..30778e4be1 --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_and_drop_ordering_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-and-drop-ordering-declarative" +version = "1.0.0" +description = "Provides declarative drag-and-drop ordering across groups with nested DragTarget and Draggable controls." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "ordering", "declarative", "kanban"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "Drag and drop ordering declarative" +controls = ["SafeArea", "Row", "Column", "Draggable", "DragTarget", "Card", "TextField", "TextButton", "Divider", "VerticalDivider"] +layout_pattern = "dashboard" +complexity = "intermediate" +features = ["group reordering", "item reordering", "nested drag targets", "declarative state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_target_positions/main.py b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_target_positions/main.py new file mode 100644 index 0000000000..1739203143 --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_target_positions/main.py @@ -0,0 +1,115 @@ +import flet as ft + + +def main(page: ft.Page): + def refresh_position(e: ft.DragTargetEvent): + lp_label.value = ( + f"local_position: ({e.local_position.x:.1f}, {e.local_position.y:.1f})" + ) + gp_label.value = ( + f"global_position: ({e.global_position.x:.1f}, {e.global_position.y:.1f})" + ) + target.update() + + def handle_will_accept(e: ft.DragWillAcceptEvent): + target.content.border = ft.Border.all(3, ft.Colors.RED) + target.update() + + def handle_move(e: ft.DragTargetEvent): + refresh_position(e) + + def handle_accept(e: ft.DragTargetEvent): + refresh_position(e) + + def handle_leave(e: ft.DragTargetLeaveEvent): + target.content.border = ft.Border.all(3, ft.Colors.BLUE_GREY_300) + target.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Row( + spacing=24, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Draggable( + group="demo", + content_feedback=ft.Container( + width=40, + height=40, + border_radius=18, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.with_opacity(0.5, ft.Colors.RED), + border=ft.Border.all( + 1.5, + ft.Colors.with_opacity( + 0.35, ft.Colors.BLUE_500 + ), + ), + shadow=ft.BoxShadow( + blur_radius=16, + color=ft.Colors.with_opacity( + 0.16, ft.Colors.BLUE_500 + ), + offset=ft.Offset(0, 6), + ), + content=ft.Icon( + ft.Icons.OPEN_WITH_ROUNDED, + color=ft.Colors.BLUE_600, + ), + ), + content=ft.Container( + width=72, + height=72, + border_radius=12, + bgcolor=ft.Colors.BLUE_500, + alignment=ft.Alignment.CENTER, + content=ft.Text("Drag me", color=ft.Colors.WHITE), + ), + ), + target := ft.DragTarget( + group="demo", + on_will_accept=handle_will_accept, + on_move=handle_move, + on_accept=handle_accept, + on_leave=handle_leave, + content=ft.Container( + width=290, + height=180, + padding=16, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_300), + border_radius=12, + bgcolor=ft.Colors.BLUE_GREY_50, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + "Drop here", + size=16, + weight=ft.FontWeight.BOLD, + ), + lp_label := ft.Text( + "local_position: -", + text_align=ft.TextAlign.CENTER, + ), + gp_label := ft.Text( + "global_position: -", + text_align=ft.TextAlign.CENTER, + ), + ], + ), + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/drag_target_positions/pyproject.toml b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_target_positions/pyproject.toml new file mode 100644 index 0000000000..27ca56d0ac --- /dev/null +++ b/sdk/python/examples/controls/core/drag_target_and_draggable/drag_target_positions/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "drag-target-positions" +version = "1.0.0" +description = "Shows DragTarget local_position and global_position values updating live while a draggable moves inside the target." +requires-python = ">=3.10" +keywords = ["draggable", "drag target", "drag position", "local position", "global position"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Draggable"] + +[tool.flet.metadata] +title = "DragTarget positions" +controls = ["SafeArea", "Column", "Row", "Draggable", "DragTarget", "Container", "Text", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["live drag coordinates", "local_position", "global_position", "drop target feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/drag_target_and_draggable/media/drag_and_drop_containers.gif b/sdk/python/examples/controls/core/drag_target_and_draggable/media/drag_and_drop_containers.gif new file mode 100644 index 0000000000..96f639e448 Binary files /dev/null and b/sdk/python/examples/controls/core/drag_target_and_draggable/media/drag_and_drop_containers.gif differ diff --git a/sdk/python/examples/controls/core/gesture_detector/draggable_containers/main.py b/sdk/python/examples/controls/core/gesture_detector/draggable_containers/main.py new file mode 100644 index 0000000000..3ceae2d653 --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/draggable_containers/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_pan_update1(e: ft.DragUpdateEvent[ft.GestureDetector]): + container = e.control.parent + container.top = max(0.0, container.top + e.local_delta.y) + container.left = max(0.0, container.left + e.local_delta.x) + container.update() + + def handle_pan_update2(e: ft.DragUpdateEvent[ft.GestureDetector]): + e.control.top = max(0.0, e.control.top + e.local_delta.y) + e.control.left = max(0.0, e.control.left + e.local_delta.x) + e.control.update() + + page.add( + ft.SafeArea( + content=ft.Stack( + width=1000, + height=500, + controls=[ + ft.Container( + bgcolor=ft.Colors.AMBER, + width=50, + height=50, + left=0, + top=0, + content=ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=10, + on_pan_update=handle_pan_update1, + ), + ), + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=10, + on_vertical_drag_update=handle_pan_update2, + left=100, + top=100, + content=ft.Container( + bgcolor=ft.Colors.BLUE, + width=50, + height=50, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/gesture_detector/draggable_containers/pyproject.toml b/sdk/python/examples/controls/core/gesture_detector/draggable_containers/pyproject.toml new file mode 100644 index 0000000000..b412691782 --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/draggable_containers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-draggable-containers" +version = "1.0.0" +description = "Drags nested and standalone GestureDetector controls inside a Stack using pan updates." +requires-python = ">=3.10" +keywords = ["gesture detector", "drag", "pan update", "stack", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Draggable containers" +controls = ["SafeArea", "Stack", "Container", "GestureDetector"] +layout_pattern = "canvas" +complexity = "basic" +features = ["free dragging", "nested gesture detector", "position updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/gesture_detector/handling_events/main.py b/sdk/python/examples/controls/core/gesture_detector/handling_events/main.py new file mode 100644 index 0000000000..22ce866537 --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/handling_events/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.GestureDetector( + hover_interval=50, + on_tap=lambda e: print(e), + on_tap_down=lambda e: print(e), + on_tap_up=lambda e: print(e), + on_secondary_tap=lambda e: print(e), + on_secondary_tap_down=lambda e: print(e), + on_secondary_tap_up=lambda e: print(e), + on_long_press_start=lambda e: print(e), + on_long_press_end=lambda e: print(e), + on_secondary_long_press_start=lambda e: print(e), + on_secondary_long_press_end=lambda e: print(e), + on_double_tap=lambda e: print(e), + on_double_tap_down=lambda e: print(e), + on_pan_start=lambda e: print(e), + on_pan_update=lambda e: print(e), + on_pan_end=lambda e: print(e), + on_hover=lambda e: print(e), + on_enter=lambda e: print(e), + on_exit=lambda e: print(e), + content=ft.Container( + bgcolor=ft.Colors.GREEN, + width=200, + height=200, + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/gesture_detector/handling_events/pyproject.toml b/sdk/python/examples/controls/core/gesture_detector/handling_events/pyproject.toml new file mode 100644 index 0000000000..c753db7140 --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-handling-events" +version = "1.0.0" +description = "Logs tap, press, pan, hover, and enter/exit callbacks from a single GestureDetector." +requires-python = ">=3.10" +keywords = ["gesture detector", "events", "tap", "pan", "hover"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "GestureDetector", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["multi-gesture callbacks", "hover and pointer callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/gesture_detector/media/draggable_containers.gif b/sdk/python/examples/controls/core/gesture_detector/media/draggable_containers.gif new file mode 100644 index 0000000000..88ae3784dd Binary files /dev/null and b/sdk/python/examples/controls/core/gesture_detector/media/draggable_containers.gif differ diff --git a/sdk/python/examples/controls/core/gesture_detector/mouse_cursors/main.py b/sdk/python/examples/controls/core/gesture_detector/mouse_cursors/main.py new file mode 100644 index 0000000000..f0321d16c2 --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/mouse_cursors/main.py @@ -0,0 +1,50 @@ +import random + +import flet as ft + + +def main(page: ft.Page): + def on_pan_update(event: ft.DragUpdateEvent[ft.GestureDetector]): + container.top = max(0.0, container.top + event.local_delta.y) + container.left = max(0.0, container.left + event.local_delta.x) + container.update() + + gesture_detector = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.BASIC, + drag_interval=50, + on_pan_update=on_pan_update, + ) + container = ft.Container( + bgcolor=ft.Colors.AMBER, + width=150, + height=150, + left=0, + top=0, + content=gesture_detector, + ) + + def handle_button_click(e: ft.Event[ft.Button]): + gesture_detector.mouse_cursor = random.choice(list(ft.MouseCursor)) + text.value = f"Mouse Cursor: {gesture_detector.mouse_cursor}" + gesture_detector.update() + text.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + width=1000, + height=500, + controls=[container], + ), + ft.Button("Change mouse Cursor", on_click=handle_button_click), + text := ft.Text(f"Mouse Cursor: {gesture_detector.mouse_cursor}"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/gesture_detector/mouse_cursors/pyproject.toml b/sdk/python/examples/controls/core/gesture_detector/mouse_cursors/pyproject.toml new file mode 100644 index 0000000000..14df3ff2e1 --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/mouse_cursors/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-mouse-cursors" +version = "1.0.0" +description = "Randomizes GestureDetector mouse cursors and drags the target container in a Stack." +requires-python = ">=3.10" +keywords = ["gesture detector", "mouse cursor", "drag", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Mouse cursors" +controls = ["SafeArea", "Column", "Stack", "Container", "GestureDetector", "Button", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["cursor switching", "drag interaction", "live status text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/gesture_detector/window_drag_area/main.py b/sdk/python/examples/controls/core/gesture_detector/window_drag_area/main.py new file mode 100644 index 0000000000..19221a2d2c --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/window_drag_area/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def on_pan_update(e: ft.DragUpdateEvent[ft.GestureDetector]): + page.window.left += e.global_delta.x + page.window.top += e.global_delta.y + + page.add( + ft.SafeArea( + content=ft.Stack( + width=1000, + height=500, + controls=[ + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + on_pan_update=on_pan_update, + left=200, + top=200, + content=ft.Container( + bgcolor=ft.Colors.PINK, + width=50, + height=50, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/gesture_detector/window_drag_area/pyproject.toml b/sdk/python/examples/controls/core/gesture_detector/window_drag_area/pyproject.toml new file mode 100644 index 0000000000..d59165524f --- /dev/null +++ b/sdk/python/examples/controls/core/gesture_detector/window_drag_area/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "gesture-detector-window-drag-area" +version = "1.0.0" +description = "Moves the app window by dragging a GestureDetector handle control." +requires-python = ">=3.10" +keywords = ["gesture detector", "window", "drag", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/GestureDetector"] + +[tool.flet.metadata] +title = "Window drag area" +controls = ["SafeArea", "Stack", "GestureDetector", "Container"] +layout_pattern = "canvas" +complexity = "basic" +features = ["window dragging", "global drag delta"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/grid_view/media/photo_gallery.png b/sdk/python/examples/controls/core/grid_view/media/photo_gallery.png new file mode 100644 index 0000000000..723434a026 Binary files /dev/null and b/sdk/python/examples/controls/core/grid_view/media/photo_gallery.png differ diff --git a/sdk/python/examples/controls/core/grid_view/photo_gallery/main.py b/sdk/python/examples/controls/core/grid_view/photo_gallery/main.py new file mode 100644 index 0000000000..ea96f88d95 --- /dev/null +++ b/sdk/python/examples/controls/core/grid_view/photo_gallery/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "GridView Example" + page.theme_mode = ft.ThemeMode.DARK + page.padding = 50 + + page.add( + ft.SafeArea( + expand=True, + content=ft.GridView( + expand=True, + runs_count=5, + max_extent=150, + child_aspect_ratio=1.0, + spacing=5, + run_spacing=5, + controls=[ + ft.Image( + src=f"https://picsum.photos/150/150?{i}", + fit=ft.BoxFit.NONE, + repeat=ft.ImageRepeat.NO_REPEAT, + border_radius=ft.BorderRadius.all(10), + ) + for i in range(0, 60) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/grid_view/photo_gallery/pyproject.toml b/sdk/python/examples/controls/core/grid_view/photo_gallery/pyproject.toml new file mode 100644 index 0000000000..4cb1c16f4c --- /dev/null +++ b/sdk/python/examples/controls/core/grid_view/photo_gallery/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "grid-view-photo-gallery" +version = "1.0.0" +description = "Renders a responsive GridView photo gallery with remote images and spacing configuration." +requires-python = ">=3.10" +keywords = ["grid view", "photo gallery", "images", "responsive layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/GridView"] + +[tool.flet.metadata] +title = "Photo gallery" +controls = ["SafeArea", "GridView", "Image"] +layout_pattern = "gallery" +complexity = "basic" +features = ["remote image grid", "responsive runs and extent", "rounded thumbnails"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/hero/basic/main.py b/sdk/python/examples/controls/core/hero/basic/main.py new file mode 100644 index 0000000000..cb3ba79d46 --- /dev/null +++ b/sdk/python/examples/controls/core/hero/basic/main.py @@ -0,0 +1,131 @@ +import flet as ft + + +def main(page: ft.Page): + hero_tag = "demo-hero-card" + + def build_card(size: int, label: str) -> ft.Container: + icon_size = max(24, int(size * 0.28)) + return ft.Container( + width=size, + height=size, + border_radius=ft.BorderRadius.all(20), + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment.BOTTOM_RIGHT, + colors=[ft.Colors.BLUE_700, ft.Colors.CYAN_400], + ), + alignment=ft.Alignment.CENTER, + content=ft.Stack( + fit=ft.StackFit.EXPAND, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Icon( + ft.Icons.ROCKET_LAUNCH, + size=icon_size, + color=ft.Colors.WHITE, + ), + ), + ft.Container( + alignment=ft.Alignment.BOTTOM_CENTER, + padding=ft.Padding.only(left=8, right=8, bottom=10), + content=ft.Text( + label, + color=ft.Colors.WHITE, + weight=ft.FontWeight.BOLD, + size=12, + no_wrap=True, + max_lines=1, + overflow=ft.TextOverflow.ELLIPSIS, + text_align=ft.TextAlign.CENTER, + ), + ), + ], + ), + ) + + async def go_to_details(_): + await page.push_route("/details") + + async def go_home(_): + await page.push_route("/") + + def build_home_view() -> ft.View: + return ft.View( + route="/", + appbar=ft.AppBar(title=ft.Text("Hero animation")), + controls=[ + ft.SafeArea( + expand=True, + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text("Tap the card to navigate"), + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.CLICK, + on_tap=go_to_details, + content=ft.Hero( + tag=hero_tag, + content=build_card(130, "Open details"), + ), + ), + ], + ), + ), + ) + ], + ) + + def build_details_view() -> ft.View: + return ft.View( + route="/details", + appbar=ft.AppBar(title=ft.Text("Details")), + controls=[ + ft.SafeArea( + expand=True, + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Hero( + tag=hero_tag, + transition_on_user_gestures=True, + content=build_card(280, "Details"), + ), + ft.Button("Back", on_click=go_home), + ], + ), + ), + ) + ], + ) + + def route_change(e: ft.RouteChangeEvent = None): + page.views.clear() + page.views.append(build_home_view()) + if page.route == "/details": + page.views.append(build_details_view()) + page.update() + + async def view_pop(e: ft.ViewPopEvent): + if e.view is not None: + page.views.remove(e.view) + await page.push_route(page.views[-1].route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + route_change() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/hero/basic/pyproject.toml b/sdk/python/examples/controls/core/hero/basic/pyproject.toml new file mode 100644 index 0000000000..736bedf137 --- /dev/null +++ b/sdk/python/examples/controls/core/hero/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "hero-basic" +version = "1.0.0" +description = "Demonstrates Hero animation between home and details views with a shared tagged card." +requires-python = ">=3.10" +keywords = ["hero", "animation", "route transition", "navigation", "gesture"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Hero"] + +[tool.flet.metadata] +title = "Basic" +controls = ["View", "SafeArea", "Container", "Column", "GestureDetector", "Hero", "AppBar", "Button", "Text", "Icon"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["hero route transition", "shared hero tag", "view navigation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/hero/gallery/main.py b/sdk/python/examples/controls/core/hero/gallery/main.py new file mode 100644 index 0000000000..5acb56eca3 --- /dev/null +++ b/sdk/python/examples/controls/core/hero/gallery/main.py @@ -0,0 +1,223 @@ +import flet as ft + +PRODUCTS = [ + { + "id": 1, + "name": "Comet", + "subtitle": "Fast launch profile", + "description": "Balanced setup for quick iteration and lightweight payloads.", + "icon": ft.Icons.ROCKET_LAUNCH, + "start_color": ft.Colors.BLUE_700, + "end_color": ft.Colors.CYAN_400, + }, + { + "id": 2, + "name": "Nebula", + "subtitle": "Visual pipeline", + "description": "Optimized for rich UI transitions and animated data surfaces.", + "icon": ft.Icons.AUTO_AWESOME, + "start_color": ft.Colors.DEEP_PURPLE_700, + "end_color": ft.Colors.PINK_400, + }, + { + "id": 3, + "name": "Orbit", + "subtitle": "Reliable baseline", + "description": "Stable profile focused on consistency and performance.", + "icon": ft.Icons.PUBLIC, + "start_color": ft.Colors.GREEN_700, + "end_color": ft.Colors.LIGHT_GREEN_400, + }, + { + "id": 4, + "name": "Aurora", + "subtitle": "Analytics focus", + "description": "Configured for telemetry-heavy apps and live metrics.", + "icon": ft.Icons.ANALYTICS, + "start_color": ft.Colors.ORANGE_700, + "end_color": ft.Colors.AMBER_400, + }, + { + "id": 5, + "name": "Pulse", + "subtitle": "Real-time profile", + "description": "Tuned for frequent updates, messaging, and event streams.", + "icon": ft.Icons.BOLT, + "start_color": ft.Colors.RED_700, + "end_color": ft.Colors.DEEP_ORANGE_400, + }, +] + + +def hero_tag(product_id: int) -> str: + return f"product-hero-{product_id}" + + +def main(page: ft.Page): + def product_by_id(product_id: int): + for product in PRODUCTS: + if product["id"] == product_id: + return product + return None + + def route_product_id(route: str): + segments = [segment for segment in route.split("/") if segment] + if len(segments) != 2 or segments[0] != "product": + return None + try: + return int(segments[1]) + except ValueError: + return None + + async def open_product(product_id: int): + await page.push_route(f"/product/{product_id}") + + async def back_to_gallery(e: ft.Event[ft.Button]): + await page.push_route("/") + + def build_hero_tile(product: dict, size: int) -> ft.Hero: + icon_size = max(24, int(size * 0.4)) + return ft.Hero( + tag=hero_tag(product["id"]), + transition_on_user_gestures=True, + content=ft.Container( + width=size, + height=size, + border_radius=ft.BorderRadius.all(20), + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment.BOTTOM_RIGHT, + colors=[product["start_color"], product["end_color"]], + ), + alignment=ft.Alignment.CENTER, + content=ft.Icon(product["icon"], color=ft.Colors.WHITE, size=icon_size), + ), + ) + + def build_home_view() -> ft.View: + rows: list[ft.Control] = [] + for product in PRODUCTS: + rows.append( + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.CLICK, + on_tap=lambda _, pid=product["id"]: page.run_task( + open_product, pid + ), + content=ft.Card( + content=ft.Container( + padding=12, + content=ft.Row( + vertical_alignment=ft.CrossAxisAlignment.CENTER, + spacing=12, + controls=[ + build_hero_tile(product, 78), + ft.Column( + spacing=4, + controls=[ + ft.Text( + product["name"], + size=18, + weight=ft.FontWeight.W_600, + ), + ft.Text( + product["subtitle"], + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Text( + "Tap to view details", + size=12, + color=ft.Colors.PRIMARY, + ), + ], + ), + ], + ), + ) + ), + ) + ) + + return ft.View( + route="/", + appbar=ft.AppBar(title=ft.Text("Hero gallery")), + controls=[ + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + spacing=10, + scroll=ft.ScrollMode.AUTO, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + "Each card has a unique Hero tag. " + "Open any item to see a matched transition.", + color=ft.Colors.ON_SURFACE_VARIANT, + ), + *rows, + ], + ), + ) + ], + ) + + def build_details_view(product: dict) -> ft.View: + return ft.View( + route=f"/product/{product['id']}", + appbar=ft.AppBar(title=ft.Text(product["name"])), + controls=[ + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=16, + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Container(height=8), + build_hero_tile(product, 220), + ft.Text( + product["subtitle"], + size=20, + weight=ft.FontWeight.W_600, + text_align=ft.TextAlign.CENTER, + ), + ft.Container( + width=520, + content=ft.Text( + product["description"], + text_align=ft.TextAlign.CENTER, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ), + ft.Button("Back to gallery", on_click=back_to_gallery), + ], + ), + ) + ], + ) + + def route_change(e: ft.RouteChangeEvent = None): + page.views.clear() + page.views.append(build_home_view()) + + pid = route_product_id(page.route) + if pid is not None: + product = product_by_id(pid) + if product is not None: + page.views.append(build_details_view(product)) + + page.update() + + async def view_pop(e: ft.ViewPopEvent): + if e.view is not None: + page.views.remove(e.view) + await page.push_route(page.views[-1].route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + route_change() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/hero/gallery/pyproject.toml b/sdk/python/examples/controls/core/hero/gallery/pyproject.toml new file mode 100644 index 0000000000..d5fa75ca01 --- /dev/null +++ b/sdk/python/examples/controls/core/hero/gallery/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "hero-gallery" +version = "1.0.0" +description = "Shows a gallery of items with unique Hero tags and animated transitions to detail views." +requires-python = ">=3.10" +keywords = ["hero", "gallery", "animation", "navigation", "cards"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Hero"] + +[tool.flet.metadata] +title = "Gallery" +controls = ["View", "SafeArea", "Column", "Row", "Container", "Card", "GestureDetector", "Hero", "AppBar", "Button", "Text", "Icon"] +layout_pattern = "gallery" +complexity = "basic" +features = ["multiple hero tags", "list-to-details transition", "scrollable gallery"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/icon/basic/main.py b/sdk/python/examples/controls/core/icon/basic/main.py new file mode 100644 index 0000000000..e6269a2e42 --- /dev/null +++ b/sdk/python/examples/controls/core/icon/basic/main.py @@ -0,0 +1,67 @@ +from typing import cast + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # material + ft.Row( + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon( + ft.Icons.AUDIOTRACK, + color=ft.Colors.GREEN_400, + size=30, + ), + ft.Icon( + ft.Icons.BEACH_ACCESS, + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), + ] + ), + # cupertino + ft.Row( + controls=[ + ft.Icon( + ft.CupertinoIcons.PROFILE_CIRCLED, + color=ft.Colors.PINK, + ), + ft.Icon( + icon=cast( + ft.CupertinoIcons, + ft.CupertinoIcons.random(), + ), + color=ft.Colors.GREEN_400, + size=30, + ), + ft.Icon( + icon=cast( + ft.CupertinoIcons, + ft.CupertinoIcons.random(), + ), + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon( + icon=cast( + ft.CupertinoIcons, + ft.CupertinoIcons.random(), + ), + color="#c1c1c1", + ), + ] + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/icon/basic/pyproject.toml b/sdk/python/examples/controls/core/icon/basic/pyproject.toml new file mode 100644 index 0000000000..4c927ec0ca --- /dev/null +++ b/sdk/python/examples/controls/core/icon/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-basic" +version = "1.0.0" +description = "Displays Material and Cupertino icons with different sizes and colors." +requires-python = ">=3.10" +keywords = ["icon", "material icons", "cupertino icons", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Icon"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Row", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["material icons", "cupertino icons", "icon color and size"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/icon/media/basic.png b/sdk/python/examples/controls/core/icon/media/basic.png new file mode 100644 index 0000000000..7b7cb64aac Binary files /dev/null and b/sdk/python/examples/controls/core/icon/media/basic.png differ diff --git a/media/icons/macos/flet-png/app_icon_512.png b/sdk/python/examples/controls/core/image/assets/app_icon_512.png similarity index 100% rename from media/icons/macos/flet-png/app_icon_512.png rename to sdk/python/examples/controls/core/image/assets/app_icon_512.png diff --git a/sdk/python/examples/controls/core/image/dynamic_svg/main.py b/sdk/python/examples/controls/core/image/dynamic_svg/main.py new file mode 100644 index 0000000000..f7fbf83804 --- /dev/null +++ b/sdk/python/examples/controls/core/image/dynamic_svg/main.py @@ -0,0 +1,26 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + svg_image = """ + + + + + +""" + + img = ft.Image(src=svg_image.format(0, 0)) + page.add(ft.SafeArea(content=img)) + + for _ in range(0, 10): + for i in range(0, 10): + img.src = svg_image.format(i * 10, i * 10) + img.update() + await asyncio.sleep(0.1) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/dynamic_svg/pyproject.toml b/sdk/python/examples/controls/core/image/dynamic_svg/pyproject.toml new file mode 100644 index 0000000000..9b980ea1ea --- /dev/null +++ b/sdk/python/examples/controls/core/image/dynamic_svg/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-dynamic-svg" +version = "1.0.0" +description = "Animates an inline SVG image by updating ellipse dimensions over time." +requires-python = ">=3.10" +keywords = ["image", "svg", "dynamic svg", "animation", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying a dynamic SVG image" +controls = ["SafeArea", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["inline svg generation", "async animation loop", "dynamic image updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/image/fade_in/main.py b/sdk/python/examples/controls/core/image/fade_in/main.py new file mode 100644 index 0000000000..1fc7a187de --- /dev/null +++ b/sdk/python/examples/controls/core/image/fade_in/main.py @@ -0,0 +1,43 @@ +import time + +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def show_random(e: ft.Event[ft.Button]): + image.src = f"https://picsum.photos/320/200?random={time.time()}" # random + image.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + image := ft.Image( + src="https://picsum.photos/320/200?random=1", + width=360, + height=220, + fit=ft.BoxFit.COVER, + # solid blue image as bas64 + placeholder_src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAAAmCAYAAACyAQkgAAAMS2lDQ1BJQ0MgUHJvZmlsZQAASImVVwdck0cbv3dkQggQCENG2EsQkRFARggr7I0gKiEJEEaMCUHFjRYrWCcigqOiVRDFDYi4UKtWiuK2juJApVKLtbiV70IALf3G77v87u6f/z33v+d53nvHAUDv4kuleagmAPmSAllcSABrUkoqi9QD1AAV/qyBHl8gl3JiYiIALMP938vrGwBR9lcdlVr/HP+vRUsokgsAQGIgzhDKBfkQHwIAbxVIZQUAEKWQt5hZIFXicoh1ZNBBiGuVOEuFW5U4Q4UvD9okxHEhfgwAWZ3Pl2UBoNEHeVahIAvq0GG0wFkiFEsg9ofYNz9/uhDihRDbQhu4Jl2pz874Sifrb5oZI5p8ftYIVsUyWMiBYrk0jz/7/0zH/y75eYrhNWxgVc+WhcYpY4Z5e5w7PVyJ1SF+K8mIioZYGwAUFwsH7ZWYma0ITVTZo7YCORfmDDAhnijPi+cN8XFCfmA4xEYQZ0ryoiKGbIozxcFKG5g/tFJcwEuAWB/iWpE8KH7I5qRsetzwujcyZVzOEP+MLxv0Qan/WZGbyFHpY9rZIt6QPuZUlJ2QDDEV4sBCcVIUxBoQR8lz48OHbNKKsrlRwzYyRZwyFkuIZSJJSIBKH6vIlAXHDdnvypcPx46dzBbzoobwlYLshFBVrrDHAv6g/zAWrE8k4SQO64jkkyKGYxGKAoNUseNkkSQxXsXj+tKCgDjVXNxemhczZI8HiPJClLw5xAnywvjhuYUFcHOq9PESaUFMgspPvCqHHxaj8gffByIAFwQCFlDAmgGmgxwg7uht6oX/VCPBgA9kIAuIgOMQMzwjeXBEAtt4UAR+h0gE5CPzAgZHRaAQ8p9GsUpOPMKpWkeQOTSmVMkFTyDOB+EgD/5XDCpJRjxIAo8hI/6HR3xYBTCGPFiV4/+eH2a/MBzIRAwxiuEVWfRhS2IQMZAYSgwm2uGGuC/ujUfA1h9WF5yNew7H8cWe8ITQSXhIuE7oItyeJi6WjfIyEnRB/eCh/GR8nR/cGmq64QG4D1SHyjgTNwSOuCtch4P7wZXdIMsd8luZFdYo7b9F8NUVGrKjOFNQih7Fn2I7eqaGvYbbiIoy11/nR+Vrxki+uSMjo9fnfpV9IezDR1ti32IHsXPYKewC1oo1ARZ2AmvG2rFjSjyy4x4P7rjh1eIG/cmFOqP3zJcrq8yk3Lneucf5o2qsQDSrQHkzcqdLZ8vEWdkFLA58Y4hYPInAaSzLxdnFDQDl+0f1eHsVO/heQZjtX7jFvwLgc2JgYODoFy7sBAD7PeAj4cgXzpYNXy1qAJw/IlDIClUcrmwI8MlBh3efATABFsAWxuMC3IE38AdBIAxEgwSQAqZC77PhPpeBmWAuWARKQBlYBdaBKrAFbAO1YA84AJpAKzgFfgQXwWVwHdyBu6cbPAd94DX4gCAICaEhDMQAMUWsEAfEBWEjvkgQEoHEISlIOpKFSBAFMhdZjJQha5AqZCtSh+xHjiCnkAtIJ3IbeYD0IH8i71EMVUd1UGPUGh2HslEOGo4moFPQLHQGWoQuQVeglWgNuhttRE+hF9HraBf6HO3HAKaGMTEzzBFjY1wsGkvFMjEZNh8rxSqwGqwBa4HX+SrWhfVi73AizsBZuCPcwaF4Ii7AZ+Dz8eV4FV6LN+Jn8Kv4A7wP/0ygEYwIDgQvAo8wiZBFmEkoIVQQdhAOE87Ce6mb8JpIJDKJNkQPeC+mEHOIc4jLiZuIe4kniZ3ER8R+EolkQHIg+ZCiSXxSAamEtIG0m3SCdIXUTXpLViObkl3IweRUsoRcTK4g7yIfJ18hPyV/oGhSrChelGiKkDKbspKyndJCuUTppnygalFtqD7UBGoOdRG1ktpAPUu9S32lpqZmruapFqsmVluoVqm2T+282gO1d+ra6vbqXPU0dYX6CvWd6ifVb6u/otFo1jR/WiqtgLaCVkc7TbtPe6vB0HDS4GkINRZoVGs0alzReEGn0K3oHPpUehG9gn6Qfoneq0nRtNbkavI152tWax7RvKnZr8XQGq8VrZWvtVxrl9YFrWfaJG1r7SBtofYS7W3ap7UfMTCGBYPLEDAWM7YzzjK6dYg6Njo8nRydMp09Oh06fbrauq66SbqzdKt1j+l2MTGmNZPHzGOuZB5g3mC+1zPW4+iJ9JbpNehd0XujP0bfX1+kX6q/V/+6/nsDlkGQQa7BaoMmg3uGuKG9YazhTMPNhmcNe8fojPEeIxhTOubAmF+MUCN7ozijOUbbjNqN+o1NjEOMpcYbjE8b95owTfxNckzKTY6b9JgyTH1NxablpidMf2PpsjisPFYl6wyrz8zILNRMYbbVrMPsg7mNeaJ5sfle83sWVAu2RaZFuUWbRZ+lqWWk5VzLestfrChWbKtsq/VW56zeWNtYJ1svtW6yfmajb8OzKbKpt7lrS7P1s51hW2N7zY5ox7bLtdtkd9ketXezz7avtr/kgDq4O4gdNjl0jiWM9RwrGVsz9qajuiPHsdCx3vGBE9MpwqnYqcnpxTjLcanjVo87N+6zs5tznvN25zvjtceHjS8e3zL+Txd7F4FLtcu1CbQJwRMWTGie8NLVwVXkutn1lhvDLdJtqVub2yd3D3eZe4N7j4elR7rHRo+bbB12DHs5+7wnwTPAc4Fnq+c7L3evAq8DXn94O3rneu/yfjbRZqJo4vaJj3zMffg+W326fFm+6b7f+3b5mfnx/Wr8Hvpb+Av9d/g/5dhxcji7OS8CnANkAYcD3nC9uPO4JwOxwJDA0sCOIO2gxKCqoPvB5sFZwfXBfSFuIXNCToYSQsNDV4fe5BnzBLw6Xl+YR9i8sDPh6uHx4VXhDyPsI2QRLZFoZFjk2si7UVZRkqimaBDNi14bfS/GJmZGzNFYYmxMbHXsk7jxcXPjzsUz4qfF74p/nRCQsDLhTqJtoiKxLYmelJZUl/QmOTB5TXLXpHGT5k26mGKYIk5pTiWlJqXuSO2fHDR53eTuNLe0krQbU2ymzJpyYarh1Lypx6bRp/GnHUwnpCen70r/yI/m1/D7M3gZGzP6BFzBesFzob+wXNgj8hGtET3N9Mlck/ksyydrbVZPtl92RXavmCuuEr/MCc3ZkvMmNzp3Z+5AXnLe3nxyfnr+EYm2JFdyZrrJ9FnTO6UO0hJp1wyvGetm9MnCZTvkiHyKvLlAB37otytsFd8oHhT6FlYXvp2ZNPPgLK1Zklnts+1nL5v9tCi46Ic5+BzBnLa5ZnMXzX0wjzNv63xkfsb8tgUWC5Ys6F4YsrB2EXVR7qKfi52L1xT/tTh5ccsS4yULlzz6JuSb+hKNElnJzaXeS7d8i38r/rZj2YRlG5Z9LhWW/lTmXFZR9nG5YPlP343/rvK7gRWZKzpWuq/cvIq4SrLqxmq/1bVrtNYUrXm0NnJtYzmrvLT8r3XT1l2ocK3Ysp66XrG+qzKisnmD5YZVGz5WZVddrw6o3rvRaOOyjW82CTdd2ey/uWGL8ZayLe+/F39/a2vI1sYa65qKbcRthduebE/afu4H9g91Owx3lO34tFOys6s2rvZMnUdd3S6jXSvr0XpFfc/utN2X9wTuaW5wbNi6l7m3bB/Yp9j32/70/TcOhB9oO8g+2HDI6tDGw4zDpY1I4+zGvqbspq7mlObOI2FH2lq8Ww4fdTq6s9WstfqY7rGVx6nHlxwfOFF0ov+k9GTvqaxTj9qmtd05Pen0tTOxZzrOhp89/2Pwj6fPcc6dOO9zvvWC14UjP7F/arrofrGx3a398M9uPx/ucO9ovORxqfmy5+WWzomdx6/4XTl1NfDqj9d41y5ej7reeSPxxq2baTe7bglvPbudd/vlL4W/fLiz8C7hbuk9zXsV943u1/xq9+veLveuYw8CH7Q/jH9455Hg0fPH8scfu5c8oT2peGr6tO6Zy7PWnuCey79N/q37ufT5h96S37V+3/jC9sWhP/z/aO+b1Nf9UvZy4M/lrwxe7fzL9a+2/pj++6/zX394U/rW4G3tO/a7c++T3z/9MPMj6WPlJ7tPLZ/DP98dyB8YkPJl/MFPAQwojzaZAPy5EwBaCgAMeG6kTladDwcLojrTDiLwn7DqDDlY3AFogN/0sb3w6+YmAPu2A2AN9elpAMTQAEjwBOiECSN1+Cw3eO5UFiI8G3yf/CkjPwP8m6I6k37l9+geKFVdwej+X1Z+gxetqozPAAAAimVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAA5KGAAcAAAASAAAAeKACAAQAAAABAAAAKqADAAQAAAABAAAAJgAAAABBU0NJSQAAAFNjcmVlbnNob3QjvaYSAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB1GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4zODwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj40MjwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PlNjcmVlbnNob3Q8L2V4aWY6VXNlckNvbW1lbnQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgrqO0/nAAAAHGlET1QAAAACAAAAAAAAABMAAAAoAAAAEwAAABMAAAI80JL4DwAAAghJREFUWAnMVtthwzAIrDJPmkmSjlxvVvcAncCSsJx+1R/BvA50ILfl8/W9f6RPgUfcUUKDugczdZU/7lcdsQWxu8iGVoC6Q3cL4bJWyuO1SYb3k0We2iPAquQEaEiHQZiQk1aiyjmjBPUEJtKjsneLkf3WejqBm2UJk2R0lJF5h0Gj2x5HFwso04a9+O07jfoideaO6XpgHG3OaIz0ExIzHowTahJBupMiAWPE5gwSkwOg3svy+Nokhoi9P9HjQViCMkmJ5jRdTgacyETNu8RorKHvXSHi8lKqztuPhLaTcKx2krX6Y//x1nedssOrS52mnzB6f8p3FGeWxaqFpgx1E2kTqlnMNunMcafoJ2NvSTRkO7pEmVHwRqkhPTB38TNTd3RAOnYxc/NwkIcJIFN3EpS33cSb7qbuqM0tpOscqR8Lu+a33m2Tt7NOJ+Er0wAHQ79LHUa5P/HBF6P+mJcMTWUNJQMmfScPt9qQFVTjQg2rtPqVBGSikYTRGnAYCltbgcOfpsPRmLMGBrRJGYHTP6FDcFeIzLIB6iq1r5xR1qXk5Jo+FI+G2si/ZDT2Gd51R2/4r6afSNMR3BEM3RnUHVLd4gK2vQp18ghI9nBEGoQE6j4y7ujYSoY5tQ/pMPCkF7+TEXeAg9N2dObhEoUDkpXI6OGWB2ZbuuSjEHVixMbG90OGAvwCAAD//wYd6lsAAAIBSURBVM2WQXbDIAxETc6T9CRtr5ycLO4I80FY0Nh5XZQuJkJiJA2y3fTxfV+XJS3LIhiits+uQKeN1dKY472Vrp/39XJpPONyk9pY1UZE0nIOu6I5bA1rLB1ZAzQCEbidXlJUtHh+g8IfL8AnVKaDCkJHSuyGkuj2dV9piMTYGXV6pGRTeBNrJ0AdpJzcnCzLXlcpJSYMk/gvFK11T36YUOlqiirAK5LUIYrh8f4J33wbxeZXRpophxR9tIuZVeM7yTHaYPhri7PDMXegUwinNyxCSUJT0eLTTU99Kk993rFN/aFoxH4m+wSxqLpjgSxTuJamn96cEPaKQvQKA7E2qsKvDh/wZxlVccE8ozd74dculDD170toCcE+hqUjP6NGpBusOSF6kaBXlOCgGMROuRMKQkdN2A1Ho+YmQoHJFD0zkySjJ+wxllJM0adOZGUV6RWFCBwT2ZfpYSH9aq22K8pEcqAk2J98y0IoNNxsrK2//GWyLRrKD+TZdH4GjQkbBUeNn8qh0rOiEHHYJ6ot0ApBc4Rujn4mnXKi3F8c6QczOjgIwby2nceXKJc36RfcnRybKLr3BmJt/OFM7itnRjOqgTAxSq8ZfVhvKHz0P7PSWunIjwpKgYiADbI/xKDUbka7hGI0+8CCllDshn4m+aA4XRXIhVV8ym+vMaG9zn4AEXliZeYetTcAAAAASUVORK5CYII=", # noqa: E501 + placeholder_fade_out_animation=ft.Animation( + duration=ft.Duration(milliseconds=900), + curve=ft.AnimationCurve.EASE_OUT, + ), + fade_in_animation=ft.Animation( + duration=ft.Duration(milliseconds=700), + curve=ft.AnimationCurve.EASE_IN_OUT, + ), + ), + ft.Button("Show random image", on_click=show_random), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/fade_in/pyproject.toml b/sdk/python/examples/controls/core/image/fade_in/pyproject.toml new file mode 100644 index 0000000000..6ce30c1956 --- /dev/null +++ b/sdk/python/examples/controls/core/image/fade_in/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-fade-in" +version = "1.0.0" +description = "Loads random network images with placeholder and fade-in animations." +requires-python = ">=3.10" +keywords = ["image", "fade in", "placeholder", "animation", "network"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Fade-in images with a placeholder" +controls = ["SafeArea", "Column", "Image", "Button", "Animation", "Duration"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["placeholder image", "fade-in animation", "dynamic image source"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/image/gallery/assets/app_icon_512.png b/sdk/python/examples/controls/core/image/gallery/assets/app_icon_512.png new file mode 100644 index 0000000000..f89a749ada Binary files /dev/null and b/sdk/python/examples/controls/core/image/gallery/assets/app_icon_512.png differ diff --git a/sdk/python/examples/controls/core/image/gallery/main.py b/sdk/python/examples/controls/core/image/gallery/main.py new file mode 100644 index 0000000000..4aacd340d1 --- /dev/null +++ b/sdk/python/examples/controls/core/image/gallery/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Image Example" + page.theme_mode = ft.ThemeMode.LIGHT + page.padding = 50 + + gallery = ft.Row(expand=True, wrap=False, scroll=ft.ScrollMode.ALWAYS) + + for i in range(0, 30): + gallery.controls.append( + ft.Image( + src=f"https://picsum.photos/200/200?{i}", + width=200, + height=200, + fit=ft.BoxFit.NONE, + repeat=ft.ImageRepeat.NO_REPEAT, + border_radius=ft.BorderRadius.all(10), + ) + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Image( + src="assets/app_icon_512.png", + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + ), + gallery, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/gallery/pyproject.toml b/sdk/python/examples/controls/core/image/gallery/pyproject.toml new file mode 100644 index 0000000000..b82b3765f2 --- /dev/null +++ b/sdk/python/examples/controls/core/image/gallery/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-gallery" +version = "1.0.0" +description = "Shows a local app icon and a horizontally scrollable gallery of remote images." +requires-python = ">=3.10" +keywords = ["image", "gallery", "scroll", "assets", "network images"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Image gallery" +controls = ["SafeArea", "Column", "Row", "Image"] +layout_pattern = "gallery" +complexity = "basic" +features = ["local asset image", "horizontal scrolling", "network image thumbnails"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/image/gapless_playback/main.py b/sdk/python/examples/controls/core/image/gapless_playback/main.py new file mode 100644 index 0000000000..a6edc789f2 --- /dev/null +++ b/sdk/python/examples/controls/core/image/gapless_playback/main.py @@ -0,0 +1,86 @@ +import random + +import flet as ft + + +def get_new_image_src() -> str: + random_id = random.randint(1, 85) + return f"https://picsum.photos/id/{random_id}/1280/720" + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + initial_src = get_new_image_src() + image_with_gapless = ft.Image( + src=initial_src, + width=340, + height=220, + fit=ft.BoxFit.COVER, + gapless_playback=True, + ) + image_without_gapless = ft.Image( + src=initial_src, + width=340, + height=220, + fit=ft.BoxFit.COVER, + gapless_playback=False, + ) + + def image_panel(title: str, image: ft.Image): + return ft.Column( + spacing=8, + width=340, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(title, weight=ft.FontWeight.BOLD), + ft.Container( + content=image, + bgcolor=ft.Colors.BLUE_GREY_900, + border_radius=ft.BorderRadius.all(12), + clip_behavior=ft.ClipBehavior.ANTI_ALIAS, + ), + ], + ) + + def next_photo(e: ft.Event[ft.Button]): + new_src = get_new_image_src() + image_with_gapless.src = new_src + image_without_gapless.src = new_src + image_with_gapless.update() + image_without_gapless.update() + + page.appbar = ft.AppBar(title="Gapless Playback Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Click 'Load next photo' to switch both images to a new URL.\n" + "The left/top image keeps showing the previous frame while " + "loading " + "the next one. This is referred to as gapless playback.", + text_align=ft.TextAlign.CENTER, + ), + ft.Row( + wrap=True, + spacing=20, + run_spacing=20, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + image_panel("gapless_playback=True", image_with_gapless), + image_panel( + "gapless_playback=False", + image_without_gapless, + ), + ], + ), + ft.FilledButton("Load next photo", on_click=next_photo), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/gapless_playback/pyproject.toml b/sdk/python/examples/controls/core/image/gapless_playback/pyproject.toml new file mode 100644 index 0000000000..c2b1ef33b8 --- /dev/null +++ b/sdk/python/examples/controls/core/image/gapless_playback/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-gapless-playback" +version = "1.0.0" +description = "Compares Image gapless playback enabled vs disabled while switching sources." +requires-python = ">=3.10" +keywords = ["image", "gapless playback", "comparison", "network images"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Gapless playback when changing image sources" +controls = ["SafeArea", "Column", "Row", "Container", "Text", "Image", "FilledButton", "AppBar"] +layout_pattern = "comparison" +complexity = "basic" +features = ["gapless playback comparison", "dynamic image source switching"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/image/lucide_icons/main.py b/sdk/python/examples/controls/core/image/lucide_icons/main.py new file mode 100644 index 0000000000..b21abe75e2 --- /dev/null +++ b/sdk/python/examples/controls/core/image/lucide_icons/main.py @@ -0,0 +1,29 @@ +import flet as ft + +""" +- Browse Lucide icons: https://lucide.dev/ +- Copy SVG and use it as value for `Image.src` +""" + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Image( + src='', # noqa: E501 + color=ft.Colors.PINK, + ), + ft.Image( + src='', # noqa: E501 + color=ft.Colors.GREEN, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/lucide_icons/pyproject.toml b/sdk/python/examples/controls/core/image/lucide_icons/pyproject.toml new file mode 100644 index 0000000000..70fce26f51 --- /dev/null +++ b/sdk/python/examples/controls/core/image/lucide_icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-lucide-icons" +version = "1.0.0" +description = "Shows Lucide SVG icons rendered through Image with custom colors." +requires-python = ">=3.10" +keywords = ["image", "lucide", "svg icons", "inline svg"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying a Lucide icon" +controls = ["SafeArea", "Row", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["inline svg icons", "icon color styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/image/media/gallery.gif b/sdk/python/examples/controls/core/image/media/gallery.gif new file mode 100644 index 0000000000..60aa24c0c9 Binary files /dev/null and b/sdk/python/examples/controls/core/image/media/gallery.gif differ diff --git a/sdk/python/examples/controls/core/image/src_base64_and_bytes/main.py b/sdk/python/examples/controls/core/image/src_base64_and_bytes/main.py new file mode 100644 index 0000000000..be4ab3b798 --- /dev/null +++ b/sdk/python/examples/controls/core/image/src_base64_and_bytes/main.py @@ -0,0 +1,33 @@ +import base64 + +import flet as ft + + +def main(page: ft.Page): + # image as base64 string + base64_src = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 + # image as bytes + bytes_src = base64.b64decode(base64_src) + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Image( + src=base64_src, + width=100, + height=100, + ), + ft.Image( + src=bytes_src, + width=100, + height=100, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/src_base64_and_bytes/pyproject.toml b/sdk/python/examples/controls/core/image/src_base64_and_bytes/pyproject.toml new file mode 100644 index 0000000000..accbac2bbd --- /dev/null +++ b/sdk/python/examples/controls/core/image/src_base64_and_bytes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-src-base64-and-bytes" +version = "1.0.0" +description = "Renders images from base64 string and decoded byte data sources." +requires-python = ">=3.10" +keywords = ["image", "base64", "bytes", "binary data"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying images from base64 strings and byte data" +controls = ["SafeArea", "Row", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["base64 image source", "bytes image source"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/image/static_svg/main.py b/sdk/python/examples/controls/core/image/static_svg/main.py new file mode 100644 index 0000000000..c8cca29797 --- /dev/null +++ b/sdk/python/examples/controls/core/image/static_svg/main.py @@ -0,0 +1,75 @@ +import flet as ft + + +def main(page: ft.Page): + svg_image = """ + + + + + + +""" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Image( + src="https://raw.githubusercontent.com/dnfield/flutter_svg/master/packages/flutter_svg/example/assets/wikimedia/Firefox_Logo_2017.svg", + width=200, + height=200, + ), + ft.Image( + src=svg_image, + width=100, + height=100, + color=ft.Colors.RED, + ), + ft.Image( + src=svg_image, + width=100, + height=100, + color=ft.Colors.BLUE, + ), + ft.Container( + bgcolor=ft.Colors.BLACK_87, + border_radius=5, + content=ft.Image( + src=svg_image, + width=100, + height=100, + color=ft.Colors.WHITE, + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/image/static_svg/pyproject.toml b/sdk/python/examples/controls/core/image/static_svg/pyproject.toml new file mode 100644 index 0000000000..ca8cd772f6 --- /dev/null +++ b/sdk/python/examples/controls/core/image/static_svg/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "image-static-svg" +version = "1.0.0" +description = "Displays static SVG images from network and inline SVG strings with color overrides." +requires-python = ">=3.10" +keywords = ["image", "svg", "static svg", "inline svg", "color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Image"] + +[tool.flet.metadata] +title = "Displaying a static SVG image" +controls = ["SafeArea", "Column", "Image", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["network svg", "inline svg", "svg color tinting"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/interactive_viewer/handling_events/main.py b/sdk/python/examples/controls/core/interactive_viewer/handling_events/main.py new file mode 100644 index 0000000000..7acd572406 --- /dev/null +++ b/sdk/python/examples/controls/core/interactive_viewer/handling_events/main.py @@ -0,0 +1,21 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.InteractiveViewer( + min_scale=0.1, + max_scale=15, + 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.Image(src="https://picsum.photos/500/500"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/interactive_viewer/handling_events/pyproject.toml b/sdk/python/examples/controls/core/interactive_viewer/handling_events/pyproject.toml new file mode 100644 index 0000000000..6ea1bbbeb7 --- /dev/null +++ b/sdk/python/examples/controls/core/interactive_viewer/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "interactive-viewer-handling-events" +version = "1.0.0" +description = "Logs start, update, and end callbacks while panning and zooming an InteractiveViewer image." +requires-python = ">=3.10" +keywords = ["interactive viewer", "events", "zoom", "pan", "image"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/InteractiveViewer"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "InteractiveViewer", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["interaction event callbacks", "pinch zoom", "panning"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/interactive_viewer/transformations/main.py b/sdk/python/examples/controls/core/interactive_viewer/transformations/main.py new file mode 100644 index 0000000000..70366436d0 --- /dev/null +++ b/sdk/python/examples/controls/core/interactive_viewer/transformations/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + async def handle_zoom_in(e: ft.Event[ft.Button]): + await i.zoom(1.2) + + async def handle_zoom_out(e: ft.Event[ft.Button]): + await i.zoom(0.8) + + async def handle_pan(e: ft.Event[ft.Button]): + await i.pan(dx=50, dy=50) + + async def handle_reset(e: ft.Event[ft.Button]): + await i.reset() + + async def handle_reset_slow(e: ft.Event[ft.Button]): + await i.reset(animation_duration=ft.Duration(seconds=2)) + + async def handle_save_state(e: ft.Event[ft.Button]): + await i.save_state() + + async def handle_restore_state(e: ft.Event[ft.Button]): + await i.restore_state() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + i := ft.InteractiveViewer( + min_scale=0.1, + max_scale=5, + boundary_margin=ft.Margin.all(20), + content=ft.Image(src="https://picsum.photos/500/500"), + ), + ft.Row( + wrap=True, + controls=[ + ft.Button("Zoom In", on_click=handle_zoom_in), + ft.Button("Zoom Out", on_click=handle_zoom_out), + ft.Button("Pan", on_click=handle_pan), + ft.Button("Save State", on_click=handle_save_state), + ft.Button("Restore State", on_click=handle_restore_state), + ft.Button("Reset (instant)", on_click=handle_reset), + ft.Button("Reset (slow)", on_click=handle_reset_slow), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/interactive_viewer/transformations/pyproject.toml b/sdk/python/examples/controls/core/interactive_viewer/transformations/pyproject.toml new file mode 100644 index 0000000000..6c02a8375f --- /dev/null +++ b/sdk/python/examples/controls/core/interactive_viewer/transformations/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "interactive-viewer-transformations" +version = "1.0.0" +description = "Applies InteractiveViewer programmatic zoom, pan, save/restore state, and reset actions." +requires-python = ">=3.10" +keywords = ["interactive viewer", "transformations", "zoom", "pan", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/InteractiveViewer"] + +[tool.flet.metadata] +title = "Programmatic transformations" +controls = ["SafeArea", "Column", "Row", "InteractiveViewer", "Image", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic zoom", "programmatic pan", "save and restore state", "animated reset"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/keyboard_listener/detect_keys/main.py b/sdk/python/examples/controls/core/keyboard_listener/detect_keys/main.py new file mode 100644 index 0000000000..c251f16bbc --- /dev/null +++ b/sdk/python/examples/controls/core/keyboard_listener/detect_keys/main.py @@ -0,0 +1,35 @@ +import flet as ft + + +async def main(page: ft.Page): + pressed_keys = set() + + def key_down(e: ft.KeyDownEvent): + pressed_keys.add(e.key) + keys.controls = [ft.Text(k, size=20) for k in pressed_keys] + keys.update() + + def key_up(e: ft.KeyUpEvent): + pressed_keys.remove(e.key) + keys.controls = [ft.Text(k, size=20) for k in pressed_keys] + keys.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Press any keys..."), + ft.KeyboardListener( + autofocus=True, + on_key_down=key_down, + on_key_up=key_up, + content=(keys := ft.Row()), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/keyboard_listener/detect_keys/pyproject.toml b/sdk/python/examples/controls/core/keyboard_listener/detect_keys/pyproject.toml new file mode 100644 index 0000000000..71f487e5c1 --- /dev/null +++ b/sdk/python/examples/controls/core/keyboard_listener/detect_keys/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "keyboard-listener-detect-keys" +version = "1.0.0" +description = "Tracks pressed keys with KeyboardListener and shows active keys in real time." +requires-python = ">=3.10" +keywords = ["keyboard listener", "keyboard", "key down", "key up", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Keyboard"] + +[tool.flet.metadata] +title = "Press any keys" +controls = ["SafeArea", "Column", "KeyboardListener", "Row", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["key down and key up handling", "active key list", "keyboard focus"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_align/main.py b/sdk/python/examples/controls/core/layout_control/animate_align/main.py new file mode 100644 index 0000000000..6a79ab3c94 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_align/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_click(e: ft.Event[ft.Button]): + txt.align = ft.Alignment.TOP_LEFT + txt.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + width=200, + height=200, + controls=[ + txt := ft.Text( + "Hello, Flet!", + align=ft.Alignment.BOTTOM_RIGHT, + animate_align=1000, + ) + ], + ), + ft.Button("Animate align", on_click=animate_click), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_align/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_align/pyproject.toml new file mode 100644 index 0000000000..5a719c7158 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_align/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-align" +version = "1.0.0" +description = "Animates Text alignment within a Stack using animate_align." +requires-python = ">=3.10" +keywords = ["layout control", "animate align", "text", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate align" +controls = ["SafeArea", "Column", "Stack", "Text", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["alignment animation", "button-triggered transition"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_margin/main.py b/sdk/python/examples/controls/core/layout_control/animate_margin/main.py new file mode 100644 index 0000000000..db328a0c9b --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_margin/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_click(e: ft.Event[ft.Button]): + c.margin = 0 + txt.margin = ft.Margin.only(left=50, top=70) + c.update() + txt.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + c := ft.Container( + width=200, + height=200, + bgcolor=ft.Colors.AMBER, + margin=40, + animate=True, + content=( + txt := ft.Text( + "Hello, Flet!", + margin=20, + animate_margin=1000, + ) + ), + ), + ft.Button("Animate margin", on_click=animate_click), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_margin/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_margin/pyproject.toml new file mode 100644 index 0000000000..18b08944a6 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_margin/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-margin" +version = "1.0.0" +description = "Animates container and text margins to show layout spacing transitions." +requires-python = ">=3.10" +keywords = ["layout control", "animate margin", "container", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate margin" +controls = ["SafeArea", "Column", "Container", "Text", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["margin animation", "container animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_offset/main.py b/sdk/python/examples/controls/core/layout_control/animate_offset/main.py new file mode 100644 index 0000000000..e66a89701b --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_offset/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + container.offset = ft.Offset(0, 0) + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=150, + height=150, + bgcolor=ft.Colors.BLUE, + border_radius=ft.BorderRadius.all(10), + offset=ft.Offset(x=-1.1, y=0), + animate_offset=ft.Animation( + duration=600, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ft.Button("Reveal!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_offset/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_offset/pyproject.toml new file mode 100644 index 0000000000..6937d6d1aa --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_offset/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-offset" +version = "1.0.0" +description = "Reveals a container by animating its offset from off-screen to visible." +requires-python = ">=3.10" +keywords = ["layout control", "animate offset", "container", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate offset" +controls = ["SafeArea", "Column", "Container", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["offset animation", "slide-in reveal"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_opacity/main.py b/sdk/python/examples/controls/core/layout_control/animate_opacity/main.py new file mode 100644 index 0000000000..b5e28999f8 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_opacity/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_opacity(e: ft.Event[ft.Button]): + container.opacity = 0 if container.opacity == 1 else 1 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + container := ft.Container( + width=150, + height=150, + bgcolor=ft.Colors.BLUE, + border_radius=10, + animate_opacity=300, + ), + ft.Button( + content="Animate opacity", + on_click=animate_opacity, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_opacity/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_opacity/pyproject.toml new file mode 100644 index 0000000000..e573462b70 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_opacity/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-opacity" +version = "1.0.0" +description = "Toggles a container between visible and transparent states with animate_opacity." +requires-python = ">=3.10" +keywords = ["layout control", "animate opacity", "container", "fade"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate opacity" +controls = ["SafeArea", "Column", "Container", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["opacity animation", "fade toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_position/main.py b/sdk/python/examples/controls/core/layout_control/animate_position/main.py new file mode 100644 index 0000000000..56474d8504 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_position/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + def animate_container(e: ft.Event[ft.Button]): + c1.top = 20 + c1.left = 200 + c2.top = 100 + c2.left = 40 + c3.top = 180 + c3.left = 100 + stack.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + stack := ft.Stack( + height=400, + controls=[ + c1 := ft.Container( + width=50, + height=50, + bgcolor="red", + animate_position=1000, + ), + c2 := ft.Container( + width=50, + height=50, + bgcolor="green", + top=60, + left=0, + animate_position=500, + ), + c3 := ft.Container( + width=50, + height=50, + bgcolor="blue", + top=120, + left=0, + animate_position=1000, + ), + ], + ), + ft.Button("Animate!", on_click=animate_container), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_position/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_position/pyproject.toml new file mode 100644 index 0000000000..b393a63ec4 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_position/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-position" +version = "1.0.0" +description = "Animates top/left positions of multiple containers inside a Stack." +requires-python = ">=3.10" +keywords = ["layout control", "animate position", "stack", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate position" +controls = ["SafeArea", "Column", "Stack", "Container", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["position animation", "multi-control movement"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_rotation/main.py b/sdk/python/examples/controls/core/layout_control/animate_rotation/main.py new file mode 100644 index 0000000000..ac3adda8ce --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_rotation/main.py @@ -0,0 +1,39 @@ +from math import pi + +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 30 + + def animate(e: ft.Event[ft.Button]): + container.rotate.angle += pi / 2 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + container := ft.Container( + width=100, + height=70, + bgcolor=ft.Colors.BLUE, + border_radius=5, + rotate=ft.Rotate(angle=0, alignment=ft.Alignment.CENTER), + animate_rotation=ft.Animation( + duration=300, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ft.Button("Animate!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_rotation/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_rotation/pyproject.toml new file mode 100644 index 0000000000..62256eecaa --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_rotation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-rotation" +version = "1.0.0" +description = "Rotates a container in quarter turns with animate_rotation and bounce curve." +requires-python = ">=3.10" +keywords = ["layout control", "animate rotation", "container", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate rotation" +controls = ["SafeArea", "Column", "Container", "Button", "Rotate", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["rotation animation", "incremental angle updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/animate_scale/main.py b/sdk/python/examples/controls/core/layout_control/animate_scale/main.py new file mode 100644 index 0000000000..abd4cfa7cd --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_scale/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 30 + + def animate(e: ft.Event[ft.Button]): + container.scale = 2 if container.scale == 1 else 1 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + container := ft.Container( + width=100, + height=100, + bgcolor=ft.Colors.BLUE, + border_radius=5, + scale=1, + animate_scale=ft.Animation( + duration=600, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ft.Button("Animate!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/animate_scale/pyproject.toml b/sdk/python/examples/controls/core/layout_control/animate_scale/pyproject.toml new file mode 100644 index 0000000000..a95f5e19aa --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/animate_scale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-animate-scale" +version = "1.0.0" +description = "Animates container scale between normal and enlarged sizes." +requires-python = ">=3.10" +keywords = ["layout control", "animate scale", "container", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Animate scale" +controls = ["SafeArea", "Column", "Container", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["scale animation", "toggle scaling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/assets/icon-192.png b/sdk/python/examples/controls/core/layout_control/assets/icon-192.png new file mode 100644 index 0000000000..65da3b9571 Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/assets/icon-192.png differ diff --git a/sdk/python/examples/controls/core/layout_control/bursting_flet/assets/icon-192.png b/sdk/python/examples/controls/core/layout_control/bursting_flet/assets/icon-192.png new file mode 100644 index 0000000000..65da3b9571 Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/bursting_flet/assets/icon-192.png differ diff --git a/sdk/python/examples/controls/core/layout_control/bursting_flet/main.py b/sdk/python/examples/controls/core/layout_control/bursting_flet/main.py new file mode 100644 index 0000000000..9106c60f9e --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/bursting_flet/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def animate(e: ft.Event[ft.Button]): + image.scale = 30 + image.opacity = 0 + image.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + image := ft.Image( + src="icon-192.png", + width=100, + height=100, + scale=1.0, + animate_scale=ft.Animation( + 300, + ft.AnimationCurve.EASE_IN_QUINT, + ), + opacity=1.0, + animate_opacity=ft.Animation( + 300, + ft.AnimationCurve.EASE_IN_QUINT, + ), + ), + ft.Button("Boom!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/bursting_flet/pyproject.toml b/sdk/python/examples/controls/core/layout_control/bursting_flet/pyproject.toml new file mode 100644 index 0000000000..49921d2d3c --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/bursting_flet/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-bursting-flet" +version = "1.0.0" +description = "Creates a burst effect by rapidly scaling and fading the Flet icon image." +requires-python = ">=3.10" +keywords = ["layout control", "image", "scale", "opacity", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Bursting flet" +controls = ["SafeArea", "Column", "Image", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["combined scale and opacity animations", "asset image animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/flip/main.py b/sdk/python/examples/controls/core/layout_control/flip/main.py new file mode 100644 index 0000000000..3abd87179e --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/flip/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 20 + + def toggle_x(e: ft.Event[ft.Button]): + card.flip.flip_x = not card.flip.flip_x + card.update() + + def toggle_y(e: ft.Event[ft.Button]): + card.flip.flip_y = not card.flip.flip_y + card.update() + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=20, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + card := ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Flip me", size=24, weight=ft.FontWeight.BOLD), + flip=ft.Flip( + flip_x=False, + flip_y=False, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button("Toggle X", on_click=toggle_x), + ft.Button("Toggle Y", on_click=toggle_y), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/flip/pyproject.toml b/sdk/python/examples/controls/core/layout_control/flip/pyproject.toml new file mode 100644 index 0000000000..683de547da --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/flip/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-flip" +version = "1.0.0" +description = "Toggles flip_x and flip_y on a card using LayoutControl flip transform." +requires-python = ">=3.10" +keywords = ["layout control", "flip", "transform", "card"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Flip" +controls = ["SafeArea", "Column", "Container", "Text", "Flip", "Row", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["flip_x toggle", "flip_y toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/image_slideshow/main.py b/sdk/python/examples/controls/core/layout_control/image_slideshow/main.py new file mode 100644 index 0000000000..c6f1d01d35 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/image_slideshow/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + image1.left = 400 if image1.left == 0 else 0 + image2.left = 0 if image2.left == -400 else -400 + stack.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + stack := ft.Stack( + width=200, + height=300, + controls=[ + image1 := ft.Image( + src="https://picsum.photos/200/300?1", + left=0, + animate_position=ft.Animation( + duration=300, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + image2 := ft.Image( + src="https://picsum.photos/200/300?2", + left=-400, + animate_position=ft.Animation( + duration=300, + curve=ft.AnimationCurve.BOUNCE_OUT, + ), + ), + ], + ), + ft.Button("Slide!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/image_slideshow/pyproject.toml b/sdk/python/examples/controls/core/layout_control/image_slideshow/pyproject.toml new file mode 100644 index 0000000000..459e6a669f --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/image_slideshow/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-image-slideshow" +version = "1.0.0" +description = "Slides two images horizontally using animated left position changes." +requires-python = ">=3.10" +keywords = ["layout control", "image slideshow", "animate position", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Image slideshow" +controls = ["SafeArea", "Column", "Stack", "Image", "Button", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["sliding images", "position animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/matrix4_transform/main.py b/sdk/python/examples/controls/core/layout_control/matrix4_transform/main.py new file mode 100644 index 0000000000..1b72aad9ef --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/matrix4_transform/main.py @@ -0,0 +1,93 @@ +from math import pi + +import flet as ft + + +def card(title: str, color: str, matrix: ft.Matrix4) -> ft.Container: + return ft.Container( + width=220, + height=130, + border_radius=18, + bgcolor=color, + padding=12, + content=ft.Text(title, size=18, weight=ft.FontWeight.BOLD), + transform=ft.Transform( + matrix=matrix, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.AUTO + page.spacing = 20 + + perspective_tilt = ( + ft.Matrix4.identity() + .set_entry(3, 2, 0.0018) + .rotate_x(-0.35) + .rotate_y(0.45) + .translate(0, -10, 0) + ) + + skew_and_rotate = ft.Matrix4.skew_y(0.28).rotate_z(-pi / 14) + + mirrored_spin = ft.Matrix4.diagonal3_values(-1, 1, 1).rotate_z(pi / 10) + + mix = ft.Matrix4.translation_values(24, -8, 0).multiply( + ft.Matrix4.rotation_z(pi / 16).scale(0.9, 0.9) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=20, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Matrix4 transform recording + replay", size=24), + ft.ResponsiveRow( + controls=[ + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Perspective tilt", + ft.Colors.CYAN_300, + perspective_tilt, + ), + ), + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Skew + rotate", + ft.Colors.AMBER_300, + skew_and_rotate, + ), + ), + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Mirror + spin", + ft.Colors.PINK_200, + mirrored_spin, + ), + ), + ft.Container( + col={"sm": 6, "md": 3}, + content=card( + "Multiply chain", + ft.Colors.LIGHT_GREEN_300, + mix, + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/matrix4_transform/pyproject.toml b/sdk/python/examples/controls/core/layout_control/matrix4_transform/pyproject.toml new file mode 100644 index 0000000000..2021b0a6e5 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/matrix4_transform/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-matrix4-transform" +version = "1.0.0" +description = "Demonstrates Matrix4 perspective, skew, mirror, and chained transforms on cards." +requires-python = ">=3.10" +keywords = ["layout control", "matrix4", "transform", "perspective", "skew"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Matrix4 Transform" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Text", "Transform", "Matrix4"] +layout_pattern = "comparison" +complexity = "basic" +features = ["perspective transform", "skew and rotation", "matrix multiply chain"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/media/animate_offset.gif b/sdk/python/examples/controls/core/layout_control/media/animate_offset.gif new file mode 100644 index 0000000000..f3e4262ff0 Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/media/animate_offset.gif differ diff --git a/sdk/python/examples/controls/core/layout_control/media/animate_opacity.gif b/sdk/python/examples/controls/core/layout_control/media/animate_opacity.gif new file mode 100644 index 0000000000..8bc32fa324 Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/media/animate_opacity.gif differ diff --git a/sdk/python/examples/controls/core/layout_control/media/animate_position.gif b/sdk/python/examples/controls/core/layout_control/media/animate_position.gif new file mode 100644 index 0000000000..7ebe705ebc Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/media/animate_position.gif differ diff --git a/sdk/python/examples/controls/core/layout_control/media/animate_rotation.gif b/sdk/python/examples/controls/core/layout_control/media/animate_rotation.gif new file mode 100644 index 0000000000..1290682bb1 Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/media/animate_rotation.gif differ diff --git a/sdk/python/examples/controls/core/layout_control/media/animate_scale.gif b/sdk/python/examples/controls/core/layout_control/media/animate_scale.gif new file mode 100644 index 0000000000..58dce9b043 Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/media/animate_scale.gif differ diff --git a/sdk/python/examples/controls/core/layout_control/media/animated_switcher.gif b/sdk/python/examples/controls/core/layout_control/media/animated_switcher.gif new file mode 100644 index 0000000000..f9429bebdb Binary files /dev/null and b/sdk/python/examples/controls/core/layout_control/media/animated_switcher.gif differ diff --git a/sdk/python/examples/controls/core/layout_control/offset/main.py b/sdk/python/examples/controls/core/layout_control/offset/main.py new file mode 100644 index 0000000000..cfd44c59a9 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/offset/main.py @@ -0,0 +1,71 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.add( + ft.SafeArea( + content=ft.Stack( + width=460, + height=260, + controls=[ + ft.Text( + "Offset translates by control size.", + left=12, + top=8, + size=16, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Container( + left=30, + top=70, + width=170, + height=90, + border_radius=16, + bgcolor=ft.Colors.BLUE_100, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_400), + alignment=ft.Alignment.CENTER, + content=ft.Text( + "Original", + size=20, + color=ft.Colors.BLUE_GREY_700, + ), + ), + ft.Container( + left=30, + top=70, + width=170, + height=90, + border_radius=16, + bgcolor=ft.Colors.AMBER_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("Offset", size=26, weight=ft.FontWeight.BOLD), + offset=ft.Offset( + x=1.05, + y=0.55, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ft.Icon( + ft.Icons.ARROW_RIGHT_ALT_ROUNDED, + left=212, + top=82, + size=44, + color=ft.Colors.BLUE_GREY_600, + ), + ft.Text( + "offset = Offset(1.05, 0.55)", + left=194, + top=222, + size=14, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/offset/pyproject.toml b/sdk/python/examples/controls/core/layout_control/offset/pyproject.toml new file mode 100644 index 0000000000..e1d069ba1d --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/offset/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-offset" +version = "1.0.0" +description = "Visualizes Offset translation relative to control size with labeled overlays." +requires-python = ">=3.10" +keywords = ["layout control", "offset", "transform", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Offset" +controls = ["SafeArea", "Stack", "Container", "Text", "Icon", "Offset"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["offset translation", "visual offset comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/rocket/main.py b/sdk/python/examples/controls/core/layout_control/rocket/main.py new file mode 100644 index 0000000000..edc1573306 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/rocket/main.py @@ -0,0 +1,48 @@ +from math import pi + +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def animate(e: ft.Event[ft.Button]): + container.rotate.angle -= 0.5 * pi + container.content.scale = 2.0 if container.content.scale == 1.0 else 1.0 + container.content.opacity = 0.4 if container.content.scale == 1.0 else 1.0 + container.update() + + page.add( + ft.SafeArea( + content=ft.Column( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + height=300, + controls=[ + container := ft.Container( + width=120, + height=70, + alignment=ft.Alignment.CENTER_RIGHT, + rotate=ft.Rotate(0, alignment=ft.Alignment.CENTER_LEFT), + animate_rotation=ft.Animation(duration=1000), + content=ft.Container( + scale=1.0, + animate_scale=1000, + opacity=1.0, + animate_opacity=True, + content=ft.Icon( + ft.Icons.ROCKET, + size=40, + color=ft.Colors.BLACK, + ), + ), + ), + ft.Button("Launch!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/rocket/pyproject.toml b/sdk/python/examples/controls/core/layout_control/rocket/pyproject.toml new file mode 100644 index 0000000000..af5a85a9b6 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/rocket/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-rocket" +version = "1.0.0" +description = "Launch animation combining rotation, scale, and opacity on a rocket icon." +requires-python = ">=3.10" +keywords = ["layout control", "rocket", "rotation", "scale", "opacity"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Rocket" +controls = ["SafeArea", "Column", "Container", "Icon", "Button", "Rotate", "Animation"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["combined transform animation", "icon launch effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/rotate/main.py b/sdk/python/examples/controls/core/layout_control/rotate/main.py new file mode 100644 index 0000000000..5b84f976e9 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/rotate/main.py @@ -0,0 +1,29 @@ +from math import pi + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.add( + ft.SafeArea( + content=ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Rotate", size=28, weight=ft.FontWeight.BOLD), + rotate=ft.Rotate( + angle=pi / 10, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/rotate/pyproject.toml b/sdk/python/examples/controls/core/layout_control/rotate/pyproject.toml new file mode 100644 index 0000000000..b670cf878a --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/rotate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-rotate" +version = "1.0.0" +description = "Applies a fixed rotation transform to a container using Rotate." +requires-python = ">=3.10" +keywords = ["layout control", "rotate", "transform", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Rotate" +controls = ["SafeArea", "Container", "Text", "Rotate"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["static rotation transform"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/scale/main.py b/sdk/python/examples/controls/core/layout_control/scale/main.py new file mode 100644 index 0000000000..469eaa2112 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/scale/main.py @@ -0,0 +1,28 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.add( + ft.SafeArea( + content=ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.GREEN_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Scale", size=28, weight=ft.FontWeight.BOLD), + scale=ft.Scale( + scale_x=1.18, + scale_y=0.82, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/scale/pyproject.toml b/sdk/python/examples/controls/core/layout_control/scale/pyproject.toml new file mode 100644 index 0000000000..94014411a5 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/scale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-scale" +version = "1.0.0" +description = "Applies non-uniform scaling to a container using Scale transform." +requires-python = ">=3.10" +keywords = ["layout control", "scale", "transform", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Scale" +controls = ["SafeArea", "Container", "Text", "Scale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["static scale transform", "non-uniform scaling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/layout_control/switcher/main.py b/sdk/python/examples/controls/core/layout_control/switcher/main.py new file mode 100644 index 0000000000..3e5530824c --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/switcher/main.py @@ -0,0 +1,52 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + shader.rotate = 1 + shader.scale = 3 + shader.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + width=500, + height=300, + controls=[ + shader := ft.ShaderMask( + blend_mode=ft.BlendMode.COLOR_BURN, + border_radius=5, + animate_rotation=300, + animate_scale=ft.Animation( + 600, + ft.AnimationCurve.BOUNCE_OUT, + ), + shader=ft.RadialGradient( + center=ft.Alignment.TOP_LEFT, + radius=1.0, + colors=[ + ft.Colors.YELLOW, + ft.Colors.DEEP_ORANGE_900, + ], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="https://picsum.photos/140/100?1", + width=140, + height=100, + fit=ft.BoxFit.FILL, + ), + ) + ], + ), + ft.Button("Animate!", on_click=animate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/layout_control/switcher/pyproject.toml b/sdk/python/examples/controls/core/layout_control/switcher/pyproject.toml new file mode 100644 index 0000000000..a22e038460 --- /dev/null +++ b/sdk/python/examples/controls/core/layout_control/switcher/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "layout-control-switcher" +version = "1.0.0" +description = "Animates ShaderMask rotation and scale over an image with gradient shader." +requires-python = ">=3.10" +keywords = ["layout control", "shader mask", "rotation", "scale", "image"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/LayoutControl"] + +[tool.flet.metadata] +title = "Switcher" +controls = ["SafeArea", "Column", "Stack", "ShaderMask", "Image", "Button", "RadialGradient"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["shader mask animation", "rotation and scale animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/list_view/autoscroll_and_dynamic_items/main.py b/sdk/python/examples/controls/core/list_view/autoscroll_and_dynamic_items/main.py new file mode 100644 index 0000000000..e1a40ec6ae --- /dev/null +++ b/sdk/python/examples/controls/core/list_view/autoscroll_and_dynamic_items/main.py @@ -0,0 +1,52 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + def handle_switch_change(e: ft.Event[ft.Switch]): + lv.auto_scroll = not lv.auto_scroll + lv.update() + + lv = ft.ListView( + spacing=10, + padding=20, + width=150, + auto_scroll=True, + controls=[ + ft.Text(f"Line {i}", color=ft.Colors.ON_SECONDARY) for i in range(0, 60) + ], + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Row( + expand=True, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Container( + bgcolor=ft.Colors.GREY_500, + content=lv, + ), + ft.Switch( + thumb_icon=ft.Icons.LIST_OUTLINED, + value=True, + label="Auto-scroll", + label_position=ft.LabelPosition.RIGHT, + on_change=handle_switch_change, + ), + ], + ), + ) + ) + + # Add a new item to the ListView every second. + for i in range(len(lv.controls), 120): + await asyncio.sleep(1) + lv.controls.append(ft.Text(f"Line {i}", color=ft.Colors.ON_SECONDARY)) + lv.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/list_view/autoscroll_and_dynamic_items/pyproject.toml b/sdk/python/examples/controls/core/list_view/autoscroll_and_dynamic_items/pyproject.toml new file mode 100644 index 0000000000..9e8059c952 --- /dev/null +++ b/sdk/python/examples/controls/core/list_view/autoscroll_and_dynamic_items/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "list-view-autoscroll-and-dynamic-items" +version = "1.0.0" +description = "Adds new ListView items over time and toggles auto-scroll behavior with a switch." +requires-python = ">=3.10" +keywords = ["list view", "auto scroll", "dynamic items", "async", "switch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ListView"] + +[tool.flet.metadata] +title = "Auto-scrolling and dynamical items addition" +controls = ["SafeArea", "Row", "Container", "ListView", "Text", "Switch"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["auto-scroll toggle", "dynamic list item appending", "async updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/list_view/media/autoscroll_and_dynamic_items.gif b/sdk/python/examples/controls/core/list_view/media/autoscroll_and_dynamic_items.gif new file mode 100644 index 0000000000..6887014ec9 Binary files /dev/null and b/sdk/python/examples/controls/core/list_view/media/autoscroll_and_dynamic_items.gif differ diff --git a/sdk/python/examples/controls/core/markdown/basic/main.py b/sdk/python/examples/controls/core/markdown/basic/main.py new file mode 100644 index 0000000000..075fc15c35 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/basic/main.py @@ -0,0 +1,98 @@ +import flet as ft + +sample = """ +# Markdown Example +Markdown allows you to easily include formatted text, images, and even formatted Dart +code in your app. + +## Titles + +Setext-style + +This is an H1 +============= + +This is an H2 +------------- + +Atx-style + +# This is an H1 + +## This is an H2 + +###### This is an H6 + +Select the valid headers: + +- [x] `# hello` +- [ ] `#hello` + +## Links + +[inline-style](https://www.google.com) + +## Images + +![Image from Flet assets](/icons/icon-192.png) + +![Test image](https://picsum.photos/200/300) + +## Tables + +|Syntax |Result | +|---------------------------------------|-------------------------------------| +|`*italic 1*` |*italic 1* | +|`_italic 2_` | _italic 2_ | +|`**bold 1**` |**bold 1** | +|`__bold 2__` |__bold 2__ | +|`This is a ~~strikethrough~~` |This is a ~~strikethrough~~ | +|`***italic bold 1***` |***italic bold 1*** | +|`___italic bold 2___` |___italic bold 2___ | +|`***~~italic bold strikethrough 1~~***`|***~~italic bold strikethrough 1~~***| +|`~~***italic bold strikethrough 2***~~`|~~***italic bold strikethrough 2***~~| + +## Styling + +Style text as _italic_, __bold__, ~~strikethrough~~, or `inline code`. + +- Use bulleted lists +- To better clarify +- Your points + +## Code blocks + +Formatted Dart code looks really pretty too: + +~~~dart +void main() { + runApp(MaterialApp( + home: Scaffold( + body: ft.Markdown(data: markdownData), + ), + )); +} +~~~ +""" + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + + async def handle_link_tap(e: ft.Event[ft.Markdown]): + await page.launch_url(e.data) + + page.add( + ft.SafeArea( + content=ft.Markdown( + value=sample, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + on_tap_link=handle_link_tap, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/markdown/basic/pyproject.toml b/sdk/python/examples/controls/core/markdown/basic/pyproject.toml new file mode 100644 index 0000000000..784c5c4417 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-basic" +version = "1.0.0" +description = "Renders a long Markdown document with links, images, tables, and code blocks." +requires-python = ">=3.10" +keywords = ["markdown", "rich text", "links", "tables", "code blocks"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Markdown"] +layout_pattern = "article" +complexity = "basic" +features = ["github markdown rendering", "link tap callback", "scrollable markdown"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py b/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py new file mode 100644 index 0000000000..7c836b9c83 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/code_syntax_highlight/main.py @@ -0,0 +1,181 @@ +import flet as ft + +sample = """ +# Flet + + + +Flet is a framework for adding server-driven UI (SDUI) experiences to existing Flutter +apps or building standalone web, mobile and desktop apps with Flutter UI. + +Add an interactive `FletApp` widget to your Flutter app whose content is controlled by a remote Python script. +It is an ideal solution for building non-core or frequently changing functionality such as product catalog, feedback form, in-app survey or support chat. Flet enables your team to ship new features faster by reducing the number of App Store validation cycles. Just re-deploy a web app hosting a Python script and your users will get an instant update! + +On the server side Flet provides an easy to learn programming model that enables Python developers without prior Flutter (or even front-end) experience to participate in development of your larger Flutter app or build their own apps with Flutter UI from scratch. + +## Getting started with Flet + +### Install `flet` Python module + +Flet requires Python 3.7 or above. To start with Flet, you need to install flet module first: + +~~~bash +pip install flet +~~~ + +### Create Python program + +Create a new Python program using Flet which will be driving the content of `FletApp` widget. + +Let's do a simple `counter.py` app similar to a Flutter new project template: + +~~~python +import flet +from flet import IconButton, Page, Row, TextField, icons + +def main(page: Page): + page.title = "Flet counter example" + page.vertical_alignment = "center" + + txt_number = TextField(value="0", text_align="right", width=100) + + def minus_click(e): + txt_number.value = int(txt_number.value) - 1 + page.update() + + def plus_click(e): + txt_number.value = int(txt_number.value) + 1 + page.update() + + page.add( + Row( + [ + IconButton(icons.REMOVE, on_click=minus_click), + txt_number, + IconButton(icons.ADD, on_click=plus_click), + ], + alignment="center", + ) + ) + +flet.app(main, port=8550) +~~~ + +Run the app: + +~~~bash +python counter.py +~~~ + +You should see the app running in a native OS window. + +There is a web server (Fletd) running in the background on a fixed port `8550`. Fletd web server is a "bridge" between Python and Flutter. + +`FletApp` widget in your Flutter application will be communicating with Fletd web server via WebSockets to receive UI updates and send user-generated UI events. + +For production use Python app along with Fletd could be [deployed to a public web host](https://flet.dev/docs/publish/web/dynamic-website/) and be accessible via HTTPS with domain name. + +### Add Flet widget to a Flutter app + +Create a new or open existing Flutter project. + +Install Flutter `flet` package: + +~~~bash +flutter pub add flet +~~~ + +For a new project replace `main.dart` with the following: + +~~~dart +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +void main() async { + await setupDesktop(); + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + title: 'Flet Flutter Demo', + home: FletApp(pageUrl: "http://localhost:8550"), + ); + } +} +~~~ + +In the app above `FletApp` widget is hosted inside `MaterialApp` widget. + +If Flet app must be able to handle page route change events (web browser URL changes, mobile app deep linking) it must be the top most widget as it contains its own `MaterialApp` widget handling route changes: + +~~~dart +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +void main() async { + await setupDesktop(); + runApp(const FletApp(pageUrl: "http://localhost:8550")); +} +~~~ + +Run the program and see Flet app running inside a Flutter app. + +When adding `FletApp` widget to the existing desktop Flutter app make sure `setupDesktop()` is called before `runApp()` to initialize Flet's built-in window manager. + +## Flet learning resources + +* [Getting started for Python](https://flet.dev/docs/getting-started/installation/) +* [Controls reference](https://flet.dev/docs/controls) +* [Tutorials](https://flet.dev/docs/tutorials) +* [Examples](https://github.com/flet-dev/examples/tree/main/python) + +## Flet community + +* [Discussions](https://github.com/flet-dev/flet/discussions) +* [Discord](https://discord.gg/dzWXP8SHG8) +* [Twitter](https://twitter.com/fletdev) +* [Email](mailto:hello@flet.dev) + +## FAQ + +Coming soon. + +## Adding custom Flutter widgets + +Coming soon. +""" # noqa: E501 + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + + page.fonts = { + "Roboto Mono": "RobotoMono-VariableFont_wght.ttf", + } + + async def navigate_md_link(e: ft.Event[ft.Markdown]): + await page.launch_url(e.data) + + page.add( + ft.SafeArea( + content=ft.Markdown( + value=sample, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + code_theme=ft.MarkdownCodeTheme.ATOM_ONE_DARK, + code_style_sheet=ft.MarkdownStyleSheet( + code_text_style=ft.TextStyle(font_family="Roboto Mono") + ), + on_tap_link=navigate_md_link, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/markdown/code_syntax_highlight/pyproject.toml b/sdk/python/examples/controls/core/markdown/code_syntax_highlight/pyproject.toml new file mode 100644 index 0000000000..8acfd0fa29 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/code_syntax_highlight/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-code-syntax-highlight" +version = "1.0.0" +description = "Displays Markdown with syntax-highlighted code blocks and custom monospace font style." +requires-python = ">=3.10" +keywords = ["markdown", "syntax highlight", "code theme", "fonts"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "Code syntax highlight" +controls = ["SafeArea", "Markdown", "MarkdownStyleSheet", "TextStyle"] +layout_pattern = "article" +complexity = "basic" +features = ["code syntax highlighting", "custom code font", "link tap callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/markdown/custom_text_theme/main.py b/sdk/python/examples/controls/core/markdown/custom_text_theme/main.py new file mode 100644 index 0000000000..132a52d039 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/custom_text_theme/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.DARK + + def change_theme_mode(e: ft.Event[ft.Switch]): + if page.theme_mode == ft.ThemeMode.DARK: + page.theme_mode = ft.ThemeMode.LIGHT + switch.thumb_icon = ft.Icons.LIGHT_MODE + else: + switch.thumb_icon = ft.Icons.DARK_MODE + page.theme_mode = ft.ThemeMode.DARK + page.update() + + switch = ft.Switch(thumb_icon=ft.Icons.DARK_MODE, on_change=change_theme_mode) + + page.add( + ft.SafeArea( + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Container( + bgcolor="#550000", + padding=20, + theme=ft.Theme( + text_theme=ft.TextTheme( + body_medium=ft.TextStyle(color=ft.Colors.WHITE), + body_large=ft.TextStyle(color=ft.Colors.WHITE), + body_small=ft.TextStyle(color=ft.Colors.WHITE), + ) + ), + content=ft.Markdown("I can read this!"), + ), + ft.Container( + padding=ft.Padding.only(bottom=50), + alignment=ft.Alignment.TOP_RIGHT, + content=switch, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/markdown/custom_text_theme/pyproject.toml b/sdk/python/examples/controls/core/markdown/custom_text_theme/pyproject.toml new file mode 100644 index 0000000000..ed894ad15e --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/custom_text_theme/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-custom-text-theme" +version = "1.0.0" +description = "Applies a custom text theme to Markdown and toggles light/dark theme mode." +requires-python = ">=3.10" +keywords = ["markdown", "theme", "text theme", "dark mode", "switch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "Custom text theme" +controls = ["SafeArea", "Row", "Container", "Markdown", "Switch", "Theme", "TextTheme"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom markdown text colors", "theme mode toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/markdown/listviews/main.py b/sdk/python/examples/controls/core/markdown/listviews/main.py new file mode 100644 index 0000000000..119a5905b4 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/listviews/main.py @@ -0,0 +1,160 @@ +import flet as ft + +sample = """ +# Markdown Example +Markdown allows you to easily include formatted text, images, and even formatted Dart +code in your app. + +## Titles + +Setext-style + +``` +This is an H1 +============= + +This is an H2 +------------- +``` + +Atx-style + +``` +# This is an H1 + +## This is an H2 + +###### This is an H6 +``` + +Select the valid headers: + +- [x] `# hello` +- [ ] `#hello` + +## Links + +[Google's Homepage][Google] + +``` +[inline-style](https://www.google.com) + +[reference-style][Google] +``` + +## Images + +![Flutter logo](/icons/icon-192.png) + +![Test image](https://picsum.photos/200/300) + +## Tables + +|Syntax |Result | +|---------------------------------------|-------------------------------------| +|`*italic 1*` |*italic 1* | +|`_italic 2_` | _italic 2_ | +|`**bold 1**` |**bold 1** | +|`__bold 2__` |__bold 2__ | +|`This is a ~~strikethrough~~` |This is a ~~strikethrough~~ | +|`***italic bold 1***` |***italic bold 1*** | +|`___italic bold 2___` |___italic bold 2___ | +|`***~~italic bold strikethrough 1~~***`|***~~italic bold strikethrough 1~~***| +|`~~***italic bold strikethrough 2***~~`|~~***italic bold strikethrough 2***~~| + +## Styling +Style text as _italic_, __bold__, ~~strikethrough~~, or `inline code`. + +- Use bulleted lists +- To better clarify +- Your points + +## Code blocks +Formatted Dart code looks really pretty too: + +``` +void main() { + runApp(MaterialApp( + home: Scaffold( + body: Markdown(data: markdownData), + ), + )); +} +``` + +## Center Title + +###### ※ ※ ※ + +_* How to implement it see main.dart#L129 in example._ + +## Custom Syntax + +NaOH + Al_2O_3 = NaAlO_2 + H_2O + +C_4H_10 = C_2H_6 + C_2H_4 + +## Markdown widget + +This is an example of how to create your own Markdown widget: + + Markdown(data: 'Hello _world_!'); + +Enjoy! + +[Google]: https://www.google.com/ + +## Line Breaks + +This is an example of how to create line breaks (tab or two whitespaces): + +line 1 + + +line 2 + + + +line 3 +""" + + +def main(page: ft.Page): + async def navigate_md_link(e: ft.Event[ft.Markdown]): + await page.launch_url(e.data) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.ListView( + expand=True, + controls=[ + ft.Markdown( + value=sample, + on_tap_link=navigate_md_link, + ) + ], + ), + ft.Divider(), + ft.ListView( + expand=True, + controls=[ + ft.Markdown( + value=sample, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + on_tap_link=navigate_md_link, + ) + ], + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/markdown/listviews/pyproject.toml b/sdk/python/examples/controls/core/markdown/listviews/pyproject.toml new file mode 100644 index 0000000000..3425a3daa6 --- /dev/null +++ b/sdk/python/examples/controls/core/markdown/listviews/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "markdown-listviews" +version = "1.0.0" +description = "Compares Markdown rendering in two ListViews, including selectable GitHub-style mode." +requires-python = ">=3.10" +keywords = ["markdown", "listview", "selectable", "comparison"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Markdown"] + +[tool.flet.metadata] +title = "ListViews" +controls = ["SafeArea", "Column", "ListView", "Divider", "Markdown"] +layout_pattern = "comparison" +complexity = "basic" +features = ["dual markdown views", "selectable markdown", "github extension set"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/markdown/media/basic.gif b/sdk/python/examples/controls/core/markdown/media/basic.gif new file mode 100644 index 0000000000..9075ce62b5 Binary files /dev/null and b/sdk/python/examples/controls/core/markdown/media/basic.gif differ diff --git a/sdk/python/examples/controls/core/markdown/media/code_syntax_highlight.png b/sdk/python/examples/controls/core/markdown/media/code_syntax_highlight.png new file mode 100644 index 0000000000..f19bc1cfcf Binary files /dev/null and b/sdk/python/examples/controls/core/markdown/media/code_syntax_highlight.png differ diff --git a/sdk/python/examples/controls/core/page/app_exit_confirm_dialog/main.py b/sdk/python/examples/controls/core/page/app_exit_confirm_dialog/main.py new file mode 100644 index 0000000000..8e26e87e58 --- /dev/null +++ b/sdk/python/examples/controls/core/page/app_exit_confirm_dialog/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + def window_event(e: ft.WindowEvent): + if e.type == ft.WindowEventType.CLOSE: + page.show_dialog(confirm_dialog) + page.update() + + page.window.prevent_close = True + page.window.on_event = window_event + + async def handle_yes_click(e: ft.Event[ft.Button]): + await page.window.destroy() + + def handle_no_click(e: ft.Event[ft.OutlinedButton]): + page.pop_dialog() + page.update() + + confirm_dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Please confirm"), + content=ft.Text("Do you really want to exit this app?"), + actions=[ + ft.Button(content="Yes", on_click=handle_yes_click), + ft.OutlinedButton(content="No", on_click=handle_no_click), + ], + actions_alignment=ft.MainAxisAlignment.END, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + 'Try exiting this app by clicking window\'s "Close" button!' + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/app_exit_confirm_dialog/pyproject.toml b/sdk/python/examples/controls/core/page/app_exit_confirm_dialog/pyproject.toml new file mode 100644 index 0000000000..ac7c8d0668 --- /dev/null +++ b/sdk/python/examples/controls/core/page/app_exit_confirm_dialog/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "page-app-exit-confirm-dialog" +version = "1.0.0" +description = "Demonstrates handling window close events with a custom confirm dialog." +requires-python = ">=3.10" +keywords = ["page", "window", "close", "confirm dialog", "window event", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "App exit confirm dialog" +controls = ["SafeArea", "Text", "AlertDialog", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["window close interception", "confirm dialog"] + +[tool.flet] +platforms = ["macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/device_locale/main.py b/sdk/python/examples/controls/core/page/device_locale/main.py new file mode 100644 index 0000000000..28888ec8cf --- /dev/null +++ b/sdk/python/examples/controls/core/page/device_locale/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +async def main(page: ft.Page): + def format_locales(locales: list[ft.Locale]) -> str: + """Format locale list for display.""" + return ", ".join(str(loc) for loc in locales) + + def handle_locale_change(e: ft.LocaleChangeEvent): + page.add(ft.Text(f"Locales changed: {format_locales(e.locales)}")) + + page.on_locale_change = handle_locale_change + page.scroll = ft.ScrollMode.AUTO + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + initial_locales = (await page.get_device_info()).locales + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text(f"Initial locales: {format_locales(initial_locales)}"), + ft.Text( + "Change your system or browser language to trigger " + "on_locale_change.", + color=ft.Colors.BLUE, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/device_locale/pyproject.toml b/sdk/python/examples/controls/core/page/device_locale/pyproject.toml new file mode 100644 index 0000000000..3f84bdecf9 --- /dev/null +++ b/sdk/python/examples/controls/core/page/device_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-device-locale" +version = "1.0.0" +description = "Demonstrates locale-change handling and initial locale reporting in a Page." +requires-python = ">=3.10" +keywords = ["page", "locale", "locales", "on_locale_change", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Localization"] + +[tool.flet.metadata] +title = "Device locale" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["locale change handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/device_orientation/main.py b/sdk/python/examples/controls/core/page/device_orientation/main.py new file mode 100644 index 0000000000..a9e781fb71 --- /dev/null +++ b/sdk/python/examples/controls/core/page/device_orientation/main.py @@ -0,0 +1,69 @@ +import flet as ft + + +def main(page: ft.Page) -> None: + page.title = "Device orientation lock" + page.appbar = ft.AppBar( + title=ft.Text("Device orientation Playground"), + center_title=True, + bgcolor=ft.Colors.BLUE, + ) + + def handle_media_change(e: ft.PageMediaData) -> None: + page.show_dialog( + ft.SnackBar( + f"I see you rotated the device to {e.orientation.name} orientation. 👀", + action="Haha!", + duration=ft.Duration(seconds=3), + ) + ) + + page.on_media_change = handle_media_change + + async def on_checkbox_change(e: ft.Event[ft.Checkbox]) -> None: + # get selection + selected = [o for o, checkbox in checkboxes.items() if checkbox.value] + # apply selection + await page.set_allowed_device_orientations(selected) + + checkboxes: dict[ft.DeviceOrientation, ft.Checkbox] = { + orientation: ft.Checkbox( + label=orientation.name, + value=True, + on_change=on_checkbox_change, + disabled=not page.platform.is_mobile(), # disabled on non-mobile platforms + ) + for orientation in list(ft.DeviceOrientation) + } + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + spans=[ + # shown only on mobile platforms + ft.TextSpan( + "Select the orientations that should remain enabled " + "for the app. " + "If no orientation is selected, " + "the system defaults will be used.", + visible=page.platform.is_mobile(), + ), + # shown only on non-mobile platforms + ft.TextSpan( + "Please open this example on a mobile device instead.", + visible=not page.platform.is_mobile(), + style=ft.TextStyle(weight=ft.FontWeight.BOLD), + ), + ], + ), + ft.Column(controls=list(checkboxes.values())), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/device_orientation/pyproject.toml b/sdk/python/examples/controls/core/page/device_orientation/pyproject.toml new file mode 100644 index 0000000000..3e4a4b5f30 --- /dev/null +++ b/sdk/python/examples/controls/core/page/device_orientation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-device-orientation" +version = "1.0.0" +description = "Shows how to handle device orientation and lock allowed orientations at runtime." +requires-python = ">=3.10" +keywords = ["page", "orientation", "media", "checkbox", "mobile"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Page"] + +[tool.flet.metadata] +title = "Device orientation" +controls = ["SafeArea", "AppBar", "Text", "Column", "Checkbox", "Page"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["media change handling", "orientation locking"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/keyboard_events/main.py b/sdk/python/examples/controls/core/page/keyboard_events/main.py new file mode 100644 index 0000000000..f1a745ef6f --- /dev/null +++ b/sdk/python/examples/controls/core/page/keyboard_events/main.py @@ -0,0 +1,56 @@ +import flet as ft + + +class ButtonControl(ft.Container): + def __init__(self, text): + super().__init__() + self.content: ft.Text = ft.Text(text) + self.border = ft.Border.all(1, ft.Colors.BLACK_54) + self.border_radius = 3 + self.bgcolor = "0x09000000" + self.padding = 10 + self.visible = False + + +def main(page: ft.Page): + page.spacing = 50 + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def on_keyboard(e: ft.KeyboardEvent): + key.content.value = e.key + key.visible = True + shift.visible = e.shift + ctrl.visible = e.ctrl + alt.visible = e.alt + meta.visible = e.meta + page.update() + + page.on_keyboard_event = on_keyboard + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Press any key with a combination of CTRL, ALT, SHIFT " + "and META keys..." + ), + ft.Row( + controls=[ + key := ButtonControl(""), + shift := ButtonControl("Shift"), + ctrl := ButtonControl("Control"), + alt := ButtonControl("Alt"), + meta := ButtonControl("Meta"), + ], + alignment=ft.MainAxisAlignment.CENTER, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/keyboard_events/pyproject.toml b/sdk/python/examples/controls/core/page/keyboard_events/pyproject.toml new file mode 100644 index 0000000000..c514e22398 --- /dev/null +++ b/sdk/python/examples/controls/core/page/keyboard_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-keyboard-events" +version = "1.0.0" +description = "Demonstrates live updates from page keyboard events and modifier keys." +requires-python = ">=3.10" +keywords = ["page", "keyboard", "keyboard event", "shortcut", "modifier keys"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Keyboard"] + +[tool.flet.metadata] +title = "Keyboard events" +controls = ["SafeArea", "Column", "Row", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["keyboard input handling", "modifier keys display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/semantics_debugger/main.py b/sdk/python/examples/controls/core/page/semantics_debugger/main.py new file mode 100644 index 0000000000..58abf08baf --- /dev/null +++ b/sdk/python/examples/controls/core/page/semantics_debugger/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def on_keyboard(e: ft.KeyboardEvent): + if e.shift and e.key == "S": + page.show_semantics_debugger = not page.show_semantics_debugger + page.update() + + page.on_keyboard_event = on_keyboard + + def button_click(e: ft.Event[ft.Button]): + counter.value = str(int(counter.value) + 1) + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + counter := ft.Text("0", size=40), + ft.Text("Press Shift+S to toggle semantics debugger"), + ft.Button( + content="Increment number", + icon=ft.Icons.ADD, + on_click=button_click, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/semantics_debugger/pyproject.toml b/sdk/python/examples/controls/core/page/semantics_debugger/pyproject.toml new file mode 100644 index 0000000000..232f5d1182 --- /dev/null +++ b/sdk/python/examples/controls/core/page/semantics_debugger/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-semantics-debugger" +version = "1.0.0" +description = "Demonstrates toggling the semantics debugger using a keyboard shortcut." +requires-python = ">=3.10" +keywords = ["page", "semantics", "accessibility", "keyboard shortcut", "debugger"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Accessibility"] + +[tool.flet.metadata] +title = "Semantics debugger" +controls = ["SafeArea", "Column", "Text", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["semantics debugger toggle", "keyboard interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/set_platform/main.py b/sdk/python/examples/controls/core/page/set_platform/main.py new file mode 100644 index 0000000000..9cea0a76d3 --- /dev/null +++ b/sdk/python/examples/controls/core/page/set_platform/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def set_android(e: ft.Event[ft.Button]): + page.platform = ft.PagePlatform.ANDROID + page.update() + print("New platform:", page.platform) + + def set_ios(e: ft.Event[ft.Button]): + page.platform = ft.PagePlatform.IOS + page.update() + print("New platform:", page.platform) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Switch(label="Switch A", adaptive=True), + ft.Button("Set Android", on_click=set_android), + ft.Button("Set iOS", on_click=set_ios), + ] + ) + ) + ) + + print("Default platform:", page.platform) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/set_platform/pyproject.toml b/sdk/python/examples/controls/core/page/set_platform/pyproject.toml new file mode 100644 index 0000000000..40c0a370d4 --- /dev/null +++ b/sdk/python/examples/controls/core/page/set_platform/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-set-platform" +version = "1.0.0" +description = "Demonstrates switching page platform at runtime between iOS and Android." +requires-python = ">=3.10" +keywords = ["page", "platform", "ios", "android", "switch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Page"] + +[tool.flet.metadata] +title = "Set platform" +controls = ["SafeArea", "Column", "Switch", "Button"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["runtime platform switching", "page platform update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/splash_test/main.py b/sdk/python/examples/controls/core/page/splash_test/main.py new file mode 100644 index 0000000000..d00d4bac14 --- /dev/null +++ b/sdk/python/examples/controls/core/page/splash_test/main.py @@ -0,0 +1,32 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + async def handle_button_click(e: ft.Event[ft.Button]): + my_bar = ft.ProgressBar() + + page.overlay.append(my_bar) + btn.disabled = True + page.update() + await asyncio.sleep(3) + + page.overlay.remove(my_bar) + btn.disabled = False + page.update() + + btn = ft.Button("Do some lengthy task!", on_click=handle_button_click) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + btn, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/splash_test/pyproject.toml b/sdk/python/examples/controls/core/page/splash_test/pyproject.toml new file mode 100644 index 0000000000..28d4feeb18 --- /dev/null +++ b/sdk/python/examples/controls/core/page/splash_test/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-splash-test" +version = "1.0.0" +description = "Shows overlay progress-bar feedback while an async task runs." +requires-python = ">=3.10" +keywords = ["page", "overlay", "async", "progress", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressBar"] + +[tool.flet.metadata] +title = "Splash test" +controls = ["SafeArea", "Column", "Button", "ProgressBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["async task execution", "page overlay usage"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/window_hidden_on_start/main.py b/sdk/python/examples/controls/core/page/window_hidden_on_start/main.py new file mode 100644 index 0000000000..b8229c3f41 --- /dev/null +++ b/sdk/python/examples/controls/core/page/window_hidden_on_start/main.py @@ -0,0 +1,33 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + print("Window is hidden on start. Will show after 3 seconds...") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Hello!"), + ] + ) + ) + ) + + # some configuration that we want to do before showing the window + page.window.width = 300 + page.window.height = 200 + page.update() + await page.window.center() + + # wait for 3 seconds before showing the window + await asyncio.sleep(3) + + # show the window + page.window.visible = True + page.update() + + +if __name__ == "__main__": + ft.run(main, view=ft.AppView.FLET_APP_HIDDEN) diff --git a/sdk/python/examples/controls/core/page/window_hidden_on_start/pyproject.toml b/sdk/python/examples/controls/core/page/window_hidden_on_start/pyproject.toml new file mode 100644 index 0000000000..7b1135659e --- /dev/null +++ b/sdk/python/examples/controls/core/page/window_hidden_on_start/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "page-window-hidden-on-start" +version = "1.0.0" +description = "Demonstrates initializing window settings before showing a hidden app window." +requires-python = ">=3.10" +keywords = ["page", "window", "hidden", "startup", "overlay", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Window hidden on start" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["hidden startup", "window configuration"] + +[tool.flet] +platforms = ["macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page/window_resize/main.py b/sdk/python/examples/controls/core/page/window_resize/main.py new file mode 100644 index 0000000000..9a372bba20 --- /dev/null +++ b/sdk/python/examples/controls/core/page/window_resize/main.py @@ -0,0 +1,28 @@ +import flet as ft + + +def main(page: ft.Page): + if page.window.width is None or page.window.height is None: + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Window size can be changed only in desktop apps."), + ] + ) + ) + ) + return + + width = 400 + height = 300 + + chrome_width = page.window.width - page.width + chrome_height = page.window.height - page.height + page.window.width = width + chrome_width + page.window.height = height + chrome_height + page.window.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page/window_resize/pyproject.toml b/sdk/python/examples/controls/core/page/window_resize/pyproject.toml new file mode 100644 index 0000000000..1d2efd0311 --- /dev/null +++ b/sdk/python/examples/controls/core/page/window_resize/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "page-window-resize" +version = "1.0.0" +description = "Demonstrates resizing the app window programmatically in desktop contexts." +requires-python = ">=3.10" +keywords = ["page", "window", "resize", "desktop", "window metrics"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Pages/Page"] + +[tool.flet.metadata] +title = "Window resize" +controls = ["SafeArea", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["window geometry", "desktop platform behavior"] + +[tool.flet] +platforms = ["macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page_view/basic/main.py b/sdk/python/examples/controls/core/page_view/basic/main.py new file mode 100644 index 0000000000..61e6198b10 --- /dev/null +++ b/sdk/python/examples/controls/core/page_view/basic/main.py @@ -0,0 +1,59 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 0 + + page.add( + ft.SafeArea( + expand=True, + content=ft.PageView( + expand=True, + viewport_fraction=0.9, + on_change=lambda e: print(f"Currently viewing page {int(e.data)}"), + selected_index=1, + horizontal=True, + controls=[ + ft.Container( + bgcolor=ft.Colors.INDIGO_400, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Welcome", size=40, weight=ft.FontWeight.BOLD), + ft.Text("Swipe to see what PageView can do."), + ], + ), + ), + ft.Container( + bgcolor=ft.Colors.PINK_300, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Icon(ft.Icons.ANIMATION, size=72), + ft.Text( + "Viewport fraction lets you peek at the next slide." + ), + ], + ), + ), + ft.Container( + bgcolor=ft.Colors.TEAL_300, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Icon(ft.Icons.TOUCH_APP, size=72), + ft.Text("Use on_change to respond to page swipes."), + ], + ), + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page_view/basic/pyproject.toml b/sdk/python/examples/controls/core/page_view/basic/pyproject.toml new file mode 100644 index 0000000000..7ae5f8826a --- /dev/null +++ b/sdk/python/examples/controls/core/page_view/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "page-view-basic" +version = "1.0.0" +description = "Demonstrates a swipeable PageView with page-change callback and peeked viewport pages." +requires-python = ">=3.10" +keywords = ["page view", "pageview", "swipe", "carousel", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/PageView"] + +[tool.flet.metadata] +title = "Basic" +controls = ["PageView", "SafeArea", "Container", "Column", "Text", "Icon"] +layout_pattern = "pager" +complexity = "basic" +features = ["horizontal swipe navigation", "page change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/page_view/programmatic_swipe/main.py b/sdk/python/examples/controls/core/page_view/programmatic_swipe/main.py new file mode 100644 index 0000000000..8dca9fae2a --- /dev/null +++ b/sdk/python/examples/controls/core/page_view/programmatic_swipe/main.py @@ -0,0 +1,78 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 0 + + async def show_previous_page(e: ft.Event[ft.FloatingActionButton]): + await view.previous_page( + animation_curve=ft.AnimationCurve.BOUNCE_OUT, + animation_duration=ft.Duration(seconds=1), + ) + + async def show_next_page(e: ft.Event[ft.FloatingActionButton]): + await view.next_page( + animation_curve=ft.AnimationCurve.BOUNCE_OUT, + animation_duration=ft.Duration(seconds=1), + ) + + page.floating_action_button = ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + wrap=True, + controls=[ + ft.FloatingActionButton( + icon=ft.Icons.SWIPE_LEFT, + on_click=show_previous_page, + tooltip="Previous Page", + ), + ft.FloatingActionButton( + icon=ft.Icons.SWIPE_RIGHT, + on_click=show_next_page, + tooltip="Next Page", + ), + ], + ) + + page.add( + ft.SafeArea( + expand=True, + content=( + view := ft.PageView( + expand=True, + viewport_fraction=0.9, + selected_index=1, + horizontal=True, + controls=[ + ft.Container( + bgcolor=bgcolor, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + f"Page {idx}", + size=55, + weight=ft.FontWeight.BOLD, + ), + ], + ), + ) + for idx, bgcolor in enumerate( + [ + ft.Colors.RED_800, + ft.Colors.BLUE_800, + ft.Colors.GREEN_800, + ft.Colors.ORANGE_800, + ft.Colors.PURPLE_800, + ft.Colors.PINK_800, + ] + ) + ], + ) + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/page_view/programmatic_swipe/pyproject.toml b/sdk/python/examples/controls/core/page_view/programmatic_swipe/pyproject.toml new file mode 100644 index 0000000000..83b969da04 --- /dev/null +++ b/sdk/python/examples/controls/core/page_view/programmatic_swipe/pyproject.toml @@ -0,0 +1,40 @@ +[project] +name = "page-view-programmatic-swipe" +version = "1.0.0" +description = "Demonstrates programmatic PageView navigation via previous/next actions." +requires-python = ">=3.10" +keywords = [ + "page view", + "pageview", + "programmatic swipe", + "floating action button", + "async", +] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/PageView"] + +[tool.flet.metadata] +title = "Programmatic Swipe" +controls = [ + "PageView", + "SafeArea", + "Container", + "Column", + "Text", + "Row", + "FloatingActionButton", +] +layout_pattern = "programmatic-controls" +complexity = "basic" +features = ["programmatic page navigation", "manual swipe control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/pagelet/basic/main.py b/sdk/python/examples/controls/core/pagelet/basic/main.py new file mode 100644 index 0000000000..16aba792e2 --- /dev/null +++ b/sdk/python/examples/controls/core/pagelet/basic/main.py @@ -0,0 +1,87 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.MainAxisAlignment.CENTER + page.vertical_alignment = ft.CrossAxisAlignment.CENTER + + async def handle_show_drawer(e: ft.Event[ft.FloatingActionButton]): + await pagelet.show_drawer() + + async def handle_show_end_drawer(e: ft.Event[ft.Button]): + await pagelet.show_end_drawer() + await asyncio.sleep(3) + await pagelet.close_end_drawer() + + page.add( + ft.SafeArea( + content=( + pagelet := ft.Pagelet( + width=500, + height=500, + appbar=ft.AppBar( + title=ft.Text("Pagelet AppBar"), + center_title=True, + bgcolor=ft.Colors.RED_500, + ), + content=ft.Text("Pagelet Body"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + bottom_appbar=ft.BottomAppBar( + bgcolor=ft.Colors.BLUE, + shape=ft.CircularRectangleNotchShape(), + content=ft.Row( + controls=[ + ft.IconButton( + icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE + ), + ft.Container(expand=True), + ft.IconButton( + icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE + ), + ft.IconButton( + icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE + ), + ], + ), + ), + drawer=ft.NavigationDrawer( + on_dismiss=lambda e: print("Drawer dismissed"), + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_COMMENT, + label="Item 2", + ), + ], + ), + end_drawer=ft.NavigationDrawer( + on_dismiss=lambda e: print("End Drawer dismissed"), + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.SLOW_MOTION_VIDEO, + label="Item 3", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.INSERT_CHART, + label="Item 4", + ), + ], + ), + floating_action_button=ft.FloatingActionButton( + icon=ft.Icons.ADD, + shape=ft.CircleBorder(), + ), + floating_action_button_location=ft.FloatingActionButtonLocation.CENTER_DOCKED, + ) + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/pagelet/basic/pyproject.toml b/sdk/python/examples/controls/core/pagelet/basic/pyproject.toml new file mode 100644 index 0000000000..781caf594c --- /dev/null +++ b/sdk/python/examples/controls/core/pagelet/basic/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "pagelet-basic" +version = "1.0.0" +description = "Shows a Pagelet configured with app bars, drawers, and a floating action button." +requires-python = ">=3.10" +keywords = [ + "pagelet", + "navigation drawer", + "app bar", + "floating action button", + "async", +] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Pagelet"] + +[tool.flet.metadata] +title = "Basic" +controls = [ + "Pagelet", + "SafeArea", + "AppBar", + "BottomAppBar", + "NavigationDrawer", + "NavigationDrawerDestination", + "FloatingActionButton", + "Text", + "IconButton", + "Row", + "Column", + "Container", +] +layout_pattern = "app-shell" +complexity = "basic" +features = ["drawer navigation", "floating action behavior", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/pagelet/basic_declarative/main.py b/sdk/python/examples/controls/core/pagelet/basic_declarative/main.py new file mode 100644 index 0000000000..a1bb723132 --- /dev/null +++ b/sdk/python/examples/controls/core/pagelet/basic_declarative/main.py @@ -0,0 +1,81 @@ +import flet as ft + + +@ft.component +def App(): + async def handle_show_drawer(): + await p.show_drawer() + + async def handle_show_end_drawer(): + await p.show_end_drawer() + + p = ft.Pagelet( + width=400, + height=400, + appbar=ft.AppBar( + title=ft.Text("Pagelet AppBar Title"), + bgcolor=ft.Colors.AMBER_ACCENT, + ), + content=ft.Container( + ft.Column( + [ + ft.Text("Pagelet Body"), + ft.Button("Show end drawer", on_click=handle_show_end_drawer), + ] + ), + padding=ft.Padding.all(16), + ), + bgcolor=ft.Colors.AMBER_100, + bottom_appbar=ft.BottomAppBar( + bgcolor=ft.Colors.BLUE, + shape=ft.CircularRectangleNotchShape(), + content=ft.Row( + controls=[ + ft.IconButton(icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE), + ft.Container(expand=True), + ft.IconButton(icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE), + ft.IconButton(icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE), + ] + ), + ), + drawer=ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_COMMENT, + label="Item 2", + ), + ], + ), + end_drawer=ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.SLOW_MOTION_VIDEO, + label="Item 3", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.INSERT_CHART, + label="Item 4", + ), + ], + ), + floating_action_button=ft.FloatingActionButton( + content="Open", + shape=ft.CircleBorder(), + on_click=handle_show_drawer, + ), + floating_action_button_location=ft.FloatingActionButtonLocation.CENTER_DOCKED, + ) + return ft.SafeArea(content=p) + + +def main(page: ft.Page): + page.title = "Pagelet example" + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/pagelet/basic_declarative/pyproject.toml b/sdk/python/examples/controls/core/pagelet/basic_declarative/pyproject.toml new file mode 100644 index 0000000000..4522c4dfbe --- /dev/null +++ b/sdk/python/examples/controls/core/pagelet/basic_declarative/pyproject.toml @@ -0,0 +1,46 @@ +[project] +name = "pagelet-basic-declarative" +version = "1.0.0" +description = "Demonstrates a declarative Pagelet with drawers and an app shell." +requires-python = ">=3.10" +keywords = [ + "pagelet", + "declarative", + "navigation drawer", + "component", + "material", + "async", +] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Pagelet"] + +[tool.flet.metadata] +title = "Basic Declarative" +controls = [ + "Pagelet", + "SafeArea", + "AppBar", + "BottomAppBar", + "NavigationDrawer", + "NavigationDrawerDestination", + "FloatingActionButton", + "Button", + "Text", + "Row", + "IconButton", + "Container", +] +layout_pattern = "app-shell" +complexity = "basic" +features = ["declarative UI composition", "drawer navigation", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/placeholder/basic/main.py b/sdk/python/examples/controls/core/placeholder/basic/main.py new file mode 100644 index 0000000000..999d1af536 --- /dev/null +++ b/sdk/python/examples/controls/core/placeholder/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Placeholder( + expand=True, + color=ft.Colors.GREEN_ACCENT, + fallback_height=200, + fallback_width=300, + stroke_width=20, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/placeholder/basic/pyproject.toml b/sdk/python/examples/controls/core/placeholder/basic/pyproject.toml new file mode 100644 index 0000000000..f85545a582 --- /dev/null +++ b/sdk/python/examples/controls/core/placeholder/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "placeholder-basic" +version = "1.0.0" +description = "Shows a basic Placeholder control with fallback dimensions and custom styling." +requires-python = ">=3.10" +keywords = ["placeholder", "layout", "fallback size", "ui shell"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Placeholder"] + +[tool.flet.metadata] +title = "Basic" +controls = ["Placeholder", "SafeArea"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["placeholder layout", "fallback dimensions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/placeholder/media/basic.png b/sdk/python/examples/controls/core/placeholder/media/basic.png new file mode 100644 index 0000000000..7e4c082719 Binary files /dev/null and b/sdk/python/examples/controls/core/placeholder/media/basic.png differ diff --git a/sdk/python/examples/controls/core/responsive_row/basic/main.py b/sdk/python/examples/controls/core/responsive_row/basic/main.py new file mode 100644 index 0000000000..3ae27d498f --- /dev/null +++ b/sdk/python/examples/controls/core/responsive_row/basic/main.py @@ -0,0 +1,86 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_page_resize(e: ft.PageResizeEvent): + pw.value = f"{page.width} px" + pw.update() + + page.on_resize = handle_page_resize + + pw = ft.Text(text_align=ft.TextAlign.END, style=ft.TextTheme.display_small) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.ResponsiveRow( + controls=[ + ft.Container( + content=ft.Text("Column 1"), + padding=5, + bgcolor=ft.Colors.YELLOW, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ft.Container( + content=ft.Text("Column 2"), + padding=5, + bgcolor=ft.Colors.GREEN, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ft.Container( + content=ft.Text("Column 3"), + padding=5, + bgcolor=ft.Colors.BLUE, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ft.Container( + content=ft.Text("Column 4"), + padding=5, + bgcolor=ft.Colors.PINK_300, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ), + ], + ), + ft.ResponsiveRow( + run_spacing={ft.ResponsiveRowBreakpoint.XS: 10}, + controls=[ + ft.TextField( + label="TextField 1", + col={ft.ResponsiveRowBreakpoint.MD: 4}, + ), + ft.TextField( + label="TextField 2", + col={ft.ResponsiveRowBreakpoint.MD: 4}, + ), + ft.TextField( + label="TextField 3", + col={ft.ResponsiveRowBreakpoint.MD: 4}, + ), + ], + ), + pw, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/responsive_row/basic/pyproject.toml b/sdk/python/examples/controls/core/responsive_row/basic/pyproject.toml new file mode 100644 index 0000000000..3651bdfbd5 --- /dev/null +++ b/sdk/python/examples/controls/core/responsive_row/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "responsive-row-basic" +version = "1.0.0" +description = "Builds a four-column responsive layout and form row that adapt to breakpoints." +requires-python = ">=3.10" +keywords = ["responsive row", "layout", "breakpoints", "grid", "adaptive columns"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ResponsiveRow"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "TextField", "Text"] +layout_pattern = "responsive-grid" +complexity = "basic" +features = ["responsive columns", "text field reflow", "window-aware spacing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/responsive_row/custom_breakpoint/main.py b/sdk/python/examples/controls/core/responsive_row/custom_breakpoint/main.py new file mode 100644 index 0000000000..9df8c13beb --- /dev/null +++ b/sdk/python/examples/controls/core/responsive_row/custom_breakpoint/main.py @@ -0,0 +1,120 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "ResponsiveRow with custom breakpoints" + page.padding = 16 + + breakpoints = { + "phone": 0, + "tablet": 540, + "desktop": 800, + } + + sorted_breakpoints = sorted(breakpoints.items(), key=lambda item: item[1]) + + breakpoint_labels = { + name: ft.Text(f"{name}: >= {value}px", weight=ft.FontWeight.W_500) + for name, value in sorted_breakpoints + } + + width_label = ft.Text() + breakpoint_label = ft.Text() + + def update_status(_=None): + width = ( + (page.window.width if page.window and page.window.width else None) + or page.width + or 0 + ) + width_label.value = f"Page width: {width:.0f}px" + active_breakpoint = max( + (bp for bp, min_width in breakpoints.items() if width >= min_width), + key=lambda bp: breakpoints[bp], + default="phone", + ) + breakpoint_label.value = f"Active breakpoint: {active_breakpoint}" + for name, label in breakpoint_labels.items(): + is_active = name == active_breakpoint + label.color = ft.Colors.BLUE_700 if is_active else None + label.weight = ft.FontWeight.W_700 if is_active else ft.FontWeight.W_400 + label.update() + width_label.update() + breakpoint_label.update() + + page.on_resize = update_status + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Resize the window to see custom breakpoints in action."), + ft.Text( + "Cards switch column spans at phone, tablet, and " + "desktop widths." + ), + ft.Column( + [ + ft.Text( + "Custom breakpoints (min widths):", + weight=ft.FontWeight.W_600, + ), + ft.Column(list(breakpoint_labels.values()), spacing=2), + ], + spacing=6, + ), + ft.ResponsiveRow( + breakpoints=breakpoints, + columns={"phone": 4, "tablet": 8, "desktop": 12}, + spacing=10, + run_spacing=10, + controls=[ + ft.Container( + content=ft.Text( + "Card 1", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.AMBER_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ft.Container( + content=ft.Text( + "Card 2", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.GREEN_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ft.Container( + content=ft.Text( + "Card 3", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.BLUE_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ft.Container( + content=ft.Text( + "Card 4", size=16, weight=ft.FontWeight.W_600 + ), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.PINK_200, + height=60, + col={"phone": 4, "tablet": 4, "desktop": 3}, + ), + ], + ), + width_label, + breakpoint_label, + ] + ) + ) + ) + update_status() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/responsive_row/custom_breakpoint/pyproject.toml b/sdk/python/examples/controls/core/responsive_row/custom_breakpoint/pyproject.toml new file mode 100644 index 0000000000..8cb8f41ecb --- /dev/null +++ b/sdk/python/examples/controls/core/responsive_row/custom_breakpoint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "responsive-row-custom-breakpoint" +version = "1.0.0" +description = "Shows custom breakpoint values and column layouts for ResponsiveRow." +requires-python = ">=3.10" +keywords = ["responsive row", "custom breakpoints", "layout", "adaptive UI"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ResponsiveRow"] + +[tool.flet.metadata] +title = "Custom Breakpoints" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Text", "TextField"] +layout_pattern = "responsive-dashboard" +complexity = "basic" +features = ["custom breakpoints", "adaptive columns", "resize indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/responsive_row/media/basic.gif b/sdk/python/examples/controls/core/responsive_row/media/basic.gif new file mode 100644 index 0000000000..697447a03c Binary files /dev/null and b/sdk/python/examples/controls/core/responsive_row/media/basic.gif differ diff --git a/sdk/python/examples/controls/core/responsive_row/scrollable/main.py b/sdk/python/examples/controls/core/responsive_row/scrollable/main.py new file mode 100644 index 0000000000..b629fb102c --- /dev/null +++ b/sdk/python/examples/controls/core/responsive_row/scrollable/main.py @@ -0,0 +1,66 @@ +import flet as ft + + +def build_card(index: int, color: ft.Colors) -> ft.Container: + return ft.Container( + bgcolor=color, + border_radius=8, + padding=16, + content=ft.Column( + spacing=10, + controls=[ + ft.Text(f"Card {index}", size=22, weight=ft.FontWeight.BOLD), + ft.Text("Line 1"), + ft.Text("Line 2"), + ft.Text("Line 3"), + ft.Text("Line 4"), + ft.Text("Line 5"), + ], + ), + ) + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + spacing=12, + controls=[ + ft.Text( + "Resize the window height. The header stays visible while " + "the responsive content scrolls." + ), + ft.ResponsiveRow( + expand=True, + scroll=ft.ScrollMode.AUTO, + spacing=16, + run_spacing=16, + controls=[ + ft.Container( + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 4, + }, + content=build_card( + i, + [ + ft.Colors.BLUE_50, + ft.Colors.GREEN_50, + ft.Colors.AMBER_50, + ][i % 3], + ), + ) + for i in range(1, 10) + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/responsive_row/scrollable/pyproject.toml b/sdk/python/examples/controls/core/responsive_row/scrollable/pyproject.toml new file mode 100644 index 0000000000..128d25f854 --- /dev/null +++ b/sdk/python/examples/controls/core/responsive_row/scrollable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "responsive-row-scrollable" +version = "1.0.0" +description = "Keeps header content fixed while a tall ResponsiveRow of cards scrolls vertically." +requires-python = ">=3.10" +keywords = ["responsive row", "scroll", "layout", "cards", "adaptive columns"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ResponsiveRow"] + +[tool.flet.metadata] +title = "Scrollable" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Text"] +layout_pattern = "responsive-grid" +complexity = "basic" +features = ["scrollable content", "responsive columns", "fixed header"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/rotated_box/basic/main.py b/sdk/python/examples/controls/core/rotated_box/basic/main.py new file mode 100644 index 0000000000..3b93edb5cc --- /dev/null +++ b/sdk/python/examples/controls/core/rotated_box/basic/main.py @@ -0,0 +1,98 @@ +import flet as ft + + +def _demo_control(content: ft.Control) -> ft.Container: + return ft.Container( + padding=10, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + content=content, + ) + + +def _lane(title: str, controls: list[ft.Control]) -> ft.Container: + return ft.Container( + width=540, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=12, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(title, size=16, weight=ft.FontWeight.BOLD), + ft.Divider(height=1), + ft.Row( + spacing=14, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=controls, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.padding = 24 + page.scroll = ft.ScrollMode.AUTO + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "RotatedBox rotates before layout. Compare occupied " + "space below:", + size=16, + weight=ft.FontWeight.W_500, + ), + ft.Column( + spacing=16, + controls=[ + _lane( + "Normal controls", + [ + _demo_control(ft.Text("Text", size=26)), + _demo_control( + ft.ProgressBar( + width=170, value=0.65, color=ft.Colors.GREEN + ) + ), + _demo_control(ft.Button("Button")), + ], + ), + _lane( + "RotatedBox quarter_turns=1", + [ + _demo_control( + ft.RotatedBox( + quarter_turns=1, + content=ft.Text("Text", size=26), + ) + ), + _demo_control( + ft.RotatedBox( + quarter_turns=1, + content=ft.ProgressBar( + width=170, + value=0.65, + color=ft.Colors.GREEN, + ), + ) + ), + _demo_control( + ft.RotatedBox( + quarter_turns=1, + content=ft.Button("Button"), + ) + ), + ], + ), + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/rotated_box/basic/pyproject.toml b/sdk/python/examples/controls/core/rotated_box/basic/pyproject.toml new file mode 100644 index 0000000000..302a2e7cf6 --- /dev/null +++ b/sdk/python/examples/controls/core/rotated_box/basic/pyproject.toml @@ -0,0 +1,39 @@ +[project] +name = "rotated-box-basic" +version = "1.0.0" +description = "Compares normal layouted controls with quarter_turns RotatedBox rendering." +requires-python = ">=3.10" +keywords = ["rotated box", "layout", "rotation", "transform", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/RotatedBox"] + +[tool.flet.metadata] +title = "Basic" +controls = [ + "SafeArea", + "Column", + "Row", + "Container", + "RotatedBox", + "Text", + "Button", + "ProgressBar", +] +layout_pattern = "compare-layout" +complexity = "basic" +features = [ + "rotation before layout", + "visual space comparison", + "before-after examples", +] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/row/alignment/main.py b/sdk/python/examples/controls/core/row/alignment/main.py new file mode 100644 index 0000000000..270670e0e3 --- /dev/null +++ b/sdk/python/examples/controls/core/row/alignment/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +@ft.control +class RowWithAlignment(ft.Column): + alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.START + + def init(self): + self.controls = [ + ft.Text(str(self.alignment), size=16), + ft.Container( + bgcolor=ft.Colors.AMBER_100, + content=ft.Row( + alignment=self.alignment, + controls=self.generate_items(3), + ), + ), + ] + + @staticmethod + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER_500, + ) + for i in range(1, count + 1) + ] + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + page.add( + ft.SafeArea( + content=ft.Column( + scroll=ft.ScrollMode.AUTO, + controls=[ + RowWithAlignment(alignment=ft.MainAxisAlignment.START), + RowWithAlignment(alignment=ft.MainAxisAlignment.CENTER), + RowWithAlignment(alignment=ft.MainAxisAlignment.END), + RowWithAlignment(alignment=ft.MainAxisAlignment.SPACE_BETWEEN), + RowWithAlignment(alignment=ft.MainAxisAlignment.SPACE_AROUND), + RowWithAlignment(alignment=ft.MainAxisAlignment.SPACE_EVENLY), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/row/alignment/pyproject.toml b/sdk/python/examples/controls/core/row/alignment/pyproject.toml new file mode 100644 index 0000000000..c5be8678a2 --- /dev/null +++ b/sdk/python/examples/controls/core/row/alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-alignment" +version = "1.0.0" +description = "Row main-axis alignment modes demonstrated side by side." +requires-python = ">=3.10" +keywords = ["row", "layout", "alignment", "mainaxisalignment", "scroll"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row alignment" +controls = ["Column", "Row", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["main axis alignment", "layout comparison", "vertical scrolling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/row/media/alignment.png b/sdk/python/examples/controls/core/row/media/alignment.png new file mode 100644 index 0000000000..98d6d3adee Binary files /dev/null and b/sdk/python/examples/controls/core/row/media/alignment.png differ diff --git a/sdk/python/examples/controls/core/row/media/spacing.gif b/sdk/python/examples/controls/core/row/media/spacing.gif new file mode 100644 index 0000000000..a05a7a3f93 Binary files /dev/null and b/sdk/python/examples/controls/core/row/media/spacing.gif differ diff --git a/sdk/python/examples/controls/core/row/media/vertical_alignment.png b/sdk/python/examples/controls/core/row/media/vertical_alignment.png new file mode 100644 index 0000000000..50778f83a2 Binary files /dev/null and b/sdk/python/examples/controls/core/row/media/vertical_alignment.png differ diff --git a/sdk/python/examples/controls/core/row/media/wrap.gif b/sdk/python/examples/controls/core/row/media/wrap.gif new file mode 100644 index 0000000000..6846bb2efd Binary files /dev/null and b/sdk/python/examples/controls/core/row/media/wrap.gif differ diff --git a/sdk/python/examples/controls/core/row/spacing/main.py b/sdk/python/examples/controls/core/row/spacing/main.py new file mode 100644 index 0000000000..d0f30660a0 --- /dev/null +++ b/sdk/python/examples/controls/core/row/spacing/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER, + border_radius=ft.BorderRadius.all(5), + ) + for i in range(1, count + 1) + ] + + def handle_slider_change(e: ft.Event[ft.Slider]): + row.spacing = int(e.control.value) + row.update() + + row = ft.Row(spacing=0, scroll=ft.ScrollMode.AUTO, controls=generate_items(10)) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text("Spacing between items"), + ft.Slider( + key="slider", + min=0, + max=50, + divisions=50, + value=0, + label="{value}", + on_change=handle_slider_change, + ), + ] + ), + row, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/row/spacing/pyproject.toml b/sdk/python/examples/controls/core/row/spacing/pyproject.toml new file mode 100644 index 0000000000..984bfb5dab --- /dev/null +++ b/sdk/python/examples/controls/core/row/spacing/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-spacing" +version = "1.0.0" +description = "Adjust row spacing interactively with a slider." +requires-python = ">=3.10" +keywords = ["row", "layout", "spacing", "slider", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row spacing" +controls = ["Column", "Row", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["slider-driven spacing", "dynamic layout updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/row/vertical_alignment/main.py b/sdk/python/examples/controls/core/row/vertical_alignment/main.py new file mode 100644 index 0000000000..8a6c45df27 --- /dev/null +++ b/sdk/python/examples/controls/core/row/vertical_alignment/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +@ft.control +class RowWithVerticalAlignment(ft.Column): + alignment: ft.CrossAxisAlignment = ft.CrossAxisAlignment.START + + def init(self): + self.controls = [ + ft.Text(str(self.alignment), size=16), + ft.Container( + bgcolor=ft.Colors.AMBER_100, + height=150, + content=ft.Row( + vertical_alignment=self.alignment, + controls=self.generate_items(3), + ), + ), + ] + + @staticmethod + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER_500, + ) + for i in range(1, count + 1) + ] + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + RowWithVerticalAlignment(alignment=ft.CrossAxisAlignment.START), + RowWithVerticalAlignment(alignment=ft.CrossAxisAlignment.CENTER), + RowWithVerticalAlignment(alignment=ft.CrossAxisAlignment.END), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/row/vertical_alignment/pyproject.toml b/sdk/python/examples/controls/core/row/vertical_alignment/pyproject.toml new file mode 100644 index 0000000000..a64f580540 --- /dev/null +++ b/sdk/python/examples/controls/core/row/vertical_alignment/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-vertical-alignment" +version = "1.0.0" +description = "Row cross-axis alignment modes with visual comparison." +requires-python = ">=3.10" +keywords = ["row", "layout", "crossaxisalignment", "alignment"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row vertical alignment" +controls = ["Column", "Row", "Container", "Text"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["cross axis alignment", "layout comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/row/wrap/main.py b/sdk/python/examples/controls/core/row/wrap/main.py new file mode 100644 index 0000000000..5102616595 --- /dev/null +++ b/sdk/python/examples/controls/core/row/wrap/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + def generate_items(count: int): + return [ + ft.Container( + content=ft.Text(value=str(i)), + alignment=ft.Alignment.CENTER, + width=50, + height=50, + bgcolor=ft.Colors.AMBER, + border_radius=ft.BorderRadius.all(5), + ) + for i in range(1, count + 1) + ] + + def handle_slider_change(e: ft.Event[ft.Slider]): + row.width = float(e.control.value) + row.update() + + row = ft.Row( + wrap=True, + spacing=10, + run_spacing=10, + width=page.window.width, + controls=generate_items(30), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + ft.Text( + "Change the row width to see how child items wrap " + "onto multiple rows:" + ), + ft.Slider( + min=0, + max=page.window.width, + divisions=20, + value=page.window.width, + label="{value}", + on_change=handle_slider_change, + ), + ] + ), + row, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/row/wrap/pyproject.toml b/sdk/python/examples/controls/core/row/wrap/pyproject.toml new file mode 100644 index 0000000000..37aefedc32 --- /dev/null +++ b/sdk/python/examples/controls/core/row/wrap/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "row-wrap" +version = "1.0.0" +description = "Row wrapping behavior controlled by dynamic width." +requires-python = ">=3.10" +keywords = ["row", "layout", "wrap", "slider", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Row"] + +[tool.flet.metadata] +title = "Row wrapping" +controls = ["Column", "Row", "Container", "Text", "Slider"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["wrap behavior", "width-driven layout", "slider interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/safe_area/basic/main.py b/sdk/python/examples/controls/core/safe_area/basic/main.py new file mode 100644 index 0000000000..85bf4d58ff --- /dev/null +++ b/sdk/python/examples/controls/core/safe_area/basic/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +class State: + counter = 0 + + +def main(page: ft.Page): + state = State() + message = ft.Text("0", size=50) + + def handle_button_click(e: ft.Event[ft.FloatingActionButton]): + state.counter += 1 + message.value = str(state.counter) + message.update() + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, + on_click=handle_button_click, + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + alignment=ft.Alignment.CENTER, + content=message, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/safe_area/basic/pyproject.toml b/sdk/python/examples/controls/core/safe_area/basic/pyproject.toml new file mode 100644 index 0000000000..d4fcdd2bdf --- /dev/null +++ b/sdk/python/examples/controls/core/safe_area/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "safe-area-basic" +version = "1.0.0" +description = "Keep centered content inside device safe insets while updating a counter." +requires-python = ">=3.10" +keywords = ["safearea", "layout", "counter", "floatingactionbutton", "mobile"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/SafeArea"] + +[tool.flet.metadata] +title = "SafeArea basic" +controls = ["SafeArea", "Container", "Text", "FloatingActionButton"] +layout_pattern = "centered-single-action" +complexity = "basic" +features = ["safe insets", "floating action button", "counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/screenshot/taking_screenshot/main.py b/sdk/python/examples/controls/core/screenshot/taking_screenshot/main.py new file mode 100644 index 0000000000..c61bca220b --- /dev/null +++ b/sdk/python/examples/controls/core/screenshot/taking_screenshot/main.py @@ -0,0 +1,35 @@ +from pathlib import Path + +import flet as ft +from flet.utils.files import get_current_script_dir + + +def main(page: ft.Page): + async def take_screenshot(e: ft.Event[ft.Button]): + image = await scr.capture() + with open(Path(get_current_script_dir(), "screenshot.png"), "wb") as f: + f.write(image) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + scr := ft.Screenshot( + content=ft.Container( + padding=10, + content=ft.Button( + "Hello, world!", + bgcolor=ft.Colors.BLUE, + elevation=10, + ), + ) + ), + ft.Button("Take screenshot", on_click=take_screenshot), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/screenshot/taking_screenshot/pyproject.toml b/sdk/python/examples/controls/core/screenshot/taking_screenshot/pyproject.toml new file mode 100644 index 0000000000..d43f346b42 --- /dev/null +++ b/sdk/python/examples/controls/core/screenshot/taking_screenshot/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "screenshot-taking-screenshot" +version = "1.0.0" +description = "Capture a Screenshot control asynchronously and save the image to a file." +requires-python = ">=3.10" +keywords = ["screenshot", "capture", "button", "async", "file"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Screenshot"] + +[tool.flet.metadata] +title = "Taking screenshot" +controls = ["Screenshot", "Container", "Button", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["async capture", "save to file", "button interaction"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/screenshot/taking_screenshot/screenshot.png b/sdk/python/examples/controls/core/screenshot/taking_screenshot/screenshot.png new file mode 100644 index 0000000000..9000215d7f Binary files /dev/null and b/sdk/python/examples/controls/core/screenshot/taking_screenshot/screenshot.png differ diff --git a/sdk/python/examples/controls/core/semantics/basic/main.py b/sdk/python/examples/controls/core/semantics/basic/main.py new file mode 100644 index 0000000000..2626ace4f3 --- /dev/null +++ b/sdk/python/examples/controls/core/semantics/basic/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_gain_accessibility_focus(e: ft.Event[ft.Semantics]): + print("focus gained") + + def handle_lose_accessibility_focus(e: ft.Event[ft.Semantics]): + print("focus lost") + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Semantics( + label="Input your occupation", + on_did_gain_accessibility_focus=handle_gain_accessibility_focus, + on_did_lose_accessibility_focus=handle_lose_accessibility_focus, + content=ft.TextField( + label="Occupation", + hint_text="Use 20 words or less", + value="What is your occupation?", + ), + ), + ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/semantics/basic/pyproject.toml b/sdk/python/examples/controls/core/semantics/basic/pyproject.toml new file mode 100644 index 0000000000..49f5044254 --- /dev/null +++ b/sdk/python/examples/controls/core/semantics/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "semantics-basic" +version = "1.0.0" +description = "Attach semantics labels and accessibility focus events to a text field." +requires-python = ">=3.10" +keywords = ["semantics", "accessibility", "textfield", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Accessibility"] + +[tool.flet.metadata] +title = "Semantics basic" +controls = ["Semantics", "TextField", "Icon", "Column", "SafeArea"] +layout_pattern = "form-field" +complexity = "basic" +features = ["accessibility labels", "focus events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/shader_mask/fade_out_image_bottom/main.py b/sdk/python/examples/controls/core/shader_mask/fade_out_image_bottom/main.py new file mode 100644 index 0000000000..b8bd1b39b3 --- /dev/null +++ b/sdk/python/examples/controls/core/shader_mask/fade_out_image_bottom/main.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.ShaderMask( + content=ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==" + ), + blend_mode=ft.BlendMode.DST_IN, + border_radius=10, + shader=ft.LinearGradient( + begin=ft.Alignment.TOP_CENTER, + end=ft.Alignment.BOTTOM_CENTER, + colors=[ft.Colors.BLACK, ft.Colors.TRANSPARENT], + stops=[0.5, 1.0], + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/shader_mask/fade_out_image_bottom/pyproject.toml b/sdk/python/examples/controls/core/shader_mask/fade_out_image_bottom/pyproject.toml new file mode 100644 index 0000000000..0f5b6ef4ed --- /dev/null +++ b/sdk/python/examples/controls/core/shader_mask/fade_out_image_bottom/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shader-mask-fade-out-image-bottom" +version = "1.0.0" +description = "Fade the bottom of an image using a linear ShaderMask transparency gradient." +requires-python = ">=3.10" +keywords = ["shadermask", "image", "lineargradient", "fade", "transparency"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/ShaderMask"] + +[tool.flet.metadata] +title = "ShaderMask fade out image bottom" +controls = ["ShaderMask", "Image", "Row", "SafeArea"] +layout_pattern = "single-focus" +complexity = "basic" +features = ["linear gradient", "image fade", "blend mode"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/shader_mask/linear_and_radial_gradients/main.py b/sdk/python/examples/controls/core/shader_mask/linear_and_radial_gradients/main.py new file mode 100644 index 0000000000..4cc30d5adf --- /dev/null +++ b/sdk/python/examples/controls/core/shader_mask/linear_and_radial_gradients/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.ShaderMask( + blend_mode=ft.BlendMode.COLOR_BURN, + shader=ft.RadialGradient( + center=ft.Alignment.TOP_LEFT, + radius=1.0, + colors=[ft.Colors.YELLOW, ft.Colors.DEEP_ORANGE_900], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", + width=300, + height=300, + fit=ft.BoxFit.FILL, + ), + ), + ft.ShaderMask( + blend_mode=ft.BlendMode.DST_IN, + shader=ft.LinearGradient( + begin=ft.Alignment.TOP_CENTER, + end=ft.Alignment.BOTTOM_CENTER, + colors=[ft.Colors.BLACK, ft.Colors.TRANSPARENT], + stops=[0.5, 1.0], + ), + content=ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==" + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/shader_mask/linear_and_radial_gradients/pyproject.toml b/sdk/python/examples/controls/core/shader_mask/linear_and_radial_gradients/pyproject.toml new file mode 100644 index 0000000000..a51447c94a --- /dev/null +++ b/sdk/python/examples/controls/core/shader_mask/linear_and_radial_gradients/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shader-mask-linear-and-radial-gradients" +version = "1.0.0" +description = "Compare radial and linear ShaderMask gradients applied to images." +requires-python = ">=3.10" +keywords = ["shadermask", "image", "gradients", "lineargradient", "radialgradient"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/ShaderMask"] + +[tool.flet.metadata] +title = "ShaderMask linear and radial gradients" +controls = ["ShaderMask", "Image", "Row", "SafeArea"] +layout_pattern = "comparison-grid" +complexity = "basic" +features = ["linear gradient", "radial gradient", "image masking"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/shader_mask/media/fade_out_image_bottom.png b/sdk/python/examples/controls/core/shader_mask/media/fade_out_image_bottom.png new file mode 100644 index 0000000000..a9921a0805 Binary files /dev/null and b/sdk/python/examples/controls/core/shader_mask/media/fade_out_image_bottom.png differ diff --git a/sdk/python/examples/controls/core/shader_mask/media/pink_radial_glow.png b/sdk/python/examples/controls/core/shader_mask/media/pink_radial_glow.png new file mode 100644 index 0000000000..b48de21ece Binary files /dev/null and b/sdk/python/examples/controls/core/shader_mask/media/pink_radial_glow.png differ diff --git a/sdk/python/examples/controls/core/shader_mask/pink_radial_glow/main.py b/sdk/python/examples/controls/core/shader_mask/pink_radial_glow/main.py new file mode 100644 index 0000000000..2368f7d093 --- /dev/null +++ b/sdk/python/examples/controls/core/shader_mask/pink_radial_glow/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", + width=300, + height=300, + fit=ft.BoxFit.FILL, + ), + ft.ShaderMask( + blend_mode=ft.BlendMode.MULTIPLY, + shader=ft.RadialGradient( + center=ft.Alignment.CENTER, + radius=0.5, + colors=[ft.Colors.WHITE, ft.Colors.PINK], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", + width=300, + height=300, + fit=ft.BoxFit.FILL, + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/shader_mask/pink_radial_glow/pyproject.toml b/sdk/python/examples/controls/core/shader_mask/pink_radial_glow/pyproject.toml new file mode 100644 index 0000000000..59632826e0 --- /dev/null +++ b/sdk/python/examples/controls/core/shader_mask/pink_radial_glow/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shader-mask-pink-radial-glow" +version = "1.0.0" +description = "Apply a radial ShaderMask glow to an image using a burn blend mode." +requires-python = ">=3.10" +keywords = ["shadermask", "image", "radialgradient", "blendmode", "visual-effect"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/ShaderMask"] + +[tool.flet.metadata] +title = "ShaderMask pink radial glow" +controls = ["ShaderMask", "Image", "Row", "SafeArea"] +layout_pattern = "single-focus" +complexity = "basic" +features = ["radial gradient", "blend mode", "image masking"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/shimmer/basic/main.py b/sdk/python/examples/controls/core/shimmer/basic/main.py new file mode 100644 index 0000000000..d1bc09c7e2 --- /dev/null +++ b/sdk/python/examples/controls/core/shimmer/basic/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Shimmer( + base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), + highlight_color=ft.Colors.WHITE, + content=ft.Column( + controls=[ + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ], + ), + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/shimmer/basic/pyproject.toml b/sdk/python/examples/controls/core/shimmer/basic/pyproject.toml new file mode 100644 index 0000000000..a5684337c7 --- /dev/null +++ b/sdk/python/examples/controls/core/shimmer/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shimmer-basic" +version = "1.0.0" +description = "Show a basic Shimmer loading effect over stacked placeholder blocks." +requires-python = ">=3.10" +keywords = ["shimmer", "loading", "placeholder", "animation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/Shimmer"] + +[tool.flet.metadata] +title = "Shimmer basic" +controls = ["Shimmer", "Column", "Container", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["loading placeholders", "animated highlight"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/shimmer/basic_placeholder/main.py b/sdk/python/examples/controls/core/shimmer/basic_placeholder/main.py new file mode 100644 index 0000000000..d1b3132b52 --- /dev/null +++ b/sdk/python/examples/controls/core/shimmer/basic_placeholder/main.py @@ -0,0 +1,70 @@ +import flet as ft + + +def _line(width: int, height: int = 12) -> ft.Control: + return ft.Container( + width=width, + height=height, + bgcolor=ft.Colors.GREY_400, + border_radius=ft.BorderRadius.all(height), + ) + + +def _placeholder_tile() -> ft.Control: + return ft.Container( + padding=ft.Padding.all(16), + bgcolor=ft.Colors.with_opacity(0.3, ft.Colors.WHITE), + border_radius=ft.BorderRadius.all(20), + content=ft.Row( + spacing=16, + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Container( + width=48, + height=48, + bgcolor=ft.Colors.with_opacity(0.5, ft.Colors.GREY_400), + border_radius=ft.BorderRadius.all(24), + content=ft.Icon(ft.Icons.PERSON, color=ft.Colors.GREY_500), + ), + ft.Column( + expand=True, + spacing=10, + controls=[ + _line(160), + _line(120), + ft.Row( + spacing=10, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[_line(70, 10), _line(90, 10)], + ), + ], + ), + ft.Container( + width=32, + height=32, + bgcolor=ft.Colors.GREY_200, + border_radius=ft.BorderRadius.all(16), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.title = "Shimmer - loading placeholders" + + page.add( + ft.SafeArea( + content=ft.Shimmer( + base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), + highlight_color=ft.Colors.WHITE, + content=ft.Column( + controls=[_placeholder_tile() for _ in range(3)], + ), + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/shimmer/basic_placeholder/pyproject.toml b/sdk/python/examples/controls/core/shimmer/basic_placeholder/pyproject.toml new file mode 100644 index 0000000000..e23a646165 --- /dev/null +++ b/sdk/python/examples/controls/core/shimmer/basic_placeholder/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shimmer-basic-placeholder" +version = "1.0.0" +description = "Animate card-style loading placeholders with a Shimmer effect." +requires-python = ">=3.10" +keywords = ["shimmer", "placeholder", "loading", "card", "skeleton"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/Shimmer"] + +[tool.flet.metadata] +title = "Shimmer basic placeholder" +controls = ["Shimmer", "Column", "Row", "Container", "Icon", "SafeArea"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["skeleton placeholders", "animated highlight", "card layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/shimmer/custom_gradient/main.py b/sdk/python/examples/controls/core/shimmer/custom_gradient/main.py new file mode 100644 index 0000000000..8ac6e48b0a --- /dev/null +++ b/sdk/python/examples/controls/core/shimmer/custom_gradient/main.py @@ -0,0 +1,69 @@ +import flet as ft + + +def _stat_block(title: str, subtitle: str) -> ft.Control: + def metric(width: int, height: int = 14) -> ft.Control: + return ft.Container( + width=width, + height=height, + bgcolor=ft.Colors.WHITE, + opacity=0.6, + border_radius=ft.BorderRadius.all(height), + ) + + return ft.Container( + width=200, + padding=ft.Padding.all(20), + bgcolor=ft.Colors.with_opacity(0.1, ft.Colors.BLACK), + border_radius=ft.BorderRadius.all(24), + content=ft.Column( + spacing=16, + controls=[ + metric(140), + ft.Row(spacing=10, controls=[metric(60, 10), metric(90, 10)]), + ft.Container( + border_radius=ft.BorderRadius.all(16), + bgcolor=ft.Colors.WHITE, + opacity=0.35, + ), + ft.Column(spacing=8, controls=[metric(120, 12), metric(160, 12)]), + ft.Text(title, weight=ft.FontWeight.W_600), + ft.Text(subtitle, size=12), + ], + ), + ) + + +def main(page: ft.Page): + page.title = "Shimmer - custom gradients" + page.bgcolor = "#0e0e18" + accent = ft.LinearGradient( + begin=ft.Alignment(-1.0, -0.5), + end=ft.Alignment(1.0, 0.5), + colors=[ + ft.Colors.PURPLE, + ft.Colors.PURPLE, + ft.Colors.AMBER_200, + ft.Colors.PURPLE, + ft.Colors.PURPLE, + ], + stops=[0.0, 0.35, 0.5, 0.65, 1.0], + ) + + cards = ft.Row( + wrap=True, + controls=[ + ft.Shimmer( + gradient=accent, + direction=ft.ShimmerDirection.TTB, + period=2200, + content=_stat_block("Recent activity", "Smooth top-to-bottom sweep"), + ), + ], + ) + + page.add(ft.SafeArea(content=cards)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/shimmer/custom_gradient/pyproject.toml b/sdk/python/examples/controls/core/shimmer/custom_gradient/pyproject.toml new file mode 100644 index 0000000000..ec46c8b0d9 --- /dev/null +++ b/sdk/python/examples/controls/core/shimmer/custom_gradient/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "shimmer-custom-gradient" +version = "1.0.0" +description = "Use a custom gradient Shimmer animation over a dashboard-style stat card." +requires-python = ">=3.10" +keywords = ["shimmer", "gradient", "animation", "dashboard", "card"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Effects/Shimmer"] + +[tool.flet.metadata] +title = "Shimmer custom gradient" +controls = ["Shimmer", "Row", "Column", "Container", "Text", "SafeArea"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["custom gradient", "animated highlight", "dashboard card"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/stack/absolute_positioning/main.py b/sdk/python/examples/controls/core/stack/absolute_positioning/main.py new file mode 100644 index 0000000000..16bf50da08 --- /dev/null +++ b/sdk/python/examples/controls/core/stack/absolute_positioning/main.py @@ -0,0 +1,67 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Container( + border_radius=8, + padding=5, + width=200, + height=200, + bgcolor=ft.Colors.BLACK, + content=ft.Stack( + controls=[ + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.RED, + border_radius=5, + ), + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.YELLOW, + border_radius=5, + right=0, + ), + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.BLUE, + border_radius=5, + right=0, + bottom=0, + ), + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.GREEN, + border_radius=5, + left=0, + bottom=0, + ), + ft.Column( + left=85, + top=85, + controls=[ + ft.Container( + width=20, + height=20, + bgcolor=ft.Colors.PURPLE, + border_radius=5, + ) + ], + ), + ] + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/stack/absolute_positioning/pyproject.toml b/sdk/python/examples/controls/core/stack/absolute_positioning/pyproject.toml new file mode 100644 index 0000000000..19508589b2 --- /dev/null +++ b/sdk/python/examples/controls/core/stack/absolute_positioning/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "stack-absolute-positioning" +version = "1.0.0" +description = "Places colored containers at fixed corners and center positions inside a Stack." +requires-python = ">=3.10" +keywords = ["stack", "layout", "positioning", "absolute", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Stack"] + +[tool.flet.metadata] +title = "Absolute positioning" +controls = ["SafeArea", "Container", "Stack", "Column"] +layout_pattern = "center-stage" +complexity = "basic" +features = ["absolute positioning"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/stack/media/absolute_positioning.png b/sdk/python/examples/controls/core/stack/media/absolute_positioning.png new file mode 100644 index 0000000000..0ddf3fd794 Binary files /dev/null and b/sdk/python/examples/controls/core/stack/media/absolute_positioning.png differ diff --git a/sdk/python/examples/controls/core/stack/media/online_avatar.png b/sdk/python/examples/controls/core/stack/media/online_avatar.png new file mode 100644 index 0000000000..e8dd15ab4a Binary files /dev/null and b/sdk/python/examples/controls/core/stack/media/online_avatar.png differ diff --git a/sdk/python/examples/controls/core/stack/media/text_on_image.png b/sdk/python/examples/controls/core/stack/media/text_on_image.png new file mode 100644 index 0000000000..dc4dae269f Binary files /dev/null and b/sdk/python/examples/controls/core/stack/media/text_on_image.png differ diff --git a/sdk/python/examples/controls/core/stack/online_avatar/main.py b/sdk/python/examples/controls/core/stack/online_avatar/main.py new file mode 100644 index 0000000000..d78318471a --- /dev/null +++ b/sdk/python/examples/controls/core/stack/online_avatar/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + width=40, + height=40, + controls=[ + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" + ), + ft.Container( + alignment=ft.Alignment.BOTTOM_LEFT, + content=ft.CircleAvatar(bgcolor=ft.Colors.GREEN, radius=5), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/stack/online_avatar/pyproject.toml b/sdk/python/examples/controls/core/stack/online_avatar/pyproject.toml new file mode 100644 index 0000000000..6eb6c68f12 --- /dev/null +++ b/sdk/python/examples/controls/core/stack/online_avatar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "stack-online-avatar" +version = "1.0.0" +description = "Overlays an online-status badge on top of a profile avatar using Stack." +requires-python = ">=3.10" +keywords = ["stack", "avatar", "status", "overlay", "badge"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Stack"] + +[tool.flet.metadata] +title = "Online avatar" +controls = ["SafeArea", "Stack", "CircleAvatar", "Container"] +layout_pattern = "overlay" +complexity = "basic" +features = ["status indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/stack/text_on_image/main.py b/sdk/python/examples/controls/core/stack/text_on_image/main.py new file mode 100644 index 0000000000..d86b58f4d5 --- /dev/null +++ b/sdk/python/examples/controls/core/stack/text_on_image/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + width=300, + height=300, + controls=[ + ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", + width=300, + height=300, + fit=ft.BoxFit.CONTAIN, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + value="Image title", + color=ft.Colors.SURFACE_TINT, + size=40, + weight=ft.FontWeight.BOLD, + opacity=0.5, + ) + ], + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/stack/text_on_image/pyproject.toml b/sdk/python/examples/controls/core/stack/text_on_image/pyproject.toml new file mode 100644 index 0000000000..c4860cfeb3 --- /dev/null +++ b/sdk/python/examples/controls/core/stack/text_on_image/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "stack-text-on-image" +version = "1.0.0" +description = "Layers a centered title over a base64-backed image inside a Stack." +requires-python = ">=3.10" +keywords = ["stack", "image", "text", "overlay", "base64"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Stack"] + +[tool.flet.metadata] +title = "Text on image" +controls = ["SafeArea", "Stack", "Image", "Row", "Text"] +layout_pattern = "overlay" +complexity = "basic" +features = ["text overlay"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/text/custom_styles/main.py b/sdk/python/examples/controls/core/text/custom_styles/main.py new file mode 100644 index 0000000000..ef783de13a --- /dev/null +++ b/sdk/python/examples/controls/core/text/custom_styles/main.py @@ -0,0 +1,125 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text custom styles" + page.scroll = ft.ScrollMode.ADAPTIVE + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Size 10", size=10), + ft.Text( + "Size 30, Italic", + size=30, + color=ft.Colors.PINK_600, + italic=True, + ), + ft.Text( + value="Size 40, w100", + size=40, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.BLUE_600, + weight=ft.FontWeight.W_100, + ), + ft.Text( + value="Size 50, Normal", + size=50, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.ORANGE_800, + weight=ft.FontWeight.NORMAL, + ), + ft.Text( + value="Size 60, Bold, Italic", + size=50, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.GREEN_700, + weight=ft.FontWeight.BOLD, + italic=True, + ), + ft.Text( + value="Size 70, w900, selectable", + size=70, + weight=ft.FontWeight.W_900, + selectable=True, + ), + ft.Text( + value="Limit long text to 1 line with ellipsis", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text( + value=( + "Proin rutrum, purus sit amet elementum volutpat, nunc " + "lacus vulputate orci, cursus ultrices neque dui quis " + "purus. Ut ultricies purus nec nibh bibendum, eget " + "vestibulum metus various. Duis convallis maximus justo, " + "eu rutrum libero maximus id. Donec ullamcorper arcu in " + "sapien molestie, non pellentesque tellus pellentesque. " + "Nulla nec tristique ex. Maecenas euismod nisl enim, a " + "convallis arcu laoreet at. Ut at tortor finibus, rutrum " + "massa sit amet, pulvinar velit. Phasellus diam lorem, " + "viverra vitae leo vitae, consequat suscipit lorem." + ), + max_lines=1, + overflow=ft.TextOverflow.ELLIPSIS, + ), + ft.Text( + value="Limit long text to 2 lines and fading", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text( + value=( + "Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit. Curabitur quis nibh vitae purus consectetur " + "facilisis sed vitae ipsum. Quisque faucibus sed nulla " + "placerat sagittis. Phasellus condimentum risus vitae " + "nulla vestibulum auctor. Curabitur scelerisque, nibh " + "eget imperdiet consequat, odio ante tempus diam, sed " + "volutpat nisl erat eget turpis. Sed viverra, diam sit " + "amet blandit vulputate, mi tellus dapibus lorem, vitae " + "vehicula diam mauris placerat diam. Morbi sit amet " + "pretium turpis, et consequat ligula. Nulla velit sem, " + "suscipit sit amet dictum non, tincidunt sed nulla. " + "Aenean pellentesque odio porttitor sagittis aliquam. " + "Name various at metus vitae vulputate. Praesent " + "faucibus nibh lorem, eu pretium dolor dictum nec. " + "Phasellus eget dui laoreet, viverra magna vitae, " + "pellentesque diam." + ), + max_lines=2, + ), + ft.Text( + value="Limit the width and height of long text", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text( + value=( + "Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit. Curabitur quis nibh vitae purus consectetur " + "facilisis sed vitae ipsum. Quisque faucibus sed nulla " + "placerat sagittis. Phasellus condimentum risus vitae " + "nulla vestibulum auctor. Curabitur scelerisque, nibh " + "eget imperdiet consequat, odio ante tempus diam, sed " + "volutpat nisl erat eget turpis. Sed viverra, diam sit " + "amet blandit vulputate, mi tellus dapibus lorem, vitae " + "vehicula diam mauris placerat diam. Morbi sit amet " + "pretium turpis, et consequat ligula. Nulla velit sem, " + "suscipit sit amet dictum non, tincidunt sed nulla. " + "Aenean pellentesque odio porttitor sagittis aliquam. " + "Name various at metus vitae vulputate. Praesent " + "faucibus nibh lorem, eu pretium dolor dictum nec. " + "Phasellus eget dui laoreet, viverra magna vitae, " + "pellentesque diam." + ), + width=700, + height=100, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/text/custom_styles/pyproject.toml b/sdk/python/examples/controls/core/text/custom_styles/pyproject.toml new file mode 100644 index 0000000000..f79c371dd4 --- /dev/null +++ b/sdk/python/examples/controls/core/text/custom_styles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-custom-styles" +version = "1.0.0" +description = "Demonstrates Text size, color, weight, selection, and overflow styling variations." +requires-python = ">=3.10" +keywords = ["text", "styles", "typography", "overflow", "selection"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Text"] + +[tool.flet.metadata] +title = "Custom text styles" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "stacked-content" +complexity = "basic" +features = ["custom text styling", "overflow handling", "selectable text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/text/media/custom_styles.gif b/sdk/python/examples/controls/core/text/media/custom_styles.gif new file mode 100644 index 0000000000..5339429ef9 Binary files /dev/null and b/sdk/python/examples/controls/core/text/media/custom_styles.gif differ diff --git a/sdk/python/examples/controls/core/text/media/rich_text_basic.png b/sdk/python/examples/controls/core/text/media/rich_text_basic.png new file mode 100644 index 0000000000..818b09d0d2 Binary files /dev/null and b/sdk/python/examples/controls/core/text/media/rich_text_basic.png differ diff --git a/sdk/python/examples/controls/core/text/media/rich_text_border_stroke.png b/sdk/python/examples/controls/core/text/media/rich_text_border_stroke.png new file mode 100644 index 0000000000..53e17a24ac Binary files /dev/null and b/sdk/python/examples/controls/core/text/media/rich_text_border_stroke.png differ diff --git a/sdk/python/examples/controls/core/text/media/rich_text_gradient.png b/sdk/python/examples/controls/core/text/media/rich_text_gradient.png new file mode 100644 index 0000000000..573d91b2bd Binary files /dev/null and b/sdk/python/examples/controls/core/text/media/rich_text_gradient.png differ diff --git a/sdk/python/examples/controls/core/text/media/text_theme_styles.png b/sdk/python/examples/controls/core/text/media/text_theme_styles.png new file mode 100644 index 0000000000..4e0c6e6bb7 Binary files /dev/null and b/sdk/python/examples/controls/core/text/media/text_theme_styles.png differ diff --git a/sdk/python/examples/controls/core/text/media/variable_font_weight.gif b/sdk/python/examples/controls/core/text/media/variable_font_weight.gif new file mode 100644 index 0000000000..5fadf0ca54 Binary files /dev/null and b/sdk/python/examples/controls/core/text/media/variable_font_weight.gif differ diff --git a/sdk/python/examples/controls/core/text/rich_text_basic/main.py b/sdk/python/examples/controls/core/text/rich_text_basic/main.py new file mode 100644 index 0000000000..d60c089721 --- /dev/null +++ b/sdk/python/examples/controls/core/text/rich_text_basic/main.py @@ -0,0 +1,123 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Plain text with default style"), + ft.Text( + "Selectable plain text with default style", + selectable=True, + ), + ft.Text( + value="Some text", + selectable=True, + size=30, + spans=[ + ft.TextSpan( + text="here goes italic", + style=ft.TextStyle( + italic=True, + size=20, + color=ft.Colors.GREEN, + ), + spans=[ + ft.TextSpan( + text="bold and italic", + style=ft.TextStyle(weight=ft.FontWeight.BOLD), + ), + ft.TextSpan( + text="just italic", + spans=[ + ft.TextSpan( + "smaller italic", + ft.TextStyle(size=15), + ) + ], + ), + ], + ) + ], + ), + ft.Text( + disabled=False, + spans=[ + ft.TextSpan( + text="underlined and clickable", + style=ft.TextStyle( + decoration=ft.TextDecoration.UNDERLINE + ), + on_click=lambda e: print(f"Clicked span: {e.control}"), + on_enter=lambda e: print(f"Entered span: {e.control}"), + on_exit=lambda e: print(f"Exited span: {e.control}"), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="underlined red wavy", + style=ft.TextStyle( + decoration=ft.TextDecoration.UNDERLINE, + decoration_color=ft.Colors.RED, + decoration_style=ft.TextDecorationStyle.WAVY, + ), + on_enter=lambda e: print(f"Entered span: {e.control}"), + on_exit=lambda e: print(f"Exited span: {e.control}"), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="overlined blue", + style=ft.TextStyle( + decoration=ft.TextDecoration.OVERLINE, + decoration_color="blue", + ), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="overlined and underlined", + style=ft.TextStyle( + decoration=ft.TextDecoration.OVERLINE + | ft.TextDecoration.UNDERLINE + ), + ), + ft.TextSpan(text=" "), + ft.TextSpan( + text="line through thick", + style=ft.TextStyle( + decoration=ft.TextDecoration.LINE_THROUGH, + decoration_thickness=3, + ), + ), + ], + ), + ], + ), + ), + ) + + def handle_link_highlight(e: ft.Event[ft.TextSpan]): + e.control.style.color = ft.Colors.BLUE + e.control.update() + + def handle_link_unhighlight(e: ft.Event[ft.TextSpan]): + e.control.style.color = None + e.control.update() + + page.add( + ft.Text( + disabled=False, + spans=[ + ft.TextSpan( + text="Go to Google", + style=ft.TextStyle(decoration=ft.TextDecoration.UNDERLINE), + url="https://google.com", + on_enter=handle_link_highlight, + on_exit=handle_link_unhighlight, + ) + ], + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/text/rich_text_basic/pyproject.toml b/sdk/python/examples/controls/core/text/rich_text_basic/pyproject.toml new file mode 100644 index 0000000000..65dbd280d8 --- /dev/null +++ b/sdk/python/examples/controls/core/text/rich_text_basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-rich-text-basic" +version = "1.0.0" +description = "Combines nested TextSpan styles, interactive spans, and an external link in rich text." +requires-python = ">=3.10" +keywords = ["text", "rich text", "textspan", "link", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Text"] + +[tool.flet.metadata] +title = "Basic rich text" +controls = ["SafeArea", "Column", "Text", "TextSpan"] +layout_pattern = "stacked-content" +complexity = "basic" +features = ["nested text spans", "clickable spans", "external links"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/text/rich_text_border_stroke/main.py b/sdk/python/examples/controls/core/text/rich_text_border_stroke/main.py new file mode 100644 index 0000000000..8ccbded7c4 --- /dev/null +++ b/sdk/python/examples/controls/core/text/rich_text_border_stroke/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + controls=[ + ft.Text( + spans=[ + ft.TextSpan( + text="Greetings, planet!", + style=ft.TextStyle( + size=40, + weight=ft.FontWeight.BOLD, + foreground=ft.Paint( + color=ft.Colors.BLUE_700, + stroke_width=6, + style=ft.PaintingStyle.STROKE, + ), + ), + ), + ], + ), + ft.Text( + spans=[ + ft.TextSpan( + text="Greetings, planet!", + style=ft.TextStyle( + size=40, + weight=ft.FontWeight.BOLD, + color=ft.Colors.GREY_300, + ), + ), + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/text/rich_text_border_stroke/pyproject.toml b/sdk/python/examples/controls/core/text/rich_text_border_stroke/pyproject.toml new file mode 100644 index 0000000000..6cc719494b --- /dev/null +++ b/sdk/python/examples/controls/core/text/rich_text_border_stroke/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-rich-text-border-stroke" +version = "1.0.0" +description = "Layers stroked and filled rich text in a Stack to create an outlined title effect." +requires-python = ">=3.10" +keywords = ["text", "rich text", "stroke", "outline", "stack"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Text"] + +[tool.flet.metadata] +title = "Rich text border stroke" +controls = ["SafeArea", "Stack", "Text", "TextSpan"] +layout_pattern = "overlay" +complexity = "basic" +features = ["stroked text effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/text/rich_text_gradient/main.py b/sdk/python/examples/controls/core/text/rich_text_gradient/main.py new file mode 100644 index 0000000000..613acd0559 --- /dev/null +++ b/sdk/python/examples/controls/core/text/rich_text_gradient/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Text( + spans=[ + ft.TextSpan( + text="Greetings, planet!", + style=ft.TextStyle( + size=40, + weight=ft.FontWeight.BOLD, + foreground=ft.Paint( + gradient=ft.PaintLinearGradient( + begin=(0, 20), + end=(150, 20), + colors=[ft.Colors.RED, ft.Colors.YELLOW], + ) + ), + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/text/rich_text_gradient/pyproject.toml b/sdk/python/examples/controls/core/text/rich_text_gradient/pyproject.toml new file mode 100644 index 0000000000..8c8080f2f7 --- /dev/null +++ b/sdk/python/examples/controls/core/text/rich_text_gradient/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-rich-text-gradient" +version = "1.0.0" +description = "Applies a linear gradient paint to rich text for a multicolor title." +requires-python = ">=3.10" +keywords = ["text", "rich text", "gradient", "paint", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Text"] + +[tool.flet.metadata] +title = "Rich text gradient" +controls = ["SafeArea", "Text", "TextSpan"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["gradient text effect"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/text/text_theme_styles/main.py b/sdk/python/examples/controls/core/text/text_theme_styles/main.py new file mode 100644 index 0000000000..7d6fc1f00a --- /dev/null +++ b/sdk/python/examples/controls/core/text/text_theme_styles/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text theme styles" + page.scroll = ft.ScrollMode.ADAPTIVE + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Display Large", + theme_style=ft.TextThemeStyle.DISPLAY_LARGE, + ), + ft.Text( + "Display Medium", + theme_style=ft.TextThemeStyle.DISPLAY_MEDIUM, + ), + ft.Text( + "Display Small", + theme_style=ft.TextThemeStyle.DISPLAY_SMALL, + ), + ft.Text( + "Headline Large", + theme_style=ft.TextThemeStyle.HEADLINE_LARGE, + ), + ft.Text( + "Headline Medium", + theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM, + ), + ft.Text( + "Headline Small", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Text("Title Large", theme_style=ft.TextThemeStyle.TITLE_LARGE), + ft.Text("Title Medium", theme_style=ft.TextThemeStyle.TITLE_MEDIUM), + ft.Text("Title Small", theme_style=ft.TextThemeStyle.TITLE_SMALL), + ft.Text("Label Large", theme_style=ft.TextThemeStyle.LABEL_LARGE), + ft.Text( + "Label Medium", + theme_style=ft.TextThemeStyle.LABEL_MEDIUM, + ), + ft.Text("Label Small", theme_style=ft.TextThemeStyle.LABEL_SMALL), + ft.Text("Body Large", theme_style=ft.TextThemeStyle.BODY_LARGE), + ft.Text("Body Medium", theme_style=ft.TextThemeStyle.BODY_MEDIUM), + ft.Text("Body Small", theme_style=ft.TextThemeStyle.BODY_SMALL), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/text/text_theme_styles/pyproject.toml b/sdk/python/examples/controls/core/text/text_theme_styles/pyproject.toml new file mode 100644 index 0000000000..78dfca8fff --- /dev/null +++ b/sdk/python/examples/controls/core/text/text_theme_styles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-theme-styles" +version = "1.0.0" +description = "Shows the built-in TextThemeStyle variants from display styles through body and labels." +requires-python = ">=3.10" +keywords = ["text", "theme", "typography", "styles", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Text"] + +[tool.flet.metadata] +title = "Theme text styles" +controls = ["SafeArea", "Column", "Text"] +layout_pattern = "stacked-content" +complexity = "basic" +features = ["theme typography"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/text/variable_font_weight/main.py b/sdk/python/examples/controls/core/text/variable_font_weight/main.py new file mode 100644 index 0000000000..9e8f2aa871 --- /dev/null +++ b/sdk/python/examples/controls/core/text/variable_font_weight/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.fonts = { + "RobotoSlab": "https://github.com/google/fonts/raw/main/apache/robotoslab/RobotoSlab%5Bwght%5D.ttf" + } + + def handle_slider_change(e): + text.weight = f"w{int(e.control.value)}" # noqa + text.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + text := ft.Text( + "This is rendered with Roboto Slab", + size=30, + font_family="RobotoSlab", + weight=ft.FontWeight.W_100, + ), + ft.Slider( + min=100, + max=900, + divisions=8, + label="Weight = {value}", + width=500, + on_change=handle_slider_change, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/text/variable_font_weight/pyproject.toml b/sdk/python/examples/controls/core/text/variable_font_weight/pyproject.toml new file mode 100644 index 0000000000..619de2f703 --- /dev/null +++ b/sdk/python/examples/controls/core/text/variable_font_weight/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-variable-font-weight" +version = "1.0.0" +description = "Adjusts a variable font weight interactively with a slider." +requires-python = ">=3.10" +keywords = ["text", "font", "variable", "weight", "slider"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Text"] + +[tool.flet.metadata] +title = "Variable font weight" +controls = ["SafeArea", "Column", "Text", "Slider"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["interactive font weight control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/transparent_pointer/basic/main.py b/sdk/python/examples/controls/core/transparent_pointer/basic/main.py new file mode 100644 index 0000000000..e5781d0ca3 --- /dev/null +++ b/sdk/python/examples/controls/core/transparent_pointer/basic/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +def main(page: ft.Page): + def button_clicked(e): + print("transparent pointer button clicked") + + page.add( + ft.SafeArea( + expand=True, + content=ft.Stack( + expand=True, + controls=[ + ft.GestureDetector( + on_tap=lambda _: print("TAP!"), + multi_tap_touches=3, + on_multi_tap=lambda e: print("MULTI TAP:", e.global_position), + on_multi_long_press=lambda _: print("Multi tap long press"), + ), + ft.TransparentPointer( + content=ft.Container( + padding=50, + content=ft.Button( + "Test button", + on_click=button_clicked, + ), + ) + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/transparent_pointer/basic/pyproject.toml b/sdk/python/examples/controls/core/transparent_pointer/basic/pyproject.toml new file mode 100644 index 0000000000..58f14d2f79 --- /dev/null +++ b/sdk/python/examples/controls/core/transparent_pointer/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "transparent-pointer-basic" +version = "1.0.0" +description = "Lets pointer events pass through an overlaid button using TransparentPointer." +requires-python = ">=3.10" +keywords = ["transparent pointer", "gesture", "overlay", "stack", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TransparentPointer"] + +[tool.flet.metadata] +title = "TransparentPointer basic" +controls = ["SafeArea", "Stack", "GestureDetector", "TransparentPointer", "Container", "Button"] +layout_pattern = "overlay" +complexity = "basic" +features = ["pointer pass-through", "gesture handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/alignment/container/main.py b/sdk/python/examples/controls/core/types/alignment/container/main.py new file mode 100644 index 0000000000..95a29be797 --- /dev/null +++ b/sdk/python/examples/controls/core/types/alignment/container/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Containers with different alignments" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + alignment=ft.Alignment.CENTER, + width=150, + height=150, + content=ft.Button("Center"), + ), + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + alignment=ft.Alignment.TOP_LEFT, + width=150, + height=150, + content=ft.Button("Top left"), + ), + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + alignment=ft.Alignment(-0.5, -0.5), + width=150, + height=150, + content=ft.Button("-0.5, -0.5"), + ), + ], + wrap=True, + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/alignment/container/pyproject.toml b/sdk/python/examples/controls/core/types/alignment/container/pyproject.toml new file mode 100644 index 0000000000..af1bd0458a --- /dev/null +++ b/sdk/python/examples/controls/core/types/alignment/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-alignment-container" +version = "1.0.0" +description = "Shows how container content placement changes with preset and custom alignment values." +requires-python = ">=3.10" +keywords = ["alignment", "types", "container", "layout", "positioning"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Container alignment" +controls = ["SafeArea", "Column", "Row", "Container", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["preset alignment", "custom alignment coordinates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/alignment/media/container.png b/sdk/python/examples/controls/core/types/alignment/media/container.png new file mode 100644 index 0000000000..fbbf766e69 Binary files /dev/null and b/sdk/python/examples/controls/core/types/alignment/media/container.png differ diff --git a/sdk/python/examples/controls/core/types/alignment/media/overview.png b/sdk/python/examples/controls/core/types/alignment/media/overview.png new file mode 100644 index 0000000000..8a09665fb8 Binary files /dev/null and b/sdk/python/examples/controls/core/types/alignment/media/overview.png differ diff --git a/sdk/python/examples/controls/core/types/animated_switcher_transition/showcase/main.py b/sdk/python/examples/controls/core/types/animated_switcher_transition/showcase/main.py new file mode 100644 index 0000000000..9802998e0d --- /dev/null +++ b/sdk/python/examples/controls/core/types/animated_switcher_transition/showcase/main.py @@ -0,0 +1,81 @@ +import flet as ft + + +def showcase_card(transition: ft.AnimatedSwitcherTransition) -> ft.Container: + state = 0 + values = ["A", "B"] + + switcher = ft.AnimatedSwitcher( + duration=500, + reverse_duration=300, + transition=transition, + content=ft.Text( + values[0], + size=40, + weight=ft.FontWeight.BOLD, + ), + ) + + def swap(_): + nonlocal state + state = 1 - state + switcher.content = ft.Text( + values[state], + size=40, + weight=ft.FontWeight.BOLD, + ) + switcher.update() + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(transition.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=90, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + alignment=ft.Alignment.CENTER, + content=switcher, + ), + ft.Button("Swap", on_click=swap), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="AnimatedSwitcherTransition Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Swap content to compare switcher transition effects."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(transition) + for transition in ft.AnimatedSwitcherTransition + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/animated_switcher_transition/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/animated_switcher_transition/showcase/pyproject.toml new file mode 100644 index 0000000000..d10e0b0ec9 --- /dev/null +++ b/sdk/python/examples/controls/core/types/animated_switcher_transition/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-animated-switcher-transition-showcase" +version = "1.0.0" +description = "Compares Animated Switcher Transition values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["animated switcher transition", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animated Switcher Transition showcase" +controls = ["SafeArea", "Column", "Container", "AnimatedSwitcher", "Text", "Button", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/animation_curve/showcase/main.py b/sdk/python/examples/controls/core/types/animation_curve/showcase/main.py new file mode 100644 index 0000000000..3cdbfac2f1 --- /dev/null +++ b/sdk/python/examples/controls/core/types/animation_curve/showcase/main.py @@ -0,0 +1,174 @@ +import asyncio + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + duration_ms = 1200 + track_width = 248 + racer_size = 26 + lane_padding = 10 + lane_inner_width = track_width + lane_width = lane_inner_width + lane_padding * 2 + travel_units = (lane_inner_width - racer_size) / racer_size + card_animations: list = [] + + def showcase_card(curve: ft.AnimationCurve) -> ft.Container: + state = {"forward": False} + progress = ft.Container( + width=0, + height=6, + border_radius=3, + bgcolor=ft.Colors.PRIMARY_CONTAINER, + animate=ft.Animation(duration_ms, curve=curve), + ) + racer = ft.Container( + width=racer_size, + height=racer_size, + border_radius=13, + bgcolor=ft.Colors.PRIMARY, + shadow=ft.BoxShadow( + blur_radius=12, spread_radius=1, color=ft.Colors.PRIMARY + ), + alignment=ft.Alignment.CENTER, + content=ft.Icon(ft.Icons.BOLT, size=14, color=ft.Colors.ON_PRIMARY), + offset=ft.Offset(0, 0), + rotate=0, + scale=1, + animate_offset=ft.Animation(duration_ms, curve=curve), + animate_rotation=ft.Animation(duration_ms, curve=curve), + animate_scale=ft.Animation(duration_ms, curve=curve), + ) + status = ft.Text("idle", size=11, color=ft.Colors.ON_SURFACE_VARIANT) + + def animate(forward: bool): + state["forward"] = forward + racer.offset = ft.Offset(travel_units if forward else 0, 0) + racer.rotate = 1 if forward else 0 + racer.scale = 1.25 if forward else 1 + progress.width = track_width if forward else 0 + status.value = "forward" if forward else "reverse" + racer.update() + progress.update() + status.update() + + def replay(e): + animate(not state["forward"]) + + card_animations.append(animate) + + return ft.Container( + width=340, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=9, + controls=[ + ft.Text(curve.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=track_width, + height=6, + border_radius=3, + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGH, + content=progress, + ), + ft.Container( + width=lane_width, + height=48, + padding=lane_padding, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + clip_behavior=ft.ClipBehavior.HARD_EDGE, + bgcolor=ft.Colors.SURFACE, + content=ft.Stack( + controls=[ + ft.Row( + spacing=0, + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + ft.Container( + width=4, + height=22, + bgcolor=ft.Colors.OUTLINE, + ), + ft.Container( + width=4, + height=22, + bgcolor=ft.Colors.OUTLINE, + ), + ], + ), + racer, + ], + ), + ), + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + controls=[ + status, + ft.Button("Replay", icon=ft.Icons.REPLAY, on_click=replay), + ], + ), + ], + ), + ) + + def play_all(e): + for animate in card_animations: + animate(True) + + def reverse_all(e): + for animate in card_animations: + animate(False) + + async def wave_all(): + for animate in card_animations: + animate(True) + await asyncio.sleep(0.04) + + page.appbar = ft.AppBar(title="AnimationCurve Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Curve Lab: compare timing profiles across motion, " + "progress, and spin." + ), + ft.Row( + wrap=True, + spacing=8, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button( + "Play all", icon=ft.Icons.PLAY_ARROW, on_click=play_all + ), + ft.Button( + "Reverse all", + icon=ft.Icons.REPLAY, + on_click=reverse_all, + ), + ft.Button( + "Wave", on_click=lambda e: page.run_task(wave_all) + ), + ], + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(curve) for curve in ft.AnimationCurve], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/animation_curve/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/animation_curve/showcase/pyproject.toml new file mode 100644 index 0000000000..c43bcf9ae6 --- /dev/null +++ b/sdk/python/examples/controls/core/types/animation_curve/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-animation-curve-showcase" +version = "1.0.0" +description = "Compares Animation Curve values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["animation curve", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Animation Curve showcase" +controls = ["SafeArea", "Column", "Page", "AnimationCurve", "Container", "Icon", "Text", "Stack"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/app_lifecycle_state/showcase/main.py b/sdk/python/examples/controls/core/types/app_lifecycle_state/showcase/main.py new file mode 100644 index 0000000000..6600f230ce --- /dev/null +++ b/sdk/python/examples/controls/core/types/app_lifecycle_state/showcase/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + log = ft.Column( + spacing=4, + scroll=ft.ScrollMode.AUTO, + height=220, + ) + + def add_log(message: str): + log.controls.insert(0, ft.Text(message, size=12)) + if len(log.controls) > 20: + log.controls.pop() + log.update() + + def on_lifecycle(e: ft.AppLifecycleStateChangeEvent): + add_log(f"Received: {e.state.name}") + + page.on_app_lifecycle_state_change = on_lifecycle + + page.appbar = ft.AppBar(title="AppLifecycleState Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Switch app focus/visibility to see lifecycle state changes." + ), + ft.Text( + "Ex: minimize/restore app, switch tabs, or " + "background/foreground app.", + size=11, + ), + ft.Row( + wrap=True, + spacing=8, + controls=[ + ft.Container( + padding=ft.Padding.symmetric(horizontal=8, vertical=4), + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=12, + content=ft.Text(state.name, size=11), + ) + for state in ft.AppLifecycleState + ], + ), + ft.Container( + width=720, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=log, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/app_lifecycle_state/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/app_lifecycle_state/showcase/pyproject.toml new file mode 100644 index 0000000000..d1d6ad23aa --- /dev/null +++ b/sdk/python/examples/controls/core/types/app_lifecycle_state/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-app-lifecycle-state-showcase" +version = "1.0.0" +description = "Compares App Lifecycle State values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["app lifecycle state", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "App Lifecycle State showcase" +controls = ["SafeArea", "Column", "Page", "Text", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/assertiveness/showcase/main.py b/sdk/python/examples/controls/core/types/assertiveness/showcase/main.py new file mode 100644 index 0000000000..d1aeaa04aa --- /dev/null +++ b/sdk/python/examples/controls/core/types/assertiveness/showcase/main.py @@ -0,0 +1,74 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + semantics = ft.SemanticsService() + + def showcase_card(assertiveness: ft.Assertiveness) -> ft.Container: + status = ft.Text("Send an accessibility announcement.", size=11) + + async def announce(): + try: + await semantics.announce_message( + f"Announcement with {assertiveness.name} assertiveness.", + assertiveness=assertiveness, + ) + status.value = f"Sent with {assertiveness.value}." + except Exception as ex: + status.value = f"Error: {ex}" + status.update() + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(assertiveness.name, weight=ft.FontWeight.BOLD), + ft.Text( + assertiveness.value, + size=11, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Button( + "Announce message", + icon=ft.Icons.RECORD_VOICE_OVER, + on_click=lambda: page.run_task(announce), + ), + status, + ], + ), + ) + + page.appbar = ft.AppBar(title="Assertiveness Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare announcement assertiveness levels. " + "Enable a screen reader to hear the difference." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(assertiveness) + for assertiveness in ft.Assertiveness + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/assertiveness/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/assertiveness/showcase/pyproject.toml new file mode 100644 index 0000000000..21f9fee925 --- /dev/null +++ b/sdk/python/examples/controls/core/types/assertiveness/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-assertiveness-showcase" +version = "1.0.0" +description = "Compares Assertiveness values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["assertiveness", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Accessibility"] + +[tool.flet.metadata] +title = "Assertiveness showcase" +controls = ["SafeArea", "Column", "Page", "SemanticsService", "Container", "Text", "Button", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/axis/showcase/main.py b/sdk/python/examples/controls/core/types/axis/showcase/main.py new file mode 100644 index 0000000000..16f7cb0cd2 --- /dev/null +++ b/sdk/python/examples/controls/core/types/axis/showcase/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +def showcase_card(axis: ft.Axis) -> ft.Container: + return ft.Container( + width=350 if axis == ft.Axis.HORIZONTAL else 220, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(axis.name, weight=ft.FontWeight.BOLD), + ft.SegmentedButton( + direction=axis, + selected=["medium"], + segments=[ + ft.Segment(value="small", label="Small"), + ft.Segment(value="medium", label="Medium"), + ft.Segment(value="large", label="Large"), + ], + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="Axis Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare horizontal vs vertical segment layout."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(axis) for axis in ft.Axis], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/axis/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/axis/showcase/pyproject.toml new file mode 100644 index 0000000000..29a5cd6a13 --- /dev/null +++ b/sdk/python/examples/controls/core/types/axis/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-axis-showcase" +version = "1.0.0" +description = "Compares Axis values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["axis", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Axis showcase" +controls = ["SafeArea", "Column", "Container", "Text", "SegmentedButton", "Segment", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/badge/media/in_navigation_bar.png b/sdk/python/examples/controls/core/types/badge/media/in_navigation_bar.png new file mode 100644 index 0000000000..696af03f16 Binary files /dev/null and b/sdk/python/examples/controls/core/types/badge/media/in_navigation_bar.png differ diff --git a/sdk/python/examples/controls/core/types/blend_mode/showcase/main.py b/sdk/python/examples/controls/core/types/blend_mode/showcase/main.py new file mode 100644 index 0000000000..233bb45fd0 --- /dev/null +++ b/sdk/python/examples/controls/core/types/blend_mode/showcase/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def showcase_card(blend_mode: ft.BlendMode) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(blend_mode.name, weight=ft.FontWeight.BOLD), + ft.Image( + src="https://picsum.photos/id/237/200/300", + width=240, + height=130, + fit=ft.BoxFit.COVER, + color=ft.Colors.LIGHT_GREEN_200, + color_blend_mode=blend_mode, + border_radius=8, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BlendMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare color blending results for each BlendMode value."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(blend_mode) for blend_mode in ft.BlendMode + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/blend_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/blend_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..c9f8a8b9ab --- /dev/null +++ b/sdk/python/examples/controls/core/types/blend_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blend-mode-showcase" +version = "1.0.0" +description = "Compares Blend Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["blend mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Blend Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/blur/container/main.py b/sdk/python/examples/controls/core/types/blur/container/main.py new file mode 100644 index 0000000000..dbb97a746f --- /dev/null +++ b/sdk/python/examples/controls/core/types/blur/container/main.py @@ -0,0 +1,68 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + i = 1 + + img_container = ft.Container( + image=ft.DecorationImage(src="https://picsum.photos/300/300"), + width=300, + height=300, + ) + + def handle_button_click(e: ft.Event[ft.Button]): + nonlocal i + img_container.image = ft.DecorationImage( + src=f"https://picsum.photos/300/300?random={i}" + ) + i += 1 + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Stack( + controls=[ + img_container, + ft.Container( + width=100, + height=100, + blur=10, + bgcolor="#22CCCC00", + ), + ft.Container( + width=100, + height=100, + left=20, + top=120, + blur=(0, 10), + ), + ft.Container( + top=50, + right=10, + blur=ft.Blur(10, 0, ft.BlurTileMode.MIRROR), + width=100, + height=100, + bgcolor="#44CCCCCC", + border_radius=10, + border=ft.Border.all(2, ft.Colors.BLACK), + ), + ft.Button( + content="Change Background", + bottom=5, + right=5, + # style=ft.ButtonStyle(text_style=ft.TextStyle(size=8)), + on_click=handle_button_click, + ), + ] + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/blur/container/pyproject.toml b/sdk/python/examples/controls/core/types/blur/container/pyproject.toml new file mode 100644 index 0000000000..f292c3b561 --- /dev/null +++ b/sdk/python/examples/controls/core/types/blur/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blur-container" +version = "1.0.0" +description = "Demonstrates how Blur values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["blur", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Blur" +controls = ["SafeArea", "Column", "Page", "Container", "Button", "Stack", "ButtonStyle"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["blur preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/blur/media/container.gif b/sdk/python/examples/controls/core/types/blur/media/container.gif new file mode 100644 index 0000000000..74be430125 Binary files /dev/null and b/sdk/python/examples/controls/core/types/blur/media/container.gif differ diff --git a/sdk/python/examples/controls/core/types/blur_style/showcase/main.py b/sdk/python/examples/controls/core/types/blur_style/showcase/main.py new file mode 100644 index 0000000000..70efd25917 --- /dev/null +++ b/sdk/python/examples/controls/core/types/blur_style/showcase/main.py @@ -0,0 +1,64 @@ +import flet as ft + + +def showcase_card(style: ft.BlurStyle) -> ft.Container: + sample = ft.Container( + width=130, + height=90, + border_radius=12, + bgcolor=ft.Colors.BLUE_400, + shadow=ft.BoxShadow( + blur_radius=28, + spread_radius=3, + color=ft.Colors.RED_400, + offset=ft.Offset(10, 10), + blur_style=style, + ), + ) + + return ft.Container( + width=300, + height=180, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=12, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(style.name, weight=ft.FontWeight.BOLD), + sample, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BlurStyle Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare shadow blur rendering styles. " + "The blue box uses red shadow with selected blur style." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.BlurStyle], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/blur_style/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/blur_style/showcase/pyproject.toml new file mode 100644 index 0000000000..7e66a5182f --- /dev/null +++ b/sdk/python/examples/controls/core/types/blur_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blur-style-showcase" +version = "1.0.0" +description = "Compares Blur Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["blur style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Blur Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/blur_tile_mode/showcase/main.py b/sdk/python/examples/controls/core/types/blur_tile_mode/showcase/main.py new file mode 100644 index 0000000000..1cbce512d1 --- /dev/null +++ b/sdk/python/examples/controls/core/types/blur_tile_mode/showcase/main.py @@ -0,0 +1,89 @@ +import flet as ft + + +def checkerboard() -> ft.Column: + colors = [ft.Colors.TEAL_300, ft.Colors.AMBER_300] + return ft.Column( + spacing=0, + controls=[ + ft.Row( + spacing=0, + controls=[ + ft.Container( + width=24, + height=24, + bgcolor=colors[(row + col) % 2], + ) + for col in range(9) + ], + ) + for row in range(6) + ], + ) + + +def showcase_card(mode: ft.BlurTileMode) -> ft.Container: + preview = ft.Container( + width=216, + height=144, + border_radius=8, + clip_behavior=ft.ClipBehavior.ANTI_ALIAS, + content=ft.Stack( + controls=[ + checkerboard(), + ft.Container( + left=8, + top=28, + width=120, + height=80, + blur=ft.Blur(8, 8, mode), + bgcolor="#55FFFFFF", + border_radius=8, + border=ft.Border.all(1, ft.Colors.WHITE), + ), + ] + ), + ) + + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + preview, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BlurTileMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare blur edge sampling outside source bounds."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in ft.BlurTileMode], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/blur_tile_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/blur_tile_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..d38f1037d0 --- /dev/null +++ b/sdk/python/examples/controls/core/types/blur_tile_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-blur-tile-mode-showcase" +version = "1.0.0" +description = "Compares Blur Tile Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["blur tile mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Blur Tile Mode showcase" +controls = ["SafeArea", "Column", "Row", "Container", "Stack", "Text", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/border/container/main.py b/sdk/python/examples/controls/core/types/border/container/main.py new file mode 100644 index 0000000000..7e41cfa36f --- /dev/null +++ b/sdk/python/examples/controls/core/types/border/container/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Containers with different borders" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Container( + bgcolor=ft.Colors.AMBER, + padding=15, + border=ft.Border.all(10, ft.Colors.PINK_600), + border_radius=ft.BorderRadius.all(30), + width=150, + height=150, + ), + ft.Container( + bgcolor=ft.Colors.DEEP_PURPLE, + padding=15, + border=ft.Border.all(3, ft.Colors.LIGHT_GREEN_ACCENT), + border_radius=ft.BorderRadius.only( + top_left=10, bottom_right=10 + ), + width=150, + height=150, + ), + ft.Container( + bgcolor=ft.Colors.BLUE_GREY_900, + padding=15, + border=ft.Border.symmetric( + vertical=ft.BorderSide(8, ft.Colors.YELLOW_800) + ), + width=150, + height=150, + ), + ] + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/border/container/pyproject.toml b/sdk/python/examples/controls/core/types/border/container/pyproject.toml new file mode 100644 index 0000000000..c52f800ae2 --- /dev/null +++ b/sdk/python/examples/controls/core/types/border/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-border-container" +version = "1.0.0" +description = "Demonstrates how Border values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["border", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Border" +controls = ["SafeArea", "Column", "Page", "Row", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["border preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/border_side_stroke_align/showcase/main.py b/sdk/python/examples/controls/core/types/border_side_stroke_align/showcase/main.py new file mode 100644 index 0000000000..8c832d3b77 --- /dev/null +++ b/sdk/python/examples/controls/core/types/border_side_stroke_align/showcase/main.py @@ -0,0 +1,80 @@ +import flet as ft + + +def showcase_card(align: ft.BorderSideStrokeAlign) -> ft.Container: + preview = ft.Container( + width=150, + height=150, + alignment=ft.Alignment.CENTER, + content=ft.Stack( + controls=[ + ft.Container( + width=90, + height=90, + border_radius=45, + bgcolor=ft.Colors.ON_SURFACE, + ), + ft.Container( + width=90, + height=90, + border_radius=45, + border=ft.Border.all( + side=ft.BorderSide( + width=18, + color=ft.Colors.RED, + stroke_align=align, + ) + ), + ), + ], + ), + ) + + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(align.name, weight=ft.FontWeight.BOLD), + preview, + ft.Text(f"value={align.value}", size=11), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BorderSideStrokeAlign Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how thick borders are painted relative to " + "the shape path." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(align) for align in ft.BorderSideStrokeAlign + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/border_side_stroke_align/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/border_side_stroke_align/showcase/pyproject.toml new file mode 100644 index 0000000000..ac77d1641c --- /dev/null +++ b/sdk/python/examples/controls/core/types/border_side_stroke_align/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-border-side-stroke-align-showcase" +version = "1.0.0" +description = "Compares Border Side Stroke Align values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["border side stroke align", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Border Side Stroke Align showcase" +controls = ["SafeArea", "Column", "BorderSideStrokeAlign", "Container", "Stack", "Text", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/border_style/showcase/main.py b/sdk/python/examples/controls/core/types/border_style/showcase/main.py new file mode 100644 index 0000000000..65e973d67f --- /dev/null +++ b/sdk/python/examples/controls/core/types/border_style/showcase/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def showcase_card(style: ft.BorderStyle) -> ft.Container: + side = ft.BorderSide(width=4, color=ft.Colors.PRIMARY, style=style) + border = ft.Border(left=side, top=side, right=side, bottom=side) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(style.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=100, + border=border, + border_radius=8, + bgcolor=ft.Colors.SURFACE, + alignment=ft.Alignment.CENTER, + content=ft.Text("Border preview"), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BorderStyle Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare rendered border sides for each BorderStyle value." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.BorderStyle], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/border_style/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/border_style/showcase/pyproject.toml new file mode 100644 index 0000000000..e3e37ec423 --- /dev/null +++ b/sdk/python/examples/controls/core/types/border_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-border-style-showcase" +version = "1.0.0" +description = "Compares Border Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["border style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Border Style showcase" +controls = ["SafeArea", "Column", "BorderStyle", "Container", "Text", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/box_fit/showcase/main.py b/sdk/python/examples/controls/core/types/box_fit/showcase/main.py new file mode 100644 index 0000000000..f471940b63 --- /dev/null +++ b/sdk/python/examples/controls/core/types/box_fit/showcase/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def showcase_card(fit: ft.BoxFit) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(fit.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=120, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + clip_behavior=ft.ClipBehavior.HARD_EDGE, + bgcolor=ft.Colors.SURFACE, + content=ft.Image( + src="https://picsum.photos/id/1025/420/220", + width=240, + height=120, + fit=fit, + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BoxFit Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how the same image is inscribed into a fixed frame." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(fit) for fit in ft.BoxFit], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/box_fit/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/box_fit/showcase/pyproject.toml new file mode 100644 index 0000000000..4fa8c1cae6 --- /dev/null +++ b/sdk/python/examples/controls/core/types/box_fit/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-box-fit-showcase" +version = "1.0.0" +description = "Compares Box Fit values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["box fit", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Box Fit showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/box_shadow/container/main.py b/sdk/python/examples/controls/core/types/box_shadow/container/main.py new file mode 100644 index 0000000000..5f96f16579 --- /dev/null +++ b/sdk/python/examples/controls/core/types/box_shadow/container/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + bgcolor=ft.Colors.YELLOW, + width=100, + height=100, + border_radius=50, + shadow=[ + ft.BoxShadow( + spread_radius=1, + blur_radius=15, + color=ft.Colors.WHITE, + offset=ft.Offset(-5, -5), + ), + ft.BoxShadow( + spread_radius=1, + blur_radius=15, + color=ft.Colors.GREY_600, + offset=ft.Offset(5, 5), + ), + ], + ), + ft.Container( + # bgcolor=ft.Colors.WHITE, + border_radius=10, + width=100, + height=100, + shadow=ft.BoxShadow( + spread_radius=1, + blur_radius=15, + color=ft.Colors.BLUE_GREY_300, + offset=ft.Offset(0, 0), + blur_style=ft.BlurStyle.OUTER, + ), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/box_shadow/container/pyproject.toml b/sdk/python/examples/controls/core/types/box_shadow/container/pyproject.toml new file mode 100644 index 0000000000..46dd31faaa --- /dev/null +++ b/sdk/python/examples/controls/core/types/box_shadow/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-box-shadow-container" +version = "1.0.0" +description = "Demonstrates how Box Shadow values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["box shadow", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Box Shadow" +controls = ["SafeArea", "Column", "Page", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["box shadow preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/box_shape/showcase/main.py b/sdk/python/examples/controls/core/types/box_shape/showcase/main.py new file mode 100644 index 0000000000..07a86207c3 --- /dev/null +++ b/sdk/python/examples/controls/core/types/box_shape/showcase/main.py @@ -0,0 +1,70 @@ +import flet as ft + + +def showcase_card(shape: ft.BoxShape) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(shape.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=200, + height=120, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.SURFACE, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + content=ft.Container( + width=120, + height=90, + alignment=ft.Alignment.CENTER, + shape=shape, + bgcolor=ft.Colors.PRIMARY_CONTAINER, + border=ft.Border.all(2, ft.Colors.PRIMARY), + border_radius=( + ft.BorderRadius.all(16) + if shape == ft.BoxShape.RECTANGLE + else None + ), + content=ft.Text( + "Shape", + color=ft.Colors.ON_PRIMARY_CONTAINER, + weight=ft.FontWeight.BOLD, + ), + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="BoxShape Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare rectangular and circular box decoration shapes."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(shape) for shape in ft.BoxShape], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/box_shape/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/box_shape/showcase/pyproject.toml new file mode 100644 index 0000000000..1e0960ad42 --- /dev/null +++ b/sdk/python/examples/controls/core/types/box_shape/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-box-shape-showcase" +version = "1.0.0" +description = "Compares Box Shape values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["box shape", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Box Shape showcase" +controls = ["SafeArea", "Column", "Container", "Text", "BorderRadius", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/card_variant/showcase/main.py b/sdk/python/examples/controls/core/types/card_variant/showcase/main.py new file mode 100644 index 0000000000..9f167c1328 --- /dev/null +++ b/sdk/python/examples/controls/core/types/card_variant/showcase/main.py @@ -0,0 +1,63 @@ +import flet as ft + + +def showcase_card(variant: ft.CardVariant) -> ft.Container: + card = ft.Card( + variant=variant, + content=ft.Container( + width=260, + padding=12, + content=ft.Column( + spacing=6, + controls=[ + ft.Text("Quarterly Report", weight=ft.FontWeight.BOLD), + ft.Text( + "Revenue increased by 18% compared to last quarter.", + size=12, + ), + ], + ), + ), + ) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(variant.name, weight=ft.FontWeight.BOLD), + card, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="CardVariant Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare Material card visual variants."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(variant) for variant in ft.CardVariant], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/card_variant/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/card_variant/showcase/pyproject.toml new file mode 100644 index 0000000000..8e5b3460d3 --- /dev/null +++ b/sdk/python/examples/controls/core/types/card_variant/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-card-variant-showcase" +version = "1.0.0" +description = "Compares Card Variant values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["card variant", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Card Variant showcase" +controls = ["SafeArea", "Column", "Container", "Card", "Text", "Page", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/clip_behavior/showcase/main.py b/sdk/python/examples/controls/core/types/clip_behavior/showcase/main.py new file mode 100644 index 0000000000..6494919a06 --- /dev/null +++ b/sdk/python/examples/controls/core/types/clip_behavior/showcase/main.py @@ -0,0 +1,88 @@ +import flet as ft + + +def clip_preview(clip_behavior: ft.ClipBehavior) -> ft.Container: + return ft.Container( + width=240, + height=130, + border=ft.Border.all(2, ft.Colors.OUTLINE), + border_radius=10, + bgcolor=ft.Colors.SURFACE, + content=ft.Stack( + clip_behavior=clip_behavior, + controls=[ + ft.Container( + width=160, + height=70, + left=-25, + top=30, + bgcolor=ft.Colors.PRIMARY_CONTAINER, + border_radius=16, + ), + ft.Container( + width=90, + height=90, + left=150, + top=-20, + bgcolor=ft.Colors.TERTIARY_CONTAINER, + border_radius=45, + ), + ft.Container( + width=90, + height=90, + left=70, + top=22, + bgcolor=ft.Colors.SECONDARY, + border_radius=45, + alignment=ft.Alignment.CENTER, + content=ft.Icon(ft.Icons.CROP, color=ft.Colors.WHITE), + ), + ], + ), + ) + + +def showcase_card(clip_behavior: ft.ClipBehavior) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(clip_behavior.name, weight=ft.FontWeight.BOLD), + clip_preview(clip_behavior), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="ClipBehavior Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how overflow is clipped for each ClipBehavior value." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(cb) for cb in ft.ClipBehavior], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/clip_behavior/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/clip_behavior/showcase/pyproject.toml new file mode 100644 index 0000000000..22eaaa0deb --- /dev/null +++ b/sdk/python/examples/controls/core/types/clip_behavior/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-clip-behavior-showcase" +version = "1.0.0" +description = "Compares Clip Behavior values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["clip behavior", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Clip Behavior showcase" +controls = ["SafeArea", "Column", "Container", "Stack", "Icon", "Text", "Page", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/context/disable_auto_update/main.py b/sdk/python/examples/controls/core/types/context/disable_auto_update/main.py new file mode 100644 index 0000000000..38e4b09ad2 --- /dev/null +++ b/sdk/python/examples/controls/core/types/context/disable_auto_update/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + def button_click(): + ft.context.disable_auto_update() + b.content = "Button clicked!" + # update just the button + b.update() + + page.controls.append(ft.Text("This won't appear")) + # no page.update() will be called here + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[b := ft.Button("Action!", on_click=button_click)] + ) + ) + ) + # page.update() - auto-update is enabled by default + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/context/disable_auto_update/pyproject.toml b/sdk/python/examples/controls/core/types/context/disable_auto_update/pyproject.toml new file mode 100644 index 0000000000..81793bc37a --- /dev/null +++ b/sdk/python/examples/controls/core/types/context/disable_auto_update/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-context-disable-auto-update" +version = "1.0.0" +description = "Shows how disabling automatic updates requires explicit control refreshes." +requires-python = ">=3.10" +keywords = ["context", "disable auto update"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types"] + +[tool.flet.metadata] +title = "Disable auto update" +controls = ["SafeArea", "Column", "Page", "Text", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["manual updates", "context access"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/context/get_page/main.py b/sdk/python/examples/controls/core/types/context/get_page/main.py new file mode 100644 index 0000000000..092e600c82 --- /dev/null +++ b/sdk/python/examples/controls/core/types/context/get_page/main.py @@ -0,0 +1,18 @@ +import flet as ft + + +def main(page: ft.Page): + def button_click(e): + print("Page width:", ft.context.page.width) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Button("Get page width", on_click=button_click)] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/context/get_page/pyproject.toml b/sdk/python/examples/controls/core/types/context/get_page/pyproject.toml new file mode 100644 index 0000000000..2e4fb7a761 --- /dev/null +++ b/sdk/python/examples/controls/core/types/context/get_page/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-context-get-page" +version = "1.0.0" +description = "Reads the current page from ft.context inside an event handler." +requires-python = ">=3.10" +keywords = ["context", "get page"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types"] + +[tool.flet.metadata] +title = "Get page from context" +controls = ["SafeArea", "Column", "Page", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["context access", "event handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/context_menu_trigger/showcase/main.py b/sdk/python/examples/controls/core/types/context_menu_trigger/showcase/main.py new file mode 100644 index 0000000000..39203d11b4 --- /dev/null +++ b/sdk/python/examples/controls/core/types/context_menu_trigger/showcase/main.py @@ -0,0 +1,90 @@ +import flet as ft + + +def showcase_card(trigger: ft.ContextMenuTrigger) -> ft.Container: + def on_select(e: ft.ContextMenuSelectEvent): + item = e.item.content if e.item else f"item #{e.item_index}" + status.value = f"Selected: {item}" + status.update() + + def on_dismiss(_): + if status.value == "Open the menu in the area below.": + status.value = "Menu dismissed." + status.update() + + menu = ft.ContextMenu( + primary_trigger=trigger, + primary_items=[ + ft.PopupMenuItem(icon=ft.Icons.EDIT, content="Edit"), + ft.PopupMenuItem(icon=ft.Icons.CONTENT_COPY, content="Duplicate"), + ft.PopupMenuItem(icon=ft.Icons.DELETE, content="Delete"), + ], + on_select=on_select, + on_dismiss=on_dismiss, + content=ft.Container( + width=280, + height=120, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + alignment=ft.Alignment.CENTER, + content=ft.Text( + text_align=ft.TextAlign.CENTER, + value=( + "Press and hold inside the area." + if trigger == ft.ContextMenuTrigger.LONG_PRESS + else "Press mouse button down inside the area." + ), + ), + ), + ) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(trigger.name, weight=ft.FontWeight.BOLD), + menu, + status := ft.Text("Open the menu in the area below.", size=11), + ], + ), + ) + + +async def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + if page.web: + await ft.BrowserContextMenu().disable() + + page.appbar = ft.AppBar(title="ContextMenuTrigger Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare context-menu open behavior for primary trigger modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(trigger) for trigger in ft.ContextMenuTrigger + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/context_menu_trigger/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/context_menu_trigger/showcase/pyproject.toml new file mode 100644 index 0000000000..17b755de33 --- /dev/null +++ b/sdk/python/examples/controls/core/types/context_menu_trigger/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-context-menu-trigger-showcase" +version = "1.0.0" +description = "Compares Context Menu Trigger values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["context menu trigger", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Context Menu Trigger showcase" +controls = ["SafeArea", "Column", "Container", "ContextMenu", "PopupMenuItem", "Text", "BrowserContextMenu", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/cross_axis_alignment/showcase/main.py b/sdk/python/examples/controls/core/types/cross_axis_alignment/showcase/main.py new file mode 100644 index 0000000000..34986862a2 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cross_axis_alignment/showcase/main.py @@ -0,0 +1,103 @@ +import flet as ft + + +def showcase_card(alignment: ft.CrossAxisAlignment) -> ft.Container: + if alignment == ft.CrossAxisAlignment.STRETCH: + preview = ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + vertical_alignment=alignment, + controls=[ + ft.Container(width=40, bgcolor=ft.Colors.PRIMARY_CONTAINER), + ft.Container(width=40, bgcolor=ft.Colors.TERTIARY_CONTAINER), + ft.Container(width=40, bgcolor=ft.Colors.SECONDARY_CONTAINER), + ], + ) + else: + effective_alignment = ( + ft.CrossAxisAlignment.CENTER + if alignment == ft.CrossAxisAlignment.BASELINE + else alignment + ) + preview = ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + vertical_alignment=effective_alignment, + controls=[ + ft.Container( + width=40, + height=24, + bgcolor=ft.Colors.PRIMARY_CONTAINER, + ), + ft.Container( + width=40, + height=46, + bgcolor=ft.Colors.TERTIARY_CONTAINER, + ), + ft.Container( + width=40, + height=34, + bgcolor=ft.Colors.SECONDARY_CONTAINER, + ), + ], + ) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(alignment.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=250, + height=120, + padding=8, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=preview, + ), + ft.Text( + "Baseline uses center fallback in this showcase.", + size=11, + visible=alignment == ft.CrossAxisAlignment.BASELINE, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="CrossAxisAlignment Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare vertical alignment behavior inside the same " + "row height." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) + for alignment in ft.CrossAxisAlignment + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/cross_axis_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/cross_axis_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..c756fd84cd --- /dev/null +++ b/sdk/python/examples/controls/core/types/cross_axis_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cross-axis-alignment-showcase" +version = "1.0.0" +description = "Compares Cross Axis Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cross axis alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Cross Axis Alignment showcase" +controls = ["SafeArea", "Column", "Container", "Row", "Text", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/cupertino_button_size/showcase/main.py b/sdk/python/examples/controls/core/types/cupertino_button_size/showcase/main.py new file mode 100644 index 0000000000..8313c3e541 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_button_size/showcase/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +def showcase_card(size: ft.CupertinoButtonSize) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(size.name, weight=ft.FontWeight.BOLD), + ft.CupertinoButton( + content="Continue", + icon=ft.CupertinoIcons.RIGHT_CHEVRON, + size=size, + bgcolor=ft.Colors.BLUE_600, + color=ft.Colors.WHITE, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="CupertinoButtonSize Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare iOS button size presets."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(size) for size in ft.CupertinoButtonSize + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/cupertino_button_size/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/cupertino_button_size/showcase/pyproject.toml new file mode 100644 index 0000000000..9d856aad67 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_button_size/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-button-size-showcase" +version = "1.0.0" +description = "Compares Cupertino Button Size values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino button size", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Button Size showcase" +controls = ["SafeArea", "Column", "Container", "Text", "CupertinoButton", "CupertinoIcons", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/cupertino_date_picker_date_order/showcase/main.py b/sdk/python/examples/controls/core/types/cupertino_date_picker_date_order/showcase/main.py new file mode 100644 index 0000000000..96b6619de6 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_date_picker_date_order/showcase/main.py @@ -0,0 +1,67 @@ +from datetime import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def showcase_card(date_order: ft.CupertinoDatePickerDateOrder) -> ft.Container: + def open_picker(_): + picker = ft.CupertinoDatePicker( + date_picker_mode=ft.CupertinoDatePickerMode.DATE, + date_order=date_order, + value=datetime(2024, 3, 12, 10, 0), + ) + page.show_dialog( + ft.CupertinoBottomSheet( + content=picker, + height=216, + padding=ft.Padding.only(top=6), + ) + ) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(date_order.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open picker", + icon=ft.CupertinoIcons.CALENDAR, + on_click=open_picker, + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="CupertinoDatePickerDateOrder Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open each variant in CupertinoBottomSheet."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(date_order) + for date_order in ft.CupertinoDatePickerDateOrder + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/cupertino_date_picker_date_order/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/cupertino_date_picker_date_order/showcase/pyproject.toml new file mode 100644 index 0000000000..24cc993de8 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_date_picker_date_order/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-date-picker-date-order-showcase" +version = "1.0.0" +description = "Compares Cupertino Date Picker Date Order values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino date picker date order", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Date Picker Date Order showcase" +controls = ["SafeArea", "Column", "Container", "CupertinoDatePicker", "CupertinoBottomSheet", "Text", "Button", "CupertinoIcons"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/cupertino_date_picker_mode/showcase/main.py b/sdk/python/examples/controls/core/types/cupertino_date_picker_mode/showcase/main.py new file mode 100644 index 0000000000..9df0fffb59 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_date_picker_mode/showcase/main.py @@ -0,0 +1,68 @@ +from datetime import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def showcase_card(mode: ft.CupertinoDatePickerMode) -> ft.Container: + def open_picker(_): + picker = ft.CupertinoDatePicker( + date_picker_mode=mode, + value=datetime(2024, 7, 13, 16, 14), + use_24h_format=True, + ) + page.show_dialog( + ft.CupertinoBottomSheet( + content=picker, + height=216, + padding=ft.Padding.only(top=6), + ) + ) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open picker", + icon=ft.CupertinoIcons.CALENDAR, + on_click=open_picker, + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="CupertinoDatePickerMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Open each mode in CupertinoBottomSheet to compare behavior." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(mode) for mode in ft.CupertinoDatePickerMode + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/cupertino_date_picker_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/cupertino_date_picker_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..d323e12630 --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_date_picker_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-date-picker-mode-showcase" +version = "1.0.0" +description = "Compares Cupertino Date Picker Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino date picker mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Date Picker Mode showcase" +controls = ["SafeArea", "Column", "Container", "CupertinoDatePicker", "CupertinoBottomSheet", "Text", "Button", "CupertinoIcons"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/cupertino_timer_picker_mode/showcase/main.py b/sdk/python/examples/controls/core/types/cupertino_timer_picker_mode/showcase/main.py new file mode 100644 index 0000000000..570a06b79b --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_timer_picker_mode/showcase/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def showcase_card(mode: ft.CupertinoTimerPickerMode) -> ft.Container: + return ft.Container( + width=340, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + ft.CupertinoTimerPicker( + mode=mode, + value=ft.Duration(seconds=754), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="CupertinoTimerPickerMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare timer picker layouts."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(mode) for mode in ft.CupertinoTimerPickerMode + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/cupertino_timer_picker_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/cupertino_timer_picker_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..a0764ed68c --- /dev/null +++ b/sdk/python/examples/controls/core/types/cupertino_timer_picker_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-cupertino-timer-picker-mode-showcase" +version = "1.0.0" +description = "Compares Cupertino Timer Picker Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["cupertino timer picker mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Cupertino Timer Picker Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "CupertinoTimerPicker", "Duration", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/date_picker_entry_mode/showcase/main.py b/sdk/python/examples/controls/core/types/date_picker_entry_mode/showcase/main.py new file mode 100644 index 0000000000..96213f1327 --- /dev/null +++ b/sdk/python/examples/controls/core/types/date_picker_entry_mode/showcase/main.py @@ -0,0 +1,63 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + today = datetime.datetime.now() + picker = ft.DatePicker( + first_date=datetime.datetime(year=today.year - 1, month=1, day=1), + last_date=datetime.datetime(year=today.year + 1, month=12, day=31), + ) + + def open_picker(entry_mode: ft.DatePickerEntryMode): + picker.entry_mode = entry_mode + picker.date_picker_mode = ft.DatePickerMode.DAY + page.show_dialog(picker) + + def showcase_card(entry_mode: ft.DatePickerEntryMode) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(entry_mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open DatePicker", + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _, m=entry_mode: open_picker(m), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="DatePickerEntryMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Open the picker to compare calendar and input entry modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(m) for m in ft.DatePickerEntryMode], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/date_picker_entry_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/date_picker_entry_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..d4137823f7 --- /dev/null +++ b/sdk/python/examples/controls/core/types/date_picker_entry_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-date-picker-entry-mode-showcase" +version = "1.0.0" +description = "Compares Date Picker Entry Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["date picker entry mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Date Picker Entry Mode showcase" +controls = ["SafeArea", "Column", "DatePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/date_picker_mode/showcase/main.py b/sdk/python/examples/controls/core/types/date_picker_mode/showcase/main.py new file mode 100644 index 0000000000..48a991503b --- /dev/null +++ b/sdk/python/examples/controls/core/types/date_picker_mode/showcase/main.py @@ -0,0 +1,63 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + today = datetime.datetime.now() + picker = ft.DatePicker( + first_date=datetime.datetime(year=today.year - 1, month=1, day=1), + last_date=datetime.datetime(year=today.year + 1, month=12, day=31), + entry_mode=ft.DatePickerEntryMode.CALENDAR, + ) + + def open_picker(date_picker_mode: ft.DatePickerMode): + picker.date_picker_mode = date_picker_mode + page.show_dialog(picker) + + def showcase_card(date_picker_mode: ft.DatePickerMode) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(date_picker_mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open DatePicker", + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _, m=date_picker_mode: open_picker(m), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="DatePickerMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Open the picker to compare initial day vs year display mode." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(m) for m in ft.DatePickerMode], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/date_picker_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/date_picker_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..3abdbc3e08 --- /dev/null +++ b/sdk/python/examples/controls/core/types/date_picker_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-date-picker-mode-showcase" +version = "1.0.0" +description = "Compares Date Picker Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["date picker mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Date Picker Mode showcase" +controls = ["SafeArea", "Column", "DatePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/dismiss_direction/showcase/main.py b/sdk/python/examples/controls/core/types/dismiss_direction/showcase/main.py new file mode 100644 index 0000000000..c04aed797c --- /dev/null +++ b/sdk/python/examples/controls/core/types/dismiss_direction/showcase/main.py @@ -0,0 +1,99 @@ +import flet as ft + + +def showcase_card(direction: ft.DismissDirection) -> ft.Container: + status = ft.Text("Swipe the tile", size=12, color=ft.Colors.ON_SURFACE_VARIANT) + + def create_item() -> ft.Dismissible: + return ft.Dismissible( + dismiss_direction=direction, + on_dismiss=lambda _: on_dismiss(), + background=ft.Container( + bgcolor=ft.Colors.GREEN_200, + alignment=ft.Alignment.CENTER_LEFT, + padding=10, + content=ft.Icon(ft.Icons.CHECK, color=ft.Colors.GREEN_900), + ), + secondary_background=ft.Container( + bgcolor=ft.Colors.RED_200, + alignment=ft.Alignment.CENTER_RIGHT, + padding=10, + content=ft.Icon(ft.Icons.DELETE, color=ft.Colors.RED_900), + ), + content=ft.Container( + height=52, + border_radius=8, + bgcolor=ft.Colors.SURFACE, + border=ft.Border.all(1, ft.Colors.OUTLINE), + alignment=ft.Alignment.CENTER, + content=ft.Text("Dismiss me"), + ), + ) + + def on_dismiss(): + slot.content = ft.Container( + height=52, + border_radius=8, + bgcolor=ft.Colors.SURFACE, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + alignment=ft.Alignment.CENTER, + content=ft.Text("Dismissed"), + ) + status.value = f"Dismissed via {direction.name}" + slot.update() + status.update() + + def reset_item(_): + slot.content = create_item() + status.value = "Swipe the tile" + slot.update() + status.update() + + slot = ft.Container(content=create_item()) + + return ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(direction.name, weight=ft.FontWeight.BOLD), + status, + slot, + ft.Button("Reset", on_click=reset_item), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="DismissDirection Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Try swipe directions to see which ones are allowed."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(direction) + for direction in ft.DismissDirection + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/dismiss_direction/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/dismiss_direction/showcase/pyproject.toml new file mode 100644 index 0000000000..0b1d38a920 --- /dev/null +++ b/sdk/python/examples/controls/core/types/dismiss_direction/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-dismiss-direction-showcase" +version = "1.0.0" +description = "Compares Dismiss Direction values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["dismiss direction", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Dismiss Direction showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Dismissible", "Icon", "Button", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/filter_quality/showcase/main.py b/sdk/python/examples/controls/core/types/filter_quality/showcase/main.py new file mode 100644 index 0000000000..71b37e7189 --- /dev/null +++ b/sdk/python/examples/controls/core/types/filter_quality/showcase/main.py @@ -0,0 +1,66 @@ +import flet as ft + +IMAGE_URL = "https://picsum.photos/id/1025/64/64" + + +def showcase_card(quality: ft.FilterQuality) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(quality.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=120, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + clip_behavior=ft.ClipBehavior.HARD_EDGE, + bgcolor=ft.Colors.SURFACE, + content=ft.Image( + src=IMAGE_URL, + width=240, + height=120, + fit=ft.BoxFit.FILL, + filter_quality=quality, + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="FilterQuality Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare image sampling quality while scaling the " + "same source image." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(quality) for quality in ft.FilterQuality + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/filter_quality/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/filter_quality/showcase/pyproject.toml new file mode 100644 index 0000000000..c716e1ad01 --- /dev/null +++ b/sdk/python/examples/controls/core/types/filter_quality/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-filter-quality-showcase" +version = "1.0.0" +description = "Compares Filter Quality values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["filter quality", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Filter Quality showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/floating_action_button_location/showcase/main.py b/sdk/python/examples/controls/core/types/floating_action_button_location/showcase/main.py new file mode 100644 index 0000000000..c762d3264c --- /dev/null +++ b/sdk/python/examples/controls/core/types/floating_action_button_location/showcase/main.py @@ -0,0 +1,73 @@ +import flet as ft + + +def showcase_card(location: ft.FloatingActionButtonLocation) -> ft.Container: + mini = location.name.startswith("MINI_") + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(location.name, weight=ft.FontWeight.BOLD), + ft.Pagelet( + width=260, + height=200, + bgcolor=ft.Colors.SURFACE, + appbar=ft.AppBar( + title=ft.Text("AppBar", size=12), + center_title=True, + toolbar_height=38, + bgcolor=ft.Colors.PRIMARY_CONTAINER, + ), + content=ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Body", size=12), + ), + bottom_appbar=ft.BottomAppBar( + height=42, + bgcolor=ft.Colors.SECONDARY_CONTAINER, + ), + floating_action_button=ft.FloatingActionButton( + icon=ft.Icons.ADD, + mini=mini, + bgcolor=ft.Colors.LIGHT_BLUE_400, + ), + floating_action_button_location=location, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="FloatingActionButtonLocation Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare FloatingActionButton placement presets."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(location) + for location in ft.FloatingActionButtonLocation + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/floating_action_button_location/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/floating_action_button_location/showcase/pyproject.toml new file mode 100644 index 0000000000..ac108dceed --- /dev/null +++ b/sdk/python/examples/controls/core/types/floating_action_button_location/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-floating-action-button-location-showcase" +version = "1.0.0" +description = "Compares Floating Action Button Location values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["floating action button location", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Floating Action Button Location showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Pagelet", "AppBar", "BottomAppBar", "FloatingActionButton"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/font_weight/showcase/main.py b/sdk/python/examples/controls/core/types/font_weight/showcase/main.py new file mode 100644 index 0000000000..daaf4a2203 --- /dev/null +++ b/sdk/python/examples/controls/core/types/font_weight/showcase/main.py @@ -0,0 +1,47 @@ +import flet as ft + +SAMPLE_TEXT = "Sphinx of black quartz" + + +def showcase_card(weight: ft.FontWeight) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(weight.name, size=12, color=ft.Colors.ON_SURFACE_VARIANT), + ft.Text(SAMPLE_TEXT, weight=weight, size=24), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="FontWeight Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare text thickness across all FontWeight values."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(weight) for weight in ft.FontWeight], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/font_weight/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/font_weight/showcase/pyproject.toml new file mode 100644 index 0000000000..2ed08c2426 --- /dev/null +++ b/sdk/python/examples/controls/core/types/font_weight/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-font-weight-showcase" +version = "1.0.0" +description = "Compares Font Weight values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["font weight", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Font Weight showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/gradient/container/main.py b/sdk/python/examples/controls/core/types/gradient/container/main.py new file mode 100644 index 0000000000..d7414b5231 --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/container/main.py @@ -0,0 +1,106 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Container( + content=ft.Text("Linear gradient"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment(0.8, 1), + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + ), + ), + ft.Container( + content=ft.Text("Linear gradient with stops"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.LinearGradient( + begin=ft.Alignment.CENTER_LEFT, + end=ft.Alignment.CENTER_RIGHT, + tile_mode=ft.GradientTileMode.MIRROR, + stops=[0.1, 0.2, 1.0], + colors=[ + ft.Colors.RED, + ft.Colors.GREEN, + ft.Colors.BLUE, + ], + ), + ), + ft.Container( + content=ft.Text("Radial gradient"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.RadialGradient( + center=ft.Alignment(0.7, -0.6), + radius=0.2, + stops=[0.4, 1.0], + colors=["0xFFFFFF00", "0xFF0099FF"], + ), + ), + ft.Container( + content=ft.Text("Sweep gradient"), + padding=10, + alignment=ft.Alignment.CENTER, + width=200, + height=200, + border_radius=10, + gradient=ft.SweepGradient( + center=ft.Alignment.CENTER, + start_angle=0.0, + end_angle=math.pi * 2, + rotation=math.pi / 4, + stops=[0.0, 0.25, 0.5, 0.75, 1.0], + colors=[ + "0xFF4285F4", + "0xFF34A853", + "0xFFFBBC05", + "0xFFEA4335", + "0xFF4285F4", + ], + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/gradient/container/pyproject.toml b/sdk/python/examples/controls/core/types/gradient/container/pyproject.toml new file mode 100644 index 0000000000..daefa68277 --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-container" +version = "1.0.0" +description = "Demonstrates how Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Gradient" +controls = ["SafeArea", "Column", "Row", "Container", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/gradient/linear_gradient/container/main.py b/sdk/python/examples/controls/core/types/gradient/linear_gradient/container/main.py new file mode 100644 index 0000000000..faf1aaaf4e --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/linear_gradient/container/main.py @@ -0,0 +1,40 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=ft.BorderRadius.all(5), + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment(0.8, 1), + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + ), + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/gradient/linear_gradient/container/pyproject.toml b/sdk/python/examples/controls/core/types/gradient/linear_gradient/container/pyproject.toml new file mode 100644 index 0000000000..b6e2bac2dd --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/linear_gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-linear-gradient-container" +version = "1.0.0" +description = "Demonstrates how Linear Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "linear gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Linear Gradient" +controls = ["SafeArea", "Column", "Container", "BorderRadius"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["linear gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/gradient/linear_gradient/media/container.png b/sdk/python/examples/controls/core/types/gradient/linear_gradient/media/container.png new file mode 100644 index 0000000000..104af1221d Binary files /dev/null and b/sdk/python/examples/controls/core/types/gradient/linear_gradient/media/container.png differ diff --git a/sdk/python/examples/controls/core/types/gradient/radial_gradient/container/main.py b/sdk/python/examples/controls/core/types/gradient/radial_gradient/container/main.py new file mode 100644 index 0000000000..3777d923b9 --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/radial_gradient/container/main.py @@ -0,0 +1,28 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=ft.BorderRadius.all(5), + gradient=ft.RadialGradient( + center=ft.Alignment(0.7, -0.6), + radius=0.2, + colors=["0xFFFFFF00", "0xFF0099FF"], + stops=[0.4, 1.0], + ), + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/gradient/radial_gradient/container/pyproject.toml b/sdk/python/examples/controls/core/types/gradient/radial_gradient/container/pyproject.toml new file mode 100644 index 0000000000..c4b66640d3 --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/radial_gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-radial-gradient-container" +version = "1.0.0" +description = "Demonstrates how Radial Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "radial gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Radial Gradient" +controls = ["SafeArea", "Column", "Container", "BorderRadius"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["radial gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/gradient/radial_gradient/media/container.png b/sdk/python/examples/controls/core/types/gradient/radial_gradient/media/container.png new file mode 100644 index 0000000000..c0ae75a100 Binary files /dev/null and b/sdk/python/examples/controls/core/types/gradient/radial_gradient/media/container.png differ diff --git a/sdk/python/examples/controls/core/types/gradient/sweep_gradient/container/main.py b/sdk/python/examples/controls/core/types/gradient/sweep_gradient/container/main.py new file mode 100644 index 0000000000..cdc0b70e86 --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/sweep_gradient/container/main.py @@ -0,0 +1,37 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + width=150, + height=150, + border_radius=ft.BorderRadius.all(5), + gradient=ft.SweepGradient( + center=ft.Alignment.CENTER, + start_angle=0.0, + end_angle=math.pi * 2, + stops=[0.0, 0.25, 0.5, 0.75, 1.0], + colors=[ + "0xFF4285F4", + "0xFF34A853", + "0xFFFBBC05", + "0xFFEA4335", + "0xFF4285F4", + ], + ), + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/gradient/sweep_gradient/container/pyproject.toml b/sdk/python/examples/controls/core/types/gradient/sweep_gradient/container/pyproject.toml new file mode 100644 index 0000000000..969bca1f5e --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient/sweep_gradient/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-sweep-gradient-container" +version = "1.0.0" +description = "Demonstrates how Sweep Gradient values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["gradient", "sweep gradient", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Sweep Gradient" +controls = ["SafeArea", "Column", "Container", "BorderRadius"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["sweep gradient preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/gradient/sweep_gradient/media/container.png b/sdk/python/examples/controls/core/types/gradient/sweep_gradient/media/container.png new file mode 100644 index 0000000000..a12bce96c1 Binary files /dev/null and b/sdk/python/examples/controls/core/types/gradient/sweep_gradient/media/container.png differ diff --git a/sdk/python/examples/controls/core/types/gradient_tile_mode/showcase/main.py b/sdk/python/examples/controls/core/types/gradient_tile_mode/showcase/main.py new file mode 100644 index 0000000000..3ebfd0af4a --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient_tile_mode/showcase/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def showcase_card(mode: ft.GradientTileMode) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=120, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + gradient=ft.RadialGradient( + radius=0.22, + colors=[ft.Colors.PRIMARY, ft.Colors.AMBER_400], + tile_mode=mode, + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="GradientTileMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how gradients behave outside their defined " + "paint region." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in ft.GradientTileMode], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/gradient_tile_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/gradient_tile_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..59d3d26d7b --- /dev/null +++ b/sdk/python/examples/controls/core/types/gradient_tile_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-gradient-tile-mode-showcase" +version = "1.0.0" +description = "Compares Gradient Tile Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["gradient tile mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Gradient Tile Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/image_repeat/showcase/main.py b/sdk/python/examples/controls/core/types/image_repeat/showcase/main.py new file mode 100644 index 0000000000..c6a57acd17 --- /dev/null +++ b/sdk/python/examples/controls/core/types/image_repeat/showcase/main.py @@ -0,0 +1,59 @@ +import flet as ft + + +def showcase_card(repeat: ft.ImageRepeat) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(repeat.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=130, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.Image( + src="https://picsum.photos/id/237/200/300", + width=240, + height=130, + repeat=repeat, + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="ImageRepeat Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how an image fills uncovered space using repeat modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(repeat) for repeat in ft.ImageRepeat], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/image_repeat/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/image_repeat/showcase/pyproject.toml new file mode 100644 index 0000000000..b6771091fc --- /dev/null +++ b/sdk/python/examples/controls/core/types/image_repeat/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-image-repeat-showcase" +version = "1.0.0" +description = "Compares Image Repeat values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["image repeat", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Image Repeat showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Image", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/label_position/showcase/main.py b/sdk/python/examples/controls/core/types/label_position/showcase/main.py new file mode 100644 index 0000000000..b8b7ab0f05 --- /dev/null +++ b/sdk/python/examples/controls/core/types/label_position/showcase/main.py @@ -0,0 +1,69 @@ +import flet as ft + + +def showcase_card(label_position: ft.LabelPosition) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + controls=[ + ft.Text(label_position.name, weight=ft.FontWeight.BOLD), + ft.Checkbox( + label="Checkbox label", + value=True, + label_position=label_position, + ), + ft.RadioGroup( + content=ft.Row( + controls=[ + ft.Radio( + label=f"{i}", + value=f"{i}", + label_position=label_position, + ) + for i in range(1, 4) + ], + ) + ), + ft.Switch( + label="Switch label", + value=True, + label_position=label_position, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="LabelPosition Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare left/right label placement for form controls."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(label_position) + for label_position in ft.LabelPosition + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/label_position/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/label_position/showcase/pyproject.toml new file mode 100644 index 0000000000..5303edb6f6 --- /dev/null +++ b/sdk/python/examples/controls/core/types/label_position/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-label-position-showcase" +version = "1.0.0" +description = "Compares Label Position values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["label position", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Label Position showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Checkbox", "RadioGroup", "Row", "Radio"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/launch_mode/showcase/main.py b/sdk/python/examples/controls/core/types/launch_mode/showcase/main.py new file mode 100644 index 0000000000..ac43a8254c --- /dev/null +++ b/sdk/python/examples/controls/core/types/launch_mode/showcase/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + launcher = ft.UrlLauncher() + + def showcase_card(mode: ft.LaunchMode) -> ft.Container: + status = ft.Text("Click to check support on this platform.", size=11) + + async def check_support(): + try: + supported = await launcher.supports_launch_mode(mode) + closable = await launcher.supports_close_for_launch_mode(mode) + status.value = ( + f"supports_launch_mode={supported} / supports_close={closable}" + ) + except Exception as ex: + status.value = f"Error: {ex}" + status.update() + + return ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Check support", + icon=ft.Icons.CHECK_CIRCLE_OUTLINE, + on_click=lambda: page.run_task(check_support), + ), + status, + ], + ), + ) + + page.appbar = ft.AppBar(title="LaunchMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Check launch-mode support reported by the current platform." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in ft.LaunchMode], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/launch_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/launch_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..3a94debdd1 --- /dev/null +++ b/sdk/python/examples/controls/core/types/launch_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-launch-mode-showcase" +version = "1.0.0" +description = "Compares Launch Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["launch mode", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Launch Mode showcase" +controls = ["SafeArea", "Column", "UrlLauncher", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/list_tile_style/showcase/main.py b/sdk/python/examples/controls/core/types/list_tile_style/showcase/main.py new file mode 100644 index 0000000000..1005eb83bd --- /dev/null +++ b/sdk/python/examples/controls/core/types/list_tile_style/showcase/main.py @@ -0,0 +1,56 @@ +import flet as ft + + +def showcase_card(style: ft.ListTileStyle) -> ft.Container: + return ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(style.name, weight=ft.FontWeight.BOLD), + ft.Container( + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.ListTile( + style=style, + leading=ft.Icon(ft.Icons.PERSON), + title=ft.Text("Jane Doe"), + subtitle=ft.Text("Product Manager"), + trailing=ft.Icon(ft.Icons.CHEVRON_RIGHT), + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="ListTileStyle Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare list tile typography presets."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.ListTileStyle], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/list_tile_style/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/list_tile_style/showcase/pyproject.toml new file mode 100644 index 0000000000..d8fa6c03e5 --- /dev/null +++ b/sdk/python/examples/controls/core/types/list_tile_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-list-tile-style-showcase" +version = "1.0.0" +description = "Compares List Tile Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["list tile style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "List Tile Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "ListTile", "Icon", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/list_tile_title_alignment/showcase/main.py b/sdk/python/examples/controls/core/types/list_tile_title_alignment/showcase/main.py new file mode 100644 index 0000000000..64aa6dc654 --- /dev/null +++ b/sdk/python/examples/controls/core/types/list_tile_title_alignment/showcase/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +def showcase_card(alignment: ft.ListTileTitleAlignment) -> ft.Container: + return ft.Container( + width=380, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(alignment.name, weight=ft.FontWeight.BOLD), + ft.Container( + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.ListTile( + title_alignment=alignment, + leading=ft.CircleAvatar(content=ft.Text("JD")), + title=ft.Text("Jane Doe"), + subtitle=ft.Text( + "This subtitle helps visualize vertical alignment." + ), + is_three_line=True, + trailing=ft.Icon(ft.Icons.MORE_VERT), + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="ListTileTitleAlignment Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare leading/trailing alignment against title area."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) + for alignment in ft.ListTileTitleAlignment + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/list_tile_title_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/list_tile_title_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..730b62a190 --- /dev/null +++ b/sdk/python/examples/controls/core/types/list_tile_title_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-list-tile-title-alignment-showcase" +version = "1.0.0" +description = "Compares List Tile Title Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["list tile title alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "List Tile Title Alignment showcase" +controls = ["SafeArea", "Column", "Container", "Text", "ListTile", "CircleAvatar", "Icon", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/main_axis_alignment/showcase/main.py b/sdk/python/examples/controls/core/types/main_axis_alignment/showcase/main.py new file mode 100644 index 0000000000..ae73750d80 --- /dev/null +++ b/sdk/python/examples/controls/core/types/main_axis_alignment/showcase/main.py @@ -0,0 +1,74 @@ +import flet as ft + + +def dot(label: str) -> ft.Container: + return ft.Container( + width=36, + height=36, + border_radius=18, + bgcolor=ft.Colors.PRIMARY_CONTAINER, + alignment=ft.Alignment.CENTER, + content=ft.Text(label, size=12, color=ft.Colors.ON_PRIMARY_CONTAINER), + ) + + +def showcase_card(alignment: ft.MainAxisAlignment) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(alignment.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=250, + height=70, + padding=8, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.Row( + alignment=alignment, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[dot("1"), dot("2"), dot("3")], + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="MainAxisAlignment Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare horizontal distribution of children in a " + "fixed-width row." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) + for alignment in ft.MainAxisAlignment + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/main_axis_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/main_axis_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..5f322ef8bf --- /dev/null +++ b/sdk/python/examples/controls/core/types/main_axis_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-main-axis-alignment-showcase" +version = "1.0.0" +description = "Compares Main Axis Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["main axis alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Main Axis Alignment showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Row", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/margin/container/main.py b/sdk/python/examples/controls/core/types/margin/container/main.py new file mode 100644 index 0000000000..1f758862e8 --- /dev/null +++ b/sdk/python/examples/controls/core/types/margin/container/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Margin Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + spacing=0, + controls=[ + ft.Container( + content=ft.Button("container_1"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.all(10), + margin=ft.Margin.all(10), + width=200, + height=200, + ), + ft.Container( + content=ft.Button("container_2"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.all(20), + margin=ft.Margin.all(20), + width=200, + height=200, + ), + ft.Container( + content=ft.Button("container_3"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.symmetric(horizontal=10), + margin=ft.Margin.symmetric(vertical=10), + width=200, + height=200, + ), + ft.Container( + content=ft.Button("container_4"), + bgcolor=ft.Colors.AMBER, + # padding=ft.Padding.only(left=10), + margin=ft.Margin.only(left=10), + width=200, + height=200, + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/margin/container/pyproject.toml b/sdk/python/examples/controls/core/types/margin/container/pyproject.toml new file mode 100644 index 0000000000..068bfd937c --- /dev/null +++ b/sdk/python/examples/controls/core/types/margin/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-margin-container" +version = "1.0.0" +description = "Demonstrates how Margin values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["margin", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Margin" +controls = ["SafeArea", "Column", "Row", "Container", "Button", "Margin"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["margin preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/mouse_cursor/showcase/main.py b/sdk/python/examples/controls/core/types/mouse_cursor/showcase/main.py new file mode 100644 index 0000000000..fb4ab60f81 --- /dev/null +++ b/sdk/python/examples/controls/core/types/mouse_cursor/showcase/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def showcase_card(cursor: ft.MouseCursor) -> ft.GestureDetector: + return ft.GestureDetector( + mouse_cursor=cursor, + content=ft.Container( + width=250, + height=100, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=4, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(cursor.name, weight=ft.FontWeight.BOLD), + ], + ), + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="MouseCursor Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Hover each card to compare cursor styles. " + "Cursor rendering can vary by OS and browser.", + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(cursor) for cursor in ft.MouseCursor], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/mouse_cursor/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/mouse_cursor/showcase/pyproject.toml new file mode 100644 index 0000000000..608c178174 --- /dev/null +++ b/sdk/python/examples/controls/core/types/mouse_cursor/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-mouse-cursor-showcase" +version = "1.0.0" +description = "Compares Mouse Cursor values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["mouse cursor", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Mouse Cursor showcase" +controls = ["SafeArea", "Column", "GestureDetector", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/navigation_bar_label_behavior/showcase/main.py b/sdk/python/examples/controls/core/types/navigation_bar_label_behavior/showcase/main.py new file mode 100644 index 0000000000..7471161a3b --- /dev/null +++ b/sdk/python/examples/controls/core/types/navigation_bar_label_behavior/showcase/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def showcase_card(behavior: ft.NavigationBarLabelBehavior) -> ft.Container: + bar = ft.NavigationBar( + label_behavior=behavior, + selected_index=1, + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.HOME, label="Home"), + ft.NavigationBarDestination(icon=ft.Icons.SEARCH, label="Search"), + ft.NavigationBarDestination(icon=ft.Icons.PERSON, label="Profile"), + ], + ) + + return ft.Container( + width=380, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(behavior.name, weight=ft.FontWeight.BOLD), + bar, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="NavigationBarLabelBehavior Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare destination label visibility strategies."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(behavior) + for behavior in ft.NavigationBarLabelBehavior + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/navigation_bar_label_behavior/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/navigation_bar_label_behavior/showcase/pyproject.toml new file mode 100644 index 0000000000..e072faaad5 --- /dev/null +++ b/sdk/python/examples/controls/core/types/navigation_bar_label_behavior/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-navigation-bar-label-behavior-showcase" +version = "1.0.0" +description = "Compares Navigation Bar Label Behavior values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["navigation bar label behavior", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Navigation Bar Label Behavior showcase" +controls = ["SafeArea", "Column", "Container", "NavigationBar", "NavigationBarDestination", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/navigation_rail_label_type/showcase/main.py b/sdk/python/examples/controls/core/types/navigation_rail_label_type/showcase/main.py new file mode 100644 index 0000000000..7ad4568f5c --- /dev/null +++ b/sdk/python/examples/controls/core/types/navigation_rail_label_type/showcase/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def showcase_card(label_type: ft.NavigationRailLabelType) -> ft.Container: + rail = ft.NavigationRail( + width=100, + height=220, + selected_index=1, + label_type=label_type, + destinations=[ + ft.NavigationRailDestination(icon=ft.Icons.HOME, label="Home"), + ft.NavigationRailDestination(icon=ft.Icons.SEARCH, label="Search"), + ft.NavigationRailDestination(icon=ft.Icons.PERSON, label="Profile"), + ], + ) + + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(label_type.name, weight=ft.FontWeight.BOLD), + rail, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="NavigationRailLabelType Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare label visibility in compact navigation rail."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(t) for t in ft.NavigationRailLabelType], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/navigation_rail_label_type/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/navigation_rail_label_type/showcase/pyproject.toml new file mode 100644 index 0000000000..5d35a46208 --- /dev/null +++ b/sdk/python/examples/controls/core/types/navigation_rail_label_type/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-navigation-rail-label-type-showcase" +version = "1.0.0" +description = "Compares Navigation Rail Label Type values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["navigation rail label type", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Navigation Rail Label Type showcase" +controls = ["SafeArea", "Column", "Container", "NavigationRail", "NavigationRailDestination", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/orientation/showcase/main.py b/sdk/python/examples/controls/core/types/orientation/showcase/main.py new file mode 100644 index 0000000000..5edf88fd5e --- /dev/null +++ b/sdk/python/examples/controls/core/types/orientation/showcase/main.py @@ -0,0 +1,58 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def showcase_card(orientation: ft.Orientation) -> ft.Container: + picker = ft.TimePicker( + value=time(hour=10, minute=30), + help_text=f"{orientation.name} time picker", + orientation=orientation, + ) + + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(orientation.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open TimePicker", + icon=ft.Icons.ACCESS_TIME, + on_click=lambda _, p=picker: page.show_dialog(p), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="Orientation Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("TimePicker supports PORTRAIT and LANDSCAPE layouts."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(orientation) for orientation in ft.Orientation + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/orientation/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/orientation/showcase/pyproject.toml new file mode 100644 index 0000000000..f1a194f52e --- /dev/null +++ b/sdk/python/examples/controls/core/types/orientation/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-orientation-showcase" +version = "1.0.0" +description = "Compares Orientation values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["orientation", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Orientation showcase" +controls = ["SafeArea", "Column", "Container", "TimePicker", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/overlay_visibility_mode/showcase/main.py b/sdk/python/examples/controls/core/types/overlay_visibility_mode/showcase/main.py new file mode 100644 index 0000000000..7fcb7b0265 --- /dev/null +++ b/sdk/python/examples/controls/core/types/overlay_visibility_mode/showcase/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def showcase_card(mode: ft.OverlayVisibilityMode) -> ft.Container: + return ft.Container( + width=380, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + ft.Text("Prefix/suffix visibility (prefilled):", size=11), + ft.CupertinoTextField( + value="Flet", + placeholder_text="Search", + prefix=ft.Icon(ft.CupertinoIcons.SEARCH), + suffix=ft.Icon(ft.CupertinoIcons.MIC), + prefix_visibility_mode=mode, + suffix_visibility_mode=mode, + ), + ft.Text("Clear button visibility:", size=11), + ft.CupertinoTextField( + value="Clear me", + placeholder_text="Type text", + clear_button_visibility_mode=mode, + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="OverlayVisibilityMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare when Cupertino text field overlays appear."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(mode) for mode in ft.OverlayVisibilityMode + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/overlay_visibility_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/overlay_visibility_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..098dd6a9fa --- /dev/null +++ b/sdk/python/examples/controls/core/types/overlay_visibility_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-overlay-visibility-mode-showcase" +version = "1.0.0" +description = "Compares Overlay Visibility Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["overlay visibility mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Overlay Visibility Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "CupertinoTextField", "Icon", "CupertinoIcons", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/padding/container/main.py b/sdk/python/examples/controls/core/types/padding/container/main.py new file mode 100644 index 0000000000..053c724922 --- /dev/null +++ b/sdk/python/examples/controls/core/types/padding/container/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Containers with different padding" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Container( + content=ft.Button("container_1"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.all(10), + width=150, + height=150, + ), + ft.Container( + content=ft.Button("container_2"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.all(20), + width=150, + height=150, + ), + ft.Container( + content=ft.Button("container_3"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.symmetric(horizontal=10), + width=150, + height=150, + ), + ft.Container( + content=ft.Button("container_4"), + bgcolor=ft.Colors.AMBER, + padding=ft.Padding.only(left=10), + width=150, + height=150, + ), + ] + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/padding/container/pyproject.toml b/sdk/python/examples/controls/core/types/padding/container/pyproject.toml new file mode 100644 index 0000000000..8a9df35de8 --- /dev/null +++ b/sdk/python/examples/controls/core/types/padding/container/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-padding-container" +version = "1.0.0" +description = "Demonstrates how Padding values change container presentation and layout." +requires-python = ">=3.10" +keywords = ["padding", "container"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Padding" +controls = ["SafeArea", "Column", "Row", "Container", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["padding preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/padding/media/container.png b/sdk/python/examples/controls/core/types/padding/media/container.png new file mode 100644 index 0000000000..9785f99d04 Binary files /dev/null and b/sdk/python/examples/controls/core/types/padding/media/container.png differ diff --git a/sdk/python/examples/controls/core/types/paint_gradient/canvas_paint/main.py b/sdk/python/examples/controls/core/types/paint_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..399cae0f65 --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/canvas_paint/main.py @@ -0,0 +1,78 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + cv.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + cv.Path( + elements=[ + cv.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/paint_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/core/types/paint_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..8fd9712300 --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Paint Gradient" +controls = ["SafeArea", "Column", "Canvas", "Rect", "Circle", "Path"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py b/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..e318a22fe6 --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/canvas_paint/main.py @@ -0,0 +1,38 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..38e00a14a6 --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-paint-linear-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Linear Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "paint linear gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Paint Linear Gradient" +controls = ["SafeArea", "Column", "Canvas", "Rect"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/media/canvas_paint.png b/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/media/canvas_paint.png new file mode 100644 index 0000000000..9a0e56ee47 Binary files /dev/null and b/sdk/python/examples/controls/core/types/paint_gradient/paint_linear_gradient/media/canvas_paint.png differ diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py b/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..6e8470470a --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/canvas_paint/main.py @@ -0,0 +1,36 @@ +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..f92263b71b --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-paint-radial-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Radial Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "paint radial gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Paint Radial Gradient" +controls = ["SafeArea", "Column", "Canvas", "Circle"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/media/canvas_paint.png b/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/media/canvas_paint.png new file mode 100644 index 0000000000..354919e3c0 Binary files /dev/null and b/sdk/python/examples/controls/core/types/paint_gradient/paint_radial_gradient/media/canvas_paint.png differ diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py b/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py new file mode 100644 index 0000000000..f8c6b76e4a --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/canvas_paint/main.py @@ -0,0 +1,50 @@ +import math + +import flet as ft +import flet.canvas as cv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + cv.Canvas( + width=float("inf"), + expand=True, + shapes=[ + cv.Path( + elements=[ + cv.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml b/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml new file mode 100644 index 0000000000..88269b060a --- /dev/null +++ b/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/canvas_paint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-paint-gradient-paint-sweep-gradient-canvas-paint" +version = "1.0.0" +description = "Draws a canvas preview using Paint Sweep Gradient gradient settings and paint objects." +requires-python = ">=3.10" +keywords = ["paint gradient", "paint sweep gradient", "canvas paint"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Paint Sweep Gradient" +controls = ["SafeArea", "Column", "Canvas", "Path"] +layout_pattern = "canvas" +complexity = "basic" +features = ["canvas drawing", "gradient paint preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/media/canvas_paint.png b/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/media/canvas_paint.png new file mode 100644 index 0000000000..d07c5d3093 Binary files /dev/null and b/sdk/python/examples/controls/core/types/paint_gradient/paint_sweep_gradient/media/canvas_paint.png differ diff --git a/sdk/python/examples/controls/core/types/painting_style/showcase/main.py b/sdk/python/examples/controls/core/types/painting_style/showcase/main.py new file mode 100644 index 0000000000..7166d110cd --- /dev/null +++ b/sdk/python/examples/controls/core/types/painting_style/showcase/main.py @@ -0,0 +1,61 @@ +import flet as ft +import flet.canvas as cv + + +def showcase_card(style: ft.PaintingStyle) -> ft.Container: + return ft.Container( + width=250, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(style.name, weight=ft.FontWeight.BOLD), + cv.Canvas( + width=240, + height=110, + shapes=[ + cv.Circle( + x=120, + y=55, + radius=34, + paint=ft.Paint( + style=style, + stroke_width=10, + color=ft.Colors.PRIMARY, + ), + ) + ], + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="PaintingStyle Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare filled vs outlined rendering for the same shape."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(style) for style in ft.PaintingStyle], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/painting_style/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/painting_style/showcase/pyproject.toml new file mode 100644 index 0000000000..532a039433 --- /dev/null +++ b/sdk/python/examples/controls/core/types/painting_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-painting-style-showcase" +version = "1.0.0" +description = "Compares Painting Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["painting style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Painting Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Circle", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/point_mode/showcase/main.py b/sdk/python/examples/controls/core/types/point_mode/showcase/main.py new file mode 100644 index 0000000000..cd3d733724 --- /dev/null +++ b/sdk/python/examples/controls/core/types/point_mode/showcase/main.py @@ -0,0 +1,71 @@ +import flet as ft +import flet.canvas as cv + +POINTS = [ + (25, 75), + (70, 30), + (115, 75), + (160, 30), + (205, 75), +] + + +def showcase_card(mode: cv.PointMode) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(mode.name, weight=ft.FontWeight.BOLD), + cv.Canvas( + width=240, + height=110, + shapes=[ + cv.Points( + points=POINTS, + point_mode=mode, + paint=ft.Paint( + color=ft.Colors.PRIMARY, + stroke_width=12, + stroke_cap=ft.StrokeCap.ROUND, + ), + ) + ], + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="PointMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how the same coordinate list is interpreted " + "by each point mode." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(mode) for mode in cv.PointMode], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/point_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/point_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..7b979c7992 --- /dev/null +++ b/sdk/python/examples/controls/core/types/point_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-point-mode-showcase" +version = "1.0.0" +description = "Compares Point Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["point mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Point Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Points", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/popup_menu_position/showcase/main.py b/sdk/python/examples/controls/core/types/popup_menu_position/showcase/main.py new file mode 100644 index 0000000000..b04aa79b57 --- /dev/null +++ b/sdk/python/examples/controls/core/types/popup_menu_position/showcase/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def showcase_card(position: ft.PopupMenuPosition) -> ft.Container: + menu = ft.PopupMenuButton( + menu_position=position, + icon=ft.Text("Click me to open menu", color=ft.Colors.BLUE), + items=[ + ft.PopupMenuItem(icon=ft.Icons.EDIT, content="Rename"), + ft.PopupMenuItem(icon=ft.Icons.CONTENT_COPY, content="Duplicate"), + ft.PopupMenuItem(icon=ft.Icons.DELETE, content="Delete"), + ], + ) + + return ft.Container( + width=300, + height=220, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text(position.name, weight=ft.FontWeight.BOLD), + menu, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="PopupMenuPosition Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open each popup menu to compare their positioning."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(position) for position in ft.PopupMenuPosition + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/popup_menu_position/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/popup_menu_position/showcase/pyproject.toml new file mode 100644 index 0000000000..06a4d50b26 --- /dev/null +++ b/sdk/python/examples/controls/core/types/popup_menu_position/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-popup-menu-position-showcase" +version = "1.0.0" +description = "Compares Popup Menu Position values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["popup menu position", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Popup Menu Position showcase" +controls = ["SafeArea", "Column", "Container", "PopupMenuButton", "Text", "PopupMenuItem", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/scroll_bar/showcase/main.py b/sdk/python/examples/controls/core/types/scroll_bar/showcase/main.py new file mode 100644 index 0000000000..ad2c09a7a9 --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_bar/showcase/main.py @@ -0,0 +1,211 @@ +from typing import Optional + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.appbar = ft.AppBar(title="Scrollbar Dataclass Showcase") + + def get_scrollbar() -> ft.Scrollbar: + def str_as_bool(value: Optional[str]) -> Optional[bool]: + return True if value == "true" else False if value == "false" else None + + return ft.Scrollbar( + thumb_visibility=str_as_bool(thumb_visibility.value), + track_visibility=str_as_bool(track_visibility.value), + interactive=str_as_bool(interactive.value), + thickness=thickness_value.value if use_thickness.value else None, + radius=radius_value.value if use_radius.value else None, + orientation=None + if orientation.value == "none" + else ft.ScrollbarOrientation(orientation.value), + ) + + def get_preview_content(scrollbar: ft.Scrollbar) -> tuple[str, ft.Control]: + selected_orientation = scrollbar.orientation + is_horizontal = selected_orientation in ( + ft.ScrollbarOrientation.TOP, + ft.ScrollbarOrientation.BOTTOM, + ) + if is_horizontal: + return ( + "Horizontal preview (TOP/BOTTOM orientation)", + ft.Row( + spacing=8, + scroll=scrollbar, + controls=[ + ft.Container( + width=110, + height=80, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + alignment=ft.Alignment.CENTER, + content=ft.Text(f"Tile {i + 1}"), + ) + for i in range(18) + ], + ), + ) + + return ( + "Vertical preview (None/LEFT/RIGHT orientation)", + ft.Column( + spacing=4, + scroll=scrollbar, + controls=[ft.Text(f"Item {i + 1}") for i in range(40)], + ), + ) + + def update_preview(): + thickness_value.disabled = not use_thickness.value + radius_value.disabled = not use_radius.value + + scrollbar = get_scrollbar() + title, content = get_preview_content(scrollbar) + preview_title.value = title + preview_viewport.content = content + page.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Interactive playground for the Scrollbar dataclass. " + "Change each property and inspect the live result." + ), + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + controls=[ + ft.Text( + "Configuration", weight=ft.FontWeight.BOLD + ), + thumb_visibility := ft.Dropdown( + label="thumb_visibility", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (theme default)" + ), + ft.DropdownOption("true", "True"), + ft.DropdownOption("false", "False"), + ], + ), + track_visibility := ft.Dropdown( + label="track_visibility", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (theme default)" + ), + ft.DropdownOption("true", "True"), + ft.DropdownOption("false", "False"), + ], + ), + interactive := ft.Dropdown( + label="interactive", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (platform default)" + ), + ft.DropdownOption("true", "True"), + ft.DropdownOption("false", "False"), + ], + ), + orientation := ft.Dropdown( + label="orientation", + value="none", + on_select=update_preview, + options=[ + ft.DropdownOption( + "none", "None (auto side)" + ) + ] + + [ + ft.DropdownOption(o.value, o.name) + for o in ft.ScrollbarOrientation + ], + ), + use_thickness := ft.Checkbox( + label="Set thickness", + value=False, + on_change=update_preview, + ), + thickness_value := ft.Slider( + min=0, + max=20, + divisions=20, + value=8, + label="{value}", + on_change=update_preview, + ), + use_radius := ft.Checkbox( + label="Set radius", + value=False, + on_change=update_preview, + ), + radius_value := ft.Slider( + min=0, + max=20, + divisions=20, + value=8, + label="{value}", + on_change=update_preview, + ), + ], + ), + ), + ft.Container( + width=420, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=10, + controls=[ + ft.Text( + "Live preview", weight=ft.FontWeight.BOLD + ), + preview_title := ft.Text( + weight=ft.FontWeight.BOLD + ), + preview_viewport := ft.Container( + height=260, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + ), + ], + ), + ), + ], + ), + ], + ), + ) + ) + + update_preview() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/scroll_bar/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/scroll_bar/showcase/pyproject.toml new file mode 100644 index 0000000000..d2b883974c --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_bar/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-bar-showcase" +version = "1.0.0" +description = "Compares Scroll Bar values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll bar", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Bar showcase" +controls = ["SafeArea", "Column", "AppBar", "Scrollbar", "Row", "Container", "Text", "Dropdown"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/scroll_bar_orientation/showcase/main.py b/sdk/python/examples/controls/core/types/scroll_bar_orientation/showcase/main.py new file mode 100644 index 0000000000..f4705443e0 --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_bar_orientation/showcase/main.py @@ -0,0 +1,99 @@ +import flet as ft + + +def showcase_card(orientation: ft.ScrollbarOrientation) -> ft.Container: + is_vertical = orientation in ( + ft.ScrollbarOrientation.LEFT, + ft.ScrollbarOrientation.RIGHT, + ) + scrollbar = ft.Scrollbar( + orientation=orientation, + thumb_visibility=True, + track_visibility=True, + thickness=10, + radius=8, + ) + + if is_vertical: + viewport = ft.Container( + height=220, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + content=ft.Column( + spacing=4, + scroll=scrollbar, + controls=[ft.Text(f"Item {i + 1}") for i in range(35)], + ), + ) + else: + viewport = ft.Container( + height=130, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + content=ft.Row( + spacing=8, + scroll=scrollbar, + controls=[ + ft.Container( + width=84, + height=72, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + alignment=ft.Alignment.CENTER, + content=ft.Text(f"{i + 1}"), + ) + for i in range(20) + ], + ), + ) + + return ft.Container( + width=330, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(orientation.name, weight=ft.FontWeight.BOLD), + viewport, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="ScrollbarOrientation Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "LEFT/RIGHT apply to vertical scrollables, TOP/BOTTOM apply to " + "horizontal scrollables.", + ), + ft.Row( + wrap=True, + spacing=12, + run_spacing=12, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(orientation) + for orientation in ft.ScrollbarOrientation + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/scroll_bar_orientation/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/scroll_bar_orientation/showcase/pyproject.toml new file mode 100644 index 0000000000..64bf8ca97a --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_bar_orientation/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-bar-orientation-showcase" +version = "1.0.0" +description = "Compares Scroll Bar Orientation values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll bar orientation", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Bar Orientation showcase" +controls = ["SafeArea", "Column", "Container", "Scrollbar", "Text", "Row", "AppBar"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/scroll_direction/showcase/main.py b/sdk/python/examples/controls/core/types/scroll_direction/showcase/main.py new file mode 100644 index 0000000000..b3294e3e50 --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_direction/showcase/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + counts = {direction: 0 for direction in ft.ScrollDirection} + count_labels = { + direction: ft.Text(f"{direction.name}: 0") for direction in ft.ScrollDirection + } + + def on_scroll(e: ft.OnScrollEvent): + if e.event_type == ft.ScrollType.USER and e.direction is not None: + counts[e.direction] += 1 + count_labels[ + e.direction + ].value = f"{e.direction.name}: {counts[e.direction]}" + last.value = f"Last USER direction: {e.direction.name}" + for label in count_labels.values(): + label.update() + last.update() + + page.appbar = ft.AppBar(title="ScrollDirection Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Scroll the list and watch USER direction notifications."), + last := ft.Text("Last USER direction: none"), + ft.Row( + wrap=True, + spacing=10, + controls=[count_labels[d] for d in ft.ScrollDirection], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Container( + width=360, + height=240, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + content=ft.Column( + scroll=ft.ScrollMode.ALWAYS, + on_scroll=on_scroll, + controls=[ + ft.Text(f"Scrollable item {i + 1}") for i in range(60) + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/scroll_direction/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/scroll_direction/showcase/pyproject.toml new file mode 100644 index 0000000000..972a8e79c0 --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_direction/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-direction-showcase" +version = "1.0.0" +description = "Compares Scroll Direction values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll direction", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Direction showcase" +controls = ["SafeArea", "Column", "Text", "OnScrollEvent", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/scroll_mode/showcase/main.py b/sdk/python/examples/controls/core/types/scroll_mode/showcase/main.py new file mode 100644 index 0000000000..28fb6062ac --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_mode/showcase/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def showcase_card(scroll_mode: ft.ScrollMode) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(scroll_mode.name, weight=ft.FontWeight.BOLD), + ft.Text("Scroll inside this panel", size=12), + ft.Container( + height=170, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + padding=8, + content=ft.Column( + spacing=4, + scroll=scroll_mode, + controls=[ft.Text(f"Item {i + 1}") for i in range(24)], + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="ScrollMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare scrollbar visibility and scrolling behavior modes." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(scroll_mode) for scroll_mode in ft.ScrollMode + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/scroll_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/scroll_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..a1f07d9d88 --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-mode-showcase" +version = "1.0.0" +description = "Compares Scroll Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/scroll_type/showcase/main.py b/sdk/python/examples/controls/core/types/scroll_type/showcase/main.py new file mode 100644 index 0000000000..919aa2a67a --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_type/showcase/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + counts = {event_type: 0 for event_type in ft.ScrollType} + count_labels = { + event_type: ft.Text(f"{event_type.name}: 0") for event_type in ft.ScrollType + } + + def on_scroll(e: ft.OnScrollEvent): + counts[e.event_type] += 1 + count_labels[ + e.event_type + ].value = f"{e.event_type.name}: {counts[e.event_type]}" + last.value = ( + f"Last event: {e.event_type.name}, pixels={round(e.pixels, 1)}" + f"{', direction=' if e.direction else ''}" + ) + for label in count_labels.values(): + label.update() + last.update() + + page.appbar = ft.AppBar(title="ScrollType Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Scroll the list to generate start/update/user/end " + "notifications." + ), + last := ft.Text(), + ft.Row( + wrap=True, + spacing=10, + controls=[count_labels[t] for t in ft.ScrollType], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Container( + width=360, + height=240, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + padding=8, + content=ft.Column( + scroll=ft.ScrollMode.ALWAYS, + on_scroll=on_scroll, + controls=[ + ft.Text(f"Scrollable item {i + 1}") for i in range(60) + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/scroll_type/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/scroll_type/showcase/pyproject.toml new file mode 100644 index 0000000000..b18761c9c1 --- /dev/null +++ b/sdk/python/examples/controls/core/types/scroll_type/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-scroll-type-showcase" +version = "1.0.0" +description = "Compares Scroll Type values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["scroll type", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Scroll Type showcase" +controls = ["SafeArea", "Column", "Text", "OnScrollEvent", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/slider_interaction/showcase/main.py b/sdk/python/examples/controls/core/types/slider_interaction/showcase/main.py new file mode 100644 index 0000000000..1f10f9589c --- /dev/null +++ b/sdk/python/examples/controls/core/types/slider_interaction/showcase/main.py @@ -0,0 +1,67 @@ +import flet as ft + + +def showcase_card(interaction: ft.SliderInteraction) -> ft.Container: + value_text = ft.Text("Value: 50") + + def on_change(e: ft.Event[ft.Slider]): + value_text.value = f"Value: {round(e.control.value)}" + value_text.update() + + return ft.Container( + width=340, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(interaction.name, weight=ft.FontWeight.BOLD), + value_text, + ft.Container( + width=260, + padding=ft.Padding.symmetric(horizontal=8), + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.Slider( + min=0, + max=100, + value=50, + divisions=20, + interaction=interaction, + on_change=on_change, + ), + ), + ft.Text("Try tapping track and dragging thumb.", size=11), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="SliderInteraction Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare which gestures are accepted by each slider mode."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(i) for i in ft.SliderInteraction], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/slider_interaction/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/slider_interaction/showcase/pyproject.toml new file mode 100644 index 0000000000..cdfaaf317e --- /dev/null +++ b/sdk/python/examples/controls/core/types/slider_interaction/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-slider-interaction-showcase" +version = "1.0.0" +description = "Compares Slider Interaction values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["slider interaction", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Slider Interaction showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Slider", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/snack_bar_behavior/showcase/main.py b/sdk/python/examples/controls/core/types/snack_bar_behavior/showcase/main.py new file mode 100644 index 0000000000..b8ef114c9b --- /dev/null +++ b/sdk/python/examples/controls/core/types/snack_bar_behavior/showcase/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def open_snack(behavior: ft.SnackBarBehavior): + page.show_dialog( + ft.SnackBar( + content=ft.Text(f"Behavior: {behavior.name}"), + behavior=behavior, + margin=ft.Margin.only(bottom=100), + action=ft.SnackBarAction(label="Close"), + ) + ) + + def showcase_card(behavior: ft.SnackBarBehavior) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(behavior.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open SnackBar", + icon=ft.Icons.MESSAGE, + on_click=lambda _, b=behavior: open_snack(b), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="SnackBarBehavior Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare snack bar placement: fixed vs floating."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(behavior) for behavior in ft.SnackBarBehavior + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/snack_bar_behavior/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/snack_bar_behavior/showcase/pyproject.toml new file mode 100644 index 0000000000..7318ebddd3 --- /dev/null +++ b/sdk/python/examples/controls/core/types/snack_bar_behavior/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-snack-bar-behavior-showcase" +version = "1.0.0" +description = "Compares Snack Bar Behavior values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["snack bar behavior", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Snack Bar Behavior showcase" +controls = ["SafeArea", "Column", "SnackBar", "Text", "Margin", "SnackBarAction", "Container", "Button"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/stroke_cap/showcase/main.py b/sdk/python/examples/controls/core/types/stroke_cap/showcase/main.py new file mode 100644 index 0000000000..1629021e79 --- /dev/null +++ b/sdk/python/examples/controls/core/types/stroke_cap/showcase/main.py @@ -0,0 +1,78 @@ +import flet as ft +import flet.canvas as cv + + +def showcase_card(stroke_cap: ft.StrokeCap) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(stroke_cap.name, weight=ft.FontWeight.BOLD), + cv.Canvas( + width=240, + height=90, + shapes=[ + cv.Line( + x1=40, + y1=45, + x2=200, + y2=45, + paint=ft.Paint( + stroke_width=24, + color=ft.Colors.PRIMARY, + stroke_cap=stroke_cap, + ), + ), + cv.Line( + x1=40, + y1=16, + x2=40, + y2=74, + paint=ft.Paint(stroke_width=2, color=ft.Colors.RED), + ), + cv.Line( + x1=200, + y1=16, + x2=200, + y2=74, + paint=ft.Paint(stroke_width=2, color=ft.Colors.RED), + ), + ], + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="StrokeCap Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare line endings for each StrokeCap value."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(stroke_cap) for stroke_cap in ft.StrokeCap + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/stroke_cap/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/stroke_cap/showcase/pyproject.toml new file mode 100644 index 0000000000..193d6bf26f --- /dev/null +++ b/sdk/python/examples/controls/core/types/stroke_cap/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-stroke-cap-showcase" +version = "1.0.0" +description = "Compares Stroke Cap values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["stroke cap", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Stroke Cap showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Line", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/stroke_join/showcase/main.py b/sdk/python/examples/controls/core/types/stroke_join/showcase/main.py new file mode 100644 index 0000000000..57a5bea667 --- /dev/null +++ b/sdk/python/examples/controls/core/types/stroke_join/showcase/main.py @@ -0,0 +1,67 @@ +import flet as ft +import flet.canvas as cv + + +def showcase_card(stroke_join: ft.StrokeJoin) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(stroke_join.name, weight=ft.FontWeight.BOLD), + cv.Canvas( + width=240, + height=120, + shapes=[ + cv.Path( + elements=[ + cv.Path.MoveTo(40, 95), + cv.Path.LineTo(120, 25), + cv.Path.LineTo(200, 95), + ], + paint=ft.Paint( + style=ft.PaintingStyle.STROKE, + stroke_width=24, + color=ft.Colors.PRIMARY, + stroke_cap=ft.StrokeCap.BUTT, + stroke_join=stroke_join, + ), + ) + ], + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="StrokeJoin Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare corner rendering for each StrokeJoin value."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(stroke_join) for stroke_join in ft.StrokeJoin + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/stroke_join/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/stroke_join/showcase/pyproject.toml new file mode 100644 index 0000000000..b7a1190591 --- /dev/null +++ b/sdk/python/examples/controls/core/types/stroke_join/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-stroke-join-showcase" +version = "1.0.0" +description = "Compares Stroke Join values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["stroke join", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Canvas"] + +[tool.flet.metadata] +title = "Stroke Join showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Canvas", "Path", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/tab_alignment/showcase/main.py b/sdk/python/examples/controls/core/types/tab_alignment/showcase/main.py new file mode 100644 index 0000000000..89d73b37d5 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tab_alignment/showcase/main.py @@ -0,0 +1,77 @@ +import flet as ft + + +def showcase_card(alignment: ft.TabAlignment) -> ft.Container: + scrollable = alignment != ft.TabAlignment.FILL + tabs_count = 4 + + tab_bar = ft.TabBar( + scrollable=scrollable, + tab_alignment=alignment, + tabs=[ft.Tab(label=f"Tab {i + 1}") for i in range(tabs_count)], + ) + + tab_view = ft.Container( + height=70, + alignment=ft.Alignment.CENTER, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.TabBarView( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text(f"View {i + 1}"), + ) + for i in range(tabs_count) + ] + ), + ) + + return ft.Container( + width=380, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(alignment.name, weight=ft.FontWeight.BOLD), + ft.Tabs( + length=tabs_count, + selected_index=1, + content=ft.Column(spacing=8, controls=[tab_bar, tab_view]), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TabAlignment Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare how tabs are positioned within the tab bar."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(alignment) for alignment in ft.TabAlignment + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/tab_alignment/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/tab_alignment/showcase/pyproject.toml new file mode 100644 index 0000000000..c6ad799038 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tab_alignment/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tab-alignment-showcase" +version = "1.0.0" +description = "Compares Tab Alignment values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tab alignment", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Tabs"] + +[tool.flet.metadata] +title = "Tab Alignment showcase" +controls = ["SafeArea", "Column", "Container", "TabBar", "Tab", "TabBarView", "Text", "Tabs"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/tab_bar_indicator_size/showcase/main.py b/sdk/python/examples/controls/core/types/tab_bar_indicator_size/showcase/main.py new file mode 100644 index 0000000000..76b09a4ba7 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tab_bar_indicator_size/showcase/main.py @@ -0,0 +1,87 @@ +import flet as ft + + +def showcase_card(indicator_size: ft.TabBarIndicatorSize) -> ft.Container: + tabs_count = 3 + + tab_bar = ft.TabBar( + indicator_size=indicator_size, + indicator=ft.UnderlineTabIndicator( + border_side=ft.BorderSide(width=4, color=ft.Colors.PRIMARY), + insets=ft.Padding.only(bottom=3), + ), + tabs=[ + ft.Tab(label="A"), + ft.Tab(label="Long Label"), + ft.Tab(label="Mid"), + ], + ) + + tab_view = ft.Container( + height=70, + alignment=ft.Alignment.CENTER, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.TabBarView( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text(f"View {i + 1}"), + ) + for i in range(tabs_count) + ] + ), + ) + + return ft.Container( + width=380, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(indicator_size.name, weight=ft.FontWeight.BOLD), + ft.Tabs( + length=tabs_count, + selected_index=1, + content=ft.Column(spacing=8, controls=[tab_bar, tab_view]), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TabBarIndicatorSize Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare indicator width when matching tab bounds vs " + "label bounds." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(indicator_size) + for indicator_size in ft.TabBarIndicatorSize + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/tab_bar_indicator_size/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/tab_bar_indicator_size/showcase/pyproject.toml new file mode 100644 index 0000000000..69e5d58ca8 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tab_bar_indicator_size/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tab-bar-indicator-size-showcase" +version = "1.0.0" +description = "Compares Tab Bar Indicator Size values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tab bar indicator size", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Tabs"] + +[tool.flet.metadata] +title = "Tab Bar Indicator Size showcase" +controls = ["SafeArea", "Column", "Container", "TabBar", "UnderlineTabIndicator", "Tab", "TabBarView", "Text"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/tab_indicator_animation/showcase/main.py b/sdk/python/examples/controls/core/types/tab_indicator_animation/showcase/main.py new file mode 100644 index 0000000000..cd4faea466 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tab_indicator_animation/showcase/main.py @@ -0,0 +1,84 @@ +import flet as ft + + +def showcase_card(animation: ft.TabIndicatorAnimation) -> ft.Container: + tabs_count = 3 + + tab_bar = ft.TabBar( + indicator_animation=animation, + indicator=ft.UnderlineTabIndicator( + border_side=ft.BorderSide(width=4, color=ft.Colors.PRIMARY), + insets=ft.Padding.only(bottom=3), + ), + tabs=[ + ft.Tab(label="Home"), + ft.Tab(label="Search"), + ft.Tab(label="Profile"), + ], + ) + + tab_view = ft.Container( + height=70, + alignment=ft.Alignment.CENTER, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.TabBarView( + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text(f"View {i + 1}"), + ) + for i in range(tabs_count) + ] + ), + ) + + return ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(animation.name, weight=ft.FontWeight.BOLD), + ft.Tabs( + length=tabs_count, + selected_index=1, + content=ft.Column(spacing=8, controls=[tab_bar, tab_view]), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TabIndicatorAnimation Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Click tabs to compare indicator movement animation."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(animation) + for animation in ft.TabIndicatorAnimation + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/tab_indicator_animation/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/tab_indicator_animation/showcase/pyproject.toml new file mode 100644 index 0000000000..95e671753c --- /dev/null +++ b/sdk/python/examples/controls/core/types/tab_indicator_animation/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tab-indicator-animation-showcase" +version = "1.0.0" +description = "Compares Tab Indicator Animation values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tab indicator animation", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/Tabs"] + +[tool.flet.metadata] +title = "Tab Indicator Animation showcase" +controls = ["SafeArea", "Column", "Container", "TabBar", "UnderlineTabIndicator", "Tab", "TabBarView", "Text"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/text_align/showcase/main.py b/sdk/python/examples/controls/core/types/text_align/showcase/main.py new file mode 100644 index 0000000000..5ecc9fdfba --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_align/showcase/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def showcase_card(text_align: ft.TextAlign) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(text_align.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=130, + padding=10, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.Text( + text_align=text_align, + value="Flet helps you build cross-platform Python apps from one codebase.", # noqa: E501 + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TextAlign Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare horizontal text alignment modes in the same " + "text block." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(text_align) for text_align in ft.TextAlign + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/text_align/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/text_align/showcase/pyproject.toml new file mode 100644 index 0000000000..256bdd58fb --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_align/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-align-showcase" +version = "1.0.0" +description = "Compares Text Align values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text align", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Text Align showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/text_capitalization/showcase/main.py b/sdk/python/examples/controls/core/types/text_capitalization/showcase/main.py new file mode 100644 index 0000000000..c0679c974a --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_capitalization/showcase/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +def showcase_card(cap: ft.TextCapitalization) -> ft.Container: + field = ft.TextField( + width=260, + label="Type here", + capitalization=cap, + border=ft.InputBorder.OUTLINE, + ) + + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(cap.name, weight=ft.FontWeight.BOLD), + field, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TextCapitalization Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare keyboard capitalization preferences for text fields." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(c) for c in ft.TextCapitalization], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/text_capitalization/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/text_capitalization/showcase/pyproject.toml new file mode 100644 index 0000000000..f39f115902 --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_capitalization/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-capitalization-showcase" +version = "1.0.0" +description = "Compares Text Capitalization values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text capitalization", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Text Capitalization showcase" +controls = ["SafeArea", "Column", "Container", "TextField", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/text_decoration_style/showcase/main.py b/sdk/python/examples/controls/core/types/text_decoration_style/showcase/main.py new file mode 100644 index 0000000000..fea90b1a74 --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_decoration_style/showcase/main.py @@ -0,0 +1,64 @@ +import flet as ft + + +def showcase_card(style: ft.TextDecorationStyle) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(style.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=240, + height=80, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + alignment=ft.Alignment.CENTER, + content=ft.Text( + "Decorated text sample", + style=ft.TextStyle( + size=22, + decoration=ft.TextDecoration.UNDERLINE, + decoration_style=style, + decoration_thickness=2.4, + decoration_color=ft.Colors.PRIMARY, + ), + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TextDecorationStyle Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare underline rendering for each decoration style."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(style) for style in ft.TextDecorationStyle + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/text_decoration_style/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/text_decoration_style/showcase/pyproject.toml new file mode 100644 index 0000000000..a4c5892825 --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_decoration_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-decoration-style-showcase" +version = "1.0.0" +description = "Compares Text Decoration Style values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text decoration style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Text Decoration Style showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/text_overflow/showcase/main.py b/sdk/python/examples/controls/core/types/text_overflow/showcase/main.py new file mode 100644 index 0000000000..461c94e0dc --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_overflow/showcase/main.py @@ -0,0 +1,61 @@ +import flet as ft + + +def showcase_card(overflow: ft.TextOverflow) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(overflow.name, weight=ft.FontWeight.BOLD), + ft.Container( + width=250, + height=46, + padding=8, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=8, + bgcolor=ft.Colors.SURFACE, + content=ft.Text( + "The quick brown fox jumps over the lazy dog near the Flet bridge.", # noqa: E501 + max_lines=1, + overflow=overflow, + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TextOverflow Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare how one-line text behaves when content exceeds width." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(overflow) for overflow in ft.TextOverflow + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/text_overflow/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/text_overflow/showcase/pyproject.toml new file mode 100644 index 0000000000..7d7931aec2 --- /dev/null +++ b/sdk/python/examples/controls/core/types/text_overflow/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-text-overflow-showcase" +version = "1.0.0" +description = "Compares Text Overflow values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["text overflow", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Text Overflow showcase" +controls = ["SafeArea", "Column", "Container", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/theme_animation_style/showcase/main.py b/sdk/python/examples/controls/core/types/theme_animation_style/showcase/main.py new file mode 100644 index 0000000000..4b6b1379f9 --- /dev/null +++ b/sdk/python/examples/controls/core/types/theme_animation_style/showcase/main.py @@ -0,0 +1,64 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + custom_style = ft.AnimationStyle( + duration=ft.Duration(seconds=2), + curve=ft.AnimationCurve.EASE_IN_OUT_CUBIC, + ) + + def apply_style(value: str): + if value == "default": + page.theme_animation_style = None + elif value == "custom": + page.theme_animation_style = custom_style + else: + page.theme_animation_style = ft.AnimationStyle.no_animation() + page.update() + + def handle_style_change(e: ft.Event[ft.SegmentedButton]): + apply_style(e.control.selected[0]) + + def handle_theme_toggle(e: ft.Event[ft.Button]): + if page.theme_mode == ft.ThemeMode.LIGHT: + page.theme_mode = ft.ThemeMode.DARK + toggle_button.icon = ft.Icons.LIGHT_MODE + else: + page.theme_mode = ft.ThemeMode.LIGHT + toggle_button.icon = ft.Icons.DARK_MODE + page.update() + + toggle_button = ft.Button( + "Switch Theme Mode", + icon=ft.Icons.DARK_MODE, + on_click=handle_theme_toggle, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=16, + controls=[ + ft.SegmentedButton( + selected=["default"], + on_change=handle_style_change, + segments=[ + ft.Segment(value="default", label=ft.Text("Default")), + ft.Segment(value="custom", label=ft.Text("Custom")), + ft.Segment(value="none", label=ft.Text("None")), + ], + ), + toggle_button, + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/theme_animation_style/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/theme_animation_style/showcase/pyproject.toml new file mode 100644 index 0000000000..05e1a77138 --- /dev/null +++ b/sdk/python/examples/controls/core/types/theme_animation_style/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-theme-animation-style-showcase" +version = "1.0.0" +description = "Demonstrates Page.theme_animation_style by switching between default, custom, and disabled theme transitions." +requires-python = ">=3.10" +keywords = ["theme animation style", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Types"] + +[tool.flet.metadata] +title = "Theme Animation Style showcase" +controls = ["SafeArea", "Column", "SegmentedButton", "Segment", "Button", "Page", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["theme switching", "animation override"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/theme_mode/showcase/main.py b/sdk/python/examples/controls/core/types/theme_mode/showcase/main.py new file mode 100644 index 0000000000..8534532bdd --- /dev/null +++ b/sdk/python/examples/controls/core/types/theme_mode/showcase/main.py @@ -0,0 +1,72 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.SYSTEM + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def apply_theme_mode(theme_mode: ft.ThemeMode): + page.theme_mode = theme_mode + status.value = f"Active mode: {theme_mode.name}" + page.update() + + def showcase_card(theme_mode: ft.ThemeMode) -> ft.Container: + return ft.Container( + width=250, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(theme_mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Apply", + on_click=lambda _, m=theme_mode: apply_theme_mode(m), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="ThemeMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Switch the app theme mode and inspect the preview below."), + status := ft.Text(f"Active mode: {page.theme_mode.name}"), + ft.Container( + width=500, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=10, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.OutlinedButton("Outlined"), + ft.FilledButton("Filled"), + ft.Switch(label="Switch", value=True), + ], + ), + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(theme_mode) for theme_mode in ft.ThemeMode + ], + ), + ], + ), + ) + ) + + apply_theme_mode(ft.ThemeMode.SYSTEM) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/theme_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/theme_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..fae4752297 --- /dev/null +++ b/sdk/python/examples/controls/core/types/theme_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-theme-mode-showcase" +version = "1.0.0" +description = "Compares Theme Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["theme mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Theme Mode showcase" +controls = ["SafeArea", "Column", "Container", "Text", "Button", "AppBar", "Row", "OutlinedButton"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/tile_affinity/showcase/main.py b/sdk/python/examples/controls/core/types/tile_affinity/showcase/main.py new file mode 100644 index 0000000000..2ae4ca3e84 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tile_affinity/showcase/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def showcase_card(affinity: ft.TileAffinity) -> ft.Container: + tile = ft.ExpansionTile( + title="Project settings", + subtitle="Compare where the expand arrow appears.", + affinity=affinity, + expanded=True, + controls=[ + ft.ListTile(title="General"), + ft.ListTile(title="Notifications"), + ], + ) + + return ft.Container( + width=360, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(affinity.name, weight=ft.FontWeight.BOLD), + tile, + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="TileAffinity Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Compare expand-arrow placement in ExpansionTile."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(affinity) for affinity in ft.TileAffinity + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/tile_affinity/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/tile_affinity/showcase/pyproject.toml new file mode 100644 index 0000000000..1e5b54ef36 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tile_affinity/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tile-affinity-showcase" +version = "1.0.0" +description = "Compares Tile Affinity values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["tile affinity", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Tile Affinity showcase" +controls = ["SafeArea", "Column", "Container", "ExpansionTile", "ListTile", "Text", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/time_picker_entry_mode/showcase/main.py b/sdk/python/examples/controls/core/types/time_picker_entry_mode/showcase/main.py new file mode 100644 index 0000000000..702e7e9d80 --- /dev/null +++ b/sdk/python/examples/controls/core/types/time_picker_entry_mode/showcase/main.py @@ -0,0 +1,56 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + picker = ft.TimePicker(value=time(hour=19, minute=30)) + + def open_picker(entry_mode: ft.TimePickerEntryMode): + picker.entry_mode = entry_mode + page.show_dialog(picker) + + def showcase_card(entry_mode: ft.TimePickerEntryMode) -> ft.Container: + return ft.Container( + width=320, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(entry_mode.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open TimePicker", + icon=ft.Icons.SCHEDULE, + on_click=lambda _, m=entry_mode: open_picker(m), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="TimePickerEntryMode Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open the picker to compare dial/input entry modes."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(m) for m in ft.TimePickerEntryMode], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/time_picker_entry_mode/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/time_picker_entry_mode/showcase/pyproject.toml new file mode 100644 index 0000000000..f17fe232c4 --- /dev/null +++ b/sdk/python/examples/controls/core/types/time_picker_entry_mode/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-time-picker-entry-mode-showcase" +version = "1.0.0" +description = "Compares Time Picker Entry Mode values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["time picker entry mode", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Time Picker Entry Mode showcase" +controls = ["SafeArea", "Column", "TimePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/time_picker_hour_format/showcase/main.py b/sdk/python/examples/controls/core/types/time_picker_hour_format/showcase/main.py new file mode 100644 index 0000000000..7fe31551b1 --- /dev/null +++ b/sdk/python/examples/controls/core/types/time_picker_hour_format/showcase/main.py @@ -0,0 +1,62 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + time_picker = ft.TimePicker( + value=time(hour=19, minute=30), + help_text="Pick meeting time", + ) + + def open_picker(hour_format: ft.TimePickerHourFormat): + time_picker.hour_format = hour_format + page.show_dialog(time_picker) + + def showcase_card(hour_format: ft.TimePickerHourFormat) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(hour_format.name, weight=ft.FontWeight.BOLD), + ft.Button( + "Open TimePicker", + icon=ft.Icons.SCHEDULE, + on_click=lambda _, f=hour_format: open_picker(f), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="TimePickerHourFormat Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Open the picker to compare 12h, 24h, and system modes."), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + showcase_card(hour_format) + for hour_format in ft.TimePickerHourFormat + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/time_picker_hour_format/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/time_picker_hour_format/showcase/pyproject.toml new file mode 100644 index 0000000000..d29968f289 --- /dev/null +++ b/sdk/python/examples/controls/core/types/time_picker_hour_format/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-time-picker-hour-format-showcase" +version = "1.0.0" +description = "Compares Time Picker Hour Format values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["time picker hour format", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Time Picker Hour Format showcase" +controls = ["SafeArea", "Column", "TimePicker", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/tooltip/media/with_decoration.gif b/sdk/python/examples/controls/core/types/tooltip/media/with_decoration.gif new file mode 100644 index 0000000000..b931aff78b Binary files /dev/null and b/sdk/python/examples/controls/core/types/tooltip/media/with_decoration.gif differ diff --git a/sdk/python/examples/controls/core/types/tooltip/with_decoration/main.py b/sdk/python/examples/controls/core/types/tooltip/with_decoration/main.py new file mode 100644 index 0000000000..0aa6566bc5 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tooltip/with_decoration/main.py @@ -0,0 +1,49 @@ +import math + +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Hover to see the simple tooltip", + tooltip="This is a simple tooltip", + ), + ft.Text( + value="Hover to see the complex tooltip", + tooltip=ft.Tooltip( + message="This is a complex tooltip", + padding=20, + text_style=ft.TextStyle(size=20, color=ft.Colors.WHITE), + decoration=ft.BoxDecoration( + border_radius=10, + gradient=ft.LinearGradient( + begin=ft.Alignment.TOP_LEFT, + end=ft.Alignment(0.8, 1), + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + ), + ), + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/tooltip/with_decoration/pyproject.toml b/sdk/python/examples/controls/core/types/tooltip/with_decoration/pyproject.toml new file mode 100644 index 0000000000..13233d0195 --- /dev/null +++ b/sdk/python/examples/controls/core/types/tooltip/with_decoration/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-tooltip-with-decoration" +version = "1.0.0" +description = "Shows simple and decorated tooltips with custom gradient styling." +requires-python = ">=3.10" +keywords = ["tooltip", "with decoration"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Tooltip"] + +[tool.flet.metadata] +title = "Tooltip with decoration" +controls = ["SafeArea", "Column", "Text", "Tooltip", "BoxDecoration"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["tooltip styling", "gradient decoration"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/url_target/showcase/main.py b/sdk/python/examples/controls/core/types/url_target/showcase/main.py new file mode 100644 index 0000000000..f77405a13e --- /dev/null +++ b/sdk/python/examples/controls/core/types/url_target/showcase/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + async def open_url(target: ft.UrlTarget): + url = "https://flet.dev" + await ft.UrlLauncher().launch_url(ft.Url(url=url, target=target)) + status.value = f"Opened {url} with target {target.name}" + status.update() + + def showcase_card(target: ft.UrlTarget) -> ft.Container: + return ft.Container( + width=280, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Column( + spacing=8, + controls=[ + ft.Text(target.name, weight=ft.FontWeight.BOLD), + ft.Text(target.value, size=12, color=ft.Colors.ON_SURFACE_VARIANT), + ft.Button( + "Open flet.dev", + icon=ft.Icons.OPEN_IN_NEW, + on_click=lambda: page.run_task(open_url, target), + ), + ], + ), + ) + + page.appbar = ft.AppBar(title="UrlTarget Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Click a card to launch URL with the selected browser target." + ), + status := ft.Text(), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[showcase_card(target) for target in ft.UrlTarget], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/url_target/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/url_target/showcase/pyproject.toml new file mode 100644 index 0000000000..c385c91ecb --- /dev/null +++ b/sdk/python/examples/controls/core/types/url_target/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-url-target-showcase" +version = "1.0.0" +description = "Compares URL Target values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["url target", "showcase", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "URL Target showcase" +controls = ["SafeArea", "Column", "UrlLauncher", "Container", "Text", "Button", "AppBar", "Row"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/visual_density/showcase/main.py b/sdk/python/examples/controls/core/types/visual_density/showcase/main.py new file mode 100644 index 0000000000..e95d06311e --- /dev/null +++ b/sdk/python/examples/controls/core/types/visual_density/showcase/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +def density_card(visual_density: ft.VisualDensity) -> ft.Container: + return ft.Container( + width=300, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + theme=ft.Theme(visual_density=visual_density), + dark_theme=ft.Theme(visual_density=visual_density), + content=ft.Column( + spacing=8, + controls=[ + ft.Text(visual_density.name, weight=ft.FontWeight.BOLD), + ft.IconButton(icon=ft.Icons.ADD), + ft.Checkbox(label="Checkbox", value=True), + ft.Chip( + label="Explore topics", + leading=ft.Icon(ft.Icons.EXPLORE_OUTLINED), + ), + ft.RadioGroup( + value="1", + content=ft.Row( + controls=[ + ft.Radio(label=f"{i}", value=f"{i}") for i in range(1, 4) + ], + ), + ), + ], + ), + ) + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.appbar = ft.AppBar(title="VisualDensity Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Compare component density presets across Material controls." + ), + ft.Row( + wrap=True, + spacing=12, + expand=True, + scroll=ft.ScrollMode.AUTO, + alignment=ft.MainAxisAlignment.CENTER, + controls=[density_card(vd) for vd in ft.VisualDensity], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/visual_density/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/visual_density/showcase/pyproject.toml new file mode 100644 index 0000000000..402f099d04 --- /dev/null +++ b/sdk/python/examples/controls/core/types/visual_density/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-visual-density-showcase" +version = "1.0.0" +description = "Compares Visual Density values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["visual density", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Visual Density showcase" +controls = ["SafeArea", "Column", "Container", "Theme", "Text", "IconButton", "Checkbox", "Chip"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/types/window_event_type/showcase/main.py b/sdk/python/examples/controls/core/types/window_event_type/showcase/main.py new file mode 100644 index 0000000000..f55feb9479 --- /dev/null +++ b/sdk/python/examples/controls/core/types/window_event_type/showcase/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + log = ft.Column( + spacing=4, + scroll=ft.ScrollMode.AUTO, + height=220, + ) + + def add_log(message: str): + log.controls.insert(0, ft.Text(message, size=12)) + if len(log.controls) > 20: + log.controls.pop() + log.update() + + def on_window_event(e: ft.WindowEvent): + add_log(f"Received: {e.type.name}") + + page.window.on_event = on_window_event + + page.appbar = ft.AppBar(title="WindowEventType Showcase") + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Interact with the app window and watch incoming event types." + ), + ft.Text( + "Desktop only. Try focus, blur, resize, move, " + "minimize, maximize.", + size=11, + ), + ft.Row( + wrap=True, + spacing=8, + controls=[ + ft.Container( + padding=ft.Padding.symmetric(horizontal=8, vertical=4), + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=12, + content=ft.Text(event_type.name, size=11), + ) + for event_type in ft.WindowEventType + ], + ), + ft.Container( + width=720, + padding=12, + border=ft.Border.all(1, ft.Colors.RED), + border_radius=10, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=log, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/types/window_event_type/showcase/pyproject.toml b/sdk/python/examples/controls/core/types/window_event_type/showcase/pyproject.toml new file mode 100644 index 0000000000..e4375f4ddf --- /dev/null +++ b/sdk/python/examples/controls/core/types/window_event_type/showcase/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "types-window-event-type-showcase" +version = "1.0.0" +description = "Compares Window Event Type values by applying them to a live control preview." +requires-python = ">=3.10" +keywords = ["window event type", "showcase"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Container"] + +[tool.flet.metadata] +title = "Window Event Type showcase" +controls = ["SafeArea", "Column", "Text", "AppBar", "Row", "Container"] +layout_pattern = "gallery" +complexity = "basic" +features = ["enum comparison", "live preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/vertical_divider/basic/main.py b/sdk/python/examples/controls/core/vertical_divider/basic/main.py new file mode 100644 index 0000000000..5bbe82841f --- /dev/null +++ b/sdk/python/examples/controls/core/vertical_divider/basic/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Row( + width=180, + height=100, + spacing=0, + controls=[ + ft.Container( + bgcolor=ft.Colors.ORANGE_300, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(), + ft.Container( + bgcolor=ft.Colors.BROWN_400, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(width=1, color=ft.Colors.WHITE), + ft.Container( + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(width=9, thickness=3), + ft.Container( + bgcolor=ft.Colors.GREEN_300, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/vertical_divider/basic/pyproject.toml b/sdk/python/examples/controls/core/vertical_divider/basic/pyproject.toml new file mode 100644 index 0000000000..776000ff46 --- /dev/null +++ b/sdk/python/examples/controls/core/vertical_divider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "vertical-divider-basic" +version = "1.0.0" +description = "Separates colored containers in a row using VerticalDivider variants." +requires-python = ">=3.10" +keywords = ["vertical divider", "layout", "row", "spacing", "divider"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/VerticalDivider"] + +[tool.flet.metadata] +title = "VerticalDivider basic" +controls = ["SafeArea", "Row", "VerticalDivider", "Container"] +layout_pattern = "single-row" +complexity = "basic" +features = ["divider width and thickness variants"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/core/window_drag_area/no_frame_window/main.py b/sdk/python/examples/controls/core/window_drag_area/no_frame_window/main.py new file mode 100644 index 0000000000..3e403a4f3c --- /dev/null +++ b/sdk/python/examples/controls/core/window_drag_area/no_frame_window/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + page.window.title_bar_hidden = True + page.window.title_bar_buttons_hidden = True + + async def handle_window_close(e: ft.Event[ft.IconButton]): + await page.window.close() + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.WindowDragArea( + expand=True, + content=ft.Container( + bgcolor=ft.Colors.AMBER_300, + padding=10, + content=ft.Text( + "Drag this area to move, maximize and " + "restore application window." + ), + ), + ), + ft.IconButton(ft.Icons.CLOSE, on_click=handle_window_close), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/core/window_drag_area/no_frame_window/pyproject.toml b/sdk/python/examples/controls/core/window_drag_area/no_frame_window/pyproject.toml new file mode 100644 index 0000000000..a358ed0a40 --- /dev/null +++ b/sdk/python/examples/controls/core/window_drag_area/no_frame_window/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "window-drag-area-no-frame-window" +version = "1.0.0" +description = "Creates a frameless window with a custom draggable title area and close button." +requires-python = ">=3.10" +keywords = ["window drag area", "desktop", "window", "frameless", "drag"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Window"] + +[tool.flet.metadata] +title = "No frame window" +controls = ["SafeArea", "Row", "WindowDragArea", "Container", "Text", "IconButton"] +layout_pattern = "toolbar-content" +complexity = "basic" +features = ["frameless window", "custom window dragging"] + +[tool.flet] +platforms = ["windows", "macos", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_action_sheet/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_action_sheet/basic/main.py new file mode 100644 index 0000000000..e1b6dfd77b --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_action_sheet/basic/main.py @@ -0,0 +1,63 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_click(e: ft.Event[ft.CupertinoActionSheetAction]): + messages.controls.append(ft.Text(f"Action clicked: {e.control.content.value}")) + page.pop_dialog() + + action_sheet = ft.CupertinoActionSheet( + title=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ft.Text("Title"), ft.Icon(ft.Icons.BEDTIME)], + ), + message=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ft.Text("Description"), ft.Icon(ft.Icons.AUTO_AWESOME)], + ), + cancel=ft.CupertinoActionSheetAction( + on_click=handle_click, + content=ft.Text("Cancel"), + ), + actions=[ + ft.CupertinoActionSheetAction( + default=True, + on_click=handle_click, + content=ft.Text("Default Action"), + ), + ft.CupertinoActionSheetAction( + on_click=handle_click, + content=ft.Text("Normal Action"), + ), + ft.CupertinoActionSheetAction( + destructive=True, + on_click=handle_click, + content=ft.Text("Destructive Action"), + ), + ], + ) + + bottom_sheet = ft.CupertinoBottomSheet(action_sheet) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog(bottom_sheet), + content="Open CupertinoBottomSheet", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_action_sheet/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_action_sheet/basic/pyproject.toml new file mode 100644 index 0000000000..d75c53aeda --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_action_sheet/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-action-sheet-basic" +version = "1.0.0" +description = "Opens a CupertinoActionSheet in a CupertinoBottomSheet and logs the selected action." +requires-python = ">=3.10" +keywords = ["cupertino", "action sheet", "bottom sheet", "dialog"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/CupertinoActionSheet"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "CupertinoFilledButton", "CupertinoBottomSheet", "CupertinoActionSheet", "CupertinoActionSheetAction", "Text", "Row", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "action callbacks", "destructive action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_action_sheet/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_action_sheet/media/basic.png new file mode 100644 index 0000000000..6288de3f4b Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_action_sheet/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/basic/main.py new file mode 100644 index 0000000000..daaac7718d --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.CupertinoActivityIndicator( + animating=True, + color=ft.Colors.RED, + radius=50, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/basic/pyproject.toml new file mode 100644 index 0000000000..059023c68e --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-activity-indicator-basic" +version = "1.0.0" +description = "Shows a centered CupertinoActivityIndicator with custom color and radius." +requires-python = ">=3.10" +keywords = ["cupertino", "activity indicator", "loading", "spinner"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/CupertinoActivityIndicator"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoActivityIndicator"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["indeterminate loading state", "custom radius", "custom color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/media/basic.png new file mode 100644 index 0000000000..451a779e60 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/progress/main.py b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/progress/main.py new file mode 100644 index 0000000000..5e961f6871 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/progress/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +async def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 20 + + indicator = ft.CupertinoActivityIndicator(progress=1.0, radius=40) + + def handle_progress_change(e: ft.Event[ft.Slider]): + indicator.progress = e.control.value + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + indicator, + ft.Slider( + min=0.0, + value=indicator.progress, + max=1.0, + divisions=10, + round=1, + label="Progress = {value}", + width=400, + on_change=handle_progress_change, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/progress/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/progress/pyproject.toml new file mode 100644 index 0000000000..9b9dd80ced --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_activity_indicator/progress/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-activity-indicator-progress" +version = "1.0.0" +description = "Drives CupertinoActivityIndicator progress with a slider for determinate loading feedback." +requires-python = ">=3.10" +keywords = ["cupertino", "activity indicator", "progress", "slider"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/CupertinoActivityIndicator"] + +[tool.flet.metadata] +title = "Progress" +controls = ["SafeArea", "Column", "CupertinoActivityIndicator", "Slider"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["determinate progress", "slider-driven updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..a2ebc10673 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/cupertino_material_and_adaptive/main.py @@ -0,0 +1,86 @@ +from typing import Union + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.AUTO + + messages = ft.Column(tight=True) + + def handle_action_click( + e: ft.Event[Union[ft.TextButton, ft.CupertinoDialogAction]], + ): + messages.controls.append(ft.Text(f"Action clicked: {e.control.content}")) + page.pop_dialog() + + cupertino_actions = [ + ft.CupertinoDialogAction( + destructive=True, + on_click=handle_action_click, + content="Yes", + ), + ft.CupertinoDialogAction( + default=False, + on_click=handle_action_click, + content="No", + ), + ] + + material_actions = [ + ft.TextButton(on_click=handle_action_click, content="Yes"), + ft.TextButton(on_click=handle_action_click, content="No"), + ] + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.FilledButton( + on_click=lambda _: page.show_dialog( + ft.AlertDialog( + title=ft.Text("Material Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + actions=material_actions, + ) + ), + content="Open Material Dialog", + ), + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoAlertDialog( + title=ft.Text("Cupertino Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + actions=cupertino_actions, + ) + ), + content="Open Cupertino Dialog", + ), + ft.FilledButton( + adaptive=True, + bgcolor=ft.Colors.BLUE_ACCENT, + on_click=lambda _: page.show_dialog( + ft.AlertDialog( + adaptive=True, + title=ft.Text("Adaptive Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + actions=( + cupertino_actions + if page.platform.is_apple() + else material_actions + ), + ) + ), + content="Open Adaptive Dialog", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..9493419196 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-alert-dialog-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Compares Material, Cupertino, and adaptive alert dialogs with platform-aware action sets." +requires-python = ">=3.10" +keywords = ["cupertino", "material", "adaptive", "alert dialog", "platform"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/CupertinoAlertDialog"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "FilledButton", "CupertinoFilledButton", "AlertDialog", "CupertinoAlertDialog", "TextButton", "CupertinoDialogAction", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["platform-adaptive dialog", "material and cupertino comparison", "action callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/file_deletion_confirmation/main.py b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/file_deletion_confirmation/main.py new file mode 100644 index 0000000000..59b81d76d7 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/file_deletion_confirmation/main.py @@ -0,0 +1,51 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_dialog_dismissal(_: ft.Event[ft.DialogControl]): + messages.controls.append(ft.Text("Dialog dismissed")) + + def handle_action_click(e: ft.Event[ft.CupertinoDialogAction]): + messages.controls.append(ft.Text(f"Action clicked: {e.control.content}")) + page.pop_dialog() + + cupertino_alert_dialog = ft.CupertinoAlertDialog( + title=ft.Text("Cupertino Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + on_dismiss=handle_dialog_dismissal, + actions=[ + ft.CupertinoDialogAction( + destructive=True, + on_click=handle_action_click, + content="Yes", + ), + ft.CupertinoDialogAction( + default=True, + on_click=handle_action_click, + content="No", + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog(cupertino_alert_dialog), + content="Open CupertinoAlertDialog", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml new file mode 100644 index 0000000000..ccc954f4b0 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/file_deletion_confirmation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-alert-dialog-file-deletion-confirmation" +version = "1.0.0" +description = "Shows a CupertinoAlertDialog for file deletion confirmation with dismiss and action callbacks." +requires-python = ">=3.10" +keywords = ["cupertino", "alert dialog", "confirmation", "actions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/CupertinoAlertDialog"] + +[tool.flet.metadata] +title = "File deletion confirmation" +controls = ["SafeArea", "Column", "CupertinoFilledButton", "CupertinoAlertDialog", "CupertinoDialogAction", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "dismiss callback", "action callbacks", "destructive action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/adaptive.png new file mode 100644 index 0000000000..cd576c97e9 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/adaptive_dialog_action.png b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/adaptive_dialog_action.png new file mode 100644 index 0000000000..09012f830d Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/adaptive_dialog_action.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/file_deletion_confirmation.png b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/file_deletion_confirmation.png new file mode 100644 index 0000000000..f7dd214929 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_alert_dialog/media/file_deletion_confirmation.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_app_bar/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_app_bar/basic/main.py new file mode 100644 index 0000000000..e8b2b54a4e --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_app_bar/basic/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.appbar = ft.CupertinoAppBar( + leading=ft.Icon(ft.Icons.PALETTE, color=ft.Colors.ON_SECONDARY), + title=ft.Text("CupertinoAppBar Example"), + trailing=ft.Icon(ft.Icons.WB_SUNNY_OUTLINED, color=ft.Colors.ON_SECONDARY), + automatic_background_visibility=False, + bgcolor=ft.Colors.SECONDARY, + brightness=ft.Brightness.LIGHT, + ) + + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_app_bar/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_app_bar/basic/pyproject.toml new file mode 100644 index 0000000000..6daad9f02d --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_app_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-app-bar-basic" +version = "1.0.0" +description = "Displays a CupertinoAppBar with custom leading and trailing icons and light theme styling." +requires-python = ">=3.10" +keywords = ["cupertino", "app bar", "navigation", "toolbar"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoAppBar"] + +[tool.flet.metadata] +title = "Basic" +controls = ["CupertinoAppBar", "Icon", "Text", "SafeArea"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["custom app bar colors", "leading and trailing icons"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_app_bar/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_app_bar/media/basic.png new file mode 100644 index 0000000000..898643d28f Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_app_bar/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_app_bar/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_app_bar/media/index.png new file mode 100644 index 0000000000..07a0a4a056 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_app_bar/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_app_bar/theme_mode_toggle/main.py b/sdk/python/examples/controls/cupertino/cupertino_app_bar/theme_mode_toggle/main.py new file mode 100644 index 0000000000..bfd61b3be1 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_app_bar/theme_mode_toggle/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_theme_mode_toggle(_: ft.Event[ft.IconButton]): + page.theme_mode = ( + ft.ThemeMode.DARK + if page.theme_mode == ft.ThemeMode.LIGHT + else ft.ThemeMode.LIGHT + ) + theme_mode_button.icon = ( + ft.Icons.WB_SUNNY_OUTLINED + if page.theme_mode == ft.ThemeMode.LIGHT + else ft.Icons.WB_SUNNY + ) + + theme_mode_button = ft.IconButton( + icon=( + ft.Icons.WB_SUNNY_OUTLINED + if page.theme_mode == ft.ThemeMode.LIGHT + else ft.Icons.WB_SUNNY + ), + icon_color=ft.Colors.ON_INVERSE_SURFACE, + on_click=handle_theme_mode_toggle, + ) + + page.appbar = ft.CupertinoAppBar( + automatic_background_visibility=False, + leading=ft.Icon(ft.Icons.PALETTE, color=ft.Colors.ON_INVERSE_SURFACE), + bgcolor=ft.Colors.INVERSE_SURFACE, + trailing=theme_mode_button, + title=ft.Text("CupertinoAppBar Example", color=ft.Colors.ON_INVERSE_SURFACE), + ) + + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_app_bar/theme_mode_toggle/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_app_bar/theme_mode_toggle/pyproject.toml new file mode 100644 index 0000000000..6ee28dccbd --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_app_bar/theme_mode_toggle/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-app-bar-theme-mode-toggle" +version = "1.0.0" +description = "Toggles page theme mode from a CupertinoAppBar trailing icon button." +requires-python = ">=3.10" +keywords = ["cupertino", "app bar", "theme", "toggle", "icon button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoAppBar"] + +[tool.flet.metadata] +title = "Theme mode toggle" +controls = ["CupertinoAppBar", "Icon", "IconButton", "Text", "SafeArea"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["theme mode toggle", "dynamic icon update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_button/basic/main.py new file mode 100644 index 0000000000..dfffecc41e --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_button/basic/main.py @@ -0,0 +1,54 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoButton( + bgcolor=ft.CupertinoColors.LIGHT_BACKGROUND_GRAY, + opacity_on_click=0.3, + on_click=lambda _: print("Normal CupertinoButton clicked!"), + content=ft.Text( + value="Normal CupertinoButton", + color=ft.CupertinoColors.DESTRUCTIVE_RED, + ), + ), + ft.CupertinoButton( + bgcolor=ft.Colors.PRIMARY, + alignment=ft.Alignment.TOP_LEFT, + border_radius=ft.BorderRadius.all(15), + opacity_on_click=0.5, + on_click=lambda _: print("Filled CupertinoButton clicked!"), + content=ft.Text( + "Filled CupertinoButton", + color=ft.Colors.YELLOW, + ), + ), + ft.CupertinoButton( + bgcolor=ft.Colors.PRIMARY, + disabled=True, + alignment=ft.Alignment.TOP_LEFT, + opacity_on_click=0.5, + content=ft.Text("Disabled CupertinoButton"), + ), + ft.Button( + adaptive=True, + bgcolor=ft.CupertinoColors.SYSTEM_TEAL, + content=ft.Row( + tight=True, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color="pink"), + ft.Text("Button+adaptive"), + ], + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_button/basic/pyproject.toml new file mode 100644 index 0000000000..597cbb92ae --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-button-basic" +version = "1.0.0" +description = "Demonstrates styled, disabled, and adaptive CupertinoButton variations in one layout." +requires-python = ">=3.10" +keywords = ["cupertino", "button", "adaptive", "disabled", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "CupertinoButton", "Button", "Text", "Row", "Icon"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom button styling", "disabled button", "adaptive button"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive.png new file mode 100644 index 0000000000..89bcd477d7 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive_icon_button.png b/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive_icon_button.png new file mode 100644 index 0000000000..320f88532f Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive_icon_button.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive_tonal_button.png b/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive_tonal_button.png new file mode 100644 index 0000000000..e671c0aced Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_button/media/adaptive_tonal_button.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_button/media/basic.png new file mode 100644 index 0000000000..0f29e96f52 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_button/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_button/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_button/media/index.png new file mode 100644 index 0000000000..9beffe16f8 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_button/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_checkbox/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino/cupertino_checkbox/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..79d36b7ea0 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_checkbox/cupertino_material_and_adaptive/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoCheckbox(label="Cupertino Checkbox", value=True), + ft.Checkbox(label="Material Checkbox", value=True), + ft.Container(height=20), + ft.Text( + value=( + "Adaptive Checkbox shows as CupertinoCheckbox on macOS " + "and iOS and as Checkbox on other platforms:" + ) + ), + ft.Checkbox( + adaptive=True, + label="Adaptive Checkbox", + value=True, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..9715f7580f --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_checkbox/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-checkbox-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Shows Cupertino, Material, and adaptive checkbox behavior side by side." +requires-python = ">=3.10" +keywords = ["cupertino", "checkbox", "adaptive", "material", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoCheckbox"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "CupertinoCheckbox", "Checkbox", "Text", "Container"] +layout_pattern = "form" +complexity = "basic" +features = ["platform-adaptive checkbox", "cupertino and material comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_checkbox/media/cupertino_material_and_adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_checkbox/media/cupertino_material_and_adaptive.png new file mode 100644 index 0000000000..d2a36f7665 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_checkbox/media/cupertino_material_and_adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_checkbox/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_checkbox/media/index.png new file mode 100644 index 0000000000..20966d826f Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_checkbox/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_checkbox/styled/main.py b/sdk/python/examples/controls/cupertino/cupertino_checkbox/styled/main.py new file mode 100644 index 0000000000..bdf4215312 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_checkbox/styled/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoCheckbox( + label="Cupertino Checkbox tristate", + value=True, + tristate=True, + check_color=ft.Colors.GREY_900, + fill_color={ + ft.ControlState.HOVERED: ft.Colors.PINK_200, + ft.ControlState.PRESSED: ft.Colors.LIME_ACCENT_200, + ft.ControlState.SELECTED: ft.Colors.DEEP_ORANGE_200, + ft.ControlState.DEFAULT: ft.Colors.TEAL_200, + }, + ), + ft.CupertinoCheckbox( + label="Cupertino Checkbox circle border", + value=True, + shape=ft.CircleBorder(), + ), + ft.CupertinoCheckbox( + label="Cupertino Checkbox border states", + value=True, + ), + ft.CupertinoCheckbox( + label="Cupertino Checkbox label position", + value=True, + label_position=ft.LabelPosition.LEFT, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_checkbox/styled/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_checkbox/styled/pyproject.toml new file mode 100644 index 0000000000..f65ba4f923 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_checkbox/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-checkbox-styled" +version = "1.0.0" +description = "Configures CupertinoCheckbox styles including fill states, shape, tristate, and label position." +requires-python = ">=3.10" +keywords = ["cupertino", "checkbox", "styling", "tristate", "shape"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoCheckbox"] + +[tool.flet.metadata] +title = "Styled" +controls = ["SafeArea", "Column", "CupertinoCheckbox", "CircleBorder"] +layout_pattern = "form" +complexity = "basic" +features = ["tristate checkbox", "state-based fill colors", "custom shape", "left-side label"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_context_menu/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_context_menu/basic/main.py new file mode 100644 index 0000000000..ef9b62851e --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_context_menu/basic/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.CupertinoContextMenu( + enable_haptic_feedback=True, + actions=[ + ft.CupertinoContextMenuAction( + default=True, + trailing_icon=ft.Icons.CHECK, + on_click=lambda _: print("Action 1"), + content="Action 1", + ), + ft.CupertinoContextMenuAction( + trailing_icon=ft.Icons.MORE, + on_click=lambda _: print("Action 2"), + content="Action 2", + ), + ft.CupertinoContextMenuAction( + destructive=True, + trailing_icon=ft.Icons.CANCEL, + on_click=lambda _: print("Action 3"), + content="Action 3", + ), + ], + content=ft.Image("https://picsum.photos/200/200"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_context_menu/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_context_menu/basic/pyproject.toml new file mode 100644 index 0000000000..95a6ae7858 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_context_menu/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-context-menu-basic" +version = "1.0.0" +description = "Opens a CupertinoContextMenu on image long-press with default and destructive actions." +requires-python = ">=3.10" +keywords = ["cupertino", "context menu", "image", "actions", "long press"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoContextMenu"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoContextMenu", "CupertinoContextMenuAction", "Image"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["context menu actions", "destructive action", "haptic feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_context_menu/media/basic.gif b/sdk/python/examples/controls/cupertino/cupertino_context_menu/media/basic.gif new file mode 100644 index 0000000000..88e60f2adb Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_context_menu/media/basic.gif differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_date_picker/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_date_picker/basic/main.py new file mode 100644 index 0000000000..d6dad041da --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_date_picker/basic/main.py @@ -0,0 +1,43 @@ +from datetime import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + message = ft.Text("Chosen Time:") + + def handle_date_change(e: ft.Event[ft.CupertinoDatePicker]): + message.value = f"Chosen Date: {e.control.value.strftime('%Y-%m-%d %H:%M %p')}" + + cupertino_date_picker = ft.CupertinoDatePicker( + value=datetime.now(), + date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, + on_change=handle_date_change, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=cupertino_date_picker, + ) + ), + content="Open CupertinoDatePicker", + ), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_date_picker/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_date_picker/basic/pyproject.toml new file mode 100644 index 0000000000..f262648823 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_date_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-date-picker-basic" +version = "1.0.0" +description = "Shows a CupertinoDatePicker in a bottom sheet and updates text when the value changes." +requires-python = ">=3.10" +keywords = ["cupertino", "date picker", "bottom sheet", "events", "datetime"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoDatePicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "CupertinoFilledButton", "CupertinoBottomSheet", "CupertinoDatePicker", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["date and time selection", "on_change callback", "bottom sheet presentation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_date_picker/custom_locale/main.py b/sdk/python/examples/controls/cupertino/cupertino_date_picker/custom_locale/main.py new file mode 100644 index 0000000000..8defa93279 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_date_picker/custom_locale/main.py @@ -0,0 +1,27 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.CupertinoFilledButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=ft.CupertinoDatePicker( + locale=ft.Locale("zh", "Hans"), + date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, + ), + ) + ), + content="Open CupertinoDatePicker (zh_Hans locale)", + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_date_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_date_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..5d73da8931 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_date_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-date-picker-custom-locale" +version = "1.0.0" +description = "Opens CupertinoDatePicker with zh_Hans locale to demonstrate localized date formatting." +requires-python = ">=3.10" +keywords = ["date picker", "custom locale", "locale", "internationalization", "zh_Hans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoDatePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "CupertinoFilledButton", "CupertinoBottomSheet", "CupertinoDatePicker", "Locale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom locale", "date and time picker", "bottom sheet presentation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_date_picker/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_date_picker/media/basic.png new file mode 100644 index 0000000000..79f0fea700 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_date_picker/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_filled_button/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_filled_button/basic/main.py new file mode 100644 index 0000000000..8f1d5d727d --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_filled_button/basic/main.py @@ -0,0 +1,17 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.CupertinoFilledButton( + opacity_on_click=0.3, + on_click=lambda _: print("CupertinoFilledButton clicked!"), + content=ft.Text("CupertinoFilledButton"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_filled_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_filled_button/basic/pyproject.toml new file mode 100644 index 0000000000..66d70134c2 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_filled_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-filled-button-basic" +version = "1.0.0" +description = "Renders a CupertinoFilledButton with click opacity and click callback behavior." +requires-python = ">=3.10" +keywords = ["cupertino", "filled button", "button", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoFilledButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoFilledButton", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom click opacity", "button click callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_filled_button/media/adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_filled_button/media/adaptive.png new file mode 100644 index 0000000000..2edae23641 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_filled_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_filled_button/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_filled_button/media/basic.png new file mode 100644 index 0000000000..fbfbe5e8ab Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_filled_button/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_list_tile/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_list_tile/media/index.png new file mode 100644 index 0000000000..9b99cb60c0 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_list_tile/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_list_tile/media/notched.png b/sdk/python/examples/controls/cupertino/cupertino_list_tile/media/notched.png new file mode 100644 index 0000000000..9dbb15b1ee Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_list_tile/media/notched.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_list_tile/notched/main.py b/sdk/python/examples/controls/cupertino/cupertino_list_tile/notched/main.py new file mode 100644 index 0000000000..a60ccaefca --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_list_tile/notched/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_tile_click(_: ft.Event[ft.CupertinoListTile]): + print("Tile clicked") + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoListTile( + additional_info=ft.Text("Wed Jan 24"), + bgcolor_activated=ft.Colors.AMBER_ACCENT, + leading=ft.Icon(ft.CupertinoIcons.GAME_CONTROLLER), + title=ft.Text("CupertinoListTile: notched = False"), + subtitle=ft.Text("Subtitle"), + trailing=ft.Icon(ft.CupertinoIcons.ALARM), + on_click=handle_tile_click, + ), + ft.CupertinoListTile( + notched=True, + additional_info=ft.Text("Thu Jan 25"), + leading=ft.Icon(ft.CupertinoIcons.GAME_CONTROLLER), + title=ft.Text("CupertinoListTile: notched = True"), + subtitle=ft.Text("Subtitle"), + trailing=ft.Icon(ft.CupertinoIcons.ALARM), + on_click=handle_tile_click, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_list_tile/notched/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_list_tile/notched/pyproject.toml new file mode 100644 index 0000000000..3e07330748 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_list_tile/notched/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-list-tile-notched" +version = "1.0.0" +description = "Compares CupertinoListTile with and without notched layout, including leading, trailing, and click actions." +requires-python = ">=3.10" +keywords = ["cupertino", "list tile", "notched", "layout", "click"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/CupertinoListTile"] + +[tool.flet.metadata] +title = "Notched" +controls = ["SafeArea", "Column", "CupertinoListTile", "Text", "Icon"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["notched tile", "tile click callback", "additional info"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/basic/main.py new file mode 100644 index 0000000000..8c622ac09d --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/basic/main.py @@ -0,0 +1,39 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "CupertinoNavigationBar Example" + + page.navigation_bar = ft.CupertinoNavigationBar( + bgcolor=ft.Colors.AMBER_100, + inactive_color=ft.Colors.GREY, + active_color=ft.Colors.BLACK, + on_change=lambda e: print("Selected tab:", e.control.selected_index), + destinations=[ + ft.NavigationBarDestination( + icon=ft.Icons.EXPLORE_OUTLINED, + selected_icon=ft.Icons.EXPLORE, + label="Explore", + ), + ft.NavigationBarDestination( + icon=ft.Icons.COMMUTE_OUTLINED, + selected_icon=ft.Icons.COMMUTE, + label="Commute", + ), + ft.NavigationBarDestination( + icon=ft.Icons.BOOKMARK_BORDER, + selected_icon=ft.Icons.BOOKMARK, + label="Favorites", + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/basic/pyproject.toml new file mode 100644 index 0000000000..9883ea5523 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-navigation-bar-basic" +version = "1.0.0" +description = "Shows a CupertinoNavigationBar with three destinations and selected tab callback logging." +requires-python = ">=3.10" +keywords = ["cupertino", "navigation bar", "tabs", "destinations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoNavigationBar"] + +[tool.flet.metadata] +title = "Basic" +controls = ["CupertinoNavigationBar", "NavigationBarDestination", "SafeArea", "Text"] +layout_pattern = "tabbed-navigation" +complexity = "basic" +features = ["bottom navigation", "destination selection callback", "active and inactive colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/media/adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/media/adaptive.png new file mode 100644 index 0000000000..8ffee75b55 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/media/adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/media/basic.png b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/media/basic.png new file mode 100644 index 0000000000..4f530a9ffe Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/media/basic.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/wired/main.py b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/wired/main.py new file mode 100644 index 0000000000..bd46019cc1 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/wired/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "CupertinoNavigationBar Example" + + body_text = ft.Text("Explore!") + + def handle_nav_destination_change(e: ft.Event[ft.CupertinoNavigationBar]): + if e.control.selected_index == 0: + body_text.value = "Explore!" + elif e.control.selected_index == 1: + body_text.value = "Find Your Way!" + else: + body_text.value = "Your Favorites!" + + page.navigation_bar = ft.CupertinoNavigationBar( + bgcolor=ft.Colors.AMBER_100, + inactive_color=ft.Colors.GREY, + active_color=ft.Colors.BLACK, + on_change=handle_nav_destination_change, + destinations=[ + ft.NavigationBarDestination( + icon=ft.Icons.EXPLORE_OUTLINED, + selected_icon=ft.Icons.EXPLORE, + label="Explore", + ), + ft.NavigationBarDestination( + icon=ft.Icons.COMMUTE_OUTLINED, + selected_icon=ft.Icons.COMMUTE, + label="Commute", + ), + ft.NavigationBarDestination( + icon=ft.Icons.BOOKMARK_BORDER, + selected_icon=ft.Icons.BOOKMARK, + label="Favorites", + ), + ], + ) + + page.add( + ft.SafeArea( + content=body_text, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/wired/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/wired/pyproject.toml new file mode 100644 index 0000000000..ed3db35d10 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_navigation_bar/wired/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-navigation-bar-wired" +version = "1.0.0" +description = "Wires CupertinoNavigationBar selection to update the page body text for each destination." +requires-python = ">=3.10" +keywords = ["cupertino", "navigation bar", "state", "destinations", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/CupertinoNavigationBar"] + +[tool.flet.metadata] +title = "Wired" +controls = ["CupertinoNavigationBar", "NavigationBarDestination", "SafeArea", "Text"] +layout_pattern = "tabbed-navigation" +complexity = "basic" +features = ["selection-driven content", "destination change handler"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_picker/fruit_selection/main.py b/sdk/python/examples/controls/cupertino/cupertino_picker/fruit_selection/main.py new file mode 100644 index 0000000000..ba028fea93 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_picker/fruit_selection/main.py @@ -0,0 +1,54 @@ +import flet as ft + +FRUITS = [ + "Apple", + "Mango", + "Banana", + "Orange", + "Pineapple", + "Strawberry", +] + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + selected_fruit_text = ft.Text(value=FRUITS[3], size=23) + + def handle_selection_change(e: ft.Event[ft.CupertinoPicker]): + selected_fruit_text.value = FRUITS[int(e.data)] + + cupertino_picker = ft.CupertinoPicker( + selected_index=3, + magnification=1.22, + squeeze=1.2, + use_magnifier=True, + on_change=handle_selection_change, + controls=[ft.Text(value=f) for f in FRUITS], + ) + + page.add( + ft.SafeArea( + content=ft.Row( + tight=True, + controls=[ + ft.Text("Selected Fruit:", size=23), + ft.TextButton( + style=ft.ButtonStyle(color=ft.Colors.BLUE), + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=cupertino_picker, + ) + ), + content=selected_fruit_text, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_picker/fruit_selection/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_picker/fruit_selection/pyproject.toml new file mode 100644 index 0000000000..63f20899d9 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_picker/fruit_selection/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-picker-fruit-selection" +version = "1.0.0" +description = "Opens a CupertinoPicker in a bottom sheet to choose a fruit and reflect the selected value." +requires-python = ">=3.10" +keywords = ["cupertino", "picker", "bottom sheet", "selection", "dialog"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoPicker"] + +[tool.flet.metadata] +title = "Fruit selection" +controls = ["SafeArea", "Row", "Text", "TextButton", "CupertinoBottomSheet", "CupertinoPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["picker selection callback", "bottom sheet presentation", "live value update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_picker/media/fruit_selection.gif b/sdk/python/examples/controls/cupertino/cupertino_picker/media/fruit_selection.gif new file mode 100644 index 0000000000..2afbe7815b Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_picker/media/fruit_selection.gif differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_radio/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_radio/basic/main.py new file mode 100644 index 0000000000..9a5dae4b75 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_radio/basic/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + group = ft.RadioGroup( + content=ft.Column( + controls=[ + ft.CupertinoRadio( + value="red", + label="Red", + active_color=ft.Colors.RED_200, + inactive_color=ft.Colors.RED_600, + ), + ft.CupertinoRadio( + value="green", + label="Green", + fill_color=ft.Colors.GREEN, + ), + ft.CupertinoRadio( + value="blue", + label="Blue", + active_color=ft.Colors.BLUE, + ), + ], + ) + ) + + def handle_button_click(_: ft.Event[ft.Button]): + message.value = f"Your favorite color is: {group.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + group, + ft.Button(content="Submit", on_click=handle_button_click), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_radio/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_radio/basic/pyproject.toml new file mode 100644 index 0000000000..cda13ceab4 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_radio/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-radio-basic" +version = "1.0.0" +description = "Collects color selection with CupertinoRadio controls in a RadioGroup and submit action." +requires-python = ">=3.10" +keywords = ["cupertino", "radio", "radio group", "selection", "form"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoRadio"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "RadioGroup", "CupertinoRadio", "Text", "Button"] +layout_pattern = "form" +complexity = "basic" +features = ["single-choice selection", "submit callback", "custom active colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_radio/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino/cupertino_radio/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..e7db545a6c --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_radio/cupertino_material_and_adaptive/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + group = ft.RadioGroup( + content=ft.Column( + controls=[ + ft.CupertinoRadio( + value="red", + label="Red - Cupertino Radio", + active_color=ft.Colors.RED, + inactive_color=ft.Colors.RED, + ), + ft.Radio( + value="green", + label="Green - Material Radio", + fill_color=ft.Colors.GREEN, + ), + ft.Radio( + value="blue", + label="Blue - Adaptive Radio", + adaptive=True, + active_color=ft.Colors.BLUE, + ), + ], + ) + ) + + def handle_button_click(_: ft.Event[ft.Button]): + message.value = f"Your favorite color is: {group.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + group, + ft.Button(content="Submit", on_click=handle_button_click), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..5649e80abe --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_radio/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-radio-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Compares Cupertino, Material, and adaptive radio controls inside one RadioGroup workflow." +requires-python = ">=3.10" +keywords = ["cupertino", "radio", "adaptive", "material", "comparison"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoRadio"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "RadioGroup", "CupertinoRadio", "Radio", "Text", "Button"] +layout_pattern = "form" +complexity = "basic" +features = ["adaptive radio", "cupertino and material comparison", "submit callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_radio/media/cupertino_material_and_adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_radio/media/cupertino_material_and_adaptive.png new file mode 100644 index 0000000000..11c8eb3b9c Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_radio/media/cupertino_material_and_adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_radio/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_radio/media/index.png new file mode 100644 index 0000000000..4d484b9095 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_radio/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_segmented_button/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/basic/main.py new file mode 100644 index 0000000000..2c53dbab8d --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/basic/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.CupertinoSegmentedButton( + selected_index=1, + selected_color=ft.Colors.RED_400, + on_change=lambda e: print(f"selected_index: {e.data}"), + padding=ft.Padding.symmetric(vertical=20, horizontal=50), + controls=[ + ft.Text("One"), + ft.Container( + padding=ft.Padding.symmetric(vertical=10, horizontal=30), + content=ft.Text("Two"), + ), + ft.Container( + padding=ft.Padding.symmetric(vertical=5, horizontal=10), + content=ft.Text("Three"), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_segmented_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/basic/pyproject.toml new file mode 100644 index 0000000000..5a95cc6b29 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-segmented-button-basic" +version = "1.0.0" +description = "Shows a CupertinoSegmentedButton with mixed segment content sizes and selection events." +requires-python = ">=3.10" +keywords = ["cupertino", "segmented button", "selection", "buttons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoSegmentedButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoSegmentedButton", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["segment selection callback", "custom segment padding", "selected color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_segmented_button/media/basic.gif b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/media/basic.gif new file mode 100644 index 0000000000..8811892f38 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/media/basic.gif differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_segmented_button/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/media/index.png new file mode 100644 index 0000000000..2d4efc4fc7 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_segmented_button/segments_padding/main.py b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/segments_padding/main.py new file mode 100644 index 0000000000..89b8572a37 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/segments_padding/main.py @@ -0,0 +1,75 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + segmented_button = ft.CupertinoSegmentedButton( + selected_index=1, + selected_color=ft.Colors.RED_400, + unselected_color=ft.Colors.GREY_400, + on_change=lambda e: print(f"selected_index: {e.data}"), + controls=[ + ft.Text("All"), + ft.Container( + padding=ft.Padding.symmetric(vertical=30, horizontal=0), + content=ft.Text("None"), + ), + ft.Container( + padding=ft.Padding.symmetric(vertical=0, horizontal=30), + content=ft.Text("Some"), + ), + ], + ) + + def handle_vertical_change(e: ft.Event[ft.Slider]): + segmented_button.controls[1].padding = ft.Padding.only( + top=e.control.value, + bottom=e.control.value, + ) + + def handle_horizontal_change(e: ft.Event[ft.Slider]): + segmented_button.controls[2].padding = ft.Padding.only( + left=e.control.value, + right=e.control.value, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + segmented_button, + ft.Text("Vertical padding button 1:"), + ft.Slider( + label="{value}", + min=0, + max=50, + divisions=50, + value=30, + on_change=handle_vertical_change, + ), + ft.Text("Horizontal padding button 2:"), + ft.Slider( + label="{value}", + min=0, + max=50, + divisions=50, + value=30, + on_change=handle_horizontal_change, + ), + ft.Text( + value=( + "*note that padding changes to one segment can effect " + "padding on other segments*" + ), + theme_style=ft.TextThemeStyle.LABEL_MEDIUM, + color=ft.Colors.ORANGE_ACCENT, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_segmented_button/segments_padding/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/segments_padding/pyproject.toml new file mode 100644 index 0000000000..cc9405d557 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_segmented_button/segments_padding/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-segmented-button-segments-padding" +version = "1.0.0" +description = "Adjusts CupertinoSegmentedButton segment padding interactively using sliders." +requires-python = ">=3.10" +keywords = ["cupertino", "segmented button", "padding", "slider", "interactive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoSegmentedButton"] + +[tool.flet.metadata] +title = "Segments padding" +controls = ["SafeArea", "Column", "CupertinoSegmentedButton", "Container", "Slider", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["interactive padding controls", "segment layout tuning", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_slider/handling_events/main.py b/sdk/python/examples/controls/cupertino/cupertino_slider/handling_events/main.py new file mode 100644 index 0000000000..bf0b5bbe24 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_slider/handling_events/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.theme_mode = ft.ThemeMode.LIGHT + + slider_value = ft.Text("0.0") + slider_status = ft.Text() + + def handle_change_start(_: ft.Event[ft.CupertinoSlider]): + slider_status.value = "Sliding" + + def handle_change(e: ft.Event[ft.CupertinoSlider]): + slider_value.value = str(e.control.value) + + def handle_change_end(_: ft.Event[ft.CupertinoSlider]): + slider_status.value = "Finished sliding" + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + slider_value, + ft.CupertinoSlider( + divisions=20, + min=0, + max=100, + active_color=ft.Colors.PURPLE, + thumb_color=ft.Colors.PURPLE, + on_change_start=handle_change_start, + on_change_end=handle_change_end, + on_change=handle_change, + ), + slider_status, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_slider/handling_events/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_slider/handling_events/pyproject.toml new file mode 100644 index 0000000000..5107f23c90 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_slider/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-slider-handling-events" +version = "1.0.0" +description = "Tracks CupertinoSlider start, change, and end events with live status text updates." +requires-python = ">=3.10" +keywords = ["cupertino", "slider", "events", "input", "status"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoSlider"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "Column", "CupertinoSlider", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["on_change_start", "on_change", "on_change_end", "live value display"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_slider/media/handling_events.gif b/sdk/python/examples/controls/cupertino/cupertino_slider/media/handling_events.gif new file mode 100644 index 0000000000..6dcc4c7028 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_slider/media/handling_events.gif differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_slider/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_slider/media/index.png new file mode 100644 index 0000000000..59f0b39282 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_slider/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/basic/main.py new file mode 100644 index 0000000000..7202f24ef7 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/basic/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "CupertinoSlidingSegmentedButton Example" + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_selection_change(e: ft.Event[ft.CupertinoSlidingSegmentedButton]): + page.show_dialog( + ft.SnackBar(ft.Text(f"Segment {e.control.selected_index + 1} was chosen!")) + ) + + page.add( + ft.SafeArea( + content=ft.CupertinoSlidingSegmentedButton( + selected_index=1, + thumb_color=ft.Colors.BLUE_400, + on_change=handle_selection_change, + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Three"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/basic/pyproject.toml new file mode 100644 index 0000000000..1602c82675 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-sliding-segmented-button-basic" +version = "1.0.0" +description = "Displays CupertinoSlidingSegmentedButton and shows feedback when segment selection changes." +requires-python = ">=3.10" +keywords = ["cupertino", "sliding segmented button", "selection", "snackbar"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/CupertinoSlidingSegmentedButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "CupertinoSlidingSegmentedButton", "Text", "SnackBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["segment change callback", "selection feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/media/basic.gif b/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/media/basic.gif new file mode 100644 index 0000000000..98d355517e Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_sliding_segmented_button/media/basic.gif differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_switch/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino/cupertino_switch/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..b8e59fc494 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_switch/cupertino_material_and_adaptive/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.CupertinoSwitch(label="Cupertino Switch", value=True), + ft.Switch( + label="Material Switch", + value=True, + thumb_color={ft.ControlState.SELECTED: ft.Colors.BLUE}, + track_color=ft.Colors.YELLOW, + focus_color=ft.Colors.PURPLE, + ), + ft.Container(height=20), + ft.Text( + value=( + "Adaptive Switch shows as CupertinoSwitch on macOS and " + "iOS and as Switch on other platforms:" + ) + ), + ft.Switch(adaptive=True, label="Adaptive Switch", value=True), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..1b90621e72 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_switch/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-switch-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Shows Cupertino, Material, and adaptive switch controls with custom switch styling." +requires-python = ">=3.10" +keywords = ["cupertino", "switch", "adaptive", "material", "toggle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoSwitch"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "CupertinoSwitch", "Switch", "Text", "Container"] +layout_pattern = "form" +complexity = "basic" +features = ["adaptive switch", "cupertino and material comparison", "custom thumb and track colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_switch/media/cupertino_material_and_adaptive.gif b/sdk/python/examples/controls/cupertino/cupertino_switch/media/cupertino_material_and_adaptive.gif new file mode 100644 index 0000000000..f17194470a Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_switch/media/cupertino_material_and_adaptive.gif differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_switch/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_switch/media/index.png new file mode 100644 index 0000000000..b77a655bd6 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_switch/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/background_image/main.py b/sdk/python/examples/controls/cupertino/cupertino_text_field/background_image/main.py new file mode 100644 index 0000000000..bd9c022ea0 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_text_field/background_image/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +async def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.CupertinoTextField( + label="Textfield Label", + label_style=ft.TextStyle(italic=True, weight=ft.FontWeight.BOLD), + bgcolor=ft.Colors.BLUE_GREY, + image=ft.DecorationImage(src="https://picsum.photos/1000/260"), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/background_image/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_text_field/background_image/pyproject.toml new file mode 100644 index 0000000000..fcaf3d9f18 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_text_field/background_image/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-text-field-background-image" +version = "1.0.0" +description = "Applies a background decoration image to CupertinoTextField with custom label styling." +requires-python = ">=3.10" +keywords = ["cupertino", "text field", "background image", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTextField"] + +[tool.flet.metadata] +title = "Background image" +controls = ["SafeArea", "CupertinoTextField", "TextStyle", "DecorationImage"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["text field background image", "custom label style"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/cupertino_material_and_adaptive/main.py b/sdk/python/examples/controls/cupertino/cupertino_text_field/cupertino_material_and_adaptive/main.py new file mode 100644 index 0000000000..5243a7595d --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_text_field/cupertino_material_and_adaptive/main.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + label="Material text field", + label_style=ft.TextStyle(color=ft.Colors.GREY_400), + ), + ft.CupertinoTextField( + placeholder_text="Cupertino text field", + placeholder_style=ft.TextStyle(color=ft.Colors.GREY_400), + ), + ft.TextField( + adaptive=True, + label="Adaptive text field", + label_style=ft.TextStyle(color=ft.Colors.GREY_400), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml new file mode 100644 index 0000000000..fb14e28587 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_text_field/cupertino_material_and_adaptive/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-text-field-cupertino-material-and-adaptive" +version = "1.0.0" +description = "Compares Material, Cupertino, and adaptive text fields with placeholder and label styling." +requires-python = ">=3.10" +keywords = ["cupertino", "text field", "adaptive", "material", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTextField"] + +[tool.flet.metadata] +title = "Cupertino, material and adaptive" +controls = ["SafeArea", "Column", "CupertinoTextField", "TextField", "TextStyle"] +layout_pattern = "form" +complexity = "basic" +features = ["adaptive text field", "cupertino and material comparison"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/media/cupertino_material_and_adaptive.png b/sdk/python/examples/controls/cupertino/cupertino_text_field/media/cupertino_material_and_adaptive.png new file mode 100644 index 0000000000..7380142729 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_text_field/media/cupertino_material_and_adaptive.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/media/index.png b/sdk/python/examples/controls/cupertino/cupertino_text_field/media/index.png new file mode 100644 index 0000000000..2af135ae51 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_text_field/media/index.png differ diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/selection_change/main.py b/sdk/python/examples/controls/cupertino/cupertino_text_field/selection_change/main.py new file mode 100644 index 0000000000..8f9318ba83 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_text_field/selection_change/main.py @@ -0,0 +1,55 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text selection" + + selection = ft.Text("Select some text from the field.") + selection_details = ft.Text() + caret = ft.Text("Caret position: -") + + def handle_selection_change(e: ft.TextSelectionChangeEvent[ft.CupertinoTextField]): + selection.value = ( + f"Selection: '{e.selected_text}'" if e.selected_text else "No selection." + ) + selection_details.value = f"start={e.selection.start}, end={e.selection.end}" + caret.value = f"Caret position: {e.selection.end}" + + field = ft.CupertinoTextField( + value="Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + multiline=True, + min_lines=3, + autofocus=True, + on_selection_change=handle_selection_change, + ) + + async def select_characters(_: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection( + base_offset=0, + extent_offset=len(field.value), + ) + + async def move_caret(_: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection(base_offset=0, extent_offset=0) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=10, + controls=[ + field, + selection, + selection_details, + caret, + ft.Button(content="Select all text", on_click=select_characters), + ft.Button(content="Move caret to start", on_click=move_caret), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_text_field/selection_change/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_text_field/selection_change/pyproject.toml new file mode 100644 index 0000000000..ec7a8dee60 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_text_field/selection_change/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-text-field-selection-change" +version = "1.0.0" +description = "Handles CupertinoTextField text selection changes and provides buttons to select text or move caret." +requires-python = ">=3.10" +keywords = ["cupertino", "text field", "selection", "caret", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTextField"] + +[tool.flet.metadata] +title = "Selection change" +controls = ["SafeArea", "Column", "CupertinoTextField", "Text", "Button", "TextSelection"] +layout_pattern = "form" +complexity = "basic" +features = ["selection change callback", "programmatic selection", "caret control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_timer_picker/basic/main.py b/sdk/python/examples/controls/cupertino/cupertino_timer_picker/basic/main.py new file mode 100644 index 0000000000..b427f5f376 --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_timer_picker/basic/main.py @@ -0,0 +1,49 @@ +import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + timer_value_text = ft.Text( + value="00:01:10", + size=23, + color=ft.CupertinoColors.DESTRUCTIVE_RED, + ) + + def handle_timer_picker_change(e: ft.Event[ft.CupertinoTimerPicker]): + timer_value_text.value = time.strftime("%H:%M:%S", time.gmtime(e.data)) + + timer_picker = ft.CupertinoTimerPicker( + value=300, + second_interval=10, + minute_interval=1, + mode=ft.CupertinoTimerPickerMode.HOUR_MINUTE_SECONDS, + on_change=handle_timer_picker_change, + ) + + page.add( + ft.SafeArea( + content=ft.Row( + tight=True, + controls=[ + ft.Text("TimerPicker Value:", size=23), + ft.CupertinoButton( + on_click=lambda _: page.show_dialog( + ft.CupertinoBottomSheet( + height=216, + padding=ft.Padding.only(top=6), + content=timer_picker, + ) + ), + content=timer_value_text, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/cupertino/cupertino_timer_picker/basic/pyproject.toml b/sdk/python/examples/controls/cupertino/cupertino_timer_picker/basic/pyproject.toml new file mode 100644 index 0000000000..28334699da --- /dev/null +++ b/sdk/python/examples/controls/cupertino/cupertino_timer_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "cupertino-timer-picker-basic" +version = "1.0.0" +description = "Opens CupertinoTimerPicker in a bottom sheet and updates displayed timer value on change." +requires-python = ">=3.10" +keywords = ["cupertino", "timer picker", "bottom sheet", "time", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CupertinoTimerPicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Row", "Text", "CupertinoButton", "CupertinoBottomSheet", "CupertinoTimerPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["timer selection", "on_change callback", "bottom sheet presentation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/cupertino/cupertino_timer_picker/media/basic.gif b/sdk/python/examples/controls/cupertino/cupertino_timer_picker/media/basic.gif new file mode 100644 index 0000000000..75ac9f45e8 Binary files /dev/null and b/sdk/python/examples/controls/cupertino/cupertino_timer_picker/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/alert_dialog/media/adaptive_dialog_action.png b/sdk/python/examples/controls/material/alert_dialog/media/adaptive_dialog_action.png new file mode 100644 index 0000000000..3ef63c5882 Binary files /dev/null and b/sdk/python/examples/controls/material/alert_dialog/media/adaptive_dialog_action.png differ diff --git a/sdk/python/examples/controls/material/alert_dialog/media/index.png b/sdk/python/examples/controls/material/alert_dialog/media/index.png new file mode 100644 index 0000000000..cd343abceb Binary files /dev/null and b/sdk/python/examples/controls/material/alert_dialog/media/index.png differ diff --git a/sdk/python/examples/controls/material/alert_dialog/modal_and_non_modal/main.py b/sdk/python/examples/controls/material/alert_dialog/modal_and_non_modal/main.py new file mode 100644 index 0000000000..138ade206d --- /dev/null +++ b/sdk/python/examples/controls/material/alert_dialog/modal_and_non_modal/main.py @@ -0,0 +1,46 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "AlertDialog examples" + + dialog = ft.AlertDialog( + title=ft.Text("Hello"), + content=ft.Text("You are notified!"), + alignment=ft.Alignment.CENTER, + on_dismiss=lambda e: print("Dialog dismissed!"), + title_padding=ft.Padding.all(25), + ) + + modal_dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Please confirm"), + content=ft.Text("Do you really want to delete all those files?"), + actions=[ + ft.TextButton("Yes", on_click=lambda e: page.pop_dialog()), + ft.TextButton("No", on_click=lambda e: page.pop_dialog()), + ], + actions_alignment=ft.MainAxisAlignment.END, + on_dismiss=lambda e: print("Modal dialog dismissed!"), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Open dialog", + on_click=lambda e: page.show_dialog(dialog), + ), + ft.Button( + content="Open modal dialog", + on_click=lambda e: page.show_dialog(modal_dialog), + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/alert_dialog/modal_and_non_modal/pyproject.toml b/sdk/python/examples/controls/material/alert_dialog/modal_and_non_modal/pyproject.toml new file mode 100644 index 0000000000..cc9dd91aec --- /dev/null +++ b/sdk/python/examples/controls/material/alert_dialog/modal_and_non_modal/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "alert-dialog-modal-and-non-modal" +version = "1.0.0" +description = "AlertDialog example showing modal and non-modal dialog behavior." +requires-python = ">=3.10" +keywords = ["alertdialog", "dialog", "modal", "material", "actions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/AlertDialog"] + +[tool.flet.metadata] +title = "Modal and non-modal dialogs" +controls = ["SafeArea", "Column", "Button", "AlertDialog", "Text", "TextButton"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["modal dialog", "non-modal dialog", "dialog actions", "dismiss events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/app_bar/actions_and_popup_menu/main.py b/sdk/python/examples/controls/material/app_bar/actions_and_popup_menu/main.py new file mode 100644 index 0000000000..33bc4ecf69 --- /dev/null +++ b/sdk/python/examples/controls/material/app_bar/actions_and_popup_menu/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "AppBar Example" + + def handle_checked_item_click(e: ft.Event[ft.PopupMenuItem]): + e.control.checked = not e.control.checked + + page.appbar = ft.AppBar( + leading=ft.Icon(ft.Icons.PALETTE), + leading_width=40, + title=ft.Text("AppBar Example"), + center_title=False, + bgcolor=ft.Colors.BLUE_GREY_400, + actions=[ + ft.IconButton(ft.Icons.WB_SUNNY_OUTLINED), + ft.IconButton(ft.Icons.FILTER_3), + ft.PopupMenuButton( + key="popup", + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(), # divider + ft.PopupMenuItem( + content="Checked item", + checked=False, + on_click=handle_checked_item_click, + ), + ], + ), + ], + ) + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Body!")]))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/app_bar/actions_and_popup_menu/pyproject.toml b/sdk/python/examples/controls/material/app_bar/actions_and_popup_menu/pyproject.toml new file mode 100644 index 0000000000..78c52f2a25 --- /dev/null +++ b/sdk/python/examples/controls/material/app_bar/actions_and_popup_menu/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "app-bar-actions-and-popup-menu" +version = "1.0.0" +description = "AppBar with action icons and popup menu interactions." +requires-python = ">=3.10" +keywords = ["appbar", "navigation", "popup menu", "actions", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/AppBar"] + +[tool.flet.metadata] +title = "Actions and popup menu" +controls = ["AppBar", "Icon", "IconButton", "PopupMenuButton", "PopupMenuItem", "SafeArea", "Column", "Text"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["popup menu actions", "checked state toggle", "app bar actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/app_bar/media/actions_and_popup_menu.gif b/sdk/python/examples/controls/material/app_bar/media/actions_and_popup_menu.gif new file mode 100644 index 0000000000..3ce841fc91 Binary files /dev/null and b/sdk/python/examples/controls/material/app_bar/media/actions_and_popup_menu.gif differ diff --git a/sdk/python/examples/controls/material/app_bar/media/index.png b/sdk/python/examples/controls/material/app_bar/media/index.png new file mode 100644 index 0000000000..61336e5bd2 Binary files /dev/null and b/sdk/python/examples/controls/material/app_bar/media/index.png differ diff --git a/sdk/python/examples/controls/material/app_bar/theme_mode_toggle/main.py b/sdk/python/examples/controls/material/app_bar/theme_mode_toggle/main.py new file mode 100644 index 0000000000..6314e81ffa --- /dev/null +++ b/sdk/python/examples/controls/material/app_bar/theme_mode_toggle/main.py @@ -0,0 +1,99 @@ +import flet as ft + +LIGHT_SEED_COLOR = ft.Colors.DEEP_ORANGE +DARK_SEED_COLOR = ft.Colors.DEEP_PURPLE + + +def main(page: ft.Page): + page.title = "AppBar Example" + + def handle_checked_item_click(e: ft.Event[ft.PopupMenuItem]): + e.control.checked = not e.control.checked + + page.theme_mode = ft.ThemeMode.LIGHT + page.theme = ft.Theme(color_scheme_seed=LIGHT_SEED_COLOR) + page.dark_theme = ft.Theme(color_scheme_seed=DARK_SEED_COLOR) + + def toggle_theme_mode(e: ft.Event[ft.IconButton]): + page.theme_mode = ( + ft.ThemeMode.DARK + if page.theme_mode == ft.ThemeMode.LIGHT + else ft.ThemeMode.LIGHT + ) + theme_mode_toggle.icon = ( + ft.Icons.WB_SUNNY_OUTLINED + if page.theme_mode == ft.ThemeMode.LIGHT + else ft.Icons.WB_SUNNY + ) + + theme_mode_toggle = ft.IconButton( + key="theme_mode_toggle", + icon=( + ft.Icons.WB_SUNNY_OUTLINED + if page.theme_mode == ft.ThemeMode.LIGHT + else ft.Icons.WB_SUNNY + ), + on_click=toggle_theme_mode, + ) + + page.padding = 50 + page.appbar = ft.AppBar( + # toolbar_height=100, + bgcolor=ft.Colors.SECONDARY_CONTAINER, + leading=ft.Icon(ft.Icons.PALETTE), + leading_width=40, + title=ft.Text("AppBar Example"), + center_title=False, + actions=[ + theme_mode_toggle, + ft.PopupMenuButton( + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(icon=ft.Icons.POWER_INPUT, content="Check power"), + ft.PopupMenuItem( + on_click=lambda _: print( + "Button with a custom content clicked!" + ), + content=ft.Row( + controls=[ + ft.Icon(ft.Icons.HOURGLASS_TOP_OUTLINED), + ft.Text("Item with a custom content"), + ] + ), + ), + ft.PopupMenuItem(), # divider + ft.PopupMenuItem( + content="Checked item", + checked=False, + on_click=handle_checked_item_click, + ), + ] + ), + ], + ) + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Flet is a framework that allows building web, desktop " + "and mobile applications in Python without prior experience " + "in frontend development.You can build a UI for your program " + "with Flet controls which are based on Flutter by Google. " + "Flet goes beyond merely wrapping Flutter widgets. It adds " + "its own touch by combining smaller widgets, simplifying " + "complexities, implementing UI best practices, and applying " + "sensible defaults. This ensures that your applications look " + "stylish and polished without requiring additional design " + "efforts on your part.", + text_align=ft.TextAlign.END, + ), + ft.Button("Click me!"), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/app_bar/theme_mode_toggle/pyproject.toml b/sdk/python/examples/controls/material/app_bar/theme_mode_toggle/pyproject.toml new file mode 100644 index 0000000000..03a0df11f3 --- /dev/null +++ b/sdk/python/examples/controls/material/app_bar/theme_mode_toggle/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "app-bar-theme-mode-toggle" +version = "1.0.0" +description = "AppBar example with theme mode toggle and popup menu actions." +requires-python = ">=3.10" +keywords = ["appbar", "navigation", "theme mode", "popup menu"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/AppBar"] + +[tool.flet.metadata] +title = "Theme mode toggle" +controls = ["AppBar", "Icon", "IconButton", "PopupMenuButton", "PopupMenuItem", "SafeArea", "Column", "Text", "Button", "Theme"] +layout_pattern = "toolbar-actions" +complexity = "basic" +features = ["theme mode toggle", "popup menu interactions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/auto_complete/basic/main.py b/sdk/python/examples/controls/material/auto_complete/basic/main.py new file mode 100644 index 0000000000..7edc3f42bc --- /dev/null +++ b/sdk/python/examples/controls/material/auto_complete/basic/main.py @@ -0,0 +1,55 @@ +import flet as ft + +numbers = [ + ("one 1", "One"), + ("two 2", "Two"), + ("three 3", "Three"), + ("four 4", "Four"), + ("five 5", "Five"), + ("six 6", "Six"), + ("seven 7", "Seven"), + ("eight 8", "Eight"), + ("nine 9", "Nine"), + ("ten 10", "Ten"), +] + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def handle_change(e: ft.Event[ft.AutoComplete]): + info.value = f"Current input 👀: {e.data!r} \n" + + def handle_select(e: ft.AutoCompleteSelectEvent): + info.value = ( + f"Current input 👀: {e.control.value!r} \n" + f"Your selection: {e.selection.value}" + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.AutoComplete( + value="One", + width=200, + on_change=handle_change, + on_select=handle_select, + suggestions=[ + ft.AutoCompleteSuggestion(key=key, value=value) + for key, value in numbers + ], + ), + info := ft.Text( + "Enter a number (in words or digits) to get suggestions." + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/auto_complete/basic/pyproject.toml b/sdk/python/examples/controls/material/auto_complete/basic/pyproject.toml new file mode 100644 index 0000000000..f5e35a1a6c --- /dev/null +++ b/sdk/python/examples/controls/material/auto_complete/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "auto-complete-basic" +version = "1.0.0" +description = "Basic AutoComplete with change and select event handling." +requires-python = ">=3.10" +keywords = ["autocomplete", "input", "suggestions", "events", "selection"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/AutoComplete"] + +[tool.flet.metadata] +title = "Basic AutoComplete" +controls = ["SafeArea", "Column", "AutoComplete", "AutoCompleteSuggestion", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["input suggestions", "on_change handling", "on_select handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/autofill_group/basic/main.py b/sdk/python/examples/controls/material/autofill_group/basic/main.py new file mode 100644 index 0000000000..b391f4f215 --- /dev/null +++ b/sdk/python/examples/controls/material/autofill_group/basic/main.py @@ -0,0 +1,38 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.AutofillGroup( + content=ft.Column( + controls=[ + ft.TextField( + label="Name", + autofill_hints=ft.AutofillHint.NAME, + ), + ft.TextField( + label="Email", + autofill_hints=[ft.AutofillHint.EMAIL], + ), + ft.TextField( + label="Phone Number", + autofill_hints=[ft.AutofillHint.TELEPHONE_NUMBER], + ), + ft.TextField( + label="Street Address", + autofill_hints=ft.AutofillHint.FULL_STREET_ADDRESS, + ), + ft.TextField( + label="Postal Code", + autofill_hints=ft.AutofillHint.POSTAL_CODE, + ), + ] + ) + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/autofill_group/basic/pyproject.toml b/sdk/python/examples/controls/material/autofill_group/basic/pyproject.toml new file mode 100644 index 0000000000..3127e997f6 --- /dev/null +++ b/sdk/python/examples/controls/material/autofill_group/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "autofill-group-basic" +version = "1.0.0" +description = "Basic AutofillGroup with common autofill hints." +requires-python = ">=3.10" +keywords = ["autofillgroup", "autofill", "input", "text field", "form"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/AutofillGroup"] + +[tool.flet.metadata] +title = "Basic AutofillGroup" +controls = ["SafeArea", "AutofillGroup", "Column", "TextField"] +layout_pattern = "form" +complexity = "basic" +features = ["autofill hints", "grouped form fields"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/autofill_group/media/basic.gif b/sdk/python/examples/controls/material/autofill_group/media/basic.gif new file mode 100644 index 0000000000..ccbbf5c4b9 Binary files /dev/null and b/sdk/python/examples/controls/material/autofill_group/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/badge/basic/main.py b/sdk/python/examples/controls/material/badge/basic/main.py new file mode 100644 index 0000000000..1bcb907ef2 --- /dev/null +++ b/sdk/python/examples/controls/material/badge/basic/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Badge example" + page.navigation_bar = ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination( + icon=ft.Icon( + ft.Icons.EXPLORE, + badge=ft.Badge(small_size=10), + ), + label="Explore", + ), + ft.NavigationBarDestination( + icon=ft.Icons.COMMUTE, + label="Commute", + ), + ft.NavigationBarDestination( + icon=ft.Icon( + ft.Icons.PHONE, + badge="10", + ) + ), + ] + ) + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Body!")]))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/badge/basic/pyproject.toml b/sdk/python/examples/controls/material/badge/basic/pyproject.toml new file mode 100644 index 0000000000..1172027519 --- /dev/null +++ b/sdk/python/examples/controls/material/badge/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "badge-basic" +version = "1.0.0" +description = "Basic Badge usage on NavigationBar icons." +requires-python = ">=3.10" +keywords = ["badge", "display", "navigation bar", "icon", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Badge"] + +[tool.flet.metadata] +title = "Basic Badge" +controls = ["NavigationBar", "NavigationBarDestination", "Icon", "Badge", "SafeArea", "Column", "Text"] +layout_pattern = "navigation" +complexity = "basic" +features = ["badge on icon", "text badge", "small badge indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/banner/basic/main.py b/sdk/python/examples/controls/material/banner/basic/main.py new file mode 100644 index 0000000000..38fe8f4578 --- /dev/null +++ b/sdk/python/examples/controls/material/banner/basic/main.py @@ -0,0 +1,56 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_banner_close(e: ft.Event[ft.TextButton]): + page.pop_dialog() + page.add(ft.Text("Action clicked: " + e.control.data)) + + action_button_style = ft.ButtonStyle(color=ft.Colors.BLUE) + banner = ft.Banner( + bgcolor=ft.Colors.AMBER_100, + leading=ft.Icon(ft.Icons.WARNING_AMBER_ROUNDED, color=ft.Colors.AMBER, size=40), + content=ft.Text( + value="Oops, there were some errors while trying to delete the file. " + "What would you like to do?", + color=ft.Colors.BLACK, + ), + actions=[ + ft.TextButton( + content="Retry", + style=action_button_style, + on_click=handle_banner_close, + data="retry", + ), + ft.TextButton( + content="Ignore", + style=action_button_style, + on_click=handle_banner_close, + data="ignore", + ), + ft.TextButton( + content="Cancel", + style=action_button_style, + on_click=handle_banner_close, + data="cancel", + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Show Banner", on_click=lambda e: page.show_dialog(banner) + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/banner/basic/pyproject.toml b/sdk/python/examples/controls/material/banner/basic/pyproject.toml new file mode 100644 index 0000000000..42eda939e0 --- /dev/null +++ b/sdk/python/examples/controls/material/banner/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "banner-basic" +version = "1.0.0" +description = "Basic Banner dialog with action buttons." +requires-python = ">=3.10" +keywords = ["banner", "dialog", "actions", "material", "notification"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/Banner"] + +[tool.flet.metadata] +title = "Basic Banner" +controls = ["SafeArea", "Column", "Button", "Banner", "Icon", "Text", "TextButton"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["banner dialog", "action buttons", "dialog close and follow-up message"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/banner/media/basic.gif b/sdk/python/examples/controls/material/banner/media/basic.gif new file mode 100644 index 0000000000..58271ae1f1 Binary files /dev/null and b/sdk/python/examples/controls/material/banner/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/bottom_app_bar/border_radius/main.py b/sdk/python/examples/controls/material/bottom_app_bar/border_radius/main.py new file mode 100644 index 0000000000..e23794c53e --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_app_bar/border_radius/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.bottom_appbar = ft.BottomAppBar( + border_radius=ft.BorderRadius.all(20), + bgcolor=ft.Colors.BLUE, + content=ft.Row( + controls=[ + ft.IconButton(icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE), + ft.Container(expand=True), + ft.IconButton(icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE), + ft.IconButton(icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE), + ] + ), + ) + + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Content goes here...")]))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/bottom_app_bar/border_radius/pyproject.toml b/sdk/python/examples/controls/material/bottom_app_bar/border_radius/pyproject.toml new file mode 100644 index 0000000000..ee7bd517a8 --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_app_bar/border_radius/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-app-bar-border-radius" +version = "1.0.0" +description = "BottomAppBar with custom border radius." +requires-python = ">=3.10" +keywords = ["bottom app bar", "navigation", "border radius", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/BottomAppBar"] + +[tool.flet.metadata] +title = "BottomAppBar border radius" +controls = ["BottomAppBar", "Row", "IconButton", "Container", "SafeArea", "Column", "Text"] +layout_pattern = "navigation" +complexity = "basic" +features = ["custom border radius", "app bar actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/bottom_app_bar/notched_fab/main.py b/sdk/python/examples/controls/material/bottom_app_bar/notched_fab/main.py new file mode 100644 index 0000000000..4e3e1dee21 --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_app_bar/notched_fab/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, + shape=ft.CircleBorder(), + ) + page.floating_action_button_location = ft.FloatingActionButtonLocation.CENTER_DOCKED + + page.bottom_appbar = ft.BottomAppBar( + bgcolor=ft.Colors.BLUE, + shape=ft.CircularRectangleNotchShape(), + content=ft.Row( + controls=[ + ft.IconButton(icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE), + ft.Container(expand=True), + ft.IconButton(icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE), + ft.IconButton(icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE), + ] + ), + ) + + page.add(ft.SafeArea(content=ft.Column(controls=[ft.Text("Content goes here...")]))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/bottom_app_bar/notched_fab/pyproject.toml b/sdk/python/examples/controls/material/bottom_app_bar/notched_fab/pyproject.toml new file mode 100644 index 0000000000..f36832054d --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_app_bar/notched_fab/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-app-bar-notched-fab" +version = "1.0.0" +description = "BottomAppBar with a notched centered FloatingActionButton." +requires-python = ">=3.10" +keywords = ["bottom app bar", "navigation", "floating action button", "notch", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/BottomAppBar"] + +[tool.flet.metadata] +title = "Notched FloatingActionButton" +controls = ["BottomAppBar", "FloatingActionButton", "Row", "IconButton", "Container", "SafeArea", "Column", "Text"] +layout_pattern = "navigation" +complexity = "basic" +features = ["center docked FAB", "notched app bar", "app bar actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/bottom_sheet/basic/main.py b/sdk/python/examples/controls/material/bottom_sheet/basic/main.py new file mode 100644 index 0000000000..d177d87532 --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_sheet/basic/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "BottomSheet Example" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_sheet_dismissal(e: ft.Event[ft.DialogControl]): + page.add(ft.Text("Bottom sheet dismissed")) + + sheet = ft.BottomSheet( + on_dismiss=handle_sheet_dismissal, + content=ft.Container( + padding=50, + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + tight=True, + controls=[ + ft.Text("Here is a bottom sheet!"), + ft.Button("Dismiss", on_click=lambda _: page.pop_dialog()), + ], + ), + ), + ) + + page.add( + ft.SafeArea( + # avoid_intrusions_left=False, + # avoid_intrusions_top=False, + # avoid_intrusions_right=False, + # avoid_intrusions_bottom=False, + content=ft.Column( + controls=[ + ft.Button( + content="Display bottom sheet", + on_click=lambda e: page.show_dialog(sheet), + ) + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/bottom_sheet/basic/pyproject.toml b/sdk/python/examples/controls/material/bottom_sheet/basic/pyproject.toml new file mode 100644 index 0000000000..8ca7ef2873 --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_sheet/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-sheet-basic" +version = "1.0.0" +description = "Basic BottomSheet dialog with dismiss handling." +requires-python = ">=3.10" +keywords = ["bottom sheet", "dialog", "material", "dismiss", "actions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/BottomSheet"] + +[tool.flet.metadata] +title = "Basic BottomSheet" +controls = ["SafeArea", "Column", "Button", "BottomSheet", "Container", "Text"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["bottom sheet dialog", "dismiss callback", "dialog actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/bottom_sheet/fullscreen/main.py b/sdk/python/examples/controls/material/bottom_sheet/fullscreen/main.py new file mode 100644 index 0000000000..c83d974ad3 --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_sheet/fullscreen/main.py @@ -0,0 +1,46 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_switch_change(e: ft.Event[ft.Switch]): + sheet.fullscreen = e.control.value + + sheet = ft.BottomSheet( + fullscreen=True, + show_drag_handle=True, + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("This is bottom sheet's content!"), + ft.Button("Close bottom sheet", on_click=lambda: page.pop_dialog()), + ], + ), + ), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Button( + content="Display bottom sheet", + on_click=lambda e: page.show_dialog(sheet), + ), + ft.Switch( + value=True, + label="Fullscreen", + on_change=handle_switch_change, + ), + ], + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/bottom_sheet/fullscreen/pyproject.toml b/sdk/python/examples/controls/material/bottom_sheet/fullscreen/pyproject.toml new file mode 100644 index 0000000000..ed8a9d2eff --- /dev/null +++ b/sdk/python/examples/controls/material/bottom_sheet/fullscreen/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "bottom-sheet-fullscreen" +version = "1.0.0" +description = "BottomSheet with fullscreen toggle and drag handle." +requires-python = ">=3.10" +keywords = ["bottom sheet", "dialog", "fullscreen", "switch", "drag handle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/BottomSheet"] + +[tool.flet.metadata] +title = "BottomSheet fullscreen" +controls = ["SafeArea", "Column", "Button", "Switch", "BottomSheet", "Container", "Text"] +layout_pattern = "dialog-flow" +complexity = "basic" +features = ["fullscreen toggle", "bottom sheet dialog", "drag handle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/animate_on_hover/main.py b/sdk/python/examples/controls/material/button/animate_on_hover/main.py new file mode 100644 index 0000000000..48bee832f6 --- /dev/null +++ b/sdk/python/examples/controls/material/button/animate_on_hover/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def animate(e: ft.Event[ft.Button]): + e.control.rotate = 0.1 if e.data else 0 + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Hover over me, I'm animated!", + rotate=0, + animate_rotation=100, + on_hover=animate, + on_click=lambda e: page.add( + ft.Text("Clicked! Try a long press!") + ), + on_long_press=lambda e: page.add( + ft.Text("I knew you could do it!") + ), + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/animate_on_hover/pyproject.toml b/sdk/python/examples/controls/material/button/animate_on_hover/pyproject.toml new file mode 100644 index 0000000000..4fdd92ca6a --- /dev/null +++ b/sdk/python/examples/controls/material/button/animate_on_hover/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-animate-on-hover" +version = "1.0.0" +description = "Animated button rotation on hover with click and long-press actions." +requires-python = ">=3.10" +keywords = ["button", "hover", "animation", "click", "long press"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Animate on hover" +controls = ["SafeArea", "Column", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["hover animation", "click handling", "long press handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/basic/main.py b/sdk/python/examples/controls/material/button/basic/main.py new file mode 100644 index 0000000000..5ed3eb5012 --- /dev/null +++ b/sdk/python/examples/controls/material/button/basic/main.py @@ -0,0 +1,18 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button(content="Enabled button"), + ft.Button(content="Disabled button", disabled=True), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/basic/pyproject.toml b/sdk/python/examples/controls/material/button/basic/pyproject.toml new file mode 100644 index 0000000000..5f2ab8d7a5 --- /dev/null +++ b/sdk/python/examples/controls/material/button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-basic" +version = "1.0.0" +description = "Basic enabled and disabled Button examples." +requires-python = ">=3.10" +keywords = ["button", "material", "basic", "disabled"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Basic button" +controls = ["SafeArea", "Column", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/button_shapes/main.py b/sdk/python/examples/controls/material/button/button_shapes/main.py new file mode 100644 index 0000000000..b8535d9b0b --- /dev/null +++ b/sdk/python/examples/controls/material/button/button_shapes/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 30 + page.spacing = 30 + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Stadium", + style=ft.ButtonStyle(shape=ft.StadiumBorder()), + ), + ft.Button( + content="Rounded rectangle", + style=ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10) + ), + ), + ft.Button( + content="Continuous rectangle", + style=ft.ButtonStyle( + shape=ft.ContinuousRectangleBorder(radius=30) + ), + ), + ft.Button( + content="Beveled rectangle", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=10) + ), + ), + ft.Button( + content="Circle", + style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=30), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/button_shapes/pyproject.toml b/sdk/python/examples/controls/material/button/button_shapes/pyproject.toml new file mode 100644 index 0000000000..7341199ad7 --- /dev/null +++ b/sdk/python/examples/controls/material/button/button_shapes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-shapes" +version = "1.0.0" +description = "Button examples demonstrating different shape styles." +requires-python = ">=3.10" +keywords = ["button", "shape", "styling", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Button shapes" +controls = ["SafeArea", "Column", "Button", "ButtonStyle"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["shape styling", "multiple border types"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/custom_content/main.py b/sdk/python/examples/controls/material/button/custom_content/main.py new file mode 100644 index 0000000000..d55ef98eba --- /dev/null +++ b/sdk/python/examples/controls/material/button/custom_content/main.py @@ -0,0 +1,40 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + width=150, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), + ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), + ], + ), + ), + ft.Button( + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + spacing=5, + controls=[ + ft.Text(value="Compound button", size=20), + ft.Text(value="This is secondary text"), + ], + ), + ), + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/custom_content/pyproject.toml b/sdk/python/examples/controls/material/button/custom_content/pyproject.toml new file mode 100644 index 0000000000..e35326baaa --- /dev/null +++ b/sdk/python/examples/controls/material/button/custom_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-custom-content" +version = "1.0.0" +description = "Buttons with custom row and column content." +requires-python = ">=3.10" +keywords = ["button", "custom content", "layout", "icons", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Custom content" +controls = ["SafeArea", "Column", "Button", "Row", "Container", "Icon", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom button content", "compound button layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/handling_clicks/main.py b/sdk/python/examples/controls/material/button/handling_clicks/main.py new file mode 100644 index 0000000000..74c18fd0fb --- /dev/null +++ b/sdk/python/examples/controls/material/button/handling_clicks/main.py @@ -0,0 +1,26 @@ +import flet as ft + + +def main(page: ft.Page): + def button_clicked(e: ft.Event[ft.Button]): + button.data += 1 + message.value = f"Button clicked {button.data} time(s)" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.Button( + content="Button with 'click' event", + data=0, + on_click=button_clicked, + ), + message := ft.Text(), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/material/button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..cd5400a91e --- /dev/null +++ b/sdk/python/examples/controls/material/button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-handling-clicks" +version = "1.0.0" +description = "Button click handling with a live click counter." +requires-python = ">=3.10" +keywords = ["button", "events", "on_click", "counter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["click event handling", "dynamic label updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/icons/main.py b/sdk/python/examples/controls/material/button/icons/main.py new file mode 100644 index 0000000000..0476f6b5ac --- /dev/null +++ b/sdk/python/examples/controls/material/button/icons/main.py @@ -0,0 +1,22 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button(content="Button with icon", icon=ft.Icons.WAVES_ROUNDED), + ft.Button( + content="Button with colorful icon", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/icons/pyproject.toml b/sdk/python/examples/controls/material/button/icons/pyproject.toml new file mode 100644 index 0000000000..b5d29b90e7 --- /dev/null +++ b/sdk/python/examples/controls/material/button/icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-icons" +version = "1.0.0" +description = "Button examples with default and custom icon colors." +requires-python = ">=3.10" +keywords = ["button", "icon", "material", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Buttons with icons" +controls = ["SafeArea", "Column", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["button icons", "custom icon color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/button/media/adaptive.png b/sdk/python/examples/controls/material/button/media/adaptive.png new file mode 100644 index 0000000000..64405df7cb Binary files /dev/null and b/sdk/python/examples/controls/material/button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/button/media/basic.png b/sdk/python/examples/controls/material/button/media/basic.png new file mode 100644 index 0000000000..93b513e460 Binary files /dev/null and b/sdk/python/examples/controls/material/button/media/basic.png differ diff --git a/sdk/python/examples/controls/material/button/media/custom_content.png b/sdk/python/examples/controls/material/button/media/custom_content.png new file mode 100644 index 0000000000..1786efb255 Binary files /dev/null and b/sdk/python/examples/controls/material/button/media/custom_content.png differ diff --git a/sdk/python/examples/controls/material/button/media/handling_clicks.gif b/sdk/python/examples/controls/material/button/media/handling_clicks.gif new file mode 100644 index 0000000000..de5963a703 Binary files /dev/null and b/sdk/python/examples/controls/material/button/media/handling_clicks.gif differ diff --git a/sdk/python/examples/controls/material/button/media/icons.png b/sdk/python/examples/controls/material/button/media/icons.png new file mode 100644 index 0000000000..f588eded02 Binary files /dev/null and b/sdk/python/examples/controls/material/button/media/icons.png differ diff --git a/sdk/python/examples/controls/material/button/media/index.png b/sdk/python/examples/controls/material/button/media/index.png new file mode 100644 index 0000000000..068570191f Binary files /dev/null and b/sdk/python/examples/controls/material/button/media/index.png differ diff --git a/sdk/python/examples/controls/material/button/styling/main.py b/sdk/python/examples/controls/material/button/styling/main.py new file mode 100644 index 0000000000..9af4e73372 --- /dev/null +++ b/sdk/python/examples/controls/material/button/styling/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Styled button 1", + style=ft.ButtonStyle( + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + bgcolor={ + ft.ControlState.FOCUSED: ft.Colors.PINK_200, + ft.ControlState.DEFAULT: ft.Colors.YELLOW, + }, + padding={ft.ControlState.HOVERED: 20}, + overlay_color=ft.Colors.TRANSPARENT, + elevation={ + ft.ControlState.DEFAULT: 0, + ft.ControlState.HOVERED: 5, + ft.ControlState.PRESSED: 10, + }, + animation_duration=500, + side={ + ft.ControlState.DEFAULT: ft.BorderSide( + 1, color=ft.Colors.BLUE_100 + ), + ft.ControlState.HOVERED: ft.BorderSide( + 3, color=ft.Colors.BLUE_400 + ), + ft.ControlState.PRESSED: ft.BorderSide( + 6, color=ft.Colors.BLUE_600 + ), + }, + shape={ + ft.ControlState.HOVERED: ft.RoundedRectangleBorder( + radius=20 + ), + ft.ControlState.DEFAULT: ft.RoundedRectangleBorder( + radius=2 + ), + }, + ), + ) + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/button/styling/pyproject.toml b/sdk/python/examples/controls/material/button/styling/pyproject.toml new file mode 100644 index 0000000000..da5d934598 --- /dev/null +++ b/sdk/python/examples/controls/material/button/styling/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "button-styling" +version = "1.0.0" +description = "Button style customization by control states." +requires-python = ">=3.10" +keywords = ["button", "styling", "control state", "animation", "hover"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Button styling" +controls = ["SafeArea", "Column", "Button", "ButtonStyle", "BorderSide"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["state-based styling", "hover effects", "animated style transitions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/card/media/music_info.gif b/sdk/python/examples/controls/material/card/media/music_info.gif new file mode 100644 index 0000000000..63aff20eaa Binary files /dev/null and b/sdk/python/examples/controls/material/card/media/music_info.gif differ diff --git a/sdk/python/examples/controls/material/card/music_info/main.py b/sdk/python/examples/controls/material/card/music_info/main.py new file mode 100644 index 0000000000..3996d62040 --- /dev/null +++ b/sdk/python/examples/controls/material/card/music_info/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Card Example" + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.Card( + shadow_color=ft.Colors.ON_SURFACE_VARIANT, + content=ft.Container( + width=400, + padding=10, + content=ft.Column( + controls=[ + ft.ListTile( + bgcolor=ft.Colors.GREY_400, + leading=ft.Icon(ft.Icons.ALBUM), + title=ft.Text("The Enchanted Nightingale"), + subtitle=ft.Text( + "Music by Julie Gable. Lyrics by Sidney Stein." + ), + ), + ft.Row( + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.TextButton("Buy tickets"), + ft.TextButton("Listen"), + ], + ), + ] + ), + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/card/music_info/pyproject.toml b/sdk/python/examples/controls/material/card/music_info/pyproject.toml new file mode 100644 index 0000000000..3915c0af7c --- /dev/null +++ b/sdk/python/examples/controls/material/card/music_info/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "card-music-info" +version = "1.0.0" +description = "Card with music info and action buttons." +requires-python = ">=3.10" +keywords = ["card", "listtile", "actions", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Card"] + +[tool.flet.metadata] +title = "Music info" +controls = ["SafeArea", "Card", "Container", "Column", "ListTile", "Row", "TextButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["card layout", "action buttons"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/checkbox/basic/main.py b/sdk/python/examples/controls/material/checkbox/basic/main.py new file mode 100644 index 0000000000..39d2161d59 --- /dev/null +++ b/sdk/python/examples/controls/material/checkbox/basic/main.py @@ -0,0 +1,36 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + f"Checkboxes values are: {c1.value}, {c2.value}, {c3.value}, " + f"{c4.value}, {c5.value}." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + c1 := ft.Checkbox( + label="Unchecked by default checkbox", value=False + ), + c2 := ft.Checkbox( + label="Undefined by default tristate checkbox", tristate=True + ), + c3 := ft.Checkbox(label="Checked by default checkbox", value=True), + c4 := ft.Checkbox(label="Disabled checkbox", disabled=True), + c5 := ft.Checkbox( + label="Checkbox with LEFT label_position", + label_position=ft.LabelPosition.LEFT, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/checkbox/basic/pyproject.toml b/sdk/python/examples/controls/material/checkbox/basic/pyproject.toml new file mode 100644 index 0000000000..5c43b689e5 --- /dev/null +++ b/sdk/python/examples/controls/material/checkbox/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "checkbox-basic" +version = "1.0.0" +description = "Basic checkbox states with a submit action." +requires-python = ">=3.10" +keywords = ["checkbox", "material", "input", "form", "state", "tristate"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Checkbox"] + +[tool.flet.metadata] +title = "Basic checkbox" +controls = ["SafeArea", "Column", "Checkbox", "Button", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["checkbox state examples", "button click handling", "value summary output"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/checkbox/handling_events/main.py b/sdk/python/examples/controls/material/checkbox/handling_events/main.py new file mode 100644 index 0000000000..01588ec09b --- /dev/null +++ b/sdk/python/examples/controls/material/checkbox/handling_events/main.py @@ -0,0 +1,26 @@ +import flet as ft + + +def main(page: ft.Page): + events = ft.Column() + + def handle_checkbox_change(e: ft.Event[ft.Checkbox]): + events.controls.append(ft.Text(f"Checkbox value changed to {e.control.value}")) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Checkbox( + label="Checkbox with 'change' event", + on_change=handle_checkbox_change, + ), + events, + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/checkbox/handling_events/pyproject.toml b/sdk/python/examples/controls/material/checkbox/handling_events/pyproject.toml new file mode 100644 index 0000000000..fce792665c --- /dev/null +++ b/sdk/python/examples/controls/material/checkbox/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "checkbox-handling-events" +version = "1.0.0" +description = "Checkbox change event handling with dynamic text updates." +requires-python = ">=3.10" +keywords = ["checkbox", "material", "input", "events", "on_change", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Checkbox"] + +[tool.flet.metadata] +title = "Checkbox events" +controls = ["SafeArea", "Column", "Checkbox", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["on_change handling", "event-driven UI updates", "state change log"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/checkbox/media/basic.gif b/sdk/python/examples/controls/material/checkbox/media/basic.gif new file mode 100644 index 0000000000..392020d1db Binary files /dev/null and b/sdk/python/examples/controls/material/checkbox/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/checkbox/media/handling_events.gif b/sdk/python/examples/controls/material/checkbox/media/handling_events.gif new file mode 100644 index 0000000000..dd01bac222 Binary files /dev/null and b/sdk/python/examples/controls/material/checkbox/media/handling_events.gif differ diff --git a/sdk/python/examples/controls/material/checkbox/media/index.png b/sdk/python/examples/controls/material/checkbox/media/index.png new file mode 100644 index 0000000000..0cf5bb73ed Binary files /dev/null and b/sdk/python/examples/controls/material/checkbox/media/index.png differ diff --git a/sdk/python/examples/controls/material/checkbox/styled/main.py b/sdk/python/examples/controls/material/checkbox/styled/main.py new file mode 100644 index 0000000000..316741d037 --- /dev/null +++ b/sdk/python/examples/controls/material/checkbox/styled/main.py @@ -0,0 +1,35 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Checkbox(label="Checkbox with default style"), + ft.Checkbox( + label="Checkbox with constant fill color", + fill_color=ft.Colors.RED, + check_color=ft.Colors.YELLOW, + ), + ft.Row( + controls=[ + ft.Checkbox( + key="dynamic_fill_checkbox", + fill_color={ + ft.ControlState.HOVERED: ft.Colors.BLUE, + ft.ControlState.SELECTED: ft.Colors.GREEN, + ft.ControlState.DEFAULT: ft.Colors.RED, + }, + ), + ft.Text("Checkbox with dynamic fill color"), + ], + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/checkbox/styled/pyproject.toml b/sdk/python/examples/controls/material/checkbox/styled/pyproject.toml new file mode 100644 index 0000000000..ecd06ccd75 --- /dev/null +++ b/sdk/python/examples/controls/material/checkbox/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "checkbox-styled" +version = "1.0.0" +description = "Styled checkboxes with fixed and state-based colors." +requires-python = ">=3.10" +keywords = ["checkbox", "material", "input", "styling", "colors", "controlstate"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Checkbox"] + +[tool.flet.metadata] +title = "Styled checkboxes" +controls = ["SafeArea", "Column", "Checkbox"] +layout_pattern = "form" +complexity = "basic" +features = ["static styling", "state-based fill colors", "custom check color"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/chip/assist_chips/main.py b/sdk/python/examples/controls/material/chip/assist_chips/main.py new file mode 100644 index 0000000000..4579949c82 --- /dev/null +++ b/sdk/python/examples/controls/material/chip/assist_chips/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + url_launcher = ft.UrlLauncher() + page.services.append(url_launcher) + + def handle_chip1_click(e: ft.Event[ft.Chip]): + e.control.label.value = "Saved to favorites" + e.control.leading = ft.Icon(ft.Icons.FAVORITE_OUTLINED) + e.control.disabled = True + + async def handle_chip2_click(e: ft.Event[ft.Chip]): + await url_launcher.launch_url("https://maps.google.com") + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.Chip( + label=ft.Text("Save to favourites"), + leading=ft.Icon(ft.Icons.FAVORITE_BORDER_OUTLINED), + bgcolor=ft.Colors.GREEN_200, + disabled_color=ft.Colors.GREEN_100, + autofocus=True, + on_click=handle_chip1_click, + ), + ft.Chip( + label=ft.Text("9 min walk"), + leading=ft.Icon(ft.Icons.MAP_SHARP), + bgcolor=ft.Colors.GREEN_200, + on_click=handle_chip2_click, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/chip/assist_chips/pyproject.toml b/sdk/python/examples/controls/material/chip/assist_chips/pyproject.toml new file mode 100644 index 0000000000..3f1b5da46d --- /dev/null +++ b/sdk/python/examples/controls/material/chip/assist_chips/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "chip-assist-chips" +version = "1.0.0" +description = "Assist chips with click actions and dynamic state updates." +requires-python = ">=3.10" +keywords = ["chip", "assist chip", "material", "input", "actions", "async", "url launch"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Chip"] + +[tool.flet.metadata] +title = "Assist chips" +controls = ["SafeArea", "Row", "Chip", "Icon", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["click handling", "async url launch", "dynamic chip state"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/chip/filter_chips/main.py b/sdk/python/examples/controls/material/chip/filter_chips/main.py new file mode 100644 index 0000000000..d2f4b4ff67 --- /dev/null +++ b/sdk/python/examples/controls/material/chip/filter_chips/main.py @@ -0,0 +1,39 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_amenity_selection(e: ft.Event[ft.Chip]): + print("Amenity selected:", e.control.label.value) + + amenities = ["Washer / Dryer", "Ramp access", "Dogs OK", "Cats OK", "Smoke-free"] + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Icon(ft.Icons.HOTEL_CLASS), + ft.Text("Amenities"), + ] + ), + ft.Row( + controls=[ + ft.Chip( + label=ft.Text(amenity), + bgcolor=ft.Colors.GREEN_200, + disabled_color=ft.Colors.GREEN_100, + autofocus=True, + on_select=handle_amenity_selection, + ) + for amenity in amenities + ] + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/chip/filter_chips/pyproject.toml b/sdk/python/examples/controls/material/chip/filter_chips/pyproject.toml new file mode 100644 index 0000000000..d0c2aea954 --- /dev/null +++ b/sdk/python/examples/controls/material/chip/filter_chips/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "chip-filter-chips" +version = "1.0.0" +description = "Filter chips for amenity selection with on_select events." +requires-python = ">=3.10" +keywords = ["chip", "filter chip", "material", "input", "selection", "filters"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Chip"] + +[tool.flet.metadata] +title = "Filter chips" +controls = ["SafeArea", "Column", "Row", "Chip", "Icon", "Text"] +layout_pattern = "filter-bar" +complexity = "basic" +features = ["selection handling", "chip toggles", "event-driven filtering UI"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/chip/media/assist_chips.png b/sdk/python/examples/controls/material/chip/media/assist_chips.png new file mode 100644 index 0000000000..9c086f24fc Binary files /dev/null and b/sdk/python/examples/controls/material/chip/media/assist_chips.png differ diff --git a/sdk/python/examples/controls/material/chip/media/filter_chips.png b/sdk/python/examples/controls/material/chip/media/filter_chips.png new file mode 100644 index 0000000000..77d6ce280b Binary files /dev/null and b/sdk/python/examples/controls/material/chip/media/filter_chips.png differ diff --git a/sdk/python/examples/controls/material/circle_avatar/media/user_avatars.png b/sdk/python/examples/controls/material/circle_avatar/media/user_avatars.png new file mode 100644 index 0000000000..a5143c1c5e Binary files /dev/null and b/sdk/python/examples/controls/material/circle_avatar/media/user_avatars.png differ diff --git a/sdk/python/examples/controls/material/circle_avatar/user_avatars/main.py b/sdk/python/examples/controls/material/circle_avatar/user_avatars/main.py new file mode 100644 index 0000000000..e05a253f24 --- /dev/null +++ b/sdk/python/examples/controls/material/circle_avatar/user_avatars/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + # a "normal" avatar with background image + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4", + content=ft.Text("FF"), + ), + # avatar with failing foreground image and fallback text + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/_5041459?s=88&v=4", + content=ft.Text("FF"), + ), + # avatar with icon, aka icon with inverse background + ft.CircleAvatar(content=ft.Icon(ft.Icons.ABC)), + # avatar with icon and custom colors + ft.CircleAvatar( + content=ft.Icon(ft.Icons.WARNING_ROUNDED), + color=ft.Colors.YELLOW_200, + bgcolor=ft.Colors.AMBER_700, + ), + # avatar with online status + ft.Stack( + width=40, + height=40, + controls=[ + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" + ), + ft.Container( + alignment=ft.Alignment.BOTTOM_LEFT, + content=ft.CircleAvatar( + bgcolor=ft.Colors.GREEN, radius=5 + ), + ), + ], + ), + ] + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/circle_avatar/user_avatars/pyproject.toml b/sdk/python/examples/controls/material/circle_avatar/user_avatars/pyproject.toml new file mode 100644 index 0000000000..4a35a23979 --- /dev/null +++ b/sdk/python/examples/controls/material/circle_avatar/user_avatars/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "circle-avatar-user-avatars" +version = "1.0.0" +description = "CircleAvatar showcase with images, icons, fallback content, and online status badge." +requires-python = ">=3.10" +keywords = ["circleavatar", "avatar", "image", "icon", "status"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/CircleAvatar"] + +[tool.flet.metadata] +title = "User avatars" +controls = ["SafeArea", "CircleAvatar", "Text", "Icon", "Stack", "Container"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["image avatar", "fallback content", "online status indicator"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/context_menu/custom_trigger/main.py b/sdk/python/examples/controls/material/context_menu/custom_trigger/main.py new file mode 100644 index 0000000000..e75d19d64f --- /dev/null +++ b/sdk/python/examples/controls/material/context_menu/custom_trigger/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +def main(page: ft.Page): + async def open_menu(e: ft.TapEvent[ft.GestureDetector]): + await menu.open( + local_position=e.local_position, + global_position=e.global_position, + ) + + menu = ft.ContextMenu( + expand=True, + items=[ + ft.PopupMenuItem( + content="Cut", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Copy", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Paste", + on_click=lambda e: print(f"{e.control.content}"), + ), + ], + content=ft.GestureDetector( + expand=True, + on_double_tap_down=open_menu, + content=ft.Container( + key="context_menu_custom_trigger_area", + bgcolor=ft.Colors.BLUE, + alignment=ft.Alignment.CENTER, + content=ft.Text("Double-click to open the context menu."), + ), + ), + ) + + page.add( + ft.SafeArea( + expand=True, + content=menu, + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/context_menu/custom_trigger/pyproject.toml b/sdk/python/examples/controls/material/context_menu/custom_trigger/pyproject.toml new file mode 100644 index 0000000000..9ef4f4a086 --- /dev/null +++ b/sdk/python/examples/controls/material/context_menu/custom_trigger/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "context-menu-custom-trigger" +version = "1.0.0" +description = "Opens ContextMenu from a custom double-tap gesture with precise pointer position." +requires-python = ">=3.10" +keywords = ["context menu", "custom trigger", "gesture", "double tap"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/ContextMenu"] + +[tool.flet.metadata] +title = "Custom trigger" +controls = ["SafeArea", "ContextMenu", "PopupMenuItem", "GestureDetector", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom open trigger", "position-based menu opening"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/context_menu/programmatic_open/main.py b/sdk/python/examples/controls/material/context_menu/programmatic_open/main.py new file mode 100644 index 0000000000..a9c02c06cf --- /dev/null +++ b/sdk/python/examples/controls/material/context_menu/programmatic_open/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def handle_select(e: ft.ContextMenuSelectEvent): + action = e.item.content + page.show_dialog(ft.SnackBar(f"Item '{action}' selected.")) + + async def open_menu(e: ft.Event[ft.Button]): + await menu.open() + + menu = ft.ContextMenu( + on_select=handle_select, + items=[ + ft.PopupMenuItem( + content="Item 1", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Item 2", + on_click=lambda e: print(f"{e.control.content}"), + ), + ft.PopupMenuItem( + content="Item 3", + on_click=lambda e: print(f"{e.control.content}"), + ), + ], + content=ft.Button("Click to open menu", on_click=open_menu), + ) + + page.add( + ft.SafeArea( + content=menu, + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/context_menu/programmatic_open/pyproject.toml b/sdk/python/examples/controls/material/context_menu/programmatic_open/pyproject.toml new file mode 100644 index 0000000000..d879bdad71 --- /dev/null +++ b/sdk/python/examples/controls/material/context_menu/programmatic_open/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "context-menu-programmatic-open" +version = "1.0.0" +description = "Programmatically opens ContextMenu from a button and handles selected menu actions." +requires-python = ">=3.10" +keywords = ["context menu", "programmatic open", "popup menu", "selection"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/ContextMenu"] + +[tool.flet.metadata] +title = "Programmatic open" +controls = ["SafeArea", "ContextMenu", "PopupMenuItem", "Button", "SnackBar"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["programmatic menu opening", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/context_menu/triggers/main.py b/sdk/python/examples/controls/material/context_menu/triggers/main.py new file mode 100644 index 0000000000..f7e356c262 --- /dev/null +++ b/sdk/python/examples/controls/material/context_menu/triggers/main.py @@ -0,0 +1,49 @@ +import flet as ft + + +async def main(page: ft.Page): + # on web, disable default browser context menu + if page.web: + await page.browser_context_menu.disable() + + def handle_item_click(e: ft.Event[ft.PopupMenuItem]): + action = e.control.content + page.show_dialog(ft.SnackBar(content=f"Item '{action}' selected.")) + + page.add( + ft.SafeArea( + expand=True, + content=ft.ContextMenu( + primary_items=[ + ft.PopupMenuItem(content="Primary 1", on_click=handle_item_click), + ft.PopupMenuItem(content="Primary 2", on_click=handle_item_click), + ], + primary_trigger=ft.ContextMenuTrigger.DOWN, + secondary_items=[ + ft.PopupMenuItem(content="Secondary 1", on_click=handle_item_click), + ft.PopupMenuItem(content="Secondary 2", on_click=handle_item_click), + ], + secondary_trigger=ft.ContextMenuTrigger.DOWN, + tertiary_items=[ + ft.PopupMenuItem(content="Tertiary 1", on_click=handle_item_click), + ft.PopupMenuItem(content="Tertiary 2", on_click=handle_item_click), + ], + tertiary_trigger=ft.ContextMenuTrigger.DOWN, + on_select=lambda e: print(f"Selected item: {e.item.content}"), + on_dismiss=lambda e: print("Menu dismissed"), + expand=True, + content=ft.Container( + key="context_menu_trigger_area", + expand=True, + bgcolor=ft.Colors.BLUE, + alignment=ft.Alignment.CENTER, + border_radius=ft.BorderRadius.all(12), + content=ft.Text("Left/middle/right click to open a context menu."), + ), + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/context_menu/triggers/pyproject.toml b/sdk/python/examples/controls/material/context_menu/triggers/pyproject.toml new file mode 100644 index 0000000000..1a54126e82 --- /dev/null +++ b/sdk/python/examples/controls/material/context_menu/triggers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "context-menu-triggers" +version = "1.0.0" +description = "ContextMenu trigger demo with separate primary, secondary, and tertiary click actions." +requires-python = ">=3.10" +keywords = ["context menu", "triggers", "popup menu", "mouse buttons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/ContextMenu"] + +[tool.flet.metadata] +title = "Triggers" +controls = ["SafeArea", "ContextMenu", "PopupMenuItem", "Container", "Text", "SnackBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["multi-trigger menus", "item selection callback", "dismiss callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/data_table/adaptive_row_heights/main.py b/sdk/python/examples/controls/material/data_table/adaptive_row_heights/main.py new file mode 100644 index 0000000000..b274ac4738 --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/adaptive_row_heights/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.DataTable( + width=560, + data_row_min_height=48, + data_row_max_height=float("inf"), + columns=[ + ft.DataColumn(label="Description"), + ft.DataColumn(label="Notes"), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell("TWO lines visible without overflow"), + ft.DataCell("Line 1\nLine 2"), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell("FOUR lines visible without overflow"), + ft.DataCell("Line 1\nLine 2\nLine 3\nLine 4"), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell("FIVE lines visible without overflow"), + ft.DataCell("Line 1\nLine 2\nLine 3\nLine 4\nLine 5"), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/data_table/adaptive_row_heights/pyproject.toml b/sdk/python/examples/controls/material/data_table/adaptive_row_heights/pyproject.toml new file mode 100644 index 0000000000..819ec0f036 --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/adaptive_row_heights/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-adaptive-row-heights" +version = "1.0.0" +description = "Demonstrates adaptive DataTable row heights for multi-line cell content using infinite max row height." +requires-python = ">=3.10" +keywords = ["data table", "adaptive row height", "multiline", "cells"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Adaptive row heights" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell"] +layout_pattern = "table-view" +complexity = "basic" +features = ["adaptive row height", "multiline cell content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/data_table/basic/main.py b/sdk/python/examples/controls/material/data_table/basic/main.py new file mode 100644 index 0000000000..1aa53bbe3b --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/basic/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.DataTable( + expand=True, + columns=[ + ft.DataColumn(label=ft.Text("First name")), + ft.DataColumn(label=ft.Text("Last name")), + ft.DataColumn(label=ft.Text("Age"), numeric=True), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("John")), + ft.DataCell(ft.Text("Smith")), + ft.DataCell(ft.Text("43")), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Jack")), + ft.DataCell(ft.Text("Brown")), + ft.DataCell(ft.Text("19")), + ], + ), + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Alice")), + ft.DataCell(ft.Text("Wong")), + ft.DataCell(ft.Text("25")), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/data_table/basic/pyproject.toml b/sdk/python/examples/controls/material/data_table/basic/pyproject.toml new file mode 100644 index 0000000000..0943448c32 --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-basic" +version = "1.0.0" +description = "Shows a basic DataTable with text columns and numeric age values." +requires-python = ">=3.10" +keywords = ["data table", "rows", "columns", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["tabular data", "numeric column"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/data_table/handling_events/main.py b/sdk/python/examples/controls/material/data_table/handling_events/main.py new file mode 100644 index 0000000000..834ae328cb --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/handling_events/main.py @@ -0,0 +1,81 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_row_selection_change(e: ft.Event[ft.DataRow]) -> None: + if e.control.data == 1: + row1.selected = not row1.selected + elif e.control.data == 2: + row2.selected = not row2.selected + elif e.control.data == 3: + row3.selected = not row3.selected + + table.update() + + def handle_column_sort(e: ft.DataColumnSortEvent) -> None: + if e.control.data in [1, 2]: + print(f"{e.column_index}, {e.ascending}") + table.sort_ascending = e.ascending + table.update() + + table = ft.DataTable( + width=700, + bgcolor=ft.Colors.TEAL_ACCENT_200, + border=ft.Border.all(2, ft.Colors.RED_ACCENT_200), + border_radius=10, + vertical_lines=ft.border.BorderSide(3, ft.Colors.BLUE_600), + horizontal_lines=ft.border.BorderSide(1, ft.Colors.GREEN_600), + sort_column_index=0, + sort_ascending=True, + heading_row_color=ft.Colors.BLACK_12, + heading_row_height=100, + data_row_color={ft.ControlState.HOVERED: "0x30FF0000"}, + show_checkbox_column=True, + divider_thickness=0, + column_spacing=200, + columns=[ + ft.DataColumn( + label=ft.Text("Column 1"), + tooltip="This is the first column", + data=1, + on_sort=handle_column_sort, + ), + ft.DataColumn( + label=ft.Text("Column 2"), + tooltip="This is a second column", + numeric=True, + data=2, + on_sort=handle_column_sort, + ), + ], + rows=[ + row1 := ft.DataRow( + cells=[ft.DataCell(ft.Text("A")), ft.DataCell(ft.Text("1"))], + selected=True, + on_select_change=handle_row_selection_change, + data=1, + ), + row2 := ft.DataRow( + cells=[ft.DataCell(ft.Text("B")), ft.DataCell(ft.Text("2"))], + selected=False, + on_select_change=handle_row_selection_change, + data=2, + ), + row3 := ft.DataRow( + cells=[ft.DataCell(ft.Text("C")), ft.DataCell(ft.Text("3"))], + selected=False, + on_select_change=handle_row_selection_change, + data=3, + ), + ], + ) + + page.add( + ft.SafeArea( + content=table, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/data_table/handling_events/pyproject.toml b/sdk/python/examples/controls/material/data_table/handling_events/pyproject.toml new file mode 100644 index 0000000000..7b0ba7433e --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-handling-events" +version = "1.0.0" +description = "Handles DataTable row selection and column sort events with visual table state updates." +requires-python = ">=3.10" +keywords = ["data table", "events", "row selection", "sorting"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["row selection callback", "column sort callback", "table state updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py b/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py new file mode 100644 index 0000000000..ba277b0ff2 --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/sortable_and_selectable/main.py @@ -0,0 +1,116 @@ +import flet as ft + + +def main(page: ft.Page): + inventory_items = [ + {"id": 1, "name": "Alpha", "qty": 4}, + {"id": 2, "name": "Bravo", "qty": 9}, + {"id": 3, "name": "Charlie", "qty": 2}, + {"id": 4, "name": "Delta", "qty": 6}, + {"id": 5, "name": "Echo", "qty": 3}, + {"id": 6, "name": "Foxtrot", "qty": 8}, + {"id": 7, "name": "Golf", "qty": 1}, + {"id": 8, "name": "Hotel", "qty": 7}, + {"id": 9, "name": "India", "qty": 5}, + {"id": 10, "name": "Juliet", "qty": 10}, + ] + displayed_items = list(inventory_items) + selected_item_ids: set[int] = {1, 3, 5} + + sort_key_for_column = { + 0: lambda item: str(item["name"]).lower(), + 1: lambda item: int(item["qty"]), + } + + def build_rows(items: list[dict[str, int | str]]) -> list[ft.DataRow]: + return [ + ft.DataRow( + selected=item["id"] in selected_item_ids, + on_select_change=handle_row_selection_change, + data=item["id"], + cells=[ + ft.DataCell(ft.Text(item["name"])), + ft.DataCell(ft.Text(str(item["qty"]))), + ], + ) + for item in items + ] + + def refresh_table_rows() -> None: + table.rows = build_rows(displayed_items) + table.update() + + def handle_row_selection_change(e: ft.Event[ft.DataRow]) -> None: + row = e.control + item_id = row.data + is_selected = e.data + + if is_selected: + selected_item_ids.add(item_id) + else: + selected_item_ids.discard(item_id) + + row.selected = is_selected + row.update() + + def handle_select_all(e: ft.Event[ft.DataTable]) -> None: + if e.data: + selected_item_ids.update(int(item["id"]) for item in displayed_items) + else: + selected_item_ids.clear() + + refresh_table_rows() + + def handle_column_sort(e: ft.DataColumnSortEvent) -> None: + displayed_items.sort( + key=sort_key_for_column[e.column_index], + reverse=not e.ascending, + ) + + table.sort_column_index = e.column_index + table.sort_ascending = e.ascending + refresh_table_rows() + + table = ft.DataTable( + width=700, + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=10, + vertical_lines=ft.border.BorderSide(1, ft.Colors.OUTLINE_VARIANT), + horizontal_lines=ft.border.BorderSide(1, ft.Colors.OUTLINE_VARIANT), + sort_column_index=0, + sort_ascending=True, + heading_row_color=ft.Colors.SURFACE_CONTAINER_HIGHEST, + heading_row_height=100, + data_row_color={ + ft.ControlState.HOVERED: ft.Colors.with_opacity(0.08, ft.Colors.PRIMARY), + ft.ControlState.SELECTED: ft.Colors.with_opacity(0.14, ft.Colors.PRIMARY), + }, + show_checkbox_column=True, + on_select_all=handle_select_all, + divider_thickness=1, + column_spacing=200, + columns=[ + ft.DataColumn( + label=ft.Text("Item"), + on_sort=handle_column_sort, + ), + ft.DataColumn( + label=ft.Text("Quantity"), + tooltip="Numeric quantity", + numeric=True, + on_sort=handle_column_sort, + ), + ], + rows=build_rows(displayed_items), + ) + + page.add( + ft.SafeArea( + content=table, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/data_table/sortable_and_selectable/pyproject.toml b/sdk/python/examples/controls/material/data_table/sortable_and_selectable/pyproject.toml new file mode 100644 index 0000000000..5a6031e82c --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/sortable_and_selectable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-sortable-and-selectable" +version = "1.0.0" +description = "Implements sortable DataTable columns and selectable rows while preserving selection across sorts." +requires-python = ">=3.10" +keywords = ["data table", "sorting", "selection", "checkbox", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Sortable and selectable" +controls = ["SafeArea", "DataTable", "DataColumn", "DataRow", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "intermediate" +features = ["column sorting", "row selection", "select all", "stable selection across sorts"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/data_table/spacing/main.py b/sdk/python/examples/controls/material/data_table/spacing/main.py new file mode 100644 index 0000000000..38f4cec3cb --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/spacing/main.py @@ -0,0 +1,122 @@ +import flet as ft + + +def _cell(label: str, color: str = ft.Colors.SURFACE_CONTAINER_HIGHEST) -> ft.DataCell: + return ft.DataCell( + ft.Container( + width=90, + height=32, + alignment=ft.Alignment.CENTER, + bgcolor=color, + border=ft.Border.all(1, ft.Colors.BLACK_26), + content=ft.Text(label, size=12, weight=ft.FontWeight.W_600), + ) + ) + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.theme_mode = ft.ThemeMode.DARK + + def update_spacing() -> None: + table.horizontal_margin = horizontal_margin_slider.value + table.column_spacing = column_spacing_slider.value + table.update() + + def handle_spacing_change(_: ft.Event[ft.Slider]) -> None: + update_spacing() + + def set_preset(horizontal_margin: float, column_spacing: float) -> None: + horizontal_margin_slider.value = horizontal_margin + column_spacing_slider.value = column_spacing + horizontal_margin_slider.update() + column_spacing_slider.update() + update_spacing() + + horizontal_margin_slider = ft.Slider( + key="horizontal_margin_slider", + min=0, + max=40, + divisions=40, + value=16, + label="{value}", + on_change=handle_spacing_change, + ) + column_spacing_slider = ft.Slider( + key="column_spacing_slider", + min=0, + max=40, + divisions=40, + value=16, + label="{value}", + on_change=handle_spacing_change, + ) + + table = ft.DataTable( + border=ft.Border.all(1, ft.Colors.ON_SURFACE_VARIANT), + horizontal_margin=horizontal_margin_slider.value, + column_spacing=column_spacing_slider.value, + horizontal_lines=ft.BorderSide(1, ft.Colors.ON_SURFACE_VARIANT), + vertical_lines=ft.BorderSide(1, ft.Colors.ON_SURFACE_VARIANT), + heading_row_height=40, + data_row_min_height=40, + data_row_max_height=40, + columns=[ + ft.DataColumn(label="Col A"), + ft.DataColumn(label="Col B"), + ft.DataColumn(label="Col C"), + ], + rows=[ + ft.DataRow(cells=[_cell("A1"), _cell("B1"), _cell("C1")]), + ft.DataRow(cells=[_cell("A2"), _cell("B2"), _cell("C2")]), + ], + ) + + page.appbar = ft.AppBar(title="DataTable spacing") + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Container( + width=520, + padding=12, + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + border_radius=8, + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("horizontal_margin (outer edges)"), + horizontal_margin_slider, + ft.Text("column_spacing (between columns)"), + column_spacing_slider, + ft.Row( + wrap=True, + controls=[ + ft.FilledButton( + "Reset", + on_click=lambda _: set_preset(16, 16), + ), + ft.OutlinedButton( + "Compact preset", + on_click=lambda _: set_preset(0, 0), + ), + ft.OutlinedButton( + "Spacious preset", + on_click=lambda _: set_preset(24, 32), + ), + ], + ), + ], + ), + ), + table, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/data_table/spacing/pyproject.toml b/sdk/python/examples/controls/material/data_table/spacing/pyproject.toml new file mode 100644 index 0000000000..cb2d259a87 --- /dev/null +++ b/sdk/python/examples/controls/material/data_table/spacing/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "data-table-spacing" +version = "1.0.0" +description = "Adjusts DataTable horizontal margin and column spacing interactively with sliders and presets." +requires-python = ">=3.10" +keywords = ["data table", "spacing", "horizontal margin", "slider", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable"] + +[tool.flet.metadata] +title = "Spacing" +controls = ["SafeArea", "Column", "DataTable", "DataColumn", "DataRow", "DataCell", "Slider", "FilledButton", "OutlinedButton", "Container", "Text", "AppBar"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["interactive spacing controls", "preset spacing buttons", "live table layout updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/date_picker/basic/main.py b/sdk/python/examples/controls/material/date_picker/basic/main.py new file mode 100644 index 0000000000..96c77b1bbb --- /dev/null +++ b/sdk/python/examples/controls/material/date_picker/basic/main.py @@ -0,0 +1,47 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_change(e: ft.Event[ft.DatePicker]): + messages.controls.append( + ft.Text(f"Date changed: {e.control.value.strftime('%m/%d/%Y')}") + ) + + def handle_dismissal(_: ft.Event[ft.DialogControl]): + messages.controls.append(ft.Text("DatePicker dismissed")) + + today = datetime.datetime(year=2025, month=4, day=15) + + picker = ft.DatePicker( + first_date=datetime.datetime(year=today.year - 1, month=1, day=1), + last_date=datetime.datetime(year=today.year + 1, month=today.month, day=20), + current_date=today, + on_change=handle_change, + on_dismiss=handle_dismissal, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog(picker), + content="Pick date", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/date_picker/basic/pyproject.toml b/sdk/python/examples/controls/material/date_picker/basic/pyproject.toml new file mode 100644 index 0000000000..3a637a72e7 --- /dev/null +++ b/sdk/python/examples/controls/material/date_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-picker-basic" +version = "1.0.0" +description = "Opens DatePicker dialog and logs selected date and dismiss events in the page content." +requires-python = ">=3.10" +keywords = ["date picker", "dialog", "events", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DatePicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Button", "DatePicker", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "date change callback", "dismiss callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/date_picker/custom_locale/main.py b/sdk/python/examples/controls/material/date_picker/custom_locale/main.py new file mode 100644 index 0000000000..025ffc11b7 --- /dev/null +++ b/sdk/python/examples/controls/material/date_picker/custom_locale/main.py @@ -0,0 +1,30 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + current_date = datetime.datetime(year=2025, month=4, day=15) + + page.add( + ft.SafeArea( + content=ft.Button( + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog( + ft.DatePicker( + locale=ft.Locale("zh", "Hans"), + first_date=datetime.datetime(year=2024, month=1, day=1), + last_date=datetime.datetime(year=2026, month=12, day=31), + current_date=current_date, + ) + ), + content="Pick date (zh_Hans locale)", + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/date_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/material/date_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..e1eaefa81c --- /dev/null +++ b/sdk/python/examples/controls/material/date_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-picker-custom-locale" +version = "1.0.0" +description = "Opens DatePicker with zh_Hans locale to demonstrate localized calendar UI." +requires-python = ">=3.10" +keywords = ["date picker", "custom locale", "locale", "internationalization", "zh_Hans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DatePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "Button", "DatePicker", "Locale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["localized date picker", "dialog open action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/date_picker/media/basic.png b/sdk/python/examples/controls/material/date_picker/media/basic.png new file mode 100644 index 0000000000..392bf883cf Binary files /dev/null and b/sdk/python/examples/controls/material/date_picker/media/basic.png differ diff --git a/sdk/python/examples/controls/material/date_range_picker/basic/main.py b/sdk/python/examples/controls/material/date_range_picker/basic/main.py new file mode 100644 index 0000000000..2533b459b3 --- /dev/null +++ b/sdk/python/examples/controls/material/date_range_picker/basic/main.py @@ -0,0 +1,56 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + messages = ft.Column(tight=True) + + def handle_change(e: ft.Event[ft.DateRangePicker]): + messages.controls.extend( + [ + ft.Text( + f"Start Date changed: {e.control.start_value.strftime('%m/%d/%Y')}" + ), + ft.Text( + f"End Date changed: {e.control.end_value.strftime('%m/%d/%Y')}" + ), + ] + ) + + def handle_dismissal(_: ft.Event[ft.DialogControl]): + messages.controls.append(ft.Text("DateRangePicker dismissed")) + + today = datetime.datetime(year=2025, month=4, day=15) + + picker = ft.DateRangePicker( + start_value=datetime.datetime(year=today.year, month=today.month, day=1), + end_value=datetime.datetime(year=today.year, month=today.month, day=15), + first_date=datetime.datetime(year=2024, month=1, day=1), + last_date=datetime.datetime(year=2026, month=12, day=31), + current_date=today, + on_change=handle_change, + on_dismiss=handle_dismissal, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + icon=ft.Icons.DATE_RANGE, + on_click=lambda _: page.show_dialog(picker), + content="Pick date range", + ), + messages, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/date_range_picker/basic/pyproject.toml b/sdk/python/examples/controls/material/date_range_picker/basic/pyproject.toml new file mode 100644 index 0000000000..277af9af5f --- /dev/null +++ b/sdk/python/examples/controls/material/date_range_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-range-picker-basic" +version = "1.0.0" +description = "Opens DateRangePicker and displays start and end date values after selection." +requires-python = ">=3.10" +keywords = ["date range picker", "dialog", "events", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DateRangePicker"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Button", "DateRangePicker", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["open dialog", "range change callback", "dismiss callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/date_range_picker/custom_locale/main.py b/sdk/python/examples/controls/material/date_range_picker/custom_locale/main.py new file mode 100644 index 0000000000..1471143d1b --- /dev/null +++ b/sdk/python/examples/controls/material/date_range_picker/custom_locale/main.py @@ -0,0 +1,32 @@ +import datetime + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + current_date = datetime.datetime(year=2025, month=4, day=15) + + page.add( + ft.SafeArea( + content=ft.Button( + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog( + ft.DateRangePicker( + locale=ft.Locale("zh", "Hans"), + start_value=datetime.datetime(year=2025, month=4, day=10), + end_value=datetime.datetime(year=2025, month=4, day=20), + first_date=datetime.datetime(year=2024, month=1, day=1), + last_date=datetime.datetime(year=2026, month=12, day=31), + current_date=current_date, + ) + ), + content="Pick dates (zh_Hans locale)", + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/date_range_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/material/date_range_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..96095238e7 --- /dev/null +++ b/sdk/python/examples/controls/material/date_range_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "date-range-picker-custom-locale" +version = "1.0.0" +description = "Opens DateRangePicker with zh_Hans locale for localized date range selection." +requires-python = ">=3.10" +keywords = ["date range picker", "custom locale", "locale", "internationalization", "zh_Hans"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/DateRangePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "Button", "DateRangePicker", "Locale"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["localized date range picker", "dialog open action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/date_range_picker/media/basic.png b/sdk/python/examples/controls/material/date_range_picker/media/basic.png new file mode 100644 index 0000000000..392bf883cf Binary files /dev/null and b/sdk/python/examples/controls/material/date_range_picker/media/basic.png differ diff --git a/sdk/python/examples/controls/material/divider/basic/main.py b/sdk/python/examples/controls/material/divider/basic/main.py new file mode 100644 index 0000000000..8821065032 --- /dev/null +++ b/sdk/python/examples/controls/material/divider/basic/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + spacing=0, + expand=True, + controls=[ + ft.Container( + expand=True, + bgcolor=ft.Colors.AMBER, + alignment=ft.Alignment.CENTER, + ), + ft.Divider(), + ft.Container( + expand=True, + bgcolor=ft.Colors.PINK, + alignment=ft.Alignment.CENTER, + ), + ft.Divider(height=1, color=ft.Colors.WHITE), + ft.Container( + expand=True, + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + ), + ft.Divider(height=9, thickness=3), + ft.Container( + expand=True, + bgcolor=ft.Colors.DEEP_PURPLE_200, + alignment=ft.Alignment.CENTER, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/divider/basic/pyproject.toml b/sdk/python/examples/controls/material/divider/basic/pyproject.toml new file mode 100644 index 0000000000..91cdcc1a7d --- /dev/null +++ b/sdk/python/examples/controls/material/divider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "divider-basic" +version = "1.0.0" +description = "Demonstrates Divider height, thickness, and color between vertically stacked containers." +requires-python = ">=3.10" +keywords = ["divider", "layout", "spacing", "separator"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Divider"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Container", "Divider"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom divider thickness", "custom divider color", "section separation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/divider/media/basic.png b/sdk/python/examples/controls/material/divider/media/basic.png new file mode 100644 index 0000000000..c97e78cd69 Binary files /dev/null and b/sdk/python/examples/controls/material/divider/media/basic.png differ diff --git a/sdk/python/examples/controls/material/dropdown/color_selection_with_filtering/main.py b/sdk/python/examples/controls/material/dropdown/color_selection_with_filtering/main.py new file mode 100644 index 0000000000..2b068a4ad2 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/color_selection_with_filtering/main.py @@ -0,0 +1,40 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + def get_options() -> list[ft.DropdownOption]: + colors = [ + ft.Colors.RED, + ft.Colors.BLUE, + ft.Colors.YELLOW, + ft.Colors.PURPLE, + ft.Colors.LIME, + ] + return [ + ft.DropdownOption( + key=color.value, + content=ft.Text(value=color.value, color=color), + ) + for color in colors + ] + + def handle_dropdown_select(e: ft.Event[ft.Dropdown]): + e.control.color = e.control.value + + page.add( + ft.SafeArea( + content=ft.Dropdown( + key="color_dropdown", + editable=True, + label="Color", + options=get_options(), + on_select=handle_dropdown_select, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown/color_selection_with_filtering/pyproject.toml b/sdk/python/examples/controls/material/dropdown/color_selection_with_filtering/pyproject.toml new file mode 100644 index 0000000000..0d65fd09f6 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/color_selection_with_filtering/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-color-selection-with-filtering" +version = "1.0.0" +description = "Filters editable dropdown options by color and applies selected color to the control text." +requires-python = ">=3.10" +keywords = ["dropdown", "filter", "editable", "selection", "color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Color selection with filtering" +controls = ["SafeArea", "Dropdown", "DropdownOption", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["editable dropdown", "option filtering", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown/declarative/main.py b/sdk/python/examples/controls/material/dropdown/declarative/main.py new file mode 100644 index 0000000000..b0458ae32a --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/declarative/main.py @@ -0,0 +1,56 @@ +from dataclasses import dataclass +from typing import cast + +import flet as ft + + +@dataclass +@ft.observable +class Form: + color: str = "red" + + def change_color(self, new_color: str): + print("New color:", new_color) + self.color = new_color + + +@ft.component +def App(): + form, _ = ft.use_state(lambda: Form()) + + return ft.SafeArea( + content=ft.Column( + controls=cast( + list[ft.Control], + [ + ft.Text(f"Selected color: {form.color}"), + ft.Column( + controls=[ + ft.Dropdown( + key="declarative_dropdown", + editable=True, + label="Color", + value=form.color, + on_select=lambda e: form.change_color( + cast(str, e.control.value) + ), + options=[ + ft.DropdownOption(key="red", text="Red"), + ft.DropdownOption(key="green", text="Green"), + ft.DropdownOption(key="blue", text="Blue"), + ], + ), + ], + ), + ], + ), + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown/declarative/pyproject.toml b/sdk/python/examples/controls/material/dropdown/declarative/pyproject.toml new file mode 100644 index 0000000000..491b746bca --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-declarative" +version = "1.0.0" +description = "Uses a declarative component and observable state to keep Dropdown selection synchronized." +requires-python = ">=3.10" +keywords = ["dropdown", "declarative", "component", "state", "observable"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Declarative" +controls = ["SafeArea", "Column", "Dropdown", "DropdownOption", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["declarative state", "selection binding", "component rendering"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown/icon_selection/main.py b/sdk/python/examples/controls/material/dropdown/icon_selection/main.py new file mode 100644 index 0000000000..797320a766 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/icon_selection/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def get_options() -> list[ft.DropdownOption]: + icons = [ + {"name": "Smile", "icon": ft.Icons.SENTIMENT_SATISFIED_OUTLINED}, + {"name": "Cloud", "icon": ft.Icons.CLOUD_OUTLINED}, + {"name": "Brush", "icon": ft.Icons.BRUSH_OUTLINED}, + {"name": "Heart", "icon": ft.Icons.FAVORITE}, + ] + return [ + ft.DropdownOption(key=icon["name"], leading_icon=icon["icon"]) + for icon in icons + ] + + page.add( + ft.SafeArea( + content=ft.Dropdown( + key="icon_dropdown", + border=ft.InputBorder.UNDERLINE, + enable_filter=True, + editable=True, + leading_icon=ft.Icons.SEARCH, + label="Icon", + options=get_options(), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown/icon_selection/pyproject.toml b/sdk/python/examples/controls/material/dropdown/icon_selection/pyproject.toml new file mode 100644 index 0000000000..a956da14f8 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/icon_selection/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-icon-selection" +version = "1.0.0" +description = "Displays dropdown options with leading icons and interactive text filtering." +requires-python = ">=3.10" +keywords = ["dropdown", "icons", "filter", "editable", "search"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Icon selection" +controls = ["SafeArea", "Dropdown", "DropdownOption"] +layout_pattern = "form" +complexity = "basic" +features = ["leading icons", "editable dropdown", "option filtering"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown/media/color_selection_with_filtering.gif b/sdk/python/examples/controls/material/dropdown/media/color_selection_with_filtering.gif new file mode 100644 index 0000000000..b02f196890 Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown/media/color_selection_with_filtering.gif differ diff --git a/sdk/python/examples/controls/material/dropdown/media/icon_selection.png b/sdk/python/examples/controls/material/dropdown/media/icon_selection.png new file mode 100644 index 0000000000..55e01a0509 Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown/media/icon_selection.png differ diff --git a/sdk/python/examples/controls/material/dropdown/select_and_change_events/main.py b/sdk/python/examples/controls/material/dropdown/select_and_change_events/main.py new file mode 100644 index 0000000000..e818656797 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/select_and_change_events/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + colors = [ + ft.Colors.RED, + ft.Colors.BLUE, + ft.Colors.YELLOW, + ft.Colors.PURPLE, + ft.Colors.LIME, + ] + + def get_options() -> list[ft.DropdownOption]: + options: list[ft.DropdownOption] = [] + for color in colors: + options.append( + ft.DropdownOption( + key=color.value, + content=ft.Text(value=color.value, color=color), + leading_icon=ft.Icon(ft.Icons.PALETTE, color=color), + ) + ) + return options + + display_value = ft.Text() + display_text = ft.Text() + + def dropdown_select(e: ft.Event[ft.Dropdown]): + e.control.color = e.control.value + display_value.value = f"VALUE changed to {e.control.value}" + + def dropdown_text_change(e: ft.Event[ft.Dropdown]): + display_text.value = f"TEXT changed to {e.control.text}" + + page.scroll = ft.ScrollMode.AUTO + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + display_value, + display_text, + ft.Dropdown( + key="select_change_dropdown", + editable=True, + label="Color", + width=float("inf"), + options=get_options(), + on_select=dropdown_select, + on_text_change=dropdown_text_change, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown/select_and_change_events/pyproject.toml b/sdk/python/examples/controls/material/dropdown/select_and_change_events/pyproject.toml new file mode 100644 index 0000000000..ecbb6b06ec --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/select_and_change_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-select-and-change-events" +version = "1.0.0" +description = "Handles dropdown select and text-change events while showing selected value and typed text." +requires-python = ">=3.10" +keywords = ["dropdown", "events", "on_select", "on_text_change", "editable"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Select and change events" +controls = ["SafeArea", "Column", "Dropdown", "DropdownOption", "Icon", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["select callback", "text change callback", "live value labels"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown/styled/main.py b/sdk/python/examples/controls/material/dropdown/styled/main.py new file mode 100644 index 0000000000..7c8014e49c --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/styled/main.py @@ -0,0 +1,133 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Dropdown( + key="styled_dropdown_1", + text_size=20, + content_padding=10, + color=ft.Colors.PURPLE_200, + bgcolor=ft.Colors.BLUE_200, + filled=True, + border_radius=30, + border_color=ft.Colors.GREEN_800, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + focused_border_width=5, + options=[ + ft.DropdownOption("a", "Style 1A"), + ft.DropdownOption("b", "Style 1B"), + ft.DropdownOption("c", "Style 1C"), + ], + ), + ft.Dropdown( + key="styled_dropdown_2", + border_radius=30, + filled=True, + fill_color=ft.Colors.RED_400, + border_color=ft.Colors.TRANSPARENT, + bgcolor=ft.Colors.RED_200, + color=ft.Colors.CYAN_400, + focused_border_color=ft.Colors.PINK_300, + focused_border_width=20, + options=[ + ft.DropdownOption("a", "Style 2A"), + ft.DropdownOption("b", "Style 2B"), + ft.DropdownOption("c", "Style 2C"), + ], + ), + ft.Dropdown( + key="styled_dropdown_3", + border_color=ft.Colors.PINK_ACCENT, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + focused_border_width=25, + border_radius=30, + width=150, + border_width=5, + options=[ + ft.DropdownOption("a", "Style 3A"), + ft.DropdownOption("b", "Style 3B"), + ft.DropdownOption("c", "Style 3C"), + ], + ), + ft.Container( + padding=ft.Padding.only(bottom=20), + content=ft.Dropdown( + key="styled_dropdown_4", + text_size=30, + color=ft.Colors.ORANGE_ACCENT, + border_radius=20, + filled=True, + border_width=0, + autofocus=True, + focused_border_color=ft.Colors.GREEN_100, + focused_border_width=10, + width=200, + height=50, + options=[ + ft.dropdown.Option("a", "Style 4A"), + ft.dropdown.Option("b", "Style 4B"), + ft.dropdown.Option("c", "Style 4C"), + ], + ), + ), + ft.Dropdown( + key="styled_dropdown_5", + text_size=30, + border_radius=20, + filled=True, + border_width=0, + focused_border_color=ft.Colors.GREEN_100, + focused_border_width=10, + content_padding=20, + width=200, + options=[ + ft.DropdownOption( + key="a", + text="Style 5A", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=15), + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + ), + ), + ft.DropdownOption( + key="b", + text="Style 5B", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=15), + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + ), + ), + ft.DropdownOption( + key="c", + text="Style 5C", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=15), + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown/styled/pyproject.toml b/sdk/python/examples/controls/material/dropdown/styled/pyproject.toml new file mode 100644 index 0000000000..dce56d324e --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-styled" +version = "1.0.0" +description = "Showcases multiple Dropdown visual styles including borders, fills, and per-option button styles." +requires-python = ">=3.10" +keywords = ["dropdown", "styling", "theming", "options", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Dropdown"] + +[tool.flet.metadata] +title = "Styled" +controls = ["SafeArea", "Column", "Container", "Dropdown", "DropdownOption", "ButtonStyle"] +layout_pattern = "form" +complexity = "basic" +features = ["custom borders", "filled styles", "option style customization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown_m2/add_and_delete_options/main.py b/sdk/python/examples/controls/material/dropdown_m2/add_and_delete_options/main.py new file mode 100644 index 0000000000..552f45e500 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/add_and_delete_options/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + dropdown = ft.DropdownM2(options=[], color=ft.Colors.BLUE_400) + input_field = ft.TextField(hint_text="Enter item name") + + def find_option(option_name: str): + for option in dropdown.options: + if option_name == option.key: + return option + return None + + def handle_addition(_: ft.Event[ft.Button]): + dropdown.options.append(ft.dropdownm2.Option(input_field.value)) + dropdown.value = input_field.value + input_field.value = "" + dropdown.update() + input_field.update() + + def handle_deletion(_: ft.Event[ft.OutlinedButton]): + option = find_option(dropdown.value) + if option is not None: + dropdown.options.remove(option) + dropdown.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + dropdown, + ft.Row( + controls=[ + input_field, + ft.Button(content="Add", on_click=handle_addition), + ft.OutlinedButton( + content="Delete selected", + on_click=handle_deletion, + style=ft.ButtonStyle(bgcolor=ft.Colors.RED), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown_m2/add_and_delete_options/pyproject.toml b/sdk/python/examples/controls/material/dropdown_m2/add_and_delete_options/pyproject.toml new file mode 100644 index 0000000000..25f4c60fda --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/add_and_delete_options/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-add-and-delete-options" +version = "1.0.0" +description = "Adds and removes DropdownM2 options dynamically based on text input and current selection." +requires-python = ">=3.10" +keywords = ["dropdownm2", "dynamic options", "add option", "delete option", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Add and delete options" +controls = ["SafeArea", "Column", "Row", "DropdownM2", "TextField", "Button", "OutlinedButton"] +layout_pattern = "form" +complexity = "basic" +features = ["dynamic option insertion", "delete selected option"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown_m2/basic/main.py b/sdk/python/examples/controls/material/dropdown_m2/basic/main.py new file mode 100644 index 0000000000..4c305510e3 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/basic/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + dd = ft.DropdownM2( + width=100, + value="Green", + options=[ + ft.dropdownm2.Option("Red"), + ft.dropdownm2.Option("Green"), + ft.dropdownm2.Option("Blue"), + ], + ) + + def handle_button_click(_: ft.Event[ft.Button]): + message.value = f"Dropdown value is: {dd.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + dd, + ft.Button(content="Submit", on_click=handle_button_click), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown_m2/basic/pyproject.toml b/sdk/python/examples/controls/material/dropdown_m2/basic/pyproject.toml new file mode 100644 index 0000000000..616704dcd2 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-basic" +version = "1.0.0" +description = "Submits selected DropdownM2 value and displays it in a message label." +requires-python = ">=3.10" +keywords = ["dropdownm2", "selection", "submit", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "DropdownM2", "Button", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["value selection", "submit callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown_m2/dropdown_random_icon/main.py b/sdk/python/examples/controls/material/dropdown_m2/dropdown_random_icon/main.py new file mode 100644 index 0000000000..672eae65a9 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/dropdown_random_icon/main.py @@ -0,0 +1,44 @@ +import random + +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + dd = ft.DropdownM2(options=[], options_fill_horizontally=True) + + def handle_dropdown_change(e: ft.Event[ft.DropdownM2]): + message.value = f"{e.control.value} chosen" + + def handle_new_random_item(_: ft.Event[ft.Button]): + icon = ft.Icon(ft.Icons.random()) + dd.options.append( + ft.dropdownm2.Option( + text=f"{str(icon.icon)[6:]}", + content=icon, + ) + ) + dd.update() + + def handle_items_shuffle(_: ft.Event[ft.Button]): + random.shuffle(dd.options) + dd.update() + + dd.on_change = handle_dropdown_change + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + dd, + ft.Button("Add random Option", on_click=handle_new_random_item), + ft.Button("Shuffle Options", on_click=handle_items_shuffle), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown_m2/dropdown_random_icon/pyproject.toml b/sdk/python/examples/controls/material/dropdown_m2/dropdown_random_icon/pyproject.toml new file mode 100644 index 0000000000..deb83af937 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/dropdown_random_icon/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-dropdown-random-icon" +version = "1.0.0" +description = "Adds random icon options to DropdownM2 and supports shuffling option order interactively." +requires-python = ">=3.10" +keywords = ["dropdownm2", "icons", "dynamic options", "shuffle", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Dropdown random icon" +controls = ["SafeArea", "Column", "DropdownM2", "Button", "Icon", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["random option generation", "option shuffling", "selection callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown_m2/handling_events/main.py b/sdk/python/examples/controls/material/dropdown_m2/handling_events/main.py new file mode 100644 index 0000000000..411705aa8a --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/handling_events/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + message = ft.Text() + + def dropdown_changed(e: ft.Event[ft.DropdownM2]): + message.value = f"Dropdown changed to {e.control.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.DropdownM2( + width=200, + color=ft.Colors.BLUE_GREY_700, + on_change=dropdown_changed, + options=[ + ft.dropdownm2.Option("Red"), + ft.dropdownm2.Option("Green"), + ft.dropdownm2.Option("Blue"), + ], + ), + message, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown_m2/handling_events/pyproject.toml b/sdk/python/examples/controls/material/dropdown_m2/handling_events/pyproject.toml new file mode 100644 index 0000000000..7cb513559f --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-handling-events" +version = "1.0.0" +description = "Updates helper text when DropdownM2 selection changes via on_change event." +requires-python = ">=3.10" +keywords = ["dropdownm2", "events", "on_change", "selection", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "Column", "DropdownM2", "Text"] +layout_pattern = "form" +complexity = "basic" +features = ["on_change callback", "live message update"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown_m2/label_and_hint/main.py b/sdk/python/examples/controls/material/dropdown_m2/label_and_hint/main.py new file mode 100644 index 0000000000..16f5a73680 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/label_and_hint/main.py @@ -0,0 +1,23 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.DropdownM2( + label="Color", + hint_text="Choose your favourite color?", + autofocus=True, + color=ft.Colors.BLACK, + options=[ + ft.dropdownm2.Option("Red"), + ft.dropdownm2.Option("Green"), + ft.dropdownm2.Option("Blue"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/dropdown_m2/label_and_hint/pyproject.toml b/sdk/python/examples/controls/material/dropdown_m2/label_and_hint/pyproject.toml new file mode 100644 index 0000000000..41dca107a4 --- /dev/null +++ b/sdk/python/examples/controls/material/dropdown_m2/label_and_hint/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "dropdown-m2-label-and-hint" +version = "1.0.0" +description = "Shows DropdownM2 with label, hint text, and autofocus configuration." +requires-python = ">=3.10" +keywords = ["dropdownm2", "label", "hint", "autofocus", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/DropdownM2"] + +[tool.flet.metadata] +title = "Dropdown with label and hint" +controls = ["SafeArea", "DropdownM2"] +layout_pattern = "form" +complexity = "basic" +features = ["label text", "hint text", "autofocus"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/dropdown_m2/media/add_and_delete_options.gif b/sdk/python/examples/controls/material/dropdown_m2/media/add_and_delete_options.gif new file mode 100644 index 0000000000..68bd10253d Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown_m2/media/add_and_delete_options.gif differ diff --git a/sdk/python/examples/controls/material/dropdown_m2/media/basic.gif b/sdk/python/examples/controls/material/dropdown_m2/media/basic.gif new file mode 100644 index 0000000000..1202c3ff78 Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown_m2/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/dropdown_m2/media/handling_events.gif b/sdk/python/examples/controls/material/dropdown_m2/media/handling_events.gif new file mode 100644 index 0000000000..15c3523f7a Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown_m2/media/handling_events.gif differ diff --git a/sdk/python/examples/controls/material/dropdown_m2/media/label_and_hint.gif b/sdk/python/examples/controls/material/dropdown_m2/media/label_and_hint.gif new file mode 100644 index 0000000000..425ddd0033 Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown_m2/media/label_and_hint.gif differ diff --git a/sdk/python/examples/controls/material/dropdown_m2/media/search.gif b/sdk/python/examples/controls/material/dropdown_m2/media/search.gif new file mode 100644 index 0000000000..f8c162fdfd Binary files /dev/null and b/sdk/python/examples/controls/material/dropdown_m2/media/search.gif differ diff --git a/sdk/python/examples/controls/material/expansion_panel_list/basic/main.py b/sdk/python/examples/controls/material/expansion_panel_list/basic/main.py new file mode 100644 index 0000000000..70c6420a6d --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_panel_list/basic/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_change(e: ft.Event[ft.ExpansionPanelList]): + print(f"change on panel with index {e.data}") + + def handle_delete(e: ft.Event[ft.IconButton]): + icon_button = e.control + tile = icon_button.parent + panel = tile.parent + + panel_list.controls.remove(panel) + panel_list.update() + + panel_list = ft.ExpansionPanelList( + expand_icon_color=ft.Colors.AMBER, + elevation=8, + divider_color=ft.Colors.AMBER, + on_change=handle_change, + controls=[ + ft.ExpansionPanel( + bgcolor=ft.Colors.BLUE_400, + expanded=True, + ), + ], + ) + + colors = [ + ft.Colors.GREEN_500, + ft.Colors.BLUE_800, + ft.Colors.RED_800, + ] + + for i, bgcolor in enumerate(colors): + panel_list.controls.append( + ft.ExpansionPanel( + bgcolor=bgcolor, + header=ft.ListTile(title=ft.Text(f"Panel {i}"), bgcolor=bgcolor), + content=ft.ListTile( + bgcolor=bgcolor, + title=ft.Text(f"This is in Panel {i}"), + subtitle=ft.Text(f"Press the icon to delete panel {i}"), + trailing=ft.IconButton( + icon=ft.Icons.DELETE, + on_click=handle_delete, + ), + ), + ) + ) + + page.add( + ft.SafeArea( + content=panel_list, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_panel_list/basic/pyproject.toml b/sdk/python/examples/controls/material/expansion_panel_list/basic/pyproject.toml new file mode 100644 index 0000000000..6210493fde --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_panel_list/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-panel-list-basic" +version = "1.0.0" +description = "Builds an ExpansionPanelList with dynamic panel deletion and panel-change callbacks." +requires-python = ">=3.10" +keywords = ["expansion panel list", "panels", "delete", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionPanelList"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "ExpansionPanelList", "ExpansionPanel", "ListTile", "IconButton", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["panel expand/collapse", "dynamic panel removal", "panel change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/expansion_panel_list/media/basic.gif b/sdk/python/examples/controls/material/expansion_panel_list/media/basic.gif new file mode 100644 index 0000000000..dbdfa0c29a Binary files /dev/null and b/sdk/python/examples/controls/material/expansion_panel_list/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/expansion_panel_list/scrollable/main.py b/sdk/python/examples/controls/material/expansion_panel_list/scrollable/main.py new file mode 100644 index 0000000000..f652646aa5 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_panel_list/scrollable/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.ExpansionPanelList( + expand=True, + scroll=ft.ScrollMode.ALWAYS, + spacing=8, + controls=[ + ft.ExpansionPanel( + can_tap_header=True, + header=ft.ListTile(title=ft.Text(f"Panel {i}")), + content=ft.ListTile( + title=ft.Text(f"Details for panel {i}"), + subtitle=ft.Text( + "This content can be expanded or collapsed." + ), + ), + ) + for i in range(1, 41) + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_panel_list/scrollable/pyproject.toml b/sdk/python/examples/controls/material/expansion_panel_list/scrollable/pyproject.toml new file mode 100644 index 0000000000..0545271517 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_panel_list/scrollable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-panel-list-scrollable" +version = "1.0.0" +description = "Builds an ExpansionPanelList with scrollable panels." +requires-python = ">=3.10" +keywords = ["expansion panel list", "panels", "scrollable", "events"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionPanelList"] + +[tool.flet.metadata] +title = "Scrollable" +controls = ["SafeArea", "ExpansionPanelList", "ExpansionPanel", "ListTile", "IconButton", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["panel expand/collapse", "scrollable panels", "panel change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/expansion_tile/basic/main.py b/sdk/python/examples/controls/material/expansion_tile/basic/main.py new file mode 100644 index 0000000000..35c995f70a --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/basic/main.py @@ -0,0 +1,79 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.spacing = 0 + page.padding = 0 + + def handle_tile_change(e: ft.Event[ft.ExpansionTile]): + page.show_dialog( + ft.SnackBar( + duration=1000, + content=ft.Text( + value=( + f"ExpansionTile was " + f"{'expanded' if e.data == 'true' else 'collapsed'}" + ) + ), + ) + ) + if e.control.trailing: + e.control.trailing.icon = ( + ft.Icons.ARROW_DROP_DOWN + if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE + else ft.Icons.ARROW_DROP_DOWN_CIRCLE + ) + e.control.trailing.update() + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=0, + controls=[ + ft.ExpansionTile( + expanded=True, + title=ft.Text("ExpansionTile 1"), + subtitle=ft.Text("Trailing expansion arrow icon"), + affinity=ft.TileAffinity.PLATFORM, + maintain_state=True, + collapsed_text_color=ft.Colors.RED, + text_color=ft.Colors.RED, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 1.1")), + ft.ListTile(title=ft.Text("This is sub-tile number 1.2")), + ], + ), + ft.ExpansionTile( + expanded=True, + title=ft.Text("ExpansionTile 2"), + subtitle=ft.Text("Custom expansion arrow icon"), + trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN), + collapsed_text_color=ft.Colors.GREEN, + text_color=ft.Colors.GREEN, + on_change=handle_tile_change, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 2.1")), + ft.ListTile(title=ft.Text("This is sub-tile number 2.2")), + ], + ), + ft.ExpansionTile( + expanded=True, + title=ft.Text("ExpansionTile 3"), + subtitle=ft.Text("Leading expansion arrow icon"), + affinity=ft.TileAffinity.LEADING, + collapsed_text_color=ft.Colors.BLUE_800, + text_color=ft.Colors.BLUE_200, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 3.1")), + ft.ListTile(title=ft.Text("This is sub-tile number 3.2")), + ], + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_tile/basic/pyproject.toml b/sdk/python/examples/controls/material/expansion_tile/basic/pyproject.toml new file mode 100644 index 0000000000..215a1a74fe --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-basic" +version = "1.0.0" +description = "Shows ExpansionTile variants with trailing and leading arrows, snack feedback, and nested list tiles." +requires-python = ">=3.10" +keywords = ["expansion tile", "layout", "events", "list tiles"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "ExpansionTile", "ListTile", "Text", "Icon", "SnackBar"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["tile expand/collapse", "change callback", "custom arrow affinity"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/expansion_tile/borders/main.py b/sdk/python/examples/controls/material/expansion_tile/borders/main.py new file mode 100644 index 0000000000..6182183949 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/borders/main.py @@ -0,0 +1,45 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.ExpansionTile( + title=ft.Text( + value="Expansion Tile with changing borders", + text_align=ft.TextAlign.CENTER, + ), + subtitle=ft.Text( + value="Tile border changes when expanded", + text_align=ft.TextAlign.CENTER, + ), + bgcolor=ft.Colors.BLUE_GREY_200, + controls_padding=ft.Padding.symmetric(horizontal=10), + collapsed_bgcolor=ft.Colors.BLUE_GREY_200, + affinity=ft.TileAffinity.PLATFORM, + maintain_state=True, + shape=ft.RoundedRectangleBorder(radius=20), + collapsed_shape=ft.StadiumBorder(side=ft.BorderSide(width=2)), + collapsed_text_color=ft.Colors.GREY_800, + text_color=ft.Colors.GREY_800, + controls=[ + ft.ListTile( + title=ft.Text("A sub-tile"), + bgcolor=ft.Colors.BLUE_GREY_200, + shape=ft.RoundedRectangleBorder(radius=20), + ), + ft.ListTile( + title=ft.Text("Another sub-tile"), + bgcolor=ft.Colors.BLUE_GREY_200, + shape=ft.RoundedRectangleBorder(radius=20), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_tile/borders/pyproject.toml b/sdk/python/examples/controls/material/expansion_tile/borders/pyproject.toml new file mode 100644 index 0000000000..a8a5d91721 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/borders/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-borders" +version = "1.0.0" +description = "Demonstrates ExpansionTile border and shape changes between collapsed and expanded states." +requires-python = ">=3.10" +keywords = ["expansion tile", "borders", "shape", "collapsed state", "expanded state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Borders" +controls = ["SafeArea", "ExpansionTile", "ListTile", "RoundedRectangleBorder", "StadiumBorder", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["collapsed vs expanded shapes", "custom borders", "tile background styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/expansion_tile/custom_animations/main.py b/sdk/python/examples/controls/material/expansion_tile/custom_animations/main.py new file mode 100644 index 0000000000..3fd04b24bc --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/custom_animations/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.spacing = 20 + + tile = ft.ExpansionTile( + expanded=True, + title=ft.Text("Expand/Collapse me while being attentive to the animations!"), + controls=[ + ft.ListTile(title=ft.Text("Sub-item 1")), + ft.ListTile(title=ft.Text("Sub-item 2")), + ft.ListTile(title=ft.Text("Sub-item 3")), + ], + ) + + def switch_animation(e: ft.Event[ft.CupertinoSlidingSegmentedButton]): + if e.control.selected_index == 0: + tile.animation_style = None + elif e.control.selected_index == 1: + tile.animation_style = ft.AnimationStyle( + curve=ft.AnimationCurve.BOUNCE_OUT, + duration=ft.Duration(seconds=5), + ) + else: + tile.animation_style = ft.AnimationStyle.no_animation() + tile.update() + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.CupertinoSlidingSegmentedButton( + selected_index=0, + thumb_color=ft.Colors.BLUE_400, + on_change=switch_animation, + controls=[ + ft.Text("Default animation"), + ft.Text("Custom animation"), + ft.Text("No animation"), + ], + ), + tile, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_tile/custom_animations/pyproject.toml b/sdk/python/examples/controls/material/expansion_tile/custom_animations/pyproject.toml new file mode 100644 index 0000000000..8b17b4a2e2 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/custom_animations/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-custom-animations" +version = "1.0.0" +description = "Switches ExpansionTile animation behavior between default, custom curve, and no animation." +requires-python = ">=3.10" +keywords = ["expansion tile", "animation", "cupertino sliding segmented button", "curve"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Custom animations" +controls = ["SafeArea", "Column", "ExpansionTile", "ListTile", "CupertinoSlidingSegmentedButton", "AnimationStyle", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["animation style switching", "custom animation curve", "disable animations"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/expansion_tile/programmatic_expansion/main.py b/sdk/python/examples/controls/material/expansion_tile/programmatic_expansion/main.py new file mode 100644 index 0000000000..6ff48ec833 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/programmatic_expansion/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.spacing = 20 + + tile = ft.ExpansionTile( + title=ft.Text("I am the title of this tile.", weight=ft.FontWeight.BOLD), + subtitle=ft.Text("This is the subtitle."), + affinity=ft.TileAffinity.LEADING, + controls=[ft.Text("👻", size=80)], + expanded=True, + on_change=lambda e: print(f"Tile was {'expanded' if e.data else 'collapsed'}"), + ) + + def expand_tile(_: ft.Event[ft.FilledButton]): + tile.expanded = True + tile.update() + + def collapse_tile(_: ft.Event[ft.OutlinedButton]): + tile.expanded = False + tile.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.FilledButton("Expand Tile", on_click=expand_tile), + ft.OutlinedButton("Collapse Tile", on_click=collapse_tile), + ], + ), + tile, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_tile/programmatic_expansion/pyproject.toml b/sdk/python/examples/controls/material/expansion_tile/programmatic_expansion/pyproject.toml new file mode 100644 index 0000000000..e6a00cdf0d --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/programmatic_expansion/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-programmatic-expansion" +version = "1.0.0" +description = "Controls ExpansionTile expanded state programmatically with dedicated expand and collapse buttons." +requires-python = ">=3.10" +keywords = ["expansion tile", "programmatic", "expand", "collapse", "buttons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Programmatic expansion" +controls = ["SafeArea", "Column", "Row", "ExpansionTile", "FilledButton", "OutlinedButton", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic expansion", "programmatic collapse"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/expansion_tile/theme_mode_toggle/main.py b/sdk/python/examples/controls/material/expansion_tile/theme_mode_toggle/main.py new file mode 100644 index 0000000000..579b09222f --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/theme_mode_toggle/main.py @@ -0,0 +1,108 @@ +import flet as ft + + +def main(page: ft.Page): + page.spacing = 0 + page.padding = 0 + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_switch_change(e: ft.Event[ft.Switch]): + page.theme_mode = ft.ThemeMode.DARK if e.control.value else ft.ThemeMode.LIGHT + e.control.thumb_icon = ( + ft.Icons.DARK_MODE + if page.theme_mode == ft.ThemeMode.DARK + else ft.Icons.LIGHT_MODE + ) + page.update() + + def handle_expansion_tile_change(e: ft.Event[ft.ExpansionTile]): + page.show_dialog( + ft.SnackBar( + duration=1000, + content=ft.Text( + value=( + f"ExpansionTile was " + f"{'expanded' if e.data == 'true' else 'collapsed'}" + ) + ), + ) + ) + if e.control.trailing: + e.control.trailing.icon = ( + ft.Icons.ARROW_DROP_DOWN + if e.control.trailing.icon == ft.Icons.ARROW_DROP_DOWN_CIRCLE + else ft.Icons.ARROW_DROP_DOWN_CIRCLE + ) + e.control.trailing.update() + + switch = ft.Switch( + thumb_icon=ft.Icons.DARK_MODE, + on_change=handle_switch_change, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=0, + controls=[ + ft.ExpansionTile( + key="theme_mode_toggle_top_panel", + title=ft.Text("ExpansionTile 1"), + subtitle=ft.Text("Trailing expansion arrow icon"), + bgcolor=ft.Colors.BLUE_GREY_200, + collapsed_bgcolor=ft.Colors.BLUE_GREY_200, + affinity=ft.TileAffinity.PLATFORM, + maintain_state=True, + collapsed_text_color=ft.Colors.RED, + text_color=ft.Colors.RED, + controls=[ + ft.ListTile( + title=ft.Text("This is sub-tile number 1"), + bgcolor=ft.Colors.BLUE_GREY_200, + ) + ], + ), + ft.ExpansionTile( + title=ft.Text("ExpansionTile 2"), + subtitle=ft.Text("Custom expansion arrow icon"), + trailing=ft.Icon(ft.Icons.ARROW_DROP_DOWN), + collapsed_text_color=ft.Colors.GREEN, + text_color=ft.Colors.GREEN, + on_change=handle_expansion_tile_change, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 2")) + ], + ), + ft.ExpansionTile( + title=ft.Text("ExpansionTile 3"), + subtitle=ft.Text("Leading expansion arrow icon"), + affinity=ft.TileAffinity.LEADING, + expanded=True, + collapsed_text_color=ft.Colors.BLUE_800, + text_color=ft.Colors.BLUE_200, + controls=[ + ft.ListTile(title=ft.Text("This is sub-tile number 3")), + ft.ListTile(title=ft.Text("This is sub-tile number 4")), + ft.ListTile(title=ft.Text("This is sub-tile number 5")), + ], + ), + ft.Row( + expand=True, + alignment=ft.MainAxisAlignment.END, + controls=[ + ft.Container( + padding=ft.Padding.only(bottom=50), + alignment=ft.Alignment.BOTTOM_RIGHT, + expand=True, + content=switch, + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/expansion_tile/theme_mode_toggle/pyproject.toml b/sdk/python/examples/controls/material/expansion_tile/theme_mode_toggle/pyproject.toml new file mode 100644 index 0000000000..5f5ccd2e34 --- /dev/null +++ b/sdk/python/examples/controls/material/expansion_tile/theme_mode_toggle/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "expansion-tile-theme-mode-toggle" +version = "1.0.0" +description = "Combines ExpansionTile layouts with a switch to toggle page theme mode and icon state." +requires-python = ">=3.10" +keywords = ["expansion tile", "theme mode", "toggle", "switch", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ExpansionTile"] + +[tool.flet.metadata] +title = "Theme mode toggle" +controls = ["SafeArea", "Column", "Row", "ExpansionTile", "ListTile", "Switch", "SnackBar", "Text", "Icon"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["theme toggle", "expansion change feedback", "custom tile colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/filled_button/basic/main.py b/sdk/python/examples/controls/material/filled_button/basic/main.py new file mode 100644 index 0000000000..611921f80e --- /dev/null +++ b/sdk/python/examples/controls/material/filled_button/basic/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "FilledButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.FilledButton(content="Filled button"), + ft.FilledButton(content="Disabled button", disabled=True), + ft.FilledButton( + content="Button with icon", + icon=ft.Icons.ADD_OUTLINED, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/filled_button/basic/pyproject.toml b/sdk/python/examples/controls/material/filled_button/basic/pyproject.toml new file mode 100644 index 0000000000..d516fe6611 --- /dev/null +++ b/sdk/python/examples/controls/material/filled_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "filled-button-basic" +version = "1.0.0" +description = "Shows enabled, disabled, and icon variants of FilledButton in a simple vertical layout." +requires-python = ">=3.10" +keywords = ["filled button", "button states", "icon button", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/FilledButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "FilledButton"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["enabled and disabled states", "button with icon"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/filled_button/media/adaptive.png b/sdk/python/examples/controls/material/filled_button/media/adaptive.png new file mode 100644 index 0000000000..a1fa0966bd Binary files /dev/null and b/sdk/python/examples/controls/material/filled_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/filled_button/media/basic.png b/sdk/python/examples/controls/material/filled_button/media/basic.png new file mode 100644 index 0000000000..a65ee79d9b Binary files /dev/null and b/sdk/python/examples/controls/material/filled_button/media/basic.png differ diff --git a/sdk/python/examples/controls/material/filled_button/media/index.png b/sdk/python/examples/controls/material/filled_button/media/index.png new file mode 100644 index 0000000000..d1b2fabd62 Binary files /dev/null and b/sdk/python/examples/controls/material/filled_button/media/index.png differ diff --git a/sdk/python/examples/controls/material/filled_tonal_button/basic/main.py b/sdk/python/examples/controls/material/filled_tonal_button/basic/main.py new file mode 100644 index 0000000000..75b3855d51 --- /dev/null +++ b/sdk/python/examples/controls/material/filled_tonal_button/basic/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "FilledTonalButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.FilledTonalButton(content="Filled tonal button"), + ft.FilledTonalButton(content="Disabled button", disabled=True), + ft.FilledTonalButton( + content="Button with icon", + icon=ft.Icons.ADD_OUTLINED, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/filled_tonal_button/basic/pyproject.toml b/sdk/python/examples/controls/material/filled_tonal_button/basic/pyproject.toml new file mode 100644 index 0000000000..de96406766 --- /dev/null +++ b/sdk/python/examples/controls/material/filled_tonal_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "filled-tonal-button-basic" +version = "1.0.0" +description = "Demonstrates FilledTonalButton variants including disabled and icon button states." +requires-python = ">=3.10" +keywords = ["filled tonal button", "button states", "icon button", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/FilledTonalButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "FilledTonalButton"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["enabled and disabled states", "button with icon"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/filled_tonal_button/media/adaptive.png b/sdk/python/examples/controls/material/filled_tonal_button/media/adaptive.png new file mode 100644 index 0000000000..64eed7527c Binary files /dev/null and b/sdk/python/examples/controls/material/filled_tonal_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/filled_tonal_button/media/basic.png b/sdk/python/examples/controls/material/filled_tonal_button/media/basic.png new file mode 100644 index 0000000000..f08773f020 Binary files /dev/null and b/sdk/python/examples/controls/material/filled_tonal_button/media/basic.png differ diff --git a/sdk/python/examples/controls/material/filled_tonal_button/media/index.png b/sdk/python/examples/controls/material/filled_tonal_button/media/index.png new file mode 100644 index 0000000000..e8c9c4288a Binary files /dev/null and b/sdk/python/examples/controls/material/filled_tonal_button/media/index.png differ diff --git a/sdk/python/examples/controls/material/floating_action_button/handling_clicks/main.py b/sdk/python/examples/controls/material/floating_action_button/handling_clicks/main.py new file mode 100644 index 0000000000..df6ae30919 --- /dev/null +++ b/sdk/python/examples/controls/material/floating_action_button/handling_clicks/main.py @@ -0,0 +1,64 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Floating Action Button" + page.theme_mode = ft.ThemeMode.LIGHT + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.padding = 0 + page.scroll = ft.ScrollMode.HIDDEN + + count = 1 + + def handle_fab_click(e: ft.Event[ft.FloatingActionButton]): + nonlocal count + page.add( + ft.ListTile( + title=ft.Text(f"Tile {count}"), + bgcolor=ft.Colors.TEAL_300, + leading=ft.Icon( + ft.Icons.CIRCLE_OUTLINED, + color=ft.Colors.DEEP_ORANGE_300, + ), + on_click=lambda x: print(x.control.title.value + " was clicked!"), + ) + ) + page.show_dialog(ft.SnackBar(ft.Text("Tile was added successfully!"))) + count += 1 + + page.floating_action_button = ft.FloatingActionButton( + key="handling_clicks_fab", + icon=ft.Icons.ADD, + on_click=handle_fab_click, + bgcolor=ft.Colors.LIME_300, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Container( + bgcolor=ft.Colors.BLUE, + padding=ft.Padding.all(20), + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + value="Floating Action Button Example", + style=ft.TextStyle( + size=20, + weight=ft.FontWeight.W_500, + ), + ) + ], + ), + ), + ft.Text("Press the FAB to add a tile!"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/floating_action_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/material/floating_action_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..1a136b3c09 --- /dev/null +++ b/sdk/python/examples/controls/material/floating_action_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "floating-action-button-handling-clicks" +version = "1.0.0" +description = "Adds list tiles with a FloatingActionButton click and shows a SnackBar confirmation." +requires-python = ">=3.10" +keywords = ["floating action button", "list tile", "click handling", "snackbar"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/FloatingActionButton"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "Container", "Row", "Text", "FloatingActionButton", "ListTile", "SnackBar", "Icon"] +layout_pattern = "feed" +complexity = "basic" +features = ["floating action button click", "dynamic list updates", "snackbar feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/floating_action_button/media/handling_clicks.gif b/sdk/python/examples/controls/material/floating_action_button/media/handling_clicks.gif new file mode 100644 index 0000000000..430c8eef90 Binary files /dev/null and b/sdk/python/examples/controls/material/floating_action_button/media/handling_clicks.gif differ diff --git a/sdk/python/examples/controls/material/floating_action_button/media/index.png b/sdk/python/examples/controls/material/floating_action_button/media/index.png new file mode 100644 index 0000000000..6b0b6d9a20 Binary files /dev/null and b/sdk/python/examples/controls/material/floating_action_button/media/index.png differ diff --git a/sdk/python/examples/controls/material/icon_button/handling_clicks/main.py b/sdk/python/examples/controls/material/icon_button/handling_clicks/main.py new file mode 100644 index 0000000000..b65e615873 --- /dev/null +++ b/sdk/python/examples/controls/material/icon_button/handling_clicks/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "IconButton Example" + + def button_clicked(e: ft.Event[ft.IconButton]): + button.data += 1 + message.value = f"Button clicked {button.data} time(s)" + message.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.IconButton( + key="handling_clicks_icon_button", + icon=ft.Icons.PLAY_CIRCLE_FILL_OUTLINED, + data=0, + on_click=button_clicked, + ), + message := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/icon_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/material/icon_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..8fd6e7bd26 --- /dev/null +++ b/sdk/python/examples/controls/material/icon_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-button-handling-clicks" +version = "1.0.0" +description = "Counts IconButton clicks and updates a text status message." +requires-python = ">=3.10" +keywords = ["icon button", "click handling", "events", "counter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/IconButton"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "IconButton", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["click callback", "live click counter"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/icon_button/media/adaptive.png b/sdk/python/examples/controls/material/icon_button/media/adaptive.png new file mode 100644 index 0000000000..286fb71b23 Binary files /dev/null and b/sdk/python/examples/controls/material/icon_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/icon_button/media/handling_clicks.gif b/sdk/python/examples/controls/material/icon_button/media/handling_clicks.gif new file mode 100644 index 0000000000..8acd3e5bd7 Binary files /dev/null and b/sdk/python/examples/controls/material/icon_button/media/handling_clicks.gif differ diff --git a/sdk/python/examples/controls/material/icon_button/media/index.png b/sdk/python/examples/controls/material/icon_button/media/index.png new file mode 100644 index 0000000000..45079c2243 Binary files /dev/null and b/sdk/python/examples/controls/material/icon_button/media/index.png differ diff --git a/sdk/python/examples/controls/material/icon_button/selected_icon/main.py b/sdk/python/examples/controls/material/icon_button/selected_icon/main.py new file mode 100644 index 0000000000..a48cb53f4c --- /dev/null +++ b/sdk/python/examples/controls/material/icon_button/selected_icon/main.py @@ -0,0 +1,35 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "IconButton Example" + page.padding = 10 + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def handle_click(e: ft.Event[ft.IconButton]): + e.control.selected = not e.control.selected + e.control.update() + + page.add( + ft.SafeArea( + content=ft.IconButton( + key="selected_icon_button", + icon=ft.Icons.BATTERY_1_BAR, + selected_icon=ft.Icons.BATTERY_FULL, + scale=5, + on_click=handle_click, + selected=False, + style=ft.ButtonStyle( + color={ + ft.ControlState.SELECTED: ft.Colors.GREEN, + ft.ControlState.DEFAULT: ft.Colors.RED, + } + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/icon_button/selected_icon/pyproject.toml b/sdk/python/examples/controls/material/icon_button/selected_icon/pyproject.toml new file mode 100644 index 0000000000..6544e68bce --- /dev/null +++ b/sdk/python/examples/controls/material/icon_button/selected_icon/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-button-selected-icon" +version = "1.0.0" +description = "Toggles IconButton selected state and switches between default and selected icons." +requires-python = ">=3.10" +keywords = ["icon button", "selected icon", "toggle", "button style"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/IconButton"] + +[tool.flet.metadata] +title = "Selected icon" +controls = ["SafeArea", "IconButton", "ButtonStyle"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["selected state toggle", "selected icon", "state-based colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/icon_button/variants/main.py b/sdk/python/examples/controls/material/icon_button/variants/main.py new file mode 100644 index 0000000000..07738941ab --- /dev/null +++ b/sdk/python/examples/controls/material/icon_button/variants/main.py @@ -0,0 +1,107 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "IconButton variants" + page.padding = 10 + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + def toggle_icon_button(e): + e.control.selected = not e.control.selected + + page.add( + ft.SafeArea( + content=ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + spacing=50, + controls=[ + # Normal buttons column (enabled only) + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "Normal", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.IconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ft.FilledIconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ft.FilledTonalIconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ft.OutlinedIconButton( + icon=ft.Icons.FILTER_DRAMA, + ), + ], + ), + # Disabled buttons column + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "Disabled", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.IconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ft.FilledIconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ft.FilledTonalIconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ft.OutlinedIconButton( + icon=ft.Icons.FILTER_DRAMA, + disabled=True, + ), + ], + ), + # Toggle buttons column + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=20, + controls=[ + ft.Text( + "Toggle", + theme_style=ft.TextThemeStyle.BODY_MEDIUM, + ), + ft.IconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ft.FilledIconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ft.FilledTonalIconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ft.OutlinedIconButton( + icon=ft.Icons.FILTER_DRAMA, + selected=False, + on_click=toggle_icon_button, + ), + ], + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/icon_button/variants/pyproject.toml b/sdk/python/examples/controls/material/icon_button/variants/pyproject.toml new file mode 100644 index 0000000000..163fd07c2c --- /dev/null +++ b/sdk/python/examples/controls/material/icon_button/variants/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "icon-button-variants" +version = "1.0.0" +description = "Compares normal, disabled, and toggle variants across IconButton style families." +requires-python = ">=3.10" +keywords = ["icon button", "variants", "filled", "outlined", "toggle"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/IconButton"] + +[tool.flet.metadata] +title = "Variants" +controls = ["SafeArea", "Row", "Column", "Text", "IconButton", "FilledIconButton", "FilledTonalIconButton", "OutlinedIconButton"] +layout_pattern = "comparison" +complexity = "basic" +features = ["variant comparison", "disabled states", "toggle buttons"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/list_tile/basic/assets/icon-192.png b/sdk/python/examples/controls/material/list_tile/basic/assets/icon-192.png new file mode 100644 index 0000000000..65da3b9571 Binary files /dev/null and b/sdk/python/examples/controls/material/list_tile/basic/assets/icon-192.png differ diff --git a/sdk/python/examples/controls/material/list_tile/basic/main.py b/sdk/python/examples/controls/material/list_tile/basic/main.py new file mode 100644 index 0000000000..62eccfb21e --- /dev/null +++ b/sdk/python/examples/controls/material/list_tile/basic/main.py @@ -0,0 +1,83 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "ListTile Example" + + page.add( + ft.SafeArea( + content=ft.Card( + content=ft.Container( + width=500, + padding=ft.Padding.symmetric(vertical=10), + content=ft.Column( + spacing=0, + controls=[ + ft.ListTile(title=ft.Text("One-line list tile")), + ft.ListTile( + title=ft.Text("One-line dense list tile"), + dense=True, + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.SETTINGS), + title=ft.Text("One-line selected list tile"), + selected=True, + ), + ft.ListTile( + leading=ft.Image( + src="assets/icon-192.png", + fit=ft.BoxFit.CONTAIN, + ), + title=ft.Text("One-line with leading control"), + ), + ft.ListTile( + title=ft.Text("One-line with trailing control"), + trailing=ft.PopupMenuButton( + icon=ft.Icons.MORE_VERT, + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(content="Item 2"), + ], + ), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.ALBUM), + title=ft.Text( + value=( + "One-line with leading and trailing controls" + ) + ), + trailing=ft.PopupMenuButton( + icon=ft.Icons.MORE_VERT, + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(content="Item 2"), + ], + ), + ), + ft.ListTile( + leading=ft.Icon(ft.Icons.SNOOZE), + title=ft.Text( + value=( + "Two-line with leading and trailing controls" + ) + ), + subtitle=ft.Text("Here is a second title."), + trailing=ft.PopupMenuButton( + icon=ft.Icons.MORE_VERT, + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(content="Item 2"), + ], + ), + ), + ], + ), + ) + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/list_tile/basic/pyproject.toml b/sdk/python/examples/controls/material/list_tile/basic/pyproject.toml new file mode 100644 index 0000000000..5816f01ba3 --- /dev/null +++ b/sdk/python/examples/controls/material/list_tile/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "list-tile-basic" +version = "1.0.0" +description = "Showcases one-line and two-line ListTile variants with leading/trailing controls and selection state." +requires-python = ">=3.10" +keywords = ["list tile", "material", "popup menu", "selection", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/ListTile"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Card", "Container", "Column", "ListTile", "Icon", "Image", "PopupMenuButton", "PopupMenuItem", "Text"] +layout_pattern = "list-detail" +complexity = "basic" +features = ["tile variants", "leading and trailing controls", "selected and dense states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/list_tile/media/basic.png b/sdk/python/examples/controls/material/list_tile/media/basic.png new file mode 100644 index 0000000000..7a0e29c16c Binary files /dev/null and b/sdk/python/examples/controls/material/list_tile/media/basic.png differ diff --git a/sdk/python/examples/controls/material/list_tile/media/index.png b/sdk/python/examples/controls/material/list_tile/media/index.png new file mode 100644 index 0000000000..fc3bdeb8ba Binary files /dev/null and b/sdk/python/examples/controls/material/list_tile/media/index.png differ diff --git a/sdk/python/examples/controls/material/menu_bar/media/nested_submenus.gif b/sdk/python/examples/controls/material/menu_bar/media/nested_submenus.gif new file mode 100644 index 0000000000..5455898d19 Binary files /dev/null and b/sdk/python/examples/controls/material/menu_bar/media/nested_submenus.gif differ diff --git a/sdk/python/examples/controls/material/menu_bar/nested_submenus/main.py b/sdk/python/examples/controls/material/menu_bar/nested_submenus/main.py new file mode 100644 index 0000000000..fcdc64ff0f --- /dev/null +++ b/sdk/python/examples/controls/material/menu_bar/nested_submenus/main.py @@ -0,0 +1,135 @@ +import flet as ft + + +def main(page: ft.Page): + appbar_text_ref = ft.Ref[ft.Text]() + + def handle_menu_item_click(e: ft.Event[ft.MenuItemButton]): + text = e.control.content.value + page.show_dialog(ft.SnackBar(ft.Text(f"{text} was clicked!"))) + appbar_text_ref.current.value = text + appbar_text_ref.current.update() + + def handle_submenu_open(e: ft.Event[ft.SubmenuButton]): + print(f"{e.control.content.value}.on_open") + + def handle_submenu_close(e: ft.Event[ft.SubmenuButton]): + print(f"{e.control.content.value}.on_close") + + def handle_submenu_hover(e: ft.Event[ft.SubmenuButton]): + print(f"{e.control.content.value}.on_hover") + + page.appbar = ft.AppBar( + title=ft.Text("Menus", ref=appbar_text_ref), + center_title=True, + bgcolor=ft.Colors.BLUE, + ) + + page.add( + ft.SafeArea( + content=ft.Row( + controls=[ + ft.MenuBar( + expand=True, + style=ft.MenuStyle( + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.RED_300, + mouse_cursor={ + ft.ControlState.HOVERED: ft.MouseCursor.WAIT, + ft.ControlState.DEFAULT: ft.MouseCursor.ZOOM_OUT, + }, + ), + controls=[ + ft.SubmenuButton( + content=ft.Text("File"), + on_open=handle_submenu_open, + on_close=handle_submenu_close, + on_hover=handle_submenu_hover, + controls=[ + ft.MenuItemButton( + content=ft.Text("About"), + leading=ft.Icon(ft.Icons.INFO), + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.GREEN_100 + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Save"), + leading=ft.Icon(ft.Icons.SAVE), + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.GREEN_100 + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Quit"), + leading=ft.Icon(ft.Icons.CLOSE), + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.GREEN_100 + ) + } + ), + ), + ], + ), + ft.SubmenuButton( + content=ft.Text("View"), + on_open=handle_submenu_open, + on_close=handle_submenu_close, + on_hover=handle_submenu_hover, + controls=[ + ft.SubmenuButton( + content=ft.Text("Zoom"), + controls=[ + ft.MenuItemButton( + content=ft.Text("Magnify"), + leading=ft.Icon(ft.Icons.ZOOM_IN), + close_on_click=False, + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.PURPLE_200 + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Minify"), + leading=ft.Icon(ft.Icons.ZOOM_OUT), + close_on_click=False, + on_click=handle_menu_item_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ( + ft.Colors.PURPLE_200 + ) + } + ), + ), + ], + ) + ], + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/menu_bar/nested_submenus/pyproject.toml b/sdk/python/examples/controls/material/menu_bar/nested_submenus/pyproject.toml new file mode 100644 index 0000000000..36115e22b6 --- /dev/null +++ b/sdk/python/examples/controls/material/menu_bar/nested_submenus/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "menu-bar-nested-submenus" +version = "1.0.0" +description = "Builds a MenuBar with nested submenus, hover callbacks, and click feedback." +requires-python = ">=3.10" +keywords = ["menu bar", "submenu", "nested menu", "events", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/MenuBar"] + +[tool.flet.metadata] +title = "MenuBar with nested submenus" +controls = ["SafeArea", "Row", "MenuBar", "SubmenuButton", "MenuItemButton", "AppBar", "SnackBar", "Text", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["nested submenus", "menu open and close callbacks", "menu item click feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/menu_item_button/basic/main.py b/sdk/python/examples/controls/material/menu_item_button/basic/main.py new file mode 100644 index 0000000000..97bf6dc256 --- /dev/null +++ b/sdk/python/examples/controls/material/menu_item_button/basic/main.py @@ -0,0 +1,83 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 0 + page.spacing = 0 + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_color_click(e: ft.Event[ft.MenuItemButton]): + color = e.control.content.value + background_container.content.value = f"{color} background color" + background_container.bgcolor = color.lower() + + def handle_on_hover(e: ft.Event[ft.MenuItemButton]): + print(e) + + menubar = ft.MenuBar( + expand=True, + controls=[ + ft.SubmenuButton( + content=ft.Text("BgColors"), + controls=[ + ft.MenuItemButton( + content=ft.Text("Blue"), + leading=ft.Icon(ft.Icons.COLORIZE), + style=ft.ButtonStyle( + bgcolor={ft.ControlState.HOVERED: ft.Colors.BLUE} + ), + on_click=handle_color_click, + on_hover=handle_on_hover, + ), + ft.MenuItemButton( + content=ft.Text("Green"), + leading=ft.Icon(ft.Icons.COLORIZE), + style=ft.ButtonStyle( + bgcolor={ft.ControlState.HOVERED: ft.Colors.GREEN} + ), + on_click=handle_color_click, + on_hover=handle_on_hover, + ), + ft.MenuItemButton( + content=ft.Text("Red"), + leading=ft.Icon(ft.Icons.COLORIZE), + style=ft.ButtonStyle( + bgcolor={ft.ControlState.HOVERED: ft.Colors.RED} + ), + on_click=handle_color_click, + on_hover=handle_on_hover, + ), + ], + ), + ], + ) + + page.add( + ft.SafeArea( + expand=True, + avoid_intrusions_left=False, + avoid_intrusions_top=False, + avoid_intrusions_right=False, + avoid_intrusions_bottom=False, + content=ft.Column( + expand=True, + spacing=0, + controls=[ + ft.Row(controls=[menubar]), + background_container := ft.Container( + expand=True, + bgcolor=ft.Colors.WHITE, + alignment=ft.Alignment.CENTER, + content=ft.Text( + value="Choose a bgcolor from the menu", + style=ft.TextStyle(weight=ft.FontWeight.W_500), + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/menu_item_button/basic/pyproject.toml b/sdk/python/examples/controls/material/menu_item_button/basic/pyproject.toml new file mode 100644 index 0000000000..b747c3d414 --- /dev/null +++ b/sdk/python/examples/controls/material/menu_item_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "menu-item-button-basic" +version = "1.0.0" +description = "Uses MenuItemButton items to change page background color from a submenu with hover styling." +requires-python = ">=3.10" +keywords = ["menu item button", "submenu", "hover style", "events", "background color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/MenuItemButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Column", "Row", "MenuBar", "SubmenuButton", "MenuItemButton", "Container", "Text", "Icon"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["submenu item click handling", "menu item hover styling", "dynamic background color updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/menu_item_button/media/basic.gif b/sdk/python/examples/controls/material/menu_item_button/media/basic.gif new file mode 100644 index 0000000000..7ddd02561b Binary files /dev/null and b/sdk/python/examples/controls/material/menu_item_button/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/navigation_bar/basic/main.py b/sdk/python/examples/controls/material/navigation_bar/basic/main.py new file mode 100644 index 0000000000..b10a48b2df --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_bar/basic/main.py @@ -0,0 +1,27 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "NavigationBar Example" + + page.navigation_bar = ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.EXPLORE, label="Explore"), + ft.NavigationBarDestination(icon=ft.Icons.COMMUTE, label="Commute"), + ft.NavigationBarDestination( + icon=ft.Icons.BOOKMARK_BORDER, + selected_icon=ft.Icons.BOOKMARK, + label="Favorites", + ), + ] + ) + + page.add( + ft.SafeArea( + content=ft.Text("Body!"), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/navigation_bar/basic/pyproject.toml b/sdk/python/examples/controls/material/navigation_bar/basic/pyproject.toml new file mode 100644 index 0000000000..4457421a1c --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-bar-basic" +version = "1.0.0" +description = "Demonstrates a Material NavigationBar with three destination tabs." +requires-python = ">=3.10" +keywords = ["navigation bar", "bottom navigation", "destinations", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationBar"] + +[tool.flet.metadata] +title = "Basic" +controls = ["NavigationBar", "NavigationBarDestination", "SafeArea", "Text"] +layout_pattern = "tabbed-navigation" +complexity = "basic" +features = ["bottom navigation", "destination tabs"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/navigation_bar/media/adaptive.png b/sdk/python/examples/controls/material/navigation_bar/media/adaptive.png new file mode 100644 index 0000000000..ca9769a41c Binary files /dev/null and b/sdk/python/examples/controls/material/navigation_bar/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/navigation_bar/media/basic.gif b/sdk/python/examples/controls/material/navigation_bar/media/basic.gif new file mode 100644 index 0000000000..3fef56305c Binary files /dev/null and b/sdk/python/examples/controls/material/navigation_bar/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/navigation_drawer/adaptive_navigation/main.py b/sdk/python/examples/controls/material/navigation_drawer/adaptive_navigation/main.py new file mode 100644 index 0000000000..540a68b204 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/adaptive_navigation/main.py @@ -0,0 +1,143 @@ +import flet as ft + +DESTINATIONS = [ + ("Messages", ft.Icons.WIDGETS_OUTLINED, ft.Icons.WIDGETS), + ("Profile", ft.Icons.FORMAT_PAINT_OUTLINED, ft.Icons.FORMAT_PAINT), + ("Settings", ft.Icons.SETTINGS_OUTLINED, ft.Icons.SETTINGS), +] + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.padding = 0 + + screen_index = 0 + + def build_page_index_text() -> ft.Text: + return ft.Text(f"Page Index = {screen_index}", size=24) + + def set_screen(index: int): + nonlocal screen_index + screen_index = index + render() + + def build_navigation_bar() -> ft.NavigationBar: + def handle_nav_bar_change(e: ft.Event[ft.NavigationBar]): + set_screen(e.control.selected_index) + + return ft.NavigationBar( + selected_index=screen_index, + on_change=handle_nav_bar_change, + destinations=[ + ft.NavigationBarDestination( + label=label, + icon=icon, + selected_icon=selected_icon, + ) + for label, icon, selected_icon in DESTINATIONS + ], + ) + + def build_navigation_rail() -> ft.NavigationRail: + def handle_nav_rail_change(e: ft.Event[ft.NavigationRail]): + if e.control.selected_index is not None: + set_screen(e.control.selected_index) + + return ft.NavigationRail( + min_width=50, + selected_index=screen_index, + use_indicator=True, + on_change=handle_nav_rail_change, + destinations=[ + ft.NavigationRailDestination( + label=label, + icon=icon, + selected_icon=selected_icon, + ) + for label, icon, selected_icon in DESTINATIONS + ], + ) + + def build_end_drawer() -> ft.NavigationDrawer: + async def handle_drawer_change(e: ft.Event[ft.NavigationDrawer]): + set_screen(e.control.selected_index) + await page.close_end_drawer() + + return ft.NavigationDrawer( + selected_index=screen_index, + on_change=handle_drawer_change, + controls=[ + ft.Container( + padding=ft.Padding.only(left=28, top=16, right=16, bottom=10), + content=ft.Text( + "Header", theme_style=ft.TextThemeStyle.TITLE_SMALL + ), + ), + *[ + ft.NavigationDrawerDestination( + label=label, + icon=icon, + selected_icon=selected_icon, + ) + for label, icon, selected_icon in DESTINATIONS + ], + ], + ) + + def build_bottom_bar_layout() -> ft.SafeArea: + return ft.SafeArea( + expand=True, + content=ft.Container( + expand=True, + alignment=ft.Alignment.CENTER, + content=build_page_index_text(), + ), + ) + + def build_drawer_layout() -> ft.SafeArea: + async def open_drawer(e: ft.Event[ft.Button]): + await page.show_end_drawer() + + return ft.SafeArea( + expand=True, + avoid_intrusions_top=False, + avoid_intrusions_bottom=False, + content=ft.Row( + expand=True, + controls=[ + ft.Container( + padding=ft.Padding.symmetric(horizontal=5), + content=build_navigation_rail(), + ), + ft.VerticalDivider(thickness=1, width=1), + ft.Column( + expand=True, + alignment=ft.MainAxisAlignment.SPACE_EVENLY, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + build_page_index_text(), + ft.Button("Open Drawer", on_click=open_drawer), + ], + ), + ], + ), + ) + + def render(): + page.clean() + if (page.width or page.window.width) >= 450: # wide layout + page.navigation_bar = None + page.end_drawer = build_end_drawer() + page.add(build_drawer_layout()) + else: # narrow layout + page.end_drawer = None + page.navigation_bar = build_navigation_bar() + page.add(build_bottom_bar_layout()) + page.update() + + page.on_resize = lambda e: render() + render() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/navigation_drawer/adaptive_navigation/pyproject.toml b/sdk/python/examples/controls/material/navigation_drawer/adaptive_navigation/pyproject.toml new file mode 100644 index 0000000000..a9545c7511 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/adaptive_navigation/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-drawer-adaptive-navigation" +version = "1.0.0" +description = "Demonstrates adaptive navigation with NavigationBar on narrow layouts and NavigationRail plus NavigationDrawer on wide layouts." +requires-python = ">=3.10" +keywords = ["navigation drawer", "navigation rail", "navigation bar", "adaptive navigation", "responsive"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationDrawer"] + +[tool.flet.metadata] +title = "Adaptive Navigation" +controls = ["NavigationDrawer", "NavigationDrawerDestination", "NavigationRail", "NavigationRailDestination", "NavigationBar", "NavigationBarDestination", "Button", "SafeArea", "Container", "Row", "Column", "VerticalDivider", "Text", "Page"] +layout_pattern = "adaptive-navigation" +complexity = "intermediate" +features = ["responsive layout", "adaptive navigation", "end drawer", "navigation rail", "navigation bar"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/navigation_drawer/media/position_end.gif b/sdk/python/examples/controls/material/navigation_drawer/media/position_end.gif new file mode 100644 index 0000000000..f87d23cf92 Binary files /dev/null and b/sdk/python/examples/controls/material/navigation_drawer/media/position_end.gif differ diff --git a/sdk/python/examples/controls/material/navigation_drawer/media/position_start.gif b/sdk/python/examples/controls/material/navigation_drawer/media/position_start.gif new file mode 100644 index 0000000000..c2db87fa91 Binary files /dev/null and b/sdk/python/examples/controls/material/navigation_drawer/media/position_start.gif differ diff --git a/sdk/python/examples/controls/material/navigation_drawer/position_end/main.py b/sdk/python/examples/controls/material/navigation_drawer/position_end/main.py new file mode 100644 index 0000000000..7201b80ab1 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/position_end/main.py @@ -0,0 +1,41 @@ +import flet as ft + + +def main(page: ft.Page): + async def handle_show_drawer(): + await page.show_end_drawer() + + def handle_dismissal(e: ft.Event[ft.NavigationDrawer]): + print("Drawer dismissed!") + + async def handle_change(e: ft.Event[ft.NavigationDrawer]): + print(f"Selected Index changed: {e.control.selected_index}") + await page.close_end_drawer() + + page.end_drawer = ft.NavigationDrawer( + on_dismiss=handle_dismissal, + on_change=handle_change, + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.ADD_COMMENT), + label="Item 2", + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Button( + content="Show end drawer", + on_click=handle_show_drawer, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/navigation_drawer/position_end/pyproject.toml b/sdk/python/examples/controls/material/navigation_drawer/position_end/pyproject.toml new file mode 100644 index 0000000000..f649167a6b --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/position_end/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-drawer-position-end" +version = "1.0.0" +description = "Demonstrates an end-position NavigationDrawer with destination selection handling." +requires-python = ">=3.10" +keywords = ["navigation drawer", "drawer", "navigation", "end position", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationDrawer"] + +[tool.flet.metadata] +title = "End Position" +controls = ["NavigationDrawer", "NavigationDrawerDestination", "Button", "SafeArea", "Page"] +layout_pattern = "drawer-navigation" +complexity = "basic" +features = ["end drawer", "destination callbacks", "open/close actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/navigation_drawer/position_start/main.py b/sdk/python/examples/controls/material/navigation_drawer/position_start/main.py new file mode 100644 index 0000000000..438b560964 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/position_start/main.py @@ -0,0 +1,50 @@ +import flet as ft + + +def main(page: ft.Page): + async def handle_show_drawer(): + await page.show_drawer() + + def handle_dismissal(e: ft.Event[ft.NavigationDrawer]): + print("Drawer dismissed!") + + async def handle_change(e: ft.Event[ft.NavigationDrawer]): + print(f"Selected Index changed: {e.control.selected_index}") + await page.close_drawer() + + page.drawer = ft.NavigationDrawer( + on_dismiss=handle_dismissal, + on_change=handle_change, + controls=[ + ft.Container(height=12), + ft.NavigationDrawerDestination( + label="Item 1", + icon=ft.Icons.DOOR_BACK_DOOR_OUTLINED, + selected_icon=ft.Icon(ft.Icons.DOOR_BACK_DOOR), + ), + ft.Divider(thickness=2), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.MAIL_OUTLINED), + label="Item 2", + selected_icon=ft.Icons.MAIL, + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.PHONE_OUTLINED), + label="Item 3", + selected_icon=ft.Icons.PHONE, + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Button( + content="Show drawer", + on_click=handle_show_drawer, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/navigation_drawer/position_start/pyproject.toml b/sdk/python/examples/controls/material/navigation_drawer/position_start/pyproject.toml new file mode 100644 index 0000000000..de3b5e011f --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/position_start/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-drawer-position-start" +version = "1.0.0" +description = "Demonstrates a start-position NavigationDrawer with labeled destinations and callbacks." +requires-python = ">=3.10" +keywords = ["navigation drawer", "drawer", "navigation", "start position", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationDrawer"] + +[tool.flet.metadata] +title = "Start Position" +controls = ["NavigationDrawer", "NavigationDrawerDestination", "Button", "SafeArea", "Container", "Divider", "Page"] +layout_pattern = "drawer-navigation" +complexity = "basic" +features = ["start drawer", "navigation destinations", "selection and dismiss callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/navigation_drawer/theming/main.py b/sdk/python/examples/controls/material/navigation_drawer/theming/main.py new file mode 100644 index 0000000000..ea5a71ce9d --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/theming/main.py @@ -0,0 +1,77 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.theme = ft.Theme( + color_scheme_seed=ft.Colors.INDIGO, + navigation_drawer_theme=ft.NavigationDrawerTheme( + bgcolor=ft.Colors.RED_300, + indicator_color=ft.Colors.INDIGO_100, + icon_theme={ + ft.ControlState.DEFAULT: ft.IconTheme( + color=ft.Colors.INDIGO_900, + size=22, + ), + ft.ControlState.SELECTED: ft.IconTheme( + color=ft.Colors.YELLOW, + size=28, + ), + }, + label_text_style={ + ft.ControlState.DEFAULT: ft.TextStyle( + color=ft.Colors.YELLOW, + size=11, + italic=True, + ), + ft.ControlState.SELECTED: ft.TextStyle( + color=ft.Colors.INDIGO_900, + size=15, + weight=ft.FontWeight.BOLD, + ), + }, + ), + ) + + page.drawer = ft.NavigationDrawer( + controls=[ + ft.Container( + padding=ft.Padding.only(left=28, top=20, bottom=12), + content=ft.Text( + "Workspace", theme_style=ft.TextThemeStyle.TITLE_MEDIUM + ), + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.DASHBOARD_OUTLINED, + selected_icon=ft.Icons.DASHBOARD, + label="Dashboard", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.NOTIFICATIONS_OUTLINED, + selected_icon=ft.Icons.NOTIFICATIONS, + label="Notifications", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + selected_icon=ft.Icons.SETTINGS, + label="Settings", + ), + ], + ) + + async def handle_show_drawer(e: ft.Event[ft.Button]): + await page.show_drawer() + + page.add( + ft.SafeArea( + content=ft.Button( + "Show drawer", + icon=ft.Icons.MENU, + on_click=handle_show_drawer, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/navigation_drawer/theming/pyproject.toml b/sdk/python/examples/controls/material/navigation_drawer/theming/pyproject.toml new file mode 100644 index 0000000000..a50266def9 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_drawer/theming/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-drawer-theming" +version = "1.0.0" +description = "Demonstrates NavigationDrawer theming with custom background, icons, labels, and indicator styles." +requires-python = ">=3.10" +keywords = ["navigation drawer", "drawer", "navigation", "theming", "theme"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationDrawer"] + +[tool.flet.metadata] +title = "Theming" +controls = ["NavigationDrawer", "NavigationDrawerDestination", "Button", "SafeArea", "Container", "Text", "Page"] +layout_pattern = "drawer-navigation" +complexity = "basic" +features = ["navigation drawer theme", "state-based icon theme", "state-based label styles", "selection indicator styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/navigation_rail/basic/main.py b/sdk/python/examples/controls/material/navigation_rail/basic/main.py new file mode 100644 index 0000000000..1637fcb988 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_rail/basic/main.py @@ -0,0 +1,56 @@ +import flet as ft + + +def main(page: ft.Page): + rail = ft.NavigationRail( + selected_index=0, + label_type=ft.NavigationRailLabelType.ALL, + min_width=100, + min_extended_width=400, + group_alignment=-0.9, + on_change=lambda e: print("Selected destination:", e.control.selected_index), + leading=ft.FloatingActionButton( + icon=ft.Icons.CREATE, + content="Add", + on_click=lambda e: print("FAB clicked!"), + ), + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.FAVORITE_BORDER, + selected_icon=ft.Icons.FAVORITE, + label="First", + ), + ft.NavigationRailDestination( + icon=ft.Icon(ft.Icons.BOOKMARK_BORDER), + selected_icon=ft.Icon(ft.Icons.BOOKMARK), + label="Second", + ), + ft.NavigationRailDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + selected_icon=ft.Icon(ft.Icons.SETTINGS), + label=ft.Text("Settings"), + ), + ], + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Row( + expand=True, + controls=[ + ft.SelectionArea(content=rail), + ft.VerticalDivider(width=1), + ft.Column( + alignment=ft.MainAxisAlignment.START, + expand=True, + controls=[ft.Text("Body!")], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/navigation_rail/basic/pyproject.toml b/sdk/python/examples/controls/material/navigation_rail/basic/pyproject.toml new file mode 100644 index 0000000000..9187d09833 --- /dev/null +++ b/sdk/python/examples/controls/material/navigation_rail/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "navigation-rail-basic" +version = "1.0.0" +description = "Demonstrates a Material NavigationRail with three destinations and custom leading FAB." +requires-python = ">=3.10" +keywords = ["navigation rail", "material", "navigation", "rail", "destinations"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/NavigationRail"] + +[tool.flet.metadata] +title = "Basic" +controls = ["NavigationRail", "NavigationRailDestination", "SafeArea", "FloatingActionButton", "SelectionArea", "Page", "VerticalDivider", "Column", "Row", "Text"] +layout_pattern = "side-navigation" +complexity = "basic" +features = ["navigation rail", "destination selection", "leading action button"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/navigation_rail/media/basic.png b/sdk/python/examples/controls/material/navigation_rail/media/basic.png new file mode 100644 index 0000000000..b1bdd1877a Binary files /dev/null and b/sdk/python/examples/controls/material/navigation_rail/media/basic.png differ diff --git a/sdk/python/examples/controls/material/outlined_button/basic/main.py b/sdk/python/examples/controls/material/outlined_button/basic/main.py new file mode 100644 index 0000000000..796f7e046d --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton(content="Outlined button"), + ft.OutlinedButton(content="Disabled button", disabled=True), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/outlined_button/basic/pyproject.toml b/sdk/python/examples/controls/material/outlined_button/basic/pyproject.toml new file mode 100644 index 0000000000..5a0c1b037e --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-basic" +version = "1.0.0" +description = "Shows enabled and disabled OutlinedButton variants." +requires-python = ">=3.10" +keywords = ["outlined button", "button", "material", "disabled states"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "OutlinedButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/outlined_button/custom_content/main.py b/sdk/python/examples/controls/material/outlined_button/custom_content/main.py new file mode 100644 index 0000000000..9894601896 --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/custom_content/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + page.theme_mode = ft.ThemeMode.LIGHT + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton( + width=150, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), + ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), + ], + ), + ), + ft.OutlinedButton( + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + spacing=5, + controls=[ + ft.Text(value="Compound button", size=20), + ft.Text(value="This is secondary text"), + ], + ), + ), + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/outlined_button/custom_content/pyproject.toml b/sdk/python/examples/controls/material/outlined_button/custom_content/pyproject.toml new file mode 100644 index 0000000000..a85e0741a0 --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/custom_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-custom-content" +version = "1.0.0" +description = "Demonstrates OutlinedButtons with custom content and icon/text composition." +requires-python = ">=3.10" +keywords = ["outlined button", "custom content", "compound button", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Custom content" +controls = ["SafeArea", "OutlinedButton", "Row", "Column", "Icon", "Container", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["custom button content", "compound layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/outlined_button/handling_clicks/main.py b/sdk/python/examples/controls/material/outlined_button/handling_clicks/main.py new file mode 100644 index 0000000000..8cb6d21646 --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/handling_clicks/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_button_click(e: ft.Event[ft.OutlinedButton]): + button.data += 1 + message.value = f"Button clicked {button.data} time(s)" + page.update() + + button = ft.OutlinedButton( + content="Button with 'click' event", + data=0, + on_click=handle_button_click, + ) + message = ft.Text() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[button, message], + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + expand=True, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/outlined_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/material/outlined_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..db34e2728d --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-handling-clicks" +version = "1.0.0" +description = "Demonstrates OutlinedButton click handling with a live counter." +requires-python = ">=3.10" +keywords = ["outlined button", "events", "on_click", "counter", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Handling clicks" +controls = ["SafeArea", "Column", "OutlinedButton", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["click event handling", "dynamic label updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/outlined_button/icons/main.py b/sdk/python/examples/controls/material/outlined_button/icons/main.py new file mode 100644 index 0000000000..733c763310 --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/icons/main.py @@ -0,0 +1,26 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "OutlinedButton Example" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton( + content="Button with icon", icon=ft.Icons.CHAIR_OUTLINED + ), + ft.OutlinedButton( + content="Button with colorful icon", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/outlined_button/icons/pyproject.toml b/sdk/python/examples/controls/material/outlined_button/icons/pyproject.toml new file mode 100644 index 0000000000..bc759a083d --- /dev/null +++ b/sdk/python/examples/controls/material/outlined_button/icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "outlined-button-icons" +version = "1.0.0" +description = "Shows OutlinedButtons with icon and color variations." +requires-python = ">=3.10" +keywords = ["outlined button", "icon button", "material icons", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/OutlinedButton"] + +[tool.flet.metadata] +title = "Icons" +controls = ["SafeArea", "OutlinedButton", "Icon"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["icon support"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/outlined_button/media/adaptive.png b/sdk/python/examples/controls/material/outlined_button/media/adaptive.png new file mode 100644 index 0000000000..6770b5c2e9 Binary files /dev/null and b/sdk/python/examples/controls/material/outlined_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/outlined_button/media/basic.png b/sdk/python/examples/controls/material/outlined_button/media/basic.png new file mode 100644 index 0000000000..50c75fe74a Binary files /dev/null and b/sdk/python/examples/controls/material/outlined_button/media/basic.png differ diff --git a/sdk/python/examples/controls/material/outlined_button/media/custom_content.png b/sdk/python/examples/controls/material/outlined_button/media/custom_content.png new file mode 100644 index 0000000000..4e2fbda4fd Binary files /dev/null and b/sdk/python/examples/controls/material/outlined_button/media/custom_content.png differ diff --git a/sdk/python/examples/controls/material/outlined_button/media/handling_clicks.gif b/sdk/python/examples/controls/material/outlined_button/media/handling_clicks.gif new file mode 100644 index 0000000000..4ce673efa0 Binary files /dev/null and b/sdk/python/examples/controls/material/outlined_button/media/handling_clicks.gif differ diff --git a/sdk/python/examples/controls/material/outlined_button/media/icons.png b/sdk/python/examples/controls/material/outlined_button/media/icons.png new file mode 100644 index 0000000000..b073f977e1 Binary files /dev/null and b/sdk/python/examples/controls/material/outlined_button/media/icons.png differ diff --git a/sdk/python/examples/controls/material/outlined_button/media/index.png b/sdk/python/examples/controls/material/outlined_button/media/index.png new file mode 100644 index 0000000000..dcede8642c Binary files /dev/null and b/sdk/python/examples/controls/material/outlined_button/media/index.png differ diff --git a/sdk/python/examples/controls/material/popup_menu_button/basic/main.py b/sdk/python/examples/controls/material/popup_menu_button/basic/main.py new file mode 100644 index 0000000000..4d2474e8de --- /dev/null +++ b/sdk/python/examples/controls/material/popup_menu_button/basic/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_check_item_click(e: ft.Event[ft.PopupMenuItem]): + e.control.checked = not e.control.checked + + page.add( + ft.SafeArea( + content=ft.PopupMenuButton( + key="popup", + items=[ + ft.PopupMenuItem(content="Item 1"), + ft.PopupMenuItem(icon=ft.Icons.POWER_INPUT, content="Check power"), + ft.PopupMenuItem( + content=ft.Row( + controls=[ + ft.Icon(ft.Icons.HOURGLASS_TOP_OUTLINED), + ft.Text("Item with a custom content"), + ] + ), + on_click=lambda _: print("Button with custom content clicked!"), + ), + ft.PopupMenuItem(), # divider + ft.PopupMenuItem( + content="Checked item", + checked=False, + on_click=handle_check_item_click, + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/popup_menu_button/basic/pyproject.toml b/sdk/python/examples/controls/material/popup_menu_button/basic/pyproject.toml new file mode 100644 index 0000000000..ae70c59181 --- /dev/null +++ b/sdk/python/examples/controls/material/popup_menu_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "popup-menu-button-basic" +version = "1.0.0" +description = "Shows a PopupMenuButton with text, icon, custom content, and checked menu items." +requires-python = ">=3.10" +keywords = ["popup menu", "popup menu button", "menu", "material", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/PopupMenuButton"] + +[tool.flet.metadata] +title = "Basic" +controls = ["PopupMenuButton", "PopupMenuItem", "SafeArea", "Row", "Icon", "Text"] +layout_pattern = "overlay-action" +complexity = "basic" +features = ["menu actions", "custom menu content", "checkable menu item"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/popup_menu_button/media/basic.gif b/sdk/python/examples/controls/material/popup_menu_button/media/basic.gif new file mode 100644 index 0000000000..893f023ee7 Binary files /dev/null and b/sdk/python/examples/controls/material/popup_menu_button/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/popup_menu_button/media/index.gif b/sdk/python/examples/controls/material/popup_menu_button/media/index.gif new file mode 100644 index 0000000000..26a8d3595d Binary files /dev/null and b/sdk/python/examples/controls/material/popup_menu_button/media/index.gif differ diff --git a/sdk/python/examples/controls/material/progress_bar/determinate_and_indeterminate/main.py b/sdk/python/examples/controls/material/progress_bar/determinate_and_indeterminate/main.py new file mode 100644 index 0000000000..fdf4f9ae5a --- /dev/null +++ b/sdk/python/examples/controls/material/progress_bar/determinate_and_indeterminate/main.py @@ -0,0 +1,38 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + determinate_bar = ft.ProgressBar(width=400) + determinate_message = ft.Text("Doing something...") + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Linear progress indicator", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Column(controls=[determinate_message, determinate_bar]), + ft.Text( + value="Indeterminate progress bar", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.ProgressBar(width=400, color=ft.Colors.AMBER), + ] + ) + ) + ) + + for i in range(0, 101): + determinate_bar.value = i * 0.01 + await asyncio.sleep(0.1) + if i == 100: + determinate_message.value = "Finished!" + page.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/progress_bar/determinate_and_indeterminate/pyproject.toml b/sdk/python/examples/controls/material/progress_bar/determinate_and_indeterminate/pyproject.toml new file mode 100644 index 0000000000..89a80866c8 --- /dev/null +++ b/sdk/python/examples/controls/material/progress_bar/determinate_and_indeterminate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "progress-bar-determinate-and-indeterminate" +version = "1.0.0" +description = "Animates a determinate and an indeterminate linear ProgressBar." +requires-python = ">=3.10" +keywords = ["progress bar", "progress", "linear progress", "async", "loading"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressBar"] + +[tool.flet.metadata] +title = "Determinate and Indeterminate" +controls = ["ProgressBar", "SafeArea", "Column", "Text"] +layout_pattern = "status-dashboard" +complexity = "basic" +features = ["linear progress animation", "determinate updates", "indeterminate progress", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/progress_bar/media/determinate_and_indeterminate.gif b/sdk/python/examples/controls/material/progress_bar/media/determinate_and_indeterminate.gif new file mode 100644 index 0000000000..ca79c8d9e8 Binary files /dev/null and b/sdk/python/examples/controls/material/progress_bar/media/determinate_and_indeterminate.gif differ diff --git a/sdk/python/examples/controls/material/progress_ring/determinate_and_indeterminate/main.py b/sdk/python/examples/controls/material/progress_ring/determinate_and_indeterminate/main.py new file mode 100644 index 0000000000..2d8d55d955 --- /dev/null +++ b/sdk/python/examples/controls/material/progress_ring/determinate_and_indeterminate/main.py @@ -0,0 +1,50 @@ +import asyncio + +import flet as ft + + +async def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Circular progress indicator", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Row( + controls=[ + determinate_ring := ft.ProgressRing( + width=16, height=16, stroke_width=2 + ), + determinate_message := ft.Text( + "Wait for the completion..." + ), + ] + ), + ft.Text( + value="Indeterminate circular progress", + theme_style=ft.TextThemeStyle.HEADLINE_SMALL, + ), + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.ProgressRing(), + ft.Text("I'm going to run for ages..."), + ], + ), + ] + ) + ) + ) + + for i in range(0, 101): + determinate_ring.value = i * 0.01 + await asyncio.sleep(0.1) + if i == 100: + determinate_message.value = "Finished!" + page.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/progress_ring/determinate_and_indeterminate/pyproject.toml b/sdk/python/examples/controls/material/progress_ring/determinate_and_indeterminate/pyproject.toml new file mode 100644 index 0000000000..349fd80e13 --- /dev/null +++ b/sdk/python/examples/controls/material/progress_ring/determinate_and_indeterminate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "progress-ring-determinate-and-indeterminate" +version = "1.0.0" +description = "Shows determinate and indeterminate circular progress indicators." +requires-python = ">=3.10" +keywords = ["progress ring", "circular progress", "progress", "async", "loading"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressRing"] + +[tool.flet.metadata] +title = "Determinate and Indeterminate" +controls = ["ProgressRing", "SafeArea", "Column", "Row", "Text"] +layout_pattern = "status-dashboard" +complexity = "basic" +features = ["circular progress animation", "determinate updates", "indeterminate progress", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/progress_ring/gauge_with_progress/main.py b/sdk/python/examples/controls/material/progress_ring/gauge_with_progress/main.py new file mode 100644 index 0000000000..c4debb6670 --- /dev/null +++ b/sdk/python/examples/controls/material/progress_ring/gauge_with_progress/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Stack( + width=100, + height=100, + controls=[ + ft.Container(content=ft.Text("60%"), alignment=ft.Alignment.CENTER), + ft.ProgressRing(value=0.6, width=100, height=100), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/progress_ring/gauge_with_progress/pyproject.toml b/sdk/python/examples/controls/material/progress_ring/gauge_with_progress/pyproject.toml new file mode 100644 index 0000000000..8fe45302f4 --- /dev/null +++ b/sdk/python/examples/controls/material/progress_ring/gauge_with_progress/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "progress-ring-gauge-with-progress" +version = "1.0.0" +description = "Shows a fixed gauge-style ProgressRing with an overlaid percentage label." +requires-python = ">=3.10" +keywords = ["progress ring", "gauge", "circular progress", "static progress"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/ProgressRing"] + +[tool.flet.metadata] +title = "Gauge with Progress" +controls = ["ProgressRing", "SafeArea", "Stack", "Container", "Text"] +layout_pattern = "status-dashboard" +complexity = "basic" +features = ["gauge-style indicator", "overlay text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/progress_ring/media/determinate_and_indeterminate.gif b/sdk/python/examples/controls/material/progress_ring/media/determinate_and_indeterminate.gif new file mode 100644 index 0000000000..a0eea5b793 Binary files /dev/null and b/sdk/python/examples/controls/material/progress_ring/media/determinate_and_indeterminate.gif differ diff --git a/sdk/python/examples/controls/material/radio/basic/main.py b/sdk/python/examples/controls/material/radio/basic/main.py new file mode 100644 index 0000000000..87b9f166ad --- /dev/null +++ b/sdk/python/examples/controls/material/radio/basic/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = f"Your favorite color is: {group.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + group := ft.RadioGroup( + content=ft.Column( + controls=[ + ft.Radio( + key="basic_radio_red", value="red", label="Red" + ), + ft.Radio(value="green", label="Green"), + ft.Radio(value="blue", label="Blue"), + ] + ) + ), + ft.Button( + key="basic_submit_button", + content="Submit", + on_click=handle_button_click, + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/radio/basic/pyproject.toml b/sdk/python/examples/controls/material/radio/basic/pyproject.toml new file mode 100644 index 0000000000..5a4b37129d --- /dev/null +++ b/sdk/python/examples/controls/material/radio/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "radio-basic" +version = "1.0.0" +description = "Shows radio selection with a submit action and simple message display." +requires-python = ">=3.10" +keywords = ["radio", "radio group", "selection", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Radio"] + +[tool.flet.metadata] +title = "Basic" +controls = ["RadioGroup", "Radio", "Button", "Text", "SafeArea"] +layout_pattern = "form" +complexity = "basic" +features = ["radio selection", "form submission"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/radio/handling_selection_changes/main.py b/sdk/python/examples/controls/material/radio/handling_selection_changes/main.py new file mode 100644 index 0000000000..4dbe2cf358 --- /dev/null +++ b/sdk/python/examples/controls/material/radio/handling_selection_changes/main.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_selection_change(e: ft.Event[ft.RadioGroup]): + message.value = f"Your favorite color is: {e.control.value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Select your favorite color:"), + ft.RadioGroup( + on_change=handle_selection_change, + content=ft.Column( + controls=[ + ft.Radio(value="red", label="Red"), + ft.Radio(value="green", label="Green"), + ft.Radio(value="blue", label="Blue"), + ] + ), + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/radio/handling_selection_changes/pyproject.toml b/sdk/python/examples/controls/material/radio/handling_selection_changes/pyproject.toml new file mode 100644 index 0000000000..997042fc58 --- /dev/null +++ b/sdk/python/examples/controls/material/radio/handling_selection_changes/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "radio-handling-selection-changes" +version = "1.0.0" +description = "Shows live RadioGroup selection updates using on_change events." +requires-python = ">=3.10" +keywords = ["radio", "selection changes", "on_change", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Radio"] + +[tool.flet.metadata] +title = "Handling Selection Changes" +controls = ["RadioGroup", "Radio", "Text", "SafeArea"] +layout_pattern = "form" +complexity = "basic" +features = ["selection change handling", "reactive feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/radio/media/basic.gif b/sdk/python/examples/controls/material/radio/media/basic.gif new file mode 100644 index 0000000000..b733d95e46 Binary files /dev/null and b/sdk/python/examples/controls/material/radio/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/radio/media/handling_selection_changes.gif b/sdk/python/examples/controls/material/radio/media/handling_selection_changes.gif new file mode 100644 index 0000000000..871f676fb9 Binary files /dev/null and b/sdk/python/examples/controls/material/radio/media/handling_selection_changes.gif differ diff --git a/sdk/python/examples/controls/material/radio/media/index.png b/sdk/python/examples/controls/material/radio/media/index.png new file mode 100644 index 0000000000..b8e620e3ad Binary files /dev/null and b/sdk/python/examples/controls/material/radio/media/index.png differ diff --git a/sdk/python/examples/controls/material/radio/styled/main.py b/sdk/python/examples/controls/material/radio/styled/main.py new file mode 100644 index 0000000000..8c83c4e0ba --- /dev/null +++ b/sdk/python/examples/controls/material/radio/styled/main.py @@ -0,0 +1,39 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.RadioGroup( + ft.Column( + controls=[ + ft.Radio( + key="styled_radio_default", + label="Radio with default style", + value="1", + ), + ft.Radio( + key="styled_radio_constant", + label="Radio with constant fill color", + value="2", + fill_color=ft.Colors.RED, + ), + ft.Radio( + key="styled_radio_dynamic", + label="Radio with dynamic fill color", + value="3", + fill_color={ + ft.ControlState.HOVERED: ft.Colors.BLUE, + ft.ControlState.SELECTED: ft.Colors.GREEN, + ft.ControlState.DEFAULT: ft.Colors.RED, + }, + ), + ] + ) + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/radio/styled/pyproject.toml b/sdk/python/examples/controls/material/radio/styled/pyproject.toml new file mode 100644 index 0000000000..206a8092f6 --- /dev/null +++ b/sdk/python/examples/controls/material/radio/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "radio-styled" +version = "1.0.0" +description = "Demonstrates styled Radio controls with static and state-based colors." +requires-python = ">=3.10" +keywords = ["radio", "styled controls", "control states", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Radio"] + +[tool.flet.metadata] +title = "Styled" +controls = ["Radio", "RadioGroup", "SafeArea"] +layout_pattern = "form" +complexity = "basic" +features = ["state-based styling", "radio group styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/range_slider/basic/main.py b/sdk/python/examples/controls/material/range_slider/basic/main.py new file mode 100644 index 0000000000..c5512ca934 --- /dev/null +++ b/sdk/python/examples/controls/material/range_slider/basic/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Range slider with divisions and labels", + size=20, + weight=ft.FontWeight.BOLD, + ), + ft.Container(height=30), + ft.RangeSlider( + min=0, + max=50, + start_value=10, + divisions=10, + end_value=20, + inactive_color=ft.Colors.GREEN_300, + active_color=ft.Colors.GREEN_700, + overlay_color=ft.Colors.GREEN_100, + label="{value}", + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/range_slider/basic/pyproject.toml b/sdk/python/examples/controls/material/range_slider/basic/pyproject.toml new file mode 100644 index 0000000000..a51f67b788 --- /dev/null +++ b/sdk/python/examples/controls/material/range_slider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "range-slider-basic" +version = "1.0.0" +description = "Shows a configured RangeSlider with labels and divisions." +requires-python = ">=3.10" +keywords = ["range slider", "slider", "input controls", "selection range"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/RangeSlider"] + +[tool.flet.metadata] +title = "Basic" +controls = ["RangeSlider", "SafeArea", "Text", "Column", "Container"] +layout_pattern = "input-panel" +complexity = "basic" +features = ["range selection", "labeled ranges"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/range_slider/handling_change_events/main.py b/sdk/python/examples/controls/material/range_slider/handling_change_events/main.py new file mode 100644 index 0000000000..44d74e3620 --- /dev/null +++ b/sdk/python/examples/controls/material/range_slider/handling_change_events/main.py @@ -0,0 +1,46 @@ +import flet as ft + + +def main(page: ft.Page): + page.scroll = ft.ScrollMode.AUTO + + def handle_slider_change_start(e: ft.Event[ft.RangeSlider]): + print(f"on_change_start: {e.control.start_value}, {e.control.end_value}") + + def handle_slider_change(e: ft.Event[ft.RangeSlider]): + print(f"on_change: {e.control.start_value}, {e.control.end_value}") + + def handle_slider_change_end(e: ft.Event[ft.RangeSlider]): + print(f"on_change_end: {e.control.start_value}, {e.control.end_value}") + message.value = f"on_change_end: {e.control.start_value}, {e.control.end_value}" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + value="Range slider with events", + size=20, + weight=ft.FontWeight.BOLD, + ), + ft.Container(height=30), + ft.RangeSlider( + divisions=100, + min=0, + max=100, + start_value=10, + end_value=20, + on_change_start=handle_slider_change_start, + on_change=handle_slider_change, + on_change_end=handle_slider_change_end, + label="{value}%", + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/range_slider/handling_change_events/pyproject.toml b/sdk/python/examples/controls/material/range_slider/handling_change_events/pyproject.toml new file mode 100644 index 0000000000..4f02ef78b0 --- /dev/null +++ b/sdk/python/examples/controls/material/range_slider/handling_change_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "range-slider-handling-change-events" +version = "1.0.0" +description = "Shows event callbacks for RangeSlider value changes." +requires-python = ">=3.10" +keywords = ["range slider", "events", "on_change", "async", "input controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/RangeSlider"] + +[tool.flet.metadata] +title = "Handling Change Events" +controls = ["RangeSlider", "SafeArea", "Text", "Column", "Container"] +layout_pattern = "input-panel" +complexity = "basic" +features = ["range change events", "callback updates", "scrollable content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/range_slider/media/basic.gif b/sdk/python/examples/controls/material/range_slider/media/basic.gif new file mode 100644 index 0000000000..b21b0f78c4 Binary files /dev/null and b/sdk/python/examples/controls/material/range_slider/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/reorderable_drag_handle/basic/main.py b/sdk/python/examples/controls/material/reorderable_drag_handle/basic/main.py new file mode 100644 index 0000000000..434be4460b --- /dev/null +++ b/sdk/python/examples/controls/material/reorderable_drag_handle/basic/main.py @@ -0,0 +1,37 @@ +import flet as ft + + +def main(page: ft.Page): + def on_reorder(e: ft.OnReorderEvent): + # Reorder controls list to match the UI change + e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) + + page.add( + ft.SafeArea( + content=ft.ReorderableListView( + expand=True, + show_default_drag_handles=False, + on_reorder=on_reorder, + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), + leading=ft.ReorderableDragHandle( + key=f"drag_handle_{i}", + content=ft.Icon( + ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED + ), + mouse_cursor=ft.MouseCursor.GRAB, + ), + bgcolor=ft.Colors.ERROR + if i % 2 == 0 + else ft.Colors.ON_ERROR_CONTAINER, + ) + for i in range(10) + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/reorderable_drag_handle/basic/pyproject.toml b/sdk/python/examples/controls/material/reorderable_drag_handle/basic/pyproject.toml new file mode 100644 index 0000000000..dc348247ad --- /dev/null +++ b/sdk/python/examples/controls/material/reorderable_drag_handle/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "reorderable-drag-handle-basic" +version = "1.0.0" +description = "Shows a ReorderableListView with custom drag handles." +requires-python = ">=3.10" +keywords = ["reorderable drag handle", "drag handle", "reorderable list"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Reorderable"] + +[tool.flet.metadata] +title = "Basic" +controls = ["ReorderableListView", "ReorderableDragHandle", "ListTile", "SafeArea"] +layout_pattern = "draggable-list" +complexity = "basic" +features = ["custom drag handles", "reorderable list items"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/reorderable_drag_handle/media/basic.gif b/sdk/python/examples/controls/material/reorderable_drag_handle/media/basic.gif new file mode 100644 index 0000000000..1bebc19107 Binary files /dev/null and b/sdk/python/examples/controls/material/reorderable_drag_handle/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/reorderable_list_view/horizontal_and_vertical/main.py b/sdk/python/examples/controls/material/reorderable_list_view/horizontal_and_vertical/main.py new file mode 100644 index 0000000000..13b121a95a --- /dev/null +++ b/sdk/python/examples/controls/material/reorderable_list_view/horizontal_and_vertical/main.py @@ -0,0 +1,57 @@ +import flet as ft + + +def main(page: ft.Page): + # the primary color is the color of the reorder handle + page.theme = page.dark_theme = ft.Theme( + color_scheme=ft.ColorScheme(primary=ft.Colors.BLUE) + ) + + def handle_reorder(e: ft.OnReorderEvent): + # Reorder controls list to match the UI change + e.control.controls.insert(e.new_index, e.control.controls.pop(e.old_index)) + + def get_color(i): + return ft.Colors.ERROR if i % 2 == 0 else ft.Colors.ON_ERROR_CONTAINER + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + [ # horizontal + ft.ReorderableListView( + expand=True, + horizontal=True, + on_reorder=handle_reorder, + controls=[ + ft.Container( + content=ft.Text(f"Item {i}", color=ft.Colors.BLACK), + bgcolor=get_color(i), + margin=ft.Margin.symmetric(horizontal=5, vertical=10), + width=100, + alignment=ft.Alignment.CENTER, + ) + for i in range(10) + ], + ), + # vertical + ft.ReorderableListView( + expand=True, + on_reorder=handle_reorder, + controls=[ + ft.ListTile( + title=ft.Text(f"Item {i}", color=ft.Colors.BLACK), + leading=ft.Icon(ft.Icons.CHECK, color=ft.Colors.RED), + bgcolor=get_color(i), + ) + for i in range(10) + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/reorderable_list_view/media/horizontal_and_vertical.gif b/sdk/python/examples/controls/material/reorderable_list_view/media/horizontal_and_vertical.gif new file mode 100644 index 0000000000..3a2fe62951 Binary files /dev/null and b/sdk/python/examples/controls/material/reorderable_list_view/media/horizontal_and_vertical.gif differ diff --git a/sdk/python/examples/controls/material/search_bar/basic/main.py b/sdk/python/examples/controls/material/search_bar/basic/main.py new file mode 100644 index 0000000000..aabcf48592 --- /dev/null +++ b/sdk/python/examples/controls/material/search_bar/basic/main.py @@ -0,0 +1,59 @@ +import flet as ft + +colors = [ + "Amber", + "Blue Grey", + "Brown", + "Deep Orange", + "Green", + "Light Blue", + "Orange", + "Red", +] + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def build_tiles(items: list[str]) -> list[ft.Control]: + return [ + ft.ListTile( + title=ft.Text(item), + data=item, + on_click=handle_tile_click, + ) + for item in items + ] + + async def handle_tile_click(e: ft.Event[ft.ListTile]): + await anchor.close_view() + + async def handle_change(e: ft.Event[ft.SearchBar]): + query = e.control.value.strip().lower() + matching = ( + [color for color in colors if query in color.lower()] if query else colors + ) + anchor.controls = build_tiles(matching) + + def handle_submit(e: ft.Event[ft.SearchBar]): + print(f"Submit: {e.data}") + + async def handle_tap(e: ft.Event[ft.SearchBar]): + await anchor.open_view() + + anchor = ft.SearchBar( + view_elevation=4, + divider_color=ft.Colors.AMBER, + bar_hint_text="Search colors...", + view_hint_text="Choose a color from the suggestions...", + on_change=handle_change, + on_submit=handle_submit, + on_tap=handle_tap, + controls=build_tiles(colors), + ) + + page.add(ft.SafeArea(content=anchor)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/search_bar/basic/pyproject.toml b/sdk/python/examples/controls/material/search_bar/basic/pyproject.toml new file mode 100644 index 0000000000..12aa2fd6ad --- /dev/null +++ b/sdk/python/examples/controls/material/search_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "search-bar-basic" +version = "1.0.0" +description = "Search colors with async suggestions shown inside a SearchBar view." +requires-python = ">=3.10" +keywords = ["searchbar", "search", "suggestions", "listtile", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/SearchBar"] + +[tool.flet.metadata] +title = "SearchBar basic" +controls = ["SearchBar", "ListTile", "Text", "SafeArea"] +layout_pattern = "search-overlay" +complexity = "basic" +features = ["async suggestions", "live filtering", "search submit"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/search_bar/media/basic.gif b/sdk/python/examples/controls/material/search_bar/media/basic.gif new file mode 100644 index 0000000000..5b4623cd48 Binary files /dev/null and b/sdk/python/examples/controls/material/search_bar/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/segmented_button/media/basic.gif b/sdk/python/examples/controls/material/segmented_button/media/basic.gif new file mode 100644 index 0000000000..3f1d5e3b0b Binary files /dev/null and b/sdk/python/examples/controls/material/segmented_button/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/segmented_button/single_multiple_selection/main.py b/sdk/python/examples/controls/material/segmented_button/single_multiple_selection/main.py new file mode 100644 index 0000000000..f0dd892d73 --- /dev/null +++ b/sdk/python/examples/controls/material/segmented_button/single_multiple_selection/main.py @@ -0,0 +1,76 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_selection_change(e: ft.Event[ft.SegmentedButton]): + print(e) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.SegmentedButton( + on_change=handle_selection_change, + selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), + selected=["1", "4"], + allow_empty_selection=True, + allow_multiple_selection=True, + segments=[ + ft.Segment( + value="1", + label=ft.Text("One"), + icon=ft.Icon(ft.Icons.LOOKS_ONE), + ), + ft.Segment( + value="2", + label=ft.Text("Two"), + icon=ft.Icon(ft.Icons.LOOKS_TWO), + ), + ft.Segment( + value="3", + label=ft.Text("Three"), + icon=ft.Icon(ft.Icons.LOOKS_3), + ), + ft.Segment( + value="4", + label=ft.Text("Four"), + icon=ft.Icon(ft.Icons.LOOKS_4), + ), + ], + ), + ft.SegmentedButton( + on_change=handle_selection_change, + selected_icon=ft.Icon(ft.Icons.CHECK_SHARP), + selected=["2"], + allow_multiple_selection=False, + segments=[ + ft.Segment( + value="1", + label=ft.Text("One"), + icon=ft.Icon(ft.Icons.LOOKS_ONE), + ), + ft.Segment( + value="2", + label=ft.Text("Two"), + icon=ft.Icon(ft.Icons.LOOKS_TWO), + ), + ft.Segment( + value="3", + label=ft.Text("Three"), + icon=ft.Icon(ft.Icons.LOOKS_3), + ), + ft.Segment( + value="4", + label=ft.Text("Four"), + icon=ft.Icon(ft.Icons.LOOKS_4), + ), + ], + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/segmented_button/single_multiple_selection/pyproject.toml b/sdk/python/examples/controls/material/segmented_button/single_multiple_selection/pyproject.toml new file mode 100644 index 0000000000..26195e36e7 --- /dev/null +++ b/sdk/python/examples/controls/material/segmented_button/single_multiple_selection/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "segmented-button-single-multiple-selection" +version = "1.0.0" +description = "Compare single and multiple selection behavior with SegmentedButton." +requires-python = ">=3.10" +keywords = ["segmentedbutton", "selection", "multiple", "single", "icons"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/SegmentedButton"] + +[tool.flet.metadata] +title = "SegmentedButton single and multiple selection" +controls = ["SegmentedButton", "Segment", "Icon", "Text", "Column", "SafeArea"] +layout_pattern = "comparison-stack" +complexity = "basic" +features = ["single selection", "multiple selection", "selection change"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/selection_area/basic/main.py b/sdk/python/examples/controls/material/selection_area/basic/main.py new file mode 100644 index 0000000000..8349f9d283 --- /dev/null +++ b/sdk/python/examples/controls/material/selection_area/basic/main.py @@ -0,0 +1,48 @@ +import flet as ft + +TEXT_STYLE = ft.TextStyle( + size=22, + weight=ft.FontWeight.W_600, + decoration=ft.TextDecoration( + ft.TextDecoration.UNDERLINE | ft.TextDecoration.OVERLINE + ), + decoration_style=ft.TextDecorationStyle.WAVY, +) + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.SelectionArea( + content=ft.Column( + controls=[ + ft.Text( + "Selectable text", + color=ft.Colors.GREEN, + style=TEXT_STYLE, + key="selectable", + ), + ft.Text( + "Also selectable", + color=ft.Colors.GREEN, + style=TEXT_STYLE, + ), + ] + ) + ), + ft.Text( + "Not selectable", + color=ft.Colors.RED, + style=TEXT_STYLE, + key="non-selectable", + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/selection_area/basic/pyproject.toml b/sdk/python/examples/controls/material/selection_area/basic/pyproject.toml new file mode 100644 index 0000000000..586ad28711 --- /dev/null +++ b/sdk/python/examples/controls/material/selection_area/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "selection-area-basic" +version = "1.0.0" +description = "Compare selectable and non-selectable text using a SelectionArea wrapper." +requires-python = ">=3.10" +keywords = ["selectionarea", "text", "selection", "typography"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/SelectionArea"] + +[tool.flet.metadata] +title = "SelectionArea basic" +controls = ["SelectionArea", "Column", "Text", "SafeArea"] +layout_pattern = "comparison-stack" +complexity = "basic" +features = ["text selection", "selectable content", "styled text"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/selection_area/media/basic.gif b/sdk/python/examples/controls/material/selection_area/media/basic.gif new file mode 100644 index 0000000000..cfa38e94a9 Binary files /dev/null and b/sdk/python/examples/controls/material/selection_area/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/slider/basic/main.py b/sdk/python/examples/controls/material/slider/basic/main.py new file mode 100644 index 0000000000..a0e344977e --- /dev/null +++ b/sdk/python/examples/controls/material/slider/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Default slider:"), + ft.Slider(), + ft.Text("Default disabled slider:"), + ft.Slider(disabled=True), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/slider/basic/pyproject.toml b/sdk/python/examples/controls/material/slider/basic/pyproject.toml new file mode 100644 index 0000000000..fc7205e833 --- /dev/null +++ b/sdk/python/examples/controls/material/slider/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-basic" +version = "1.0.0" +description = "Compare enabled and disabled Slider controls with the default settings." +requires-python = ">=3.10" +keywords = ["slider", "input", "disabled", "basic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider basic" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/slider/custom_label/main.py b/sdk/python/examples/controls/material/slider/custom_label/main.py new file mode 100644 index 0000000000..f9899ba202 --- /dev/null +++ b/sdk/python/examples/controls/material/slider/custom_label/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Slider with value:"), + ft.Slider(value=0.3), + ft.Text("Slider with a custom range and label:"), + ft.Slider(min=0, max=100, divisions=10, label="{value}%"), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/slider/custom_label/pyproject.toml b/sdk/python/examples/controls/material/slider/custom_label/pyproject.toml new file mode 100644 index 0000000000..d056ba6632 --- /dev/null +++ b/sdk/python/examples/controls/material/slider/custom_label/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-custom-label" +version = "1.0.0" +description = "Show Slider values with a preset position and a custom percentage label." +requires-python = ">=3.10" +keywords = ["slider", "label", "divisions", "range"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider custom label" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["custom label", "custom range", "divisions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/slider/handling_events/main.py b/sdk/python/examples/controls/material/slider/handling_events/main.py new file mode 100644 index 0000000000..ef9aaa4f7a --- /dev/null +++ b/sdk/python/examples/controls/material/slider/handling_events/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + def slider_changed(e: ft.Event[ft.Slider]): + message.value = f"Slider changed to {e.control.value}" + message.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Slider with 'on_change' event:"), + ft.Slider( + key="slider", + min=0, + max=100, + divisions=10, + label="{value}%", + on_change=slider_changed, + ), + message := ft.Text(), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/slider/handling_events/pyproject.toml b/sdk/python/examples/controls/material/slider/handling_events/pyproject.toml new file mode 100644 index 0000000000..089cc264e5 --- /dev/null +++ b/sdk/python/examples/controls/material/slider/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-handling-events" +version = "1.0.0" +description = "Update a text label live when a Slider value changes." +requires-python = ">=3.10" +keywords = ["slider", "events", "on_change", "text"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider handling events" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["value change handling", "live updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/slider/media/random_values.gif b/sdk/python/examples/controls/material/slider/media/random_values.gif new file mode 100644 index 0000000000..0f358371ba Binary files /dev/null and b/sdk/python/examples/controls/material/slider/media/random_values.gif differ diff --git a/sdk/python/examples/controls/material/slider/random_values/main.py b/sdk/python/examples/controls/material/slider/random_values/main.py new file mode 100644 index 0000000000..4a325aff2c --- /dev/null +++ b/sdk/python/examples/controls/material/slider/random_values/main.py @@ -0,0 +1,35 @@ +import asyncio +import random + +import flet as ft + + +async def main(page: ft.Page): + def handle_slider_change(e: ft.Event[ft.Slider]): + message.value = f"Slider.value changed to {e.control.value}" + message.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Slider with 'on_change' event:"), + slider := ft.Slider( + label="{value}", on_change=handle_slider_change + ), + message := ft.Text(), + ] + ) + ) + ) + + while True: + await asyncio.sleep(1) + slider.value = random.random() + event = ft.Event("_", slider, data=slider.value) + handle_slider_change(event) + slider.update() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/slider/random_values/pyproject.toml b/sdk/python/examples/controls/material/slider/random_values/pyproject.toml new file mode 100644 index 0000000000..18847f2766 --- /dev/null +++ b/sdk/python/examples/controls/material/slider/random_values/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "slider-random-values" +version = "1.0.0" +description = "Animate a Slider with random values and mirror each update in a text label." +requires-python = ">=3.10" +keywords = ["slider", "random", "animation", "events", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Slider"] + +[tool.flet.metadata] +title = "Slider random values" +controls = ["Slider", "Text", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["async updates", "random values", "live updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/snack_bar/action/main.py b/sdk/python/examples/controls/material/snack_bar/action/main.py new file mode 100644 index 0000000000..73925c694c --- /dev/null +++ b/sdk/python/examples/controls/material/snack_bar/action/main.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + def open_simple_action(e: ft.Event[ft.Button]): + page.show_dialog( + ft.SnackBar( + ft.Text("The file has been deleted."), + action="Undo", + on_action=lambda e: print("Simple Undo clicked"), + ) + ) + + def open_custom_action(e: ft.Event[ft.Button]): + page.show_dialog( + ft.SnackBar( + ft.Text("The directory has been deleted."), + persist=False, + action=ft.SnackBarAction( + label="Undo delete", + text_color=ft.Colors.YELLOW, + bgcolor=ft.Colors.BLUE, + on_click=lambda e: print("Custom Undo clicked"), + ), + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Open SnackBar with a Simple action", + on_click=open_simple_action, + ), + ft.Button( + "Open SnackBar with a Custom action", + on_click=open_custom_action, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/snack_bar/action/pyproject.toml b/sdk/python/examples/controls/material/snack_bar/action/pyproject.toml new file mode 100644 index 0000000000..d02f8e012b --- /dev/null +++ b/sdk/python/examples/controls/material/snack_bar/action/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "snack-bar-action" +version = "1.0.0" +description = "Compare simple and custom SnackBar actions opened from separate buttons." +requires-python = ">=3.10" +keywords = ["snackbar", "action", "button", "feedback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/SnackBar"] + +[tool.flet.metadata] +title = "SnackBar action" +controls = ["SnackBar", "SnackBarAction", "Button", "Column", "SafeArea"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["simple action", "custom action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/snack_bar/basic/main.py b/sdk/python/examples/controls/material/snack_bar/basic/main.py new file mode 100644 index 0000000000..01a5947ad2 --- /dev/null +++ b/sdk/python/examples/controls/material/snack_bar/basic/main.py @@ -0,0 +1,12 @@ +import flet as ft + + +def main(page: ft.Page): + def on_click(e: ft.Event[ft.Button]): + page.show_dialog(ft.SnackBar(ft.Text("Hello, world!"))) + + page.add(ft.SafeArea(content=ft.Button("Open SnackBar", on_click=on_click))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/snack_bar/basic/pyproject.toml b/sdk/python/examples/controls/material/snack_bar/basic/pyproject.toml new file mode 100644 index 0000000000..935c517c00 --- /dev/null +++ b/sdk/python/examples/controls/material/snack_bar/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "snack-bar-basic" +version = "1.0.0" +description = "Open a basic SnackBar from a button tap." +requires-python = ">=3.10" +keywords = ["snackbar", "dialog", "button", "feedback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/SnackBar"] + +[tool.flet.metadata] +title = "SnackBar basic" +controls = ["SnackBar", "Button", "Text", "SafeArea"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog open"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/snack_bar/counter/main.py b/sdk/python/examples/controls/material/snack_bar/counter/main.py new file mode 100644 index 0000000000..6b527d8518 --- /dev/null +++ b/sdk/python/examples/controls/material/snack_bar/counter/main.py @@ -0,0 +1,40 @@ +import flet as ft + + +class Data: + def __init__(self) -> None: + self.counter = 0 + + def increment(self): + self.counter += 1 + + def decrement(self): + self.counter -= 1 + + +data = Data() + + +def main(page: ft.Page): + page.title = "SnackBar Example" + + snack_bar = ft.SnackBar( + content=ft.Text("You did it!"), + action="Undo it!", + on_action=lambda e: data.decrement(), + ) + + def handle_button_click(e: ft.Event[ft.Button]): + data.increment() + snack_bar.content.value = f"You did it x {data.counter}" + if not snack_bar.open: + page.show_dialog(snack_bar) + page.update() + + page.add( + ft.SafeArea(content=ft.Button("Open SnackBar", on_click=handle_button_click)) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/snack_bar/counter/pyproject.toml b/sdk/python/examples/controls/material/snack_bar/counter/pyproject.toml new file mode 100644 index 0000000000..801708e796 --- /dev/null +++ b/sdk/python/examples/controls/material/snack_bar/counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "snack-bar-counter" +version = "1.0.0" +description = "Count repeated SnackBar opens and support undoing the latest increment." +requires-python = ">=3.10" +keywords = ["snackbar", "counter", "undo", "feedback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/SnackBar"] + +[tool.flet.metadata] +title = "SnackBar counter" +controls = ["SnackBar", "Button", "Text", "SafeArea"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["counter updates", "undo action"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/snack_bar/media/basic.gif b/sdk/python/examples/controls/material/snack_bar/media/basic.gif new file mode 100644 index 0000000000..03bcca3280 Binary files /dev/null and b/sdk/python/examples/controls/material/snack_bar/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/submenu_button/basic/main.py b/sdk/python/examples/controls/material/submenu_button/basic/main.py new file mode 100644 index 0000000000..ab6e627de2 --- /dev/null +++ b/sdk/python/examples/controls/material/submenu_button/basic/main.py @@ -0,0 +1,141 @@ +import flet as ft + + +def main(page: ft.Page): + page.padding = 0 + page.spacing = 0 + + def handle_color_click(e: ft.Event[ft.MenuItemButton]): + color = e.control.content.value + background_container.content.value = f"{color} background color" + background_container.bgcolor = color.lower() + + def handle_alignment_click(e: ft.Event[ft.MenuItemButton]): + background_container.alignment = e.control.data + + def handle_on_hover(e: ft.Event[ft.MenuItemButton]): + print(f"{e.control.content.value}.on_hover") + + menubar = ft.MenuBar( + expand=True, + controls=[ + ft.SubmenuButton( + content=ft.Text("Change Body"), + key="submenubutton", + controls=[ + ft.SubmenuButton( + content=ft.Text("BG Color"), + leading=ft.Icon(ft.Icons.COLORIZE), + controls=[ + ft.MenuItemButton( + content=ft.Text("Blue"), + on_click=handle_color_click, + on_hover=handle_on_hover, + style=ft.ButtonStyle( + bgcolor={ft.ControlState.HOVERED: ft.Colors.BLUE} + ), + ), + ft.MenuItemButton( + content=ft.Text("Green"), + on_click=handle_color_click, + on_hover=handle_on_hover, + style=ft.ButtonStyle( + bgcolor={ft.ControlState.HOVERED: ft.Colors.GREEN} + ), + ), + ft.MenuItemButton( + content=ft.Text("Red"), + on_click=handle_color_click, + on_hover=handle_on_hover, + style=ft.ButtonStyle( + bgcolor={ft.ControlState.HOVERED: ft.Colors.RED} + ), + ), + ], + ), + ft.SubmenuButton( + content=ft.Text("Text alignment"), + leading=ft.Icon(ft.Icons.LOCATION_PIN), + controls=[ + ft.MenuItemButton( + content=ft.Text("bottom_center"), + data=ft.Alignment.BOTTOM_CENTER, + on_click=handle_alignment_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ft.Colors.GREY_100 + } + ), + ), + ft.MenuItemButton( + content=ft.Text("bottom_left"), + data=ft.Alignment.BOTTOM_LEFT, + on_click=handle_alignment_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ft.Colors.GREY_100 + } + ), + ), + ft.MenuItemButton( + content=ft.Text("top_center"), + data=ft.Alignment.TOP_CENTER, + on_click=handle_alignment_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ft.Colors.GREY_100 + } + ), + ), + ft.MenuItemButton( + content=ft.Text("center_left"), + data=ft.Alignment.CENTER_LEFT, + on_click=handle_alignment_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ft.Colors.GREY_100 + } + ), + ), + ft.MenuItemButton( + content=ft.Text("center_right"), + data=ft.Alignment.CENTER_RIGHT, + on_click=handle_alignment_click, + style=ft.ButtonStyle( + bgcolor={ + ft.ControlState.HOVERED: ft.Colors.GREY_100 + } + ), + ), + ], + ), + ], + ) + ], + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + spacing=0, + controls=[ + ft.Row(controls=[menubar]), + background_container := ft.Container( + expand=True, + bgcolor=ft.Colors.SURFACE_TINT, + alignment=ft.Alignment.CENTER, + content=ft.Text( + value="Choose a bgcolor from the menu", + style=ft.TextStyle(size=24, weight=ft.FontWeight.BOLD), + ), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/submenu_button/basic/pyproject.toml b/sdk/python/examples/controls/material/submenu_button/basic/pyproject.toml new file mode 100644 index 0000000000..43a34f8d99 --- /dev/null +++ b/sdk/python/examples/controls/material/submenu_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "submenu-button-basic" +version = "1.0.0" +description = "Changes background color and text alignment from nested SubmenuButton menu actions." +requires-python = ">=3.10" +keywords = ["submenu button", "menu", "nested", "alignment", "color"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/SubmenuButton"] + +[tool.flet.metadata] +title = "SubmenuButton basic" +controls = ["SafeArea", "Column", "Row", "MenuBar", "SubmenuButton", "MenuItemButton", "Container", "Text", "Icon"] +layout_pattern = "toolbar-content" +complexity = "basic" +features = ["nested menus", "live style updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/submenu_button/media/basic.gif b/sdk/python/examples/controls/material/submenu_button/media/basic.gif new file mode 100644 index 0000000000..c1579e183f Binary files /dev/null and b/sdk/python/examples/controls/material/submenu_button/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/submenu_button/media/standalone.gif b/sdk/python/examples/controls/material/submenu_button/media/standalone.gif new file mode 100644 index 0000000000..fd8efd29c5 Binary files /dev/null and b/sdk/python/examples/controls/material/submenu_button/media/standalone.gif differ diff --git a/sdk/python/examples/controls/material/submenu_button/standalone/main.py b/sdk/python/examples/controls/material/submenu_button/standalone/main.py new file mode 100644 index 0000000000..f847b06ef6 --- /dev/null +++ b/sdk/python/examples/controls/material/submenu_button/standalone/main.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + smb = ft.SubmenuButton( + expand=True, + content=ft.Text("Text Styles"), + key="smbutton", + menu_style=ft.MenuStyle( + alignment=ft.Alignment.CENTER_RIGHT, side=ft.BorderSide(1) + ), + controls=[ + ft.MenuItemButton( + content=ft.Text("Underlined"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + style=ft.ButtonStyle( + text_style={ + ft.ControlState.HOVERED: ft.TextStyle( + decoration=ft.TextDecoration.UNDERLINE + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Bold"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + style=ft.ButtonStyle( + text_style={ + ft.ControlState.HOVERED: ft.TextStyle(weight=ft.FontWeight.BOLD) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Italic"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + style=ft.ButtonStyle( + text_style={ft.ControlState.HOVERED: ft.TextStyle(italic=True)} + ), + ), + ], + ) + + page.add( + ft.SafeArea( + content=ft.Row(controls=[smb]), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/submenu_button/standalone/pyproject.toml b/sdk/python/examples/controls/material/submenu_button/standalone/pyproject.toml new file mode 100644 index 0000000000..a48b321cf5 --- /dev/null +++ b/sdk/python/examples/controls/material/submenu_button/standalone/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "submenu-button-standalone" +version = "1.0.0" +description = "Shows a standalone SubmenuButton with hover-driven text style previews." +requires-python = ">=3.10" +keywords = ["submenu button", "menu", "text style", "hover", "standalone"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Navigation/SubmenuButton"] + +[tool.flet.metadata] +title = "Standalone SubmenuButton" +controls = ["SafeArea", "Row", "SubmenuButton", "MenuItemButton", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["hover styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/switch/basic/main.py b/sdk/python/examples/controls/material/switch/basic/main.py new file mode 100644 index 0000000000..e559bcdea2 --- /dev/null +++ b/sdk/python/examples/controls/material/switch/basic/main.py @@ -0,0 +1,30 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + f"Switch values are: {c1.value}, {c2.value}, {c3.value}, {c4.value}." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + c1 := ft.Switch(label="Unchecked switch", value=False), + c2 := ft.Switch(label="Checked switch", value=True), + c3 := ft.Switch(label="Disabled switch", disabled=True), + c4 := ft.Switch( + label="Switch with rendered label_position='left'", + label_position=ft.LabelPosition.LEFT, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/switch/basic/pyproject.toml b/sdk/python/examples/controls/material/switch/basic/pyproject.toml new file mode 100644 index 0000000000..2e517dff88 --- /dev/null +++ b/sdk/python/examples/controls/material/switch/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "switch-basic" +version = "1.0.0" +description = "Compares checked, unchecked, disabled, and left-labeled Switch controls and reports their values." +requires-python = ">=3.10" +keywords = ["switch", "input", "states", "button", "label"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Switch"] + +[tool.flet.metadata] +title = "Switch basic" +controls = ["SafeArea", "Column", "Switch", "Button", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["multiple states", "value summary"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/switch/handling_events/main.py b/sdk/python/examples/controls/material/switch/handling_events/main.py new file mode 100644 index 0000000000..e302d2f3bb --- /dev/null +++ b/sdk/python/examples/controls/material/switch/handling_events/main.py @@ -0,0 +1,26 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_switch_change(e: ft.Event[ft.Switch]): + page.theme_mode = ft.ThemeMode.DARK if e.control.value else ft.ThemeMode.LIGHT + e.control.label = ( + "Light ThemeMode" + if page.theme_mode == ft.ThemeMode.LIGHT + else "Dark ThemeMode" + ) + + page.theme_mode = ft.ThemeMode.LIGHT + page.add( + ft.SafeArea( + content=ft.Switch( + key="theme_mode_switch", + label="Light ThemeMode", + on_change=handle_switch_change, + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/switch/handling_events/pyproject.toml b/sdk/python/examples/controls/material/switch/handling_events/pyproject.toml new file mode 100644 index 0000000000..45ce19a929 --- /dev/null +++ b/sdk/python/examples/controls/material/switch/handling_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "switch-handling-events" +version = "1.0.0" +description = "Toggles page theme mode and updates the label when a Switch value changes." +requires-python = ">=3.10" +keywords = ["switch", "events", "theme", "toggle", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/Switch"] + +[tool.flet.metadata] +title = "Handling events" +controls = ["SafeArea", "Switch"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["change events", "theme toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/switch/media/basic.gif b/sdk/python/examples/controls/material/switch/media/basic.gif new file mode 100644 index 0000000000..a623f8b4ab Binary files /dev/null and b/sdk/python/examples/controls/material/switch/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/switch/media/handling_events.gif b/sdk/python/examples/controls/material/switch/media/handling_events.gif new file mode 100644 index 0000000000..a3587440e2 Binary files /dev/null and b/sdk/python/examples/controls/material/switch/media/handling_events.gif differ diff --git a/sdk/python/examples/controls/material/switch/media/index.png b/sdk/python/examples/controls/material/switch/media/index.png new file mode 100644 index 0000000000..8f2057d6e6 Binary files /dev/null and b/sdk/python/examples/controls/material/switch/media/index.png differ diff --git a/sdk/python/examples/controls/material/tabs/basic/main.py b/sdk/python/examples/controls/material/tabs/basic/main.py new file mode 100644 index 0000000000..dcca9fd589 --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/basic/main.py @@ -0,0 +1,51 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + selected_index=1, + length=3, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Tab 1", icon=ft.Icons.SETTINGS_PHONE), + ft.Tab(label="Tab 2", icon=ft.Icons.SETTINGS), + ft.Tab( + label=ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/102273996?s=200&v=4", + ), + ), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 1"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 2"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 3"), + ), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/tabs/basic/pyproject.toml b/sdk/python/examples/controls/material/tabs/basic/pyproject.toml new file mode 100644 index 0000000000..ce99e923ec --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-basic" +version = "1.0.0" +description = "Displays a basic Tabs layout with icons, an avatar tab label, and matching tab content." +requires-python = ">=3.10" +keywords = ["tabs", "navigation", "icons", "avatar", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Tabs basic" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Container", "Text", "CircleAvatar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["icon tabs", "avatar tab label"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/tabs/custom_indicator/main.py b/sdk/python/examples/controls/material/tabs/custom_indicator/main.py new file mode 100644 index 0000000000..937e794a74 --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/custom_indicator/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tab_alignment=ft.TabAlignment.START, + indicator_animation=ft.TabIndicatorAnimation.ELASTIC, + indicator_size=ft.TabBarIndicatorSize.LABEL, + indicator=ft.UnderlineTabIndicator( + border_side=ft.BorderSide(5, color=ft.Colors.RED), + border_radius=ft.BorderRadius.all(1), + insets=ft.Padding.only(bottom=5), + ), + tabs=[ + ft.Tab(label=ft.Text("Home")), + ft.Tab(label=ft.Text("My Account")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Home Tab Content"), + ft.Text("Profile Tab Content"), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/tabs/custom_indicator/pyproject.toml b/sdk/python/examples/controls/material/tabs/custom_indicator/pyproject.toml new file mode 100644 index 0000000000..881c26f48a --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/custom_indicator/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-custom-indicator" +version = "1.0.0" +description = "Customizes the tab underline indicator with elastic animation, rounded corners, and insets." +requires-python = ">=3.10" +keywords = ["tabs", "indicator", "underline", "animation", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Custom tab indicator" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Text", "UnderlineTabIndicator"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom indicator", "elastic indicator animation"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/tabs/dynamic_tab_addition/main.py b/sdk/python/examples/controls/material/tabs/dynamic_tab_addition/main.py new file mode 100644 index 0000000000..2377a757fe --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/dynamic_tab_addition/main.py @@ -0,0 +1,65 @@ +import flet as ft + + +@ft.control +class MyContainer(ft.Container): + text: str = "" + height: int = 100 + alignment: ft.Alignment = ft.Alignment.CENTER + + def init(self): + self.bgcolor = ft.Colors.random() + self.content = ft.Text(self.text) + + +def main(page: ft.Page): + def handle_new_tab(e: ft.Event[ft.CupertinoFilledButton]): + tab_count = len(tab_bar.tabs) + 1 + tab_bar.tabs.append(ft.Tab(label=ft.Text(f"Tab {tab_count}"))) + tab_view.controls.append(MyContainer(text=f"Tab {tab_count} content")) + tabs.length = len(tab_bar.tabs) + + tabs = ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + tab_bar := ft.TabBar( + tab_alignment=ft.TabAlignment.CENTER, + tabs=[ + ft.Tab(label=ft.Text("Tab 1")), + ft.Tab(label=ft.Text("Tab 2")), + ], + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.CupertinoFilledButton( + content="Add New Tab", + icon=ft.Icons.ADD, + on_click=handle_new_tab, + ), + ], + ), + tab_view := ft.TabBarView( + expand=True, + controls=[ + MyContainer(text="Tab 1 content"), + MyContainer(text="Tab 2 content"), + ], + ), + ], + ), + ) + + page.add( + ft.SafeArea( + expand=True, + content=tabs, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/tabs/dynamic_tab_addition/pyproject.toml b/sdk/python/examples/controls/material/tabs/dynamic_tab_addition/pyproject.toml new file mode 100644 index 0000000000..6677164a2b --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/dynamic_tab_addition/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-dynamic-tab-addition" +version = "1.0.0" +description = "Adds new tabs and matching content panels dynamically from a button click." +requires-python = ">=3.10" +keywords = ["tabs", "dynamic", "add tab", "button", "state"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Dynamic tab addition" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Row", "CupertinoFilledButton", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["dynamic tabs", "button-driven updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/tabs/media/basic.gif b/sdk/python/examples/controls/material/tabs/media/basic.gif new file mode 100644 index 0000000000..f49ce72451 Binary files /dev/null and b/sdk/python/examples/controls/material/tabs/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/tabs/move_to/main.py b/sdk/python/examples/controls/material/tabs/move_to/main.py new file mode 100644 index 0000000000..c8b961e0e7 --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/move_to/main.py @@ -0,0 +1,78 @@ +import random + +import flet as ft + + +def main(page: ft.Page): + async def handle_move_to_random(e: ft.Event[ft.FloatingActionButton]): + # random index, excluding the current one + i = random.choice([i for i in range(tabs.length) if i != tabs.selected_index]) + + await tabs.move_to( + index=i, + animation_curve=ft.AnimationCurve.FAST_OUT_SLOWIN, + animation_duration=ft.Duration(seconds=3), + ) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.MOVE_UP, + content="Move to a random tab", + on_click=handle_move_to_random, + ) + + tabs = ft.Tabs( + length=6, + selected_index=5, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tab_alignment=ft.TabAlignment.CENTER, + tabs=[ + ft.Tab(label=ft.Text("Tab 1")), + ft.Tab(label=ft.Text("Tab 2")), + ft.Tab(label=ft.Text("Tab 3")), + ft.Tab(label=ft.Text("Tab 4")), + ft.Tab(label=ft.Text("Tab 5")), + ft.Tab(label=ft.Text("Tab 6")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 1 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 2 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 3 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 4 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 5 content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Tab 6 content"), + ), + ], + ), + ], + ), + ) + + page.add(ft.SafeArea(expand=True, content=tabs)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/tabs/move_to/pyproject.toml b/sdk/python/examples/controls/material/tabs/move_to/pyproject.toml new file mode 100644 index 0000000000..c975d28d7c --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/move_to/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-move-to" +version = "1.0.0" +description = "Animates programmatic tab switching to a random tab using Tabs.move_to." +requires-python = ">=3.10" +keywords = ["tabs", "move_to", "animation", "async", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Programmatic tab switch" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "FloatingActionButton", "Container", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic tab switching", "animated transitions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/tabs/nested/main.py b/sdk/python/examples/controls/material/tabs/nested/main.py new file mode 100644 index 0000000000..3bf34173eb --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/nested/main.py @@ -0,0 +1,58 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ft.Tabs( + length=2, + selected_index=1, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label=ft.Text("Main Tab 1")), + ft.Tab(label=ft.Text("Main Tab 2")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Main Tab 1 content"), + ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + secondary=True, + tabs=[ + ft.Tab(label=ft.Text("SubTab 1")), + ft.Tab(label=ft.Text("SubTab 2")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Nested Tab 1 content"), + ft.Text("Nested Tab 2 content"), + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/tabs/nested/pyproject.toml b/sdk/python/examples/controls/material/tabs/nested/pyproject.toml new file mode 100644 index 0000000000..c0278892dc --- /dev/null +++ b/sdk/python/examples/controls/material/tabs/nested/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tabs-nested" +version = "1.0.0" +description = "Embeds a secondary Tabs control inside a parent tab to demonstrate nested navigation." +requires-python = ">=3.10" +keywords = ["tabs", "nested", "secondary", "navigation", "layout"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/Tabs"] + +[tool.flet.metadata] +title = "Nested tabs" +controls = ["SafeArea", "Tabs", "Column", "TabBar", "TabBarView", "Tab", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["nested tabs", "secondary tab bar"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_button/basic/main.py b/sdk/python/examples/controls/material/text_button/basic/main.py new file mode 100644 index 0000000000..b9f8c11117 --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/basic/main.py @@ -0,0 +1,20 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Basic text buttons" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextButton(content="Text button"), + ft.TextButton(content="Disabled button", disabled=True), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_button/basic/pyproject.toml b/sdk/python/examples/controls/material/text_button/basic/pyproject.toml new file mode 100644 index 0000000000..aa5b7a2bb7 --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-basic" +version = "1.0.0" +description = "Shows enabled and disabled TextButton controls with the default appearance." +requires-python = ">=3.10" +keywords = ["text button", "button", "disabled", "basic", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton basic" +controls = ["SafeArea", "Column", "TextButton"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["enabled and disabled states"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_button/custom_content/main.py b/sdk/python/examples/controls/material/text_button/custom_content/main.py new file mode 100644 index 0000000000..82642c013e --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/custom_content/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "TextButtons with custom content" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextButton( + width=150, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PINK), + ft.Icon(ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN), + ft.Icon(ft.Icons.BEACH_ACCESS, color=ft.Colors.BLUE), + ], + ), + ), + ft.TextButton( + content=ft.Container( + padding=ft.Padding.all(10), + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + spacing=5, + controls=[ + ft.Text(value="Compound button", size=20), + ft.Text(value="This is secondary text"), + ], + ), + ), + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_button/custom_content/pyproject.toml b/sdk/python/examples/controls/material/text_button/custom_content/pyproject.toml new file mode 100644 index 0000000000..57fdaafae0 --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/custom_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-custom-content" +version = "1.0.0" +description = "Builds TextButton controls with rows of icons and compound multi-line content." +requires-python = ">=3.10" +keywords = ["text button", "custom content", "icons", "compound", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton custom content" +controls = ["SafeArea", "Column", "TextButton", "Row", "Container", "Column", "Icon", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["custom button content", "compound button layout"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_button/handling_clicks/main.py b/sdk/python/examples/controls/material/text_button/handling_clicks/main.py new file mode 100644 index 0000000000..1e8cb47b9d --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/handling_clicks/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "TextButton with 'click' event" + + def button_clicked(e): + button.data += 1 + message_text.value = f"Button clicked {button.data} time(s)" + + message_text = ft.Text() + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + button := ft.TextButton( + key="TextButton", + content="Button with 'click' event", + data=0, + on_click=button_clicked, + ), + ft.Container( + padding=ft.Padding(left=12), + content=message_text, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_button/handling_clicks/pyproject.toml b/sdk/python/examples/controls/material/text_button/handling_clicks/pyproject.toml new file mode 100644 index 0000000000..88527e5907 --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/handling_clicks/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-handling-clicks" +version = "1.0.0" +description = "Updates a counter message each time a TextButton click event fires." +requires-python = ">=3.10" +keywords = ["text button", "events", "click", "counter", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton handling clicks" +controls = ["SafeArea", "Column", "TextButton", "Container", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["click handling", "live counter updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_button/icons/main.py b/sdk/python/examples/controls/material/text_button/icons/main.py new file mode 100644 index 0000000000..9e1e445ab0 --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/icons/main.py @@ -0,0 +1,27 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "TextButtons with icons" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextButton( + content="Button with icon", + icon=ft.Icons.WAVES_OUTLINED, + ), + ft.TextButton( + content="Button with colorful icon", + icon=ft.Icons.PARK_ROUNDED, + icon_color=ft.Colors.GREEN_400, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_button/icons/pyproject.toml b/sdk/python/examples/controls/material/text_button/icons/pyproject.toml new file mode 100644 index 0000000000..df13c044b9 --- /dev/null +++ b/sdk/python/examples/controls/material/text_button/icons/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-button-icons" +version = "1.0.0" +description = "Adds standard and custom-colored icons to TextButton controls." +requires-python = ">=3.10" +keywords = ["text button", "icons", "button", "material", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Buttons/TextButton"] + +[tool.flet.metadata] +title = "TextButton icons" +controls = ["SafeArea", "Column", "TextButton"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["icon buttons", "custom icon colors"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_button/media/adaptive.png b/sdk/python/examples/controls/material/text_button/media/adaptive.png new file mode 100644 index 0000000000..df99b3b3ba Binary files /dev/null and b/sdk/python/examples/controls/material/text_button/media/adaptive.png differ diff --git a/sdk/python/examples/controls/material/text_button/media/index.png b/sdk/python/examples/controls/material/text_button/media/index.png new file mode 100644 index 0000000000..45e7e870b1 Binary files /dev/null and b/sdk/python/examples/controls/material/text_button/media/index.png differ diff --git a/sdk/python/examples/controls/material/text_field/basic/main.py b/sdk/python/examples/controls/material/text_field/basic/main.py new file mode 100644 index 0000000000..6cece3e499 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/basic/main.py @@ -0,0 +1,43 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + f"Textboxes values are: '{tb1.value}', '{tb2.value}', " + f"'{tb3.value}', '{tb4.value}', '{tb5.value}'." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + tb1 := ft.TextField(label="Standard"), + tb2 := ft.TextField( + label="Disabled", + disabled=True, + value="First name", + ), + tb3 := ft.TextField( + label="Read-only", + read_only=True, + value="Last name", + ), + tb4 := ft.TextField( + label="With placeholder", + hint_text="Please enter text here", + ), + tb5 := ft.TextField( + label="With an icon", + icon=ft.Icons.EMOJI_EMOTIONS, + ), + ft.Button(content="Submit", on_click=handle_button_click), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/basic/pyproject.toml b/sdk/python/examples/controls/material/text_field/basic/pyproject.toml new file mode 100644 index 0000000000..b4d729ec59 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-basic" +version = "1.0.0" +description = "Compares standard, disabled, read-only, placeholder, and icon TextField states." +requires-python = ">=3.10" +keywords = ["text field", "input", "disabled", "read-only", "basic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "TextField basic" +controls = ["SafeArea", "Column", "TextField", "Button", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["multiple field states", "value summary"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/handling_change_events/main.py b/sdk/python/examples/controls/material/text_field/handling_change_events/main.py new file mode 100644 index 0000000000..251a43878c --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/handling_change_events/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_field_change(e: ft.Event[ft.TextField]): + message.value = e.control.value + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + key="handling_change_textfield", + label="Textbox with 'change' event:", + on_change=handle_field_change, + ), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/handling_change_events/pyproject.toml b/sdk/python/examples/controls/material/text_field/handling_change_events/pyproject.toml new file mode 100644 index 0000000000..87de8505cd --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/handling_change_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-handling-change-events" +version = "1.0.0" +description = "Echoes TextField input live as the value changes." +requires-python = ">=3.10" +keywords = ["text field", "events", "change", "input", "live"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Handling change events" +controls = ["SafeArea", "Column", "TextField", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["change events", "live updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/label_hint_helper_counter/main.py b/sdk/python/examples/controls/material/text_field/label_hint_helper_counter/main.py new file mode 100644 index 0000000000..4064453cf7 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/label_hint_helper_counter/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + + def handle_field_change(e: ft.Event[ft.TextField]): + message.value = e.control.value + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + key="label_hint_helper_counter_textfield", + on_change=handle_field_change, + text_style=ft.TextStyle( + size=15, + italic=True, + color=ft.Colors.DEEP_ORANGE_600, + bgcolor=ft.Colors.LIME_ACCENT_200, + ), + label="Label", + label_style=ft.TextStyle( + size=17, + weight=ft.FontWeight.BOLD, + italic=True, + color=ft.Colors.BLUE, + bgcolor=ft.Colors.RED_700, + ), + hint_text="Hint", + hint_style=ft.TextStyle( + size=15, + weight=ft.FontWeight.BOLD, + italic=True, + color=ft.Colors.PINK_ACCENT, + bgcolor=ft.Colors.BROWN_400, + ), + helper="Helper", + helper_style=ft.TextStyle( + size=14, + weight=ft.FontWeight.BOLD, + color=ft.Colors.DEEP_PURPLE, + bgcolor=ft.Colors.BLUE_50, + ), + counter="Counter", + counter_style=ft.TextStyle( + size=14, + italic=True, + color=ft.Colors.YELLOW, + bgcolor=ft.Colors.GREEN_500, + ), + ), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/label_hint_helper_counter/pyproject.toml b/sdk/python/examples/controls/material/text_field/label_hint_helper_counter/pyproject.toml new file mode 100644 index 0000000000..79f08fb3a5 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/label_hint_helper_counter/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-label-hint-helper-counter" +version = "1.0.0" +description = "Styles TextField label, hint, helper, and counter text independently." +requires-python = ">=3.10" +keywords = ["text field", "label", "hint", "helper", "counter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Custom label, hint, helper, and counter texts and styles" +controls = ["SafeArea", "Column", "TextField", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["custom label styling", "custom hint styling", "custom helper and counter styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/media/basic.gif b/sdk/python/examples/controls/material/text_field/media/basic.gif new file mode 100644 index 0000000000..3305656fd8 Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/basic.gif differ diff --git a/sdk/python/examples/controls/material/text_field/media/handling_change_events.gif b/sdk/python/examples/controls/material/text_field/media/handling_change_events.gif new file mode 100644 index 0000000000..4b87116cad Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/handling_change_events.gif differ diff --git a/sdk/python/examples/controls/material/text_field/media/index.png b/sdk/python/examples/controls/material/text_field/media/index.png new file mode 100644 index 0000000000..3f8cc55504 Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/index.png differ diff --git a/sdk/python/examples/controls/material/text_field/media/multiline.gif b/sdk/python/examples/controls/material/text_field/media/multiline.gif new file mode 100644 index 0000000000..297253cf2e Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/multiline.gif differ diff --git a/sdk/python/examples/controls/material/text_field/media/password.gif b/sdk/python/examples/controls/material/text_field/media/password.gif new file mode 100644 index 0000000000..3e5e66780e Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/password.gif differ diff --git a/sdk/python/examples/controls/material/text_field/media/prefix_and_suffix.gif b/sdk/python/examples/controls/material/text_field/media/prefix_and_suffix.gif new file mode 100644 index 0000000000..b1dfdabe9e Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/prefix_and_suffix.gif differ diff --git a/sdk/python/examples/controls/material/text_field/media/underlined_and_borderless.gif b/sdk/python/examples/controls/material/text_field/media/underlined_and_borderless.gif new file mode 100644 index 0000000000..7ccb7adfc5 Binary files /dev/null and b/sdk/python/examples/controls/material/text_field/media/underlined_and_borderless.gif differ diff --git a/sdk/python/examples/controls/material/text_field/multiline/main.py b/sdk/python/examples/controls/material/text_field/multiline/main.py new file mode 100644 index 0000000000..a45ecb5fda --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/multiline/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + key="multiline_standard", + label="Standard", + multiline=True, + ), + ft.TextField( + label="Disabled", + multiline=True, + disabled=True, + value="line1\nline2\nline3\nline4\nline5", + ), + ft.TextField( + key="multiline_auto_height", + label="Auto adjusted height with max lines", + multiline=True, + min_lines=1, + max_lines=3, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/multiline/pyproject.toml b/sdk/python/examples/controls/material/text_field/multiline/pyproject.toml new file mode 100644 index 0000000000..32d2ae4e32 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/multiline/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-multiline" +version = "1.0.0" +description = "Compares multiline TextField configurations including disabled and auto-sized fields." +requires-python = ">=3.10" +keywords = ["text field", "multiline", "input", "disabled", "autosize"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Multiline fields" +controls = ["SafeArea", "Column", "TextField"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["multiline input", "auto-sized height"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/password/main.py b/sdk/python/examples/controls/material/text_field/password/main.py new file mode 100644 index 0000000000..98af2c3894 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/password/main.py @@ -0,0 +1,18 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.TextField( + key="password_textfield", + label="Password with reveal button", + password=True, + can_reveal_password=True, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/password/pyproject.toml b/sdk/python/examples/controls/material/text_field/password/pyproject.toml new file mode 100644 index 0000000000..e26b76d4e5 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/password/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-password" +version = "1.0.0" +description = "Shows a password TextField with a built-in reveal button." +requires-python = ">=3.10" +keywords = ["text field", "password", "secure input", "reveal", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Password with reveal button" +controls = ["SafeArea", "TextField"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["password reveal"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/prefix_and_suffix/main.py b/sdk/python/examples/controls/material/text_field/prefix_and_suffix/main.py new file mode 100644 index 0000000000..b82ba0f3f5 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/prefix_and_suffix/main.py @@ -0,0 +1,59 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_button_click(e: ft.Event[ft.Button]): + message.value = ( + "Textboxes values are: " + f"'{prefix_field.value}', " + f"'{suffix_field.value}', " + f"'{prefix_suffix_field.value}', " + f"'{color_field.value}'." + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + prefix_field := ft.TextField( + key="prefix_field", + label="With prefix", + prefix="https://", + ), + suffix_field := ft.TextField( + key="suffix_field", + label="With suffix", + suffix=".com", + ), + prefix_suffix_field := ft.TextField( + key="prefix_suffix_field", + label="With prefix and suffix", + prefix="https://", + suffix=".com", + enable_interactive_selection=True, + ), + color_field := ft.TextField( + key="color_field", + label="My favorite color", + icon=ft.Icons.FORMAT_SIZE, + hint_text="Type your favorite color", + helper="You can type only one color", + counter="{value_length}/{max_length} chars used", + prefix_icon=ft.Icons.COLOR_LENS, + suffix="...is your color", + max_length=20, + ), + ft.Button( + key="submit_button", + content="Submit", + on_click=handle_button_click, + ), + message := ft.Text(), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/prefix_and_suffix/pyproject.toml b/sdk/python/examples/controls/material/text_field/prefix_and_suffix/pyproject.toml new file mode 100644 index 0000000000..baef30c0c8 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/prefix_and_suffix/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-prefix-and-suffix" +version = "1.0.0" +description = "Adds prefixes, suffixes, counters, and helper text to TextField inputs." +requires-python = ">=3.10" +keywords = ["text field", "prefix", "suffix", "counter", "helper"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Setting prefixes and suffixes" +controls = ["SafeArea", "Column", "TextField", "Button", "Text"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["prefix and suffix text", "helper text", "counters"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/selection_change/main.py b/sdk/python/examples/controls/material/text_field/selection_change/main.py new file mode 100644 index 0000000000..8589f7ae77 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/selection_change/main.py @@ -0,0 +1,56 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Text selection" + + def handle_selection_change(e: ft.TextSelectionChangeEvent[ft.TextField]): + selection.value = ( + f"Selection: '{e.selected_text}'" if e.selected_text else "No selection." + ) + selection_details.value = f"start={e.selection.start}, end={e.selection.end}" + caret.value = f"Caret position: {e.selection.end}" + + async def select_characters(e: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection( + base_offset=0, extent_offset=len(field.value) + ) + + async def move_caret(e: ft.Event[ft.Button]): + await field.focus() + field.selection = ft.TextSelection(base_offset=0, extent_offset=0) + + page.add( + ft.SafeArea( + content=ft.Column( + spacing=10, + controls=[ + field := ft.TextField( + value=( + "Lorem ipsum dolor sit amet, consectetur adipiscing elit." + ), + multiline=True, + min_lines=3, + autofocus=True, + on_selection_change=handle_selection_change, + ), + selection := ft.Text("Select some text from the field."), + selection_details := ft.Text(), + caret := ft.Text("Caret position: -"), + ft.Button( + content="Select all text", + on_click=select_characters, + ), + ft.Button( + content="Move caret to start", + on_click=move_caret, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/selection_change/pyproject.toml b/sdk/python/examples/controls/material/text_field/selection_change/pyproject.toml new file mode 100644 index 0000000000..710da215d8 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/selection_change/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-selection-change" +version = "1.0.0" +description = "Tracks TextField selection ranges and moves the caret with buttons." +requires-python = ">=3.10" +keywords = ["text field", "selection", "caret", "async", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Handling selection changes" +controls = ["SafeArea", "Column", "TextField", "Text", "Button"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["selection events", "caret control"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/styled/main.py b/sdk/python/examples/controls/material/text_field/styled/main.py new file mode 100644 index 0000000000..e45fa80469 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/styled/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +async def main(page: ft.Page): + page.padding = 50 + + tf = ft.TextField( + key="styled_textfield", + text_size=30, + cursor_color=ft.Colors.RED, + selection_color=ft.Colors.YELLOW, + color=ft.Colors.PINK, + bgcolor=ft.Colors.BLACK_26, + filled=True, + focused_color=ft.Colors.GREEN, + focused_bgcolor=ft.Colors.CYAN_200, + border_radius=30, + border_color=ft.Colors.GREEN_800, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + max_length=20, + capitalization=ft.TextCapitalization.CHARACTERS, + ) + + page.add( + ft.SafeArea( + content=tf, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/styled/pyproject.toml b/sdk/python/examples/controls/material/text_field/styled/pyproject.toml new file mode 100644 index 0000000000..652ce7e042 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/styled/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-styled" +version = "1.0.0" +description = "Customizes TextField colors, cursor, borders, capitalization, and focus behavior." +requires-python = ">=3.10" +keywords = ["text field", "styling", "focus", "async", "input"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Styled TextField" +controls = ["SafeArea", "TextField"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom field styling", "programmatic focus"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/text_field/underlined_and_borderless/main.py b/sdk/python/examples/controls/material/text_field/underlined_and_borderless/main.py new file mode 100644 index 0000000000..48bfe8f685 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/underlined_and_borderless/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.TextField( + key="underlined_field", + label="Underlined", + border=ft.InputBorder.UNDERLINE, + hint_text="Enter text here", + ), + ft.TextField( + key="underlined_filled_field", + label="Underlined filled", + border=ft.InputBorder.UNDERLINE, + filled=True, + hint_text="Enter text here", + ), + ft.TextField( + key="borderless_field", + label="Borderless", + border=ft.InputBorder.NONE, + hint_text="Enter text here", + ), + ft.TextField( + key="borderless_filled_field", + label="Borderless filled", + border=ft.InputBorder.NONE, + filled=True, + hint_text="Enter text here", + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/text_field/underlined_and_borderless/pyproject.toml b/sdk/python/examples/controls/material/text_field/underlined_and_borderless/pyproject.toml new file mode 100644 index 0000000000..11e7d234c4 --- /dev/null +++ b/sdk/python/examples/controls/material/text_field/underlined_and_borderless/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "text-field-underlined-and-borderless" +version = "1.0.0" +description = "Shows underlined and borderless TextField styles with filled and unfilled variants." +requires-python = ">=3.10" +keywords = ["text field", "border", "underlined", "borderless", "styling"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/TextField"] + +[tool.flet.metadata] +title = "Underlined and borderless TextFields" +controls = ["SafeArea", "Column", "TextField"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["underlined border", "borderless style"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/time_picker/basic/main.py b/sdk/python/examples/controls/material/time_picker/basic/main.py new file mode 100644 index 0000000000..a94793e6c6 --- /dev/null +++ b/sdk/python/examples/controls/material/time_picker/basic/main.py @@ -0,0 +1,49 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_change(e: ft.Event[ft.TimePicker]): + selection.value = f"Selection: {time_picker.value}" + page.show_dialog(ft.SnackBar(f"TimePicker change: {time_picker.value}")) + + def handle_dismissal(e: ft.Event[ft.DialogControl]): + page.show_dialog(ft.SnackBar("TimePicker dismissed!")) + + def handle_entry_mode_change(e: ft.TimePickerEntryModeChangeEvent): + page.show_dialog(ft.SnackBar(f"Entry mode changed: {time_picker.entry_mode}")) + + time_picker = ft.TimePicker( + value=time(hour=19, minute=30), + confirm_text="Confirm", + error_invalid_text="Time out of range", + help_text="Pick your time slot", + entry_mode=ft.TimePickerEntryMode.DIAL, + on_change=handle_change, + on_dismiss=handle_dismissal, + on_entry_mode_change=handle_entry_mode_change, + ) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + key="pick_time_button", + content="Pick time", + icon=ft.Icons.TIME_TO_LEAVE, + on_click=lambda: page.show_dialog(time_picker), + ), + selection := ft.Text(weight=ft.FontWeight.BOLD), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/time_picker/basic/pyproject.toml b/sdk/python/examples/controls/material/time_picker/basic/pyproject.toml new file mode 100644 index 0000000000..e0215ded66 --- /dev/null +++ b/sdk/python/examples/controls/material/time_picker/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "time-picker-basic" +version = "1.0.0" +description = "Opens a TimePicker dialog and reports selection, dismissal, and entry mode changes." +requires-python = ">=3.10" +keywords = ["time picker", "dialog", "events", "selection", "material"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/TimePicker"] + +[tool.flet.metadata] +title = "TimePicker basic" +controls = ["SafeArea", "Column", "Button", "Text", "TimePicker", "SnackBar"] +layout_pattern = "stacked-actions" +complexity = "basic" +features = ["dialog opening", "change callbacks", "dismiss callbacks"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/time_picker/custom_locale/main.py b/sdk/python/examples/controls/material/time_picker/custom_locale/main.py new file mode 100644 index 0000000000..a0db948bb3 --- /dev/null +++ b/sdk/python/examples/controls/material/time_picker/custom_locale/main.py @@ -0,0 +1,27 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.SafeArea( + content=ft.Button( + key="custom_locale_button", + content="Pick time (zh_Hans locale)", + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda e: page.show_dialog( + ft.TimePicker( + value=time(hour=19, minute=30), + locale=ft.Locale("zh", "Hans"), + ) + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/time_picker/custom_locale/pyproject.toml b/sdk/python/examples/controls/material/time_picker/custom_locale/pyproject.toml new file mode 100644 index 0000000000..ed1d04a6dd --- /dev/null +++ b/sdk/python/examples/controls/material/time_picker/custom_locale/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "time-picker-custom-locale" +version = "1.0.0" +description = "Opens a TimePicker dialog using a custom zh_Hans locale." +requires-python = ">=3.10" +keywords = ["time picker", "locale", "dialog", "internationalization", "button"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/TimePicker"] + +[tool.flet.metadata] +title = "Custom locale" +controls = ["SafeArea", "Button", "TimePicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["custom locale"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/controls/material/time_picker/hour_formats/main.py b/sdk/python/examples/controls/material/time_picker/hour_formats/main.py new file mode 100644 index 0000000000..ae0ef4d7b4 --- /dev/null +++ b/sdk/python/examples/controls/material/time_picker/hour_formats/main.py @@ -0,0 +1,80 @@ +from datetime import time + +import flet as ft + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def get_system_hour_format(): + """Returns the current system's hour format.""" + return "24h" if page.media.always_use_24_hour_format else "12h" + + def format_time(value: time) -> str: + """Returns a formatted time string based on TimePicker and system settings.""" + use_24h = time_picker.hour_format == ft.TimePickerHourFormat.H24 or ( + time_picker.hour_format == ft.TimePickerHourFormat.SYSTEM + and page.media.always_use_24_hour_format + ) + return value.strftime("%H:%M" if use_24h else "%I:%M %p") + + def handle_change(e: ft.Event[ft.TimePicker]): + selection.value = f"Selection: {format_time(time_picker.value)}" + + time_picker = ft.TimePicker( + value=time(hour=19, minute=30), + help_text="Choose your meeting time", + on_change=handle_change, + ) + + def open_picker(e: ft.Event[ft.Button]): + choice = format_dropdown.value + hour_format_map = { + "system": ft.TimePickerHourFormat.SYSTEM, + "12h": ft.TimePickerHourFormat.H12, + "24h": ft.TimePickerHourFormat.H24, + } + time_picker.hour_format = hour_format_map[choice] + page.show_dialog(time_picker) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + format_dropdown := ft.Dropdown( + label="Hour format", + value="system", + width=260, + key="dd", + options=[ + ft.DropdownOption( + key="system", + text=( + f"System default " + f"({get_system_hour_format()})" + ), + ), + ft.DropdownOption(key="12h", text="12-hour clock"), + ft.DropdownOption(key="24h", text="24-hour clock"), + ], + ), + ft.Button( + "Open TimePicker", + icon=ft.Icons.SCHEDULE, + on_click=open_picker, + ), + ], + ), + selection := ft.Text(weight=ft.FontWeight.BOLD), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/controls/material/time_picker/hour_formats/pyproject.toml b/sdk/python/examples/controls/material/time_picker/hour_formats/pyproject.toml new file mode 100644 index 0000000000..979eb6eaf5 --- /dev/null +++ b/sdk/python/examples/controls/material/time_picker/hour_formats/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "time-picker-hour-formats" +version = "1.0.0" +description = "Switches a TimePicker between system, 12-hour, and 24-hour display formats." +requires-python = ">=3.10" +keywords = ["time picker", "hour format", "dropdown", "12h", "24h"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Dialogs/TimePicker"] + +[tool.flet.metadata] +title = "Hour formats" +controls = ["SafeArea", "Column", "Row", "Dropdown", "Button", "Text", "TimePicker"] +layout_pattern = "toolbar-content" +complexity = "basic" +features = ["hour format switching", "system format detection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/cookbook/cpu_bound_callback.py b/sdk/python/examples/cookbook/cpu_bound_callback.py new file mode 100644 index 0000000000..83188b1d8e --- /dev/null +++ b/sdk/python/examples/cookbook/cpu_bound_callback.py @@ -0,0 +1,47 @@ +import asyncio +import time + +import flet as ft + + +class CpuProgressApp: + def __init__(self, page: ft.Page): + self.page = page + self.loop = asyncio.get_running_loop() + + self.page.title = "Simple thread + asyncio task" + self.pb = ft.ProgressBar(value=0.0, width=420) + self.btn = ft.Button("Start", on_click=self.start_clicked) + self.page.add(ft.Column([self.btn, self.pb], tight=True, spacing=10)) + + # ---------- Thread-safe UI updates ---------- + async def set_progress(self, p: float): + self.pb.value = p + self.page.update() + + def report_callback(self, p: float): + # Called from worker thread -> hop to main asyncio loop + asyncio.run_coroutine_threadsafe(self.set_progress(p), self.loop) + + # ---------- Handlers ---------- + async def start_clicked(self, _=None): + self.btn.disabled = True + await self.set_progress(0.0) + + # Run blocking job in a thread and wait for it to finish + await asyncio.to_thread(self.long_job, 100, self.report_callback) + + self.btn.disabled = False + await self.set_progress(1.0) + + # ---------- Blocking job ---------- + @staticmethod + def long_job(steps: int, report_callback): + for i in range(steps): + _ = sum(range(200_000)) # small CPU burn; bump if needed + time.sleep(0.1) + report_callback((i + 1) / steps) # 0..1 + + +if __name__ == "__main__": + ft.run(CpuProgressApp) diff --git a/sdk/python/examples/cookbook/cpu_bound_png_stream.py b/sdk/python/examples/cookbook/cpu_bound_png_stream.py new file mode 100644 index 0000000000..3343c5f9b3 --- /dev/null +++ b/sdk/python/examples/cookbook/cpu_bound_png_stream.py @@ -0,0 +1,129 @@ +import asyncio +import contextlib +import io +import random +import threading +import time +from typing import Optional + +from PIL import Image, ImageDraw + +import flet as ft +import flet.canvas as fc + + +# ---------- frame generator ---------- +def make_frame(i: int, w: int = 640, h: int = 480) -> bytes: + img = Image.new( + "RGB", + (w, h), + (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), + ) + draw = ImageDraw.Draw(img) + + # random circles + for _ in range(10): + x1, y1 = random.randint(0, w - 40), random.randint(0, h - 40) + x2, y2 = x1 + random.randint(20, 80), y1 + random.randint(20, 80) + color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + draw.ellipse([x1, y1, x2, y2], fill=color, outline="black") + + # random lines + for _ in range(10): + x1, y1 = random.randint(0, w - 1), random.randint(0, h - 1) + x2, y2 = random.randint(0, w - 1), random.randint(0, h - 1) + color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) + draw.line([x1, y1, x2, y2], fill=color, width=3) + + # label + draw.text((10, 10), f"Frame {i}\n{time.strftime('%H:%M:%S')}", fill="white") + + buf = io.BytesIO() + img.save(buf, format="PNG") + return buf.getvalue() + + +# ---------- producer thread: pushes into asyncio.Queue ---------- +def producer_thread( + loop: asyncio.AbstractEventLoop, + q: asyncio.Queue, + stop_evt: threading.Event, + target_fps: float = 20.0, + max_frames: Optional[int] = None, +): + interval = 1.0 / target_fps if target_fps > 0 else 0.0 + next_t = time.perf_counter() + i = 0 + while not stop_evt.is_set() and (max_frames is None or i < max_frames): + png = make_frame(i, w=1200, h=1000) + # thread-safe put into asyncio.Queue with backpressure + fut = asyncio.run_coroutine_threadsafe(q.put((i, png)), loop) + try: + fut.result(timeout=5) # block here if queue is full + except Exception: + break + + i += 1 + if interval: + next_t += interval + delay = next_t - time.perf_counter() + if delay > 0: + time.sleep(delay) + else: + # we're behind; reset schedule to avoid spiral of death + next_t = time.perf_counter() + + +# ---------- async consumer: draws frames ---------- +async def consumer_loop( + q: asyncio.Queue, + canvas: fc.Canvas, + stop_evt: threading.Event, +): + while not stop_evt.is_set(): + try: + idx, png = await q.get() + except asyncio.CancelledError: + break + + print("Draw:", len(png)) + canvas.shapes = [fc.Image(src=png, x=0, y=0)] + canvas.update() + + +# ---------- main entry ---------- +async def main(page: ft.Page): + canvas = fc.Canvas(expand=True) + page.add(canvas) + + loop = asyncio.get_running_loop() + q: asyncio.Queue = asyncio.Queue(maxsize=100) # bounded = backpressure + stop_evt = threading.Event() + + # launch consumer + consumer = asyncio.create_task(consumer_loop(q, canvas, stop_evt)) + + # launch producer in a thread + t = threading.Thread( + target=producer_thread, + args=(loop, q, stop_evt), + kwargs=dict(target_fps=20.0, max_frames=100), # tweak as needed + daemon=True, + ) + t.start() + + try: + # wait for producer to finish + while t.is_alive(): + await asyncio.sleep(0.1) + finally: + stop_evt.set() + t.join(timeout=2) + if not consumer.done(): + consumer.cancel() + with contextlib.suppress(asyncio.CancelledError): + await consumer + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/cookbook/cpu_bound_queue.py b/sdk/python/examples/cookbook/cpu_bound_queue.py new file mode 100644 index 0000000000..3c98dea6a3 --- /dev/null +++ b/sdk/python/examples/cookbook/cpu_bound_queue.py @@ -0,0 +1,56 @@ +import asyncio +import time + +import flet as ft + + +class CpuProgressApp: + def __init__(self, page: ft.Page): + self.page = page + self.loop = asyncio.get_running_loop() + + self.page.title = "Simple thread + asyncio task (Queue)" + self.pb = ft.ProgressBar(value=0.0, width=420) + self.btn = ft.Button("Start", on_click=self.start_clicked) + self.page.add(ft.Column([self.btn, self.pb], tight=True, spacing=10)) + + # Async queue for progress updates from the worker + self.progress_queue: asyncio.Queue[float] = asyncio.Queue(maxsize=100) + + # Start one consumer task that keeps the UI in sync with queue updates + self.consumer_task = asyncio.create_task(self.consume_progress()) + + # ---------- Queue consumer (runs on main asyncio loop) ---------- + async def consume_progress(self): + while True: + p = await self.progress_queue.get() # 0..1 + self.pb.value = p + self.page.update() + + # ---------- Enqueue helper usable from any thread ---------- + def enqueue_progress(self, p: float): + # Called from the worker thread; schedule a put into the asyncio queue + asyncio.run_coroutine_threadsafe(self.progress_queue.put(p), self.loop) + + # ---------- Click handler ---------- + async def start_clicked(self, _=None): + self.btn.disabled = True + await self.progress_queue.put(0.0) + + # Run blocking job in a thread and wait for it to finish + await asyncio.to_thread(self.long_job, 100, self.enqueue_progress) + + self.btn.disabled = False + await self.progress_queue.put(1.0) # final update + + # ---------- Blocking job (runs in thread) ---------- + @staticmethod + def long_job(steps: int, enqueue_progress): + for i in range(steps): + _ = sum(range(200_000)) # small CPU burn; bump if needed + time.sleep(0.1) + enqueue_progress((i + 1) / steps) # 0..1 + + +if __name__ == "__main__": + ft.run(CpuProgressApp) diff --git a/sdk/python/examples/cookbook/user_control_with_auto_update.py b/sdk/python/examples/cookbook/user_control_with_auto_update.py new file mode 100644 index 0000000000..bd7e11214b --- /dev/null +++ b/sdk/python/examples/cookbook/user_control_with_auto_update.py @@ -0,0 +1,46 @@ +from typing import Optional + +import flet as ft + + +@ft.control(isolated=True) +class MyPanel(ft.Container): + # control properties + color: Optional[ft.ColorValue] = None + greeting: str = "Hi" + + # called only once + def build(self): + print(self.page.platform) + self.content = ft.Column( + controls=[ + ft.Button( + f"Make {self.color.value}", on_click=self.on_change_color_click + ), + ft.Row( + [ft.Button(f"Say {self.greeting}!", on_click=self.on_say_click)] + ), + ] + ) + + def on_change_color_click(self, e): + self.page.bgcolor = self.color + self.page.update() + + def on_say_click(self, e): + self.content.controls.append(ft.Text(self.greeting)) + + +def main(page: ft.Page): + page.controls.append( + ft.Row( + vertical_alignment=ft.CrossAxisAlignment.START, + controls=[ + MyPanel(color=ft.Colors.RED, width=200), + MyPanel(color=ft.Colors.GREEN, greeting="whoops", width=200), + ], + ) + ) + + +ft.run(main) diff --git a/sdk/python/examples/extensions/ads/example_1/main.py b/sdk/python/examples/extensions/ads/example_1/main.py new file mode 100644 index 0000000000..31f03032e5 --- /dev/null +++ b/sdk/python/examples/extensions/ads/example_1/main.py @@ -0,0 +1,77 @@ +import flet as ft +import flet_ads as fta + +# Test ad unit IDs +ids = { + ft.PagePlatform.ANDROID: { + "banner": "ca-app-pub-3940256099942544/6300978111", + "interstitial": "ca-app-pub-3940256099942544/1033173712", + }, + ft.PagePlatform.IOS: { + "banner": "ca-app-pub-3940256099942544/2934735716", + "interstitial": "ca-app-pub-3940256099942544/4411468910", + }, +} + + +def main(page: ft.Page): + page.appbar = ft.AppBar( + adaptive=True, + title="Mobile Ads Playground", + bgcolor=ft.Colors.LIGHT_BLUE_300, + ) + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.AUTO + + def show_new_interstitial_ad(): + async def show_iad(e: ft.Event[fta.InterstitialAd]): + await iad.show() + + iad = fta.InterstitialAd( + unit_id=ids[page.platform]["interstitial"], + on_load=show_iad, + on_error=lambda e: print("InterstitialAd error", e.data), + on_open=lambda e: print("InterstitialAd opened"), + on_close=lambda e: print("InterstitialAd closed"), + on_impression=lambda e: print("InterstitialAd impression"), + on_click=lambda e: print("InterstitialAd clicked"), + ) + + def get_new_banner_ad() -> fta.BannerAd: + return fta.BannerAd( + unit_id=ids[page.platform]["banner"], + width=320, + height=50, + on_click=lambda e: print("BannerAd clicked"), + on_load=lambda e: print("BannerAd loaded"), + on_error=lambda e: print("BannerAd error", e.data), + on_open=lambda e: print("BannerAd opened"), + on_close=lambda e: print("BannerAd closed"), + on_impression=lambda e: print("BannerAd impression"), + on_will_dismiss=lambda e: print("BannerAd will dismiss"), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton( + content="Show InterstitialAd", + on_click=show_new_interstitial_ad, + disabled=page.web + or not page.platform.is_mobile(), # mobile only + ), + ft.OutlinedButton( + content="Show BannerAd", + on_click=lambda e: page.add(get_new_banner_ad()), + disabled=page.web + or not page.platform.is_mobile(), # mobile only + ), + ] + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/ads/example_1/pyproject.toml b/sdk/python/examples/extensions/ads/example_1/pyproject.toml new file mode 100644 index 0000000000..4ae4abd56a --- /dev/null +++ b/sdk/python/examples/extensions/ads/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "ads-example-1" +version = "1.0.0" +description = "Mobile ads example with BannerAd and InterstitialAd." +requires-python = ">=3.10" +keywords = ["ads", "banner ad", "interstitial ad", "admob", "mobile"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-ads"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Marketing/Ads"] + +[tool.flet.metadata] +title = "BannerAd and InterstitialAd" +controls = ["SafeArea", "Column", "OutlinedButton", "AppBar", "BannerAd", "InterstitialAd"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["banner ad loading", "interstitial ad loading", "ad lifecycle callbacks", "platform-specific ad units"] + +[tool.flet] +platforms = ["ios", "android"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/ads/media/example_1.gif b/sdk/python/examples/extensions/ads/media/example_1.gif new file mode 100644 index 0000000000..23d155c21d Binary files /dev/null and b/sdk/python/examples/extensions/ads/media/example_1.gif differ diff --git a/sdk/python/examples/extensions/audio/declarative_1/assets/sounds_sweet-life-luxury-chill.mp3 b/sdk/python/examples/extensions/audio/declarative_1/assets/sounds_sweet-life-luxury-chill.mp3 new file mode 100644 index 0000000000..f1cf864f74 Binary files /dev/null and b/sdk/python/examples/extensions/audio/declarative_1/assets/sounds_sweet-life-luxury-chill.mp3 differ diff --git a/sdk/python/examples/extensions/audio/declarative_1/main.py b/sdk/python/examples/extensions/audio/declarative_1/main.py new file mode 100644 index 0000000000..86765cbe82 --- /dev/null +++ b/sdk/python/examples/extensions/audio/declarative_1/main.py @@ -0,0 +1,47 @@ +import flet as ft +import flet_audio as fta + + +@ft.component +def App(): + duration, set_duration = ft.use_state(0.0) + position, set_position = ft.use_state(0.0) + + audio, _ = ft.use_state( + lambda: fta.Audio( + src="sounds_sweet-life-luxury-chill.mp3", + autoplay=False, + on_duration_change=lambda e: set_duration(e.duration.in_milliseconds), + on_position_change=lambda e: set_position(e.position), + ) + ) + + ft.on_mounted(lambda: ft.context.page.services.append(audio)) + + async def play(): + await audio.play() + + async def pause(): + await audio.pause() + + async def resume(): + await audio.resume() + + return ft.SafeArea( + content=ft.Column( + controls=[ + ft.ProgressBar(position / duration if duration > 0 else 0), + ft.Button("Play", disabled=duration == 0, on_click=play), + ft.Button("Pause", disabled=duration == 0, on_click=pause), + ft.Button("Resume", disabled=duration == 0, on_click=resume), + ] + ) + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/audio/declarative_1/pyproject.toml b/sdk/python/examples/extensions/audio/declarative_1/pyproject.toml new file mode 100644 index 0000000000..51bc71729f --- /dev/null +++ b/sdk/python/examples/extensions/audio/declarative_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-declarative-1" +version = "1.0.0" +description = "Builds a declarative audio player with playback controls and live progress updates." +requires-python = ">=3.10" +keywords = ["services", "audio", "declarative", "progress", "playback", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Audio"] + +[tool.flet.metadata] +title = "Declarative audio player" +controls = ["SafeArea", "Column", "ProgressBar", "Button", "Audio"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["declarative state", "audio playback", "live progress updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/audio/example_1/assets/viper.mp3 b/sdk/python/examples/extensions/audio/example_1/assets/viper.mp3 new file mode 100644 index 0000000000..2351f792e2 Binary files /dev/null and b/sdk/python/examples/extensions/audio/example_1/assets/viper.mp3 differ diff --git a/sdk/python/examples/extensions/audio/example_1/main.py b/sdk/python/examples/extensions/audio/example_1/main.py new file mode 100644 index 0000000000..c11beade57 --- /dev/null +++ b/sdk/python/examples/extensions/audio/example_1/main.py @@ -0,0 +1,93 @@ +import flet as ft +import flet_audio as fta + + +def main(page: ft.Page): + url = "viper.mp3" + + async def play(): + await audio.play() + + async def pause(): + await audio.pause() + + async def resume(): + await audio.resume() + + async def release(): + await audio.release() + + def set_volume(value: float): + audio.volume += value + + def set_balance(value: float): + audio.balance += value + + async def seek_2s(): + await audio.seek(ft.Duration(seconds=2)) + + async def get_duration(): + duration = await audio.get_duration() + print("Duration:", duration) + + async def on_get_current_position(): + position = await audio.get_current_position() + print("Current position:", position) + + audio = fta.Audio( + src=url, + autoplay=False, + volume=1, + balance=0, + release_mode=fta.ReleaseMode.STOP, + on_loaded=lambda _: print("Loaded"), + on_duration_change=lambda e: print("Duration changed:", e.duration), + on_position_change=lambda e: print("Position changed:", e.position), + on_state_change=lambda e: print("State changed:", e.state), + on_seek_complete=lambda _: print("Seek complete"), + ) + page.services.append(audio) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("Play", on_click=play), + ft.Button("Pause", on_click=pause), + ft.Button("Resume", on_click=resume), + ft.Button("Release", on_click=release), + ft.Button("Seek 2s", on_click=seek_2s), + ft.Row( + controls=[ + ft.Button( + "Volume down", + on_click=lambda _: set_volume(-0.1), + ), + ft.Button("Volume up", on_click=lambda _: set_volume(0.1)), + ] + ), + ft.Row( + controls=[ + ft.Button( + "Balance left", + on_click=lambda _: set_balance(-0.1), + ), + ft.Button( + "Balance right", + on_click=lambda _: set_balance(0.1), + ), + ] + ), + ft.Button("Get duration", on_click=get_duration), + ft.Button( + "Get current position", + on_click=on_get_current_position, + ), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/audio/example_1/pyproject.toml b/sdk/python/examples/extensions/audio/example_1/pyproject.toml new file mode 100644 index 0000000000..c578fd9737 --- /dev/null +++ b/sdk/python/examples/extensions/audio/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-example-1" +version = "1.0.0" +description = "Controls audio playback, seek position, volume, and balance for a remote track." +requires-python = ">=3.10" +keywords = ["services", "audio", "playback", "seek", "volume", "balance", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Audio"] + +[tool.flet.metadata] +title = "Audio playback controls" +controls = ["SafeArea", "Column", "Row", "Button", "Audio"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["audio playback", "seek control", "volume adjustment", "balance adjustment"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/audio_recorder/basic/main.py b/sdk/python/examples/extensions/audio_recorder/basic/main.py new file mode 100644 index 0000000000..c2d4b8b5bb --- /dev/null +++ b/sdk/python/examples/extensions/audio_recorder/basic/main.py @@ -0,0 +1,81 @@ +import flet as ft +import flet_audio_recorder as far + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.appbar = ft.AppBar(title=ft.Text("Audio Recorder"), center_title=True) + + path = "test-audio-file.wav" + + def show_snackbar(message): + page.show_dialog(ft.SnackBar(ft.Text(message))) + + async def handle_recording_start(e: ft.Event[ft.Button]): + show_snackbar("Starting recording...") + await recorder.start_recording(output_path=path) + + async def handle_recording_stop(e: ft.Event[ft.Button]): + output_path = await recorder.stop_recording() + show_snackbar(f"Stopped recording. Output Path: {output_path}") + if page.web and output_path is not None: + await page.launch_url(output_path) + + async def handle_list_devices(e: ft.Event[ft.Button]): + o = await recorder.get_input_devices() + show_snackbar(f"Input Devices: {', '.join([f'{d.id}:{d.label}' for d in o])}") + + async def handle_has_permission(e: ft.Event[ft.Button]): + try: + status = await recorder.has_permission() + show_snackbar(f"Audio Recording Permission status: {status}") + except Exception as e: + show_snackbar(f"Error checking permission: {e}") + + async def handle_pause(e: ft.Event[ft.Button]): + print(f"isRecording: {await recorder.is_recording()}") + if await recorder.is_recording(): + await recorder.pause_recording() + + async def handle_resume(e: ft.Event[ft.Button]): + print(f"isPaused: {await recorder.is_paused()}") + if await recorder.is_paused(): + await recorder.resume_recording() + + async def handle_audio_encoder_test(e: ft.Event[ft.Button]): + print(await recorder.is_supported_encoder(far.AudioEncoder.WAV)) + + recorder = far.AudioRecorder( + configuration=far.AudioRecorderConfiguration(encoder=far.AudioEncoder.WAV), + on_state_change=lambda e: print(f"State Changed: {e.data}"), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Start Audio Recorder", on_click=handle_recording_start + ), + ft.Button( + content="Stop Audio Recorder", on_click=handle_recording_stop + ), + ft.Button(content="List Devices", on_click=handle_list_devices), + ft.Button(content="Pause Recording", on_click=handle_pause), + ft.Button(content="Resume Recording", on_click=handle_resume), + ft.Button( + content="WAV Encoder Support", + on_click=handle_audio_encoder_test, + ), + ft.Button( + content="Get Audio Recording Permission Status", + on_click=handle_has_permission, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/audio_recorder/basic/pyproject.toml b/sdk/python/examples/extensions/audio_recorder/basic/pyproject.toml new file mode 100644 index 0000000000..8e94897cdf --- /dev/null +++ b/sdk/python/examples/extensions/audio_recorder/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-recorder-basic" +version = "1.0.0" +description = "Records audio, lists input devices, and checks recorder permissions from one screen." +requires-python = ">=3.10" +keywords = ["audio recorder", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio-recorder"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/AudioRecorder"] + +[tool.flet.metadata] +title = "Audio recorder basic" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "Button", "AudioRecorder"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["audio recording", "permission check", "device listing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/audio_recorder/stream_and_download/main.py b/sdk/python/examples/extensions/audio_recorder/stream_and_download/main.py new file mode 100644 index 0000000000..d8616bb9df --- /dev/null +++ b/sdk/python/examples/extensions/audio_recorder/stream_and_download/main.py @@ -0,0 +1,98 @@ +import io +import time +import wave + +import flet as ft +import flet_audio_recorder as far + +SAMPLE_RATE = 44100 +CHANNELS = 1 +BYTES_PER_SAMPLE = 2 + + +def pcm_to_wav_bytes(pcm_data: bytes) -> bytes: + wav_buffer = io.BytesIO() + with wave.open(wav_buffer, "wb") as wav: + wav.setnchannels(CHANNELS) + wav.setsampwidth(BYTES_PER_SAMPLE) + wav.setframerate(SAMPLE_RATE) + wav.writeframes(pcm_data) + return wav_buffer.getvalue() + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + buffer = bytearray() + + def show_snackbar(message: str): + page.show_dialog(ft.SnackBar(content=message, duration=ft.Duration(seconds=5))) + + def handle_stream(e: far.AudioRecorderStreamEvent): + buffer.extend(e.chunk) + status.value = ( + f"Streaming chunk {e.sequence}; {e.bytes_streamed} bytes collected." + ) + + async def handle_recording_start(e: ft.Event[ft.Button]): + if not await recorder.has_permission(): + show_snackbar("Microphone permission is required.") + return + + buffer.clear() + status.value = "Recording..." + await recorder.start_recording( + configuration=far.AudioRecorderConfiguration( + encoder=far.AudioEncoder.PCM16BITS, + sample_rate=SAMPLE_RATE, + channels=CHANNELS, + ), + ) + + async def handle_recording_stop(e: ft.Event[ft.Button]): + await recorder.stop_recording() + if not buffer: + show_snackbar("Nothing was recorded.") + return + + wav_bytes = pcm_to_wav_bytes(bytes(buffer)) + file_name = f"recording-{int(time.time())}.wav" + file_path = await ft.FilePicker().save_file( + file_name=file_name, + file_type=ft.FilePickerFileType.CUSTOM, + allowed_extensions=["wav"], + src_bytes=wav_bytes, + ) + + if file_path and not (page.web or page.platform.is_mobile()): + with open(file_path, "wb") as output: + output.write(wav_bytes) + + if page.web: + status.value = f"Downloaded {file_name} ({len(wav_bytes)} bytes)." + else: + status.value = f"Saved to: {file_path}" if file_path else "Save cancelled." + show_snackbar(status.value) + + recorder = far.AudioRecorder(on_stream=handle_stream) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text( + "Stream PCM16 audio chunks and save or download " + "them as a WAV file." + ), + ft.Button("Start recording", on_click=handle_recording_start), + ft.Button("Stop and save", on_click=handle_recording_stop), + status := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/audio_recorder/stream_and_download/pyproject.toml b/sdk/python/examples/extensions/audio_recorder/stream_and_download/pyproject.toml new file mode 100644 index 0000000000..3aacaa520f --- /dev/null +++ b/sdk/python/examples/extensions/audio_recorder/stream_and_download/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-recorder-stream-and-download" +version = "1.0.0" +description = "Streams PCM16 audio chunks and saves or downloads them as a WAV file from bytes." +requires-python = ">=3.10" +keywords = ["audio recorder", "streaming", "download", "services", "async", "save to file"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio-recorder"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/AudioRecorder"] + +[tool.flet.metadata] +title = "Audio recorder stream and download" +controls = ["SafeArea", "Column", "Page", "Text", "Button", "FilePicker", "AudioRecorder"] +layout_pattern = "inline-actions" +complexity = "intermediate" +features = ["audio recording", "streaming chunks", "download from bytes", "save to file", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/audio_recorder/upload/main.py b/sdk/python/examples/extensions/audio_recorder/upload/main.py new file mode 100644 index 0000000000..487c0f406a --- /dev/null +++ b/sdk/python/examples/extensions/audio_recorder/upload/main.py @@ -0,0 +1,78 @@ +import time + +import flet as ft +import flet_audio_recorder as far + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def show_snackbar(message: str): + page.show_dialog(ft.SnackBar(content=message, duration=ft.Duration(seconds=5))) + + def handle_upload(e: far.AudioRecorderUploadEvent): + if e.error: + status.value = f"Upload error: {e.error}" + elif e.progress == 1: + status.value = f"Upload complete: {e.bytes_uploaded or 0} bytes." + else: + status.value = f"Uploading: {e.bytes_uploaded or 0} bytes sent." + + async def handle_recording_start(e: ft.Event[ft.Button]): + if not await recorder.has_permission(): + show_snackbar("Microphone permission is required.") + return + + file_name = f"recordings/rec-{int(time.time())}.pcm" + try: + upload_url = page.get_upload_url(file_name=file_name, expires=600) + except RuntimeError as ex: + if "FLET_SECRET_KEY" not in str(ex): + raise + status.value = ( + "Uploads require a secret key. " + "Set FLET_SECRET_KEY before running this app." + ) + show_snackbar(status.value) + return + + status.value = "Recording..." + await recorder.start_recording( + upload=far.AudioRecorderUploadSettings( + upload_url=upload_url, + file_name=file_name, + ), + configuration=far.AudioRecorderConfiguration( + encoder=far.AudioEncoder.PCM16BITS, + channels=1, + ), + ) + + async def handle_recording_stop(e: ft.Event[ft.Button]): + await recorder.stop_recording() + show_snackbar( + "Recording stopped. See 'uploads/recordings' folder for the recorded file." + ) + + recorder = far.AudioRecorder(on_upload=handle_upload) + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Record PCM16 audio and upload it as it streams."), + ft.Button("Start upload", on_click=handle_recording_start), + ft.Button("Stop recording", on_click=handle_recording_stop), + status := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run( + main, + upload_dir="uploads", + ) diff --git a/sdk/python/examples/extensions/audio_recorder/upload/pyproject.toml b/sdk/python/examples/extensions/audio_recorder/upload/pyproject.toml new file mode 100644 index 0000000000..add31ce914 --- /dev/null +++ b/sdk/python/examples/extensions/audio_recorder/upload/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-audio-recorder-upload" +version = "1.0.0" +description = "Records PCM16 audio and uploads the streamed bytes to Flet upload storage." +requires-python = ">=3.10" +keywords = ["audio recorder", "upload", "streaming", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-audio-recorder"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/AudioRecorder"] + +[tool.flet.metadata] +title = "Audio recorder upload" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "Button", "AudioRecorder"] +layout_pattern = "inline-actions" +complexity = "intermediate" +features = ["audio recording", "streaming upload", "upload progress", "async"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/camera/example_1/main.py b/sdk/python/examples/extensions/camera/example_1/main.py new file mode 100644 index 0000000000..64f583ad2f --- /dev/null +++ b/sdk/python/examples/extensions/camera/example_1/main.py @@ -0,0 +1,481 @@ +import base64 +import logging +from dataclasses import dataclass, field +from datetime import datetime +from math import cos, pi, sin + +import flet as ft +import flet_camera as fc + + +@dataclass +class State: + cameras: list[fc.CameraDescription] = field(default_factory=list) + selected_camera: fc.CameraDescription | None = None + camera_labels: dict[str, str] = field(default_factory=dict) + is_streaming: bool = False + is_streaming_supported: bool = False + is_initialized: bool = False + is_preview_paused: bool = False + is_recording: bool = False + is_recording_paused: bool = False + device_orientation: ft.DeviceOrientation | None = None + last_frame_width: int | None = None + last_frame_height: int | None = None + + +async def main(page: ft.Page): + image_frame_width = 280 + image_frame_height = 200 + page.title = "Camera control" + page.padding = 16 + page.scroll = ft.ScrollMode.AUTO + page.horizontal_alignment = ft.CrossAxisAlignment.STRETCH + + state = State() + + preview = fc.Camera( + expand=True, + preview_enabled=True, + content=ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Icon( + ft.Icons.CENTER_FOCUS_STRONG, + color=ft.Colors.WHITE_70, + size=48, + ), + ), + ) + + status = ft.Text(value="Select a camera", size=12) + last_photo_label = ft.Text("Last photo", visible=False) + last_image = ft.Image( + src=base64.b64decode( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/wIAAgMBAp0YVwAAAABJRU5ErkJggg==" + ), + width=image_frame_width, + height=image_frame_height, + fit=ft.BoxFit.CONTAIN, + gapless_playback=True, + ) + last_image_frame = ft.Container( + width=image_frame_width, + height=image_frame_height, + alignment=ft.Alignment.CENTER, + content=last_image, + visible=False, + ) + selector = ft.Dropdown(label="Camera", options=[]) + recorded_video_path = ft.Text(value="Recorded video: not saved yet", size=12) + take_photo_btn = ft.FilledIconButton( + icon=ft.Icons.PHOTO_CAMERA, + tooltip="Take photo", + disabled=True, + ) + record_btn = ft.FilledTonalIconButton( + icon=ft.Icons.VIDEOCAM, + selected_icon=ft.Icons.STOP, + selected=False, + tooltip="Start / stop recording", + disabled=True, + ) + pause_recording_btn = ft.OutlinedIconButton( + icon=ft.Icons.PAUSE, + selected_icon=ft.Icons.PLAY_ARROW, + selected=False, + tooltip="Pause / resume recording", + disabled=True, + ) + stream_btn = ft.OutlinedIconButton( + icon=ft.Icons.PLAY_ARROW, + selected_icon=ft.Icons.STOP, + selected=False, + tooltip="Start / stop image stream", + disabled=True, + ) + preview_btn = ft.OutlinedIconButton( + icon=ft.Icons.VISIBILITY_OFF, + selected_icon=ft.Icons.VISIBILITY, + selected=True, + tooltip="Pause / resume preview", + disabled=True, + ) + + def has_human_readable_name(camera: fc.CameraDescription) -> bool: + name = camera.name.strip() + if not name: + return False + if name.startswith("com.apple.avfoundation."): + return False + return not (":" in name and "." in name) + + def camera_label(camera: fc.CameraDescription) -> str: + if has_human_readable_name(camera): + return camera.name + + direction = camera.lens_direction.value.capitalize() + lens_map = { + "wide": "Wide", + "telephoto": "Telephoto", + "ultraWide": "Ultra Wide", + "unknown": "Unknown", + } + lens_type = lens_map.get(camera.lens_type.value, camera.lens_type.value) + return f"{direction} ({lens_type})" + + def device_orientation_degrees(orientation: ft.DeviceOrientation | None) -> int: + if orientation == ft.DeviceOrientation.PORTRAIT_UP: + return 0 + if orientation == ft.DeviceOrientation.LANDSCAPE_RIGHT: + return 90 + if orientation == ft.DeviceOrientation.PORTRAIT_DOWN: + return 180 + if orientation == ft.DeviceOrientation.LANDSCAPE_LEFT: + return 270 + return 0 + + def image_rotation_radians() -> float: + camera = state.selected_camera + if camera is None: + return 0.0 + sensor_orientation = camera.sensor_orientation + device_degrees = device_orientation_degrees(state.device_orientation) + if camera.lens_direction == fc.CameraLensDirection.FRONT: + rotation_degrees = (sensor_orientation + device_degrees) % 360 + else: + rotation_degrees = (sensor_orientation - device_degrees + 360) % 360 + return rotation_degrees * pi / 180 + + def apply_last_image_transform(src_width: int | None, src_height: int | None): + _ = (src_width, src_height) + last_image.width = image_frame_width + last_image.height = image_frame_height + + if page.platform != ft.PagePlatform.ANDROID: + last_image.offset = None + last_image.rotate = None + return + + angle = image_rotation_radians() + width = float(image_frame_width) + height = float(image_frame_height) + calc_angle = -angle + + # Flet uses clockwise radians for Rotate.angle. + def rotate_point(x: float, y: float) -> tuple[float, float]: + return ( + x * cos(calc_angle) + y * sin(calc_angle), + -x * sin(calc_angle) + y * cos(calc_angle), + ) + + corners = [ + rotate_point(0.0, 0.0), + rotate_point(width, 0.0), + rotate_point(0.0, height), + rotate_point(width, height), + ] + min_x = min(p[0] for p in corners) + min_y = min(p[1] for p in corners) + + # Control.offset is normalized by control width/height. + last_image.offset = ft.Offset( + x=(-min_x / width) if width else 0.0, + y=(-min_y / height) if height else 0.0, + ) + last_image.rotate = ft.Rotate(angle=angle, alignment=ft.Alignment.TOP_LEFT) + + async def get_cameras(): + state.cameras = await preview.get_available_cameras() + state.camera_labels.clear() + seen_labels: dict[str, int] = {} + for camera in state.cameras: + label = camera_label(camera) + seen_labels[label] = seen_labels.get(label, 0) + 1 + if seen_labels[label] > 1: + label = f"{label} {seen_labels[label]}" + state.camera_labels[camera.name] = label + + selector.options = [ + ft.DropdownOption(key=c.name, text=state.camera_labels[c.name]) + for c in state.cameras + ] + if selector.value and selector.value not in state.camera_labels: + selector.value = None + state.selected_camera = None + state.is_initialized = False + state.is_streaming = False + state.is_recording = False + state.is_recording_paused = False + state.is_preview_paused = False + state.is_streaming_supported = False + state.device_orientation = None + sync_action_buttons() + status.value = "Select a camera" + page.update() + + def sync_action_buttons(): + take_photo_btn.disabled = not state.is_initialized + record_btn.disabled = not state.is_initialized + record_btn.selected = state.is_recording + pause_recording_btn.selected = state.is_recording_paused + pause_recording_btn.disabled = not state.is_recording + stream_btn.selected = state.is_streaming + stream_btn.disabled = not ( + state.is_initialized and state.is_streaming_supported + ) + preview_btn.selected = not state.is_preview_paused + preview_btn.disabled = not state.is_initialized + + async def init_camera(e=None): + state.selected_camera = next( + (c for c in state.cameras if c.name == selector.value), + None, + ) + if not state.selected_camera: + status.value = "No camera selected" + return + + selected_label = state.camera_labels.get( + state.selected_camera.name, state.selected_camera.name + ) + status.value = f"Initializing {selected_label}" + status.update() + await preview.initialize( + description=state.selected_camera, + resolution_preset=fc.ResolutionPreset.MEDIUM, + enable_audio=True, + image_format_group=fc.ImageFormatGroup.JPEG, + ) + if not page.web: + try: + await preview.lock_capture_orientation() + except RuntimeError as ex: + logging.warning("Could not lock capture orientation: %s", ex) + state.is_initialized = True + state.is_streaming = False + state.is_streaming_supported = await preview.supports_image_streaming() + sync_action_buttons() + page.update() + + async def take_photo(): + if not state.is_initialized: + status.value = "Initialize camera first" + page.update() + return + data = await preview.take_picture() + last_image.src = data + apply_last_image_transform(state.last_frame_width, state.last_frame_height) + last_photo_label.visible = True + last_image_frame.visible = True + page.update() + + async def start_recording(): + if not state.is_initialized: + status.value = "Initialize camera first" + page.update() + return + await preview.prepare_for_video_recording() + await preview.start_video_recording() + state.is_recording = True + state.is_recording_paused = False + sync_action_buttons() + status.value = "Recording video..." + page.update() + + async def pause_recording(): + if not state.is_initialized or not state.is_recording: + return + await preview.pause_video_recording() + state.is_recording_paused = True + sync_action_buttons() + status.value = "Recording paused" + page.update() + + async def resume_recording(): + if not state.is_initialized or not state.is_recording: + return + await preview.resume_video_recording() + state.is_recording_paused = False + sync_action_buttons() + status.value = "Recording resumed" + page.update() + + async def stop_recording(): + if not state.is_initialized or not state.is_recording: + return + data = await preview.stop_video_recording() + state.is_recording = False + state.is_recording_paused = False + sync_action_buttons() + if not data: + status.value = "No video data returned" + page.update() + return + + ext = fc.detect_video_extension(data) + filename = f"recording_{datetime.now().strftime('%Y%m%d_%H%M%S')}.{ext}" + saved_path = await ft.FilePicker().save_file( + file_name=filename, + src_bytes=data, + ) + + kb_size = len(data) / 1024 + status.value = f"Video recorded: {kb_size:.1f} KB" + if saved_path: + recorded_video_path.value = f"Recorded video: {saved_path}" + else: + recorded_video_path.value = "Recorded video save canceled" + page.update() + + async def on_state_change(e: fc.CameraStateEvent): + if e.description == state.selected_camera: + state.device_orientation = e.device_orientation + state.is_recording = e.is_recording_video + state.is_recording_paused = e.is_recording_paused + state.is_streaming = e.is_streaming_images + state.is_preview_paused = e.is_preview_paused + sync_action_buttons() + if e.has_error: + status.value = f"Camera error: {e.error_description}" + elif e.is_taking_picture: + status.value = "Taking picture..." + elif e.is_recording_paused: + status.value = "Recording paused" + elif e.is_recording_video: + status.value = "Recording video..." + elif e.is_streaming_images: + status.value = "Streaming images..." + elif e.is_preview_paused: + status.value = "Preview paused" + else: + status.value = "Camera ready" + page.update() + + preview.on_state_change = on_state_change + selector.on_select = init_camera + + async def start_streaming(): + if not state.is_initialized: + status.value = "Initialize camera first" + page.update() + return + if not state.is_streaming_supported: + status.value = "Image streaming is not supported by this camera" + page.update() + return + await preview.start_image_stream() + state.is_streaming = True + sync_action_buttons() + page.update() + + async def stop_streaming(): + if not state.is_initialized: + return + await preview.stop_image_stream() + state.is_streaming = False + sync_action_buttons() + page.update() + + def on_stream_image(e: fc.CameraImageEvent): + try: + state.last_frame_width = e.width + state.last_frame_height = e.height + last_image.src = e.bytes + apply_last_image_transform(e.width, e.height) + last_photo_label.visible = True + last_image_frame.visible = True + page.update() + except Exception as ex: + logging.exception("Failed to render stream frame: %s", ex) + + preview.on_stream_image = on_stream_image + + async def pause_preview(): + if not state.is_initialized: + return + await preview.pause_preview() + state.is_preview_paused = True + sync_action_buttons() + page.update() + + async def resume_preview(): + if not state.is_initialized: + return + await preview.resume_preview() + state.is_preview_paused = False + sync_action_buttons() + page.update() + + async def toggle_recording(): + if state.is_recording: + await stop_recording() + else: + await start_recording() + + async def toggle_recording_pause(): + if state.is_recording_paused: + await resume_recording() + else: + await pause_recording() + + async def toggle_streaming(): + if state.is_streaming: + await stop_streaming() + else: + await start_streaming() + + async def toggle_preview(): + if state.is_preview_paused: + await resume_preview() + else: + await pause_preview() + + take_photo_btn.on_click = take_photo + record_btn.on_click = toggle_recording + pause_recording_btn.on_click = toggle_recording_pause + stream_btn.on_click = toggle_streaming + preview_btn.on_click = toggle_preview + + page.on_connect = get_cameras + + page.add( + ft.SafeArea( + content=ft.Column( + [ + ft.Row( + [ + selector, + ft.IconButton(ft.Icons.REFRESH, on_click=get_cameras), + ], + wrap=True, + ), + ft.Container( + height=320, + bgcolor=ft.Colors.BLACK, + border_radius=3, + content=preview, + ), + status, + ft.Row( + [ + take_photo_btn, + record_btn, + pause_recording_btn, + stream_btn, + preview_btn, + ], + wrap=True, + ), + recorded_video_path, + last_photo_label, + last_image_frame, + ] + ) + ) + ) + + await get_cameras() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/camera/example_1/pyproject.toml b/sdk/python/examples/extensions/camera/example_1/pyproject.toml new file mode 100644 index 0000000000..50b4785835 --- /dev/null +++ b/sdk/python/examples/extensions/camera/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "camera-example-1" +version = "1.0.0" +description = "Comprehensive camera demo with preview, photos, video recording, and streaming." +requires-python = ">=3.10" +keywords = ["camera", "photo", "video", "streaming", "device orientation", "media"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-camera"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Camera"] + +[tool.flet.metadata] +title = "Camera playground" +controls = ["SafeArea", "Column", "Row", "Container", "IconButton", "Dropdown", "Text", "Image", "FilledIconButton", "FilledTonalIconButton", "OutlinedIconButton", "Camera"] +layout_pattern = "control-panel" +complexity = "advanced" +features = ["camera initialization", "photo capture", "video recording", "record pause/resume", "image streaming", "preview pause/resume", "camera state events"] + +[tool.flet] +platforms = ["web", "ios", "android"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/bar_chart/example_1/main.py b/sdk/python/examples/extensions/charts/bar_chart/example_1/main.py new file mode 100644 index 0000000000..36955504a3 --- /dev/null +++ b/sdk/python/examples/extensions/charts/bar_chart/example_1/main.py @@ -0,0 +1,100 @@ +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=fch.BarChart( + expand=True, + interactive=True, + max_y=110, + border=ft.Border.all(1, ft.Colors.GREY_400), + horizontal_grid_lines=fch.ChartGridLines( + color=ft.Colors.GREY_300, width=1, dash_pattern=[3, 3] + ), + tooltip=fch.BarChartTooltip( + bgcolor=ft.Colors.with_opacity(0.5, ft.Colors.GREY_300), + border_radius=ft.BorderRadius.all(20), + ), + left_axis=fch.ChartAxis( + label_size=40, title=ft.Text("Fruit supply"), title_size=40 + ), + right_axis=fch.ChartAxis(show_labels=False), + bottom_axis=fch.ChartAxis( + label_size=40, + labels=[ + fch.ChartAxisLabel( + value=0, label=ft.Container(ft.Text("Apple"), padding=10) + ), + fch.ChartAxisLabel( + value=1, + label=ft.Container(ft.Text("Blueberry"), padding=10), + ), + fch.ChartAxisLabel( + value=2, label=ft.Container(ft.Text("Cherry"), padding=10) + ), + fch.ChartAxisLabel( + value=3, label=ft.Container(ft.Text("Orange"), padding=10) + ), + ], + ), + groups=[ + fch.BarChartGroup( + x=0, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=40, + width=40, + color=ft.Colors.GREEN, + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=1, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=100, + width=40, + color=ft.Colors.BLUE, + tooltip=fch.BarChartRodTooltip("Blueberry"), + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=2, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=30, + width=40, + color=ft.Colors.RED, + border_radius=0, + ), + ], + ), + fch.BarChartGroup( + x=3, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=60, + width=40, + color=ft.Colors.ORANGE, + tooltip=fch.BarChartRodTooltip("Orange"), + border_radius=0, + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/bar_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/bar_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..4514c98701 --- /dev/null +++ b/sdk/python/examples/extensions/charts/bar_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-bar-chart-example-1" +version = "1.0.0" +description = "Interactive bar chart showing fruit supply with custom axes, tooltips, and grid lines." +requires-python = ">=3.10" +keywords = ["charts", "bar-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/BarChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "BarChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/bar_chart/example_2/main.py b/sdk/python/examples/extensions/charts/bar_chart/example_2/main.py new file mode 100644 index 0000000000..c03f535fd5 --- /dev/null +++ b/sdk/python/examples/extensions/charts/bar_chart/example_2/main.py @@ -0,0 +1,75 @@ +import flet as ft +import flet_charts as fch + + +class CustomRod(fch.BarChartRod): + def __init__(self, y: float, hovered: bool = False): + super().__init__() + self.hovered = hovered + self.y = y + self.width = 22 + self.color = ft.Colors.WHITE + self.bg_to_y = 20 + self.bg_color = ft.Colors.GREEN_300 + + def before_update(self): + super().before_update() + self.to_y = self.y + 0.5 if self.hovered else self.y + self.color = ft.Colors.YELLOW if self.hovered else ft.Colors.WHITE + self.border_side = ( + ft.BorderSide(width=1, color=ft.Colors.RED) + if self.hovered + else ft.BorderSide(width=1, color=ft.Colors.BLUE) + ) + + +def main(page: ft.Page): + def on_chart_event(e: fch.BarChartEvent): + if e.type == fch.ChartEventType.POINTER_HOVER: + for group_index, group in enumerate(chart.groups): + for rod_index, rod in enumerate(group.rods): + rod.hovered = ( + e.group_index == group_index and e.rod_index == rod_index + ) + chart.update() + + chart = fch.BarChart( + on_event=on_chart_event, + interactive=True, + groups=[ + fch.BarChartGroup(x=0, rods=[CustomRod(5)]), + fch.BarChartGroup(x=1, rods=[CustomRod(6.5)]), + fch.BarChartGroup(x=2, rods=[CustomRod(15)]), + fch.BarChartGroup(x=3, rods=[CustomRod(7.5)]), + fch.BarChartGroup(x=4, rods=[CustomRod(9)]), + fch.BarChartGroup(x=5, rods=[CustomRod(11.5)]), + fch.BarChartGroup(x=6, rods=[CustomRod(6)]), + ], + bottom_axis=fch.ChartAxis( + labels=[ + fch.ChartAxisLabel(value=0, label=ft.Text("M", color=ft.Colors.BLUE)), + fch.ChartAxisLabel(value=1, label=ft.Text("T", color=ft.Colors.YELLOW)), + fch.ChartAxisLabel(value=2, label=ft.Text("W", color=ft.Colors.BLUE)), + fch.ChartAxisLabel(value=3, label=ft.Text("T", color=ft.Colors.YELLOW)), + fch.ChartAxisLabel(value=4, label=ft.Text("F", color=ft.Colors.BLUE)), + fch.ChartAxisLabel(value=5, label=ft.Text("S", color=ft.Colors.YELLOW)), + fch.ChartAxisLabel(value=6, label=ft.Text("S", color=ft.Colors.BLUE)), + ], + ), + ) + + page.add( + ft.SafeArea( + content=ft.Container( + bgcolor=ft.Colors.GREEN_200, + padding=10, + border_radius=5, + expand=True, + content=chart, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/bar_chart/example_2/pyproject.toml b/sdk/python/examples/extensions/charts/bar_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..4a3b548b99 --- /dev/null +++ b/sdk/python/examples/extensions/charts/bar_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-bar-chart-example-2" +version = "1.0.0" +description = "Bar chart with pointer-hover interaction that highlights individual rods dynamically." +requires-python = ">=3.10" +keywords = ["charts", "bar-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/BarChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "BarChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/bar_chart/media/example_1.png b/sdk/python/examples/extensions/charts/bar_chart/media/example_1.png new file mode 100644 index 0000000000..f078a20f3c Binary files /dev/null and b/sdk/python/examples/extensions/charts/bar_chart/media/example_1.png differ diff --git a/sdk/python/examples/extensions/charts/bar_chart/media/example_2.gif b/sdk/python/examples/extensions/charts/bar_chart/media/example_2.gif new file mode 100644 index 0000000000..e21fbc62ba Binary files /dev/null and b/sdk/python/examples/extensions/charts/bar_chart/media/example_2.gif differ diff --git a/sdk/python/examples/extensions/charts/candlestick_chart/example_1/main.py b/sdk/python/examples/extensions/charts/candlestick_chart/example_1/main.py new file mode 100644 index 0000000000..342be7df31 --- /dev/null +++ b/sdk/python/examples/extensions/charts/candlestick_chart/example_1/main.py @@ -0,0 +1,130 @@ +import flet as ft +import flet_charts as fch + +CANDLE_DATA = [ + ("Mon", 24.8, 28.6, 23.9, 27.2), + ("Tue", 27.2, 30.1, 25.8, 28.4), + ("Wed", 28.4, 31.2, 26.5, 29.1), + ("Thu", 29.1, 32.4, 27.9, 31.8), + ("Fri", 31.8, 34.0, 29.7, 30.2), + ("Sat", 30.2, 33.6, 28.3, 32.7), + ("Sun", 32.7, 35.5, 30.1, 34.6), +] + + +def build_spots() -> list[fch.CandlestickChartSpot]: + """Create candlestick spots from the static data.""" + spots: list[fch.CandlestickChartSpot] = [] + for index, (label, open_, high, low, close) in enumerate(CANDLE_DATA): + spots.append( + fch.CandlestickChartSpot( + x=float(index), + open=open_, + high=high, + low=low, + close=close, + selected=index == len(CANDLE_DATA) - 1, + tooltip=fch.CandlestickChartSpotTooltip( + text=( + f"{label}\n" + f"Open: {open_:0.1f}\n" + f"High: {high:0.1f}\n" + f"Low : {low:0.1f}\n" + f"Close: {close:0.1f}" + ), + bottom_margin=12, + ), + ) + ) + return spots + + +def main(page: ft.Page): + page.title = "Candlestick chart" + page.padding = 24 + page.theme_mode = ft.ThemeMode.DARK + + info = ft.Text("Interact with the chart to see event details.") + + spots = build_spots() + min_x = -0.5 + max_x = len(spots) - 0.5 + min_y = min(low for _, _, _, low, _ in CANDLE_DATA) - 1 + max_y = max(high for _, _, _, _, high in CANDLE_DATA) + 1 + + def handle_event(e: fch.CandlestickChartEvent): + if e.spot_index is not None and e.spot_index >= 0: + label, open_, high, low, close = CANDLE_DATA[e.spot_index] + info.value = ( + f"{e.type.value} • {label}: " + f"O {open_:0.1f} H {high:0.1f} L {low:0.1f} C {close:0.1f}" + ) + else: + info.value = f"{e.type.value} • outside candlesticks" + info.update() + + chart = fch.CandlestickChart( + expand=True, + min_x=min_x, + max_x=max_x, + min_y=min_y, + max_y=max_y, + baseline_x=0, + baseline_y=min_y, + bgcolor=ft.Colors.with_opacity(0.2, ft.Colors.BLUE_GREY_900), + horizontal_grid_lines=fch.ChartGridLines(interval=2, dash_pattern=[2, 2]), + vertical_grid_lines=fch.ChartGridLines(interval=1, dash_pattern=[2, 2]), + left_axis=fch.ChartAxis( + label_spacing=2, + label_size=60, + title=ft.Text("Price (k USD)", color=ft.Colors.GREY_300), + show_min=False, + ), + bottom_axis=fch.ChartAxis( + labels=[ + fch.ChartAxisLabel( + value=index, + label=ft.Text(name, color=ft.Colors.GREY_300), + ) + for index, (name, *_rest) in enumerate(CANDLE_DATA) + ], + label_spacing=1, + label_size=40, + show_min=False, + show_max=False, + ), + spots=spots, + tooltip=fch.CandlestickChartTooltip( + bgcolor=ft.Colors.BLUE_GREY_800, + horizontal_alignment=fch.HorizontalAlignment.CENTER, + fit_inside_horizontally=True, + ), + on_event=handle_event, + ) + + page.add( + ft.SafeArea( + content=ft.Container( + expand=True, + border_radius=16, + padding=20, + content=ft.Column( + expand=True, + spacing=20, + controls=[ + ft.Text( + "Weekly OHLC snapshot (demo data)", + size=20, + weight=ft.FontWeight.BOLD, + ), + chart, + info, + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/candlestick_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/candlestick_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..cc4fe18069 --- /dev/null +++ b/sdk/python/examples/extensions/charts/candlestick_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-candlestick-chart-example-1" +version = "1.0.0" +description = "Candlestick chart visualizing weekly OHLC data with labeled axes and event-driven tooltips." +requires-python = ">=3.10" +keywords = ["charts", "candlestick-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/CandlestickChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "CandlestickChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/candlestick_chart/media/example_1.png b/sdk/python/examples/extensions/charts/candlestick_chart/media/example_1.png new file mode 100644 index 0000000000..2563a3ff1c Binary files /dev/null and b/sdk/python/examples/extensions/charts/candlestick_chart/media/example_1.png differ diff --git a/sdk/python/examples/extensions/charts/line_chart/dashboard_declarative/main.py b/sdk/python/examples/extensions/charts/line_chart/dashboard_declarative/main.py new file mode 100644 index 0000000000..88dda9002d --- /dev/null +++ b/sdk/python/examples/extensions/charts/line_chart/dashboard_declarative/main.py @@ -0,0 +1,144 @@ +import asyncio +import random +from dataclasses import dataclass, field + +import flet as ft +import flet_charts as ft_charts + +MAX_POINTS = 20 + + +@dataclass +class DataPoint: + x: float + y: float + + +@dataclass +@ft.observable +class ChartData: + x: float = 0.0 + min_y: float = 0.0 + max_y: float = 1.0 + points: list[DataPoint] = field(default_factory=list) + + def __post_init__(self): + for _ in range(MAX_POINTS): + self.add_point() + + def add_point(self): + self.points.append( + DataPoint(x=self.x, y=random.uniform(self.min_y, self.max_y)) + ) + self.x += 0.5 + if len(self.points) > MAX_POINTS: + self.points.pop(0) + + +@ft.component +def Gauge( + min_y: float = 0.0, + max_y: float = 1.0, + width: int = 200, + height: int = 150, + line_color=ft.Colors.BLUE, + bgcolor=ft.Colors.BLUE_100, +): + chart_data, _ = ft.use_state(lambda: ChartData(min_y=min_y, max_y=max_y)) + + async def generate_chart_data(): + for _ in range(0, 100): + chart_data.add_point() + await asyncio.sleep(1.0) + + ft.on_mounted(generate_chart_data) + + return ft_charts.LineChart( + data_series=[ + ft_charts.LineChartData( + stroke_width=2, + color=line_color, + curved=True, + points=[ + ft_charts.LineChartDataPoint( + key=point.x, + x=point.x, + y=point.y, + selected_point=ft_charts.ChartCirclePoint(radius=4), + selected_below_line=False, + tooltip=f"{round(point.y, 2)}%", + ) + for point in chart_data.points + ], + below_line_bgcolor=bgcolor, + ) + ], + border=ft.Border.all(1, ft.Colors.GREY_400), + horizontal_grid_lines=ft_charts.ChartGridLines( + color=ft.Colors.GREY_300, width=1, dash_pattern=[3, 3], interval=0.1 + ), + tooltip=ft_charts.LineChartTooltip( + bgcolor=ft.Colors.BLACK_12, + border_radius=4, + padding=ft.Padding(5), + ), + min_y=0, + max_y=1, + width=width, + height=height, + animation=ft.Animation(duration=0), + ) + + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Row( + controls=[ + ft.Column( + [ + ft.Text("CPU Usage"), + Gauge( + min_y=0.3, + max_y=1.0, + line_color=ft.Colors.BLUE, + bgcolor=ft.Colors.BLUE_100, + ), + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + ft.Column( + [ + ft.Text("Memory Usage"), + Gauge( + min_y=0.2, + max_y=0.5, + line_color=ft.Colors.GREEN, + bgcolor=ft.Colors.GREEN_100, + ), + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + ft.Column( + [ + ft.Text("Disk Usage"), + Gauge( + min_y=0.7, + max_y=0.9, + line_color=ft.Colors.ORANGE, + bgcolor=ft.Colors.ORANGE_100, + ), + ], + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + ), + ] + ), + ) + + +def main(page: ft.Page): + page.render(App) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/line_chart/dashboard_declarative/pyproject.toml b/sdk/python/examples/extensions/charts/line_chart/dashboard_declarative/pyproject.toml new file mode 100644 index 0000000000..92a3d983ca --- /dev/null +++ b/sdk/python/examples/extensions/charts/line_chart/dashboard_declarative/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-line-chart-dashboard-declarative" +version = "1.0.0" +description = "Declarative dashboard with live-updating line chart gauges for CPU, memory, and disk usage." +requires-python = ">=3.10" +keywords = ["charts", "line-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/LineChart", "Declarative"] + +[tool.flet.metadata] +title = "Dashboard Declarative" +controls = ["SafeArea", "LineChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/line_chart/example_1/main.py b/sdk/python/examples/extensions/charts/line_chart/example_1/main.py new file mode 100644 index 0000000000..5721e35204 --- /dev/null +++ b/sdk/python/examples/extensions/charts/line_chart/example_1/main.py @@ -0,0 +1,215 @@ +import flet as ft +import flet_charts as fch + + +class State: + toggled = True + + +state = State() + + +def main(page: ft.Page): + data_1 = [ + fch.LineChartData( + stroke_width=8, + color=ft.Colors.LIGHT_GREEN, + curved=True, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 1.5), + fch.LineChartDataPoint(5, 1.4), + fch.LineChartDataPoint(7, 3.4), + fch.LineChartDataPoint(10, 2), + fch.LineChartDataPoint(12, 2.2), + fch.LineChartDataPoint(13, 1.8), + ], + ), + fch.LineChartData( + color=ft.Colors.PINK, + below_line_bgcolor=ft.Colors.with_opacity(0, ft.Colors.PINK), + stroke_width=8, + curved=True, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 2.8), + fch.LineChartDataPoint(7, 1.2), + fch.LineChartDataPoint(10, 2.8), + fch.LineChartDataPoint(12, 2.6), + fch.LineChartDataPoint(13, 3.9), + ], + ), + fch.LineChartData( + color=ft.Colors.CYAN, + stroke_width=8, + curved=True, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(1, 2.8), + fch.LineChartDataPoint(3, 1.9), + fch.LineChartDataPoint(6, 3), + fch.LineChartDataPoint(10, 1.3), + fch.LineChartDataPoint(13, 2.5), + ], + ), + ] + + data_2 = [ + fch.LineChartData( + stroke_width=4, + color=ft.Colors.with_opacity(0.5, ft.Colors.LIGHT_GREEN), + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 4), + fch.LineChartDataPoint(5, 1.8), + fch.LineChartDataPoint(7, 5), + fch.LineChartDataPoint(10, 2), + fch.LineChartDataPoint(12, 2.2), + fch.LineChartDataPoint(13, 1.8), + ], + ), + fch.LineChartData( + color=ft.Colors.with_opacity(0.5, ft.Colors.PINK), + below_line_bgcolor=ft.Colors.with_opacity(0.2, ft.Colors.PINK), + stroke_width=4, + curved=True, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(1, 1), + fch.LineChartDataPoint(3, 2.8), + fch.LineChartDataPoint(7, 1.2), + fch.LineChartDataPoint(10, 2.8), + fch.LineChartDataPoint(12, 2.6), + fch.LineChartDataPoint(13, 3.9), + ], + ), + fch.LineChartData( + color=ft.Colors.with_opacity(0.5, ft.Colors.CYAN), + stroke_width=4, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(1, 3.8), + fch.LineChartDataPoint(3, 1.9), + fch.LineChartDataPoint(6, 5), + fch.LineChartDataPoint(10, 3.3), + fch.LineChartDataPoint(13, 4.5), + ], + ), + ] + + chart = fch.LineChart( + data_series=data_1, + border=ft.Border( + bottom=ft.BorderSide(4, ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE)) + ), + tooltip=fch.LineChartTooltip( + bgcolor=ft.Colors.with_opacity(0.8, ft.Colors.BLUE_GREY) + ), + min_y=0, + max_y=4, + min_x=0, + max_x=14, + expand=True, + right_axis=fch.ChartAxis(show_labels=False), + left_axis=fch.ChartAxis( + label_size=40, + labels=[ + fch.ChartAxisLabel( + value=1, + label=ft.Text("1m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=2, + label=ft.Text("2m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=3, + label=ft.Text("3m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=4, + label=ft.Text("4m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=5, + label=ft.Text("5m", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=6, + label=ft.Text("6m", size=14, weight=ft.FontWeight.BOLD), + ), + ], + ), + bottom_axis=fch.ChartAxis( + label_size=32, + labels=[ + fch.ChartAxisLabel( + value=2, + label=ft.Container( + margin=ft.Margin(top=10), + content=ft.Text( + value="SEP", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE), + ), + ), + ), + fch.ChartAxisLabel( + value=7, + label=ft.Container( + margin=ft.Margin(top=10), + content=ft.Text( + value="OCT", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE), + ), + ), + ), + fch.ChartAxisLabel( + value=12, + label=ft.Container( + margin=ft.Margin(top=10), + content=ft.Text( + value="DEC", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE), + ), + ), + ), + ], + ), + ) + + def toggle_data(e: ft.Event[ft.IconButton]): + if state.toggled: + chart.data_series = data_2 + chart.data_series[2].point = True + chart.max_y = 6 + chart.interactive = False + else: + chart.data_series = data_1 + chart.max_y = 4 + chart.interactive = True + state.toggled = not state.toggled + chart.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.IconButton(ft.Icons.REFRESH, on_click=toggle_data), + chart, + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/line_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/line_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..54d4d14a4f --- /dev/null +++ b/sdk/python/examples/extensions/charts/line_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-line-chart-example-1" +version = "1.0.0" +description = "Interactive multi-series line chart that toggles between detailed and simplified datasets." +requires-python = ">=3.10" +keywords = ["charts", "line-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/LineChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "LineChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/line_chart/example_2/main.py b/sdk/python/examples/extensions/charts/line_chart/example_2/main.py new file mode 100644 index 0000000000..e4dffef422 --- /dev/null +++ b/sdk/python/examples/extensions/charts/line_chart/example_2/main.py @@ -0,0 +1,149 @@ +import flet as ft +import flet_charts as fch + + +class State: + toggled = True + + +state = State() + + +def main(page: ft.Page): + data_1 = [ + fch.LineChartData( + stroke_width=5, + color=ft.Colors.CYAN, + curved=True, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(0, 3), + fch.LineChartDataPoint(2.6, 2), + fch.LineChartDataPoint(4.9, 5), + fch.LineChartDataPoint(6.8, 3.1), + fch.LineChartDataPoint(8, 4), + fch.LineChartDataPoint(9.5, 3), + fch.LineChartDataPoint(11, 4), + ], + ) + ] + + data_2 = [ + fch.LineChartData( + stroke_width=5, + color=ft.Colors.CYAN, + curved=True, + rounded_stroke_cap=True, + points=[ + fch.LineChartDataPoint(0, 3.44), + fch.LineChartDataPoint(2.6, 3.44), + fch.LineChartDataPoint(4.9, 3.44), + fch.LineChartDataPoint(6.8, 3.44), + fch.LineChartDataPoint(8, 3.44), + fch.LineChartDataPoint(9.5, 3.44), + fch.LineChartDataPoint(11, 3.44), + ], + ) + ] + + chart = fch.LineChart( + expand=True, + data_series=data_1, + min_y=0, + max_y=6, + min_x=0, + max_x=11, + border=ft.Border.all(3, ft.Colors.with_opacity(0.2, ft.Colors.ON_SURFACE)), + horizontal_grid_lines=fch.ChartGridLines( + interval=1, color=ft.Colors.with_opacity(0.2, ft.Colors.ON_SURFACE), width=1 + ), + vertical_grid_lines=fch.ChartGridLines( + interval=1, color=ft.Colors.with_opacity(0.2, ft.Colors.ON_SURFACE), width=1 + ), + tooltip=fch.LineChartTooltip( + bgcolor=ft.Colors.with_opacity(0.8, ft.Colors.BLUE_GREY) + ), + left_axis=fch.ChartAxis( + label_size=40, + labels=[ + fch.ChartAxisLabel( + value=1, + label=ft.Text("10K", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=3, + label=ft.Text("30K", size=14, weight=ft.FontWeight.BOLD), + ), + fch.ChartAxisLabel( + value=5, + label=ft.Text("50K", size=14, weight=ft.FontWeight.BOLD), + ), + ], + ), + bottom_axis=fch.ChartAxis( + label_size=32, + labels=[ + fch.ChartAxisLabel( + value=2, + label=ft.Container( + margin=ft.Margin(top=10), + content=ft.Text( + value="MAR", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE), + ), + ), + ), + fch.ChartAxisLabel( + value=5, + label=ft.Container( + margin=ft.Margin(top=10), + content=ft.Text( + value="JUN", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE), + ), + ), + ), + fch.ChartAxisLabel( + value=8, + label=ft.Container( + margin=ft.Margin(top=10), + content=ft.Text( + value="SEP", + size=16, + weight=ft.FontWeight.BOLD, + color=ft.Colors.with_opacity(0.5, ft.Colors.ON_SURFACE), + ), + ), + ), + ], + ), + ) + + def toggle_data(e: ft.Event[ft.ElevatedButton]): + if state.toggled: + chart.data_series = data_2 + chart.interactive = False + else: + chart.data_series = data_1 + chart.interactive = True + state.toggled = not state.toggled + chart.update() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("avg", on_click=toggle_data), + chart, + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/line_chart/example_2/pyproject.toml b/sdk/python/examples/extensions/charts/line_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..4cf6bc1838 --- /dev/null +++ b/sdk/python/examples/extensions/charts/line_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-line-chart-example-2" +version = "1.0.0" +description = "Line chart with custom axis labels and button-triggered switching between trend and average views." +requires-python = ">=3.10" +keywords = ["charts", "line-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/LineChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "LineChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/line_chart/media/example_1.gif b/sdk/python/examples/extensions/charts/line_chart/media/example_1.gif new file mode 100644 index 0000000000..00f0f16d25 Binary files /dev/null and b/sdk/python/examples/extensions/charts/line_chart/media/example_1.gif differ diff --git a/sdk/python/examples/extensions/charts/line_chart/media/example_2.gif b/sdk/python/examples/extensions/charts/line_chart/media/example_2.gif new file mode 100644 index 0000000000..38b70098d2 Binary files /dev/null and b/sdk/python/examples/extensions/charts/line_chart/media/example_2.gif differ diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/animate/main.py b/sdk/python/examples/extensions/charts/matplotlib_chart/animate/main.py new file mode 100644 index 0000000000..24c820419a --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/animate/main.py @@ -0,0 +1,62 @@ +import logging + +import matplotlib.pyplot as plt +import numpy as np + +import flet as ft +import flet_charts + +logging.basicConfig(level=logging.INFO) + +state = {} + + +def main(page: ft.Page): + import matplotlib.animation as animation + + # Fixing random state for reproducibility + np.random.seed(19680801) + + def random_walk(num_steps, max_step=0.05): + """Return a 3D random walk as (num_steps, 3) array.""" + start_pos = np.random.random(3) + steps = np.random.uniform(-max_step, max_step, size=(num_steps, 3)) + walk = start_pos + np.cumsum(steps, axis=0) + return walk + + def update_lines(num, walks, lines): + for line, walk in zip(lines, walks): + line.set_data_3d(walk[:num, :].T) + return lines + + # Data: 40 random walks as (num_steps, 3) arrays + num_steps = 30 + walks = [random_walk(num_steps) for index in range(40)] + + # Attaching 3D axis to the figure + fig = plt.figure() + ax = fig.add_subplot(projection="3d") + + # Create lines initially without data + lines = [ax.plot([], [], [])[0] for _ in walks] + + # Setting the Axes properties + ax.set(xlim3d=(0, 1), xlabel="X") + ax.set(ylim3d=(0, 1), ylabel="Y") + ax.set(zlim3d=(0, 1), zlabel="Z") + + # Creating the Animation object + state["anim"] = animation.FuncAnimation( + fig, update_lines, num_steps, fargs=(walks, lines), interval=100 + ) + + page.add( + ft.SafeArea( + expand=True, + content=flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/animate/pyproject.toml b/sdk/python/examples/extensions/charts/matplotlib_chart/animate/pyproject.toml new file mode 100644 index 0000000000..6f85b24086 --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/animate/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-animate" +version = "1.0.0" +description = "Animated 3D random-walk Matplotlib chart embedded in a Flet application." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Animate" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["animated chart", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/bar_chart/main.py b/sdk/python/examples/extensions/charts/matplotlib_chart/bar_chart/main.py new file mode 100644 index 0000000000..edd9252dc8 --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/bar_chart/main.py @@ -0,0 +1,30 @@ +import matplotlib.pyplot as plt + +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + fig, ax = plt.subplots() + + fruits = ["apple", "blueberry", "cherry", "orange"] + counts = [40, 100, 30, 55] + bar_labels = ["red", "blue", "_red", "orange"] + bar_colors = ["tab:red", "tab:blue", "tab:red", "tab:orange"] + + ax.bar(fruits, counts, label=bar_labels, color=bar_colors) + + ax.set_ylabel("fruit supply") + ax.set_title("Fruit supply by kind and color") + ax.legend(title="Fruit color") + + page.add( + ft.SafeArea( + expand=True, + content=fch.MatplotlibChart(figure=fig, expand=True), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/bar_chart/pyproject.toml b/sdk/python/examples/extensions/charts/matplotlib_chart/bar_chart/pyproject.toml new file mode 100644 index 0000000000..e926721e7c --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/bar_chart/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-bar-chart" +version = "1.0.0" +description = "Matplotlib bar chart example with categorical data, labels, and legend integration." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Bar Chart" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/handle_events/main.py b/sdk/python/examples/extensions/charts/matplotlib_chart/handle_events/main.py new file mode 100644 index 0000000000..2c0541ae5b --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/handle_events/main.py @@ -0,0 +1,109 @@ +import matplotlib.pyplot as plt +import numpy as np + +import flet as ft +import flet_charts as fch + +state = {} + + +def main(page: ft.Page): + # Fixing random state for reproducibility + np.random.seed(19680801) + + X = np.random.rand(100, 200) + xs = np.mean(X, axis=1) + ys = np.std(X, axis=1) + + fig, (ax, ax2) = plt.subplots(2, 1) + ax.set_title("click on point to plot time series") + (line,) = ax.plot(xs, ys, "o", picker=True, pickradius=5) + + class PointBrowser: + """ + Click on a point to select and highlight it -- the data that + generated the point will be shown in the lower Axes. Use the 'n' + and 'p' keys to browse through the next and previous points + """ + + def __init__(self): + self.lastind = 0 + + self.text = ax.text( + 0.05, 0.95, "selected: none", transform=ax.transAxes, va="top" + ) + (self.selected,) = ax.plot( + [xs[0]], [ys[0]], "o", ms=12, alpha=0.4, color="yellow", visible=False + ) + + def on_press(self, event): + if self.lastind is None: + return + if event.key not in ("n", "p"): + return + inc = 1 if event.key == "n" else -1 + + self.lastind += inc + self.lastind = np.clip(self.lastind, 0, len(xs) - 1) + self.update() + + def on_pick(self, event): + if event.artist != line: + return True + + N = len(event.ind) + if not N: + return True + + # the click locations + x = event.mouseevent.xdata + y = event.mouseevent.ydata + + distances = np.hypot(x - xs[event.ind], y - ys[event.ind]) + indmin = distances.argmin() + dataind = event.ind[indmin] + + self.lastind = dataind + self.update() + + def update(self): + if self.lastind is None: + return + + dataind = self.lastind + + ax2.clear() + ax2.plot(X[dataind]) + + ax2.text( + 0.05, + 0.9, + f"mu={xs[dataind]:1.3f}\nsigma={ys[dataind]:1.3f}", + transform=ax2.transAxes, + va="top", + ) + ax2.set_ylim(-0.5, 1.5) + self.selected.set_visible(True) + self.selected.set_data([xs[dataind]], [ys[dataind]]) + + self.text.set_text(f"selected: {dataind:d}") + fig.canvas.draw() + + browser = PointBrowser() + state["browser"] = browser + + fig.canvas.mpl_connect("pick_event", browser.on_pick) + fig.canvas.mpl_connect("key_press_event", browser.on_press) + + # plt.show() + + page.add( + ft.SafeArea( + expand=True, + content=fch.MatplotlibChartWithToolbar(figure=fig, expand=True), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/handle_events/pyproject.toml b/sdk/python/examples/extensions/charts/matplotlib_chart/handle_events/pyproject.toml new file mode 100644 index 0000000000..9e577cecfa --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/handle_events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-handle-events" +version = "1.0.0" +description = "Matplotlib chart demonstrating pick and keyboard events to inspect selected data points." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Handle Events" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["event handling", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/media/3d.png b/sdk/python/examples/extensions/charts/matplotlib_chart/media/3d.png new file mode 100644 index 0000000000..4b650fed36 Binary files /dev/null and b/sdk/python/examples/extensions/charts/matplotlib_chart/media/3d.png differ diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/media/animate.png b/sdk/python/examples/extensions/charts/matplotlib_chart/media/animate.png new file mode 100644 index 0000000000..05e9c6bf21 Binary files /dev/null and b/sdk/python/examples/extensions/charts/matplotlib_chart/media/animate.png differ diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/media/bar_chart.png b/sdk/python/examples/extensions/charts/matplotlib_chart/media/bar_chart.png new file mode 100644 index 0000000000..9c56e7130c Binary files /dev/null and b/sdk/python/examples/extensions/charts/matplotlib_chart/media/bar_chart.png differ diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/media/handle_events.png b/sdk/python/examples/extensions/charts/matplotlib_chart/media/handle_events.png new file mode 100644 index 0000000000..44c1e604ab Binary files /dev/null and b/sdk/python/examples/extensions/charts/matplotlib_chart/media/handle_events.png differ diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/media/toolbar.png b/sdk/python/examples/extensions/charts/matplotlib_chart/media/toolbar.png new file mode 100644 index 0000000000..31315f8633 Binary files /dev/null and b/sdk/python/examples/extensions/charts/matplotlib_chart/media/toolbar.png differ diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py b/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py new file mode 100644 index 0000000000..9cc1c2084d --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/main.py @@ -0,0 +1,48 @@ +import logging + +import matplotlib.pyplot as plt + +import flet as ft +import flet_charts + +logging.basicConfig(level=logging.INFO) + + +def main(page: ft.Page): + from mpl_toolkits.mplot3d import axes3d + + fig = plt.figure() + ax = fig.add_subplot(projection="3d") + X, Y, Z = axes3d.get_test_data(0.1) + + # Plot the 3D surface + ax.plot_surface( + X, Y, Z, edgecolor="royalblue", lw=0.5, rstride=8, cstride=8, alpha=0.3 + ) + + # Plot projections of the contours for each dimension. By choosing offsets + # that match the appropriate axes limits, the projected contours will sit on + # the 'walls' of the graph + ax.contourf(X, Y, Z, zdir="z", offset=-100, cmap="coolwarm") + ax.contourf(X, Y, Z, zdir="x", offset=-40, cmap="coolwarm") + ax.contourf(X, Y, Z, zdir="y", offset=40, cmap="coolwarm") + + ax.set( + xlim=(-40, 40), + ylim=(-40, 40), + zlim=(-100, 100), + xlabel="X", + ylabel="Y", + zlabel="Z", + ) + + page.add( + ft.SafeArea( + content=flet_charts.MatplotlibChartWithToolbar(figure=fig, expand=True), + expand=True, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/pyproject.toml b/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/pyproject.toml new file mode 100644 index 0000000000..252c4b2eb2 --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/three_d/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-three-d" +version = "1.0.0" +description = "Matplotlib 3D chart rendering a double-helix-style surface and line composition." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Three D" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["3d chart", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/toolbar/main.py b/sdk/python/examples/extensions/charts/matplotlib_chart/toolbar/main.py new file mode 100644 index 0000000000..b27ca768fd --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/toolbar/main.py @@ -0,0 +1,42 @@ +import matplotlib.pyplot as plt +import numpy as np + +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + # Fixing random state for reproducibility + np.random.seed(19680801) + + dt = 0.01 + t = np.arange(0, 30, dt) + nse1 = np.random.randn(len(t)) # white noise 1 + nse2 = np.random.randn(len(t)) # white noise 2 + + # Two signals with a coherent part at 10Hz and a random part + s1 = np.sin(2 * np.pi * 10 * t) + nse1 + s2 = np.sin(2 * np.pi * 10 * t) + nse2 + + fig, axs = plt.subplots(2, 1) + axs[0].plot(t, s1, t, s2) + axs[0].set_xlim(0, 2) + axs[0].set_xlabel("time") + axs[0].set_ylabel("s1 and s2") + axs[0].grid(True) + + cxy, f = axs[1].cohere(s1, s2, 256, 1.0 / dt) + axs[1].set_ylabel("coherence") + + fig.tight_layout() + + page.add( + ft.SafeArea( + expand=True, + content=fch.MatplotlibChartWithToolbar(figure=fig, expand=True), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/matplotlib_chart/toolbar/pyproject.toml b/sdk/python/examples/extensions/charts/matplotlib_chart/toolbar/pyproject.toml new file mode 100644 index 0000000000..d2ba114e9e --- /dev/null +++ b/sdk/python/examples/extensions/charts/matplotlib_chart/toolbar/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-matplotlib-chart-toolbar" +version = "1.0.0" +description = "Matplotlib chart with built-in toolbar for panning, zooming, and data exploration." +requires-python = ">=3.10" +keywords = ["charts", "matplotlib-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "matplotlib", "numpy"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/MatplotlibChart"] + +[tool.flet.metadata] +title = "Toolbar" +controls = ["SafeArea", "MatplotlibChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization", "interactive toolbar", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/pie_chart/example_1/main.py b/sdk/python/examples/extensions/charts/pie_chart/example_1/main.py new file mode 100644 index 0000000000..dd909aa49b --- /dev/null +++ b/sdk/python/examples/extensions/charts/pie_chart/example_1/main.py @@ -0,0 +1,53 @@ +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + normal_border = ft.BorderSide(0, ft.Colors.with_opacity(0, ft.Colors.WHITE)) + hovered_border = ft.BorderSide(6, ft.Colors.SECONDARY) + + def on_chart_event(e: fch.PieChartEvent): + for idx, section in enumerate(chart.sections): + section.border_side = ( + hovered_border if idx == e.section_index else normal_border + ) + chart.update() + + chart = fch.PieChart( + sections_space=1, + center_space_radius=0, + on_event=on_chart_event, + expand=True, + sections=[ + fch.PieChartSection( + value=25, + color=ft.Colors.BLUE, + radius=80, + border_side=normal_border, + ), + fch.PieChartSection( + value=25, + color=ft.Colors.YELLOW, + radius=65, + border_side=normal_border, + ), + fch.PieChartSection( + value=25, + color=ft.Colors.PINK, + radius=60, + border_side=normal_border, + ), + fch.PieChartSection( + value=25, + color=ft.Colors.GREEN, + radius=70, + border_side=normal_border, + ), + ], + ) + + page.add(ft.SafeArea(content=chart)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/pie_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/pie_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..f47f2d8d92 --- /dev/null +++ b/sdk/python/examples/extensions/charts/pie_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-pie-chart-example-1" +version = "1.0.0" +description = "Pie chart with hover-sensitive section borders for interactive emphasis." +requires-python = ">=3.10" +keywords = ["charts", "pie-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PieChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "PieChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/pie_chart/example_2/main.py b/sdk/python/examples/extensions/charts/pie_chart/example_2/main.py new file mode 100644 index 0000000000..fc58e9be39 --- /dev/null +++ b/sdk/python/examples/extensions/charts/pie_chart/example_2/main.py @@ -0,0 +1,69 @@ +import flet as ft +import flet_charts as fch + +NORMAL_RADIUS = 50 +HOVER_RADIUS = 60 +NORMAL_TITLE_STYLE = ft.TextStyle( + size=16, color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD +) +HOVER_TITLE_STYLE = ft.TextStyle( + size=22, + color=ft.Colors.WHITE, + weight=ft.FontWeight.BOLD, + shadow=ft.BoxShadow(blur_radius=2, color=ft.Colors.BLACK_54), +) + + +def main(page: ft.Page): + def on_chart_event(e: fch.PieChartEvent): + for idx, section in enumerate(chart.sections): + if idx == e.section_index: + section.radius = HOVER_RADIUS + section.title_style = HOVER_TITLE_STYLE + else: + section.radius = NORMAL_RADIUS + section.title_style = NORMAL_TITLE_STYLE + chart.update() + + chart = fch.PieChart( + expand=True, + sections_space=0, + center_space_radius=40, + on_event=on_chart_event, + sections=[ + fch.PieChartSection( + value=40, + title="40%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.BLUE, + radius=NORMAL_RADIUS, + ), + fch.PieChartSection( + value=30, + title="30%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.YELLOW, + radius=NORMAL_RADIUS, + ), + fch.PieChartSection( + value=15, + title="15%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.PURPLE, + radius=NORMAL_RADIUS, + ), + fch.PieChartSection( + value=15, + title="15%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.GREEN, + radius=NORMAL_RADIUS, + ), + ], + ) + + page.add(ft.SafeArea(content=chart)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/pie_chart/example_2/pyproject.toml b/sdk/python/examples/extensions/charts/pie_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..caa7187d66 --- /dev/null +++ b/sdk/python/examples/extensions/charts/pie_chart/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-pie-chart-example-2" +version = "1.0.0" +description = "Pie chart with interactive section radius and title styling on hover." +requires-python = ">=3.10" +keywords = ["charts", "pie-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PieChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "PieChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/pie_chart/example_3/main.py b/sdk/python/examples/extensions/charts/pie_chart/example_3/main.py new file mode 100644 index 0000000000..6f4c0b204c --- /dev/null +++ b/sdk/python/examples/extensions/charts/pie_chart/example_3/main.py @@ -0,0 +1,91 @@ +import flet as ft +import flet_charts as fch + +NORMAL_RADIUS = 100 +HOVER_RADIUS = 110 +NORMAL_TITLE_STYLE = ft.TextStyle( + size=12, color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD +) +HOVER_TITLE_STYLE = ft.TextStyle( + size=16, + color=ft.Colors.WHITE, + weight=ft.FontWeight.BOLD, + shadow=ft.BoxShadow(blur_radius=2, color=ft.Colors.BLACK_54), +) +NORMAL_BADGE_SIZE = 40 +HOVER_BADGE_SIZE = 50 + + +class SectionBadge(ft.Container): + def __init__(self, icon: ft.IconData, size: int = NORMAL_BADGE_SIZE): + super().__init__( + content=ft.Icon(icon), + width=size, + height=size, + border=ft.Border.all(1, ft.Colors.BROWN), + border_radius=size / 2, + bgcolor=ft.Colors.WHITE, + ) + + +def main(page: ft.Page): + def on_chart_event(e: fch.PieChartEvent): + for idx, section in enumerate(chart.sections): + if idx == e.section_index: + section.radius = HOVER_RADIUS + section.title_style = HOVER_TITLE_STYLE + else: + section.radius = NORMAL_RADIUS + section.title_style = NORMAL_TITLE_STYLE + chart.update() + + chart = fch.PieChart( + sections_space=0, + center_space_radius=0, + on_event=on_chart_event, + expand=True, + sections=[ + fch.PieChartSection( + value=40, + title="40%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.BLUE, + radius=NORMAL_RADIUS, + badge=SectionBadge(ft.Icons.AC_UNIT), + badge_position=0.98, + ), + fch.PieChartSection( + value=30, + title="30%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.YELLOW, + radius=NORMAL_RADIUS, + badge=SectionBadge(ft.Icons.ACCESS_ALARM), + badge_position=0.98, + ), + fch.PieChartSection( + value=15, + title="15%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.PURPLE, + radius=NORMAL_RADIUS, + badge=SectionBadge(ft.Icons.APPLE), + badge_position=0.98, + ), + fch.PieChartSection( + value=15, + title="15%", + title_style=NORMAL_TITLE_STYLE, + color=ft.Colors.GREEN, + radius=NORMAL_RADIUS, + badge=SectionBadge(ft.Icons.PEDAL_BIKE), + badge_position=0.98, + ), + ], + ) + + page.add(ft.SafeArea(content=chart)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/pie_chart/example_3/pyproject.toml b/sdk/python/examples/extensions/charts/pie_chart/example_3/pyproject.toml new file mode 100644 index 0000000000..7501160de0 --- /dev/null +++ b/sdk/python/examples/extensions/charts/pie_chart/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-pie-chart-example-3" +version = "1.0.0" +description = "Pie chart with icon badges and animated section highlighting based on pointer events." +requires-python = ">=3.10" +keywords = ["charts", "pie-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PieChart"] + +[tool.flet.metadata] +title = "Example 3" +controls = ["SafeArea", "PieChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/pie_chart/media/example_1.gif b/sdk/python/examples/extensions/charts/pie_chart/media/example_1.gif new file mode 100644 index 0000000000..777f09c758 Binary files /dev/null and b/sdk/python/examples/extensions/charts/pie_chart/media/example_1.gif differ diff --git a/sdk/python/examples/extensions/charts/pie_chart/media/example_2.gif b/sdk/python/examples/extensions/charts/pie_chart/media/example_2.gif new file mode 100644 index 0000000000..fb12fbcb47 Binary files /dev/null and b/sdk/python/examples/extensions/charts/pie_chart/media/example_2.gif differ diff --git a/sdk/python/examples/extensions/charts/pie_chart/media/example_3.gif b/sdk/python/examples/extensions/charts/pie_chart/media/example_3.gif new file mode 100644 index 0000000000..148cb5402d Binary files /dev/null and b/sdk/python/examples/extensions/charts/pie_chart/media/example_3.gif differ diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_1/main.py b/sdk/python/examples/extensions/charts/plotly_chart/example_1/main.py new file mode 100644 index 0000000000..2354419df0 --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_1/main.py @@ -0,0 +1,15 @@ +import plotly.express as px + +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + df = px.data.gapminder().query("continent=='Oceania'") + fig = px.line(df, x="year", y="lifeExp", color="country") + + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/plotly_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..82f0eef85c --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "charts-plotly-chart-example-1" +version = "1.0.0" +description = "Plotly line chart showing life expectancy trends by country in Oceania." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +platforms = ["ios", "android", "macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_2/main.py b/sdk/python/examples/extensions/charts/plotly_chart/example_2/main.py new file mode 100644 index 0000000000..663b3c9099 --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_2/main.py @@ -0,0 +1,23 @@ +import plotly.express as px + +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + df = px.data.gapminder().query("continent == 'Oceania'") + fig = px.bar( + df, + x="year", + y="pop", + hover_data=["lifeExp", "gdpPercap"], + color="country", + labels={"pop": "population of Canada"}, + height=400, + ) + + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_2/pyproject.toml b/sdk/python/examples/extensions/charts/plotly_chart/example_2/pyproject.toml new file mode 100644 index 0000000000..b9dd2891c7 --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_2/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "charts-plotly-chart-example-2" +version = "1.0.0" +description = "Plotly bar chart comparing population with additional hover metrics by country and year." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 2" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +platforms = ["ios", "android", "macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_3/main.py b/sdk/python/examples/extensions/charts/plotly_chart/example_3/main.py new file mode 100644 index 0000000000..0f28b067fd --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_3/main.py @@ -0,0 +1,17 @@ +import plotly.graph_objects as go + +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + labels = ["Oxygen", "Hydrogen", "Carbon_Dioxide", "Nitrogen"] + values = [4500, 2500, 1053, 500] + + fig = go.Figure(data=[go.Pie(labels=labels, values=values)]) + + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_3/pyproject.toml b/sdk/python/examples/extensions/charts/plotly_chart/example_3/pyproject.toml new file mode 100644 index 0000000000..36d91a2df6 --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_3/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "charts-plotly-chart-example-3" +version = "1.0.0" +description = "Plotly pie chart example for categorical distribution visualization." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 3" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +platforms = ["ios", "android", "macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_4/main.py b/sdk/python/examples/extensions/charts/plotly_chart/example_4/main.py new file mode 100644 index 0000000000..9f50698e45 --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_4/main.py @@ -0,0 +1,59 @@ +import plotly.graph_objects as go + +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + x = [ + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 1", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2", + "day 2", + ] + + fig = go.Figure() + + fig.add_trace( + go.Box( + y=[0.2, 0.2, 0.6, 1.0, 0.5, 0.4, 0.2, 0.7, 0.9, 0.1, 0.5, 0.3], + x=x, + name="kale", + marker_color="#3D9970", + ) + ) + fig.add_trace( + go.Box( + y=[0.6, 0.7, 0.3, 0.6, 0.0, 0.5, 0.7, 0.9, 0.5, 0.8, 0.7, 0.2], + x=x, + name="radishes", + marker_color="#FF4136", + ) + ) + fig.add_trace( + go.Box( + y=[0.1, 0.3, 0.1, 0.9, 0.6, 0.6, 0.9, 1.0, 0.3, 0.6, 0.8, 0.5], + x=x, + name="carrots", + marker_color="#FF851B", + ) + ) + + fig.update_layout( + yaxis_title="normalized moisture", + boxmode="group", # group together boxes of the different traces + ) + + page.add(ft.SafeArea(content=fch.PlotlyChart(figure=fig, expand=True))) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/plotly_chart/example_4/pyproject.toml b/sdk/python/examples/extensions/charts/plotly_chart/example_4/pyproject.toml new file mode 100644 index 0000000000..56d8ea44f3 --- /dev/null +++ b/sdk/python/examples/extensions/charts/plotly_chart/example_4/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "charts-plotly-chart-example-4" +version = "1.0.0" +description = "Plotly grouped box plot comparing moisture distributions across categories." +requires-python = ">=3.10" +keywords = ["charts", "plotly-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts", "kaleido", "numpy", "pandas", "plotly[express]"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/PlotlyChart"] + +[tool.flet.metadata] +title = "Example 4" +controls = ["SafeArea", "PlotlyChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +platforms = ["ios", "android", "macos", "windows", "linux"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/plotly_chart/media/example_1.png b/sdk/python/examples/extensions/charts/plotly_chart/media/example_1.png new file mode 100644 index 0000000000..9aedc455dc Binary files /dev/null and b/sdk/python/examples/extensions/charts/plotly_chart/media/example_1.png differ diff --git a/sdk/python/examples/extensions/charts/plotly_chart/media/example_2.png b/sdk/python/examples/extensions/charts/plotly_chart/media/example_2.png new file mode 100644 index 0000000000..eef1a04561 Binary files /dev/null and b/sdk/python/examples/extensions/charts/plotly_chart/media/example_2.png differ diff --git a/sdk/python/examples/extensions/charts/plotly_chart/media/example_3.png b/sdk/python/examples/extensions/charts/plotly_chart/media/example_3.png new file mode 100644 index 0000000000..c3ba2dadd5 Binary files /dev/null and b/sdk/python/examples/extensions/charts/plotly_chart/media/example_3.png differ diff --git a/sdk/python/examples/extensions/charts/plotly_chart/media/example_4.png b/sdk/python/examples/extensions/charts/plotly_chart/media/example_4.png new file mode 100644 index 0000000000..de326cd2f5 Binary files /dev/null and b/sdk/python/examples/extensions/charts/plotly_chart/media/example_4.png differ diff --git a/sdk/python/examples/extensions/charts/radar_chart/example_1/main.py b/sdk/python/examples/extensions/charts/radar_chart/example_1/main.py new file mode 100644 index 0000000000..4cefb9815a --- /dev/null +++ b/sdk/python/examples/extensions/charts/radar_chart/example_1/main.py @@ -0,0 +1,63 @@ +import flet as ft +import flet_charts as fch + + +def main(page: ft.Page): + page.title = "Radar chart" + page.padding = 20 + # page.vertical_alignment = page.horizontal_alignment = "center" + page.theme_mode = ft.ThemeMode.LIGHT + + categories = ["macOS", "Linux", "Windows"] + + page.add( + ft.SafeArea( + content=fch.RadarChart( + expand=True, + titles=[fch.RadarChartTitle(text=label) for label in categories], + center_min_value=True, + tick_count=4, + ticks_text_style=ft.TextStyle(size=20, color=ft.Colors.ON_SURFACE), + title_text_style=ft.TextStyle( + size=24, weight=ft.FontWeight.BOLD, color=ft.Colors.ON_SURFACE + ), + on_event=lambda e: print(e.type), + data_sets=[ + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.2, ft.Colors.DEEP_PURPLE), + border_color=ft.Colors.DEEP_PURPLE, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(300), + fch.RadarDataSetEntry(50), + fch.RadarDataSetEntry(250), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.15, ft.Colors.PINK), + border_color=ft.Colors.PINK, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(250), + fch.RadarDataSetEntry(100), + fch.RadarDataSetEntry(200), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.12, ft.Colors.CYAN), + border_color=ft.Colors.CYAN, + entry_radius=4, + entries=[ + fch.RadarDataSetEntry(200), + fch.RadarDataSetEntry(150), + fch.RadarDataSetEntry(50), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/radar_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/radar_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..cafd659afa --- /dev/null +++ b/sdk/python/examples/extensions/charts/radar_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-radar-chart-example-1" +version = "1.0.0" +description = "Radar chart comparing platform values across multiple datasets with styled titles and ticks." +requires-python = ">=3.10" +keywords = ["charts", "radar-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/RadarChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "RadarChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/radar_chart/media/example_1.png b/sdk/python/examples/extensions/charts/radar_chart/media/example_1.png new file mode 100644 index 0000000000..aaebaa547c Binary files /dev/null and b/sdk/python/examples/extensions/charts/radar_chart/media/example_1.png differ diff --git a/sdk/python/examples/extensions/charts/scatter_chart/example_1/main.py b/sdk/python/examples/extensions/charts/scatter_chart/example_1/main.py new file mode 100644 index 0000000000..8b6faa3d45 --- /dev/null +++ b/sdk/python/examples/extensions/charts/scatter_chart/example_1/main.py @@ -0,0 +1,168 @@ +import random + +import flet as ft +import flet_charts as fch + + +class MySpot(fch.ScatterChartSpot): + def __init__( + self, + x: float, + y: float, + radius: float = 8.0, + color: ft.Colors = None, + show_tooltip: bool = False, + ): + super().__init__( + x=x, + y=y, + radius=radius, + color=color, + show_tooltip=show_tooltip, + selected=y == 43, + ) + + +flutter_logo_spots = [ + MySpot(20, 14.5), + MySpot(20, 14.5), + MySpot(22, 16.5), + MySpot(24, 18.5), + MySpot(22, 12.5), + MySpot(24, 14.5), + MySpot(26, 16.5), + MySpot(24, 10.5), + MySpot(26, 12.5), + MySpot(28, 14.5), + MySpot(26, 8.5), + MySpot(28, 10.5), + MySpot(30, 12.5), + MySpot(28, 6.5), + MySpot(30, 8.5), + MySpot(32, 10.5), + MySpot(30, 4.5), + MySpot(32, 6.5), + MySpot(34, 8.5), + MySpot(34, 4.5), + MySpot(36, 6.5), + MySpot(38, 4.5), + # section 2 + MySpot(20, 14.5), + MySpot(22, 12.5), + MySpot(24, 10.5), + MySpot(22, 16.5), + MySpot(24, 14.5), + MySpot(26, 12.5), + MySpot(24, 18.5), + MySpot(26, 16.5), + MySpot(28, 14.5), + MySpot(26, 20.5), + MySpot(28, 18.5), + MySpot(30, 16.5), + MySpot(28, 22.5), + MySpot(30, 20.5), + MySpot(32, 18.5), + MySpot(30, 24.5), + MySpot(32, 22.5), + MySpot(34, 20.5), + MySpot(34, 24.5), + MySpot(36, 22.5), + MySpot(38, 24.5), + # section 3 + MySpot(10, 25), + MySpot(12, 23), + MySpot(14, 21), + MySpot(12, 27), + MySpot(14, 25), + MySpot(16, 23), + MySpot(14, 29), + MySpot(16, 27), + MySpot(18, 25), + MySpot(16, 31), + MySpot(18, 29), + MySpot(20, 27), + MySpot(18, 33), + MySpot(20, 31), + MySpot(22, 29), + MySpot(20, 35), + MySpot(22, 33), + MySpot(24, 31), + MySpot(22, 37), + MySpot(24, 35), + MySpot(26, 33), + MySpot(24, 39), + MySpot(26, 37), + MySpot(28, 35), + MySpot(26, 41), + MySpot(28, 39), + MySpot(30, 37), + MySpot(28, 43), + MySpot(30, 41), + MySpot(32, 39), + MySpot(30, 45), + MySpot(32, 43), + MySpot(34, 41), + MySpot(34, 45), + MySpot(36, 43), + MySpot(38, 45), +] + + +def get_random_spots(): + """Generates random spots for the scatter chart.""" + return [ + MySpot( + x=random.uniform(4, 50), + y=random.uniform(4, 50), + radius=random.uniform(4, 20), + ) + for _ in range(len(flutter_logo_spots)) + ] + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def handle_event(e: fch.ScatterChartEvent): + if e.type == fch.ChartEventType.TAP_DOWN: + e.control.spots = ( + flutter_logo_spots + if (e.control.spots != flutter_logo_spots) + else get_random_spots() + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Tap on the chart to toggle between random spots and Flutter " + "logo spots." + ), + fch.ScatterChart( + expand=True, + aspect_ratio=1.0, + min_x=0.0, + max_x=50.0, + min_y=0.0, + max_y=50.0, + left_axis=fch.ChartAxis(show_labels=False), + right_axis=fch.ChartAxis(show_labels=False), + top_axis=fch.ChartAxis(show_labels=False), + bottom_axis=fch.ChartAxis(show_labels=False), + show_tooltips_for_selected_spots_only=False, + on_event=handle_event, + animation=ft.Animation( + duration=ft.Duration(milliseconds=600), + curve=ft.AnimationCurve.FAST_OUT_SLOWIN, + ), + spots=flutter_logo_spots, + ), + ], + ), + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/charts/scatter_chart/example_1/pyproject.toml b/sdk/python/examples/extensions/charts/scatter_chart/example_1/pyproject.toml new file mode 100644 index 0000000000..a3478064b4 --- /dev/null +++ b/sdk/python/examples/extensions/charts/scatter_chart/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "charts-scatter-chart-example-1" +version = "1.0.0" +description = "Scatter chart that toggles between random spots and a Flutter-logo point pattern on tap." +requires-python = ">=3.10" +keywords = ["charts", "scatter-chart", "flet"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-charts"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Charts/ScatterChart"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "ScatterChart"] +layout_pattern = "single-chart" +complexity = "basic" +features = ["chart visualization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/charts/scatter_chart/media/example_1.png b/sdk/python/examples/extensions/charts/scatter_chart/media/example_1.png new file mode 100644 index 0000000000..1647cf5d37 Binary files /dev/null and b/sdk/python/examples/extensions/charts/scatter_chart/media/example_1.png differ diff --git a/sdk/python/examples/extensions/code_editor/example_1/main.py b/sdk/python/examples/extensions/code_editor/example_1/main.py new file mode 100644 index 0000000000..48f89f9b1b --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_1/main.py @@ -0,0 +1,49 @@ +import flet_code_editor as fce + +import flet as ft + +CODE = """import flet as ft + +def main(page: ft.Page): + counter = ft.Text("0", size=50, data=0) + + def btn_click(e): + counter.data += 1 + counter.value = str(counter.data) + counter.update() + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=btn_click + ) + page.add( + ft.SafeArea( + ft.Container( + counter, + alignment=ft.Alignment.CENTER, + expand=True, + ), + expand=True, + ), + ) + +ft.run(main) +""" + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + code_theme=fce.CodeTheme.ATOM_ONE_LIGHT, + value=CODE, + expand=True, + on_change=lambda e: print("Changed:", e.data), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/code_editor/example_1/pyproject.toml b/sdk/python/examples/extensions/code_editor/example_1/pyproject.toml new file mode 100644 index 0000000000..902a03aead --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-1" +version = "1.0.0" +description = "Basic CodeEditor setup with Python syntax highlighting and change callbacks." +requires-python = ">=3.10" +keywords = ["code editor", "syntax highlighting", "python", "editor"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CodeEditor"] + +[tool.flet.metadata] +title = "Basic example" +controls = ["SafeArea", "CodeEditor"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["syntax highlighting", "change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/code_editor/example_2/main.py b/sdk/python/examples/extensions/code_editor/example_2/main.py new file mode 100644 index 0000000000..9f52719643 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_2/main.py @@ -0,0 +1,145 @@ +import flet_code_editor as fce + +import flet as ft + +CODE = """import flet as ft + +def main(page: ft.Page): + counter = ft.Text("0", size=50, data=0) + + def btn_click(e): + counter.data += 1 + counter.value = str(counter.data) + counter.update() + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=btn_click + ) + page.add( + ft.SafeArea( + ft.Container( + counter, + alignment=ft.Alignment.CENTER, + expand=True, + ), + expand=True, + ), + ) + +ft.run(main) +""" + +font_families = [ + # Apple platforms + "SF Mono", + "Menlo", + # Android + "Roboto Mono", + # Windows + "Consolas", + # Linux + "Ubuntu Mono", + # Universal fallbacks + "Courier New", +] + + +def main(page: ft.Page): + page.title = "CodeEditor selection" + max_selection_preview = 80 + + theme = fce.CustomCodeTheme( + keyword=ft.TextStyle(color=ft.Colors.INDIGO_600, weight=ft.FontWeight.W_600), + string=ft.TextStyle(color=ft.Colors.RED_700), + comment=ft.TextStyle(color=ft.Colors.GREY_600, italic=True), + ) + + text_style = ft.TextStyle( + font_family="monospace", font_family_fallback=font_families, size=12 + ) + + gutter_style = fce.GutterStyle( + text_style=ft.TextStyle( + font_family="monospace", font_family_fallback=font_families, size=12 + ), + show_line_numbers=True, + show_folding_handles=True, + width=60, + ) + + def handle_selection_change(e: ft.TextSelectionChangeEvent[fce.CodeEditor]): + if e.selected_text: + normalized = " ".join(e.selected_text.split()) + suffix = "..." if len(normalized) > max_selection_preview else "" + preview = normalized[:max_selection_preview] + selection.value = ( + f"Selection ({len(e.selected_text)} chars): '{preview}{suffix}'" + ) + else: + selection.value = "No selection." + selection_details.value = f"start={e.selection.start}, end={e.selection.end}" + caret.value = f"Caret position: {e.selection.end}" + + async def select_all(e: ft.Event[ft.Button]): + await editor.focus() + editor.selection = ft.TextSelection( + base_offset=0, + extent_offset=len(editor.value or ""), + ) + + async def move_caret_to_start(e: ft.Event[ft.Button]): + await editor.focus() + editor.selection = ft.TextSelection(base_offset=0, extent_offset=0) + + page.padding = 0 + page.spacing = 0 + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + spacing=10, + expand=True, + controls=[ + editor := fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + code_theme=theme, + autocomplete=True, + autocomplete_words=[ + "Container", + "Button", + "Text", + "Row", + "Column", + ], + value=CODE, + text_style=text_style, + gutter_style=gutter_style, + padding=10, + on_selection_change=handle_selection_change, + expand=True, + ), + ft.Column( + margin=10, + controls=[ + selection := ft.Text("Select some text from the editor."), + selection_details := ft.Text(), + caret := ft.Text("Caret position: -"), + ft.Row( + controls=[ + ft.Button("Select all text", on_click=select_all), + ft.Button( + "Move caret to start", + on_click=move_caret_to_start, + ), + ], + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/code_editor/example_2/pyproject.toml b/sdk/python/examples/extensions/code_editor/example_2/pyproject.toml new file mode 100644 index 0000000000..4f66885707 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-2" +version = "1.0.0" +description = "CodeEditor selection demo with custom theme, gutter styling, and caret/selection controls." +requires-python = ">=3.10" +keywords = ["code editor", "selection", "caret", "theme", "gutter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CodeEditor"] + +[tool.flet.metadata] +title = "Selection handling" +controls = ["SafeArea", "Column", "CodeEditor", "Text", "Row", "Button"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["selection change handling", "programmatic caret movement", "custom code theme"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/code_editor/example_3/main.py b/sdk/python/examples/extensions/code_editor/example_3/main.py new file mode 100644 index 0000000000..f0a61d7399 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_3/main.py @@ -0,0 +1,50 @@ +import flet_code_editor as fce + +import flet as ft + +CODE = """# 1 +# 2 +# 3 +import json +import textwrap + +print("Folding demo") +""" + + +def main(page: ft.Page): + editor = fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + value=CODE, + selection=ft.TextSelection(base_offset=41, extent_offset=62), + autofocus=True, + expand=True, + on_selection_change=lambda e: print("Selection:", e), + ) + + async def fold_imports(): + await editor.fold_imports() + + async def fold_comment(): + await editor.fold_comment_at_line_zero() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Button("Fold imports", on_click=fold_imports), + ft.Button("Fold comment", on_click=fold_comment), + ] + ), + editor, + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/code_editor/example_3/pyproject.toml b/sdk/python/examples/extensions/code_editor/example_3/pyproject.toml new file mode 100644 index 0000000000..8b3fe515f1 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-3" +version = "1.0.0" +description = "CodeEditor folding demo with predefined selection and toolbar actions for folding code blocks." +requires-python = ">=3.10" +keywords = ["code editor", "folding", "selection", "toolbar", "python"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CodeEditor"] + +[tool.flet.metadata] +title = "Folding and initial selection" +controls = ["SafeArea", "Column", "Row", "Button", "CodeEditor"] +layout_pattern = "control-panel" +complexity = "basic" +features = ["code folding", "initial text selection", "selection change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/code_editor/example_4/main.py b/sdk/python/examples/extensions/code_editor/example_4/main.py new file mode 100644 index 0000000000..407e740dcb --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_4/main.py @@ -0,0 +1,65 @@ +import asyncio +import json + +import flet_code_editor as fce + +import flet as ft + +INVALID_JSON = """{ + "name": "flet" + "version": 1 +}""" + + +async def main(page: ft.Page): + page.title = "CodeEditor JSON analyzer" + + debounce_task = None + + def analyze_json(code): + issues = [] + try: + json.loads(code) + except json.JSONDecodeError as ex: + issues.append( + fce.Issue( + line=ex.lineno - 1, + message=ex.msg, + type=fce.IssueType.ERROR, + ) + ) + editor.issues = issues + editor.update() + + async def debounced_analyze(code): + await asyncio.sleep(0.5) + analyze_json(code) + + def on_code_change(e): + nonlocal debounce_task + if debounce_task: + debounce_task.cancel() + debounce_task = asyncio.ensure_future(debounced_analyze(e.data)) + + editor = fce.CodeEditor( + language=fce.CodeLanguage.JSON, + code_theme=fce.CodeTheme.ATOM_ONE_LIGHT, + value=INVALID_JSON, + on_change=on_code_change, + gutter_style=fce.GutterStyle( + show_errors=True, + show_line_numbers=True, + show_folding_handles=True, + width=80, + ), + expand=True, + ) + + page.add(ft.SafeArea(expand=True, content=editor)) + + # Run initial analysis + analyze_json(INVALID_JSON) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/code_editor/example_4/pyproject.toml b/sdk/python/examples/extensions/code_editor/example_4/pyproject.toml new file mode 100644 index 0000000000..7b958293d8 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_4/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-4" +version = "1.0.0" +description = "CodeEditor with Python-side JSON analysis and gutter error markers." +requires-python = ">=3.10" +keywords = ["code editor", "json", "analyzer", "error markers", "gutter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CodeEditor"] + +[tool.flet.metadata] +title = "JSON analyzer" +controls = ["SafeArea", "CodeEditor"] +layout_pattern = "single-panel" +complexity = "intermediate" +features = ["json validation", "error markers", "debounced analysis"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/code_editor/example_5/main.py b/sdk/python/examples/extensions/code_editor/example_5/main.py new file mode 100644 index 0000000000..3a68e4ff05 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_5/main.py @@ -0,0 +1,68 @@ +import ast +import asyncio + +import flet_code_editor as fce + +import flet as ft + +INVALID_PYTHON = """import os + +def greet(name) + print(f"Hello, {name}!") + +greet("World") +""" + + +async def main(page: ft.Page): + page.title = "CodeEditor Python analyzer" + + debounce_task = None + + def analyze_python(code): + issues = [] + try: + ast.parse(code) + except SyntaxError as ex: + issues.append( + fce.Issue( + line=(ex.lineno or 1) - 1, + message=ex.msg, + type=fce.IssueType.ERROR, + ) + ) + editor.issues = issues + editor.update() + + async def debounced_analyze(code): + await asyncio.sleep(0.5) + analyze_python(code) + + def on_code_change(e): + nonlocal debounce_task + if debounce_task: + debounce_task.cancel() + debounce_task = asyncio.ensure_future(debounced_analyze(e.data)) + + editor = fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + code_theme=fce.CodeTheme.ATOM_ONE_LIGHT, + value=INVALID_PYTHON, + on_change=on_code_change, + gutter_style=fce.GutterStyle( + show_errors=True, + show_line_numbers=True, + show_folding_handles=True, + width=80, + ), + expand=True, + ) + + page.add(ft.SafeArea(expand=True, content=editor)) + + # Run initial analysis + analyze_python(INVALID_PYTHON) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/code_editor/example_5/pyproject.toml b/sdk/python/examples/extensions/code_editor/example_5/pyproject.toml new file mode 100644 index 0000000000..d5e53527e3 --- /dev/null +++ b/sdk/python/examples/extensions/code_editor/example_5/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "code-editor-example-5" +version = "1.0.0" +description = "CodeEditor with Python-side syntax analysis and gutter error markers." +requires-python = ">=3.10" +keywords = ["code editor", "python", "analyzer", "error markers", "gutter"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-code-editor"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Input/CodeEditor"] + +[tool.flet.metadata] +title = "Python analyzer" +controls = ["SafeArea", "CodeEditor"] +layout_pattern = "single-panel" +complexity = "intermediate" +features = ["python validation", "error markers", "debounced analysis"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/color_pickers/example_1/main.py b/sdk/python/examples/extensions/color_pickers/example_1/main.py new file mode 100644 index 0000000000..72627c2702 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_1/main.py @@ -0,0 +1,45 @@ +import flet as ft +from flet_color_pickers import ColorLabelType, ColorPicker, PaletteType + + +def main(page: ft.Page): + page.title = "ColorPicker" + page.padding = 20 + + def on_color_change(e: ft.ControlEvent): + print(f"color: {e.data}") + + def on_history_change(e: ft.ControlEvent): + # e.data is a list of hex strings + print(f"history: {e.data}") + + def on_hsv_color_change(e: ft.ControlEvent): + print("hsv: ", e.control.hsv_color) + + picker = ColorPicker( + color="#ff0000", + # hsv_color=HsvColor(alpha=1, hue=0, saturation=1, value=1), + color_history=[ + "#ff0000", + "#00ff00", + "#0000ff", + "#ffff00", + "#00ffff", + "#ff00ff", + ], + on_color_change=on_color_change, + palette_type=PaletteType.RGB_WITH_GREEN, + on_history_change=on_history_change, + on_hsv_color_change=on_hsv_color_change, + label_types=[ + ColorLabelType.HEX, + ColorLabelType.RGB, + ], + picker_area_border_radius=ft.BorderRadius.all(20), + ) + + page.add(ft.SafeArea(content=picker)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/color_pickers/example_1/pyproject.toml b/sdk/python/examples/extensions/color_pickers/example_1/pyproject.toml new file mode 100644 index 0000000000..a82b43e074 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-1" +version = "1.0.0" +description = "ColorPicker example with RGB palette mode, color history, and HSV/history change callbacks." +requires-python = ">=3.10" +keywords = ["color picker", "rgb", "hsv", "history", "palette"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Color pickers"] + +[tool.flet.metadata] +title = "ColorPicker" +controls = ["SafeArea", "ColorPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "color history", "hsv updates"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/color_pickers/example_2/main.py b/sdk/python/examples/extensions/color_pickers/example_2/main.py new file mode 100644 index 0000000000..088be69b20 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_2/main.py @@ -0,0 +1,23 @@ +import flet as ft +from flet_color_pickers import HueRingPicker + + +def main(page: ft.Page): + page.title = "HueRingPicker" + page.padding = 20 + + def on_color_change(e: ft.ControlEvent): + print(f"color: {e.data}") + + picker = HueRingPicker( + color="#00ff00", + hue_ring_stroke_width=20, + picker_area_border_radius=ft.BorderRadius.all(5), + on_color_change=on_color_change, + ) + + page.add(ft.SafeArea(content=picker)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/color_pickers/example_2/pyproject.toml b/sdk/python/examples/extensions/color_pickers/example_2/pyproject.toml new file mode 100644 index 0000000000..9aa3499541 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_2/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-2" +version = "1.0.0" +description = "HueRingPicker example with custom ring stroke width and color change callback." +requires-python = ">=3.10" +keywords = ["color picker", "hue ring", "color selection", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Color pickers"] + +[tool.flet.metadata] +title = "HueRingPicker" +controls = ["SafeArea", "HueRingPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "hue ring customization"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/color_pickers/example_3/main.py b/sdk/python/examples/extensions/color_pickers/example_3/main.py new file mode 100644 index 0000000000..9f74c16144 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_3/main.py @@ -0,0 +1,23 @@ +import flet as ft +from flet_color_pickers import ColorModel, SlidePicker + + +def main(page: ft.Page): + page.title = "SlidePicker" + page.padding = 20 + + def on_color_change(e: ft.ControlEvent): + print(f"color: {e.data}") + + picker = SlidePicker( + color="#0000ff", + color_model=ColorModel.RGB, + indicator_border_radius=ft.BorderRadius.all(5), + on_color_change=on_color_change, + ) + + page.add(ft.SafeArea(content=picker)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/color_pickers/example_3/pyproject.toml b/sdk/python/examples/extensions/color_pickers/example_3/pyproject.toml new file mode 100644 index 0000000000..7030783d7d --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_3/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-3" +version = "1.0.0" +description = "SlidePicker example using RGB color model with styled indicator and color change callback." +requires-python = ">=3.10" +keywords = ["color picker", "slide picker", "rgb", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Color pickers"] + +[tool.flet.metadata] +title = "SlidePicker" +controls = ["SafeArea", "SlidePicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "rgb color model", "indicator styling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/color_pickers/example_4/main.py b/sdk/python/examples/extensions/color_pickers/example_4/main.py new file mode 100644 index 0000000000..d52aaf43b4 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_4/main.py @@ -0,0 +1,25 @@ +import flet as ft +from flet_color_pickers import MaterialPicker + + +def main(page: ft.Page): + page.title = "MaterialPicker" + page.padding = 20 + + def on_color_change(e: ft.ControlEvent): + print(f"color: {e.data}") + + def on_primary_change(e: ft.ControlEvent): + print(f"primary: {e.data}") + + picker = MaterialPicker( + color="#ff9800", + on_color_change=on_color_change, + on_primary_change=on_primary_change, + ) + + page.add(ft.SafeArea(content=picker)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/color_pickers/example_4/pyproject.toml b/sdk/python/examples/extensions/color_pickers/example_4/pyproject.toml new file mode 100644 index 0000000000..ca7ba98b86 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_4/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-4" +version = "1.0.0" +description = "MaterialPicker example with callbacks for both selected color and primary swatch changes." +requires-python = ">=3.10" +keywords = ["color picker", "material picker", "swatch", "callback"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Color pickers"] + +[tool.flet.metadata] +title = "MaterialPicker" +controls = ["SafeArea", "MaterialPicker"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["color change callback", "primary swatch callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/color_pickers/example_5/main.py b/sdk/python/examples/extensions/color_pickers/example_5/main.py new file mode 100644 index 0000000000..a6d9a5faa1 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_5/main.py @@ -0,0 +1,47 @@ +import flet as ft +from flet_color_pickers import BlockPicker + + +def main(page: ft.Page): + page.title = "BlockPicker" + page.padding = 20 + + def on_color_change(e: ft.ControlEvent): + print(f"color: {e.data}") + + dialog_picker = BlockPicker( + color="#9c27b0", + available_colors=[ + "#f44336", + "#e91e63", + "#9c27b0", + "#3f51b5", + "#2196f3", + "#009688", + "#4caf50", + "#795548", + ], + on_color_change=on_color_change, + ) + + dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Pick a color"), + content=dialog_picker, + actions=[ + ft.TextButton("Close", on_click=lambda e: page.pop_dialog()), + ], + ) + + page.add( + ft.SafeArea( + content=ft.IconButton( + icon=ft.Icons.BRUSH, + on_click=lambda e: page.show_dialog(dialog), + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/color_pickers/example_5/pyproject.toml b/sdk/python/examples/extensions/color_pickers/example_5/pyproject.toml new file mode 100644 index 0000000000..5852c07107 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_5/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-5" +version = "1.0.0" +description = "BlockPicker dialog example with curated color palette and icon-triggered modal launch." +requires-python = ">=3.10" +keywords = ["color picker", "block picker", "dialog", "palette", "modal"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Color pickers"] + +[tool.flet.metadata] +title = "BlockPicker" +controls = ["SafeArea", "IconButton", "AlertDialog", "TextButton", "BlockPicker"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog picker", "color change callback", "custom color palette"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/color_pickers/example_6/main.py b/sdk/python/examples/extensions/color_pickers/example_6/main.py new file mode 100644 index 0000000000..c3cf95d121 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_6/main.py @@ -0,0 +1,49 @@ +import flet as ft +from flet_color_pickers import MultipleChoiceBlockPicker + + +def main(page: ft.Page): + page.title = "MultipleChoiceBlockPicker" + page.padding = 20 + + def on_colors_change(e: ft.ControlEvent): + print(f"colors: {e.data}") + + dialog_picker = MultipleChoiceBlockPicker( + colors=["#03a9f4", "#4caf50"], + available_colors=[ + "#f44336", + "#e91e63", + "#9c27b0", + "#3f51b5", + "#2196f3", + "#03a9f4", + "#009688", + "#4caf50", + "#ff9800", + "#795548", + ], + on_colors_change=on_colors_change, + ) + + dialog = ft.AlertDialog( + modal=True, + title=ft.Text("Pick colors"), + content=dialog_picker, + actions=[ + ft.TextButton("Close", on_click=lambda e: page.pop_dialog()), + ], + ) + + page.add( + ft.SafeArea( + content=ft.IconButton( + icon=ft.Icons.BRUSH, + on_click=lambda e: page.show_dialog(dialog), + ) + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/color_pickers/example_6/pyproject.toml b/sdk/python/examples/extensions/color_pickers/example_6/pyproject.toml new file mode 100644 index 0000000000..76f8233f93 --- /dev/null +++ b/sdk/python/examples/extensions/color_pickers/example_6/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "color-pickers-example-6" +version = "1.0.0" +description = "MultipleChoiceBlockPicker dialog with multi-select colors and icon-triggered modal launch." +requires-python = ">=3.10" +keywords = ["color picker", "multi-select", "block picker", "dialog", "palette"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-color-pickers"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Color pickers"] + +[tool.flet.metadata] +title = "MultipleChoiceBlockPicker" +controls = ["SafeArea", "IconButton", "AlertDialog", "TextButton", "MultipleChoiceBlockPicker"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["dialog picker", "multiple color selection", "colors change callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/datatable2/column_widths/main.py b/sdk/python/examples/extensions/datatable2/column_widths/main.py new file mode 100644 index 0000000000..d7677f3444 --- /dev/null +++ b/sdk/python/examples/extensions/datatable2/column_widths/main.py @@ -0,0 +1,67 @@ +import flet as ft +import flet_datatable2 as fdt + + +def main(page: ft.Page): + def cell_text(value: str) -> ft.Text: + """A helper to truncate any overflowing cell text with an ellipsis.""" + return ft.Text(value, overflow=ft.TextOverflow.ELLIPSIS, max_lines=1) + + page.add( + ft.SafeArea( + expand=True, + content=fdt.DataTable2( + expand=True, + min_width=600, + columns=[ + # Absolute pixel width — best for predictable, short fields. + fdt.DataColumn2(label="Name", fixed_width=140), + # Relative size S — compact, auto-fits the remaining space. + fdt.DataColumn2(label="Role", size=fdt.DataColumnSize.S), + # Relative size L — takes the lion's share of what's left. + fdt.DataColumn2(label="Recent work", size=fdt.DataColumnSize.L), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell(cell_text("Alice Nakamura")), + ft.DataCell(cell_text("Engineer")), + ft.DataCell( + cell_text( + "Led the migration of our checkout service " + "to a set of composable workers, cutting " + "p99 latency in half." + ) + ), + ] + ), + ft.DataRow( + cells=[ + # Longer than 140px — shows ellipsis in a fixed column. + ft.DataCell(cell_text("Bartholomew Laurent-Fitzgerald")), + ft.DataCell(cell_text("Designer")), + ft.DataCell( + cell_text( + "Rebuilt the onboarding flow and maintains " + "the internal design-system token registry." + ) + ), + ] + ), + ft.DataRow( + cells=[ + ft.DataCell(cell_text("Chen")), + ft.DataCell(cell_text("PM")), + ft.DataCell( + cell_text("Owns the Platform Reliability roadmap.") + ), + ] + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/datatable2/column_widths/pyproject.toml b/sdk/python/examples/extensions/datatable2/column_widths/pyproject.toml new file mode 100644 index 0000000000..7c50df2a66 --- /dev/null +++ b/sdk/python/examples/extensions/datatable2/column_widths/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "datatable2-column-widths" +version = "1.0.0" +description = "Demonstrates DataTable2 column widths (fixed pixels and relative S/M/L) with ellipsis truncation for overflowing cell text." +requires-python = ">=3.10" +keywords = ["datatable2", "column width", "ellipsis", "overflow", "extension"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-datatable2"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable2"] + +[tool.flet.metadata] +title = "Column widths" +controls = ["SafeArea", "DataTable2", "DataColumn2", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["fixed column width", "relative column size", "text ellipsis overflow"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/datatable2/empty_state/main.py b/sdk/python/examples/extensions/datatable2/empty_state/main.py new file mode 100644 index 0000000000..aeb33ed5e6 --- /dev/null +++ b/sdk/python/examples/extensions/datatable2/empty_state/main.py @@ -0,0 +1,23 @@ +import flet as ft +import flet_datatable2 as fdt + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=fdt.DataTable2( + expand=True, + empty=ft.Text("This table is empty."), + columns=[ + fdt.DataColumn2(label=ft.Text("First name")), + fdt.DataColumn2(label=ft.Text("Last name")), + fdt.DataColumn2(label=ft.Text("Age"), numeric=True), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/datatable2/empty_state/pyproject.toml b/sdk/python/examples/extensions/datatable2/empty_state/pyproject.toml new file mode 100644 index 0000000000..453c47b7b0 --- /dev/null +++ b/sdk/python/examples/extensions/datatable2/empty_state/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "datatable2-empty-state" +version = "1.0.0" +description = "Shows an empty DataTable2 state with configured columns and placeholder content." +requires-python = ">=3.10" +keywords = ["datatable2", "data table", "empty state", "extension"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-datatable2"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable2"] + +[tool.flet.metadata] +title = "Empty state" +controls = ["SafeArea", "DataTable2", "DataColumn2", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["empty table state", "DataTable2 columns"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/datatable2/media/sortable_and_selectable.gif b/sdk/python/examples/extensions/datatable2/media/sortable_and_selectable.gif new file mode 100644 index 0000000000..07fb5a645e Binary files /dev/null and b/sdk/python/examples/extensions/datatable2/media/sortable_and_selectable.gif differ diff --git a/sdk/python/examples/extensions/datatable2/sortable_and_selectable/main.py b/sdk/python/examples/extensions/datatable2/sortable_and_selectable/main.py new file mode 100644 index 0000000000..29cdd9ac1a --- /dev/null +++ b/sdk/python/examples/extensions/datatable2/sortable_and_selectable/main.py @@ -0,0 +1,147 @@ +from dataclasses import dataclass + +import flet as ft +import flet_datatable2 as ftd + + +@dataclass +class Dessert: + name: str + calories: float + fat: float + carbs: float + protein: float + sodium: float + calcium: float + iron: float + + +desserts = [ + Dessert("Frozen Yogurt", 159, 6.0, 24, 4.0, 87, 14, 1), + Dessert("Ice Cream Sandwich", 237, 9.0, 37, 4.3, 129, 8, 1), + Dessert("Eclair", 262, 16.0, 24, 6.0, 337, 6, 7), + Dessert("Cupcake", 305, 3.7, 67, 4.3, 413, 3, 8), + Dessert("Gingerbread", 356, 16.0, 49, 3.9, 327, 7, 16), + Dessert("Jelly Bean", 375, 0.0, 94, 0.0, 50, 0, 0), + Dessert("Lollipop", 392, 0.2, 98, 0.0, 38, 0, 2), + Dessert("Honeycomb", 408, 3.2, 87, 6.5, 562, 0, 45), + Dessert("Donut", 452, 25.0, 51, 4.9, 326, 2, 22), + Dessert("Apple Pie", 518, 26.0, 65, 7.0, 54, 12, 6), + Dessert("Frozen Yougurt with sugar", 168, 6.0, 26, 4.0, 87, 14, 1), + Dessert("Ice Cream Sandwich with sugar", 246, 9.0, 39, 4.3, 129, 8, 1), + Dessert("Eclair with sugar", 271, 16.0, 26, 6.0, 337, 6, 7), + Dessert("Cupcake with sugar", 314, 3.7, 69, 4.3, 413, 3, 8), + Dessert("Gingerbread with sugar", 345, 16.0, 51, 3.9, 327, 7, 16), + Dessert("Jelly Bean with sugar", 364, 0.0, 96, 0.0, 50, 0, 0), + Dessert("Lollipop with sugar", 401, 0.2, 100, 0.0, 38, 0, 2), + Dessert("Honeycomb with sugar", 417, 3.2, 89, 6.5, 562, 0, 45), + Dessert("Donut with sugar", 461, 25.0, 53, 4.9, 326, 2, 22), + Dessert("Apple pie with sugar", 527, 26.0, 67, 7.0, 54, 12, 6), + Dessert("Frozen yougurt with honey", 223, 6.0, 36, 4.0, 87, 14, 1), + Dessert("Ice Cream Sandwich with honey", 301, 9.0, 49, 4.3, 129, 8, 1), + Dessert("Eclair with honey", 326, 16.0, 36, 6.0, 337, 6, 7), + Dessert("Cupcake with honey", 369, 3.7, 79, 4.3, 413, 3, 8), + Dessert("Gingerbread with honey", 420, 16.0, 61, 3.9, 327, 7, 16), + Dessert("Jelly Bean with honey", 439, 0.0, 106, 0.0, 50, 0, 0), + Dessert("Lollipop with honey", 456, 0.2, 110, 0.0, 38, 0, 2), + Dessert("Honeycomb with honey", 472, 3.2, 99, 6.5, 562, 0, 45), + Dessert("Donut with honey", 516, 25.0, 63, 4.9, 326, 2, 22), + Dessert("Apple pie with honey", 582, 26.0, 77, 7.0, 54, 12, 6), +] + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + sorted_desserts = list(desserts) + + def handle_row_selection_change(e: ft.Event[ftd.DataRow2]) -> None: + e.control.selected = not e.control.selected + e.control.update() + + def sort_column(e: ft.DataColumnSortEvent) -> None: + sorters = [ + lambda d: d.name.lower(), + lambda d: d.calories, + lambda d: d.fat, + lambda d: d.carbs, + lambda d: d.protein, + lambda d: d.sodium, + lambda d: d.calcium, + lambda d: d.iron, + ] + sorted_desserts.sort(key=sorters[e.column_index], reverse=not e.ascending) + table.rows = get_data_rows(sorted_desserts) + table.sort_column_index = e.column_index + table.sort_ascending = e.ascending + table.update() + + def get_data_columns() -> list[ftd.DataColumn2]: + return [ + ftd.DataColumn2( + label=ft.Text("Name"), + size=ftd.DataColumnSize.L, + on_sort=sort_column, + heading_row_alignment=ft.MainAxisAlignment.START, + ), + ftd.DataColumn2( + label=ft.Text("Calories"), + on_sort=sort_column, + numeric=True, + heading_row_alignment=ft.MainAxisAlignment.END, + ), + ftd.DataColumn2(label=ft.Text("Fat"), on_sort=sort_column, numeric=True), + ftd.DataColumn2(label=ft.Text("Carbs"), on_sort=sort_column, numeric=True), + ftd.DataColumn2( + label=ft.Text("Protein"), + on_sort=sort_column, + numeric=True, + ), + ftd.DataColumn2(label=ft.Text("Sodium"), on_sort=sort_column, numeric=True), + ftd.DataColumn2( + label=ft.Text("Calcium"), + on_sort=sort_column, + numeric=True, + ), + ftd.DataColumn2(label=ft.Text("Iron"), on_sort=sort_column, numeric=True), + ] + + def get_data_rows(items: list) -> list[ftd.DataRow2]: + return [ + ftd.DataRow2( + specific_row_height=50, + on_select_change=handle_row_selection_change, + cells=[ + ft.DataCell(content=ft.Text(dessert.name)), + ft.DataCell(content=ft.Text(dessert.calories)), + ft.DataCell(content=ft.Text(dessert.fat)), + ft.DataCell(content=ft.Text(dessert.carbs)), + ft.DataCell(content=ft.Text(dessert.protein)), + ft.DataCell(content=ft.Text(dessert.sodium)), + ft.DataCell(content=ft.Text(dessert.calcium)), + ft.DataCell(content=ft.Text(dessert.iron)), + ], + ) + for dessert in items + ] + + table = ftd.DataTable2( + expand=True, + show_checkbox_column=True, + column_spacing=0, + heading_row_color=ft.Colors.SECONDARY_CONTAINER, + horizontal_margin=12, + sort_ascending=True, + bottom_margin=10, + min_width=600, + on_select_all=lambda _: print("All selected"), + columns=get_data_columns(), + rows=get_data_rows(sorted_desserts), + ) + + page.add(ft.SafeArea(expand=True, content=table)) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/datatable2/sortable_and_selectable/pyproject.toml b/sdk/python/examples/extensions/datatable2/sortable_and_selectable/pyproject.toml new file mode 100644 index 0000000000..7f925f6162 --- /dev/null +++ b/sdk/python/examples/extensions/datatable2/sortable_and_selectable/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "datatable2-sortable-and-selectable" +version = "1.0.0" +description = "Builds an interactive DataTable2 with sortable nutrition columns and selectable rows." +requires-python = ">=3.10" +keywords = ["datatable2", "sorting", "selection", "rows", "extension"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-datatable2"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Layout/DataTable2"] + +[tool.flet.metadata] +title = "Sortable and selectable" +controls = ["SafeArea", "DataTable2", "DataColumn2", "DataRow2", "DataCell", "Text"] +layout_pattern = "table-view" +complexity = "basic" +features = ["column sorting", "row selection", "select-all callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/flashlight/example_1/main.py b/sdk/python/examples/extensions/flashlight/example_1/main.py new file mode 100644 index 0000000000..453c7682be --- /dev/null +++ b/sdk/python/examples/extensions/flashlight/example_1/main.py @@ -0,0 +1,25 @@ +import flet as ft +import flet_flashlight as ffl + + +def main(page: ft.Page): + async def turn_on_flashlight(): + await ffl.Flashlight().on() + + async def turn_off_flashlight(): + await ffl.Flashlight().off() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("Turn On Flashlight", on_click=turn_on_flashlight), + ft.Button("Turn Off Flashlight", on_click=turn_off_flashlight), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/flashlight/example_1/pyproject.toml b/sdk/python/examples/extensions/flashlight/example_1/pyproject.toml new file mode 100644 index 0000000000..1aede54156 --- /dev/null +++ b/sdk/python/examples/extensions/flashlight/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-flashlight-example-1" +version = "1.0.0" +description = "Turns the device flashlight on and off with two simple actions." +requires-python = ">=3.10" +keywords = ["flashlight", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-flashlight"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Flashlight"] + +[tool.flet.metadata] +title = "Flashlight example" +controls = ["SafeArea", "Column", "Page", "Flashlight", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["flashlight toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["ios", "android"] diff --git a/sdk/python/examples/extensions/geolocator/example_1/main.py b/sdk/python/examples/extensions/geolocator/example_1/main.py new file mode 100644 index 0000000000..adf5973b0b --- /dev/null +++ b/sdk/python/examples/extensions/geolocator/example_1/main.py @@ -0,0 +1,155 @@ +from typing import Callable + +import flet as ft +import flet_geolocator as ftg + + +async def main(page: ft.Page): + page.scroll = ft.ScrollMode.ADAPTIVE + page.appbar = ft.AppBar(title=ft.Text("Geolocator Tests")) + + def handle_position_change(e: ftg.GeolocatorPositionChangeEvent): + page.add(ft.Text(f"New position: {e.position.latitude} {e.position.longitude}")) + + def get_dialog(handler: Callable): + return ft.AlertDialog( + adaptive=True, + title="Opening Location Settings...", + content=ft.Text( + "You are about to be redirected to the location/app settings. " + "Please locate this app and grant it location permissions." + ), + actions=[ft.TextButton("Take me there", on_click=handler)], + actions_alignment=ft.MainAxisAlignment.CENTER, + ) + + def show_snackbar(message): + page.show_dialog(ft.SnackBar(ft.Text(message))) + + async def handle_permission_request(e: ft.Event[ft.OutlinedButton]): + try: + p = await geo.request_permission() + page.add(ft.Text(f"request_permission: {p}")) + show_snackbar(f"Permission request sent: {p}") + except RuntimeError as ex: + show_snackbar(f"Could not request permission: {ex}") + + async def handle_get_permission_status(e: ft.Event[ft.OutlinedButton]): + try: + p = await geo.get_permission_status() + show_snackbar(f"Permission status: {p}") + except RuntimeError as ex: + show_snackbar(f"Could not read permission status: {ex}") + + async def handle_get_current_position(e: ft.Event[ft.OutlinedButton]): + try: + p = await geo.get_current_position() + show_snackbar(f"Current position: ({p.latitude}, {p.longitude})") + print(f"Current position: ({p.latitude}, {p.longitude})") + except RuntimeError as ex: + show_snackbar(f"Could not get current position: {ex}") + print(f"Could not get current position: {ex}") + + async def handle_get_last_known_position(e): + try: + p = await geo.get_last_known_position() + if p is None: + show_snackbar("No last known position available.") + else: + show_snackbar(f"Last known position: ({p.latitude}, {p.longitude})") + print(f"Last known position: ({p.latitude}, {p.longitude})") + except RuntimeError as ex: + show_snackbar(f"Could not get last known position: {ex}") + + async def handle_location_service_enabled(e): + try: + p = await geo.is_location_service_enabled() + show_snackbar(f"Location service enabled: {p}") + except RuntimeError as ex: + show_snackbar(f"Could not check location service: {ex}") + + async def handle_open_location_settings(e: ft.Event[ft.OutlinedButton]): + try: + p = await geo.open_location_settings() + page.pop_dialog() + if p is True: + show_snackbar("Location settings opened successfully.") + else: + show_snackbar("Location settings could not be opened.") + except RuntimeError as ex: + page.pop_dialog() + show_snackbar(f"Could not open location settings: {ex}") + + async def handle_open_app_settings(e: ft.Event[ft.OutlinedButton]): + try: + p = await geo.open_app_settings() + page.pop_dialog() + if p: + show_snackbar("App settings opened successfully.") + else: + show_snackbar("App settings could not be opened.") + except RuntimeError as ex: + page.pop_dialog() + show_snackbar(f"Could not open app settings: {ex}") + + location_settings_dlg = get_dialog(handle_open_location_settings) + app_settings_dlg = get_dialog(handle_open_app_settings) + + geo = ftg.Geolocator( + configuration=ftg.GeolocatorConfiguration( + accuracy=ftg.GeolocatorPositionAccuracy.LOW + ), + on_position_change=handle_position_change, + on_error=lambda e: page.add(ft.Text(f"Error: {e.data}")), + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + wrap=True, + controls=[ + ft.OutlinedButton( + content="Request Permission", + on_click=handle_permission_request, + ), + ft.OutlinedButton( + content="Get Permission Status", + on_click=handle_get_permission_status, + ), + ft.OutlinedButton( + content="Get Current Position", + on_click=handle_get_current_position, + ), + ft.OutlinedButton( + content="Get Last Known Position", + visible=not page.web, + on_click=handle_get_last_known_position, + ), + ft.OutlinedButton( + content="Is Location Service Enabled", + on_click=handle_location_service_enabled, + ), + ft.OutlinedButton( + content="Open Location Settings", + visible=not page.web, # (1)! + on_click=lambda e: page.show_dialog( + location_settings_dlg + ), + ), + ft.OutlinedButton( + content="Open App Settings", + visible=not page.web, # (1)! + on_click=lambda e: page.show_dialog(app_settings_dlg), + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/geolocator/example_1/pyproject.toml b/sdk/python/examples/extensions/geolocator/example_1/pyproject.toml new file mode 100644 index 0000000000..9cc6ddfa6a --- /dev/null +++ b/sdk/python/examples/extensions/geolocator/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-geolocator-example-1" +version = "1.0.0" +description = "Requests location permissions and exercises geolocator actions from one dashboard." +requires-python = ">=3.10" +keywords = ["geolocator", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-geolocator"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/Geolocator"] + +[tool.flet.metadata] +title = "Geolocator example" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "GeolocatorPositionChangeEvent", "TextButton", "OutlinedButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["permission handling", "location actions"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/lottie/example_1/assets/sample.json b/sdk/python/examples/extensions/lottie/example_1/assets/sample.json new file mode 100644 index 0000000000..afd268ea80 --- /dev/null +++ b/sdk/python/examples/extensions/lottie/example_1/assets/sample.json @@ -0,0 +1 @@ +{"assets":[],"layers":[{"ddd":0,"ind":0,"ty":4,"nm":"B 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[1,1,1,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":26,"op":37,"st":22,"bm":0,"sr":1},{"ddd":0,"ind":1,"ty":4,"nm":"B","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":26,"op":37,"st":22,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"B blue layer 6","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-1.324,-11.343],[2.439,-7.314],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.612,-2.224]],"v":[[-55.603,-180.739],[-55.439,-147.686],[-63.981,-142.398],[-70.654,-190.988],[-63.612,-197.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[9.939,-11.314],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[9.112,-3.724]],"v":[[-32.103,-179.739],[-36.939,-146.686],[-53.481,-139.398],[-60.154,-190.488],[-47.112,-197.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.154,-14.341],[9.939,-11.314],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[9.112,-3.724]],"v":[[-32.103,-179.739],[-36.939,-146.686],[-53.481,-139.398],[-60.154,-190.488],[-47.112,-197.276]],"c":true}],"e":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-11.249,-176.983],[-23.893,-143.184],[-46.891,-138.152],[-50.397,-189.494],[-30.535,-196.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-11.249,-176.983],[-23.893,-143.184],[-46.891,-138.152],[-50.397,-189.494],[-30.535,-196.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[4.397,-174.239],[-14.439,-139.686],[-40.981,-136.898],[-44.654,-188.488],[-18.612,-193.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[4.397,-174.239],[-14.439,-139.686],[-40.981,-136.898],[-44.654,-188.488],[-18.612,-193.276]],"c":true}],"e":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.998,-170.132],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.998,-170.132],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"n":"0_1_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[5.931,-1.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-44.931,-50.495],[-55.177,-48.495],[-60.677,-102.158],[-53.931,-106.658],[-42.844,-84.676]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-27.431,-47.995],[-46.177,-46.495],[-51.177,-100.658],[-34.431,-104.658],[-18.344,-87.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-27.431,-47.995],[-46.177,-46.495],[-51.177,-100.658],[-34.431,-104.658],[-18.344,-87.176]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[2.589,13.962]],"v":[[-10.681,-46.995],[-40.427,-45.245],[-43.677,-98.908],[-17.181,-102.408],[3.406,-81.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[2.589,13.962]],"v":[[-10.681,-46.995],[-40.427,-45.245],[-43.677,-98.908],[-17.181,-102.408],[3.406,-81.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[20.156,-76.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[20.156,-76.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[6.902,-43.495],[-34.844,-42.662],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[6.902,-43.495],[-34.844,-42.662],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"n":"0_1_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[1,1,1,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":16,"op":26,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"B blue layer 5","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[5.759,27.537],[4.508,20.972],[7.96,-31.787],[0,0],[0,0],[-52.303,4.363],[12.713,79.144]],"o":[[-6.241,-30.463],[-18.411,-85.645],[-8.037,32.093],[0,0],[0,0],[17.982,-1.5],[-4.202,-26.16]],"v":[[-23.759,-157.537],[-41.089,-239.855],[-57.963,-260.093],[-97.507,-214.093],[-76.507,-0.5],[-13.982,-7.5],[-8.213,-83.644]],"c":true}],"e":[{"i":[[8.259,26.537],[3.138,21.22],[33.463,-28.907],[0,0],[0,0],[-52.485,0],[6.213,46.144]],"o":[[-3.241,-28.463],[-9.411,-63.645],[-29.686,25.644],[0,0],[0,0],[43.482,0],[-4.959,-36.833]],"v":[[21.241,-163.037],[14.911,-228.855],[-29.963,-255.093],[-95.007,-217.593],[-76.507,-0.5],[17.018,-3.5],[41.787,-87.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[8.259,26.537],[3.138,21.22],[33.463,-28.907],[0,0],[0,0],[-52.485,0],[6.213,46.144]],"o":[[-3.241,-28.463],[-9.411,-63.645],[-29.686,25.644],[0,0],[0,0],[43.482,0],[-4.959,-36.833]],"v":[[21.241,-163.037],[14.911,-228.855],[-29.963,-255.093],[-95.007,-217.593],[-76.507,-0.5],[17.018,-3.5],[41.787,-87.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[37.463,-16.657],[0,0],[0,0],[-26.242,0],[5.463,51.394]],"o":[[3.509,-24.213],[-4.661,-61.895],[-35.537,14.843],[0,0],[0,0],[52.482,4],[-3.676,-32.795]],"v":[[46.741,-144.787],[49.661,-211.605],[-14.963,-245.343],[-91.757,-220.343],[-77.257,-0.75],[21.518,-2],[72.287,-76.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[37.463,-16.657],[0,0],[0,0],[-26.242,0],[5.463,51.394]],"o":[[3.509,-24.213],[-4.661,-61.895],[-35.537,14.843],[0,0],[0,0],[52.482,4],[-3.676,-32.795]],"v":[[46.741,-144.787],[49.661,-211.605],[-14.963,-245.343],[-91.757,-220.343],[-77.257,-0.75],[21.518,-2],[72.287,-76.144]],"c":true}],"e":[{"i":[[23.259,15.537],[2.058,21.352],[34.868,-8.794],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.037,9.593],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[56.241,-133.537],[68.411,-198.355],[-2.963,-239.593],[-88.507,-223.093],[-78.007,-1],[26.018,-0.5],[86.787,-72.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[23.259,15.537],[2.058,21.352],[34.868,-8.794],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.037,9.593],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[56.241,-133.537],[68.411,-198.355],[-2.963,-239.593],[-88.507,-223.093],[-78.007,-1],[26.018,-0.5],[86.787,-72.144]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[36.665,-5.6],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-2.705,-47.408],[-19.018,4.797],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[76.911,-186.105],[5.787,-235.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[36.665,-5.6],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-2.705,-47.408],[-19.018,4.797],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[76.911,-186.105],[5.787,-235.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0,"y":1},"o":{"x":0.167,"y":0.167},"n":"0_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":16,"op":26,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":9.771},"p":{"k":[{"i":{"x":0.601,"y":0.889},"o":{"x":0.239,"y":0.067},"n":"0p601_0p889_0p239_0p067","t":9,"s":[241.443,258.888,0],"e":[222.443,251.888,0],"to":[-0.5,-0.33333334326744,0],"ti":[-1.02731943130493,-0.37357068061829,0]},{"i":{"x":0.686,"y":1},"o":{"x":0.239,"y":0.304},"n":"0p686_1_0p239_0p304","t":11,"s":[222.443,251.888,0],"e":[242,259,0],"to":[5.54179763793945,2.01519918441772,0],"ti":[-3.09325051307678,-1.12481832504272,0]},{"t":20.3449832499027}]},"a":{"k":[0,0,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":8.999,"s":[-100,100,100],"e":[-128,128,100]},{"t":21.9237344563007}]}},"ao":0,"ip":9.99999961256981,"op":22.7584036290646,"st":-10.5559570491314,"bm":0,"sr":0.96000009775162},{"ddd":0,"ind":5,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":-22.412},"p":{"k":[{"i":{"x":0.592,"y":0.891},"o":{"x":0.257,"y":0.068},"n":"0p592_0p891_0p257_0p068","t":9,"s":[225.656,310.504,0],"e":[206.656,303.504,0],"to":[-0.5,-0.33333334326744,0],"ti":[-1.516930103302,-0.31094110012054,0]},{"i":{"x":0.762,"y":1},"o":{"x":0.257,"y":0.3},"n":"0p762_1_0p257_0p3","t":11,"s":[206.656,303.504,0],"e":[228,308,0],"to":[6.19302797317505,1.26945006847382,0],"ti":[-0.32227402925491,0,0]},{"t":20.3640127778053}]},"a":{"k":[0,0,0]},"s":{"k":[-100,100,100]}},"ao":0,"ip":10.0000003576279,"op":22.5608477592468,"st":-9.35224944353104,"bm":0,"sr":0.95000010728836},{"ddd":0,"ind":6,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":26.915},"p":{"k":[{"i":{"x":0.587,"y":0.894},"o":{"x":0.264,"y":0.068},"n":"0p587_0p894_0p264_0p068","t":10,"s":[228.667,205.657,0],"e":[209.667,198.657,0],"to":[-0.5,-0.33333334326744,0],"ti":[-1.19691395759583,-0.40347543358803,0]},{"i":{"x":0.713,"y":1},"o":{"x":0.264,"y":0.336},"n":"0p713_1_0p264_0p336","t":12,"s":[209.667,198.657,0],"e":[223,204,0],"to":[4.62041616439819,1.55752575397491,0],"ti":[-0.48471575975418,0,0]},{"t":19.0271503602465}]},"a":{"k":[0,0,0]},"s":{"k":[-100,100,100]}},"ao":0,"ip":11.0000006233652,"op":22.5608497237166,"st":-9.35224822411935,"bm":0,"sr":0.95000010728836},{"ddd":0,"ind":7,"ty":4,"nm":"B blue layer 4 shadow","parent":34,"ks":{"o":{"k":5},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[6,3],[35.446,17.154],[1.39,-24.214],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[-35.446,-17.154],[-1.585,27.613],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-94,-266],[-98,-118],[-80,-5],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-143,-270],[-133,-137],[-118,-11],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-143,-270],[-133,-137],[-118,-11],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-178,-280],[-159,-145],[-141,4],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6,3],[0,-5],[-5,-22],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[5,22],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-178,-280],[-159,-145],[-141,4],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-7,-32],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[6.414,29.323],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-158,-284],[-149,-204],[-118,6],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[6,3],[0,-5],[-7,-32],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[6.414,29.323],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-140,-282],[-158,-284],[-149,-204],[-118,6],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-0.752,-22.548],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[1,30],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-106,-286],[-115,-276],[-99,-138],[-79,20],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[6,3],[0,-5],[-0.752,-22.548],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[1,30],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-106,-286],[-115,-276],[-99,-138],[-79,20],[-119,27],[-97,40],[-59,31],[-74,-216]],"c":true}],"e":[{"i":[[6,3],[0,-5],[-0.752,-22.548],[-7,-13],[-11,-18],[-9,-3],[0,0],[0,0]],"o":[[-6,-3],[0,5],[1,30],[7,13],[11,18],[9,3],[0,0],[0,0]],"v":[[-388,-298],[-397,-288],[-381,-150],[-361,8],[-401,15],[-379,28],[-341,19],[-356,-228]],"c":true}]},{"t":15}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[3.637,14.035],[-6.562,-18.555],[0,0],[0,0],[0,0],[1.944,58.843],[5.869,46.436],[6.789,29.064]],"o":[[-3.783,-14.599],[12.079,34.152],[0,0],[0,0],[0,0],[-0.327,-9.886],[-2.413,-19.093],[-6.444,-27.588]],"v":[[-100.137,-270.035],[-81.079,-226.152],[-69.301,-172.891],[-65.375,-112.805],[-61.507,1.5],[-65.673,-78.614],[-71.869,-138.936],[-83.556,-205.912]],"c":true}],"e":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}],"e":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}],"e":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}],"e":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[3.05,20.138],[0,0],[9.544,-4.956],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[-3.05,-20.138],[0,0],[-12.518,6.5],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-72.45,-171.862],[-51.007,-10.5],[-65.982,-2.5],[-81.213,-61.644],[-90.187,-141.969]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[3.05,20.138],[0,0],[9.544,-4.956],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[-3.05,-20.138],[0,0],[-12.518,6.5],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-72.45,-171.862],[-51.007,-10.5],[-65.982,-2.5],[-81.213,-61.644],[-90.187,-141.969]],"c":true}],"e":[{"i":[[2.706,12.59],[7.96,-31.787],[0,0],[0,0],[0,0],[-52.303,4.363],[12.713,79.144],[5.528,26.028]],"o":[[-18.411,-85.645],[-8.037,32.093],[0,0],[0,0],[0,0],[17.982,-1.5],[-1.68,-10.456],[-8.303,-39.094]],"v":[[-41.089,-239.855],[-57.963,-260.093],[-97.507,-214.093],[-93.006,-168.319],[-76.507,-0.5],[-13.982,-7.5],[-8.213,-83.644],[-20.289,-143.83]],"c":true}]},{"t":16}]},"nm":"B"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":10,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"B blue layer 4","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[3.637,14.035],[-6.562,-18.555],[0,0],[0,0],[0,0],[1.944,58.843],[5.869,46.436],[6.789,29.064]],"o":[[-3.783,-14.599],[12.079,34.152],[0,0],[0,0],[0,0],[-0.327,-9.886],[-2.413,-19.093],[-6.444,-27.588]],"v":[[-100.137,-270.035],[-81.079,-226.152],[-69.301,-172.891],[-65.375,-112.805],[-61.507,1.5],[-65.673,-78.614],[-71.869,-138.936],[-83.556,-205.912]],"c":true}],"e":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[1.179,13.587],[-16.316,-11.006],[0,0],[0,0],[0,0],[51.329,28.838],[-0.631,46.436],[1.219,29.821]],"o":[[-1.863,-21.465],[33.579,22.652],[0,0],[0,0],[0,0],[-23.827,-13.386],[0.145,-10.708],[-0.944,-23.088]],"v":[[-180.137,-248.535],[-116.079,-227.152],[-76.301,-169.391],[-71.875,-105.305],[-64.007,0.5],[-127.173,-60.614],[-176.869,-121.436],[-176.556,-181.412]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[62.482,13.5],[0.713,41.144],[-1.198,29.377]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-23.658,-5.112],[-0.183,-10.545],[1.875,-45.981]],"v":[[-210.589,-237.355],[-131.463,-229.593],[-83.507,-180.593],[-80.113,-142.106],[-67.007,-0.5],[-149.982,-38.5],[-213.713,-83.644],[-211.875,-154.519]],"c":true}],"e":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0.592,13.423],[-38.037,-14.907],[0,0],[0,0],[0,0],[49.59,6.194],[2.062,42.216],[0.844,29.39]],"o":[[-0.911,-20.645],[31.01,12.153],[0,0],[0,0],[0,0],[-24.018,-3],[-0.514,-10.534],[-1.267,-44.142]],"v":[[-219.089,-243.355],[-134.463,-234.593],[-89.007,-187.093],[-84.613,-147.106],[-68.507,-0.5],[-150.482,-30.5],[-213.713,-68.644],[-215.875,-135.019]],"c":true}],"e":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[1.979,12.724],[-39.037,-17.407],[0,0],[0,0],[0,0],[49.482,7],[3.213,42.144],[3.102,33.18]],"o":[[-3.911,-25.145],[30.419,13.564],[0,0],[0,0],[0,0],[-13.966,-1.976],[-0.805,-10.559],[-4.66,-49.835]],"v":[[-212.089,-255.355],[-134.463,-244.093],[-94.007,-197.593],[-89.078,-155.355],[-71.007,-0.5],[-128.482,-21.5],[-193.213,-61.644],[-199.771,-135.061]],"c":true}],"e":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.758,12.578],[-32.825,-21.239],[0,0],[0,0],[0,0],[34.982,4],[4.713,44.644],[5.969,34.173]],"o":[[-8.911,-40.645],[27.963,18.093],[0,0],[0,0],[0,0],[-14.013,-1.602],[-1.112,-10.531],[-8.965,-51.327]],"v":[[-179.589,-262.855],[-130.463,-262.593],[-96.507,-222.593],[-91.042,-175.962],[-71.007,-5],[-104.982,-18.5],[-144.713,-64.144],[-156.854,-139.358]],"c":true}],"e":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[-3.55,-45.138],[0,0],[4.732,-1.5],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[3.168,40.285],[0,0],[-13.445,4.262],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-73.45,-164.862],[-61.507,-3],[-68.482,-0.25],[-81.213,-61.644],[-90.187,-141.969]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[3.235,12.104],[-17.053,-18.911],[0,0],[-3.55,-45.138],[0,0],[4.732,-1.5],[7.213,61.144],[5.736,34.461]],"o":[[-17.411,-65.145],[14.963,16.593],[0,0],[3.168,40.285],[0,0],[-13.445,4.262],[-1.291,-10.944],[-8.055,-48.393]],"v":[[-114.589,-252.855],[-102.463,-279.593],[-83.507,-232.593],[-73.45,-164.862],[-61.507,-3],[-68.482,-0.25],[-81.213,-61.644],[-90.187,-141.969]],"c":true}],"e":[{"i":[[2.706,12.59],[7.96,-31.787],[0,0],[0,0],[0,0],[-52.303,4.363],[12.713,79.144],[5.528,26.028]],"o":[[-18.411,-85.645],[-8.037,32.093],[0,0],[0,0],[0,0],[17.982,-1.5],[-1.68,-10.456],[-8.303,-39.094]],"v":[[-41.089,-239.855],[-57.963,-260.093],[-97.507,-214.093],[-93.006,-168.319],[-76.507,-0.5],[-13.982,-7.5],[-8.213,-83.644],[-20.289,-143.83]],"c":true}]},{"t":16}]},"nm":"B"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":9,"op":16,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":9,"ty":4,"nm":"B blue layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[20.982,16]],"o":[[0,0],[0,0],[-11.216,-8.553]],"v":[[-78.007,-37.093],[-72.507,0.5],[-84.482,-27.5]],"c":true}},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":14,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":26.875},"p":{"k":[{"i":{"x":0.663,"y":0.933},"o":{"x":0.334,"y":0.066},"n":"0p663_0p933_0p334_0p066","t":9,"s":[269.705,292.352,0],"e":[250.705,285.352,0],"to":[-0.5,-0.33333334326744,0],"ti":[-0.60055363178253,-0.48845085501671,0]},{"i":{"x":0.685,"y":1},"o":{"x":0.334,"y":0.228},"n":"0p685_1_0p334_0p228","t":11,"s":[250.705,285.352,0],"e":[276,308,0],"to":[9.00963115692139,7.32784128189087,0],"ti":[-0.48727434873581,0,0]},{"t":22.5016243755817}]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"ip":10.0000001490116,"op":24.4098640978336,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":11,"ty":3,"nm":"Null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":-21.596},"p":{"k":[{"i":{"x":0.58,"y":0.829},"o":{"x":0.278,"y":0.114},"n":"0p58_0p829_0p278_0p114","t":9,"s":[217.311,226.631,0],"e":[198.311,219.631,0],"to":[0,0,0],"ti":[-3.21461248397827,3.18686246871948,0]},{"i":{"x":0.726,"y":1},"o":{"x":0.278,"y":0.371},"n":"0p726_1_0p278_0p371","t":11,"s":[198.311,219.631,0],"e":[223,195,0],"to":[8.70546340942383,-8.63031387329102,0],"ti":[-1.45636057853699,0,0]},{"t":21.5996034443378}]},"a":{"k":[0,0,0]},"s":{"k":[100,-100,100]}},"ao":0,"ip":10.0000001490116,"op":24.4098640978336,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":12,"ty":3,"nm":"null smoke","parent":34,"ks":{"o":{"k":0},"r":{"k":16.774},"p":{"k":[{"i":{"x":0.577,"y":0.847},"o":{"x":0.284,"y":0.103},"n":"0p577_0p847_0p284_0p103","t":9,"s":[261.182,221.23,0],"e":[242.182,214.23,0],"to":[0,0,0],"ti":[-3.1457417011261,0.33704376220703,0]},{"i":{"x":0.697,"y":1},"o":{"x":0.284,"y":0.405},"n":"0p697_1_0p284_0p405","t":11,"s":[242.182,214.23,0],"e":[263,212,0],"to":[7.38616800308228,-0.79137516021729,0],"ti":[-3.2727952003479,0.3506566286087,0]},{"t":18.9003057777882}]},"a":{"k":[0,0,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":9.9,"s":[100,100,100],"e":[122,122,100]},{"t":20.7004822790623}]}},"ao":0,"ip":10.0000001490116,"op":24.4098640978336,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":13,"ty":3,"nm":"Null 26","parent":34,"ks":{"o":{"k":0},"r":{"k":-11.144},"p":{"k":[{"i":{"x":0.573,"y":0.757},"o":{"x":0.294,"y":0.167},"n":"0p573_0p757_0p294_0p167","t":9,"s":[267.556,276.269,0],"e":[248.556,269.269,0],"to":[0,0,0],"ti":[-4.61654806137085,2.50612592697144,0]},{"i":{"x":0.699,"y":1},"o":{"x":0.294,"y":0.426},"n":"0p699_1_0p294_0p426","t":11,"s":[248.556,269.269,0],"e":[273,256,0],"to":[9.04685020446777,-4.91114711761475,0],"ti":[-3.86238408088684,2.09672284126282,0]},{"t":17.4897499382496}]},"a":{"k":[0,0,0]},"s":{"k":[100,-100,100]}},"ao":0,"ip":10.0000001490116,"op":21.5510979294777,"st":-11.1670814454556,"bm":0,"sr":0.99000012874603},{"ddd":0,"ind":14,"ty":4,"nm":"B blue layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[-1.24,5.104],[0.198,1.892],[0,0],[0,0],[0,0],[-0.804,-2.124],[0.343,-5.77],[-1.462,6.091]],"o":[[1.049,-4.319],[-0.297,-2.847],[0,0],[0,0],[0,0],[0.386,1.02],[0.093,-2.77],[0.816,-3.399]],"v":[[-22.001,-21.919],[-20.415,-30.453],[-22.49,-31.96],[-27.759,-19.513],[-32.548,3.666],[-29.736,4.974],[-28.593,7.27],[-25.53,-6.238]],"c":true}],"e":[{"i":[[-1.032,7.042],[1.743,2.453],[0,0],[0,0],[0,0],[-3.84,-2.615],[-0.171,-9.84],[-1.176,8.399]],"o":[[0.873,-5.959],[-2.624,-3.692],[0,0],[0,0],[0,0],[1.845,1.256],[2.053,-13.363],[0.656,-4.688]],"v":[[-19.587,-23.915],[-19.439,-35.572],[-25.627,-39.562],[-30.78,-20.831],[-37.568,3.797],[-29.696,6.026],[-25.346,16.687],[-22.197,-8.804]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[{"i":[[-1.032,7.042],[1.743,2.453],[0,0],[0,0],[0,0],[-3.84,-2.615],[-0.171,-9.84],[-1.176,8.399]],"o":[[0.873,-5.959],[-2.624,-3.692],[0,0],[0,0],[0,0],[1.845,1.256],[2.053,-13.363],[0.656,-4.688]],"v":[[-19.587,-23.915],[-19.439,-35.572],[-25.627,-39.562],[-30.78,-20.831],[-37.568,3.797],[-29.696,6.026],[-25.346,16.687],[-22.197,-8.804]],"c":true}],"e":[{"i":[[-0.284,9.426],[4.036,2.935],[0,0],[0,0],[0,0],[-7.528,-4.291],[-1.775,-13.654],[-0.23,11.234]],"o":[[0.241,-7.977],[-6.074,-4.417],[0,0],[0,0],[0,0],[6.05,3.449],[0.725,-17.904],[0.128,-6.27]],"v":[[-11.741,-32.523],[-17.536,-48.935],[-30.445,-51.84],[-35.936,-26.366],[-41.832,3.676],[-25.8,5.301],[-13.725,26.404],[-12.128,-11.48]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[-0.284,9.426],[4.036,2.935],[0,0],[0,0],[0,0],[-7.528,-4.291],[-1.775,-13.654],[-0.23,11.234]],"o":[[0.241,-7.977],[-6.074,-4.417],[0,0],[0,0],[0,0],[6.05,3.449],[0.725,-17.904],[0.128,-6.27]],"v":[[-11.741,-32.523],[-17.536,-48.935],[-30.445,-51.84],[-35.936,-26.366],[-41.832,3.676],[-25.8,5.301],[-13.725,26.404],[-12.128,-11.48]],"c":true}],"e":[{"i":[[0.512,9.416],[12.036,5.935],[0,0],[0,0],[0,0],[-10.429,-3.711],[-2.775,-15.904],[1.665,20.58]],"o":[[-0.759,-13.977],[-8.794,-4.337],[0,0],[0,0],[0,0],[11.8,4.199],[-1.275,-18.904],[-0.872,-10.77]],"v":[[-0.741,-42.023],[-15.536,-66.935],[-34.945,-68.34],[-40.936,-29.866],[-44.332,2.676],[-17.3,1.801],[4.275,28.904],[1.372,-13.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0.512,9.416],[12.036,5.935],[0,0],[0,0],[0,0],[-10.429,-3.711],[-2.775,-15.904],[1.665,20.58]],"o":[[-0.759,-13.977],[-8.794,-4.337],[0,0],[0,0],[0,0],[11.8,4.199],[-1.275,-18.904],[-0.872,-10.77]],"v":[[-0.741,-42.023],[-15.536,-66.935],[-34.945,-68.34],[-40.936,-29.866],[-44.332,2.676],[-17.3,1.801],[4.275,28.904],[1.372,-13.73]],"c":true}],"e":[{"i":[[2.118,9.189],[13.168,3.137],[0,0],[0,0],[0,0],[-21.716,-6.523],[-3.775,-12.404],[3.122,20.41]],"o":[[-4.259,-18.477],[-14.964,-3.565],[0,0],[0,0],[0,0],[22.3,6.699],[-2.775,-18.904],[-2.872,-18.77]],"v":[[12.259,-65.023],[-14.536,-90.935],[-40.945,-84.34],[-43.436,-51.366],[-48.332,2.176],[-5.8,-5.199],[26.275,28.404],[16.372,-36.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[2.118,9.189],[13.168,3.137],[0,0],[0,0],[0,0],[-21.716,-6.523],[-3.775,-12.404],[3.122,20.41]],"o":[[-4.259,-18.477],[-14.964,-3.565],[0,0],[0,0],[0,0],[22.3,6.699],[-2.775,-18.904],[-2.872,-18.77]],"v":[[12.259,-65.023],[-14.536,-90.935],[-40.945,-84.34],[-43.436,-51.366],[-48.332,2.176],[-5.8,-5.199],[26.275,28.404],[16.372,-36.73]],"c":true}],"e":[{"i":[[2.118,9.189],[13.533,0.289],[0,0],[0,0],[0,0],[-54.798,-20.458],[-2.775,-7.904],[4.128,20.23]],"o":[[-4.259,-18.477],[-26.464,-0.565],[0,0],[0,0],[0,0],[23.3,8.699],[-0.275,-14.904],[-3.009,-14.743]],"v":[[31.259,-89.523],[-7.536,-119.435],[-46.945,-102.34],[-48.936,-56.366],[-51.832,2.676],[27.2,-12.199],[54.275,22.904],[40.872,-40.73]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[2.118,9.189],[13.533,0.289],[0,0],[0,0],[0,0],[-54.798,-20.458],[-2.775,-7.904],[4.128,20.23]],"o":[[-4.259,-18.477],[-26.464,-0.565],[0,0],[0,0],[0,0],[23.3,8.699],[-0.275,-14.904],[-3.009,-14.743]],"v":[[31.259,-89.523],[-7.536,-119.435],[-46.945,-102.34],[-48.936,-56.366],[-51.832,2.676],[27.2,-12.199],[54.275,22.904],[40.872,-40.73]],"c":true}],"e":[{"i":[[2.741,9.023],[35.536,-9.065],[0,0],[0,0],[0,0],[-58.271,5.078],[7.345,30.067],[7.32,28.81]],"o":[[-6.003,-19.766],[-38.857,9.912],[0,0],[0,0],[0,0],[72.3,-6.301],[-3.275,-13.404],[-3.372,-13.27]],"v":[[77.259,-132.023],[-1.536,-158.935],[-53.945,-122.34],[-54.436,-66.866],[-54.832,1.176],[23.7,-42.699],[103.275,-31.596],[86.872,-91.23]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[2.741,9.023],[35.536,-9.065],[0,0],[0,0],[0,0],[-58.271,5.078],[7.345,30.067],[7.32,28.81]],"o":[[-6.003,-19.766],[-38.857,9.912],[0,0],[0,0],[0,0],[72.3,-6.301],[-3.275,-13.404],[-3.372,-13.27]],"v":[[77.259,-132.023],[-1.536,-158.935],[-53.945,-122.34],[-54.436,-66.866],[-54.832,1.176],[23.7,-42.699],[103.275,-31.596],[86.872,-91.23]],"c":true}],"e":[{"i":[[2.692,12.158],[14.536,-18.065],[0,0],[0,0],[0,0],[-45.886,36.274],[7.225,30.096],[8.494,27.268]],"o":[[-3.759,-16.977],[-25.14,31.242],[0,0],[0,0],[0,0],[35.8,-28.301],[-2.392,-9.964],[-7.872,-25.27]],"v":[[26.759,-245.023],[-23.036,-213.935],[-60.445,-143.84],[-59.936,-99.866],[-58.832,1.676],[-5.3,-69.199],[64.275,-130.596],[40.372,-201.73]],"c":true}]},{"t":8}]},"nm":"B"},{"ty":"mm","mm":2,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":1,"op":9,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":15,"ty":4,"nm":"B orange layer 3 shadow 2","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-99,-265],[-121,-264],[-133,-219],[-107,10],[-84,33],[-49,13],[-62,-108]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}],"e":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[60,-286],[-92,-274],[-104,-229],[-78,0],[-55,23],[104,4],[115,-139]],"c":true}]},{"t":19}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-264.603,-181.739],[-262.939,-148.686],[-267.481,-144.898],[-273.154,-192.488],[-271.112,-195.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}],"e":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}],"e":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}],"e":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-262.931,-52.995],[-268.677,-50.995],[-274.177,-102.658],[-270.431,-105.658],[-264.344,-84.176]],"c":true}],"e":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}],"e":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":16,"ty":4,"nm":"B orange layer 3 shadow","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-99,-265],[-121,-264],[-133,-219],[-107,10],[-84,33],[-49,13],[-62,-108]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-70,-275],[-92,-274],[-104,-229],[-78,0],[-55,23],[-20,3],[-33,-118]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[-25.168,-278.566],[-92,-274],[-104,-229],[-78,0],[-55,23],[22.285,0.453],[-2.338,-146.717]],"c":true}],"e":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[16.753,14.499],[0,0],[0,0],[0,0],[0,0],[-3,10],[21.96,31.036]],"o":[[-16.753,-14.499],[0,0],[0,0],[0,0],[0,0],[3,-10],[2.96,-38.964]],"v":[[19.753,-282.501],[-92,-274],[-104,-229],[-78,0],[-55,23],[64.682,-1.606],[39.04,-141.036]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[24,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[12,-31]],"v":[[67,-296],[-92,-274],[-104,-229],[-78,0],[-55,23],[110,9],[57,-143]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[-3,10],[4,29]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[3,-10],[-4,-29]],"v":[[60,-286],[-92,-274],[-104,-229],[-78,0],[-55,23],[104,4],[115,-139]],"c":true}]},{"t":19}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":14,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":17,"ty":4,"nm":"B orange layer 5","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-264.603,-181.739],[-262.939,-148.686],[-267.481,-144.898],[-273.154,-192.488],[-271.112,-195.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-1.324,-11.343],[1.439,-10.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[3.112,-1.724]],"v":[[-60.603,-177.739],[-58.939,-144.686],[-63.481,-140.898],[-69.154,-188.488],[-67.112,-191.276]],"c":true}],"e":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-1.324,-11.343],[4.939,-8.814],[0,0],[0,0],[0,0]],"o":[[1.603,13.739],[0,0],[0,0],[0,0],[6.612,-3.724]],"v":[[-40.603,-178.239],[-44.439,-146.186],[-54.981,-139.898],[-61.654,-188.488],[-53.612,-193.776]],"c":true}],"e":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-0.897,-12.761],[7.439,-4.314],[0,0],[0,0],[0,0]],"o":[[1.049,14.93],[0,0],[0,0],[0,0],[11.112,-4.224]],"v":[[-22.103,-175.239],[-29.439,-144.686],[-49.481,-139.398],[-53.654,-189.988],[-40.112,-193.776]],"c":true}],"e":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-2.295,-14.342],[14.615,-7.06],[0,0],[0,0],[0,0]],"o":[[2.247,14.043],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[-5.749,-174.483],[-19.893,-141.684],[-44.391,-137.152],[-47.397,-188.494],[-26.535,-193.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[7.397,-171.739],[-12.939,-138.686],[-40.981,-136.898],[-43.154,-187.488],[-17.112,-191.276]],"c":true}],"e":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[17.58,-1.876],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.855,-1.149]],"v":[[16.498,-167.632],[-5.273,-137.269],[-37.547,-135.91],[-39.662,-187.025],[-9.278,-190.383]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[24.639,-165.025],[-0.738,-135.852],[-35.862,-134.172],[-36.92,-187.061],[-2.991,-188.991]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[28.279,-161.917],[4.297,-134.435],[-34.177,-133.435],[-34.177,-187.098],[3.297,-187.598]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[31.613,-160.417],[4.963,-133.935],[-33.677,-133.268],[-33.677,-186.264],[4.297,-186.598]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[32.279,-158.917],[6.297,-132.935],[-32.677,-132.935],[-32.677,-184.598],[6.297,-184.598]],"c":true}]},{"t":24}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-262.931,-52.995],[-268.677,-50.995],[-274.177,-102.658],[-270.431,-105.658],[-264.344,-84.176]],"c":true}],"e":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[2.931,-7.005],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[2.931,0.658],[2.344,19.176]],"v":[[-46.431,-52.995],[-52.177,-50.995],[-57.677,-102.658],[-53.931,-105.658],[-47.844,-84.176]],"c":true}],"e":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[7.931,-3.505],[0,0],[0,0],[0,0],[-1.768,-14.461]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.344,19.176]],"v":[[-32.931,-51.495],[-45.677,-48.995],[-51.177,-100.658],[-40.431,-104.658],[-26.844,-83.176]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[8.931,-2.842],[2.589,13.962]],"v":[[-19.931,-48.995],[-40.177,-47.495],[-45.177,-99.158],[-24.431,-103.158],[-6.344,-82.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[15.681,-1.092],[2.589,13.962]],"v":[[-7.681,-46.495],[-37.927,-44.245],[-41.177,-97.908],[-14.681,-101.408],[8.906,-80.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[2.589,13.962]],"v":[[-0.931,-44.995],[-36.677,-42.995],[-39.177,-97.158],[-3.931,-100.158],[21.656,-76.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-1.77,-14.283]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.726,14.041]],"v":[[7.902,-44.495],[-34.344,-44.162],[-35.844,-96.158],[5.902,-97.825],[29.989,-73.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[12.235,-42.745],[-33.761,-42.329],[-34.761,-95.908],[11.235,-96.242],[37.322,-69.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[13.569,-41.995],[-32.677,-41.995],[-33.677,-95.658],[16.569,-94.658],[40.656,-68.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.658],[43.156,-67.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[16.569,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-93.658],[43.156,-67.676]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":18,"ty":4,"nm":"B orange layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[-17.127,-8.576],[-4.287,-8.856]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[11.982,6],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-46.507,-102.093],[-51.007,3.5],[-21.482,0],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-73.259,-145.537],[-82.089,-178.355],[-90.963,-174.593],[-83.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-87.007,-159.593],[-69.007,-0.5],[-59.482,-33.5],[-71.713,-94.644]],"c":true}],"e":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[2.759,16.037],[1.089,6.855],[3.15,2.884],[0,0],[0,0],[0.024,23.358],[2.213,13.144]],"o":[[-0.741,-7.963],[-2.92,-18.378],[-1.537,-1.407],[0,0],[0,0],[-0.018,-17.5],[-2.755,-16.362]],"v":[[-74.759,-145.537],[-84.089,-185.855],[-90.463,-219.593],[-95.507,-208.093],[-71.507,0.5],[-51.482,-32],[-65.713,-94.144]],"c":true}],"e":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.509,31.287],[6.813,20.34],[4.963,-11.907],[0,0],[0,0],[-17.018,16],[9.213,50.737]],"o":[[-6.241,-30.463],[-5.911,-17.645],[-6.06,14.54],[0,0],[0,0],[9.992,-9.394],[-3.787,-20.856]],"v":[[-51.259,-158.537],[-71.589,-238.355],[-80.963,-225.093],[-96.007,-202.593],[-72.007,0],[-29.482,-25.5],[-34.213,-88.644]],"c":true}],"e":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[8.509,31.287],[4.772,20.913],[18.771,-35.562],[0,0],[0,0],[-35.294,7.846],[9.713,50.644]],"o":[[-6.241,-30.463],[-20.911,-91.645],[-14.037,26.593],[0,0],[0,0],[44.982,-10],[-4.991,-26.022]],"v":[[-6.759,-153.537],[-31.089,-246.855],[-59.463,-246.093],[-97.007,-208.093],[-74.007,0.5],[-18.482,-13.5],[11.287,-77.644]],"c":true}],"e":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[9.759,27.037],[3.56,21.153],[32.297,-24.991],[0,0],[0,0],[-51.855,8.105],[16.213,81.144]],"o":[[-6.241,-30.463],[-13.911,-82.645],[-39.537,30.593],[0,0],[0,0],[47.982,-7.5],[-5.191,-25.982]],"v":[[27.241,-164.537],[14.411,-234.855],[-36.963,-250.093],[-97.507,-214.093],[-76.507,-0.5],[0.018,-9],[47.287,-86.144]],"c":true}],"e":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[9.759,25.037],[3.589,22.355],[46.963,-21.907],[0,0],[0,0],[-52.444,2.078],[5.958,46.178]],"o":[[-1.241,-27.463],[-10.199,-63.523],[-35.55,16.583],[0,0],[0,0],[50.482,-2],[-5.787,-44.856]],"v":[[49.241,-157.537],[45.911,-224.855],[-24.963,-243.593],[-95.007,-217.593],[-76.507,-0.5],[33.018,-7],[72.287,-80.144]],"c":true}],"e":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,21.037],[2.598,21.286],[45.963,-10.657],[0,0],[0,0],[-28.018,1],[5.463,51.394]],"o":[[3.509,-24.213],[-4.161,-64.895],[-38.537,12.343],[0,0],[0,0],[59.982,2.5],[-3.676,-32.795]],"v":[[59.241,-140.287],[64.661,-201.605],[-11.463,-241.343],[-91.757,-220.343],[-77.257,-0.75],[28.018,-4.5],[84.787,-81.144]],"c":true}],"e":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[21.759,21.537],[2.058,21.352],[37.463,-5.907],[0,0],[0,0],[0,0],[4.713,56.644]],"o":[[10.259,-19.963],[-5.411,-56.145],[-38.749,6.11],[0,0],[0,0],[45.482,1],[-2.393,-28.758]],"v":[[62.241,-133.037],[74.911,-192.355],[-0.463,-236.593],[-88.507,-223.093],[-78.007,-1],[23.018,-2.5],[92.287,-70.144]],"c":true}],"e":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[0.089,22.605],[44.213,-5.407],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[11.759,-13.713],[-2.705,-47.408],[-24.787,2.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[60.241,-127.787],[78.411,-180.605],[5.787,-233.593],[-86.007,-223.593],[-78.007,-1],[24.768,-0.25],[93.287,-66.644]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[21.149,8.762],[0,21.451],[38.463,-2.407],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[59.241,-124.037],[79.411,-176.855],[14.537,-231.593],[-83.507,-224.093],[-78.007,-1],[23.518,0],[94.787,-61.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":22.253,"s":[{"i":[[21.149,8.762],[0.749,21.438],[38.114,-1.203],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.741,-120.537],[79.911,-168.605],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[92.037,-63.144]],"c":true}],"e":[{"i":[[21.149,8.762],[0,21.451],[37.766,0],[0,0],[0,0],[0,0],[0,41.089]],"o":[[15.106,-9.064],[0,-38.672],[0,0],[0,0],[0,0],[37.463,0],[0,-29.004]],"v":[[55.241,-119.037],[79.411,-164.355],[12.037,-226.593],[-79.507,-226.593],[-79.507,0],[23.518,0],[90.287,-63.144]],"c":true}]},{"t":24}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":11,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":19,"ty":4,"nm":"B orange layer 2 shadow","parent":34,"ks":{"o":{"k":5},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[27,-20],[0,0],[-5,-11],[-20,3],[0,21],[-1,63]],"o":[[-10.811,8.008],[0,0],[5,11],[20,-3],[0,-21],[1,-63]],"v":[[-55,-172],[-86,-85],[-92,10],[-95,22],[0,21],[-15,-137]],"c":true}],"e":[{"i":[[27,-20],[0,0],[-5,-11],[-20,3],[0,21],[-1,63]],"o":[[-10.811,8.008],[0,0],[5,11],[20,-3],[0,-21],[1,-63]],"v":[[-55,-172],[-86,-85],[-92,10],[-58,40],[42,28],[20,-147]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[27,-20],[0,0],[-5,-11],[-20,3],[0,21],[-1,63]],"o":[[-10.811,8.008],[0,0],[5,11],[20,-3],[0,-21],[1,-63]],"v":[[-55,-172],[-86,-85],[-92,10],[-58,40],[42,28],[20,-147]],"c":true}],"e":[{"i":[[55,-29],[0,0],[-5,-11],[-20,3],[0,21],[28,61]],"o":[[-55,29],[0,0],[5,11],[20,-3],[0,-21],[-26.285,-57.263]],"v":[[-79,-179],[-124,-104],[-119,72],[-21,87],[50,-29],[4,-198]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[55,-29],[0,0],[-5,-11],[-20,3],[0,21],[28,61]],"o":[[-55,29],[0,0],[5,11],[20,-3],[0,-21],[-26.285,-57.263]],"v":[[-79,-179],[-124,-104],[-119,72],[-21,87],[50,-29],[4,-198]],"c":true}],"e":[{"i":[[29.478,-54.745],[0,0],[-5,-11],[-20,3],[0,21],[13,66]],"o":[[-7,13],[0,0],[5,11],[20,-3],[0,-21],[-12.177,-61.82]],"v":[[-115,-165],[-124,-104],[-107,16],[-80,39],[-19,5],[-54,-216]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[29.478,-54.745],[0,0],[-5,-11],[-20,3],[0,21],[13,66]],"o":[[-7,13],[0,0],[5,11],[20,-3],[0,-21],[-12.177,-61.82]],"v":[[-115,-165],[-124,-104],[-107,16],[-80,39],[-19,5],[-54,-216]],"c":true}],"e":[{"i":[[29.478,-54.745],[0,0],[-5,-11],[-20,3],[0,21],[13,66]],"o":[[-7,13],[0,0],[5,11],[20,-3],[0,-21],[-12.177,-61.82]],"v":[[-150,-165],[-159,-104],[-142,16],[-115,39],[-54,5],[-77,-199]],"c":true}]},{"t":10}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-39.481,-45.472],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.545875,6.84424999999999],[0.27600000000001,3.45950000000002],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.37050000000001,-3.98150000000001],[-0.545875,-6.84424999999999],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-80.744875,-161.3375],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B 2"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":11,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":20,"ty":4,"nm":"B orange layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-39.481,-45.472],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-44.677,-58.245],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.759,26.037],[0.589,9.355],[8.227,2.939],[0,0],[0,0],[0,0],[-15.518,-7.5],[-1.787,-7.356]],"o":[[-1.241,-21.463],[-0.382,-6.06],[-9.537,-3.407],[0,0],[0,0],[0,0],[12.065,5.831],[-1.787,-26.856]],"v":[[-12.759,-43.537],[-15.089,-87.355],[-25.963,-106.093],[-47.257,-101.593],[-49.484,-64.148],[-53.507,3.5],[-22.232,0.5],[-8.713,17.856]],"c":true}],"e":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[1.35375,9.22725],[1.2945,5.92749999999999],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-3.1205,-19.9815],[-1.35375,-9.22725],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[12.9565,-90.9865],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[1.54124999999999,8.22725],[1.5445,4.67749999999998],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-3.62050000000001,-19.2315],[-1.54125000000001,-8.22725],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[76.519,-124.8615],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.4935,12.920375],[2.2355,2.65499999999997],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-3.6205,-10.9815],[-4.4935,-12.920375],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[32.28725,-233.940875],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[3.073,9.17012500000001],[0.66749999999999,3.40600000000001],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-1.3705,-6.23150000000001],[-3.07300000000001,-9.17012499999998],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-60.45125,-196.815125],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.545875,6.84424999999999],[0.27600000000001,3.45950000000002],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.37050000000001,-3.98150000000001],[-0.545875,-6.84424999999999],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-80.744875,-161.3375],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.993,13.755],[-0.576,6.238],[1.302,0.585],[0,0],[0,0],[-2.275,-1.384],[-0.28,-3.435]],"o":[[1.757,-16.495],[0.509,-5.518],[-2.446,-1.099],[0,0],[0,0],[1.508,0.917],[1.082,-12.356]],"v":[[-36.507,-32.755],[-33.509,-58.982],[-33.554,-66.651],[-36.609,-64.578],[-46.5,1.214],[-41.725,1.384],[-40.332,4.606]],"c":true}],"e":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.741,19.537],[-0.161,8.855],[3.194,1.609],[0,0],[0,0],[-8.518,-3.5],[-1.037,-4.856]],"o":[[-0.241,-13.963],[0.11,-6.071],[-3.787,-1.907],[0,0],[0,0],[4.451,1.829],[0.963,-28.106]],"v":[[-29.259,-43.037],[-28.339,-74.105],[-32.213,-84.593],[-40.757,-84.843],[-54.257,6.75],[-37.482,2.75],[-30.463,12.606]],"c":true}],"e":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0.832,26.037],[0.279,9.355],[-0.34,-0.907],[0,0],[0,0],[-1.764,2.5],[-2,4.644]],"o":[[-0.587,-21.463],[-0.181,-6.06],[-2.641,3.629],[0,0],[0,0],[1.764,-2.5],[3,-26.606]],"v":[[-48.414,-64.537],[-46.516,-92.355],[-47.66,-93.593],[-51.128,-76.843],[-60.507,13.25],[-56.514,6],[-52.5,-2.394]],"c":true}],"e":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[5.759,37.537],[2.589,11.855],[15.486,1.354],[0,0],[0,0],[-32.518,-11.5],[-4.287,-8.856]],"o":[[-6.241,-39.963],[-1.296,-5.932],[-27.537,-2.407],[0,0],[0,0],[21.489,7.6],[-3.287,-20.356]],"v":[[19.241,-49.037],[9.411,-111.855],[-17.463,-132.593],[-53.507,-120.593],[-55.507,2.5],[4.018,-9.5],[30.287,16.856]],"c":true}],"e":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[7.259,32.537],[3.089,9.355],[44.113,-3.3],[0,0],[0,0],[-53.018,1],[3.713,19.144]],"o":[[-7.241,-38.463],[-1.904,-5.765],[-48.037,3.593],[0,0],[0,0],[60.505,-1.141],[-3.159,-16.288]],"v":[[83.741,-85.537],[72.411,-142.355],[4.537,-172.593],[-61.007,-138.593],[-59.007,1.5],[28.018,-33.5],[99.787,-17.644]],"c":true}],"e":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[10.759,29.037],[4.471,5.31],[29.463,-40.407],[0,0],[0,0],[-43.018,23.5],[3.713,19.144]],"o":[[-7.241,-21.963],[-3.911,-4.645],[-7.99,10.959],[0,0],[0,0],[44.538,-24.331],[-3.159,-16.288]],"v":[[45.241,-195.037],[21.411,-260.355],[-37.963,-203.593],[-68.007,-155.093],[-61.507,3],[11.018,-60],[71.287,-111.144]],"c":true}],"e":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[4.259,17.037],[1.335,6.812],[2.963,-14.907],[0,0],[0,0],[-7.018,26.5],[3.713,19.144]],"o":[[-2.741,-12.463],[-0.911,-4.645],[-2.644,13.302],[0,0],[0,0],[9.673,-36.528],[-3.159,-16.288]],"v":[[-52.759,-171.537],[-67.089,-217.855],[-68.963,-189.593],[-76.007,-170.093],[-64.007,1.5],[-40.982,-50],[-39.713,-115.644]],"c":true}],"e":[{"i":[[2.759,16.037],[0.552,6.919],[3.15,2.884],[0,0],[0,0],[4.147,22.987],[2.213,13.144]],"o":[[-0.741,-7.963],[-0.411,-5.145],[-1.537,-1.407],[0,0],[0,0],[-3.518,-19.5],[-2.755,-16.362]],"v":[[-79.259,-143.537],[-82.089,-178.355],[-90.963,-174.593],[-80.007,-159.593],[-66.507,1.5],[-58.482,-36],[-71.713,-94.644]],"c":true}]},{"t":11}]},"nm":"B 2"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":4,"op":11,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":21,"ty":4,"nm":"B blue layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[0,0],[1.135,0.16],[0.519,-0.169],[0.368,-1.304],[0.165,-1.422],[-2.463,0.226],[-0.024,0.731],[0.1,1.443]],"o":[[0,0],[-0.591,-0.084],[-0.572,0.81],[-0.408,1.446],[-0.141,1.212],[2.637,-0.242],[-0.113,-1.414],[-0.065,-0.946]],"v":[[-29.39,-0.524],[-31.301,-0.669],[-32.486,-0.16],[-34.047,2.548],[-34.859,5.55],[-31.571,8.49],[-28.75,5.075],[-29.073,1.857]],"c":true}],"e":[{"i":[[0,0],[4.131,0.584],[1.89,-0.615],[1.34,-4.746],[0.602,-5.175],[-8.964,0.823],[-0.088,2.66],[0.363,5.252]],"o":[[0,0],[-2.152,-0.304],[-2.08,2.95],[-1.486,5.262],[-0.513,4.413],[9.6,-0.881],[-0.41,-5.148],[-0.238,-3.443]],"v":[[-27.079,-7.92],[-34.036,-8.446],[-38.349,-6.594],[-44.031,3.262],[-46.987,14.191],[-35.017,24.893],[-24.75,12.463],[-25.925,0.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":2,"s":[{"i":[[0,0],[4.131,0.584],[1.89,-0.615],[1.34,-4.746],[0.602,-5.175],[-8.964,0.823],[-0.088,2.66],[0.363,5.252]],"o":[[0,0],[-2.152,-0.304],[-2.08,2.95],[-1.486,5.262],[-0.513,4.413],[9.6,-0.881],[-0.41,-5.148],[-0.238,-3.443]],"v":[[-27.079,-7.92],[-34.036,-8.446],[-38.349,-6.594],[-44.031,3.262],[-46.987,14.191],[-35.017,24.893],[-24.75,12.463],[-25.925,0.75]],"c":true}],"e":[{"i":[[0,0],[8.324,1.188],[3.808,-1.25],[2.7,-9.654],[1.213,-10.525],[-18.063,1.674],[-0.178,5.41],[0.731,10.682]],"o":[[0,0],[-4.337,-0.619],[-4.192,6],[-2.994,10.703],[-1.034,8.975],[19.344,-1.793],[-0.826,-10.471],[-0.479,-7.002]],"v":[[-18.099,-21.695],[-32.116,-22.765],[-40.808,-19],[-52.256,1.047],[-58.213,23.275],[-34.094,45.043],[-13.405,19.761],[-15.773,-4.063]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[0,0],[8.324,1.188],[3.808,-1.25],[2.7,-9.654],[1.213,-10.525],[-18.063,1.674],[-0.178,5.41],[0.731,10.682]],"o":[[0,0],[-4.337,-0.619],[-4.192,6],[-2.994,10.703],[-1.034,8.975],[19.344,-1.793],[-0.826,-10.471],[-0.479,-7.002]],"v":[[-18.099,-21.695],[-32.116,-22.765],[-40.808,-19],[-52.256,1.047],[-58.213,23.275],[-34.094,45.043],[-13.405,19.761],[-15.773,-4.063]],"c":true}],"e":[{"i":[[0,0],[12.843,1.833],[4.559,8.938],[3.186,-15.134],[3.035,-13.004],[-27.952,1.396],[-0.275,8.346],[1.128,16.48]],"o":[[0,0],[-6.691,-0.955],[-2.441,12.438],[-4.015,19.071],[-3.168,13.574],[31.05,-1.551],[-1.275,-16.154],[-0.74,-10.803]],"v":[[-2.195,-42.59],[-24.593,-43.083],[-44.559,-47.688],[-56.436,-7.116],[-64.082,27.176],[-28.8,62.301],[4.275,27.154],[0.622,-14.23]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[12.843,1.833],[4.559,8.938],[3.186,-15.134],[3.035,-13.004],[-27.952,1.396],[-0.275,8.346],[1.128,16.48]],"o":[[0,0],[-6.691,-0.955],[-2.441,12.438],[-4.015,19.071],[-3.168,13.574],[31.05,-1.551],[-1.275,-16.154],[-0.74,-10.803]],"v":[[-2.195,-42.59],[-24.593,-43.083],[-44.559,-47.688],[-56.436,-7.116],[-64.082,27.176],[-28.8,62.301],[4.275,27.154],[0.622,-14.23]],"c":true}],"e":[{"i":[[0,0],[30.844,0.507],[4.059,4.688],[1.936,-11.384],[-2.168,-13.176],[-27.451,0.398],[1.225,11.846],[3.429,20.36]],"o":[[0,0],[-10.157,-0.167],[-1.941,14.188],[-3.267,19.214],[1.6,9.723],[38.05,-0.551],[-1.275,-15.904],[-3.372,-20.02]],"v":[[12.805,-58.84],[-26.843,-38.833],[-49.309,-49.938],[-55.686,-8.616],[-60.582,43.176],[-20.55,70.051],[26.275,28.904],[17.122,-30.23]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[30.844,0.507],[4.059,4.688],[1.936,-11.384],[-2.168,-13.176],[-27.451,0.398],[1.225,11.846],[3.429,20.36]],"o":[[0,0],[-10.157,-0.167],[-1.941,14.188],[-3.267,19.214],[1.6,9.723],[38.05,-0.551],[-1.275,-15.904],[-3.372,-20.02]],"v":[[12.805,-58.84],[-26.843,-38.833],[-49.309,-49.938],[-55.686,-8.616],[-60.582,43.176],[-20.55,70.051],[26.275,28.904],[17.122,-30.23]],"c":true}],"e":[{"i":[[0,0],[-0.089,-0.987],[-0.278,-3.396],[-0.525,-7.148],[-4.945,-5.803],[-9.866,11.148],[0.725,3.596],[6.837,19.482]],"o":[[0,0],[0.121,1.333],[0.323,3.936],[1.428,19.437],[2.832,3.324],[11.55,-13.051],[-1.275,-15.904],[-5.622,-16.02]],"v":[[10.305,-57.09],[10.44,-55.64],[11.04,-48.623],[12.314,-32.116],[21.668,57.426],[44.2,51.551],[54.275,22.904],[39.872,-29.73]],"c":true}]},{"t":6}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":1,"s":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.195,-0.013],[0.819,-14.412]],"v":[[-23.513,-54.481],[-25.144,-53.423],[-32.713,-2.808],[-29.826,7.494],[-26.917,-1.136]],"c":true}],"e":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.195,-0.013],[0.819,-14.412]],"v":[[-31.013,-45.315],[-32.644,-44.256],[-40.213,6.359],[-37.326,16.661],[-34.417,8.03]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":3,"s":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.195,-0.013],[0.819,-14.412]],"v":[[-31.013,-45.315],[-32.644,-44.256],[-40.213,6.359],[-37.326,16.661],[-34.417,8.03]],"c":true}],"e":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.196,-0.013],[0.819,-14.412]],"v":[[-37.096,-52.997],[-38.727,-51.938],[-46.296,-1.323],[-43.159,7.979],[-40.5,0.348]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.404,3.747],[1.477,0.688],[1.74,-9.708],[-5.091,0.021],[-0.25,4.402]],"o":[[-1.673,-0.138],[-1.523,11.938],[-0.954,5.323],[3.196,-0.013],[0.819,-14.412]],"v":[[-37.096,-52.997],[-38.727,-51.938],[-46.296,-1.323],[-43.159,7.979],[-40.5,0.348]],"c":true}],"e":[{"i":[[-0.103,4.085],[4.059,4.688],[1.686,-13.134],[-16.7,0.449],[-0.025,15.596]],"o":[[-5.407,-0.167],[-1.941,14.188],[-2.481,19.331],[7.341,-0.197],[-0.025,-17.404]],"v":[[-31.343,-55.333],[-44.309,-60.438],[-51.186,-11.116],[-42.05,21.551],[-30.225,2.654]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.103,4.085],[4.059,4.688],[1.686,-13.134],[-16.7,0.449],[-0.025,15.596]],"o":[[-5.407,-0.167],[-1.941,14.188],[-2.481,19.331],[7.341,-0.197],[-0.025,-17.404]],"v":[[-31.343,-55.333],[-44.309,-60.438],[-51.186,-11.116],[-42.05,21.551],[-30.225,2.654]],"c":true}],"e":[{"i":[[-0.089,-0.987],[-0.278,-3.396],[-0.525,-7.148],[-9.866,11.148],[0.725,3.596]],"o":[[0.121,1.333],[0.323,3.936],[1.428,19.437],[11.55,-13.051],[-1.275,-15.904]],"v":[[5.773,-76.735],[6.373,-69.719],[7.647,-53.212],[39.533,30.455],[49.608,1.808]],"c":true}]},{"t":6}]},"nm":"B 2"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.01,0.24,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":1,"op":7,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":22,"ty":4,"nm":"B white layer 2 shadow 2","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-38.124,-198.023],[-153.77,-179.155],[-179.51,0.476],[-152.785,32.892],[-44.446,28.81],[-41.27,-85.157]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[50,-11],[0,0],[0,0]],"v":[[92,-282],[-116,-244],[-109,24],[-51,19],[110,22],[100.956,-130.738]],"c":true}]},{"t":19.1474609375}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-276.179,-132.292],[-277.37,-102.994],[-282.552,-101.351],[-288.355,-146.931],[-283.229,-149.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}],"e":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}],"e":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}],"e":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,0.935],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.446,-160.417],[1.88,-133.369],[-33.177,-133.101],[-33.105,-184.681],[4.646,-184.998]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-287.306,-16.62],[-293.677,-14.62],[-299.802,-64.783],[-294.431,-67.033],[-284.719,-47.051]],"c":true}],"e":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}],"e":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}],"e":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.158],[41.656,-68.176]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":23,"ty":4,"nm":"B white layer 2 shadow","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-38.124,-198.023],[-153.77,-179.155],[-179.51,0.476],[-152.785,32.892],[-44.446,28.81],[-41.27,-85.157]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[0,0],[0,0]],"v":[[-26.124,-205.023],[-141.77,-186.155],[-167.51,-6.524],[-140.785,25.892],[-10.446,30.81],[-18.323,-87.679]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[0,0],[-4,0.01],[-22.446,5.81],[5.009,56.785]],"o":[[0,0],[0,0],[0,0],[51.196,-0.129],[11.259,-2.914],[-4.977,-56.418]],"v":[[7.876,-190.023],[-107.77,-171.155],[-133.51,8.476],[-106.785,40.892],[16.554,39.31],[20.584,-78.085]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,31.5],[9.358,52.957]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-15.801],[-9.297,-52.616]],"v":[[37.5,-220],[-101,-170],[-88,11],[-55,37],[65.5,7],[58.347,-118.825]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-18.5,33],[14.123,54.022]],"o":[[0,0],[0,0],[0,0],[50,-11],[9.28,-16.553],[-14.032,-53.673]],"v":[[-38.5,-242],[-236,-164],[-88,11],[-55,36],[8.5,-10],[-8.199,-138.898]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.976,14.749],[13.055,55.474]],"o":[[0,0],[0,0],[0,0],[50,-11],[8.026,-10.785],[-12.971,-55.116]],"v":[[-61,-230],[-236,-164],[-109,24],[-60,28],[-17,2],[-33.126,-122.6]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,14.5],[13.551,58.865]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-7.273],[-13.463,-58.485]],"v":[[-61,-237],[-191,-176],[-109,24],[-76,30],[-11.5,5],[-33.006,-122.007]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-14,18],[17.568,58.925]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.023,-9.029],[-17.454,-58.545]],"v":[[-56,-244],[-191,-176],[-109,24],[-76,30],[7,0],[-19.42,-129.321]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-12,13],[17.065,63.067]],"o":[[0,0],[0,0],[0,0],[50,-11],[6.019,-6.521],[-16.954,-62.66]],"v":[[-39,-257],[-191,-176],[-109,24],[-76,30],[23,1],[-3.665,-133.486]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-9,17],[17.689,64.569]],"o":[[0,0],[0,0],[0,0],[50,-11],[4.515,-8.528],[-17.575,-64.152]],"v":[[-13,-271],[-191,-176],[-109,24],[-76,30],[53,-5],[23.204,-145]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,20],[23.562,61.869]],"o":[[0,0],[0,0],[0,0],[50,-11],[7.752,-9.689],[-8.438,-57.131]],"v":[[17,-282],[-191,-176],[-109,24],[-76,30],[71,-9],[50.438,-146.869]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-16,15],[24.604,34.177]],"o":[[0,0],[0,0],[0,0],[50,-11],[16,-15],[3.604,-39.823]],"v":[[46,-289],[-116,-244],[-109,24],[-51,19],[77,-7],[61.396,-150.177]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[-10.999,17.25],[28.431,29.796]],"o":[[0,0],[0,0],[0,0],[50,-11],[10.999,-17.25],[16.431,-29.204]],"v":[[65.252,-286.25],[-116,-244],[-109,24],[-51,19],[88.001,-9.75],[65.569,-132.796]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[-3.907,0.859],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[50,-11],[0,0],[0,0]],"v":[[92,-282],[-116,-244],[-109,24],[-51,19],[110,22],[100.956,-130.738]],"c":true}]},{"t":19.1474609375}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":24,"ty":4,"nm":"B white layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-276.179,-132.292],[-277.37,-102.994],[-282.552,-101.351],[-288.355,-146.931],[-283.229,-149.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.196,-15.458],[4.87,-2.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[2.979,-1.252]],"v":[[-45.179,-170.292],[-46.37,-140.994],[-51.552,-139.351],[-57.355,-184.931],[-52.229,-187.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.196,-15.458],[10.37,-3.756],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[5.729,-1.752]],"v":[[-29.679,-174.292],[-36.62,-141.244],[-48.302,-138.851],[-53.605,-186.431],[-42.979,-189.748]],"c":true}],"e":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.196,-15.458],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[1.997,14.059],[0,0],[0,0],[0,0],[12.104,-2.127]],"v":[[-14.179,-171.542],[-26.62,-140.744],[-44.802,-137.851],[-48.605,-186.931],[-32.479,-190.998]],"c":true}],"e":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-0.946,-15.083],[11.62,-1.881],[0,0],[0,0],[0,0]],"o":[[0.889,14.172],[0,0],[0,0],[0,0],[11.854,-1.752]],"v":[[-0.554,-168.667],[-16.12,-139.619],[-41.927,-136.351],[-45.105,-186.931],[-21.854,-190.998]],"c":true}],"e":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[0,-14.502],[17.62,-0.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[16.104,-1.752]],"v":[[9.196,-166.167],[-14.62,-138.119],[-39.927,-136.351],[-41.855,-185.931],[-15.354,-189.498]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[0,-14.502],[18.37,-0.631],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[15.303,-0.876]],"v":[[18.196,-164.417],[-8.37,-136.494],[-37.552,-135.101],[-38.855,-185.806],[-8.479,-188.373]],"c":true}],"e":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[0,-14.502],[19.12,-1.131],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[24.196,-162.667],[-2.12,-134.869],[-35.177,-133.851],[-35.855,-185.681],[-1.604,-187.248]],"c":true}],"e":[{"i":[[0,-14.502],[18.37,0.935],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.446,-160.417],[1.88,-133.369],[-33.177,-133.101],[-33.105,-184.681],[4.646,-184.998]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-287.306,-16.62],[-293.677,-14.62],[-299.802,-64.783],[-294.431,-67.033],[-284.719,-47.051]],"c":true}],"e":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[6.056,-1.63],[0,0],[0,0],[0,0],[-1.281,-9.949]],"o":[[0,0],[0,0],[0,0],[4.931,-1.967],[1.649,12.81]],"v":[[-33.306,-52.62],[-39.677,-50.62],[-45.802,-100.783],[-40.431,-103.033],[-30.719,-83.051]],"c":true}],"e":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[11.556,-3.13],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[8.681,-1.967],[0.969,10.301]],"v":[[-21.806,-51.87],[-37.427,-49.12],[-43.552,-99.783],[-28.431,-103.533],[-13.719,-83.551]],"c":true}],"e":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.181,-3.38],[0,0],[0,0],[0,0],[-0.953,-10.127]],"o":[[0,0],[0,0],[0,0],[14.306,-2.342],[0.969,10.301]],"v":[[-10.556,-49.87],[-36.177,-47.37],[-40.302,-98.783],[-18.181,-102.533],[2.031,-79.801]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[-5.181,-47.745],[-34.927,-46.745],[-38.427,-97.908],[-7.931,-101.158],[14.156,-75.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[2.819,-46.495],[-33.927,-44.495],[-36.427,-96.908],[0.069,-98.908],[23.656,-72.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[16.556,-0.967],[0,14.2]],"v":[[6.819,-45.12],[-33.427,-44.245],[-34.802,-95.783],[5.694,-97.283],[31.781,-71.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[10.819,-43.745],[-32.927,-43.995],[-33.177,-94.658],[11.319,-95.658],[36.406,-69.676]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-41.995],[-32.677,-41.995],[-32.677,-93.658],[16.569,-94.158],[41.656,-68.176]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":25,"ty":4,"nm":"B white layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-1.282,17.269],[-0.661,17.73],[1.838,0.593],[0,0],[0,0],[-1.643,0],[-0.912,-1.481]],"o":[[1.259,-16.963],[0.075,-2.02],[-1.701,-0.549],[0,0],[0,0],[1.257,0],[0.338,-3.231]],"v":[[-41.009,-32.537],[-38.089,-79.48],[-39.588,-83.593],[-42.507,-82.468],[-50.507,4.375],[-47.107,4],[-44.213,5.856]],"c":true}],"e":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.008,17.316],[0.339,16.48],[3.281,1.942],[0,0],[0,0],[-6.268,-1],[-1.162,-9.106]],"o":[[0.009,-21.463],[-0.098,-4.771],[-4.912,-2.907],[0,0],[0,0],[5.666,0.904],[-0.412,-10.356]],"v":[[-34.509,-42.537],[-34.339,-91.23],[-37.588,-101.593],[-47.007,-102.468],[-59.132,7.5],[-45.982,2.75],[-34.588,14.106]],"c":true}],"e":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.009,17.287],[2.01,28.256],[7.354,3.812],[0,0],[0,0],[-11.66,-5.191],[-3.162,-10.856]],"o":[[-1.064,-18.224],[-0.411,-5.77],[-10.912,-5.657],[0,0],[0,0],[11.232,5],[-1.162,-18.356]],"v":[[-16.009,-48.037],[-20.089,-101.23],[-28.588,-120.343],[-52.757,-120.968],[-55.882,3.75],[-26.232,2.5],[-10.838,21.356]],"c":true}],"e":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[3.581,24.09],[2.339,28.23],[18.566,5.173],[0,0],[0,0],[-42.815,-12.244],[-3.162,-9.856]],"o":[[-4.491,-30.213],[-0.972,-11.734],[-34.662,-9.657],[0,0],[0,0],[19.232,5.5],[-2.412,-16.356]],"v":[[28.491,-50.787],[21.161,-112.48],[-7.588,-142.843],[-60.007,-138.968],[-58.382,3.5],[13.518,-2.5],[41.412,22.606]],"c":true}],"e":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[6.259,23.537],[9.028,29.832],[35.338,-11.407],[0,0],[0,0],[-43.647,8.83],[7.838,30.644]],"o":[[-6.901,-25.951],[-3.411,-11.27],[-35.699,11.524],[0,0],[0,0],[66.732,-13.5],[-4.529,-17.709]],"v":[[98.991,-111.037],[77.161,-192.23],[3.912,-187.593],[-68.757,-153.968],[-60.882,2],[23.768,-27],[112.412,-55.894]],"c":true}],"e":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[9.241,25.213],[14.339,35.48],[31.838,-35.407],[0,0],[0,0],[-37.642,23.794],[7.838,30.644]],"o":[[-9.241,-25.213],[-15.283,-37.816],[-16.668,18.536],[0,0],[0,0],[45.482,-28.75],[-4.529,-17.709]],"v":[[33.991,-189.537],[9.161,-252.48],[-36.838,-201.593],[-76.007,-167.218],[-63.882,2],[24.768,-48],[62.412,-113.394]],"c":true}],"e":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[9.241,25.213],[15.339,35.73],[24.588,-31.657],[0,0],[0,0],[-33.385,29.471],[8.088,31.144]],"o":[[-9.241,-25.213],[-19.116,-44.526],[-15.291,19.687],[0,0],[0,0],[38.232,-33.75],[-4.594,-17.692]],"v":[[1.491,-181.287],[-33.839,-268.23],[-51.588,-209.843],[-83.257,-178.968],[-66.382,1.5],[2.768,-41.25],[25.662,-113.144]],"c":true}],"e":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[9.241,25.213],[14.589,37.98],[24.588,-31.657],[0,0],[0,0],[-36.476,25.546],[8.088,31.144]],"o":[[-9.241,-25.213],[-17.376,-45.234],[-15.291,19.687],[0,0],[0,0],[34.982,-24.5],[-4.594,-17.692]],"v":[[-0.759,-180.537],[-36.839,-272.73],[-56.338,-216.843],[-89.257,-186.468],[-69.382,1],[6.518,-38],[24.662,-104.894]],"c":true}],"e":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[8.009,25.037],[13.247,38.034],[35.338,-37.657],[0,0],[0,0],[-39.772,20.031],[8.088,31.144]],"o":[[-11.991,-32.463],[-17.16,-49.27],[-21.388,22.792],[0,0],[0,0],[36.732,-18.5],[-4.594,-17.692]],"v":[[11.241,-169.037],[-25.59,-271.98],[-60.088,-220.343],[-93.257,-193.718],[-71.382,1],[15.768,-34.75],[32.662,-102.144]],"c":true}],"e":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[8.259,24.037],[10.641,35.776],[35.838,-35.157],[0,0],[0,0],[-42.018,14.75],[10.338,43.894]],"o":[[-9.241,-31.213],[-13.91,-46.77],[-22.312,21.888],[0,0],[0,0],[40.972,-14.383],[-7.971,-33.842]],"v":[[23.991,-176.037],[-5.09,-269.48],[-49.338,-232.593],[-95.757,-200.718],[-72.382,0.25],[27.268,-29],[47.662,-96.394]],"c":true}],"e":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.009,23.287],[7.59,33.73],[50.58,-35.169],[0,0],[0,0],[0,0],[11.714,49.114]],"o":[[-7.241,-28.463],[-10.225,-45.445],[-25.662,17.843],[0,0],[0,0],[43.732,-7.5],[-10.162,-42.606]],"v":[[42.741,-173.287],[20.411,-260.73],[-42.588,-234.593],[-97.257,-206.968],[-73.882,0.25],[35.018,-20.5],[65.662,-88.144]],"c":true}],"e":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[3.259,21.287],[6.044,31.942],[57.588,-23.657],[0,0],[0,0],[0,0],[10.088,66.644]],"o":[[-1.741,-23.963],[-8.661,-45.77],[-33.448,13.74],[0,0],[0,0],[43.732,-7.5],[-8.74,-57.737]],"v":[[54.991,-175.537],[44.161,-246.98],[-37.838,-233.593],[-96.757,-212.718],[-75.382,0],[38.518,-14.75],[79.662,-80.894]],"c":true}],"e":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[3.259,21.287],[4.985,35.86],[31.838,-13.407],[0,0],[0,0],[0,0],[7.588,68.394]],"o":[[-1.491,-26.213],[-5.911,-42.52],[-31.691,13.345],[0,0],[0,0],[38.732,-3.75],[-6.443,-58.072]],"v":[[65.241,-152.287],[61.661,-221.73],[10.912,-247.343],[-94.007,-216.968],[-77.382,-0.75],[40.268,-9.5],[88.162,-79.394]],"c":true}],"e":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[2.759,8.787],[5.839,35.73],[33.162,-9.093],[0,0],[0,0],[0,0],[2.478,49.663]],"o":[[-2.741,-7.463],[-6.377,-39.022],[-33.162,9.093],[0,0],[0,0],[38.732,-3.75],[-2.912,-58.356]],"v":[[66.241,-138.287],[71.911,-205.73],[16.162,-241.093],[-91.507,-220.468],[-77.382,-0.75],[41.768,-6.5],[92.912,-66.894]],"c":true}],"e":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[27.259,18.287],[2.089,21.98],[37.838,-4.407],[0,0],[0,0],[0,0],[0.838,46.394]],"o":[[11.509,-17.213],[-3.742,-39.362],[0,0],[0,0],[0,0],[36.982,0],[-0.523,-28.962]],"v":[[63.241,-131.037],[77.161,-188.98],[16.162,-235.843],[-89.507,-222.468],[-78.882,-0.5],[31.768,-3.75],[95.162,-60.894]],"c":true}],"e":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[25.509,15.287],[1.964,22.98],[38.338,-2.657],[0,0],[0,0],[0,0],[-0.037,44.769]],"o":[[11.884,-14.088],[-3.365,-39.367],[0,0],[0,0],[0,0],[36.982,0],[0.026,-31.246]],"v":[[61.616,-125.787],[79.286,-179.98],[15.537,-232.218],[-86.382,-224.093],[-79.007,-0.375],[30.268,-2.75],[94.037,-62.519]],"c":true}],"e":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[23.759,12.287],[0.374,21.444],[38.838,-0.907],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[12.259,-10.963],[-0.705,-39.533],[0,0],[0,0],[0,0],[36.982,0],[0.053,-28.967]],"v":[[59.491,-123.537],[79.911,-170.48],[17.412,-229.593],[-83.257,-225.718],[-79.132,-0.25],[28.768,-1.75],[93.412,-61.644]],"c":true}],"e":[{"i":[[23.009,8.287],[0.374,21.444],[37.94,-0.602],[0,0],[0,0],[0,0],[-0.076,41.089]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[39.468,0.25],[0.053,-28.967]],"v":[[55.991,-119.287],[79.661,-166.48],[11.162,-226.593],[-79.507,-226.218],[-79.132,-0.25],[22.518,-0.25],[91.162,-62.644]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":5,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":26,"ty":4,"nm":"B light blue layer 3 shadow 2","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[4.596,42.859],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-5.931,-55.302],[0,0]],"v":[[-58.13,-221.16],[-111.991,-226.753],[-103.289,41.823],[-46.069,-81.698],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[116,-7],[70,-285]],"c":true}]},{"t":18}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-268.103,-143.239],[-271.189,-115.936],[-276.731,-115.148],[-282.154,-159.988],[-277.112,-161.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}],"e":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}],"e":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.363,-160.417],[4.963,-133.935],[-32.927,-133.268],[-32.927,-184.014],[3.297,-184.848]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-272.931,-26.995],[-280.427,-25.995],[-286.427,-75.158],[-279.181,-76.658],[-269.094,-56.926]],"c":true}],"e":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}],"e":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-42.745],[-32.677,-41.995],[-32.677,-93.658],[16.069,-94.158],[41.406,-67.926]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":27,"ty":4,"nm":"B light blue layer 3 shadow","parent":34,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":16,"s":[5],"e":[40]},{"t":22}]},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[4.596,42.859],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-5.931,-55.302],[0,0]],"v":[[-58.13,-221.16],[-111.991,-226.753],[-103.289,41.823],[-46.069,-81.698],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[9.482,45.79],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[-11.278,-54.464],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[-0.569,37.802],[-54.696,-253.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[42.431,32.302],[11.804,-249.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,0],[0,0],[-3.12,0.516],[-3.803,42.936],[0,0]],"o":[[0,0],[0,0],[3.12,-0.516],[3.803,-42.936],[0,0]],"v":[[-9.13,-263.16],[-128.991,-241.753],[-103.289,41.823],[70.931,-10.698],[8.304,-239.118]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[59,30],[-33,-263]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[0,0],[0,0],[-3,1],[3,43],[0,0]],"o":[[0,0],[0,0],[3,-1],[-3,-43],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[41,8],[-35,-264]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[0,0],[0,0],[-3,1],[-1,39],[0,0]],"o":[[0,0],[0,0],[3,-1],[1.444,-56.302],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[70,-17],[3,-268]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-9],[28,-280]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[96,-19],[50,-287]],"c":true}],"e":[{"i":[[0,0],[0,0],[-3,1],[9.112,40.348],[0,0]],"o":[[0,0],[0,0],[3,-1],[-12.406,-54.937],[0,0]],"v":[[-47,-270],[-162,-230],[-92,46],[116,-7],[70,-285]],"c":true}]},{"t":18}]},"o":{"k":100},"x":{"k":0},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":7,"op":15,"st":0,"bm":10,"sr":1},{"ddd":0,"ind":28,"ty":4,"nm":"B light blue layer 4","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-268.103,-143.239],[-271.189,-115.936],[-276.731,-115.148],[-282.154,-159.988],[-277.112,-161.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[-2.154,-14.341],[5.939,-1.064],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[3.862,-1.474]],"v":[[-36.103,-162.739],[-39.189,-135.436],[-44.731,-134.648],[-50.154,-179.488],[-45.112,-180.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[7.862,-1.724]],"v":[[-22.103,-167.239],[-29.189,-138.186],[-43.481,-135.648],[-49.154,-181.988],[-37.862,-184.776]],"c":true}],"e":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[-2.154,-14.341],[7.939,-1.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[10.862,0.026]],"v":[[-9.353,-166.739],[-20.189,-138.686],[-42.231,-135.648],[-46.654,-183.988],[-26.862,-187.276]],"c":true}],"e":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[-1.634,-14.432],[15.643,-0.316],[0,0],[0,0],[0,0]],"o":[[1.499,13.233],[0,0],[0,0],[0,0],[12.13,-2.72]],"v":[[1.501,-165.483],[-19.143,-137.184],[-39.891,-135.152],[-43.647,-185.494],[-18.285,-187.276]],"c":true}],"e":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[-2.154,-14.341],[17.439,-2.814],[0,0],[0,0],[0,0]],"o":[[2.109,14.042],[0,0],[0,0],[0,0],[13.612,-1.724]],"v":[[10.147,-167.739],[-8.939,-136.936],[-38.481,-134.898],[-40.154,-185.488],[-12.862,-186.776]],"c":true}],"e":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[-1.534,-14.395],[14.273,-2.231],[0,0],[0,0],[0,0]],"o":[[1.502,14.095],[0,0],[0,0],[0,0],[14.778,1.383]],"v":[[17.998,-164.132],[-2.523,-136.269],[-36.047,-134.41],[-37.912,-185.525],[-5.028,-187.133]],"c":true}],"e":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[-0.767,-14.448],[16.041,-0.938],[0,0],[0,0],[0,0]],"o":[[0.751,14.147],[0,0],[0,0],[0,0],[14.678,-0.575]],"v":[[23.139,-163.775],[0.762,-135.102],[-34.862,-134.172],[-35.92,-185.061],[-3.241,-186.241]],"c":true}],"e":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[0,-14.502],[14.502,0],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[27.029,-160.917],[4.297,-134.435],[-33.677,-133.685],[-33.677,-184.598],[2.797,-185.348]],"c":true}],"e":[{"i":[[0,-14.502],[16.037,-0.065],[0,0],[0,0],[0,0]],"o":[[0,14.2],[0,0],[0,0],[0,0],[14.502,0]],"v":[[30.363,-160.417],[4.963,-133.935],[-32.927,-133.268],[-32.927,-184.014],[3.297,-184.848]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ind":2,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-272.931,-26.995],[-280.427,-25.995],[-286.427,-75.158],[-279.181,-76.658],[-269.094,-56.926]],"c":true}],"e":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[7.181,0.245],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[5.681,-0.592],[2.589,13.962]],"v":[[-25.931,-49.995],[-33.427,-48.995],[-39.427,-98.158],[-32.181,-99.658],[-22.094,-79.926]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[7.681,-0.842],[2.589,13.962]],"v":[[-17.681,-50.245],[-33.677,-48.495],[-39.427,-98.158],[-22.431,-100.908],[-7.094,-82.426]],"c":true}],"e":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[13.431,-1.505],[0,0],[0,0],[0,0],[-2.656,-14.324]],"o":[[0,0],[0,0],[0,0],[11.931,0.158],[2.589,13.962]],"v":[[-9.181,-49.745],[-33.677,-47.745],[-37.927,-97.908],[-12.681,-100.908],[5.906,-78.676]],"c":true}],"e":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[14.118,-0.752],[0,0],[0,0],[0,0],[-1.406,-16.074]],"o":[[0,0],[0,0],[0,0],[11.868,-1.421],[1.237,14.146]],"v":[[-2.681,-47.745],[-34.177,-45.745],[-36.927,-96.908],[-7.181,-99.908],[16.656,-76.926]],"c":true}],"e":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[12.181,0.495],[0,0],[0,0],[0,0],[-0.906,-12.324]],"o":[[0,0],[0,0],[0,0],[14.804,0],[1.041,14.162]],"v":[[3.069,-47.245],[-32.927,-45.495],[-35.677,-96.408],[1.819,-98.408],[24.906,-73.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.264,-12.571]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.261,12.426]],"v":[[8.652,-45.745],[-33.344,-44.412],[-34.844,-95.658],[6.902,-97.325],[31.239,-71.926]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[-0.885,-14.241]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0.863,14.121]],"v":[[10.735,-44.495],[-33.261,-43.579],[-33.761,-94.908],[11.235,-95.742],[35.822,-70.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[12.681,0.408],[0,14.2]],"v":[[14.319,-43.995],[-32.677,-43.245],[-33.177,-93.658],[16.569,-94.658],[39.156,-68.176]],"c":true}],"e":[{"i":[[14.804,0],[0,0],[0,0],[0,0],[0,-14.2]],"o":[[0,0],[0,0],[0,0],[14.804,0],[0,14.2]],"v":[[14.819,-42.745],[-32.677,-41.995],[-32.677,-93.658],[16.069,-94.158],[41.406,-67.926]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":15,"op":23,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":29,"ty":4,"nm":"B light blue layer 3","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.201,21.411],[-0.286,15.23],[2.474,0.203],[0,0],[0,0],[-1.893,-0.375],[-0.662,-1.856]],"o":[[0.134,-14.338],[0.036,-1.896],[-1.912,-0.157],[0,0],[0,0],[0.644,0.128],[1.338,-20.856]],"v":[[-46.509,-50.162],[-44.214,-98.23],[-45.963,-101.593],[-49.132,-100.593],[-55.007,4.75],[-50.857,4.25],[-48.588,6.856]],"c":true}],"e":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0.279,24.912],[0.464,22.605],[2.088,1.343],[0,0],[0,0],[-4.143,-2],[-0.787,-3.981]],"o":[[-0.241,-21.463],[-0.098,-4.771],[-4.242,-2.728],[0,0],[0,0],[3.51,1.694],[-0.037,-19.356]],"v":[[-40.884,-52.662],[-41.839,-108.48],[-44.463,-118.593],[-53.507,-120.718],[-54.757,3.5],[-45.357,4.875],[-39.963,12.856]],"c":true}],"e":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[2.509,24.787],[1.952,19.983],[11.463,8.593],[0,0],[0,0],[-8.268,-3.75],[-3.537,-7.856]],"o":[[-1.87,-18.476],[-0.161,-1.645],[-7.865,-5.896],[0,0],[0,0],[10.005,4.538],[-1.787,-20.356]],"v":[[-22.759,-58.037],[-27.839,-117.855],[-38.713,-134.843],[-60.257,-138.093],[-58.257,2.5],[-32.482,4.25],[-15.963,19.356]],"c":true}],"e":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[2.509,23.537],[1.952,19.983],[37.213,10.843],[0,0],[0,0],[-37.012,-3.318],[3.87,36.773]],"o":[[-1.969,-18.466],[-0.161,-1.645],[-39.595,-11.537],[0,0],[0,0],[52.982,4.75],[-2.037,-19.356]],"v":[[46.741,-67.787],[41.411,-115.355],[-2.713,-150.593],[-68.757,-153.593],[-61.507,2.25],[4.268,0.25],[56.037,7.356]],"c":true}],"e":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[5.869,20.677],[5.339,19.355],[49.963,-14.657],[0,0],[0,0],[-48.018,8.5],[14.463,52.894]],"o":[[-5.241,-18.463],[-6.854,-24.846],[-39.574,11.609],[0,0],[0,0],[56.175,-9.944],[-11.083,-40.532]],"v":[[79.741,-141.537],[64.661,-196.855],[-12.963,-182.843],[-76.257,-168.093],[-64.507,2],[54.518,-20],[98.287,-79.394]],"c":true}],"e":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":11,"s":[{"i":[[7.415,20.175],[10.589,29.855],[50.213,-22.407],[0,0],[0,0],[-48.907,15.377],[14.389,46.029]],"o":[[-8.991,-24.463],[-8.616,-24.291],[-37.662,16.806],[0,0],[0,0],[43.732,-13.75],[-12.537,-40.106]],"v":[[75.491,-152.537],[45.911,-232.355],[-25.463,-197.593],[-83.007,-177.843],[-66.757,2],[45.518,-26.75],[98.787,-83.894]],"c":true}],"e":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":12,"s":[{"i":[[6.732,20.413],[9.339,28.855],[50.213,-22.407],[0,0],[0,0],[-49.459,13.494],[14.043,47.445]],"o":[[-7.491,-22.713],[-7.937,-24.521],[-37.662,16.806],[0,0],[0,0],[43.982,-12],[-12.537,-42.356]],"v":[[73.491,-153.537],[43.411,-239.855],[-29.463,-206.343],[-89.007,-186.343],[-68.507,1.5],[45.518,-26.75],[96.287,-84.644]],"c":true}],"e":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[5.741,20.713],[9.339,28.855],[60.463,-27.657],[0,0],[0,0],[-49.459,13.494],[12.963,47.644]],"o":[[-5.741,-20.713],[-7.937,-24.521],[-37.505,17.155],[0,0],[0,0],[43.982,-12],[-11.586,-42.584]],"v":[[73.741,-153.787],[45.411,-241.855],[-29.713,-213.843],[-93.257,-193.343],[-71.257,0.5],[49.768,-26.5],[95.287,-81.894]],"c":true}],"e":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":14,"s":[{"i":[[5.741,20.713],[7.839,29.855],[63.713,-28.907],[0,0],[0,0],[-50.018,11.25],[12.963,53.394]],"o":[[-5.741,-20.713],[-6.546,-24.929],[-37.557,17.04],[0,0],[0,0],[46.058,-10.359],[-10.749,-44.276]],"v":[[75.741,-154.037],[52.411,-240.355],[-22.963,-222.593],[-96.007,-200.343],[-72.507,1.25],[48.768,-23.5],[95.037,-81.894]],"c":true}],"e":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[4.259,17.037],[7.839,29.855],[64.463,-23.407],[0,0],[0,0],[-49.518,7.25],[10.523,50.543]],"o":[[-5.991,-25.463],[-6.546,-24.929],[-38.765,14.076],[0,0],[0,0],[48.964,-7.169],[-9.287,-44.606]],"v":[[76.491,-154.787],[58.161,-239.105],[-23.213,-225.593],[-97.507,-206.343],[-74.007,1.25],[52.268,-20],[94.787,-82.394]],"c":true}],"e":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16,"s":[{"i":[[4.009,18.287],[9.089,30.105],[63.963,-18.157],[0,0],[0,0],[-52.207,5.395],[4.963,38.144]],"o":[[-1.741,-23.713],[-7.236,-23.967],[-39.674,11.262],[0,0],[0,0],[67.732,-7],[-5.852,-44.98]],"v":[[74.491,-158.287],[64.411,-233.605],[-18.713,-229.093],[-96.757,-211.843],[-75.507,0.25],[45.268,-14.75],[94.287,-79.394]],"c":true}],"e":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":16.963,"s":[{"i":[[5.509,15.037],[12.589,49.605],[49.213,-8.907],[0,0],[0,0],[-52.29,4.52],[5.084,46.282]],"o":[[-2.241,-23.713],[-7.654,-30.16],[-40.583,7.345],[0,0],[0,0],[60.732,-5.25],[-5.037,-45.856]],"v":[[73.241,-141.287],[69.161,-222.855],[-16.963,-229.093],[-94.757,-216.843],[-76.507,-0.5],[42.768,-11.75],[94.037,-80.894]],"c":true}],"e":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":17.93,"s":[{"i":[[15.759,20.037],[2.089,16.855],[46.963,-6.157],[0,0],[0,0],[-32.059,1.901],[3.213,53.144]],"o":[[4.509,-21.713],[-5.161,-61.645],[-32.938,4.318],[0,0],[0,0],[63.232,-3.75],[-3.787,-41.856]],"v":[[68.491,-134.287],[76.911,-187.605],[-8.463,-229.843],[-91.507,-219.843],[-77.257,-0.75],[22.518,-7.25],[94.037,-72.894]],"c":true}],"e":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18.756,"s":[{"i":[[20.259,14.037],[1.766,21.378],[30.713,-3.907],[0,0],[0,0],[-39.232,1.5],[3.134,56.753]],"o":[[11.509,-19.963],[-4.411,-53.395],[-38.914,4.95],[0,0],[0,0],[39.232,-1.5],[-1.787,-32.356]],"v":[[63.741,-128.537],[77.411,-184.105],[3.537,-230.593],[-88.507,-223.093],[-78.007,-1],[25.018,-5.5],[93.537,-70.894]],"c":true}],"e":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.63,"s":[{"i":[[24.259,15.287],[1.029,21.401],[37.213,-2.157],[0,0],[0,0],[0,0],[2.205,48.866]],"o":[[12.683,-14.513],[-3.911,-45.645],[-21.287,1.093],[0,0],[0,0],[45.482,1],[-1.09,-28.807]],"v":[[61.241,-124.787],[78.661,-178.355],[4.787,-229.343],[-86.007,-223.593],[-78.007,-1],[18.768,-3.5],[92.287,-66.644]],"c":true}],"e":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20.505,"s":[{"i":[[22.009,10.287],[0,21.451],[39.713,-1.157],[0,0],[0,0],[0,0],[-0.303,41.088]],"o":[[14.509,-10.713],[0,-38.672],[0,0],[0,0],[0,0],[45.482,1],[0.213,-28.856]],"v":[[58.491,-122.287],[79.161,-171.855],[11.037,-228.593],[-83.507,-224.093],[-78.007,-1],[21.268,-2.5],[92.037,-63.394]],"c":true}],"e":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21.376,"s":[{"i":[[21.149,8.762],[0.374,21.444],[35.338,-1.657],[0,0],[0,0],[0,0],[-0.227,41.088]],"o":[[15.106,-9.064],[-0.705,-39.533],[0,0],[0,0],[0,0],[43.478,0.75],[0.16,-28.893]],"v":[[56.741,-121.162],[79.411,-167.48],[13.912,-227.343],[-81.507,-224.968],[-78.382,-0.75],[19.518,-1.25],[91.287,-62.019]],"c":true}],"e":[{"i":[[21.149,8.762],[0.749,21.438],[32.213,-0.907],[0,0],[0,0],[0,0],[-0.152,41.088]],"o":[[15.106,-9.064],[-1.411,-40.395],[0,0],[0,0],[0,0],[41.473,0.5],[0.106,-28.93]],"v":[[56.241,-119.787],[79.411,-168.105],[13.287,-226.593],[-79.507,-225.843],[-78.757,-0.5],[21.518,-0.5],[90.787,-62.894]],"c":true}]},{"t":22.2529296875}]},"nm":"B"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":15,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":30,"ty":4,"nm":"B light blue layer 2","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-0.899,27.404],[-1.161,21.73],[-2.043,1.082],[0,0],[0,0],[1.78,-1.142],[1.963,-3.606]],"o":[[0.634,-19.338],[0.161,-3.017],[1.713,-0.907],[0,0],[0,0],[-2.143,1.375],[-0.037,-20.106]],"v":[[-64.884,-51.412],[-61.589,-110.48],[-56.963,-116.843],[-53.507,-117.468],[-55.257,2.75],[-61.857,5.625],[-66.463,11.356]],"c":true}},"nm":"B"},{"ty":"mm","mm":1,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":7,"op":8,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":31,"ty":4,"nm":"B light blue layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[2.067,0.035],[0.272,0.321],[0.13,-0.779],[-0.356,-1.134],[-1.495,0.021],[0.012,0.775],[0.067,1.41]],"o":[[0,0],[-0.681,-0.011],[-0.197,0.927],[-0.219,1.314],[0.201,0.642],[2.094,-0.03],[0.082,-1.953],[-0.078,-1.64]],"v":[[-48.938,-1.125],[-52.016,0.387],[-54.014,-0.086],[-54.792,2.812],[-54.769,6.713],[-51.876,8.407],[-48.457,5.952],[-48.648,1.19]],"c":true}],"e":[{"i":[[0,0],[8.009,0.121],[1.054,1.117],[0.503,-2.712],[-1.38,-3.952],[-5.796,0.074],[0.046,2.698],[0.26,4.913]],"o":[[0,0],[-2.637,-0.04],[-0.765,3.23],[-0.848,4.577],[0.781,2.235],[8.117,-0.104],[0.318,-6.802],[-0.303,-5.714]],"v":[[-41.806,-11.476],[-53.736,-6.21],[-62.84,-11.105],[-65.858,1.238],[-65.495,16.577],[-54.51,22.479],[-39.943,14.677],[-40.685,-3.661]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[8.009,0.121],[1.054,1.117],[0.503,-2.712],[-1.38,-3.952],[-5.796,0.074],[0.046,2.698],[0.26,4.913]],"o":[[0,0],[-2.637,-0.04],[-0.765,3.23],[-0.848,4.577],[0.781,2.235],[8.117,-0.104],[0.318,-6.802],[-0.303,-5.714]],"v":[[-41.806,-11.476],[-53.736,-6.21],[-62.84,-11.105],[-65.858,1.238],[-65.495,16.577],[-54.51,22.479],[-39.943,14.677],[-40.685,-3.661]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[4.357,-2.3],[0.602,-17.382],[-1.273,-6.802],[-19.282,0.006],[0.47,7.998],[1.175,10.637]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-0.349,10.097],[0.939,5.019],[22.347,-0.007],[-0.749,-8.21],[-1.405,-12.724]],"v":[[-32.13,-94.796],[-52.413,-95.468],[-69.857,-95.45],[-70.102,-37.118],[-69.977,24.12],[-51.218,42.744],[-15.72,20.252],[-22.595,-20.776]],"c":true}]},{"t":8}]},"nm":"B"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.15,0.8,0.55,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":6,"op":9,"st":2,"bm":0,"sr":1},{"ddd":0,"ind":32,"ty":4,"nm":"B white layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[2.067,0.035],[0.272,0.321],[0.13,-0.779],[-0.356,-1.134],[-1.495,0.021],[0.012,0.775],[0.067,1.41]],"o":[[0,0],[-0.681,-0.011],[-0.197,0.927],[-0.219,1.314],[0.201,0.642],[2.094,-0.03],[0.082,-1.953],[-0.078,-1.64]],"v":[[-45.188,-1.125],[-48.266,0.387],[-50.264,-0.086],[-51.042,2.812],[-51.019,6.713],[-48.126,8.407],[-44.707,5.952],[-44.898,1.19]],"c":true}],"e":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-36.501,-11.351],[-47.446,-6.085],[-55.798,-10.98],[-58.567,1.363],[-58.234,15.952],[-47.697,21.854],[-34.792,13.302],[-35.472,-3.536]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-36.501,-11.351],[-47.446,-6.085],[-55.798,-10.98],[-58.567,1.363],[-58.234,15.952],[-47.697,21.854],[-34.792,13.302],[-35.472,-3.536]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.102,-14.882],[-1.273,-6.802],[-19.282,0.006],[0.47,7.998],[1.175,10.637]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-0.746,10.075],[0.939,5.019],[22.347,-0.007],[-0.749,-8.211],[-1.405,-12.724]],"v":[[-20.38,-97.546],[-49.163,-91.968],[-61.857,-100.7],[-65.602,-41.118],[-67.977,23.12],[-40.968,39.244],[-11.22,17.752],[-14.595,-21.526]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.102,-14.882],[-1.273,-6.802],[-19.282,0.006],[0.47,7.998],[1.175,10.637]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-0.746,10.075],[0.939,5.019],[22.347,-0.007],[-0.749,-8.211],[-1.405,-12.724]],"v":[[-20.38,-97.546],[-49.163,-91.968],[-61.857,-100.7],[-65.602,-41.118],[-67.977,23.12],[-40.968,39.244],[-11.22,17.752],[-14.595,-21.526]],"c":true}],"e":[{"i":[[0,0],[5.836,-0.538],[0.9,1.062],[-1.035,-10.477],[-0.481,-2.985],[-4.731,0.661],[-0.012,3.839],[1.64,5.168]],"o":[[0,0],[-2.242,0.207],[0.323,6.451],[0.436,4.412],[0.355,2.203],[8.337,-1.165],[-0.012,-6.693],[-1.375,-4.332]],"v":[[33.321,-6.126],[25.664,-9.212],[19,-11.513],[22.285,15.477],[25.087,31.97],[31.697,39.589],[41.03,25.38],[38.496,8.259]],"c":true}]},{"t":8}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.007,0.279],[0.272,0.321],[0.079,-0.813],[-1.102,-0.004],[0.001,1.067]],"o":[[-0.362,-0.011],[-0.13,0.97],[-0.13,1.326],[0.541,0.002],[-0.002,-1.19]],"v":[[-254.943,4.83],[-255.945,4.464],[-256.48,7.854],[-255.801,10.105],[-255.008,8.796]],"c":true}],"e":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-49.268,-10.266],[-52.833,-11.541],[-54.733,0.268],[-52.319,8.11],[-49.502,3.548]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-49.268,-10.266],[-52.833,-11.541],[-54.733,0.268],[-52.319,8.11],[-49.502,3.548]],"c":true}],"e":[{"i":[[-0.103,2.475],[4.052,2.841],[0.919,-10.247],[-10.422,0.015],[0.022,12.118]],"o":[[-5.362,-2.495],[-1.938,8.597],[-0.804,8.962],[8.067,-0.012],[-0.019,-10.546]],"v":[[-44.638,-94.255],[-60.829,-101],[-66.196,3.288],[-56.078,21.235],[-40.272,8.382]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[-0.103,2.475],[4.052,2.841],[0.919,-10.247],[-10.422,0.015],[0.022,12.118]],"o":[[-5.362,-2.495],[-1.938,8.597],[-0.804,8.962],[8.067,-0.012],[-0.019,-10.546]],"v":[[-44.638,-94.255],[-60.829,-101],[-66.196,3.288],[-56.078,21.235],[-40.272,8.382]],"c":true}],"e":[{"i":[[-0.061,2.109],[3.595,-2.75],[0.696,-6.135],[-9.66,-0.026],[0.013,8.051]],"o":[[-3.175,-0.086],[-1.14,7.324],[-1.137,10.012],[4.745,0.013],[-0.015,-8.985]],"v":[[-56.056,-36.486],[-75.595,-26.5],[-76.296,12.591],[-66.594,33.585],[-52.9,17.2]],"c":true}]},{"t":8}]},"nm":"B 2"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0.32,0.5,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":5,"op":9,"st":1,"bm":0,"sr":1},{"ddd":0,"ind":33,"ty":4,"nm":"B orange layer 1","parent":34,"ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[250,400,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0,0],[2.067,0.035],[0.272,0.321],[0.13,-0.779],[-0.356,-1.134],[-1.495,0.021],[0.012,0.775],[0.067,1.41]],"o":[[0,0],[-0.681,-0.011],[-0.197,0.927],[-0.219,1.314],[0.201,0.642],[2.094,-0.03],[0.082,-1.953],[-0.078,-1.64]],"v":[[-40.938,-1],[-44.016,0.512],[-46.014,0.039],[-46.792,2.937],[-46.769,6.838],[-43.876,9.032],[-40.457,6.077],[-40.648,1.315]],"c":true}],"e":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-32.501,-11.351],[-43.446,-6.085],[-50.548,-7.73],[-53.317,2.363],[-53.734,15.952],[-42.697,22.604],[-30.292,13.552],[-31.472,-3.286]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,0],[7.348,0.121],[0.967,1.117],[0.461,-2.712],[-1.266,-3.952],[-5.317,0.074],[0.042,2.698],[0.239,4.913]],"o":[[0,0],[-2.42,-0.04],[-0.702,3.23],[-0.778,4.577],[0.716,2.235],[7.447,-0.104],[0.292,-6.802],[-0.278,-5.714]],"v":[[-32.501,-11.351],[-43.446,-6.085],[-50.548,-7.73],[-53.317,2.363],[-53.734,15.952],[-42.697,22.604],[-30.292,13.552],[-31.472,-3.286]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.602,-8.382],[-1.273,-6.802],[-16.121,0.205],[0.47,7.998],[2.014,10.511]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-1.896,9.923],[0.939,5.019],[22.345,-0.285],[-0.749,-8.211],[-1.98,-10.335]],"v":[[-16.38,-29.046],[-39.663,-18.718],[-54.607,-25.2],[-57.602,-5.368],[-59.727,23.12],[-35.218,37.244],[-9.72,15.252],[-13.845,-14.276]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[1.602,-8.382],[-1.273,-6.802],[-16.121,0.205],[0.47,7.998],[2.014,10.511]],"o":[[0,0],[-5.965,-0.086],[-1.14,7.324],[-1.896,9.923],[0.939,5.019],[22.345,-0.285],[-0.749,-8.211],[-1.98,-10.335]],"v":[[-16.38,-29.046],[-39.663,-18.718],[-54.607,-25.2],[-57.602,-5.368],[-59.727,23.12],[-35.218,37.244],[-9.72,15.252],[-13.845,-14.276]],"c":true}],"e":[{"i":[[0,0],[18.114,0.262],[2.384,2.42],[0.352,-20.882],[-1.273,-6.802],[-12.532,1.506],[-0.03,8.748],[4.345,11.776]],"o":[[0,0],[-5.965,-0.086],[0.857,14.7],[-0.17,10.101],[0.939,5.019],[22.085,-2.655],[-0.03,-15.252],[-3.642,-9.873]],"v":[[7.12,-52.546],[-13.163,-60.718],[-24.857,-45.45],[-24.102,2.382],[-21.977,37.12],[-4.468,50.494],[29.53,19.252],[22.155,-15.776]],"c":true}]},{"t":7}]},"nm":"B"},{"ind":1,"ty":"sh","ks":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[-0.007,0.279],[0.272,0.321],[0.079,-0.813],[-1.102,-0.004],[0.001,1.067]],"o":[[-0.362,-0.011],[-0.13,0.97],[-0.13,1.326],[0.541,0.002],[-0.002,-1.19]],"v":[[-254.943,4.83],[-255.945,4.464],[-256.48,7.854],[-255.801,10.105],[-255.008,8.796]],"c":true}],"e":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-44.518,-9.766],[-48.083,-11.041],[-49.983,0.768],[-47.319,8.11],[-44.752,2.798]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[-0.025,0.973],[0.967,1.117],[0.283,-2.831],[-3.919,-0.012],[0.005,3.715]],"o":[[-1.288,-0.04],[-0.462,3.38],[-0.461,4.62],[1.925,0.006],[-0.006,-4.146]],"v":[[-44.518,-9.766],[-48.083,-11.041],[-49.983,0.768],[-47.319,8.11],[-44.752,2.798]],"c":true}],"e":[{"i":[[-0.103,2.475],[4.052,2.841],[1.184,-7.201],[-11.422,1.515],[0.022,9.45]],"o":[[-5.398,-0.101],[-1.938,8.597],[-1.932,11.751],[7.997,-1.061],[-0.025,-10.546]],"v":[[-35.638,-26.505],[-50.579,-29.75],[-56.696,0.288],[-45.828,20.985],[-35.272,6.382]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[-0.103,2.475],[4.052,2.841],[1.184,-7.201],[-11.422,1.515],[0.022,9.45]],"o":[[-5.398,-0.101],[-1.938,8.597],[-1.932,11.751],[7.997,-1.061],[-0.025,-10.546]],"v":[[-35.638,-26.505],[-50.579,-29.75],[-56.696,0.288],[-45.828,20.985],[-35.272,6.382]],"c":true}],"e":[{"i":[[-0.061,2.109],[3.595,-2.75],[0.696,-6.135],[-9.66,-0.026],[0.013,8.051]],"o":[[-3.175,-0.086],[-1.14,7.324],[-1.137,10.012],[4.745,0.013],[-0.015,-8.985]],"v":[[-15.306,-36.486],[-34.095,-25],[-34.796,14.091],[-25.094,35.085],[-12.4,18.95]],"c":true}]},{"t":7}]},"nm":"B 2"},{"ty":"mm","mm":3,"nm":"Merge Paths 1"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.86,0.86,0.86,1]},"o":{"k":100},"nm":"Fill 1"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"Transform"}],"nm":"B"}],"ip":4,"op":8,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":34,"ty":1,"nm":"ResizerTemp","parent":35,"ks":{"o":{"k":0},"r":{"k":0},"p":{"k":[74,102,0]},"a":{"k":[250,300,0]},"s":{"k":[30,30,100]}},"ao":0,"sw":500,"sh":600,"sc":"#ffffff","ip":0,"op":37,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":35,"ty":1,"nm":"White Solid 8","ks":{"o":{"k":0},"r":{"k":0},"p":{"k":[40,50,0]},"a":{"k":[70,100,0]},"s":{"k":[57.143,50,100]}},"ao":0,"sw":140,"sh":200,"sc":"#ffffff","ip":0,"op":37,"st":0,"bm":0,"sr":1}],"v":"4.4.26","ddd":0,"ip":0,"op":37,"fr":25,"w":80,"h":100} diff --git a/sdk/python/examples/extensions/lottie/example_1/main.py b/sdk/python/examples/extensions/lottie/example_1/main.py new file mode 100644 index 0000000000..cba7564e9b --- /dev/null +++ b/sdk/python/examples/extensions/lottie/example_1/main.py @@ -0,0 +1,33 @@ +import flet as ft +import flet_lottie as ftl + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ftl.Lottie( + src="https://raw.githubusercontent.com/xvrh/lottie-flutter/master/example/assets/Mobilo/A.json", + reverse=False, + animate=True, + error_content=ft.Placeholder(ft.Text("Error loading Lottie")), + on_error=lambda e: print(f"Error loading Lottie: {e.data}"), + ), + ftl.Lottie( + src="sample.json", + reverse=False, + animate=True, + enable_merge_paths=True, + enable_layers_opacity=True, + error_content=ft.Placeholder(ft.Text("Error loading Lottie")), + on_error=lambda e: print(f"Error loading Lottie: {e.data}"), + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/lottie/example_1/pyproject.toml b/sdk/python/examples/extensions/lottie/example_1/pyproject.toml new file mode 100644 index 0000000000..670db24128 --- /dev/null +++ b/sdk/python/examples/extensions/lottie/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "lottie-example-1" +version = "1.0.0" +description = "Plays Lottie animations from a remote URL and local JSON file with error fallback content." +requires-python = ">=3.10" +keywords = ["lottie", "animation", "json", "remote", "assets"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-lottie"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Lottie"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "Column", "Lottie", "Placeholder", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["remote lottie animation", "local lottie asset", "error callback and fallback content"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/attribution/main.py b/sdk/python/examples/extensions/map/attribution/main.py new file mode 100644 index 0000000000..b9b517cd2a --- /dev/null +++ b/sdk/python/examples/extensions/map/attribution/main.py @@ -0,0 +1,82 @@ +import flet as ft +import flet_map as ftm + + +def main(page: ft.Page): + def launch_url(url: str): + page.run_task(ft.UrlLauncher().launch_url, url) + + page.add( + ft.SafeArea( + expand=True, + content=ftm.Map( + expand=True, + initial_zoom=11, + initial_center=ftm.MapLatitudeLongitude( + latitude=40.7128, longitude=-74.0060 + ), + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + on_image_error=lambda e: print(f"TileLayer Error: {e.data}"), + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + text_style=ft.TextStyle( + color=ft.Colors.WHITE, weight=ft.FontWeight.BOLD, size=15 + ), + alignment=ft.Alignment.TOP_RIGHT, + bgcolor=ft.Colors.BLUE, + on_click=lambda: launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ftm.RichAttribution( + alignment=ftm.AttributionAlignment.BOTTOM_RIGHT, + popup_bgcolor=ft.Colors.WHITE, + popup_border_radius=8, + popup_initial_display_duration=4000, + permanent_height=28, + attributions=[ + ftm.ImageSourceAttribution( + image=ft.Image( + src="iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC", # noqa: E501 + width=74, + height=28, + fit=ft.BoxFit.CONTAIN, + ), + height=28, + tooltip="Flet Logo", + on_click=lambda: launch_url("https://flet.dev"), + ), + ftm.TextSourceAttribution( + text="OpenStreetMap contributors", + text_style=ft.TextStyle(size=12), + on_click=lambda: launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ftm.TextSourceAttribution( + text="flet-map", + text_style=ft.TextStyle( + color=ft.Colors.RED, + size=15, + weight=ft.FontWeight.BOLD, + decoration=ft.TextDecoration.UNDERLINE, + ), + prepend_copyright=False, + on_click=lambda: launch_url( + "https://flet.dev/docs/controls/map/" + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/attribution/pyproject.toml b/sdk/python/examples/extensions/map/attribution/pyproject.toml new file mode 100644 index 0000000000..bad880e10d --- /dev/null +++ b/sdk/python/examples/extensions/map/attribution/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-attribution" +version = "1.0.0" +description = "Compares simple and rich flet-map attribution layers with clickable text and image source attributions." +requires-python = ">=3.10" +keywords = ["map", "attribution", "rich attribution", "source attribution", "flet-map"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Extensions/Map"] + +[tool.flet.metadata] +title = "Attribution" +controls = ["SafeArea", "Image", "Map", "TileLayer", "SimpleAttribution", "RichAttribution", "TextSourceAttribution", "ImageSourceAttribution"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["simple attribution layer", "rich attribution popup", "text and image source attributions", "attribution click handlers"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/basic/main.py b/sdk/python/examples/extensions/map/basic/main.py new file mode 100644 index 0000000000..17ef94dbe2 --- /dev/null +++ b/sdk/python/examples/extensions/map/basic/main.py @@ -0,0 +1,25 @@ +import flet as ft +import flet_map as ftm + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ftm.Map( + expand=True, + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + on_image_error=lambda e: print(f"TileLayer Error: {e.data}"), + ), + ftm.SimpleAttribution(text="OpenStreetMap contributors"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/basic/pyproject.toml b/sdk/python/examples/extensions/map/basic/pyproject.toml new file mode 100644 index 0000000000..de5396dc6b --- /dev/null +++ b/sdk/python/examples/extensions/map/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-basic" +version = "1.0.0" +description = "Shows a basic flet-map tile layer with error callback handling." +requires-python = ">=3.10" +keywords = ["map", "tile layer", "flet-map", "geospatial"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Map"] + +[tool.flet.metadata] +title = "Basic" +controls = ["SafeArea", "Map", "TileLayer", "SimpleAttribution"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["map tile rendering", "tile load error callback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/camera_controls/main.py b/sdk/python/examples/extensions/map/camera_controls/main.py new file mode 100644 index 0000000000..da1886e17f --- /dev/null +++ b/sdk/python/examples/extensions/map/camera_controls/main.py @@ -0,0 +1,113 @@ +import flet as ft +import flet_map as ftm + + +def main(page: ft.Page): + page.padding = 16 + + async def update_camera_status(trigger: str): + camera = await my_map.get_camera() + camera_status.value = ( + f"Camera [{trigger}]: " + f"center=({camera.center.latitude:.5f}, {camera.center.longitude:.5f}), " + f"zoom={camera.zoom:.2f}, rotation={camera.rotation:.1f}" + ) + page.update() + + async def zoom_in(e: ft.Event[ft.Button]): + await my_map.zoom_in() + await update_camera_status("zoom_in") + + async def zoom_out(e: ft.Event[ft.Button]): + await my_map.zoom_out() + await update_camera_status("zoom_out") + + async def rotate_plus_15(e: ft.Event[ft.Button]): + await my_map.rotate_from(15) + await update_camera_status("rotate_from(+15)") + + async def reset_rotation(e: ft.Event[ft.Button]): + await my_map.reset_rotation() + await update_camera_status("reset_rotation") + + async def center_berlin(e: ft.Event[ft.Button]): + await my_map.center_on(point=ftm.MapLatitudeLongitude(52.52, 13.405), zoom=12) + await update_camera_status("center_on(berlin)") + + async def move_tokyo(e: ft.Event[ft.Button]): + await my_map.move_to( + destination=ftm.MapLatitudeLongitude(35.6762, 139.6503), zoom=11 + ) + await update_camera_status("move_to(tokyo)") + + async def set_world_zoom(e: ft.Event[ft.Button]): + await my_map.zoom_to(3) + await update_camera_status("zoom_to(3)") + + page.appbar = ft.AppBar(title="Camera controls") + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text( + "Use buttons to control map camera programmatically.", + size=12, + ), + ft.Row( + wrap=True, + spacing=8, + run_spacing=8, + controls=[ + ft.Button("Zoom in", on_click=zoom_in), + ft.Button("Zoom out", on_click=zoom_out), + ft.Button("Rotate +15°", on_click=rotate_plus_15), + ft.Button("Reset rotation", on_click=reset_rotation), + ft.Button("Center Berlin", on_click=center_berlin), + ft.Button("Move to Tokyo", on_click=move_tokyo), + ft.Button("World zoom (3)", on_click=set_world_zoom), + ], + ), + camera_status := ft.Text(selectable=True, font_family="monospace"), + my_map := ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude(52.52, 13.405), + initial_zoom=5, + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ftm.MarkerLayer( + markers=[ + ftm.Marker( + coordinates=ftm.MapLatitudeLongitude( + 52.52, 13.405 + ), + content=ft.Icon(ft.Icons.LOCATION_ON), + ), + ftm.Marker( + coordinates=ftm.MapLatitudeLongitude( + 35.6762, 139.6503 + ), + content=ft.Icon(ft.Icons.LOCATION_ON), + ), + ] + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/camera_controls/pyproject.toml b/sdk/python/examples/extensions/map/camera_controls/pyproject.toml new file mode 100644 index 0000000000..5988072e51 --- /dev/null +++ b/sdk/python/examples/extensions/map/camera_controls/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-camera-controls" +version = "1.0.0" +description = "Controls map camera programmatically with zoom, rotate, center, move, and state text updates." +requires-python = ">=3.10" +keywords = ["map", "camera controls", "zoom", "rotate", "markers"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Map"] + +[tool.flet.metadata] +title = "Camera Controls" +controls = ["SafeArea", "Column", "Row", "Map", "TileLayer", "SimpleAttribution", "MarkerLayer", "Marker", "Button", "Text", "Icon", "AppBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["programmatic camera actions", "camera state display", "predefined map centers"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/idle_camera/main.py b/sdk/python/examples/extensions/map/idle_camera/main.py new file mode 100644 index 0000000000..d2c383beb6 --- /dev/null +++ b/sdk/python/examples/extensions/map/idle_camera/main.py @@ -0,0 +1,84 @@ +import flet as ft +import flet_map as ftm + +IDLE_EVENT_TYPES = { + ftm.MapEventType.MOVE_END, + ftm.MapEventType.FLING_ANIMATION_END, + ftm.MapEventType.FLING_ANIMATION_NOT_STARTED, + ftm.MapEventType.DOUBLE_TAP_ZOOM_END, + ftm.MapEventType.ROTATE_END, +} + + +def main(page: ft.Page): + page.padding = 16 + + async def handle_map_event(e: ftm.MapEvent): + last_event.value = ( + "Last event: " + f"type={e.event_type}, source={e.source.value}, zoom={e.camera.zoom:.2f}" + ) + + if e.event_type in IDLE_EVENT_TYPES: # here the camera is settled/idle + camera = await e.control.get_camera() + settled_camera.value = ( + "Settled camera: " + f"center=({camera.center.latitude:.3f}, " + f"{camera.center.longitude:.3f}), " + f"zoom={camera.zoom:.2f}, rotation={camera.rotation:.1f}, " + f"trigger={e.event_type}" + ) + + page.update() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text("Camera idle pattern", size=20, weight=ft.FontWeight.BOLD), + ft.Text( + ( + "Drag, fling, rotate, zoom and watch " + "when the camera is settled." + ), + size=12, + ), + last_event := ft.Text( + "Last event: -", selectable=True, font_family="monospace" + ), + settled_camera := ft.Text( + "Settled camera: -", selectable=True, font_family="monospace" + ), + ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude( + latitude=52.52, longitude=13.405 + ), + initial_zoom=11, + on_event=handle_map_event, + interaction_configuration=ftm.InteractionConfiguration( + flags=ftm.InteractionFlag.ALL + ), + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/idle_camera/pyproject.toml b/sdk/python/examples/extensions/map/idle_camera/pyproject.toml new file mode 100644 index 0000000000..d968844306 --- /dev/null +++ b/sdk/python/examples/extensions/map/idle_camera/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-idle-camera" +version = "1.0.0" +description = "Tracks map events and reports settled camera state when idle-related events occur." +requires-python = ">=3.10" +keywords = ["map", "camera idle", "events", "interaction flags"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Map"] + +[tool.flet.metadata] +title = "Idle Camera" +controls = ["SafeArea", "Column", "Map", "TileLayer", "SimpleAttribution", "Text"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["map event handling", "idle camera detection", "camera status output"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/interaction_flags/main.py b/sdk/python/examples/extensions/map/interaction_flags/main.py new file mode 100644 index 0000000000..580b8914c5 --- /dev/null +++ b/sdk/python/examples/extensions/map/interaction_flags/main.py @@ -0,0 +1,105 @@ +import flet as ft +import flet_map as ftm + +FLAG_OPTIONS: list[tuple[str, ftm.InteractionFlag]] = [ + ("Drag", ftm.InteractionFlag.DRAG), + ("Fling animation", ftm.InteractionFlag.FLING_ANIMATION), + ("Pinch move", ftm.InteractionFlag.PINCH_MOVE), + ("Pinch zoom", ftm.InteractionFlag.PINCH_ZOOM), + ("Double tap zoom", ftm.InteractionFlag.DOUBLE_TAP_ZOOM), + ("Double tap drag zoom", ftm.InteractionFlag.DOUBLE_TAP_DRAG_ZOOM), + ("Scroll wheel zoom", ftm.InteractionFlag.SCROLL_WHEEL_ZOOM), + ("Rotate", ftm.InteractionFlag.ROTATE), +] + + +def main(page: ft.Page): + page.padding = 16 + + def get_selected_flags() -> ftm.InteractionFlag: + flags = ftm.InteractionFlag.NONE + for checkbox in checkboxes: + if checkbox.value: + flags |= checkbox.data + return flags + + def update_interaction_flags(e: ft.Event[ft.Checkbox] = None): + flags = get_selected_flags() + my_map.interaction_configuration = ftm.InteractionConfiguration(flags=flags) + page.update() + + def handle_map_event(e: ftm.MapEvent): + event_type = e.event_type.value if e.event_type else "-" + last_event.value = ( + "Last event: " + f"type={event_type}, source={e.source.value}, zoom={e.camera.zoom:.2f}" + ) + page.update() + + checkboxes = [ + ft.Checkbox( + label=label, + value=True, + data=flag, + on_change=update_interaction_flags, + ) + for label, flag in FLAG_OPTIONS + ] + + my_map = ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude(latitude=52.52, longitude=13.405), + initial_zoom=11, + on_event=handle_map_event, + interaction_configuration=ftm.InteractionConfiguration( + flags=ftm.InteractionFlag.ALL + ), + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + on_image_error=lambda e: print(f"TileLayer Error: {e.data}"), + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + ], + ) + + page.appbar = ft.AppBar(title="Interaction flags") + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text( + ( + "Toggle flags and try dragging, zooming, rotating, " + "and scrolling." + ), + size=12, + ), + ft.ResponsiveRow( + controls=[ + ft.Container(col={"sm": 6, "md": 4}, content=c) + for c in checkboxes + ] + ), + last_event := ft.Text( + "Last event: -", selectable=True, font_family="monospace" + ), + ft.Container(expand=True, content=my_map), + ], + ), + ) + ) + + update_interaction_flags() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/interaction_flags/pyproject.toml b/sdk/python/examples/extensions/map/interaction_flags/pyproject.toml new file mode 100644 index 0000000000..7da4c77b70 --- /dev/null +++ b/sdk/python/examples/extensions/map/interaction_flags/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-interaction-flags" +version = "1.0.0" +description = "Toggles map interaction flags with checkboxes and displays live map event details." +requires-python = ">=3.10" +keywords = ["map", "interaction flags", "checkbox", "events", "attribution"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Map"] + +[tool.flet.metadata] +title = "Interaction Flags" +controls = ["SafeArea", "Column", "ResponsiveRow", "Container", "Checkbox", "Map", "TileLayer", "SimpleAttribution", "Text", "AppBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["runtime interaction toggles", "map event logging", "tile attribution"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/multi_layers/main.py b/sdk/python/examples/extensions/map/multi_layers/main.py new file mode 100644 index 0000000000..e79263637b --- /dev/null +++ b/sdk/python/examples/extensions/map/multi_layers/main.py @@ -0,0 +1,139 @@ +import random + +import flet as ft +import flet_map as ftm + + +def main(page: ft.Page): + def handle_tap(e: ftm.MapTapEvent): + if e.name == "tap": + marker_layer.markers.append( + ftm.Marker( + content=ft.Icon( + ft.Icons.LOCATION_ON, color=ft.CupertinoColors.DESTRUCTIVE_RED + ), + coordinates=e.coordinates, + ) + ) + elif e.name == "secondary_tap": + circle_layer.circles.append( + ftm.CircleMarker( + radius=random.randint(5, 10), + coordinates=e.coordinates, + color=ft.Colors.random(), + border_color=ft.Colors.random(), + border_stroke_width=4, + ) + ) + page.update() + + page.appbar = ft.AppBar(title="Multiple Layers") + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.Text( + "Click anywhere to add a Marker, right-click to add a " + "CircleMarker." + ), + ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude(15, 10), + initial_zoom=4.2, + interaction_configuration=ftm.InteractionConfiguration( + flags=ftm.InteractionFlag.ALL + ), + on_tap=handle_tap, + on_secondary_tap=handle_tap, + on_event=print, + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + on_image_error=lambda e: print("TileLayer Error"), + ), + ftm.SimpleAttribution( + text="OpenStreetMap contributors", + on_click=lambda e: e.page.launch_url( + "https://www.openstreetmap.org/copyright" + ), + ), + marker_layer := ftm.MarkerLayer( + markers=[ + ftm.Marker( + content=ft.Icon(ft.Icons.LOCATION_ON), + coordinates=ftm.MapLatitudeLongitude(30, 15), + ), + ftm.Marker( + content=ft.Icon(ft.Icons.LOCATION_ON), + coordinates=ftm.MapLatitudeLongitude(10, 10), + ), + ftm.Marker( + content=ft.Icon(ft.Icons.LOCATION_ON), + coordinates=ftm.MapLatitudeLongitude(25, 45), + ), + ], + ), + circle_layer := ftm.CircleLayer( + circles=[ + ftm.CircleMarker( + radius=10, + coordinates=ftm.MapLatitudeLongitude(16, 24), + color=ft.Colors.RED, + border_color=ft.Colors.BLUE, + border_stroke_width=4, + ), + ], + ), + ftm.PolygonLayer( + polygons=[ + ftm.PolygonMarker( + label="Popular Touristic Area", + label_text_style=ft.TextStyle( + color=ft.Colors.BLACK, + size=15, + weight=ft.FontWeight.BOLD, + ), + color=ft.Colors.with_opacity( + 0.3, ft.Colors.BLUE + ), + coordinates=[ + ftm.MapLatitudeLongitude(10, 10), + ftm.MapLatitudeLongitude(30, 15), + ftm.MapLatitudeLongitude(25, 45), + ], + ), + ], + ), + ftm.PolylineLayer( + polylines=[ + ftm.PolylineMarker( + border_stroke_width=3, + border_color=ft.Colors.RED, + gradient_colors=[ + ft.Colors.BLACK, + ft.Colors.BLACK, + ], + color=ft.Colors.with_opacity( + 0.6, ft.Colors.GREEN + ), + coordinates=[ + ftm.MapLatitudeLongitude(10, 10), + ftm.MapLatitudeLongitude(30, 15), + ftm.MapLatitudeLongitude(25, 45), + ], + ), + ], + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/multi_layers/pyproject.toml b/sdk/python/examples/extensions/map/multi_layers/pyproject.toml new file mode 100644 index 0000000000..ac7fd98b24 --- /dev/null +++ b/sdk/python/examples/extensions/map/multi_layers/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-multi-layers" +version = "1.0.0" +description = "Combines tile, marker, circle, polygon, and polyline layers with tap-to-add overlays." +requires-python = ">=3.10" +keywords = ["map", "layers", "markers", "polygons", "polylines"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Map"] + +[tool.flet.metadata] +title = "Multiple Layers" +controls = ["SafeArea", "Column", "Text", "Map", "TileLayer", "SimpleAttribution", "MarkerLayer", "Marker", "CircleLayer", "CircleMarker", "PolygonLayer", "PolygonMarker", "PolylineLayer", "PolylineMarker", "Icon", "AppBar"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["multi-layer map composition", "tap and secondary-tap overlay creation", "tile attribution"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/map/overlay_images/main.py b/sdk/python/examples/extensions/map/overlay_images/main.py new file mode 100644 index 0000000000..3c264b8300 --- /dev/null +++ b/sdk/python/examples/extensions/map/overlay_images/main.py @@ -0,0 +1,53 @@ +import flet as ft +import flet_map as ftm + +base64_image = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ftm.Map( + expand=True, + initial_center=ftm.MapLatitudeLongitude(51.5, -0.09), + initial_zoom=6, + layers=[ + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="flet-map-examples/1.0", + ), + ftm.OverlayImageLayer( + overlay_images=[ + ftm.OverlayImage( + src=base64_image, + bounds=ftm.MapLatitudeLongitudeBounds( + corner_1=ftm.MapLatitudeLongitude(51.5, -0.09), + corner_2=ftm.MapLatitudeLongitude(48.8566, 2.3522), + ), + opacity=0.8, + ), + ftm.RotatedOverlayImage( + src=base64_image, + top_left_corner=ftm.MapLatitudeLongitude( + 53.377, -2.999 + ), + bottom_left_corner=ftm.MapLatitudeLongitude( + 52.503, -1.868 + ), + bottom_right_corner=ftm.MapLatitudeLongitude( + 53.475, 0.275 + ), + opacity=0.8, + ), + ] + ), + ftm.SimpleAttribution(text="OpenStreetMap contributors"), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/map/overlay_images/pyproject.toml b/sdk/python/examples/extensions/map/overlay_images/pyproject.toml new file mode 100644 index 0000000000..b55a305775 --- /dev/null +++ b/sdk/python/examples/extensions/map/overlay_images/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "map-overlay-images" +version = "1.0.0" +description = "Places rectangular and rotated image overlays on top of an interactive map." +requires-python = ">=3.10" +keywords = ["map", "overlay", "image", "rotated overlay"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-map"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Displays/Map"] + +[tool.flet.metadata] +title = "Overlay Images" +controls = ["SafeArea", "Map", "TileLayer", "OverlayImageLayer", "OverlayImage", "RotatedOverlayImage", "SimpleAttribution"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["rectangular image overlay", "rotated image overlay"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/permission_handler/example_1/main.py b/sdk/python/examples/extensions/permission_handler/example_1/main.py new file mode 100644 index 0000000000..3903d1ba1a --- /dev/null +++ b/sdk/python/examples/extensions/permission_handler/example_1/main.py @@ -0,0 +1,44 @@ +import flet as ft +import flet_permission_handler as fph + + +def main(page: ft.Page): + page.appbar = ft.AppBar(title="PermissionHandler Playground") + + def show_snackbar(message: str): + page.show_dialog(ft.SnackBar(ft.Text(message))) + + async def get_permission_status(e: ft.Event[ft.OutlinedButton]): + status = await ph.get_status(fph.Permission.MICROPHONE) + show_snackbar(f"Microphone permission status: {status.name}") + + async def request_permission(e: ft.Event[ft.OutlinedButton]): + status = await ph.request(fph.Permission.MICROPHONE) + show_snackbar(f"Requested microphone permission: {status.name}") + + async def open_app_settings(e: ft.Event[ft.OutlinedButton]): + show_snackbar("Opening app settings...") + await ph.open_app_settings() + + ph = fph.PermissionHandler() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.OutlinedButton("Open app settings", on_click=open_app_settings), + ft.OutlinedButton( + "Request Microphone permission", on_click=request_permission + ), + ft.OutlinedButton( + "Get Microphone permission status", + on_click=get_permission_status, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/permission_handler/example_1/pyproject.toml b/sdk/python/examples/extensions/permission_handler/example_1/pyproject.toml new file mode 100644 index 0000000000..c8b6bbf0b1 --- /dev/null +++ b/sdk/python/examples/extensions/permission_handler/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-permission-handler-example-1" +version = "1.0.0" +description = "Requests microphone permission, reads its status, and opens app settings." +requires-python = ">=3.10" +keywords = ["permission handler", "example 1", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-permission-handler"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/PermissionHandler"] + +[tool.flet.metadata] +title = "Permission handler example" +controls = ["SafeArea", "Column", "Page", "AppBar", "Text", "OutlinedButton", "PermissionHandler"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["permission request", "settings shortcut"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["windows", "ios", "android", "web"] diff --git a/sdk/python/examples/extensions/rive/example_1/assets/vehicles.riv b/sdk/python/examples/extensions/rive/example_1/assets/vehicles.riv new file mode 100644 index 0000000000..5574a91f25 Binary files /dev/null and b/sdk/python/examples/extensions/rive/example_1/assets/vehicles.riv differ diff --git a/sdk/python/examples/extensions/rive/example_1/main.py b/sdk/python/examples/extensions/rive/example_1/main.py new file mode 100644 index 0000000000..689775fe3c --- /dev/null +++ b/sdk/python/examples/extensions/rive/example_1/main.py @@ -0,0 +1,29 @@ +import flet as ft +import flet_rive as ftr + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ftr.Rive( + src="https://cdn.rive.app/animations/vehicles.riv", + placeholder=ft.ProgressBar(), + width=300, + height=200, + ), + ftr.Rive( + src="vehicles.riv", + placeholder=ft.ProgressBar(), + width=300, + height=200, + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/rive/example_1/pyproject.toml b/sdk/python/examples/extensions/rive/example_1/pyproject.toml new file mode 100644 index 0000000000..3198cd20b2 --- /dev/null +++ b/sdk/python/examples/extensions/rive/example_1/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "rive-example-1" +version = "1.0.0" +description = "Plays a remote Rive animation and a local Rive asset." +requires-python = ">=3.10" +keywords = ["rive", "animation", "extension", "assets", "local file", "remote file"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-rive"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Rive"] + +[tool.flet.metadata] +title = "Example 1" +controls = ["SafeArea", "Column", "Rive", "ProgressBar"] +layout_pattern = "media-showcase" +complexity = "basic" +features = ["remote animations", "local asset playback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/secure_storage/basic/main.py b/sdk/python/examples/extensions/secure_storage/basic/main.py new file mode 100644 index 0000000000..178b664f94 --- /dev/null +++ b/sdk/python/examples/extensions/secure_storage/basic/main.py @@ -0,0 +1,98 @@ +import base64 +import os + +import flet as ft +import flet_secure_storage as fss + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + storage = fss.SecureStorage( + web_options=fss.WebOptions( + db_name="customstorage", + public_key="publickey", + wrap_key=base64.urlsafe_b64encode(os.urandom(32)).decode(), + wrap_key_iv=base64.urlsafe_b64encode(os.urandom(16)).decode(), + ), + android_options=fss.AndroidOptions( + reset_on_error=True, + migrate_on_algorithm_change=True, + enforce_biometrics=True, + key_cipher_algorithm=fss.KeyCipherAlgorithm.AES_GCM_NO_PADDING, + storage_cipher_algorithm=fss.StorageCipherAlgorithm.AES_GCM_NO_PADDING, + ), + ) + + key = ft.TextField(label="Key", value="example_key") + value = ft.TextField(label="Value", value="secret_value") + result = ft.Text(theme_style=ft.TextThemeStyle.TITLE_LARGE) + + async def set_value(e): + await storage.set(key.value, value.value) + result.value = "Value saved" + + async def get_value(e): + result.value = await storage.get(key.value) + + async def remove_value(e): + await storage.remove(key.value) + result.value = "Value removed" + + async def clear_storage(e): + await storage.clear() + result.value = "Storage cleared" + + async def contains_key(e): + exists = await storage.contains_key(key.value) + result.value = f"Key exists: {exists}" + + async def get_availability(e): + is_availability = await storage.get_availability() + page.show_dialog( + ft.SnackBar( + content=ft.Text( + value=f"Protected data available: {is_availability}" + if is_availability + else "Protected data available: None" + ) + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=10, + controls=[ + result, + key, + value, + ft.Row( + width=300, + wrap=True, + controls=[ + ft.Button("Set", on_click=set_value), + ft.Button("Get", on_click=get_value), + ft.Button("Contains key", on_click=contains_key), + ft.Button("Remove", on_click=remove_value), + ft.Button("Clear", on_click=clear_storage), + ft.Button( + "Check Data Availability", + on_click=get_availability, + ), + ], + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/secure_storage/basic/pyproject.toml b/sdk/python/examples/extensions/secure_storage/basic/pyproject.toml new file mode 100644 index 0000000000..f38c6177b0 --- /dev/null +++ b/sdk/python/examples/extensions/secure_storage/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-secure-storage-basic" +version = "1.0.0" +description = "Stores, reads, removes, and clears protected key-value entries in secure storage." +requires-python = ">=3.10" +keywords = ["secure storage", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-secure-storage"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/SecureStorage"] + +[tool.flet.metadata] +title = "Basic secure storage" +controls = ["SafeArea", "Column", "Page", "SecureStorage", "TextField", "Text", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["protected storage", "key-value operations"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/basic/main.py b/sdk/python/examples/extensions/video/basic/main.py new file mode 100644 index 0000000000..2198cf0851 --- /dev/null +++ b/sdk/python/examples/extensions/video/basic/main.py @@ -0,0 +1,23 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ftv.Video( + expand=True, + autoplay=True, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/basic/pyproject.toml b/sdk/python/examples/extensions/video/basic/pyproject.toml new file mode 100644 index 0000000000..0a0ccb922f --- /dev/null +++ b/sdk/python/examples/extensions/video/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-basic" +version = "1.0.0" +description = "Plays a single video using the flet-video player." +requires-python = ">=3.10" +keywords = ["video", "media", "player", "basic"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Basic Video" +controls = ["SafeArea", "Video"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["video playback", "autoplay"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/button_bars/assets/video-sample.mp4 b/sdk/python/examples/extensions/video/button_bars/assets/video-sample.mp4 new file mode 100644 index 0000000000..3ae36b91c8 Binary files /dev/null and b/sdk/python/examples/extensions/video/button_bars/assets/video-sample.mp4 differ diff --git a/sdk/python/examples/extensions/video/button_bars/main.py b/sdk/python/examples/extensions/video/button_bars/main.py new file mode 100644 index 0000000000..f9e713c60d --- /dev/null +++ b/sdk/python/examples/extensions/video/button_bars/main.py @@ -0,0 +1,59 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + label_style = ft.TextStyle( + size=12, + color=ft.Colors.WHITE, + weight=ft.FontWeight.BOLD, + ) + + page.add( + ft.SafeArea( + expand=True, + content=ftv.Video( + expand=True, + playlist=[ + ftv.VideoMedia("video-sample.mp4"), + ], + controls=ftv.MaterialDesktopVideoControls( + visible_on_mount=True, + primary_button_bar=[ + ftv.VideoSkipPreviousButton(icon_color=ft.Colors.CYAN), + ftv.VideoPlayOrPauseButton( + icon_size=40, + icon_color=ft.Colors.CYAN, + ), + ftv.VideoSkipNextButton( + icon=ft.Icon(ft.Icons.FAST_FORWARD), + icon_color=ft.Colors.CYAN, + ), + ], + top_button_bar=[ + ft.Text("Top button bar", style=label_style), + ftv.VideoSpacer(), + ftv.VideoFullscreenButton(icon_color=ft.Colors.AMBER), + ], + bottom_button_bar=[ + ft.Text("Bottom button bar", style=label_style), + ftv.VideoSpacer(), + ftv.VideoPositionIndicator( + text_style=ft.TextStyle( + size=13, + color=ft.Colors.WHITE, + ) + ), + ftv.VideoVolumeButton( + slider_width=96, + icon_color=ft.Colors.AMBER, + ), + ], + ), + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/button_bars/pyproject.toml b/sdk/python/examples/extensions/video/button_bars/pyproject.toml new file mode 100644 index 0000000000..0453573ccc --- /dev/null +++ b/sdk/python/examples/extensions/video/button_bars/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-button-bars" +version = "1.0.0" +description = "Customize video controls primary, top, and bottom button bars." +requires-python = ">=3.10" +keywords = ["video", "controls", "media", "material", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Button bars" +controls = ["SafeArea", "Text", "Icon", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["controls", "button bars", "built-in controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/controls/main.py b/sdk/python/examples/extensions/video/controls/main.py new file mode 100644 index 0000000000..9b69d8d406 --- /dev/null +++ b/sdk/python/examples/extensions/video/controls/main.py @@ -0,0 +1,127 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + def set_controls( + value: ftv.VideoControls | ft.Control | None, + ): + video.controls = value + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + video := ftv.Video( + expand=True, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ], + controls=ftv.MaterialDesktopVideoControls( + visible_on_mount=True, + display_seek_bar=True, + modify_volume_on_scroll=True, + toggle_fullscreen_on_double_press=True, + play_and_pause_on_tap=True, + seek_bar_position_color=ft.Colors.BLUE, + volume_bar_active_color=ft.Colors.YELLOW, + controls_hover_duration=ft.Duration(seconds=5), + ), + ), + ft.Row( + wrap=True, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button( + "Adaptive", + on_click=lambda _: set_controls( + ftv.AdaptiveVideoControls( + material=ftv.MaterialVideoControls( + visible_on_mount=True, + display_seek_bar=True, + volume_gesture=True, + brightness_gesture=True, + seek_gesture=True, + seek_on_double_tap=True, + speed_up_on_long_press=True, + seek_bar_position_color=ft.Colors.BLUE, + button_bar_button_color="#E0F7FA", + ), + material_desktop=ftv.MaterialDesktopVideoControls( + visible_on_mount=True, + display_seek_bar=True, + modify_volume_on_scroll=True, + toggle_fullscreen_on_double_press=True, + play_and_pause_on_tap=True, + hide_mouse_on_controls_removal=True, + seek_bar_position_color=ft.Colors.BLUE, + volume_bar_active_color=ft.Colors.YELLOW, + ), + ) + ), + ), + ft.Button( + "Material", + on_click=lambda _: set_controls( + ftv.MaterialVideoControls( + visible_on_mount=True, + volume_gesture=True, + brightness_gesture=True, + seek_gesture=True, + seek_on_double_tap=True, + speed_up_on_long_press=True, + speed_up_factor=2.5, + controls_transition_duration=ft.Duration( + milliseconds=450 + ), + seek_bar_position_color=ft.Colors.BLUE, + button_bar_button_color="#E0F7FA", + ) + ), + ), + ft.Button( + "Material Desktop", + on_click=lambda _: set_controls( + ftv.MaterialDesktopVideoControls( + visible_on_mount=True, + display_seek_bar=True, + modify_volume_on_scroll=True, + toggle_fullscreen_on_double_press=True, + play_and_pause_on_tap=True, + hide_mouse_on_controls_removal=True, + controls_hover_duration=ft.Duration(seconds=5), + seek_bar_position_color=ft.Colors.BLUE, + seek_bar_hover_height=8, + volume_bar_active_color=ft.Colors.YELLOW, + ) + ), + ), + ft.Button( + "Custom Control", + on_click=lambda _: set_controls( + ft.Container( + alignment=ft.Alignment.BOTTOM_CENTER, + padding=16, + content=ft.Text("This is a custom control..."), + ) + ), + ), + ft.Button( + "No Controls", + on_click=lambda _: set_controls(None), + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/controls/pyproject.toml b/sdk/python/examples/extensions/video/controls/pyproject.toml new file mode 100644 index 0000000000..a924227726 --- /dev/null +++ b/sdk/python/examples/extensions/video/controls/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-controls" +version = "1.0.0" +description = "Switch between built-in, custom, and hidden video controls." +requires-python = ">=3.10" +keywords = ["video", "controls", "media", "material", "desktop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Controls" +controls = ["SafeArea", "Column", "Row", "Button", "IconButton", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["controls", "adaptive controls", "material controls", "custom controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/controls_mode/main.py b/sdk/python/examples/extensions/video/controls_mode/main.py new file mode 100644 index 0000000000..a5b546bb5f --- /dev/null +++ b/sdk/python/examples/extensions/video/controls_mode/main.py @@ -0,0 +1,42 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=ftv.Video( + expand=True, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ], + controls={ + ftv.VideoControlsMode.NORMAL: ftv.MaterialDesktopVideoControls( + visible_on_mount=True, + bottom_button_bar=[ + ftv.VideoPlayOrPauseButton(), + ftv.VideoSpacer(), + ft.Text("NORMAL Mode", weight=ft.FontWeight.BOLD), + ftv.VideoFullscreenButton(), + ], + ), + ftv.VideoControlsMode.FULLSCREEN: ftv.MaterialDesktopVideoControls( + visible_on_mount=True, + bottom_button_bar=[ + ftv.VideoFullscreenButton(), + ftv.VideoSpacer(), + ft.Text("FULLSCREEN Mode", weight=ft.FontWeight.BOLD), + ftv.VideoPlayOrPauseButton(), + ], + ), + }, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/controls_mode/pyproject.toml b/sdk/python/examples/extensions/video/controls_mode/pyproject.toml new file mode 100644 index 0000000000..fbc5249288 --- /dev/null +++ b/sdk/python/examples/extensions/video/controls_mode/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-controls-mode" +version = "1.0.0" +description = "Show different video controls in normal and fullscreen modes." +requires-python = ">=3.10" +keywords = ["video", "controls", "media", "fullscreen"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Mode-specific controls" +controls = ["SafeArea", "Container", "Text", "Video"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["controls", "mode-specific controls", "fullscreen controls"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/events/main.py b/sdk/python/examples/extensions/video/events/main.py new file mode 100644 index 0000000000..d85d050e40 --- /dev/null +++ b/sdk/python/examples/extensions/video/events/main.py @@ -0,0 +1,63 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + def handle_load(e: ft.Event[ftv.Video]): + print("Video loaded") + + def handle_complete(e: ft.Event[ftv.Video]): + print(f"Track completed: {e.data}") + + def handle_track_change(e: ft.Event[ftv.Video]): + print(f"Track changed to index {e.data}") + + def handle_position_change(e: ft.Event[ftv.Video]): + print(f"Position: {e.data.in_milliseconds / 1000:.3f}s") + + def handle_duration_change(e: ft.Event[ftv.Video]): + print(f"Duration changed: {e.data.in_seconds}s") + + def handle_error(e: ft.Event[ftv.Video]): + print(f"Error: {e.data}") + + def handle_enter_fullscreen(e: ft.Event[ftv.Video]): + print("Entered fullscreen") + + def handle_exit_fullscreen(e: ft.Event[ftv.Video]): + print("Exited fullscreen") + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + controls=[ + ftv.Video( + expand=True, + autoplay=True, + on_load=handle_load, + on_complete=handle_complete, + on_track_change=handle_track_change, + on_position_change=handle_position_change, + on_duration_change=handle_duration_change, + on_error=handle_error, + on_enter_fullscreen=handle_enter_fullscreen, + on_exit_fullscreen=handle_exit_fullscreen, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4" + ), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/events/pyproject.toml b/sdk/python/examples/extensions/video/events/pyproject.toml new file mode 100644 index 0000000000..23ba44d8dc --- /dev/null +++ b/sdk/python/examples/extensions/video/events/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-events" +version = "1.0.0" +description = "React to video events: load, complete, track change, error, etc." +requires-python = ">=3.10" +keywords = ["video", "events", "load", "complete", "track change"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Events" +controls = ["SafeArea", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["event handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/playback/main.py b/sdk/python/examples/extensions/video/playback/main.py new file mode 100644 index 0000000000..159249dce1 --- /dev/null +++ b/sdk/python/examples/extensions/video/playback/main.py @@ -0,0 +1,79 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + async def handle_play(e: ft.Event[ft.Button]): + await video.play() + + async def handle_play_or_pause(e: ft.Event[ft.Button]): + await video.play_or_pause() + + async def handle_pause(e: ft.Event[ft.Button]): + await video.pause() + + async def handle_stop(e: ft.Event[ft.Button]): + await video.stop() + + async def handle_seek(e: ft.Event[ft.Button]): + await video.seek(ft.Duration(seconds=10)) + + async def handle_next(e: ft.Event[ft.Button]): + await video.next() + + async def handle_previous(e: ft.Event[ft.Button]): + await video.previous() + + async def handle_status(e: ft.Event[ft.Button]): + playing = await video.is_playing() + position = (await video.get_current_position()).in_seconds + duration = (await video.get_duration()).in_seconds + page.show_dialog( + ft.SnackBar( + f"Playing?: {playing} | Duration: {duration}s | Position: {position}s" + ) + ) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + video := ftv.Video( + expand=True, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4" + ), + ], + ), + ft.Row( + wrap=True, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button("Play", on_click=handle_play), + ft.Button("Play Or Pause", on_click=handle_play_or_pause), + ft.Button("Pause", on_click=handle_pause), + ft.Button("Stop", on_click=handle_stop), + ft.Button("Seek 10s", on_click=handle_seek), + ft.Button("Previous", on_click=handle_previous), + ft.Button("Next", on_click=handle_next), + ft.Button("Show Status", on_click=handle_status), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/playback/pyproject.toml b/sdk/python/examples/extensions/video/playback/pyproject.toml new file mode 100644 index 0000000000..2f1217f1e2 --- /dev/null +++ b/sdk/python/examples/extensions/video/playback/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-playback" +version = "1.0.0" +description = "Control video playback: play, pause, stop, seek, and inspect status." +requires-python = ">=3.10" +keywords = ["video", "playback", "play", "pause", "seek"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Playback Controls" +controls = ["SafeArea", "Column", "Row", "Button", "Text", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["play/pause/stop", "seek", "status inspection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/playlist/main.py b/sdk/python/examples/extensions/video/playlist/main.py new file mode 100644 index 0000000000..d67766f120 --- /dev/null +++ b/sdk/python/examples/extensions/video/playlist/main.py @@ -0,0 +1,74 @@ +import random + +import flet as ft +import flet_video as ftv + +media = [ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4" + ), + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4" + ), +] + + +def main(page: ft.Page): + def handle_add(e: ft.Event[ft.Button]): + video.playlist.append(random.choice(media)) + + def handle_remove(e: ft.Event[ft.Button]): + if video.playlist: + video.playlist.pop(random.randint(0, len(video.playlist) - 1)) + + def handle_replace(e: ft.Event[ft.Button]): + video.playlist = random.sample(media, 3) + + async def handle_next(e: ft.Event[ft.Button]): + await video.next() + + async def handle_previous(e: ft.Event[ft.Button]): + await video.previous() + + async def handle_jump(e: ft.Event[ft.Button]): + await video.jump_to(0) + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + video := ftv.Video( + expand=True, + autoplay=True, + playlist=media[:2], + playlist_mode=ftv.PlaylistMode.LOOP, + ), + ft.Row( + wrap=True, + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Button("Add Random", on_click=handle_add), + ft.Button("Remove Random", on_click=handle_remove), + ft.Button("Replace Playlist", on_click=handle_replace), + ft.Button("Next", on_click=handle_next), + ft.Button("Previous", on_click=handle_previous), + ft.Button("Jump to First", on_click=handle_jump), + ], + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/playlist/pyproject.toml b/sdk/python/examples/extensions/video/playlist/pyproject.toml new file mode 100644 index 0000000000..15ebcbfa45 --- /dev/null +++ b/sdk/python/examples/extensions/video/playlist/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-playlist" +version = "1.0.0" +description = "Manage a video playlist: add, remove, replace, and navigate between tracks." +requires-python = ">=3.10" +keywords = ["video", "playlist", "media", "loop", "navigation"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Playlist" +controls = ["SafeArea", "Column", "Row", "Button", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["playlist mutation", "loop mode", "next/previous/jump"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/screenshot/main.py b/sdk/python/examples/extensions/video/screenshot/main.py new file mode 100644 index 0000000000..d7d52d3c87 --- /dev/null +++ b/sdk/python/examples/extensions/video/screenshot/main.py @@ -0,0 +1,56 @@ +import flet as ft +import flet_video as ftv + + +def main(page: ft.Page): + async def handle_screenshot(e: ft.Event[ft.FloatingActionButton]): + image = await video.take_screenshot(format="image/png") + if image is None: + status.value = "No video frame is available yet." + else: + preview.content = ft.Image( + src=image, + width=260, + height=146, + fit=ft.BoxFit.CONTAIN, + ) + status.value = f"Captured {len(image)} bytes." + page.update() + + page.floating_action_button = ft.FloatingActionButton( + content="Take screenshot", + icon=ft.Icons.CAMERA_ALT, + on_click=handle_screenshot, + ) + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + video := ftv.Video( + expand=True, + autoplay=True, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ], + ), + preview := ft.Container( + width=260, + height=146, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.BLACK_12, + content=ft.Text("No screenshot yet"), + ), + status := ft.Text(), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/screenshot/pyproject.toml b/sdk/python/examples/extensions/video/screenshot/pyproject.toml new file mode 100644 index 0000000000..691296c054 --- /dev/null +++ b/sdk/python/examples/extensions/video/screenshot/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-screenshot" +version = "1.0.0" +description = "Capture the current video frame and display it as an image." +requires-python = ">=3.10" +keywords = ["video", "screenshot", "frame", "capture"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Video Screenshot" +controls = ["SafeArea", "Column", "Row", "Button", "Container", "Image", "Text", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["frame capture", "image preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/video/subtitles/main.py b/sdk/python/examples/extensions/video/subtitles/main.py new file mode 100644 index 0000000000..cebecc9c9b --- /dev/null +++ b/sdk/python/examples/extensions/video/subtitles/main.py @@ -0,0 +1,69 @@ +import flet as ft +import flet_video as ftv + +SAMPLE_VTT = """WEBVTT + +00:00:00.000 --> 00:00:04.000 +Welcome to flet-video! + +00:00:04.000 --> 00:00:08.000 +Subtitles are styled via VideoSubtitleConfiguration. + +00:00:08.000 --> 00:00:14.000 +This track is provided as raw VTT text. +""" + + +def main(page: ft.Page): + page.spacing = 20 + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + subtitle_track = ftv.VideoSubtitleTrack( + src=SAMPLE_VTT, + title="English", + language="en", + ) + + def handle_change(e: ft.Event[ft.Switch]): + if e.control.value: + video.subtitle_track = subtitle_track + else: + video.subtitle_track = ftv.VideoSubtitleTrack.none() + + page.add( + ft.SafeArea( + expand=True, + content=ft.Column( + expand=True, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + video := ftv.Video( + expand=True, + autoplay=False, + playlist=[ + ftv.VideoMedia( + "https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4" + ), + ], + subtitle_track=subtitle_track, + subtitle_configuration=ftv.VideoSubtitleConfiguration( + text_align=ft.TextAlign.CENTER, + text_style=ft.TextStyle( + size=24, + color=ft.Colors.YELLOW, + weight=ft.FontWeight.BOLD, + bgcolor=ft.Colors.BLACK_54, + ), + ), + ), + ft.Switch( + value=True, label="Show Subtitles", on_change=handle_change + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/video/subtitles/pyproject.toml b/sdk/python/examples/extensions/video/subtitles/pyproject.toml new file mode 100644 index 0000000000..2da50ee4ea --- /dev/null +++ b/sdk/python/examples/extensions/video/subtitles/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "video-subtitles" +version = "1.0.0" +description = "Display and style subtitles, with a toggle to enable/disable them." +requires-python = ">=3.10" +keywords = ["video", "subtitles", "vtt", "captions"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-video"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Media/Video"] + +[tool.flet.metadata] +title = "Subtitles" +controls = ["SafeArea", "Column", "Switch", "Video"] +layout_pattern = "dashboard" +complexity = "basic" +features = ["inline VTT subtitle track", "custom subtitle styling", "toggle subtitles"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/extensions/webview/example_1/main.py b/sdk/python/examples/extensions/webview/example_1/main.py new file mode 100644 index 0000000000..7bc13ebda5 --- /dev/null +++ b/sdk/python/examples/extensions/webview/example_1/main.py @@ -0,0 +1,21 @@ +import flet as ft +import flet_webview as fwv + + +def main(page: ft.Page): + page.add( + ft.SafeArea( + expand=True, + content=fwv.WebView( + url="https://flet.dev", + on_page_started=lambda _: print("Page started"), + on_page_ended=lambda _: print("Page ended"), + on_web_resource_error=lambda e: print("WebView error:", e.data), + expand=True, + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/extensions/webview/example_1/pyproject.toml b/sdk/python/examples/extensions/webview/example_1/pyproject.toml new file mode 100644 index 0000000000..a2dffc3a8b --- /dev/null +++ b/sdk/python/examples/extensions/webview/example_1/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "webview-example-1" +version = "1.0.0" +description = "Displays a web page in a WebView and logs page lifecycle events." +requires-python = ">=3.10" +keywords = ["webview", "browser", "web", "events", "embedded"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet", "flet-webview"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Display/WebView"] + +[tool.flet.metadata] +title = "WebView example 1" +controls = ["SafeArea", "WebView"] +layout_pattern = "single-panel" +complexity = "basic" +features = ["page lifecycle events"] + +[tool.flet] +platforms = ["macos", "ios", "android"] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/gallery.yaml b/sdk/python/examples/gallery.yaml new file mode 100644 index 0000000000..0e02041c6b --- /dev/null +++ b/sdk/python/examples/gallery.yaml @@ -0,0 +1,250 @@ +# Curated catalog for the Flet gallery. +# +# Top-level `categories:` is a map of name -> entry. An entry is either +# `null` (bare name, no metadata, no children) or a map. Inside an +# entry, `_`-prefixed keys are metadata (`_icon`, `_description`); all +# other keys are child categories with the same recursive shape. +# +# Insertion order = display order. Slugs are derived from names. +# Examples whose `[tool.flet.gallery].categories` reference a path not +# in this file will be skipped at scan time. + +categories: + Featured: + _icon: star + _description: Featured examples and demos + 7GUIs: + + Getting Started: + _icon: rocket_launch + _description: Quick-start examples and tutorials + Declarative: + + Layout: + _icon: dashboard + _description: Layout primitives and containers + Card: + Column: + Container: + Control: + CupertinoListTile: + DataTable: + DataTable2: + Dismissible: + Divider: + ExpansionPanelList: + ExpansionTile: + GridView: + LayoutControl: + ListTile: + ListView: + Pagelet: + PageView: + Placeholder: + ResponsiveRow: + RotatedBox: + Row: + SafeArea: + Stack: + Tabs: + VerticalDivider: + #WindowDragArea: + + Buttons: + _icon: smart_button + _description: Material and Cupertino buttons + Button: + FilledButton: + FilledTonalButton: + OutlinedButton: + TextButton: + IconButton: + FloatingActionButton: + MenuItemButton: + PopupMenuButton: + CupertinoButton: + CupertinoFilledButton: + CupertinoSegmentedButton: + CupertinoSlidingSegmentedButton: + + Input: + _icon: input + _description: Form controls and pickers + AutoComplete: + AutofillGroup: + Checkbox: + Chip: + CodeEditor: + ContextMenu: + Dropdown: + DropdownM2: + Radio: + RangeSlider: + Reorderable: + SearchBar: + SegmentedButton: + Slider: + Switch: + TextField: + TransparentPointer: + CupertinoCheckbox: + CupertinoContextMenu: + CupertinoDatePicker: + CupertinoPicker: + CupertinoRadio: + CupertinoSlider: + CupertinoSwitch: + CupertinoTextField: + CupertinoTimerPicker: + + Displays: + _icon: image + _description: Visual indicators and media displays + Badge: + Canvas: + CircleAvatar: + CupertinoActivityIndicator: + Icon: + Image: + Map: + Markdown: + ProgressBar: + ProgressRing: + Text: + Tooltip: + WebView: + + Dialogs: + _icon: chat_bubble_outline + _description: Modals, sheets, and notifications + AlertDialog: + Banner: + BottomSheet: + DatePicker: + DateRangePicker: + SnackBar: + TimePicker: + CupertinoActionSheet: + CupertinoAlertDialog: + + Navigation: + _icon: navigation + _description: AppBars, drawers, and routing + AppBar: + BottomAppBar: + Hero: + MenuBar: + NavigationBar: + NavigationDrawer: + NavigationRail: + Router: + Routing: + SubmenuButton: + Tabs: + CupertinoAppBar: + CupertinoNavigationBar: + + Charts: + _icon: bar_chart + _description: Plotting and data viz + BarChart: + CandlestickChart: + LineChart: + MatplotlibChart: + PieChart: + PlotlyChart: + RadarChart: + ScatterChart: + + Declarative: + _icon: code + _description: Examples of declarative UI style and patterns + + Games: + _icon: sports_esports + _description: Game examples and demos + + Animations: + _icon: animation + _description: Animation controls + Apps: + AnimatedSwitcher: + + Effects: + _icon: auto_awesome + _description: Visual effects and shaders + ShaderMask: + Shimmer: + + Media: + _icon: movie + _description: Audio, video, Lottie, Rive + Audio: # download audio to assets - CORS preventing from github + AudioRecorder: + Lottie: + Rive: + Video: + Camera: + + Accessibility: + _icon: accessibility + _description: Accessibility features and examples + + Utility: + _icon: build + _description: Gestures, drag/drop, screenshots + BrowserContextMenu: + Clipboard: # Clipboard files gives 404 on https://flet.app/api/gallery/apps/services/clipboard/files/package.zip?v=0, warn about Safari and iOS + Color pickers: + Connectivity: + Draggable: + FilePicker: + Flashlight: + GestureDetector: + InteractiveViewer: + Keyboard: + Localization: + Page: + PermissionHandler: + SecureStorage: + ScreenBrightness: + Screenshot: + SelectionArea: + Share: + SharedPreferences: + Storagepaths: + Types: + UrlLauncher: + Wakelock: + Window: + + Sensors: + _icon: sensors + _description: Device sensors and hardware features + Accelerometer: + Barometer: + Battery: + Geolocator: # Geolocator.request_permission() got an unexpected keyword argument 'timeout' + Gyroscope: + HapticFeedback: + Magnetometer: + ShakeDetector: + UserAccelerometer: + + Marketing: + _icon: campaign + _description: Examples of marketing and monetization features + Ads: + InAppPurchase: + + Tools: + _icon: handyman + _description: Development tools and utilities + + Cookbook: + _icon: interests + _description: Recipes and patterns for common app features + + Community: + _icon: people + _description: Examples contributed by the community diff --git a/sdk/python/examples/publish-gallery.sh b/sdk/python/examples/publish-gallery.sh new file mode 100644 index 0000000000..dd6e97bb0b --- /dev/null +++ b/sdk/python/examples/publish-gallery.sh @@ -0,0 +1,12 @@ +flet --version +DIST_PATH=$PWD/dist +flet publish apps/todo/basic/main.py --distpath $DIST_PATH/todo --base-url todo --app-name "Flet To-Do" --app-description "A classic To-Do app inspired by TodoMVC project." +flet publish apps/icons_browser/main.py --distpath $DIST_PATH/icons_browser --base-url icons_browser --app-name "Flet Icons Browser" --app-description "Quickly search through icons collection to use in your app." +flet publish tutorials/calculator/calc.py --distpath $DIST_PATH/calculator --base-url calculator --app-name "Calculator" --app-description "A simple calculator app written in Flet." +flet publish tutorials/solitaire_declarative/solitaire-final/main.py --distpath $DIST_PATH/solitaire --base-url solitaire --assets assets --app-name "Solitaire" --app-description "Learn how to handle gestures and position controls on a page." +flet publish apps/declarative/trolli/main.py --distpath $DIST_PATH/trolli --base-url trolli --assets assets --route-url-strategy "hash" --app-name "Trolli" --app-description "A clone of Trello." +flet publish apps/routing_navigation/home_store/main.py --distpath $DIST_PATH/simple_routing --base-url simple_routing --route-url-strategy "hash" --app-name "Flet routing example" --app-description "An example of routing in Flet." +flet publish apps/counter/basic/main.py --distpath $DIST_PATH/counter --base-url counter --app-name "Counter" --app-description "Counter to get an idea of Flet." +flet publish apps/flet_animation/main.py --distpath $DIST_PATH/flet_animation --base-url flet_animation --app-name "Flet animation" --app-description "An example of implicit animations in Flet." +flet publish apps/greeter/basic/main.py --distpath $DIST_PATH/greeter --base-url greeter --app-name "Greeter" --app-description "A basic example of interactive forms in Flet." +flet publish apps/hello_world/basic/main.py --distpath $DIST_PATH/hello_world --base-url hello_world --app-name "Hello, world!" --app-description "A very minimal example of Flet app." diff --git a/sdk/python/examples/pyproject.toml b/sdk/python/examples/pyproject.toml new file mode 100644 index 0000000000..656b859cd6 --- /dev/null +++ b/sdk/python/examples/pyproject.toml @@ -0,0 +1,39 @@ +[project] +name = "flet-examples" +version = "0.1.0" +description = "Sample apps for Flet" +license = "Apache-2.0" +readme = "README.md" +requires-python = ">=3.10,<3.15" +dependencies = [ + "flet", + "flet-contrib", +] + +[dependency-groups] +dev = [ + "flet[all]", + "matplotlib", + "mplfinance", + "pandas", + "plotly" +] + +[build-system] +requires = ["setuptools>=68", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["."] +include = [ + "apps", + "apps.*", + "controls", + "controls.*", + "cookbook", + "cookbook.*", + "services", + "services.*", + "tutorials", + "tutorials.*", +] diff --git a/sdk/python/examples/services/accelerometer/basic/main.py b/sdk/python/examples/services/accelerometer/basic/main.py new file mode 100644 index 0000000000..3e2a60a515 --- /dev/null +++ b/sdk/python/examples/services/accelerometer/basic/main.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_reading(e: ft.AccelerometerReadingEvent): + reading.value = f"x={e.x:.2f} m/s^2, y={e.y:.2f} m/s^2, z={e.z:.2f} m/s^2" + + def handle_error(e: ft.SensorErrorEvent): + page.add(ft.Text(f"Accelerometer error: {e.message}")) + + page.services.append( + ft.Accelerometer( + on_reading=handle_reading, + on_error=handle_error, + interval=ft.Duration(milliseconds=100), + cancel_on_error=False, + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Move your device to see accelerometer readings."), + reading := ft.Text("Waiting for data..."), + ] + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/accelerometer/basic/pyproject.toml b/sdk/python/examples/services/accelerometer/basic/pyproject.toml new file mode 100644 index 0000000000..0e14dad58a --- /dev/null +++ b/sdk/python/examples/services/accelerometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-accelerometer-basic" +version = "1.0.0" +description = "Streams live accelerometer readings and displays sensor errors from the device." +requires-python = ">=3.10" +keywords = ["services", "accelerometer", "sensor", "device", "readings"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/Accelerometer"] + +[tool.flet.metadata] +title = "Basic accelerometer" +controls = ["SafeArea", "Column", "Text", "Accelerometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/barometer/basic/main.py b/sdk/python/examples/services/barometer/basic/main.py new file mode 100644 index 0000000000..36fd76ff3a --- /dev/null +++ b/sdk/python/examples/services/barometer/basic/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_reading(e: ft.BarometerReadingEvent): + reading.value = f"{e.pressure:.2f} hPa" + + def handle_error(e: ft.SensorErrorEvent): + page.add(ft.Text(f"Barometer error: {e.message}")) + + page.services.append( + ft.Barometer( + on_reading=handle_reading, + on_error=handle_error, + interval=ft.Duration(milliseconds=500), + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Atmospheric pressure (hPa)."), + reading := ft.Text("Waiting for data..."), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/barometer/basic/pyproject.toml b/sdk/python/examples/services/barometer/basic/pyproject.toml new file mode 100644 index 0000000000..e27a1ad3ef --- /dev/null +++ b/sdk/python/examples/services/barometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-barometer-basic" +version = "1.0.0" +description = "Streams atmospheric pressure readings and reports barometer errors from the device sensor." +requires-python = ">=3.10" +keywords = ["barometer", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/Barometer"] + +[tool.flet.metadata] +title = "Basic barometer" +controls = ["SafeArea", "Column", "Page", "BarometerReadingEvent", "Text", "Barometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/battery/basic/main.py b/sdk/python/examples/services/battery/basic/main.py new file mode 100644 index 0000000000..53816b5a4d --- /dev/null +++ b/sdk/python/examples/services/battery/basic/main.py @@ -0,0 +1,40 @@ +import flet as ft + + +async def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + async def refresh_info(e: ft.Event[ft.Button] = None): + level = await battery.get_battery_level() + state = await battery.get_battery_state() + save_mode = await battery.is_in_battery_save_mode() + info.value = ( + f"Battery level: {level}% \n" + f"Battery state: {state.name} \n" + f"Battery saver: {'ON' if save_mode else 'OFF'}" + ) + + async def on_state_change(e: ft.BatteryStateChangeEvent): + print(f"State changed: {e.state}") + await refresh_info() + + battery = ft.Battery(on_state_change=on_state_change) + page.services.append(battery) # need to keep a reference to the service + + page.add( + ft.SafeArea( + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + info := ft.Text(), + ft.Button("Refresh battery info", on_click=refresh_info), + ], + ) + ) + ) + await refresh_info() + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/battery/basic/pyproject.toml b/sdk/python/examples/services/battery/basic/pyproject.toml new file mode 100644 index 0000000000..4e614481a0 --- /dev/null +++ b/sdk/python/examples/services/battery/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-battery-basic" +version = "1.0.0" +description = "Shows battery level, battery state, and battery saver status with a refresh action." +requires-python = ">=3.10" +keywords = ["battery", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/Battery"] + +[tool.flet.metadata] +title = "Basic battery" +controls = ["SafeArea", "Column", "Page", "Button", "Battery", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["battery state", "battery saver status"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios", "windows", "linux", "macos"] diff --git a/sdk/python/examples/services/browsercontextmenu/basic/main.py b/sdk/python/examples/services/browsercontextmenu/basic/main.py new file mode 100644 index 0000000000..0956cf47ca --- /dev/null +++ b/sdk/python/examples/services/browsercontextmenu/basic/main.py @@ -0,0 +1,39 @@ +# +# Run this example as a web app using the command: +# +# flet run --web main.py +# + + +import flet as ft + + +async def main(page: ft.Page): + bcm = ft.BrowserContextMenu() + + async def disable_context_menu(): + await bcm.disable() + + async def enable_context_menu(): + await bcm.enable() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + "Disable browser context menu", + on_click=disable_context_menu, + ), + ft.Button( + "Enable browser context menu", + on_click=enable_context_menu, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml b/sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml new file mode 100644 index 0000000000..648c584428 --- /dev/null +++ b/sdk/python/examples/services/browsercontextmenu/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-browsercontextmenu-basic" +version = "1.0.0" +description = "Enables and disables the browser context menu from a simple web control panel." +requires-python = ">=3.10" +keywords = ["browsercontextmenu", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/BrowserContextMenu"] + +[tool.flet.metadata] +title = "Basic browser context menu" +controls = ["SafeArea", "Column", "Page", "BrowserContextMenu", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["web context menu toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/services/clipboard/files/main.py b/sdk/python/examples/services/clipboard/files/main.py new file mode 100644 index 0000000000..cbef745747 --- /dev/null +++ b/sdk/python/examples/services/clipboard/files/main.py @@ -0,0 +1,107 @@ +import os +import subprocess +import sys +import tempfile +from pathlib import Path + +import flet as ft + + +def open_file(_, path: str): + """Open a desktop file in the default application.""" + if os.path.isfile(path): + if sys.platform == "darwin": # macOS + subprocess.run(["open", path]) + elif sys.platform == "win32": # Windows + os.startfile(path) + else: # Linux / BSD + subprocess.run(["xdg-open", path]) + + +async def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + # supported-platform checkers + supports_set_files = not page.web and page.platform.is_desktop() + supports_get_files = not page.web and ( + page.platform.is_desktop() or page.platform == ft.PagePlatform.ANDROID + ) + + def get_sample_files() -> list[str]: + # create temporary files + sample_dir = Path(tempfile.gettempdir()) / "flet_clipboard_files_example" + sample_dir.mkdir(parents=True, exist_ok=True) + sample_files = [ + sample_dir / "sample_1.txt", + sample_dir / "sample_2.txt", + ] + sample_files[0].write_text("Clipboard sample file #1\n", encoding="utf-8") + sample_files[1].write_text("Clipboard sample file #2\n", encoding="utf-8") + return [str(p) for p in sample_files] + + async def set_files_to_clipboard(e: ft.Event[ft.Button]): + files = get_sample_files() + ok = await ft.Clipboard().set_files(files) + status.value = ( + f"Set {len(files)} file references to clipboard (result: {ok})." + if ok + else "Failed to set file references to clipboard." + ) + + async def get_files_from_clipboard(e: ft.Event[ft.Button]): + files = await ft.Clipboard().get_files() + if files: + files_lv.controls = [ + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text(f, selectable=True), + ft.IconButton( + icon=ft.Icons.OPEN_IN_NEW, + icon_size=15, + on_click=lambda e, f=f: open_file(e, f), + tooltip="Open file", + ), + ], + ) + for f in files + ] + else: + files_lv.controls = [] + status.value = f"Read {len(files)} file reference(s) from clipboard." + + page.add( + ft.SafeArea( + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + "Set example files to clipboard", + on_click=set_files_to_clipboard, + disabled=not supports_set_files, + tooltip="Supported on desktop platforms only." + if not supports_set_files + else None, + ), + ft.Button( + "Get files from clipboard", + on_click=get_files_from_clipboard, + disabled=not supports_get_files, + tooltip="Supported on Android and desktop platforms only." + if not supports_get_files + else None, + ), + status := ft.Text(), + files_lv := ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=0, + controls=[], + ), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/clipboard/files/pyproject.toml b/sdk/python/examples/services/clipboard/files/pyproject.toml new file mode 100644 index 0000000000..8d55519e84 --- /dev/null +++ b/sdk/python/examples/services/clipboard/files/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-clipboard-files" +version = "1.0.0" +description = "Writes sample file references to the clipboard and reads clipboard file entries back." +requires-python = ">=3.10" +keywords = ["clipboard", "files", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Clipboard"] + +[tool.flet.metadata] +title = "Clipboard files" +controls = ["SafeArea", "Column", "Page", "Button", "Clipboard", "Row", "Text", "IconButton"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["clipboard file references", "desktop file open"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/clipboard/images/main.py b/sdk/python/examples/services/clipboard/images/main.py new file mode 100644 index 0000000000..8f544359ba --- /dev/null +++ b/sdk/python/examples/services/clipboard/images/main.py @@ -0,0 +1,56 @@ +import base64 + +import flet as ft + +SAMPLE_PNG = base64.b64decode( + "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" +) + + +async def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + async def set_image_to_clipboard(e: ft.Event[ft.Button]): + await ft.Clipboard().set_image(SAMPLE_PNG) + status.value = f"Sample image copied to clipboard ({len(SAMPLE_PNG)} bytes)." + preview.content = ft.Image(src=SAMPLE_PNG) + + async def get_image_from_clipboard(e: ft.Event[ft.Button]): + clipboard_image = await ft.Clipboard().get_image() + if clipboard_image is None: + status.value = "No image found in clipboard." + preview.content = None + return + else: + preview.content = ft.Image(src=clipboard_image) + status.value = ( + f"Image loaded from clipboard ({len(clipboard_image)} bytes)." + ) + + page.add( + ft.SafeArea( + ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Button( + "Set example image to clipboard", + on_click=set_image_to_clipboard, + disabled=not (page.web or page.platform.is_mobile()), + tooltip="Supported on mobile platforms only." + if not (page.web or page.platform.is_mobile()) + else None, + ), + ft.Button( + "Get image from clipboard", + on_click=get_image_from_clipboard, + ), + status := ft.Text(), + preview := ft.Container(width=360, height=240), + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/clipboard/images/pyproject.toml b/sdk/python/examples/services/clipboard/images/pyproject.toml new file mode 100644 index 0000000000..d9d8d5aefa --- /dev/null +++ b/sdk/python/examples/services/clipboard/images/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-clipboard-images" +version = "1.0.0" +description = "Copies a sample image to the clipboard and previews image data loaded from the clipboard." +requires-python = ">=3.10" +keywords = ["clipboard", "images", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Clipboard"] + +[tool.flet.metadata] +title = "Clipboard images" +controls = ["SafeArea", "Column", "Page", "Button", "Clipboard", "Image", "Text", "Container"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["copy image", "clipboard image preview"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/clipboard/text/main.py b/sdk/python/examples/services/clipboard/text/main.py new file mode 100644 index 0000000000..a2113c092f --- /dev/null +++ b/sdk/python/examples/services/clipboard/text/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +async def main(page: ft.Page): + async def set_to_clipboard(): + await ft.Clipboard().set(text_to_copy.value) + text_to_copy.value = "" + page.show_dialog(ft.SnackBar("Text copied to clipboard")) + + async def get_from_clipboard(): + contents = await ft.Clipboard().get() + page.add(ft.Text(f"Clipboard contents: {contents}")) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + controls=[ + text_to_copy := ft.TextField(label="Text to copy"), + ft.Button("Set to clipboard", on_click=set_to_clipboard), + ft.Button( + "Get from clipboard", on_click=get_from_clipboard + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/clipboard/text/pyproject.toml b/sdk/python/examples/services/clipboard/text/pyproject.toml new file mode 100644 index 0000000000..7d3a552b4f --- /dev/null +++ b/sdk/python/examples/services/clipboard/text/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-clipboard-text" +version = "1.0.0" +description = "Copies text to the clipboard and reads the current clipboard text back into the app." +requires-python = ">=3.10" +keywords = ["clipboard", "text", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Clipboard"] + +[tool.flet.metadata] +title = "Clipboard text" +controls = ["SafeArea", "Column", "Page", "Clipboard", "Text", "TextField", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["copy text", "read clipboard"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/connectivity/basic/main.py b/sdk/python/examples/services/connectivity/basic/main.py new file mode 100644 index 0000000000..f7314d8ca3 --- /dev/null +++ b/sdk/python/examples/services/connectivity/basic/main.py @@ -0,0 +1,42 @@ +import flet as ft + + +async def main(page: ft.Page): + connectivity = ft.Connectivity() + + status = ft.Text() + changes = ft.Text() + + async def refresh(_=None): + results = await connectivity.get_connectivity() + status.value = "Current connectivity: " + ", ".join(r.value for r in results) + + async def on_change(e: ft.ConnectivityChangeEvent): + changes.value = "Connectivity changed: " + ", ".join( + r.value for r in e.connectivity + ) + await refresh() + + connectivity.on_change = on_change + + await refresh() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + status, + ft.Button("Refresh connectivity", on_click=refresh), + changes, + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/connectivity/basic/pyproject.toml b/sdk/python/examples/services/connectivity/basic/pyproject.toml new file mode 100644 index 0000000000..2cc81a1b1a --- /dev/null +++ b/sdk/python/examples/services/connectivity/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-connectivity-basic" +version = "1.0.0" +description = "Displays current connectivity state and listens for connectivity change events." +requires-python = ">=3.10" +keywords = ["connectivity", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Connectivity"] + +[tool.flet.metadata] +title = "Basic connectivity" +controls = ["SafeArea", "Column", "Page", "Connectivity", "Text", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["connectivity status", "change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/file_picker/media/pick_and_upload.png b/sdk/python/examples/services/file_picker/media/pick_and_upload.png new file mode 100644 index 0000000000..97ee09aa86 Binary files /dev/null and b/sdk/python/examples/services/file_picker/media/pick_and_upload.png differ diff --git a/sdk/python/examples/services/file_picker/media/pick_save_and_get_directory_path.png b/sdk/python/examples/services/file_picker/media/pick_save_and_get_directory_path.png new file mode 100644 index 0000000000..db9661a752 Binary files /dev/null and b/sdk/python/examples/services/file_picker/media/pick_save_and_get_directory_path.png differ diff --git a/sdk/python/examples/services/file_picker/pick_and_save_text_content/main.py b/sdk/python/examples/services/file_picker/pick_and_save_text_content/main.py new file mode 100644 index 0000000000..5109eb7369 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_and_save_text_content/main.py @@ -0,0 +1,82 @@ +# +# Example of picking and saving text content with FilePicker. +# +# Run this example with: +# uv run flet run --web main.py +# +import flet as ft + + +def main(page: ft.Page): + selected_file_name = ft.Text("No file selected") + selected_file_content = ft.TextField( + label="Selected file content", + multiline=True, + min_lines=8, + max_lines=14, + ) + save_status = ft.Text() + + async def pick_text_file(_: ft.Event[ft.Button]): + files = await ft.FilePicker().pick_files( + allow_multiple=False, + with_data=True, + file_type=ft.FilePickerFileType.CUSTOM, + allowed_extensions=["txt", "md"], + ) + if not files: + selected_file_name.value = "Selection cancelled" + selected_file_content.value = "" + return + + selected = files[0] + selected_file_name.value = f"Selected: {selected.name} ({selected.size} bytes)" + selected_file_content.value = ( + selected.bytes.decode("utf-8", errors="replace") if selected.bytes else "" + ) + save_status.value = "" + + async def save_text_file(_: ft.Event[ft.Button]): + file_name = "flet_text_content.txt" + file_path = await ft.FilePicker().save_file( + file_name=file_name, + file_type=ft.FilePickerFileType.CUSTOM, + allowed_extensions=["txt"], + src_bytes=selected_file_content.value.encode("utf-8"), + ) + if page.web: + save_status.value = f"Downloaded as {file_name}" + else: + save_status.value = ( + f"Saved to: {file_path}" if file_path else "Save cancelled" + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Pick a .txt/.md file and load its text from " + "FilePickerFile.bytes" + ), + ft.Button( + content="Pick text file", + icon=ft.Icons.UPLOAD_FILE, + on_click=pick_text_file, + ), + selected_file_name, + selected_file_content, + ft.Button( + content="Save / Download text", + icon=ft.Icons.DOWNLOAD, + on_click=save_text_file, + ), + save_status, + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml b/sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml new file mode 100644 index 0000000000..e52072d1e4 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_and_save_text_content/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-file-picker-pick-and-save-text-content" +version = "1.0.0" +description = "Loads text file contents from picked files and saves or downloads edited text output." +requires-python = ">=3.10" +keywords = ["file picker", "pick and save text content", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/FilePicker"] + +[tool.flet.metadata] +title = "Pick and save text content" +controls = ["SafeArea", "Column", "Page", "Text", "TextField", "Button", "FilePicker"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["file picking", "save to file"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/file_picker/pick_and_upload/main.py b/sdk/python/examples/services/file_picker/pick_and_upload/main.py new file mode 100644 index 0000000000..a521cca52d --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_and_upload/main.py @@ -0,0 +1,99 @@ +# +# Example of picking and uploading files with progress indication +# +# Run this example with: +# export FLET_SECRET_KEY= +# uv run flet run --web examples/services/file_picker/pick_and_upload/main.py +# +from dataclasses import dataclass, field + +import flet as ft + + +@dataclass +class State: + file_picker: ft.FilePicker | None = None + picked_files: list[ft.FilePickerFile] = field(default_factory=list) + + +state = State() + + +def main(page: ft.Page): + if not page.web: + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "This example is only available in Flet Web mode.\n" + "\n" + "Run this example with:\n" + " export FLET_SECRET_KEY=\n" + " flet run --web " + "examples/services/file_picker/pick_and_upload/main.py", + color=ft.Colors.RED, + selectable=True, + ) + ], + ), + ) + ) + return + + prog_bars: dict[str, ft.ProgressRing] = {} + + def on_upload_progress(e: ft.FilePickerUploadEvent): + prog_bars[e.file_name].value = e.progress + + async def handle_files_pick(e: ft.Event[ft.Button]): + state.file_picker = ft.FilePicker(on_upload=on_upload_progress) + files = await state.file_picker.pick_files(allow_multiple=True) + print("Picked files:", files) + state.picked_files = files + + # update progress bars + upload_button.disabled = len(files) == 0 + prog_bars.clear() + upload_progress.controls.clear() + for f in files: + prog = ft.ProgressRing(value=0, bgcolor="#eeeeee", width=20, height=20) + prog_bars[f.name] = prog + upload_progress.controls.append(ft.Row([prog, ft.Text(f.name)])) + + async def handle_file_upload(e: ft.Event[ft.Button]): + upload_button.disabled = True + await state.file_picker.upload( + files=[ + ft.FilePickerUploadFile( + name=file.name, + upload_url=page.get_upload_url(f"dir/{file.name}", 60), + ) + for file in state.picked_files + ] + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button( + content="Select files...", + icon=ft.Icons.FOLDER_OPEN, + on_click=handle_files_pick, + ), + upload_progress := ft.Column(), + upload_button := ft.Button( + content="Upload", + icon=ft.Icons.UPLOAD, + on_click=handle_file_upload, + disabled=True, + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main, upload_dir="examples") diff --git a/sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml b/sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml new file mode 100644 index 0000000000..b6ff387f77 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_and_upload/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-file-picker-pick-and-upload" +version = "1.0.0" +description = "Picks multiple files in web mode and uploads them with live progress indicators." +requires-python = ">=3.10" +keywords = ["file picker", "pick and upload", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/FilePicker"] + +[tool.flet.metadata] +title = "Pick and upload files" +controls = ["SafeArea", "Column", "FilePicker", "FilePickerFile", "Page", "Text", "ProgressRing", "FilePickerUploadEvent"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["file upload", "upload progress"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["web"] diff --git a/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py new file mode 100644 index 0000000000..855604f2b9 --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/main.py @@ -0,0 +1,60 @@ +import flet as ft + + +def main(page: ft.Page): + async def handle_pick_files(e: ft.Event[ft.Button]): + files = await ft.FilePicker().pick_files(allow_multiple=True) + selected_files.value = ( + ", ".join(map(lambda f: f.name, files)) if files else "Cancelled!" + ) + + async def handle_save_file(e: ft.Event[ft.Button]): + save_file_path.value = await ft.FilePicker().save_file() + + async def handle_get_directory_path(e: ft.Event[ft.Button]): + directory_path.value = await ft.FilePicker().get_directory_path() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Row( + controls=[ + ft.Button( + content="Pick files", + icon=ft.Icons.UPLOAD_FILE, + on_click=handle_pick_files, + ), + selected_files := ft.Text(), + ] + ), + ft.Row( + controls=[ + ft.Button( + content="Save file", + icon=ft.Icons.SAVE, + on_click=handle_save_file, + disabled=page.web, # disable this button in web mode + ), + save_file_path := ft.Text(), + ] + ), + ft.Row( + controls=[ + ft.Button( + content="Open directory", + icon=ft.Icons.FOLDER_OPEN, + on_click=handle_get_directory_path, + disabled=page.web, # disable this button in web mode + ), + directory_path := ft.Text(), + ] + ), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml new file mode 100644 index 0000000000..788b4e313a --- /dev/null +++ b/sdk/python/examples/services/file_picker/pick_save_and_get_directory_path/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-file-picker-pick-save-and-get-directory-path" +version = "1.0.0" +description = "Demonstrates file picking, save dialogs, and directory selection in one example." +requires-python = ">=3.10" +keywords = ["file picker", "pick save and get directory path", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/FilePicker"] + +[tool.flet.metadata] +title = "Pick, save, and browse directories" +controls = ["SafeArea", "Column", "Page", "Button", "FilePicker", "Row", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["file picking", "save dialog", "directory picker"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/gyroscope/basic/main.py b/sdk/python/examples/services/gyroscope/basic/main.py new file mode 100644 index 0000000000..9221e246cd --- /dev/null +++ b/sdk/python/examples/services/gyroscope/basic/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_reading(e: ft.GyroscopeReadingEvent): + reading.value = f"x={e.x:.2f} rad/s, y={e.y:.2f} rad/s, z={e.z:.2f} rad/s" + + def handle_error(e: ft.SensorErrorEvent): + page.add(ft.Text(f"Gyroscope error: {e.message}")) + + page.services.append( + ft.Gyroscope( + on_reading=handle_reading, + on_error=handle_error, + interval=ft.Duration(milliseconds=100), + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Rotate your device to see gyroscope readings."), + reading := ft.Text("Waiting for data..."), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/gyroscope/basic/pyproject.toml b/sdk/python/examples/services/gyroscope/basic/pyproject.toml new file mode 100644 index 0000000000..43625bb4b4 --- /dev/null +++ b/sdk/python/examples/services/gyroscope/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-gyroscope-basic" +version = "1.0.0" +description = "Streams gyroscope rotation readings and reports sensor errors from supported devices." +requires-python = ">=3.10" +keywords = ["gyroscope", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/Gyroscope"] + +[tool.flet.metadata] +title = "Basic gyroscope" +controls = ["SafeArea", "Column", "Page", "GyroscopeReadingEvent", "Text", "Gyroscope"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/haptic_feedback/basic/main.py b/sdk/python/examples/services/haptic_feedback/basic/main.py new file mode 100644 index 0000000000..1c5654e46e --- /dev/null +++ b/sdk/python/examples/services/haptic_feedback/basic/main.py @@ -0,0 +1,34 @@ +import flet as ft + + +def main(page: ft.Page): + hf = ft.HapticFeedback() + + async def heavy_impact(): + await hf.heavy_impact() + + async def medium_impact(): + await hf.medium_impact() + + async def light_impact(): + await hf.light_impact() + + async def vibrate(): + await hf.vibrate() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Button("Heavy impact", on_click=heavy_impact), + ft.Button("Medium impact", on_click=medium_impact), + ft.Button("Light impact", on_click=light_impact), + ft.Button("Vibrate", on_click=vibrate), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/haptic_feedback/basic/pyproject.toml b/sdk/python/examples/services/haptic_feedback/basic/pyproject.toml new file mode 100644 index 0000000000..80da16d74f --- /dev/null +++ b/sdk/python/examples/services/haptic_feedback/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-haptic-feedback-basic" +version = "1.0.0" +description = "Triggers heavy, medium, light, and vibration haptic feedback actions." +requires-python = ">=3.10" +keywords = ["haptic feedback", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/HapticFeedback"] + +[tool.flet.metadata] +title = "Basic haptic feedback" +controls = ["SafeArea", "Column", "Page", "HapticFeedback", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["haptic feedback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/magnetometer/basic/main.py b/sdk/python/examples/services/magnetometer/basic/main.py new file mode 100644 index 0000000000..06241d144e --- /dev/null +++ b/sdk/python/examples/services/magnetometer/basic/main.py @@ -0,0 +1,32 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_reading(e: ft.MagnetometerReadingEvent): + reading.value = f"x={e.x:.2f} uT, y={e.y:.2f} uT, z={e.z:.2f} uT" + + def handle_error(e: ft.SensorErrorEvent): + page.add(ft.Text(f"Magnetometer error: {e.message}")) + + page.services.append( + ft.Magnetometer( + on_reading=handle_reading, + on_error=handle_error, + interval=ft.Duration(milliseconds=200), + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text("Monitor the ambient magnetic field (uT)."), + reading := ft.Text("Waiting for data..."), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/magnetometer/basic/pyproject.toml b/sdk/python/examples/services/magnetometer/basic/pyproject.toml new file mode 100644 index 0000000000..4c82b6ce68 --- /dev/null +++ b/sdk/python/examples/services/magnetometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-magnetometer-basic" +version = "1.0.0" +description = "Streams ambient magnetic field readings and reports magnetometer errors." +requires-python = ">=3.10" +keywords = ["magnetometer", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/Magnetometer"] + +[tool.flet.metadata] +title = "Basic magnetometer" +controls = ["SafeArea", "Column", "Page", "MagnetometerReadingEvent", "Text", "Magnetometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/screen_brightness/basic/main.py b/sdk/python/examples/services/screen_brightness/basic/main.py new file mode 100644 index 0000000000..d02d36cfb3 --- /dev/null +++ b/sdk/python/examples/services/screen_brightness/basic/main.py @@ -0,0 +1,109 @@ +import flet as ft + + +async def main(page: ft.Page): + sb = ft.ScreenBrightness() + page.services.append(sb) + + info = ft.Text() + system_change = ft.Text() + app_change = ft.Text() + + level = ft.Slider(min=0, max=1, divisions=20, value=0.5, label="Brightness") + animate_switch = ft.Switch( + label="Animate application changes", value=True, on_change=None + ) + auto_reset_switch = ft.Switch( + label="Auto-reset application brightness on lifecycle changes", + value=True, + on_change=None, + ) + + async def refresh_info(): + system_brightness = await sb.get_system_screen_brightness() + app_brightness = await sb.get_application_screen_brightness() + can_change_system = await sb.can_change_system_screen_brightness() + + animate_switch.value = await sb.is_animate() + auto_reset_switch.value = await sb.is_auto_reset() + + info.value = ( + f"System: {system_brightness:.2f} | " + f"Application: {app_brightness:.2f} | " + f"Can change system: {can_change_system}" + ) + + async def set_application_brightness(_): + await sb.set_application_screen_brightness(level.value) + await refresh_info() + + async def set_system_brightness(_): + await sb.set_system_screen_brightness(level.value) + await refresh_info() + + async def reset_application_brightness(_): + await sb.reset_application_screen_brightness() + await refresh_info() + + async def toggle_animate(e: ft.Event[ft.Switch]): + await sb.set_animate(e.control.value) + await refresh_info() + + async def toggle_auto_reset(e: ft.Event[ft.Switch]): + await sb.set_auto_reset(e.control.value) + await refresh_info() + + async def on_system_change(e: ft.ScreenBrightnessChangeEvent): + system_change.value = f"System brightness changed: {e.brightness:.2f}" + + async def on_application_change(e: ft.ScreenBrightnessChangeEvent): + app_change.value = f"Application brightness changed: {e.brightness:.2f}" + + sb.on_system_screen_brightness_change = on_system_change + sb.on_application_screen_brightness_change = on_application_change + + await refresh_info() + + animate_switch.on_change = toggle_animate + auto_reset_switch.on_change = toggle_auto_reset + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + info, + level, + ft.Row( + [ + ft.Button( + "Set application", + on_click=set_application_brightness, + ), + ft.Button( + "Set system", on_click=set_system_brightness + ), + ft.TextButton( + "Reset application", + on_click=reset_application_brightness, + ), + ], + wrap=True, + ), + animate_switch, + auto_reset_switch, + ft.Divider(), + system_change, + app_change, + ], + spacing=12, + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/screen_brightness/basic/pyproject.toml b/sdk/python/examples/services/screen_brightness/basic/pyproject.toml new file mode 100644 index 0000000000..c8ca35e686 --- /dev/null +++ b/sdk/python/examples/services/screen_brightness/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-screen-brightness-basic" +version = "1.0.0" +description = "Reads and adjusts system and application brightness with live change notifications." +requires-python = ">=3.10" +keywords = ["screen brightness", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/ScreenBrightness"] + +[tool.flet.metadata] +title = "Basic screen brightness" +controls = ["SafeArea", "Column", "Page", "ScreenBrightness", "Text", "Slider", "Switch", "Row"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["brightness control", "change events"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/semantics_service/accessibility_features/main.py b/sdk/python/examples/services/semantics_service/accessibility_features/main.py new file mode 100644 index 0000000000..768bf9f44b --- /dev/null +++ b/sdk/python/examples/services/semantics_service/accessibility_features/main.py @@ -0,0 +1,40 @@ +import flet as ft + + +async def main(page: ft.Page): + page.title = "SemanticsService - Accessibility features" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + async def get_features() -> str: + features = await ft.SemanticsService().get_accessibility_features() + return "\n".join( + [ + f"Accessible navigation: {features.accessible_navigation}", + f"Bold text: {features.bold_text}", + f"Disable animations: {features.disable_animations}", + f"High contrast: {features.high_contrast}", + f"Invert colors: {features.invert_colors}", + f"Reduce motion: {features.reduce_motion}", + f"On/off switch labels: {features.on_off_switch_labels}", + f"Supports announcements: {features.supports_announcements}", + ] + ) + + async def refresh_features(e: ft.Event[ft.Button]): + info.value = await get_features() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + info := ft.Text(await get_features()), + ft.Button("Refresh features", on_click=refresh_features), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml b/sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml new file mode 100644 index 0000000000..e1aee6fd14 --- /dev/null +++ b/sdk/python/examples/services/semantics_service/accessibility_features/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-semantics-service-accessibility-features" +version = "1.0.0" +description = "Reads accessibility feature flags from SemanticsService and refreshes them on demand." +requires-python = ">=3.10" +keywords = ["semantics service", "accessibility features", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Accessibility"] + +[tool.flet.metadata] +title = "Accessibility features" +controls = ["SafeArea", "Column", "Page", "SemanticsService", "Button", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["accessibility features"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/shake_detector/basic/main.py b/sdk/python/examples/services/shake_detector/basic/main.py new file mode 100644 index 0000000000..eb4b47ecc5 --- /dev/null +++ b/sdk/python/examples/services/shake_detector/basic/main.py @@ -0,0 +1,24 @@ +import flet as ft + + +def main(page: ft.Page): + page.services.append( + ft.ShakeDetector( + minimum_shake_count=2, + shake_slop_time_ms=300, + shake_count_reset_time_ms=1000, + on_shake=lambda _: page.add(ft.Text("Shake detected!")), + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Text("Shake your device!")], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/shake_detector/basic/pyproject.toml b/sdk/python/examples/services/shake_detector/basic/pyproject.toml new file mode 100644 index 0000000000..bfa6d08543 --- /dev/null +++ b/sdk/python/examples/services/shake_detector/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-shake-detector-basic" +version = "1.0.0" +description = "Detects shake gestures and appends a message each time a shake is recognized." +requires-python = ">=3.10" +keywords = ["shake detector", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/ShakeDetector"] + +[tool.flet.metadata] +title = "Basic shake detector" +controls = ["SafeArea", "Column", "Page", "ShakeDetector", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["shake detection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/share/basic/main.py b/sdk/python/examples/services/share/basic/main.py new file mode 100644 index 0000000000..56a339d125 --- /dev/null +++ b/sdk/python/examples/services/share/basic/main.py @@ -0,0 +1,84 @@ +import os + +import flet as ft + + +async def main(page: ft.Page): + share = ft.Share() + + status = ft.Text() + result_raw = ft.Text() + + async def do_share_text(): + result = await share.share_text( + "Hello from Flet!", + subject="Greeting", + title="Share greeting", + ) + status.value = f"Share status: {result.status}" + result_raw.value = f"Raw: {result.raw}" + + async def do_share_uri(): + result = await share.share_uri("https://flet.dev") + status.value = f"Share status: {result.status}" + result_raw.value = f"Raw: {result.raw}" + + async def do_share_files_from_bytes(): + file = ft.ShareFile.from_bytes( + b"Sample content from memory", + mime_type="text/plain", + name="sample.txt", + ) + result = await share.share_files( + [file], + text="Sharing a file from memory", + ) + status.value = f"Share status: {result.status}" + result_raw.value = f"Raw: {result.raw}" + + async def do_share_files_from_paths(): + if page.web: + status.value = "File sharing from paths is not supported on the web." + return + # + temp_dir = await ft.StoragePaths().get_temporary_directory() + file_path = os.path.join(temp_dir, "sample_from_path.txt") + with open(file_path, "wb") as f: + f.write(b"Sample content from file path") + + result = await share.share_files( + [ft.ShareFile.from_path(file_path)], + text="Sharing a file from memory", + ) + status.value = f"Share status: {result.status}" + result_raw.value = f"Raw: {result.raw}" + + page.add( + ft.SafeArea( + ft.Column( + [ + ft.Row( + [ + ft.Button("Share text", on_click=do_share_text), + ft.Button("Share link", on_click=do_share_uri), + ft.Button( + "Share file from bytes", + on_click=do_share_files_from_bytes, + ), + ft.Button( + "Share file from path", + on_click=do_share_files_from_paths, + ), + ], + wrap=True, + ), + status, + result_raw, + ], + ) + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/share/basic/pyproject.toml b/sdk/python/examples/services/share/basic/pyproject.toml new file mode 100644 index 0000000000..6b38b5f7a0 --- /dev/null +++ b/sdk/python/examples/services/share/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-share-basic" +version = "1.0.0" +description = "Shares text, links, and files while showing the raw share result status." +requires-python = ">=3.10" +keywords = ["share", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Share"] + +[tool.flet.metadata] +title = "Basic share" +controls = ["SafeArea", "Column", "Page", "Share", "Text", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["share sheet", "file sharing"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/sharedpreferences/basic/main.py b/sdk/python/examples/services/sharedpreferences/basic/main.py new file mode 100644 index 0000000000..89f93cb338 --- /dev/null +++ b/sdk/python/examples/services/sharedpreferences/basic/main.py @@ -0,0 +1,44 @@ +import flet as ft + + +async def main(page: ft.Page): + async def set_value(): + await ft.SharedPreferences().set(store_key.value, store_value.value) + get_key.value = store_key.value + store_key.value = "" + store_value.value = "" + page.show_dialog(ft.SnackBar("Value saved to SharedPreferences")) + + async def get_value(): + contents = await ft.SharedPreferences().get(get_key.value) + page.add(ft.Text(f"SharedPreferences contents: {contents}")) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + ft.Row( + [ + store_key := ft.TextField(label="Key"), + store_value := ft.TextField(label="Value"), + ft.Button("Set", on_click=set_value), + ] + ), + ft.Row( + [ + get_key := ft.TextField(label="Key"), + ft.Button("Get", on_click=get_value), + ] + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/sharedpreferences/basic/pyproject.toml b/sdk/python/examples/services/sharedpreferences/basic/pyproject.toml new file mode 100644 index 0000000000..aa9c465860 --- /dev/null +++ b/sdk/python/examples/services/sharedpreferences/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-sharedpreferences-basic" +version = "1.0.0" +description = "Writes and reads plain SharedPreferences values using keyed inputs." +requires-python = ">=3.10" +keywords = ["sharedpreferences", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/SharedPreferences"] + +[tool.flet.metadata] +title = "Basic shared preferences" +controls = ["SafeArea", "Column", "Page", "SharedPreferences", "Text", "Row", "TextField", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["key-value storage"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/storagepaths/basic/main.py b/sdk/python/examples/services/storagepaths/basic/main.py new file mode 100644 index 0000000000..2ceacefd62 --- /dev/null +++ b/sdk/python/examples/services/storagepaths/basic/main.py @@ -0,0 +1,62 @@ +import flet as ft + + +async def main(page: ft.Page): + storage_paths = ft.StoragePaths() + + items = [] + for label, method in [ + ("Application cache directory", storage_paths.get_application_cache_directory), + ( + "Application documents directory", + storage_paths.get_application_documents_directory, + ), + ( + "Application support directory", + storage_paths.get_application_support_directory, + ), + ("Downloads directory", storage_paths.get_downloads_directory), + ("External cache directories", storage_paths.get_external_cache_directories), + ( + "External storage directories", + storage_paths.get_external_storage_directories, + ), + ("Library directory", storage_paths.get_library_directory), + ("External storage directory", storage_paths.get_external_storage_directory), + ("Temporary directory", storage_paths.get_temporary_directory), + ("Console log filename", storage_paths.get_console_log_filename), + ]: + try: + value = await method() + except ft.FletUnsupportedPlatformException as e: + value = f"Not supported: {e}" + except Exception as e: + value = f"Error: {e}" + else: + if isinstance(value, list): + value = ", ".join(value) + elif value is None: + value = "Unavailable" + + items.append( + ft.Text( + spans=[ + ft.TextSpan( + f"{label}: ", style=ft.TextStyle(weight=ft.FontWeight.BOLD) + ), + ft.TextSpan(value), + ] + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ft.Column(items, spacing=5)], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/storagepaths/basic/pyproject.toml b/sdk/python/examples/services/storagepaths/basic/pyproject.toml new file mode 100644 index 0000000000..8bc8689720 --- /dev/null +++ b/sdk/python/examples/services/storagepaths/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-storagepaths-basic" +version = "1.0.0" +description = "Lists storage path APIs and shows unsupported-path errors on the current platform." +requires-python = ">=3.10" +keywords = ["storagepaths", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Storagepaths"] + +[tool.flet.metadata] +title = "Basic storage paths" +controls = ["SafeArea", "Column", "Page", "Text"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["path discovery", "platform fallback"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/urllauncher/basic/main.py b/sdk/python/examples/services/urllauncher/basic/main.py new file mode 100644 index 0000000000..87a65e52e7 --- /dev/null +++ b/sdk/python/examples/services/urllauncher/basic/main.py @@ -0,0 +1,96 @@ +import flet as ft + + +async def main(page: ft.Page): + url_launcher = ft.UrlLauncher() + + url = ft.TextField(label="URL to open", value="https://flet.dev", expand=True) + status = ft.Text() + + async def can_launch(): + can = await url_launcher.can_launch_url(url.value) + status.value = f"Can launch: {can}" + + async def launch_default(): + await url_launcher.launch_url(url.value) + + async def launch_in_app_webview(): + await url_launcher.launch_url( + url.value, + mode=ft.LaunchMode.IN_APP_WEB_VIEW, + web_view_configuration=ft.WebViewConfiguration( + enable_javascript=True, enable_dom_storage=True + ), + ) + + async def launch_in_app_browser_view(): + await url_launcher.launch_url( + url.value, + mode=ft.LaunchMode.IN_APP_BROWSER_VIEW, + browser_configuration=ft.BrowserConfiguration(show_title=True), + ) + + async def launch_external(): + await url_launcher.launch_url( + url.value, + mode=ft.LaunchMode.EXTERNAL_APPLICATION, + web_only_window_name="_blank", + ) + + async def launch_popup(): + await url_launcher.open_window( + url.value, title="Flet popup", width=480, height=640 + ) + + async def close_webview(_): + supported = await url_launcher.supports_close_for_launch_mode( + ft.LaunchMode.IN_APP_WEB_VIEW + ) + if supported: + await url_launcher.close_in_app_web_view() + else: + status.value = "Close in-app web view not supported on this platform" + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + url, + ft.Row( + [ + ft.Button("Launch URL", on_click=launch_default), + ft.Button( + "Launch in-app webview", + on_click=launch_in_app_webview, + ), + ft.Button( + "Launch in-app browser view", + on_click=launch_in_app_browser_view, + ), + ft.Button( + "Launch external/new tab", + on_click=launch_external, + ), + ft.Button( + "Open popup window (web)", on_click=launch_popup + ), + ft.Button("Can launch?", on_click=can_launch), + ft.Button( + "Close in-app webview", on_click=close_webview + ), + ], + wrap=True, + ), + status, + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/urllauncher/basic/pyproject.toml b/sdk/python/examples/services/urllauncher/basic/pyproject.toml new file mode 100644 index 0000000000..d3043316bd --- /dev/null +++ b/sdk/python/examples/services/urllauncher/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-urllauncher-basic" +version = "1.0.0" +description = "Launches URLs in multiple modes including web view, browser view, and popup windows." +requires-python = ">=3.10" +keywords = ["urllauncher", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/UrlLauncher", "Navigation/Routing"] + +[tool.flet.metadata] +title = "Basic URL launcher" +controls = ["SafeArea", "Column", "Page", "UrlLauncher", "TextField", "Text", "LaunchMode", "WebViewConfiguration"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["URL launch modes", "popup window"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/services/user_accelerometer/basic/main.py b/sdk/python/examples/services/user_accelerometer/basic/main.py new file mode 100644 index 0000000000..e95fd81062 --- /dev/null +++ b/sdk/python/examples/services/user_accelerometer/basic/main.py @@ -0,0 +1,35 @@ +import flet as ft + + +def main(page: ft.Page): + def handle_reading(e: ft.UserAccelerometerReadingEvent): + reading.value = f"x={e.x:.2f} m/s^2, y={e.y:.2f} m/s^2, z={e.z:.2f} m/s^2" + + def handle_error(e: ft.SensorErrorEvent): + page.add(ft.Text(f"UserAccelerometer error: {e.message}")) + + page.services.append( + ft.UserAccelerometer( + on_reading=handle_reading, + on_error=handle_error, + interval=ft.Duration(milliseconds=100), + ) + ) + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Text( + "Linear acceleration without gravity. " + "Keep the app running on a device with motion sensors." + ), + reading := ft.Text("Waiting for data..."), + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/user_accelerometer/basic/pyproject.toml b/sdk/python/examples/services/user_accelerometer/basic/pyproject.toml new file mode 100644 index 0000000000..7300bce705 --- /dev/null +++ b/sdk/python/examples/services/user_accelerometer/basic/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "services-user-accelerometer-basic" +version = "1.0.0" +description = "Streams linear acceleration readings without gravity and reports sensor errors." +requires-python = ">=3.10" +keywords = ["user accelerometer", "basic", "services"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Sensors/UserAccelerometer"] + +[tool.flet.metadata] +title = "Basic user accelerometer" +controls = ["SafeArea", "Column", "Page", "UserAccelerometerReadingEvent", "Text", "UserAccelerometer"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["live sensor readings", "sensor error handling"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" +platforms = ["android", "ios"] diff --git a/sdk/python/examples/services/wakelock/basic/main.py b/sdk/python/examples/services/wakelock/basic/main.py new file mode 100644 index 0000000000..bff1d937d5 --- /dev/null +++ b/sdk/python/examples/services/wakelock/basic/main.py @@ -0,0 +1,48 @@ +import flet as ft + + +async def main(page: ft.Page): + wakelock = ft.Wakelock() + + status = ft.Text() + + async def update_status(): + enabled = await wakelock.is_enabled() + status.value = f"Wakelock enabled: {enabled}" + + async def enable_lock(): + await wakelock.enable() + await update_status() + + async def disable_lock(): + await wakelock.disable() + await update_status() + + await update_status() + + page.add( + ft.SafeArea( + content=ft.Column( + controls=[ + ft.Column( + [ + status, + ft.Row( + [ + ft.Button("Enable wakelock", on_click=enable_lock), + ft.Button( + "Disable wakelock", on_click=disable_lock + ), + ], + wrap=True, + ), + ], + ) + ], + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/services/wakelock/basic/pyproject.toml b/sdk/python/examples/services/wakelock/basic/pyproject.toml new file mode 100644 index 0000000000..fe08430e86 --- /dev/null +++ b/sdk/python/examples/services/wakelock/basic/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "services-wakelock-basic" +version = "1.0.0" +description = "Enables and disables wakelock while showing the current wakelock state." +requires-python = ">=3.10" +keywords = ["wakelock", "basic", "services", "async"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Utility/Wakelock"] + +[tool.flet.metadata] +title = "Basic wakelock" +controls = ["SafeArea", "Column", "Page", "Wakelock", "Text", "Row", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["wakelock toggle"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/tutorials/calculator/Dockerfile b/sdk/python/examples/tutorials/calculator/Dockerfile new file mode 100644 index 0000000000..0cf132eb0f --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3-alpine + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8080 + +CMD ["python", "./calc.py"] diff --git a/sdk/python/examples/tutorials/calculator/__init__.py b/sdk/python/examples/tutorials/calculator/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/examples/tutorials/calculator/calc.py b/sdk/python/examples/tutorials/calculator/calc.py new file mode 100644 index 0000000000..f699fead6a --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/calc.py @@ -0,0 +1,172 @@ +from dataclasses import field + +import flet as ft + + +@ft.control +class CalcButton(ft.Button): + expand: int = field(default_factory=lambda: 1) + + +@ft.control +class DigitButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.WHITE_24 + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.ORANGE + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ExtraActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + color: ft.Colors = ft.Colors.BLACK + + +@ft.control +class CalculatorApp(ft.Container): + def init(self): + self.reset() + self.width = 350 + self.bgcolor = ft.Colors.BLACK + self.border_radius = ft.BorderRadius.all(20) + self.padding = 20 + self.result = ft.Text(value="0", color=ft.Colors.WHITE, size=20) + + self.content = ft.Column( + controls=[ + ft.Row( + controls=[self.result], + alignment=ft.MainAxisAlignment.END, + ), + ft.Row( + controls=[ + ExtraActionButton(content="AC", on_click=self.button_clicked), + ExtraActionButton(content="+/-", on_click=self.button_clicked), + ExtraActionButton(content="%", on_click=self.button_clicked), + ActionButton(content="/", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="7", on_click=self.button_clicked), + DigitButton(content="8", on_click=self.button_clicked), + DigitButton(content="9", on_click=self.button_clicked), + ActionButton(content="*", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="4", on_click=self.button_clicked), + DigitButton(content="5", on_click=self.button_clicked), + DigitButton(content="6", on_click=self.button_clicked), + ActionButton(content="-", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="1", on_click=self.button_clicked), + DigitButton(content="2", on_click=self.button_clicked), + DigitButton(content="3", on_click=self.button_clicked), + ActionButton(content="+", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton( + content="0", expand=2, on_click=self.button_clicked + ), + DigitButton(content=".", on_click=self.button_clicked), + ActionButton(content="=", on_click=self.button_clicked), + ] + ), + ] + ) + + def button_clicked(self, e): + data = e.control.content + print(f"Button clicked with data = {data}") + if self.result.value == "Error" or data == "AC": + self.result.value = "0" + self.reset() + + elif data in ("1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "."): + if self.result.value == "0" or self.new_operand: + self.result.value = data + self.new_operand = False + else: + self.result.value = self.result.value + data + + elif data in ("+", "-", "*", "/"): + self.result.value = self.calculate( + self.operand1, float(self.result.value), self.operator + ) + self.operator = data + if self.result.value == "Error": + self.operand1 = "0" + else: + self.operand1 = float(self.result.value) + self.new_operand = True + + elif data in ("="): + self.result.value = self.calculate( + self.operand1, float(self.result.value), self.operator + ) + self.reset() + + elif data in ("%"): + self.result.value = float(self.result.value) / 100 + self.reset() + + elif data in ("+/-"): + if float(self.result.value) > 0: + self.result.value = "-" + str(self.result.value) + + elif float(self.result.value) < 0: + self.result.value = str( + self.format_number(abs(float(self.result.value))) + ) + + self.update() + + def format_number(self, num): + if num % 1 == 0: + return int(num) + else: + return num + + def calculate(self, operand1, operand2, operator): + if operator == "+": + return self.format_number(operand1 + operand2) + + elif operator == "-": + return self.format_number(operand1 - operand2) + + elif operator == "*": + return self.format_number(operand1 * operand2) + + elif operator == "/": + if operand2 == 0: + return "Error" + else: + return self.format_number(operand1 / operand2) + + def reset(self): + self.operator = "+" + self.operand1 = 0 + self.new_operand = True + + +def main(page: ft.Page): + page.title = "Calc App" + # create application instance + calc = CalculatorApp() + + # add application's root control to the page + page.add(calc) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/calculator/calc1.py b/sdk/python/examples/tutorials/calculator/calc1.py new file mode 100644 index 0000000000..df8c33d47f --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/calc1.py @@ -0,0 +1,33 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Calc App" + result = ft.Text(value="0") + + page.add( + result, + ft.Button("AC"), + ft.Button("+/-"), + ft.Button("%"), + ft.Button("/"), + ft.Button("7"), + ft.Button("8"), + ft.Button("9"), + ft.Button("*"), + ft.Button("4"), + ft.Button("5"), + ft.Button("6"), + ft.Button("-"), + ft.Button("1"), + ft.Button("2"), + ft.Button("3"), + ft.Button("+"), + ft.Button("0"), + ft.Button("."), + ft.Button("="), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/tutorials/calculator/calc2.py b/sdk/python/examples/tutorials/calculator/calc2.py new file mode 100644 index 0000000000..f32bf0113f --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/calc2.py @@ -0,0 +1,53 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Calc App" + result = ft.Text(value="0") + + page.add( + ft.Row(controls=[result]), + ft.Row( + controls=[ + ft.Button("AC"), + ft.Button("+/-"), + ft.Button("%"), + ft.Button("/"), + ] + ), + ft.Row( + controls=[ + ft.Button("7"), + ft.Button("8"), + ft.Button("9"), + ft.Button("*"), + ] + ), + ft.Row( + controls=[ + ft.Button("4"), + ft.Button("5"), + ft.Button("6"), + ft.Button("-"), + ] + ), + ft.Row( + controls=[ + ft.Button("1"), + ft.Button("2"), + ft.Button("3"), + ft.Button("+"), + ] + ), + ft.Row( + controls=[ + ft.Button("0"), + ft.Button("."), + ft.Button("="), + ] + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/tutorials/calculator/calc3.py b/sdk/python/examples/tutorials/calculator/calc3.py new file mode 100644 index 0000000000..90dd4ddf24 --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/calc3.py @@ -0,0 +1,84 @@ +from dataclasses import field + +import flet as ft + + +def main(page: ft.Page): + page.title = "Calc App" + result = ft.Text(value="0", color=ft.Colors.WHITE, size=20) + + @ft.control + class CalcButton(ft.Button): + expand: int = field(default_factory=lambda: 1) + + @ft.control + class DigitButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.WHITE_24 + color: ft.Colors = ft.Colors.WHITE + + @ft.control + class ActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.ORANGE + color: ft.Colors = ft.Colors.WHITE + + @ft.control + class ExtraActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + color: ft.Colors = ft.Colors.BLACK + + page.add( + ft.Container( + width=350, + bgcolor=ft.Colors.BLACK, + border_radius=ft.BorderRadius.all(20), + padding=20, + content=ft.Column( + controls=[ + ft.Row(controls=[result], alignment=ft.MainAxisAlignment.END), + ft.Row( + controls=[ + ExtraActionButton(content="AC"), + ExtraActionButton(content="+/-"), + ExtraActionButton(content="%"), + ActionButton(content="/"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="7"), + DigitButton(content="8"), + DigitButton(content="9"), + ActionButton(content="*"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="4"), + DigitButton(content="5"), + DigitButton(content="6"), + ActionButton(content="-"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="1"), + DigitButton(content="2"), + DigitButton(content="3"), + ActionButton(content="+"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="0", expand=2), + DigitButton(content="."), + ActionButton(content="="), + ], + ), + ] + ), + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/examples/tutorials/calculator/calc4.py b/sdk/python/examples/tutorials/calculator/calc4.py new file mode 100644 index 0000000000..5808f29681 --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/calc4.py @@ -0,0 +1,95 @@ +from dataclasses import field + +import flet as ft + + +@ft.control +class CalcButton(ft.Button): + expand: int = field(default_factory=lambda: 1) + + +@ft.control +class DigitButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.WHITE_24 + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.ORANGE + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ExtraActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + color: ft.Colors = ft.Colors.BLACK + + +@ft.control +class CalculatorApp(ft.Container): + def init(self): + self.width = 350 + self.bgcolor = ft.Colors.BLACK + self.border_radius = ft.BorderRadius.all(20) + self.padding = 20 + self.result = ft.Text(value="0", color=ft.Colors.WHITE, size=20) + self.content = ft.Column( + controls=[ + ft.Row( + controls=[self.result], + alignment=ft.MainAxisAlignment.END, + ), + ft.Row( + controls=[ + ExtraActionButton(content="AC"), + ExtraActionButton(content="+/-"), + ExtraActionButton(content="%"), + ActionButton(content="/"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="7"), + DigitButton(content="8"), + DigitButton(content="9"), + ActionButton(content="*"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="4"), + DigitButton(content="5"), + DigitButton(content="6"), + ActionButton(content="-"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="1"), + DigitButton(content="2"), + DigitButton(content="3"), + ActionButton(content="+"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="0", expand=2), + DigitButton(content="."), + ActionButton(content="="), + ] + ), + ] + ) + + +def main(page: ft.Page): + page.title = "Calc App" + # create application instance + calc = CalculatorApp() + + # add application's root control to the page + page.add(calc) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/calculator/calc5.py b/sdk/python/examples/tutorials/calculator/calc5.py new file mode 100644 index 0000000000..f699fead6a --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/calc5.py @@ -0,0 +1,172 @@ +from dataclasses import field + +import flet as ft + + +@ft.control +class CalcButton(ft.Button): + expand: int = field(default_factory=lambda: 1) + + +@ft.control +class DigitButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.WHITE_24 + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.ORANGE + color: ft.Colors = ft.Colors.WHITE + + +@ft.control +class ExtraActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + color: ft.Colors = ft.Colors.BLACK + + +@ft.control +class CalculatorApp(ft.Container): + def init(self): + self.reset() + self.width = 350 + self.bgcolor = ft.Colors.BLACK + self.border_radius = ft.BorderRadius.all(20) + self.padding = 20 + self.result = ft.Text(value="0", color=ft.Colors.WHITE, size=20) + + self.content = ft.Column( + controls=[ + ft.Row( + controls=[self.result], + alignment=ft.MainAxisAlignment.END, + ), + ft.Row( + controls=[ + ExtraActionButton(content="AC", on_click=self.button_clicked), + ExtraActionButton(content="+/-", on_click=self.button_clicked), + ExtraActionButton(content="%", on_click=self.button_clicked), + ActionButton(content="/", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="7", on_click=self.button_clicked), + DigitButton(content="8", on_click=self.button_clicked), + DigitButton(content="9", on_click=self.button_clicked), + ActionButton(content="*", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="4", on_click=self.button_clicked), + DigitButton(content="5", on_click=self.button_clicked), + DigitButton(content="6", on_click=self.button_clicked), + ActionButton(content="-", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton(content="1", on_click=self.button_clicked), + DigitButton(content="2", on_click=self.button_clicked), + DigitButton(content="3", on_click=self.button_clicked), + ActionButton(content="+", on_click=self.button_clicked), + ] + ), + ft.Row( + controls=[ + DigitButton( + content="0", expand=2, on_click=self.button_clicked + ), + DigitButton(content=".", on_click=self.button_clicked), + ActionButton(content="=", on_click=self.button_clicked), + ] + ), + ] + ) + + def button_clicked(self, e): + data = e.control.content + print(f"Button clicked with data = {data}") + if self.result.value == "Error" or data == "AC": + self.result.value = "0" + self.reset() + + elif data in ("1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "."): + if self.result.value == "0" or self.new_operand: + self.result.value = data + self.new_operand = False + else: + self.result.value = self.result.value + data + + elif data in ("+", "-", "*", "/"): + self.result.value = self.calculate( + self.operand1, float(self.result.value), self.operator + ) + self.operator = data + if self.result.value == "Error": + self.operand1 = "0" + else: + self.operand1 = float(self.result.value) + self.new_operand = True + + elif data in ("="): + self.result.value = self.calculate( + self.operand1, float(self.result.value), self.operator + ) + self.reset() + + elif data in ("%"): + self.result.value = float(self.result.value) / 100 + self.reset() + + elif data in ("+/-"): + if float(self.result.value) > 0: + self.result.value = "-" + str(self.result.value) + + elif float(self.result.value) < 0: + self.result.value = str( + self.format_number(abs(float(self.result.value))) + ) + + self.update() + + def format_number(self, num): + if num % 1 == 0: + return int(num) + else: + return num + + def calculate(self, operand1, operand2, operator): + if operator == "+": + return self.format_number(operand1 + operand2) + + elif operator == "-": + return self.format_number(operand1 - operand2) + + elif operator == "*": + return self.format_number(operand1 * operand2) + + elif operator == "/": + if operand2 == 0: + return "Error" + else: + return self.format_number(operand1 / operand2) + + def reset(self): + self.operator = "+" + self.operand1 = 0 + self.new_operand = True + + +def main(page: ft.Page): + page.title = "Calc App" + # create application instance + calc = CalculatorApp() + + # add application's root control to the page + page.add(calc) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/calculator/fly.toml b/sdk/python/examples/tutorials/calculator/fly.toml new file mode 100644 index 0000000000..b3e5764295 --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/fly.toml @@ -0,0 +1,40 @@ +app = "flet-calc" + +kill_signal = "SIGINT" +kill_timeout = 5 +processes = [] + +[env] + FLET_SERVER_PORT = "8080" + FLET_FORCE_WEB_SERVER = "true" + +[experimental] + allowed_public_ports = [] + auto_rollback = true + +[[services]] + http_checks = [] + internal_port = 8080 + processes = ["app"] + protocol = "tcp" + script_checks = [] + + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + type = "connections" + + [[services.ports]] + force_https = true + handlers = ["http"] + port = 80 + + [[services.ports]] + handlers = ["tls", "http"] + port = 443 + + [[services.tcp_checks]] + grace_period = "1s" + interval = "15s" + restart_limit = 0 + timeout = "2s" diff --git a/sdk/python/examples/tutorials/calculator/media/app-1.png b/sdk/python/examples/tutorials/calculator/media/app-1.png new file mode 100644 index 0000000000..9f82b83b64 Binary files /dev/null and b/sdk/python/examples/tutorials/calculator/media/app-1.png differ diff --git a/sdk/python/examples/tutorials/calculator/media/app-2.png b/sdk/python/examples/tutorials/calculator/media/app-2.png new file mode 100644 index 0000000000..3642abede7 Binary files /dev/null and b/sdk/python/examples/tutorials/calculator/media/app-2.png differ diff --git a/sdk/python/examples/tutorials/calculator/media/app.gif b/sdk/python/examples/tutorials/calculator/media/app.gif new file mode 100644 index 0000000000..b3b09e7e3c Binary files /dev/null and b/sdk/python/examples/tutorials/calculator/media/app.gif differ diff --git a/sdk/python/examples/tutorials/calculator/media/app.png b/sdk/python/examples/tutorials/calculator/media/app.png new file mode 100644 index 0000000000..5acebb1fe1 Binary files /dev/null and b/sdk/python/examples/tutorials/calculator/media/app.png differ diff --git a/sdk/python/examples/tutorials/calculator/media/container-layout.png b/sdk/python/examples/tutorials/calculator/media/container-layout.png new file mode 100644 index 0000000000..12d84173e0 Binary files /dev/null and b/sdk/python/examples/tutorials/calculator/media/container-layout.png differ diff --git a/sdk/python/examples/tutorials/calculator/media/container-layout.svg b/sdk/python/examples/tutorials/calculator/media/container-layout.svg new file mode 100644 index 0000000000..18916ffe6b --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/media/container-layout.svg @@ -0,0 +1,4 @@ + + + +
Text
Container decorates the Column with rounded border, black background color and padding.
Column contains the row with the Text and 5 rows with buttons.
AC
+/-
Row with Text control. Row aligment is set to "end" for its child controls (Text) to be aligned to the right.
%
/
7
8
9
*
4
5
6
-
1
2
3
+
0
.
=
Expand = 1 is used for each button in the row to expand them within the row equally (in proportion 1:1:1:1).
Expand = 2 is used for "0" button and expand = 1 for "." and "=" buttons to expand them in proportion 2:1:1 within the row.
\ No newline at end of file diff --git a/sdk/python/examples/tutorials/calculator/media/phone-app.png b/sdk/python/examples/tutorials/calculator/media/phone-app.png new file mode 100644 index 0000000000..55c0003d11 Binary files /dev/null and b/sdk/python/examples/tutorials/calculator/media/phone-app.png differ diff --git a/sdk/python/examples/tutorials/calculator/pyproject.toml b/sdk/python/examples/tutorials/calculator/pyproject.toml new file mode 100644 index 0000000000..d9fa503ced --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/pyproject.toml @@ -0,0 +1,23 @@ +[project] +name = "tutorials-calculator" +version = "1.0.0" +description = "Builds an iOS-style calculator app with custom button controls and arithmetic operations." +requires-python = ">=3.10" +keywords = ["tutorials", "calculator", "productivity", "custom controls"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.metadata] +title = "Calculator" +controls = ["Container", "Column", "Row", "Text", "Button"] +layout_pattern = "center-stage" +complexity = "beginner" +features = ["custom controls", "arithmetic", "state management"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/tutorials/calculator/requirements.txt b/sdk/python/examples/tutorials/calculator/requirements.txt new file mode 100644 index 0000000000..9f5592458b --- /dev/null +++ b/sdk/python/examples/tutorials/calculator/requirements.txt @@ -0,0 +1 @@ +flet>=0.25.1 diff --git a/sdk/python/examples/tutorials/chat/Dockerfile b/sdk/python/examples/tutorials/chat/Dockerfile new file mode 100644 index 0000000000..02b838dc35 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3-alpine + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8000 + +CMD ["python", "chat.py"] diff --git a/sdk/python/examples/tutorials/chat/chat_1.py b/sdk/python/examples/tutorials/chat/chat_1.py new file mode 100644 index 0000000000..63f5959d56 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/chat_1.py @@ -0,0 +1,18 @@ +import flet as ft + + +def main(page: ft.Page): + chat = ft.Column() + new_message = ft.TextField() + + def send_click(e): + chat.controls.append(ft.Text(new_message.value)) + new_message.value = "" + + page.add( + chat, + ft.Row(controls=[new_message, ft.Button("Send", on_click=send_click)]), + ) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/chat/chat_2.py b/sdk/python/examples/tutorials/chat/chat_2.py new file mode 100644 index 0000000000..e74cdf9d78 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/chat_2.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +class Message: + user: str + text: str + + +def main(page: ft.Page): + chat = ft.Column() + new_message = ft.TextField() + + def on_message(message: Message): + chat.controls.append(ft.Text(f"{message.user}: {message.text}")) + page.update() + + page.pubsub.subscribe(on_message) + + def send_click(e): + page.pubsub.send_all(Message(user=page.session.id, text=new_message.value)) + new_message.value = "" + + page.add(chat, ft.Row([new_message, ft.Button("Send", on_click=send_click)])) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/chat/chat_3.py b/sdk/python/examples/tutorials/chat/chat_3.py new file mode 100644 index 0000000000..dc12500bdd --- /dev/null +++ b/sdk/python/examples/tutorials/chat/chat_3.py @@ -0,0 +1,69 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +class Message: + user: str + text: str + message_type: str + + +def main(page: ft.Page): + chat = ft.Column() + new_message = ft.TextField() + + def on_message(message: Message): + if message.message_type == "chat_message": + chat.controls.append(ft.Text(f"{message.user}: {message.text}")) + elif message.message_type == "login_message": + chat.controls.append( + ft.Text(message.text, italic=True, color=ft.Colors.BLACK_45, size=12) + ) + page.update() + + page.pubsub.subscribe(on_message) + + def send_click(e): + page.pubsub.send_all( + Message( + user=page.session.store.get("user_name"), + text=new_message.value, + message_type="chat_message", + ) + ) + new_message.value = "" + + user_name = ft.TextField(label="Enter your name") + + def join_click(e): + if not user_name.value: + user_name.error_text = "Name cannot be blank!" + else: + page.session.store.set("user_name", user_name.value) + # page.dialog.open = False + page.pop_dialog() + page.pubsub.send_all( + Message( + user=user_name.value, + text=f"{user_name.value} has joined the chat.", + message_type="login_message", + ) + ) + + page.show_dialog( + ft.AlertDialog( + open=True, + modal=True, + title=ft.Text("Welcome!"), + content=ft.Column([user_name], tight=True), + actions=[ft.Button(content="Join chat", on_click=join_click)], + actions_alignment=ft.MainAxisAlignment.END, + ) + ) + + page.add(chat, ft.Row([new_message, ft.Button("Send", on_click=send_click)])) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/chat/fly.toml b/sdk/python/examples/tutorials/chat/fly.toml new file mode 100644 index 0000000000..4800d5d839 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/fly.toml @@ -0,0 +1,20 @@ +app = "flet-chat" + +kill_signal = "SIGINT" +kill_timeout = 5 +processes = [] + +[env] + FLET_SESSION_TIMEOUT = "60" + +[http_service] + internal_port = 8000 + force_https = true + auto_stop_machines = true + auto_start_machines = true + min_machines_running = 0 + + [http_service.concurrency] + type = "connections" + soft_limit = 200 + hard_limit = 250 diff --git a/sdk/python/examples/tutorials/chat/main.py b/sdk/python/examples/tutorials/chat/main.py new file mode 100644 index 0000000000..532c26e01d --- /dev/null +++ b/sdk/python/examples/tutorials/chat/main.py @@ -0,0 +1,162 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +class Message: # noqa: B903 + user_name: str + text: str + message_type: str + + +@ft.control +class ChatMessage(ft.Row): + def __init__(self, message: Message): + super().__init__() + self.message = message + self.vertical_alignment = ft.CrossAxisAlignment.START + self.controls = [ + ft.CircleAvatar( + content=ft.Text(self.get_initials(self.message.user_name)), + color=ft.Colors.WHITE, + bgcolor=self.get_avatar_color(self.message.user_name), + ), + ft.Column( + tight=True, + spacing=5, + controls=[ + ft.Text(self.message.user_name, weight=ft.FontWeight.BOLD), + ft.Text(self.message.text, selectable=True), + ], + ), + ] + + def get_initials(self, user_name: str): + if user_name: + return user_name[:1].capitalize() + else: + return "Unknown" # or any default value you prefer + + def get_avatar_color(self, user_name: str): + colors_lookup = [ + ft.Colors.AMBER, + ft.Colors.BLUE, + ft.Colors.BROWN, + ft.Colors.CYAN, + ft.Colors.GREEN, + ft.Colors.INDIGO, + ft.Colors.LIME, + ft.Colors.ORANGE, + ft.Colors.PINK, + ft.Colors.PURPLE, + ft.Colors.RED, + ft.Colors.TEAL, + ft.Colors.YELLOW, + ] + return colors_lookup[hash(user_name) % len(colors_lookup)] + + +def main(page: ft.Page): + page.horizontal_alignment = ft.CrossAxisAlignment.STRETCH + page.title = "Flet Chat" + + def join_chat_click(e): + if not join_user_name.value: + join_user_name.error_text = "Name cannot be blank!" + join_user_name.update() + else: + page.session.store.set("user_name", join_user_name.value) + welcome_dlg.open = False + new_message.prefix = ft.Text(f"{join_user_name.value}: ") + page.pubsub.send_all( + Message( + user_name=join_user_name.value, + text=f"{join_user_name.value} has joined the chat.", + message_type="login_message", + ) + ) + + async def send_message_click(e): + if new_message.value != "": + page.pubsub.send_all( + Message( + page.session.store.get("user_name"), + new_message.value, + message_type="chat_message", + ) + ) + new_message.value = "" + await new_message.focus() + + def on_message(message: Message): + if message.message_type == "chat_message": + m = ChatMessage(message) + elif message.message_type == "login_message": + m = ft.Text( + message.text, italic=True, color=ft.Colors.ON_SURFACE_VARIANT, size=12 + ) + chat.controls.append(m) + page.update() + + page.pubsub.subscribe(on_message) + + # A dialog asking for a user display name + join_user_name = ft.TextField( + label="Enter your name to join the chat", + autofocus=True, + on_submit=join_chat_click, + ) + welcome_dlg = ft.AlertDialog( + open=True, + modal=True, + title=ft.Text("Welcome!"), + content=ft.Column([join_user_name], width=300, height=70, tight=True), + actions=[ft.Button(content="Join chat", on_click=join_chat_click)], + actions_alignment=ft.MainAxisAlignment.END, + ) + + page.overlay.append(welcome_dlg) + + # Chat messages + chat = ft.ListView( + expand=True, + spacing=10, + auto_scroll=True, + ) + + # A new message entry form + new_message = ft.TextField( + hint_text="Write a message...", + autofocus=True, + shift_enter=True, + min_lines=1, + max_lines=5, + filled=True, + expand=True, + on_submit=send_message_click, + ) + + # Add everything to the page + page.add( + ft.Container( + content=chat, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=5, + padding=10, + expand=True, + ), + ft.Row( + controls=[ + new_message, + ft.IconButton( + icon=ft.Icons.SEND_ROUNDED, + tooltip="Send message", + on_click=send_message_click, + ), + ] + ), + ) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/chat/media/chat-1.png b/sdk/python/examples/tutorials/chat/media/chat-1.png new file mode 100644 index 0000000000..e80da0f69a Binary files /dev/null and b/sdk/python/examples/tutorials/chat/media/chat-1.png differ diff --git a/sdk/python/examples/tutorials/chat/media/chat-2.gif b/sdk/python/examples/tutorials/chat/media/chat-2.gif new file mode 100644 index 0000000000..2c3037f482 Binary files /dev/null and b/sdk/python/examples/tutorials/chat/media/chat-2.gif differ diff --git a/sdk/python/examples/tutorials/chat/media/chat-3.gif b/sdk/python/examples/tutorials/chat/media/chat-3.gif new file mode 100644 index 0000000000..1bb6928abe Binary files /dev/null and b/sdk/python/examples/tutorials/chat/media/chat-3.gif differ diff --git a/sdk/python/examples/tutorials/chat/media/chat-4.png b/sdk/python/examples/tutorials/chat/media/chat-4.png new file mode 100644 index 0000000000..3b79b7ad06 Binary files /dev/null and b/sdk/python/examples/tutorials/chat/media/chat-4.png differ diff --git a/sdk/python/examples/tutorials/chat/media/chat.gif b/sdk/python/examples/tutorials/chat/media/chat.gif new file mode 100644 index 0000000000..b1fea20cc8 Binary files /dev/null and b/sdk/python/examples/tutorials/chat/media/chat.gif differ diff --git a/sdk/python/examples/tutorials/chat/media/layout-1.svg b/sdk/python/examples/tutorials/chat/media/layout-1.svg new file mode 100644 index 0000000000..ca4b447fa0 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/media/layout-1.svg @@ -0,0 +1,4 @@ + + + +
 TextField
Send
Button has "on_click" event that adds Text to chat.controls.
Text
Each Text control is an item in chat.controls list.
"chat" Column is a container for Text controls to show messages history vertically.
Text
"new_message" TextField is used for 
user input. 
Row is a container to show TextField and ElevatedButton horizontally.
\ No newline at end of file diff --git a/sdk/python/examples/tutorials/chat/media/layout-2.svg b/sdk/python/examples/tutorials/chat/media/layout-2.svg new file mode 100644 index 0000000000..6a2607580c --- /dev/null +++ b/sdk/python/examples/tutorials/chat/media/layout-2.svg @@ -0,0 +1,4 @@ + + + +
   TextField
   TextField
<
<
IconButton has "on_click" event that adds message to chat.controls
IconButton has "on_click" event that...
Each Text control is an item in chat.controls list showing "login_message"
Each Text control is an item in c...
"chat" is a ListView control which is recommended to use for scrollable lists of controls
"chat" is a ListView control which...
Text
Text
"new_message" TextField is used for user input 
"new_message" TextField is used for user inpu...
Row is a container to show "new_message" TextField and "send" IconButton horizontally
Row is a container to show "new_mes...
Container is used for decoration of "chat" ListView
Container is used for deco...
Page has 2 controls: Container and Row
Page has 2 controls: Container and Row
ChatMessage control
ChatMessage control
JS
JS
<User name> (Text)
<User name> (Text)
<message text> (Text)
<message text> (Text)
Text is not SVG - cannot display
diff --git a/sdk/python/examples/tutorials/chat/media/layout-chatmessage.svg b/sdk/python/examples/tutorials/chat/media/layout-chatmessage.svg new file mode 100644 index 0000000000..45d47ca946 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/media/layout-chatmessage.svg @@ -0,0 +1,4 @@ + + + +
J S
J S
 <user name> (Text control)
 <user name> (Text control)
<message text> (Text control)
<message text> (Text control)
CircleAvatar shows user name initials on a coloured background
CircleAvatar shows user name init...
ChatMessage is a Row containing CircleAvatar and Column
ChatMessage is a Row containing C...
Column with user name and message Texts
Column with user name and message...
Text is not SVG - cannot display
diff --git a/sdk/python/examples/tutorials/chat/media/username-dialog.png b/sdk/python/examples/tutorials/chat/media/username-dialog.png new file mode 100644 index 0000000000..7f81e68440 Binary files /dev/null and b/sdk/python/examples/tutorials/chat/media/username-dialog.png differ diff --git a/sdk/python/examples/tutorials/chat/requirements.txt b/sdk/python/examples/tutorials/chat/requirements.txt new file mode 100644 index 0000000000..8db06baba1 --- /dev/null +++ b/sdk/python/examples/tutorials/chat/requirements.txt @@ -0,0 +1 @@ +flet diff --git a/sdk/python/examples/tutorials/solitaire/media/drag-and-drop1.png b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop1.png new file mode 100644 index 0000000000..bb6aaf9728 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop1.png differ diff --git a/sdk/python/examples/tutorials/solitaire/media/drag-and-drop2.gif b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop2.gif new file mode 100644 index 0000000000..9a1b19fe2e Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop2.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/drag-and-drop3.gif b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop3.gif new file mode 100644 index 0000000000..c7070d9551 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop3.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/drag-and-drop4.gif b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop4.gif new file mode 100644 index 0000000000..4ba6056036 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop4.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/drag-and-drop5.gif b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop5.gif new file mode 100644 index 0000000000..7ed06fbb73 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop5.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/drag-and-drop6.gif b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop6.gif new file mode 100644 index 0000000000..972b918df4 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/drag-and-drop6.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/fanned-piles1.png b/sdk/python/examples/tutorials/solitaire/media/fanned-piles1.png new file mode 100644 index 0000000000..42f9ee8ec0 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/fanned-piles1.png differ diff --git a/sdk/python/examples/tutorials/solitaire/media/fanned-piles2.gif b/sdk/python/examples/tutorials/solitaire/media/fanned-piles2.gif new file mode 100644 index 0000000000..b907d3ec19 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/fanned-piles2.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/fanned-piles3.gif b/sdk/python/examples/tutorials/solitaire/media/fanned-piles3.gif new file mode 100644 index 0000000000..0f152a581b Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/fanned-piles3.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/game-rules1.gif b/sdk/python/examples/tutorials/solitaire/media/game-rules1.gif new file mode 100644 index 0000000000..03fafd9406 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/game-rules1.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/game-rules2.gif b/sdk/python/examples/tutorials/solitaire/media/game-rules2.gif new file mode 100644 index 0000000000..2023a33b53 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/game-rules2.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/game-setup-wiki.png b/sdk/python/examples/tutorials/solitaire/media/game-setup-wiki.png new file mode 100644 index 0000000000..c93d738436 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/game-setup-wiki.png differ diff --git a/sdk/python/examples/tutorials/solitaire/media/game-setup1.png b/sdk/python/examples/tutorials/solitaire/media/game-setup1.png new file mode 100644 index 0000000000..1380939de4 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/game-setup1.png differ diff --git a/sdk/python/examples/tutorials/solitaire/media/game-setup2.png b/sdk/python/examples/tutorials/solitaire/media/game-setup2.png new file mode 100644 index 0000000000..0235f9c7f9 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/game-setup2.png differ diff --git a/sdk/python/examples/tutorials/solitaire/media/game-setup3.png b/sdk/python/examples/tutorials/solitaire/media/game-setup3.png new file mode 100644 index 0000000000..a34ea36f15 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/game-setup3.png differ diff --git a/sdk/python/examples/tutorials/solitaire/media/part1-final.gif b/sdk/python/examples/tutorials/solitaire/media/part1-final.gif new file mode 100644 index 0000000000..f310f94762 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/part1-final.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/media/solitaire-layout.svg b/sdk/python/examples/tutorials/solitaire/media/solitaire-layout.svg new file mode 100644 index 0000000000..ae39e9404c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/media/solitaire-layout.svg @@ -0,0 +1,4 @@ + + + +

Solitaire layout

Stock pile
Foundation piles
Waste pile
Tableau (fanned piles)
(top=0, left=0)
(top=0, left=100)
(top=0, left=300)
(top=0, left=600)
(top=0, left=400)
(top=150, left=0)
(top=150, left=100)
(top=150, left=200)
(top=150, left=600)
Solitaire height = 500
Solitaire width = 1000
\ No newline at end of file diff --git a/sdk/python/examples/tutorials/solitaire/media/winning-the-game.gif b/sdk/python/examples/tutorials/solitaire/media/winning-the-game.gif new file mode 100644 index 0000000000..221c6ebfa0 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/media/winning-the-game.gif differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-classes/card.py b/sdk/python/examples/tutorials/solitaire/solitaire-classes/card.py new file mode 100644 index 0000000000..1cf4affb7d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-classes/card.py @@ -0,0 +1,63 @@ +CARD_WIDTH = 70 +CARD_HEIGHT = 100 +DROP_PROXIMITY = 20 + +import flet as ft + + +class Card(ft.GestureDetector): + def __init__(self, solitaire, color): + super().__init__() + self.slot = None + self.mouse_cursor = ft.MouseCursor.MOVE + self.drag_interval = 5 + self.on_pan_start = self.start_drag + self.on_pan_update = self.drag + self.on_pan_end = self.drop + self.left = None + self.top = None + self.solitaire = solitaire + self.color = color + self.content = ft.Container( + bgcolor=self.color, width=CARD_WIDTH, height=CARD_HEIGHT + ) + + def move_on_top(self): + """Moves draggable card to the top of the stack""" + self.solitaire.controls.remove(self) + self.solitaire.controls.append(self) + self.solitaire.update() + + def bounce_back(self): + """Returns card to its original position""" + self.top = self.slot.top + self.left = self.slot.left + self.update() + + def place(self, slot): + """Place card to the slot""" + self.top = slot.top + self.left = slot.left + self.slot = slot + + def start_drag(self, e: ft.DragStartEvent): + self.move_on_top() + self.update() + + def drag(self, e: ft.DragUpdateEvent): + self.top = max(0, self.top + e.local_delta.y) + self.left = max(0, self.left + e.local_delta.x) + self.update() + + def drop(self, e: ft.DragEndEvent): + for slot in self.solitaire.slots: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.update() + return + + self.bounce_back() + self.update() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-classes/main.py b/sdk/python/examples/tutorials/solitaire/solitaire-classes/main.py new file mode 100644 index 0000000000..bf09580328 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-classes/main.py @@ -0,0 +1,11 @@ +import flet as ft +from solitaire import Solitaire + + +def main(page: ft.Page): + solitaire = Solitaire() + + page.add(solitaire) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-classes/slot.py b/sdk/python/examples/tutorials/solitaire/solitaire-classes/slot.py new file mode 100644 index 0000000000..5a4caba256 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-classes/slot.py @@ -0,0 +1,15 @@ +import flet as ft + +SLOT_WIDTH = 70 +SLOT_HEIGHT = 100 + + +class Slot(ft.Container): + def __init__(self, top, left): + super().__init__() + self.pile = [] + self.width = SLOT_WIDTH + self.height = SLOT_HEIGHT + self.left = left + self.top = top + self.border = ft.Border.all(1) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-classes/solitaire.py b/sdk/python/examples/tutorials/solitaire/solitaire-classes/solitaire.py new file mode 100644 index 0000000000..20358cabc6 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-classes/solitaire.py @@ -0,0 +1,39 @@ +SOLITAIRE_WIDTH = 1000 +SOLITAIRE_HEIGHT = 500 + +import flet as ft +from card import Card +from slot import Slot + + +class Solitaire(ft.Stack): + def __init__(self): + super().__init__() + self.controls = [] + self.slots = [] + self.cards = [] + self.width = SOLITAIRE_WIDTH + self.height = SOLITAIRE_HEIGHT + + def did_mount(self): + self.create_card_deck() + self.create_slots() + self.deal_cards() + + def create_card_deck(self): + card1 = Card(self, color="GREEN") + card2 = Card(self, color="YELLOW") + self.cards = [card1, card2] + + def create_slots(self): + self.slots.append(Slot(top=0, left=0)) + self.slots.append(Slot(top=0, left=200)) + self.slots.append(Slot(top=0, left=300)) + self.controls.extend(self.slots) + self.update() + + def deal_cards(self): + self.controls.extend(self.cards) + for card in self.cards: + card.place(self.slots[0]) + self.update() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step1.py b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step1.py new file mode 100644 index 0000000000..f0aa8c55b1 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step1.py @@ -0,0 +1,25 @@ +import flet as ft + +# Use of GestureDetector for with on_pan_update event for dragging card +# Absolute positioning of controls within stack + + +def main(page: ft.Page): + def drag(e: ft.DragUpdateEvent): + e.control.top = max(0, e.control.top + e.local_delta.y) + e.control.left = max(0, e.control.left + e.local_delta.x) + e.control.update() + + card = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_update=drag, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), + ) + + page.add(ft.Stack(controls=[card], width=1000, height=500)) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step2.py b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step2.py new file mode 100644 index 0000000000..cf6a000887 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step2.py @@ -0,0 +1,62 @@ +import flet as ft + +# Using Container for slot where the card should be dropped +# on_pan_start event for the card: remember position of card to bounce it back on_pan_end of needed. +# on_pan_end: check if card is in proximity of the slot and either place it to the slot or return to original position (bounce back). +# Solitaire class created for holding original position coordinates + + +class Solitaire: + def __init__(self): + self.start_top = 0 + self.start_left = 0 + + +def main(page: ft.Page): + def place(card, slot): + """place card to the slot""" + card.top = slot.top + card.left = slot.left + + def bounce_back(game, card): + """return card to its original position""" + card.top = game.start_top + card.left = game.start_left + + def start_drag(e: ft.DragStartEvent): + solitaire.start_top = e.control.top + solitaire.start_left = e.control.left + + def drag(e: ft.DragUpdateEvent): + e.control.top = max(0, e.control.top + e.local_delta.y) + e.control.left = max(0, e.control.left + e.local_delta.x) + e.control.update() + + def drop(e: ft.DragEndEvent): + if abs(e.control.top - slot.top) < 20 and abs(e.control.left - slot.left) < 20: + place(e.control, slot) + + else: + bounce_back(solitaire, e.control) + + e.control.update() + + slot = ft.Container(width=70, height=100, left=200, top=0, border=ft.Border.all(1)) + + card = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=start_drag, + on_pan_update=drag, + on_pan_end=drop, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), + ) + + solitaire = Solitaire() + + page.add(ft.Stack(controls=[slot, card], width=1000, height=500)) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step3.py b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step3.py new file mode 100644 index 0000000000..265da8b4eb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step3.py @@ -0,0 +1,78 @@ +import flet as ft + +# Adding second card. Now the one of the cards will not be on top of stack when being dragged +# move_on_top function to move the card on top on_pan_start event + + +class Solitaire: + def __init__(self): + self.start_top = 0 + self.start_left = 0 + + +def main(page: ft.Page): + def place(card, slot): + """place card to the slot""" + card.top = slot.top + card.left = slot.left + + def bounce_back(game, card): + """return card to its original position""" + card.top = game.start_top + card.left = game.start_left + + def move_on_top(card, controls): + """Moves draggable card to the top of the stack""" + controls.remove(card) + controls.append(card) + page.update() + + def start_drag(e: ft.DragStartEvent): + move_on_top(e.control, controls) + solitaire.start_top = e.control.top + solitaire.start_left = e.control.left + + def drag(e: ft.DragUpdateEvent): + e.control.top = max(0, e.control.top + e.local_delta.y) + e.control.left = max(0, e.control.left + e.local_delta.x) + e.control.update() + + def drop(e: ft.DragEndEvent): + if abs(e.control.top - slot.top) < 20 and abs(e.control.left - slot.left) < 20: + place(e.control, slot) + else: + bounce_back(solitaire, e.control) + + e.control.update() + + slot = ft.Container(width=70, height=100, left=200, top=0, border=ft.Border.all(1)) + + card1 = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=start_drag, + on_pan_update=drag, + on_pan_end=drop, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), + ) + + card2 = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=start_drag, + on_pan_update=drag, + on_pan_end=drop, + left=100, + top=0, + content=ft.Container(bgcolor=ft.Colors.YELLOW, width=70, height=100), + ) + + solitaire = Solitaire() + + controls = [slot, card1, card2] + page.add(ft.Stack(controls=controls, width=1000, height=500)) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step4.py b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step4.py new file mode 100644 index 0000000000..bfde4a5659 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step4.py @@ -0,0 +1,96 @@ +import flet as ft + +# Adding 2 more slots +# Deal cards before the beginning of the game +# On_pan_end, go through slots list to find slot in proximity if possible + + +class Solitaire: + def __init__(self): + self.start_top = 0 + self.start_left = 0 + + +def main(page: ft.Page): + def place(card, slot): + """place card to the slot""" + card.top = slot.top + card.left = slot.left + + def bounce_back(game, card): + """return card to its original position""" + card.top = game.start_top + card.left = game.start_left + page.update() + + def move_on_top(card, controls): + """Moves draggable card to the top of the stack""" + controls.remove(card) + controls.append(card) + page.update() + + def start_drag(e: ft.DragStartEvent): + move_on_top(e.control, controls) + solitaire.start_top = e.control.top + solitaire.start_left = e.control.left + + def drag(e: ft.DragUpdateEvent): + e.control.top = max(0, e.control.top + e.local_delta.y) + e.control.left = max(0, e.control.left + e.local_delta.x) + e.control.update() + + def drop(e: ft.DragEndEvent): + for slot in slots: + if ( + abs(e.control.top - slot.top) < 20 + and abs(e.control.left - slot.left) < 20 + ): + place(e.control, slot) + e.control.update() + return + + bounce_back(solitaire, e.control) + e.control.update() + + slot0 = ft.Container(width=70, height=100, left=0, top=0, border=ft.Border.all(1)) + + slot1 = ft.Container(width=70, height=100, left=200, top=0, border=ft.Border.all(1)) + + slot2 = ft.Container(width=70, height=100, left=300, top=0, border=ft.Border.all(1)) + + slots = [slot0, slot1, slot2] + + card1 = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=start_drag, + on_pan_update=drag, + on_pan_end=drop, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), + ) + + card2 = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=start_drag, + on_pan_update=drag, + on_pan_end=drop, + left=100, + top=0, + content=ft.Container(bgcolor=ft.Colors.YELLOW, width=70, height=100), + ) + + controls = [slot0, slot1, slot2, card1, card2] + + # deal cards + place(card1, slot0) + place(card2, slot0) + + solitaire = Solitaire() + + page.add(ft.Stack(controls=controls, width=1000, height=500)) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/card.py b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/card.py new file mode 100644 index 0000000000..6270336bb4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/card.py @@ -0,0 +1,94 @@ +CARD_WIDTH = 70 +CARD_HEIGHT = 100 +DROP_PROXIMITY = 30 +CARD_OFFSET = 20 + +import flet as ft + + +class Card(ft.GestureDetector): + def __init__(self, solitaire, color): + super().__init__() + self.mouse_cursor = ft.MouseCursor.MOVE + self.drag_interval = 5 + self.on_pan_start = self.start_drag + self.on_pan_update = self.drag + self.on_pan_end = self.drop + self.left = None + self.top = None + self.solitaire = solitaire + self.slot = None + self.card_offset = CARD_OFFSET + self.color = color + self.content = ft.Container( + bgcolor=self.color, width=CARD_WIDTH, height=CARD_HEIGHT + ) + self.draggable_pile = [self] + + def move_on_top(self): + """Brings draggable card pile to the top of the stack""" + + # for card in self.get_draggable_pile(): + for card in self.draggable_pile: + self.solitaire.controls.remove(card) + self.solitaire.controls.append(card) + self.solitaire.update() + + def bounce_back(self): + """Returns draggable pile to its original position""" + for card in self.draggable_pile: + card.top = card.slot.top + card.slot.pile.index(card) * CARD_OFFSET + card.left = card.slot.left + self.solitaire.update() + + def place(self, slot): + """Place draggable pile to the slot""" + for card in self.draggable_pile: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + card.left = slot.left + + # remove card from it's original slot, if it exists + if card.slot is not None: + card.slot.pile.remove(card) + + # change card's slot to a new slot + card.slot = slot + + # add card to the new slot's pile + slot.pile.append(card) + + self.solitaire.update() + + def get_draggable_pile(self): + """returns list of cards that will be dragged together, starting with the current card""" + if self.slot is not None: + self.draggable_pile = self.slot.pile[self.slot.pile.index(self) :] + else: # slot == None when the cards are dealt and need to be place in slot for the first time + self.draggable_pile = [self] + + def start_drag(self, e: ft.DragStartEvent): + self.get_draggable_pile() + self.move_on_top() + self.solitaire.update() + + def drag(self, e: ft.DragUpdateEvent): + for card in self.draggable_pile: + card.top = ( + max(0, self.top + e.local_delta.y) + + self.draggable_pile.index(card) * CARD_OFFSET + ) + card.left = max(0, self.left + e.local_delta.x) + self.solitaire.update() + + def drop(self, e: ft.DragEndEvent): + for slot in self.solitaire.slots: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) + < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.solitaire.update() + return + + self.bounce_back() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/main.py b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/main.py new file mode 100644 index 0000000000..bf09580328 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/main.py @@ -0,0 +1,11 @@ +import flet as ft +from solitaire import Solitaire + + +def main(page: ft.Page): + solitaire = Solitaire() + + page.add(solitaire) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/slot.py b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/slot.py new file mode 100644 index 0000000000..5a4caba256 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/slot.py @@ -0,0 +1,15 @@ +import flet as ft + +SLOT_WIDTH = 70 +SLOT_HEIGHT = 100 + + +class Slot(ft.Container): + def __init__(self, top, left): + super().__init__() + self.pile = [] + self.width = SLOT_WIDTH + self.height = SLOT_HEIGHT + self.left = left + self.top = top + self.border = ft.Border.all(1) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/solitaire.py b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/solitaire.py new file mode 100644 index 0000000000..a670da60da --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles/solitaire.py @@ -0,0 +1,45 @@ +# CARD_OFFSET = 20 +SOLITAIRE_WIDTH = 1000 +SOLITAIRE_HEIGHT = 500 + +import flet as ft +from card import Card +from slot import Slot + + +class Solitaire(ft.Stack): + def __init__(self): + super().__init__() + # self.start_top = 0 + # self.start_left = 0 + self.controls = [] + self.slots = [] + # self.card_offset = CARD_OFFSET + self.width = SOLITAIRE_WIDTH + self.height = SOLITAIRE_HEIGHT + + def did_mount(self): + self.create_card_deck() + self.create_slots() + self.deal_cards() + + def create_card_deck(self): + card1 = Card(self, color="GREEN") + card2 = Card(self, color="YELLOW") + card3 = Card(self, color="RED") + card4 = Card(self, color="BLUE") + self.cards = [card1, card2, card3, card4] + + def create_slots(self): + self.slots.append(Slot(top=0, left=0)) + self.slots.append(Slot(top=0, left=200)) + self.slots.append(Slot(top=0, left=300)) + self.controls.extend(self.slots) + self.update() + + def deal_cards(self): + self.controls.extend(self.cards) + + for card in self.cards: + card.place(self.slots[0]) + self.update() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/Dockerfile b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/Dockerfile new file mode 100644 index 0000000000..2fe01b9780 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3-alpine + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8080 + +CMD ["python", "./main.py"] diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_clubs.svg new file mode 100644 index 0000000000..55d98208ac --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_clubs.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_diamonds.svg new file mode 100644 index 0000000000..1286c25a5e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_diamonds.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_hearts.svg new file mode 100644 index 0000000000..73c6edd671 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_hearts.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_spades.svg new file mode 100644 index 0000000000..830135370d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/10_spades.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_clubs.svg new file mode 100644 index 0000000000..d623e9b404 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_clubs.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_diamonds.svg new file mode 100644 index 0000000000..26aa767cde --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_diamonds.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_hearts.svg new file mode 100644 index 0000000000..53afaa958e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_hearts.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_spades.svg new file mode 100644 index 0000000000..22fe99d7fc --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/2_spades.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_clubs.svg new file mode 100644 index 0000000000..dc06314904 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_clubs.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_diamonds.svg new file mode 100644 index 0000000000..1b8c766378 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_diamonds.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_hearts.svg new file mode 100644 index 0000000000..d5142bc196 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_hearts.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_spades.svg new file mode 100644 index 0000000000..aa3a137d75 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/3_spades.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_clubs.svg new file mode 100644 index 0000000000..32cb3c16c0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_clubs.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_diamonds.svg new file mode 100644 index 0000000000..a6858f8578 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_diamonds.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_hearts.svg new file mode 100644 index 0000000000..1acb9a6724 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_hearts.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_spades.svg new file mode 100644 index 0000000000..c49351766a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/4_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_clubs.svg new file mode 100644 index 0000000000..f41b8c3ec8 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_clubs.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_diamonds.svg new file mode 100644 index 0000000000..8cb1f09b84 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_diamonds.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_hearts.svg new file mode 100644 index 0000000000..fdf1a3ddf3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_spades.svg new file mode 100644 index 0000000000..9bf5500c73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/5_spades.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_clubs.svg new file mode 100644 index 0000000000..80e1931832 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_clubs.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_diamonds.svg new file mode 100644 index 0000000000..01f12ece8c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_diamonds.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_hearts.svg new file mode 100644 index 0000000000..04ae7766b7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_spades.svg new file mode 100644 index 0000000000..024adc16d2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/6_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_clubs.svg new file mode 100644 index 0000000000..79b2f62e3d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_clubs.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_diamonds.svg new file mode 100644 index 0000000000..2a38c99667 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_diamonds.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_hearts.svg new file mode 100644 index 0000000000..72f42fe94a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_hearts.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_spades.svg new file mode 100644 index 0000000000..7519ad6ca2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/7_spades.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_clubs.svg new file mode 100644 index 0000000000..452a8dd29a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_clubs.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_diamonds.svg new file mode 100644 index 0000000000..abf41a526f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_diamonds.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_hearts.svg new file mode 100644 index 0000000000..fd50551001 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_hearts.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_spades.svg new file mode 100644 index 0000000000..77ce108a2f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/8_spades.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_clubs.svg new file mode 100644 index 0000000000..b2749c0dbb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_clubs.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_diamonds.svg new file mode 100644 index 0000000000..eec88db012 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_diamonds.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_hearts.svg new file mode 100644 index 0000000000..66bc2770d0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_hearts.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_spades.svg new file mode 100644 index 0000000000..c21f4ac14e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/9_spades.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_clubs.svg new file mode 100644 index 0000000000..46b22496a3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_clubs.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_diamonds.svg new file mode 100644 index 0000000000..0745d5e321 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_diamonds.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_hearts.svg new file mode 100644 index 0000000000..70c5640276 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_hearts.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_spades.svg new file mode 100644 index 0000000000..2d015c67e0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Ace_spades.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_clubs.svg new file mode 100644 index 0000000000..4bcd40e03f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_clubs.svg @@ -0,0 +1,2103 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_diamonds.svg new file mode 100644 index 0000000000..c371d95b73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_diamonds.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_hearts.svg new file mode 100644 index 0000000000..6bd3a18cce --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_hearts.svg @@ -0,0 +1,2092 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_spades.svg new file mode 100644 index 0000000000..745ca85965 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Jack_spades.svg @@ -0,0 +1,2361 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_clubs.svg new file mode 100644 index 0000000000..173c31bd95 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_clubs.svg @@ -0,0 +1,2357 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_diamonds.svg new file mode 100644 index 0000000000..42cd892f9e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_diamonds.svg @@ -0,0 +1,1864 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_hearts.svg new file mode 100644 index 0000000000..ca382b506c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_hearts.svg @@ -0,0 +1,3106 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_spades.svg new file mode 100644 index 0000000000..73d1f69770 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/King_spades.svg @@ -0,0 +1,1771 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_clubs.svg new file mode 100644 index 0000000000..b041d9a2f4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_clubs.svg @@ -0,0 +1,2408 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_diamonds.svg new file mode 100644 index 0000000000..a2b9ef9805 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_diamonds.svg @@ -0,0 +1,1857 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_hearts.svg new file mode 100644 index 0000000000..4c5420c510 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_hearts.svg @@ -0,0 +1,2418 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_spades.svg new file mode 100644 index 0000000000..e2b9306800 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/Queen_spades.svg @@ -0,0 +1,2202 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/card_back.png b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/card_back.png new file mode 100644 index 0000000000..dd8b3416dc Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/assets/images/card_back.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/card.py b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/card.py new file mode 100644 index 0000000000..5429d54dfb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/card.py @@ -0,0 +1,155 @@ +import flet as ft + +CARD_WIDTH = 70 +CARD_HEIGHT = 100 +DROP_PROXIMITY = 30 +CARD_OFFSET = 20 + + +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + super().__init__() + self.mouse_cursor = ft.MouseCursor.MOVE + self.drag_interval = 5 + self.on_pan_start = self.start_drag + self.on_pan_update = self.drag + self.on_pan_end = self.drop + self.on_tap = self.click + self.on_double_tap = self.doubleclick + self.suite = suite + self.rank = rank + self.face_up = False + self.top = None + self.left = None + self.solitaire = solitaire + self.slot = None + self.content = ft.Container( + width=CARD_WIDTH, + height=CARD_HEIGHT, + border_radius=ft.BorderRadius.all(6), + content=ft.Image(src="/images/card_back.png"), + ) + self.draggable_pile = [self] + + def turn_face_up(self): + """Reveals card""" + self.face_up = True + self.content.content.src = f"/images/{self.rank.name}_{self.suite.name}.svg" + self.solitaire.update() + + def turn_face_down(self): + """Hides card""" + self.face_up = False + self.content.content.src = "/images/card_back.png" + self.solitaire.update() + + def move_on_top(self): + """Brings draggable card pile to the top of the stack""" + + for card in self.draggable_pile: + self.solitaire.controls.remove(card) + self.solitaire.controls.append(card) + self.solitaire.update() + + def bounce_back(self): + """Returns draggable pile to its original position""" + for card in self.draggable_pile: + if card.slot in self.solitaire.tableau: + card.top = card.slot.top + card.slot.pile.index(card) * CARD_OFFSET + else: + card.top = card.slot.top + card.left = card.slot.left + self.solitaire.update() + + def place(self, slot): + """Place draggable pile to the slot""" + + for card in self.draggable_pile: + if slot in self.solitaire.tableau: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + else: + card.top = slot.top + card.left = slot.left + + # remove card from it's original slot, if exists + if card.slot is not None: + card.slot.pile.remove(card) + + # change card's slot to a new slot + card.slot = slot + + # add card to the new slot's pile + slot.pile.append(card) + + if self.solitaire.check_win(): + self.solitaire.winning_sequence() + + self.solitaire.update() + + def get_draggable_pile(self): + """returns list of cards that will be dragged together, starting with the current card""" + + if ( + self.slot is not None + and self.slot != self.solitaire.stock + and self.slot != self.solitaire.waste + ): + self.draggable_pile = self.slot.pile[self.slot.pile.index(self) :] + else: # slot == None when the cards are dealt and need to be place in slot for the first time + self.draggable_pile = [self] + + def start_drag(self, e: ft.DragStartEvent): + if self.face_up: + self.get_draggable_pile() + self.move_on_top() + + def drag(self, e: ft.DragUpdateEvent): + if self.face_up: + for card in self.draggable_pile: + card.top = ( + max(0, self.top + e.local_delta.y) + + self.draggable_pile.index(card) * CARD_OFFSET + ) + card.left = max(0, self.left + e.local_delta.x) + self.solitaire.update() + + def drop(self, e: ft.DragEndEvent): + if self.face_up: + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) + < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_tableau_rules(self, slot): + self.place(slot) + return + + if len(self.draggable_pile) == 1: + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return + + self.bounce_back() + + def click(self, e): + self.get_draggable_pile() + if self.slot in self.solitaire.tableau: + if not self.face_up and len(self.draggable_pile) == 1: + self.turn_face_up() + elif self.slot == self.solitaire.stock: + self.move_on_top() + self.place(self.solitaire.waste) + self.turn_face_up() + + def doubleclick(self, e): + self.get_draggable_pile() + if self.face_up and len(self.draggable_pile) == 1: + self.move_on_top() + for slot in self.solitaire.foundations: + if self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/fly.toml b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/fly.toml new file mode 100644 index 0000000000..d0e5eaf2eb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/fly.toml @@ -0,0 +1,40 @@ +app = "solitaire-part1" + +kill_signal = "SIGINT" +kill_timeout = 5 +processes = [] + +[env] + FLET_SERVER_PORT = "8080" + FLET_FORCE_WEB_SERVER = "true" + +[experimental] + allowed_public_ports = [] + auto_rollback = true + +[[services]] + http_checks = [] + internal_port = 8080 + processes = ["app"] + protocol = "tcp" + script_checks = [] + + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + type = "connections" + + [[services.ports]] + force_https = true + handlers = ["http"] + port = 80 + + [[services.ports]] + handlers = ["tls", "http"] + port = 443 + + [[services.tcp_checks]] + grace_period = "1s" + interval = "15s" + restart_limit = 0 + timeout = "2s" diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/main.py b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/main.py new file mode 100644 index 0000000000..5a574b8028 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/main.py @@ -0,0 +1,13 @@ +import flet as ft +from solitaire import Solitaire + + +def main(page: ft.Page): + page.on_error = lambda e: print("Page error:", e.data) + + solitaire = Solitaire() + + page.add(solitaire) + + +ft.run(main, assets_dir="assets") diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/requirements.txt b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/requirements.txt new file mode 100644 index 0000000000..9f5592458b --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/requirements.txt @@ -0,0 +1 @@ +flet>=0.25.1 diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/slot.py b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/slot.py new file mode 100644 index 0000000000..74cc1a76e7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/slot.py @@ -0,0 +1,26 @@ +SLOT_WIDTH = 70 +SLOT_HEIGHT = 100 + +import flet as ft + + +class Slot(ft.Container): + def __init__(self, solitaire, top, left, border): + super().__init__() + self.pile = [] + self.width = SLOT_WIDTH + self.height = SLOT_HEIGHT + self.left = left + self.top = top + self.on_click = self.click + self.solitaire = solitaire + self.border = border + self.border_radius = ft.BorderRadius.all(6) + + def get_top_card(self): + if len(self.pile) > 0: + return self.pile[-1] + + def click(self, e): + if self == self.solitaire.stock: + self.solitaire.restart_stock() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/solitaire.py b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/solitaire.py new file mode 100644 index 0000000000..2e994e5345 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final-part1/solitaire.py @@ -0,0 +1,163 @@ +import random + +from card import Card +from slot import Slot + +import flet as ft + +SOLITAIRE_WIDTH = 1000 +SOLITAIRE_HEIGHT = 500 + + +class Suite: + def __init__(self, suite_name, suite_color): + self.name = suite_name + self.color = suite_color + + +class Rank: + def __init__(self, card_name, card_value): + self.name = card_name + self.value = card_value + + +class Solitaire(ft.Stack): + def __init__(self): + super().__init__() + self.controls = [] + self.width = SOLITAIRE_WIDTH + self.height = SOLITAIRE_HEIGHT + + def did_mount(self): + self.create_card_deck() + self.create_slots() + self.deal_cards() + + def create_card_deck(self): + suites = [ + Suite("hearts", "RED"), + Suite("diamonds", "RED"), + Suite("clubs", "BLACK"), + Suite("spades", "BLACK"), + ] + ranks = [ + Rank("Ace", 1), + Rank("2", 2), + Rank("3", 3), + Rank("4", 4), + Rank("5", 5), + Rank("6", 6), + Rank("7", 7), + Rank("8", 8), + Rank("9", 9), + Rank("10", 10), + Rank("Jack", 11), + Rank("Queen", 12), + Rank("King", 13), + ] + + self.cards = [] + + for suite in suites: + for rank in ranks: + self.cards.append(Card(solitaire=self, suite=suite, rank=rank)) + + def create_slots(self): + self.stock = Slot(solitaire=self, top=0, left=0, border=ft.Border.all(1)) + + self.waste = Slot(solitaire=self, top=0, left=100, border=None) + + self.foundations = [] + x = 300 + for i in range(4): + self.foundations.append( + Slot(solitaire=self, top=0, left=x, border=ft.Border.all(1, "outline")) + ) + x += 100 + + self.tableau = [] + x = 0 + for i in range(7): + self.tableau.append(Slot(solitaire=self, top=150, left=x, border=None)) + x += 100 + + self.controls.append(self.stock) + self.controls.append(self.waste) + self.controls.extend(self.foundations) + self.controls.extend(self.tableau) + self.update() + + def deal_cards(self): + random.shuffle(self.cards) + self.controls.extend(self.cards) + + # deal to tableau + first_slot = 0 + remaining_cards = self.cards + + while first_slot < len(self.tableau): + for slot in self.tableau[first_slot:]: + top_card = remaining_cards[0] + top_card.place(slot) + remaining_cards.remove(top_card) + first_slot += 1 + + # place remaining cards to stock pile + for card in remaining_cards: + card.place(self.stock) + print(f"Card in stock: {card.rank.name} {card.suite.name}") + + self.update() + + for slot in self.tableau: + slot.get_top_card().turn_face_up() + + self.update() + + def check_foundations_rules(self, card, slot): + top_card = slot.get_top_card() + if top_card is not None: + return ( + card.suite.name == top_card.suite.name + and card.rank.value - top_card.rank.value == 1 + ) + else: + return card.rank.name == "Ace" + + def check_tableau_rules(self, card, slot): + top_card = slot.get_top_card() + if top_card is not None: + return ( + card.suite.color != top_card.suite.color + and top_card.rank.value - card.rank.value == 1 + and top_card.face_up + ) + else: + return card.rank.name == "King" + + def restart_stock(self): + while len(self.waste.pile) > 0: + card = self.waste.get_top_card() + card.turn_face_down() + card.move_on_top() + card.place(self.stock) + + def check_win(self): + cards_num = 0 + for slot in self.foundations: + cards_num += len(slot.pile) + if cards_num == 52: + return True + return False + + def winning_sequence(self): + for slot in self.foundations: + for card in slot.pile: + card.animate_position = 2000 + card.move_on_top() + card.top = random.randint(0, SOLITAIRE_HEIGHT) + card.left = random.randint(0, SOLITAIRE_WIDTH) + self.update() + self.controls.append( + ft.AlertDialog(title=ft.Text("Congratulations! You won!"), open=True) + ) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_clubs.svg new file mode 100644 index 0000000000..55d98208ac --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_clubs.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_diamonds.svg new file mode 100644 index 0000000000..1286c25a5e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_diamonds.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_hearts.svg new file mode 100644 index 0000000000..73c6edd671 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_hearts.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_spades.svg new file mode 100644 index 0000000000..830135370d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/10_spades.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_clubs.svg new file mode 100644 index 0000000000..d623e9b404 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_clubs.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_diamonds.svg new file mode 100644 index 0000000000..26aa767cde --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_diamonds.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_hearts.svg new file mode 100644 index 0000000000..53afaa958e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_hearts.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_spades.svg new file mode 100644 index 0000000000..22fe99d7fc --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/2_spades.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_clubs.svg new file mode 100644 index 0000000000..dc06314904 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_clubs.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_diamonds.svg new file mode 100644 index 0000000000..1b8c766378 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_diamonds.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_hearts.svg new file mode 100644 index 0000000000..d5142bc196 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_hearts.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_spades.svg new file mode 100644 index 0000000000..aa3a137d75 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/3_spades.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_clubs.svg new file mode 100644 index 0000000000..32cb3c16c0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_clubs.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_diamonds.svg new file mode 100644 index 0000000000..a6858f8578 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_diamonds.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_hearts.svg new file mode 100644 index 0000000000..1acb9a6724 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_hearts.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_spades.svg new file mode 100644 index 0000000000..c49351766a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/4_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_clubs.svg new file mode 100644 index 0000000000..f41b8c3ec8 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_clubs.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_diamonds.svg new file mode 100644 index 0000000000..8cb1f09b84 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_diamonds.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_hearts.svg new file mode 100644 index 0000000000..fdf1a3ddf3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_spades.svg new file mode 100644 index 0000000000..9bf5500c73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/5_spades.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_clubs.svg new file mode 100644 index 0000000000..80e1931832 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_clubs.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_diamonds.svg new file mode 100644 index 0000000000..01f12ece8c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_diamonds.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_hearts.svg new file mode 100644 index 0000000000..04ae7766b7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_spades.svg new file mode 100644 index 0000000000..024adc16d2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/6_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_clubs.svg new file mode 100644 index 0000000000..79b2f62e3d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_clubs.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_diamonds.svg new file mode 100644 index 0000000000..2a38c99667 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_diamonds.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_hearts.svg new file mode 100644 index 0000000000..72f42fe94a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_hearts.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_spades.svg new file mode 100644 index 0000000000..7519ad6ca2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/7_spades.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_clubs.svg new file mode 100644 index 0000000000..452a8dd29a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_clubs.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_diamonds.svg new file mode 100644 index 0000000000..abf41a526f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_diamonds.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_hearts.svg new file mode 100644 index 0000000000..fd50551001 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_hearts.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_spades.svg new file mode 100644 index 0000000000..77ce108a2f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/8_spades.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_clubs.svg new file mode 100644 index 0000000000..b2749c0dbb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_clubs.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_diamonds.svg new file mode 100644 index 0000000000..eec88db012 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_diamonds.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_hearts.svg new file mode 100644 index 0000000000..66bc2770d0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_hearts.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_spades.svg new file mode 100644 index 0000000000..c21f4ac14e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/9_spades.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_clubs.svg new file mode 100644 index 0000000000..46b22496a3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_clubs.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_diamonds.svg new file mode 100644 index 0000000000..0745d5e321 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_diamonds.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_hearts.svg new file mode 100644 index 0000000000..70c5640276 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_hearts.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_spades.svg new file mode 100644 index 0000000000..2d015c67e0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Ace_spades.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_clubs.svg new file mode 100644 index 0000000000..4bcd40e03f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_clubs.svg @@ -0,0 +1,2103 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_diamonds.svg new file mode 100644 index 0000000000..c371d95b73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_diamonds.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_hearts.svg new file mode 100644 index 0000000000..6bd3a18cce --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_hearts.svg @@ -0,0 +1,2092 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_spades.svg new file mode 100644 index 0000000000..745ca85965 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Jack_spades.svg @@ -0,0 +1,2361 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_clubs.svg new file mode 100644 index 0000000000..173c31bd95 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_clubs.svg @@ -0,0 +1,2357 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_diamonds.svg new file mode 100644 index 0000000000..42cd892f9e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_diamonds.svg @@ -0,0 +1,1864 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_hearts.svg new file mode 100644 index 0000000000..ca382b506c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_hearts.svg @@ -0,0 +1,3106 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_spades.svg new file mode 100644 index 0000000000..73d1f69770 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/King_spades.svg @@ -0,0 +1,1771 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_clubs.svg new file mode 100644 index 0000000000..b041d9a2f4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_clubs.svg @@ -0,0 +1,2408 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_diamonds.svg new file mode 100644 index 0000000000..a2b9ef9805 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_diamonds.svg @@ -0,0 +1,1857 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_hearts.svg new file mode 100644 index 0000000000..4c5420c510 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_hearts.svg @@ -0,0 +1,2418 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_spades.svg new file mode 100644 index 0000000000..e2b9306800 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/Queen_spades.svg @@ -0,0 +1,2202 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card.png b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card.png new file mode 100644 index 0000000000..b1def7f8d5 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back0.png b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back0.png new file mode 100644 index 0000000000..dd8b3416dc Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back0.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back1.png b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back1.png new file mode 100644 index 0000000000..e024e961b2 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back1.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back1.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back1.svg new file mode 100644 index 0000000000..de53ba9863 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back1.svg @@ -0,0 +1,91 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back2.png b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back2.png new file mode 100644 index 0000000000..acc9f15c79 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back2.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back2.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back2.svg new file mode 100644 index 0000000000..7e5b1b5c1b --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back2.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back3.png b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back3.png new file mode 100644 index 0000000000..09ffcdb6f6 Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back3.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back3.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back3.svg new file mode 100644 index 0000000000..33520ea8e7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back3.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back4.svg b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back4.svg new file mode 100644 index 0000000000..3810b313f7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/assets/images/card_back4.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + Card backs: grid blue + 2009-03-23T13:56:40 + playing card backs for the "Ornamental", "White", "Simple" and "Bordered" sets + http://openclipart.org/detail/23034/card-backs:-grid-blue-by-nicubunu + + + nicubunu + + + + + bordered deck + card + cards + clip art + clipart + deck + gambling + game + image + media + ornamental deck + play + playing cards + png + public domain + simple deck + svg + white deck + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/card.py b/sdk/python/examples/tutorials/solitaire/solitaire-final/card.py new file mode 100644 index 0000000000..0ce7351cd6 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/card.py @@ -0,0 +1,176 @@ +import flet as ft + + +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + super().__init__() + self.solitaire = solitaire + self.suite = suite + self.rank = rank + self.face_up = False + self.slot = None + + self.mouse_cursor = ft.MouseCursor.MOVE + self.drag_interval = 5 + self.on_pan_update = self.drag + self.on_pan_start = self.start_drag + self.on_pan_end = self.drop + self.on_tap = self.click + self.on_double_tap = self.doubleclick + self.content = ft.Container( + width=70, + height=100, + border_radius=ft.BorderRadius.all(6), + # content=ft.Image(src=f"/images/card_back.svg"), + content=ft.Image(src=self.solitaire.settings.card_back), + ) + + def turn_face_up(self): + self.face_up = True + self.content.content.src = f"/images/{self.rank.name}_{self.suite.name}.svg" + self.solitaire.update() + + def turn_face_down(self): + self.face_up = False + # self.content.content.src=f"/images/card_back.svg" + self.content.content.src = self.solitaire.settings.card_back + self.solitaire.update() + + def can_be_moved(self): + if self.face_up and self.slot.type != "waste": + return True + if self.slot.type == "waste" and len( + self.solitaire.waste.pile + ) - 1 == self.solitaire.waste.pile.index(self): + return True + return False + + def start_drag(self, e: ft.DragStartEvent): + # if e.control.face_up: + if self.can_be_moved(): + cards_to_drag = self.get_cards_to_move() + self.solitaire.move_on_top(cards_to_drag) + # remember card original position to return it back if needed + self.solitaire.current_top = e.control.top + self.solitaire.current_left = e.control.left + self.solitaire.update() + + def drag(self, e: ft.DragUpdateEvent): + if self.can_be_moved(): + i = 0 + for card in self.get_cards_to_move(): + card.top = max(0, self.top + e.local_delta.y) + if card.slot.type == "tableau": + card.top += i * self.solitaire.card_offset + card.left = max(0, self.left + e.local_delta.x) + i += 1 + self.solitaire.update() + + def drop(self, e: ft.DragEndEvent): + if self.can_be_moved(): + cards_to_drag = self.get_cards_to_move() + slots = self.solitaire.tableau + self.solitaire.foundation + # check if card is close to any of the tableau or foundation slots + for slot in slots: + # compare with top and left position of the top card in the slot pile + if ( + abs(self.top - slot.upper_card_top()) < 40 + and abs(self.left - slot.left) < 40 + ): + if ( + slot.type == "tableau" + and self.solitaire.check_tableau_rules( + self, slot.get_top_card() + ) + ) or ( + slot.type == "foundation" + and len(cards_to_drag) == 1 + and self.solitaire.check_foundation_rules( + self, slot.get_top_card() + ) + ): + old_slot = self.slot + for card in cards_to_drag: + card.place(slot) + # reveal top card in old tableau slot if exists + if len(old_slot.pile) > 0 and old_slot.type == "tableau": + old_slot.get_top_card().turn_face_up() + elif old_slot.type == "waste": + self.solitaire.display_waste() + self.solitaire.update() + + return + + # return card to original position + self.solitaire.bounce_back(cards_to_drag) + self.solitaire.update() + + def doubleclick(self, e): + if self.slot.type in ("waste", "tableau"): + if self.face_up: + # self.move_on_top(self.solitaire.controls, [self]) + self.solitaire.move_on_top([self]) + old_slot = self.slot + for slot in self.solitaire.foundation: + if self.solitaire.check_foundation_rules(self, slot.get_top_card()): + # if True: + self.place(slot) + # if len(old_slot.pile) > 0: + # old_slot.get_top_card().turn_face_up() + # self.solitaire.display_waste() + self.solitaire.update() + return + + def click(self, e): + if self.slot.type == "stock": + # first, set the current top 3 cards to invisible + for card in self.solitaire.waste.get_top_three_cards(): + card.visible = False + + for i in range( + min(self.solitaire.settings.waste_size, len(self.solitaire.stock.pile)) + ): + top_card = self.solitaire.stock.pile[-1] + # self.move_on_top(self.solitaire.controls, [top_card]) + # self.solitaire.move_on_top([top_card]) + top_card.place(self.solitaire.waste) + top_card.turn_face_up() + self.solitaire.display_waste() + self.solitaire.update() + + if self.slot.type == "tableau": + if self.face_up == False and len( + self.slot.pile + ) - 1 == self.slot.pile.index(self): + self.turn_face_up() + + def place(self, slot): + self.top = slot.top + self.left = slot.left + if slot.type == "tableau": + self.top += self.solitaire.card_offset * len(slot.pile) + + # remove the card form the old slot's pile if exists + + if self.slot is not None: + self.slot.pile.remove(self) + + # set card's slot as new slot + self.slot = slot + + # add the card to the new slot's pile + slot.pile.append(self) + self.solitaire.move_on_top([self]) + if self.solitaire.check_if_you_won(): + self.solitaire.on_win() + self.solitaire.update() + + def get_cards_to_move(self): + """ + Returns a list of cards that will be dragged together, + starting with the current card. + """ + if self.slot is not None: + return self.slot.pile[self.slot.pile.index(self) :] + + return [self] diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/layout.py b/sdk/python/examples/tutorials/solitaire/solitaire-final/layout.py new file mode 100644 index 0000000000..fe8894d91c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/layout.py @@ -0,0 +1,50 @@ +import flet as ft +from settings import SettingsDialog + + +def create_appbar(page, settings, on_new_game): + def new_game_clicked(e): + on_new_game(settings) + + def show_rules(e): + page.dialog = rules_dialog + rules_dialog.open = True + page.update() + + def show_settings(e): + page.dialog = SettingsDialog(settings, on_new_game) + page.dialog.open = True + page.update() + + page.appbar = ft.AppBar( + leading=ft.Image(src="/images/card.png"), + leading_width=30, + title=ft.Text("Flet solitaire"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + actions=[ + ft.TextButton(content="New game", on_click=new_game_clicked), + ft.TextButton(content="Rules", on_click=show_rules), + ft.IconButton(ft.Icons.SETTINGS, on_click=show_settings), + ], + ) + + rules_md = ft.Markdown( + """ + Klondike is played with a standard 52-card deck, without Jokers. + + The four foundations (light rectangles in the upper right of the figure) are built up by suit from Ace (low in this game) to King, and the tableau piles can be built down by alternate colors. Every face-up card in a partial pile, or a complete pile, can be moved, as a unit, to another tableau pile on the basis of its highest card. Any empty piles can be filled with a King, or a pile of cards with a King. The aim of the game is to build up four stacks of cards starting with Ace and ending with King, all of the same suit, on one of the four foundations, at which time the player would have won. There are different ways of dealing the remainder of the deck from the stock to the waste, which can be selected in the Settings: + + - Turning three cards at once to the waste, with no limit on passes through the deck. + - Turning three cards at once to the waste, with three passes through the deck. + - Turning one card at a time to the waste, with three passes through the deck. + - Turning one card at a time to the waste, with no limit on passes through the deck. + + If the player can no longer make any meaningful moves, the game is considered lost. + """ + ) + + rules_dialog = ft.AlertDialog( + title=ft.Text("Solitaire rules"), + content=rules_md, + on_dismiss=lambda e: print("Dialog dismissed!"), + ) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/main.py b/sdk/python/examples/tutorials/solitaire/solitaire-final/main.py new file mode 100644 index 0000000000..7433ee8321 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/main.py @@ -0,0 +1,34 @@ +import flet as ft +from layout import create_appbar +from settings import Settings +from solitaire import Solitaire + +# logging.basicConfig(level=logging.DEBUG) + + +def main(page: ft.Page): + def on_new_game(settings): + page.controls.pop() + new_solitaire = Solitaire(settings, on_win) + page.add(new_solitaire) + page.update() + + def on_win(): + page.add( + ft.AlertDialog( + title=ft.Text("YOU WIN!"), + open=True, + on_dismiss=lambda e: page.controls.pop(), + ) + ) + print("You win") + page.update() + + settings = Settings() + create_appbar(page, settings, on_new_game) + + solitaire = Solitaire(settings, on_win) + page.add(solitaire) + + +ft.run(main, assets_dir="assets") diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/settings.py b/sdk/python/examples/tutorials/solitaire/solitaire-final/settings.py new file mode 100644 index 0000000000..a164275cfd --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/settings.py @@ -0,0 +1,95 @@ +import flet as ft + + +class Settings: + def __init__( + self, waste_size=3, deck_passes_allowed=1000, card_back="/images/card_back0.png" + ): + self.waste_size = waste_size + self.deck_passes_allowed = deck_passes_allowed + self.card_back = card_back + + +class SettingsDialog(ft.AlertDialog): + def __init__(self, settings, on_settings_applied): + super().__init__() + self.on_settings_applied = on_settings_applied + self.settings = settings + self.modal = True + self.title = ft.Text("Solitaire Settings") + self.waste_size = ft.RadioGroup( + value=self.settings.waste_size, + content=ft.Row( + controls=[ + ft.Radio(value=1, label="One card"), + ft.Radio(value=3, label="Three cards"), + ] + ), + ) + self.deck_passes_allowed = ft.RadioGroup( + value=self.settings.deck_passes_allowed, + content=ft.Row( + controls=[ + ft.Radio(value=3, label="Three"), + ft.Radio(value=1000, label="Unlimited"), + ] + ), + ) + self.generate_card_backs() + + self.content = ft.Column( + controls=[ + ft.Text("Waste pile size:"), + self.waste_size, + ft.Text("Passes through the deck:"), + self.deck_passes_allowed, + ft.Row(controls=self.card_backs), + ft.Checkbox( + label="New game will be started when settings are updated.", + value=True, + disabled=True, + ), + ], + tight=True, + ) + self.actions = [ + ft.TextButton("Cancel", on_click=self.cancel), + ft.FilledButton("Apply settings", on_click=self.apply_settings), + ] + + def generate_card_backs(self): + self.card_backs = [] + for i in range(4): + self.card_backs.append( + ft.Container( + width=70, + height=100, + content=ft.Image(src=f"/images/card_back{i}.png"), + border_radius=ft.BorderRadius.all(6), + on_click=self.choose_card_design, + data=i, + ) + ) + self.selected_card = self.card_backs[0] + + def choose_card_design(self, e): + for card in self.card_backs: + if card.data != e.control.data: + card.border = None + e.control.border = ft.Border.all(3) + self.selected_card = e.control + self.update() + + def cancel(self, e): + self.waste_size.value = self.settings.waste_size + self.deck_passes_allowed.value = self.settings.deck_passes_allowed + self.open = False + self.update() + + def apply_settings(self, e): + self.open = False + self.settings.waste_size = int(self.waste_size.value) + self.settings.deck_passes_allowed = int(self.deck_passes_allowed.value) + self.settings.card_back = self.selected_card.content.src + self.on_settings_applied(self.settings) + self.update() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/slot.py b/sdk/python/examples/tutorials/solitaire/solitaire-final/slot.py new file mode 100644 index 0000000000..5aaae94476 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/slot.py @@ -0,0 +1,40 @@ +import flet as ft + + +class Slot(ft.Container): + def __init__(self, solitaire, slot_type, top, left, border): + super().__init__() + self.solitaire = solitaire + self.pile = [] + self.type = slot_type + self.width = 70 + self.height = 100 + self.left = left + self.top = top + self.border_radius = ft.BorderRadius.all(6) + self.border = border + self.on_click = self.click + + def get_top_card(self): + if len(self.pile) > 0: + return self.pile[-1] + + def get_top_three_cards(self): + n = len(self.pile) + return self.pile[max(0, n - 3) :] + + def fan_top_three(self): + for i, card in enumerate(self.get_top_three_cards()): + card.left = self.left + self.solitaire.card_offset * i + card.visible = True + + def upper_card_top(self): + if self.type == "tableau": + if len(self.pile) > 1: + return self.top + self.solitaire.card_offset * (len(self.pile) - 1) + return self.top + + def click(self, e): + if self.type == "stock" and self.solitaire.deck_passes_remaining > 1: + self.solitaire.deck_passes_remaining -= 1 + self.solitaire.restart_stock() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-final/solitaire.py b/sdk/python/examples/tutorials/solitaire/solitaire-final/solitaire.py new file mode 100644 index 0000000000..c0ec827d89 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-final/solitaire.py @@ -0,0 +1,192 @@ +# from settings import Settings +import random + +from card import Card +from slot import Slot + +import flet as ft + + +class Suite: + def __init__(self, suite_name, suite_color): + self.name = suite_name + self.color = suite_color + + +class Rank: + def __init__(self, card_name, card_value): + self.name = card_name + self.value = card_value + + +class Solitaire(ft.Stack): + def __init__(self, settings, on_win): + super().__init__() + self.width = 1000 + self.height = 500 + self.current_top = 0 + self.current_left = 0 + self.card_offset = 20 + self.settings = settings + self.deck_passes_remaining = int(self.settings.deck_passes_allowed) + self.controls = [] + self.on_win = on_win + + def did_mount(self): + self.create_slots() + self.create_card_deck() + self.deal_cards() + + def create_slots(self): + self.stock = Slot( + solitaire=self, slot_type="stock", top=0, left=0, border=ft.Border.all(1) + ) + + self.waste = Slot( + solitaire=self, slot_type="waste", top=0, left=100, border=None + ) + + self.foundation = [] + x = 300 + for i in range(4): + self.foundation.append( + Slot( + solitaire=self, + slot_type="foundation", + top=0, + left=x, + border=ft.Border.all(1, "outline"), + ) + ) + x += 100 + + self.tableau = [] + x = 0 + for i in range(7): + self.tableau.append( + Slot( + solitaire=self, + slot_type="tableau", + top=150, + left=x, + # border=ft.Border.all(1), + border=None, + ) + ) + x += 100 + + self.controls.append(self.stock) + self.controls.append(self.waste) + self.controls.extend(self.foundation) + self.controls.extend(self.tableau) + self.update() + + def create_card_deck(self): + suites = [ + Suite("hearts", "RED"), + Suite("diamonds", "RED"), + Suite("clubs", "BLACK"), + Suite("spades", "BLACK"), + ] + ranks = [ + Rank("Ace", 1), + Rank("2", 2), + Rank("3", 3), + Rank("4", 4), + Rank("5", 5), + Rank("6", 6), + Rank("7", 7), + Rank("8", 8), + Rank("9", 9), + Rank("10", 10), + Rank("Jack", 11), + Rank("Queen", 12), + Rank("King", 13), + ] + + self.cards = [] + + for suite in suites: + for rank in ranks: + file_name = f"{rank.name}_{suite.name}.svg" + # print(file_name) + self.cards.append(Card(solitaire=self, suite=suite, rank=rank)) + # self.stock = self.cards + random.shuffle(self.cards) + self.controls.extend(self.cards) + self.update() + + def deal_cards(self): + # Tableau + card_index = 0 + first_slot = 0 + while card_index <= 27: + for slot_index in range(first_slot, len(self.tableau)): + self.cards[card_index].place(self.tableau[slot_index]) + card_index += 1 + first_slot += 1 + + # Reveal top cards in slot piles: + for number in range(len(self.tableau)): + # self.tableau[number].pile[-1].turn_face_up() + self.tableau[number].get_top_card().turn_face_up() + + # Stock pile + for i in range(28, len(self.cards)): + self.cards[i].place(self.stock) + + def move_on_top(self, cards_to_drag): + """Brings draggable card pile to the top of the stack""" + + for card in cards_to_drag: + self.controls.remove(card) + self.controls.append(card) + self.update() + + def bounce_back(self, cards): + i = 0 + for card in cards: + card.top = self.current_top + if card.slot.type == "tableau": + card.top += i * self.card_offset + card.left = self.current_left + i += 1 + + def display_waste(self): + if self.settings.waste_size == 3: + self.waste.fan_top_three() + self.update() + + def restart_stock(self): + self.waste.pile.reverse() + while len(self.waste.pile) > 0: + card = self.waste.pile[0] + card.turn_face_down() + card.place(self.stock) + self.update() + + def check_foundation_rules(self, current_card, top_card=None): + if top_card is not None: + return ( + current_card.suite.name == top_card.suite.name + and current_card.rank.value - top_card.rank.value == 1 + ) + else: + return current_card.rank.name == "Ace" + + def check_tableau_rules(self, current_card, top_card=None): + if top_card is not None: + return ( + current_card.suite.color != top_card.suite.color + and top_card.rank.value - current_card.rank.value == 1 + ) + else: + return current_card.rank.name == "King" + + def check_if_you_won(self): + cards_num = 0 + for slot in self.foundation: + cards_num += len(slot.pile) + if cards_num == 52: + return True + return False diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_clubs.svg new file mode 100644 index 0000000000..55d98208ac --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_clubs.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_diamonds.svg new file mode 100644 index 0000000000..1286c25a5e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_diamonds.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_hearts.svg new file mode 100644 index 0000000000..73c6edd671 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_hearts.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_spades.svg new file mode 100644 index 0000000000..830135370d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/10_spades.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_clubs.svg new file mode 100644 index 0000000000..d623e9b404 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_clubs.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_diamonds.svg new file mode 100644 index 0000000000..26aa767cde --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_diamonds.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_hearts.svg new file mode 100644 index 0000000000..53afaa958e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_hearts.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_spades.svg new file mode 100644 index 0000000000..22fe99d7fc --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/2_spades.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_clubs.svg new file mode 100644 index 0000000000..dc06314904 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_clubs.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_diamonds.svg new file mode 100644 index 0000000000..1b8c766378 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_diamonds.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_hearts.svg new file mode 100644 index 0000000000..d5142bc196 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_hearts.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_spades.svg new file mode 100644 index 0000000000..aa3a137d75 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/3_spades.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_clubs.svg new file mode 100644 index 0000000000..32cb3c16c0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_clubs.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_diamonds.svg new file mode 100644 index 0000000000..a6858f8578 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_diamonds.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_hearts.svg new file mode 100644 index 0000000000..1acb9a6724 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_hearts.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_spades.svg new file mode 100644 index 0000000000..c49351766a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/4_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_clubs.svg new file mode 100644 index 0000000000..f41b8c3ec8 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_clubs.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_diamonds.svg new file mode 100644 index 0000000000..8cb1f09b84 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_diamonds.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_hearts.svg new file mode 100644 index 0000000000..fdf1a3ddf3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_spades.svg new file mode 100644 index 0000000000..9bf5500c73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/5_spades.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_clubs.svg new file mode 100644 index 0000000000..80e1931832 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_clubs.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_diamonds.svg new file mode 100644 index 0000000000..01f12ece8c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_diamonds.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_hearts.svg new file mode 100644 index 0000000000..04ae7766b7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_spades.svg new file mode 100644 index 0000000000..024adc16d2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/6_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_clubs.svg new file mode 100644 index 0000000000..79b2f62e3d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_clubs.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_diamonds.svg new file mode 100644 index 0000000000..2a38c99667 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_diamonds.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_hearts.svg new file mode 100644 index 0000000000..72f42fe94a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_hearts.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_spades.svg new file mode 100644 index 0000000000..7519ad6ca2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/7_spades.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_clubs.svg new file mode 100644 index 0000000000..452a8dd29a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_clubs.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_diamonds.svg new file mode 100644 index 0000000000..abf41a526f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_diamonds.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_hearts.svg new file mode 100644 index 0000000000..fd50551001 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_hearts.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_spades.svg new file mode 100644 index 0000000000..77ce108a2f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/8_spades.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_clubs.svg new file mode 100644 index 0000000000..b2749c0dbb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_clubs.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_diamonds.svg new file mode 100644 index 0000000000..eec88db012 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_diamonds.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_hearts.svg new file mode 100644 index 0000000000..66bc2770d0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_hearts.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_spades.svg new file mode 100644 index 0000000000..c21f4ac14e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/9_spades.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_clubs.svg new file mode 100644 index 0000000000..46b22496a3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_clubs.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_diamonds.svg new file mode 100644 index 0000000000..0745d5e321 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_diamonds.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_hearts.svg new file mode 100644 index 0000000000..70c5640276 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_hearts.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_spades.svg new file mode 100644 index 0000000000..2d015c67e0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Ace_spades.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_clubs.svg new file mode 100644 index 0000000000..4bcd40e03f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_clubs.svg @@ -0,0 +1,2103 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_diamonds.svg new file mode 100644 index 0000000000..c371d95b73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_diamonds.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_hearts.svg new file mode 100644 index 0000000000..6bd3a18cce --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_hearts.svg @@ -0,0 +1,2092 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_spades.svg new file mode 100644 index 0000000000..745ca85965 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Jack_spades.svg @@ -0,0 +1,2361 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_clubs.svg new file mode 100644 index 0000000000..173c31bd95 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_clubs.svg @@ -0,0 +1,2357 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_diamonds.svg new file mode 100644 index 0000000000..42cd892f9e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_diamonds.svg @@ -0,0 +1,1864 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_hearts.svg new file mode 100644 index 0000000000..ca382b506c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_hearts.svg @@ -0,0 +1,3106 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_spades.svg new file mode 100644 index 0000000000..73d1f69770 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/King_spades.svg @@ -0,0 +1,1771 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_clubs.svg new file mode 100644 index 0000000000..b041d9a2f4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_clubs.svg @@ -0,0 +1,2408 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_diamonds.svg new file mode 100644 index 0000000000..a2b9ef9805 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_diamonds.svg @@ -0,0 +1,1857 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_hearts.svg new file mode 100644 index 0000000000..4c5420c510 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_hearts.svg @@ -0,0 +1,2418 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_spades.svg new file mode 100644 index 0000000000..e2b9306800 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/Queen_spades.svg @@ -0,0 +1,2202 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/card_back.png b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/card_back.png new file mode 100644 index 0000000000..dd8b3416dc Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/assets/images/card_back.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/card.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/card.py new file mode 100644 index 0000000000..193932c892 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/card.py @@ -0,0 +1,157 @@ +import flet as ft + +CARD_WIDTH = 70 +CARD_HEIGHT = 100 +DROP_PROXIMITY = 30 +CARD_OFFSET = 20 + + +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + super().__init__() + self.mouse_cursor = ft.MouseCursor.MOVE + self.drag_interval = 5 + self.on_pan_start = self.start_drag + self.on_pan_update = self.drag + self.on_pan_end = self.drop + self.on_tap = self.click + self.on_double_tap = self.doubleclick + self.suite = suite + self.rank = rank + self.face_up = False + self.top = None + self.left = None + self.solitaire = solitaire + self.slot = None + self.content = ft.Container( + width=CARD_WIDTH, + height=CARD_HEIGHT, + border_radius=ft.BorderRadius.all(6), + content=ft.Image(src="/images/card_back.png"), + ) + self.draggable_pile = [self] + + def turn_face_up(self): + """Reveals card""" + self.face_up = True + self.content.content.src = f"/images/{self.rank.name}_{self.suite.name}.svg" + self.solitaire.update() + + def turn_face_down(self): + """Hides card""" + self.face_up = False + self.content.content.src = "/images/card_back.png" + self.solitaire.update() + + def move_on_top(self): + """Brings draggable card pile to the top of the stack""" + + for card in self.draggable_pile: + self.solitaire.controls.remove(card) + self.solitaire.controls.append(card) + self.solitaire.update() + + def bounce_back(self): + """Returns draggable pile to its original position""" + for card in self.draggable_pile: + if card.slot in self.solitaire.tableau: + card.top = card.slot.top + card.slot.pile.index(card) * CARD_OFFSET + else: + card.top = card.slot.top + card.left = card.slot.left + self.solitaire.update() + + def place(self, slot): + """Place draggable pile to the slot""" + + for card in self.draggable_pile: + if slot in self.solitaire.tableau: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + else: + card.top = slot.top + card.left = slot.left + + # remove card from it's original slot, if exists + if card.slot is not None: + card.slot.pile.remove(card) + + # change card's slot to a new slot + card.slot = slot + + # add card to the new slot's pile + slot.pile.append(card) + + self.solitaire.update() + + def get_draggable_pile(self): + """ + Returns a list of cards that will be dragged together, + starting with the current card. + """ + + if ( + self.slot is not None + and self.slot != self.solitaire.stock + and self.slot != self.solitaire.waste + ): + self.draggable_pile = self.slot.pile[self.slot.pile.index(self) :] + else: + # slot == None when the cards are dealt and + # need to be place in slot for the first time + self.draggable_pile = [self] + + def start_drag(self, e: ft.DragStartEvent): + if self.face_up: + self.get_draggable_pile() + self.move_on_top() + + def drag(self, e: ft.DragUpdateEvent): + if self.face_up: + for card in self.draggable_pile: + card.top = ( + max(0, self.top + e.local_delta.y) + + self.draggable_pile.index(card) * CARD_OFFSET + ) + card.left = max(0, self.left + e.local_delta.x) + self.solitaire.update() + + def drop(self, e: ft.DragEndEvent): + if self.face_up: + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) + < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_tableau_rules(self, slot): + self.place(slot) + return + + if len(self.draggable_pile) == 1: + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return + + self.bounce_back() + + def click(self, e): + self.get_draggable_pile() + if self.slot in self.solitaire.tableau: + if not self.face_up and len(self.draggable_pile) == 1: + self.turn_face_up() + elif self.slot == self.solitaire.stock: + self.move_on_top() + self.place(self.solitaire.waste) + self.turn_face_up() + + def doubleclick(self, e): + self.get_draggable_pile() + if self.face_up and len(self.draggable_pile) == 1: + self.move_on_top() + for slot in self.solitaire.foundations: + if self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/main.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/main.py new file mode 100644 index 0000000000..2b95e018f1 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/main.py @@ -0,0 +1,11 @@ +import flet as ft +from solitaire import Solitaire + + +def main(page: ft.Page): + solitaire = Solitaire() + + page.add(solitaire) + + +ft.run(main, assets_dir="assets") diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/slot.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/slot.py new file mode 100644 index 0000000000..8b1f46ed83 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/slot.py @@ -0,0 +1,26 @@ +import flet as ft + +SLOT_WIDTH = 70 +SLOT_HEIGHT = 100 + + +class Slot(ft.Container): + def __init__(self, solitaire, top, left, border): + super().__init__() + self.pile = [] + self.width = SLOT_WIDTH + self.height = SLOT_HEIGHT + self.left = left + self.top = top + self.on_click = self.click + self.solitaire = solitaire + self.border = border + self.border_radius = ft.BorderRadius.all(6) + + def get_top_card(self): + if len(self.pile) > 0: + return self.pile[-1] + + def click(self, e): + if self == self.solitaire.stock: + self.solitaire.restart_stock() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/solitaire.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/solitaire.py new file mode 100644 index 0000000000..deb04821c4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-rules/solitaire.py @@ -0,0 +1,144 @@ +import random + +from card import Card +from slot import Slot + +import flet as ft + +# CARD_OFFSET = 20 +SOLITAIRE_WIDTH = 1000 +SOLITAIRE_HEIGHT = 500 + + +class Suite: + def __init__(self, suite_name, suite_color): + self.name = suite_name + self.color = suite_color + + +class Rank: + def __init__(self, card_name, card_value): + self.name = card_name + self.value = card_value + + +class Solitaire(ft.Stack): + def __init__(self): + super().__init__() + self.controls = [] + self.width = SOLITAIRE_WIDTH + self.height = SOLITAIRE_HEIGHT + + def did_mount(self): + self.create_card_deck() + self.create_slots() + self.deal_cards() + + def create_card_deck(self): + suites = [ + Suite("hearts", "RED"), + Suite("diamonds", "RED"), + Suite("clubs", "BLACK"), + Suite("spades", "BLACK"), + ] + ranks = [ + Rank("Ace", 1), + Rank("2", 2), + Rank("3", 3), + Rank("4", 4), + Rank("5", 5), + Rank("6", 6), + Rank("7", 7), + Rank("8", 8), + Rank("9", 9), + Rank("10", 10), + Rank("Jack", 11), + Rank("Queen", 12), + Rank("King", 13), + ] + + self.cards = [] + + for suite in suites: + for rank in ranks: + self.cards.append(Card(solitaire=self, suite=suite, rank=rank)) + + def create_slots(self): + self.stock = Slot(solitaire=self, top=0, left=0, border=ft.Border.all(1)) + + self.waste = Slot(solitaire=self, top=0, left=100, border=None) + + self.foundations = [] + x = 300 + for i in range(4): + self.foundations.append( + Slot(solitaire=self, top=0, left=x, border=ft.Border.all(1, "outline")) + ) + x += 100 + + self.tableau = [] + x = 0 + for i in range(7): + self.tableau.append(Slot(solitaire=self, top=150, left=x, border=None)) + x += 100 + + self.controls.append(self.stock) + self.controls.append(self.waste) + self.controls.extend(self.foundations) + self.controls.extend(self.tableau) + self.update() + + def deal_cards(self): + random.shuffle(self.cards) + self.controls.extend(self.cards) + + # deal to tableau + first_slot = 0 + remaining_cards = self.cards + + while first_slot < len(self.tableau): + for slot in self.tableau[first_slot:]: + top_card = remaining_cards[0] + top_card.place(slot) + remaining_cards.remove(top_card) + first_slot += 1 + + # place remaining cards to stock pile + for card in remaining_cards: + card.place(self.stock) + print(f"Card in stock: {card.rank.name} {card.suite.name}") + + self.update() + + for slot in self.tableau: + slot.get_top_card().turn_face_up() + + self.update() + + def check_foundations_rules(self, card, slot): + top_card = slot.get_top_card() + if top_card is not None: + return ( + card.suite.name == top_card.suite.name + and card.rank.value - top_card.rank.value == 1 + ) + else: + return card.rank.name == "Ace" + + def check_tableau_rules(self, card, slot): + top_card = slot.get_top_card() + if top_card is not None: + return ( + card.suite.color != top_card.suite.color + and top_card.rank.value - card.rank.value == 1 + and top_card.face_up + ) + else: + return card.rank.name == "King" + + def restart_stock(self): + while len(self.waste.pile) > 0: + card = self.waste.get_top_card() + card.turn_face_down() + card.move_on_top() + card.place(self.stock) diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_clubs.svg new file mode 100644 index 0000000000..55d98208ac --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_clubs.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_diamonds.svg new file mode 100644 index 0000000000..1286c25a5e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_diamonds.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_hearts.svg new file mode 100644 index 0000000000..73c6edd671 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_hearts.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_spades.svg new file mode 100644 index 0000000000..830135370d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/10_spades.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_clubs.svg new file mode 100644 index 0000000000..d623e9b404 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_clubs.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_diamonds.svg new file mode 100644 index 0000000000..26aa767cde --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_diamonds.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_hearts.svg new file mode 100644 index 0000000000..53afaa958e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_hearts.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_spades.svg new file mode 100644 index 0000000000..22fe99d7fc --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/2_spades.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_clubs.svg new file mode 100644 index 0000000000..dc06314904 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_clubs.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_diamonds.svg new file mode 100644 index 0000000000..1b8c766378 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_diamonds.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_hearts.svg new file mode 100644 index 0000000000..d5142bc196 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_hearts.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_spades.svg new file mode 100644 index 0000000000..aa3a137d75 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/3_spades.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_clubs.svg new file mode 100644 index 0000000000..32cb3c16c0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_clubs.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_diamonds.svg new file mode 100644 index 0000000000..a6858f8578 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_diamonds.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_hearts.svg new file mode 100644 index 0000000000..1acb9a6724 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_hearts.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_spades.svg new file mode 100644 index 0000000000..c49351766a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/4_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_clubs.svg new file mode 100644 index 0000000000..f41b8c3ec8 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_clubs.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_diamonds.svg new file mode 100644 index 0000000000..8cb1f09b84 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_diamonds.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_hearts.svg new file mode 100644 index 0000000000..fdf1a3ddf3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_spades.svg new file mode 100644 index 0000000000..9bf5500c73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/5_spades.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_clubs.svg new file mode 100644 index 0000000000..80e1931832 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_clubs.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_diamonds.svg new file mode 100644 index 0000000000..01f12ece8c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_diamonds.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_hearts.svg new file mode 100644 index 0000000000..04ae7766b7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_spades.svg new file mode 100644 index 0000000000..024adc16d2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/6_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_clubs.svg new file mode 100644 index 0000000000..79b2f62e3d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_clubs.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_diamonds.svg new file mode 100644 index 0000000000..2a38c99667 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_diamonds.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_hearts.svg new file mode 100644 index 0000000000..72f42fe94a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_hearts.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_spades.svg new file mode 100644 index 0000000000..7519ad6ca2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/7_spades.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_clubs.svg new file mode 100644 index 0000000000..452a8dd29a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_clubs.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_diamonds.svg new file mode 100644 index 0000000000..abf41a526f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_diamonds.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_hearts.svg new file mode 100644 index 0000000000..fd50551001 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_hearts.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_spades.svg new file mode 100644 index 0000000000..77ce108a2f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/8_spades.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_clubs.svg new file mode 100644 index 0000000000..b2749c0dbb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_clubs.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_diamonds.svg new file mode 100644 index 0000000000..eec88db012 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_diamonds.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_hearts.svg new file mode 100644 index 0000000000..66bc2770d0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_hearts.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_spades.svg new file mode 100644 index 0000000000..c21f4ac14e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/9_spades.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_clubs.svg new file mode 100644 index 0000000000..46b22496a3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_clubs.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_diamonds.svg new file mode 100644 index 0000000000..0745d5e321 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_diamonds.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_hearts.svg new file mode 100644 index 0000000000..70c5640276 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_hearts.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_spades.svg new file mode 100644 index 0000000000..2d015c67e0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Ace_spades.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_clubs.svg new file mode 100644 index 0000000000..4bcd40e03f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_clubs.svg @@ -0,0 +1,2103 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_diamonds.svg new file mode 100644 index 0000000000..c371d95b73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_diamonds.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_hearts.svg new file mode 100644 index 0000000000..6bd3a18cce --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_hearts.svg @@ -0,0 +1,2092 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_spades.svg new file mode 100644 index 0000000000..745ca85965 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Jack_spades.svg @@ -0,0 +1,2361 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_clubs.svg new file mode 100644 index 0000000000..173c31bd95 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_clubs.svg @@ -0,0 +1,2357 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_diamonds.svg new file mode 100644 index 0000000000..42cd892f9e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_diamonds.svg @@ -0,0 +1,1864 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_hearts.svg new file mode 100644 index 0000000000..ca382b506c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_hearts.svg @@ -0,0 +1,3106 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_spades.svg new file mode 100644 index 0000000000..73d1f69770 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/King_spades.svg @@ -0,0 +1,1771 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_clubs.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_clubs.svg new file mode 100644 index 0000000000..b041d9a2f4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_clubs.svg @@ -0,0 +1,2408 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_diamonds.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_diamonds.svg new file mode 100644 index 0000000000..a2b9ef9805 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_diamonds.svg @@ -0,0 +1,1857 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_hearts.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_hearts.svg new file mode 100644 index 0000000000..4c5420c510 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_hearts.svg @@ -0,0 +1,2418 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_spades.svg b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_spades.svg new file mode 100644 index 0000000000..e2b9306800 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/Queen_spades.svg @@ -0,0 +1,2202 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/card_back.png b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/card_back.png new file mode 100644 index 0000000000..dd8b3416dc Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images/card_back.png differ diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/card.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/card.py new file mode 100644 index 0000000000..6351aa685b --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/card.py @@ -0,0 +1,118 @@ +import flet as ft + +CARD_WIDTH = 70 +CARD_HEIGHT = 100 +DROP_PROXIMITY = 30 +CARD_OFFSET = 20 + + +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + super().__init__() + self.mouse_cursor = ft.MouseCursor.MOVE + self.drag_interval = 5 + self.on_pan_start = self.start_drag + self.on_pan_update = self.drag + self.on_pan_end = self.drop + self.suite = suite + self.rank = rank + self.face_up = False + self.top = None + self.left = None + self.solitaire = solitaire + self.slot = None + self.content = ft.Container( + width=CARD_WIDTH, + height=CARD_HEIGHT, + border_radius=ft.BorderRadius.all(6), + content=ft.Image(src="/images/card_back.png"), + ) + self.draggable_pile = [self] + + def turn_face_up(self): + """Reveals card""" + self.face_up = True + self.content.content.src = f"/images/{self.rank.name}_{self.suite.name}.svg" + self.solitaire.update() + + def move_on_top(self): + """Brings draggable card pile to the top of the stack""" + + for card in self.draggable_pile: + self.solitaire.controls.remove(card) + self.solitaire.controls.append(card) + self.solitaire.update() + + def bounce_back(self): + """Returns draggable pile to its original position""" + for card in self.draggable_pile: + if card.slot in self.solitaire.tableau: + card.top = card.slot.top + card.slot.pile.index(card) * CARD_OFFSET + else: + card.top = card.slot.top + card.left = card.slot.left + self.solitaire.update() + + def place(self, slot): + """Place draggable pile to the slot""" + + for card in self.draggable_pile: + if slot in self.solitaire.tableau: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + else: + card.top = slot.top + card.left = slot.left + + # remove card from it's original slot, if exists + if card.slot is not None: + card.slot.pile.remove(card) + + # change card's slot to a new slot + card.slot = slot + + # add card to the new slot's pile + slot.pile.append(card) + + self.solitaire.update() + + def get_draggable_pile(self): + """returns list of cards that will be dragged together, starting with the current card""" + if self.slot is not None: + self.draggable_pile = self.slot.pile[self.slot.pile.index(self) :] + else: # slot == None when the cards are dealt and need to be place in slot for the first time + self.draggable_pile = [self] + + def start_drag(self, e: ft.DragStartEvent): + self.get_draggable_pile() + self.move_on_top() + self.solitaire.update() + + def drag(self, e: ft.DragUpdateEvent): + for card in self.draggable_pile: + card.top = ( + max(0, self.top + e.local_delta.y) + + self.draggable_pile.index(card) * CARD_OFFSET + ) + card.left = max(0, self.left + e.local_delta.x) + self.solitaire.update() + + def drop(self, e: ft.DragEndEvent): + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) + < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.solitaire.update() + return + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.solitaire.update() + return + + self.bounce_back() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/main.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/main.py new file mode 100644 index 0000000000..2b95e018f1 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/main.py @@ -0,0 +1,11 @@ +import flet as ft +from solitaire import Solitaire + + +def main(page: ft.Page): + solitaire = Solitaire() + + page.add(solitaire) + + +ft.run(main, assets_dir="assets") diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/slot.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/slot.py new file mode 100644 index 0000000000..110f7f3637 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/slot.py @@ -0,0 +1,20 @@ +SLOT_WIDTH = 70 +SLOT_HEIGHT = 100 + +import flet as ft + + +class Slot(ft.Container): + def __init__(self, top, left, border): + super().__init__() + self.pile = [] + self.width = SLOT_WIDTH + self.height = SLOT_HEIGHT + self.left = left + self.top = top + self.border = border + self.border_radius = ft.BorderRadius.all(6) + + def get_top_card(self): + if len(self.pile) > 0: + return self.pile[-1] diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/solitaire.py b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/solitaire.py new file mode 100644 index 0000000000..3991f7fb72 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/solitaire.py @@ -0,0 +1,115 @@ +import random + +from card import Card +from slot import Slot + +import flet as ft + +# CARD_OFFSET = 20 +SOLITAIRE_WIDTH = 1000 +SOLITAIRE_HEIGHT = 500 + + +class Suite: + def __init__(self, suite_name, suite_color): + self.name = suite_name + self.color = suite_color + + +class Rank: + def __init__(self, card_name, card_value): + self.name = card_name + self.value = card_value + + +class Solitaire(ft.Stack): + def __init__(self): + super().__init__() + self.controls = [] + self.width = SOLITAIRE_WIDTH + self.height = SOLITAIRE_HEIGHT + + def did_mount(self): + self.create_card_deck() + self.create_slots() + self.deal_cards() + + def create_card_deck(self): + suites = [ + Suite("hearts", "RED"), + Suite("diamonds", "RED"), + Suite("clubs", "BLACK"), + Suite("spades", "BLACK"), + ] + ranks = [ + Rank("Ace", 1), + Rank("2", 2), + Rank("3", 3), + Rank("4", 4), + Rank("5", 5), + Rank("6", 6), + Rank("7", 7), + Rank("8", 8), + Rank("9", 9), + Rank("10", 10), + Rank("Jack", 11), + Rank("Queen", 12), + Rank("King", 13), + ] + + self.cards = [] + + for suite in suites: + for rank in ranks: + self.cards.append(Card(solitaire=self, suite=suite, rank=rank)) + + def create_slots(self): + self.stock = Slot(top=0, left=0, border=ft.Border.all(1)) + + self.waste = Slot(top=0, left=100, border=None) + + self.foundations = [] + x = 300 + for i in range(4): + self.foundations.append( + Slot(top=0, left=x, border=ft.Border.all(1, "outline")) + ) + x += 100 + + self.tableau = [] + x = 0 + for i in range(7): + self.tableau.append(Slot(top=150, left=x, border=None)) + x += 100 + + self.controls.append(self.stock) + self.controls.append(self.waste) + self.controls.extend(self.foundations) + self.controls.extend(self.tableau) + self.update() + + def deal_cards(self): + random.shuffle(self.cards) + self.controls.extend(self.cards) + + # deal to tableau + first_slot = 0 + remaining_cards = self.cards + + while first_slot < len(self.tableau): + for slot in self.tableau[first_slot:]: + top_card = remaining_cards[0] + top_card.place(slot) + remaining_cards.remove(top_card) + first_slot += 1 + + # place remaining cards to stock pile + for card in remaining_cards: + card.place(self.stock) + + self.update() + + for slot in self.tableau: + slot.get_top_card().turn_face_up() + + self.update() diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-layout.drawio b/sdk/python/examples/tutorials/solitaire/solitaire-layout.drawio new file mode 100644 index 0000000000..a8e29fda0d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-layout.drawio @@ -0,0 +1 @@ +7Vzfj+I2EP5rkK4PeyJxEuDxFm57qlR1JVa9u0eXmGARYpSYA/rX1yYOSezABtZgU3ginjg//M3M5/F4QgcMF5vfU7ic/UlCFHfcbrjpgFHHdZ0+8NgPl2yFJHAHuSRKcShkpWCM/0VC2BXSFQ5RVutICYkpXtaFE5IkaEJrMpimZF3vNiVx/alLGCFFMJ7AWJV+xyGd5dK+3y3l3xCOZsWTna44s4BFZyHIZjAk64oIfO2AYUoIzY8WmyGKOXoFLvl1LwfO7l8sRQltc0E3ipIFHkTBC/07+PZH/+VtPn8Sd/kF45UYsHhZui0QSMkqCRG/SbcDntczTNF4CSf87JopnclmdBGzlsMOM5qSOfqLnceUq5zDAZ7xogqT6xWiAtGdRLwJSinaHByisweOmRwiC0TTLesiLvAE1MLY+qK5LhXXGwjZrKI0LxBCKIwl2t+5xJMdCEhPgdfXjG8Is9mur6MHMb+OmBuokAVNkDngYpAFlkMGJMwGKmTgupC5mhHTAFJQx2jPilVXbMKoeymMgH0YOdaB5NkHErAOJN2Urt/b3J5nGCPdHH4BbzMPUs8+kOyzpL59IMmUZB6kgX0gedaBVKwobULJtw8l3StCHdObfShZGHLLHmc+UnIsDLplj7MAJQujbtnjLECpKVoKYsqHzsYSRPxoTGJMIU4R6xjDLVnRog97ZtlNgZcBRZvyWEMSk5RJEpKwns9THMeSKOOZriRiAr9svRGmkdGTe0hXhOlmGu9ygTMchihhsrqGdecsmpIUTlOSwr+Y/tRAbkzJZM6HgZke9KkExjhiiI4mDBvE5M8cOTyB8RdxYsEw549p1M0RPUxJQkWC2gk0hZKymylaChqUdLncmxpIvnA8IMUkEZrK7lRVfl8KQgzrylUDte8wo+hGHcq/VE7NsJZaBIooCb/wnSoOcQyzDE/qeqojiDaY/uDHn33R+lk5M9pUG1vRyB+JQmWrS4KVvRZZpRN0jCJEaofCNEL0WMdBs6IqmvCPTEApihnr/Kq/cJN6xBNeCWZDqewESd7alzScD1RcVSpZvZG8QyKbSg6EcqOdteyH/QEDahFDn2ZAsteVBgX6QdWkPnedo1bFG68oxWyInBZ0W5rb1tD6VhlaT5ehuVc2tBbLEF2GZoS5QEt7OjTDPOzpNHtS90ne4D8xgism/DSFScIMRYSUv91ptAJ8v6YjD6jhiuMdMTb98UqLnRttLODVp5vBIDA53xS1Gu8ThG8VQQx0EYR3ZYJQMzqfKFl2eNqENfgwhzyPg6a0lN0cU7gfZIqCGQyvY8Bp6xiB8EFS2NfCKdjxxiukTCHJTuLugtBsjuhkVly8029RO9YEOAM13f4oaIM3flYbJb3sWheINQrbfp9LTFKJUycApUCpLZNIa255qXVhHgHqCmnHI1ypJYPsShHvjj32iq5ryDibnLbWuHc2yS3cGEvooomD9W7XIgp1RdJIFOB+iQLYRhSnLUfuniiMrkyALqI4WPN5LaJQt8EaiSK4X6KQCwRME0Xx/AdRtCMKo5szgbaFh2Gi8NQ92Eai8O6XKDzHMqJoUb5/60TRvNFyfDNPI7kUXvH+zp3R7Mf/JpHqqUFyLZHq+I9UaoWRnlxJXaZrRLwWH4LcOiXppJfAJGtI0xnoemeGLgdK2q/FGWo5ZgvOuOMUqlz9Z5w0Wnzz8yANyd5tSaGezRoHP2K8Em0UeDxoo+3Oi2284bf4vuvBG5LBm+INbdGG6XDDd8/hjUd+Va3eM8Ybp9Uh3z1vGE1tyAnW81cppnnj3KLkjL0YPaFK8cL22NayTBlMTwpTfDmF1dZg5BtduRbIV7O71W9CBXLF/OIXGcDbml5SQvMP8sBoUNLWh6abnpwTa/gfMKfJ/uSicn3zzbmFyA/PP8nzpb/M238ef6rj98E7N7q056tJ1Krn52BWFqQ36fkaPF2urfCbPB3oiSxZs/x7y1zR5b+Egq//AQ== diff --git a/sdk/python/examples/tutorials/solitaire/solitaire-layout.svg b/sdk/python/examples/tutorials/solitaire/solitaire-layout.svg new file mode 100644 index 0000000000..c1f71305f8 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire/solitaire-layout.svg @@ -0,0 +1,4 @@ + + + +

Solitaire layout

Solitaire layout
Stock pile
Stock p...
Foundation piles
Foundat...
Waste pile
Waste pi...
Tableau (fanned piles)
Tableau (fanned pil...
(top=0, left=0)
(top=0, le...
(top=0, left=100)
(top=0, le...
(top=0, left=300)
(top=0, le...
(top=0, left=600)
(top=0, le...
(top=0, left=400)
(top=0, le...
(top=150, left=0)
(top=150,...
(top=150, left=100)
(top=150,...
(top=150, left=100)
(top=150,...
(top=150, left=600)
(top=150,...
Solitaire height = 500
Solitaire height = 500
Solitaire width = 1000
Solitaire width = 1000
Text is not SVG - cannot display
diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step1_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step1_field_gd.py new file mode 100644 index 0000000000..b8be8c8e35 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step1_field_gd.py @@ -0,0 +1,96 @@ +# Step 1: Basic drag-and-drop of rectangles (cards) within a bounded area. + +from dataclasses import dataclass, field + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Card: + top: float = 0 + left: float = 0 + color: str = ft.Colors.GREEN + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(left=0, top=0, color=ft.Colors.GREEN), + Card(left=100, top=0, color=ft.Colors.RED), + ], + ) + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + # Pure view: just render from state + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(Game()) + dragging, set_dragging = ft.use_state(None) # None or Card being dragged + + def point_in_card(x: float, y: float) -> Card | None: + for c in state.cards: + if (c.left <= x <= c.left + CARD_W) and (c.top <= y <= c.top + CARD_H): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def on_pan_start(e: ft.DragStartEvent): + # Only start dragging if pointer is inside the card + # e.local_position.x / e.local_position.y are relative to the GestureDetector + # content (the Stack) + grabbed = point_in_card(e.local_position.x, e.local_position.y) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + c = dragging + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + + def on_pan_end(e: ft.DragEndEvent): + set_dragging(None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[CardView(c) for c in state.cards], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step2.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step2.py new file mode 100644 index 0000000000..dbe9040073 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step2.py @@ -0,0 +1,83 @@ +from dataclasses import dataclass + +import flet as ft + + +@dataclass +@ft.observable +class GameState: + # card position + card_left: float = 0 + card_top: float = 0 + + # slot position + slot_left: float = 200 + slot_top: float = 0 + + # remember where the drag started (to bounce back) + drag_start_left: float = 0 + drag_start_top: float = 0 + + # snap threshold in px + snap_threshold: float = 20 + + +@ft.component +def App(): + s, _ = ft.use_state(GameState()) + + def on_pan_start(e: ft.DragStartEvent): + # capture where the card was when the drag started + s.drag_start_left = s.card_left + s.drag_start_top = s.card_top + + def on_pan_update(e: ft.DragUpdateEvent): + # move by delta (no control mutation) + s.card_left = max(0, s.card_left + e.local_delta.x) + s.card_top = max(0, s.card_top + e.local_delta.y) + + def on_pan_end(e: ft.DragEndEvent): + # snap to slot if close enough, otherwise bounce back + near_x = abs(s.card_left - s.slot_left) < s.snap_threshold + near_y = abs(s.card_top - s.slot_top) < s.snap_threshold + if near_x and near_y: + s.card_left = s.slot_left + s.card_top = s.slot_top + else: + s.card_left = s.drag_start_left + s.card_top = s.drag_start_top + + return ft.Stack( + width=1000, + height=500, + controls=[ + # drop slot (purely a function of state) + ft.Container( + left=s.slot_left, + top=s.slot_top, + width=70, + height=100, + border=ft.Border.all(1, ft.Colors.BLACK45), + border_radius=5, + ), + # draggable card + ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + left=s.card_left, + top=s.card_top, + content=ft.Container( + width=70, + height=100, + bgcolor=ft.Colors.GREEN, + border_radius=5, + ), + ), + ], + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step2_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step2_field_gd.py new file mode 100644 index 0000000000..14c825a435 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step2_field_gd.py @@ -0,0 +1,147 @@ +# Step 2: Place the card into a slot if close enough when dropped, otherwise bounce +# to deck. + +from dataclasses import dataclass, field + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Card: + top: float = 0 + left: float = 0 + color: str = ft.Colors.GREEN + home: str = "deck" # "deck" or Slot.id + + +@ft.observable +@dataclass +class Slot: + id: str = "slot1" + top: float = 200 + left: float = 0 + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(left=0, top=0, color=ft.Colors.GREEN, home="deck"), + Card(left=100, top=0, color=ft.Colors.RED, home="waste"), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=0, top=200, id="slot1"), + Slot(left=100, top=200, id="slot2"), + ], + ) + snap_threshold: float = 20 # px + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + # Pure view: just render from state + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(Game()) + dragging, set_dragging = ft.use_state(None) # None or Card being dragged + + def point_in_card(x: float, y: float) -> Card | None: + for c in state.cards: + if (c.left <= x <= c.left + CARD_W) and (c.top <= y <= c.top + CARD_H): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def on_pan_start(e: ft.DragStartEvent): + # Only start dragging if pointer is inside the card + # e.local_position.x / e.local_position.y are relative to the GestureDetector + # content (the Stack) + grabbed = point_in_card(e.local_position.x, e.local_position.y) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + c = dragging + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + + def on_pan_end(e: ft.DragEndEvent): + c = dragging + if c is None: + return + # snap to slot if close enough + moved = False + for s in state.slots: + near_x = abs(c.left - s.left) < state.snap_threshold + near_y = abs(c.top - s.top) < state.snap_threshold + if near_x and near_y: + c.left = s.left + c.top = s.top + c.home = s.id + moved = True + if not moved: + # bounce back to deck position + c.left = 0 + c.top = 0 + c.home = "deck" + + set_dragging(None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[SlotView(s) for s in state.slots] + + [CardView(c) for c in state.cards], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step3.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step3.py new file mode 100644 index 0000000000..a46f8bc918 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step3.py @@ -0,0 +1,100 @@ +from dataclasses import dataclass, field + +import flet as ft + + +@dataclass +@ft.observable +class Card: + id: str + left: float + top: float + color: str + home: str = "deck" # "deck" or "slot" + + +@dataclass +@ft.observable +class GameState: + slot_left: float = 200 + slot_top: float = 0 + snap_threshold: float = 20 + cards: list[Card] = field( + default_factory=lambda: [ + Card(id="card1", left=0, top=0, color=ft.Colors.GREEN), + Card(id="card2", left=100, top=0, color=ft.Colors.YELLOW), + ] + ) + + def bring_to_top(self, card: Card): + self.cards.remove(card) + self.cards.append(card) + + +@ft.component +def CardView(card: Card, state: GameState, key=None) -> ft.Control: + drag_start_pos, set_drag_start_pos = ft.use_state((card.left, card.top)) + + def on_pan_start(e: ft.DragStartEvent): + state.bring_to_top(card) + print("drag start", card.id, card.left, card.top, card.color) + set_drag_start_pos((card.left, card.top)) + + def on_pan_update(e: ft.DragUpdateEvent): + print("drag update", card.id, card.left, card.top, card.color) + card.left = max(0, card.left + e.local_delta.x) + card.top = max(0, card.top + e.local_delta.y) + + def on_pan_end(e: ft.DragEndEvent): + print("drag end", card.id, card.left, card.top, card.color) + near_x = abs(card.left - state.slot_left) < state.snap_threshold + near_y = abs(card.top - state.slot_top) < state.snap_threshold + if near_x and near_y: + card.left = state.slot_left + card.top = state.slot_top + else: + card.left = drag_start_pos[0] + card.top = drag_start_pos[1] + + return ft.GestureDetector( + key=card.id, + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + left=card.left, + top=card.top, + content=ft.Container( + bgcolor=card.color, + width=70, + height=100, + border_radius=5, + ), + ) + + +@ft.component +def App(): + state, _ = ft.use_state(GameState()) + + return ft.Stack( + width=1000, + height=500, + controls=[ + # Slot + ft.Container( + left=state.slot_left, + top=state.slot_top, + width=70, + height=100, + border=ft.Border.all(1, ft.Colors.BLACK45), + border_radius=5, + ), + # Cards (order in list = z-order) + *[CardView(c, state, key=c.id) for c in state.cards], + ], + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step3_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step3_field_gd.py new file mode 100644 index 0000000000..c5e061e02f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step3_field_gd.py @@ -0,0 +1,153 @@ +# Step 3: Place the card into a slot if close enough when dropped, otherwise bounce +# back to slot. + +from dataclasses import dataclass, field + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Card: + top: float = 0 + left: float = 0 + color: str = ft.Colors.GREEN + home: str = "deck" # "deck" or Slot.id + + +@ft.observable +@dataclass +class Slot: + id: str = "slot1" + top: float = 200 + left: float = 0 + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(left=0, top=0, color=ft.Colors.GREEN, home="deck"), + Card(left=100, top=0, color=ft.Colors.RED, home="waste"), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=0, top=200, id="slot1"), + Slot(left=100, top=200, id="slot2"), + ], + ) + snap_threshold: float = 20 # px + + def find_slot_by_id(self, slot_id: str) -> Slot | None: + for s in self.slots: + if s.id == slot_id: + return s + return None + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + # Pure view: just render from state + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(Game()) + dragging, set_dragging = ft.use_state(None) # None or Card being dragged + + def point_in_card(x: float, y: float) -> Card | None: + for c in state.cards: + if (c.left <= x <= c.left + CARD_W) and (c.top <= y <= c.top + CARD_H): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def on_pan_start(e: ft.DragStartEvent): + # Only start dragging if pointer is inside the card + # e.local_position.x / e.local_position.y are relative to the GestureDetector + # content (the Stack) + grabbed = point_in_card(e.local_position.x, e.local_position.y) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + c = dragging + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + + def on_pan_end(e: ft.DragEndEvent): + c = dragging + if c is None: + return + # snap to slot if close enough + moved = False + for s in state.slots: + near_x = abs(c.left - s.left) < state.snap_threshold + near_y = abs(c.top - s.top) < state.snap_threshold + if near_x and near_y: + c.left = s.left + c.top = s.top + c.home = s.id + moved = True + if not moved: + # bounce back to home position + home_slot = state.find_slot_by_id(c.home) + c.left = home_slot.left if home_slot else 0 + c.top = home_slot.top if home_slot else 0 + + set_dragging(None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[SlotView(s) for s in state.slots] + + [CardView(c) for c in state.cards], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step4.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step4.py new file mode 100644 index 0000000000..041004879a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step4.py @@ -0,0 +1,129 @@ +from dataclasses import dataclass, field + +import flet as ft + + +@dataclass +@ft.observable +class Card: + id: str + left: float + top: float + color: str + home: str = "deck" # "deck" or "slot" + + +@dataclass +@ft.observable +class Slot: + id: str + left: float + top: float + home: str = "deck" # "deck" or "slot" + + +@dataclass +@ft.observable +class GameState: + slot_left: float = 200 + slot_top: float = 0 + snap_threshold: float = 20 + cards: list[Card] = field( + default_factory=lambda: [ + Card(id="card1", left=0, top=0, color=ft.Colors.GREEN), + Card(id="card2", left=100, top=0, color=ft.Colors.YELLOW), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(id="slot1", left=200, top=0), + ] + ) + + def bring_to_top(self, card: Card): + self.cards.remove(card) + self.cards.append(card) + + +@ft.component +def CardView(card: Card, state: GameState, key=None) -> ft.Control: + drag_start_pos, set_drag_start_pos = ft.use_state((card.left, card.top)) + + def on_pan_start(e: ft.DragStartEvent): + state.bring_to_top(card) + print("drag start", card.id, card.left, card.top, card.color) + set_drag_start_pos((card.left, card.top)) + + def on_pan_update(e: ft.DragUpdateEvent): + print("drag update", card.id, card.left, card.top, card.color) + card.left = max(0, card.left + e.local_delta.x) + card.top = max(0, card.top + e.local_delta.y) + + def on_pan_end(e: ft.DragEndEvent): + print("drag end", card.id, card.left, card.top, card.color) + near_x = abs(card.left - state.slot_left) < state.snap_threshold + near_y = abs(card.top - state.slot_top) < state.snap_threshold + if near_x and near_y: + card.left = state.slot_left + card.top = state.slot_top + else: + card.left = drag_start_pos[0] + card.top = drag_start_pos[1] + + return ft.GestureDetector( + key=card.id, + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + left=card.left, + top=card.top, + content=ft.Container( + bgcolor=card.color, + width=70, + height=100, + border_radius=5, + ), + ) + + +@ft.component +def SlotView(slot: Slot, state: GameState, key=None) -> ft.Control: + return ft.Container( + key=slot.id, + left=slot.left, + top=slot.top, + width=70, + height=100, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + ) + + +@ft.component +def App(): + state, _ = ft.use_state(GameState()) + + return ft.Stack( + width=1000, + height=500, + controls=[ + # Slot + ft.Container( + left=state.slot_left, + top=state.slot_top, + width=70, + height=100, + border=ft.Border.all(1, ft.Colors.BLACK45), + border_radius=5, + ), + # Slots (order in list = z-order) + *[SlotView(s, state, key=s.id) for s in state.slots], + # Cards (order in list = z-order) + *[CardView(c, state, key=c.id) for c in state.cards], + ], + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step4_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step4_field_gd.py new file mode 100644 index 0000000000..e743f6649e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step4_field_gd.py @@ -0,0 +1,174 @@ +# Step 4: Place the card into a slot if close enough when dropped, otherwise +# bounce back to its home slot. Card.home is a Slot, not a string. + +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Slot: + id: str = "slot1" + top: float = 200 + left: float = 0 + + +@ft.observable +@dataclass +class Card: + top: float = 0 + left: float = 0 + color: str = ft.Colors.GREEN + home: Optional[Slot] = None # <-- reference to a Slot, not a string + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(color=ft.Colors.GREEN), # positions will be set in __post_init__ + Card(color=ft.Colors.RED), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=0, top=200, id="slot1"), + Slot(left=100, top=200, id="slot2"), + ], + ) + snap_threshold: float = 20 # px + + # def find_slot_by_id(self, slot_id: str) -> Optional[Slot]: + # for s in self.slots: + # if s.id == slot_id: + # return s + # return None + + def __post_init__(self): + """Initialize homes & coordinates: card1 -> deck, card2 -> waste.""" + # deck = self.find_slot_by_id("deck") + # waste = self.find_slot_by_id("waste") + + # if len(self.cards) >= 1 and deck: + # c1 = self.cards[0] + # c1.home = deck + # c1.left, c1.top = deck.left, deck.top + + # if len(self.cards) >= 2 and waste: + # c2 = self.cards[1] + # c2.home = waste + # c2.left, c2.top = waste.left, waste.top + self.cards[0].home = self.slots[0] + self.cards[0].left, self.cards[0].top = self.slots[0].left, self.slots[0].top + self.cards[1].home = self.slots[1] + self.cards[1].left, self.cards[1].top = self.slots[1].left, self.slots[1].top + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + content=ft.Text(slot.id, size=10, color=ft.Colors.BLACK45), + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(Game()) + dragging, set_dragging = ft.use_state(None) # None or Card + + def point_in_card(x: float, y: float) -> Optional[Card]: + # Check topmost first so you can grab the card on top + for c in reversed(state.cards): + if (c.left <= x <= c.left + CARD_W) and (c.top <= y <= c.top + CARD_H): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def on_pan_start(e: ft.DragStartEvent): + grabbed = point_in_card(e.local_position.x, e.local_position.y) + print("grabbed", grabbed) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + c = dragging + print("moving", c) + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + + def on_pan_end(_: ft.DragEndEvent): + c = dragging + if c is None: + return + + # Try to snap to a nearby slot; otherwise bounce back to c.home + snapped = False + for s in state.slots: + near_x = abs(c.left - s.left) < state.snap_threshold + near_y = abs(c.top - s.top) < state.snap_threshold + if near_x and near_y: + c.left, c.top = s.left, s.top + c.home = s # <-- update to the Slot object + snapped = True + break + + if not snapped and c.home is not None: + c.left, c.top = c.home.left, c.home.top + + set_dragging(None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[ + *(SlotView(s) for s in state.slots), + *(CardView(c) for c in state.cards), + ], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step5_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step5_field_gd.py new file mode 100644 index 0000000000..3d20cf2d56 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step5_field_gd.py @@ -0,0 +1,167 @@ +# Step 5: Slot has piles of Cards. When a Card is dropped into a Slot, it becomes part +# of that Slot's pile (Slot.cards). + +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Slot: + id: str = "slot1" + top: float = 200 + left: float = 0 + cards: list["Card"] = field(default_factory=list) + + +@ft.observable +@dataclass +class Card: + top: float = 0 + left: float = 0 + color: str = ft.Colors.GREEN + home: Optional[Slot] = None # <-- reference to a Slot, not a string + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(color=ft.Colors.GREEN), # positions will be set in __post_init__ + Card(color=ft.Colors.RED), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=0, top=200, id="slot1"), + Slot(left=100, top=200, id="slot2"), + ], + ) + snap_threshold: float = 20 # px + + def __post_init__(self): + """Initialize homes & coordinates: card1 -> deck, card2 -> waste.""" + + # Set initial homes and positions + self.cards[0].home = self.slots[0] + self.cards[0].left, self.cards[0].top = self.slots[0].left, self.slots[0].top + self.cards[1].home = self.slots[1] + self.cards[1].left, self.cards[1].top = self.slots[1].left, self.slots[1].top + + # Add cards to slots' card lists + self.slots[0].cards.append(self.cards[0]) + self.slots[1].cards.append(self.cards[1]) + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + content=ft.Text(slot.id, size=10, color=ft.Colors.BLACK45), + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(Game()) + dragging, set_dragging = ft.use_state(None) # None or Card + + def point_in_card(x: float, y: float) -> Optional[Card]: + # Check topmost first so you can grab the card on top + for c in reversed(state.cards): + if (c.left <= x <= c.left + CARD_W) and (c.top <= y <= c.top + CARD_H): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def on_pan_start(e: ft.DragStartEvent): + grabbed = point_in_card(e.local_position.x, e.local_position.y) + print("grabbed", grabbed) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + c = dragging + print("moving", c) + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + + def on_pan_end(_: ft.DragEndEvent): + c = dragging + if c is None: + return + + # Try to snap to a nearby slot; otherwise bounce back to c.home + snapped = False + for s in state.slots: + near_x = abs(c.left - s.left) < state.snap_threshold + near_y = abs(c.top - s.top) < state.snap_threshold + if near_x and near_y: + c.left, c.top = s.left, s.top + c.home.cards.remove(c) # Remove card from previous slot's pile + c.home = s # <-- update to the Slot object + s.cards.append(c) # Add card to the slot's pile + snapped = True + break + + if not snapped and c.home is not None: + c.left, c.top = c.home.left, c.home.top + + set_dragging(None) + print("dropped", c) + print("slot now has cards:", len(c.home.cards) if c.home else None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[ + *(SlotView(s) for s in state.slots), + *(CardView(c) for c in state.cards), + ], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step6_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step6_field_gd.py new file mode 100644 index 0000000000..333af7c2bf --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step6_field_gd.py @@ -0,0 +1,198 @@ +# Step 6: Put cards into slot1, slot2, slot3 with offset, in other slots without offset. + +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Slot: + id: str + top: float + left: float + cards: list["Card"] = field(default_factory=list) + stacking: bool = False # whether cards in this slot stack with offset + + +@ft.observable +@dataclass +class Card: + top: float = 0 + left: float = 0 + color: str = ft.Colors.GREEN + home: Optional[Slot] = None # <-- reference to a Slot, not a string + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(color=ft.Colors.GREEN), # positions will be set in __post_init__ + Card(color=ft.Colors.RED), + Card(color=ft.Colors.BLUE), + Card(color=ft.Colors.YELLOW), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=200, top=0, id="foundation1"), + Slot(left=300, top=0, id="foundation2"), + Slot(left=0, top=200, id="slot1", stacking=True), + Slot(left=100, top=200, id="slot2", stacking=True), + Slot(left=200, top=200, id="slot3", stacking=True), + ], + ) + snap_threshold: float = 20 # px + + def __post_init__(self): + """Initialize homes & coordinates: card1 -> deck, card2 -> waste.""" + + # Set initial homes and positions + # self.cards[0].home = self.slots[0] + # self.cards[0].left, self.cards[0].top = self.slots[0].left, self.slots[0].top + # self.cards[1].home = self.slots[1] + # self.cards[1].left, self.cards[1].top = self.slots[1].left, self.slots[1].top + for card in self.cards: + card.home = self.slots[0] + card.left, card.top = self.slots[0].left, self.slots[0].top + + # Add cards to slots' card lists + self.slots[0].cards = self.cards.copy() + print("deck has cards:", len(self.slots[0].cards)) + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 +SNAP_THRESHOLD = 20 # px +OFFSET_Y = 20 # px + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + content=ft.Text(slot.id, size=10, color=ft.Colors.BLACK45), + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(lambda: Game()) + dragging, set_dragging = ft.use_state(None) # None or Card + start_x, set_start_x = ft.use_state(0) + start_y, set_start_y = ft.use_state(0) + + print("Current cards in deck:", len(state.slots[0].cards)) + + def point_in_card(x: float, y: float) -> Optional[Card]: + # Check topmost first so you can grab the card on top + for c in reversed(state.cards): + if ( + (c.left <= x <= c.left + CARD_W) + and (c.top <= y <= c.top + CARD_H) + and (c.home.cards.index(c) == len(c.home.cards) - 1) + ): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def on_pan_start(e: ft.DragStartEvent): + grabbed = point_in_card(e.local_position.x, e.local_position.y) + print("grabbed", grabbed) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + set_start_x(grabbed.left) + set_start_y(grabbed.top) + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + dragging.left = max(0, dragging.left + e.local_delta.x) + dragging.top = max(0, dragging.top + e.local_delta.y) + + def on_pan_end(_: ft.DragEndEvent): + if dragging is None: + return + + # Try to snap to a nearby slot; otherwise bounce back to dragging.home + # with offset if stacking + snapped = False + for s in state.slots: + if s != dragging.home: + offset = ( + (len(s.cards) - 1) * OFFSET_Y + if s.stacking and len(s.cards) > 0 + else 0 + ) + near_x = abs(dragging.left - s.left) < SNAP_THRESHOLD + near_y = abs(dragging.top - (s.top + offset)) < SNAP_THRESHOLD + if near_x and near_y: + dragging.left, dragging.top = ( + s.left, + s.top + OFFSET_Y * len(s.cards) if s.stacking else s.top, + ) + dragging.home.cards.remove( + dragging + ) # Remove card from previous slot's pile + dragging.home = s # <-- update to the Slot object + s.cards.append(dragging) # Add card to the slot's pile + snapped = True + break + + if not snapped: + dragging.left, dragging.top = start_x, start_y + + set_dragging(None) + print("dropped", dragging) + print( + "slot now has cards:", len(dragging.home.cards) if dragging.home else None + ) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[ + *(SlotView(s) for s in state.slots), + *(CardView(c) for c in state.cards), + ], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step7_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step7_field_gd.py new file mode 100644 index 0000000000..b4743b9352 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step7_field_gd.py @@ -0,0 +1,197 @@ +# Step 7: Refactor calculations to be more readable and maintainable. + +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Slot: + id: str + top: float + left: float + cards: list["Card"] = field(default_factory=list) + stacking: bool = False # whether cards in this slot stack with offset + + +@ft.observable +@dataclass +class Card: + color: str + top: float = 0 + left: float = 0 + home: Optional[Slot] = None # <-- reference to a Slot, not a string + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(color=ft.Colors.GREEN), # positions will be set in __post_init__ + Card(color=ft.Colors.RED), + Card(color=ft.Colors.BLUE), + Card(color=ft.Colors.YELLOW), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=200, top=0, id="foundation1"), + Slot(left=300, top=0, id="foundation2"), + Slot(left=0, top=200, id="slot1", stacking=True), + Slot(left=100, top=200, id="slot2", stacking=True), + Slot(left=200, top=200, id="slot3", stacking=True), + ], + ) + # snap_threshold: float = 20 # px + + def __post_init__(self): + """Initialize homes & coordinates: card1 -> deck, card2 -> waste.""" + + # Set initial homes and positions + # self.cards[0].home = self.slots[0] + # self.cards[0].left, self.cards[0].top = self.slots[0].left, self.slots[0].top + # self.cards[1].home = self.slots[1] + # self.cards[1].left, self.cards[1].top = self.slots[1].left, self.slots[1].top + for card in self.cards: + card.home = self.slots[0] + card.left, card.top = self.slots[0].left, self.slots[0].top + + # Add cards to slots' card lists + self.slots[0].cards = self.cards.copy() + print("deck has cards:", len(self.slots[0].cards)) + + +# Card visual constants +CARD_W = 70 +CARD_H = 100 +SNAP_THRESHOLD = 20 # px +OFFSET_Y = 20 # px + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + content=ft.Text(slot.id, size=10, color=ft.Colors.BLACK45), + ) + + +# ---------- App ---------- +@ft.component +def App(): + state, _ = ft.use_state(lambda: Game()) + dragging, set_dragging = ft.use_state(None) # None or Card being dragged + start_x, set_start_x = ft.use_state(0) # initial x of the card being dragged + start_y, set_start_y = ft.use_state(0) # initial y of the card being dragged + + print("Current cards in deck:", len(state.slots[0].cards)) + + def point_in_card(x: float, y: float) -> Optional[Card]: + # Check topmost first so you can grab the card on top + for c in reversed(state.cards): + if ( + (c.left <= x <= c.left + CARD_W) + and (c.top <= y <= c.top + CARD_H) + and ( + c.home.cards.index(c) == len(c.home.cards) - 1 + ) # is topmost in its slot + ): + return c + return None + + def move_to_top(card: Card): + state.cards.remove(card) + state.cards.append(card) + + def nearest_slot(card: Card) -> Optional[Slot]: + """Return the nearest slot to the card within SNAP_THRESHOLD, or None.""" + for s in state.slots: + if s != card.home: + offset = ( + (len(s.cards) - 1) * OFFSET_Y + if s.stacking and len(s.cards) > 0 + else 0 + ) + near_x = abs(card.left - s.left) < SNAP_THRESHOLD + near_y = abs(card.top - (s.top + offset)) < SNAP_THRESHOLD + if near_x and near_y: + return s + return None + + def on_pan_start(e: ft.DragStartEvent): + grabbed = point_in_card(e.local_position.x, e.local_position.y) + print("grabbed", grabbed) + set_dragging(grabbed) + if grabbed is not None: + move_to_top(grabbed) + set_start_x(grabbed.left) # remember initial x of the card being dragged + set_start_y(grabbed.top) # remember initial y of the card being dragged + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + dragging.left = max(0, dragging.left + e.local_delta.x) + dragging.top = max(0, dragging.top + e.local_delta.y) + + def on_pan_end(_: ft.DragEndEvent): + if dragging is None: + return + + s = nearest_slot(dragging) + if s is not None: # snap to this slot + dragging.left, dragging.top = ( + s.left, + s.top + OFFSET_Y * len(s.cards) if s.stacking else s.top, + ) + dragging.home.cards.remove( + dragging + ) # Remove card from previous slot's pile + dragging.home = s # <-- update to the Slot object + s.cards.append(dragging) # Add card to the slot's pile + else: # bounce back to where it was picked up + dragging.left, dragging.top = start_x, start_y + + set_dragging(None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[ + *(SlotView(s) for s in state.slots), + *(CardView(c) for c in state.cards), + ], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step8_field_gd.py b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step8_field_gd.py new file mode 100644 index 0000000000..c5ec218931 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/drag-and-drop/step8_field_gd.py @@ -0,0 +1,192 @@ +# Step 8: Move piles of cards from stackable slots to stackable slots. + +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + +# Card visual constants +CARD_W = 70 +CARD_H = 100 +SNAP_THRESHOLD = 20 # px +OFFSET_Y = 20 # px + + +# ---------- Model ---------- +@ft.observable +@dataclass +class Slot: + id: str + top: float + left: float + cards: list["Card"] = field(default_factory=list) + stacking: bool = False # whether cards in this slot stack with offset + + +@ft.observable +@dataclass +class Card: + color: str + top: float = 0 + left: float = 0 + home: Optional[Slot] = None # <-- reference to a Slot, not a string + + +@ft.observable +@dataclass +class Game: + cards: list[Card] = field( + default_factory=lambda: [ + Card(color=ft.Colors.GREEN), # positions will be set in __post_init__ + Card(color=ft.Colors.RED), + Card(color=ft.Colors.BLUE), + Card(color=ft.Colors.YELLOW), + Card(color=ft.Colors.PURPLE), + Card(color=ft.Colors.ORANGE), + Card(color=ft.Colors.BROWN), + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(left=0, top=0, id="deck"), + Slot(left=100, top=0, id="waste"), + Slot(left=200, top=0, id="foundation1"), + Slot(left=300, top=0, id="foundation2"), + Slot(left=0, top=200, id="slot1", stacking=True), + Slot(left=100, top=200, id="slot2", stacking=True), + Slot(left=200, top=200, id="slot3", stacking=True), + ], + ) + + def __post_init__(self): + """Initialize homes & coordinates: place cards in the deck slot.""" + + for card in self.cards: + card.home = self.slots[0] + card.left, card.top = self.slots[0].left, self.slots[0].top + + # Add cards to deck card list + self.slots[0].cards = self.cards.copy() + + def move_to_top(self, cards: list[Card]): + for card in cards: + self.cards.remove(card) + self.cards.append(card) + + def nearest_slot(self, card: Card) -> Optional[Slot]: + """Return the nearest slot to the card within SNAP_THRESHOLD, or None.""" + for s in self.slots: + if s != card.home: + offset = ( + (len(s.cards) - 1) * OFFSET_Y + if s.stacking and len(s.cards) > 0 + else 0 + ) + near_x = abs(card.left - s.left) < SNAP_THRESHOLD + near_y = abs(card.top - (s.top + offset)) < SNAP_THRESHOLD + if near_x and near_y: + return s + return None + + def point_in_card_stack(self, x: float, y: float) -> Optional[list[Card]]: + # Check topmost first so you can grab the card on top + for c in reversed(self.cards): + if (c.left <= x <= c.left + CARD_W) and (c.top <= y <= c.top + CARD_H): + return [c] + c.home.cards[ + c.home.cards.index(c) + 1 : + ] # return the card and all cards below it + return None + + +# ---------- View (pure) ---------- +@ft.component +def CardView(card: Card) -> ft.Control: + return ft.Container( + bgcolor=card.color, + left=card.left, + top=card.top, + width=CARD_W, + height=CARD_H, + border_radius=5, + ) + + +@ft.component +def SlotView(slot: Slot) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=CARD_W, + height=CARD_H, + border=ft.Border.all(1, ft.Colors.PRIMARY), + border_radius=5, + content=ft.Text(slot.id, size=10, color=ft.Colors.BLACK45), + ) + + +# ---------- App ---------- +@ft.component +def App(): + game, _ = ft.use_state(lambda: Game()) + dragging, set_dragging = ft.use_state(None) # None or list[Card] being dragged + start_x, set_start_x = ft.use_state(None) # initial x of the card being dragged + start_y, set_start_y = ft.use_state(None) # initial y of the card being dragged + + def on_pan_start(e: ft.DragStartEvent): + grabbed = game.point_in_card_stack(e.local_position.x, e.local_position.y) + # set_dragging(grabbed[0] if grabbed else None) + set_dragging(grabbed) + if grabbed is not None: + game.move_to_top(grabbed) + set_start_x( + grabbed[0].left + ) # remember initial x of the top card being dragged + set_start_y( + grabbed[0].top + ) # remember initial y of the top card being dragged + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None: + return + print("length of dragging", len(dragging)) + for c in dragging: + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + + def on_pan_end(_: ft.DragEndEvent): + if dragging is None: + return + + s = game.nearest_slot(dragging[0]) + if s is not None: # snap to this slot + for c in dragging: + c.left = s.left + c.top = s.top + OFFSET_Y * (len(s.cards)) if s.stacking else s.top + c.home.cards.remove(c) # Remove card from previous slot's pile + c.home = s # <-- update to the Slot object + s.cards.append(c) # Add card to the slot's pile + + else: # bounce back to where it was picked up + for i, c in enumerate(dragging): + c.left, c.top = start_x, start_y + i * OFFSET_Y + + set_dragging(None) + + return ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + mouse_cursor=ft.MouseCursor.MOVE, + content=ft.Stack( + controls=[ + *(SlotView(s) for s in game.slots), + *(CardView(c) for c in game.cards), + ], + width=1000, + height=500, + ), + ) + + +ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_clubs.svg new file mode 100644 index 0000000000..55d98208ac --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_clubs.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_diamonds.svg new file mode 100644 index 0000000000..1286c25a5e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_diamonds.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_hearts.svg new file mode 100644 index 0000000000..73c6edd671 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_hearts.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_spades.svg new file mode 100644 index 0000000000..830135370d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/10_spades.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_clubs.svg new file mode 100644 index 0000000000..d623e9b404 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_clubs.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_diamonds.svg new file mode 100644 index 0000000000..26aa767cde --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_diamonds.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_hearts.svg new file mode 100644 index 0000000000..53afaa958e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_hearts.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_spades.svg new file mode 100644 index 0000000000..22fe99d7fc --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/2_spades.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_clubs.svg new file mode 100644 index 0000000000..dc06314904 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_clubs.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_diamonds.svg new file mode 100644 index 0000000000..1b8c766378 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_diamonds.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_hearts.svg new file mode 100644 index 0000000000..d5142bc196 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_hearts.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_spades.svg new file mode 100644 index 0000000000..aa3a137d75 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/3_spades.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_clubs.svg new file mode 100644 index 0000000000..32cb3c16c0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_clubs.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_diamonds.svg new file mode 100644 index 0000000000..a6858f8578 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_diamonds.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_hearts.svg new file mode 100644 index 0000000000..1acb9a6724 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_hearts.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_spades.svg new file mode 100644 index 0000000000..c49351766a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/4_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_clubs.svg new file mode 100644 index 0000000000..f41b8c3ec8 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_clubs.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_diamonds.svg new file mode 100644 index 0000000000..8cb1f09b84 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_diamonds.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_hearts.svg new file mode 100644 index 0000000000..fdf1a3ddf3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_spades.svg new file mode 100644 index 0000000000..9bf5500c73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/5_spades.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_clubs.svg new file mode 100644 index 0000000000..80e1931832 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_clubs.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_diamonds.svg new file mode 100644 index 0000000000..01f12ece8c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_diamonds.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_hearts.svg new file mode 100644 index 0000000000..04ae7766b7 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_hearts.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_spades.svg new file mode 100644 index 0000000000..024adc16d2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/6_spades.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_clubs.svg new file mode 100644 index 0000000000..79b2f62e3d --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_clubs.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_diamonds.svg new file mode 100644 index 0000000000..2a38c99667 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_diamonds.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_hearts.svg new file mode 100644 index 0000000000..72f42fe94a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_hearts.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_spades.svg new file mode 100644 index 0000000000..7519ad6ca2 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/7_spades.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_clubs.svg new file mode 100644 index 0000000000..452a8dd29a --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_clubs.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_diamonds.svg new file mode 100644 index 0000000000..abf41a526f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_diamonds.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_hearts.svg new file mode 100644 index 0000000000..fd50551001 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_hearts.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_spades.svg new file mode 100644 index 0000000000..77ce108a2f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/8_spades.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_clubs.svg new file mode 100644 index 0000000000..b2749c0dbb --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_clubs.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_diamonds.svg new file mode 100644 index 0000000000..eec88db012 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_diamonds.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_hearts.svg new file mode 100644 index 0000000000..66bc2770d0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_hearts.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_spades.svg new file mode 100644 index 0000000000..c21f4ac14e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/9_spades.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_clubs.svg new file mode 100644 index 0000000000..46b22496a3 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_clubs.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_diamonds.svg new file mode 100644 index 0000000000..0745d5e321 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_diamonds.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_hearts.svg new file mode 100644 index 0000000000..70c5640276 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_hearts.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_spades.svg new file mode 100644 index 0000000000..2d015c67e0 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Ace_spades.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_clubs.svg new file mode 100644 index 0000000000..4bcd40e03f --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_clubs.svg @@ -0,0 +1,2103 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_diamonds.svg new file mode 100644 index 0000000000..c371d95b73 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_diamonds.svg @@ -0,0 +1,1740 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_hearts.svg new file mode 100644 index 0000000000..6bd3a18cce --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_hearts.svg @@ -0,0 +1,2092 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_spades.svg new file mode 100644 index 0000000000..745ca85965 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Jack_spades.svg @@ -0,0 +1,2361 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_clubs.svg new file mode 100644 index 0000000000..173c31bd95 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_clubs.svg @@ -0,0 +1,2357 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_diamonds.svg new file mode 100644 index 0000000000..42cd892f9e --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_diamonds.svg @@ -0,0 +1,1864 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_hearts.svg new file mode 100644 index 0000000000..ca382b506c --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_hearts.svg @@ -0,0 +1,3106 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_spades.svg new file mode 100644 index 0000000000..73d1f69770 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/King_spades.svg @@ -0,0 +1,1771 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_clubs.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_clubs.svg new file mode 100644 index 0000000000..b041d9a2f4 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_clubs.svg @@ -0,0 +1,2408 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_diamonds.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_diamonds.svg new file mode 100644 index 0000000000..a2b9ef9805 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_diamonds.svg @@ -0,0 +1,1857 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_hearts.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_hearts.svg new file mode 100644 index 0000000000..4c5420c510 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_hearts.svg @@ -0,0 +1,2418 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_spades.svg b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_spades.svg new file mode 100644 index 0000000000..e2b9306800 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/Queen_spades.svg @@ -0,0 +1,2202 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/card_back.png b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/card_back.png new file mode 100644 index 0000000000..dd8b3416dc Binary files /dev/null and b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/assets/images/card_back.png differ diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py new file mode 100644 index 0000000000..d541cc2b19 --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py @@ -0,0 +1,438 @@ +# Step 8: Move piles of cards from stackable slots to stackable slots. + +import random +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + +# Constants for layout and styling +BG_COLOR = "#207F4C" + +# Card aspect ratio (height / width) +CARD_ASPECT = 100 / 70 +COLS = 7 +# gap as a fraction of card width — used for sides, top, and between cards +GAP_FACTOR = 0.15 + + +# ---------- Model ---------- +@dataclass +class Suite: + name: str + color: str + + +@dataclass +class Rank: + name: str + value: int + + +suites = [ + Suite("hearts", "RED"), + Suite("diamonds", "RED"), + Suite("clubs", "BLACK"), + Suite("spades", "BLACK"), +] + +ranks = [ + Rank("Ace", 1), + Rank("2", 2), + Rank("3", 3), + Rank("4", 4), + Rank("5", 5), + Rank("6", 6), + Rank("7", 7), + Rank("8", 8), + Rank("9", 9), + Rank("10", 10), + Rank("Jack", 11), + Rank("Queen", 12), + Rank("King", 13), +] + + +@ft.observable +@dataclass +class Slot: + id: str + col: int # column index (0..6) + row: int # row index (0=top, 1=bottom) + top: float = 0 + left: float = 0 + cards: list["Card"] = field(default_factory=list) + stacking: bool = False # whether cards in this slot stack with offset + + +@ft.observable +@dataclass +class Card: + id: str + suite: Suite + rank: Rank + face_up: bool = False + top: float = 0 + left: float = 0 + home: Optional[Slot] = None # <-- reference to a Slot, not a string + + +@ft.observable +@dataclass +class Game: + card_w: float = 70 + card_h: float = 100 + offset_y: float = 15 + snap_threshold: float = 25 + cards: list[Card] = field( + default_factory=lambda: [ + Card(id=f"{suite.name}_{rank.name}", suite=suite, rank=rank) + for suite in suites + for rank in ranks + ] + ) + slots: list[Slot] = field( + default_factory=lambda: [ + Slot(id="deck", col=0, row=0), + Slot(id="waste", col=1, row=0), + Slot(id="foundation1", col=3, row=0), + Slot(id="foundation2", col=4, row=0), + Slot(id="foundation3", col=5, row=0), + Slot(id="foundation4", col=6, row=0), + Slot(id="tableau1", col=0, row=1, stacking=True), + Slot(id="tableau2", col=1, row=1, stacking=True), + Slot(id="tableau3", col=2, row=1, stacking=True), + Slot(id="tableau4", col=3, row=1, stacking=True), + Slot(id="tableau5", col=4, row=1, stacking=True), + Slot(id="tableau6", col=5, row=1, stacking=True), + Slot(id="tableau7", col=6, row=1, stacking=True), + ], + ) + + def __post_init__(self): + """Initialize homes & coordinates: place cards in the deck slot.""" + random.shuffle(self.cards) + + # Deal cards in tableau1..tableau7 + n = 6 + i = 0 + for card in self.cards: + self.place_card_in_slot(card, self.slots[n]) + n = n + 1 if n < 12 else 6 + i + if n >= 12: + if i < 7: + i = i + 1 + else: + break + + # Place remaining cards in the deck + for c in self.cards[self.cards.index(card) + 1 :]: + self.place_card_in_slot(c, self.slots[0]) + + # Turn last card in each tableau face up + for slot in self.slots[6:]: + slot.cards[-1].face_up = True + + def layout(self, width: float): + """Recompute slot positions and card sizes for the given board width.""" + if width <= 0: + return + # width = card_w * COLS + gap * (COLS + 1), where gap = card_w * GAP_FACTOR + factor = COLS + GAP_FACTOR * (COLS + 1) + self.card_w = width / factor + self.card_h = self.card_w * CARD_ASPECT + gap = self.card_w * GAP_FACTOR + self.offset_y = self.card_h * 0.18 + self.snap_threshold = self.card_w * 0.4 + + col_step = self.card_w + gap + # Equal gap on top, between rows, and sides + row_y = [gap, gap + self.card_h + gap] + + for s in self.slots: + s.left = gap + s.col * col_step + s.top = row_y[s.row] + + # Snap each card back to its home slot's new coordinates + for slot in self.slots: + for i, c in enumerate(slot.cards): + c.left = slot.left + c.top = slot.top + (self.offset_y * i if slot.stacking else 0) + + def move_to_top(self, cards: list[Card]): + for card in cards: + self.cards.remove(card) + self.cards.append(card) + + def nearest_slot(self, card: Card) -> Optional[Slot]: + """Return the nearest slot to the card within snap_threshold, or None.""" + for s in self.slots: + if s != card.home: + offset = ( + (len(s.cards) - 1) * self.offset_y + if s.stacking and len(s.cards) > 0 + else 0 + ) + near_x = abs(card.left - s.left) < self.snap_threshold + near_y = abs(card.top - (s.top + offset)) < self.snap_threshold + if near_x and near_y: + return s + return None + + def point_in_card_stack(self, x: float, y: float) -> Optional[list[Card]]: + # Check topmost first so you can grab the card on top + for c in reversed(self.cards): + if (c.left <= x <= c.left + self.card_w) and ( + c.top <= y <= c.top + self.card_h + ): + return [c] + c.home.cards[ + c.home.cards.index(c) + 1 : + ] # return the card and all cards below it + return None + + def place_card_in_slot(self, card: Card, slot: Slot): + """Place a card in a slot, updating its home and position.""" + if card.home is not None: + card.home.cards.remove(card) # Remove card from previous slot's pile + card.home = slot # <-- update to the Slot object + slot.cards.append(card) # Add card to the slot's pile + card.left = slot.left + card.top = ( + slot.top + self.offset_y * (len(slot.cards) - 1) + if slot.stacking + else slot.top + ) + if self.check_win(): + ft.context.page.show_dialog( + ft.AlertDialog( + title=ft.Text("You won!"), + actions=[ + ft.TextButton( + "OK", on_click=lambda e: ft.context.page.pop_dialog() + ) + ], + ) + ) + + def open_card(self, card: Card): + # Only flip/move if: face-down, in deck, and it's the top card of the deck + if ( + not card.face_up and card.home.cards[-1] == card + ): # flip only if it's face down and the top card in the slot + card.face_up = True + self.move_to_top([card]) + if card.home.id == "deck": # move to waste + self.place_card_in_slot(card, self.slots[1]) # move to waste slot + + def reset_deck(self, slot: Slot): + # Move all cards from waste back to deck in REVERSED order, face down. + if slot.id != "deck": + return + + if len(slot.cards) > 0: + return # only reset if deck is empty + + # deck = self.slots[0] # or self.find_slot_by_id("deck") + # waste = self.slots[1] # or self.find_slot_by_id("waste") + + while len(self.slots[1].cards) > 0: + card = self.slots[1].cards[-1] + card.face_up = False + self.move_to_top([card]) + self.place_card_in_slot(card, self.slots[0]) + + print("Current cards in deck:", len(self.slots[0].cards)) + + def rules_allow_move(self, cards: list[Card], slot: Slot) -> bool: + """Basic Solitaire rules for moving cards between slots""" + # Moving to foundation slots + if slot.id.startswith("foundation"): + if len(cards) != 1: + return False # can move only one card at a time to foundation + else: + if len(slot.cards) == 0 and cards[0].rank.value == 1: + return True # Ace can be placed in empty foundation + elif len(slot.cards) > 0: + top_card = slot.cards[-1] + if ( + cards[0].suite == top_card.suite + and cards[0].rank.value == top_card.rank.value + 1 + ): + return True # same suite, one rank higher + return False # otherwise not allowed + elif slot.id.startswith("tableau"): + # Moving to tableau slots + if len(slot.cards) == 0: + return cards[0].rank.value == 13 # King can be placed in empty tableau + else: + top_card = slot.cards[-1] + if ( + cards[0].suite.color != top_card.suite.color + and cards[0].rank.value == top_card.rank.value - 1 + ): + return True # alternating colors, one rank lower + return False # otherwise not allowed + else: # moving to deck or waste (not allowed) + return False + + def check_win(self): + # Win if all 4 foundation slots have 13 cards each + return all(len(slot.cards) == 13 for slot in self.slots[2:6]) + + +# ---------- View (pure) ---------- +@ft.component +def CardView( + card: Card, card_w: float, card_h: float, on_card_click, key=None +) -> ft.Control: + return ft.Container( + left=card.left, + top=card.top, + width=card_w, + height=card_h, + border_radius=5, + content=( + ft.Image(src=f"/images/{card.rank.name}_{card.suite.name}.svg") + if card.face_up + else ft.Image(src="/images/card_back.png") + ), + on_click=lambda _e: on_card_click(card), + ) + + +@ft.component +def SlotView( + slot: Slot, card_w: float, card_h: float, on_slot_click, key=None +) -> ft.Control: + return ft.Container( + left=slot.left, + top=slot.top, + width=card_w, + height=card_h, + border=ft.Border.all(1, ft.Colors.BLACK_12), + border_radius=10, + on_click=lambda _e: on_slot_click(slot), + ) + + +# ---------- App ---------- + + +@ft.component +def App(): + page = ft.context.page + page.title = "Solitaire" + page.padding = 0 + page.bgcolor = BG_COLOR + + game, set_game = ft.use_state(lambda: Game()) + board_w, set_board_w = ft.use_state(0.0) + dragging, set_dragging = ft.use_state(None) # None or list[Card] being dragged + start_x, set_start_x = ft.use_state(None) # initial x of the card being dragged + start_y, set_start_y = ft.use_state(None) # initial y of the card being dragged + + ft.use_effect(lambda: game.layout(board_w), [game, board_w]) + + def on_pan_start(e: ft.DragStartEvent): + grabbed = game.point_in_card_stack(e.local_position.x, e.local_position.y) + # set_dragging(grabbed[0] if grabbed else None) + set_dragging(grabbed) + if grabbed is not None and grabbed[0].face_up: + game.move_to_top(grabbed) + set_start_x( + grabbed[0].left + ) # remember initial x of the top card being dragged + set_start_y( + grabbed[0].top + ) # remember initial y of the top card being dragged + + def on_pan_update(e: ft.DragUpdateEvent): + if dragging is None or not dragging[0].face_up: + return + for c in dragging: + c.left = max(0, c.left + e.local_delta.x) + c.top = max(0, c.top + e.local_delta.y) + game.notify() + + def on_pan_end(_: ft.DragEndEvent): + if dragging is None or not dragging[0].face_up: + return + + s = game.nearest_slot(dragging[0]) + + if s is not None and game.rules_allow_move(dragging, s): + for c in dragging: + game.place_card_in_slot(c, s) # snap to this slot + + else: # bounce back to where it was picked up + for i, c in enumerate(dragging): + c.left, c.top = start_x, start_y + i * game.offset_y + + game.notify() + set_dragging(None) + + def open_card_and_notify(card: Card): + game.open_card(card) + game.notify() + + def reset_deck_and_notify(slot: Slot): + game.reset_deck(slot) + game.notify() + + cb_reset_deck = ft.use_callback(reset_deck_and_notify, [game]) + cb_open_card = ft.use_callback(open_card_and_notify, [game]) + + MemoSlotView = ft.memo(SlotView) + MemoCardView = ft.memo(CardView) + + board = ft.GestureDetector( + on_pan_start=on_pan_start, + on_pan_update=on_pan_update, + on_pan_end=on_pan_end, + drag_interval=5, + on_size_change=lambda e: set_board_w(e.width), + content=ft.Stack( + expand=True, + controls=[ + ft.Container(expand=True, bgcolor=BG_COLOR, key="bg") + ] # to capture full area + + [ + MemoSlotView(s, game.card_w, game.card_h, cb_reset_deck, key=s.id) + for s in game.slots + ] + + [ + MemoCardView(c, game.card_w, game.card_h, cb_open_card, key=c.id) + for c in game.cards + ], + ), + ) + + bottom_bar = ft.Container( + bottom=0, + padding=10, + content=ft.Row( + controls=[ + ft.FilledButton("New Game", on_click=lambda _: set_game(Game())), + ft.Text( + f"Cards in deck: {len(game.slots[0].cards)}", + color=ft.Colors.WHITE, + ), + ft.Text( + f"Cards in waste: {len(game.slots[1].cards)}", + color=ft.Colors.WHITE, + ), + ], + ), + ) + + return ft.Stack( + expand=True, + controls=[ + ft.Container(expand=True, content=board), + bottom_bar, + ], + ) + + +if __name__ == "__main__": + ft.run(lambda page: page.render(App)) diff --git a/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/pyproject.toml b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/pyproject.toml new file mode 100644 index 0000000000..a29e6b454b --- /dev/null +++ b/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "tutorials-solitaire-declarative-solitaire-final" +version = "1.0.0" +description = "Builds a declarative Solitaire game with stackable slots, drag-and-drop piles, and win detection." +requires-python = ">=3.10" +keywords = ["tutorials", "solitaire", "declarative", "game", "drag and drop"] +authors = [{ name = "Flet team", email = "hello@flet.dev" }] +dependencies = ["flet"] + +[dependency-groups] +dev = ["flet-cli", "flet-desktop", "flet-web"] + +[tool.flet.gallery] +categories = ["Featured", "Games", "Declarative"] + +[tool.flet.metadata] +title = "Solitaire" +controls = ["Stack", "Container", "GestureDetector", "Image", "Column", "Row", "FilledButton", "AlertDialog"] +layout_pattern = "center-stage" +complexity = "advanced" +features = ["drag and drop", "game state", "stacking piles", "win detection"] + +[tool.flet] +org = "dev.flet" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" diff --git a/sdk/python/examples/tutorials/todo/async/main.py b/sdk/python/examples/tutorials/todo/async/main.py new file mode 100644 index 0000000000..f3721fdce2 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/async/main.py @@ -0,0 +1,178 @@ +import flet as ft + + +class Task(ft.UserControl): + def __init__(self, task_name, task_status_change, task_delete): + super().__init__() + self.completed = False + self.task_name = task_name + self.task_status_change = task_status_change + self.task_delete = task_delete + + def build(self): + self.display_task = ft.Checkbox( + value=False, label=self.task_name, on_change=self.status_changed + ) + self.edit_name = ft.TextField(expand=1) + + self.display_view = ft.Row( + alignment="spaceBetween", + vertical_alignment="center", + controls=[ + self.display_task, + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=self.edit_clicked, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=self.delete_clicked, + ), + ], + ), + ], + ) + + self.edit_view = ft.Row( + visible=False, + alignment="spaceBetween", + vertical_alignment="center", + controls=[ + self.edit_name, + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=self.save_clicked, + ), + ], + ) + return ft.Column(controls=[self.display_view, self.edit_view]) + + async def edit_clicked(self, e): + self.edit_name.value = self.display_task.label + self.display_view.visible = False + self.edit_view.visible = True + await self.update() + + async def save_clicked(self, e): + self.display_task.label = self.edit_name.value + self.display_view.visible = True + self.edit_view.visible = False + await self.update() + + async def status_changed(self, e): + self.completed = self.display_task.value + await self.task_status_change(self) + + async def delete_clicked(self, e): + await self.task_delete(self) + + +class TodoApp(ft.UserControl): + def build(self): + self.new_task = ft.TextField( + hint_text="What needs to be done?", on_submit=self.add_clicked, expand=True + ) + self.tasks = ft.Column() + + self.filter = ft.Tabs( + selected_index=0, + on_change=self.tabs_changed, + tabs=[ft.Tab(text="all"), ft.Tab(text="active"), ft.Tab(text="completed")], + ) + + self.items_left = ft.Text("0 items left") + + # application's root control (i.e. "view") containing all other controls + return ft.Column( + width=600, + controls=[ + ft.Row( + [ft.Text(value="Todos", style="headlineMedium")], alignment="center" + ), + ft.Row( + controls=[ + self.new_task, + ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=self.add_clicked + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + self.filter, + self.tasks, + ft.Row( + alignment="spaceBetween", + vertical_alignment="center", + controls=[ + self.items_left, + ft.OutlinedButton( + text="Clear completed", on_click=self.clear_clicked + ), + ], + ), + ], + ), + ], + ) + + async def add_clicked(self, e): + if self.new_task.value: + task = Task(self.new_task.value, self.task_status_change, self.task_delete) + self.tasks.controls.append(task) + self.new_task.value = "" + await self.new_task.focus() + await self.update() + + async def task_status_change(self, task): + await self.update() + + async def task_delete(self, task): + self.tasks.controls.remove(task) + await self.update() + + async def tabs_changed(self, e): + await self.update() + + async def clear_clicked(self, e): + for task in self.tasks.controls[:]: + if task.completed: + await self.task_delete(task) + + async def update(self): + status = self.filter.tabs[self.filter.selected_index].text + count = 0 + for task in self.tasks.controls: + task.visible = ( + status == "all" + or (status == "active" and not task.completed) + or (status == "completed" and task.completed) + ) + if not task.completed: + count += 1 + self.items_left.value = f"{count} active item(s) left" + await super().update() + + +async def main(page: ft.Page): + page.title = "ToDo App" + page.horizontal_alignment = "center" + page.scroll = "adaptive" + await page.update() + + # create application instance + app = TodoApp() + + # add application's root control to the page + await page.add_async(app) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/hello.py b/sdk/python/examples/tutorials/todo/hello.py new file mode 100644 index 0000000000..991c635ce5 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/hello.py @@ -0,0 +1,8 @@ +import flet as ft + + +def main(page: ft.Page): + page.add(ft.Text(value="Hello, world!")) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/media/app-1.png b/sdk/python/examples/tutorials/todo/media/app-1.png new file mode 100644 index 0000000000..f13c4187ef Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/app-1.png differ diff --git a/sdk/python/examples/tutorials/todo/media/app-2.png b/sdk/python/examples/tutorials/todo/media/app-2.png new file mode 100644 index 0000000000..2a5f057c26 Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/app-2.png differ diff --git a/sdk/python/examples/tutorials/todo/media/app-4.png b/sdk/python/examples/tutorials/todo/media/app-4.png new file mode 100644 index 0000000000..2334fbd471 Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/app-4.png differ diff --git a/sdk/python/examples/tutorials/todo/media/complete-demo-web.gif b/sdk/python/examples/tutorials/todo/media/complete-demo-web.gif new file mode 100644 index 0000000000..96ee77326d Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/complete-demo-web.gif differ diff --git a/sdk/python/examples/tutorials/todo/media/diagram-1.png b/sdk/python/examples/tutorials/todo/media/diagram-1.png new file mode 100644 index 0000000000..cbae9461da Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/diagram-1.png differ diff --git a/sdk/python/examples/tutorials/todo/media/diagram-1.svg b/sdk/python/examples/tutorials/todo/media/diagram-1.svg new file mode 100644 index 0000000000..72f46e1764 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/media/diagram-1.svg @@ -0,0 +1,3 @@ + + +
Page with "center" horizontal alignment
Page with "center" horizontal alignment
"new_task" TextField
"new_task" TextField
 + 
 + 
Row with TextField and FloatingActionButton
Row with TextField and Fl...
V
V
Create ToDo App
Create ToDo App
Share app with colleagues
Share app with colleagues
"tasks_view" Column with a list of Checkboxes
"tasks_view" Column with...
width=600
width=600
"view" Column containing Row with TextField and Button and "tasks_view" Column
"view" Column containing Row wi...
Expand = True
Expand = True
Viewer does not support full SVG 1.1
\ No newline at end of file diff --git a/sdk/python/examples/tutorials/todo/media/diagram-2.png b/sdk/python/examples/tutorials/todo/media/diagram-2.png new file mode 100644 index 0000000000..61e193500d Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/diagram-2.png differ diff --git a/sdk/python/examples/tutorials/todo/media/diagram-2.svg b/sdk/python/examples/tutorials/todo/media/diagram-2.svg new file mode 100644 index 0000000000..f5ba4bdb07 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/media/diagram-2.svg @@ -0,0 +1,4 @@ + + + +
TextField
TextField
Add
Add
"edit_view" row is invisible by default; becomes visible after "Edit" is clicked
"edit_view" row is invisible by defa...
CheckBox
CheckBox
"display_view" row is visible by default; becomes invisible after "Edit" is clicked
"display_view" row is visible by defau...
"view" column is a container for "display_view" and "edit_view" rows
"view" column is a container for "d...
TextField
TextField
Save
Save
Edit
Edit
Delete
Delete
V
V
CheckBox
CheckBox
TextField
TextField
Save
Save
Edit
Edit
Delete
Delete
V
V
Text is not SVG - cannot display
\ No newline at end of file diff --git a/sdk/python/examples/tutorials/todo/media/filtering.gif b/sdk/python/examples/tutorials/todo/media/filtering.gif new file mode 100644 index 0000000000..443dfffad5 Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/filtering.gif differ diff --git a/sdk/python/examples/tutorials/todo/media/hello-world.png b/sdk/python/examples/tutorials/todo/media/hello-world.png new file mode 100644 index 0000000000..c25ac6ac56 Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/hello-world.png differ diff --git a/sdk/python/examples/tutorials/todo/media/view-edit-delete.gif b/sdk/python/examples/tutorials/todo/media/view-edit-delete.gif new file mode 100644 index 0000000000..157f28c981 Binary files /dev/null and b/sdk/python/examples/tutorials/todo/media/view-edit-delete.gif differ diff --git a/sdk/python/examples/tutorials/todo/step_1.py b/sdk/python/examples/tutorials/todo/step_1.py new file mode 100644 index 0000000000..412daa3dc1 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/step_1.py @@ -0,0 +1,16 @@ +import flet +from flet import Checkbox, FloatingActionButton, Icons, Page, TextField + + +def main(page: Page): + def add_clicked(e): + page.add(Checkbox(label=new_task.value)) + new_task.value = "" + page.update() + + new_task = TextField(hint_text="Whats needs to be done?") + + page.add(new_task, FloatingActionButton(icon=Icons.ADD, on_click=add_clicked)) + + +flet.run(main) diff --git a/sdk/python/examples/tutorials/todo/step_2.py b/sdk/python/examples/tutorials/todo/step_2.py new file mode 100644 index 0000000000..ad70fa5f70 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/step_2.py @@ -0,0 +1,29 @@ +import flet as ft + + +def main(page: ft.Page): + def add_clicked(e): + tasks_view.controls.append(ft.Checkbox(label=new_task.value)) + new_task.value = "" + view.update() + + new_task = ft.TextField(hint_text="What needs to be done?", expand=True) + tasks_view = ft.Column() + view = ft.Column( + width=600, + controls=[ + ft.Row( + controls=[ + new_task, + ft.FloatingActionButton(icon=ft.Icons.ADD, on_click=add_clicked), + ], + ), + tasks_view, + ], + ) + + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.add(view) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/step_3.py b/sdk/python/examples/tutorials/todo/step_3.py new file mode 100644 index 0000000000..c331574924 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/step_3.py @@ -0,0 +1,41 @@ +import flet as ft + + +@ft.control +class TodoApp(ft.Column): + # application's root control is a Column containing all other controls + def init(self): + self.new_task = ft.TextField(hint_text="What needs to be done?", expand=True) + self.tasks_view = ft.Column() + self.width = 600 + self.controls = [ + ft.Row( + controls=[ + self.new_task, + ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=self.add_clicked + ), + ], + ), + self.tasks_view, + ] + + def add_clicked(self, e): + self.tasks_view.controls.append(ft.Checkbox(label=self.new_task.value)) + self.new_task.value = "" + self.update() + + +def main(page: ft.Page): + page.title = "To-Do App" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.update() + + # create application instance + todo = TodoApp() + + # add application's root control to the page + page.add(todo) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/step_4.py b/sdk/python/examples/tutorials/todo/step_4.py new file mode 100644 index 0000000000..d046047d7d --- /dev/null +++ b/sdk/python/examples/tutorials/todo/step_4.py @@ -0,0 +1,113 @@ +from dataclasses import field +from typing import Callable + +import flet as ft + + +@ft.control +class Task(ft.Column): + task_name: str = "" + on_task_delete: Callable[["Task"], None] = field(default=lambda task: None) + + def init(self): + self.display_task = ft.Checkbox(value=False, label=self.task_name) + self.edit_name = ft.TextField(expand=1) + + self.display_view = ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.display_task, + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=self.edit_clicked, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=self.delete_clicked, + ), + ], + ), + ], + ) + + self.edit_view = ft.Row( + visible=False, + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.edit_name, + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=self.save_clicked, + ), + ], + ) + self.controls = [self.display_view, self.edit_view] + + def edit_clicked(self, e): + self.edit_name.value = self.display_task.label + self.display_view.visible = False + self.edit_view.visible = True + self.update() + + def save_clicked(self, e): + self.display_task.label = self.edit_name.value + self.display_view.visible = True + self.edit_view.visible = False + self.update() + + def delete_clicked(self, e): + self.on_task_delete(self) + + +@ft.control +class TodoApp(ft.Column): + # application's root control is a Column containing all other controls + def init(self): + self.new_task = ft.TextField(hint_text="What needs to be done?", expand=True) + self.tasks = ft.Column() + self.width = 600 + self.controls = [ + ft.Row( + controls=[ + self.new_task, + ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=self.add_clicked + ), + ], + ), + self.tasks, + ] + + def add_clicked(self, e): + task = Task(task_name=self.new_task.value, on_task_delete=self.task_delete) + self.tasks.controls.append(task) + self.new_task.value = "" + self.update() + + def task_delete(self, task): + self.tasks.controls.remove(task) + self.update() + + +def main(page: ft.Page): + page.title = "To-Do App" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.update() + + # create application instance + app = TodoApp() + + # add application's root control to the page + page.add(app) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/todo.py b/sdk/python/examples/tutorials/todo/todo.py new file mode 100644 index 0000000000..6f0956ebbc --- /dev/null +++ b/sdk/python/examples/tutorials/todo/todo.py @@ -0,0 +1,163 @@ +from dataclasses import field +from typing import Callable + +import flet as ft + + +@ft.control +class Task(ft.Column): + task_name: str = "" + on_status_change: Callable[[], None] = field(default=lambda: None) + on_delete: Callable[["Task"], None] = field(default=lambda task: None) + + def init(self): + self.completed = False + self.display_task = ft.Checkbox( + value=False, label=self.task_name, on_change=self.status_changed + ) + self.edit_name = ft.TextField(expand=1) + + self.display_view = ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.display_task, + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=self.edit_clicked, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=self.delete_clicked, + ), + ], + ), + ], + ) + + self.edit_view = ft.Row( + visible=False, + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.edit_name, + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=self.save_clicked, + ), + ], + ) + self.controls = [self.display_view, self.edit_view] + + def edit_clicked(self, e): + self.edit_name.value = self.display_task.label + self.display_view.visible = False + self.edit_view.visible = True + self.update() + + def save_clicked(self, e): + self.display_task.label = self.edit_name.value + self.display_view.visible = True + self.edit_view.visible = False + self.update() + + def status_changed(self, e): + self.completed = self.display_task.value + self.on_status_change() + + def delete_clicked(self, e): + self.on_delete(self) + + +@ft.control +class TodoApp(ft.Column): + # application's root control is a Column containing all other controls + def init(self): + self.new_task = ft.TextField(hint_text="Whats needs to be done?", expand=True) + self.tasks = ft.Column() + + self.filter = ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label="all"), + ft.Tab(label="active"), + ft.Tab(label="completed"), + ], + ) + + self.filter_tabs = ft.Tabs( + length=3, + selected_index=0, + on_change=lambda e: self.update(), + content=self.filter, + ) + + self.width = 600 + self.controls = [ + ft.Row( + controls=[ + self.new_task, + ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=self.add_clicked + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + self.filter_tabs, + self.tasks, + ], + ), + ] + + def add_clicked(self, e): + task = Task( + task_name=self.new_task.value, + on_status_change=self.task_status_change, + on_delete=self.task_delete, + ) + self.tasks.controls.append(task) + self.new_task.value = "" + self.update() + + def task_status_change(self): + self.update() + + def task_delete(self, task): + self.tasks.controls.remove(task) + self.update() + + def before_update(self): + status = self.filter.tabs[self.filter_tabs.selected_index].label + for task in self.tasks.controls: + task.visible = ( + status == "all" + or (status == "active" and not task.completed) + or (status == "completed" and task.completed) + ) + + def tabs_changed(self, e): + self.update() + + +def main(page: ft.Page): + page.title = "To-Do App" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.update() + + # create application instance + app = TodoApp() + + # add application's root control to the page + page.add(app) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/todo/todo.py b/sdk/python/examples/tutorials/todo/todo/todo.py new file mode 100644 index 0000000000..c6a0d05a8f --- /dev/null +++ b/sdk/python/examples/tutorials/todo/todo/todo.py @@ -0,0 +1,170 @@ +import flet as ft + + +class Task(ft.Column): + def __init__(self, task_name, task_delete): + super().__init__() + self.completed = False + self.task_name = task_name + self.task_delete = task_delete + + def build(self): + self.display_task = ft.Checkbox( + value=False, label=self.task_name, on_change=self.status_changed + ) + self.edit_name = ft.TextField(expand=1) + + self.display_view = ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.display_task, + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=self.edit_clicked, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=self.delete_clicked, + ), + ], + ), + ], + ) + + self.edit_view = ft.Row( + visible=False, + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.edit_name, + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=self.save_clicked, + ), + ], + ) + self.controls = [self.display_view, self.edit_view] + + def edit_clicked(self, e): + self.edit_name.value = self.display_task.label + self.display_view.visible = False + self.edit_view.visible = True + + def save_clicked(self, e): + self.display_task.label = self.edit_name.value + self.display_view.visible = True + self.edit_view.visible = False + + def status_changed(self, e): + self.completed = self.display_task.value + + def delete_clicked(self, e): + self.task_delete(self) + + +class TodoApp(ft.Column): + # application's root control is a Column containing all other controls + def build(self): + self.new_task = ft.TextField( + hint_text="What needs to be done?", on_submit=self.add_clicked, expand=True + ) + self.tasks = ft.Column() + + self.filter_tabs = ft.Tabs( + length=3, + selected_index=0, + on_change=lambda e: self.update(), + content=self.filter, + ) + + self.filter = ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label="all"), + ft.Tab(label="active"), + ft.Tab(label="completed"), + ], + ) + + self.items_left = ft.Text("0 items left") + + self.width = 600 + self.controls = [ + ft.Row( + [ft.Text(value="Todos", theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM)], + alignment=ft.MainAxisAlignment.CENTER, + ), + ft.Row( + controls=[ + self.new_task, + ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=self.add_clicked + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + self.filter_tabs, + self.tasks, + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + self.items_left, + ft.OutlinedButton( + content="Clear completed", on_click=self.clear_clicked + ), + ], + ), + ], + ), + ] + + async def add_clicked(self, e): + if self.new_task.value: + task = Task(self.new_task.value, self.task_delete) + self.tasks.controls.append(task) + self.new_task.value = "" + await self.new_task.focus() + + def task_delete(self, task): + self.tasks.controls.remove(task) + + def clear_clicked(self, e): + for task in self.tasks.controls[:]: + if task.completed: + self.task_delete(task) + + def before_update(self): + status = self.filter.tabs[self.filter_tabs.selected_index].label + count = 0 + for task in self.tasks.controls: + task.visible = ( + status == "all" + or (status == "active" and not task.completed) + or (status == "completed" and task.completed) + ) + if not task.completed: + count += 1 + self.items_left.value = f"{count} active item(s) left" + + +def main(page: ft.Page): + page.title = "ToDo App" + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.scroll = ft.ScrollMode.ADAPTIVE + + # create app control and add it to the page + page.add(TodoApp()) + + +ft.run(main) diff --git a/sdk/python/examples/tutorials/todo/todo/todo_reactive.py b/sdk/python/examples/tutorials/todo/todo/todo_reactive.py new file mode 100644 index 0000000000..5a18f00ad7 --- /dev/null +++ b/sdk/python/examples/tutorials/todo/todo/todo_reactive.py @@ -0,0 +1,215 @@ +import logging +from dataclasses import dataclass, field +from typing import cast + +import flet as ft + +logging.basicConfig(level=logging.INFO) + +TaskID = ft.IdCounter() + + +@ft.observable +@dataclass +class TaskItem: + name: str + completed: bool = False + id: int = field(default_factory=TaskID) + + def update_task(self, new_name: str): + self.name = new_name + + def toggle_task_status(self): + self.completed = not self.completed + + +@ft.observable +@dataclass +class TodoAppState: + tasks: list[TaskItem] = field(default_factory=list) + statuses: list[str] = field(default_factory=lambda: ["all", "active", "completed"]) + status: str = "all" + + def get_tasks(self) -> list[TaskItem]: + return list( + filter( + lambda task: self.status == "all" + or self.status == "active" + and not task.completed + or self.status == "completed" + and task.completed, + self.tasks, + ) + ) + + @property + def active_tasks_number(self) -> int: + return len([task for task in self.tasks if not task.completed]) + + def status_changed(self, e: ft.Event[ft.Tabs]): + self.status = self.statuses[e.control.selected_index] + + def add_task(self, new_task_event: str): + self.tasks.append(TaskItem(new_task_event)) + + def delete_task(self, task: TaskItem): + self.tasks.remove(task) + + def clear_completed(self): + self.tasks = list(filter(lambda task: not task.completed, self.tasks)) + + +@ft.component +def TodoAppView(): + state, _ = ft.use_state(lambda: TodoAppState()) + new_task_name, set_new_task_name = ft.use_state("") + new_task_field: ft.Ref = ft.Ref() + + async def add_task(): + state.add_task(new_task_name) + set_new_task_name("") + await cast(ft.TextField, new_task_field.current).focus() + + return ft.View( + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Column( + [ + Header(), + ft.Row( + controls=[ + ft.TextField( + ref=new_task_field, + hint_text="What needs to be done?", + on_submit=add_task, + value=new_task_name, + on_change=lambda e: set_new_task_name(e.control.value), + autofocus=True, + expand=True, + ), + ft.FloatingActionButton( + icon=ft.Icons.ADD, + on_click=add_task, + ), + ], + ), + ft.Column( + spacing=25, + controls=[ + ft.Tabs( + selected_index=state.statuses.index(state.status), + length=len(state.statuses), + on_change=state.status_changed, + content=ft.TabBar( + scrollable=False, + tabs=[ft.Tab(label=tab) for tab in state.statuses], + ), + ), + ft.Column( + [ + TaskItemView(task, state.delete_task, key=task.id) + for task in state.get_tasks() + ] + ), + Footer( + active_tasks_number=state.active_tasks_number, + clear_completed=state.clear_completed, + ), + ], + ), + ] + ) + ], + ) + + +@ft.component +def TaskItemView(task: TaskItem, delete_task, key=None) -> ft.Control: + edit_mode, set_edit_mode = ft.use_state(False) + new_name, set_new_name = ft.use_state("") + + def edit(): + set_edit_mode(True) + set_new_name(task.name) + + def complete_edit(): + task.update_task(new_name) + set_edit_mode(False) + + return ( + ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Checkbox( + value=task.completed, + label=task.name, + on_change=lambda: task.toggle_task_status(), + ), + ft.Row( + spacing=0, + controls=[ + ft.IconButton( + icon=ft.Icons.CREATE_OUTLINED, + tooltip="Edit To-Do", + on_click=edit, + ), + ft.IconButton( + ft.Icons.DELETE_OUTLINE, + tooltip="Delete To-Do", + on_click=lambda: delete_task(task), + ), + ], + ), + ], + ) + if not edit_mode + else ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.TextField( + value=new_name, + on_change=lambda e: set_new_name(e.control.value), + expand=1, + ), + ft.IconButton( + icon=ft.Icons.DONE_OUTLINE_OUTLINED, + icon_color=ft.Colors.GREEN, + tooltip="Update To-Do", + on_click=complete_edit, + ), + ], + ) + ) + + +@ft.component +def Header(): + return ft.Row( + [ + ft.Text( + value="Todos", + theme_style=ft.TextThemeStyle.HEADLINE_MEDIUM, + ) + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + + +@ft.component +def Footer(active_tasks_number: int, clear_completed): + return ft.Row( + alignment=ft.MainAxisAlignment.SPACE_BETWEEN, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text(f"{active_tasks_number} items left"), + ft.OutlinedButton( + content="Clear completed", + on_click=clear_completed, + ), + ], + ) + + +ft.run(lambda page: page.render_views(TodoAppView)) diff --git a/sdk/python/examples/tutorials/trolli/media/add-board-capability.gif b/sdk/python/examples/tutorials/trolli/media/add-board-capability.gif new file mode 100644 index 0000000000..5c06616608 Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/add-board-capability.gif differ diff --git a/sdk/python/examples/tutorials/trolli/media/app.gif b/sdk/python/examples/tutorials/trolli/media/app.gif new file mode 100644 index 0000000000..cc059da896 Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/app.gif differ diff --git a/sdk/python/examples/tutorials/trolli/media/basic-nav-rail-toggle.gif b/sdk/python/examples/tutorials/trolli/media/basic-nav-rail-toggle.gif new file mode 100644 index 0000000000..3dbf4d4eda Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/basic-nav-rail-toggle.gif differ diff --git a/sdk/python/examples/tutorials/trolli/media/drag-drop-list.gif b/sdk/python/examples/tutorials/trolli/media/drag-drop-list.gif new file mode 100644 index 0000000000..3dcf24514c Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/drag-drop-list.gif differ diff --git a/sdk/python/examples/tutorials/trolli/media/drag-lists-and-items.gif b/sdk/python/examples/tutorials/trolli/media/drag-lists-and-items.gif new file mode 100644 index 0000000000..64d7f0a771 Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/drag-lists-and-items.gif differ diff --git a/sdk/python/examples/tutorials/trolli/media/mock-up.png b/sdk/python/examples/tutorials/trolli/media/mock-up.png new file mode 100644 index 0000000000..ec2e92d164 Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/mock-up.png differ diff --git a/sdk/python/examples/tutorials/trolli/media/navigation.gif b/sdk/python/examples/tutorials/trolli/media/navigation.gif new file mode 100644 index 0000000000..11c8541f5f Binary files /dev/null and b/sdk/python/examples/tutorials/trolli/media/navigation.gif differ diff --git a/sdk/python/packages/flet-ads/CHANGELOG.md b/sdk/python/packages/flet-ads/CHANGELOG.md new file mode 100644 index 0000000000..f555bfce12 --- /dev/null +++ b/sdk/python/packages/flet-ads/CHANGELOG.md @@ -0,0 +1,26 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.82.0 + +### Changed + +- Refactored ads controls: `BaseAd` is now based on `flet.BaseControl`, `InterstitialAd` is now a `flet.Service`, `BannerAd` is now a `flet.LayoutControl`, and examples were updated ([#6194](https://github.com/flet-dev/flet/issues/6194), [#6235](https://github.com/flet-dev/flet/pull/6235)). + +## 0.80.0 + +### Added + +- Deployed online documentation: https://flet-dev.github.io/flet-ads/ + +### Changed + +- Refactored all controls to use `@flet.control` dataclass-style definition. + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-ads/LICENSE b/sdk/python/packages/flet-ads/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-ads/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-ads/README.md b/sdk/python/packages/flet-ads/README.md new file mode 100644 index 0000000000..2d00f8afa9 --- /dev/null +++ b/sdk/python/packages/flet-ads/README.md @@ -0,0 +1,42 @@ +# flet-ads + +[![pypi](https://img.shields.io/pypi/v/flet-ads.svg)](https://pypi.python.org/pypi/flet-ads) +[![downloads](https://static.pepy.tech/badge/flet-ads/month)](https://pepy.tech/project/flet-ads) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-ads) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-ads.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-ads.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-ads/LICENSE) + +Display Google Ads in [Flet](https://flet.dev) apps. + +It is based on the [google_mobile_ads](https://pub.dev/packages/google_mobile_ads) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/ads/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | + +## Usage + +### Installation + +To install the `flet-ads` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-ads + ``` + +- Using `pip`: + ```bash + pip install flet-ads + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/ads). diff --git a/sdk/python/packages/flet-ads/pyproject.toml b/sdk/python/packages/flet-ads/pyproject.toml new file mode 100644 index 0000000000..f982905859 --- /dev/null +++ b/sdk/python/packages/flet-ads/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-ads" +version = "0.1.0" +description = "Display Google Ads in Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/ads" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-ads" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_ads" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-ads/src/flet_ads/__init__.py b/sdk/python/packages/flet-ads/src/flet_ads/__init__.py new file mode 100644 index 0000000000..03bf87a29e --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/__init__.py @@ -0,0 +1,17 @@ +from flet_ads.banner_ad import BannerAd +from flet_ads.base_ad import BaseAd +from flet_ads.interstitial_ad import InterstitialAd +from flet_ads.types import ( + AdRequest, + PaidAdEvent, + PrecisionType, +) + +__all__ = [ + "AdRequest", + "BannerAd", + "BaseAd", + "InterstitialAd", + "PaidAdEvent", + "PrecisionType", +] diff --git a/sdk/python/packages/flet-ads/src/flet_ads/banner_ad.py b/sdk/python/packages/flet-ads/src/flet_ads/banner_ad.py new file mode 100644 index 0000000000..858be20718 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/banner_ad.py @@ -0,0 +1,41 @@ +from typing import Optional + +import flet as ft +from flet_ads.base_ad import BaseAd +from flet_ads.types import PaidAdEvent + + +@ft.control("BannerAd") +class BannerAd(ft.LayoutControl, BaseAd): + """ + Displays a banner ad. + + Example: Test IDs + AdMob [provides](https://developers.google.com/admob/flutter/banner#always_test_with_test_ads) + unit IDs for testing purposes. Set :attr:`unit_id` to the appropriate value + based on the platform you're testing on: + + - Android: `"ca-app-pub-3940256099942544/9214589741"` + - iOS: `"ca-app-pub-3940256099942544/2435281174"` + + Remember to replace them in production. + + Raises: + FletUnsupportedPlatformException: When this control is used on a web + and/or non-mobile platform. + """ + + on_will_dismiss: Optional[ft.ControlEventHandler["BannerAd"]] = None + """ + Called before dismissing a full screen view. + + Note: + Only available on iOS. + """ + + on_paid: Optional[ft.ControlEventHandler[PaidAdEvent["BannerAd"]]] = None + """ + Called when this ad is estimated to have earned money. + + Available for allowlisted accounts only. + """ diff --git a/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py b/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py new file mode 100644 index 0000000000..1f2d1a5137 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/base_ad.py @@ -0,0 +1,74 @@ +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft +from flet_ads.types import AdRequest + + +@dataclass(kw_only=True) +class BaseAd(ft.BaseControl): + """ + Base class for all Ad controls. + + This class defines shared ad request and lifecycle event properties for + concrete ad controls/services. + + Raises: + FletUnsupportedPlatformException: When using this control on a web + and/or non-mobile platform. + """ + + unit_id: str + """ + Ad unit ID for this ad. + """ + + request: AdRequest = field(default_factory=lambda: AdRequest()) + """ + Targeting information used to fetch an Ad. + """ + + on_load: Optional[ft.ControlEventHandler["BaseAd"]] = None + """ + Called when this ad is loaded successfully. + """ + + on_error: Optional[ft.ControlEventHandler["BaseAd"]] = None + """ + Called when an ad request failed. + + Event handler argument :attr:`~flet.Event.data` property + contains information about the error. + """ + + on_open: Optional[ft.ControlEventHandler["BaseAd"]] = None + """ + Called when this ad opens up. + + A full screen view/overlay is presented in response to the user clicking + on an ad. You may want to pause animations and time sensitive + interactions. + """ + + on_close: Optional[ft.ControlEventHandler["BaseAd"]] = None + """ + Called when the full screen view has been closed. You should restart + anything paused while handling :attr:`~flet_ads.BaseAd.on_open`. + """ + + on_impression: Optional[ft.ControlEventHandler["BaseAd"]] = None + """ + Called when an impression occurs on this ad. + """ + + on_click: Optional[ft.ControlEventHandler["BaseAd"]] = None + """ + Called when this ad is clicked. + """ + + def before_update(self): + if self.page.web or not self.page.platform.is_mobile(): + raise ft.FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on " + f"Mobile (Android and iOS)" + ) diff --git a/sdk/python/packages/flet-ads/src/flet_ads/interstitial_ad.py b/sdk/python/packages/flet-ads/src/flet_ads/interstitial_ad.py new file mode 100644 index 0000000000..f2a651f72a --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/interstitial_ad.py @@ -0,0 +1,37 @@ +import flet as ft +from flet_ads.base_ad import BaseAd + + +@ft.control("InterstitialAd") +class InterstitialAd(ft.Service, BaseAd): + """ + Displays a full-screen interstitial ad. + + Note: + Each instance is allowed to be shown (using :meth:`show`) only once. + To show another ad, create a new instance. Reusing an already-shown instance + will result in errors or unexpected behavior. + + Example: Test IDs + AdMob [provides](https://developers.google.com/admob/flutter/banner#always_test_with_test_ads) + unit IDs for testing purposes. Set :attr:`~flet_ads.BaseAd.unit_id` + to the appropriate value based on the platform you're testing on: + + - Android: `"ca-app-pub-3940256099942544/1033173712"` + - iOS: `"ca-app-pub-3940256099942544/4411468910"` + + Remember to replace them in production. + + Raises: + FletUnsupportedPlatformException: When using this control on a + web and/or non-mobile platform. + """ # noqa: E501 + + async def show(self): + """ + Present the loaded interstitial ad as a full-screen overlay. + + The ad must be loaded before this method is called. + """ + + await self._invoke_method("show") diff --git a/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py b/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py new file mode 100644 index 0000000000..b3d45272af --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/native_ad.py @@ -0,0 +1,33 @@ +import flet as ft +from flet_ads.banner_ad import BannerAd +from flet_ads.types import NativeAdTemplateStyle + +__all__ = ["NativeAd"] + + +@ft.control("NativeAd") +class NativeAd(BannerAd): + """ + Renders a native ad. + """ + + factory_id: str = None + """ + An identifier for the factory that creates the Platform view. + + Raises: + ValueError: When neither `factory_id` nor :attr:`template_style` is set. + """ + + template_style: NativeAdTemplateStyle = None + """ + A style for the native ad template. + + Raises: + ValueError: When neither :attr:`factory_id` nor `template_style` is set. + """ + + def before_update(self): + super().before_update() + if self.factory_id is None and self.template_style is None: + raise ValueError("factory_id or template_style must be set") diff --git a/sdk/python/packages/flet-ads/src/flet_ads/types.py b/sdk/python/packages/flet-ads/src/flet_ads/types.py new file mode 100644 index 0000000000..a15e144cb8 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flet_ads/types.py @@ -0,0 +1,131 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +import flet as ft + +__all__ = [ + "AdRequest", + "NativeAdTemplateStyle", + "NativeAdTemplateTextStyle", + "NativeAdTemplateType", + "NativeTemplateFontStyle", + "PaidAdEvent", + "PrecisionType", +] + + +class PrecisionType(Enum): + """Describes how accurately a paid ad value is reported.""" + + UNKNOWN = "unknown" + """An ad value with unknown precision.""" + + ESTIMATED = "estimated" + """An ad value estimated from aggregated data.""" + + PUBLISHER_PROVIDED = "publisherProvided" + """A publisher-provided ad value, such as manual CPMs in a mediation group.""" + + PRECISE = "precise" + """The precise value paid for this ad.""" + + +@dataclass +class PaidAdEvent(ft.Event[ft.EventControlType]): + """ + Event data for paid ad events. + """ + + value: float + """ + The monetary value of the ad. + """ + + precision: PrecisionType + """ + The precision of the ad value. + """ + + currency_code: str + """ + The currency code of the ad value. + """ + + +@ft.value +class AdRequest: + """ + Targeting info per the AdMob API. + + This class's properties mirror the native AdRequest API. See for example: + [AdRequest.Builder for Android](https://developers.google.com/android/reference/com/google/android/gms/ads/AdRequest.Builder). + """ + + keywords: Optional[list[str]] = None + """ + Words or phrases describing the current user activity. + """ + + content_url: Optional[str] = None + """ + URL string for a webpage whose content matches the app’s primary content. + + This webpage content is used for targeting and brand safety purposes. + """ + + neighboring_content_urls: Optional[list[str]] = None + """ + URLs representing web content near an ad. + """ + + non_personalized_ads: Optional[bool] = None + """ + Non-personalized ads are ads that are not based on a user’s past behavior. + + For more information: https://support.google.com/admob/answer/7676680?hl=en + """ + + http_timeout: Optional[int] = None + """ + A custom timeout (in milliseconds) for HTTPS calls during an ad request. + + Note: + This is only supported in Android. (ignored on iOS) + """ + + extras: Optional[dict[str, str]] = None + """ + Extras to pass to the AdMob adapter. + """ + + +class NativeAdTemplateType(Enum): + SMALL = "small" + MEDIUM = "medium" + + +class NativeTemplateFontStyle(Enum): + NORMAL = "normal" + BOLD = "bold" + ITALIC = "italic" + MONOSPACE = "monospace" + + +@ft.value +class NativeAdTemplateTextStyle: + size: Optional[ft.Number] = None + text_color: Optional[ft.ColorValue] = None + bgcolor: Optional[ft.ColorValue] = None + style: Optional[NativeTemplateFontStyle] = None + + +@ft.value +class NativeAdTemplateStyle: + template_type: NativeAdTemplateType = NativeAdTemplateType.MEDIUM + main_bgcolor: Optional[ft.ColorValue] = None + corner_radius: Optional[ft.Number] = None + call_to_action_text_style: Optional[NativeAdTemplateTextStyle] = None + primary_text_style: Optional[NativeAdTemplateTextStyle] = None + secondary_text_style: Optional[NativeAdTemplateTextStyle] = None + tertiary_text_style: Optional[NativeAdTemplateTextStyle] = None diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/.gitignore b/sdk/python/packages/flet-ads/src/flutter/flet_ads/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/.metadata b/sdk/python/packages/flet-ads/src/flutter/flet_ads/.metadata new file mode 100644 index 0000000000..07d8623a38 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2e9cb0aa71a386a91f73f7088d115c0d96654829" + channel: "stable" + +project_type: package diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/analysis_options.yaml b/sdk/python/packages/flet-ads/src/flutter/flet_ads/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/flet_ads.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/flet_ads.dart new file mode 100644 index 0000000000..add538918f --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/flet_ads.dart @@ -0,0 +1,3 @@ +library flet_ads; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/banner.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/banner.dart new file mode 100644 index 0000000000..f9951fb05a --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/banner.dart @@ -0,0 +1,84 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import '../utils/ads.dart'; + +class BannerAdControl extends StatefulWidget { + final Control control; + + const BannerAdControl({super.key, required this.control}); + + @override + State createState() => _BannerAdControlState(); +} + +class _BannerAdControlState extends State with FletStoreMixin { + bool _isLoaded = false; + + @override + Widget build(BuildContext context) { + debugPrint( + "BannerAd build: ${widget.control.id} (${widget.control.hashCode})"); + final testAdUnitId = isIOSMobile() + ? 'ca-app-pub-3940256099942544/4411468910' + : 'ca-app-pub-3940256099942544/1033173712'; + BannerAd bannerAd = BannerAd( + adUnitId: widget.control.getString("unit_id", testAdUnitId)!, + request: + parseAdRequest(widget.control.get("request"), const AdRequest())!, + size: AdSize.banner, + listener: BannerAdListener( + // Called when an ad is successfully received. + onAdLoaded: (ad) { + widget.control.triggerEvent("load"); + setState(() { + _isLoaded = true; + }); + }, + // Called when an ad request failed. + onAdFailedToLoad: (ad, error) { + widget.control.triggerEvent("error", error.toString()); + // Dispose the ad to free resources. + ad.dispose(); + setState(() { + _isLoaded = false; + }); + }, + // Called when an ad opens an overlay that covers the screen. + onAdOpened: (Ad ad) { + widget.control.triggerEvent("open"); + }, + // Called when an ad removes an overlay that covers the screen. + onAdClosed: (Ad ad) { + widget.control.triggerEvent("close"); + }, + onAdClicked: (Ad ad) { + widget.control.triggerEvent("click"); + }, + onAdWillDismissScreen: (Ad ad) { + widget.control.triggerEvent("will_dismiss"); + }, + onPaidEvent: (ad, double valueMicros, PrecisionType precision, + String currencyCode) { + widget.control.triggerEvent("paid", { + "value": valueMicros, + "precision": precision.name, + "currency_code": currencyCode + }); + }, + // Called when an impression occurs on the ad. + onAdImpression: (Ad ad) { + widget.control.triggerEvent("impression"); + }, + ), + ); + + if (!_isLoaded) { + bannerAd.load(); + } + + return LayoutControl( + control: widget.control, child: AdWidget(ad: bannerAd)); + } +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart new file mode 100644 index 0000000000..fa04866801 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/extension.dart @@ -0,0 +1,39 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import 'banner.dart'; +import 'interstitial.dart'; + +class Extension extends FletExtension { + @override + void ensureInitialized() { + if (isMobilePlatform()) { + MobileAds.instance.initialize(); + } + } + + @override + FletService? createService(Control control) { + switch (control.type) { + case "InterstitialAd": + return InterstitialAdService(control: control); + default: + return null; + } + } + + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "BannerAd": + return BannerAdControl(control: control); + /* TODO: Finalize NativeAdControl -> https://developers.google.com/admob/flutter/native/platforms + case "NativeAd": + return NativeAdControl(control: control); + */ + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/interstitial.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/interstitial.dart new file mode 100644 index 0000000000..74d39ffe1c --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/interstitial.dart @@ -0,0 +1,70 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import '../utils/ads.dart'; + +class InterstitialAdService extends FletService { + InterstitialAdService({required super.control}); + + static InterstitialAd? _interstitialAd; + + @override + void init() { + super.init(); + debugPrint("InterstitialAd(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + + InterstitialAd.load( + adUnitId: control.getString( + "unit_id", + isIOSMobile() + ? 'ca-app-pub-3940256099942544/4411468910' + : 'ca-app-pub-3940256099942544/1033173712')!, + request: parseAdRequest(control.get("request"), const AdRequest())!, + adLoadCallback: InterstitialAdLoadCallback( + onAdLoaded: (ad) { + ad.fullScreenContentCallback = FullScreenContentCallback( + onAdShowedFullScreenContent: (ad) => control.triggerEvent("open"), + onAdImpression: (ad) => control.triggerEvent("impression"), + onAdFailedToShowFullScreenContent: (ad, error) { + control.triggerEvent("error", error.toString()); + ad.dispose(); // free resources + }, + onAdDismissedFullScreenContent: (ad) { + // Called when the ad dismissed full screen content. + control.triggerEvent("close"); + // Dispose the ad here to free resources. + ad.dispose(); + }, + onAdClicked: (ad) => control.triggerEvent("click"), + ); + + // Keep a reference to show it later. + _interstitialAd = ad; + control.triggerEvent("load"); + }, + onAdFailedToLoad: (LoadAdError error) { + control.triggerEvent("error", error.toString()); + _interstitialAd?.dispose(); + }, + )); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("InterstitialAd.$name($args)"); + switch (name) { + case "show": + _interstitialAd?.show(); + return null; + default: + throw Exception("Unknown InterstitialAd method: $name"); + } + } + + @override + void dispose() { + _interstitialAd?.dispose(); + super.dispose(); + } +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/native.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/native.dart new file mode 100644 index 0000000000..94f11b62f7 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/src/native.dart @@ -0,0 +1,73 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import '../utils/ads.dart'; +import '../utils/native.dart'; + +class NativeAdControl extends StatefulWidget { + final Control control; + + const NativeAdControl({super.key, required this.control}); + + @override + State createState() => _NativeAdControlState(); +} + +class _NativeAdControlState extends State with FletStoreMixin { + bool _isLoaded = false; + + @override + Widget build(BuildContext context) { + debugPrint( + "NativeAd build: ${widget.control.id} (${widget.control.hashCode})"); + final testAdUnitId = isIOSMobile() + ? 'ca-app-pub-3940256099942544/3986624511' + : 'ca-app-pub-3940256099942544/2247696110'; + var factoryId = widget.control.getString("factory_id"); + var templateStyle = parseNativeTemplateStyle( + widget.control.get("template_style"), Theme.of(context)); + if (factoryId == null && templateStyle == null) { + return const ErrorControl("factory_id or template_style is required"); + } + + NativeAd nativeAd = NativeAd( + adUnitId: widget.control.getString("unit_id", testAdUnitId)!, + factoryId: factoryId, + listener: NativeAdListener( + onAdLoaded: (ad) { + widget.control.triggerEvent("load"); + setState(() { + _isLoaded = true; + }); + }, + onAdFailedToLoad: (ad, error) { + widget.control.triggerEvent("error", error.toString()); + ad.dispose(); // Dispose the ad here to free resources + }, + onAdClicked: (ad) => widget.control.triggerEvent("click"), + onAdImpression: (ad) => widget.control.triggerEvent("impression"), + onAdClosed: (ad) => widget.control.triggerEvent("close"), + onAdOpened: (ad) => widget.control.triggerEvent("open"), + onAdWillDismissScreen: (ad) => + widget.control.triggerEvent("will_dismiss"), + onPaidEvent: (Ad ad, valueMicros, precision, currencyCode) { + widget.control.triggerEvent("paid", { + "value": valueMicros, + "precision": precision, + "currency_code": currencyCode + }); + }, + ), + request: + parseAdRequest(widget.control.get("request"), const AdRequest())!, + nativeTemplateStyle: templateStyle); + + if (!_isLoaded) { + nativeAd.load(); + } + + return LayoutControl( + control: widget.control, child: AdWidget(ad: nativeAd)); + } +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/ads.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/ads.dart new file mode 100644 index 0000000000..83add99a15 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/ads.dart @@ -0,0 +1,14 @@ +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +AdRequest? parseAdRequest(dynamic value, [AdRequest? defaultValue]) { + if (value == null) return defaultValue; + + return AdRequest( + keywords: value["keywords"], + contentUrl: value["content_url"], + nonPersonalizedAds: value["non_personalized_ads"], + neighboringContentUrls: value["neighboring_content_urls"], + httpTimeoutMillis: value["http_timeout"], + extras: value["extras"], + ); +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/native.dart b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/native.dart new file mode 100644 index 0000000000..c983fb36c5 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/lib/utils/native.dart @@ -0,0 +1,51 @@ +import 'package:collection/collection.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +TemplateType? parseTemplateType(String? value, [TemplateType? defaultValue]) { + if (value == null) return defaultValue; + return TemplateType.values.firstWhereOrNull( + (e) => e.toString().toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +NativeTemplateFontStyle? parseNativeTemplateFontStyle(String? value, + [NativeTemplateFontStyle? defaultValue]) { + if (value == null) return defaultValue; + return NativeTemplateFontStyle.values.firstWhereOrNull( + (e) => e.toString().toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +NativeTemplateTextStyle? parseNativeTemplateTextStyle( + dynamic value, ThemeData theme, + [NativeTemplateTextStyle? defaultValue]) { + if (value == null) return defaultValue; + + return NativeTemplateTextStyle( + size: parseDouble(value["size"]), + textColor: parseColor(value["color"], theme), + backgroundColor: parseColor(value["bgcolor"], theme), + style: parseNativeTemplateFontStyle(value["style"]), + ); +} + +NativeTemplateStyle? parseNativeTemplateStyle(dynamic value, ThemeData theme, + [NativeTemplateStyle? defaultValue]) { + if (value == null) return defaultValue; + + return NativeTemplateStyle( + templateType: + parseTemplateType(value["template_type"], TemplateType.medium)!, + mainBackgroundColor: parseColor(value["main_bgcolor"], theme), + cornerRadius: parseDouble(value["corner_radius"]), + callToActionTextStyle: parseNativeTemplateTextStyle( + theme, value["call_to_action_text_style"]), + primaryTextStyle: + parseNativeTemplateTextStyle(value["primary_text_style"], theme), + secondaryTextStyle: + parseNativeTemplateTextStyle(value["secondary_text_style"], theme), + tertiaryTextStyle: + parseNativeTemplateTextStyle(value["tertiary_text_style"], theme)); +} diff --git a/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml b/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml new file mode 100644 index 0000000000..060cdf5d28 --- /dev/null +++ b/sdk/python/packages/flet-ads/src/flutter/flet_ads/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_ads +description: Display Google Ads in Flet apps. +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + google_mobile_ads: ^8.0.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-audio-recorder/CHANGELOG.md b/sdk/python/packages/flet-audio-recorder/CHANGELOG.md new file mode 100644 index 0000000000..e05edec44a --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/CHANGELOG.md @@ -0,0 +1,52 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.85.0 + +### Added + +- Added PCM16 streaming to `AudioRecorder`, including `on_stream` chunks and direct upload support via `AudioRecorderUploadSettings` ([#5858](https://github.com/flet-dev/flet/issues/5858), [#6423](https://github.com/flet-dev/flet/pull/6423)) by @ndonkoHenri. + +## 0.80.0 + +### Added + +- Deployed online documentation: https://flet.dev/docs/audio-recorder/ +- `AudioRecorder` control new property: `configuration` +- New dataclasses: + - `AudioRecorderConfiguration` + - `AndroidRecorderConfiguration` + - `IosRecorderConfiguration` + - `InputDevice` +- New enums: + - `AndroidAudioSource` + - `IosAudioCategoryOption` + +### Changed + +- Refactored `AudioRecorder` control to use `@ft.control` dataclass-style definition and switched to `Service` control type + +#### Breaking Changes + +- `AudioRecorder` must now be added to `Page.services` instead of `Page.overlay`. +- Recording configuration properties (`audio_encoder`, `suppress_noise`, `cancel_echo`, `auto_gain`, `channels_num`, `sample_rate`, `bit_rate`) are now grouped under `configuration: AudioRecorderConfiguration` +- Event `on_state_changed` renamed to `on_state_change` +- In all methods, parameter `wait_timeout` was renamed to `timeout`. +- The following `AudioRecorder` sync methods were made [`async`](https://docs.python.org/3/library/asyncio.html): + - `is_recording` + - `stop_recording` + - `cancel_recording` + - `resume_recording` + - `pause_recording` + - `is_paused` + - `is_supported_encoder` + - `get_input_devices` + - `has_permission` + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-audio-recorder/LICENSE b/sdk/python/packages/flet-audio-recorder/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-audio-recorder/README.md b/sdk/python/packages/flet-audio-recorder/README.md new file mode 100644 index 0000000000..60989994d1 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/README.md @@ -0,0 +1,46 @@ +# flet-audio-recorder + +[![pypi](https://img.shields.io/pypi/v/flet-audio-recorder.svg)](https://pypi.python.org/pypi/flet-audio-recorder) +[![downloads](https://static.pepy.tech/badge/flet-audio-recorder/month)](https://pepy.tech/project/flet-audio-recorder) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-audio-recorder) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-audio-recorder.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-audio-recorder.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-audio-recorder/LICENSE) + +Adds audio recording support to [Flet](https://flet.dev) apps. + +It is based on the [record](https://pub.dev/packages/record) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/services/audiorecorder/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-audio-recorder` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-audio-recorder + ``` + +- Using `pip`: + ```bash + pip install flet-audio-recorder + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +> [!NOTE] +> On Linux, encoding is provided by [fmedia](https://stsaz.github.io/fmedia/) which must be installed separately. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/audio_recorder). diff --git a/sdk/python/packages/flet-audio-recorder/pyproject.toml b/sdk/python/packages/flet-audio-recorder/pyproject.toml new file mode 100644 index 0000000000..1e996268ac --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-audio-recorder" +version = "0.1.0" +description = "Adds audio recording support to Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/services/audiorecorder" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-audio-recorder" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_audio_recorder" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/__init__.py b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/__init__.py new file mode 100644 index 0000000000..5279de47ba --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/__init__.py @@ -0,0 +1,31 @@ +from .audio_recorder import AudioRecorder +from .types import ( + AndroidAudioSource, + AndroidRecorderConfiguration, + AudioEncoder, + AudioRecorderConfiguration, + AudioRecorderState, + AudioRecorderStateChangeEvent, + AudioRecorderStreamEvent, + AudioRecorderUploadEvent, + AudioRecorderUploadSettings, + InputDevice, + IosAudioCategoryOption, + IosRecorderConfiguration, +) + +__all__ = [ + "AndroidAudioSource", + "AndroidRecorderConfiguration", + "AudioEncoder", + "AudioRecorder", + "AudioRecorderConfiguration", + "AudioRecorderState", + "AudioRecorderStateChangeEvent", + "AudioRecorderStreamEvent", + "AudioRecorderUploadEvent", + "AudioRecorderUploadSettings", + "InputDevice", + "IosAudioCategoryOption", + "IosRecorderConfiguration", +] diff --git a/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/audio_recorder.py b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/audio_recorder.py new file mode 100644 index 0000000000..a31db5b0b0 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/audio_recorder.py @@ -0,0 +1,187 @@ +from dataclasses import field +from typing import Optional + +import flet as ft + +from .types import ( + AudioEncoder, + AudioRecorderConfiguration, + AudioRecorderStateChangeEvent, + AudioRecorderStreamEvent, + AudioRecorderUploadEvent, + AudioRecorderUploadSettings, + InputDevice, +) + +__all__ = ["AudioRecorder"] + + +@ft.control("AudioRecorder") +class AudioRecorder(ft.Service): + """ + A control that allows you to record audio from your device. + + This control can record audio using different audio encoders and also allows + configuration of various audio recording parameters such as + noise suppression, echo cancellation, and more. + """ + + configuration: AudioRecorderConfiguration = field( + default_factory=lambda: AudioRecorderConfiguration() + ) + """ + The default configuration of the audio recorder. + """ + + on_state_change: Optional[ft.EventHandler[AudioRecorderStateChangeEvent]] = None + """ + Called when recording state changes. + """ + + on_upload: Optional[ft.EventHandler[AudioRecorderUploadEvent]] = None + """ + Called when streaming upload progress or errors are available. + """ + + on_stream: Optional[ft.EventHandler[AudioRecorderStreamEvent]] = None + """ + Called when a raw :attr:`~flet_audio_recorder.AudioEncoder.PCM16BITS` \ + recording chunk is available. + """ + + async def start_recording( + self, + output_path: Optional[str] = None, + configuration: Optional[AudioRecorderConfiguration] = None, + upload: Optional[AudioRecorderUploadSettings] = None, + ) -> bool: + """ + Starts recording audio and saves it to a file or streams it. + + If neither `upload` nor :attr:`on_stream` is used, `output_path` must be + provided on platforms other than web. + + When streaming, use :attr:`~flet_audio_recorder.AudioEncoder.PCM16BITS` as + the encoder. In that case, emitted or uploaded + :attr:`~flet_audio_recorder.AudioRecorderStreamEvent.chunk`s contain raw PCM16 + data. In some use cases, these chunks can be wrapped in a container such as + WAV if the output must be directly playable as an audio file. + + Args: + output_path: The file path where the audio will be saved. + It must be specified if not on web. + configuration: The configuration for the audio recorder. If `None`, the + :attr:`flet_audio_recorder.AudioRecorder.configuration` will be used. + upload: Upload settings to stream recording bytes directly + to a destination, for example a URL returned by + :meth:`flet.Page.get_upload_url`. + + Returns: + `True` if recording was successfully started, `False` otherwise. + + Raises: + ValueError: If `output_path` is not provided on platforms other than web + when neither streaming nor uploads are requested. + ValueError: If streaming is requested with an encoder other than + :attr:`~flet_audio_recorder.AudioEncoder.PCM16BITS`. + """ + is_streaming = upload is not None or self.on_stream is not None + if not is_streaming and not (self.page.web or output_path): + raise ValueError("output_path must be provided on platforms other than web") + + effective_configuration = ( + configuration if configuration is not None else self.configuration + ) + if is_streaming and effective_configuration.encoder != AudioEncoder.PCM16BITS: + raise ValueError( + "Streaming recordings require AudioEncoder.PCM16BITS as encoder." + ) + + return await self._invoke_method( + method_name="start_recording", + arguments={ + "output_path": output_path, + "configuration": effective_configuration, + "upload": upload, + }, + ) + + async def is_recording(self) -> bool: + """ + Checks whether the audio recorder is currently recording. + + Returns: + `True` if the recorder is currently recording, `False` otherwise. + """ + return await self._invoke_method("is_recording") + + async def stop_recording(self) -> Optional[str]: + """ + Stops the audio recording and optionally returns the recording location. + + Returns: + The local file path where the audio was saved, a Blob URL on web, or + `None` when streaming (i.e. when `upload` or :attr:`on_stream` is set). + """ + return await self._invoke_method("stop_recording") + + async def cancel_recording(self): + """ + Cancels the current audio recording. + """ + await self._invoke_method("cancel_recording") + + async def resume_recording(self): + """ + Resumes a paused audio recording. + """ + await self._invoke_method("resume_recording") + + async def pause_recording(self): + """ + Pauses the ongoing audio recording. + """ + await self._invoke_method("pause_recording") + + async def is_paused(self) -> bool: + """ + Checks whether the audio recorder is currently paused. + + Returns: + `True` if the recorder is paused, `False` otherwise. + """ + return await self._invoke_method("is_paused") + + async def is_supported_encoder(self, encoder: AudioEncoder) -> bool: + """ + Checks if the given audio encoder is supported by the recorder. + + Args: + encoder: The audio encoder to check. + + Returns: + `True` if the encoder is supported, `False` otherwise. + """ + return await self._invoke_method("is_supported_encoder", {"encoder": encoder}) + + async def get_input_devices(self) -> list[InputDevice]: + """ + Retrieves the available input devices for recording. + + Returns: + A list of available input devices. + """ + r = await self._invoke_method("get_input_devices") + return [ + InputDevice(id=device_id, label=label) for device_id, label in r.items() + ] + + async def has_permission(self) -> bool: + """ + Checks if the app has permission to record audio, requesting it if needed. + + Returns: + `True` if permission is already granted or granted after the request; + `False` otherwise. + """ + return await self._invoke_method("has_permission") diff --git a/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py new file mode 100644 index 0000000000..0f6472d21f --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flet_audio_recorder/types.py @@ -0,0 +1,443 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import TYPE_CHECKING, Optional + +import flet as ft + +if TYPE_CHECKING: + from .audio_recorder import AudioRecorder # noqa + +__all__ = [ + "AndroidAudioSource", + "AndroidRecorderConfiguration", + "AudioEncoder", + "AudioRecorderConfiguration", + "AudioRecorderState", + "AudioRecorderStateChangeEvent", + "AudioRecorderStreamEvent", + "AudioRecorderUploadEvent", + "AudioRecorderUploadSettings", + "InputDevice", + "IosAudioCategoryOption", + "IosRecorderConfiguration", +] + + +class AudioRecorderState(Enum): + """State of the audio recorder.""" + + STOPPED = "stopped" + """The audio recorder is stopped and not recording.""" + + RECORDING = "recording" + """The audio recorder is currently recording audio.""" + + PAUSED = "paused" + """The audio recorder is paused and can be resumed.""" + + +@dataclass +class AudioRecorderStateChangeEvent(ft.Event["AudioRecorder"]): + """ + Event payload for recorder state transitions. + + Delivered by :attr:`flet_audio_recorder.AudioRecorder.on_state_change`. + """ + + state: AudioRecorderState + """The new state of the audio recorder.""" + + +@dataclass +class AudioRecorderUploadEvent(ft.Event["AudioRecorder"]): + """ + Event payload for streaming recording uploads. + + Delivered by :attr:`flet_audio_recorder.AudioRecorder.on_upload` for + uploads started with :meth:`flet_audio_recorder.AudioRecorder.start_recording`. + """ + + file_name: Optional[str] = None + """Name provided by :attr:`AudioRecorderUploadSettings.file_name`.""" + + progress: Optional[float] = None + """ + Upload progress from `0.0` to `1.0`. + + Streaming uploads do not know their total size until recording stops, so + :attr:`bytes_uploaded` is usually the best progress indicator while recording is + active. + """ + + bytes_uploaded: Optional[int] = None + """Number of bytes uploaded so far.""" + + error: Optional[str] = None + """Error message if the upload failed.""" + + +@dataclass +class AudioRecorderStreamEvent(ft.Event["AudioRecorder"]): + """ + Event payload for raw recording stream chunks. + + Delivered by :attr:`flet_audio_recorder.AudioRecorder.on_stream`. + """ + + chunk: bytes + """ + Raw :attr:`~flet_audio_recorder.AudioEncoder.PCM16BITS` audio bytes emitted by \ + :class:`~flet_audio_recorder.AudioRecorder`. + """ + + sequence: int + """Incremental chunk number.""" + + bytes_streamed: int + """Total number of bytes delivered through :attr:`chunk` so far.""" + + +class AudioEncoder(Enum): + """ + Represents the different audio encoders for audio recording. + """ + + AACLC = "aacLc" + """ + Advanced Audio Codec Low Complexity. + A commonly used encoder for streaming and general audio recording. + """ + + AACELD = "aacEld" + """ + Advanced Audio Codec Enhanced Low Delay. + Suitable for low-latency applications like VoIP. + """ + + AACHE = "aacHe" + """ + Advanced Audio Codec High Efficiency. + Optimized for high-quality audio at lower bit rates. + """ + + AMRNB = "amrNb" + """ + Adaptive Multi-Rate Narrow Band. + Used for speech audio in mobile communication. + """ + + AMRWB = "amrWb" + """ + Adaptive Multi-Rate Wide Band. + Used for higher-quality speech audio. + """ + + OPUS = "opus" + """ + A codec designed for both speech and audio applications, + known for its versatility. + """ + + FLAC = "flac" + """ + Free Lossless Audio Codec. + Provides high-quality lossless audio compression. + """ + + WAV = "wav" + """ + Standard audio format used for raw, uncompressed audio data. + """ + + PCM16BITS = "pcm16bits" + """ + Pulse Code Modulation with 16-bit depth, used for high-fidelity audio. + """ + + +class AndroidAudioSource(Enum): + """Android-specific audio source types.""" + + DEFAULT_SOURCE = "defaultSource" + """Default audio source.""" + + MIC = "mic" + """Microphone audio source.""" + + VOICE_UPLINK = "voiceUplink" + """Voice call uplink (Tx) audio source.""" + + VOICE_DOWNLINK = "voiceDownlink" + """Voice call downlink (Rx) audio source.""" + + VOICE_CALL = "voiceCall" + """Voice call uplink + downlink audio source.""" + + CAMCORDER = "camcorder" + """ + Microphone audio source tuned for video recording, + with the same orientation as the camera, if available. + """ + + VOICE_RECOGNITION = "voiceRecognition" + """Microphone audio source tuned for voice recognition.""" + + VOICE_COMMUNICATION = "voiceCommunication" + """Microphone audio source tuned for voice communications such as VoIP.""" + + REMOTE_SUBMIX = "remoteSubMix" + """Audio source for a submix of audio streams to be presented remotely.""" + + UNPROCESSED = "unprocessed" + """ + Microphone audio source tuned for unprocessed (raw) sound if available, + behaves like `DEFAULT_SOURCE` otherwise. + """ + + VOICE_PERFORMANCE = "voicePerformance" + """ + Source for capturing audio meant to be processed in real time + and played back for live performance (e.g karaoke). + """ + + +@ft.value +class AndroidRecorderConfiguration: + """Android specific configuration for recording.""" + + use_legacy: bool = False + """ + Whether to use the Android MediaRecorder. + + While advanced recorder (the default) unlocks additional features, + the legacy recorder is stability oriented. + """ + + mute_audio: bool = False + """ + Whether to mute all audio streams like alarms, music, ring, etc. + + This is useful when you want to record audio without any background noise. + The streams are restored to their previous state after recording is stopped + and will stay at current state on pause/resume. + """ + + manage_bluetooth: bool = True + """ + Try to start a bluetooth audio connection to a headset (Bluetooth SCO). + """ + + audio_source: AndroidAudioSource = AndroidAudioSource.DEFAULT_SOURCE + """ + Defines the audio source. + + An audio source defines both a default physical source of audio signal, + and a recording configuration. + Some effects are available or not depending on this source. + + Most of the time, you should use + :attr:`flet_audio_recorder.AndroidAudioSource.DEFAULT_SOURCE` or + :attr:`flet_audio_recorder.AndroidAudioSource.MIC`. + """ + + +class IosAudioCategoryOption(Enum): + """ + Audio behaviors. + + Each option is valid only for specific audio session categories. + """ + + MIX_WITH_OTHERS = "mixWithOthers" + """ + Whether audio from this session mixes with audio + from active sessions in other audio apps. + """ + + DUCK_OTHERS = "duckOthers" + """ + Reduces the volume of other audio sessions while audio from this session plays. + """ + + ALLOW_BLUETOOTH = "allowBluetooth" + """ + Bluetooth hands-free devices appear as available input routes. + """ + + DEFAULT_TO_SPEAKER = "defaultToSpeaker" + """ + Audio from the session defaults to the built-in speaker instead of the receiver. + """ + + INTERRUPT_SPOKEN_AUDIO_AND_MIX_WITH_OTHERS = "interruptSpokenAudioAndMixWithOthers" + """ + Pause spoken audio content from other sessions when your app plays its audio. + + Available from iOS 9.0. + """ + + ALLOW_BLUETOOTH_A2DP = "allowBluetoothA2DP" + """ + Stream audio from this session to Bluetooth devices + that support the Advanced Audio Distribution Profile (A2DP). + + Note: + Available from iOS 10.0. + """ + + ALLOW_AIRPLAY = "allowAirPlay" + """ + Stream audio from this session to AirPlay devices. + + Note: + Available from iOS 10.0. + """ + + OVERRIDE_MUTED_MICROPHONE_INTERRUPTION = "overrideMutedMicrophoneInterruption" + """ + System interrupts the audio session when it mutes the built-in microphone. + + Note: + Available from iOS 14.5. + """ + + +@ft.value +class IosRecorderConfiguration: + """iOS specific configuration for recording.""" + + options: list[IosAudioCategoryOption] = field( + default_factory=lambda: [ + IosAudioCategoryOption.DEFAULT_TO_SPEAKER, + IosAudioCategoryOption.ALLOW_BLUETOOTH, + IosAudioCategoryOption.ALLOW_BLUETOOTH_A2DP, + ] + ) + """ + Optional audio behaviors. + """ + + manage_audio_session: bool = True + """ + Whether to manage the shared AVAudioSession. + + Set this to `False` if another plugin is + already managing the AVAudioSession. + """ + + +@ft.value +class InputDevice: + """An audio input device.""" + + id: str + """The ID used to select the device on the platform.""" + + label: str + """The label text representation.""" + + +@ft.value +class AudioRecorderConfiguration: + """Recording configuration.""" + + encoder: AudioEncoder = AudioEncoder.WAV + """ + The requested output format through this given encoder. + """ + + suppress_noise: bool = False + """ + The recorder will try to negate the input + noise (if available on the device). + + Recording volume may be lowered by using this. + """ + + cancel_echo: bool = False + """ + The recorder will try to reduce echo (if available on the device). + + Recording volume may be lowered by using this. + """ + + auto_gain: bool = False + """ + The recorder will try to auto adjust recording volume in a + limited range (if available on the device). + + Recording volume may be lowered by using this. + """ + + channels: int = 2 + """ + The numbers of channels for the recording. + + - `1` for mono + - `2` for stereo + + Most platforms only accept at most 2 channels. + """ + + sample_rate: int = 44100 + """ + The sample rate for audio in samples per second if applicable. + """ + + bit_rate: ft.Number = 128000 + """ + The audio encoding bit rate in bits per second if applicable. + """ + + device: Optional[InputDevice] = None + """ + The device to be used for recording. + + If `None`, default device will be selected. + """ + + android_configuration: AndroidRecorderConfiguration = field( + default_factory=lambda: AndroidRecorderConfiguration() + ) + """ + Android specific configuration. + """ + + ios_configuration: IosRecorderConfiguration = field( + default_factory=lambda: IosRecorderConfiguration() + ) + """ + iOS specific configuration. + """ + + +@ft.value +class AudioRecorderUploadSettings: + """ + Upload settings for streaming recordings. + + Note: + Uploads started by :meth:`flet_audio_recorder.AudioRecorder.start_recording` + send raw :attr:`~flet_audio_recorder.AudioEncoder.PCM16BITS` bytes. They do + not add a playable audio container such as WAV. + """ + + upload_url: str + """ + Destination URL, for example one returned by :meth:`flet.Page.get_upload_url`. + """ + + method: str = "PUT" + """ + HTTP method to use when uploading the streamed bytes. + """ + + headers: Optional[dict[str, str]] = None + """ + HTTP headers sent with the upload request. + """ + + file_name: Optional[str] = None + """ + Friendly name reported in upload events. + """ diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/.gitignore b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/CHANGELOG.md b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/CHANGELOG.md new file mode 100644 index 0000000000..010a321b90 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.1.0 + +Initial release of the package. diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/LICENSE b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/README.md b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/README.md new file mode 100644 index 0000000000..c0da60f9da --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/README.md @@ -0,0 +1,3 @@ +# Flet `AudioRecorder` control + +`AudioRecorder` control to use in Flet apps. diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/analysis_options.yaml b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/flet_audio_recorder.dart b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/flet_audio_recorder.dart new file mode 100644 index 0000000000..345e980435 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/flet_audio_recorder.dart @@ -0,0 +1,3 @@ +library flet_video; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/audio_recorder.dart b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/audio_recorder.dart new file mode 100644 index 0000000000..c91b8c7c47 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/audio_recorder.dart @@ -0,0 +1,470 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; +import 'package:http/http.dart' as http; +import 'package:record/record.dart'; + +import 'utils/audio_recorder.dart'; + +class AudioRecorderService extends FletService { + AudioRecorderService({required super.control}); + + AudioRecorder? recorder; + StreamSubscription? _onStateChangedSubscription; + + // Subscription to the raw PCM audio stream produced by `recorder.startStream`. + // Only active while a streaming recording (upload and/or Python-side stream) + // is in progress; `null` for regular file-based recordings. + StreamSubscription? _recordStreamSubscription; + + // Holds the state of the current streaming recording (upload request, + // bytes counter, completion signal). `null` when no streaming is active. + _StreamingSession? _streamSession; + + @override + void init() { + super.init(); + debugPrint("AudioRecorder.init($hashCode)"); + control.addInvokeMethodListener(_invokeMethod); + + recorder = AudioRecorder(); + + _onStateChangedSubscription = recorder!.onStateChanged().listen((state) { + _onStateChanged.call(state); + }); + } + + void _onStateChanged(RecordState state) { + var stateMap = { + RecordState.record: "recording", + RecordState.pause: "paused", + RecordState.stop: "stopped", + }; + control.triggerEvent("state_change", stateMap[state]); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("AudioRecorder.$name($args)"); + switch (name) { + case "start_recording": + final config = parseRecordConfig(args["configuration"]); + final upload = args["upload"]; + final stream = control.hasEventHandler("stream"); + if (config != null && await recorder!.hasPermission()) { + // If either upload or stream is requested, switch to the + // streaming code path (PCM chunks instead of file output). + if (upload != null || stream) { + return await _startStreamingRecording(config, upload, stream); + } + + final out = control.backend.getAssetSource(args["output_path"] ?? ""); + if (!isWebPlatform() && !out.isFile) { + // on non-web platforms, the output path must be a valid file path + return false; + } + + await recorder!.start(config, path: out.path); + return true; + } + return false; + case "stop_recording": + // For streaming recordings there is no output file to return; instead + // we stop the recorder and wait for the audio stream's `onDone` handler + // (`_finishStreamingRecording`) to flush and close the upload request. + if (_streamSession != null) { + await recorder!.stop(); + await _streamSession?.completed.future; + return null; + } + return await recorder!.stop(); + case "cancel_recording": + // Tear down any in-flight streaming session before cancelling the + // recorder so partial uploads are aborted and listeners are notified. + if (_streamSession != null) { + await _cancelStreamingRecording("Recording cancelled"); + } + await recorder!.cancel(); + break; + case "resume_recording": + await recorder!.resume(); + break; + case "pause_recording": + await recorder!.pause(); + break; + case "is_supported_encoder": + var encoder = parseAudioEncoder(args["encoder"]); + if (encoder != null) { + return await recorder!.isEncoderSupported(encoder); + } + break; + case "is_paused": + return await recorder!.isPaused(); + case "is_recording": + return await recorder!.isRecording(); + case "has_permission": + return await recorder!.hasPermission(); + case "get_input_devices": + List devices = await recorder!.listInputDevices(); + return devices.asMap().map((k, v) { + return MapEntry(v.id, v.label); + }); + default: + throw Exception("Unknown AudioRecorder method: $name"); + } + } + + @override + void dispose() { + debugPrint("AudioRecorder(${control.id}).dispose()"); + _onStateChangedSubscription?.cancel(); + _recordStreamSubscription?.cancel(); + _streamSession?.dispose(); + recorder?.dispose(); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + /// Starts a streaming recording. + /// + /// Depending on the arguments, the raw PCM chunks produced by the recorder + /// are either: + /// * forwarded to a remote HTTP endpoint via a chunked `StreamedRequest` + /// (when [uploadArgs] is provided), and/or + /// * pushed to Python as "stream" events (when [stream] is `true`). + /// + /// Both sinks can be active at the same time. Returns `true` if the + /// recorder successfully started streaming, `false` otherwise. + Future _startStreamingRecording( + RecordConfig config, + Map? uploadArgs, + bool stream, + ) async { + // Defensive cleanup: ensure no previous streaming session is lingering + // before we start a new one (e.g. if the user restarts without stopping). + await _recordStreamSubscription?.cancel(); + await _streamSession?.dispose(); + _recordStreamSubscription = null; + _streamSession = null; + + final uploadConfig = uploadArgs != null + ? _UploadConfig.fromMap(Map.from(uploadArgs)) + : null; + + // Build a chunked HTTP request up front. We don't call `.send()` yet — that + // happens after the audio subscription is wired up so the first chunks are not lost. + http.StreamedRequest? request; + if (uploadConfig != null) { + final uploadUrl = + _getFullUploadUrl(control.backend.pageUri, uploadConfig.url); + request = http.StreamedRequest(uploadConfig.method, Uri.parse(uploadUrl)); + if (uploadConfig.headers != null) { + request.headers.addAll(uploadConfig.headers!); + } + } + + final session = _StreamingSession( + stream: stream, uploadConfig: uploadConfig, request: request); + _streamSession = session; + + try { + final audioStream = await recorder!.startStream(config); + + // Emit an initial 0% progress event so listeners can show an upload + // started state before any bytes are produced by the microphone. + if (uploadConfig != null) { + _sendUploadEvent( + fileName: uploadConfig.fileName, progress: 0.0, bytesUploaded: 0); + } + + _recordStreamSubscription = audioStream.listen( + (chunk) { + // For every audio chunk produced by the recorder: count it, feed + // it to the HTTP upload sink (if any), and forward it to Python + // (if a stream handler is subscribed). + session.bytesSent += chunk.length; + session.request?.sink.add(chunk); + + if (session.request != null) { + _sendUploadEvent( + fileName: uploadConfig?.fileName, + bytesUploaded: session.bytesSent, + ); + } + + if (session.stream) { + _sendStreamEvent( + chunk, + sequence: session.nextSequence(), + bytesStreamed: session.bytesSent, + ); + } + }, + onError: (error) async { + if (uploadConfig != null) { + _sendUploadEvent( + fileName: uploadConfig.fileName, + error: error.toString(), + ); + } + await _cancelStreamingRecording(); + }, + onDone: () async { + // The recorder stopped normally — finalize the upload and notify. + await _finishStreamingRecording(); + }, + cancelOnError: true, + ); + + // Kick off the HTTP request now that the sink will receive chunks. + session.startUpload(); + return true; + } catch (error) { + // Anything thrown while starting the stream (permissions, network, + // recorder errors) is reported and the session is discarded. + if (uploadConfig != null) { + _sendUploadEvent( + fileName: uploadConfig.fileName, + error: error.toString(), + ); + } + session.complete(); + _streamSession = null; + return false; + } + } + + /// Finalizes a streaming recording after the audio stream's `onDone` fires. + /// + /// Closes the HTTP request sink, awaits the server response, and emits a + /// final progress or error event to Python. Always resets the streaming + /// state, even on failure, so a new recording can be started afterwards. + Future _finishStreamingRecording() async { + final session = _streamSession; + if (session == null) { + return; + } + + try { + // Closing the sink signals the end of the chunked request body so the + // server can finish processing and return a response. + await session.request?.sink.close(); + final responseFuture = session.responseFuture; + if (session.request != null && responseFuture != null) { + final response = await responseFuture; + // successful + if (response.statusCode >= 200 && response.statusCode <= 204) { + _sendUploadEvent( + fileName: session.uploadConfig?.fileName, + progress: 1.0, + bytesUploaded: session.bytesSent, + ); + } else { + // not successful + final body = await http.Response.fromStream(response); + _sendUploadEvent( + fileName: session.uploadConfig?.fileName, + error: + "Upload endpoint returned code ${response.statusCode}: ${body.body}", + ); + } + } + } catch (error) { + if (session.uploadConfig != null) { + _sendUploadEvent( + fileName: session.uploadConfig?.fileName, + error: error.toString(), + ); + } + } finally { + // Whatever happened, release the subscription and signal the + // `stop_recording` awaiter that the session has fully wound down. + session.complete(); + await _recordStreamSubscription?.cancel(); + _recordStreamSubscription = null; + _streamSession = null; + } + } + + /// Aborts the current streaming recording. + /// + /// Called when the user cancels a recording or the audio stream emits an + /// error. Closes the upload sink without waiting for a response, notifies + /// Python with [error] (defaulting to "Recording cancelled"), and resets + /// the streaming state. + Future _cancelStreamingRecording([String? error]) async { + final session = _streamSession; + if (session == null) { + return; + } + + try { + await _recordStreamSubscription?.cancel(); + _recordStreamSubscription = null; + await session.request?.sink.close(); + if (session.uploadConfig != null) { + _sendUploadEvent( + fileName: session.uploadConfig?.fileName, + error: error ?? "Recording cancelled", + ); + } + } finally { + session.complete(); + _streamSession = null; + } + } + + /// Fires the "upload" event on the Python-side control with the current + /// upload progress or an error message. Any field may be null when not + /// applicable (e.g. `progress` is null for per-chunk progress pings). + void _sendUploadEvent({ + String? fileName, + double? progress, + int? bytesUploaded, + String? error, + }) { + control.triggerEvent("upload", { + "file_name": fileName, + "progress": progress, + "bytes_uploaded": bytesUploaded, + "error": error, + }); + } + + /// Fires the "stream" event with a single PCM [chunk] and its monotonically + /// increasing [sequence] number, allowing the Python side to reassemble the + /// audio in order and detect gaps. + void _sendStreamEvent( + Uint8List chunk, { + required int sequence, + required int bytesStreamed, + }) { + control.triggerEvent("stream", { + "chunk": chunk, + "sequence": sequence, + "bytes_streamed": bytesStreamed, + }); + } + + /// Resolves a possibly-relative [uploadUrl] against the current [pageUri]. + /// + /// If [uploadUrl] already contains an authority (scheme + host) it is used + /// verbatim; otherwise its path/query are combined with the page's + /// scheme/host/port so that relative upload endpoints work out of the box. + String _getFullUploadUrl(Uri pageUri, String uploadUrl) { + final uploadUri = Uri.parse(uploadUrl); + if (uploadUri.hasAuthority) { + return uploadUrl; + } + return Uri( + scheme: pageUri.scheme, + host: pageUri.host, + port: pageUri.port, + path: uploadUri.path, + query: uploadUri.query, + ).toString(); + } +} + +/// Value object describing where/how the streamed recording should be +/// uploaded. Built from the `upload` dict passed from Python on `start_recording`. +class _UploadConfig { + const _UploadConfig({ + required this.url, + required this.method, + this.headers, + this.fileName, + }); + + /// Parses the raw map received from Python. + factory _UploadConfig.fromMap(Map value) { + final headers = value["headers"]; + return _UploadConfig( + url: value["upload_url"], + method: (value["method"] ?? "PUT").toString().toUpperCase(), + headers: headers != null ? Map.from(headers) : null, + fileName: value["file_name"], + ); + } + + /// Destination URL — may be absolute or relative to the Flet page URI. + final String url; + + /// HTTP method to use for the upload (e.g. `PUT` or `POST`). + final String method; + + /// Optional request headers (e.g. auth, content-type). + final Map? headers; + + /// Optional file name echoed back in upload events so Python listeners + /// can correlate progress updates with a specific recording. + final String? fileName; +} + +/// Bundles everything needed to track a single streaming recording: +/// * whether Python is listening to `stream` events, +/// * the upload config and HTTP request (if uploading), +/// * byte/sequence counters, and +/// * a `Completer` used by `stop_recording` to await clean shutdown. +class _StreamingSession { + _StreamingSession({required this.stream, this.uploadConfig, this.request}) + : completed = Completer(); + + /// `true` when Python has a handler attached for the "stream" event. + final bool stream; + + /// Upload target for this session, or `null` when only streaming to Python. + final _UploadConfig? uploadConfig; + + /// Chunked HTTP request receiving the PCM bytes, or `null` when not uploading. + final http.StreamedRequest? request; + + /// Resolves once the session has fully torn down (success, error, or + /// cancellation). Awaited by `stop_recording` so callers can rely on the + /// upload being flushed before the method returns. + final Completer completed; + + /// Future of the server response to the chunked upload. Populated by + /// [startUpload] and awaited by `_finishStreamingRecording`. + Future? responseFuture; + + /// Total number of audio bytes produced so far — used for progress events + /// and as the final uploaded-bytes count. + int bytesSent = 0; + + /// Monotonic counter for stream events, incremented by [nextSequence]. + int _sequence = 0; + + /// Starts sending the chunked request. Must be called after the audio + /// subscription has been attached so no chunks are dropped. + void startUpload() { + if (request != null) { + responseFuture = request!.send(); + } + } + + /// Returns the next sequence number for a "stream" event (starts at 1). + int nextSequence() { + _sequence += 1; + return _sequence; + } + + /// Marks the session as fully wound down. Safe to call multiple times. + void complete() { + if (!completed.isCompleted) { + completed.complete(); + } + } + + /// Best-effort cleanup used when the service itself is being disposed + /// (e.g. the control is removed from the page mid-recording). + Future dispose() async { + try { + await request?.sink.close(); + } catch (_) { + // Ignore sink shutdown errors during service disposal. + } + complete(); + } +} diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/extension.dart b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/extension.dart new file mode 100644 index 0000000000..a7b9865ad9 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/extension.dart @@ -0,0 +1,15 @@ +import 'package:flet/flet.dart'; + +import 'audio_recorder.dart'; + +class Extension extends FletExtension { + @override + FletService? createService(Control control) { + switch (control.type) { + case "AudioRecorder": + return AudioRecorderService(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart new file mode 100644 index 0000000000..9f65d339df --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart @@ -0,0 +1,73 @@ +import 'package:collection/collection.dart'; +import 'package:flet/flet.dart'; +import 'package:record/record.dart'; + +AudioEncoder? parseAudioEncoder(String? value, [AudioEncoder? defaultValue]) { + if (value == null) return defaultValue; + return AudioEncoder.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +InputDevice? parseInputDevice(dynamic value, [InputDevice? defaultValue]) { + if (value == null) return defaultValue; + return InputDevice(id: value["id"], label: value["label"]); +} + +AndroidAudioSource? parseAndroidAudioSource(String? value, + [AndroidAudioSource? defaultValue]) { + if (value == null) return defaultValue; + return AndroidAudioSource.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +AndroidRecordConfig? parseAndroidRecordConfig(dynamic value, + [AndroidRecordConfig? defaultValue]) { + if (value == null) return defaultValue; + return AndroidRecordConfig( + audioSource: parseAndroidAudioSource( + value["audio_source"], AndroidAudioSource.defaultSource)!, + manageBluetooth: parseBool(value["manage_bluetooth"], true)!, + muteAudio: parseBool(value["mute_audio"], false)!, + useLegacy: parseBool(value["use_legacy"], false)!); +} + +IosAudioCategoryOption? parseIosAudioCategoryOption(String? value, + [IosAudioCategoryOption? defaultValue]) { + if (value == null) return defaultValue; + return IosAudioCategoryOption.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +IosRecordConfig? parseIosRecordConfig(dynamic value, + [IosRecordConfig? defaultValue]) { + if (value == null) return defaultValue; + var options = (value["options"] as List) + .map((o) => parseIosAudioCategoryOption(o)) + .nonNulls + .toList(); + return IosRecordConfig( + manageAudioSession: parseBool(value["manage_audio_session"], true)!, + categoryOptions: options, + ); +} + +RecordConfig? parseRecordConfig(dynamic value, [RecordConfig? defaultValue]) { + if (value == null) return defaultValue; + return RecordConfig( + autoGain: parseBool(value["auto_gain"], false)!, + bitRate: parseInt(value["bit_rate"], 128000)!, + encoder: parseAudioEncoder(value["encoder"], AudioEncoder.wav)!, + echoCancel: parseBool(value["cancel_echo"], false)!, + noiseSuppress: parseBool(value["suppress_noise"], false)!, + numChannels: parseInt(value["channels"], 2)!, + device: parseInputDevice(value["device"]), + sampleRate: parseInt(value["sample_rate"], 44100)!, + androidConfig: parseAndroidRecordConfig( + value["android_configuration"], const AndroidRecordConfig())!, + iosConfig: parseIosRecordConfig( + value["ios_configuration"], const IosRecordConfig())!, + ); +} diff --git a/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml new file mode 100644 index 0000000000..626f0576e3 --- /dev/null +++ b/sdk/python/packages/flet-audio-recorder/src/flutter/flet_audio_recorder/pubspec.yaml @@ -0,0 +1,24 @@ +name: flet_audio_recorder +description: Flet AudioRecorder control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + http: ^1.2.2 + record: ^6.2.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-audio/CHANGELOG.md b/sdk/python/packages/flet-audio/CHANGELOG.md new file mode 100644 index 0000000000..7b2214db56 --- /dev/null +++ b/sdk/python/packages/flet-audio/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.80.0 + +## Added + +- Deployed online documentation: https://flet-dev.github.io/flet-audio/ + +### Changed + +- Refactored `Audio` control to use `@ft.control` dataclass-style definition and switched to `Service` control type. + +### Breaking Changes + +- `Audio` must now be added to `Page.services` instead of `Page.overlay`. +- The following properties were renamed: + - `on_state_changed` → `on_state_change` + - `on_duration_changed` → `on_duration_change` + - `on_position_changed` → `on_position_change` +- Method `Audio.play()` now accepts an optional `position` parameter for specifying start position. +- The following sync methods were made [`async`](https://docs.python.org/3/library/asyncio.html): + - `get_duration()` + - `get_current_position()` + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-audio/LICENSE b/sdk/python/packages/flet-audio/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-audio/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-audio/README.md b/sdk/python/packages/flet-audio/README.md new file mode 100644 index 0000000000..b44c8adc32 --- /dev/null +++ b/sdk/python/packages/flet-audio/README.md @@ -0,0 +1,53 @@ +# flet-audio + +[![pypi](https://img.shields.io/pypi/v/flet-audio.svg)](https://pypi.python.org/pypi/flet-audio) +[![downloads](https://static.pepy.tech/badge/flet-audio/month)](https://pepy.tech/project/flet-audio) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-audio) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-audio.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-audio.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-audio/LICENSE) + +A [Flet](https://flet.dev) extension package for playing audio. + +It is based on the [audioplayers](https://pub.dev/packages/audioplayers) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/services/audio/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-audio` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-audio + ``` + +- Using `pip`: + ```bash + pip install flet-audio + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +> [!NOTE] +> On Linux/WSL, you need to install [`GStreamer`](https://github.com/GStreamer/gstreamer) library. +> +> If you receive `error while loading shared libraries: libgstapp-1.0.so.0`, it means `GStreamer` is not installed in your WSL environment. +> +> To install it, run the following command: +> +> ```bash +> apt install -y libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-tools +> ``` + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/audio). diff --git a/sdk/python/packages/flet-audio/pyproject.toml b/sdk/python/packages/flet-audio/pyproject.toml new file mode 100644 index 0000000000..1914b2e4a1 --- /dev/null +++ b/sdk/python/packages/flet-audio/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-audio" +version = "0.1.0" +description = "Provides audio integration and playback in Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/services/audio" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-audio" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_audio" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-audio/src/flet_audio/__init__.py b/sdk/python/packages/flet-audio/src/flet_audio/__init__.py new file mode 100644 index 0000000000..0161798244 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flet_audio/__init__.py @@ -0,0 +1,17 @@ +from flet_audio.audio import Audio +from flet_audio.types import ( + AudioDurationChangeEvent, + AudioPositionChangeEvent, + AudioState, + AudioStateChangeEvent, + ReleaseMode, +) + +__all__ = [ + "Audio", + "AudioDurationChangeEvent", + "AudioPositionChangeEvent", + "AudioState", + "AudioStateChangeEvent", + "ReleaseMode", +] diff --git a/sdk/python/packages/flet-audio/src/flet_audio/audio.py b/sdk/python/packages/flet-audio/src/flet_audio/audio.py new file mode 100644 index 0000000000..5fdc039ae2 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flet_audio/audio.py @@ -0,0 +1,174 @@ +from typing import Optional, Union + +import flet as ft +from flet_audio.types import ( + AudioDurationChangeEvent, + AudioPositionChangeEvent, + AudioStateChangeEvent, + ReleaseMode, +) + + +@ft.control("Audio") +class Audio(ft.Service): + """ + A control to simultaneously play multiple audio sources. + """ + + src: Optional[Union[str, bytes]] = None + """ + The audio source. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + + Note: + [Here](https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md#supported-formats--encodings) + is a list of supported audio formats. + """ + + autoplay: bool = False + """ + Starts playing audio as soon as audio control is added to a page. + + Note: + Autoplay works in desktop, mobile apps and Safari browser, + but doesn't work in Chrome/Edge. + """ + + volume: ft.Number = 1.0 + """ + Sets the volume (amplitude). + It's value ranges between `0.0` (mute) and `1.0` (maximum volume). + Intermediate values are linearly interpolated. + """ + + balance: ft.Number = 0.0 + """ + Defines the stereo balance. + + * `-1` - The left channel is at full volume; the right channel is silent. + * `1` - The right channel is at full volume; the left channel is silent. + * `0` - Both channels are at the same volume. + """ + + playback_rate: ft.Number = 1.0 + """ + Defines the playback rate. + + Should ideally be set when creating the constructor. + + Note: + - iOS and macOS have limits between `0.5x` and `2x`. + - Android SDK version should be 23 or higher. + """ + + release_mode: ReleaseMode = ReleaseMode.RELEASE + """ + Defines the release mode. + """ + + on_loaded: Optional[ft.ControlEventHandler["Audio"]] = None + """ + Fires when an audio is loaded/buffered. + """ + + on_duration_change: Optional[ft.EventHandler[AudioDurationChangeEvent]] = None + """ + Fires as soon as audio duration is available + (it might take a while to download or buffer it). + """ + + on_state_change: Optional[ft.EventHandler[AudioStateChangeEvent]] = None + """ + Fires when audio player state changes. + """ + + on_position_change: Optional[ft.EventHandler[AudioPositionChangeEvent]] = None + """ + Fires when audio position is changed. + Will continuously update the position of the playback + every 1 second if the status is playing. + + Can be used for a progress bar. + """ + + on_seek_complete: Optional[ft.ControlEventHandler["Audio"]] = None + """ + Fires on seek completions. + An event is going to be sent as soon as the audio seek is finished. + """ + + async def play(self, position: ft.DurationValue = 0): + """ + Starts playing audio from the specified `position`. + + Args: + position: The position to start playback from. + """ + await self._invoke_method( + method_name="play", + arguments={"position": position}, + ) + + async def pause(self): + """ + Pauses the audio that is currently playing. + + If you call :meth:`~flet_audio.Audio.resume` later, + the audio will resume from the point that it has been paused. + """ + await self._invoke_method("pause") + + async def resume(self): + """ + Resumes the audio that has been paused or stopped. + """ + await self._invoke_method("resume") + + async def release(self): + """ + Releases the resources associated with this media player. + These are going to be fetched or buffered again as soon as + you change the source or call :meth:`~flet_audio.Audio.resume`. + """ + await self._invoke_method("release") + + async def seek(self, position: ft.DurationValue): + """ + Moves the cursor to the desired position. + + Args: + position: The position to seek/move to. + """ + await self._invoke_method( + method_name="seek", + arguments={"position": position}, + ) + + async def get_duration(self) -> Optional[ft.Duration]: + """ + Get audio duration of the audio playback. + + It will be available as soon as the audio duration is available + (it might take a while to download or buffer it if file is not local). + + Returns: + The duration of audio playback. + """ + return await self._invoke_method( + method_name="get_duration", + ) + + async def get_current_position(self) -> Optional[ft.Duration]: + """ + Get the current position of the audio playback. + + Returns: + The current position of the audio playback. + """ + return await self._invoke_method( + method_name="get_current_position", + ) diff --git a/sdk/python/packages/flet-audio/src/flet_audio/types.py b/sdk/python/packages/flet-audio/src/flet_audio/types.py new file mode 100644 index 0000000000..bf101549d4 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flet_audio/types.py @@ -0,0 +1,94 @@ +from dataclasses import dataclass +from enum import Enum +from typing import TYPE_CHECKING + +import flet as ft + +if TYPE_CHECKING: + from flet_audio.audio import Audio # noqa + +__all__ = [ + "AudioDurationChangeEvent", + "AudioPositionChangeEvent", + "AudioState", + "AudioStateChangeEvent", + "ReleaseMode", +] + + +class ReleaseMode(Enum): + """The behavior of Audio player when an audio is finished or stopped.""" + + RELEASE = "release" + """ + Releases all resources, just like calling release method. + + Info: + - On Android, the media player is quite resource-intensive, and this will + let it go. Data will be buffered again when needed (if it's a remote file, + it will be downloaded again). + - On iOS and macOS, works just like + :meth:`flet_audio.Audio.release` method. + """ + + LOOP = "loop" + """ + Keeps buffered data and plays again after completion, creating a loop. + Notice that calling stop method is not enough to release the resources + when this mode is being used. + """ + + STOP = "stop" + """ + Stops audio playback but keep all resources intact. + Use this if you intend to play again later. + """ + + +class AudioState(Enum): + """The state of the audio player.""" + + STOPPED = "stopped" + """The audio player is stopped.""" + + PLAYING = "playing" + """The audio player is currently playing audio.""" + + PAUSED = "paused" + """The audio player is paused and can be resumed.""" + + COMPLETED = "completed" + """The audio player has successfully reached the end of the audio.""" + + DISPOSED = "disposed" + """The audio player has been disposed of and should not be used anymore.""" + + +@dataclass +class AudioStateChangeEvent(ft.Event["Audio"]): + """ + Event triggered when the audio playback state changes. + """ + + state: AudioState + """The current state of the audio player.""" + + +@dataclass +class AudioPositionChangeEvent(ft.Event["Audio"]): + """ + Event triggered when the audio playback position changes. + """ + + position: int + """The current playback position in milliseconds.""" + + +@dataclass +class AudioDurationChangeEvent(ft.Event["Audio"]): + """ + Event triggered when the audio duration changes. + """ + + duration: ft.Duration + """The duration of the audio.""" diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/.gitignore b/sdk/python/packages/flet-audio/src/flutter/flet_audio/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/.metadata b/sdk/python/packages/flet-audio/src/flutter/flet_audio/.metadata new file mode 100644 index 0000000000..07d8623a38 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2e9cb0aa71a386a91f73f7088d115c0d96654829" + channel: "stable" + +project_type: package diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/analysis_options.yaml b/sdk/python/packages/flet-audio/src/flutter/flet_audio/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/flet_audio.dart b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/flet_audio.dart new file mode 100644 index 0000000000..60323733ba --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/flet_audio.dart @@ -0,0 +1,3 @@ +library flet_audio; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/audio.dart b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/audio.dart new file mode 100644 index 0000000000..fed3367b1b --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/audio.dart @@ -0,0 +1,184 @@ +import 'dart:async'; + +import 'package:audioplayers/audioplayers.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; + +import 'utils/audio.dart'; + +class AudioService extends FletService { + AudioService({required super.control}); + + AudioPlayer player = AudioPlayer(); + Duration? _duration; + int _position = -1; + StreamSubscription? _onDurationChangedSubscription; + StreamSubscription? _onStateChangedSubscription; + StreamSubscription? _onPositionChangedSubscription; + StreamSubscription? _onSeekCompleteSubscription; + + String? _src; + Uint8List? _srcBytes; + ReleaseMode? _releaseMode; + double? _volume; + double? _balance; + double? _playbackRate; + + @override + void init() { + super.init(); + debugPrint("Audio(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + + _onDurationChangedSubscription = + player.onDurationChanged.listen((duration) { + control.triggerEvent("duration_change", {"duration": duration}); + _duration = duration; + }); + + _onStateChangedSubscription = + player.onPlayerStateChanged.listen((PlayerState state) { + control.triggerEvent("state_change", {"state": state.name}); + }); + + _onPositionChangedSubscription = + player.onPositionChanged.listen((position) { + int posMs = (position.inMilliseconds / 1000).round() * 1000; + if (posMs != _position) { + _position = posMs; + } else if (position.inMilliseconds == _duration?.inMilliseconds) { + _position = _duration!.inMilliseconds; + } else { + return; + } + control.triggerEvent("position_change", {"position": posMs}); + }); + + _onSeekCompleteSubscription = player.onSeekComplete.listen((event) { + control.triggerEvent("seek_complete"); + }); + + update(); + } + + @override + void update() { + debugPrint("Audio(${control.id}).update: ${control.properties}"); + + final resolvedSrc = control.getSrc("src"); + if (resolvedSrc.error != null) { + throw Exception("Audio src decode error: ${resolvedSrc.error}"); + } + if (resolvedSrc.isEmpty) { + throw Exception("Audio must have \"src\" specified."); + } + var autoplay = control.getBool("autoplay", false)!; + var volume = control.getDouble("volume", 1.0)!; + var balance = control.getDouble("balance", 0.0)!; + var playbackRate = control.getDouble("playback_rate", 1)!; + var releaseMode = parseReleaseMode(control.getString("release_mode")); + + () async { + bool srcChanged = false; + // URL or file + if (resolvedSrc.uri != null && resolvedSrc.uri != _src) { + _src = resolvedSrc.uri; + _srcBytes = null; + srcChanged = true; + + var assetSrc = control.backend.getAssetSource(_src!); + if (assetSrc.isFile) { + await player.setSourceDeviceFile(assetSrc.path); + } else { + await player.setSourceUrl(assetSrc.path); + } + } else if (resolvedSrc.bytes != null && + (_srcBytes == null || !listEquals(_srcBytes, resolvedSrc.bytes))) { + // bytes + _srcBytes = resolvedSrc.bytes; + _src = null; + srcChanged = true; + await player.setSourceBytes(resolvedSrc.bytes!); + } + + if (srcChanged) { + control.triggerEvent("loaded"); + } + + // releaseMode + if (releaseMode != null && releaseMode != _releaseMode) { + _releaseMode = releaseMode; + await player.setReleaseMode(releaseMode); + } + + // volume + if (volume != _volume && volume >= 0 && volume <= 1) { + _volume = volume; + await player.setVolume(volume); + } + + // playbackRate + if (playbackRate != _playbackRate) { + _playbackRate = playbackRate; + await player.setPlaybackRate(playbackRate); + } + + // balance + if (!kIsWeb && balance != _balance && balance >= -1 && balance <= 1) { + _balance = balance; + await player.setBalance(balance); + } + + // autoplay + if (srcChanged && autoplay) { + await player.resume(); + } + }(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Audio.$name($args)"); + switch (name) { + case "play": + final position = parseDuration(args["position"]); + if (position != null) { + await player.seek(position); + } + await player.resume(); + break; + case "resume": + await player.resume(); + break; + case "pause": + await player.pause(); + break; + case "release": + await player.release(); + break; + case "seek": + final position = parseDuration(args["position"]); + if (position != null) { + await player.seek(position); + } + break; + case "get_duration": + return await player.getDuration(); + case "get_current_position": + return await player.getCurrentPosition(); + default: + throw Exception("Unknown Audio method: $name"); + } + } + + @override + void dispose() { + debugPrint("Audio(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + _onDurationChangedSubscription?.cancel(); + _onStateChangedSubscription?.cancel(); + _onPositionChangedSubscription?.cancel(); + _onSeekCompleteSubscription?.cancel(); + player.dispose(); + super.dispose(); + } +} diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/extension.dart b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/extension.dart new file mode 100644 index 0000000000..392ae16161 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/extension.dart @@ -0,0 +1,15 @@ +import 'package:flet/flet.dart'; + +import 'audio.dart'; + +class Extension extends FletExtension { + @override + FletService? createService(Control control) { + switch (control.type) { + case "Audio": + return AudioService(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/utils/audio.dart b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/utils/audio.dart new file mode 100644 index 0000000000..aa6ef27e61 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/lib/src/utils/audio.dart @@ -0,0 +1,9 @@ +import 'package:audioplayers/audioplayers.dart'; +import 'package:collection/collection.dart'; + +ReleaseMode? parseReleaseMode(String? value, [ReleaseMode? defaultValue]) { + if (value == null) return defaultValue; + return ReleaseMode.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} diff --git a/sdk/python/packages/flet-audio/src/flutter/flet_audio/pubspec.yaml b/sdk/python/packages/flet-audio/src/flutter/flet_audio/pubspec.yaml new file mode 100644 index 0000000000..de72ee7be4 --- /dev/null +++ b/sdk/python/packages/flet-audio/src/flutter/flet_audio/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_audio +description: Flet Audio control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + audioplayers: ^6.6.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-camera/LICENSE b/sdk/python/packages/flet-camera/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-camera/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-camera/README.md b/sdk/python/packages/flet-camera/README.md new file mode 100644 index 0000000000..5df0e3441e --- /dev/null +++ b/sdk/python/packages/flet-camera/README.md @@ -0,0 +1,42 @@ +# flet-camera + +[![pypi](https://img.shields.io/pypi/v/flet-camera.svg)](https://pypi.python.org/pypi/flet-camera) +[![downloads](https://static.pepy.tech/badge/flet-camera/month)](https://pepy.tech/project/flet-camera) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-camera) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-camera.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-camera.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-camera/LICENSE) + +A camera control for [Flet](https://flet.dev) apps. + +It is powered by the [camera](https://pub.dev/packages/camera) Flutter package. + +## Documentation + +Detailed documentation for this package can be found [here](https://flet.dev/docs/controls/camera/). + +## Platform Support + +| Platform | iOS | Android | Web | Windows | macOS | Linux | +|----------|-----|---------|-----|---------|-------|-------| +| Supported| ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | + +## Usage + +### Installation + +To install the `flet-camera` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-camera + ``` + +- Using `pip`: + ```bash + pip install flet-camera + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Permissions + +Camera access requires runtime permissions on mobile and desktop platforms. Use the [`flet-permission-handler`](https://pypi.org/project/flet-permission-handler/) package to request camera and microphone permissions before initializing the control. diff --git a/sdk/python/packages/flet-camera/pyproject.toml b/sdk/python/packages/flet-camera/pyproject.toml new file mode 100644 index 0000000000..8bdc6fe12f --- /dev/null +++ b/sdk/python/packages/flet-camera/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-camera" +version = "0.1.0" +description = "Camera control for Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/camera" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-camera" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_camera" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-camera/src/flet_camera/__init__.py b/sdk/python/packages/flet-camera/src/flet_camera/__init__.py new file mode 100644 index 0000000000..c8b8a74d27 --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flet_camera/__init__.py @@ -0,0 +1,35 @@ +""" +Public exports for the flet-camera package. +""" + +from flet_camera.camera import Camera +from flet_camera.types import ( + CameraDescription, + CameraImageEvent, + CameraLensDirection, + CameraLensType, + CameraPreviewSize, + CameraStateEvent, + ExposureMode, + FlashMode, + FocusMode, + ImageFormatGroup, + ResolutionPreset, +) +from flet_camera.utils import detect_video_extension + +__all__ = [ + "Camera", + "CameraDescription", + "CameraImageEvent", + "CameraLensDirection", + "CameraLensType", + "CameraPreviewSize", + "CameraStateEvent", + "ExposureMode", + "FlashMode", + "FocusMode", + "ImageFormatGroup", + "ResolutionPreset", + "detect_video_extension", +] diff --git a/sdk/python/packages/flet-camera/src/flet_camera/camera.py b/sdk/python/packages/flet-camera/src/flet_camera/camera.py new file mode 100644 index 0000000000..5de864202d --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flet_camera/camera.py @@ -0,0 +1,270 @@ +""" +Camera control definition for the flet-camera package. +""" + +from typing import Optional + +import flet as ft +from flet.utils import from_dict +from flet_camera.types import ( + CameraDescription, + CameraImageEvent, + CameraStateEvent, + ExposureMode, + FlashMode, + FocusMode, + ImageFormatGroup, + ResolutionPreset, +) + +__all__ = ["Camera"] + + +@ft.control("Camera") +class Camera(ft.LayoutControl): + """ + A control that provides camera preview and capture capabilities. + """ + + preview_enabled: bool = True + """ + Whether the preview surface is shown. + """ + + content: Optional[ft.Control] = None + """ + Optional child to overlay on top of the camera preview. + """ + + on_state_change: Optional[ft.EventHandler[CameraStateEvent]] = None + """Fires when the camera controller state changes.""" + + on_stream_image: Optional[ft.EventHandler[CameraImageEvent]] = None + """ + Fires when an image frame is available while streaming. + """ + + async def get_available_cameras(self) -> list[CameraDescription]: + """ + Lists the available camera devices on the current platform. + + Returns: + A list of available camera descriptions. + """ + cameras = await self._invoke_method("get_available_cameras") + return [from_dict(CameraDescription, c) for c in cameras or []] + + async def initialize( + self, + description: CameraDescription, + resolution_preset: ResolutionPreset, + enable_audio: bool = True, + fps: Optional[int] = None, + video_bitrate: Optional[int] = None, + audio_bitrate: Optional[int] = None, + image_format_group: Optional[ImageFormatGroup] = None, + ): + """ + Initializes a new camera controller for the given description. + + Args: + description: Camera device to bind to. + resolution_preset: Desired resolution preset. + enable_audio: Whether audio is enabled for recordings. + fps: Optional target frames per second. + video_bitrate: Optional video bitrate. + audio_bitrate: Optional audio bitrate. + image_format_group: Optional image format group override. + """ + await self._invoke_method( + "initialize", + { + "description": description, + "resolution_preset": resolution_preset, + "enable_audio": enable_audio, + "fps": fps, + "video_bitrate": video_bitrate, + "audio_bitrate": audio_bitrate, + "image_format_group": image_format_group, + }, + ) + + async def get_exposure_offset_step_size(self) -> float: + """Returns the smallest increment supported for exposure offset changes.""" + return await self._invoke_method("get_exposure_offset_step_size") + + async def get_max_exposure_offset(self) -> float: + """Maximum exposure offset supported by the current camera.""" + return await self._invoke_method("get_max_exposure_offset") + + async def get_max_zoom_level(self) -> float: + """Maximum zoom level supported by the current camera.""" + return await self._invoke_method("get_max_zoom_level") + + async def get_min_exposure_offset(self) -> float: + """Minimum exposure offset supported by the current camera.""" + return await self._invoke_method("get_min_exposure_offset") + + async def get_min_zoom_level(self) -> float: + """Minimum zoom level supported by the current camera.""" + return await self._invoke_method("get_min_zoom_level") + + async def lock_capture_orientation( + self, orientation: Optional[ft.DeviceOrientation] = None + ): + """ + Locks capture orientation to the specified device orientation. + + Args: + orientation: Specific orientation to lock, or current + device orientation if None. + """ + await self._invoke_method( + "lock_capture_orientation", + {"orientation": orientation}, + ) + + async def unlock_capture_orientation(self): + """Unlocks the capture orientation.""" + await self._invoke_method("unlock_capture_orientation") + + async def pause_preview(self): + """Pauses the camera preview.""" + await self._invoke_method("pause_preview") + + async def resume_preview(self): + """Resumes the camera preview.""" + await self._invoke_method("resume_preview") + + async def take_picture(self) -> bytes: + """ + Captures a still image and returns the encoded bytes. + + Returns: + Encoded image bytes. + """ + return await self._invoke_method("take_picture") + + async def prepare_for_video_recording(self): + """Prepares the capture session for video recording.""" + await self._invoke_method("prepare_for_video_recording") + + async def start_video_recording(self): + """Starts capturing video.""" + await self._invoke_method("start_video_recording") + + async def pause_video_recording(self): + """Pauses an active video recording.""" + await self._invoke_method("pause_video_recording") + + async def resume_video_recording(self): + """Resumes a paused video recording.""" + await self._invoke_method("resume_video_recording") + + async def stop_video_recording(self) -> bytes: + """ + Stops video recording and returns the recorded bytes. + + Returns: + Encoded video file bytes. + """ + return await self._invoke_method("stop_video_recording") + + async def supports_image_streaming(self) -> bool: + """Indicates whether image streaming is supported on the current platform.""" + return await self._invoke_method("supports_image_streaming") + + async def start_image_stream(self): + """Begins streaming camera image frames.""" + await self._invoke_method("start_image_stream") + + async def stop_image_stream(self): + """Stops streaming camera image frames.""" + await self._invoke_method("stop_image_stream") + + async def set_description(self, description: CameraDescription): + """ + Switches to another camera description. + + Args: + description: Camera to switch to. + """ + await self._invoke_method("set_description", {"description": description}) + + async def set_exposure_mode(self, mode: ExposureMode): + """Changes the exposure mode. + + Args: + mode: Exposure mode to apply. + """ + await self._invoke_method("set_exposure_mode", {"mode": mode}) + + async def set_exposure_offset(self, offset: float) -> float: + """Sets exposure offset in EV units. + + Args: + offset: Exposure offset to apply. + + Returns: + The offset value that was set. + """ + return await self._invoke_method("set_exposure_offset", {"offset": offset}) + + async def set_exposure_point(self, point: Optional[ft.OffsetValue]): + """ + Sets the exposure metering point. + + Args: + point: Normalized offset (0..1) or None to reset. + """ + await self._invoke_method("set_exposure_point", {"point": point}) + + async def set_flash_mode(self, mode: FlashMode): + """Changes the flash mode. + + Args: + mode: Flash mode to apply. + """ + await self._invoke_method("set_flash_mode", {"mode": mode}) + + async def set_focus_mode(self, mode: FocusMode): + """Changes the focus mode. + + Args: + mode: Focus mode to apply. + """ + await self._invoke_method("set_focus_mode", {"mode": mode}) + + async def set_focus_point(self, point: Optional[ft.OffsetValue]): + """ + Sets the focus metering point. + + Args: + point: Normalized offset (0..1) or None to reset. + """ + await self._invoke_method("set_focus_point", {"point": point}) + + async def set_zoom_level(self, zoom: float): + """Applies the provided zoom level. + + Args: + zoom: Zoom level to set. + """ + await self._invoke_method("set_zoom_level", {"zoom": zoom}) + + def before_update(self): + """Validate platform support prior to sending updates.""" + super().before_update() + + # validate platform + if not ( + self.page.web + or self.page.platform + in [ + ft.PagePlatform.ANDROID, + ft.PagePlatform.IOS, + ] + ): + raise ft.FletUnsupportedPlatformException( + "Camera is currently only supported on Android, iOS and Web platforms." + ) diff --git a/sdk/python/packages/flet-camera/src/flet_camera/types.py b/sdk/python/packages/flet-camera/src/flet_camera/types.py new file mode 100644 index 0000000000..aa1f2e8394 --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flet_camera/types.py @@ -0,0 +1,234 @@ +from dataclasses import dataclass +from enum import Enum +from typing import TYPE_CHECKING, Optional + +import flet as ft + +if TYPE_CHECKING: + from flet_camera.camera import Camera # noqa + +__all__ = [ + "CameraDescription", + "CameraImageEvent", + "CameraLensDirection", + "CameraLensType", + "CameraPreviewSize", + "CameraStateEvent", + "ExposureMode", + "FlashMode", + "FocusMode", + "ImageFormatGroup", + "ResolutionPreset", +] + + +class ResolutionPreset(Enum): + """Represents a capture resolution preset.""" + + LOW = "low" + """Low resolution preset.""" + MEDIUM = "medium" + """Medium resolution preset.""" + HIGH = "high" + """High resolution preset.""" + VERY_HIGH = "veryHigh" + """Very high resolution preset.""" + ULTRA_HIGH = "ultraHigh" + """Ultra high resolution preset.""" + MAX = "max" + """Maximum available resolution preset.""" + + +class ImageFormatGroup(Enum): + """Describes the image output format.""" + + BGRA8888 = "bgra8888" + """Raw BGRA 8888 format.""" + JPEG = "jpeg" + """JPEG-compressed format.""" + NV21 = "nv21" + """NV21 YUV format (Android).""" + YUV420 = "yuv420" + """YUV420 planar format.""" + UNKNOWN = "unknown" + """Unknown or unsupported format.""" + + +class FlashMode(Enum): + """Flash modes supported by the camera.""" + + OFF = "off" + """Disable flash.""" + AUTO = "auto" + """Use flash automatically when required.""" + ALWAYS = "always" + """Always fire flash.""" + TORCH = "torch" + """Continuous torch/flashlight mode.""" + + +class ExposureMode(Enum): + """Exposure modes supported by the camera.""" + + AUTO = "auto" + """Automatic exposure.""" + LOCKED = "locked" + """Lock exposure to the current value.""" + + +class FocusMode(Enum): + """Focus modes supported by the camera.""" + + AUTO = "auto" + """Automatic focus.""" + LOCKED = "locked" + """Lock focus to the current value.""" + + +class CameraLensDirection(Enum): + """Direction the camera is facing.""" + + FRONT = "front" + """Front facing camera.""" + BACK = "back" + """Back facing camera.""" + EXTERNAL = "external" + """External camera device.""" + + +class CameraLensType(Enum): + """Type of the camera lens.""" + + WIDE = "wide" + """Wide-angle lens.""" + TELEPHOTO = "telephoto" + """Telephoto lens.""" + ULTRA_WIDE = "ultraWide" + """Ultra-wide lens.""" + UNKNOWN = "unknown" + """Unknown lens type.""" + + +@ft.value +class CameraPreviewSize: + """Dimensions of a camera preview.""" + + width: ft.Number + """Preview width in logical pixels.""" + + height: ft.Number + """Preview height in logical pixels.""" + + +@ft.value +class CameraDescription: + """Properties of a camera device.""" + + name: str + """Human-readable identifier of the camera device.""" + + lens_direction: CameraLensDirection + """Physical lens direction (front, back, external).""" + + sensor_orientation: int + """Clockwise angle (0, 90, 180, 270) needed to display upright output.""" + + lens_type: CameraLensType = CameraLensType.UNKNOWN + """Lens hardware type (wide, telephoto, ultra-wide, or unknown).""" + + +@dataclass +class CameraStateEvent(ft.Event["Camera"]): + """Snapshot of the camera controller state.""" + + is_initialized: bool + """Whether the controller has been initialized.""" + + is_recording_video: bool + """Whether a video recording is in progress.""" + + is_recording_paused: bool + """Whether an active recording is currently paused.""" + + is_taking_picture: bool + """True while a still capture is underway.""" + + is_streaming_images: bool + """True when image streaming is running.""" + + is_preview_paused: bool + """True when the preview has been manually paused.""" + + is_capture_orientation_locked: bool + """True if capture orientation is locked.""" + + device_orientation: Optional[ft.DeviceOrientation] = None + """Current device UI orientation.""" + + locked_capture_orientation: Optional[ft.DeviceOrientation] = None + """Orientation used when capture orientation is locked.""" + + recording_orientation: Optional[ft.DeviceOrientation] = None + """Orientation used for the current recording.""" + + preview_pause_orientation: Optional[ft.DeviceOrientation] = None + """Orientation used when the preview was paused.""" + + flash_mode: Optional[FlashMode] = None + """Active flash mode.""" + + exposure_mode: Optional[ExposureMode] = None + """Active exposure mode.""" + + focus_mode: Optional[FocusMode] = None + """Active focus mode.""" + + exposure_point_supported: Optional[bool] = None + """Whether custom exposure points are supported.""" + + focus_point_supported: Optional[bool] = None + """Whether custom focus points are supported.""" + + preview_size: Optional[CameraPreviewSize] = None + """Preview dimensions, when available.""" + + aspect_ratio: Optional[ft.Number] = None + """Preview aspect ratio, when available.""" + + error_description: Optional[str] = None + """Error message when the controller has an error.""" + + has_error: Optional[bool] = None + """Indicates if the controller is in an error state.""" + + description: Optional[CameraDescription] = None + """The underlying camera description.""" + + +@dataclass +class CameraImageEvent(ft.Event["Camera"]): + """Image data produced by the camera stream.""" + + width: int + """Pixel width of the frame.""" + + height: int + """Pixel height of the frame.""" + + format: Optional[ImageFormatGroup] + """Raw image format group of the source frame.""" + + encoded_format: str + """Encoding used for the output bytes (e.g., jpeg).""" + + bytes: bytes + """Encoded image bytes.""" + + lens_aperture: Optional[ft.Number] = None + """Lens aperture value for the frame.""" + + sensor_exposure_time: Optional[int] = None + """Exposure time in nanoseconds.""" + + sensor_sensitivity: Optional[ft.Number] = None + """Sensor sensitivity (ISO).""" diff --git a/sdk/python/packages/flet-camera/src/flet_camera/utils.py b/sdk/python/packages/flet-camera/src/flet_camera/utils.py new file mode 100644 index 0000000000..4b6195f78f --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flet_camera/utils.py @@ -0,0 +1,26 @@ +""" +Utility helpers for the flet-camera package. +""" + +__all__ = ["detect_video_extension"] + + +def detect_video_extension(data: bytes) -> str: + """ + Detects a likely video file extension from encoded bytes. + + Returns: + One of `"webm"`, `"mov"`, `"mp4"`, or `"bin"` if unknown. + """ + # Matroska/WebM EBML header. + if data.startswith(b"\x1a\x45\xdf\xa3"): + return "webm" + + # ISO BMFF (mp4/mov) starts with a box size + "ftyp". + if len(data) >= 12 and data[4:8] == b"ftyp": + brand = data[8:12] + if brand == b"qt ": + return "mov" + return "mp4" + + return "bin" diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/.gitignore b/sdk/python/packages/flet-camera/src/flutter/flet_camera/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/LICENSE b/sdk/python/packages/flet-camera/src/flutter/flet_camera/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/analysis_options.yaml b/sdk/python/packages/flet-camera/src/flutter/flet_camera/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/flet_camera.dart b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/flet_camera.dart new file mode 100644 index 0000000000..0f12494a97 --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/flet_camera.dart @@ -0,0 +1,3 @@ +library flet_camera; + +export 'src/extension.dart'; diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/camera.dart b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/camera.dart new file mode 100644 index 0000000000..ecec9ad7e9 --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/camera.dart @@ -0,0 +1,279 @@ +import 'dart:async'; +import 'dart:isolate'; +import 'dart:typed_data'; + +import 'package:camera/camera.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/camera.dart'; + +class CameraControl extends StatefulWidget { + final Control control; + + const CameraControl({super.key, required this.control}); + + @override + State createState() => _CameraControlState(); +} + +class _CameraControlState extends State { + CameraController? _controller; + bool _previewEnabled = true; + bool _processingImage = false; + + @override + void initState() { + super.initState(); + _previewEnabled = widget.control.getBool("preview_enabled", true)!; + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void didUpdateWidget(covariant CameraControl oldWidget) { + super.didUpdateWidget(oldWidget); + final enabled = widget.control.getBool("preview_enabled", true)!; + if (enabled != _previewEnabled) { + setState(() => _previewEnabled = enabled); + } + } + + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + _processingImage = false; + _detachController(); + super.dispose(); + } + + void _attachController(CameraController controller) { + _detachController(); + _controller = controller; + controller.addListener(_onControllerValueChanged); + } + + void _detachController() { + final controller = _controller; + if (controller != null) { + controller.removeListener(_onControllerValueChanged); + controller.dispose(); + } + _controller = null; + } + + void _onControllerValueChanged() { + final controller = _controller; + if (controller == null) { + return; + } + if (widget.control.getBool("on_state_change", false)!) { + widget.control + .triggerEvent("state_change", cameraValueToMap(controller.value)); + } + if (mounted) { + setState(() {}); + } + } + + CameraController _requireController() { + final controller = _controller; + if (controller == null) { + throw Exception("Camera is not initialized. Call initialize() first."); + } + return controller; + } + + Future> _initializeController( + Map args) async { + final description = parseCameraDescription(args["description"]); + if (description == null) { + throw Exception("Camera description is required for initialization."); + } + + final resolutionPreset = + parseResolutionPreset(args["resolution_preset"], ResolutionPreset.max); + final enableAudio = parseBool(args["enable_audio"], true)!; + final fps = parseInt(args["fps"]); + final videoBitrate = parseInt(args["video_bitrate"]); + final audioBitrate = parseInt(args["audio_bitrate"]); + final imageFormatGroup = parseImageFormatGroup( + args["image_format_group"], + ImageFormatGroup.unknown, + )!; + + final controller = CameraController( + description, + resolutionPreset, + enableAudio: enableAudio, + fps: fps, + videoBitrate: videoBitrate, + audioBitrate: audioBitrate, + imageFormatGroup: imageFormatGroup, + ); + + _attachController(controller); + await controller.initialize(); + return cameraValueToMap(controller.value); + } + + Future _startImageStream() async { + final controller = _requireController(); + await controller.startImageStream((CameraImage image) { + if (!widget.control.hasEventHandler("stream_image")) { + return; + } + if (_processingImage) { + return; + } + _processingImage = true; + unawaited(_processStreamImage(image)); + }); + } + + Future _processStreamImage(CameraImage image) async { + try { + final Uint8List encoded = image.format.group == ImageFormatGroup.jpeg + ? encodeCameraImage(image) + : await Isolate.run( + () => encodeCameraImagePayload( + cameraImageToPayload( + image, + ), + ), + ); + if (encoded.isEmpty) { + return; + } + widget.control + .triggerEvent("stream_image", cameraImageToMap(image, encoded)); + } finally { + _processingImage = false; + } + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Camera.$name($args)"); + switch (name) { + case "get_available_cameras": + final cameras = await availableCameras(); + return cameras.map((c) => cameraDescriptionToMap(c)).toList(); + case "initialize": + await _initializeController(args is Map ? args : {}); + break; + case "get_exposure_offset_step_size": + return await _requireController().getExposureOffsetStepSize(); + case "get_max_exposure_offset": + return await _requireController().getMaxExposureOffset(); + case "get_max_zoom_level": + return await _requireController().getMaxZoomLevel(); + case "get_min_exposure_offset": + return await _requireController().getMinExposureOffset(); + case "get_min_zoom_level": + return await _requireController().getMinZoomLevel(); + case "lock_capture_orientation": + final orientation = parseDeviceOrientation(args["orientation"]); + await _requireController().lockCaptureOrientation(orientation); + break; + case "unlock_capture_orientation": + await _requireController().unlockCaptureOrientation(); + break; + case "pause_preview": + await _requireController().pausePreview(); + break; + case "resume_preview": + await _requireController().resumePreview(); + break; + case "take_picture": + final file = await _requireController().takePicture(); + return await file.readAsBytes(); + case "prepare_for_video_recording": + await _requireController().prepareForVideoRecording(); + break; + case "start_video_recording": + await _requireController().startVideoRecording(); + break; + case "pause_video_recording": + await _requireController().pauseVideoRecording(); + break; + case "resume_video_recording": + await _requireController().resumeVideoRecording(); + break; + case "stop_video_recording": + final file = await _requireController().stopVideoRecording(); + return await file.readAsBytes(); + case "supports_image_streaming": + return _requireController().supportsImageStreaming(); + case "start_image_stream": + await _startImageStream(); + break; + case "stop_image_stream": + await _requireController().stopImageStream(); + _processingImage = false; + break; + case "set_description": + final description = parseCameraDescription(args["description"]); + if (description != null) { + await _requireController().setDescription(description); + } + break; + case "set_exposure_mode": + final mode = parseExposureMode(args["mode"]); + if (mode != null) { + await _requireController().setExposureMode(mode); + } + break; + case "set_exposure_offset": + final offset = parseDouble(args["offset"]); + if (offset != null) { + return await _requireController().setExposureOffset(offset); + } + break; + case "set_exposure_point": + final point = parseOffset(args["point"]); + await _requireController().setExposurePoint(point); + break; + case "set_flash_mode": + final mode = parseFlashMode(args["mode"]); + if (mode != null) { + await _requireController().setFlashMode(mode); + } + break; + case "set_focus_mode": + final mode = parseFocusMode(args["mode"]); + if (mode != null) { + await _requireController().setFocusMode(mode); + } + break; + case "set_focus_point": + final point = parseOffset(args["point"]); + await _requireController().setFocusPoint(point); + break; + case "set_zoom_level": + final zoom = parseDouble(args["zoom"]); + if (zoom != null) { + await _requireController().setZoomLevel(zoom); + } + break; + default: + throw Exception("Unknown Camera method: $name"); + } + return null; + } + + @override + Widget build(BuildContext context) { + debugPrint("Camera build: ${widget.control.id}"); + + Widget preview = const SizedBox.shrink(); + final controller = _controller; + + if (_previewEnabled && + controller != null && + controller.value.isInitialized) { + final contentWidget = widget.control.buildWidget("content"); + preview = CameraPreview(controller, child: contentWidget); + } + + return LayoutControl(control: widget.control, child: preview); + } +} diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/extension.dart b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/extension.dart new file mode 100644 index 0000000000..c68d9ea2b7 --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/extension.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; + +import 'camera.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "Camera": + return CameraControl(key: key, control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart new file mode 100644 index 0000000000..fcd78466e9 --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/lib/src/utils/camera.dart @@ -0,0 +1,302 @@ +import 'dart:math'; + +import 'package:camera/camera.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/services.dart'; +import 'package:image/image.dart' as img; + +CameraDescription? parseCameraDescription(dynamic value) { + if (value == null) return null; + if (value is CameraDescription) return value; + if (value is Map) { + final lensDirection = parseEnum(CameraLensDirection.values, + value["lens_direction"], CameraLensDirection.back)!; + final lensType = parseEnum( + CameraLensType.values, value["lens_type"], CameraLensType.unknown)!; + final sensorOrientation = value["sensor_orientation"]; + final name = value["name"]; + if (name is String && sensorOrientation is int) { + return CameraDescription( + name: name, + lensDirection: lensDirection, + sensorOrientation: sensorOrientation, + lensType: lensType, + ); + } + } + return null; +} + +ResolutionPreset parseResolutionPreset(dynamic value, + [ResolutionPreset? defaultValue]) { + return parseEnum(ResolutionPreset.values, value, defaultValue)!; +} + +ImageFormatGroup? parseImageFormatGroup(dynamic value, + [ImageFormatGroup? defaultValue]) { + return parseEnum(ImageFormatGroup.values, value, defaultValue); +} + +FlashMode? parseFlashMode(dynamic value, [FlashMode? defaultValue]) { + return parseEnum(FlashMode.values, value, defaultValue); +} + +ExposureMode? parseExposureMode(dynamic value, [ExposureMode? defaultValue]) { + return parseEnum(ExposureMode.values, value, defaultValue); +} + +FocusMode? parseFocusMode(dynamic value, [FocusMode? defaultValue]) { + return parseEnum(FocusMode.values, value, defaultValue); +} + +Map cameraDescriptionToMap(CameraDescription description) { + return { + "name": description.name, + "lens_direction": description.lensDirection.name, + "sensor_orientation": description.sensorOrientation, + "lens_type": description.lensType.name, + }; +} + +Map? sizeToMap(Size? size) { + if (size == null) return null; + return {"width": size.width, "height": size.height}; +} + +Map cameraValueToMap(CameraValue value) { + return { + "is_initialized": value.isInitialized, + "is_recording_video": value.isRecordingVideo, + "is_recording_paused": value.isRecordingPaused, + "is_taking_picture": value.isTakingPicture, + "is_streaming_images": value.isStreamingImages, + "is_preview_paused": value.isPreviewPaused, + "is_capture_orientation_locked": value.isCaptureOrientationLocked, + "locked_capture_orientation": value.lockedCaptureOrientation?.name, + "recording_orientation": value.recordingOrientation?.name, + "device_orientation": value.deviceOrientation.name, + "flash_mode": value.flashMode.name, + "exposure_mode": value.exposureMode.name, + "focus_mode": value.focusMode.name, + "exposure_point_supported": value.exposurePointSupported, + "focus_point_supported": value.focusPointSupported, + "preview_pause_orientation": value.previewPauseOrientation?.name, + "preview_size": sizeToMap(value.previewSize), + "aspect_ratio": value.previewSize != null ? value.aspectRatio : null, + "error_description": value.errorDescription, + "has_error": value.hasError, + "description": cameraDescriptionToMap(value.description), + }..removeWhere((_, v) => v == null); +} + +Map cameraImageToMap( + CameraImage image, Uint8List encodedBytes) { + return { + "width": image.width, + "height": image.height, + "format": image.format.group.name, + "encoded_format": "jpeg", + "lens_aperture": image.lensAperture, + "sensor_exposure_time": image.sensorExposureTime, + "sensor_sensitivity": image.sensorSensitivity, + "bytes": encodedBytes, + }..removeWhere((_, v) => v == null); +} + +Uint8List encodeCameraImage(CameraImage image) { + switch (image.format.group) { + case ImageFormatGroup.bgra8888: + case ImageFormatGroup.nv21: + case ImageFormatGroup.yuv420: + return encodeCameraImagePayload(cameraImageToPayload(image)); + case ImageFormatGroup.jpeg: + if (image.planes.isEmpty) { + return Uint8List(0); + } + return image.planes.first.bytes; + default: + return Uint8List(0); + } +} + +Map cameraImageToPayload( + CameraImage image, +) { + return { + "width": image.width, + "height": image.height, + "format": image.format.group.name, + "planes": image.planes + .map( + (p) => { + "bytes": Uint8List.fromList(p.bytes), + "bytes_per_row": p.bytesPerRow, + "bytes_per_pixel": p.bytesPerPixel, + }, + ) + .toList(), + }; +} + +Uint8List encodeCameraImagePayload(Map payload) { + final format = payload["format"]; + switch (format) { + case "bgra8888": + return _encodeBgra8888Payload(payload); + case "nv21": + return _encodeNv21Payload(payload); + case "yuv420": + return _encodeYuv420Payload(payload); + case "jpeg": + final planes = payload["planes"]; + if (planes is List && planes.isNotEmpty) { + final first = planes.first; + if (first is Map && first["bytes"] is Uint8List) { + return first["bytes"] as Uint8List; + } + } + return Uint8List(0); + default: + return Uint8List(0); + } +} + +Uint8List _encodeBgra8888Payload(Map payload) { + final width = payload["width"]; + final height = payload["height"]; + final planes = payload["planes"]; + if (width is! int || height is! int || planes is! List || planes.isEmpty) { + return Uint8List(0); + } + final plane = planes.first; + if (plane is! Map || plane["bytes"] is! Uint8List) { + return Uint8List(0); + } + final bytes = plane["bytes"] as Uint8List; + final bytesPerRow = plane["bytes_per_row"]; + if (bytesPerRow is! int) { + return Uint8List(0); + } + final img.Image converted = img.Image.fromBytes( + width: width, + height: height, + bytes: bytes.buffer, + numChannels: 4, + rowStride: bytesPerRow, + order: img.ChannelOrder.bgra, + ); + return Uint8List.fromList(img.encodeJpg(converted)); +} + +Uint8List _encodeYuv420Payload(Map payload) { + final width = payload["width"]; + final height = payload["height"]; + final planes = payload["planes"]; + if (width is! int || height is! int || planes is! List || planes.isEmpty) { + return Uint8List(0); + } + final yPlane = planes[0]; + final uPlane = planes.length > 1 ? planes[1] : null; + final vPlane = planes.length > 2 ? planes[2] : null; + if (yPlane is! Map || yPlane["bytes"] is! Uint8List) { + return Uint8List(0); + } + final yBytes = yPlane["bytes"] as Uint8List; + final yBytesPerRow = yPlane["bytes_per_row"]; + if (yBytesPerRow is! int) { + return Uint8List(0); + } + final uBytes = uPlane is Map && uPlane["bytes"] is Uint8List + ? uPlane["bytes"] as Uint8List + : null; + final vBytes = vPlane is Map && vPlane["bytes"] is Uint8List + ? vPlane["bytes"] as Uint8List + : null; + final uvPixelStride = uPlane is Map && uPlane["bytes_per_pixel"] is int + ? uPlane["bytes_per_pixel"] as int + : 1; + final uvRowStride = uPlane is Map && uPlane["bytes_per_row"] is int + ? uPlane["bytes_per_row"] as int + : 0; + + final img.Image converted = img.Image(width: width, height: height); + for (int y = 0; y < height; y++) { + final int yRow = y * yBytesPerRow; + final int uvRow = uvRowStride * (y >> 1); + for (int x = 0; x < width; x++) { + final int yIndex = yRow + x; + if (yIndex >= yBytes.length) { + continue; + } + final int uvIndex = uvRow + (x >> 1) * uvPixelStride; + final int yp = yBytes[yIndex]; + final int up = + (uBytes != null && uvIndex < uBytes.length) ? uBytes[uvIndex] : 128; + final int vp = + (vBytes != null && uvIndex < vBytes.length) ? vBytes[uvIndex] : 128; + final (int r, int g, int b) = _yuvToRgb(yp, up, vp); + converted.setPixelRgba(x, y, r, g, b, 255); + } + } + return Uint8List.fromList(img.encodeJpg(converted)); +} + +Uint8List _encodeNv21Payload(Map payload) { + final width = payload["width"]; + final height = payload["height"]; + final planes = payload["planes"]; + if (width is! int || height is! int || planes is! List || planes.length < 2) { + return Uint8List(0); + } + final yPlane = planes[0]; + final uvPlane = planes[1]; + if (yPlane is! Map || + uvPlane is! Map || + yPlane["bytes"] is! Uint8List || + uvPlane["bytes"] is! Uint8List) { + return Uint8List(0); + } + final yBytes = yPlane["bytes"] as Uint8List; + final uvBytes = uvPlane["bytes"] as Uint8List; + final yBytesPerRow = yPlane["bytes_per_row"]; + final uvRowStride = uvPlane["bytes_per_row"]; + if (yBytesPerRow is! int || uvRowStride is! int) { + return Uint8List(0); + } + final uvPixelStride = + uvPlane["bytes_per_pixel"] is int ? uvPlane["bytes_per_pixel"] as int : 2; + final img.Image converted = img.Image(width: width, height: height); + for (int y = 0; y < height; y++) { + final int yRow = y * yBytesPerRow; + final int uvRow = uvRowStride * (y >> 1); + for (int x = 0; x < width; x++) { + final int yIndex = yRow + x; + if (yIndex >= yBytes.length) { + continue; + } + final int uvIndex = uvRow + (x >> 1) * uvPixelStride; + if (uvIndex + 1 >= uvBytes.length) { + continue; + } + final int yp = yBytes[yIndex]; + final int vp = uvBytes[uvIndex]; + final int up = uvBytes[uvIndex + 1]; + final (int r, int g, int b) = _yuvToRgb(yp, up, vp); + converted.setPixelRgba(x, y, r, g, b, 255); + } + } + return Uint8List.fromList(img.encodeJpg(converted)); +} + +(int, int, int) _yuvToRgb(int y, int u, int v) { + final double yp = y.toDouble(); + final double up = u.toDouble() - 128.0; + final double vp = v.toDouble() - 128.0; + int r = (yp + 1.402 * vp).round(); + int g = (yp - 0.344136 * up - 0.714136 * vp).round(); + int b = (yp + 1.772 * up).round(); + r = max(0, min(255, r)); + g = max(0, min(255, g)); + b = max(0, min(255, b)); + return (r, g, b); +} diff --git a/sdk/python/packages/flet-camera/src/flutter/flet_camera/pubspec.yaml b/sdk/python/packages/flet-camera/src/flutter/flet_camera/pubspec.yaml new file mode 100644 index 0000000000..b9d6618afb --- /dev/null +++ b/sdk/python/packages/flet-camera/src/flutter/flet_camera/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_camera +description: Flet Camera control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=3.16.0" + +dependencies: + flutter: + sdk: flutter + + camera: ^0.12.0 + image: ^4.5.4 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-charts/CHANGELOG.md b/sdk/python/packages/flet-charts/CHANGELOG.md new file mode 100644 index 0000000000..924753c582 --- /dev/null +++ b/sdk/python/packages/flet-charts/CHANGELOG.md @@ -0,0 +1,80 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.85.0 + +### Fixed + +- Fixed `LineChartEvent.spots` returning undecoded MessagePack extension values instead of `LineChartEventSpot` objects ([#6443](https://github.com/flet-dev/flet/issues/6443), [#6468](https://github.com/flet-dev/flet/pull/6468)) by @ndonkoHenri. +- Fixed `LineChart` (and other charts) silently dropping custom `ChartAxisLabel` entries whose `value` matched a tick only after floating-point rounding (e.g. `0.1`, `0.2`, `0.3`) by switching label lookup to a tolerance-based comparison scaled to the axis interval ([#6445](https://github.com/flet-dev/flet/issues/6445), [#6459](https://github.com/flet-dev/flet/pull/6459)) by @KangZhaoKui. +- Fixed unbounded browser memory growth in `MatplotlibChart` on Flutter web (CanvasKit/WASM) during animations by replacing the generic `Canvas` + `capture()` rendering flow with a dedicated `MatplotlibChartCanvas` widget that composites matplotlib diff frames in CPU memory; also fixes Safari async PNG decode (`EncodingError: Loading error.`), a render/`figure.savefig()` race that crashed the toolbar Download, and pan/zoom playback lag from buffered pointer events ([#6473](https://github.com/flet-dev/flet/pull/6473)) by @FeodorFitsner. + +## 0.80.0 + +Initial release. + +### Added + +- Deployed online documentation: https://flet.dev/docs/charts/ +- New Chart control: `ScatterChart` +- New Chart control: `CandlestickChart` + +#### BarChart + +- New property: `tooltip` +- New enum: `BarChartTooltipDirection` +- In `BarChartRod`: new property `tooltip` + +#### LineChart + +- New property: `tooltip` +- In `LineChartDataPoint`: new property `tooltip` (now accepts a `LineChartDataPointTooltip` instance) + +### Changed + +All chart controls have been refactored to use `@ft.control` dataclass-style definition + +#### BarChart + +- Renamed properties: + - `bar_groups` → `groups` + - `groups_space` → `spacing` + - `animate` → `animation` + - `on_chart_event` → `on_event` +- Tooltip configuration has been redesigned: + - Removed properties: `tooltip_bgcolor`, `tooltip_rounded_radius`, `tooltip_margin`, `tooltip_padding`, `tooltip_max_content_width`, `tooltip_rotate_angle`, `tooltip_horizontal_offset`, `tooltip_border_side`, `tooltip_fit_inside_horizontally`, `tooltip_fit_inside_vertically`, `tooltip_direction` + - use the new `tooltip` property of type `BarChartTooltip` +- In `BarChartGroup`: + - Renamed properties: + - `bar_rods` → `rods` + - `bars_space` → `spacing` +- In `BarChartRod`: + - Renamed properties: + - `rod_stack_items` → `stack_items` + - `bg_color` → `bgcolor` + - `bg_gradient` → `background_gradient` + +#### LineChart + +- Renamed properties: + - `animate` → `animation` + - `on_chart_event` → `on_event` +- `LineChart` Tooltip configuration has been redesigned: + - Removed properties: `tooltip_bgcolor`, `tooltip_rounded_radius`, `tooltip_margin`, `tooltip_padding`, `tooltip_max_content_width`, `tooltip_rotate_angle`, `tooltip_horizontal_offset`, `tooltip_border_side`, `tooltip_fit_inside_horizontally`, `tooltip_fit_inside_vertically`, `tooltip_show_on_top_of_chart_box_area` + - use the new `tooltip` property of type `LineChartTooltip` +- In `LineChartData`: + - Renamed properties: `data_points` → `points`, `stroke_cap_round` → `rounded_stroke_cap` + - Removed properties: `above_line_bgcolor`, `below_line_bgcolor` + - Renamed property: `selected_below_line` +- In `LineChartDataPoint`: + - Removed properties: `tooltip_align`, `tooltip_style` - use `tooltip` property instead which is now of type `LineChartDataPointTooltip` + +#### PieChart + +- Renamed properties: + - `animate` → `animation` + - `on_chart_event` → `on_event` diff --git a/sdk/python/packages/flet-charts/LICENSE b/sdk/python/packages/flet-charts/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-charts/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-charts/README.md b/sdk/python/packages/flet-charts/README.md new file mode 100644 index 0000000000..43911767a7 --- /dev/null +++ b/sdk/python/packages/flet-charts/README.md @@ -0,0 +1,53 @@ +# flet-charts + +[![pypi](https://img.shields.io/pypi/v/flet-charts.svg)](https://pypi.python.org/pypi/flet-charts) +[![downloads](https://static.pepy.tech/badge/flet-charts/month)](https://pepy.tech/project/flet-charts) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-charts) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-charts.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-charts.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-charts/LICENSE) + +A [Flet](https://flet.dev) extension for creating interactive charts and graphs. + +It is based on the [fl_chart](https://pub.dev/packages/fl_chart) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/charts/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-charts` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-charts + ``` + +- Using `pip`: + ```bash + pip install flet-charts + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/charts). + +### Available charts + +- [`BarChart`](https://flet.dev/docs/controls/charts/barchart) +- [`CandlestickChart`](https://flet.dev/docs/controls/charts/candlestickchart) +- [`LineChart`](https://flet.dev/docs/controls/charts/linechart) +- [`MatplotlibChart`](https://flet.dev/docs/controls/charts/matplotlibchart) +- [`PieChart`](https://flet.dev/docs/controls/charts/piechart) +- [`PlotlyChart`](https://flet.dev/docs/controls/charts/plotlychart) +- [`RadarChart`](https://flet.dev/docs/controls/charts/radarchart) +- [`ScatterChart`](https://flet.dev/docs/controls/charts/scatterchart) diff --git a/sdk/python/packages/flet-charts/integration_tests/conftest.py b/sdk/python/packages/flet-charts/integration_tests/conftest.py new file mode 100644 index 0000000000..608d26608b --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/conftest.py @@ -0,0 +1,32 @@ +from pathlib import Path + +import pytest_asyncio + +import flet.testing as ftt + + +def create_flet_app(request): + params = getattr(request, "param", {}) + return ftt.FletTestApp( + flutter_app_dir=(Path(__file__).parent / "../../../../../client").resolve(), + test_path=request.fspath, + flet_app_main=params.get("flet_app_main"), + skip_pump_and_settle=params.get("skip_pump_and_settle", False), + assets_dir=Path(__file__).resolve().parent / "assets", + ) + + +@pytest_asyncio.fixture(scope="module") +async def flet_app(request): + flet_app = create_flet_app(request) + await flet_app.start() + yield flet_app + await flet_app.teardown() + + +@pytest_asyncio.fixture(scope="function") +async def flet_app_function(request): + flet_app = create_flet_app(request) + await flet_app.start() + yield flet_app + await flet_app.teardown() diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png new file mode 100644 index 0000000000..d8edda72f3 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png new file mode 100644 index 0000000000..59984cabf1 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png new file mode 100644 index 0000000000..896bf4e802 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/bar_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png new file mode 100644 index 0000000000..31bd5be78a Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png new file mode 100644 index 0000000000..ebe189336c Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/candlestick_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png new file mode 100644 index 0000000000..0d50433bee Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png new file mode 100644 index 0000000000..35f2c91b14 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png new file mode 100644 index 0000000000..b5d03d566c Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/line_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png new file mode 100644 index 0000000000..7f3250b9d8 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/bar_chart.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png new file mode 100644 index 0000000000..ebaffcbe88 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/handle_events.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png new file mode 100644 index 0000000000..c3fd1f8d4f Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/three_d.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png new file mode 100644 index 0000000000..63f0388b82 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/matplotlib_chart/toolbar.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png new file mode 100644 index 0000000000..30716c1f34 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png new file mode 100644 index 0000000000..6abdb67a5d Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png new file mode 100644 index 0000000000..e9ef47d553 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/pie_chart/example_3.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png new file mode 100644 index 0000000000..668f2c0b2b Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png new file mode 100644 index 0000000000..9828e790dc Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_2.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png new file mode 100644 index 0000000000..a8fe17dd8d Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_3.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png new file mode 100644 index 0000000000..4a668512f2 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/example_4.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png new file mode 100644 index 0000000000..76da2da143 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/plotly_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png new file mode 100644 index 0000000000..afd0d9b91f Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png new file mode 100644 index 0000000000..e978295f44 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/radar_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png new file mode 100644 index 0000000000..75b1d61347 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/example_1.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png new file mode 100644 index 0000000000..2284808ac1 Binary files /dev/null and b/sdk/python/packages/flet-charts/integration_tests/examples/golden/macos/scatter_chart/image_for_docs.png differ diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py new file mode 100644 index 0000000000..7453ded581 --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_bar_chart.py @@ -0,0 +1,71 @@ +import pytest + +import flet as ft +import flet.testing as ftt +import flet_charts as fch +from examples.controls.charts.bar_chart import example_1, example_2 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + fch.BarChart( + border=ft.Border.all(1, ft.Colors.GREY_400), + groups=[ + fch.BarChartGroup( + x=0, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=40, + color=ft.Colors.BLUE_GREY_200, + ), + ], + ), + fch.BarChartGroup( + x=1, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=60, + color=ft.Colors.BLUE_GREY_600, + ), + ], + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_2.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_2(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_2", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py new file mode 100644 index 0000000000..0a665d91d5 --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_candlestick_chart.py @@ -0,0 +1,53 @@ +import pytest + +import flet as ft +import flet.testing as ftt +import flet_charts as fch +from examples.controls.charts.candlestick_chart import example_1 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + fch.CandlestickChart( + min_x=-1, + max_x=2, + min_y=20, + max_y=30, + bgcolor=ft.Colors.AMBER_200, + spots=[ + fch.CandlestickChartSpot( + x=0, + open=22.6, + high=28.3, + low=21.4, + close=24.1, + ), + fch.CandlestickChartSpot( + x=1, + open=25.4, + high=27.6, + low=22.3, + close=23.9, + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py new file mode 100644 index 0000000000..bf91b7b037 --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_line_chart.py @@ -0,0 +1,72 @@ +import pytest + +import flet as ft +import flet.testing as ftt +import flet_charts as fch +from examples.controls.charts.line_chart import example_1, example_2 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + fch.LineChart( + data_series=[ + fch.LineChartData( + color=ft.Colors.BLUE_GREY_500, + curved=True, + points=[ + fch.LineChartDataPoint(1, 0.5), + fch.LineChartDataPoint(2, 1.5), + fch.LineChartDataPoint(3, 1), + ], + ), + fch.LineChartData( + color=ft.Colors.AMBER_400, + curved=True, + points=[ + fch.LineChartDataPoint(1, 2), + fch.LineChartDataPoint(2, 0.5), + fch.LineChartDataPoint(3, 1.5), + ], + ), + ], + min_y=0, + max_y=3, + min_x=0, + max_x=5, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_2.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_2(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_2", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py new file mode 100644 index 0000000000..d2aafaa4dd --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_matplotlib_chart.py @@ -0,0 +1,70 @@ +import pytest + +import flet.testing as ftt +from examples.controls.charts.matplotlib_chart import ( + bar_chart, + handle_events, + three_d, + toolbar, +) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": bar_chart.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_bar_chart(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "bar_chart", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handle_events.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handle_events(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handle_events", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": toolbar.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_toolbar(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "toolbar", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": three_d.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_three_d(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "three_d", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py new file mode 100644 index 0000000000..af0e8f1723 --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_pie_chart.py @@ -0,0 +1,52 @@ +import pytest + +import flet.testing as ftt +from examples.controls.charts.pie_chart import example_1, example_2, example_3 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_2.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_2(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_2", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_3.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_3(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_3", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py new file mode 100644 index 0000000000..8b97b5c30d --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_plotly_chart.py @@ -0,0 +1,88 @@ +import plotly.express as px +import pytest + +import flet as ft +import flet.testing as ftt +import flet_charts as fch +from examples.controls.charts.plotly_chart import ( + example_1, + example_2, + example_3, + example_4, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.padding = 20 + flet_app_function.page.update() + data_canada = px.data.gapminder().query("country == 'Canada'") + fig = px.bar(data_canada, x="year", y="pop") + await flet_app_function.assert_control_screenshot( + request.node.name, fch.PlotlyChart(figure=fig, expand=True) + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_2.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_2(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_2", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_3.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_3(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_3", + await flet_app_function.page.take_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_4.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_4(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_4", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py new file mode 100644 index 0000000000..c46f69fdc1 --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_radar_chart.py @@ -0,0 +1,62 @@ +import pytest + +import flet as ft +import flet.testing as ftt +import flet_charts as fch +from examples.controls.charts.radar_chart import example_1 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.padding = 20 + flet_app_function.page.update() + await flet_app_function.assert_control_screenshot( + request.node.name, + fch.RadarChart( + # expand=True, + titles=[ + fch.RadarChartTitle(text="winter", position_percentage_offset=0.1), + fch.RadarChartTitle(text="spring", position_percentage_offset=0.1), + fch.RadarChartTitle(text="summer", position_percentage_offset=0.1), + fch.RadarChartTitle(text="autumn", position_percentage_offset=0.1), + ], + radar_shape=fch.RadarShape.CIRCLE, + data_sets=[ + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.2, ft.Colors.BLUE_GREY_700), + entries=[ + fch.RadarDataSetEntry(130), + fch.RadarDataSetEntry(95), + fch.RadarDataSetEntry(190), + fch.RadarDataSetEntry(60), + ], + ), + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.2, ft.Colors.CYAN_400), + entries=[ + fch.RadarDataSetEntry(90), + fch.RadarDataSetEntry(45), + fch.RadarDataSetEntry(265), + fch.RadarDataSetEntry(150), + ], + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py b/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py new file mode 100644 index 0000000000..6d8c3a3187 --- /dev/null +++ b/sdk/python/packages/flet-charts/integration_tests/examples/test_scatter_chart.py @@ -0,0 +1,57 @@ +import pytest + +import flet as ft +import flet.testing as ftt +import flet_charts as fch +from examples.controls.charts.scatter_chart import example_1 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + chart_spots = [ + fch.ScatterChartSpot( + x=i * 2, + y=i * 3, + ) + for i in range(10) + ] + chart_spots += [ + fch.ScatterChartSpot( + x=i, + y=i, + ) + for i in range(10) + ] + + chart_spots += [ + fch.ScatterChartSpot( + x=i + 2, + y=i + 10, + ) + for i in range(10) + ] + + await flet_app_function.assert_control_screenshot( + request.node.name, + fch.ScatterChart( + aspect_ratio=1.0, + spots=chart_spots, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": example_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_example_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "example_1", + await flet_app_function.page.take_screenshot(), + ) diff --git a/sdk/python/packages/flet-charts/pyproject.toml b/sdk/python/packages/flet-charts/pyproject.toml new file mode 100644 index 0000000000..889f819a26 --- /dev/null +++ b/sdk/python/packages/flet-charts/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-charts" +version = "0.1.0" +description = "Interactive chart controls for Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/charts" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-charts" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_charts" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-charts/src/flet_charts/__init__.py b/sdk/python/packages/flet-charts/src/flet_charts/__init__.py new file mode 100644 index 0000000000..53f33967c6 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/__init__.py @@ -0,0 +1,122 @@ +from flet_charts.bar_chart import ( + BarChart, + BarChartEvent, + BarChartTooltip, + BarChartTooltipDirection, +) +from flet_charts.bar_chart_group import BarChartGroup +from flet_charts.bar_chart_rod import BarChartRod, BarChartRodTooltip +from flet_charts.bar_chart_rod_stack_item import BarChartRodStackItem +from flet_charts.candlestick_chart import ( + CandlestickChart, + CandlestickChartEvent, + CandlestickChartTooltip, +) +from flet_charts.candlestick_chart_spot import ( + CandlestickChartSpot, + CandlestickChartSpotTooltip, +) +from flet_charts.chart_axis import ChartAxis, ChartAxisLabel +from flet_charts.line_chart import ( + LineChart, + LineChartEvent, + LineChartEventSpot, + LineChartTooltip, +) +from flet_charts.line_chart_data import LineChartData +from flet_charts.line_chart_data_point import ( + LineChartDataPoint, + LineChartDataPointTooltip, +) +from flet_charts.matplotlib_chart import ( + MatplotlibChart, + MatplotlibChartMessageEvent, + MatplotlibChartToolbarButtonsUpdateEvent, +) +from flet_charts.matplotlib_chart_canvas import ( + MatplotlibChartCanvas, + MatplotlibChartCanvasResizeEvent, +) +from flet_charts.matplotlib_chart_with_toolbar import MatplotlibChartWithToolbar +from flet_charts.pie_chart import PieChart, PieChartEvent +from flet_charts.pie_chart_section import PieChartSection +from flet_charts.plotly_chart import PlotlyChart +from flet_charts.radar_chart import ( + RadarChart, + RadarChartEvent, + RadarChartTitle, + RadarShape, +) +from flet_charts.radar_data_set import RadarDataSet, RadarDataSetEntry +from flet_charts.scatter_chart import ( + ScatterChart, + ScatterChartEvent, + ScatterChartTooltip, +) +from flet_charts.scatter_chart_spot import ScatterChartSpot, ScatterChartSpotTooltip +from flet_charts.types import ( + ChartCirclePoint, + ChartCrossPoint, + ChartDataPointTooltip, + ChartEventType, + ChartGridLines, + ChartPointLine, + ChartPointShape, + ChartSquarePoint, + HorizontalAlignment, +) + +__all__ = [ + "BarChart", + "BarChartEvent", + "BarChartGroup", + "BarChartRod", + "BarChartRodStackItem", + "BarChartRodTooltip", + "BarChartTooltip", + "BarChartTooltipDirection", + "CandlestickChart", + "CandlestickChartEvent", + "CandlestickChartSpot", + "CandlestickChartSpotTooltip", + "CandlestickChartTooltip", + "ChartAxis", + "ChartAxisLabel", + "ChartCirclePoint", + "ChartCrossPoint", + "ChartDataPointTooltip", + "ChartEventType", + "ChartGridLines", + "ChartPointLine", + "ChartPointShape", + "ChartSquarePoint", + "HorizontalAlignment", + "LineChart", + "LineChartData", + "LineChartDataPoint", + "LineChartDataPointTooltip", + "LineChartEvent", + "LineChartEventSpot", + "LineChartTooltip", + "MatplotlibChart", + "MatplotlibChartCanvas", + "MatplotlibChartCanvasResizeEvent", + "MatplotlibChartMessageEvent", + "MatplotlibChartToolbarButtonsUpdateEvent", + "MatplotlibChartWithToolbar", + "PieChart", + "PieChartEvent", + "PieChartSection", + "PlotlyChart", + "RadarChart", + "RadarChartEvent", + "RadarChartTitle", + "RadarDataSet", + "RadarDataSetEntry", + "RadarShape", + "ScatterChart", + "ScatterChartEvent", + "ScatterChartSpot", + "ScatterChartSpotTooltip", + "ScatterChartTooltip", +] diff --git a/sdk/python/packages/flet-charts/src/flet_charts/bar_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart.py new file mode 100644 index 0000000000..a75fd77f75 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart.py @@ -0,0 +1,306 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import Any, Optional + +import flet as ft +from flet_charts.bar_chart_group import BarChartGroup +from flet_charts.chart_axis import ChartAxis +from flet_charts.types import ChartEventType, ChartGridLines, HorizontalAlignment + +__all__ = [ + "BarChart", + "BarChartEvent", + "BarChartTooltip", + "BarChartTooltipDirection", +] + + +class BarChartTooltipDirection(Enum): + """Controls showing tooltip on top or bottom.""" + + AUTO = "auto" + """Tooltip shows on top if value is positive, on bottom if value is negative.""" + + TOP = "top" + """Tooltip always shows on top.""" + + BOTTOM = "bottom" + """Tooltip always shows on bottom.""" + + +@ft.value +class BarChartTooltip: + """Configuration of the tooltip for :class:`~flet_charts.BarChart`s.""" + + bgcolor: ft.ColorValue = ft.Colors.SECONDARY + """ + Background color of tooltips. + """ + + border_radius: Optional[ft.BorderRadiusValue] = None + """ + The border radius of the tooltip. + """ + + margin: ft.Number = 16 + """ + Applies a bottom margin for showing tooltip on top of rods. + """ + + padding: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(vertical=8, horizontal=16) + ) + """ + Applies a padding for showing contents inside the tooltip. + """ + + max_width: Optional[ft.Number] = None + """ + Restricts the tooltip's width. + """ + + rotation: ft.Number = 0.0 + """ + The rotation angle of the tooltip. + """ + + horizontal_offset: ft.Number = 0.0 + """ + The horizontal offset of this tooltip. + """ + + border_side: Optional[ft.BorderSide] = None + """ + The tooltip border side. + """ + + fit_inside_horizontally: bool = False + """ + Forces the tooltip to shift horizontally inside the chart, if overflow happens. + """ + + fit_inside_vertically: bool = False + """ + Forces the tooltip to shift vertically inside the chart, if overflow happens. + """ + + direction: BarChartTooltipDirection = BarChartTooltipDirection.AUTO + """ + Defines the direction of this tooltip. + """ + + horizontal_alignment: HorizontalAlignment = HorizontalAlignment.CENTER + """ + Defines the horizontal alignment of this tooltip. + """ + + def copy( + self, + *, + bgcolor: Optional[ft.ColorValue] = None, + border_radius: Optional[ft.BorderRadiusValue] = None, + margin: Optional[ft.Number] = None, + padding: Optional[ft.PaddingValue] = None, + max_width: Optional[ft.Number] = None, + rotation: Optional[ft.Number] = None, + horizontal_offset: Optional[ft.Number] = None, + border_side: Optional[ft.BorderSide] = None, + fit_inside_horizontally: Optional[bool] = None, + fit_inside_vertically: Optional[bool] = None, + direction: Optional[BarChartTooltipDirection] = None, + horizontal_alignment: Optional[HorizontalAlignment] = None, + ) -> "BarChartTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BarChartTooltip( + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + border_radius=( + border_radius if border_radius is not None else self.border_radius + ), + margin=margin if margin is not None else self.margin, + padding=padding if padding is not None else self.padding, + max_width=max_width if max_width is not None else self.max_width, + rotation=rotation if rotation is not None else self.rotation, + horizontal_offset=( + horizontal_offset + if horizontal_offset is not None + else self.horizontal_offset + ), + border_side=border_side if border_side is not None else self.border_side, + fit_inside_horizontally=( + fit_inside_horizontally + if fit_inside_horizontally is not None + else self.fit_inside_horizontally + ), + fit_inside_vertically=( + fit_inside_vertically + if fit_inside_vertically is not None + else self.fit_inside_vertically + ), + direction=direction if direction is not None else self.direction, + horizontal_alignment=( + horizontal_alignment + if horizontal_alignment is not None + else self.horizontal_alignment + ), + ) + + +@dataclass +class BarChartEvent(ft.Event["BarChart"]): + """ + Event payload emitted when the user hovers or clicks a bar chart. + """ + + type: ChartEventType + """ + The type of event that occurred on the chart. + """ + + group_index: Optional[int] = None + """ + Bar's index or `-1` if chart is hovered or clicked outside of any bar. + """ + + rod_index: Optional[int] = None + """ + Rod's index or `-1` if chart is hovered or clicked outside of any bar. + """ + + stack_item_index: Optional[int] = None + """ + Stack item's index or `-1` if chart is hovered or clicked outside of any bar. + """ + + +@ft.control("BarChart") +class BarChart(ft.LayoutControl): + """ + Draws a bar chart. + + ```python + fch.BarChart( + border=ft.Border.all(1, ft.Colors.GREY_400), + groups=[ + fch.BarChartGroup( + x=0, + rods=[ + fch.BarChartRod( + from_y=0, + to_y=40, + color=ft.Colors.BLUE_GREY_200, + ), + ], + ), + ..., + ], + ) + ``` + + """ + + groups: list[BarChartGroup] = field(default_factory=list) + """ + The list of :class:`~flet_charts.BarChartGroup`s to draw. + """ + + group_spacing: ft.Number = 16.0 + """ + An amount of space between bar :attr:`groups`. + """ + + group_alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.SPACE_EVENLY + """ + The alignment of the bar :attr:`groups` within this chart. + + If set to :attr:`flet.MainAxisAlignment.CENTER`, + the space between the `groups` can be specified using :attr:`group_spacing`. + """ + + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + """ + Controls chart implicit animation. + """ + + interactive: bool = True + """ + Enables automatic tooltips when hovering chart bars. + """ + + bgcolor: Optional[ft.ColorValue] = None + """ + Background color of the chart. + """ + + border: Optional[ft.Border] = None + """ + The border around the chart. + """ + + horizontal_grid_lines: Optional[ChartGridLines] = None + """ + Controls drawing of chart's horizontal lines. + """ + + vertical_grid_lines: Optional[ChartGridLines] = None + """ + Controls drawing of chart's vertical lines. + """ + + left_axis: Optional[ChartAxis] = None + """ + The appearance of the left axis, its title and labels. + """ + + top_axis: Optional[ChartAxis] = None + """ + The appearance of the top axis, its title and labels. + """ + + right_axis: Optional[ChartAxis] = None + """ + The appearance of the right axis, its title and labels. + """ + + bottom_axis: Optional[ChartAxis] = None + """ + The appearance of the bottom axis, its title and labels. + """ + + baseline_y: Optional[ft.Number] = None + """ + Baseline value for Y axis. + """ + + min_y: Optional[ft.Number] = None + """ + The minimum displayed value for Y axis. + """ + + max_y: Optional[ft.Number] = None + """ + The maximum displayed value for Y axis. + """ + + tooltip: Optional[BarChartTooltip] = field( + default_factory=lambda: BarChartTooltip() + ) + """ + The tooltip configuration for this chart. + + If set to `None`, tooltips will not shown throughout this chart. + """ + + on_event: Optional[ft.EventHandler[BarChartEvent]] = None + """ + Called when an event occurs on this chart, such as a click or hover. + """ + + def __post_init__(self, ref: Optional[ft.Ref[Any]]): + super().__post_init__(ref) + self._internals["skip_properties"] = ["tooltip"] diff --git a/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_group.py b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_group.py new file mode 100644 index 0000000000..bff2745948 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_group.py @@ -0,0 +1,36 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_charts.bar_chart_rod import BarChartRod + +__all__ = ["BarChartGroup"] + + +@ft.control("BarChartGroup") +class BarChartGroup(ft.BaseControl): + """ + Groups one or more bar rods rendered at the same X-axis position. + """ + + x: int = 0 + """ + Group position on X axis. + """ + + rods: list[BarChartRod] = field(default_factory=list) + """ + The list of :class:`~flet_charts.BarChartRod` + objects to display in the group. + """ + + group_vertically: bool = False + """ + If set to `True` bar rods are drawn on top of each other; otherwise bar rods + are drawn next to each other. + """ + + spacing: Optional[ft.Number] = None + """ + The amount of space between bar rods. + """ diff --git a/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_rod.py b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_rod.py new file mode 100644 index 0000000000..622b8965fc --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_rod.py @@ -0,0 +1,139 @@ +from dataclasses import field +from typing import Optional, Union + +import flet as ft +from flet_charts.bar_chart_rod_stack_item import BarChartRodStackItem +from flet_charts.types import ChartDataPointTooltip + +__all__ = ["BarChartRod", "BarChartRodTooltip"] + + +@ft.value +class BarChartRodTooltip(ChartDataPointTooltip): + """ + Tooltip configuration for the :class:`~flet_charts.BarChartRod`. + """ + + text: Optional[str] = None + """ + The text to display in the tooltip. + + When `None`, defaults to + :attr:`flet_charts.BarChartRod.to_y`. + """ + + def copy( + self, + *, + text: Optional[str] = None, + text_style: Optional[ft.TextStyle] = None, + text_align: Optional[ft.TextAlign] = None, + text_spans: Optional[list[ft.TextSpan]] = None, + rtl: Optional[bool] = None, + ) -> "BarChartRodTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BarChartRodTooltip( + text=text if text is not None else self.text, + text_style=text_style if text_style is not None else self.text_style, + text_align=text_align if text_align is not None else self.text_align, + text_spans=text_spans.copy() + if text_spans is not None + else (self.text_spans.copy() if self.text_spans is not None else None), + rtl=rtl if rtl is not None else self.rtl, + ) + + +@ft.control("BarChartRod") +class BarChartRod(ft.BaseControl): + """A bar rod in a :class:`~flet_charts.BarChartGroup`.""" + + stack_items: list[BarChartRodStackItem] = field(default_factory=list) + """ + Optional list of :class:`~flet_charts.BarChartRodStackItem` objects to draw a \ + stacked bar. + """ + + from_y: ft.Number = 0 + """ + Specifies a starting position of this rod on Y axis. + """ + + to_y: Optional[ft.Number] = None + """ + Specifies an ending position of this rod on Y axis. + """ + + width: Optional[ft.Number] = None + """ + The width of this rod. + """ + + color: Optional[ft.ColorValue] = None + """ + Rod color. + """ + + gradient: Optional[ft.Gradient] = None + """ + Gradient to draw rod's background. + """ + + border_radius: Optional[ft.BorderRadiusValue] = None + """ + Border radius of a bar rod. + """ + + border_side: Optional[ft.BorderSide] = None + """ + Border to draw around rod. + """ + + bg_from_y: Optional[ft.Number] = None + """ + An optional starting position of a background behind this rod. + """ + + bg_to_y: Optional[ft.Number] = None + """ + An optional ending position of a background behind this rod. + """ + + bgcolor: Optional[ft.ColorValue] = None + """ + An optional color of a background behind + this rod. + """ + + background_gradient: Optional[ft.Gradient] = None + """ + An optional gradient to draw a background with. + """ + + selected: bool = False + """ + If set to `True` a tooltip is always shown on top of the bar when + :attr:`flet_charts.BarChart.interactive` + is set to `False`. + """ + + tooltip: Union[BarChartRodTooltip, str] = field( + default_factory=lambda: BarChartRodTooltip() + ) + """ + The rod's tooltip configuration for this rod. + """ + + show_tooltip: bool = True + """ + Whether a tooltip should be shown on top of hovered bar. + """ + + def before_update(self): + super().before_update() + self._internals["tooltip"] = ( + BarChartRodTooltip(text=self.tooltip) + if isinstance(self.tooltip, str) + else self.tooltip + ) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_rod_stack_item.py b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_rod_stack_item.py new file mode 100644 index 0000000000..322304acaa --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/bar_chart_rod_stack_item.py @@ -0,0 +1,33 @@ +from dataclasses import field +from typing import Optional + +import flet as ft + +__all__ = ["BarChartRodStackItem"] + + +@ft.control("BarChartRodStackItem") +class BarChartRodStackItem(ft.BaseControl): + """ + Colored segment used to build a stacked bar rod. + """ + + from_y: Optional[ft.Number] = None + """ + The starting position of this item inside a bar rod. + """ + + to_y: ft.Number = 0 + """ + The ending position of this item inside a bar rod. + """ + + color: Optional[ft.ColorValue] = None + """ + The color of this item. + """ + + border_side: ft.BorderSide = field(default_factory=lambda: ft.BorderSide.none()) + """ + A border around this item. + """ diff --git a/sdk/python/packages/flet-charts/src/flet_charts/candlestick_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/candlestick_chart.py new file mode 100644 index 0000000000..07299b5a03 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/candlestick_chart.py @@ -0,0 +1,300 @@ +from dataclasses import dataclass, field +from typing import Any, Optional + +import flet as ft +from flet_charts.candlestick_chart_spot import CandlestickChartSpot +from flet_charts.chart_axis import ChartAxis +from flet_charts.types import ChartEventType, ChartGridLines, HorizontalAlignment + +__all__ = [ + "CandlestickChart", + "CandlestickChartEvent", + "CandlestickChartTooltip", +] + + +@ft.value +class CandlestickChartTooltip: + """Configuration of the tooltip for :class:`~flet_charts.CandlestickChart`s.""" + + bgcolor: ft.ColorValue = "#FFFFECEF" + """ + Background color applied to the tooltip bubble. + """ + + border_radius: ft.BorderRadiusValue = field( + default_factory=lambda: ft.BorderRadius.all(4) + ) + """ + Corner radius of the tooltip bubble. + """ + + padding: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(vertical=8, horizontal=16) + ) + """ + Padding inside the tooltip bubble. + """ + + max_width: ft.Number = 120 + """ + Maximum width of the tooltip bubble. + """ + + rotation: ft.Number = 0.0 + """ + Rotation angle (in degrees) applied to the tooltip bubble. + """ + + horizontal_offset: ft.Number = 0 + """ + Horizontal offset applied to the tooltip bubble. + """ + + horizontal_alignment: HorizontalAlignment = HorizontalAlignment.CENTER + """ + Horizontal alignment of the tooltip relative to the tapped candlestick. + """ + + border_side: ft.BorderSide = field(default_factory=lambda: ft.BorderSide.none()) + """ + The tooltip bubble border. + """ + + fit_inside_horizontally: bool = False + """ + Forces the tooltip bubble to remain inside the chart horizontally. + """ + + fit_inside_vertically: bool = False + """ + Forces the tooltip bubble to remain inside the chart vertically. + """ + + show_on_top_of_chart_box_area: bool = False + """ + When set to `True`, the tooltip is drawn at the top of the chart box. + """ + + def copy( + self, + *, + bgcolor: Optional[ft.ColorValue] = None, + border_radius: Optional[ft.BorderRadiusValue] = None, + padding: Optional[ft.PaddingValue] = None, + max_width: Optional[ft.Number] = None, + rotation: Optional[ft.Number] = None, + horizontal_offset: Optional[ft.Number] = None, + horizontal_alignment: Optional[HorizontalAlignment] = None, + border_side: Optional[ft.BorderSide] = None, + fit_inside_horizontally: Optional[bool] = None, + fit_inside_vertically: Optional[bool] = None, + show_on_top_of_chart_box_area: Optional[bool] = None, + ) -> "CandlestickChartTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return CandlestickChartTooltip( + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + border_radius=( + border_radius if border_radius is not None else self.border_radius + ), + padding=padding if padding is not None else self.padding, + max_width=max_width if max_width is not None else self.max_width, + rotation=rotation if rotation is not None else self.rotation, + horizontal_offset=( + horizontal_offset + if horizontal_offset is not None + else self.horizontal_offset + ), + horizontal_alignment=( + horizontal_alignment + if horizontal_alignment is not None + else self.horizontal_alignment + ), + border_side=border_side if border_side is not None else self.border_side, + fit_inside_horizontally=( + fit_inside_horizontally + if fit_inside_horizontally is not None + else self.fit_inside_horizontally + ), + fit_inside_vertically=( + fit_inside_vertically + if fit_inside_vertically is not None + else self.fit_inside_vertically + ), + show_on_top_of_chart_box_area=( + show_on_top_of_chart_box_area + if show_on_top_of_chart_box_area is not None + else self.show_on_top_of_chart_box_area + ), + ) + + +@dataclass +class CandlestickChartEvent(ft.Event["CandlestickChart"]): + """Event raised for interactions with a :class:`~flet_charts.CandlestickChart`.""" + + type: ChartEventType + """ + Type of pointer gesture that triggered the event. + """ + + spot_index: Optional[int] = None + """ + Index of the candlestick that was interacted with; `None` if none. + """ + + +@ft.control("CandlestickChart") +class CandlestickChart(ft.LayoutControl): + """ + Draws a candlestick chart representing OHLC values. + + ```python + fch.CandlestickChart( + min_x=-1, + max_x=2, + min_y=20, + max_y=30, + bgcolor=ft.Colors.AMBER_200, + spots=[ + fch.CandlestickChartSpot( + x=0, + open=22.6, + high=28.3, + low=21.4, + close=24.1, + ), + ..., + ], + ) + ``` + + """ + + spots: list[CandlestickChartSpot] = field(default_factory=list) + """ + Candlesticks to display on the chart. + """ + + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + """ + Controls chart implicit animations. + """ + + interactive: bool = True + """ + Enables automatic tooltips and highlighting when hovering the chart. + """ + + show_tooltips_for_selected_spots_only: bool = False + """ + Whether to permanently and only show the tooltips of spots with their + :attr:`~flet_charts.CandlestickChartSpot.selected` property set to `True`. + """ + + long_press_duration: Optional[ft.DurationValue] = None + """ + The duration of a long press on the chart. + """ + + touch_spot_threshold: ft.Number = 4 + """ + The distance threshold to consider a touch near a candlestick. + """ + + bgcolor: Optional[ft.ColorValue] = None + """ + Background color of the chart. + """ + + border: Optional[ft.Border] = None + """ + Border drawn around the chart. + """ + + horizontal_grid_lines: Optional[ChartGridLines] = None + """ + Horizontal grid lines configuration. + """ + + vertical_grid_lines: Optional[ChartGridLines] = None + """ + Vertical grid lines configuration. + """ + + left_axis: Optional[ChartAxis] = None + """ + Appearance of the left axis, its title and labels. + """ + + top_axis: Optional[ChartAxis] = None + """ + Appearance of the top axis, its title and labels. + """ + + right_axis: Optional[ChartAxis] = None + """ + Appearance of the right axis, its title and labels. + """ + + bottom_axis: Optional[ChartAxis] = None + """ + Appearance of the bottom axis, its title and labels. + """ + + baseline_x: Optional[ft.Number] = None + """ + Baseline value on the X axis. + """ + + min_x: Optional[ft.Number] = None + """ + Minimum value displayed on the X axis. + """ + + max_x: Optional[ft.Number] = None + """ + Maximum value displayed on the X axis. + """ + + baseline_y: Optional[ft.Number] = None + """ + Baseline value on the Y axis. + """ + + min_y: Optional[ft.Number] = None + """ + Minimum value displayed on the Y axis. + """ + + max_y: Optional[ft.Number] = None + """ + Maximum value displayed on the Y axis. + """ + + rotation_quarter_turns: ft.Number = 0 + """ + Number of quarter turns (90-degree increments) to rotate the chart. + """ + + tooltip: Optional[CandlestickChartTooltip] = field( + default_factory=lambda: CandlestickChartTooltip() + ) + """ + Tooltip configuration for the chart. + """ + + on_event: Optional[ft.EventHandler[CandlestickChartEvent]] = None + """ + Called when an event occurs on this chart. + """ + + def __post_init__(self, ref: Optional[ft.Ref[Any]]): + super().__post_init__(ref) + self._internals["skip_properties"] = ["tooltip"] diff --git a/sdk/python/packages/flet-charts/src/flet_charts/candlestick_chart_spot.py b/sdk/python/packages/flet-charts/src/flet_charts/candlestick_chart_spot.py new file mode 100644 index 0000000000..7162277071 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/candlestick_chart_spot.py @@ -0,0 +1,98 @@ +from dataclasses import field +from typing import Optional, Union + +import flet as ft +from flet_charts.types import ChartDataPointTooltip + +__all__ = ["CandlestickChartSpot", "CandlestickChartSpotTooltip"] + + +@ft.value +class CandlestickChartSpotTooltip(ChartDataPointTooltip): + """Tooltip configuration for the :class:`~flet_charts.CandlestickChartSpot`.""" + + bottom_margin: ft.Number = 8 + """ + Space between the tooltip bubble and the candlestick. + """ + + def copy( + self, + *, + text: Optional[str] = None, + text_style: Optional[ft.TextStyle] = None, + text_align: Optional[ft.TextAlign] = None, + text_spans: Optional[list[ft.TextSpan]] = None, + rtl: Optional[bool] = None, + bottom_margin: Optional[ft.Number] = None, + ) -> "CandlestickChartSpotTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return CandlestickChartSpotTooltip( + text=text if text is not None else self.text, + text_style=text_style if text_style is not None else self.text_style, + text_align=text_align if text_align is not None else self.text_align, + text_spans=text_spans.copy() + if text_spans is not None + else (self.text_spans.copy() if self.text_spans is not None else None), + rtl=rtl if rtl is not None else self.rtl, + bottom_margin=bottom_margin + if bottom_margin is not None + else self.bottom_margin, + ) + + +@ft.control("CandlestickChartSpot") +class CandlestickChartSpot(ft.BaseControl): + """Represents a candlestick rendered on a :class:`~flet_charts.CandlestickChart`.""" + + x: ft.Number + """ + The position of the candlestick on the X axis. + """ + + open: ft.Number + """ + The open value of the candlestick. + """ + + high: ft.Number + """ + The high value of the candlestick. + """ + + low: ft.Number + """ + The low value of the candlestick. + """ + + close: ft.Number + """ + The close value of the candlestick. + """ + + selected: bool = False + """ + Whether to treat this candlestick as selected. + """ + + tooltip: Union[CandlestickChartSpotTooltip, str] = field( + default_factory=lambda: CandlestickChartSpotTooltip() + ) + """ + Tooltip configuration for this candlestick. + """ + + show_tooltip: bool = True + """ + Whether the tooltip should be shown when this candlestick is highlighted. + """ + + def before_update(self): + super().before_update() + self._internals["tooltip"] = ( + CandlestickChartSpotTooltip(text=self.tooltip) + if isinstance(self.tooltip, str) + else self.tooltip + ) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/chart_axis.py b/sdk/python/packages/flet-charts/src/flet_charts/chart_axis.py new file mode 100644 index 0000000000..a648eb80bf --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/chart_axis.py @@ -0,0 +1,84 @@ +from dataclasses import field +from typing import Optional + +import flet as ft + +__all__ = ["ChartAxis", "ChartAxisLabel"] + + +@ft.control("ChartAxisLabel") +class ChartAxisLabel(ft.BaseControl): + """ + Configures a custom label for specific value. + """ + + value: Optional[ft.Number] = None + """ + A value to draw label for. + """ + + label: Optional[ft.StrOrControl] = None + """ + The label to display for the specified :attr:`value`. + """ + + +@ft.control("ChartAxis") +class ChartAxis(ft.BaseControl): + """ + Configures chart axis. + """ + + title: Optional[ft.Control] = None + """ + A `Control` to display as axis title. + """ + + title_size: ft.Number = 16 + """ + The size of title area. + """ + + show_labels: bool = True + """ + Whether to display the :attr:`labels` along the axis. + If `labels` is empty then automatic labels are displayed. + """ + + labels: list[ChartAxisLabel] = field(default_factory=list) + """ + The list of :class:`~flet_charts.ChartAxisLabel` + objects to set custom axis labels for only specific values. + """ + + label_spacing: Optional[ft.Number] = None + """ + The spacing/interval between labels. + + If a value is not set, a suitable value + will be automatically calculated and used. + """ + + label_size: ft.Number = 22 + """ + The maximum space for each label in :attr:`labels`. + + Each label will stretch to fit this space. + """ + + show_min: bool = True + """ + Whether to display a label for the minimum value + independent of the sampling interval. + """ + + show_max: bool = True + """ + Whether to display a label for the maximum value + independent of the sampling interval. + """ + + def before_update(self): + super().before_update() + if self.label_spacing == 0: + raise ValueError("label_spacing cannot be 0") diff --git a/sdk/python/packages/flet-charts/src/flet_charts/line_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/line_chart.py new file mode 100644 index 0000000000..f49cb9289a --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/line_chart.py @@ -0,0 +1,336 @@ +from dataclasses import dataclass, field +from typing import Any, Optional + +import flet as ft +from flet_charts.chart_axis import ChartAxis +from flet_charts.line_chart_data import LineChartData +from flet_charts.types import ChartEventType, ChartGridLines, HorizontalAlignment + +__all__ = [ + "LineChart", + "LineChartEvent", + "LineChartEventSpot", + "LineChartTooltip", +] + + +@ft.value +class LineChartEventSpot: + """ + Identifies a concrete line/point pair involved in a chart interaction event. + """ + + bar_index: int + """ + The line's index or `-1` if no line was hovered. + """ + + spot_index: int + """ + The line's point index or `-1` if no point was hovered. + """ + + def copy( + self, + *, + bar_index: Optional[int] = None, + spot_index: Optional[int] = None, + ) -> "LineChartEventSpot": + """ + Returns a copy of this object with the specified properties overridden. + """ + return LineChartEventSpot( + bar_index=bar_index if bar_index is not None else self.bar_index, + spot_index=spot_index if spot_index is not None else self.spot_index, + ) + + +@dataclass +class LineChartEvent(ft.Event["LineChart"]): + """ + Event payload emitted when the user interacts with a line chart. + """ + + type: ChartEventType + """ + The type of event that occurred. + """ + + spots: list[LineChartEventSpot] + """ + Spots on which the event occurred. + + Note: + This list is empty when the event does not target a concrete point, for + example when the pointer hovers over or taps empty chart space. + """ + + +@ft.value +class LineChartTooltip: + """Configuration of the tooltip for :class:`~flet_charts.LineChart`s.""" + + bgcolor: ft.ColorValue = "#FF607D8B" + """ + Background color of tooltip. + """ + + border_radius: Optional[ft.BorderRadiusValue] = None + """ + The tooltip's border radius. + """ + + margin: ft.Number = 16 + """ + Applies a bottom margin for showing tooltip on top of rods. + """ + + padding: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(vertical=8, horizontal=16) + ) + """ + Applies a padding for showing contents inside the tooltip. + """ + + max_width: ft.Number = 120 + """ + Restricts the tooltip's width. + """ + + rotation: ft.Number = 0.0 + """ + The tooltip's rotation angle in degrees. + """ + + horizontal_offset: ft.Number = 0.0 + """ + Applies horizontal offset for showing tooltip. + """ + + border_side: ft.BorderSide = field(default_factory=lambda: ft.BorderSide.none()) + """ + Defines the borders of this tooltip. + """ + + fit_inside_horizontally: bool = False + """ + Forces the tooltip to shift horizontally inside the chart, if overflow happens. + """ + + fit_inside_vertically: bool = False + """ + Forces the tooltip to shift vertically inside the chart, if overflow happens. + """ + + show_on_top_of_chart_box_area: bool = False + """ + Whether to force the tooltip container to top of the line. + """ + + horizontal_alignment: HorizontalAlignment = HorizontalAlignment.CENTER + """ + The horizontal alignment of this tooltip. + """ + + def copy( + self, + *, + bgcolor: Optional[ft.ColorValue] = None, + border_radius: Optional[ft.BorderRadiusValue] = None, + margin: Optional[ft.Number] = None, + padding: Optional[ft.PaddingValue] = None, + max_width: Optional[ft.Number] = None, + rotation: Optional[ft.Number] = None, + horizontal_offset: Optional[ft.Number] = None, + border_side: Optional[ft.BorderSide] = None, + fit_inside_horizontally: Optional[bool] = None, + fit_inside_vertically: Optional[bool] = None, + show_on_top_of_chart_box_area: Optional[bool] = None, + ) -> "LineChartTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return LineChartTooltip( + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + border_radius=( + border_radius if border_radius is not None else self.border_radius + ), + margin=margin if margin is not None else self.margin, + padding=padding if padding is not None else self.padding, + max_width=max_width if max_width is not None else self.max_width, + rotation=rotation if rotation is not None else self.rotation, + horizontal_offset=( + horizontal_offset + if horizontal_offset is not None + else self.horizontal_offset + ), + border_side=border_side if border_side is not None else self.border_side, + fit_inside_horizontally=( + fit_inside_horizontally + if fit_inside_horizontally is not None + else self.fit_inside_horizontally + ), + fit_inside_vertically=( + fit_inside_vertically + if fit_inside_vertically is not None + else self.fit_inside_vertically + ), + show_on_top_of_chart_box_area=( + show_on_top_of_chart_box_area + if show_on_top_of_chart_box_area is not None + else self.show_on_top_of_chart_box_area + ), + ) + + +@ft.control("LineChart") +class LineChart(ft.LayoutControl): + """ + Draws a line chart. + + Example: + ```python + fch.LineChart( + min_y=0, + max_y=3, + min_x=0, + max_x=5, + data_series=[ + fch.LineChartData( + color=ft.Colors.BLUE_GREY_500, + curved=True, + points=[ + fch.LineChartDataPoint(1, 0.5), + fch.LineChartDataPoint(2, 1.5), + fch.LineChartDataPoint(3, 1), + ], + ), + ..., + ], + ) + ``` + + """ + + data_series: list[LineChartData] = field(default_factory=list) + """ + A list of :class:`~flet_charts.LineChartData` + controls drawn as separate lines on a chart. + """ + + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + """ + Controls chart implicit animation. + """ + + interactive: bool = True + """ + Enables automatic tooltips and points highlighting when hovering over the chart. + """ + + point_line_start: Optional[ft.Number] = None + """ + The start of the vertical line drawn under the selected point. + + Defaults to chart's bottom edge. + """ + + point_line_end: Optional[ft.Number] = None + """ + The end of the vertical line drawn at selected point position. + + Defaults to data point's `y` value. + """ + + bgcolor: Optional[ft.ColorValue] = None + """ + Background color of the chart. + """ + + border: Optional[ft.Border] = None + """ + The border around the chart. + """ + + horizontal_grid_lines: Optional[ChartGridLines] = None + """ + Controls drawing of chart's horizontal lines. + """ + + vertical_grid_lines: Optional[ChartGridLines] = None + """ + Controls drawing of chart's vertical lines. + """ + + left_axis: Optional[ChartAxis] = None + """ + Defines the appearance of the left axis, its title and labels. + """ + + top_axis: Optional[ChartAxis] = None + """ + Defines the appearance of the top axis, its title and labels. + """ + + right_axis: Optional[ChartAxis] = None + """ + Defines the appearance of the right axis, its title and labels. + """ + + bottom_axis: Optional[ChartAxis] = None + """ + Defines the appearance of the bottom axis, its title and labels. + """ + + baseline_x: Optional[ft.Number] = None + """ + Baseline value for X axis. + """ + + min_x: Optional[ft.Number] = None + """ + Defines the minimum displayed value for X axis. + """ + + max_x: Optional[ft.Number] = None + """ + Defines the maximum displayed value for X axis. + """ + + baseline_y: Optional[ft.Number] = None + """ + Baseline value for Y axis. + """ + + min_y: Optional[ft.Number] = None + """ + Defines the minimum displayed value for Y axis. + """ + + max_y: Optional[ft.Number] = None + """ + Defines the maximum displayed value for Y axis. + """ + + tooltip: Optional[LineChartTooltip] = field( + default_factory=lambda: LineChartTooltip() + ) + """ + The tooltip configuration for this chart. + + If set to `None`, no tooltips will be shown throughout this chart. + """ + + on_event: Optional[ft.EventHandler[LineChartEvent]] = None + """ + Fires when a chart line is hovered or clicked. + """ + + def __post_init__(self, ref: Optional[ft.Ref[Any]]): + super().__post_init__(ref) + self._internals["skip_properties"] = ["tooltip"] + self._internals["skip_inherited_notifier"] = True diff --git a/sdk/python/packages/flet-charts/src/flet_charts/line_chart_data.py b/sdk/python/packages/flet-charts/src/flet_charts/line_chart_data.py new file mode 100644 index 0000000000..620aa7fb8d --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/line_chart_data.py @@ -0,0 +1,159 @@ +from dataclasses import field +from typing import Optional, Union + +import flet as ft +from flet_charts.line_chart_data_point import LineChartDataPoint +from flet_charts.types import ChartPointLine, ChartPointShape + +__all__ = ["LineChartData"] + + +@ft.control("LineChartData") +class LineChartData(ft.BaseControl): + """ + Styling and geometry configuration for a single line series. + """ + + points: list[LineChartDataPoint] = field(default_factory=list) + """ + A list of points (dots) of :class:`~flet_charts.LineChartDataPoint` + type representing a single chart line. + """ + + curved: bool = False + """ + Whether to draw this chart line as a curve. + """ + + color: ft.ColorValue = ft.Colors.CYAN + """ + A color of chart line. + """ + + gradient: Optional[ft.Gradient] = None + """ + Gradient to draw line's background. + """ + + stroke_width: ft.Number = 2.0 + """ + The width of a chart line. + """ + + rounded_stroke_cap: bool = False + """ + Whether to draw rounded line caps. + """ + + prevent_curve_over_shooting: bool = False + """ + Whether to prevent overshooting when draw curve line on linear sequence spots. + """ + + prevent_curve_over_shooting_threshold: ft.Number = 10.0 + """ + Threshold for :attr:`prevent_curve_over_shooting` algorithm. + """ + + dash_pattern: Optional[list[int]] = None + """ + Defines dash effect of the line. The value is a circular list of dash offsets + and lengths. For example, the list `[5, 10]` would result in dashes 5 pixels + long followed by blank spaces 10 pixels long. By default, a solid line is + drawn. + """ + + shadow: ft.BoxShadow = field( + default_factory=lambda: ft.BoxShadow(color=ft.Colors.TRANSPARENT) + ) + """ + Shadow to drop by a chart line. + """ + + above_line_bgcolor: Optional[ft.ColorValue] = None + """ + Fill the area above chart line with the specified + color. + """ + + above_line_gradient: Optional[ft.Gradient] = None + """ + Fill the area above chart line with the specified gradient. + """ + + above_line_cutoff_y: Optional[ft.Number] = None + """ + Cut off filled area above line chart at specific Y value. + """ + + above_line: Optional[ChartPointLine] = None + """ + A vertical line drawn between a line point and the top edge of the chart. + """ + + below_line_bgcolor: Optional[ft.ColorValue] = None + """ + Fill the area below chart line with the specified + color. + """ + + below_line_gradient: Optional[ft.Gradient] = None + """ + Fill the area below chart line with the specified gradient. + """ + + below_line_cutoff_y: Optional[ft.Number] = None + """ + Cut off filled area below line chart at specific Y value. + """ + + below_line: Optional[ChartPointLine] = None + """ + A vertical line drawn between a line point and the bottom edge of the chart. + """ + + selected_below_line: Union[None, bool, ChartPointLine] = None + """ + A vertical line drawn between selected line point and the bottom edge of the + chart. + + Setting this property to `True` will draw a line with default style. + """ + + point: Union[None, bool, ChartPointShape] = None + """ + Defines the appearance and shape of a line point (dot). + + Setting this property to `True` will draw a point with default style. + """ + + selected_point: Union[None, bool, ChartPointShape] = None + """ + Defines the appearance and shape of a selected line point. + """ + + curve_smoothness: ft.Number = 0.35 + """ + Defines the smoothness of a curve line, + when :attr:`curved` is set to `True`. + """ + + rounded_stroke_join: bool = False + """ + Whether to draw rounded line joins. + """ + + step_direction: Optional[ft.Number] = None + """ + Determines the direction of each step. + + If not `None`, this chart will be drawn as a + [Step Line Chart](https://docs.anychart.com/Basic_Charts/Step_Line_Chart). + + Below are some typical values: + + - `0.0`: Go to the next spot directly, with the current point's y value. + - `0.5`: Go to the half with the current spot y, and with the next spot y + for the rest. + - `1.0`: Go to the next spot y and direct line to the next spot. + """ diff --git a/sdk/python/packages/flet-charts/src/flet_charts/line_chart_data_point.py b/sdk/python/packages/flet-charts/src/flet_charts/line_chart_data_point.py new file mode 100644 index 0000000000..d75fffc972 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/line_chart_data_point.py @@ -0,0 +1,114 @@ +from dataclasses import field +from typing import Optional, Union + +import flet as ft +from flet_charts.types import ChartDataPointTooltip, ChartPointLine, ChartPointShape + +__all__ = ["LineChartDataPoint", "LineChartDataPointTooltip"] + + +@ft.value +class LineChartDataPointTooltip(ChartDataPointTooltip): + """Tooltip configuration for the :class:`~flet_charts.LineChartDataPoint`.""" + + text: Optional[str] = None + """ + The text to display in the tooltip. + + When `None`, defaults to + :attr:`flet_charts.LineChartDataPoint.y`. + """ + + def copy( + self, + *, + text: Optional[str] = None, + text_style: Optional[ft.TextStyle] = None, + text_align: Optional[ft.TextAlign] = None, + text_spans: Optional[list[ft.TextSpan]] = None, + rtl: Optional[bool] = None, + ) -> "LineChartDataPointTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return LineChartDataPointTooltip( + text=text if text is not None else self.text, + text_style=text_style if text_style is not None else self.text_style, + text_align=text_align if text_align is not None else self.text_align, + text_spans=text_spans.copy() + if text_spans is not None + else (self.text_spans.copy() if self.text_spans is not None else None), + rtl=rtl if rtl is not None else self.rtl, + ) + + +@ft.control("LineChartDataPoint") +class LineChartDataPoint(ft.BaseControl): + """A :class:`~flet_charts.LineChartData` point.""" + + x: ft.Number + """ + The position of a point on `X` axis. + """ + + y: ft.Number + """ + The position of a point on `Y` axis. + """ + + selected: bool = False + """ + Draw the point as selected when + :attr:`flet_charts.LineChart.interactive` + is set to `False`. + """ + + point: Union[None, bool, ChartPointShape] = None + """ + Defines the appearance and shape of a line point. + """ + + selected_point: Union[None, bool, ChartPointShape] = None + """ + Defines the appearance and shape of a selected line point. + """ + + show_above_line: bool = True + """ + Whether to display a line above data point. + """ + + show_below_line: bool = True + """ + Whether to display a line below data point. + """ + + selected_below_line: Union[None, bool, ChartPointLine] = None + """ + A vertical line drawn between selected line point and the bottom edge of the chart. + + The value is either `True` - draw a line with default style, `False` - do not draw a + line under selected point, or an instance of :class:`~flet_charts.ChartPointLine` \ + class to + specify line style to draw. + """ + + tooltip: Union[LineChartDataPointTooltip, str] = field( + default_factory=lambda: LineChartDataPointTooltip() + ) + """ + Configuration of the tooltip for this data point. + """ + + show_tooltip: bool = True + """ + Whether the :attr:`tooltip` should be shown when this data point is hovered over. + """ + + def before_update(self): + super().before_update() + self._internals["tooltip"] = ( + LineChartDataPointTooltip(text=self.tooltip) + if isinstance(self.tooltip, str) + else self.tooltip + ) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py new file mode 100644 index 0000000000..450ecab3af --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_backends/backend_flet_agg.py @@ -0,0 +1,20 @@ +from matplotlib import _api +from matplotlib.backends import backend_webagg_core + + +class FigureCanvasFletAgg(backend_webagg_core.FigureCanvasWebAggCore): + """Canvas implementation used to render Matplotlib figures in Flet.""" + + manager_class = _api.classproperty(lambda cls: FigureManagerFletAgg) + supports_blit = False + + +class FigureManagerFletAgg(backend_webagg_core.FigureManagerWebAgg): + """Figure manager binding Matplotlib WebAgg tooling to Flet transport.""" + + _toolbar2_class = backend_webagg_core.NavigationToolbar2WebAgg + + +FigureCanvas = FigureCanvasFletAgg +FigureManager = FigureManagerFletAgg +interactive = True diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py new file mode 100644 index 0000000000..ed31e64403 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart.py @@ -0,0 +1,538 @@ +import asyncio +import logging +from dataclasses import dataclass, field +from io import BytesIO +from typing import Any, Optional + +import flet as ft +from flet_charts.matplotlib_chart_canvas import ( + MatplotlibChartCanvas, + MatplotlibChartCanvasResizeEvent, +) + +_MATPLOTLIB_IMPORT_ERROR: Optional[ImportError] = None + +try: + import matplotlib # type: ignore[import] + from matplotlib.figure import Figure # type: ignore[import] +except ImportError as e: # pragma: no cover - depends on optional dependency + matplotlib = None # type: ignore[assignment] + Figure = Any # type: ignore[assignment] + _MATPLOTLIB_IMPORT_ERROR = e +else: + matplotlib.use("module://flet_charts.matplotlib_backends.backend_flet_agg") + +__all__ = [ + "MatplotlibChart", + "MatplotlibChartMessageEvent", + "MatplotlibChartToolbarButtonsUpdateEvent", +] + +logger = logging.getLogger("flet-charts.matplotlib") + +figure_cursors = { + "default": None, + "pointer": ft.MouseCursor.CLICK, + "crosshair": ft.MouseCursor.PRECISE, + "move": ft.MouseCursor.MOVE, + "wait": ft.MouseCursor.WAIT, + "ew-resize": ft.MouseCursor.RESIZE_LEFT_RIGHT, + "ns-resize": ft.MouseCursor.RESIZE_UP_DOWN, +} + + +def _require_matplotlib() -> None: + """ + Ensure optional matplotlib dependency is available. + + Raises: + ModuleNotFoundError: If `matplotlib` is not installed. + """ + + if matplotlib is None: + raise ModuleNotFoundError( + 'Install "matplotlib" Python package to use MatplotlibChart control.' + ) from _MATPLOTLIB_IMPORT_ERROR + + +@dataclass +class MatplotlibChartMessageEvent(ft.Event["MatplotlibChart"]): + """ + Event carrying status text produced by the Matplotlib backend. + """ + + message: str + """ + Message text. + """ + + +@dataclass +class MatplotlibChartToolbarButtonsUpdateEvent(ft.Event["MatplotlibChart"]): + """ + Event describing enabled/disabled state changes for toolbar navigation buttons. + """ + + back_enabled: bool + """ + Whether Back button is enabled or not. + """ + forward_enabled: bool + """ + Whether Forward button is enabled or not. + """ + + +@ft.control(kw_only=True, isolated=True) +class MatplotlibChart(ft.GestureDetector): + """ + Displays a [Matplotlib](https://matplotlib.org/) chart. + + To display a Matplotlib figure with a built-in toolbar UI, use + :class:`~flet_charts.MatplotlibChartWithToolbar`. + + Warning: + This control requires the [`matplotlib`](https://matplotlib.org/) + Python package to be installed. + + See this [installation guide](index.md#installation) for more information. + """ + + figure: Figure = field(metadata={"skip": True}) + """ + Matplotlib figure to draw - an instance of + [`matplotlib.figure.Figure`](https://matplotlib.org/stable/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure). + """ + + on_message: Optional[ft.EventHandler[MatplotlibChartMessageEvent]] = None + """ + The event is triggered on figure message update. + """ + + on_toolbar_buttons_update: Optional[ + ft.EventHandler[MatplotlibChartToolbarButtonsUpdateEvent] + ] = None + """ + Triggers when toolbar buttons status is updated. + """ + + def init(self): + _require_matplotlib() + super().init() + + def build(self): + self.mouse_cursor = ft.MouseCursor.WAIT + self.__started = False + self.__dpr = self.page.media.device_pixel_ratio + logger.debug(f"DPR: {self.__dpr}") + self.__image_mode = "full" + + self.mpl_canvas = MatplotlibChartCanvas( + on_resize=self._on_canvas_resize, + expand=True, + ) + # Rubberband (zoom selection) overlay drawn on top of the chart image. + self._rubberband = ft.Container( + visible=False, + border=ft.Border.all(1, ft.Colors.with_opacity(0.6, ft.Colors.GREY)), + ) + self._stack = ft.Stack( + controls=[self.mpl_canvas, self._rubberband], + expand=True, + ) + self.keyboard_listener = ft.KeyboardListener( + self._stack, + autofocus=True, + on_key_down=self._on_key_down, + on_key_up=self._on_key_up, + ) + self.content = self.keyboard_listener + self.on_enter = self._on_enter + self.on_hover = self._on_hover + self.on_exit = self._on_exit + self.on_pan_start = self._pan_start + self.on_pan_update = self._pan_update + self.on_pan_end = self._pan_end + self.on_right_pan_start = self._right_pan_start + self.on_right_pan_update = self._right_pan_update + self.on_right_pan_end = self._right_pan_end + self.img_count = 1 + self._receive_queue = asyncio.Queue() + self._main_loop = asyncio.get_event_loop() + self._width = 0 + self._height = 0 + self._waiting = False + + def _on_key_down(self, e: ft.KeyboardEvent) -> None: + """ + Handle key-down notifications from keyboard listener. + + Args: + e: Keyboard event payload. + """ + + logger.debug(f"ON KEY DOWN: {e}") + + def _on_key_up(self, e: ft.KeyboardEvent) -> None: + """ + Handle key-up notifications from keyboard listener. + + Args: + e: Keyboard event payload. + """ + + logger.debug(f"ON KEY UP: {e}") + + def _on_enter(self, e: ft.HoverEvent): + """ + Notify backend that pointer entered the chart area. + + Args: + e: Hover event containing local pointer coordinates. + """ + + logger.debug(f"_on_enter: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "figure_enter", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 0, + "modifiers": [], + } + ) + + def _on_hover(self, e: ft.HoverEvent): + """ + Notify backend about pointer movement over chart area. + + Args: + e: Hover event containing local pointer coordinates. + """ + + logger.debug(f"_on_hover: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "motion_notify", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 0, + "modifiers": [], + } + ) + + def _on_exit(self, e: ft.HoverEvent): + """ + Notify backend that pointer left the chart area. + + Args: + e: Hover event containing local pointer coordinates. + """ + + logger.debug(f"_on_exit: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "figure_leave", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 0, + "modifiers": [], + } + ) + + def _pan_start(self, e: ft.DragStartEvent): + """ + Start primary-button drag interaction. + + Args: + e: Drag start event containing local pointer coordinates. + """ + + logger.debug(f"_pan_start: {e.local_position.x}, {e.local_position.y}") + asyncio.create_task(self.keyboard_listener.focus()) + self.send_message( + { + "type": "button_press", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 1, + "modifiers": [], + } + ) + + def _pan_update(self, e: ft.DragUpdateEvent): + """ + Continue primary-button drag interaction. + + Args: + e: Drag update event containing local pointer coordinates. + """ + + logger.debug(f"_pan_update: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "motion_notify", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 1, + "modifiers": [], + } + ) + + def _pan_end(self, e: ft.DragEndEvent): + """ + End primary-button drag interaction. + + Args: + e: Drag end event containing local pointer coordinates. + """ + + logger.debug(f"_pan_end: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "button_release", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 0, + "modifiers": [], + } + ) + + def _right_pan_start(self, e: ft.PointerEvent): + """ + Start secondary-button drag interaction. + + Args: + e: Pointer event containing local pointer coordinates. + """ + + logger.debug(f"_pan_start: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "button_press", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 2, + "buttons": 2, + "modifiers": [], + } + ) + + def _right_pan_update(self, e: ft.PointerEvent): + """ + Continue secondary-button drag interaction. + + Args: + e: Pointer event containing local pointer coordinates. + """ + + logger.debug(f"_pan_update: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "motion_notify", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 0, + "buttons": 2, + "modifiers": [], + } + ) + + def _right_pan_end(self, e: ft.PointerEvent): + """ + End secondary-button drag interaction. + + Args: + e: Pointer event containing local pointer coordinates. + """ + + logger.debug(f"_pan_end: {e.local_position.x}, {e.local_position.y}") + self.send_message( + { + "type": "button_release", + "x": e.local_position.x * self.__dpr, + "y": e.local_position.y * self.__dpr, + "button": 2, + "buttons": 0, + "modifiers": [], + } + ) + + def will_unmount(self): + """ + Called when the control is about to be removed from the page. + """ + self.figure.canvas.manager.remove_web_socket(self) + + def home(self): + """ + Resets the view to the original state. + """ + logger.debug("home)") + self.send_message({"type": "toolbar_button", "name": "home"}) + + def back(self): + """ + Goes back to the previous view. + """ + logger.debug("back()") + self.send_message({"type": "toolbar_button", "name": "back"}) + + def forward(self): + """ + Goes forward to the next view. + """ + logger.debug("forward)") + self.send_message({"type": "toolbar_button", "name": "forward"}) + + def pan(self): + """ + Activates the pan tool. + """ + logger.debug("pan()") + self.send_message({"type": "toolbar_button", "name": "pan"}) + + def zoom(self): + """ + Activates the zoom tool. + """ + logger.debug("zoom()") + self.send_message({"type": "toolbar_button", "name": "zoom"}) + + def download(self, format) -> bytes: + """ + Downloads the current figure in the specified format. + Args: + format (str): The format to download the figure in (e.g., 'png', + 'jpg', 'svg', etc.). + Returns: + bytes: The figure image in the specified format as a byte array. + """ + logger.debug(f"Download in format: {format}") + buff = BytesIO() + self.figure.savefig(buff, format=format, dpi=self.figure.dpi * self.__dpr) + return buff.getvalue() + + async def _receive_loop(self): + """ + Consume backend messages and apply canvas/state updates. + + The loop handles both binary image frames and JSON control messages + (cursor updates, draw requests, rubber-band overlays, status text, and + toolbar history state). + """ + + while True: + is_binary, content = await self._receive_queue.get() + + if is_binary: + assert isinstance(content, (bytes, bytearray)) + logger.debug(f"receive_binary({len(content)})") + # Hand the frame to the client widget — full PNG replaces the + # backbuffer, diff PNG composites onto it. Awaiting naturally + # rate-limits this loop to the client's processing speed and + # yields the asyncio loop for incoming events. + if self.__image_mode == "full": + await self.mpl_canvas.apply_full(bytes(content)) + else: + await self.mpl_canvas.apply_diff(bytes(content)) + self.img_count += 1 + self._waiting = False + else: + logger.debug(f"receive_json({content})") + if content["type"] == "image_mode": + self.__image_mode = content["mode"] + elif content["type"] == "cursor": + self.mouse_cursor = figure_cursors[content["cursor"]] + self.update() + elif content["type"] == "draw" and not self._waiting: + self._waiting = True + self.send_message({"type": "draw"}) + elif content["type"] == "rubberband": + if ( + content["x0"] != -1 + and content["y0"] != -1 + and content["x1"] != -1 + and content["y1"] != -1 + ): + x0 = content["x0"] / self.__dpr + y0 = self._height - content["y0"] / self.__dpr + x1 = content["x1"] / self.__dpr + y1 = self._height - content["y1"] / self.__dpr + self._rubberband.left = min(x0, x1) + self._rubberband.top = min(y0, y1) + self._rubberband.width = abs(x1 - x0) + self._rubberband.height = abs(y1 - y0) + self._rubberband.visible = True + else: + self._rubberband.visible = False + self._rubberband.update() + elif content["type"] == "resize": + self.send_message({"type": "refresh"}) + elif content["type"] == "message": + await self._trigger_event( + "message", {"message": content["message"]} + ) + elif content["type"] == "history_buttons": + await self._trigger_event( + "toolbar_buttons_update", + { + "back_enabled": content["Back"], + "forward_enabled": content["Forward"], + }, + ) + + def send_message(self, message): + """Sends a message to the figure's canvas manager.""" + logger.debug(f"send_message({message})") + manager = self.figure.canvas.manager + if manager is not None: + manager.handle_json(message) + + def send_json(self, content): + """Sends a JSON message to the front end.""" + logger.debug(f"send_json: {content}") + self._main_loop.call_soon_threadsafe( + lambda: self._receive_queue.put_nowait((False, content)) + ) + + def send_binary(self, blob): + """Sends a binary message to the front end.""" + self._main_loop.call_soon_threadsafe( + lambda: self._receive_queue.put_nowait((True, blob)) + ) + + async def _on_canvas_resize(self, e: MatplotlibChartCanvasResizeEvent): + """ + Handle canvas resize and initialize backend session on first resize. + + On first call, starts receive loop, registers this control with figure + manager, and requests initial image state. On every call, stores current + dimensions and sends a resize message to backend. + + Args: + e: Canvas resize event. + """ + + logger.debug(f"on_canvas_resize: {e.width}, {e.height}") + + if not self.__started: + self.__started = True + asyncio.create_task(self._receive_loop()) + self.figure.canvas.manager.add_web_socket(self) + self.send_message({"type": "send_image_mode"}) + self.send_message( + {"type": "set_device_pixel_ratio", "device_pixel_ratio": self.__dpr} + ) + self.send_message({"type": "refresh"}) + self._width = e.width + self._height = e.height + self.send_message( + {"type": "resize", "width": self._width, "height": self._height} + ) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py new file mode 100644 index 0000000000..174167a404 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_canvas.py @@ -0,0 +1,72 @@ +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft + +__all__ = ["MatplotlibChartCanvas", "MatplotlibChartCanvasResizeEvent"] + + +@dataclass +class MatplotlibChartCanvasResizeEvent(ft.Event["MatplotlibChartCanvas"]): + """ + Event emitted when the canvas reports a new rendered size. + """ + + width: float = field(metadata={"data_field": "w"}) + """New width of the canvas in logical pixels.""" + + height: float = field(metadata={"data_field": "h"}) + """New height of the canvas in logical pixels.""" + + +@ft.control("MatplotlibChartCanvas") +class MatplotlibChartCanvas(ft.LayoutControl): + """ + Display widget for matplotlib WebAgg-style image streams. + + Receives full and incremental "diff" PNG frames and composites them in + CPU memory, holding at most one decoded image for display at a time. + Avoids the per-frame `Picture.toImage` allocations that the generic + `flet.canvas.Canvas` capture path uses, which on Flutter web + (CanvasKit/WASM) accumulate and aren't promptly reclaimed by the JS GC + during animation, causing browser memory growth. + """ + + resize_interval: ft.Number = 10 + """ + Sampling interval in milliseconds for `on_resize` event. + """ + + on_resize: Optional[ft.EventHandler[MatplotlibChartCanvasResizeEvent]] = None + """ + Called when the size of this canvas has changed. + """ + + async def apply_full(self, image_bytes: bytes) -> None: + """ + Replace the current displayed image with a full PNG frame. + + Args: + image_bytes: PNG bytes of the complete frame. + """ + await self._invoke_method("apply_full", arguments={"bytes": image_bytes}) + + async def apply_diff(self, image_bytes: bytes) -> None: + """ + Composite an incremental "diff" PNG frame onto the current image. + + Pixels with non-zero alpha replace the corresponding pixels in the + existing backbuffer; transparent pixels leave the backbuffer + unchanged. If no backbuffer exists yet, the diff is treated as a + full frame. + + Args: + image_bytes: PNG bytes of the diff frame. + """ + await self._invoke_method("apply_diff", arguments={"bytes": image_bytes}) + + async def clear(self) -> None: + """ + Clear the displayed image and discard the backbuffer. + """ + await self._invoke_method("clear") diff --git a/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_with_toolbar.py b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_with_toolbar.py new file mode 100644 index 0000000000..805be57f8b --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/matplotlib_chart_with_toolbar.py @@ -0,0 +1,169 @@ +from dataclasses import field +from typing import Any, Optional + +import flet as ft +import flet_charts + +_MATPLOTLIB_IMPORT_ERROR: Optional[ImportError] = None + +try: + from matplotlib.figure import Figure # type: ignore +except ImportError as e: # pragma: no cover - depends on optional dependency + Figure = Any # type: ignore[assignment] + _MATPLOTLIB_IMPORT_ERROR = e + +_download_formats = [ + "eps", + "jpeg", + "pgf", + "pdf", + "png", + "ps", + "raw", + "svg", + "tif", + "webp", +] + + +def _require_matplotlib() -> None: + """ + Ensure matplotlib dependency is available. + + Raises: + ModuleNotFoundError: If `matplotlib` is not installed. + """ + + if _MATPLOTLIB_IMPORT_ERROR is not None: + raise ModuleNotFoundError( + 'Install "matplotlib" Python package to use MatplotlibChart control.' + ) from _MATPLOTLIB_IMPORT_ERROR + + +@ft.control(kw_only=True, isolated=True) +class MatplotlibChartWithToolbar(ft.Column): + """ + Composite control that combines a `MatplotlibChart` with a ready-made toolbar UI. + + Warning: + This control requires the [`matplotlib`](https://matplotlib.org/) + Python package to be installed. + + See this [installation guide](index.md#installation) for more information. + """ + + figure: Figure = field(metadata={"skip": True}) + """ + Matplotlib figure to draw - an instance of + [`matplotlib.figure.Figure`](https://matplotlib.org/stable/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure). + """ # noqa: E501 + + def build(self): + _require_matplotlib() + self.mpl = flet_charts.MatplotlibChart( + figure=self.figure, + expand=True, + on_message=self.on_message, + on_toolbar_buttons_update=self.on_toolbar_update, + ) + self.home_btn = ft.IconButton(ft.Icons.HOME, on_click=lambda: self.mpl.home()) + self.back_btn = ft.IconButton( + ft.Icons.ARROW_BACK_ROUNDED, on_click=lambda: self.mpl.back() + ) + self.fwd_btn = ft.IconButton( + ft.Icons.ARROW_FORWARD_ROUNDED, on_click=lambda: self.mpl.forward() + ) + self.pan_btn = ft.IconButton( + ft.Icons.OPEN_WITH, + selected_icon=ft.Icons.OPEN_WITH, + selected_icon_color=ft.Colors.AMBER_800, + on_click=self.pan_click, + ) + self.zoom_btn = ft.IconButton( + ft.Icons.ZOOM_IN, + selected_icon=ft.Icons.ZOOM_IN, + selected_icon_color=ft.Colors.AMBER_800, + on_click=self.zoom_click, + ) + self.download_btn = ft.IconButton( + ft.Icons.DOWNLOAD, on_click=self.download_click + ) + self.download_fmt = ft.Dropdown( + value="png", + options=[ft.DropdownOption(fmt) for fmt in _download_formats], + ) + self.msg = ft.Text() + self.controls = [ + ft.Row( + controls=[ + self.home_btn, + self.back_btn, + self.fwd_btn, + self.pan_btn, + self.zoom_btn, + self.download_btn, + self.download_fmt, + self.msg, + ] + ), + self.mpl, + ] + if not self.expand: + if not self.height: + self.height = self.figure.bbox.height + if not self.width: + self.width = self.figure.bbox.width + + def on_message(self, e: flet_charts.MatplotlibChartMessageEvent): + """ + Show status text produced by the underlying chart toolbar backend. + + Args: + e: Message event emitted by :class:`~flet_charts.MatplotlibChart`. + """ + + self.msg.value = e.message + self.msg.update() + + def on_toolbar_update( + self, e: flet_charts.MatplotlibChartToolbarButtonsUpdateEvent + ): + """ + Synchronize back/forward button enabled state with chart history. + + Args: + e: Toolbar state update event from + :class:`~flet_charts.MatplotlibChart`. + """ + + self.back_btn.disabled = not e.back_enabled + self.fwd_btn.disabled = not e.forward_enabled + self.update() + + def pan_click(self): + """ + Toggle pan mode and ensure zoom mode is turned off. + """ + + self.mpl.pan() + self.pan_btn.selected = not self.pan_btn.selected + self.zoom_btn.selected = False + + def zoom_click(self): + """ + Toggle zoom mode and ensure pan mode is turned off. + """ + + self.mpl.zoom() + self.pan_btn.selected = False + self.zoom_btn.selected = not self.zoom_btn.selected + + async def download_click(self): + """ + Export the figure in the selected format and prompt user to save it. + """ + + fmt = self.download_fmt.value + buffer = self.mpl.download(fmt) + title = self.figure.canvas.manager.get_window_title() + await ft.FilePicker().save_file(file_name=f"{title}.{fmt}", src_bytes=buffer) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/pie_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/pie_chart.py new file mode 100644 index 0000000000..6ed6c88a3d --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/pie_chart.py @@ -0,0 +1,84 @@ +from dataclasses import dataclass, field +from typing import Optional + +import flet as ft +from flet_charts.pie_chart_section import PieChartSection +from flet_charts.types import ChartEventType + +__all__ = ["PieChart", "PieChartEvent"] + + +@dataclass +class PieChartEvent(ft.Event["PieChart"]): + """ + Event payload emitted when the user interacts with a pie chart section. + """ + + type: ChartEventType + """ + Type of the event. + """ + + section_index: Optional[int] = None + """ + Section's index or `-1` if no section was hovered. + """ + + local_x: Optional[float] = None + """ + X coordinate of the local position where the event occurred. + """ + + local_y: Optional[float] = None + """ + Y coordinate of the local position where the event occurred. + """ + + +@ft.control("PieChart") +class PieChart(ft.LayoutControl): + """ + A pie chart control displaying multiple sections as slices of a circle. + """ + + sections: list[PieChartSection] = field(default_factory=list) + """ + A list of :class:`~flet_charts.PieChartSection` + controls drawn in a circle. + """ + + center_space_color: Optional[ft.ColorValue] = None + """ + Free space color in the middle of a chart. + """ + + center_space_radius: Optional[ft.Number] = None + """ + Free space radius in the middle of a chart. + """ + + sections_space: Optional[ft.Number] = None + """ + A gap between `sections`. + """ + + start_degree_offset: Optional[ft.Number] = None + """ + By default, `sections` are drawn from zero degree (right side of the circle) + clockwise. You can change the starting point by setting `start_degree_offset` + (in degrees). + """ + + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + """ + Controls chart implicit animation. + """ + + on_event: Optional[ft.EventHandler[PieChartEvent]] = None + """ + Fires when a chart section is hovered or clicked. + """ diff --git a/sdk/python/packages/flet-charts/src/flet_charts/pie_chart_section.py b/sdk/python/packages/flet-charts/src/flet_charts/pie_chart_section.py new file mode 100644 index 0000000000..0af14ab015 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/pie_chart_section.py @@ -0,0 +1,78 @@ +from dataclasses import field +from typing import Optional + +import flet as ft + +__all__ = ["PieChartSection"] + + +@ft.control("PieChartSection") +class PieChartSection(ft.BaseControl): + """ + Configures a :class:`~flet_charts.PieChart` section. + """ + + value: ft.Number + """ + Determines how much the section should occupy. This depends on sum of all sections, + each section should occupy (`value` / sum of all values) * `360` degrees. + """ + + radius: Optional[ft.Number] = None + """ + External radius of the section. + """ + + color: Optional[ft.ColorValue] = None + """ + Background color of the section. + """ + + border_side: ft.BorderSide = field(default_factory=lambda: ft.BorderSide.none()) + """ + The border around section shape. + """ + + title: Optional[str] = None + """ + A title drawn at the center of the section. + """ + + title_style: Optional[ft.TextStyle] = None + """ + The style to draw `title` with. + """ + + title_position: Optional[ft.Number] = None + """ + The position/offset of the :attr:`title` relative to the section's center. + + - `0.0`: near the center + - `1.0`: near the outside of the chart + + By default the :attr:`title` is drawn in the middle of the section. + """ + + badge: Optional[ft.Control] = None + """ + An optional `Control` drawn in the middle of a section. + """ + + badge_position: Optional[ft.Number] = None + """ + The position/offset of the :attr:`badge` relative to the section's center. + + - `0.0`: near the center + - `1.0`: near the outside of the chart + + By default the :attr:`badge` is drawn in the middle of the section. + """ + + gradient: Optional[ft.Gradient] = None + """ + Defines the gradient of section. If specified, overrides the color setting. + """ + + def init(self): + super().init() + self._internals["skip_properties"] = ["badge"] diff --git a/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py new file mode 100644 index 0000000000..c0d6e8e3bf --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/plotly_chart.py @@ -0,0 +1,85 @@ +import re +import xml.etree.ElementTree as ET +from dataclasses import field +from typing import Any, Optional + +import flet as ft + +_PLOTLY_IMPORT_ERROR: Optional[ImportError] = None + +try: + from plotly.graph_objects import Figure +except ImportError as e: # pragma: no cover - depends on optional dependency + Figure = Any # type: ignore[assignment] + _PLOTLY_IMPORT_ERROR = e + +__all__ = ["PlotlyChart"] + + +def _require_plotly() -> None: + """ + Ensure plotly dependency is available. + + Raises: + ModuleNotFoundError: If `plotly` is not installed. + """ + + if _PLOTLY_IMPORT_ERROR is not None: + raise ModuleNotFoundError( + 'Install "plotly" Python package to use PlotlyChart control.' + ) from _PLOTLY_IMPORT_ERROR + + +@ft.control(kw_only=True) +class PlotlyChart(ft.Container): + """ + Displays a [Plotly](https://plotly.com/python/) chart. + + Warning: + This control requires the [`plotly`](https://plotly.com/python/) and + [`kaleido`](https://github.com/plotly/Kaleido) Python + packages to be installed. + + See this [installation guide](index.md#installation) for more information. + + ```python + import plotly.express as px + + data_canada = px.data.gapminder().query("country == 'Canada'") + fig = px.bar(data_canada, x="year", y="pop") + fch.PlotlyChart(figure=fig, expand=True) + ``` + + """ + + figure: Figure = field(metadata={"skip": True}) + """ + Plotly figure to draw. + + The value is an instance of [`plotly.graph_objects.Figure`](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html). + """ + + original_size: bool = False + """ + Whether to display this chart in original size. + + Set to `False` for it to fit it's configured bounds. + """ + + def init(self): + _require_plotly() + self.alignment = ft.Alignment.CENTER + self.__img = ft.Image(src="", fit=ft.BoxFit.FILL) + self.content = self.__img + + def before_update(self): + super().before_update() + if self.figure is not None: + svg = self.figure.to_image(format="svg").decode("utf-8") + + if not self.original_size: + root = ET.fromstring(svg) + w = float(re.findall(r"\d+", root.attrib["width"])[0]) + h = float(re.findall(r"\d+", root.attrib["height"])[0]) + self.__img.aspect_ratio = w / h + self.__img.src = svg diff --git a/sdk/python/packages/flet-charts/src/flet_charts/radar_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/radar_chart.py new file mode 100644 index 0000000000..b5dfbda565 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/radar_chart.py @@ -0,0 +1,230 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import Optional + +import flet as ft +from flet_charts.radar_data_set import RadarDataSet +from flet_charts.types import ChartEventType + +__all__ = ["RadarChart", "RadarChartEvent", "RadarChartTitle", "RadarShape"] + + +class RadarShape(Enum): + """Shape of the radar grid and data polygons.""" + + CIRCLE = "circle" + """Draws radial circles for the grid and data outlines.""" + + POLYGON = "polygon" + """Draws straight-edged polygons for the grid and data outlines.""" + + +@ft.control("RadarChartTitle") +class RadarChartTitle(ft.BaseControl): + """ + Custom title configuration displayed around a :class:`~flet_charts.RadarChart`. + """ + + text: str = "" + """ + The text displayed for the title. + """ + + angle: ft.Number = 0 + """ + Rotation angle (in degrees) applied to the title. + """ + + position_percentage_offset: Optional[ft.Number] = None + """ + Defines the relative distance of this title from the chart center. + + - `0` draws this title near the inside edge of each section. + - `1` draws this title near the outside edge of each section. + + Must be between `0` and `1` (inclusive), if set. + + Note: + If set, it takes precedence over the parent + :attr:`flet_charts.RadarChart.title_position_percentage_offset` + value. + """ + + text_spans: Optional[list[ft.TextSpan]] = None + """ + Inline spans appended to the title. + """ + + +@dataclass +class RadarChartEvent(ft.Event["RadarChart"]): + """ + Event raised for interactions with a :class:`~flet_charts.RadarChart`. + """ + + type: ChartEventType + """ + The touch or pointer event that occurred. + """ + + data_set_index: Optional[int] = None + """ + The index of the touched data set, if any. + """ + + entry_index: Optional[int] = None + """ + The index of the touched radar entry, if any. + """ + + entry_value: Optional[ft.Number] = None + """ + The value of the touched radar entry, if any. + """ + + +@ft.control("RadarChart") +class RadarChart(ft.LayoutControl): + """ + A radar chart made of multiple datasets. + + ```python + fch.RadarChart( + titles=[fch.RadarChartTitle(text="winter"), ...], + radar_shape=fch.RadarShape.CIRCLE, + data_sets=[ + fch.RadarDataSet( + fill_color=ft.Colors.with_opacity(0.2, ft.Colors.BLUE_GREY_700), + entries=[fch.RadarDataSetEntry(130), ...], + ), + ..., + ], + ) + ``` + + """ + + data_sets: list[RadarDataSet] = field(default_factory=list) + """ + A list of :class:`~flet_charts.RadarDataSet` controls rendered on the chart. + """ + + titles: list[RadarChartTitle] = field(default_factory=list) + """ + The titles shown around this chart, matching the number of entries per set. + """ + + title_text_style: Optional[ft.TextStyle] = None + """ + The text style applied to titles around this chart. + """ + + title_position_percentage_offset: ft.Number = 0.2 + """ + Defines the relative distance of titles from the chart center. + + - `0` draws titles near the inside edge of each section. + - `1` draws titles near the outside edge of each section. + + Must be between `0` and `1` (inclusive). + + Raises: + ValueError: If set to a value less than `0` or greater than `1`. + """ + + radar_bgcolor: ft.ColorValue = ft.Colors.TRANSPARENT + """ + The background color of the radar area. + """ + + radar_border_side: ft.BorderSide = field( + default_factory=lambda: ft.BorderSide(width=2.0) + ) + """ + The outline drawn around the radar area. + """ + + radar_shape: RadarShape = RadarShape.POLYGON + """ + The shape of the radar area. + """ + + border: Optional[ft.Border] = None + """ + The border drawn around this chart. + """ + + center_min_value: bool = False + """ + Whether minimum entry values should be positioned at the center of this chart. + """ + + tick_count: ft.Number = 1 + """ + Number of tick rings drawn from the centre to the edge. + + Must be greater than or equal to `1`. + + Raises: + ValueError: If set to a value less than `1`. + """ + + ticks_text_style: Optional[ft.TextStyle] = None + """ + The text style used to draw tick labels. + """ + + tick_border_side: ft.BorderSide = field( + default_factory=lambda: ft.BorderSide(width=2.0) + ) + """ + The style of the tick rings. + """ + + grid_border_side: ft.BorderSide = field( + default_factory=lambda: ft.BorderSide(width=2.0) + ) + """ + The style of the radar grid lines. + """ + + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + """ + Controls the implicit animation applied when updating this chart. + """ + + interactive: bool = True + """ + Enables touch interactions and event notifications. + """ + + long_press_duration: Optional[ft.DurationValue] = None + """ + The duration before a long-press event fires. + """ + + touch_spot_threshold: ft.Number = 10 + """ + The radius (in logical pixels) used to detect nearby entries for touches. + """ + + on_event: Optional[ft.EventHandler[RadarChartEvent]] = None + """ + Called when the chart is interacted with. + """ + + def init(self): + super().init() + entries_lengths = {len(ds.entries) for ds in self.data_sets} + if len(entries_lengths) > 1: + raise ValueError( + "All data sets in the data_sets list must have equal number of entries" + ) + if not (0 <= self.title_position_percentage_offset <= 1): + raise ValueError("title_position_percentage_offset must be between 0 and 1") + if self.tick_count is not None and self.tick_count < 1: + raise ValueError("tick_count must be greater than or equal to 1") diff --git a/sdk/python/packages/flet-charts/src/flet_charts/radar_data_set.py b/sdk/python/packages/flet-charts/src/flet_charts/radar_data_set.py new file mode 100644 index 0000000000..568e13d947 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/radar_data_set.py @@ -0,0 +1,68 @@ +from dataclasses import field +from typing import Annotated, Optional + +import flet as ft +from flet.utils.validation import V + +__all__ = ["RadarDataSet", "RadarDataSetEntry"] + + +@ft.control("RadarDataSetEntry") +class RadarDataSetEntry(ft.BaseControl): + """ + A single data point rendered on a :class:`~flet_charts.RadarChart`. + """ + + value: ft.Number + """ + The numeric value drawn for this entry. + """ + + +@ft.control("RadarDataSet") +class RadarDataSet(ft.BaseControl): + """ + A collection of :class:`~flet_charts.RadarDataSetEntry` drawn as a filled radar \ + shape. + """ + + entries: Annotated[ + list[RadarDataSetEntry], + V.or_( + V.length_eq(0), + V.length_ge(3), + message=lambda _control, _field_name, value: ( + f"entries can contain either 0 or at least 3 items, got {len(value)}" + ), + ), + ] = field(default_factory=list) + """ + The data points that compose this set. + """ + + fill_color: ft.ColorValue = ft.Colors.CYAN + """ + The color used to fill this dataset. + """ + + fill_gradient: Optional[ft.Gradient] = None + """ + The gradient used to fill this dataset. + + Takes precedence over :attr:`fill_color`. + """ + + border_color: ft.ColorValue = ft.Colors.CYAN + """ + The color of the dataset outline. + """ + + border_width: ft.Number = 2.0 + """ + The width of the dataset outline. + """ + + entry_radius: ft.Number = 5.0 + """ + The radius of each entry. + """ diff --git a/sdk/python/packages/flet-charts/src/flet_charts/scatter_chart.py b/sdk/python/packages/flet-charts/src/flet_charts/scatter_chart.py new file mode 100644 index 0000000000..01646de1dc --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/scatter_chart.py @@ -0,0 +1,276 @@ +from dataclasses import dataclass, field +from typing import Any, Optional + +import flet as ft +from flet_charts.chart_axis import ChartAxis +from flet_charts.scatter_chart_spot import ScatterChartSpot +from flet_charts.types import ChartEventType, ChartGridLines, HorizontalAlignment + +__all__ = ["ScatterChart", "ScatterChartEvent", "ScatterChartTooltip"] + + +@ft.value +class ScatterChartTooltip: + """Configuration of the tooltip for :class:`~flet_charts.ScatterChart`s.""" + + bgcolor: ft.ColorValue = "#FF607D8B" + """ + The tooltip's background color. + """ + + border_radius: Optional[ft.BorderRadiusValue] = None + """ + The tooltip's border radius. + """ + + padding: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(vertical=8, horizontal=16) + ) + """ + Applies a padding for showing contents inside the tooltip. + """ + + max_width: ft.Number = 120 + """ + Restricts the tooltip's width. + """ + + rotation: ft.Number = 0.0 + """ + The tooltip's rotation angle in degrees. + """ + + horizontal_offset: ft.Number = 0 + """ + Applies horizontal offset for showing tooltip. + """ + + horizontal_alignment: HorizontalAlignment = HorizontalAlignment.CENTER + """ + The tooltip's horizontal alignment. + """ + + border_side: ft.BorderSide = field(default_factory=lambda: ft.BorderSide.none()) + """ + The tooltip's border side. + """ + + fit_inside_horizontally: bool = False + """ + Forces the tooltip to shift horizontally inside the chart, if overflow happens. + """ + + fit_inside_vertically: bool = False + """ + Forces the tooltip to shift vertically inside the chart, if overflow happens. + """ + + def copy( + self, + *, + bgcolor: Optional[ft.ColorValue] = None, + border_radius: Optional[ft.BorderRadiusValue] = None, + padding: Optional[ft.PaddingValue] = None, + max_width: Optional[ft.Number] = None, + rotation: Optional[ft.Number] = None, + horizontal_offset: Optional[ft.Number] = None, + horizontal_alignment: Optional[HorizontalAlignment] = None, + border_side: Optional[ft.BorderSide] = None, + fit_inside_horizontally: Optional[bool] = None, + fit_inside_vertically: Optional[bool] = None, + ) -> "ScatterChartTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ScatterChartTooltip( + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + border_radius=( + border_radius if border_radius is not None else self.border_radius + ), + padding=padding if padding is not None else self.padding, + max_width=max_width if max_width is not None else self.max_width, + rotation=rotation if rotation is not None else self.rotation, + horizontal_offset=( + horizontal_offset + if horizontal_offset is not None + else self.horizontal_offset + ), + horizontal_alignment=( + horizontal_alignment + if horizontal_alignment is not None + else self.horizontal_alignment + ), + border_side=border_side if border_side is not None else self.border_side, + fit_inside_horizontally=( + fit_inside_horizontally + if fit_inside_horizontally is not None + else self.fit_inside_horizontally + ), + fit_inside_vertically=( + fit_inside_vertically + if fit_inside_vertically is not None + else self.fit_inside_vertically + ), + ) + + +@dataclass +class ScatterChartEvent(ft.Event["ScatterChart"]): + """ + Event payload emitted when the user interacts with a scatter chart. + """ + + type: ChartEventType + """ + The type of the event that occurred. + """ + + spot_index: Optional[int] = None + """ + The index of the touched spot, if any. + """ + + +@ft.control("ScatterChart") +class ScatterChart(ft.LayoutControl): + """ + A scatter chart control. + + ScatterChart draws some points in a square space, + points are defined by :class:`~flet_charts.ScatterChartSpot`s. + + ```python + fch.ScatterChart( + aspect_ratio=1.0, + spots=[ + fch.ScatterChartSpot( + x=random.uniform(4, 50), + y=random.uniform(4, 50), + ) + for _ in range(30) + ], + ) + ``` + + """ + + spots: list[ScatterChartSpot] = field(default_factory=list) + """ + List of :class:`~flet_charts.ScatterChartSpot`s to show on the chart. + """ + + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + """ + Controls chart implicit animation. + """ + + interactive: bool = True + """ + Enables automatic tooltips when hovering chart bars. + """ + + long_press_duration: Optional[ft.DurationValue] = None + """ + The duration of a long press on the chart. + """ + + bgcolor: Optional[ft.ColorValue] = None + """ + The chart's background color. + """ + + border: Optional[ft.Border] = None + """ + The border around the chart. + """ + + horizontal_grid_lines: Optional[ChartGridLines] = None + """ + Controls drawing of chart's horizontal lines. + """ + + vertical_grid_lines: Optional[ChartGridLines] = None + """ + Controls drawing of chart's vertical lines. + """ + + left_axis: Optional[ChartAxis] = None + """ + Configures the appearance of the left axis, its title and labels. + """ + + top_axis: Optional[ChartAxis] = None + """ + Configures the appearance of the top axis, its title and labels. + """ + + right_axis: Optional[ChartAxis] = None + """ + Configures the appearance of the right axis, its title and labels. + """ + + bottom_axis: Optional[ChartAxis] = None + """ + Configures the appearance of the bottom axis, its title and labels. + """ + + baseline_x: Optional[ft.Number] = None + """ + The baseline value for X axis. + """ + + min_x: Optional[ft.Number] = None + """ + The minimum displayed value for X axis. + """ + + max_x: Optional[ft.Number] = None + """ + The maximum displayed value for X axis. + """ + + baseline_y: Optional[ft.Number] = None + """ + Baseline value for Y axis. + """ + + min_y: Optional[ft.Number] = None + """ + The minimum displayed value for Y axis. + """ + + max_y: Optional[ft.Number] = None + """ + The maximum displayed value for Y axis. + """ + + tooltip: ScatterChartTooltip = field(default_factory=lambda: ScatterChartTooltip()) + """ + The tooltip configuration for the chart. + """ + + show_tooltips_for_selected_spots_only: bool = False + """ + Whether to permanently and only show the tooltips of spots with their + :attr:`~flet_charts.ScatterChartSpot.selected` property set to `True`. + """ + + rotation_quarter_turns: ft.Number = 0 + """ + Number of quarter turns (90-degree increments) to rotate the chart. + Ex: `1` rotates the chart `90` degrees clockwise, + `2` rotates `180` degrees and `0` for no rotation. + """ + + on_event: Optional[ft.EventHandler[ScatterChartEvent]] = None + """ + Called when an event occurs on this chart. + """ + + def __post_init__(self, ref: Optional[ft.Ref[Any]]): + super().__post_init__(ref) + self._internals["skip_properties"] = ["tooltip"] diff --git a/sdk/python/packages/flet-charts/src/flet_charts/scatter_chart_spot.py b/sdk/python/packages/flet-charts/src/flet_charts/scatter_chart_spot.py new file mode 100644 index 0000000000..7e2d0fbeb0 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/scatter_chart_spot.py @@ -0,0 +1,141 @@ +from dataclasses import field +from typing import Any, Optional, Union + +import flet as ft +from flet_charts.types import ChartDataPointTooltip, ChartPointShape + +__all__ = ["ScatterChartSpot", "ScatterChartSpotTooltip"] + + +@ft.value +class ScatterChartSpotTooltip(ChartDataPointTooltip): + """ + Tooltip configuration for the :class:`~flet_charts.ScatterChartSpot`. + """ + + text: Optional[str] = None + """ + The text to display in the tooltip. + + When `None`, defaults to :attr:`flet_charts.ScatterChartSpot.y`. + """ + + bottom_margin: ft.Number = 8 + """ + The bottom space from the spot. + """ + + def copy( + self, + *, + text: Optional[str] = None, + text_style: Optional[ft.TextStyle] = None, + text_align: Optional[ft.TextAlign] = None, + text_spans: Optional[list[ft.TextSpan]] = None, + rtl: Optional[bool] = None, + bottom_margin: Optional[float] = None, + ) -> "ScatterChartSpotTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ScatterChartSpotTooltip( + text=text if text is not None else self.text, + text_style=text_style if text_style is not None else self.text_style, + text_align=text_align if text_align is not None else self.text_align, + text_spans=text_spans.copy() + if text_spans is not None + else (self.text_spans.copy() if self.text_spans is not None else None), + rtl=rtl if rtl is not None else self.rtl, + bottom_margin=bottom_margin + if bottom_margin is not None + else self.bottom_margin, + ) + + +@ft.control("ScatterChartSpot") +class ScatterChartSpot(ft.BaseControl): + """A spot on a scatter chart.""" + + x: Optional[ft.Number] = None + """ + The position of a spot on `X` axis. + """ + + y: Optional[ft.Number] = None + """ + The position of a spot on `Y` axis. + """ + + visible: bool = True + """ + Determines whether to show or hide the spot. + """ + + radius: Optional[ft.Number] = None + """ + Radius of a spot. + """ + + color: Optional[ft.ColorValue] = None + """ + Color of a spot. + """ + + render_priority: ft.Number = 0 + """ + Sort by this to manage overlap. + """ + + x_error: Optional[Any] = None + """ + Determines the error range of the data point using + [FlErrorRange](https://github.com/imaNNeo/fl_chart/blob/main/repo_files/documentations/base_chart.md#flerrorrange) + (which contains lowerBy and upperValue) for the `X` axis. + """ + + y_error: Optional[Any] = None + """ + Determines the error range of the data point using + [FlErrorRange](https://github.com/imaNNeo/fl_chart/blob/main/repo_files/documentations/base_chart.md#flerrorrange) + (which contains lowerBy and upperValue) for the `Y` axis. + """ + + selected: bool = False + """ + Whether to treat this spot as selected. + """ + + tooltip: Union[ScatterChartSpotTooltip, str] = field( + default_factory=lambda: ScatterChartSpotTooltip() + ) + """ + Tooltip configuration for this spot. + """ + + show_tooltip: bool = True + """ + Whether to show the tooltip. + """ + + label_text: str = "" + """ + TBD + """ + + label_text_style: ft.TextStyle = field(default_factory=lambda: ft.TextStyle()) + """ + TBD + """ + + point: Union[None, bool, ChartPointShape] = None + """ + TBD + """ + + def before_update(self): + super().before_update() + self._internals["tooltip"] = ( + ScatterChartSpotTooltip(text=self.tooltip) + if isinstance(self.tooltip, str) + else self.tooltip + ) diff --git a/sdk/python/packages/flet-charts/src/flet_charts/types.py b/sdk/python/packages/flet-charts/src/flet_charts/types.py new file mode 100644 index 0000000000..23a4d72c9c --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flet_charts/types.py @@ -0,0 +1,427 @@ +from dataclasses import field +from enum import Enum +from typing import Optional + +import flet as ft + +__all__ = [ + "ChartCirclePoint", + "ChartCrossPoint", + "ChartDataPointTooltip", + "ChartEventType", + "ChartGridLines", + "ChartPointLine", + "ChartPointShape", + "ChartSquarePoint", + "HorizontalAlignment", +] + + +@ft.value +class ChartGridLines: + """ + Configures the appearance of horizontal and vertical grid lines within the chart. + """ + + interval: Optional[ft.Number] = None + """ + The interval between grid lines. + """ + + color: Optional[ft.ColorValue] = None + """ + The color of a grid line. + """ + + width: ft.Number = 2.0 + """ + The width of a grid line. + """ + + dash_pattern: Optional[list[int]] = None + """ + Defines dash effect of the line. The value is a circular list of dash offsets + and lengths. For example, the list `[5, 10]` would result in dashes 5 pixels long + followed by blank spaces 10 pixels long. By default, a solid line is drawn. + """ + + def copy( + self, + *, + interval: Optional[ft.Number] = None, + color: Optional[ft.ColorValue] = None, + width: Optional[ft.Number] = None, + dash_pattern: Optional[list[int]] = None, + ) -> "ChartGridLines": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ChartGridLines( + interval=interval if interval is not None else self.interval, + color=color if color is not None else self.color, + width=width if width is not None else self.width, + dash_pattern=dash_pattern.copy() + if dash_pattern is not None + else (self.dash_pattern.copy() if self.dash_pattern is not None else None), + ) + + +@ft.value +class ChartPointShape: + """ + Base class for chart point shapes. + + See usable subclasses: + + * :class:`~flet_charts.ChartCirclePoint` + * :class:`~flet_charts.ChartCrossPoint` + * :class:`~flet_charts.ChartSquarePoint` + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + + +@ft.value +class ChartCirclePoint(ChartPointShape): + """Draws a circle.""" + + color: Optional[ft.ColorValue] = None + """ + The fill color to use for the circle. + """ + + radius: Optional[ft.Number] = None + """ + The radius of the circle. + """ + + stroke_color: Optional[ft.ColorValue] = None + """ + The stroke color to use for the circle + """ + + stroke_width: ft.Number = 0 + """ + The stroke width to use for the circle. + """ + + def __post_init__(self): + self._type = "ChartCirclePoint" + + def copy( + self, + *, + color: Optional[ft.ColorValue] = None, + radius: Optional[ft.Number] = None, + stroke_color: Optional[ft.ColorValue] = None, + stroke_width: Optional[ft.Number] = None, + ) -> "ChartCirclePoint": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ChartCirclePoint( + color=color if color is not None else self.color, + radius=radius if radius is not None else self.radius, + stroke_color=stroke_color + if stroke_color is not None + else self.stroke_color, + stroke_width=stroke_width + if stroke_width is not None + else self.stroke_width, + ) + + +@ft.value +class ChartSquarePoint(ChartPointShape): + """Draws a square.""" + + color: Optional[ft.ColorValue] = None + """ + The fill color to use for the square. + """ + + size: ft.Number = 4.0 + """ + The size of the square. + """ + + stroke_color: Optional[ft.ColorValue] = None + """ + The stroke color to use for the square. + """ + + stroke_width: ft.Number = 1.0 + """ + The stroke width to use for the square. + """ + + def __post_init__(self): + self._type = "ChartSquarePoint" + + def copy( + self, + *, + color: Optional[ft.ColorValue] = None, + size: Optional[ft.Number] = None, + stroke_color: Optional[ft.ColorValue] = None, + stroke_width: Optional[ft.Number] = None, + ) -> "ChartSquarePoint": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ChartSquarePoint( + color=color if color is not None else self.color, + size=size if size is not None else self.size, + stroke_color=stroke_color + if stroke_color is not None + else self.stroke_color, + stroke_width=stroke_width + if stroke_width is not None + else self.stroke_width, + ) + + +@ft.value +class ChartCrossPoint(ChartPointShape): + """Draws a cross-mark (X).""" + + color: Optional[ft.ColorValue] = None + """ + The fill color to use for the + cross-mark(X). + """ + + size: ft.Number = 8.0 + """ + The size of the cross-mark. + """ + + width: ft.Number = 2.0 + """ + The thickness of the cross-mark. + """ + + def __post_init__(self): + self._type = "ChartCrossPoint" + + def copy( + self, + *, + color: Optional[ft.ColorValue] = None, + size: Optional[ft.Number] = None, + width: Optional[ft.Number] = None, + ) -> "ChartCrossPoint": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ChartCrossPoint( + color=color if color is not None else self.color, + size=size if size is not None else self.size, + width=width if width is not None else self.width, + ) + + +@ft.value +class ChartPointLine: + """Defines style of a line.""" + + color: Optional[ft.ColorValue] = None + """ + The line's color. + """ + + width: ft.Number = 2 + """ + The line's width. + """ + + dash_pattern: Optional[list[int]] = None + """ + The line's dash pattern. + """ + + gradient: Optional[ft.Gradient] = None + """ + The line's gradient. + """ + + def copy( + self, + *, + color: Optional[ft.ColorValue] = None, + width: Optional[ft.Number] = None, + dash_pattern: Optional[list[int]] = None, + gradient: Optional[ft.Gradient] = None, + ) -> "ChartPointLine": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ChartPointLine( + color=color if color is not None else self.color, + width=width if width is not None else self.width, + dash_pattern=dash_pattern.copy() + if dash_pattern is not None + else self.dash_pattern.copy() + if self.dash_pattern is not None + else None, + gradient=gradient if gradient is not None else self.gradient, + ) + + +class ChartEventType(Enum): + """The type of event that occurred on the chart.""" + + PAN_END = "panEnd" + """ + When a pointer that was previously in contact with + the screen and moving is no longer in contact with the screen. + """ + + PAN_CANCEL = "panCancel" + """ + When the pointer that previously triggered a pan-start did not complete. + """ + + POINTER_EXIT = "pointerExit" + """ + The pointer has moved with respect to the device while the + pointer is or is not in contact with the device, and exited our chart. + """ + + LONG_PRESS_END = "longPressEnd" + """ + When a pointer stops contacting the screen after a long press + gesture was detected. Also reports the position where the + pointer stopped contacting the screen. + """ + + TAP_UP = "tapUp" + """ + When a pointer that will trigger a tap has stopped contacting the screen. + """ + + TAP_CANCEL = "tapCancel" + """ + When the pointer that previously triggered a tap-down will not end up causing a tap. + """ + + POINTER_ENTER = "pointerEnter" + """ + The pointer has moved with respect to the device while the pointer is or is + not in contact with the device, and it has entered our chart. + """ + + POINTER_HOVER = "pointerHover" + """ + The pointer has moved with respect to the device while the pointer is not + in contact with the device. + """ + + PAN_DOWN = "panDown" + """ + When a pointer has contacted the screen and might begin to move + """ + + PAN_START = "panStart" + """ + When a pointer has contacted the screen and has begun to move. + """ + + PAN_UPDATE = "panUpdate" + """ + When a pointer that is in contact with the screen and moving + has moved again. + """ + + LONG_PRESS_MOVE_UPDATE = "longPressMoveUpdate" + """ + When a pointer is moving after being held in contact at the same + location for a long period of time. Reports the new position and its offset + from the original down position. + """ + + LONG_PRESS_START = "longPressStart" + """ + When a pointer has remained in contact with the screen at the + same location for a long period of time. + """ + + TAP_DOWN = "tapDown" + """ + When a pointer that might cause a tap has contacted the + screen. + """ + + UNDEFINED = "undefined" + """ + An undefined event. + """ + + +@ft.value +class ChartDataPointTooltip: + """ + Configuration of the tooltip for data points in charts. + """ + + text: Optional[str] = None + """ + The text to display in this tooltip. + """ + + text_style: ft.TextStyle = field(default_factory=lambda: ft.TextStyle()) + """ + A text style to display tooltip with. + """ + + text_align: ft.TextAlign = ft.TextAlign.CENTER + """ + The text alignment of the tooltip. + """ + + text_spans: Optional[list[ft.TextSpan]] = None + """ + Additional text spans to show on this tooltip. + """ + + rtl: bool = False + """ + Whether the text is right-to-left. + """ + + def copy( + self, + *, + text: Optional[str] = None, + text_style: Optional[ft.TextStyle] = None, + text_align: Optional[ft.TextAlign] = None, + text_spans: Optional[list[ft.TextSpan]] = None, + rtl: Optional[bool] = None, + ) -> "ChartDataPointTooltip": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ChartDataPointTooltip( + text=text if text is not None else self.text, + text_style=text_style if text_style is not None else self.text_style, + text_align=text_align if text_align is not None else self.text_align, + text_spans=text_spans.copy() + if text_spans is not None + else self.text_spans.copy() + if self.text_spans is not None + else None, + rtl=rtl if rtl is not None else self.rtl, + ) + + +class HorizontalAlignment(Enum): + """Defines an element's horizontal alignment to given point.""" + + LEFT = "left" + """Element shown on the left side of the given point.""" + + CENTER = "center" + """Element shown horizontally center aligned to a given point.""" + + RIGHT = "right" + """Element shown on the right side of the given point.""" diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/.gitignore b/sdk/python/packages/flet-charts/src/flutter/flet_charts/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/CHANGELOG.md b/sdk/python/packages/flet-charts/src/flutter/flet_charts/CHANGELOG.md new file mode 100644 index 0000000000..2a5a5dfd04 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/CHANGELOG.md @@ -0,0 +1,3 @@ +# 0.2.0 + +Initial release of the package. diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/LICENSE b/sdk/python/packages/flet-charts/src/flutter/flet_charts/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/analysis_options.yaml b/sdk/python/packages/flet-charts/src/flutter/flet_charts/analysis_options.yaml new file mode 100644 index 0000000000..8df683425b --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:flutter_lints/flutter.yaml + + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/flet_charts.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/flet_charts.dart new file mode 100644 index 0000000000..42992b0a97 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/flet_charts.dart @@ -0,0 +1,3 @@ +library flet_flashlight; + +export 'src/extension.dart' show Extension; diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/bar_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/bar_chart.dart new file mode 100644 index 0000000000..960d6eb3c7 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/bar_chart.dart @@ -0,0 +1,97 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/bar_chart.dart'; +import 'utils/charts.dart'; + +class BarChartControl extends StatefulWidget { + final Control control; + + BarChartControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => _BarChartControlState(); +} + +class _BarChartControlState extends State { + BarChartEventData? _eventData; + + @override + Widget build(BuildContext context) { + debugPrint("BarChart build: ${widget.control.id}"); + final theme = Theme.of(context); + + var animation = widget.control.getAnimation( + "animation", + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 150), + curve: Curves.linear))!; + var border = widget.control.getBorder("border", theme); + var leftTitles = parseAxisTitles(widget.control.child("left_axis")); + var topTitles = parseAxisTitles(widget.control.child("top_axis")); + var rightTitles = parseAxisTitles(widget.control.child("right_axis")); + var bottomTitles = parseAxisTitles(widget.control.child("bottom_axis")); + var interactive = widget.control.getBool("interactive", true)!; + + List barGroups = widget.control + .children("groups") + .map((group) => parseBarChartGroupData(group, interactive, context)) + .toList(); + + var chart = BarChart( + BarChartData( + backgroundColor: widget.control.getColor("bgcolor", context), + minY: widget.control.getDouble("min_y"), + maxY: widget.control.getDouble("max_y"), + baselineY: widget.control.getDouble("baseline_y"), + titlesData: FlTitlesData( + show: (leftTitles.sideTitles.showTitles || + topTitles.sideTitles.showTitles || + rightTitles.sideTitles.showTitles || + bottomTitles.sideTitles.showTitles), + leftTitles: leftTitles, + topTitles: topTitles, + rightTitles: rightTitles, + bottomTitles: bottomTitles, + ), + borderData: FlBorderData(show: border != null, border: border), + alignment: parseBarChartAlignment( + widget.control.getMainAxisAlignment("group_alignment")?.name), + gridData: parseChartGridData( + widget.control.get("horizontal_grid_lines"), + widget.control.get("vertical_grid_lines"), + theme), + groupsSpace: widget.control.getDouble("spacing"), + barGroups: barGroups, + barTouchData: BarTouchData( + enabled: interactive, + touchTooltipData: parseBarTouchTooltipData(context, widget.control), + touchCallback: widget.control.getBool("on_event", false)! + ? (FlTouchEvent evt, BarTouchResponse? resp) { + var eventData = BarChartEventData.fromDetails(evt, resp); + if (eventData != _eventData) { + _eventData = eventData; + widget.control.triggerEvent("event", eventData.toMap()); + } + } + : null, + ), + ), + duration: animation.duration, // Optional + curve: animation.curve, + ); + + return LayoutControl( + control: widget.control, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return (constraints.maxHeight == double.infinity) + ? ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 300), + child: chart) + : chart; + })); + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/candlestick_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/candlestick_chart.dart new file mode 100644 index 0000000000..15bc6c8cb8 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/candlestick_chart.dart @@ -0,0 +1,129 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/candlestick_chart.dart'; +import 'utils/charts.dart'; + +class CandlestickChartControl extends StatefulWidget { + final Control control; + + CandlestickChartControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => + _CandlestickChartControlState(); +} + +class _CandlestickChartControlState extends State { + CandlestickChartEventData? _eventData; + + @override + Widget build(BuildContext context) { + debugPrint("CandlestickChart build: ${widget.control.id}"); + + final theme = Theme.of(context); + final animation = widget.control.getAnimation( + "animation", + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 150), + curve: Curves.linear))!; + final border = widget.control.getBorder("border", theme); + + final leftTitles = parseAxisTitles(widget.control.child("left_axis")); + final topTitles = parseAxisTitles(widget.control.child("top_axis")); + final rightTitles = parseAxisTitles(widget.control.child("right_axis")); + final bottomTitles = parseAxisTitles(widget.control.child("bottom_axis")); + + final interactive = widget.control.getBool("interactive", true)!; + + final spotControls = widget.control.children("spots"); + final candlestickSpots = spotControls.map((spot) { + spot.notifyParent = true; + return CandlestickSpot( + x: spot.getDouble("x", 0)!, + open: spot.getDouble("open", 0)!, + high: spot.getDouble("high", 0)!, + low: spot.getDouble("low", 0)!, + close: spot.getDouble("close", 0)!, + show: spot.visible, + ); + }).toList(); + + final candlestickTouchData = CandlestickTouchData( + enabled: interactive && !widget.control.disabled, + handleBuiltInTouches: !widget.control + .getBool("show_tooltips_for_selected_spots_only", false)!, + longPressDuration: widget.control.getDuration("long_press_duration"), + touchSpotThreshold: widget.control.getDouble("touch_spot_threshold", 4)!, + touchTooltipData: parseCandlestickTouchTooltipData( + context, + widget.control, + spotControls, + ), + touchCallback: widget.control.getBool("on_event", false)! + ? (event, response) { + final eventData = + CandlestickChartEventData.fromDetails(event, response); + if (eventData != _eventData) { + _eventData = eventData; + widget.control.triggerEvent("event", eventData.toMap()); + } + } + : null, + ); + + final chart = CandlestickChart( + CandlestickChartData( + candlestickSpots: candlestickSpots, + backgroundColor: widget.control.getColor("bgcolor", context), + minX: widget.control.getDouble("min_x"), + maxX: widget.control.getDouble("max_x"), + baselineX: widget.control.getDouble("baseline_x"), + minY: widget.control.getDouble("min_y"), + maxY: widget.control.getDouble("max_y"), + baselineY: widget.control.getDouble("baseline_y"), + titlesData: FlTitlesData( + show: (leftTitles.sideTitles.showTitles || + topTitles.sideTitles.showTitles || + rightTitles.sideTitles.showTitles || + bottomTitles.sideTitles.showTitles), + leftTitles: leftTitles, + topTitles: topTitles, + rightTitles: rightTitles, + bottomTitles: bottomTitles, + ), + borderData: FlBorderData(show: border != null, border: border), + gridData: parseChartGridData( + widget.control.get("horizontal_grid_lines"), + widget.control.get("vertical_grid_lines"), + theme), + candlestickTouchData: candlestickTouchData, + showingTooltipIndicators: spotControls + .asMap() + .entries + .where((e) => e.value.getBool("selected", false)!) + .map((e) => e.key) + .toList(), + rotationQuarterTurns: + widget.control.getInt("rotation_quarter_turns", 0)!, + ), + duration: animation.duration, + curve: animation.curve, + ); + + return LayoutControl( + control: widget.control, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return (constraints.maxHeight == double.infinity) + ? ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 300), + child: chart, + ) + : chart; + }), + ); + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/extension.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/extension.dart new file mode 100644 index 0000000000..cff762597c --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/extension.dart @@ -0,0 +1,34 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'bar_chart.dart'; +import 'candlestick_chart.dart'; +import 'line_chart.dart'; +import 'matplotlib_chart_canvas.dart'; +import 'radar_chart.dart'; +import 'pie_chart.dart'; +import 'scatter_chart.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "BarChart": + return BarChartControl(key: key, control: control); + case "CandlestickChart": + return CandlestickChartControl(key: key, control: control); + case "LineChart": + return LineChartControl(key: key, control: control); + case "MatplotlibChartCanvas": + return MatplotlibChartCanvasControl(key: key, control: control); + case "RadarChart": + return RadarChartControl(key: key, control: control); + case "PieChart": + return PieChartControl(key: key, control: control); + case "ScatterChart": + return ScatterChartControl(key: key, control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/line_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/line_chart.dart new file mode 100644 index 0000000000..d5defa781d --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/line_chart.dart @@ -0,0 +1,236 @@ +import 'package:collection/collection.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/charts.dart'; +import 'utils/line_chart.dart'; + +class LineChartControl extends StatefulWidget { + final Control control; + + LineChartControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => _LineChartControlState(); +} + +class _LineChartControlState extends State { + LineChartEventData? _eventData; + + final Map> _barSpots = {}; + + @override + void initState() { + super.initState(); + widget.control.addListener(_chartUpdated); + _chartUpdated(); + } + + @override + void dispose() { + widget.control.removeListener(_chartUpdated); + super.dispose(); + } + + _chartUpdated() { + setState(() { + for (var lineBar in widget.control.children("data_series")) { + lineBar.notifyParent = true; + List spots = []; + if (_barSpots.containsKey(lineBar.id)) { + spots = _barSpots[lineBar.id]!; + } else { + _barSpots[lineBar.id] = spots; + } + + spots.clear(); + for (var spot in lineBar.children("points")) { + spot.notifyParent = true; + spots.add(FlSpot(spot.getDouble("x")!, spot.getDouble("y")!)); + } + } + + // removed data series + for (var lineBarId in _barSpots.keys.toList()) { + if (!widget.control + .children("data_series") + .any((bar) => bar.id == lineBarId)) { + _barSpots.remove(lineBarId); + } + } + }); + } + + @override + Widget build(BuildContext context) { + debugPrint("LineChart build: ${widget.control.id}"); + final theme = Theme.of(context); + var animation = widget.control.getAnimation( + "animation", + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 150), + curve: Curves.linear))!; + var border = widget.control.getBorder("border", theme); + var leftTitles = parseAxisTitles(widget.control.child("left_axis")); + var topTitles = parseAxisTitles(widget.control.child("top_axis")); + var rightTitles = parseAxisTitles(widget.control.child("right_axis")); + var bottomTitles = parseAxisTitles(widget.control.child("bottom_axis")); + var interactive = widget.control.getBool("interactive", true)!; + var pointLineStart = widget.control.getDouble("point_line_start"); + var pointLineEnd = widget.control.getDouble("point_line_end"); + + List barsData = []; + List selectedPoints = []; + + var barIndex = 0; + for (var ds in widget.control.children("data_series")) { + var barData = parseLineChartBarData( + widget.control, ds, interactive, context, _barSpots); + barsData.add(barData); + + var spotIndex = 0; + for (var p in ds.children("points")) { + if (!interactive && p.getBool("selected", false)!) { + selectedPoints + .add(LineBarSpot(barData, barIndex, barData.spots[spotIndex])); + } + spotIndex++; + } + + barIndex++; + } + + var chart = LineChart( + LineChartData( + backgroundColor: widget.control.getColor("bgcolor", context), + minX: widget.control.getDouble("min_x"), + maxX: widget.control.getDouble("max_x"), + minY: widget.control.getDouble("min_y"), + maxY: widget.control.getDouble("max_y"), + baselineX: widget.control.getDouble("baseline_x"), + baselineY: widget.control.getDouble("baseline_y"), + showingTooltipIndicators: groupBy(selectedPoints, (p) => p.x) + .values + .map((e) => ShowingTooltipIndicators(e)) + .toList(), + titlesData: FlTitlesData( + show: (leftTitles.sideTitles.showTitles || + topTitles.sideTitles.showTitles || + rightTitles.sideTitles.showTitles || + bottomTitles.sideTitles.showTitles), + leftTitles: leftTitles, + topTitles: topTitles, + rightTitles: rightTitles, + bottomTitles: bottomTitles, + ), + borderData: FlBorderData(show: border != null, border: border), + gridData: parseChartGridData( + widget.control.get("horizontal_grid_lines"), + widget.control.get("vertical_grid_lines"), + theme), + lineBarsData: barsData, + lineTouchData: LineTouchData( + enabled: interactive, + getTouchLineStart: pointLineStart != null + ? (barData, spotIndex) => pointLineStart + : defaultGetTouchLineStart, + getTouchLineEnd: pointLineEnd != null + ? (barData, spotIndex) => pointLineEnd + : defaultGetTouchLineEnd, + getTouchedSpotIndicator: + (LineChartBarData barData, List spotIndexes) { + var barIndex = interactive + ? barsData.indexWhere( + (b) => b == barData.copyWith(showingIndicators: [])) + : barsData.indexWhere((b) => b == barData); + + return spotIndexes.map((index) { + if (barIndex == -1) return null; + + var allDotsLine = parseSelectedFlLine( + widget.control + .children("data_series")[barIndex] + .get("selected_below_line"), + theme, + barData.color, + barData.gradient); + + FlLine? dotLine = parseSelectedFlLine( + widget.control + .children("data_series")[barIndex] + .children("points")[index] + .get("selected_below_line"), + theme, + barData.color, + barData.gradient); + + return TouchedSpotIndicatorData( + dotLine ?? + allDotsLine ?? + FlLine( + color: getDefaultPointColor( + 0, barData.color, barData.gradient), + strokeWidth: 3), + FlDotData( + show: true, + getDotPainter: (spot, percent, barData, index) { + var allDotsPainter = parseChartDotPainter( + widget.control + .children("data_series")[barIndex] + .get("selected_point"), + theme, + percent, + barData.color, + barData.gradient, + selected: true); + var dotPainter = parseChartDotPainter( + widget.control + .children("data_series")[barIndex] + .children("points")[index] + .get("selected_point"), + theme, + percent, + barData.color, + barData.gradient, + selected: true); + return dotPainter ?? + allDotsPainter ?? + getDefaultDotPainter( + percent, barData.color, barData.gradient, + selected: true); + }, + ), + ); + }).toList(); + }, + touchTooltipData: parseLineTouchTooltipData( + context, widget.control, const LineTouchTooltipData())!, + touchCallback: widget.control.getBool("on_event", false)! + ? (evt, resp) { + var eventData = LineChartEventData.fromDetails(evt, resp); + if (eventData != _eventData) { + _eventData = eventData; + widget.control.triggerEvent("event", eventData.toMap()); + } + } + : null, + )), + duration: animation.duration, // Optional + curve: animation.curve, + ); + + return LayoutControl( + control: widget.control, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return (constraints.maxHeight == double.infinity) + ? ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 300), + child: chart, + ) + : chart; + })); + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart new file mode 100644 index 0000000000..2970c752f0 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart @@ -0,0 +1,457 @@ +import 'dart:async'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/material.dart'; + +/// Display widget for matplotlib WebAgg-style image streams. +/// +/// Two rendering strategies, picked at runtime by platform: +/// +/// - **GPU + flatten** (native): keeps an `_backdrop` plus a list of pending +/// diff `ui.Image`s, paints all of them per frame, and bakes them into a +/// fresh backdrop via `Picture.toImage` every [_GpuMatplotlibChartCanvasState._flattenInterval] +/// diffs. Fast (no GPU↔CPU readback) and memory-stable on native runtimes +/// where Dart GC is aggressive enough to reclaim layer-held SkImage refs. +/// +/// - **CPU composite** (web): decodes each PNG to RGBA bytes, composites +/// onto a single backbuffer in Dart, and uploads ONE fresh `ui.Image` per +/// frame. Slower per frame, but holds at most one `ui.Image` at a time so +/// layer-ref accumulation stays bounded under Flutter web (CanvasKit/WASM) +/// where Dart GC doesn't promptly reclaim native SkImage refs. +class MatplotlibChartCanvasControl extends StatefulWidget { + final Control control; + + MatplotlibChartCanvasControl({Key? key, required this.control}) + : super(key: key ?? ValueKey("control_${control.id}")); + + @override + // ignore: no_logic_in_create_state + State createState() => kIsWeb + ? _CpuMatplotlibChartCanvasState() + : _GpuMatplotlibChartCanvasState(); +} + +// --------------------------------------------------------------------------- +// Shared helpers +// --------------------------------------------------------------------------- + +Uint8List _extractBytes(dynamic args) { + final v = args is Map ? args["bytes"] : args; + if (v is Uint8List) return v; + if (v is ByteData) { + return v.buffer.asUint8List(v.offsetInBytes, v.lengthInBytes); + } + if (v is List) return Uint8List.fromList(v); + if (v is List && v.every((e) => e is int)) { + return Uint8List.fromList(v.cast()); + } + throw ArgumentError("Expected bytes for image data, got ${v.runtimeType}"); +} + +abstract class _MatplotlibChartCanvasStateBase + extends State { + // Serialize concurrent apply_full / apply_diff calls so backdrop mutations + // happen in arrival order. + Future? _applyChain; + + Size _lastSize = Size.zero; + int _lastResize = DateTime.now().millisecondsSinceEpoch; + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + widget.control.removeInvokeMethodListener(_invokeMethod); + disposeResources(); + super.dispose(); + } + + /// Subclass hook — release any held `ui.Image`s / backbuffers. + void disposeResources(); + + Future applyFull(Uint8List bytes); + Future applyDiff(Uint8List bytes); + Future clearAll(); + CustomPainter buildPainter(); + + Future _invokeMethod(String name, dynamic args) async { + switch (name) { + case "apply_full": + await _enqueue(() => applyFull(_extractBytes(args))); + return; + case "apply_diff": + await _enqueue(() => applyDiff(_extractBytes(args))); + return; + case "clear": + await _enqueue(clearAll); + return; + default: + throw Exception("Unknown MatplotlibChartCanvas method: $name"); + } + } + + Future _enqueue(Future Function() task) { + final prev = _applyChain ?? Future.value(); + final next = prev.then((_) => task()); + _applyChain = next.catchError((_) {}); + return next; + } + + void _maybeReportResize(Size size) { + final resizeInterval = widget.control.getInt("resize_interval", 10)!; + final now = DateTime.now().millisecondsSinceEpoch; + if ((now - _lastResize > resizeInterval && _lastSize != size) || + _lastSize.isEmpty) { + _lastSize = size; + _lastResize = now; + widget.control + .triggerEvent("resize", {"w": size.width, "h": size.height}); + } + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + _maybeReportResize(constraints.biggest); + }); + return CustomPaint( + size: constraints.biggest, + painter: buildPainter(), + ); + }, + ); + } +} + +/// Decodes PNG bytes to a [ui.Image], staying GPU-resident. +Future _decodeImage(Uint8List bytes) async { + if (bytes.isEmpty) { + debugPrint("MatplotlibChartCanvas: skipping empty image bytes"); + return null; + } + // Defensive copy; Safari's WASM runtime can free underlying buffers across + // async boundaries and trigger "EncodingError: Loading error.". + final owned = Uint8List.fromList(bytes); + ui.Codec? codec; + try { + codec = await ui.instantiateImageCodec(owned, allowUpscaling: false); + final frame = await codec.getNextFrame(); + return frame.image; + } catch (e) { + debugPrint( + "MatplotlibChartCanvas: decode failed (${owned.length} bytes): $e"); + rethrow; + } finally { + codec?.dispose(); + } +} + +// --------------------------------------------------------------------------- +// GPU + flatten strategy (native runtimes) +// --------------------------------------------------------------------------- + +class _GpuMatplotlibChartCanvasState + extends _MatplotlibChartCanvasStateBase { + // Number of diffs to accumulate before flattening into a fresh backdrop. + // Larger = fewer Picture.toImage calls; smaller = lower transient memory. + static const int _flattenInterval = 10; + + ui.Image? _backdrop; + final List _diffs = []; + + @override + void disposeResources() { + _backdrop?.dispose(); + _backdrop = null; + for (final img in _diffs) { + img.dispose(); + } + _diffs.clear(); + } + + @override + Future applyFull(Uint8List bytes) async { + final image = await _decodeImage(bytes); + if (image == null) return; + _replaceBackdrop(image); + _disposeDiffs(); + if (mounted) setState(() {}); + } + + @override + Future applyDiff(Uint8List bytes) async { + if (_backdrop == null) { + // No baseline yet — first frame must be a full. + await applyFull(bytes); + return; + } + final image = await _decodeImage(bytes); + if (image == null) return; + _diffs.add(image); + if (_diffs.length >= _flattenInterval) { + await _flatten(); + } + if (mounted) setState(() {}); + } + + @override + Future clearAll() async { + _replaceBackdrop(null); + _disposeDiffs(); + if (mounted) setState(() {}); + } + + /// Bakes [_backdrop] + pending [_diffs] into a single new backdrop via + /// `Picture.toImage`, replaces [_backdrop], and drops the diffs. + Future _flatten() async { + final backdrop = _backdrop; + if (backdrop == null || _diffs.isEmpty) return; + + final w = backdrop.width; + final h = backdrop.height; + + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final paint = Paint(); + canvas.drawImage(backdrop, Offset.zero, paint); + for (final diff in _diffs) { + canvas.drawImage(diff, Offset.zero, paint); + } + + final picture = recorder.endRecording(); + final ui.Image newBackdrop; + try { + newBackdrop = await picture.toImage(w, h); + } finally { + picture.dispose(); + } + + _replaceBackdrop(newBackdrop); + _disposeDiffs(); + } + + void _replaceBackdrop(ui.Image? image) { + final old = _backdrop; + _backdrop = image; + if (old != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + old.dispose(); + }); + } + } + + void _disposeDiffs() { + if (_diffs.isEmpty) return; + final old = List.of(_diffs); + _diffs.clear(); + WidgetsBinding.instance.addPostFrameCallback((_) { + for (final img in old) { + img.dispose(); + } + }); + } + + @override + CustomPainter buildPainter() => _GpuMatplotlibImagePainter( + backdrop: _backdrop, + diffs: List.unmodifiable(_diffs), + ); +} + +class _GpuMatplotlibImagePainter extends CustomPainter { + final ui.Image? backdrop; + final List diffs; + + const _GpuMatplotlibImagePainter({ + required this.backdrop, + required this.diffs, + }); + + @override + void paint(Canvas canvas, Size size) { + final bg = backdrop; + if (bg == null) return; + final dst = Rect.fromLTWH(0, 0, size.width, size.height); + final paint = Paint(); + final bgSrc = + Rect.fromLTWH(0, 0, bg.width.toDouble(), bg.height.toDouble()); + canvas.drawImageRect(bg, bgSrc, dst, paint); + for (final diff in diffs) { + final src = + Rect.fromLTWH(0, 0, diff.width.toDouble(), diff.height.toDouble()); + canvas.drawImageRect(diff, src, dst, paint); + } + } + + @override + bool shouldRepaint(_GpuMatplotlibImagePainter old) { + return backdrop != old.backdrop || diffs.length != old.diffs.length; + } +} + +// --------------------------------------------------------------------------- +// CPU composite strategy (web — CanvasKit/WASM) +// --------------------------------------------------------------------------- + +class _CpuMatplotlibChartCanvasState + extends _MatplotlibChartCanvasStateBase { + ui.Image? _displayImage; + Uint8List? _backbuffer; + int _bbWidth = 0; + int _bbHeight = 0; + + @override + void disposeResources() { + _displayImage?.dispose(); + _displayImage = null; + _backbuffer = null; + } + + @override + Future applyFull(Uint8List bytes) async { + final decoded = await _decodeRgba(bytes); + if (decoded == null) return; + + _backbuffer = decoded.bytes; + _bbWidth = decoded.width; + _bbHeight = decoded.height; + + final image = await _makeImage(decoded.bytes, decoded.width, decoded.height); + _swapDisplay(image); + } + + @override + Future applyDiff(Uint8List bytes) async { + if (_backbuffer == null) { + // No baseline yet — treat as full. + await applyFull(bytes); + return; + } + + final decoded = await _decodeRgba(bytes); + if (decoded == null) return; + + // Promote to a full replace if the frame size changed. + if (decoded.width != _bbWidth || + decoded.height != _bbHeight || + decoded.bytes.length != _backbuffer!.length) { + _backbuffer = decoded.bytes; + _bbWidth = decoded.width; + _bbHeight = decoded.height; + final image = + await _makeImage(decoded.bytes, decoded.width, decoded.height); + _swapDisplay(image); + return; + } + + // Composite: matplotlib's diff PNG has alpha=0 for unchanged pixels. + // Where alpha != 0, copy the new pixel into the backbuffer. + final bb = _backbuffer!.buffer.asUint32List(); + final df = decoded.bytes.buffer.asUint32List(); + for (int i = 0; i < df.length; i++) { + // RGBA8888 on little-endian: alpha is the highest byte (0xFF000000). + if ((df[i] & 0xFF000000) != 0) { + bb[i] = df[i]; + } + } + + final image = await _makeImage(_backbuffer!, _bbWidth, _bbHeight); + _swapDisplay(image); + } + + @override + Future clearAll() async { + final old = _displayImage; + _displayImage = null; + _backbuffer = null; + _bbWidth = 0; + _bbHeight = 0; + if (old != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + old.dispose(); + }); + } + if (mounted) setState(() {}); + } + + Future<_DecodedRgba?> _decodeRgba(Uint8List bytes) async { + final img = await _decodeImage(bytes); + if (img == null) return null; + try { + final byteData = + await img.toByteData(format: ui.ImageByteFormat.rawRgba); + if (byteData == null) return null; + return _DecodedRgba( + bytes: byteData.buffer.asUint8List(), + width: img.width, + height: img.height, + ); + } finally { + img.dispose(); + } + } + + Future _makeImage(Uint8List rgba, int width, int height) { + final completer = Completer(); + ui.decodeImageFromPixels( + rgba, + width, + height, + ui.PixelFormat.rgba8888, + completer.complete, + ); + return completer.future; + } + + void _swapDisplay(ui.Image newImage) { + final old = _displayImage; + _displayImage = newImage; + if (mounted) setState(() {}); + if (old != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + old.dispose(); + }); + } + } + + @override + CustomPainter buildPainter() => + _CpuMatplotlibImagePainter(image: _displayImage); +} + +class _DecodedRgba { + final Uint8List bytes; + final int width; + final int height; + _DecodedRgba( + {required this.bytes, required this.width, required this.height}); +} + +class _CpuMatplotlibImagePainter extends CustomPainter { + final ui.Image? image; + + const _CpuMatplotlibImagePainter({required this.image}); + + @override + void paint(Canvas canvas, Size size) { + final img = image; + if (img == null) return; + final src = + Rect.fromLTWH(0, 0, img.width.toDouble(), img.height.toDouble()); + final dst = Rect.fromLTWH(0, 0, size.width, size.height); + canvas.drawImageRect(img, src, dst, Paint()); + } + + @override + bool shouldRepaint(_CpuMatplotlibImagePainter old) => old.image != image; +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/pie_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/pie_chart.dart new file mode 100644 index 0000000000..7dfd8b752b --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/pie_chart.dart @@ -0,0 +1,71 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/pie_chart.dart'; + +class PieChartControl extends StatefulWidget { + final Control control; + + PieChartControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => _PieChartControlState(); +} + +class _PieChartControlState extends State { + PieChartEventData? _eventData; + + @override + Widget build(BuildContext context) { + debugPrint("PieChart build: ${widget.control.id}"); + + var animation = widget.control.getAnimation( + "animation", + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 150), + curve: Curves.linear))!; + + List sections = widget.control + .children("sections") + .map((section) => parsePieChartSectionData(section, context)) + .toList(); + + Widget chart = PieChart( + PieChartData( + centerSpaceColor: + widget.control.getColor("center_space_color", context), + centerSpaceRadius: widget.control.getDouble("center_space_radius"), + sectionsSpace: widget.control.getDouble("sections_space"), + startDegreeOffset: widget.control.getDouble("start_degree_offset"), + pieTouchData: PieTouchData( + enabled: true, + touchCallback: widget.control.getBool("on_event", false)! + ? (FlTouchEvent evt, PieTouchResponse? resp) { + var eventData = PieChartEventData.fromDetails(evt, resp); + if (eventData != _eventData) { + _eventData = eventData; + widget.control.triggerEvent("event", eventData.toMap()); + } + } + : null, + ), + sections: sections, + ), + duration: animation.duration, // Optional + curve: animation.curve, + ); + + return LayoutControl( + control: widget.control, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return (constraints.maxHeight == double.infinity) + ? ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 300), + child: chart) + : chart; + })); + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/radar_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/radar_chart.dart new file mode 100644 index 0000000000..ba251ecb6d --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/radar_chart.dart @@ -0,0 +1,104 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/radar_chart.dart'; + +class RadarChartControl extends StatefulWidget { + final Control control; + + RadarChartControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => _RadarChartControlState(); +} + +class _RadarChartControlState extends State { + RadarChartEventData? _eventData; + + @override + Widget build(BuildContext context) { + debugPrint("RadarChart build: ${widget.control.id}‚"); + + final theme = Theme.of(context); + final animation = widget.control.getAnimation( + "animation", + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 150), + curve: Curves.linear))!; + final interactive = widget.control.getBool("interactive", true)! && + !widget.control.disabled; + final border = widget.control.getBorder("border", theme); + final titleControls = widget.control.children("titles", visibleOnly: false); + + final chart = RadarChart( + RadarChartData( + dataSets: widget.control + .children("data_sets") + .map((ds) => parseRadarDataSet(ds, theme, context)) + .toList(), + + // Radar and borders + radarBackgroundColor: widget.control + .getColor("radar_bgcolor", context, Colors.transparent)!, + radarBorderData: widget.control.getBorderSide( + "radar_border_side", theme, + defaultValue: const BorderSide(width: 2))!, + radarShape: parseRadarShape( + widget.control.get("radar_shape"), RadarShape.polygon)!, + borderData: FlBorderData(show: border != null, border: border), + gridBorderData: widget.control.getBorderSide("grid_border_side", theme, + defaultValue: const BorderSide(width: 2))!, + + // Titles + titleTextStyle: widget.control.getTextStyle("title_text_style", theme), + titlePositionPercentageOffset: + widget.control.getDouble("title_position_percentage_offset", 0.2)!, + getTitle: titleControls.isNotEmpty + ? (int index, double angle) { + if (index >= titleControls.length) { + return RadarChartTitle(text: '', angle: angle); + } + final ctrl = titleControls[index]; + return parseRadarChartTitle(ctrl, theme, angle); + } + : null, + + // Ticks + tickCount: widget.control.getInt("tick_count", 1)!, + ticksTextStyle: widget.control.getTextStyle("ticks_text_style", theme), + tickBorderData: widget.control.getBorderSide("tick_border_side", theme, + defaultValue: const BorderSide(width: 2))!, + isMinValueAtCenter: widget.control.getBool("center_min_value", false)!, + + // Interaction + radarTouchData: RadarTouchData( + enabled: interactive, + longPressDuration: widget.control.getDuration("long_press_duration"), + touchSpotThreshold: widget.control.getDouble("touch_spot_threshold"), + touchCallback: (event, response) { + final eventData = RadarChartEventData.fromDetails(event, response); + if (eventData != _eventData) { + _eventData = eventData; + widget.control.triggerEvent("event", eventData.toMap()); + } + }, + ), + ), + duration: animation.duration, + curve: animation.curve, + ); + + return LayoutControl( + control: widget.control, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return (constraints.maxHeight == double.infinity) + ? ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 300), + child: chart) + : chart; + })); + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/scatter_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/scatter_chart.dart new file mode 100644 index 0000000000..5bcf298b23 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/scatter_chart.dart @@ -0,0 +1,142 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/charts.dart'; +import 'utils/scatter_chart.dart'; + +class ScatterChartControl extends StatefulWidget { + final Control control; + + ScatterChartControl({Key? key, required this.control}) + : super(key: ValueKey("control_${control.id}")); + + @override + State createState() => _ScatterChartControlState(); +} + +class _ScatterChartControlState extends State { + @override + Widget build(BuildContext context) { + debugPrint("ScatterChart build: ${widget.control.id}"); + + final theme = Theme.of(context); + var animation = widget.control.getAnimation( + "animation", + ImplicitAnimationDetails( + duration: const Duration(milliseconds: 150), + curve: Curves.linear))!; + var border = widget.control.getBorder("border", theme); + + var leftTitles = parseAxisTitles(widget.control.child("left_axis")); + var topTitles = parseAxisTitles(widget.control.child("top_axis")); + var rightTitles = parseAxisTitles(widget.control.child("right_axis")); + var bottomTitles = parseAxisTitles(widget.control.child("bottom_axis")); + + var interactive = widget.control.getBool("interactive", true)!; + + // Build list of ScatterSpotData + final spotsAsControls = widget.control.children('spots'); + final spots = spotsAsControls.map((spot) { + spot.notifyParent = true; + var x = spot.getDouble('x', 0)!; + var y = spot.getDouble('y', 0)!; + return ScatterSpot(x, y, + show: spot.visible, + renderPriority: spot.getInt('render_priority', 0)!, + xError: spot.get('x_error'), + yError: spot.get('y_error'), + dotPainter: spot.get("point") != null + ? parseChartDotPainter(spot.get("point"), theme, 0, null, null) + : FlDotCirclePainter( + radius: spot.getDouble("radius"), + color: spot.getColor( + "color", + context, + Colors.primaries[ + ((x * y) % Colors.primaries.length).toInt()])!, + )); + }).toList(); + + final chart = ScatterChart( + ScatterChartData( + scatterSpots: spots, + backgroundColor: widget.control.getColor("bgcolor", context), + minX: widget.control.getDouble("min_x"), + maxX: widget.control.getDouble("max_x"), + minY: widget.control.getDouble("min_y"), + maxY: widget.control.getDouble("max_y"), + baselineX: widget.control.getDouble("baseline_x"), + baselineY: widget.control.getDouble("baseline_y"), + titlesData: FlTitlesData( + show: (leftTitles.sideTitles.showTitles || + topTitles.sideTitles.showTitles || + rightTitles.sideTitles.showTitles || + bottomTitles.sideTitles.showTitles), + leftTitles: leftTitles, + topTitles: topTitles, + rightTitles: rightTitles, + bottomTitles: bottomTitles, + ), + borderData: FlBorderData(show: border != null, border: border), + gridData: parseChartGridData( + widget.control.get("horizontal_grid_lines"), + widget.control.get("vertical_grid_lines"), + theme), + scatterTouchData: ScatterTouchData( + enabled: interactive && !widget.control.disabled, + touchCallback: widget.control.getBool("on_event", false)! + ? (evt, resp) { + var eventData = ScatterChartEventData.fromDetails(evt, resp); + widget.control.triggerEvent("event", eventData.toMap()); + } + : null, + longPressDuration: widget.control.getDuration("long_press_duration"), + handleBuiltInTouches: !widget.control + .getBool("show_tooltips_for_selected_spots_only", false)!, + touchTooltipData: + parseScatterTouchTooltipData(context, widget.control, spots), + ), + scatterLabelSettings: ScatterLabelSettings( + showLabel: true, + getLabelFunction: (spotIndex, spot) { + var dp = spotsAsControls[spotIndex]; + return dp.getString("label_text", "")!; + }, + getLabelTextStyleFunction: (spotIndex, spot) { + var dp = spotsAsControls[spotIndex]; + var labelStyle = + dp.getTextStyle("label_text_style", theme, const TextStyle())!; + if (labelStyle.color == null) { + labelStyle = + labelStyle.copyWith(color: spot.dotPainter.mainColor); + } + return labelStyle; + }, + ), + showingTooltipIndicators: spotsAsControls + .asMap() + .entries + .where((e) => e.value.getBool("selected", false)!) + .map((e) => e.key) + .toList(), + rotationQuarterTurns: + widget.control.getInt('rotation_quarter_turns', 0)!, + //errorIndicatorData: widget.control.get('error_indicator_data'), + ), + duration: animation.duration, + curve: animation.curve, + ); + + return LayoutControl( + control: widget.control, + child: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return (constraints.maxHeight == double.infinity) + ? ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 300), + child: chart) + : chart; + })); + } +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/bar_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/bar_chart.dart new file mode 100644 index 0000000000..921ae1f808 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/bar_chart.dart @@ -0,0 +1,241 @@ +import 'package:collection/collection.dart'; +import 'package:equatable/equatable.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'charts.dart'; + +class BarChartEventData extends Equatable { + final String eventType; + final int? groupIndex; + final int? rodIndex; + final int? stackItemIndex; + + const BarChartEventData({ + required this.eventType, + required this.groupIndex, + required this.rodIndex, + required this.stackItemIndex, + }); + + factory BarChartEventData.fromDetails( + FlTouchEvent event, + BarTouchResponse? response, + ) { + return BarChartEventData( + eventType: resolveFlTouchEventType(event), + groupIndex: response != null && response.spot != null + ? response.spot!.touchedBarGroupIndex + : null, + rodIndex: response != null && response.spot != null + ? response.spot!.touchedRodDataIndex + : null, + stackItemIndex: response != null && response.spot != null + ? response.spot!.touchedStackItemIndex + : null, + ); + } + + Map toMap() => { + 'type': eventType, + 'group_index': groupIndex, + 'rod_index': rodIndex, + 'stack_item_index': stackItemIndex, + }; + + @override + List get props => [eventType, groupIndex, rodIndex, stackItemIndex]; +} + +TooltipDirection? parseTooltipDirection( + String? value, [ + TooltipDirection? defaultValue, +]) { + if (value == null) return defaultValue; + return TooltipDirection.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase(), + ) ?? + defaultValue; +} + +BarTouchTooltipData? parseBarTouchTooltipData( + BuildContext context, + Control control, [ + BarTouchTooltipData? defaultValue, +]) { + var tooltip = control.get("tooltip"); + if (tooltip == null) return defaultValue; + + final theme = Theme.of(context); + + return BarTouchTooltipData( + getTooltipColor: (BarChartGroupData group) => + parseColor(tooltip["bgcolor"], theme, theme.colorScheme.secondary)!, + tooltipBorderRadius: parseBorderRadius(tooltip["border_radius"]), + tooltipMargin: parseDouble(tooltip["margin"], 16)!, + tooltipPadding: parsePadding( + tooltip["padding"], + const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + )!, + maxContentWidth: parseDouble(tooltip["max_width"]), + rotateAngle: parseDouble(tooltip["rotation"], 0.0)!, + tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0)!, + tooltipBorder: parseBorderSide(tooltip["border_side"], theme), + fitInsideHorizontally: parseBool( + tooltip["fit_inside_horizontally"], + false, + )!, + fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!, + direction: parseTooltipDirection( + tooltip["direction"], + TooltipDirection.auto, + )!, + tooltipHorizontalAlignment: parseFLHorizontalAlignment( + tooltip["horizontal_alignment"], + FLHorizontalAlignment.center, + )!, + getTooltipItem: (group, groupIndex, rod, rodIndex) { + var rod = + control.children("groups")[groupIndex].children("rods")[rodIndex]; + return parseBarTooltipItem(rod, context); + }, + ); +} + +BarTooltipItem? parseBarTooltipItem(Control rod, BuildContext context) { + if (!rod.getBool("show_tooltip", true)!) return null; + + var tooltip = rod.internals?["tooltip"]; + if (tooltip == null) return null; + + final theme = Theme.of(context); + var tooltipTextStyle = parseTextStyle( + tooltip["text_style"], + theme, + const TextStyle(), + )!; + if (tooltipTextStyle.color == null) { + tooltipTextStyle = tooltipTextStyle.copyWith( + color: rod.getGradient("gradient", theme)?.colors.first ?? + rod.getColor("color", context, Colors.blueGrey)!, + ); + } + return BarTooltipItem( + tooltip["text"] ?? rod.getDouble("to_y", 0)!.toString(), + tooltipTextStyle, + textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!, + textDirection: parseBool(tooltip["rtl"], false)! + ? TextDirection.rtl + : TextDirection.ltr, + children: tooltip["text_spans"] != null + ? parseTextSpans(tooltip["text_spans"], theme, ( + s, + eventName, [ + eventData, + ]) { + s.triggerEvent(eventName, eventData); + }) + : null, + ); +} + +BarChartGroupData parseBarChartGroupData( + Control group, + bool interactiveChart, + BuildContext context, +) { + group.notifyParent = true; + return BarChartGroupData( + x: group.getInt("x", 0)!, + barsSpace: group.getDouble("spacing"), + groupVertically: group.getBool("group_vertically", false)!, + showingTooltipIndicators: group + .children("rods") + .asMap() + .entries + .where( + (rod) => !interactiveChart && rod.value.getBool("selected", false)!, + ) + .map((rod) => rod.key) + .toList(), + barRods: group + .children("rods") + .map((rod) => parseBarChartRodData(rod, interactiveChart, context)) + .toList(), + ); +} + +BarChartRodData parseBarChartRodData( + Control rod, + bool interactiveChart, + BuildContext context, +) { + rod.notifyParent = true; + + final theme = Theme.of(context); + var bgFromY = rod.getDouble("bg_from_y"); + var bgToY = rod.getDouble("bg_to_y"); + var bgcolor = rod.getColor("bgcolor", context); + var backgroundGradient = rod.getGradient("background_gradient", theme); + + return BarChartRodData( + fromY: rod.getDouble("from_y"), + toY: rod.getDouble("to_y", 0)!, + width: rod.getDouble("width"), + color: rod.getColor("color", context), + gradient: rod.getGradient("gradient", theme), + borderRadius: rod.getBorderRadius("border_radius"), + borderSide: rod.getBorderSide( + "border_side", + theme, + defaultValue: BorderSide.none, + ), + backDrawRodData: BackgroundBarChartRodData( + show: (bgFromY != null || + bgToY != null || + bgcolor != null || + backgroundGradient != null), + fromY: bgFromY, + toY: bgToY, + color: bgcolor, + gradient: backgroundGradient, + ), + rodStackItems: rod + .children("stack_items") + .map( + (rodStackItem) => parseBarChartRodStackItem( + rodStackItem, + interactiveChart, + context, + ), + ) + .toList(), + ); +} + +BarChartRodStackItem parseBarChartRodStackItem( + Control rodStackItem, + bool interactiveChart, + BuildContext context, +) { + rodStackItem.notifyParent = true; + return BarChartRodStackItem( + rodStackItem.getDouble("from_y")!, + rodStackItem.getDouble("to_y", 0)!, + rodStackItem.getColor("color", context)!, + borderSide: rodStackItem.getBorderSide( + "border_side", + Theme.of(context), + defaultValue: BorderSide.none, + )!, + ); +} + +BarChartAlignment? parseBarChartAlignment(String? value, + [BarChartAlignment? defaultValue]) { + if (value == null) return defaultValue; + return BarChartAlignment.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart new file mode 100644 index 0000000000..2ccfcb8357 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart @@ -0,0 +1,118 @@ +import 'package:equatable/equatable.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'charts.dart'; + +class CandlestickChartEventData extends Equatable { + final String eventType; + final int? spotIndex; + + const CandlestickChartEventData({ + required this.eventType, + required this.spotIndex, + }); + + factory CandlestickChartEventData.fromDetails( + FlTouchEvent event, + CandlestickTouchResponse? response, + ) { + return CandlestickChartEventData( + eventType: resolveFlTouchEventType(event), + spotIndex: response?.touchedSpot?.spotIndex, + ); + } + + Map toMap() => { + "type": eventType, + "spot_index": spotIndex, + }; + + @override + List get props => [eventType, spotIndex]; +} + +CandlestickTouchTooltipData parseCandlestickTouchTooltipData( + BuildContext context, Control control, List spotControls) { + final tooltip = control.get("tooltip") ?? {}; + final theme = Theme.of(context); + + return CandlestickTouchTooltipData( + tooltipBorder: parseBorderSide(tooltip["border_side"], theme, + defaultValue: BorderSide.none)!, + rotateAngle: parseDouble(tooltip["rotation"], 0.0)!, + tooltipBorderRadius: + parseBorderRadius(tooltip["border_radius"], BorderRadius.circular(4))!, + tooltipPadding: parsePadding(tooltip["padding"], + const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!, + tooltipHorizontalAlignment: parseFLHorizontalAlignment( + tooltip["horizontal_alignment"], FLHorizontalAlignment.center)!, + tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0)!, + maxContentWidth: parseDouble(tooltip["max_width"], 120)!, + fitInsideHorizontally: + parseBool(tooltip["fit_inside_horizontally"], false)!, + fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!, + showOnTopOfTheChartBoxArea: + parseBool(tooltip["show_on_top_of_chart_box_area"], false)!, + getTooltipColor: (spot) => + parseColor(tooltip["bgcolor"], theme, const Color(0xFFFFECEF))!, + getTooltipItems: (painter, touchedSpot, spotIndex) { + if (spotIndex < 0 || spotIndex >= spotControls.length) { + return null; + } + return parseCandlestickTooltipItem( + spotControls[spotIndex], + painter, + touchedSpot, + spotIndex, + context, + ); + }, + ); +} + +CandlestickTooltipItem? parseCandlestickTooltipItem( + Control spotControl, + FlCandlestickPainter painter, + CandlestickSpot touchedSpot, + int spotIndex, + BuildContext context, +) { + if (!spotControl.getBool("show_tooltip", true)!) { + return null; + } + + final tooltip = spotControl.internals?["tooltip"]; + if (tooltip == null) { + return null; + } + + final theme = Theme.of(context); + var textStyle = + parseTextStyle(tooltip["text_style"], theme, const TextStyle())!; + if (textStyle.color == null) { + textStyle = textStyle.copyWith( + color: painter.getMainColor( + spot: touchedSpot, + spotIndex: spotIndex, + ), + ); + } + + return CandlestickTooltipItem( + tooltip["text"] ?? "", + textStyle: textStyle, + bottomMargin: parseDouble(tooltip["bottom_margin"], 8)!, + textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!, + textDirection: parseBool(tooltip["rtl"], false)! + ? TextDirection.rtl + : TextDirection.ltr, + children: tooltip["text_spans"] != null + ? parseTextSpans(tooltip["text_spans"], theme, (s, eventName, + [eventData]) { + s.triggerEvent(eventName, eventData); + }) + : null, + ); +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/charts.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/charts.dart new file mode 100644 index 0000000000..91213a6b09 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/charts.dart @@ -0,0 +1,194 @@ +import 'package:collection/collection.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +FlDotPainter invisibleDotPainter = + FlDotCirclePainter(radius: 0, strokeWidth: 0); +FlLine invisibleLine = const FlLine(strokeWidth: 0); + +FlGridData parseChartGridData( + dynamic horizontal, dynamic vertical, ThemeData theme) { + if (horizontal == null && vertical == null) { + return const FlGridData(show: false); + } + + var hLine = parseFlLine(horizontal, theme); + var vLine = parseFlLine(vertical, theme); + + return FlGridData( + show: true, + drawHorizontalLine: horizontal != null, + horizontalInterval: + horizontal != null ? parseDouble(horizontal["interval"]) : null, + getDrawingHorizontalLine: + hLine == null ? defaultGridLine : (value) => hLine, + drawVerticalLine: vertical != null, + verticalInterval: + vertical != null ? parseDouble(vertical["interval"]) : null, + getDrawingVerticalLine: vLine == null ? defaultGridLine : (value) => vLine, + ); +} + +FlLine? parseFlLine(dynamic value, ThemeData theme, [FlLine? defaultValue]) { + if (value == null || + (value['color'] == null && + value['width'] == null && + value['gradient'] == null && + value['dash_pattern'] == null)) { + return defaultValue; + } + + return FlLine( + color: parseColor(value['color'], theme, Colors.black)!, + strokeWidth: parseDouble(value['width'], 2)!, + gradient: parseGradient(value['gradient'], theme), + dashArray: (value['dash_pattern'] as List?) + ?.map((e) => parseInt(e)) + .nonNulls + .toList()); +} + +FlLine? parseSelectedFlLine( + dynamic value, ThemeData theme, Color? color, Gradient? gradient, + [FlLine? defaultValue]) { + if (value == null) return defaultValue; + + if (value == false) { + return invisibleLine; + } else if (value == true) { + return FlLine( + color: getDefaultPointColor(0, color, gradient), strokeWidth: 3); + } + + return parseFlLine(value, theme, defaultValue)?.copyWith( + color: parseColor( + value['color'], theme, defaultGetDotStrokeColor(0, color, gradient))); +} + +FlDotPainter? parseChartDotPainter(dynamic value, ThemeData theme, + double percentage, Color? barColor, Gradient? barGradient, + {FlDotPainter? defaultValue, bool selected = false}) { + if (value == null) { + return defaultValue; + } else if (value == false) { + return invisibleDotPainter; + } else if (value == true) { + return getDefaultDotPainter(percentage, barColor, barGradient, + selected: selected); + } + var type = value["_type"]; + var strokeWidth = parseDouble(value["stroke_width"]); + var size = parseDouble(value["size"]); + var color = parseColor(value['color'], theme); + var strokeColor = parseColor(value['stroke_color'], theme, + defaultGetDotStrokeColor(percentage, barColor, barGradient))!; + + if (type == "ChartCirclePoint") { + return FlDotCirclePainter( + color: color ?? getDefaultPointColor(percentage, barColor, barGradient), + radius: parseDouble(value["radius"]), + strokeColor: strokeColor, + strokeWidth: strokeWidth ?? 0.0); + } else if (type == "ChartSquarePoint") { + return FlDotSquarePainter( + color: color ?? getDefaultPointColor(percentage, barColor, barGradient), + size: size ?? 4.0, + strokeColor: strokeColor, + strokeWidth: strokeWidth ?? 1.0); + } else if (type == "ChartCrossPoint") { + return FlDotCrossPainter( + color: + color ?? defaultGetDotStrokeColor(percentage, barColor, barGradient), + size: size ?? 8.0, + width: parseDouble(value["width"], 2.0)!, + ); + } + return defaultValue; +} + +FlDotPainter getDefaultDotPainter( + double percentage, Color? barColor, Gradient? barGradient, + {bool selected = false}) { + return FlDotCirclePainter( + radius: selected ? 8 : 4, + strokeWidth: selected ? 2 : 1, + color: getDefaultPointColor(percentage, barColor, barGradient), + strokeColor: defaultGetDotStrokeColor(percentage, barColor, barGradient), + ); +} + +Color getDefaultPointColor( + double percentage, Color? barColor, Gradient? barGradient) { + if (barGradient != null && barGradient is LinearGradient) { + return lerpGradient( + barGradient.colors, barGradient.getSafeColorStops(), percentage / 100); + } + return barGradient?.colors.first ?? barColor ?? Colors.blueGrey; +} + +Color defaultGetDotStrokeColor(double percentage, + [Color? barColor, Gradient? barGradient]) { + Color color = getDefaultPointColor(percentage, barColor, barGradient); + return color.darken(); +} + +AxisTitles parseAxisTitles(Control? control) { + if (control == null) { + return const AxisTitles(sideTitles: SideTitles(showTitles: false)); + } + + control.notifyParent = true; + final labels = control.children("labels"); + for (final label in labels) { + label.notifyParent = true; + } + + return AxisTitles( + axisNameWidget: control.buildWidget("title"), + axisNameSize: control.getDouble("title_size", 16)!, + sideTitles: SideTitles( + showTitles: control.getBool("show_labels", true)!, + reservedSize: control.getDouble("label_size", 22)!, + interval: control.getDouble("label_spacing"), + minIncluded: control.getBool("show_min", true)!, + maxIncluded: control.getBool("show_max", true)!, + getTitlesWidget: labels.isEmpty + ? defaultGetTitle + : (double value, TitleMeta meta) { + final epsilon = meta.appliedInterval * 1e-3; + final label = labels.firstWhereOrNull((l) { + final v = l.getDouble("value"); + return v != null && (v - value).abs() < epsilon; + }); + return label?.buildTextOrWidget("label") ?? + const SizedBox.shrink(); + }, + )); +} + +FLHorizontalAlignment? parseFLHorizontalAlignment(String? value, + [FLHorizontalAlignment? defaultValue]) { + if (value == null) return defaultValue; + return FLHorizontalAlignment.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +String resolveFlTouchEventType(FlTouchEvent event) { + if (event is FlPointerEnterEvent) return "pointerEnter"; + if (event is FlPointerExitEvent) return "pointerExit"; + if (event is FlPointerHoverEvent) return "pointerHover"; + if (event is FlPanCancelEvent) return "panCancel"; + if (event is FlPanDownEvent) return "panDown"; + if (event is FlPanEndEvent) return "panEnd"; + if (event is FlPanStartEvent) return "panStart"; + if (event is FlPanUpdateEvent) return "panUpdate"; + if (event is FlLongPressEnd) return "longPressEnd"; + if (event is FlLongPressMoveUpdate) return "longPressMoveUpdate"; + if (event is FlLongPressStart) return "longPressStart"; + if (event is FlTapCancelEvent) return "tapCancel"; + if (event is FlTapDownEvent) return "tapDown"; + if (event is FlTapUpEvent) return "tapUp"; + return "undefined"; +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/line_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/line_chart.dart new file mode 100644 index 0000000000..437b0f7aee --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/line_chart.dart @@ -0,0 +1,220 @@ +import 'package:equatable/equatable.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'charts.dart'; + +class LineChartEventData extends Equatable { + final String eventType; + final List barSpots; + + const LineChartEventData({required this.eventType, required this.barSpots}); + + factory LineChartEventData.fromDetails( + FlTouchEvent event, LineTouchResponse? response) { + return LineChartEventData( + eventType: resolveFlTouchEventType(event), + barSpots: response != null && response.lineBarSpots != null + ? response.lineBarSpots! + .map((bs) => LineChartEventDataSpot( + barIndex: bs.barIndex, spotIndex: bs.spotIndex)) + .toList() + : []); + } + + Map toMap() => { + 'type': eventType, + 'spots': barSpots.map((spot) => spot.toMap()).toList(), + }; + + @override + List get props => [eventType, barSpots]; +} + +class LineChartEventDataSpot extends Equatable { + final int barIndex; + final int spotIndex; + + const LineChartEventDataSpot( + {required this.barIndex, required this.spotIndex}); + + Map toMap() => { + 'bar_index': barIndex, + 'spot_index': spotIndex, + }; + + @override + List get props => [barIndex, spotIndex]; +} + +LineTooltipItem? parseLineTooltipItem( + Control dataPoint, LineBarSpot spot, BuildContext context) { + if (!dataPoint.getBool("show_tooltip", true)!) return null; + + var tooltip = dataPoint.internals?["tooltip"]; + if (tooltip == null) return null; + + final theme = Theme.of(context); + var style = parseTextStyle(tooltip["text_style"], theme, const TextStyle())!; + if (style.color == null) { + style = style.copyWith( + color: spot.bar.gradient?.colors.first ?? + spot.bar.color ?? + Colors.blueGrey); + } + return LineTooltipItem( + tooltip["text"] ?? dataPoint.getDouble("y", 0)!.toString(), style, + textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!, + textDirection: parseBool(tooltip["rtl"], false)! + ? TextDirection.rtl + : TextDirection.ltr, + children: tooltip["text_spans"] != null + ? parseTextSpans(tooltip["text_spans"], theme, (s, eventName, + [eventData]) { + s.triggerEvent(eventName, eventData); + }) + : null); +} + +LineTouchTooltipData? parseLineTouchTooltipData( + BuildContext context, Control control, + [LineTouchTooltipData? defaultValue]) { + final tooltip = control.get("tooltip"); + if (tooltip == null) return defaultValue; + + final theme = Theme.of(context); + + return LineTouchTooltipData( + getTooltipColor: (LineBarSpot spot) => parseColor( + tooltip["bgcolor"], theme, const Color.fromRGBO(96, 125, 139, 1))!, + tooltipBorderRadius: parseBorderRadius(tooltip["border_radius"]), + tooltipMargin: parseDouble(tooltip["margin"], 16)!, + tooltipPadding: parsePadding(tooltip["padding"], + const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!, + maxContentWidth: parseDouble(tooltip["max_width"], 120)!, + rotateAngle: parseDouble(tooltip["rotation"], 0.0)!, + tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0)!, + tooltipBorder: parseBorderSide(tooltip["border_side"], theme, + defaultValue: BorderSide.none)!, + fitInsideHorizontally: + parseBool(tooltip["fit_inside_horizontally"], false)!, + fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!, + showOnTopOfTheChartBoxArea: + parseBool(tooltip["show_on_top_of_chart_box_area"], false)!, + tooltipHorizontalAlignment: parseFLHorizontalAlignment( + tooltip["horizontal_alignment"], FLHorizontalAlignment.center)!, + getTooltipItems: (List touchedSpots) { + return touchedSpots + .map((LineBarSpot spot) => parseLineTooltipItem( + control + .children("data_series")[spot.barIndex] + .children("points")[spot.spotIndex], + spot, + context)) + .nonNulls + .toList(); + }, + ); +} + +LineChartBarData parseLineChartBarData( + Control parent, + Control chartData, + bool interactiveChart, + BuildContext context, + Map> barSpots) { + final theme = Theme.of(context); + + var aboveLineBgcolor = chartData.getColor("above_line_bgcolor", context); + var aboveLineGradient = chartData.getGradient("above_line_gradient", theme); + var belowLineBgcolor = chartData.getColor("below_line_bgcolor", context); + var belowLineGradient = chartData.getGradient("below_line_gradient", theme); + var dashPattern = chartData.get("dash_pattern"); + var barColor = chartData.getColor("color", context, Colors.cyan)!; + var barGradient = chartData.getGradient("gradient", theme); + var aboveLine = parseFlLine(chartData.get("above_line"), Theme.of(context)); + var belowLine = parseFlLine(chartData.get("below_line"), Theme.of(context)); + var aboveLineCutoffY = chartData.getDouble("above_line_cutoff_y"); + var belowLineCutoffY = chartData.getDouble("below_line_cutoff_y"); + var stepDirection = chartData.getDouble("step_direction"); + + Map spots = { + for (var e in chartData.children("points")) + FlSpot(e.getDouble("x", 0)!, e.getDouble("y", 0)!): e + }; + return LineChartBarData( + preventCurveOverShooting: + chartData.getBool("prevent_curve_over_shooting", false)!, + preventCurveOvershootingThreshold: + chartData.getDouble("prevent_curve_over_shooting_threshold", 10.0)!, + spots: barSpots[chartData.id] ?? [], + curveSmoothness: chartData.getDouble("curve_smoothness", 0.35)!, + show: chartData.visible, + isStepLineChart: stepDirection != null, + lineChartStepData: LineChartStepData(stepDirection: stepDirection ?? 0.5), + showingIndicators: chartData + .children("points") + .asMap() + .entries + .where( + (dp) => !interactiveChart && dp.value.getBool("selected", false)!) + .map((e) => e.key) + .toList(), + isCurved: chartData.getBool("curved", false)!, + isStrokeCapRound: chartData.getBool("rounded_stroke_cap", false)!, + isStrokeJoinRound: chartData.getBool("rounded_stroke_join", false)!, + barWidth: chartData.getDouble("stroke_width", 2.0)!, + dashArray: dashPattern != null + ? (dashPattern as List).map((e) => parseInt(e)).nonNulls.toList() + : null, + shadow: parseBoxShadow(chartData.get("shadow"), Theme.of(context)) ?? + const Shadow(color: Colors.transparent), + dotData: FlDotData( + show: true, + getDotPainter: (spot, percent, barData, index) { + var allDotsPainter = parseChartDotPainter( + chartData.get("point"), theme, percent, barColor, barGradient); + var dotPainter = parseChartDotPainter( + chartData.children("points")[index].get("point"), + theme, + percent, + barColor, + barGradient); + return dotPainter ?? allDotsPainter ?? invisibleDotPainter; + }), + aboveBarData: aboveLineBgcolor != null || + aboveLineGradient != null || + aboveLine != null + ? BarAreaData( + show: true, + color: aboveLineBgcolor, + gradient: aboveLineGradient, + applyCutOffY: aboveLineCutoffY != null, + cutOffY: aboveLineCutoffY ?? 0, + spotsLine: BarAreaSpotsLine( + show: aboveLine != null, + flLineStyle: aboveLine ?? const FlLine(), + checkToShowSpotLine: (spot) => + spots[spot]!.getBool("show_above_line", true)!, + )) + : null, + belowBarData: belowLineBgcolor != null || + belowLineGradient != null || + belowLine != null + ? BarAreaData( + show: true, + color: belowLineBgcolor, + gradient: belowLineGradient, + applyCutOffY: belowLineCutoffY != null, + cutOffY: belowLineCutoffY ?? 0, + spotsLine: BarAreaSpotsLine( + show: belowLine != null, + flLineStyle: belowLine ?? const FlLine(), + checkToShowSpotLine: (spot) => + spots[spot]!.getBool("show_below_line", true)!, + )) + : null, + color: barColor, + gradient: barGradient); +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/pie_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/pie_chart.dart new file mode 100644 index 0000000000..d536127ba8 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/pie_chart.dart @@ -0,0 +1,57 @@ +import 'package:equatable/equatable.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'charts.dart'; + +class PieChartEventData extends Equatable { + final String eventType; + final int? sectionIndex; + final Offset? localPosition; + + const PieChartEventData( + {required this.eventType, + required this.sectionIndex, + this.localPosition}); + + factory PieChartEventData.fromDetails( + FlTouchEvent event, PieTouchResponse? response) { + return PieChartEventData( + eventType: resolveFlTouchEventType(event), + sectionIndex: response?.touchedSection?.touchedSectionIndex, + localPosition: event.localPosition, + ); + } + + Map toMap() => { + 'type': eventType, + 'section_index': sectionIndex, + "local_x": localPosition?.dx, + "local_y": localPosition?.dy + }; + + @override + List get props => [eventType, sectionIndex]; +} + +PieChartSectionData parsePieChartSectionData( + Control section, BuildContext context) { + section.notifyParent = true; + var theme = Theme.of(context); + var title = section.getString("title"); + return PieChartSectionData( + value: section.getDouble("value"), + color: section.getColor("color", context), + radius: section.getDouble("radius"), + showTitle: title != null, + title: title, + gradient: section.getGradient("gradient", theme), + titleStyle: section.getTextStyle("title_style", theme), + borderSide: section.getBorderSide("border_side", theme, + defaultValue: BorderSide.none)!, + titlePositionPercentageOffset: section.getDouble("title_position"), + badgeWidget: section.buildWidget("badge"), + badgePositionPercentageOffset: section.getDouble("badge_position"), + ); +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/radar_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/radar_chart.dart new file mode 100644 index 0000000000..0a769c0205 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/radar_chart.dart @@ -0,0 +1,92 @@ +import 'package:collection/collection.dart'; +import 'package:equatable/equatable.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'charts.dart'; + +RadarShape? parseRadarShape(String? value, [RadarShape? defaultValue]) { + if (value == null) return defaultValue; + return RadarShape.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +class RadarChartEventData extends Equatable { + final String eventType; + final int? dataSetIndex; + final int? entryIndex; + final double? entryValue; + + const RadarChartEventData({ + required this.eventType, + this.dataSetIndex, + this.entryIndex, + this.entryValue, + }); + + factory RadarChartEventData.fromDetails( + FlTouchEvent event, RadarTouchResponse? response) { + final touchedSpot = response?.touchedSpot; + + return RadarChartEventData( + eventType: resolveFlTouchEventType(event), + dataSetIndex: touchedSpot?.touchedDataSetIndex, + entryIndex: touchedSpot?.touchedRadarEntryIndex, + entryValue: touchedSpot?.touchedRadarEntry.value, + ); + } + + Map toMap() => { + 'type': eventType, + 'data_set_index': dataSetIndex, + 'entry_index': entryIndex, + 'entry_value': entryValue, + }; + + @override + List get props => [eventType, dataSetIndex, entryIndex, entryValue]; +} + +RadarDataSet parseRadarDataSet( + Control dataSet, ThemeData theme, BuildContext context) { + dataSet.notifyParent = true; + final fillColor = dataSet.getColor("fill_color", context, Colors.cyan)!; + final fillGradient = dataSet.getGradient("fill_gradient", theme); + final borderColor = dataSet.getColor("border_color", context, Colors.cyan)!; + final borderWidth = dataSet.getDouble("border_width", 2.0)!; + final entryRadius = dataSet.getDouble("entry_radius", 5.0)!; + + final entries = dataSet.children("entries").map((entry) { + entry.notifyParent = true; + return RadarEntry(value: entry.getDouble("value", 0)!); + }).toList(); + + return RadarDataSet( + dataEntries: entries, + fillColor: fillColor, + fillGradient: fillGradient, + borderColor: borderColor, + borderWidth: borderWidth, + entryRadius: entryRadius, + ); +} + +RadarChartTitle parseRadarChartTitle( + Control title, ThemeData theme, double defaultAngle) { + title.notifyParent = true; + final spansValue = title.get("text_spans"); + final spans = spansValue != null + ? parseTextSpans(spansValue, theme, (control, eventName, [eventData]) { + control.triggerEvent(eventName, eventData); + }) + : null; + + return RadarChartTitle( + text: title.getString("text", "")!, + angle: title.getDouble("angle") ?? defaultAngle, + positionPercentageOffset: title.getDouble("position_percentage_offset"), + children: spans, + ); +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/scatter_chart.dart b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/scatter_chart.dart new file mode 100644 index 0000000000..2536045d9f --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/lib/src/utils/scatter_chart.dart @@ -0,0 +1,86 @@ +import 'package:equatable/equatable.dart'; +import 'package:fl_chart/fl_chart.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'charts.dart'; + +class ScatterChartEventData extends Equatable { + final String eventType; + final int? spotIndex; + + const ScatterChartEventData({required this.eventType, this.spotIndex}); + + factory ScatterChartEventData.fromDetails( + FlTouchEvent event, ScatterTouchResponse? response) { + return ScatterChartEventData( + eventType: resolveFlTouchEventType(event), + spotIndex: response?.touchedSpot?.spotIndex); + } + + Map toMap() => {'type': eventType, 'spot_index': spotIndex}; + + @override + List get props => [eventType, spotIndex]; +} + +ScatterTouchTooltipData parseScatterTouchTooltipData( + BuildContext context, Control control, List spots) { + var tooltip = control.get("tooltip") ?? {}; + + final theme = Theme.of(context); + + return ScatterTouchTooltipData( + tooltipBorder: parseBorderSide(tooltip["border_side"], theme, + defaultValue: BorderSide.none)!, + rotateAngle: parseDouble(tooltip["rotation"], 0.0)!, + maxContentWidth: parseDouble(tooltip["max_width"], 120)!, + tooltipPadding: parsePadding(tooltip["padding"], + const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!, + tooltipHorizontalAlignment: parseFLHorizontalAlignment( + tooltip["horizontal_alignment"], FLHorizontalAlignment.center)!, + tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0), + tooltipBorderRadius: parseBorderRadius(tooltip["border_radius"]), + fitInsideHorizontally: + parseBool(tooltip["fit_inside_horizontally"], false)!, + fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!, + getTooltipColor: (ScatterSpot touchedSpot) { + return parseColor( + tooltip["bgcolor"], theme, const Color.fromRGBO(96, 125, 139, 1))!; + }, + getTooltipItems: (ScatterSpot touchedSpot) { + var spotIndex = spots.indexWhere( + (spot) => spot.x == touchedSpot.x && spot.y == touchedSpot.y); + return parseScatterTooltipItem( + control.children("spots")[spotIndex], touchedSpot, context); + }, + ); +} + +ScatterTooltipItem? parseScatterTooltipItem( + Control dataPoint, ScatterSpot spot, BuildContext context) { + if (!dataPoint.getBool("show_tooltip", true)!) return null; + + var tooltip = dataPoint.internals?["tooltip"]; + if (tooltip == null) return null; + + final theme = Theme.of(context); + var style = parseTextStyle(tooltip["text_style"], theme, const TextStyle())!; + if (style.color == null) { + style = style.copyWith(color: spot.dotPainter.mainColor); + } + return ScatterTooltipItem( + tooltip["text"] ?? dataPoint.getDouble("y").toString(), + textStyle: style, + textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!, + textDirection: parseBool(tooltip["rtl"], false)! + ? TextDirection.rtl + : TextDirection.ltr, + bottomMargin: parseDouble(tooltip["bottom_margin"]), + children: tooltip["text_spans"] != null + ? parseTextSpans(tooltip["text_spans"], theme, (s, eventName, + [eventData]) { + s.triggerEvent(eventName, eventData); + }) + : null); +} diff --git a/sdk/python/packages/flet-charts/src/flutter/flet_charts/pubspec.yaml b/sdk/python/packages/flet-charts/src/flutter/flet_charts/pubspec.yaml new file mode 100644 index 0000000000..5a04e97118 --- /dev/null +++ b/sdk/python/packages/flet-charts/src/flutter/flet_charts/pubspec.yaml @@ -0,0 +1,25 @@ +name: flet_charts +description: A Flet extension for creating interactive charts and graphs. +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + + collection: ^1.16.0 + equatable: ^2.0.3 + fl_chart: ^1.2.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-cli/README.md b/sdk/python/packages/flet-cli/README.md index b75cf75d22..9b134294b7 100644 --- a/sdk/python/packages/flet-cli/README.md +++ b/sdk/python/packages/flet-cli/README.md @@ -1,5 +1,8 @@ # Flet CLI +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-cli) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-cli.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-cli.svg) + Flet CLI is a command-line interface tool for Flet, a framework for building interactive multi-platform applications using Python. ## Features @@ -14,4 +17,4 @@ To create a new Flet project: ``` flet create myapp -``` \ No newline at end of file +``` diff --git a/sdk/python/packages/flet-cli/pyproject.toml b/sdk/python/packages/flet-cli/pyproject.toml index a3b6e4643d..4b65881aa8 100644 --- a/sdk/python/packages/flet-cli/pyproject.toml +++ b/sdk/python/packages/flet-cli/pyproject.toml @@ -5,14 +5,16 @@ description = "Flet CLI" authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }] license = "Apache-2.0" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "flet", "watchdog >=4.0.0", "packaging >=25.0", "qrcode >=7.4.2", - "toml >=0.10.2", - "cookiecutter >=2.6.0" + "tomli >= 1.1.0 ; python_version < '3.11'", + "cookiecutter >=2.6.0", + "binaryornot <0.5", + "chardet <6" ] [project.urls] @@ -25,4 +27,4 @@ hook-dirs = "flet_cli.__pyinstaller:get_hook_dirs" [build-system] requires = ["setuptools"] -build-backend = "setuptools.build_meta" \ No newline at end of file +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/__init__.py b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/__init__.py index 1c52aadf4b..8d649a152c 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/__init__.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/__init__.py @@ -2,4 +2,8 @@ def get_hook_dirs(): + """ + Return directories containing PyInstaller hook modules for `flet-cli`. + """ + return [os.path.dirname(__file__)] diff --git a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/hook-flet.py b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/hook-flet.py index 6338d355d4..485003cb86 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/hook-flet.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/hook-flet.py @@ -1,4 +1,4 @@ -import os +from PyInstaller.utils.hooks import collect_data_files import flet_cli.__pyinstaller.config as hook_config from flet_cli.__pyinstaller.utils import get_flet_bin_path @@ -7,5 +7,11 @@ if not bin_path: bin_path = get_flet_bin_path() +datas = [] +datas += collect_data_files("flet.controls.material", includes=["icons.json"]) +datas += collect_data_files( + "flet.controls.cupertino", includes=["cupertino_icons.json"] +) + if bin_path: - datas = [(bin_path, "flet_desktop/app")] + datas.append((bin_path, "flet_desktop/app")) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/macos_utils.py b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/macos_utils.py index f197294379..2a4342cfd3 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/macos_utils.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/macos_utils.py @@ -5,11 +5,22 @@ import tarfile from pathlib import Path -from flet.utils import safe_tar_extractall from PyInstaller.building.icon import normalize_icon_type +from flet.utils import safe_tar_extractall + def unpack_app_bundle(tar_path): + """ + Extract a macOS app bundle archive and remove the source tarball. + + Args: + tar_path: Path to a `*.tar.gz` archive containing `Flet.app`. + + Returns: + Path to extracted `Flet.app`. + """ + bin_dir = str(Path(tar_path).parent) with tarfile.open(tar_path, "r:gz") as tar_arch: @@ -20,6 +31,14 @@ def unpack_app_bundle(tar_path): def update_flet_view_icon(app_path, icon_path): + """ + Replace app icon in a macOS app bundle and update Info.plist metadata. + + Args: + app_path: Path to app bundle directory. + icon_path: Path to source icon file. + """ + print("Updating Flet View icon", app_path, icon_path) icon_file = "AppIcon.icns" @@ -50,6 +69,20 @@ def update_flet_view_version_info( product_version, copyright, ): + """ + Update selected Info.plist metadata fields in a macOS app bundle. + + Args: + app_path: Path to app bundle directory. + bundle_id: Optional bundle identifier override. + product_name: Optional display/bundle name override. + product_version: Optional version string. + copyright: Optional copyright text. + + Returns: + Final app bundle path (may change when app bundle is renamed). + """ + print("Updating Flet View plist", app_path) pl = __load_info_plist(app_path) @@ -75,6 +108,17 @@ def update_flet_view_version_info( def assemble_app_bundle(app_path, tar_path): + """ + Code-sign a macOS app bundle, package it as tar.gz, and remove unpacked bundle. + + Args: + app_path: Path to app bundle directory. + tar_path: Destination tar.gz path. + + Raises: + SystemError: If `codesign` fails. + """ + # sign app bundle print(f"Signing file {app_path}") cmd_args = [ @@ -91,11 +135,12 @@ def assemble_app_bundle(app_path, tar_path): cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - universal_newlines=True, + text=True, ) if p.returncode: raise SystemError( - f"codesign command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}" + f"codesign command ({cmd_args}) failed with " + f"error code {p.returncode}!\noutput: {p.stdout}" ) # pack tar @@ -107,14 +152,30 @@ def assemble_app_bundle(app_path, tar_path): def __load_info_plist(app_path): + """ + Load Info.plist content from a macOS app bundle. + """ + with open(__get_plist_path(app_path), "rb") as fp: return plistlib.load(fp) def __save_info_plist(app_path, pl): + """ + Save Info.plist content to a macOS app bundle. + + Args: + app_path: Path to app bundle directory. + pl: Parsed plist dictionary to persist. + """ + with open(__get_plist_path(app_path), "wb") as fp: plistlib.dump(pl, fp) def __get_plist_path(app_path): + """ + Return path to `Info.plist` inside a macOS app bundle. + """ + return os.path.join(app_path, "Contents", "Info.plist") diff --git a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py index f901f00286..f9087befc8 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/rthooks/pyi_rth_localhost_fletd.py @@ -1,11 +1,16 @@ import logging import os +import sys -import flet - -logger = logging.getLogger(flet.__name__) +logger = logging.getLogger("flet") logger.info("Running PyInstaller runtime hook for Flet...") os.environ["FLET_SERVER_IP"] = "127.0.0.1" + +# On Windows, set AppUserModelID so the taskbar associates the Flet client window +# with the parent executable (a PyInstaller bundle in this case) rather than the cached +# flet.exe. This ensures taskbar pins and shortcuts point to the correct executable. +if sys.platform == "win32" and "FLET_APP_USER_MODEL_ID" not in os.environ: + os.environ["FLET_APP_USER_MODEL_ID"] = os.path.abspath(sys.executable) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/utils.py b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/utils.py index 5359a36e61..bfe25b30b4 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/utils.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/utils.py @@ -4,17 +4,44 @@ from pathlib import Path from flet.utils import copy_tree -from flet_desktop import get_package_bin_dir +from flet_desktop import ensure_client_cached def get_flet_bin_path(): - bin_path = get_package_bin_dir() - if not os.path.exists(bin_path): - return None - return bin_path + """ + Return path to Flet desktop binaries, if available. + + Resolution order: + + 1. FLET_VIEW_PATH environment variable. + 2. Cached / downloaded client from ~/.flet/client/. + + Returns: + Absolute binaries directory path or `None` when not found. + """ + + # 1. Check FLET_VIEW_PATH (developer / custom build mode). + flet_view_path = os.environ.get("FLET_VIEW_PATH") + if flet_view_path and os.path.exists(flet_view_path): + return flet_view_path + + # 2. Fall back to cached / downloaded client. + cache_dir = ensure_client_cached() + if cache_dir and cache_dir.exists(): + return str(cache_dir) + + return None def copy_flet_bin(): + """ + Copy packaged Flet desktop binaries into a temporary directory. + + Returns: + Path to the temporary copied binaries directory, or `None` when source + binaries are unavailable. + """ + bin_path = get_flet_bin_path() if not bin_path: return None diff --git a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/win_utils.py b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/win_utils.py index 054665dc96..0f58b6376d 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/win_utils.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/__pyinstaller/win_utils.py @@ -12,6 +12,14 @@ def update_flet_view_icon(exe_path, icon_path): + """ + Replace icon resources in a Windows executable. + + Args: + exe_path: Path to target executable file. + icon_path: Path to source icon file or executable resource. + """ + print("Updating Flet View icon", exe_path, icon_path) RT_ICON = 3 @@ -26,8 +34,8 @@ def update_flet_view_icon(exe_path, icon_path): hdst = win32api.BeginUpdateResource(exe_path, 0) iconid = 1 - # Each step in the following enumerate() will instantiate an IconFile object, as a result of deferred execution - # of the map() above. + # Each step in the following enumerate() will instantiate an IconFile object, + # as a result of deferred execution of the map() above. i = 101 data = icon.grp_icon_dir() data = data + icon.grp_icondir_entries(iconid) @@ -49,7 +57,23 @@ def update_flet_view_version_info( file_version, company_name, copyright, -): +) -> str: + """ + Update VERSIONINFO resources in a Windows executable. + + Args: + exe_path: Path to target executable file. + product_name: Optional product name value. + file_description: Optional file description value. + product_version: Optional product version string. + file_version: Optional file version string (`n.n.n.n` expected). + company_name: Optional company name value. + copyright: Optional legal copyright value. + + Returns: + Path to a temporary text file containing serialized version info. + """ + print("Updating Flet View version info", exe_path) # load versioninfo from exe diff --git a/sdk/python/packages/flet-cli/src/flet_cli/cli.py b/sdk/python/packages/flet-cli/src/flet_cli/cli.py index 540fec75b0..1a7b3e1a8e 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/cli.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/cli.py @@ -4,11 +4,14 @@ import flet.version import flet_cli.commands.build import flet_cli.commands.create -import flet_cli.commands.doctor # Adding the doctor command +import flet_cli.commands.debug +import flet_cli.commands.devices +import flet_cli.commands.doctor +import flet_cli.commands.emulators import flet_cli.commands.pack import flet_cli.commands.publish import flet_cli.commands.run -from flet.version import update_version +import flet_cli.commands.serve # Source https://stackoverflow.com/a/26379693 @@ -20,12 +23,11 @@ def set_default_subparser( This should be called after setting up the argument parser but before `parse_args()`. - Parameters: - - name (str): The name of the default subparser to use. - - args (list, optional): A list of arguments passed to `parse_args()`. Defaults - to None. - - index (int): Position in `sys.argv` where the default subparser should be - inserted. Defaults to 0. + Args: + name: The name of the default subparser to use. + args: A list of arguments passed to `parse_args()`. + index: Position in `sys.argv` where the default subparser should be + inserted. """ # exit if help or version flags are present @@ -60,29 +62,47 @@ def set_default_subparser( args.insert(index, name) -def main(): - parser = argparse.ArgumentParser() +def get_parser() -> argparse.ArgumentParser: + """Construct and return the CLI argument parser.""" + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter + ) + + # add version flag parser.add_argument( "--version", "-V", action="version", - version=flet.version.version if flet.version.version else update_version(), + version=( + f"Flet: {flet.version.flet_version}\n" + f"Flutter: {flet.version.flutter_version}\n" + f"Pyodide: {flet.version.pyodide_version}" + ), ) sp = parser.add_subparsers(dest="command") + # register subcommands flet_cli.commands.create.Command.register_to(sp, "create") flet_cli.commands.run.Command.register_to(sp, "run") flet_cli.commands.build.Command.register_to(sp, "build") + flet_cli.commands.debug.Command.register_to(sp, "debug") flet_cli.commands.pack.Command.register_to(sp, "pack") flet_cli.commands.publish.Command.register_to(sp, "publish") - flet_cli.commands.doctor.Command.register_to( - sp, "doctor" - ) # Register the doctor command + flet_cli.commands.serve.Command.register_to(sp, "serve") + flet_cli.commands.emulators.Command.register_to(sp, "emulators") + flet_cli.commands.devices.Command.register_to(sp, "devices") + flet_cli.commands.doctor.Command.register_to(sp, "doctor") # set "run" as the default subparser set_default_subparser(parser, name="run", index=1) + return parser + + +def main(): + parser = get_parser() + # print usage/help if called without arguments if len(sys.argv) == 1: parser.print_help(sys.stdout) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/base.py index bfccf24184..95459e88d7 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/base.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/base.py @@ -1,9 +1,53 @@ import argparse -from typing import Any, List, Optional +from typing import Any, Optional from flet_cli.commands.options import Option, verbose_option +class CustomArgumentDefaultsHelpFormatter(argparse.HelpFormatter): + """ + An argparse help formatter that appends default values to help text + selectively. + + Defaults are added only when they are informative and not already + present in the help string. Noisy or redundant defaults (such as + None, empty lists, booleans for flag arguments, or suppressed values) + are omitted. + """ + + def _get_help_string(self, action: argparse.Action) -> str: + """ + Return help text for an argparse action with optional default annotation. + + Args: + action: Parser action whose help text should be formatted. + + Returns: + The action help string, optionally suffixed with + `"(default: %(default)s)"` when the default is meaningful. + """ + + help_text = action.help or "" + default = action.default + + # skip appending a default + if ( + default is None + or default == [] + or isinstance(default, bool) # store_true / store_false flags + or default is argparse.SUPPRESS + or any(token in help_text for token in ("%(default)", "(default:")) + ): + return help_text + + # only add defaults for optionals or for nargs implying optional values + defaulting_nargs = (argparse.OPTIONAL, argparse.ZERO_OR_MORE) + if action.option_strings or action.nargs in defaulting_nargs: + help_text += " (default: %(default)s)" + + return help_text + + class BaseCommand: """A CLI subcommand""" @@ -13,7 +57,7 @@ class BaseCommand: description: Optional[str] = None # A list of pre-defined options which will be loaded on initializing # Rewrite this if you don't want the default ones - arguments: List[Option] = [verbose_option] + arguments: list[Option] = [verbose_option] def __init__(self, parser: argparse.ArgumentParser) -> None: for arg in self.arguments: @@ -25,14 +69,15 @@ def register_to( cls, subparsers: argparse._SubParsersAction, name: Optional[str] = None, - **kwargs: Any + **kwargs: Any, ) -> None: """Register a subcommand to the subparsers, with an optional name of the subcommand. """ help_text = cls.description or cls.__doc__ name = name or cls.name or "" - # Remove the existing subparser as it will raises an error on Python 3.11+ + + # Remove the existing subparser as it will raise an error on Python 3.11+ subparsers._name_parser_map.pop(name, None) subactions = subparsers._get_subactions() subactions[:] = [action for action in subactions if action.dest != name] @@ -40,7 +85,7 @@ def register_to( name, description=help_text, help=help_text, - # formatter_class=PdmFormatter, + formatter_class=CustomArgumentDefaultsHelpFormatter, **kwargs, ) command = cls(parser) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py index d951bde13c..fb45b8e5a4 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build.py @@ -1,617 +1,73 @@ import argparse -import glob -import os -import platform -import re -import shutil -import sys -from pathlib import Path -from typing import Optional, cast -import flet.version -import flet_cli.utils.processes as processes -import yaml -from flet.utils import cleanup_path, copy_tree, is_windows, slugify -from flet.utils.platform_utils import get_bool_env_var -from flet.version import update_version -from flet_cli.commands.base import BaseCommand -from flet_cli.utils.hash_stamp import HashStamp -from flet_cli.utils.merge import merge_dict -from flet_cli.utils.project_dependencies import ( - get_poetry_dependencies, - get_project_dependencies, -) -from flet_cli.utils.pyproject_toml import load_pyproject_toml -from packaging import version -from packaging.requirements import Requirement -from rich.console import Console, Group +from rich.console import Group from rich.live import Live -from rich.panel import Panel -from rich.progress import Progress -from rich.style import Style -from rich.table import Column, Table -from rich.theme import Theme -PYODIDE_ROOT_URL = "https://cdn.jsdelivr.net/pyodide/v0.27.2/full" -DEFAULT_TEMPLATE_URL = "gh:flet-dev/flet-build-template" +from flet_cli.commands.build_base import BaseBuildCommand, console -MINIMAL_FLUTTER_VERSION = version.Version("3.29.3") -no_rich_output = get_bool_env_var("FLET_CLI_NO_RICH_OUTPUT") - -error_style = Style(color="red", bold=True) -warning_style = Style(color="yellow", bold=True) -console = Console( - log_path=False, - theme=Theme({"log.message": "green bold"}), - force_terminal=not no_rich_output, -) -verbose1_style = Style(dim=True, bold=False) -verbose2_style = Style(color="bright_black", bold=False) - - -class Command(BaseCommand): +class Command(BaseBuildCommand): """ - Build an executable app or install bundle. + Build a Flet Python app into a platform-specific executable or + installable bundle. It supports building for desktop (macOS, Linux, Windows), web, + Android (APK/AAB), and iOS (IPA and simulator .app), with a wide range of + customization options for metadata, assets, splash screens, and signing. + + Detailed guide with usage examples: https://flet.dev/docs/publish """ def __init__(self, parser: argparse.ArgumentParser) -> None: super().__init__(parser) - self.env = {} - self.pubspec_path = None - self.rel_out_dir = None - self.assets_path = None - self.package_platform = None - self.config_platform = None - self.target_platform = None - self.flutter_dependencies = {} - self.package_app_path = None - self.options = None - self.template_data = None - self.python_module_filename = None - self.out_dir = None - self.python_module_name = None - self.get_pyproject = None - self.python_app_path = None - self.emojis = {} - self.dart_exe = None - self.verbose = False - self.build_dir = None - self.flutter_dir: Optional[Path] = None - self.flutter_packages_dir = None - self.flutter_packages_temp_dir = None - self.flutter_exe = None - self.skip_flutter_doctor = get_bool_env_var("FLET_CLI_SKIP_FLUTTER_DOCTOR") - self.no_rich_output = no_rich_output - self.current_platform = platform.system() - self.platforms = { - "windows": { - "package_platform": "Windows", - "config_platform": "windows", - "flutter_build_command": "windows", - "status_text": "Windows app", - "outputs": ["build/windows/x64/runner/Release/*"], - "dist": "windows", - "can_be_run_on": ["Windows"], - }, - "macos": { - "package_platform": "Darwin", - "config_platform": "macos", - "flutter_build_command": "macos", - "status_text": "macOS bundle", - "outputs": ["build/macos/Build/Products/Release/{product_name}.app"], - "dist": "macos", - "can_be_run_on": ["Darwin"], - }, - "linux": { - "package_platform": "Linux", - "config_platform": "linux", - "flutter_build_command": "linux", - "status_text": "app for Linux", - "outputs": ["build/linux/{arch}/release/bundle/*"], - "dist": "linux", - "can_be_run_on": ["Linux"], - }, - "web": { - "package_platform": "Pyodide", - "config_platform": "web", - "flutter_build_command": "web", - "status_text": "web app", - "outputs": ["build/web/*"], - "dist": "web", - "can_be_run_on": ["Darwin", "Windows", "Linux"], - }, - "apk": { - "package_platform": "Android", - "config_platform": "android", - "flutter_build_command": "apk", - "status_text": ".apk for Android", - "outputs": ["build/app/outputs/flutter-apk/*"], - "dist": "apk", - "can_be_run_on": ["Darwin", "Windows", "Linux"], - }, - "aab": { - "package_platform": "Android", - "config_platform": "android", - "flutter_build_command": "appbundle", - "status_text": ".aab bundle for Android", - "outputs": ["build/app/outputs/bundle/release/*"], - "dist": "aab", - "can_be_run_on": ["Darwin", "Windows", "Linux"], - }, - "ipa": { - "package_platform": "iOS", - "config_platform": "ios", - "flutter_build_command": "ipa", - "status_text": ".ipa bundle for iOS", - "outputs": ["build/ios/archive/*", "build/ios/ipa/*"], - "dist": "ipa", - "can_be_run_on": ["Darwin"], - }, - } - - self.cross_platform_permissions = { - "location": { - "info_plist": { - "NSLocationWhenInUseUsageDescription": "This app uses location service when in use.", - "NSLocationAlwaysAndWhenInUseUsageDescription": "This app uses location service.", - }, - "macos_entitlements": { - "com.apple.security.personal-information.location": True - }, - "android_permissions": { - "android.permission.ACCESS_FINE_LOCATION": True, - "android.permission.ACCESS_COARSE_LOCATION": True, - "android.permission.ACCESS_BACKGROUND_LOCATION": True, - }, - "android_features": { - "android.hardware.location.network": False, - "android.hardware.location.gps": False, - }, - }, - "camera": { - "info_plist": { - "NSCameraUsageDescription": "This app uses the camera to capture photos and videos." - }, - "macos_entitlements": {"com.apple.security.device.camera": True}, - "android_permissions": {"android.permission.CAMERA": True}, - "android_features": { - "android.hardware.camera": False, - "android.hardware.camera.any": False, - "android.hardware.camera.front": False, - "android.hardware.camera.external": False, - "android.hardware.camera.autofocus": False, - }, - }, - "microphone": { - "info_plist": { - "NSMicrophoneUsageDescription": "This app uses microphone to record sounds.", - }, - "macos_entitlements": {"com.apple.security.device.audio-input": True}, - "android_permissions": { - "android.permission.RECORD_AUDIO": True, - "android.permission.WRITE_EXTERNAL_STORAGE": True, - "android.permission.READ_EXTERNAL_STORAGE": True, - }, - "android_features": {}, - }, - "photo_library": { - "info_plist": { - "NSPhotoLibraryUsageDescription": "This app saves photos and videos to the photo library." - }, - "macos_entitlements": { - "com.apple.security.personal-information.photos-library": True - }, - "android_permissions": { - "android.permission.READ_MEDIA_VISUAL_USER_SELECTED": True - }, - "android_features": {}, - }, - } + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register build-specific CLI arguments. - # create and display build-platform-matrix table - self.platform_matrix_table = Table( - Column("Command", style="cyan", justify="left"), - Column("Platform", style="magenta", justify="center"), - title="Build Platform Matrix", - header_style="bold", - show_lines=True, - ) - for p, info in self.platforms.items(): - self.platform_matrix_table.add_row( - "flet build " + p, - ", ".join(info["can_be_run_on"]).replace("Darwin", "macOS"), - ) + Args: + parser: Argument parser configured by the command runner. + """ - def add_arguments(self, parser: argparse.ArgumentParser) -> None: parser.add_argument( "target_platform", - type=str, - choices=["macos", "linux", "windows", "web", "apk", "aab", "ipa"], - help="the type of a package or target platform to build", - ) - parser.add_argument( - "python_app_path", - type=str, - nargs="?", - default=".", - help="path to a directory with a Python program", - ) - parser.add_argument( - "--arch", - dest="target_arch", - nargs="+", - default=[], - help="package for specific architectures only. Used with Android and macOS builds only.", - ) - parser.add_argument( - "--exclude", - dest="exclude", - nargs="+", - default=[], - help="exclude files and directories from a Python app package", + type=str.lower, + choices=[ + "macos", + "linux", + "windows", + "web", + "apk", + "aab", + "ipa", + "ios-simulator", + ], + help="The target platform or type of package to build", ) parser.add_argument( "-o", "--output", dest="output_dir", - help="where to put resulting executable or bundle (default is /build/)", - required=False, - ) - parser.add_argument( - "--clear-cache", - dest="clear_cache", - action="store_true", - default=None, - help="clear build cache", - ) - parser.add_argument( - "--project", - dest="project_name", - help="project name for executable or bundle", - required=False, - ) - parser.add_argument( - "--description", - dest="description", - help="the description to use for executable or bundle", - required=False, - ) - parser.add_argument( - "--product", - dest="product_name", - help="project display name that is shown in window titles and about app dialogs", - required=False, - ) - parser.add_argument( - "--org", - dest="org_name", - help='org name in reverse domain name notation, e.g. "com.mycompany" - combined with project name and used as an iOS and Android bundle ID', - required=False, - ) - parser.add_argument( - "--bundle-id", - dest="bundle_id", - help='bundle ID for the application, e.g. "com.mycompany.app-name" - used as an iOS, Android, macOS and Linux bundle ID', - required=False, - ) - parser.add_argument( - "--company", - dest="company_name", - help="company name to display in about app dialogs", - required=False, - ) - parser.add_argument( - "--copyright", - dest="copyright", - help="copyright text to display in about app dialogs", - required=False, - ) - parser.add_argument( - "--android-adaptive-icon-background", - dest="android_adaptive_icon_background", - help="the color which will be used to fill out the background of the adaptive icon", - required=False, - ) - parser.add_argument( - "--splash-color", - dest="splash_color", - help="background color of app splash screen on iOS, Android and web", - required=False, - ) - parser.add_argument( - "--splash-dark-color", - dest="splash_dark_color", - help="background color in dark mode of app splash screen on iOS, Android and web", - required=False, - ) - parser.add_argument( - "--no-web-splash", - dest="no_web_splash", - action="store_true", - default=None, - help="disable web app splash screen", - ) - parser.add_argument( - "--no-ios-splash", - dest="no_ios_splash", - action="store_true", - default=None, - help="disable iOS app splash screen", - ) - parser.add_argument( - "--no-android-splash", - dest="no_android_splash", - action="store_true", - default=None, - help="disable Android app splash screen", - ) - parser.add_argument( - "--ios-team-id", - dest="ios_team_id", - type=str, - help="team ID to sign iOS bundle (ipa only)", - required=False, - ) - parser.add_argument( - "--ios-export-method", - dest="ios_export_method", - type=str, - help='export method for iOS app. Default is "debugging"', - required=False, - ) - parser.add_argument( - "--ios-provisioning-profile", - dest="ios_provisioning_profile", - type=str, - help="provisioning profile name or UUID that used to sign and export iOS app", - required=False, - ) - parser.add_argument( - "--ios-signing-certificate", - dest="ios_signing_certificate", - type=str, - help="provide a certificate name, SHA-1 hash, or automatic selector to use for signing iOS app bundle", - required=False, - ) - parser.add_argument( - "--base-url", - dest="base_url", - type=str, - help="base URL for the app (web only)", - ) - parser.add_argument( - "--web-renderer", - dest="web_renderer", - choices=["canvaskit", "html"], - help="renderer to use (web only)", - ) - parser.add_argument( - "--use-color-emoji", - dest="use_color_emoji", - action="store_true", - help="enables color emojis with CanvasKit renderer (web only)", - ) - parser.add_argument( - "--route-url-strategy", - dest="route_url_strategy", - choices=["path", "hash"], - help="URL routing strategy (web only)", - ) - parser.add_argument( - "--pwa-background-color", - dest="pwa_background_color", - help="an initial background color for your web application", - required=False, - ) - parser.add_argument( - "--pwa-theme-color", - dest="pwa_theme_color", - help="default color for your web application's user interface", required=False, + help="Output directory for the final executable/bundle " + "(default: /build/)", ) - parser.add_argument( - "--split-per-abi", - dest="split_per_abi", - action="store_true", - default=None, - help="whether to split the APKs per ABIs.", - ) - parser.add_argument( - "--compile-app", - dest="compile_app", - action="store_true", - default=None, - help="compile app's .py files to .pyc", - ) - parser.add_argument( - "--compile-packages", - dest="compile_packages", - action="store_true", - default=None, - help="compile site packages' .py files to .pyc", - ) - parser.add_argument( - "--cleanup-app", - dest="cleanup_app", - action="store_true", - default=None, - help="remove unnecessary app files upon packaging", - ) - parser.add_argument( - "--cleanup-app-files", - dest="cleanup_app_files", - action="append", - nargs="*", - help="the list of globs to delete extra app files and directories", - ) - parser.add_argument( - "--cleanup-packages", - dest="cleanup_packages", - action="store_true", - default=None, - help="remove unnecessary package files upon packaging", - ) - parser.add_argument( - "--cleanup-package-files", - dest="cleanup_package_files", - action="append", - nargs="*", - help="the list of globs to delete extra package files and directories", - ) - parser.add_argument( - "--flutter-build-args", - dest="flutter_build_args", - action="append", - nargs="*", - help="additional arguments for flutter build command", - ) - parser.add_argument( - "--source-packages", - dest="source_packages", - nargs="+", - default=[], - help="the list of Python packages to install from source distributions", - ) - parser.add_argument( - "--info-plist", - dest="info_plist", - nargs="+", - default=[], - help='the list of "=|True|False" pairs to add to Info.plist for macOS and iOS builds', - ) - parser.add_argument( - "--macos-entitlements", - dest="macos_entitlements", - nargs="+", - default=[], - help='the list of "=|True|False" entitlements for macOS builds', - ) - parser.add_argument( - "--android-features", - dest="android_features", - nargs="+", - default=[], - help='the list of "=True|False" features to add to AndroidManifest.xml', - ) - parser.add_argument( - "--android-permissions", - dest="android_permissions", - nargs="+", - default=[], - help='the list of "=True|False" permissions to add to AndroidManifest.xml', - ) - parser.add_argument( - "--android-meta-data", - dest="android_meta_data", - nargs="+", - default=[], - help='the list of "=" app meta-data entries to add to AndroidManifest.xml', - ) - parser.add_argument( - "--permissions", - dest="permissions", - nargs="+", - default=[], - choices=["location", "camera", "microphone", "photo_library"], - help="the list of cross-platform permissions for iOS, Android and macOS apps", - ) - parser.add_argument( - "--deep-linking-scheme", - dest="deep_linking_scheme", - help='deep linking URL scheme to configure for iOS and Android builds, i.g. "https" or "myapp"', - ) - parser.add_argument( - "--deep-linking-host", - dest="deep_linking_host", - help="deep linking URL host for iOS and Android builds", - ) - parser.add_argument( - "--android-signing-key-store", - dest="android_signing_key_store", - help="path to an upload keystore .jks file for Android apps", - ) - parser.add_argument( - "--android-signing-key-store-password", - dest="android_signing_key_store_password", - help="Android signing store password", - ) - parser.add_argument( - "--android-signing-key-password", - dest="android_signing_key_password", - help="Android signing key password", - ) - parser.add_argument( - "--android-signing-key-alias", - dest="android_signing_key_alias", - default="upload", - help='Android signing key alias. Default is "upload".', - ) - parser.add_argument( - "--build-number", - dest="build_number", - type=int, - help="build number - an identifier used as an internal version number", - ) - parser.add_argument( - "--build-version", - dest="build_version", - help='build version - a "x.y.z" string used as the version number shown to users', - ) - parser.add_argument( - "--module-name", - dest="module_name", - help="python module name with an app entry point", - ) - parser.add_argument( - "--template", - dest="template", - type=str, - help="a directory containing Flutter bootstrap template, or a URL to a git repository template", - ) - parser.add_argument( - "--template-dir", - dest="template_dir", - type=str, - help="relative path to a Flutter bootstrap template in a repository", - ) - parser.add_argument( - "--template-ref", - dest="template_ref", - type=str, - help="the branch, tag or commit ID to checkout after cloning the repository with Flutter bootstrap template", - ) - parser.add_argument( - "--show-platform-matrix", - action="store_true", - default=False, - help="displays the build platform matrix in a table, then exits", - ) - parser.add_argument( - "--no-rich-output", - action="store_true", - default=False, - help="disables rich output and uses plain text instead", - ) - parser.add_argument( - "--skip-flutter-doctor", - action="store_true", - default=False, - help="whether to skip running Flutter doctor in failed builds", - ) + super().add_arguments(parser) def handle(self, options: argparse.Namespace) -> None: - self.options = options + """ + Execute the full build pipeline for the selected target platform. + + Args: + options: Parsed command-line options. + """ + + super().handle(options) + assert self.target_platform self.status = console.status( - f"[bold blue]Initializing {self.options.target_platform} build...", + f"[bold blue]Initializing {self.target_platform} build...", spinner="bouncingBall", ) - self.progress = Progress(transient=True) - self.no_rich_output = self.no_rich_output or self.options.no_rich_output - self.verbose = self.options.verbose with Live(Group(self.status, self.progress), console=console) as self.live: - self.initialize_build() + self.initialize_command() self.validate_target_platform() self.validate_entry_point() self.setup_template_data() @@ -622,1391 +78,65 @@ def handle(self, options: argparse.Namespace) -> None: self.update_flutter_dependencies() self.customize_icons() self.customize_splash_images() - self.flutter_build() + self.run_flutter() self.copy_build_output() self.cleanup( 0, message=( - f"Successfully built your [cyan]{self.platforms[self.options.target_platform]['status_text']}[/cyan]! {self.emojis['success']} " - f"Find it in [cyan]{self.rel_out_dir}[/cyan] directory. {self.emojis['directory']}" + f"Successfully built your [cyan]" + f"{self.platforms[self.target_platform]['status_text']}" + f"[/cyan]! {self.emojis['success']} " + f"Find it in [cyan]{self.rel_out_dir}[/cyan] directory. " + f"{self.emojis['directory']}" + ( - f"\nRun [cyan]python -m http.server --directory {self.rel_out_dir}[/cyan] command to start dev web server with your app. " - if self.options.target_platform == "web" + "\nRun [cyan]flet serve[/cyan] command to " + "start a web server with your app. " + if self.target_platform == "web" else "" ) ), ) - def initialize_build(self): - assert self.options - self.emojis = { - "checkmark": "[green]OK[/]" if self.no_rich_output else "✅", - "loading": "" if self.no_rich_output else "⏳", - "success": "" if self.no_rich_output else "🥳", - "directory": "" if self.no_rich_output else "📁", - } - - self.python_app_path = Path(self.options.python_app_path).resolve() - self.skip_flutter_doctor = ( - self.skip_flutter_doctor or self.options.skip_flutter_doctor - ) - self.package_platform = self.platforms[self.options.target_platform][ - "package_platform" - ] - self.config_platform = self.platforms[self.options.target_platform][ - "config_platform" - ] - - if not ( - os.path.exists(self.python_app_path) or os.path.isdir(self.python_app_path) - ): - self.cleanup( - 1, - f"Path to Flet app does not exist or is not a directory: {self.python_app_path}", - ) - - # get `flutter` and `dart` executables from PATH - self.flutter_exe = self.find_flutter_batch("flutter") - self.dart_exe = self.find_flutter_batch("dart") - - if ( - not self.flutter_exe - or not self.dart_exe - or not self.flutter_version_valid() - ): - self.install_flutter() - - if self.verbose > 0: - console.log("Flutter executable:", self.flutter_exe, style=verbose2_style) - console.log("Dart executable:", self.dart_exe, style=verbose2_style) - - if self.package_platform == "Android": - self.install_jdk() - self.install_android_sdk() - - self.rel_out_dir = self.options.output_dir or os.path.join( - "build", self.platforms[self.options.target_platform]["dist"] - ) - - self.build_dir = self.python_app_path.joinpath("build") - self.flutter_dir = self.build_dir.joinpath("flutter") - self.flutter_packages_dir = self.build_dir.joinpath("flutter-packages") - self.flutter_packages_temp_dir = self.build_dir.joinpath( - "flutter-packages-temp" - ) - self.out_dir = ( - Path(self.options.output_dir).resolve() - if self.options.output_dir - else self.python_app_path.joinpath(self.rel_out_dir) - ) - self.pubspec_path = str(self.flutter_dir.joinpath("pubspec.yaml")) - self.get_pyproject = load_pyproject_toml(self.python_app_path) - - def flutter_version_valid(self): - version_results = self.run( - [ - self.flutter_exe, - "--version", - "--no-version-check", - "--suppress-analytics", - ], - cwd=os.getcwd(), - capture_output=True, - ) - if version_results.returncode == 0 and version_results.stdout: - match = re.search(r"Flutter (\d+\.\d+\.\d+)", version_results.stdout) - if match: - flutter_version = version.parse(match.group(1)) - - # validate installed Flutter version - return ( - flutter_version.major == MINIMAL_FLUTTER_VERSION.major - and flutter_version.minor == MINIMAL_FLUTTER_VERSION.minor - ) - else: - console.log(1, "Failed to validate Flutter version.") - return False - - def install_flutter(self): - self.update_status( - f"[bold blue]Installing Flutter {MINIMAL_FLUTTER_VERSION}..." - ) - from flet_cli.utils.flutter import install_flutter - - flutter_dir = install_flutter( - str(MINIMAL_FLUTTER_VERSION), self.log_stdout, progress=self.progress - ) - ext = ".bat" if platform.system() == "Windows" else "" - self.flutter_exe = os.path.join(flutter_dir, "bin", f"flutter{ext}") - self.dart_exe = os.path.join(flutter_dir, "bin", f"dart{ext}") - path_env = cleanup_path( - cleanup_path(os.environ.get("PATH", ""), "flutter"), "dart" - ) - self.env["PATH"] = os.pathsep.join([os.path.join(flutter_dir, "bin"), path_env]) - - # desktop mode - if self.config_platform in ["macos", "windows", "linux"]: - if self.verbose > 0: - console.log( - "Ensure Flutter has desktop support enabled", - style=verbose1_style, - ) - config_result = self.run( - [ - self.flutter_exe, - "config", - "--no-version-check", - "--suppress-analytics", - f"--enable-{self.config_platform}-desktop", - ], - cwd=os.getcwd(), - capture_output=self.verbose < 1, - ) - if config_result.returncode != 0: - if config_result.stdout: - console.log(config_result.stdout, style=verbose1_style) - if config_result.stderr: - console.log(config_result.stderr, style=error_style) - self.cleanup(config_result.returncode) - - console.log( - f"Flutter {MINIMAL_FLUTTER_VERSION} installed {self.emojis['checkmark']}" - ) - - def install_jdk(self): - from flet_cli.utils.jdk import install_jdk - - self.update_status("[bold blue]Installing JDK...") - jdk_dir = install_jdk(self.log_stdout, progress=self.progress) - self.env["JAVA_HOME"] = jdk_dir - - # config flutter's JDK dir - if self.verbose > 0: - console.log( - "Configuring Flutter's path to JDK", - style=verbose1_style, - ) - config_result = self.run( - [ - self.flutter_exe, - "config", - "--no-version-check", - "--suppress-analytics", - f"--jdk-dir={jdk_dir}", - ], - cwd=os.getcwd(), - capture_output=self.verbose < 1, - ) - if config_result.returncode != 0: - if config_result.stdout: - console.log(config_result.stdout, style=verbose1_style) - if config_result.stderr: - console.log(config_result.stderr, style=error_style) - self.cleanup(config_result.returncode) - - console.log(f"JDK installed {self.emojis['checkmark']}") - - def install_android_sdk(self): - from flet_cli.utils.android_sdk import AndroidSDK - - self.update_status("[bold blue]Installing Android SDK...") - self.env["ANDROID_HOME"] = AndroidSDK( - self.env["JAVA_HOME"], self.log_stdout, progress=self.progress - ).install() - console.log(f"Android SDK installed {self.emojis['checkmark']}") - - def validate_target_platform(self): - assert self.options - if ( - self.current_platform - not in self.platforms[self.options.target_platform]["can_be_run_on"] - or self.options.show_platform_matrix - ): - can_build_message = ( - "can't" - if self.current_platform - not in self.platforms[self.options.target_platform]["can_be_run_on"] - else "can" - ) - # replace "Darwin" with "macOS" for user-friendliness - self.current_platform = ( - "macOS" if self.current_platform == "Darwin" else self.current_platform - ) - # highlight the current platform in the build matrix table - self.platform_matrix_table.rows[ - list(self.platforms.keys()).index(self.options.target_platform) - ].style = "bold red1" - console.log(self.platform_matrix_table) - - message = f"You {can_build_message} build [cyan]{self.options.target_platform}[/] on [magenta]{self.current_platform}[/]." - self.cleanup(1, message) - - def validate_entry_point(self): - assert self.options - assert self.python_app_path - assert self.get_pyproject - - self.package_app_path = Path(self.python_app_path) - if self.get_pyproject("tool.flet.app.path"): - self.package_app_path = self.python_app_path.joinpath( - cast(str, self.get_pyproject("tool.flet.app.path")) - ) - - self.python_module_name = Path( - self.options.module_name - or cast(str, self.get_pyproject("tool.flet.app.module")) - or "main" - ).stem - self.python_module_filename = f"{self.python_module_name}.py" - if not self.package_app_path.joinpath(self.python_module_filename).exists(): - self.cleanup( - 1, - f"{self.python_module_filename} not found in the root of Flet app directory. " - f"Use --module-name option to specify an entry point for your Flet app.", - ) - - def setup_template_data(self): - assert self.options - assert self.python_app_path - assert self.get_pyproject - - base_url = ( - ( - self.options.base_url - or cast(str, self.get_pyproject("tool.flet.web.base_url")) - or "/" - ) - .strip("/") - .strip() - ) - project_name_orig = ( - self.options.project_name - or self.get_pyproject("project.name") - or self.get_pyproject("tool.poetry.name") - or self.python_app_path.name - ) - project_name_slug = slugify(cast(str, project_name_orig)) - project_name = project_name_slug.replace("-", "_") - product_name = ( - self.options.product_name - or self.get_pyproject("tool.flet.product") - or project_name_orig - ) - - split_per_abi = ( - self.options.split_per_abi - if self.options.split_per_abi is not None - else ( - self.get_pyproject("tool.flet.android.split_per_abi") - if self.get_pyproject("tool.flet.android.split_per_abi") is not None - else False - ) - ) - - info_plist = {} - macos_entitlements = { - "com.apple.security.app-sandbox": False, - "com.apple.security.cs.allow-jit": True, - "com.apple.security.network.client": True, - "com.apple.security.network.server": True, - "com.apple.security.files.user-selected.read-write": True, - } - android_permissions = {"android.permission.INTERNET": True} - android_features = { - "android.software.leanback": False, - "android.hardware.touchscreen": False, - } - android_meta_data = {"io.flutter.embedding.android.EnableImpeller": "false"} - - # merge values from "--permissions" arg: - for p in ( - self.options.permissions - or self.get_pyproject("tool.flet.permissions") - or [] - ): - if p in self.cross_platform_permissions: - info_plist.update(self.cross_platform_permissions[p]["info_plist"]) - macos_entitlements.update( - self.cross_platform_permissions[p]["macos_entitlements"] - ) - android_permissions.update( - self.cross_platform_permissions[p]["android_permissions"] - ) - android_features.update( - self.cross_platform_permissions[p]["android_features"] - ) - - info_plist = merge_dict( - info_plist, - ( - self.get_pyproject("tool.flet.macos.info") - if self.package_platform == "Darwin" - else self.get_pyproject("tool.flet.ios.info") - ) - or {}, - ) - - # parse --info-plist - for p in self.options.info_plist: - i = p.find("=") - if i > -1: - k = p[:i] - v = p[i + 1 :] - info_plist[k] = True if v == "True" else False if v == "False" else v - else: - self.cleanup(1, f"Invalid Info.plist option: {p}") - - macos_entitlements = merge_dict( - macos_entitlements, - self.get_pyproject("tool.flet.macos.entitlement") or {}, - ) - - # parse --macos-entitlements - for p in self.options.macos_entitlements: - i = p.find("=") - if i > -1: - macos_entitlements[p[:i]] = True if p[i + 1 :] == "True" else False - else: - self.cleanup(1, f"Invalid macOS entitlement option: {p}") - - android_permissions = merge_dict( - android_permissions, - self.get_pyproject("tool.flet.android.permission") or {}, - ) - - # parse --android-permissions - for p in self.options.android_permissions: - i = p.find("=") - if i > -1: - android_permissions[p[:i]] = True if p[i + 1 :] == "True" else False - else: - self.cleanup(1, f"Invalid Android permission option: {p}") - - android_features = merge_dict( - android_features, - self.get_pyproject("tool.flet.android.feature") or {}, - ) - - # parse --android-features - for p in self.options.android_features: - i = p.find("=") - if i > -1: - android_features[p[:i]] = True if p[i + 1 :] == "True" else False - else: - self.cleanup(1, f"Invalid Android feature option: {p}") - - android_meta_data = merge_dict( - android_meta_data, - self.get_pyproject("tool.flet.android.meta_data") or {}, - ) - - # parse --android-meta-data - for p in self.options.android_meta_data: - i = p.find("=") - if i > -1: - android_meta_data[p[:i]] = p[i + 1 :] - else: - self.cleanup(1, f"Invalid Android meta-data option: {p}") - - deep_linking_scheme = ( - self.get_pyproject("tool.flet.ios.deep_linking.scheme") - if self.package_platform == "iOS" - else ( - self.get_pyproject("tool.flet.android.deep_linking.scheme") - if self.package_platform == "Android" - else self.get_pyproject("tool.flet.deep_linking.scheme") - ) - ) - - deep_linking_host = ( - self.get_pyproject("tool.flet.ios.deep_linking.host") - if self.package_platform == "iOS" - else ( - self.get_pyproject("tool.flet.android.deep_linking.host") - if self.package_platform == "Android" - else self.get_pyproject("tool.flet.deep_linking.host") - ) - ) - - if self.options.deep_linking_scheme and self.options.deep_linking_host: - deep_linking_scheme = self.options.deep_linking_scheme - deep_linking_host = self.options.deep_linking_host - - target_arch = ( - self.options.target_arch - or self.get_pyproject(f"tool.flet.{self.config_platform}.target_arch") - or self.get_pyproject("tool.flet.target_arch") - ) - - ios_export_method = ( - self.options.ios_export_method - or self.get_pyproject("tool.flet.ios.export_method") - or "debugging" - ) - - ios_export_method_opts = ( - self.get_pyproject("tool.flet.ios.export_methods").get(ios_export_method) - if self.get_pyproject("tool.flet.ios.export_methods") - else {} - ) or {} - - ios_provisioning_profile = ( - self.options.ios_provisioning_profile - or self.get_pyproject("tool.flet.ios.provisioning_profile") - or ios_export_method_opts.get("provisioning_profile") - ) - - ios_signing_certificate = ( - self.options.ios_signing_certificate - or self.get_pyproject("tool.flet.ios.signing_certificate") - or ios_export_method_opts.get("signing_certificate") - ) - - ios_export_options = ( - self.get_pyproject("tool.flet.ios.export_options") - or ios_export_method_opts.get("export_options") - or {} - ) - - ios_team_id = ( - self.options.ios_team_id - or self.get_pyproject("tool.flet.ios.team_id") - or ios_export_method_opts.get("team_id") - ) - - if self.options.target_platform in ["ipa"] and not ios_provisioning_profile: - console.print( - Panel( - "This build will generate an .xcarchive (Xcode Archive). To produce an .ipa (iOS App Package), please specify a Provisioning Profile.", - style=warning_style, - ) - ) - - assert self.flutter_dir - self.template_data = { - "out_dir": self.flutter_dir.name, - "sep": os.sep, - "python_module_name": self.python_module_name, - "route_url_strategy": ( - self.options.route_url_strategy - or self.get_pyproject("tool.flet.web.route_url_strategy") - or "path" - ), - "web_renderer": ( - self.options.web_renderer - or self.get_pyproject("tool.flet.web.renderer") - or "canvaskit" - ), - "use_color_emoji": ( - "true" - if self.options.use_color_emoji - or self.get_pyproject("tool.flet.web.use_color_emoji") - else "false" - ), - "pwa_background_color": ( - self.options.pwa_background_color - or self.get_pyproject("tool.flet.web.pwa_background_color") - ), - "pwa_theme_color": ( - self.options.pwa_theme_color - or self.get_pyproject("tool.flet.web.pwa_theme_color") - ), - "base_url": f"/{base_url}/" if base_url else "/", - "split_per_abi": split_per_abi, - "project_name": project_name, - "project_name_slug": project_name_slug, - "product_name": product_name, - "description": ( - self.options.description - or self.get_pyproject("project.description") - or self.get_pyproject("tool.poetry.description") - ), - "org_name": self.options.org_name - or self.get_pyproject(f"tool.flet.{self.config_platform}.org") - or self.get_pyproject("tool.flet.org"), - "bundle_id": self.options.bundle_id - or self.get_pyproject(f"tool.flet.{self.config_platform}.bundle_id") - or self.get_pyproject("tool.flet.bundle_id"), - "company_name": ( - self.options.company_name or self.get_pyproject("tool.flet.company") - ), - "copyright": self.options.copyright - or self.get_pyproject("tool.flet.copyright"), - "ios_export_method": ios_export_method, - "ios_provisioning_profile": ios_provisioning_profile, - "ios_signing_certificate": ios_signing_certificate, - "ios_export_options": ios_export_options, - "ios_team_id": ios_team_id, - "options": { - "package_platform": self.package_platform, - "config_platform": self.config_platform, - "target_arch": ( - target_arch - if isinstance(target_arch, list) - else [target_arch] - if isinstance(target_arch, str) - else [] - ), - "info_plist": info_plist, - "macos_entitlements": macos_entitlements, - "android_permissions": android_permissions, - "android_features": android_features, - "android_meta_data": android_meta_data, - "deep_linking": { - "scheme": deep_linking_scheme, - "host": deep_linking_host, - }, - "android_signing": self.options.android_signing_key_store is not None, - }, - "flutter": {"dependencies": list(self.flutter_dependencies.keys())}, - "pyproject": self.get_pyproject(), - } - - def create_flutter_project(self, second_pass=False): - assert self.options - assert self.get_pyproject - assert self.flutter_dir - assert self.template_data - assert self.build_dir - assert self.pubspec_path - - hash = HashStamp( - self.build_dir / ".hash" / f"template-{'2' if second_pass else '1'}" - ) - - template_url = ( - self.options.template - or self.get_pyproject("tool.flet.template.url") - or DEFAULT_TEMPLATE_URL - ) - hash.update(template_url) - - template_ref = self.options.template_ref or self.get_pyproject( - "tool.flet.template.ref" - ) - if not template_ref: - template_ref = ( - version.Version(flet.version.version).base_version - if flet.version.version - else update_version() - ) - hash.update(template_ref) - - template_dir = self.options.template_dir or self.get_pyproject( - "tool.flet.template.dir" - ) - hash.update(template_dir) - hash.update(self.template_data) - - hash_changed = hash.has_changed() - - if hash_changed: - # if options.clear_cache is set, delete any existing Flutter bootstrap project directory - if ( - self.options.clear_cache - and self.flutter_dir.exists() - and not second_pass - ): - if self.verbose > 1: - console.log(f"Deleting {self.flutter_dir}", style=verbose2_style) - shutil.rmtree(self.flutter_dir, ignore_errors=True) - - # create a new Flutter bootstrap project directory, if non-existent - if not second_pass: - self.flutter_dir.mkdir(parents=True, exist_ok=True) - self.update_status( - f'[bold blue]Creating Flutter bootstrap project from {template_url} with ref "{template_ref}"...' - ) - - try: - from cookiecutter.main import cookiecutter - - cookiecutter( - template=template_url, - checkout=template_ref, - directory=template_dir, - output_dir=str(self.flutter_dir.parent), - no_input=True, - overwrite_if_exists=True, - extra_context={ - k: v for k, v in self.template_data.items() if v is not None - }, - ) - except Exception as e: - shutil.rmtree(self.flutter_dir) - self.cleanup(1, f"{e}") - - pyproject_pubspec = self.get_pyproject("tool.flet.flutter.pubspec") - - if pyproject_pubspec: - pubspec = self.load_yaml(self.pubspec_path) - pubspec = merge_dict(pubspec, pyproject_pubspec) - self.save_yaml(self.pubspec_path, pubspec) - - # make backup of pubspec.yaml - shutil.copyfile(self.pubspec_path, f"{self.pubspec_path}.orig") - - if not second_pass: - console.log( - f'Created Flutter bootstrap project from {template_url} with ref "{template_ref}" {self.emojis["checkmark"]}' - ) - - hash.commit() - - return hash_changed - - def register_flutter_extensions(self): - assert self.flutter_packages_dir - assert self.flutter_packages_temp_dir - assert isinstance(self.flutter_dependencies, dict) - assert self.template_data - assert self.build_dir - - if self.flutter_packages_temp_dir.exists(): - # copy packages from temp to permanent location - if self.flutter_packages_dir.exists(): - shutil.rmtree(self.flutter_packages_dir, ignore_errors=True) - shutil.move(self.flutter_packages_temp_dir, self.flutter_packages_dir) - - if self.flutter_packages_dir.exists(): - self.update_status("[bold blue]Registering Flutter user extensions...") - - for fp in os.listdir(self.flutter_packages_dir): - if (self.flutter_packages_dir / fp / "pubspec.yaml").exists(): - ext_dir = str(self.flutter_packages_dir / fp) - if self.verbose > 0: - console.log(f"Found Flutter extension at {ext_dir}") - self.flutter_dependencies[fp] = {"path": ext_dir} - - self.template_data["flutter"]["dependencies"] = list( - self.flutter_dependencies.keys() - ) - - console.log( - f"Registered Flutter user extensions {self.emojis['checkmark']}" - ) - - def update_flutter_dependencies(self): - assert self.pubspec_path - assert self.template_data - assert self.get_pyproject - assert self.build_dir - assert isinstance(self.flutter_dependencies, dict) - - pubspec = self.load_yaml(self.pubspec_path) - - # merge dependencies to a dest pubspec.yaml - for k, v in self.flutter_dependencies.items(): - pubspec["dependencies"][k] = v - - # make sure project_name is not named as any of the dependencies - for dep in pubspec["dependencies"].keys(): - if dep == self.template_data["project_name"]: - self.cleanup( - 1, - f"Project name cannot have the same name as one of its dependencies: {dep}. " - f"Use --project option to specify a different project name.", - ) - - self.save_yaml(self.pubspec_path, pubspec) - - def customize_icons(self): - assert self.package_app_path - assert self.flutter_dir - assert self.options - assert self.get_pyproject - assert self.pubspec_path - assert self.build_dir - - hash = HashStamp(self.build_dir / ".hash" / "icons") - - pubspec_origin_path = f"{self.pubspec_path}.orig" - pubspec = self.load_yaml(pubspec_origin_path) - - copy_ops = [] - self.assets_path = self.package_app_path.joinpath("assets") - if self.assets_path.exists(): - images_dir = "images" - images_path = self.flutter_dir.joinpath(images_dir) - images_path.mkdir(exist_ok=True) - - # copy icons - default_icon = self.find_platform_image( - self.assets_path, images_path, "icon", copy_ops, hash - ) - ios_icon = self.find_platform_image( - self.assets_path, images_path, "icon_ios", copy_ops, hash - ) - android_icon = self.find_platform_image( - self.assets_path, images_path, "icon_android", copy_ops, hash - ) - web_icon = self.find_platform_image( - self.assets_path, images_path, "icon_web", copy_ops, hash - ) - windows_icon = self.find_platform_image( - self.assets_path, images_path, "icon_windows", copy_ops, hash - ) - macos_icon = self.find_platform_image( - self.assets_path, images_path, "icon_macos", copy_ops, hash - ) - - self.fallback_image( - pubspec, "flutter_launcher_icons.image_path", [default_icon], images_dir - ) - self.fallback_image( - pubspec, - "flutter_launcher_icons.image_path_ios", - [ios_icon, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_launcher_icons.image_path_android", - [android_icon, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_launcher_icons.adaptive_icon_foreground", - [android_icon, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_launcher_icons.web.image_path", - [web_icon, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_launcher_icons.windows.image_path", - [windows_icon, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_launcher_icons.macos.image_path", - [macos_icon, default_icon], - images_dir, - ) - - adaptive_icon_background = ( - self.options.android_adaptive_icon_background - or self.get_pyproject("tool.flet.android.adaptive_icon_background") - ) - if adaptive_icon_background: - pubspec["flutter_launcher_icons"]["adaptive_icon_background"] = ( - adaptive_icon_background - ) - - # check if pubspec changed - hash.update(Path(pubspec_origin_path).stat().st_mtime) - hash.update(pubspec["flutter_launcher_icons"]) - - # save pubspec.yaml - if hash.has_changed(): - if copy_ops: - self.update_status("[bold blue]Customizing app icons...") - for op in copy_ops: - if self.verbose > 0: - console.log( - f"Copying image {op[0]} to {op[1]}", style=verbose1_style - ) - shutil.copy(op[0], op[1]) - console.log(f"Customized app icons {self.emojis['checkmark']}") - - updated_pubspec = self.load_yaml(self.pubspec_path) - updated_pubspec["flutter_launcher_icons"] = pubspec[ - "flutter_launcher_icons" - ] - self.save_yaml(self.pubspec_path, updated_pubspec) - - self.update_status("[bold blue]Generating app icons...") - - # icons - icons_result = self.run( - [ - self.dart_exe, - "run", - "--suppress-analytics", - "flutter_launcher_icons", - ], - cwd=str(self.flutter_dir), - capture_output=self.verbose < 1, - ) - if icons_result.returncode != 0: - if icons_result.stdout: - console.log(icons_result.stdout, style=verbose1_style) - if icons_result.stderr: - console.log(icons_result.stderr, style=error_style) - self.cleanup(icons_result.returncode) - console.log(f"Generated app icons {self.emojis['checkmark']}") - - hash.commit() - - def customize_splash_images(self): - assert self.package_app_path - assert self.flutter_dir - assert self.options - assert self.get_pyproject - assert self.pubspec_path - assert self.build_dir - - if self.options.target_platform not in ["web", "ipa", "apk", "aab"]: - return - - hash = HashStamp(self.build_dir / ".hash" / "splashes") - - pubspec_origin_path = f"{self.pubspec_path}.orig" - - pubspec = self.load_yaml(pubspec_origin_path) - - copy_ops = [] - self.assets_path = self.package_app_path.joinpath("assets") - if self.assets_path.exists(): - images_dir = "images" - images_path = self.flutter_dir.joinpath(images_dir) - images_path.mkdir(exist_ok=True) - - # copy icons - default_icon = self.find_platform_image( - self.assets_path, images_path, "icon", copy_ops, hash - ) - - # copy splash images - default_splash = self.find_platform_image( - self.assets_path, images_path, "splash", copy_ops, hash - ) - default_dark_splash = self.find_platform_image( - self.assets_path, images_path, "splash_dark", copy_ops, hash - ) - ios_splash = self.find_platform_image( - self.assets_path, images_path, "splash_ios", copy_ops, hash - ) - ios_dark_splash = self.find_platform_image( - self.assets_path, images_path, "splash_dark_ios", copy_ops, hash - ) - android_splash = self.find_platform_image( - self.assets_path, images_path, "splash_android", copy_ops, hash - ) - android_dark_splash = self.find_platform_image( - self.assets_path, images_path, "splash_dark_android", copy_ops, hash - ) - web_splash = self.find_platform_image( - self.assets_path, images_path, "splash_web", copy_ops, hash - ) - web_dark_splash = self.find_platform_image( - self.assets_path, images_path, "splash_dark_web", copy_ops, hash - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image", - [default_splash, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_dark", - [default_dark_splash, default_splash, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_ios", - [ios_splash, default_splash, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_dark_ios", - [ - ios_dark_splash, - default_dark_splash, - ios_splash, - default_splash, - default_icon, - ], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_android", - [android_splash, default_splash, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.android_12.image", - [android_splash, default_splash, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_dark_android", - [ - android_dark_splash, - default_dark_splash, - android_splash, - default_splash, - default_icon, - ], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.android_12.image_dark", - [ - android_dark_splash, - default_dark_splash, - android_splash, - default_splash, - default_icon, - ], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_web", - [web_splash, default_splash, default_icon], - images_dir, - ) - self.fallback_image( - pubspec, - "flutter_native_splash.image_dark_web", - [ - web_dark_splash, - default_dark_splash, - web_splash, - default_splash, - default_icon, - ], - images_dir, - ) - - # splash colors - splash_color = ( - self.options.splash_color - or self.get_pyproject(f"tool.flet.{self.config_platform}.splash.color") - or self.get_pyproject("tool.flet.splash.color") - ) - if splash_color: - pubspec["flutter_native_splash"]["color"] = splash_color - pubspec["flutter_native_splash"]["android_12"]["color"] = splash_color - - splash_dark_color = ( - self.options.splash_dark_color - or self.get_pyproject(f"tool.flet.{self.config_platform}.splash.dark_color") - or self.get_pyproject("tool.flet.splash.dark_color") - ) - if splash_dark_color: - pubspec["flutter_native_splash"]["color_dark"] = splash_dark_color - pubspec["flutter_native_splash"]["android_12"]["color_dark"] = ( - splash_dark_color - ) - - splash_icon_bgcolor = self.get_pyproject( - f"tool.flet.{self.config_platform}.splash.icon_bgcolor" - ) or self.get_pyproject("tool.flet.splash.icon_bgcolor") - - if splash_icon_bgcolor: - pubspec["flutter_native_splash"]["android_12"]["icon_background_color"] = ( - splash_icon_bgcolor - ) - - splash_icon_dark_bgcolor = self.get_pyproject( - f"tool.flet.{self.config_platform}.splash.icon_dark_bgcolor" - ) or self.get_pyproject("tool.flet.splash.icon_dark_bgcolor") - - if splash_icon_dark_bgcolor: - pubspec["flutter_native_splash"]["android_12"][ - "icon_background_color_dark" - ] = splash_icon_dark_bgcolor - - # enable/disable splashes - pubspec["flutter_native_splash"]["web"] = ( - not self.options.no_web_splash - if self.options.no_web_splash is not None - else ( - self.get_pyproject("tool.flet.splash.web") - if self.get_pyproject("tool.flet.splash.web") is not None - else True - ) - ) - pubspec["flutter_native_splash"]["ios"] = ( - not self.options.no_ios_splash - if self.options.no_ios_splash is not None - else ( - self.get_pyproject("tool.flet.splash.ios") - if self.get_pyproject("tool.flet.splash.ios") is not None - else True - ) - ) - pubspec["flutter_native_splash"]["android"] = ( - not self.options.no_android_splash - if self.options.no_android_splash is not None - else ( - self.get_pyproject("tool.flet.splash.android") - if self.get_pyproject("tool.flet.splash.android") is not None - else True - ) - ) - - # check if pubspec changed - hash.update(Path(pubspec_origin_path).stat().st_mtime) - hash.update(pubspec["flutter_native_splash"]) - - # save pubspec.yaml - if hash.has_changed(): - if copy_ops: - self.update_status("[bold blue]Customizing app splash images...") - for op in copy_ops: - if self.verbose > 0: - console.log( - f"Copying image {op[0]} to {op[1]}", style=verbose1_style - ) - shutil.copy(op[0], op[1]) - console.log(f"Customized app splash images {self.emojis['checkmark']}") - - updated_pubspec = self.load_yaml(self.pubspec_path) - updated_pubspec["flutter_native_splash"] = pubspec["flutter_native_splash"] - self.save_yaml(self.pubspec_path, updated_pubspec) - - # splash screens - self.update_status("[bold blue]Generating splash screens...") - splash_result = self.run( - [ - self.dart_exe, - "run", - "--suppress-analytics", - "flutter_native_splash:create", - ], - cwd=str(self.flutter_dir), - capture_output=self.verbose < 1, - ) - if splash_result.returncode != 0: - if splash_result.stdout: - console.log(splash_result.stdout, style=verbose1_style) - if splash_result.stderr: - console.log(splash_result.stderr, style=error_style) - self.cleanup(splash_result.returncode) - console.log(f"Generated splash screens {self.emojis['checkmark']}") - - hash.commit() - - def fallback_image(self, pubspec, yaml_path: str, images: list, images_dir: str): - d = pubspec - pp = yaml_path.split(".") - for p in pp[:-1]: - d = d[p] - for image in images: - if image: - d[pp[-1]] = f"{images_dir}/{image}" - return - - def package_python_app(self): - assert self.options - assert self.get_pyproject - assert self.python_app_path - assert self.package_app_path - assert self.build_dir - assert self.flutter_dir - assert self.flutter_packages_dir - assert self.flutter_packages_temp_dir - assert self.template_data - - hash = HashStamp(self.build_dir / ".hash" / "package") - - self.update_status("[bold blue]Packaging Python app...") - package_args = [ - self.dart_exe, - "run", - "--suppress-analytics", - "serious_python:main", - "package", - str(self.package_app_path), - "--platform", - self.package_platform, - ] - - if self.template_data["options"]["target_arch"]: - package_args.extend( - ["--arch"] + self.template_data["options"]["target_arch"] - ) - - package_env = {} - - # requirements - requirements_txt = self.python_app_path.joinpath("requirements.txt") - - toml_dependencies = ( - get_poetry_dependencies(self.get_pyproject("tool.poetry.dependencies")) - or get_project_dependencies(self.get_pyproject("project.dependencies")) - or [] - ) - - platform_dependencies = get_project_dependencies( - self.get_pyproject(f"tool.flet.{self.config_platform}.dependencies") - ) - if platform_dependencies: - toml_dependencies.extend(platform_dependencies) - - dev_packages_configured = False - if len(toml_dependencies) > 0: - dev_packages = ( - self.get_pyproject(f"tool.flet.{self.config_platform}.dev_packages") - or self.get_pyproject("tool.flet.dev_packages") - or [] - ) - if len(dev_packages) > 0: - for i in range(0, len(toml_dependencies)): - package_name = Requirement(toml_dependencies[i]).name - if package_name in dev_packages: - dev_path = Path(dev_packages[package_name]) - if not dev_path.is_absolute(): - dev_path = (self.python_app_path / dev_path).resolve() - toml_dependencies[i] = f"{package_name} @ file://{dev_path}" - dev_packages_configured = True - if dev_packages_configured: - toml_dependencies.append("--no-cache-dir") - - for toml_dep in toml_dependencies: - package_args.extend(["-r", toml_dep]) - - elif requirements_txt.exists(): - if self.verbose > 1: - with open(requirements_txt, encoding="utf-8") as f: - reqs_txt_contents = f.read() - console.log( - f"Contents of requirements.txt: {reqs_txt_contents}", - style=verbose2_style, - ) - hash.update(reqs_txt_contents) - package_args.extend(["-r", "-r", "-r", str(requirements_txt)]) - else: - flet_version = ( - flet.version.version if flet.version.version else update_version() - ) - package_args.extend(["-r", f"flet=={flet_version}"]) - - # site-packages variable - if self.package_platform != "Pyodide": - package_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( - self.build_dir / "site-packages" - ) - - # flutter-packages variable - if self.flutter_packages_temp_dir.exists(): - shutil.rmtree(self.flutter_packages_temp_dir) - - package_env["SERIOUS_PYTHON_FLUTTER_PACKAGES"] = str( - self.flutter_packages_temp_dir - ) - - # exclude - exclude_list = ["build"] - - app_exclude = ( - self.options.exclude - or self.get_pyproject(f"tool.flet.{self.config_platform}.app.exclude") - or self.get_pyproject("tool.flet.app.exclude") - ) - if app_exclude: - exclude_list.extend(app_exclude) - - if self.options.target_platform == "web": - exclude_list.append("assets") - package_args.extend(["--exclude", ",".join(exclude_list)]) - - # source-packages - source_packages = ( - self.options.source_packages - or self.get_pyproject(f"tool.flet.{self.config_platform}.source_packages") - or self.get_pyproject("tool.flet.source_packages") - ) - if source_packages: - package_env["SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS"] = ",".join( - source_packages - ) - - if self.get_bool_setting(self.options.compile_app, "compile.app", False): - package_args.append("--compile-app") - - if self.get_bool_setting( - self.options.compile_packages, "compile.packages", False - ): - package_args.append("--compile-packages") - - cleanup_app = self.get_bool_setting( - self.options.cleanup_app, "cleanup.app", False - ) - cleanup_packages = self.get_bool_setting( - self.options.cleanup_packages, "cleanup.packages", True - ) - - # TODO: should be depreacted - if self.get_bool_setting(None, "compile.cleanup", False): - cleanup_app = cleanup_packages = True - - if cleanup_app_files := ( - self.options.cleanup_app_files - or self.get_pyproject(f"tool.flet.{self.config_platform}.cleanup.app_files") - or self.get_pyproject("tool.flet.cleanup.app_files") - ): - package_args.extend(["--cleanup-app-files", ",".join(cleanup_app_files)]) - cleanup_app = True - - if cleanup_package_files := ( - self.options.cleanup_package_files - or self.get_pyproject( - f"tool.flet.{self.config_platform}.cleanup.package_files" - ) - or self.get_pyproject("tool.flet.cleanup.package_files") - ): - package_args.extend( - ["--cleanup-package-files", ",".join(cleanup_package_files)] - ) - cleanup_packages = True - - if cleanup_app: - package_args.append("--cleanup-app") - - if cleanup_packages: - package_args.append("--cleanup-packages") - - if self.verbose > 1: - package_args.append("--verbose") - - # check if site-packages installation could be skipped - for arg in package_args: - hash.update(arg) - - if not dev_packages_configured: - if not hash.has_changed(): - package_args.append("--skip-site-packages") - else: - if self.flutter_packages_dir.exists(): - shutil.rmtree(self.flutter_packages_dir, ignore_errors=True) - - package_result = self.run( - package_args, - cwd=str(self.flutter_dir), - env=package_env, - capture_output=self.verbose < 1, - ) - - if package_result.returncode != 0: - if package_result.stdout: - console.log(package_result.stdout, style=verbose1_style) - if package_result.stderr: - console.log(package_result.stderr, style=error_style) - self.cleanup(package_result.returncode) + def add_flutter_command_args(self, args: list[str]): + """ + Append `flutter build` arguments derived from CLI options and project config. - hash.commit() - - # make sure app/app.zip exists - app_zip_path = self.flutter_dir.joinpath("app", "app.zip") - if not os.path.exists(app_zip_path): - self.cleanup(1, "Flet app package app/app.zip was not created.") - - console.log(f"Packaged Python app {self.emojis['checkmark']}") - - def get_bool_setting(self, cli_option, pyproj_setting, default_value): - assert self.get_pyproject - return ( - cli_option - if cli_option is not None - else ( - self.get_pyproject(f"tool.flet.{self.config_platform}.{pyproj_setting}") - if self.get_pyproject( - f"tool.flet.{self.config_platform}.{pyproj_setting}" - ) - is not None - else ( - self.get_pyproject(f"tool.flet.{pyproj_setting}") - if self.get_pyproject(f"tool.flet.{pyproj_setting}") is not None - else default_value - ) - ) - ) + Args: + args: Mutable command argument list to extend. + """ - def flutter_build(self): assert self.options assert self.build_dir assert self.get_pyproject assert self.template_data + assert self.target_platform - self.update_status( - f"[bold blue]Building [cyan]{self.platforms[self.options.target_platform]['status_text']}[/cyan]..." - ) - # flutter build - build_args = [ - self.flutter_exe, - "build", - self.platforms[self.options.target_platform]["flutter_build_command"], - "--no-version-check", - "--suppress-analytics", - ] - - build_env = {} - - # site-packages variable - if self.package_platform != "Pyodide": - build_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( - self.build_dir / "site-packages" - ) - - android_signing_key_store = ( - self.options.android_signing_key_store - or self.get_pyproject("tool.flet.android.signing.key_store") - ) - if android_signing_key_store: - build_env["FLET_ANDROID_SIGNING_KEY_STORE"] = android_signing_key_store - - key_store_password = ( - self.options.android_signing_key_store_password - or os.getenv("FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD") - ) - key_password = self.options.android_signing_key_password or os.getenv( - "FLET_ANDROID_SIGNING_KEY_PASSWORD" - ) - if key_store_password or key_password: - build_env["FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD"] = ( - key_store_password if key_store_password else key_password - ) - build_env["FLET_ANDROID_SIGNING_KEY_PASSWORD"] = ( - key_password if key_password else key_store_password - ) - - android_signing_key_alias = ( - self.options.android_signing_key_alias - or self.get_pyproject("tool.flet.android.signing.key_alias") + args.extend( + ["build", self.platforms[self.target_platform]["flutter_build_command"]] ) - if android_signing_key_alias: - build_env["FLET_ANDROID_SIGNING_KEY_ALIAS"] = android_signing_key_alias - if ( - self.options.target_platform in "apk" - and self.template_data["split_per_abi"] - ): - build_args.append("--split-per-abi") + if self.target_platform in "apk" and self.template_data["split_per_abi"]: + args.append("--split-per-abi") - if self.options.target_platform in ["ipa"]: + if self.target_platform in ["ipa"]: if self.template_data["ios_provisioning_profile"]: - build_args.extend( + args.extend( [ "--export-options-plist", "ios/exportOptions.plist", ] ) else: - build_args.append("--no-codesign") + args.append("--no-codesign") + elif self.target_platform == "ios-simulator": + args.append("--simulator") build_number = self.options.build_number or self.get_pyproject( "tool.flet.build_number" ) if build_number: - build_args.extend(["--build-number", str(build_number)]) + args.extend(["--build-number", str(build_number)]) build_version = ( self.options.build_version @@ -2014,190 +144,31 @@ def flutter_build(self): or self.get_pyproject("tool.poetry.version") ) if build_version: - build_args.extend(["--build-name", build_version]) - - for arg in self.get_pyproject("tool.flet.flutter.build_args") or []: - build_args.append(arg) - - if self.options.flutter_build_args: - for flutter_build_arg_arr in self.options.flutter_build_args: - build_args.extend(flutter_build_arg_arr) + args.extend(["--build-name", build_version]) - if self.verbose > 1: - build_args.append("--verbose") - - build_result = self.run( - build_args, - cwd=str(self.flutter_dir), - env=build_env, - capture_output=self.verbose < 1, - ) - - if ( - build_result.returncode != 0 - or "Encountered error while creating the IPA" in str(build_result.stderr) + for arg in ( + self.get_pyproject(f"tool.flet.{self.config_platform}.flutter.build_args") + or self.get_pyproject("tool.flet.flutter.build_args") + or [] ): - if build_result.stdout: - console.log(build_result.stdout, style=verbose1_style) - if build_result.stderr: - console.log(build_result.stderr, style=error_style) - self.cleanup(build_result.returncode if build_result.returncode else 1) - console.log( - f"Built [cyan]{self.platforms[self.options.target_platform]['status_text']}[/cyan] {self.emojis['checkmark']}", - ) + args.append(arg) - def copy_build_output(self): - assert self.template_data - assert self.options - assert self.flutter_dir - assert self.out_dir - assert self.assets_path + def run_flutter(self): + """ + Run Flutter build command and log completion status. + """ + + assert self.platforms + assert self.target_platform self.update_status( - f"[bold blue]Copying build to [cyan]{self.rel_out_dir}[/cyan] directory...", + f"[bold blue]Building [cyan]" + f"{self.platforms[self.target_platform]['status_text']}[/cyan]..." ) - arch = platform.machine().lower() - if arch in {"x86_64", "amd64"}: - arch = "x64" - elif arch in {"arm64", "aarch64"}: - arch = "arm64" - - for build_output in self.platforms[self.options.target_platform]["outputs"]: - build_output_dir = ( - str(self.flutter_dir.joinpath(build_output)) - .replace("{arch}", arch) - .replace("{project_name}", self.template_data["project_name"]) - .replace("{product_name}", self.template_data["product_name"]) - ) - - if self.verbose > 0: - console.log( - "Copying build output from: " + build_output_dir, - style=verbose1_style, - ) - - build_output_glob = os.path.basename(build_output_dir) - build_output_dir = os.path.dirname(build_output_dir) - if not os.path.exists(build_output_dir): - continue - - if self.out_dir.exists(): - shutil.rmtree(str(self.out_dir)) - self.out_dir.mkdir(parents=True, exist_ok=True) - - def ignore_build_output(path, files): - if path == build_output_dir and build_output_glob != "*": - return [f for f in os.listdir(path) if f != build_output_glob] - return [] - # copy build result to out_dir - copy_tree(build_output_dir, str(self.out_dir), ignore=ignore_build_output) - - if self.options.target_platform == "web" and self.assets_path.exists(): - # copy `assets` directory contents to the output directory - copy_tree(str(self.assets_path), str(self.out_dir)) + self._run_flutter_command() console.log( - f"Copied build to [cyan]{self.rel_out_dir}[/cyan] directory {self.emojis['checkmark']}" - ) - - def find_platform_image( - self, - src_path: Path, - dest_path: Path, - image_name: str, - copy_ops: list, - hash: HashStamp, - ): - images = glob.glob(str(src_path.joinpath(f"{image_name}.*"))) - if len(images) > 0: - if self.verbose > 0: - console.log( - f'Found "{image_name}" image at {images[0]}', style=verbose1_style - ) - copy_ops.append((images[0], dest_path)) - hash.update(images[0]) - hash.update(Path(images[0]).stat().st_mtime) - return Path(images[0]).name - return None - - def find_flutter_batch(self, exe_filename: str): - batch_path = shutil.which(exe_filename) - if not batch_path: - return None - if is_windows() and batch_path.endswith(".file"): - return batch_path.replace(".file", ".bat") - return batch_path - - def run(self, args, cwd, env: Optional[dict] = None, capture_output=True): - if self.verbose > 0: - console.log(f"Run subprocess: {args}", style=verbose1_style) - - return processes.run( - args, - cwd, - env={**self.env, **env} if env else self.env, - capture_output=capture_output, - log=self.log_stdout, - ) - - def cleanup(self, exit_code: int, message: Optional[str] = None): - if exit_code == 0: - msg = message or f"Success! {self.emojis['success']}" - self.live.update(Panel(msg), refresh=True) - else: - msg = ( - message - if message is not None - else "Error building Flet app - see the log of failed command above." - ) - - # windows has been reported to raise encoding errors when running `flutter doctor` - # so skip running `flutter doctor` if no_rich_output is True and platform is Windows - if not ( - (self.no_rich_output and self.current_platform == "Windows") - or self.skip_flutter_doctor - ): - status = console.status( - "[bold blue]Running Flutter doctor...", - spinner="bouncingBall", - ) - self.live.update( - Group(Panel(msg, style=error_style), status), refresh=True - ) - self.run_flutter_doctor() - self.live.update(Panel(msg, style=error_style), refresh=True) - - sys.exit(exit_code) - - def run_flutter_doctor(self): - flutter_doctor = self.run( - [self.flutter_exe, "doctor", "--no-version-check", "--suppress-analytics"], - cwd=os.getcwd(), - capture_output=True, + f"Built [cyan]{self.platforms[self.target_platform]['status_text']}" + f"[/cyan] {self.emojis['checkmark']}", ) - if flutter_doctor.returncode == 0 and flutter_doctor.stdout: - console.log(flutter_doctor.stdout, style=verbose1_style) - - def update_status(self, status): - if self.no_rich_output: - console.log(status) - else: - self.status.update(status) - - def log_stdout(self, message): - if self.verbose > 0: - console.log( - message, - end="", - style=verbose2_style, - markup=False, - ) - - def load_yaml(self, path): - with open(str(path), encoding="utf-8") as f: - return yaml.safe_load(f) - - def save_yaml(self, path, doc): - with open(str(path), "w", encoding="utf-8") as f: - yaml.dump(doc, f) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py new file mode 100644 index 0000000000..29faa3ab1f --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/build_base.py @@ -0,0 +1,2368 @@ +import argparse +import copy +import glob +import os +import platform +import shutil +from pathlib import Path +from typing import Optional, cast + +import yaml +from packaging.requirements import Requirement +from rich.panel import Panel +from rich.table import Column, Table + +import flet.version +import flet_cli.utils.processes as processes +from flet.utils import copy_tree, slugify +from flet_cli.commands.flutter_base import ( + BaseFlutterCommand, + console, + error_style, + verbose1_style, + verbose2_style, + warning_style, +) +from flet_cli.utils.cli import parse_cli_bool_value +from flet_cli.utils.hash_stamp import HashStamp +from flet_cli.utils.merge import merge_dict +from flet_cli.utils.plist import is_supported_plist_value, parse_cli_plist_value +from flet_cli.utils.project_dependencies import ( + get_poetry_dependencies, + get_project_dependencies, +) +from flet_cli.utils.pyproject_toml import load_pyproject_toml + +DEFAULT_TEMPLATE_URL = ( + "https://github.com/flet-dev/flet/releases/download/" + "v{version}/flet-build-template.zip" +) + + +class BaseBuildCommand(BaseFlutterCommand): + """ + A base build-related CLI command. + """ + + def __init__(self, parser: argparse.ArgumentParser) -> None: + super().__init__(parser) + + self.pubspec_path = None + self.rel_out_dir = None + self.assets_path = None + self.target_platform = None + self.package_platform = None + self.config_platform = None + self.debug_platform = None + self.flutter_dependencies = {} + self.package_app_path = None + self.template_data = None + self.python_module_filename = None + self.out_dir = None + self.python_module_name = None + self.get_pyproject = None + self.python_app_path = None + self.build_dir = None + self.flutter_dir: Optional[Path] = None + self.flutter_packages_dir = None + self.flutter_packages_temp_dir = None + self.platforms = { + "windows": { + "package_platform": "Windows", + "config_platform": "windows", + "flutter_build_command": "windows", + "status_text": "Windows app", + "outputs": ["build/windows/x64/runner/Release/*"], + "dist": "windows", + "can_be_run_on": ["Windows"], + }, + "macos": { + "package_platform": "Darwin", + "config_platform": "macos", + "flutter_build_command": "macos", + "status_text": "macOS bundle", + "outputs": ["build/macos/Build/Products/Release/{artifact_name}.app"], + "dist": "macos", + "can_be_run_on": ["Darwin"], + }, + "linux": { + "package_platform": "Linux", + "config_platform": "linux", + "flutter_build_command": "linux", + "status_text": "app for Linux", + "outputs": ["build/linux/{arch}/release/bundle/*"], + "dist": "linux", + "can_be_run_on": ["Linux"], + }, + "web": { + "package_platform": "Emscripten", + "config_platform": "web", + "flutter_build_command": "web", + "status_text": "web app", + "outputs": ["build/web/*"], + "dist": "web", + "can_be_run_on": ["Darwin", "Windows", "Linux"], + }, + "apk": { + "package_platform": "Android", + "config_platform": "android", + "flutter_build_command": "apk", + "status_text": ".apk for Android", + "outputs": ["build/app/outputs/flutter-apk/*"], + "dist": "apk", + "can_be_run_on": ["Darwin", "Windows", "Linux"], + }, + "aab": { + "package_platform": "Android", + "config_platform": "android", + "flutter_build_command": "appbundle", + "status_text": ".aab bundle for Android", + "outputs": ["build/app/outputs/bundle/release/*"], + "dist": "aab", + "can_be_run_on": ["Darwin", "Windows", "Linux"], + }, + "ipa": { + "package_platform": "iOS", + "config_platform": "ios", + "flutter_build_command": "ipa", + "status_text": ".ipa bundle for iOS", + "outputs": ["build/ios/archive/*", "build/ios/ipa/*"], + "dist": "ipa", + "can_be_run_on": ["Darwin"], + }, + "ios-simulator": { + "package_platform": "iOS", + "config_platform": "ios", + "flutter_build_command": "ios", + "status_text": ".app bundle for iOS Simulator", + "outputs": ["build/ios/iphonesimulator/*"], + "dist": "ios-simulator", + "can_be_run_on": ["Darwin"], + }, + } + + self.cross_platform_permissions = { + "location": { + "ios_info_plist": { + "NSLocationWhenInUseUsageDescription": "This app uses location service when in use.", # noqa: E501 + "NSLocationAlwaysAndWhenInUseUsageDescription": "This app uses location service.", # noqa: E501 + }, + "macos_info_plist": { + "NSLocationUsageDescription": "This app needs access to your location.", # noqa: E501 + }, + "macos_entitlements": { + "com.apple.security.personal-information.location": True + }, + "android_permissions": { + "android.permission.ACCESS_FINE_LOCATION": True, + "android.permission.ACCESS_COARSE_LOCATION": True, + "android.permission.ACCESS_BACKGROUND_LOCATION": True, + }, + "android_features": { + "android.hardware.location.network": False, + "android.hardware.location.gps": False, + }, + }, + "camera": { + "ios_info_plist": { + "NSCameraUsageDescription": "This app uses the camera to capture photos and videos." # noqa: E501 + }, + "macos_info_plist": { + "NSCameraUsageDescription": "This app uses the camera to capture photos and videos." # noqa: E501 + }, + "macos_entitlements": {"com.apple.security.device.camera": True}, + "android_permissions": {"android.permission.CAMERA": True}, + "android_features": { + "android.hardware.camera": False, + "android.hardware.camera.any": False, + "android.hardware.camera.front": False, + "android.hardware.camera.external": False, + "android.hardware.camera.autofocus": False, + }, + }, + "microphone": { + "ios_info_plist": { + "NSMicrophoneUsageDescription": "This app uses microphone to record sounds.", # noqa: E501 + }, + "macos_info_plist": { + "NSMicrophoneUsageDescription": "This app uses microphone to record sounds.", # noqa: E501 + }, + "macos_entitlements": {"com.apple.security.device.audio-input": True}, + "android_permissions": { + "android.permission.RECORD_AUDIO": True, + "android.permission.WRITE_EXTERNAL_STORAGE": True, + "android.permission.READ_EXTERNAL_STORAGE": True, + }, + "android_features": {}, + }, + "photo_library": { + "ios_info_plist": { + "NSPhotoLibraryUsageDescription": "This app saves photos and videos to the photo library." # noqa: E501 + }, + "macos_info_plist": { + "NSPhotoLibraryUsageDescription": "This app saves photos and videos to the photo library." # noqa: E501 + }, + "macos_entitlements": { + "com.apple.security.personal-information.photos-library": True + }, + "android_permissions": { + "android.permission.READ_MEDIA_VISUAL_USER_SELECTED": True + }, + "android_features": {}, + }, + } + + # create and display build-platform-matrix table + self.platform_matrix_table = Table( + Column("Command", style="cyan", justify="left"), + Column("Platform", style="magenta", justify="center"), + title="Build Platform Matrix", + header_style="bold", + show_lines=True, + ) + for p, info in self.platforms.items(): + self.platform_matrix_table.add_row( + "flet build " + p, + ", ".join(info["can_be_run_on"]).replace("Darwin", "macOS"), + ) + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register shared build arguments used by all concrete build commands. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "python_app_path", + type=str, + nargs="?", + default=".", + help="Path to a directory with a Flet Python program", + ) + parser.add_argument( + "--arch", + dest="target_arch", + nargs="+", + default=[], + help="Build for specific CPU architectures " + "(used in macOS and Android builds only). Example: `--arch arm64 x64`", + ) + parser.add_argument( + "--exclude", + dest="exclude", + action="extend", + nargs="+", + default=[], + help="Files and/or directories to exclude from the package" + "; can be used multiple times", + ) + parser.add_argument( + "--clear-cache", + dest="clear_cache", + action="store_true", + default=None, + help="Remove any existing build cache before starting the build process", + ) + parser.add_argument( + "--project", + dest="project_name", + required=False, + help="Project name for bundle IDs and identifiers; used as the default " + "for artifact and product names", + ) + parser.add_argument( + "--artifact", + dest="artifact_name", + required=False, + help="Executable or bundle name on disk", + ) + parser.add_argument( + "--description", + dest="description", + required=False, + help="Short description of the application", + ) + parser.add_argument( + "--product", + dest="product_name", + required=False, + help="Display name shown in app launchers, window titles, " + "and about dialogs.", + ) + parser.add_argument( + "--org", + dest="org_name", + required=False, + help="Organization name in reverse domain name notation, " + "e.g. `com.mycompany`, combined with project name and " + "used in bundle IDs and signing", + ) + parser.add_argument( + "--bundle-id", + dest="bundle_id", + required=False, + help="Bundle ID for the application, e.g. `com.mycompany.app-name`. " + "It is used as an iOS, Android, macOS and Linux bundle ID", + ) + parser.add_argument( + "--company", + dest="company_name", + required=False, + help="Company name to display in about app dialogs", + ) + parser.add_argument( + "--copyright", + dest="copyright", + required=False, + help="Copyright text to display in about app dialogs", + ) + parser.add_argument( + "--android-adaptive-icon-background", + dest="android_adaptive_icon_background", + required=False, + help="The color to be used to fill out the background of " + "Android adaptive icons", + ) + parser.add_argument( + "--splash-color", + dest="splash_color", + required=False, + help="Background color of app splash screen on iOS, Android and web", + ) + parser.add_argument( + "--splash-dark-color", + dest="splash_dark_color", + required=False, + help="Background color in dark mode of app splash screen on " + "iOS, Android and web", + ) + parser.add_argument( + "--no-web-splash", + dest="no_web_splash", + action="store_true", + default=None, + help="Disable splash screen on web platform", + ) + parser.add_argument( + "--no-ios-splash", + dest="no_ios_splash", + action="store_true", + default=None, + help="Disable splash screen on iOS platform", + ) + parser.add_argument( + "--no-android-splash", + dest="no_android_splash", + action="store_true", + default=None, + help="Disable splash screen on Android platform", + ) + parser.add_argument( + "--ios-team-id", + dest="ios_team_id", + type=str, + help="Apple developer team ID for signing iOS app bundle (ipa only)", + required=False, + ) + parser.add_argument( + "--ios-export-method", + dest="ios_export_method", + type=str, + required=False, + help="Export method for iOS app bundle (default: debugging)", + ) + parser.add_argument( + "--ios-provisioning-profile", + dest="ios_provisioning_profile", + type=str, + required=False, + help="Provisioning profile name or UUID that should be used to sign and " + "export iOS app bundle", + ) + parser.add_argument( + "--ios-signing-certificate", + dest="ios_signing_certificate", + type=str, + required=False, + help="Signing certificate name, SHA-1 hash, or automatic selector to use " + "for signing iOS app bundle", + ) + parser.add_argument( + "--base-url", + dest="base_url", + type=str, + help="Base URL from which the app is served (web only)", + ) + parser.add_argument( + "--web-renderer", + dest="web_renderer", + type=str.lower, + choices=["auto", "canvaskit", "skwasm"], + help="Flutter web renderer to use (web only) [env: FLET_WEB_RENDERER=]", + ) + parser.add_argument( + "--route-url-strategy", + dest="route_url_strategy", + type=str.lower, + choices=["path", "hash"], + help="Base URL path to serve the app from. " + "Useful if the app is hosted in a subdirectory (web only) " + "[env: FLET_WEB_ROUTE_URL_STRATEGY=]", + ) + parser.add_argument( + "--pwa-background-color", + dest="pwa_background_color", + required=False, + help="Initial background color for your web app (web only)", + ) + parser.add_argument( + "--pwa-theme-color", + dest="pwa_theme_color", + required=False, + help="Default color for your web app's user interface (web only)", + ) + parser.add_argument( + "--no-wasm", + dest="no_wasm", + action="store_true", + default=False, + help="Disable WASM target for web build (web only)", + ) + parser.add_argument( + "--no-cdn", + dest="no_cdn", + action="store_true", + default=False, + help="Disable loading of CanvasKit, Pyodide and fonts from CDN " + "[env: FLET_WEB_NO_CDN=]", + ) + parser.add_argument( + "--split-per-abi", + dest="split_per_abi", + action="store_true", + default=None, + help="Split the APKs per ABIs (Android only)", + ) + parser.add_argument( + "--compile-app", + dest="compile_app", + action="store_true", + default=None, + help="Pre-compile app's `.py` files to `.pyc`", + ) + parser.add_argument( + "--compile-packages", + dest="compile_packages", + action="store_true", + default=None, + help="Pre-compile site packages' `.py` files to `.pyc`", + ) + parser.add_argument( + "--cleanup-app", + dest="cleanup_app", + action="store_true", + default=None, + help="Remove unnecessary app files upon packaging", + ) + parser.add_argument( + "--cleanup-app-files", + dest="cleanup_app_files", + action="extend", + nargs="+", + help="The list of globs to delete extra app files and directories", + ) + parser.add_argument( + "--cleanup-packages", + dest="cleanup_packages", + action="store_true", + default=None, + help="Remove unnecessary package files upon packaging", + ) + parser.add_argument( + "--cleanup-package-files", + dest="cleanup_package_files", + action="extend", + nargs="+", + help="The list of globs to delete extra package files and directories", + ) + parser.add_argument( + "--flutter-build-args", + dest="flutter_build_args", + action="append", + nargs="*", + help="Additional arguments for flutter build command", + ) + parser.add_argument( + "--source-packages", + dest="source_packages", + nargs="+", + default=[], + help="The list of Python packages to install from source distributions", + ) + parser.add_argument( + "--info-plist", + dest="info_plist", + action="extend", + nargs="+", + default=[], + help="The list of `=` pairs to add to Info.plist. Values can " + "be booleans, strings, numbers, TOML arrays, or TOML inline tables " + "(macos, ipa and ios-simulator only); can be used multiple times", + ) + parser.add_argument( + "--macos-entitlements", + dest="macos_entitlements", + action="extend", + nargs="+", + default=[], + help="The list of `=` entitlements. Values can be booleans, " + "strings, numbers, TOML arrays, or TOML inline tables " + "(macos only); can be used multiple times", + ) + parser.add_argument( + "--android-features", + dest="android_features", + action="extend", + nargs="+", + default=[], + help="The list of `=true|false` features to add to " + "AndroidManifest.xml (android only); can be used multiple times", + ) + parser.add_argument( + "--android-permissions", + dest="android_permissions", + action="extend", + nargs="+", + default=[], + help="The list of `=true|false` permissions to add to " + "AndroidManifest.xml (android only); can be used multiple times", + ) + parser.add_argument( + "--android-meta-data", + dest="android_meta_data", + action="extend", + nargs="+", + default=[], + help="The list of `=` app meta-data entries to add to " + "AndroidManifest.xml (android only); can be used multiple times", + ) + parser.add_argument( + "--permissions", + dest="permissions", + type=str.lower, + nargs="+", + default=[], + choices=["location", "camera", "microphone", "photo_library"], + help="The list of pre-defined cross-platform permissions for iOS, Android " + "and macOS builds", + ) + parser.add_argument( + "--deep-linking-scheme", + dest="deep_linking_scheme", + help="Deep linking URL scheme to configure for iOS and Android builds, " + "i.g. `https` or `myapp`", + ) + parser.add_argument( + "--deep-linking-host", + dest="deep_linking_host", + help="Deep linking URL host for iOS and Android builds", + ) + parser.add_argument( + "--android-signing-key-store", + dest="android_signing_key_store", + help="path to an upload keystore `.jks` file for Android apps " + "[env: FLET_ANDROID_SIGNING_KEY_STORE=]", + ) + parser.add_argument( + "--android-signing-key-store-password", + dest="android_signing_key_store_password", + help="Android signing store password " + "[env: FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD=]", + ) + parser.add_argument( + "--android-signing-key-password", + dest="android_signing_key_password", + help="Android signing key password " + "[env: FLET_ANDROID_SIGNING_KEY_PASSWORD=]", + ) + parser.add_argument( + "--android-signing-key-alias", + dest="android_signing_key_alias", + default=None, + help="Android signing key alias [env: FLET_ANDROID_SIGNING_KEY_ALIAS=]", + ) + parser.add_argument( + "--build-number", + dest="build_number", + type=int, + help="Build number - an identifier used as an internal version number", + ) + parser.add_argument( + "--build-version", + dest="build_version", + help="Build version - a `x.y.z` string used as the version number " + "shown to users", + ) + parser.add_argument( + "--module-name", + dest="module_name", + help="Python module name with an app entry point", + ) + parser.add_argument( + "--template", + dest="template", + type=str, + help="Directory containing Flutter bootstrap template, or a URL " + "to a git repository template", + ) + parser.add_argument( + "--template-dir", + dest="template_dir", + type=str, + help="Relative path to a Flutter bootstrap template in a repository", + ) + parser.add_argument( + "--template-ref", + dest="template_ref", + type=str, + help="The branch, tag or commit ID to checkout after cloning " + "the repository with Flutter bootstrap template", + ) + parser.add_argument( + "--show-platform-matrix", + action="store_true", + default=False, + help="Display the build platform matrix in a table, then exit", + ) + super().add_arguments(parser) + + def handle(self, options: argparse.Namespace) -> None: + """ + Store build command options and resolve requested target platform. + + Args: + options: Parsed command-line options. + """ + + super().handle(options) + if "target_platform" in self.options: + self.target_platform = self.options.target_platform + + def initialize_command(self): + """ + Initialize build paths, target metadata, and shared Flutter prerequisites. + """ + + assert self.options + assert self.target_platform + + self.package_platform = self.platforms[self.target_platform]["package_platform"] + self.config_platform = self.platforms[self.target_platform]["config_platform"] + self.require_android_sdk = self.package_platform == "Android" + + super().initialize_command() + + self.python_app_path = Path(self.options.python_app_path).resolve() + + if not ( + os.path.exists(self.python_app_path) or os.path.isdir(self.python_app_path) + ): + self.cleanup( + 1, + f"Path to Flet app does not exist or is not a directory: " + f"{self.python_app_path}", + ) + + self.rel_out_dir = self.options.output_dir or os.path.join( + "build", self.platforms[self.target_platform]["dist"] + ) + + self.build_dir = self.python_app_path.joinpath("build") + self.flutter_dir = self.build_dir.joinpath("flutter") + self.flutter_packages_dir = self.build_dir.joinpath("flutter-packages") + self.flutter_packages_temp_dir = self.build_dir.joinpath( + "flutter-packages-temp" + ) + self.out_dir = ( + Path(self.options.output_dir).resolve() + if self.options.output_dir + else self.python_app_path.joinpath(self.rel_out_dir) + ) + self.pubspec_path = str(self.flutter_dir.joinpath("pubspec.yaml")) + self.get_pyproject = load_pyproject_toml(self.python_app_path) + + def validate_target_platform(self): + """ + Validate whether current host OS can build the selected target platform. + + Displays build matrix context and exits when target is unsupported or + when matrix display is explicitly requested. + """ + + assert self.options + assert self.target_platform + if ( + self.current_platform + not in self.platforms[self.target_platform]["can_be_run_on"] + or self.options.show_platform_matrix + ): + can_build_message = ( + "can't" + if self.current_platform + not in self.platforms[self.target_platform]["can_be_run_on"] + else "can" + ) + # replace "Darwin" with "macOS" for user-friendliness + self.current_platform = ( + "macOS" if self.current_platform == "Darwin" else self.current_platform + ) + # highlight the current platform in the build matrix table + self.platform_matrix_table.rows[ + list(self.platforms.keys()).index(self.target_platform) + ].style = "bold red1" + console.log(self.platform_matrix_table) + + message = f"You {can_build_message} build " + f"[cyan]{self.target_platform}[/] on " + f"[magenta]{self.current_platform}[/]." + self.cleanup(1, message) + + def validate_entry_point(self): + """ + Resolve app entry-point module and ensure corresponding Python file exists. + """ + + assert self.options + assert self.python_app_path + assert self.get_pyproject + + self.package_app_path = Path(self.python_app_path) + if self.get_pyproject("tool.flet.app.path"): + self.package_app_path = self.python_app_path.joinpath( + cast(str, self.get_pyproject("tool.flet.app.path")) + ) + + self.python_module_name = Path( + self.options.module_name + or cast(str, self.get_pyproject("tool.flet.app.module")) + or "main" + ).stem + self.python_module_filename = f"{self.python_module_name}.py" + if not self.package_app_path.joinpath(self.python_module_filename).exists(): + self.cleanup( + 1, + f"{self.python_module_filename} not found in the root of Flet " + "app directory. Use --module-name option to specify an entry point " + "for your Flet app.", + ) + + def setup_template_data(self): + """ + Build template context by merging CLI options, project config, and defaults. + + The resulting context is stored in `self.template_data` and later used + to render Flutter bootstrap templates. + """ + + assert self.options + assert self.python_app_path + assert self.get_pyproject + + base_url = ( + ( + self.options.base_url + or cast(str, self.get_pyproject("tool.flet.web.base_url")) + or "/" + ) + .strip("/") + .strip() + ) + project_name_raw = ( + self.options.project_name + or self.get_pyproject("project.name") + or self.python_app_path.name + ) + project_name_slug = slugify(cast(str, project_name_raw)) + project_name = project_name_slug.replace("-", "_") + artifact_name = ( + self.options.artifact_name + or self.get_pyproject(f"tool.flet.{self.config_platform}.artifact") + or self.get_pyproject("tool.flet.artifact") + or self.options.project_name + or self.get_pyproject("project.name") + or self.python_app_path.name + ) + product_name = ( + self.options.product_name + or self.get_pyproject("tool.flet.product") + or self.options.project_name + or self.get_pyproject("project.name") + or self.python_app_path.name + ) + + split_per_abi = ( + self.options.split_per_abi + if self.options.split_per_abi is not None + else ( + self.get_pyproject("tool.flet.android.split_per_abi") + if self.get_pyproject("tool.flet.android.split_per_abi") is not None + else False + ) + ) + + info_plist = {} + macos_entitlements = { + "com.apple.security.app-sandbox": False, + "com.apple.security.cs.allow-jit": True, + "com.apple.security.network.client": True, + "com.apple.security.network.server": True, + "com.apple.security.files.user-selected.read-write": True, + } + android_permissions = {"android.permission.INTERNET": True} + android_features = { + "android.software.leanback": False, + "android.hardware.touchscreen": False, + } + android_meta_data = {} + + # merge values from "--permissions" arg: + for p in ( + self.options.permissions + or self.get_pyproject("tool.flet.permissions") + or [] + ): + if p in self.cross_platform_permissions: + permission_config = self.cross_platform_permissions[p] + info_plist.update( + permission_config.get(f"{self.config_platform}_info_plist", {}) + or permission_config.get("info_plist", {}) + ) + macos_entitlements.update( + self.cross_platform_permissions[p]["macos_entitlements"] + ) + android_permissions.update( + self.cross_platform_permissions[p]["android_permissions"] + ) + android_features.update( + self.cross_platform_permissions[p]["android_features"] + ) + + info_plist = merge_dict( + info_plist, + ( + self.get_pyproject("tool.flet.macos.info") + if self.package_platform == "Darwin" + else self.get_pyproject("tool.flet.ios.info") + ) + or {}, + ) + + # parse --info-plist + for p in self.options.info_plist: + i = p.find("=") + if i > -1: + k = p[:i] + v = p[i + 1 :] + info_plist[k] = parse_cli_plist_value(v) + else: + self.cleanup(1, f"Invalid Info.plist option: {p}") + + for key, value in info_plist.items(): + if not is_supported_plist_value(value): + self.cleanup( + 1, + "Unsupported Info.plist value type for " + f"{key}: {type(value).__name__}. Supported types are " + "string, boolean, integer, float, dictionary, and arrays " + "containing those values.", + ) + + macos_entitlements = merge_dict( + macos_entitlements, + self.get_pyproject("tool.flet.macos.entitlement") or {}, + ) + + # parse --macos-entitlements + for p in self.options.macos_entitlements: + i = p.find("=") + if i > -1: + macos_entitlements[p[:i]] = parse_cli_plist_value(p[i + 1 :]) + else: + self.cleanup(1, f"Invalid macOS entitlement option: {p}") + + for key, value in macos_entitlements.items(): + if not is_supported_plist_value(value): + self.cleanup( + 1, + "Unsupported macOS entitlement value type for " + f"{key}: {type(value).__name__}. Supported types are " + "string, boolean, integer, float, dictionary, and arrays " + "containing those values.", + ) + + android_permissions = merge_dict( + android_permissions, + self.get_pyproject("tool.flet.android.permission") or {}, + ) + + # parse --android-permissions + for p in self.options.android_permissions: + i = p.find("=") + if i > -1: + try: + android_permissions[p[:i]] = parse_cli_bool_value(p[i + 1 :]) + except ValueError: + self.cleanup( + 1, + f"Invalid Android permission option value for {p[:i]}: " + f"{p[i + 1 :]}. Expected true or false.", + ) + else: + self.cleanup(1, f"Invalid Android permission option: {p}") + + android_features = merge_dict( + android_features, + self.get_pyproject("tool.flet.android.feature") or {}, + ) + + # parse --android-features + for p in self.options.android_features: + i = p.find("=") + if i > -1: + try: + android_features[p[:i]] = parse_cli_bool_value(p[i + 1 :]) + except ValueError: + self.cleanup( + 1, + f"Invalid Android feature option value for {p[:i]}: " + f"{p[i + 1 :]}. Expected true or false.", + ) + else: + self.cleanup(1, f"Invalid Android feature option: {p}") + + android_meta_data = merge_dict( + android_meta_data, + self.get_pyproject("tool.flet.android.meta_data") or {}, + ) + + # parse --android-meta-data + for p in self.options.android_meta_data: + i = p.find("=") + if i > -1: + android_meta_data[p[:i]] = p[i + 1 :] + else: + self.cleanup(1, f"Invalid Android meta-data option: {p}") + + deep_linking_scheme = ( + self.get_pyproject("tool.flet.ios.deep_linking.scheme") + if self.package_platform == "iOS" + else ( + self.get_pyproject("tool.flet.android.deep_linking.scheme") + if self.package_platform == "Android" + else self.get_pyproject("tool.flet.deep_linking.scheme") + ) + ) + + deep_linking_host = ( + self.get_pyproject("tool.flet.ios.deep_linking.host") + if self.package_platform == "iOS" + else ( + self.get_pyproject("tool.flet.android.deep_linking.host") + if self.package_platform == "Android" + else self.get_pyproject("tool.flet.deep_linking.host") + ) + ) + + if self.options.deep_linking_scheme and self.options.deep_linking_host: + deep_linking_scheme = self.options.deep_linking_scheme + deep_linking_host = self.options.deep_linking_host + + target_arch = ( + self.options.target_arch + or self.get_pyproject(f"tool.flet.{self.config_platform}.target_arch") + or self.get_pyproject("tool.flet.target_arch") + ) + + ios_export_method = ( + self.options.ios_export_method + or self.get_pyproject("tool.flet.ios.export_method") + or "debugging" + ) + + ios_export_method_opts = ( + self.get_pyproject("tool.flet.ios.export_methods").get(ios_export_method) + if self.get_pyproject("tool.flet.ios.export_methods") + else {} + ) or {} + + ios_provisioning_profile = ( + self.options.ios_provisioning_profile + or self.get_pyproject("tool.flet.ios.provisioning_profile") + or ios_export_method_opts.get("provisioning_profile") + ) + + ios_signing_certificate = ( + self.options.ios_signing_certificate + or self.get_pyproject("tool.flet.ios.signing_certificate") + or ios_export_method_opts.get("signing_certificate") + ) + + ios_export_options = ( + self.get_pyproject("tool.flet.ios.export_options") + or ios_export_method_opts.get("export_options") + or {} + ) + + ios_team_id = ( + self.options.ios_team_id + or self.get_pyproject("tool.flet.ios.team_id") + or ios_export_method_opts.get("team_id") + ) + + if ( + self.target_platform in ["ipa"] + and not ios_provisioning_profile + and not self.debug_platform + ): + console.print( + Panel( + "This build will generate an .xcarchive (Xcode Archive). " + "To produce an .ipa (iOS App Package), please specify " + "a Provisioning Profile.", + style=warning_style, + ) + ) + + assert self.flutter_dir + self.template_data = { + "out_dir": self.flutter_dir.name, + "sep": os.sep, + "python_module_name": self.python_module_name, + "route_url_strategy": ( + self.options.route_url_strategy + or self.get_pyproject("tool.flet.web.route_url_strategy") + or "path" + ), + "web_renderer": ( + self.options.web_renderer + or self.get_pyproject("tool.flet.web.renderer") + or "auto" + ), + "pwa_background_color": ( + self.options.pwa_background_color + or self.get_pyproject("tool.flet.web.pwa_background_color") + ), + "pwa_theme_color": ( + self.options.pwa_theme_color + or self.get_pyproject("tool.flet.web.pwa_theme_color") + ), + "no_wasm": ( + self.options.no_wasm + or self.get_pyproject("tool.flet.web.wasm") == False # noqa: E712 + ), + "no_cdn": ( + self.options.no_cdn or self.get_pyproject("tool.flet.web.cdn") == False # noqa: E712 + ), + "base_url": f"/{base_url}/" if base_url else "/", + "split_per_abi": split_per_abi, + "project_name": project_name, + "project_name_slug": project_name_slug, + "artifact_name": artifact_name, + "product_name": product_name, + "description": ( + self.options.description + or self.get_pyproject("project.description") + or self.get_pyproject("tool.poetry.description") + ), + "org_name": self.options.org_name + or self.get_pyproject(f"tool.flet.{self.config_platform}.org") + or self.get_pyproject("tool.flet.org"), + "bundle_id": self.options.bundle_id + or self.get_pyproject(f"tool.flet.{self.config_platform}.bundle_id") + or self.get_pyproject("tool.flet.bundle_id"), + "company_name": ( + self.options.company_name or self.get_pyproject("tool.flet.company") + ), + "copyright": self.options.copyright + or self.get_pyproject("tool.flet.copyright"), + "ios_export_method": ios_export_method, + "ios_provisioning_profile": ios_provisioning_profile, + "ios_signing_certificate": ios_signing_certificate, + "ios_export_options": ios_export_options, + "ios_team_id": ios_team_id, + "options": { + "package_platform": self.package_platform, + "config_platform": self.config_platform, + "target_arch": ( + target_arch + if isinstance(target_arch, list) + else [target_arch] + if isinstance(target_arch, str) + else [] + ), + "info_plist": info_plist, + "macos_entitlements": macos_entitlements, + "android_permissions": android_permissions, + "android_features": android_features, + "android_meta_data": android_meta_data, + "deep_linking": { + "scheme": deep_linking_scheme, + "host": deep_linking_host, + }, + "android_signing": bool( + self.options.android_signing_key_store + or self.get_pyproject("tool.flet.android.signing.key_store") + or os.getenv("FLET_ANDROID_SIGNING_KEY_STORE") + ), + }, + "flutter": {"dependencies": list(self.flutter_dependencies.keys())}, + "pyproject": self.get_pyproject(), + } + + def create_flutter_project(self, second_pass=False): + """ + Render Flutter bootstrap project from template if template inputs changed. + + Args: + second_pass: Whether this render happens after extension registration. + + Returns: + `True` when template output changed and files were regenerated, + otherwise `False`. + """ + + assert self.options + assert self.get_pyproject + assert self.flutter_dir + assert self.template_data + assert self.build_dir + assert self.pubspec_path + + hash = HashStamp( + self.build_dir / ".hash" / f"template-{'2' if second_pass else '1'}" + ) + + template_url = self.options.template or self.get_pyproject( + "tool.flet.template.url" + ) + + template_ref = self.options.template_ref or self.get_pyproject( + "tool.flet.template.ref" + ) + if not template_ref: + template_ref = flet.version.flet_version + + is_local_dev = False + if template_url: + # User-provided template (git repo or local path) — use checkout + checkout = template_ref + else: + # Check for local dev templates first (running from source checkout) + local_tpl = Path(__file__).resolve().parents[5] / "templates" / "build" + if local_tpl.is_dir(): + template_url = str(local_tpl) + checkout = None + is_local_dev = True + else: + template_url = DEFAULT_TEMPLATE_URL.format(version=template_ref) + checkout = None + + hash.update(template_url) + hash.update(template_ref) + + template_dir = self.options.template_dir or self.get_pyproject( + "tool.flet.template.dir" + ) + hash.update(template_dir) + hash.update(self.template_data) + + hash_changed = hash.has_changed() + + if hash_changed: + # if options.clear_cache is set, delete any existing Flutter bootstrap + # project directory + if ( + self.options.clear_cache + and self.flutter_dir.exists() + and not second_pass + ): + if self.verbose > 1: + console.log(f"Deleting {self.flutter_dir}", style=verbose2_style) + shutil.rmtree(self.flutter_dir, ignore_errors=True) + + # create a new Flutter bootstrap project directory, if non-existent + if not second_pass: + self.flutter_dir.mkdir(parents=True, exist_ok=True) + status = f"[bold blue]Creating app shell from {template_url}" + if checkout: + status += f' with ref "{template_ref}"' + status += "..." + self.update_status(status) + + try: + from cookiecutter.main import cookiecutter + + cookiecutter( + template=template_url, + checkout=checkout, + directory=template_dir, + output_dir=str(self.flutter_dir.parent), + no_input=True, + overwrite_if_exists=True, + extra_context={ + k: v for k, v in self.template_data.items() if v is not None + }, + ) + except Exception as e: + shutil.rmtree(self.flutter_dir) + self.cleanup(1, f"{e}") + + # For local development, override flet dependency with path + if is_local_dev: + repo_root = flet.version.find_repo_root(Path(__file__).resolve().parent) + if repo_root: + flet_pkg_path = str(repo_root / "packages" / "flet") + pubspec = self.load_yaml(self.pubspec_path) + pubspec["dependencies"]["flet"] = {"path": flet_pkg_path} + pubspec.setdefault("dependency_overrides", {})["flet"] = { + "path": flet_pkg_path + } + self.save_yaml(self.pubspec_path, pubspec) + + pyproject_pubspec = self.get_pyproject("tool.flet.flutter.pubspec") + + if pyproject_pubspec: + pyproject_pubspec = copy.deepcopy(pyproject_pubspec) + pubspec = self.load_yaml(self.pubspec_path) + # Replace individual dependency entries from pyproject rather + # than deep-merging them — a Dart dependency can only have one + # source, so merging {"path":…} with {"git":…} is invalid. + for section in ( + "dependencies", + "dependency_overrides", + "dev_dependencies", + ): + if section in pyproject_pubspec: + pubspec.setdefault(section, {}).update( + pyproject_pubspec.pop(section) + ) + pubspec = merge_dict(pubspec, pyproject_pubspec) + self.save_yaml(self.pubspec_path, pubspec) + + # make backup of pubspec.yaml + shutil.copyfile(self.pubspec_path, f"{self.pubspec_path}.orig") + + if not second_pass: + console.log(f"Created app shell {self.emojis['checkmark']}") + + hash.commit() + + return hash_changed + + def register_flutter_extensions(self): + """ + Discover local Flutter extension packages and inject them into dependencies. + """ + + assert self.flutter_packages_dir + assert self.flutter_packages_temp_dir + assert isinstance(self.flutter_dependencies, dict) + assert self.template_data + assert self.build_dir + + if self.flutter_packages_temp_dir.exists(): + # copy packages from temp to permanent location + if self.flutter_packages_dir.exists(): + shutil.rmtree(self.flutter_packages_dir, ignore_errors=True) + shutil.move(self.flutter_packages_temp_dir, self.flutter_packages_dir) + + if self.flutter_packages_dir.exists(): + self.update_status("[bold blue]Registering Flutter user extensions...") + + for fp in os.listdir(self.flutter_packages_dir): + if (self.flutter_packages_dir / fp / "pubspec.yaml").exists(): + ext_dir = str(self.flutter_packages_dir / fp) + if self.verbose > 0: + console.log(f"Found Flutter extension at {ext_dir}") + self.flutter_dependencies[fp] = {"path": ext_dir} + + self.template_data["flutter"]["dependencies"] = list( + self.flutter_dependencies.keys() + ) + + console.log( + f"Registered Flutter user extensions {self.emojis['checkmark']}" + ) + + def update_flutter_dependencies(self): + """ + Merge resolved Flutter extension dependencies into `pubspec.yaml`. + """ + + assert self.pubspec_path + assert self.template_data + assert self.get_pyproject + assert self.build_dir + assert isinstance(self.flutter_dependencies, dict) + + pubspec = self.load_yaml(self.pubspec_path) + + # merge dependencies to a dest pubspec.yaml + for k, v in self.flutter_dependencies.items(): + pubspec["dependencies"][k] = v + + # make sure project_name is not named as any of the dependencies + for dep in pubspec["dependencies"]: + if dep == self.template_data["project_name"]: + self.cleanup( + 1, + f"Project name cannot have the same name as one of its " + f"dependencies: {dep}. Use --project option to specify " + "a different project name.", + ) + + self.save_yaml(self.pubspec_path, pubspec) + + def customize_icons(self): + """ + Resolve platform icon assets, patch pubspec icon config, and generate icons. + """ + + assert self.package_app_path + assert self.flutter_dir + assert self.options + assert self.get_pyproject + assert self.pubspec_path + assert self.build_dir + + hash = HashStamp(self.build_dir / ".hash" / "icons") + + pubspec_origin_path = f"{self.pubspec_path}.orig" + pubspec = self.load_yaml(pubspec_origin_path) + + copy_ops = [] + self.assets_path = self.package_app_path.joinpath("assets") + if self.assets_path.exists(): + images_dir = "images" + images_path = self.flutter_dir.joinpath(images_dir) + images_path.mkdir(exist_ok=True) + + # copy icons + default_icon = self.find_platform_image( + self.assets_path, images_path, "icon", copy_ops, hash + ) + ios_icon = self.find_platform_image( + self.assets_path, images_path, "icon_ios", copy_ops, hash + ) + android_icon = self.find_platform_image( + self.assets_path, images_path, "icon_android", copy_ops, hash + ) + web_icon = self.find_platform_image( + self.assets_path, images_path, "icon_web", copy_ops, hash + ) + windows_icon = self.find_platform_image( + self.assets_path, images_path, "icon_windows", copy_ops, hash + ) + macos_icon = self.find_platform_image( + self.assets_path, images_path, "icon_macos", copy_ops, hash + ) + + self.fallback_image( + pubspec, "flutter_launcher_icons.image_path", [default_icon], images_dir + ) + self.fallback_image( + pubspec, + "flutter_launcher_icons.image_path_ios", + [ios_icon, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_launcher_icons.image_path_android", + [android_icon, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_launcher_icons.adaptive_icon_foreground", + [android_icon, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_launcher_icons.web.image_path", + [web_icon, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_launcher_icons.windows.image_path", + [windows_icon, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_launcher_icons.macos.image_path", + [macos_icon, default_icon], + images_dir, + ) + + adaptive_icon_background = ( + self.options.android_adaptive_icon_background + or self.get_pyproject("tool.flet.android.adaptive_icon_background") + ) + if adaptive_icon_background: + pubspec["flutter_launcher_icons"]["adaptive_icon_background"] = ( + adaptive_icon_background + ) + + # check if pubspec changed + hash.update(Path(pubspec_origin_path).stat().st_mtime) + hash.update(pubspec["flutter_launcher_icons"]) + + # save pubspec.yaml + if hash.has_changed(): + if copy_ops: + self.update_status("[bold blue]Customizing app icons...") + for op in copy_ops: + if self.verbose > 0: + console.log( + f"Copying image {op[0]} to {op[1]}", style=verbose1_style + ) + shutil.copy(op[0], op[1]) + console.log(f"Customized app icons {self.emojis['checkmark']}") + + updated_pubspec = self.load_yaml(self.pubspec_path) + updated_pubspec["flutter_launcher_icons"] = pubspec[ + "flutter_launcher_icons" + ] + self.save_yaml(self.pubspec_path, updated_pubspec) + + self.update_status("[bold blue]Generating app icons...") + + # icons + icons_result = self.run( + [ + self.dart_exe, + "run", + "--suppress-analytics", + "flutter_launcher_icons", + ], + cwd=str(self.flutter_dir), + capture_output=self.verbose < 1, + ) + if icons_result.returncode != 0: + if isinstance(icons_result.stdout, str): + console.log(icons_result.stdout, style=verbose1_style) + if isinstance(icons_result.stderr, str): + console.log(icons_result.stderr, style=error_style) + self.cleanup(icons_result.returncode) + console.log(f"Generated app icons {self.emojis['checkmark']}") + + hash.commit() + + def customize_splash_images(self): + """ + Resolve splash assets/colors, patch splash config, and generate splash files. + """ + + assert self.package_app_path + assert self.flutter_dir + assert self.options + assert self.get_pyproject + assert self.pubspec_path + assert self.build_dir + assert self.target_platform + + if self.target_platform not in ["web", "ipa", "ios-simulator", "apk", "aab"]: + return + + hash = HashStamp(self.build_dir / ".hash" / "splashes") + + pubspec_origin_path = f"{self.pubspec_path}.orig" + + pubspec = self.load_yaml(pubspec_origin_path) + + copy_ops = [] + self.assets_path = self.package_app_path.joinpath("assets") + if self.assets_path.exists(): + images_dir = "images" + images_path = self.flutter_dir.joinpath(images_dir) + images_path.mkdir(exist_ok=True) + + # copy icons + default_icon = self.find_platform_image( + self.assets_path, images_path, "icon", copy_ops, hash + ) + + # copy splash images + default_splash = self.find_platform_image( + self.assets_path, images_path, "splash", copy_ops, hash + ) + default_dark_splash = self.find_platform_image( + self.assets_path, images_path, "splash_dark", copy_ops, hash + ) + ios_splash = self.find_platform_image( + self.assets_path, images_path, "splash_ios", copy_ops, hash + ) + ios_dark_splash = self.find_platform_image( + self.assets_path, images_path, "splash_dark_ios", copy_ops, hash + ) + android_splash = self.find_platform_image( + self.assets_path, images_path, "splash_android", copy_ops, hash + ) + android_dark_splash = self.find_platform_image( + self.assets_path, images_path, "splash_dark_android", copy_ops, hash + ) + web_splash = self.find_platform_image( + self.assets_path, images_path, "splash_web", copy_ops, hash + ) + web_dark_splash = self.find_platform_image( + self.assets_path, images_path, "splash_dark_web", copy_ops, hash + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image", + [default_splash, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_dark", + [default_dark_splash, default_splash, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_ios", + [ios_splash, default_splash, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_dark_ios", + [ + ios_dark_splash, + default_dark_splash, + ios_splash, + default_splash, + default_icon, + ], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_android", + [android_splash, default_splash, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.android_12.image", + [android_splash, default_splash, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_dark_android", + [ + android_dark_splash, + default_dark_splash, + android_splash, + default_splash, + default_icon, + ], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.android_12.image_dark", + [ + android_dark_splash, + default_dark_splash, + android_splash, + default_splash, + default_icon, + ], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_web", + [web_splash, default_splash, default_icon], + images_dir, + ) + self.fallback_image( + pubspec, + "flutter_native_splash.image_dark_web", + [ + web_dark_splash, + default_dark_splash, + web_splash, + default_splash, + default_icon, + ], + images_dir, + ) + + # splash colors + splash_color = ( + self.options.splash_color + or self.get_pyproject(f"tool.flet.{self.config_platform}.splash.color") + or self.get_pyproject("tool.flet.splash.color") + ) + if splash_color: + pubspec["flutter_native_splash"]["color"] = splash_color + pubspec["flutter_native_splash"]["android_12"]["color"] = splash_color + + splash_dark_color = ( + self.options.splash_dark_color + or self.get_pyproject(f"tool.flet.{self.config_platform}.splash.dark_color") + or self.get_pyproject("tool.flet.splash.dark_color") + ) + if splash_dark_color: + pubspec["flutter_native_splash"]["color_dark"] = splash_dark_color + pubspec["flutter_native_splash"]["android_12"]["color_dark"] = ( + splash_dark_color + ) + + splash_icon_bgcolor = self.get_pyproject( + f"tool.flet.{self.config_platform}.splash.icon_bgcolor" + ) or self.get_pyproject("tool.flet.splash.icon_bgcolor") + + if splash_icon_bgcolor: + pubspec["flutter_native_splash"]["android_12"]["icon_background_color"] = ( + splash_icon_bgcolor + ) + + splash_icon_dark_bgcolor = self.get_pyproject( + f"tool.flet.{self.config_platform}.splash.icon_dark_bgcolor" + ) or self.get_pyproject("tool.flet.splash.icon_dark_bgcolor") + + if splash_icon_dark_bgcolor: + pubspec["flutter_native_splash"]["android_12"][ + "icon_background_color_dark" + ] = splash_icon_dark_bgcolor + + # enable/disable splashes + pubspec["flutter_native_splash"]["web"] = ( + not self.options.no_web_splash + if self.options.no_web_splash is not None + else ( + self.get_pyproject("tool.flet.splash.web") + if self.get_pyproject("tool.flet.splash.web") is not None + else True + ) + ) + pubspec["flutter_native_splash"]["ios"] = ( + not self.options.no_ios_splash + if self.options.no_ios_splash is not None + else ( + self.get_pyproject("tool.flet.splash.ios") + if self.get_pyproject("tool.flet.splash.ios") is not None + else True + ) + ) + pubspec["flutter_native_splash"]["android"] = ( + not self.options.no_android_splash + if self.options.no_android_splash is not None + else ( + self.get_pyproject("tool.flet.splash.android") + if self.get_pyproject("tool.flet.splash.android") is not None + else True + ) + ) + + # check if pubspec changed + hash.update(Path(pubspec_origin_path).stat().st_mtime) + hash.update(pubspec["flutter_native_splash"]) + + # save pubspec.yaml + if hash.has_changed(): + if copy_ops: + self.update_status("[bold blue]Customizing app splash images...") + for op in copy_ops: + if self.verbose > 0: + console.log( + f"Copying image {op[0]} to {op[1]}", style=verbose1_style + ) + shutil.copy(op[0], op[1]) + console.log(f"Customized app splash images {self.emojis['checkmark']}") + + updated_pubspec = self.load_yaml(self.pubspec_path) + updated_pubspec["flutter_native_splash"] = pubspec["flutter_native_splash"] + self.save_yaml(self.pubspec_path, updated_pubspec) + + # splash screens + self.update_status("[bold blue]Generating splash screens...") + splash_result = self.run( + [ + self.dart_exe, + "run", + "--suppress-analytics", + "flutter_native_splash:create", + ], + cwd=str(self.flutter_dir), + capture_output=self.verbose < 1, + ) + if splash_result.returncode != 0: + if isinstance(splash_result.stdout, str): + console.log(splash_result.stdout, style=verbose1_style) + if isinstance(splash_result.stderr, str): + console.log(splash_result.stderr, style=error_style) + self.cleanup(splash_result.returncode) + console.log(f"Generated splash screens {self.emojis['checkmark']}") + + hash.commit() + + def fallback_image(self, pubspec, yaml_path: str, images: list, images_dir: str): + """ + Assign first available image from candidates to a nested pubspec key path. + + Args: + pubspec: Parsed pubspec document. + yaml_path: Dot-separated key path to image setting. + images: Candidate image file names in fallback order. + images_dir: Relative image directory prefix. + """ + + d = pubspec + pp = yaml_path.split(".") + for p in pp[:-1]: + d = d[p] + for image in images: + if image: + d[pp[-1]] = f"{images_dir}/{image}" + return + + def package_python_app(self): + """ + Package Python app and dependencies into Flutter-consumable app archive. + + Handles dependency resolution, cleanup/compile flags, cache checks, and + invokes `serious_python` packaging command. + """ + + assert self.options + assert self.get_pyproject + assert self.python_app_path + assert self.package_app_path + assert self.build_dir + assert self.flutter_dir + assert self.flutter_packages_dir + assert self.flutter_packages_temp_dir + assert self.template_data + + hash = HashStamp(self.build_dir / ".hash" / "package") + + self.update_status("[bold blue]Packaging Python app...") + package_args = [ + self.dart_exe, + "run", + "--suppress-analytics", + "serious_python:main", + "package", + str(self.package_app_path), + "--platform", + self.package_platform, + ] + + if self.template_data["options"]["target_arch"]: + package_args.extend( + ["--arch"] + self.template_data["options"]["target_arch"] + ) + + package_env = {} + + # requirements + requirements_txt = self.python_app_path.joinpath("requirements.txt") + + toml_dependencies = ( + get_poetry_dependencies(self.get_pyproject("tool.poetry.dependencies")) + or get_project_dependencies(self.get_pyproject("project.dependencies")) + or [] + ) + + platform_dependencies = get_project_dependencies( + self.get_pyproject(f"tool.flet.{self.config_platform}.dependencies") + ) + if platform_dependencies: + toml_dependencies.extend(platform_dependencies) + + dev_packages_configured = False + if len(toml_dependencies) > 0: + dev_packages = ( + self.get_pyproject(f"tool.flet.{self.config_platform}.dev_packages") + or self.get_pyproject("tool.flet.dev_packages") + or [] + ) + if len(dev_packages) > 0: + for i in range(0, len(toml_dependencies)): + package_name = Requirement(toml_dependencies[i]).name + if package_name in dev_packages: + package_location = dev_packages[package_name] + dev_path = Path(package_location) + if not dev_path.is_absolute(): + dev_path = (self.python_app_path / dev_path).resolve() + if dev_path.exists(): + toml_dependencies[i] = f"{package_name} @ file://{dev_path}" + else: + toml_dependencies[i] = ( + f"{package_name} @ {package_location}" + ) + dev_packages_configured = True + if dev_packages_configured: + toml_dependencies.append("--no-cache-dir") + + for toml_dep in toml_dependencies: + package_args.extend(["-r", toml_dep]) + + elif requirements_txt.exists(): + if self.verbose > 1: + with open(requirements_txt, encoding="utf-8") as f: + reqs_txt_contents = f.read() + console.log( + f"Contents of requirements.txt: {reqs_txt_contents}", + style=verbose2_style, + ) + hash.update(reqs_txt_contents) + package_args.extend(["-r", "-r", "-r", str(requirements_txt)]) + else: + package_args.extend(["-r", f"flet=={flet.version.flet_version}"]) + + # site-packages variable + if self.package_platform != "Emscripten": + package_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( + self.build_dir / "site-packages" + ) + + # flutter-packages variable + if self.flutter_packages_temp_dir.exists(): + shutil.rmtree(self.flutter_packages_temp_dir) + + package_env["SERIOUS_PYTHON_FLUTTER_PACKAGES"] = str( + self.flutter_packages_temp_dir + ) + + # exclude + exclude_list = ["build"] + + app_exclude = ( + self.options.exclude + or self.get_pyproject(f"tool.flet.{self.config_platform}.app.exclude") + or self.get_pyproject("tool.flet.app.exclude") + ) + if app_exclude: + exclude_list.extend(app_exclude) + + if self.target_platform == "web": + exclude_list.append("assets") + package_args.extend(["--exclude", ",".join(exclude_list)]) + + # source-packages + source_packages = ( + self.options.source_packages + or self.get_pyproject(f"tool.flet.{self.config_platform}.source_packages") + or self.get_pyproject("tool.flet.source_packages") + ) + if source_packages: + package_env["SERIOUS_PYTHON_ALLOW_SOURCE_DISTRIBUTIONS"] = ",".join( + source_packages + ) + + if self.get_bool_setting(self.options.compile_app, "compile.app", False): + package_args.append("--compile-app") + + if self.get_bool_setting( + self.options.compile_packages, "compile.packages", False + ): + package_args.append("--compile-packages") + + cleanup_app = self.get_bool_setting( + self.options.cleanup_app, "cleanup.app", False + ) + cleanup_packages = self.get_bool_setting( + self.options.cleanup_packages, "cleanup.packages", True + ) + + if cleanup_app_files := ( + self.options.cleanup_app_files + or self.get_pyproject(f"tool.flet.{self.config_platform}.cleanup.app_files") + or self.get_pyproject("tool.flet.cleanup.app_files") + ): + if isinstance(cleanup_app_files, str): + cleanup_app_files = [ + value.strip() for value in cleanup_app_files.split(",") + ] + if isinstance(cleanup_app_files, list): + package_args.extend( + [ + "--cleanup-app-files", + ",".join([v.strip() for v in cleanup_app_files if v.strip()]), + ] + ) + cleanup_app = True + + if cleanup_package_files := ( + self.options.cleanup_package_files + or self.get_pyproject( + f"tool.flet.{self.config_platform}.cleanup.package_files" + ) + or self.get_pyproject("tool.flet.cleanup.package_files") + ): + if isinstance(cleanup_package_files, str): + cleanup_package_files = [ + value for value in cleanup_package_files.split(",") + ] + if isinstance(cleanup_package_files, list): + package_args.extend( + [ + "--cleanup-package-files", + ",".join( + [v.strip() for v in cleanup_package_files if v.strip()] + ), + ] + ) + cleanup_packages = True + + if cleanup_app: + package_args.append("--cleanup-app") + + if cleanup_packages: + package_args.append("--cleanup-packages") + + if self.verbose > 1: + package_args.append("--verbose") + + # check if site-packages installation could be skipped + for arg in package_args: + hash.update(arg) + + if not dev_packages_configured: + if not hash.has_changed(): + package_args.append("--skip-site-packages") + else: + if self.flutter_packages_dir.exists(): + shutil.rmtree(self.flutter_packages_dir, ignore_errors=True) + + package_result = self.run( + package_args, + cwd=str(self.flutter_dir), + env=package_env, + capture_output=self.verbose < 1, + ) + + if package_result.returncode != 0: + if isinstance(package_result.stdout, str): + console.log(package_result.stdout, style=verbose1_style) + if isinstance(package_result.stderr, str): + console.log(package_result.stderr, style=error_style) + self.cleanup(package_result.returncode) + + hash.commit() + + # make sure app/app.zip exists + app_zip_path = self.flutter_dir.joinpath("app", "app.zip") + if not os.path.exists(app_zip_path): + self.cleanup(1, "Flet app package app/app.zip was not created.") + + console.log(f"Packaged Python app {self.emojis['checkmark']}") + + def get_bool_setting(self, cli_option, pyproj_setting, default_value): + """ + Resolve a boolean setting with precedence: CLI option, pyproject, default. + + Args: + cli_option: Value from CLI argument. + pyproj_setting: Relative key under `tool.flet..` and + `tool.flet.`. + default_value: Fallback value when no override is defined. + + Returns: + Resolved boolean-like setting value. + """ + + assert self.get_pyproject + return ( + cli_option + if cli_option is not None + else ( + self.get_pyproject(f"tool.flet.{self.config_platform}.{pyproj_setting}") + if self.get_pyproject( + f"tool.flet.{self.config_platform}.{pyproj_setting}" + ) + is not None + else ( + self.get_pyproject(f"tool.flet.{pyproj_setting}") + if self.get_pyproject(f"tool.flet.{pyproj_setting}") is not None + else default_value + ) + ) + ) + + def add_flutter_command_args(self, args: list[str]): + """ + Hook for subclasses to append command-specific Flutter arguments. + + Args: + args: Mutable argument list to extend. + """ + + pass + + def run_flutter(self): + """ + Execute Flutter command for the current build target. + """ + + self._run_flutter_command() + + def _run_flutter_command(self): + """ + Build final Flutter CLI command, configure environment, and run it. + """ + + assert self.options + assert self.build_dir + assert self.get_pyproject + assert self.template_data + assert self.target_platform + + # flutter build + build_args = [self.flutter_exe] + self.add_flutter_command_args(build_args) + build_args.extend( + [ + "--no-version-check", + "--suppress-analytics", + ] + ) + + build_env = {} + + # site-packages variable + if self.package_platform != "Emscripten": + build_env["SERIOUS_PYTHON_SITE_PACKAGES"] = str( + self.build_dir / "site-packages" + ) + + if self.package_platform == "Emscripten" and not self.template_data["no_wasm"]: + build_args.append("--wasm") + + android_signing_key_store = ( + self.options.android_signing_key_store + or self.get_pyproject("tool.flet.android.signing.key_store") + or os.getenv("FLET_ANDROID_SIGNING_KEY_STORE") + ) + if android_signing_key_store: + build_env["FLET_ANDROID_SIGNING_KEY_STORE"] = android_signing_key_store + + key_store_password = ( + self.options.android_signing_key_store_password + or os.getenv("FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD") + ) + key_password = self.options.android_signing_key_password or os.getenv( + "FLET_ANDROID_SIGNING_KEY_PASSWORD" + ) + if key_store_password or key_password: + build_env["FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD"] = ( + key_store_password if key_store_password else key_password + ) + build_env["FLET_ANDROID_SIGNING_KEY_PASSWORD"] = ( + key_password if key_password else key_store_password + ) + + if android_signing_key_store: + android_signing_key_alias = ( + self.options.android_signing_key_alias + or self.get_pyproject("tool.flet.android.signing.key_alias") + or os.getenv("FLET_ANDROID_SIGNING_KEY_ALIAS") + or "upload" + ) + build_env["FLET_ANDROID_SIGNING_KEY_ALIAS"] = android_signing_key_alias + + flutter_build_args = ( + self.options.flutter_build_args + or self.get_pyproject( + f"tool.flet.{self.config_platform}.flutter.build_args" + ) + or self.get_pyproject("tool.flet.flutter.build_args") + ) + if flutter_build_args: + if isinstance(flutter_build_args, (list, tuple)): + for arg in flutter_build_args: + if isinstance(arg, (list, tuple)): + build_args.extend(arg) + elif isinstance(arg, str): + build_args.append(arg) + elif isinstance(flutter_build_args, str): + build_args.append(flutter_build_args) + + if self.verbose > 1: + build_args.append("--verbose") + + build_result = self.run( + build_args, + cwd=str(self.flutter_dir), + env=build_env, + capture_output=self.verbose < 1, + ) + + if ( + build_result.returncode != 0 + or "Encountered error while creating the IPA" in str(build_result.stderr) + ): + if isinstance(build_result.stdout, str): + console.log(build_result.stdout, style=verbose1_style) + if isinstance(build_result.stderr, str): + console.log(build_result.stderr, style=error_style) + self.cleanup(build_result.returncode if build_result.returncode else 1) + + def copy_build_output(self): + """ + Copy generated platform artifacts into the requested output directory. + """ + + assert self.template_data + assert self.options + assert self.flutter_dir + assert self.out_dir + assert self.assets_path + assert self.target_platform + + self.update_status( + f"[bold blue]Copying build to [cyan]{self.rel_out_dir}[/cyan] directory...", + ) + arch = platform.machine().lower() + if arch in {"x86_64", "amd64"}: + arch = "x64" + elif arch in {"arm64", "aarch64"}: + arch = "arm64" + + def make_ignore_fn(out_dir, out_glob): + """ + Create a shutil ignore callback that keeps only one selected output glob. + """ + + def ignore(path, names): + """ + Filter sibling entries at `out_dir` so only `out_glob` is copied. + """ + + if path == out_dir and out_glob != "*": + return [f for f in os.listdir(path) if f != out_glob] + return [] + + return ignore + + for build_output in self.platforms[self.target_platform]["outputs"]: + build_output_dir = ( + str(self.flutter_dir.joinpath(build_output)) + .replace("{arch}", arch) + .replace("{artifact_name}", self.template_data["artifact_name"]) + .replace("{project_name}", self.template_data["project_name"]) + .replace("{product_name}", self.template_data["product_name"]) + ) + + if self.verbose > 0: + console.log( + "Copying build output from: " + build_output_dir, + style=verbose1_style, + ) + + build_output_glob = os.path.basename(build_output_dir) + build_output_dir = os.path.dirname(build_output_dir) + if not os.path.exists(build_output_dir): + continue + + if self.out_dir.exists(): + shutil.rmtree(str(self.out_dir)) + self.out_dir.mkdir(parents=True, exist_ok=True) + + # copy build result to out_dir + copy_tree( + build_output_dir, + str(self.out_dir), + ignore=make_ignore_fn(build_output_dir, build_output_glob), + ) + + if self.target_platform == "web" and self.assets_path.exists(): + # copy `assets` directory contents to the output directory + copy_tree(str(self.assets_path), str(self.out_dir)) + elif self.target_platform in {"apk", "aab"}: + self.rename_android_build_outputs() + + console.log( + f"Copied build to [cyan]{self.rel_out_dir}[/cyan] " + f"directory {self.emojis['checkmark']}" + ) + + def rename_android_build_outputs(self): + """ + Rename copied Android release artifacts so they honor user-configured + artifact names. + + Flutter outputs APK/AAB release files with an `app` prefix + (`app-release.*`, `app--release.*`), plus optional `.sha1` files. + This method removes the `-release` segment and replaces only the + leading `app` token with the resolved Flet artifact name. + """ + assert self.target_platform + assert self.out_dir + assert self.template_data + + artifact_name = str(self.template_data["artifact_name"]) + output_ext = "apk" if self.target_platform == "apk" else "aab" + release_suffix = f"-release.{output_ext}" + release_hash_suffix = f"{release_suffix}.sha1" + final_suffix = f".{output_ext}" + final_hash_suffix = f"{final_suffix}.sha1" + + for output_file in self.out_dir.iterdir(): + if not output_file.is_file(): + continue + + name = output_file.name + suffix = None + final_file_suffix = None + if name.endswith(release_hash_suffix): + suffix = release_hash_suffix + final_file_suffix = final_hash_suffix + elif name.endswith(release_suffix): + suffix = release_suffix + final_file_suffix = final_suffix + if suffix is None or final_file_suffix is None: + continue + + prefix = name[: -len(suffix)] + # Only rewrite Flutter default release outputs that start with `app`. + if prefix != "app" and not prefix.startswith("app-"): + continue + + # Keep ABI and hash suffixes, but drop `-release`. + renamed = f"{artifact_name}{prefix[len('app') :]}{final_file_suffix}" + if renamed == name: + continue + + renamed_path = output_file.with_name(renamed) + if renamed_path.exists(): + console.log( + f"Skipping rename of [cyan]{name}[/cyan] because " + f"[cyan]{renamed}[/cyan] already exists.", + style=warning_style, + ) + continue + + output_file.rename(renamed_path) + if self.verbose > 0: + console.log( + f"Renamed build output from [cyan]{name}[/cyan] to " + f"[cyan]{renamed}[/cyan].", + style=verbose1_style, + ) + + def find_platform_image( + self, + src_path: Path, + dest_path: Path, + image_name: str, + copy_ops: list, + hash: HashStamp, + ): + """ + Find the best matching image file for the current target platform. + + When multiple files share the same base name (e.g. `icon.icns`, + `icon.ico`, `icon.png`), the method filters out formats that are + incompatible with the build target before selecting the first match. + For example, `.icns` is skipped on Windows builds because + `flutter_launcher_icons` cannot decode it. + + Args: + src_path: Source assets directory. + dest_path: Destination image directory. + image_name: Base image name (without extension). + copy_ops: Mutable copy operation list to append to. + hash: Hash accumulator used for change detection. + + Returns: + File name of matched image, or `None` if not found. + """ + + # .icns is macOS-only and .ico is Windows-only; filter out + # incompatible formats so flutter_launcher_icons gets a decodable file. + images = list( + filter( + lambda p: not ( + (ext := Path(p).suffix.lower()) == ".icns" + and self.target_platform != "macos" + or ext == ".ico" + and self.target_platform != "windows" + ), + glob.glob(str(src_path.joinpath(f"{image_name}.*"))), + ) + ) + + if not images: + return None + + best = images[0] + if self.verbose > 0: + console.log(f'Found "{image_name}" image at {best}', style=verbose1_style) + copy_ops.append((best, dest_path)) + hash.update(best) + hash.update(Path(best).stat().st_mtime) + return Path(best).name + + def run(self, args, cwd, env: Optional[dict] = None, capture_output=True): + """ + Run subprocess with merged environment and optional verbose logging. + + Args: + args: Command and arguments to execute. + cwd: Working directory for the process. + env: Additional environment variables merged on top of `self.env`. + capture_output: Whether process output should be captured. + + Returns: + Process result object returned by `flet_cli.utils.processes.run`. + """ + + if self.verbose > 0: + console.log(f"Run subprocess: {args}", style=verbose1_style) + + return processes.run( + args, + cwd, + env={**self.env, **env} if env else self.env, + capture_output=capture_output, + log=self.log_stdout, + ) + + def load_yaml(self, path): + """ + Load and parse a YAML document from disk. + + Args: + path: YAML file path. + + Returns: + Parsed YAML object. + """ + + with open(str(path), encoding="utf-8") as f: + return yaml.safe_load(f) + + def save_yaml(self, path, doc): + """ + Serialize YAML document to disk. + + Args: + path: Destination YAML file path. + doc: YAML-serializable document object. + """ + + with open(str(path), "w", encoding="utf-8") as f: + yaml.dump(doc, f) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py index b9f761d224..9af5bef439 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/create.py @@ -1,72 +1,118 @@ import argparse import os +import platform from pathlib import Path +from rich.console import Console +from rich.style import Style + import flet.version from flet.utils import slugify from flet_cli.commands.base import BaseCommand -from packaging import version -from rich.console import Console -from rich.style import Style error_style = Style(color="red1", bold=True) console = Console(log_path=False) +DEFAULT_APP_TEMPLATE_URL = ( + "https://github.com/flet-dev/flet/releases/download/" + "v{version}/flet-app-templates.zip" +) + class Command(BaseCommand): """ - Create a new Flet app from a template. + Create a new Flet project using a predefined template. + It sets up the initial directory structure, metadata, + and required files to help you get started quickly. """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register command-line options for creating a project from templates. + + Args: + parser: Argument parser configured by the command runner. + """ + parser.add_argument( "output_directory", type=str, default=".", nargs="?", - help="project output directory", + help="Directory where the new Flet project will be created. " + "If omitted, the project is created in the current directory", ) parser.add_argument( "--project-name", dest="project_name", - help="project name for the new Flet app", required=False, + help="Name of the new Flet project. " + "This will be used in metadata files such as `pyproject.toml`", ) parser.add_argument( "--description", dest="description", - help="the description to use for the new Flet project", required=False, + help="Short description of the new Flet project. " + "This will appear in generated metadata", ) parser.add_argument( "--template", dest="template", + type=str.lower, choices=["app", "extension"], default="app", - help="template to use for new Flet project", required=False, + help="The template to use (or type of project to create) " + "for new Flet project", ) parser.add_argument( "--template-ref", dest="template_ref", type=str, - help="the branch, tag or commit ID to checkout after cloning the repository with Flet app templates", + help="Git reference (branch, tag, or commit ID) of the Flet template " + "repository (flet-dev/flet-app-templates) to use. Useful when using a " + "custom or development version of templates", ) def handle(self, options: argparse.Namespace) -> None: + """ + Render and generate a new project using the selected cookiecutter template. + + Args: + options: Parsed command-line options. + """ + from cookiecutter.main import cookiecutter self.verbose = options.verbose + system_name = platform.system().lower() + platform_name = { + "windows": "windows", + "darwin": "darwin", + "linux": "linux", + }.get(system_name, system_name) + template_data = { "template_name": options.template, - "flet_version": flet.version.version, + "flet_version": flet.version.flet_version, "sep": os.sep, + "platform": platform_name, } template_ref = options.template_ref - if not template_ref and flet.version.version: - template_ref = version.Version(flet.version.version).base_version + if not template_ref: + template_ref = flet.version.flet_version + + # Resolve template source: local dev, or zip from GitHub release + local_tpl = Path(__file__).resolve().parents[5] / "templates" / "app" + if local_tpl.is_dir(): + template_url = str(local_tpl) + checkout = None + else: + template_url = DEFAULT_APP_TEMPLATE_URL.format(version=template_ref) + checkout = None out_dir = Path(options.output_directory).resolve() template_data["out_dir"] = out_dir.name @@ -82,8 +128,8 @@ def handle(self, options: argparse.Namespace) -> None: # print("Template data:", template_data) try: cookiecutter( - f"gh:flet-dev/flet-app-templates", - checkout=template_ref, + template_url, + checkout=checkout, directory=options.template, output_dir=str(out_dir.parent), no_input=True, @@ -102,7 +148,7 @@ def handle(self, options: argparse.Namespace) -> None: if self.verbose > 0: console.print(f"[cyan]Files created at[/cyan] {out_dir}:\n") - for root, dirs, files in os.walk(out_dir): + for root, _, files in os.walk(out_dir): for file in files: rel_path = os.path.relpath(os.path.join(root, file), out_dir) console.print(rel_path) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py new file mode 100644 index 0000000000..fff1b7b8d3 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/debug.py @@ -0,0 +1,189 @@ +import argparse +import contextlib +import os +import platform + +from rich.console import Group +from rich.live import Live + +from flet_cli.commands.build_base import BaseBuildCommand, console, verbose2_style + + +class Command(BaseBuildCommand): + """ + Run a Flet Python app in debug mode on a specified platform (desktop, web, mobile). + """ + + def __init__(self, parser: argparse.ArgumentParser) -> None: + super().__init__(parser) + self.debug_platforms = { + "windows": {"target_platform": "windows", "device_id": "windows"}, + "macos": {"target_platform": "macos", "device_id": "macos"}, + "linux": {"target_platform": "linux", "device_id": "linux"}, + "web": {"target_platform": "web", "device_id": "chrome"}, + "ios": {"target_platform": "ipa", "device_id": None}, + "android": {"target_platform": "apk", "device_id": None}, + } + self.debug_platform = None + self.device_id = None + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register command-line arguments for debug builds and run sessions. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "platform", + type=str.lower, + nargs="?", + choices=["macos", "linux", "windows", "web", "ios", "android"], + help="The target platform to run the app on", + ) + parser.add_argument( + "--device-id", + "-d", + type=str, + dest="device_id", + help="Device ID to run the app on for iOS and Android builds.", + ) + parser.add_argument( + "--show-devices", + dest="show_devices", + action="store_true", + default=False, + help="Show connected devices for iOS and Android builds.", + ) + parser.add_argument( + "--release", + dest="release", + action="store_true", + default=False, + help="Build the app in release mode.", + ) + parser.add_argument( + "--route", + type=str, + dest="route", + help="Route to open the app on for web, iOS and Android builds.", + ) + super().add_arguments(parser) + + def handle(self, options: argparse.Namespace) -> None: + """ + Prepare project artifacts and run the app in debug/release mode. + + Args: + options: Parsed command-line options. + """ + + super().handle(options) + self.options.output_dir = None # disable output dir for debug builds + if self.options: + if "platform" in self.options and self.options.platform: + self.debug_platform = self.options.platform + else: + self.debug_platform = platform.system().lower() + if self.debug_platform == "darwin": + self.debug_platform = "macos" + self.platform_label = self.platform_labels[self.debug_platform] + self.target_platform = self.debug_platforms[self.debug_platform][ + "target_platform" + ] + self.device_id = self.debug_platforms[self.debug_platform]["device_id"] + if self.options.device_id: + self.device_id = self.options.device_id + + self.status = console.status( + f"[bold blue]Initializing {self.target_platform} debug session...", + spinner="bouncingBall", + ) + with Live(Group(self.status, self.progress), console=console) as self.live: + self.check_device_id() + self.initialize_command() + if self.options.show_devices: + self.run_flutter_devices() + self.live.update("", refresh=True) + return + self.validate_target_platform() + self.validate_entry_point() + self.setup_template_data() + self.create_flutter_project() + self.package_python_app() + self.register_flutter_extensions() + if self.create_flutter_project(second_pass=True): + self.update_flutter_dependencies() + self.customize_icons() + self.customize_splash_images() + self.run_flutter() + self.cleanup(0, message="Debug session ended.") + + def check_device_id(self): + """ + Validate that a device ID is available for mobile debug targets. + """ + + if self.device_id is None and self.debug_platform in [ + "ios", + "android", + ]: + self.skip_flutter_doctor = True + self.cleanup( + 1, + "Device ID must be specified for iOS and Android debug builds.\n" + "Use --device-id option to specify it.\n" + "Use --show-devices option to list connected devices.", + ) + + def add_flutter_command_args(self, args: list[str]): + """ + Append `flutter run` arguments for selected device and mode. + + Args: + args: Mutable argument list to extend. + """ + + assert self.device_id + args.extend(["run", "-d", self.device_id]) + + if self.options: + if self.options.release: + args.append("--release") + if self.options.route and self.debug_platform in [ + "web", + "ios", + "android", + ]: + args.extend(["--route", self.options.route]) + + def run_flutter(self): + """ + Run the prepared Flutter project on the selected target device. + """ + + assert self.platforms + assert self.target_platform + mode = "release" if self.options.release else "debug" + self.update_status( + f"[bold blue]Running {mode} version of the app on " + f"[cyan]{self.platform_label}[/cyan] device..." + ) + + with contextlib.suppress(KeyboardInterrupt): + self._run_flutter_command() + + def run_flutter_devices(self): + """ + Run `flutter devices` and print discovered devices to verbose output. + """ + + self.update_status("[bold blue]Checking connected devices...") + flutter_devices = self.run( + [self.flutter_exe, "devices", "--no-version-check", "--suppress-analytics"], + cwd=os.getcwd(), + capture_output=True, + ) + if flutter_devices.returncode == 0 and flutter_devices.stdout: + console.log(flutter_devices.stdout, style=verbose2_style) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/devices.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/devices.py new file mode 100644 index 0000000000..14fc057c86 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/devices.py @@ -0,0 +1,242 @@ +import argparse +import os + +from rich.console import Group +from rich.live import Live +from rich.panel import Panel +from rich.table import Column, Table + +from flet_cli.commands.flutter_base import BaseFlutterCommand, console, verbose2_style + + +class Command(BaseFlutterCommand): + """ + List all connected iOS and Android devices. + """ + + def __init__(self, parser: argparse.ArgumentParser) -> None: + super().__init__(parser) + self.devices_platform = None + self.device_timeout = 10 + self.device_connection = "default" + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register command-line options for connected-device listing. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "platform", + type=str.lower, + nargs="?", + choices=["ios", "android"], + help="The target platform to list devices for. " + "If not specified, lists all platforms.", + ) + parser.add_argument( + "--device-timeout", + type=int, + default=10, + dest="device_timeout", + help="Time (in seconds) to wait for devices to attach", + ) + parser.add_argument( + "--device-connection", + type=str.lower, + choices=["both", "attached", "wireless"], + default="both", + dest="device_connection", + help="Filter devices by connection type: attached (USB) or wireless", + ) + super().add_arguments(parser) + + def handle(self, options: argparse.Namespace) -> None: + """ + Initialize environment and render the filtered device list. + + Args: + options: Parsed command-line options. + """ + + super().handle(options) + if self.options and "platform" in self.options and self.options.platform: + self.devices_platform = self.options.platform + if self.options and "device_timeout" in self.options: + self.device_timeout = self.options.device_timeout or 10 + if self.options and "device_connection" in self.options: + self.device_connection = self.options.device_connection + self.platform_label = self.platform_labels[self.devices_platform] + + self.status = console.status( + "[bold blue]Initializing environment...", + spinner="bouncingBall", + ) + with Live(Group(self.status, self.progress), console=console) as self.live: + self.initialize_command() + self.run_flutter_devices() + self.cleanup(0) + + def initialize_command(self): + """ + Enable Android SDK requirement and run shared Flutter initialization. + """ + + self.require_android_sdk = True + + super().initialize_command() + + def run_flutter_devices(self): + """ + Run `flutter devices`, parse results, and display matching mobile devices. + """ + + self.update_status( + f"[bold blue]Checking connected {self.platform_label} devices..." + ) + flutter_devices = self.run( + [ + self.flutter_exe, + "devices", + "--no-version-check", + "--suppress-analytics", + "--device-timeout", + str(self.device_timeout), + ], + cwd=os.getcwd(), + capture_output=True, + ) + output = flutter_devices.stdout or "" + + if flutter_devices.returncode != 0: + error_output = flutter_devices.stderr or output + self.cleanup( + flutter_devices.returncode, + message=( + error_output or "Failed to retrieve devices via `flutter devices`." + ), + ) + return None + + if output and self.verbose >= 1: + console.log(output, style=verbose2_style) + + footer = ( + '\nRun [green]"flet emulators"[/green] to list ' + "and start any available device emulators.\n" + ) + + devices = [ + device + for device in self._parse_devices_output(output) + if device["platform"] in ("ios", "android") + ] + if self.device_connection != "both": + devices = [d for d in devices if d["connection"] == self.device_connection] + if self.devices_platform: + devices = [d for d in devices if d["platform"] == self.devices_platform] + + if not devices: + self.cleanup( + 0, + Group(Panel(f"No {self.platform_label} devices found."), footer), + no_border=True, + ) + + devices_table = Table( + Column("ID", style="magenta", justify="left", no_wrap=True), + Column("Name", style="cyan", justify="left"), + Column("Platform", style="green", justify="center"), + Column("Details", style="yellow", justify="left"), + title=f"Connected {self.platform_label} devices", + header_style="bold", + show_lines=True, + ) + + for device in devices: + devices_table.add_row( + device["id"], + device["name"], + device["platform_label"], + device["details"], + ) + + self.cleanup(0, message=Group(devices_table, footer), no_border=True) + + def _parse_devices_output(self, output: str) -> list[dict]: + """ + Parse bullet-delimited `flutter devices` output into structured records. + + Args: + output: Text output from `flutter devices`. + + Returns: + A list of dictionaries containing name/id/platform/connection/details. + """ + + devices = [] + for raw_line in output.splitlines(): + line = raw_line.strip() + if not line or "\u2022" not in line: + continue + parts = [p.strip() for p in line.split("\u2022")] + if len(parts) < 3: + continue + + name = parts[0] + device_id = parts[1] + platform_raw = parts[2] + details = parts[3] if len(parts) > 3 else "" + platform = self._normalize_platform(platform_raw) + connection = self._detect_connection_type(parts) + + devices.append( + { + "name": name, + "id": device_id, + "platform": platform, + "platform_label": platform_raw, + "connection": connection, + "details": details, + } + ) + + return devices + + def _normalize_platform(self, platform_raw: str) -> str | None: + """ + Normalize a platform label to a canonical identifier. + + Args: + platform_raw: Raw platform text from `flutter devices`. + + Returns: + `"android"`, `"ios"`, or `None` if not recognized. + """ + + platform_lower = platform_raw.lower() + if "android" in platform_lower: + return "android" + if "ios" in platform_lower: + return "ios" + return None + + def _detect_connection_type(self, parts: list[str]) -> str: + """ + Infer connection type from parsed output segments. + + Args: + parts: Bullet-separated columns from one device row. + + Returns: + `"wireless"` when Wi‑Fi markers are present, otherwise `"attached"`. + """ + + # Heuristic: Flutter prints "wireless" or "wifi" in one of the bullet segments + # for wireless devices. Default to "attached" otherwise. + parts_lower = " ".join(parts).lower() + if "wireless" in parts_lower or "wi-fi" in parts_lower or "wifi" in parts_lower: + return "wireless" + return "attached" diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/doctor.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/doctor.py index 3b7722d9ea..2dc8f89ef8 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/doctor.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/doctor.py @@ -1,16 +1,10 @@ import argparse -import os import platform -import shutil -import subprocess import sys -import flet.version -from flet.utils import cleanup_path from rich.console import Console -from rich.status import Status -from rich.style import Style +import flet.version from flet_cli.commands.base import BaseCommand # Rich console setup for styled output @@ -19,50 +13,27 @@ class Command(BaseCommand): """ - `flet doctor` command to provide information about the system and environment setup. + Get information about the system and environment setup. """ def handle(self, options: argparse.Namespace) -> None: """Handle the 'doctor' command.""" verbose = options.verbose - # Step-by-step checks (No need to store results) - self.check_flet_version() - self.check_python_version() - self.check_os_info() - - # Extra details in verbose mode - if verbose: - self.check_virtual_env() - - def check_flet_version(self) -> None: - """Check and print Flet version.""" - with console.status("[bold white]Checking Flet version..."): - flet_version = flet.version.version or "Unknown" - console.print(f"[green]✔ Flet Version:[/green] {flet_version}") - - def check_python_version(self) -> None: - """Check and print Python version.""" - with console.status("[bold white]Checking Python version..."): - console.print(f"[green]✔ Python Version:[/green] {sys.version}") + os_name = platform.system() + if os_name == "Darwin": + os_name = "macOS" + os_version = platform.mac_ver()[0] + else: + os_version = platform.release() - def check_os_info(self) -> None: - """Check and print OS information.""" - with console.status("[bold white]Checking OS information..."): - os_info = f"{platform.system()} {platform.release()} ({platform.version()})" - console.print(f"[green]✔ Operating System:[/green] {os_info}") + arch = platform.machine() + console.print( + f"Flet {flet.version.flet_version} on {os_name} {os_version} ({arch})" + if arch + else f"Flet {flet.version.flet_version} on {os_name} {os_version}" + ) - def check_virtual_env(self) -> None: - """Check if a Python virtual environment is active.""" - with console.status("[bold white]Checking Python virtual environment..."): - venv = os.getenv("VIRTUAL_ENV") - conda_env = os.getenv("CONDA_PREFIX") + console.print(f"Python {platform.python_version()} ({sys.executable})") - if venv: - console.print(f"[green]✔ Virtual Environment active:[/green] {venv}") - elif conda_env: - console.print(f"[green]✔ Conda Environment active:[/green] {conda_env}") - else: - console.print( - "[yellow]⚠ No virtual environment or Conda detected[/yellow]" - ) + # TODO: output Flutter version, if installed diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/emulators.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/emulators.py new file mode 100644 index 0000000000..7ed1d48274 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/emulators.py @@ -0,0 +1,400 @@ +import argparse +import os +import re +from pathlib import Path + +from rich.console import Group +from rich.live import Live +from rich.panel import Panel +from rich.table import Column, Table + +from flet_cli.commands.flutter_base import BaseFlutterCommand, console, verbose2_style +from flet_cli.utils.android_sdk import AndroidSDK + + +class Command(BaseFlutterCommand): + """ + List, create, and launch available emulators. + """ + + def __init__(self, parser: argparse.ArgumentParser) -> None: + super().__init__(parser) + self.action = None + self.emulator_target = None + self.cold_boot = False + self.emulator_name = None + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register command-line arguments for emulator management. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "action", + type=str.lower, + nargs="?", + choices=["start", "create", "delete"], + help="Action to perform: start an emulator, create a new one, " + "or delete it.", + ) + parser.add_argument( + "emulator", + type=str, + nargs="?", + help="Emulator ID or name (required for start, create, and delete).", + ) + parser.add_argument( + "--cold", + dest="cold", + action="store_true", + default=False, + help="Cold boot the emulator when starting.", + ) + super().add_arguments(parser) + + def handle(self, options: argparse.Namespace) -> None: + """ + Execute emulator action flow based on parsed options. + + Initializes required tooling and then dispatches to list, create, start, + or delete logic. + + Args: + options: Parsed CLI options. + """ + + super().handle(options) + if self.options: + self.action = self.options.action + self.emulator_target = self.options.emulator + self.emulator_name = self.options.emulator + self.cold_boot = bool(self.options.cold) + + self.status = console.status( + "[bold blue]Initializing environment...", + spinner="bouncingBall", + ) + with Live(Group(self.status, self.progress), console=console) as self.live: + self.initialize_command() + if self.action == "delete": + if not self.emulator_target: + self.skip_flutter_doctor = True + self.cleanup(1, "Provide emulator ID or name to delete.") + self._delete_emulator() + return + if self.action == "create": + if not self.emulator_name: + self.skip_flutter_doctor = True + self.cleanup(1, "Provide emulator name to create.") + self._create_emulator() + return + if self.action == "start": + if not self.emulator_target: + self.skip_flutter_doctor = True + self.cleanup(1, "Provide emulator ID or name to start.") + self._launch_emulator() + return + self._list_emulators() + + def initialize_command(self): + """ + Enable Android SDK requirement and run base initialization steps. + """ + + self.require_android_sdk = True + + super().initialize_command() + + def _list_emulators(self): + """ + Retrieve available emulators and render them in a table. + + Exits through `cleanup()` with a summary message when no emulators are + found or when discovery fails. + """ + + self.update_status("[bold blue]Listing available emulators...") + emulators_process = self.run( + [ + self.flutter_exe, + "emulators", + "--no-version-check", + "--suppress-analytics", + ], + cwd=os.getcwd(), + capture_output=True, + ) + output = emulators_process.stdout or "" + + if emulators_process.returncode != 0: + error_output = emulators_process.stderr or output + self.cleanup( + emulators_process.returncode, + message=( + error_output + or "Failed to retrieve emulators via `flutter emulators`." + ), + ) + return + + if output and self.verbose >= 1: + console.log(output, style=verbose2_style) + + emulators = self._parse_emulators_output(output) + if not emulators: + footer = ( + '\nRun [green]"flet emulators create "[/green] ' + "to create a new emulator.\n" + ) + self.cleanup(0, Group(Panel("No emulators found."), footer), no_border=True) + + table = Table( + Column("ID", style="magenta", justify="left", no_wrap=True), + Column("Name", style="cyan", justify="left"), + Column("Platform", style="green", justify="center"), + Column("Manufacturer", style="yellow", justify="left"), + title="Available emulators", + header_style="bold", + show_lines=True, + ) + + for emulator in emulators: + table.add_row( + emulator["id"], + emulator["name"], + emulator["platform_label"], + emulator["manufacturer"], + ) + + footer = ( + "\n" + "Launch an emulator with " + '[green]"flet emulators start "[/green].\n' + "Create a new emulator with " + '[green]"flet emulators create "[/green].\n' + "Delete an Android emulator with " + '[green]"flet emulators delete "[/green].\n' + "\n" + "You can find more information on managing emulators at the links below:\n" + " https://developer.android.com/studio/run/managing-avds\n" + " https://developer.android.com/studio/command-line/avdmanager" + ) + + self.cleanup(0, message=Group(table, footer), no_border=True) + + def _launch_emulator(self): + """ + Start the selected emulator, optionally in cold-boot mode. + + Exits through `cleanup()` with command output on failure or a success + confirmation message. + """ + + assert self.emulator_target + self.update_status( + f"[bold blue]Starting emulator [cyan]{self.emulator_target}[/cyan]..." + ) + args = [ + self.flutter_exe, + "emulators", + "--launch", + self.emulator_target, + "--no-version-check", + "--suppress-analytics", + ] + if self.cold_boot: + args.append("--cold") + + launch_result = self.run( + args, + cwd=os.getcwd(), + capture_output=True, + ) + + output = launch_result.stdout or "" + if launch_result.returncode != 0: + error_output = launch_result.stderr or output + self.cleanup( + launch_result.returncode, + ( + error_output + if error_output + else f"Failed to start emulator '{self.emulator_target}'." + ), + ) + return + + if output and self.verbose >= 1: + console.log(output, style=verbose2_style) + + mode = " (cold boot)" if self.cold_boot else "" + self.cleanup(0, f"Emulator [cyan]{self.emulator_target}[/cyan] started{mode}.") + + def _delete_emulator(self): + """ + Delete the selected Android virtual device. + + Resolves SDK location, then delegates deletion to + `AndroidSDK`. + """ + + assert self.emulator_target + self.update_status( + f"[bold blue]Deleting emulator [cyan]{self.emulator_target}[/cyan]..." + ) + home_dir = self.env.get("ANDROID_HOME") or AndroidSDK.android_home_dir() + if not home_dir: + self.cleanup( + 1, "ANDROID_HOME is not set and Android SDK location cannot be found." + ) + + sdk = AndroidSDK( + self.env.get("JAVA_HOME", ""), self.log_stdout, progress=self.progress + ) + + try: + sdk.delete_avd(Path(home_dir), self.emulator_target) + except Exception as exc: # pragma: no cover - defensive + self.skip_flutter_doctor = True + self.cleanup( + 1, f"Failed to delete emulator '{self.emulator_target}': {exc}" + ) + return + + self.cleanup(0, f"Deleted emulator [cyan]{self.emulator_target}[/cyan].") + + def _create_emulator(self): + """ + Create a new emulator using the provided name. + + Validates name format before invoking the create command. + """ + + self.update_status("[bold blue]Creating emulator...") + if not self._is_valid_emulator_name(self.emulator_name): + self.skip_flutter_doctor = True + self.cleanup( + 1, + "Emulator name is invalid. Allowed characters: a-z A-Z 0-9 . _ -", + ) + + args = [ + self.flutter_exe, + "emulators", + "--create", + "--no-version-check", + "--suppress-analytics", + ] + if self.emulator_name: + args.extend(["--name", self.emulator_name]) + + create_result = self.run( + args, + cwd=os.getcwd(), + capture_output=True, + ) + output = create_result.stdout or "" + error_output = create_result.stderr or output + invalid_name = ( + "contains invalid characters" in (error_output or "").lower() + or "contains invalid characters" in output.lower() + ) + exit_code = create_result.returncode or (1 if invalid_name else 0) + if exit_code != 0: + self.cleanup( + exit_code, + error_output or "Failed to create emulator.", + ) + return + + if output and self.verbose >= 1: + console.log(output, style=verbose2_style) + + created_name = self.emulator_name + self.cleanup( + 0, + f"Created emulator [cyan]{created_name}[/cyan]. " + "Use `flet emulators` to list it or " + f"`flet emulators start {created_name}` to start it.", + ) + + def _is_valid_emulator_name(self, name: str) -> bool: + """ + Validate emulator name against supported characters. + + Args: + name: Emulator name candidate. + + Returns: + `True` when the name contains only letters, digits, `.`, `_`, and `-`. + """ + + return bool(re.match(r"^[A-Za-z0-9._-]+$", name or "")) + + def _parse_emulators_output(self, output: str) -> list[dict]: + """ + Parse emulator rows from command output. + + Args: + output: Text output produced by `flutter emulators`. + + Returns: + A list of dictionaries with emulator metadata fields: + `id`, `name`, `platform`, `platform_label`, and `manufacturer`. + """ + + emulators = [] + for raw_line in output.splitlines(): + line = raw_line.strip() + if not line or "\u2022" not in line: + continue + parts = [p.strip() for p in line.split("\u2022") if p.strip()] + if len(parts) < 2: + continue + + emulator_id = parts[0] + name = parts[1] + # Skip header rows printed by `flutter emulators` (Id • Name • Platform ...) + lower_head = {p.lower() for p in parts[:4]} + if {"id", "name", "platform"}.issubset(lower_head): + continue + details_segments = parts[2:] + platform_raw = details_segments[-1] if details_segments else "" + platform = self._normalize_platform(platform_raw) + manufacturer = ( + " • ".join(details_segments[:-1]) if len(details_segments) > 1 else "" + ) + platform_label = platform_raw or platform or "Unknown" + + emulators.append( + { + "name": name, + "id": emulator_id, + "platform": platform, + "platform_label": platform_label, + "manufacturer": manufacturer, + } + ) + + return emulators + + def _normalize_platform(self, platform_raw: str) -> str | None: + """ + Normalize a platform label to a canonical value. + + Args: + platform_raw: Raw platform label extracted from command output. + + Returns: + `"android"`, `"ios"`, or `None` when no known platform is detected. + """ + + platform_lower = platform_raw.lower() + if "android" in platform_lower: + return "android" + if "ios" in platform_lower: + return "ios" + return None diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/flutter_base.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/flutter_base.py new file mode 100644 index 0000000000..bb4efedbf5 --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/flutter_base.py @@ -0,0 +1,512 @@ +import argparse +import os +import platform +import re +import shutil +import sys +from typing import Any, Optional + +from packaging import version +from rich.console import Console, Group +from rich.panel import Panel +from rich.progress import Progress +from rich.prompt import Confirm +from rich.style import Style +from rich.theme import Theme + +import flet.version +import flet_cli.utils.processes as processes +from flet.utils import cleanup_path, is_windows +from flet.utils.platform_utils import get_bool_env_var +from flet_cli.commands.base import BaseCommand +from flet_cli.utils.flutter import get_flutter_dir, install_flutter + +no_rich_output = get_bool_env_var("FLET_CLI_NO_RICH_OUTPUT") + +error_style = Style(color="red", bold=True) +warning_style = Style(color="yellow", bold=True) +console = Console( + log_path=False, + theme=Theme({"log.message": "green bold"}), + force_terminal=not no_rich_output, +) +verbose1_style = Style(dim=True, bold=False) +verbose2_style = Style(color="bright_black", bold=False) + + +class BaseFlutterCommand(BaseCommand): + """ + A base Flutter CLI command. + """ + + def __init__(self, parser: argparse.ArgumentParser) -> None: + super().__init__(parser) + + self.env = {} + self.options = None + self.emojis = {} + self.dart_exe = None + self.flutter_exe = None + self.required_flutter_version: Optional[version.Version] = None + self.verbose = False + self.require_android_sdk = False + self.skip_flutter_doctor = get_bool_env_var("FLET_CLI_SKIP_FLUTTER_DOCTOR") + self.no_rich_output = no_rich_output + self.current_platform = platform.system() + self.progress = Progress(transient=True) + self.platform_labels = { + "windows": "Windows", + "macos": "macOS", + "linux": "Linux", + "web": "Web", + "ios": "iOS", + "android": "Android", + None: "iOS/Android", + } + self.assume_yes = False + self._android_install_confirmed = False + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register shared CLI arguments for Flutter-based commands. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "--no-rich-output", + action="store_true", + default=False, + help="Disable rich output and prefer plain text. Useful on Windows builds " + "[env: FLET_CLI_NO_RICH_OUTPUT=]", + ) + parser.add_argument( + "--yes", + dest="assume_yes", + action="store_true", + default=False, + help="Answer yes to all prompts (install dependencies " + "without confirmation).", + ) + parser.add_argument( + "--skip-flutter-doctor", + action="store_true", + default=False, + help="Skip running Flutter doctor upon failed builds " + "[env: FLET_CLI_SKIP_FLUTTER_DOCTOR=]", + ) + + def handle(self, options: argparse.Namespace) -> None: + """ + Store common option values used by derived commands. + + Args: + options: Parsed command-line options. + """ + + self.options = options + self.no_rich_output = self.no_rich_output or self.options.no_rich_output + self.verbose = self.options.verbose + self.assume_yes = getattr(self.options, "assume_yes", False) + + def initialize_command(self): + """ + Validate prerequisites and prepare Flutter/Android toolchain. + + This method resolves required Flutter version, locates or installs SDK + binaries, and optionally provisions JDK/Android SDK when the command + requires mobile tooling. + """ + + assert self.options + self.required_flutter_version = version.Version(flet.version.flutter_version) + if self.required_flutter_version == version.Version("0"): + self.cleanup( + 1, + "Unable to determine the required Flutter SDK version. " + "If in a source checkout, ensure a valid `.fvmrc` file exists.", + ) + + self.emojis = { + "checkmark": "[green]OK[/]" if self.no_rich_output else "✅", + "loading": "" if self.no_rich_output else "⏳", + "success": "" if self.no_rich_output else "🥳", + "directory": "" if self.no_rich_output else "📁", + } + + self.skip_flutter_doctor = ( + self.skip_flutter_doctor or self.options.skip_flutter_doctor + ) + + # get `flutter` and `dart` executables from PATH + self.flutter_exe = self.find_flutter_batch("flutter") + self.dart_exe = self.find_flutter_batch("dart") + + if ( + not self.flutter_exe + or not self.dart_exe + or not self.flutter_version_valid() + ): + if not self.assume_yes: + console.log( + "Flutter SDK not found or invalid version installed.", + style=warning_style, + ) + prompt = ( + f"Flutter SDK {self.required_flutter_version} is required. " + f"It will be installed now. Proceed? [y/n] " + ) + + if not self._prompt_input(prompt): + self.skip_flutter_doctor = True + self.cleanup( + 1, + "Flutter SDK installation is required. " + "Re-run with --yes to install automatically.", + ) + self.install_flutter() + + if self.verbose > 0: + console.log("Flutter executable:", self.flutter_exe, style=verbose2_style) + console.log("Dart executable:", self.dart_exe, style=verbose2_style) + + if self.require_android_sdk: + if not self._confirm_android_sdk_installation(): + self.skip_flutter_doctor = True + self.cleanup( + 1, + "Android SDK installation is required. " + "Re-run with --yes to install automatically.", + ) + self.install_jdk() + self.install_android_sdk() + + def flutter_version_valid(self): + """ + Check whether the discovered Flutter SDK matches required major/minor version. + + Returns: + `True` when installed Flutter version is compatible, otherwise `False`. + """ + + assert self.required_flutter_version + version_results = self.run( + [ + self.flutter_exe, + "--version", + "--no-version-check", + "--suppress-analytics", + ], + cwd=os.getcwd(), + capture_output=True, + ) + if version_results.returncode == 0 and version_results.stdout: + match = re.search(r"Flutter (\d+\.\d+\.\d+)", version_results.stdout) + if match: + flutter_version = version.parse(match.group(1)) + + # validate installed Flutter version + return ( + flutter_version.major == self.required_flutter_version.major + and flutter_version.minor == self.required_flutter_version.minor + ) + else: + console.log(1, "Failed to validate Flutter version.") + return False + + def install_flutter(self): + """ + Install required Flutter SDK and update command environment. + + Also enables desktop support for the current desktop platform when + applicable. + """ + + assert self.required_flutter_version + self.update_status( + f"[bold blue]Installing Flutter {self.required_flutter_version}..." + ) + + flutter_dir = install_flutter( + str(self.required_flutter_version), self.log_stdout, progress=self.progress + ) + ext = ".bat" if platform.system() == "Windows" else "" + self.flutter_exe = os.path.join(flutter_dir, "bin", f"flutter{ext}") + self.dart_exe = os.path.join(flutter_dir, "bin", f"dart{ext}") + path_env = cleanup_path( + cleanup_path(os.environ.get("PATH", ""), "flutter"), "dart" + ) + self.env["PATH"] = os.pathsep.join([os.path.join(flutter_dir, "bin"), path_env]) + + # desktop mode + desktop_platform = platform.system().lower() + if desktop_platform == "darwin": + desktop_platform = "macos" + if desktop_platform in ["macos", "windows", "linux"]: + if self.verbose > 0: + console.log( + "Ensure Flutter has desktop support enabled", + style=verbose1_style, + ) + config_result = self.run( + [ + self.flutter_exe, + "config", + "--no-version-check", + "--suppress-analytics", + f"--enable-{desktop_platform}-desktop", + ], + cwd=os.getcwd(), + capture_output=self.verbose < 1, + ) + if config_result.returncode != 0: + if isinstance(config_result.stdout, str): + console.log(config_result.stdout, style=verbose1_style) + if isinstance(config_result.stderr, str): + console.log(config_result.stderr, style=error_style) + self.cleanup(config_result.returncode) + + if self.verbose > 0: + console.log( + f"Flutter {self.required_flutter_version} " + f"installed {self.emojis['checkmark']}" + ) + + def install_jdk(self): + """ + Install or resolve JDK and configure Flutter to use it. + """ + + from flet_cli.utils.jdk import install_jdk + + self.update_status("[bold blue]Installing JDK...") + jdk_dir = install_jdk(self.log_stdout, progress=self.progress) + self.env["JAVA_HOME"] = jdk_dir + + # config flutter's JDK dir + if self.verbose > 0: + console.log( + "Configuring Flutter's path to JDK", + style=verbose1_style, + ) + config_result = self.run( + [ + self.flutter_exe, + "config", + "--no-version-check", + "--suppress-analytics", + f"--jdk-dir={jdk_dir}", + ], + cwd=os.getcwd(), + capture_output=self.verbose < 1, + ) + if config_result.returncode != 0: + if isinstance(config_result.stdout, str): + console.log(config_result.stdout, style=verbose1_style) + if isinstance(config_result.stderr, str): + console.log(config_result.stderr, style=error_style) + self.cleanup(config_result.returncode) + + if self.verbose > 0: + console.log(f"JDK installed {self.emojis['checkmark']}") + + def install_android_sdk(self): + """ + Install Android SDK command-line tools and required baseline packages. + """ + + from flet_cli.utils.android_sdk import AndroidSDK + + self.update_status("[bold blue]Installing Android SDK...") + self.env["ANDROID_HOME"] = AndroidSDK( + self.env["JAVA_HOME"], self.log_stdout, progress=self.progress + ).install() + + if self.verbose > 0: + console.log(f"Android SDK installed {self.emojis['checkmark']}") + + def _confirm_android_sdk_installation(self) -> bool: + """ + Confirm Android SDK installation when it is missing or incomplete. + + Returns: + `True` when installation is confirmed or not needed, otherwise `False`. + """ + + from flet_cli.utils.android_sdk import AndroidSDK + + if AndroidSDK.has_minimal_packages_installed(): + self._android_install_confirmed = True + return True + if self._android_install_confirmed: + return True + if self.assume_yes: + self._android_install_confirmed = True + return True + + prompt = ( + "\nAndroid SDK is required. If it's missing or incomplete, " + "it will be installed now. Proceed? [y/n] " + ) + + if self._prompt_input(prompt): + self._android_install_confirmed = True + return True + return False + + def _prompt_input(self, prompt: str) -> bool: + """ + Ask an interactive yes/no prompt while temporarily pausing live rendering. + + Args: + prompt: Prompt text shown to the user. + + Returns: + `True` when user confirms, otherwise `False`. + """ + + self.live.stop() + try: + return Confirm.ask(prompt, default=True) + finally: + self.live.start() + + def find_flutter_batch(self, exe_filename: str): + """Locate the Flutter/Dart executable, preferring the managed SDK install.""" + assert self.required_flutter_version + + install_dir = get_flutter_dir(str(self.required_flutter_version)) + ext = ".bat" if is_windows() else "" + batch_path = os.path.join(install_dir, "bin", f"{exe_filename}{ext}") + + if os.path.exists(batch_path): + return batch_path + + # Fall back to system-installed executable + batch_path = shutil.which(exe_filename) + if not batch_path: + return None + + if is_windows(): + # convert shim paths + if batch_path.endswith(".file"): + return batch_path.replace(".file", ".bat") + + # normalize .exe casing + root, ext = os.path.splitext(batch_path) + if ext.lower() == ".exe": + return f"{root}.exe" + + return batch_path + + def run(self, args, cwd, env: Optional[dict] = None, capture_output=True): + """ + Run a subprocess using merged command environment. + + Args: + args: Command and arguments to execute. + cwd: Working directory for the process. + env: Additional environment variables merged on top of `self.env`. + capture_output: Whether to capture output instead of streaming. + + Returns: + Process result object returned by `flet_cli.utils.processes.run`. + """ + + if self.verbose > 0: + console.log(f"Run subprocess: {args}", style=verbose1_style) + + return processes.run( + args, + cwd, + env={**self.env, **env} if env else self.env, + capture_output=capture_output, + log=self.log_stdout, + ) + + def cleanup(self, exit_code: int, message: Any = None, no_border: bool = False): + """ + Finalize command output, optionally run Flutter doctor, and exit process. + + Args: + exit_code: Exit status code. + message: Optional success/error message content. + no_border: Whether to render success message without a panel border. + """ + + if exit_code == 0: + self.live.update( + (message if no_border else Panel(message)) if message else "", + refresh=True, + ) + else: + msg = ( + message + if message is not None + else "Error building Flet app - see the log of failed command above." + ) + + # windows has been reported to raise encoding errors + # when running `flutter doctor` + # so skip running `flutter doctor` if no_rich_output is True + # and platform is Windows + if not ( + (self.no_rich_output and self.current_platform == "Windows") + or self.skip_flutter_doctor + ): + status = console.status( + "[bold blue]Running Flutter doctor...", + spinner="bouncingBall", + ) + self.live.update( + Group(Panel(msg, style=error_style), status), refresh=True + ) + self.run_flutter_doctor() + self.live.update(Panel(msg, style=error_style), refresh=True) + + sys.exit(exit_code) + + def run_flutter_doctor(self): + """ + Execute `flutter doctor` and print diagnostic output. + """ + + flutter_doctor = self.run( + [self.flutter_exe, "doctor", "--no-version-check", "--suppress-analytics"], + cwd=os.getcwd(), + capture_output=True, + ) + if flutter_doctor.stdout: + console.log(flutter_doctor.stdout, style=verbose1_style) + if flutter_doctor.stderr: + console.log(flutter_doctor.stderr, style=error_style) + + def update_status(self, status): + """ + Update current live status message or log it in plain-output mode. + + Args: + status: Status text to display. + """ + + if self.no_rich_output: + console.log(status) + else: + self.status.update(status) + + def log_stdout(self, message): + """ + Log subprocess output lines when verbose mode is enabled. + + Args: + message: Output text chunk. + """ + + if self.verbose > 0: + console.log( + message, + end="", + style=verbose2_style, + markup=False, + ) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/options.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/options.py index a4dd559038..1776ec7498 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/options.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/options.py @@ -12,9 +12,23 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.kwargs = kwargs def add_to_parser(self, parser: argparse._ActionsContainer) -> None: + """ + Add this option definition to an argument parser or compatible container. + + Args: + parser: Parser-like object exposing `add_argument()`. + """ + parser.add_argument(*self.args, **self.kwargs) def add_to_group(self, group: argparse._ArgumentGroup) -> None: + """ + Add this option definition to an argument group. + + Args: + group: Argument group that receives the option. + """ + group.add_argument(*self.args, **self.kwargs) @@ -23,5 +37,6 @@ def add_to_group(self, group: argparse._ArgumentGroup) -> None: "--verbose", action="count", default=0, - help="-v for detailed output and -vv for more detailed", + help="Enable verbose output. " + "Use -v for standard verbose logging and -vv for more detailed output", ) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/pack.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/pack.py index f5db95cf39..28d055e403 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/pack.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/pack.py @@ -2,32 +2,46 @@ import os import shutil import sys +import tarfile +import zipfile from pathlib import Path -from flet.utils import is_macos, is_windows - import flet_cli.__pyinstaller.config as hook_config +from flet.utils import is_linux, is_macos, is_windows from flet_cli.commands.base import BaseCommand class Command(BaseCommand): """ - Package Flet app to a desktop standalone bundle. + Package a Flet application into a standalone desktop executable or app bundle + using PyInstaller. """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: - parser.add_argument("script", type=str, help="path to a Python script") + """ + Register command-line options for desktop packaging via PyInstaller. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "script", + type=str, + help="Path to the Python script that launches your Flet app", + ) parser.add_argument( "-i", "--icon", dest="icon", - help="path to an icon file (.ico, .png, .icns)", + help="Path to an icon file for your executable or app bundle. " + "Supported formats: `.ico` (Windows), `.png` (Linux) and `.icns` (macOS)", ) parser.add_argument( "-n", "--name", dest="name", - help="name for the generated executable (Windows) or app bundle (macOS)", + help="Name for the generated executable (Windows) or app bundle (macOS)", ) parser.add_argument( "-D", @@ -35,92 +49,101 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="onedir", action="store_true", default=False, - help="create a one-folder bundle containing an executable (Windows)", + help="Create a one-folder bundle instead of a " + "single-file executable (Windows only)", ) parser.add_argument( "--distpath", dest="distpath", - help="where to put the bundled app (default: ./dist)", + default="dist", + help="Directory where the packaged app will be placed", ) parser.add_argument( "--add-data", dest="add_data", action="append", nargs="*", - help="additional non-binary files or folders to be added to the executable", + help="Add additional non-binary files or folders to the bundle. " + "Accepts one or more arguments in the form `source:destination`", ) parser.add_argument( "--add-binary", dest="add_binary", action="append", nargs="*", - help="additional binary files to be added to the executable", + help="Additional binary files to be added to the executable." + "Format: `source:destination[:platform]`", ) parser.add_argument( "--hidden-import", dest="hidden_import", action="append", nargs="*", - help="add an import not visible in the code of the script(s)", + help="Add Python modules that are dynamically imported " + "and not detected by static analysis", ) parser.add_argument( "--product-name", dest="product_name", - help="executable product name (Windows) or bundle name (macOS)", + help="Product name to be embedded in the " + "executable (Windows) or bundle (macOS)", ) parser.add_argument( "--file-description", dest="file_description", - help="executable file description (Windows)", + help="File description to embed in the executable (Windows)", ) parser.add_argument( "--product-version", dest="product_version", - help="executable product version (Windows) or bundle version (macOS)", + help="Product version for the executable (Windows) or bundle (macOS)", ) parser.add_argument( "--file-version", dest="file_version", - help="executable file version, n.n.n.n (Windows)", + help="File version for the executable in `n.n.n.n` format (Windows only)", ) parser.add_argument( "--company-name", dest="company_name", - help="executable company name (Windows)", + help="Company name metadata for the Windows executable", ) parser.add_argument( "--copyright", dest="copyright", - help="executable (Windows) or bundle (macOS) copyright", + help="Copyright string embedded in the " + "executable (Windows) or bundle (macOS)", ) parser.add_argument( "--codesign-identity", dest="codesign_identity", - help="Code signing identity (macOS)", + help="Code signing identity to sign the app bundle (macOS only)", ) parser.add_argument( "--bundle-id", dest="bundle_id", - help="bundle identifier (macOS)", + help="Bundle identifier used for macOS app packaging", ) parser.add_argument( "--debug-console", dest="debug_console", - help="Show python console (Ensure correct DEBUG level)", + help="Show python debug console window (ensure correct DEBUG level). " + "Useful for troubleshooting runtime errors", ) parser.add_argument( "--uac-admin", dest="uac_admin", default=False, action="store_true", - help="Using this option creates a Manifest that will request elevation upon application start.(Windows)", + help="Request elevated (admin) permissions on application " + "start (Windows only). Adds a UAC manifest to the executable", ) parser.add_argument( "--pyinstaller-build-args", dest="pyinstaller_build_args", action="append", nargs="*", - help="additional arguments for pyinstaller build command", + help="Additional raw arguments to the underlying pyinstaller build command", ) parser.add_argument( "-y", @@ -128,15 +151,47 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="non_interactive", default=False, action="store_true", - help="Non-interactive mode.", + help="Enable non-interactive mode. All prompts will be skipped", ) + def compress_flet_client_dir(self, temp_bin_dir: str, archive_name: str) -> None: + """Compress the flet/ directory into an archive and remove the original. + + Args: + temp_bin_dir: Path to the temporary directory containing the flet/ + subdirectory with client binaries. + archive_name: Target archive filename. Uses zip for `.zip` + extensions and gzipped tar for everything else. + """ + flet_dir = os.path.join(temp_bin_dir, "flet") + if not os.path.isdir(flet_dir): + return + archive_path = os.path.join(temp_bin_dir, archive_name) + if archive_name.endswith(".zip"): # windows + with zipfile.ZipFile(archive_path, "w", zipfile.ZIP_DEFLATED) as zf: + for root, _dirs, files in os.walk(flet_dir): + for f in files: + full = os.path.join(root, f) + arcname = os.path.relpath(full, temp_bin_dir) + zf.write(full, arcname) + else: + with tarfile.open(archive_path, "w:gz") as tar: + tar.add(flet_dir, arcname="flet") + shutil.rmtree(flet_dir) + def handle(self, options: argparse.Namespace) -> None: + """ + Package the app into a standalone desktop artifact. + + Args: + options: Parsed command-line options. + """ + from flet.utils.pip import ensure_flet_desktop_package_installed ensure_flet_desktop_package_installed() - is_dir_not_empty = lambda dir: os.path.isdir(dir) and len(os.listdir(dir)) != 0 + is_dir_not_empty = lambda dir: os.path.isdir(dir) and len(os.listdir(dir)) != 0 # noqa: E731 # delete "build" directory build_dir = os.path.join(os.getcwd(), "build") @@ -145,9 +200,9 @@ def handle(self, options: argparse.Namespace) -> None: shutil.rmtree(build_dir, ignore_errors=True) else: delete_dir_prompt = input( - f'Do you want to delete "build" directory? (y/n) ' + 'Do you want to delete "build" directory? (y/n) ' ) - if not delete_dir_prompt.lower() == "n": + if delete_dir_prompt.lower() != "n": shutil.rmtree(build_dir, ignore_errors=True) else: print('Failing... "build" directory must be empty to proceed.') @@ -165,13 +220,15 @@ def handle(self, options: argparse.Namespace) -> None: shutil.rmtree(dist_dir, ignore_errors=True) else: delete_dir_prompt = input( - f'Do you want to delete "{os.path.basename(dist_dir)}" directory? (y/n) ' + f'Do you want to delete "{os.path.basename(dist_dir)}" ' + f"directory? (y/n) " ) - if not delete_dir_prompt.lower() == "n": + if delete_dir_prompt.lower() != "n": shutil.rmtree(dist_dir, ignore_errors=True) else: print( - f'Failing... DISTPATH "{os.path.basename(dist_dir)}" directory must be empty to proceed.' + f'Failing... DISTPATH "{os.path.basename(dist_dir)}" directory ' + f"must be empty to proceed." ) exit(1) @@ -263,6 +320,12 @@ def handle(self, options: argparse.Namespace) -> None: pyi_args.extend(["--version-file", version_info_path]) + # Compress the patched flet/ directory into flet-windows.zip + # so ensure_client_cached() finds it at runtime. + self.compress_flet_client_dir( + hook_config.temp_bin_dir, "flet-windows.zip" + ) + elif is_macos(): from flet_cli.__pyinstaller.macos_utils import ( assemble_app_bundle, @@ -272,32 +335,70 @@ def handle(self, options: argparse.Namespace) -> None: ) tar_path = os.path.join( - hook_config.temp_bin_dir, "flet-macos-amd64.tar.gz" + hook_config.temp_bin_dir, "flet-macos.tar.gz" ) + + # Find the .app bundle: either unpack from tar.gz or + # locate an already-extracted bundle (GitHub releases cache). + app_path = None if os.path.exists(tar_path): - # unpack app_path = unpack_app_bundle(tar_path) + else: + for entry in os.listdir(hook_config.temp_bin_dir): + if entry.endswith(".app"): + app_path = os.path.join(hook_config.temp_bin_dir, entry) + break - # icon - if options.icon: - icon_path = options.icon - if not Path(icon_path).is_absolute(): - icon_path = str(Path(os.getcwd()).joinpath(icon_path)) - update_flet_view_icon(app_path, icon_path) - - # version info - app_path = update_flet_view_version_info( - app_path=app_path, - bundle_id=options.bundle_id, - product_name=options.product_name, - product_version=options.product_version, - copyright=options.copyright, + if not app_path: + print( + "Error: macOS app bundle not found in " + f"{hook_config.temp_bin_dir}. " + "Set FLET_VIEW_PATH to the directory " + "containing your Flet.app." ) + sys.exit(1) - # assemble - assemble_app_bundle(app_path, tar_path) + # icon + if options.icon: + icon_path = options.icon + if not Path(icon_path).is_absolute(): + icon_path = str(Path(os.getcwd()).joinpath(icon_path)) + update_flet_view_icon(app_path, icon_path) + + # version info + app_path = update_flet_view_version_info( + app_path=app_path, + bundle_id=options.bundle_id, + product_name=options.product_name, + product_version=options.product_version, + copyright=options.copyright, + ) + + # Compress the patched .app bundle back into flet-macos.tar.gz so + # ensure_client_cached() finds it at runtime. + assemble_app_bundle(app_path, tar_path) + + # Remove everything except the tar.gz so PyInstaller doesn't try + # to process loose framework binaries. + for entry in os.listdir(hook_config.temp_bin_dir): + entry_path = os.path.join(hook_config.temp_bin_dir, entry) + if entry_path == tar_path: + continue + if os.path.isdir(entry_path): + shutil.rmtree(entry_path, ignore_errors=True) + else: + os.remove(entry_path) + + elif is_linux(): + from flet_desktop import get_artifact_filename + + # Compress the flet/ directory into a tar.gz + # so ensure_client_cached() finds it at runtime. + self.compress_flet_client_dir( + hook_config.temp_bin_dir, get_artifact_filename() + ) - # run PyInstaller! + # run PyInstaller print("Running PyInstaller:", pyi_args) PyInstaller.__main__.run(pyi_args) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py index c609c08d9b..921e470aec 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/publish.py @@ -1,15 +1,13 @@ import argparse import os -import re import shutil import sys import tarfile import tempfile from pathlib import Path -from flet.core.types import WebRenderer +from flet.controls.types import RouteUrlStrategy, WebRenderer from flet.utils import copy_tree, is_within_directory, random_string - from flet_cli.commands.base import BaseCommand from flet_cli.utils.project_dependencies import ( get_poetry_dependencies, @@ -20,15 +18,22 @@ class Command(BaseCommand): """ - Publish Flet app as a standalone web app. + Compile and package a Flet app as a standalone static web application. """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register CLI arguments used to publish a static web build. + + Args: + parser: Argument parser configured by the command runner. + """ + parser.add_argument( "script", type=str, nargs="?", - help="path to a Python script", + help="Path to the Python script that starts your Flet app", default=".", ) parser.add_argument( @@ -36,7 +41,8 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="pre", action="store_true", default=False, - help="allow micropip to install pre-release Python packages", + help="Allow micropip to install pre-release Python packages. " + "Use this if your app depends on a prerelease version of a package", ) parser.add_argument( "-a", @@ -44,81 +50,104 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="assets_dir", type=str, default=None, - help="path to an assets directory", + help="Path to a directory containing static assets " + "used by the app (e.g., images, fonts, icons). [env: FLET_ASSETS_DIR=]", ) parser.add_argument( "--distpath", dest="distpath", - help="where to put the published app (default: ./dist)", + default="dist", + help="Directory where the published web app should be placed", ) parser.add_argument( "--app-name", dest="app_name", type=str, default=None, - help="application name", + help="Full name of the application. " + "This is used in PWA metadata and may appear in the install prompt", ) parser.add_argument( "--app-short-name", dest="app_short_name", type=str, default=None, - help="application short name", + help="A shorter version of the application name, " + "often used in homescreen icons or install prompts", ) parser.add_argument( "--app-description", dest="app_description", type=str, default=None, - help="application description", + help="Short description of the application. " + "Used in PWA manifests and metadata", ) parser.add_argument( "--base-url", dest="base_url", type=str, default=None, - help="base URL for the app", + help="Base URL path to serve the app from. " + "Useful if the app is hosted in a subdirectory", ) parser.add_argument( "--web-renderer", dest="web_renderer", - choices=["canvaskit", "html"], - default="canvaskit", - help="web renderer to use", - ) - parser.add_argument( - "--use-color-emoji", - dest="use_color_emoji", - action="store_true", - default=False, - help="enables color emojis with CanvasKit renderer", + type=str.lower, + choices=["auto", "canvaskit", "skwasm"], + default="auto", + help="Flutter web renderer to use [env: FLET_WEB_RENDERER=]", ) parser.add_argument( "--route-url-strategy", dest="route_url_strategy", + type=str.lower, choices=["path", "hash"], default="path", - help="URL routing strategy", + help="Controls how routes are handled in the browser " + "[env: FLET_WEB_ROUTE_URL_STRATEGY=]", ) parser.add_argument( "--pwa-background-color", dest="pwa_background_color", - help="an initial background color for your web application", required=False, + help="Initial background color of your web app during the " + "loading phase (used in splash screens)", ) parser.add_argument( "--pwa-theme-color", dest="pwa_theme_color", - help="default color for your web application's user interface", required=False, + help="Default color of the browser UI (e.g., address bar) " + "when your app is installed as a PWA", + ) + parser.add_argument( + "--no-cdn", + dest="no_cdn", + action="store_true", + default=False, + help="Disable loading of CanvasKit, Pyodide, and fonts from CDNs. " + "Use this for full offline deployments or air-gapped environments", ) def handle(self, options: argparse.Namespace) -> None: + """ + Build and package the app as a static web distribution. + Args: + options: Parsed command-line options. + """ + import flet.version from flet.utils.pip import ensure_flet_web_package_installed ensure_flet_web_package_installed() - from flet_web import get_package_web_dir, patch_index_html, patch_manifest_json + from flet_web import ( + get_package_web_dir, + patch_font_manifest_json, + patch_index_html, + patch_manifest_json, + ) # constants dist_name = "dist" @@ -172,10 +201,9 @@ def handle(self, options: argparse.Namespace) -> None: # copy assets assets_dir = options.assets_dir if assets_dir and not Path(assets_dir).is_absolute(): - assets_dir = str(script_path.joinpath(assets_dir).resolve()) + assets_dir = str(script_dir / assets_dir) else: assets_dir = str(script_dir / assets_name) - if os.path.exists(assets_dir): copy_tree(assets_dir, str(dist_dir)) @@ -190,7 +218,7 @@ def handle(self, options: argparse.Namespace) -> None: deps = toml_dependencies print(f"pyproject.toml dependencies: {deps}") elif requirements_txt.exists(): - with open(requirements_txt, "r", encoding="utf-8") as f: + with open(requirements_txt, encoding="utf-8") as f: deps = list( filter( lambda dep: not dep.startswith("#"), @@ -200,7 +228,7 @@ def handle(self, options: argparse.Namespace) -> None: print(f"{reqs_filename} dependencies: {deps}") if len(deps) == 0: - deps = [f"flet=={flet.version.version}"] + deps = [f"flet=={flet.version.flet_version}"] temp_reqs_txt = Path(tempfile.gettempdir()).joinpath(random_string(10)) with open(temp_reqs_txt, "w", encoding="utf-8") as f: @@ -210,17 +238,28 @@ def handle(self, options: argparse.Namespace) -> None: app_tar_gz_path = os.path.join(dist_dir, app_tar_gz_filename) def filter_tar(tarinfo: tarfile.TarInfo): + """ + Filter files that should be excluded from packaged app archive. + + Args: + tarinfo: Tar member metadata for a candidate file. + + Returns: + The original `tarinfo` to include the file, or `None` to skip it. + """ + full_path = os.path.join(script_dir, tarinfo.name) if ( - tarinfo.name.startswith(".") - or tarinfo.name.startswith("__pycache__") - or tarinfo.name == reqs_filename + ( + tarinfo.name.startswith(".") + or tarinfo.name.startswith("__pycache__") + or tarinfo.name == reqs_filename + ) + or assets_dir + and is_within_directory(assets_dir, full_path) + or is_within_directory(dist_dir, full_path) ): return None - elif assets_dir and is_within_directory(assets_dir, full_path): - return None - elif is_within_directory(dist_dir, full_path): - return None # tarinfo.uid = tarinfo.gid = 0 # tarinfo.uname = tarinfo.gname = "root" if tarinfo.name != "": @@ -272,6 +311,8 @@ def filter_tar(tarinfo: tarfile.TarInfo): "tool.flet.web.pwa_theme_color" ) + no_cdn = options.no_cdn or get_pyproject("tool.flet.web.cdn") == False # noqa: E712 + print("Patching index.html") patch_index_html( index_path=os.path.join(dist_dir, "index.html"), @@ -282,25 +323,16 @@ def filter_tar(tarinfo: tarfile.TarInfo): pyodide_pre=options.pre, pyodide_script_path=str(script_path), web_renderer=WebRenderer( - ( - options.web_renderer - or get_pyproject("tool.flet.web.renderer") - or "canvaskit" - ) + options.web_renderer + or get_pyproject("tool.flet.web.renderer") + or "auto" ), - use_color_emoji=( - True - if ( - options.use_color_emoji - or get_pyproject("tool.flet.web.use_color_emoji") - ) - else False - ), - route_url_strategy=str( + route_url_strategy=RouteUrlStrategy( options.route_url_strategy or get_pyproject("tool.flet.web.route_url_strategy") or "path" ), + no_cdn=no_cdn, ) print("Patching manifest.json") @@ -312,3 +344,9 @@ def filter_tar(tarinfo: tarfile.TarInfo): background_color=pwa_background_color, theme_color=pwa_theme_color, ) + + if no_cdn: + print("Patching FontManifest.json") + patch_font_manifest_json( + manifest_path=os.path.join(dist_dir, "assets", "FontManifest.json") + ) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py index f2da83ab58..2be23587a1 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/run.py @@ -1,7 +1,6 @@ import argparse import os import platform -import shutil import signal import subprocess import sys @@ -12,6 +11,9 @@ from urllib.parse import quote, urlparse, urlunparse import qrcode +from watchdog.events import FileSystemEventHandler +from watchdog.observers import Observer + from flet.utils import ( get_free_tcp_port, get_local_ip, @@ -19,25 +21,29 @@ open_in_browser, random_string, ) -from watchdog.events import FileSystemEventHandler -from watchdog.observers import Observer - from flet_cli.commands.base import BaseCommand from flet_cli.utils.pyproject_toml import load_pyproject_toml class Command(BaseCommand): """ - Run a Flet app in hot-reload mode. + Run a Flet application in hot reload mode. """ def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register CLI arguments for the `flet run` command. + + Args: + parser: Argument parser configured by the command runner. + """ + parser.add_argument( "script", type=str, nargs="?", default=".", - help="path to a Python script", + help="Path to the Python script that starts your Flet app", ) parser.add_argument( "-p", @@ -45,21 +51,23 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="port", type=int, default=None, - help="custom TCP port to run Flet app on", + help="Custom TCP or HTTP (if `--web` option is used) port to run the Flet " + "app on. If not specified, a random port will be chosen", ) parser.add_argument( "--host", dest="host", type=str, default=None, - help='host to run Flet web app on. Use "*" to listen on all IPs.', + help='The host to run Flet web app on. Use "*" to listen on all IPs', ) parser.add_argument( "--name", dest="app_name", type=str, default=None, - help="app name to distinguish it from other on the same port", + help="A unique name for your app. " + "Useful when running multiple apps on the same port", ) parser.add_argument( "-m", @@ -67,7 +75,8 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="module", action="store_true", default=False, - help="treat the script as a python module path as opposed to a file path", + help="Treat the script as a python module path instead of a file path. " + "Example: flet run -m my_app.main", ) parser.add_argument( "-d", @@ -75,7 +84,8 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="directory", action="store_true", default=False, - help="watch script directory", + help="Watch the directory of the script for changes " + "and hot reload the app accordingly", ) parser.add_argument( "-r", @@ -83,7 +93,8 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="recursive", action="store_true", default=False, - help="watch script directory and all sub-directories recursively", + help="Watch script directory and all its " + "sub-directories recursively for file changes", ) parser.add_argument( "-n", @@ -91,7 +102,7 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="hidden", action="store_true", default=False, - help="application window is hidden on startup", + help="Start the application with the window hidden", ) parser.add_argument( "-w", @@ -99,21 +110,22 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="web", action="store_true", default=False, - help="open app in a web browser", + help="Launch the Flet app as a dynamic website and automatically " + "open it in your web browser after startup", ) parser.add_argument( "--ios", dest="ios", action="store_true", default=False, - help="open app on iOS device", + help="Launch the app on an iOS device", ) parser.add_argument( "--android", dest="android", action="store_true", default=False, - help="open app on Android device", + help="Launch the app on an Android device", ) parser.add_argument( "-a", @@ -121,17 +133,31 @@ def add_arguments(self, parser: argparse.ArgumentParser) -> None: dest="assets_dir", type=str, default="assets", - help="path to assets directory", + help="Path to a directory containing static assets " + "used by the app (e.g. images, fonts)", ) parser.add_argument( "--ignore-dirs", dest="ignore_dirs", type=str, default=None, - help="directories to ignore during watch. If more than one, separate with a comma.", + help="Comma-separated list of directory names to ignore " + "when watching for file changes", ) def handle(self, options: argparse.Namespace) -> None: + """ + Resolve runtime settings, start file watching, and run hot-reload loop. + + This method prepares the script/module path, selects transport + configuration (port or UDS), resolves assets and ignore directories, + starts the child app process through `Handler`, and keeps the + observer running until termination. + + Args: + options: Parsed command options produced by :meth:`add_arguments`. + """ + from flet.utils.pip import ( ensure_flet_desktop_package_installed, ensure_flet_web_package_installed, @@ -195,12 +221,7 @@ def handle(self, options: argparse.Namespace) -> None: ) flet_app_data_dir = project_dir / "storage" / "data" - flet_app_data_dir.mkdir(parents=True, exist_ok=True) - flet_app_temp_dir = project_dir / "storage" / "temp" - if flet_app_temp_dir.exists(): - shutil.rmtree(str(flet_app_temp_dir), ignore_errors=True) - flet_app_temp_dir.mkdir(parents=True, exist_ok=True) my_event_handler = Handler( args=[sys.executable, "-u"] @@ -239,6 +260,14 @@ def handle(self, options: argparse.Namespace) -> None: class Handler(FileSystemEventHandler): + """ + File-system event handler that manages app process lifecycle for hot reload. + + The handler starts the Python app process, watches for code changes, and + restarts the process when relevant files change. It also handles launch of + desktop view or browser/QR output depending on runtime mode. + """ + def __init__( self, args, @@ -283,6 +312,13 @@ def __init__( self.start_process() def start_process(self): + """ + Start the application subprocess with computed Flet environment variables. + + The method configures server/display settings, storage paths, encoding + behavior, and then starts background output processing. + """ + p_env = {**os.environ} if self.web or self.ios or self.android: p_env["FLET_FORCE_WEB_SERVER"] = "true" @@ -317,6 +353,14 @@ def start_process(self): th.start() def on_any_event(self, event): + """ + React to file-system events and trigger a debounced process restart. + + Events coming from ignored directories are skipped. Restart is performed + for create/modify/delete/move events either on the target script or + within the watched directory tree. + """ + for directory in self.ignore_dirs: child = os.path.abspath(event.src_path) # check if the file which triggered the reload is in the (ignored) directory @@ -328,7 +372,6 @@ def on_any_event(self, event): if ( self.watch_directory or event.src_path == self.script_path ) and event.event_type in ["modified", "deleted", "created", "moved"]: - current_time = time.time() if (current_time - self.last_time) > 0.5 and self.is_running: self.last_time = current_time @@ -336,6 +379,17 @@ def on_any_event(self, event): th.start() def print_output(self, p): + """ + Stream subprocess output and react to initial app display URL signal. + + When a display URL line is detected, this method either prints/open it, + renders a QR code for mobile mode, or opens desktop view and waits for + that process to finish. + + Args: + p: Running child process whose stdout is consumed. + """ + while True: line = p.stdout.readline() if not line: @@ -343,7 +397,10 @@ def print_output(self, p): line = line.rstrip("\r\n") if line.startswith(self.page_url_prefix): if not self.page_url: - self.page_url = line[len(self.page_url_prefix) + 1 :] + parts = line[len(self.page_url_prefix) + 1 :].split(" ", 1) + self.page_url = parts[0] + if len(parts) > 1 and parts[1] == "flet_app_hidden": + self.hidden = True if ( self.page_url.startswith("http") and not self.ios @@ -363,6 +420,13 @@ def print_output(self, p): print(line) def open_flet_view_and_wait(self): + """ + Open desktop view for the current page URL and block until it exits. + + After the desktop view process exits, the child app process is + terminated and the handler termination event is set. + """ + from flet_desktop import open_flet_view self.fvp, self.pid_file = open_flet_view( @@ -377,12 +441,27 @@ def open_flet_view_and_wait(self): self.terminate.set() def restart_program(self): + """ + Restart the child app process used for hot reload. + + The current process is terminated first, then a fresh process is started + with the same runtime arguments and environment. + """ + self.is_running = False self.p.send_signal(signal.SIGTERM) self.p.wait() self.start_process() def print_qr_code(self, orig_url: str, android: bool): + """ + Print a LAN URL and terminal QR code for connecting from a mobile device. + + Args: + orig_url: URL emitted by the running app process. + android: Whether to generate an Android launcher URL format. + """ + u = urlparse(orig_url) ip_addr = get_local_ip() lan_url = urlunparse( @@ -416,6 +495,10 @@ def print_qr_code(self, orig_url: str, android: bool): print("Scan QR code above with Camera app.") def clear_console(self): + """ + Clear the current terminal screen on supported platforms. + """ + if platform.system() == "Windows": if platform.release() in {"10", "11"}: subprocess.run( diff --git a/sdk/python/packages/flet-cli/src/flet_cli/commands/serve.py b/sdk/python/packages/flet-cli/src/flet_cli/commands/serve.py new file mode 100644 index 0000000000..f9994a0a3e --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/commands/serve.py @@ -0,0 +1,102 @@ +import argparse +import http.server +import socketserver +from pathlib import Path + +from rich.console import Console +from rich.style import Style + +from flet_cli.commands.base import BaseCommand + +error_style = Style(color="red1", bold=True) +console = Console(log_path=False) + + +class CustomHandler(http.server.SimpleHTTPRequestHandler): + """ + Static-file request handler that injects cross-origin isolation headers. + """ + + def __init__(self, *args, directory=None, **kwargs): + super().__init__(*args, directory=directory, **kwargs) + + def end_headers(self): + """ + Append CORS/COOP/COEP headers before finalizing HTTP response headers. + """ + + self.send_header("Cross-Origin-Opener-Policy", "same-origin") + self.send_header("Cross-Origin-Embedder-Policy", "require-corp") + self.send_header("Access-Control-Allow-Origin", "*") + super().end_headers() + + +class Command(BaseCommand): + """ + Serve static files from a directory with a lightweight web server, + optionally adding WebAssembly-related headers for Flet web apps. + """ + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """ + Register command-line arguments for the local static file server. + + Args: + parser: Argument parser configured by the command runner. + """ + + parser.add_argument( + "web_root", + type=str, + nargs="?", + help="Directory to serve", + default="./build/web", + ) + parser.add_argument( + "-p", + "--port", + type=int, + default=8000, + help="Port number to serve the files on. Use this to customize the port if " + "the default is already in use or needs to be changed", + ) + + def handle(self, options: argparse.Namespace) -> None: + """ + Serve files from the selected directory on a local HTTP port. + + Args: + options: Parsed command-line options. + """ + + directory = Path(options.web_root).resolve() + if not directory.is_dir(): + console.print( + f"Error: Directory '{directory}' does not exist or is not a folder.", + style=error_style, + ) + exit(1) + + def handler(*args, **kwargs): + """ + Factory that binds `CustomHandler` to `directory`. + """ + + return CustomHandler( + *args, + directory=str(directory), + **kwargs, + ) + + try: + with socketserver.TCPServer(("", options.port), handler) as httpd: + console.print( + f"Serving [green]{directory}[/green] at [cyan]" + f"http://localhost:{options.port}[/cyan] (Press Ctrl+C to stop)\n" + ) + httpd.serve_forever() + except KeyboardInterrupt: + console.print("\n[bold yellow]Server stopped by user.[/bold yellow]") + except OSError as e: + console.print(f"Error: {e}", style=error_style) + exit(1) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/android_sdk.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/android_sdk.py index da321f7f9b..c9a6e0f8a4 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/android_sdk.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/android_sdk.py @@ -4,9 +4,10 @@ from pathlib import Path from typing import Optional +from rich.progress import Progress + from flet_cli.utils import processes from flet_cli.utils.distros import download_with_progress, extract_with_progress -from rich.progress import Progress ANDROID_CMDLINE_TOOLS_DOWNLOAD_VERSION = "11076708" ANDROID_CMDLINE_TOOLS_VERSION = "12.0" @@ -20,6 +21,13 @@ class AndroidSDK: + """ + Helper for discovering, installing, and invoking Android SDK tooling. + + The class manages command-line tools installation, required package setup, + license acceptance, and subprocess execution with the required environment. + """ + def __init__( self, java_home: str, log, progress: Optional[Progress] = None ) -> None: @@ -29,6 +37,13 @@ def __init__( @staticmethod def studio_android_home_dir() -> Path: + """ + Return the default Android Studio SDK directory for the current platform. + + Returns: + Platform-specific SDK path typically used by Android Studio. + """ + return ( Path.home() / "AppData" / "Local" / "Android" / "Sdk" if platform.system() == "Windows" @@ -41,10 +56,29 @@ def studio_android_home_dir() -> Path: @staticmethod def default_android_home_dir() -> Path: + """ + Return the fallback SDK installation directory used by this CLI. + + Returns: + Default SDK path under the user's home directory. + """ + return Path.home() / "Android" / "sdk" @staticmethod def android_home_dir() -> Optional[Path]: + """ + Locate an existing Android SDK home directory. + + Detection order: + - `ANDROID_HOME` when it exists; + - `ANDROID_SDK_ROOT` when it exists; + - common SDK directories used by Android Studio and the CLI. + + Returns: + Existing SDK directory path, or `None` if no installation is found. + """ + # check ANDROID_HOME environment variable home_dir = os.getenv("ANDROID_HOME") if home_dir and Path(home_dir).exists(): @@ -66,6 +100,16 @@ def android_home_dir() -> Optional[Path]: return None def cmdline_tools_bin(self, home_dir: Path) -> Optional[Path]: + """ + Return the `cmdline-tools` binary directory in an SDK installation. + + Args: + home_dir: Android SDK home directory. + + Returns: + Path to the tools `bin` directory, or `None` if not found. + """ + for d in [ home_dir / "cmdline-tools" / "latest" / "bin", home_dir / "cmdline-tools" / ANDROID_CMDLINE_TOOLS_VERSION / "bin", @@ -75,15 +119,105 @@ def cmdline_tools_bin(self, home_dir: Path) -> Optional[Path]: return None def tool_exe(self, name: str, windows_ext: str): + """ + Build a platform-specific executable name. + + Args: + name: Base executable name. + windows_ext: Extension to append on Windows (for example `.bat`). + + Returns: + Executable name for the current platform. + """ + ext = windows_ext if platform.system() == "Windows" else "" return f"{name}{ext}" def sdkmanager_exe(self, home_dir): + """ + Return the absolute path to `sdkmanager`. + + Args: + home_dir: Android SDK home directory. + + Returns: + Path to the `sdkmanager` executable. + """ + bin = self.cmdline_tools_bin(home_dir) assert bin return bin / self.tool_exe("sdkmanager", ".bat") + def avdmanager_exe(self, home_dir): + """ + Return the absolute path to `avdmanager`. + + Args: + home_dir: Android SDK home directory. + + Returns: + Path to the `avdmanager` executable. + """ + + bin = self.cmdline_tools_bin(home_dir) + assert bin + return bin / self.tool_exe("avdmanager", ".bat") + + @staticmethod + def has_minimal_packages_installed() -> bool: + """ + Check whether a usable SDK and required baseline packages are present. + + Returns: + `True` when SDK command-line tools and all packages in + `MINIMAL_PACKAGES` are installed; otherwise `False`. + """ + + home_dir = AndroidSDK.android_home_dir() + if not home_dir: + return False + + sdk = AndroidSDK("", lambda *_: None) + if not sdk.cmdline_tools_bin(home_dir): + return False + + for package in MINIMAL_PACKAGES: + if not home_dir.joinpath(*package.split(";")).exists(): + return False + + return True + + def delete_avd(self, home_dir: Path, avd_name: str) -> None: + """ + Deletes an Android Virtual Device using avdmanager. + """ + self.log(f'Deleting Android emulator "{avd_name}"') + result = self.run( + [ + self.avdmanager_exe(home_dir), + "delete", + "avd", + "-n", + avd_name, + ], + env={"ANDROID_HOME": str(home_dir)}, + capture_output=True, + ) + if result.returncode != 0: + self.log(result.stderr or result.stdout) + raise RuntimeError(f'Failed to delete Android emulator "{avd_name}"') + def cmdline_tools_url(self): + """ + Build the command-line tools archive URL for the current platform. + + Returns: + Download URL for Android command-line tools. + + Raises: + RuntimeError: If the current platform or architecture is unsupported. + """ + try: url_platform = { "Darwin": { @@ -98,7 +232,7 @@ def cmdline_tools_url(self): }, }[platform.system()][platform.machine()] except KeyError: - raise Exception( + raise RuntimeError( f"Unsupported platform: {platform.system()}-{platform.machine()}" ) from None @@ -108,6 +242,17 @@ def cmdline_tools_url(self): ) def install(self): + """ + Ensure Android command-line tools and required SDK packages are installed. + + The method locates an SDK home (or chooses a default path), installs + command-line tools if needed, installs all entries in `MINIMAL_PACKAGES`, + and accepts licenses when new packages are installed. + + Returns: + Android SDK home directory as a string. + """ + home_dir = AndroidSDK.android_home_dir() install = True if not home_dir: @@ -136,6 +281,13 @@ def install(self): return str(home_dir) def _install_cmdlinetools(self, android_home: Path): + """ + Download and extract Android command-line tools into `android_home`. + + Args: + android_home: SDK home directory where `cmdline-tools` is created. + """ + archive_path = os.path.join(tempfile.gettempdir(), "commandlinetools.zip") url = self.cmdline_tools_url() self.log(f"Downloading Android cmdline tools from {url}...") @@ -154,6 +306,20 @@ def _install_cmdlinetools(self, android_home: Path): os.remove(archive_path) def _install_package(self, home_dir: Path, package_name: str) -> int: + """ + Install a single SDK package when it is not already present. + + Args: + home_dir: Android SDK home directory. + package_name: SDK package identifier accepted by `sdkmanager`. + + Returns: + `1` when installation was performed, `0` when already installed. + + Raises: + RuntimeError: If package installation fails. + """ + if home_dir.joinpath(*package_name.split(";")).exists(): self.log(f'Android SDK package "{package_name}" is already installed') return 0 @@ -183,10 +349,20 @@ def _install_package(self, home_dir: Path, package_name: str) -> int: ) if p.returncode != 0: self.log(p.stderr) - raise Exception("Error installing Android SDK tools") + raise RuntimeError("Error installing Android SDK tools") return 1 def _accept_licenses(self, home_dir: Path): + """ + Accept Android SDK licenses non-interactively. + + Args: + home_dir: Android SDK home directory. + + Raises: + RuntimeError: If license acceptance fails. + """ + self.log("Accepting Android SDK licenses") p = self.run( @@ -208,9 +384,22 @@ def _accept_licenses(self, home_dir: Path): ) if p.returncode != 0: self.log(p.stderr) - raise Exception("Error accepting Android SDK licenses") + raise RuntimeError("Error accepting Android SDK licenses") def get_installed_packages(self, home_dir: Path): + """ + Query installed SDK packages using `sdkmanager`. + + Args: + home_dir: Android SDK home directory. + + Returns: + Command output listing installed packages. + + Raises: + RuntimeError: If querying installed packages fails. + """ + self.log("Checking installed Android APIs and build tools") p = self.run( [self.sdkmanager_exe(home_dir), "--list_installed"], @@ -219,12 +408,28 @@ def get_installed_packages(self, home_dir: Path): ) if p.returncode != 0: self.log(p.stderr) - raise Exception( + raise RuntimeError( "Error retrieving the list of installed Android SDK packages" ) return p.stdout def run(self, args, env=None, cwd=None, capture_output=True): + """ + Run a subprocess configured for Android SDK tooling. + + `JAVA_HOME` is always injected from this instance, then merged with + any additional environment entries. + + Args: + args: Command arguments passed to the subprocess helper. + env: Optional additional environment variables. + cwd: Optional working directory. Defaults to current directory. + capture_output: Forwarded to subprocess helper. + + Returns: + Subprocess result object returned by `flet_cli.utils.processes.run`. + """ + self.log(f"Run subprocess: {args}") cmd_env = {"JAVA_HOME": self.java_home} diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/cli.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/cli.py new file mode 100644 index 0000000000..25343015aa --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/cli.py @@ -0,0 +1,8 @@ +def parse_cli_bool_value(value: str) -> bool: + """Parse a CLI boolean value, accepting only true/false tokens.""" + normalized = value.strip().lower() + if normalized == "true": + return True + if normalized == "false": + return False + raise ValueError("expected true or false") diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py index 89b97cee6a..cdce7d1426 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/distros.py @@ -25,9 +25,14 @@ def download_with_progress(url, dest_path, progress: Optional[Progress] = None): def extract_with_progress( - archive_path, extract_to, progress: Optional[Progress] = None + archive_path, + extract_to, + progress: Optional[Progress] = None, ): - """Extracts an archive with a progress bar and preserves file attributes, including symbolic links.""" + """ + Extracts an archive with a progress bar and preserves file attributes, + including symbolic links. + """ if archive_path.endswith(".zip"): with zipfile.ZipFile(archive_path, "r") as archive: total_files = len(archive.namelist()) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py index 46d9155379..92e143d548 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/flutter.py @@ -4,10 +4,11 @@ from pathlib import Path from typing import Optional -from flet_cli.utils.distros import download_with_progress, extract_with_progress from rich.console import Console from rich.progress import Progress +from flet_cli.utils.distros import download_with_progress, extract_with_progress + def get_flutter_url(version): """Determines the Flutter archive URL based on the platform.""" @@ -28,9 +29,40 @@ def get_flutter_url(version): raise ValueError(f"Unsupported platform: {system}") +def get_flutter_dir(version): + """ + Return the local install directory for a specific SDK version. + + Args: + version: SDK version string. + + Returns: + Absolute path under the user's home directory: `~/flutter/`. + """ + + home_dir = Path.home() + return os.path.join(home_dir, "flutter", version) + + def install_flutter(version, log, progress: Optional[Progress] = None): + """ + Ensure the requested SDK version is installed and return its directory. + + If the version is not present, this function downloads the platform archive, + extracts it into a temporary directory, moves the extracted runtime to + `~/flutter/`, and removes temporary files. + + Args: + version: SDK version string to install. + log: Callback used for status messages. + progress: Optional rich progress instance used for download/extract UI. + + Returns: + Absolute path to the installed SDK directory. + """ + + install_dir = get_flutter_dir(version) home_dir = Path.home() - install_dir = os.path.join(home_dir, "flutter", version) if not os.path.exists(install_dir): url = get_flutter_url(version) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/hash_stamp.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/hash_stamp.py index 9b8d6a9079..48ee59da97 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/hash_stamp.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/hash_stamp.py @@ -3,20 +3,48 @@ class HashStamp: + """ + Track a SHA-256 digest and persist it to a stamp file. + + A `HashStamp` instance is typically used to detect whether a set of values + has changed since the last run. + """ + def __init__(self, path) -> None: self._path = path self._hash = hashlib.sha256() def update(self, data): + """ + Add a value to the current digest state. + + Args: + data: Value to include in the hash. `None` values are ignored. + """ + if data is not None: self._hash.update(str(data).encode()) def has_changed(self): + """ + Check whether the current digest differs from the stored stamp. + + Returns: + `True` if the current digest does not match the stamp file content; + otherwise `False`. + """ + hash_file = Path(self._path) last_hash = hash_file.read_text() if hash_file.exists() else "" return self._hash.hexdigest() != last_hash def commit(self): + """ + Persist the current digest value to the stamp file. + + Parent directories are created automatically when needed. + """ + hash_file = Path(self._path) hash_file.parent.mkdir(parents=True, exist_ok=True) hash_file.write_text(self._hash.hexdigest()) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/jdk.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/jdk.py index 30abc35852..228adb4eb5 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/jdk.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/jdk.py @@ -6,10 +6,11 @@ from pathlib import Path from typing import Optional -from flet_cli.utils.distros import download_with_progress, extract_with_progress from rich.console import Console from rich.progress import Progress +from flet_cli.utils.distros import download_with_progress, extract_with_progress + # Constants JDK_MAJOR_VER = 17 JDK_RELEASE = "17.0.13" @@ -18,10 +19,28 @@ def get_java_home(): + """ + Return the `JAVA_HOME` environment variable value, if set. + + Returns: + The configured Java home directory or `None`. + """ + return os.getenv("JAVA_HOME") def check_jdk_version(jdk_path): + """ + Verify that a Java installation at `jdk_path` matches the required major version. + + Args: + jdk_path: Java home directory containing `bin/javac`. + + Returns: + `True` when the detected major version equals `JDK_MAJOR_VER`, + otherwise `False`. + """ + try: result = subprocess.run( [os.path.join(jdk_path, "bin", "javac"), "-version"], @@ -66,6 +85,23 @@ def platform_info(): def install_jdk(log, progress: Optional[Progress] = None): + """ + Ensure a compatible JDK is available and return its home directory. + + Resolution order: + - Use `JAVA_HOME` when it points to a matching JDK. + - On macOS, try `/usr/libexec/java_home`. + - Otherwise download and install the configured Temurin JDK release into + `~/java/`. + + Args: + log: Callback used for status messages. + progress: Optional rich progress instance used for download/extract UI. + + Returns: + Java home directory for the installed or discovered JDK. + """ + java_home = get_java_home() # Step 1: Check if JAVA_HOME is set and valid diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/merge.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/merge.py index c761d7dbca..54e741c4f5 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/merge.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/merge.py @@ -1,4 +1,20 @@ def merge_dict(a: dict, b: dict, path=[]): + """ + Recursively merge dictionary `b` into dictionary `a`. + + For keys present in both dictionaries: + - if both values are dictionaries, they are merged recursively; + - otherwise, the value from `b` replaces the value in `a`. + + Args: + a: Destination dictionary that is updated in place. + b: Source dictionary whose values are merged into `a`. + path: Internal recursion path used while descending nested dictionaries. + + Returns: + The updated destination dictionary `a`. + """ + for key in b: if key in a and isinstance(a[key], dict) and isinstance(b[key], dict): merge_dict(a[key], b[key], path + [str(key)]) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/plist.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/plist.py new file mode 100644 index 0000000000..37d0134d0a --- /dev/null +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/plist.py @@ -0,0 +1,42 @@ +try: + import tomllib +except ModuleNotFoundError: + import tomli as tomllib + + +def is_supported_plist_value(value) -> bool: + """Checks if the value is a supported type for plist values.""" + # string and boolean + if isinstance(value, (str, bool)): + return True + # integer and float/real + if isinstance(value, (int, float)): + return True + # array + if isinstance(value, list): + return all(is_supported_plist_value(item) for item in value) + # dictionary + if isinstance(value, dict): + return all( + isinstance(key, str) and is_supported_plist_value(item) + for key, item in value.items() + ) + return False + + +def parse_cli_plist_value(value: str): + """Parses a CLI-provided plist value, supporting TOML syntax for complex types.""" + value = value.strip() + lowered = value.lower() + if lowered in {"true", "false"}: + return lowered == "true" + + try: + parsed = tomllib.loads(f"value = {value}")["value"] + except Exception: + return value + + if is_supported_plist_value(parsed): + return parsed + + return value diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/processes.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/processes.py index 1d46aa008e..cce84bf5e0 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/processes.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/processes.py @@ -9,6 +9,30 @@ def run(args, cwd, env: Optional[dict] = None, capture_output=True, log=None): + """ + Execute a subprocess command with optional streamed logging. + + On Windows, the console output code page is temporarily switched to UTF-8 + while the command runs, then restored. + + Args: + args: Command and arguments passed to the subprocess. + cwd: Working directory for the command. + env: Extra environment variables merged into the current process env. + capture_output: If `True`, run with `subprocess.run` and + capture output in memory. If `False`, stream combined output line by line. + log: Optional callback receiving each output line when `capture_output=False`. + + Returns: + A completed `subprocess.CompletedProcess` + when `capture_output=True`, otherwise a finished + `subprocess.Popen` instance. + + Raises: + KeyboardInterrupt: Re-raised after terminating the child process when + interactive streaming is interrupted. + """ + if is_windows(): # Source: https://stackoverflow.com/a/77374899/1435891 # Save the current console output code page and switch to 65001 (UTF-8) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/project_dependencies.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/project_dependencies.py index f39561bfca..5e0d6f5536 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/project_dependencies.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/project_dependencies.py @@ -2,98 +2,132 @@ # Based on: https://pypi.org/project/toml-to-requirements/ -from __future__ import annotations - +import re from typing import Any, Optional +from packaging.requirements import Requirement + + +def _windows_safe(req_str: str) -> str: + """Insert a space before bare `<` or `>` so Windows cmd.exe does not + interpret them as shell redirection when the string is passed via `-r` + to a `.BAT` subprocess.""" + return re.sub(r"(?<=[^ ])([<>])", r" \1", req_str) + + +def _poetry_version_to_pep440(version: str) -> str: + """Convert a Poetry version constraint to PEP 440 syntax. + + - `^1.2.3` → `>=1.2.3` + - `~1.2.3` → `~=1.2.3` (`~=` passes through unchanged) + - `*` → `""` (no constraint) + - `1.2.3` (bare version) → `==1.2.3` + - Anything else is returned as-is (already PEP 440). + """ + version = version.replace(" ", "") + if not version or version == "*": + return "" + if version.startswith("^"): + return f">={version[1:]}" + if version.startswith("~") and not version.startswith("~="): + return f"~={version[1:]}" + # Bare version number → pin with == + if version[0].isdigit(): + return f"=={version}" + return version + + +def _poetry_dep_to_pep508(name: str, value: Any) -> str: + """Convert a single Poetry dependency entry to a PEP 508 requirement string.""" + suffix = "" + + if isinstance(value, dict): + version = value.get("version") + if version: + specifier = _poetry_version_to_pep440(version) + markers = value.get("markers") + if markers is not None: + suffix = f"; {markers}" + if specifier: + return f"{name}{specifier}{suffix}" + return f"{name}{suffix}" + + git_url = value.get("git") + if git_url: + url = f"git+{git_url}" if not git_url.startswith("git@") else git_url + rev = value.get("branch") or value.get("rev") or value.get("tag") + if rev: + url = f"{url}@{rev}" + subdirectory = value.get("subdirectory") + if subdirectory: + url = f"{url}#subdirectory={subdirectory}" + markers = value.get("markers") + if markers is not None: + suffix = f"; {markers}" + return f"{name} @ {url}{suffix}" + + path = value.get("path") + if path: + return path + + url = value.get("url") + if url: + return url + + raise ValueError(f"Unsupported dependency specification: {name} = {value}") + + # String value + specifier = _poetry_version_to_pep440(value) + if specifier: + return f"{name}{specifier}" + return name + def get_poetry_dependencies( poetry_dependencies: Optional[dict[str, Any]] = None, ) -> Optional[list[str]]: + """ + Convert Poetry dependency declarations into pip-style requirement strings. + + Args: + poetry_dependencies: Value from `tool.poetry.dependencies`. + Returns: + Sorted requirement strings or `None` when `poetry_dependencies` is `None`. + """ if poetry_dependencies is None: return None - def format_dependency_version(dependency_name: str, dependency_value: Any): - sep = "@" - value = "" - suffix = "" - - if isinstance(dependency_value, dict): - version = dependency_value.get("version") - if version: - sep = "==" - value = version - else: - git_url = dependency_value.get("git") - if git_url: - value = ( - f"git+{git_url}" if not git_url.startswith("git@") else git_url - ) - rev = ( - dependency_value.get("branch") - or dependency_value.get("rev") - or dependency_value.get("tag") - ) - if rev: - value = f"{value}@{rev}" - subdirectory = dependency_value.get("subdirectory") - if subdirectory: - value = f"{value}#subdirectory={subdirectory}" - else: - path = dependency_value.get("path") - if path: - value = path - dependency_name = "" - sep = "" - else: - url = dependency_value.get("url") - if url: - value = url - dependency_name = "" - sep = "" - else: - raise Exception( - f"Unsupported dependency specification: {dependency_name} = {dependency_value}" - ) - - # markers - common for all - markers = dependency_value.get("markers") - if markers is not None: - suffix = f";{markers}" - else: - value = dependency_value - sep = "==" - - if value.startswith("^"): - sep = ">=" - value = value[1:] - elif value.startswith("~"): - sep = "~=" - value = value[1:] - return f"{dependency_name}~={value[1:]}" - elif "<" in value or ">" in value: - sep = "" - value = value.replace(" ", "") - - return f"{dependency_name}{sep}{value}{suffix}" - dependencies: set[str] = { - format_dependency_version(dependency, version) - for dependency, version in poetry_dependencies.items() - if dependency != "python" + _windows_safe(_poetry_dep_to_pep508(dep, ver)) + for dep, ver in poetry_dependencies.items() + if dep != "python" } return sorted(dependencies) def get_project_dependencies( - project_dependencies: Optional[dict[str, Any]] = None, + project_dependencies: Optional[list[str]] = None, ) -> Optional[list[str]]: + """ + Normalize PEP 621 `project.dependencies` into a sorted unique list. + + Args: + project_dependencies: Value from `project.dependencies`. + Returns: + Sorted dependency strings, or `None` when input is `None`. + """ if project_dependencies is None: return None - dependencies = set(project_dependencies) + dependencies: set[str] = set() + for dep in project_dependencies: + try: + req = Requirement(dep) + dependencies.add(_windows_safe(str(req))) + except Exception: + dependencies.add(_windows_safe(dep)) return sorted(dependencies) diff --git a/sdk/python/packages/flet-cli/src/flet_cli/utils/pyproject_toml.py b/sdk/python/packages/flet-cli/src/flet_cli/utils/pyproject_toml.py index 05e5f5b894..44effafa40 100644 --- a/sdk/python/packages/flet-cli/src/flet_cli/utils/pyproject_toml.py +++ b/sdk/python/packages/flet-cli/src/flet_cli/utils/pyproject_toml.py @@ -1,17 +1,42 @@ +import sys from pathlib import Path from typing import Any, Optional -import toml +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib def load_pyproject_toml(project_dir: Path): + """ + Load `pyproject.toml` from `project_dir` and return a section accessor. + + Args: + project_dir: Project root directory that may contain `pyproject.toml`. + + Returns: + A callable `get_pyproject()` that resolves values from the parsed document. + """ + pyproject_toml: Optional[dict[str, Any]] = {} pyproject_toml_file = project_dir.joinpath("pyproject.toml") if pyproject_toml_file.exists(): with pyproject_toml_file.open("r", encoding="utf-8") as f: - pyproject_toml = toml.loads(f.read()) + pyproject_toml = tomllib.loads(f.read()) def get_pyproject(setting: Optional[str] = None): + """ + Return the parsed `pyproject.toml` value for a dotted setting path. + + Args: + setting: Dotted path such as `"tool.poetry.dependencies"`. + When omitted or empty, returns the full parsed document. + + Returns: + The requested value, or `None` when any segment does not exist. + """ + if not setting: return pyproject_toml diff --git a/sdk/python/packages/flet-cli/tests/test_plist.py b/sdk/python/packages/flet-cli/tests/test_plist.py new file mode 100644 index 0000000000..047c4000f9 --- /dev/null +++ b/sdk/python/packages/flet-cli/tests/test_plist.py @@ -0,0 +1,52 @@ +from flet_cli.utils.plist import is_supported_plist_value, parse_cli_plist_value + + +def test_parse_cli_plist_value_supports_strings_and_booleans(): + """Strings and booleans should parse into their respective Python types.""" + assert parse_cli_plist_value("true") is True + assert parse_cli_plist_value("False") is False + assert parse_cli_plist_value("TEAMID.example.app") == "TEAMID.example.app" + + +def test_parse_cli_plist_value_keeps_quoted_literals_as_strings(): + """Quoted literals should remain strings even if they look typed.""" + assert parse_cli_plist_value('"true"') == "true" + assert parse_cli_plist_value('"false"') == "false" + assert parse_cli_plist_value('"42"') == "42" + assert parse_cli_plist_value('"3.14"') == "3.14" + + +def test_parse_cli_plist_value_supports_integers_and_floats(): + """Numeric TOML literals should parse into Python numbers.""" + assert parse_cli_plist_value("42") == 42 + assert parse_cli_plist_value("3.14") == 3.14 + + +def test_parse_cli_plist_value_supports_toml_arrays(): + """TOML arrays should parse into Python lists.""" + assert parse_cli_plist_value('["group.dev.example", "group.dev.shared"]') == [ + "group.dev.example", + "group.dev.shared", + ] + + +def test_parse_cli_plist_value_supports_toml_inline_tables(): + """TOML inline tables should parse into Python dictionaries.""" + assert parse_cli_plist_value('{ "com.apple.mail" = ["compose"] }') == { + "com.apple.mail": ["compose"] + } + + +def test_supported_plist_value_accepts_numbers(): + """The plist validator should accept integer and real values.""" + assert is_supported_plist_value(1) + assert is_supported_plist_value(1.5) + assert is_supported_plist_value(["group.dev.example", 1, 1.5]) + assert is_supported_plist_value({"com.apple.mail": 1}) + + +def test_unsupported_plist_types_are_rejected(): + """The plist validator should reject null values recursively.""" + assert not is_supported_plist_value(None) + assert not is_supported_plist_value(["group.dev.example", None]) + assert not is_supported_plist_value({"com.apple.mail": None}) diff --git a/sdk/python/packages/flet-cli/tests/test_project_dependencies.py b/sdk/python/packages/flet-cli/tests/test_project_dependencies.py new file mode 100644 index 0000000000..900b575b29 --- /dev/null +++ b/sdk/python/packages/flet-cli/tests/test_project_dependencies.py @@ -0,0 +1,241 @@ +"""Tests for project_dependencies module.""" + +import pytest + +from flet_cli.utils.project_dependencies import ( + get_poetry_dependencies, + get_project_dependencies, +) + +# --------------------------------------------------------------------------- +# get_poetry_dependencies +# --------------------------------------------------------------------------- + + +class TestGetPoetryDependencies: + def test_none_returns_none(self): + assert get_poetry_dependencies(None) is None + + def test_empty_dict(self): + assert get_poetry_dependencies({}) == [] + + def test_python_excluded(self): + assert get_poetry_dependencies({"python": "^3.10"}) == [] + + def test_exact_version(self): + result = get_poetry_dependencies({"packaging": "26.0"}) + assert result == ["packaging==26.0"] + + def test_caret(self): + result = get_poetry_dependencies({"urllib3": "^2.6.0"}) + assert result == ["urllib3 >=2.6.0"] + + def test_tilde(self): + result = get_poetry_dependencies({"setuptools": "~82.0.0"}) + assert result == ["setuptools~=82.0.0"] + + def test_tilde_equals_passthrough(self): + result = get_poetry_dependencies({"setuptools": "~=82.0.0"}) + assert result == ["setuptools~=82.0.0"] + + def test_wildcard(self): + result = get_poetry_dependencies({"boto3": "*"}) + assert result == ["boto3"] + + def test_less_than(self): + result = get_poetry_dependencies({"chardet": "<6"}) + assert result == ["chardet <6"] + + def test_less_than_equal(self): + result = get_poetry_dependencies({"requests": "<=2.32.4"}) + assert result == ["requests <=2.32.4"] + + def test_greater_than_equal(self): + result = get_poetry_dependencies({"certifi": ">=2026.1.4"}) + assert result == ["certifi >=2026.1.4"] + + def test_range_constraint(self): + result = get_poetry_dependencies({"pydantic": ">=2.9.0,<3.0.0"}) + # _windows_safe ensures spaces before < and > + assert "pydantic" in result[0] + assert " >=" in result[0] + assert " <" in result[0] + + def test_not_equal_combined(self): + result = get_poetry_dependencies({"pandas": ">=2.3,!=2.3.3"}) + assert "pandas" in result[0] + assert " >=" in result[0] + assert "!=" in result[0] + + def test_spaces_in_version_stripped(self): + result = get_poetry_dependencies({"chardet": " < 6 "}) + assert result == ["chardet <6"] + + def test_dict_version(self): + result = get_poetry_dependencies( + {"scipy": {"version": "^1.16", "optional": True}} + ) + assert result == ["scipy >=1.16"] + + def test_dict_version_with_markers(self): + result = get_poetry_dependencies( + {"pywin32": {"version": ">=310", "markers": "sys_platform == 'win32'"}} + ) + assert result == ["pywin32 >=310; sys_platform == 'win32'"] + + def test_dict_git(self): + result = get_poetry_dependencies( + {"numpy": {"git": "https://github.com/numpy/numpy.git", "branch": "main"}} + ) + assert result == ["numpy @ git+https://github.com/numpy/numpy.git@main"] + + def test_dict_git_ssh(self): + result = get_poetry_dependencies( + {"mylib": {"git": "git@github.com:org/repo.git", "tag": "v1.0"}} + ) + assert result == ["mylib @ git@github.com:org/repo.git@v1.0"] + + def test_dict_git_subdirectory(self): + result = get_poetry_dependencies( + { + "mylib": { + "git": "https://github.com/org/mono.git", + "branch": "main", + "subdirectory": "packages/mylib", + } + } + ) + assert "subdirectory=packages/mylib" in result[0] + + def test_dict_path(self): + result = get_poetry_dependencies({"mylib": {"path": "../mylib"}}) + assert result == ["../mylib"] + + def test_dict_url(self): + result = get_poetry_dependencies( + {"mylib": {"url": "https://example.com/mylib.tar.gz"}} + ) + assert result == ["https://example.com/mylib.tar.gz"] + + def test_dict_unsupported_raises(self): + with pytest.raises(ValueError, match="Unsupported"): + get_poetry_dependencies({"bad": {"extras": ["foo"]}}) + + def test_sorted_output(self): + result = get_poetry_dependencies({"zlib": "1.0", "aiohttp": "3.0"}) + assert result == ["aiohttp==3.0", "zlib==1.0"] + + def test_multiple_deps(self): + deps = { + "python": "^3.10", + "boto3": "*", + "chardet": "<6", + "packaging": "26.0", + } + result = get_poetry_dependencies(deps) + assert "boto3" in result + assert any("chardet" in r for r in result) + assert any("packaging" in r for r in result) + # python should be excluded + assert not any("python" in r for r in result) + + +# --------------------------------------------------------------------------- +# get_project_dependencies +# --------------------------------------------------------------------------- + + +class TestGetProjectDependencies: + def test_none_returns_none(self): + assert get_project_dependencies(None) is None + + def test_empty_list(self): + assert get_project_dependencies([]) == [] + + def test_simple_dep(self): + result = get_project_dependencies(["boto3"]) + assert result == ["boto3"] + + def test_exact_version(self): + result = get_project_dependencies(["packaging==26.0"]) + assert result == ["packaging==26.0"] + + def test_gte(self): + result = get_project_dependencies(["flet>=0.82.0"]) + assert result == ["flet >=0.82.0"] + + def test_lt_gets_space(self): + result = get_project_dependencies(["chardet<6"]) + assert result == ["chardet <6"] + + def test_lte_gets_space(self): + result = get_project_dependencies(["requests<=2.32.4"]) + assert result == ["requests <=2.32.4"] + + def test_gt_gets_space(self): + result = get_project_dependencies(["chardet>3"]) + assert result == ["chardet >3"] + + def test_combined_constraints(self): + result = get_project_dependencies(["pydantic>=2.9.0,<3.0.0"]) + assert len(result) == 1 + dep = result[0] + assert "pydantic" in dep + assert " <" in dep or " >" in dep + + def test_not_equal(self): + result = get_project_dependencies(["pandas>=2.3,!=2.3.3"]) + assert len(result) == 1 + assert " >=" in result[0] + assert "!=" in result[0] + + def test_compatible_release(self): + result = get_project_dependencies(["setuptools~=82.0.0"]) + assert result == ["setuptools~=82.0.0"] + + def test_extras(self): + result = get_project_dependencies(["uvicorn[standard]>=0.42.0"]) + dep = result[0] + assert "uvicorn" in dep + assert "[standard]" in dep + assert " >=" in dep + + def test_markers_preserved(self): + result = get_project_dependencies(['pywin32>=310; sys_platform == "win32"']) + assert len(result) == 1 + assert "sys_platform" in result[0] + assert "win32" in result[0] + assert " >=" in result[0] + + def test_url_dep(self): + result = get_project_dependencies( + ["numpy @ git+https://github.com/numpy/numpy.git@main"] + ) + assert len(result) == 1 + assert "git+https://github.com/numpy/numpy.git@main" in result[0] + + def test_extra_spaces_normalized(self): + result = get_project_dependencies(["chardet < 6"]) + assert result == ["chardet <6"] + + def test_sorted_and_deduplicated(self): + result = get_project_dependencies(["zlib>=1.0", "aiohttp>=3.0", "zlib>=1.0"]) + assert result[0].startswith("aiohttp") + assert len(result) == 2 + + def test_downstream_compatible(self): + """Output must be parseable by packaging.requirements.Requirement, + since build_base.py does Requirement(dep).name on our output.""" + from packaging.requirements import Requirement + + deps = [ + "flet>=0.82.0", + "chardet<6", + "pydantic>=2.9.0,<3.0.0", + 'pywin32>=310; sys_platform == "win32"', + "uvicorn[standard]>=0.42.0", + ] + result = get_project_dependencies(deps) + for dep in result: + req = Requirement(dep) + assert req.name # must parse without error diff --git a/sdk/python/packages/flet-code-editor/CHANGELOG.md b/sdk/python/packages/flet-code-editor/CHANGELOG.md new file mode 100644 index 0000000000..3fe25dc7ff --- /dev/null +++ b/sdk/python/packages/flet-code-editor/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.85.0 + +### Added + +- `issues` property on `CodeEditor` for displaying code analysis error markers in the gutter, along with new `Issue` and `IssueType` types. Analysis is performed on the Python side via `on_change` and pushed to the editor. + +### Fixed + +- `CodeEditor` background not filling the entire area when `expand=True`. + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-code-editor/LICENSE b/sdk/python/packages/flet-code-editor/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-code-editor/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-code-editor/README.md b/sdk/python/packages/flet-code-editor/README.md new file mode 100644 index 0000000000..cb9318b7fe --- /dev/null +++ b/sdk/python/packages/flet-code-editor/README.md @@ -0,0 +1,34 @@ +# flet-code-editor + +[![pypi](https://img.shields.io/pypi/v/flet-code-editor.svg)](https://pypi.python.org/pypi/flet-code-editor) +[![downloads](https://static.pepy.tech/badge/flet-code-editor/month)](https://pepy.tech/project/flet-code-editor) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-code-editor/LICENSE) + +A [Flet](https://flet.dev) extension for editing and highlighting source code. + +It is based on the [flutter_code_editor](https://pub.dev/packages/flutter_code_editor) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/codeeditor/). + +## Usage + +### Installation + +To install the `flet-code-editor` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-code-editor + ``` + +- Using `pip`: + ```bash + pip install flet-code-editor + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/code_editor). diff --git a/sdk/python/packages/flet-code-editor/pyproject.toml b/sdk/python/packages/flet-code-editor/pyproject.toml new file mode 100644 index 0000000000..59076c9cb6 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-code-editor" +version = "0.1.0" +description = "Edit and highlight source code inside Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/codeeditor" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-code-editor" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_code_editor" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-code-editor/src/flet_code_editor/__init__.py b/sdk/python/packages/flet-code-editor/src/flet_code_editor/__init__.py new file mode 100644 index 0000000000..f7eed2bbc8 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flet_code_editor/__init__.py @@ -0,0 +1,19 @@ +from flet_code_editor.code_editor import CodeEditor +from flet_code_editor.types import ( + CodeLanguage, + CodeTheme, + CustomCodeTheme, + GutterStyle, + Issue, + IssueType, +) + +__all__ = [ + "CodeEditor", + "CodeLanguage", + "CodeTheme", + "CustomCodeTheme", + "GutterStyle", + "Issue", + "IssueType", +] diff --git a/sdk/python/packages/flet-code-editor/src/flet_code_editor/code_editor.py b/sdk/python/packages/flet-code-editor/src/flet_code_editor/code_editor.py new file mode 100644 index 0000000000..88b20a1efe --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flet_code_editor/code_editor.py @@ -0,0 +1,93 @@ +from dataclasses import field +from typing import Optional, Union + +import flet as ft +from flet_code_editor.types import ( + CodeLanguage, + CodeTheme, + CustomCodeTheme, + GutterStyle, + Issue, +) + +__all__ = ["CodeEditor"] + + +@ft.control("CodeEditor") +class CodeEditor(ft.LayoutControl): + """Edit and highlight source code.""" + + language: Optional[CodeLanguage] = None + """ + Syntax highlighting language. + """ + + code_theme: Optional[Union[CodeTheme, CustomCodeTheme]] = None + """ + Syntax highlighting theme. + """ + + text_style: Optional[ft.TextStyle] = None + """Text style for the editor content.""" + + padding: Optional[ft.PaddingValue] = None + """Padding around the editor.""" + + value: Optional[str] = None + """Full text including folded sections and service comments.""" + + selection: Optional[ft.TextSelection] = None + """ + Represents the current text selection or caret position in the editor. + + Setting this property updates the editor selection and may trigger + :attr:`on_selection_change` when the editor is focused. + """ + + gutter_style: Optional[GutterStyle] = None + """Gutter styling.""" + + autocomplete: Optional[bool] = False + """Whether autocomplete is enabled.""" + + autocomplete_words: Optional[list[str]] = None + """Words offered by autocomplete.""" + + issues: list[Issue] = field(default_factory=list) + """List of code analysis issues to display in the editor gutter.""" + + read_only: Optional[bool] = False + """Whether the editor is read-only.""" + + autofocus: Optional[bool] = False + """Whether this editor should focus itself if nothing else is focused.""" + + on_change: Optional[ft.ControlEventHandler["CodeEditor"]] = None + """Called when the editor text changes.""" + + on_selection_change: Optional[ + ft.EventHandler[ft.TextSelectionChangeEvent["CodeEditor"]] + ] = None + """Called when the text selection or caret position changes.""" + + on_focus: Optional[ft.ControlEventHandler["CodeEditor"]] = None + """Called when the editor receives focus.""" + + on_blur: Optional[ft.ControlEventHandler["CodeEditor"]] = None + """Called when the editor loses focus.""" + + async def focus(self): + """Request focus for this editor.""" + await self._invoke_method("focus") + + async def fold_comment_at_line_zero(self): + """Fold the comment block at line 0.""" + await self._invoke_method("fold_comment_at_line_zero") + + async def fold_imports(self): + """Fold import sections.""" + await self._invoke_method("fold_imports") + + async def fold_at(self, line_number: int): + """Fold the block starting at the given line number.""" + await self._invoke_method("fold_at", arguments={"line_number": line_number}) diff --git a/sdk/python/packages/flet-code-editor/src/flet_code_editor/types.py b/sdk/python/packages/flet-code-editor/src/flet_code_editor/types.py new file mode 100644 index 0000000000..bc8da83b84 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flet_code_editor/types.py @@ -0,0 +1,888 @@ +from enum import Enum +from typing import Optional + +import flet as ft +from flet.controls.core.markdown import MarkdownCodeTheme, MarkdownCustomCodeTheme + +__all__ = [ + "CodeLanguage", + "CodeTheme", + "CustomCodeTheme", + "GutterStyle", + "Issue", + "IssueType", +] + + +class CodeLanguage(Enum): + # 1-9 + ONE_C = "1c" + """ + 1C + """ + + # A + ABNF = "abnf" + """ + ABNF + """ + ACCESSLOG = "accesslog" + """ + Accesslog + """ + ACTIONSCRIPT = "actionscript" + """ + ActionScript + """ + ADA = "ada" + """ + Ada + """ + ANGELSCRIPT = "angelscript" + """ + Angelscript + """ + APACHE = "apache" + """ + Apache + """ + APPLESCRIPT = "applescript" + """ + AppleScript + """ + ARCADE = "arcade" + """ + Arcade + """ + ARDUINO = "arduino" + """ + Arduino + """ + ARMASM = "armasm" + """ + ARM Assembly + """ + ASCIIDOC = "asciidoc" + """ + AsciiDoc + """ + ASPECTJ = "aspectj" + """ + Aspectj + """ + AUTOHOTKEY = "autohotkey" + """ + AutoHotkey + """ + AUTOIT = "autoit" + """ + AutoIt + """ + AVRASM = "avrasm" + """ + AVR Assembly + """ + AWK = "awk" + """ + Awk + """ + AXAPTA = "axapta" + """ + Axapta + """ + + # B + BASH = "bash" + """ + Bash + """ + BASIC = "basic" + """ + Basic + """ + BNF = "bnf" + """ + BNF + """ + BRAINFUCK = "brainfuck" + """ + Brainfuck + """ + + # C + CAL = "cal" + """ + Cal + """ + CAPNPROTO = "capnproto" + """ + Cap'n Proto + """ + CEYLON = "ceylon" + """ + Ceylon + """ + CLEAN = "clean" + """ + Clean + """ + CLOJURE = "clojure" + """ + Clojure + """ + CLOJURE_REPL = "clojure-repl" + """ + Clojure REPL + """ + CMAKE = "cmake" + """ + CMake + """ + COFFEESCRIPT = "coffeescript" + """ + CoffeeScript + """ + COQ = "coq" + """ + Coq + """ + COS = "cos" + """ + Cos + """ + CPP = "cpp" + """ + C++ + """ + CRMSH = "crmsh" + """ + Crmsh + """ + CRYSTAL = "crystal" + """ + Crystal + """ + CS = "cs" + """ + C# + """ + CSP = "csp" + """ + Csp + """ + CSS = "css" + """ + CSS + """ + + # D + D = "d" + """ + D + """ + DART = "dart" + """ + Dart + """ + DELPHI = "delphi" + """ + Delphi + """ + DIFF = "diff" + """ + Diff + """ + DJANGO = "django" + """ + Django + """ + DNS = "dns" + """ + DNS + """ + DOCKERFILE = "dockerfile" + """ + Dockerfile + """ + DOS = "dos" + """ + DOS + """ + DSCONFIG = "dsconfig" + """ + DSConfig + """ + DTS = "dts" + """ + DTS + """ + DUST = "dust" + """ + Dust + """ + + # E + EBNF = "ebnf" + """ + EBNF + """ + ELIXIR = "elixir" + """ + Elixir + """ + ELM = "elm" + """ + Elm + """ + ERB = "erb" + """ + Erb + """ + ERLANG = "erlang" + """ + Erlang + """ + ERLANG_REPL = "erlang-repl" + """ + Erlang REPL + """ + EXCEL = "excel" + """ + Excel + """ + + # F + FIX = "fix" + """ + Fix + """ + FLIX = "flix" + """ + Flix + """ + FORTRAN = "fortran" + """ + Fortran + """ + FSHARP = "fsharp" + """ + F# + """ + + # G + GAMS = "gams" + """ + Gams + """ + GAUSS = "gauss" + """ + Gauss + """ + GCODE = "gcode" + """ + G-code + """ + GHERKIN = "gherkin" + """ + Gherkin + """ + GLSL = "glsl" + """ + GLSL + """ + GML = "gml" + """ + GML + """ + GN = "gn" + """ + Gn + """ + GO = "go" + """ + Go + """ + GOLO = "golo" + """ + Golo + """ + GRADLE = "gradle" + """ + Gradle + """ + GRAPHQL = "graphql" + """ + GraphQL + """ + GROOVY = "groovy" + """ + Groovy + """ + + # H + HAML = "haml" + """ + Haml + """ + HANDLEBARS = "handlebars" + """ + Handlebars + """ + HASKELL = "haskell" + """ + Haskell + """ + HAXE = "haxe" + """ + Haxe + """ + HSP = "hsp" + """ + Hsp + """ + HTMLBARS = "htmlbars" + """ + HTMLBars + """ + HTTP = "http" + """ + HTTP + """ + HY = "hy" + """ + Hy + """ + + # I + INFORM7 = "inform7" + """ + INFORM7 + """ + INI = "ini" + """ + INI + """ + IRPF90 = "irpf90" + """ + IRPF90 + """ + ISBL = "isbl" + """ + ISBL + """ + + # J + JAVA = "java" + """ + Java + """ + JAVASCRIPT = "javascript" + """ + Javascript + """ + JBOSS_CLI = "jboss-cli" + """ + JBoss CLI + """ + JSON = "json" + """ + JSON + """ + JULIA = "julia" + """ + Julia + """ + JULIA_REPL = "julia-repl" + """ + Julia REPL + """ + + # K + KOTLIN = "kotlin" + """ + Kotlin + """ + + # L + LASSO = "lasso" + """ + Lasso + """ + LDIF = "ldif" + """ + LDIF + """ + LEAF = "leaf" + """ + Leaf + """ + LESS = "less" + """ + Less + """ + LISP = "lisp" + """ + Lisp + """ + LIVECODESERVER = "livecodeserver" + """ + LiveCode Server + """ + LIVESCRIPT = "livescript" + """ + Livescript + """ + LLVM = "llvm" + """ + LLVM + """ + LSL = "lsl" + """ + LSL + """ + LUA = "lua" + """ + Lua + """ + + # M + MAKEFILE = "makefile" + """ + Makefile + """ + MARKDOWN = "markdown" + """ + Markdown + """ + MATHEMATICA = "mathematica" + """ + Mathematica + """ + MATLAB = "matlab" + """ + Matlab + """ + MAXIMA = "maxima" + """ + Maxima + """ + MEL = "mel" + """ + Mel + """ + MERCURY = "mercury" + """ + Mercury + """ + MIPSASM = "mipsasm" + """ + MIPS Assembly + """ + MIZAR = "mizar" + """ + Mizar + """ + MOJOLICIOUS = "mojolicious" + """ + Mojolicious + """ + MONKEY = "monkey" + """ + Monkey + """ + MOONSCRIPT = "moonscript" + """ + MoonScript + """ + + # N + N1QL = "n1ql" + """ + N1QL + """ + NGINX = "nginx" + """ + Nginx + """ + NIMROD = "nimrod" + """ + Nimrod + """ + NIX = "nix" + """ + Nix + """ + NSIS = "nsis" + """ + NSIS + """ + + # O + OBJECTIVEC = "objectivec" + """ + Objective-C + """ + OCAML = "ocaml" + """ + OCaml + """ + OPENSCAD = "openscad" + """ + OpenSCAD + """ + OXYGENE = "oxygene" + """ + Oxygene + """ + + # P + PARSER3 = "parser3" + """ + PARSER3 + """ + PERL = "perl" + """ + Perl + """ + PF = "pf" + """ + PF + """ + PGSQL = "pgsql" + """ + PostgreSQL + """ + PHP = "php" + """ + PHP + """ + PLAINTEXT = "plaintext" + """ + Plain text + """ + PONY = "pony" + """ + Pony + """ + POWERSHELL = "powershell" + """ + PowerShell + """ + PROCESSING = "processing" + """ + Processing + """ + PROFILE = "profile" + """ + Profile + """ + PROLOG = "prolog" + """ + Prolog + """ + PROPERTIES = "properties" + """ + Properties + """ + PROTOBUF = "protobuf" + """ + Protocol Buffers + """ + PUPPET = "puppet" + """ + Puppet + """ + PUREBASIC = "purebasic" + """ + PureBasic + """ + PYTHON = "python" + """ + Python + """ + + # Q + Q = "q" + """ + Q + """ + QML = "qml" + """ + QML + """ + + # R + R = "r" + """ + R + """ + REASONML = "reasonml" + """ + ReasonML + """ + RIB = "rib" + """ + Rib + """ + ROBOCONF = "roboconf" + """ + Roboconf + """ + ROUTEROS = "routeros" + """ + RouterOS + """ + RSL = "rsl" + """ + RSL + """ + RUBY = "ruby" + """ + Ruby + """ + RULESLANGUAGE = "ruleslanguage" + """ + Rules language + """ + RUST = "rust" + """ + Rust + """ + + # S + SAS = "sas" + """ + SAS + """ + SCALA = "scala" + """ + Scala + """ + SCHEME = "scheme" + """ + Scheme + """ + SCILAB = "scilab" + """ + Scilab + """ + SCSS = "scss" + """ + SCSS + """ + SHELL = "shell" + """ + Shell + """ + SMALI = "smali" + """ + Smali + """ + SMALLTALK = "smalltalk" + """ + Smalltalk + """ + SML = "sml" + """ + SML + """ + SOLIDITY = "solidity" + """ + Solidity + """ + SQF = "sqf" + """ + SQF + """ + SQL = "sql" + """ + SQL + """ + STAN = "stan" + """ + Stan + """ + STATA = "stata" + """ + Stata + """ + STEP21 = "step21" + """ + STEP21 + """ + STYLUS = "stylus" + """ + Stylus + """ + SUBUNIT = "subunit" + """ + SubUnit + """ + SWIFT = "swift" + """ + Swift + """ + + # T + TAGGERSCRIPT = "taggerscript" + """ + Tagger Script + """ + TAP = "tap" + """ + Tap + """ + TCL = "tcl" + """ + Tcl + """ + TEX = "tex" + """ + TeX + """ + THRIFT = "thrift" + """ + Thrift + """ + TP = "tp" + """ + TP + """ + TWIG = "twig" + """ + Twig + """ + TYPESCRIPT = "typescript" + """ + TypeScript + """ + + # V + VALA = "vala" + """ + Vala + """ + VBNET = "vbnet" + """ + VB.NET + """ + VBSCRIPT = "vbscript" + """ + VBScript + """ + VBSCRIPT_HTML = "vbscript-html" + """ + VBScript HTML + """ + VERILOG = "verilog" + """ + Verilog + """ + VHDL = "vhdl" + """ + VHDL + """ + VIM = "vim" + """ + Vim script + """ + VUE = "vue" + """ + Vue + """ + + # X + X86ASM = "x86asm" + """ + x86 Assembly + """ + XL = "xl" + """ + Xl + """ + XML = "xml" + """ + XML + """ + XQUERY = "xquery" + """ + XQuery + """ + + # Y + YAML = "yaml" + """ + YAML + """ + + # Z + ZEPHIR = "zephir" + """ + Zephir + """ + + +CodeTheme = MarkdownCodeTheme +"""Alias for `flet.MarkdownCodeTheme`.""" + +CustomCodeTheme = MarkdownCustomCodeTheme +"""Alias for `flet.MarkdownCustomCodeTheme`.""" + + +@ft.value +class GutterStyle: + """Defines gutter appearance (line numbers) for the code editor.""" + + text_style: Optional[ft.TextStyle] = None + """Text style for line numbers.""" + + background_color: Optional[ft.ColorValue] = None + """Background color for the gutter.""" + + width: Optional[ft.Number] = None + """Fixed width of the gutter.""" + + margin: Optional[ft.Number] = None + """Margin outside the gutter.""" + + show_errors: bool = True + """Whether to show errors in the gutter.""" + + show_folding_handles: bool = True + """Whether to show folding handles in the gutter.""" + + show_line_numbers: bool = True + """Whether to show line numbers in the gutter.""" + + +class IssueType(Enum): + """Severity level of a code analysis issue.""" + + ERROR = "error" + """Error severity.""" + + WARNING = "warning" + """Warning severity.""" + + INFO = "info" + """Informational severity.""" + + +@ft.value +class Issue: + """A code analysis issue displayed in the editor gutter.""" + + line: int = 0 + """0-indexed line number where the issue occurs.""" + + message: str = "" + """Description of the issue.""" + + type: Optional[IssueType] = None + """Severity level: error, warning, or info.""" + + suggestion: Optional[str] = None + """Optional suggested fix.""" + + url: Optional[str] = None + """Optional URL for more information.""" diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/.gitignore b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/.metadata b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/.metadata new file mode 100644 index 0000000000..07d8623a38 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2e9cb0aa71a386a91f73f7088d115c0d96654829" + channel: "stable" + +project_type: package diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/analysis_options.yaml b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/flet_code_editor.dart b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/flet_code_editor.dart new file mode 100644 index 0000000000..59c49b6b56 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/flet_code_editor.dart @@ -0,0 +1,3 @@ +library flet_code_editor; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/code_editor.dart b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/code_editor.dart new file mode 100644 index 0000000000..7b0be51f67 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/code_editor.dart @@ -0,0 +1,262 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart' as fce; +import 'package:highlight/languages/all.dart'; + +import 'utils/code_editor.dart'; +import 'utils/flet_code_controller.dart'; + +class CodeEditorControl extends StatefulWidget { + final Control control; + + const CodeEditorControl({super.key, required this.control}); + + @override + State createState() => _CodeEditorControlState(); +} + +class _CodeEditorControlState extends State { + late FletCodeController _controller; + late final FocusNode _focusNode; + bool _didAutoFocus = false; + TextSelection? _selection; + String _value = ""; + String? _languageName; + + @override + void initState() { + super.initState(); + _focusNode = FocusNode(); + _focusNode.addListener(_onFocusChange); + _controller = _createController(); + _value = _readValue(); + _selection = _controller.selection; + _controller.addListener(_handleControllerChange); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + @override + void dispose() { + _controller.removeListener(_handleControllerChange); + _controller.dispose(); + _focusNode.removeListener(_onFocusChange); + _focusNode.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("CodeEditor.$name($args)"); + switch (name) { + case "focus": + _focusNode.requestFocus(); + break; + case "fold_comment_at_line_zero": + _controller.foldCommentAtLineZero(); + break; + case "fold_imports": + _controller.foldImports(); + break; + case "fold_at": + final line = parseInt(args["line_number"]); + if (line != null) { + _controller.foldAt(line); + } + break; + default: + throw Exception("Unknown CodeEditor method: $name"); + } + } + + void _onFocusChange() { + widget.control.triggerEvent(_focusNode.hasFocus ? "focus" : "blur"); + } + + FletCodeController _createController() { + _languageName = widget.control.get("language", "")!; + return FletCodeController( + text: _initialValueFromControl(), + language: allLanguages[_languageName!.toLowerCase()], + ); + } + + String _initialValueFromControl() { + return widget.control.getString("value") ?? ""; + } + + List? _stringList(dynamic value) { + if (value is List) { + return value.map((e) => e.toString()).toList(); + } + return null; + } + + String _readValue() => _controller.fullText; + + void _setValue(String value) { + _controller.fullText = value; + } + + void _handleControllerChange() { + final value = _readValue(); + final selection = _controller.selection; + final selectionChanged = selection != _selection; + final valueChanged = value != _value; + + if (!valueChanged && !selectionChanged) { + return; + } + + _value = value; + _selection = selection; + + final updates = {}; + + if (valueChanged) { + updates["value"] = value; + } + + if (selectionChanged) { + if (selection.isValid) { + updates["selection"] = selection.toMap(); + } else { + updates["selection"] = null; + } + } + + if (updates.isNotEmpty) { + widget.control.updateProperties(updates); + } + + if (valueChanged && widget.control.getBool("on_change", false)!) { + widget.control.triggerEvent("change", value); + } + + if (selectionChanged && selection.isValid) { + final visibleText = _controller.text; + widget.control.triggerEvent("selection_change", { + "selected_text": visibleText.substring(selection.start, selection.end), + "selection": selection.toMap(), + }); + } + } + + @override + Widget build(BuildContext context) { + debugPrint("CodeEditor build: ${widget.control.id}"); + + final languageName = widget.control.get("language", "")!; + if (languageName != _languageName) { + final previousSelection = _controller.selection; + _controller.removeListener(_handleControllerChange); + _controller.dispose(); + _controller = _createController(); + _value = _readValue(); + _controller.addListener(_handleControllerChange); + if (previousSelection.isValid) { + _controller.selection = previousSelection; + } + } + + final value = widget.control.getString("value"); + final controllerValue = _readValue(); + if (value != null && value != controllerValue) { + _setValue(value); + _value = value; + } + + final explicitSelection = widget.control.getTextSelection( + "selection", + minOffset: 0, + maxOffset: _controller.text.length, + ); + if (explicitSelection != null && + explicitSelection != _controller.selection) { + _controller.selection = explicitSelection; + } + + final autofocus = widget.control.getBool("autofocus", false)!; + if (!_didAutoFocus && autofocus) { + _didAutoFocus = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + FocusScope.of(context).autofocus(_focusNode); + } + }); + } + + final themeData = parseCodeThemeData(widget.control, context); + final gutterStyle = parseGutterStyle(widget.control, context); + final autocompleteEnabled = widget.control.getBool("autocomplete", false)!; + final autocompleteWords = + _stringList(widget.control.get("autocomplete_words")) ?? const []; + _controller.autocompletionEnabled = autocompleteEnabled; + if (autocompleteEnabled) { + _controller.autocompleter.setCustomWords(autocompleteWords); + } else { + _controller.autocompleter.setCustomWords(const []); + _controller.popupController.hide(); + } + + // Apply issues from Python side + final issuesList = widget.control.get("issues"); + final List parsedIssues; + if (issuesList is List) { + parsedIssues = issuesList + .whereType() + .map((item) => fce.Issue( + line: parseInt(item["line"]) ?? 0, + message: item["message"]?.toString() ?? "", + type: parseEnum(fce.IssueType.values, item["type"]?.toString(), fce.IssueType.error)!, + suggestion: item["suggestion"]?.toString(), + url: item["url"]?.toString(), + )) + .toList(); + } else { + parsedIssues = const []; + } + final prevIssueCount = _controller.analysisResult.issues.length; + if (parsedIssues.length != prevIssueCount || parsedIssues.isNotEmpty) { + _controller.removeListener(_handleControllerChange); + _controller.setIssues(fce.AnalysisResult(issues: parsedIssues)); + _controller.addListener(_handleControllerChange); + } + + Widget buildEditor({double? minHeight}) { + Widget editor = SingleChildScrollView( + child: ConstrainedBox( + constraints: BoxConstraints(minHeight: minHeight ?? 0), + child: fce.CodeField( + controller: _controller, + focusNode: _focusNode, + readOnly: widget.control.getBool("read_only", false)!, + textStyle: + widget.control.getTextStyle("text_style", Theme.of(context)), + gutterStyle: gutterStyle, + padding: widget.control.getEdgeInsets("padding", EdgeInsets.zero)!, + enabled: !widget.control.disabled, + ), + )); + + if (themeData != null) { + editor = fce.CodeTheme(data: themeData, child: editor); + } + + return editor; + } + + final isExpanded = widget.control.getExpand("expand") != null; + + Widget child; + if (isExpanded) { + child = LayoutBuilder( + builder: (context, constraints) => + buildEditor(minHeight: constraints.maxHeight), + ); + } else { + child = buildEditor(); + } + + return LayoutControl(control: widget.control, child: child); + } +} diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/extension.dart b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/extension.dart new file mode 100644 index 0000000000..15f3b8e4ba --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/extension.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; + +import 'code_editor.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "CodeEditor": + return CodeEditorControl(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/utils/code_editor.dart b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/utils/code_editor.dart new file mode 100644 index 0000000000..ce8a7b9c60 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/utils/code_editor.dart @@ -0,0 +1,87 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart' as fce; +import 'package:flutter_highlight/theme_map.dart'; + +fce.CodeThemeData? parseCodeThemeData(Control control, BuildContext context) { + final codeTheme = control.get("code_theme"); + if (codeTheme is! Map) { + if (codeTheme is String) { + final named = themeMap[codeTheme.toLowerCase()]; + return named == null ? null : fce.CodeThemeData(styles: named); + } + return null; + } + + final themeName = codeTheme["name"]; + if (themeName is String) { + final named = themeMap[themeName.toLowerCase()]; + if (named != null) { + return fce.CodeThemeData(styles: named); + } + } + + final styles = codeTheme["styles"]; + final Map stylesSource; + if (styles is Map) { + stylesSource = styles.cast(); + } else { + // CustomCodeTheme is serialized as a flat map of token -> TextStyle. + final flattened = Map.of(codeTheme); + flattened.remove("name"); + stylesSource = flattened; + } + + final parsedStyles = {}; + stylesSource.forEach((key, value) { + final style = parseTextStyle(value, Theme.of(context)); + if (style != null) { + parsedStyles[key.toString()] = style; + } + }); + + if (parsedStyles.isEmpty) { + return null; + } + + return fce.CodeThemeData(styles: parsedStyles); +} + +fce.GutterStyle? parseGutterStyle(Control control, BuildContext context) { + final gutterStyle = control.get("gutter_style"); + if (gutterStyle is! Map) { + return null; + } + + final textStyle = parseTextStyle(gutterStyle["text_style"], Theme.of(context)); + final background = + parseColor(gutterStyle["background_color"], Theme.of(context)); + final width = parseDouble(gutterStyle["width"]); + final margin = _parseGutterMargin(gutterStyle["margin"]); + + final showErrors = gutterStyle["show_errors"]; + final showFoldingHandles = gutterStyle["show_folding_handles"]; + final showLineNumbers = gutterStyle["show_line_numbers"]; + + return fce.GutterStyle( + textStyle: textStyle, + background: background, + width: width ?? 80.0, + margin: margin ?? 10.0, + showErrors: showErrors is bool ? showErrors : true, + showFoldingHandles: showFoldingHandles is bool ? showFoldingHandles : true, + showLineNumbers: showLineNumbers is bool ? showLineNumbers : true, + ); +} + +double? _parseGutterMargin(dynamic value) { + final margin = parseDouble(value); + if (margin != null) { + return margin; + } + final edgeInsets = parseEdgeInsets(value); + if (edgeInsets == null) { + return null; + } + return (edgeInsets.left + edgeInsets.right) / 2; +} diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/utils/flet_code_controller.dart b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/utils/flet_code_controller.dart new file mode 100644 index 0000000000..0277e55a55 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/lib/src/utils/flet_code_controller.dart @@ -0,0 +1,64 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_code_editor/flutter_code_editor.dart' as fce; + +class FletCodeController extends fce.CodeController { + FletCodeController({ + super.text, + super.language, + }); + + bool autocompletionEnabled = false; + + @override + Future analyzeCode() async { + // Analysis is handled by the Python side via the issues property. + } + + void setIssues(fce.AnalysisResult result) { + analysisResult = result; + notifyListeners(); + } + + @override + Future generateSuggestions() async { + if (!autocompletionEnabled) { + popupController.hide(); + return; + } + return super.generateSuggestions(); + } + + @override + void insertSelectedWord() { + final previousSelection = selection; + final selectedWord = popupController.getSelectedWord(); + final startPosition = value.wordAtCursorStart; + final currentWord = value.wordAtCursor; + + if (startPosition == null || currentWord == null) { + popupController.hide(); + return; + } + + final endReplacingPosition = startPosition + currentWord.length; + final endSelectionPosition = startPosition + selectedWord.length; + + final replacedText = text.replaceRange( + startPosition, + endReplacingPosition, + selectedWord, + ); + + final adjustedSelection = previousSelection.copyWith( + baseOffset: endSelectionPosition, + extentOffset: endSelectionPosition, + ); + + value = TextEditingValue( + text: replacedText, + selection: adjustedSelection, + ); + + popupController.hide(); + } +} diff --git a/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/pubspec.yaml b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/pubspec.yaml new file mode 100644 index 0000000000..68778cf209 --- /dev/null +++ b/sdk/python/packages/flet-code-editor/src/flutter/flet_code_editor/pubspec.yaml @@ -0,0 +1,28 @@ +name: flet_code_editor +description: Flet CodeEditor control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + flutter_code_editor: + git: + url: https://github.com/flet-dev/flutter-code-editor + ref: pinyin-fix + + flutter_highlight: ^0.7.0 + highlight: ^0.7.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-color-pickers/CHANGELOG.md b/sdk/python/packages/flet-color-pickers/CHANGELOG.md new file mode 100644 index 0000000000..621a0dbdaa --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 0.1.0 + +- Initial release. diff --git a/sdk/python/packages/flet-color-pickers/LICENSE b/sdk/python/packages/flet-color-pickers/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-color-pickers/README.md b/sdk/python/packages/flet-color-pickers/README.md new file mode 100644 index 0000000000..9746f01a2c --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/README.md @@ -0,0 +1,42 @@ +# flet-color-pickers + +[![pypi](https://img.shields.io/pypi/v/flet-color-pickers.svg)](https://pypi.python.org/pypi/flet-color-pickers) +[![downloads](https://static.pepy.tech/badge/flet-color-pickers/month)](https://pepy.tech/project/flet-color-pickers) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-color-pickers) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-color-pickers.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-color-pickers.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-color-pickers/LICENSE) + +A [Flet](https://flet.dev) extension package for picking colors. + +It is based on the [flutter_colorpicker](https://pub.dev/packages/flutter_colorpicker) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/colorpickers/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-color-pickers` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-color-pickers + ``` + +- Using `pip`: + ```bash + pip install flet-color-pickers + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/color_pickers). diff --git a/sdk/python/packages/flet-color-pickers/pyproject.toml b/sdk/python/packages/flet-color-pickers/pyproject.toml new file mode 100644 index 0000000000..c199f9e237 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-color-pickers" +version = "0.1.0" +description = "Pick colors in Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/colorpickers" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-color-pickers" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_color_pickers" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/__init__.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/__init__.py new file mode 100644 index 0000000000..671a4caa85 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/__init__.py @@ -0,0 +1,24 @@ +from flet_color_pickers.block_picker import BlockPicker +from flet_color_pickers.color_picker import ( + ColorLabelType, + ColorPicker, + HsvColor, + PaletteType, +) +from flet_color_pickers.hue_ring_picker import HueRingPicker +from flet_color_pickers.material_picker import MaterialPicker +from flet_color_pickers.multiple_choice_block_picker import MultipleChoiceBlockPicker +from flet_color_pickers.slide_picker import ColorModel, SlidePicker + +__all__ = [ + "BlockPicker", + "ColorLabelType", + "ColorModel", + "ColorPicker", + "HsvColor", + "HueRingPicker", + "MaterialPicker", + "MultipleChoiceBlockPicker", + "PaletteType", + "SlidePicker", +] diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/block_picker.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/block_picker.py new file mode 100644 index 0000000000..0b504aaecc --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/block_picker.py @@ -0,0 +1,31 @@ +from typing import Optional + +import flet as ft + +__all__ = ["BlockPicker"] + + +@ft.control("BlockPicker") +class BlockPicker(ft.LayoutControl): + """ + A color picker that lets users choose a color from a grid of available + colors. + """ + + color: Optional[ft.ColorValue] = None + """ + The currently selected color. + """ + + available_colors: Optional[list[ft.ColorValue]] = None + """ + A list of available colors to pick from. + """ + + on_color_change: Optional[ft.ControlEventHandler["BlockPicker"]] = None + """ + Called when the picker color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the color value as a hex string. + """ diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/color_picker.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/color_picker.py new file mode 100644 index 0000000000..2e64d1a4fb --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/color_picker.py @@ -0,0 +1,182 @@ +from enum import Enum +from typing import Optional + +import flet as ft + +__all__ = ["ColorLabelType", "ColorPicker", "HsvColor", "PaletteType"] + + +class ColorLabelType(Enum): + """Defines which textual color representations are shown by the picker.""" + + HEX = "hex" + """Hexadecimal notation (for example `#RRGGBB`).""" + + RGB = "rgb" + """Red, green, blue channel notation.""" + + HSV = "hsv" + """Hue, saturation, value notation.""" + + HSL = "hsl" + """Hue, saturation, lightness notation.""" + + +class PaletteType(Enum): + """ + Defines the interactive palette layout used by \ + :class:`~flet_color_pickers.ColorPicker`. + + Each value selects which color channels are controlled by the 2D palette and + which channel is moved to a separate slider. + """ + + HSV = "hsv" + """HSV palette area with default channel arrangement.""" + + HSV_WITH_HUE = "hsvWithHue" + """HSV palette where hue is controlled in the palette interaction.""" + + HSV_WITH_VALUE = "hsvWithValue" + """HSV palette where value/brightness is controlled in the palette interaction.""" + + HSV_WITH_SATURATION = "hsvWithSaturation" + """HSV palette where saturation is controlled in the palette interaction.""" + + HSL = "hsl" + """HSL palette area with default channel arrangement.""" + + HSL_WITH_HUE = "hslWithHue" + """HSL palette where hue is controlled in the palette interaction.""" + + HSL_WITH_LIGHTNESS = "hslWithLightness" + """HSL palette where lightness is controlled in the palette interaction.""" + + HSL_WITH_SATURATION = "hslWithSaturation" + """HSL palette where saturation is controlled in the palette interaction.""" + + RGB_WITH_BLUE = "rgbWithBlue" + """RGB palette with blue as the varying channel.""" + + RGB_WITH_GREEN = "rgbWithGreen" + """RGB palette with green as the varying channel.""" + + RGB_WITH_RED = "rgbWithRed" + """RGB palette with red as the varying channel.""" + + HUE_WHEEL = "hueWheel" + """Circular hue wheel palette.""" + + +@ft.value +class HsvColor: + """Represents a color in the HSV color space with alpha channel.""" + + alpha: ft.Number + """Opacity component in range `0.0..1.0`.""" + + hue: ft.Number + """Hue angle component in degrees.""" + + saturation: ft.Number + """Saturation component in range `0.0..1.0`.""" + + value: ft.Number + """Value/brightness component in range `0.0..1.0`.""" + + +@ft.control("ColorPicker") +class ColorPicker(ft.LayoutControl): + """ + A full-featured color picker with palette, sliders, labels, and optional + history. + """ + + color: Optional[ft.ColorValue] = None + """ + The currently selected color. + """ + + color_picker_width: Optional[ft.Number] = None + """ + Width of the color picker in virtual pixels. + """ + + color_history: Optional[list[ft.ColorValue]] = None + """ + A list of colors to display as a history palette. + + To be notified when the palette changes, set `on_history_change`. + """ + + display_thumb_color: bool = True + """ + Whether to display the thumb color in slider. + """ + + enable_alpha: bool = True + """ + Whether to enable alpha (opacity) slider. + """ + + hex_input_bar: bool = True + """ + Whether to show the hex input bar. + """ + + label_text_style: Optional[ft.TextStyle] = None + """ + Text style for labels. + """ + + label_types: Optional[list[ColorLabelType]] = None + """ + Color label types to display. + """ + + palette_type: Optional[PaletteType] = None + """ + Palette type for the picker area. + """ + + picker_area_border_radius: Optional[ft.BorderRadiusValue] = None + """ + Border radius for the picker area. + """ + + picker_area_height_percent: Optional[ft.Number] = None + """ + Height of the picker area as a percentage of the picker width. + """ + + hsv_color: Optional[HsvColor] = None + """ + The currently selected HSV color. + + Provide an `HsvColor` instance with fields: `alpha`, `hue`, `saturation`, + `value`. + """ + + on_color_change: Optional[ft.ControlEventHandler["ColorPicker"]] = None + """ + Called when the picker color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the color value as a hex string. + """ + + on_history_change: Optional[ft.ControlEventHandler["ColorPicker"]] = None + """ + Called when the history palette is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the list of color values as hex strings. + """ + + on_hsv_color_change: Optional[ft.ControlEventHandler["ColorPicker"]] = None + """ + Called when the picker HSV color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the HSV values as a dict with keys: `alpha`, `hue`, `saturation`, `value`. + """ diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/hue_ring_picker.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/hue_ring_picker.py new file mode 100644 index 0000000000..c2b59390f5 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/hue_ring_picker.py @@ -0,0 +1,51 @@ +from typing import Optional + +import flet as ft + +__all__ = ["HueRingPicker"] + + +@ft.control("HueRingPicker") +class HueRingPicker(ft.LayoutControl): + """ + A hue ring color picker that lets users select a hue on a circular ring, + with an optional alpha slider. + """ + + color: Optional[ft.ColorValue] = None + """ + The currently selected color. + """ + + color_picker_height: Optional[ft.Number] = None + """ + Height of the color picker in virtual pixels. + """ + + enable_alpha: bool = False + """ + Whether to enable alpha (opacity) slider. + """ + + hue_ring_stroke_width: Optional[ft.Number] = None + """ + Stroke width for the hue ring. + """ + + picker_area_border_radius: Optional[ft.BorderRadiusValue] = None + """ + Border radius for the picker area. + """ + + portrait_only: bool = False + """ + Whether to force portrait layout. + """ + + on_color_change: Optional[ft.ControlEventHandler["HueRingPicker"]] = None + """ + Called when the picker color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the color value as a hex string. + """ diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/material_picker.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/material_picker.py new file mode 100644 index 0000000000..64888700b4 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/material_picker.py @@ -0,0 +1,44 @@ +from typing import Optional + +import flet as ft + +__all__ = ["MaterialPicker"] + + +@ft.control("MaterialPicker") +class MaterialPicker(ft.LayoutControl): + """ + A material palette picker for selecting primary and shade colors, with + optional shade labels. + """ + + color: Optional[ft.ColorValue] = None + """ + The currently selected color. + """ + + enable_label: bool = False + """ + Whether to show color shade labels. + """ + + portrait_only: bool = False + """ + Whether to force portrait layout. + """ + + on_color_change: Optional[ft.ControlEventHandler["MaterialPicker"]] = None + """ + Called when the picker color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the color value as a hex string. + """ + + on_primary_change: Optional[ft.ControlEventHandler["MaterialPicker"]] = None + """ + Called when the primary color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the color value as a hex string. + """ diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/multiple_choice_block_picker.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/multiple_choice_block_picker.py new file mode 100644 index 0000000000..bbb232024a --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/multiple_choice_block_picker.py @@ -0,0 +1,33 @@ +from typing import Optional + +import flet as ft + +__all__ = ["MultipleChoiceBlockPicker"] + + +@ft.control("MultipleChoiceBlockPicker") +class MultipleChoiceBlockPicker(ft.LayoutControl): + """ + A color picker that lets users choose multiple colors from a grid of available + colors. + """ + + colors: Optional[list[ft.ColorValue]] = None + """ + The currently selected colors. + """ + + available_colors: Optional[list[ft.ColorValue]] = None + """ + A list of available colors to pick from. + """ + + on_colors_change: Optional[ft.ControlEventHandler["MultipleChoiceBlockPicker"]] = ( + None + ) + """ + Called when the picker colors are changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the list of color values as hex strings. + """ diff --git a/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/slide_picker.py b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/slide_picker.py new file mode 100644 index 0000000000..7f1b07de13 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flet_color_pickers/slide_picker.py @@ -0,0 +1,118 @@ +from enum import Enum +from typing import Optional + +import flet as ft +from flet_color_pickers.color_picker import ColorLabelType + +__all__ = ["ColorModel", "SlidePicker"] + + +class ColorModel(Enum): + """ + Defines color models. + """ + + RGB = "rgb" + """Red, green, blue channels.""" + + HSV = "hsv" + """Hue, saturation, value channels.""" + + HSL = "hsl" + """Hue, saturation, lightness channels.""" + + +@ft.control("SlidePicker") +class SlidePicker(ft.LayoutControl): + """ + A slider-based color picker that exposes RGB/HSV/HSL channels with optional + labels and indicators. + """ + + color: Optional[ft.ColorValue] = None + """ + The currently selected color. + """ + + color_model: Optional[ColorModel] = None + """ + The color model used by the sliders. + """ + + display_thumb_color: bool = True + """ + Whether to display the thumb color in sliders. + """ + + enable_alpha: bool = True + """ + Whether to enable alpha (opacity) slider. + """ + + indicator_alignment_begin: Optional[ft.Alignment] = None + """ + Alignment for the indicator split begin. + """ + + indicator_alignment_end: Optional[ft.Alignment] = None + """ + Alignment for the indicator split end. + """ + + indicator_border_radius: Optional[ft.BorderRadiusValue] = None + """ + Border radius for the indicator. + """ + + indicator_size: Optional[ft.Size] = None + """ + Size of the indicator. + """ + + label_text_style: Optional[ft.TextStyle] = None + """ + Text style for labels. + """ + + label_types: Optional[list[ColorLabelType]] = None + """ + Color label types to display. + """ + + show_indicator: bool = True + """ + Whether to show the color indicator. + """ + + show_label: bool = True + """ + Whether to show labels. + """ + + show_params: bool = True + """ + Whether to show parameter values. + """ + + show_slider_text: bool = True + """ + Whether to show slider text. + """ + + slider_size: Optional[ft.Size] = None + """ + Size of the sliders. + """ + + slider_text_style: Optional[ft.TextStyle] = None + """ + Text style for slider text. + """ + + on_color_change: Optional[ft.ControlEventHandler["SlidePicker"]] = None + """ + Called when the picker color is changed. + + The :attr:`~flet.Event.data` property of the event handler argument contains + the color value as a hex string. + """ diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/.gitignore b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/analysis_options.yaml b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/flet_color_pickers.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/flet_color_pickers.dart new file mode 100644 index 0000000000..ae9d6da102 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/flet_color_pickers.dart @@ -0,0 +1,3 @@ +library flet_color_pickers; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/block_picker.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/block_picker.dart new file mode 100644 index 0000000000..fe30d148a5 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/block_picker.dart @@ -0,0 +1,60 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +class BlockPickerControl extends StatefulWidget { + final Control control; + + const BlockPickerControl({super.key, required this.control}); + + @override + State createState() => _BlockPickerControlState(); +} + +class _BlockPickerControlState extends State { + Color _pickerColor = Colors.black; + + void _onColorChanged(Color color) { + setState(() { + _pickerColor = color; + }); + final colorHex = color.toHex(); + widget.control.updateProperties({"color": colorHex}, notify: true); + widget.control.triggerEvent("color_change", colorHex); + } + + @override + Widget build(BuildContext context) { + debugPrint("BlockPickerControl build: ${widget.control.id}"); + + final controlColor = + widget.control.getColor("color", context) ?? Colors.black; + if (controlColor.value != _pickerColor.value) { + _pickerColor = controlColor; + } + + final rawColors = widget.control.get("available_colors"); + final theme = Theme.of(context); + final availableColors = []; + if (rawColors is List) { + for (final raw in rawColors) { + final parsed = parseColor(raw?.toString(), theme); + if (parsed != null) { + availableColors.add(parsed); + } + } + } + final picker = availableColors.isNotEmpty + ? BlockPicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + availableColors: availableColors, + ) + : BlockPicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + ); + + return LayoutControl(control: widget.control, child: picker); + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/color_picker.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/color_picker.dart new file mode 100644 index 0000000000..b2655b940d --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/color_picker.dart @@ -0,0 +1,114 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +import 'utils/color_pickers.dart'; + +class ColorPickerControl extends StatefulWidget { + final Control control; + + const ColorPickerControl({super.key, required this.control}); + + @override + State createState() => _ColorPickerControlState(); +} + +class _ColorPickerControlState extends State { + Color _pickerColor = Colors.black; + + void _onColorChanged(Color color) { + setState(() { + _pickerColor = color; + }); + final colorHex = color.toHex(); + widget.control.updateProperties({"picker_color": colorHex}, notify: true); + widget.control.triggerEvent("color_change", colorHex); + } + + void _onHsvColorChanged(HSVColor color) { + final hsvData = { + "alpha": color.alpha, + "hue": color.hue, + "saturation": color.saturation, + "value": color.value, + }; + widget.control.updateProperties({"hsv_color": hsvData}, notify: true); + widget.control.triggerEvent("hsv_color_change", hsvData); + } + + void _onHistoryChanged(List colors) { + final colorsHex = colors.map((color) => color.toHex()).toList(); + widget.control.updateProperties({"color_history": colorsHex}, notify: true); + widget.control.triggerEvent("history_change", colorsHex); + } + + @override + Widget build(BuildContext context) { + debugPrint("ColorPickerControl build: ${widget.control.id}"); + + final pickerHsvColor = parseHsvColor(widget.control.get("hsv_color")); + final controlColor = + widget.control.getColor("color", context) ?? Colors.black; + if (pickerHsvColor != null) { + final hsvColor = pickerHsvColor.toColor(); + if (hsvColor.value != _pickerColor.value) { + _pickerColor = hsvColor; + } + } else if (controlColor.value != _pickerColor.value) { + _pickerColor = controlColor; + } + + final rawLabelTypes = widget.control.get("label_types"); + final labelTypes = []; + if (rawLabelTypes is List) { + for (final raw in rawLabelTypes) { + final parsed = parseLabelType(raw?.toString()); + if (parsed != null) { + labelTypes.add(parsed); + } + } + } + + final labelTypesArg = rawLabelTypes is List + ? labelTypes + : const [ColorLabelType.rgb, ColorLabelType.hsv, ColorLabelType.hsl]; + + final rawHistory = widget.control.get("color_history"); + final theme = Theme.of(context); + final colorHistory = []; + if (rawHistory is List) { + for (final raw in rawHistory) { + final parsed = parseColor(raw?.toString(), theme); + if (parsed != null) { + colorHistory.add(parsed); + } + } + } + + final picker = ColorPicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + colorPickerWidth: widget.control.getDouble("color_picker_width") ?? 300.0, + colorHistory: colorHistory.isNotEmpty ? colorHistory : null, + onHistoryChanged: _onHistoryChanged, + displayThumbColor: widget.control.getBool("display_thumb_color", true)!, + enableAlpha: widget.control.getBool("enable_alpha", true)!, + hexInputBar: widget.control.getBool("hex_input_bar", true)!, + labelTextStyle: + widget.control.getTextStyle("label_text_style", Theme.of(context)), + labelTypes: labelTypesArg, + paletteType: + parsePaletteType(widget.control.get("palette_type")?.toString()) ?? + PaletteType.hsvWithHue, + pickerAreaBorderRadius: + widget.control.getBorderRadius("picker_area_border_radius") ?? + const BorderRadius.all(Radius.zero), + pickerAreaHeightPercent: + widget.control.getDouble("picker_area_height_percent") ?? 1.0, + pickerHsvColor: pickerHsvColor, + onHsvColorChanged: _onHsvColorChanged, + ); + + return LayoutControl(control: widget.control, child: picker); + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/extension.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/extension.dart new file mode 100644 index 0000000000..0a8578bc4a --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/extension.dart @@ -0,0 +1,31 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; + +import 'block_picker.dart'; +import 'color_picker.dart'; +import 'hue_ring_picker.dart'; +import 'material_picker.dart'; +import 'multiple_choice_block_picker.dart'; +import 'slide_picker.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "ColorPicker": + return ColorPickerControl(control: control); + case "HueRingPicker": + return HueRingPickerControl(control: control); + case "SlidePicker": + return SlidePickerControl(control: control); + case "MaterialPicker": + return MaterialPickerControl(control: control); + case "BlockPicker": + return BlockPickerControl(control: control); + case "MultipleChoiceBlockPicker": + return MultipleChoiceBlockPickerControl(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/hue_ring_picker.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/hue_ring_picker.dart new file mode 100644 index 0000000000..b167293b6a --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/hue_ring_picker.dart @@ -0,0 +1,52 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +class HueRingPickerControl extends StatefulWidget { + final Control control; + + const HueRingPickerControl({super.key, required this.control}); + + @override + State createState() => _HueRingPickerControlState(); +} + +class _HueRingPickerControlState extends State { + Color _pickerColor = Colors.black; + + void _onColorChanged(Color color) { + setState(() { + _pickerColor = color; + }); + final colorHex = color.toHex(); + widget.control.updateProperties({"color": colorHex}, notify: true); + widget.control.triggerEvent("color_change", colorHex); + } + + @override + Widget build(BuildContext context) { + debugPrint("HueRingPickerControl build: ${widget.control.id}"); + + final controlColor = + widget.control.getColor("color", context) ?? Colors.black; + if (controlColor.value != _pickerColor.value) { + _pickerColor = controlColor; + } + + final picker = HueRingPicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + colorPickerHeight: + widget.control.getDouble("color_picker_height") ?? 250.0, + enableAlpha: widget.control.getBool("enable_alpha", false)!, + hueRingStrokeWidth: + widget.control.getDouble("hue_ring_stroke_width") ?? 20.0, + pickerAreaBorderRadius: + widget.control.getBorderRadius("picker_area_border_radius") ?? + const BorderRadius.all(Radius.zero), + portraitOnly: widget.control.getBool("portrait_only", false)!, + ); + + return LayoutControl(control: widget.control, child: picker); + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/material_picker.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/material_picker.dart new file mode 100644 index 0000000000..3506781b31 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/material_picker.dart @@ -0,0 +1,51 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +class MaterialPickerControl extends StatefulWidget { + final Control control; + + const MaterialPickerControl({super.key, required this.control}); + + @override + State createState() => _MaterialPickerControlState(); +} + +class _MaterialPickerControlState extends State { + Color _pickerColor = Colors.black; + + void _onColorChanged(Color color) { + setState(() { + _pickerColor = color; + }); + final colorHex = color.toHex(); + widget.control.updateProperties({"color": colorHex}, notify: true); + widget.control.triggerEvent("color_change", colorHex); + } + + void _onPrimaryChanged(Color color) { + final colorHex = color.toHex(); + widget.control.triggerEvent("primary_change", colorHex); + } + + @override + Widget build(BuildContext context) { + debugPrint("MaterialPickerControl build: ${widget.control.id}"); + + final controlColor = + widget.control.getColor("color", context) ?? Colors.black; + if (controlColor.value != _pickerColor.value) { + _pickerColor = controlColor; + } + + final picker = MaterialPicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + onPrimaryChanged: _onPrimaryChanged, + enableLabel: widget.control.getBool("enable_label", false)!, + portraitOnly: widget.control.getBool("portrait_only", false)!, + ); + + return LayoutControl(control: widget.control, child: picker); + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/multiple_choice_block_picker.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/multiple_choice_block_picker.dart new file mode 100644 index 0000000000..8f9c25e0e3 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/multiple_choice_block_picker.dart @@ -0,0 +1,73 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +class MultipleChoiceBlockPickerControl extends StatefulWidget { + final Control control; + + const MultipleChoiceBlockPickerControl({super.key, required this.control}); + + @override + State createState() => + _MultipleChoiceBlockPickerControlState(); +} + +class _MultipleChoiceBlockPickerControlState + extends State { + List _pickerColors = [Colors.black]; + + void _onColorsChanged(List colors) { + setState(() { + _pickerColors = colors; + }); + final colorsHex = colors.map((color) => color.toHex()).toList(); + widget.control.updateProperties({"colors": colorsHex}, notify: true); + widget.control.triggerEvent("colors_change", colorsHex); + } + + @override + Widget build(BuildContext context) { + debugPrint("MultipleChoiceBlockPickerControl build: ${widget.control.id}"); + + final rawColors = widget.control.get("colors"); + final theme = Theme.of(context); + final parsedColors = []; + if (rawColors is List) { + for (final raw in rawColors) { + final parsed = parseColor(raw?.toString(), theme); + if (parsed != null) { + parsedColors.add(parsed); + } + } + } + if (parsedColors.isNotEmpty) { + _pickerColors = parsedColors; + } else if (_pickerColors.isEmpty) { + _pickerColors = [Colors.black]; + } + + final rawAvailableColors = widget.control.get("available_colors"); + final availableColors = []; + if (rawAvailableColors is List) { + for (final raw in rawAvailableColors) { + final parsed = parseColor(raw?.toString(), theme); + if (parsed != null) { + availableColors.add(parsed); + } + } + } + + final picker = availableColors.isNotEmpty + ? MultipleChoiceBlockPicker( + pickerColors: _pickerColors, + onColorsChanged: _onColorsChanged, + availableColors: availableColors, + ) + : MultipleChoiceBlockPicker( + pickerColors: _pickerColors, + onColorsChanged: _onColorsChanged, + ); + + return LayoutControl(control: widget.control, child: picker); + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/slide_picker.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/slide_picker.dart new file mode 100644 index 0000000000..0033d5ebcc --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/slide_picker.dart @@ -0,0 +1,78 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +import 'utils/color_pickers.dart'; + +class SlidePickerControl extends StatefulWidget { + final Control control; + + const SlidePickerControl({super.key, required this.control}); + + @override + State createState() => _SlidePickerControlState(); +} + +class _SlidePickerControlState extends State { + Color _pickerColor = Colors.black; + + void _onColorChanged(Color color) { + final colorHex = color.toHex(); + widget.control.triggerEvent("color_change", colorHex); + } + + @override + Widget build(BuildContext context) { + debugPrint("SlidePickerControl build: ${widget.control.id}"); + + final controlColor = + widget.control.getColor("color", context) ?? Colors.black; + if (controlColor.value != _pickerColor.value) { + _pickerColor = controlColor; + } + + final colorModel = parseColorModel( + widget.control.get("color_model")?.toString(), ColorModel.rgb); + final rawLabelTypes = widget.control.get("label_types"); + final labelTypes = []; + if (rawLabelTypes is List) { + for (final raw in rawLabelTypes) { + final parsed = parseLabelType(raw?.toString()); + if (parsed != null) { + labelTypes.add(parsed); + } + } + } + final labelTypesArg = + rawLabelTypes is List ? labelTypes : const []; + + final picker = SlidePicker( + pickerColor: _pickerColor, + onColorChanged: _onColorChanged, + colorModel: colorModel ?? ColorModel.rgb, + displayThumbColor: widget.control.getBool("display_thumb_color", true)!, + enableAlpha: widget.control.getBool("enable_alpha", true)!, + indicatorAlignmentBegin: widget.control.getAlignment( + "indicator_alignment_begin", const Alignment(-1.0, -3.0))!, + indicatorAlignmentEnd: widget.control + .getAlignment("indicator_alignment_end", const Alignment(1.0, 3.0))!, + indicatorBorderRadius: + widget.control.getBorderRadius("indicator_border_radius") ?? + const BorderRadius.all(Radius.zero), + indicatorSize: + widget.control.getSize("indicator_size", const Size(280, 50))!, + labelTextStyle: + widget.control.getTextStyle("label_text_style", Theme.of(context)), + labelTypes: labelTypesArg, + showIndicator: widget.control.getBool("show_indicator", true)!, + showLabel: widget.control.getBool("show_label", true)!, + showParams: widget.control.getBool("show_params", true)!, + showSliderText: widget.control.getBool("show_slider_text", true)!, + sliderSize: widget.control.getSize("slider_size", const Size(260, 40))!, + sliderTextStyle: + widget.control.getTextStyle("slider_text_style", Theme.of(context)), + ); + + return LayoutControl(control: widget.control, child: picker); + } +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/utils/color_pickers.dart b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/utils/color_pickers.dart new file mode 100644 index 0000000000..a659a5dd71 --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/lib/src/utils/color_pickers.dart @@ -0,0 +1,28 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_colorpicker/flutter_colorpicker.dart'; + +HSVColor? parseHsvColor(dynamic value) { + if (value is Map) { + final alpha = parseDouble(value["alpha"]); + final hue = parseDouble(value["hue"]); + final saturation = parseDouble(value["saturation"]); + final val = parseDouble(value["value"]); + if (alpha != null && hue != null && saturation != null && val != null) { + return HSVColor.fromAHSV(alpha, hue, saturation, val); + } + } + return null; +} + +PaletteType? parsePaletteType(String? value, [PaletteType? defaultValue]) { + return parseEnum(PaletteType.values, value, defaultValue); +} + +ColorLabelType? parseLabelType(String? value, [ColorLabelType? defaultValue]) { + return parseEnum(ColorLabelType.values, value, defaultValue); +} + +ColorModel? parseColorModel(String? value, [ColorModel? defaultValue]) { + return parseEnum(ColorModel.values, value, defaultValue); +} diff --git a/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/pubspec.yaml b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/pubspec.yaml new file mode 100644 index 0000000000..3e68b2e57e --- /dev/null +++ b/sdk/python/packages/flet-color-pickers/src/flutter/flet_color_pickers/pubspec.yaml @@ -0,0 +1,22 @@ +name: flet_color_pickers +description: Flet color picker controls +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + flutter_colorpicker: ^1.0.3 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-datatable2/CHANGELOG.md b/sdk/python/packages/flet-datatable2/CHANGELOG.md new file mode 100644 index 0000000000..8b30cbbd58 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.80.0 + +## Added + +- Deployed online documentation: https://flet.dev/docs/datatable2/ +- New enums: `DataColumnSize` + +### Changed + +- Refactored all controls to use `@flet.control` dataclass-style definition. +- Additionally, they are now all based on their flet counterparts: + - `DataTable2` is now based on `flet.DataTable` + - `DataColumn2` is now based on `flet.DataColumn` + - `DataRow2` is now based on `flet.DataRow` + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-datatable2/LICENSE b/sdk/python/packages/flet-datatable2/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-datatable2/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-datatable2/README.md b/sdk/python/packages/flet-datatable2/README.md new file mode 100644 index 0000000000..93e7e56752 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/README.md @@ -0,0 +1,45 @@ +# flet-datatable2 + +[![pypi](https://img.shields.io/pypi/v/flet-datatable2.svg)](https://pypi.python.org/pypi/flet-datatable2) +[![downloads](https://static.pepy.tech/badge/flet-datatable2/month)](https://pepy.tech/project/flet-datatable2) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-datatable2) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-datatable2.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-datatable2.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-datatable2/LICENSE) + +An enhanced data table for [Flet](https://flet.dev) apps that builds on the built-in component by adding sticky headers, +fixed top rows, and fixed left columns while preserving all core features. + +It is based on [data_table_2](https://pub.dev/packages/data_table_2) Flutter package. + +## Documentation + +You can find its documentation [here](https://flet.dev/docs/controls/datatable2/). + +## Platform Support + +This package supports the following platforms: + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-datatable2` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-datatable2 + ``` + +- Using `pip`: + ```bash + pip install flet-datatable2 + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/datatable2). diff --git a/sdk/python/packages/flet-datatable2/pyproject.toml b/sdk/python/packages/flet-datatable2/pyproject.toml new file mode 100644 index 0000000000..7613732719 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-datatable2" +version = "0.1.0" +description = "Enhanced data table widgets for Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/datatable2" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-datatable2" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_datatable2" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-datatable2/src/flet_datatable2/__init__.py b/sdk/python/packages/flet-datatable2/src/flet_datatable2/__init__.py new file mode 100644 index 0000000000..59d4d2e7cf --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flet_datatable2/__init__.py @@ -0,0 +1,10 @@ +from flet_datatable2.datacolumn2 import DataColumn2, DataColumnSize +from flet_datatable2.datarow2 import DataRow2 +from flet_datatable2.datatable2 import DataTable2 + +__all__ = [ + "DataColumn2", + "DataColumnSize", + "DataRow2", + "DataTable2", +] diff --git a/sdk/python/packages/flet-datatable2/src/flet_datatable2/datacolumn2.py b/sdk/python/packages/flet-datatable2/src/flet_datatable2/datacolumn2.py new file mode 100644 index 0000000000..9d7bdaa509 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flet_datatable2/datacolumn2.py @@ -0,0 +1,45 @@ +from enum import Enum +from typing import Optional + +import flet as ft + +__all__ = ["DataColumn2", "DataColumnSize"] + + +class DataColumnSize(Enum): + """ + Relative size of a column determines the share of total table + width allocated to each individual column. + + When determining column widths, ratios between `S`, `M` and `L` + columns are kept (i.e. Large columns are set to 1.2x width of Medium ones). + + See :attr:`flet_datatable2.DataTable2.sm_ratio`, \ + :attr:`flet_datatable2.DataTable2.lm_ratio`. + """ + + S = "s" + M = "m" + L = "l" + + +@ft.control("DataColumn2") +class DataColumn2(ft.DataColumn): + """ + Extends :class:`flet.DataColumn`, + adding the ability to set relative column size and fixed column width. + + Meant to be used as an item of :attr:`flet_datatable2.DataTable2.columns`. + """ + + fixed_width: Optional[ft.Number] = None + """ + Defines absolute width of the column in pixels + (as opposed to relative :attr:`size` used by default). + """ + + size: Optional[DataColumnSize] = DataColumnSize.S + """ + Column sizes are determined based on available width by distributing + it to individual columns accounting for their relative sizes. + """ diff --git a/sdk/python/packages/flet-datatable2/src/flet_datatable2/datarow2.py b/sdk/python/packages/flet-datatable2/src/flet_datatable2/datarow2.py new file mode 100644 index 0000000000..e00c839187 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flet_datatable2/datarow2.py @@ -0,0 +1,85 @@ +from typing import Optional + +import flet as ft + +__all__ = ["DataRow2"] + + +@ft.control("DataRow2") +class DataRow2(ft.DataRow): + """ + Extends :class:`flet.DataRow`, adding row-level `tap` events. + + There are also :attr:`on_secondary_tap` and :attr:`on_secondary_tap_down`, + which are not available in :class:`~flet.DataCell`s and can be useful in + desktop settings to handle right-click actions. + """ + + decoration: Optional[ft.BoxDecoration] = None + """ + Decoration to be applied to this row. + + Note: + If provided, + :attr:`flet.DataTable.divider_thickness` + has no effect. + """ + + specific_row_height: Optional[ft.Number] = None + """ + Specific row height. + + Falls back to :attr:`flet_datatable2.DataTable2.data_row_height` if not set. + """ + + on_double_tap: Optional[ft.ControlEventHandler["DataRow2"]] = None + """ + Fires when the row is double-tapped. + + Note: + Won't be called if tapped cell has any tap event handlers + (:attr:`~flet.DataCell.on_tap`, + :attr:`~flet.DataCell.on_double_tap`, + :attr:`~flet.DataCell.on_long_press`, + :attr:`~flet.DataCell.on_tap_cancel`, + :attr:`~flet.DataCell.on_tap_down`) set. + """ + + on_secondary_tap: Optional[ft.ControlEventHandler["DataRow2"]] = None + """ + Fires when the row is right-clicked (secondary tap). + + Note: + Won't be called if tapped cell has any tap event handlers + (:attr:`~flet.DataCell.on_tap`, + :attr:`~flet.DataCell.on_double_tap`, + :attr:`~flet.DataCell.on_long_press`, + :attr:`~flet.DataCell.on_tap_cancel`, + :attr:`~flet.DataCell.on_tap_down`) set. + """ + + on_secondary_tap_down: Optional[ft.ControlEventHandler["DataRow2"]] = None + """ + Fires when the row is right-clicked (secondary tap down). + + Note: + Won't be called if tapped cell has any tap event handlers + (:attr:`~flet.DataCell.on_tap`, + :attr:`~flet.DataCell.on_double_tap`, + :attr:`~flet.DataCell.on_long_press`, + :attr:`~flet.DataCell.on_tap_cancel`, + :attr:`~flet.DataCell.on_tap_down`) set. + """ + + on_tap: Optional[ft.EventHandler[ft.TapEvent["DataRow2"]]] = None + """ + Fires when the row is tapped. + + Note: + Won't be called if tapped cell has any tap event handlers + (:attr:`~flet.DataCell.on_tap`, + :attr:`~flet.DataCell.on_double_tap`, + :attr:`~flet.DataCell.on_long_press`, + :attr:`~flet.DataCell.on_tap_cancel`, + :attr:`~flet.DataCell.on_tap_down`) set. + """ diff --git a/sdk/python/packages/flet-datatable2/src/flet_datatable2/datatable2.py b/sdk/python/packages/flet-datatable2/src/flet_datatable2/datatable2.py new file mode 100644 index 0000000000..8262b653c8 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flet_datatable2/datatable2.py @@ -0,0 +1,141 @@ +from dataclasses import field +from typing import Optional, Union + +import flet as ft +from flet_datatable2.datacolumn2 import DataColumn2 +from flet_datatable2.datarow2 import DataRow2 + +__all__ = ["DataTable2"] + + +@ft.control("DataTable2") +class DataTable2(ft.DataTable): + """ + Provides sticky header row, scrollable data rows, + and additional layout flexibility with :class:`~flet_datatable2.DataColumn2` + and :class:`~flet_datatable2.DataRow2`. + + Note: + `DataTable2` doesn't support + :attr:`flet.DataTable.data_row_min_height` + and :attr:`flet.DataTable.data_row_max_height` + properties present in the parent :class:`~flet.DataTable`. + Use :attr:`data_row_height` instead. + """ + + columns: list[Union[DataColumn2, ft.DataColumn]] + """ + A list of table columns. + """ + + rows: list[Union[ft.DataRow, DataRow2]] = field(default_factory=list) + """ + A list of table rows. + """ + + empty: Optional[ft.Control] = None + """ + Placeholder control shown when there are no data rows. + """ + + bottom_margin: Optional[ft.Number] = None + """ + Adds space after the last row if set. + """ + + lm_ratio: ft.Number = 1.2 + """ + Ratio of Large column width to Medium. + """ + + sm_ratio: ft.Number = 0.67 + """ + Ratio of Small column width to Medium. + """ + + fixed_left_columns: int = 0 + """ + Number of sticky columns on the left. Includes checkbox column, if present. + """ + + fixed_top_rows: int = 1 + """ + Number of sticky rows from the top. Includes heading row by default. + """ + + fixed_columns_color: Optional[ft.ColorValue] = None + """ + Background color for sticky left columns. + """ + + fixed_corner_color: Optional[ft.ColorValue] = None + """ + Background color of the fixed top-left corner cell. + """ + + sort_arrow_icon_color: Optional[ft.ColorValue] = None + """ + When set always overrides/preceeds default arrow icon color. + """ + + min_width: Optional[ft.Number] = None + """ + Minimum table width before horizontal scrolling kicks in. + """ + + show_heading_checkbox: bool = True + """ + Controls visibility of the heading checkbox. + """ + + heading_checkbox_theme: Optional[ft.CheckboxTheme] = None + """ + Overrides theme of the heading checkbox. + """ + + data_row_checkbox_theme: Optional[ft.CheckboxTheme] = None + """ + Overrides theme of checkboxes in each data row. + """ + + sort_arrow_icon: ft.IconData = ft.Icons.ARROW_UPWARD + """ + Icon shown when sorting is applied. + """ + + sort_arrow_animation_duration: ft.DurationValue = field( + default_factory=lambda: ft.Duration(milliseconds=150) + ) + """ + Duration of sort arrow animation. + """ + + visible_horizontal_scroll_bar: Optional[bool] = None + """ + Determines visibility of the horizontal scrollbar. + """ + + visible_vertical_scroll_bar: Optional[bool] = None + """ + Determines visibility of the vertical scrollbar. + """ + + checkbox_alignment: ft.Alignment = field( + default_factory=lambda: ft.Alignment.CENTER + ) + """ + Alignment of the checkbox. + """ + + data_row_height: Optional[ft.Number] = None + """ + Height of each data row. + """ + + # present in parent (DataTable) but of no use in DataTable2 + data_row_min_height: None = field( + init=False, repr=False, compare=False, metadata={"skip": True} + ) + data_row_max_height: None = field( + init=False, repr=False, compare=False, metadata={"skip": True} + ) diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/.gitignore b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/flet_datatable2.dart b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/flet_datatable2.dart new file mode 100644 index 0000000000..77c3be7cfc --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/flet_datatable2.dart @@ -0,0 +1,5 @@ +library flet_datatable2; + +//export "../src/create_control.dart" show createControl, ensureInitialized; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/data_sources.dart b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/data_sources.dart new file mode 100644 index 0000000000..afaf60bf56 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/data_sources.dart @@ -0,0 +1,692 @@ +// ignore_for_file: avoid_print + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:data_table_2/data_table_2.dart'; + +// Copyright 2019 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// The file was extracted from GitHub: https://github.com/flutter/gallery +// Changes and modifications by Maxim Saplin, 2021 + +/// Keeps track of selected rows, feed the data into DesertsDataSource +class RestorableDessertSelections extends RestorableProperty> { + Set _dessertSelections = {}; + + /// Returns whether or not a dessert row is selected by index. + bool isSelected(int index) => _dessertSelections.contains(index); + + /// Takes a list of [Dessert]s and saves the row indices of selected rows + /// into a [Set]. + void setDessertSelections(List desserts) { + final updatedSet = {}; + for (var i = 0; i < desserts.length; i += 1) { + var dessert = desserts[i]; + if (dessert.selected) { + updatedSet.add(i); + } + } + _dessertSelections = updatedSet; + notifyListeners(); + } + + @override + Set createDefaultValue() => _dessertSelections; + + @override + Set fromPrimitives(Object? data) { + final selectedItemIndices = data as List; + _dessertSelections = { + ...selectedItemIndices.map((dynamic id) => id as int), + }; + return _dessertSelections; + } + + @override + void initWithValue(Set value) { + _dessertSelections = value; + } + + @override + Object toPrimitives() => _dessertSelections.toList(); +} + +int _idCounter = 0; + +/// Domain model entity +class Dessert { + Dessert( + this.name, + this.calories, + this.fat, + this.carbs, + this.protein, + this.sodium, + this.calcium, + this.iron, + ); + + final int id = _idCounter++; + + final String name; + final int calories; + final double fat; + final int carbs; + final double protein; + final int sodium; + final int calcium; + final int iron; + bool selected = false; +} + +/// Data source implementing standard Flutter's DataTableSource abstract class +/// which is part of DataTable and PaginatedDataTable synchronous data fecthin API. +/// This class uses static collection of deserts as a data store, projects it into +/// DataRows, keeps track of selected items, provides sprting capability +class DessertDataSource extends DataTableSource { + DessertDataSource.empty(this.context) { + desserts = []; + } + + DessertDataSource(this.context, + [sortedByCalories = false, + this.hasRowTaps = false, + this.hasRowHeightOverrides = false, + this.hasZebraStripes = false]) { + desserts = _desserts; + if (sortedByCalories) { + sort((d) => d.calories, true); + } + } + + final BuildContext context; + late List desserts; + // Add row tap handlers and show snackbar + bool hasRowTaps = false; + // Override height values for certain rows + bool hasRowHeightOverrides = false; + // Color each Row by index's parity + bool hasZebraStripes = false; + + void sort(Comparable Function(Dessert d) getField, bool ascending) { + desserts.sort((a, b) { + final aValue = getField(a); + final bValue = getField(b); + return ascending + ? Comparable.compare(aValue, bValue) + : Comparable.compare(bValue, aValue); + }); + notifyListeners(); + } + + void updateSelectedDesserts(RestorableDessertSelections selectedRows) { + _selectedCount = 0; + for (var i = 0; i < desserts.length; i += 1) { + var dessert = desserts[i]; + if (selectedRows.isSelected(i)) { + dessert.selected = true; + _selectedCount += 1; + } else { + dessert.selected = false; + } + } + notifyListeners(); + } + + @override + DataRow2 getRow(int index, [Color? color]) { + final format = NumberFormat.decimalPercentPattern( + locale: 'en', + decimalDigits: 0, + ); + assert(index >= 0); + if (index >= desserts.length) throw 'index > _desserts.length'; + final dessert = desserts[index]; + return DataRow2.byIndex( + index: index, + selected: dessert.selected, + color: color != null + ? WidgetStateProperty.all(color) + : (hasZebraStripes && index.isEven + ? WidgetStateProperty.all(Theme.of(context).highlightColor) + : null), + onSelectChanged: (value) { + if (dessert.selected != value) { + _selectedCount += value! ? 1 : -1; + assert(_selectedCount >= 0); + dessert.selected = value; + notifyListeners(); + } + }, + onTap: hasRowTaps + ? () => _showSnackbar(context, 'Tapped on row ${dessert.name}') + : null, + onDoubleTap: hasRowTaps + ? () => _showSnackbar(context, 'Double Tapped on row ${dessert.name}') + : null, + onLongPress: hasRowTaps + ? () => _showSnackbar(context, 'Long pressed on row ${dessert.name}') + : null, + onSecondaryTap: hasRowTaps + ? () => _showSnackbar(context, 'Right clicked on row ${dessert.name}') + : null, + onSecondaryTapDown: hasRowTaps + ? (d) => + _showSnackbar(context, 'Right button down on row ${dessert.name}') + : null, + specificRowHeight: + hasRowHeightOverrides && dessert.fat >= 25 ? 100 : null, + cells: [ + DataCell(Text(dessert.name)), + DataCell(Text('${dessert.calories}'), + onTap: () => _showSnackbar(context, + 'Tapped on a cell with "${dessert.calories}"', Colors.red)), + DataCell(Text(dessert.fat.toStringAsFixed(1))), + DataCell(Text('${dessert.carbs}')), + DataCell(Text(dessert.protein.toStringAsFixed(1))), + DataCell(Text('${dessert.sodium}')), + DataCell(Text(format.format(dessert.calcium / 100))), + DataCell(Text(format.format(dessert.iron / 100))), + ], + ); + } + + @override + int get rowCount => desserts.length; + + @override + bool get isRowCountApproximate => false; + + @override + int get selectedRowCount => _selectedCount; + + void selectAll(bool? checked) { + for (final dessert in desserts) { + dessert.selected = checked ?? false; + } + _selectedCount = (checked ?? false) ? desserts.length : 0; + notifyListeners(); + } +} + +/// Async datasource for AsynPaginatedDataTabke2 example. Based on AsyncDataTableSource which +/// is an extension to Flutter's DataTableSource and aimed at solving +/// saync data fetching scenarious by paginated table (such as using Web API) +class DessertDataSourceAsync extends AsyncDataTableSource { + DessertDataSourceAsync() { + print('DessertDataSourceAsync created'); + } + + DessertDataSourceAsync.empty() { + _empty = true; + print('DessertDataSourceAsync.empty created'); + } + + DessertDataSourceAsync.error() { + _errorCounter = 0; + print('DessertDataSourceAsync.error created'); + } + + bool _empty = false; + int? _errorCounter; + + RangeValues? _caloriesFilter; + + RangeValues? get caloriesFilter => _caloriesFilter; + set caloriesFilter(RangeValues? calories) { + _caloriesFilter = calories; + refreshDatasource(); + } + + final DesertsFakeWebService _repo = DesertsFakeWebService(); + + String _sortColumn = "name"; + bool _sortAscending = true; + + void sort(String columnName, bool ascending) { + _sortColumn = columnName; + _sortAscending = ascending; + refreshDatasource(); + } + + Future getTotalRecords() { + return Future.delayed( + const Duration(milliseconds: 0), () => _empty ? 0 : _dessertsX3.length); + } + + @override + Future getRows(int startIndex, int count) async { + print('getRows($startIndex, $count)'); + if (_errorCounter != null) { + _errorCounter = _errorCounter! + 1; + + if (_errorCounter! % 2 == 1) { + await Future.delayed(const Duration(milliseconds: 1000)); + throw 'Error #${((_errorCounter! - 1) / 2).round() + 1} has occured'; + } + } + + final format = NumberFormat.decimalPercentPattern( + locale: 'en', + decimalDigits: 0, + ); + assert(startIndex >= 0); + + // List returned will be empty is there're fewer items than startingAt + var x = _empty + ? await Future.delayed(const Duration(milliseconds: 2000), + () => DesertsFakeWebServiceResponse(0, [])) + : await _repo.getData( + startIndex, count, _caloriesFilter, _sortColumn, _sortAscending); + + var r = AsyncRowsResponse( + x.totalRecords, + x.data.map((dessert) { + return DataRow( + key: ValueKey(dessert.id), + //selected: dessert.selected, + onSelectChanged: (value) { + if (value != null) { + setRowSelection(ValueKey(dessert.id), value); + } + }, + cells: [ + DataCell(Text(dessert.name)), + DataCell(Text('${dessert.calories}')), + DataCell(Text(dessert.fat.toStringAsFixed(1))), + DataCell(Text('${dessert.carbs}')), + DataCell(Text(dessert.protein.toStringAsFixed(1))), + DataCell(Text('${dessert.sodium}')), + DataCell(Text(format.format(dessert.calcium / 100))), + DataCell(Text(format.format(dessert.iron / 100))), + ], + ); + }).toList()); + + return r; + } +} + +class DesertsFakeWebServiceResponse { + DesertsFakeWebServiceResponse(this.totalRecords, this.data); + + /// THe total ammount of records on the server, e.g. 100 + final int totalRecords; + + /// One page, e.g. 10 reocrds + final List data; +} + +class DesertsFakeWebService { + int Function(Dessert, Dessert)? _getComparisonFunction( + String column, bool ascending) { + var coef = ascending ? 1 : -1; + switch (column) { + case 'name': + return (Dessert d1, Dessert d2) => coef * d1.name.compareTo(d2.name); + case 'calories': + return (Dessert d1, Dessert d2) => coef * (d1.calories - d2.calories); + case 'fat': + return (Dessert d1, Dessert d2) => coef * (d1.fat - d2.fat).round(); + case 'carbs': + return (Dessert d1, Dessert d2) => coef * (d1.carbs - d2.carbs); + case 'protein': + return (Dessert d1, Dessert d2) => + coef * (d1.protein - d2.protein).round(); + case 'sodium': + return (Dessert d1, Dessert d2) => coef * (d1.sodium - d2.sodium); + case 'calcium': + return (Dessert d1, Dessert d2) => coef * (d1.calcium - d2.calcium); + case 'iron': + return (Dessert d1, Dessert d2) => coef * (d1.iron - d2.iron); + } + + return null; + } + + Future getData(int startingAt, int count, + RangeValues? caloriesFilter, String sortedBy, bool sortedAsc) async { + return Future.delayed( + Duration( + milliseconds: startingAt == 0 + ? 2650 + : startingAt < 20 + ? 2000 + : 400), () { + var result = _dessertsX3; + + if (caloriesFilter != null) { + result = result + .where((e) => + e.calories >= caloriesFilter.start && + e.calories <= caloriesFilter.end) + .toList(); + } + + result.sort(_getComparisonFunction(sortedBy, sortedAsc)); + return DesertsFakeWebServiceResponse( + result.length, result.skip(startingAt).take(count).toList()); + }); + } +} + +int _selectedCount = 0; + +List _desserts = [ + Dessert( + 'Frozen Yogurt', + 159, + 6.0, + 24, + 4.0, + 87, + 14, + 1, + ), + Dessert( + 'Ice Cream Sandwich', + 237, + 9.0, + 37, + 4.3, + 129, + 8, + 1, + ), + Dessert( + 'Eclair', + 262, + 16.0, + 24, + 6.0, + 337, + 6, + 7, + ), + Dessert( + 'Cupcake', + 305, + 3.7, + 67, + 4.3, + 413, + 3, + 8, + ), + Dessert( + 'Gingerbread', + 356, + 16.0, + 49, + 3.9, + 327, + 7, + 16, + ), + Dessert( + 'Jelly Bean', + 375, + 0.0, + 94, + 0.0, + 50, + 0, + 0, + ), + Dessert( + 'Lollipop', + 392, + 0.2, + 98, + 0.0, + 38, + 0, + 2, + ), + Dessert( + 'Honeycomb', + 408, + 3.2, + 87, + 6.5, + 562, + 0, + 45, + ), + Dessert( + 'Donut', + 452, + 25.0, + 51, + 4.9, + 326, + 2, + 22, + ), + Dessert( + 'Apple Pie', + 518, + 26.0, + 65, + 7.0, + 54, + 12, + 6, + ), + Dessert( + 'Frozen Yougurt with sugar', + 168, + 6.0, + 26, + 4.0, + 87, + 14, + 1, + ), + Dessert( + 'Ice Cream Sandwich with sugar', + 246, + 9.0, + 39, + 4.3, + 129, + 8, + 1, + ), + Dessert( + 'Eclair with sugar', + 271, + 16.0, + 26, + 6.0, + 337, + 6, + 7, + ), + Dessert( + 'Cupcake with sugar', + 314, + 3.7, + 69, + 4.3, + 413, + 3, + 8, + ), + Dessert( + 'Gingerbread with sugar', + 345, + 16.0, + 51, + 3.9, + 327, + 7, + 16, + ), + Dessert( + 'Jelly Bean with sugar', + 364, + 0.0, + 96, + 0.0, + 50, + 0, + 0, + ), + Dessert( + 'Lollipop with sugar', + 401, + 0.2, + 100, + 0.0, + 38, + 0, + 2, + ), + Dessert( + 'Honeycomd with sugar', + 417, + 3.2, + 89, + 6.5, + 562, + 0, + 45, + ), + Dessert( + 'Donut with sugar', + 461, + 25.0, + 53, + 4.9, + 326, + 2, + 22, + ), + Dessert( + 'Apple pie with sugar', + 527, + 26.0, + 67, + 7.0, + 54, + 12, + 6, + ), + Dessert( + 'Forzen yougurt with honey', + 223, + 6.0, + 36, + 4.0, + 87, + 14, + 1, + ), + Dessert( + 'Ice Cream Sandwich with honey', + 301, + 9.0, + 49, + 4.3, + 129, + 8, + 1, + ), + Dessert( + 'Eclair with honey', + 326, + 16.0, + 36, + 6.0, + 337, + 6, + 7, + ), + Dessert( + 'Cupcake with honey', + 369, + 3.7, + 79, + 4.3, + 413, + 3, + 8, + ), + Dessert( + 'Gignerbread with hone', + 420, + 16.0, + 61, + 3.9, + 327, + 7, + 16, + ), + Dessert( + 'Jelly Bean with honey', + 439, + 0.0, + 106, + 0.0, + 50, + 0, + 0, + ), + Dessert( + 'Lollipop with honey', + 456, + 0.2, + 110, + 0.0, + 38, + 0, + 2, + ), + Dessert( + 'Honeycomd with honey', + 472, + 3.2, + 99, + 6.5, + 562, + 0, + 45, + ), + Dessert( + 'Donut with honey', + 516, + 25.0, + 63, + 4.9, + 326, + 2, + 22, + ), + Dessert( + 'Apple pie with honey', + 582, + 26.0, + 77, + 7.0, + 54, + 12, + 6, + ), +]; + +List _dessertsX3 = _desserts.toList() + ..addAll(_desserts.map((i) => Dessert('${i.name} x2', i.calories, i.fat, + i.carbs, i.protein, i.sodium, i.calcium, i.iron))) + ..addAll(_desserts.map((i) => Dessert('${i.name} x3', i.calories, i.fat, + i.carbs, i.protein, i.sodium, i.calcium, i.iron))); + +_showSnackbar(BuildContext context, String text, [Color? color]) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + backgroundColor: color, + duration: const Duration(seconds: 1), + content: Text(text), + )); +} diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/datatable2.dart b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/datatable2.dart new file mode 100644 index 0000000000..f57d5fcd6f --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/datatable2.dart @@ -0,0 +1,195 @@ +import 'package:data_table_2/data_table_2.dart'; +import 'package:flet/flet.dart' as ft; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'utils/datatable.dart'; + +class DataTable2Control extends StatefulWidget { + final Control control; + + const DataTable2Control({ + super.key, + required this.control, + }); + + @override + State createState() => _DataTable2ControlState(); +} + +class _DataTable2ControlState extends State { + //final ScrollController _horizontalController = ScrollController(); + //final ScrollController _controller = ScrollController(); + + // @override + // void dispose() { + // _horizontalController.dispose(); + // _controller.dispose(); + // super.dispose(); + // } + + @override + Widget build(BuildContext context) { + debugPrint("DataTable2Control build: ${widget.control.id}"); + + var bgColor = widget.control.getString("bgcolor"); + var border = widget.control.getBorder("border", Theme.of(context)); + var borderRadius = widget.control.getBorderRadius("border_radius"); + var gradient = widget.control.getGradient("gradient", Theme.of(context)); + var horizontalLines = + widget.control.getBorderSide("horizontal_lines", Theme.of(context)); + var verticalLines = + widget.control.getBorderSide("vertical_lines", Theme.of(context)); + var defaultDecoration = + Theme.of(context).dataTableTheme.decoration ?? const BoxDecoration(); + + BoxDecoration? decoration; + if (bgColor != null || + border != null || + borderRadius != null || + gradient != null) { + decoration = (defaultDecoration as BoxDecoration).copyWith( + color: parseColor(bgColor, Theme.of(context)), + border: border, + borderRadius: borderRadius, + gradient: gradient); + } + + var datatable2 = DataTable2( + // scrollController: _controller, + // horizontalScrollController: _horizontalController, + decoration: decoration, + border: (horizontalLines != null || verticalLines != null) + ? TableBorder( + horizontalInside: horizontalLines ?? BorderSide.none, + verticalInside: verticalLines ?? BorderSide.none) + : null, + clipBehavior: widget.control.getClipBehavior("clip_behavior", Clip.none)!, + checkboxHorizontalMargin: + widget.control.getDouble("checkbox_horizontal_margin"), + columnSpacing: widget.control.getDouble("column_spacing"), + minWidth: widget.control.getDouble("min_width"), + bottomMargin: widget.control.getDouble("bottom_margin"), + empty: widget.control.buildWidget("empty"), + isHorizontalScrollBarVisible: + widget.control.getBool("visible_horizontal_scroll_bar"), + isVerticalScrollBarVisible: + widget.control.getBool("visible_vertical_scroll_bar"), + fixedLeftColumns: widget.control.getInt("fixed_left_columns", 0)!, + fixedTopRows: widget.control.getInt("fixed_top_rows", 1)!, + fixedColumnsColor: + widget.control.getColor("fixed_columns_color", context), + fixedCornerColor: widget.control.getColor("fixed_corner_color", context), + smRatio: widget.control.getDouble("sm_ratio", 0.67)!, + lmRatio: widget.control.getDouble("lm_ratio", 1.2)!, + sortArrowIcon: + widget.control.getIconData("sort_arrow_icon") ?? Icons.arrow_upward, + sortArrowAnimationDuration: widget.control.getDuration( + "sort_arrow_animation_duration", Duration(milliseconds: 150))!, + checkboxAlignment: + widget.control.getAlignment("checkbox_alignment", Alignment.center)!, + headingCheckboxTheme: widget.control + .getCheckboxTheme("heading_checkbox_theme", Theme.of(context)), + datarowCheckboxTheme: widget.control + .getCheckboxTheme("data_row_checkbox_theme", Theme.of(context)), + showHeadingCheckBox: + widget.control.getBool("show_heading_checkbox", true)!, + dataRowColor: widget.control + .getWidgetStateColor("data_row_color", Theme.of(context)), + dataRowHeight: widget.control.getDouble("data_row_height"), + sortArrowIconColor: + widget.control.getColor("sort_arrow_icon_color", context), + dataTextStyle: + widget.control.getTextStyle("data_text_style", Theme.of(context)), + headingRowColor: widget.control + .getWidgetStateColor("heading_row_color", Theme.of(context)), + headingRowHeight: widget.control.getDouble("heading_row_height"), + headingTextStyle: + widget.control.getTextStyle("heading_text_style", Theme.of(context)), + headingRowDecoration: + widget.control.getBoxDecoration("heading_row_decoration", context), + dividerThickness: widget.control.getDouble("divider_thickness"), + horizontalMargin: widget.control.getDouble("horizontal_margin"), + showBottomBorder: widget.control.getBool("show_bottom_border", false)!, + showCheckboxColumn: + widget.control.getBool("show_checkbox_column", false)!, + sortAscending: widget.control.getBool("sort_ascending", false)!, + sortColumnIndex: widget.control.getInt("sort_column_index"), + onSelectAll: widget.control.getBool("on_select_all", false)! + ? (bool? selected) => + widget.control.triggerEvent("select_all", selected) + : null, + columns: widget.control.children("columns").map((column) { + column.notifyParent = true; + var tooltip = + parseTooltip(column.get("tooltip"), context, const Placeholder()); + return DataColumn2( + size: parseColumnSize(column.getString("size"), ColumnSize.S)!, + fixedWidth: column.getDouble("fixed_width"), + numeric: column.getBool("numeric", false)!, + tooltip: tooltip?.message, + headingRowAlignment: + column.getMainAxisAlignment("heading_row_alignment"), + onSort: column.getBool("on_sort", false)! + ? (columnIndex, ascending) => column + .triggerEvent("sort", {"ci": columnIndex, "asc": ascending}) + : null, + label: column.buildTextOrWidget("label")!); + }).toList(), + rows: widget.control.children("rows").map((row) { + row.notifyParent = true; + return DataRow2( + key: ValueKey(row.id), + selected: row.getBool("selected", false)!, + color: row.getWidgetStateColor("color", Theme.of(context)), + specificRowHeight: row.getDouble("specific_row_height"), + decoration: row.getBoxDecoration("decoration", context), + onSelectChanged: row.getBool("on_select_change", false)! + ? (selected) => row.triggerEvent("select_change", selected) + : null, + onLongPress: row.getBool("on_long_press", false)! + ? () => row.triggerEvent("long_press") + : null, + onDoubleTap: row.getBool("on_double_tap", false)! + ? () => row.triggerEvent("double_tap") + : null, + onTap: row.getBool("on_tap", false)! + ? () => row.triggerEvent("tap") + : null, + onSecondaryTap: row.getBool("on_secondary_tap", false)! + ? () => row.triggerEvent("secondary_tap") + : null, + onSecondaryTapDown: row.getBool("on_secondary_tap_down", false)! + ? (details) => + row.triggerEvent("secondary_tap_down", details.toMap()) + : null, + cells: row.children("cells").map((cell) { + cell.notifyParent = true; + return DataCell( + cell.buildWidget("content")!, + placeholder: cell.getBool("placeholder", false)!, + showEditIcon: cell.getBool("show_edit_icon", false)!, + onDoubleTap: cell.getBool("on_double_tap", false)! + ? () => cell.triggerEvent("double_tap") + : null, + onLongPress: cell.getBool("on_long_press", false)! + ? () => cell.triggerEvent("long_press") + : null, + onTap: cell.getBool("on_tap", false)! + ? () => cell.triggerEvent("tap") + : null, + onTapCancel: cell.getBool("on_tap_cancel", false)! + ? () => cell.triggerEvent("tap_cancel") + : null, + onTapDown: cell.getBool("on_tap_down", false)! + ? (details) => cell.triggerEvent("tap_down", details.toMap()) + : null, + ); + }).toList(), + ); + }).toList(), + ); + + return LayoutControl(control: widget.control, child: datatable2); + } +} diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/extension.dart b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/extension.dart new file mode 100644 index 0000000000..2f0172dd19 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/extension.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; + +import 'datatable2.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "DataTable2": + return DataTable2Control(key: key, control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/utils/datatable.dart b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/utils/datatable.dart new file mode 100644 index 0000000000..4e602981d0 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/lib/src/utils/datatable.dart @@ -0,0 +1,11 @@ +import 'package:collection/collection.dart'; +import 'package:data_table_2/data_table_2.dart'; + +ColumnSize? parseColumnSize(String? size, [ColumnSize? defValue]) { + if (size == null) { + return defValue; + } + return ColumnSize.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == size.toLowerCase()) ?? + defValue; +} diff --git a/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/pubspec.yaml b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/pubspec.yaml new file mode 100644 index 0000000000..5cf7afb0c7 --- /dev/null +++ b/sdk/python/packages/flet-datatable2/src/flutter/flet_datatable2/pubspec.yaml @@ -0,0 +1,22 @@ +name: flet_datatable2 +description: Flet DataTable2 control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.3.0 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + data_table_2: ^2.7.2 + + flet: + path: ../../../../../../../packages/flet + + flutter: + sdk: flutter + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-desktop/README.md b/sdk/python/packages/flet-desktop/README.md index a2a61bc5c8..d45c5fe550 100644 --- a/sdk/python/packages/flet-desktop/README.md +++ b/sdk/python/packages/flet-desktop/README.md @@ -1,3 +1,6 @@ # Flet Desktop client in Flutter -This package contains a compiled Flutter Flet desktop client. \ No newline at end of file +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-desktop) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-desktop.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-desktop.svg) + +This package contains a compiled Flutter Flet desktop client. diff --git a/sdk/python/packages/flet-desktop/pyproject.toml b/sdk/python/packages/flet-desktop/pyproject.toml index c1561a4ac6..bc8ca4e9bb 100644 --- a/sdk/python/packages/flet-desktop/pyproject.toml +++ b/sdk/python/packages/flet-desktop/pyproject.toml @@ -5,7 +5,7 @@ description = "Flet Desktop client in Flutter" authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }] license = "Apache-2.0" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "flet" ] @@ -15,9 +15,6 @@ Homepage = "https://flet.dev" Repository = "https://github.com/flet-dev/flet" Documentation = "https://flet.dev/docs" -[tool.setuptools.package-data] -"flet_desktop.app" = ["**/*"] - [build-system] requires = ["setuptools"] -build-backend = "setuptools.build_meta" \ No newline at end of file +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py b/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py index 1575638eee..3a62d0a61d 100644 --- a/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py +++ b/sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py @@ -1,9 +1,13 @@ import asyncio +import ctypes +import ctypes.util import logging import os +import shutil import signal import stat import subprocess +import sys import tarfile import tempfile import urllib.request @@ -19,16 +23,248 @@ is_windows, random_string, safe_tar_extractall, + safe_zip_extractall, ) logger = logging.getLogger(flet_desktop.__name__) +# Supported Linux build targets ordered by glibc version. +# Each entry maps a minimum glibc (major, minor) to a distro_id used in +# release artifact filenames. +_GLIBC_DISTRO_TABLE = [ + ((2, 28), "debian10"), + ((2, 31), "ubuntu20.04"), + ((2, 35), "ubuntu22.04"), + ((2, 36), "debian12"), + ((2, 39), "ubuntu24.04"), +] + def get_package_bin_dir(): + """ + Return the directory that contains bundled desktop runtime artifacts. + + The directory may contain platform-specific executables or compressed + archives used to provision the desktop client at runtime. When the + package is installed without bundled binaries the directory will be + empty and the download path is used instead. + """ + return str(Path(__file__).parent.joinpath("app")) +def __get_desktop_flavor(): + """ + Return the desktop client flavor to use: `"full"` or `"light"`. + + Resolution order: + + 1. `FLET_DESKTOP_FLAVOR` environment variable. + 2. `[tool.flet].desktop_flavor` in the project's `pyproject.toml`. + 3. Default: `"light"` on Linux, `"full"` elsewhere. + """ + + env_flavor = os.environ.get("FLET_DESKTOP_FLAVOR", "").strip().lower() + if env_flavor in ("full", "light"): + return env_flavor + + # Try reading from pyproject.toml in the current working directory. + try: + if sys.version_info >= (3, 11): + import tomllib + else: + import tomli as tomllib # type: ignore[no-redef] + + pyproject_path = Path(os.getcwd()) / "pyproject.toml" + if pyproject_path.is_file(): + with pyproject_path.open("rb") as f: + data = tomllib.load(f) + flavor = data.get("tool", {}).get("flet", {}).get("desktop_flavor", "") + if isinstance(flavor, str) and flavor.strip().lower() in ( + "full", + "light", + ): + return flavor.strip().lower() + except Exception: + pass + + return "light" if is_linux() else "full" + + +def __get_system_glibc_version(): + """ + Return the system glibc version as a `(major, minor)` tuple. + + Falls back to `(0, 0)` when detection fails. + """ + + try: + libc_name = ctypes.util.find_library("c") + if not libc_name: + return (0, 0) + libc = ctypes.CDLL(libc_name) + gnu_get_libc_version = libc.gnu_get_libc_version + gnu_get_libc_version.restype = ctypes.c_char_p + ver_str = gnu_get_libc_version().decode("ascii") + parts = ver_str.split(".") + return (int(parts[0]), int(parts[1])) + except Exception: + return (0, 0) + + +def __get_linux_distro_id(): + """ + Return the distro id to use for downloading the Linux binary archive. + + Uses glibc version detection to pick the best matching build target + (highest glibc requirement that is <= system glibc). Can be + overridden via the `FLET_LINUX_DISTRO` environment variable. + """ + + override = os.environ.get("FLET_LINUX_DISTRO", "").strip() + if override: + return override + + sys_glibc = __get_system_glibc_version() + best = None + for required_glibc, distro_id in _GLIBC_DISTRO_TABLE: + if sys_glibc >= required_glibc: + best = distro_id + if best is None: + best = _GLIBC_DISTRO_TABLE[0][1] # oldest as last resort + logger.warning( + f"Could not detect glibc version (got {sys_glibc}), " + f"falling back to {best}. Set FLET_LINUX_DISTRO to override." + ) + return best + + +def get_artifact_filename(): + """ + Return the release artifact filename for the current platform. + + Windows: `flet-windows.zip` + macOS: `flet-macos.tar.gz` + Linux: `flet-linux-{distro}[-light]-{arch}.tar.gz` + """ + + if is_windows(): + return "flet-windows.zip" + if is_macos(): + return "flet-macos.tar.gz" + # Linux + distro = __get_linux_distro_id() + arch = get_arch() + flavor = __get_desktop_flavor() + if flavor == "light": + return f"flet-linux-{distro}-light-{arch}.tar.gz" + return f"flet-linux-{distro}-{arch}.tar.gz" + + +def __get_client_storage_dir(): + """ + Return a versioned local directory used to store unpacked desktop client files. + + The path format is: `~/.flet/client/flet-desktop-{flavor}-{version}`. + """ + + flavor = __get_desktop_flavor() + return Path.home().joinpath( + ".flet", "client", f"flet-desktop-{flavor}-{flet_desktop.version.version}" + ) + + +def __download_flet_client(file_name): + """ + Download a Flet client archive from GitHub Releases. + + The download URL is constructed from the version embedded in + `flet_desktop.version.version`. It can be overridden entirely + via the `FLET_CLIENT_URL` environment variable. + + Args: + file_name: Archive filename to download (e.g. `flet-macos.tar.gz`). + + Returns: + Local path to the downloaded archive. + """ + + ver = flet_desktop.version.version + flet_url = f"https://github.com/flet-dev/flet/releases/download/v{ver}/{file_name}" + flet_url = os.environ.get("FLET_CLIENT_URL", flet_url) + logger.info(f"Downloading Flet v{ver} from {flet_url}") + print(f"Preparing Flet v{ver} for the first use. This is a one-time operation...") + temp_arch = Path(tempfile.gettempdir()).joinpath(f"{file_name}.{random_string(10)}") + urllib.request.urlretrieve(flet_url, str(temp_arch)) + return str(temp_arch) + + +def ensure_client_cached(): + """ + Ensure the desktop client is extracted in the local cache directory. + + If the cache directory does not exist, looks for a bundled archive in + the package (for PyInstaller bundles) and falls back to downloading + from GitHub Releases. + + Returns: + :class:`Path` to the cache directory containing the unpacked client. + """ + + cache_dir = __get_client_storage_dir() + if cache_dir.exists(): + logger.info(f"Flet client found in cache: {cache_dir}") + return cache_dir + + artifact = get_artifact_filename() + + # Check for a bundled archive (PyInstaller or legacy wheel). + bundled = os.path.join(get_package_bin_dir(), artifact) + if os.path.exists(bundled): + archive_path = bundled + else: + archive_path = __download_flet_client(artifact) + + # Extract to a temp directory first, then atomically rename to the cache + # directory. This prevents a partially extracted cache from being treated + # as valid on a subsequent run. + temp_extract = cache_dir.parent / f"{cache_dir.name}.{random_string(8)}" + temp_extract.mkdir(parents=True, exist_ok=True) + + logger.info(f"Extracting Flet client from {archive_path} to {temp_extract}") + try: + # Use the artifact name (not archive_path which may have a random suffix + # from __download_flet_client) to determine the archive format. + if artifact.endswith(".zip"): + with zipfile.ZipFile(archive_path, "r") as zf: + safe_zip_extractall(zf, str(temp_extract)) + else: + with tarfile.open(archive_path, "r:gz") as tar_arch: + safe_tar_extractall(tar_arch, str(temp_extract)) + + temp_extract.rename(cache_dir) + except Exception: + shutil.rmtree(temp_extract, ignore_errors=True) + raise + + return cache_dir + + def open_flet_view(page_url, assets_dir, hidden): + """ + Start a desktop view process and return the process object and PID file path. + + Args: + page_url: Page endpoint the desktop client should open. + assets_dir: Optional assets directory passed to the client process. + hidden: Whether the window should start hidden. + + Returns: + A tuple containing: + - `subprocess.Popen`: started desktop process. + - `str`: path to a temporary PID file used by `close_flet_view()`. + """ + args, flet_env, pid_file = __locate_and_unpack_flet_view( page_url, assets_dir, hidden ) @@ -36,6 +272,20 @@ def open_flet_view(page_url, assets_dir, hidden): async def open_flet_view_async(page_url, assets_dir, hidden): + """ + Asynchronously start a desktop view process. + + Args: + page_url: Page endpoint the desktop client should open. + assets_dir: Optional assets directory passed to the client process. + hidden: Whether the window should start hidden. + + Returns: + A tuple containing: + - `asyncio.subprocess.Process`: started desktop process. + - `str`: path to a temporary PID file used by `close_flet_view()`. + """ + args, flet_env, pid_file = __locate_and_unpack_flet_view( page_url, assets_dir, hidden ) @@ -46,6 +296,18 @@ async def open_flet_view_async(page_url, assets_dir, hidden): def close_flet_view(pid_file): + """ + Terminate a running desktop view process using its PID file. + + The function attempts to read the process ID from `pid_file`, send a + termination signal, and remove the PID file. Failures while terminating are + intentionally ignored, but the PID file is removed when possible. + + Args: + pid_file: Path to the PID file returned by `open_flet_view()` + or `open_flet_view_async()`. + """ + if pid_file is not None and os.path.exists(pid_file): try: with open(pid_file, encoding="utf-8") as f: @@ -59,6 +321,33 @@ def close_flet_view(pid_file): def __locate_and_unpack_flet_view(page_url, assets_dir, hidden): + """ + Resolve desktop client executable, prepare launch arguments, and environment. + + Resolution strategy (per platform): + + 1. Prefer app binaries produced by `flet build` in the current workspace. + 2. Use `FLET_VIEW_PATH` when provided. + 3. Use cached / downloaded client from `~/.flet/client/`. + + Platform-specific launch commands are prepared for Windows, macOS, and Linux. + + Args: + page_url: Page endpoint the desktop client should open. + assets_dir: Optional assets directory passed to the client process. + hidden: Whether to set `FLET_HIDE_WINDOW_ON_START=true` in process env. + + Returns: + A tuple containing: + - `list[str]`: command arguments for the desktop client. + - `dict[str, str]`: environment variables for the launched process. + - `str`: path to the temporary PID file. + + Raises: + FileNotFoundError: If a required desktop executable or archive + cannot be located or downloaded. + """ + logger.info("Starting Flet View app...") args = [] @@ -68,91 +357,70 @@ def __locate_and_unpack_flet_view(page_url, assets_dir, hidden): if is_windows(): flet_path = None - # try loading Flet client built with the latest run of `flet build` + # 1. Try loading Flet client built with the latest run of `flet build` build_windows = os.path.join(os.getcwd(), "build", "windows") if os.path.exists(build_windows): for f in os.listdir(build_windows): if f.endswith(".exe"): flet_path = os.path.join(build_windows, f) + # 2. Check FLET_VIEW_PATH (developer mode) if not flet_path: - flet_exe = "flet.exe" - temp_flet_dir = Path.home().joinpath( - ".flet", "bin", f"flet-{flet_desktop.version.version}" - ) - - # check if flet_view.exe exists in "bin" directory (user mode) - flet_path = os.path.join(get_package_bin_dir(), "flet", flet_exe) - logger.info(f"Looking for Flet executable at: {flet_path}") - if os.path.exists(flet_path): - logger.info(f"Flet View found in: {flet_path}") - else: - # check if flet.exe is in FLET_VIEW_PATH (flet developer mode) - flet_path = os.environ.get("FLET_VIEW_PATH") - if flet_path and os.path.exists(flet_path): - logger.info(f"Flet View found in PATH: {flet_path}") - flet_path = os.path.join(flet_path, flet_exe) + flet_view_path = os.environ.get("FLET_VIEW_PATH") + if flet_view_path and os.path.exists(flet_view_path): + exe_path = os.path.join(flet_view_path, "flet.exe") + if os.path.isfile(exe_path): + logger.info(f"Flet View found via FLET_VIEW_PATH: {flet_view_path}") + flet_path = exe_path else: - if not temp_flet_dir.exists(): - zip_file = __download_flet_client("flet-windows.zip") - - logger.info( - f"Extracting flet.exe from archive to {temp_flet_dir}" - ) - temp_flet_dir.mkdir(parents=True, exist_ok=True) - with zipfile.ZipFile(zip_file, "r") as zip_arch: - zip_arch.extractall(str(temp_flet_dir)) - flet_path = str(temp_flet_dir.joinpath("flet", flet_exe)) + logger.warning( + f"FLET_VIEW_PATH set to {flet_view_path} " + f"but flet.exe not found there" + ) + + # 3. Use cached or downloaded client + if not flet_path: + cache_dir = ensure_client_cached() + flet_path = str(cache_dir.joinpath("flet", "flet.exe")) + args = [flet_path, page_url, pid_file] + elif is_macos(): app_path = None - # try loading Flet client built with the latest run of `flet build` + # 1. Try loading Flet client built with the latest run of `flet build` build_macos = os.path.join(os.getcwd(), "build", "macos") if os.path.exists(build_macos): for f in os.listdir(build_macos): if f.endswith(".app"): app_path = os.path.join(build_macos, f) + # 2. Check FLET_VIEW_PATH (developer mode) if not app_path: - # build version-specific path to Flet.app - temp_flet_dir = Path.home().joinpath( - ".flet", "bin", f"flet-{flet_desktop.version.version}" - ) - - # check if flet.exe is in FLET_VIEW_PATH (flet developer mode) - flet_path = os.environ.get("FLET_VIEW_PATH") - if flet_path: - logger.info(f"Flet.app is set via FLET_VIEW_PATH: {flet_path}") - temp_flet_dir = Path(flet_path) + flet_view_path = os.environ.get("FLET_VIEW_PATH") + if flet_view_path: + logger.info(f"Flet.app is set via FLET_VIEW_PATH: {flet_view_path}") + temp_flet_dir = Path(flet_view_path) else: - # check if flet_view.app exists in a temp directory - if not temp_flet_dir.exists(): - # check if flet.tar.gz exists - gz_filename = "flet-macos.tar.gz" - tar_file = os.path.join(get_package_bin_dir(), gz_filename) - logger.info(f"Looking for Flet.app archive at: {tar_file}") - if not os.path.exists(tar_file): - tar_file = __download_flet_client(gz_filename) - - logger.info(f"Extracting Flet.app from archive to {temp_flet_dir}") - temp_flet_dir.mkdir(parents=True, exist_ok=True) - with tarfile.open(str(tar_file), "r:gz") as tar_arch: - safe_tar_extractall(tar_arch, str(temp_flet_dir)) - else: - logger.info(f"Flet View found in: {temp_flet_dir}") + # 3. Use cached or downloaded client + temp_flet_dir = ensure_client_cached() app_name = None for f in os.listdir(temp_flet_dir): if f.endswith(".app"): app_name = f - assert ( - app_name is not None - ), f"Application bundle not found in {temp_flet_dir}" + if app_name is None: + raise FileNotFoundError( + f"Application bundle not found in {temp_flet_dir}" + ) app_path = temp_flet_dir.joinpath(app_name) + + logger.info(f"page_url: {page_url}") + logger.info(f"pid_file: {pid_file}") args = ["open", str(app_path), "-n", "-W", "--args", page_url, pid_file] + elif is_linux(): app_path = None - # try loading Flet client built with the latest run of `flet build` + # 1. Try loading Flet client built with the latest run of `flet build` build_linux = os.path.join(os.getcwd(), "build", "linux") if os.path.exists(build_linux): for f in os.listdir(build_linux): @@ -160,36 +428,26 @@ def __locate_and_unpack_flet_view(page_url, assets_dir, hidden): if os.path.isfile(ef) and stat.S_IXUSR & os.stat(ef)[stat.ST_MODE]: app_path = ef + # 2. Check FLET_VIEW_PATH (developer mode) if not app_path: - # build version-specific path to flet folder - temp_flet_dir = Path.home().joinpath( - ".flet", "bin", f"flet-{flet_desktop.version.version}" - ) - - # check if flet.exe is in FLET_VIEW_PATH (flet developer mode) - flet_path = os.environ.get("FLET_VIEW_PATH") - if flet_path: - logger.info(f"Flet View is set via FLET_VIEW_PATH: {flet_path}") - temp_flet_dir = Path(flet_path) - app_path = temp_flet_dir.joinpath("flet") - else: - # check if flet_view.app exists in a temp directory - if not temp_flet_dir.exists(): - # check if flet.tar.gz exists - gz_filename = f"flet-linux-{get_arch()}.tar.gz" - tar_file = os.path.join(get_package_bin_dir(), gz_filename) - logger.info(f"Looking for Flet bundle archive at: {tar_file}") - if not os.path.exists(tar_file): - tar_file = __download_flet_client(gz_filename) - - logger.info(f"Extracting Flet from archive to {temp_flet_dir}") - temp_flet_dir.mkdir(parents=True, exist_ok=True) - with tarfile.open(str(tar_file), "r:gz") as tar_arch: - safe_tar_extractall(tar_arch, str(temp_flet_dir)) + flet_view_path = os.environ.get("FLET_VIEW_PATH") + if flet_view_path: + exe_path = str(Path(flet_view_path).joinpath("flet")) + if os.path.isfile(exe_path): + logger.info( + f"Flet View is set via FLET_VIEW_PATH: {flet_view_path}" + ) + app_path = exe_path else: - logger.info(f"Flet View found in: {temp_flet_dir}") + logger.warning( + f"FLET_VIEW_PATH set to {flet_view_path} " + f"but flet executable not found there" + ) + if not app_path: + # 3. Use cached or downloaded client + cache_dir = ensure_client_cached() + app_path = str(cache_dir.joinpath("flet", "flet")) - app_path = temp_flet_dir.joinpath("flet", "flet") args = [str(app_path), page_url, pid_file] flet_env = {**os.environ} @@ -201,17 +459,3 @@ def __locate_and_unpack_flet_view(page_url, assets_dir, hidden): flet_env["FLET_HIDE_WINDOW_ON_START"] = "true" return args, flet_env, pid_file - - -def __download_flet_client(file_name): - ver = flet_desktop.version.version - if not ver: - import flet.version - from flet.version import update_version - - ver = flet.version.version or update_version() - temp_arch = Path(tempfile.gettempdir()).joinpath(file_name) - flet_url = f"https://github.com/flet-dev/flet/releases/download/v{ver}/{file_name}" - logger.info(f"Downloading Flet v{ver} from {flet_url} to {temp_arch}") - urllib.request.urlretrieve(flet_url, temp_arch) - return str(temp_arch) diff --git a/sdk/python/packages/flet-flashlight/CHANGELOG.md b/sdk/python/packages/flet-flashlight/CHANGELOG.md new file mode 100644 index 0000000000..7015195b95 --- /dev/null +++ b/sdk/python/packages/flet-flashlight/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.80.0 + +## Added + +- Deployed online documentation: https://flet.dev/docs/flashlight/ +- `Flashlight` control new properties: `on`, `on_error` +- `Flashlight` control new methods: `is_available` +- New exception classes: + - `FlashlightException` + - `FlashlightEnableExistentUserException` + - `FlashlightEnableNotAvailableException` + - `FlashlightEnableException` + - `FlashlightDisableExistentUserException` + - `FlashlightDisableNotAvailableException` + - `FlashlightDisableException` + +### Changed + +- Refactored `Flashlight` control to use `@ft.control` dataclass-style definition and switched to `Service` control type. +- `Flashlight` must now be added to `Page.services` instead of `Page.overlay` due to control type change. + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-flashlight/LICENSE b/sdk/python/packages/flet-flashlight/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-flashlight/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-flashlight/README.md b/sdk/python/packages/flet-flashlight/README.md new file mode 100644 index 0000000000..c871cc5879 --- /dev/null +++ b/sdk/python/packages/flet-flashlight/README.md @@ -0,0 +1,44 @@ +# flet-flashlight + +[![pypi](https://img.shields.io/pypi/v/flet-flashlight.svg)](https://pypi.python.org/pypi/flet-flashlight) +[![downloads](https://static.pepy.tech/badge/flet-flashlight/month)](https://pepy.tech/project/flet-flashlight) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-flashlight) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-flashlight.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-flashlight.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-flashlight/LICENSE) + +A [Flet](https://flet.dev) extension to manage the device torch/flashlight. + +It is based on the [flashlight](https://pub.dev/packages/flashlight) Flutter package. + +> **Important:** Add `Flashlight` instances to `page.services` before calling toggle or other methods. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/services/flashlight/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | + +## Usage + +### Installation + +To install the `flet-flashlight` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-flashlight + ``` + +- Using `pip`: + ```bash + pip install flet-flashlight + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/flashlight). diff --git a/sdk/python/packages/flet-flashlight/pyproject.toml b/sdk/python/packages/flet-flashlight/pyproject.toml new file mode 100644 index 0000000000..ce46b49ade --- /dev/null +++ b/sdk/python/packages/flet-flashlight/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-flashlight" +version = "0.1.0" +description = "Control device torch/flashlight from Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/services/flashlight" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-flashlight" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_flashlight" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-flashlight/src/flet_flashlight/__init__.py b/sdk/python/packages/flet-flashlight/src/flet_flashlight/__init__.py new file mode 100644 index 0000000000..20a80b2f5a --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flet_flashlight/__init__.py @@ -0,0 +1,5 @@ +from .flashlight import Flashlight + +__all__ = [ + "Flashlight", +] diff --git a/sdk/python/packages/flet-flashlight/src/flet_flashlight/flashlight.py b/sdk/python/packages/flet-flashlight/src/flet_flashlight/flashlight.py new file mode 100644 index 0000000000..decb0c0818 --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flet_flashlight/flashlight.py @@ -0,0 +1,28 @@ +import flet as ft + +__all__ = ["Flashlight"] + + +@ft.control("Flashlight") +class Flashlight(ft.Service): + """ + A control to use FlashLight. Works on iOS and Android. + """ + + async def on(self): + """ + Turns the flashlight on. + """ + await self._invoke_method("on") + + async def off(self): + """ + Turns the flashlight off. + """ + await self._invoke_method("off") + + async def is_available(self): + """ + Checks if the flashlight is available on the device. + """ + return await self._invoke_method("is_available") diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/.gitignore b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/analysis_options.yaml b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/analysis_options.yaml new file mode 100644 index 0000000000..8df683425b --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:flutter_lints/flutter.yaml + + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/flet_flashlight.dart b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/flet_flashlight.dart new file mode 100644 index 0000000000..42992b0a97 --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/flet_flashlight.dart @@ -0,0 +1,3 @@ +library flet_flashlight; + +export 'src/extension.dart' show Extension; diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/src/extension.dart b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/src/extension.dart new file mode 100644 index 0000000000..215b5db8d2 --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/src/extension.dart @@ -0,0 +1,15 @@ +import 'package:flet/flet.dart'; + +import 'flashlight.dart'; + +class Extension extends FletExtension { + @override + FletService? createService(Control control) { + switch (control.type) { + case "Flashlight": + return FlashlightControl(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/src/flashlight.dart b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/src/flashlight.dart new file mode 100644 index 0000000000..971e40ad4f --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/lib/src/flashlight.dart @@ -0,0 +1,40 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; +import 'package:torch_light/torch_light.dart'; + +class FlashlightControl extends FletService { + FlashlightControl({required super.control}); + + @override + void init() { + super.init(); + debugPrint("Flashlight(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Flashlight.$name($args)"); + if (isMobilePlatform()) { + switch (name) { + case "on": + await TorchLight.enableTorch(); + case "off": + await TorchLight.disableTorch(); + case "is_available": + return await TorchLight.isTorchAvailable(); + default: + throw Exception("Unknown Flashlight method: $name"); + } + } else { + throw Exception( + "Flashlight control is supported only on Android and iOS devices."); + } + } + + @override + void dispose() { + debugPrint("Flashlight(${control.id}).dispose"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml new file mode 100644 index 0000000000..1ca7a12bdf --- /dev/null +++ b/sdk/python/packages/flet-flashlight/src/flutter/flet_flashlight/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_flashlight +description: Flet Flashlight control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + torch_light: 1.1.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-geolocator/CHANGELOG.md b/sdk/python/packages/flet-geolocator/CHANGELOG.md new file mode 100644 index 0000000000..370995bc54 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/CHANGELOG.md @@ -0,0 +1,65 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.85.1 + +### Fixed + +- `Geolocator.get_last_known_position()` no longer crashes with `TypeError: argument after ** must be a mapping, not NoneType` when the platform has no cached fix; it now returns `Optional[GeolocatorPosition]` and yields `None` for the empty case ([#6487](https://github.com/flet-dev/flet/pull/6487)). +- `Geolocator.get_current_position()` no longer hangs indefinitely on web — added a Dart-side `Future.timeout` workaround for the upstream [`geolocator_web` 4.1.3](https://pub.dev/packages/geolocator_web) `inMicroseconds`/`inMilliseconds` timeout typo, and picked sensible web defaults (`time_limit: 30s`, `maximum_age: 5m`) for single-shot calls only (the position stream is left untouched) ([#6487](https://github.com/flet-dev/flet/pull/6487)). +- The Dart side reading `args["settings"]` instead of `args["configuration"]` silently dropped the configuration on every `getCurrentPosition` call; now resolved ([#6487](https://github.com/flet-dev/flet/pull/6487)). +- The position stream is now gated behind a registered `on_position_change` / `on_error` handler, and the previous subscription is cancelled on `update()` to prevent listener leaks and unsolicited CoreLocation prompts at service init ([#6487](https://github.com/flet-dev/flet/pull/6487)). +- Platform exceptions (`LocationServiceDisabledException`, `PermissionDeniedException`, `PermissionDefinitionsNotFoundException`, `PermissionRequestInProgressException`, `PositionUpdateException`, `TimeoutException`) are translated into actionable error messages via a private `_GeolocatorException` whose `toString()` drops the default `Exception:` prefix, so Python sees `RuntimeError("Location request timed out.")` rather than `RuntimeError("Exception: ...")` ([#6487](https://github.com/flet-dev/flet/pull/6487)). + +### Documentation + +- Added a "Web: cached vs. fresh positions" section explaining the default `maximum_age` and how to override it via `GeolocatorWebConfiguration` ([#6487](https://github.com/flet-dev/flet/pull/6487)). +- Added a macOS troubleshooting note for the recurring browser `POSITION_UNAVAILABLE` failure mode (`sudo killall locationd`) ([#6487](https://github.com/flet-dev/flet/pull/6487)). + +## 0.80.0 + +### Added + +- Deployed online documentation: https://flet.dev/docs/geolocator/ +- `Geolocator` control new methods: `distance_between` +- `Geolocator` control new properties: `position`, `configuration` +- New dataclasses: + - `GeolocatorConfiguration` + - `GeolocatorWebConfiguration` + - `GeolocatorIosConfiguration` + - `GeolocatorAndroidConfiguration` + - `ForegroundNotificationConfiguration` + +### Changed + +- Refactored `Geolocator` control to use `@ft.control` dataclass-style definition and switched to `Service` control type + +#### Breaking Changes + +- `Geolocator` must now be added to `Page.services` instead of `Page.overlay`. +- `Geolocator` method `get_current_position_async` parameters changed: + - removed `accuracy` + - `location_settings` renamed to `configuration` (type changed) + - `wait_timeout` renamed to `timeout` +- In all `Geolocator` methods, parameter `wait_timeout` renamed to `timeout`. +- The following `Geolocator` sync methods were made [`async`](https://docs.python.org/3/library/asyncio.html): + - `get_current_position` + - `get_last_known_position` + - `get_permission_status` + - `request_permission` + - `is_location_service_enabled` + - `open_app_settings` + - `open_location_settings` +- Enum `GeolocatorActivityType` renamed to `GeolocatorIosActivityType` + +## 0.1.0 + +Initial release. + + +[0.2.0]: https://github.com/flet-dev/flet-geolocator/compare/0.1.0...0.2.0 +[0.1.0]: https://github.com/flet-dev/flet-geolocator/releases/tag/0.1.0 diff --git a/sdk/python/packages/flet-geolocator/LICENSE b/sdk/python/packages/flet-geolocator/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-geolocator/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-geolocator/README.md b/sdk/python/packages/flet-geolocator/README.md new file mode 100644 index 0000000000..d98bdb93a8 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/README.md @@ -0,0 +1,48 @@ +# flet-geolocator + +[![pypi](https://img.shields.io/pypi/v/flet-geolocator.svg)](https://pypi.python.org/pypi/flet-geolocator) +[![downloads](https://static.pepy.tech/badge/flet-geolocator/month)](https://pepy.tech/project/flet-geolocator) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-geolocator) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-geolocator.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-geolocator.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-geolocator/LICENSE) + +Adds geolocation capabilities to your [Flet](https://flet.dev) apps. + +Features include: +- Get the last known location; +- Get the current location of the device; +- Get continuous location updates; +- Check if location services are enabled on the device. + +It is based on the [geolocator](https://pub.dev/packages/geolocator) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/services/geolocator/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-geolocator` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-geolocator + ``` + +- Using `pip`: + ```bash + pip install flet-geolocator + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/geolocator). diff --git a/sdk/python/packages/flet-geolocator/pyproject.toml b/sdk/python/packages/flet-geolocator/pyproject.toml new file mode 100644 index 0000000000..f7bd370512 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-geolocator" +version = "0.1.0" +description = "Adds geolocation capabilities to your Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/services/geolocator" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-geolocator" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_geolocator" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-geolocator/src/flet_geolocator/__init__.py b/sdk/python/packages/flet-geolocator/src/flet_geolocator/__init__.py new file mode 100644 index 0000000000..d7d0fc12a4 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flet_geolocator/__init__.py @@ -0,0 +1,27 @@ +from flet_geolocator.geolocator import Geolocator +from flet_geolocator.types import ( + ForegroundNotificationConfiguration, + GeolocatorAndroidConfiguration, + GeolocatorConfiguration, + GeolocatorIosActivityType, + GeolocatorIosConfiguration, + GeolocatorPermissionStatus, + GeolocatorPosition, + GeolocatorPositionAccuracy, + GeolocatorPositionChangeEvent, + GeolocatorWebConfiguration, +) + +__all__ = [ + "ForegroundNotificationConfiguration", + "Geolocator", + "GeolocatorAndroidConfiguration", + "GeolocatorConfiguration", + "GeolocatorIosActivityType", + "GeolocatorIosConfiguration", + "GeolocatorPermissionStatus", + "GeolocatorPosition", + "GeolocatorPositionAccuracy", + "GeolocatorPositionChangeEvent", + "GeolocatorWebConfiguration", +] diff --git a/sdk/python/packages/flet-geolocator/src/flet_geolocator/geolocator.py b/sdk/python/packages/flet-geolocator/src/flet_geolocator/geolocator.py new file mode 100644 index 0000000000..b4158787b4 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flet_geolocator/geolocator.py @@ -0,0 +1,194 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_geolocator.types import ( + GeolocatorConfiguration, + GeolocatorPermissionStatus, + GeolocatorPosition, + GeolocatorPositionChangeEvent, +) + +__all__ = ["Geolocator"] + + +@ft.control("Geolocator") +class Geolocator(ft.Service): + """ + A control that allows you to fetch GPS data from your device. + """ + + configuration: Optional[GeolocatorConfiguration] = None + """ + Some additional configuration. + """ + + on_position_change: Optional[ft.EventHandler[GeolocatorPositionChangeEvent]] = None + """ + Fires when the position of the device changes. + """ + + on_error: Optional[ft.ControlEventHandler["Geolocator"]] = None + """ + Fires when an error occurs. + + The :attr:`~flet.Event.data` property of the event + handler argument contains information on the error. + """ + + position: Optional[GeolocatorPosition] = field( + default=None, init=False + ) # TODO: make this property readonly + """ + The current position of the device. (read-only) + + Starts as `None` and will be updated when the position changes. + """ + + async def get_current_position( + self, + configuration: Optional[GeolocatorConfiguration] = None, + ) -> GeolocatorPosition: + """ + Gets the current position of the device with the desired accuracy and settings. + + Note: + Depending on the availability of different location services, + this can take several seconds. It is recommended to call the + :meth:`get_last_known_position` method first to receive a + known/cached position and update it with the result of the + :meth:`get_current_position` method. + + Args: + configuration: Additional configuration for the location request. + If not specified, then the \ + :attr:`flet_geolocator.Geolocator.configuration` + property is used. + + Returns: + The current position of the device as a \ + :class:`~flet_geolocator.GeolocatorPosition`. + """ + r = await self._invoke_method( + method_name="get_current_position", + arguments={"configuration": configuration or self.configuration}, + ) + return GeolocatorPosition(**r) + + async def get_last_known_position(self) -> Optional[GeolocatorPosition]: + """ + Gets the last known position stored on the user's device. + The accuracy can be defined using the + :attr:`~flet_geolocator.Geolocator.configuration` property. + + Returns: + The last known position of the device as a \ + :class:`~flet_geolocator.GeolocatorPosition`, + or `None` if no last known position is available. + + Raises: + FletUnsupportedPlatformException: If invoked on a web platform. + """ + if self.page.web: + raise ft.FletUnsupportedPlatformException( + "get_last_known_position is not supported on web" + ) + r = await self._invoke_method("get_last_known_position") + return GeolocatorPosition(**r) if r else None + + async def get_permission_status(self) -> GeolocatorPermissionStatus: + """ + Gets which permission the app has been granted to access the device's location. + + Returns: + The status of the permission. + """ + r = await self._invoke_method( + "get_permission_status", + ) + return GeolocatorPermissionStatus(r) + + async def request_permission(self) -> GeolocatorPermissionStatus: + """ + Requests the device for access to the device's location. + + Returns: + The status of the permission request. + """ + r = await self._invoke_method("request_permission") + return GeolocatorPermissionStatus(r) + + async def is_location_service_enabled(self) -> bool: + """ + Checks if location service is enabled. + + Returns: + `True` if location service is enabled, `False` otherwise. + """ + return await self._invoke_method("is_location_service_enabled") + + async def open_app_settings(self) -> bool: + """ + Attempts to open the app's settings. + + Returns: + `True` if the app's settings were opened successfully, `False` otherwise. + + Raises: + FletUnsupportedPlatformException: If invoked on a web platform. + """ + if self.page.web: + raise ft.FletUnsupportedPlatformException( + "open_app_settings is not supported on web" + ) + return await self._invoke_method( + "open_app_settings", + ) + + async def open_location_settings(self) -> bool: + """ + Attempts to open the device's location settings. + + Returns: + `True` if the device's settings were opened successfully, `False` otherwise. + + Raises: + FletUnsupportedPlatformException: If invoked on a web platform. + """ + if self.page.web: + raise ft.FletUnsupportedPlatformException( + "open_location_settings is not supported on web" + ) + return await self._invoke_method("open_location_settings") + + async def distance_between( + self, + start_latitude: ft.Number, + start_longitude: ft.Number, + end_latitude: ft.Number, + end_longitude: ft.Number, + ) -> ft.Number: + """ + Calculates the distance between the supplied coordinates in meters. + + The distance between the coordinates is calculated using the + Haversine formula (see https://en.wikipedia.org/wiki/Haversine_formula). + + Args: + start_latitude: The latitude of the starting point, in degrees. + start_longitude: The longitude of the starting point, in degrees. + end_latitude: The latitude of the ending point, in degrees. + end_longitude: The longitude of the ending point, in degrees. + + Returns: + The distance between the coordinates in meters. + """ + return await self._invoke_method( + method_name="distance_between", + arguments={ + "start_latitude": start_latitude, + "start_longitude": start_longitude, + "end_latitude": end_latitude, + "end_longitude": end_longitude, + }, + ) diff --git a/sdk/python/packages/flet-geolocator/src/flet_geolocator/types.py b/sdk/python/packages/flet-geolocator/src/flet_geolocator/types.py new file mode 100644 index 0000000000..4c3c4ed2c5 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flet_geolocator/types.py @@ -0,0 +1,441 @@ +import datetime +from dataclasses import dataclass, field +from enum import Enum +from typing import TYPE_CHECKING, Optional + +import flet as ft + +if TYPE_CHECKING: + from flet_geolocator.geolocator import Geolocator # noqa + +__all__ = [ + "ForegroundNotificationConfiguration", + "GeolocatorAndroidConfiguration", + "GeolocatorConfiguration", + "GeolocatorIosActivityType", + "GeolocatorIosConfiguration", + "GeolocatorPermissionStatus", + "GeolocatorPosition", + "GeolocatorPositionAccuracy", + "GeolocatorPositionChangeEvent", + "GeolocatorWebConfiguration", +] + + +class GeolocatorPositionAccuracy(Enum): + """Represent the possible location accuracy values.""" + + LOWEST = "lowest" + """ + Location is accurate within a distance of 3000m on iOS and 500m on Android. + + On Android, corresponds to + [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive). + """ + + LOW = "low" + """ + Location is accurate within a distance of 1000m on iOS and 500m on Android. + + On Android, corresponds to + [PRIORITY_LOW_POWER](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_low_power). + """ + + MEDIUM = "medium" + """ + Location is accurate within a distance of 100m on iOS and between 100m and + 500m on Android. + + On Android, corresponds to + [PRIORITY_BALANCED_POWER_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_balanced_power_accuracy). + """ + + HIGH = "high" + """ + Location is accurate within a distance of 10m on iOS and between 0m and + 100m on Android. + + On Android, corresponds to + [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy). + """ + + BEST = "best" + """ + Location is accurate within a distance of ~0m on iOS and between 0m and + 100m on Android. + + On Android, corresponds to + [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy). + """ + + BEST_FOR_NAVIGATION = "bestForNavigation" + """ + Location accuracy is optimized for navigation on iOS and matches the + `GeolocatorPositionAccuracy.BEST` on Android. + + On Android, corresponds to + [PRIORITY_HIGH_ACCURACY](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_high_accuracy). + """ + + REDUCED = "reduced" + """ + Location accuracy is reduced for iOS 14+ devices. Matches + `GeolocatorPositionAccuracy.LOWEST` on iOS 13 and below and all other platforms. + + On Android, corresponds to + [PRIORITY_PASSIVE](https://developers.google.com/android/reference/com/google/android/gms/location/Priority#public-static-final-int-priority_passive). + """ + + +class GeolocatorPermissionStatus(Enum): + """Represent the possible location permissions.""" + + DENIED = "denied" + """ + Permission to access the device's location is denied. + + The app should try to request permission using the + :meth:`flet_geolocator.Geolocator.request_permission` method. + """ + + DENIED_FOREVER = "deniedForever" + """ + Permission to access the device's location is permanently denied. + + When requesting permissions, the permission dialog will not be shown until the + user updates the permission in the app settings. + """ + + WHILE_IN_USE = "whileInUse" + """ + Permission to access the device's location is allowed only while the app is in use. + """ + + ALWAYS = "always" + """ + Permission to access the device's location is allowed even when the app is + running in the background. + """ + + UNABLE_TO_DETERMINE = "unableToDetermine" + """ + Permission status cannot be determined. + + This status is only returned by the \ + :meth:`flet_geolocator.Geolocator.request_permission` method + on the web platform for browsers that did not implement the Permissions API. + See: https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API + """ + + +class GeolocatorIosActivityType(Enum): + """Represents the possible iOS activity types.""" + + AUTOMOTIVE_NAVIGATION = "automotiveNavigation" + """ + The location manager is being used specifically during vehicular + navigation to track location changes to the automobile. + """ + + FITNESS = "fitness" + """ + The location manager is being used to track fitness activities such as + walking, running, cycling, and so on. + """ + + OTHER_NAVIGATION = "otherNavigation" + """ + The location manager is being used to track movements for other types of + vehicular navigation that are not automobile related. + """ + + AIRBORNE = "airborne" + """ + The location manager is being used specifically during + airborne activities. + """ + + OTHER = "other" + """ + The location manager is being used for an unknown activity. + """ + + +@ft.value +class GeolocatorPosition: + """Detailed location information.""" + + latitude: Optional[ft.Number] = None + """ + The latitude of this position in degrees normalized to the interval -90.0 + to +90.0 (both inclusive). + """ + + longitude: Optional[ft.Number] = None + """ + The longitude of the position in degrees normalized to the interval -180 + (exclusive) to +180 (inclusive). + """ + + speed: Optional[ft.Number] = None + """ + The speed at which the device is traveling in meters per second over ground. + + The speed is not available on all devices. + In these cases the value is `0.0`. + """ + + altitude: Optional[ft.Number] = None + """ + The altitude of the device in meters. + + The altitude is not available on all devices. + In these cases the returned value is `0.0`. + """ + + timestamp: datetime.datetime = None + """ + The time at which this position was determined. + """ + + accuracy: Optional[ft.Number] = None + """ + The estimated horizontal accuracy of the position in meters. + + The accuracy is not available on all devices. + In these cases the value is `0.0`. + """ + + altitude_accuracy: Optional[ft.Number] = None + """ + The estimated vertical accuracy of the position in meters. + + The accuracy is not available on all devices. + In these cases the value is `0.0`. + """ + + heading: Optional[ft.Number] = None + """ + The heading in which the device is traveling in degrees. + + The heading is not available on all devices. + In these cases the value is `0.0`. + """ + + heading_accuracy: Optional[ft.Number] = None + """ + The estimated heading accuracy of the position in degrees. + + The heading accuracy is not available on all devices. + In these cases the value is `0.0`. + """ + + speed_accuracy: Optional[ft.Number] = None + """ + The estimated speed accuracy of this position, in meters per second. + + The speed accuracy is not available on all devices. + In these cases the value is `0.0`. + """ + + floor: Optional[int] = None + """ + The floor specifies the floor of the building on which the device is + located. + + The floor property is only available on iOS + and only when the information is available. + In all other cases this value will be `None`. + """ + + mocked: Optional[bool] = None + """ + Will be `True` on Android (starting from API level 18) when the location came + from the mocked provider. + + On iOS this value will always be `False`. + """ + + +@ft.value +class GeolocatorConfiguration: + """ + Base configuration for position requests and position-stream updates. + + Use this type when you want the same settings to apply across all + platforms. Platform-specific configuration classes extend it with + additional options. + """ + + accuracy: GeolocatorPositionAccuracy = GeolocatorPositionAccuracy.BEST + """ + Defines the desired accuracy that should be used to determine the location data. + """ + + distance_filter: int = 0 + """ + The minimum distance (measured in meters) a device must move + horizontally before an update event is generated. + + Set to `0` when you want to be notified of all movements. + """ + + time_limit: ft.DurationValue = None + """ + Specifies a timeout interval. + + For no time limit, set to `None`. + """ + + +@ft.value +class GeolocatorWebConfiguration(GeolocatorConfiguration): + """Web specific settings.""" + + maximum_age: ft.DurationValue = field(default_factory=lambda: ft.Duration()) + """ + A value indicating the maximum age of a possible cached + position that is acceptable to return. If set to 0, it means + that the device cannot use a cached position and must + attempt to retrieve the real current position. + """ + + +@ft.value +class GeolocatorIosConfiguration(GeolocatorConfiguration): + """iOS specific settings.""" + + activity_type: GeolocatorIosActivityType = GeolocatorIosActivityType.OTHER + """ + The location manager uses the information in this property as a cue + to determine when location updates may be automatically paused. + """ + + pause_location_updates_automatically: bool = False + """ + Allows the location manager to pause updates to improve battery life + on the target device without sacrificing location data. + When this property is set to `True`, the location manager pauses updates + (and powers down the appropriate hardware) at times when the + location data is unlikely to change. + """ + + show_background_location_indicator: bool = False + """ + Flag to ask the Apple OS to show the background location indicator (iOS only) + if app starts up and background and requests the users location. + + For this setting to work and for the location to be retrieved the user must + have granted "always" permissions for location retrieval. + """ + + allow_background_location_updates: bool = True + """ + Flag to allow the app to receive location updates in the background (iOS only) + + Note: + For this setting to work `Info.plist` should contain the following keys: + - UIBackgroundModes and the value should contain "location" + - NSLocationAlwaysUsageDescription + """ + + +@ft.value +class ForegroundNotificationConfiguration: + """ + Android foreground-service notification settings for background tracking. + + Supply this configuration through + `GeolocatorAndroidConfiguration.foreground_notification_config` to control + the persistent notification shown while background location updates are active. + """ + + notification_title: str + """ + The title used for the foreground service notification. + """ + + notification_text: str + """ + The body used for the foreground service notification. + """ + + notification_channel_name: str = "Background Location" + """ + The user visible name of the notification channel. + + The notification channel name will be displayed in the system settings. + The maximum recommended length is 40 characters, the name might be + truncated if it is to long. Default value: "Background Location". + """ + + notification_enable_wake_lock: bool = False + """ + When enabled, a Wakelock is acquired when background execution is started. + + If this is false then the system can still sleep and all location + events will be received at once when the system wakes up again. + + Wake lock permissions should be obtained first by using a permissions library. + """ + + notification_enable_wifi_lock: bool = False + """ + When enabled, a WifiLock is acquired when background execution is started. + This allows the application to keep the Wi-Fi radio awake, even when the + user has not used the device in a while + (e.g. for background network communications). + + Wifi lock permissions should be obtained first by using a permissions library. + """ + + notification_set_ongoing: bool = False + """ + When enabled, the displayed notification is persistent and + the user cannot dismiss it. + """ + + # foreground_notification_color: Optional[ft.ColorValue] = None + + +@ft.value +class GeolocatorAndroidConfiguration(GeolocatorConfiguration): + """Android specific settings.""" + + interval_duration: ft.DurationValue = field( + default_factory=lambda: ft.Duration(milliseconds=5000) + ) + """ + The desired interval for active location updates. + """ + + use_msl_altitude: bool = False + """ + Whether altitude should be calculated as MSL (EGM2008) from NMEA messages + and reported as the altitude instead of using the geoidal height (WSG84). Setting + this property true will help to align Android altitude to that of iOS which + uses MSL. + + If the NMEA message is empty then the altitude reported will still be + the standard WSG84 altitude from the GPS receiver. + + MSL Altitude is only available starting from Android N and not all devices support + NMEA message returning $GPGGA sequences. + + This property only works with position stream updates and has no effect when + getting the current position or last known position. + """ + + foreground_notification_config: Optional[ForegroundNotificationConfiguration] = None + + +@dataclass +class GeolocatorPositionChangeEvent(ft.Event["Geolocator"]): + """ + Event data provided to `Geolocator.on_position_change` handlers. + """ + + position: GeolocatorPosition + """ + The current/new position of the device. + """ diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/.gitignore b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/analysis_options.yaml b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/flet_geolocator.dart b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/flet_geolocator.dart new file mode 100644 index 0000000000..39799a4a71 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/flet_geolocator.dart @@ -0,0 +1,3 @@ +library flet_geolocator; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/extension.dart b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/extension.dart new file mode 100644 index 0000000000..6a282e4915 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/extension.dart @@ -0,0 +1,15 @@ +import 'package:flet/flet.dart'; + +import 'geolocator.dart'; + +class Extension extends FletExtension { + @override + FletService? createService(Control control) { + switch (control.type) { + case "Geolocator": + return GeolocatorService(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/geolocator.dart b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/geolocator.dart new file mode 100644 index 0000000000..39553e3080 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/geolocator.dart @@ -0,0 +1,159 @@ +import 'dart:async'; + +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:geolocator/geolocator.dart'; + +import 'utils/geolocator.dart'; + +class GeolocatorService extends FletService { + GeolocatorService({required super.control}); + + StreamSubscription? _onPositionChangedSubscription; + + @override + void init() { + super.init(); + debugPrint("Geolocator(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + registerEvents(); + } + + @override + void update() { + debugPrint("Geolocator(${control.id}).update: ${control.properties}"); + registerEvents(); + } + + void registerEvents() { + _onPositionChangedSubscription?.cancel(); + _onPositionChangedSubscription = null; + + if (!control.hasEventHandler("position_change") && + !control.hasEventHandler("error")) { + return; + } + + _onPositionChangedSubscription = Geolocator.getPositionStream( + locationSettings: parseLocationSettings(control.get("configuration")), + ).listen( + (Position? position) { + if (position != null) { + control.updateProperties({"position": position.toMap()}); + control + .triggerEvent("position_change", {"position": position.toMap()}); + } + }, + onError: (Object error, StackTrace stackTrace) { + control.triggerEvent("error", _describeLocationError(error)); + }, + ); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Geolocator.$name($args)"); + try { + switch (name) { + case "request_permission": + var permission = await Geolocator.requestPermission(); + return permission.name; + case "get_permission_status": + var permission = await Geolocator.checkPermission(); + return permission.name; + case "is_location_service_enabled": + var serviceEnabled = await Geolocator.isLocationServiceEnabled(); + return serviceEnabled; + case "open_app_settings": + if (!kIsWeb) { + return await Geolocator.openAppSettings(); + } + return false; + case "open_location_settings": + if (!kIsWeb) { + return await Geolocator.openLocationSettings(); + } + return false; + case "get_last_known_position": + if (!kIsWeb) { + return (await Geolocator.getLastKnownPosition())?.toMap(); + } + return null; + case "get_current_position": + { + final settings = parseLocationSettings(args["configuration"], + forSingleShot: true); + // Workaround for geolocator_web 4.1.3: it passes + // `timeout?.inMicroseconds` to the browser API instead of + // `inMilliseconds`, so the configured timeLimit is effectively + // ignored. Enforce it on the Dart side here. + final positionFuture = + Geolocator.getCurrentPosition(locationSettings: settings); + final timeLimit = settings?.timeLimit; + final currentPosition = kIsWeb && timeLimit != null + ? await positionFuture.timeout(timeLimit, + onTimeout: () => throw TimeoutException( + "Browser did not return a position within " + "${timeLimit.inSeconds}s.", + timeLimit)) + : await positionFuture; + return currentPosition.toMap(); + } + case "distance_between": + var p = [ + args["start_latitude"], + args["start_longitude"], + args["end_latitude"], + args["end_longitude"] + ]; + if (p.every((e) => e != null)) { + return Geolocator.distanceBetween(p[0], p[1], p[2], p[3]); + } + return null; + default: + throw Exception("Unknown Geolocator method: $name"); + } + } catch (error) { + throw _GeolocatorException(_describeLocationError(error)); + } + } + + String _describeLocationError(Object error) { + if (error is LocationServiceDisabledException) { + return "Location services are disabled. " + "Enable them in the device or system settings."; + } + if (error is PermissionDeniedException) { + return "Location permission denied: ${error.message ?? 'no message'}."; + } + if (error is PermissionDefinitionsNotFoundException) { + return "Location permissions are not declared in the platform manifest " + "(Info.plist / AndroidManifest.xml): ${error.message ?? ''}"; + } + if (error is PermissionRequestInProgressException) { + return "A location permission request is already in progress."; + } + if (error is PositionUpdateException) { + return "Failed to obtain position: ${error.message ?? ''}"; + } + if (error is TimeoutException) { + return "Location request timed out."; + } + return error.toString(); + } + + @override + void dispose() { + debugPrint("Geolocator(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + _onPositionChangedSubscription?.cancel(); + super.dispose(); + } +} + +class _GeolocatorException implements Exception { + final String message; + const _GeolocatorException(this.message); + + @override + String toString() => message; +} diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/utils/geolocator.dart b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/utils/geolocator.dart new file mode 100644 index 0000000000..e606d65c78 --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/lib/src/utils/geolocator.dart @@ -0,0 +1,104 @@ +import 'package:collection/collection.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:geolocator/geolocator.dart'; + +LocationAccuracy? parseLocationAccuracy(String? value, + [LocationAccuracy? defaultValue]) { + if (value == null) return defaultValue; + return LocationAccuracy.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +extension PositionExtension on Position { + Map toMap() => { + "latitude": latitude, + "longitude": longitude, + "speed": speed, + "altitude": altitude, + "timestamp": timestamp, + "accuracy": accuracy, + "altitude_accuracy": altitudeAccuracy, + "heading": heading, + "heading_accuracy": headingAccuracy, + "speed_accuracy": speedAccuracy, + "floor": floor, + "mocked": isMocked, + }; +} + +ActivityType? parseActivityType(String? value, [ActivityType? defaultValue]) { + if (value == null) return defaultValue; + return ActivityType.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase()) ?? + defaultValue; +} + +LocationSettings? parseLocationSettings(dynamic value, + {bool forSingleShot = false, LocationSettings? defaultValue}) { + if (value == null) return defaultValue; + + var distanceFilter = parseInt(value["distance_filter"], 0)!; + var accuracy = + parseLocationAccuracy(value["accuracy"], LocationAccuracy.best)!; + var timeLimit = parseDuration(value["time_limit"]); + if (kIsWeb) { + return WebSettings( + accuracy: accuracy, + distanceFilter: distanceFilter, + timeLimit: + timeLimit ?? (forSingleShot ? const Duration(seconds: 30) : null), + maximumAge: parseDuration(value["maximum_age"], + forSingleShot ? const Duration(minutes: 5) : Duration.zero)!, + ); + } else if (isAndroidMobile()) { + return AndroidSettings( + accuracy: accuracy, + distanceFilter: distanceFilter, + timeLimit: timeLimit, + intervalDuration: parseDuration( + value["interval_duration"], const Duration(milliseconds: 5000))!, + useMSLAltitude: parseBool(value["use_msl_altitude"], false)!, + // Needed to prevent background to stop working when app goes in background + foregroundNotificationConfig: (value["foreground_notification_text"] != + null || + value["foreground_notification_title"] != null) + ? ForegroundNotificationConfig( + notificationText: + value["foreground_notification_text"] ?? "Location Updates", + notificationTitle: value["foreground_notification_title"] ?? + "Running in Background", + enableWakeLock: parseBool( + value["foreground_notification_enable_wake_lock"], false)!, + enableWifiLock: parseBool( + value["foreground_notification_enable_wifi_lock"], false)!, + // color: + // parseColor(value["foreground_notification_color"], theme), + notificationChannelName: + value["foreground_notification_channel_name"] ?? + 'Background Location', + setOngoing: parseBool( + value["foreground_notification_set_ongoing"], false)!) + : null); + } else if (isApplePlatform()) { + return AppleSettings( + accuracy: accuracy, + distanceFilter: distanceFilter, + timeLimit: timeLimit, + activityType: + parseActivityType(value["activity_type"], ActivityType.other)!, + pauseLocationUpdatesAutomatically: + parseBool(value["pause_location_updates_automatically"], false)!, + showBackgroundLocationIndicator: + parseBool(value["show_background_location_indicator"], false)!, + allowBackgroundLocationUpdates: + parseBool(value["allow_background_location_updates"], true)!, + ); + } else { + return LocationSettings( + accuracy: accuracy, + distanceFilter: distanceFilter, + timeLimit: timeLimit); + } +} diff --git a/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/pubspec.yaml b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/pubspec.yaml new file mode 100644 index 0000000000..026d3bad9b --- /dev/null +++ b/sdk/python/packages/flet-geolocator/src/flutter/flet_geolocator/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_geolocator +description: Flet Geolocator control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + geolocator: 14.0.2 + collection: ^1.16.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-lottie/CHANGELOG.md b/sdk/python/packages/flet-lottie/CHANGELOG.md new file mode 100644 index 0000000000..396e62490f --- /dev/null +++ b/sdk/python/packages/flet-lottie/CHANGELOG.md @@ -0,0 +1,27 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.85.0 + +### Fixed + +- Fix `Lottie` failing to load local asset files on Windows desktop (and unreliably on other desktop platforms), so animations referenced by `src="file.json"` from the app's `assets/` directory now display correctly ([#6386](https://github.com/flet-dev/flet/issues/6386), [#6426](https://github.com/flet-dev/flet/pull/6426)) by @ndonkoHenri. + +## 0.80.0 + +## Added + +- `Lottie` control new properties: `enable_merge_paths`, `enable_layers_opacity`, `headers`, `error_content`. +- Deployed online documentation: https://flet.dev/docs/lottie/ + +### Changed + +- Refactored `Lottie` control to use `@ft.control` dataclass-style definition. + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-lottie/LICENSE b/sdk/python/packages/flet-lottie/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-lottie/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-lottie/README.md b/sdk/python/packages/flet-lottie/README.md new file mode 100644 index 0000000000..c3fa638c11 --- /dev/null +++ b/sdk/python/packages/flet-lottie/README.md @@ -0,0 +1,42 @@ +# flet-lottie + +[![pypi](https://img.shields.io/pypi/v/flet-lottie.svg)](https://pypi.python.org/pypi/flet-lottie) +[![downloads](https://static.pepy.tech/badge/flet-lottie/month)](https://pepy.tech/project/flet-lottie) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-lottie) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-lottie.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-lottie.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-lottie/LICENSE) + +A [Flet](https://flet.dev) extension package for displaying Lottie animations. + +It is based on the [lottie](https://pub.dev/packages/lottie) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/lottie/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-lottie` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-lottie + ``` + +- Using `pip`: + ```bash + pip install flet-lottie + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/lottie). diff --git a/sdk/python/packages/flet-lottie/pyproject.toml b/sdk/python/packages/flet-lottie/pyproject.toml new file mode 100644 index 0000000000..96103f3f29 --- /dev/null +++ b/sdk/python/packages/flet-lottie/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-lottie" +version = "0.1.0" +description = "Display Lottie animations in Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/lottie" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-lottie" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_lottie" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-lottie/src/flet_lottie/__init__.py b/sdk/python/packages/flet-lottie/src/flet_lottie/__init__.py new file mode 100644 index 0000000000..c6cf2c653a --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flet_lottie/__init__.py @@ -0,0 +1,3 @@ +from flet_lottie.lottie import Lottie + +__all__ = ["Lottie"] diff --git a/sdk/python/packages/flet-lottie/src/flet_lottie/lottie.py b/sdk/python/packages/flet-lottie/src/flet_lottie/lottie.py new file mode 100644 index 0000000000..4c563a8b67 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flet_lottie/lottie.py @@ -0,0 +1,96 @@ +from typing import Optional, Union + +import flet as ft + +__all__ = ["Lottie"] + + +@ft.control("Lottie") +class Lottie(ft.LayoutControl): + """ + Displays lottie animations. + + Note: + - Layer effects are currently not supported. + See [airbnb/lottie-android#1964](https://github.com/airbnb/lottie-android/issues/1964) + and [xvrh/lottie-flutter#189](https://github.com/xvrh/lottie-flutter/issues/189) for details. + """ # noqa: E501 + + src: Union[str, bytes] + """ + The lottie animation source. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + """ + + repeat: bool = True + """ + Whether the animation should repeat in a loop. + + Note: + Has no effect if :attr:`animate` is `False`. + """ + + reverse: bool = False + """ + Whether the animation should be played in reverse + (from start to end and then continuously from end to start). + + Note: + Has no effect if :attr:`animate` or :attr:`repeat` is `False`. + """ + + animate: bool = True + """ + Whether the animation should be played automatically. + """ + + enable_merge_paths: bool = False + """ + Whether to enable merge path support. + """ + + enable_layers_opacity: bool = False + """ + Whether to enable layer-level opacity. + """ + + background_loading: Optional[bool] = None + """ + Whether the animation should be loaded in the background. + """ + + filter_quality: ft.FilterQuality = ft.FilterQuality.LOW + """ + The quality of the image layer. + """ + + fit: Optional[ft.BoxFit] = None + """ + Defines how to inscribe the Lottie composition + into the space allocated during layout. + """ + + headers: Optional[dict[str, str]] = None + """ + Headers for network requests. + """ + + error_content: Optional[ft.Control] = None + """ + A control to display when an error occurs + while loading the Lottie animation. + + For more information on the error, see :attr:`on_error`. + """ + + on_error: Optional[ft.ControlEventHandler["Lottie"]] = None + """ + Fires when an error occurs while loading the Lottie animation. + + The :attr:`~flet.Event.data` property of the event handler argument + contains information on the error. + """ diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/.gitignore b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/.metadata b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/.metadata new file mode 100644 index 0000000000..07d8623a38 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2e9cb0aa71a386a91f73f7088d115c0d96654829" + channel: "stable" + +project_type: package diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/analysis_options.yaml b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/flet_lottie.dart b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/flet_lottie.dart new file mode 100644 index 0000000000..ca99abed23 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/flet_lottie.dart @@ -0,0 +1,3 @@ +library flet_lottie; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/extension.dart b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/extension.dart new file mode 100644 index 0000000000..ed479da13c --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/extension.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; + +import 'lottie.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "Lottie": + return LottieControl(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie.dart b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie.dart new file mode 100644 index 0000000000..6efc1ced62 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie.dart @@ -0,0 +1 @@ +export 'file_lottie_web.dart' if (dart.library.io) 'file_lottie_io.dart'; diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie_io.dart b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie_io.dart new file mode 100644 index 0000000000..536fc9c253 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie_io.dart @@ -0,0 +1,33 @@ +import 'dart:io' as io; + +import 'package:flutter/widgets.dart'; +import 'package:lottie/lottie.dart'; + +LottieBuilder fileLottie( + String path, { + bool? animate, + bool? repeat, + bool? reverse, + AlignmentGeometry? alignment, + BoxFit? fit, + FilterQuality? filterQuality, + LottieOptions? options, + bool? backgroundLoading, + ImageErrorWidgetBuilder? errorBuilder, + void Function(LottieComposition)? onLoaded, + void Function(String)? onWarning, +}) => + Lottie.file( + io.File(path), + animate: animate, + repeat: repeat, + reverse: reverse, + alignment: alignment, + fit: fit, + filterQuality: filterQuality, + options: options, + backgroundLoading: backgroundLoading, + errorBuilder: errorBuilder, + onLoaded: onLoaded, + onWarning: onWarning, + ); diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie_web.dart b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie_web.dart new file mode 100644 index 0000000000..1e988b9ce4 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/file_lottie_web.dart @@ -0,0 +1,24 @@ +import 'package:flutter/widgets.dart'; +import 'package:lottie/lottie.dart'; + +LottieBuilder fileLottie( + String path, { + bool? animate, + bool? repeat, + bool? reverse, + AlignmentGeometry? alignment, + BoxFit? fit, + FilterQuality? filterQuality, + LottieOptions? options, + bool? backgroundLoading, + ImageErrorWidgetBuilder? errorBuilder, + void Function(LottieComposition)? onLoaded, + void Function(String)? onWarning, +}) { + // Local file loading is not supported on web. On web, `getAssetSrc` + // always returns `isFile: false`, so this code path is unreachable at + // runtime — this stub exists only to keep the package compiling for web. + throw UnsupportedError( + 'Lottie.file is not supported on Flutter Web.', + ); +} diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/lottie.dart b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/lottie.dart new file mode 100644 index 0000000000..61e2844ce5 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/lib/src/lottie.dart @@ -0,0 +1,132 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; +import 'package:lottie/lottie.dart'; + +import 'file_lottie.dart'; + +class LottieControl extends StatefulWidget { + final Control control; + + const LottieControl({super.key, required this.control}); + + @override + State createState() => _LottieControlState(); +} + +class _LottieControlState extends State { + @override + Widget build(BuildContext context) { + debugPrint( + "Lottie build: ${widget.control.id} (${widget.control.hashCode})", + ); + + var repeat = widget.control.getBool("repeat", true)!; + var backgroundLoading = widget.control.getBool("background_loading"); + var reverse = widget.control.getBool("reverse", false)!; + var animate = widget.control.getBool("animate", true)!; + var fit = widget.control.getBoxFit("fit"); + var alignment = widget.control.getAlignment("alignment"); + var filterQuality = widget.control.getFilterQuality("filter_quality"); + var errorContent = widget.control.buildWidget("error_content"); + final resolvedSrc = widget.control.getSrc("src"); + + if (resolvedSrc.error != null) { + return errorContent ?? + ErrorControl("Error decoding src", description: resolvedSrc.error); + } + + if (resolvedSrc.isEmpty) { + return const ErrorControl("Lottie must have \"src\" specified."); + } + + var options = LottieOptions( + enableMergePaths: widget.control.getBool("enable_merge_paths", false)!, + enableApplyingOpacityToLayers: widget.control.getBool( + "enable_layers_opacity", + false, + )!, + ); + + void onError(String value) { + if (widget.control.getBool("on_error", false)!) { + widget.control.triggerEvent("error", value); + } + } + + void onLoad(LottieComposition composition) { + if (widget.control.getBool("on_load", false)!) { + widget.control.triggerEvent("load"); + } + } + + Widget errorBuilder(context, error, stackTrace) { + onError(error.toString()); + return errorContent ?? + ErrorControl("Error loading Lottie", description: error.toString()); + } + + Widget? lottie; + + // bytes + if (resolvedSrc.hasBytes) { + try { + lottie = Lottie.memory( + resolvedSrc.bytes!, + repeat: repeat, + reverse: reverse, + animate: animate, + alignment: alignment, + fit: fit, + filterQuality: filterQuality, + options: options, + backgroundLoading: backgroundLoading, + errorBuilder: errorBuilder, + onLoaded: onLoad, + onWarning: onError, + ); + } catch (ex) { + onError(ex.toString()); + return errorContent ?? + ErrorControl("Error decoding src", description: ex.toString()); + } + } else { + var assetSrc = widget.control.backend.getAssetSource(resolvedSrc.uri!); + // Local File + if (assetSrc.isFile) { + lottie = fileLottie( + assetSrc.path, + repeat: repeat, + reverse: reverse, + animate: animate, + alignment: alignment, + options: options, + fit: fit, + filterQuality: filterQuality, + backgroundLoading: backgroundLoading, + errorBuilder: errorBuilder, + onLoaded: onLoad, + onWarning: onError, + ); + } else { + // URL + lottie = Lottie.network( + assetSrc.path, + repeat: repeat, + reverse: reverse, + animate: animate, + alignment: alignment, + fit: fit, + options: options, + filterQuality: filterQuality, + backgroundLoading: backgroundLoading, + headers: widget.control.get("headers")?.cast(), + errorBuilder: errorBuilder, + onLoaded: onLoad, + onWarning: onError, + ); + } + } + + return LayoutControl(control: widget.control, child: lottie); + } +} diff --git a/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/pubspec.yaml b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/pubspec.yaml new file mode 100644 index 0000000000..6e2ff5d5a2 --- /dev/null +++ b/sdk/python/packages/flet-lottie/src/flutter/flet_lottie/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_lottie +description: Flet Lottie control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + lottie: 3.3.3 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-map/CHANGELOG.md b/sdk/python/packages/flet-map/CHANGELOG.md new file mode 100644 index 0000000000..0084909256 --- /dev/null +++ b/sdk/python/packages/flet-map/CHANGELOG.md @@ -0,0 +1,36 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.85.0 + +### Added + +- Added image overlay support for maps with `OverlayImageLayer`, `OverlayImage`, and `RotatedOverlayImage` ([#6319](https://github.com/flet-dev/flet/issues/6319), [#6421](https://github.com/flet-dev/flet/pull/6421)) by @ndonkoHenri. +- Added `SimpleAttribution.text_style` for styling simple map attribution text by @ndonkoHenri. + +## 0.81.1 + +### Added + +- Added `Map.get_camera()` to retrieve current map camera state. +- Added `MapEventType` enum and `MapEvent.event_type`. +- Added `MapEvent.old_camera`, `MapEvent.coordinates`, and `MapEvent.id` payload fields. +- Added support for [WMS](https://www.mngeo.state.mn.us/chouse/wms/index.html) tiles via `TileLayer.wms_configuration` of type `WMSTileLayerConfiguration`. +- Added more examples and `TileLayer` improved documentation. + +### Fixed + +- Corrected `MapEventSource.INTERACTIVE_FLAGS_CHANGED` value to `interactiveFlagsChanged`. + +## 0.80.0 + +- Added configuration helpers for cameras, interaction flags, and stroke patterns. +- Introduced attribution controls and additional layer types for circles, polygons, and polylines. +- Published hosted documentation: https://flet.dev/docs/map/ + +## 0.1.0 + +- Initial release. diff --git a/sdk/python/packages/flet-map/LICENSE b/sdk/python/packages/flet-map/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-map/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-map/README.md b/sdk/python/packages/flet-map/README.md new file mode 100644 index 0000000000..5f2c57c8b8 --- /dev/null +++ b/sdk/python/packages/flet-map/README.md @@ -0,0 +1,42 @@ +# flet-map + +[![pypi](https://img.shields.io/pypi/v/flet-map.svg)](https://pypi.python.org/pypi/flet-map) +[![downloads](https://static.pepy.tech/badge/flet-map/month)](https://pepy.tech/project/flet-map) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-map) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-map.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-map.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-map/LICENSE) + +A [Flet](https://flet.dev) extension for displaying interactive maps. + +It is based on the [flutter_map](https://pub.dev/packages/flutter_map) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/map/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-map` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-map + ``` + +- Using `pip`: + ```bash + pip install flet-map + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/map). diff --git a/sdk/python/packages/flet-map/pyproject.toml b/sdk/python/packages/flet-map/pyproject.toml new file mode 100644 index 0000000000..fcaacf6f6f --- /dev/null +++ b/sdk/python/packages/flet-map/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-map" +version = "0.2.0" +description = "Interactive map controls for Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/map" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-map" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_map" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-map/src/flet_map/__init__.py b/sdk/python/packages/flet-map/src/flet_map/__init__.py new file mode 100644 index 0000000000..dd4b377d00 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/__init__.py @@ -0,0 +1,101 @@ +from flet_map.circle_layer import CircleLayer, CircleMarker +from flet_map.map import Map +from flet_map.map_layer import MapLayer +from flet_map.marker_layer import Marker, MarkerLayer +from flet_map.overlay_image_layer import ( + BaseOverlayImage, + OverlayImage, + OverlayImageLayer, + RotatedOverlayImage, +) +from flet_map.polygon_layer import PolygonLayer, PolygonMarker +from flet_map.polyline_layer import PolylineLayer, PolylineMarker +from flet_map.rich_attribution import RichAttribution +from flet_map.simple_attribution import SimpleAttribution +from flet_map.source_attribution import ( + ImageSourceAttribution, + SourceAttribution, + TextSourceAttribution, +) +from flet_map.tile_layer import TileLayer +from flet_map.types import ( + AttributionAlignment, + Camera, + CameraFit, + CursorKeyboardRotationConfiguration, + CursorRotationBehaviour, + DashedStrokePattern, + DottedStrokePattern, + FadeInTileDisplay, + InstantaneousTileDisplay, + InteractionConfiguration, + InteractionFlag, + KeyboardConfiguration, + MapEvent, + MapEventSource, + MapEventType, + MapHoverEvent, + MapLatitudeLongitude, + MapLatitudeLongitudeBounds, + MapPointerEvent, + MapPositionChangeEvent, + MapTapEvent, + MultiFingerGesture, + PatternFit, + SolidStrokePattern, + StrokePattern, + TileDisplay, + TileLayerEvictErrorTileStrategy, + WMSTileLayerConfiguration, +) + +__all__ = [ + "AttributionAlignment", + "BaseOverlayImage", + "Camera", + "CameraFit", + "CircleLayer", + "CircleMarker", + "CursorKeyboardRotationConfiguration", + "CursorRotationBehaviour", + "DashedStrokePattern", + "DottedStrokePattern", + "FadeInTileDisplay", + "ImageSourceAttribution", + "InstantaneousTileDisplay", + "InteractionConfiguration", + "InteractionFlag", + "KeyboardConfiguration", + "Map", + "MapEvent", + "MapEventSource", + "MapEventType", + "MapHoverEvent", + "MapLatitudeLongitude", + "MapLatitudeLongitudeBounds", + "MapLayer", + "MapPointerEvent", + "MapPositionChangeEvent", + "MapTapEvent", + "Marker", + "MarkerLayer", + "MultiFingerGesture", + "OverlayImage", + "OverlayImageLayer", + "PatternFit", + "PolygonLayer", + "PolygonMarker", + "PolylineLayer", + "PolylineMarker", + "RichAttribution", + "RotatedOverlayImage", + "SimpleAttribution", + "SolidStrokePattern", + "SourceAttribution", + "StrokePattern", + "TextSourceAttribution", + "TileDisplay", + "TileLayer", + "TileLayerEvictErrorTileStrategy", + "WMSTileLayerConfiguration", +] diff --git a/sdk/python/packages/flet-map/src/flet_map/circle_layer.py b/sdk/python/packages/flet-map/src/flet_map/circle_layer.py new file mode 100644 index 0000000000..1f2f4d4f86 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/circle_layer.py @@ -0,0 +1,69 @@ +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer +from flet_map.types import MapLatitudeLongitude + +__all__ = ["CircleLayer", "CircleMarker"] + + +@ft.control("CircleMarker") +class CircleMarker(ft.BaseControl): + """ + A circular marker displayed on the Map at the specified + location through the :class:`~flet_map.CircleLayer`. + """ + + radius: ft.Number + """The radius of the circle""" + + coordinates: MapLatitudeLongitude + """The center coordinates of the circle""" + + color: Optional[ft.ColorValue] = None + """The color of the circle area.""" + + border_color: Optional[ft.ColorValue] = None + """ + The color of the circle border line. + + Tip: + :attr:`border_stroke_width` must be greater than + `0.0` in order for this color to be visible. + """ + + border_stroke_width: ft.Number = 0.0 + """ + The stroke width for the circle border. + + Raises: + ValueError: If it is less than `0.0`. + """ + + use_radius_in_meter: bool = False + """ + Whether the :attr:`radius` should use the unit meters. + """ + + visible: bool = True + """ + Whether this marker is rendered on the map. + """ + + def before_update(self): + super().before_update() + if self.border_stroke_width < 0: + raise ValueError( + "border_stroke_width must be greater than or equal to 0, " + f"got {self.border_stroke_width}" + ) + + +@ft.control("CircleLayer") +class CircleLayer(MapLayer): + """ + A layer to display :class:`~flet_map.CircleMarker`. + """ + + circles: list[CircleMarker] + """A list of :class:`~flet_map.CircleMarker` to display.""" diff --git a/sdk/python/packages/flet-map/src/flet_map/map.py b/sdk/python/packages/flet-map/src/flet_map/map.py new file mode 100644 index 0000000000..12f875ce89 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/map.py @@ -0,0 +1,385 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet.utils import from_dict +from flet_map.map_layer import MapLayer +from flet_map.types import ( + Camera, + CameraFit, + InteractionConfiguration, + MapEvent, + MapHoverEvent, + MapLatitudeLongitude, + MapPointerEvent, + MapPositionChangeEvent, + MapTapEvent, +) + +__all__ = ["Map"] + + +@ft.control("Map") +class Map(ft.LayoutControl): + """ + An interactive map that displays various layers. + """ + + layers: list[MapLayer] + """ + A list of layers to be displayed (stack-like) on the map. + """ + + initial_center: MapLatitudeLongitude = field( + default_factory=lambda: MapLatitudeLongitude(latitude=50.5, longitude=30.51) + ) + """ + The initial center of the map. + """ + + initial_rotation: ft.Number = 0.0 + """ + The rotation (in degrees) when the map is first loaded. + """ + + initial_zoom: ft.Number = 13.0 + """ + The zoom when the map is first loaded. + + If :attr:`initial_camera_fit` is non-`None` this has no effect. + """ + + interaction_configuration: InteractionConfiguration = field( + default_factory=lambda: InteractionConfiguration() + ) + """ + The interaction configuration. + """ + + bgcolor: ft.ColorValue = ft.Colors.GREY_300 + """ + The background color of this control. + """ + + keep_alive: bool = False + """ + Whether to enable the built in keep-alive functionality. + + If the map is within a complex layout, such as a :class:`~flet.ListView`, + the map will reset to its initial position after it appears back into view. + To ensure this doesn't happen, enable this flag to prevent it from rebuilding. + """ + + max_zoom: Optional[ft.Number] = None + """ + The maximum (highest) zoom level of every layer. + Each layer can specify additional zoom level restrictions. + """ + + min_zoom: Optional[ft.Number] = None + """ + The minimum (smallest) zoom level of every layer. + Each layer can specify additional zoom level restrictions. + """ + + animation_curve: ft.AnimationCurve = ft.AnimationCurve.FAST_OUT_SLOWIN + """ + The default animation curve to be used for map-animations + when calling instance methods like :meth:`zoom_in`, + :meth:`rotate_from`, + :meth:`move_to` etc. + """ + + animation_duration: ft.DurationValue = field( + default_factory=lambda: ft.Duration(milliseconds=500) + ) + """ + The default animation duration to be used for map-animations + when calling instance methods like :meth:`zoom_in`, + :meth:`rotate_from`, + :meth:`move_to` etc. + """ + + initial_camera_fit: Optional[CameraFit] = None + """ + Defines the visible bounds when the map is first loaded. + Takes precedence over :attr:`initial_center`/:attr:`initial_zoom`. + """ + + on_init: Optional[ft.ControlEventHandler["Map"]] = None + """ + Fires when the map is initialized. + """ + + on_tap: Optional[ft.EventHandler[MapTapEvent]] = None + """ + Fires when a tap event occurs. + """ + + on_hover: Optional[ft.EventHandler[MapHoverEvent]] = None + """ + Fires when a hover event occurs. + """ + + on_secondary_tap: Optional[ft.EventHandler[MapTapEvent]] = None + """ + Fires when a secondary tap event occurs. + """ + + on_long_press: Optional[ft.EventHandler[MapTapEvent]] = None + """ + Fires when a long press event occurs. + """ + + on_event: Optional[ft.EventHandler[MapEvent]] = None + """ + Fires when any map events occurs. + """ + + on_position_change: Optional[ft.EventHandler[MapPositionChangeEvent]] = None + """ + Fires when the map position changes, e.g. when the user pans or zooms the map. + """ + + on_pointer_down: Optional[ft.EventHandler[MapPointerEvent]] = None + """ + Fires when a pointer down event occurs. + """ + + on_pointer_cancel: Optional[ft.EventHandler[MapPointerEvent]] = None + """ + Fires when a pointer cancel event occurs. + """ + + on_pointer_up: Optional[ft.EventHandler[MapPointerEvent]] = None + """ + Fires when a pointer up event occurs. + """ + + async def rotate_from( + self, + degree: ft.Number, + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Applies a rotation of `degree` to the current rotation. + + Args: + degree: The number of degrees to increment to the current rotation. + animation_curve: The curve of the animation. If None (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. + If None (the default), :attr:`flet_map.Map.animation_duration` will be \ + used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + """ + await self._invoke_method( + method_name="rotate_from", + arguments={ + "degree": degree, + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def reset_rotation( + self, + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Resets the map's rotation to 0 degrees. + + Args: + animation_curve: The curve of the animation. If None (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. + If None (the default), :attr:`flet_map.Map.animation_duration` will be \ + used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + """ + await self._invoke_method( + method_name="reset_rotation", + arguments={ + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def zoom_in( + self, + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Zooms in by one zoom-level from the current one. + + Args: + animation_curve: The curve of the animation. If None (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. If None (the default), + :attr:`flet_map.Map.animation_duration` will be used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + """ + await self._invoke_method( + method_name="zoom_in", + arguments={ + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def zoom_out( + self, + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Zooms out by one zoom-level from the current one. + + Args: + animation_curve: The curve of the animation. If `None` (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. + If None (the default), :attr:`flet_map.Map.animation_duration` will be \ + used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + """ + await self._invoke_method( + method_name="zoom_out", + arguments={ + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def zoom_to( + self, + zoom: ft.Number, + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Zoom the map to a specific zoom level. + + Args: + zoom: The zoom level to zoom to. + animation_curve: The curve of the animation. If `None` (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. + If None (the default), :attr:`flet_map.Map.animation_duration` will be \ + used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + """ + await self._invoke_method( + method_name="zoom_to", + arguments={ + "zoom": zoom, + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def move_to( + self, + destination: Optional[MapLatitudeLongitude] = None, + zoom: Optional[ft.Number] = None, + rotation: Optional[ft.Number] = None, + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + offset: ft.OffsetValue = (0, 0), + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Moves to a specific location. + + Args: + destination: The destination point to move to. + zoom: The zoom level to be applied. If provided, + must be greater than or equal to `0.0`. + rotation: Rotation (in degrees) to be applied. + offset: The offset to be used. Only works when `rotation` is `None`. + animation_curve: The curve of the animation. If None (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. + If None (the default), :attr:`flet_map.Map.animation_duration` will be \ + used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + + Raises: + ValueError: If `zoom` is not `None` and is negative. + """ + if zoom is not None and zoom < 0: + raise ValueError(f"zoom must be greater than or equal to zero, got {zoom}") + await self._invoke_method( + method_name="move_to", + arguments={ + "destination": destination, + "zoom": zoom, + "offset": offset, + "rotation": rotation, + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def center_on( + self, + point: MapLatitudeLongitude, + zoom: Optional[ft.Number], + animation_curve: Optional[ft.AnimationCurve] = None, + animation_duration: Optional[ft.DurationValue] = None, + cancel_ongoing_animations: bool = False, + ) -> None: + """ + Centers the map on the given point. + + Args: + point: The point on which to center the map. + zoom: The zoom level to be applied. + animation_curve: The curve of the animation. If `None` (the default), + :attr:`flet_map.Map.animation_curve` will be used. + animation_duration: The duration of the animation. + If None (the default), :attr:`flet_map.Map.animation_duration` will be \ + used. + cancel_ongoing_animations: Whether to cancel/stop all + ongoing map-animations before starting this new one. + """ + await self._invoke_method( + method_name="center_on", + arguments={ + "point": point, + "zoom": zoom, + "curve": animation_curve or self.animation_curve, + "duration": animation_duration or self.animation_duration, + "cancel_ongoing_animations": cancel_ongoing_animations, + }, + ) + + async def get_camera(self) -> Camera: + """ + Gets the current camera snapshot of the map. + + Returns: + The current camera state. + """ + camera = await self._invoke_method("get_camera") + return from_dict(Camera, camera) diff --git a/sdk/python/packages/flet-map/src/flet_map/map_layer.py b/sdk/python/packages/flet-map/src/flet_map/map_layer.py new file mode 100644 index 0000000000..aea198aa5c --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/map_layer.py @@ -0,0 +1,21 @@ +import flet as ft + +__all__ = ["MapLayer"] + + +@ft.control("MapLayer") +class MapLayer(ft.Control): + """ + Abstract class for all map layers. + + The following layers are available: + + - :class:`~flet_map.CircleLayer` + - :class:`~flet_map.MarkerLayer` + - :class:`~flet_map.OverlayImageLayer` + - :class:`~flet_map.PolygonLayer` + - :class:`~flet_map.PolylineLayer` + - :class:`~flet_map.RichAttribution` + - :class:`~flet_map.SimpleAttribution` + - :class:`~flet_map.TileLayer` + """ diff --git a/sdk/python/packages/flet-map/src/flet_map/marker_layer.py b/sdk/python/packages/flet-map/src/flet_map/marker_layer.py new file mode 100644 index 0000000000..4a10bc7bc3 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/marker_layer.py @@ -0,0 +1,113 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer +from flet_map.types import MapLatitudeLongitude + +__all__ = ["Marker", "MarkerLayer"] + + +@ft.control("Marker") +class Marker(ft.BaseControl): + """ + A marker displayed on the Map at the specified location + through the :class:`~flet_map.MarkerLayer`. + """ + + content: ft.Control + """ + The content to be displayed at :attr:`coordinates`. + + Raises: + ValueError: If it is not :attr:`~flet.Control.visible`. + """ + + coordinates: MapLatitudeLongitude + """ + The coordinates of the marker. + + This will be the center of the marker, + if :attr:`alignment` is :attr:`flet.Alignment.CENTER`. + """ + + rotate: Optional[bool] = None + """ + Whether to counter rotate this marker to the map's rotation, + to keep a fixed orientation. + So, when `True`, this marker will always appear upright and + vertical from the user's perspective. + + If `None`, defaults to the value of the parent :attr:`flet_map.MarkerLayer.rotate`. + + Note: + This is not used to apply a custom rotation in degrees to this marker. + + """ + + height: ft.Number = 30.0 + """ + The height of the :attr:`content` Control. + + Raises: + ValueError: If it is less than `0.0`. + """ + + width: ft.Number = 30.0 + """ + The width of the :attr:`content` Control. + + Raises: + ValueError: If it is less than `0.0`. + """ + + alignment: Optional[ft.Alignment] = None + """ + Alignment of the marker relative to the normal center at :attr:`coordinates`. + + Defaults to the value of the parent :attr:`flet_map.MarkerLayer.alignment`. + """ + + visible: bool = True + """ + Whether this marker is rendered on the map. + """ + + def before_update(self): + super().before_update() + if not self.content.visible: + raise ValueError("content must be visible") + if self.height < 0: + raise ValueError( + f"height must be greater than or equal to 0, got {self.height}" + ) + if self.width < 0: + raise ValueError( + f"width must be greater than or equal to 0, got {self.width}" + ) + + +@ft.control("MarkerLayer") +class MarkerLayer(MapLayer): + """ + A layer to display Markers. + """ + + markers: list[Marker] + """ + A list of :class:`~flet_map.Marker`s to display. + """ + + alignment: Optional[ft.Alignment] = field( + default_factory=lambda: ft.Alignment.CENTER + ) + """ + The alignment of each marker relative to its normal center at + :attr:`flet_map.Marker.coordinates`. + """ + + rotate: bool = False + """ + Whether to counter-rotate :attr:`markers` to the map's rotation, + to keep a fixed orientation. + """ diff --git a/sdk/python/packages/flet-map/src/flet_map/overlay_image_layer.py b/sdk/python/packages/flet-map/src/flet_map/overlay_image_layer.py new file mode 100644 index 0000000000..a06c854afd --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/overlay_image_layer.py @@ -0,0 +1,116 @@ +from typing import Annotated, Union + +import flet as ft +from flet.utils.validation import V +from flet_map.map_layer import MapLayer +from flet_map.types import MapLatitudeLongitude, MapLatitudeLongitudeBounds + +__all__ = [ + "BaseOverlayImage", + "OverlayImage", + "OverlayImageLayer", + "RotatedOverlayImage", +] + + +@ft.control("BaseOverlayImage", kw_only=True) +class BaseOverlayImage(ft.BaseControl): + """ + Abstract class for image overlays displayed through + :class:`~flet_map.OverlayImageLayer`. + + The following overlay image types are available: + + - :class:`~flet_map.OverlayImage` + - :class:`~flet_map.RotatedOverlayImage` + """ + + src: Union[str, bytes] + """ + The image source. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + """ + + opacity: Annotated[ + ft.Number, + V.between(0.0, 1.0), + ] = 1.0 + """ + The opacity in which the image should get rendered on the map. + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ + + gapless_playback: bool = False + """ + Whether to continue showing the old image (`True`), or briefly show nothing + (`False`), when the image provider changes. + """ + + filter_quality: ft.FilterQuality = ft.FilterQuality.MEDIUM + """ + The rendering quality of the image. + """ + + visible: bool = True + """ + Whether this overlay image is rendered on the map. + """ + + +@ft.control("OverlayImage", kw_only=True) +class OverlayImage(BaseOverlayImage): + """ + An unrotated image overlay that spans between a given bounding box. + """ + + bounds: MapLatitudeLongitudeBounds + """ + The latitude and longitude bounds where this image will be displayed. + """ + + +@ft.control("RotatedOverlayImage", kw_only=True) +class RotatedOverlayImage(BaseOverlayImage): + """ + An image overlay transformed across three corner points. + + The top-right corner is derived from :attr:`top_left_corner`, + :attr:`bottom_left_corner`, and :attr:`bottom_right_corner`. + """ + + top_left_corner: MapLatitudeLongitude + """ + The coordinates of the top-left corner of the image. + """ + + bottom_left_corner: MapLatitudeLongitude + """ + The coordinates of the bottom-left corner of the image. + """ + + bottom_right_corner: MapLatitudeLongitude + """ + The coordinates of the bottom-right corner of the image. + """ + + +@ft.control("OverlayImageLayer", kw_only=True) +class OverlayImageLayer(MapLayer): + """ + A layer to display image overlays. + + Tip: + Place this layer after every non-translucent layer that should appear + below it. Layers rendered after this one may cover its overlay images. + """ + + overlay_images: list[BaseOverlayImage] + """ + A list of image overlays to display. + """ diff --git a/sdk/python/packages/flet-map/src/flet_map/polygon_layer.py b/sdk/python/packages/flet-map/src/flet_map/polygon_layer.py new file mode 100644 index 0000000000..f0d371b36c --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/polygon_layer.py @@ -0,0 +1,139 @@ +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer +from flet_map.types import MapLatitudeLongitude + +__all__ = ["PolygonLayer", "PolygonMarker"] + + +@ft.control("PolygonMarker") +class PolygonMarker(ft.BaseControl): + """ + A marker for the :class:`~flet_map.PolygonLayer`. + """ + + coordinates: list[MapLatitudeLongitude] + """ + The points for the outline of this polygon. + """ + + label: Optional[str] = None + """ + An optional label for this polygon. + + Note: + Specifying a label will reduce performance, as the internal + canvas must be drawn to and 'saved' more frequently to ensure the proper + stacking order is maintained. This can be avoided, potentially at the + expense of appearance, by setting \ + :attr:`flet_map.PolygonLayer.draw_labels_last`. + """ + + label_text_style: Optional[ft.TextStyle] = None + """ + The text style for the label. + """ + + border_color: ft.ColorValue = ft.Colors.GREEN + """ + The color of the border outline. + """ + + color: ft.ColorValue = ft.Colors.GREEN + """ + The color of the polygon. + """ + + border_stroke_width: ft.Number = 0.0 + """ + The width of the border outline. + + Raises: + ValueError: If it is less than `0.0`. + """ + + disable_holes_border: bool = False + """ + Whether holes should have borders. + """ + + rotate_label: bool = False + """ + Whether to rotate the label counter to the camera's rotation, + to ensure it remains upright. + """ + + stroke_cap: ft.StrokeCap = ft.StrokeCap.ROUND + """ + Style to use for line endings. + """ + + stroke_join: ft.StrokeJoin = ft.StrokeJoin.ROUND + """ + Style to use for line segment joins. + """ + + visible: bool = True + """ + Whether this marker is rendered on the map. + """ + + def before_update(self): + super().before_update() + if self.border_stroke_width < 0: + raise ValueError( + "border_stroke_width must be greater than or equal to 0, " + f"got {self.border_stroke_width}" + ) + + +@ft.control("PolygonLayer") +class PolygonLayer(MapLayer): + """ + A layer to display PolygonMarkers. + """ + + polygons: list[PolygonMarker] + """ + A list of :class:`~flet_map.PolygonMarker`s to display. + """ + + polygon_culling: bool = True + """ + Whether to cull polygons and polygon sections that are outside of the viewport. + """ + + polygon_labels: bool = True + """ + Whether to draw per-polygon labels. + """ + + draw_labels_last: bool = False + """ + Whether to draw labels last and thus over all the polygons. + """ + + simplification_tolerance: ft.Number = 0.3 + """ + The tolerance value used to simplify polygon outlines before rendering. + + Higher values will result in polygons with fewer points, which can improve + rendering performance at the cost of reduced geometric accuracy. Lower values + preserve more detail but may decrease performance, especially with complex polygons. + + Set to `0` to disable simplification. + """ + + use_alternative_rendering: bool = False + """ + Whether to use an alternative rendering pathway to draw polygons onto the + underlying `Canvas`, which can be more performant in 'some' circumstances. + + This will not always improve performance, and there are other important + considerations before enabling it. It is intended for use when prior + profiling indicates more performance is required after other methods are + already in use. For example, it may worsen performance when there are a + huge number of polygons to triangulate - and so this is best used in + conjunction with simplification, not as a replacement. + """ diff --git a/sdk/python/packages/flet-map/src/flet_map/polyline_layer.py b/sdk/python/packages/flet-map/src/flet_map/polyline_layer.py new file mode 100644 index 0000000000..eb469317e5 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/polyline_layer.py @@ -0,0 +1,129 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer +from flet_map.types import MapLatitudeLongitude, SolidStrokePattern, StrokePattern + +__all__ = ["PolylineLayer", "PolylineMarker"] + + +@ft.control("PolylineMarker") +class PolylineMarker(ft.BaseControl): + """ + A marker for the :class:`~flet_map.PolylineLayer`. + """ + + coordinates: list[MapLatitudeLongitude] + """ + The list of coordinates for the polyline. + """ + + colors_stop: Optional[list[ft.Number]] = None + """ + The stops for the :attr:`gradient_colors`. + """ + + gradient_colors: Optional[list[ft.ColorValue]] = None + """ + The List of colors in case a gradient should get used. + """ + + border_color: ft.ColorValue = ft.Colors.YELLOW + """ + The border's color. + """ + + color: ft.ColorValue = ft.Colors.YELLOW + """ + The color of the line stroke. + """ + + stroke_width: ft.Number = 1.0 + """ + The width of the stroke. + + Raises: + ValueError: If it is less than `0.0`. + """ + + border_stroke_width: ft.Number = 0.0 + """ + The width of the stroke with of the line border. + + Raises: + ValueError: If it is less than `0.0`. + """ + + use_stroke_width_in_meter: bool = False + """ + Whether the stroke's width should have meters as unit. + """ + + stroke_pattern: StrokePattern = field(default_factory=lambda: SolidStrokePattern()) + """ + Determines whether the line should be solid, dotted, or dashed, and the + exact characteristics of each. + """ + + stroke_cap: ft.StrokeCap = ft.StrokeCap.ROUND + """ + Style to use for line endings. + """ + + stroke_join: ft.StrokeJoin = ft.StrokeJoin.ROUND + """ + Style to use for line segment joins. + """ + + visible: bool = True + """ + Whether this marker is rendered on the map. + """ + + def before_update(self): + super().before_update() + if self.border_stroke_width < 0: + raise ValueError( + "border_stroke_width must be greater than or equal to 0, " + f"got {self.border_stroke_width}" + ) + if self.stroke_width < 0: + raise ValueError( + f"stroke_width must be greater than or equal to 0, " + f"got {self.stroke_width}" + ) + + +@ft.control("PolylineLayer") +class PolylineLayer(MapLayer): + """ + A layer to display :class:`~flet_map.PolylineMarker`s. + """ + + polylines: list[PolylineMarker] + """ + List of :class:`~flet_map.PolylineMarker`s to be drawn. + """ + + culling_margin: ft.Number = 10.0 + """ + Acceptable extent outside of viewport before culling polyline segments. + """ + + min_hittable_radius: ft.Number = 10.0 + """ + The minimum radius of the hittable area around each polyline in logical pixels. + + The entire visible area is always hittable, but if the visible area is + smaller than this, then this will be the hittable area. + """ + + simplification_tolerance: ft.Number = 0.3 + """ + The tolerance (in map units) used to simplify polylines for rendering. + + Higher values result in more aggressive simplification, + which can improve performance but may reduce the accuracy of + the displayed polyline. + """ diff --git a/sdk/python/packages/flet-map/src/flet_map/rich_attribution.py b/sdk/python/packages/flet-map/src/flet_map/rich_attribution.py new file mode 100644 index 0000000000..85f2eee78e --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/rich_attribution.py @@ -0,0 +1,65 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer +from flet_map.source_attribution import SourceAttribution +from flet_map.types import AttributionAlignment + +__all__ = ["RichAttribution"] + + +@ft.control("RichAttribution") +class RichAttribution(MapLayer): + """ + An animated and interactive attribution layer that supports both images and text + (displayed in a popup controlled by an icon button adjacent to the images). + """ + + attributions: list[SourceAttribution] + """ + List of attributions to display. + + :class:`~flet_map.TextSourceAttribution`s are shown in a popup box, + unlike :class:`~flet_map.ImageSourceAttribution`, which are visible permanently. + """ + + alignment: Optional[AttributionAlignment] = None + """ + The position in which to anchor this attribution control. + """ + + popup_bgcolor: Optional[ft.ColorValue] = ft.Colors.SURFACE + """ + The color to use as the popup box's background color. + """ + + popup_border_radius: Optional[ft.BorderRadiusValue] = None + """ + The radius of the edges of the popup box. + """ + + popup_initial_display_duration: ft.DurationValue = field( + default_factory=lambda: ft.Duration() + ) + """ + The popup box will be open by default and be hidden this + long after the map is initialised. + + This is useful with certain sources/tile servers that make immediate + attribution mandatory and are not attributed with a permanently + visible :class:`~flet_map.ImageSourceAttribution`. + """ + + permanent_height: ft.Number = 24.0 + """ + The height of the permanent row in which is found the popup menu toggle button. + Also determines spacing between the items within the row. + """ + + show_flutter_map_attribution: bool = True + """ + Whether to add an additional attribution logo and text + for [`flutter-map`](https://docs.fleaflet.dev/), + on which 'flet-map' package is based for map-renderings. + """ diff --git a/sdk/python/packages/flet-map/src/flet_map/simple_attribution.py b/sdk/python/packages/flet-map/src/flet_map/simple_attribution.py new file mode 100644 index 0000000000..161c099a4e --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/simple_attribution.py @@ -0,0 +1,37 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer + +__all__ = ["SimpleAttribution"] + + +@ft.control("SimpleAttribution") +class SimpleAttribution(MapLayer): + """ + A simple attribution layer displayed on the Map. + """ + + text: str + """ + The attribution message to be displayed. + """ + + text_style: Optional[ft.TextStyle] = None + """ + The style to use for :attr:`text`. + """ + + alignment: ft.Alignment = field(default_factory=lambda: ft.Alignment.BOTTOM_RIGHT) + """ + The alignment of this attribution on the map. + """ + + bgcolor: ft.ColorValue = ft.Colors.SURFACE + """ + The color of the box containing the :attr:`text`. + """ + + on_click: Optional[ft.ControlEventHandler["SimpleAttribution"]] = None + """Fired when this attribution is clicked/pressed.""" diff --git a/sdk/python/packages/flet-map/src/flet_map/source_attribution.py b/sdk/python/packages/flet-map/src/flet_map/source_attribution.py new file mode 100644 index 0000000000..3ffc5dabcd --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/source_attribution.py @@ -0,0 +1,75 @@ +from dataclasses import dataclass +from typing import Optional + +import flet as ft + +__all__ = ["ImageSourceAttribution", "SourceAttribution", "TextSourceAttribution"] + + +@dataclass +class SourceAttribution(ft.BaseControl): + """ + Abstract class for source attribution controls: + + - :class:`~flet_map.ImageSourceAttribution` + - :class:`~flet_map.TextSourceAttribution` + """ + + +@ft.control("ImageSourceAttribution") +class ImageSourceAttribution(SourceAttribution): + """ + An image attribution permanently displayed adjacent to the + open/close icon of a :class:`~flet_map.RichAttribution` control. + For it to be displayed, it should be part of a + :attr:`flet_map.RichAttribution.attributions` list. + """ + + image: ft.Image + """ + The :class:`~flet.Image` to be displayed. + + Raises: + ValueError: If the image is not visible. + """ + + height: ft.Number = 24.0 + """ + The height of the image. + Should be the same as :attr:`flet_map.RichAttribution.permanent_height`, + otherwise layout issues may occur. + """ + + tooltip: Optional[str] = None + """Tooltip text to be displayed when the image is hovered over.""" + + on_click: Optional[ft.ControlEventHandler["ImageSourceAttribution"]] = None + """Fired when this attribution is clicked/pressed.""" + + def before_update(self): + super().before_update() + if not self.image.visible: + raise ValueError("image must be visible") + + +@ft.control("TextSourceAttribution") +class TextSourceAttribution(SourceAttribution): + """ + A text source attribution displayed on the Map. + For it to be displayed, it should be part of a + :attr:`flet_map.RichAttribution.attributions` list. + """ + + text: str + """The text to display as attribution, styled with :attr:`text_style`.""" + + text_style: Optional[ft.TextStyle] = None + """Style used to display the :attr:`text`.""" + + prepend_copyright: bool = True + """ + Whether to add the '©' character to the start of :attr:`text` automatically. + """ + + on_click: Optional[ft.ControlEventHandler["TextSourceAttribution"]] = None + """Fired when this attribution is clicked/pressed.""" diff --git a/sdk/python/packages/flet-map/src/flet_map/tile_layer.py b/sdk/python/packages/flet-map/src/flet_map/tile_layer.py new file mode 100644 index 0000000000..250aa5d48a --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/tile_layer.py @@ -0,0 +1,402 @@ +from dataclasses import field +from typing import Optional + +import flet as ft +from flet_map.map_layer import MapLayer +from flet_map.types import ( + FadeInTileDisplay, + MapLatitudeLongitudeBounds, + TileDisplay, + TileLayerEvictErrorTileStrategy, + WMSTileLayerConfiguration, +) + +__all__ = ["TileLayer"] + + +@ft.control("TileLayer") +class TileLayer(MapLayer): + """ + Displays square raster images in a continuous grid, + sourced from the provided :attr:`url_template` and :attr:`fallback_url`. + + Typically, the first layer to be added to a :class:`~flet_map.Map`, + as it provides the tiles on which other layers are displayed. + + Info: Caching + This control supports basic map tile caching (for compatible tile providers). + On non-web platforms, built-in caching is automatically enabled with a default + soft limit of 1 GB. On web platforms, caching is typically handled by the browser. + + No guarantees are provided regarding the persistence or reliability of cached + tiles. Cached data may become unavailable or be cleared at any time. + For example, do not rely on this caching mechanism in scenarios where missing + tiles could create risk or unsafe conditions (for example, offline or + safety-critical mapping applications). + + It aims to: + + - Improve developer experience by: + - Reducing the costs of using tile servers by reducing + duplicate tile requests + - Keep your app lightweight - the built-in cache doesn't ship any binaries + or databases, just a couple extra libraries you probably already use + - Improve user experience by: + - Reducing tile loading durations, as fetching from the cache is very quick + - Reducing network/Internet usage, which may be limited or metered/expensive (eg. mobile broadband) + - Improve compliance with tile server requirements, by reducing the strain on them + - Be extensible, customizable, and integrate with multiple tile providers + + But it comes at the expense of usage of on-device storage capacity. + + Info: Supported sources + flet-map doesn't provide tiles, so you'll need to bring your own raster tiles. + There are multiple different supported sources. + + - Slippy Map/CARTO (XYZ): This is the most common format for raster tiles, + although many satellite tiles will instead use WMS. + Typically, a URL with placeholders for X, Y, and Z values. Set the + :attr:`url_template` to the template provided by the tile server - + usually it can be copied directly from an account portal or documentation. + Additional information, like API/access keys, can be passed in using the + :attr:`additional_options` property. It's also possible to specify a + :attr:`fallback_url` template, used if fetching a tile from the primary + :attr:`url_template` fails. + - Tile Map Service (TMS): This is also supported. Follow the instructions for + the XYZ source above, then set the :attr:`enable_tms` property to `True`. + Read more on WMS [here](https://en.wikipedia.org/wiki/Tile_Map_Service). + - Web Map Services (WMS): This is also supported. Use :attr:`wms_configuration` + to specify the necessary configuration for WMS tile servers. + Read more on WMS [here](https://www.mngeo.state.mn.us/chouse/wms/index.html). + + Example: + ```python + ftm.TileLayer( + url_template="https://tile.openstreetmap.org/{z}/{x}/{y}.png", + user_agent_package_name="MyTownMaps/1.4 (+https://example.org; contact: maps@example.org)", + ) + ``` + """ # noqa: E501 + + url_template: str + """ + The URL template is a string that contains placeholders, + which, when filled in, create a URL/URI to a specific tile. + + Provider Examples: https://wiki.openstreetmap.org/wiki/Raster_tile_providers + + Placeholders: + As well as the standard XYZ placeholders in the template, the following + placeholders may also be used: + + - `{s}`: see :attr:`subdomains` property + - `{r}`: retina scaling factor (2 or 1) + - `{d}`: reflects the :attr:`tile_size` property + + Additional placeholders can also be added freely to the template, + and are filled in with the specified values in :attr:`additional_options`. + This can be used to easier add switchable styles or access tokens. + + Compliance with tile server requirements: + It is your own responsibility to comply with any appropriate restrictions and + requirements set by your chosen tile server/provider. Always read their terms + of service. Failure to do so may lead to any punishment, + at the tile server's discretion. + + Production apps should be extremely cautious about using this tile server; + other projects, libraries, and packages suggesting that OpenStreetMap provides + free-to-use map tiles are incorrect. + + Case Example - OpenStreetMap (direct): + OpenStreetMap (OSM) is one of the most popular sources for map tiles and + data. Their data is free for everyone to use (under + [ODbL](https://opendatacommons.org/licenses/odbl/)), but their public + [tile server](https://tile.openstreetmap.org) is not free for everyone to + use. It is without cost (for users), but, "without cost" ≠ + "without restriction" ≠ "open". Due to excessive usage, the OSM Foundation + (running OSM as a not-for-profit) has implemented some measures to prevent + abuse and ensure the sustainability of their service. + + For example: on non-web platforms (ex: desktop), they require a proper + [User-Agent](https://en.wikipedia.org/wiki/User-Agent_header) header + to be set. See the :attr:`user_agent_package_name` property for + details and recommended best practices. This does not apply to the web + platform, because you cannot set a User-Agent header different to what is + provided by the browser. + + Read more on their tile usage policy + [here](https://operations.osmfoundation.org/policies/tiles/). + """ + + fallback_url: Optional[str] = None + """ + Fallback URL template used if fetching tiles from :attr:`url_template` fails. + + The template must follow the same format and support the same placeholders + as :attr:`url_template`. + + Note: + When this is specified, tiles will not be cached in memory, to prevent + inconsistencies when :attr:`url_template` is unreliable, avoiding + situations where tiles from different sources are displayed simultaneously. + Disabling caching may negatively impact performance and efficiency, hence the + recommendation to only specify a fallback URL when really necessary. + """ + + subdomains: list[str] = field(default_factory=lambda: ["a", "b", "c"]) + """ + List of subdomains used in the URL template. + + To use subdomains, add the `{s}` placeholder to the URL + template (:attr:`url_template` and :attr:`fallback_url`) + + Note: + Subdomains are now usually considered redundant due to the usage of HTTP/2 + & HTTP/3 which don't have the same restrictions. Usage of subdomains will + also hinder the ability to cache tiles, potentially leading to increased tile + requests and costs. Hence, if the server supports HTTP/2 or HTTP/3 + ([how to check](https://stackoverflow.com/a/71288871/11846040)), + avoid using subdomains. + + Example: + If :attr:`subdomains` is set to `["a", "b", "c"]` + and the :attr:`url_template` is + `"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"`, + the resulting tile URLs will be: + + - `"https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"` + - `"https://b.tile.openstreetmap.org/{z}/{x}/{y}.png"` + - `"https://c.tile.openstreetmap.org/{z}/{x}/{y}.png"` + """ + + user_agent_package_name: str = "unknown" + """ + The package name of the user agent to use when fetching tiles from the tile server. + + This is used to identify your app to the tile server, + and is important for compliance with tile server usage policies. + + Tip: OSM best practice recommendations + OpenStreetMap (OSM) [recommends](https://operations.osmfoundation.org/policies/tiles/) the following: + + - Use a clear, unique [User-Agent](https://en.wikipedia.org/wiki/User-Agent_header) + string that names your app and optionally includes a contact URL or email. + - Good Example: `MyTownMaps/1.4 (+https://example.org; contact: maps@example.org)` + - Bad Example: `com.example.app` + - For web apps, the browsers will use the browser’s default `User-Agent` header. + - Do not use a library default User-Agent, and never impersonate + another app or a browser. + - If your platform automatically sets an `X-Requested-With` header with an + app ID, that is acceptable, but a proper `User-Agent` is still recommended. + - Referer (web only): Browsers are expected to send a valid `Referer` header. + Native apps usually do not have a referer, this is ok. + """ # noqa: E501 + + tile_bounds: Optional[MapLatitudeLongitudeBounds] = None + """ + Defines the bounds of the map. + Only tiles that fall within these bounds will be loaded. + """ + + tile_size: int = 256 + """ + The size in pixels of each tile image. + Should be a positive power of `2`. + + Note: + Some tile servers will use 512x512px tiles instead of 256x256px, such as + Mapbox. Using these larger tiles can help reduce tile requests, and when + ombined with Retina Mode, it can give the same resolution. + + To use these tiles, set `tile_size` to the actual dimensions of the tiles + (otherwise they will appear to small), such as `512`. Also set + :attr:`zoom_offset` to the result of `-((d/256) - 1)` - ie. `-1` for + x512px tiles (otherwise they will appear at the wrong geographical locations). + + The `{d}` placeholder may also be used in the URL template + (:attr:`url_template` and :attr:`fallback_url`) to pass through the + value of `tile_size`. + + Raises: + ValueError: If it is less than `0.0`. + """ + + min_native_zoom: int = 0 + """ + Minimum zoom level supported by the tile source. + + Tiles from below this zoom level will not be displayed, instead tiles at + this zoom level will be displayed and scaled. + + This should usually be `0` (as default), as most tile sources will support + zoom levels onwards from this. + + Raises: + ValueError: If it is less than `0.0`. + """ + + max_native_zoom: int = 19 + """ + Maximum zoom number supported by the tile source has available. + + Tiles from above this zoom level will not be displayed, instead tiles at + this zoom level will be displayed and scaled. + + Most tile servers support up to zoom level `19`, which is the default. + Otherwise, this should be specified. + + You can also set :attr:`max_zoom`, which is an absolute zoom limit for users. + It is recommended to set it to a few levels greater than the maximum zoom level + covered by any of your tile layers. + + Raises: + ValueError: If it is less than `0.0`. + """ + + zoom_reverse: bool = False + """ + Whether the zoom number used in tile URLs will be reversed + (`max_zoom - zoom` instead of `zoom`). + """ + + zoom_offset: ft.Number = 0.0 + """ + The zoom number used in tile URLs will be offset with this value. + + Raises: + ValueError: If it is less than `0.0`. + """ + + keep_buffer: int = 2 + """ + When panning the map, keep this many rows and columns of + tiles before unloading them. + """ + + pan_buffer: int = 1 + """ + When loading tiles only visible tiles are loaded by default. + + This option increases the loaded tiles by the given number on both axis which can + help prevent the user from seeing loading tiles whilst panning. Setting the + pan buffer too high can impact performance, typically this is set to `0` or `1`. + """ + + enable_tms: bool = False + """ + Whether to inverse Y-axis numbering for tiles. + Turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services. + """ + + enable_retina_mode: bool = False + """ + Whether to enable retina mode. + Retina mode improves the resolution of map tiles, particularly on + high density displays. + """ + + additional_options: dict[str, str] = field(default_factory=dict) + """ + Static information that should replace placeholders in the :attr:`url_template`. + Applying API keys, for example, is a good usecase of this parameter. + + Example: + ```python + TileLayer( + url_template="https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}{r}.png?access_token={accessToken}", + additional_options={ + 'accessToken': '', + 'id': 'mapbox.streets', + }, + ) + ``` + """ + + max_zoom: ft.Number = float("inf") + """ + The maximum zoom level up to which this layer will be displayed (inclusive). + The main usage for this property is to display a different `TileLayer` + when zoomed far in. + + Prefer :attr:`max_native_zoom` for setting the maximum zoom level supported by the + tile source. + + Typically set to infinity so that there are tiles always displayed. + + Raises: + ValueError: If it is less than `0.0`. + """ + + min_zoom: ft.Number = 0.0 + """ + The minimum zoom level at which this layer is displayed (inclusive). + + Typically `0.0`. + + Raises: + ValueError: If it is less than `0.0`. + """ + + error_image_src: Optional[str] = None + """ + The source of the tile image to show in place of the tile that failed to load. + + See :attr:`on_image_error` property for details on the error. + """ + + evict_error_tile_strategy: Optional[TileLayerEvictErrorTileStrategy] = ( + TileLayerEvictErrorTileStrategy.NONE + ) + """ + If a tile was loaded with error, + the tile provider will be asked to evict the image based on this strategy. + """ + + display_mode: TileDisplay = field(default_factory=lambda: FadeInTileDisplay()) + """ + Defines how tiles are displayed on the map. + """ + + wms_configuration: Optional[WMSTileLayerConfiguration] = None + """ + The configuration for [WMS](https://www.mngeo.state.mn.us/chouse/wms/index.html) + tile servers. + """ + + on_image_error: Optional[ft.ControlEventHandler["TileLayer"]] = None + """ + Fires if an error occurs when fetching the tiles. + + Event handler argument :attr:`~flet.Event.data` property contains + information about the error. + """ + + def before_update(self): + super().before_update() + if self.tile_size < 0: + raise ValueError( + f"tile_size must be greater than or equal to 0, got {self.tile_size}" + ) + if self.min_native_zoom < 0: + raise ValueError( + "min_native_zoom must be greater than or equal to 0, " + f"got {self.min_native_zoom}" + ) + if self.max_native_zoom < 0: + raise ValueError( + "max_native_zoom must be greater than or equal to 0, " + f"got {self.max_native_zoom}" + ) + if self.zoom_offset < 0: + raise ValueError( + f"zoom_offset must be greater than or equal to 0, " + f"got {self.zoom_offset}" + ) + if self.max_zoom < 0: + raise ValueError( + f"max_zoom must be greater than or equal to 0, got {self.max_zoom}" + ) + if self.min_zoom < 0: + raise ValueError( + f"min_zoom must be greater than or equal to 0, got {self.min_zoom}" + ) diff --git a/sdk/python/packages/flet-map/src/flet_map/types.py b/sdk/python/packages/flet-map/src/flet_map/types.py new file mode 100644 index 0000000000..61ca482538 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flet_map/types.py @@ -0,0 +1,1214 @@ +from dataclasses import dataclass, field # dataclass kept for event types +from enum import Enum, IntFlag +from typing import TYPE_CHECKING, Optional + +import flet as ft +from flet.controls.animation import AnimationCurve + +if TYPE_CHECKING: + from flet_map.map import Map # noqa + +__all__ = [ + "AttributionAlignment", + "Camera", + "CameraFit", + "CursorKeyboardRotationConfiguration", + "CursorRotationBehaviour", + "DashedStrokePattern", + "DottedStrokePattern", + "FadeInTileDisplay", + "InstantaneousTileDisplay", + "InteractionConfiguration", + "InteractionFlag", + "KeyboardConfiguration", + "MapEvent", + "MapEventSource", + "MapEventType", + "MapHoverEvent", + "MapLatitudeLongitude", + "MapLatitudeLongitudeBounds", + "MapPointerEvent", + "MapPositionChangeEvent", + "MapTapEvent", + "MultiFingerGesture", + "PatternFit", + "SolidStrokePattern", + "StrokePattern", + "TileDisplay", + "TileLayerEvictErrorTileStrategy", + "WMSTileLayerConfiguration", +] + + +class TileLayerEvictErrorTileStrategy(Enum): + """Strategies on how to handle tile errors.""" + + NONE = "none" + """Never evict images for tiles which failed to load.""" + + DISPOSE = "dispose" + """Evict images for tiles which failed to load when they are pruned.""" + + NOT_VISIBLE = "notVisible" + """ + Evict images for tiles which failed to load and: + - do not belong to the current zoom level AND/OR + - are not visible + """ + + NOT_VISIBLE_RESPECT_MARGIN = "notVisibleRespectMargin" + """ + Evict images for tiles which failed to load and: + - do not belong to the current zoom level AND/OR + - are not visible, respecting the pruning buffer + (the maximum of the `keep_buffer` and `pan_buffer`). + """ + + +class AttributionAlignment(Enum): + """Position to anchor :class:`~flet_map.RichAttribution` control relative to the \ + map.""" + + BOTTOM_LEFT = "bottomLeft" + """The bottom left corner.""" + + BOTTOM_RIGHT = "bottomRight" + """The bottom right corner.""" + + +class PatternFit(Enum): + """ + Determines how a non-solid :class:`~flet_map.StrokePattern` should be fit to a line + when their lengths are not equal or multiples + """ + + NONE = "none" + """ + Don't apply any specific fit to the pattern - repeat exactly as specified, + and stop when the last point is reached. + + Not recommended, as it may leave a gap between the final segment and the last + point, making it unclear where the line ends. + """ + + SCALE_DOWN = "scaleDown" + """ + Scale the pattern to ensure it fits an integer number of times into the + polyline (smaller version regarding rounding, cf. :attr:`SCALE_UP`). + """ + + SCALE_UP = "scaleUp" + """ + Scale the pattern to ensure it fits an integer number of times into the + polyline (bigger version regarding rounding, cf. :attr:`SCALE_DOWN`). + """ + + APPEND_DOT = "appendDot" + """ + Uses the pattern exactly, truncating the final dash if it does not fit, or + adding a single dot at the last point if the final dash does not reach the + last point (there is a gap at that location). + """ + + EXTEND_FINAL_DASH = "extendFinalDash" + """ + Uses the pattern exactly, truncating the final dash if it does not fit, or + extending the final dash to the last point if it would not normally reach + that point (there is a gap at that location). + + Only useful when working with :class:`~flet_map.DashedStrokePattern`. + Similar to `APPEND_DOT` for `DottedStrokePattern`. + """ + + +@ft.value +class Camera: + """ + Snapshot of the map camera state. + """ + + center: "MapLatitudeLongitude" + """ + The center of this camera. + """ + + zoom: ft.Number + """ + Defines how far this camera is zoomed. + """ + + min_zoom: ft.Number + """ + The minimum allowed zoom level. + """ + + max_zoom: ft.Number + """ + The maximum allowed zoom level. + """ + + rotation: ft.Number + """ + The rotation (in degrees) of the camera. + """ + + +@ft.value +class StrokePattern: + """ + Determines whether a stroke should be solid, dotted, or dashed, + and the exact characteristics of each. + + This is an abstract class and shouldn't be used directly. + + See usable derivatives: + - :class:`~flet_map.SolidStrokePattern` + - :class:`~flet_map.DashedStrokePattern` + - :class:`~flet_map.DottedStrokePattern` + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + + +@ft.value +class SolidStrokePattern(StrokePattern): + """A solid/unbroken stroke pattern.""" + + def __post_init__(self): + self._type = "solid" + + +@ft.value +class DashedStrokePattern(StrokePattern): + """ + A stroke pattern of alternating dashes and gaps, defined by :attr:`segments`. + """ + + segments: list[ft.Number] + """ + A list of even length with a minimum of 2, in the form of + `[a₁, b₁, (a₂, b₂, ...)]`, where `a` should be the length of segments in + 'units', and `b` the length of the space after each segment in units. Both + values must be strictly positive. + + 'Units' refers to pixels, unless the pattern has been scaled due to the + :attr:`pattern_fit` being :attr:`flet_map.PatternFit.SCALE_UP`. + + If more than two items are specified, then each segments will + alternate/iterate through the values. + + For example, `[50, 10, 10, 10]` will cause: + + * a segment of length 50px + * followed by a space of 10px + * followed by a segment of length 10px + * followed by a space of 10px + * followed by a segment of length of 50px + * followed by a space of 10px + * and so on ... + + Raises: + ValueError: If the list does not contain at least two items, + or if its length is not even. + """ + + pattern_fit: PatternFit = PatternFit.SCALE_UP + """ + Determines how this stroke pattern should be fit to a line when their lengths + are not equal or multiples. + """ + + def __setattr__(self, name, value): + if name == "segments": + if len(value) < 2: + raise ValueError("segments must contain at least two items") + if len(value) % 2 != 0: + raise ValueError("segments length must be even") + super().__setattr__(name, value) + + def __post_init__(self): + self._type = "dashed" + + +@ft.value +class DottedStrokePattern(StrokePattern): + """ + A stroke pattern of circular dots, spaced with :attr:`spacing_factor`. + """ + + spacing_factor: ft.Number = 1.5 + """ + The multiplier used to calculate the spacing between dots in a dotted polyline, + with respect to `Polyline.stroke_width` / `Polygon.border_stroke_width`. + A value of `1.0` will result in spacing equal to the `stroke_width`. + Increasing the value increases the spacing with the same scaling. + + May also be scaled by the use of :attr:`flet_map.PatternFit.SCALE_UP`. + + Raises: + ValueError: If it is less than or equal to zero. + """ + + pattern_fit: PatternFit = PatternFit.SCALE_UP + """ + Determines how this stroke pattern should be fit to a line when their + lengths are not equal or multiples. + """ + + def __post_init__(self): + if self.spacing_factor <= 0: + raise ValueError( + f"spacing_factor must be greater than to 0.0, got {self.spacing_factor}" + ) + self._type = "dotted" + + +@ft.value +class MapLatitudeLongitude: + """Map coordinates in degrees.""" + + latitude: ft.Number + """The latitude point of this coordinate.""" + + longitude: ft.Number + """The longitude point of this coordinate.""" + + +@ft.value +class MapLatitudeLongitudeBounds: + """ + Both corners have to be on opposite sites, but it doesn't matter + which opposite corners or in what order the corners are provided. + """ + + corner_1: MapLatitudeLongitude + """The corner 1.""" + + corner_2: MapLatitudeLongitude + """The corner 2.""" + + +class InteractionFlag(IntFlag): + """ + Flags to enable/disable certain interaction events on the map. + + Example: + - :attr:`flet_map.InteractionFlag.ALL` to enable all events + - :attr:`flet_map.InteractionFlag.NONE` to disable all events + """ + + NONE = 0 + """No interaction.""" + + DRAG = 1 << 0 + """Panning with a single finger or cursor.""" + + FLING_ANIMATION = 1 << 1 + """Fling animation after panning if velocity is great enough.""" + + PINCH_MOVE = 1 << 2 + """Panning with multiple fingers.""" + + PINCH_ZOOM = 1 << 3 + """Zooming with a multi-finger pinch gesture.""" + + DOUBLE_TAP_ZOOM = 1 << 4 + """Zooming with a single-finger double tap gesture.""" + + DOUBLE_TAP_DRAG_ZOOM = 1 << 5 + """Zooming with a single-finger double-tap-drag gesture.""" + + SCROLL_WHEEL_ZOOM = 1 << 6 + """Zooming with a mouse scroll wheel.""" + + ROTATE = 1 << 7 + """Rotation with two-finger twist gesture.""" + + ALL = ( + (1 << 0) + | (1 << 1) + | (1 << 2) + | (1 << 3) + | (1 << 4) + | (1 << 5) + | (1 << 6) + | (1 << 7) + ) + """All available interactive flags.""" + + @staticmethod + def has_flag(left_flags: int, right_flags: int) -> bool: + """ + Returns: + `True` if `left_flags` has at least one member + in `right_flags` (intersection). + """ + return left_flags & right_flags != 0 + + @staticmethod + def has_multi_finger(flags: int) -> bool: + """ + Returns: + `True` if any multi-finger gesture flags + (:attr:`flet_map.MultiFingerGesture.PINCH_MOVE`, + :attr:`flet_map.MultiFingerGesture.PINCH_ZOOM`, + :attr:`flet_map.MultiFingerGesture.ROTATE`) are enabled. + """ + return InteractionFlag.has_flag( + flags, + ( + MultiFingerGesture.PINCH_MOVE + | MultiFingerGesture.PINCH_ZOOM + | MultiFingerGesture.ROTATE + ), + ) + + @staticmethod + def has_drag(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`~flet_map.InteractionFlag.DRAG` interaction + flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.DRAG) + + @staticmethod + def has_fling_animation(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`~flet_map.InteractionFlag.FLING_ANIMATION` + interaction flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.FLING_ANIMATION) + + @staticmethod + def has_pinch_move(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`~flet_map.InteractionFlag.PINCH_MOVE` + interaction flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.PINCH_MOVE) + + @staticmethod + def has_fling_pinch_zoom(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`~flet_map.InteractionFlag.PINCH_ZOOM` + interaction flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.PINCH_ZOOM) + + @staticmethod + def has_double_tap_drag_zoom(flags: int) -> bool: + """ + Returns: + `True` if the + :attr:`~flet_map.InteractionFlag.DOUBLE_TAP_DRAG_ZOOM` + interaction flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.DOUBLE_TAP_DRAG_ZOOM) + + @staticmethod + def has_double_tap_zoom(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`~flet_map.InteractionFlag.DOUBLE_TAP_ZOOM` + interaction flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.DOUBLE_TAP_ZOOM) + + @staticmethod + def has_rotate(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`ROTATE` interactive flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.ROTATE) + + @staticmethod + def has_scroll_wheel_zoom(flags: int) -> bool: + """ + Returns: + `True` if the :attr:`SCROLL_WHEEL_ZOOM` interaction flag is enabled. + """ + return InteractionFlag.has_flag(flags, InteractionFlag.SCROLL_WHEEL_ZOOM) + + +class MultiFingerGesture(IntFlag): + """Flags to enable/disable certain multi-finger gestures on the map.""" + + NONE = 0 + """No multi-finger gesture.""" + + PINCH_MOVE = 1 << 0 + """Pinch move gesture, which allows moving the map by dragging with two fingers.""" + + PINCH_ZOOM = 1 << 1 + """ + Pinch zoom gesture, which allows zooming in and out by pinching with two fingers. + """ + + ROTATE = 1 << 2 + """Rotate gesture, which allows rotating the map by twisting two fingers.""" + + ALL = (1 << 0) | (1 << 1) | (1 << 2) + """All multi-finger gestures defined in this enum.""" + + +@ft.value +class InteractionConfiguration: + """ + Configures user interaction behavior. + """ + + enable_multi_finger_gesture_race: bool = False + """ + If `True`, then :attr:`rotation_threshold` and :attr:`pinch_zoom_threshold` + and :attr:`pinch_move_threshold` will race. + If multiple gestures win at the same time, then precedence: + :attr:`pinch_zoom_win_gestures` > :attr:`rotation_win_gestures` > + :attr:`pinch_move_win_gestures` + """ + + pinch_move_threshold: ft.Number = 40.0 + """ + Map starts to move when `pinch_move_threshold` has been achieved + or another multi finger gesture wins which allows + :attr:`flet_map.MultiFingerGesture.PINCH_MOVE`. + + Note: + If :attr:`flet_map.InteractionConfiguration.flags` doesn't contain + :attr:`flet_map.InteractionFlag.PINCH_MOVE` or + :attr:`enable_multi_finger_gesture_race` is false then pinch move cannot win. + """ + + scroll_wheel_velocity: ft.Number = 0.005 + """ + The used velocity how fast the map should zoom in or out by scrolling + with the scroll wheel of a mouse. + """ + + pinch_zoom_threshold: ft.Number = 0.5 + """ + Map starts to zoom when `pinch_zoom_threshold` has been achieved or + another multi finger gesture wins which allows + :attr:`flet_map.MultiFingerGesture.PINCH_ZOOM`. + + Note: + If :attr:`flet_map.InteractionConfiguration.flags` + doesn't contain :attr:`flet_map.InteractionFlag.PINCH_ZOOM` + or :attr:`enable_multi_finger_gesture_race` is false then zoom cannot win. + """ + + rotation_threshold: ft.Number = 20.0 + """ + Map starts to rotate when `rotation_threshold` has been achieved or + another multi finger gesture wins which allows \ + :attr:`flet_map.MultiFingerGesture.ROTATE`. + + Note: + If :attr:`flet_map.InteractionConfiguration.flags` + doesn't contain :attr:`flet_map.InteractionFlag.ROTATE` + or :attr:`enable_multi_finger_gesture_race` is false then rotate cannot win. + """ + + flags: InteractionFlag = InteractionFlag.ALL + """ + Defines the map events to be enabled/disabled. + """ + + rotation_win_gestures: MultiFingerGesture = MultiFingerGesture.ROTATE + """ + When :attr:`rotation_threshold` wins over :attr:`pinch_zoom_threshold` and + :attr:`pinch_move_threshold` then `rotation_win_gestures` gestures will be used. + """ + + pinch_move_win_gestures: MultiFingerGesture = ( + MultiFingerGesture.PINCH_ZOOM | MultiFingerGesture.PINCH_MOVE + ) + """ + When :attr:`pinch_move_threshold` wins over :attr:`rotation_threshold` + and :attr:`pinch_zoom_threshold` then `pinch_move_win_gestures` gestures + will be used. + + By default :attr:`flet_map.MultiFingerGesture.PINCH_MOVE` + and :attr:`flet_map.MultiFingerGesture.PINCH_ZOOM` + gestures will take effect see :class:`~flet_map.MultiFingerGesture` for custom \ + settings. + """ + + pinch_zoom_win_gestures: MultiFingerGesture = ( + MultiFingerGesture.PINCH_ZOOM | MultiFingerGesture.PINCH_MOVE + ) + """ + When :attr:`pinch_zoom_threshold` wins over :attr:`rotation_threshold` + and :attr:`pinch_move_threshold` + then `pinch_zoom_win_gestures` gestures will be used. + + By default :attr:`flet_map.MultiFingerGesture.PINCH_ZOOM` + and :attr:`flet_map.MultiFingerGesture.PINCH_MOVE` + gestures will take effect see `MultiFingerGesture` for custom settings. + """ + + keyboard_configuration: "KeyboardConfiguration" = field( + default_factory=lambda: KeyboardConfiguration() + ) + """ + Options to configure how keyboard keys may be used to control the map. + + Keyboard movements using the arrow keys are enabled by default. + """ + + cursor_keyboard_rotation_configuration: "CursorKeyboardRotationConfiguration" = ( + field(default_factory=lambda: CursorKeyboardRotationConfiguration()) + ) + """ + Options to control the keyboard and mouse cursor being used together + to rotate the map. + """ + + +class MapEventSource(Enum): + """Defines the source of a :class:`~flet_map.MapEvent`.""" + + MAP_CONTROLLER = "mapController" + """The `MapEvent` is caused programmatically by the `MapController`.""" + + TAP = "tap" + """The `MapEvent` is caused by a tap gesture.""" + + SECONDARY_TAP = "secondaryTap" + """The `MapEvent` is caused by a secondary tap gesture.""" + + LONG_PRESS = "longPress" + """The `MapEvent` is caused by a long press gesture.""" + + DOUBLE_TAP = "doubleTap" + """The `MapEvent` is caused by a double tap gesture.""" + + DOUBLE_TAP_HOLD = "doubleTapHold" + """The `MapEvent` is caused by a double tap and hold gesture.""" + + DRAG_START = "dragStart" + """The `MapEvent` is caused by the start of a drag gesture.""" + + ON_DRAG = "onDrag" + """The `MapEvent` is caused by a drag update gesture.""" + + DRAG_END = "dragEnd" + """The `MapEvent` is caused by the end of a drag gesture.""" + + MULTI_FINGER_GESTURE_START = "multiFingerGestureStart" + """The `MapEvent` is caused by the start of a two finger gesture.""" + + ON_MULTI_FINGER = "onMultiFinger" + """The `MapEvent` is caused by a two finger gesture update.""" + + MULTI_FINGER_GESTURE_END = "multiFingerEnd" + """The `MapEvent` is caused by a the end of a two finger gesture.""" + + FLING_ANIMATION_CONTROLLER = "flingAnimationController" + """ + The `MapEvent` is caused by the `AnimationController` while + performing the fling gesture. + """ + + DOUBLE_TAP_ZOOM_ANIMATION_CONTROLLER = "doubleTapZoomAnimationController" + """ + The `MapEvent` is caused by the `AnimationController` + while performing the double tap zoom in animation. + """ + + INTERACTIVE_FLAGS_CHANGED = "interactiveFlagsChanged" + """The `MapEvent` is caused by a change of the interactive flags.""" + + FIT_CAMERA = "fitCamera" + """The `MapEvent` is caused by calling fit_camera.""" + + CUSTOM = "custom" + """The `MapEvent` is caused by a custom source.""" + + SCROLL_WHEEL = "scrollWheel" + """The `MapEvent` is caused by a scroll wheel zoom gesture.""" + + NON_ROTATED_SIZE_CHANGE = "nonRotatedSizeChange" + """The `MapEvent` is caused by a size change of the `Map` constraints.""" + + CURSOR_KEYBOARD_ROTATION = "cursorKeyboardRotation" + """The `MapEvent` is caused by a 'CTRL + drag' rotation gesture.""" + + KEYBOARD = "keyboard" + """ + The `MapEvent` is caused by a keyboard key. + See :class:`~flet_map.KeyboardConfiguration` for details. + """ + + +class MapEventType(Enum): + """Concrete subtype of a :class:`~flet_map.MapEvent`.""" + + TAP = "tap" + """A map tap event.""" + + SECONDARY_TAP = "secondaryTap" + """A secondary tap event.""" + + LONG_PRESS = "longPress" + """A long press event.""" + + MOVE = "move" + """A camera move update event.""" + + MOVE_START = "moveStart" + """The start of a move gesture/interaction.""" + + MOVE_END = "moveEnd" + """The end of a move gesture/interaction.""" + + FLING_ANIMATION = "flingAnimation" + """A fling animation update event.""" + + FLING_ANIMATION_NOT_STARTED = "flingAnimationNotStarted" + """A fling was evaluated but not started.""" + + FLING_ANIMATION_START = "flingAnimationStart" + """The start of a fling animation.""" + + FLING_ANIMATION_END = "flingAnimationEnd" + """The end of a fling animation.""" + + DOUBLE_TAP_ZOOM = "doubleTapZoom" + """A double tap zoom update event.""" + + SCROLL_WHEEL_ZOOM = "scrollWheelZoom" + """A scroll wheel zoom update event.""" + + DOUBLE_TAP_ZOOM_START = "doubleTapZoomStart" + """The start of a double tap zoom animation.""" + + DOUBLE_TAP_ZOOM_END = "doubleTapZoomEnd" + """The end of a double tap zoom animation.""" + + ROTATE = "rotate" + """A map rotation update event.""" + + ROTATE_START = "rotateStart" + """The start of a rotation interaction.""" + + ROTATE_END = "rotateEnd" + """The end of a rotation interaction.""" + + NON_ROTATED_SIZE_CHANGE = "nonRotatedSizeChange" + """A map constraint/size-change event.""" + + UNKNOWN = "unknown" + """Fallback value for unrecognized map event types.""" + + +@ft.value +class CameraFit: + """ + Defines how the camera should fit the bounds or coordinates, + depending on which one was provided. + + Raises: + ValueError: If both :attr:`bounds` and :attr:`coordinates` + are `None` or not `None`. + """ + + bounds: Optional[MapLatitudeLongitudeBounds] = None + """ + The bounds which the camera should contain once it is fitted. + + Note: + If this is not `None`, :attr:`coordinates` should be `None`, and vice versa. + """ + + coordinates: Optional[list[MapLatitudeLongitude]] = None + """ + The coordinates which the camera should contain once it is fitted. + + Note: + If this is not `None`, :attr:`bounds` should be `None`, and vice versa. + """ + + max_zoom: Optional[ft.Number] = None + """ + The inclusive upper zoom limit used for the resulting fit. + + If the zoom level calculated for the fit exceeds the `max_zoom` value, + `max_zoom` will be used instead. + """ + + min_zoom: ft.Number = 0.0 + """ + """ + + padding: ft.PaddingValue = field(default_factory=lambda: ft.Padding.zero()) + """ + Adds a constant/pixel-based padding to the normal fit. + """ + + force_integer_zoom_level: bool = False + """ + Whether the zoom level of the resulting fit should be rounded to the + nearest integer level. + """ + + def __post_init__(self): + if not ( + (self.bounds and not self.coordinates) + or (self.coordinates and not self.bounds) + ): + raise ValueError( + "only one of bounds or coordinates must be provided, not both" + ) + + +@dataclass +class MapTapEvent(ft.TapEvent["Map"]): + """ + Map tap event that includes information on the tap. + """ + + coordinates: MapLatitudeLongitude + """Coordinates of the point at which the tap occurred.""" + + +@dataclass +class MapHoverEvent(ft.HoverEvent["Map"]): + """ + Map hover event that includes geographic coordinates of the pointer. + """ + + coordinates: MapLatitudeLongitude + """Coordinates of the point currently hovered by the pointer.""" + + +@dataclass +class MapPositionChangeEvent(ft.Event["Map"]): + """ + Event emitted when the map camera position changes. + """ + + coordinates: MapLatitudeLongitude + """Current center coordinates after the position change.""" + + camera: Camera + """Current camera snapshot after the change.""" + + has_gesture: bool + """Whether this change was caused by a user gesture.""" + + +@dataclass +class MapPointerEvent(ft.PointerEvent["Map"]): + """ + Map pointer event with translated geographic coordinates. + """ + + coordinates: MapLatitudeLongitude + """Coordinates of the point targeted by this pointer event.""" + + +@dataclass +class MapEvent(ft.Event["Map"]): + """ + Map event emitted for camera/interaction updates from various sources. + """ + + source: MapEventSource + """Who/what issued the event.""" + + event_type: MapEventType + """ + Concrete subtype of this map event. + """ + + camera: Camera + """The camera state after the event.""" + + old_camera: Optional[Camera] = None + """ + Camera state before the event. + + Set only for :attr:`flet_map.MapEventType.MOVE`, \ + :attr:`flet_map.MapEventType.FLING_ANIMATION`, + :attr:`flet_map.MapEventType.DOUBLE_TAP_ZOOM`, \ + :attr:`flet_map.MapEventType.SCROLL_WHEEL_ZOOM`, + :attr:`flet_map.MapEventType.ROTATE`, and \ + :attr:`flet_map.MapEventType.NON_ROTATED_SIZE_CHANGE`. + """ + + coordinates: Optional[MapLatitudeLongitude] = None + """ + Tap/press coordinates associated with this event. + + Set only for :attr:`flet_map.MapEventType.TAP`, \ + :attr:`flet_map.MapEventType.SECONDARY_TAP`, and + :attr:`flet_map.MapEventType.LONG_PRESS`. + """ + + id: Optional[str] = None + """ + Optional custom identifier associated with this event. + + Set only for :attr:`flet_map.MapEventType.MOVE` and \ + :attr:`flet_map.MapEventType.ROTATE`. + """ + + +@ft.value +class TileDisplay: + """ + Defines how the tile should get displayed on the map. + + This is an abstract class and shouldn't be used directly. + + See usable derivatives: + - `InstantaneousTileDisplay` + - `FadeInTileDisplay` + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + + +@ft.value +class InstantaneousTileDisplay(TileDisplay): + """A `TileDisplay` that should get instantaneously displayed.""" + + opacity: ft.Number = 1.0 + """ + The optional opacity of the tile. + + Raises: + ValueError: If its value is not between `0.0` and `1.0` inclusive. + """ + + def __post_init__(self): + if not (0.0 <= self.opacity <= 1.0): + raise ValueError( + f"opacity must be between 0.0 and 1.0 inclusive, got {self.opacity}" + ) + self._type = "instantaneous" + + +@ft.value +class FadeInTileDisplay(TileDisplay): + """A `TileDisplay` that should get faded in.""" + + duration: ft.DurationValue = field( + default_factory=lambda: ft.Duration(milliseconds=100) + ) + """ + The duration of the fade in animation. + """ + + start_opacity: ft.Number = 0.0 + """ + Opacity start value when a tile is faded in. + + Raises: + ValueError: If its value is not between `0.0` and `1.0` inclusive. + """ + + reload_start_opacity: ft.Number = 0.0 + """ + Opacity start value when a tile is reloaded. + + Raises: + ValueError: If its value is not between `0.0` and `1.0` inclusive. + """ + + def __post_init__(self): + if not (0.0 <= self.start_opacity <= 1.0): + raise ValueError( + "start_opacity must be between 0.0 and 1.0 inclusive, " + f"got {self.start_opacity}" + ) + if not (0.0 <= self.reload_start_opacity <= 1.0): + raise ValueError( + "reload_start_opacity must be between 0.0 and 1.0 inclusive, " + f"got {self.reload_start_opacity}" + ) + self._type = "fadein" + + +@ft.value +class KeyboardConfiguration: + """ + Options to configure how keyboard keys may be used to control the map. + When a key is pushed down, an animation starts, consisting of a curved + portion which takes the animation to its maximum velocity, an indefinitely + long animation at maximum velocity, then ended on the key up with another + curved portion. + + If a key is pressed and released quickly, it might trigger a short animation + called a 'leap'. The leap consists of a part of the curved portion, and also + scales the velocity of the concerned gesture. + + Info: + See :class:`~flet_map.CursorKeyboardRotationConfiguration` for options + to control the keyboard and + mouse cursor being used together to rotate the map. + """ + + autofocus: bool = True + """ + Whether to request focus as soon as the map control appears + (and to enable keyboard controls). + """ + + animation_curve_duration: ft.DurationValue = field( + default_factory=lambda: ft.Duration(milliseconds=450) + ) + """ + Duration of the curved (:attr:`flet.AnimationCurve.EASE_IN`) + portion of the animation occurring + after a key down event (and after a key up event if + :attr:`animation_curve_reverse_duration` is `None`) + """ + + animation_curve_reverse_duration: Optional[ft.DurationValue] = field( + default_factory=lambda: ft.Duration(milliseconds=600) + ) + """ + Duration of the curved (reverse + :attr:`flet.AnimationCurve.EASE_IN`) + portion of the animation occurring after a key up event. + + Set to `None` to use :attr:`animation_curve_duration`. + """ + + animation_curve_curve: AnimationCurve = AnimationCurve.EASE_IN_OUT + """ + Curve of the curved portion of the animation occurring after + key down and key up events. + """ + + enable_arrow_keys_panning: bool = True + """ + Whether to allow arrow keys to pan the map (in their respective directions). + """ + + enable_qe_rotating: bool = True + """ + Whether to allow the `Q` & `E` keys (*) to rotate the map (`Q` rotates + anticlockwise, `E` rotates clockwise). + + QE are only the physical and logical keys on QWERTY keyboards. + On non- QWERTY keyboards, such as AZERTY, + the keys in the same position as on the QWERTY keyboard is used (ie. AE on AZERTY). + """ + + enable_rf_zooming: bool = True + """ + Whether to allow the `R` & `F` keys to zoom the map (`R` zooms IN + (increases zoom level), `F` zooms OUT (decreases zoom level)). + + RF are only the physical and logical keys on QWERTY keyboards. + On non- QWERTY keyboards, such as AZERTY, + the keys in the same position as on the QWERTY keyboard is used (ie. RF on AZERTY). + """ + + enable_wasd_panning: bool = True + """ + Whether to allow the `W`, `A`, `S`, `D` keys (*) to pan the map + (in the directions UP, LEFT, DOWN, RIGHT respectively). + + WASD are only the physical and logical keys on QWERTY keyboards. + On non- QWERTY keyboards, such as AZERTY, + the keys in the same position as on the QWERTY keyboard is + used (ie. ZQSD on AZERTY). + + If enabled, it is recommended to enable `enable_arrow_keys_panning` + to provide panning functionality easily for left handed users. + """ + + leap_max_of_curve_component: ft.Number = 0.6 + """ + The percentage (0.0 - 1.0) of the curve animation component that is driven + to (from 0), then in reverse from (to 0). + + Reducing means the leap occurs quicker (assuming a consistent curve + animation duration). Also see `*_leap_velocity_multiplier` properties to + change the distance of the leap assuming a consistent leap duration. + + For example, if set to 1, then the leap will take + `animation_curve_duration + animation_curve_reverse_duration` + to complete. + + Must be greater than 0 and less than or equal to 1. + To disable leaping, or change the maximum length of the key press + that will trigger a leap, see :attr:`perform_leap_trigger_duration`. + """ + + max_rotate_velocity: ft.Number = 3 + """ + The maximum angular difference to apply per frame to the camera's rotation + during a rotation animation. + + Measured in degrees. Negative numbers will flip the standard rotation keys. + """ + + max_zoom_velocity: ft.Number = 0.03 + """ + The maximum zoom level difference to apply per frame to the camera's zoom + level during a zoom animation. + + Measured in zoom levels. Negative numbers will flip the standard zoom keys. + """ + + pan_leap_velocity_multiplier: ft.Number = 5 + """ + The amount to scale the panning offset velocity by during a leap animation. + + The larger the number, the larger the movement during a leap. + To change the duration of a leap, see :attr:`leap_max_of_curve_component`. + """ + + rotate_leap_velocity_multiplier: ft.Number = 3 + """ + The amount to scale the rotation velocity by during a leap animation + + The larger the number, the larger the rotation difference during a leap. + To change the duration of a leap, see :attr:`leap_max_of_curve_component`. + + This may cause the pan velocity to exceed :attr:`max_rotate_velocity`. + """ + + zoom_leap_velocity_multiplier: ft.Number = 3 + """ + The amount to scale the zooming velocity by during a leap animation. + + The larger the number, the larger the zoom difference during a leap. To + change the duration of a leap, see :attr:`leap_max_of_curve_component`. + + This may cause the pan velocity to exceed :attr:`max_zoom_velocity`. + """ + + perform_leap_trigger_duration: Optional[ft.DurationValue] = field( + default_factory=lambda: ft.Duration(milliseconds=100) + ) + """ + Maximum duration between the key down and key up events of an animation + which will trigger a 'leap'. + + To customize the leap itself, see the :attr:`leap_max_of_curve_component` & + `*leap_velocity_multiplier` (:attr:`zoom_leap_velocity_multiplier`, + :attr:`pan_leap_velocity_multiplier` and + :attr:`rotate_leap_velocity_multiplier`) properties. + + Set to `None` to disable leaping. + """ + + @classmethod + def disabled(cls) -> "KeyboardConfiguration": + """ + Disable keyboard control of the map. + + Info: + :class:`~flet_map.CursorKeyboardRotationConfiguration` may still be active, + and is not disabled if this is disabled. + """ + return KeyboardConfiguration( + enable_arrow_keys_panning=False, + perform_leap_trigger_duration=None, + autofocus=False, + ) + + +class CursorRotationBehaviour(Enum): + """ + The behaviour of the cursor/keyboard rotation function in terms of the angle + that the map is rotated to. + + Does not disable cursor/keyboard rotation, or adjust its triggers: see + `CursorKeyboardRotationConfiguration.is_key_trigger`. + """ + + OFFSET = "offset" + """ + Offset the current rotation of the map to the angle at which the + user drags their cursor. + """ + + SET_NORTH = "setNorth" + """ + Set the North of the map to the angle at which the user drags their cursor. + """ + + +@ft.value +class CursorKeyboardRotationConfiguration: + """ + Options to configure cursor/keyboard rotation. + + Cursor/keyboard rotation is designed for desktop platforms, + and allows the cursor to be used to set the rotation of the map + whilst a keyboard key is held down (as triggered by `is_key_trigger`). + """ + + set_north_on_click: bool = True + """ + Whether to set the North of the map to the clicked angle, + when the user clicks their mouse without dragging + (a `on_pointer_down` event followed by `on_pointer_up` + without a change in rotation). + """ + + behavior: CursorRotationBehaviour = CursorRotationBehaviour.OFFSET + """ + The behaviour of the cursor/keyboard rotation function in terms of the + angle that the map is rotated to. + + Does not disable cursor/keyboard rotation, or + adjust its triggers: see `is_key_trigger`. + """ + + # TODO + trigger_keys: list = field( + default_factory=lambda: [ + # ft.LogicalKeyboardKey.CONTROL, + # ft.LogicalKeyboardKey.CONTROL_LEFT, + # ft.LogicalKeyboardKey.CONTROL_RIGHT, + ] + ) + """ + List of keys that will trigger cursor/keyboard rotation, when pressed. + """ + + @classmethod + def disabled(cls) -> "CursorKeyboardRotationConfiguration": + """A disabled `CursorKeyboardRotationConfiguration`.""" + return CursorKeyboardRotationConfiguration(trigger_keys=[]) + + +@ft.value +class WMSTileLayerConfiguration: + """Configuration for a WMS :class:`~flet_map.TileLayer`.""" + + base_url: str + """WMS service's URL, for example `http://ows.mundialis.de/services/service?`""" + + format: str = "image/png" + """WMS image format (use 'image/png' for layers with transparency).""" + + version: str = "1.1.1" + """Version of the WMS service to use.""" + + uppercase_bool_value: bool = False + """Encode boolean values as uppercase in request.""" + + transparent: bool = True + """Whether to make tiles transparent.""" + + layers: list[str] = field(default_factory=list) + """List of WMS layers to show.""" + + styles: list[str] = field(default_factory=list) + """List of WMS styles.""" + + additional_parameters: dict[str, str] = field(default_factory=dict) + """Additional request parameters.""" diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/.gitignore b/sdk/python/packages/flet-map/src/flutter/flet_map/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/.metadata b/sdk/python/packages/flet-map/src/flutter/flet_map/.metadata new file mode 100644 index 0000000000..07d8623a38 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2e9cb0aa71a386a91f73f7088d115c0d96654829" + channel: "stable" + +project_type: package diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/analysis_options.yaml b/sdk/python/packages/flet-map/src/flutter/flet_map/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/flet_map.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/flet_map.dart new file mode 100644 index 0000000000..e569f53f80 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/flet_map.dart @@ -0,0 +1,3 @@ +library flet_map; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/circle_layer.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/circle_layer.dart new file mode 100644 index 0000000000..86c4c8e778 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/circle_layer.dart @@ -0,0 +1,34 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_map/flutter_map.dart'; + +import 'utils/map.dart'; + +class CircleLayerControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const CircleLayerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("CircleLayerControl build: ${control.id}"); + + var circles = control + .children("circles") + .where((c) => c.type == "CircleMarker") + .map((circle) { + circle.notifyParent = true; + return CircleMarker( + point: circle.getLatLng("coordinates")!, + color: circle.getColor("color", context, const Color(0xFF00FF00))!, + borderColor: circle.getColor( + "border_color", context, const Color(0xFFFFFF00))!, + borderStrokeWidth: circle.getDouble("border_stroke_width", 0.0)!, + useRadiusInMeter: circle.getBool("use_radius_in_meter", false)!, + radius: circle.getDouble("radius", 10)!); + }).toList(); + + return BaseControl(control: control, child: CircleLayer(circles: circles)); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/extension.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/extension.dart new file mode 100644 index 0000000000..d97d9f55b6 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/extension.dart @@ -0,0 +1,40 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; + +import 'circle_layer.dart'; +import 'map.dart'; +import 'marker_layer.dart'; +import 'overlay_image_layer.dart'; +import 'polygon_layer.dart'; +import 'polyline_layer.dart'; +import 'rich_attribution.dart'; +import 'simple_attribution.dart'; +import 'tile_layer.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "Map": + return MapControl(key: key, control: control); + case "RichAttribution": + return RichAttributionControl(key: key, control: control); + case "SimpleAttribution": + return SimpleAttributionControl(key: key, control: control); + case "TileLayer": + return TileLayerControl(key: key, control: control); + case "MarkerLayer": + return MarkerLayerControl(key: key, control: control); + case "OverlayImageLayer": + return OverlayImageLayerControl(key: key, control: control); + case "CircleLayer": + return CircleLayerControl(key: key, control: control); + case "PolygonLayer": + return PolygonLayerControl(key: key, control: control); + case "PolylineLayer": + return PolylineLayerControl(key: key, control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/map.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/map.dart new file mode 100644 index 0000000000..56e4981d74 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/map.dart @@ -0,0 +1,131 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:flutter_map_animations/flutter_map_animations.dart'; + +import 'utils/map.dart'; + +class MapControl extends StatefulWidget { + final Control control; + + const MapControl({super.key, required this.control}); + + @override + State createState() => _MapControlState(); +} + +class _MapControlState extends State + with FletStoreMixin, TickerProviderStateMixin { + late final _animatedMapController = AnimatedMapController(vsync: this); + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Map.$name($args)"); + args ??= {}; + var defaultAnimationCurve = + widget.control.getCurve("animation_curve", Curves.fastOutSlowIn); + var defaultAnimationDuration = widget.control + .getDuration("animation_duration", const Duration(milliseconds: 500))!; + var animationCurve = parseCurve(args["curve"], defaultAnimationCurve); + var animationDuration = + parseDuration(args["duration"], defaultAnimationDuration); + var cancelPreviousAnimations = parseBool(args["cancel_ongoing_animations"]); + var zoom = parseDouble(args["zoom"]); + switch (name) { + case "rotate_from": + var degree = parseDouble(args["degree"]); + if (degree != null) { + await _animatedMapController.animatedRotateFrom( + degree, + curve: animationCurve, + duration: animationDuration, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + } + break; + case "reset_rotation": + await _animatedMapController.animatedRotateReset( + curve: animationCurve, + duration: animationDuration, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + break; + case "zoom_in": + await _animatedMapController.animatedZoomIn( + curve: animationCurve, + duration: animationDuration, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + break; + case "zoom_out": + await _animatedMapController.animatedZoomOut( + curve: animationCurve, + duration: animationDuration, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + break; + case "zoom_to": + if (zoom != null) { + await _animatedMapController.animatedZoomTo( + zoom, + curve: animationCurve, + duration: animationDuration, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + } + break; + case "move_to": + await _animatedMapController.animateTo( + zoom: zoom, + curve: animationCurve, + rotation: parseDouble(args["rotation"]), + duration: animationDuration, + dest: parseLatLng(args["destination"]), + offset: parseOffset(args["offset"], Offset.zero)!, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + break; + case "center_on": + var point = parseLatLng(args["point"]); + if (point != null) { + await _animatedMapController.centerOnPoint( + point, + zoom: zoom, + curve: animationCurve, + duration: animationDuration, + cancelPreviousAnimations: cancelPreviousAnimations, + ); + } + break; + case "get_camera": + return _animatedMapController.mapController.camera.toMap(); + default: + throw Exception("Unknown Map method: $name"); + } + } + + @override + void dispose() { + _animatedMapController.dispose(); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("Map build: ${widget.control.id} (${widget.control.hashCode})"); + + Widget map = FlutterMap( + mapController: _animatedMapController.mapController, + options: parseConfiguration(widget.control, context, const MapOptions())!, + children: widget.control.buildWidgets("layers"), + ); + + return LayoutControl(control: widget.control, child: map); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/marker_layer.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/marker_layer.dart new file mode 100644 index 0000000000..53563af9c9 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/marker_layer.dart @@ -0,0 +1,42 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_map_animations/flutter_map_animations.dart'; + +import 'utils/map.dart'; + +class MarkerLayerControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const MarkerLayerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("MarkerLayerControl build: ${control.id}"); + var markers = control + .children("markers") + .where((c) => c.type == "Marker") + .map((marker) { + marker.notifyParent = true; + return AnimatedMarker( + point: marker.getLatLng("coordinates")!, + rotate: marker.getBool("rotate"), + height: marker.getDouble("height", 30.0)!, + width: marker.getDouble("width", 30.0)!, + alignment: marker.getAlignment("alignment"), + builder: (BuildContext context, Animation animation) { + return marker.buildWidget("content") ?? + const ErrorControl("content must be provided and visible"); + }); + }).toList(); + + return BaseControl( + control: control, + child: AnimatedMarkerLayer( + markers: markers, + rotate: control.getBool("rotate", false)!, + alignment: control.getAlignment("alignment", Alignment.center)!, + ), + ); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/overlay_image_layer.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/overlay_image_layer.dart new file mode 100644 index 0000000000..305766ca3f --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/overlay_image_layer.dart @@ -0,0 +1,73 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; + +import 'utils/map.dart'; + +class OverlayImageLayerControl extends StatelessWidget { + final Control control; + + const OverlayImageLayerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("OverlayImageLayerControl build: ${control.id}"); + + final overlayImages = control + .children("overlay_images") + .map((overlayImage) { + overlayImage.notifyParent = true; + + final imageProvider = overlayImage.getImageProvider("src", context); + if (imageProvider == null) return null; + + final opacity = overlayImage.getDouble("opacity", 1.0)!; + final gaplessPlayback = + overlayImage.getBool("gapless_playback", false)!; + final filterQuality = overlayImage.getFilterQuality( + "filter_quality", FilterQuality.medium)!; + + switch (overlayImage.type) { + case "OverlayImage": + final bounds = overlayImage.getLatLngBounds("bounds"); + if (bounds == null) return null; + return OverlayImage( + imageProvider: imageProvider, + bounds: bounds, + opacity: opacity, + gaplessPlayback: gaplessPlayback, + filterQuality: filterQuality, + ); + case "RotatedOverlayImage": + final topLeftCorner = overlayImage.getLatLng("top_left_corner"); + final bottomLeftCorner = + overlayImage.getLatLng("bottom_left_corner"); + final bottomRightCorner = + overlayImage.getLatLng("bottom_right_corner"); + if (topLeftCorner == null || + bottomLeftCorner == null || + bottomRightCorner == null) { + return null; + } + return RotatedOverlayImage( + imageProvider: imageProvider, + topLeftCorner: topLeftCorner, + bottomLeftCorner: bottomLeftCorner, + bottomRightCorner: bottomRightCorner, + opacity: opacity, + gaplessPlayback: gaplessPlayback, + filterQuality: filterQuality, + ); + default: + return null; + } + }) + .nonNulls + .toList(); + + return BaseControl( + control: control, + child: OverlayImageLayer(overlayImages: overlayImages), + ); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/polygon_layer.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/polygon_layer.dart new file mode 100644 index 0000000000..af588fcdca --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/polygon_layer.dart @@ -0,0 +1,48 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; + +import 'utils/map.dart'; + +class PolygonLayerControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const PolygonLayerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("PolygonLayerControl build: ${control.id}"); + + var polygons = control + .children("polygons") + .where((c) => c.type == "PolygonMarker") + .map((polygon) { + polygon.notifyParent = true; + return Polygon( + borderStrokeWidth: polygon.getDouble("border_stroke_width", 0)!, + borderColor: polygon.getColor("border_color", context, Colors.green)!, + color: polygon.getColor("color", context, Colors.green)!, + disableHolesBorder: polygon.getBool("disable_holes_border", false)!, + rotateLabel: polygon.getBool("rotate_label", false)!, + label: polygon.getString("label"), + labelStyle: polygon.getTextStyle( + "label_text_style", Theme.of(context), const TextStyle())!, + strokeCap: polygon.getStrokeCap("stroke_cap", StrokeCap.round)!, + strokeJoin: polygon.getStrokeJoin("stroke_join", StrokeJoin.round)!, + points: polygon.getLatLngList("coordinates")); + }).toList(); + + return BaseControl( + control: control, + child: PolygonLayer( + polygons: polygons, + polygonCulling: control.getBool("polygon_culling", true)!, + polygonLabels: control.getBool("polygon_labels", true)!, + drawLabelsLast: control.getBool("draw_labels_last", false)!, + simplificationTolerance: + control.getDouble("simplification_tolerance", 0.3)!, + useAltRendering: control.getBool("use_alternative_rendering", false)!, + ), + ); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/polyline_layer.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/polyline_layer.dart new file mode 100644 index 0000000000..e4c8bfd32e --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/polyline_layer.dart @@ -0,0 +1,57 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; + +import 'utils/map.dart'; + +class PolylineLayerControl extends StatelessWidget with FletStoreMixin { + final Control control; + + const PolylineLayerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("PolylineLayerControl build: ${control.id}"); + + var polylines = control + .children("polylines") + .where((c) => c.type == "PolylineMarker") + .map((polyline) { + polyline.notifyParent = true; + return Polyline( + borderStrokeWidth: polyline.getDouble("border_stroke_width", 0)!, + borderColor: + polyline.getColor("border_color", context, Colors.yellow)!, + color: polyline.getColor("color", context, Colors.yellow)!, + pattern: polyline.getStrokePattern( + "stroke_pattern", const StrokePattern.solid())!, + strokeCap: polyline.getStrokeCap("stroke_cap", StrokeCap.round)!, + strokeJoin: polyline.getStrokeJoin("stroke_join", StrokeJoin.round)!, + strokeWidth: polyline.getDouble("stroke_width", 1.0)!, + useStrokeWidthInMeter: + polyline.getBool("use_stroke_width_in_meter", false)!, + colorsStop: polyline + .get("colors_stop", [])! + .map((e) => parseDouble(e)) + .nonNulls + .toList(), + gradientColors: polyline + .get("gradient_colors", [])! + .map((e) => parseColor(e, Theme.of(context))) + .nonNulls + .toList(), + points: polyline.getLatLngList("coordinates")); + }).toList(); + + return BaseControl( + control: control, + child: PolylineLayer( + polylines: polylines, + cullingMargin: control.getDouble("culling_margin", 10.0)!, + minimumHitbox: control.getDouble("min_hittable_radius", 10.0)!, + simplificationTolerance: + control.getDouble("simplification_tolerance", 0.3)!, + ), + ); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/rich_attribution.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/rich_attribution.dart new file mode 100644 index 0000000000..344a56d58a --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/rich_attribution.dart @@ -0,0 +1,64 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; + +import 'utils/attribution_alignment.dart'; + +class RichAttributionControl extends StatefulWidget { + final Control control; + + const RichAttributionControl({super.key, required this.control}); + + @override + State createState() => _RichAttributionControlState(); +} + +class _RichAttributionControlState extends State + with FletStoreMixin { + @override + Widget build(BuildContext context) { + debugPrint("RichAttributionControl build: ${widget.control.id}"); + + var attributions = widget.control + .children("attributions") + .map((Control c) { + c.notifyParent = true; + if (c.type == "TextSourceAttribution") { + return TextSourceAttribution( + c.getString("text", "Placeholder Text")!, + textStyle: c.getTextStyle("text_style", Theme.of(context)), + onTap: () => c.triggerEvent("click"), + prependCopyright: c.getBool("prepend_copyright", true)!, + ); + } else if (c.type == "ImageSourceAttribution") { + var image = c.buildWidget("image"); + if (image == null) return null; + return LogoSourceAttribution( + image, + height: c.getDouble("height", 24.0)!, + tooltip: c.getString("tooltip"), + onTap: () => c.triggerEvent("click"), + ); + } + }) + .nonNulls + .toList(); + + return BaseControl( + control: widget.control, + child: RichAttributionWidget( + attributions: attributions, + permanentHeight: widget.control.getDouble("permanent_height", 24.0)!, + popupBackgroundColor: widget.control.getColor( + "popup_bgcolor", context, Theme.of(context).colorScheme.surface), + showFlutterMapAttribution: + widget.control.getBool("show_flutter_map_attribution", true)!, + alignment: widget.control.getAttributionAlignment( + "alignment", AttributionAlignment.bottomRight)!, + popupBorderRadius: + widget.control.getBorderRadius("popup_border_radius"), + popupInitialDisplayDuration: widget.control + .getDuration("popup_initial_display_duration", Duration.zero)!), + ); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/simple_attribution.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/simple_attribution.dart new file mode 100644 index 0000000000..15cf31f7f7 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/simple_attribution.dart @@ -0,0 +1,33 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_map/flutter_map.dart'; + +class SimpleAttributionControl extends StatelessWidget { + final Control control; + + const SimpleAttributionControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("SimpleAttributionControl build: ${control.id}"); + final text = control.getString("text"); + + if (text == null) { + return const ErrorControl("SimpleAttribution.text must be provided"); + } + + return BaseControl( + control: control, + child: SimpleAttributionWidget( + source: Text( + text, + style: control.getTextStyle("text_style", Theme.of(context)), + ), + onTap: () => control.triggerEvent("click"), + backgroundColor: control.getColor( + "bgcolor", context, Theme.of(context).colorScheme.surface)!, + alignment: control.getAlignment("alignment", Alignment.bottomRight)!, + ), + ); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/tile_layer.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/tile_layer.dart new file mode 100644 index 0000000000..dac12189a3 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/tile_layer.dart @@ -0,0 +1,68 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_map/flutter_map.dart'; + +import './utils/map.dart'; + +class TileLayerControl extends StatelessWidget { + final Control control; + + const TileLayerControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("TileLayerControl build: ${control.id}"); + + var errorImageSrc = control.getString("errorImageSrc"); + ImageProvider? errorImage; + + if (errorImageSrc != null) { + var assetSrc = control.backend.getAssetSource(errorImageSrc); + if (assetSrc.isFile) { + // from File + errorImage = AssetImage(assetSrc.path); + } else { + // URL + errorImage = NetworkImage(assetSrc.path); + } + } + Widget tileLayer = TileLayer( + urlTemplate: control.getString("url_template"), + fallbackUrl: control.getString("fallback_url"), + subdomains: + control.get("subdomains")?.map((e) => e.toString()).toList() ?? + const ['a', 'b', 'c'], + tileProvider: NetworkTileProvider(), + tileDisplay: + control.getTileDisplay("display_mode", const TileDisplay.fadeIn())!, + tileDimension: control.getInt("tile_size", 256)!, + userAgentPackageName: + control.getString("user_agent_package_name", 'unknown')!, + minNativeZoom: control.getInt("min_native_zoom", 0)!, + maxNativeZoom: control.getInt("max_native_zoom", 19)!, + zoomReverse: control.getBool("zoom_reverse", false)!, + zoomOffset: control.getDouble("zoom_offset", 0)!, + keepBuffer: control.getInt("keep_buffer", 2)!, + panBuffer: control.getInt("pan_buffer", 1)!, + tms: control.getBool("enable_tms", false)!, + tileBounds: control.getLatLngBounds("tile_bounds"), + retinaMode: control.getBool("enable_retina_mode"), + maxZoom: control.getDouble("max_zoom", double.infinity)!, + minZoom: control.getDouble("min_zoom", 0)!, + evictErrorTileStrategy: control.getEvictErrorTileStrategy( + "evict_error_tile_strategy", EvictErrorTileStrategy.none)!, + errorImage: errorImage, + errorTileCallback: (TileImage t, Object o, StackTrace? s) { + control.triggerEvent("image_error", o.toString()); + }, + additionalOptions: control + .get("additional_options") + ?.map((k, v) => MapEntry(k.toString(), v.toString())) ?? + const {}, + wmsOptions: control.getWMSTileLayerOptions("wms_configuration"), + ); + + return BaseControl(control: control, child: tileLayer); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/utils/attribution_alignment.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/utils/attribution_alignment.dart new file mode 100644 index 0000000000..ac8b3c0bba --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/utils/attribution_alignment.dart @@ -0,0 +1,14 @@ +import 'package:flet/flet.dart'; +import 'package:flutter_map/flutter_map.dart'; + +AttributionAlignment? parseAttributionAlignment(String? value, + [AttributionAlignment? defaultValue]) { + return parseEnum(AttributionAlignment.values, value, defaultValue); +} + +extension AttributionAlignmentControlExtension on Control { + AttributionAlignment? getAttributionAlignment(String propertyName, + [AttributionAlignment? defaultValue]) { + return parseAttributionAlignment(getString(propertyName), defaultValue); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/utils/map.dart b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/utils/map.dart new file mode 100644 index 0000000000..7caaf54814 --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/lib/src/utils/map.dart @@ -0,0 +1,457 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:latlong2/latlong.dart'; + +LatLng? parseLatLng(dynamic value, [LatLng? defaultValue]) { + if (value == null) return defaultValue; + + return LatLng( + parseDouble(value['latitude'], 0)!, parseDouble(value['longitude'], 0)!); +} + +LatLngBounds? parseLatLngBounds(dynamic value, [LatLngBounds? defaultValue]) { + if (value == null || + value['corner_1'] == null || + value['corner_2'] == null || + parseLatLng(value['corner_1']) == null || + parseLatLng(value['corner_2']) == null) { + return defaultValue; + } + return LatLngBounds( + parseLatLng(value['corner_1'])!, parseLatLng(value['corner_2'])!); +} + +PatternFit? parsePatternFit(String? value, [PatternFit? defaultValue]) { + return parseEnum(PatternFit.values, value, defaultValue); +} + +StrokePattern? parseStrokePattern(dynamic value, + [StrokePattern? defaultValue]) { + if (value == null) return defaultValue; + final type = value['_type']; + if (type == 'dotted') { + return StrokePattern.dotted( + spacingFactor: parseDouble(value['spacing_factor'], 1.5)!, + patternFit: parsePatternFit(value['pattern_fit'], PatternFit.scaleUp)!, + ); + } else if (type == 'solid') { + return const StrokePattern.solid(); + } else if (type == 'dashed') { + var segments = value['segments'] as List; + + return StrokePattern.dashed( + patternFit: parsePatternFit(value['pattern_fit'], PatternFit.scaleUp)!, + segments: segments.map((e) => parseDouble(e)).nonNulls.toList(), + ); + } + + return defaultValue; +} + +TileDisplay? parseTileDisplay(dynamic value, [TileDisplay? defaultValue]) { + if (value == null) return defaultValue; + final type = value['_type']; + if (type == 'instantaneous') { + return TileDisplay.instantaneous( + opacity: parseDouble(value['opacity'], 1.0)!, + ); + } else if (type == 'fadein') { + return TileDisplay.fadeIn( + startOpacity: parseDouble(value['start_opacity'], 0.0)!, + reloadStartOpacity: parseDouble(value['reload_start_opacity'], 0.0)!, + duration: + parseDuration(value['duration'], const Duration(milliseconds: 100))!, + ); + } + return defaultValue; +} + +InteractionOptions? parseInteractionOptions(dynamic value, + [InteractionOptions? defaultValue]) { + if (value == null) return defaultValue; + return InteractionOptions( + enableMultiFingerGestureRace: + parseBool(value["enable_multi_finger_gesture_race"], false)!, + pinchMoveThreshold: parseDouble(value["pinch_move_threshold"], 40.0)!, + scrollWheelVelocity: parseDouble(value["scroll_wheel_velocity"], 0.005)!, + pinchZoomThreshold: parseDouble(value["pinch_zoom_threshold"], 0.5)!, + rotationThreshold: parseDouble(value["rotation_threshold"], 20.0)!, + flags: parseInt(value["flags"], InteractiveFlag.all)!, + rotationWinGestures: + parseInt(value["rotation_win_gestures"], MultiFingerGesture.rotate)!, + pinchMoveWinGestures: parseInt(value["pinch_move_win_gestures"], + MultiFingerGesture.pinchZoom | MultiFingerGesture.pinchMove)!, + pinchZoomWinGestures: parseInt(value["pinch_zoom_win_gestures"], + MultiFingerGesture.pinchZoom | MultiFingerGesture.pinchMove)!, + keyboardOptions: parseKeyboardOptions( + value["keyboard_configuration"], const KeyboardOptions())!, + cursorKeyboardRotationOptions: parseCursorKeyboardRotationOptions( + value["cursor_keyboard_rotation_configuration"], + const CursorKeyboardRotationOptions())!, + ); +} + +CameraFit? parseCameraFit(dynamic value, [CameraFit? defaultValue]) { + if (value == null) return defaultValue; + + final bounds = parseLatLngBounds(value["bounds"]); + final coordinates = (value["coordinates"] as List?) + ?.map((c) => parseLatLng(c)) + .nonNulls + .toList(); + if (bounds == null && coordinates == null) return defaultValue; + + final forceIntegerZoomLevel = + parseBool(value["force_integer_zoom_level"], false)!; + final maxZoom = parseDouble(value["max_zoom"]); + final minZoom = parseDouble(value["min_zoom"], 0)!; + final padding = parsePadding(value["padding"], EdgeInsets.zero)!; + if (bounds != null) { + return CameraFit.insideBounds( + bounds: bounds, + forceIntegerZoomLevel: forceIntegerZoomLevel, + maxZoom: maxZoom, + minZoom: minZoom, + padding: padding, + ); + } else { + return CameraFit.coordinates( + coordinates: coordinates!, + forceIntegerZoomLevel: forceIntegerZoomLevel, + maxZoom: maxZoom, + minZoom: minZoom, + padding: padding, + ); + } +} + +KeyboardOptions? parseKeyboardOptions(dynamic value, + [KeyboardOptions? defaultValue]) { + if (value == null) return defaultValue; + return KeyboardOptions( + autofocus: parseBool(value["autofocus"], true)!, + animationCurveDuration: parseDuration(value["animation_curve_duration"], + const Duration(milliseconds: 450))!, + animationCurveCurve: + parseCurve(value["animation_curve_curve"], Curves.easeInOut)!, + enableArrowKeysPanning: + parseBool(value["enable_arrow_keys_panning"], true)!, + enableQERotating: parseBool(value["enable_qe_rotating"], true)!, + enableRFZooming: parseBool(value["enable_rf_zooming"], true)!, + enableWASDPanning: parseBool(value["enable_wasd_panning"], true)!, + leapMaxOfCurveComponent: + parseDouble(value["leap_max_of_curve_component"], 0.6)!, + // maxPanVelocity: , + maxRotateVelocity: parseDouble(value["max_rotate_velocity"], 3)!, + maxZoomVelocity: parseDouble(value["max_zoom_velocity"], 0.03)!, + panLeapVelocityMultiplier: + parseDouble(value["pan_leap_velocity_multiplier"], 5)!, + rotateLeapVelocityMultiplier: + parseDouble(value["rotate_leap_velocity_multiplier"], 3)!, + zoomLeapVelocityMultiplier: + parseDouble(value["zoom_leap_velocity_multiplier"], 3)!, + performLeapTriggerDuration: parseDuration( + value["perform_leap_trigger_duration"], + const Duration(milliseconds: 100))!, + animationCurveReverseDuration: parseDuration( + value["animation_curve_reverse_duration"], + const Duration(milliseconds: 600))!); +} + +CursorRotationBehaviour? parseCursorRotationBehaviour(String? value, + [CursorRotationBehaviour? defaultValue]) { + return parseEnum(CursorRotationBehaviour.values, value, defaultValue); +} + +CursorKeyboardRotationOptions? parseCursorKeyboardRotationOptions(dynamic value, + [CursorKeyboardRotationOptions? defaultValue]) { + if (value == null) return defaultValue; + return CursorKeyboardRotationOptions( + setNorthOnClick: parseBool(value["set_north_on_click"], true)!, + behaviour: parseCursorRotationBehaviour( + value["behaviour"], CursorRotationBehaviour.offset)!, + isKeyTrigger: value["trigger_keys"] != null + ? (LogicalKeyboardKey key) { + return (value["trigger_keys"] as List).contains(key); + } + : null); +} + +// Crs? parseCrs(dynamic value, [Crs? defaultValue]) { +// if (value == null) return defaultValue; +// return Crs(); +// } + +// MapCamera? parseMapCamera(dynamic value, [MapCamera? defaultValue]) { +// if (value == null) return defaultValue; +// return MapCamera( +// crs: Crs(), +// center: parseLatLng(value["center"])!, +// zoom: parseDouble(value["zoom"], 0)!, +// minZoom: parseDouble(value["min_zoom"], 0)!, +// maxZoom: parseDouble(value["max_zoom"], 0)!, +// rotation: parseDouble(value["rotation"], 0)!, +// bounds: parseLatLngBounds(value["bounds"]), +// ); +// } + +EvictErrorTileStrategy? parseEvictErrorTileStrategy(String? value, + [EvictErrorTileStrategy? defaultValue]) { + return parseEnum(EvictErrorTileStrategy.values, value, defaultValue); +} + +extension TapPositionExtension on TapPosition { + Map toMap() => { + "gx": global.dx, + "gy": global.dy, + "lx": relative?.dx, + "ly": relative?.dy, + }; +} + +extension LatLngExtension on LatLng { + Map toMap() => { + "latitude": latitude, + "longitude": longitude, + }; +} + +extension LatLngBoundsExtension on LatLngBounds { + // TODO + // Map toMap() => { + // + // }; +} + +extension MapCameraExtension on MapCamera { + Map toMap() => { + "center": center.toMap(), + "zoom": zoom, + "min_zoom": minZoom, + "max_zoom": maxZoom, + "rotation": rotation, + }; +} + +WMSTileLayerOptions? parseWMSTileLayerOptions(dynamic value, + [WMSTileLayerOptions? defaultValue]) { + if (value == null) return defaultValue; + return WMSTileLayerOptions( + baseUrl: value["base_url"], + format: value["format"] ?? 'image/png', + version: value["version"] ?? '1.1.1', + uppercaseBoolValue: parseBool(value["uppercase_bool_value"], false)!, + transparent: parseBool(value["transparent"], true)!, + layers: (value["layers"] as List?)?.map((e) => e.toString()).toList() ?? + const [], + styles: (value["styles"] as List?)?.map((e) => e.toString()).toList() ?? + const [], + otherParameters: value["additional_parameters"] != null + ? Map.from(value["additional_parameters"]) + : const {}, + ); +} + +MapOptions? parseConfiguration(Control control, BuildContext context, + [MapOptions? defaultValue]) { + return MapOptions( + initialCenter: + control.getLatLng("initial_center", const LatLng(50.5, 30.51))!, + interactionOptions: control.getInteractionOptions( + "interaction_configuration", const InteractionOptions())!, + backgroundColor: control.getColor("bgcolor", context, Colors.grey[300])!, + initialRotation: control.getDouble("initial_rotation", 0.0)!, + initialZoom: control.getDouble("initial_zoom", 13.0)!, + keepAlive: control.getBool("keep_alive", false)!, + maxZoom: control.getDouble("max_zoom"), + minZoom: control.getDouble("min_zoom"), + initialCameraFit: control.getCameraFit("initial_camera_fit"), + onPointerHover: control.hasEventHandler("hover") + ? (PointerHoverEvent e, LatLng latlng) { + control.triggerEvent("hover", { + "coordinates": latlng.toMap(), + ...e.toMap(), + }); + } + : null, + onTap: control.hasEventHandler("tap") + ? (TapPosition pos, LatLng latlng) { + control.triggerEvent("tap", { + "coordinates": latlng.toMap(), + ...pos.toMap(), + }); + } + : null, + onLongPress: control.hasEventHandler("long_press") + ? (TapPosition pos, LatLng latlng) { + control.triggerEvent("long_press", { + "coordinates": latlng.toMap(), + ...pos.toMap(), + }); + } + : null, + onPositionChanged: control.hasEventHandler("position_change") + ? (MapCamera camera, bool hasGesture) { + control.triggerEvent("position_change", { + "coordinates": camera.center.toMap(), + "has_gesture": hasGesture, + "camera": camera.toMap() + }); + } + : null, + onPointerDown: control.hasEventHandler("pointer_down") + ? (PointerDownEvent e, LatLng latlng) { + control.triggerEvent("pointer_down", { + "coordinates": latlng.toMap(), + ...e.toMap(), + }); + } + : null, + onPointerCancel: control.hasEventHandler("pointer_cancel") + ? (PointerCancelEvent e, LatLng latlng) { + control.triggerEvent("pointer_cancel", { + "coordinates": latlng.toMap(), + ...e.toMap(), + }); + } + : null, + onPointerUp: control.hasEventHandler("pointer_up") + ? (PointerUpEvent e, LatLng latlng) { + control.triggerEvent( + "pointer_up", {"coordinates": latlng.toMap(), ...e.toMap()}); + } + : null, + onSecondaryTap: control.hasEventHandler("secondary_tap") + ? (TapPosition pos, LatLng latlng) { + control.triggerEvent("secondary_tap", { + "coordinates": latlng.toMap(), + ...pos.toMap(), + }); + } + : null, + onMapEvent: control.hasEventHandler("event") + ? (MapEvent e) => control.triggerEvent("event", e.toMap()) + : null, + onMapReady: control.hasEventHandler("init") + ? () => control.triggerEvent("init") + : null, + ); +} + +String getMapEventType(MapEvent event) { + const eventTypeMap = { + MapEventTap: "tap", + MapEventSecondaryTap: "secondaryTap", + MapEventLongPress: "longPress", + MapEventMove: "move", + MapEventMoveStart: "moveStart", + MapEventMoveEnd: "moveEnd", + MapEventFlingAnimation: "flingAnimation", + MapEventFlingAnimationNotStarted: "flingAnimationNotStarted", + MapEventFlingAnimationStart: "flingAnimationStart", + MapEventFlingAnimationEnd: "flingAnimationEnd", + MapEventDoubleTapZoom: "doubleTapZoom", + MapEventScrollWheelZoom: "scrollWheelZoom", + MapEventDoubleTapZoomStart: "doubleTapZoomStart", + MapEventDoubleTapZoomEnd: "doubleTapZoomEnd", + MapEventRotate: "rotate", + MapEventRotateStart: "rotateStart", + MapEventRotateEnd: "rotateEnd", + MapEventNonRotatedSizeChange: "nonRotatedSizeChange", + }; + return eventTypeMap[event.runtimeType] ?? "unknown"; +} + +MapCamera? getMapEventOldCamera(MapEvent event) => switch (event) { + MapEventWithMove(:final oldCamera) => oldCamera, + _ => null, + }; + +LatLng? getMapEventCoordinates(MapEvent event) => switch (event) { + MapEventTap(:final tapPosition) || + MapEventSecondaryTap(:final tapPosition) || + MapEventLongPress(:final tapPosition) => + tapPosition, + _ => null, + }; + +String? getMapEventId(MapEvent event) => switch (event) { + MapEventMove(:final id) || MapEventRotate(:final id) => id, + _ => null, + }; + +extension MapEventExtension on MapEvent { + Map toMap() { + return { + "source": source.name, + "event_type": getMapEventType(this), + "camera": camera.toMap(), + "old_camera": getMapEventOldCamera(this)?.toMap(), + "coordinates": getMapEventCoordinates(this)?.toMap(), + "id": getMapEventId(this), + }; + } +} + +extension MapParsersControlExtension on Control { + LatLng? getLatLng(String propertyName, [LatLng? defaultValue]) { + return parseLatLng(get(propertyName), defaultValue); + } + + LatLngBounds? getLatLngBounds(String propertyName, + [LatLngBounds? defaultValue]) { + return parseLatLngBounds(get(propertyName), defaultValue); + } + + List getLatLngList(String propertyName, + [List defaultValue = const []]) { + return get(propertyName) + ?.map((c) => parseLatLng(c)) + .nonNulls + .toList() ?? + defaultValue; + } + + StrokePattern? getStrokePattern(String propertyName, + [StrokePattern? defaultValue]) { + return parseStrokePattern(get(propertyName), defaultValue); + } + + TileDisplay? getTileDisplay(String propertyName, + [TileDisplay? defaultValue]) { + return parseTileDisplay(get(propertyName), defaultValue); + } + + InteractionOptions? getInteractionOptions(String propertyName, + [InteractionOptions? defaultValue]) { + return parseInteractionOptions(get(propertyName), defaultValue); + } + + CameraFit? getCameraFit(String propertyName, [CameraFit? defaultValue]) { + return parseCameraFit(get(propertyName), defaultValue); + } + + KeyboardOptions? getKeyboardOptions(String propertyName, + [KeyboardOptions? defaultValue]) { + return parseKeyboardOptions(get(propertyName), defaultValue); + } + + CursorKeyboardRotationOptions? getCursorKeyboardRotationOptions( + String propertyName, + [CursorKeyboardRotationOptions? defaultValue]) { + return parseCursorKeyboardRotationOptions(get(propertyName), defaultValue); + } + + EvictErrorTileStrategy? getEvictErrorTileStrategy(String propertyName, + [EvictErrorTileStrategy? defaultValue]) { + return parseEvictErrorTileStrategy(getString(propertyName), defaultValue); + } + + WMSTileLayerOptions? getWMSTileLayerOptions(String propertyName, + [WMSTileLayerOptions? defaultValue]) { + return parseWMSTileLayerOptions(get(propertyName), defaultValue); + } +} diff --git a/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml b/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml new file mode 100644 index 0000000000..16d246490d --- /dev/null +++ b/sdk/python/packages/flet-map/src/flutter/flet_map/pubspec.yaml @@ -0,0 +1,25 @@ +name: flet_map +description: Flet Map control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + flutter_map: ^8.3.0 + flutter_map_animations: 0.9.0 + latlong2: 0.9.1 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-permission-handler/CHANGELOG.md b/sdk/python/packages/flet-permission-handler/CHANGELOG.md new file mode 100644 index 0000000000..452535c259 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/CHANGELOG.md @@ -0,0 +1,41 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.80.0 + +## Added + +- Deployed online documentation: https://flet.dev/docs/permission-handler/ +- `PermissionHandler` control new methods: + - `get_status_async` + - `request_async` + - `open_app_settings_async` + +### Changed + +- Refactored `PermissionHandler` control to use `@ft.control` dataclass-style definition and switched to `Service` control type + +### Breaking Changes + +- Enum `PermissionType` renamed to `Permission` +- `PermissionHandler` method `check_permission_async` renamed to `get_status_async`, with parameters changed: + - `of` → `permission` (type: `PermissionType` → `Permission`) + - `wait_timeout` → `timeout` +- `PermissionHandler` method `request_permission_async` renamed to `request_async`, with parameters changed: + - `of` → `permission` (type: `PermissionType` → `Permission`) + - `wait_timeout` → `timeout` +- `PermissionHandler` method `open_app_settings_async` parameter `wait_timeout` renamed to `timeout` (type: `Optional[float]` → `int`) +- Removed sync methods from `PermissionHandler`: + - `check_permission` → use `get_status_async` instead + - `request_permission` → use `request_async` instead + - `open_app_settings` → use `open_app_settings_async` instead +- `PermissionHandler` must now be added to `Page.services` before being used instead of `Page.overlay`. +- `PermissionHandler` can now only be used on the following platforms: Windows, iOS, Android, and Web. A `FletUnimplementedPlatformException` will be raised if used on unsupported platforms. + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-permission-handler/LICENSE b/sdk/python/packages/flet-permission-handler/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-permission-handler/README.md b/sdk/python/packages/flet-permission-handler/README.md new file mode 100644 index 0000000000..c0149a9a75 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/README.md @@ -0,0 +1,47 @@ +# flet-permission-handler + +[![pypi](https://img.shields.io/pypi/v/flet-permission-handler.svg)](https://pypi.python.org/pypi/flet-permission-handler) +[![downloads](https://static.pepy.tech/badge/flet-permission-handler/month)](https://pepy.tech/project/flet-permission-handler) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-permission-handler) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-permission-handler.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-permission-handler.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-permission-handler/LICENSE) + +A [Flet](https://flet.dev) extension that simplifies working with device permissions. + +It is based on the [permission_handler](https://pub.dev/packages/permission_handler) Flutter package +and brings similar functionality to Flet, including: + +- Requesting permissions at runtime +- Checking the current permission status (e.g., granted, denied) +- Redirecting users to system settings to manually grant permissions + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/services/permissionhandler/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-permission-handler` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-permission-handler + ``` + +- Using `pip`: + ```bash + pip install flet-permission-handler + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/permission_handler). diff --git a/sdk/python/packages/flet-permission-handler/pyproject.toml b/sdk/python/packages/flet-permission-handler/pyproject.toml new file mode 100644 index 0000000000..0400bc0b35 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-permission-handler" +version = "0.1.0" +description = "Manage runtime permissions in Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/services/permissionhandler" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-permission-handler" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_permission_handler" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/__init__.py b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/__init__.py new file mode 100644 index 0000000000..af48b31356 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/__init__.py @@ -0,0 +1,8 @@ +from flet_permission_handler.permission_handler import PermissionHandler +from flet_permission_handler.types import Permission, PermissionStatus + +__all__ = [ + "Permission", + "PermissionHandler", + "PermissionStatus", +] diff --git a/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py new file mode 100644 index 0000000000..06f8d7a169 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/permission_handler.py @@ -0,0 +1,82 @@ +from typing import Optional + +import flet as ft +from flet_permission_handler.types import Permission, PermissionStatus + +__all__ = ["PermissionHandler"] + + +@ft.control("PermissionHandler") +class PermissionHandler(ft.Service): + """ + Manages permissions for the application. + + Danger: Platform support + Currently only supported on Android, iOS, Windows, and Web platforms. + + Raises: + FletUnsupportedPlatformException: If the platform is not supported. + """ + + def before_update(self): + super().before_update() + + # validate platform + if not ( + self.page.web + or self.page.platform + in [ + ft.PagePlatform.ANDROID, + ft.PagePlatform.IOS, + ft.PagePlatform.WINDOWS, + ] + ): + raise ft.FletUnsupportedPlatformException( + "PermissionHandler is currently only supported on Android, iOS, " + "Windows, and Web platforms." + ) + + async def get_status(self, permission: Permission) -> Optional[PermissionStatus]: + """ + Gets the current status of the given `permission`. + + Args: + permission: The `Permission` to check the status for. + + Returns: + A `PermissionStatus` if the status is known, otherwise `None`. + """ + status = await self._invoke_method( + method_name="get_status", + arguments={"permission": permission}, + ) + return PermissionStatus(status) if status is not None else None + + async def request(self, permission: Permission) -> Optional[PermissionStatus]: + """ + Request the user for access to the `permission` if access hasn't already been + granted access before. + + Args: + permission: The `Permission` to request. + + Returns: + The new `PermissionStatus` after the request, or `None` if the request + was not successful. + """ + r = await self._invoke_method( + method_name="request", + arguments={"permission": permission}, + ) + return PermissionStatus(r) if r is not None else None + + async def open_app_settings(self) -> bool: + """ + Opens the app settings page. + + Returns: + `True` if the app settings page could be opened, otherwise `False`. + """ + return await self._invoke_method( + method_name="open_app_settings", + ) diff --git a/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/types.py b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/types.py new file mode 100644 index 0000000000..db05d5e40a --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flet_permission_handler/types.py @@ -0,0 +1,425 @@ +from enum import Enum + +__all__ = [ + "Permission", + "PermissionStatus", +] + + +class PermissionStatus(Enum): + """Defines the state of a :class:`~flet_permission_handler.Permission`.""" + + GRANTED = "granted" + """ + The user granted access to the requested feature. + """ + + DENIED = "denied" + """ + The user denied access to the requested feature, permission needs to be asked first. + """ + + PERMANENTLY_DENIED = "permanentlyDenied" + """ + Permission to the requested feature is permanently denied, + the permission dialog will not be shown when requesting this permission. + The user may still change the permission status in the settings. + + Note: + - On Android: + - Android 11+ (API 30+): whether the user denied the permission + for a second time. + - Below Android 11 (API 30): whether the user denied access + to the requested feature and selected to never again show a request. + - On iOS: If the user has denied access to the requested feature. + """ + + LIMITED = "limited" + """ + The user has authorized this application for limited access. + So far this is only relevant for the Photo Library picker. + + Note: + Only supported on iOS (iOS14+) and Android (Android 14+). + """ + + PROVISIONAL = "provisional" + """ + The application is provisionally authorized to post non-interruptive + user notifications. + + Note: + Only supported on iOS (iOS 12+). + """ + + RESTRICTED = "restricted" + """ + The OS denied access to the requested feature. The user cannot change + this app's status, possibly due to active restrictions such as parental + controls being in place. + + Note: + Only supported on iOS. + """ + + +# todo: show how pyproject config for each could look like for each permission +# (what exactly is needed in manifest, plist, etc.) + + +class Permission(Enum): + """Defines the permissions which can be checked and requested.""" + + ACCESS_MEDIA_LOCATION = "accessMediaLocation" + """ + Permission for accessing the device's media library. + + Allows an application to access any geographic locations persisted in the + user's shared collection. + + Note: + Only supported on Android 10+ (API 29+) only. + """ + + ACCESS_NOTIFICATION_POLICY = "accessNotificationPolicy" + """ + Permission for accessing the device's notification policy. + + Allows the user to access the notification policy of the phone. + Example: Allows app to turn on and off do-not-disturb. + + Note: + Only supported on Android Marshmallow+ (API 23+) only. + """ + + ACTIVITY_RECOGNITION = "activityRecognition" + """ + Permission for accessing the activity recognition. + + Note: + Only supported on Android 10+ (API 29+) only. + """ + + APP_TRACKING_TRANSPARENCY = "appTrackingTransparency" + """ + Permission for accessing the device's tracking state. + Allows user to accept that your app collects data about end users and + shares it with other companies for purposes of tracking across apps and + websites. + + Note: + Only supported on iOS only. + """ + + ASSISTANT = "assistant" + """ + Info: + - Android: Nothing + - iOS: SiriKit + """ + + AUDIO = "audio" + """ + Permission for accessing the device's audio files from external storage. + + Note: + Only supported on Android 13+ (API 33+) only. + """ + + BACKGROUND_REFRESH = "backgroundRefresh" + """ + Permission for reading the current background refresh status. + + Note: + Only supported on iOS only. + """ + + BLUETOOTH = "bluetooth" + """ + Permission for accessing the device's bluetooth adapter state. + + Depending on the platform and version, the requirements are slightly different: + + Info: + - Android: always allowed. + - iOS: + - 13 and above: The authorization state of Core Bluetooth manager. + - below 13: always allowed. + """ + + BLUETOOTH_ADVERTISE = "bluetoothAdvertise" + """ + Permission for advertising Bluetooth devices + Allows the user to make this device discoverable to other Bluetooth devices. + + Note: + Only supported on Android 12+ (API 31+) only. + """ + + BLUETOOTH_CONNECT = "bluetoothConnect" + """ + Permission for connecting to Bluetooth devices. + Allows the user to connect with already paired Bluetooth devices. + + Note: + Only supported on Android 12+ (API 31+) only. + """ + + BLUETOOTH_SCAN = "bluetoothScan" + """ + Permission for scanning for Bluetooth devices. + + Note: + Only supported on Android 12+ (API 31+) only. + """ + + CALENDAR_FULL_ACCESS = "calendarFullAccess" + """ + Permission for reading from and writing to the device's calendar. + """ + + CALENDAR_WRITE_ONLY = "calendarWriteOnly" + """ + Permission for writing to the device's calendar. + + On iOS 16 and lower, this permission is identical to + :attr:`CALENDAR_FULL_ACCESS`. + """ + + CAMERA = "camera" + """ + Permission for accessing the device's camera. + + Info: + - Android: Camera + - iOS: Photos (Camera Roll and Camera) + """ + + CONTACTS = "contacts" + """ + Permission for accessing the device's contacts. + + Info: + - Android: Contacts + - iOS: AddressBook + """ + + CRITICAL_ALERTS = "criticalAlerts" + """ + Permission for sending critical alerts. + Allow for sending notifications that override the ringer. + + Note: + Only supported on iOS only. + """ + + IGNORE_BATTERY_OPTIMIZATIONS = "ignoreBatteryOptimizations" + """ + Permission for accessing ignore battery optimizations. + + Note: + Only supported on Android only. + """ + + LOCATION = "location" + """ + Permission for accessing the device's location. + + Info: + - Android: Fine and Coarse Location + - iOS: CoreLocation (Always and WhenInUse) + """ + + LOCATION_ALWAYS = "locationAlways" + """ + Info: + iOS: CoreLocation (Always) + """ + + LOCATION_WHEN_IN_USE = "locationWhenInUse" + """ + Permission for accessing the device's location when the app is + running in the foreground. + + Info: + - Android: Fine and Coarse Location + - iOS: CoreLocation - WhenInUse + """ + + MANAGE_EXTERNAL_STORAGE = "manageExternalStorage" + """ + Permission for accessing the device's external storage. + Allows an application a broad access to external storage in scoped storage. + + You should request this permission only when your app cannot + effectively make use of the more privacy-friendly APIs. + For more information: + https://developer.android.com/training/data-storage/manage-all-files + + Info: + When the privacy-friendly APIs (i.e. [Storage Access Framework](https://developer.android.com/guide/topics/providers/document-provider) + or the[MediaStore](https://developer.android.com/training/data-storage/shared/media) APIs) + is all your app needs, the [PermissionGroup.storage] are the only + permissions you need to request. + + If the usage of this permission is needed, you have to fill out + the Permission Declaration Form upon submitting your app to the + Google Play Store. + More details: + https://support.google.com/googleplay/android-developer/answer/9214102#zippy= + + Note: + Only supported on Android 11+ (API 30+) only. + """ # noqa: E501 + + MEDIA_LIBRARY = "mediaLibrary" + """ + Permission for accessing the device's media library. + + Note: + Only supported on iOS 9.3+ only + """ + + MICROPHONE = "microphone" + """ + Permission for accessing the device's microphone. + """ + + NEARBY_WIFI_DEVICES = "nearbyWifiDevices" + """ + Permission for connecting to nearby devices via Wi-Fi. + + Note: + Only supported on Android 13+ (API 33+) only. + """ + + NOTIFICATION = "notification" + """ + Permission for pushing notifications. + """ + + PHONE = "phone" + """ + Permission for accessing the device's phone state. + + Note: + Only supported on Android only. + """ + + PHOTOS = "photos" + """ + Permission for accessing (read & write) the device's photos. + + If you only want to add photos, you can use + the `PHOTOS_ADD_ONLY` permission instead (iOS only). + """ + + PHOTOS_ADD_ONLY = "photosAddOnly" + """ + Permission for adding photos to the device's photo library (iOS only). + + If you want to read them as well, use the `Permission.PHOTOS` permission instead. + + Info: + iOS: Photos (14+ read & write access level) + """ + + REMINDERS = "reminders" + """ + Permission for accessing the device's reminders. + + Note: + Only supported on iOS only. + """ + + REQUEST_INSTALL_PACKAGES = "requestInstallPackages" + """ + Permission for requesting installing packages. + + Note: + Only supported on Android Marshmallow+ (API 23+) only. + """ + + SCHEDULE_EXACT_ALARM = "scheduleExactAlarm" + """ + Permission for scheduling exact alarms. + + Note: + Only supported on Android 12+ (API 31+) only. + """ + + SENSORS = "sensors" + """ + Permission for accessing the device's sensors. + + Info: + - Android: Body Sensors + - iOS: CoreMotion + """ + + SENSORS_ALWAYS = "sensorsAlways" + """ + Permission for accessing the device's sensors in background. + + Note: + Only supported on Android 13+ (API 33+) only. + """ + + SMS = "sms" + """ + Permission for sending and reading SMS messages (Android only). + """ + + SPEECH = "speech" + """ + Permission for accessing speech recognition. + + Info: + - Android: Requests access to microphone + (identical to requesting :attr:`MICROPHONE`). + - iOS: Requests speech access (different from requesting + :attr:`MICROPHONE`). + """ + + STORAGE = "storage" + """ + Permission for accessing external storage. + + Depending on the platform and version, the requirements are slightly different: + + Info: + - Android: + - On Android 13 (API 33) and above, this permission is deprecated and + always returns `PermissionStatus.denied`. Instead use `Permission.PHOTOS`, + `Permission.VIDEO`, `Permission.AUDIO` or + `Permission.MANAGE_EXTERNAL_STORAGE`. + For more information see + [this](https://pub.dev/packages/permission_handler#faq). + + - Below Android 13 (API 33), the `READ_EXTERNAL_STORAGE` and + `WRITE_EXTERNAL_STORAGE` permissions are requested (depending on the + definitions in the AndroidManifest.xml) file. + - iOS: Access to folders like `Documents` or `Downloads`. Implicitly granted. + """ + + SYSTEM_ALERT_WINDOW = "systemAlertWindow" + """ + Permission for creating system alert window. + Allows an app to create windows shown on top of all other apps. + + Note: + Only supported on Android only. + """ + + UNKNOWN = "unknown" + """ + The unknown only used for return type, never requested. + """ + + VIDEOS = "videos" + """ + Permission for accessing the device's video files from external storage. + + Note: + Only supported on Android 13+ (API 33+) only. + """ diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/.gitignore b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/analysis_options.yaml b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/flet_permission_handler.dart b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/flet_permission_handler.dart new file mode 100644 index 0000000000..076a1f34a0 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/flet_permission_handler.dart @@ -0,0 +1,3 @@ +library flet_permission_handler; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/extension.dart b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/extension.dart new file mode 100644 index 0000000000..35ec302865 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/extension.dart @@ -0,0 +1,15 @@ +import 'package:flet/flet.dart'; + +import 'permission_handler.dart'; + +class Extension extends FletExtension { + @override + FletService? createService(Control control) { + switch (control.type) { + case "PermissionHandler": + return PermissionHandlerService(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/permission_handler.dart b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/permission_handler.dart new file mode 100644 index 0000000000..523ac12837 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/permission_handler.dart @@ -0,0 +1,46 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; +import 'package:permission_handler/permission_handler.dart'; + +import 'utils/permission_handler.dart'; + +class PermissionHandlerService extends FletService { + PermissionHandlerService({required super.control}); + + @override + void init() { + super.init(); + debugPrint("PermissionHandler(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("PermissionHandler.$name($args)"); + switch (name) { + case "get_status": + return await parsePermission(args['permission'])?.status.then((value) { + return value.name; + }); + case "request": + var permission = parsePermission(args['permission']); + if (permission != null) { + Future status = permission.request(); + return await status.then((value) async { + return value.name; + }); + } + break; + case "open_app_settings": + return await openAppSettings(); + default: + throw Exception("Unknown PermissionHandler method: $name"); + } + } + + @override + void dispose() { + debugPrint("PermissionHandler(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } +} diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/utils/permission_handler.dart b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/utils/permission_handler.dart new file mode 100644 index 0000000000..6ff8f0a7aa --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/lib/src/utils/permission_handler.dart @@ -0,0 +1,11 @@ +import "package:collection/collection.dart"; +import "package:permission_handler/permission_handler.dart"; + +Permission? parsePermission(String? value, [Permission? defaultValue]) { + if (value == null) return defaultValue; + return Permission.values.firstWhereOrNull( + (Permission p) => + p.toString().split('.').last.toLowerCase() == value.toLowerCase(), + ) ?? + defaultValue; +} diff --git a/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/pubspec.yaml b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/pubspec.yaml new file mode 100644 index 0000000000..ee7f793a14 --- /dev/null +++ b/sdk/python/packages/flet-permission-handler/src/flutter/flet_permission_handler/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_permission_handler +description: Flet Permission Handler control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + permission_handler: 12.0.1 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-rive/CHANGELOG.md b/sdk/python/packages/flet-rive/CHANGELOG.md new file mode 100644 index 0000000000..acb1314356 --- /dev/null +++ b/sdk/python/packages/flet-rive/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## 0.80.3 + +- Major update: migrated to `rive` 0.14.0. + +## 0.80.0 + +- Published documentation at https://flet.dev/docs/rive/ +- Added async-friendly examples and workspace integration for the `Rive` control. + +## 0.1.0 + +- Initial release. diff --git a/sdk/python/packages/flet-rive/LICENSE b/sdk/python/packages/flet-rive/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-rive/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-rive/README.md b/sdk/python/packages/flet-rive/README.md new file mode 100644 index 0000000000..94bc36e0c1 --- /dev/null +++ b/sdk/python/packages/flet-rive/README.md @@ -0,0 +1,42 @@ +# flet-rive + +[![pypi](https://img.shields.io/pypi/v/flet-rive.svg)](https://pypi.python.org/pypi/flet-rive) +[![downloads](https://static.pepy.tech/badge/flet-rive/month)](https://pepy.tech/project/flet-rive) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-rive) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-rive.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-rive.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-rive/LICENSE) + +A cross-platform [Flet](https://flet.dev) extension for displaying [Rive](https://rive.app/) animations. + +It is based on the [rive](https://pub.dev/packages/rive) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/rive/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-rive` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-rive + ``` + +- Using `pip`: + ```bash + pip install flet-rive + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/rive). diff --git a/sdk/python/packages/flet-rive/pyproject.toml b/sdk/python/packages/flet-rive/pyproject.toml new file mode 100644 index 0000000000..8b2f9f529b --- /dev/null +++ b/sdk/python/packages/flet-rive/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-rive" +version = "0.1.0" +description = "Display Rive animations in Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/rive" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-rive" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_rive" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-rive/src/flet_rive/__init__.py b/sdk/python/packages/flet-rive/src/flet_rive/__init__.py new file mode 100644 index 0000000000..1c676ffb41 --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flet_rive/__init__.py @@ -0,0 +1,3 @@ +from flet_rive.rive import Rive as Rive + +__all__ = ["Rive"] diff --git a/sdk/python/packages/flet-rive/src/flet_rive/rive.py b/sdk/python/packages/flet-rive/src/flet_rive/rive.py new file mode 100644 index 0000000000..e660e54be0 --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flet_rive/rive.py @@ -0,0 +1,82 @@ +from dataclasses import field +from typing import Optional + +import flet as ft + +__all__ = ["Rive"] + + +@ft.control("Rive") +class Rive(ft.LayoutControl): + """ + Displays rive animations. + """ + + src: str + """ + The source of your rive animation. + + Can either be a URL or a path to a local asset file. + """ + + placeholder: Optional[ft.Control] = None + """ + Control displayed while the Rive is loading. + """ + + artboard: Optional[str] = None + """ + The name of the artboard to use. + If not specified, the default artboard of the provided `src` is used. + """ + + alignment: Optional[ft.Alignment] = None + """ + Alignment for the animation in the Rive control. + """ + + enable_antialiasing: bool = True + """ + Whether to enable anti-aliasing when rendering. + """ + + use_artboard_size: bool = False + """ + Determines whether to use the inherent size of the artboard, + i.e. the absolute size defined by the artboard, + or size the control based on the available constraints only (sized by parent). + """ + + fit: Optional[ft.BoxFit] = None + """ + The animation's fit. + """ + + speed_multiplier: ft.Number = 1.0 + """ + A multiplier for controlling the speed of the Rive animation playback. + """ + + animations: list[str] = field(default_factory=list) + """ + List of animations to play; default animation is played if empty. + """ + + state_machines: list[str] = field(default_factory=list) + """ + List of state machines to play; none will play if empty. + """ + + headers: Optional[dict[str, str]] = None + """ + Headers for network requests. + """ + + clip_rect: Optional[ft.Rect] = None + """ + Clip the artboard to this rect. + + If not supplied it'll default to the constraint size provided by the parent + control. + Unless the Artboard has clipping disabled, then no clip will be applied. + """ diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/.gitignore b/sdk/python/packages/flet-rive/src/flutter/flet_rive/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/.metadata b/sdk/python/packages/flet-rive/src/flutter/flet_rive/.metadata new file mode 100644 index 0000000000..07d8623a38 --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2e9cb0aa71a386a91f73f7088d115c0d96654829" + channel: "stable" + +project_type: package diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/analysis_options.yaml b/sdk/python/packages/flet-rive/src/flutter/flet_rive/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/flet_rive.dart b/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/flet_rive.dart new file mode 100644 index 0000000000..6f81f1a43b --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/flet_rive.dart @@ -0,0 +1,3 @@ +library flet_rive; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/src/extension.dart b/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/src/extension.dart new file mode 100644 index 0000000000..46362ed23a --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/src/extension.dart @@ -0,0 +1,22 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:rive/rive.dart'; + +import 'rive.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "Rive": + return RiveControl(control: control); + default: + return null; + } + } + + @override + void ensureInitialized() { + RiveNative.init(); + } +} diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/src/rive.dart b/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/src/rive.dart new file mode 100644 index 0000000000..402532d208 --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/lib/src/rive.dart @@ -0,0 +1,394 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:rive/rive.dart' as rive; + +class RiveControl extends StatefulWidget { + final Control control; + + const RiveControl({super.key, required this.control}); + + @override + State createState() => _RiveControlState(); +} + +class _RiveControlState extends State { + Future? _fileFuture; + rive.File? _file; + String? _filePath; + bool _fileIsLocal = false; + Map? _fileHeaders; + _RiveMultiAnimationPainter? _painter; + List _animations = const []; + List _stateMachines = const []; + double _speedMultiplier = 1; + rive.Fit _fit = rive.RiveDefaults.fit; + Alignment _alignment = rive.RiveDefaults.alignment; + + @override + void dispose() { + _painter?.dispose(); + _file?.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("Rive build: ${widget.control.id} (${widget.control.hashCode})"); + var src = widget.control.getString("src"); + if (src == null) { + return const ErrorControl("Rive must have \"src\" specified."); + } + + var artBoard = widget.control.getString("art_board"); + var useArtBoardSize = widget.control.getBool("use_art_board_size", false)!; + var boxFit = widget.control.getBoxFit("fit"); + var fit = _toRiveFit(boxFit); + var alignment = + widget.control.getAlignment("alignment") ?? rive.RiveDefaults.alignment; + var placeholder = widget.control.buildWidget("placeholder"); + var speedMultiplier = widget.control.getDouble("speed_multiplier", 1)!; + var animations = widget.control.get>("animations", const [])!; + var stateMachines = + widget.control.get>("state_machines", const [])!; + var headers = widget.control.get("headers")?.cast(); + var clipRect = widget.control.getRect("clip_rect"); + + var assetSrc = widget.control.backend.getAssetSource(src); + _syncFileLoader(assetSrc.path, assetSrc.isFile, headers); + _syncPainter( + animations: animations, + stateMachines: stateMachines, + speedMultiplier: speedMultiplier, + fit: fit, + alignment: alignment, + ); + + final fileFuture = _fileFuture; + final painter = _painter; + if (fileFuture == null || painter == null) { + return LayoutControl( + control: widget.control, + child: placeholder ?? const SizedBox.shrink(), + ); + } + + Widget riveWidget = FutureBuilder( + future: fileFuture, + builder: (context, snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return placeholder ?? const SizedBox.shrink(); + } + if (snapshot.hasError) { + return ErrorControl( + "Rive failed to load: ${snapshot.error ?? "unknown error"}"); + } + final file = snapshot.data; + if (file == null) { + return const ErrorControl("Rive file could not be loaded."); + } + _syncLoadedFile(file); + + Widget child = rive.RiveFileWidget( + file: file, + painter: painter, + artboardName: artBoard, + ); + + if (useArtBoardSize) { + final artboard = artBoard == null + ? file.defaultArtboard() + : file.artboard(artBoard); + if (artboard != null) { + final bounds = artboard.bounds; + child = SizedBox( + width: bounds.width, + height: bounds.height, + child: child, + ); + } + } + + if (clipRect != null) { + child = ClipRect( + clipper: _RiveRectClipper(clipRect), + child: child, + ); + } + + return child; + }, + ); + + return LayoutControl(control: widget.control, child: riveWidget); + } + + void _syncLoadedFile(rive.File file) { + if (!identical(file, _file)) { + _file?.dispose(); + _file = file; + } + } + + void _syncFileLoader( + String path, + bool isFile, + Map? headers, + ) { + if (_fileFuture != null && + _filePath == path && + _fileIsLocal == isFile && + mapEquals(_fileHeaders, headers)) { + return; + } + _file?.dispose(); + _file = null; + _filePath = path; + _fileIsLocal = isFile; + _fileHeaders = headers == null ? null : Map.from(headers); + _fileFuture = _loadFile(path, isFile, headers); + } + + void _syncPainter({ + required List animations, + required List stateMachines, + required double speedMultiplier, + required rive.Fit fit, + required Alignment alignment, + }) { + if (_painter == null || + !listEquals(_animations, animations) || + !listEquals(_stateMachines, stateMachines)) { + _painter?.dispose(); + _painter = _RiveMultiAnimationPainter( + animationNames: List.from(animations), + stateMachineNames: List.from(stateMachines), + speedMultiplier: speedMultiplier, + fit: fit, + alignment: alignment, + ); + _animations = List.from(animations); + _stateMachines = List.from(stateMachines); + _speedMultiplier = speedMultiplier; + _fit = fit; + _alignment = alignment; + return; + } + + if (_speedMultiplier != speedMultiplier) { + _painter!.speedMultiplier = speedMultiplier; + _speedMultiplier = speedMultiplier; + } + if (_fit != fit) { + _painter!.fit = fit; + _fit = fit; + } + if (_alignment != alignment) { + _painter!.alignment = alignment; + _alignment = alignment; + } + } + + Future _loadFile( + String path, + bool isFile, + Map? headers, + ) async { + if (isFile) { + return rive.File.path( + path, + riveFactory: rive.Factory.rive, + ); + } + return rive.File.url( + path, + riveFactory: rive.Factory.rive, + headers: headers, + ); + } +} + +base class _RiveMultiAnimationPainter extends rive.BasicArtboardPainter + with rive.RivePointerEventMixin { + _RiveMultiAnimationPainter({ + required List animationNames, + required List stateMachineNames, + required this.speedMultiplier, + required super.fit, + required super.alignment, + }) : _animationNames = animationNames, + _stateMachineNames = stateMachineNames, + super(); + + final List _animationNames; + final List _stateMachineNames; + double speedMultiplier; + final List _animations = []; + final List _stateMachines = []; + bool _previousHit = false; + + @override + void artboardChanged(rive.Artboard artboard) { + super.artboardChanged(artboard); + _disposeControllers(); + + if (_animationNames.isEmpty && _stateMachineNames.isEmpty) { + final machine = artboard.defaultStateMachine(); + if (machine != null) { + _stateMachines.add(machine); + machine.addAdvanceRequestListener(_onAdvanceRequested); + } else if (artboard.animationCount() > 0) { + _animations.add(artboard.animationAt(0)); + } + } else { + for (final name in _animationNames) { + final animation = artboard.animationNamed(name); + if (animation != null) { + _animations.add(animation); + } + } + + for (final name in _stateMachineNames) { + final machine = artboard.stateMachine(name); + if (machine != null) { + _stateMachines.add(machine); + machine.addAdvanceRequestListener(_onAdvanceRequested); + } + } + } + + notifyListeners(); + } + + void _onAdvanceRequested() { + notifyListeners(); + } + + @override + bool hitTest(Offset position) { + if (_stateMachines.isEmpty || artboard == null) { + return false; + } + final hit = _stateMachines.any((machine) { + return machine.hitTest( + localToArtboard( + position: position, + artboardBounds: artboard!.bounds, + fit: fit, + alignment: alignment, + size: size, + scaleFactor: layoutScaleFactor, + ), + ); + }); + return hit || _previousHit; + } + + @override + void pointerEvent(PointerEvent event, HitTestEntry entry) { + if (_stateMachines.isEmpty || artboard == null) { + return; + } + var hit = false; + for (final machine in _stateMachines) { + final position = localToArtboard( + position: event.localPosition, + artboardBounds: artboard!.bounds, + fit: fit, + alignment: alignment, + size: size, + scaleFactor: layoutScaleFactor, + ); + final rive.HitResult result; + if (event is PointerDownEvent) { + result = machine.pointerDown(position, pointerId: event.pointer); + } else if (event is PointerUpEvent) { + result = machine.pointerUp(position, pointerId: event.pointer); + } else if (event is PointerMoveEvent) { + result = machine.pointerMove(position, pointerId: event.pointer); + } else if (event is PointerHoverEvent) { + result = machine.pointerMove(position, pointerId: event.pointer); + } else if (event is PointerExitEvent) { + result = machine.pointerExit(position, pointerId: event.pointer); + } else { + result = rive.HitResult.none; + } + if (result != rive.HitResult.none) { + hit = true; + } + } + if (hit || _previousHit) { + scheduleRepaint(); + } + _previousHit = hit; + } + + @override + bool advance(double elapsedSeconds) { + if (_animations.isEmpty && _stateMachines.isEmpty) { + final artboard = this.artboard; + if (artboard == null) { + return false; + } + final scaled = elapsedSeconds * speedMultiplier; + return artboard.advance(scaled); + } + + var advanced = false; + final scaled = elapsedSeconds * speedMultiplier; + for (final animation in _animations) { + advanced = animation.advanceAndApply(scaled) || advanced; + } + for (final machine in _stateMachines) { + advanced = machine.advanceAndApply(scaled) || advanced; + } + return advanced; + } + + void _disposeControllers() { + for (final animation in _animations) { + animation.dispose(); + } + _animations.clear(); + for (final machine in _stateMachines) { + machine.removeAdvanceRequestListener(_onAdvanceRequested); + machine.dispose(); + } + _stateMachines.clear(); + } + + @override + void dispose() { + _disposeControllers(); + super.dispose(); + } +} + +class _RiveRectClipper extends CustomClipper { + _RiveRectClipper(this.rect); + + final Rect rect; + + @override + Rect getClip(Size size) => rect; + + @override + bool shouldReclip(covariant _RiveRectClipper oldClipper) { + return oldClipper.rect != rect; + } +} + +rive.Fit _toRiveFit(BoxFit? fit) { + return switch (fit) { + BoxFit.fill => rive.Fit.fill, + BoxFit.contain => rive.Fit.contain, + BoxFit.cover => rive.Fit.cover, + BoxFit.fitHeight => rive.Fit.fitHeight, + BoxFit.fitWidth => rive.Fit.fitWidth, + BoxFit.none => rive.Fit.none, + BoxFit.scaleDown => rive.Fit.scaleDown, + _ => rive.RiveDefaults.fit, + }; +} diff --git a/sdk/python/packages/flet-rive/src/flutter/flet_rive/pubspec.yaml b/sdk/python/packages/flet-rive/src/flutter/flet_rive/pubspec.yaml new file mode 100644 index 0000000000..a7029019ab --- /dev/null +++ b/sdk/python/packages/flet-rive/src/flutter/flet_rive/pubspec.yaml @@ -0,0 +1,23 @@ +name: flet_rive +description: Flet Rive control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + rive: ^0.14.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-secure-storage/LICENSE b/sdk/python/packages/flet-secure-storage/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-secure-storage/README.md b/sdk/python/packages/flet-secure-storage/README.md new file mode 100644 index 0000000000..e95a510c18 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/README.md @@ -0,0 +1,50 @@ +# flet-secure-storage + +[![pypi](https://img.shields.io/pypi/v/flet-secure-storage.svg)](https://pypi.python.org/pypi/flet-secure-storage) +[![downloads](https://static.pepy.tech/badge/flet-secure-storage/month)](https://pepy.tech/project/flet-secure-storage) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-secure-storage) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-secure-storage.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-secure-storage.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-secure-storage/LICENSE) + +A service for safely storing sensitive key–value data using the platform’s native secure storage mechanisms—Keychain on iOS/macOS, Windows Credential Manager, libsecret on Linux, and Keystore on Android. + +Powered by Flutter's [`flutter_secure_storage`](https://pub.dev/packages/flutter_secure_storage) package. + +You need `libsecret-1-dev` on your machine to build the project, and `libsecret-1-0` to run the application (add it as a dependency after packaging your app). If you using snapcraft to build the project use the following. + +Apart from `libsecret` you also need a keyring service, for that you need either [`gnome-keyring`](https://wiki.gnome.org/Projects/GnomeKeyring) (for Gnome users) or [`kwalletmanager`](https://wiki.archlinux.org/title/KDE_Wallet) (for KDE users) or other light provider like [`secret-service`](https://github.com/yousefvand/secret-service). + +```bash +sudo apt-get install libsecret-1-dev libsecret-1-0 +``` + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/services/securestorage/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-secure-storage` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-secure-storage + ``` + +- Using `pip`: + ```bash + pip install flet-secure-storage + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/secure_storage). diff --git a/sdk/python/packages/flet-secure-storage/pyproject.toml b/sdk/python/packages/flet-secure-storage/pyproject.toml new file mode 100644 index 0000000000..e9eb3f07f8 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "flet-secure-storage" +version = "0.1.0" +description = "Secure Storage control for Flet" +authors = [{name = "Appveyor Systems Inc.", email = "hello@flet.dev"}] +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/services/securestorage" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-secure-storage" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_secure_storage" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/__init__.py b/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/__init__.py new file mode 100644 index 0000000000..33ce1e2720 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/__init__.py @@ -0,0 +1,28 @@ +from flet_secure_storage.secure_storage import SecureStorage, SecureStorageEvent +from flet_secure_storage.types import ( + AccessControlFlag, + AndroidOptions, + AppleOptions, + IOSOptions, + KeychainAccessibility, + KeyCipherAlgorithm, + MacOsOptions, + StorageCipherAlgorithm, + WebOptions, + WindowsOptions, +) + +__all__ = [ + "AccessControlFlag", + "AndroidOptions", + "AppleOptions", + "IOSOptions", + "KeyCipherAlgorithm", + "KeychainAccessibility", + "MacOsOptions", + "SecureStorage", + "SecureStorageEvent", + "StorageCipherAlgorithm", + "WebOptions", + "WindowsOptions", +] diff --git a/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/secure_storage.py b/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/secure_storage.py new file mode 100644 index 0000000000..6c28e70716 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/secure_storage.py @@ -0,0 +1,288 @@ +from dataclasses import dataclass, field +from typing import Any, Optional + +import flet as ft +from flet.controls.base_control import control +from flet.controls.services.service import Service +from flet_secure_storage.types import ( + AndroidOptions, + IOSOptions, + MacOsOptions, + WebOptions, + WindowsOptions, +) + + +@dataclass +class SecureStorageEvent(ft.Event["SecureStorage"]): + """ + The event fired by SecureStorage when availability changes. + """ + + available: Optional[bool] + """ + The availability of secure storage. True if secure storage is available, + False if not, None if unknown. + """ + + +@control("SecureStorage") +class SecureStorage(Service): + """ + A class to manage secure storage in a Flet application across multiple platforms. + """ + + ios_options: IOSOptions = field(default_factory=lambda: IOSOptions()) + """ + iOS-specific configuration for secure storage. + """ + + android_options: AndroidOptions = field(default_factory=lambda: AndroidOptions()) + """ + Android-specific configuration for secure storage. + """ + + windows_options: WindowsOptions = field(default_factory=lambda: WindowsOptions()) + """ + Windows-specific configuration for secure storage. + """ + + macos_options: MacOsOptions = field(default_factory=lambda: MacOsOptions()) + """ + macOS-specific configuration for secure storage. + """ + + web_options: WebOptions = field(default_factory=lambda: WebOptions()) + """ + Web-specific configuration for secure storage. + """ + + on_change: Optional[ft.EventHandler["SecureStorageEvent"]] = None + """ + Fires when secure storage availability changes. + + iOS only feature. For unsupported platforms, this event will never fire. + The payload is a `SecureStorageEvent` object with the `available` field. + """ + + async def get_availability(self) -> Optional[bool]: + """ + Gets the current availability status of secure storage. + + iOS and macOS only. On macOS, available only on macOS 12+. + On older macOS versions, always returns True. + On unsupported platforms, returns None. + + Returns: + A boolean indicating storage availability, or None if unsupported. + """ + return await self._invoke_method("get_availability") + + async def set( + self, + key: str, + value: Any, + *, + web: Optional[WebOptions] = None, + ios: Optional[IOSOptions] = None, + macos: Optional[MacOsOptions] = None, + android: Optional[AndroidOptions] = None, + windows: Optional[WindowsOptions] = None, + ) -> None: + """ + Stores a value in secure storage under the given key. + + Args: + key: The key to store the value under. + value: The value to store (cannot be None). + web: Optional web-specific configuration. + ios: Optional iOS-specific configuration. + macos: Optional macOS-specific configuration. + android: Optional Android-specific configuration. + windows: Optional Windows-specific configuration. + + Raises: + ValueError: If `value` is None. + """ + if value is None: + raise ValueError("value can't be None") + return await self._invoke_method( + method_name="set", + arguments={ + "key": key, + "value": value, + "web": web, + "ios": ios, + "macos": macos, + "android": android, + "windows": windows, + }, + ) + + async def get( + self, + key: str, + *, + web: Optional[WebOptions] = None, + ios: Optional[IOSOptions] = None, + macos: Optional[MacOsOptions] = None, + android: Optional[AndroidOptions] = None, + windows: Optional[WindowsOptions] = None, + ) -> Optional[str]: + """ + Retrieves the value stored under the given key in secure storage. + + Args: + key: The key to retrieve. + web: Optional web-specific configuration. + ios: Optional iOS-specific configuration. + macos: Optional macOS-specific configuration. + android: Optional Android-specific configuration. + windows: Optional Windows-specific configuration. + + Returns: + The stored string value, or None if the key does not exist. + """ + return await self._invoke_method( + method_name="get", + arguments={ + "key": key, + "web": web, + "ios": ios, + "macos": macos, + "android": android, + "windows": windows, + }, + ) + + async def get_all( + self, + *, + web: Optional[WebOptions] = None, + ios: Optional[IOSOptions] = None, + macos: Optional[MacOsOptions] = None, + android: Optional[AndroidOptions] = None, + windows: Optional[WindowsOptions] = None, + ) -> dict[str, str]: + """ + Retrieves all key-value pairs from secure storage. + + Args: + web: Optional web-specific configuration. + ios: Optional iOS-specific configuration. + macos: Optional macOS-specific configuration. + android: Optional Android-specific configuration. + windows: Optional Windows-specific configuration. + + Returns: + A dictionary with all stored key-value pairs. + """ + return await self._invoke_method( + method_name="get_all", + arguments={ + "web": web, + "ios": ios, + "macos": macos, + "android": android, + "windows": windows, + }, + ) + + async def contains_key( + self, + key: str, + *, + web: Optional[WebOptions] = None, + ios: Optional[IOSOptions] = None, + macos: Optional[MacOsOptions] = None, + android: Optional[AndroidOptions] = None, + windows: Optional[WindowsOptions] = None, + ) -> bool: + """ + Checks whether the given key exists in secure storage. + + Args: + key: The key to check. + web: Optional web-specific configuration. + ios: Optional iOS-specific configuration. + macos: Optional macOS-specific configuration. + android: Optional Android-specific configuration. + windows: Optional Windows-specific configuration. + + Returns: + True if the key exists, False otherwise. + """ + return await self._invoke_method( + method_name="contains_key", + arguments={ + "key": key, + "web": web, + "ios": ios, + "macos": macos, + "android": android, + "windows": windows, + }, + ) + + async def remove( + self, + key: str, + *, + web: Optional[WebOptions] = None, + ios: Optional[IOSOptions] = None, + macos: Optional[MacOsOptions] = None, + android: Optional[AndroidOptions] = None, + windows: Optional[WindowsOptions] = None, + ) -> None: + """ + Removes the value stored under the given key in secure storage. + + Args: + key: The key to remove. + web: Optional web-specific configuration. + ios: Optional iOS-specific configuration. + macos: Optional macOS-specific configuration. + android: Optional Android-specific configuration. + windows: Optional Windows-specific configuration. + """ + return await self._invoke_method( + method_name="remove", + arguments={ + "key": key, + "web": web, + "ios": ios, + "macos": macos, + "android": android, + "windows": windows, + }, + ) + + async def clear( + self, + *, + web: Optional[WebOptions] = None, + ios: Optional[IOSOptions] = None, + macos: Optional[MacOsOptions] = None, + android: Optional[AndroidOptions] = None, + windows: Optional[WindowsOptions] = None, + ) -> None: + """ + Clears all key-value pairs from secure storage. + + Args: + web: Optional web-specific configuration. + ios: Optional iOS-specific configuration. + macos: Optional macOS-specific configuration. + android: Optional Android-specific configuration. + windows: Optional Windows-specific configuration. + """ + return await self._invoke_method( + method_name="clear", + arguments={ + "web": web, + "ios": ios, + "macos": macos, + "android": android, + "windows": windows, + }, + ) diff --git a/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/types.py b/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/types.py new file mode 100644 index 0000000000..b5f401eafe --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/types.py @@ -0,0 +1,455 @@ +from dataclasses import field +from datetime import datetime +from enum import Enum +from typing import Optional + +import flet as ft + + +class KeychainAccessibility(Enum): + """ + KeyChain accessibility attributes for iOS/macOS platforms. + + These attributes determine when the app can access secure values + stored in the Keychain. + """ + + PASSCODE = "passcode" + """ + The data in the keychain can only be accessed when the device is unlocked. + + Only available if a passcode is set on the device. + Items with this attribute do not migrate to a new device. + """ + + UNLOCKED = "unlocked" + """ + The data in the keychain item can be accessed only while + the device is unlocked by the user. + """ + + UNLOCKED_THIS_DEVICE = "unlocked_this_device" + """ + The data in the keychain item can be accessed only while + the device is unlocked by the user. + + Items with this attribute do not migrate to a new device. + """ + + FIRST_UNLOCK = "first_unlock" + """ + The data in the keychain item cannot be accessed after a restart until + the device has been unlocked once by the user. + + Enables access to secure values after the device is unlocked for the first + time after a reboot. + """ + + FIRST_UNLOCK_THIS_DEVICE = "first_unlock_this_device" + """ + The data in the keychain item cannot be accessed after + a restart until the device has been unlocked once by the user. + + Items with this attribute do not migrate to a new device. + + Allows access to secure values only after the device is unlocked for the first time + since installation on this device. + """ + + +class AccessControlFlag(Enum): + """ + Keychain access control flags that define security conditions for accessing items. + + These flags can be combined to create complex access control policies using + the `access_control_flags` parameter in `IOSOptions` or `MacOsOptions`. + + Rules for combining flags: + - Use `AccessControlFlag.OR` to allow access if any condition is met + - Use `AccessControlFlag.AND` to require that all specified conditions are met + - Only one logical operator (OR/AND) can be used per combination + """ + + DEVICE_PASSCODE = "devicePasscode" + """ + Constraint to access an item with a passcode. + """ + + BIOMETRY_ANY = "biometryAny" + """ + Constraint to access an item with biometrics (Touch ID/Face ID). + """ + + BIOMETRY_CURRENT_SET = "biometryCurrentSet" + """ + Constraint to access an item with the currently enrolled biometrics. + """ + + USER_PRESENCE = "userPresence" + """ + Constraint to access an item with either biometry or passcode. + """ + + WATCH = "watch" + """ + Constraint to access an item with a paired watch. + """ + + OR = "or" + """ + Combine multiple constraints with an OR operation. + """ + + AND = "and" + """ + Combine multiple constraints with an AND operation. + """ + + APPLICATION_PASSWORD = "applicationPassword" + """ + Use an application-provided password for encryption. + """ + + PRIVATE_KEY_USAGE = "privateKeyUsage" + """ + Enable private key usage for signing operations. + """ + + +class KeyCipherAlgorithm(Enum): + """ + Algorithm used to encrypt/wrap the secret key in Android KeyStore. + + Different algorithms provide different security guarantees and compatibility levels: + + - RSA algorithms wrap the AES encryption key with RSA (no biometric support) + - AES algorithm stores the key directly in Android KeyStore + (supports biometric authentication) + + See the [AndroidOptions] class for usage examples and combinations. + """ + + RSA_ECB_PKCS1_PADDING = "RSA_ECB_PKCS1Padding" + """ + Legacy RSA/ECB/PKCS1Padding for backwards compatibility. + """ + + RSA_ECB_OAEP_WITH_SHA256_AND_MGF1_PADDING = "RSA_ECB_OAEPwithSHA_256andMGF1Padding" + """ + RSA/ECB/OAEPWithSHA-256AndMGF1Padding (API 23+). + + This is the default and recommended algorithm for most use cases. + Provides strong authenticated encryption without biometrics. + """ + + AES_GCM_NO_PADDING = "AES_GCM_NoPadding" + """ + AES/GCM/NoPadding for KeyStore-based key wrapping (supports biometrics). + + Use this algorithm when you need biometric authentication support. + Requires API 23+ for basic use, API 28+ for enforced biometric authentication. + """ + + +class StorageCipherAlgorithm(Enum): + """ + Algorithm used to encrypt stored data on Android. + + Modern applications should use `AES_GCM_NO_PADDING` for better security. + The legacy `AES_CBC_PKCS7_PADDING` is provided for backwards compatibility only. + """ + + AES_CBC_PKCS7_PADDING = "AES_CBC_PKCS7Padding" + """ + Legacy AES/CBC/PKCS7Padding for backwards compatibility. + """ + + AES_GCM_NO_PADDING = "AES_GCM_NoPadding" + """ + AES/GCM/NoPadding (API 23+). + + This is the default and recommended storage cipher algorithm. + Provides authenticated encryption with associated data (AEAD). + """ + + +@ft.value +class AndroidOptions: + """ + Specific options for Android platform for secure storage. + + Provides configurable options for encryption, key wrapping, biometric enforcement, + and shared preferences naming. + """ + + reset_on_error: bool = True + """ + When an error is detected, automatically reset all data to prevent fatal errors + with unknown keys. + + Be aware that data is PERMANENTLY erased when this occurs. + """ + + migrate_on_algorithm_change: bool = True + """ + When the encryption algorithm changes, automatically migrate existing data + to the new algorithm. Preserves data across algorithm upgrades. + + If False, data may be lost when algorithm changes unless + reset_on_error is True. + """ + + enforce_biometrics: bool = False + """ + Whether to enforce biometric or PIN authentication. + + When True: + - The plugin throws an exception if no biometric/PIN is enrolled. + - The encryption key is generated with authentication required. + + When False: + - The plugin gracefully degrades if biometrics are unavailable. + - The key is generated without authentication required. + """ + + key_cipher_algorithm: KeyCipherAlgorithm = ( + KeyCipherAlgorithm.RSA_ECB_OAEP_WITH_SHA256_AND_MGF1_PADDING + ) + """ + Algorithm used to encrypt the secret key. + + Legacy RSA/ECB/PKCS1Padding is available for backwards compatibility. + """ + + storage_cipher_algorithm: StorageCipherAlgorithm = ( + StorageCipherAlgorithm.AES_GCM_NO_PADDING + ) + """ + Algorithm used to encrypt stored data. + + Legacy AES/CBC/PKCS7Padding is available for backwards compatibility. + """ + + shared_preferences_name: Optional[str] = None + """ + The name of the shared preferences database to use. + + Changing this will prevent access to already saved preferences. + """ + + preferences_key_prefix: Optional[str] = None + """ + Prefix for shared preference keys. Ensures keys are unique to your app. + + An underscore (_) is added automatically. + + Changing this prevents access to existing preferences. + """ + + biometric_prompt_title: str = "Authenticate to access" + """ + Title displayed in the biometric authentication prompt. + """ + + biometric_prompt_subtitle: str = "Use biometrics or device credentials" + """ + Subtitle displayed in the biometric authentication prompt. + """ + + +@ft.value +class AppleOptions: + """ + Specific options for Apple platforms (iOS/macOS) for secure storage. + + This class allows configuring keychain access and storage behavior. + Use `IOSOptions` for iOS-specific configuration + or `MacOsOptions` for macOS-specific configuration. + + Note: + - Most options apply to both iOS and macOS + - Some options (like `group_id` on macOS) only apply when + certain keychain flags are set + - See individual option documentation for platform-specific behavior + """ + + account_name: Optional[str] = "flet_secure_storage_service" + """ + Represents the service or application name associated with the item. + + Typically used to group related keychain items. + """ + + group_id: Optional[str] = None + """ + Specifies the app group for shared access. Allows multiple apps in the + same app group to access the item. + """ + + accessibility: Optional[KeychainAccessibility] = KeychainAccessibility.UNLOCKED + """ + Defines the accessibility level of the keychain item. + + Controls when the item is accessible (e.g., when device is unlocked + or after first unlock). + """ + + synchronizable: bool = False + """ + Indicates whether the keychain item should be synchronized with iCloud. + + - True: Enables synchronization across user's devices + - False: Item stays local to this device only + """ + + label: Optional[str] = None + """ + A user-visible label for the keychain item. + Helps identify the item in keychain management tools. + """ + + description: Optional[str] = None + """ + A description of the keychain item. + Can describe a category of items (shared) or a specific item (unique). + """ + + comment: Optional[str] = None + """ + A comment associated with the keychain item. + Often used for metadata or debugging information. + """ + + invisible: Optional[bool] = None + """ + Indicates whether the keychain item is hidden from user-visible lists. + Can apply to all items in a category (shared) or specific items (unique). + """ + + is_negative: Optional[bool] = None + """ + Indicates whether the item is a placeholder or a negative entry. + Typically unique to individual keychain items. + """ + + creation_date: Optional[datetime] = None + """ + The creation date of the keychain item. + Automatically set by the system when an item is created. + """ + + last_modified_date: Optional[datetime] = None + """ + The last modification date of the keychain item. + Automatically updated when an item is modified. + """ + + result_limit: Optional[int] = None + """ + Specifies the maximum number of results to return in a query. + For example, 1 for a single result, or `None` for all matching results. + """ + + is_persistent: Optional[bool] = None + """ + Indicates whether to return a persistent reference to the keychain item. + Used for persistent access across app sessions. + """ + + auth_ui_behavior: Optional[str] = None + """ + Controls how authentication UI is presented during secure operations. + Determines whether authentication prompts are displayed to the user. + """ + + access_control_flags: list[AccessControlFlag] = field(default_factory=list) + """ + Keychain access control flags that define security conditions for accessing items. + """ + + +@ft.value +class IOSOptions(AppleOptions): + """ + iOS-specific configuration for secure storage. + + All configurable options are inherited from `AppleOptions`. + There are currently no iOS-only options. + """ + + +@ft.value +class MacOsOptions(AppleOptions): + """ + Specific options for macOS platform. + Extends `AppleOptions` and adds the `usesDataProtectionKeychain` parameter. + """ + + uses_data_protection_keychain: bool = True + """ + Indicates whether the macOS data protection keychain is used. + """ + + +@ft.value +class WebOptions: + """ + Specific options for the Web platform for secure storage. + + Configures database, encryption, and storage behavior on web platforms. + """ + + db_name: str = "FletEncryptedStorage" + """ + The name of the database used for secure storage. + """ + + public_key: str = "FletSecureStorage" + """ + The public key used for encryption. + """ + + wrap_key: str = "" + """ + The key used to wrap the encryption key. + """ + + wrap_key_iv: str = "" + """ + The initialization vector (IV) used for the wrap key. + """ + + use_session_storage: bool = False + """ + Whether to use session storage instead of local storage. + """ + + +@ft.value +class WindowsOptions: + """ + Specific options for Windows platform for secure storage. + + Allows configuring backward compatibility when reading/writing + values from previous versions of storage. + + Note: + You need the C++ ATL libraries installed along with Visual Studio Build Tools. + Download from: https://visualstudio.microsoft.com/downloads/?q=build+tools + Make sure the C++ ATL under optional components is installed as well. + """ + + use_backward_compatibility: bool = False + """ + If True, attempts to read values written by previous versions of the storage. + When reading or writing old storage values, they will be automatically + migrated to new storage. + + Note: + - May introduce performance overhead. + - May cause errors for keys with `"`, `<`, `>`, `|`, `:`, `*`, `?`, `/`, `\\`. + or any ASCII control characters. + - May cause errors for keys containing `/../`, `\\..\\`, or similar patterns. + - May cause errors for very long keys (length depends on app's product name, + company name, and executing account). + """ diff --git a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/flet_secure_storage.dart b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/flet_secure_storage.dart new file mode 100644 index 0000000000..faabfd5681 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/flet_secure_storage.dart @@ -0,0 +1,3 @@ +library flet_secure_storage; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/extension.dart b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/extension.dart new file mode 100644 index 0000000000..46135b14f1 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/extension.dart @@ -0,0 +1,15 @@ +import 'package:flet/flet.dart'; + +import 'secure_storage.dart'; + +class Extension extends FletExtension { + @override + FletService? createService(Control control) { + switch (control.type) { + case "SecureStorage": + return SecureStorageService(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/secure_storage.dart b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/secure_storage.dart new file mode 100644 index 0000000000..ed194b68b9 --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/secure_storage.dart @@ -0,0 +1,143 @@ +import 'dart:async'; + +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +import 'utils/secure_storage.dart'; + +class SecureStorageService extends FletService { + SecureStorageService({required super.control}); + + FlutterSecureStorage? _storage; + StreamSubscription? _onSecureDataChanged; + AndroidOptions androidOptions = AndroidOptions.defaultOptions; + WindowsOptions windowsOptions = WindowsOptions.defaultOptions; + LinuxOptions linuxOptions = LinuxOptions.defaultOptions; + MacOsOptions macOsOptions = MacOsOptions.defaultOptions; + IOSOptions iosOptions = IOSOptions.defaultOptions; + WebOptions webOptions = WebOptions.defaultOptions; + + FlutterSecureStorage get storage { + return _storage ??= FlutterSecureStorage( + lOptions: linuxOptions, + aOptions: parseAndroidOptions(control.get("android_options"), androidOptions)!, + wOptions: parseWindowsOptions(control.get("windows_options"), windowsOptions)!, + mOptions: parseMacOptions(control.get("macos_options"), macOsOptions)!, + iOptions: parseIosOptions(control.get("ios_options"), iosOptions)!, + webOptions: parseWebOptions(control.get("web_options"), webOptions)!, + ); + } + + @override + void init() { + super.init(); + debugPrint("SecureStorageService(${control.id}).init: ${control.properties}"); + control.addInvokeMethodListener(_invokeMethod); + _updateListeners(); + } + + @override + void update() { + debugPrint("SecureStorageService(${control.id}).update: ${control.properties}"); + _updateListeners(); + } + + void _updateListeners() { + final listenChange = control.getBool("on_change") == true; + if (listenChange && _onSecureDataChanged == null) { + _onSecureDataChanged = storage.onCupertinoProtectedDataAvailabilityChanged?.listen( + (bool result) { + control.triggerEvent("change", {"available": result}); + }, onError: (error) { + debugPrint("SecureStorageService: error listening to connectivity: $error"); + } + ); + } else if (!listenChange && _onSecureDataChanged != null) { + _onSecureDataChanged?.cancel(); + _onSecureDataChanged = null; + } + } + + Future _invokeMethod(String name, dynamic args) async { + AndroidOptions aOptions = parseAndroidOptions(args?["android"], storage.aOptions)!; + IOSOptions iOptions = parseIosOptions(args?["ios"], storage.iOptions)!; + LinuxOptions lOptions = storage.lOptions; + WindowsOptions wOptions = parseWindowsOptions(args?["windows"], storage.wOptions)!; + WebOptions webOptions = parseWebOptions(args?["web"], storage.webOptions)!; + MacOsOptions mOptions = parseMacOptions(args?["macos"], storage.mOptions as MacOsOptions)!; + switch (name) { + case "set": + return await storage.write( + key: args["key"]!, + value: args["value"]!, + aOptions: aOptions, + iOptions: iOptions, + lOptions: lOptions, + wOptions: wOptions, + webOptions: webOptions, + mOptions: mOptions, + ); + case "get": + return await storage.read( + key: args["key"]!, + aOptions: aOptions, + iOptions: iOptions, + lOptions: lOptions, + wOptions: wOptions, + webOptions: webOptions, + mOptions: mOptions, + ); + case "get_all": + return await storage.readAll( + aOptions: aOptions, + iOptions: iOptions, + lOptions: lOptions, + wOptions: wOptions, + webOptions: webOptions, + mOptions: mOptions, + ); + case "contains_key": + return await storage.containsKey( + key: args["key"]!, + aOptions: aOptions, + iOptions: iOptions, + lOptions: lOptions, + wOptions: wOptions, + webOptions: webOptions, + mOptions: mOptions, + ); + case "remove": + return await storage.delete( + key: args["key"]!, + aOptions: aOptions, + iOptions: iOptions, + lOptions: lOptions, + wOptions: wOptions, + webOptions: webOptions, + mOptions: mOptions, + ); + case "clear": + return await storage.deleteAll( + aOptions: aOptions, + iOptions: iOptions, + lOptions: lOptions, + wOptions: wOptions, + webOptions: webOptions, + mOptions: mOptions, + ); + case "get_availability": + return await storage.isCupertinoProtectedDataAvailable(); + default: + throw Exception("Unknown SecureStorage method: $name"); + } + } + + @override + void dispose() { + debugPrint("SecureStorageService(${control.id}).dispose()"); + control.removeInvokeMethodListener(_invokeMethod); + _onSecureDataChanged?.cancel(); + super.dispose(); + } +} diff --git a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/utils/secure_storage.dart b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/utils/secure_storage.dart new file mode 100644 index 0000000000..154b81ba4b --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/utils/secure_storage.dart @@ -0,0 +1,123 @@ +import 'package:collection/collection.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +IOSOptions? parseIosOptions(dynamic value, [IOSOptions? defaultValue]) { + if (value == null) return defaultValue; + return IOSOptions( + accountName: value["account_name"], + groupId: value["group_id"], + accessibility: parseKeychainAccessibility(value["accessibility"], KeychainAccessibility.unlocked), + synchronizable: parseBool(value["synchronizable"], false)!, + label: value["label"], + description: value["description"], + comment: value["comment"], + isInvisible: parseBool(value["is_invisible"]), + isNegative: parseBool(value["is_negative"]), + creationDate: value["creation_date"], + lastModifiedDate: value["last_modified_date"], + resultLimit: parseInt(value["result_limit"]), + shouldReturnPersistentReference: parseBool(value["is_persistent"], false)!, + authenticationUIBehavior: value["auth_ui_behavior"], + accessControlFlags: parseAccessControlFlags(value["access_control_flags"], const [])!, + ); +} + +MacOsOptions? parseMacOptions(dynamic value, [MacOsOptions? defaultValue]) { + if (value == null) return defaultValue; + return MacOsOptions( + accountName: value["account_name"], + groupId: value["group_id"], + accessibility: parseKeychainAccessibility(value["accessibility"], KeychainAccessibility.unlocked), + synchronizable: parseBool(value["synchronizable"], false)!, + label: value["label"], + description: value["description"], + comment: value["comment"], + isInvisible: parseBool(value["is_invisible"]), + isNegative: parseBool(value["is_negative"]), + creationDate: value["creation_date"], + lastModifiedDate: value["last_modified_date"], + resultLimit: parseInt(value["result_limit"]), + shouldReturnPersistentReference: parseBool(value["is_persistent"]), + authenticationUIBehavior: value["auth_ui_behavior"], + accessControlFlags: parseAccessControlFlags(value["access_control_flags"], const [])!, + usesDataProtectionKeychain: parseBool(value["uses_data_protection_keychain"], true)! + ); +} + +AndroidOptions? parseAndroidOptions(dynamic value, [AndroidOptions? defaultValue]) { + if (value == null) return defaultValue; + return AndroidOptions( + resetOnError: parseBool(value['reset_on_error'], true)!, + migrateOnAlgorithmChange: parseBool(value['migrate_on_algorithm_change'], true)!, + enforceBiometrics: parseBool(value['enforce_biometrics'], false)!, + keyCipherAlgorithm: parseKeyCipherAlgorithm( + value['key_cipher_algorithm'], + KeyCipherAlgorithm.RSA_ECB_OAEPwithSHA_256andMGF1Padding + )!, + storageCipherAlgorithm: parseStorageCipherAlgorithm( + value['storage_cipher_algorithm'], + StorageCipherAlgorithm.AES_GCM_NoPadding + )!, + sharedPreferencesName: value['shared_preferences_name'], + preferencesKeyPrefix: value['preferences_key_prefix'], + biometricPromptTitle: value['biometric_prompt_title'], + biometricPromptSubtitle: value['biometric_prompt_subtitle'], + ); +} + +WindowsOptions? parseWindowsOptions(dynamic value, [WindowsOptions? defaultValue]) { + if (value == null) return defaultValue; + return WindowsOptions( + useBackwardCompatibility: parseBool(value["use_backward_compatibility"], false)!, + ); +} + +WebOptions? parseWebOptions(dynamic value, [WebOptions? defaultValue]) { + if (value == null) return defaultValue; + return WebOptions( + dbName: value["db_name"] ?? "FletEncryptedStorage", + publicKey: value["public_key"] ?? "FletSecureStorage", + wrapKey: value["wrap_key"] ?? "", + wrapKeyIv: value["wrap_key_iv"] ?? "", + useSessionStorage: parseBool(value["use_session_storage"], false)!, + ); +} + +KeychainAccessibility? parseKeychainAccessibility(String? value, [KeychainAccessibility? defaultValue]) { + if (value == null) return defaultValue; + return KeychainAccessibility.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase() + ) ?? defaultValue; +} + +KeyCipherAlgorithm? parseKeyCipherAlgorithm(String? value, [KeyCipherAlgorithm? defaultValue]) { + if (value == null) return defaultValue; + return KeyCipherAlgorithm.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase() + ) ?? defaultValue; +} + +StorageCipherAlgorithm? parseStorageCipherAlgorithm(String? value, [StorageCipherAlgorithm? defaultValue]) { + if (value == null) return defaultValue; + return StorageCipherAlgorithm.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase() + ) ?? defaultValue; +} + +AccessControlFlag? parseAccessControlFlag(String? value, [AccessControlFlag? defaultValue]) { + if (value == null) return defaultValue; + return AccessControlFlag.values.firstWhereOrNull( + (e) => e.name.toLowerCase() == value.toLowerCase() + ) ?? defaultValue; +} + +List? parseAccessControlFlags(List? value, [List? defaultValue,]) { + if (value == null) return defaultValue; + + return value + .whereType() + .map((e) => parseAccessControlFlag(e)).nonNulls + .whereType() + .toList(); +} diff --git a/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml new file mode 100644 index 0000000000..eb1322748e --- /dev/null +++ b/sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml @@ -0,0 +1,22 @@ +name: flet_secure_storage +description: Flet Secure Storage control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.3.0 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + flutter_secure_storage: 10.0.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-video/CHANGELOG.md b/sdk/python/packages/flet-video/CHANGELOG.md new file mode 100644 index 0000000000..d44fd73dc0 --- /dev/null +++ b/sdk/python/packages/flet-video/CHANGELOG.md @@ -0,0 +1,43 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.85.0 + +### Added + +- Configurable `Video.controls` with adaptive, Material, Material desktop, custom, hidden, and normal/fullscreen-specific controls ([#6463](https://github.com/flet-dev/flet/pull/6463)). +- `Video.take_screenshot()` for capturing the current video frame as PNG, JPEG, or raw BGRA bytes ([#6463](https://github.com/flet-dev/flet/pull/6463)). +- `Video.on_position_change` and `Video.on_duration_change` events emitting the current position and media duration ([#6463](https://github.com/flet-dev/flet/pull/6463)). + +### Changed + +- `Video.playlist` can now be mutated directly for playlist add and remove operations; `playlist_add()` and `playlist_remove()` are deprecated ([#6463](https://github.com/flet-dev/flet/pull/6463)). +- `Video.show_controls` is deprecated; set `Video.controls` to `None` to hide controls ([#6463](https://github.com/flet-dev/flet/pull/6463)). + +### Fixed + +- Reduce Linux memory retention when repeatedly removing `Video` controls by linking `media_kit` video apps against mimalloc in Flet run and build flows ([#6164](https://github.com/flet-dev/flet/issues/6164), [#6416](https://github.com/flet-dev/flet/pull/6416)). + +## 0.80.0 + +### Added + +- Deployed online documentation: https://flet.dev/docs/video/ +- `Video` new property: `subtitle_track` +- `VideoConfiguration` new properties: `width`, `height`, `scale` + +### Changed + +- Refactored `Video` control to use `@flet.control` dataclass-style definition. +- Renamed `Video` event handler properties: + - `on_loaded` → `on_load` + - `on_completed` → `on_complete` + - `on_track_changed` → `on_track_change` + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-video/LICENSE b/sdk/python/packages/flet-video/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-video/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-video/README.md b/sdk/python/packages/flet-video/README.md new file mode 100644 index 0000000000..701829f16e --- /dev/null +++ b/sdk/python/packages/flet-video/README.md @@ -0,0 +1,56 @@ +# flet-video + +[![pypi](https://img.shields.io/pypi/v/flet-video.svg)](https://pypi.python.org/pypi/flet-video) +[![downloads](https://static.pepy.tech/badge/flet-video/month)](https://pepy.tech/project/flet-video) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-video) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-video.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-video.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-video/LICENSE) + +A cross-platform video player for [Flet](https://flet.dev) apps. + +It is based on the [media_kit](https://pub.dev/packages/media_kit) Flutter package. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/video/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-video` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-video + ``` + +- Using `pip`: + ```bash + pip install flet-video + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +> [!NOTE] +> To play video on Linux/WSL you need to install [`libmpv`](https://github.com/mpv-player/mpv) library: +> +> ```bash +> sudo apt update +> sudo apt install libmpv-dev libmpv2 +> ``` +> +> If you encounter `libmpv.so.1` load errors, run: +> +> ```bash +> sudo ln -s /usr/lib/x86_64-linux-gnu/libmpv.so /usr/lib/libmpv.so.1 +> ``` + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/video). diff --git a/sdk/python/packages/flet-video/pyproject.toml b/sdk/python/packages/flet-video/pyproject.toml new file mode 100644 index 0000000000..2e48aaf357 --- /dev/null +++ b/sdk/python/packages/flet-video/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-video" +version = "0.1.0" +description = "Cross-platform video playback for Flet apps." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/video" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-video" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_video" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-video/src/flet_video/__init__.py b/sdk/python/packages/flet-video/src/flet_video/__init__.py new file mode 100644 index 0000000000..237453106c --- /dev/null +++ b/sdk/python/packages/flet-video/src/flet_video/__init__.py @@ -0,0 +1,47 @@ +""" +Public exports for the flet-video package. +""" + +from flet_video.types import ( + AdaptiveVideoControls, + MaterialDesktopVideoControls, + MaterialVideoControls, + PlaylistMode, + VideoBarItem, + VideoConfiguration, + VideoControls, + VideoControlsMode, + VideoFullscreenButton, + VideoMedia, + VideoPlayOrPauseButton, + VideoPositionIndicator, + VideoSkipNextButton, + VideoSkipPreviousButton, + VideoSpacer, + VideoSubtitleConfiguration, + VideoSubtitleTrack, + VideoVolumeButton, +) +from flet_video.video import Video + +__all__ = [ + "AdaptiveVideoControls", + "MaterialDesktopVideoControls", + "MaterialVideoControls", + "PlaylistMode", + "Video", + "VideoBarItem", + "VideoConfiguration", + "VideoControls", + "VideoControlsMode", + "VideoFullscreenButton", + "VideoMedia", + "VideoPlayOrPauseButton", + "VideoPositionIndicator", + "VideoSkipNextButton", + "VideoSkipPreviousButton", + "VideoSpacer", + "VideoSubtitleConfiguration", + "VideoSubtitleTrack", + "VideoVolumeButton", +] diff --git a/sdk/python/packages/flet-video/src/flet_video/types.py b/sdk/python/packages/flet-video/src/flet_video/types.py new file mode 100644 index 0000000000..1c228616de --- /dev/null +++ b/sdk/python/packages/flet-video/src/flet_video/types.py @@ -0,0 +1,1033 @@ +""" +Type definitions and configuration objects for flet-video. +""" + +from dataclasses import field +from enum import Enum +from typing import Optional, Union + +import flet as ft + +__all__ = [ + "AdaptiveVideoControls", + "MaterialDesktopVideoControls", + "MaterialVideoControls", + "PlaylistMode", + "VideoBarItem", + "VideoConfiguration", + "VideoControls", + "VideoControlsMode", + "VideoFullscreenButton", + "VideoMedia", + "VideoPlayOrPauseButton", + "VideoPositionIndicator", + "VideoSkipNextButton", + "VideoSkipPreviousButton", + "VideoSpacer", + "VideoSubtitleConfiguration", + "VideoSubtitleTrack", + "VideoVolumeButton", +] + + +class PlaylistMode(Enum): + """Defines the playback mode for the video playlist.""" + + NONE = "none" + """End playback once end of the playlist is reached.""" + + SINGLE = "single" + """Indefinitely loop over the currently playing file in the playlist.""" + + LOOP = "loop" + """Loop over the playlist & restart it from beginning once end is reached.""" + + +class VideoControlsMode(Enum): + """Modes that can receive different :attr:`Video.controls` values.""" + + NORMAL = "normal" + """Controls used when the video is not fullscreen.""" + + FULLSCREEN = "fullscreen" + """Controls used when the video is fullscreen.""" + + DEFAULT = "default" + """Fallback controls used when no applicable mode-specific value is provided.""" + + +@ft.value +class VideoMedia: + """Represents a media resource for video playback.""" + + resource: str + """URI of the media resource.""" + + http_headers: Optional[dict[str, str]] = None + """HTTP headers to be used for the media resource.""" + + extras: Optional[dict[str, str]] = None + """Additional metadata for the media resource.""" + + +@ft.value +class VideoConfiguration: + """Additional configuration for video playback.""" + + output_driver: Optional[str] = None + """ + Sets the [--vo](https://mpv.io/manual/stable/#options-vo) property + on native backend. + + The default value is platform dependent: + - Windows, GNU/Linux, macOS & iOS : `"libmpv"` + - Android: `"gpu"` + """ + + hardware_decoding_api: Optional[str] = None + """ + Sets the [--hwdec](https://mpv.io/manual/stable/#options-hwdec) + property on native backend. + + The default value is platform dependent: + - Windows, GNU/Linux, macOS & iOS : `"auto"` + - Android: `"auto-safe"` + """ + + enable_hardware_acceleration: bool = True + """ + Whether to enable hardware acceleration. + When disabled, may cause battery drain, device heating, and high CPU usage. + """ + + width: Optional[ft.Number] = None + """ + The fixed width for the video output. + """ + + height: Optional[ft.Number] = None + """ + The fixed height for the video output. + """ + + scale: ft.Number = 1.0 + """ + The scale for the video output. + Specifying this option will cause :attr:`width` & :attr:`height` to be ignored. + """ + + mpv_properties: Optional[dict[str, Union[str, int, float, bool]]] = None + """ + Extra mpv/libmpv properties to set on + native backends (Windows/macOS/Linux/iOS/Android). + + The keys are mpv option/property names without the leading `--`. Values can be + `str`, `int`, `float` or `bool`. All values are converted to strings before being + passed to mpv; boolean values are converted to `"yes"` / `"no"`. + + Full list of mpv options: https://mpv.io/manual/stable/#options + + Example: + ```python + >>> VideoConfiguration( + mpv_properties={ + "profile": "low-latency", # --profile=low-latency + "untimed": True, # --untimed + "volume": 80, # --volume=80 + } + ) + ``` + """ + + +@ft.value +class VideoBarItem: + """Base class for built-in video controls button bar items.""" + + _type: str = field(default="", init=False, repr=False) + """ + Identifies which built-in video controls button bar item should be used. + + This value is fixed by each concrete item class. + """ + + +@ft.value +class VideoPlayOrPauseButton(VideoBarItem): + """A built-in play/pause button item.""" + + _type: str = field(default="playOrPauseButton", init=False, repr=False) + """ + Identifies this item as a built-in play/pause button. + """ + + icon_size: Optional[ft.Number] = None + """ + Overrides the icon size. + """ + + icon_color: Optional[ft.ColorValue] = None + """ + Overrides the icon color. + """ + + +@ft.value +class VideoSkipNextButton(VideoBarItem): + """A built-in skip next button item.""" + + _type: str = field(default="skipNextButton", init=False, repr=False) + """ + Identifies this item as a built-in skip next button. + """ + + icon: Optional[ft.Control] = None + """ + Icon displayed by the button. + + If omitted, the default skip next icon is used. + """ + + icon_size: Optional[ft.Number] = None + """ + Overrides the icon size. + """ + + icon_color: Optional[ft.ColorValue] = None + """ + Overrides the icon color. + """ + + +@ft.value +class VideoSkipPreviousButton(VideoBarItem): + """A built-in skip previous button item.""" + + _type: str = field(default="skipPreviousButton", init=False, repr=False) + """ + Identifies this item as a built-in skip previous button. + """ + + icon: Optional[ft.Control] = None + """ + Icon displayed by the button. + + If omitted, the default skip previous icon is used. + """ + + icon_size: Optional[ft.Number] = None + """ + Overrides the icon size. + """ + + icon_color: Optional[ft.ColorValue] = None + """ + Overrides the icon color. + """ + + +@ft.value +class VideoFullscreenButton(VideoBarItem): + """A built-in fullscreen button item.""" + + _type: str = field(default="fullscreenButton", init=False, repr=False) + """ + Identifies this item as a built-in fullscreen button. + """ + + icon: Optional[ft.Control] = None + """ + Icon displayed by the button. + + If omitted, the default fullscreen icon is used. + """ + + icon_size: Optional[ft.Number] = None + """ + Overrides the icon size. + """ + + icon_color: Optional[ft.ColorValue] = None + """ + Overrides the icon color. + """ + + +@ft.value +class VideoPositionIndicator(VideoBarItem): + """A built-in playback position indicator item.""" + + _type: str = field(default="positionIndicator", init=False, repr=False) + """ + Identifies this item as a built-in playback position indicator. + """ + + text_style: Optional[ft.TextStyle] = None + """ + Overrides the text style. + """ + + +@ft.value +class VideoSpacer(VideoBarItem): + """A built-in spacer item for video controls button bars.""" + + _type: str = field(default="spacer", init=False, repr=False) + """ + Identifies this item as a built-in spacer. + """ + + flex: int = 1 + """ + The flex factor to use for the spacer. + """ + + +@ft.value +class VideoVolumeButton(VideoBarItem): + """ + A built-in volume button and slider item. + + Note: + This item is currently rendered only by :class:`MaterialDesktopVideoControls`. + """ + + _type: str = field(default="volumeButton", init=False, repr=False) + """ + Identifies this item as a built-in Material desktop volume button. + """ + + icon_size: Optional[ft.Number] = None + """ + Overrides the icon size. + """ + + icon_color: Optional[ft.ColorValue] = None + """ + Overrides the icon color. + """ + + volume_mute_icon: Optional[ft.Control] = None + """ + Icon displayed when volume is muted. + + If omitted, the default muted volume icon is used. + """ + + volume_low_icon: Optional[ft.Control] = None + """ + Icon displayed when volume is low. + + If omitted, the default low volume icon is used. + """ + + volume_high_icon: Optional[ft.Control] = None + """ + Icon displayed when volume is high. + + If omitted, the default high volume icon is used. + """ + + slider_width: Optional[ft.Number] = None + """ + Width of the volume slider. + """ + + +@ft.value +class VideoControls: + """Base class for built-in video controls.""" + + _type: str = field(default="", init=False, repr=False) + """ + Identifies which built-in controls implementation should be used. + + This value is fixed by each concrete controls class. + """ + + +@ft.value +class MaterialVideoControls(VideoControls): + """Touch-oriented Material video controls.""" + + _type: str = field(default="material", init=False, repr=False) + """ + Identifies this value as Material video controls. + """ + + # Behavior + + display_seek_bar: bool = True + """ + Whether to display seek bar. + """ + + automatically_imply_skip_next_button: bool = True + """ + Whether a skip next button should be displayed if there are more than one + videos in the playlist. + """ + + automatically_imply_skip_previous_button: bool = True + """ + Whether a skip previous button should be displayed if there are more than one + videos in the playlist. + """ + + volume_gesture: bool = False + """ + Whether to modify volume on vertical drag gesture on the right side of the screen. + """ + + brightness_gesture: bool = False + """ + Whether to modify screen brightness on vertical drag gesture on the left side + of the screen. + """ + + seek_gesture: bool = False + """ + Whether to seek on horizontal drag gesture. + """ + + gestures_enabled_while_controls_visible: bool = True + """ + Whether to allow gesture controls to work while controls are visible. + + Note: + This option is ignored when gestures are disabled. + """ + + seek_on_double_tap: bool = False + """ + Whether to enable double tap to seek on left or right side of the screen. + """ + + seek_on_double_tap_enabled_while_controls_visible: bool = True + """ + Whether to allow double tap to seek on left or right side of the screen to + work while controls are visible. + + Note: + This option is ignored when :attr:`seek_on_double_tap` is `False`. + """ + + seek_on_double_tap_layout_taps_ratios: list[int] = field( + default_factory=lambda: [1, 1, 1] + ) + """ + Width proportions for the backward seek, instant tap, and forward seek areas + when a double tap occurs on the video widget. + """ + + seek_on_double_tap_layout_widget_ratios: list[int] = field( + default_factory=lambda: [1, 1, 1] + ) + """ + Width proportions for the visual indicators shown during backward seek, + instant tap, and forward seek actions. + """ + + seek_on_double_tap_backward_duration: ft.DurationValue = 10000 + """ + Duration of seek on double tap backward. + """ + + seek_on_double_tap_forward_duration: ft.DurationValue = 10000 + """ + Duration of seek on double tap forward. + """ + + visible_on_mount: bool = False + """ + Whether the controls are initially visible. + """ + + speed_up_on_long_press: bool = False + """ + Whether to speed up on long press. + """ + + speed_up_factor: ft.Number = 2.0 + """ + Factor to speed up on long press. + """ + + vertical_gesture_sensitivity: ft.Number = 100 + """ + Gesture sensitivity on vertical drag gestures, the higher the value is the + less sensitive the gesture. + """ + + horizontal_gesture_sensitivity: ft.Number = 1000 + """ + Gesture sensitivity on horizontal drag gestures, the higher the value is the + less sensitive the gesture. + """ + + backdrop_color: Optional[ft.ColorValue] = "#66000000" + """ + Color of backdrop that comes up when controls are visible. + """ + + # Generic + + padding: Optional[ft.PaddingValue] = None + """ + Padding around the controls. + """ + + controls_hover_duration: ft.DurationValue = 3000 + """ + Duration after which the controls will be hidden when there is no mouse movement. + """ + + controls_transition_duration: ft.DurationValue = 300 + """ + Duration for which the controls will be animated when shown or hidden. + """ + + initial_volume: ft.Number = 0.5 + """ + Initial volume value used by the volume gesture indicator. + + It ranges from `0.0` to `1.0`. + """ + + initial_brightness: ft.Number = 0.5 + """ + Initial brightness value used by the brightness gesture indicator. + + It ranges from `0.0` to `1.0`. + """ + + # Button bar + + primary_button_bar: Optional[list[Union[ft.Control, VideoBarItem]]] = None + """ + Controls displayed in the primary button bar. + + Set to a list to replace the primary button bar, or an empty list to hide + it; if `None`, the native default is: + ```python + [ + ftv.VideoSpacer(flex=2), + ftv.VideoSkipPreviousButton(), + ftv.VideoSpacer(), + ftv.VideoPlayOrPauseButton(icon_size=48.0), + ftv.VideoSpacer(), + ftv.VideoSkipNextButton(), + ftv.VideoSpacer(flex=2), + ] + ``` + """ + + top_button_bar: Optional[list[Union[ft.Control, VideoBarItem]]] = None + """ + Controls displayed in the top button bar. + + Set to a list to replace the top button bar, or an empty list to hide it; + if `None`, the native default is an empty list. + """ + + top_button_bar_margin: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(horizontal=16.0) + ) + """ + Margin around the top button bar. + """ + + bottom_button_bar: Optional[list[Union[ft.Control, VideoBarItem]]] = None + """ + Controls displayed in the bottom button bar. + + Set to a list to replace the bottom button bar, or an empty list to hide + it; if `None`, the native default is: + ```python + [ + ftv.VideoPositionIndicator(), + ftv.VideoSpacer(), + ftv.VideoFullscreenButton(), + ] + ``` + """ + + bottom_button_bar_margin: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.only(left=16.0, right=8.0) + ) + """ + Margin around the button bar. + """ + + button_bar_height: ft.Number = 56.0 + """ + Height of the button bar. + """ + + button_bar_button_size: ft.Number = 24.0 + """ + Size of the button bar buttons. + """ + + button_bar_button_color: ft.ColorValue = "#FFFFFFFF" + """ + Color of the button bar buttons. + """ + + # Seek bar + + seek_bar_margin: ft.PaddingValue = 0 + """ + Margin around the seek bar. + """ + + seek_bar_height: ft.Number = 2.4 + """ + Height of the seek bar. + """ + + seek_bar_container_height: ft.Number = 36.0 + """ + Height of the seek bar container. + """ + + seek_bar_color: ft.ColorValue = "#3DFFFFFF" + """ + Color of the seek bar. + """ + + seek_bar_position_color: ft.ColorValue = "#FFFF0000" + """ + Color of the playback position section in the seek bar. + """ + + seek_bar_buffer_color: ft.ColorValue = "#3DFFFFFF" + """ + Color of the playback buffer section in the seek bar. + """ + + seek_bar_thumb_size: ft.Number = 12.8 + """ + Size of the seek bar thumb. + """ + + seek_bar_thumb_color: ft.ColorValue = "#FFFF0000" + """ + Color of the seek bar thumb. + """ + + seek_bar_alignment: ft.Alignment = field( + default_factory=lambda: ft.Alignment.BOTTOM_CENTER + ) + """ + Alignment of seek bar inside the seek bar container. + """ + + # Subtitle + + shift_subtitles_on_controls_visibility_change: bool = False + """ + Whether to shift the subtitles upwards when the controls are visible. + """ + + +@ft.value +class MaterialDesktopVideoControls(VideoControls): + """Desktop-oriented Material video controls.""" + + _type: str = field(default="materialDesktop", init=False, repr=False) + """ + Identifies this value as Material desktop video controls. + """ + + # Behavior + + display_seek_bar: bool = True + """ + Whether to display seek bar. + """ + + automatically_imply_skip_next_button: bool = True + """ + Whether a skip next button should be displayed if there are more than one + videos in the playlist. + """ + + automatically_imply_skip_previous_button: bool = True + """ + Whether a skip previous button should be displayed if there are more than one + videos in the playlist. + """ + + modify_volume_on_scroll: bool = True + """ + Modify volume on mouse scroll. + """ + + toggle_fullscreen_on_double_press: bool = True + """ + Whether to toggle fullscreen on double press. + """ + + hide_mouse_on_controls_removal: bool = False + """ + Whether to hide mouse on controls removal. + + Note: + On most platforms, the mouse must move before it becomes hidden. It + works on macOS without moving the mouse. + """ + + play_and_pause_on_tap: bool = False + """ + Whether to toggle play and pause on tap. + """ + + visible_on_mount: bool = False + """ + Whether the controls are initially visible. + """ + + # Generic + + padding: Optional[ft.PaddingValue] = None + """ + Padding around the controls. + """ + + controls_hover_duration: ft.DurationValue = 3000 + """ + Duration after which the controls will be hidden when there is no mouse movement. + """ + + controls_transition_duration: ft.DurationValue = 150 + """ + Duration for which the controls will be animated when shown or hidden. + """ + + # Button bar + + primary_button_bar: Optional[list[Union[ft.Control, VideoBarItem]]] = None + """ + Controls displayed in the primary button bar. + + Set to a list to replace the primary button bar, or an empty list to hide + it; if `None`, the native default is an empty list. + """ + + top_button_bar: Optional[list[Union[ft.Control, VideoBarItem]]] = None + """ + Controls displayed in the top button bar. + + Set to a list to replace the top button bar, or an empty list to hide it; + if `None`, the native default is an empty list. + """ + + top_button_bar_margin: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(horizontal=16.0) + ) + """ + Margin around the top button bar. + """ + + bottom_button_bar: Optional[list[Union[ft.Control, VideoBarItem]]] = None + """ + Controls displayed in the bottom button bar. + + Set to a list to replace the bottom button bar, or an empty list to hide + it; if `None`, the native default is: + ```python + [ + ftv.VideoSkipPreviousButton(), + ftv.VideoPlayOrPauseButton(), + ftv.VideoSkipNextButton(), + ftv.VideoSpacer(), + ftv.VideoPositionIndicator(), + ftv.VideoFullscreenButton(), + ftv.VideoVolumeButton(), + ] + ``` + """ + + bottom_button_bar_margin: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(horizontal=16.0) + ) + """ + Margin around the bottom button bar. + """ + + button_bar_height: ft.Number = 56.0 + """ + Height of the button bar. + """ + + button_bar_button_size: ft.Number = 28.0 + """ + Size of the button bar buttons. + """ + + button_bar_button_color: ft.ColorValue = "#FFFFFFFF" + """ + Color of the button bar buttons. + """ + + # Seek bar + + seek_bar_transition_duration: ft.DurationValue = 300 + """ + Duration for which the seek bar will be animated when the user seeks. + """ + + seek_bar_thumb_transition_duration: ft.DurationValue = 150 + """ + Duration for which the seek bar thumb will be animated when the user seeks. + """ + + seek_bar_margin: ft.PaddingValue = field( + default_factory=lambda: ft.Padding.symmetric(horizontal=16.0) + ) + """ + Margin around the seek bar. + """ + + seek_bar_height: ft.Number = 3.2 + """ + Height of the seek bar. + """ + + seek_bar_hover_height: ft.Number = 5.6 + """ + Height of the seek bar when hovered. + """ + + seek_bar_container_height: ft.Number = 36.0 + """ + Height of the seek bar container. + """ + + seek_bar_color: ft.ColorValue = "#3DFFFFFF" + """ + Color of the seek bar. + """ + + seek_bar_hover_color: ft.ColorValue = "#3DFFFFFF" + """ + Color of the hovered section in the seek bar. + """ + + seek_bar_position_color: ft.ColorValue = "#FFFF0000" + """ + Color of the playback position section in the seek bar. + """ + + seek_bar_buffer_color: ft.ColorValue = "#3DFFFFFF" + """ + Color of the playback buffer section in the seek bar. + """ + + seek_bar_thumb_size: ft.Number = 12.0 + """ + Size of the seek bar thumb. + """ + + seek_bar_thumb_color: ft.ColorValue = "#FFFF0000" + """ + Color of the seek bar thumb. + """ + + # Volume bar + + volume_bar_color: ft.ColorValue = "#3DFFFFFF" + """ + Color of the volume bar. + """ + + volume_bar_active_color: ft.ColorValue = "#FFFFFFFF" + """ + Color of the active region in the volume bar. + """ + + volume_bar_thumb_size: ft.Number = 12.0 + """ + Size of the volume bar thumb. + """ + + volume_bar_thumb_color: ft.ColorValue = "#FFFFFFFF" + """ + Color of the volume bar thumb. + """ + + volume_bar_transition_duration: ft.DurationValue = 150 + """ + Duration for which the volume bar will be animated when the user hovers. + """ + + # Subtitle + + shift_subtitles_on_controls_visibility_change: bool = True + """ + Whether to shift the subtitles upwards when the controls are visible. + """ + + +@ft.value +class AdaptiveVideoControls(VideoControls): + """ + Platform-adaptive video controls. + + Adaptive controls select the controls implementation at runtime based on the + current :attr:`flet.Page.platform`: + - Android and iOS use Material controls. + - macOS, Windows, and Linux use Material desktop controls. + - Other platforms show no built-in controls. + + Use :attr:`material` and :attr:`material_desktop` to configure the controls + family that may be selected for each platform. + """ + + _type: str = field(default="adaptive", init=False, repr=False) + """ + Identifies this value as adaptive video controls. + """ + + material: Optional[MaterialVideoControls] = None + """ + Controls used when adaptive controls select Material controls. + + If omitted, Material controls use the default + :class:`MaterialVideoControls` value. + """ + + material_desktop: Optional[MaterialDesktopVideoControls] = None + """ + Controls used when adaptive controls select Material desktop controls. + + If omitted, Material desktop controls use the default + :class:`MaterialDesktopVideoControls` value. + """ + + +@ft.value +class VideoSubtitleTrack: + """Represents a subtitle track for a video.""" + + src: str + """ + The subtitle source. + + Supported values: + - A URL (e.g. "https://example.com/subs.srt" or "www.example.com/sub.vtt") + - An absolute local file path (not supported on the web platform) + - A raw subtitle text string (e.g. the full contents of an SRT/VTT file) + """ + + title: Optional[str] = None + """The title of the subtitle track, e.g. 'English'.""" + + language: Optional[str] = None + """The language of the subtitle track, e.g. 'en'.""" + + channels_count: Optional[int] = None + """ + The number of audio channels detected in the media. + """ + + channels: Optional[str] = None + """ + Channel layout string describing the spatial arrangement of channels. + """ + + sample_rate: Optional[int] = None + """ + Audio sampling rate in hertz. + """ + + fps: Optional[ft.Number] = None + """ + Video frames per second. + """ + + bitrate: Optional[int] = None + """ + Overall media bitrate in bits per second. + """ + + rotate: Optional[int] = None + """ + Rotation metadata in degrees to apply when rendering the video. + """ + + par: Optional[ft.Number] = None + """ + Pixel aspect ratio value. + """ + + audio_channels: Optional[int] = None + """ + Explicit audio channel count override. + """ + + album_art: Optional[bool] = None + """ + Whether the track represents album art rather than timed media. + """ + + codec: Optional[str] = None + """ + Codec identifier for the media stream. + """ + + decoder: Optional[str] = None + """ + Decoder name used to process the media stream. + """ + + @classmethod + def none(cls) -> "VideoSubtitleTrack": + """No subtitle track. Disables subtitle output.""" + return VideoSubtitleTrack(src="none") + + @classmethod + def auto(cls) -> "VideoSubtitleTrack": + """Default subtitle track. Selects the first subtitle track.""" + return VideoSubtitleTrack(src="auto") + + +@ft.value +class VideoSubtitleConfiguration: + """Represents the configuration for video subtitles.""" + + text_style: ft.TextStyle = field( + default_factory=lambda: ft.TextStyle( + height=1.4, + size=32.0, + letter_spacing=0.0, + word_spacing=0.0, + color=ft.Colors.WHITE, + weight=ft.FontWeight.NORMAL, + bgcolor=ft.Colors.BLACK_54, + ) + ) + """The text style to be used for the subtitles.""" + + text_scale_factor: ft.Number = 1.0 + """ + Defines the scale factor for the subtitle text. + """ + + text_align: ft.TextAlign = ft.TextAlign.CENTER + """ + The text alignment to be used for the subtitles. + """ + + padding: ft.PaddingValue = field( + default_factory=lambda: ft.Padding(left=16.0, top=0.0, right=16.0, bottom=24.0) + ) + """ + The padding to be used for the subtitles. + """ + + visible: bool = True + """ + Whether the subtitles should be visible or not. + """ diff --git a/sdk/python/packages/flet-video/src/flet_video/video.py b/sdk/python/packages/flet-video/src/flet_video/video.py new file mode 100644 index 0000000000..ccdaa38919 --- /dev/null +++ b/sdk/python/packages/flet-video/src/flet_video/video.py @@ -0,0 +1,392 @@ +""" +Video control definition for the flet-video package. +""" + +from dataclasses import field +from typing import Annotated, Optional, Union + +import flet as ft +from flet.utils.deprecated import deprecated +from flet.utils.validation import V +from flet_video.types import ( + AdaptiveVideoControls, + PlaylistMode, + VideoConfiguration, + VideoControls, + VideoControlsMode, + VideoMedia, + VideoSubtitleConfiguration, + VideoSubtitleTrack, +) + +__all__ = ["Video"] + + +@ft.control("Video") +class Video(ft.LayoutControl): + """ + A control that displays a video from a playlist. + """ + + playlist: list[VideoMedia] = field(default_factory=list) + """ + A list of `VideoMedia`s representing the video files to be played. + """ + + title: str = "flet-video" + """ + Defines the name of the underlying window & process for native backend. + This is visible inside the windows' volume mixer. + """ + + fit: ft.BoxFit = ft.BoxFit.CONTAIN + """ + The box fit to use for the video. + """ + + fill_color: ft.ColorValue = ft.Colors.BLACK + """ + Defines the color used to fill the video background. + """ + + wakelock: bool = True + """ + Whether to acquire wake lock while playing the video. + When `True`, device's display will not go to standby/sleep while + the video is playing. + """ + + autoplay: bool = False + """ + Whether the video should start playing automatically. + """ + + show_controls: Annotated[ + Optional[bool], + V.deprecated( + version="0.85.0", + delete_version="0.88.0", + reason="Use controls=None to hide controls.", + docs_reason="To hide controls, instead set :attr:`controls` to `None`.", + ), + ] = None + """ + Whether to show the video player :attr:`controls`. + """ + + controls: Optional[ + Union[ + VideoControls, + ft.Control, + dict[VideoControlsMode, Optional[Union[VideoControls, ft.Control]]], + ] + ] = field(default_factory=lambda: AdaptiveVideoControls()) + """ + Controls displayed over the video. + + Set to a :class:`VideoControls` object to use built-in controls, a + :class:`flet.Control` object to use custom Flet controls, or `None` to hide + controls. + + To use different controls outside and inside fullscreen, set this property + to a dictionary keyed by :class:`VideoControlsMode`. The + :attr:`VideoControlsMode.DEFAULT` value is used when + :attr:`VideoControlsMode.NORMAL` controls are not provided. If + :attr:`VideoControlsMode.FULLSCREEN` controls are not provided, + :attr:`VideoControlsMode.NORMAL` controls are reused before + falling back to :attr:`VideoControlsMode.DEFAULT`. A mode value of + `None` hides controls for that mode only. + + Note: + During the :attr:`show_controls` deprecation period, `show_controls=False` + hides controls even when this property is set. + """ + + fullscreen: bool = False + """ + Whether the video player is presented in fullscreen mode. + + Set to `True` to enter fullscreen or `False` to exit fullscreen programmatically. + """ + + muted: bool = False + """ + Defines whether the video player should be started in muted state. + """ + + playlist_mode: Optional[PlaylistMode] = None + """ + Represents the mode of playback for the playlist. + """ + + shuffle_playlist: bool = False + """ + Defines whether the playlist should be shuffled. + """ + + volume: ft.Number = 100.0 + """ + Defines the volume of the video player. + + Note: + It's value ranges between `0.0` to `100.0` (inclusive), where `0.0` + is muted and `100.0` is the maximum volume. + An exception will be raised if the value is outside this range. + + Raises: + ValueError: If its value is not between `0.0` and `100.0` (inclusive). + """ + + playback_rate: ft.Number = 1.0 + """ + Defines the playback rate of the video player. + """ + + alignment: ft.Alignment = field(default_factory=lambda: ft.Alignment.CENTER) + """ + Defines the Alignment of the viewport. + """ + + filter_quality: ft.FilterQuality = ft.FilterQuality.LOW + """ + Filter quality of the texture used to render the video output. + + Note: + Android was reported to show blurry images when using + :attr:`flet.FilterQuality.HIGH`. + Prefer the usage of :attr:`flet.FilterQuality.MEDIUM` + on this platform. + """ + + pause_upon_entering_background_mode: bool = True + """ + Whether to pause the video when application enters background mode. + """ + + resume_upon_entering_foreground_mode: bool = False + """ + Whether to resume the video when application enters foreground mode. + Has effect only if :attr:`pause_upon_entering_background_mode` is also set to + `True`. + """ + + pitch: ft.Number = 1.0 + """ + Defines the relative pitch of the video player. + """ + + configuration: VideoConfiguration = field( + default_factory=lambda: VideoConfiguration() + ) + """ + Additional configuration for the video player. + """ + + subtitle_configuration: VideoSubtitleConfiguration = field( + default_factory=lambda: VideoSubtitleConfiguration() + ) + """ + Defines the subtitle configuration for the video player. + """ + + subtitle_track: Optional[VideoSubtitleTrack] = None + """ + Defines the subtitle track for the video player. + """ + + on_load: Optional[ft.ControlEventHandler["Video"]] = None + """Fires when the video player is initialized and ready for playback.""" + + on_enter_fullscreen: Optional[ft.ControlEventHandler["Video"]] = None + """Fires when the video player enters fullscreen.""" + + on_exit_fullscreen: Optional[ft.ControlEventHandler["Video"]] = None + """Fires when the video player exits fullscreen""" + + on_error: Optional[ft.ControlEventHandler["Video"]] = None + """ + Fires when an error occurs. + + Event handler argument's :attr:`~flet.Event.data` property contains + information about the error. + """ + + on_complete: Optional[ft.ControlEventHandler["Video"]] = None + """Fires when a video player completes.""" + + on_track_change: Optional[ft.ControlEventHandler["Video"]] = None + """ + Fires when a video track changes. + + Event handler argument's :attr:`~flet.Event.data` property contains + the index of the new track. + """ + + on_position_change: Optional[ft.ControlEventHandler["Video"]] = None + """ + Fires when the current playback position changes. + + Event handler argument's :attr:`~flet.Event.data` property contains + the current position as a :class:`flet.Duration`. + """ + + on_duration_change: Optional[ft.ControlEventHandler["Video"]] = None + """ + Fires when the current media duration changes. + + Event handler argument's :attr:`~flet.Event.data` property contains + the current duration as a :class:`flet.Duration`. + """ + + def before_update(self): + super().before_update() + if not (0 <= self.volume <= 100): + raise ValueError( + f"volume must be between 0 and 100 inclusive, got {self.volume}" + ) + + async def play(self): + """Starts playing the video.""" + await self._invoke_method("play") + + async def pause(self): + """Pauses the video player.""" + await self._invoke_method("pause") + + async def play_or_pause(self): + """ + Cycles between play and pause states of the video player, + i.e., plays if paused and pauses if playing. + """ + await self._invoke_method("play_or_pause") + + async def stop(self): + """Stops the video player.""" + await self._invoke_method("stop") + + async def next(self): + """Jumps to the next `VideoMedia` in the :attr:`playlist`.""" + await self._invoke_method("next") + + async def previous(self): + """Jumps to the previous `VideoMedia` in the :attr:`playlist`.""" + await self._invoke_method("previous") + + async def seek(self, position: ft.DurationValue): + """ + Seeks the currently playing `VideoMedia` from the + :attr:`playlist` at the specified `position`. + """ + await self._invoke_method( + "seek", + {"position": position}, + ) + + async def jump_to(self, media_index: int): + """ + Jumps to the `VideoMedia` at the specified `media_index` + in the :attr:`playlist`. + """ + if not (-len(self.playlist) <= media_index < len(self.playlist)): + raise IndexError("media_index is out of range") + if media_index < 0: + # dart doesn't support negative indexes + media_index = len(self.playlist) + media_index + await self._invoke_method( + method_name="jump_to", + arguments={"media_index": media_index}, + ) + + @deprecated( + reason="Use playlist.append(media) instead.", + docs_reason="Use :attr:`playlist` directly, for example `video.playlist.append(media)`.", # noqa: E501 + version="0.85.0", + delete_version="0.88.0", + show_parentheses=True, + ) + async def playlist_add(self, media: VideoMedia): + """Appends/Adds the provided `media` to the `playlist`.""" + if not media.resource: + raise ValueError("media has no resource") + self.playlist.append(media) + + @deprecated( + reason="Use playlist.pop(media_index) instead.", + docs_reason="Use :attr:`playlist` directly, for example `video.playlist.pop(media_index)`.", # noqa: E501 + version="0.85.0", + delete_version="0.88.0", + show_parentheses=True, + ) + async def playlist_remove(self, media_index: int): + """Removes the provided `media` from the `playlist`.""" + playlist_length = len(self.playlist) + if not (-playlist_length <= media_index < playlist_length): + raise IndexError("media_index is out of range") + if media_index < 0: + media_index = playlist_length + media_index + self.playlist.pop(media_index) + + async def is_playing(self) -> bool: + """ + Returns: + `True` if the video player is currently playing, `False` otherwise. + """ + return await self._invoke_method("is_playing") + + async def is_completed(self) -> bool: + """ + Returns: + `True` if video player has reached the end of + the currently playing media, `False` otherwise. + """ + return await self._invoke_method("is_completed") + + async def get_duration(self) -> ft.Duration: + """ + Returns: + The duration of the currently playing media. + """ + return await self._invoke_method("get_duration") + + async def get_current_position(self) -> ft.Duration: + """ + Returns: + The current position of the currently playing media. + """ + return await self._invoke_method("get_current_position") + + async def take_screenshot( + self, + format: Optional[str] = "image/png", + include_libass_subtitles: bool = False, + ) -> Optional[bytes]: + """ + Captures a screenshot of the current video frame. + + Args: + format: The image format to return. Supported values are `"image/png"` + (PNG encoded image), `"image/jpeg"` (JPEG encoded image), + and `None` (raw BGRA pixel buffer on native backends). + include_libass_subtitles: Whether to include libass subtitles in the + screenshot on native backends. This requires libass support in the + underlying player and is ignored on the web backend. + + Returns: + Encoded image bytes, or `None` if the current backend cannot capture a + video frame. + + Raises: + ValueError: If `format` is not supported. + """ + supported_formats = ("image/png", "image/jpeg", None) + if format not in supported_formats: + raise ValueError( + f"format must be one of {supported_formats}, got {format!r}" + ) + return await self._invoke_method( + "take_screenshot", + arguments={ + "format": format, + "include_libass_subtitles": include_libass_subtitles, + }, + ) diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/.gitignore b/sdk/python/packages/flet-video/src/flutter/flet_video/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/LICENSE b/sdk/python/packages/flet-video/src/flutter/flet_video/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/analysis_options.yaml b/sdk/python/packages/flet-video/src/flutter/flet_video/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/flet_video.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/flet_video.dart new file mode 100644 index 0000000000..345e980435 --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/flet_video.dart @@ -0,0 +1,3 @@ +library flet_video; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/extension.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/extension.dart new file mode 100644 index 0000000000..278ece6f43 --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/extension.dart @@ -0,0 +1,22 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:media_kit/media_kit.dart'; + +import 'video.dart'; + +class Extension extends FletExtension { + @override + void ensureInitialized() { + MediaKit.ensureInitialized(); + } + + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "Video": + return VideoControl(key: key, control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/file_utils_io.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/file_utils_io.dart new file mode 100644 index 0000000000..fb8568dd6e --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/file_utils_io.dart @@ -0,0 +1,9 @@ +import 'dart:io'; + +/// Only available on non‐web platforms. +/// Returns the file's contents if it exists, or null otherwise. +String? readFileAsStringIfExists(String path) { + final file = File(path); + if (file.existsSync()) return file.readAsStringSync(); + return null; +} diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/file_utils_web.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/file_utils_web.dart new file mode 100644 index 0000000000..ef494e019f --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/file_utils_web.dart @@ -0,0 +1,4 @@ +/// On web, local‐path reading isn’t supported. Always returns null. +String? readFileAsStringIfExists(String path) { + return null; +} diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/video.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/video.dart new file mode 100644 index 0000000000..f1ae013129 --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/utils/video.dart @@ -0,0 +1,545 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +import "file_utils_web.dart" if (dart.library.io) 'file_utils_io.dart'; + +/// Empty controls builder used when controls are explicitly disabled. +Widget _noVideoControls(VideoState state) => const SizedBox.shrink(); + +/// Controls builder that selects the controls implementation for the current +/// platform. +Widget _adaptiveVideoControls(VideoState state) { + switch (Theme.of(state.context).platform) { + case TargetPlatform.android: + case TargetPlatform.iOS: + return MaterialVideoControls(state); + case TargetPlatform.macOS: + case TargetPlatform.windows: + case TargetPlatform.linux: + return MaterialDesktopVideoControls(state); + default: + return _noVideoControls(state); + } +} + +Media? parseVideoMedia(dynamic value, FletBackend backend, + [Media? defaultValue]) { + if (value == null || value["resource"] == null) return defaultValue; + + final extras = (value["extras"] as Map?)?.map( + (key, val) => MapEntry(key.toString(), val.toString()), + ); + + final httpHeaders = (value["http_headers"] as Map?)?.map( + (key, val) => MapEntry(key.toString(), val.toString()), + ); + + // Resolve relative paths against assets_dir / page URI, matching how + // every other Flet media control handles `src`. media_kit's Media() + // accepts both URLs and absolute filesystem paths, so a single + // resolved string works for both web and native backends. + final resource = backend.getAssetSource(value["resource"] as String).path; + + return Media(resource, extras: extras, httpHeaders: httpHeaders); +} + +List? parseVideoMedias(dynamic value, FletBackend backend, + [List? defaultValue]) { + if (value == null) return defaultValue; + + if (value is List) { + return value.map((e) => parseVideoMedia(e, backend)).nonNulls.toList(); + } + + final media = parseVideoMedia(value, backend); + return media != null ? [media] : defaultValue; +} + +SubtitleViewConfiguration? parseSubtitleConfiguration( + dynamic value, ThemeData theme, + [SubtitleViewConfiguration? defaultValue]) { + if (value == null) return defaultValue; + + return SubtitleViewConfiguration( + style: parseTextStyle( + value["text_style"], + theme, + const TextStyle( + height: 1.4, + fontSize: 32.0, + letterSpacing: 0.0, + wordSpacing: 0.0, + color: Color(0xffffffff), + fontWeight: FontWeight.normal, + backgroundColor: Color(0xaa000000)))!, + visible: parseBool(value["visible"], true)!, + textScaler: TextScaler.linear(parseDouble(value["text_scale_factor"], 1)!), + textAlign: parseTextAlign(value["text_align"], TextAlign.center)!, + padding: parsePadding( + value["padding"], const EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 24.0))!, + ); +} + +bool isUrl(String value) { + final urlPattern = RegExp(r'^(http:\/\/|https:\/\/|www\.)'); + return urlPattern.hasMatch(value); +} + +SubtitleTrack? parseSubtitleTrack( + dynamic value, + BuildContext context, [ + SubtitleTrack? defaultValue, +]) { + if (value == null) return defaultValue; + + String src; + final String rawSrc = value["src"] as String; + if (rawSrc == "none") return SubtitleTrack.no(); + if (rawSrc == "auto") return SubtitleTrack.auto(); + + bool uri = false; + + if (isUrl(rawSrc)) { + uri = true; + src = rawSrc; + } else { + // Non-URL: on non-web platforms, try reading it as a file path + String? fileContents; + if (!isWebPlatform()) { + // todo: add support for relative paths to assets-dir + fileContents = readFileAsStringIfExists(rawSrc); + } + + // If reading succeeded, use the file’s contents; + // otherwise assume rawSrc is already subtitle text + src = fileContents ?? rawSrc; + uri = false; + } + + return SubtitleTrack( + src, + value["title"], + value["language"], + channelscount: parseInt(value["channels_count"]), + channels: value["channels"], + samplerate: parseInt(value["sample_rate"]), + fps: parseDouble(value["fps"]), + bitrate: parseInt(value["bitrate"]), + rotate: parseInt(value["rotate"]), + par: parseDouble(value["par"]), + audiochannels: parseInt(value["audio_channels"]), + albumart: parseBool(value["album_art"]), + codec: value["codec"], + decoder: value["decoder"], + data: !uri, + // true when providing raw subtitle text + uri: uri, // true when providing a URL + ); +} + +VideoControllerConfiguration? parseControllerConfiguration(dynamic value, + [VideoControllerConfiguration? defaultValue]) { + if (value == null) return defaultValue; + return VideoControllerConfiguration( + vo: value["output_driver"], + hwdec: value["hardware_decoding_api"], + enableHardwareAcceleration: + parseBool(value["enable_hardware_acceleration"], true)!, + width: value["width"], + height: value["height"], + scale: parseDouble(value["scale"], 1.0)!, + ); +} + +List parseVideoControlsIntList(dynamic value, List defaultValue) { + if (value == null) return defaultValue; + if (value is List) { + final result = value.map((e) => parseInt(e)).nonNulls.toList(); + return result.isNotEmpty ? result : defaultValue; + } + return defaultValue; +} + +Widget? parseVideoControlsBarItem( + dynamic value, ThemeData theme, bool materialDesktop) { + final controlWidget = parseControlWidget(value); + if (controlWidget != null) return controlWidget; + if (value is! Map) return null; + + final icon = parseControlWidget(value["icon"]); + final iconSize = parseDouble(value["icon_size"]); + final iconColor = parseColor(value["icon_color"], theme); + + switch (value["_type"]) { + case "playOrPauseButton": + return materialDesktop + ? MaterialDesktopPlayOrPauseButton( + iconSize: iconSize, + iconColor: iconColor, + ) + : MaterialPlayOrPauseButton( + iconSize: iconSize, + iconColor: iconColor, + ); + case "skipNextButton": + return materialDesktop + ? MaterialDesktopSkipNextButton( + icon: icon, + iconSize: iconSize, + iconColor: iconColor, + ) + : MaterialSkipNextButton( + icon: icon, + iconSize: iconSize, + iconColor: iconColor, + ); + case "skipPreviousButton": + return materialDesktop + ? MaterialDesktopSkipPreviousButton( + icon: icon, + iconSize: iconSize, + iconColor: iconColor, + ) + : MaterialSkipPreviousButton( + icon: icon, + iconSize: iconSize, + iconColor: iconColor, + ); + case "fullscreenButton": + return materialDesktop + ? MaterialDesktopFullscreenButton( + icon: icon, + iconSize: iconSize, + iconColor: iconColor, + ) + : MaterialFullscreenButton( + icon: icon, + iconSize: iconSize, + iconColor: iconColor, + ); + case "positionIndicator": + final style = parseTextStyle(value["text_style"], theme); + return materialDesktop + ? MaterialDesktopPositionIndicator(style: style) + : MaterialPositionIndicator(style: style); + case "spacer": + return Spacer(flex: parseInt(value["flex"], 1)!); + case "volumeButton": + return materialDesktop + ? MaterialDesktopVolumeButton( + iconSize: iconSize, + iconColor: iconColor, + volumeMuteIcon: parseControlWidget(value["volume_mute_icon"]), + volumeLowIcon: parseControlWidget(value["volume_low_icon"]), + volumeHighIcon: parseControlWidget(value["volume_high_icon"]), + sliderWidth: parseDouble(value["slider_width"]), + ) + : null; + default: + return null; + } +} + +List? parseVideoControlsBar( + dynamic value, ThemeData theme, bool materialDesktop) { + if (value is! List) return null; + + return value + .map((item) => parseVideoControlsBarItem(item, theme, materialDesktop)) + .nonNulls + .toList(); +} + +MaterialVideoControlsThemeData parseMaterialVideoControlsThemeData( + dynamic value, ThemeData theme) { + value ??= const {}; + return MaterialVideoControlsThemeData( + // behavior + displaySeekBar: parseBool(value["display_seek_bar"], true)!, + automaticallyImplySkipNextButton: + parseBool(value["automatically_imply_skip_next_button"], true)!, + automaticallyImplySkipPreviousButton: + parseBool(value["automatically_imply_skip_previous_button"], true)!, + volumeGesture: parseBool(value["volume_gesture"], false)!, + brightnessGesture: parseBool(value["brightness_gesture"], false)!, + seekGesture: parseBool(value["seek_gesture"], false)!, + gesturesEnabledWhileControlsVisible: + parseBool(value["gestures_enabled_while_controls_visible"], true)!, + seekOnDoubleTap: parseBool(value["seek_on_double_tap"], false)!, + seekOnDoubleTapEnabledWhileControlsVisible: parseBool( + value["seek_on_double_tap_enabled_while_controls_visible"], true)!, + seekOnDoubleTapLayoutTapsRatios: parseVideoControlsIntList( + value["seek_on_double_tap_layout_taps_ratios"], const [1, 1, 1]), + seekOnDoubleTapLayoutWidgetRatios: parseVideoControlsIntList( + value["seek_on_double_tap_layout_widget_ratios"], const [1, 1, 1]), + seekOnDoubleTapBackwardDuration: parseDuration( + value["seek_on_double_tap_backward_duration"], + const Duration(seconds: 10))!, + seekOnDoubleTapForwardDuration: parseDuration( + value["seek_on_double_tap_forward_duration"], + const Duration(seconds: 10))!, + visibleOnMount: parseBool(value["visible_on_mount"], false)!, + speedUpOnLongPress: parseBool(value["speed_up_on_long_press"], false)!, + speedUpFactor: parseDouble(value["speed_up_factor"], 2.0)!, + verticalGestureSensitivity: + parseDouble(value["vertical_gesture_sensitivity"], 100)!, + horizontalGestureSensitivity: + parseDouble(value["horizontal_gesture_sensitivity"], 1000)!, + backdropColor: + parseColor(value["backdrop_color"], theme, const Color(0x66000000)), + // generic + padding: parsePadding(value["padding"]), + controlsHoverDuration: parseDuration( + value["controls_hover_duration"], const Duration(seconds: 3))!, + controlsTransitionDuration: parseDuration( + value["controls_transition_duration"], + const Duration(milliseconds: 300))!, + initialVolume: parseDouble(value["initial_volume"], 0.5), + initialBrightness: parseDouble(value["initial_brightness"], 0.5), + // button bar + primaryButtonBar: + parseVideoControlsBar(value["primary_button_bar"], theme, false) ?? + kDefaultMaterialVideoControlsThemeData.primaryButtonBar, + topButtonBar: + parseVideoControlsBar(value["top_button_bar"], theme, false) ?? + kDefaultMaterialVideoControlsThemeData.topButtonBar, + topButtonBarMargin: parsePadding(value["top_button_bar_margin"], + const EdgeInsets.symmetric(horizontal: 16.0))!, + bottomButtonBar: + parseVideoControlsBar(value["bottom_button_bar"], theme, false) ?? + kDefaultMaterialVideoControlsThemeData.bottomButtonBar, + bottomButtonBarMargin: parsePadding(value["bottom_button_bar_margin"], + const EdgeInsets.only(left: 16.0, right: 8.0))!, + buttonBarHeight: parseDouble(value["button_bar_height"], 56.0)!, + buttonBarButtonSize: parseDouble(value["button_bar_button_size"], 24.0)!, + buttonBarButtonColor: parseColor( + value["button_bar_button_color"], theme, const Color(0xFFFFFFFF))!, + // seek bar + seekBarMargin: parsePadding(value["seek_bar_margin"], EdgeInsets.zero)!, + seekBarHeight: parseDouble(value["seek_bar_height"], 2.4)!, + seekBarContainerHeight: + parseDouble(value["seek_bar_container_height"], 36.0)!, + seekBarColor: + parseColor(value["seek_bar_color"], theme, const Color(0x3DFFFFFF))!, + seekBarPositionColor: parseColor( + value["seek_bar_position_color"], theme, const Color(0xFFFF0000))!, + seekBarBufferColor: parseColor( + value["seek_bar_buffer_color"], theme, const Color(0x3DFFFFFF))!, + seekBarThumbSize: parseDouble(value["seek_bar_thumb_size"], 12.8)!, + seekBarThumbColor: parseColor( + value["seek_bar_thumb_color"], theme, const Color(0xFFFF0000))!, + seekBarAlignment: + parseAlignment(value["seek_bar_alignment"], Alignment.bottomCenter)!, + // subtitle + shiftSubtitlesOnControlsVisibilityChange: parseBool( + value["shift_subtitles_on_controls_visibility_change"], false)!, + ); +} + +MaterialDesktopVideoControlsThemeData + parseMaterialDesktopVideoControlsThemeData(dynamic value, ThemeData theme) { + value ??= const {}; + return MaterialDesktopVideoControlsThemeData( + // behavior + displaySeekBar: parseBool(value["display_seek_bar"], true)!, + automaticallyImplySkipNextButton: + parseBool(value["automatically_imply_skip_next_button"], true)!, + automaticallyImplySkipPreviousButton: + parseBool(value["automatically_imply_skip_previous_button"], true)!, + modifyVolumeOnScroll: parseBool(value["modify_volume_on_scroll"], true)!, + toggleFullscreenOnDoublePress: + parseBool(value["toggle_fullscreen_on_double_press"], true)!, + hideMouseOnControlsRemoval: + parseBool(value["hide_mouse_on_controls_removal"], false)!, + playAndPauseOnTap: parseBool(value["play_and_pause_on_tap"], false)!, + visibleOnMount: parseBool(value["visible_on_mount"], false)!, + // generic + padding: parsePadding(value["padding"]), + controlsHoverDuration: parseDuration( + value["controls_hover_duration"], const Duration(seconds: 3))!, + controlsTransitionDuration: parseDuration( + value["controls_transition_duration"], + const Duration(milliseconds: 150))!, + // button bar + primaryButtonBar: + parseVideoControlsBar(value["primary_button_bar"], theme, true) ?? + kDefaultMaterialDesktopVideoControlsThemeData.primaryButtonBar, + topButtonBar: parseVideoControlsBar(value["top_button_bar"], theme, true) ?? + kDefaultMaterialDesktopVideoControlsThemeData.topButtonBar, + topButtonBarMargin: parsePadding(value["top_button_bar_margin"], + const EdgeInsets.symmetric(horizontal: 16.0))!, + bottomButtonBar: + parseVideoControlsBar(value["bottom_button_bar"], theme, true) ?? + kDefaultMaterialDesktopVideoControlsThemeData.bottomButtonBar, + bottomButtonBarMargin: parsePadding(value["bottom_button_bar_margin"], + const EdgeInsets.symmetric(horizontal: 16.0))!, + buttonBarHeight: parseDouble(value["button_bar_height"], 56.0)!, + buttonBarButtonSize: parseDouble(value["button_bar_button_size"], 28.0)!, + buttonBarButtonColor: parseColor( + value["button_bar_button_color"], theme, const Color(0xFFFFFFFF))!, + // seek bar + seekBarTransitionDuration: parseDuration( + value["seek_bar_transition_duration"], + const Duration(milliseconds: 300))!, + seekBarThumbTransitionDuration: parseDuration( + value["seek_bar_thumb_transition_duration"], + const Duration(milliseconds: 150))!, + seekBarMargin: parsePadding(value["seek_bar_margin"], + const EdgeInsets.symmetric(horizontal: 16.0))!, + seekBarHeight: parseDouble(value["seek_bar_height"], 3.2)!, + seekBarHoverHeight: parseDouble(value["seek_bar_hover_height"], 5.6)!, + seekBarContainerHeight: + parseDouble(value["seek_bar_container_height"], 36.0)!, + seekBarColor: + parseColor(value["seek_bar_color"], theme, const Color(0x3DFFFFFF))!, + seekBarHoverColor: parseColor( + value["seek_bar_hover_color"], theme, const Color(0x3DFFFFFF))!, + seekBarPositionColor: parseColor( + value["seek_bar_position_color"], theme, const Color(0xFFFF0000))!, + seekBarBufferColor: parseColor( + value["seek_bar_buffer_color"], theme, const Color(0x3DFFFFFF))!, + seekBarThumbSize: parseDouble(value["seek_bar_thumb_size"], 12.0)!, + seekBarThumbColor: parseColor( + value["seek_bar_thumb_color"], theme, const Color(0xFFFF0000))!, + // volume bar + volumeBarColor: + parseColor(value["volume_bar_color"], theme, const Color(0x3DFFFFFF))!, + volumeBarActiveColor: parseColor( + value["volume_bar_active_color"], theme, const Color(0xFFFFFFFF))!, + volumeBarThumbSize: parseDouble(value["volume_bar_thumb_size"], 12.0)!, + volumeBarThumbColor: parseColor( + value["volume_bar_thumb_color"], theme, const Color(0xFFFFFFFF))!, + volumeBarTransitionDuration: parseDuration( + value["volume_bar_transition_duration"], + const Duration(milliseconds: 150))!, + // subtitle + shiftSubtitlesOnControlsVisibilityChange: parseBool( + value["shift_subtitles_on_controls_visibility_change"], true)!, + ); +} + +bool _isVideoControlsModeMap(dynamic value) { + if (value is! Map) return false; + if (value.containsKey("_type")) return false; + return value.keys.every( + (key) => key == "normal" || key == "fullscreen" || key == "default"); +} + +dynamic _resolveVideoControlsMode(dynamic value, bool fullscreen) { + if (!_isVideoControlsModeMap(value)) return value; + + if (fullscreen) { + if (value.containsKey("fullscreen")) return value["fullscreen"]; + } + if (value.containsKey("normal")) return value["normal"]; + if (value.containsKey("default")) return value["default"]; + return null; +} + +Widget Function(VideoState) _customVideoControls(dynamic value) { + return (_) => parseControlWidget(value) ?? const SizedBox.shrink(); +} + +/// Selects the controls builder requested by the serialized controls value. +Widget Function(VideoState)? parseVideoControls(dynamic value) { + if (_isVideoControlsModeMap(value)) { + return (state) { + final modeValue = + _resolveVideoControlsMode(value, isFullscreen(state.context)); + final controls = parseVideoControls(modeValue); + return controls?.call(state) ?? const SizedBox.shrink(); + }; + } + + if (value is Control) { + return _customVideoControls(value); + } + + if (value == null) return _noVideoControls; + + switch (value["_type"]) { + case "adaptive": + return _adaptiveVideoControls; + case "material": + return MaterialVideoControls; + case "materialDesktop": + return MaterialDesktopVideoControls; + default: + return _adaptiveVideoControls; + } +} + +/// Wraps the video with the theme provider required by the selected built-in +/// controls implementation. +Widget wrapVideoControlsTheme(Widget child, dynamic value, ThemeData theme) { + if (_isVideoControlsModeMap(value)) { + final normal = _resolveVideoControlsMode(value, false); + final fullscreen = _resolveVideoControlsMode(value, true); + return MaterialVideoControlsTheme( + normal: parseMaterialVideoControlsThemeData( + _materialVideoControlsThemeValue(normal), theme), + fullscreen: parseMaterialVideoControlsThemeData( + _materialVideoControlsThemeValue(fullscreen), theme), + child: MaterialDesktopVideoControlsTheme( + normal: parseMaterialDesktopVideoControlsThemeData( + _materialDesktopVideoControlsThemeValue(normal), theme), + fullscreen: parseMaterialDesktopVideoControlsThemeData( + _materialDesktopVideoControlsThemeValue(fullscreen), theme), + child: child, + ), + ); + } + + if (value == null || value is Control) return child; + + switch (value["_type"]) { + case "adaptive": + final material = value["material"]; + final materialDesktop = value["material_desktop"]; + return MaterialVideoControlsTheme( + normal: parseMaterialVideoControlsThemeData(material, theme), + fullscreen: parseMaterialVideoControlsThemeData(material, theme), + child: MaterialDesktopVideoControlsTheme( + normal: parseMaterialDesktopVideoControlsThemeData( + materialDesktop, theme), + fullscreen: parseMaterialDesktopVideoControlsThemeData( + materialDesktop, theme), + child: child, + ), + ); + case "material": + return MaterialVideoControlsTheme( + normal: parseMaterialVideoControlsThemeData(value, theme), + fullscreen: parseMaterialVideoControlsThemeData(value, theme), + child: child, + ); + case "materialDesktop": + return MaterialDesktopVideoControlsTheme( + normal: parseMaterialDesktopVideoControlsThemeData(value, theme), + fullscreen: parseMaterialDesktopVideoControlsThemeData(value, theme), + child: child, + ); + default: + return child; + } +} + +dynamic _materialVideoControlsThemeValue(dynamic value) { + if (value is! Map) return null; + if (value["_type"] == "material") return value; + if (value["_type"] == "adaptive") return value["material"]; + return null; +} + +dynamic _materialDesktopVideoControlsThemeValue(dynamic value) { + if (value is! Map) return null; + if (value["_type"] == "materialDesktop") return value; + if (value["_type"] == "adaptive") return value["material_desktop"]; + return null; +} + +PlaylistMode? parsePlaylistMode(String? value, [PlaylistMode? defaultValue]) { + return parseEnum(PlaylistMode.values, value, defaultValue); +} diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart new file mode 100644 index 0000000000..03eceb7c45 --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/lib/src/video.dart @@ -0,0 +1,451 @@ +import 'dart:async'; + +import 'package:collection/collection.dart'; +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +import 'utils/video.dart'; + +class VideoControl extends StatefulWidget { + final Control control; + + const VideoControl({super.key, required this.control}); + + @override + State createState() => _VideoControlState(); +} + +class _VideoControlState extends State with FletStoreMixin { + GlobalKey _videoKey = GlobalKey(); + StreamSubscription? _errorSub; + StreamSubscription? _completedSub; + StreamSubscription? _playlistSub; + StreamSubscription? _positionSub; + StreamSubscription? _durationSub; + late Player _player; + late VideoController _controller; + bool _initialized = false; + Future? _openFuture; + + /// Snapshot of the last-known playlist, used to diff against incoming + /// updates so single add/remove changes can be applied without a full reload. + dynamic _playlist; + + /// Deep equality used to compare playlist entries (lists of media maps). + static const _playlistEquality = DeepCollectionEquality(); + + /// Returns a deep copy of [value] so the snapshot is decoupled from the + /// source and won't be mutated by reference. + dynamic _copyPlaylist(dynamic value) { + if (value is List) { + return value.map(_copyPlaylist).toList(); + } + if (value is Map) { + return value.map((key, value) => MapEntry(key, _copyPlaylist(value))); + } + return value; + } + + /// Returns the appended media if [current] differs from [previous] only by + /// a single trailing item, otherwise `null`. + dynamic _appendedPlaylistMedia(List previous, List current) { + if (current.length != previous.length + 1) { + return null; + } + for (var i = 0; i < previous.length; i++) { + if (!_playlistEquality.equals(previous[i], current[i])) { + return null; + } + } + return current.last; + } + + /// Returns the removed index if [current] differs from [previous] only by + /// a single removed item, otherwise `null`. + int? _removedPlaylistIndex(List previous, List current) { + if (previous.length != current.length + 1) { + return null; + } + + int? removedIndex; + var currentIndex = 0; + for (var previousIndex = 0; + previousIndex < previous.length; + previousIndex++) { + if (currentIndex < current.length && + _playlistEquality.equals( + previous[previousIndex], current[currentIndex])) { + currentIndex++; + } else if (removedIndex == null) { + removedIndex = previousIndex; + } else { + return null; + } + } + return removedIndex; + } + + /// Applies an updated [playlist] by issuing a single `add` or `remove` when + /// the diff is a one-item append/removal; otherwise falls back to reopening + /// the player with the full playlist (preserving play state). + Future _updatePlaylist(dynamic playlist) async { + final previousPlaylist = _playlist; + _playlist = _copyPlaylist(playlist); + + if (previousPlaylist is List && playlist is List) { + // add + final addedMedia = _appendedPlaylistMedia(previousPlaylist, playlist); + if (addedMedia != null) { + final media = parseVideoMedia(addedMedia, widget.control.backend); + if (media != null) { + await _player.add(media); + return; + } + } + + // remove + final removedIndex = _removedPlaylistIndex(previousPlaylist, playlist); + if (removedIndex != null) { + await _player.remove(removedIndex); + return; + } + } + + final play = + widget.control.getBool("autoplay", false)! || _player.state.playing; + await _player.open( + Playlist(parseVideoMedias(playlist, widget.control.backend, [])!), + play: play); + } + + Future _applyMpvProperties(Control control) async { + final cfg = control.get("configuration"); + if (cfg is! Map) return; + + final mpvPropsRaw = cfg["mpv_properties"]; + if (mpvPropsRaw is! Map) return; + + final platform = _player.platform; + if (platform is! NativePlayer) return; + final native = platform as dynamic; + + for (final entry in mpvPropsRaw.entries) { + final key = entry.key.toString(); + final val = entry.value; + if (val == null) continue; + final valueStr = val is bool ? (val ? "yes" : "no") : val.toString(); + await native.setProperty(key, valueStr); + } + } + + void _setup(Control control) { + final playerConfig = PlayerConfiguration( + title: control.getString("title", "flet-video")!, + muted: control.getBool("muted", false)!, + pitch: control.getDouble("pitch") != null, + ready: control.hasEventHandler("load") + ? () => control.triggerEvent("load") + : null, + ); + + _player = Player(configuration: playerConfig); + + final videoControllerConfiguration = parseControllerConfiguration( + control.get("configuration"), const VideoControllerConfiguration())!; + _controller = + VideoController(_player, configuration: videoControllerConfiguration); + + _initialized = true; + + control.addInvokeMethodListener(_invokeMethod); + + if (control.hasEventHandler("error")) { + _errorSub = _player.stream.error.listen((message) { + control.triggerEvent("error", message); + }); + } + + if (control.hasEventHandler("complete")) { + _completedSub = _player.stream.completed.listen((completed) { + control.triggerEvent("complete", completed); + }); + } + + if (control.hasEventHandler("track_change")) { + _playlistSub = _player.stream.playlist.listen((playlist) { + control.triggerEvent("track_change", playlist.index); + }); + } + + if (control.hasEventHandler("position_change")) { + _positionSub = _player.stream.position.listen((position) { + control.triggerEvent("position_change", position); + }); + } + + if (control.hasEventHandler("duration_change")) { + _durationSub = _player.stream.duration.listen((duration) { + control.triggerEvent("duration_change", duration); + }); + } + + final playlist = + Playlist(parseVideoMedias(control.get("playlist"), control.backend, [])!); + final autoplay = control.getBool("autoplay", false)!; + _playlist = _copyPlaylist(control.get("playlist")); + + _openFuture = () async { + await _applyMpvProperties(control); + await _player.open(playlist, play: autoplay); + }(); + } + + void _teardown(Control control) { + if (!_initialized) { + return; + } + + control.removeInvokeMethodListener(_invokeMethod); + + _errorSub?.cancel(); + _errorSub = null; + _completedSub?.cancel(); + _completedSub = null; + _playlistSub?.cancel(); + _playlistSub = null; + _positionSub?.cancel(); + _positionSub = null; + _durationSub?.cancel(); + _durationSub = null; + + _player.dispose(); + _openFuture = null; + _initialized = false; + } + + Future _handleEnterFullscreen() async { + widget.control.updateProperties({"_fullscreen": true}, python: false); + if (!widget.control.getBool("fullscreen", false)!) { + widget.control.updateProperties({"fullscreen": true}); + } + widget.control.triggerEvent("enter_fullscreen"); + await defaultEnterNativeFullscreen(); + } + + Future _handleExitFullscreen() async { + widget.control.updateProperties({"_fullscreen": false}, python: false); + if (widget.control.getBool("fullscreen", false)!) { + widget.control.updateProperties({"fullscreen": false}); + } + widget.control.triggerEvent("exit_fullscreen"); + await defaultExitNativeFullscreen(); + } + + @override + void initState() { + super.initState(); + _setup(widget.control); + } + + @override + void didUpdateWidget(covariant VideoControl oldWidget) { + super.didUpdateWidget(oldWidget); + + if (oldWidget.control != widget.control) { + _teardown(oldWidget.control); + _videoKey = GlobalKey(); + _setup(widget.control); + } + } + + @override + void dispose() { + _teardown(widget.control); + super.dispose(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("Video.$name($args)"); + switch (name) { + case "play": + await _player.play(); + break; + case "pause": + await _player.pause(); + break; + case "play_or_pause": + await _player.playOrPause(); + break; + case "stop": + await _player.stop(); + _player.open( + Playlist(parseVideoMedias( + widget.control.get("playlist"), widget.control.backend, [])!), + play: false); + break; + case "seek": + var position = parseDuration(args["position"]); + if (position != null) await _player.seek(position); + break; + case "next": + await _player.next(); + break; + case "previous": + await _player.previous(); + break; + case "jump_to": + final mediaIndex = parseInt(args["media_index"]); + if (mediaIndex != null) await _player.jump(mediaIndex); + break; + case "is_playing": + return _player.state.playing; + case "is_completed": + return _player.state.completed; + case "get_duration": + return _player.state.duration; + case "get_current_position": + return _player.state.position; + case "take_screenshot": + await _openFuture; + if (!_initialized) return null; + final format = + args.containsKey("format") ? args["format"] : "image/png"; + return await _player.screenshot( + format: format, + includeLibassSubtitles: args["include_libass_subtitles"] == true, + ); + default: + throw Exception("Unknown Video method: $name"); + } + } + + @override + Widget build(BuildContext context) { + debugPrint("Video build: ${widget.control.id}"); + + var subtitleConfiguration = parseSubtitleConfiguration( + widget.control.get("subtitle_configuration"), + Theme.of(context), + const SubtitleViewConfiguration())!; + var subtitleTrack = + parseSubtitleTrack(widget.control.get("subtitle_track"), context); + + var volume = widget.control.getDouble("volume"); + var pitch = widget.control.getDouble("pitch"); + var playbackRate = widget.control.getDouble("playback_rate"); + var playlist = widget.control.get("playlist"); + var shufflePlaylist = widget.control.getBool("shuffle_playlist"); + var controls = widget.control.getBool("show_controls", true)! + ? widget.control.get("controls") + : null; + var playlistMode = + parsePlaylistMode(widget.control.getString("playlist_mode")); + var fullscreen = widget.control.getBool("fullscreen", false)!; + + // previous values + final prevVolume = widget.control.getDouble("_volume"); + final prevPitch = widget.control.getDouble("_pitch"); + final prevPlaybackRate = widget.control.getDouble("_playback_rate"); + final prevShufflePlaylist = widget.control.getBool("_shuffle_playlist"); + final PlaylistMode? prevPlaylistMode = widget.control.get("_playlist_mode"); + final SubtitleTrack? prevSubtitleTrack = + widget.control.get("_subtitle_track"); + final prevFullscreen = widget.control.getBool("_fullscreen", false)!; + + Video video = Video( + key: _videoKey, + controller: _controller, + wakelock: widget.control.getBool("wakelock", true)!, + controls: parseVideoControls(controls), + pauseUponEnteringBackgroundMode: + widget.control.getBool("pause_upon_entering_background_mode", true)!, + resumeUponEnteringForegroundMode: widget.control + .getBool("resume_upon_entering_foreground_mode", false)!, + alignment: widget.control.getAlignment("alignment", Alignment.center)!, + fit: widget.control.getBoxFit("fit", BoxFit.contain)!, + filterQuality: + widget.control.getFilterQuality("filter_quality", FilterQuality.low)!, + subtitleViewConfiguration: subtitleConfiguration, + fill: widget.control.getColor("fill_color", context, Colors.black)!, + onEnterFullscreen: _handleEnterFullscreen, + onExitFullscreen: _handleExitFullscreen, + ); + + final themedVideo = + wrapVideoControlsTheme(video, controls, Theme.of(context)); + + () async { + // volume + if (volume != null && + volume != prevVolume && + volume >= 0 && + volume <= 100) { + widget.control.updateProperties({"_volume": volume}, python: false); + await _player.setVolume(volume); + } + + // pitch + if (pitch != null && pitch != prevPitch) { + widget.control.updateProperties({"_pitch": pitch}, python: false); + await _player.setPitch(pitch); + } + + // playbackRate + if (playbackRate != null && playbackRate != prevPlaybackRate) { + widget.control + .updateProperties({"_playback_rate": playbackRate}, python: false); + await _player.setRate(playbackRate); + } + + // playlist + if (!_playlistEquality.equals(playlist, _playlist)) { + await _updatePlaylist(playlist); + } + + // shufflePlaylist + if (shufflePlaylist != null && shufflePlaylist != prevShufflePlaylist) { + widget.control.updateProperties({"_shuffle_playlist": shufflePlaylist}, + python: false); + await _player.setShuffle(shufflePlaylist); + } + + // playlistMode + if (playlistMode != null && playlistMode != prevPlaylistMode) { + widget.control + .updateProperties({"_playlist_mode": playlistMode}, python: false); + await _player.setPlaylistMode(playlistMode); + } + + // subtitleTrack + if (subtitleTrack != null && subtitleTrack != prevSubtitleTrack) { + await _openFuture; + if (!_initialized) return; + widget.control.updateProperties({"_subtitle_track": subtitleTrack}, + python: false); + await _player.setSubtitleTrack(subtitleTrack); + } + + // fullscreen + if (fullscreen != prevFullscreen) { + widget.control + .updateProperties({"_fullscreen": fullscreen}, python: false); + // Defer fullscreen transition until after this frame's build completes. + WidgetsBinding.instance.addPostFrameCallback((_) { + final videoState = _videoKey.currentState; + if (videoState == null) { + return; + } + if (fullscreen) { + videoState.enterFullscreen(); + } else { + videoState.exitFullscreen(); + } + }); + } + }(); + + return LayoutControl(control: widget.control, child: themedVideo); + } +} diff --git a/sdk/python/packages/flet-video/src/flutter/flet_video/pubspec.yaml b/sdk/python/packages/flet-video/src/flutter/flet_video/pubspec.yaml new file mode 100644 index 0000000000..726536baff --- /dev/null +++ b/sdk/python/packages/flet-video/src/flutter/flet_video/pubspec.yaml @@ -0,0 +1,25 @@ +name: flet_video +description: Flet Video control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + + collection: ^1.16.0 + media_kit: 1.2.6 + media_kit_video: 2.0.1 + media_kit_libs_video: 1.0.7 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet-web/README.md b/sdk/python/packages/flet-web/README.md index 938357c108..c6d7eec5f8 100644 --- a/sdk/python/packages/flet-web/README.md +++ b/sdk/python/packages/flet-web/README.md @@ -1,3 +1,6 @@ # Flet Web client in Flutter -This package contains a compiled Flutter Flet web client. \ No newline at end of file +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-web) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-web.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-web.svg) + +This package contains a compiled Flutter Flet web client. diff --git a/sdk/python/packages/flet-web/pyproject.toml b/sdk/python/packages/flet-web/pyproject.toml index 4454573b69..0340024e58 100644 --- a/sdk/python/packages/flet-web/pyproject.toml +++ b/sdk/python/packages/flet-web/pyproject.toml @@ -5,11 +5,11 @@ description = "Flet web client in Flutter." authors = [{ name = "Appveyor Systems Inc.", email = "hello@flet.dev" }] license = "Apache-2.0" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "flet", "fastapi >=0.115.12", - "uvicorn[standard] >=0.34.2" + "uvicorn[standard] >=0.35.0" ] [project.urls] diff --git a/sdk/python/packages/flet-web/src/flet_web/__init__.py b/sdk/python/packages/flet-web/src/flet_web/__init__.py index a47b1b876e..3187280872 100644 --- a/sdk/python/packages/flet-web/src/flet_web/__init__.py +++ b/sdk/python/packages/flet-web/src/flet_web/__init__.py @@ -1,9 +1,28 @@ import os from pathlib import Path -from flet_web.patch_index import patch_index_html, patch_manifest_json +from flet_web.patch_index import ( + patch_font_manifest_json, + patch_index_html, + patch_manifest_json, +) def get_package_web_dir(): + """ + Returns directory containing bundled web runtime assets. + + If `FLET_WEB_PATH` environment variable is set, its value is returned. + Otherwise, the package-local `web` directory is used. + """ + web_root_dir = os.environ.get("FLET_WEB_PATH") return web_root_dir or str(Path(__file__).parent.joinpath("web")) + + +__all__ = [ + "get_package_web_dir", + "patch_font_manifest_json", + "patch_index_html", + "patch_manifest_json", +] diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/README.md b/sdk/python/packages/flet-web/src/flet_web/fastapi/README.md index dd96b54c8f..ffedb3f722 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/README.md +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/README.md @@ -27,8 +27,8 @@ async def main(page: ft.Page): page.floating_action_button = ft.FloatingActionButton( icon=ft.icons.ADD, on_click=add_click ) - await page.add_async( - ft.Container(counter, alignment=ft.alignment.center, expand=True) + page.add( + ft.Container(counter, alignment=ft.Alignment.CENTER, expand=True) ) app = flet_fastapi.app(main) @@ -70,11 +70,11 @@ import flet_fastapi async def root_main(page: ft.Page): - await page.add_async(ft.Text("This is root app!")) + page.add(ft.Text("This is root app!")) async def sub_main(page: ft.Page): - await page.add_async(ft.Text("This is sub app!")) + page.add(ft.Text("This is sub app!")) app = flet_fastapi.FastAPI() @@ -106,7 +106,7 @@ async def lifespan(app: FastAPI): app = FastAPI(lifespan=lifespan) async def main(page: ft.Page): - await page.add_async(ft.Text("Hello, Flet!")) + page.add(ft.Text("Hello, Flet!")) app.mount("/flet-app", flet_fastapi.app(main)) ``` @@ -143,4 +143,4 @@ gunicorn -k uvicorn.workers.UvicornWorker counter:app `FLET_OAUTH_STATE_TIMEOUT` - OAuth state lifetime, in seconds, which is a maximum allowed time between starting OAuth flow and redirecting to OAuth callback URL. Default is 600 seconds. -`FLET_MAX_UPLOAD_SIZE` - max allowed size of an uploaded file, bytes. \ No newline at end of file +`FLET_MAX_UPLOAD_SIZE` - max allowed size of an uploaded file, bytes. diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/__init__.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/__init__.py index 8ad6e239a9..e06e5307d3 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/__init__.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/__init__.py @@ -2,5 +2,16 @@ from flet_web.fastapi.flet_app import FletApp from flet_web.fastapi.flet_app_manager import app_manager from flet_web.fastapi.flet_fastapi import FastAPI +from flet_web.fastapi.flet_oauth import FletOAuth from flet_web.fastapi.flet_static_files import FletStaticFiles from flet_web.fastapi.flet_upload import FletUpload + +__all__ = [ + "FastAPI", + "FletApp", + "FletOAuth", + "FletStaticFiles", + "FletUpload", + "app", + "app_manager", +] diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/app.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/app.py index 6cade3f3b7..459ea5a041 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/app.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/app.py @@ -1,15 +1,17 @@ import asyncio import os -from typing import Awaitable, Callable, Optional, Union +from typing import Optional from fastapi import Request, WebSocket -from flet.core.page import Page -from flet.core.types import WebRenderer +from starlette.middleware.base import BaseHTTPMiddleware +from flet.app import AppCallable +from flet.controls.types import RouteUrlStrategy, WebRenderer from flet_web.fastapi.flet_app import ( DEFAULT_FLET_OAUTH_STATE_TIMEOUT, DEFAULT_FLET_SESSION_TIMEOUT, FletApp, + app_manager, ) from flet_web.fastapi.flet_fastapi import FastAPI from flet_web.fastapi.flet_oauth import FletOAuth @@ -18,15 +20,16 @@ def app( - session_handler: Union[Callable[[Page], Awaitable], Callable[[Page], None]], + main: AppCallable, + before_main: Optional[AppCallable] = None, proxy_path: Optional[str] = None, assets_dir: Optional[str] = None, app_name: Optional[str] = None, app_short_name: Optional[str] = None, app_description: Optional[str] = None, - web_renderer: WebRenderer = WebRenderer.CANVAS_KIT, - use_color_emoji: bool = False, - route_url_strategy: str = "path", + web_renderer: WebRenderer = WebRenderer.AUTO, + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: bool = False, upload_dir: Optional[str] = None, upload_endpoint_path: Optional[str] = None, max_upload_size: Optional[int] = None, @@ -37,21 +40,28 @@ def app( """ Mount all Flet FastAPI handlers in one call. - Parameters: - * `session_handler` (function or coroutine) - application entry point - a method called for newly connected user. Handler must have 1 parameter: `page` - `Page` instance. - * `assets_dir` (str, optional) - an absolute path to app's assets directory. - * `app_name` (str, optional) - PWA application name. - * `app_short_name` (str, optional) - PWA application short name. - * `app_description` (str, optional) - PWA application description. - * `web_renderer` (WebRenderer) - web renderer defaulting to `WebRenderer.CANVAS_KIT`. - * `use_color_emoji` (bool) - whether to load a font with color emoji. Default is `False`. - * `route_url_strategy` (str) - routing URL strategy: `path` (default) or `hash`. - * `upload_dir` (str) - an absolute path to a directory with uploaded files. - * `upload_endpoint_path` (str, optional) - absolute URL of upload endpoint, e.g. `/upload`. - * `max_upload_size` (str, int) - maximum size of a single upload, bytes. Unlimited if `None`. - * `secret_key` (str, optional) - secret key to sign and verify upload requests. - * `session_timeout_seconds` (int, optional)- session lifetime, in seconds, after user disconnected. - * `oauth_state_timeout_seconds` (int, optional) - OAuth state lifetime, in seconds, which is a maximum allowed time between starting OAuth flow and redirecting to OAuth callback URL. + Args: + main: Application entry point. It is called for newly connected users. + Handler (function or coroutine) must have 1 parameter of + instance :class:`~flet.Page`. + before_main: Called after `Page` was created, but before calling `main`. + proxy_path: URL prefix when the app is mounted under a proxy. + assets_dir: an absolute path to app's assets directory. + app_name: PWA application name. + app_short_name: PWA application short name. + app_description: PWA application description. + web_renderer: web renderer defaulting to `WebRenderer.AUTO`. + route_url_strategy: routing URL strategy: `path` (default) or `hash`. + no_cdn: do not load resources from CDN. + upload_dir: an absolute path to a directory with uploaded files. + upload_endpoint_path: absolute URL of upload endpoint, e.g. `/upload`. + max_upload_size: maximum size of a single upload, bytes. Unlimited if `None`. + secret_key: secret key to sign and verify upload requests. + session_timeout_seconds: session lifetime, in seconds, + after the user disconnected. + oauth_state_timeout_seconds: OAuth state lifetime, in seconds, + which is the maximum allowed time between starting OAuth flow and + redirecting to OAuth callback URL. """ env_upload_dir = os.getenv("FLET_UPLOAD_DIR") @@ -79,9 +89,17 @@ def app( @fastapi_app.websocket(f"/{websocket_endpoint}") async def app_handler(websocket: WebSocket): + """ + Handles Flet WebSocket session lifecycle for one client connection. + + The handler creates a new `FletApp` + instance and delegates message send/receive processing to it. + """ await FletApp( - asyncio.get_running_loop(), - session_handler, + loop=asyncio.get_running_loop(), + executor=app_manager.executor, + main=main, + before_main=before_main, session_timeout_seconds=session_timeout_seconds, oauth_state_timeout_seconds=oauth_state_timeout_seconds, upload_endpoint_path=upload_endpoint_path, @@ -94,6 +112,9 @@ async def app_handler(websocket: WebSocket): f"/{upload_endpoint_path if upload_endpoint_path else upload_endpoint}" ) async def upload_handler(request: Request): + """ + Handles signed file uploads routed through the Flet upload endpoint. + """ await FletUpload( upload_dir=upload_dir, max_upload_size=max_upload_size, @@ -102,6 +123,9 @@ async def upload_handler(request: Request): @fastapi_app.get(f"/{oauth_callback_endpoint}") async def oauth_redirect_handler(request: Request): + """ + Handles OAuth provider callback redirect and returns auth response. + """ return await FletOAuth().handle(request) fastapi_app.mount( @@ -113,9 +137,31 @@ async def oauth_redirect_handler(request: Request): app_short_name=app_short_name, app_description=app_description, web_renderer=web_renderer, - use_color_emoji=use_color_emoji, route_url_strategy=route_url_strategy, + websocket_endpoint_path=websocket_endpoint, + no_cdn=no_cdn, ), ) + # Add middleware for custom headers + class CustomHeadersMiddleware(BaseHTTPMiddleware): + """ + Injects security/CORS headers required by browser-side Flet runtime. + """ + + async def dispatch(self, request: Request, call_next): + """ + Adds fixed response headers for isolation and cross-origin access. + + Returns: + The downstream response with added headers. + """ + response = await call_next(request) + response.headers["Cross-Origin-Opener-Policy"] = "same-origin" + response.headers["Cross-Origin-Embedder-Policy"] = "require-corp" + response.headers["Access-Control-Allow-Origin"] = "*" + return response + + fastapi_app.add_middleware(CustomHeadersMiddleware) + return fastapi_app diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py index 75828974ef..58f0655974 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app.py @@ -1,67 +1,89 @@ import asyncio -import copy -import json +import inspect import logging import os import traceback +import weakref +from concurrent.futures import ThreadPoolExecutor from datetime import datetime, timedelta, timezone -from typing import Any, Dict, List, Optional +from typing import Any, Optional -import flet_web.fastapi as flet_fastapi +import msgpack from fastapi import WebSocket, WebSocketDisconnect -from flet.core.event import Event -from flet.core.local_connection import LocalConnection -from flet.core.page import Page, PageDisconnectedException -from flet.core.protocol import ( - ClientActions, + +import flet_web.fastapi as flet_fastapi +from flet.app import AppCallable +from flet.controls.base_control import BaseControl +from flet.controls.context import _context_page, context +from flet.controls.exceptions import FletPageDisconnectedException +from flet.messaging.connection import Connection +from flet.messaging.protocol import ( + ClientAction, ClientMessage, - Command, - CommandEncoder, - PageCommandResponsePayload, - PageCommandsBatchResponsePayload, - RegisterWebClientRequestPayload, + ControlEventBody, + InvokeMethodResponseBody, + RegisterClientRequestBody, + RegisterClientResponseBody, + UpdateControlPropsBody, + configure_encode_object_for_msgpack, + decode_ext_from_msgpack, ) +from flet.messaging.session import Session from flet.utils import random_string, sha1 from flet_web.fastapi.flet_app_manager import app_manager from flet_web.fastapi.oauth_state import OAuthState from flet_web.uploads import build_upload_url logger = logging.getLogger(flet_fastapi.__name__) +transport_log = logging.getLogger("flet_transport") DEFAULT_FLET_SESSION_TIMEOUT = 3600 DEFAULT_FLET_OAUTH_STATE_TIMEOUT = 600 -class FletApp(LocalConnection): +class FletApp(Connection): + """ + Handle Flet app WebSocket connections. + + Args: + loop: `asyncio` event loop (`asyncio.get_running_loop()`). + executor: Thread pool executor (`app_manager.executor`). + main: Application entry point - an async method called for newly + connected user. Handler coroutine must have + 1 parameter of instance `Page`. + before_main: Called before `main`. + session_timeout_seconds: Session lifetime, in seconds, + after user disconnected. + oauth_state_timeout_seconds: OAuth state lifetime, in seconds, which + is a maximum allowed time between starting OAuth flow + and redirecting to OAuth callback URL. + upload_endpoint_path: Absolute URL of upload endpoint, e.g. `/upload`. + secret_key: Secret key to sign upload requests. + """ + def __init__( self, loop: asyncio.AbstractEventLoop, - session_handler, + executor: ThreadPoolExecutor, + main: AppCallable, + before_main: Optional[AppCallable], session_timeout_seconds: int = DEFAULT_FLET_SESSION_TIMEOUT, oauth_state_timeout_seconds: int = DEFAULT_FLET_OAUTH_STATE_TIMEOUT, upload_endpoint_path: Optional[str] = None, secret_key: Optional[str] = None, ): - """ - Handle Flet app WebSocket connections. - - Parameters: - - * `session_handler` (Coroutine) - application entry point - an async method called for newly connected user. Handler coroutine must have 1 parameter: `page` - `Page` instance. - * `session_timeout_seconds` (int, optional) - session lifetime, in seconds, after user disconnected. - * `oauth_state_timeout_seconds` (int, optional) - OAuth state lifetime, in seconds, which is a maximum allowed time between starting OAuth flow and redirecting to OAuth callback URL. - * `upload_endpoint_path` (str, optional) - absolute URL of upload endpoint, e.g. `/upload`. - * `secret_key` (str, optional) - secret key to sign upload requests. - """ super().__init__() self.__id = random_string(8) logger.info(f"New FletApp: {self.__id}") - self.__page = None - self.__loop = loop - self.__session_handler = session_handler + self.__session = None + self.loop = loop + self.executor = executor + self.__main = main + self.__before_main = before_main self.__session_timeout_seconds = session_timeout_seconds self.__oauth_state_timeout_seconds = oauth_state_timeout_seconds + self.__running_tasks = set() env_session_timeout_seconds = os.getenv("FLET_SESSION_TIMEOUT") if env_session_timeout_seconds: @@ -74,28 +96,27 @@ def __init__( self.__upload_endpoint_path = upload_endpoint_path self.__secret_key = secret_key + app_id = self.__id + weakref.finalize( + self, lambda: logger.info(f"FletApp was garbage collected: {app_id}") + ) + async def handle(self, websocket: WebSocket): """ Handle WebSocket connection. - Parameters: - - * `websocket` (WebSocket) - Websocket instance. + Args: + websocket: WebSocket instance. """ self.__websocket = websocket - self.client_ip = ( + self.__client_ip = ( self.__websocket.client.host if self.__websocket.client else "" - ).split(":")[0] - self.client_user_agent = ( - self.__websocket.headers["user-agent"] - if "user-agent" in self.__websocket.headers - else "" ) + self.__client_user_agent = self.__websocket.headers.get("user-agent", "") + self.__oauth_state_id = self.__websocket.cookies.get("flet_oauth_state") - self.pubsubhub = app_manager.get_pubsubhub( - self.__session_handler, loop=self.__loop - ) + self.pubsubhub = app_manager.get_pubsubhub(self.__main, loop=self.loop) self.page_url = str(websocket.url).rsplit("/", 1)[0] self.page_name = websocket.url.path.rsplit("/", 1)[0].lstrip("/") @@ -106,325 +127,333 @@ async def handle(self, websocket: WebSocket): await self.__websocket.accept() self.__send_queue = asyncio.Queue() - st = asyncio.create_task(self.__send_loop()) + send_loop_task = asyncio.create_task(self.__send_loop()) await self.__receive_loop() - st.cancel() + await send_loop_task - async def __on_event(self, e): - session = await app_manager.get_session( - self.__get_unique_session_id(e.sessionID) + # disconnect this connection from a session + await app_manager.disconnect_session( + self.__get_unique_session_id(self.__session.id), + self.__session_timeout_seconds, ) - if session is not None: - try: - await session.on_event_async( - Event(e.eventTarget, e.eventName, e.eventData) - ) - except PageDisconnectedException: - logger.debug( - f"Event handler attempted to update disconnected page: {e.sessionID}" - ) - if e.eventTarget == "page" and e.eventName == "close": - logger.info(f"Session closed: {e.sessionID}") - await app_manager.delete_session( - self.__get_unique_session_id(e.sessionID) - ) - async def __on_session_created(self, session_data): - logger.info(f"Start session: {session_data.sessionID}") - session_id = session_data.sessionID + async def __on_session_created(self): + """ + Run app entry handler for a newly created session. + + Initializes page context, executes `main` in supported callable forms + (coroutine, generator, async generator, sync function), and performs + post-event updates. + """ + + assert self.__session + logger.info(f"Start session: {self.__session.id}") try: - assert self.__session_handler is not None - if asyncio.iscoroutinefunction(self.__session_handler): - await self.__session_handler(self.__page) + assert self.__main is not None + _context_page.set(self.__session.page) + context.reset_auto_update() + + if inspect.iscoroutinefunction(self.__main): + await self.__main(self.__session.page) + + elif inspect.isasyncgenfunction(self.__main): + async for _ in self.__main(self.__session.page): + await self.__session.after_event(self.__session.page) + + elif inspect.isgeneratorfunction(self.__main): + for _ in self.__main(self.__session.page): + await self.__session.after_event(self.__session.page) else: - # run in thread pool - await asyncio.get_running_loop().run_in_executor( - app_manager.executor, self.__session_handler, self.__page - ) - except PageDisconnectedException: + self.__main(self.__session.page) + + await self.__session.after_event(self.__session.page) + except FletPageDisconnectedException: logger.debug( - f"Session handler attempted to update disconnected page: {session_id}" + "Session handler attempted to update disconnected page: " + f"{self.__session.id}" ) except BrokenPipeError: - logger.info(f"Session handler terminated: {session_id}") + logger.info( + "Session handler terminated: " + f"{self.__session.id if self.__session else ''}" + ) except Exception as e: - print( - f"Unhandled error processing page session {session_id}:", - traceback.format_exc(), + logger.error( + "Unhandled error processing page session: " + f"{self.__session.id if self.__session else ''}", + exc_info=True, ) - assert self.__page - self.__page.error(f"There was an error while processing your request: {e}") + if self.__session: + self.__session.error(str(e)) async def __send_loop(self): + """ + Drain outbound message queue and forward packed frames to WebSocket. + + The loop stops when `None` sentinel is received, then clears transport + references. + """ + assert self.__websocket assert self.__send_queue while True: message = await self.__send_queue.get() + if message is None: + break + try: - await self.__websocket.send_text(message) + await self.__websocket.send_bytes(message) except Exception: # re-enqueue the message to repeat it when re-connected - self.__send_queue.put_nowait(message) + # self.__send_queue.put_nowait(message) raise + self.__websocket = None + self.__send_queue = None async def __receive_loop(self): + """ + Receive binary frames from WebSocket and dispatch decoded client messages. + + On disconnect/error, terminates send loop via queue sentinel when a + session is active. + """ + assert self.__websocket try: while True: - await self.__on_message(await self.__websocket.receive_text()) + data = await self.__websocket.receive_bytes() + await self.__on_message( + msgpack.unpackb(data, ext_hook=decode_ext_from_msgpack) + ) except Exception as e: if not isinstance(e, WebSocketDisconnect): - logger.warning(f"Receive loop error: {e}") - if self.__page: - await app_manager.disconnect_session( - self.__get_unique_session_id(self.__page.session_id), - self.__session_timeout_seconds, - ) - self.__websocket = None - self.__send_queue = None + logger.warning(f"Receive loop error: {e}", exc_info=True) + if self.__session: + # terminate __send_loop + await self.__send_queue.put(None) - async def __on_message(self, data: str): - logger.debug(f"_on_message: {data}") - msg_dict = json.loads(data) - msg = ClientMessage(**msg_dict) - if msg.action == ClientActions.REGISTER_WEB_CLIENT: - self._client_details = RegisterWebClientRequestPayload(**msg.payload) - - new_session = True - if ( - not self._client_details.sessionId - or await app_manager.get_session( - self.__get_unique_session_id(self._client_details.sessionId) - ) - is None - ): - # generate session ID - self._client_details.sessionId = random_string(16) - - # create new Page object - self.__page = Page( - self, - self._client_details.sessionId, - executor=app_manager.executor, - loop=asyncio.get_running_loop(), + async def __on_message(self, data: Any): + """ + Handle one decoded client message and dispatch + by `ClientAction`. + + Args: + data: Decoded message payload from msgpack transport. + + Raises: + RuntimeError: If message action is unknown. + """ + + action = ClientAction(data[0]) + body = data[1] + transport_log.debug(f"_on_message: {action} {body}") + task = None + if action == ClientAction.REGISTER_CLIENT: + req = RegisterClientRequestBody(**body) + + new_session = False + + # try to retrieve existing session + if req.session_id: + self.__session = await app_manager.get_session( + self.__get_unique_session_id(req.session_id) ) + oauth_state = None + if self.__oauth_state_id: + oauth_state = app_manager.retrieve_state(self.__oauth_state_id) + if oauth_state: + self.__session = await app_manager.get_session( + oauth_state.session_id + ) + + # re-create session + if self.__session is None: + new_session = True + + # create new session + self.__session = Session(self) + # register session await app_manager.add_session( - self.__get_unique_session_id(self._client_details.sessionId), - self.__page, - ) - else: - # existing session - logger.info( - f"Existing session requested: {self._client_details.sessionId}" + self.__get_unique_session_id(self.__session.id), + self.__session, ) - self.__page = await app_manager.get_session( - self.__get_unique_session_id(self._client_details.sessionId) + + _context_page.set(self.__session.page) + + original_route = self.__session.page.route + + # apply page patch + self.__session.apply_page_patch(req.page) + + register_error = "" + if new_session: + # update IP and user-agent + self.__session.page.client_ip = self.__client_ip + self.__session.page.client_user_agent = self.__client_user_agent + + # run before_main + try: + if inspect.iscoroutinefunction(self.__before_main): + await self.__before_main(self.__session.page) + elif callable(self.__before_main): + self.__before_main(self.__session.page) + except Exception as e: + register_error = f"{e}\n{traceback.format_exc()}" + logger.error( + "Unhandled error in before_main() handler", exc_info=True + ) + + # register response + self.send_message( + ClientMessage( + ClientAction.REGISTER_CLIENT, + RegisterClientResponseBody( + session_id=self.__session.id, + page_patch=self.__session.get_page_patch() + if new_session + else self.__session.page, + error=register_error, + ), ) - new_session = False - - # update page props - assert self.__page - original_route = self.__page.route - self.__page._set_attr("route", self._client_details.pageRoute, False) - self.__page._set_attr("pwa", self._client_details.isPWA, False) - self.__page._set_attr("web", self._client_details.isWeb, False) - self.__page._set_attr("debug", self._client_details.isDebug, False) - self.__page._set_attr("platform", self._client_details.platform, False) - self.__page._set_attr( - "platformBrightness", self._client_details.platformBrightness, False - ) - self.__page._set_attr("media", self._client_details.media, False) - self.__page._set_attr("width", self._client_details.pageWidth, False) - self.__page._set_attr("height", self._client_details.pageHeight, False) - self.__page._set_attr( - "windowWidth", self._client_details.windowWidth, False - ) - self.__page._set_attr( - "windowHeight", self._client_details.windowHeight, False - ) - self.__page._set_attr("windowTop", self._client_details.windowTop, False) - self.__page._set_attr("windowLeft", self._client_details.windowLeft, False) - self.__page._set_attr("clientIP", self.client_ip, False) - self.__page._set_attr("clientUserAgent", self.client_user_agent, False) - - p = self.__page.snapshot.get("page") - if not p: - p = { - "i": "page", - "t": "page", - "p": "", - "c": [], - } - self.__page.snapshot["page"] = p - self.__page.copy_attrs(p) - - # send register response - self.__send( - self._create_register_web_client_response(controls=self.__page.snapshot) ) + if register_error: + self.__session.error(register_error) + return + # start session if new_session: - asyncio.create_task( - self.__on_session_created(self._create_session_handler_arg()) - ) + asyncio.create_task(self.__on_session_created()) else: await app_manager.reconnect_session( - self.__get_unique_session_id(self._client_details.sessionId), self + self.__get_unique_session_id(self.__session.id), self ) - if original_route != self.__page.route: - self.__page.go(self.__page.route) + if ( + self.__session.page.route + and self.__session.page.route != original_route + ): + asyncio.create_task( + self.__session.page._trigger_event( + "route_change", {"route": self.__session.page.route} + ) + ) + + if oauth_state: + await self.__session.page._authorize_callback( + { + "state": self.__oauth_state_id, + "code": oauth_state.code, + "error": oauth_state.error, + "error_description": oauth_state.error_description, + } + ) + + elif action == ClientAction.CONTROL_EVENT: + req = ControlEventBody(**body) + task = asyncio.create_task( + self.__session.dispatch_event(req.target, req.name, req.data) + ) - elif msg.action == ClientActions.PAGE_EVENT_FROM_WEB: - if self.__on_event is not None: - asyncio.create_task( - self.__on_event(self._create_page_event_handler_arg(msg)) - ) + elif action == ClientAction.UPDATE_CONTROL_PROPS: + req = UpdateControlPropsBody(**body) + self.__session.apply_patch(req.id, req.props) + + elif action == ClientAction.INVOKE_METHOD: + req = InvokeMethodResponseBody(**body) + self.__session.handle_invoke_method_results( + req.control_id, req.call_id, req.result, req.error + ) - elif msg.action == ClientActions.UPDATE_CONTROL_PROPS: - if self.__on_event is not None: - asyncio.create_task( - self.__on_event(self._create_update_control_props_handler_arg(msg)) - ) else: # it's something else - raise Exception(f'Unknown message "{msg.action}": {msg.payload}') - - def _process_get_upload_url_command(self, attrs): - assert len(attrs) == 2, '"getUploadUrl" command has wrong number of attrs' - assert ( - self.__upload_endpoint_path - ), "upload_path should be specified to enable uploads" - return ( - build_upload_url( - self.__upload_endpoint_path, - attrs["file"], - int(attrs["expires"]), - self.__secret_key, - ), - None, + raise RuntimeError(f'Unknown message "{action}": {body}') + + if task: + self.__running_tasks.add(task) + task.add_done_callback(self.__running_tasks.discard) + + def send_message(self, message: ClientMessage): + """ + Serialize and enqueue a server message for transport to the client. + + Args: + message: Outbound protocol message. + """ + + transport_log.debug(f"send_message: {message}") + m = msgpack.packb( + [message.action, message.body], + default=configure_encode_object_for_msgpack(BaseControl), ) + self.__send_queue.put_nowait(m) + + def get_upload_url(self, file_name: str, expires: int) -> str: + """ + Build signed upload URL for a file. + + Args: + file_name: File name to be uploaded. + expires: URL lifetime in seconds. + + Returns: + Signed relative upload URL. + + Raises: + RuntimeError: If upload endpoint is not configured. + """ + + if not self.__upload_endpoint_path: + raise RuntimeError("upload_path should be specified to enable uploads") + return build_upload_url( + self.__upload_endpoint_path, + file_name, + expires, + self.__secret_key, + ) + + def oauth_authorize(self, attrs: dict[str, Any]): + """ + Persist OAuth state metadata for a pending authorization flow. + + Args: + attrs: OAuth attributes payload containing `state` and optional + completion page data. + """ - def __process_oauth_authorize_command(self, attrs: Dict[str, Any]): state_id = attrs["state"] state = OAuthState( - session_id=self.__get_unique_session_id(self._client_details.sessionId), + session_id=self.__get_unique_session_id(self.__session.id), expires_at=datetime.now(timezone.utc) + timedelta(seconds=self.__oauth_state_timeout_seconds), - complete_page_html=attrs.get("completePageHtml", None), - complete_page_url=attrs.get("completePageUrl", None), + complete_page_html=attrs.get("completePageHtml"), + complete_page_url=attrs.get("completePageUrl"), ) app_manager.store_state(state_id, state) - return ( - "", - None, - ) - def _process_add_command(self, command: Command): - assert self.__page - result, message = super()._process_add_command(command) - if message: - for oc in message.payload.controls: - control = copy.deepcopy(oc) - id = control["i"] - pid = control["p"] - parent = self.__page.snapshot[pid] - assert parent, f"parent control not found: {pid}" - if id not in parent["c"]: - if "at" in control: - parent["c"].insert(int(control["at"]), id) - else: - parent["c"].append(id) - self.__page.snapshot[id] = control - return result, message - - def _process_set_command(self, values, attrs): - assert self.__page - result, message = super()._process_set_command(values, attrs) - control = self.__page.snapshot.get(values[0]) - if control: - for k, v in attrs.items(): - control[k] = v - return result, message - - def _process_remove_command(self, values): - assert self.__page - result, message = super()._process_remove_command(values) - for id in values: - control = self.__page.snapshot.get(id) - assert ( - control is not None - ), f"_process_remove_command: control with ID '{id}' not found." - for cid in self.__get_all_descendant_ids(id): - self.__page.snapshot.pop(cid, None) - # delete control itself - self.__page.snapshot.pop(id, None) - # remove id from parent - parent = self.__page.snapshot.get(control["p"]) - if parent: - parent["c"].remove(id) - return result, message - - def _process_clean_command(self, values): - assert self.__page - result, message = super()._process_clean_command(values) - for id in values: - for cid in self.__get_all_descendant_ids(id): - self.__page.snapshot.pop(cid, None) - return result, message - - def __get_all_descendant_ids(self, id): - assert self.__page - ids = [] - control = self.__page.snapshot.get(id) - if control: - for cid in control["c"]: - ids.append(cid) - ids.extend(self.__get_all_descendant_ids(cid)) - return ids - - def send_command(self, session_id: str, command: Command): - if command.name == "oauthAuthorize": - result, message = self.__process_oauth_authorize_command(command.attrs) - else: - result, message = self._process_command(command) - if message: - self.__send(message) - return PageCommandResponsePayload(result=result, error="") - - def send_commands(self, session_id: str, commands: List[Command]): - results = [] - messages = [] - for command in commands: - if command.name == "oauthAuthorize": - result, message = self.__process_oauth_authorize_command(command.attrs) - else: - result, message = self._process_command(command) - if command.name in ["add", "get"]: - results.append(result) - if message: - messages.append(message) - if len(messages) > 0: - self.__send(ClientMessage(ClientActions.PAGE_CONTROLS_BATCH, messages)) - return PageCommandsBatchResponsePayload(results=results, error="") - - def __send(self, message: ClientMessage): - m = json.dumps(message, cls=CommandEncoder, separators=(",", ":")) - logger.debug(f"__send: {m}") - if self.__send_queue: - self.__loop.call_soon_threadsafe(self.__send_queue.put_nowait, m) - - def _get_next_control_id(self): - assert self.__page - return self.__page.get_next_control_id() - - def __get_unique_session_id(self, session_id: str): - client_hash = sha1(f"{self.client_ip}{self.client_user_agent}") + def __get_unique_session_id(self, session_id: str) -> str: + """ + Compose a stable unique session key scoped to page and client identity. + + Args: + session_id: Session identifier generated for current client. + + Returns: + Unique session key combining page name, session ID, and client hash. + """ + + ip = self.__client_ip + if ip in ["127.0.0.1", "::1"]: + ip = "" + client_hash = sha1(f"{ip}{self.__client_user_agent}") return f"{self.page_name}_{session_id}_{client_hash}" def dispose(self): + """ + Release app-level session reference during teardown. + """ + logger.info(f"Disposing FletApp: {self.__id}") - self.__page = None + self.__session = None diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app_manager.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app_manager.py index f08b6bf6f9..bf6107a87f 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app_manager.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_app_manager.py @@ -1,19 +1,15 @@ import asyncio import logging import shutil -import threading import traceback from concurrent.futures import ThreadPoolExecutor from datetime import datetime, timezone from typing import Optional -from flet.core.connection import Connection -from flet.core.locks import NopeLock -from flet.core.page import Page -from flet.core.pubsub.pubsub_hub import PubSubHub -from flet.utils import is_pyodide - import flet_web.fastapi as flet_fastapi +from flet.messaging.connection import Connection +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub from flet_web.fastapi.oauth_state import OAuthState logger = logging.getLogger(flet_fastapi.__name__) @@ -25,37 +21,49 @@ class FletAppManager: """ def __init__(self): - self.__sessions_lock = asyncio.Lock() - self.__sessions: dict[str, Page] = {} + self.__sessions: dict[str, Session] = {} self.__evict_sessions_task = None self.__states: dict[str, OAuthState] = {} - self.__states_lock = threading.Lock() if not is_pyodide() else NopeLock() self.__evict_oauth_states_task = None self.__temp_dirs = {} self.__executor = ThreadPoolExecutor(thread_name_prefix="flet_fastapi") - self.__pubsubhubs_lock = threading.Lock() if not is_pyodide() else NopeLock() self.__pubsubhubs = {} @property def executor(self): + """ + Thread pool executor shared by app sessions and pub/sub hubs. + """ + return self.__executor def get_pubsubhub( self, session_handler, loop: Optional[asyncio.AbstractEventLoop] = None ): - with self.__pubsubhubs_lock: - psh = self.__pubsubhubs.get(session_handler, None) - if psh is None: - psh = PubSubHub( - loop=loop or asyncio.get_running_loop(), - executor=self.__executor, - ) - self.__pubsubhubs[session_handler] = psh - return psh + """ + Get or create pub/sub hub associated with a session handler. + + Args: + session_handler: Session entry handler used as cache key. + loop: Event loop for new hub creation. + + Returns: + Existing or newly created :class:`~flet.pubsub.PubSubHub`. + """ + + psh = self.__pubsubhubs.get(session_handler, None) + if psh is None: + psh = PubSubHub( + loop=loop or asyncio.get_running_loop(), + executor=self.__executor, + ) + self.__pubsubhubs[session_handler] = psh + return psh async def start(self): """ - Background task evicting expired app data. Must be called at FastAPI application startup. + Background task evicting expired app data. Must be called at FastAPI + application startup. """ if not self.__evict_sessions_task: logger.info("Starting up Flet App Manager") @@ -77,89 +85,176 @@ async def shutdown(self): if self.__evict_oauth_states_task: self.__evict_oauth_states_task.cancel() - async def get_session(self, session_id: str) -> Optional[Page]: - async with self.__sessions_lock: - return self.__sessions.get(session_id) + async def get_session(self, session_id: str) -> Optional[Session]: + """ + Retrieve session by unique session ID. - async def add_session(self, session_id: str, conn: Page): - async with self.__sessions_lock: - self.__sessions[session_id] = conn - logger.info( - f"New session created ({len(self.__sessions)} total): {session_id}" - ) + Args: + session_id: Unique session key. + + Returns: + Session instance or `None` if not found. + """ + + return self.__sessions.get(session_id) + + async def add_session(self, session_id: str, session: Session): + """ + Register a new active session. + + Args: + session_id: Unique session key. + session: Session instance to register. + """ + + self.__sessions[session_id] = session + logger.info(f"New session created ({len(self.__sessions)} total): {session_id}") async def reconnect_session(self, session_id: str, conn: Connection): + """ + Reconnect transport to an existing session. + + Args: + session_id: Unique session key. + conn: New active transport connection. + + Raises: + RuntimeError: If session is expired or not found. + """ + logger.info(f"Session reconnected: {session_id}") - async with self.__sessions_lock: - if session_id in self.__sessions: - page = self.__sessions[session_id] - old_conn = page.connection - await page._connect(conn) - if old_conn: - old_conn.dispose() + if session_id in self.__sessions: + session = self.__sessions[session_id] + session.attach_connection(conn) + + # Run connect event handlers asynchronously so websocket receive loop + # isn't blocked by user handlers (e.g., on_connect invoking _invoke_method). + + async def _connect(): + try: + await session.dispatch_connect_event() + except Exception as e: + logger.error( + f"Unhandled error reconnecting session {session_id}: {e}", + exc_info=True, + ) + try: + session.error(str(e)) + except Exception: + logger.error( + "Failed to report reconnect error to session", + exc_info=True, + ) + + asyncio.create_task(_connect()) + else: + raise RuntimeError(f"Session has expired or not found: {session_id}") async def disconnect_session(self, session_id: str, session_timeout_seconds: int): + """ + Mark session disconnected and set expiration timeout. + + Args: + session_id: Unique session key. + session_timeout_seconds: Retention period before eviction. + """ + logger.info(f"Session disconnected: {session_id}") - async with self.__sessions_lock: - if session_id in self.__sessions: - await self.__sessions[session_id]._disconnect(session_timeout_seconds) + if session_id in self.__sessions: + await self.__sessions[session_id].disconnect(session_timeout_seconds) async def delete_session(self, session_id: str): - async with self.__sessions_lock: - page = self.__sessions.pop(session_id, None) - total = len(self.__sessions) - if page is not None: + """ + Remove session from registry and close it if present. + + Args: + session_id: Unique session key. + """ + + session = self.__sessions.pop(session_id, None) + total = len(self.__sessions) + if session is not None: logger.info(f"Delete session ({total} left): {session_id}") try: - old_conn = page.connection - page._close() - if old_conn: - old_conn.dispose() + session.close() except Exception as e: logger.error( f"Error deleting expired session: {e} {traceback.format_exc()}" ) def store_state(self, state_id: str, state: OAuthState): + """ + Store OAuth state payload by state ID. + + Args: + state_id: OAuth state identifier. + state: OAuth state payload. + """ + logger.info(f"Store oauth state: {state_id}") - with self.__states_lock: - self.__states[state_id] = state + self.__states[state_id] = state def retrieve_state(self, state_id: str) -> Optional[OAuthState]: - with self.__states_lock: - return self.__states.pop(state_id, None) + """ + Retrieve and remove OAuth state payload. + + Args: + state_id: OAuth state identifier. + + Returns: + Stored OAuth state, or `None` if missing. + """ + + return self.__states.pop(state_id, None) def add_temp_dir(self, temp_dir: str): + """ + Register temporary directory for cleanup on shutdown. + + Args: + temp_dir: Path to temporary directory. + """ + self.__temp_dirs[temp_dir] = True async def __evict_expired_sessions(self): + """ + Periodically evict expired disconnected sessions. + """ + while True: await asyncio.sleep(10) session_ids = [] - async with self.__sessions_lock: - for session_id, page in self.__sessions.items(): - if page.expires_at and datetime.now(timezone.utc) > page.expires_at: - session_ids.append(session_id) + for session_id, session in self.__sessions.items(): + if ( + session.expires_at + and datetime.now(timezone.utc) > session.expires_at + ): + session_ids.append(session_id) for session_id in session_ids: await self.delete_session(session_id) async def __evict_expired_oauth_states(self): + """ + Periodically evict expired OAuth authorization states. + """ + while True: await asyncio.sleep(10) - with self.__states_lock: - ids = [] - for id, state in self.__states.items(): - if ( - state.expires_at - and datetime.now(timezone.utc) > state.expires_at - ): - ids.append(id) + ids = [] + for id, state in self.__states.items(): + if state.expires_at and datetime.now(timezone.utc) > state.expires_at: + ids.append(id) for id in ids: logger.info(f"Delete expired oauth state: {id}") self.retrieve_state(id) def delete_temp_dirs(self): - for temp_dir in self.__temp_dirs.keys(): + """ + Delete all registered temporary directories. + """ + + for temp_dir in self.__temp_dirs: logger.info(f"Deleting temp dir: {temp_dir}") shutil.rmtree(temp_dir, ignore_errors=True) diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_fastapi.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_fastapi.py index 497a13327e..cc8052c8c8 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_fastapi.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_fastapi.py @@ -1,20 +1,10 @@ import asyncio -from contextlib import asynccontextmanager -from typing import ( - Any, - Awaitable, - Callable, - Coroutine, - Dict, - List, - Optional, - Sequence, - Type, - Union, -) +import inspect +from collections.abc import Awaitable, Coroutine, Sequence +from contextlib import asynccontextmanager, suppress +from typing import Any, Callable, Optional, Union import fastapi -import flet_web.fastapi from fastapi.datastructures import Default from fastapi.params import Depends from fastapi.utils import generate_unique_id @@ -23,67 +13,102 @@ from starlette.responses import JSONResponse, Response from starlette.routing import BaseRoute +import flet_web.fastapi + class FastAPI(fastapi.FastAPI): + """ + FastAPI wrapper that integrates Flet app-manager startup/shutdown lifecycle. + + It mirrors `fastapi.FastAPI` constructor options while + wiring a custom lifespan context that starts and stops + `flet_web.fastapi.app_manager`. + """ + def __init__( self, *, debug: bool = False, - routes: Optional[List[BaseRoute]] = None, + routes: Optional[list[BaseRoute]] = None, title: str = "FastAPI", summary: Optional[str] = None, description: str = "", version: str = "0.1.0", openapi_url: Optional[str] = "/openapi.json", - openapi_tags: Optional[List[Dict[str, Any]]] = None, - servers: Optional[List[Dict[str, Union[str, Any]]]] = None, + openapi_tags: Optional[list[dict[str, Any]]] = None, + servers: Optional[list[dict[str, Union[str, Any]]]] = None, dependencies: Optional[Sequence[Depends]] = None, - default_response_class: Type[Response] = Default(JSONResponse), + default_response_class: type[Response] = Default(JSONResponse), redirect_slashes: bool = True, docs_url: Optional[str] = "/docs", redoc_url: Optional[str] = "/redoc", swagger_ui_oauth2_redirect_url: Optional[str] = "/docs/oauth2-redirect", - swagger_ui_init_oauth: Optional[Dict[str, Any]] = None, + swagger_ui_init_oauth: Optional[dict[str, Any]] = None, middleware: Optional[Sequence[Middleware]] = None, exception_handlers: Optional[ - Dict[ - Union[int, Type[Exception]], + dict[ + Union[int, type[Exception]], Callable[[Request, Any], Coroutine[Any, Any, Response]], ] ] = None, on_startup: Optional[Sequence[Callable[[], Optional[Awaitable]]]] = None, on_shutdown: Optional[Sequence[Callable[[], Optional[Awaitable]]]] = None, terms_of_service: Optional[str] = None, - contact: Optional[Dict[str, Union[str, Any]]] = None, - license_info: Optional[Dict[str, Union[str, Any]]] = None, + contact: Optional[dict[str, Union[str, Any]]] = None, + license_info: Optional[dict[str, Union[str, Any]]] = None, openapi_prefix: str = "", root_path: str = "", root_path_in_servers: bool = True, - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, - callbacks: Optional[List[BaseRoute]] = None, + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, + callbacks: Optional[list[BaseRoute]] = None, webhooks: Optional[fastapi.routing.APIRouter] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, - swagger_ui_parameters: Optional[Dict[str, Any]] = None, + swagger_ui_parameters: Optional[dict[str, Any]] = None, generate_unique_id_function: Callable[ [fastapi.routing.APIRoute], str ] = Default(generate_unique_id), **extra: Any, ) -> None: + """ + Initialize a FastAPI app with Flet-aware lifespan handling. + + All standard FastAPI constructor parameters are supported and passed + through unchanged. + + Args: + debug: Enables debug mode. + on_startup: Optional startup callbacks executed after Flet app-manager + startup. + on_shutdown: Optional shutdown callbacks executed before Flet + app-manager shutdown. + generate_unique_id_function: Function used to generate OpenAPI + operation IDs. + **extra: Additional keyword arguments forwarded to `fastapi.FastAPI`. + """ + @asynccontextmanager async def lifespan(app: fastapi.FastAPI): + """ + Manage Flet and user-provided startup/shutdown hooks for app lifespan. + + Args: + app: FastAPI application instance whose lifespan is being managed. + """ + await flet_web.fastapi.app_manager.start() if on_startup: for h in on_startup: - if asyncio.iscoroutinefunction(h): + if inspect.iscoroutinefunction(h): await h() else: h() - yield + with suppress(asyncio.CancelledError): + yield if on_shutdown: for h in on_shutdown: - if asyncio.iscoroutinefunction(h): + if inspect.iscoroutinefunction(h): await h() else: h() diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_oauth.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_oauth.py index 2a255b6d5a..5f1d1ea7c5 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_oauth.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_oauth.py @@ -1,5 +1,6 @@ from fastapi import HTTPException, Request from fastapi.responses import HTMLResponse, RedirectResponse + from flet_web.fastapi.flet_app_manager import app_manager @@ -33,22 +34,35 @@ async def handle(self, request: Request): if not session: raise HTTPException(status_code=500, detail="Session not found") - await session._authorize_callback_async( - { - "state": state_id, - "code": request.query_params.get("code"), - "error": request.query_params.get("error"), - "error_description": request.query_params.get("error_description"), - } - ) + state.code = request.query_params.get("code") + state.error = request.query_params.get("error") + state.error_description = request.query_params.get("error_description") if state.complete_page_url: - return RedirectResponse(state.complete_page_url) + app_manager.store_state(state_id, state) + response = RedirectResponse(state.complete_page_url) + response.set_cookie( + "flet_oauth_state", + state_id, + max_age=300, + httponly=True, + secure=False, + samesite="strict", + ) + return response else: + await session.page._authorize_callback( + { + "state": state_id, + "code": state.code, + "error": state.error, + "error_description": state.error_description, + } + ) html_content = ( state.complete_page_html if state.complete_page_html - else f""" + else """ @@ -61,6 +75,6 @@ async def handle(self, request: Request):

You've been successfully signed in! You can close this tab or window now.

- """ + """ # noqa: E501 ) return HTMLResponse(content=html_content, status_code=200) diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_static_files.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_static_files.py index 60e447fec2..0146cf9cfa 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_static_files.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_static_files.py @@ -1,36 +1,47 @@ import logging +import mimetypes import os import shutil import tempfile from pathlib import Path -from typing import Optional, Tuple +from typing import Optional -import flet_web.fastapi as flet_fastapi from fastapi.staticfiles import StaticFiles -from flet.core.types import WebRenderer +from starlette.types import Receive, Scope, Send + +import flet_web.fastapi as flet_fastapi +from flet.controls.types import RouteUrlStrategy, WebRenderer from flet.utils import Once, get_bool_env_var -from flet_web import get_package_web_dir, patch_index_html, patch_manifest_json +from flet_web import ( + get_package_web_dir, + patch_font_manifest_json, + patch_index_html, + patch_manifest_json, +) from flet_web.fastapi.flet_app_manager import app_manager -from starlette.types import Receive, Scope, Send logger = logging.getLogger(flet_fastapi.__name__) +# Ensure correct MIME types on platforms (e.g. Windows) +# that do not register them by default. +mimetypes.add_type("text/javascript", ".mjs") +mimetypes.add_type("application/wasm", ".wasm") + class FletStaticFiles(StaticFiles): """ Serve Flet app static files. - Parameters: - - * `app_mount_path` (str) - absolute URL of Flet app. Default is `/`. - * `assets_dir` (str, optional) - an absolute path to app's assets directory. - * `app_name` (str, optional) - PWA application name. - * `app_short_name` (str, optional) - PWA application short name. - * `app_description` (str, optional) - PWA application description. - * `web_renderer` (WebRenderer) - web renderer defaulting to `WebRenderer.CANVAS_KIT`. - * `use_color_emoji` (bool) - whether to load a font with color emoji. Default is `False`. - * `route_url_strategy` (str) - routing URL strategy: `path` (default) or `hash`. - * `websocket_endpoint_path` (str, optional) - absolute URL of Flet app WebSocket handler. Default is `{app_mount_path}/ws`. + Args: + assets_dir: An absolute path to app's assets directory. + app_name: PWA application name. + app_short_name: PWA application short name. + app_description: PWA application description. + web_renderer: Type of web renderer. + route_url_strategy: Routing URL strategy. + no_cdn: Whether not load CanvasKit, Pyodide, and fonts from CDN. + websocket_endpoint_path: Absolute URL of Flet app WebSocket handler. + Defaults to `/ws`. """ def __init__( @@ -40,21 +51,22 @@ def __init__( app_name: Optional[str] = None, app_short_name: Optional[str] = None, app_description: Optional[str] = None, - web_renderer: WebRenderer = WebRenderer.CANVAS_KIT, - use_color_emoji: bool = False, - route_url_strategy: str = "path", + web_renderer: WebRenderer = WebRenderer.AUTO, + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: bool = False, websocket_endpoint_path: Optional[str] = None, ) -> None: - self.index = "index.html" - self.manifest_json = "manifest.json" + self.index = ["index.html"] + self.manifest_json = ["manifest.json"] + self.font_manifest_json = ["assets", "FontManifest.json"] self.__proxy_path = proxy_path self.__assets_dir = assets_dir self.__app_name = app_name self.__app_short_name = app_short_name self.__app_description = app_description self.__web_renderer = web_renderer - self.__use_color_emoji = use_color_emoji self.__route_url_strategy = route_url_strategy + self.__no_cdn = no_cdn self.__websocket_endpoint_path = websocket_endpoint_path self.__once = Once() @@ -62,41 +74,64 @@ def __init__( if env_web_renderer: self.__web_renderer = WebRenderer(env_web_renderer) - env_use_color_emoji = get_bool_env_var("FLET_WEB_USE_COLOR_EMOJI") - if env_use_color_emoji is not None: - self.__use_color_emoji = env_use_color_emoji - env_route_url_strategy = os.getenv("FLET_WEB_ROUTE_URL_STRATEGY") if env_route_url_strategy: - self.__route_url_strategy = env_route_url_strategy + self.__route_url_strategy = RouteUrlStrategy(env_route_url_strategy) + + env_no_cdn = get_bool_env_var("FLET_WEB_NO_CDN") + if env_no_cdn is not None: + self.__no_cdn = env_no_cdn logger.info(f"Web renderer configured: {self.__web_renderer}") - logger.info(f"Use color emoji: {self.__use_color_emoji}") logger.info(f"Route URL strategy configured: {self.__route_url_strategy}") + logger.info(f"No CDN configured: {self.__no_cdn}") async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: await self.__once.do(self.__config, scope["root_path"]) await super().__call__(scope, receive, send) - def lookup_path(self, path: str) -> Tuple[str, Optional[os.stat_result]]: - """Returns the index file when no match is found. + def lookup_path(self, path: str) -> tuple[str, Optional[os.stat_result]]: + """Resolve a static file path, with SPA fallback for client-side routes. + + Route-like paths (no extension, or `.html`) that don't match a file + fall back to `index.html` so the Flutter client can handle routing. + Asset-like paths (any other extension) resolve to a real `404`. Args: - path (str): Resource path. + path: Requested path, relative to the mounted static root + (e.g. `"about"`, `"sample.json"`). Returns: - [tuple[str, os.stat_result]]: Always retuens a full path and stat result. + A `(full_path, stat_result)` tuple. When `stat_result` is + `None`, Starlette responds with `404`. """ logger.debug(f"StaticFiles.lookup_path: {self.__app_mount_path} {path}") full_path, stat_result = super().lookup_path(path) - # if a file cannot be found - if stat_result is None: - return super().lookup_path(self.index) + if stat_result is not None: + return full_path, stat_result + + # Not found: SPA fallback only for route-like paths. + ext = os.path.splitext(path)[1].lower() + if ext == "" or ext == ".html": + return super().lookup_path(self.index[0]) return full_path, stat_result async def __config(self, root_path: str): + """ + Prepare a patched temporary web root and initialize static file serving. + + The method resolves app mount path, copies baseline web files + (`index.html`, `manifest.json`, and optionally `FontManifest.json`) + from either user assets or packaged web assets, applies runtime + substitutions, and configures the underlying + fastapi `StaticFiles` instance. + + Args: + root_path: ASGI root path used to compute mounted base URL. + """ + if self.__proxy_path: self.__app_mount_path = self.__proxy_path + root_path else: @@ -112,7 +147,7 @@ async def __config(self, root_path: str): logger.info(f"Web root: {web_dir}") if not os.path.exists(web_dir): - raise Exception(f"Web root path not found: {web_dir}") + raise RuntimeError(f"Web root path not found: {web_dir}") # user-defined assets if self.__assets_dir: @@ -125,33 +160,32 @@ async def __config(self, root_path: str): logger.info(f"Assets dir: {self.__assets_dir}") + def copy_temp_web_file(paths: list[str]): + """ + Copy a web asset into the temporary patched web directory. + + Source precedence is user-provided assets directory first, then + the packaged web directory. + + Args: + paths: Path segments relative to the web root. + """ + + if self.__assets_dir and os.path.exists( + p := os.path.join(self.__assets_dir, *paths) + ): + src_path = p + else: + src_path = os.path.join(web_dir, *paths) + dst_path = os.path.join(temp_dir, *paths) + Path(dst_path).parent.mkdir(parents=True, exist_ok=True) + shutil.copyfile(src_path, dst_path) + # copy index.html from assets_dir or web_dir - if self.__assets_dir and os.path.exists( - os.path.join(self.__assets_dir, self.index) - ): - shutil.copyfile( - os.path.join(self.__assets_dir, self.index), - os.path.join(temp_dir, self.index), - ) - else: - shutil.copyfile( - os.path.join(web_dir, self.index), - os.path.join(temp_dir, self.index), - ) + copy_temp_web_file(self.index) # copy manifest.json from assets_dir or web_dir - if self.__assets_dir and os.path.exists( - os.path.join(self.__assets_dir, self.manifest_json) - ): - shutil.copyfile( - os.path.join(self.__assets_dir, self.manifest_json), - os.path.join(temp_dir, self.manifest_json), - ) - else: - shutil.copyfile( - os.path.join(web_dir, self.manifest_json), - os.path.join(temp_dir, self.manifest_json), - ) + copy_temp_web_file(self.manifest_json) ws_path = self.__websocket_endpoint_path if not ws_path: @@ -160,23 +194,30 @@ async def __config(self, root_path: str): # replace variables in index.html and manifest.json patch_index_html( - index_path=os.path.join(temp_dir, self.index), + index_path=os.path.join(temp_dir, *self.index), base_href=self.__app_mount_path, websocket_endpoint_path=ws_path, app_name=self.__app_name, app_description=self.__app_description, - web_renderer=WebRenderer(self.__web_renderer), - use_color_emoji=self.__use_color_emoji, + web_renderer=self.__web_renderer, route_url_strategy=self.__route_url_strategy, + no_cdn=self.__no_cdn, ) patch_manifest_json( - manifest_path=os.path.join(temp_dir, self.manifest_json), + manifest_path=os.path.join(temp_dir, *self.manifest_json), app_name=self.__app_name, app_short_name=self.__app_short_name, app_description=self.__app_description, ) + if self.__no_cdn: + # copy FontManifest.json from assets_dir or web_dir + copy_temp_web_file(self.font_manifest_json) + patch_font_manifest_json( + manifest_path=os.path.join(temp_dir, *self.font_manifest_json) + ) + # set html=True to resolve the index even when no # the base path is passed in super().__init__(directory=temp_dir, packages=None, html=True, check_dir=True) diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_upload.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_upload.py index 588536a115..2b0591f24c 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_upload.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/flet_upload.py @@ -3,9 +3,10 @@ from datetime import datetime, timezone from typing import Optional -import flet_web.fastapi as flet_fastapi from anyio import open_file -from fastapi import Request +from fastapi import HTTPException, Request, status + +import flet_web.fastapi as flet_fastapi from flet_web.uploads import build_upload_query_string, get_upload_signature logger = logging.getLogger(flet_fastapi.__name__) @@ -15,11 +16,10 @@ class FletUpload: """ Flet app uploads handler. - Parameters: - - * `upload_dir` (str) - an absolute path to a directory with uploaded files. - * `max_upload_size` (str, int) - maximum size of a single upload, bytes. Unlimited if `None`. - * `secret_key` (str, optional) - secret key to sign and verify upload requests. + Args: + upload_dir: An absolute path to a directory with uploaded files. + max_upload_size: maximum size of a single upload, bytes. Unlimited if `None`. + secret_key: secret key to sign and verify upload requests. """ def __init__( @@ -43,21 +43,30 @@ def __init__( logger.info(f"Upload path configured: {self.__upload_dir}") - """ - Handle file upload. - - Upload must be an non-encoded (raw) file in the requst body. - """ - async def handle(self, request: Request): - file_name = request.query_params["f"] - expire_str = request.query_params["e"] - signature = request.query_params["s"] + """ + Handle file upload. + + Upload must be an non-encoded (raw) file in the request body. + """ + query_params = request.query_params + file_name = query_params.get("f") + expire_str = query_params.get("e") + signature = query_params.get("s") if not file_name or not expire_str or not signature: - raise Exception("Invalid request") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Missing upload parameters", + ) - expire_date = datetime.fromisoformat(expire_str) + try: + expire_date = datetime.fromisoformat(expire_str) + except ValueError as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid expiration parameter", + ) from e # verify signature query_string = build_upload_query_string(file_name, expire_date) @@ -67,19 +76,28 @@ async def handle(self, request: Request): ) != signature ): - raise Exception("Invalid request") + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Invalid upload signature", + ) # check expiration date if datetime.now(timezone.utc) >= expire_date: - raise Exception("Invalid request") + raise HTTPException( + status_code=status.HTTP_410_GONE, + detail="Upload URL has expired", + ) # build/validate dest path joined_path = os.path.join(self.__upload_dir, file_name) full_path = os.path.realpath(joined_path) if os.path.commonpath([full_path, self.__upload_dir]) != self.__upload_dir: - raise Exception("Invalid request") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Invalid upload destination", + ) - # create directory if not exists + # create a directory if it doesn't exist dest_dir = os.path.dirname(full_path) os.makedirs(dest_dir, exist_ok=True) @@ -89,7 +107,9 @@ async def handle(self, request: Request): async for chunk in request.stream(): size += len(chunk) if self.__max_upload_size and size > self.__max_upload_size: - raise Exception( - f"Max upload size reached: {self.__max_upload_size}" + raise HTTPException( + status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, + detail="Max upload size exceeded: " + f"{self.__max_upload_size} bytes", ) await f.write(chunk) diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/oauth_state.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/oauth_state.py index 03044db5cc..51cbd3a05f 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/oauth_state.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/oauth_state.py @@ -5,7 +5,44 @@ @dataclasses.dataclass class OAuthState: + """ + Temporary OAuth flow state persisted between auth start and callback. + + Instances are stored by `FletAppManager` + and keyed by the `flet_oauth_state` cookie value. + """ + session_id: str + """ + Related Flet session identifier. + """ + expires_at: datetime - complete_page_url: Optional[str] = dataclasses.field(default=None) - complete_page_html: Optional[str] = dataclasses.field(default=None) + """ + UTC expiration timestamp after which this state is discarded. + """ + + complete_page_url: Optional[str] = None + """ + URL to redirect/open after OAuth flow completion, if provided. + """ + + complete_page_html: Optional[str] = None + """ + Optional completion HTML returned after OAuth callback handling. + """ + + code: Optional[str] = None + """ + Authorization code returned by OAuth provider, if successful. + """ + + error: Optional[str] = None + """ + OAuth error code returned by provider, if flow failed. + """ + + error_description: Optional[str] = None + """ + Human-readable OAuth error description, when available. + """ diff --git a/sdk/python/packages/flet-web/src/flet_web/fastapi/serve_fastapi_web_app.py b/sdk/python/packages/flet-web/src/flet_web/fastapi/serve_fastapi_web_app.py index 616e644f3a..dc78bf7c99 100644 --- a/sdk/python/packages/flet-web/src/flet_web/fastapi/serve_fastapi_web_app.py +++ b/sdk/python/packages/flet-web/src/flet_web/fastapi/serve_fastapi_web_app.py @@ -1,46 +1,77 @@ import asyncio import logging -from typing import Optional +from typing import Any, Optional, Union import uvicorn -from flet.core.types import WebRenderer import flet_web.fastapi import flet_web.fastapi as flet_fastapi +from flet.app import AppCallable +from flet.controls.types import RouteUrlStrategy, WebRenderer logger = logging.getLogger(flet_fastapi.__name__) class WebServerHandle: - def __init__(self, page_url: str, server: uvicorn.Server) -> None: + """ + Runtime handle for a started FastAPI web server task. + """ + + def __init__( + self, page_url: str, server: uvicorn.Server, serve_task: asyncio.Task + ) -> None: self.page_url = page_url self.server = server + self.serve_task = serve_task async def close(self): + """ + Gracefully shut down the underlying Uvicorn server. + """ + logger.info("Closing Flet web server...") await self.server.shutdown() def get_fastapi_web_app( - session_handler, + main: AppCallable, + before_main: Optional[AppCallable], page_name: str, - assets_dir, - upload_dir, - web_renderer: Optional[WebRenderer], - use_color_emoji, - route_url_strategy, + assets_dir: str, + upload_dir: str, + web_renderer: WebRenderer = WebRenderer.AUTO, + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: bool = False, ): + """ + Build and return a FastAPI app with a mounted Flet web application. + + Args: + main: Flet app entry handler. + before_main: Optional hook called before `main`. + page_name: URL path prefix where app is mounted. + assets_dir: Absolute path to static assets directory. + upload_dir: Absolute path used for uploads. + web_renderer: Flutter web renderer mode. + route_url_strategy: Route URL strategy (`path` or `hash`). + no_cdn: Whether CDN resources should be disabled. + + Returns: + Configured FastAPI application instance. + """ + web_path = f"/{page_name.strip('/')}" app = flet_web.fastapi.FastAPI() app.mount( web_path, flet_web.fastapi.app( - session_handler, + main, + before_main=before_main, upload_dir=upload_dir, assets_dir=assets_dir, - web_renderer=web_renderer if web_renderer else WebRenderer.AUTO, - use_color_emoji=use_color_emoji, + web_renderer=web_renderer, route_url_strategy=route_url_strategy, + no_cdn=no_cdn, ), ) @@ -48,25 +79,50 @@ def get_fastapi_web_app( async def serve_fastapi_web_app( - session_handler, - host, - url_host, - port, + main: AppCallable, + before_main: Optional[AppCallable], + host: str, + url_host: str, + port: int, page_name: str, - assets_dir, - upload_dir, - web_renderer: Optional[WebRenderer], - use_color_emoji, - route_url_strategy, - blocking, - on_startup, - log_level, -): + assets_dir: str, + upload_dir: str, + web_renderer: WebRenderer = WebRenderer.AUTO, + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: bool = False, + on_startup: Optional[Any] = None, + log_level: Optional[Union[str, int]] = None, +) -> WebServerHandle: + """ + Start a mounted Flet FastAPI app with Uvicorn and return a server handle. + + Args: + main: Flet app entry handler. + before_main: Optional hook called before `main`. + host: Interface to bind the server to. + url_host: Host used to compose externally displayed page URL. + port: TCP port to bind. + page_name: URL path prefix where app is mounted. + assets_dir: Absolute path to static assets directory. + upload_dir: Absolute path used for uploads. + web_renderer: Flutter web renderer mode. + route_url_strategy: Route URL strategy (`path` or `hash`). + no_cdn: Whether CDN resources should be disabled. + on_startup: Optional callback invoked with resolved page URL. + log_level: Uvicorn log level. + + Returns: + `WebServerHandle` for controlling server lifecycle. + """ web_path = f"/{page_name.strip('/')}" page_url = f"http://{url_host}:{port}{web_path if web_path != '/' else ''}" def startup(): + """ + Invoke optional startup callback with resolved page URL. + """ + if on_startup: on_startup(page_url) @@ -75,20 +131,20 @@ def startup(): app.mount( web_path, flet_web.fastapi.app( - session_handler, + main, + before_main=before_main, upload_dir=upload_dir, assets_dir=assets_dir, - web_renderer=web_renderer if web_renderer else WebRenderer.AUTO, - use_color_emoji=use_color_emoji, + web_renderer=web_renderer, route_url_strategy=route_url_strategy, + no_cdn=no_cdn, ), ) - config = uvicorn.Config(app, host=host, port=port, log_level=log_level) + config = uvicorn.Config( + app, host=host, port=port, log_level=log_level, ws="websockets-sansio" + ) server = uvicorn.Server(config) - if blocking: - await server.serve() - else: - asyncio.create_task(server.serve()) - - return WebServerHandle(page_url=page_url, server=server) + return WebServerHandle( + page_url=page_url, server=server, serve_task=asyncio.create_task(server.serve()) + ) diff --git a/sdk/python/packages/flet-web/src/flet_web/patch_index.py b/sdk/python/packages/flet-web/src/flet_web/patch_index.py index 7bc1fdebab..af8bca4dcc 100644 --- a/sdk/python/packages/flet-web/src/flet_web/patch_index.py +++ b/sdk/python/packages/flet-web/src/flet_web/patch_index.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Optional -from flet.core.types import WebRenderer +from flet.controls.types import RouteUrlStrategy, WebRenderer def patch_index_html( @@ -16,64 +16,80 @@ def patch_index_html( pyodide_pre: bool = False, pyodide_script_path: str = "", web_renderer: WebRenderer = WebRenderer.AUTO, - use_color_emoji: bool = False, - route_url_strategy: str = "path", + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: bool = False, ): - with open(index_path, "r", encoding="utf-8") as f: + """ + Patch Flutter web `index.html` with Flet runtime and app metadata settings. + + The file is read, updated in memory, and written back to `index_path`. + This function updates base href, injects Flet app config script, and can + optionally replace title/description metadata. + + Args: + index_path: Path to `index.html`. + base_href: Base URL prefix used by the web app. + websocket_endpoint_path: Optional websocket endpoint path. + app_name: Optional app name used for page title and iOS web-app title meta. + app_description: Optional app description meta content. + pyodide: Whether to enable Pyodide mode in injected runtime config. + pyodide_pre: Whether pre-release micropip packages are allowed. + pyodide_script_path: Path to Python entry script for Pyodide apps. + web_renderer: Web renderer mode for the frontend runtime. + route_url_strategy: URL strategy used by frontend routing. + no_cdn: Whether CDN asset loading should be disabled. + """ + + with open(index_path, encoding="utf-8") as f: index = f.read() - if pyodide and pyodide_script_path: - module_name = Path(pyodide_script_path).stem - pyodideCode = f""" - - - """ - index = index.replace("", pyodideCode) - index = index.replace("%FLET_WEB_PYODIDE%", str(pyodide).lower()) + base_url = "/" + if base_href: + base_url = base_href.strip("/").strip() + base_url = "/" if base_url == "" else f"/{base_url}/" + index = index.replace( - "", - f'', + '', + f'', ) + + app_config = [] + + if pyodide and pyodide_script_path: + module_name = Path(pyodide_script_path).stem + app_config.append("flet.pyodide = true;") + app_config.append(f"flet.micropipIncludePre = {str(pyodide_pre).lower()};") + app_config.append(f'flet.pythonModuleName = "{module_name}";') + + app_config.append(f"flet.noCdn={str(no_cdn).lower()};") + app_config.append(f'flet.webRenderer="{web_renderer.value}";') + app_config.append(f'flet.routeUrlStrategy="{route_url_strategy.value}";') + app_config.append(f'flet.entrypointBaseUrl="{base_url}";') + app_config.append(f'flet.assetBase="{base_url}";') + + if websocket_endpoint_path: + app_config.append(f'flet.webSocketEndpoint="{websocket_endpoint_path}";') + index = index.replace( - "", - f"", + "", + "".format("\n".join(app_config)), ) - index = index.replace("%FLET_ROUTE_URL_STRATEGY%", route_url_strategy) - if base_href: - base_url = base_href.strip("/").strip() - index = index.replace( - '', - ''.format( - "/" if base_url == "" else "/{}/".format(base_url) - ), - ) - if websocket_endpoint_path: - index = re.sub( - r"\", - r''.format( - websocket_endpoint_path - ), - index, - ) if app_name: index = re.sub( r"\", - r''.format(app_name), + rf'', index, ) index = re.sub( r"\(.+)", - r"{}".format(app_name), + rf"{app_name}", index, ) if app_description: index = re.sub( r"\", - r''.format(app_description), + rf'', index, ) @@ -89,7 +105,23 @@ def patch_manifest_json( background_color: Optional[str] = None, theme_color: Optional[str] = None, ): - with open(manifest_path, "r", encoding="utf-8") as f: + """ + Patch selected fields in a web app `manifest.json`. + + The manifest is loaded as JSON, updated with provided values, and written + back to `manifest_path`. + + Args: + manifest_path: Path to `manifest.json`. + app_name: Optional app full name. Also sets `short_name` unless + `app_short_name` is explicitly provided. + app_short_name: Optional app short name override. + app_description: Optional manifest description. + background_color: Optional app background color. + theme_color: Optional browser UI theme color. + """ + + with open(manifest_path, encoding="utf-8") as f: manifest = json.loads(f.read()) if app_name: @@ -110,3 +142,20 @@ def patch_manifest_json( with open(manifest_path, "w", encoding="utf-8") as f: f.write(json.dumps(manifest, indent=2)) + + +def patch_font_manifest_json(manifest_path: str): + """ + Append bundled Roboto font entry to Flutter's `FontManifest.json`. + + Args: + manifest_path: Path to `FontManifest.json`. + """ + + with open(manifest_path, encoding="utf-8") as f: + manifest = json.loads(f.read()) + + manifest.append({"family": "Roboto", "fonts": [{"asset": "fonts/roboto.woff2"}]}) + + with open(manifest_path, "w", encoding="utf-8") as f: + f.write(json.dumps(manifest, indent=2)) diff --git a/sdk/python/packages/flet-web/src/flet_web/uploads.py b/sdk/python/packages/flet-web/src/flet_web/uploads.py index d25fc0c05e..825940f3cb 100644 --- a/sdk/python/packages/flet-web/src/flet_web/uploads.py +++ b/sdk/python/packages/flet-web/src/flet_web/uploads.py @@ -17,6 +17,19 @@ def build_upload_url( expires_in_seconds: int, secret_key: Optional[str], ): + """ + Build a signed relative upload URL for a single file upload operation. + + Args: + upload_endpoint_path: Upload endpoint path (with or without slashes). + file_name: File name to include in upload query. + expires_in_seconds: Signature validity duration in seconds. + secret_key: Signing key. Overridden by `FLET_SECRET_KEY` env var. + + Returns: + Relative upload URL containing query parameters and HMAC signature. + """ + expire_date = datetime.now(timezone.utc) + timedelta(seconds=expires_in_seconds) query_string = build_upload_query_string(file_name, expire_date) signature = get_upload_signature( @@ -26,6 +39,17 @@ def build_upload_url( def build_upload_query_string(file_name: str, expire_date: datetime): + """ + Build canonical query string used for upload URL signing. + + Args: + file_name: File name to upload. + expire_date: Upload expiration timestamp. + + Returns: + URL-encoded query string with file and expiration values. + """ + return urllib.parse.urlencode({"f": file_name, "e": expire_date.isoformat()}) @@ -35,12 +59,33 @@ def get_upload_signature( expire_date: datetime, secret_key: Optional[str], ): + """ + Compute HMAC signature for upload URL validation. + + Signature derivation: + - derive a short-lived signing key from secret and expiration timestamp; + - sign `` with that signing key. + + Args: + upload_endpoint_path: Upload endpoint path (with or without slashes). + query_string: Canonical upload query string. + expire_date: Expiration timestamp used in key derivation. + secret_key: Signing key. Overridden by `FLET_SECRET_KEY` env var. + + Returns: + Hex-encoded SHA-256 HMAC signature. + + Raises: + RuntimeError: If no signing secret is provided. + """ + env_secret_key = os.getenv("FLET_SECRET_KEY") if env_secret_key: secret_key = env_secret_key if not secret_key: - raise Exception( - "Specify secret_key parameter or set FLET_SECRET_KEY environment variable to enable uploads." + raise RuntimeError( + "Specify secret_key parameter or set FLET_SECRET_KEY environment " + "variable to enable uploads." ) signing_key = hmac.new( secret_key.encode("utf-8"), @@ -49,6 +94,6 @@ def get_upload_signature( ).digest() return hmac.new( signing_key, - f"{upload_endpoint_path.strip('/')}{query_string}".encode("utf-8"), + f"{upload_endpoint_path.strip('/')}{query_string}".encode(), hashlib.sha256, ).hexdigest() diff --git a/sdk/python/packages/flet-webview/CHANGELOG.md b/sdk/python/packages/flet-webview/CHANGELOG.md new file mode 100644 index 0000000000..7155c2499b --- /dev/null +++ b/sdk/python/packages/flet-webview/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## 0.80.0 + +### Added + +- Deployed online documentation: https://flet.dev/docs/webview/ + +### Changed + +- Refactored all controls to use `@flet.control` dataclass-style definition. + +## 0.1.0 + +Initial release. diff --git a/sdk/python/packages/flet-webview/LICENSE b/sdk/python/packages/flet-webview/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/sdk/python/packages/flet-webview/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sdk/python/packages/flet-webview/README.md b/sdk/python/packages/flet-webview/README.md new file mode 100644 index 0000000000..862557c241 --- /dev/null +++ b/sdk/python/packages/flet-webview/README.md @@ -0,0 +1,43 @@ +# flet-webview + +[![pypi](https://img.shields.io/pypi/v/flet-webview.svg)](https://pypi.python.org/pypi/flet-webview) +[![downloads](https://static.pepy.tech/badge/flet-webview/month)](https://pepy.tech/project/flet-webview) +[![python](https://img.shields.io/badge/python-%3E%3D3.10-%2334D058)](https://pypi.org/project/flet-webview) +[![docstring coverage](https://flet.dev/docs/assets/badges/docs-coverage/flet-webview.svg)](https://flet.dev/docs/assets/badges/docs-coverage/flet-webview.svg) +[![license](https://img.shields.io/badge/License-Apache_2.0-green.svg)](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-webview/LICENSE) + +A [Flet](https://flet.dev) extension for displaying web content in a WebView. + +It is based on the [webview_flutter](https://pub.dev/packages/webview_flutter) +and [webview_flutter_web](https://pub.dev/packages/webview_flutter_web) Flutter packages. + +## Documentation + +Detailed documentation to this package can be found [here](https://flet.dev/docs/controls/webview/). + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | + +## Usage + +### Installation + +To install the `flet-webview` package and add it to your project dependencies: + +- Using `uv`: + ```bash + uv add flet-webview + ``` + +- Using `pip`: + ```bash + pip install flet-webview + ``` + After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + +### Examples + +For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/extensions/webview). diff --git a/sdk/python/packages/flet-webview/pyproject.toml b/sdk/python/packages/flet-webview/pyproject.toml new file mode 100644 index 0000000000..e9b72025a1 --- /dev/null +++ b/sdk/python/packages/flet-webview/pyproject.toml @@ -0,0 +1,27 @@ +[project] +name = "flet-webview" +version = "0.1.0" +description = "Embed web content inside Flet apps via WebView." +readme = "README.md" +authors = [{ name = "Flet contributors", email = "hello@flet.dev" }] +license = "Apache-2.0" +requires-python = ">=3.10" +dependencies = [ + "flet", +] + +[project.urls] +Homepage = "https://flet.dev" +Documentation = "https://flet.dev/docs/controls/webview" +Repository = "https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet-webview" +Issues = "https://github.com/flet-dev/flet/issues" + +[tool.setuptools.package-data] +"flutter.flet_webview" = [ + "pubspec.yaml", + "lib/**", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/packages/flet-webview/src/flet_webview/__init__.py b/sdk/python/packages/flet-webview/src/flet_webview/__init__.py new file mode 100644 index 0000000000..4601ba14fd --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flet_webview/__init__.py @@ -0,0 +1,19 @@ +from flet_webview.types import ( + JavaScriptMode, + LogLevelSeverity, + RequestMethod, + WebViewConsoleMessageEvent, + WebViewJavaScriptEvent, + WebViewScrollEvent, +) +from flet_webview.webview import WebView + +__all__ = [ + "JavaScriptMode", + "LogLevelSeverity", + "RequestMethod", + "WebView", + "WebViewConsoleMessageEvent", + "WebViewJavaScriptEvent", + "WebViewScrollEvent", +] diff --git a/sdk/python/packages/flet-webview/src/flet_webview/types.py b/sdk/python/packages/flet-webview/src/flet_webview/types.py new file mode 100644 index 0000000000..f8261abd5b --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flet_webview/types.py @@ -0,0 +1,108 @@ +from dataclasses import dataclass +from enum import Enum +from typing import TYPE_CHECKING + +import flet as ft + +if TYPE_CHECKING: + from flet_webview.webview import WebView # noqa + +__all__ = [ + "JavaScriptMode", + "LogLevelSeverity", + "RequestMethod", + "WebViewConsoleMessageEvent", + "WebViewJavaScriptEvent", + "WebViewScrollEvent", +] + + +class RequestMethod(Enum): + """Defines the supported HTTP methods for loading a page in a `WebView`.""" + + GET = "get" + """HTTP GET method.""" + + POST = "post" + """HTTP POST method.""" + + +class LogLevelSeverity(Enum): + """Represents the severity of a JavaScript log message.""" + + ERROR = "error" + """ + Indicates an error message was logged via an "error" event of the + `console.error` method. + """ + + WARNING = "warning" + """Indicates a warning message was logged using the `console.warning` method.""" + + DEBUG = "debug" + """Indicates a debug message was logged using the `console.debug` method.""" + + INFO = "info" + """Indicates an informational message was logged using the `console.info` method.""" + + LOG = "log" + """Indicates a log message was logged using the `console.log` method.""" + + +class JavaScriptMode(Enum): + """Defines the state of JavaScript support in the `WebView`.""" + + UNRESTRICTED = "unrestricted" + """JavaScript execution is unrestricted.""" + + DISABLED = "disabled" + """JavaScript execution is disabled.""" + + +@dataclass +class WebViewScrollEvent(ft.Event["WebView"]): + """ + Event payload for `WebView.on_scroll`. + + Emitted when the page scroll position changes. + """ + + x: float + """ + The value of the horizontal offset with the origin being at the + leftmost of the `WebView`. + """ + + y: float + """ + The value of the vertical offset with the origin being at the + topmost of the `WebView`. + """ + + +@dataclass +class WebViewConsoleMessageEvent(ft.Event["WebView"]): + """ + Event payload for `WebView.on_console_message`. + """ + + message: str + """The message written to the console.""" + + severity_level: LogLevelSeverity + """The severity of a JavaScript log message.""" + + +@dataclass +class WebViewJavaScriptEvent(ft.Event["WebView"]): + """ + Event payload for `WebView.on_javascript_alert_dialog`. + + Represents a JavaScript `alert()` dialog request initiated by the loaded page. + """ + + message: str + """The message to be displayed in the window.""" + + url: str + """The URL of the page requesting the dialog.""" diff --git a/sdk/python/packages/flet-webview/src/flet_webview/webview.py b/sdk/python/packages/flet-webview/src/flet_webview/webview.py new file mode 100644 index 0000000000..91da17d8df --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flet_webview/webview.py @@ -0,0 +1,390 @@ +from typing import Optional + +from typing_extensions import Self + +import flet as ft +from flet_webview.types import ( + JavaScriptMode, + RequestMethod, + WebViewConsoleMessageEvent, + WebViewJavaScriptEvent, + WebViewScrollEvent, +) + +__all__ = ["WebView"] + + +@ft.control("WebView") +class WebView(ft.LayoutControl): + """ + Easily load webpages while allowing user interaction. + + Note: + Supported only on the following platforms: iOS, Android, macOS, and Web. + Concerning Windows and Linux support, subscribe to this + [issue](https://github.com/flet-dev/flet-webview/issues/17). + """ + + url: Optional[str] = None + """The URL of the web page to load.""" + + prevent_links: Optional[list[str]] = None + """List of url-prefixes that should not be followed/loaded/downloaded.""" + + bgcolor: Optional[ft.ColorValue] = None + """Defines the background color of the WebView.""" + + on_page_started: Optional[ft.ControlEventHandler["WebView"]] = None + """ + Fires soon as the first loading process of the webview page is started. + + The :attr:`~flet.Event.data` property of the event handler argument is of type + `str` and contains the URL. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + on_page_ended: Optional[ft.ControlEventHandler["WebView"]] = None + """ + Fires when all the webview page loading processes are ended. + + The :attr:`~flet.Event.data` property of the event handler argument is of type + `str` and contains the URL. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + on_web_resource_error: Optional[ft.ControlEventHandler["WebView"]] = None + """ + Fires when there is error with loading a webview page resource. + + The :attr:`~flet.Event.data` property of the event handler argument is of type + `str` and contains the error message. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + on_progress: Optional[ft.ControlEventHandler["WebView"]] = None + """ + Fires when the progress of the webview page loading is changed. + + The :attr:`~flet.Event.data` property of the event handler argument is of type + `int` and contains the progress value. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + on_url_change: Optional[ft.ControlEventHandler["WebView"]] = None + """ + Fires when the URL of the webview page is changed. + + The :attr:`~flet.Event.data` property of the event handler argument is of type + `str` and contains the new URL. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + on_scroll: Optional[ft.EventHandler[WebViewScrollEvent]] = None + """ + Fires when the web page's scroll position changes. + + Note: + Works only on the following platforms: iOS and Android. + """ + + on_console_message: Optional[ft.EventHandler[WebViewConsoleMessageEvent]] = None + """ + Fires when a log message is written to the JavaScript console. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + on_javascript_alert_dialog: Optional[ft.EventHandler[WebViewJavaScriptEvent]] = None + """ + Fires when the web page attempts to display a JavaScript alert() dialog. + + Note: + Works only on the following platforms: iOS, Android and macOS. + """ + + def _check_mobile_or_mac_platform(self): + """ + Checks/Validates support for the current platform (iOS, Android, or macOS). + """ + if self.page is None: + raise RuntimeError("WebView must be added to page first.") + if self.page.web or self.page.platform not in [ + ft.PagePlatform.ANDROID, + ft.PagePlatform.IOS, + ft.PagePlatform.MACOS, + ]: + raise ft.FletUnsupportedPlatformException( + "This method is supported on Android, iOS and macOS platforms only." + ) + + async def reload(self): + """ + Reloads the current URL. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("reload") + + async def can_go_back(self) -> bool: + """ + Whether there's a back history item. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Returns: + `True` if there is a back history item, `False` otherwise. + """ + self._check_mobile_or_mac_platform() + return await self._invoke_method("can_go_back") + + async def can_go_forward(self) -> bool: + """ + Whether there's a forward history item. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Returns: + `True` if there is a forward history item, `False` otherwise. + """ + self._check_mobile_or_mac_platform() + return await self._invoke_method("can_go_forward") + + async def go_back(self): + """ + Goes back in the history of the webview, if `can_go_back()` is `True`. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("go_back") + + async def go_forward(self): + """ + Goes forward in the history of the webview, + if :meth:`can_go_forward` is `True`. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("go_forward") + + async def enable_zoom(self): + """ + Enables zooming using the on-screen zoom controls and gestures. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("enable_zoom") + + async def disable_zoom(self): + """ + Disables zooming using the on-screen zoom controls and gestures. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("disable_zoom") + + async def clear_cache(self): + """ + Clears all caches used by the WebView. + + The following caches are cleared: + - Browser HTTP Cache + - Cache API caches. Service workers tend to use this cache. + - Application cache + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("clear_cache") + + async def clear_local_storage(self): + """ + Clears the local storage used by the WebView. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method("clear_local_storage") + + async def get_current_url(self) -> Optional[str]: + """ + Gets the current URL that the WebView is displaying or `None` + if no URL was ever loaded. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Returns: + The current URL that the WebView is displaying or `None` + if no URL was ever loaded. + """ + self._check_mobile_or_mac_platform() + return await self._invoke_method("get_current_url") + + async def get_title(self) -> Optional[str]: + """ + Get the title of the currently loaded page. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Returns: + The title of the currently loaded page. + """ + self._check_mobile_or_mac_platform() + return await self._invoke_method("get_title") + + async def get_user_agent(self) -> Optional[str]: + """ + Get the value used for the HTTP `User-Agent:` request header. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Returns: + The value used for the HTTP `User-Agent:` request header. + """ + self._check_mobile_or_mac_platform() + return await self._invoke_method("get_user_agent") + + async def load_file(self, path: str): + """ + Loads the provided local file. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Args: + path: The absolute path to the file. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + method_name="load_file", + arguments={"path": path}, + ) + + async def load_request(self, url: str, method: RequestMethod = RequestMethod.GET): + """ + Makes an HTTP request and loads the response in the webview. + + Args: + url: The URL to load. + method: The HTTP method to use. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + "load_request", arguments={"url": url, "method": method} + ) + + async def run_javascript(self, value: str): + """ + Runs the given JavaScript in the context of the current page. + + Args: + value: The JavaScript code to run. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + method_name="run_javascript", + arguments={"value": value}, + ) + + async def load_html(self, value: str, base_url: Optional[str] = None) -> Self: + """ + Loads the provided HTML string. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Args: + value: The HTML string to load. + base_url: The base URL to use when resolving relative URLs within the value. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + "load_html", arguments={"value": value, "base_url": base_url} + ) + + return self + + async def scroll_to(self, x: int, y: int): + """ + Scrolls to the provided position of webview pixels. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Args: + x: The x-coordinate of the scroll position. + y: The y-coordinate of the scroll position. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + method_name="scroll_to", + arguments={"x": x, "y": y}, + ) + + async def scroll_by(self, x: int, y: int): + """ + Scrolls by the provided number of webview pixels. + + Note: + Works only on the following platforms: iOS, Android, and macOS. + + Args: + x: The number of pixels to scroll by on the x-axis. + y: The number of pixels to scroll by on the y-axis. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + method_name="scroll_by", + arguments={"x": x, "y": y}, + ) + + async def set_javascript_mode(self, mode: JavaScriptMode): + """ + Sets the JavaScript mode of the WebView. + + Note: + - Works only on the following platforms: iOS, Android, and macOS. + - Disabling the JavaScript execution on the page may result to + unexpected web page behaviour. + + Args: + mode: The JavaScript mode to set. + """ + self._check_mobile_or_mac_platform() + await self._invoke_method( + method_name="set_javascript_mode", + arguments={"mode": mode}, + ) diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/.gitignore b/sdk/python/packages/flet-webview/src/flutter/flet_webview/.gitignore new file mode 100644 index 0000000000..ed7794f2ab --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/.gitignore @@ -0,0 +1,34 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies + +# override parent rules +!lib/ diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/analysis_options.yaml b/sdk/python/packages/flet-webview/src/flutter/flet_webview/analysis_options.yaml new file mode 100644 index 0000000000..a5744c1cfb --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/flet_webview.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/flet_webview.dart new file mode 100644 index 0000000000..0816f961c3 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/flet_webview.dart @@ -0,0 +1,3 @@ +library flet_webview; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/extension.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/extension.dart new file mode 100644 index 0000000000..e716a2ab23 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/extension.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; + +import 'webview.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "WebView": + return WebViewControl(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/utils/webview.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/utils/webview.dart new file mode 100644 index 0000000000..a1c65267c2 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/utils/webview.dart @@ -0,0 +1,12 @@ +import 'package:flet/flet.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +LoadRequestMethod? parseLoadRequestMethod(String? value, + [LoadRequestMethod? defaultValue]) { + return parseEnum(LoadRequestMethod.values, value, defaultValue); +} + +JavaScriptMode? parseJavaScriptMode(String? value, + [JavaScriptMode? defaultValue]) { + return parseEnum(JavaScriptMode.values, value, defaultValue); +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview.dart new file mode 100644 index 0000000000..c16163fa99 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview.dart @@ -0,0 +1,29 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +import 'webview_mobile_and_mac.dart'; +import 'webview_web.dart' if (dart.library.io) "webview_web_vain.dart"; +import 'webview_windows_and_linux.dart' + if (dart.library.html) "webview_windows_and_linux_vain.dart"; + +class WebViewControl extends StatelessWidget { + final Control control; + + const WebViewControl({super.key, required this.control}); + + @override + Widget build(BuildContext context) { + debugPrint("WebViewControl build: ${control.id}"); + Widget view = + const ErrorControl("Webview is not yet supported on this platform."); + if (isWebPlatform()) { + view = WebviewWeb(control: control); + } else if (isMobilePlatform() || isMacOSDesktop()) { + view = WebviewMobileAndMac(control: control); + } else if (isWindowsDesktop() || isLinuxDesktop()) { + view = const WebviewDesktop(); + } + + return LayoutControl(control: control, child: view); + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_mobile_and_mac.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_mobile_and_mac.dart new file mode 100644 index 0000000000..1044193f59 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_mobile_and_mac.dart @@ -0,0 +1,223 @@ +import 'package:flet/flet.dart'; +import 'package:flet_webview/src/utils/webview.dart'; +import 'package:flutter/material.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +class WebviewMobileAndMac extends StatefulWidget { + final Control control; + + const WebviewMobileAndMac({super.key, required this.control}); + + @override + State createState() => _WebviewMobileAndMacState(); +} + +class _WebviewMobileAndMacState extends State { + late WebViewController controller; + bool _scrollHandlerRegistered = false; + bool _consoleHandlerRegistered = false; + bool _alertHandlerRegistered = false; + + bool _shouldPreventNavigation(String url) { + final links = widget.control.get("prevent_links"); + if (links == null || links.isEmpty) return false; + return links.any((link) => link is String && url.startsWith(link)); + } + + void _setOptionalEventHandlers() { + // macOS currently does not surface scroll callbacks via webview_flutter. + if (!isMacOSDesktop() && + !_scrollHandlerRegistered && + widget.control.hasEventHandler("scroll")) { + try { + controller.setOnScrollPositionChange((ScrollPositionChange position) { + widget.control + .triggerEvent("scroll", {"x": position.x, "y": position.y}); + }); + _scrollHandlerRegistered = true; + } catch (e) { + debugPrint("WebView.on_scroll is not available on this platform: $e"); + } + } + + if (!_consoleHandlerRegistered && + widget.control.hasEventHandler("console_message")) { + try { + controller.setOnConsoleMessage((JavaScriptConsoleMessage message) { + widget.control.triggerEvent("console_message", { + "message": message.message, + "severity_level": message.level.name, + }); + }); + _consoleHandlerRegistered = true; + } catch (e) { + debugPrint( + "WebView.on_console_message is not available on this platform: $e"); + } + } + + if (!_alertHandlerRegistered && + widget.control.hasEventHandler("javascript_alert_dialog")) { + try { + controller.setOnJavaScriptAlertDialog( + (JavaScriptAlertDialogRequest request) async { + widget.control.triggerEvent( + "javascript_alert_dialog", + {"message": request.message, "url": request.url}, + ); + }); + _alertHandlerRegistered = true; + } catch (e) { + debugPrint( + "WebView.on_javascript_alert_dialog is not available on this platform: $e"); + } + } + } + + @override + void initState() { + super.initState(); + widget.control.addInvokeMethodListener(_invokeMethod); + + var params = const PlatformWebViewControllerCreationParams(); + controller = WebViewController.fromPlatformCreationParams(params); + + controller.setNavigationDelegate( + NavigationDelegate( + onProgress: (int progress) { + widget.control.triggerEvent("progress", progress); + }, + onUrlChange: (UrlChange url) { + widget.control.triggerEvent("url_change", url.url); + }, + onPageStarted: (String url) { + widget.control.triggerEvent("page_started", url); + }, + onPageFinished: (String url) { + widget.control.triggerEvent("page_ended", url); + }, + onWebResourceError: (WebResourceError error) { + widget.control.triggerEvent("web_resource_error", error.description); + }, + onNavigationRequest: (NavigationRequest request) { + return _shouldPreventNavigation(request.url) + ? NavigationDecision.prevent + : NavigationDecision.navigate; + }, + ), + ); + + // request + controller.loadRequest( + Uri.parse(widget.control.getString("url", "https://flet.dev")!), + method: parseLoadRequestMethod( + widget.control.getString("method"), LoadRequestMethod.get)!); + + _setOptionalEventHandlers(); + } + + Future _invokeMethod(String name, dynamic args) async { + debugPrint("WebView.$name($args)"); + switch (name) { + case "reload": + await controller.reload(); + break; + case "can_go_back": + return controller.canGoBack(); + case "can_go_forward": + return controller.canGoForward(); + case "go_back": + if (await controller.canGoBack()) { + await controller.goBack(); + } + break; + case "go_forward": + if (await controller.canGoForward()) { + await controller.goForward(); + } + break; + case "enable_zoom": + await controller.enableZoom(true); + break; + case "disable_zoom": + await controller.enableZoom(false); + break; + case "clear_cache": + await controller.clearCache(); + break; + case "clear_local_storage": + await controller.clearLocalStorage(); + break; + case "get_current_url": + return await controller.currentUrl(); + case "get_title": + return await controller.getTitle(); + case "get_user_agent": + return await controller.getUserAgent(); + case "load_file": + await controller.loadFile(args["path"]); + break; + case "load_html": + await controller.loadHtmlString(args["value"], + baseUrl: args["base_url"]); + break; + case "load_request": + var url = args["url"]; + if (url != null) { + await controller.loadRequest(Uri.parse(url), + method: parseLoadRequestMethod( + args["method"], LoadRequestMethod.get)!); + } + break; + case "run_javascript": + var javascript = args["value"]; + if (javascript != null) { + await controller.runJavaScript(javascript); + } + break; + case "scroll_to": + var x = parseInt(args["x"]); + var y = parseInt(args["y"]); + if (x != null && y != null) { + await controller.scrollTo(x, y); + } + break; + case "scroll_by": + var x = parseInt(args["x"]); + var y = parseInt(args["y"]); + if (x != null && y != null) { + await controller.scrollBy(x, y); + } + break; + case "set_javascript_mode": + var mode = parseJavaScriptMode(args["mode"]); + if (mode != null) { + await controller.setJavaScriptMode(mode); + } + break; + default: + throw Exception("Unknown WebView method: $name"); + } + } + + @override + void dispose() { + debugPrint("WebViewControl dispose: ${widget.control.id}"); + widget.control.removeInvokeMethodListener(_invokeMethod); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + debugPrint("WebViewControl build: ${widget.control.id}"); + + _setOptionalEventHandlers(); + + var bgcolor = widget.control.getColor("bgcolor", context); + + if (bgcolor != null) { + controller.setBackgroundColor(bgcolor); + } + return WebViewWidget(controller: controller); + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_web.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_web.dart new file mode 100644 index 0000000000..fff692b2eb --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_web.dart @@ -0,0 +1,37 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:webview_flutter_platform_interface/webview_flutter_platform_interface.dart'; +import 'package:webview_flutter_web/webview_flutter_web.dart'; + +class WebviewWeb extends StatefulWidget { + final Control control; + + const WebviewWeb({super.key, required this.control}); + + @override + State createState() => _WebviewWebState(); +} + +class _WebviewWebState extends State { + late PlatformWebViewController controller; + @override + void initState() { + super.initState(); + WebViewPlatform.instance = WebWebViewPlatform(); + + controller = PlatformWebViewController( + const PlatformWebViewControllerCreationParams(), + )..loadRequest( + LoadRequestParams( + uri: Uri.parse( + widget.control.getString("url", "https://flet.dev")!)), + ); + } + + @override + Widget build(BuildContext context) { + return PlatformWebViewWidget( + PlatformWebViewWidgetCreationParams(controller: controller), + ).build(context); + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_web_vain.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_web_vain.dart new file mode 100644 index 0000000000..a93c40a1a4 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_web_vain.dart @@ -0,0 +1,12 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +class WebviewWeb extends StatelessWidget { + final Control control; + + const WebviewWeb({super.key, required this.control}); + @override + Widget build(BuildContext context) { + return const ErrorControl("Webview is not yet supported on this platform."); + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_windows_and_linux.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_windows_and_linux.dart new file mode 100644 index 0000000000..8510a8ee4b --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_windows_and_linux.dart @@ -0,0 +1,11 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +class WebviewDesktop extends StatelessWidget { + const WebviewDesktop({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return const ErrorControl("Webview is not yet supported on this Platform."); + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_windows_and_linux_vain.dart b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_windows_and_linux_vain.dart new file mode 100644 index 0000000000..2b03b80508 --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/lib/src/webview_windows_and_linux_vain.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +class WebviewDesktop extends StatefulWidget { + const WebviewDesktop({Key? key}) : super(key: key); + + @override + State createState() => _WebviewDesktopState(); +} + +class _WebviewDesktopState extends State { + @override + Widget build(BuildContext context) { + return const ErrorControl("Webview is not yet supported on this Platform."); + } +} diff --git a/sdk/python/packages/flet-webview/src/flutter/flet_webview/pubspec.yaml b/sdk/python/packages/flet-webview/src/flutter/flet_webview/pubspec.yaml new file mode 100644 index 0000000000..0e86b38b7c --- /dev/null +++ b/sdk/python/packages/flet-webview/src/flutter/flet_webview/pubspec.yaml @@ -0,0 +1,27 @@ +name: flet_webview +description: Flet WebView control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + + collection: ^1.16.0 + webview_flutter: ^4.13.1 + webview_flutter_web: 0.2.3+4 + webview_flutter_platform_interface: 2.14.0 + + flet: + path: ../../../../../../../packages/flet + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/packages/flet/README.md b/sdk/python/packages/flet/README.md index 0635dd8ef4..b07edde94c 100644 --- a/sdk/python/packages/flet/README.md +++ b/sdk/python/packages/flet/README.md @@ -1,78 +1,143 @@ -# Flet - quickly build interactive apps for web, desktop and mobile in Python +

+ Flet logo +

-[Flet](https://flet.dev) is a rich User Interface (UI) framework to quickly build interactive web, desktop and mobile apps in Python without prior knowledge of web technologies like HTTP, HTML, CSS or JavaScript. You build UI with [controls](https://flet.dev/docs/controls) based on [Flutter](https://flutter.dev/) widgets to ensure your programs look cool and professional. +

+ Build multi-platform apps in Python. No frontend experience required. +

-## Requirements +

+ + License + + Package version + + Monthly downloads + + Python >= 3.10 + + Build status + + Docstring coverage +

-* Python 3.7 or above on Windows, Linux or macOS +--- -## Installation +Flet is a framework that allows building mobile, desktop and web applications +in Python only without prior experience in frontend development. -``` -pip install flet -``` +###    Single code base for any device + +Your app will equally look great on iOS, Android, Windows, Linux, macOS and web. + +###    Build an entire app in Python + +Build a cross-platform app without knowledge of Dart, Swift, Kotlin, HTML or JavaScript - only Python! + +###    150+ built-in controls and services + +Beautiful UI widgets with Material and Cupertino design: layout, navigation, dialogs, charts - Flet uses Flutter to render UI. + +###    50+ Python packages for iOS and Android + +Numpy, pandas, pydantic, cryptography, opencv, pillow and other popular libraries. + +###    Full web support + +Flet apps run natively in modern browsers using WebAssembly and Pyodide, with no server required. Prefer server-side? Deploy as a Python web app with real-time UI updates. + +###    Built-in packaging + +Build standalone executables or bundles for iOS, Android, Windows, Linux, macOS and web. Instantly deploy to App Store and Google Play. -## Create the app +###    Test on iOS and Android -Create `main.py` file with the following content: +Test your project on your own mobile device with Flet App. See your app updates as you make changes. -```python +###    Extensible + +Easily wrap any of thousands of Flutter packages to use with Flet or build new controls in pure Python using built-in UI primitives. + +###    Accessible + +Flet is built with Flutter which has solid accessibility foundations on Android, iOS, web, and desktop. + +## Flet app example + +Below is a simple "Counter" app, with a text field and two buttons to increment and decrement the counter value: + +```python title="counter.py" import flet as ft def main(page: ft.Page): page.title = "Flet counter example" page.vertical_alignment = ft.MainAxisAlignment.CENTER - txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + input = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) def minus_click(e): - txt_number.value = str(int(txt_number.value) - 1) - page.update() + input.value = str(int(input.value) - 1) def plus_click(e): - txt_number.value = str(int(txt_number.value) + 1) - page.update() + input.value = str(int(input.value) + 1) page.add( ft.Row( - [ - ft.IconButton(ft.icons.REMOVE, on_click=minus_click), - txt_number, - ft.IconButton(ft.icons.ADD, on_click=plus_click), - ], alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + input, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], ) ) -ft.app(main) +ft.run(main) ``` -## Run as a desktop app - -The following command will start the app in a native OS window: +To run the app, install `flet`: +```bash +pip install 'flet[all]' ``` -flet run main.py + +then launch the app: + +```bash +flet run counter.py ``` -![Sample app in a native window](https://flet.dev/img/docs/getting-started/flet-counter-macos.png) +This will open the app in a native OS window - what a nice alternative to Electron! 🙂 -## Run as a web app +

+ +

-The following command will start the app as a web app: +To run the same app as a web app use `--web` option with `flet run` command: -``` -flet run --web main.py +```bash +flet run --web counter.py ``` -![Sample app in a browser](https://flet.dev/img/docs/getting-started/flet-counter-safari.png) +

+ +

## Learn more -Visit [Flet website](https://flet.dev). +* [Website](https://flet.dev) +* [Documentation](https://flet.dev/docs/) +* [Roadmap](https://flet.dev/roadmap) +* [Apps Gallery](https://flet.dev/gallery) + +## Community -Continue with [Python guide](https://flet.dev/docs/getting-started/python) to learn how to make a real app. +* [Discussions](https://github.com/flet-dev/flet/discussions) +* [Discord](https://discord.gg/dzWXP8SHG8) +* [X (Twitter)](https://twitter.com/fletdev) +* [Bluesky](https://bsky.app/profile/fletdev.bsky.social) +* [Email us](mailto:hello@flet.dev) -Browse for more [Flet examples](https://github.com/flet-dev/examples/tree/main/python). +## Contributing -Join to a conversation on [Flet Discord server](https://discord.gg/dzWXP8SHG8). +Want to help improve Flet? Check out the [contribution guide](https://flet.dev/docs/contributing). diff --git a/sdk/python/packages/flet/integration_tests/.gitignore b/sdk/python/packages/flet/integration_tests/.gitignore new file mode 100644 index 0000000000..e902247845 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/.gitignore @@ -0,0 +1 @@ +*_actual.png \ No newline at end of file diff --git a/sdk/python/packages/flet/integration_tests/README.md b/sdk/python/packages/flet/integration_tests/README.md new file mode 100644 index 0000000000..e6cc7a484c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/README.md @@ -0,0 +1,79 @@ +# Flet tests + +## Commands + +Running **all** tests in directory with output and log debug output: + +```bash +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests +``` + +Running tests by suite: + +```bash +# Core +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/core + +# Material +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/material + +# Cupertino +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/cupertino + +# Theme +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/theme + +# Types +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/types + +# Services +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/services +``` + +Running **single file** tests with output and log debug output: + +```bash +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/material/test_button.py +``` + +Running **single test** with output and log debug output: + +```bash +uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests/controls/material/test_button.py -k test_basic +``` + +Running tests on iOS simulator: + +```bash +FLET_TEST_DEVICE= uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests +``` + +Running tests on Android simulator: + +```bash +FLET_TEST_DEVICE= FLET_TEST_PLATFORM=android uv run pytest -s -o log_cli=true -o log_cli_level=DEBUG packages/flet/integration_tests +``` + +Running test to create golden images: + +```bash +FLET_TEST_GOLDEN=1 uv run pytest -s -o log_cli=true -o log_cli_level=INFO packages/flet/integration_tests/controls/material/test_button.py +``` + +## Environment variables + +`FLET_TEST_PLATFORM` - The platform on which tests are running: `macos`, `windows`, `linux`, `android` or `ios`. Desktop platforms are detected automatically if not specified. + +`FLET_TEST_DEVICE` - The device to run tests on. For running tests on desktop: `macos`, `windows` or `linux` - detected automatically if not specified. To run on iOS, Android or a real device a device ID must be specified that can be obtained with `flutter devices` command. + +`FLET_TEST_GOLDEN` - Run tests to take "golden" (expected) screenshots and writing them to a file system. + +`FLET_TEST_SCREENSHOTS_PIXEL_RATIO` - device pixel ration to use to take screenshots. Default is 2.0. + +`FLET_TEST_SCREENSHOTS_SIMILARITY_THRESHOLD` - a minimum value for comparison result of golden and actual screenshot for a test to pass. Default is 99.0. + +`FLET_TEST_USE_HTTP` - run Flet app in a web server. By default, the app starts socket +server, but if integration tests use assets they could be inaccessible via TCP from iOS or +Android device or simulator. + +`FLET_TEST_DISABLE_FVM` - `True` to launch Flutter process directly, without `fvm`. This setting could be on in CI environment. Locally we normally want to run with `fvm`. diff --git a/sdk/python/packages/flet/integration_tests/apps/autoupdate/__init__.py b/sdk/python/packages/flet/integration_tests/apps/autoupdate/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/integration_tests/apps/autoupdate/app.py b/sdk/python/packages/flet/integration_tests/apps/autoupdate/app.py new file mode 100644 index 0000000000..79e67b65cc --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/autoupdate/app.py @@ -0,0 +1,47 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Autoupdate test" + + def auto_update_global_enabled_click(e): + assert ft.context.page + page.controls.append(ft.Text("Global auto update")) + + def disable_autoupdate_no_update_click(e): + ft.context.disable_auto_update() + page.controls.append(ft.Text("Auto update no update")) + + def disable_autoupdate_with_update_click(e): + ft.context.disable_auto_update() + page.controls.append(ft.Text("Auto update with update")) + page.update() + + def skip_autoupdate_after_update_called_click(e): + page.controls.append(ft.Text("This text should not appear")) + skip_button.content = "Button content updated" + skip_button.update() + + assert ft.context.page + page.add( + ft.Text(f"Auto update enabled: {ft.context.auto_update_enabled()}"), + ft.Button( + "auto_update_global_enabled", on_click=auto_update_global_enabled_click + ), + ft.Button( + "disable_autoupdate_no_update", + on_click=disable_autoupdate_no_update_click, + ), + ft.Button( + "disable_autoupdate_with_update", + on_click=disable_autoupdate_with_update_click, + ), + skip_button := ft.Button( + "skip_autoupdate_after_update_called", + on_click=skip_autoupdate_after_update_called_click, + ), + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/packages/flet/integration_tests/apps/autoupdate/test_autoupdate.py b/sdk/python/packages/flet/integration_tests/apps/autoupdate/test_autoupdate.py new file mode 100644 index 0000000000..0546599cf9 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/autoupdate/test_autoupdate.py @@ -0,0 +1,54 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +from . import app + + +@pytest.mark.parametrize( + "flet_app", + [ + { + "flet_app_main": app.main, + } + ], + indirect=True, +) +class TestApp: + @pytest.mark.asyncio(loop_scope="module") + async def test_auto_update(self, flet_app: ftt.FletTestApp): + tester = flet_app.tester + await tester.pump_and_settle() + auto_update_enabled = await tester.find_by_text("Auto update enabled: True") + assert auto_update_enabled.count == 1 + + # tap 1st button + await tester.tap(await tester.find_by_text("auto_update_global_enabled")) + await tester.pump_and_settle() + assert (await tester.find_by_text("Global auto update")).count == 1 + + # tap 2nd button + await tester.tap(await tester.find_by_text("disable_autoupdate_no_update")) + await tester.pump_and_settle() + assert (await tester.find_by_text("Auto update no update")).count == 0 + + # tap 3rd button + await tester.tap(await tester.find_by_text("disable_autoupdate_with_update")) + await tester.pump_and_settle() + assert (await tester.find_by_text("Auto update with update")).count == 1 + assert (await tester.find_by_text("Auto update no update")).count == 1 + + # tap 4th button + await tester.tap( + await tester.find_by_text("skip_autoupdate_after_update_called") + ) + await tester.pump_and_settle() + assert (await tester.find_by_text("This text should not appear")).count == 0 + assert (await tester.find_by_text("Button content updated")).count == 1 + + +@pytest.mark.asyncio(loop_scope="module") +async def test_context_throws_exception_outside_flet_app(): + with pytest.raises(Exception, match="The context is not associated with any page."): + p = ft.context.page # noqa: F841 diff --git a/sdk/python/packages/flet/integration_tests/apps/counter/__init__.py b/sdk/python/packages/flet/integration_tests/apps/counter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/integration_tests/apps/counter/app.py b/sdk/python/packages/flet/integration_tests/apps/counter/app.py new file mode 100644 index 0000000000..ac8fd1d1fa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/counter/app.py @@ -0,0 +1,31 @@ +import flet as ft + + +def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + page.update() + + page.add( + ft.Row( + [ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click, key="decrement"), + txt_number, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + ) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/packages/flet/integration_tests/apps/counter/test_counter_app.py b/sdk/python/packages/flet/integration_tests/apps/counter/test_counter_app.py new file mode 100644 index 0000000000..3933b42cd3 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/counter/test_counter_app.py @@ -0,0 +1,39 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +from . import app + + +@pytest.mark.parametrize( + "flet_app", + [ + { + "flet_app_main": app.main, + } + ], + indirect=True, +) +class TestApp: + @pytest.mark.asyncio(loop_scope="module") + async def test_app(self, flet_app: ftt.FletTestApp): + tester = flet_app.tester + await tester.pump_and_settle() + zero_text = await tester.find_by_text("0") + assert zero_text.count == 1 + + # tap increment button + increment_btn = await tester.find_by_icon(ft.Icons.ADD) + assert increment_btn.count == 1 + await tester.tap(increment_btn) + await tester.pump_and_settle() + assert (await tester.find_by_text("1")).count == 1 + + # tap decrement button + decrement_button = await tester.find_by_key("decrement") + assert decrement_button.count == 1 + await tester.tap(decrement_button) + await tester.tap(decrement_button) + await tester.pump_and_settle() + assert (await tester.find_by_text("-1")).count == 1 diff --git a/sdk/python/packages/flet/integration_tests/apps/finders/__init__.py b/sdk/python/packages/flet/integration_tests/apps/finders/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/integration_tests/apps/finders/app.py b/sdk/python/packages/flet/integration_tests/apps/finders/app.py new file mode 100644 index 0000000000..edcd78efdf --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/finders/app.py @@ -0,0 +1,29 @@ +import flet as ft + + +async def main(page: ft.Page): + print("Test mode:", page.test) + page.window.width = 800 + page.add(ft.Text("Hello, world!")) + page.add(ft.Button("Button_1")) + page.add(ft.Button("Button_2")) + page.add(ft.Text("Hello, world!!!")) + page.add(ft.Text("__world!")) + page.add( + ft.Text( + spans=[ + ft.TextSpan( + "Hello, world!", + style=ft.TextStyle(weight=ft.FontWeight.BOLD, italic=True), + ) + ] + ) + ) + page.add(ft.IconButton(ft.Icons.ADD_A_PHOTO)) + page.add(ft.Checkbox(label="Hello", key=ft.ValueKey("value_key_1"))) + page.add(ft.TextField(label="Full name", key=ft.ScrollKey("scroll_key_1"))) + page.add(ft.Button("Click me", tooltip="Tooltip1")) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/packages/flet/integration_tests/apps/finders/test_finders.py b/sdk/python/packages/flet/integration_tests/apps/finders/test_finders.py new file mode 100644 index 0000000000..24c74c5a24 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/finders/test_finders.py @@ -0,0 +1,55 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +from . import app + + +@pytest.mark.parametrize( + "flet_app", + [ + { + "flet_app_main": app.main, + } + ], + indirect=True, +) +class TestFinders: + @pytest.mark.asyncio(loop_scope="module") + async def test_find_by_text(self, flet_app: ftt.FletTestApp): + await flet_app.tester.pump(1000) + finder = await flet_app.tester.find_by_text("Hello, world!") + assert finder.count == 2 + + @pytest.mark.asyncio(loop_scope="module") + async def test_find_by_text_containing(self, flet_app: ftt.FletTestApp): + finder = await flet_app.tester.find_by_text_containing("Hello, world!") + assert finder.count == 3 + + finder = await flet_app.tester.find_by_text_containing("Hello") + assert finder.count == 4 + + finder = await flet_app.tester.find_by_text_containing("(\\s+)world") + assert finder.count == 3 + + finder = await flet_app.tester.find_by_text_containing("world!$") + assert finder.count == 3 + + @pytest.mark.asyncio(loop_scope="module") + async def test_find_by_icon(self, flet_app: ftt.FletTestApp): + finder = await flet_app.tester.find_by_icon(ft.Icons.ADD_A_PHOTO) + assert finder.count == 1 + + @pytest.mark.asyncio(loop_scope="module") + async def test_find_by_tooltip(self, flet_app: ftt.FletTestApp): + finder = await flet_app.tester.find_by_tooltip("Tooltip1") + assert finder.count == 1 + + @pytest.mark.asyncio(loop_scope="module") + async def test_find_by_key(self, flet_app: ftt.FletTestApp): + finder = await flet_app.tester.find_by_key("value_key_1") + assert finder.count == 1 + + finder = await flet_app.tester.find_by_key(ft.ScrollKey("scroll_key_1")) + assert finder.count == 1 diff --git a/sdk/python/packages/flet/integration_tests/apps/hello_world/__init__.py b/sdk/python/packages/flet/integration_tests/apps/hello_world/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/integration_tests/apps/hello_world/app.py b/sdk/python/packages/flet/integration_tests/apps/hello_world/app.py new file mode 100644 index 0000000000..0fbaee7489 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/hello_world/app.py @@ -0,0 +1,11 @@ +import flet as ft + + +async def main(page: ft.Page): + print("Test mode:", page.test) + page.window.width = 400 + page.add(ft.Text("Hello, world!")) + + +if __name__ == "__main__": + ft.run(main) diff --git a/sdk/python/packages/flet/integration_tests/apps/hello_world/test_hello_world_app.py b/sdk/python/packages/flet/integration_tests/apps/hello_world/test_hello_world_app.py new file mode 100644 index 0000000000..f1e5bb2fb5 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/apps/hello_world/test_hello_world_app.py @@ -0,0 +1,35 @@ +import pytest + +import flet.testing as ftt + +from . import app + + +@pytest.mark.parametrize( + "flet_app", + [ + { + "flet_app_main": app.main, + } + ], + indirect=True, +) +class TestHelloWorld: + @pytest.mark.asyncio(loop_scope="module") + async def test_app(self, flet_app: ftt.FletTestApp): + await flet_app.tester.pump_and_settle() + finder = await flet_app.tester.find_by_text("Hello, world!") + assert finder.count == 1 + # bytes = await flet_app.tester.take_screenshot("scr1") + # p = Path(get_current_script_dir(), "scr_1.png") + # print(p) + # with open(p, "wb") as f: + # f.write(bytes) + + @pytest.mark.asyncio(loop_scope="module") + async def test_1(self, flet_app: ftt.FletTestApp): + print("Test 1") + + @pytest.mark.asyncio(loop_scope="module") + async def test_2(self, flet_app: ftt.FletTestApp): + print("Test 2") diff --git a/sdk/python/packages/flet/integration_tests/assets/141-50x50.jpg b/sdk/python/packages/flet/integration_tests/assets/141-50x50.jpg new file mode 100644 index 0000000000..2fcb73ebe9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/assets/141-50x50.jpg differ diff --git a/sdk/python/packages/flet/integration_tests/assets/52-100x100.png b/sdk/python/packages/flet/integration_tests/assets/52-100x100.png new file mode 100644 index 0000000000..0cee0b6abc Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/assets/52-100x100.png differ diff --git a/sdk/python/packages/flet/integration_tests/assets/assets/icon-192.png b/sdk/python/packages/flet/integration_tests/assets/assets/icon-192.png new file mode 100644 index 0000000000..65da3b9571 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/assets/assets/icon-192.png differ diff --git a/sdk/python/packages/flet/integration_tests/assets/logo.svg b/sdk/python/packages/flet/integration_tests/assets/logo.svg new file mode 100644 index 0000000000..4762afefc6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/assets/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/sdk/python/packages/flet/integration_tests/assets/minion.png b/sdk/python/packages/flet/integration_tests/assets/minion.png new file mode 100644 index 0000000000..a760674567 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/assets/minion.png differ diff --git a/sdk/python/packages/flet/integration_tests/conftest.py b/sdk/python/packages/flet/integration_tests/conftest.py new file mode 100644 index 0000000000..45abb11e5d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/conftest.py @@ -0,0 +1,50 @@ +from pathlib import Path + +import pytest_asyncio + +import flet.testing as ftt +from flet.controls.context import _context_page, context + + +def create_flet_app(request): + params = getattr(request, "param", {}) + return ftt.FletTestApp( + flutter_app_dir=(Path(__file__).parent / "../../../../../client").resolve(), + test_path=request.fspath, + flet_app_main=params.get("flet_app_main"), + skip_pump_and_settle=params.get("skip_pump_and_settle", False), + assets_dir=Path(__file__).resolve().parent / "assets", + ) + + +@pytest_asyncio.fixture(scope="module") +async def flet_app(request): + """ + Module-scoped Flet app fixture. + Does not bind `ft.context.page`. + """ + flet_app = create_flet_app(request) + await flet_app.start() + yield flet_app + await flet_app.teardown() + + +@pytest_asyncio.fixture(scope="function") +async def flet_app_function(request): + """ + Function-scoped Flet app fixture. + Binds and resets `ft.context.page` per test. + """ + flet_app = create_flet_app(request) + await flet_app.start() + + # make page available via ft.context.page + token = _context_page.set(flet_app.page) + context.reset_auto_update() + + try: + yield flet_app + finally: + _context_page.reset(token) # restore previous context to avoid leakage + context.disable_components_mode() + await flet_app.teardown() diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/ios/buttons/button_1.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/ios/buttons/button_1.png new file mode 100644 index 0000000000..fa55a99c02 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/ios/buttons/button_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/ios/buttons/button_2.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/ios/buttons/button_2.png new file mode 100644 index 0000000000..26cc4d4094 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/ios/buttons/button_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_1.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_1.png new file mode 100644 index 0000000000..bb62c6c29b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_2.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_2.png new file mode 100644 index 0000000000..76301cb293 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_3.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_3.png new file mode 100644 index 0000000000..82191fb3d3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/capture_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_arc.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_arc.png new file mode 100644 index 0000000000..0f6f674cb7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_arc.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_asset_image.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_asset_image.png new file mode 100644 index 0000000000..0a7afc4021 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_asset_image.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_bytes_image.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_bytes_image.png new file mode 100644 index 0000000000..b0dd81ad0a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_bytes_image.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_circle.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_circle.png new file mode 100644 index 0000000000..05e8034b65 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_circle.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_color.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_color.png new file mode 100644 index 0000000000..4ec988bc5d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_color.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_arc.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_arc.png new file mode 100644 index 0000000000..ef34d2a61d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_arc.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_arc_with_center.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_arc_with_center.png new file mode 100644 index 0000000000..3b983c0eb6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_arc_with_center.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_circle.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_circle.png new file mode 100644 index 0000000000..8c8f848be2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_circle.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_line.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_line.png new file mode 100644 index 0000000000..42f6a9aa3e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_line.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_oval.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_oval.png new file mode 100644 index 0000000000..58f962a068 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_oval.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_path_with_fill.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_path_with_fill.png new file mode 100644 index 0000000000..0b725e1601 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_path_with_fill.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_rect.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_rect.png new file mode 100644 index 0000000000..879b063bff Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_dashed_rect.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_filled_circle_default_paint.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_filled_circle_default_paint.png new file mode 100644 index 0000000000..793feb4698 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_filled_circle_default_paint.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_filled_rect.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_filled_rect.png new file mode 100644 index 0000000000..cf5075b4c7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_filled_rect.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_flet_logo_with_path.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_flet_logo_with_path.png new file mode 100644 index 0000000000..722fd7fba4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_flet_logo_with_path.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_gradients.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_gradients.png new file mode 100644 index 0000000000..a8b7f81afd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_gradients.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_line.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_line.png new file mode 100644 index 0000000000..82191fb3d3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_line.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_oval.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_oval.png new file mode 100644 index 0000000000..b7e633bd02 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_oval.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_lines.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_lines.png new file mode 100644 index 0000000000..7172a398a9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_lines.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_points.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_points.png new file mode 100644 index 0000000000..b443cadc9a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_points.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_polygon.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_polygon.png new file mode 100644 index 0000000000..af8bd6c851 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_points_as_polygon.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_shadow.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_shadow.png new file mode 100644 index 0000000000..5221912016 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_shadow.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_text.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_text.png new file mode 100644 index 0000000000..4ff8717763 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_text.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_url_image.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_url_image.png new file mode 100644 index 0000000000..e188f98943 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/canvas/draw_url_image.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/column/column_basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/column/column_basic.png new file mode 100644 index 0000000000..36570a7858 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/column/column_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/container/container_basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/container/container_basic.png new file mode 100644 index 0000000000..2d3bdeec90 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/container/container_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/badge.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/badge.png new file mode 100644 index 0000000000..1f5b121b77 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/badge.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/col.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/col.png new file mode 100644 index 0000000000..8f6c1ba707 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/col.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/disabled_propagates_to_children.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/disabled_propagates_to_children.png new file mode 100644 index 0000000000..4abac211aa Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/disabled_propagates_to_children.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/opacity.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/opacity.png new file mode 100644 index 0000000000..e609bd2719 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/opacity.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/parent_not_visible_child_visible.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/parent_not_visible_child_visible.png new file mode 100644 index 0000000000..557ec60930 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/parent_not_visible_child_visible.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/rtl.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/rtl.png new file mode 100644 index 0000000000..7c9208ac77 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/rtl.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/tooltip_custom_properties_on_hover.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/tooltip_custom_properties_on_hover.png new file mode 100644 index 0000000000..d53718772c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/tooltip_custom_properties_on_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/tooltip_shows_on_hover.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/tooltip_shows_on_hover.png new file mode 100644 index 0000000000..c8017d2381 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/tooltip_shows_on_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/visible.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/visible.png new file mode 100644 index 0000000000..41d814e99f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control/visible.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control_isolated/tooltip_custom_properties_on_hover.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control_isolated/tooltip_custom_properties_on_hover.png new file mode 100644 index 0000000000..d53718772c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control_isolated/tooltip_custom_properties_on_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control_isolated/tooltip_shows_on_hover.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control_isolated/tooltip_shows_on_hover.png new file mode 100644 index 0000000000..c8017d2381 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/control_isolated/tooltip_shows_on_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/dismissible/dismissible_basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/dismissible/dismissible_basic.png new file mode 100644 index 0000000000..644bfa935c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/dismissible/dismissible_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/dismissible/dismissible_properties.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/dismissible/dismissible_properties.png new file mode 100644 index 0000000000..7a599f82cd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/dismissible/dismissible_properties.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/icon/basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/icon/basic.png new file mode 100644 index 0000000000..ab71dbee7c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/icon/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/icon/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/icon/theme_1.png new file mode 100644 index 0000000000..5a2b9bc831 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/icon/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/placeholder_1.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/placeholder_1.png new file mode 100644 index 0000000000..5dd519f7bd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/placeholder_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/placeholder_2.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/placeholder_2.png new file mode 100644 index 0000000000..8c32183fd2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/placeholder_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_base64.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_base64.png new file mode 100644 index 0000000000..e5600106b8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_base64.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_bytes.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_bytes.png new file mode 100644 index 0000000000..e5600106b8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_bytes.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_png.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_png.png new file mode 100644 index 0000000000..8c32183fd2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_png.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_svg_string.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_svg_string.png new file mode 100644 index 0000000000..abe665e9b3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_svg_string.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_svg_url.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_svg_url.png new file mode 100644 index 0000000000..abe665e9b3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/image/src_svg_url.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/align_inside_container.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/align_inside_container.png new file mode 100644 index 0000000000..e2e8ee131c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/align_inside_container.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/align_inside_stack.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/align_inside_stack.png new file mode 100644 index 0000000000..1a1d90c14c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/align_inside_stack.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/animate_position.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/animate_position.png new file mode 100644 index 0000000000..5a5f7af442 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/animate_position.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/aspect_ratio.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/aspect_ratio.png new file mode 100644 index 0000000000..51cac3511c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/aspect_ratio.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/flip.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/flip.png new file mode 100644 index 0000000000..ad55d18415 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/flip.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/margin_around.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/margin_around.png new file mode 100644 index 0000000000..815832a3b6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/margin_around.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/margin_bottom_right.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/margin_bottom_right.png new file mode 100644 index 0000000000..a4bb8d5559 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/margin_bottom_right.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_mirrored_spin.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_mirrored_spin.png new file mode 100644 index 0000000000..75e7a181c5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_mirrored_spin.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_multiply_chain.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_multiply_chain.png new file mode 100644 index 0000000000..f7d53ef9d8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_multiply_chain.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_perspective_tilt.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_perspective_tilt.png new file mode 100644 index 0000000000..cb7dea745d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_perspective_tilt.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_skew_and_rotate.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_skew_and_rotate.png new file mode 100644 index 0000000000..24715edfad Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/matrix4_skew_and_rotate.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/offset.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/offset.png new file mode 100644 index 0000000000..18d312e431 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/offset.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/position_constraint_combinations.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/position_constraint_combinations.png new file mode 100644 index 0000000000..a7c9374138 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/position_constraint_combinations.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/position_right_bottom.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/position_right_bottom.png new file mode 100644 index 0000000000..9e24f8869c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/position_right_bottom.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/rotate.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/rotate.png new file mode 100644 index 0000000000..4e91bd6d5f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/rotate.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/rotate_numeric_value.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/rotate_numeric_value.png new file mode 100644 index 0000000000..b139476417 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/rotate_numeric_value.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/scale.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/scale.png new file mode 100644 index 0000000000..8745d43792 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/scale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/scale_numeric_value.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/scale_numeric_value.png new file mode 100644 index 0000000000..9d5bd433ab Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/layout_control/scale_numeric_value.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/page_view/basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/page_view/basic.png new file mode 100644 index 0000000000..5f730f097f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/page_view/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/page_view/unbounded_height.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/page_view/unbounded_height.png new file mode 100644 index 0000000000..a592ce77b5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/page_view/unbounded_height.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/auto_size_1.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/auto_size_1.png new file mode 100644 index 0000000000..07a1acfb7b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/auto_size_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/auto_size_2.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/auto_size_2.png new file mode 100644 index 0000000000..e268b1f101 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/auto_size_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/cupertino_adaptive.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/cupertino_adaptive.png new file mode 100644 index 0000000000..64f24b93e4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/cupertino_adaptive.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/explicitly_sized.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/explicitly_sized.png new file mode 100644 index 0000000000..e52623d614 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/explicitly_sized.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/unbounded_height.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/unbounded_height.png new file mode 100644 index 0000000000..124d2a6572 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/pagelet/unbounded_height.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/placeholder/placeholder_basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/placeholder/placeholder_basic.png new file mode 100644 index 0000000000..d7562c1f4e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/placeholder/placeholder_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/responsive_row_basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/responsive_row_basic.png new file mode 100644 index 0000000000..3208149ab8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/responsive_row_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/unbounded_width.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/unbounded_width.png new file mode 100644 index 0000000000..5f8fc7f374 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/unbounded_width.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/zero_col_controls_are_hidden_at_breakpoint.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/zero_col_controls_are_hidden_at_breakpoint.png new file mode 100644 index 0000000000..4c7f526994 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/responsive_row/zero_col_controls_are_hidden_at_breakpoint.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/rotated_box/rotated_box.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/rotated_box/rotated_box.png new file mode 100644 index 0000000000..5fb76e6e33 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/rotated_box/rotated_box.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/row/row_basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/row/row_basic.png new file mode 100644 index 0000000000..c8e67bfb08 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/row/row_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/basic.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/basic.png new file mode 100644 index 0000000000..bd4182879e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/bold.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/bold.png new file mode 100644 index 0000000000..de981b0c56 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/bold.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/overflow.png b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/overflow.png new file mode 100644 index 0000000000..ffcd10d1ae Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/core/golden/macos/text/overflow.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_canvas.py b/sdk/python/packages/flet/integration_tests/controls/core/test_canvas.py new file mode 100644 index 0000000000..2b385b984b --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_canvas.py @@ -0,0 +1,763 @@ +import base64 +import math + +import pytest + +import flet as ft +import flet.canvas as fc +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_color(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [fc.Color(color=ft.Colors.DEEP_ORANGE_300)], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_points_as_points(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Points( + points=[ft.Offset(10, 20), ft.Offset(20, 40), ft.Offset(30, 10)], + point_mode=fc.PointMode.POINTS, + paint=ft.Paint( + stroke_width=6, + stroke_cap=ft.StrokeCap.ROUND, + color=ft.Colors.RED, + ), + ) + ], + width=50, + height=50, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_points_as_lines(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Points( + points=[ + ft.Offset(10, 20), + ft.Offset(20, 20), + ft.Offset(30, 10), + ft.Offset(30, 20), + ], + point_mode=fc.PointMode.LINES, + paint=ft.Paint( + stroke_width=3, + color=ft.Colors.BLUE, + ), + ) + ], + width=50, + height=50, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_points_as_polygon(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Points( + points=[ft.Offset(10, 20), ft.Offset(20, 40), ft.Offset(30, 10)], + point_mode=fc.PointMode.POLYGON, + paint=ft.Paint( + stroke_width=3, + color=ft.Colors.GREEN, + ), + ) + ], + width=50, + height=50, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +@pytest.mark.skip(reason="This test is temporarily disabled.") +async def test_draw_shadow(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Shadow( + path=[ + fc.Path.SubPath( + x=0, + y=0, + elements=[ + fc.Path.MoveTo(x=10, y=10), + fc.Path.LineTo(x=40, y=10), + fc.Path.LineTo(x=40, y=40), + fc.Path.LineTo(x=10, y=40), + fc.Path.LineTo(x=10, y=10), + ], + ), + ], + color=ft.Colors.PINK, + elevation=1, + ) + ], + width=50, + height=50, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_line(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [fc.Line(10, 10, 90, 90, ft.Paint(stroke_width=3))], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_line(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Line( + 10, + 10, + 90, + 90, + ft.Paint( + stroke_width=3, stroke_dash_pattern=[5, 5], color=ft.Colors.RED + ), + ) + ], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_circle(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Circle( + x=50, + y=50, + radius=40, + paint=ft.Paint(stroke_width=3, style=ft.PaintingStyle.STROKE), + ) + ], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_circle(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Circle( + x=50, + y=50, + radius=40, + paint=ft.Paint( + stroke_width=3, + stroke_dash_pattern=[5, 15], + color=ft.Colors.GREEN, + style=ft.PaintingStyle.STROKE, + ), + ) + ], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_filled_circle_default_paint(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [fc.Circle(x=50, y=50, radius=40, paint=ft.Paint())], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_oval(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Oval( + x=10, + y=10, + width=90, + height=40, + paint=ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE), + ) + ], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_oval(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Oval( + x=10, + y=10, + width=90, + height=40, + paint=ft.Paint( + stroke_width=2, + stroke_dash_pattern=[5, 15], + color=ft.Colors.GREEN, + style=ft.PaintingStyle.STROKE, + ), + ) + ], + width=100, + height=100, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_arc(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Arc( + 40, + 40, + 100, + 60, + math.pi * 0.1, + math.pi * 0.4, + paint=ft.Paint( + color=ft.Colors.YELLOW, + stroke_width=4, + style=ft.PaintingStyle.STROKE, + ), + ) + ], + width=200, + height=150, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_arc(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Arc( + 40, + 40, + 100, + 60, + math.pi * 0.1, + math.pi * 0.4, + paint=ft.Paint( + color=ft.Colors.AMBER, + stroke_width=4, + stroke_dash_pattern=[7, 7], + style=ft.PaintingStyle.STROKE, + ), + use_center=False, + ) + ], + width=200, + height=150, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_arc_with_center(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Arc( + x=40, + y=40, + width=100, + height=60, + start_angle=math.pi * 0.1, + sweep_angle=math.pi * 0.6, + paint=ft.Paint( + color=ft.Colors.AMBER, + stroke_width=4, + stroke_dash_pattern=[7, 7], + style=ft.PaintingStyle.STROKE, + ), + use_center=True, + ) + ], + width=200, + height=150, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_filled_rect(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Rect( + x=40, + y=40, + width=100, + height=60, + border_radius=5, + paint=ft.Paint( + color=ft.Colors.AMBER, + stroke_width=4, + ), + ) + ], + width=200, + height=150, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_rect(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Rect( + x=40, + y=40, + width=100, + height=60, + border_radius=5, + paint=ft.Paint( + color=ft.Colors.BLUE, + stroke_width=4, + stroke_dash_pattern=[3, 3], + style=ft.PaintingStyle.STROKE, + ), + ) + ], + width=200, + height=150, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_flet_logo_with_path(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Path( + elements=[ + fc.Path.MoveTo(25, 125), + fc.Path.QuadraticTo(50, 25, 135, 35, 0.35), + fc.Path.QuadraticTo(75, 115, 135, 215, 0.6), + fc.Path.QuadraticTo(50, 225, 25, 125, 0.35), + ], + paint=ft.Paint( + stroke_width=2, + style=ft.PaintingStyle.FILL, + color=ft.Colors.PINK_400, + ), + ), + fc.Path( + elements=[ + fc.Path.MoveTo(85, 125), + fc.Path.QuadraticTo(120, 85, 165, 75, 0.5), + fc.Path.QuadraticTo(120, 115, 165, 175, 0.3), + fc.Path.QuadraticTo(120, 165, 85, 125, 0.5), + ], + paint=ft.Paint( + stroke_width=2, + style=ft.PaintingStyle.FILL, + color=ft.Colors.with_opacity(0.5, ft.Colors.BLUE_400), + ), + ), + ], + width=300, + height=300, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_dashed_path_with_fill(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Fill( + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ) + ), + fc.Path( + paint=ft.Paint( + stroke_width=3, + stroke_dash_pattern=[3, 3], + style=ft.PaintingStyle.STROKE, + ), + elements=[ + fc.Path.MoveTo(75, 25), + fc.Path.QuadraticTo(25, 25, 25, 62.5), + fc.Path.QuadraticTo(25, 100, 50, 100), + fc.Path.QuadraticTo(50, 120, 30, 125), + fc.Path.QuadraticTo(60, 120, 65, 100), + fc.Path.QuadraticTo(125, 100, 125, 62.5), + fc.Path.QuadraticTo(125, 25, 75, 25), + ], + ), + ], + width=150, + height=150, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_text(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Fill( + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + color=ft.Colors.WHITE, + ) + ), + fc.Text( + x=0, + y=0, + value="Just a text", + ), + fc.Circle( + x=200, + y=100, + radius=2, + paint=ft.Paint(color=ft.Colors.RED), + ), + fc.Text( + x=200, + y=100, + style=ft.TextStyle(weight=ft.FontWeight.BOLD, size=30), + alignment=ft.Alignment.TOP_CENTER, + rotate=math.pi * 0.15, + value="Rotated", + spans=[ + ft.TextSpan( + text="around top_center", + style=ft.TextStyle( + italic=True, color=ft.Colors.GREEN, size=20 + ), + ) + ], + ), + fc.Circle( + x=400, + y=100, + radius=2, + paint=ft.Paint(color=ft.Colors.RED), + ), + fc.Text( + x=400, + y=100, + value="Rotated around top_left", + style=ft.TextStyle(size=20), + alignment=ft.Alignment.TOP_LEFT, + rotate=math.pi * -0.15, + ), + fc.Circle( + x=600, + y=200, + radius=2, + paint=ft.Paint(color=ft.Colors.RED), + ), + fc.Text( + x=600, + y=200, + value="Rotated around center", + style=ft.TextStyle(size=20), + alignment=ft.Alignment.CENTER, + rotate=math.pi / 2, + ), + fc.Text( + x=300, + y=400, + value="Limited to max_width and right-aligned.\n" + "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " + "do eiusmod tempor incididunt ut labore et dolore magna aliqua. " + "Ut enim ad minim veniam, quis nostrud exercitation ullamco " + "laboris nisi ut aliquip ex ea commodo consequat.", + text_align=ft.TextAlign.RIGHT, + max_width=400, + ), + fc.Text( + x=200, + y=200, + value="WOW!", + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=100, + foreground=ft.Paint( + color=ft.Colors.PINK, + stroke_width=6, + style=ft.PaintingStyle.STROKE, + stroke_join=ft.StrokeJoin.ROUND, + stroke_cap=ft.StrokeCap.ROUND, + ), + ), + ), + fc.Text( + x=200, + y=200, + value="WOW!", + style=ft.TextStyle( + weight=ft.FontWeight.BOLD, + size=100, + foreground=ft.Paint( + gradient=ft.PaintLinearGradient( + begin=(200, 200), + end=(300, 300), + colors=[ft.Colors.YELLOW, ft.Colors.RED], + ), + stroke_join=ft.StrokeJoin.ROUND, + stroke_cap=ft.StrokeCap.ROUND, + ), + ), + ), + ], + width=800, + height=500, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_gradients(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Rect( + x=10, + y=10, + width=100, + height=100, + border_radius=5, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintLinearGradient( + begin=(0, 10), + end=(100, 50), + colors=[ft.Colors.BLUE, ft.Colors.YELLOW], + ), + ), + ), + fc.Circle( + x=60, + y=170, + radius=50, + paint=ft.Paint( + style=ft.PaintingStyle.FILL, + gradient=ft.PaintRadialGradient( + radius=50, + center=(60, 170), + colors=[ft.Colors.YELLOW, ft.Colors.BLUE], + ), + ), + ), + fc.Path( + elements=[ + fc.Path.Arc( + x=10, + y=230, + width=100, + height=100, + start_angle=3 * math.pi / 4, + sweep_angle=3 * math.pi / 2, + ), + ], + paint=ft.Paint( + stroke_width=15, + stroke_join=ft.StrokeJoin.ROUND, + style=ft.PaintingStyle.STROKE, + gradient=ft.PaintSweepGradient( + start_angle=0, + end_angle=math.pi * 2, + rotation=3 * math.pi / 4, + center=(60, 280), + colors=[ft.Colors.YELLOW, ft.Colors.PURPLE], + color_stops=[0.0, 1.0], + ), + ), + ), + ], + width=150, + height=350, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_asset_image(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [fc.Image(src="52-100x100.png", x=10, y=10)], + width=120, + height=120, + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_url_image(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [ + fc.Image( + src="https://raw.githubusercontent.com/flet-dev/media/refs/heads/main/pictures/minion.png", + x=10, + y=10, + ) + ], + width=150, + height=150, + ), + pump_times=7, + pump_duration=1000, + ) + + +base64_string = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 + + +@pytest.mark.asyncio(loop_scope="module") +async def test_draw_bytes_image(flet_app: ftt.FletTestApp, request): + image_bytes = base64.b64decode(base64_string) + await flet_app.assert_control_screenshot( + request.node.name, + fc.Canvas( + [fc.Image(src=image_bytes, x=10, y=10)], + width=120, + height=120, + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_capture(flet_app: ftt.FletTestApp, request): + canvas = fc.Canvas( + [ + fc.Circle( + x=50, + y=50, + radius=40, + paint=ft.Paint( + stroke_width=3, + color=ft.Colors.GREEN, + style=ft.PaintingStyle.STROKE, + ), + ) + ], + width=100, + height=100, + ) + screenshot = ft.Screenshot(canvas) + + # clean page + flet_app.page.clean() + await flet_app.tester.pump_and_settle() + + # add canvas to a page, pump and settle + flet_app.page.add(screenshot) + await flet_app.tester.pump_and_settle() + + # ensure there is no initial capture + capture_0 = await canvas.get_capture() + assert capture_0 is None + + # take capture and assert + await canvas.capture(pixel_ratio=flet_app.screenshots_pixel_ratio) + capture_1 = await canvas.get_capture() + assert capture_1 is not None + flet_app.assert_screenshot("capture_1", capture_1) + + # clean canvas and draw a line + canvas.shapes = [fc.Line(10, 10, 90, 90, ft.Paint(stroke_width=3))] + canvas.update() + await flet_app.tester.pump_and_settle() + + # take screenshot + # it must be a circle striked out with a line (capture + shapes) + capture_2 = await screenshot.capture(pixel_ratio=flet_app.screenshots_pixel_ratio) + flet_app.assert_screenshot("capture_2", capture_2) + + # clean current capture + await canvas.clear_capture() + await flet_app.tester.pump_and_settle() + + # take screenshot + # it must be just a single line + capture_3 = await screenshot.capture(pixel_ratio=flet_app.screenshots_pixel_ratio) + flet_app.assert_screenshot("capture_3", capture_3) + + # back to empty capture + capture_4 = await canvas.get_capture() + assert capture_4 is None diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_column.py b/sdk/python/packages/flet/integration_tests/controls/core/test_column.py new file mode 100644 index 0000000000..e5f76fca04 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_column.py @@ -0,0 +1,14 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_column_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ft.Text("Item1"), ft.Text("Item2"), ft.Text("Item3")], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_container.py b/sdk/python/packages/flet/integration_tests/controls/core/test_container.py new file mode 100644 index 0000000000..86ff27a985 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_container.py @@ -0,0 +1,14 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_container_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + ft.Text("Container"), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_control.py b/sdk/python/packages/flet/integration_tests/controls/core/test_control.py new file mode 100644 index 0000000000..99b55a59a4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_control.py @@ -0,0 +1,378 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_visible(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + spacing=8, + controls=[ + ft.Container( + width=260, + height=44, + bgcolor=ft.Colors.GREEN_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Visible: True"), + ), + ft.Container( + width=260, + height=44, + bgcolor=ft.Colors.RED_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Visible: False"), + visible=False, + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_parent_not_visible_child_visible(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + spacing=8, + controls=[ + ft.Container( + width=260, + height=44, + bgcolor=ft.Colors.GREEN_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Visible sibling"), + ), + ft.Container( + visible=False, + content=ft.Container( + visible=True, + width=260, + height=44, + bgcolor=ft.Colors.RED_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("Hidden parent, visible child"), + ), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_disabled_propagates_to_children(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + spacing=12, + controls=[ + ft.Column( + spacing=8, + controls=[ + ft.Text("Enabled parent"), + ft.TextField(label="Name", value="John"), + ft.Button("Save"), + ], + ), + ft.Column( + disabled=True, + spacing=8, + controls=[ + ft.Text("Disabled parent"), + ft.TextField(label="Name", value="John"), + ft.Button("Save"), + ], + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_badge(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + padding=10, + content=ft.Row( + spacing=20, + controls=[ + ft.Container( + padding=10, + content=ft.FilledIconButton( + icon=ft.Icons.NOTIFICATIONS_OUTLINED, + badge="3", + ), + ), + ft.Container( + padding=10, + content=ft.FilledIconButton( + icon=ft.Icons.MAIL_OUTLINED, + badge=ft.Badge( + label="99+", + bgcolor=ft.Colors.RED_400, + text_color=ft.Colors.WHITE, + alignment=ft.Alignment(1, -1), + offset=ft.Offset(-2, 2), + ), + ), + ), + ], + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_opacity(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + spacing=10, + controls=[ + ft.Container( + width=260, + height=46, + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("opacity=1.0"), + opacity=1.0, + ), + ft.Container( + width=260, + height=46, + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("opacity=0.6"), + opacity=0.6, + ), + ft.Container( + width=260, + height=46, + bgcolor=ft.Colors.BLUE_300, + alignment=ft.Alignment.CENTER, + border_radius=8, + content=ft.Text("opacity=0.25"), + opacity=0.25, + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_rtl(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + spacing=12, + controls=[ + ft.Container( + width=320, + border=ft.Border.all(1, ft.Colors.BLUE_GREY_200), + padding=10, + content=ft.Row( + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Container( + width=44, height=30, bgcolor=ft.Colors.RED_300 + ), + ft.Container( + width=44, height=30, bgcolor=ft.Colors.GREEN_300 + ), + ft.Container( + width=44, height=30, bgcolor=ft.Colors.BLUE_300 + ), + ], + ), + ), + ft.Container( + width=320, + border=ft.Border.all(1, ft.Colors.BLUE_GREY_200), + padding=10, + content=ft.Row( + rtl=True, + alignment=ft.MainAxisAlignment.START, + controls=[ + ft.Container( + width=44, height=30, bgcolor=ft.Colors.RED_300 + ), + ft.Container( + width=44, height=30, bgcolor=ft.Colors.GREEN_300 + ), + ft.Container( + width=44, height=30, bgcolor=ft.Colors.BLUE_300 + ), + ], + ), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_col(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=520, + padding=10, + border=ft.Border.all(1, ft.Colors.BLUE_GREY_200), + border_radius=8, + content=ft.ResponsiveRow( + run_spacing=8, + spacing=8, + controls=[ + ft.Container( + col=6, + height=52, + bgcolor=ft.Colors.CYAN_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("col=6"), + ), + ft.Container( + col=6, + height=52, + bgcolor=ft.Colors.AMBER_300, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text("col=6"), + ), + ft.Container( + col={"sm": 4, "md": 3}, + height=52, + bgcolor=ft.Colors.PINK_200, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text('col={"sm":4,"md":3}'), + ), + ft.Container( + col={"sm": 8, "md": 9}, + height=52, + bgcolor=ft.Colors.GREEN_200, + border_radius=8, + alignment=ft.Alignment.CENTER, + content=ft.Text('col={"sm":8,"md":9}'), + ), + ], + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_tooltip_string_is_findable(flet_app: ftt.FletTestApp): + flet_app.page.add( + ft.IconButton( + icon=ft.Icons.INFO_OUTLINED, + tooltip="Info tooltip", + ) + ) + await flet_app.tester.pump_and_settle() + + finder = await flet_app.tester.find_by_tooltip("Info tooltip") + assert finder.count == 1 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_tooltip_shows_on_hover(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + flet_app.page.enable_screenshots = True + flet_app.resize_page(420, 300) + flet_app.page.update() + + flet_app.page.add( + ft.Container( + padding=100, + content=ft.IconButton( + key="info_btn", + icon=ft.Icons.INFO_OUTLINED, + tooltip=ft.Tooltip(message="Tooltip message"), + ), + ) + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + button = await flet_app.tester.find_by_key("info_btn") + await flet_app.tester.mouse_hover(button) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_tooltip_custom_properties_on_hover(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + flet_app.page.enable_screenshots = True + flet_app.resize_page(460, 320) + flet_app.page.update() + + flet_app.page.add( + ft.Container( + padding=100, + content=ft.IconButton( + key="info_btn_custom", + icon=ft.Icons.HELP_OUTLINE, + tooltip=ft.Tooltip( + message="Customized tooltip for Control.tooltip", + wait_duration=0, + show_duration=5000, + prefer_below=True, + vertical_offset=20, + bgcolor=ft.Colors.BLUE_GREY_900, + text_style=ft.TextStyle( + color=ft.Colors.WHITE, weight=ft.FontWeight.W_600, size=14 + ), + padding=ft.Padding.symmetric(horizontal=14, vertical=10), + margin=ft.Margin.only(top=8, left=8, right=8), + text_align=ft.TextAlign.CENTER, + decoration=ft.BoxDecoration( + border_radius=ft.BorderRadius.all(10), + ), + ), + ), + ) + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + button = await flet_app.tester.find_by_key("info_btn_custom") + await flet_app.tester.mouse_hover(button) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_dismissible.py b/sdk/python/packages/flet/integration_tests/controls/core/test_dismissible.py new file mode 100644 index 0000000000..b12c54e00c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_dismissible.py @@ -0,0 +1,29 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_dismissible_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Dismissible(ft.Text("Dismissible Item")), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_dismissible_properties(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Dismissible( + content=ft.ListTile(title="Item 1"), + dismiss_direction=ft.DismissDirection.HORIZONTAL, + background=ft.Container(bgcolor=ft.Colors.GREEN), + secondary_background=ft.Container(bgcolor=ft.Colors.RED), + dismiss_thresholds={ + ft.DismissDirection.END_TO_START: 0.2, + ft.DismissDirection.START_TO_END: 0.2, + }, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_icon.py b/sdk/python/packages/flet/integration_tests/controls/core/test_icon.py new file mode 100644 index 0000000000..2da90fec36 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_icon.py @@ -0,0 +1,145 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + [ # material + ft.Row( + controls=[ + ft.Icon(ft.Icons.ABC, color=ft.Colors.PINK), + ft.Icon( + ft.Icons.AUDIOTRACK, color=ft.Colors.GREEN_400, size=30 + ), + ft.Icon(ft.Icons.AC_UNIT, color=ft.Colors.BLUE, size=50), + ft.Icon(ft.Icons.SETTINGS, color="#c1c1c1"), + ft.Icon(ft.Icons.ALARM, size=40), + ] + ), + # cupertino + ft.Row( + controls=[ + ft.Icon(ft.CupertinoIcons.AIRPLANE, color=ft.Colors.PINK), + ft.Icon( + icon=ft.CupertinoIcons.CUBE_BOX, + color=ft.Colors.GREEN_400, + size=30, + ), + ft.Icon( + icon=ft.CupertinoIcons.ARCHIVEBOX, + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon(icon=ft.CupertinoIcons.BAG, color="#c1c1c1"), + ft.Icon(ft.CupertinoIcons.ALARM, size=40), + ] + ), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp): + flet_app.page.theme = ft.Theme( + icon_theme=ft.IconTheme( + color=ft.Colors.GREEN_900, + size=100, + apply_text_scaling=True, # doesn't show on screenshot + fill=0.5, # doesn't show on screenshow + opacity=0.5, + optical_size=48, # doesn't show pon screenshot + grade=-10, # doesn't show on screenshot + weight=10, # doesn't show on screenshot + shadows=ft.BoxShadow(color=ft.Colors.YELLOW, blur_radius=10), + ) + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + scr_1 = ft.Screenshot( + ft.Column( + [ # material + ft.Row( + controls=[ + ft.Icon( + ft.Icons.ABC, + fill=0, + # color=ft.Colors.PINK, + apply_text_scaling=False, + opacity=0.1, + optical_size=200, + ), + ft.Icon( + ft.Icons.AUDIOTRACK, + color=ft.Colors.GREEN_400, + size=30, + shadows=[ + ft.BoxShadow(color=ft.Colors.YELLOW, blur_radius=10), + ft.BoxShadow(color=ft.Colors.RED, blur_radius=5), + ], + ), + ft.Icon( + ft.Icons.AC_UNIT, + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon( + ft.Icons.SETTINGS, + color="#c1c1c1", + ), + ft.Icon( + ft.Icons.ALARM, + size=40, + ), + ] + ), + # cupertino + ft.Row( + controls=[ + ft.Icon( + ft.CupertinoIcons.AIRPLANE, + # color=ft.Colors.PINK, + ), + ft.Icon( + icon=ft.CupertinoIcons.CUBE_BOX, + color=ft.Colors.GREEN_400, + size=30, + ), + ft.Icon( + icon=ft.CupertinoIcons.ARCHIVEBOX, + color=ft.Colors.BLUE, + size=50, + ), + ft.Icon( + icon=ft.CupertinoIcons.BAG, + color="#c1c1c1", + ), + ft.Icon( + ft.CupertinoIcons.ALARM, + size=40, + ), + ] + ), + ] + ), + ) + flet_app.page.add(scr_1) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_image.py b/sdk/python/packages/flet/integration_tests/controls/core/test_image.py new file mode 100644 index 0000000000..5faab2df1c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_image.py @@ -0,0 +1,142 @@ +import base64 + +import pytest + +import flet as ft +import flet.testing as ftt + +base64_image = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 + + +@pytest.mark.asyncio(loop_scope="module") +async def test_src_png(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src="/minion.png", + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_src_base64(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src=base64_image, + width=100, + height=100, + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_src_svg_url(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src="https://flet.dev/img/logo.svg", + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + ), + pump_times=5, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_src_svg_string(flet_app: ftt.FletTestApp, request): + svg = """ + + + + + + + + + + + + + """ # noqa: E501 + + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src=svg, + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_src_bytes(flet_app: ftt.FletTestApp, request): + # Decode the Base64 string into bytes + bytes_image = base64.b64decode(base64_image) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src=bytes_image, + width=100, + height=100, + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.skip(reason="The test is flaky on CI") +@pytest.mark.asyncio(loop_scope="module") +async def test_placeholder_1(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src="/minion.png", + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + placeholder_src=base64_image, + fade_in_animation=ft.Animation(1000, ft.AnimationCurve.EASE_IN_OUT), + placeholder_fade_out_animation=ft.Animation( + 250, ft.AnimationCurve.EASE_OUT + ), + ), + pump_times=1, + pump_duration=50, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_placeholder_2(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Image( + src="/minion.png", + width=100, + height=100, + fit=ft.BoxFit.CONTAIN, + placeholder_src=base64_image, + fade_in_animation=ft.Animation(1000, ft.AnimationCurve.EASE_IN_OUT), + placeholder_fade_out_animation=ft.Animation( + 250, ft.AnimationCurve.EASE_OUT + ), + ), + pump_times=3, + pump_duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_layout_control.py b/sdk/python/packages/flet/integration_tests/controls/core/test_layout_control.py new file mode 100644 index 0000000000..aa46fa824c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_layout_control.py @@ -0,0 +1,433 @@ +from math import pi + +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_align_inside_stack(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Stack( + [ + ft.Button("A", align=ft.Alignment(0, 0)), + ft.Button("B", align=ft.Alignment(0.9, 0.9)), + ft.Button("C", align=ft.Alignment.BOTTOM_LEFT), + ], + width=200, + height=200, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_align_inside_container(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + ft.Button("B", align=ft.Alignment(0.9, 0.9)), + width=200, + height=200, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_margin_around(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Button( + "Button with margin", + margin=ft.Margin.all(20), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_margin_bottom_right(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Button( + "Button with margin", + margin=ft.Margin.only(bottom=20, right=20), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_position_right_bottom(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Stack( + width=420, + height=240, + controls=[ + ft.Container( + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=12, + ), + ft.Container( + width=120, + height=70, + right=24, + bottom=20, + border_radius=12, + bgcolor=ft.Colors.CYAN_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("right+bottom", size=14, weight=ft.FontWeight.BOLD), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_position_constraint_combinations(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Stack( + width=440, + height=280, + controls=[ + ft.Container( + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=12, + ), + ft.Container( + left=40, + right=40, + top=42, + height=62, + border_radius=10, + bgcolor=ft.Colors.AMBER_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("left + right", weight=ft.FontWeight.BOLD), + ), + ft.Container( + top=118, + bottom=38, + left=164, + width=110, + border_radius=10, + bgcolor=ft.Colors.GREEN_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("top + bottom", weight=ft.FontWeight.BOLD), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_animate_position(flet_app: ftt.FletTestApp, request): + # TODO(Feodor): Test framework needs improvement to correctly capture + # multiple animation screenshots. + animated = ft.Container( + width=90, + height=64, + left=18, + top=24, + border_radius=10, + bgcolor=ft.Colors.CYAN_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("move", weight=ft.FontWeight.BOLD), + animate_position=ft.Animation(600, ft.AnimationCurve.EASE_IN_OUT), + ) + root = ft.Stack( + width=320, + height=180, + controls=[ + ft.Container( + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=12, + ), + animated, + ], + ) + screenshot = ft.Screenshot(root) + + flet_app.page.clean() + flet_app.page.add(screenshot) + await flet_app.tester.pump_and_settle() + + animated.left = 196 + animated.top = 98 + animated.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await screenshot.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_aspect_ratio(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=100, + height=280, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_200), + border_radius=12, + alignment=ft.Alignment.TOP_LEFT, + padding=12, + content=ft.Column( + spacing=12, + controls=[ + ft.Container( + aspect_ratio=2, + border_radius=12, + bgcolor=ft.Colors.CYAN_300, + alignment=ft.Alignment.CENTER, + content=ft.Text( + "ratio 2.0", weight=ft.FontWeight.BOLD, size=13 + ), + ), + ft.Container( + aspect_ratio=0.5, + border_radius=12, + bgcolor=ft.Colors.ORANGE_300, + alignment=ft.Alignment.CENTER, + content=ft.Text( + "ratio 0.5", weight=ft.FontWeight.BOLD, size=13 + ), + ), + ft.Container( + width=50, + height=50, + aspect_ratio=3, + border_radius=12, + bgcolor=ft.Colors.PINK_200, + alignment=ft.Alignment.CENTER, + content=ft.Text( + "ratio wins", weight=ft.FontWeight.BOLD, size=13 + ), + ), + ], + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_flip(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Flip", size=28, weight=ft.FontWeight.BOLD), + flip=ft.Flip( + flip_x=True, + flip_y=True, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_rotate(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Rotate", size=28, weight=ft.FontWeight.BOLD), + rotate=ft.Rotate( + angle=pi / 10, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_rotate_numeric_value(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.BLUE_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Rotate", size=28, weight=ft.FontWeight.BOLD), + rotate=pi / 10, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_scale(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.GREEN_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Scale", size=28, weight=ft.FontWeight.BOLD), + scale=ft.Scale( + scale_x=1.18, + scale_y=0.82, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_scale_numeric_value(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.GREEN_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("Scale", size=28, weight=ft.FontWeight.BOLD), + scale=2.5, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_offset(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Stack( + width=460, + height=260, + controls=[ + ft.Text( + "Offset translates by control size.", + left=12, + top=8, + size=16, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.Container( + left=30, + top=70, + width=170, + height=90, + border_radius=16, + bgcolor=ft.Colors.BLUE_100, + border=ft.Border.all(2, ft.Colors.BLUE_GREY_400), + alignment=ft.Alignment.CENTER, + content=ft.Text("Original", size=20, color=ft.Colors.BLUE_GREY_700), + ), + ft.Container( + left=30, + top=70, + width=170, + height=90, + border_radius=16, + bgcolor=ft.Colors.AMBER_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("Offset", size=26, weight=ft.FontWeight.BOLD), + offset=ft.Offset( + x=1.05, + y=0.55, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ), + ft.Icon( + ft.Icons.ARROW_RIGHT_ALT_ROUNDED, + left=212, + top=82, + size=44, + color=ft.Colors.BLUE_GREY_600, + ), + ft.Text( + "offset = Offset(1.05, 0.55)", + left=194, + top=222, + size=14, + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ], + ), + ) + + +def _matrix_card(title: str, color: str, matrix: ft.Matrix4) -> ft.Container: + return ft.Container( + width=220, + height=130, + border_radius=18, + bgcolor=color, + padding=12, + content=ft.Text(title, size=18, weight=ft.FontWeight.BOLD), + transform=ft.Transform( + matrix=matrix, + alignment=ft.Alignment.CENTER, + filter_quality=ft.FilterQuality.MEDIUM, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_matrix4_perspective_tilt(flet_app: ftt.FletTestApp, request): + matrix = ( + ft.Matrix4.identity() + .set_entry(3, 2, 0.0018) + .rotate_x(-0.35) + .rotate_y(0.45) + .translate(0, -10, 0) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + _matrix_card("Perspective tilt", ft.Colors.CYAN_300, matrix), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_matrix4_skew_and_rotate(flet_app: ftt.FletTestApp, request): + matrix = ft.Matrix4.skew_y(0.28).rotate_z(-pi / 14) + + await flet_app.assert_control_screenshot( + request.node.name, + _matrix_card("Skew + rotate", ft.Colors.AMBER_300, matrix), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_matrix4_mirrored_spin(flet_app: ftt.FletTestApp, request): + matrix = ft.Matrix4.diagonal3_values(-1, 1, 1).rotate_z(pi / 10) + + await flet_app.assert_control_screenshot( + request.node.name, + _matrix_card("Mirror + spin", ft.Colors.PINK_200, matrix), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_matrix4_multiply_chain(flet_app: ftt.FletTestApp, request): + matrix = ft.Matrix4.translation_values(24, -8, 0).multiply( + ft.Matrix4.rotation_z(pi / 16).scale(0.9, 0.9) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + _matrix_card("Multiply chain", ft.Colors.LIGHT_GREEN_300, matrix), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_page_view.py b/sdk/python/packages/flet/integration_tests/controls/core/test_page_view.py new file mode 100644 index 0000000000..f1a6e5aebb --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_page_view.py @@ -0,0 +1,65 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.PageView( + height=220, + viewport_fraction=0.85, + controls=[ + ft.Container( + bgcolor=ft.Colors.PURPLE, + alignment=ft.Alignment.CENTER, + content=ft.Text("One", color=ft.Colors.WHITE), + ), + ft.Container( + bgcolor=ft.Colors.TEAL, + alignment=ft.Alignment.CENTER, + content=ft.Text("Two", color=ft.Colors.WHITE), + ), + ft.Container( + bgcolor=ft.Colors.AMBER, + alignment=ft.Alignment.CENTER, + content=ft.Text("Three", color=ft.Colors.BLACK), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_unbounded_height(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.PageView( + controls=[ + ft.Container( + bgcolor=ft.Colors.PURPLE, + alignment=ft.Alignment.CENTER, + content=ft.Text("One", color=ft.Colors.WHITE), + ), + ft.Container( + bgcolor=ft.Colors.TEAL, + alignment=ft.Alignment.CENTER, + content=ft.Text("Two", color=ft.Colors.WHITE), + ), + ], + ) + ] + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_pagelet.py b/sdk/python/packages/flet/integration_tests/controls/core/test_pagelet.py new file mode 100644 index 0000000000..c825a7ea33 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_pagelet.py @@ -0,0 +1,129 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_explicitly_sized(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Pagelet( + width=400, + height=400, + appbar=ft.AppBar( + title=ft.Text("Pagelet AppBar Title"), + bgcolor=ft.Colors.AMBER_ACCENT, + ), + bottom_appbar=ft.BottomAppBar( + content=ft.Row( + controls=[ + ft.IconButton(icon=ft.Icons.MENU), + ft.Container(expand=True), + ft.IconButton(icon=ft.Icons.SEARCH), + ft.IconButton(icon=ft.Icons.FAVORITE), + ] + ), + ), + content=ft.Container( + bgcolor=ft.Colors.AMBER, content=ft.Text("Pagelet Content") + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_auto_size(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 500) + flet_app.page.add( + ft.Pagelet( + content=ft.Container( + bgcolor=ft.Colors.AMBER, content=ft.Text("Pagelet Content") + ), + ), + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + f"{request.node.name}_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + flet_app.page.controls = [ + ft.Pagelet( + height=400, + appbar=ft.AppBar( + title=ft.Text("Pagelet AppBar Title"), + bgcolor=ft.Colors.AMBER_ACCENT, + ), + bottom_appbar=ft.BottomAppBar( + content=ft.Row( + controls=[ + ft.IconButton(icon=ft.Icons.MENU), + ft.Container(expand=True), + ft.IconButton(icon=ft.Icons.SEARCH), + ft.IconButton(icon=ft.Icons.FAVORITE), + ] + ), + ), + content=ft.Container( + bgcolor=ft.Colors.AMBER, content=ft.Text("Pagelet Content") + ), + ), + ] + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + f"{request.node.name}_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_cupertino_adaptive(flet_app: ftt.FletTestApp, request): + flet_app.page.platform = ft.PagePlatform.MACOS + await flet_app.assert_control_screenshot( + request.node.name, + ft.Pagelet( + adaptive=True, + width=350, + height=300, + appbar=ft.AppBar(title="Pagelet AppBar"), + content=ft.Text("Pagelet Content"), + navigation_bar=ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.ADD, label="New"), + ft.NavigationBarDestination(icon=ft.Icons.INBOX, label="Inbox"), + ], + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_unbounded_height(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.Pagelet( + appbar=ft.AppBar(title="Pagelet AppBar"), + content=ft.Text("Pagelet Content"), + ) + ] + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_placeholder.py b/sdk/python/packages/flet/integration_tests/controls/core/test_placeholder.py new file mode 100644 index 0000000000..f5010c6cd6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_placeholder.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_placeholder_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Placeholder(expand=True, color=ft.Colors.RED), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_responsive_row.py b/sdk/python/packages/flet/integration_tests/controls/core/test_responsive_row.py new file mode 100644 index 0000000000..4676a8a3e6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_responsive_row.py @@ -0,0 +1,106 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_responsive_row_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ResponsiveRow( + controls=[ + ft.TextField(label="TextField 1"), + ft.TextField(label="TextField 2"), + ft.TextField(label="TextField 3"), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_unbounded_width(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.ResponsiveRow( + controls=[ + ft.Text("Item 1"), + ft.Text("Item 2"), + ] + ) + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_zero_col_controls_are_hidden_at_breakpoint( + flet_app: ftt.FletTestApp, request +): + flet_app.resize_page(360, 240) + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.ResponsiveRow( + controls=[ + ft.Container( + col={"xs": 0, "xl": 2}, + bgcolor=ft.Colors.GREEN, + content=ft.Text("Left"), + ), + ft.Container( + col={"xs": 12, "xl": 8}, + bgcolor=ft.Colors.RED, + content=ft.Text("Center"), + ), + ft.Container( + col={"xs": 0, "xl": 2}, + bgcolor=ft.Colors.BLUE, + content=ft.Text("Right"), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_scroll_to(flet_app: ftt.FletTestApp): + events = [] + + def on_scroll(e: ft.OnScrollEvent): + events.append(e) + + flet_app.page.add( + row := ft.ResponsiveRow( + height=120, + width=320, + scroll=ft.ScrollMode.HIDDEN, + on_scroll=on_scroll, + controls=[ + ft.Container( + col=12, + height=70, + bgcolor=ft.Colors.BLUE_50, + content=ft.Text(f"Item {i}"), + ) + for i in range(6) + ], + ) + ) + await flet_app.tester.pump_and_settle() + + await row.scroll_to(offset=160, duration=0) + await flet_app.tester.pump_and_settle() + + assert events + assert events[-1].pixels > 0 diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_rotated_box.py b/sdk/python/packages/flet/integration_tests/controls/core/test_rotated_box.py new file mode 100644 index 0000000000..acc588226c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_rotated_box.py @@ -0,0 +1,22 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_rotated_box(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.RotatedBox( + quarter_turns=1, + content=ft.Container( + width=220, + height=120, + bgcolor=ft.Colors.TEAL_300, + border_radius=16, + alignment=ft.Alignment.CENTER, + content=ft.Text("RotatedBox", size=28, weight=ft.FontWeight.BOLD), + ), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_row.py b/sdk/python/packages/flet/integration_tests/controls/core/test_row.py new file mode 100644 index 0000000000..c6ea95e967 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_row.py @@ -0,0 +1,14 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_row_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ft.Text("Item1"), ft.Text("Item2"), ft.Text("Item3")], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/core/test_text.py b/sdk/python/packages/flet/integration_tests/controls/core/test_text.py new file mode 100644 index 0000000000..fa599f1a1f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/core/test_text.py @@ -0,0 +1,42 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Text("Hello, world!"), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_bold(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Text("Hello, world!", weight=ft.FontWeight.BOLD), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_overflow(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + width=100, + controls=[ + ft.Text( + value="Hello World! This is some very long text.", + overflow=ft.TextOverflow.ELLIPSIS, + ), + ft.Text( + value="Hello World! This is some very long text.", + style=ft.TextStyle( + overflow=ft.TextOverflow.ELLIPSIS, + ), + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_action_sheet/cupertino_action_sheet_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_action_sheet/cupertino_action_sheet_basic.png new file mode 100644 index 0000000000..073020c18a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_action_sheet/cupertino_action_sheet_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_action_sheet_action/cupertino_action_sheet_action_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_action_sheet_action/cupertino_action_sheet_action_basic.png new file mode 100644 index 0000000000..68cbf25cb8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_action_sheet_action/cupertino_action_sheet_action_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_activity_indicator/basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_activity_indicator/basic.png new file mode 100644 index 0000000000..91aea19f4b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_activity_indicator/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_activity_indicator/progress.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_activity_indicator/progress.png new file mode 100644 index 0000000000..023df1ee41 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_activity_indicator/progress.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/barrier_color_1.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/barrier_color_1.png new file mode 100644 index 0000000000..e9326b0bb7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/barrier_color_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/barrier_color_2.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/barrier_color_2.png new file mode 100644 index 0000000000..490fbab632 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/barrier_color_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/basic.png new file mode 100644 index 0000000000..c7e3d90f5f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/update_body_1.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/update_body_1.png new file mode 100644 index 0000000000..d7ed2f131b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/update_body_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/update_body_2.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/update_body_2.png new file mode 100644 index 0000000000..41f66cde84 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_alert_dialog/update_body_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_app_bar/cupertino_app_bar.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_app_bar/cupertino_app_bar.png new file mode 100644 index 0000000000..b3227d238e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_app_bar/cupertino_app_bar.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_bottom_sheet/cupertino_bottom_sheet_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_bottom_sheet/cupertino_bottom_sheet_basic.png new file mode 100644 index 0000000000..073020c18a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_bottom_sheet/cupertino_bottom_sheet_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_button/cupertino_button_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_button/cupertino_button_basic.png new file mode 100644 index 0000000000..d49c4209b5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_button/cupertino_button_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/basic.png new file mode 100644 index 0000000000..4ff0115116 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/basic_checked.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/basic_checked.png new file mode 100644 index 0000000000..070520892e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/basic_checked.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/label.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/label.png new file mode 100644 index 0000000000..fc735f8628 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/label.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/label_position.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/label_position.png new file mode 100644 index 0000000000..88b98a6af3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/label_position.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/tristate_1.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/tristate_1.png new file mode 100644 index 0000000000..2bec6e6176 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/tristate_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/tristate_2.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/tristate_2.png new file mode 100644 index 0000000000..b96245bfc7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_checkbox/tristate_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu/cupertino_context_menu_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu/cupertino_context_menu_basic.png new file mode 100644 index 0000000000..ac7b945ae2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu/cupertino_context_menu_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu/cupertino_context_menu_basic_open.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu/cupertino_context_menu_basic_open.png new file mode 100644 index 0000000000..ac7b945ae2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu/cupertino_context_menu_basic_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu_action/cupertino_context_menu_action_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu_action/cupertino_context_menu_action_basic.png new file mode 100644 index 0000000000..9e53153005 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_context_menu_action/cupertino_context_menu_action_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/basic.png new file mode 100644 index 0000000000..2e0f77bbd4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png new file mode 100644 index 0000000000..52c139f4a8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_date_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_dialog_action/cupertino_dialog_action_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_dialog_action/cupertino_dialog_action_basic.png new file mode 100644 index 0000000000..f07a203870 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_dialog_action/cupertino_dialog_action_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_filled_button/cupertino_filled_button_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_filled_button/cupertino_filled_button_basic.png new file mode 100644 index 0000000000..d041169e4b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_filled_button/cupertino_filled_button_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_list_tile/cupertino_list_tile_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_list_tile/cupertino_list_tile_basic.png new file mode 100644 index 0000000000..f83f7b2e70 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_list_tile/cupertino_list_tile_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_navigation_bar/cupertino_navigation_bar.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_navigation_bar/cupertino_navigation_bar.png new file mode 100644 index 0000000000..f453d0b2d8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_navigation_bar/cupertino_navigation_bar.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_picker/cupertino_picker_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_picker/cupertino_picker_basic.png new file mode 100644 index 0000000000..fa3fe41f2d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_picker/cupertino_picker_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/basic_blue.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/basic_blue.png new file mode 100644 index 0000000000..0709da0a7d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/basic_blue.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/basic_red.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/basic_red.png new file mode 100644 index 0000000000..cd3aca167a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/basic_red.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/checkmark.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/checkmark.png new file mode 100644 index 0000000000..0fe574f6a0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_radio/checkmark.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_segmented_button/cupertino_segmented_button_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_segmented_button/cupertino_segmented_button_basic.png new file mode 100644 index 0000000000..9ad61d1631 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_segmented_button/cupertino_segmented_button_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_slider/slider_middle.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_slider/slider_middle.png new file mode 100644 index 0000000000..11d3f72339 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_slider/slider_middle.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_slider/slider_start.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_slider/slider_start.png new file mode 100644 index 0000000000..498637050f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_slider/slider_start.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_sliding_segmented_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_sliding_segmented_button/basic.png new file mode 100644 index 0000000000..f9244e8be3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_sliding_segmented_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/active.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/active.png new file mode 100644 index 0000000000..7a9ab956f9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/active.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/active_thumb_image_src.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/active_thumb_image_src.png new file mode 100644 index 0000000000..0688c2e125 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/active_thumb_image_src.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/inactive.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/inactive.png new file mode 100644 index 0000000000..106b545dc4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/inactive.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/inactive_thumb_image_src.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/inactive_thumb_image_src.png new file mode 100644 index 0000000000..f6dc3f0230 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_switch/inactive_thumb_image_src.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/basic.png new file mode 100644 index 0000000000..df1e4b6528 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/filled.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/filled.png new file mode 100644 index 0000000000..619b8546f8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/filled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/label.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/label.png new file mode 100644 index 0000000000..3abb9ec466 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/label.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/label_and_image.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/label_and_image.png new file mode 100644 index 0000000000..b6d2bf00be Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_text_field/label_and_image.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_timer_picker/cupertino_timer_picker_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_timer_picker/cupertino_timer_picker_basic.png new file mode 100644 index 0000000000..4a1fccd7b0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_timer_picker/cupertino_timer_picker_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_tinted_button/cupertino_tinted_basic.png b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_tinted_button/cupertino_tinted_basic.png new file mode 100644 index 0000000000..399d961daf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/cupertino/golden/macos/cupertino_tinted_button/cupertino_tinted_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_action_sheet.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_action_sheet.py new file mode 100644 index 0000000000..3e68e20ac3 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_action_sheet.py @@ -0,0 +1,48 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_action_sheet_basic(flet_app: ftt.FletTestApp, request): + action_sheet = ft.CupertinoActionSheet( + title=ft.Row( + controls=[ft.Text("Title"), ft.Icon(ft.Icons.BEDTIME)], + alignment=ft.MainAxisAlignment.CENTER, + ), + message=ft.Row( + controls=[ft.Text("Description"), ft.Icon(ft.Icons.AUTO_AWESOME)], + alignment=ft.MainAxisAlignment.CENTER, + ), + cancel=ft.CupertinoActionSheetAction( + content=ft.Text("Cancel"), + ), + actions=[ + ft.CupertinoActionSheetAction( + content=ft.Text("Default Action"), + default=True, + ), + ft.CupertinoActionSheetAction( + content=ft.Text("Normal Action"), + ), + ft.CupertinoActionSheetAction( + content=ft.Text("Destructive Action"), + destructive=True, + ), + ], + ) + + cupertino_bottom_sheet = ft.CupertinoBottomSheet(action_sheet) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog(cupertino_bottom_sheet) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "cupertino_action_sheet_basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_action_sheet_action.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_action_sheet_action.py new file mode 100644 index 0000000000..56a81e8d9e --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_action_sheet_action.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_action_sheet_action_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoActionSheetAction("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_activity_indicator.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_activity_indicator.py new file mode 100644 index 0000000000..99f5e1b76c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_activity_indicator.py @@ -0,0 +1,28 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoActivityIndicator( + radius=30, + color=ft.CupertinoColors.DARK_BACKGROUND_GRAY, + animating=False, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_progress(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoActivityIndicator( + radius=30, + color=ft.CupertinoColors.DARK_BACKGROUND_GRAY, + progress=0.5, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_alert_dialog.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_alert_dialog.py new file mode 100644 index 0000000000..c6f3dffa15 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_alert_dialog.py @@ -0,0 +1,108 @@ +import asyncio + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog( + ft.CupertinoAlertDialog( + title=ft.Text("Cupertino Alert Dialog"), + content=ft.Text("Do you want to delete this file?"), + ) + ) + flet_app.page.update() + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_update_body(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog( + ft.CupertinoAlertDialog( + title=ft.Text("Test"), + actions=[ + ok := ft.TextButton("OK", visible=True), + cancel := ft.TextButton("Cancel", visible=True), + ], + ) + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + assert (await flet_app.tester.find_by_text("OK")).count == 1 + flet_app.assert_screenshot( + "update_body_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # change dialog color and hide "OK" button + await asyncio.sleep(1) + ok.visible = not ok.visible # hide button + cancel.disabled = not cancel.disabled # disable button + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + assert (await flet_app.tester.find_by_text("OK")).count == 0 + flet_app.assert_screenshot( + "update_body_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_barrier_color(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 500) + flet_app.page.update() + + flet_app.page.show_dialog( + ad := ft.CupertinoAlertDialog( + title=ft.Text("Barrier"), + content=ft.Text("Watch the barrier color."), + barrier_color=ft.Colors.RED, + ) + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "barrier_color_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + ad.barrier_color = ft.Colors.BLUE + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "barrier_color_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_app_bar.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_app_bar.py new file mode 100644 index 0000000000..1b690ce03f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_app_bar.py @@ -0,0 +1,19 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_app_bar(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoAppBar( + leading=ft.Icon(ft.Icons.PALETTE, color=ft.Colors.ON_SECONDARY), + title=ft.Text("CupertinoAppBar Example"), + trailing=ft.Icon(ft.Icons.WB_SUNNY_OUTLINED, color=ft.Colors.ON_SECONDARY), + automatic_background_visibility=False, + bgcolor=ft.Colors.SECONDARY, + brightness=ft.Brightness.LIGHT, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_bottom_sheet.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_bottom_sheet.py new file mode 100644 index 0000000000..208212a096 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_bottom_sheet.py @@ -0,0 +1,48 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_bottom_sheet_basic(flet_app: ftt.FletTestApp, request): + action_sheet = ft.CupertinoActionSheet( + title=ft.Row( + controls=[ft.Text("Title"), ft.Icon(ft.Icons.BEDTIME)], + alignment=ft.MainAxisAlignment.CENTER, + ), + message=ft.Row( + controls=[ft.Text("Description"), ft.Icon(ft.Icons.AUTO_AWESOME)], + alignment=ft.MainAxisAlignment.CENTER, + ), + cancel=ft.CupertinoActionSheetAction( + content=ft.Text("Cancel"), + ), + actions=[ + ft.CupertinoActionSheetAction( + content=ft.Text("Default Action"), + default=True, + ), + ft.CupertinoActionSheetAction( + content=ft.Text("Normal Action"), + ), + ft.CupertinoActionSheetAction( + content=ft.Text("Destructive Action"), + destructive=True, + ), + ], + ) + + cupertino_bottom_sheet = ft.CupertinoBottomSheet(action_sheet) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog(cupertino_bottom_sheet) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "cupertino_bottom_sheet_basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_button.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_button.py new file mode 100644 index 0000000000..783fc4d71d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_button_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_checkbox.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_checkbox.py new file mode 100644 index 0000000000..1bb11772dd --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_checkbox.py @@ -0,0 +1,73 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +ccbts = ft.CupertinoCheckbox( + label="Cupertino Checkbox tristate", + value=True, + tristate=True, + check_color=ft.Colors.GREY_900, + fill_color={ + ft.ControlState.SELECTED: ft.Colors.DEEP_ORANGE_200, + ft.ControlState.DEFAULT: ft.Colors.TEAL_200, + }, +) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_tristate_1(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ccbts, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_tristate_2(flet_app: ftt.FletTestApp, request): + ccbts.value = None + await flet_app.assert_control_screenshot( + request.node.name, + ccbts, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoCheckbox(), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic_checked(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoCheckbox( + value=True, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_label_position(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoCheckbox( + label="Cupertino Checkbox with circle border", + label_position=ft.LabelPosition.LEFT, + value=True, + shape=ft.CircleBorder(), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_label(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoCheckbox( + label="Cupertino Checkbox with label", + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_context_menu.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_context_menu.py new file mode 100644 index 0000000000..36d87e6a48 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_context_menu.py @@ -0,0 +1,53 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_context_menu_basic(flet_app: ftt.FletTestApp, request): + ccm = ft.CupertinoContextMenu( + enable_haptic_feedback=True, + key="ccm", + content=ft.Button("Click me", key="button"), + actions=[ + ft.CupertinoContextMenuAction( + content="Action 1", + default=True, + trailing_icon=ft.Icons.CHECK, + on_click=lambda e: print("Action 1"), + ), + ft.CupertinoContextMenuAction( + content="Action 2", + trailing_icon=ft.Icons.MORE, + on_click=lambda e: print("Action 2"), + ), + ft.CupertinoContextMenuAction( + content="Action 3", + destructive=True, + trailing_icon=ft.Icons.CANCEL, + on_click=lambda e: print("Action 3"), + ), + ], + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(ccm) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "cupertino_context_menu_basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.long_press(await flet_app.tester.find_by_key("ccm")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "cupertino_context_menu_basic_open", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_context_menu_action.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_context_menu_action.py new file mode 100644 index 0000000000..ca125d2686 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_context_menu_action.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_context_menu_action_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoContextMenuAction("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_date_picker.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_date_picker.py new file mode 100644 index 0000000000..758e8fe50b --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_date_picker.py @@ -0,0 +1,62 @@ +import datetime + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.CupertinoBottomSheet( + content=ft.CupertinoDatePicker( + value=datetime.datetime(year=2024, month=8, day=15), + date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, + ) + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_locale(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.CupertinoBottomSheet( + content=ft.CupertinoDatePicker( + locale=ft.Locale("zh", "Hans"), + value=datetime.datetime(year=2024, month=8, day=15), + date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, + ) + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_dialog_action.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_dialog_action.py new file mode 100644 index 0000000000..74619eca3b --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_dialog_action.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_dialog_action_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoDialogAction("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_filled_button.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_filled_button.py new file mode 100644 index 0000000000..f7cfd16778 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_filled_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_filled_button_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoFilledButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_list_tile.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_list_tile.py new file mode 100644 index 0000000000..4def1d0414 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_list_tile.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_list_tile_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoListTile("Cupertino List Tile"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_navigation_bar.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_navigation_bar.py new file mode 100644 index 0000000000..f2370fa902 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_navigation_bar.py @@ -0,0 +1,34 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_navigation_bar(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoNavigationBar( + bgcolor=ft.Colors.AMBER_100, + inactive_color=ft.Colors.GREY, + active_color=ft.Colors.BLACK, + on_change=lambda e: print("Selected tab:", e.control.selected_index), + destinations=[ + ft.NavigationBarDestination( + icon=ft.Icons.EXPLORE_OUTLINED, + selected_icon=ft.Icons.EXPLORE, + label="Explore", + ), + ft.NavigationBarDestination( + icon=ft.Icons.COMMUTE_OUTLINED, + selected_icon=ft.Icons.COMMUTE, + label="Commute", + ), + ft.NavigationBarDestination( + icon=ft.Icons.BOOKMARK_BORDER, + selected_icon=ft.Icons.BOOKMARK, + label="Favorites", + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_picker.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_picker.py new file mode 100644 index 0000000000..e228d64a6c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_picker.py @@ -0,0 +1,37 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_picker_basic(flet_app: ftt.FletTestApp, request): + FRUITS = [ + "Apple", + "Mango", + "Banana", + "Orange", + "Pineapple", + "Strawberry", + ] + picker = ft.CupertinoPicker( + selected_index=3, + magnification=1.22, + squeeze=1.2, + use_magnifier=True, + controls=[ft.Text(value=f) for f in FRUITS], + ) + + cupertino_bottom_sheet = ft.CupertinoBottomSheet(picker) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog(cupertino_bottom_sheet) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "cupertino_picker_basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_radio.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_radio.py new file mode 100644 index 0000000000..48af9020bb --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_radio.py @@ -0,0 +1,58 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +rs: list[ft.CupertinoRadio] = [ + ft.CupertinoRadio( + value="red", + label="Red", + active_color=ft.Colors.RED_600, + inactive_color=ft.Colors.RED_200, + key="red", + ), + ft.CupertinoRadio( + value="green", + label="Green", + fill_color=ft.Colors.GREEN, + key="green", + ), + ft.CupertinoRadio( + value="blue", + label="Blue", + active_color=ft.Colors.BLUE, + key="blue", + ), +] + +rg = ft.RadioGroup( + content=ft.Column( + controls=rs, + ), + value="red", +) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic_red(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot(request.node.name, rg) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic_blue(flet_app: ftt.FletTestApp, request): + rg.value = "blue" + await flet_app.assert_control_screenshot( + request.node.name, + rg, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_checkmark(flet_app: ftt.FletTestApp, request): + for c in rs: + c.use_checkmark_style = True + rg.update() + await flet_app.assert_control_screenshot( + request.node.name, + rg, + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_segmented_button.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_segmented_button.py new file mode 100644 index 0000000000..c0be856896 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_segmented_button.py @@ -0,0 +1,18 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_segmented_button_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoSegmentedButton( + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Ten"), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_slider.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_slider.py new file mode 100644 index 0000000000..5e9ee9a720 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_slider.py @@ -0,0 +1,39 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_slider(flet_app: ftt.FletTestApp, request): + sl = ft.CupertinoSlider( + divisions=20, + min=0, + max=100, + active_color=ft.Colors.PURPLE, + thumb_color=ft.Colors.PURPLE, + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.controls = [sl] + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "slider_start", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + sl.value = 50.0 + flet_app.page.update() + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "slider_middle", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_sliding_segmented_button.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_sliding_segmented_button.py new file mode 100644 index 0000000000..07c95a7718 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_sliding_segmented_button.py @@ -0,0 +1,18 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoSlidingSegmentedButton( + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Ten"), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_switch.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_switch.py new file mode 100644 index 0000000000..4068ed58d3 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_switch.py @@ -0,0 +1,78 @@ +import base64 + +import pytest + +import flet as ft +import flet.testing as ftt + +base64_image = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 + + +@pytest.mark.asyncio(loop_scope="module") +async def test_active(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoSwitch( + label="Cupertino Switch", + value=True, + width=300, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_inactive(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoSwitch( + label="Cupertino Switch", + value=False, + width=300, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_active_thumb_image_src(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + width=300, + controls=[ + ft.CupertinoSwitch(value=True, active_thumb_image_src="/minion.png"), + ft.CupertinoSwitch(value=True, active_thumb_image_src=base64_image), + ft.CupertinoSwitch( + value=True, active_thumb_image_src=base64.b64decode(base64_image) + ), + ft.CupertinoSwitch( + value=True, + active_thumb_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4", # noqa: E501 + ), + ], + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_inactive_thumb_image_src(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + width=300, + controls=[ + ft.CupertinoSwitch(value=False, inactive_thumb_image_src="/minion.png"), + ft.CupertinoSwitch(value=False, inactive_thumb_image_src=base64_image), + ft.CupertinoSwitch( + value=False, inactive_thumb_image_src=base64.b64decode(base64_image) + ), + ft.CupertinoSwitch( + value=False, + inactive_thumb_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4", # noqa: E501 + ), + ], + ), + pump_times=1, + pump_duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_text_field.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_text_field.py new file mode 100644 index 0000000000..b0e9c9a52d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_text_field.py @@ -0,0 +1,58 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoTextField( + placeholder_text="Cupertino text field", + placeholder_style=ft.TextStyle(color=ft.Colors.GREY_400), + margin=25, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoTextField( + placeholder_text="Cupertino text field", + placeholder_style=ft.TextStyle(color=ft.Colors.GREY_400), + value="Testing Textfield 1,2,3!", + margin=25, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_label(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoTextField( + label="Textfield Label", + label_style=ft.TextStyle(italic=True, weight=ft.FontWeight.BOLD), + margin=25, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_label_and_image(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoTextField( + label="Textfield Label", + label_style=ft.TextStyle(italic=True, weight=ft.FontWeight.BOLD), + bgcolor=ft.Colors.BLUE_GREY, + image=ft.DecorationImage( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAAOgDAAADoAQAAQAAAGQAAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDg2Nv/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIAGQD6AMBIgACEQEDEQH/xAAaAAADAQEBAQAAAAAAAAAAAAAAAQIDBAYF/8QAGQEBAQEBAQEAAAAAAAAAAAAAAAECAwQF/9oADAMBAAIQAxAAAAH0NFcPWtY1i6TuaqSy0nY2hG0ICUrJFpJFIlWkpWhKIogtKqqmYLVYmqlzNEQtQxWyMFvK5GrON9lJx30yc86YLll0GpzHU05TqDmvoquddMnMtxOZ9elcNfStPmV9IjgrqUvOdDrK6QSBL0usXpCKTKtybTPPbi1NzLosh1C83N14axgaRvnKtCKSzNyiVJEmEjCRlJMRKkIaAAQ0IaRDKQw9M6v5/wBCKp2S6bKLLJdKxKwgqJWNiApMUKaSy3cZGgZ2Ai3ZNN2S6EgtmZqGbpWQUpqSmQqSzNkuU7qXCelLhWwmJuGFbuzE1SZT0M5n0Jca0LJRiuxgVtGbSx6VjWwRTSNKBy1TSZss4KznOzaOPLeerDObnWEtQmiyFaJVJJVBKpEjElUhDVIYSMRJghoQwSYJUkQw9bQ/F7U3VzLbsCiyClCKCZsiKdEzoVktWuTsIdykqyXN2xNvWZbAGkBAxJWmhCmatTEtqHLYrslmZZiS9ByzXXPHJ2rhmvoV82zvz4iuio0lrHUl5p7ITm0rXTLWlZouPKz6C46k3yzu1zGVl5JazVLRcJ38mzf1PMu49mvgehthdCXGtaOVUrmSlUK0QUiVSSRhKoJVJEqVIYSMEqQhiSMJGCGHr234/Sm3YDVgABJFqQoSqiUWZ0tEklEyaGbW0iylMLo8WujwDd40mikLUKLUK6skgi4lp84vQsrRTqLzromMZ6HbzR1xZxTvOpktC5hhTvNxpWQtoSDyVdFc1FVKN5mJaitrOWeqEnXLvlL0nN4/Keu+Tnfleb1XJrn8fv4NevL1j8z6DTRXKpUrJVolUklUqlWiFaIKSSrkQwkYSMRJglSEMqRiIA9kx+XuCQIFJcykkZ1Zm10UFlvNlrErastEap2ZZ7i8+mjM60SSNLOdpc6cpYamdaSgoiaqJJqh0meWvOppjpWkEohIvfnDo5izmfW9Z4zvs+a/oI53vnEKqOae5anHfc4+e+zS3hvZxnWtSc2nRJlG0zRokmeW2M3z/Mv4tzvzqevLGqN88qeVnpevyvp27VKWSkkqlUq0QMSVQQrRBSJVFQUiSkiVISpCGJIypGHsFE+T0aPCl1UJLmBoQlaCKrFppMGjvBx01yOzpfPZtPOjdc6OiuQOxcgdGec1ttzbGylxcukhaokFLnO7jnraal0LOeyjkntk5ddatTBmklVTNErVBFwZGyXN6CZRu65q6qjn01STapFOiJYCGS4fG5vnVK2ntznK87lKMrKyeKT9T4fcns38H786JULKoIKRKtJCpEq5qSkkqglUiSkSMqSkkjCRhIw9PkHl9TQS3QWACEgqgIkDUaCkAAEjYGQGioAAEgACtAMkwLoIdgulhMCCiQhUCgFCAzyBZQVSCNUBTAWYDkF2ATJBWyCNGBmwKoEJAbCPOedDpjPYOvPn4wPpyBnIaz8T6wZb+pC66QM9EAJAggJQAgpIEQAkAIEEFCBBAIAQB//EACoQAAICAgIBBAIBBAMAAAAAAAABERICEAMgEwQhMVAwQCIFFCNBMjNg/9oACAEBAAEFAtr9yCCCO8dGQypQqQOBvcEEEEEEdIIKlDxnjKFChQr1jrJY8hdHkQuRsZlP0MEEC+iggggggqVKlSNsggoUKkFSpXVShQ8YuMXGiqIWo6zqCpBGrFnNGyg8R4Mx4iiWmMa+ij6GCCCCNwR1jUFSpBUgqVKlSCCCCCO3t0gr1oQQtta+B5DzLlifoY/UggjtH6MEEEagggggjpBBHSR5lyxKJQiCNySWLFiSUWHyFizY82T9JH6cftST+GSSxYkkvB5BZEjbPdkaqeIXGj4LFyxYkkksySSw2WWJ/dcr5eP10DdutX/5GSSxcuy7JJLFjyjzYvcgWo0xC08kjLM9xJkPViw2TpKSg+NnqMs+fkyXIYZnBzZcTx/mvGVF7GWX3sk/oyTqCCCr01uNyWZcuXLssWLlz5KsQhstqHpJCxRitc1lx83Py4mT5shvOMOf3w58+PPDkXJhP1c6nU/hkknUk7+CxYnck7knTHlAsvxMcH8fwwQuiZPdoWMmGMakzzg5Gsx4o5K5LL2fycXJlw5cfLhyr6qdST1knrJLFuNQVI1JJHT2LFtRq4uQ8h5C8lxZsWQ8oMuSe6SPYhMeGoIPGVKM8YsRYFYPGLjKIojFJEjeuf2MsklnytvJ5R7s+NY5vDLg5vNh9fI2SLpBHeSxcmRIjbe6iR8DY/coUKFCvSGxcTPEeNHjRRHjxPGh4HjZRiwyPGeMWEEFVp6gRJOoI3lkuPH1PqFyYfJb292fO49+Hm8XJx8mPJh9LJJPSCCEQRqekklixYknTJR7MUdIII25Ks8ZRELbKkFRYkdZLEvVh5F2i+Rdj5GeRk5MjIWBEajUdcs8cT1PqMOT0yy9k9PTLIzydeH49P6h8WWOSzx/fkkkn8EkkkkkklixYsWJ1JJJYtpIX4I7wQQiq6ztR0gggqVRGJGPSPw+vTx9Q2+jgycJwxQck04c45E2ej5vH++9z2f661LJFkyzLMn8rLMsySSz7MkkQxsTP9STqRPv/UP+3LJjbSs1xNtPPJvJ8WOR/vL/AJZr/D8Ne+MHp8nnw/u//8QAHxEAAgICAwEBAQAAAAAAAAAAABEBEBIgITBAAjFQ/9oACAEDAQE/Ae9jHTODg41QhCEYiFsx1zck+FjGMezHTpjMh06YxjMjIZkZD0Y9HTMjIfiYx6MYx2+hWjExMa40ezrkUnJ+iF4XohCEIQhUhCEIQqi3outWuCfkY/NECFq6e0C6F1O4MiZuJ8KEIXQupjpj63rMj0/CJ8EfxZ0+tZPjwf/EAB4RAQABBAIDAAAAAAAAAAAAABEAARAgQBIwAiFQ/9oACAECAQE/AdtjGMYxjmX9Wpvlix1EIYmJcnGGwQhDA0CGRYhdpqkNtxMWMYx9ylbHzmM5XYxjlxlPGGo3Os7DupT7/jjSV0P/xAApEAABAwIFAgYDAAAAAAAAAAABABExAiEQEiBBYEBRAzAyYXGBEyJw/9oACAEBAAY/AuMTjKnmkabqP7xbnb1FgicxG47JvEo+wnHMJ8l16CKR6bJrrLUbppp7JxHMo1FQnODMnBt2Qqp5nZX0bYQrYOI3Cek/XNhgw0vSWK7VCeP26XNVCGVXTDS6FQvss1McKsp6iPPuQFaXhQo1WRHZd6dwhUIPMcw3Cgq+l0wdbfC+UXX46j+pg+/MafjCSn90UFfEnAVb4Uk9d//EACcQAAMAAgICAgICAwEBAAAAAAABERAhMUEgUTBhQHGBkVChwbHw/9oACAEBAAE/IULJLC8F+Il4hCExGQYmENgRWOUQH9DfikF4amysaKE3oQaogX0EhJwOMn2Qgg1SERCHA0xvUM9ITWwi8Mxt9j8IQa/JWBBBYXhSlL53zhCCRCEIQnxDFGUaGbjLcVH6eCRUEHWH6iKBDFIiyR1DgbG3gsbFSH6ob4QQNBUGOEMbwhKL0bC4ZifmpEEJ8V82XMwkTK8IbeIQmSEw1hMiM4TgvoLDI1+DIOIo16xGIoQiGx1kWslCsIaQr2QqCPYrpjbM/wA9IQhCCRCEzBrCRCZviITCJhMQhCEJh4pcx+IQrx6DWJcYIIjWGvsQnzhuNnLEsa9CwwsI9kEYNRL7F1ErkQPWxwarfTArE+KfkLKEEiEGiZZBYhCYzExMQSJiEITzhEQ0NrwN478YXZPsnM4GDfoa+R4qA/oQt8G3IgaEkDLLLfBk3E7fI47Gt8nC6K9sez29vT1BcLf/AByhPGjVU8JRoW1/gEsQSxPghCYhCEITEIQnytlKVkILDYzeLZDJ4L+2H6n6DRXJiURETIIiGIhkhNe8JXRWIMLZE3CUPo2ZzydITeqJL0LTpDkNSNNp+ie4u1NBN7/gSl9bsr2OSWFtZnwzE/CWUT5KXwpczNJIKX4mXNGo6IyijcYR+sLeUwnWJMiyhhTLKKxfoNENoRi6+hg2dwpqVPoJOENA/odxtfsRQn6QhTS17XIyH0spuTb+Bw3MbPM8J8s+eE8KUbwuFwpSlLil8BRijbw2EEhJSkjNZWaE4QqiGPktEkxJLDiKjRo1g50XB/HhCZVcj6B6yxdjvsrFpckpJyJ60N3o00c4eGkNFisOAotpRC7Q5SxCccFQVuR8nMQuW5XjP8DSlKPC4MUuLghcMsG/WBmRkeEGrwTm0J+x1whUTFQxKHYt9jLiHPR/ANPZQw16GntYYsDnFfhNyfodzRBaY7hyEw5EzobLl40fRHAbsShg28s4QYcbbNH3KzsjCo9qhvrIk+xsWZHsW5zoCYnhPwZ8d8GhoYylGylJKYI+SCIMyiI14N4tRwuMafQkNDaXZ6B/sjE/oaaTObC+oi5GFpmi+tjMxyT7ESPTIfUJfRf0N1o5ncJLvInbsZVtoUSIElJcES6INh7xUEGhkZEO66fZXvTf0zRUNL0J9Ary0Ndf+jQ1bB0Cj/shDtXvp+h4n5M8KUpcUYYbYhCCMDUgSSEEMTGpJGCrGfZU+yez6hW2xU4Q2xXvGw7NSIbGYX5H2YkCUaLi2fZK5ok+xa6EFM6SNRv6Lb4KNFyxzejgTYuxZwYpjVEPsYkyQYhMonrPs2Rw7rYiKlf0NrgaomuCoRLljc9O/oUeNs7/AOn0VG+D/sMJqqn+LPio8CwUuXiweDfGiixMhFoNPeEM4KLKKHRsY+ikfyUTKi4ZRCvE+sTGcDBJLGhNYc9k9kOMvgddCj0SQz7j7hL4QvrEItYoi+DzXHF/oZfM/c5K0voOFSGinAOXgnpz9D8Rr9CrVhdEPZfryOQ3ffYlucbuvQmJiExCZnwT42GyiYT8zH8LSnA8oZPBNm3JxisQECBMJ+LwsNEQxhkwTMtCYxjexMpXBn7GyGz7H0MMGFCYTFKGFy2IZsn1/wBkD3/s1b+4ajuw8U+xhe3wKkk4+xSkkkhn26EVXa4ONrpjUF6EJf6N7Lk/fxP8T//aAAwDAQACAAMAAAAQfLXGYkrmOcme+ZknMuOKv8IjL2woTJZvF9Z/VNBldWbwQQKxWIG/fb/f3vfmu4wSIzzxRiwMhEr7H3wjuCNksUUWWfnKHzCBUF5lm1XYJc603EAU/wCrv/7ev37/AN7b4ik1iXztstizXtrxwf8AGVsSWau7OXrWMiW/AEMbcM9MVlq6Gdl84wqqb18885/++peU6/8AtdeM99t17DsuixKvIKZH3mBG2Z5Id/3tvR0+kGgsZhQBTAIBNJPv2/nPz2jhHjywem8+Se5+Hny8SglEKBw7sscUf53V/HH58gWOjeQ5DhzQbSQZCBOFOo/PHqP6vWa+a8Okj7wxVTX0QI4dBl2FWDQUdqsDl20uRHuH+EhXGW5g39ZWTYPBOLDggAv/AN38MMON/wDfDD9D+ififDie+/fjj/8A34Xnog4vo3XAIYIAAAAAHPPPHPPPAAv/xAAeEQADAQEBAAMBAQAAAAAAAAAAAREQISAwMUBRYf/aAAgBAwEBPxDG6PpCM6QhBIhDhR7qiC6KikJpBGKIIFFtRVrWNoJtif8AcJkJ8M8NzD8AmjhcTSGixSRvWiisopBGZwzfg99nMcGg0X0NmNmPpC5PE8zW6MPClE55K0uKVlyHSMTsgxMyisRY4VHMVFOEKODpB2G0E3hBCEJkJsITYTDZdV6BZHifGrMeIyISIpcomdKylK96Ohf6J36KEhshWUmTITIQmwm0hEKCGQQREIi4uKXKUS4XCkZcg3CieJkRFlCX9GkyF9DhQexui4WXchCIhCIhCEITIQV7JELhfEIRs8psulIxRuk8Q5lw2ysfSkB0Np5StqihCZCEIQhCZCE/MXztfrH/xAAdEQADAQEBAQADAAAAAAAAAAAAAREQISAwMVFg/9oACAECAQE/EKXzSl80hGQhTp06dO5RNL4G7PznSExWcEkyBr9YXCF8z3SlIyMm3JnSMjIsdxHmLx0jIyMjxGIyEJiZCMoVRBMKxKhJLKTzfjFkIQmkEEITEJtITLt2FFFIQh3EWEOFQ1ITTE0ilZcpS+KUpS+UEzhwqKX1fFLs2EIQXOERBERFIOBKPBs8K6QTKXaUpfN80pS5HsJs8TLsREcKcJJILkllFY+428TN0QJETKXKUpS5Sl2lKVsEIdIyZGRkZHiHchCEIRkZ3ymwviELiUEpnRdGmspSl2lLlKX+BH//xAAoEAADAAICAwACAgICAwAAAAAAAREhMRBBUWFxIIGRobHB0eEw8PH/2gAIAQEAAT8QDCyJSROCcKiCcRkLxUUpUYG0ylRRuDcKNNk4VXB/BX45sKFIbIbqmRE9kFENm0xr2Ie0Ne0LZG0ssoYRvZ8Pl9DLF+BqtjcHHY2wmbTE/wB+Cd0JmkM7DLMnQD6kMC3YlKoiDbGQEvSGjoUdHaY1QkbgyPSiLauj0CSr0gv3sa4bRzfqD7jMy8jV4j/AHghOJxCE4hCE5wTicQhBgmQwhvheFKUSIjhJSmTJSsaIZkyUbondmX4KkXBsyPA0XR8Fc1DXsavogSoh7QjtM7UGusGXoRhr2xroZ04Pk+RX0elCNoX4HbQbPoV7YV2md46BCX0jqJD6EPKoafaIW4ZcJCd/6JIoXQJ30xXYkXRHY9zYjs/g3SCquj7GjKxjFu1L5WkRRKYRJfAtRsalaPtc/Q1XKGB4HkapCEITiEITiEIQnEIQn4KR9cCCUEmxJojEmxqEIxucE6UpCE4OhO8Ufp8CDSXRBCEIvBHBZfBqvA5HfOlZI6tMppjReR2W+hs+iOyZHk9QlfSEj0k+Bq6R4B8IUCdCkSMiS7HA25obtCbCN6L9CGI8CVdEhS00eGLOXTpf4ErWWOkoOeDR0MNYF/3GLFLQOO0bNTI3fCcRjUGqQhOIQhCcQhCcQnEJxCEIX4FIo/GGGx5JyIMFRY1B4FQ1ShRzuRKHwK98FAleSxSR4I4YeSD4fD4HZI66I8DzwihXvjBIkFQb8Ib7MXk0LiJGlG0u0K9CAE+WeB8I+5+DNP5iX0JEQuhlHaDcrSu4PwGnGxtVjehjXsIV01uFGbAbrUUXYqGrYza9eBs7Y6x1xGPJCGBqkIUQwQhCEITiEIQhCEITiEJCSRBX+IWCohBER44JcG7G7FBHgi8cYuDV4+gSInBTyRE4pBq8iBtDy0JWJGUVdGT9BVeDPouOhtPbH1g19DJMCVuRCZnYZZEP6G7CkpRjTO/UOTzkWnEkIhdgVVql3waexMcojyWGvaY0ohqtok8CbrbIx4DUjZfDbrQt/mLI50l2xYKtD1mCODMyQNlvGDXkhPRBOySTdLpg1DBghGRjTRCEJxOYQhCEIQhCEIQhOCciCghB5EmiEGm+CRCghHGPw0f4BIiIiMFXFMl4vDaR4ChuhsHXQlQnpGCJ4BqdqK8nZE0SGd0fk3wsXU2KXf8AITL/ALHasqrGO7ENJCcmBq1Bq0zWco06dqPdhBGyWG4dRs3jyS2F5iZGQ6UGqWhjXh+ydiIsXSLJN6JJFaxFVKjWSeW32xm1VUPAWjSLuwR1sjfP0v8AgRNv4D74O+J9H7okvGPJJpjVMcIYMDj/AAjKJwxzCEIQhCcQhCEEILInCE4wjBghgwYKiCCoqKiCBRkK9FRYNV2JhZyioSvsqKiovF9jd7Fkgg5E7owJFtnWYzSjaNg1dMTNGhjSJOMeJDltItcSEzP3P0zUkNM2VFWpDd2eUJi0SBo6F1Qylw/gu6m/YrnVeEtpf2VZDos/gh2I2x7dMZyT4J8V8Q1a5B0rlqJD++SQhr4LZ9ImOybf6DWMqJRwY2n0++RaSSMpPT8P2bn/ACN3yP0iifghCDUIY/DBCFEIQnEITiEJwohUKRKcVcI4Y4pGNUiOevIq4Nzg2XBIuyfJMELsbjwUSnYpqoI8lEwU0xMxou0NA/pMr0+CNnCmmN319E9DswbULsf8HSJmkIhtkG9VMS2bZhpDpayKkm3MF0aX6E6UW30x/BSF9K8Uo4JN9IXqg5tCmjHWJTyNdkvQ/dhUmxENstWRI1Hhr6Q5K2ELQTmQnrJfBs3kqJFJJX2QLt5ayU/eIKTrPGBlU7hd3De4XvfmMXz6YxVf8kV/tYJv0TjHCcYHEYGqQhCGCEfEIQhCcQhCEIQglOHjkcdjVDY2OC/IoME4pmUc7Hjgu4x12VjMfYMuUeljKjpbYmeBR2OTsBstFdE24Sfs7lDewMSi8xJrbGjoh1f2WxJHsiNbQt72P5ymJiqraHUDV3R/ZoT4Jn+iAwFNozCgxGktlbVwn2H0K/0UWXEmaXIkX+A3W2UeB1LGaVjgpylX6J62h7xsW1YeXo6FEamfI084DwHv6Oz/AKFMpFGYhkEdWCUpsa0XaHzLg1/Bkz5LWs20tF60XSQgSax+hZBfAySM6IbTf7Xa9ClqzLYa8r0UNTlBqcGqQhCDUIQwQn4RkKIQhOIQhFybvEEiRIoPBOvwJKhoGbMryO6T6KxPJl0LfQkMLI0+BQVeB+oNzgaJ5TPIQsNpEkl6O9/MQeIiQbcNeyX0vpmV6Yy60Ellj3GjxjsKlrFSKvo17Q1KkR8CPdf0KltUTPb9BjEn+x5WEoJOOk1dPWeO+qCUgNGJ/I21mfYnhlPopZ2N1aD6EEyO/oZ2PrEkqngzS36YEIWhBhKQ7Gun9jMt2QRGZcXp3m/PghCvN2lh/GxIuW/9siRb/aV/yxM2ob6pA38INShr6GPcRnin6ERZErj/AJByVDTSZRtvaEJwwOMjIQjMGBqkIQwYIQwTmMnNEITg1Q5ErKmNEIEexjQleCZ+BME3ihtF3HVp/Sz6hHlFLQ35wGrsdYT6GtMkeRtD1EGRRlPQ3lMgh/sYY1BmdCjGrWV+xmz/AKJCR0IXgwiFvRwOkOgJ0Q0QjaiYkqDXyZ+h7SGoRCUuqIIdayXIaGmgsqnE3SgbNWnYnwpdSyb9xHgqSsaG9tL6YMgf2OmanTCV0JvQ1fQlaEqGi4agxFiVp5TzNjqnprYSab9DbkvchJf0Q2G43uPZJG0b8XRij34QyqlmSkJ9Ak50ZWPpm41a0MmO+FrSXtf32IjyF2TiEMGCEINQwQhghDBCE4QxxCEJy2XYkbPgUjdjZjrIxminkGLQnXY22o6Uyew9xDTNWx72yC08kNX0Nisb6Mm7Sm3xJQxI0KumMqo+idy/kz4CRdoR7EDgbTEb0W2KFhR+hI6HX0NV2MCoaMfYdQ1s0kEmvBU3wXG2h1K4Hb8PQz5CMN7UIrrAq6MT1r6e4HatZ89jVv8Asl3GtR39NY/sZaVJCfgVOuUbux6OoJX2VDafDIUY0OFDaS7yiXwf3ZUaYBNVSfS6LJOtNbjMiPThkCarjYxLX3FMjssS72FHUrXYNwvGxH+xCpY/YdPjYRN0XqVDX/yFWTTj9MhROScjVGoURkMGCGDBXEZghgj4hCDkN8lnkDnxCcJwwxfz10joHCcJeE/h5Avc3+xt6HuPaaBnkIY2xzbHPjHhFKN+BD2ZNHwNXgU7X8DG2jbMfhP6SDaG9IatENLLBrsaZmyYc8mOR6A5spUeWeQNz5D24UUowYYfwmBhhdeo2P7HrP7bqiKtORtjESmgwDmxNDBLWngIngASEduA04bI2eP4ElhLwEpPJ6G5Sb3OdIn6mj/yfv8A8iEIQhCcQhCEIT8P/9k=" + ), + ), + pump_duration=ft.Duration.from_unit(seconds=4), + pump_times=1, + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_timer_picker.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_timer_picker.py new file mode 100644 index 0000000000..1a715635fe --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_timer_picker.py @@ -0,0 +1,28 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_timer_picker_basic(flet_app: ftt.FletTestApp, request): + timer_picker = ft.CupertinoTimerPicker( + value=300, + second_interval=10, + minute_interval=1, + mode=ft.CupertinoTimerPickerMode.HOUR_MINUTE_SECONDS, + ) + + cupertino_bottom_sheet = ft.CupertinoBottomSheet(timer_picker) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog(cupertino_bottom_sheet) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "cupertino_timer_picker_basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_tinted_button.py b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_tinted_button.py new file mode 100644 index 0000000000..0085241bd2 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/cupertino/test_cupertino_tinted_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_tinted_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CupertinoTintedButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/ios/buttons/button_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/ios/buttons/button_1.png new file mode 100644 index 0000000000..fa55a99c02 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/ios/buttons/button_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/ios/buttons/button_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/ios/buttons/button_2.png new file mode 100644 index 0000000000..26cc4d4094 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/ios/buttons/button_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/barrier_color_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/barrier_color_1.png new file mode 100644 index 0000000000..409d0eb8a2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/barrier_color_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/barrier_color_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/barrier_color_2.png new file mode 100644 index 0000000000..9867a97774 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/barrier_color_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/basic.png new file mode 100644 index 0000000000..2b8679b363 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/update_body_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/update_body_1.png new file mode 100644 index 0000000000..369c1871d8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/update_body_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/update_body_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/update_body_2.png new file mode 100644 index 0000000000..b48b0c80de Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/alert_dialog/update_body_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/app_bar/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/app_bar/basic.png new file mode 100644 index 0000000000..df6cc298e4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/app_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/basic.png new file mode 100644 index 0000000000..b651f9c66d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/properties1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/properties1.png new file mode 100644 index 0000000000..72fa1f7fab Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/properties1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/small_size.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/small_size.png new file mode 100644 index 0000000000..beba137021 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/badge/small_size.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/presence_0.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/presence_0.png new file mode 100644 index 0000000000..704e472c7c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/presence_0.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/presence_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/presence_1.png new file mode 100644 index 0000000000..2e9b92c0b1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/presence_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/string_content.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/string_content.png new file mode 100644 index 0000000000..037da66229 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/banner/string_content.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_app_bar/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_app_bar/basic.png new file mode 100644 index 0000000000..eff910fc99 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_app_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_sheet/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_sheet/basic.png new file mode 100644 index 0000000000..9b965ade23 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_sheet/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_sheet/fullscreen.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_sheet/fullscreen.png new file mode 100644 index 0000000000..a75ece1c2c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/bottom_sheet/fullscreen.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/basic.png new file mode 100644 index 0000000000..33c9c5b303 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/issue_5538.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/issue_5538.png new file mode 100644 index 0000000000..0a99816c7a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/issue_5538.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/style.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/style.png new file mode 100644 index 0000000000..501993b495 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/style.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/style_conflicts.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/style_conflicts.png new file mode 100644 index 0000000000..e312bc167b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/button/style_conflicts.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/card/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/card/basic.png new file mode 100644 index 0000000000..cab54c9944 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/card/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/basic.png new file mode 100644 index 0000000000..2d9fef4dcb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_1.png new file mode 100644 index 0000000000..c277ec2b3b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_2.png new file mode 100644 index 0000000000..5fed0cb0b4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_3.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_3.png new file mode 100644 index 0000000000..d47baabfa2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/checkbox/theme_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/chip/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/chip/basic.png new file mode 100644 index 0000000000..c3bb12e519 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/chip/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/chip/clicked.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/chip/clicked.png new file mode 100644 index 0000000000..f46a2f6178 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/chip/clicked.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/background_image_src.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/background_image_src.png new file mode 100644 index 0000000000..cc1b28d544 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/background_image_src.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/foreground_image_src.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/foreground_image_src.png new file mode 100644 index 0000000000..cc1b28d544 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/foreground_image_src.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/icon_content.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/icon_content.png new file mode 100644 index 0000000000..08f551be76 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/icon_content.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/text_content.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/text_content.png new file mode 100644 index 0000000000..9afbfa3e7e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/circle_avatar/text_content.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/context_menu/programmatic_open_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/context_menu/programmatic_open_1.png new file mode 100644 index 0000000000..3e32905bff Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/context_menu/programmatic_open_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/context_menu/programmatic_open_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/context_menu/programmatic_open_2.png new file mode 100644 index 0000000000..3e32905bff Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/context_menu/programmatic_open_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/data_table/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/data_table/basic.png new file mode 100644 index 0000000000..e0e269d9d2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/data_table/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/data_table/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/data_table/theme_1.png new file mode 100644 index 0000000000..c0aab672d2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/data_table/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/basic.png new file mode 100644 index 0000000000..b4b6a3e048 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png new file mode 100644 index 0000000000..48c185d151 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/basic.png new file mode 100644 index 0000000000..3797e0c3c3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png new file mode 100644 index 0000000000..ac6c92a984 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/properties_calendar.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/properties_calendar.png new file mode 100644 index 0000000000..38a98958a6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/properties_calendar.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/properties_input.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/properties_input.png new file mode 100644 index 0000000000..b2734a4ac0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/date_range_picker/properties_input.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/basic.png new file mode 100644 index 0000000000..20beececec Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/properties.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/properties.png new file mode 100644 index 0000000000..3f1e991ffe Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/properties.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/radius.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/radius.png new file mode 100644 index 0000000000..b10f45b964 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/divider/radius.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_0.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_0.png new file mode 100644 index 0000000000..bd328ed14e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_0.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_1.png new file mode 100644 index 0000000000..82857d6888 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_2.png new file mode 100644 index 0000000000..8c3f8289a8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/basic_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/theme_0.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/theme_0.png new file mode 100644 index 0000000000..2309359bbd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/theme_0.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/theme_1.png new file mode 100644 index 0000000000..c597652d1e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/dropdown/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_panel_list/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_panel_list/basic.png new file mode 100644 index 0000000000..6f6f802c6a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_panel_list/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/basic.png new file mode 100644 index 0000000000..65da6999c7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/collapsed.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/collapsed.png new file mode 100644 index 0000000000..a96ab52fc9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/collapsed.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/expanded.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/expanded.png new file mode 100644 index 0000000000..db8e3bf9b3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/expansion_tile/expanded.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_button/basic.png new file mode 100644 index 0000000000..dd8d294496 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_tonal_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_tonal_button/basic.png new file mode 100644 index 0000000000..743680f369 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/filled_tonal_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/basic.png new file mode 100644 index 0000000000..66215d5788 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/center_top_location.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/center_top_location.png new file mode 100644 index 0000000000..7fe13317fc Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/center_top_location.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/disabled.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/disabled.png new file mode 100644 index 0000000000..e4f44e092e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/disabled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/elevation.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/elevation.png new file mode 100644 index 0000000000..cffb2ed57e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/elevation.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/end_top_location.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/end_top_location.png new file mode 100644 index 0000000000..3c59e011de Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/end_top_location.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/focus.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/focus.png new file mode 100644 index 0000000000..44884fe363 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/focus.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/hover.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/hover.png new file mode 100644 index 0000000000..96ebdd05bb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/properties1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/properties1.png new file mode 100644 index 0000000000..16434ba2b4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/floating_action_button/properties1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/basic.png new file mode 100644 index 0000000000..11115d5173 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/horizontal.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/horizontal.png new file mode 100644 index 0000000000..fbd080ea9f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/horizontal.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/horizontal_unbound.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/horizontal_unbound.png new file mode 100644 index 0000000000..4e72b47736 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/horizontal_unbound.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/max_extent.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/max_extent.png new file mode 100644 index 0000000000..d2178613aa Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/grid_view/max_extent.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled.png new file mode 100644 index 0000000000..2b8ba256f9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_disabled.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_disabled.png new file mode 100644 index 0000000000..27226bd234 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_disabled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_selected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_selected.png new file mode 100644 index 0000000000..2b8ba256f9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal.png new file mode 100644 index 0000000000..2c443c0d9e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_disabled.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_disabled.png new file mode 100644 index 0000000000..27226bd234 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_disabled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_selected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_selected.png new file mode 100644 index 0000000000..2c443c0d9e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_unselected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_unselected.png new file mode 100644 index 0000000000..62e5ddd4a9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_tonal_unselected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_unselected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_unselected.png new file mode 100644 index 0000000000..0fc4951743 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/filled_unselected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined.png new file mode 100644 index 0000000000..66ca5e79aa Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_disabled.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_disabled.png new file mode 100644 index 0000000000..aac0ac3711 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_disabled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_selected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_selected.png new file mode 100644 index 0000000000..d1e9f1c901 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_unselected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_unselected.png new file mode 100644 index 0000000000..66ca5e79aa Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/outlined_unselected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard.png new file mode 100644 index 0000000000..ec453a3aac Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_disabled.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_disabled.png new file mode 100644 index 0000000000..68056f597c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_disabled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_selected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_selected.png new file mode 100644 index 0000000000..688d7f5635 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_unselected.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_unselected.png new file mode 100644 index 0000000000..ec453a3aac Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/icon_button/standard_unselected.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/basic.png new file mode 100644 index 0000000000..6ba25bdef4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties1.png new file mode 100644 index 0000000000..0c6caaafc9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties2.png new file mode 100644 index 0000000000..8b7eab046c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties3.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties3.png new file mode 100644 index 0000000000..1b886a722e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/properties3.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_click1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_click1.png new file mode 100644 index 0000000000..48d3500603 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_click1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_hover.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_hover.png new file mode 100644 index 0000000000..d0a319e2d7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_initial.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_initial.png new file mode 100644 index 0000000000..4fe54bb6d1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_tile/toggle_inputs_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/basic.png new file mode 100644 index 0000000000..b41842213c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/horizontal.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/horizontal.png new file mode 100644 index 0000000000..bd99bc66f7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/horizontal.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/horizontal_unbound.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/horizontal_unbound.png new file mode 100644 index 0000000000..3c2b704997 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/list_view/horizontal_unbound.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_1.png new file mode 100644 index 0000000000..4c42278feb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_2.png new file mode 100644 index 0000000000..ccc3379a1a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_3.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_3.png new file mode 100644 index 0000000000..fec4aef4a8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/markdown/md_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_bar/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_bar/basic.png new file mode 100644 index 0000000000..e66981e844 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_bar/basic_open.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_bar/basic_open.png new file mode 100644 index 0000000000..80bf8a3ee8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_bar/basic_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_item_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_item_button/basic.png new file mode 100644 index 0000000000..b7c6f1b38d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/menu_item_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/basic.png new file mode 100644 index 0000000000..91e6047876 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_1.png new file mode 100644 index 0000000000..9c0cc19faf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_2.png new file mode 100644 index 0000000000..29213fb68b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_3.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_3.png new file mode 100644 index 0000000000..59497fa8de Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_bar/theme_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/end_position.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/end_position.png new file mode 100644 index 0000000000..7c37e7cc96 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/end_position.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/start_position.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/start_position.png new file mode 100644 index 0000000000..f940b92969 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/start_position.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/theme.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/theme.png new file mode 100644 index 0000000000..4df968bc82 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/theme.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/with_appbar.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/with_appbar.png new file mode 100644 index 0000000000..f940b92969 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/with_appbar.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/with_cupertino_appbar.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/with_cupertino_appbar.png new file mode 100644 index 0000000000..f5fb85fbec Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_drawer/with_cupertino_appbar.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/basic.png new file mode 100644 index 0000000000..a7ebb029e2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/no_selected_icon.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/no_selected_icon.png new file mode 100644 index 0000000000..444103edb7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/no_selected_icon.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/scrollable_with_pinned_leading_and_trailing.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/scrollable_with_pinned_leading_and_trailing.png new file mode 100644 index 0000000000..ee63226ace Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/scrollable_with_pinned_leading_and_trailing.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/unbounded_height.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/unbounded_height.png new file mode 100644 index 0000000000..38ea12f713 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/navigation_rail/unbounded_height.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/outlined_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/outlined_button/basic.png new file mode 100644 index 0000000000..908dbd6dd5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/outlined_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/basic.png new file mode 100644 index 0000000000..c9a04e690a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/basic_opened.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/basic_opened.png new file mode 100644 index 0000000000..5153641006 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/basic_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/theme.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/theme.png new file mode 100644 index 0000000000..84b7705df3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/theme.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/theme_opened.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/theme_opened.png new file mode 100644 index 0000000000..4e61ffe793 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/popup_menu_button/theme_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/progress_bar/determinate.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/progress_bar/determinate.png new file mode 100644 index 0000000000..b6860d3dd8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/progress_bar/determinate.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/radio/basic_one.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/radio/basic_one.png new file mode 100644 index 0000000000..b171fe5301 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/radio/basic_one.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/radio/basic_three.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/radio/basic_three.png new file mode 100644 index 0000000000..07e4aae5e4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/radio/basic_three.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/default.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/default.png new file mode 100644 index 0000000000..0c6a1855d5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/default.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/slider_move.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/slider_move.png new file mode 100644 index 0000000000..620b587296 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/slider_move.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/tap.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/tap.png new file mode 100644 index 0000000000..b33f089ee0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/range_slider/tap.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/reorderable_list_view/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/reorderable_list_view/basic.png new file mode 100644 index 0000000000..97f53185c7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/reorderable_list_view/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/reorderable_list_view/custom_drag_handle.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/reorderable_list_view/custom_drag_handle.png new file mode 100644 index 0000000000..d95649aac3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/reorderable_list_view/custom_drag_handle.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/basic.png new file mode 100644 index 0000000000..24b3ddb9f9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/basic_opened.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/basic_opened.png new file mode 100644 index 0000000000..e725e36977 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/basic_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme.png new file mode 100644 index 0000000000..bd1642c81f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme_hovered.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme_hovered.png new file mode 100644 index 0000000000..3d64f6c4c6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme_hovered.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme_opened.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme_opened.png new file mode 100644 index 0000000000..3a40cffbae Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/search_bar/theme_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/segmented_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/segmented_button/basic.png new file mode 100644 index 0000000000..b3ca5fd84e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/segmented_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/segmented_button/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/segmented_button/theme_1.png new file mode 100644 index 0000000000..3e57375826 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/segmented_button/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/slider/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/slider/basic.png new file mode 100644 index 0000000000..ff33f19ef4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/slider/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/slider/range_and_label.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/slider/range_and_label.png new file mode 100644 index 0000000000..d16283a6e8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/slider/range_and_label.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/basic.png new file mode 100644 index 0000000000..5b3879f380 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/cupertino_page.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/cupertino_page.png new file mode 100644 index 0000000000..6435c56056 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/cupertino_page.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/custom_action.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/custom_action.png new file mode 100644 index 0000000000..438bfa00ea Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/custom_action.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/simple_action.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/simple_action.png new file mode 100644 index 0000000000..e7e84d5286 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/snack_bar/simple_action.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/submenu_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/submenu_button/basic.png new file mode 100644 index 0000000000..b7c6f1b38d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/submenu_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/basic.png new file mode 100644 index 0000000000..9268dc8162 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/nesting.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/nesting.png new file mode 100644 index 0000000000..87eaacdca0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/nesting.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/unbounded_tabbarview_height.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/unbounded_tabbarview_height.png new file mode 100644 index 0000000000..1b69a0efda Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/tabs/unbounded_tabbarview_height.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/text_button/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/text_button/basic.png new file mode 100644 index 0000000000..3068e86755 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/text_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/basic.png new file mode 100644 index 0000000000..3eef714a01 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/label.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/label.png new file mode 100644 index 0000000000..02ed560e89 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/label.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/label_and_value.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/label_and_value.png new file mode 100644 index 0000000000..e869a70b19 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/textfield/label_and_value.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/basic.png new file mode 100644 index 0000000000..1a54ee0c8a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_12.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_12.png new file mode 100644 index 0000000000..80d7facc86 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_12.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_24.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_24.png new file mode 100644 index 0000000000..3c0d045164 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/hour_format_24.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/locale.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/locale.png new file mode 100644 index 0000000000..0bde9394c3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/time_picker/locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/vertical_divider/basic.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/vertical_divider/basic.png new file mode 100644 index 0000000000..bbc8d1a0e9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/vertical_divider/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/vertical_divider/properties.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/vertical_divider/properties.png new file mode 100644 index 0000000000..3322a849f2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/macos/vertical_divider/properties.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_1.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_1.png new file mode 100644 index 0000000000..549451ad26 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_2.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_2.png new file mode 100644 index 0000000000..c87cfdb1ee Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_3.png b/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_3.png new file mode 100644 index 0000000000..c0414dd0f7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/material/golden/windows/markdown/md_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_alert_dialog.py b/sdk/python/packages/flet/integration_tests/controls/material/test_alert_dialog.py new file mode 100644 index 0000000000..2951aebd08 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_alert_dialog.py @@ -0,0 +1,114 @@ +import asyncio + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + ad = ft.AlertDialog( + key="ad", + title=ft.Text("Hello"), + content=ft.Text("You are notified!"), + alignment=ft.Alignment.CENTER, + on_dismiss=lambda e: print("Dialog dismissed!"), + title_padding=ft.Padding.all(25), + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog(ad) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_update_body(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ad := ft.AlertDialog( + key="ad", + title=ft.Text("Test"), + bgcolor=ft.Colors.YELLOW, + actions_alignment=ft.MainAxisAlignment.END, + actions=[ + ok := ft.TextButton("OK", visible=True), + cancel := ft.TextButton("Cancel", visible=True), + ], + ) + ) + await flet_app.tester.pump_and_settle() + assert (await flet_app.tester.find_by_text("OK")).count == 1 + flet_app.assert_screenshot( + "update_body_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # change dialog color and hide "OK" button + await asyncio.sleep(1) + ad.bgcolor = ft.Colors.RED + ok.visible = not ok.visible # hide button + cancel.disabled = not cancel.disabled # disable button + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + assert (await flet_app.tester.find_by_text("OK")).count == 0 + flet_app.assert_screenshot( + "update_body_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_barrier_color(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 500) + flet_app.page.update() + + flet_app.page.show_dialog( + ad := ft.AlertDialog( + title=ft.Text("Barrier"), + content=ft.Text("Watch the barrier color."), + barrier_color=ft.Colors.RED, + ) + ) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "barrier_color_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + ad.barrier_color = ft.Colors.BLUE + flet_app.page.update() + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "barrier_color_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_app_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_app_bar.py new file mode 100644 index 0000000000..afa7368a07 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_app_bar.py @@ -0,0 +1,22 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.AppBar( + bgcolor=ft.Colors.PRIMARY_CONTAINER, + leading=ft.Icon(ft.Icons.PALETTE), + leading_width=40, + title=ft.Text("AppBar Test"), + center_title=False, + actions=[ + ft.IconButton(icon=ft.Icons.TAB), + ft.IconButton(icon=ft.Icons.WALLET), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_badge.py b/sdk/python/packages/flet/integration_tests/controls/material/test_badge.py new file mode 100644 index 0000000000..0e60e53297 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_badge.py @@ -0,0 +1,67 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton(icon=ft.Icons.PHONE, badge=ft.Badge()), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_properties1(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton( + icon=ft.Icons.PHONE, + badge=ft.Badge( + label="1", + offset=ft.Offset(5, 5), + alignment=ft.Alignment(-1, -1), + bgcolor=ft.Colors.GREEN, + # label_visible=False, + large_size=20, + small_size=10, + padding=ft.Padding.all(5), + text_color=ft.Colors.YELLOW, + text_style=ft.TextStyle( + size=10, + weight=ft.FontWeight.BOLD, + color=ft.Colors.BLACK, + italic=True, + ), + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_small_size(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton( + icon=ft.Icons.PHONE, + badge=ft.Badge( + # label="1", + offset=ft.Offset(5, 5), + alignment=ft.Alignment(-1, -1), + bgcolor=ft.Colors.GREEN, + # label_visible=False, + large_size=20, + small_size=10, + # padding=ft.Padding.all(5), + # text_color=ft.Colors.YELLOW, + # text_style=ft.TextStyle( + # size=10, + # weight=ft.FontWeight.BOLD, + # color=ft.Colors.BLACK, + # italic=True, + # ), + ), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_banner.py b/sdk/python/packages/flet/integration_tests/controls/material/test_banner.py new file mode 100644 index 0000000000..042be31baa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_banner.py @@ -0,0 +1,97 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_presence(flet_app: ftt.FletTestApp, request): + action_button_style = ft.ButtonStyle(color=ft.Colors.BLUE) + + def handle_banner_close(e: ft.Event[ft.TextButton]): + flet_app.page.pop_dialog() + flet_app.page.add(ft.Text(f"Action clicked: {e.control.content}")) + + banner = ft.Banner( + key="banner", + bgcolor=ft.Colors.AMBER_100, + leading=ft.Icon(ft.Icons.WARNING_AMBER_ROUNDED, color=ft.Colors.AMBER, size=40), + content=ft.Text( + value="Oops, there were some errors while trying to delete the file. What " + "would you like to do?", + color=ft.Colors.BLACK, + ), + actions=[ + ft.TextButton( + content="Retry", + style=action_button_style, + on_click=handle_banner_close, + key="retry", + ), + ft.TextButton( + content="Cancel", + style=action_button_style, + on_click=handle_banner_close, + key="cancel", + ), + ], + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add( + ft.Button( + key="eb", + content="Show Banner", + on_click=lambda e: flet_app.page.show_dialog(banner), + ) + ) + await flet_app.tester.pump_and_settle() + + await flet_app.tester.tap(await flet_app.tester.find_by_key("eb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "presence_0", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + await flet_app.tester.tap(await flet_app.tester.find_by_key("retry")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "presence_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_string_content(flet_app: ftt.FletTestApp, request): + banner = ft.Banner( + "This is a banner with string content.", + actions=[ + ft.TextButton("Retry"), + ft.TextButton("Cancel"), + ], + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.show_dialog(banner) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_bottom_app_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_bottom_app_bar.py new file mode 100644 index 0000000000..2dd0b2a9fa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_bottom_app_bar.py @@ -0,0 +1,23 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.BottomAppBar( + bgcolor=ft.Colors.BLUE, + shape=ft.CircularRectangleNotchShape(), + content=ft.Row( + controls=[ + ft.IconButton(icon=ft.Icons.MENU, icon_color=ft.Colors.WHITE), + ft.Container(expand=True), + ft.IconButton(icon=ft.Icons.SEARCH, icon_color=ft.Colors.WHITE), + ft.IconButton(icon=ft.Icons.FAVORITE, icon_color=ft.Colors.WHITE), + ] + ), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_bottom_sheet.py b/sdk/python/packages/flet/integration_tests/controls/material/test_bottom_sheet.py new file mode 100644 index 0000000000..53b6404d60 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_bottom_sheet.py @@ -0,0 +1,65 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + sheet = ft.BottomSheet( + content=ft.Container( + padding=50, + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + tight=True, + controls=[ + ft.Text("Here is a bottom sheet!"), + ft.Button("Dismiss", on_click=lambda _: flet_app.page.pop_dialog()), + ], + ), + ), + ) + flet_app.page.show_dialog(sheet) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_fullscreen(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + sheet = ft.BottomSheet( + fullscreen=True, + content=ft.Container( + padding=50, + content=ft.Column( + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + tight=True, + controls=[ + ft.Text("Here is a bottom sheet!"), + ft.Button("Dismiss", on_click=lambda _: flet_app.page.pop_dialog()), + ], + ), + ), + ) + flet_app.page.show_dialog(sheet) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_button.py new file mode 100644 index 0000000000..1787abc7e4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_button.py @@ -0,0 +1,74 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Button("Click me"), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_issue_5538(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.Button( + content="Button 1", + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=4)), + ), + ft.Button( + content="Button 2", + bgcolor=ft.Colors.RED, + style=ft.ButtonStyle(shape=ft.RoundedRectangleBorder(radius=4)), + ), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_style(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Button( + content="Test Button", + style=ft.ButtonStyle( + bgcolor=ft.Colors.BLUE, + shape=ft.RoundedRectangleBorder(radius=10), + side=ft.BorderSide(width=3, color=ft.Colors.YELLOW), + padding=ft.Padding.all(20), + text_style=ft.TextStyle( + size=15, + weight=ft.FontWeight.BOLD, + color=ft.Colors.WHITE, + ), + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_style_conflicts(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Button( + content="Test Button", + elevation=10, + color=ft.Colors.BLACK, + bgcolor=ft.Colors.BLUE, + style=ft.ButtonStyle( + elevation=2, + color=ft.Colors.WHITE, + bgcolor=ft.Colors.RED, + ), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_card.py b/sdk/python/packages/flet/integration_tests/controls/material/test_card.py new file mode 100644 index 0000000000..d5f127e906 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_card.py @@ -0,0 +1,18 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Card( + content=ft.Container( + width=400, + padding=10, + content=ft.Text("Card"), + ), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_checkbox.py b/sdk/python/packages/flet/integration_tests/controls/material/test_checkbox.py new file mode 100644 index 0000000000..347a0dbb96 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_checkbox.py @@ -0,0 +1,67 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Checkbox(), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp): + flet_app.page.theme = ft.Theme( + checkbox_theme=ft.CheckboxTheme( + check_color=ft.Colors.RED, + overlay_color=ft.Colors.GREEN, + fill_color=ft.Colors.BLUE, + splash_radius=30, + border_side=ft.BorderSide(color=ft.Colors.YELLOW, width=1), + visual_density=ft.VisualDensity.COMPACT, + shape=ft.BeveledRectangleBorder(radius=ft.BorderRadius.all(10)), + mouse_cursor=ft.MouseCursor.FORBIDDEN, + ) + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + scr_1 = ft.Screenshot(cb := ft.Checkbox(key="cb", value=True, margin=20)) + flet_app.page.add(scr_1) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + # hover to check overlay color and splash radius + checkbox = await flet_app.tester.find_by_key("cb") + assert checkbox.count == 1 + await flet_app.tester.mouse_hover(checkbox) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_2", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + # uncheck the checkbox to test border side + cb.value = False + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_3", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_chip.py b/sdk/python/packages/flet/integration_tests/controls/material/test_chip.py new file mode 100644 index 0000000000..15d888375c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_chip.py @@ -0,0 +1,53 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Chip( + label=ft.Text("Save to favourites"), + leading=ft.Icon(ft.Icons.FAVORITE_BORDER_OUTLINED), + bgcolor=ft.Colors.GREEN_200, + disabled_color=ft.Colors.GREEN_100, + autofocus=True, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_clicked(flet_app: ftt.FletTestApp, request): + flet_app.page.clean() + await flet_app.tester.pump_and_settle() + + def handle_chip_click(e: ft.Event[ft.Chip]): + e.control.label.value = "Saved to favorites" + e.control.leading = ft.Icon(ft.Icons.FAVORITE_OUTLINED) + e.control.disabled = True + + chip = ft.Chip( + label=ft.Text("Save to favourites"), + leading=ft.Icon(ft.Icons.FAVORITE_BORDER_OUTLINED), + bgcolor=ft.Colors.GREEN_200, + disabled_color=ft.Colors.GREEN_100, + autofocus=True, + on_click=handle_chip_click, + key="chip", + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(chip) + await flet_app.tester.pump_and_settle() + await flet_app.tester.tap(await flet_app.tester.find_by_key("chip")) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_circle_avatar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_circle_avatar.py new file mode 100644 index 0000000000..856cf342de --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_circle_avatar.py @@ -0,0 +1,66 @@ +import base64 + +import pytest + +import flet as ft +import flet.testing as ftt + +base64_image = "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" # noqa: E501 + + +@pytest.mark.asyncio(loop_scope="module") +async def test_text_content(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CircleAvatar(content=ft.Text("Text")), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_icon_content(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.CircleAvatar( + content=ft.Icon(ft.Icons.ABC), + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_foreground_image_src(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + width=300, + controls=[ + ft.CircleAvatar(foreground_image_src="/minion.png"), + ft.CircleAvatar(foreground_image_src=base64_image), + ft.CircleAvatar(foreground_image_src=base64.b64decode(base64_image)), + ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" # noqa: E501 + ), + ], + ), + pump_times=1, + pump_duration=1000, + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_background_image_src(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Row( + width=300, + controls=[ + ft.CircleAvatar(background_image_src="/minion.png"), + ft.CircleAvatar(background_image_src=base64_image), + ft.CircleAvatar(background_image_src=base64.b64decode(base64_image)), + ft.CircleAvatar( + background_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" # noqa: E501 + ), + ], + ), + pump_times=1, + pump_duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_context_menu.py b/sdk/python/packages/flet/integration_tests/controls/material/test_context_menu.py new file mode 100644 index 0000000000..44f71819d9 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_context_menu.py @@ -0,0 +1,38 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_programmatic_open(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(250, 250) + flet_app.page.add( + menu := ft.ContextMenu( + content=ft.IconButton(ft.Icons.MENU), + items=[ + ft.PopupMenuItem("Item 1"), + ft.PopupMenuItem("Item 2"), + ft.PopupMenuItem("Item 3"), + ], + ) + ) + await flet_app.tester.pump_and_settle() + + await menu.open() + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "programmatic_open_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "programmatic_open_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_data_table.py b/sdk/python/packages/flet/integration_tests/controls/material/test_data_table.py new file mode 100644 index 0000000000..f637caf357 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_data_table.py @@ -0,0 +1,34 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.DataTable( + columns=[ + ft.DataColumn(label="Column 1"), + ft.DataColumn(label=ft.Text("Column 2")), + ft.DataColumn(label=ft.Text("Column 3")), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell("Item 1"), + ft.DataCell(ft.Text("Item 2")), + ft.DataCell(ft.Text("Item 3")), + ] + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_date_picker.py b/sdk/python/packages/flet/integration_tests/controls/material/test_date_picker.py new file mode 100644 index 0000000000..c7c351c049 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_date_picker.py @@ -0,0 +1,60 @@ +import datetime + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DatePicker( + first_date=datetime.datetime(year=2000, month=10, day=1), + current_date=datetime.datetime(year=2025, month=8, day=15), + last_date=datetime.datetime(year=2025, month=10, day=1), + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_locale(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DatePicker( + locale=ft.Locale("zh", "Hans"), + first_date=datetime.datetime(year=2000, month=10, day=1), + current_date=datetime.datetime(year=2025, month=8, day=15), + last_date=datetime.datetime(year=2025, month=10, day=1), + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_date_range_picker.py b/sdk/python/packages/flet/integration_tests/controls/material/test_date_range_picker.py new file mode 100644 index 0000000000..9397cac750 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_date_range_picker.py @@ -0,0 +1,118 @@ +import datetime + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DateRangePicker( + start_value=datetime.datetime(year=2000, month=10, day=1), + end_value=datetime.datetime(year=2000, month=10, day=15), + first_date=datetime.datetime(year=2000, month=10, day=1), + last_date=datetime.datetime(year=2000, month=11, day=15), + current_date=datetime.datetime(year=2000, month=10, day=16), + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties1(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DateRangePicker( + start_value=datetime.datetime(year=2000, month=10, day=7), + end_value=datetime.datetime(year=2000, month=10, day=15), + first_date=datetime.datetime(year=2000, month=10, day=1), + last_date=datetime.datetime(year=2000, month=11, day=15), + current_date=datetime.datetime(year=2000, month=10, day=16), + switch_to_calendar_icon=ft.Icons.BABY_CHANGING_STATION, + switch_to_input_icon=ft.Icons.ACCESS_ALARM, + save_text="Custom save text", + error_invalid_range_text="Invalid range custom text", + help_text="Custom help text", + cancel_text="Custom cancel text", + confirm_text="Custom confirm text", + error_format_text="Custom error format text", + error_invalid_text="Custom error invalid text", + field_end_hint_text="Custom end hint text", + field_start_hint_text="Custom start hint text", + field_end_label_text="Custom end label text", + field_start_label_text="Custom start label text", + modal=False, + barrier_color=ft.Colors.RED, + keyboard_type=ft.KeyboardType.EMAIL, + # entry_mode=ft.DatePickerEntryMode.CALENDAR, + ) + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "properties_calendar", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # change to input mode + input_icon = await flet_app.tester.find_by_icon(ft.Icons.ACCESS_ALARM) + assert input_icon.count == 1 + await flet_app.tester.tap(input_icon) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "properties_input", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_locale(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DateRangePicker( + locale=ft.Locale("zh", "Hans"), + start_value=datetime.datetime(year=2000, month=10, day=1), + end_value=datetime.datetime(year=2000, month=10, day=15), + first_date=datetime.datetime(year=2000, month=10, day=1), + last_date=datetime.datetime(year=2000, month=11, day=15), + current_date=datetime.datetime(year=2000, month=10, day=16), + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_divider.py b/sdk/python/packages/flet/integration_tests/controls/material/test_divider.py new file mode 100644 index 0000000000..2339eac9f9 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_divider.py @@ -0,0 +1,48 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Divider(), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Divider( + color=ft.Colors.RED, + height=50, + thickness=2, + leading_indent=20, + trailing_indent=20, + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_radius(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Divider( + color=ft.Colors.RED, + height=40, + radius=20, + thickness=30, + leading_indent=20, + trailing_indent=20, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_dropdown.py b/sdk/python/packages/flet/integration_tests/controls/material/test_dropdown.py new file mode 100644 index 0000000000..7e9c4c6933 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_dropdown.py @@ -0,0 +1,120 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(350, 300) + + colors = ["red", "blue", "green"] + flet_app.page.add( + dd := ft.Dropdown( + key="dd", + label="Color", + text="Select a color", + options=[ + ft.DropdownOption(key=color, content=ft.Text(value=color, color=color)) + for color in colors + ], + ) + ) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "basic_0", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("dd")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "basic_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # select red option + red_options = await flet_app.tester.find_by_text("red") + assert red_options.count == 2 # Flutter Finder bug - should be 1 + await flet_app.tester.tap(red_options.last) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "basic_2", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # clear value + dd.value = None + dd.update() + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "basic_0", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(350, 300) + flet_app.page.theme = ft.Theme( + dropdown_theme=ft.DropdownTheme( + text_style=ft.TextStyle(color=ft.Colors.PURPLE, size=20), + menu_style=ft.MenuStyle( + alignment=ft.Alignment.BOTTOM_CENTER, + elevation=10, + bgcolor=ft.Colors.GREEN_300, + ), + ) + ) + + colors = [ft.Colors.RED, ft.Colors.BLUE, ft.Colors.GREEN] + flet_app.page.add( + ft.Dropdown( + key="dd", + label="Color", + text="Select a color", + options=[ + ft.DropdownOption(key=color.value, content=ft.Text(value=color.value)) + for color in colors + ], + ) + ) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "theme_0", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("dd")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_expansion_panel_list.py b/sdk/python/packages/flet/integration_tests/controls/material/test_expansion_panel_list.py new file mode 100644 index 0000000000..3ae6042f3a --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_expansion_panel_list.py @@ -0,0 +1,14 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ExpansionPanelList( + controls=[ft.ExpansionPanel(ft.Text("Expansion Panel"))], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_expansion_tile.py b/sdk/python/packages/flet/integration_tests/controls/material/test_expansion_tile.py new file mode 100644 index 0000000000..00e7bb48ee --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_expansion_tile.py @@ -0,0 +1,65 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + await flet_app.assert_control_screenshot( + request.node.name, + ft.ExpansionTile( + title="ExpansionTile Title", + subtitle="ExpansionTile Subtitle", + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_expanded(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.add( + tile := ft.ExpansionTile( + key="tile", + expanded=False, + title="ExpansionTile Title", + subtitle="ExpansionTile Subtitle", + trailing=ft.Icons.SUNNY, + controls_padding=ft.Padding.all(10), + tile_padding=ft.Padding.all(20), + affinity=ft.TileAffinity.LEADING, + controls=[ + ft.Text("ExpansionTile Content"), + ft.Text("More Content"), + ], + ) + ) + await flet_app.tester.pump_and_settle() + + # collapsed state + assert tile.expanded is False + await flet_app.assert_control_screenshot("collapsed", tile) + + # tap/click on the tile to expand + await flet_app.tester.tap(await flet_app.tester.find_by_key("tile")) + await flet_app.tester.pump_and_settle() + + # expanded state + assert tile.expanded is True + await flet_app.assert_control_screenshot("expanded", tile) + + # collapse programatically + tile.expanded = False + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + # collapsed state + await flet_app.assert_control_screenshot("collapsed", tile) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py new file mode 100644 index 0000000000..84ca94af5a --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py new file mode 100644 index 0000000000..b7ec452f08 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_filled_tonal_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledTonalButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_floating_action_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_floating_action_button.py new file mode 100644 index 0000000000..a091b75438 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_floating_action_button.py @@ -0,0 +1,143 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FloatingActionButton("OK"), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties1(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FloatingActionButton( + content="Add", + icon=ft.Icons.ADD, + bgcolor=ft.Colors.GREEN, + shape=ft.RoundedRectangleBorder( + radius=4, side=ft.BorderSide(color=ft.Colors.RED, width=2.0) + ), + autofocus=False, + foreground_color=ft.Colors.PURPLE, + clip_behavior=ft.ClipBehavior.ANTI_ALIAS, # not shows on screenshot + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties2(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + fab = ft.FloatingActionButton( + key="fab", + content="Add", + bgcolor=ft.Colors.GREEN, + focus_color=ft.Colors.YELLOW, + elevation=20, + focus_elevation=50, + disabled_elevation=30, + hover_elevation=100, + hover_color=ft.Colors.BLUE, + highlight_elevation=50, # is not shown on screenshots + splash_color=ft.Colors.ORANGE, # is not shown on screenshots + enable_feedback=True, # is not shown on screenshots + url="https://example.com", # is not shown on screenshots + mouse_cursor=ft.MouseCursor.COPY, # is not shown on screenshots + ) + flet_app.page.add(fab) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "elevation", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test focus color + fab.autofocus = True + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "focus", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test disabled + fab.autofocus = False + fab.disabled = True + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "disabled", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test hover + fab.disabled = False + flet_app.page.update() + await flet_app.tester.pump_and_settle() + button = await flet_app.tester.find_by_key("fab") + assert button.count == 1 + await flet_app.tester.mouse_hover(button) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "hover", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_location(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.floating_action_button = ft.FloatingActionButton("OK") + + # center_top_location + loc = ft.FloatingActionButtonLocation.CENTER_TOP + flet_app.page.floating_action_button_location = loc + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "center_top_location", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # end_top_location + loc = ft.FloatingActionButtonLocation.END_TOP + flet_app.page.floating_action_button_location = loc + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "end_top_location", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_grid_view.py b/sdk/python/packages/flet/integration_tests/controls/material/test_grid_view.py new file mode 100644 index 0000000000..ddf2f5d01c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_grid_view.py @@ -0,0 +1,73 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.GridView( + controls=[ + ft.Container(ft.Text("Item 1"), bgcolor=ft.Colors.BLUE), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_max_extent(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.GridView( + max_extent=200, + controls=[ + ft.Container(ft.Text("Item 1"), bgcolor=ft.Colors.BLUE), + ft.Container(ft.Text("Item 2"), bgcolor=ft.Colors.GREEN), + ft.Container(ft.Text("Item 3"), bgcolor=ft.Colors.RED), + ft.Container(ft.Text("Item 4"), bgcolor=ft.Colors.YELLOW), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_horizontal_unbound(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.GridView( + horizontal=True, + controls=[ + ft.Container( + ft.Text("Item 1"), + bgcolor=ft.Colors.BLUE, + ) + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_horizontal(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.GridView( + horizontal=True, + height=100, + controls=[ + ft.Container( + ft.Text("Item 1"), + bgcolor=ft.Colors.BLUE, + ), + ft.Container( + ft.Text("Item 2"), + bgcolor=ft.Colors.RED, + ), + ft.Container( + ft.Text("Item 3"), + bgcolor=ft.Colors.GREEN, + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_icon_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_icon_button.py new file mode 100644 index 0000000000..a2f5117e35 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_icon_button.py @@ -0,0 +1,132 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_standard(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton(ft.Icons.HOME), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_standard_disabled(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton(ft.Icons.HOME, disabled=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_standard_selected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton(ft.Icons.HOME, selected=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_standard_unselected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton(ft.Icons.HOME, selected=False), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledIconButton(ft.Icons.HOME), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_disabled(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledIconButton(ft.Icons.HOME, disabled=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_selected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledIconButton(ft.Icons.HOME, selected=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_unselected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledIconButton(ft.Icons.HOME, selected=False), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_tonal(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledTonalIconButton(ft.Icons.HOME), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_tonal_disabled(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledTonalIconButton(ft.Icons.HOME, disabled=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_tonal_selected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledTonalIconButton(ft.Icons.HOME, selected=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_filled_tonal_unselected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledTonalIconButton(ft.Icons.HOME, selected=False), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_outlined(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.OutlinedIconButton(ft.Icons.HOME), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_outlined_disabled(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.OutlinedIconButton(ft.Icons.HOME, disabled=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_outlined_selected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.OutlinedIconButton(ft.Icons.HOME, selected=True), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_outlined_unselected(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.OutlinedIconButton(ft.Icons.HOME, selected=False), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_list_tile.py b/sdk/python/packages/flet/integration_tests/controls/material/test_list_tile.py new file mode 100644 index 0000000000..f02439daa1 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_list_tile.py @@ -0,0 +1,284 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ListTile("List Tile"), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties1(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.ListTile( + "List Tile with custom shape", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + shape=ft.RoundedRectangleBorder( + radius=10, side=ft.BorderSide(color=ft.Colors.RED, width=2.0) + ), + ), + ft.ListTile( + "Dense List Tile", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + dense=True, + ), + ft.ListTile( + "List Tile with Content Padding", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + content_padding=ft.Padding.all(20), + ), + ft.ListTile( + "List Tile with autofocus", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + autofocus=True, + ), + ft.ListTile( + "Disabled List Tile", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + disabled=True, + ), + ft.ListTile( + "Selected List Tile", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + selected=True, + selected_color=ft.Colors.PINK_200, + selected_tile_color=ft.Colors.PURPLE_200, + ), + ft.ListTile( + "Drawer style List Tile", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + style=ft.ListTileStyle.DRAWER, + ), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties2(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.ListTile( + title="List Tile with horizontal spacing", + subtitle="Subtitle", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + splash_color=ft.Colors.GREEN_200, # is not shown on screenshot + hover_color=ft.Colors.YELLOW_200, + horizontal_spacing=50, + title_alignment=ft.ListTileTitleAlignment.THREE_LINE, + ), + ft.ListTile( + title="List Tile with minimum leading width", + subtitle="Top Title Alignment", + is_three_line=True, + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + splash_color=ft.Colors.GREEN_200, # is not shown on screenshot + hover_color=ft.Colors.YELLOW_200, + min_leading_width=100, + title_alignment=ft.ListTileTitleAlignment.TOP, # default value + ), + ft.ListTile( + title="List Tile with minimum vertical padding", + subtitle="Center Title Alignment", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + splash_color=ft.Colors.GREEN_200, # is not shown on screenshot + hover_color=ft.Colors.YELLOW_200, + min_vertical_padding=30, + title_alignment=ft.ListTileTitleAlignment.CENTER, + ), + ft.ListTile( + title="List Tile with icon color and text color and styles", + subtitle="Bottom Title Alignment", + icon_color=ft.Colors.RED, + text_color=ft.Colors.PURPLE, + title_text_style=ft.TextStyle(size=20, weight=ft.FontWeight.BOLD), + subtitle_text_style=ft.TextStyle(size=10, italic=True), + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + title_alignment=ft.ListTileTitleAlignment.BOTTOM, + ), + ft.ListTile( + title="List Tile with leading and trailing text style", + subtitle="Title Height Title Alignment", + icon_color=ft.Colors.PINK, + leading=ft.Text("Leading"), + trailing=ft.Text("Trailing"), + leading_and_trailing_text_style=ft.TextStyle( + color=ft.Colors.RED, + size=12, + ), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + title_alignment=ft.ListTileTitleAlignment.TITLE_HEIGHT, + ), + ft.ListTile( + title="List Tile with minimum height", + subtitle="Title Height Title Alignment", + icon_color=ft.Colors.RED, + leading=ft.Text("Leading"), + trailing=ft.Text("Trailing"), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + min_height=150, + title_alignment=ft.ListTileTitleAlignment.TITLE_HEIGHT, + ), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties3(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.ListTile( + title="List Tile without three line", + subtitle="Long Long Long Long Long Long Long Long Long Long Long " + "Long Long Long Long Long Long Long Long Long Long Long" + "Long Subtitle with is_three_line = False", + # is_three_line=True, + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + ), + ft.ListTile( + title="List Tile with three line", + subtitle="Long Long Long Long Long Long Long Long Long Long Long " + "Long Long Long Long Long Long Long Long Long Long Long" + "Long Subtitle with is_three_line = True", + is_three_line=True, # not sure if this behaviour is correct or not. + # Tested it in flutter, it also shows more than 3 lines + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + ), + ft.ListTile( + title="List Tile with Compact visual density", + subtitle="Long Long Long Long Long Long Long Long Long Long Long " + "Long Long Long Long Long Long Long Long Long Long Long" + "Long Subtitle with is_three_line = False", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + visual_density=ft.VisualDensity.COMPACT, + ), + ft.ListTile( + title="List Tile with Standard visual density", + subtitle="Long Long Long Long Long Long Long Long Long Long Long " + "Long Long Long Long Long Long Long Long Long Long Long" + "Long Subtitle with is_three_line = False", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Icon(ft.Icons.ARROW_FORWARD), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + visual_density=ft.VisualDensity.STANDARD, + ), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_toggle_inputs(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + lt = ft.ListTile( + key="lt", + title="ListTileStyle with toggle inputs", + subtitle="List", + leading=ft.Icon(ft.Icons.STAR), + trailing=ft.Checkbox(), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + style=ft.ListTileStyle.LIST, + hover_color=ft.Colors.YELLOW_200, + toggle_inputs=True, + ) + + flet_app.page.add(lt) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "toggle_inputs_initial", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test hover + tile = await flet_app.tester.find_by_key("lt") + assert tile.count == 1 + await flet_app.tester.mouse_hover(tile) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "toggle_inputs_hover", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + await flet_app.tester.tap(tile) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "toggle_inputs_click1", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test click2 - issue #5627 + # await flet_app.tester.tap(tile) + # await flet_app.tester.pump_and_settle() + + # flet_app.assert_screenshot( + # "toggle_click2", + # await flet_app.page.take_screenshot( + # pixel_ratio=flet_app.screenshots_pixel_ratio + # ), + # ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_list_view.py b/sdk/python/packages/flet/integration_tests/controls/material/test_list_view.py new file mode 100644 index 0000000000..f4c9a7eba5 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_list_view.py @@ -0,0 +1,47 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ListView( + controls=[ + ft.ListTile("List Tile"), + ] + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_horizontal(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ListView( + horizontal=True, + height=100, + controls=[ + ft.Text("List item 1"), + ft.Text("List item 2"), + ft.Text("List item 3"), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_horizontal_unbound(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ListView( + horizontal=True, + controls=[ + ft.Text("List item 1"), + ft.Text("List item 2"), + ft.Text("List item 3"), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_markdown.py b/sdk/python/packages/flet/integration_tests/controls/material/test_markdown.py new file mode 100644 index 0000000000..f084ce5446 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_markdown.py @@ -0,0 +1,130 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +sample_1 = """ +# Markdown Example +Markdown allows you to easily include formatted text, images, and even formatted Dart +code in your app. + +## Titles + +Setext-style + +This is an H1 +============= + +This is an H2 +------------- + +Atx-style + +# This is an H1 + +## This is an H2 + +###### This is an H6 + +Select the valid headers: + +- [x] `# hello` +- [ ] `#hello` + +## Links + +[inline-style](https://www.google.com) + +## Styling + +Style text as _italic_, __bold__, ~~strikethrough~~, or `inline code`. + +- Use bulleted lists +- To better clarify +- Your points + + +""" + +sample_2 = """ +## Tables + +|Syntax |Result | +|---------------------------------------|-------------------------------------| +|`*italic 1*` |*italic 1* | +|`_italic 2_` | _italic 2_ | +|`**bold 1**` |**bold 1** | +|`__bold 2__` |__bold 2__ | +|`This is a ~~strikethrough~~` |This is a ~~strikethrough~~ | +|`***italic bold 1***` |***italic bold 1*** | +|`___italic bold 2___` |___italic bold 2___ | +|`***~~italic bold strikethrough 1~~***`|***~~italic bold strikethrough 1~~***| +|`~~***italic bold strikethrough 2***~~`|~~***italic bold strikethrough 2***~~| + + +## Code blocks + +Formatted Dart code looks really pretty too: + +``` +void main() { + runApp(MaterialApp( + home: Scaffold( + body: ft.Markdown(data: markdownData), + ), + )); +} +``` +""" + +sample_3 = r""" +Regular inline: $y = mx + b$ + +Block equation: + +$$ +\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2} +$$ + +With brackets: \[ \sum_{n=1}^{\infty} \frac{1}{n^2} = \frac{\pi^2}{6} \] + +Greek letters: $\alpha, \beta, \gamma, \Delta, \Omega$ + +Fractions and roots: $\frac{a}{b}, \sqrt{x}, \sqrt[3]{y}$ +""" + + +@pytest.mark.asyncio(loop_scope="module") +async def test_md_1(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Markdown( + value=sample_1, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_md_2(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Markdown( + value=sample_2, + selectable=True, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_md_3(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Markdown( + value=sample_3, + latex_style=ft.TextStyle(color="orange"), + latex_scale_factor=1.5, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_menu_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_menu_bar.py new file mode 100644 index 0000000000..87b74152ba --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_menu_bar.py @@ -0,0 +1,62 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + pb = ft.MenuBar( + expand=True, + style=ft.MenuStyle( + alignment=ft.Alignment.TOP_LEFT, + bgcolor=ft.Colors.RED_300, + mouse_cursor={ + ft.ControlState.HOVERED: ft.MouseCursor.WAIT, + ft.ControlState.DEFAULT: ft.MouseCursor.ZOOM_OUT, + }, + ), + controls=[ + ft.SubmenuButton( + key="sb", + content="File", + controls=[ + ft.MenuItemButton( + content=ft.Text("About"), + leading=ft.Icon(ft.Icons.INFO), + ), + ft.MenuItemButton( + content=ft.Text("Save"), + leading=ft.Icon(ft.Icons.SAVE), + ), + ft.MenuItemButton( + content=ft.Text("Quit"), + leading=ft.Icon(ft.Icons.CLOSE), + ), + ], + ), + ], + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(pb) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("sb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "basic_open", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_menu_item_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_menu_item_button.py new file mode 100644 index 0000000000..62e9a83e8a --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_menu_item_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.MenuItemButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_bar.py new file mode 100644 index 0000000000..6d1a072ad2 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_bar.py @@ -0,0 +1,99 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.NavigationBar( + selected_index=2, + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.EXPLORE, label="Explore"), + ft.NavigationBarDestination(icon=ft.Icons.COMMUTE, label="Commute"), + ft.NavigationBarDestination( + icon=ft.Icons.BOOKMARK_BORDER, + selected_icon=ft.Icon(ft.Icons.BOOKMARK), + label="Favorites", + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp): + flet_app.page.theme = ft.Theme( + navigation_bar_theme=ft.NavigationBarTheme( + bgcolor=ft.Colors.GREEN_200, + shadow_color=ft.Colors.ORANGE_500, # not shows in the screenshot + elevation=50, # not shows in the screenshot + indicator_color=ft.Colors.GREEN, + overlay_color=ft.Colors.YELLOW_300, + height=200, + label_text_style=ft.TextStyle(color=ft.Colors.ORANGE_900, size=20), + indicator_shape=ft.RoundedRectangleBorder( + radius=ft.BorderRadius.all(10), + side=ft.BorderSide(color=ft.Colors.PURPLE, width=3), + ), + label_behavior=ft.NavigationBarLabelBehavior.ONLY_SHOW_SELECTED, + label_padding=ft.Padding.all(20), + ) + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + scr_1 = ft.Screenshot( + ft.NavigationBar( + key="nb", + elevation=100, + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.EXPLORE, label="Explore"), + ft.NavigationBarDestination( + key="add", icon=ft.Icon(ft.Icons.ADD), label="Add" + ), + ft.NavigationBarDestination( + key="phone", + icon=ft.Icons.PHONE_ENABLED, + label="Phone", + ), + ], + ) + ) + flet_app.page.add(scr_1) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + # hover to check overlay color + add = await flet_app.tester.find_by_key("add") + assert add.count == 1 + await flet_app.tester.mouse_hover(add) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_2", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + # click to check label behaviour + await flet_app.tester.tap(add) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_3", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_drawer.py b/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_drawer.py new file mode 100644 index 0000000000..ee30f154ad --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_drawer.py @@ -0,0 +1,175 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_end_position(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 500) + flet_app.page.end_drawer = ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.ADD_COMMENT), + label="Item 2", + ), + ], + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + await flet_app.page.show_end_drawer() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_start_position(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 500) + flet_app.page.drawer = ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.ADD_COMMENT), + label="Item 2", + ), + ], + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + await flet_app.page.show_drawer() + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 500) + flet_app.page.theme = ft.Theme( + navigation_drawer_theme=ft.NavigationDrawerTheme( + bgcolor=ft.Colors.BLUE_GREY_200, + elevation=20, + shadow_color=ft.Colors.RED, + indicator_color=ft.Colors.ORANGE, + indicator_shape=ft.RoundedRectangleBorder( + radius=ft.BorderRadius.all(10), + ), + indicator_size=ft.Size(200, 50), + label_text_style=ft.TextStyle(color=ft.Colors.GREEN), + tile_height=100, + ) + ) + flet_app.page.drawer = ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.ADD_COMMENT), + label="Item 2", + ), + ], + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + await flet_app.page.show_drawer() + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_with_appbar(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 500) + + flet_app.page.appbar = ft.AppBar(title="AppBar") + flet_app.page.drawer = ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.ADD_COMMENT), + label="Item 2", + ), + ], + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + await flet_app.page.show_drawer() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_with_cupertino_appbar(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 500) + + flet_app.page.appbar = ft.CupertinoAppBar(title="CupertinoAppBar") + flet_app.page.drawer = ft.NavigationDrawer( + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.ADD_TO_HOME_SCREEN_SHARP, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icon(ft.Icons.ADD_COMMENT), + label="Item 2", + ), + ], + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + await flet_app.page.show_drawer() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_rail.py b/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_rail.py new file mode 100644 index 0000000000..18865f676c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_navigation_rail.py @@ -0,0 +1,163 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.NavigationRail( + height=400, + selected_index=0, + label_type=ft.NavigationRailLabelType.ALL, + min_width=100, + min_extended_width=400, + group_alignment=-0.9, + on_change=lambda e: print( + "Selected destination:", e.control.selected_index + ), + leading=ft.FloatingActionButton( + icon=ft.Icons.CREATE, + content="Add", + on_click=lambda e: print("FAB clicked!"), + ), + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.FAVORITE_BORDER, + selected_icon=ft.Icons.FAVORITE, + label="First", + ), + ft.NavigationRailDestination( + icon=ft.Icon(ft.Icons.BOOKMARK_BORDER), + selected_icon=ft.Icon(ft.Icons.BOOKMARK), + label="Second", + ), + ft.NavigationRailDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + selected_icon=ft.Icon(ft.Icons.SETTINGS), + label=ft.Text("Settings"), + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_no_selected_icon(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.NavigationRail( + height=400, + selected_index=0, + label_type=ft.NavigationRailLabelType.ALL, + min_width=100, + min_extended_width=400, + leading=ft.FloatingActionButton(icon=ft.Icons.CREATE, content="Add"), + group_alignment=-0.9, + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icon(ft.Icons.PHONE, badge="10"), + label="Calls", + ), + ft.NavigationRailDestination( + icon=ft.Icon(ft.Icons.MAIL, badge=ft.Badge()), + label="Mail", + ), + ft.NavigationRailDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + # selected_icon=ft.Icon(ft.Icons.SETTINGS), + label=ft.Text("Settings"), + ), + ], + on_change=lambda e: print( + "Selected destination:", e.control.selected_index + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_scrollable_with_pinned_leading_and_trailing( + flet_app: ftt.FletTestApp, request +): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + + await flet_app.assert_control_screenshot( + request.node.name, + ft.NavigationRail( + height=280, + width=140, + selected_index=0, + label_type=ft.NavigationRailLabelType.ALL, + min_width=100, + min_extended_width=180, + scrollable=True, + pin_leading_to_top=True, + pin_trailing_to_bottom=True, + leading=ft.IconButton(icon=ft.Icons.MENU, tooltip="Menu"), + trailing=ft.IconButton(icon=ft.Icons.SETTINGS, tooltip="Settings"), + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.LOOKS_ONE, + label="One", + ), + ft.NavigationRailDestination( + icon=ft.Icons.LOOKS_TWO, + label="Two", + ), + ft.NavigationRailDestination( + icon=ft.Icons.LOOKS_3, + label="Three", + ), + ft.NavigationRailDestination( + icon=ft.Icons.LOOKS_4, + label="Four", + ), + ft.NavigationRailDestination( + icon=ft.Icons.LOOKS_5, + label="Five", + ), + ft.NavigationRailDestination( + icon=ft.Icons.LOOKS_6, + label="Six", + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_unbounded_height(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + request.node.name, + ft.Column( + controls=[ + ft.NavigationRail( + selected_index=0, + label_type=ft.NavigationRailLabelType.ALL, + min_width=100, + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.FAVORITE_BORDER, + selected_icon=ft.Icons.FAVORITE, + label="First", + ), + ft.NavigationRailDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + selected_icon=ft.Icon(ft.Icons.SETTINGS), + label=ft.Text("Settings"), + ), + ], + ) + ] + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py new file mode 100644 index 0000000000..d162c6f2ca --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_outlined_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.OutlinedButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_popup_menu_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_popup_menu_button.py new file mode 100644 index 0000000000..1dc83f1e14 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_popup_menu_button.py @@ -0,0 +1,124 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + pb = ft.PopupMenuButton( + key="pb", + items=[ + ft.PopupMenuItem("Item 1"), + ft.PopupMenuItem(icon=ft.Icons.POWER_INPUT, content="Check power"), + ft.PopupMenuItem( + content=ft.Row( + [ + ft.Icon(ft.Icons.HOURGLASS_TOP_OUTLINED), + ft.Text("Item with a custom content"), + ] + ), + ), + ft.PopupMenuItem(), # divider + ft.PopupMenuItem( + content="Checked item", + checked=False, + ), + ], + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(pb) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("pb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "basic_opened", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp, request): + pb = ft.PopupMenuButton( + size_constraints=ft.BoxConstraints(min_width=200, max_width=300), + key="pb", + items=[ + ft.PopupMenuItem( + "Item 1", label_text_style=ft.TextStyle(color=ft.Colors.BLUE_700) + ), + ft.PopupMenuItem(icon=ft.Icons.POWER_INPUT, content="Check power"), + ft.PopupMenuItem( + content=ft.Row( + [ + ft.Icon(ft.Icons.HOURGLASS_TOP_OUTLINED), + ft.Text("Item with a custom content"), + ] + ), + ), + ft.PopupMenuItem(), # divider + ft.PopupMenuItem( + content="Checked item", + checked=False, + ), + ], + ) + flet_app.page.theme = ft.Theme( + popup_menu_theme=ft.PopupMenuTheme( + # color=ft.Colors.RED, + elevation=20, + shadow_color=ft.Colors.BLUE, + icon_color=ft.Colors.ORANGE_600, + enable_feedback=True, + icon_size=30, + shape=ft.RoundedRectangleBorder( + radius=ft.BorderRadius.all(10), + side=ft.BorderSide(color=ft.Colors.GREEN_900, width=2), + ), + label_text_style=ft.TextStyle(size=15, color=ft.Colors.GREEN_500), + menu_position=ft.PopupMenuPosition.OVER, + mouse_cursor=ft.MouseCursor.GRAB, + menu_padding=ft.Padding.all(20), + ), + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(pb) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "theme", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("pb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_opened", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_progress_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_progress_bar.py new file mode 100644 index 0000000000..f2f9f4c5b5 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_progress_bar.py @@ -0,0 +1,14 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_determinate(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.ProgressBar( + width=400, color=ft.Colors.GREEN_400, bgcolor=ft.Colors.GREY_400, value=0.5 + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_radio.py b/sdk/python/packages/flet/integration_tests/controls/material/test_radio.py new file mode 100644 index 0000000000..481a28bf21 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_radio.py @@ -0,0 +1,26 @@ +import pytest + +import flet as ft +import flet.testing as ftt + +rg = ft.RadioGroup( + content=ft.Column( + controls=[ + ft.Radio(value="one", label="One"), + ft.Radio(value="two", label="Two"), + ft.Radio(value="three", label="Three"), + ], + ), + value="one", +) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic_one(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot(request.node.name, rg) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic_three(flet_app: ftt.FletTestApp, request): + rg.value = "two" + await flet_app.assert_control_screenshot(request.node.name, rg) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_range_slider.py b/sdk/python/packages/flet/integration_tests/controls/material/test_range_slider.py new file mode 100644 index 0000000000..f57bc336da --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_range_slider.py @@ -0,0 +1,56 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + rs = ft.RangeSlider( + min=0, + max=50, + start_value=0, + divisions=10, + end_value=50, + inactive_color=ft.Colors.GREEN_300, + active_color=ft.Colors.GREEN_700, + overlay_color=ft.Colors.GREEN_100, + label="{value}%", + key="rs", + ) + c = ft.Container(content=rs, padding=ft.Padding.only(top=40)) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(c) + await flet_app.tester.pump_and_settle() + + # default + flet_app.assert_screenshot( + "default", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # move slider + rs.end_value = 20 + rs.start_value = 10 + flet_app.page.update() + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "slider_move", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # tap + await flet_app.tester.tap(await flet_app.tester.find_by_key("rs")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "tap", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_reorderable_list_view.py b/sdk/python/packages/flet/integration_tests/controls/material/test_reorderable_list_view.py new file mode 100644 index 0000000000..b4db8b9fae --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_reorderable_list_view.py @@ -0,0 +1,51 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + await flet_app.assert_control_screenshot( + request.node.name, + ft.ReorderableListView( + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}"), + ) + for i in range(5) + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_drag_handle(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + await flet_app.assert_control_screenshot( + request.node.name, + ft.ReorderableListView( + show_default_drag_handles=False, + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), + leading=ft.ReorderableDragHandle( + content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), + mouse_cursor=ft.MouseCursor.GRAB, + ), + bgcolor=ft.Colors.ERROR + if i % 2 == 0 + else ft.Colors.ON_ERROR_CONTAINER, + ) + for i in range(5) + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_search_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_search_bar.py new file mode 100644 index 0000000000..7d1fa8b33c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_search_bar.py @@ -0,0 +1,131 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + async def handle_tap(e: ft.Event[ft.SearchBar]): + print("handle_tap") + await sb.open_view() + + sb = ft.SearchBar( + key="sb", + bar_hint_text="Search colors...", + view_hint_text="Choose a color from the suggestions...", + on_tap=handle_tap, + controls=[ft.ListTile(title=ft.Text(f"Color {i}")) for i in range(10)], + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(sb) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "basic", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("sb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "basic_opened", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp, request): + flet_app.page.theme = ft.Theme( + search_bar_theme=ft.SearchBarTheme( + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + text_capitalization=ft.TextCapitalization.SENTENCES, + shadow_color=ft.Colors.YELLOW, + overlay_color=ft.Colors.PURPLE, + padding=ft.Padding(10, 20, 50, 20), + elevation=100, + text_style=ft.TextStyle(color=ft.Colors.RED, italic=True, size=30), + hint_style=ft.TextStyle(color=ft.Colors.PINK, size=20, italic=True), + shape=ft.RoundedRectangleBorder( + radius=ft.BorderRadius.all(50), + ), + border_side=ft.BorderSide(color=ft.Colors.PURPLE, width=2), + ), + search_view_theme=ft.SearchViewTheme( + bgcolor=ft.Colors.PURPLE_200, + divider_color=ft.Colors.BLUE_800, + elevation=30, + header_hint_text_style=ft.TextStyle( + color=ft.Colors.BLUE, size=20, italic=True + ), + header_text_style=ft.TextStyle(color=ft.Colors.GREEN, size=20, italic=True), + shape=ft.RoundedRectangleBorder(radius=ft.BorderRadius.all(20)), + border_side=ft.BorderSide(color=ft.Colors.PURPLE, width=2), + size_constraints=ft.BoxConstraints( + min_width=400, max_width=400, min_height=400, max_height=400 + ), + header_height=100, + padding=ft.Padding(10, 20, 50, 20), + bar_padding=ft.Padding.all(5), + shrink_wrap=True, + ), + ) + + async def handle_tap(e: ft.Event[ft.SearchBar]): + print("handle_tap") + await sb.open_view() + + sb = ft.SearchBar( + key="sb", + bar_hint_text="Search colors...", + view_hint_text="Choose a color from the suggestions...", + on_tap=handle_tap, + controls=[ft.ListTile(title=ft.Text(f"Color {i}")) for i in range(10)], + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(sb) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "theme", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # hover to check overlay color + await flet_app.tester.mouse_hover(await flet_app.tester.find_by_key("sb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_hovered", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("sb")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_opened", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_segmented_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_segmented_button.py new file mode 100644 index 0000000000..2bb41e4faa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_segmented_button.py @@ -0,0 +1,89 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.SegmentedButton( + selected=["1"], + segments=[ + ft.Segment( + value="1", + label="1", + icon=ft.Icons.LOOKS_ONE, + ), + ft.Segment( + value="2", + label=ft.Text("2"), + icon=ft.Icon(ft.Icons.LOOKS_TWO), + ), + ft.Segment( + value="3", + label=ft.Text("3"), + ), + ft.Segment( + value="4", + icon=ft.Icons.LOOKS_4, + ), + ], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme(flet_app: ftt.FletTestApp): + flet_app.page.theme = ft.Theme( + segmented_button_theme=ft.SegmentedButtonTheme( + selected_icon=ft.Icons.HOME, + style=ft.ButtonStyle( + bgcolor=ft.Colors.BLUE, shape=ft.BeveledRectangleBorder() + ), + ) + ) + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + scr_1 = ft.Screenshot( + ft.SegmentedButton( + selected=["1"], + segments=[ + ft.Segment( + value="1", + label="1", + icon=ft.Icons.LOOKS_ONE, + ), + ft.Segment( + value="2", + label=ft.Text("2"), + icon=ft.Icon(ft.Icons.LOOKS_TWO), + ), + ft.Segment( + value="3", + label=ft.Text("3"), + ), + ft.Segment( + value="4", + icon=ft.Icons.LOOKS_4, + ), + ], + ), + key="sb", + ) + flet_app.page.add(scr_1) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1", + await scr_1.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_slider.py b/sdk/python/packages/flet/integration_tests/controls/material/test_slider.py new file mode 100644 index 0000000000..209d83955a --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_slider.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Slider(value=0.3), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_range_and_label(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.Slider(min=0, max=100, divisions=10, label="{value}%"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_snack_bar.py b/sdk/python/packages/flet/integration_tests/controls/material/test_snack_bar.py new file mode 100644 index 0000000000..d1abb86374 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_snack_bar.py @@ -0,0 +1,80 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 300) + flet_app.page.show_dialog(ft.SnackBar(ft.Text("Hello, world!"))) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_simple_action(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 300) + flet_app.page.show_dialog(ft.SnackBar(ft.Text("Directory deleted."), action="Undo")) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_custom_action(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 300) + flet_app.page.show_dialog( + ft.SnackBar( + ft.Text("File deleted."), + action=ft.SnackBarAction( + label="Undo delete", + text_color=ft.Colors.YELLOW, + bgcolor=ft.Colors.BLUE, + ), + ) + ) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_cupertino_page(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 300) + flet_app.page.platform = ft.PagePlatform.MACOS + flet_app.page.adaptive = True + flet_app.page.update() + + flet_app.page.show_dialog(ft.SnackBar("Snackbar in cupertino page.")) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_submenu_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_submenu_button.py new file mode 100644 index 0000000000..3e6765a3de --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_submenu_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.SubmenuButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_tabs.py b/sdk/python/packages/flet/integration_tests/controls/material/test_tabs.py new file mode 100644 index 0000000000..c357d0446b --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_tabs.py @@ -0,0 +1,305 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + name=request.node.name, + expand_screenshot=True, + control=ft.Tabs( + length=2, + content=ft.Column( + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Tab 1"), + ft.Tab(label="Tab 2", icon=ft.Icons.SETTINGS), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + content=ft.Text("This is Tab 1"), + alignment=ft.Alignment.CENTER, + ), + ft.Container( + content=ft.Text("This is Tab 3"), + alignment=ft.Alignment.CENTER, + ), + ], + ), + ], + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_nesting(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + name=request.node.name, + expand_screenshot=True, + control=ft.Tabs( + length=2, + expand=True, + selected_index=1, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label=ft.Text("Main Tab 1")), + ft.Tab(label=ft.Text("Main Tab 2")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Main Tab 1 content"), + ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + secondary=True, + tabs=[ + ft.Tab(label=ft.Text("SubTab 1")), + ft.Tab(label=ft.Text("SubTab 2")), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("Nested Tab 1 content"), + ft.Text("Nested Tab 2 content"), + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_disabled_tab(flet_app: ftt.FletTestApp): + clicked_indexes = [] + flet_app.page.padding = 0 + flet_app.resize_page(300, 300) + flet_app.page.add( + tabs := ft.Tabs( + selected_index=0, + length=3, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + scrollable=False, + on_click=lambda e: clicked_indexes.append(int(e.data)), + tabs=[ + ft.Tab(label="Tab 1"), + tab_2 := ft.Tab(label="Tab 2"), + ft.Tab(label="Tab 3"), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("View 1"), + ft.Text("View 2"), + ft.Text("View 3"), + ], + ), + ], + ), + ) + ) + await flet_app.tester.pump_and_settle() + + # click tab2 + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 1 + assert clicked_indexes == [1] + + # disable tab2 + tabs.selected_index = 0 + tab_2.disabled = True + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + # click tab2 (disabled) + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 0 + assert clicked_indexes == [1] + + # re-enable tab2 + tab_2.disabled = False + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + # click tab2 + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 1 + assert clicked_indexes == [1, 1] + + +@pytest.mark.asyncio(loop_scope="function") +async def test_disabled_tabbar(flet_app: ftt.FletTestApp): + clicked_indexes = [] + flet_app.page.padding = 0 + flet_app.resize_page(300, 300) + flet_app.page.add( + tabs := ft.Tabs( + selected_index=0, + length=3, + expand=True, + content=ft.Column( + expand=True, + controls=[ + tab_bar := ft.TabBar( + disabled=True, + scrollable=False, + on_click=lambda e: clicked_indexes.append(int(e.data)), + tabs=[ + ft.Tab(label="Tab 1"), + ft.Tab(label="Tab 2"), + ft.Tab(label="Tab 3"), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("View 1"), + ft.Text("View 2"), + ft.Text("View 3"), + ], + ), + ], + ), + ) + ) + await flet_app.tester.pump_and_settle() + + # click tab2 (disabled TabBar) + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 0 + assert clicked_indexes == [] + + # re-enable tabbar + tab_bar.disabled = False + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 1 + assert clicked_indexes == [1] + + +@pytest.mark.asyncio(loop_scope="function") +async def test_disabled_tabs(flet_app: ftt.FletTestApp): + clicked_indexes = [] + flet_app.page.padding = 0 + flet_app.resize_page(300, 300) + flet_app.page.add( + tabs := ft.Tabs( + disabled=True, + selected_index=0, + length=3, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + scrollable=False, + on_click=lambda e: clicked_indexes.append(int(e.data)), + tabs=[ + ft.Tab(label="Tab 1"), + ft.Tab(label="Tab 2"), + ft.Tab(label="Tab 3"), + ], + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Text("View 1"), + ft.Text("View 2"), + ft.Text("View 3"), + ], + ), + ], + ), + ) + ) + await flet_app.tester.pump_and_settle() + + # click tab2 (disabled Tabs) + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 0 + assert clicked_indexes == [] + + # re-enable Tabs + tabs.disabled = False + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + # click tab2 + await flet_app.tester.tap((await flet_app.tester.find_by_text("Tab 2")).first) + await flet_app.tester.pump_and_settle() + assert tabs.selected_index == 1 + assert clicked_indexes == [1] + + +@pytest.mark.asyncio(loop_scope="function") +async def test_unbounded_tabbarview_height(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app.assert_control_screenshot( + name=request.node.name, + control=ft.Column( + controls=[ + ft.Tabs( + length=1, + content=ft.Column( + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Tab 1"), + ] + ), + ft.TabBarView( + controls=[ + ft.Container( + content=ft.Text("Tab 1 content"), + alignment=ft.Alignment.CENTER, + ) + ], + ), + ], + ), + ) + ] + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py b/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py new file mode 100644 index 0000000000..12a61c379d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_text_button.py @@ -0,0 +1,12 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.TextButton("Click me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_textfield.py b/sdk/python/packages/flet/integration_tests/controls/material/test_textfield.py new file mode 100644 index 0000000000..1c2cc43978 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_textfield.py @@ -0,0 +1,28 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="module") +async def test_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.TextField(margin=20), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_label(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.TextField(label="TextField label", margin=20), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_label_and_value(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ft.TextField(label="TextField label", value="TextField 1 value", margin=20), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py b/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py new file mode 100644 index 0000000000..6cb9964c81 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_time_picker.py @@ -0,0 +1,107 @@ +import datetime + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(600, 450) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.page.show_dialog( + ft.TimePicker( + confirm_text="Confirm", + error_invalid_text="Time out of range", + help_text="Pick your time slot", + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H24, + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_hour_format_12(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(600, 450) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.TimePicker( + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H12, + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_hour_format_24(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(600, 450) + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.page.show_dialog( + ft.TimePicker( + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H24, + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_locale(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(600, 450) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.TimePicker( + locale=ft.Locale("zh", "Hans"), + value=datetime.time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H24, + ) + ) + + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/material/test_vertical_divider.py b/sdk/python/packages/flet/integration_tests/controls/material/test_vertical_divider.py new file mode 100644 index 0000000000..5487afed14 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/material/test_vertical_divider.py @@ -0,0 +1,52 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(ft.VerticalDivider(expand=True)) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_properties(flet_app: ftt.FletTestApp, request): + flet_app.page.theme_mode = ft.ThemeMode.LIGHT + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add( + ft.VerticalDivider( + expand=True, + thickness=20, + color=ft.Colors.RED, + width=100, + leading_indent=100, + trailing_indent=100, + radius=10, + ) + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/services/test_battery.py b/sdk/python/packages/flet/integration_tests/controls/services/test_battery.py new file mode 100644 index 0000000000..aa70a897a9 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/services/test_battery.py @@ -0,0 +1,26 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method. +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_battery(flet_app: ftt.FletTestApp): + battery = ft.Battery() + + level = await battery.get_battery_level() + state = await battery.get_battery_state() + save_mode = await battery.is_in_battery_save_mode() + + assert level is None or isinstance(level, int) + if isinstance(level, int): + assert 0 <= level <= 100 + assert isinstance(state, ft.BatteryState) + assert isinstance(save_mode, bool) diff --git a/sdk/python/packages/flet/integration_tests/controls/services/test_clipboard.py b/sdk/python/packages/flet/integration_tests/controls/services/test_clipboard.py new file mode 100644 index 0000000000..f6e86745c3 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/services/test_clipboard.py @@ -0,0 +1,68 @@ +import base64 +from pathlib import Path +from tempfile import TemporaryDirectory + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt +from flet.controls.exceptions import FletUnsupportedPlatformException + + +# Create a new flet_app instance for each test method. +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_text(flet_app: ftt.FletTestApp): + clipboard = ft.Clipboard() + + expected = "Flet clipboard integration test value" + await clipboard.set(expected) + actual = await clipboard.get() + + assert actual == expected + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image(flet_app: ftt.FletTestApp): + bytes_image = base64.b64decode( + "iVBORw0KGgoAAAANSUhEUgAAABkAAAAgCAYAAADnnNMGAAAACXBIWXMAAAORAAADkQFnq8zdAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAA6dJREFUSImllltoHFUYx3/fzOzm0lt23ZrQ1AQbtBehNpvQohgkBYVo410RwQctNE3Sh0IfiiBoIAjqi6TYrKnFy4O3oiiRavDJFi3mXomIBmOxNZe63ay52GR3Zj4f2sTEzmx3m//TYf7/c35zvgPnO6KqrESXqpq3muocAikv6m+/zytj3ejik1VN21G31YA9CgJ6xC+bMyQZPVCuarciPAMYC99V6Vw5pLbFSibHmlVoRVj9P3cmPBM8tSJI/M6mzabpfoAQ9fIF7WK4bd5vvuFnLGgy2vi0abg94A0AcJGvMq3hDxGRyar9r4F+iLAm0yIiRk8m37tctS1WsrIhhrI30+Srmg+J87OXUf3lWGS1q89dC6ltsSanxk4Aj2QBABii96300g87P/rtlrWr8l+vyDMfdlXSyyEikqxsiOUAQJCBhfHdXRfCq1LSsSlcWG+KBAGStvvrMkgiuv8lUc2mREukPwLUfHG+uTQv8Eown7VL3XlbBxYhf1c17hbVF3MDwA9bts280TnaU1YYqPby07aeFlUlHt27wSQ4CLo+F8AvoTCvHmyKF+ZbEb/M77P2LgvAwmrTHAHflN3KZxVbMC2jMFNOpgPnrMSOhvvFkMezXdwV4ePbtvHtxnJAMQ0j4JtVnO+eLb5oiSlt5HDbv7t1O90lpYCCCKbhfzW5kAIwUAazR0BlfII8Ow0I6uoVmI9MyAMwbMs8CExmDbk4zgu931MyO4OI4KrYflkRjOoTI+uM9d1vjotwKPu9QMk/sxzuO8POiVFcdZ1M2YBVsMEAKOqLvaPIe7mACuw0z/80SMH58SMplxlfiDhVi7dw2pltRhjKBQTQdrSja2KKTfE551NHuaZ0QVPvWYQUn31/Vm2nDvgjF4grVJx6suSvrvrSJ/6cSW2Oz9mf264uNrB806xZ1k/CZ49dUKgDEtlCROX2hfHpx8pGuuo3PpqYulw8fjndOp1yhgtNKRevJ1FyR2Ola+jXAjdnwTkZ6o896GdWdxDw7IxFg+0DpmXchTKSBWQnIuJn9u4j7dt+13UfHXEkXQOcuQ4kMhVtqsgUyPiQiPQfHw1NB2sRjmXKuTg1NwwBYLhtPtQX26eqTwGXPDOqvmcC4Hnwfrrad94GrVsOYTqUTkQY+iTlNe/6O1miSP/x0VB/+wMIDwHn/vtV1iQC4Xv95uUEWVCoL9Y5Z+gdovoyMHUFJHv88jmVy0vTuw7cZNv2YaA61Bfb7ZX5F8SaUv2xwZevAAAAAElFTkSuQmCC" + ) + clipboard = ft.Clipboard() + + if not (flet_app.page.web or flet_app.page.platform.is_mobile()): + with pytest.raises(FletUnsupportedPlatformException): + await clipboard.set_image(bytes_image) + return + + await clipboard.set_image(bytes_image) + actual = await clipboard.get_image() + + assert isinstance(actual, bytes) and len(actual) > 0 + + +@pytest.mark.asyncio(loop_scope="function") +async def test_files(flet_app: ftt.FletTestApp): + clipboard = ft.Clipboard() + + if flet_app.page.web or not flet_app.page.platform.is_desktop(): + with pytest.raises(FletUnsupportedPlatformException): + await clipboard.set_files(["/tmp/not-used.txt"]) + return + + with TemporaryDirectory() as tmp: + file1 = Path(tmp) / "clipboard_file_1.txt" + file1.write_text("file 1") + file2 = Path(tmp) / "clipboard_file_2.txt" + file2.write_text("file 2") + + expected = [str(file1), str(file2)] + ok = await clipboard.set_files(expected) + actual = await clipboard.get_files() + + assert ok is True + assert set(actual) == set(expected) diff --git a/sdk/python/packages/flet/integration_tests/controls/services/test_shared_preferences.py b/sdk/python/packages/flet/integration_tests/controls/services/test_shared_preferences.py new file mode 100644 index 0000000000..9da36ec3e6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/services/test_shared_preferences.py @@ -0,0 +1,69 @@ +from uuid import uuid4 + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method. +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_crud_flow(flet_app: ftt.FletTestApp): + prefs = ft.SharedPreferences() + prefix = f"it_sp_{uuid4().hex}" + + values = { + f"{prefix}_str": "hello", + f"{prefix}_int": 123, + f"{prefix}_float": 123.25, + f"{prefix}_bool": True, + f"{prefix}_list": ["a", "b", "c"], + } + + # initially keys should not exist + for key in values: + assert await prefs.contains_key(key) is False + + # set values + for key, value in values.items(): + assert await prefs.set(key, value) is True + + # get values + for key, value in values.items(): + assert await prefs.get(key) == value + assert await prefs.contains_key(key) is True + + # keys with prefix should be returned + keys = await prefs.get_keys(prefix) + for key in values: + assert key in keys + + # remove one key + first_key = next(iter(values)) + assert await prefs.remove(first_key) is True + assert await prefs.contains_key(first_key) is False + assert await prefs.get(first_key) is None + + # clear everything + assert await prefs.clear() is True + for key in values: + assert await prefs.contains_key(key) is False + assert await prefs.get(key) is None + + # unsupported types should fail + unsupported_values = { + f"{prefix}_dict": {"a": 1}, + f"{prefix}_tuple": ("a", "b"), + f"{prefix}_list_int": [1, 2, 3], + f"{prefix}_none": None, + } + for key, value in unsupported_values.items(): + with pytest.raises(ValueError, match="Unsupported value type"): + await prefs.set(key, value) # type: ignore[arg-type] + assert await prefs.contains_key(key) is False diff --git a/sdk/python/packages/flet/integration_tests/controls/services/test_storage_paths.py b/sdk/python/packages/flet/integration_tests/controls/services/test_storage_paths.py new file mode 100644 index 0000000000..5dfe3854a6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/services/test_storage_paths.py @@ -0,0 +1,84 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt +from flet.controls.exceptions import FletUnsupportedPlatformException + + +# Create a new flet_app instance for each test method. +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_storage_paths(flet_app: ftt.FletTestApp): + paths = ft.StoragePaths() + + if flet_app.page.web: + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_application_cache_directory() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_application_documents_directory() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_application_support_directory() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_downloads_directory() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_temporary_directory() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_console_log_filename() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_library_directory() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_external_cache_directories() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_external_storage_directories() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_external_storage_directory() + return + + cache_dir = await paths.get_application_cache_directory() + documents_dir = await paths.get_application_documents_directory() + support_dir = await paths.get_application_support_directory() + temporary_dir = await paths.get_temporary_directory() + console_log_filename = await paths.get_console_log_filename() + downloads_dir = await paths.get_downloads_directory() + + assert isinstance(cache_dir, str) and cache_dir + assert isinstance(documents_dir, str) and documents_dir + assert isinstance(support_dir, str) and support_dir + assert isinstance(temporary_dir, str) and temporary_dir + assert isinstance(console_log_filename, str) and console_log_filename + assert console_log_filename.endswith("console.log") + assert downloads_dir is None or isinstance(downloads_dir, str) + + # library directory + if flet_app.page.platform.is_apple(): + library_dir = await paths.get_library_directory() + assert isinstance(library_dir, str) and library_dir + else: + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_library_directory() + + # external storage directories + if flet_app.page.platform == ft.PagePlatform.ANDROID: + external_cache_dirs = await paths.get_external_cache_directories() + external_storage_dirs = await paths.get_external_storage_directories() + external_storage_dir = await paths.get_external_storage_directory() + + assert external_cache_dirs is None or all( + isinstance(path, str) and path for path in external_cache_dirs + ) + assert external_storage_dirs is None or all( + isinstance(path, str) and path for path in external_storage_dirs + ) + assert external_storage_dir is None or isinstance(external_storage_dir, str) + else: + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_external_cache_directories() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_external_storage_directories() + with pytest.raises(FletUnsupportedPlatformException): + await paths.get_external_storage_directory() diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/button_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/button_theme/theme_1.png new file mode 100644 index 0000000000..978a1aeeb0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/button_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_accents_palette.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_accents_palette.png new file mode 100644 index 0000000000..bb7bbd49b6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_accents_palette.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_buttons.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_buttons.png new file mode 100644 index 0000000000..3546d58d89 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_buttons.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_error_banner.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_error_banner.png new file mode 100644 index 0000000000..23b5f8d2e0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_error_banner.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_primary_palette.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_primary_palette.png new file mode 100644 index 0000000000..33a1aa1d1c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_primary_palette.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_secondary_palette.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_secondary_palette.png new file mode 100644 index 0000000000..ae121dd7df Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_secondary_palette.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_surface_roles.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_surface_roles.png new file mode 100644 index 0000000000..b3002320f3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_surface_roles.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_tertiary_palette.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_tertiary_palette.png new file mode 100644 index 0000000000..9e3d0fe19e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_tertiary_palette.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_themed_card.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_themed_card.png new file mode 100644 index 0000000000..28f1f815f2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/color_scheme/theme_1_themed_card.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/data_table_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/data_table_theme/theme_1.png new file mode 100644 index 0000000000..c0aab672d2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/data_table_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/date_picker_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/date_picker_theme/theme_1.png new file mode 100644 index 0000000000..90f1ebd29e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/date_picker_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/date_range_picker_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/date_range_picker_theme/theme_1.png new file mode 100644 index 0000000000..1d7d12a5b3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/date_range_picker_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/expansion_tile_theme/theme_1_collapsed.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/expansion_tile_theme/theme_1_collapsed.png new file mode 100644 index 0000000000..6d18cea66f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/expansion_tile_theme/theme_1_collapsed.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/expansion_tile_theme/theme_1_expanded.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/expansion_tile_theme/theme_1_expanded.png new file mode 100644 index 0000000000..b4edbda25f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/expansion_tile_theme/theme_1_expanded.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/filled_button_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/filled_button_theme/theme_1.png new file mode 100644 index 0000000000..a854a023be Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/filled_button_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_focus_disabled.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_focus_disabled.png new file mode 100644 index 0000000000..8569365571 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_focus_disabled.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_hover.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_hover.png new file mode 100644 index 0000000000..56f9c3239a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_normal.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_normal.png new file mode 100644 index 0000000000..1b94fc0236 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/floating_action_button_theme/theme_1_normal.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/icon_button_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/icon_button_theme/theme_1.png new file mode 100644 index 0000000000..34e385a950 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/icon_button_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/list_tile_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/list_tile_theme/theme_1.png new file mode 100644 index 0000000000..82d7a5ac10 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/list_tile_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/outlined_button_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/outlined_button_theme/theme_1.png new file mode 100644 index 0000000000..978a1aeeb0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/outlined_button_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/text_button_theme/theme_1.png b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/text_button_theme/theme_1.png new file mode 100644 index 0000000000..978a1aeeb0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/controls/theme/golden/macos/text_button_theme/theme_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_button_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_button_theme.py new file mode 100644 index 0000000000..1f46911712 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_button_theme.py @@ -0,0 +1,31 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + button_theme=ft.ButtonTheme( + style=ft.ButtonStyle( + bgcolor=ft.Colors.GREEN, + shape=ft.BeveledRectangleBorder(radius=5), + side=ft.BorderSide(width=5, color=ft.Colors.GREEN_900), + padding=ft.Padding.all(10), + ), + ) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.Button(content="Button"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_color_scheme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_color_scheme.py new file mode 100644 index 0000000000..151801dfa4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_color_scheme.py @@ -0,0 +1,400 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp): + flet_app.page.theme = ft.Theme( + color_scheme=ft.ColorScheme( + error=ft.Colors.RED, + error_container=ft.Colors.RED_900, + inverse_primary=ft.Colors.GREEN_900, + inverse_surface=ft.Colors.BLACK, + on_error=ft.Colors.WHITE, + on_error_container=ft.Colors.WHITE, + on_inverse_surface=ft.Colors.WHITE, + on_primary=ft.Colors.YELLOW, + on_primary_container=ft.Colors.YELLOW, + on_primary_fixed=ft.Colors.WHITE, + on_primary_fixed_variant=ft.Colors.WHITE, + on_secondary=ft.Colors.WHITE, + on_secondary_container=ft.Colors.WHITE, + on_secondary_fixed=ft.Colors.WHITE, + on_secondary_fixed_variant=ft.Colors.WHITE, + on_surface=ft.Colors.BLACK, + on_surface_variant=ft.Colors.RED, + on_tertiary=ft.Colors.WHITE, + on_tertiary_container=ft.Colors.WHITE, + on_tertiary_fixed=ft.Colors.WHITE, + on_tertiary_fixed_variant=ft.Colors.WHITE, + outline=ft.Colors.BLUE_200, + outline_variant=ft.Colors.BLUE_400, + primary=ft.Colors.GREEN, + primary_container=ft.Colors.GREEN_900, + primary_fixed=ft.Colors.GREEN_400, + primary_fixed_dim=ft.Colors.GREEN_700, + scrim=ft.Colors.BLACK, + secondary=ft.Colors.BLUE, + secondary_container=ft.Colors.BLUE_900, + secondary_fixed=ft.Colors.BLUE_400, + secondary_fixed_dim=ft.Colors.BLUE_700, + shadow=ft.Colors.BLACK, + surface=ft.Colors.ORANGE_400, + surface_bright=ft.Colors.ORANGE_200, + surface_container=ft.Colors.ORANGE, + surface_container_high=ft.Colors.ORANGE_300, + surface_container_highest=ft.Colors.ORANGE_500, + surface_container_low=ft.Colors.ORANGE_100, + surface_container_lowest=ft.Colors.ORANGE_50, + surface_dim=ft.Colors.ORANGE_600, + surface_tint=ft.Colors.GREEN, + tertiary=ft.Colors.RED, + tertiary_container=ft.Colors.RED_900, + tertiary_fixed=ft.Colors.RED_400, + tertiary_fixed_dim=ft.Colors.RED_700, + ) + ) + + flet_app.resize_page(500, 500) + flet_app.page.scroll = ft.ScrollMode.HIDDEN + + def swatch(label: str, fill_color: str, text_color: str) -> ft.Container: + return ft.Container( + width=100, + height=72, + bgcolor=fill_color, + border_radius=ft.BorderRadius.all(12), + border=ft.Border.all(1, ft.Colors.OUTLINE_VARIANT), + padding=10, + content=ft.Column( + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + spacing=4, + controls=[ + ft.Text( + label, + size=11, + weight=ft.FontWeight.BOLD, + color=text_color, + text_align=ft.TextAlign.CENTER, + ) + ], + ), + ) + + primary_palette = ft.Screenshot( + ft.Row( + key=ft.ScrollKey("primary_palette"), + wrap=True, + controls=[ + swatch("Primary", ft.Colors.PRIMARY, ft.Colors.ON_PRIMARY), + swatch( + "Primary Ctr", + ft.Colors.PRIMARY_CONTAINER, + ft.Colors.ON_PRIMARY_CONTAINER, + ), + swatch( + "Primary Fix", ft.Colors.PRIMARY_FIXED, ft.Colors.ON_PRIMARY_FIXED + ), + swatch( + "Primary Dim", + ft.Colors.PRIMARY_FIXED_DIM, + ft.Colors.ON_PRIMARY_FIXED, + ), + ], + ) + ) + + secondary_palette = ft.Screenshot( + ft.Row( + key=ft.ScrollKey("secondary_palette"), + wrap=True, + controls=[ + swatch("Secondary", ft.Colors.SECONDARY, ft.Colors.ON_SECONDARY), + swatch( + "Secondary Ctr", + ft.Colors.SECONDARY_CONTAINER, + ft.Colors.ON_SECONDARY_CONTAINER, + ), + swatch( + "Secondary Fix", + ft.Colors.SECONDARY_FIXED, + ft.Colors.ON_SECONDARY_FIXED, + ), + swatch( + "Secondary Dim", + ft.Colors.SECONDARY_FIXED_DIM, + ft.Colors.ON_SECONDARY_FIXED, + ), + ], + ) + ) + + tertiary_palette = ft.Screenshot( + ft.Row( + key=ft.ScrollKey("tertiary_palette"), + wrap=True, + controls=[ + swatch("Tertiary", ft.Colors.TERTIARY, ft.Colors.ON_TERTIARY), + swatch( + "Tertiary Ctr", + ft.Colors.TERTIARY_CONTAINER, + ft.Colors.ON_TERTIARY_CONTAINER, + ), + swatch( + "Tertiary Fix", + ft.Colors.TERTIARY_FIXED, + ft.Colors.ON_TERTIARY_FIXED, + ), + swatch( + "Tertiary Dim", + ft.Colors.TERTIARY_FIXED_DIM, + ft.Colors.ON_TERTIARY_FIXED, + ), + ], + ) + ) + + surface_palette = ft.Screenshot( + ft.Row( + key=ft.ScrollKey("surface_roles"), + wrap=True, + controls=[ + swatch("Surface", ft.Colors.SURFACE, ft.Colors.ON_SURFACE), + swatch("Surface Br", ft.Colors.SURFACE_BRIGHT, ft.Colors.ON_SURFACE), + swatch("Surface Dim", ft.Colors.SURFACE_DIM, ft.Colors.ON_SURFACE), + swatch("Surface Tint", ft.Colors.SURFACE_TINT, ft.Colors.ON_SURFACE), + swatch("Container", ft.Colors.SURFACE_CONTAINER, ft.Colors.ON_SURFACE), + swatch( + "Ctr High", ft.Colors.SURFACE_CONTAINER_HIGH, ft.Colors.ON_SURFACE + ), + swatch( + "Ctr Highest", + ft.Colors.SURFACE_CONTAINER_HIGHEST, + ft.Colors.ON_SURFACE, + ), + swatch( + "Ctr Low", ft.Colors.SURFACE_CONTAINER_LOW, ft.Colors.ON_SURFACE + ), + swatch( + "Ctr Lowest", + ft.Colors.SURFACE_CONTAINER_LOWEST, + ft.Colors.ON_SURFACE, + ), + ], + ) + ) + + accents_palette = ft.Screenshot( + ft.Row( + key=ft.ScrollKey("accents_palette"), + wrap=True, + controls=[ + swatch( + "Inverse", ft.Colors.INVERSE_SURFACE, ft.Colors.ON_INVERSE_SURFACE + ), + swatch( + "Inverse Pri", + ft.Colors.INVERSE_PRIMARY, + ft.Colors.ON_INVERSE_SURFACE, + ), + swatch("Scrim", ft.Colors.SCRIM, ft.Colors.ON_INVERSE_SURFACE), + swatch("Outline", ft.Colors.OUTLINE, ft.Colors.ON_SURFACE_VARIANT), + swatch("Outline Var", ft.Colors.OUTLINE_VARIANT, ft.Colors.ON_SURFACE), + swatch("Error", ft.Colors.ERROR, ft.Colors.ON_ERROR), + swatch( + "Error Ctr", ft.Colors.ERROR_CONTAINER, ft.Colors.ON_ERROR_CONTAINER + ), + ], + ) + ) + + buttons = ft.Screenshot( + ft.Row( + wrap=True, + controls=[ + ft.FilledButton( + "Primary button", + style=ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=14), + padding=ft.Padding.symmetric(horizontal=24, vertical=12), + ), + ), + ft.FilledTonalButton( + "Tonal secondary", + style=ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=14), + padding=ft.Padding.symmetric(horizontal=20, vertical=12), + ), + ), + ft.OutlinedButton( + "Surface variant", + style=ft.ButtonStyle( + side=ft.BorderSide(width=2, color=ft.Colors.OUTLINE), + shape=ft.RoundedRectangleBorder(radius=14), + padding=ft.Padding.symmetric(horizontal=20, vertical=12), + ), + ), + ft.TextButton( + "Tertiary text", + style=ft.ButtonStyle( + color=ft.Colors.TERTIARY, + overlay_color=ft.Colors.TERTIARY_CONTAINER, + shape=ft.RoundedRectangleBorder(radius=14), + ), + ), + ft.IconButton( + icon=ft.Icons.FAVORITE, + icon_color=ft.Colors.ON_TERTIARY_CONTAINER, + style=ft.ButtonStyle( + bgcolor=ft.Colors.TERTIARY_CONTAINER, + shape=ft.CircleBorder(), + overlay_color=ft.Colors.TERTIARY, + ), + ), + ft.FloatingActionButton( + icon=ft.Icons.ADD, + bgcolor=ft.Colors.SECONDARY_CONTAINER, + foreground_color=ft.Colors.ON_SECONDARY_CONTAINER, + shape=ft.CircleBorder(), + ), + ], + ) + ) + + themed_card = ft.Screenshot( + ft.Card( + key=ft.ScrollKey("themed_card"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGH, + content=ft.Container( + padding=10, + content=ft.Column( + spacing=8, + alignment=ft.MainAxisAlignment.START, + horizontal_alignment=ft.CrossAxisAlignment.START, + controls=[ + ft.Text( + "Card on surface container", + size=18, + weight=ft.FontWeight.BOLD, + color=ft.Colors.ON_SURFACE, + ), + ft.Text( + "Uses outline variant border and shadow color.", + color=ft.Colors.ON_SURFACE_VARIANT, + ), + ft.ListTile( + title=ft.Text("Selected list tile"), + leading=ft.Icon(ft.Icons.PALETTE, color=ft.Colors.PRIMARY), + selected=True, + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGH, + selected_color=ft.Colors.ON_PRIMARY, + trailing=ft.Switch(value=True), + ), + ], + ), + ), + ) + ) + + error_banner = ft.Screenshot( + ft.Container( + key=ft.ScrollKey("error_banner"), + bgcolor=ft.Colors.ERROR_CONTAINER, + border_radius=ft.BorderRadius.all(10), + padding=ft.Padding.symmetric(horizontal=16, vertical=12), + content=ft.Row( + spacing=10, + alignment=ft.MainAxisAlignment.START, + vertical_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Icon(ft.Icons.ERROR, color=ft.Colors.ON_ERROR_CONTAINER), + ft.Text( + "Error container background with on-error text.", + color=ft.Colors.ON_ERROR_CONTAINER, + weight=ft.FontWeight.BOLD, + expand=True, + ), + ], + ), + ) + ) + + flet_app.page.add( + ft.Column( + controls=[ + buttons, + primary_palette, + secondary_palette, + tertiary_palette, + surface_palette, + accents_palette, + themed_card, + error_banner, + ], + ) + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1_buttons", + await buttons.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="primary_palette", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_primary_palette", + await primary_palette.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="secondary_palette", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_secondary_palette", + await secondary_palette.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="tertiary_palette", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_tertiary_palette", + await tertiary_palette.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="surface_roles", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_surface_roles", + await surface_palette.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="accents_palette", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_accents_palette", + await accents_palette.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="themed_card", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_themed_card", + await themed_card.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) + + await flet_app.page.scroll_to(scroll_key="error_banner", duration=0) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_error_banner", + await error_banner.capture(pixel_ratio=flet_app.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_data_table_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_data_table_theme.py new file mode 100644 index 0000000000..9dab82e948 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_data_table_theme.py @@ -0,0 +1,73 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + data_table_theme=ft.DataTableTheme( + checkbox_horizontal_margin=10, + column_spacing=50, + data_row_max_height=200, + data_row_min_height=0, + data_row_color=ft.Colors.GREEN_200, + data_text_style=ft.TextStyle(color=ft.Colors.GREEN_800), + divider_thickness=10, + horizontal_margin=20, + heading_text_style=ft.TextStyle(italic=True), + heading_row_color=ft.Colors.ORANGE_200, + heading_row_height=100, + data_row_cursor=ft.MouseCursor.FORBIDDEN, # doesn't show on screenshot + heading_row_alignment=ft.MainAxisAlignment.START, + heading_cell_cursor=ft.MouseCursor.HELP, # doesn't show on screenshot + decoration=ft.BoxDecoration( + shape=ft.BoxShape.RECTANGLE, + bgcolor=ft.Colors.PURPLE_100, + border=ft.Border.all(color=ft.Colors.RED), + ), + ), + divider_theme=ft.DividerTheme( + color=ft.Colors.GREEN, + thickness=5, + ), + ) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.DataTable( + show_checkbox_column=True, + columns=[ + ft.DataColumn(label="Column 1"), + ft.DataColumn(label=ft.Text("Column 2")), + ft.DataColumn(label=ft.Text("Column 3")), + ], + rows=[ + ft.DataRow( + on_select_change=lambda e: print(f"Selected row {e.data}"), + cells=[ + ft.DataCell("Item 1"), + ft.DataCell(ft.Text("Item 2")), + ft.DataCell(ft.Text("Item 3")), + ], + ), + ft.DataRow( + on_select_change=lambda e: print(f"Selected row {e.data}"), + cells=[ + ft.DataCell("Item 1"), + ft.DataCell(ft.Text("Item 2")), + ft.DataCell(ft.Text("Item 3")), + ], + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_date_picker_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_date_picker_theme.py new file mode 100644 index 0000000000..d32ec7f4ed --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_date_picker_theme.py @@ -0,0 +1,41 @@ +import datetime + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + date_picker_theme=ft.DatePickerTheme( + bgcolor=ft.Colors.GREEN_200, + ) + ) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DatePicker( + first_date=datetime.datetime(year=2000, month=10, day=1), + current_date=datetime.datetime(year=2025, month=8, day=15), + last_date=datetime.datetime(year=2025, month=10, day=1), + ) + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_date_range_picker_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_date_range_picker_theme.py new file mode 100644 index 0000000000..199cfe16bd --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_date_range_picker_theme.py @@ -0,0 +1,54 @@ +import datetime + +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(500, 600) + flet_app.page.theme = ft.Theme( + date_picker_theme=ft.DatePickerTheme( + bgcolor=ft.Colors.GREEN_200, + range_picker_bgcolor=ft.Colors.GREEN_100, + range_picker_elevation=10, + range_picker_header_foreground_color=ft.Colors.GREEN_900, + range_picker_header_headline_text_style=ft.TextStyle(italic=True), + range_picker_shape=ft.BeveledRectangleBorder( + radius=20, + side=ft.BorderSide(5, color=ft.Colors.PURPLE), + ), + range_picker_header_help_text_style=ft.TextStyle(color=ft.Colors.GREEN_800), + range_selection_bgcolor=ft.Colors.YELLOW_200, + range_selection_overlay_color=ft.Colors.YELLOW_400, + ) + ) + flet_app.page.update() + + flet_app.page.show_dialog( + ft.DateRangePicker( + current_date=datetime.datetime(year=2025, month=8, day=15), + first_date=datetime.datetime(year=2000, month=10, day=1), + last_date=datetime.datetime(year=2025, month=10, day=1), + start_value=datetime.datetime(year=2000, month=10, day=7), + end_value=datetime.datetime(year=2000, month=10, day=15), + ) + ) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_expansion_tile_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_expansion_tile_theme.py new file mode 100644 index 0000000000..21bbfbe61e --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_expansion_tile_theme.py @@ -0,0 +1,67 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.page.theme = ft.Theme( + expansion_tile_theme=ft.ExpansionTileTheme( + bgcolor=ft.Colors.GREEN_200, + icon_color=ft.Colors.PINK, + text_color=ft.Colors.ORANGE, + collapsed_bgcolor=ft.Colors.YELLOW, + collapsed_icon_color=ft.Colors.BLUE, + collapsed_text_color=ft.Colors.PURPLE, + tile_padding=ft.Padding.all(10), + controls_padding=ft.Padding(bottom=100), + expanded_alignment=ft.Alignment.BOTTOM_RIGHT, + clip_behavior=ft.ClipBehavior.HARD_EDGE, + ) + ) + + et = ft.ExpansionTile( + key="et", + title="ExpansionTile Title", + subtitle="ExpansionTile Subtitle", + # leading=ft.Icons.UMBRELLA, + trailing=ft.Icons.SUNNY, + controls=[ + ft.Text("ExpansionTile Content"), + ft.Text("More Content"), + ], + controls_padding=ft.Padding.all(10), + tile_padding=ft.Padding.all(20), + affinity=ft.TileAffinity.LEADING, + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.add(et) + await flet_app.tester.pump_and_settle() + + # normal state + flet_app.assert_screenshot( + "theme_1_collapsed", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # open state + await flet_app.tester.tap(await flet_app.tester.find_by_key("et")) + await flet_app.tester.pump_and_settle() + flet_app.assert_screenshot( + "theme_1_expanded", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_filled_button_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_filled_button_theme.py new file mode 100644 index 0000000000..5b7744a662 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_filled_button_theme.py @@ -0,0 +1,33 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + filled_button_theme=ft.FilledButtonTheme( + style=ft.ButtonStyle( + bgcolor=ft.Colors.GREEN, + shape=ft.BeveledRectangleBorder( + radius=5, + ), + side=ft.BorderSide(width=5, color=ft.Colors.GREEN_900), + padding=ft.Padding.all(10), + ), + ) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.FilledButton(content="Button"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_floating_action_button_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_floating_action_button_theme.py new file mode 100644 index 0000000000..6f0cdab340 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_floating_action_button_theme.py @@ -0,0 +1,95 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.page.theme = ft.Theme( + floating_action_button_theme=ft.FloatingActionButtonTheme( + bgcolor=ft.Colors.ORANGE, + hover_color=ft.Colors.GREEN, + focus_color=ft.Colors.RED, + foreground_color=ft.Colors.PINK, + splash_color=ft.Colors.YELLOW, + shape=ft.RoundedRectangleBorder( + radius=4, side=ft.BorderSide(color=ft.Colors.BLUE, width=2.0) + ), + elevation=20, + hover_elevation=30, + focus_elevation=40, + disabled_elevation=50, + highlight_elevation=60, + enable_feedback=True, + extended_padding=ft.Padding.all(5), + text_style=ft.TextStyle(italic=True), + icon_label_spacing=20, + extended_size_constraints=ft.BoxConstraints( + min_width=200, + max_width=200, + min_height=200, + max_height=200, + ), + size_constraints=ft.BoxConstraints( + min_width=100, + max_width=100, + min_height=100, + max_height=100, + ), + ) + ) + + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + + fab1 = ft.FloatingActionButton( + key="fab1", + content="Add", + icon=ft.Icons.ADD, + ) + fab2 = ft.FloatingActionButton(ft.Text("Text", color=ft.Colors.GREEN), mini=True) + fab3 = ft.FloatingActionButton("Text", disabled=True) + fab4 = ft.FloatingActionButton("Long Long Long Long Text", disabled=True) + flet_app.page.add(fab1, fab2, fab3, fab4) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1_normal", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test focus and disabled + fab2.autofocus = True + fab3.disabled = True + flet_app.page.update() + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1_focus_disabled", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) + + # test hover + button = await flet_app.tester.find_by_key("fab1") + assert button.count == 1 + await flet_app.tester.mouse_hover(button) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + "theme_1_hover", + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_icon_button_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_icon_button_theme.py new file mode 100644 index 0000000000..1ccd529278 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_icon_button_theme.py @@ -0,0 +1,33 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + icon_button_theme=ft.IconButtonTheme( + style=ft.ButtonStyle( + bgcolor=ft.Colors.GREEN, + shape=ft.BeveledRectangleBorder( + radius=5, + ), + side=ft.BorderSide(width=5, color=ft.Colors.GREEN_900), + padding=ft.Padding.all(10), + ), + ) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.IconButton(icon=ft.Icons.UMBRELLA), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_list_tile_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_list_tile_theme.py new file mode 100644 index 0000000000..9aabfea7f8 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_list_tile_theme.py @@ -0,0 +1,97 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.page.enable_screenshots = True + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + list_tile_theme=ft.ListTileTheme( + icon_color=ft.Colors.PURPLE, + text_color=ft.Colors.PINK, + bgcolor=ft.Colors.LIGHT_GREEN_ACCENT_100, + selected_tile_color=ft.Colors.LIGHT_GREEN_ACCENT_400, + selected_color=ft.Colors.GREEN_700, + is_three_line=True, + enable_feedback=False, + dense=True, + shape=ft.RoundedRectangleBorder( + radius=10, side=ft.BorderSide(color=ft.Colors.RED, width=2.0) + ), + visual_density=ft.VisualDensity.COMFORTABLE, + content_padding=ft.Padding.symmetric(horizontal=20, vertical=10), + min_vertical_padding=50, + horizontal_spacing=30, + min_leading_width=80, + title_text_style=ft.TextStyle( + color=ft.Colors.GREEN, italic=True, weight=ft.FontWeight.BOLD + ), + subtitle_text_style=ft.TextStyle( + color=ft.Colors.GREEN, italic=True, weight=ft.FontWeight.W_200 + ), + leading_and_trailing_text_style=ft.TextStyle( + color=ft.Colors.BLUE, + bgcolor=ft.Colors.GREEN_200, + italic=True, + weight=ft.FontWeight.W_200, + ), + mouse_cursor=ft.MouseCursor.FORBIDDEN, + min_height=100, + style=ft.ListTileStyle.LIST, + title_alignment=ft.ListTileTitleAlignment.THREE_LINE, + ) + ) + + tile_1 = ft.ListTile( + "ListTile with is_three_line = False", + subtitle="List", + leading=ft.Icon(ft.Icons.STAR), + is_three_line=False, + trailing=ft.Checkbox(), + # bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + style=ft.ListTileStyle.LIST, + toggle_inputs=True, + visual_density=ft.VisualDensity.COMPACT, + ) + tile_2 = ft.ListTile( + "ListTile default is_three_line", + subtitle="List", + leading=ft.Icon(ft.Icons.STAR), + # is_three_line=True, + trailing=ft.Checkbox(), + selected=True, + # bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + style=ft.ListTileStyle.LIST, + toggle_inputs=False, + ) + tile_3 = ft.ListTile( + title="ListTile is_three_line = True", + subtitle="Subtitle", + is_three_line=True, + leading=ft.Text("Leading"), + trailing=ft.Text("Trailing"), + bgcolor=ft.Colors.LIGHT_BLUE_ACCENT_100, + hover_color=ft.Colors.YELLOW_200, + style=ft.ListTileStyle.DRAWER, + shape=ft.RoundedRectangleBorder(radius=10), + ) + + flet_app.page.add(tile_1, tile_2, tile_3) + await flet_app.tester.pump_and_settle() + + flet_app.assert_screenshot( + request.node.name, + await flet_app.page.take_screenshot( + pixel_ratio=flet_app.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_outlined_button_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_outlined_button_theme.py new file mode 100644 index 0000000000..2182ba09e4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_outlined_button_theme.py @@ -0,0 +1,33 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + outlined_button_theme=ft.OutlinedButtonTheme( + style=ft.ButtonStyle( + bgcolor=ft.Colors.GREEN, + shape=ft.BeveledRectangleBorder( + radius=5, + ), + side=ft.BorderSide(width=5, color=ft.Colors.GREEN_900), + padding=ft.Padding.all(10), + ), + ) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.OutlinedButton(content="Button"), + ) diff --git a/sdk/python/packages/flet/integration_tests/controls/theme/test_text_button_theme.py b/sdk/python/packages/flet/integration_tests/controls/theme/test_text_button_theme.py new file mode 100644 index 0000000000..26bbbf0d45 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/controls/theme/test_text_button_theme.py @@ -0,0 +1,33 @@ +import pytest +import pytest_asyncio + +import flet as ft +import flet.testing as ftt + + +# Create a new flet_app instance for each test method +@pytest_asyncio.fixture(scope="function", autouse=True) +def flet_app(flet_app_function): + return flet_app_function + + +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_1(flet_app: ftt.FletTestApp, request): + flet_app.resize_page(400, 600) + flet_app.page.theme = ft.Theme( + text_button_theme=ft.TextButtonTheme( + style=ft.ButtonStyle( + bgcolor=ft.Colors.GREEN, + shape=ft.BeveledRectangleBorder( + radius=5, + ), + side=ft.BorderSide(width=5, color=ft.Colors.GREEN_900), + padding=ft.Padding.all(10), + ), + ) + ) + + await flet_app.assert_control_screenshot( + request.node.name, + ft.TextButton(content="Button"), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py b/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py new file mode 100644 index 0000000000..51e28e16ec --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/apps/test_router.py @@ -0,0 +1,649 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.apps.router.active_links import main as active_links +from examples.apps.router.app_drawer import main as app_drawer +from examples.apps.router.auth_dialog import main as auth_dialog +from examples.apps.router.auth_page import main as auth_page +from examples.apps.router.basic import main as basic +from examples.apps.router.dynamic_segments import main as dynamic_segments +from examples.apps.router.featured import main as featured +from examples.apps.router.featured_views import main as featured_views +from examples.apps.router.index_routes import main as index_routes +from examples.apps.router.layout_outlet import main as layout_outlet +from examples.apps.router.loaders import main as loaders +from examples.apps.router.nested_outlet_views import main as nested_outlet_views +from examples.apps.router.nested_routes import main as nested_routes +from examples.apps.router.prefix_routes import main as prefix_routes +from examples.apps.router.runtime_routes import main as runtime_routes +from examples.apps.router.splats import main as splats + +# Helpers to run Router examples. Examples don't define a `main(page)` function — +# they use `page.render(App)` or `page.render_views(App)` inline in a lambda. +# The test fixture expects a callable taking a page, so we wrap the `App` +# component in a small main function here. + + +def _make_render_main(app_component): + def main(page: ft.Page): + page.render(app_component) + + return main + + +def _make_render_views_main(app_component): + def main(page: ft.Page): + page.render_views(app_component) + + return main + + +# --------------------------------------------------------------------------- +# Simple examples — flat routing, outlets, index/prefix/dynamic/splat patterns +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(basic.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + home = await flet_app_function.tester.find_by_text("Home page") + assert home.count == 1 + + about_btn = await flet_app_function.tester.find_by_text("About") + assert about_btn.count == 1 + await flet_app_function.tester.tap(about_btn) + await flet_app_function.tester.pump_and_settle() + + about = await flet_app_function.tester.find_by_text("About page") + assert about.count == 1 + + home_btn = await flet_app_function.tester.find_by_text("Home") + assert home_btn.count == 1 + await flet_app_function.tester.tap(home_btn) + await flet_app_function.tester.pump_and_settle() + + home = await flet_app_function.tester.find_by_text("Home page") + assert home.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(active_links.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_active_links(flet_app_function: ftt.FletTestApp): + home = await flet_app_function.tester.find_by_text("Home page") + assert home.count == 1 + + products_link = await flet_app_function.tester.find_by_text("Products") + assert products_link.count == 1 + await flet_app_function.tester.tap(products_link) + await flet_app_function.tester.pump_and_settle() + + products = await flet_app_function.tester.find_by_text("Products page") + assert products.count == 1 + + settings_link = await flet_app_function.tester.find_by_text("Settings") + assert settings_link.count == 1 + await flet_app_function.tester.tap(settings_link) + await flet_app_function.tester.pump_and_settle() + + settings = await flet_app_function.tester.find_by_text("Settings page") + assert settings.count == 1 + + await flet_app_function.page.push_route("/") + await flet_app_function.tester.pump_and_settle() + home = await flet_app_function.tester.find_by_text("Home page") + assert home.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(index_routes.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_index_routes(flet_app_function: ftt.FletTestApp): + dashboard = await flet_app_function.tester.find_by_text( + "Dashboard (index route for /)" + ) + assert dashboard.count == 1 + + settings_btn = await flet_app_function.tester.find_by_text("Settings") + assert settings_btn.count == 1 + await flet_app_function.tester.tap(settings_btn) + await flet_app_function.tester.pump_and_settle() + + settings_home = await flet_app_function.tester.find_by_text( + "Settings Home (index route for /settings)" + ) + assert settings_home.count == 1 + + profile_btn = await flet_app_function.tester.find_by_text("Profile") + assert profile_btn.count == 1 + await flet_app_function.tester.tap(profile_btn) + await flet_app_function.tester.pump_and_settle() + + profile = await flet_app_function.tester.find_by_text("Profile Settings") + assert profile.count == 1 + + security_btn = await flet_app_function.tester.find_by_text("Security") + assert security_btn.count == 1 + await flet_app_function.tester.tap(security_btn) + await flet_app_function.tester.pump_and_settle() + + security = await flet_app_function.tester.find_by_text("Security Settings") + assert security.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(layout_outlet.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_layout_outlet(flet_app_function: ftt.FletTestApp): + # AppBar is shared across all routes — verify it's there on initial render. + appbar_title = await flet_app_function.tester.find_by_text("My App") + assert appbar_title.count == 1 + + home = await flet_app_function.tester.find_by_text("Welcome home!") + assert home.count == 1 + + about_btn = await flet_app_function.tester.find_by_text("About") + assert about_btn.count == 1 + await flet_app_function.tester.tap(about_btn) + await flet_app_function.tester.pump_and_settle() + + about = await flet_app_function.tester.find_by_text("About us") + assert about.count == 1 + # AppBar still present after navigation + appbar_title = await flet_app_function.tester.find_by_text("My App") + assert appbar_title.count == 1 + + contact_btn = await flet_app_function.tester.find_by_text("Contact") + assert contact_btn.count == 1 + await flet_app_function.tester.tap(contact_btn) + await flet_app_function.tester.pump_and_settle() + + contact = await flet_app_function.tester.find_by_text("Contact page") + assert contact.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(prefix_routes.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_prefix_routes(flet_app_function: ftt.FletTestApp): + home_text = await flet_app_function.tester.find_by_text("Select a section above") + assert home_text.count == 1 + + # Pathless layout wraps Users with ADMIN PANEL header + users_btn = await flet_app_function.tester.find_by_text("Users") + assert users_btn.count == 1 + await flet_app_function.tester.tap(users_btn) + await flet_app_function.tester.pump_and_settle() + + users = await flet_app_function.tester.find_by_text("Users page") + assert users.count == 1 + admin_header = await flet_app_function.tester.find_by_text("ADMIN PANEL") + assert admin_header.count == 1 + + # Path-only grouping — /api/users has no admin layout + api_users_btn = await flet_app_function.tester.find_by_text("API Users") + assert api_users_btn.count == 1 + await flet_app_function.tester.tap(api_users_btn) + await flet_app_function.tester.pump_and_settle() + + api_users = await flet_app_function.tester.find_by_text("API: Users endpoint") + assert api_users.count == 1 + admin_header = await flet_app_function.tester.find_by_text("ADMIN PANEL") + assert admin_header.count == 0 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(dynamic_segments.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_dynamic_segments(flet_app_function: ftt.FletTestApp): + users_heading = await flet_app_function.tester.find_by_text("Users") + assert users_heading.count == 1 + + alice_btn = await flet_app_function.tester.find_by_text("User alice") + assert alice_btn.count == 1 + await flet_app_function.tester.tap(alice_btn) + await flet_app_function.tester.pump_and_settle() + + alice = await flet_app_function.tester.find_by_text("User: alice") + assert alice.count == 1 + + post_btn = await flet_app_function.tester.find_by_text("View post #10") + assert post_btn.count == 1 + await flet_app_function.tester.tap(post_btn) + await flet_app_function.tester.pump_and_settle() + + post = await flet_app_function.tester.find_by_text("User: alice, Post: 10") + assert post.count == 1 + + back_btn = await flet_app_function.tester.find_by_text("Back to user") + assert back_btn.count == 1 + await flet_app_function.tester.tap(back_btn) + await flet_app_function.tester.pump_and_settle() + + alice = await flet_app_function.tester.find_by_text("User: alice") + assert alice.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(splats.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_splats(flet_app_function: ftt.FletTestApp): + title = await flet_app_function.tester.find_by_text("File Browser Demo") + assert title.count == 1 + + browse_btn = await flet_app_function.tester.find_by_text( + "Browse /files/docs/readme.md" + ) + assert browse_btn.count == 1 + await flet_app_function.tester.tap(browse_btn) + await flet_app_function.tester.pump_and_settle() + + path_text = await flet_app_function.tester.find_by_text( + "Current path: docs/readme.md" + ) + assert path_text.count == 1 + + +# --------------------------------------------------------------------------- +# Data / state examples +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(loaders.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_loaders(flet_app_function: ftt.FletTestApp): + home_title = await flet_app_function.tester.find_by_text("Home") + assert home_title.count >= 1 # "Home" appears in button + heading + message = await flet_app_function.tester.find_by_text("Welcome to the app!") + assert message.count == 1 + + products_btn = await flet_app_function.tester.find_by_text("Products") + assert products_btn.count == 1 + await flet_app_function.tester.tap(products_btn) + await flet_app_function.tester.pump_and_settle() + + widget = await flet_app_function.tester.find_by_text("Widget A") + assert widget.count == 1 + + await flet_app_function.tester.tap(widget) + await flet_app_function.tester.pump_and_settle() + + stock = await flet_app_function.tester.find_by_text("In stock: 42") + assert stock.count == 1 + + back_btn = await flet_app_function.tester.find_by_text("Back to products") + assert back_btn.count == 1 + await flet_app_function.tester.tap(back_btn) + await flet_app_function.tester.pump_and_settle() + + gadget = await flet_app_function.tester.find_by_text("Gadget B") + assert gadget.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(runtime_routes.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_runtime_routes(flet_app_function: ftt.FletTestApp): + home = await flet_app_function.tester.find_by_text("Home page") + assert home.count == 1 + + # Admin button not yet present + admin_btn_before = await flet_app_function.tester.find_by_text("Admin") + assert admin_btn_before.count == 0 + + add_btn = await flet_app_function.tester.find_by_text("Add Admin Route") + assert add_btn.count == 1 + await flet_app_function.tester.tap(add_btn) + await flet_app_function.tester.pump_and_settle() + + admin_btn = await flet_app_function.tester.find_by_text("Admin") + assert admin_btn.count == 1 + await flet_app_function.tester.tap(admin_btn) + await flet_app_function.tester.pump_and_settle() + + admin_panel = await flet_app_function.tester.find_by_text( + "Admin panel (dynamically added!)" + ) + assert admin_panel.count == 1 + + remove_btn = await flet_app_function.tester.find_by_text("Remove Admin Route") + assert remove_btn.count == 1 + await flet_app_function.tester.tap(remove_btn) + await flet_app_function.tester.pump_and_settle() + + home = await flet_app_function.tester.find_by_text("Home page") + assert home.count == 1 + admin_btn_after = await flet_app_function.tester.find_by_text("Admin") + assert admin_btn_after.count == 0 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(auth_page.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_auth_page(flet_app_function: ftt.FletTestApp): + login_title = await flet_app_function.tester.find_by_text("Login") + assert login_title.count == 1 + + sign_in_btn = await flet_app_function.tester.find_by_text("Sign In") + assert sign_in_btn.count == 1 + await flet_app_function.tester.tap(sign_in_btn) + await flet_app_function.tester.pump_and_settle() + + dashboard = await flet_app_function.tester.find_by_text( + "Dashboard — Welcome, admin!" + ) + assert dashboard.count == 1 + + logout_btn = await flet_app_function.tester.find_by_text("Logout") + assert logout_btn.count == 1 + await flet_app_function.tester.tap(logout_btn) + await flet_app_function.tester.pump_and_settle() + + login_title = await flet_app_function.tester.find_by_text("Login") + assert login_title.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(auth_dialog.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_auth_dialog(flet_app_function: ftt.FletTestApp): + dialog_title = await flet_app_function.tester.find_by_text("Please log in") + assert dialog_title.count == 1 + + login_btn = await flet_app_function.tester.find_by_text("Login") + assert login_btn.count == 1 + await flet_app_function.tester.tap(login_btn) + await flet_app_function.tester.pump_and_settle() + + greeting = await flet_app_function.tester.find_by_text("Home — Hello, admin!") + assert greeting.count == 1 + + logout_btn = await flet_app_function.tester.find_by_text("Logout") + assert logout_btn.count == 1 + await flet_app_function.tester.tap(logout_btn) + await flet_app_function.tester.pump_and_settle() + + dialog_title = await flet_app_function.tester.find_by_text("Please log in") + assert dialog_title.count == 1 + + +# --------------------------------------------------------------------------- +# Featured example +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_main(featured.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_featured(flet_app_function: ftt.FletTestApp): + sign_in = await flet_app_function.tester.find_by_text("Sign In") + assert sign_in.count == 1 + + login_btn = await flet_app_function.tester.find_by_text("Login") + assert login_btn.count == 1 + await flet_app_function.tester.tap(login_btn) + await flet_app_function.tester.pump_and_settle() + + greeting = await flet_app_function.tester.find_by_text( + "Welcome to the Router Demo!" + ) + assert greeting.count == 1 + featured_count = await flet_app_function.tester.find_by_text( + "3 featured projects available" + ) + assert featured_count.count == 1 + + browse_btn = await flet_app_function.tester.find_by_text("Browse projects") + assert browse_btn.count == 1 + await flet_app_function.tester.tap(browse_btn) + await flet_app_function.tester.pump_and_settle() + + flet_project = await flet_app_function.tester.find_by_text("Flet") + assert flet_project.count == 1 + await flet_app_function.tester.tap(flet_project) + await flet_app_function.tester.pump_and_settle() + + description = await flet_app_function.tester.find_by_text("Build apps in Python") + assert description.count == 1 + + back_btn = await flet_app_function.tester.find_by_text("Back to projects") + assert back_btn.count == 1 + await flet_app_function.tester.tap(back_btn) + await flet_app_function.tester.pump_and_settle() + + flutter_project = await flet_app_function.tester.find_by_text("Flutter") + assert flutter_project.count == 1 + + # Navigate to settings via nav link + settings_link = await flet_app_function.tester.find_by_text("Settings") + assert settings_link.count >= 1 + await flet_app_function.page.push_route("/settings") + await flet_app_function.tester.pump_and_settle() + + sections_text = await flet_app_function.tester.find_by_text("Available sections:") + assert sections_text.count == 1 + profile_item = await flet_app_function.tester.find_by_text("Profile") + assert profile_item.count == 1 + await flet_app_function.tester.tap(profile_item) + await flet_app_function.tester.pump_and_settle() + + profile_title = await flet_app_function.tester.find_by_text("Profile Settings") + assert profile_title.count == 1 + + +# --------------------------------------------------------------------------- +# manage_views examples +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_views_main(nested_routes.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_nested_routes(flet_app_function: ftt.FletTestApp): + home_title = await flet_app_function.tester.find_by_text("Home") + assert home_title.count >= 1 # appears in AppBar and body + + go_products_btn = await flet_app_function.tester.find_by_text("Go to Products") + assert go_products_btn.count == 1 + await flet_app_function.tester.tap(go_products_btn) + await flet_app_function.tester.pump_and_settle() + + products_title = await flet_app_function.tester.find_by_text("All Products") + assert products_title.count == 1 + + product1_btn = await flet_app_function.tester.find_by_text("View Product #1") + assert product1_btn.count == 1 + await flet_app_function.tester.tap(product1_btn) + await flet_app_function.tester.pump_and_settle() + + details = await flet_app_function.tester.find_by_text("Details for product #1") + assert details.count == 1 + + # AppBar back → go to products + back_btn = await flet_app_function.tester.find_by_tooltip("Back") + assert back_btn.count == 1 + await flet_app_function.tester.tap(back_btn) + await flet_app_function.tester.pump_and_settle() + + products_title = await flet_app_function.tester.find_by_text("All Products") + assert products_title.count == 1 + + # AppBar back → go to home + back_btn = await flet_app_function.tester.find_by_tooltip("Back") + assert back_btn.count == 1 + await flet_app_function.tester.tap(back_btn) + await flet_app_function.tester.pump_and_settle() + + go_products_btn = await flet_app_function.tester.find_by_text("Go to Products") + assert go_products_btn.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_views_main(nested_outlet_views.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_nested_outlet_views(flet_app_function: ftt.FletTestApp): + welcome = await flet_app_function.tester.find_by_text("Welcome!") + assert welcome.count == 1 + + browse_btn = await flet_app_function.tester.find_by_text("Browse Products") + assert browse_btn.count == 1 + await flet_app_function.tester.tap(browse_btn) + await flet_app_function.tester.pump_and_settle() + + products_title = await flet_app_function.tester.find_by_text("All Products") + assert products_title.count == 1 + # Shared layout footer visible on products list + footer = await flet_app_function.tester.find_by_text("Products Footer") + assert footer.count == 1 + + product1_btn = await flet_app_function.tester.find_by_text("View Product #1") + assert product1_btn.count == 1 + await flet_app_function.tester.tap(product1_btn) + await flet_app_function.tester.pump_and_settle() + + product_title = await flet_app_function.tester.find_by_text("Product #1") + assert product_title.count == 1 + # Footer still present — shared layout wraps the detail view too + footer = await flet_app_function.tester.find_by_text("Products Footer") + assert footer.count == 1 + + # AppBar back → products list + back_btn = await flet_app_function.tester.find_by_tooltip("Back") + assert back_btn.count == 1 + await flet_app_function.tester.tap(back_btn) + await flet_app_function.tester.pump_and_settle() + + products_title = await flet_app_function.tester.find_by_text("All Products") + assert products_title.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_views_main(featured_views.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_featured_views(flet_app_function: ftt.FletTestApp): + welcome = await flet_app_function.tester.find_by_text("Welcome to the app!") + assert welcome.count == 1 + + # Navigate to Projects via URL (NavigationRail tap is flaky in tests). + await flet_app_function.page.push_route("/projects") + await flet_app_function.tester.pump_and_settle() + + projects_title = await flet_app_function.tester.find_by_text("All Projects") + assert projects_title.count == 1 + project_btn = await flet_app_function.tester.find_by_text("Landing Page Redesign") + assert project_btn.count == 1 + + # Note: the example deliberately pins RootLayout's View.route="/" to + # avoid slide transitions between top-level destinations. A side-effect + # is that pushing /projects/:pid can't produce a stacked detail view + # (all views share the same Navigator key), so we only assert on the + # top-level destinations here. + + # Settings with tabs — General by default + await flet_app_function.page.push_route("/settings/general") + await flet_app_function.tester.pump_and_settle() + + general_title = await flet_app_function.tester.find_by_text("General Settings") + assert general_title.count == 1 + + # Switch to Account tab + await flet_app_function.page.push_route("/settings/account") + await flet_app_function.tester.pump_and_settle() + + account_title = await flet_app_function.tester.find_by_text("Account Settings") + assert account_title.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": _make_render_views_main(app_drawer.App)}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_app_drawer(flet_app_function: ftt.FletTestApp): + welcome = await flet_app_function.tester.find_by_text("Welcome") + assert welcome.count == 1 + + browse_btn = await flet_app_function.tester.find_by_text("Browse Apps") + assert browse_btn.count == 1 + await flet_app_function.tester.tap(browse_btn) + await flet_app_function.tester.pump_and_settle() + + your_apps = await flet_app_function.tester.find_by_text("Your apps") + assert your_apps.count == 1 + + app_btn = await flet_app_function.tester.find_by_text("Acme Web") + assert app_btn.count == 1 + await flet_app_function.tester.tap(app_btn) + await flet_app_function.tester.pump_and_settle() + + app_id_text = await flet_app_function.tester.find_by_text("App ID: 1") + assert app_id_text.count == 1 + + # Open Settings drawer via in-content button (simpler than the AppBar icon) + open_settings = await flet_app_function.tester.find_by_text("Open Settings") + assert open_settings.count == 1 + await flet_app_function.tester.tap(open_settings) + await flet_app_function.tester.pump_and_settle() + + general_title = await flet_app_function.tester.find_by_text("General Settings") + assert general_title.count == 1 + + # Deep-link directly to Permissions tab + await flet_app_function.page.push_route("/apps/1/settings/permissions") + await flet_app_function.tester.pump_and_settle() + + permissions_title = await flet_app_function.tester.find_by_text("Permissions") + assert permissions_title.count >= 1 + permission_switch = await flet_app_function.tester.find_by_text( + "Require 2FA for admins" + ) + assert permission_switch.count == 1 diff --git a/sdk/python/packages/flet/integration_tests/examples/apps/test_routing_navigation.py b/sdk/python/packages/flet/integration_tests/examples/apps/test_routing_navigation.py new file mode 100644 index 0000000000..824d8394c7 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/apps/test_routing_navigation.py @@ -0,0 +1,244 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.apps.routing_navigation.drawer_navigation import main as drawer_navigation +from examples.apps.routing_navigation.home_store import main as home_store +from examples.apps.routing_navigation.initial_route import main as initial_route +from examples.apps.routing_navigation.pop_view_confirm import main as pop_view_confirm +from examples.apps.routing_navigation.pop_views_until import main as pop_views_until +from examples.apps.routing_navigation.route_change_event import ( + main as route_change_event, +) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": initial_route.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_initial_route(flet_app_function: ftt.FletTestApp): + text = await flet_app_function.tester.find_by_text("Initial route: /") + assert text.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": route_change_event.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_route_change_event(flet_app_function: ftt.FletTestApp): + text = await flet_app_function.tester.find_by_text("Initial route: /") + assert text.count == 1 + await flet_app_function.page.push_route("/new-route") + await flet_app_function.tester.pump_and_settle() + new_text = await flet_app_function.tester.find_by_text("New route: /new-route") + assert new_text.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": home_store.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_home_store(flet_app_function: ftt.FletTestApp): + # Verify initial view + button = await flet_app_function.tester.find_by_text_containing("Visit Store") + assert button.count == 1 + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + + # Verify store view + store_button = await flet_app_function.tester.find_by_text_containing("Go Home") + assert store_button.count == 1 + await flet_app_function.tester.tap(store_button) + await flet_app_function.tester.pump_and_settle() + + # Verify back to initial view + button = await flet_app_function.tester.find_by_text_containing("Visit Store") + assert button.count == 1 + + # Go to store again with push_route + await flet_app_function.page.push_route("/store") + await flet_app_function.tester.pump_and_settle() + store_button = await flet_app_function.tester.find_by_text_containing("Go Home") + assert store_button.count == 1 + + # Go home again with push_route + await flet_app_function.page.push_route("/") + await flet_app_function.tester.pump_and_settle() + button = await flet_app_function.tester.find_by_text_containing("Visit Store") + assert button.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": pop_view_confirm.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_pop_view_confirm(flet_app_function: ftt.FletTestApp): + # Verify initial view + button = await flet_app_function.tester.find_by_text_containing("Go to store") + assert button.count == 1 + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + + # Verify permission view + permission_view_text = await flet_app_function.tester.find_by_text("/store View") + assert permission_view_text.count == 1 + + # Click Back button + back_button = await flet_app_function.tester.find_by_tooltip("Back") + assert back_button.count == 1 + await flet_app_function.tester.tap(back_button) + await flet_app_function.tester.pump_and_settle() + + # Verify that confirmation dialog is shown + dlg_text = await flet_app_function.tester.find_by_text("Please confirm") + assert dlg_text.count == 1 + + # Click No button + no_button = await flet_app_function.tester.find_by_text("No") + assert no_button.count == 1 + await flet_app_function.tester.tap(no_button) + await flet_app_function.tester.pump_and_settle() + + # Verify still in permission view + permission_view_text = await flet_app_function.tester.find_by_text("/store View") + assert permission_view_text.count == 1 + + # Click Back button again + back_button = await flet_app_function.tester.find_by_tooltip("Back") + assert back_button.count == 1 + await flet_app_function.tester.tap(back_button) + await flet_app_function.tester.pump_and_settle() + + # Verify that confirmation dialog is shown again + dlg_text = await flet_app_function.tester.find_by_text("Please confirm") + assert dlg_text.count == 1 + + # Click Yes button + yes_button = await flet_app_function.tester.find_by_text("Yes") + assert yes_button.count == 1 + await flet_app_function.tester.tap(yes_button) + await flet_app_function.tester.pump_and_settle() + + # Verify back to initial view + button = await flet_app_function.tester.find_by_text_containing("Go to store") + assert button.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": drawer_navigation.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_drawer_navigation(flet_app_function: ftt.FletTestApp): + # Verify initial view + hamburger_button = await flet_app_function.tester.find_by_icon(ft.Icons.MENU) + assert hamburger_button.count == 1 + await flet_app_function.tester.tap(hamburger_button) + await flet_app_function.tester.pump_and_settle() + + # Select Store from drawer + store_item = await flet_app_function.tester.find_by_icon(ft.Icons.STORE_OUTLINED) + assert store_item.count == 1 + await flet_app_function.tester.tap(store_item) + await flet_app_function.tester.pump_and_settle() + + # Verify store view + store_text = await flet_app_function.tester.find_by_text("Welcome to Store Page") + assert store_text.count == 1 + + # Open drawer again + hamburger_button = await flet_app_function.tester.find_by_icon(ft.Icons.MENU) + assert hamburger_button.count == 1 + await flet_app_function.tester.tap(hamburger_button) + await flet_app_function.tester.pump_and_settle() + + # Select About from drawer + about_item = await flet_app_function.tester.find_by_icon(ft.Icons.PHONE_OUTLINED) + assert about_item.count == 1 + await flet_app_function.tester.tap(about_item) + await flet_app_function.tester.pump_and_settle() + + # Verify about view + about_text = await flet_app_function.tester.find_by_text("Welcome to About Page") + assert about_text.count == 1 + + # Open drawer again + hamburger_button = await flet_app_function.tester.find_by_icon(ft.Icons.MENU) + assert hamburger_button.count == 1 + await flet_app_function.tester.tap(hamburger_button) + await flet_app_function.tester.pump_and_settle() + + # Select Home from drawer + home_item = await flet_app_function.tester.find_by_icon(ft.Icons.HOME_OUTLINED) + assert home_item.count == 1 + await flet_app_function.tester.tap(home_item) + await flet_app_function.tester.pump_and_settle() + + # Verify home view + home_text = await flet_app_function.tester.find_by_text("Welcome to Home Page") + assert home_text.count == 1 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": pop_views_until.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_pop_views_until(flet_app_function: ftt.FletTestApp): + # Verify initial view + button = await flet_app_function.tester.find_by_text_containing("Start flow") + assert button.count == 1 + result_text = await flet_app_function.tester.find_by_text("No result yet") + assert result_text.count == 1 + + # Navigate to Step 1 + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + step1_text = await flet_app_function.tester.find_by_text("Step 1 of the flow") + assert step1_text.count == 1 + + # Navigate to Step 2 + step2_button = await flet_app_function.tester.find_by_text_containing( + "Go to Step 2" + ) + assert step2_button.count == 1 + await flet_app_function.tester.tap(step2_button) + await flet_app_function.tester.pump_and_settle() + step2_text = await flet_app_function.tester.find_by_text("Step 2 of the flow") + assert step2_text.count == 1 + + # Navigate to Step 3 + step3_button = await flet_app_function.tester.find_by_text_containing( + "Go to Step 3" + ) + assert step3_button.count == 1 + await flet_app_function.tester.tap(step3_button) + await flet_app_function.tester.pump_and_settle() + final_text = await flet_app_function.tester.find_by_text("Flow complete!") + assert final_text.count == 1 + + # Click "Finish and go Home" — triggers pop_views_until + finish_button = await flet_app_function.tester.find_by_text_containing( + "Finish and go Home" + ) + assert finish_button.count == 1 + await flet_app_function.tester.tap(finish_button) + await flet_app_function.tester.pump_and_settle() + + # Verify back at Home with result + result_text = await flet_app_function.tester.find_by_text("Result: Flow completed!") + assert result_text.count == 1 + + # Verify we can start the flow again + button = await flet_app_function.tester.find_by_text_containing("Start flow") + assert button.count == 1 diff --git a/sdk/python/packages/flet/integration_tests/examples/apps/test_use_dialog.py b/sdk/python/packages/flet/integration_tests/examples/apps/test_use_dialog.py new file mode 100644 index 0000000000..d89df7c8fa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/apps/test_use_dialog.py @@ -0,0 +1,225 @@ +import asyncio + +import pytest + +import flet.testing as ftt +from examples.apps.declarative.use_dialog_basic import main as use_dialog_basic +from examples.apps.declarative.use_dialog_chained import main as use_dialog_chained +from examples.apps.declarative.use_dialog_multiple import main as use_dialog_multiple + +# ``use_dialog_*`` examples don't define a ``main(page)`` with page.render; they +# export both ``App`` (component) and ``main`` (wrapper). We use the module's +# ``main`` directly. + + +# --------------------------------------------------------------------------- +# use_dialog_basic — single dialog, open/cancel/confirm +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": use_dialog_basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_use_dialog_basic(flet_app_function: ftt.FletTestApp): + title = await flet_app_function.tester.find_by_text("Declarative Dialog Example") + assert title.count == 1 + + # Dialog not yet open + dialog_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert dialog_title.count == 0 + + # Open dialog via "Delete File" button + open_btn = await flet_app_function.tester.find_by_text("Delete File") + assert open_btn.count == 1 + await flet_app_function.tester.tap(open_btn) + await flet_app_function.tester.pump_and_settle() + + dialog_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert dialog_title.count == 1 + cancel_btn = await flet_app_function.tester.find_by_text("Cancel") + assert cancel_btn.count == 1 + + # Dismiss via Cancel + await flet_app_function.tester.tap(cancel_btn) + await flet_app_function.tester.pump_and_settle() + + dialog_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert dialog_title.count == 0 + + # Reopen and confirm — wait past the 2s asyncio.sleep in handle_delete. + open_btn = await flet_app_function.tester.find_by_text("Delete File") + assert open_btn.count == 1 + await flet_app_function.tester.tap(open_btn) + await flet_app_function.tester.pump_and_settle() + + delete_btn = await flet_app_function.tester.find_by_text("Delete") + assert delete_btn.count == 1 + await flet_app_function.tester.tap(delete_btn) + await flet_app_function.tester.pump_and_settle() + + # Mid-delete state + deleting_msg = await flet_app_function.tester.find_by_text( + "Deleting, please wait..." + ) + assert deleting_msg.count == 1 + + # Wait for the async delete (2s) and one pump to let the dialog unmount. + await asyncio.sleep(2.3) + await flet_app_function.tester.pump_and_settle() + + dialog_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert dialog_title.count == 0 + + +# --------------------------------------------------------------------------- +# use_dialog_chained — confirm dialog → success dialog after dismiss +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": use_dialog_chained.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_use_dialog_chained(flet_app_function: ftt.FletTestApp): + title = await flet_app_function.tester.find_by_text("Chained Dialogs Example") + assert title.count == 1 + + status = await flet_app_function.tester.find_by_text( + "Click the button to delete the file." + ) + assert status.count == 1 + + # Open confirm dialog + open_btn = await flet_app_function.tester.find_by_text("Delete File") + assert open_btn.count == 1 + await flet_app_function.tester.tap(open_btn) + await flet_app_function.tester.pump_and_settle() + + confirm_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert confirm_title.count == 1 + + # Confirm delete — waits 2s in handle_delete, then closes confirm and + # (via on_dismiss chaining on the use_ref flag) opens the success dialog. + # We give the async sleep time to complete *before* pumping again so + # the dismiss-event round-trip runs inside pump_and_settle. + delete_btn = await flet_app_function.tester.find_by_text("Delete") + assert delete_btn.count == 1 + await flet_app_function.tester.tap(delete_btn) + + await asyncio.sleep(2.5) + await flet_app_function.tester.pump_and_settle() + # Give the dismiss animation + on_dismiss round-trip one more settle pass. + await asyncio.sleep(0.3) + await flet_app_function.tester.pump_and_settle() + + # Success dialog is now up. + success_title = await flet_app_function.tester.find_by_text("Done!") + assert success_title.count == 1 + success_body = await flet_app_function.tester.find_by_text( + "report.pdf has been deleted." + ) + assert success_body.count == 1 + + # Dismiss success dialog via OK. + ok_btn = await flet_app_function.tester.find_by_text("OK") + assert ok_btn.count == 1 + await flet_app_function.tester.tap(ok_btn) + await flet_app_function.tester.pump_and_settle() + + success_title = await flet_app_function.tester.find_by_text("Done!") + assert success_title.count == 0 + + # Status text flipped to "File deleted." and the Delete button is disabled. + status = await flet_app_function.tester.find_by_text("File deleted.") + assert status.count == 1 + + +# --------------------------------------------------------------------------- +# use_dialog_multiple — per-item rename and delete dialogs +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": use_dialog_multiple.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_use_dialog_multiple(flet_app_function: ftt.FletTestApp): + title = await flet_app_function.tester.find_by_text("Multiple Dialogs Example") + assert title.count == 1 + + for name in ("report.pdf", "photo.jpg", "notes.txt"): + item = await flet_app_function.tester.find_by_text(name) + assert item.count == 1 + + # Open the rename dialog for report.pdf via its pencil tooltip. + rename_btns = await flet_app_function.tester.find_by_tooltip("Rename") + assert rename_btns.count == 3 + await flet_app_function.tester.tap(rename_btns.first) + await flet_app_function.tester.pump_and_settle() + + rename_title = await flet_app_function.tester.find_by_text("Rename report.pdf") + assert rename_title.count == 1 + + cancel_btn = await flet_app_function.tester.find_by_text("Cancel") + assert cancel_btn.count == 1 + await flet_app_function.tester.tap(cancel_btn) + await flet_app_function.tester.pump_and_settle() + + rename_title = await flet_app_function.tester.find_by_text("Rename report.pdf") + assert rename_title.count == 0 + + # Open delete dialog for report.pdf — the second file-item row triggers + # via the Delete tooltip icon. + delete_btns = await flet_app_function.tester.find_by_tooltip("Delete") + assert delete_btns.count == 3 + await flet_app_function.tester.tap(delete_btns.first) + await flet_app_function.tester.pump_and_settle() + + delete_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert delete_title.count == 1 + body = await flet_app_function.tester.find_by_text("This action cannot be undone.") + assert body.count == 1 + + cancel_btn = await flet_app_function.tester.find_by_text("Cancel") + assert cancel_btn.count == 1 + await flet_app_function.tester.tap(cancel_btn) + await flet_app_function.tester.pump_and_settle() + + delete_title = await flet_app_function.tester.find_by_text("Delete report.pdf?") + assert delete_title.count == 0 + + # Confirm a delete on photo.jpg — should remove that row after the 1s + # simulated async. + delete_btns = await flet_app_function.tester.find_by_tooltip("Delete") + assert delete_btns.count == 3 + # tap the second row's delete + second = delete_btns.at(1) + await flet_app_function.tester.tap(second) + await flet_app_function.tester.pump_and_settle() + + delete_title = await flet_app_function.tester.find_by_text("Delete photo.jpg?") + assert delete_title.count == 1 + + confirm = await flet_app_function.tester.find_by_text("Delete") + assert confirm.count == 1 + await flet_app_function.tester.tap(confirm) + await flet_app_function.tester.pump_and_settle() + + await asyncio.sleep(1.3) + await flet_app_function.tester.pump_and_settle() + + delete_title = await flet_app_function.tester.find_by_text("Delete photo.jpg?") + assert delete_title.count == 0 + photo = await flet_app_function.tester.find_by_text("photo.jpg") + assert photo.count == 0 + report = await flet_app_function.tester.find_by_text("report.pdf") + assert report.count == 1 + notes = await flet_app_function.tester.find_by_text("notes.txt") + assert notes.count == 1 diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/__init__.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/canvas/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/canvas/image_for_docs.png new file mode 100644 index 0000000000..f94b35dec8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/canvas/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/column/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/column/image_for_docs.png new file mode 100644 index 0000000000..8a0b9d2eb1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/column/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/nested_themes_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/nested_themes_1.png new file mode 100644 index 0000000000..ef694165d5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/nested_themes_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/nested_themes_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/nested_themes_2.png new file mode 100644 index 0000000000..eaedbe2356 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/nested_themes_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/size_aware.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/size_aware.png new file mode 100644 index 0000000000..f4be5bbf7a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/container/size_aware.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_loose_chat_messages.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_loose_chat_messages.png new file mode 100644 index 0000000000..510d545471 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_loose_chat_messages.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_row_equal_split.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_row_equal_split.png new file mode 100644 index 0000000000..78bff7ee0e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_row_equal_split.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_row_proportional_1_3_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_row_proportional_1_3_1.png new file mode 100644 index 0000000000..d09a46dc4f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_row_proportional_1_3_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_textfield_in_row.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_textfield_in_row.png new file mode 100644 index 0000000000..123b94d126 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/control/expand_textfield_in_row.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/grid_view/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/grid_view/image_for_docs.png new file mode 100644 index 0000000000..194565e3f6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/grid_view/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic.gif new file mode 100644 index 0000000000..cd81e89ae3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic_1.png new file mode 100644 index 0000000000..ae3e60828a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic_2.png new file mode 100644 index 0000000000..09d16eb245 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/hero/basic_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/icon/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/icon/image_for_docs.png new file mode 100644 index 0000000000..ced4d6deba Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/icon/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/image/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/image/image_for_docs.png new file mode 100644 index 0000000000..e9f13cce66 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/image/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip.png new file mode 100644 index 0000000000..cf6c5d9cbd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_after_x.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_after_x.png new file mode 100644 index 0000000000..65bf82e919 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_after_x.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_after_y.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_after_y.png new file mode 100644 index 0000000000..f1006a1e10 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_after_y.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_initial.png new file mode 100644 index 0000000000..8d472a39da Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/flip_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/matrix4_transform.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/matrix4_transform.png new file mode 100644 index 0000000000..6b8cbf3892 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/layout_control/matrix4_transform.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/list_view/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/list_view/image_for_docs.png new file mode 100644 index 0000000000..9e03eecd39 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/list_view/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/markdown/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/markdown/image_for_docs.png new file mode 100644 index 0000000000..8d4217cb79 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/markdown/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/pagelet/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/pagelet/basic.png new file mode 100644 index 0000000000..c696730687 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/pagelet/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/pagelet/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/pagelet/image_for_docs.png new file mode 100644 index 0000000000..51fb142dc3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/pagelet/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/placeholder/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/placeholder/basic.png new file mode 100644 index 0000000000..0eef7a951c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/placeholder/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/placeholder/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/placeholder/image_for_docs.png new file mode 100644 index 0000000000..3ebb0198cd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/placeholder/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic.gif new file mode 100644 index 0000000000..c646d73614 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_1.png new file mode 100644 index 0000000000..8bc2acde2a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_2.png new file mode 100644 index 0000000000..92acabaddb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_3.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_3.png new file mode 100644 index 0000000000..25b01f0ed6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/basic_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint.gif b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint.gif new file mode 100644 index 0000000000..b92fb34853 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_1.png new file mode 100644 index 0000000000..941192566a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_2.png new file mode 100644 index 0000000000..f72c5cfe1a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_3.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_3.png new file mode 100644 index 0000000000..085a368163 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/custom_breakpoint_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/image_for_docs.png new file mode 100644 index 0000000000..ce4eb87ca9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/responsive_row/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/rotated_box/rotated_box.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/rotated_box/rotated_box.png new file mode 100644 index 0000000000..c1e3f595ac Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/rotated_box/rotated_box.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/alignment.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/alignment.png new file mode 100644 index 0000000000..d94d28de98 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/alignment.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/image_for_docs.png new file mode 100644 index 0000000000..44fc49569a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/row_spacing_adjustment.gif b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/row_spacing_adjustment.gif new file mode 100644 index 0000000000..6f72ee6e8e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/row_spacing_adjustment.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing1.png new file mode 100644 index 0000000000..3c3a1e2ba6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing2.png new file mode 100644 index 0000000000..6a9637f78b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing3.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing3.png new file mode 100644 index 0000000000..d73eaa815f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/spacing3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/vertical_alignment.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/vertical_alignment.png new file mode 100644 index 0000000000..4a3013b89d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/vertical_alignment.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap1.png new file mode 100644 index 0000000000..ec6251095c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap2.png new file mode 100644 index 0000000000..d835f92c8b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap3.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap3.png new file mode 100644 index 0000000000..9b78c28627 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap_adjustment.gif b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap_adjustment.gif new file mode 100644 index 0000000000..a14ccc4cd4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/row/wrap_adjustment.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/fade_out_image_bottom.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/fade_out_image_bottom.png new file mode 100644 index 0000000000..2a433cec2d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/fade_out_image_bottom.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/image_for_docs.png new file mode 100644 index 0000000000..0690ad8c17 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/linear_and_radial_gradients.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/linear_and_radial_gradients.png new file mode 100644 index 0000000000..d6639171ad Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/linear_and_radial_gradients.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/pink_radial_glow.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/pink_radial_glow.png new file mode 100644 index 0000000000..7253c48105 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shader_mask/pink_radial_glow.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/basic_placeholder.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/basic_placeholder.png new file mode 100644 index 0000000000..55c7d0cc93 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/basic_placeholder.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/custom_gradient.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/custom_gradient.png new file mode 100644 index 0000000000..55363ccb97 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/custom_gradient.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs.gif b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs.gif new file mode 100644 index 0000000000..587b3d77af Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_0.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_0.png new file mode 100644 index 0000000000..005fba4011 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_0.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_1.png new file mode 100644 index 0000000000..c5d3436457 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_2.png new file mode 100644 index 0000000000..8ad53b2259 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_3.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_3.png new file mode 100644 index 0000000000..c22aee30e1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_4.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_4.png new file mode 100644 index 0000000000..9c835a26cd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_4.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_5.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_5.png new file mode 100644 index 0000000000..a898c3154b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_5.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_6.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_6.png new file mode 100644 index 0000000000..fc96c921fb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_6.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_7.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_7.png new file mode 100644 index 0000000000..983f38ef94 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_7.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_8.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_8.png new file mode 100644 index 0000000000..b4a66362af Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_8.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_9.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_9.png new file mode 100644 index 0000000000..6d75899bc1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/shimmer/image_for_docs_9.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/absolute_positioning.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/absolute_positioning.png new file mode 100644 index 0000000000..8a1685b7e6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/absolute_positioning.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/image_for_docs.png new file mode 100644 index 0000000000..ff97283857 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/online_avatar.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/online_avatar.png new file mode 100644 index 0000000000..9c3b843bd8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/stack/online_avatar.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/text/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/text/image_for_docs.png new file mode 100644 index 0000000000..99857ad55c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/text/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/vertical_divider/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/vertical_divider/basic.png new file mode 100644 index 0000000000..9aa2d819bd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/vertical_divider/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/vertical_divider/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/vertical_divider/image_for_docs.png new file mode 100644 index 0000000000..b12bd33ba7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/vertical_divider/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/window_drag_area/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/window_drag_area/image_for_docs.png new file mode 100644 index 0000000000..5964fd0e61 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/window_drag_area/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/window_drag_area/no_frame_window.png b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/window_drag_area/no_frame_window.png new file mode 100644 index 0000000000..634cee848a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/core/golden/macos/window_drag_area/no_frame_window.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_canvas.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_canvas.py new file mode 100644 index 0000000000..1e4269b6a1 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_canvas.py @@ -0,0 +1,38 @@ +import pytest + +import flet as ft +import flet.canvas as cv +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + cv.Canvas( + width=160, + height=160, + shapes=[ + cv.Rect( + 0, + 0, + 160, + 160, + paint=ft.Paint( + color=ft.Colors.BLUE_100, + style=ft.PaintingStyle.FILL, + ), + ), + cv.Circle( + 80, + 80, + 50, + paint=ft.Paint( + color=ft.Colors.BLUE_400, + style=ft.PaintingStyle.FILL, + ), + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_column.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_column.py new file mode 100644 index 0000000000..7d99d2631b --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_column.py @@ -0,0 +1,22 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + width=220, + height=120, + spacing=12, + controls=[ + ft.Text("Daily planning", size=20, weight=ft.FontWeight.W_600), + ft.Text("Review pull requests"), + ft.Text("Ship release"), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py new file mode 100644 index 0000000000..f16da8e81d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_container.py @@ -0,0 +1,66 @@ +import pytest + +import examples.controls.core.container.nested_themes_1.main as nested_themes_1 +import examples.controls.core.container.nested_themes_2.main as nested_themes_2 +import examples.controls.core.container.size_aware.main as size_aware +import flet.testing as ftt + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": size_aware.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_size_aware(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(260, 210) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "size_aware", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": nested_themes_1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_nested_themes_1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "nested_themes_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": nested_themes_2.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_nested_themes_2(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(650, 350) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "nested_themes_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_control.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_control.py new file mode 100644 index 0000000000..170e5a6558 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_control.py @@ -0,0 +1,67 @@ +import pytest + +import flet.testing as ftt +from examples.controls.core.control.expand_loose_chat_messages import ( + main as expand_loose_chat_messages_main, +) +from examples.controls.core.control.expand_row_equal_split import ( + main as expand_row_equal_split_main, +) +from examples.controls.core.control.expand_row_proportional_1_3_1 import ( + main as expand_row_proportional_1_3_1_main, +) +from examples.controls.core.control.expand_textfield_in_row import ( + main as expand_textfield_in_row_main, +) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": expand_textfield_in_row_main.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_expand_textfield_in_row(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "expand_textfield_in_row", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": expand_row_proportional_1_3_1_main.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_expand_row_proportional_1_3_1(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "expand_row_proportional_1_3_1", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": expand_row_equal_split_main.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_expand_row_equal_split(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "expand_row_equal_split", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": expand_loose_chat_messages_main.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_expand_loose_chat_messages(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "expand_loose_chat_messages", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_grid_view.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_grid_view.py new file mode 100644 index 0000000000..9fbe602dee --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_grid_view.py @@ -0,0 +1,31 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.GridView( + width=180, + runs_count=2, + spacing=8, + controls=[ + ft.Container( + width=50, height=50, bgcolor=ft.Colors.PRIMARY, border_radius=8 + ), + ft.Container( + width=50, height=50, bgcolor=ft.Colors.SECONDARY, border_radius=8 + ), + ft.Container( + width=50, height=50, bgcolor=ft.Colors.TERTIARY, border_radius=8 + ), + ft.Container( + width=50, height=50, bgcolor=ft.Colors.ERROR, border_radius=8 + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py new file mode 100644 index 0000000000..78c4c7742e --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_hero.py @@ -0,0 +1,62 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.core.hero.basic import main as basic + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(380, 500) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + # Initial home view + flet_app_function.assert_screenshot( + "basic_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # Navigate to details view + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Open details") + ) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=700) + ) + flet_app_function.assert_screenshot( + "basic_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # Navigate back to home view + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Back") + ) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=700) + ) + flet_app_function.assert_screenshot( + "basic_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # Create GIF + flet_app_function.create_gif( + ["basic_1", "basic_2"], + "basic", + duration=1400, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_icon.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_icon.py new file mode 100644 index 0000000000..6bcb5270d8 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_icon.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PRIMARY, size=40), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_image.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_image.py new file mode 100644 index 0000000000..db126db6f2 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_image.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Image( + src="https://flet.dev/img/logo.svg", + width=100, + height=100, + ), + pump_times=3, + pump_duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_layout_control.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_layout_control.py new file mode 100644 index 0000000000..e3d199d166 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_layout_control.py @@ -0,0 +1,68 @@ +import pytest + +import flet.testing as ftt +from examples.controls.core.layout_control.flip import main as flip +from examples.controls.core.layout_control.matrix4_transform import ( + main as matrix4_transform, +) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": flip.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_flip(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(380, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "flip_initial", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + toggle_x = await flet_app_function.tester.find_by_text("Toggle X") + await flet_app_function.tester.tap(toggle_x) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "flip_after_x", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + toggle_y = await flet_app_function.tester.find_by_text("Toggle Y") + await flet_app_function.tester.tap(toggle_y) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "flip_after_y", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": matrix4_transform.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_matrix4_transform(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(780, 360) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "matrix4_transform", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_list_view.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_list_view.py new file mode 100644 index 0000000000..bbb56695c3 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_list_view.py @@ -0,0 +1,18 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(100, 300) + flet_app_function.page.update() + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ListView( + controls=[ft.Text(f"Item {i}") for i in range(1, 6)], + divider_thickness=1, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_markdown.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_markdown.py new file mode 100644 index 0000000000..7e4135c9f8 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_markdown.py @@ -0,0 +1,16 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Markdown( + value="# Welcome\n\nThis is **Markdown** rendered in Flet.", + width=260, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py new file mode 100644 index 0000000000..0e1cccbcac --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_pagelet.py @@ -0,0 +1,38 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.core.pagelet.basic.main import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Pagelet( + width=350, + height=300, + appbar=ft.AppBar(title="Pagelet AppBar", bgcolor=ft.Colors.BLUE), + content=ft.Text("Pagelet Content"), + navigation_bar=ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.ADD, label="New"), + ft.NavigationBarDestination(icon=ft.Icons.INBOX, label="Inbox"), + ], + ), + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py new file mode 100644 index 0000000000..fbd33b72ea --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_placeholder.py @@ -0,0 +1,44 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.core.placeholder.basic.main import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Placeholder( + expand=True, + color=ft.Colors.RED_500, + ), + ) + + +@pytest.mark.skip(reason="Will fix it later") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +# @pytest.mark.asyncio(loop_scope="function") +# async def test_basic(flet_app_function: ftt.FletTestApp): +# flet_app_function.page.enable_screenshots = True +# flet_app_function.resize_page(200, 200) +# flet_app_function.page.update() +# await flet_app_function.tester.pump_and_settle() +# flet_app_function.assert_screenshot( +# "basic", +# await flet_app_function.page.take_screenshot( +# pixel_ratio=flet_app_function.screenshots_pixel_ratio +# ), +# ) +# ) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py new file mode 100644 index 0000000000..f148e6b155 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_responsive_row.py @@ -0,0 +1,134 @@ +import asyncio + +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.core.responsive_row.basic.main import main as basic +from examples.controls.core.responsive_row.custom_breakpoint.main import ( + main as custom_breakpoint, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ResponsiveRow( + controls=[ + ft.Button( + f"Button {i}", + color=ft.Colors.BLUE_GREY_300, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ) + for i in range(1, 6) + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(1000, 500) + flet_app_function.page.update() + for _ in range(5): + await flet_app_function.tester.pump(100) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + delay=ft.Duration(seconds=1), + ), + ) + flet_app_function.resize_page(800, 500) + flet_app_function.page.update() + for _ in range(5): + await flet_app_function.tester.pump(100) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + delay=ft.Duration(seconds=1), + ), + ) + flet_app_function.resize_page(200, 500) + flet_app_function.page.update() + for _ in range(5): + await flet_app_function.tester.pump(100) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic_3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + delay=ft.Duration(seconds=1), + ), + ) + flet_app_function.create_gif( + ["basic_1", "basic_2", "basic_3"], + "basic", + duration=1600, + disposal=ftt.DisposalMode.BACKGROUND, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_breakpoint}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_breakpoint(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(800, 600) + flet_app_function.page.update() + await asyncio.sleep(1) + for _ in range(10): + await flet_app_function.tester.pump(100) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "custom_breakpoint_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.resize_page(650, 600) + flet_app_function.page.update() + for _ in range(10): + await flet_app_function.tester.pump(100) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "custom_breakpoint_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.resize_page(300, 600) + flet_app_function.page.update() + for _ in range(10): + await flet_app_function.tester.pump(100) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "custom_breakpoint_3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.create_gif( + ["custom_breakpoint_1", "custom_breakpoint_2", "custom_breakpoint_3"], + "custom_breakpoint", + duration=1600, + disposal=ftt.DisposalMode.BACKGROUND, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py new file mode 100644 index 0000000000..88f6717431 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_rotated_box.py @@ -0,0 +1,23 @@ +import pytest + +import flet.testing as ftt +from examples.controls.core.rotated_box.basic.main import main as basic + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_rotated_box(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(600, 500) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "rotated_box", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_row.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_row.py new file mode 100644 index 0000000000..482ef87e68 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_row.py @@ -0,0 +1,140 @@ +import pytest + +import examples.controls.core.row.alignment.main as alignment +import examples.controls.core.row.spacing.main as spacing +import examples.controls.core.row.vertical_alignment.main as vertical_alignment +import examples.controls.core.row.wrap.main as wrap +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Row( + width=445, + scroll=ft.ScrollMode.AUTO, + controls=[ + ft.Card( + shape=ft.ContinuousRectangleBorder(radius=10), + content=ft.Container( + padding=5, + border_radius=ft.BorderRadius.all(5), + bgcolor=ft.Colors.AMBER_100, + content=ft.Text(f"Control {i}"), + ), + ) + for i in range(1, 6) + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": alignment.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_alignment(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "alignment", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": vertical_alignment.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_vertical_alignment(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "vertical_alignment", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": spacing.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_spacing(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(800, 200) + flet_app_function.page.update() + await flet_app_function.tester.tap_at(ft.Offset(200, 60)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "spacing1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(300, 60)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "spacing2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(400, 60)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "spacing3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.create_gif( + ["spacing1", "spacing2", "spacing3"], + "row_spacing_adjustment", + duration=1600, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": wrap.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_wrap(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(800, 400) + flet_app_function.page.update() + await flet_app_function.tester.tap_at(ft.Offset(600, 60)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "wrap1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(500, 60)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "wrap2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(400, 60)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "wrap3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.create_gif( + ["wrap1", "wrap2", "wrap3"], + "wrap_adjustment", + duration=1600, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shader_mask.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shader_mask.py new file mode 100644 index 0000000000..68f3c6487c --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shader_mask.py @@ -0,0 +1,91 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.core.shader_mask.fade_out_image_bottom import ( + main as fade_out_image_bottom, +) +from examples.controls.core.shader_mask.linear_and_radial_gradients import ( + main as linear_gradients, +) +from examples.controls.core.shader_mask.pink_radial_glow import ( + main as pink_radial_glow, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + sm = ft.ShaderMask( + blend_mode=ft.BlendMode.MULTIPLY, + shader=ft.LinearGradient( + begin=ft.Alignment.CENTER_LEFT, + end=ft.Alignment.CENTER_RIGHT, + colors=[ft.Colors.WHITE, ft.Colors.BLACK], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFgAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDI4OP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAaAAACAwEBAAAAAAAAAAAAAAAAAQIDBAUG/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/2gAMAwEAAhADEAAAAfQIUoiI0lZIgEyATdYWOplqrazdbSZCQ2Mcm86UBIDKQyhxEkJJOVUs6tiOVKZLUr1VENBZkjrrszlxZSXpKXYVXKbWDkyMmCsi8rIks6rJorU1ZEciLYowEAOUGN1EWlMatjUrLIwLJqIkyBU0glKLJMlLEm4hKxy1uUZUmVGMxKW1YxBJwaySIYFQUiyJJlZYJW7FUSahMYiQJhBZXKamoksnCJYVyskRZJDiCFa4ouQCViVkhSEBQAMQMRDQCG6AAGSICgYsSREZDG05QHFSbqBIsiMsQxUMATAAYkSEAAg0DE1BEMTHKJK0mEkWSESycECrsEBYIAadAEJDEBTQ4AKBMBkiGKgY3GGba8+gBgmgYgOL26zid7HsoQhRkrAAEBJRFAaIYCkgGAQjLaRkgx0qr8maa8ewYFAAmmQfOpy16PNbtTuJq1DESYqTSJ5bC2uWWtxUovM0l0EKYuM1sthjjXSMCOhGEcalbmjZrKI6zFxrmtV3L1XNMNOfGuVrhLee6VTJIiSSYQra5dXEVdVc6yIVaq9FpxQrbDP1Izx1Y8qsnVLeZK62x9zg6sb28Lq82Z6FtqlreiKZ7cHRsinDn25m7Fr6YqavucupwqEuLOzq28es2WOa02cws2WcydmnocnZLo59al2U2wXNLZWzGvbPO8l8cOs+gUudjpsS5U67MuO3p5r09C9auizh2yuNvTj1Dn5GetxejjadWsrmX2Z7Kc9V3TOystzca2VmareGLd0Ofnpqz2ZZOi+J07jdTfHnvkor6r7svfy4i1W24Y9CUYNc6pp1Y1rO2NavOvHqq3LQuzWMlr25bZckutJOBZabmTS5RTpqRsogwWuqaonZXc98c+HTg035uubu/wCe9Jz3yaZ4tTU8ctTRbxdQK/DZqjToDNdVrLvzktjy2k/U+S7mbtdj5a5+fdXpks0Nay5RlsclvfI0Y6bEtDMWK5Kbgy6Y3xlydDn289bM/XnlWqnWYUO3eVLo1YuSvZC2NVsap6WHuZt0LFz1N0yiutwNDxzXUUNJVBXB0YdvSd+/Pfw6WPMXNpVLNlbRfLVmvx27bYWSw4nchvn5g9LV052apx56UZKKed0Odd09fj9xJw0wjk815+3PZzLtlnOc1dbcve5eGMNG+fPu3US79PAuzruPj6c62106VeG7fc1Yd+Pn06NufTnUXXO5kq1c6ojqFehFHK63JWnt8Lu2X13rLynS2Q65x2akc27SRTg7ovFr6dmp5yPpBOZh9PA8vb2BON3+Zoahk0yYpr1543a+D1p03FOXLoVuyW2PNyb5d089Be9y+bRb0u15P1kuqvQueueuRZ2x14czSumFaLlXWW2rLG15bix0BoKBZW0OTVmEsKtUk4supg0z2J2azJ1MXl09ejWfP6OhHecNXWlN8L1mLpY1rhVn53kOK9HPXoo7uLk5Hqs8vCqxU9cdOuquJ9jlSO6+DDnv0dXK7MuaxmRDVTVdV8qz3aIxCYgRMpybMjdMZWutU8OvXGuOm24y6TTnX//EACsQAAICAgEDAwMFAQEBAAAAAAECAAMREhMEISIQFDEgIzAyM0BBQlAkQ//aAAgBAQABBQL8eZmZmZn0zM/QJ3/4uPyj11ms0mk0msx+cfycTH8MfH5czMz6Z9M/jx+HMzM/VmZmZn8uPTEA/FiYmPxYmJiY+jExMTExMeg/42Zn6c/VmZ/n4/5Qg7n+Zj8P9/8AEyZk7/zcTH1dUurdPV/6sfix/Ab9K53/AAGsGaAP/Kc4VHzb9ZcLGYKjWitFcN/DyZk5yfptJmfD67LjlLyoN+06fqc2fjVw31f5nbEH0HBjYCepzlXOtZyI/wA64BTVaQFf6zFazC2bRjiU9mNiqeQTmXHKsz250IF6scyzqFSDq0x7pInVI7FxNSzW5Fa3qYLA05lnKGAYYG284xLa/AB4A+VKgemRAVPoG+8YEOQezMCScB9rLTWwi0OZwGNVYpzkEY9HBdOKyBGwK2EHk/8Adp+wiszLTZDUxgpnDiBvPVs2Z0Y/buYrP7Z1D7wXPxi0a1dRWE5qYOoonuKo1p1r6goG6oseXltbKTbLG9xBdZA7stQZBzVkPe2/Kk2VV+GyCNssOpyXJ06c63i0TmE5IbRNtZzLh/IMcJblo76xUe48AKtVicTmWqqyrp+Wy/p+EpVsq96tatfEQMI/mdVjeUo6cMlxXktfxSsiWbBwuUC5i17RfFntVlrqZxYfFVxMbQkLC/uKOe3J2eawYxYoK8W0urdZWNUM2l7Xmxqeay4WSyg609Ui1vxiOfvbcg3r2Vgq8qw9QCB1TtWC5lyEsQdO+FUmpKmArrLMxWm/qLeSYYPbnWm/w3BlhZp3gOiqdgFbG9ksaJeOWyzNFfVc093m+xbMcTwC2FbGFvlPbkT9wJmtKeNEdA3UNW2iUWOfbWCFC4Fao4uUqDsuhNmVQSjBbqk8tu+xnK8SotUFbi4mnD2NO0WoKdpygln2gWEMwLOkBPJ7y9ou6RLr1TktxZY3KL9gh79yx2ZFGIxBjOK3qs3Y1tdb7VAnHkPikc7FtjYNQo6evWdSmaiMzvuB9ytNa8alQCAsUDdxgn4CCY1bZslmjs2dvt1JqOxOZjMOohpvz6Y1OQYNg88ZXfxj3LsdtozuszOxgrlHaq4ZrFDZ49WAG2va1VS09p8AfAxCMen9CYUqPjC8u5hyDtkK01INP7K0Zntxr1Kmp5mbDY4nYHsIRsOBwOOwggltXUU96rMhLPNwpiB9sd+r/d88YbAXMfIlVFjK3SOqMmkV+QnpHh+2u9YauwI3K+cnUKDK99k6uoVrYpTkXjsCvDSplaq1RUBNF20GSoICzxMC5hXy0UwZClvE/OqmcaCZbcgWSorYzu+1am2XKofuWOcN92KsstdGLaqpVziHtMzpgSyq6g1dx8d43Zj3gbw28f8AWfIsCpbx5chbMwZL6z4h/T6H4DGMe+wthptio5QgxsY0B9E6Zyj0WG21HcYxD6ENimrCYsn3ItShONONwFgbMAXTx17Z7ZIGr7hP7R2EVtpmArhgMH5h+BrG7GmsVEfAmAR1grLNjkb9FB+x/wDTvpZhQyAivvD+3UdenLDJZIth05H1dsjdRAy8LWIRyqXz5GwYsf7IOJWRjsoEZdlwQdCH74OZrCNZ09JSzMWHONE30rzxVNPgdi2E1dAZYpgCTCYowKYUUzmBrp6h+TqLCZysoNu6e5Co1LGurydam2rqzAAFysfU0oNa9jg2ZQJi0XdmbZVtuWK/InS3WW3RZ/WSIW7hgT3M78hP2upPj/iuHvVXt7fLZewKQ7WVi0VPY5ulfTVLHNcRQ7P2PZYGVzXxx+Blsqr3KGsGxlHuWMS2t5Vnd30HLVN69vEJRw1WBuy49CJ2yFGZ/vbxdtYx7ByYWOvT/swmDpnEqTC+zqmErKJS8RVw4t2bEVUnsspd0r1yhMPxFpo0AJfTAVLFAq3D0lQWO4uaVFVse9NOnbNcPed9gTj+sgOR9u4FlfICjsxBFPnQQ0Y2CbwMuORYXGW43ipSk3SeJjdPXYRXqoRzFrcTylndfbbS2rFGrJGzxp+oVLlkVYGpyrVk19Sig9Z0/GnWbluoAWy0JOfvdatpDvPcvs91hgaxivID0n7GPRlwhAATAlhQwK2CSrHMzFGPQJNCJnE2m5mxh7sNRO2AnnwtuK8wJ3UOjDptgKLa1tVyLHdr7XPMWrFdtgYva1Vd5Zq0FjEpZv0lRWjQ5IsnvH1HVq891Sq89ML8g5K1A6lNm6hK6ww41ussjMKyAWU9vozMmbTtnt6a4Pt7d06ew2PR1BsrrvD47Fc18a7pUnIaqiQPNKX3arkbdK1N1aovV+MAyRQItBdCjIjZe0KiyzR0W2tK+dVhuBlUDoR2M1i16hqvML21GCMDXsDlihzp2APriBe1uwcWWie5DM/UprvvVZaa3FqivjRm4VZZ+mVdS9kUdisIEdcFlGy0LqgUtVOZxYy5PLZXK+qsLIdlRthnvjsxwEbYRPg/OPQfEH6bmKirDV2Iod6gTV4VP+57anNaicaT/8QAIxEAAwACAgICAwEBAAAAAAAAAAERAhASISAxMEEDQFETYP/aAAgBAwEBPwHxpS/DBahCEIT5qUpfKHEn6C/4mE0l+jdYmfhwZwepr2XU1CJDjILoy7OLI93XZfCiaJUNTXR6MMkvZln0ViVOA9cWcGcHuEE3iZZX2SkKLveHRl+TJ9b71WTx4vwxGUTdGnSMYp9nQtQiOtU611uPTEoQgl/R8Sl1TkJl0tsZx+BYv+jUOS+xM5nJH0Ncu6fwb+RkRxOOmjtHJlG0j/XEWY/yCd1V8cLp4Yv2hYT0cPswxH1pb71dQnjh77MsEkmZYtb/AP/EACMRAAMAAgICAgIDAAAAAAAAAAABERASAiAhMQNAMEETIoH/2gAIAQIBAT8B6whCfjpSiZS9X0pekIQmJ0psX6c+svpov0aX8VLhsXSE7L11hGcjh66bG2LnUhTyNlbLCnJM4+DYr6eDwzVezVYhB8WevZSl8ntDRx40XEeFSCaN0brNKWiQ0X+2OThSj8i4LCIiIaRsUuPRsij94+QRBpCaG4IeOeKUrxqLFZTiJqYSHyX7y2XEIQSOS8dVjjyh/IexLDxBKHgTJho1EvMH48QROqHinnOxsbFzqPiavC4M0YuByUxGRkZq13omf7hcjY2Pk5eBJkGxMSRUPyajLm9f1n//xAA5EAACAgECBAUCBAMHBQEAAAAAAQIRIRIxEEFRYQMiMnGBE5EgMEKhM7HBQFJicoKS0QQjUGCAov/aAAgBAQAGPwL/AOcn/wCl4r5ZlY/8LqSzaJdFJr+1sab5flOr3/tjT7fkZGxPdsr5/smWqMfhxDfmXWev5GnRsSS8NdRPRXyKCju+v5mPxP8AIyVy/BnV9x2+ZLs+F6bG8ZEqsUtvycpP5NnwZTOf2MX9jn9jYlk34dey41TR1PMx0bMwbnU2rJh1Fs3N5fcxq+56pfczKX3KTNnw3RiSfCUTmXLTp7M7FxE2Uny3KfiGPE2PU/uy68q7mEdcdDYpQ+x6JfYapnpF6l8iJ+xUH5vcW1ivkNcjGr/cfTrB6Me/FU3tfDTpex6Wf4vc80WS1SrLwes1fUf2P4rE/pyr/MV9OT92fw6IxvHdH6TJLuYslGc6JOU1XYUtTaY3CkheaOR14q1DcpX7CdopbFfBszVTa50emRhHpkbM+pfPcvNFGwstYoVdDXorFblv1csi0v3N0eo0qS2vY9SyXrieaOeh6cnQ5ip7dj+L/wDkr9y2/LySFHw4+7iKOrKwWkqjuaKfUlOtmZ2MZQ6j8UTehKqWwtVRjv3Yo3iiopHP2M4J8mu5Zbvi0UmzU3aEuK0v4THKe7/Yh4aSpfqQndtFPTHtQ68TaWxNvzeFpKXLZEl4l7fubxMToq0JVFLsym1vmhKCPM89Ry3fVjT5uz1mZYKVaf3NKjgjKLfyM06qn1kXY2tQty5sTRGa0/6jKi+rMK11JyzSRcdnlFQVOryfSq3dWV/Iv+o/KvuehEtUfTub/ubp43N+Q5TTv9JOq7myHKMVXuZ0f7iKVKsFN5Q3WeZf06XuaXEq6Nxu7QplLhpTPEdGi/LuYkbmWYNyrX3KU4+x+mXydIkfopxwKd5u7HDVdmZ4KX7i1cjV13j1LlGn0oWCtOCsdjO73NMdyLVql9xx8V78y4j1vPXoQuOP1dRJ6/Ej2G9NYG5Fv/qYknq16nuY4aD6bZpHHpwae5TMbcUcmXbLj+xT2Le/txyJsx4epdb4/qMRkbP7Hokfw5WUoSKql3P0u+9HNd7Mvh6SI0adcdXueq/Yt8N8y4ZP6mDPHmVzMFcuFFi1LJb9RD2HrjG+x6VqI6VyyblWYljqYbzvYquhV8ldTdMzCx6o0zEnsIbo1O4nqF8cPDvoeZvfBcm98ZMtrHUwbU+5etNmfEgiPhRjT62W5L7DzqLetuiTit1zQ7UpXufItGps81qPZEVKTtLoNqd4+w3rxe43vSIY3Neiuwpad+QsFUPHMePY34JvhpXQXtvwzEtCT2yRk+aJrQkonpqleDD0rmxKDbrLsdzde5Wp+1kcUlg8qH4ctWO4tSaswiqNmelkq8uBR1R0rsemJ6aPTkbrkeG+5qE63KoofZk+w0zBT4P2F+GJKHhrS+fc2vFGzo+KG3Xpo7cFONMcpR8zIKUX5UbcNn9iqe/QuEjdGw0pt3vkrU9PWx1mOkjiqeD1LSLOORvk7mOuSeFVcMMS4ZMHqvjuRG7u+PpEuaG0/L0Fpfms8IeSy9JHB4nYUja/YlfJW2LKVrmO9KdYo/Qp38Ela1aTw7mrNH1FZHz7UakxvNV0KWck8cuCshJNcLXSv3Plmrt+CKG5c+HwbciVpD8q2IrTuiJsXRmTFU2SpvuKWk2pcMxJVqWOaM6pLojmsczfBexWi++oV71Y7k9tjMaW5LW+yLsqzFSbWyK6f8HfSbYaHP8AT0Fdry2NR32Fz3PCm+aJX6Tfh8Et8IftexHv2IjdcI11Iex4vuRSTs8vq7ksYoppv2FG8D6it0u5JPxVP4ZpjtuUo5Pgb+nbQ/KjMX9zLSaLh4lrsiTV74ZGN7mhrAo01SMTbjextdl6Xd9DS6TyQUdh6Z5FTKPjqPPI3e1bHh+b0kMDWRO/uW6F/Qn0WBSs7j4ZbKl/Qw2/9RpjFXzHr8FIvwIQdCen3HCS+xpjGlnfcc4ukZZuSdOJZbwYYpRjfsScpSl/g6EWoyXZ8NC2ReWzbK5Ii+dbHxROuhz9J4eWn0E2tjPMUU1YtPUh7E4trLfMUbQ1dZ3JNNPFJCrw9WDY2RsJ0ZRiNcN6LcmUpJ92ZcdxenDOY3oyb+6NKhm+QqlpUuVFc+pnLo2yPG46Hi8iTTXwavqJ/wAyc4+H6e54cpWtQ8eYja2LTkmeXxP6mmX8jGfgX/BvsP34cxvWJt53PMldiWN+CTW5sbD4czc3ZiuG5ubGP5FuWaLdNEvJXwf9t8x203XIctFktPh1q6shHT6N6ISqUIrcX9x9Ua3a9io+k8PRXp6EJc+dGrU8SQ4vGeZLwvErfkNp8qFT5FPwMf5jTOMoLqOOX3IvVfuqJedaK+wk78pm/k1abyKelW1sYqKv5G6k3/mFLqJdfwb8brh6haaT7Ik3K7NU6VbUX9S0eZeTnk9f3JLqRjOGHZbhsv1CtXmsbEpwiljSkxOVKs0up5o4W2S3hWOetUuh5lLVzrhFGY8yPd9RVd86RfnLUzS5Ut8IUcSrqOo7myL1xkueDGTauDNRnhYqymOPNEcG5v8AhpPkeZ32NLgitImlzyOMpN3tgfhyadlx/u1TI3vWeFnmUTwzdmwxEnk9KwdPMMjl/cxNmaYzI+Pxw8P8baEmkJJbo55HRsvT/UvRklzyelH/xAAoEAEAAgICAQQCAgMBAQAAAAABABEhMUFRYRAgcYGRsaHBMNHhQPD/2gAIAQEAAT8h91y5cuX7gX6l+u0yamovpfqewxBJftuXLly5cuXLly5cv2B6BmFPRcyvRm/S5cJcX11KetafKML6lSvZXpUplSpXoejiJK9nHqHpiPpcv2PqxJSUlEr1PeS/ZUdMwB4m5iX7rly5cuPoMX6L9F+y/bUFKqX6XLjBl+oRfvX079L9M+8IQHtDElSpUAuVfsFf4K9oBKlSkp6KenD0wPS5cuLfs4lZgY9X/FUqV6V/kCLLl+i/Ql5l/wCYv1qV/lqHoPUnLKle2v8AFcv/AMYzG2Co/wDmIvsq5h73UJeUfWvbX/juX7r9EDBPVEvfwG/TPo36npf/AIa9Lgewr0qeOJYAaFfMzbrH4lu4y4vsv0C409b9p/gvgU+JVYAEuWy/bqWa2/LLYQ5bl/4cdS/SvSvdUr231FyuCYg9p6cwxuOH4xmNMU4CLAu6/D3VK9L/AMNYWNnFQt/gI2dfMGz2UQQtVtQdrauncL537TJ6MdWXcpRNs/8AJomFQpsf8ZaLjKcPcwpj2XMN6mN+yjQ/iaJw/fsHEXzF6uqgy0PKS8TGgX5GWSBptla4rzf/ACYCWQS/c4nEVO5ljK4gNPwQAC1bNzjH9wxZfghzybCU+gmtrN8QBYJ3z8SilPmYGz8wCsu6hdWI+ZhXOIYy2lqCUBRupvGqwQ8IrMwAlHUwAYgdooUtM5OI/d8MrRaDEU5EKP7MouhmFa/KlZhrmlqEPpS3PBBuvPLEi0A7YL+IZdx3Co1LrggWK6JByChwQ/Y1hsmjBmXVYLAibRryx1wG2WXOKfEg5uGUePEyFVviUTLyeUbaVV5gynnDGTIRsCfESGnwsLkCuYyBKroukwvhAWaUy3AzRyzFACliiYmngdotKXLBhUlmo4YRB1Y2TzboiHMcDkmudO6J5C9ypb8GZwGkc8q4zbKIm1eMwXWjZWZdRZd5g5/wsxQKHSLxEAC/Fi80+BARVs2vEc6nbnmbIhipzKFKmM3EI00NotxwwF1wiABOskL8oZQHOL3HOW0LBqAdrbK4I5uJ2nBZaZmTAm4QBUlDgGjEVXJ4mbh5vcqF4u6gBx/JCmjrf9oOa3ZFJmhpwxaLODWbgtbOlQkwt2CYP8yLPXdI0k2b9y9gPuM9t0je5qayNvxKy8a6BlTRvhuYwOGhzGpXlYZ8U/ctVg/UYxAV32gVXc6tMjiX0qHL2JgjUCRT6E7iHT+Z3oCICLF03cAA4iqjWcdtRHyHPEWCLeFaaU8FivMBOCAVAsF0QQEEXtQOUu1FPOWVs1qN2UZsuMkfGPGIPnWHLg+IOEx4uVQL+J2A4qZc00Z1PDhKbiaaLqIr4TUuEkaBD9ZjmDAVKKOyLT9QANDixxEiA/Mgr3IBxnEEt1QFybStRkAC8MqqrO8MSWfllNUxqlBn7JTXEe9TLqasVQrRd36lJQ6EQH8IRyt08RZkN3n6TfDi3C70OVRDQ2dw74uq6rgZrS8vFzacvXE+B3iLlzweJtR9TlIFDQgI2DoxBclgvpAFBnY3KHUAO9xXR84ls5DcKp7TvQa+SwzwqagJkR1BUj3ckD0UHMN0thAoEDQcSHOrMjfmOaoOHmpoaecxufl1jgAVnIliwNmrljDu6sjXdKre5Sq3nFv4jhoGFvUcCisEzFXAMfcG/jARRQH7jdQDcRDAlG7ZR/cpzkcJpKalnK3lirBLUtcLL1kIaFg08LTA68dH/UHdpZjSobWrAq42hsL3DoeCD94CZgYLNquNXKXcV5HwY4Z6NmIa49S1TTOhlg5rlxFpFdsSotNz7ZkQvh8E4Z2IRZQNviUGXA9BBJfXNb+hzCg1dD6S+KLQ4/MpvDlZ+I1MvjjcKJQ4q4Yoi2hjUcsSkX8RMDHmVsZ1dRhFvQ1Kfxt+5vtqqZQMDoJgOx1mCWFum4RdlnUyXESAMviYTkM2kzsqqupfNQ8cZcWgV/c2FfmEsNUSniI0Eagy4O5fUWNKvMBriG5pIvjUcW18QIcfUXZVv1Btb5EfEq3WJhSToMz7YXChrRthmN+7tibK/EMLf5ThuOfmIRvUVWYzWxLqt12vaLqWrlgsMaCOGmyYM4zHsHzCtgarSKx2cVzEFijzFy4zcFbZZRu8axUyP+cAMpXUa2Rv80SzB2DcWAvZdOJagc0EGthGnV6dS319zKi4dobvjVDIrzFQwjtW44GXl4TxElYaG0wAwHwPiJcMGb4YuabrbuGxHEFqOGOUg+I1RW6fNxBV1f5uAIhKZ7llia/uV4FOnzNGuS96lALXTfzxAZxC38yxs7WdxZ/eBar7GZyN4MsTg4YGE5h+JeU9ygb5BFy+0WAN9m0a5I5hIF35CqlCKNAOZxqEyZhoMZdMqArRoREQLmgha2Q4moxSNFmNhVh8C15nDNtf1EFm0DJ3+CIBo7b1PDa3ctKlVPiZr0plbIpbLlIg7iLJGugL1+Y1SX/smyzmIsGuooMCOuGUCF8ms4jxGtDxH4o3fn/ksTyHio7oC0JRYFn7S2FJuozsCocABy7lKNTdDebliJwTKWjjGIpVfLKraKbUdhE3X3VLmrKLRmExMFMMtMmZsaYWeZpeFjEdzTmfmLAKu1QLUxHB+EuK1Nrd3qFtNVcy5pGZQkfJB183CuXHKRiTGf6nygoGN/3FeE064zFz91HTkqbv6iEsMrp1LlCl/iDfKggV43+0lBbDaB+5abHNuOJU4LHxDqAChp3zMho/Mp0nOYpVyqQSMY1uGmx9Ttn8Q6sPCmH5LjAXTO1EzKNN9kXy/X/YSiG16jkXt5LgFy3aJXcciBoeTxEzaHaKAPgIZafKXVeGnMCDlLrmXSTzF8mO4t7dOf8A75gqv9zYc0v1Nu1j+YOvwKnE5olrk1DTNQXXZfuLAtupfxp/caHauIDTLmWVLjH5AX1BCWn/ALLHZzjOpdNBb6lXmzGjBSC9270RZVXcyNn0tw+VwjH1C2coIUQxFl38zo5DmEq3AdRKKrDmC43sfiAwL6nOIiJosqmFaNwKhXmGIiNqV1MzOR1PwhmOOgKfuWCqv4iN2h/KWq1X+moX6qw35uYfSKyeX+psZMLvzMyxRCeysUwVZXXOYPjbXzAM19Liq8fiNWOFiXaJmvqCjDDHFThlhsDipRFT5ijE13HKwO0RMqziEdZF1GmxDzG7BxBEUKYt+IXOjaZ+oAVdTyiJdr/iUFmmNypudc0M0OF4XMxaKWzHlZDTqNpMILzLfWbKIUFxecyyuRIYIqVx3Ad9KwcXFsbbPmUwuG0EqJk/MdqZcJj9igc/MbackIchx1MJrxslLrGn9y6trwjulRBoSQZAs4irBVG5RRhxTKAIj0k4M8r+JfJ5R4OnPWyN4AKqNWNcOkwSail5YGS1sTkg5rcAaw1RmXCsS0TjjHDESpp8RnioSc0umiaq6/pFFR0JjMxrmosVOcbRkuTECSpmrKOpjqeAwUYbZlgAgr6leWMFgrLQF8kG1qhFBkjGjN9CfAuHBvAkriW2Pcszt+ZkEZq7+4X4zbFMXOem8qzEuaOZi7B4A8xxob5l4CK3mfKekxdjuXJiqix4LbVCod+CFrttGzZqZNH3Lot6sNQ6ZS3LFzeQuA8HLsvzEdlvAy2aLFYzFgGexiJ3lpeUomCBMMoXD6r1MrcXV1KVWD4lVScDbcy7KaxMhhzWYXMyuLY4N9r/AOzCtFcYQGWLaArzMPbTKFFX/UoWjzOC3XZFxfZchcpCk5wLndITEYBjvmZ3aZpf5hlJnLdSNtmNQVBD3UvhrKnxKM9TzMaDUgHWBxmYo70oQL9EQxwaC2+ZWqVLjdcAY6cL+oFFbJ/d6YK/ZL1fglwpHh5jsqc0RUtUrK3Cr+YHEx/0JkioYa/iB2pzRiUfIbyoilhQwV57hFyAKFzKiPiLzM7exc3GO1GYQzk3hxMgbcCVRU5zqEVYcBBUQHnJhUdGrqD1T8OYq67fDuUCn8Qez8/2iKQqskZ+g74wap2Rati2Bjtr55iHgeZVf6MAHQv5mVkMuCO7cMvXcLIHOnipQVn8Rol6YlOWv1PihPHZeWb4PzcW0DtORhAJuqJTJfMs5PxLoFajVVK1P95ZrjH7ocQu9U5SKSq3dbmUDw2fU8+bMniBnDW83+YPGFkOHtKK2GY0NIXh+YcEXdo/JCY2NA7/AHLBryUyxFpvKAMONqCYQBXcMWppliaUEmwItfiDAWKNm2bC8CM/H4MLTLmssCdN20jUAVccu5edoK7jMtarCyMRZfZXMfYrhbf3NvxihcLdb6SgAAvcbvuVVmZuq9P3LcTi/wCTDj+ZayNV3L7p9Q8fzjjaHYdTAOrnbDjW7suAh8nj6huoWKbQJS0UhlXPEOGAMeMTBgswNsZAxYa/DiIGYyH8y2dykSBg4EZYu2l4ALpZYNPCK0MaSBSYX8xQjXwgs8tNupRw9DN0XbQTEBX7hW9GChNfl/UvIAywYlfyt7mOAGAaQ8umtQz0+l4lNA1KJnLeczBGK4OYSCwzQ08JzLzaupZXAbGAOOEcdzcm3RBaU8XOR/C5XwyvD9Sst+0yzN6lmme01CHmowC978RTkKaeLlDhVSleSFYc7vN/Ez84xlN9xe1MWW8vpdgbGy5YWs8FdwNHf6lzo+4/hl6gHLoXH3FF3D2LqG44trVm5ndBSmCJK9tZ8S2N/FaSh/PzBg/or9RVNRAwjTVK56i3H8xjuisKhtgv5H9QFpSLRFh6Z28v7m55AzLhQQFgOsC57KYQfDuUQrYOSBsflcqBw7wgf//aAAwDAQACAAMAAAAQpuNOOc8YIN1obd0oFzHus46+jykIkyEq77ew4jjlp9TVUlI3sIwJxLLXRxs/VXhxCIXkZp/QJSXDAQAGa4ADFAiiCX+iBAAIQEEJhQiQ9qFWpWJrALewSIIT26eGzr/4Jg17b46w0VZTtjfAAw3oAxwvnydMKBoETlc/N39GFLkgPPsVr+SMJOklGkCkgqQaVRpCuOVII3LmU/AAOcG+55vNrJfN6D/7gjBEr4ydN0dQ10a+i7S1cHoGFYPwIq6f7JVTBXaUQW8TLLNBu1fPZkpCFjsTii6q+uhG6x4P6Gp4kwrL6MLccPZrGhDgn80FDDfjYEESx8oXUDENrqUgQ3FpS9z5tMPnWth4afqSF//EACARAAMAAwADAAMBAAAAAAAAAAABERAhMSBBUTBhcYH/2gAIAQMBAT8QeH5hDwxDy01iGNRll+JRPwlIiEyYZYbZXii2WIaZ2VlZSjeYQhMQilKXFRcUv4Jis2LCH+Glyioe/B7INTEN+MyouCdezRMNCk3i3FG14LB4V2NTTXhdF8INTCVJBdyqOzoQkvZK9GgaN4p4TQ39C2MRCRlGQYI20KfBoEtiaFDfgVjThYNGIPYmdEPVX2RCpHX0cv6FrUsOaLY2S4TxCWsf6B0Ns6oQuiVvRoEf0hNwKEMIhdbImh70hIwtD1BV1lf0WC16IJMjb2NQ010Tp+zcZpxFtUjRG4aE7hr0oEGTIJPeBIJbIaHbjGlYQJJcGuMg6x1OjXo3gr2UQdQpzDRwTvo06iIbxsxpdISP8L6h8i6wWNaLisbbehvYi2JY9ieQ/ZOQgCzZlBsRrE4awoJL0SbG/ol0JRJBwa9ibE+iZ1HyIayzi6LehHwXxhBV6Kl0qfC+kf3MWJRsuDacK2igCtBwE3RsmTN+ifQqnfAYkFhkEknsYW6E2J0//8QAHhEBAQEAAwEBAQEBAAAAAAAAAQARECExQSBRMGH/2gAIAQIBAT8Qjgk/IZnJwcvIcP8ACbzmwwuyI/ZKUmHDONyc+S7tHBlhYWfjeFttbudZIN4ZkwPG2WfnOd46jCXZm8Wf55L8sY5YZwHeNtOGONttnY3IW226M68sjrjIMnleGOMjJD5xnCljPf438idWWvzQ+xe40Zy28te7bPY6XbyQO4BCjVYl0uSr+c7GpPhlo9hhM7Qh033qZvwkmEHiG3rh/Cz6ZO9ki7gJAd2u+wF3UfnH/wClgRmWZ3K+Ww7s1vSA7Y+HCDq6Fu/vAsdh2v8AZ+BOHlkswM2RdMYOogD5fQjySJdzY15AO5B1D6l9gvlnyCeXkILbwKvTaJJPdhKfZPjdANohCMhgj5wedMP6yN44ak2AmGbw92f1vO7DaO7Hpb6g2Ddj0cG76LQbaPd0J7fJS1egbth6mO8IxdWEDAkHuPRwt6t+pdjryF7KbVmccnt7YxqNgSBuXb84CEv9mHDxQ3y+gkXvLqyyxsnEH9t7yID7wYYwSZJ3fBvJSQayXyWMOCSWYQ7xp95N2EW6iid243//xAAoEAEAAwACAgEDBQEBAQEAAAABABEhMUFRYXEQgZEgobHB0eHw8TD/2gAIAQEAAT8QeJ3GPM7/AFAamP0dsQq/U3BsuDn0L0Mi0CVkvuC8RbhBtzv6ckqLWo7huMLsePouZ9HL6Mfr/PpGpdS7gRO4HUNBATfEQG7iNiabYBXModwrUQrnZjJpmuYo4IqVLHUtuUYpKRTw1EuyWiviB20X4lpTKfEp8Mt4lMFDxS/cMw+gPMBzHYs7+hMjG64gKHSy5VOrMg8wAlQDxBCGvouWQSIYoRR8RiJA9Sx6nxQIrIg6JR4lEBATxKgEKJkIoWmRfUammHK0zkjtm6BbM1MSkNlR+lw9vpPpp8wPM+ctI9/o+f0bJcuDU+ENgSpUFXDGPEXtgWKVEVzEVFdhy5MQ8Yz5/oDcv3FlwZUlSDzFMWst8y0bT6NlstgsuFsRlHMvm+IBdwQOCCVK1uwHiOqlZ8ZSLzEizyy/mX8y0Gdypspq/rQShlUiPptLyjPpD3DwS7qV8T1QBMLua4QEFD6lZ0oNRb+npA0uGZ8so8RC4KlSpRLi39aIcTX1KZyuUR+gvmXL+lsGm4eURFmwSbmYWhqXFRDAjWw6Y1OJd6ir9LYuQhzCqlHiUeJUGj9C7szyxrqMOf8A8LYiv0D6AePrylH34wY/RV/RVS39VP0FcYu4fpePoc/rOfpU4Fc5fiIK1ULefcFZ/wDoOfS36PH1JcuL6F3KPMCoNSg8xTx9K+obFDHuYe8R37zS/MqUxofQ5nMq/oP0V7lwW5cX9PU36cbBYIyLlr9OpcOZhmr6lGaJVBXfG8QADbAuuW2fMpT3KpdTfEVLrJX0wyyIly5cv6V+irlSpUuVA2EUBRymQCF8wFciiWJWfRkQy6VV/aX1QBLd0/ajJc0oW91aFxfAOJRq+SfCIldS2HMWpT6ILsiC1lkuVhT3ErxLlxSyWS5kuckGuY21sV5OwVAIDr3BHGRbuXqXLnfMr3LsJqkoC7rp/wC5ifxCTK9v4nAax4PEd+tEMbi20RK+iUqGxVURC58mUQp3KAle4EqBfbPkzT3KlQ98Sjoi2WlcId+4qS3bWK11FZvP6HicCXko0VQUOLYoDQW6maElMt9x9bGhOPD5uVWPM7lSiVKXEdR5lmbDj9FMqBsVxKPMAKPmu4fBehjOZCOap+KNm0dcypRA3JgwKo7f8miYLAoDh7JQYrsePrT4fxOtjA/DOyNYORVb+0VqNgurRt/CGbQLSC3fZLAQqC0V4qVWeJ39b+j6lSvpthrjJfoO25Uo8fQ5+n7c/mGbQhdrEWAS2wu4sKisQy3YgH0C2FOWu4FUgYKwxNO77lwbr8fMHfQoFCWNIMls3w/0VQsPYRKIniLKzSoURsp0bXXuEIJXCvXIN1VsjApePLKrPEqV9KiBcKShnuLRjPEEU6wgP4jYDe+o/M6qCx2XCW2LKhKrDyX8RtAStWOoi4ZAUFkM84eZsM8pYCllW5SxYt+6KOhLGShtlvOCpuFkFLMHmaCzddZa1RyCUDLp9F97n3jN5qiw+8EEJNOcrssneFrU0iJWi/Ko5ZveBX7yqiL0JTv5iowbUVrXmcPlaHCBzdwvhaoEaruMxeOLX8bEBoOa4H8zW4HR/nmPLxOf3uZT00N57d8QImYav95pgNKh/sA0EFwURMptRq/mOkA5Qoh1L8hHVQQHa1KtFniodOlSqX6HggksFdlRtEy0cxniqG/MFjSyR9f75l9FyrSAjU0020c+IOWA8oliRn0Lh5qv3lkBaKVVfzxFUNq3AnYgZMrQHMGOlKrb+IBgvlLZOilpW/MRq6db5gpZy903hKIWiA5a5ESURdV3kHPtWoA+YDhMDTCuvJSLbxUoUktA13b6jRLTalPtkbS9AiAt1yDl96LD5yASIDW9kdqPYJ6lfzWWWhT9r/ePM3JRs/h/9U0BeU0mxeA4/hl42vgEl3Hh5A2LHR4nGkwefcDd9h4jxRHFKVGGvzKdovSsCJuRrPP19mUAngL580w1plt0bz1D8TsqjfmHCRsNodQgE2VX/H1HbsEDBVXNEVcSosrr3UqlCmowA1x3+Jm8oehvMxYgo0b+YwC6p5IFVXTFOIoE2L1xLSbXkHoltizjeSoOgcRM+CFabM3+S5syc4n9QSHoO38xKHFewDwQKidEwxbYnC6t6JuxeiIM1LmLwsQKA1BbXhVdkLYcab/9cI4I2PJpGpUAK6JalJSd2o3nxX3lDUWYbbrBAAJ0Nt3ZfrPvFCIZyFdiQUwaRivImTX9FpnU1dQtaPiUr4SQMr8th0XjuD1AZ5I0RFJBpAAfN/MombSug97LVDZSmHwWOpSD0qDviCZFyB5bUQYDdKtV+P2hvS00kA9DzKAIAGi5XvdhzrVzkPdY0F/MyG6aLvRNbB1ynorOKd9xnDkAPgf+QngCQW3+IjYpLGd+0QKRXOnqslH7NPZ4vmOlNivO11tJUe0Dgh5O4FAtCW7L7zmJcICeqiNnGTrTz6l2FwHR4MlYLiUNCcE5wfR081FC0OBCMr8RCjoWLCbn4EClpYICjRAhhKQCW11BrC6jp845GKYCF/GUu8S9qwhwA8w6Nt8SsCJZBG+3viJO2Wq2lPIywjCwXRr35lBpXdAeXZzHDaAfKKHMQWgIbplV87Mz8QKgOnYwY3QoDxhsuQgBFCt7xW9S8uV2B/7MdQu0Hzj5llNeGD+0q5mii543j7TDFQUUvij1kQqqKNq8csbaGwuUceoGHtFHgynL9ottSq4Ky/cVfK+HL+ZXwAgUUmQ7sP5LHT4iZSfLUuz42U4MuFrivRKAAdE9OTINbfQWdi/bIRmVS2KeZacJRpX7GURFSFqb8ZB6QeK3p+IL5tbtOPUspYhYDQo93ABxHC9tHxEDuo1huKCBWvas33HDNRdD231A7Uk50NIVowDLFCwH+YoAKJ2sSEsRAuzbNlm10Rj+4XMBaVev3goag3vw3/U6oxEcOxgOWAu7bxMcJfNYRUGzx/cJ1obzd6yVcqz45D94wFiFDYVrHCBwjCQptNQZP32aLfAJ3d1ewhaNHA0o8/MAcELym3dZzDocUcNtH/1Gw8K6Oa8faAifRUgC6decqG0YcMw5EqUE5yp6lSLyLSFLYWW/tF/NVBbr1cZCTvedh7Rv7BvURHQKtTJxDx1Ldm3W3r7uiGG2r/4I4gAc5e7Xv3Fvim6cbSRqwZAg122Ury9TKTECBW8NLpz/ADAhVVAWzoLrhhf1ZUSquvwP4nMXRNu7X+oGgNwDU+SW5I0V4RKG6Ba5UuwaaqgXzK5cSIzqkJfLMwAFcrFfPvUHZUewBe7eVGQOhLW9RLuQ7kDzZWqsrVi9A19tEoa9XewnNRrRWVA7hApRABVw44NixCekg3yf9TRh0dYtbUOZzAZi8EVWDfmbxO9VTa3mNAkiqNLc9Rd4Lor8ygzBqLW1FT17WcsfmUjjaCn5Yr0zjyPM5AB8F4hENgl44Vc7EJXzUVKkaaeCIDXjzxtQRCLl5cQfaFrhVzbDTHdw+A0tbeOCo2ES7FVRIdiYDZxXxHK5SQuu4FvTtEKCF/ZZjBDWqxQl/JMsG7oH7wGA8hKqRV4EELGcchEBDBvLxRAO90ggjj7QhEt3XcDQr1YXkApcbAP9pfZ/iz/cobPjRIX68LpP+y6Tt2pi+1ieLeXcImgK8w/DctbuS2q9j/cedFAGQcArnioqtECo8Vd/uRzN/gtygFtsQV9xmgKhfxdQmqQlu/BB5FeWA88feIAbid+XcIJE8j94CxZ5hVRj0WHj7R4JGNsuMRRBSuvtFDjSaH5ldQjHxNyIslzF+peH1KAwNe/tHYKCRW7931BcauImE7IHFePr7jxCFbXLDHismUjmhVLXR8xouZAVBx3plzeVUPESdG6Bl9EdlOhb/wCYN2ui7blFfbV+7xFvlM4IDMqC5d1GHgQqoamtepoDcvs0Uhr7wR1liydLREbQFpvHw4ZdEW1l7ayNIRta2WKTPFxBNRmWHHzGACguBNV1isQmkK4IL+aw8KkDAeKjnqLKgLZvnfUIQljb4LXLpksOSxDaurSmBElJEHDw8v2EQEg3tRcBHIdt8wUl2hObjhVtFaLlNtaxDT1H0DhFq9wfGR0VBUB/UWI1vPp8BKntzZB/MEtQN8z8GRpQaGp+ySn0F0RRMagbQBzFwICgY518RinK3jo/OEY4mypZ3EQtVTW+5f0cM4PcG+CMJtN+Lg+UGW0nEYNLeXr/AGVhYmBsH1Ut293YNls8iwsu/wCksxhJUtpC5aVRdi+d394Yxa9D45sLrHJpa+PE2hmO22KZxQq0Xp0yo8dv8/7DFsR58/8A2GTBY78P9SiAedSVUgM98/tUQ/TZtlhogWgVeeOYR5SacANf3Dg2lKAc/wAk21oNA0me5fHKvezftKML0tvVXmco4pPvTo29+osVotWHinuCuwQbd0XlfGS5QQKy+DIkhHSyT5twZw8XpVf7fc4fsKlmcuy9xDGLK7PjXSRAslV58QpRridS8iulgf3i6lButC/EbdKEovFfY/EIzo3iHLxLJpWAwYgZ0Qn9ZjKIbxuElIKTzT5QDwo9gpiQ5bVltUf3A4tTB2XCCAloenHcRCAWN/1GIH5Fc7zWnHp/yHal3F6j+BFztUuc3/dRRmOeeH9xsFYnQQnE7ora+FBn3nE4V69XBSKdiE4908rz9uIGWxrUUejuJUpaObTZLFgDThXG2xfskj6CUW2Nd67QmodL3fojFWT+BTysRrho/wD0+JXPq6xRHboCikp/2ViQLEHjqpeP4iT8IOJ/F8jrRR9patflAR9XEgAUmuKpuCBStzU5Msg/sL3+4Ja2zzR/iKNRLfA8PUWqitnUcbC8YU6a3bZh6JYIlPj5ZYMQ2OHH+EBRoPFhRFvjyrmDZVDhVHUvqtgmg2gIu0EVTsFgHuL2kvarNFEzYQ/mUOqD+kaLVZcXpRYb5V/MvASqTGrFyzng4rLxee8gHKqr9uf6h0LEb48p/kQHirOK8MXcgay7gm22CrKt/cfAAjfm5VtIdNIvAKNNHuFx3IKorSvfM4p6ma61/MJzTfcEMJDWxLFb8S5lPYEVTwHT0r7R1g2janUVovENIt6ChXEbAJo/gl4wNyLWCVYaAi+vKE1aFQUe6j4VacKuRWcxVXRaBSDzdZHo2EMSrxcuvAXhdO/vLK3zYfs9MGGVKIAo9S0JrGyt5k0l1hlPNwe1w0BZpzsXDojisfccZqkS25LgCtSK2owNIt3lC/yERVke95F3xISjjyM6l4LEFcRf5IntF57Lt/USh3mr7uYAgke6afzK3lDGmPhGVZJdd85CiDLWY3f7JEBVjKU2JydQFWwyoIeeS/M5kLT2qEwADtijMah5EILQCUAQDR0WuclwWdBuP5gRPmDTqAnHCv8AmWuNmqpjNRBa3wXz5iKdhA81Laei98EAKaAr1LTkyAD6X4iNs5G/N1K2KSq03hfMZmI3dKqqCGyy6v8AkaIVGK/tNHHFpzGzQW8TdZlvuUDpLFtuaP7iiYKxXGUXF1/kz+9IcfyA8RAZ0S+fHqK4ru7ONb+8AlutVLXf7wOIRqat4r7TbLVDZXN8+bipWFlhbSuPca+vC9il04hJs9TgNL7QeNyvNWf1HJGKAp3QHniLdwSmfcSV/agoAOW1XccRYGUqX/2A4Ry9PxzLhHL5NfadTUR39opfbjYtD1Ga80IGyOFazyZf/kVkLDYMuCItGA1Ql/mYRZWCtj/EqQwPLy7i5ByE80rsmuD45lAyMQhKwPPcNBspZPv5jSBjUS/JEwFQoJ6rn9prwSFQpou/ZYr2izh5/wCR0UKSgv4TkGGsFvg/ebvy6LMG27lC1LIo8WD6gAzAhVl9nTUwTBUwPbmIMMKLB8kWJkHa2U3Lwjvabc8eoGAIhCui/wC4q4mK6Br3At831drQU9f5CJSVss5vfQXFDoqOBUi+UhpSpU6t7iU5h7g3PPME1KnFznr8RIKpNdnSIhjKF7eTGyB0uKRBcW1Crig/3IRqq2Ahe4jHgLXnomkBfs66JYyBUP8AQSs0iob8/Yg1F1i1lQgLLsLN+8D0ZiA8hAGpnd4sRKjlaWfEU0uFUjrlNHiLLpUmFBORz5LiMqN7Df28dRivsyx0fcy6dsFIPGjxfX3j3pjBeWvULCKNw+zzHn7+xhle408LGACneX49zBvoAKqOf8io9ORW6v8AiU2aljo9ffzApP4CghqlnL+/UuizALG1GCFOKFPhyXBu3noaTyY+KYNaBYXOw90+4ux2Ea2gvMotja1yQARaB7OkNi6luA8f9lMm8VFKpgKQ3VpHKop1EAKHLcYwoiNWlf2wG282HQDivMXfVFKz0J4iEpYAYXfnhjxAWtx0SDtGvRt5cuMVFEUWPPsliERiv8pQ/uSaR9xMjywsR/2O6SzQbzj8RqYhWAdvzL5As6ewQIUh5YCwrey+YioiZ0MW4rYQLT2nkhQTfm//AGzaureLn8wa5s8WRJk15D/kstA1QdL/AJ7j+xtQbrM8kTLt2NVX2YlpYNNxzONV4WY+ZuDuK2/6hNWaMBN3QzgsMVPpr7xJOKlWjl+WpRgiwMd5b147lYQKC0B84HcVc5aq19vUGV+BO0boPN1EU7JqR5YBu8u0Dw/ePF1VXk6ra9wd0QWKfAP7+J1Q0pBRWuDiBxeJ+4f/AHcBmeLeqdvxBhLKFZbydyyjUL5D0JsPS0vCAd2mjxCYVRLWd0nxKQgtF+PxLeghwOftKSvFmzl/2PXssrQObsAUClExYulosusICltFLXhGKl+HwtP5/aLFWitHNW99EWbqwcF/yYxQOQVktGuhReOalEEFo7fzAjah8MdCyAsKtvv5YI6bL4D/AEiNUdIEWtJbzT+04ojG2l8RSVSJeHE+2peoR8NSxAWFNzu4AiaKF0S3w1QcCBRSUYcXxLPNChdC679wxY1s6Xw35tjpJWKBYWn7jcvgzS2i+iZsJDttZbeasN3DH8EmOZXFxNIVRYOPbk4zY9wHw4+IrlUPOvk24qOPXv8A5q6B/MTV9dElOVF8QRN5ZoaTR+CJFRjyeql7qK0FtDfiFNZhFdiDd+5k2Y5PFDzKZ8k27GIcEVwK+KlSeUXQf/Y0VERSj+d+MhbHlwhK4CU27tY23hbZnzDHlwNs5tlhBX2QbXO4HdiTgq7eCoJiJJe+DK/+VH6c4gY9VQ5zxEbfSIKHfEyQAu/7x+lmiaD9uPvHRJRpA4lDyIwG0Gu0AvoOOf5ghSk+B/EErdfMmms4BIOJZ7REf+v8zQUAujXNRYaOjhHQXiupTd0TZ8qxEtwUxR64faAQwhQhEuh5fEAFgLK3jiL7WA2XKtYL2r44mkeXBXJXxalbKWw8ycgvWAHWMq+tXI1UW8i3SNlGpS7ypkLi1Ma+HUr2LQwdu645gKegULtX/EOnJApwAeYIWEyLwt7qr+YUC+sbiwFARLNFREpoXg89mxCnA6JWCneokGas6/wStYssPYW3nECeIYNA7niCdF+7ZWZDzOfdLb4wwP3P3ifAIWOeLovzGXUFosV5ZYnmiOx+Ibtti5GFRVN5gKqVysXATrcWo67+Jl4bS7pneJmy/a41kAcDYLKgTyInggG4ng9y1IhccjUAH5mOynqGM0+Kjc0PeorRnPZUPDW3D7miUsC+4Ar3BFr57gvejvLXxGphhi8cQh54unI2RbBUUErwas4Py97+hGJW/aCbDRuiMbx3DLPkGuR34lHHmDKiZBdMcFEW1tg6YlSm4te3mAKZjChzMSugaES8VNsKrKb0De/5h+uDgzno9Q5ykpXzzbEWrUqjKuBsu5FtDCEARqQ5DlS9Upgs/pDiSVv+SAXY2jiMASKDXuJgR7IUTarpjdBavF8JDkFgNBEml8V6g2l3v9oDIiAu/mIlPTHbHkP4ItVOY56PlGWFrSytlwY0KN8+bimBQNyqplymaFAzdksl7lo1W0pQX8xbRvgt35lRbEVvKlf/AGn/2Q==", + height=300, + fit=ft.BoxFit.FILL, + ), + ) + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 320) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.page.add(sm) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.pump(1000) + flet_app_function.assert_screenshot( + "test_image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": pink_radial_glow.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_pink_radial_glow(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "pink_radial_glow", + await flet_app_function.take_page_controls_screenshot( + pump_times=2, pump_duration=1000 + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": linear_gradients.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_linear_and_radial_gradients(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "linear_and_radial_gradients", + await flet_app_function.take_page_controls_screenshot( + pump_times=2, pump_duration=1000 + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": fade_out_image_bottom.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_fade_out_image_bottom(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "fade_out_image_bottom", + await flet_app_function.take_page_controls_screenshot( + pump_times=2, pump_duration=1000 + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py new file mode 100644 index 0000000000..bf04598528 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_shimmer.py @@ -0,0 +1,107 @@ +import pytest + +import examples.controls.core.shimmer.basic_placeholder.main as basic_placeholder +import examples.controls.core.shimmer.custom_gradient.main as custom_gradient +import flet as ft +import flet.testing as ftt + + +@pytest.mark.skip(reason="The test is flaky on CI") +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + page = flet_app_function.page + page.enable_screenshots = True + flet_app_function.resize_page(350, 280) + page.update() + await flet_app_function.tester.pump_and_settle() + page.add( + ft.Shimmer( + base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), + highlight_color=ft.Colors.WHITE, + content=ft.Column( + controls=[ + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ], + ), + ) + ) + + images = [] + for counter in range(10): + await flet_app_function.tester.pump(100) + name = f"image_for_docs_{counter}" + images.append(name) + flet_app_function.assert_screenshot( + name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + image_names=images, output_name="image_for_docs", duration=200 + ) + + +@pytest.mark.skip(reason="The test is flaky on CI") +@pytest.mark.parametrize( + "flet_app_function", + [ + { + "flet_app_main": basic_placeholder.main, + "skip_pump_and_settle": True, + } + ], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic_placeholder(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.controls[0].disabled = True + flet_app_function.resize_page(500, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.page.controls[0].disabled = False + flet_app_function.page.update() + for _ in range(5): + await flet_app_function.tester.pump(100) + flet_app_function.assert_screenshot( + "basic_placeholder", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.skip(reason="The test is flaky on CI") +@pytest.mark.parametrize( + "flet_app_function", + [ + { + "flet_app_main": custom_gradient.main, + "skip_pump_and_settle": True, + } + ], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_gradient(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.controls[0].disabled = True + flet_app_function.resize_page(220, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.page.controls[0].disabled = False + flet_app_function.page.update() + for _ in range(8): + await flet_app_function.tester.pump(100) + flet_app_function.assert_screenshot( + "custom_gradient", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_stack.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_stack.py new file mode 100644 index 0000000000..188dd85e46 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_stack.py @@ -0,0 +1,73 @@ +import pytest + +import examples.controls.core.stack.absolute_positioning.main as absolute_positioning +import examples.controls.core.stack.online_avatar.main as online_avatar +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + st = ft.Stack( + width=300, + height=300, + controls=[ + ft.Image( + src="/9j/4QDeRXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwABAAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAABIAAAAAQAAAEgAAAABAAAABwAAkAcABAAAADAyMTABkQcABAAAAAECAwCGkgcAFQAAAMAAAAAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAACwBAAADoAQAAQAAACwBAAAAAAAAQVNDSUkAAABQaWNzdW0gSUQ6IDExAP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/CABEIASwBLAMBIgACEQEDEQH/xAAbAAACAwEBAQAAAAAAAAAAAAAAAQIDBAUGB//EABcBAQEBAQAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhADEAAAAfdDWeYAAAAAmCAsQwEwAATBDQAAAIYJNCAsQAhpENGkDOwAEwQwQ0AAJggLAAAAAAAQAAAmhKSRDKiMIkkmgDPQTSAAAAAAAhoABDBDVAAAIgAABMEAIaAEgmq0AZ2AAmCGCGkAATBAAAAAJggKQ0gACaAAQCCapAGgDOwAAAAAAQxEACYIaAAABAABYIAAEACYiTBDRec7c1MRKyuwAAAABENAAAAhggATBAAmUhpENAAIaQTD5x3PH37e463z/qnpt/z71c12CMsUABNIMQAAAAAJghggBDQAWIaBMEMEAfHbs1us2WZkb+x5y633/Q8Ttr2xwezz1aRUTKUXlaLSiVlpGUoAAAAAgBMEAACCZSAPjUq1rEyEllozXG0zRXvdXyPV09Jo85ZZ6KPDmnceG+TQ88jTpwTl6Lw3Y1ocJTQCGJgmCAsAAEAAfF046w5RZOymazjELteKxeno5em3pvM9N2zk3WdWfHmnZs4WqTr28y+TdZllLvnz7860CM6kgACwRlLsnkeLqfRfN+ersxIcicohOMli3FLJ02Ldpx2rutxXaaLs9lsyNZbPLOzZr5kzrXcnQnU1ca6TrvBKOpd5/oZvRMZGvyHo/ndualwuZqIVq+eNZXsZhN1RnNDrLZfMzX2Tli9EajorstUdCspldOs8rGO6u1J30TLMFvNmrvR+E60nrL+N09Zq8N73w0ZSUc2pWyNMbpct5re3i6sEupnMC21oZ9miXjrv2x56XoKK409XPzNEuYpei8BLuhnkTIKrFAJZ7oXOedkksUK101VVVplikmuOSZu05nm7crjpt38a2vWy8zu1KcHpZL5zR3rTi2dLLpyZ32mGPRicnH6eyPHV+5pjxc/UURwH0sOaivNG456TonNZvjhZrWcS5Vq3S6zMsrGQjNWRIldj1fz30u9du7h7bN0c9RuWEN08OxJpcw6q5HIxr1Vfj4y+mq4QdbmVOKIzZGTUKUZxGcnESalrrhLeZKuSWypnKRlKmo1U42OI2SjmuNgK/MGmFZE5UyVyhBJEXTTYJCkmoUUWWSrIkUsrspt3mbjKWA2KNkYCKWxJ1TaCInGUsSJEVE0o1NRgXVErIzjUaHSS2OmdTVQlkYyJkEU257tZsUlLJpzTjBjrsVzVdBFrpnLKtlV6K3ITSVuoLVFASQpwBxkhNVWW1SjVk0osijNyWSj1xoK5Y1J12SkGUmAmASUogONScHEnTYOLZXG+NlUrYlMiVIurza4XR1ISsIi2gjKJ/8QAKRAAAgICAgIBBAIDAQEAAAAAAAECEQMSECEEEzEUICJBIzAFQFBCgP/aAAgBAQABBQL/AOosPl4sic4ovjZKX/BhkoXkqRi8l1DyISJPcTtf8BS7Uu8XkaPH5EZpTy34/kxYnf8AwLLsbMU9X7Py8fyGli8jSEPIT/4CGXwnqYc7r6j8cHlUoTU1aNkexHsRsjdHsN0Xf+zF0RZNnj57Sy6i8kWaLe5sbFlliZGZf+si+robMUvyhkss2N2LI0QnsWWWWWJikJp/6t8x6FMjMhb4sjOiOSzY2FIsTEyxToTT/qnNQWXyseOOHylLD5Pn7Z/6Pgsg+4SaE7L7TNutyOWiOZojm7WYjksvhMU/6M+ePj4/L82WSTyyI5Zpbf0o/afUZEXTLL6sssTFIWShZO1ldQyG6LN2hZEy7+z/AC2W8kn9q+798xP2mWKuLLLExMTEyxSFkJ5VGEfKhJqRubjmZsjnkf21/R+iPyyxPrYsvlCYmKQmWb9e964ZCyojk248qeuBn6a6+OFEWM9TPSPGaxKiKJ62LGLHYscSkUhaiUCsJriZpjKxJfxH8ReEXoNvHR7PGJz8Zmf1VF0/bDJPFlxqXtxVKWNwyRp6TrWRTZqijad3lP5WfynY8kIn1LTXl2pKLbs9gpG5ue2JvE3gXA2gfizo2PYbljbpvhWhJ1ubM9jYpUbG5vxje2bNOeJx863ki8y+jysl4ecXuwn1kxec6j5saXk4pF+LIn4uDIS/x+ZEvGzQKmi2jYsQotnrkeuZ65mkz8z8x2z8i5FP7NmWdHrkeOoYjLJZZejqKyKOPPluOS0+458fvf0WY+i8gj4maLjikPxoTUsU8bUs0V7MheGRLx8TH4sh4sqKmjdntPa691HsVblo2RsrbOionrR60epX6S6EzY2V+5kPLlAj/kJ3D/IQZHLDInihIjjopji2PFk19E09GfiK1L8rpHqgPDBn0mORLwIEvAol4uRN4JDi0d32j8j8j8js3kj2M2kfkd8Ua/b4XkemfvhrHJsas1Zr3oaM1oooofZ+KHlxI9uGRLHjY/Di3PxnAmpslCSNTQ1NTRGpqUalltnZ2dnZYzbvD5EngWdKf1WBkfKxsfl40fW4tfrcVY/LxzN4jyKC+theXzv455sklJstoT6UpIc5G0j5F0fJ2W2d83xHV5L1k5cfqjRHrRrCA8za9pv0pvjsoXzvKtpuPaLNqN+JSPn7P0MtI6+2rHGzRo0Z8c9sl2aCgNJFDLtXwpMbFIb47KLPn7E3Z2uUN1xYj4Lsp8W1wimIdji9bOzU1Rpz0WWWWWWxXbExsv7GWLixMdFWa0UUUOz45dcWdMvn4Gy0yh8J26P2iy+LL5uhSLEy6LLLNuLo2LsjxrzdiQ3QpWdGq57FZ3xXNjL4u1XF91R883x8D+fsvqxtFoY/joaZ2bGyNqTZsKXZY+LEdc3xfUbqQjUqinzXdFCRqa0VR+uma8PvjQSZfV82UUzsS7qyiuGqdEUftn7bF8n/AK+Efo+OP2n1wj9/pfPD+a7omq427XZZ+mxO+P/EAB8RAQEAAgICAwEAAAAAAAAAABEAARAgQCEwEjFQYP/aAAgBAwEBPwH+yzp6rpxp6BG2ehnERt5PsNpfKdkREREREbxi+7OLGIj0M8cxpmeLPDxpvMzMzzIzGdkcj8V9r2Tf/8QAHxEAAwEAAgMBAQEAAAAAAAAAAAEREhAgAiEwQBNg/9oACAECAQE/Af8AZJko1+NETGuI+J+CEIQhPsusITrD19oNGSc00jS5qNI0jSKio0iobEyjfFF7MIhRkRgwYMk6XiEIU2LzNIhlcwhDA/AyYMkPZ76opUaRRsfmj+hs2aNMpSvliZaX6z7whOZ2nD4nynyvRF5//8QAMhAAAQIDBAkEAgEFAAAAAAAAAAERAiExECAyQQMSIjAzQFFhcVCBkZIToaJSgIKy4f/aAAgBAQAGPwL+6JNpEXoTW1Ic19DR4pmysjoP/qvobnYdCHF1qbSRwqs9ol6HmOit3GiGQRFr6MnUnQdCpW2vPuMtkxvQO24l6HUXpy7xCrrUka2kaFsQuq7bxt9Pca6myrILOtRUeS8w9k9ymj/p9A1shE63Youq8/UVI8KjJOZ2EsiFu1u4jEhiQqlyplZNVMcSHF/RxoTiucQxqY4vg4kX1ON/E4/8Tjwr2Y2dI9mrrS6kMP5YWTMf8sIu3CshkQwqTJWtqv4OHF8GBUKohPTQElf2MEPwMuh+qmwsR/wonwUhMMJhS5iiMSkozEYjIy+CtyhRblVsa2GGGo6RIbcxtZIPYksCnDQ4Sp/iZfUnDAvsT0f7J6Nfg4cP1H0ekSFfgksMXgnAUu5GRldnuakojWWfdySMUiMSr2VBvwqpOCJPYc4qSyHh2jAg9FF/JBrd6Dw60PknLwpxYjahgj8obWgVPA8MTEokUoUv5WUsZra2VJXKqYl9x1mbUh0dU8Dkli+xiMRKMmhhUbUn3JQwE9HCcKEwqhn7odSpUkyp5KKUUnvcV1osKmcXhCjeTIqVsrd7WYpjOgi6/simzGw66b9Eon9ibXqb1OpNIvkWbGMkrj2LNhNqtDWVZGZspNREuYmK2PcnZW5Oji533qNld7Woj0NXWVultSRS2pW5UnPc13GEluK2vZO9JJE9xLeV5VLst3Xl6XqX5845OyvoaGRS428e5K9MlZTeryybn//EACsQAAMAAgICAgEDAwUBAAAAAAABESExQVFhcRCBkUChsSDB0TBQ4fDxgP/aAAgBAQABPyH/AOoouxVrggRVEjVT+G9NFX+xMf0dWhJ+kQeXkowvTtSQ417/ANheqryNWQdl32NTJFz2LolLFKKVFrRkvyIWsmv1s+VAqYUvZJNG+f0NrTP9w8UwsZGQLcoVs5OF/XaY2BqVwVOr8D08iku+BxD2aGbTbvZXJ4w18Bp1kRY6POR0IEmj/SJLkwjXwmcgSkcpp/Z2toe2HBTQjDIqysmfIiv6McDIen+ieClMwyQm4+wpCXpfkgg18ycFiCxZ0bgJTzyhfIQXxWrycpP0D0XAoURS8Fxsbo9DkpeRrb7djuRtdGJ8cmHsc1pAJe8i8/gX9ADMNoiZz/pU9EQ0byLp8UZ3Nxa1FK6phR/D+UbRSidJif4FBqjhGbCBOhSzyMR10YO5I+Ah4QjAQpF0y9Cr+txy5iXZdeJQw873rlilNGNFf9Rr45+F89Gw29iTDWs/RjC4og8RVNvmsWiDyNeQqZrZFMJiwJ0sNiyKbTDEmn9E+eEr9/BSlHr4NaERC0YyT4cItOo20JiVpjQYhix5GHyrfhXxoJHOlSjLvIai+3+SiCbfAyTrY9jZ8lyI+xah4mb8RirRLBrJti7otFwLumLyMoWk0dh0x6o8I9jJ8EEjKINE+CxoaM+iJPhlW5xSbx7Kd+WdC4YrKUyteMGeSPR0Y4RG0eyISnWn5Gv/AIPEhN4ErePoa+h1klrDSz2Hl/cSmV+4ktsQXWZL2/h0R1y/oJnGRewqxMHkEbpIng/BF/spMWt/j/5G3kOcy9uL/wBwzKj0zjPhNzE4ahpK7G5a2iTcGYYZZ7J6D2WxHhUPcxhuXoTNn0NCwf2h6x+4djj9leF9DTBgzAivyGhpMeU24S/742s/nATyCR+RBSMXOVonz+RSwCp08JolXCKX+DxNldtoauAUNI0zINHC0jM8P9hrIi8ISx2DQ94yNtvIrthSnRHVb6MC0xoPGCq4HwO9ITpZDW8Mo7NHerB0ZKXLz/yIWkdagkpnXLo/iShBZf6F0QeDEncPypivxoRjLzC8ac8tGXZ9+B68oImzGzRuboXEK5RtrAyeGaR+hh/yExvGnZDhCpoaXTcI2WJLBw4ZGtSs8Q13Bt8UrXI+0TdnvHJ6PIzaG72kNGKfnIUqTJ0UkPa/kW/BIP1eudh3BV3UbHB0Uhjqk8C5kE9qOhZJnu8iQqptqKdiNOBgn3O/yJFkekeA4+4o/KqH9zR/woe6xHeCEsUegjgE7YlbaHi0pl7FiaHgvgdpQtO5IrwZxSEyuRidJmDJ6L8kqtHP68jur6VEEBoD6OIQ0ubEZL6sODPyM1p+BfshR1S98Ges+6TaTh4ElUNGGKDSfbTE2yP2KST+lntnQn4L2ENiy6g88fkqJfH9phL0wlpL8GDi/KGn0IzXstFvkrNPJ35FlZKlHyXzPZp+BJt5eB9WMo1vI1UvBpSjqwXW8Ho3F7MQ1tE6Dbyh1MVt+wyzToaC/wDMy019o80hIsfyhE0aXZdjxNpr7GTUYXY03lTgRupPUVMiG7tFdCxpIbkTzIwwZjvMRF4+yLlIctdD6Re1CWYSRfM+Ca7OAmXqSDCYGtjYav0JsjGUTFsplkuJqJRrdeTBZ+1Bc4QLk14Hkp/5NeQ+SSfR4x9x8uzTFUS/NwVk8NulNdvYsprGzHo0ib7F+Wf2Yhpu3/cboXSwxyitYITraZltC52QV9DoJo8N9DVBOKUW5TeaIJHjB1HZgT3IWF4PQ25ZWA++WVt6tEmwOzbRK0f+R8BaDsc20TkG+oycHkNqoqKmsoQWipFf3Is3AdwHZBJqtir2oJdoUAuqE1wdaHbtDoqcw+x6E9pzlnJh4F3Zn9ivgQI28FZhhzGJMfYWOnkZqTXI0Xk6Wly3TKwYG0qxzw8Mcgm2uGRFxDsQ+qVLwIU5UMJ4I3lSeCF0bfgagDjDPgteahpgSzcY1Xl4fXwyt0LFTE5GBo/7seuELMl4G3lyMS4rRgy6L5MJkC4Vtoq2qdjaZCzWJO7/ACeMQS2Q0mf3Er8DweRMh+hg0NsGbYpIyYEK7tQbTHGNs4GMuiohc8j2Iz4slMv9xrzNehvJDhNjP2JvAXbLHXobZZKw8BfYtCaRsvTHl6yXTQhxk+hs1gZpPZU2q9IY5JF7SyNvkYPLGMGXFp2LZa2dNoehCCkZ0c9EtIxZXqj0cMEK/JTY10ORSL4GmQ0nJ8PBqipDyDX8CB5IXA4NNaY8qNmjfF4G2mUb+x5w0ho1WeENnT4ZGlRYEL+htrEHsZgxZhE8PsURVfLRCHOBX0MkxTE0LmIuc4FVp2l5MjsQmBMzCnlOHlJ2MKZFPAscowCTsK6McT4DjxfoUPgZXHI2m7RwjK5OnJcx7K6WacIkM0OlzBFmQeGfopxP+TMZMh1NcjTPNDLcJSUGdDRrBg4ZylugmjR5EZWiuORKyobcn6FNjjyEmLgnJGxYZeB9g0uSiTBq0G+TWSuVgpMi5FIxtEY9iuMFePRhlYrE23yOUGJ5Y1WOgbpyFhD0hWLLX2MHNLL6NGL+HwahrkiT+JJAk3BVFyLZSGKsuiDEiGsayf/aAAwDAQACAAMAAAAQFBBBRJgQAQEAAgcJABhNJRxlNRNBBBAAAU1hs1AFJBBBhBzlIBAAQIgG0BBQwFBRBBBTAgAUAgAoBBBBAhJRBBBCBYAIBSGJELBBBlBBhJDOQFkAlYCWFKBVlBBBRxBnBkcIMxdE16iuOJKBBBZCGKQIlcJzoHfb/irCBJRBAAgtxMdi6GR5/neJ2VAM+ZRV4l8WmsmcMVqUsx2TA2XeRrWDImg6bPorAF24NqIW2CEItODVotWhca9UFvT+i/8A8T9NIlg+3o8Ky8abBy1l8wgCf8EKq2i4xoVKnkMFyF+ZSGna9ybYYciec5vVamRSkOcW71eOMaR267Q/YY51VKTwXOmV77+caVtSNFoY5Fv/xAAgEQADAAICAwEBAQAAAAAAAAAAAREQICEwMUFRcUBh/9oACAEDAQE/ENX/ACwhOudL2u06H2TdoekzdXvCaTENCbXgSe8vpekymKoQq+n+hV9JLrCaoRSUego5FYnepYThdA8E4Ip3S6EMQtZRhqCT9DbyIOWaxbicsTlFFFFEZBEIvIahgsDSEM8+BKHJcqaOPQ2V/DkIVrwNvQnWNKVE+HDzjWVFQxwcMKRZ+T8EM4+FG6QrQkmqN/WQjEmISQ49kRCEEG6hLLb9HOeBYpS4mKUTykcYuJllKVleFKJiEMZcplwt2WLBOoXQyUkwtX//xAAhEQADAAICAwEBAQEAAAAAAAAAAREQISAxQVFhMFBAcf/aAAgBAgEBPxD+ffwn8BcqUaa0P87z2DQa9Ea7/wATRjA1CvrBGUT9UxO8Rdjkan6Liaowwy1M9iVE5ky8INDCWUKB4hH0wVFWJYr6H2Ptkk+DwkLsQN4o2jRHTRp0UvAyfYn+Rp44DTGvYnPJEF9YvbOnXQvYQJnkaN0XcQmDUasgQNctkE9sf8E2TY/sj2fbBD6ErsSPg+xoNvGCy8VWTUMo9DhWbKyYRROF4GsX2UWdjeJoSIQW2SJYcIeII71khFhGujZGzojEMRKPYaguG82CFrH0d6GmFx//xAApEAEAAgICAQQCAgMBAQEAAAABABEhMUFRYRAgcYGRoTCxwdHh8EDx/9oACAEBAAE/EP4X1d+pv2PvfV3Hfq69X1ZUqV7mVK/hTMqV7WJEa9KlR1Kie+pUqVK9lf8AwO4lymVExKlRlSpUr3pcqV61K/md+letSq3HOpXsd/w17KlRK/jT1r1cxKj7Klfw8+2rlSo/wu/Yy5cfdUqJ7q/gd+te1fW/R16Mv+GiP8lerr2u/a69H+R9rr38+19Xftf53fsdfxPsd+rr2P8AKmfcyvZXsfVM+x17Fa0bF8biISFguyBAI6ZdXvEdOkeStzj33K96Z9lMpleqZ9KlPo6lMplQZai7q9EdArBS3Ut9zat2OYgG3xTx+YghIVwEA/Xwn3N6YEBT7rlX/CkqV6uvYnrXpfqlXdgAIcVBplg8fMMW0rwaPmN1VyQysFf03C6nliXmuHwwawaRx7XcNS/46lRJXsqVKlEYqVLwmacncOjIY4RSFHSEy1BLKXUSkcVtny8QgcUGX4viKC2CXdXKYCLGoBWka6iy/S/5nM1HMfc69W7ipaM6guzfmdhG+OpZyNppzEpu29v7lbUVs5IwAZWgKr5hRwSz9xFoUHJyfMqUbDzAs/RCNlEJYlwbA+KiBdvxMmMe4reI9gZnn3Opcv0qO5Ur0z6J6MbrUEimmsxvIcvMV2fctzfxHFjfcJVgeL1EsMOAzqOGg0L18S6tlmncxRmzMT0fLGkEdc/uFeChySyeWFncPOUtjTBx+WGgMtl+ly/Y79Ll+l+j6ZIZQm7KIQFQoYsLcYtHJFT4iLjvfKI148xmIaUgQcxeVuUMpTDeSN2tdOpYbQ/RF7hnDH06o12KR6nCCY+z0deh7Hfq69qvSpXYiUBWIvEDIiJiEwl4bmUHmMxXeWrrDliVFDbz4lV8O7YW5fQIzFxMgKuATDL5gmEhlDLQUBZF16MPR37QA0QHytEvl1A3i+QLZV3IlFdInHlicU3Y1yQ5gzmBWIRXhuK2W31NSotC6plQa7lhsy9ywZHnHERQzrGI65IWwUAuSM06xANX7QAa2uyWDopVupUlCHdwPBdZzHLUQbqy69KCNjL3S1quIUCNncs7l1B7juVFxMQIoWlRVQaSwpO/uPCyqcDuCwNuWU+Ii2KXlMo4D3E1ZhgZn9wMNbm9cwWpYQzSriaVh+ZziqxcTuOK7IyKUYgeklMwoMp3Ha3mImWn9S+nBuGSYO8RLFYlkhKh3Bi7eokH+ol3S3XMDKy8ejBVWPh5hRWG0HxcPJLeooGYA3glXb/5MwX8xyhdW/qLvmXBhiefqZlvGpzuUHmKG9nD/c0ZjQ7/AHBbrWu2JoLTMnswdYh3FRZZiNGs1iHZlDzBbRR+Yii5Ve8MFRux9BVysMmcEqTWZnNfUp3+bmfOLLbwEHbmxQeYxADDYg9fOJiSk4YcYQPy/mBe8Fc9ZjvrIbc4/Uzrt5QWn7nOK3CvRnUUOF1NDeTiApWLjkQwTUI/EczUzSxzUS1CqxmYNQUshgusEIZXxMC7DfUzcMYxLw+pQkFDPmbYo9TYQFAnxAtj9x3oSjtE4nOFioLjBuGrnMmGtkAs/wA8diQshLSnjUVsNrkum87FOIADldh+4ZbiqNBf9zM0p11AHSWFNQZS0b1MZ0uJZ1+WDUawEBqI28oWZ+y4YtoeBg1pXZaZdC7qVA+BYwMpDbQzI5nQ/wCoIAabzz+plCPY/wDUEDj5v/kGV+wv+Jqmk4E/UNAM/ZAIDyBVfmo5COj/ADIKoTtz+pkpff8AqCf/AADuC5LOv9risVl/9VwqYSRNKtw/9wdb96sQZqHKn/iVuuAL8XAwrHDfFvmVYtyTd1k+JRyGN6XeOoa7I3TYvmKl2l4k7coTY2cZhiIgYV0cswLzCpGFfgsIjdqgRAJm5CLCgDdtJkiNU3AaZfLgaHcURQRzhZ+Y3BAOc6/iWhr1jlK8JWmn9Q0zVXBr4cQ4EyXqupZDADpuVi15aRReDtqKLBWxuWQoN1MFZesmGDa54/uANhj/ANmL5AaBuBCI7WKGm5tgWnXsl+/pv+RGQ5ogAO7H5qCFBfknHK4zD7AeqYWpV4MVbLS1dShFoCXLRNLFRC1SsVWISJQ1RqH14otErl/nF1AdyXbbVQFPuqGLuvnUcb4lBvMtTcCkB0LcIBwBJh8l5/MpEGB1fJn+4EVh4plqd03/ANktgrkC/KQvM2HC/qG0BVqX5IxDZtOh8YgLjwI6lVUvl/giPyIA/aQQwluFsucRzgiBT9NxxvhglRjWtRozgPuA0I8Eydi6il2BO4UMRtGMC2XuHyB5JwcE4wPbFQy04qCsKJrMyRPNRVu/lZipB8GJkWGPzDWU7AvqZdoHcXGx+oypsWuH6mABSCPCMZF4C5Hk3MARZa4e95+oHOgLY+aVLoVqwn/Ezx7qyLrCxUfOBaK6uCqIoa7pZHZGxpiNqqrXP6mbKCU4825gMlboeCSCGhaAp/bCQ7LZj6MxgPFqir+ECFy735JaLHAqvjmb+eKdHhsqN/XhYu2K5YTLRvBDO27vr/cKk5btIZGSwGYhllZWoYuq95heKsrW5FJuOdQtUamJhHWEmMs2c0gWdI4iwgCI7wPEeEB1cuczidDf1FCQXNkwEA9cMxwh4y/UFGBosqnsm2qdlGnhpKCaPNp9C0RNKgvAP6m8opAREFLwWD4g1xjzQSshzy5/UpqgWlIhZ6jx8Hggk8mgFv73B04cgP71FG3CyfrErwtAA/uWyz5KX+Ri9y8V/oI0tM2uVMYxrx/hL4mttoTxcZBmMgwYoL0LkR0GHCWH5i2GcIT/AFE2uOTAw5agwMQQR8ICsMuDw8zmBLuJReYpllBVlvwTKH6xRu4upSBlFgzLLD4tg0tSGkiGRC5SsXKm6dN3KBbWmYZEssQWVXURHtyMwVKy6yB1cR0A1pfmLo090LMvBw4EfzFlb+P+o8498RAoixuWMVerEXu0M0NzJtDWEKqUJW7xtZcy+J+XEFB/F214hsuYMKIkyV23+YpTegvhtyV1zFawNCR7XcyJ1hS65+IkWAwhc+ojrnF2xK0ysvJ8Qz7sRwGeGAwC3EeUp5B5/wCSnAPkjCq3iyoZiiuoCi0/ExYqumLdW6ySrldW3LE3XUoLJzAYGOoWF1uCJzBC7s1UDHRlSIGbULAbzmxt+6lwEVQivxiDqAMuV+eYQGC6yL9x1j3HcIU3eRH/APUJwqhTcK0FAaWNxBu7Q1cUOmpm5V0LD8yyokaXfEsrawjmC5n/AKqZcNVVfcdCOMy9ymwbQNqg9LaDCYjwOs2lYcxKSKCEjWJbX2nZG4COYwUwXniGeeODETksvi5dtH5jbg1GVY70QxwWGeBwkyCdy1ZMNtU2Md2Eu9TZLbTxFFUIZ1FW29mGmocTARiCMFTNGXqFRIee5ihRwGiZRoGaxBKWWzbEIBfjMJSk+ai5M5qWpHCWN3H+MwRYk1GBcxSsU5FPomAFimcLC916ri4lRmcEMw/PCAli2ADUsUIrTwxWpKesxICxx4nV1y0CB4qFEKJoZzU+I9Mw58Q0Mt7IhrhseIk4T8wVQaMl4WUmltj/AMJQQPmrEqFg5hFmx8QeJh+0rUstaI7LFCK7aobilU72EUJU5EzG4C93UQNKJaGFqisZagRYLtDDAGmmc9RaUvhYxCA5ozUPsQN6hGT+6NGB5TcOYwbqKFV/ozWjfVxAyrVcEEUd3CWgHljbcjgTETtRZw3EACcriYEHrCgSEtXUFKYfOUK9MFSlQquYgEvBTHRs4NvuDCkfxEs1/WJUQczv6lXMtBRaWVpQqWXr4SwBudXmPXwOkwhJFLY7u5Uj7m4+XDMSGr8QhTdrzEyFmaagQMOMhAVdXmWO2bTctZzxUEdjvCI7B8s3BWRfhlwcXFIEUudVGCzErEFzaxkFLOaiGK3KYo/MEZquLgCsZ1cLNcxqygupTyJkqKXdPRAg2lamR4MRLSpcicxNiri7gYWUsdiVxkzvicob8wqqHzSM4CJxmoUVLS7vmK6xyzESMM55jlAg5q6lFRXcF0lGswLAU1FYhb1qNA0BzUQQhrdxHisGUAj06YMUsXUT46salUMbOUJbmTplEYU7mGSqoOWDlWPELDDYzYFCxxUpXAXthbfhHUFqVOMxYZoll+CoXyPqUMFZgrg0GYIlj14iqxSbgXkfMAv6CInJexmphewlzaF2QrUh7u8xSrKpbXEtFR+YN2rXqJQWVALVU5zN+xUs04MjDQzzAFW3KBFktGOKo8pHzrziUANU15j7G0vlFeJi5LcGY3NjjyxkMC/iN1TvzHUXpREgK7HlI2DdCr4lncJyEokmdkrNC28wsYzWuokKhuI2Fso6LgmRcK4g6IAdfKL0SHiI1n5JQwLVj3EvIJsGPqZWk8kGQspa4JnIrZSVGwR+GNjt1EA5s/iWaArxGU6LKi7mTuGxPVKblBL05cRXkvfDGKADolUADliKre9wbAbikUA3EKFOZ0fGK5joi3k8QI6PX+YotV8RsyZK1iKUWnqJcnfSNiMPuOsC8bjDBXMCNcINbmrYyxcCaHDGI2sUeYni45V9x7Te0xDaqWxuyLogQc7IBDWYiwj87QNC7izFk3KM/Ji9ALj6Yo0Dl7epdoqOIsmCb8xA3gZn9aSwKgagFmZ2SuTAbJSGiagrKQ8MQxZ5IKHAOJ3lzMlR5TRXqEFFwlpVALldOIoW6agVs8Kl4Yu5RSG5pl9stGQ5JWBBtuB4u4RaB+BZ5FwLBzXBm95JDWJAphjcbYsLuMxDAajIrXEYQ51EWeiJySgK1ZqXSDliIuVavFQWUuVILJJeKjY2rTi4qmRX5RWVROZu4pAYSo9xrSCgYMRktuAFDN1FijpmVnNuYIKxeo0XZzjiNFqgpAGJWIKBWPEamRhS0ZrBLVy7qYQxsCutTuM//9k=", + width=300, + height=300, + fit=ft.BoxFit.CONTAIN, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + value="Image title", + color=ft.Colors.SURFACE_TINT, + size=40, + weight=ft.FontWeight.BOLD, + opacity=0.5, + ) + ], + ), + ], + ) + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 350) + flet_app_function.page.add(st) + await flet_app_function.tester.pump_and_settle() + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "test_image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": online_avatar.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_online_avatar(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "online_avatar", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": absolute_positioning.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_absolute_positioning(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "absolute_positioning", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_text.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_text.py new file mode 100644 index 0000000000..63a9e4d9f5 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_text.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Text("Hello from Flet!", size=24, weight=ft.FontWeight.W_600), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py new file mode 100644 index 0000000000..f5cd7a9072 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_vertical_divider.py @@ -0,0 +1,45 @@ +import pytest + +import examples.controls.core.vertical_divider.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Row( + width=120, + height=60, + expand=True, + spacing=0, + controls=[ + ft.Container( + bgcolor=ft.Colors.BLUE_GREY_200, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(), + ft.Container( + bgcolor=ft.Colors.GREY_500, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/core/test_window_drag_area.py b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_window_drag_area.py new file mode 100644 index 0000000000..323e194ddd --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/core/test_window_drag_area.py @@ -0,0 +1,39 @@ +import pytest + +import examples.controls.core.window_drag_area.no_frame_window.main as no_frame_window +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.WindowDragArea( + expand=True, + content=ft.Container( + bgcolor=ft.Colors.BLUE_GREY_200, + padding=10, + content=ft.Text("Drag area."), + ), + ), + ft.IconButton(ft.Icons.CLOSE), + ] + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": no_frame_window.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_no_frame_window(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "no_frame_window", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_action_sheet/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_action_sheet/image_for_docs.png new file mode 100644 index 0000000000..ac5fcf2d9a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_action_sheet/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_activity_indicator/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_activity_indicator/image_for_docs.png new file mode 100644 index 0000000000..91aea19f4b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_activity_indicator/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_button/image_for_docs.png new file mode 100644 index 0000000000..abb0912245 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_checkbox/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_checkbox/image_for_docs.png new file mode 100644 index 0000000000..26f345cfa7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_checkbox/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_filled_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_filled_button/image_for_docs.png new file mode 100644 index 0000000000..201df65e00 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_filled_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_list_tile/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_list_tile/image_for_docs.png new file mode 100644 index 0000000000..431847f9a4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_list_tile/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_radio/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_radio/image_for_docs.png new file mode 100644 index 0000000000..682c65c9d1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_radio/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_segmented_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_segmented_button/image_for_docs.png new file mode 100644 index 0000000000..7442fc5e1e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_segmented_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_slider/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_slider/image_for_docs.png new file mode 100644 index 0000000000..30261c5895 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_slider/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_sliding_segmented_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_sliding_segmented_button/image_for_docs.png new file mode 100644 index 0000000000..83c8b16a8a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_sliding_segmented_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_switch/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_switch/image_for_docs.png new file mode 100644 index 0000000000..4fb3e0812d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_switch/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_textfield/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_textfield/image_for_docs.png new file mode 100644 index 0000000000..fe245a660a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_textfield/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_timer_picker/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_timer_picker/basic.png new file mode 100644 index 0000000000..c8578685c6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_timer_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_timer_picker/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_timer_picker/image_for_docs.png new file mode 100644 index 0000000000..ef9f2c288e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_timer_picker/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_tinted_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_tinted_button/image_for_docs.png new file mode 100644 index 0000000000..aa96d7cff5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/golden/macos/cupertino_tinted_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_action_sheet.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_action_sheet.py new file mode 100644 index 0000000000..e26374bbd4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_action_sheet.py @@ -0,0 +1,32 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + page = flet_app_function.page + page.theme_mode = ft.ThemeMode.LIGHT + page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + page.update() + await flet_app_function.tester.pump_and_settle() + + sheet = ft.CupertinoActionSheet( + title=ft.Text("Choose an option"), + message=ft.Text("Select what you would like to do."), + actions=[ + ft.CupertinoActionSheetAction(content=ft.Text("Save")), + ft.CupertinoActionSheetAction(content=ft.Text("Delete"), destructive=True), + ], + cancel=ft.CupertinoActionSheetAction(content=ft.Text("Cancel")), + ) + page.add(sheet) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_activity_indicator.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_activity_indicator.py new file mode 100644 index 0000000000..f895029263 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_activity_indicator.py @@ -0,0 +1,17 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoActivityIndicator( + radius=30, + color=ft.CupertinoColors.DARK_BACKGROUND_GRAY, + animating=False, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_button.py new file mode 100644 index 0000000000..3b206de9f0 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_button.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoButton("Tap me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_checkbox.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_checkbox.py new file mode 100644 index 0000000000..a3da56f08f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_checkbox.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[ + ft.CupertinoCheckbox(), + ft.CupertinoCheckbox(label="Checked", value=True), + ft.CupertinoCheckbox(label="Disabled", disabled=True), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_filled_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_filled_button.py new file mode 100644 index 0000000000..ca958dbaf7 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_filled_button.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoFilledButton("Tap me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_list_tile.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_list_tile.py new file mode 100644 index 0000000000..9f3e1f0cdb --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_list_tile.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoListTile( + title="Notifications", + subtitle="Enabled", + width=400, + leading=ft.Icon(ft.Icons.NOTIFICATIONS_OUTLINED), + trailing=ft.Icon(ft.Icons.CHEVRON_RIGHT), + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_radio.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_radio.py new file mode 100644 index 0000000000..f26b11088a --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_radio.py @@ -0,0 +1,23 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.RadioGroup( + value="option_2", + content=ft.Column( + intrinsic_width=True, + controls=[ + ft.CupertinoRadio(value="option_1", label="Option 1"), + ft.CupertinoRadio(value="option_2", label="Option 2"), + ft.CupertinoRadio(value="option_3", label="Option 3"), + ], + ), + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_segmented_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_segmented_button.py new file mode 100644 index 0000000000..13c2ccc2fa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_segmented_button.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoSegmentedButton( + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Three"), + ], + selected_index=1, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_slider.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_slider.py new file mode 100644 index 0000000000..d598a9942e --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_slider.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoSlider(value=0.6), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_sliding_segmented_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_sliding_segmented_button.py new file mode 100644 index 0000000000..9112b92bee --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_sliding_segmented_button.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoSlidingSegmentedButton( + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Three"), + ], + selected_index=1, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_switch.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_switch.py new file mode 100644 index 0000000000..2931a0e598 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_switch.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoSwitch(value=True), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_textfield.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_textfield.py new file mode 100644 index 0000000000..b653064d31 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_textfield.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoTextField(placeholder_text="Search"), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py new file mode 100644 index 0000000000..58e4b96be8 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_timer_picker.py @@ -0,0 +1,38 @@ +import pytest + +import examples.controls.cupertino.cupertino_timer_picker.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoTimerPicker(value=1000), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + btn = await flet_app_function.tester.find_by_text("00:01:10") + await flet_app_function.tester.tap(btn) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_tinted_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_tinted_button.py new file mode 100644 index 0000000000..f1de7c94e0 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/cupertino/test_cupertino_tinted_button.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CupertinoTintedButton("Tap me"), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/alert_dialog_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/alert_dialog_flow.gif new file mode 100644 index 0000000000..8ae3224269 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/alert_dialog_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/before_click.png new file mode 100644 index 0000000000..a66ef00fd0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/image_for_docs.png new file mode 100644 index 0000000000..6a88612d4e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/modal_dialog.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/modal_dialog.png new file mode 100644 index 0000000000..238e79dcc1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/modal_dialog.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/non_modal_dialog.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/non_modal_dialog.png new file mode 100644 index 0000000000..a44598d8d8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/alert_dialog/non_modal_dialog.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/app_bar_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/app_bar_flow.gif new file mode 100644 index 0000000000..22a6a1c32e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/app_bar_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/before_click.png new file mode 100644 index 0000000000..51a8b9eb8a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/checked_item.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/checked_item.png new file mode 100644 index 0000000000..69ef56b80d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/checked_item.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/checked_item_reopened.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/checked_item_reopened.png new file mode 100644 index 0000000000..5183d20a22 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/checked_item_reopened.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/hover_checked_item.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/hover_checked_item.png new file mode 100644 index 0000000000..7e778cd774 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/hover_checked_item.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/hover_popup.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/hover_popup.png new file mode 100644 index 0000000000..ff276090d5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/hover_popup.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/image_for_docs.png new file mode 100644 index 0000000000..60e853b38b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/popup_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/popup_open.png new file mode 100644 index 0000000000..aa69f44acf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/popup_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_after_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_after_click.png new file mode 100644 index 0000000000..29ebcf3eed Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_after_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_before_click.png new file mode 100644 index 0000000000..8d85cfabd8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_hover.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_hover.png new file mode 100644 index 0000000000..c4368a44db Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_toggle_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_toggle_flow.gif new file mode 100644 index 0000000000..56a8a2f957 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/app_bar/theme_mode_toggle_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/after_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/after_click.png new file mode 100644 index 0000000000..468a7897aa Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/after_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/auto_complete_basic_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/auto_complete_basic_flow.gif new file mode 100644 index 0000000000..36640827b6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/auto_complete_basic_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/before_click.png new file mode 100644 index 0000000000..47db9fea78 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/auto_complete/before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/badge/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/badge/basic.png new file mode 100644 index 0000000000..2e46abef29 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/badge/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/badge/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/badge/image_for_docs.png new file mode 100644 index 0000000000..8b4386a912 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/badge/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/after_ignore.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/after_ignore.png new file mode 100644 index 0000000000..7145b7e89e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/after_ignore.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/banner_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/banner_flow.gif new file mode 100644 index 0000000000..e2e5254092 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/banner_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/banner_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/banner_open.png new file mode 100644 index 0000000000..921b8682b3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/banner_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/before_click.png new file mode 100644 index 0000000000..f84d581ecf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/hover_ignore.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/hover_ignore.png new file mode 100644 index 0000000000..63510011c9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/hover_ignore.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/hover_show_banner.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/hover_show_banner.png new file mode 100644 index 0000000000..cb9786fd07 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/hover_show_banner.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/image_for_docs.png new file mode 100644 index 0000000000..6e908754f0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/banner/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/border_radius.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/border_radius.png new file mode 100644 index 0000000000..142a7b4d03 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/border_radius.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/image_for_docs.png new file mode 100644 index 0000000000..b3888ad796 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/notched_fab.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/notched_fab.png new file mode 100644 index 0000000000..94b5a5abb3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_app_bar/notched_fab.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic.gif new file mode 100644 index 0000000000..ee176dbd46 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic_1.png new file mode 100644 index 0000000000..e1c22043e1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic_2.png new file mode 100644 index 0000000000..0e794ab116 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/basic_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen.gif new file mode 100644 index 0000000000..680d23ffd0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_1.png new file mode 100644 index 0000000000..791f772ff7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_2.png new file mode 100644 index 0000000000..fa3b3b0df8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_3.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_3.png new file mode 100644 index 0000000000..791f772ff7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_4.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_4.png new file mode 100644 index 0000000000..6a065ee4cb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_4.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_5.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_5.png new file mode 100644 index 0000000000..a698486568 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/fullscreen_5.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/image_for_docs.png new file mode 100644 index 0000000000..8851d95a3d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/bottom_sheet/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/animate_on_hover_hovered.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/animate_on_hover_hovered.png new file mode 100644 index 0000000000..2b575efb6a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/animate_on_hover_hovered.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/animate_on_hover_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/animate_on_hover_initial.png new file mode 100644 index 0000000000..8d5dfac708 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/animate_on_hover_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/basic.png new file mode 100644 index 0000000000..a52c3d5bea Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/button_shapes.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/button_shapes.png new file mode 100644 index 0000000000..c4a8947892 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/button_shapes.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/custom_content.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/custom_content.png new file mode 100644 index 0000000000..fde5c490e2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/custom_content.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/handling_clicks.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/handling_clicks.png new file mode 100644 index 0000000000..b6239391fd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/handling_clicks.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/icons.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/icons.png new file mode 100644 index 0000000000..ceb9cd526f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/icons.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/image_for_docs.png new file mode 100644 index 0000000000..0eb7a73fb2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/styled_hovered.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/styled_hovered.png new file mode 100644 index 0000000000..45ace2e00c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/styled_hovered.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/styled_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/styled_initial.png new file mode 100644 index 0000000000..761bc7d45f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/button/styled_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/card/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/card/image_for_docs.png new file mode 100644 index 0000000000..97c15e1fdd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/card/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/card/music_info.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/card/music_info.png new file mode 100644 index 0000000000..17c5defeb1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/card/music_info.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/basic.png new file mode 100644 index 0000000000..c730abb7cf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/handling_events.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/handling_events.png new file mode 100644 index 0000000000..7433b43618 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/handling_events.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/image_for_docs.png new file mode 100644 index 0000000000..dea0c2ec30 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes.png new file mode 100644 index 0000000000..8a0c4a9d1a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_flow.gif new file mode 100644 index 0000000000..ac030590ee Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_hovered.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_hovered.png new file mode 100644 index 0000000000..406b3f0c07 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_hovered.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_selected.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_selected.png new file mode 100644 index 0000000000..55bc4334cd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/checkbox/styled_checkboxes_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/assist_chips.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/assist_chips.png new file mode 100644 index 0000000000..c4392dcfb8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/assist_chips.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/filter_chips.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/filter_chips.png new file mode 100644 index 0000000000..826538b339 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/filter_chips.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/image_for_docs.png new file mode 100644 index 0000000000..b10376abb2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/chip/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/circle_avatar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/circle_avatar/image_for_docs.png new file mode 100644 index 0000000000..71d935f306 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/circle_avatar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/circle_avatar/user_avatars.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/circle_avatar/user_avatars.png new file mode 100644 index 0000000000..dbbc589896 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/circle_avatar/user_avatars.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/after_double_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/after_double_click.png new file mode 100644 index 0000000000..58bb14ace7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/after_double_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/after_tap.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/after_tap.png new file mode 100644 index 0000000000..efacb87f33 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/after_tap.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/before_click.png new file mode 100644 index 0000000000..a4c701ef2d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/before_double_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/before_double_click.png new file mode 100644 index 0000000000..a5487b7cc2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/before_double_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/custom_trigger_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/custom_trigger_flow.gif new file mode 100644 index 0000000000..2ef0ed49ac Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/custom_trigger_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/image_for_docs.png new file mode 100644 index 0000000000..f5d6def08e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/left_click_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/left_click_open.png new file mode 100644 index 0000000000..efacb87f33 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/left_click_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/programmatic_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/programmatic_open.png new file mode 100644 index 0000000000..c8e2c77ec6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/programmatic_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/right_click_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/right_click_open.png new file mode 100644 index 0000000000..c414481a83 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/right_click_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/triggers_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/triggers_flow.gif new file mode 100644 index 0000000000..10d942246b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/context_menu/triggers_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/adaptive_row_heights.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/adaptive_row_heights.png new file mode 100644 index 0000000000..6e7b4af2ac Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/adaptive_row_heights.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/basic.png new file mode 100644 index 0000000000..38f21d9952 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_click_column_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_click_column_1.png new file mode 100644 index 0000000000..f46370f434 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_click_column_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_click_row_a.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_click_row_a.png new file mode 100644 index 0000000000..cc4f17fedc Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_click_row_a.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_flow.gif new file mode 100644 index 0000000000..b016f3033f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_hover_column_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_hover_column_1.png new file mode 100644 index 0000000000..3c0cf0709f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_hover_column_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_hover_row_a.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_hover_row_a.png new file mode 100644 index 0000000000..66115c7a58 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_hover_row_a.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_initial.png new file mode 100644 index 0000000000..62ca2ab1db Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/handling_events_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/image_for_docs.png new file mode 100644 index 0000000000..78b6550b79 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/sortable_and_selectable.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/sortable_and_selectable.png new file mode 100644 index 0000000000..da544983ea Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/sortable_and_selectable.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_after_column_spacing_drag.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_after_column_spacing_drag.png new file mode 100644 index 0000000000..cd55e00423 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_after_column_spacing_drag.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_after_horizontal_margin_drag.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_after_horizontal_margin_drag.png new file mode 100644 index 0000000000..c80bb75fe0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_after_horizontal_margin_drag.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_compact_preset.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_compact_preset.png new file mode 100644 index 0000000000..f183d16ee5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_compact_preset.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_flow.gif new file mode 100644 index 0000000000..35d0722cf3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_compact_preset.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_compact_preset.png new file mode 100644 index 0000000000..70151eb4c6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_compact_preset.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_reset.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_reset.png new file mode 100644 index 0000000000..130ae0d218 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_reset.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_spacious_preset.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_spacious_preset.png new file mode 100644 index 0000000000..3e2773e5c1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_hover_spacious_preset.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_initial.png new file mode 100644 index 0000000000..8a4a0607d1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_reset.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_reset.png new file mode 100644 index 0000000000..dbaf1001dd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_reset.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_spacious_preset.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_spacious_preset.png new file mode 100644 index 0000000000..29a4e8fdc0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/datatable/spacing_spacious_preset.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/basic.png new file mode 100644 index 0000000000..aa22a7de46 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png new file mode 100644 index 0000000000..60cc9f42c2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/custom_locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/image_for_docs.png new file mode 100644 index 0000000000..77a998cfe7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_picker/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/basic.png new file mode 100644 index 0000000000..f4e199f93e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png new file mode 100644 index 0000000000..98f4143da1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/custom_locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/image_for_docs.png new file mode 100644 index 0000000000..8361c84847 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/date_range_picker/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/divider/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/divider/basic.png new file mode 100644 index 0000000000..859c28e420 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/divider/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/divider/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/divider/image_for_docs.png new file mode 100644 index 0000000000..c627b0df1c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/divider/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/color_selection_with_filtering_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/color_selection_with_filtering_flow.gif new file mode 100644 index 0000000000..18cace93e5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/color_selection_with_filtering_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/declarative_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/declarative_flow.gif new file mode 100644 index 0000000000..0f7379e308 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/declarative_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/icon_selection_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/icon_selection_flow.gif new file mode 100644 index 0000000000..fd8443a180 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/icon_selection_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/image_for_docs.png new file mode 100644 index 0000000000..c493489116 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/select_and_change_events_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/select_and_change_events_flow.gif new file mode 100644 index 0000000000..be12bd5be0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/select_and_change_events_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/styled_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/styled_flow.gif new file mode 100644 index 0000000000..088e142da7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown/styled_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown_m2/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown_m2/image_for_docs.png new file mode 100644 index 0000000000..b6a68250da Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/dropdown_m2/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel/image_for_docs.png new file mode 100644 index 0000000000..cf90faab70 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_flow.gif new file mode 100644 index 0000000000..58b0433f1b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_header_placeholder_closed.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_header_placeholder_closed.png new file mode 100644 index 0000000000..adca7bead0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_header_placeholder_closed.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_header_placeholder_opened.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_header_placeholder_opened.png new file mode 100644 index 0000000000..5d69f65206 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_header_placeholder_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_delete_hovered.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_delete_hovered.png new file mode 100644 index 0000000000..3010127165 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_delete_hovered.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_deleted.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_deleted.png new file mode 100644 index 0000000000..74743d2956 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_deleted.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_opened.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_opened.png new file mode 100644 index 0000000000..f53d879db7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/basic_panel_0_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/image_for_docs.png new file mode 100644 index 0000000000..0d6388de25 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/scrollable.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/scrollable.png new file mode 100644 index 0000000000..aa3808b862 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_panel_list/scrollable.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/basic.png new file mode 100644 index 0000000000..4a19f7a2fe Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_closed.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_closed.png new file mode 100644 index 0000000000..ecd8e2f2d4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_closed.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_flow.gif new file mode 100644 index 0000000000..758f997097 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_opened.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_opened.png new file mode 100644 index 0000000000..6c797fdd66 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/borders_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/custom_animations_default.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/custom_animations_default.gif new file mode 100644 index 0000000000..fa4331a825 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/custom_animations_default.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/image_for_docs.png new file mode 100644 index 0000000000..2957fff48a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_collapsed.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_collapsed.png new file mode 100644 index 0000000000..65459bac66 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_collapsed.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_flow.gif new file mode 100644 index 0000000000..29d95d15a9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_initial.png new file mode 100644 index 0000000000..1dffb83504 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/programmatic_expansion_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/theme_mode_toggle_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/theme_mode_toggle_initial.png new file mode 100644 index 0000000000..95954ea52f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/expansion_tile/theme_mode_toggle_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_button/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_button/basic.png new file mode 100644 index 0000000000..0ea095c2c4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_button/image_for_docs.png new file mode 100644 index 0000000000..44387f2791 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_icon_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_icon_button/image_for_docs.png new file mode 100644 index 0000000000..30a415e97d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_icon_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_button/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_button/basic.png new file mode 100644 index 0000000000..70fc685afa Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_button/image_for_docs.png new file mode 100644 index 0000000000..05cc332685 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_icon_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_icon_button/image_for_docs.png new file mode 100644 index 0000000000..52287b0fa7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/filled_tonal_icon_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks.gif new file mode 100644 index 0000000000..5a58647362 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks_final.png new file mode 100644 index 0000000000..a958ee6588 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks_initial.png new file mode 100644 index 0000000000..ddc6063d93 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/handling_clicks_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/image_for_docs.png new file mode 100644 index 0000000000..92bb75ac6d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/floating_action_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks.gif new file mode 100644 index 0000000000..bc2f573499 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks_final.png new file mode 100644 index 0000000000..134d21409a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks_initial.png new file mode 100644 index 0000000000..cd79a6b779 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/handling_clicks_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/image_for_docs.png new file mode 100644 index 0000000000..49c93022b9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon.gif new file mode 100644 index 0000000000..b0f1c433f1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon_final.png new file mode 100644 index 0000000000..e3df6866f8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon_initial.png new file mode 100644 index 0000000000..0605785765 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/selected_icon_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/variants.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/variants.png new file mode 100644 index 0000000000..662a06d045 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/icon_button/variants.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/list_tile/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/list_tile/basic.png new file mode 100644 index 0000000000..f2fbfbb325 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/list_tile/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/list_tile/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/list_tile/image_for_docs.png new file mode 100644 index 0000000000..8511e36f76 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/list_tile/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/image_for_docs.png new file mode 100644 index 0000000000..69d40d4f0e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus.gif new file mode 100644 index 0000000000..c7edd74583 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus_initial.png new file mode 100644 index 0000000000..6e774283c8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus_menu_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus_menu_open.png new file mode 100644 index 0000000000..718439b86d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_bar/nested_submenus_menu_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic.gif new file mode 100644 index 0000000000..dc89b68dbe Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic_initial.png new file mode 100644 index 0000000000..eb9c483029 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic_open.png new file mode 100644 index 0000000000..bd01f01511 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/basic_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/image_for_docs.png new file mode 100644 index 0000000000..4efe5672bd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/menu_item_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_bar/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_bar/basic.png new file mode 100644 index 0000000000..9ae32ca16a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_bar/image_for_docs.png new file mode 100644 index 0000000000..ea1f377cc6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation.gif new file mode 100644 index 0000000000..82167ab65d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation1.png new file mode 100644 index 0000000000..ed4e0b93f6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation2.png new file mode 100644 index 0000000000..d18d64bd26 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/adaptive_navigation2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/image_for_docs.png new file mode 100644 index 0000000000..c8767e0332 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end.gif new file mode 100644 index 0000000000..347c659a4e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end1.png new file mode 100644 index 0000000000..36f079d66b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end2.png new file mode 100644 index 0000000000..71169d8208 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end3.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end3.png new file mode 100644 index 0000000000..308cee2ec7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_end3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start.gif new file mode 100644 index 0000000000..9ebce6e525 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start1.png new file mode 100644 index 0000000000..d4ce45ca9a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start2.png new file mode 100644 index 0000000000..19081b8f69 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start3.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start3.png new file mode 100644 index 0000000000..2045615c9e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/position_start3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming.gif new file mode 100644 index 0000000000..50e98e59ff Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming1.png new file mode 100644 index 0000000000..0d5e415db7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming2.png new file mode 100644 index 0000000000..d4db5d3833 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming3.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming3.png new file mode 100644 index 0000000000..de67c24fb8 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_drawer/theming3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_rail/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_rail/basic.png new file mode 100644 index 0000000000..237e0deede Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_rail/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_rail/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_rail/image_for_docs.png new file mode 100644 index 0000000000..b85e1a8982 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/navigation_rail/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/basic.png new file mode 100644 index 0000000000..4c338c05b1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/custom_content.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/custom_content.png new file mode 100644 index 0000000000..02c55863a2 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/custom_content.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks.gif new file mode 100644 index 0000000000..949b3aa45d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks_final.png new file mode 100644 index 0000000000..ba2b3e10d1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks_initial.png new file mode 100644 index 0000000000..eb57ec581c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/handling_clicks_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/icons.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/icons.png new file mode 100644 index 0000000000..ca39f1c160 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/icons.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/image_for_docs.png new file mode 100644 index 0000000000..2ff3cf14b0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/outlined_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic.gif new file mode 100644 index 0000000000..46a83bd118 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic_initial.png new file mode 100644 index 0000000000..f8277397ec Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic_open.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic_open.png new file mode 100644 index 0000000000..9fc458eb82 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/basic_open.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/image_for_docs.png new file mode 100644 index 0000000000..958432b0f3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/popup_menu_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_bar/image_for_docs.png new file mode 100644 index 0000000000..28ff753a35 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_ring/gauge_with_progress.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_ring/gauge_with_progress.png new file mode 100644 index 0000000000..af3ce7eadc Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_ring/gauge_with_progress.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_ring/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_ring/image_for_docs.png new file mode 100644 index 0000000000..c38f40bd1d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/progress_ring/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic.gif new file mode 100644 index 0000000000..f5b8508cd4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic_final.png new file mode 100644 index 0000000000..abfcaa7a2e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic_initial.png new file mode 100644 index 0000000000..2b7cd08b10 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/basic_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes.gif new file mode 100644 index 0000000000..ca2dce73f6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes_final.png new file mode 100644 index 0000000000..7a739659dc Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes_initial.png new file mode 100644 index 0000000000..ed8659e788 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/handling_selection_changes_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/image_for_docs.png new file mode 100644 index 0000000000..5280ecedf3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled.gif new file mode 100644 index 0000000000..0d3f5c26c5 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_constant_selected.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_constant_selected.png new file mode 100644 index 0000000000..6dc623f6ad Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_constant_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_default_selected.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_default_selected.png new file mode 100644 index 0000000000..2f0dcd4fec Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_default_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_dynamic_selected.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_dynamic_selected.png new file mode 100644 index 0000000000..f3431506b9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_dynamic_selected.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_initial.png new file mode 100644 index 0000000000..ab8ed9f91b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/radio/styled_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic.gif new file mode 100644 index 0000000000..8786476703 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic1.png new file mode 100644 index 0000000000..bab6e8165f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic2.png new file mode 100644 index 0000000000..c495e7e57d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic3.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic3.png new file mode 100644 index 0000000000..f4dc2d7e96 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/basic3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events.gif new file mode 100644 index 0000000000..f796a1fa2f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events1.png new file mode 100644 index 0000000000..5b41c13662 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events2.png new file mode 100644 index 0000000000..a7aeeb5887 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events3.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events3.png new file mode 100644 index 0000000000..52271a1a64 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/handling_events3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/image_for_docs.png new file mode 100644 index 0000000000..a0a2fcb0f7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/range_slider/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic.gif new file mode 100644 index 0000000000..66c0169301 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic_initial.png new file mode 100644 index 0000000000..2786859542 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic_reordered.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic_reordered.png new file mode 100644 index 0000000000..efc8328e51 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/basic_reordered.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/image_for_docs.png new file mode 100644 index 0000000000..ae85ed35d9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_drag_handle/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_list_view/horizontal_and_vertical.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_list_view/horizontal_and_vertical.png new file mode 100644 index 0000000000..bb04343cdb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_list_view/horizontal_and_vertical.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_list_view/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_list_view/image_for_docs.png new file mode 100644 index 0000000000..e68c9ea1b9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/reorderable_list_view/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/search_bar/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/search_bar/basic.png new file mode 100644 index 0000000000..334a7f2ef4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/search_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/search_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/search_bar/image_for_docs.png new file mode 100644 index 0000000000..22d5e5c462 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/search_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/segmented_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/segmented_button/image_for_docs.png new file mode 100644 index 0000000000..6a518d720f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/segmented_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/segmented_button/single_multiple_selection.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/segmented_button/single_multiple_selection.png new file mode 100644 index 0000000000..a8b35c921b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/segmented_button/single_multiple_selection.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/selection_area/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/selection_area/basic.png new file mode 100644 index 0000000000..a662665ddf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/selection_area/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/selection_area/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/selection_area/image_for_docs.png new file mode 100644 index 0000000000..3e8bcd5c0d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/selection_area/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/basic.png new file mode 100644 index 0000000000..5a144052e4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/custom_label.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/custom_label.png new file mode 100644 index 0000000000..3379212848 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/custom_label.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/handling_events.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/handling_events.png new file mode 100644 index 0000000000..b39b1af790 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/handling_events.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/image_for_docs.png new file mode 100644 index 0000000000..ff33f19ef4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/slider/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/action_custom.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/action_custom.png new file mode 100644 index 0000000000..8c031f5321 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/action_custom.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/action_simple.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/action_simple.png new file mode 100644 index 0000000000..e9352ecb73 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/action_simple.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/basic.png new file mode 100644 index 0000000000..2b2389af46 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/before_click.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/before_click.png new file mode 100644 index 0000000000..05078e7892 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/before_click.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/click_1.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/click_1.png new file mode 100644 index 0000000000..c58272e43f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/click_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/click_2.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/click_2.png new file mode 100644 index 0000000000..80ee9bfe16 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/click_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/image_for_docs.png new file mode 100644 index 0000000000..ff7b8adf3d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/snack_bar_flow.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/snack_bar_flow.gif new file mode 100644 index 0000000000..5f0ad99cf6 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/snack_bar/snack_bar_flow.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/basic.png new file mode 100644 index 0000000000..ce7976851c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/image_for_docs.png new file mode 100644 index 0000000000..63fb0ea8bc Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/standalone_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/standalone_initial.png new file mode 100644 index 0000000000..09765548bb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/submenu_button/standalone_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/basic.png new file mode 100644 index 0000000000..cdd89d3d7e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events.gif new file mode 100644 index 0000000000..0d97de13ab Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events_final.png new file mode 100644 index 0000000000..52a3d89c3e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events_initial.png new file mode 100644 index 0000000000..520990d2a9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/handling_events_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/image_for_docs.png new file mode 100644 index 0000000000..d30be93853 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/switch/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/tabs/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/tabs/image_for_docs.png new file mode 100644 index 0000000000..bd5c82716c Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/tabs/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/basic.png new file mode 100644 index 0000000000..71a29a66ad Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/custom_content.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/custom_content.png new file mode 100644 index 0000000000..54a7a84ad4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/custom_content.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/handling_clicks.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/handling_clicks.png new file mode 100644 index 0000000000..48963ca676 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/handling_clicks.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/icons.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/icons.png new file mode 100644 index 0000000000..05f0634d95 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/icons.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/image_for_docs.png new file mode 100644 index 0000000000..177679290d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/text_button/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/basic.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/basic.png new file mode 100644 index 0000000000..24cfed8663 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events.gif new file mode 100644 index 0000000000..03ca477123 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events_final.png new file mode 100644 index 0000000000..df330fad4e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events_initial.png new file mode 100644 index 0000000000..56ca678f55 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/handling_change_events_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/image_for_docs.png new file mode 100644 index 0000000000..211a98fbf7 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter.gif new file mode 100644 index 0000000000..18d0bbbb68 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter_final.png new file mode 100644 index 0000000000..adfab8939f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter_initial.png new file mode 100644 index 0000000000..2b90af3427 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/label_hint_helper_counter_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline.gif new file mode 100644 index 0000000000..7315a46d61 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline_final.png new file mode 100644 index 0000000000..c0752763e1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline_initial.png new file mode 100644 index 0000000000..0a797d837b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/multiline_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password.gif new file mode 100644 index 0000000000..6a20521a11 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password_final.png new file mode 100644 index 0000000000..fa3a7a1bf0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password_initial.png new file mode 100644 index 0000000000..6642745fa1 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/password_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix.gif new file mode 100644 index 0000000000..355f0caf8e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix_final.png new file mode 100644 index 0000000000..684faf54c0 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix_initial.png new file mode 100644 index 0000000000..6d2ead0788 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/prefix_and_suffix_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change.gif new file mode 100644 index 0000000000..ddd20a8ced Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change_final.png new file mode 100644 index 0000000000..4ec277da74 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change_initial.png new file mode 100644 index 0000000000..e26b8d84fb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/selection_change_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled.gif new file mode 100644 index 0000000000..f3690a821d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled_final.png new file mode 100644 index 0000000000..2a0d549e03 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled_initial.png new file mode 100644 index 0000000000..6da772b82b Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/styled_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless.gif new file mode 100644 index 0000000000..1f528f1836 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless_final.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless_final.png new file mode 100644 index 0000000000..1befdd8ae3 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless_final.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless_initial.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless_initial.png new file mode 100644 index 0000000000..94f015f2ce Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/textfield/underlined_and_borderless_initial.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic.gif new file mode 100644 index 0000000000..ee4106708a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic_confirm_hover.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic_confirm_hover.png new file mode 100644 index 0000000000..9107b218fd Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic_confirm_hover.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic_opened.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic_opened.png new file mode 100644 index 0000000000..9caf941d8a Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/basic_opened.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/custom_locale.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/custom_locale.png new file mode 100644 index 0000000000..46025a460d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/custom_locale.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats.gif b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats.gif new file mode 100644 index 0000000000..3d4c2d979f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats.gif differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats_opened_12h.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats_opened_12h.png new file mode 100644 index 0000000000..9d5f33337e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats_opened_12h.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats_opened_24h.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats_opened_24h.png new file mode 100644 index 0000000000..33ac692e98 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/hour_formats_opened_24h.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/image_for_docs.png new file mode 100644 index 0000000000..c8e716a2f4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/controls/material/golden/macos/time_picker/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_alert_dialog.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_alert_dialog.py new file mode 100644 index 0000000000..89b997b290 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_alert_dialog.py @@ -0,0 +1,137 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.alert_dialog.modal_and_non_modal import ( + main as modal_and_non_modal, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 300) + flet_app_function.page.update() + + flet_app_function.page.show_dialog( + ft.AlertDialog( + title=ft.Text("Session expired"), + content=ft.Text("Please sign in again to continue."), + actions=[ft.TextButton("Dismiss")], + open=True, + ) + ) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "test_image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": modal_and_non_modal.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + button = await flet_app_function.tester.find_by_text_containing("Open dialog") + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "non_modal_dialog", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.page.pop_dialog() + await flet_app_function.tester.pump_and_settle() + modal_button = await flet_app_function.tester.find_by_text_containing( + "Open modal dialog" + ) + await flet_app_function.tester.tap(modal_button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "modal_dialog", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["before_click", "non_modal_dialog", "before_click", "modal_dialog"], + "alert_dialog_flow", + duration=2000, + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_use_dialog_dismiss_fires_after_animation( + flet_app_function: ftt.FletTestApp, +): + @ft.component + def App(): + show, set_show = ft.use_state(False) + status, set_status = ft.use_state("waiting") + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete report.pdf?"), + content=ft.Text("This cannot be undone."), + actions=[ + ft.TextButton("Close", on_click=lambda: set_show(False)), + ], + on_dismiss=lambda: set_status("dismissed"), + ) + if show + else None + ) + + return ft.Column( + controls=[ + ft.Text(status), + ft.TextButton("Open", on_click=lambda: set_show(True)), + ] + ) + + flet_app_function.page.render(App) + await flet_app_function.tester.pump_and_settle() + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Open") + ) + await flet_app_function.tester.pump_and_settle() + + assert (await flet_app_function.tester.find_by_text("waiting")).count == 1 + assert ( + await flet_app_function.tester.find_by_text("Delete report.pdf?") + ).count == 1 + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Close") + ) + await flet_app_function.tester.pump() + + assert (await flet_app_function.tester.find_by_text("dismissed")).count == 0 + assert (await flet_app_function.tester.find_by_text("waiting")).count == 1 + + await flet_app_function.tester.pump_and_settle() + + assert (await flet_app_function.tester.find_by_text("dismissed")).count == 1 + assert ( + await flet_app_function.tester.find_by_text("Delete report.pdf?") + ).count == 0 diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_app_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_app_bar.py new file mode 100644 index 0000000000..f6640e7eda --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_app_bar.py @@ -0,0 +1,144 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.app_bar.actions_and_popup_menu import ( + main as actions_and_popup_menu, +) +from examples.controls.material.app_bar.theme_mode_toggle import ( + main as theme_mode_toggle, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.AppBar( + leading=ft.Icon(ft.Icons.MENU), + title=ft.Text("Dashboard"), + actions=[ + ft.IconButton(ft.Icons.SEARCH), + ft.IconButton(ft.Icons.MORE_VERT), + ], + bgcolor=ft.Colors.SURFACE_CONTAINER, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": actions_and_popup_menu.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_actions_and_popup_menu(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + button = await flet_app_function.tester.find_by_key("popup") + await flet_app_function.tester.mouse_hover(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "hover_popup", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "popup_open", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + checked_item = await flet_app_function.tester.find_by_text("Checked item") + await flet_app_function.tester.mouse_hover(checked_item) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "hover_checked_item", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap(checked_item) + await flet_app_function.tester.pump_and_settle() + + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "checked_item_reopened", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + [ + "before_click", + "hover_popup", + "popup_open", + "hover_checked_item", + "checked_item_reopened", + ], + "app_bar_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": theme_mode_toggle.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_mode_toggle(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 450) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "theme_mode_before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + toggle_button = await flet_app_function.tester.find_by_key("theme_mode_toggle") + await flet_app_function.tester.mouse_hover(toggle_button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "theme_mode_hover", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap(toggle_button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "theme_mode_after_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + [ + "theme_mode_before_click", + "theme_mode_hover", + "theme_mode_after_click", + ], + "theme_mode_toggle_flow", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py new file mode 100644 index 0000000000..a6c03d3132 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_auto_complete.py @@ -0,0 +1,41 @@ +import pytest + +import flet.testing as ftt +from examples.controls.material.auto_complete.basic import main as basic + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic_example_opens_suggestions(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + text_field = await flet_app_function.tester.find_by_text("One") + await flet_app_function.tester.tap(text_field) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "after_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["before_click", "after_click"], + "auto_complete_basic_flow", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py new file mode 100644 index 0000000000..a15a01ecf6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_badge.py @@ -0,0 +1,39 @@ +import pytest + +import examples.controls.material.badge.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Container( + padding=10, + content=ft.FilledIconButton( + icon=ft.Icons.PHONE, + badge=ft.Badge(label="3"), + ), + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py new file mode 100644 index 0000000000..2863d50e56 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_banner.py @@ -0,0 +1,104 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.banner.basic import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + page = flet_app_function.page + page.theme_mode = ft.ThemeMode.LIGHT + page.enable_screenshots = True + flet_app_function.resize_page(400, 200) + banner = ft.Banner( + leading=ft.Icon(ft.Icons.INFO_OUTLINED, color=ft.Colors.PRIMARY), + content=ft.Text("Backup completed successfully."), + actions=[ft.TextButton("Dismiss")], + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + open=True, + ) + page.add(banner) + page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "test_image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + page.update() + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic_banner_flow(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + show_banner_button = await flet_app_function.tester.find_by_text("Show Banner") + await flet_app_function.tester.mouse_hover(show_banner_button) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "hover_show_banner", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(show_banner_button) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "banner_open", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + ignore_button = await flet_app_function.tester.find_by_text("Ignore") + await flet_app_function.tester.mouse_hover(ignore_button) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "hover_ignore", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(ignore_button) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "after_ignore", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + [ + "before_click", + "hover_show_banner", + "banner_open", + "hover_ignore", + "after_ignore", + ], + "banner_flow", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_app_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_app_bar.py new file mode 100644 index 0000000000..7407c5b0e8 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_app_bar.py @@ -0,0 +1,69 @@ +import pytest + +import examples.controls.material.bottom_app_bar.border_radius.main as border_radius +import examples.controls.material.bottom_app_bar.notched_fab.main as notched_fab +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(400, 400) + + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.BottomAppBar( + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.IconButton(ft.Icons.MENU), + ft.IconButton(ft.Icons.SEARCH), + ft.IconButton(ft.Icons.SETTINGS), + ], + ), + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": border_radius.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_border_radius(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(500, 400) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "border_radius", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": notched_fab.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_notched_fab(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(500, 400) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "notched_fab", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py new file mode 100644 index 0000000000..4b3ff641db --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_bottom_sheet.py @@ -0,0 +1,147 @@ +import pytest + +import examples.controls.material.bottom_sheet.basic.main as basic +import examples.controls.material.bottom_sheet.fullscreen.main as fullscreen +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(200, 200) + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + + sheet = ft.BottomSheet( + content=ft.Column( + width=150, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Choose an option"), + ft.TextButton("Dismiss"), + ], + ) + ) + flet_app_function.page.show_dialog(sheet) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 450) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # open bottom sheet + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Display bottom sheet") + ) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # create gif + flet_app_function.create_gif( + [f"basic_{i}" for i in range(1, 3)], + output_name="basic", + duration=2000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": fullscreen.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_fullscreen(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 450) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "fullscreen_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # open bottom sheet + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Display bottom sheet") + ) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "fullscreen_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # close bottom sheet + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Close bottom sheet") + ) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "fullscreen_3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # toggle switch + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Fullscreen") + ) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "fullscreen_4", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # open bottom sheet + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Display bottom sheet") + ) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "fullscreen_5", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # create gif + flet_app_function.create_gif( + [f"fullscreen_{i}" for i in range(1, 6)], + output_name="fullscreen", + duration=2000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py new file mode 100644 index 0000000000..cc6b68a756 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_button.py @@ -0,0 +1,138 @@ +import pytest + +import examples.controls.material.button.animate_on_hover.main as animate_on_hover +import examples.controls.material.button.basic.main as basic +import examples.controls.material.button.button_shapes.main as button_shapes +import examples.controls.material.button.custom_content.main as custom_content +import examples.controls.material.button.handling_clicks.main as handling_clicks +import examples.controls.material.button.icons.main as icons +import examples.controls.material.button.styling.main as styling +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + [ + ft.Button(content="Enabled button"), + ft.Button(content="Disabled button", disabled=True), + ] + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": icons.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_icons(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "icons", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_content.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_content(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "custom_content", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_clicks.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_clicks(flet_app_function: ftt.FletTestApp): + scr = await flet_app_function.wrap_page_controls_in_screenshot() + button = await flet_app_function.tester.find_by_text("Button with 'click' event") + await flet_app_function.tester.tap(button) + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_clicks", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": button_shapes.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_button_shapes(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "button_shapes", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": styling.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_styling(flet_app_function: ftt.FletTestApp): + scr = await flet_app_function.wrap_page_controls_in_screenshot() + flet_app_function.assert_screenshot( + "styled_initial", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + button = await flet_app_function.tester.find_by_text_containing("Styled") + await flet_app_function.tester.mouse_hover(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "styled_hovered", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": animate_on_hover.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_animate_on_hover(flet_app_function: ftt.FletTestApp): + scr = await flet_app_function.wrap_page_controls_in_screenshot(margin=20) + flet_app_function.assert_screenshot( + "animate_on_hover_initial", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + button = await flet_app_function.tester.find_by_text_containing("Hover over me") + await flet_app_function.tester.mouse_hover(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "animate_on_hover_hovered", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + similarity_threshold=98.8, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_card.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_card.py new file mode 100644 index 0000000000..d6f8da03ef --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_card.py @@ -0,0 +1,40 @@ +import pytest + +import examples.controls.material.card.music_info.main as music_info +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Card( + shadow_color=ft.Colors.ON_SURFACE_VARIANT, + content=ft.Container( + width=400, + padding=10, + content=ft.ListTile( + bgcolor=ft.Colors.GREY_400, + leading=ft.Icon(ft.Icons.FOREST), + title=ft.Text("Card Name"), + ), + ), + ), + similarity_threshold=98.4, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": music_info.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_music_info(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "music_info", + await flet_app_function.take_page_controls_screenshot(), + similarity_threshold=98.8, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py new file mode 100644 index 0000000000..bc51199ab2 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_checkbox.py @@ -0,0 +1,101 @@ +import pytest + +import examples.controls.material.checkbox.basic.main as basic +import examples.controls.material.checkbox.handling_events.main as handling_events +import examples.controls.material.checkbox.styled.main as styled +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[ + ft.Checkbox(), + ft.Checkbox(label="Checked", value=True), + ft.Checkbox(label="Disabled", disabled=True), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + button = await flet_app_function.tester.find_by_text("Submit") + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_events.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_events(flet_app_function: ftt.FletTestApp): + checkbox = await flet_app_function.tester.find_by_text( + "Checkbox with 'change' event" + ) + await flet_app_function.tester.tap(checkbox) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.tap(checkbox) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.tap(checkbox) + await flet_app_function.tester.pump_and_settle() + scr = await flet_app_function.wrap_page_controls_in_screenshot() + flet_app_function.assert_screenshot( + "handling_events", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": styled.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_styled(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + scr = await flet_app_function.wrap_page_controls_in_screenshot() + flet_app_function.assert_screenshot( + "styled_checkboxes", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + checkbox = await flet_app_function.tester.find_by_key("dynamic_fill_checkbox") + await flet_app_function.tester.mouse_hover(checkbox) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "styled_checkboxes_hovered", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + await flet_app_function.tester.tap(checkbox) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "styled_checkboxes_selected", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) + flet_app_function.create_gif( + [ + "styled_checkboxes", + "styled_checkboxes_hovered", + "styled_checkboxes_selected", + ], + "styled_checkboxes_flow", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_chip.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_chip.py new file mode 100644 index 0000000000..961a0aef06 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_chip.py @@ -0,0 +1,67 @@ +import pytest + +import examples.controls.material.chip.assist_chips.main as assist_chips +import examples.controls.material.chip.filter_chips.main as filter_chips +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Chip( + label="Explore topics", + leading=ft.Icon(ft.Icons.EXPLORE_OUTLINED), + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": assist_chips.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_assist_chips(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 220) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "assist_chips", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": filter_chips.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_filter_chips(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(950, 250) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + dogs_ok = await flet_app_function.tester.find_by_text("Dogs OK") + await flet_app_function.tester.tap(dogs_ok) + await flet_app_function.tester.pump_and_settle() + + cats_ok = await flet_app_function.tester.find_by_text("Cats OK") + await flet_app_function.tester.tap(cats_ok) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "filter_chips", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_circle_avatar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_circle_avatar.py new file mode 100644 index 0000000000..d49c37bc81 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_circle_avatar.py @@ -0,0 +1,38 @@ +import pytest + +import examples.controls.material.circle_avatar.user_avatars.main as user_avatars +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.CircleAvatar( + content=ft.Text("AB"), + bgcolor=ft.Colors.PRIMARY, + color=ft.Colors.ON_PRIMARY, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": user_avatars.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_user_avatars(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(180, 260) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "user_avatars", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_context_menu.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_context_menu.py new file mode 100644 index 0000000000..ce67961754 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_context_menu.py @@ -0,0 +1,155 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.context_menu.custom_trigger import ( + main as custom_trigger, +) +from examples.controls.material.context_menu.programmatic_open import ( + main as programmatic_open, +) +from examples.controls.material.context_menu.triggers import main as triggers + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(250, 200) + flet_app_function.page.add( + menu := ft.ContextMenu( + content=ft.IconButton(ft.Icons.MENU), + items=[ + ft.PopupMenuItem("Rename"), + ft.PopupMenuItem("Duplicate"), + ], + ) + ) + await flet_app_function.tester.pump_and_settle() + + # open menu + await menu.open() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": triggers.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_triggers(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + trigger_area = await flet_app_function.tester.find_by_key( + "context_menu_trigger_area" + ) + await flet_app_function.tester.mouse_click(trigger_area) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "left_click_open", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap_at(ft.Offset(20, 20)) + await flet_app_function.tester.pump_and_settle() + + await flet_app_function.tester.right_mouse_click(trigger_area) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "right_click_open", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["before_click", "left_click_open", "right_click_open"], + "triggers_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_trigger.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_trigger(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "before_double_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + trigger_area = await flet_app_function.tester.find_by_key( + "context_menu_custom_trigger_area" + ) + await flet_app_function.tester.mouse_double_click(trigger_area) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "after_double_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["before_double_click", "after_double_click"], + "custom_trigger_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": programmatic_open.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_programmatic_open(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + # click button to open menu + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Click to open menu") + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + test_programmatic_open.__name__, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py new file mode 100644 index 0000000000..50647fd3e9 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_datatable.py @@ -0,0 +1,306 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.data_table.adaptive_row_heights import ( + main as adaptive_row_heights, +) +from examples.controls.material.data_table.basic import main as basic +from examples.controls.material.data_table.handling_events import ( + main as handling_events, +) +from examples.controls.material.data_table.sortable_and_selectable import ( + main as sortable_and_selectable, +) +from examples.controls.material.data_table.spacing import main as spacing + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.DataTable( + columns=[ + ft.DataColumn(label=ft.Text("Name")), + ft.DataColumn(label=ft.Text("Role")), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Alice")), + ft.DataCell(ft.Text("Engineer")), + ] + ), + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Bob")), + ft.DataCell(ft.Text("Designer")), + ] + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(355, 260) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": sortable_and_selectable.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_sortable_and_selectable(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(500, 620) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "sortable_and_selectable", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": adaptive_row_heights.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_adaptive_row_heights(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(620, 420) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "adaptive_row_heights", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_events.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_events(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(760, 380) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events_initial", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + row_a = await flet_app_function.tester.find_by_text("A") + await flet_app_function.tester.mouse_hover(row_a) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events_hover_row_a", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(row_a) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events_click_row_a", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + column_1 = await flet_app_function.tester.find_by_text("Column 1") + await flet_app_function.tester.mouse_hover(column_1) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events_hover_column_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(column_1) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events_click_column_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + [ + "handling_events_initial", + "handling_events_hover_row_a", + "handling_events_click_row_a", + "handling_events_hover_column_1", + "handling_events_click_column_1", + ], + "handling_events_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": spacing.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_spacing(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(700, 500) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "spacing_initial", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + horizontal_margin_slider = await flet_app_function.tester.find_by_key( + "horizontal_margin_slider" + ) + await flet_app_function.tester.drag( + horizontal_margin_slider, + ft.Offset(120, 0), + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_after_horizontal_margin_drag", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + column_spacing_slider = await flet_app_function.tester.find_by_key( + "column_spacing_slider" + ) + await flet_app_function.tester.drag( + column_spacing_slider, + ft.Offset(120, 0), + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_after_column_spacing_drag", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + compact_preset = await flet_app_function.tester.find_by_text("Compact preset") + await flet_app_function.tester.mouse_hover(compact_preset) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_hover_compact_preset", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(compact_preset) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_compact_preset", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + spacious_preset = await flet_app_function.tester.find_by_text("Spacious preset") + await flet_app_function.tester.mouse_hover(spacious_preset) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_hover_spacious_preset", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(spacious_preset) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_spacious_preset", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + reset_button = await flet_app_function.tester.find_by_text("Reset") + await flet_app_function.tester.mouse_hover(reset_button) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_hover_reset", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(reset_button) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "spacing_reset", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + [ + "spacing_initial", + "spacing_after_horizontal_margin_drag", + "spacing_after_column_spacing_drag", + "spacing_hover_compact_preset", + "spacing_compact_preset", + "spacing_hover_spacious_preset", + "spacing_spacious_preset", + "spacing_hover_reset", + "spacing_reset", + ], + "spacing_flow", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py new file mode 100644 index 0000000000..a0f8c1b2ce --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_picker.py @@ -0,0 +1,81 @@ +import datetime + +import pytest + +import examples.controls.material.date_picker.basic.main as basic +import examples.controls.material.date_picker.custom_locale.main as custom_locale +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 520) + flet_app_function.page.update() + + flet_app_function.page.show_dialog( + ft.DatePicker( + value=datetime.datetime(2025, 4, 15), + first_date=datetime.datetime(2024, 1, 1), + last_date=datetime.datetime(2026, 12, 31), + current_date=datetime.datetime(2025, 4, 15), + ) + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 520) + flet_app_function.page.update() + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Pick date") + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_locale.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_locale(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 520) + flet_app_function.page.update() + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Pick date (zh_Hans locale)") + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "custom_locale", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py new file mode 100644 index 0000000000..c15a68c653 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_date_range_picker.py @@ -0,0 +1,82 @@ +import datetime + +import pytest + +import examples.controls.material.date_range_picker.basic.main as basic +import examples.controls.material.date_range_picker.custom_locale.main as custom_locale +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(620, 480) + flet_app_function.page.update() + + flet_app_function.page.show_dialog( + ft.DateRangePicker( + start_value=datetime.datetime(2025, 4, 10), + end_value=datetime.datetime(2025, 4, 20), + first_date=datetime.datetime(2024, 1, 1), + last_date=datetime.datetime(2026, 12, 31), + current_date=datetime.datetime(2025, 4, 15), + ) + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(620, 480) + flet_app_function.page.update() + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Pick date range") + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_locale.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_locale(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(620, 480) + flet_app_function.page.update() + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Pick dates (zh_Hans locale)") + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "custom_locale", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py new file mode 100644 index 0000000000..64b7acdb40 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_divider.py @@ -0,0 +1,42 @@ +import pytest + +import examples.controls.material.divider.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + width=240, + spacing=10, + controls=[ + ft.Text("Section A", weight=ft.FontWeight.W_600), + ft.Divider(), + ft.Text("Section B"), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(320, 480) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_dropdown.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_dropdown.py new file mode 100644 index 0000000000..78c1a3bb0f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_dropdown.py @@ -0,0 +1,278 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.dropdown.color_selection_with_filtering import ( + main as color_selection_with_filtering, +) +from examples.controls.material.dropdown.declarative import main as declarative +from examples.controls.material.dropdown.icon_selection import main as icon_selection +from examples.controls.material.dropdown.select_and_change_events import ( + main as select_and_change_events, +) +from examples.controls.material.dropdown.styled import main as styled + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Dropdown( + width=220, + value="alice", + options=[ + ft.dropdown.Option(key="alice", text="Alice"), + ft.dropdown.Option(key="bob", text="Bob"), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": color_selection_with_filtering.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_color_selection_with_filtering(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + frames: list[bytes] = [ + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ] + + dropdown = await flet_app_function.tester.find_by_key("color_dropdown") + await flet_app_function.tester.tap(dropdown) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.enter_text(dropdown, "re") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + red_options = await flet_app_function.tester.find_by_text("red") + assert red_options.count >= 1 + await flet_app_function.tester.tap(red_options.last) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="color_selection_with_filtering_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": icon_selection.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_icon_selection(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + frames: list[bytes] = [ + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ] + + dropdown = await flet_app_function.tester.find_by_key("icon_dropdown") + await flet_app_function.tester.tap(dropdown) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + heart_options = await flet_app_function.tester.find_by_icon(ft.Icons.FAVORITE) + assert heart_options.count >= 1 + await flet_app_function.tester.tap(heart_options.last) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="icon_selection_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": declarative.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_declarative(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(360, 260) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + frames: list[bytes] = [ + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ] + + dropdown = await flet_app_function.tester.find_by_key("declarative_dropdown") + await flet_app_function.tester.tap(dropdown) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + green_option = await flet_app_function.tester.find_by_text("Green") + assert green_option.count >= 1 + await flet_app_function.tester.tap(green_option.last) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="declarative_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": select_and_change_events.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_select_and_change_events(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(380, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + frames: list[bytes] = [] + dropdown = await flet_app_function.tester.find_by_key("select_change_dropdown") + await flet_app_function.tester.tap(dropdown) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + red_option = await flet_app_function.tester.find_by_text("red") + assert red_option.count >= 1 + await flet_app_function.tester.mouse_hover(red_option.last) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + await flet_app_function.tester.tap(red_option.last) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.enter_text(dropdown, "deep_red") + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.tap_at(ft.Offset(10, 10)) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="select_and_change_events_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": styled.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_styled(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 600) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + frames = [ + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ] + + for index in range(1, 6): + dropdown = await flet_app_function.tester.find_by_key( + f"styled_dropdown_{index}" + ) + await flet_app_function.tester.tap(dropdown) + await flet_app_function.tester.pump_and_settle() + + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + selected_option = await flet_app_function.tester.find_by_text(f"Style {index}B") + assert selected_option.count >= 1 + await flet_app_function.tester.tap(selected_option.last) + await flet_app_function.tester.pump_and_settle() + + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="styled_flow", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_dropdown_m2.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_dropdown_m2.py new file mode 100644 index 0000000000..55f3ca06a6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_dropdown_m2.py @@ -0,0 +1,20 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.DropdownM2( + width=220, + value="Alice", + options=[ + ft.dropdownm2.Option(key="Alice", text="Alice"), + ft.dropdownm2.Option(key="Bob", text="Bob"), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel.py new file mode 100644 index 0000000000..8bdf896482 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel.py @@ -0,0 +1,26 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ExpansionPanelList( + width=400, + controls=[ + ft.ExpansionPanel( + header=ft.Text("Shipping address"), + content=ft.Text("123 Market Street, Springfield"), + expanded=True, + ), + ft.ExpansionPanel( + header=ft.Text("Billing address"), + content=ft.Text("Same as shipping"), + ), + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py new file mode 100644 index 0000000000..85133eb149 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_panel_list.py @@ -0,0 +1,130 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.expansion_panel_list.basic import main as basic +from examples.controls.material.expansion_panel_list.scrollable import ( + main as scrollable, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ExpansionPanelList( + width=400, + controls=[ + ft.ExpansionPanel( + header=ft.Text("Details"), + content=ft.Text("More information here"), + expanded=True, + ), + ft.ExpansionPanel( + header=ft.Text("History"), + content=ft.Text("View previous updates"), + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 500) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic_header_placeholder_opened", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + expand_icons = await flet_app_function.tester.find_by_icon(ft.Icons.EXPAND_MORE) + assert expand_icons.count >= 1 + await flet_app_function.tester.tap(expand_icons.first) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic_header_placeholder_closed", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + expand_icons = await flet_app_function.tester.find_by_icon(ft.Icons.EXPAND_MORE) + assert expand_icons.count >= 2 + await flet_app_function.tester.tap(expand_icons.at(1)) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic_panel_0_opened", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + delete_icons = await flet_app_function.tester.find_by_icon(ft.Icons.DELETE) + assert delete_icons.count >= 1 + await flet_app_function.tester.mouse_hover(delete_icons.first) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic_panel_0_delete_hovered", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(delete_icons.first) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "basic_panel_0_deleted", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + [ + "basic_header_placeholder_opened", + "basic_header_placeholder_closed", + "basic_panel_0_opened", + "basic_panel_0_delete_hovered", + "basic_panel_0_deleted", + ], + "basic_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": scrollable.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_scrollable(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 500) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "scrollable", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py new file mode 100644 index 0000000000..1f844a853f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_expansion_tile.py @@ -0,0 +1,239 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.expansion_tile.basic import main as basic +from examples.controls.material.expansion_tile.borders import main as borders +from examples.controls.material.expansion_tile.custom_animations import ( + main as custom_animations, +) +from examples.controls.material.expansion_tile.programmatic_expansion import ( + main as programmatic_expansion, +) +from examples.controls.material.expansion_tile.theme_mode_toggle import ( + main as theme_mode_toggle, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ExpansionTile( + width=400, + title="Account", + subtitle="Manage profile and security", + expanded=True, + controls=[ + ft.ListTile(title=ft.Text("Profile")), + ft.ListTile(title=ft.Text("Security")), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + test_basic.__name__, + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": borders.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_borders(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(460, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "borders_closed", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + expand_icons = await flet_app_function.tester.find_by_icon(ft.Icons.EXPAND_MORE) + assert expand_icons.count >= 1 + await flet_app_function.tester.tap(expand_icons.first) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "borders_opened", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["borders_closed", "borders_opened"], + "borders_flow", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_animations.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_animations_default(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(460, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + # Pre-tap frame — GIF will hold this for 2 s so the viewer sees the + # expanded tile before the collapse starts. + pre_tap_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + + expand_icons = await flet_app_function.tester.find_by_icon(ft.Icons.EXPAND_MORE) + assert expand_icons.count >= 1 + await flet_app_function.tester.tap(expand_icons.first) + + # ExpansionTile's default animation is 200 ms and renders at 60 Hz vsync, + # so it produces ~12 distinct pixel-level states. Sample at ~vsync + # spacing — no point oversampling, neighbors would be pixel-identical. + frame_delays_ms = [0] + [17] * 13 + [50] + animation_frames = await flet_app_function.page.take_animation( + "default_animation", + frame_delays_ms, + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + + # Play back at 80 ms/frame, hold the first frame for 2 s and the final + # settled frame for 3 s before the GIF loops. + frames = [pre_tap_frame, *animation_frames] + durations = [2000] + [80] * (len(animation_frames) - 1) + [3000] + flet_app_function.create_gif( + frames=frames, + output_name="custom_animations_default", + duration=durations, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": programmatic_expansion.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_programmatic_expansion(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(520, 320) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + frame_delays_ms = [0] + [17] * 13 + [50] + frames: list[bytes] = [] + durations: list[int] = [] + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "programmatic_expansion_initial", + initial_frame, + ) + frames.append(initial_frame) + durations.append(1200) + + collapse_button = await flet_app_function.tester.find_by_text("Collapse Tile") + await flet_app_function.tester.mouse_hover(collapse_button) + await flet_app_function.tester.pump_and_settle() + hover_collapse_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + frames.append(hover_collapse_frame) + durations.append(1000) + + await flet_app_function.tester.tap(collapse_button) + collapse_animation_frames = await flet_app_function.page.take_animation( + "programmatic_expansion_collapse", + frame_delays_ms, + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + collapsed_frame = collapse_animation_frames[-1] + flet_app_function.assert_screenshot( + "programmatic_expansion_collapsed", + collapsed_frame, + ) + frames.extend(collapse_animation_frames) + durations.extend([80] * (len(collapse_animation_frames) - 1) + [1000]) + + expand_button = await flet_app_function.tester.find_by_text("Expand Tile") + await flet_app_function.tester.mouse_hover(expand_button) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + durations.append(1000) + + await flet_app_function.tester.tap(expand_button) + expand_animation_frames = await flet_app_function.page.take_animation( + "programmatic_expansion_expand", + frame_delays_ms, + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + frames.extend(expand_animation_frames) + durations.extend([80] * (len(expand_animation_frames) - 1) + [1500]) + + flet_app_function.create_gif( + frames=frames, + output_name="programmatic_expansion_flow", + duration=durations, + ) + + +@pytest.mark.skip(reason="Will fix it later") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": theme_mode_toggle.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_theme_mode_toggle_top_panel(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(500, 700) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + + top_panel = await flet_app_function.tester.find_by_key( + "theme_mode_toggle_top_panel" + ) + await flet_app_function.tester.tap(top_panel) + await flet_app_function.tester.pump_and_settle() + expanded_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + + flet_app_function.create_gif( + frames=[initial_frame, expanded_frame], + output_name="theme_mode_toggle_top_panel_flow", + duration=[1200, 1500], + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py new file mode 100644 index 0000000000..1c3def9627 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_button.py @@ -0,0 +1,28 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.filled_button.basic import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.FilledButton(content="Tap me"), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_icon_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_icon_button.py new file mode 100644 index 0000000000..db6378ffdc --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_icon_button.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.FilledIconButton(icon=ft.Icons.CHECK), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py new file mode 100644 index 0000000000..a2cc355d93 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_button.py @@ -0,0 +1,28 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.filled_tonal_button.basic import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.FilledTonalButton(content="Tap me"), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_icon_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_icon_button.py new file mode 100644 index 0000000000..19c6e08935 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_filled_tonal_icon_button.py @@ -0,0 +1,13 @@ +import pytest + +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.FilledTonalIconButton(icon=ft.Icons.CHECK), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_floating_action_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_floating_action_button.py new file mode 100644 index 0000000000..4ce7b251fc --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_floating_action_button.py @@ -0,0 +1,97 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.floating_action_button.handling_clicks import ( + main as handling_clicks, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.FloatingActionButton(icon=ft.Icons.ADD), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_clicks.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_clicks(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 520) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_clicks_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + fab = await flet_app_function.tester.find_by_key("handling_clicks_fab") + await flet_app_function.tester.mouse_hover(fab) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(fab) + await flet_app_function.tester.pump_and_settle() + last_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_clicks_final", + last_frame, + ) + frames.append(last_frame) + + await flet_app_function.tester.mouse_hover(fab) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(fab) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.mouse_hover(fab) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(fab) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="handling_clicks", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_icon_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_icon_button.py new file mode 100644 index 0000000000..3d0d98b6b6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_icon_button.py @@ -0,0 +1,153 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.icon_button.handling_clicks import ( + main as handling_clicks, +) +from examples.controls.material.icon_button.selected_icon import ( + main as selected_icon, +) +from examples.controls.material.icon_button.variants import ( + main as variants, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.IconButton(icon=ft.Icons.FAVORITE, icon_color=ft.Colors.PRIMARY), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_clicks.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_clicks(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(320, 220) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_clicks_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + button = await flet_app_function.tester.find_by_key("handling_clicks_icon_button") + await flet_app_function.tester.mouse_hover(button) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_clicks_final", + final_frame, + ) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, + output_name="handling_clicks", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": selected_icon.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_selected_icon(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(320, 240) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "selected_icon_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + button = await flet_app_function.tester.find_by_key("selected_icon_button") + await flet_app_function.tester.mouse_hover(button) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "selected_icon_final", + final_frame, + ) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, + output_name="selected_icon", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": variants.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_variants(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(640, 420) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "variants", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py new file mode 100644 index 0000000000..68ebec6a0f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_list_tile.py @@ -0,0 +1,43 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.list_tile.basic import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ListTile( + width=400, + leading=ft.Icon(ft.Icons.ACCOUNT_CIRCLE), + title="Jane Doe", + subtitle="Product Manager", + trailing=ft.Icon(ft.Icons.CHEVRON_RIGHT), + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + ), + ) + + +# @pytest.mark.skip(reason="Will fix later") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(560, 620) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + # Asset-backed Image in the example needs one timed pump to finish painting. + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot( + pump_times=7, + pump_duration=1000, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_bar.py new file mode 100644 index 0000000000..2ee2c791b4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_bar.py @@ -0,0 +1,100 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.menu_bar.nested_submenus import main as nested_submenus + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(150, 200) + flet_app_function.page.update() + mb = ft.MenuBar( + controls=[ + ft.SubmenuButton( + content=ft.Text("Submenu"), + controls=[ + ft.MenuItemButton(content=ft.Text("Item 1")), + ft.MenuItemButton(content=ft.Text("Item 2")), + ft.MenuItemButton(content=ft.Text("Item 3")), + ], + ), + ], + ) + flet_app_function.page.add(mb) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + btn = await flet_app_function.tester.find_by_text("Submenu") + await flet_app_function.tester.tap(btn) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": nested_submenus.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_nested_submenus(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "nested_submenus_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + smb = await flet_app_function.tester.find_by_text("File") + await flet_app_function.tester.mouse_hover(smb) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + await flet_app_function.tester.tap(smb) + await flet_app_function.tester.pump_and_settle() + menu_open_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "nested_submenus_menu_open", + menu_open_frame, + ) + frames.append(menu_open_frame) + mib = await flet_app_function.tester.find_by_text("Save") + await flet_app_function.tester.mouse_hover(mib) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + await flet_app_function.tester.tap(mib) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="nested_submenus", + duration=1600, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py new file mode 100644 index 0000000000..4be7b7353f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_menu_item_button.py @@ -0,0 +1,96 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.menu_item_button.basic import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Row( + controls=[ + ft.MenuItemButton( + content=ft.Text("Yes"), + on_click=lambda e: print("yes"), + autofocus=True, + ), + ft.MenuItemButton( + content=ft.Text("No"), + on_click=lambda e: print("no"), + ), + ft.MenuItemButton( + content=ft.Text("Maybe"), + on_click=lambda e: print("maybe"), + ), + ], + alignment=ft.MainAxisAlignment.CENTER, + height=50, + width=200, + expand=True, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "basic_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + btn = await flet_app_function.tester.find_by_text("BgColors") + await flet_app_function.tester.mouse_hover(btn) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + await flet_app_function.tester.tap(btn) + await flet_app_function.tester.pump_and_settle() + open_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "basic_open", + open_frame, + ) + frames.append(open_frame) + mib = await flet_app_function.tester.find_by_text("Green") + await flet_app_function.tester.mouse_hover(mib) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + await flet_app_function.tester.tap(mib) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="basic", + duration=1600, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py new file mode 100644 index 0000000000..51e9469da9 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_bar.py @@ -0,0 +1,50 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.navigation_bar.basic.main import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + nvb = ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.CIRCLE, label="Item 1"), + ft.NavigationBarDestination(icon=ft.Icons.SQUARE, label="Item 2"), + ft.NavigationBarDestination(icon=ft.Icons.HEXAGON, label="Item 3"), + ], + ) + flet_app_function.resize_page(300, 100) + flet_app_function.page.navigation_bar = nvb + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=800) + ) + flet_app_function.assert_screenshot( + "image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_drawer.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_drawer.py new file mode 100644 index 0000000000..23e57cd995 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_drawer.py @@ -0,0 +1,246 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.navigation_drawer.adaptive_navigation.main import ( + main as adaptive_navigation, +) +from examples.controls.material.navigation_drawer.position_end.main import ( + main as position_end, +) +from examples.controls.material.navigation_drawer.position_start.main import ( + main as position_start, +) +from examples.controls.material.navigation_drawer.theming.main import main as theming + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.drawer = ft.NavigationDrawer( + tile_padding=ft.Padding(top=10), + controls=[ + ft.NavigationDrawerDestination(icon=ft.Icons.HOME_OUTLINED, label="Item 1"), + ft.NavigationDrawerDestination(icon=ft.Icons.MAIL_OUTLINED, label="Item 2"), + ft.NavigationDrawerDestination( + icon=ft.Icons.SETTINGS_OUTLINED, label="Item 3" + ), + ], + ) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=800) + ) + + await flet_app_function.page.show_drawer() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=800) + ) + flet_app_function.assert_screenshot( + "image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": position_end}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_position_end(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "position_end1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + btn = await flet_app_function.tester.find_by_text_containing("Show") + await flet_app_function.tester.mouse_hover(btn) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "position_end2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap(btn) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "position_end3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["position_end1", "position_end2", "position_end3"], + "position_end", + duration=1600, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": position_start}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_position_start(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "position_start1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + btn = await flet_app_function.tester.find_by_text_containing("Show") + await flet_app_function.tester.mouse_hover(btn) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "position_start2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap(btn) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "position_start3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["position_start1", "position_start2", "position_start3"], + "position_start", + duration=1600, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": theming}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_theming(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + + flet_app_function.assert_screenshot( + "theming1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text_containing("Show") + ) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "theming2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text_containing("Notifications") + ) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "theming3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["theming1", "theming2", "theming3"], + "theming", + duration=1600, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": adaptive_navigation}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_adaptive_navigation(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + + # narrow layout + flet_app_function.resize_page(400, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "adaptive_navigation1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + # wide layout + flet_app_function.resize_page(600, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text_containing("Open Drawer") + ) + await flet_app_function.tester.pump_and_settle( + duration=ft.Duration(milliseconds=500) + ) + flet_app_function.assert_screenshot( + "adaptive_navigation2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + flet_app_function.create_gif( + ["adaptive_navigation1", "adaptive_navigation2"], + "adaptive_navigation", + duration=1800, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py new file mode 100644 index 0000000000..02d597b9c4 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_navigation_rail.py @@ -0,0 +1,52 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.navigation_rail.basic.main import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.NavigationRail( + selected_index=0, + destinations=[ + ft.NavigationRailDestination( + icon=ft.Icons.STAR, + label="Star", + ), + ft.NavigationRailDestination( + icon=ft.Icon(ft.Icons.ADD), + label="Add", + ), + ft.NavigationRailDestination( + icon=ft.Icons.DELETE, + label=ft.Text("Delete"), + ), + ], + height=200, + width=100, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py new file mode 100644 index 0000000000..0565913ffa --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_outlined_button.py @@ -0,0 +1,126 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.outlined_button.basic.main import main as basic +from examples.controls.material.outlined_button.custom_content.main import ( + main as custom_content, +) +from examples.controls.material.outlined_button.handling_clicks.main import ( + main as handling_clicks, +) +from examples.controls.material.outlined_button.icons.main import main as icons + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.OutlinedButton(content="Outlined button"), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_content}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_content(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.assert_screenshot( + "custom_content", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": icons}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_icons(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.assert_screenshot( + "icons", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_clicks}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_clicks(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 150) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + ob = await flet_app_function.tester.find_by_text_containing("event") + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_clicks_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + await flet_app_function.tester.mouse_hover(ob) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(ob) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(ob) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(ob) + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_clicks_final", + final_frame, + ) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, + output_name="handling_clicks", + duration=1600, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py new file mode 100644 index 0000000000..191985b7ce --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_popup_menu_button.py @@ -0,0 +1,102 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.popup_menu_button.basic.main import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(100, 200) + flet_app_function.page.update() + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.add( + ft.PopupMenuButton( + key="popup", + items=[ + ft.PopupMenuItem(content="Sm"), + ft.PopupMenuItem(content="Med"), + ft.PopupMenuItem(content="Lg"), + ], + menu_position=ft.PopupMenuPosition.UNDER, + ) + ) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + pb = await flet_app_function.tester.find_by_key("popup") + await flet_app_function.tester.tap(pb) + await flet_app_function.tester.pump_and_settle() + flet_app_function.page.update() + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 240) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + pb = await flet_app_function.tester.find_by_key("popup") + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + flet_app_function.assert_screenshot( + "basic_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + await flet_app_function.tester.mouse_hover(pb) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + ) + + await flet_app_function.tester.tap(pb) + await flet_app_function.tester.pump_and_settle() + open_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + flet_app_function.assert_screenshot( + "basic_open", + open_frame, + ) + frames.append(open_frame) + + check_power = await flet_app_function.tester.find_by_text("Check power") + await flet_app_function.tester.mouse_hover(check_power) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + ) + + await flet_app_function.tester.tap(check_power) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio, + ) + ) + + flet_app_function.create_gif( + frames=frames, + output_name="basic", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_progress_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_progress_bar.py new file mode 100644 index 0000000000..68b1e2a838 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_progress_bar.py @@ -0,0 +1,33 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.progress_bar.determinate_and_indeterminate.main import ( + main as determinate_and_indeterminate, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ProgressBar(width=400, value=0.8), + ) + + +@pytest.mark.skip(reason="Test runs asynchronously") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": determinate_and_indeterminate}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_determinate_and_indeterminate(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + flet_app_function.assert_screenshot( + "determinate_and_indeterminate", + await flet_app_function.page.take_screenshot(delay=ft.Duration(seconds=15)), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_progress_ring.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_progress_ring.py new file mode 100644 index 0000000000..66e158f4db --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_progress_ring.py @@ -0,0 +1,53 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.progress_ring.determinate_and_indeterminate import ( + main as determinate_and_indeterminate, +) +from examples.controls.material.progress_ring.gauge_with_progress import ( + main as gauge_with_progress, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ProgressRing(value=0.4, padding=ft.Padding.all(10)), + ) + + +@pytest.mark.skip(reason="Will fix later") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": gauge_with_progress}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_gauge_with_progress(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "gauge_with_progress", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.skip(reason="Test runs asynchronously") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": determinate_and_indeterminate}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_determinate_and_indeterminate(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.page.update() + + flet_app_function.assert_screenshot( + "determinate_and_indeterminate", + await flet_app_function.page.take_screenshot(delay=ft.Duration(seconds=15)), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py new file mode 100644 index 0000000000..41450aef3d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_radio.py @@ -0,0 +1,280 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.radio.basic.main import main as basic +from examples.controls.material.radio.handling_selection_changes.main import ( + main as handling_selection_changes, +) +from examples.controls.material.radio.styled.main import main as styled + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.RadioGroup( + content=ft.Row( + controls=[ft.Radio(label=f"{i}") for i in range(1, 4)], + alignment=ft.MainAxisAlignment.CENTER, + expand=True, + ), + expand=True, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + async def _settle(): + await flet_app_function.tester.pump_and_settle(ft.Duration(milliseconds=500)) + + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 280) + flet_app_function.page.update() + await _settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "basic_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + red = await flet_app_function.tester.find_by_text("Red") + # Hover over radio doesn't show on screenshot + await flet_app_function.tester.mouse_hover(red) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(red) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + submit = await flet_app_function.tester.find_by_key("basic_submit_button") + await flet_app_function.tester.mouse_hover(submit) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(submit) + await _settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "basic_final", + final_frame, + ) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, + output_name="basic", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_selection_changes}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_selection_changes(flet_app_function: ftt.FletTestApp): + async def _settle(): + await flet_app_function.tester.pump_and_settle(ft.Duration(milliseconds=500)) + + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(420, 250) + flet_app_function.page.update() + await _settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_selection_changes_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + red = await flet_app_function.tester.find_by_text("Red") + # Hover over radio doesn't show on screenshot + await flet_app_function.tester.mouse_hover(red) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(red) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + green = await flet_app_function.tester.find_by_text("Green") + await flet_app_function.tester.mouse_hover(green) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(green) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + blue = await flet_app_function.tester.find_by_text("Blue") + await flet_app_function.tester.mouse_hover(blue) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(blue) + await _settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "handling_selection_changes_final", + final_frame, + ) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, + output_name="handling_selection_changes", + duration=1000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": styled}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_styled(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(500, 260) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "styled_initial", + initial_frame, + ) + frames: list[bytes] = [initial_frame] + + default_radio = await flet_app_function.tester.find_by_key("styled_radio_default") + await flet_app_function.tester.mouse_hover(default_radio) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + default_label = await flet_app_function.tester.find_by_text( + "Radio with default style" + ) + await flet_app_function.tester.tap(default_label) + await flet_app_function.tester.pump_and_settle() + default_selected_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "styled_default_selected", + default_selected_frame, + ) + frames.append(default_selected_frame) + + constant_radio = await flet_app_function.tester.find_by_key("styled_radio_constant") + await flet_app_function.tester.mouse_hover(constant_radio) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + constant_label = await flet_app_function.tester.find_by_text( + "Radio with constant fill color" + ) + await flet_app_function.tester.tap(constant_label) + await flet_app_function.tester.pump_and_settle() + constant_selected_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "styled_constant_selected", + constant_selected_frame, + ) + frames.append(constant_selected_frame) + + dynamic_radio = await flet_app_function.tester.find_by_key("styled_radio_dynamic") + await flet_app_function.tester.mouse_hover(dynamic_radio) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + dynamic_label = await flet_app_function.tester.find_by_text( + "Radio with dynamic fill color" + ) + await flet_app_function.tester.tap(dynamic_label) + await flet_app_function.tester.pump_and_settle() + dynamic_selected_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "styled_dynamic_selected", + dynamic_selected_frame, + ) + frames.append(dynamic_selected_frame) + + flet_app_function.create_gif( + frames=frames, + output_name="styled", + duration=1000, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py new file mode 100644 index 0000000000..7ecf08d0c3 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_range_slider.py @@ -0,0 +1,105 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.range_slider.basic.main import main as basic +from examples.controls.material.range_slider.handling_change_events.main import ( + main as handling_change_events, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.RangeSlider( + min=0, + max=10, + start_value=2, + divisions=10, + end_value=7, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(800, 200) + flet_app_function.page.update() + await flet_app_function.tester.tap_at(ft.Offset(200, 100)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(700, 100)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(400, 100)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.create_gif( + ["basic1", "basic2", "basic3"], + "basic", + duration=1600, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_change_events}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_change_events(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(800, 200) + flet_app_function.page.update() + await flet_app_function.tester.tap_at(ft.Offset(200, 100)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(700, 100)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap_at(ft.Offset(400, 100)) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "handling_events3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.create_gif( + ["handling_events1", "handling_events2", "handling_events3"], + "handling_events", + duration=1600, + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py new file mode 100644 index 0000000000..dc2e70f640 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_drag_handle.py @@ -0,0 +1,81 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.reorderable_drag_handle.basic.main import main as basic + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(420, 500) + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ReorderableListView( + show_default_drag_handles=False, + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), + leading=ft.ReorderableDragHandle( + content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), + mouse_cursor=ft.MouseCursor.GRAB, + ), + ) + for i in range(10) + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(420, 500) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("basic_initial", initial_frame) + frames = [initial_frame] + + drag_handle = await flet_app_function.tester.find_by_key("drag_handle_0") + + # Step 1: move item 0 downward and capture the intermediate state. + await flet_app_function.tester.drag(drag_handle, ft.Offset(0, 110)) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + # Step 2: continue dragging the same item downward and capture again. + drag_handle = await flet_app_function.tester.find_by_key("drag_handle_0") + await flet_app_function.tester.drag(drag_handle, ft.Offset(0, 110)) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + # Step 3: move item 0 to its expected final position. + drag_handle = await flet_app_function.tester.find_by_key("drag_handle_0") + await flet_app_function.tester.drag(drag_handle, ft.Offset(0, 110)) + await flet_app_function.tester.pump_and_settle() + + reordered_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("basic_reordered", reordered_frame) + frames.append(reordered_frame) + + flet_app_function.create_gif(frames=frames, output_name="basic", duration=800) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_list_view.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_list_view.py new file mode 100644 index 0000000000..d7799833ed --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_reorderable_list_view.py @@ -0,0 +1,44 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.controls.material.reorderable_list_view.horizontal_and_vertical import ( + main as horizontal_and_vertical, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.ReorderableListView( + controls=[ + ft.ListTile( + title=ft.Text(f"Item {i}"), + bgcolor=ft.Colors.BLUE_GREY_300, + ) + for i in range(1, 6) + ], + show_default_drag_handles=True, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": horizontal_and_vertical.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_horizontal_and_vertical(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "horizontal_and_vertical", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py new file mode 100644 index 0000000000..e3d37a26c2 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_search_bar.py @@ -0,0 +1,38 @@ +import pytest + +import examples.controls.material.search_bar.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.SearchBar(bar_hint_text="Search..."), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + # scr = await flet_app_function.wrap_page_controls_in_screenshot() + button = await flet_app_function.tester.find_by_text_containing("Search") + await flet_app_function.tester.tap(button) + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_segmented_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_segmented_button.py new file mode 100644 index 0000000000..a9510a3b2b --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_segmented_button.py @@ -0,0 +1,56 @@ +import pytest + +import examples.controls.material.segmented_button.single_multiple_selection.main as sms +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.SegmentedButton( + show_selected_icon=False, + selected=["3"], + segments=[ + ft.Segment( + value="1", + icon=ft.Icon(ft.Icons.SENTIMENT_VERY_SATISFIED), + ), + ft.Segment( + value="2", + icon=ft.Icon(ft.Icons.SENTIMENT_SATISFIED), + ), + ft.Segment( + value="3", + icon=ft.Icon(ft.Icons.SENTIMENT_NEUTRAL), + ), + ft.Segment( + value="4", + icon=ft.Icon(ft.Icons.SENTIMENT_DISSATISFIED), + ), + ft.Segment( + value="5", + icon=ft.Icon(ft.Icons.SENTIMENT_VERY_DISSATISFIED), + ), + ], + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": sms.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_single_multiple_selection(flet_app_function: ftt.FletTestApp): + # flet_app_function.page.enable_screenshots = True + # flet_app_function.resize_page(400, 200) + # flet_app_function.page.update() + # await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "single_multiple_selection", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py new file mode 100644 index 0000000000..f8d883f6e6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_selection_area.py @@ -0,0 +1,31 @@ +import pytest + +import examples.controls.material.selection_area.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + selectable = ft.SelectionArea( + content=ft.Text("Selectable text", color=ft.Colors.GREEN), + ) + non_selectable = ft.Text("Not selectable", color=ft.Colors.RED) + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column(controls=[selectable, non_selectable]), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py new file mode 100644 index 0000000000..e649f5065d --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_slider.py @@ -0,0 +1,58 @@ +import pytest + +import examples.controls.material.slider.basic.main as basic +import examples.controls.material.slider.custom_label.main as custom_label +import examples.controls.material.slider.handling_events.main as handling_events +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, ft.Slider(label="Slider", value=0.3) + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_label.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_label(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "custom_label", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_events.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_events(flet_app_function: ftt.FletTestApp): + scr = await flet_app_function.wrap_page_controls_in_screenshot() + await flet_app_function.tester.tap_at(ft.Offset(120, 60)) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "handling_events", + await scr.capture(pixel_ratio=flet_app_function.screenshots_pixel_ratio), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py new file mode 100644 index 0000000000..591e605d9a --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_snack_bar.py @@ -0,0 +1,122 @@ +import pytest + +import examples.controls.material.snack_bar.action.main as action +import examples.controls.material.snack_bar.basic.main as basic +import examples.controls.material.snack_bar.counter.main as counter +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + sb = ft.SnackBar(ft.Text("Opened snack bar")) + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(250, 200) + flet_app_function.page.show_dialog(sb) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "test_image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(250, 200) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + button = await flet_app_function.tester.find_by_text_containing("Open SnackBar") + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": counter.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_counter(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(250, 200) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "before_click", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + button = await flet_app_function.tester.find_by_text_containing("Open SnackBar") + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "click_1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "click_2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + flet_app_function.create_gif( + ["before_click", "click_1", "click_2"], + "snack_bar_flow", + duration=2000, + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": action.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_action(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 300) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + button = await flet_app_function.tester.find_by_text_containing( + "Open SnackBar with a Simple action" + ) + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "action_simple", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + button = await flet_app_function.tester.find_by_text_containing( + "Open SnackBar with a Custom action" + ) + await flet_app_function.tester.tap(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "action_custom", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py new file mode 100644 index 0000000000..7197403852 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_submenu_button.py @@ -0,0 +1,106 @@ +import pytest + +import examples.controls.material.submenu_button.basic.main as basic +import examples.controls.material.submenu_button.standalone.main as standalone +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + smb = ft.SubmenuButton( + content=ft.Text("Choose text style"), + key="smbutton", + expand=True, + menu_style=ft.MenuStyle( + alignment=ft.Alignment.BOTTOM_LEFT, side=ft.BorderSide(1) + ), + controls=[ + ft.MenuItemButton( + content=ft.Text("Underlined"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + style=ft.ButtonStyle( + text_style={ + ft.ControlState.HOVERED: ft.TextStyle( + decoration=ft.TextDecoration.UNDERLINE + ) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Bold"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + style=ft.ButtonStyle( + text_style={ + ft.ControlState.HOVERED: ft.TextStyle(weight=ft.FontWeight.BOLD) + } + ), + ), + ft.MenuItemButton( + content=ft.Text("Italic"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + style=ft.ButtonStyle( + text_style={ft.ControlState.HOVERED: ft.TextStyle(italic=True)} + ), + ), + ], + ) + flet_app_function.page.enable_screenshots = True + flet_app_function.page.add(ft.Row(controls=[smb])) + # flet_app_function.page.update() + # await flet_app_function.tester.pump_and_settle() + flet_app_function.resize_page(200, 200) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + button = await flet_app_function.tester.find_by_key("smbutton") + await flet_app_function.tester.mouse_hover(button) + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "test_image_for_docs", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(450, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + button = await flet_app_function.tester.find_by_key("submenubutton") + await flet_app_function.tester.tap(button) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": standalone.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_standalone_initial(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(300, 260) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "standalone_initial", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py new file mode 100644 index 0000000000..48a1c484b8 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_switch.py @@ -0,0 +1,77 @@ +import pytest + +import examples.controls.material.switch.basic.main as basic +import examples.controls.material.switch.handling_events.main as handling_events +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + [ + ft.Switch(label="Unchecked switch", value=False), + ft.Switch(label="Disabled switch", disabled=True), + ] + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_events.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_events(flet_app_function: ftt.FletTestApp): + async def _settle(): + await flet_app_function.tester.pump_and_settle(ft.Duration(milliseconds=500)) + + flet_app_function.page.enable_screenshots = True + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(320, 200) + flet_app_function.page.update() + await _settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("handling_events_initial", initial_frame) + frames = [initial_frame] + + switch = await flet_app_function.tester.find_by_key("theme_mode_switch") + await flet_app_function.tester.mouse_hover(switch) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(switch) + await _settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("handling_events_final", final_frame) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, output_name="handling_events", duration=1000 + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py new file mode 100644 index 0000000000..7595678088 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_tabs.py @@ -0,0 +1,70 @@ +import pytest + +import examples.controls.material.tabs.basic.main as basic +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Tabs( + selected_index=1, + length=3, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Tab 1", icon=ft.Icons.SETTINGS_PHONE), + ft.Tab(label="Tab 2", icon=ft.Icons.SETTINGS), + ft.Tab( + label=ft.CircleAvatar( + foreground_image_src="https://avatars.githubusercontent.com/u/102273996?s=200&v=4", + ), + ), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 1"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 2"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("This is Tab 3"), + ), + ], + ), + ], + ), + ), + expand_screenshot=True, + ) + + +@pytest.mark.skip(reason="Will fix later") +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot( + pump_times=10, + pump_duration=1000, + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py new file mode 100644 index 0000000000..2bba34c9e6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_text_button.py @@ -0,0 +1,90 @@ +import pytest + +import examples.controls.material.text_button.basic.main as basic +import examples.controls.material.text_button.custom_content.main as custom_content +import examples.controls.material.text_button.handling_clicks.main as handling_clicks +import examples.controls.material.text_button.icons.main as icons +import flet as ft +import flet.testing as ftt + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.TextButton( + content="Text Button", + icon=ft.Icons.STAR_BORDER, + icon_color=ft.Colors.BLUE_300, + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": custom_content.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_content(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "custom_content", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": icons.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_icons(flet_app_function: ftt.FletTestApp): + flet_app_function.assert_screenshot( + "icons", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_clicks.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_clicks(flet_app_function: ftt.FletTestApp): + async def _settle(): + await flet_app_function.tester.pump_and_settle(ft.Duration(milliseconds=500)) + + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(250, 150) + flet_app_function.page.update() + await _settle() + + button = await flet_app_function.tester.find_by_key("TextButton") + await flet_app_function.tester.tap(button) + await _settle() + await flet_app_function.tester.tap(button) + await _settle() + await flet_app_function.tester.tap(button) + await _settle() + flet_app_function.assert_screenshot( + "handling_clicks", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py new file mode 100644 index 0000000000..e79a4f5eb7 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_textfield.py @@ -0,0 +1,546 @@ +import pytest + +import examples.controls.material.text_field.basic.main as basic +import flet as ft +import flet.testing as ftt +from examples.controls.material.text_field.handling_change_events.main import ( + main as handling_change_events, +) +from examples.controls.material.text_field.label_hint_helper_counter.main import ( + main as label_hint_helper_counter, +) +from examples.controls.material.text_field.multiline.main import main as multiline +from examples.controls.material.text_field.password.main import main as password +from examples.controls.material.text_field.prefix_and_suffix.main import ( + main as prefix_and_suffix, +) +from examples.controls.material.text_field.selection_change.main import ( + main as selection_change, +) +from examples.controls.material.text_field.styled.main import main as styled +from examples.controls.material.text_field.underlined_and_borderless.main import ( + main as underlined_and_borderless, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.TextField(label="Name", hint_text="Jane Doe"), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.resize_page(500, 520) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "basic", + await flet_app_function.take_page_controls_screenshot(), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": handling_change_events}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_handling_change_events(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(500, 220) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + textfield = await flet_app_function.tester.find_by_key("handling_change_textfield") + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("handling_change_events_initial", initial_frame) + frames = [initial_frame] + + await flet_app_function.tester.tap(textfield) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.enter_text(textfield, "hello") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.enter_text(textfield, "hello flet") + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("handling_change_events_final", final_frame) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, output_name="handling_change_events", duration=1000 + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": selection_change}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_selection_change(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(600, 320) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("selection_change_initial", initial_frame) + frames = [initial_frame] + + select_all = await flet_app_function.tester.find_by_text("Select all text") + await flet_app_function.tester.mouse_hover(select_all) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(select_all) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + move_caret = await flet_app_function.tester.find_by_text("Move caret to start") + await flet_app_function.tester.mouse_hover(move_caret) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(move_caret) + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("selection_change_final", final_frame) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, output_name="selection_change", duration=1000 + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": password}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_password(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(420, 180) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + textfield = await flet_app_function.tester.find_by_key("password_textfield") + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("password_initial", initial_frame) + frames = [initial_frame] + + await flet_app_function.tester.tap(textfield) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.enter_text(textfield, "password") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + reveal = await flet_app_function.tester.find_by_icon(ft.Icons.VISIBILITY) + await flet_app_function.tester.tap(reveal.first) + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("password_final", final_frame) + frames.append(final_frame) + + flet_app_function.create_gif(frames=frames, output_name="password", duration=1000) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": multiline}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_multiline(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(520, 420) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + standard = await flet_app_function.tester.find_by_key("multiline_standard") + auto_height = await flet_app_function.tester.find_by_key("multiline_auto_height") + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("multiline_initial", initial_frame) + frames = [initial_frame] + + await flet_app_function.tester.tap(standard) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + await flet_app_function.tester.enter_text(standard, "flet") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(auto_height) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + for value in [ + "line1", + "line1\nline2", + "line1\nline2\nline3", + "line1\nline2\nline3\nline4", + "line1\nline2\nline3\nline4\nline5", + ]: + await flet_app_function.tester.enter_text(auto_height, value) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + if value != "line1\nline2\nline3\nline4\nline5": + await flet_app_function.tester.enter_text(auto_height, f"{value}\n") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + final_frame = frames[-1] + flet_app_function.assert_screenshot("multiline_final", final_frame) + flet_app_function.create_gif(frames=frames, output_name="multiline", duration=1000) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": underlined_and_borderless}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_underlined_and_borderless(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(520, 360) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + underlined = await flet_app_function.tester.find_by_key("underlined_field") + underlined_filled = await flet_app_function.tester.find_by_key( + "underlined_filled_field" + ) + borderless = await flet_app_function.tester.find_by_key("borderless_field") + borderless_filled = await flet_app_function.tester.find_by_key( + "borderless_filled_field" + ) + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "underlined_and_borderless_initial", initial_frame + ) + frames = [initial_frame] + + await flet_app_function.tester.tap(underlined) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.enter_text(underlined, "eat") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(underlined_filled) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.enter_text(underlined_filled, "code") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(borderless) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.enter_text(borderless, "eat again") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(borderless_filled) + await flet_app_function.tester.pump_and_settle() + await flet_app_function.tester.enter_text(borderless_filled, "code again") + await flet_app_function.tester.pump_and_settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("underlined_and_borderless_final", final_frame) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, output_name="underlined_and_borderless", duration=1000 + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": prefix_and_suffix}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_prefix_and_suffix(flet_app_function: ftt.FletTestApp): + async def _settle(): + await flet_app_function.tester.pump_and_settle(ft.Duration(milliseconds=500)) + + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(520, 520) + flet_app_function.page.update() + await _settle() + + prefix = await flet_app_function.tester.find_by_key("prefix_field") + suffix = await flet_app_function.tester.find_by_key("suffix_field") + prefix_suffix = await flet_app_function.tester.find_by_key("prefix_suffix_field") + color = await flet_app_function.tester.find_by_key("color_field") + submit = await flet_app_function.tester.find_by_key("submit_button") + + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("prefix_and_suffix_initial", initial_frame) + frames = [initial_frame] + + await flet_app_function.tester.tap(prefix) + await _settle() + await flet_app_function.tester.enter_text(prefix, "google.com") + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(suffix) + await _settle() + await flet_app_function.tester.enter_text(suffix, "github") + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(prefix_suffix) + await _settle() + await flet_app_function.tester.enter_text(prefix_suffix, "github") + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(color) + await _settle() + await flet_app_function.tester.enter_text(color, "red") + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.mouse_hover(submit) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(submit) + await _settle() + final_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("prefix_and_suffix_final", final_frame) + frames.append(final_frame) + + flet_app_function.create_gif( + frames=frames, output_name="prefix_and_suffix", duration=1000 + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": styled}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_styled(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(520, 260) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + textfield = await flet_app_function.tester.find_by_key("styled_textfield") + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("styled_initial", initial_frame) + frames = [initial_frame] + + await flet_app_function.tester.tap(textfield) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + for value in [ + "hello", + "hello flet", + "hello flet hello", + "hello flet hello flet", + ]: + await flet_app_function.tester.enter_text(textfield, value) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + final_frame = frames[-1] + flet_app_function.assert_screenshot( + "styled_final", final_frame, similarity_threshold=98.5 + ) + flet_app_function.create_gif(frames=frames, output_name="styled", duration=1000) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": label_hint_helper_counter}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_label_hint_helper_counter(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(520, 260) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + textfield = await flet_app_function.tester.find_by_key( + "label_hint_helper_counter_textfield" + ) + initial_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot( + "label_hint_helper_counter_initial", initial_frame + ) + frames = [initial_frame] + + await flet_app_function.tester.tap(textfield) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + for value in [ + "first", + "first name", + "first name last", + "first name last name", + ]: + await flet_app_function.tester.enter_text(textfield, value) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + final_frame = frames[-1] + flet_app_function.assert_screenshot("label_hint_helper_counter_final", final_frame) + flet_app_function.create_gif( + frames=frames, output_name="label_hint_helper_counter", duration=1000 + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py new file mode 100644 index 0000000000..18d23b2b60 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/controls/material/test_time_picker.py @@ -0,0 +1,293 @@ +from datetime import time + +import pytest + +import examples.controls.material.time_picker.basic.main as basic +import examples.controls.material.time_picker.custom_locale.main as custom_locale +import examples.controls.material.time_picker.hour_formats.main as hour_formats +import flet as ft +import flet.testing as ftt + +# Note: CI macOS runner uses a 12-hour (AM / PM) time format by default. + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(600, 400) + flet_app_function.page.update() + + flet_app_function.page.show_dialog( + ft.TimePicker( + value=time(hour=19, minute=30), + hour_format=ft.TimePickerHourFormat.H12, + ) + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + request.node.name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": basic.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_basic(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(600, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + pick_time = await flet_app_function.tester.find_by_key("pick_time_button") + frames = [ + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ] + + await flet_app_function.tester.mouse_hover(pick_time) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(pick_time) + await flet_app_function.tester.pump_and_settle() + opened_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("basic_opened", opened_frame) + frames.append(opened_frame) + + switch_to_text_input = await flet_app_function.tester.find_by_tooltip( + "Switch to text input mode" + ) + await flet_app_function.tester.mouse_hover(switch_to_text_input.first) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(switch_to_text_input.first) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + am = await flet_app_function.tester.find_by_text("AM") + await flet_app_function.tester.mouse_hover(am.first) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(am.first) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + hour_field = await flet_app_function.tester.find_by_text("7") + await flet_app_function.tester.enter_text(hour_field.first, "11") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + minute_field = await flet_app_function.tester.find_by_text("30") + await flet_app_function.tester.enter_text(minute_field.first, "45") + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + confirm = await flet_app_function.tester.find_by_text("Confirm") + await flet_app_function.tester.mouse_hover(confirm.first) + await flet_app_function.tester.pump_and_settle() + confirm_hover_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("basic_confirm_hover", confirm_hover_frame) + frames.append(confirm_hover_frame) + + await flet_app_function.tester.tap(confirm.first) + await flet_app_function.tester.pump_and_settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + flet_app_function.create_gif(frames=frames, output_name="basic", duration=1000) + + +@pytest.mark.parametrize( + "flet_app_function", [{"flet_app_main": hour_formats.main}], indirect=True +) +@pytest.mark.asyncio(loop_scope="function") +async def test_hour_formats(flet_app_function: ftt.FletTestApp): + async def _settle(): + await flet_app_function.tester.pump_and_settle(ft.Duration(milliseconds=500)) + + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(600, 450) + flet_app_function.page.update() + await _settle() + + open_picker = await flet_app_function.tester.find_by_text("Open TimePicker") + dropdown = await flet_app_function.tester.find_by_key("dd") + + frames = [ + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ] + + await flet_app_function.tester.mouse_hover(open_picker.first) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(dropdown) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + clock_12h = await flet_app_function.tester.find_by_text("12-hour clock") + await flet_app_function.tester.mouse_hover(clock_12h.last) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(clock_12h.last) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.mouse_hover(open_picker.first) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(open_picker.first) + await _settle() + opened_12h_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("hour_formats_opened_12h", opened_12h_frame) + frames.append(opened_12h_frame) + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_text("Cancel") + ) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(dropdown) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + clock_24h = await flet_app_function.tester.find_by_text("24-hour clock") + await flet_app_function.tester.mouse_hover(clock_24h.last) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(clock_24h.last) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.mouse_hover(open_picker.first) + await _settle() + frames.append( + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + ) + + await flet_app_function.tester.tap(open_picker.first) + await _settle() + opened_24h_frame = await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ) + flet_app_function.assert_screenshot("hour_formats_opened_24h", opened_24h_frame) + frames.append(opened_24h_frame) + + flet_app_function.create_gif( + frames=frames, output_name="hour_formats", duration=1000 + ) + + +@pytest.mark.parametrize( + "flet_app_function", [{"flet_app_main": custom_locale.main}], indirect=True +) +@pytest.mark.asyncio(loop_scope="function") +async def test_custom_locale(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(600, 400) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + await flet_app_function.tester.tap( + await flet_app_function.tester.find_by_key("custom_locale_button") + ) + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + "custom_locale", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_1.png b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_1.png new file mode 100644 index 0000000000..3cd81e518f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_1.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_2.png b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_2.png new file mode 100644 index 0000000000..dc731ac864 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_2.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_3.png b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_3.png new file mode 100644 index 0000000000..b650783d36 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/example_3.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/image_for_docs.png new file mode 100644 index 0000000000..3cd81e518f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/golden/macos/code_editor/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py new file mode 100644 index 0000000000..433c34bdb7 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/extensions/code_editor/test_code_editor.py @@ -0,0 +1,35 @@ +import pytest + +import examples.extensions.code_editor.example_1.main as example_1 +import examples.extensions.code_editor.example_2.main as example_2 +import examples.extensions.code_editor.example_3.main as example_3 +import flet.testing as ftt + + +@pytest.mark.parametrize( + "flet_app_function, screenshot_name, page_size", + [ + ({"flet_app_main": example_1.main}, "image_for_docs", (700, 500)), + ({"flet_app_main": example_1.main}, "example_1", (700, 500)), + ({"flet_app_main": example_2.main}, "example_2", (700, 500)), + ({"flet_app_main": example_3.main}, "example_3", (700, 500)), + ], + indirect=["flet_app_function"], +) +@pytest.mark.asyncio(loop_scope="function") +async def test_images_for_docs( + flet_app_function: ftt.FletTestApp, + screenshot_name: str, + page_size: tuple[int, int], +): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(*page_size) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + + flet_app_function.assert_screenshot( + screenshot_name, + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/block_picker.png b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/block_picker.png new file mode 100644 index 0000000000..a50e0de66f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/block_picker.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/hue_ring_picker.png b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/hue_ring_picker.png new file mode 100644 index 0000000000..452a72720d Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/hue_ring_picker.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/image_for_docs.png b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/image_for_docs.png new file mode 100644 index 0000000000..1451c03816 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/image_for_docs.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/material_picker.png b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/material_picker.png new file mode 100644 index 0000000000..1ec30944fb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/material_picker.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/multiple_choice_block_picker.png b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/multiple_choice_block_picker.png new file mode 100644 index 0000000000..7a0542bb57 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/multiple_choice_block_picker.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/slide_picker.png b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/slide_picker.png new file mode 100644 index 0000000000..b28354b5e9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/golden/macos/color_pickers/slide_picker.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/test_color_pickers.py b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/test_color_pickers.py new file mode 100644 index 0000000000..f2b2645a76 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/extensions/color_pickers/test_color_pickers.py @@ -0,0 +1,88 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from flet_color_pickers import ( + BlockPicker, + ColorPicker, + HueRingPicker, + MaterialPicker, + MultipleChoiceBlockPicker, + SlidePicker, +) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_image_for_docs(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[ColorPicker()], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_hue_ring_picker(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[HueRingPicker(color="#00ff00")], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_slide_picker(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[SlidePicker(color="#0000ff")], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_material_picker(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[MaterialPicker(color="#ff9800")], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_block_picker(flet_app_function: ftt.FletTestApp, request): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[BlockPicker(color="#9c27b0")], + ), + ) + + +@pytest.mark.asyncio(loop_scope="function") +async def test_multiple_choice_block_picker( + flet_app_function: ftt.FletTestApp, request +): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + await flet_app_function.assert_control_screenshot( + request.node.name, + ft.Column( + intrinsic_width=True, + controls=[ + MultipleChoiceBlockPicker(colors=["#03a9f4", "#4caf50", "#ffeb3b"]) + ], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/golden/macos/datatable2/column_widths.png b/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/golden/macos/datatable2/column_widths.png new file mode 100644 index 0000000000..2fd975f7d9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/golden/macos/datatable2/column_widths.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/golden/macos/datatable2/empty_state.png b/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/golden/macos/datatable2/empty_state.png new file mode 100644 index 0000000000..122afc4d88 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/golden/macos/datatable2/empty_state.png differ diff --git a/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/test_datatable2.py b/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/test_datatable2.py new file mode 100644 index 0000000000..e58ded4f8f --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/examples/extensions/datatable2/test_datatable2.py @@ -0,0 +1,45 @@ +import pytest + +import flet.testing as ftt +from examples.extensions.datatable2.column_widths import main as column_widths +from examples.extensions.datatable2.empty_state import main as empty_state + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": empty_state.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_empty_state(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(500, 200) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "empty_state", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": column_widths.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_column_widths(flet_app_function: ftt.FletTestApp): + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(640, 260) + flet_app_function.page.update() + + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "column_widths", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_basic.png b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_basic.png new file mode 100644 index 0000000000..cd4c07490f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_basic.png differ diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_block.png b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_block.png new file mode 100644 index 0000000000..a50e0de66f Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_block.png differ diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_hue_ring.png b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_hue_ring.png new file mode 100644 index 0000000000..1c076d34a4 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_hue_ring.png differ diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_material.png b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_material.png new file mode 100644 index 0000000000..1ec30944fb Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_material.png differ diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_multiple_choice_block.png b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_multiple_choice_block.png new file mode 100644 index 0000000000..7a0542bb57 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_multiple_choice_block.png differ diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_slide.png b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_slide.png new file mode 100644 index 0000000000..b28354b5e9 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/golden/macos/color_pickers/color_picker_slide.png differ diff --git a/sdk/python/packages/flet/integration_tests/extensions/color_pickers/test_color_pickers.py b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/test_color_pickers.py new file mode 100644 index 0000000000..f22053e293 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/extensions/color_pickers/test_color_pickers.py @@ -0,0 +1,72 @@ +import pytest + +import flet.testing as ftt +from flet_color_pickers import ( + BlockPicker, + ColorPicker, + HueRingPicker, + MaterialPicker, + MultipleChoiceBlockPicker, + SlidePicker, +) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_color_picker_basic(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + ColorPicker( + color="#ff0000", + color_picker_width=320, + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_color_picker_hue_ring(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + HueRingPicker( + color="#00ff00", + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_color_picker_slide(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + SlidePicker( + color="#0000ff", + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_color_picker_material(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + MaterialPicker( + color="#ff9800", + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_color_picker_block(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + BlockPicker( + color="#9c27b0", + ), + ) + + +@pytest.mark.asyncio(loop_scope="module") +async def test_color_picker_multiple_choice_block(flet_app: ftt.FletTestApp, request): + await flet_app.assert_control_screenshot( + request.node.name, + MultipleChoiceBlockPicker( + colors=["#03a9f4", "#4caf50", "#ffeb3b"], + ), + ) diff --git a/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc1.png b/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc1.png new file mode 100644 index 0000000000..eda7ad147e Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc1.png differ diff --git a/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc2.png b/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc2.png new file mode 100644 index 0000000000..e025d4a822 Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc2.png differ diff --git a/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc3.png b/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc3.png new file mode 100644 index 0000000000..0469aa44cf Binary files /dev/null and b/sdk/python/packages/flet/integration_tests/tutorials/golden/macos/calculator/calc3.png differ diff --git a/sdk/python/packages/flet/integration_tests/tutorials/test_calculator.py b/sdk/python/packages/flet/integration_tests/tutorials/test_calculator.py new file mode 100644 index 0000000000..8929668ce6 --- /dev/null +++ b/sdk/python/packages/flet/integration_tests/tutorials/test_calculator.py @@ -0,0 +1,65 @@ +import pytest + +import flet as ft +import flet.testing as ftt +from examples.tutorials.calculator import calc1, calc2, calc3 + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": calc1.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_calc1(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 850) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "calc1", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": calc2.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_calc2(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(350, 350) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "calc2", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) + + +@pytest.mark.parametrize( + "flet_app_function", + [{"flet_app_main": calc3.main}], + indirect=True, +) +@pytest.mark.asyncio(loop_scope="function") +async def test_calc3(flet_app_function: ftt.FletTestApp): + flet_app_function.page.theme_mode = ft.ThemeMode.LIGHT + flet_app_function.page.enable_screenshots = True + flet_app_function.resize_page(400, 350) + flet_app_function.page.update() + await flet_app_function.tester.pump_and_settle() + flet_app_function.assert_screenshot( + "calc3", + await flet_app_function.page.take_screenshot( + pixel_ratio=flet_app_function.screenshots_pixel_ratio + ), + ) diff --git a/sdk/python/packages/flet/pyproject.toml b/sdk/python/packages/flet/pyproject.toml index fe2ed6718a..c6a20b80f2 100644 --- a/sdk/python/packages/flet/pyproject.toml +++ b/sdk/python/packages/flet/pyproject.toml @@ -5,31 +5,93 @@ description = "Flet for Python - easily build interactive multi-platform apps in authors = [{name = "Appveyor Systems Inc.", email = "hello@flet.dev"}] license = "Apache-2.0" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "flet-cli; extra == 'cli'", - "flet-desktop; extra == 'desktop' and (platform_system == 'Darwin' or platform_system == 'Windows')", "flet-web; extra == 'web'", - "oauthlib >=3.2.2; platform_system != 'Pyodide'", - "httpx >=0.28.1; platform_system != 'Pyodide'", + "oauthlib >=3.2.2; platform_system != 'Emscripten'", + "httpx >=0.28.1; platform_system != 'Emscripten'", "repath >=0.9.0", - "msgpack >=1.1.0" + "msgpack >=1.1.0", + "typing-extensions; python_version < '3.11'" ] +[project.urls] +Homepage = "https://flet.dev" +Repository = "https://github.com/flet-dev/flet" +Documentation = "https://flet.dev/docs/" + [project.optional-dependencies] -all = ["flet-cli", "flet-desktop", "flet-web"] +all = [ + "flet-cli", + "flet-web", + "flet-desktop", +] cli = ["flet-cli"] -desktop = ["flet-desktop"] +desktop = [ + "flet-desktop", +] web = ["flet-web"] [project.scripts] flet = "flet.cli:main" -[project.urls] -Homepage = "https://flet.dev" -Repository = "https://github.com/flet-dev/flet" -Documentation = "https://flet.dev/docs" +[dependency-groups] +extensions = [ + "flet-ads", + "flet-audio", + "flet-audio-recorder", + "flet-camera", + "flet-charts", + "flet-code-editor", + "flet-color-pickers", + "flet-datatable2", + "flet-flashlight", + "flet-geolocator", + "flet-lottie", + "flet-map", + "flet-permission-handler", + "flet-rive", + "flet-secure-storage", + "flet-video", + "flet-webview", +] +test = [ + "pytest >=7.2.0", + "pytest_asyncio >=1.1.0", +] +dev = [ + "tomlkit >=0.11.6", + "cryptography >=39.0.0", + "pillow >=10.3.0", + "pre-commit >=2.21.0", + "pypi-cleanup==0.1.4", + "pandas >=2.2.3", + "numpy >=2.2.0", + "scikit-image >=0.25.2", + "ruff >=0.13.1", + { include-group = 'test' }, +] +docs-coverage = [ + "docstr-coverage >=2.3.2", +] +docs = [ + { include-group = 'extensions' }, + { include-group = 'docs-coverage' }, +] +all = [ + { include-group = 'dev' }, + { include-group = 'docs' }, +] [build-system] requires = ["setuptools"] -build-backend = "setuptools.build_meta" \ No newline at end of file +build-backend = "setuptools.build_meta" + +[tool.setuptools.package-data] +flet = [ + "controls/material/icons.json", + "controls/material/icons.pyi", + "controls/cupertino/cupertino_icons.json", + "controls/cupertino/cupertino_icons.pyi", +] diff --git a/sdk/python/packages/flet/src/flet/__init__.py b/sdk/python/packages/flet/src/flet/__init__.py index 45ec856792..ee854e7b27 100644 --- a/sdk/python/packages/flet/src/flet/__init__.py +++ b/sdk/python/packages/flet/src/flet/__init__.py @@ -1,319 +1,508 @@ -from flet.app import app, app_async -from flet.core import ( - alignment, - border, - border_radius, - dropdown, - dropdownm2, - margin, - padding, - painting, - size, -) -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alert_dialog import AlertDialog -from flet.core.alignment import Alignment, Axis -from flet.core.animated_switcher import AnimatedSwitcher, AnimatedSwitcherTransition -from flet.core.animation import Animation, AnimationCurve, AnimationStyle -from flet.core.app_bar import AppBar -from flet.core.audio import ( - Audio, - AudioDurationChangeEvent, - AudioPositionChangeEvent, - AudioState, - AudioStateChangeEvent, -) -from flet.core.audio_recorder import ( - AudioEncoder, - AudioRecorder, - AudioRecorderState, - AudioRecorderStateChangeEvent, -) -from flet.core.auto_complete import ( - AutoComplete, - AutoCompleteSelectEvent, - AutoCompleteSuggestion, +from typing import TYPE_CHECKING + +from flet.app import AppCallable, app, app_async, run, run_async +from flet.components.component import Component +from flet.components.component_decorator import component +from flet.components.hooks.use_callback import use_callback +from flet.components.hooks.use_context import ( + ContextProvider, + create_context, + use_context, ) -from flet.core.autofill_group import ( - AutofillGroup, - AutofillGroupDisposeAction, - AutofillHint, +from flet.components.hooks.use_dialog import use_dialog +from flet.components.hooks.use_effect import ( + on_mounted, + on_unmounted, + on_updated, + use_effect, +) +from flet.components.hooks.use_memo import use_memo +from flet.components.hooks.use_ref import use_ref +from flet.components.hooks.use_state import use_state +from flet.components.memo import memo +from flet.components.observable import Observable, observable +from flet.components.public_utils import unwrap_component +from flet.components.router import ( + LocationInfo, + Route, + Router, + is_route_active, + use_route_loader_data, + use_route_location, + use_route_outlet, + use_route_params, + use_view_path, +) +from flet.controls import alignment, border, border_radius, margin, padding +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.alignment import Alignment, Axis +from flet.controls.animation import ( + Animation, + AnimationCurve, + AnimationStyle, + AnimationValue, +) +from flet.controls.base_control import BaseControl, Value, control, value +from flet.controls.base_page import BasePage, PageMediaData, PageResizeEvent +from flet.controls.blur import ( + Blur, + BlurTileMode, + BlurValue, +) +from flet.controls.border import ( + Border, + BorderSide, + BorderSideStrokeAlign, + BorderSideStrokeAlignValue, + BorderStyle, ) -from flet.core.badge import Badge -from flet.core.banner import Banner -from flet.core.blur import Blur, BlurTileMode -from flet.core.border import Border, BorderSide, BorderSideStrokeAlign -from flet.core.border_radius import BorderRadius -from flet.core.bottom_app_bar import BottomAppBar -from flet.core.bottom_sheet import BottomSheet -from flet.core.box import ( +from flet.controls.border_radius import ( + BorderRadius, + BorderRadiusValue, +) +from flet.controls.box import ( + BlurStyle, BoxConstraints, BoxDecoration, + BoxFit, BoxShadow, + BoxShadowValue, BoxShape, ColorFilter, DecorationImage, FilterQuality, - ShadowBlurStyle, ) -from flet.core.button import Button -from flet.core.buttons import ( +from flet.controls.buttons import ( BeveledRectangleBorder, ButtonStyle, CircleBorder, ContinuousRectangleBorder, OutlinedBorder, RoundedRectangleBorder, + ShapeBorder, StadiumBorder, ) -from flet.core.card import Card, CardVariant -from flet.core.charts.bar_chart import BarChart, BarChartEvent -from flet.core.charts.bar_chart_group import BarChartGroup -from flet.core.charts.bar_chart_rod import BarChartRod -from flet.core.charts.bar_chart_rod_stack_item import BarChartRodStackItem -from flet.core.charts.chart_axis import ChartAxis -from flet.core.charts.chart_axis_label import ChartAxisLabel -from flet.core.charts.chart_grid_lines import ChartGridLines -from flet.core.charts.chart_point_line import ChartPointLine -from flet.core.charts.chart_point_shape import ( - ChartCirclePoint, - ChartCrossPoint, - ChartPointShape, - ChartSquarePoint, -) -from flet.core.charts.line_chart import LineChart, LineChartEvent, LineChartEventSpot -from flet.core.charts.line_chart_data import LineChartData -from flet.core.charts.line_chart_data_point import LineChartDataPoint -from flet.core.charts.pie_chart import PieChart, PieChartEvent -from flet.core.charts.pie_chart_section import PieChartSection -from flet.core.checkbox import Checkbox -from flet.core.chip import Chip -from flet.core.circle_avatar import CircleAvatar -from flet.core.colors import Colors -from flet.core.column import Column -from flet.core.container import Container, ContainerTapEvent -from flet.core.control import Control -from flet.core.control_event import ControlEvent -from flet.core.cupertino_action_sheet import CupertinoActionSheet -from flet.core.cupertino_action_sheet_action import CupertinoActionSheetAction -from flet.core.cupertino_activity_indicator import CupertinoActivityIndicator -from flet.core.cupertino_alert_dialog import CupertinoAlertDialog -from flet.core.cupertino_app_bar import CupertinoAppBar -from flet.core.cupertino_bottom_sheet import CupertinoBottomSheet -from flet.core.cupertino_button import CupertinoButton -from flet.core.cupertino_checkbox import CupertinoCheckbox -from flet.core.cupertino_colors import CupertinoColors -from flet.core.cupertino_context_menu import CupertinoContextMenu -from flet.core.cupertino_context_menu_action import CupertinoContextMenuAction -from flet.core.cupertino_date_picker import ( - CupertinoDatePicker, - CupertinoDatePickerDateOrder, - CupertinoDatePickerMode, +from flet.controls.colors import Colors +from flet.controls.context import Context, context +from flet.controls.control import Control +from flet.controls.control_event import ( + ControlEvent, + ControlEventHandler, + Event, + EventControlType, + EventHandler, ) -from flet.core.cupertino_dialog_action import CupertinoDialogAction -from flet.core.cupertino_filled_button import CupertinoFilledButton -from flet.core.cupertino_icons import CupertinoIcons -from flet.core.cupertino_list_tile import CupertinoListTile -from flet.core.cupertino_navigation_bar import CupertinoNavigationBar -from flet.core.cupertino_picker import CupertinoPicker -from flet.core.cupertino_radio import CupertinoRadio -from flet.core.cupertino_segmented_button import CupertinoSegmentedButton -from flet.core.cupertino_slider import CupertinoSlider -from flet.core.cupertino_sliding_segmented_button import CupertinoSlidingSegmentedButton -from flet.core.cupertino_switch import CupertinoSwitch -from flet.core.cupertino_textfield import CupertinoTextField, VisibilityMode -from flet.core.cupertino_timer_picker import ( - CupertinoTimerPicker, - CupertinoTimerPickerMode, +from flet.controls.control_state import ( + ControlState, + ControlStateValue, ) -from flet.core.datatable import ( - DataCell, - DataColumn, - DataColumnSortEvent, - DataRow, - DataTable, +from flet.controls.core.animated_switcher import ( + AnimatedSwitcher, + AnimatedSwitcherTransition, ) -from flet.core.date_picker import ( - DatePicker, - DatePickerEntryMode, - DatePickerEntryModeChangeEvent, - DatePickerMode, +from flet.controls.core.autofill_group import ( + AutofillGroup, + AutofillGroupDisposeAction, + AutofillHint, ) -from flet.core.dismissible import ( +from flet.controls.core.column import Column +from flet.controls.core.dismissible import ( Dismissible, DismissibleDismissEvent, DismissibleUpdateEvent, ) -from flet.core.divider import Divider -from flet.core.drag_target import DragTarget, DragTargetEvent -from flet.core.draggable import Draggable -from flet.core.dropdown import Dropdown, DropdownOption -from flet.core.dropdownm2 import DropdownM2 -from flet.core.elevated_button import ElevatedButton -from flet.core.exceptions import ( - FletException, - FletUnimplementedPlatformEception, - FletUnsupportedPlatformException, +from flet.controls.core.drag_target import ( + DragTarget, + DragTargetEvent, + DragTargetLeaveEvent, + DragWillAcceptEvent, ) -from flet.core.expansion_panel import ExpansionPanel, ExpansionPanelList -from flet.core.expansion_tile import ExpansionTile, TileAffinity -from flet.core.file_picker import ( - FilePicker, - FilePickerFileType, - FilePickerResultEvent, - FilePickerUploadEvent, - FilePickerUploadFile, +from flet.controls.core.draggable import Draggable +from flet.controls.core.flet_app import FletApp, FletAppOutputEvent +from flet.controls.core.gesture_detector import GestureDetector +from flet.controls.core.grid_view import GridView +from flet.controls.core.hero import Hero +from flet.controls.core.icon import Icon +from flet.controls.core.image import Image +from flet.controls.core.interactive_viewer import InteractiveViewer +from flet.controls.core.keyboard_listener import ( + KeyboardListener, + KeyDownEvent, + KeyRepeatEvent, + KeyUpEvent, +) +from flet.controls.core.list_view import ListView +from flet.controls.core.markdown import ( + Markdown, + MarkdownCodeTheme, + MarkdownCustomCodeTheme, + MarkdownExtensionSet, + MarkdownStyleSheet, +) +from flet.controls.core.merge_semantics import MergeSemantics +from flet.controls.core.page_view import PageView +from flet.controls.core.pagelet import Pagelet +from flet.controls.core.placeholder import Placeholder +from flet.controls.core.reorderable_drag_handle import ReorderableDragHandle +from flet.controls.core.responsive_row import ResponsiveRow +from flet.controls.core.rotated_box import RotatedBox +from flet.controls.core.row import Row +from flet.controls.core.safe_area import SafeArea +from flet.controls.core.screenshot import Screenshot +from flet.controls.core.semantics import Semantics +from flet.controls.core.shader_mask import ShaderMask +from flet.controls.core.shimmer import Shimmer, ShimmerDirection +from flet.controls.core.stack import Stack, StackFit +from flet.controls.core.text import ( + Text, + TextAffinity, + TextSelection, + TextSelectionChangeCause, + TextSelectionChangeEvent, +) +from flet.controls.core.text_span import TextSpan +from flet.controls.core.transparent_pointer import TransparentPointer +from flet.controls.core.view import View +from flet.controls.core.window import ( + Window, + WindowEvent, + WindowEventType, + WindowResizeEdge, +) +from flet.controls.core.window_drag_area import WindowDragArea +from flet.controls.cupertino import cupertino_colors +from flet.controls.cupertino.cupertino_action_sheet import CupertinoActionSheet +from flet.controls.cupertino.cupertino_action_sheet_action import ( + CupertinoActionSheetAction, +) +from flet.controls.cupertino.cupertino_activity_indicator import ( + CupertinoActivityIndicator, +) +from flet.controls.cupertino.cupertino_alert_dialog import CupertinoAlertDialog +from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar +from flet.controls.cupertino.cupertino_bottom_sheet import CupertinoBottomSheet +from flet.controls.cupertino.cupertino_button import ( + CupertinoButton, + CupertinoButtonSize, +) +from flet.controls.cupertino.cupertino_checkbox import CupertinoCheckbox +from flet.controls.cupertino.cupertino_colors import CupertinoColors +from flet.controls.cupertino.cupertino_context_menu import CupertinoContextMenu +from flet.controls.cupertino.cupertino_context_menu_action import ( + CupertinoContextMenuAction, +) +from flet.controls.cupertino.cupertino_date_picker import ( + CupertinoDatePicker, + CupertinoDatePickerDateOrder, + CupertinoDatePickerMode, +) +from flet.controls.cupertino.cupertino_dialog_action import CupertinoDialogAction +from flet.controls.cupertino.cupertino_filled_button import CupertinoFilledButton +from flet.controls.cupertino.cupertino_list_tile import CupertinoListTile +from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar +from flet.controls.cupertino.cupertino_picker import CupertinoPicker +from flet.controls.cupertino.cupertino_radio import CupertinoRadio +from flet.controls.cupertino.cupertino_segmented_button import CupertinoSegmentedButton +from flet.controls.cupertino.cupertino_slider import CupertinoSlider +from flet.controls.cupertino.cupertino_sliding_segmented_button import ( + CupertinoSlidingSegmentedButton, ) -from flet.core.filled_button import FilledButton -from flet.core.filled_tonal_button import FilledTonalButton -from flet.core.flashlight import Flashlight -from flet.core.flet_app import FletApp -from flet.core.floating_action_button import FloatingActionButton -from flet.core.form_field_control import InputBorder -from flet.core.geolocator import ( - Geolocator, - GeolocatorActivityType, - GeolocatorAndroidSettings, - GeolocatorAppleSettings, - GeolocatorPermissionStatus, - GeolocatorPosition, - GeolocatorPositionAccuracy, - GeolocatorPositionChangeEvent, - GeolocatorSettings, - GeolocatorWebSettings, -) -from flet.core.gesture_detector import ( +from flet.controls.cupertino.cupertino_switch import CupertinoSwitch +from flet.controls.cupertino.cupertino_textfield import ( + CupertinoTextField, + OverlayVisibilityMode, +) +from flet.controls.cupertino.cupertino_timer_picker import ( + CupertinoTimerPicker, + CupertinoTimerPickerMode, +) +from flet.controls.cupertino.cupertino_tinted_button import CupertinoTintedButton +from flet.controls.device_info import ( + AndroidBuildVersion, + AndroidDeviceInfo, + DeviceInfo, + IosDeviceInfo, + IosUtsname, + LinuxDeviceInfo, + MacOsDeviceInfo, + WebBrowserName, + WebDeviceInfo, + WindowsDeviceInfo, +) +from flet.controls.dialog_control import DialogControl +from flet.controls.duration import ( + DateTimeValue, + Duration, + DurationValue, +) +from flet.controls.events import ( + DragDownEvent, DragEndEvent, DragStartEvent, DragUpdateEvent, - GestureDetector, + ForcePressEvent, HoverEvent, + LongPressDownEvent, LongPressEndEvent, + LongPressMoveUpdateEvent, LongPressStartEvent, MultiTapEvent, + PointerEvent, ScaleEndEvent, ScaleStartEvent, ScaleUpdateEvent, ScrollEvent, TapEvent, + TapMoveEvent, ) -from flet.core.gradients import ( +from flet.controls.exceptions import ( + FletException, + FletPageDisconnectedException, + FletUnimplementedPlatformException, + FletUnsupportedPlatformException, +) +from flet.controls.geometry import Rect, Size +from flet.controls.gradients import ( + Gradient, GradientTileMode, LinearGradient, RadialGradient, SweepGradient, ) -from flet.core.grid_view import GridView -from flet.core.haptic_feedback import HapticFeedback -from flet.core.icon import Icon -from flet.core.icon_button import IconButton -from flet.core.icons import Icons -from flet.core.image import Image -from flet.core.interactive_viewer import ( - InteractiveViewer, - InteractiveViewerInteractionEndEvent, - InteractiveViewerInteractionStartEvent, - InteractiveViewerInteractionUpdateEvent, -) -from flet.core.list_tile import ListTile, ListTileStyle, ListTileTitleAlignment -from flet.core.list_view import ListView -from flet.core.lottie import Lottie -from flet.core.margin import Margin -from flet.core.markdown import ( - Markdown, - MarkdownCodeTheme, - MarkdownCustomCodeTheme, - MarkdownExtensionSet, - MarkdownStyleSheet, +from flet.controls.icon_data import IconData +from flet.controls.id_counter import IdCounter +from flet.controls.keys import Key, KeyValue, ScrollKey, ValueKey +from flet.controls.layout_control import ( + ConstrainedControl, + LayoutControl, + LayoutSizeChangeEvent, +) +from flet.controls.margin import Margin, MarginValue +from flet.controls.material import dropdown, dropdownm2 +from flet.controls.material.alert_dialog import AlertDialog +from flet.controls.material.app_bar import AppBar +from flet.controls.material.auto_complete import ( + AutoComplete, + AutoCompleteSelectEvent, + AutoCompleteSuggestion, +) +from flet.controls.material.badge import Badge, BadgeValue +from flet.controls.material.banner import Banner +from flet.controls.material.bottom_app_bar import BottomAppBar +from flet.controls.material.bottom_sheet import BottomSheet +from flet.controls.material.button import Button +from flet.controls.material.card import Card, CardVariant +from flet.controls.material.checkbox import Checkbox +from flet.controls.material.chip import Chip +from flet.controls.material.circle_avatar import CircleAvatar +from flet.controls.material.container import Container +from flet.controls.material.context_menu import ( + ContextMenu, + ContextMenuDismissEvent, + ContextMenuSelectEvent, + ContextMenuTrigger, +) +from flet.controls.material.datatable import ( + DataCell, + DataColumn, + DataColumnSortEvent, + DataRow, + DataTable, ) -from flet.core.menu_bar import MenuBar, MenuStyle -from flet.core.menu_item_button import MenuItemButton -from flet.core.navigation_bar import ( +from flet.controls.material.date_picker import ( + DatePicker, + DatePickerEntryMode, + DatePickerEntryModeChangeEvent, + DatePickerMode, +) +from flet.controls.material.date_range_picker import DateRangePicker +from flet.controls.material.divider import Divider +from flet.controls.material.dropdown import Dropdown, DropdownOption +from flet.controls.material.dropdownm2 import DropdownM2 +from flet.controls.material.elevated_button import ElevatedButton +from flet.controls.material.expansion_panel import ( + ExpansionPanel, + ExpansionPanelList, + ExpansionPanelListChangeEvent, +) +from flet.controls.material.expansion_tile import ExpansionTile, TileAffinity +from flet.controls.material.filled_button import FilledButton +from flet.controls.material.filled_tonal_button import FilledTonalButton +from flet.controls.material.floating_action_button import FloatingActionButton +from flet.controls.material.form_field_control import FormFieldControl, InputBorder +from flet.controls.material.icon_button import ( + FilledIconButton, + FilledTonalIconButton, + IconButton, + OutlinedIconButton, +) +from flet.controls.material.list_tile import ( + ListTile, + ListTileStyle, + ListTileTitleAlignment, +) +from flet.controls.material.menu_bar import MenuBar, MenuStyle +from flet.controls.material.menu_item_button import MenuItemButton +from flet.controls.material.navigation_bar import ( NavigationBar, NavigationBarDestination, NavigationBarLabelBehavior, ) -from flet.core.navigation_drawer import ( +from flet.controls.material.navigation_drawer import ( NavigationDrawer, NavigationDrawerDestination, - NavigationDrawerPosition, ) -from flet.core.navigation_rail import ( +from flet.controls.material.navigation_rail import ( NavigationRail, NavigationRailDestination, NavigationRailLabelType, ) -from flet.core.outlined_button import OutlinedButton -from flet.core.padding import Padding -from flet.core.page import ( +from flet.controls.material.outlined_button import OutlinedButton +from flet.controls.material.popup_menu_button import ( + PopupMenuButton, + PopupMenuItem, + PopupMenuPosition, +) +from flet.controls.material.progress_bar import ProgressBar +from flet.controls.material.progress_ring import ProgressRing +from flet.controls.material.radio import Radio +from flet.controls.material.radio_group import RadioGroup +from flet.controls.material.range_slider import RangeSlider +from flet.controls.material.reorderable_list_view import ( + OnReorderEvent, + ReorderableListView, +) +from flet.controls.material.search_bar import SearchBar +from flet.controls.material.segmented_button import Segment, SegmentedButton +from flet.controls.material.selection_area import SelectionArea +from flet.controls.material.slider import Slider, SliderInteraction +from flet.controls.material.snack_bar import ( + DismissDirection, + SnackBar, + SnackBarAction, + SnackBarBehavior, +) +from flet.controls.material.submenu_button import SubmenuButton +from flet.controls.material.switch import Switch +from flet.controls.material.tabs import ( + Tab, + TabAlignment, + TabBar, + TabBarHoverEvent, + TabBarIndicatorSize, + TabBarView, + TabIndicatorAnimation, + Tabs, + UnderlineTabIndicator, +) +from flet.controls.material.text_button import TextButton +from flet.controls.material.textfield import ( + InputFilter, + KeyboardType, + NumbersOnlyInputFilter, + TextCapitalization, + TextField, + TextOnlyInputFilter, +) +from flet.controls.material.time_picker import ( + TimePicker, + TimePickerEntryMode, + TimePickerEntryModeChangeEvent, + TimePickerHourFormat, +) +from flet.controls.material.tooltip import Tooltip, TooltipTriggerMode, TooltipValue +from flet.controls.material.vertical_divider import VerticalDivider +from flet.controls.multi_view import MultiView +from flet.controls.padding import Padding, PaddingValue +from flet.controls.page import ( AppLifecycleStateChangeEvent, - BrowserContextMenu, KeyboardEvent, + LocaleChangeEvent, LoginEvent, + MultiViewAddEvent, + MultiViewRemoveEvent, Page, - PageDisconnectedException, - PageMediaData, + PlatformBrightnessChangeEvent, RouteChangeEvent, ViewPopEvent, - Window, - WindowEvent, - WindowResizeEvent, - context, + ViewsPopUntilEvent, ) -from flet.core.pagelet import Pagelet -from flet.core.painting import ( +from flet.controls.painting import ( Paint, + PaintGradient, PaintingStyle, PaintLinearGradient, PaintRadialGradient, PaintSweepGradient, ) -from flet.core.permission_handler import ( - PermissionHandler, - PermissionStatus, - PermissionType, +from flet.controls.query_string import QueryString +from flet.controls.ref import Ref +from flet.controls.scrollable_control import ( + OnScrollEvent, + ScrollableControl, + Scrollbar, + ScrollbarOrientation, + ScrollDirection, + ScrollType, ) -from flet.core.placeholder import Placeholder -from flet.core.popup_menu_button import ( - PopupMenuButton, - PopupMenuItem, - PopupMenuPosition, +from flet.controls.services.accelerometer import ( + Accelerometer, + AccelerometerReadingEvent, +) +from flet.controls.services.barometer import Barometer, BarometerReadingEvent +from flet.controls.services.battery import ( + Battery, + BatteryState, + BatteryStateChangeEvent, +) +from flet.controls.services.browser_context_menu import BrowserContextMenu +from flet.controls.services.clipboard import Clipboard +from flet.controls.services.connectivity import ( + Connectivity, + ConnectivityChangeEvent, + ConnectivityType, +) +from flet.controls.services.file_picker import ( + FilePicker, + FilePickerFile, + FilePickerFileType, + FilePickerUploadEvent, + FilePickerUploadFile, ) -from flet.core.progress_bar import ProgressBar -from flet.core.progress_ring import ProgressRing -from flet.core.pubsub.pubsub_client import PubSubClient -from flet.core.pubsub.pubsub_hub import PubSubHub -from flet.core.querystring import QueryString -from flet.core.radio import Radio -from flet.core.radio_group import RadioGroup -from flet.core.range_slider import RangeSlider -from flet.core.ref import Ref -from flet.core.reorderable_draggable import ReorderableDraggable -from flet.core.reorderable_list_view import OnReorderEvent, ReorderableListView -from flet.core.responsive_row import ResponsiveRow -from flet.core.rive import Rive -from flet.core.row import Row -from flet.core.safe_area import SafeArea -from flet.core.scrollable_control import OnScrollEvent -from flet.core.search_bar import SearchBar -from flet.core.segmented_button import Segment, SegmentedButton -from flet.core.selection_area import SelectionArea -from flet.core.semantics import Semantics -from flet.core.semantics_service import Assertiveness, SemanticsService -from flet.core.shader_mask import ShaderMask -from flet.core.shake_detector import ShakeDetector -from flet.core.size import Size -from flet.core.slider import Slider, SliderInteraction -from flet.core.snack_bar import DismissDirection, SnackBar, SnackBarBehavior -from flet.core.stack import Stack, StackFit -from flet.core.submenu_button import SubmenuButton -from flet.core.switch import Switch -from flet.core.tabs import Tab, Tabs -from flet.core.template_route import TemplateRoute -from flet.core.text import Text, TextAffinity, TextSelection -from flet.core.text_button import TextButton -from flet.core.text_span import TextSpan -from flet.core.text_style import ( +from flet.controls.services.gyroscope import Gyroscope, GyroscopeReadingEvent +from flet.controls.services.haptic_feedback import HapticFeedback +from flet.controls.services.magnetometer import Magnetometer, MagnetometerReadingEvent +from flet.controls.services.screen_brightness import ( + ScreenBrightness, + ScreenBrightnessChangeEvent, +) +from flet.controls.services.semantics_service import Assertiveness, SemanticsService +from flet.controls.services.sensor_error_event import SensorErrorEvent +from flet.controls.services.service import Service +from flet.controls.services.shake_detector import ShakeDetector +from flet.controls.services.share import ( + Share, + ShareCupertinoActivityType, + ShareFile, + ShareResult, + ShareResultStatus, +) +from flet.controls.services.shared_preferences import SharedPreferences +from flet.controls.services.storage_paths import StoragePaths +from flet.controls.services.url_launcher import ( + BrowserConfiguration, + LaunchMode, + UrlLauncher, + WebViewConfiguration, +) +from flet.controls.services.user_accelerometer import ( + UserAccelerometer, + UserAccelerometerReadingEvent, +) +from flet.controls.services.wakelock import Wakelock +from flet.controls.template_route import TemplateRoute +from flet.controls.text_style import ( + StrutStyle, TextBaseline, TextDecoration, TextDecorationStyle, @@ -321,145 +510,711 @@ TextStyle, TextThemeStyle, ) -from flet.core.textfield import ( - InputFilter, - KeyboardType, - NumbersOnlyInputFilter, - TextCapitalization, - TextField, - TextOnlyInputFilter, -) -from flet.core.theme import ( - AppBarTheme, - BadgeTheme, - BannerTheme, - BottomAppBarTheme, - BottomSheetTheme, - ButtonTheme, - CardTheme, - CheckboxTheme, - ChipTheme, - ColorScheme, - DataTableTheme, - DatePickerTheme, - DialogTheme, - DividerTheme, - ElevatedButtonTheme, - ExpansionTileTheme, - FilledButtonTheme, - FloatingActionButtonTheme, - IconButtonTheme, - IconTheme, - ListTileTheme, - NavigationBarTheme, - NavigationDrawerTheme, - NavigationRailTheme, - OutlinedButtonTheme, - PageTransitionsTheme, - PageTransitionTheme, - PopupMenuTheme, - ProgressIndicatorTheme, - RadioTheme, - ScrollbarTheme, - SearchBarTheme, - SearchViewTheme, - SegmentedButtonTheme, - SliderTheme, - SnackBarTheme, - SwitchTheme, - SystemOverlayStyle, - TabsTheme, - TextButtonTheme, - TextTheme, - Theme, - TimePickerTheme, - TooltipTheme, -) -from flet.core.time_picker import ( - TimePicker, - TimePickerEntryMode, - TimePickerEntryModeChangeEvent, +from flet.controls.transform import ( + Flip, + Matrix4, + Offset, + OffsetValue, + Rotate, + RotateValue, + Scale, + ScaleValue, + Transform, ) -from flet.core.tooltip import Tooltip, TooltipTriggerMode -from flet.core.transform import Offset, Rotate, Scale -from flet.core.transparent_pointer import TransparentPointer -from flet.core.types import ( - FLET_APP, - FLET_APP_HIDDEN, - FLET_APP_WEB, - WEB_BROWSER, +from flet.controls.types import ( AppLifecycleState, AppView, + AutomaticNotchShape, BlendMode, - BorderRadiusValue, Brightness, + CircularRectangleNotchShape, ClipBehavior, - ColorEnums, ColorValue, - ControlEventType, - ControlState, - ControlStateValue, CrossAxisAlignment, - DateTimeValue, - Duration, - DurationValue, - EventType, + DeviceOrientation, FloatingActionButtonLocation, FontWeight, - IconEnums, - IconValue, - IconValueOrControl, - ImageFit, + IconDataOrControl, ImageRepeat, LabelPosition, Locale, LocaleConfiguration, MainAxisAlignment, - MarginValue, MouseCursor, NotchShape, Number, - OffsetValue, - OnFocusEvent, - OptionalControlEventCallable, - OptionalEventCallable, - OptionalNumber, - OptionalString, Orientation, - PaddingValue, PagePlatform, PointerDeviceType, ResponsiveNumber, - RotateValue, - ScaleValue, + ResponsiveRowBreakpoint, + RouteUrlStrategy, ScrollMode, StrokeCap, StrokeJoin, + StrOrControl, SupportsStr, - TabAlignment, TextAlign, ThemeMode, + Url, UrlTarget, VerticalAlignment, VisualDensity, WebRenderer, - WindowEventType, ) -from flet.core.vertical_divider import VerticalDivider -from flet.core.video import ( - PlaylistMode, - Video, - VideoConfiguration, - VideoMedia, - VideoSubtitleConfiguration, -) -from flet.core.view import View -from flet.core.webview import ( - WebView, - WebviewConsoleMessageEvent, - WebviewJavaScriptEvent, - WebviewLogLevelSeverity, - WebviewRequestMethod, - WebviewScrollEvent, -) -from flet.core.window_drag_area import WindowDragArea +from flet.pubsub.pubsub_client import PubSubClient +from flet.pubsub.pubsub_hub import PubSubHub +from flet.version import flet_version as __version__ + +if TYPE_CHECKING: + from flet.controls.cupertino import cupertino_icons + from flet.controls.cupertino.cupertino_icons import CupertinoIcons + from flet.controls.material import icons + from flet.controls.material.icons import Icons + from flet.controls.theme import ( + AppBarTheme, + BadgeTheme, + BannerTheme, + BottomAppBarTheme, + BottomSheetTheme, + ButtonTheme, + CardTheme, + CheckboxTheme, + ChipTheme, + ColorScheme, + DataTableTheme, + DatePickerTheme, + DialogTheme, + DividerTheme, + DropdownTheme, + ExpansionTileTheme, + FilledButtonTheme, + FloatingActionButtonTheme, + IconButtonTheme, + IconTheme, + ListTileTheme, + NavigationBarTheme, + NavigationDrawerTheme, + NavigationRailTheme, + OutlinedButtonTheme, + PageTransitionsTheme, + PageTransitionTheme, + PopupMenuTheme, + ProgressIndicatorTheme, + RadioTheme, + ScrollbarTheme, + SearchBarTheme, + SearchViewTheme, + SegmentedButtonTheme, + SliderTheme, + SnackBarTheme, + SwitchTheme, + SystemOverlayStyle, + TabBarTheme, + TextButtonTheme, + TextTheme, + Theme, + TimePickerTheme, + TooltipTheme, + ) + +__all__ = [ + "Accelerometer", + "AccelerometerReadingEvent", + "AdaptiveControl", + "AlertDialog", + "Alignment", + "AndroidBuildVersion", + "AndroidDeviceInfo", + "AnimatedSwitcher", + "AnimatedSwitcherTransition", + "Animation", + "AnimationCurve", + "AnimationStyle", + "AnimationValue", + "AppBar", + "AppBarTheme", + "AppCallable", + "AppLifecycleState", + "AppLifecycleStateChangeEvent", + "AppView", + "Assertiveness", + "AutoComplete", + "AutoCompleteSelectEvent", + "AutoCompleteSuggestion", + "AutofillGroup", + "AutofillGroupDisposeAction", + "AutofillHint", + "AutomaticNotchShape", + "Axis", + "Badge", + "BadgeTheme", + "BadgeValue", + "Banner", + "BannerTheme", + "Barometer", + "BarometerReadingEvent", + "BaseControl", + "BasePage", + "Battery", + "BatteryState", + "BatteryStateChangeEvent", + "BeveledRectangleBorder", + "BlendMode", + "Blur", + "BlurStyle", + "BlurTileMode", + "BlurValue", + "Border", + "BorderRadius", + "BorderRadiusValue", + "BorderSide", + "BorderSideStrokeAlign", + "BorderSideStrokeAlignValue", + "BorderStyle", + "BottomAppBar", + "BottomAppBarTheme", + "BottomSheet", + "BottomSheetTheme", + "BoxConstraints", + "BoxDecoration", + "BoxFit", + "BoxShadow", + "BoxShadowValue", + "BoxShape", + "Brightness", + "BrowserConfiguration", + "BrowserContextMenu", + "Button", + "ButtonStyle", + "ButtonTheme", + "Card", + "CardTheme", + "CardVariant", + "Checkbox", + "CheckboxTheme", + "Chip", + "ChipTheme", + "CircleAvatar", + "CircleBorder", + "CircularRectangleNotchShape", + "ClipBehavior", + "Clipboard", + "ColorFilter", + "ColorScheme", + "ColorValue", + "Colors", + "Column", + "Component", + "Connectivity", + "ConnectivityChangeEvent", + "ConnectivityType", + "ConstrainedControl", + "Container", + "Context", + "ContextMenu", + "ContextMenuDismissEvent", + "ContextMenuSelectEvent", + "ContextMenuTrigger", + "ContextProvider", + "ContinuousRectangleBorder", + "Control", + "ControlEvent", + "ControlEventHandler", + "ControlState", + "ControlStateValue", + "CrossAxisAlignment", + "CupertinoActionSheet", + "CupertinoActionSheetAction", + "CupertinoActivityIndicator", + "CupertinoAlertDialog", + "CupertinoAppBar", + "CupertinoBottomSheet", + "CupertinoButton", + "CupertinoButtonSize", + "CupertinoCheckbox", + "CupertinoColors", + "CupertinoContextMenu", + "CupertinoContextMenuAction", + "CupertinoDatePicker", + "CupertinoDatePickerDateOrder", + "CupertinoDatePickerMode", + "CupertinoDialogAction", + "CupertinoFilledButton", + "CupertinoIcons", + "CupertinoListTile", + "CupertinoNavigationBar", + "CupertinoPicker", + "CupertinoRadio", + "CupertinoSegmentedButton", + "CupertinoSlider", + "CupertinoSlidingSegmentedButton", + "CupertinoSwitch", + "CupertinoTextField", + "CupertinoTimerPicker", + "CupertinoTimerPickerMode", + "CupertinoTintedButton", + "DataCell", + "DataColumn", + "DataColumnSortEvent", + "DataRow", + "DataTable", + "DataTableTheme", + "DatePicker", + "DatePickerEntryMode", + "DatePickerEntryModeChangeEvent", + "DatePickerMode", + "DatePickerTheme", + "DateRangePicker", + "DateTimeValue", + "DecorationImage", + "DeviceInfo", + "DeviceOrientation", + "DialogControl", + "DialogTheme", + "DismissDirection", + "Dismissible", + "DismissibleDismissEvent", + "DismissibleUpdateEvent", + "Divider", + "DividerTheme", + "DragDownEvent", + "DragEndEvent", + "DragStartEvent", + "DragTarget", + "DragTargetEvent", + "DragTargetLeaveEvent", + "DragUpdateEvent", + "DragWillAcceptEvent", + "Draggable", + "Dropdown", + "DropdownM2", + "DropdownOption", + "DropdownTheme", + "Duration", + "DurationValue", + "ElevatedButton", + "Event", + "EventControlType", + "EventHandler", + "ExpansionPanel", + "ExpansionPanelList", + "ExpansionPanelListChangeEvent", + "ExpansionTile", + "ExpansionTileTheme", + "FilePicker", + "FilePickerFile", + "FilePickerFileType", + "FilePickerUploadEvent", + "FilePickerUploadFile", + "FilledButton", + "FilledButtonTheme", + "FilledIconButton", + "FilledTonalButton", + "FilledTonalIconButton", + "FilterQuality", + "FletApp", + "FletAppOutputEvent", + "FletException", + "FletPageDisconnectedException", + "FletUnimplementedPlatformException", + "FletUnsupportedPlatformException", + "Flip", + "FloatingActionButton", + "FloatingActionButtonLocation", + "FloatingActionButtonTheme", + "FontWeight", + "ForcePressEvent", + "FormFieldControl", + "GestureDetector", + "Gradient", + "GradientTileMode", + "GridView", + "Gyroscope", + "GyroscopeReadingEvent", + "HapticFeedback", + "Hero", + "HoverEvent", + "Icon", + "IconButton", + "IconButtonTheme", + "IconData", + "IconDataOrControl", + "IconTheme", + "Icons", + "IdCounter", + "Image", + "ImageRepeat", + "InputBorder", + "InputFilter", + "InteractiveViewer", + "IosDeviceInfo", + "IosUtsname", + "Key", + "KeyDownEvent", + "KeyRepeatEvent", + "KeyUpEvent", + "KeyValue", + "KeyboardEvent", + "KeyboardListener", + "KeyboardType", + "LabelPosition", + "LaunchMode", + "LayoutControl", + "LayoutSizeChangeEvent", + "LinearGradient", + "LinuxDeviceInfo", + "ListTile", + "ListTileStyle", + "ListTileTheme", + "ListTileTitleAlignment", + "ListView", + "Locale", + "LocaleChangeEvent", + "LocaleConfiguration", + "LocationInfo", + "LoginEvent", + "LongPressDownEvent", + "LongPressEndEvent", + "LongPressMoveUpdateEvent", + "LongPressStartEvent", + "MacOsDeviceInfo", + "Magnetometer", + "MagnetometerReadingEvent", + "MainAxisAlignment", + "Margin", + "MarginValue", + "Markdown", + "MarkdownCodeTheme", + "MarkdownCustomCodeTheme", + "MarkdownExtensionSet", + "MarkdownStyleSheet", + "Matrix4", + "MenuBar", + "MenuItemButton", + "MenuStyle", + "MergeSemantics", + "MouseCursor", + "MultiTapEvent", + "MultiView", + "MultiViewAddEvent", + "MultiViewRemoveEvent", + "NavigationBar", + "NavigationBarDestination", + "NavigationBarLabelBehavior", + "NavigationBarTheme", + "NavigationDrawer", + "NavigationDrawerDestination", + "NavigationDrawerTheme", + "NavigationRail", + "NavigationRailDestination", + "NavigationRailLabelType", + "NavigationRailTheme", + "NotchShape", + "Number", + "NumbersOnlyInputFilter", + "Observable", + "Offset", + "OffsetValue", + "OnReorderEvent", + "OnScrollEvent", + "Orientation", + "OutlinedBorder", + "OutlinedButton", + "OutlinedButtonTheme", + "OutlinedIconButton", + "OverlayVisibilityMode", + "Padding", + "PaddingValue", + "Page", + "PageMediaData", + "PagePlatform", + "PageResizeEvent", + "PageTransitionTheme", + "PageTransitionsTheme", + "PageView", + "Pagelet", + "Paint", + "PaintGradient", + "PaintLinearGradient", + "PaintRadialGradient", + "PaintSweepGradient", + "PaintingStyle", + "Placeholder", + "PlatformBrightnessChangeEvent", + "PointerDeviceType", + "PointerEvent", + "PopupMenuButton", + "PopupMenuItem", + "PopupMenuPosition", + "PopupMenuTheme", + "ProgressBar", + "ProgressIndicatorTheme", + "ProgressRing", + "PubSubClient", + "PubSubHub", + "QueryString", + "RadialGradient", + "Radio", + "RadioGroup", + "RadioTheme", + "RangeSlider", + "Rect", + "Ref", + "ReorderableDragHandle", + "ReorderableListView", + "ResponsiveNumber", + "ResponsiveRow", + "ResponsiveRowBreakpoint", + "Rotate", + "RotateValue", + "RotatedBox", + "RoundedRectangleBorder", + "Route", + "RouteChangeEvent", + "RouteUrlStrategy", + "Router", + "Row", + "SafeArea", + "Scale", + "ScaleEndEvent", + "ScaleStartEvent", + "ScaleUpdateEvent", + "ScaleValue", + "ScreenBrightness", + "ScreenBrightnessChangeEvent", + "Screenshot", + "ScrollDirection", + "ScrollEvent", + "ScrollKey", + "ScrollMode", + "ScrollType", + "ScrollableControl", + "Scrollbar", + "ScrollbarOrientation", + "ScrollbarTheme", + "SearchBar", + "SearchBarTheme", + "SearchViewTheme", + "Segment", + "SegmentedButton", + "SegmentedButtonTheme", + "SelectionArea", + "Semantics", + "SemanticsService", + "SensorErrorEvent", + "Service", + "ShaderMask", + "ShakeDetector", + "ShapeBorder", + "Share", + "ShareCupertinoActivityType", + "ShareFile", + "ShareResult", + "ShareResultStatus", + "SharedPreferences", + "Shimmer", + "ShimmerDirection", + "Size", + "Slider", + "SliderInteraction", + "SliderTheme", + "SnackBar", + "SnackBarAction", + "SnackBarBehavior", + "SnackBarTheme", + "Stack", + "StackFit", + "StadiumBorder", + "StoragePaths", + "StrOrControl", + "StrokeCap", + "StrokeJoin", + "StrutStyle", + "SubmenuButton", + "SupportsStr", + "SweepGradient", + "Switch", + "SwitchTheme", + "SystemOverlayStyle", + "Tab", + "TabAlignment", + "TabBar", + "TabBarHoverEvent", + "TabBarIndicatorSize", + "TabBarTheme", + "TabBarView", + "TabIndicatorAnimation", + "Tabs", + "TapEvent", + "TapMoveEvent", + "TemplateRoute", + "Text", + "TextAffinity", + "TextAlign", + "TextBaseline", + "TextButton", + "TextButtonTheme", + "TextCapitalization", + "TextDecoration", + "TextDecorationStyle", + "TextField", + "TextOnlyInputFilter", + "TextOverflow", + "TextSelection", + "TextSelectionChangeCause", + "TextSelectionChangeEvent", + "TextSpan", + "TextStyle", + "TextTheme", + "TextThemeStyle", + "Theme", + "ThemeMode", + "TileAffinity", + "TimePicker", + "TimePickerEntryMode", + "TimePickerEntryModeChangeEvent", + "TimePickerHourFormat", + "TimePickerTheme", + "Tooltip", + "TooltipTheme", + "TooltipTriggerMode", + "TooltipValue", + "Transform", + "TransparentPointer", + "UnderlineTabIndicator", + "Url", + "UrlLauncher", + "UrlTarget", + "UserAccelerometer", + "UserAccelerometerReadingEvent", + "Value", + "ValueKey", + "VerticalAlignment", + "VerticalDivider", + "View", + "ViewPopEvent", + "ViewsPopUntilEvent", + "VisualDensity", + "Wakelock", + "WebBrowserName", + "WebDeviceInfo", + "WebRenderer", + "WebViewConfiguration", + "Window", + "WindowDragArea", + "WindowEvent", + "WindowEventType", + "WindowResizeEdge", + "WindowsDeviceInfo", + "__version__", + "alignment", + "app", + "app_async", + "border", + "border_radius", + "component", + "context", + "control", + "create_context", + "cupertino_colors", + "cupertino_icons", + "dropdown", + "dropdownm2", + "icons", + "is_route_active", + "margin", + "memo", + "observable", + "on_mounted", + "on_unmounted", + "on_updated", + "padding", + "run", + "run_async", + "unwrap_component", + "use_callback", + "use_context", + "use_dialog", + "use_effect", + "use_memo", + "use_ref", + "use_route_loader_data", + "use_route_location", + "use_route_outlet", + "use_route_params", + "use_state", + "use_view_path", + "value", +] + +_THEME_EXPORTS = { + "AppBarTheme", + "BadgeTheme", + "BannerTheme", + "BottomAppBarTheme", + "BottomSheetTheme", + "ButtonTheme", + "CardTheme", + "CheckboxTheme", + "ChipTheme", + "ColorScheme", + "DataTableTheme", + "DatePickerTheme", + "DialogTheme", + "DividerTheme", + "DropdownTheme", + "ExpansionTileTheme", + "FilledButtonTheme", + "FloatingActionButtonTheme", + "IconButtonTheme", + "IconTheme", + "ListTileTheme", + "NavigationBarTheme", + "NavigationDrawerTheme", + "NavigationRailTheme", + "OutlinedButtonTheme", + "PageTransitionsTheme", + "PageTransitionTheme", + "PopupMenuTheme", + "ProgressIndicatorTheme", + "RadioTheme", + "ScrollbarTheme", + "SearchBarTheme", + "SearchViewTheme", + "SegmentedButtonTheme", + "SliderTheme", + "SnackBarTheme", + "SwitchTheme", + "SystemOverlayStyle", + "TabBarTheme", + "TextButtonTheme", + "TextTheme", + "Theme", + "TimePickerTheme", + "TooltipTheme", +} + + +def __getattr__(name: str): + if name in _THEME_EXPORTS: + from flet.controls import theme + + return getattr(theme, name) + if name == "Icons": + from flet.controls.material.icons import Icons + + return Icons + if name == "CupertinoIcons": + from flet.controls.cupertino.cupertino_icons import CupertinoIcons + + return CupertinoIcons + if name == "icons": + import importlib + + return importlib.import_module("flet.controls.material.icons") + if name == "cupertino_icons": + import importlib + + return importlib.import_module("flet.controls.cupertino.cupertino_icons") + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/sdk/python/packages/flet/src/flet/ads/__init__.py b/sdk/python/packages/flet/src/flet/ads/__init__.py deleted file mode 100644 index edb108497e..0000000000 --- a/sdk/python/packages/flet/src/flet/ads/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from flet.core.ads.banner import BannerAd -from flet.core.ads.interstitial import InterstitialAd - -""" -from flet.core.ads.native import ( - NativeAd, - NativeAdTemplateStyle, - NativeAdTemplateTextStyle, - NativeTemplateFontStyle, - NativeAdTemplateType, -) -""" diff --git a/sdk/python/packages/flet/src/flet/app.py b/sdk/python/packages/flet/src/flet/app.py index 810a571f35..24061c5e44 100644 --- a/sdk/python/packages/flet/src/flet/app.py +++ b/sdk/python/packages/flet/src/flet/app.py @@ -1,16 +1,19 @@ import asyncio import concurrent.futures +import contextlib +import inspect import logging import os import signal import traceback +from collections.abc import Awaitable from pathlib import Path -from typing import Optional +from typing import Any, Callable, Optional, Union -import flet.version -from flet.core.event import Event -from flet.core.page import Page -from flet.core.types import AppView, WebRenderer +from flet.controls.context import _context_page, context +from flet.controls.page import Page +from flet.controls.types import AppView, RouteUrlStrategy, WebRenderer +from flet.messaging.session import Session from flet.utils import ( get_bool_env_var, get_current_script_dir, @@ -20,31 +23,82 @@ is_pyodide, open_in_browser, ) +from flet.utils.deprecated import deprecated from flet.utils.pip import ( ensure_flet_desktop_package_installed, ensure_flet_web_package_installed, ) -import flet +logger = logging.getLogger("flet") -logger = logging.getLogger(flet.__name__) +AppCallable = Callable[[Page], Union[Any, Awaitable[Any]]] +"""Type alias for Flet app lifecycle callbacks. +Represents a callable (synchronous or asynchronous) that accepts a single argument of +type :class:`~flet.Page`. The return value is ignored. -def app( - target, - name="", - host=None, - port=0, +Used for both `main` and `before_main` handlers. +""" + + +@deprecated("Use run() instead.", version="0.80.0", show_parentheses=True) +def app(*args, **kwargs): + new_args = list(args) + if "target" in kwargs: + new_args.insert(0, kwargs["target"]) + return run(*new_args, **kwargs) + + +@deprecated("Use run() instead.", version="0.80.0", show_parentheses=True) +def app_async(*args, **kwargs): + new_args = list(args) + if "target" in kwargs: + new_args.insert(0, kwargs["target"]) + return run_async(*new_args, **kwargs) + + +def run( + main: AppCallable, + before_main: Optional[AppCallable] = None, + name: str = "", + host: Optional[str] = None, + port: int = 0, view: Optional[AppView] = AppView.FLET_APP, - assets_dir="assets", - upload_dir=None, - web_renderer: WebRenderer = WebRenderer.CANVAS_KIT, - use_color_emoji=False, - route_url_strategy="path", - export_asgi_app=False, + assets_dir: Optional[str] = "assets", + upload_dir: Optional[str] = None, + web_renderer: WebRenderer = WebRenderer.AUTO, + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: Optional[bool] = False, + export_asgi_app: Optional[bool] = False, + target=None, ): + """ + Runs the Flet app. + + Args: + main: Application entry point. Handler (function or coroutine) must + have 1 parameter of instance :class:`~flet.Page`. + before_main: Called after `Page` is created but before `main`. + name: Page/app name used in web URL path when applicable. + host: Host/IP to bind the web server to. + port: TCP port to bind. If `0`, an available port is chosen when needed. + view: Preferred app presentation mode. + assets_dir: A path to app's assets directory. + upload_dir: A path to a directory with uploaded files, + or where uploaded files should be saved. + web_renderer: The type of web renderer to use. + route_url_strategy: The strategy to use for generating URLs. + no_cdn: Whether not load CanvasKit, Pyodide, or fonts from CDN. + export_asgi_app: If `True`, returns a configured ASGI app instead of + running an event loop. + target: Deprecated alias for `main`. + + Returns: + When `export_asgi_app=True`, returns a FastAPI ASGI app. + Otherwise, runs the app and returns `None`. + """ if is_pyodide(): - __run_pyodide(target) + __run_pyodide(main=main or target, before_main=before_main) return if export_asgi_app: @@ -52,18 +106,26 @@ def app( from flet_web.fastapi.serve_fastapi_web_app import get_fastapi_web_app return get_fastapi_web_app( - session_handler=target, + main=main or target, + before_main=before_main, page_name=__get_page_name(name), assets_dir=__get_assets_dir_path(assets_dir, relative_to_cwd=True), upload_dir=__get_upload_dir_path(upload_dir, relative_to_cwd=True), web_renderer=web_renderer, - use_color_emoji=use_color_emoji, route_url_strategy=route_url_strategy, + no_cdn=no_cdn, ) + if isinstance(web_renderer, str): + web_renderer = WebRenderer(web_renderer) + + if isinstance(route_url_strategy, str): + route_url_strategy = RouteUrlStrategy(route_url_strategy) + return asyncio.run( - app_async( - target=target, + run_async( + main=main or target, + before_main=before_main, name=name, host=host, port=port, @@ -71,26 +133,47 @@ def app( assets_dir=assets_dir, upload_dir=upload_dir, web_renderer=web_renderer, - use_color_emoji=use_color_emoji, route_url_strategy=route_url_strategy, + no_cdn=no_cdn, ) ) -async def app_async( - target, - name="", - host=None, - port=0, +async def run_async( + main: AppCallable, + before_main: Optional[AppCallable] = None, + name: str = "", + host: Optional[str] = None, + port: int = 0, view: Optional[AppView] = AppView.FLET_APP, - assets_dir="assets", - upload_dir=None, - web_renderer: WebRenderer = WebRenderer.CANVAS_KIT, - use_color_emoji=False, - route_url_strategy="path", + assets_dir: Optional[str] = "assets", + upload_dir: Optional[str] = None, + web_renderer: WebRenderer = WebRenderer.AUTO, + route_url_strategy: RouteUrlStrategy = RouteUrlStrategy.PATH, + no_cdn: Optional[bool] = False, + target=None, ): + """ + Asynchronously run a Flet app using socket or web server transport. + + Args: + main: Application entry point. Handler (function or coroutine) must + have 1 parameter of instance :class:`~flet.Page`. + before_main: Called after `Page` is created but before `main`. + name: Page/app name used in web URL path when applicable. + host: Host/IP to bind the web server to. + port: TCP port to bind. If `0`, default/free port is selected. + view: Preferred app presentation mode. + assets_dir: Path to app assets directory. + upload_dir: Path to upload directory. + web_renderer: Web renderer type for web-hosted mode. + route_url_strategy: Route URL strategy (`path` or `hash`). + no_cdn: Whether to avoid loading CanvasKit, Pyodide, and fonts from CDN. + target: Deprecated alias for `main`. + """ + if is_pyodide(): - __run_pyodide(target) + __run_pyodide(main=main or target, before_main=before_main) return if isinstance(view, str): @@ -99,6 +182,9 @@ async def app_async( if isinstance(web_renderer, str): web_renderer = WebRenderer(web_renderer) + if isinstance(route_url_strategy, str): + route_url_strategy = RouteUrlStrategy(route_url_strategy) + force_web_server = get_bool_env_var("FLET_FORCE_WEB_SERVER") or is_linux_server() if force_web_server: view = AppView.WEB_BROWSER @@ -119,16 +205,26 @@ async def app_async( page_name = __get_page_name(name) is_socket_server = ( - is_embedded() or view == AppView.FLET_APP or view == AppView.FLET_APP_HIDDEN + is_embedded() or view in [AppView.FLET_APP, AppView.FLET_APP_HIDDEN, None] ) and not force_web_server url_prefix = os.getenv("FLET_DISPLAY_URL_PREFIX") - def on_app_startup(page_url): + def on_app_startup(page_url: str): + """ + Handle app-start notification by logging/printing URL and optional browser open. + + Args: + page_url: Resolved URL of the running app. + """ + if url_prefix is not None: - print(url_prefix, page_url) + parts = [url_prefix, page_url] + if view is not None: + parts.append(view.value) + print(*parts) else: - logger.info(f"App URL: {page_url}") + logger.info("App URL: %s", page_url) if view == AppView.WEB_BROWSER and url_prefix is None and not force_web_server: open_in_browser(page_url) @@ -137,33 +233,44 @@ def on_app_startup(page_url): terminate = asyncio.Event() - def exit_gracefully(signum, frame): - logger.debug("Gracefully terminating Flet app...") - loop.call_soon_threadsafe(terminate.set) - signal.signal(signal.SIGINT, signal.SIG_DFL) - signal.signal(signal.SIGTERM, signal.SIG_DFL) + if not is_embedded(): + + def exit_gracefully(signum, frame): + """ + Signal handler that requests graceful app termination. - signal.signal(signal.SIGINT, exit_gracefully) - signal.signal(signal.SIGTERM, exit_gracefully) + Args: + signum: Received OS signal number. + frame: Current stack frame (unused). + """ + + logger.debug("Gracefully terminating Flet app...") + loop.call_soon_threadsafe(terminate.set) + signal.signal(signal.SIGINT, signal.SIG_DFL) + signal.signal(signal.SIGTERM, signal.SIG_DFL) + + signal.signal(signal.SIGINT, exit_gracefully) + signal.signal(signal.SIGTERM, exit_gracefully) conn = ( await __run_socket_server( port=port, - session_handler=target, + main=main or target, + before_main=before_main, blocking=is_embedded(), ) if is_socket_server else await __run_web_server( - session_handler=target, + main=main or target, + before_main=before_main, host=host, port=port, page_name=page_name, assets_dir=assets_dir, upload_dir=upload_dir, web_renderer=web_renderer, - use_color_emoji=use_color_emoji, route_url_strategy=route_url_strategy, - blocking=(view == AppView.WEB_BROWSER or view is None or force_web_server), + no_cdn=no_cdn, on_startup=on_app_startup, ) ) @@ -172,11 +279,7 @@ def exit_gracefully(signum, frame): try: if ( - ( - view == AppView.FLET_APP - or view == AppView.FLET_APP_HIDDEN - or view == AppView.FLET_APP_WEB - ) + (view in [AppView.FLET_APP, AppView.FLET_APP_HIDDEN, AppView.FLET_APP_WEB]) and not force_web_server and not is_embedded() and url_prefix is None @@ -191,76 +294,105 @@ def exit_gracefully(signum, frame): assets_dir if view != AppView.FLET_APP_WEB else None, view == AppView.FLET_APP_HIDDEN, ) - try: + with contextlib.suppress(Exception): await fvp.wait() - except: - pass close_flet_view(pid_file) elif url_prefix and is_socket_server: on_app_startup(conn.page_url) - try: + with contextlib.suppress(KeyboardInterrupt): + await terminate.wait() + + elif view == AppView.WEB_BROWSER or view is None or force_web_server: + with contextlib.suppress(KeyboardInterrupt): await terminate.wait() - except KeyboardInterrupt: - pass finally: await conn.close() -async def __run_socket_server(port=0, session_handler=None, blocking=False): - from flet.flet_socket_server import FletSocketServer +def __get_on_session_created( + main: Optional[AppCallable], +) -> Callable[[Session], Awaitable[None]]: + """ + Build session-start callback that executes the user `main` handler. - uds_path = os.getenv("FLET_SERVER_UDS_PATH") + Args: + main: User-provided app entry handler. - executor = concurrent.futures.ThreadPoolExecutor() + Returns: + Async callback that initializes page context and runs `main`. + """ + + async def on_session_created(session: Session): + """ + Initialize per-session context and execute app entry handler. + + Args: + session: Active page session. + """ - async def on_event(e): - if e.sessionID in conn.sessions: - await conn.sessions[e.sessionID].on_event_async( - Event(e.eventTarget, e.eventName, e.eventData) - ) - if e.eventTarget == "page" and e.eventName == "close": - logger.info(f"Session closed: {e.sessionID}") - page = conn.sessions.pop(e.sessionID) - page._close() - del page - - async def on_session_created(session_data): - page = Page( - conn, - session_data.sessionID, - executor=executor, - loop=asyncio.get_running_loop(), - ) - await page.fetch_page_details_async() - conn.sessions[session_data.sessionID] = page logger.info("App session started") try: - assert session_handler is not None - if asyncio.iscoroutinefunction(session_handler): - await session_handler(page) + assert main is not None + _context_page.set(session.page) + context.reset_auto_update() + if inspect.iscoroutinefunction(main): + await main(session.page) + + elif inspect.isasyncgenfunction(main): + async for _ in main(session.page): + await session.after_event(session.page) + + elif inspect.isgeneratorfunction(main): + for _ in main(session.page): + await session.after_event(session.page) else: - # run in thread pool - await asyncio.get_running_loop().run_in_executor( - executor, session_handler, page - ) + # run synchronously + main(session.page) + + await session.after_event(session.page) except Exception as e: - print( - f"Unhandled error processing page session {page.session_id}:", - traceback.format_exc(), - ) - page.error(f"There was an error while processing your request: {e}") + logger.error("Unhandled error in main() handler", exc_info=True) + session.error(f"{e}\n{traceback.format_exc()}") + + return on_session_created + + +async def __run_socket_server( + port: int = 0, + main: Optional[AppCallable] = None, + before_main: Optional[AppCallable] = None, + blocking: bool = False, +): + """ + Start Flet socket server transport and return active connection object. + + Args: + port: TCP port to bind (`0` lets OS choose). + main: User app entry handler. + before_main: Optional hook called before `main`. + blocking: Whether server should run in blocking mode. + + Returns: + Started socket-server connection instance. + """ + + from flet.messaging.flet_socket_server import FletSocketServer + + uds_path = os.getenv("FLET_SERVER_UDS_PATH") + + executor = concurrent.futures.ThreadPoolExecutor() conn = FletSocketServer( loop=asyncio.get_running_loop(), port=port, uds_path=uds_path, - on_event=on_event, - on_session_created=on_session_created, + on_session_created=__get_on_session_created(main), + before_main=before_main, blocking=blocking, executor=executor, ) @@ -269,18 +401,38 @@ async def on_session_created(session_data): async def __run_web_server( - session_handler, - host, - port, - page_name, - assets_dir, - upload_dir, + main: Optional[AppCallable], + before_main: Optional[AppCallable], + host: Optional[str], + port: int, + page_name: str, + assets_dir: str, + upload_dir: Optional[str], web_renderer: Optional[WebRenderer], - use_color_emoji, - route_url_strategy, - blocking, - on_startup, + route_url_strategy: RouteUrlStrategy, + no_cdn: Optional[bool], + on_startup: Callable[[str], None], ): + """ + Start FastAPI/uvicorn web transport for Flet and return server handle. + + Args: + main: User app entry handler. + before_main: Optional hook called before `main`. + host: Host/IP to bind the server to. + port: TCP port to bind. + page_name: Web path segment used for page URL. + assets_dir: Resolved assets directory path. + upload_dir: Resolved upload directory path. + web_renderer: Web renderer mode. + route_url_strategy: Route URL strategy (`path` or `hash`). + no_cdn: Whether to disable CDN resources. + on_startup: Callback invoked with resolved page URL. + + Returns: + Running web-server handle with `.page_url` and `.close()`. + """ + ensure_flet_web_package_installed() from flet_web.fastapi.serve_fastapi_web_app import serve_fastapi_web_app @@ -289,14 +441,15 @@ async def __run_web_server( if port == 0: port = get_free_tcp_port() - logger.info(f"Starting Flet web server on port {port}...") + logger.info("Starting Flet web server on port %s...", port) - log_level = logging.getLogger(flet.__name__).getEffectiveLevel() + log_level = logging.getLogger("flet").getEffectiveLevel() if log_level == logging.CRITICAL or log_level == logging.NOTSET: log_level = logging.FATAL return await serve_fastapi_web_app( - session_handler, + main, + before_main=before_main, host=host, url_host=url_host, port=port, @@ -304,57 +457,59 @@ async def __run_web_server( assets_dir=assets_dir, upload_dir=upload_dir, web_renderer=web_renderer, - use_color_emoji=use_color_emoji, route_url_strategy=route_url_strategy, - blocking=blocking, + no_cdn=no_cdn, on_startup=on_startup, log_level=logging.getLevelName(log_level).lower(), ) -def __run_pyodide(target): - import flet_js - from flet.pyodide_connection import PyodideConnection +def __run_pyodide( + main: Optional[AppCallable] = None, + before_main: Optional[AppCallable] = None, +): + """ + Initialize Pyodide connection for browser-embedded execution. - async def on_event(e): - if e.sessionID in conn.sessions: - await conn.sessions[e.sessionID].on_event_async( - Event(e.eventTarget, e.eventName, e.eventData) - ) - if e.eventTarget == "page" and e.eventName == "close": - logger.info(f"Session closed: {e.sessionID}") - del conn.sessions[e.sessionID] - - async def on_session_created(session_data): - page = Page(conn, session_data.sessionID, loop=asyncio.get_running_loop()) - await page.fetch_page_details_async() - conn.sessions[session_data.sessionID] = page - logger.info("App session started") - try: - assert target is not None - if asyncio.iscoroutinefunction(target): - await target(page) - else: - target(page) - except Exception as e: - print( - f"Unhandled error processing page session {page.session_id}:", - traceback.format_exc(), - ) - page.error(f"There was an error while processing your request: {e}") + Args: + main: User app entry handler. + before_main: Optional hook called before `main`. + """ + from flet.messaging.pyodide_connection import PyodideConnection - conn = PyodideConnection( - on_event=on_event, - on_session_created=on_session_created, + PyodideConnection( + on_session_created=__get_on_session_created(main), before_main=before_main ) def __get_page_name(name: str): + """ + Resolve effective page name using argument and environment override. + + Args: + name: Explicit page name from API call. + + Returns: + Effective page name, preferring `FLET_WEB_APP_PATH` when `name` is empty. + """ + env_page_name = os.getenv("FLET_WEB_APP_PATH") return env_page_name if not name and env_page_name else name def __get_assets_dir_path(assets_dir: Optional[str], relative_to_cwd=False): + """ + Resolve assets directory to an absolute path and apply env override. + + Args: + assets_dir: Input assets directory path. + relative_to_cwd: Resolve relative paths from current working directory + instead of current script directory. + + Returns: + Resolved assets directory path or `None`. + """ + if assets_dir: if not Path(assets_dir).is_absolute(): if "_MEI" in __file__: @@ -368,7 +523,7 @@ def __get_assets_dir_path(assets_dir: Optional[str], relative_to_cwd=False): .joinpath(assets_dir) .resolve() ) - logger.info(f"Assets path configured: {assets_dir}") + logger.info("Assets path configured: %s", assets_dir) env_assets_dir = os.getenv("FLET_ASSETS_DIR") if env_assets_dir: @@ -377,11 +532,22 @@ def __get_assets_dir_path(assets_dir: Optional[str], relative_to_cwd=False): def __get_upload_dir_path(upload_dir: Optional[str], relative_to_cwd=False): - if upload_dir: - if not Path(upload_dir).is_absolute(): - upload_dir = str( - Path(os.getcwd() if relative_to_cwd else get_current_script_dir()) - .joinpath(upload_dir) - .resolve() - ) + """ + Resolve upload directory to an absolute path. + + Args: + upload_dir: Input upload directory path. + relative_to_cwd: Resolve relative paths from current working directory + instead of current script directory. + + Returns: + Resolved upload directory path or `None`. + """ + + if upload_dir and not Path(upload_dir).is_absolute(): + upload_dir = str( + Path(os.getcwd() if relative_to_cwd else get_current_script_dir()) + .joinpath(upload_dir) + .resolve() + ) return upload_dir diff --git a/sdk/python/packages/flet/src/flet/auth/__init__.py b/sdk/python/packages/flet/src/flet/auth/__init__.py index ffeb327a5a..bc07555402 100644 --- a/sdk/python/packages/flet/src/flet/auth/__init__.py +++ b/sdk/python/packages/flet/src/flet/auth/__init__.py @@ -1,5 +1,53 @@ +from typing import TYPE_CHECKING, Any + from flet.auth.authorization import Authorization from flet.auth.group import Group from flet.auth.oauth_provider import OAuthProvider from flet.auth.oauth_token import OAuthToken from flet.auth.user import User + +if TYPE_CHECKING: + from flet.auth.authorization_service import AuthorizationService + from flet.auth.providers import ( + Auth0OAuthProvider, + AzureOAuthProvider, + GitHubOAuthProvider, + GoogleOAuthProvider, + ) + +__all__ = [ + "Auth0OAuthProvider", + "Authorization", + "AuthorizationService", + "AzureOAuthProvider", + "GitHubOAuthProvider", + "GoogleOAuthProvider", + "Group", + "OAuthProvider", + "OAuthToken", + "User", +] + + +def __getattr__(name: str) -> Any: + if name == "AuthorizationService": + from flet.auth.authorization_service import AuthorizationService + + return AuthorizationService + if name == "Auth0OAuthProvider": + from flet.auth.providers.auth0_oauth_provider import Auth0OAuthProvider + + return Auth0OAuthProvider + if name == "AzureOAuthProvider": + from flet.auth.providers.azure_oauth_provider import AzureOAuthProvider + + return AzureOAuthProvider + if name == "GitHubOAuthProvider": + from flet.auth.providers.github_oauth_provider import GitHubOAuthProvider + + return GitHubOAuthProvider + if name == "GoogleOAuthProvider": + from flet.auth.providers.google_oauth_provider import GoogleOAuthProvider + + return GoogleOAuthProvider + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/sdk/python/packages/flet/src/flet/auth/authorization.py b/sdk/python/packages/flet/src/flet/auth/authorization.py index a33cdc4e0d..e4e845418b 100644 --- a/sdk/python/packages/flet/src/flet/auth/authorization.py +++ b/sdk/python/packages/flet/src/flet/auth/authorization.py @@ -1,234 +1,52 @@ -import asyncio -import json -import secrets -import threading -import time -from typing import List, Optional, Tuple +from typing import Any -import httpx -from oauthlib.oauth2 import WebApplicationClient -from oauthlib.oauth2.rfc6749.tokens import OAuth2Token - -from flet.auth.oauth_provider import OAuthProvider -from flet.auth.oauth_token import OAuthToken -from flet.auth.user import User -from flet.core.locks import AsyncNopeLock, NopeLock -from flet.utils import is_asyncio -from flet.version import version +__all__ = ["Authorization"] class Authorization: - def __init__( - self, - provider: OAuthProvider, - fetch_user: bool, - fetch_groups: bool, - scope: Optional[List[str]] = None, - ) -> None: - self.fetch_user = fetch_user - self.fetch_groups = fetch_groups - self.scope = scope if scope is not None else [] - self.provider = provider - self.__token: Optional[OAuthToken] = None - self.user: Optional[User] = None - self.__lock = threading.Lock() if not is_asyncio() else NopeLock() - self.__async_lock = asyncio.Lock() if is_asyncio() else AsyncNopeLock() - - # fix scopes - self.scope.extend(self.provider.scopes) - if self.fetch_user: - for s in self.provider.user_scopes: - if s not in self.scope: - self.scope.append(s) - if self.fetch_groups: - for s in self.provider.group_scopes: - if s not in self.scope: - self.scope.append(s) - - def dehydrate_token(self, saved_token: str): - self.__token = OAuthToken.from_json(saved_token) - self.__refresh_token() - self.__fetch_user_and_groups() - - async def dehydrate_token_async(self, saved_token: str): - self.__token = OAuthToken.from_json(saved_token) - await self.__refresh_token_async() - await self.__fetch_user_and_groups_async() - - # token - @property - def token(self) -> Optional[OAuthToken]: - with self.__lock: - self.__refresh_token() - return self.__token - - # token_async - @property - async def token_async(self) -> Optional[OAuthToken]: - async with self.__async_lock: - await self.__refresh_token_async() - return self.__token - - def get_authorization_data(self) -> Tuple[str, str]: - self.state = secrets.token_urlsafe(16) - client = WebApplicationClient(self.provider.client_id) - authorization_url = client.prepare_request_uri( - self.provider.authorization_endpoint, - self.provider.redirect_url, - scope=self.scope, - state=self.state, - code_challenge=self.provider.code_challenge, - code_challenge_method=self.provider.code_challenge_method, - ) - return authorization_url, self.state - - def request_token(self, code: str): - req = self.__get_request_token_request(code) - with httpx.Client(follow_redirects=True) as client: - resp = client.send(req) - resp.raise_for_status() - client = WebApplicationClient(self.provider.client_id) - t = client.parse_request_body_response(resp.text) - self.__token = self.__convert_token(t) - self.__fetch_user_and_groups() - - async def request_token_async(self, code: str): - req = self.__get_request_token_request(code) - async with httpx.AsyncClient(follow_redirects=True) as client: - resp = await client.send(req) - resp.raise_for_status() - client = WebApplicationClient(self.provider.client_id) - t = client.parse_request_body_response(resp.text) - self.__token = self.__convert_token(t) - await self.__fetch_user_and_groups_async() - - def __get_request_token_request(self, code: str): - client = WebApplicationClient(self.provider.client_id) - data = client.prepare_request_body( - code=code, - redirect_uri=self.provider.redirect_url, - client_secret=self.provider.client_secret, - include_client_id=True, - code_verifier=self.provider.code_verifier, - ) - headers = self.__get_default_headers() - headers["content-type"] = "application/x-www-form-urlencoded" - return httpx.Request( - "POST", self.provider.token_endpoint, content=data, headers=headers - ) - - def __fetch_user_and_groups(self): - assert self.__token is not None - if self.fetch_user: - self.user = self.provider._fetch_user(self.__token.access_token) - if self.user is None and self.provider.user_endpoint is not None: - if self.provider.user_id_fn is None: - raise Exception( - "user_id_fn must be specified too if user_endpoint is not None" - ) - self.user = self.__get_user() - if self.fetch_groups and self.user is not None: - self.user.groups = self.provider._fetch_groups( - self.__token.access_token - ) - - async def __fetch_user_and_groups_async(self): - assert self.__token is not None - if self.fetch_user: - self.user = await self.provider._fetch_user_async(self.__token.access_token) - if self.user is None and self.provider.user_endpoint is not None: - if self.provider.user_id_fn is None: - raise Exception( - "user_id_fn must be specified too if user_endpoint is not None" - ) - self.user = await self.__get_user_async() - if self.fetch_groups and self.user is not None: - self.user.groups = await self.provider._fetch_groups_async( - self.__token.access_token - ) - - def __convert_token(self, t: OAuth2Token): - return OAuthToken( - access_token=t["access_token"], - scope=t.get("scope"), - token_type=t.get("token_type"), - expires_in=t.get("expires_in"), - expires_at=t.get("expires_at"), - refresh_token=t.get("refresh_token"), - ) - - def __refresh_token(self): - refresh_req = self.__get_refresh_token_request() - if refresh_req: - with httpx.Client(follow_redirects=True) as client: - refresh_resp = client.send(refresh_req) - self.__complete_refresh_token_request(refresh_resp) - - async def __refresh_token_async(self): - refresh_req = self.__get_refresh_token_request() - if refresh_req: - async with httpx.AsyncClient(follow_redirects=True) as client: - refresh_resp = await client.send(refresh_req) - self.__complete_refresh_token_request(refresh_resp) - - def __get_refresh_token_request(self): - if ( - self.__token is None - or self.__token.expires_at is None - or self.__token.refresh_token is None - or time.time() < self.__token.expires_at - ): - return None - - assert self.__token is not None - client = WebApplicationClient(self.provider.client_id) - data = client.prepare_refresh_body( - client_id=self.provider.client_id, - client_secret=self.provider.client_secret, - refresh_token=self.__token.refresh_token, - redirect_uri=self.provider.redirect_url, - ) - headers = self.__get_default_headers() - headers["content-type"] = "application/x-www-form-urlencoded" - return httpx.Request( - "POST", url=self.provider.token_endpoint, content=data, headers=headers - ) - - def __complete_refresh_token_request(self, refresh_resp): - refresh_resp.raise_for_status() - assert self.__token is not None - client = WebApplicationClient(self.provider.client_id) - t = client.parse_request_body_response(refresh_resp.text) - if t.get("refresh_token") is None: - t["refresh_token"] = self.__token.refresh_token - self.__token = self.__convert_token(t) - - def __get_user(self): - user_req = self.__get_user_request() - with httpx.Client() as client: - user_resp = client.send(user_req) - return self.__complete_user_request(user_resp) - - async def __get_user_async(self): - user_req = self.__get_user_request() - async with httpx.AsyncClient(follow_redirects=True) as client: - user_resp = await client.send(user_req) - return self.__complete_user_request(user_resp) - - def __get_user_request(self): - assert self.token is not None - assert self.provider.user_endpoint is not None - headers = self.__get_default_headers() - headers["Authorization"] = f"Bearer {self.token.access_token}" - return httpx.Request("GET", self.provider.user_endpoint, headers=headers) - - def __complete_user_request(self, user_resp): - user_resp.raise_for_status() - assert self.provider.user_id_fn is not None - uj = json.loads(user_resp.text) - return User(uj, str(self.provider.user_id_fn(uj))) - - def __get_default_headers(self): - return { - "User-Agent": f"Flet/{version}", - } + """ + Abstract authorization contract used by Flet authentication workflows. + + Implementations provide OAuth-style authorization URL/state generation, + token exchange, token hydration from persisted storage, and token retrieval. + """ + + async def dehydrate_token(self, saved_token: str) -> None: + """ + Restore token state from previously persisted token data. + + Args: + saved_token: Serialized token payload. + """ + + raise NotImplementedError() + + async def get_token(self) -> Any: + """ + Return the current token, refreshing it when needed. + + Returns: + Current authorization token object. + """ + + raise NotImplementedError() + + def get_authorization_data(self) -> tuple[str, str]: + """ + Build authorization URL and state for starting auth flow. + + Returns: + A tuple containing authorization URL and generated state value. + """ + + raise NotImplementedError() + + async def request_token(self, code: str) -> None: + """ + Exchange authorization code for access/refresh token data. + + Args: + code: Authorization code returned by provider redirect. + """ + + raise NotImplementedError() diff --git a/sdk/python/packages/flet/src/flet/auth/authorization_service.py b/sdk/python/packages/flet/src/flet/auth/authorization_service.py new file mode 100644 index 0000000000..8dbfca5048 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/auth/authorization_service.py @@ -0,0 +1,269 @@ +import json +import secrets +import time +from collections.abc import Mapping +from typing import Any, Optional + +from flet.auth.authorization import Authorization +from flet.auth.oauth_provider import OAuthProvider +from flet.auth.oauth_token import OAuthToken +from flet.auth.user import User +from flet.version import flet_version + +__all__ = ["AuthorizationService"] + + +class AuthorizationService(Authorization): + """ + OAuth authorization implementation used by :meth:`flet.Page.login`. + + The service coordinates authorization URL generation, token exchange, + token refresh, and optional user/group resolution using the configured + :class:`~flet.auth.OAuthProvider`. + + Args: + provider: Configured :class:`~flet.auth.OAuthProvider` + describing OAuth endpoints, credentials, and optional user/group APIs. + fetch_user: Whether to request provider user profile information. + fetch_groups: Whether to request user groups/roles. + scope: Initial OAuth scopes. The service augments this list + with provider defaults (`provider.scopes`) and, when enabled, + provider user/group scopes. + """ + + def __init__( + self, + provider: OAuthProvider, + fetch_user: bool, + fetch_groups: bool, + scope: Optional[list[str]] = None, + ) -> None: + self.fetch_user = fetch_user + self.fetch_groups = fetch_groups + self.scope = scope if scope is not None else [] + self.provider = provider + self.__token: Optional[OAuthToken] = None + self.user: Optional[User] = None + + # fix scopes + self.scope.extend(self.provider.scopes) + if self.fetch_user: + for s in self.provider.user_scopes: + if s not in self.scope: + self.scope.append(s) + if self.fetch_groups: + for s in self.provider.group_scopes: + if s not in self.scope: + self.scope.append(s) + + async def dehydrate_token(self, saved_token: str): + """ + Restore and validate previously persisted token state. + + The token is deserialized, refreshed when expired, and optionally used + to load user and group metadata. + + Args: + saved_token: JSON-serialized token data produced by + :meth:`flet.auth.oauth_token.OAuthToken.to_json`. + """ + + self.__token = OAuthToken.from_json(saved_token) + await self.__refresh_token() + await self.__fetch_user_and_groups() + + async def get_token(self) -> Optional[OAuthToken]: + """ + Return current token after applying refresh logic when required. + + Returns: + Current :class:`~flet.auth.OAuthToken`, or `None` + if no token is available yet. + """ + + await self.__refresh_token() + return self.__token + + def get_authorization_data(self) -> tuple[str, str]: + """ + Generate authorization URL and CSRF state for OAuth redirect flow. + + Returns: + A tuple of `(authorization_url, state)`. + """ + from oauthlib.oauth2 import WebApplicationClient + + self.state = secrets.token_urlsafe(16) + client = WebApplicationClient(self.provider.client_id) + authorization_url = client.prepare_request_uri( + self.provider.authorization_endpoint, + self.provider.redirect_url, + scope=self.scope, + state=self.state, + code_challenge=self.provider.code_challenge, + code_challenge_method=self.provider.code_challenge_method, + **self.provider.authorization_params, + ) + return authorization_url, self.state + + async def request_token(self, code: str): + """ + Exchange authorization code for access token and optional profile data. + + Args: + code: Provider-issued authorization code returned to redirect URL. + + Raises: + httpx.HTTPStatusError: If token endpoint returns a non-success status. + """ + import httpx + from oauthlib.oauth2 import WebApplicationClient + + client = WebApplicationClient(self.provider.client_id) + data = client.prepare_request_body( + code=code, + redirect_uri=self.provider.redirect_url, + client_secret=self.provider.client_secret, + include_client_id=True, + code_verifier=self.provider.code_verifier, + ) + headers = self.__get_default_headers() + headers["content-type"] = "application/x-www-form-urlencoded" + req = httpx.Request( + "POST", self.provider.token_endpoint, content=data, headers=headers + ) + async with httpx.AsyncClient(follow_redirects=True) as client: + resp = await client.send(req) + resp.raise_for_status() + client = WebApplicationClient(self.provider.client_id) + t = client.parse_request_body_response(resp.text) + self.__token = self.__convert_token(t) + await self.__fetch_user_and_groups() + + async def __fetch_user_and_groups(self): + """ + Populate user and groups according to service/provider configuration. + + Uses provider override hooks first, then optionally falls back to + generic `user_endpoint` + `user_id_fn` retrieval. + + Raises: + ValueError: If `user_endpoint` is configured without `user_id_fn`. + """ + + assert self.__token is not None + if self.fetch_user: + self.user = await self.provider._fetch_user(self.__token.access_token) + if self.user is None and self.provider.user_endpoint is not None: + if self.provider.user_id_fn is None: + raise ValueError( + "user_id_fn must be specified too if user_endpoint is not None" + ) + self.user = await self.__get_user() + if self.fetch_groups and self.user is not None: + self.user.groups = await self.provider._fetch_groups( + self.__token.access_token + ) + + def __convert_token(self, t: Mapping[str, Any]) -> OAuthToken: + """ + Convert oauthlib token mapping to :class:`~flet.auth.OAuthToken`. + + Args: + t: Token dictionary returned by oauthlib client parsing. + + Returns: + Normalized token object used by Flet auth APIs. + """ + + return OAuthToken( + access_token=t["access_token"], + scope=t.get("scope"), + token_type=t.get("token_type"), + expires_in=t.get("expires_in"), + expires_at=t.get("expires_at"), + refresh_token=t.get("refresh_token"), + ) + + async def __refresh_token(self): + """ + Refresh the access token when it is expired and a refresh token is available. + + The method is a no-op when token is missing, non-expiring, not expired, + or does not include a refresh token. + + Raises: + httpx.HTTPStatusError: If the refresh request fails. + """ + + if ( + self.__token is None + or self.__token.expires_at is None + or self.__token.refresh_token is None + or time.time() < self.__token.expires_at + ): + return None + + import httpx + from oauthlib.oauth2 import WebApplicationClient + + assert self.__token is not None + client = WebApplicationClient(self.provider.client_id) + data = client.prepare_refresh_body( + client_id=self.provider.client_id, + client_secret=self.provider.client_secret, + refresh_token=self.__token.refresh_token, + redirect_uri=self.provider.redirect_url, + ) + headers = self.__get_default_headers() + headers["content-type"] = "application/x-www-form-urlencoded" + refresh_req = httpx.Request( + "POST", url=self.provider.token_endpoint, content=data, headers=headers + ) + if refresh_req: + async with httpx.AsyncClient(follow_redirects=True) as client: + refresh_resp = await client.send(refresh_req) + refresh_resp.raise_for_status() + assert self.__token is not None + client = WebApplicationClient(self.provider.client_id) + t = client.parse_request_body_response(refresh_resp.text) + if t.get("refresh_token") is None: + t["refresh_token"] = self.__token.refresh_token + self.__token = self.__convert_token(t) + + async def __get_user(self) -> User: + """ + Fetch user profile from provider `user_endpoint`. + + Returns: + A :class:`~flet.auth.User` built from response payload and + `provider.user_id_fn`. + + Raises: + httpx.HTTPStatusError: If user endpoint request fails. + """ + import httpx + + assert self.__token is not None + assert self.provider.user_endpoint is not None + headers = self.__get_default_headers() + headers["Authorization"] = f"Bearer {self.__token.access_token}" + user_req = httpx.Request("GET", self.provider.user_endpoint, headers=headers) + async with httpx.AsyncClient(follow_redirects=True) as client: + user_resp = await client.send(user_req) + user_resp.raise_for_status() + assert self.provider.user_id_fn is not None + uj = json.loads(user_resp.text) + return User(uj, str(self.provider.user_id_fn(uj))) + + def __get_default_headers(self) -> dict[str, str]: + """ + Build default HTTP headers for OAuth-related requests. + + Returns: + Base headers dictionary containing Flet user agent. + """ + + return { + "User-Agent": f"Flet/{flet_version}", + } diff --git a/sdk/python/packages/flet/src/flet/auth/group.py b/sdk/python/packages/flet/src/flet/auth/group.py index 75e05bf45f..d773037383 100644 --- a/sdk/python/packages/flet/src/flet/auth/group.py +++ b/sdk/python/packages/flet/src/flet/auth/group.py @@ -1,4 +1,25 @@ +from typing import Any + +__all__ = ["Group"] + + class Group(dict): - def __init__(self, kwargs, name: str) -> None: + """ + Group or role entry associated with an authenticated :class:`~flet.auth.User`. + + The instance behaves like a mutable mapping with provider-specific metadata, + while exposing a normalized :attr:`name` attribute commonly used by app logic. + + Args: + kwargs: Provider-specific group fields to store in the mapping. + name: Group name used for display and matching. + """ + + name: str + """ + Human-readable group name. + """ + + def __init__(self, kwargs: dict[str, Any], name: str) -> None: super().__init__(kwargs) self.name = name diff --git a/sdk/python/packages/flet/src/flet/auth/oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/oauth_provider.py index d8c8c0c72e..6288e2cc61 100644 --- a/sdk/python/packages/flet/src/flet/auth/oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/oauth_provider.py @@ -1,10 +1,40 @@ -from typing import Callable, List, Optional +from typing import Callable, Optional from flet.auth.group import Group from flet.auth.user import User class OAuthProvider: + """ + Base configuration and extension point for OAuth providers in Flet. + + Instances describe OAuth endpoints, client credentials, optional PKCE + parameters, and optional user/group retrieval behavior used by + :class:`~flet.auth.AuthorizationService`. + + Args: + client_id: OAuth client/application ID issued by the provider. + client_secret: OAuth client secret issued by the provider. + authorization_endpoint: Authorization endpoint URL used to build the + login redirect URL. + token_endpoint: Token endpoint URL used for authorization-code and + refresh-token exchange. + redirect_url: Redirect/callback URL registered with the provider. + scopes: Base OAuth scopes always requested during login. + user_scopes: Additional scopes requested when user profile loading + is enabled. + user_endpoint: Endpoint used to fetch raw user profile + data after login. + user_id_fn: Function extracting a stable user id from + `user_endpoint` response data. + group_scopes: Additional scopes requested when group loading is enabled. + code_challenge: PKCE code challenge. + code_challenge_method: PKCE challenge method. For example, `S256`. + code_verifier: PKCE code verifier used during token exchange. + authorization_params: Extra query parameters appended to authorization + URL generation by the OAuth authorization service. + """ + def __init__( self, client_id: str, @@ -12,14 +42,15 @@ def __init__( authorization_endpoint: str, token_endpoint: str, redirect_url: str, - scopes: Optional[List[str]] = None, - user_scopes: Optional[List[str]] = None, + scopes: Optional[list[str]] = None, + user_scopes: Optional[list[str]] = None, user_endpoint: Optional[str] = None, user_id_fn: Optional[Callable] = None, - group_scopes: Optional[List[str]] = None, + group_scopes: Optional[list[str]] = None, code_challenge: Optional[str] = None, code_challenge_method: Optional[str] = None, code_verifier: Optional[str] = None, + authorization_params: Optional[dict[str, str]] = None, ) -> None: self.client_id = client_id self.client_secret = client_secret @@ -31,21 +62,43 @@ def __init__( self.user_endpoint = user_endpoint self.user_id_fn = user_id_fn self.group_scopes = group_scopes if group_scopes is not None else [] + self.authorization_params = ( + authorization_params if authorization_params is not None else {} + ) self.code_challenge = code_challenge self.code_challenge_method = code_challenge_method self.code_verifier = code_verifier def _name(self): - raise Exception("Not implemented") + """ + Returns provider name/identifier. - def _fetch_groups(self, access_token: str) -> List[Group]: - return [] + Intended as an optional subclass extension point. + """ + raise NotImplementedError("Subclasses must implement _name()") - async def _fetch_groups_async(self, access_token: str) -> List[Group]: + async def _fetch_groups(self, access_token: str) -> list[Group]: + """ + Fetches user groups from the provider API. + + Args: + access_token: OAuth access token. + + Returns: + A list of :class:`~flet.auth.Group`. The base implementation + returns an empty list. + """ return [] - def _fetch_user(self, access_token: str) -> Optional[User]: - return None + async def _fetch_user(self, access_token: str) -> Optional[User]: + """ + Fetches user profile from the provider API. + + Args: + access_token: OAuth access token. - async def _fetch_user_async(self, access_token: str) -> Optional[User]: + Returns: + A :class:`~flet.auth.User` instance, or `None` to let authorization + fallback logic use `user_endpoint` / `user_id_fn`. + """ return None diff --git a/sdk/python/packages/flet/src/flet/auth/oauth_token.py b/sdk/python/packages/flet/src/flet/auth/oauth_token.py index b65492ac1f..13e94bba24 100644 --- a/sdk/python/packages/flet/src/flet/auth/oauth_token.py +++ b/sdk/python/packages/flet/src/flet/auth/oauth_token.py @@ -1,14 +1,23 @@ import json -from typing import List, Optional +from typing import Optional -from flet.core.embed_json_encoder import EmbedJsonEncoder +from flet.controls.embed_json_encoder import EmbedJsonEncoder + +__all__ = ["OAuthToken"] class OAuthToken: + """ + OAuth token payload used by Flet authentication flows. + + Stores access/refresh token fields and expiry metadata returned by OAuth + token endpoints. + """ + def __init__( self, access_token: str, - scope: Optional[List[str]] = None, + scope: Optional[list[str]] = None, token_type: Optional[str] = None, expires_in: Optional[int] = None, expires_at: Optional[float] = None, @@ -21,10 +30,26 @@ def __init__( self.expires_at = expires_at self.refresh_token = refresh_token - def to_json(self): + def to_json(self) -> str: + """ + Serializes this token to a compact JSON string. + + Returns: + JSON representation suitable for persistence and later hydration via + :meth:`from_json`. + """ return json.dumps(self, cls=EmbedJsonEncoder, separators=(",", ":")) @staticmethod - def from_json(data: str): + def from_json(data: str) -> "OAuthToken": + """ + Deserializes a token from JSON. + + Args: + data: JSON produced by :meth:`to_json`. + + Returns: + A new `OAuthToken` instance. + """ t = json.loads(data) return OAuthToken(**t) diff --git a/sdk/python/packages/flet/src/flet/auth/providers/__init__.py b/sdk/python/packages/flet/src/flet/auth/providers/__init__.py index 0d434e441b..28638f7060 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/__init__.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/__init__.py @@ -2,3 +2,10 @@ from flet.auth.providers.azure_oauth_provider import AzureOAuthProvider from flet.auth.providers.github_oauth_provider import GitHubOAuthProvider from flet.auth.providers.google_oauth_provider import GoogleOAuthProvider + +__all__ = [ + "Auth0OAuthProvider", + "AzureOAuthProvider", + "GitHubOAuthProvider", + "GoogleOAuthProvider", +] diff --git a/sdk/python/packages/flet/src/flet/auth/providers/auth0_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/auth0_oauth_provider.py index fc58726a78..37a790f0d9 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/auth0_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/auth0_oauth_provider.py @@ -1,10 +1,44 @@ +from typing import Optional + from flet.auth.oauth_provider import OAuthProvider +__all__ = ["Auth0OAuthProvider"] + class Auth0OAuthProvider(OAuthProvider): + """ + OAuth provider preset for Auth0. + + Configures Auth0 authorization/token endpoints and user-info retrieval via + `/userinfo`, using the `sub` claim as the user id. + + Attributes: + domain: Auth0 tenant domain (without protocol), for example + `example.us.auth0.com`. + audience: Optional API identifier passed as `audience` authorization + query parameter. + """ + def __init__( - self, domain: str, client_id: str, client_secret: str, redirect_url: str + self, + domain: str, + client_id: str, + client_secret: str, + redirect_url: str, + audience: Optional[str] = None, ) -> None: + """ + Initialize Auth0 OAuth provider configuration. + + Args: + domain: Auth0 tenant domain (without protocol), for example, + `example.us.auth0.com`. + client_id: Auth0 application client ID. + client_secret: Auth0 application client secret. + redirect_url: Redirect/callback URL registered in Auth0. + audience: Auth0 API identifier used to request an access + token targeted for a specific API resource server. + """ super().__init__( client_id=client_id, client_secret=client_secret, @@ -16,5 +50,9 @@ def __init__( user_endpoint=f"https://{domain}/userinfo", user_id_fn=lambda u: u["sub"], group_scopes=[], + authorization_params=( + {"audience": audience} if audience is not None else None + ), ) self.domain = domain + self.audience = audience diff --git a/sdk/python/packages/flet/src/flet/auth/providers/azure_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/azure_oauth_provider.py index 792e243a8b..e83481fca4 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/azure_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/azure_oauth_provider.py @@ -2,8 +2,17 @@ from flet.auth.oauth_provider import OAuthProvider +__all__ = ["AzureOAuthProvider"] + class AzureOAuthProvider(OAuthProvider): + """ + OAuth provider preset for Microsoft Entra ID (Azure AD). + + Uses v2 endpoints for the selected tenant and Microsoft Graph `/me` for + user profile retrieval, with Graph `id` used as the user id. + """ + def __init__( self, client_id: str, diff --git a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py index f65ee69810..9c261676f7 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/github_oauth_provider.py @@ -1,14 +1,22 @@ import json -from typing import List, Optional +from typing import Optional -import httpx from flet.auth.group import Group from flet.auth.oauth_provider import OAuthProvider from flet.auth.user import User -from flet.version import version +from flet.version import flet_version + +__all__ = ["GitHubOAuthProvider"] class GitHubOAuthProvider(OAuthProvider): + """ + OAuth provider preset for GitHub. + + Uses GitHub OAuth endpoints and fetches user profile/groups via GitHub REST + APIs (`/user`, `/user/emails`, `/user/teams`). + """ + def __init__(self, client_id: str, client_secret: str, redirect_url: str) -> None: super().__init__( client_id=client_id, @@ -20,77 +28,88 @@ def __init__(self, client_id: str, client_secret: str, redirect_url: str) -> Non group_scopes=["read:org"], ) - def _fetch_groups(self, access_token: str) -> List[Group]: - with httpx.Client(follow_redirects=True) as client: - teams_resp = client.send(self.__get_user_teams_request(access_token)) - return self.__complete_fetch_groups(teams_resp) + async def _fetch_groups(self, access_token: str) -> list[Group]: + """ + Retrieves GitHub teams for the authenticated user. - async def _fetch_groups_async(self, access_token: str) -> List[Group]: - async with httpx.AsyncClient(follow_redirects=True) as client: - teams_resp = await client.send(self.__get_user_teams_request(access_token)) - return self.__complete_fetch_groups(teams_resp) - - def __get_user_teams_request(self, access_token): - return httpx.Request( - "GET", - "https://api.github.com/user/teams", - headers=self.__get_client_headers(access_token), - ) + Args: + access_token: OAuth access token. - def __complete_fetch_groups(self, teams_resp): - teams_resp.raise_for_status() - groups = [] - tj = json.loads(teams_resp.text) - for t in tj: - groups.append( - Group( - t, - name=t["name"], + Returns: + A list of :class:`~flet.auth.Group` mapped from `/user/teams`. + """ + import httpx + + async with httpx.AsyncClient(follow_redirects=True) as client: + teams_resp = await client.send( + httpx.Request( + "GET", + "https://api.github.com/user/teams", + headers=self.__get_client_headers(access_token), ) ) - return groups + teams_resp.raise_for_status() + groups = [] + tj = json.loads(teams_resp.text) + for t in tj: + groups.append( + Group( + t, + name=t["name"], + ) + ) + return groups + + async def _fetch_user(self, access_token: str) -> Optional[User]: + """ + Retrieves the GitHub user profile and primary email. - def _fetch_user(self, access_token: str) -> Optional[User]: - user_req, emails_req = self.__get_user_details_requests(access_token) - with httpx.Client(follow_redirects=True) as client: - user_resp = client.send(user_req) - emails_resp = client.send(emails_req) - return self.__complete_fetch_user_details(user_resp, emails_resp) + Args: + access_token: OAuth access token. + + Returns: + A :class:`~flet.auth.User` built from `/user`; its `email` is populated + from the primary address in `/user/emails` when available. + """ + import httpx - async def _fetch_user_async(self, access_token: str) -> Optional[User]: - user_req, emails_req = self.__get_user_details_requests(access_token) async with httpx.AsyncClient(follow_redirects=True) as client: - user_resp = await client.send(user_req) - emails_resp = await client.send(emails_req) - return self.__complete_fetch_user_details(user_resp, emails_resp) - - def __get_user_details_requests(self, access_token): - return ( - httpx.Request( - "GET", - "https://api.github.com/user", - headers=self.__get_client_headers(access_token), - ), - httpx.Request( - "GET", - "https://api.github.com/user/emails", - headers=self.__get_client_headers(access_token), - ), - ) + user_resp = await client.send( + httpx.Request( + "GET", + "https://api.github.com/user", + headers=self.__get_client_headers(access_token), + ) + ) + user_resp.raise_for_status() + uj = json.loads(user_resp.text) + + emails_resp = await client.send( + httpx.Request( + "GET", + "https://api.github.com/user/emails", + headers=self.__get_client_headers(access_token), + ) + ) + emails_resp.raise_for_status() + ej = json.loads(emails_resp.text) + for e in ej: + if e["primary"]: + uj["email"] = e["email"] + break + return User(uj, id=str(uj["id"])) + + def __get_client_headers(self, access_token: str) -> dict[str, str]: + """ + Builds common GitHub API request headers. + + Args: + access_token: OAuth access token. - def __complete_fetch_user_details(self, user_resp, emails_resp): - user_resp.raise_for_status() - emails_resp.raise_for_status() - uj = json.loads(user_resp.text) - ej = json.loads(emails_resp.text) - for e in ej: - if e["primary"]: - uj["email"] = e["email"] - break - return User(uj, id=str(uj["id"])) - - def __get_client_headers(self, access_token): + Returns: + Headers with `Authorization` bearer token and Flet `User-Agent`. + """ return { "Authorization": f"Bearer {access_token}", - "User-Agent": f"Flet/{version}", + "User-Agent": f"Flet/{flet_version}", } diff --git a/sdk/python/packages/flet/src/flet/auth/providers/google_oauth_provider.py b/sdk/python/packages/flet/src/flet/auth/providers/google_oauth_provider.py index 85cc0492af..d49af6e9bb 100644 --- a/sdk/python/packages/flet/src/flet/auth/providers/google_oauth_provider.py +++ b/sdk/python/packages/flet/src/flet/auth/providers/google_oauth_provider.py @@ -1,7 +1,16 @@ from flet.auth.oauth_provider import OAuthProvider +__all__ = ["GoogleOAuthProvider"] + class GoogleOAuthProvider(OAuthProvider): + """ + OAuth provider preset for Google accounts. + + Configures Google OAuth endpoints and user-info retrieval via the OpenID + Connect userinfo endpoint, using `sub` as the user id. + """ + def __init__(self, client_id: str, client_secret: str, redirect_url: str) -> None: super().__init__( client_id=client_id, diff --git a/sdk/python/packages/flet/src/flet/auth/user.py b/sdk/python/packages/flet/src/flet/auth/user.py index d1ae11b558..e8c8ebc93e 100644 --- a/sdk/python/packages/flet/src/flet/auth/user.py +++ b/sdk/python/packages/flet/src/flet/auth/user.py @@ -1,5 +1,34 @@ +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from flet.auth.group import Group + +__all__ = ["User"] + + class User(dict): - def __init__(self, kwargs, id: str) -> None: + """ + Authenticated user profile used by Flet authorization flows. + + The instance is a mutable mapping with provider-specific user fields and + normalized attributes such as :attr:`id` and :attr:`groups`. + + Args: + kwargs: Provider-specific user fields to store in the mapping. + id: Stable user identifier. + """ + + id: str + """ + Provider user identifier represented as a string. + """ + + groups: list["Group"] + """ + Groups loaded for this user when group retrieval is enabled. + """ + + def __init__(self, kwargs: dict[str, Any], id: str) -> None: super().__init__(kwargs) self.id = id self.groups = [] diff --git a/sdk/python/packages/flet/src/flet/canvas/__init__.py b/sdk/python/packages/flet/src/flet/canvas/__init__.py index bf541dd231..32ddb51542 100644 --- a/sdk/python/packages/flet/src/flet/canvas/__init__.py +++ b/sdk/python/packages/flet/src/flet/canvas/__init__.py @@ -1,12 +1,33 @@ -from flet.core.canvas.arc import Arc -from flet.core.canvas.canvas import Canvas, CanvasResizeEvent -from flet.core.canvas.circle import Circle -from flet.core.canvas.color import Color -from flet.core.canvas.fill import Fill -from flet.core.canvas.line import Line -from flet.core.canvas.oval import Oval -from flet.core.canvas.path import Path -from flet.core.canvas.points import PointMode, Points -from flet.core.canvas.rect import Rect -from flet.core.canvas.shadow import Shadow -from flet.core.canvas.text import Text +from flet.controls.core.canvas.arc import Arc +from flet.controls.core.canvas.canvas import Canvas, CanvasResizeEvent +from flet.controls.core.canvas.circle import Circle +from flet.controls.core.canvas.color import Color +from flet.controls.core.canvas.fill import Fill +from flet.controls.core.canvas.image import Image +from flet.controls.core.canvas.line import Line +from flet.controls.core.canvas.oval import Oval +from flet.controls.core.canvas.path import Path +from flet.controls.core.canvas.points import PointMode, Points +from flet.controls.core.canvas.rect import Rect +from flet.controls.core.canvas.shadow import Shadow +from flet.controls.core.canvas.shape import Shape +from flet.controls.core.canvas.text import Text + +__all__ = [ + "Arc", + "Canvas", + "CanvasResizeEvent", + "Circle", + "Color", + "Fill", + "Line", + "Oval", + "Path", + "PointMode", + "Points", + "Rect", + "Shadow", + "Text", + "Image", + "Shape", +] diff --git a/sdk/python/packages/flet/src/flet/cli.py b/sdk/python/packages/flet/src/flet/cli.py index 2bc8eac4e0..df894ac9f2 100644 --- a/sdk/python/packages/flet/src/flet/cli.py +++ b/sdk/python/packages/flet/src/flet/cli.py @@ -1,6 +1,3 @@ -import subprocess -import sys - from flet.utils.pip import ensure_flet_cli_package_installed diff --git a/sdk/python/packages/flet/src/flet/components/__init__.py b/sdk/python/packages/flet/src/flet/components/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/components/component.py b/sdk/python/packages/flet/src/flet/components/component.py new file mode 100644 index 0000000000..085babbfd5 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/component.py @@ -0,0 +1,537 @@ +from __future__ import annotations + +import logging +import weakref +from collections import defaultdict +from dataclasses import dataclass, field +from typing import Any, Callable, TypeVar + +from flet.components.hooks.hook import Hook +from flet.components.hooks.use_effect import EffectHook +from flet.components.observable import Observable, ObservableSubscription +from flet.components.utils import ( + _CURRENT_RENDERER, + shallow_compare_args_and_kwargs, +) +from flet.controls.base_control import BaseControl, control +from flet.controls.context import context + +logger = logging.getLogger("flet_components") +logger.setLevel(logging.INFO) + + +@dataclass +class _ComponentState: + """ + Internal mutable state backing a `Component` instance. + + Stores hook registry/cursor, memoization snapshots, mount flags, and + observable argument subscriptions used across render cycles. + """ + + hooks: list[Hook] = field(default_factory=list) + hook_cursor: int = 0 + mounted: bool = False + is_dirty: bool = False + observable_subscriptions: list[ObservableSubscription] = field(default_factory=list) + last_args: tuple[Any, ...] = field(default_factory=tuple) + last_kwargs: dict[str, Any] = field(default_factory=dict) + last_b: Any = None + + def change_owner(self, new_owner: Any): + """ + Rebind all state-owned hooks/subscriptions to a new component instance. + + Used when component state is migrated between instances. + + Args: + new_owner: New component that should own all hooks/subscriptions. + """ + + for hook in self.hooks: + hook.component = new_owner + for sub in self.observable_subscriptions: + sub.component = new_owner + + +HookTypeT = TypeVar("HookTypeT", bound=Hook) + + +@control("C") +class Component(BaseControl): + """ + Functional component wrapper used by the component renderer. + + A component keeps hook state, tracks observable argument dependencies, + renders a function body into controls, and schedules updates/effects + through the active page session. + """ + + fn: Callable[..., Any] = field(metadata={"skip": True}) + args: tuple[Any, ...] = field(default_factory=tuple, metadata={"skip": True}) + kwargs: dict[str, Any] = field(default_factory=dict, metadata={"skip": True}) + _parent_component: weakref.ref[Component] | None = field( + default=None, metadata={"skip": True} + ) + _state: _ComponentState = field( + default_factory=_ComponentState, metadata={"skip": True} + ) + _contexts: dict[object, Any] = field(default_factory=dict, metadata={"skip": True}) + memoized: bool = field(default=False, metadata={"skip": True}) + _stale: bool = field(default=False, metadata={"skip": True}) + + visible: bool = True + + _b: Any = None # body + + def _migrate_state(self, other: BaseControl): + super()._migrate_state(other) + logger.debug("%s._migrate_state(%s)", self, other) + if not isinstance(other, Component): + return + # Hooks are positional. Migrating state between different component + # functions can mix incompatible hook types (e.g. ContextHook -> StateHook). + if self.fn is not other.fn: + return + self._state = other._state + self._state.change_owner(self) + other._stale = True + + def update(self): + """ + Render component body and patch changed output to the session. + """ + + if self._stale: + logger.debug("%s.update(): skipping (stale)", self) + return + + # Don't re-render unmounted components. A stale observable listener + # (or queued pending update) can fire after `will_unmount` — running + # the component body here would create a new render tree that is + # never attached, leaking fresh subscriptions and zombie children. + if not self._state.mounted: + logger.debug("%s.update(): skipping (unmounted)", self) + return + + logger.debug( + "%s.update(), memoized: %s", + self, + self.memoized, + ) + + self._state.is_dirty = False + + # new rendering + self._state.hook_cursor = 0 + self._detach_observable_subscriptions() + self._subscribe_observable_args(self.args, self.kwargs) + + b = Renderer(self).render(self.fn, *self.args, **self.kwargs) + + for item in b if isinstance(b, list) else [b] if b is not None else []: + object.__setattr__(item, "_frozen", True) + + if self.memoized and b is not None: + logger.debug("%s.update(): memoizing", self) + self._state.last_b = b + self._state.last_args = self.args + self._state.last_kwargs = self.kwargs + + # patch component + if b is not None: + context.page.session.patch_control( + prev_control={"_b": self._b}, + control={"_b": b}, + parent=self, + path=[], + frozen=True, + ) + + self._b = b + self._run_render_effects() + + def before_update(self): + logger.debug("%s.before_update(), memoized: %s", self, self.memoized) + is_dirty = self._state.is_dirty + self._state.is_dirty = False + + if ( + self.memoized + and not is_dirty + and shallow_compare_args_and_kwargs( + self._state.last_args, self._state.last_kwargs, self.args, self.kwargs + ) + and self._state.last_b is not None + ): + logger.debug("%s.before_update(): skipping (memo)", self) + self._b = self._state.last_b + + # fix parent + for item in self._b if isinstance(self._b, list) else [self._b]: + object.__setattr__(item, "_parent", weakref.ref(self)) + return + + self._state.hook_cursor = 0 + self._detach_observable_subscriptions() + self._subscribe_observable_args(self.args, self.kwargs) + b = Renderer(self).render(self.fn, *self.args, **self.kwargs) + + for item in b if isinstance(b, list) else [b] if b is not None else []: + object.__setattr__(item, "_frozen", True) + + if self.memoized and b is not None: + logger.debug("%s.before_update(): memoizing", self) + self._state.last_b = b + self._state.last_args = self.args + self._state.last_kwargs = self.kwargs + self._b = b + self._run_render_effects() + + def _schedule_update(self): + """ + Mark component dirty and enqueue a session update. + """ + + # Skip updates for unmounted components. Stale observable listeners + # that fire after will_unmount must not resurrect a zombie control. + if not self._state.mounted: + logger.debug("%s.schedule_update(): skipping (unmounted)", self) + return + + logger.debug("%s.schedule_update()", self) + self._state.is_dirty = True + context.page.session.schedule_update(self) + + def _schedule_effect(self, hook: EffectHook, is_cleanup: bool = False): + """ + Enqueue effect or effect-cleanup execution in session scheduler. + + Args: + hook: Effect hook to execute. + is_cleanup: Whether to run hook cleanup instead of effect body. + """ + + logger.debug("%s.schedule_effect(%s, %s)", self, hook, is_cleanup) + context.page.session.schedule_effect(hook, is_cleanup) + + def _subscribe_observable_args(self, args: tuple[Any, ...], kwargs: dict[str, Any]): + """ + Attach subscriptions for observable positional/keyword arguments. + + Args: + args: Positional arguments passed to the component function. + kwargs: Keyword arguments passed to the component function. + """ + + for a in args: + if isinstance(a, Observable): + self._attach_observable_subscription(a) + for v in kwargs.values(): + if isinstance(v, Observable): + self._attach_observable_subscription(v) + + def _attach_observable_subscription(self, observable: Observable): + """ + Subscribe component updates to an observable argument. + + Args: + observable: Observable object to subscribe to. + + Returns: + Created observable subscription. + """ + + # Use weak refs to avoid cycles + logger.debug("%s._attach_observable_subscription(%s)", self, observable) + + self._state.observable_subscriptions.append( + ObservableSubscription(owner=self, observable=observable) + ) + return self._state.observable_subscriptions[-1] + + def _detach_observable_subscription(self, subscription: ObservableSubscription): + """ + Dispose and remove one observable subscription if still attached. + + Args: + subscription: Subscription to detach. + """ + + if subscription in self._state.observable_subscriptions: + subscription.dispose() + self._state.observable_subscriptions.remove(subscription) + + def _detach_observable_subscriptions(self): + """ + Dispose and clear all observable subscriptions for this component. + """ + + for subscription in self._state.observable_subscriptions: + subscription.dispose() + self._state.observable_subscriptions.clear() + + def use_hook(self, default: Callable[[], HookTypeT]) -> HookTypeT: + """ + Return hook instance for current render slot, creating it if missing. + + Args: + default: Factory used to initialize a hook for a new slot. + + Returns: + Hook instance bound to the current hook cursor position. + """ + + hook_cursor = self._state.hook_cursor + + i = hook_cursor + hook_cursor += 1 + + if i >= len(self._state.hooks): + self._state.hooks.append(default()) + + self._state.hook_cursor = hook_cursor + return self._state.hooks[i] # type: ignore + + def _run_mount_effects(self): + """ + Schedule all effect hooks for initial mount execution. + """ + + if self._state.hooks: + logger.debug("%s._run_mount_effects()", self) + for hook in self._state.hooks: + if isinstance(hook, EffectHook): + # all effects are running on mount + self._schedule_effect(hook, is_cleanup=False) + + def _run_render_effects(self): + """ + Schedule effect hooks that should run after re-render. + + Effects with empty dependencies are ignored after mount; all others are + evaluated against previous dependencies and cleanup state. + """ + + if not self._state.mounted: + return + if self._state.hooks: + logger.debug("%s._run_render_effects()", self) + for hook in self._state.hooks: + if isinstance(hook, EffectHook) and hook.deps != []: + deps_changed = ( + hook.deps is None + or hook.prev_deps is None + or hook.deps != hook.prev_deps + ) + if deps_changed: + if callable(hook.cleanup): + self._schedule_effect(hook, is_cleanup=True) + self._schedule_effect(hook, is_cleanup=False) + + def _run_unmount_effects(self): + """ + Schedule cleanup for effect hooks and clear hook state on unmount. + """ + + if self._state.hooks: + logger.debug("%s._run_unmount_effects()", self) + for hook in self._state.hooks: + # all effects are running on unmount + if isinstance(hook, EffectHook) and callable(hook.cleanup): + self._schedule_effect(hook, is_cleanup=True) + self._state.hooks.clear() + + def did_mount(self): + """ + Mark component mounted and run mount-time effects. + """ + + super().did_mount() + self._state.mounted = True + self._run_mount_effects() + + def will_unmount(self): + """ + Mark component unmounted, detach observable listeners, and run cleanups. + """ + + super().will_unmount() + self._state.mounted = False + self._detach_observable_subscriptions() + self._run_unmount_effects() + self._b = None + self._state.last_b = None + self._state.last_args = () + self._state.last_kwargs = {} + self._contexts.clear() + + def __str__(self): + return f"{self._c}:{self.fn.__name__}({self._i} - {id(self)})" + + +# +# Renderer +# + + +class Renderer: + """ + Rendering coordinator for functional components and context stacks. + + Maintains current render stack, temporary memo flag, and provider context + values used while creating component wrappers. + """ + + _ROOT_TOKEN = ("__root__",) + + def __init__(self, root_component=None): + self._root_component = root_component + self._render_stack: list[Component] = [] + self._is_memo = False + self._contexts: dict[object, list[object]] = defaultdict(list) + + def set_memo(self): + """ + Mark next rendered component as memoized. + """ + + self._is_memo = True + + def push_context(self, key: object, value: object) -> None: + """ + Push a context value for the given key. + + Args: + key: Context identity token. + value: Context value to make active. + """ + + logger.debug("Renderer._push_context(%s, %s)", key, value) + self._contexts[key].append(value) + + def pop_context(self, key: object) -> None: + """ + Pop current context value for key and remove empty stacks. + + Args: + key: Context identity token. + """ + + logger.debug("Renderer._pop_context(%s)", key) + stack = self._contexts.get(key) + if stack: + stack.pop() + if not stack: + del self._contexts[key] + + def _snapshot_contexts(self) -> dict[object, object]: + """ + Snapshot currently active context values. + + Returns: + Dictionary containing the top value for each context key. + """ + + # take top of each stack + return {k: v[-1] for k, v in self._contexts.items() if v} + + def with_context(self): + """Context manager to make this renderer the 'current' one.""" + return self._Context(self) + + def render(self, root_fn: Callable[..., Any], *args, **kwargs): + """ + Render a root callable within this renderer context/frame. + + Args: + root_fn: Callable producing component output. + *args: Positional arguments forwarded to `root_fn`. + **kwargs: Keyword arguments forwarded to `root_fn`. + + Returns: + Value returned by `root_fn`. + """ + + # run with this renderer bound as current + with self.with_context(), self._Frame(self, self._root_component): + return root_fn(*args, **kwargs) + + def render_component( + self, + fn: Callable[..., Any], + args: tuple[Any, ...], + kwargs: dict[str, Any], + key=None, + ): + """ + Create a frozen `Component` wrapper for a function call. + + Args: + fn: Component function decorated with `@component`. + args: Positional arguments for the component function. + kwargs: Keyword arguments for the component function. + key: Optional identity key. + + Returns: + Component wrapper ready for normal control lifecycle/rendering. + + Raises: + ValueError: If `fn` is not marked as a component function. + """ + + logger.debug( + "Renderer._render_component(%s, %s, %s, %s)", fn, args, kwargs, key + ) + parent_component = len(self._render_stack) and self._render_stack[-1] + + if not hasattr(fn, "__is_component__"): + raise ValueError(f"Function {fn} is not a component (missing @component?)") + + c = Component( + fn=fn, + args=args, + kwargs=kwargs, + _parent_component=weakref.ref(parent_component) + if parent_component + else None, + memoized=self._is_memo, + key=key, + ) + c._contexts = self._snapshot_contexts() + c._frozen = True + + self._is_memo = False + + return c + + class _Frame: + """Context around entering a component; pushes/pops on renderer's stack.""" + + def __init__(self, renderer: Renderer, c: Component | None = None): + self.r = renderer + self.c = c + + def __enter__(self): + if self.c: + self.r._render_stack.append(self.c) + return self.c + + def __exit__(self, exc_type, exc, tb): + if self.c: + self.r._render_stack.pop() + + class _Context: + """Context around temporarily binding the current renderer.""" + + def __init__(self, renderer: Renderer): + self._renderer = renderer + self._token = None + + def __enter__(self): + self._token = _CURRENT_RENDERER.set(self._renderer) + return self._renderer + + def __exit__(self, exc_type, exc, tb): + if self._token is not None: + _CURRENT_RENDERER.reset(self._token) diff --git a/sdk/python/packages/flet/src/flet/components/component_decorator.py b/sdk/python/packages/flet/src/flet/components/component_decorator.py new file mode 100644 index 0000000000..f2cce32494 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/component_decorator.py @@ -0,0 +1,31 @@ +from functools import wraps +from typing import Callable, ParamSpec, TypeVar + +from flet.components.utils import current_renderer + +P = ParamSpec("P") +R = TypeVar("R") + + +def component(fn: Callable[P, R]) -> Callable[P, R]: + """ + Marks a function as a component. + """ + fn.__is_component__ = True + + @wraps(fn) + def component_wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + """ + Creates a component node for this call within the current renderer. + + Extracts optional `key` from keyword arguments, then delegates to + `Renderer.render_component(...)` so the wrapped function is tracked as a + component in the render tree. + """ + key = kwargs.pop("key", None) + r = current_renderer() + return r.render_component(fn, args, kwargs, key=key) + + component_wrapper.__is_component__ = True + component_wrapper.__component_impl__ = fn + return component_wrapper diff --git a/sdk/python/packages/flet/src/flet/components/component_owned.py b/sdk/python/packages/flet/src/flet/components/component_owned.py new file mode 100644 index 0000000000..9247fc8c79 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/component_owned.py @@ -0,0 +1,35 @@ +import weakref +from dataclasses import InitVar, dataclass +from typing import TYPE_CHECKING, Optional + +if TYPE_CHECKING: + from flet.components.component import Component + + +@dataclass() +class ComponentOwned: + """ + Base mixin for objects owned by a component via weak reference. + + Used by hook/subscription state objects that must reference their owning + component without creating strong-reference cycles. + """ + + owner: InitVar["Component"] + + def __post_init__(self, owner: "Component") -> None: + self._component = weakref.ref(owner) + + @property + def component(self) -> Optional["Component"]: + """ + The current owning component, if still alive. + + Returns: + The owner component, or `None` if the weak reference is no longer valid. + """ + return self._component() + + @component.setter + def component(self, value: "Component") -> None: + self._component = weakref.ref(value) diff --git a/sdk/python/packages/flet/src/flet/components/hooks/__init__.py b/sdk/python/packages/flet/src/flet/components/hooks/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/components/hooks/hook.py b/sdk/python/packages/flet/src/flet/components/hooks/hook.py new file mode 100644 index 0000000000..48793c237f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/hook.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass +from typing import TYPE_CHECKING + +from flet.components.component_owned import ComponentOwned + +if TYPE_CHECKING: + pass + + +@dataclass() +class Hook(ComponentOwned): + """ + Base class for component hook state objects. + + Each hook instance is bound to an owning component via + `ComponentOwned` and reused by position across + renders, allowing hook-specific subclasses to persist state between renders. + """ + + pass diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_callback.py b/sdk/python/packages/flet/src/flet/components/hooks/use_callback.py new file mode 100644 index 0000000000..fe53bf3143 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_callback.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from collections.abc import Sequence +from typing import Any, Callable, ParamSpec, TypeVar + +from flet.components.hooks.use_memo import use_memo + +P = ParamSpec("P") +R = TypeVar("R") + + +def use_callback( + fn: Callable[P, R], + dependencies: Sequence[Any] | None = None, +) -> Callable[P, R]: + """ + Memoize a function identity between renders. + + Args: + fn: A function to memoize. + dependencies: If present, fn is only re-memoized when one of the dependencies + has changed. If absent, fn is only memoized on initial render. + + Returns: + A memoized version of the function whose identity is stable between renders. + """ + # Just memoize the function object itself + return use_memo(lambda: fn, dependencies) diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_context.py b/sdk/python/packages/flet/src/flet/components/hooks/use_context.py new file mode 100644 index 0000000000..db1830e342 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_context.py @@ -0,0 +1,113 @@ +from collections.abc import Callable +from dataclasses import dataclass +from typing import TypeVar, cast + +try: + from typing import Protocol +except ImportError: + from typing_extensions import Protocol + +from flet.components.hooks.hook import Hook +from flet.components.observable import Observable +from flet.components.utils import current_component, current_renderer + + +@dataclass +class ContextHook(Hook): + """ + Marker hook for `use_context` subscription ordering. + + The hook stores no additional data; it reserves a stable hook slot so + context access follows normal hook ordering rules within a component. + """ + + pass + + +ContextValueT = TypeVar("ContextValueT") + +T = TypeVar("T") # context value type +ProviderResultT = TypeVar( + "ProviderResultT", covariant=True +) # return type of the callback/provider + + +class ContextProvider(Protocol[T]): + """ + Protocol describing objects returned by :func:`~flet.create_context`. + + A context provider is both: + - a callable wrapper that executes a callback under a provided context value; + - a holder of context metadata used by :func:`~flet.use_context` lookup. + """ + + default_value: T + _key: object + + # Generic call: whatever the callback returns (ProviderResultT), + # the provider returns too. + def __call__( + self, value: T, callback: Callable[[], ProviderResultT] + ) -> ProviderResultT: ... + + +def create_context(default_value: T) -> ContextProvider[T]: + """ + Create a context provider. + + Args: + default_value: Default context value when no provider is found. + + Returns: + A context provider that can be used with `use_context` and to wrap + parts of the component tree that should share the same context value. + """ + key = object() + + def provider(value: T, callback: Callable[[], ProviderResultT]) -> ProviderResultT: # type: ignore[type-var] + """ + Runs `callback` with `value` bound for this context key. + + The value is pushed onto the current renderer's context stack before + invocation and always popped in a `finally` block, ensuring proper + nesting and cleanup even when `callback` raises. + """ + r = current_renderer() + r.push_context(key, value) + try: + return callback() # type: ignore[return-value] + finally: + r.pop_context(key) + + p = cast(ContextProvider[T], provider) + p.default_value = default_value + p._key = key + return p + + +def use_context(context: ContextProvider[T]) -> T: + """ + Access the current context value. + + Args: + context: A context provider created by `create_context`. + + Returns: + The current context value, or the default value if no provider is found. + """ + component = current_component() + component.use_hook(lambda: ContextHook(component)) + + value = cast(T, context.default_value) + # look up the component tree for the nearest context provider + comp = component + while comp: + if context._key in comp._contexts: + value = cast(T, comp._contexts[context._key]) + break + comp = comp._parent_component() if comp._parent_component else None + + if isinstance(value, Observable): + component._attach_observable_subscription(value) + + return value diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_dialog.py b/sdk/python/packages/flet/src/flet/components/hooks/use_dialog.py new file mode 100644 index 0000000000..635ca053dd --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_dialog.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +import dataclasses +import weakref + +from flet.components.hooks.use_effect import use_effect +from flet.components.hooks.use_ref import use_ref +from flet.controls.context import context +from flet.controls.dialog_control import DialogControl + + +def _find_dialog_index(dialogs, target): + # Identity (`is`) comparison — dialog controls are dataclasses and two + # dialogs built from the same field values compare equal with `==`, + # so `in` / `.index()` would match the wrong entry when two sibling + # hosts each manage a similarly-shaped dialog. + for i, c in enumerate(dialogs.controls): + if c is target: + return i + return -1 + + +def _bind_dialog_subtree(value, parent): + if dataclasses.is_dataclass(value): + if parent is not None and parent is not value: + value._parent = weakref.ref(parent) + for field in dataclasses.fields(value): + if not field.metadata.get("skip", False): + _bind_dialog_subtree(getattr(value, field.name), value) + elif isinstance(value, list): + for item in value: + _bind_dialog_subtree(item, parent) + elif isinstance(value, dict): + for item in value.values(): + _bind_dialog_subtree(item, parent) + + +def use_dialog(dialog: DialogControl | None = None): + """ + Portal a :class:`~flet.DialogControl` to the page's dialog overlay. + + Call this hook inside a :func:`~flet.component` function on every render. + Pass a :class:`~flet.DialogControl` instance to show the dialog, + or `None` to hide/remove it. + + The hook automatically sets `open=True` on the dialog when it is + added to the overlay and removes it when `None` is passed or the + component unmounts. + + Args: + dialog: A :class:`~flet.DialogControl` to display, or `None` + to hide it. + """ + ref = use_ref(None) + page = context.page + + prev = ref.current + + if prev is not None and _find_dialog_index(page._dialogs, prev) < 0: + ref.current = None + prev = None + + if dialog is not None: + prev_idx = _find_dialog_index(page._dialogs, prev) if prev is not None else -1 + if ( + prev is not None + and prev_idx >= 0 + and prev.open + and type(prev) is type(dialog) + ): + # Frozen diff: compares prev and dialog field-by-field, migrates + # `_i` onto the new instance via `_migrate_state`, and emits only + # actual field deltas. This is what preserves Flutter widget + # identity for nested controls — notably the TextField inside an + # AlertDialog keeps its cursor/focus across re-renders. + dialog.open = True + page._prepare_dialog(dialog) + page.session.patch_control(control=dialog, prev_control=prev, frozen=True) + # Strip the `_frozen` marker set by _dataclass_added during the + # frozen diff so we can later set open=False for dismissal. + if hasattr(dialog, "_frozen"): + del dialog._frozen + # Replace the old instance with the new one in the overlay list + # — at the SAME index, so sibling hosts' entries aren't disturbed. + _bind_dialog_subtree(dialog, page._dialogs) + page._dialogs.controls[prev_idx] = dialog + # Keep `_dialogs.__prev_lists['controls']` aligned with the new + # instance. Without this, a later `_dialogs.update()` triggered + # by an unrelated operation (e.g. `page.show_dialog(SnackBar)`) + # would diff the fresh `controls` list against a snapshot + # pointing at the old Python object — different `id()`, so the + # diff emits a full REPLACE of the dialog. On Dart, REPLACE + # creates a new Control with `_open` unset, and the next build + # re-enters the show branch and pushes a second DialogRoute on + # top of the existing one. The dialog then refuses to close. + prev_lists = getattr(page._dialogs, "__prev_lists", None) + if prev_lists is not None and "controls" in prev_lists: + prev_lists["controls"][prev_idx] = dialog + ref.current = dialog + else: + dialog.open = True + page._prepare_dialog(dialog) + _bind_dialog_subtree(dialog, page._dialogs) + # Either `prev` is gone (already dismissed on the client) or + # is still in the list with `open=False` (mid-dismiss, + # awaiting the client's on_dismiss round-trip). In the + # latter case we must NOT reuse `prev`'s `_i` — Flutter's + # `AlertDialogControl` still carries `_open=True` locally + # from when the previous dialog was shown, so reusing `_i` + # means the new `open=True` patch hits `open == lastOpen` + # and the new dialog never calls `showDialog`. Append a + # fresh entry (new `_i`) and let the dismissing one finish + # on its own. + page._dialogs.controls.append(dialog) + ref.current = dialog + page.session.schedule_update(page._dialogs) + elif prev is not None and prev.open: + # Dismiss: flip open=False and patch the dialog directly. The + # frozen-patch path above swaps the dialog instance in + # `_dialogs.controls`, which desyncs `_dialogs.__prev_lists` + # — so a `schedule_update(_dialogs)` here would miss the + # `open=False` delta entirely. Patching `prev` directly is both + # cheaper (one op vs a full list diff) and unaffected by the + # list-snapshot state. + prev.open = False + page.session.patch_control(prev) + + def _cleanup(): + d = ref.current + if d is not None: + ref.current = None + if d.open: + d.open = False + page.session.patch_control(d) + + use_effect(lambda: None, dependencies=[], cleanup=_cleanup) diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_effect.py b/sdk/python/packages/flet/src/flet/components/hooks/use_effect.py new file mode 100644 index 0000000000..87a24f27a2 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_effect.py @@ -0,0 +1,120 @@ +import asyncio +from collections.abc import Awaitable, Callable, Sequence +from dataclasses import dataclass +from typing import Any + +from flet.components.hooks.hook import Hook +from flet.components.utils import current_component + + +@dataclass +class EffectHook(Hook): + """ + Hook state container backing :func:`~flet.use_effect`. + + Stores effect callbacks, dependency snapshots, and runtime task handles used + to schedule async setup/cleanup work across mount, update, and unmount + phases. + """ + + setup: Callable[[], Any | Awaitable[Any]] + cleanup: Callable[[], Any | Awaitable[Any]] | None = None + deps: list[Any] | None = None + prev_deps: list[Any] | None = None + + # runtime + _setup_task: asyncio.Task | None = None # last scheduled setup task + _cleanup_task: asyncio.Task | None = None # last scheduled cleanup task + + def cancel(self): + """ + Cancels currently scheduled setup and cleanup tasks, if still pending. + + Safe to call repeatedly; completed tasks are ignored. + """ + if self._setup_task and not self._setup_task.done(): + self._setup_task.cancel() + if self._cleanup_task and not self._cleanup_task.done(): + self._cleanup_task.cancel() + + +def use_effect( + setup: Callable[[], Any | Awaitable[Any]], + dependencies: Sequence[Any] | None = None, + cleanup: Callable[[], Any | Awaitable[Any]] | None = None, +): + """ + Perform side effects in function components. + + Args: + setup: A function that performs the side effect. It may optionally return + a cleanup function. + dependencies: If present, the effect is only re-run when one of the dependencies + has changed. If absent, the effect is only run on initial render. + cleanup: An optional function that cleans up after the effect. It is run + before the effect is re-run, and when the component unmounts. + """ + component = current_component() + deps = list(dependencies) if dependencies is not None else None + + # get or create effect hook + hook = component.use_hook( + lambda: EffectHook( + component, + setup=setup, + deps=deps, + cleanup=cleanup, + ) + ) + + # update effect hook + hook.setup = setup + hook.prev_deps = hook.deps + hook.deps = deps + hook.cleanup = cleanup + + +def on_mounted(fn: Callable[[], Any | Awaitable[Any]]) -> None: + """ + Run exactly once after the component mounts. + + Args: + fn (Callable[[], Any | Awaitable[Any]]): A function to run after the component + mounts. + """ + use_effect(fn, dependencies=[]) + + +def on_unmounted(fn: Callable[[], Any | Awaitable[Any]]) -> None: + """ + Run exactly once when the component unmounts. + + Args: + fn (Callable[[], Any | Awaitable[Any]]): A function to run when the component + unmounts. + """ + # No-op setup; only need cleanup to fire on unmount + use_effect(lambda: None, dependencies=[], cleanup=fn) + + +def on_updated( + fn: Callable[[], Any | Awaitable[Any]], dependencies: Sequence[Any] | None = None +) -> None: + """ + Run after each post-mount render (or when dependencies change). + With dependencies=None this fires every update; with dependencies=[...] only + on changes. + + Args: + fn (Callable[[], Any | Awaitable[Any]]): A function to run after each + post-mount render (or when dependencies change). + dependencies (Sequence[Any] | None): If present, `fn` is only run when one + of the dependencies has changed. If absent, `fn` is run after every + render. + """ + use_effect(fn, dependencies=dependencies) + + +on_mounted = on_mounted # alias +on_unmounted = on_unmounted # alias +on_updated = on_updated # alias diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_memo.py b/sdk/python/packages/flet/src/flet/components/hooks/use_memo.py new file mode 100644 index 0000000000..1492f722ba --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_memo.py @@ -0,0 +1,65 @@ +from collections.abc import Sequence +from dataclasses import dataclass +from typing import Any, Callable, Generic, TypeVar + +from flet.components.hooks.hook import Hook +from flet.components.utils import current_component, shallow_compare_args + +MemoValueT = TypeVar("MemoValueT") + + +@dataclass +class MemoHook(Hook, Generic[MemoValueT]): + """ + Hook state container used by :func:`~flet.use_memo`. + + It stores the last computed memo value together with the dependency snapshot + used to decide whether recomputation is required on subsequent renders. + """ + + value: MemoValueT | None = None + prev_deps: list[Any] | None = None + + +def use_memo( + calculate_value: Callable[[], MemoValueT], dependencies: Sequence[Any] | None = None +) -> MemoValueT: + """ + Memoize a computed value between renders. + + Args: + calculate_value: A function that computes the value to be memoized. + dependencies: If present, the value is only recomputed when one of + the dependencies has changed. If absent, the value is only computed + on the initial render. + + Returns: + A memoized value whose identity is stable between renders. + """ + component = current_component() + + def _create() -> MemoHook[MemoValueT]: + """ + Creates and initializes the memo hook for the first render. + + When `dependencies` is `None`, the memo value is seeded immediately so a + valid value exists even before the post-creation recompute path runs. + """ + h = MemoHook[MemoValueT](component) + # If deps is None we recompute every render, so no need to preset prev_deps. + if dependencies is None: + h.value = calculate_value() + return h + + hook = component.use_hook(_create) # type: MemoHook[MemoValueT] + + if dependencies is None: + # Always recompute + hook.value = calculate_value() + return hook.value # type: ignore[return-value] + + if hook.prev_deps is None or not shallow_compare_args(hook.prev_deps, dependencies): + hook.value = calculate_value() + hook.prev_deps = list(dependencies) + + return hook.value # type: ignore[return-value] diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py b/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py new file mode 100644 index 0000000000..6513b92d68 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_ref.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +from typing import Generic, TypeVar + +from flet.components.hooks.hook import Hook +from flet.components.utils import current_component + +__all__ = ["MutableRef", "use_ref"] + +RefValueT = TypeVar("RefValueT") + + +class MutableRef(Generic[RefValueT]): + """A mutable holder whose identity stays stable across renders.""" + + __slots__ = ("current",) + + def __init__(self, initial_value: RefValueT | None = None): + self.current = initial_value + + +@dataclass +class RefHook(Hook, Generic[RefValueT]): + """ + Hook state container backing :func:`~flet.use_ref`. + + Stores the stable `MutableRef` instance for a component so + it can be reused across renders without triggering updates when `.current` + changes. + """ + + ref: MutableRef[RefValueT] + + +def use_ref( + initial_value: RefValueT | Callable[[], RefValueT] | None = None, +) -> MutableRef[RefValueT]: + """ + Preserve a mutable value for the lifetime of the component without causing \ + re-renders. + + Args: + initial_value: Optional value or callable returning the value assigned + to `ref.current`. + + Returns: + A `MutableRef` whose `.current` property can be read and written freely. + """ + component = current_component() + + def resolve_initial() -> RefValueT | None: + """ + Resolves the initial ref value from literal or lazy initializer. + + If `initial_value` is callable, it is invoked and its return value is + used. Otherwise, `initial_value` is returned as-is. + """ + return initial_value() if callable(initial_value) else initial_value + + hook = component.use_hook( + lambda: RefHook( + component, + MutableRef(resolve_initial()), + ) + ) + + return hook.ref diff --git a/sdk/python/packages/flet/src/flet/components/hooks/use_state.py b/sdk/python/packages/flet/src/flet/components/hooks/use_state.py new file mode 100644 index 0000000000..c78de6d9c8 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/hooks/use_state.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass +from typing import Any, TypeVar + +from flet.components.hooks.hook import Hook +from flet.components.observable import Observable, ObservableSubscription +from flet.components.utils import current_component + +StateT = TypeVar("StateT") +Updater = Callable[[StateT], StateT] + + +@dataclass +class StateHook(Hook): + """ + Hook state container backing :func:`~flet.use_state`. + """ + + value: Any + """ + Current state value returned by :func:`~flet.use_state`. + + Updated by the `set_state` setter. It may hold any Python value, + including an :class:`~flet.Observable`. + """ + + subscription: ObservableSubscription | None = None + """ + Active subscription bound to `value` when `value` is observable. + + Set by `update_subscription()` to track observable changes and schedule + component updates. `None` when `value` is not an + :class:`~flet.Observable` or after detachment. + """ + + version: int = 0 + """ + Monotonic revision counter for state replacements. + + Incremented each time `set_state` accepts a changed value. Used to mark + hook-level updates even when consumers do not inspect `value` directly. + """ + + +def use_state( + initial: StateT | Callable[[], StateT], +) -> tuple[StateT, Callable[[StateT | Updater], None]]: + """ + Adds state to a function component, similar to React's useState(). + + The returned setter accepts either: + - a new value, or + - a function receiving the previous state and returning the next one. + + Args: + initial: Initial state value or a function returning it. + + Returns: + (value, set_value) tuple. + """ + component = current_component() + hook = component.use_hook( + lambda: StateHook( + component, + initial() if callable(initial) else initial, + ) + ) + + def update_subscription(h: StateHook): + """ + Refreshes observable subscription for the current state value. + + Detaches any previous subscription and, if `h.value` is an + :class:`~flet.Observable`, attaches a new `ObservableSubscription` + owned by the current component. + + Args: + h: The state hook whose subscription must be synchronized with + its current `value`. + """ + # Detach previous subscription if any + if h.subscription: + component._detach_observable_subscription(h.subscription) + h.subscription = None + + # Attach new subscription if value is Observable + if isinstance(h.value, Observable): + h.subscription = component._attach_observable_subscription(h.value) + + update_subscription(hook) + + def set_state(new_value_or_fn: StateT | Updater): + """ + Update the state value. + + Can be called with either: + - a direct new value, or + - a function that takes the current value and returns the next one. + """ + # Compute next value + new_value = ( + new_value_or_fn(hook.value) + if callable(new_value_or_fn) + else new_value_or_fn + ) + + # Only trigger update if value changed (shallow equality) + if new_value != hook.value: + hook.value = new_value + update_subscription(hook) + hook.version += 1 + if hook.component: + hook.component._schedule_update() + + return hook.value, set_state diff --git a/sdk/python/packages/flet/src/flet/components/memo.py b/sdk/python/packages/flet/src/flet/components/memo.py new file mode 100644 index 0000000000..020f62ece5 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/memo.py @@ -0,0 +1,34 @@ +from flet.components.utils import current_renderer + + +def memo(fn): + """ + Lets you skip re-rendering a component when its props are unchanged. + + Example: + ```python + import flet as ft + + + @ft.component + def MyComponent(x, y): + return ft.Text(f"x={x}, y={y}") + + + MemoizedMyComponent = ft.memo(MyComponent) + + flet.run( + lambda page: page.render( + lambda: MemoizedMyComponent(x=1, y=2), + ), + ) + ``` + """ + + def memo_wrapper(*args, **kwargs): + """Render `fn` with memoization enabled for this invocation.""" + r = current_renderer() + r.set_memo() + return fn(*args, **kwargs) + + return memo_wrapper diff --git a/sdk/python/packages/flet/src/flet/components/observable.py b/sdk/python/packages/flet/src/flet/components/observable.py new file mode 100644 index 0000000000..31d4e4f79f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/observable.py @@ -0,0 +1,441 @@ +from __future__ import annotations + +import contextlib +import weakref +from dataclasses import InitVar, dataclass +from typing import TYPE_CHECKING, Any, Callable, Optional + +from flet.components.utils import value_equal + +if TYPE_CHECKING: + from flet.components.component import Component + +from flet.components.component_owned import ComponentOwned + +Listener = Callable[[Any, Optional[str]], None] # (sender, field|None) + + +def observable(cls): + """ + Makes a class observable by mixing in :class:`~flet.Observable`. + Can be applied to any class including `dataclasses.dataclass`. + For dataclasses, decorator can be placed either above or below + the `@dataclass` decorator. + + Example: + ```python + from dataclasses import dataclass + import flet as ft + + + @ft.observable + @dataclass + class MyDataClass: + x: int + y: int + ``` + """ + if Observable in cls.__mro__: + return cls + # Build a new class whose MRO is (Observable, cls) + ns = dict(cls.__dict__) + # Defensive: avoid carrying these special slots over + ns.pop("__dict__", None) + ns.pop("__weakref__", None) + + Mixed = type(cls.__name__, (Observable, cls), ns) + Mixed.__module__ = cls.__module__ + Mixed.__qualname__ = cls.__qualname__ + return Mixed + + +@dataclass +class ObservableSubscription(ComponentOwned): + """ + Lifecycle helper that binds an observable object to a component update cycle. + + The subscription listens for observable changes and schedules re-render of + the owning component while the component is alive. + """ + + observable: InitVar[Observable] + + def __post_init__(self, owner: Component, observable: Observable) -> None: + super().__post_init__(owner) + self.__disposer = observable.subscribe(self.__on_change) + + def dispose(self): + """ + Cancel the underlying observable subscription if it is still active. + """ + + if callable(self.__disposer): + self.__disposer() + self.__disposer = None + + def __on_change(self, _sender, _field): + """ + Schedule owner component update when observable state changes. + + Args: + _sender: Observable object that emitted change. + _field: Name of changed field, or `None` for generic change. + """ + + if self.component: + self.component._schedule_update() + + +class Observable: + """ + Mixin: notifies when fields change; auto-wraps lists/dicts to be observable. + + Example: + ```python + import flet as ft + from dataclasses import dataclass + + + @ft.observable + @dataclass + class MyDataClass: + x: int + y: int + + + obj = MyDataClass(1, 2) + + + def listener(sender, field): + print(f"Changed: {field} in {sender}") + + + obj.subscribe(listener) + obj.x = 3 + obj.y = 4 + ``` + """ + + __version__ = 0 # optional version counter + + # listeners store (lazy) + @property + def __listeners(self): + """ + Lazily initialized weak set of registered listener callbacks. + """ + + storage_name = "_Observable__listeners_storage" + try: + return object.__getattribute__(self, storage_name) + except AttributeError: + ws = weakref.WeakSet() + object.__setattr__(self, storage_name, ws) + return ws + + # subscribe / notify + def subscribe(self, fn: Listener) -> Callable[[], None]: + """ + Register a change listener. + + Args: + fn: Listener callback receiving `(sender, field)`. + + Returns: + A disposer function that unsubscribes the listener. + """ + + self.__listeners.add(fn) + + def dispose(): + """ + Remove the subscribed listener from this observable. + """ + with contextlib.suppress(KeyError): + self.__listeners.remove(fn) + + return dispose + + def _notify(self, field: str | None): + """ + Notify all listeners about a field change. + + Args: + field: Changed field name, or `None` for a generic change. + """ + + self.__version__ += 1 + for fn in list(self.__listeners): + fn(self, field) + + def notify(self): + """ + Manually notify listeners that something changed. + """ + self._notify(None) + + # collection wrapping + def _wrap_if_collection(self, name: str, value: Any) -> Any: + """ + Wrap plain list/dict values into observable collection wrappers. + + Args: + name: Field name being assigned. + value: Field value to evaluate. + + Returns: + Observable collection wrapper for `list`/`dict` values, otherwise + the original value. + """ + + if isinstance(value, list) and not isinstance(value, ObservableList): + return ObservableList(self, name, value) + if isinstance(value, dict) and not isinstance(value, ObservableDict): + return ObservableDict(self, name, value) + return value + + # attribute interception + def __setattr__(self, name: str, value: Any): + if name.startswith("_"): # private/internal, don't notify + object.__setattr__(self, name, value) + return + value = self._wrap_if_collection(name, value) + old = object.__getattribute__(self, name) if hasattr(self, name) else None + object.__setattr__(self, name, value) + if not value_equal(old, value): + self._notify(name) + + def __delattr__(self, name: str): + existed = hasattr(self, name) + object.__delattr__(self, name) + if existed: + self._notify(name) + + def __repr__(self): + return f"{super().__repr__()} (version={self.__version__})" + + +# Observable collections ----------------------------------------- + + +class ObservableList(list): + """ + List wrapper that reports mutating operations to its owning observable. + """ + + __slots__ = ("_owner_ref", "_field") + + def __init__(self, owner: Observable, field: str, iterable=()): + super().__init__(iterable) + self._owner_ref = weakref.ref(owner) + self._field = field + + def _touch(self): + """ + Emit a change notification for the parent field. + """ + + owner = self._owner_ref() + if owner: + owner._notify(self._field) + + def _wrap(self, v): + """ + Wrap nested collections into observable variants before storing. + + Args: + v: Value being inserted into the list. + + Returns: + Wrapped value when applicable. + """ + + owner = self._owner_ref() + return owner._wrap_if_collection(self._field, v) if owner else v + + def append(self, x): + """ + Append an item and notify observers. + """ + + super().append(self._wrap(x)) + self._touch() + + def extend(self, it): + """ + Extend list with iterable items and notify observers. + """ + + super().extend(self._wrap(v) for v in it) + self._touch() + + def insert(self, i, x): + """ + Insert an item at a specific index and notify observers. + """ + + super().insert(i, self._wrap(x)) + self._touch() + + def remove(self, x): + """ + Remove first matching item and notify observers. + """ + + super().remove(x) + self._touch() + + def clear(self): + """ + Remove all items and notify observers. + """ + + super().clear() + self._touch() + + def sort(self, *a, **k): + """ + Sort items in place and notify observers. + """ + + super().sort(*a, **k) + self._touch() + + def reverse(self): + """ + Reverse item order in place and notify observers. + """ + + super().reverse() + self._touch() + + def pop(self, i=-1): + """ + Remove and return an item by index, then notify observers. + + Args: + i: Index to pop. Defaults to the last item. + + Returns: + Removed item. + """ + + v = super().pop(i) + self._touch() + return v + + def __setitem__(self, i, v): + super().__setitem__(i, self._wrap(v)) + self._touch() + + def __delitem__(self, i): + super().__delitem__(i) + self._touch() + + +class ObservableDict(dict): + """ + Dict wrapper that reports mutating operations to its owning observable. + """ + + __slots__ = ("_owner_ref", "_field") + + def __init__(self, owner: Observable, field: str, mapping=()): + super().__init__(mapping) + self._owner_ref = weakref.ref(owner) + self._field = field + + def _touch(self): + """ + Emit a change notification for the parent field. + """ + + owner = self._owner_ref() + if owner: + owner._notify(self._field) + + def _wrap(self, v): + """ + Wrap nested collections into observable variants before storing. + + Args: + v: Value being inserted into the dict. + + Returns: + Wrapped value when applicable. + """ + + owner = self._owner_ref() + return owner._wrap_if_collection(self._field, v) if owner else v + + def __setitem__(self, k, v): + super().__setitem__(k, self._wrap(v)) + self._touch() + + def __delitem__(self, k): + super().__delitem__(k) + self._touch() + + def clear(self): + """ + Remove all entries and notify observers. + """ + + super().clear() + self._touch() + + def update(self, *a, **k): + """ + Update mapping with values and notify observers. + + Positional mapping/iterable arguments are forwarded to `dict.update()`; + keyword values are wrapped when needed. + """ + + super().update(*a, **{kk: self._wrap(vv) for kk, vv in k.items()}) + self._touch() + + def pop(self, k, *d): + """ + Remove key and return its value, then notify observers. + + Args: + k: Key to remove. + *d: Optional default value. + + Returns: + Removed value or default. + """ + + v = super().pop(k, *d) + self._touch() + return v + + def popitem(self): + """ + Remove and return the last inserted key-value pair, then notify observers. + + Returns: + Removed `(key, value)` pair. + """ + + kv = super().popitem() + self._touch() + return kv + + def setdefault(self, k, d=None): + """ + Return value for key, inserting default when key is absent. + + Args: + k: Key to look up. + d: Default value to insert when key does not exist. + + Returns: + Existing or newly inserted value. + """ + + if k not in self: + super().__setitem__(k, self._wrap(d)) + self._touch() + return dict.__getitem__(self, k) diff --git a/sdk/python/packages/flet/src/flet/components/public_utils.py b/sdk/python/packages/flet/src/flet/components/public_utils.py new file mode 100644 index 0000000000..842e9e7982 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/public_utils.py @@ -0,0 +1,23 @@ +from typing import Any + +from flet.components.component import Component + + +def unwrap_component(c: Any): + """ + Resolves a component wrapper chain to its rendered payload. + + If `c` is a `Component`, this function repeatedly follows + its rendered body (`_b`) until the value is no longer a `Component`. + + Args: + c: A value that may be a component wrapper or an already unwrapped value. + + Returns: + The first non-`Component` value in the chain (for example a control, + list of controls/views, or `None`). + """ + p = c + while isinstance(p, Component): + p = p._b + return p diff --git a/sdk/python/packages/flet/src/flet/components/router.py b/sdk/python/packages/flet/src/flet/components/router.py new file mode 100644 index 0000000000..ff0a6be49a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/router.py @@ -0,0 +1,699 @@ +""" +Router — React Router-like declarative routing for Flet components. + +Provides nested route matching, layout routes with outlets, dynamic segments, +optional segments, splats, data loaders, navigation hooks, and view-stack +navigation with swipe-back gesture support. +""" + +from __future__ import annotations + +import re +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Callable +from urllib.parse import urlparse + +import repath + +from flet.components.component_decorator import component + +if TYPE_CHECKING: + from flet.controls.control import Control +from flet.components.hooks.use_context import create_context, use_context +from flet.components.hooks.use_effect import use_effect +from flet.components.hooks.use_ref import use_ref +from flet.components.hooks.use_state import use_state +from flet.controls.context import context + +__all__ = [ + "LocationInfo", + "Route", + "Router", + "is_route_active", + "use_route_loader_data", + "use_route_location", + "use_route_outlet", + "use_route_params", + "use_view_path", +] + +# --------------------------------------------------------------------------- +# Data types +# --------------------------------------------------------------------------- + + +@dataclass +class Route: + """ + Defines a single route in the route tree. + + Routes can be nested via ``children`` to create layout hierarchies. + A route with ``component`` and ``children`` acts as a layout route — its + component should call :func:`~flet.use_route_outlet` to render the + matched child. + + Args: + path: Relative path segment. Supports dynamic segments (``:name``), + optional segments (``:name?``), splats (``:name*``), and custom + regex constraints (``:name(\\\\d+)``). ``None`` for pathless + layout routes. + index: When ``True``, this route matches when the parent path + matches exactly (no further segments). Index routes must not + have ``path`` or ``children``. + component: A ``@component`` function to render when this route + matches. + children: Nested child routes. + loader: Optional data loader function. Called with the matched + params dict when the route matches. Result is available via + :func:`~flet.use_route_loader_data`. + outlet: When ``True`` and ``manage_views=True``, this route acts + as a layout that wraps its matched child via + :func:`~flet.use_route_outlet` within a single + :class:`~flet.View`, instead of each child becoming a separate + :class:`~flet.View`. + """ + + path: str | None = None + index: bool = False + component: Callable | None = None + children: list[Route] | None = field(default=None) + loader: Callable[..., Any] | None = None + outlet: bool = False + + +@dataclass +class LocationInfo: + """ + Describes the current location parsed from the page route. + + Args: + pathname: URL path portion (e.g. ``/products/42``). + search: Query string portion without leading ``?``. + hash: Fragment portion without leading ``#``. + """ + + pathname: str + search: str = "" + hash: str = "" + + +# --------------------------------------------------------------------------- +# Internal: route matching +# --------------------------------------------------------------------------- + + +@dataclass +class _RouteMatch: + """One matched level in the route chain.""" + + route: Route + params: dict[str, str] + full_path: str + resolved_path: str = "" + + +def _join_paths(parent: str, child: str) -> str: + """Join parent and child path segments, normalizing slashes.""" + if not child: + return parent + parent = parent.rstrip("/") + if not child.startswith("/"): + child = "/" + child + return parent + child + + +def _normalize_path(path: str) -> str: + """Ensure path starts with / and has no trailing /.""" + if not path: + return "/" + if not path.startswith("/"): + path = "/" + path + if path != "/" and path.endswith("/"): + path = path.rstrip("/") + return path + + +def _match_routes( + routes: list[Route], + pathname: str, + parent_path: str = "", +) -> list[_RouteMatch] | None: + """ + Match pathname against route tree. + + Returns a chain of matched routes from outermost to innermost, + or ``None`` if no route matches. + """ + for route in routes: + result = _try_match(route, pathname, parent_path) + if result is not None: + return result + return None + + +def _try_match( + route: Route, + pathname: str, + parent_path: str, +) -> list[_RouteMatch] | None: + """Try to match a single route (and its children) against pathname.""" + + if route.index: + # Index routes match the parent path exactly + full_path = _normalize_path(parent_path) if parent_path else "/" + pattern = repath.pattern(full_path) + m = re.match(pattern, pathname) + if m: + return [ + _RouteMatch( + route=route, + params=m.groupdict(), + full_path=full_path, + resolved_path=m.group(0), + ) + ] + # Also try with trailing slash stripped from pathname + if pathname.endswith("/") and pathname != "/": + m = re.match(pattern, pathname.rstrip("/")) + if m: + return [ + _RouteMatch( + route=route, + params=m.groupdict(), + full_path=full_path, + resolved_path=m.group(0), + ) + ] + return None + + # Build full path for this route + route_path = route.path or "" + full_path = _join_paths(parent_path, route_path) + if not full_path: + full_path = "/" + + if route.children: + # Parent route — try prefix match to extract params, then match children + parent_params: dict[str, str] = {} + parent_resolved = full_path + if route_path: + # Only do prefix match if route has a path segment + prefix_pattern = repath.pattern(full_path, end=False) + prefix_m = re.match(prefix_pattern, pathname) + if not prefix_m: + return None + parent_params = prefix_m.groupdict() + parent_resolved = prefix_m.group(0) + + # Try matching children + for child in route.children: + child_result = _try_match(child, pathname, full_path) + if child_result is not None: + return [ + _RouteMatch( + route=route, + params=parent_params, + full_path=full_path, + resolved_path=parent_resolved, + ) + ] + child_result + + # No children matched — if this route has a component, try exact match + if route.component: + exact_pattern = repath.pattern(full_path) + exact_m = re.match(exact_pattern, pathname) + if exact_m: + return [ + _RouteMatch( + route=route, + params=exact_m.groupdict(), + full_path=full_path, + resolved_path=exact_m.group(0), + ) + ] + + return None + + # Leaf route — exact match + leaf_pattern = repath.pattern(full_path) + m = re.match(leaf_pattern, pathname) + if m: + return [ + _RouteMatch( + route=route, + params=m.groupdict(), + full_path=full_path, + resolved_path=m.group(0), + ) + ] + + return None + + +# --------------------------------------------------------------------------- +# Contexts +# --------------------------------------------------------------------------- + +_MISSING = object() # sentinel to detect calls outside Router + +_location_context = create_context(_MISSING) +_params_context = create_context(_MISSING) +_outlet_context = create_context(_MISSING) +_loader_data_context = create_context(_MISSING) +_view_path_context = create_context(_MISSING) + + +def _is_inside_router(value: Any) -> bool: + """Check if a router hook is called inside a Router component tree.""" + return value is not _MISSING + + +# --------------------------------------------------------------------------- +# Hooks +# --------------------------------------------------------------------------- + + +def use_route_params() -> dict[str, str]: + """ + Returns all dynamic segment parameters from the current matched route chain. + + Must be called inside a component rendered by a :class:`~flet.Router`. + Returns an empty dict if called outside a Router tree (e.g. during a + stale observable re-render). + + Returns: + Dictionary mapping parameter names to their matched string values. + """ + value = use_context(_params_context) + if not _is_inside_router(value): + return {} + return value + + +def use_route_location() -> str: + """ + Returns the current location pathname. + + Must be called inside a component rendered by a :class:`~flet.Router`. + Returns an empty string if called outside a Router tree. + + Returns: + The current URL pathname (e.g. ``"/products/42"``). + """ + loc = use_context(_location_context) + if not _is_inside_router(loc): + return "" + return loc.pathname + + +def use_view_path() -> str: + """ + Returns the resolved URL for the current view level. + + This differs from :func:`use_route_location` which returns the full + current URL. ``use_view_path`` returns the URL up to the current + view level (the leaf route of the view in ``manage_views=True`` mode). + + Useful as the ``route`` value for :class:`~flet.View` to produce a + unique Navigator key per view in the stack. + + Must be called inside a component rendered by a :class:`~flet.Router`. + Returns an empty string if called outside a Router tree. + + Returns: + The resolved URL for this view level (e.g. ``"/products/42"``). + """ + value = use_context(_view_path_context) + if not _is_inside_router(value): + return "" + return str(value) + + +def use_route_outlet() -> Control: + """ + Returns the matched child route's rendered component. + + Used inside layout route components to render the active child route. + Must be called inside a component rendered by a :class:`~flet.Router`. + Returns ``None`` if called outside a Router tree. + + Returns: + The rendered child component, or ``None`` if no child matches. + """ + value = use_context(_outlet_context) + if not _is_inside_router(value): + return None + return value + + +def use_route_loader_data(): + """ + Returns the data from the current route's loader function. + + Must be called inside a component whose route has a ``loader`` defined. + + Returns: + The return value of the route's loader function, or ``None``. + """ + value = use_context(_loader_data_context) + if not _is_inside_router(value): + return None + return value + + +def is_route_active(path: str, exact: bool = False) -> bool: + """ + Check whether the given path matches the current location. + + Useful for highlighting active navigation links or tabs. + + Args: + path: Path to check against the current location. + exact: If ``True``, requires an exact match. If ``False`` (default), + a prefix match is used (e.g. ``"/products"`` matches + ``"/products/42"``). + + Returns: + ``True`` if the path matches the current location. + """ + loc = use_context(_location_context) + if not _is_inside_router(loc): + return False + pathname = loc.pathname + path = _normalize_path(path) + + if exact or path == "/": + return pathname == path + + return pathname == path or pathname.startswith(path + "/") + + +# --------------------------------------------------------------------------- +# Outlet chain builder +# --------------------------------------------------------------------------- + + +def _build_outlet_chain( + chain: list[_RouteMatch], + loader_results: dict[int, Any], + index: int = 0, +): + """ + Build nested outlet context providers from the match chain. + + Recursively processes the chain from outermost (index=0) to innermost. + Each level wraps the next level as its outlet context. + """ + # Skip routes without components (path-only grouping) + while index < len(chain) and chain[index].route.component is None: + index += 1 + + if index >= len(chain): + return None + + matched = chain[index] + route = matched.route + loader_data = loader_results.get(index) + + # Recursively build the child outlet + child = _build_outlet_chain(chain, loader_results, index + 1) + + def render_level(): + """Render this route level's component, optionally wrapped with loader data.""" + if loader_data is not None: + return _loader_data_context(loader_data, route.component) + return route.component() + + if child is not None: + # Layout route: provide child as outlet, then render this level + return _outlet_context(child, render_level) + else: + # Leaf route: just render + return render_level() + + +# --------------------------------------------------------------------------- +# View-stack builder (manage_views=True) +# --------------------------------------------------------------------------- + + +def _split_chain_into_view_levels( + chain: list[_RouteMatch], +) -> tuple[list[_RouteMatch], list[tuple[_RouteMatch, str]]]: + """ + Split matched chain into layout wrappers and view entries. + + Only **pathless** routes (no ``path``, not ``index``) with a component + are treated as layouts that wrap every View. All other routes with + a component become their own View in the stack. + + Returns: + A tuple of (layouts, view_entries) where: + - layouts: pathless routes with components that wrap every View + - view_entries: path-bearing routes, each becoming its own View. + Each entry is ``(match, accumulated_path)``. + """ + layouts: list[_RouteMatch] = [] + view_entries: list[tuple[_RouteMatch, str]] = [] + + for i, match in enumerate(chain): + route = match.route + if route.component is None: + continue + + is_last = i == len(chain) - 1 + + if not is_last and route.outlet: + # Explicit outlet layout — wraps child views + layouts.append(match) + else: + view_entries.append((match, match.full_path)) + + return layouts, view_entries + + +def _build_view_level( + layouts: list[_RouteMatch], + leaf_match: _RouteMatch, + loader_results: dict[int, Any], + chain: list[_RouteMatch], +): + """ + Build the component tree for a single View level. + + Wraps the leaf component in layout outlets and optional loader data. + """ + leaf_route = leaf_match.route + leaf_index = chain.index(leaf_match) + leaf_loader_data = loader_results.get(leaf_index) + + def render_leaf(): + if leaf_loader_data is not None: + return _loader_data_context(leaf_loader_data, leaf_route.component) + return leaf_route.component() + + if not layouts: + return render_leaf() + + # Wrap the leaf in layout outlets from innermost to outermost. + # The innermost layout gets the leaf as its outlet; each outer layout + # gets the next inner layout as its outlet. + current_render = render_leaf + for layout_match in reversed(layouts): + layout_route = layout_match.route + layout_index = chain.index(layout_match) + layout_loader_data = loader_results.get(layout_index) + # Capture loop variables + _lr = layout_route + _lld = layout_loader_data + _cr = current_render + + def make_render(_lr=_lr, _lld=_lld, _cr=_cr): + def render_layout(): + if _lld is not None: + return _loader_data_context(_lld, _lr.component) + return _lr.component() + + return lambda: _outlet_context(_cr(), render_layout) + + current_render = make_render() + + return current_render() + + +# --------------------------------------------------------------------------- +# Router component +# --------------------------------------------------------------------------- + + +@component +def Router( + routes: list[Route], + not_found: Callable | None = None, + manage_views: bool = False, +) -> Control: + """ + Top-level router component that matches the current page route against + a tree of :class:`~flet.Route` definitions and renders the matched + component chain. + + The Router subscribes to :attr:`~flet.Page.on_route_change` + and re-renders automatically when the route changes. + + Navigation is done via :meth:`~flet.Page.push_route` or + :meth:`~flet.Page.navigate`. + + When ``manage_views`` is ``True``, the Router returns a list of + :class:`~flet.View` objects (one per path level) instead of a single + component tree. This enables swipe-back gestures, system back button, + and :class:`~flet.AppBar` implicit back button on mobile. + Must be used with :meth:`~flet.Page.render_views`. + + Args: + routes: List of top-level :class:`~flet.Route` definitions. + not_found: Optional component to render when no route matches (404). + manage_views: When ``True``, produce a list of + :class:`~flet.View` objects (one per path level) instead of a + single component tree. Route components should return + :class:`~flet.View` instances with ``route`` and ``appbar`` + set. Use with :meth:`~flet.Page.render_views`. + + Example: + ```python + @ft.component + def App(): + return ft.Router( + [ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ft.Route(path="products/:pid", component=ProductDetails), + ], + manage_views=True, + ) + ``` + """ + page = context.page + location, set_location = use_state(page.route or "/") + prev_route_handler_ref = use_ref(None) + prev_pop_handler_ref = use_ref(None) + + # Subscribe to route changes on mount + def setup_listeners(): + prev_route_handler_ref.current = page.on_route_change + + def on_route_change(e): + set_location(e.route) + + page.on_route_change = on_route_change + + if manage_views: + prev_pop_handler_ref.current = page.on_view_pop + + def on_view_pop(e): + from flet.components.public_utils import unwrap_component + + views_list = unwrap_component(page.views) + if isinstance(views_list, list) and len(views_list) > 1: + prev_view = unwrap_component(views_list[-2]) + if prev_view is not None: + page.navigate(prev_view.route) + + page.on_view_pop = on_view_pop + + def teardown_listeners(): + page.on_route_change = prev_route_handler_ref.current + if manage_views: + page.on_view_pop = prev_pop_handler_ref.current + + use_effect(setup_listeners, dependencies=[], cleanup=teardown_listeners) + + # Parse location + parsed = urlparse(location) + pathname = _normalize_path(parsed.path or "/") + search = parsed.query or "" + hash_val = parsed.fragment or "" + + # Match routes + chain = _match_routes(routes, pathname) + + if chain is None: + if not_found is not None: + if manage_views: + from flet.controls.core.view import View + + return [View(route=pathname, controls=[not_found()])] + return not_found() + return None + + # Merge all params from the chain + all_params: dict[str, str] = {} + for m in chain: + all_params.update(m.params) + + # Run loaders + loader_results: dict[int, Any] = {} + for i, m in enumerate(chain): + if m.route.loader is not None: + loader_results[i] = m.route.loader(all_params) + + # Build location info + loc = LocationInfo(pathname=pathname, search=search, hash=hash_val) + + if not manage_views: + # Single-view mode (existing behavior) + return _location_context( + loc, + lambda: _params_context( + all_params, lambda: _build_outlet_chain(chain, loader_results) + ), + ) + + # Multi-view mode: return a list of route component results. + # Each route component should return a View (with appbar, controls, + # route, etc.). The Router sets route and can_pop on each View + # after the component body executes (via the patch walk). + # Used with page.render_views(App). + layouts, view_entries = _split_chain_into_view_levels(chain) + + results = [] + for match, _ in view_entries: + # Params accumulated up to this view level + level_params: dict[str, str] = {} + for m in chain: + level_params.update(m.params) + if m is match: + break + + # LocationInfo.pathname is the actual URL (not the route template), + # so is_route_active() and use_route_location() work consistently. + level_loc = LocationInfo(pathname=pathname, search=search, hash=hash_val) + # Per-view resolved URL — unique per view level for Navigator keying. + level_view_path = match.resolved_path or match.full_path or "/" + _match = match + # Only apply layouts that appear before this view entry in the chain + match_idx = chain.index(match) + _layouts = [lm for lm in layouts if chain.index(lm) < match_idx] + + def build_view_content( + _match=_match, + _layouts=_layouts, + _level_params=level_params, + _level_loc=level_loc, + _level_view_path=level_view_path, + ): + return _view_path_context( + _level_view_path, + lambda: _location_context( + _level_loc, + lambda: _params_context( + _level_params, + lambda: _build_view_level( + _layouts, _match, loader_results, chain + ), + ), + ), + ) + + results.append(build_view_content()) + + return results diff --git a/sdk/python/packages/flet/src/flet/components/utils.py b/sdk/python/packages/flet/src/flet/components/utils.py new file mode 100644 index 0000000000..53d4a201de --- /dev/null +++ b/sdk/python/packages/flet/src/flet/components/utils.py @@ -0,0 +1,165 @@ +import contextvars +import math +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from flet.components.component import Component, Renderer + + +_CURRENT_RENDERER: "contextvars.ContextVar[Renderer | None]" = contextvars.ContextVar( + "CURRENT_RENDERER", default=None +) + + +def current_renderer() -> "Renderer": + """ + Returns the renderer bound to the current execution context. + + The active renderer is stored in a context variable and is set while running + inside `Renderer.render(...)` or `Renderer.with_context(...)`. + + Returns: + The current `Renderer`. + + Raises: + RuntimeError: If no renderer is currently bound. + """ + r = _CURRENT_RENDERER.get() + if r is None: + raise RuntimeError( + "No current renderer is set. Call via Renderer.render(...) " + "or Renderer.with_context(...)." + ) + return r + + +def current_component() -> "Component": + """ + Returns the component currently being rendered. + + This is the top item of the current renderer render stack and is used by + hooks to access component-local state. + + Returns: + The currently rendering `Component`. + + Raises: + RuntimeError: If called outside an active component render frame. + """ + r = current_renderer() + if not r._render_stack: + raise RuntimeError("Hooks must be called inside a component render.") + return r._render_stack[-1] + + +def value_equal(a, b) -> bool: + """ + Compares two values with tolerant semantics for reactive updates. + + Comparison order: + - identity check (`a is b`); + - equality check (`a == b`) with exception suppression; + - special-case `float('nan')` so NaN compares equal to NaN. + + Args: + a: First value. + b: Second value. + + Returns: + `True` when values are considered equivalent for change detection; + otherwise `False`. + """ + # Fast path + if a is b: + return True + # Handle normal equality + try: + if a == b: + return True + except Exception: + pass + # Treat NaN == NaN as equal (like JS Object.is) + return ( + isinstance(a, float) + and isinstance(b, float) + and math.isnan(a) + and math.isnan(b) + ) + + +def shallow_compare_args( + prev_args: Sequence[Any], + args: Sequence[Any], +) -> bool: + """ + Performs shallow positional-argument comparison. + + Two argument sequences are considered equal when they are the same object, + or when they have equal length and each pair is either identical + (`is`) or equal (`==`). + + Args: + prev_args: Previously stored positional arguments. + args: New positional arguments. + + Returns: + `True` if arguments are shallow-equal; otherwise `False`. + """ + if prev_args is args: + return True + if len(prev_args) != len(args): + return False + return all(not (a is not b and a != b) for a, b in zip(prev_args, args)) + + +def shallow_compare_kwargs( + prev_kwargs: dict[str, Any], + kwargs: dict[str, Any], +) -> bool: + """ + Performs shallow keyword-argument comparison. + + Two mappings are considered equal when they are the same object, have the + same key set, and each corresponding value is either identical (`is`) or + equal (`==`). + + Args: + prev_kwargs: Previously stored keyword arguments. + kwargs: New keyword arguments. + + Returns: + `True` if keyword arguments are shallow-equal; otherwise `False`. + """ + if prev_kwargs is kwargs: + return True + if prev_kwargs.keys() != kwargs.keys(): + return False + for k in prev_kwargs: + a, b = prev_kwargs[k], kwargs[k] + if a is not b and a != b: + return False + return True + + +def shallow_compare_args_and_kwargs( + prev_args: tuple[Any, ...], + prev_kwargs: dict[str, Any], + args: tuple[Any, ...], + kwargs: dict[str, Any], +) -> bool: + """ + Performs combined shallow comparison of positional and keyword arguments. + + Args: + prev_args: Previously stored positional arguments. + prev_kwargs: Previously stored keyword arguments. + args: New positional arguments. + kwargs: New keyword arguments. + + Returns: + `True` only if both positional and keyword arguments are shallow-equal. + """ + return shallow_compare_args(prev_args, args) and shallow_compare_kwargs( + prev_kwargs, kwargs + ) diff --git a/sdk/python/packages/flet/src/flet/controls/__init__.py b/sdk/python/packages/flet/src/flet/controls/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/controls/adaptive_control.py b/sdk/python/packages/flet/src/flet/controls/adaptive_control.py new file mode 100644 index 0000000000..b37105656a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/adaptive_control.py @@ -0,0 +1,42 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control + +__all__ = ["AdaptiveControl"] + + +@control(kw_only=True) +class AdaptiveControl(Control): + """ + Base class for controls that support adaptive behavior, which allows them to \ + adjust their appearance and behavior based on the target platform (ex: Material \ + design on Android/Windows/Linux, Cupertino design on iOS/macOS). + + The :attr:`adaptive` property is applicable in two common scenarios: + + 1. **Platform-adaptive controls**: + These controls have a corresponding version on both Material and Cupertino + platforms. When `adaptive` is set to `True`, the control renders the + appropriate platform-specific implementation. + + 2. **Container controls**: + Controls that contain children (ex: :class:`~flet.Row`, :class:`~flet.Column`) \ + can pass + the `adaptive` value down to their children that do not explicitly define it + themselves. This enables nested adaptive behavior in complex layouts. + + Extension developers can use this base class to create their own adaptive controls + by checking the `adaptive` flag at runtime and rendering accordingly. + + Note: + This class does not implement any platform-specific rendering itself. + It is up to the control inheriting from it to interpret the :attr:`adaptive` + flag and render accordingly. + """ + + adaptive: Optional[bool] = None + """ + Enables platform-specific rendering or inheritance of adaptiveness from parent \ + controls. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/alignment.py b/sdk/python/packages/flet/src/flet/controls/alignment.py new file mode 100644 index 0000000000..dddf844054 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/alignment.py @@ -0,0 +1,130 @@ +from enum import Enum +from typing import ClassVar, Optional + +from flet.controls.base_control import value +from flet.controls.types import Number + +__all__ = [ + "Alignment", + "Axis", +] + + +class Axis(Enum): + """ + The two cardinal directions in two dimensions. + + The axis is always relative to the current coordinate space. This means, for + example, that a [horizontal] axis might actually be diagonally from top + right to bottom left, due to some local transform applied to the scene. + """ + + HORIZONTAL = "horizontal" + """ + Left and right. + """ + VERTICAL = "vertical" + """ + Up and down. + """ + + +@value +class Alignment: + """ + Defines an alignment relative to the center. + """ + + x: Number + """ + Represents the horizontal distance from the center. + + It's value ranges between `-1.0` and `1.0` inclusive. + """ + + y: Number + """ + Represents the vertical distance from the center. + + It's value ranges between `-1.0` and `1.0` inclusive. + """ + + BOTTOM_CENTER: ClassVar["AlignmentProperty"] + """ + Represents the bottom center and is equivalent to `Alignment(0.0, 1.0)`. + """ + + BOTTOM_LEFT: ClassVar["AlignmentProperty"] + """ + Represents the bottom left corner and is equivalent to `Alignment(-1.0, 1.0)`. + """ + + BOTTOM_RIGHT: ClassVar["AlignmentProperty"] + """ + Represents the bottom right corner and is equivalent to `Alignment(1.0, 1.0)`. + """ + + CENTER: ClassVar["AlignmentProperty"] + """ + Represents the center and is equivalent to `Alignment(0.0, 0.0)`. + """ + + CENTER_LEFT: ClassVar["AlignmentProperty"] + """ + Represents the center left and is equivalent to `Alignment(-1.0, 0.0)`. + """ + + CENTER_RIGHT: ClassVar["AlignmentProperty"] + """ + Represents the center right and is equivalent to `Alignment(1.0, 0.0)`. + """ + + TOP_CENTER: ClassVar["AlignmentProperty"] + """ + Represents the top center and is equivalent to `Alignment(0.0, -1.0)`. + """ + + TOP_LEFT: ClassVar["AlignmentProperty"] + """ + Represents the top left corner and is equivalent to `Alignment(-1.0, -1.0)`. + """ + + TOP_RIGHT: ClassVar["AlignmentProperty"] + """ + Represents the top right corner and is equivalent to `Alignment(1.0, -1.0)`. + """ + + def copy( + self, + *, + x: Optional[Number] = None, + y: Optional[Number] = None, + ) -> "Alignment": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Alignment( + x=x if x is not None else self.x, + y=y if y is not None else self.y, + ) + + +class AlignmentProperty: + """Descriptor used to expose predefined :class:`~flet.Alignment` constants.""" + + def __init__(self, factory): + self.factory = factory + + def __get__(self, instance, owner) -> Alignment: + return self.factory() + + +Alignment.BOTTOM_CENTER = AlignmentProperty(lambda: Alignment(0.0, 1.0)) +Alignment.BOTTOM_LEFT = AlignmentProperty(lambda: Alignment(-1.0, 1.0)) +Alignment.BOTTOM_RIGHT = AlignmentProperty(lambda: Alignment(1.0, 1.0)) +Alignment.CENTER = AlignmentProperty(lambda: Alignment(0.0, 0.0)) +Alignment.CENTER_LEFT = AlignmentProperty(lambda: Alignment(-1.0, 0.0)) +Alignment.CENTER_RIGHT = AlignmentProperty(lambda: Alignment(1.0, 0.0)) +Alignment.TOP_CENTER = AlignmentProperty(lambda: Alignment(0.0, -1.0)) +Alignment.TOP_LEFT = AlignmentProperty(lambda: Alignment(-1.0, -1.0)) +Alignment.TOP_RIGHT = AlignmentProperty(lambda: Alignment(1.0, -1.0)) diff --git a/sdk/python/packages/flet/src/flet/controls/animation.py b/sdk/python/packages/flet/src/flet/controls/animation.py new file mode 100644 index 0000000000..0ecc2cc0c7 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/animation.py @@ -0,0 +1,343 @@ +from dataclasses import field +from enum import Enum +from typing import Optional, Union + +from flet.controls.base_control import value +from flet.controls.duration import Duration, DurationValue + +__all__ = [ + "Animation", + "AnimationCurve", + "AnimationStyle", + "AnimationValue", +] + + +class AnimationCurve(Enum): + """ + Animation curves. + """ + + BOUNCE_IN = "bounceIn" + """ + Easing that enters with a bounce effect. + """ + + BOUNCE_IN_OUT = "bounceInOut" + """ + Easing that bounces both at the beginning and the end. + """ + + BOUNCE_OUT = "bounceOut" + """ + Easing that exits with a bounce effect. + """ + + DECELERATE = "decelerate" + """ + Starts quickly, then slows down toward the end. + """ + + EASE = "ease" + """ + Standard symmetric ease-in/ease-out curve. + """ + + EASE_IN = "easeIn" + """ + Starts slowly and accelerates. + """ + + EASE_IN_BACK = "easeInBack" + """ + Ease-in curve with a slight initial backward overshoot. + """ + + EASE_IN_CIRC = "easeInCirc" + """ + Circular ease-in curve. + """ + + EASE_IN_CUBIC = "easeInCubic" + """ + Cubic ease-in curve. + """ + + EASE_IN_EXPO = "easeInExpo" + """ + Exponential ease-in curve. + """ + + EASE_IN_OUT = "easeInOut" + """ + Symmetric ease-in/ease-out curve. + """ + + EASE_IN_OUT_BACK = "easeInOutBack" + """ + Ease-in/ease-out curve with overshoot near both ends. + """ + + EASE_IN_OUT_CIRC = "easeInOutCirc" + """ + Circular ease-in/ease-out curve. + """ + + EASE_IN_OUT_CUBIC = "easeInOutCubic" + """ + Cubic ease-in/ease-out curve. + """ + + EASE_IN_OUT_CUBIC_EMPHASIZED = "easeInOutCubicEmphasized" + """ + Material 3 emphasized cubic ease-in/ease-out curve. + """ + + EASE_IN_OUT_EXPO = "easeInOutExpo" + """ + Exponential ease-in/ease-out curve. + """ + + EASE_IN_OUT_QUAD = "easeInOutQuad" + """ + Quadratic ease-in/ease-out curve. + """ + + EASE_IN_OUT_QUART = "easeInOutQuart" + """ + Quartic ease-in/ease-out curve. + """ + + EASE_IN_OUT_QUINT = "easeInOutQuint" + """ + Quintic ease-in/ease-out curve. + """ + + EASE_IN_OUT_SINE = "easeInOutSine" + """ + Sinusoidal ease-in/ease-out curve. + """ + + EASE_IN_QUAD = "easeInQuad" + """ + Quadratic ease-in curve. + """ + + EASE_IN_QUART = "easeInQuart" + """ + Quartic ease-in curve. + """ + + EASE_IN_QUINT = "easeInQuint" + """ + Quintic ease-in curve. + """ + + EASE_IN_SINE = "easeInSine" + """ + Sinusoidal ease-in curve. + """ + + EASE_IN_TO_LINEAR = "easeInToLinear" + """ + Transitions from ease-in motion into linear motion. + """ + + EASE_OUT = "easeOut" + """ + Starts quickly and decelerates to the end. + """ + + EASE_OUT_BACK = "easeOutBack" + """ + Ease-out curve with trailing overshoot. + """ + + EASE_OUT_CIRC = "easeOutCirc" + """ + Circular ease-out curve. + """ + + EASE_OUT_CUBIC = "easeOutCubic" + """ + Cubic ease-out curve. + """ + + EASE_OUT_EXPO = "easeOutExpo" + """ + Exponential ease-out curve. + """ + + EASE_OUT_QUAD = "easeOutQuad" + """ + Quadratic ease-out curve. + """ + + EASE_OUT_QUART = "easeOutQuart" + """ + Quartic ease-out curve. + """ + + EASE_OUT_QUINT = "easeOutQuint" + """ + Quintic ease-out curve. + """ + + EASE_OUT_SINE = "easeOutSine" + """ + Sinusoidal ease-out curve. + """ + + ELASTIC_IN = "elasticIn" + """ + Elastic spring-like ease-in curve. + """ + + ELASTIC_IN_OUT = "elasticInOut" + """ + Elastic spring-like ease-in/ease-out curve. + """ + + ELASTIC_OUT = "elasticOut" + """ + Elastic spring-like ease-out curve. + """ + + FAST_LINEAR_TO_SLOW_EASE_IN = "fastLinearToSlowEaseIn" + """ + Starts linear and then eases into a slower end. + """ + + FAST_OUT_SLOWIN = "fastOutSlowIn" + """ + Material motion curve: quick start, gentle finish. + """ + + LINEAR = "linear" + """ + Constant speed with no easing. + """ + + LINEAR_TO_EASE_OUT = "linearToEaseOut" + """ + Starts linear and transitions to an ease-out tail. + """ + + SLOW_MIDDLE = "slowMiddle" + """ + Slows in the middle section of the animation. + """ + + +@value +class Animation: + """ + Explicit animation configuration for animatable control properties. + + Properties that accept animation usually also support shorthand values via + :data:`~flet.AnimationValue`: + - `True`: enables a default `1000ms` :attr:`~flet.AnimationCurve.LINEAR` animation. + - `int`: interpreted as animation duration in milliseconds with a linear curve. + """ + + duration: DurationValue = field(default_factory=lambda: Duration()) + """ + The duration of the animation. + + If provided as an integer, it is considered/assumed to be in milliseconds. + For more control and flexibility, use :class:`~flet.Duration` instead. + """ + + curve: AnimationCurve = AnimationCurve.LINEAR + """ + Easing curve that shapes interpolation over time. + """ + + def copy( + self, + *, + duration: Optional[DurationValue] = None, + curve: Optional[AnimationCurve] = None, + ) -> "Animation": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Animation( + duration=duration if duration is not None else self.duration, + curve=curve if curve is not None else self.curve, + ) + + +@value +class AnimationStyle: + """ + Used to override the default parameters of an animation. + + Note: + If :attr:`duration` and :attr:`reverse_duration` are set to + :class:`~flet.Duration`, the corresponding animation will be disabled. + See :meth:`no_animation` method for a convenient way to create + such an instance. + """ + + duration: Optional[DurationValue] = None + """ + The duration of the animation. + """ + + reverse_duration: Optional[DurationValue] = None + """ + The duration of the reverse animation. + """ + + curve: Optional[AnimationCurve] = None + """ + The curve to use for the animation. + """ + + reverse_curve: Optional[AnimationCurve] = None + """ + The curve to use for the reverse animation. + """ + + @staticmethod + def no_animation() -> "AnimationStyle": + """ + Creates an instance of `AnimationStyle` with no animation. + """ + return AnimationStyle( + duration=Duration(), + reverse_duration=Duration(), + ) + + def copy( + self, + *, + duration: Optional[DurationValue] = None, + reverse_duration: Optional[DurationValue] = None, + curve: Optional[AnimationCurve] = None, + reverse_curve: Optional[AnimationCurve] = None, + ) -> "AnimationStyle": + """ + Returns a copy of this object with the specified properties overridden. + """ + return AnimationStyle( + duration=duration if duration is not None else self.duration, + reverse_duration=reverse_duration + if reverse_duration is not None + else self.reverse_duration, + curve=curve if curve is not None else self.curve, + reverse_curve=reverse_curve + if reverse_curve is not None + else self.reverse_curve, + ) + + +AnimationValue = Union[bool, int, Animation] +"""Type alias for animation configuration values. + +Represents animation input as either: +- `True` or `False` to enable or disable animation, +- an `int` duration in milliseconds, +- or an explicit :class:`~flet.Animation` configuration. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/base_control.py b/sdk/python/packages/flet/src/flet/controls/base_control.py new file mode 100644 index 0000000000..95e29de41c --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/base_control.py @@ -0,0 +1,505 @@ +import inspect +import logging +import sys +from dataclasses import InitVar, dataclass, field +from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, overload + +from flet.controls.context import _context_page, context +from flet.controls.control_event import ControlEvent, get_event_field_type +from flet.controls.id_counter import ControlId +from flet.controls.ref import Ref +from flet.controls.value_types import Prop, Value, _install_props, value +from flet.utils.from_dict import from_dict +from flet.utils.object_model import get_param_count +from flet.utils.validation import validate + +logger = logging.getLogger("flet") +controls_log = logging.getLogger("flet_controls") + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + + +if TYPE_CHECKING: + from .base_page import BasePage + from .keys import KeyValue + from .page import Page + +__all__ = [ + "BaseControl", + "Prop", + "Value", + "control", + "skip_field", + "value", +] + +# --------------------------------------------------------------------------- +# Sparse property tracking is defined in value_types.py to avoid circular +# imports: value types (Duration, Alignment, etc.) need @value but are +# imported transitively by this module. +# Prop, Value, _install_props and value are re-exported from here +# for backwards compatibility. +# --------------------------------------------------------------------------- + + +def skip_field(): + """ + Creates a dataclass field excluded from control tree traversal and patching. + + The returned field uses `metadata={"skip": True}` so runtime diff/configuration + logic ignores it. This is intended for Python-side state that must not + participate in UI reconciliation/serialization. + """ + return field(default=None, metadata={"skip": True}) + + +T = TypeVar("T", bound="BaseControl") + + +@overload +def control(cls: type[T]) -> type[T]: + """ + Overload for using `@control` without arguments. + + Applies dataclass behavior and control wiring to `cls` using default options. + """ + ... + + +@overload +def control( + dart_widget_name: Optional[Union[type[T], str]] = None, + *, + isolated: Optional[bool] = None, + post_init_args: int = 1, + **dataclass_kwargs: Any, +) -> Callable[[type[T]], type[T]]: + """ + Overload for using `@control(...)` with explicit decorator arguments. + + Returns a class decorator that applies dataclass behavior and optional + control metadata (`dart_widget_name`, `isolated`, `post_init_args`). + """ + ... + + +@dataclass_transform() +def control( + dart_widget_name: Optional[Union[type[T], str]] = None, + *, + isolated: Optional[bool] = None, + post_init_args: int = 1, + **dataclass_kwargs: Any, +) -> Union[type[T], Callable[[type[T]], type[T]]]: + """ + Decorator to optionally set widget name and 'isolated' while behaving like \ + `dataclasses.dataclass`. + + Parameters: + dart_widget_name: The name of widget on Dart side. + isolated: If `True`, marks the control as isolated. An isolated control + is excluded from page updates when its parent control is updated. + post_init_args: Number of InitVar arguments to pass to __post_init__. + dataclass_kwargs: Additional keyword arguments passed to `@dataclass`. + + Usage: + - Supports `@control` (without parentheses) + - Supports `@control("WidgetName")` (with optional arguments) + - Supports `@control("WidgetName", post_init_args=1, isolated=True)` to + specify the number of `InitVar` arguments and isolation + """ + + # Case 1: If used as `@control` (without parentheses) + if isinstance(dart_widget_name, type): + return _apply_control( + dart_widget_name, None, isolated, post_init_args, **dataclass_kwargs + ) + + # Case 2: If used as `@control("custom_type", post_init_args=N, isolated=True)` + def wrapper(cls: type[T]) -> type[T]: + return _apply_control( + cls, dart_widget_name, isolated, post_init_args, **dataclass_kwargs + ) + + return wrapper + + +def _apply_control( + cls: type[T], + type_name: Optional[str], + isolated: Optional[bool], + post_init_args: int, + **dataclass_kwargs, +) -> type[T]: + """Applies @control logic, ensuring compatibility with @dataclass.""" + cls = dataclass(**dataclass_kwargs)(cls) # Apply @dataclass first + _install_props(cls) # Install Prop descriptors for sparse tracking + + orig_post_init = getattr(cls, "__post_init__", lambda self, *args: None) + + def new_post_init(self: T, *args): + """Set the type and isolation only if explicitly provided.""" + if type_name is not None and (not hasattr(self, "_c") or self._c is None): + self._c = type_name # Only set type if explicitly provided + + if isolated is not None: + self._isolated = isolated # Set the _isolated field if provided + + # Pass only the correct number of arguments to `__post_init__` + orig_post_init(self, *args[:post_init_args]) + + cls.__post_init__ = new_post_init + return cls + + +@dataclass(kw_only=True) +class BaseControl: + """ + Base class for all Flet controls and services. + """ + + # ------------------------------------------------------------------ + # Sparse property tracking — MUST be the first two init=False fields + # so the dataclass-generated __init__ initialises them before any + # Prop.__set__ call for init=True fields. + # ------------------------------------------------------------------ + _values: dict = field( + default_factory=dict, + init=False, + repr=False, + compare=False, + metadata={"skip": True}, + ) + _dirty: dict = field( + default_factory=dict, + init=False, + repr=False, + compare=False, + metadata={"skip": True}, + ) + + _i: int = field(init=False, compare=False) + """ + Runtime-generated internal control id used by the session protocol. + """ + + _c: str = field(init=False) + """ + Dart-side control type name set by the `@control` decorator. + """ + + data: Any = skip_field() + """ + Arbitrary data of any type. + """ + + key: Optional["KeyValue"] = None + + ref: InitVar[Optional[Ref["BaseControl"]]] = None + """A reference to this control.""" + + _internals: dict = field( + default_factory=dict, init=False, repr=False, compare=False + ) + """ + A dictionary for storing internal control configuration. + """ + + def __post_init__(self, ref: Optional[Ref[Any]]): + """ + Finalize control bootstrap after dataclass initialization. + + Assigns an internal id, validates `@control` metadata, attaches `ref` + when provided, and then calls `init()`. Override `init()` for setup + logic; avoid overriding this method in normal controls. + """ + self.__class__.__hash__ = BaseControl.__hash__ + self._i = ControlId.next() + if not hasattr(self, "_c") or self._c is None: + cls_name = f"{self.__class__.__module__}.{self.__class__.__qualname__}" + raise ValueError( + f"Control {cls_name} must have @control decorator with " + "type_name specified." + ) + + if ref is not None: + ref.current = self + + self.init() + # Construction is not a mutation: clear dirty tracking so only + # post-construction mutations are visible to the non-frozen diff. + self._dirty.clear() + + # control_id = self._i + # object_id = id(self) + # ctrl_type = self._c + # weakref.finalize( + # self, + # lambda: controls_log.debug( + # f"Control was garbage collected: {ctrl_type}({control_id} " + # f"- {object_id})" + # ), + # ) + + def __hash__(self) -> int: + """ + Preserve object-identity hashing for mutable dataclass controls. + """ + return object.__hash__(self) + + @property + def parent(self) -> Optional["BaseControl"]: + """ + The direct ancestor(parent) of this control. + + It defaults to `None` and will only have a value when this control is mounted + (added to the page tree). + + The `Page` control (which is the root of the tree) is an exception - it always + has `parent=None`. + """ + parent_ref = getattr(self, "_parent", None) + return parent_ref() if parent_ref else None + + @property + def page(self) -> "Union[Page, BasePage]": + """ + The page to which this control belongs to. + """ + from .page import Page + + parent = self + while parent: + if isinstance(parent, Page): + return parent + parent = parent.parent + raise RuntimeError( + f"{self.__class__.__qualname__}({self._i}) " + "Control must be added to the page first" + ) + + def is_isolated(self): + """ + Return whether this control is marked as isolated. + + Isolated controls are excluded from parent-driven update traversal and + are expected to manage their own update boundaries. + """ + return hasattr(self, "_isolated") and self._isolated + + def init(self): + """ + Called after control instance initialization and before \ + the first build / update cycle. + + Override this hook to perform lightweight setup that depends on initialized + fields. Do not call `update()` here. + """ + pass + + def build(self): + """ + Called once during control initialization to define its child controls. + `page` property is available/usable in this method. + """ + pass + + def before_update(self): + """ + This method is called every time when this control is being updated. + + Note: + Make sure not to call/request an `update()` here. + """ + pass + + def _before_update_safe(self): + """ + Run `before_update()` while preserving the frozen marker. + + Internal runtime helper. It temporarily removes `_frozen` so the hook + can adjust properties and then restores the previous frozen state. + """ + frozen = getattr(self, "_frozen", None) + if frozen is not None: + del self._frozen + + self.before_update() + validate(self, suppress_repeated_errors=True) + + if frozen is not None: + self._frozen = frozen + + def before_event(self, e: ControlEvent): + """ + Intercept an event before its handler is executed. + + Return `False` to cancel dispatch. Return `True` or `None` to continue + normal event processing. + """ + return True + + def did_mount(self): + """ + Called after the control is mounted into the page tree. + + Override to start resources that require an attached page, for example + subscriptions, timers, or service listeners. + """ + controls_log.debug("%s.did_mount()", self) + pass + + def will_unmount(self): + """ + Called before the control is removed from the page tree. + + Override to dispose resources created in `did_mount()`, such as + subscriptions, timers, or external handles. + """ + controls_log.debug("%s.will_unmount()", self) + pass + + # public methods + def update(self) -> None: + """ + Request a UI update for this control. + + Call after changing control state or properties. The control must be + attached to a page and not marked as frozen. + """ + if hasattr(self, "_frozen"): + raise RuntimeError("Frozen control cannot be updated.") + if not self.page: + raise RuntimeError( + f"{self.__class__.__qualname__} Control must be added to the page first" + ) + self.page.update(self) + + async def _invoke_method( + self, + method_name: str, + arguments: Optional[dict[str, Any]] = None, + timeout: Optional[float] = None, + ) -> Any: + """ + Invoke a runtime method for this control via the active session. + + Internal async bridge used by controls and services for imperative + method calls on the backend/runtime side. + """ + if not self.page: + raise RuntimeError( + f"{self.__class__.__qualname__} Control must be added to the page first" + ) + + return await self.page.session.invoke_method( + self._i, method_name, arguments, timeout + ) + + async def _trigger_event( + self, event_name: str, event_data: Any, e: Optional[ControlEvent] = None + ): + """ + Resolve and dispatch an event to the matching `on_` handler. + + Internal helper that builds event objects, calls `before_event()`, + executes sync/async handlers, and notifies session progress. + """ + field_name = f"on_{event_name}" + if not hasattr(self, field_name): + # field_name not defined + return + + event_type = get_event_field_type(self, field_name) + if event_type is None: + return + + if e is None: + if event_type == ControlEvent or not isinstance(event_data, dict): + # simple ControlEvent + e = ControlEvent(control=self, name=event_name, data=event_data) + else: + # custom ControlEvent + args = { + "control": self, + "name": event_name, + **(event_data or {}), + } + e = from_dict(event_type, args) + + handle_event = self.before_event(e) + + if handle_event is None or handle_event: + _context_page.set(self.page) + context.reset_auto_update() + + controls_log.debug("Trigger event %s.%s %s", self, field_name, e) + + if not self.page: + raise RuntimeError( + "Control must be added to a page before triggering events. Use " + "page.add(control) or add it to a parent control that's on a page." + ) + session = self.page.session + + # Handle async and sync event handlers accordingly + event_handler = getattr(self, field_name) + if inspect.iscoroutinefunction(event_handler): + if get_param_count(event_handler) == 0: + await event_handler() + else: + await event_handler(e) + + elif inspect.isasyncgenfunction(event_handler): + if get_param_count(event_handler) == 0: + async for _ in event_handler(): + await session.after_event(session.index.get(self._i)) + else: + async for _ in event_handler(e): + await session.after_event(session.index.get(self._i)) + return + + elif inspect.isgeneratorfunction(event_handler): + if get_param_count(event_handler) == 0: + for _ in event_handler(): + await session.after_event(session.index.get(self._i)) + else: + for _ in event_handler(e): + await session.after_event(session.index.get(self._i)) + return + + elif callable(event_handler): + if get_param_count(event_handler) == 0: + event_handler() + else: + event_handler(e) + + await session.after_event(session.index.get(self._i)) + + def _migrate_state(self, other: "BaseControl"): + """ + Transfer transient runtime state from a previous control instance. + + This hook is used by reconciliation when replacing controls with newer + instances of the same logical node. Override to copy extra runtime + fields, and always call `super()._migrate_state(other)` first. + """ + if not isinstance(other, BaseControl): + return + self._i = other._i + if self.data is None: + self.data = other.data + + def __str__(self): + """ + Return a debug-friendly control identifier string. + """ + return f"{self._c}({self._i} - {id(self)})" + + +# Install Prop descriptors for BaseControl's own public fields (key). +# Subclasses decorated with @control get this called via _apply_control. +_install_props(BaseControl) diff --git a/sdk/python/packages/flet/src/flet/controls/base_page.py b/sdk/python/packages/flet/src/flet/controls/base_page.py new file mode 100644 index 0000000000..23a8ce98f2 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/base_page.py @@ -0,0 +1,858 @@ +import logging +import weakref +from dataclasses import dataclass, field +from typing import ( + TYPE_CHECKING, + Optional, + Union, +) + +from flet.components.public_utils import unwrap_component +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.animation import AnimationCurve, AnimationStyle +from flet.controls.base_control import BaseControl, control +from flet.controls.box import BoxDecoration +from flet.controls.control import Control +from flet.controls.control_event import ( + Event, + EventHandler, +) +from flet.controls.core.view import View +from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar +from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar +from flet.controls.dialog_control import DialogControl +from flet.controls.duration import DurationValue +from flet.controls.keys import ScrollKey +from flet.controls.material.app_bar import AppBar +from flet.controls.material.bottom_app_bar import BottomAppBar +from flet.controls.material.floating_action_button import FloatingActionButton +from flet.controls.material.navigation_bar import NavigationBar +from flet.controls.material.navigation_drawer import NavigationDrawer +from flet.controls.padding import Padding, PaddingValue +from flet.controls.scrollable_control import Scrollbar +from flet.controls.services.service import Service +from flet.controls.transform import OffsetValue +from flet.controls.types import ( + ColorValue, + CrossAxisAlignment, + FloatingActionButtonLocation, + LocaleConfiguration, + MainAxisAlignment, + Number, + Orientation, + ScrollMode, + ThemeMode, +) + +logger = logging.getLogger("flet") + +_MANAGED_DIALOG_DISMISS_ORIGINAL = "_managed_dialog_dismiss_original" +_MANAGED_DIALOG_DISMISS_WRAPPER = "_managed_dialog_dismiss_wrapper" + +if TYPE_CHECKING: + from flet.controls.theme import Theme + + +@dataclass +class PageMediaData: + """ + Represents the environmental metrics of a page or window. + + This data is updated whenever the platform window or layout changes, + such as when rotating a device, resizing a browser window, or adjusting + system UI elements like the keyboard or safe areas. + """ + + padding: Padding + """ + The space surrounding the entire display, accounting for system UI like notches \ + and status bars. + """ + + view_padding: Padding + """ + Similar to :attr:`padding`, but includes padding that is always reserved (even \ + when the system UI is hidden). + """ + + view_insets: Padding + """ + Areas obscured by system UI overlays, such as the on-screen keyboard or system \ + gesture areas. + """ + + device_pixel_ratio: float + """ + The number of device pixels for each logical pixel. + """ + + orientation: Orientation + """ + The orientation of the page. + """ + + always_use_24_hour_format: bool = False + """ + Whether to use 24-hour format when formatting time. + + Note: + The behavior of this flag is different across platforms: + + - On Android this flag is reported directly from the user settings called + "Use 24-hour format". It applies to any locale used by the application, + whether it is the system-wide locale, or the custom locale set by the + application. + - On iOS this flag is set to true when the user setting called "24-Hour Time" + is set or the system-wide locale's default uses 24-hour + formatting. + """ + + +@dataclass +class PageResizeEvent(Event["BasePage"]): + """ + Event fired when the size of the containing window or browser is changed. + + Typically used to adapt layout dynamically in response to resizes, + such as switching between compact and expanded views in a responsive design. + """ + + width: float + """ + The new width of the page in logical pixels. + """ + + height: float + """ + The new height of the page in logical pixels. + """ + + +@control("BasePage", isolated=True, kw_only=True) +class BasePage(AdaptiveControl): + """ + A visual container representing a top-level view in a Flet application. + + `BasePage` serves as the base class for :class:`~flet.Page` and \ + :class:`~flet.MultiView`, + and provides a unified surface for rendering application content, app bars, + navigation elements, dialogs, overlays, and more. It manages one or more + :class:`~flet.View` instances and exposes high-level layout, + scrolling, and theming properties. + + Unlike lower-level layout controls (e.g., :class:`~flet.Column`, + :class:`~flet.Container`), :class:`~flet.BasePage` represents + an entire logical view or screen of the app. It provides direct access + to view-level controls such as :class:`~flet.AppBar`, :class:`~flet.NavigationBar`, + :class:`~flet.FloatingActionButton`, and supports system-level events like window + resizing and media changes. + + This class is not intended to be used directly in most apps; instead, + use :class:`~flet.Page` or :class:`~flet.MultiView`, which extend this base + functionality. + """ + + views: list[View] = field(default_factory=lambda: [View()]) + """ + A list of views managed by the page. + + Each :class:`~flet.View` represents a distinct navigation state or screen + in the application. + + The first view in the list is considered the active one by default. + """ + + theme_mode: Optional[ThemeMode] = ThemeMode.SYSTEM + """ + The page's theme mode. + """ + + theme: Optional["Theme"] = None + """ + Customizes the theme of the application when in light theme mode. Currently, a \ + theme can only be automatically generated from a "seed" color. For example, to \ + generate light theme from a green color. + """ + + dark_theme: Optional["Theme"] = None + """ + Customizes the theme of the application when in dark theme mode. + """ + + theme_animation_style: Optional[AnimationStyle] = None + """ + Overrides the default animation style used when the application's theme + is changed (for example, when :attr:`theme_mode` switches between light + and dark). + + Tip: + Use :meth:`flet.AnimationStyle.no_animation` to disable the theme + transition entirely. + """ + + locale_configuration: Optional[LocaleConfiguration] = None + """ + Configures supported locales and the current locale. + """ + + show_semantics_debugger: Optional[bool] = None + """ + Whether to turn on an overlay that shows the accessibility information reported by \ + the framework. + """ + + title: Optional[str] = None + """ + Page or window title. + """ + + enable_screenshots: bool = False + """ + Enable taking screenshots of the entire page with `take_screenshot` method. + """ + + on_resize: Optional[EventHandler["PageResizeEvent"]] = None + """ + Called when a user resizes a browser or native OS window containing Flet app + + Example: + ```python + def main(page: ft.Page): + def handle_page_size(e): + print("New page size:", page.window.width, page.window_height) + + page.on_resize = handle_page_size + ``` + """ + + on_media_change: Optional[EventHandler[PageMediaData]] = None + """ + Called when :attr:`media` has changed. + """ + + media: PageMediaData = field( + default_factory=lambda: PageMediaData( + padding=Padding.zero(), + view_padding=Padding.zero(), + view_insets=Padding.zero(), + device_pixel_ratio=0, + orientation=Orientation.PORTRAIT, + always_use_24_hour_format=False, + ) + ) + """ + The current environmental metrics of the page or window. + + This data is updated whenever the platform window or layout changes, + such as when rotating a device, resizing a browser window, or adjusting + system UI elements like the keyboard or safe areas. + """ + + width: Optional[Number] = None + """ + Page width in logical pixels. + + Note: + - This property is read-only. + - To get or set the full window height including window chrome (e.g., + title bar and borders) when running a Flet app on desktop, + use the :attr:`~flet.Window.width` property of :attr:`flet.Page.window` \ + instead. + """ + + height: Optional[Number] = None + """ + Page height in logical pixels. + + Note: + - This property is read-only. + - To get or set the full window height including window chrome (e.g., + title bar and borders) when running a Flet app on desktop, + use the :attr:`~flet.Window.height` property of + :attr:`flet.Page.window` instead. + """ + + _overlay: "Overlay" = field(default_factory=lambda: Overlay()) + _dialogs: "Dialogs" = field(default_factory=lambda: Dialogs()) + + def __resolved_views(self) -> list[View]: + views = unwrap_component(self.views) + if isinstance(views, View): + return [views] + return [unwrap_component(v) for v in views] + + def __root_view(self) -> View: + """ + Return the root view of this page container. + + Returns: + The first :class:`~flet.View` in :attr:`views`. + + Raises: + RuntimeError: If no views are available. + """ + + views = self.__resolved_views() + if len(views) == 0: + raise RuntimeError("views list is empty.") + return views[0] + + def __top_view(self) -> View: + """ + Return the top-most (active) view in the view stack. + + Returns: + The last :class:`~flet.View` in :attr:`views`. + + Raises: + RuntimeError: If no views are available. + """ + + views = self.__resolved_views() + if len(views) == 0: + raise RuntimeError("views list is empty.") + return views[-1] + + def update(self, *controls: Control) -> None: + """ + Push pending updates to the connected client. + + Args: + *controls: Specific controls to update. When omitted, updates this + page object. + """ + + if len(controls) == 0: + self.page.update(self) + else: + self.page.update(*controls) + + def add(self, *controls: Control) -> None: + """ + Adds controls to the page. + + Example: + ```python + page.add(ft.Text("Hello!"), ft.FilledButton("Button")) + ``` + """ + self.controls.extend(controls) + self.update() + + def insert(self, at: int, *controls: Control) -> None: + """ + Inserts controls at specific index of `page.controls` list. + """ + n = at + for c in controls: + self.controls.insert(n, c) + n += 1 + self.update() + + def remove(self, *controls: Control) -> None: + """ + Removes specific controls from `page.controls` list. + """ + for c in controls: + self.controls.remove(c) + self.update() + + def remove_at(self, index: int) -> None: + """ + Remove controls from `page.controls` list at specific index. + """ + self.controls.pop(index) + self.update() + + def clean(self) -> None: + """ + Remove all root view controls and send update to the client. + """ + + self.controls.clear() + self.update() + + async def scroll_to( + self, + offset: Optional[Number] = None, + delta: Optional[Number] = None, + scroll_key: Union[ScrollKey, str, int, float, bool, None] = None, + duration: Optional[DurationValue] = None, + curve: Optional[AnimationCurve] = None, + ) -> None: + """ + Moves scroll position to either absolute `offset`, relative `delta` or jump to \ + the control with specified `scroll_key`. + + See :meth:`flet.Column.scroll_to` for method details + and examples. + """ + await self.__root_view().scroll_to( + offset=offset, + delta=delta, + scroll_key=scroll_key, + duration=duration, + curve=curve, + ) + + def show_dialog(self, dialog: DialogControl) -> None: + """ + Displays a dialog and manages its dismissal lifecycle. + + This method adds the specified `dialog` to the active dialog stack + and renders it on the page. + The :attr:`~flet.DialogControl.on_dismiss` handler of the dialog + is temporarily wrapped to ensure the dialog is removed from the stack and + its dismissal event is triggered appropriately. + + Args: + dialog: The dialog instance to display. Must not yet be open. + + Raises: + RuntimeError: If the specified dialog is already open. + """ + if dialog in self._dialogs.controls: + raise RuntimeError("Dialog is already opened") + + dialog.open = True + self._prepare_dialog(dialog) + + self._dialogs.controls.append(dialog) + self._dialogs.update() + + def pop_dialog(self) -> Optional[DialogControl]: + """ + Closes the most recently opened dialog. + + This method searches the active dialog stack for the topmost dialog + that is currently open, marks it as closed, updates its state, + and returns the closed dialog. + + Returns: + The closed dialog instance if one was found, otherwise `None`. + """ + dialog = next( + (dlg for dlg in reversed(self._dialogs.controls) if dlg.open), None + ) + if not dialog: + return None + dialog.open = False + dialog.update() + return dialog + + def _prepare_dialog(self, dialog: DialogControl) -> None: + self._set_dialog_parent(dialog) + self._wrap_dialog_on_dismiss(dialog) + + def _set_dialog_parent(self, dialog: DialogControl) -> None: + dialog._parent = weakref.ref(self._dialogs) + + def _get_original_dialog_on_dismiss(self, dialog: DialogControl): + wrapper = getattr(dialog, _MANAGED_DIALOG_DISMISS_WRAPPER, None) + if wrapper is not None and dialog.on_dismiss is wrapper: + return getattr(dialog, _MANAGED_DIALOG_DISMISS_ORIGINAL, None) + return dialog.on_dismiss + + def _wrap_dialog_on_dismiss(self, dialog: DialogControl) -> None: + original_on_dismiss = self._get_original_dialog_on_dismiss(dialog) + + async def wrapped_on_dismiss(*args): + # Keep the dialog mounted until Flutter reports dismiss. Removing it + # earlier can drop the post-animation dismiss callback entirely. + self._restore_dialog_on_dismiss(dialog) + self._remove_dialog(dialog) + e = args[0] + if ( + original_on_dismiss and (e.data is None or e.data) + # e.data == True for TimePicker and DatePicker if they were + # dismissed without changing the value + ): + await dialog._trigger_event("dismiss", e) + + setattr(dialog, _MANAGED_DIALOG_DISMISS_ORIGINAL, original_on_dismiss) + setattr(dialog, _MANAGED_DIALOG_DISMISS_WRAPPER, wrapped_on_dismiss) + dialog.on_dismiss = wrapped_on_dismiss + + def _restore_dialog_on_dismiss(self, dialog: DialogControl) -> None: + original_on_dismiss = getattr(dialog, _MANAGED_DIALOG_DISMISS_ORIGINAL, None) + if hasattr(dialog, _MANAGED_DIALOG_DISMISS_ORIGINAL): + delattr(dialog, _MANAGED_DIALOG_DISMISS_ORIGINAL) + if hasattr(dialog, _MANAGED_DIALOG_DISMISS_WRAPPER): + delattr(dialog, _MANAGED_DIALOG_DISMISS_WRAPPER) + dialog.on_dismiss = original_on_dismiss + + def _remove_dialog(self, dialog: DialogControl) -> None: + if dialog in self._dialogs.controls: + self._dialogs.controls.remove(dialog) + self._dialogs.update() + + async def show_drawer(self): + """ + Show the drawer. + + Raises: + ValueError: If no :attr:`drawer` is defined. + """ + await self.__top_view().show_drawer() + + async def close_drawer(self): + """ + Close the drawer. + """ + await self.__top_view().close_drawer() + + async def show_end_drawer(self): + """ + Show the end drawer. + + Raises: + ValueError: If no :attr:`end_drawer` is defined. + """ + await self.__top_view().show_end_drawer() + + async def close_end_drawer(self): + """ + Close the end drawer. + """ + await self.__top_view().close_end_drawer() + + async def take_screenshot( + self, + pixel_ratio: Optional[Number] = None, + delay: Optional[DurationValue] = None, + ) -> bytes: + """ + Captures a screenshot of the entire page with overlays. + + Args: + pixel_ratio: A pixel ratio of the captured screenshot. + If `None`, device-specific pixel ratio will be used. + delay: A delay before taking a screenshot. + The delay will be 20 milliseconds if not specified. + + Returns: + Screenshot in PNG format. + """ + return await self._invoke_method( + "take_screenshot", arguments={"pixel_ratio": pixel_ratio, "delay": delay} + ) + + async def take_animation( + self, + name: str, + frame_delays_ms: list[int], + pixel_ratio: Optional[Number] = None, + ) -> list[bytes]: + """ + Captures an animated sequence of page screenshots in a single + round-trip. Each entry in `frame_delays_ms` is the delay in + milliseconds to wait before capturing that frame. The wait and + capture loop runs entirely on the Flutter side, so animation + timing isn't distorted by Python-Flutter RPC latency the way it + is with a Python-driven `take_screenshot` loop. + + Requires `enable_screenshots` = `True`. + + Args: + name: Name prefix for the captured frames (for debugging). + frame_delays_ms: Per-frame delays in milliseconds. The list + length determines the number of frames captured. + pixel_ratio: A pixel ratio of the captured frames. + If `None`, device-specific pixel ratio will be used. + + Returns: + List of PNG-encoded frames, one per entry in `frame_delays_ms`. + """ + return await self._invoke_method( + "take_animation", + arguments={ + "name": name, + "frame_delays_ms": frame_delays_ms, + "pixel_ratio": pixel_ratio, + }, + ) + + # overlay + @property + def overlay(self) -> list[BaseControl]: + """ + The list of overlay controls rendered above page content. + """ + + return self._overlay.controls + + # controls + @property + def controls(self) -> list[BaseControl]: + """ + Root view content controls displayed by this page. + """ + + return self.__root_view().controls + + @controls.setter + def controls(self, value: list[BaseControl]): + self.__root_view().controls = value + + # appbar + @property + def appbar(self) -> Union[AppBar, CupertinoAppBar, None]: + """ + Gets or sets the top application bar (:class:`~flet.AppBar` or \ + :class:`~flet.CupertinoAppBar`) for the view. + + The app bar typically displays the page title and optional actions + such as navigation icons, menus, or other interactive elements. + """ + return self.__root_view().appbar + + @appbar.setter + def appbar(self, value: Union[AppBar, CupertinoAppBar, None]): + self.__root_view().appbar = value + + # bottom_appbar + @property + def bottom_appbar(self) -> Optional[BottomAppBar]: + """ + Bottom app bar displayed in the root view. + """ + + return self.__root_view().bottom_appbar + + @bottom_appbar.setter + def bottom_appbar(self, value: Optional[BottomAppBar]): + self.__root_view().bottom_appbar = value + + # navigation_bar + @property + def navigation_bar(self) -> Optional[Union[NavigationBar, CupertinoNavigationBar]]: + """ + Bottom navigation bar for the root view. + """ + + return self.__root_view().navigation_bar + + @navigation_bar.setter + def navigation_bar( + self, + value: Optional[Union[NavigationBar, CupertinoNavigationBar]], + ): + self.__root_view().navigation_bar = value + + # drawer + @property + def drawer(self) -> Optional[NavigationDrawer]: + """ + Navigation drawer opened from the leading edge. + """ + + return self.__root_view().drawer + + @drawer.setter + def drawer(self, value: Optional[NavigationDrawer]): + self.__root_view().drawer = value + + # end_drawer + @property + def end_drawer(self) -> Optional[NavigationDrawer]: + """ + Navigation drawer opened from the trailing edge. + """ + + return self.__root_view().end_drawer + + @end_drawer.setter + def end_drawer(self, value: Optional[NavigationDrawer]): + self.__root_view().end_drawer = value + + # decoration + @property + def decoration(self) -> Optional[BoxDecoration]: + """ + Background decoration of the root view container. + """ + + return self.__root_view().decoration + + @decoration.setter + def decoration(self, value: Optional[BoxDecoration]): + self.__root_view().decoration = value + + # foreground_decoration + @property + def foreground_decoration(self) -> Optional[BoxDecoration]: + """ + Foreground decoration painted above root view content. + """ + + return self.__root_view().foreground_decoration + + @foreground_decoration.setter + def foreground_decoration(self, value: Optional[BoxDecoration]): + self.__root_view().foreground_decoration = value + + # floating_action_button + @property + def floating_action_button(self) -> Optional[FloatingActionButton]: + """ + Floating action button shown for the root view. + """ + + return self.__root_view().floating_action_button + + @floating_action_button.setter + def floating_action_button(self, value: Optional[FloatingActionButton]): + self.__root_view().floating_action_button = value + + # floating_action_button_location + @property + def floating_action_button_location( + self, + ) -> Optional[Union[FloatingActionButtonLocation, OffsetValue]]: + """ + Placement of the floating action button in the root view. + """ + + return self.__root_view().floating_action_button_location + + @floating_action_button_location.setter + def floating_action_button_location( + self, value: Optional[Union[FloatingActionButtonLocation, OffsetValue]] + ): + self.__root_view().floating_action_button_location = value + + # horizontal_alignment + @property + def horizontal_alignment(self) -> CrossAxisAlignment: + """ + Horizontal alignment of root view child controls. + """ + + return self.__root_view().horizontal_alignment + + @horizontal_alignment.setter + def horizontal_alignment(self, value: CrossAxisAlignment): + self.__root_view().horizontal_alignment = value + + # vertical_alignment + @property + def vertical_alignment(self) -> MainAxisAlignment: + """ + Vertical alignment of root view child controls. + """ + + return self.__root_view().vertical_alignment + + @vertical_alignment.setter + def vertical_alignment(self, value: MainAxisAlignment): + self.__root_view().vertical_alignment = value + + # spacing + @property + def spacing(self) -> Number: + """ + Default spacing between root view child controls. + """ + + return self.__root_view().spacing + + @spacing.setter + def spacing(self, value: Number): + self.__root_view().spacing = value + + # padding + @property + def padding(self) -> Optional[PaddingValue]: + """ + Inner padding for the root view content. + """ + + return self.__root_view().padding + + @padding.setter + def padding(self, value: Optional[PaddingValue]): + self.__root_view().padding = value + + # bgcolor + @property + def bgcolor(self) -> Optional[ColorValue]: + """ + Background color of the root view. + """ + + return self.__root_view().bgcolor + + @bgcolor.setter + def bgcolor(self, value: Optional[ColorValue]): + self.__root_view().bgcolor = value + + # scroll + @property + def scroll(self) -> Optional[Union[ScrollMode, Scrollbar]]: + """ + Scroll behavior mode for root view content. + """ + + return self.__root_view().scroll + + @scroll.setter + def scroll(self, value: Optional[Union[ScrollMode, Scrollbar]]): + self.__root_view().scroll = value + + # auto_scroll + @property + def auto_scroll(self) -> bool: + """ + Whether root view should auto-scroll to the end on content changes. + """ + + return self.__root_view().auto_scroll + + @auto_scroll.setter + def auto_scroll(self, value: bool): + self.__root_view().auto_scroll = value + + # services + @property + def services(self) -> list[Service]: + """ + Service instances attached to the root view lifecycle. + """ + + return self.__root_view().services + + @services.setter + def services(self, value: list[Service]): + self.__root_view().services = value + + # Magic methods + def __contains__(self, item: Control) -> bool: + return item in self.controls + + +@control("Overlay") +class Overlay(BaseControl): + """ + Internal container for controls displayed above main page content. + """ + + controls: list[BaseControl] = field(default_factory=list) + """ + Overlay controls rendered in stacking order. + """ + + def init(self): + super().init() + self._internals["host_positioned"] = True + + +@control("Dialogs") +class Dialogs(BaseControl): + """ + Internal container tracking dialogs currently managed by a page. + """ + + controls: list[DialogControl] = field(default_factory=list) + """ + Stack of active dialog controls. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/blur.py b/sdk/python/packages/flet/src/flet/controls/blur.py new file mode 100644 index 0000000000..4a71b6861b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/blur.py @@ -0,0 +1,73 @@ +from enum import Enum +from typing import Optional, Union + +from flet.controls.base_control import value +from flet.controls.types import Number + +__all__ = [ + "Blur", + "BlurTileMode", + "BlurValue", +] + + +class BlurTileMode(Enum): + """ + Edge sampling mode used when applying blur beyond source bounds. + """ + + CLAMP = "clamp" + """ + Extends edge pixels outward. + """ + + DECAL = "decal" + """ + Treats samples outside bounds as transparent. + """ + + MIRROR = "mirror" + """ + Repeats the image by mirroring at each edge. + """ + + REPEATED = "repeated" + """ + Repeats the image pattern without mirroring. + """ + + +@value +class Blur: + """ + Gaussian blur configuration. + """ + + sigma_x: Number + """ + Horizontal Gaussian sigma. + + Larger values produce stronger blur along the X axis. + """ + + sigma_y: Number + """ + Vertical Gaussian sigma. + + Larger values produce stronger blur along the Y axis. + """ + + tile_mode: Optional[BlurTileMode] = None + """ + How sampling outside source bounds is handled during blur. + """ + + +BlurValue = Union[Number, tuple[Number, Number], Blur] +"""Type alias for blur configuration values. + +Represents blur as either: +- a single sigma value applied to both axes, +- a `(sigma_x, sigma_y)` tuple, +- or an explicit :class:`~flet.Blur` object. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/border.py b/sdk/python/packages/flet/src/flet/controls/border.py new file mode 100644 index 0000000000..c806a35b88 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/border.py @@ -0,0 +1,311 @@ +from dataclasses import field +from enum import Enum +from typing import Optional, Union + +from flet.controls.base_control import value +from flet.controls.colors import Colors +from flet.controls.types import ColorValue, Number + +__all__ = [ + "Border", + "BorderSide", + "BorderSideStrokeAlign", + "BorderSideStrokeAlignValue", + "BorderStyle", +] + + +class BorderSideStrokeAlign(float, Enum): + """ + Defines where a border stroke is painted relative to the border path. + """ + + INSIDE = -1.0 + """ + The border is drawn fully inside of the border path. + """ + + CENTER = 0.0 + """ + The border is drawn on the center of the border path, with half of the \ + `BorderSide.width` on the inside, and the other half on the outside of the path. + """ + + OUTSIDE = 1.0 + """ + The border is drawn on the outside of the border path. + """ + + +class BorderStyle(Enum): + """ + Defines how a border side is rendered. + """ + + NONE = "none" + """Skip (doesn't paint) the border.""" + + SOLID = "solid" + """Draw the border as a solid line.""" + + +@value +class BorderSide: + """ + Creates the side of a border. + + By default, the border is `1.0` logical pixels wide and solid black color. + + To omit (not show) a side, set :attr:`style` to :attr:`flet.BorderStyle.NONE`. + It skips painting the border, but the border still has a :attr:`width`. + """ + + width: Number = 1.0 + """ + The width of this side of the border, in logical pixels. + + Setting width to 0.0 will result in a hairline border. This means that + the border will have the width of one physical pixel. Hairline + rendering takes shortcuts when the path overlaps a pixel more than once. + This means that it will render faster than otherwise, but it might + double-hit pixels, giving it a slightly darker/lighter result. + + Tip: + To omit the border entirely, set the :attr:`style` + to :attr:`flet.BorderStyle.NONE`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + color: ColorValue = Colors.BLACK + """ + The color of this side of the border. + """ + + stroke_align: "BorderSideStrokeAlignValue" = BorderSideStrokeAlign.INSIDE + """ + The relative position of the stroke on a `BorderSide` in an `OutlinedBorder` or \ + `Border`. + """ + + style: BorderStyle = BorderStyle.SOLID + """ + The style of this side of the border. + """ + + def __post_init__(self): + if self.width < 0.0: + raise ValueError( + f"width must be greater than or equal to 0.0, got {self.width}" + ) + + # Properties + + @property + def stroke_inset(self): + """ + The amount of the stroke width that lies inside this `BorderSide`. + + For example, this will return the :attr:`width` for a :attr:`stroke_align` + of `-`1, half the :attr:`width` for a :attr:`stroke_align` of `0`, and `0` + for a `stroke_align` of `1`. + """ + return self.width * (1 - (1 + self.stroke_align) / 2) + + @property + def stroke_outset(self): + """ + The amount of the stroke width that lies outside this `BorderSide`. + + For example, this will return `0` for a :attr:`stroke_align` of `-1`, half the + :attr:`width` for a :attr:`stroke_align` of `0`, and the :attr:`width` + for a :attr:`stroke_align` of `1`. + """ + return self.width * (1 + self.stroke_align) / 2 + + @property + def stroke_offset(self): + """ + The offset of the stroke, taking into account the stroke alignment. + + For example, this will return the negative :attr:`width` of the stroke + for a :attr:`stroke_align` of -1, 0 for a :attr:`stroke_align` of 0, and the + :attr:`width` for a :attr:`stroke_align` of -1. + """ + return self.width * self.stroke_align + + # Instance Methods + + def copy( + self, + *, + width: Optional[Number] = None, + color: Optional[ColorValue] = None, + stroke_align: Optional["BorderSideStrokeAlignValue"] = None, + ) -> "BorderSide": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BorderSide( + width=width if width is not None else self.width, + color=color if color is not None else self.color, + stroke_align=stroke_align + if stroke_align is not None + else self.stroke_align, + ) + + # Static Methods + + @staticmethod + def none() -> "BorderSide": + """ + Creates a border side that is not rendered. + + Returns: + A hairline black :class:`~flet.BorderSide` with + :attr:`style` set to :attr:`flet.BorderStyle.NONE`. + """ + return BorderSide(width=0.0, style=BorderStyle.NONE) + + +@value +class Border: + """ + A border comprised of four sides: `top`, `right`, `bottom`, `left`. + + Each side of the border is an instance of + :class:`~flet.BorderSide`. + """ + + top: BorderSide = field(default_factory=lambda: BorderSide.none()) + """ + Top side of the border. + """ + + right: BorderSide = field(default_factory=lambda: BorderSide.none()) + """ + Right side of the border. + """ + + bottom: BorderSide = field(default_factory=lambda: BorderSide.none()) + """ + Bottom side of the border. + """ + + left: BorderSide = field(default_factory=lambda: BorderSide.none()) + """ + Left side of the border. + """ + + # Class Methods + + @classmethod + def all( + cls, + width: Optional[Number] = None, + color: Optional[ColorValue] = None, + side: Optional[BorderSide] = None, + ) -> "Border": + """ + Creates a border whose sides are all the same. + + If `side` is not `None`, it gets used and both `width` and `color` are ignored. + + Args: + width: The side width. Used only when `side` is `None`. + color: The side color. Used only when `side` is `None`. + side: The :class:`~flet.BorderSide` to apply to all sides. If set, + it has precedence over `width` and `color`. + + Returns: + A :class:`~flet.Border` with identical sides. + """ + if side is not None: + return Border(top=side, right=side, bottom=side, left=side) + bs = BorderSide(width or 1.0, color or Colors.BLACK) + return Border(left=bs, top=bs, right=bs, bottom=bs) + + @classmethod + def symmetric( + cls, + *, + vertical: Optional[BorderSide] = None, + horizontal: Optional[BorderSide] = None, + ) -> "Border": + """ + Creates a border with symmetrical vertical and horizontal sides. + + The `vertical` argument applies to the :attr:`left` and :attr:`right` sides, + and the `horizontal` argument applies to the :attr:`top` and :attr:`bottom` + sides. + + Args: + vertical: The side applied to the left and right. + horizontal: The side applied to the top and bottom. + + Returns: + A :class:`~flet.Border` with mirrored side pairs. + """ + if vertical is None: + vertical = BorderSide(width=0.0, style=BorderStyle.NONE) + if horizontal is None: + horizontal = BorderSide(width=0.0, style=BorderStyle.NONE) + return Border(left=horizontal, top=vertical, right=horizontal, bottom=vertical) + + @classmethod + def only( + cls, + *, + left: Optional[BorderSide] = None, + top: Optional[BorderSide] = None, + right: Optional[BorderSide] = None, + bottom: Optional[BorderSide] = None, + ) -> "Border": + """ + Creates a border with explicit sides. + + Args: + left: The left side. Defaults to no border. + top: The top side. Defaults to no border. + right: The right side. Defaults to no border. + bottom: The bottom side. Defaults to no border. + + Returns: + A :class:`~flet.Border` built from the provided sides. + """ + return Border( + left=left or BorderSide(width=0.0, style=BorderStyle.NONE), + top=top or BorderSide(width=0.0, style=BorderStyle.NONE), + right=right or BorderSide(width=0.0, style=BorderStyle.NONE), + bottom=bottom or BorderSide(width=0.0, style=BorderStyle.NONE), + ) + + # Instance Methods + + def copy( + self, + *, + left: Optional[BorderSide] = None, + top: Optional[BorderSide] = None, + right: Optional[BorderSide] = None, + bottom: Optional[BorderSide] = None, + ) -> "Border": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Border( + left=left if left is not None else self.left, + top=top if top is not None else self.top, + right=right if right is not None else self.right, + bottom=bottom if bottom is not None else self.bottom, + ) + + +BorderSideStrokeAlignValue = Union[BorderSideStrokeAlign, Number] +"""Type alias for border stroke alignment values. + +Represents stroke alignment as either: +- a :class:`~flet.BorderSideStrokeAlign` enum value, +- or a numeric alignment value. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/border_radius.py b/sdk/python/packages/flet/src/flet/controls/border_radius.py new file mode 100644 index 0000000000..b1333d4adc --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/border_radius.py @@ -0,0 +1,169 @@ +from typing import Optional, Union + +from flet.controls.base_control import value +from flet.controls.types import Number + +__all__ = [ + "BorderRadius", + "BorderRadiusValue", +] + + +@value +class BorderRadius: + """ + Corner radii for a rectangle, defined for all four corners. + """ + + top_left: Number + """ + Radius of the top left border corner. + """ + + top_right: Number + """ + Radius of the top right border corner. + """ + + bottom_left: Number + """ + Radius of the bottom left border corner. + """ + + bottom_right: Number + """ + Radius of the bottom right border corner. + """ + + # Class Methods + + @classmethod + def all(cls, value: Number) -> "BorderRadius": + """Creates a `BorderRadius` where all radii are `radius`.""" + return BorderRadius( + top_left=value, top_right=value, bottom_left=value, bottom_right=value + ) + + @classmethod + def horizontal(cls, *, left: Number = 0, right: Number = 0) -> "BorderRadius": + """ + Creates a horizontally symmetrical `BorderRadius` where the `left` and `right` \ + sides of the rectangle have the same radii. + """ + return BorderRadius( + top_left=left, top_right=right, bottom_left=left, bottom_right=right + ) + + @classmethod + def vertical(cls, *, top: Number = 0, bottom: Number = 0) -> "BorderRadius": + """ + Creates a vertically symmetric `BorderRadius` where the `top` and `bottom` \ + sides of the rectangle have the same radii. + """ + return BorderRadius( + top_left=top, top_right=top, bottom_left=bottom, bottom_right=bottom + ) + + @classmethod + def only( + cls, + *, + top_left: Number = 0, + top_right: Number = 0, + bottom_left: Number = 0, + bottom_right: Number = 0, + ) -> "BorderRadius": + """ + Creates a border radius with only the given values. + The other corners will be right angles. + """ + return BorderRadius( + top_left=top_left, + top_right=top_right, + bottom_left=bottom_left, + bottom_right=bottom_right, + ) + + # Instance Methods + + def copy( + self, + *, + top_left: Optional[Number] = None, + top_right: Optional[Number] = None, + bottom_left: Optional[Number] = None, + bottom_right: Optional[Number] = None, + ) -> "BorderRadius": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BorderRadius( + top_left=top_left if top_left is not None else self.top_left, + top_right=top_right if top_right is not None else self.top_right, + bottom_left=bottom_left if bottom_left is not None else self.bottom_left, + bottom_right=bottom_right + if bottom_right is not None + else self.bottom_right, + ) + + # Arithmetics + + def __add__(self, other: "BorderRadius") -> "BorderRadius": + """Adds two `BorderRadius` instances.""" + if not isinstance(other, BorderRadius): + return NotImplemented + return BorderRadius( + top_left=self.top_left + other.top_left, + top_right=self.top_right + other.top_right, + bottom_left=self.bottom_left + other.bottom_left, + bottom_right=self.bottom_right + other.bottom_right, + ) + + def __sub__(self, other: "BorderRadius") -> "BorderRadius": + """Subtracts one `BorderRadius` from another.""" + if not isinstance(other, BorderRadius): + return NotImplemented + return BorderRadius( + top_left=self.top_left - other.top_left, + top_right=self.top_right - other.top_right, + bottom_left=self.bottom_left - other.bottom_left, + bottom_right=self.bottom_right - other.bottom_right, + ) + + def __mul__(self, other: Union["BorderRadius", Number]) -> "BorderRadius": + """Multiplies `BorderRadius` by a scalar factor.""" + if isinstance(other, BorderRadius): + return BorderRadius( + top_left=self.top_left * other.top_left, + top_right=self.top_right * other.top_right, + bottom_left=self.bottom_left * other.bottom_left, + bottom_right=self.bottom_right * other.bottom_right, + ) + elif isinstance(other, Number): + return BorderRadius( + top_left=self.top_left * other, + top_right=self.top_right * other, + bottom_left=self.bottom_left * other, + bottom_right=self.bottom_right * other, + ) + return NotImplemented + + def __floordiv__(self, quotient: int) -> "BorderRadius": + """Performs floor division on `BorderRadius`.""" + if quotient == 0: + raise ZeroDivisionError("Division by zero is not possible") + return BorderRadius( + top_left=self.top_left // quotient, + top_right=self.top_right // quotient, + bottom_left=self.bottom_left // quotient, + bottom_right=self.bottom_right // quotient, + ) + + +BorderRadiusValue = Union[Number, BorderRadius] +"""Type alias for border radius values. + +Represents radius as either: +- a single numeric radius applied to all corners, +- or an explicit :class:`~flet.BorderRadius` configuration. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/box.py b/sdk/python/packages/flet/src/flet/controls/box.py new file mode 100644 index 0000000000..e69e5b2274 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/box.py @@ -0,0 +1,542 @@ +from dataclasses import field +from enum import Enum +from typing import Optional, Union + +from flet.controls.alignment import Alignment +from flet.controls.base_control import value +from flet.controls.border import Border +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.colors import Colors +from flet.controls.gradients import Gradient +from flet.controls.transform import Offset, OffsetValue +from flet.controls.types import ( + BlendMode, + ColorValue, + ImageRepeat, + Number, +) + +__all__ = [ + "BlurStyle", + "BoxConstraints", + "BoxDecoration", + "BoxFit", + "BoxShadow", + "BoxShadowValue", + "BoxShape", + "ColorFilter", + "DecorationImage", + "FilterQuality", +] + + +@value +class ColorFilter: + """ + Defines a color filter. + """ + + color: Optional[ColorValue] = None + """ + The color to use when applying the filter. + """ + + blend_mode: Optional[BlendMode] = None + """ + The blend mode to apply to the color filter. + """ + + def copy( + self, + *, + color: Optional[ColorValue] = None, + blend_mode: Optional[BlendMode] = None, + ) -> "ColorFilter": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ColorFilter( + color=color if color is not None else self.color, + blend_mode=blend_mode if blend_mode is not None else self.blend_mode, + ) + + +class FilterQuality(Enum): + """ + Quality levels for image sampling in Image and DecorationImage objects. + """ + + NONE = "none" + """ + The fastest filtering method, albeit also the lowest quality. + """ + + LOW = "low" + """ + Better quality than none, faster than medium. + """ + + MEDIUM = "medium" + """ + The best all around filtering method that is only worse than high at extremely \ + large scale factors. + """ + + HIGH = "high" + """ + Best possible quality when scaling up images by scale factors larger than 5-10x. + When images are scaled down, this can be worse than medium for scales smaller than + 0.5x, or when animating the scale factor. + This option is also the slowest. + """ + + +class BlurStyle(Enum): + """ + Styles to use for blurs + """ + + NORMAL = "normal" + """ + Fuzzy inside and outside. This is useful for painting shadows that are + offset from the shape that ostensibly is casting the shadow. + """ + + SOLID = "solid" + """ + Solid inside, fuzzy outside. This corresponds to drawing the shape, and + additionally drawing the blur. This can make objects appear brighter, + maybe even as if they were fluorescent. + """ + + OUTER = "outer" + """ + Nothing inside, fuzzy outside. This is useful for painting shadows for + partially transparent shapes, when they are painted separately but without + an offset, so that the shadow doesn't paint below the shape. + """ + + INNER = "inner" + """ + Fuzzy inside, nothing outside. This can make shapes appear to be lit from + within. + """ + + +@value +class BoxShadow: + """ + Configuration for a box's shadow. + """ + + spread_radius: Number = 0.0 + """ + The amount the box should be inflated prior to applying the blur. + """ + + blur_radius: Number = 0.0 + """ + The standard deviation of the Gaussian to convolve with the shadow's shape. + """ + + color: ColorValue = Colors.BLACK + """ + Color used to draw the shadow. + """ + + offset: OffsetValue = field(default_factory=lambda: Offset()) + """ + The displacement of the shadow from the casting element. Positive x/y offsets will \ + shift the shadow to the right and down, while negative offsets shift the shadow to \ + the left and up. The offsets are relative to the position of the element that is \ + casting it. + """ + + blur_style: BlurStyle = BlurStyle.NORMAL + """ + The blur style to apply to this shadow. + """ + + def copy( + self, + *, + spread_radius: Optional[Number] = None, + blur_radius: Optional[Number] = None, + color: Optional[ColorValue] = None, + offset: Optional[OffsetValue] = None, + blur_style: Optional[BlurStyle] = None, + ) -> "BoxShadow": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BoxShadow( + spread_radius=spread_radius + if spread_radius is not None + else self.spread_radius, + blur_radius=blur_radius if blur_radius is not None else self.blur_radius, + color=color if color is not None else self.color, + offset=offset if offset is not None else self.offset, + blur_style=blur_style if blur_style is not None else self.blur_style, + ) + + +BoxShadowValue = Union[BoxShadow, list[BoxShadow]] +"""Type alias for box shadow values. + +Represents shadows as either: +- a single :class:`~flet.BoxShadow` object, +- or a list of :class:`~flet.BoxShadow` objects. +""" + + +class BoxShape(Enum): + """ + The shape to use when rendering a :class:`~flet.Border` or \ + :class:`~flet.BoxDecoration`. + """ + + RECTANGLE = "rectangle" + """ + An axis-aligned rectangle, optionally with rounded corners. + + The amount of corner rounding, if any, is determined by the border radius + specified by classes such as :class:`~flet.BoxDecoration` or :class:`~flet.Border`. + The rectangle's edges match those of the box in which it is painted. + """ + + CIRCLE = "circle" + """ + A circle centered in the middle of the box into which the :class:`~flet.Border` or + :class:`~flet.BoxDecoration` is painted. The diameter of the circle is the shortest + dimension of the box, either the width or the height, such that the circle + touches the edges of the box. + """ + + +class BoxFit(Enum): + """ + How a box should be inscribed into another box. + """ + + NONE = "none" + """ + Align the source within the target box (by default, centering) and discard + any portions of the source that lie outside the box. + + The source image is not resized. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_none.png) + """ # noqa: E501 + + CONTAIN = "contain" + """ + As large as possible while still containing the source entirely within the + target box. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_contain.png) + """ # noqa: E501 + + COVER = "cover" + """ + As small as possible while still covering the entire target box. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_cover.png) + """ # noqa: E501 + + FILL = "fill" + """ + Fill the target box by distorting the source's aspect ratio. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_fill.png) + """ # noqa: E501 + + FIT_HEIGHT = "fitHeight" + """ + Make sure the full height of the source is shown, regardless of + whether this means the source overflows the target box horizontally. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_fitHeight.png) + """ # noqa: E501 + + FIT_WIDTH = "fitWidth" + """ + Make sure the full width of the source is shown, regardless of + whether this means the source overflows the target box vertically. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_fitWidth.png) + """ # noqa: E501 + + SCALE_DOWN = "scaleDown" + """ + Align the source within the target box (by default, centering) and, if + necessary, scale the source down to ensure that the source fits within the box. + + This is the same as :attr:`CONTAIN` if that would shrink the image, otherwise it + is the same as :attr:`NONE`. + + ![](https://flutter.github.io/assets-for-api-docs/assets/painting/box_fit_scaleDown.png) + """ # noqa: E501 + + +@value +class DecorationImage: + """ + An image for a box decoration. + """ + + src: Optional[Union[str, bytes]] = None + """ + The image source to paint. + + Accepts URLs, asset paths, base64 strings (with or without `data:` prefixes), + or raw bytes. + """ + + color_filter: Optional[ColorFilter] = None + """ + A color filter to apply to the image before painting it. + """ + + fit: Optional[BoxFit] = None + """ + How the image should be inscribed into the box. + """ + + alignment: Alignment = field(default_factory=lambda: Alignment.CENTER) + """ + The alignment of the image within its bounds. + """ + + repeat: ImageRepeat = ImageRepeat.NO_REPEAT + """ + How the image should be repeated to fill the box. + """ + + match_text_direction: bool = False + """ + Whether to paint the image in the direction of the TextDirection. + """ + + scale: Number = 1.0 + """ + The scale(image pixels to be shown per logical pixels) to apply to the image. + """ + + opacity: Number = 1.0 + """ + The opacity of the image. + """ + + filter_quality: FilterQuality = FilterQuality.MEDIUM + """ + The quality of the image filter. + """ + + invert_colors: bool = False + """ + Whether to invert the colors of the image while drawing. + """ + + anti_alias: bool = False + """ + Whether to paint the image in anti-aliased quality. + """ + + def copy( + self, + *, + src: Optional[Union[str, bytes]] = None, + color_filter: Optional[ColorFilter] = None, + fit: Optional[BoxFit] = None, + alignment: Optional[Alignment] = None, + repeat: Optional[ImageRepeat] = None, + match_text_direction: Optional[bool] = None, + scale: Optional[Number] = None, + opacity: Optional[Number] = None, + filter_quality: Optional[FilterQuality] = None, + invert_colors: Optional[bool] = None, + anti_alias: Optional[bool] = None, + ) -> "DecorationImage": + """ + Returns a copy of this object with the specified properties overridden. + """ + return DecorationImage( + src=src if src is not None else self.src, + color_filter=color_filter + if color_filter is not None + else self.color_filter, + fit=fit if fit is not None else self.fit, + alignment=alignment if alignment is not None else self.alignment, + repeat=repeat if repeat is not None else self.repeat, + match_text_direction=match_text_direction + if match_text_direction is not None + else self.match_text_direction, + scale=scale if scale is not None else self.scale, + opacity=opacity if opacity is not None else self.opacity, + filter_quality=filter_quality + if filter_quality is not None + else self.filter_quality, + invert_colors=invert_colors + if invert_colors is not None + else self.invert_colors, + anti_alias=anti_alias if anti_alias is not None else self.anti_alias, + ) + + +@value +class BoxDecoration: + """ + BoxDecoration provides a description of how to paint a box. + The box has a border, a body, and may cast a shadow. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color to fill in the background of the box. + """ + + image: Optional[DecorationImage] = None + """ + An image to paint above the background :attr:`bgcolor` or :attr:`gradient`. + """ + + border: Optional[Border] = None + """ + A border to draw above the background :attr:`bgcolor`, :attr:`gradient`, and \ + :attr:`image`. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The border radius of the box. + """ + + shadows: Optional[BoxShadowValue] = None + """ + A list of shadows cast by the box. + """ + + gradient: Optional[Gradient] = None + """ + A gradient to use when filling the box. + """ + + shape: BoxShape = BoxShape.RECTANGLE + """ + The shape to fill the :attr:`bgcolor`, :attr:`gradient`, and :attr:`image` + into and to cast as the :attr:`shadows`. + """ + + blend_mode: Optional[BlendMode] = None + """ + The blend mode to apply to the background :attr:`bgcolor` or :attr:`gradient`. + """ + + def __post_init__(self): + if not ( + self.blend_mode is None + or self.bgcolor is not None + or self.gradient is not None + ): + raise ValueError( + "blend_mode applies to the BoxDecoration's background color " + "or gradient, but no color or gradient was provided" + ) + if self.shape == BoxShape.CIRCLE and self.border_radius: + raise ValueError("border_radius must be None when shape is BoxShape.CIRCLE") + + def copy( + self, + *, + bgcolor: Optional[ColorValue] = None, + image: Optional[DecorationImage] = None, + border: Optional[Border] = None, + border_radius: Optional[BorderRadiusValue] = None, + shadows: Optional[BoxShadowValue] = None, + gradient: Optional[Gradient] = None, + shape: Optional[BoxShape] = None, + blend_mode: Optional[BlendMode] = None, + ): + """Returns a new `BoxDecoration` with selected fields overridden.""" + return BoxDecoration( + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + image=image if image is not None else self.image, + border=border if border is not None else self.border, + border_radius=border_radius + if border_radius is not None + else self.border_radius, + shadows=shadows if shadows is not None else self.shadows, + gradient=gradient if gradient is not None else self.gradient, + shape=shape if shape is not None else self.shape, + blend_mode=blend_mode if blend_mode is not None else self.blend_mode, + ) + + +@value +class BoxConstraints: + """ + Constraints that must be respected by a size of a box. + + A :class:`~flet.Size` respects a BoxConstraints if, and only if, + all of the following relations hold: + + min_width <= Size.width <= max_width + min_height <= Size.height <= max_height + + Read more about BoxConstraints + [here](https://api.flutter.dev/flutter/rendering/BoxConstraints-class.html). + """ + + min_width: Number = 0 + """ + The minimum width that satisfies the constraints, \ + such that `0.0 <= min_width <= max_width`. + """ + + min_height: Number = 0 + """ + The minimum height that satisfies the constraints, \ + such that `0.0 <= min_height <= max_height`. + """ + + max_width: Number = float("inf") + """ + The maximum width that satisfies the constraints, \ + such that `min_width <= max_width <= float("inf")`. + """ + + max_height: Number = float("inf") + """ + The maximum height that satisfies the constraints, \ + such that `min_height <= max_height <= float("inf")`. + """ + + def __post_init__(self): + if not (0 <= self.min_width <= self.max_width <= float("inf")): + raise ValueError( + "min_width and max_width must be between 0 and infinity " + "and min_width must be less than or equal to max_width" + ) + if not (0 <= self.min_height <= self.max_height <= float("inf")): + raise ValueError( + "min_height and max_height must be between 0 and infinity " + "and min_height must be less than or equal to max_height" + ) + + def copy( + self, + *, + min_width: Optional[Number] = None, + min_height: Optional[Number] = None, + max_width: Optional[Number] = None, + max_height: Optional[Number] = None, + ) -> "BoxConstraints": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BoxConstraints( + min_width=min_width if min_width is not None else self.min_width, + min_height=min_height if min_height is not None else self.min_height, + max_width=max_width if max_width is not None else self.max_width, + max_height=max_height if max_height is not None else self.max_height, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/buttons.py b/sdk/python/packages/flet/src/flet/controls/buttons.py new file mode 100644 index 0000000000..b4db55597d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/buttons.py @@ -0,0 +1,338 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import value +from flet.controls.border import BorderSide +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.control_state import ControlStateValue +from flet.controls.duration import DurationValue +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + MouseCursor, + Number, + VisualDensity, +) + +__all__ = [ + "BeveledRectangleBorder", + "ButtonStyle", + "CircleBorder", + "ContinuousRectangleBorder", + "OutlinedBorder", + "RoundedRectangleBorder", + "ShapeBorder", + "StadiumBorder", +] + + +@value +class ShapeBorder: + """ + Base class for shape outlines. Not intended to be used directly. + + See subclasses/implementations: + + - :class:`~flet.OutlinedBorder` + """ + + +@value +class OutlinedBorder(ShapeBorder): + """ + An abstract class that can be used to create custom borders. + + See subclasses/implementations: + + - :class:`~flet.BeveledRectangleBorder` + - :class:`~flet.ContinuousRectangleBorder` + - :class:`~flet.CircleBorder` + - :class:`~flet.RoundedRectangleBorder` + - :class:`~flet.StadiumBorder` + """ + + side: Optional[BorderSide] = None + """ + The border outline's color and weight. + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + + +@value +class StadiumBorder(OutlinedBorder): + """ + A border that looks like a stadium. + """ + + def __post_init__(self): + self._type = "stadium" + + def copy( + self, + *, + side: Optional[BorderSide] = None, + ) -> "StadiumBorder": + """ + Returns a copy of this object with the specified properties overridden. + """ + return StadiumBorder( + side=side if side is not None else self.side, + ) + + +@value +class RoundedRectangleBorder(OutlinedBorder): + """ + A border with rounded rectangle corners. + """ + + radius: Optional[BorderRadiusValue] = None + """ + The radius for each corner. + """ + + def __post_init__(self): + self._type = "roundedRectangle" + + def copy( + self, + *, + side: Optional[BorderSide] = None, + radius: Optional[BorderRadiusValue] = None, + ) -> "RoundedRectangleBorder": + """ + Returns a copy of this object with the specified properties overridden. + """ + return RoundedRectangleBorder( + side=side if side is not None else self.side, + radius=radius if radius is not None else self.radius, + ) + + +@value +class CircleBorder(OutlinedBorder): + """ + A border with a circle shape. + """ + + eccentricity: Number = 0.0 + + def __post_init__(self): + self._type = "circle" + + def copy( + self, + *, + side: Optional[BorderSide] = None, + eccentricity: Optional[Number] = None, + ) -> "CircleBorder": + """ + Returns a copy of this object with the specified properties overridden. + """ + return CircleBorder( + side=side if side is not None else self.side, + eccentricity=eccentricity + if eccentricity is not None + else self.eccentricity, + ) + + +@value +class BeveledRectangleBorder(RoundedRectangleBorder): + """ + A border with beveled rectangle corners. + """ + + def __post_init__(self): + self._type = "beveledRectangle" + + def copy( + self, + *, + side: Optional[BorderSide] = None, + radius: Optional[BorderRadiusValue] = None, + ) -> "BeveledRectangleBorder": + """ + Returns a copy of this object with the specified properties overridden. + """ + return BeveledRectangleBorder( + side=side if side is not None else self.side, + radius=radius if radius is not None else self.radius, + ) + + +@value +class ContinuousRectangleBorder(RoundedRectangleBorder): + """ + A border with continuous rectangle corners. + """ + + def __post_init__(self): + self._type = "continuousRectangle" + + def copy( + self, + *, + side: Optional[BorderSide] = None, + radius: Optional[BorderRadiusValue] = None, + ) -> "ContinuousRectangleBorder": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ContinuousRectangleBorder( + side=side if side is not None else self.side, + radius=radius if radius is not None else self.radius, + ) + + +@value +class ButtonStyle: + """ + Allows controlling all visual aspects of a button, such as shape, foreground, \ + background and shadow colors, content padding, border width and radius. + + Most of these style attributes could be configured for all or particular + :class:`~flet.ControlState` of a button, + such as `HOVERED`, `FOCUSED`, `DISABLED` and others. + """ + + color: Optional[ControlStateValue[ColorValue]] = None + """ + The color for the button's Text and Icon control descendants. + """ + + bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + The button's background fill color. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The highlight color that's typically used to indicate that the button is focused, \ + hovered, or pressed. + """ + + shadow_color: Optional[ControlStateValue[ColorValue]] = None + """ + The shadow color of the button's Material. + """ + + elevation: Optional[ControlStateValue[Optional[Number]]] = None + """ + The elevation of the button's Material. + """ + + animation_duration: Optional[DurationValue] = None + """ + Defines the duration in milliseconds of animated changes for shape and elevation. + """ + + padding: Optional[ControlStateValue[PaddingValue]] = None + """ + The padding between the button's boundary and its content. + """ + + side: Optional[ControlStateValue[BorderSide]] = None + """ + Defines the button's border outline. + """ + + shape: Optional[ControlStateValue[OutlinedBorder]] = None + """ + The shape of the button's underlying Material. + """ + + alignment: Optional[Alignment] = None + """ + The alignment of the button's content. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. + """ + + text_style: Optional[ControlStateValue[TextStyle]] = None + """ + The text style of the button's `Text` control descendants. + """ + + icon_size: Optional[ControlStateValue[Optional[Number]]] = None + """ + The icon's size inside of the button. + """ + + icon_color: Optional[ControlStateValue[ColorValue]] = None + """ + The icon's color inside the button. + + If not set or `None`, then the `color` will be used. + """ + + visual_density: Optional[VisualDensity] = None + """ + Defines how compact the button's layout will be. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + The cursor to be displayed when the mouse pointer enters or is hovering over the \ + button. + """ + + def copy( + self, + *, + color: Optional[ControlStateValue[ColorValue]] = None, + bgcolor: Optional[ControlStateValue[ColorValue]] = None, + overlay_color: Optional[ControlStateValue[ColorValue]] = None, + shadow_color: Optional[ControlStateValue[ColorValue]] = None, + elevation: Optional[ControlStateValue[Optional[Number]]] = None, + animation_duration: Optional[DurationValue] = None, + padding: Optional[ControlStateValue[PaddingValue]] = None, + side: Optional[ControlStateValue[BorderSide]] = None, + shape: Optional[ControlStateValue[OutlinedBorder]] = None, + alignment: Optional[Alignment] = None, + enable_feedback: Optional[bool] = None, + text_style: Optional[ControlStateValue[TextStyle]] = None, + icon_size: Optional[ControlStateValue[Optional[Number]]] = None, + icon_color: Optional[ControlStateValue[ColorValue]] = None, + visual_density: Optional[VisualDensity] = None, + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None, + ) -> "ButtonStyle": + """ + Returns a copy of this object with the specified properties overridden. + """ + return ButtonStyle( + color=color if color is not None else self.color, + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + overlay_color=overlay_color + if overlay_color is not None + else self.overlay_color, + shadow_color=shadow_color + if shadow_color is not None + else self.shadow_color, + elevation=elevation if elevation is not None else self.elevation, + animation_duration=animation_duration + if animation_duration is not None + else self.animation_duration, + padding=padding if padding is not None else self.padding, + side=side if side is not None else self.side, + shape=shape if shape is not None else self.shape, + alignment=alignment if alignment is not None else self.alignment, + enable_feedback=enable_feedback + if enable_feedback is not None + else self.enable_feedback, + text_style=text_style if text_style is not None else self.text_style, + icon_size=icon_size if icon_size is not None else self.icon_size, + icon_color=icon_color if icon_color is not None else self.icon_color, + visual_density=visual_density + if visual_density is not None + else self.visual_density, + mouse_cursor=mouse_cursor + if mouse_cursor is not None + else self.mouse_cursor, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/colors.py b/sdk/python/packages/flet/src/flet/controls/colors.py new file mode 100644 index 0000000000..fbddce30ca --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/colors.py @@ -0,0 +1,519 @@ +""" +Code to generate colors: +``` +$lines = Get-Content "colors.dart" + +$section = '' + +foreach($line in $lines) { + + if ($line.Contains("case `"")) { + $color = $line.Replace('case "', "").replace('":', "").trim() + $ucolor = $color.toUpper() + "$ucolor = `"$color`"" + } elseif ($line.Contains('Map _plainColors')) { + $section = 'plain' + } elseif ($line.Contains('Map _materialColors')) { + $section = 'primary' + } elseif ($line.Contains('Map _materialAccentColors')) + { + $section = 'accent' + } elseif ($line.startswith(' "')) { + $color = $line.split('"')[1] + $ucolor = $color.replace('deep', 'deep_') \ + .replace('light', 'light_') \ + .replace('grey', '_grey') \ + .replace('accent', '_accent') + $ucolor = $ucolor.upper() + "$ucolor = `"$color`"" + if ($section -eq 'primary') { + $shades = @(50, 100, 200, 300, 400, 500, 600, 700, 800, 900) + foreach($shade in $shades) { + "$($ucolor)_$shade = `"$($color)$shade`"" + } + } elseif ($section -eq 'accent') { + $shades = @(100, 200, 400, 700) + foreach($shade in $shades) { + "$($ucolor)_$shade = `"$($color)$shade`"" + } + } + } +} +``` + +--- + +Code to sort the members: +``` +s = sorted(Colors, key=lambda i: i.value) +for i in s: + print(f'{i.name} = "{i.value}"') +``` +""" + +import random +from enum import Enum +from typing import TYPE_CHECKING, Optional, Union + +from flet.utils.deprecated_enum import DeprecatedEnumMeta + +if TYPE_CHECKING: + from flet.controls.types import ColorValue + +__all__ = ["Colors"] + + +class Colors(str, Enum, metaclass=DeprecatedEnumMeta): + """ + Named Material colors. + """ + + def __eq__(self, other): + if isinstance(other, str): + return self.value.lower() == other.lower() + if isinstance(other, Enum): + return self.value.lower() == other.value.lower() + return NotImplemented + + def __hash__(self): + return hash(self.value.lower()) + + @staticmethod + def random( + exclude: Optional[list["Colors"]] = None, + weights: Optional[dict["Colors", int]] = None, + ) -> Optional["Colors"]: + """ + Selects a random color, with optional exclusions and weights. + + Args: + exclude: A list of Colors to exclude from the selection. + weights: A dictionary mapping color members to their respective weights for + weighted random selection. + + Returns: + A randomly selected color, or None if all members are excluded. + + Examples: + >>> Colors.random(exclude=[Colors.RED, Colors.GREEN]) + Colors.BLUE + """ + choices = list(Colors) + if exclude: + choices = [member for member in choices if member not in exclude] + if not choices: + return None + if weights: + weights_list = [weights.get(c, 1) for c in choices] + return random.choices(choices, weights=weights_list)[0] + return random.choice(choices) + + @staticmethod + def with_opacity(opacity: Union[int, float], color: "ColorValue") -> str: + """ + Returns a color with the given opacity. + + Args: + opacity: The opacity value between `0.0` and `1.0`. + color: The color to apply opacity to. + + Returns: + A string representing the color with opacity, in the format + `"color,opacity"`. + + Examples: + >>> Colors.with_opacity(0.5, Colors.RED) + 'red,0.5' + + Raises: + ValueError: If the opacity is not between `0` and `1` (inclusive). + """ + if not (0 <= opacity <= 1): + raise ValueError( + f"opacity must be between 0.0 and 1.0 inclusive, got {opacity}" + ) + color_str = color.value if isinstance(color, Enum) else color + return f"{color_str},{opacity}" + + PRIMARY = "primary" + ON_PRIMARY = "onprimary" + PRIMARY_CONTAINER = "primarycontainer" + ON_PRIMARY_CONTAINER = "onprimarycontainer" + PRIMARY_FIXED = "primaryfixed" + PRIMARY_FIXED_DIM = "primaryfixeddim" + ON_PRIMARY_FIXED = "onprimaryfixed" + ON_PRIMARY_FIXED_VARIANT = "onprimaryfixedvariant" + + SECONDARY = "secondary" + ON_SECONDARY = "onsecondary" + SECONDARY_CONTAINER = "secondarycontainer" + ON_SECONDARY_CONTAINER = "onsecondarycontainer" + SECONDARY_FIXED = "secondaryfixed" + SECONDARY_FIXED_DIM = "secondaryfixeddim" + ON_SECONDARY_FIXED = "onsecondaryfixed" + ON_SECONDARY_FIXED_VARIANT = "onsecondaryfixedvariant" + + TERTIARY = "tertiary" + ON_TERTIARY = "ontertiary" + TERTIARY_CONTAINER = "tertiarycontainer" + ON_TERTIARY_CONTAINER = "ontertiarycontainer" + TERTIARY_FIXED = "tertiaryfixed" + TERTIARY_FIXED_DIM = "tertiaryfixeddim" + ON_TERTIARY_FIXED = "ontertiaryfixed" + ON_TERTIARY_FIXED_VARIANT = "ontertiaryfixedvariant" + + ERROR = "error" + ON_ERROR = "onerror" + ERROR_CONTAINER = "errorcontainer" + ON_ERROR_CONTAINER = "onerrorcontainer" + + SURFACE = "surface" + ON_SURFACE = "onsurface" + ON_SURFACE_VARIANT = "onsurfacevariant" + SURFACE_TINT = "surfacetint" + SURFACE_DIM = "surfacedim" + SURFACE_BRIGHT = "surfacebright" + SURFACE_CONTAINER = "surfacecontainer" + SURFACE_CONTAINER_LOW = "surfacecontainerlow" + SURFACE_CONTAINER_LOWEST = "surfacecontainerlowest" + SURFACE_CONTAINER_HIGH = "surfacecontainerhigh" + SURFACE_CONTAINER_HIGHEST = "surfacecontainerhighest" + + OUTLINE = "outline" + OUTLINE_VARIANT = "outlinevariant" + SHADOW = "shadow" + SCRIM = "scrim" + INVERSE_SURFACE = "inversesurface" + ON_INVERSE_SURFACE = "oninversesurface" + INVERSE_PRIMARY = "inverseprimary" + + AMBER = "amber" + AMBER_100 = "amber100" + AMBER_200 = "amber200" + AMBER_300 = "amber300" + AMBER_400 = "amber400" + AMBER_50 = "amber50" + AMBER_500 = "amber500" + AMBER_600 = "amber600" + AMBER_700 = "amber700" + AMBER_800 = "amber800" + AMBER_900 = "amber900" + AMBER_ACCENT = "amberaccent" + AMBER_ACCENT_100 = "amberaccent100" + AMBER_ACCENT_200 = "amberaccent200" + AMBER_ACCENT_400 = "amberaccent400" + AMBER_ACCENT_700 = "amberaccent700" + BLACK = "black" + BLACK_12 = "black12" + BLACK_26 = "black26" + BLACK_38 = "black38" + BLACK_45 = "black45" + BLACK_54 = "black54" + BLACK_87 = "black87" + BLUE = "blue" + BLUE_100 = "blue100" + BLUE_200 = "blue200" + BLUE_300 = "blue300" + BLUE_400 = "blue400" + BLUE_50 = "blue50" + BLUE_500 = "blue500" + BLUE_600 = "blue600" + BLUE_700 = "blue700" + BLUE_800 = "blue800" + BLUE_900 = "blue900" + BLUE_ACCENT = "blueaccent" + BLUE_ACCENT_100 = "blueaccent100" + BLUE_ACCENT_200 = "blueaccent200" + BLUE_ACCENT_400 = "blueaccent400" + BLUE_ACCENT_700 = "blueaccent700" + BLUE_GREY = "bluegrey" + BLUE_GREY_100 = "bluegrey100" + BLUE_GREY_200 = "bluegrey200" + BLUE_GREY_300 = "bluegrey300" + BLUE_GREY_400 = "bluegrey400" + BLUE_GREY_50 = "bluegrey50" + BLUE_GREY_500 = "bluegrey500" + BLUE_GREY_600 = "bluegrey600" + BLUE_GREY_700 = "bluegrey700" + BLUE_GREY_800 = "bluegrey800" + BLUE_GREY_900 = "bluegrey900" + BROWN = "brown" + BROWN_100 = "brown100" + BROWN_200 = "brown200" + BROWN_300 = "brown300" + BROWN_400 = "brown400" + BROWN_50 = "brown50" + BROWN_500 = "brown500" + BROWN_600 = "brown600" + BROWN_700 = "brown700" + BROWN_800 = "brown800" + BROWN_900 = "brown900" + CYAN = "cyan" + CYAN_100 = "cyan100" + CYAN_200 = "cyan200" + CYAN_300 = "cyan300" + CYAN_400 = "cyan400" + CYAN_50 = "cyan50" + CYAN_500 = "cyan500" + CYAN_600 = "cyan600" + CYAN_700 = "cyan700" + CYAN_800 = "cyan800" + CYAN_900 = "cyan900" + CYAN_ACCENT = "cyanaccent" + CYAN_ACCENT_100 = "cyanaccent100" + CYAN_ACCENT_200 = "cyanaccent200" + CYAN_ACCENT_400 = "cyanaccent400" + CYAN_ACCENT_700 = "cyanaccent700" + DEEP_ORANGE = "deeporange" + DEEP_ORANGE_100 = "deeporange100" + DEEP_ORANGE_200 = "deeporange200" + DEEP_ORANGE_300 = "deeporange300" + DEEP_ORANGE_400 = "deeporange400" + DEEP_ORANGE_50 = "deeporange50" + DEEP_ORANGE_500 = "deeporange500" + DEEP_ORANGE_600 = "deeporange600" + DEEP_ORANGE_700 = "deeporange700" + DEEP_ORANGE_800 = "deeporange800" + DEEP_ORANGE_900 = "deeporange900" + DEEP_ORANGE_ACCENT = "deeporangeaccent" + DEEP_ORANGE_ACCENT_100 = "deeporangeaccent100" + DEEP_ORANGE_ACCENT_200 = "deeporangeaccent200" + DEEP_ORANGE_ACCENT_400 = "deeporangeaccent400" + DEEP_ORANGE_ACCENT_700 = "deeporangeaccent700" + DEEP_PURPLE = "deeppurple" + DEEP_PURPLE_100 = "deeppurple100" + DEEP_PURPLE_200 = "deeppurple200" + DEEP_PURPLE_300 = "deeppurple300" + DEEP_PURPLE_400 = "deeppurple400" + DEEP_PURPLE_50 = "deeppurple50" + DEEP_PURPLE_500 = "deeppurple500" + DEEP_PURPLE_600 = "deeppurple600" + DEEP_PURPLE_700 = "deeppurple700" + DEEP_PURPLE_800 = "deeppurple800" + DEEP_PURPLE_900 = "deeppurple900" + DEEP_PURPLE_ACCENT = "deeppurpleaccent" + DEEP_PURPLE_ACCENT_100 = "deeppurpleaccent100" + DEEP_PURPLE_ACCENT_200 = "deeppurpleaccent200" + DEEP_PURPLE_ACCENT_400 = "deeppurpleaccent400" + DEEP_PURPLE_ACCENT_700 = "deeppurpleaccent700" + GREEN = "green" + GREEN_100 = "green100" + GREEN_200 = "green200" + GREEN_300 = "green300" + GREEN_400 = "green400" + GREEN_50 = "green50" + GREEN_500 = "green500" + GREEN_600 = "green600" + GREEN_700 = "green700" + GREEN_800 = "green800" + GREEN_900 = "green900" + GREEN_ACCENT = "greenaccent" + GREEN_ACCENT_100 = "greenaccent100" + GREEN_ACCENT_200 = "greenaccent200" + GREEN_ACCENT_400 = "greenaccent400" + GREEN_ACCENT_700 = "greenaccent700" + GREY = "grey" + GREY_100 = "grey100" + GREY_200 = "grey200" + GREY_300 = "grey300" + GREY_400 = "grey400" + GREY_50 = "grey50" + GREY_500 = "grey500" + GREY_600 = "grey600" + GREY_700 = "grey700" + GREY_800 = "grey800" + GREY_900 = "grey900" + INDIGO = "indigo" + INDIGO_100 = "indigo100" + INDIGO_200 = "indigo200" + INDIGO_300 = "indigo300" + INDIGO_400 = "indigo400" + INDIGO_50 = "indigo50" + INDIGO_500 = "indigo500" + INDIGO_600 = "indigo600" + INDIGO_700 = "indigo700" + INDIGO_800 = "indigo800" + INDIGO_900 = "indigo900" + INDIGO_ACCENT = "indigoaccent" + INDIGO_ACCENT_100 = "indigoaccent100" + INDIGO_ACCENT_200 = "indigoaccent200" + INDIGO_ACCENT_400 = "indigoaccent400" + INDIGO_ACCENT_700 = "indigoaccent700" + LIGHT_BLUE = "lightblue" + LIGHT_BLUE_100 = "lightblue100" + LIGHT_BLUE_200 = "lightblue200" + LIGHT_BLUE_300 = "lightblue300" + LIGHT_BLUE_400 = "lightblue400" + LIGHT_BLUE_50 = "lightblue50" + LIGHT_BLUE_500 = "lightblue500" + LIGHT_BLUE_600 = "lightblue600" + LIGHT_BLUE_700 = "lightblue700" + LIGHT_BLUE_800 = "lightblue800" + LIGHT_BLUE_900 = "lightblue900" + LIGHT_BLUE_ACCENT = "lightblueaccent" + LIGHT_BLUE_ACCENT_100 = "lightblueaccent100" + LIGHT_BLUE_ACCENT_200 = "lightblueaccent200" + LIGHT_BLUE_ACCENT_400 = "lightblueaccent400" + LIGHT_BLUE_ACCENT_700 = "lightblueaccent700" + LIGHT_GREEN = "lightgreen" + LIGHT_GREEN_100 = "lightgreen100" + LIGHT_GREEN_200 = "lightgreen200" + LIGHT_GREEN_300 = "lightgreen300" + LIGHT_GREEN_400 = "lightgreen400" + LIGHT_GREEN_50 = "lightgreen50" + LIGHT_GREEN_500 = "lightgreen500" + LIGHT_GREEN_600 = "lightgreen600" + LIGHT_GREEN_700 = "lightgreen700" + LIGHT_GREEN_800 = "lightgreen800" + LIGHT_GREEN_900 = "lightgreen900" + LIGHT_GREEN_ACCENT = "lightgreenaccent" + LIGHT_GREEN_ACCENT_100 = "lightgreenaccent100" + LIGHT_GREEN_ACCENT_200 = "lightgreenaccent200" + LIGHT_GREEN_ACCENT_400 = "lightgreenaccent400" + LIGHT_GREEN_ACCENT_700 = "lightgreenaccent700" + LIME = "lime" + LIME_100 = "lime100" + LIME_200 = "lime200" + LIME_300 = "lime300" + LIME_400 = "lime400" + LIME_50 = "lime50" + LIME_500 = "lime500" + LIME_600 = "lime600" + LIME_700 = "lime700" + LIME_800 = "lime800" + LIME_900 = "lime900" + LIME_ACCENT = "limeaccent" + LIME_ACCENT_100 = "limeaccent100" + LIME_ACCENT_200 = "limeaccent200" + LIME_ACCENT_400 = "limeaccent400" + LIME_ACCENT_700 = "limeaccent700" + ORANGE = "orange" + ORANGE_100 = "orange100" + ORANGE_200 = "orange200" + ORANGE_300 = "orange300" + ORANGE_400 = "orange400" + ORANGE_50 = "orange50" + ORANGE_500 = "orange500" + ORANGE_600 = "orange600" + ORANGE_700 = "orange700" + ORANGE_800 = "orange800" + ORANGE_900 = "orange900" + ORANGE_ACCENT = "orangeaccent" + ORANGE_ACCENT_100 = "orangeaccent100" + ORANGE_ACCENT_200 = "orangeaccent200" + ORANGE_ACCENT_400 = "orangeaccent400" + ORANGE_ACCENT_700 = "orangeaccent700" + PINK = "pink" + PINK_100 = "pink100" + PINK_200 = "pink200" + PINK_300 = "pink300" + PINK_400 = "pink400" + PINK_50 = "pink50" + PINK_500 = "pink500" + PINK_600 = "pink600" + PINK_700 = "pink700" + PINK_800 = "pink800" + PINK_900 = "pink900" + PINK_ACCENT = "pinkaccent" + PINK_ACCENT_100 = "pinkaccent100" + PINK_ACCENT_200 = "pinkaccent200" + PINK_ACCENT_400 = "pinkaccent400" + PINK_ACCENT_700 = "pinkaccent700" + PURPLE = "purple" + PURPLE_100 = "purple100" + PURPLE_200 = "purple200" + PURPLE_300 = "purple300" + PURPLE_400 = "purple400" + PURPLE_50 = "purple50" + PURPLE_500 = "purple500" + PURPLE_600 = "purple600" + PURPLE_700 = "purple700" + PURPLE_800 = "purple800" + PURPLE_900 = "purple900" + PURPLE_ACCENT = "purpleaccent" + PURPLE_ACCENT_100 = "purpleaccent100" + PURPLE_ACCENT_200 = "purpleaccent200" + PURPLE_ACCENT_400 = "purpleaccent400" + PURPLE_ACCENT_700 = "purpleaccent700" + RED = "red" + RED_100 = "red100" + RED_200 = "red200" + RED_300 = "red300" + RED_400 = "red400" + RED_50 = "red50" + RED_500 = "red500" + RED_600 = "red600" + RED_700 = "red700" + RED_800 = "red800" + RED_900 = "red900" + RED_ACCENT = "redaccent" + RED_ACCENT_100 = "redaccent100" + RED_ACCENT_200 = "redaccent200" + RED_ACCENT_400 = "redaccent400" + RED_ACCENT_700 = "redaccent700" + TEAL = "teal" + TEAL_100 = "teal100" + TEAL_200 = "teal200" + TEAL_300 = "teal300" + TEAL_400 = "teal400" + TEAL_50 = "teal50" + TEAL_500 = "teal500" + TEAL_600 = "teal600" + TEAL_700 = "teal700" + TEAL_800 = "teal800" + TEAL_900 = "teal900" + TEAL_ACCENT = "tealaccent" + TEAL_ACCENT_100 = "tealaccent100" + TEAL_ACCENT_200 = "tealaccent200" + TEAL_ACCENT_400 = "tealaccent400" + TEAL_ACCENT_700 = "tealaccent700" + TRANSPARENT = "transparent" + WHITE = "white" + WHITE_10 = "white10" + WHITE_12 = "white12" + WHITE_24 = "white24" + WHITE_30 = "white30" + WHITE_38 = "white38" + WHITE_54 = "white54" + WHITE_60 = "white60" + WHITE_70 = "white70" + YELLOW = "yellow" + YELLOW_100 = "yellow100" + YELLOW_200 = "yellow200" + YELLOW_300 = "yellow300" + YELLOW_400 = "yellow400" + YELLOW_50 = "yellow50" + YELLOW_500 = "yellow500" + YELLOW_600 = "yellow600" + YELLOW_700 = "yellow700" + YELLOW_800 = "yellow800" + YELLOW_900 = "yellow900" + YELLOW_ACCENT = "yellowaccent" + YELLOW_ACCENT_100 = "yellowaccent100" + YELLOW_ACCENT_200 = "yellowaccent200" + YELLOW_ACCENT_400 = "yellowaccent400" + YELLOW_ACCENT_700 = "yellowaccent700" + + +# TODO - remove in Flet 1.0 +_DEPRECATED_COLOR_ALIASES = { + "BLACK12": ("BLACK_12", "Use Colors.BLACK_12 instead."), + "BLACK26": ("BLACK_26", "Use Colors.BLACK_26 instead."), + "BLACK38": ("BLACK_38", "Use Colors.BLACK_38 instead."), + "BLACK45": ("BLACK_45", "Use Colors.BLACK_45 instead."), + "BLACK54": ("BLACK_54", "Use Colors.BLACK_54 instead."), + "BLACK87": ("BLACK_87", "Use Colors.BLACK_87 instead."), + "WHITE10": ("WHITE_10", "Use Colors.WHITE_10 instead."), + "WHITE12": ("WHITE_12", "Use Colors.WHITE_12 instead."), + "WHITE24": ("WHITE_24", "Use Colors.WHITE_24 instead."), + "WHITE30": ("WHITE_30", "Use Colors.WHITE_30 instead."), + "WHITE38": ("WHITE_38", "Use Colors.WHITE_38 instead."), + "WHITE54": ("WHITE_54", "Use Colors.WHITE_54 instead."), + "WHITE60": ("WHITE_60", "Use Colors.WHITE_60 instead."), + "WHITE70": ("WHITE_70", "Use Colors.WHITE_70 instead."), +} + +Colors._deprecated_members_ = _DEPRECATED_COLOR_ALIASES + +for alias_name, (target_name, _) in _DEPRECATED_COLOR_ALIASES.items(): + Colors._member_map_[alias_name] = getattr(Colors, target_name) diff --git a/sdk/python/packages/flet/src/flet/controls/context.py b/sdk/python/packages/flet/src/flet/controls/context.py new file mode 100644 index 0000000000..11a263da5f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/context.py @@ -0,0 +1,185 @@ +from contextvars import ContextVar +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from flet.controls.page import Page + + +class Context: + """ + Manages the context for Flet controls, including page reference and auto-update \ + behavior. + + Context instance is accessed via :data:`flet.context`. + """ + + def __init__(self) -> None: + self.__components_mode = False + + @property + def page(self) -> "Page": + """ + Returns the current :class:`~flet.Page` associated with the context. + + Example: + ```python + # take page width anywhere in the app + width = ft.context.page.width + ``` + + Returns: + The current page. + + Raises: + RuntimeError: If the property is accessed outside a running Flet app. + """ + page = _context_page.get() + if page is None: + raise RuntimeError( + "The context is not associated with any page. " + "Make sure you are accessing ft.context.page " + "inside a Flet app callback." + ) + return page + + def enable_auto_update(self): + """ + Enables auto-update behavior for the current context. + + Example: + ```python + import flet as ft + + # disable auto-update globally for the app + ft.context.disable_auto_update() + + + def main(page: ft.Page): + # enable auto-update just inside main + ft.context.enable_auto_update() + + page.controls.append(ft.Text("Hello, world!")) + # page.update() - we don't need to call it explicitly + + + ft.run(main) + ``` + """ + _update_behavior_context_var.get()._auto_update_enabled = True + + def disable_auto_update(self): + """ + Disables auto-update behavior for the current context. + + Example: + ```python + import flet as ft + + + def main(page: ft.Page): + def button_click(): + ft.context.disable_auto_update() + b.content = "Button clicked!" + # update just the button + b.update() + + page.controls.append(ft.Text("This won't appear")) + # no page.update() will be called here + + page.controls.append(b := ft.Button("Action!", on_click=button_click)) + # page.update() - auto-update is enabled by default + + + ft.run(main) + ``` + """ + _update_behavior_context_var.get()._auto_update_enabled = False + + def enable_components_mode(self): + """ + Enables components mode in the current context. + """ + self.__components_mode = True + + def disable_components_mode(self): + """ + Disables components mode in the current context. + """ + self.__components_mode = False + + def is_components_mode(self) -> bool: + """ + Returns whether the current context is in components mode. + + Returns: + `True` if in components mode, `False` otherwise. + """ + return self.__components_mode + + def mark_update_called(self): + """ + Marks that `.update()` was explicitly called during the current handler. + """ + _update_behavior_context_var.get()._update_called = True + + def was_update_called(self) -> bool: + """ + Returns whether `.update()` was explicitly called during the current handler. + + Returns: + `True` if `.update()` was called, `False` otherwise. + """ + return _update_behavior_context_var.get()._update_called + + def reset_update_called(self): + """ + Resets the update-called flag for the current context. + """ + _update_behavior_context_var.get()._update_called = False + + def auto_update_enabled(self) -> bool: + """ + Returns whether auto-update is enabled in the current context. + + Returns: + `True` if auto-update is enabled, `False` otherwise. + """ + return ( + not self.__components_mode + and _update_behavior_context_var.get()._auto_update_enabled + ) + + def reset_auto_update(self): + """ + Copies the parent auto-update state into the current context. + """ + current = _update_behavior_context_var.get() + new = UpdateBehavior() + new._auto_update_enabled = current._auto_update_enabled + _update_behavior_context_var.set(new) + + +class UpdateBehavior: + """ + Internal class used by the Context API to manage auto-update behavior. + + An instance of UpdateBehavior is stored in a context variable and tracks + whether automatic updates are enabled for the current context. The Context + class interacts with UpdateBehavior to enable, disable, and query the + auto-update state. + """ + + _auto_update_enabled: bool = True + _update_called: bool = False + + +_context_page = ContextVar("flet_session_page", default=None) + +_update_behavior_context_var = ContextVar("update_behavior", default=UpdateBehavior()) # noqa: B039 + +context = Context() +"""Global context object for the running Flet app. + +Use :data:`flet.context` to access the current page and control +auto-update behavior inside callbacks. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/control.py b/sdk/python/packages/flet/src/flet/controls/control.py new file mode 100644 index 0000000000..66f56eb413 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/control.py @@ -0,0 +1,142 @@ +from dataclasses import dataclass +from typing import Annotated, Optional, Union + +from flet.controls.base_control import BaseControl +from flet.controls.material.badge import BadgeValue +from flet.controls.material.tooltip import TooltipValue +from flet.controls.types import Number, ResponsiveNumber +from flet.utils.validation import V + +__all__ = ["Control"] + + +@dataclass(kw_only=True) +class Control(BaseControl): + """ + Base class for controls. + + Not meant to be used directly. + """ + + expand: Annotated[ + Optional[Union[bool, int]], + V.instance_of((bool, int)), + ] = None + """ + Specifies whether/how this control should expand to fill available space in its \ + parent layout. + + More information + [here](https://flet.dev/docs/cookbook/expanding-controls/#expand). + + Note: + Has effect only if the direct parent of this control is one of the following + controls, or their subclasses: :class:`~flet.Column`, :class:`~flet.Row`, + :class:`~flet.View`, :class:`~flet.Page`. + + Raises: + ValueError: If it is not of type `bool` or `int`. + """ + + expand_loose: bool = False + """ + Allows the control to expand along the main axis if space is available, but does \ + not require it to fill all available space. + + More information + [here](https://flet.dev/docs/cookbook/expanding-controls/#expand_loose). + + Note: + If `expand_loose` is `True`, it will have effect only if: + + - `expand` is not `None` and + - the direct parent of this control is one of the following controls, or their + subclasses: :class:`~flet.Column`, :class:`~flet.Row`, :class:`~flet.View`, + :class:`~flet.Page`. + """ + + # todo: if dict, validate keys with those in parent (ResponsiveRow.breakpoints) + col: ResponsiveNumber = 12 + """ + If a parent of this control is a :class:`~flet.ResponsiveRow`, this property is \ + used to determine how many virtual columns of a screen this control will span. + + Can be a number or a dictionary configured to have a different value for specific + breakpoints, for example `col={"sm": 6}`. + + A value of `0` hides the control for that breakpoint, so it does not occupy any + columns in the parent :class:`~flet.ResponsiveRow`. + + This control spans the 12 virtual columns by default. + + | Breakpoint | Dimension | + |---|---| + | xs | <576px | + | sm | ≥576px | + | md | ≥768px | + | lg | ≥992px | + | xl | ≥1200px | + | xxl | ≥1400px | + """ + + opacity: Annotated[ + Number, + V.between(0.0, 1.0), + ] = 1.0 + """ + Defines the transparency of the control. + + Value ranges from `0.0` (completely transparent) to `1.0` (completely opaque + without any transparency). + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ + + tooltip: Optional[TooltipValue] = None + """ + The tooltip to show when this control is hovered over. + """ + + badge: Optional[BadgeValue] = None + """ + A badge to show on top of this control. + """ + + visible: bool = True + """ + Every control has `visible` property which is `True` by default - control is \ + rendered on the page. Setting `visible` to `False` completely prevents control \ + (and all its children if any) from rendering on a page canvas. Hidden controls \ + cannot be focused or selected with a keyboard or mouse and they do not emit any \ + events. + """ + + disabled: bool = False + """ + Every control has `disabled` property which is `False` by default - control and \ + all its children are enabled. + + Note: + The value of this property will be propagated down to all children controls + recursively. + + Example: + For example, if you have a form with multiple entry controls you can + disable them all together by disabling container: + + ```python + ft.Column( + disabled = True, + controls=[ + ft.TextField(), + ft.TextField() + ] + ) + ``` + """ + + rtl: bool = False + """ + Whether the text direction of the control should be right-to-left (RTL). + """ diff --git a/sdk/python/packages/flet/src/flet/controls/control_event.py b/sdk/python/packages/flet/src/flet/controls/control_event.py new file mode 100644 index 0000000000..940938e0c6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/control_event.py @@ -0,0 +1,155 @@ +import inspect +import sys +from dataclasses import InitVar, dataclass, field +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ForwardRef, + Generic, + Optional, + TypeVar, + Union, + get_args, + get_origin, +) + +from flet.utils.typing_utils import eval_type + +if TYPE_CHECKING: + from .base_control import BaseControl # noqa + from .page import Page + from .base_page import BasePage + + _BaseControlType = BaseControl +else: + _BaseControlType = Any + +__all__ = [ + "ControlEvent", + "ControlEventHandler", + "Event", + "EventControlType", + "EventHandler", + "get_event_field_type", +] + + +def get_event_field_type(control: Any, field_name: str): + """ + Resolve the concrete event payload type for an event-handler field. + + Inspects merged annotations across the control MRO and evaluates forward + references so runtime event objects can be created with the right type. + """ + frame = inspect.currentframe().f_back + localns = frame.f_globals.copy() + localns.update(frame.f_locals) + + merged_annotations = {} + annotation_modules = {} + + for cls in control.__class__.__mro__: + annotations = getattr(cls, "__annotations__", {}) + module = sys.modules.get(cls.__module__) + module_dict = module.__dict__ if module else {} + + for name, annotation in annotations.items(): + if get_origin(annotation) is InitVar or str(annotation).startswith( + "dataclasses.InitVar" + ): + continue # Skip InitVar + if name not in merged_annotations: + merged_annotations[name] = annotation + annotation_modules[name] = module_dict + + if field_name not in merged_annotations: + return None + + annotation = merged_annotations[field_name] + + globalns = {} + current_module = sys.modules.get(control.__class__.__module__) + if current_module: + globalns.update(current_module.__dict__) + + owner_module_dict = annotation_modules.get(field_name) + if owner_module_dict: + for key, value in owner_module_dict.items(): + globalns.setdefault(key, value) + + globalns.setdefault("__builtins__", __builtins__) + type_params = getattr(control.__class__, "__type_params__", ()) + + try: + # Resolve forward refs manually + if isinstance(annotation, ForwardRef): + annotation = eval_type( + annotation, globalns, localns, type_params=type_params + ) + + clbs = get_args(annotation) # callable(s) + clb = clbs[1] if len(clbs) > 2 else clbs[0] + event_type = get_args(clb)[0][0] + + if isinstance(event_type, ForwardRef): + event_type = eval_type( + event_type, globalns, localns, type_params=type_params + ) + + return event_type + except Exception as e: + raise RuntimeError(f"[resolve error] {field_name}: {e}") from e + + +EventControlType = TypeVar("EventControlType", bound=_BaseControlType) +"""Type variable bound to a control type for typed event payloads.""" + + +@dataclass +class Event(Generic[EventControlType]): + """ + Base event payload passed to control event handlers. + """ + + name: str + data: Optional[Any] = field(default=None, kw_only=True) + control: EventControlType = field(repr=False) + + @property + def page(self) -> Union["Page", "BasePage"]: + """ + Page that owns the event source control. + """ + if not self.control.page: + raise RuntimeError("event control is not attached to a page") + return self.control.page + + @property + def target(self) -> int: + """ + Internal id of the control that emitted this event. + """ + return self.control._i + + +EventType = TypeVar("EventType", bound=Event) + +ControlEventHandler = Union[Callable[[], Any], Callable[[Event[EventControlType]], Any]] +"""Type alias for typed control event callback handlers. + +Represents a callback that accepts either: +- no arguments, +- or a typed :class:`~flet.Event` for a specific control type. +""" + +EventHandler = Union[Callable[[], Any], Callable[[EventType], Any]] +"""Type alias for generic event callback handlers. + +Represents a callback that accepts either: +- no arguments, +- or an :class:`~flet.Event`-derived payload. +""" + +ControlEvent = Event[_BaseControlType] +"""Type alias for an event emitted by any base control.""" diff --git a/sdk/python/packages/flet/src/flet/controls/control_state.py b/sdk/python/packages/flet/src/flet/controls/control_state.py new file mode 100644 index 0000000000..7a9d59250b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/control_state.py @@ -0,0 +1,98 @@ +from enum import Enum +from typing import TypeVar, Union + +__all__ = ["ControlState", "ControlStateValue"] + + +class ControlState(Enum): + """ + Interactive states that some controls can take on when receiving input + from the user. + + States are defined by the Material 3 design + [specification](https://m3.material.io/foundations/interaction/states), + but are not limited to it. + + Not all states are always applicable to all controls. + """ + + HOVERED = "hovered" + """ + The state when the user drags their mouse cursor over the given control. + + See [material docs](https://material.io/design/interaction/states.html#hover). + """ + + FOCUSED = "focused" + """ + The state when the user navigates with the keyboard to a given control. + + This can also sometimes be triggered when a control is tapped. For example, + when a [`TextField`] is tapped, it becomes :attr:`FOCUSED`. + + See [material docs](https://material.io/design/interaction/states.html#focus). + """ + + PRESSED = "pressed" + """ + The state when the user is actively pressing down on the given control. + + See [material docs](https://material.io/design/interaction/states.html#pressed). + """ + + DRAGGED = "dragged" + """ + The state when this control is being dragged from one place to another by the user. + + See [material docs](https://material.io/design/interaction/states.html#dragged). + """ + + SELECTED = "selected" + """ + The state when this item has been selected. + + This applies to things that can be toggled (such as chips and checkboxes) + and things that are selected from a set of options (such as tabs and radio buttons). + + See [material docs](https://material.io/design/interaction/states.html#selected). + """ + + SCROLLED_UNDER = "scrolledUnder" + """ + The state when this control overlaps the content of a scrollable below. + + Used by :class:`~flet.AppBar` to indicate that the primary scrollable's + content has scrolled up and behind the app bar. + """ + + DISABLED = "disabled" + """ + The state when this control is disabled and cannot be interacted with. + + Disabled controls should not respond to hover, focus, press, or drag + interactions. + + See [material docs](https://material.io/design/interaction/states.html#disabled). + """ + + ERROR = "error" + """ + The state when the control has entered some form of invalid state. + + See [material docs](https://material.io/design/interaction/states.html#usage). + """ + + DEFAULT = "default" + """ + The default state. Will be used for undeclared states. + """ + + +T = TypeVar("T") +ControlStateValue = Union[T, dict[ControlState, T]] +"""Type alias for state-dependent control values. + +Represents either: +- a single value applied to all (supported) states, +- or a mapping from :class:`~flet.ControlState` to per-state values. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/core/__init__.py b/sdk/python/packages/flet/src/flet/controls/core/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/controls/core/animated_switcher.py b/sdk/python/packages/flet/src/flet/controls/core/animated_switcher.py new file mode 100644 index 0000000000..c55ab3c689 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/animated_switcher.py @@ -0,0 +1,81 @@ +from dataclasses import field +from enum import Enum +from typing import Annotated + +from flet.controls.animation import AnimationCurve +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.duration import Duration, DurationValue +from flet.controls.layout_control import LayoutControl +from flet.utils.validation import V + +__all__ = ["AnimatedSwitcher", "AnimatedSwitcherTransition"] + + +class AnimatedSwitcherTransition(Enum): + """ + Visual transition strategy used by :attr:`flet.AnimatedSwitcher.transition`. + + Controls how old and new content are animated while the switch occurs. + """ + + FADE = "fade" + """ + Cross-fades between outgoing and incoming content. + """ + + ROTATION = "rotation" + """ + Rotates content during the switch. + """ + + SCALE = "scale" + """ + Scales content during the switch. + """ + + +@control("AnimatedSwitcher") +class AnimatedSwitcher(LayoutControl): + """ + Used to switch between controls with an animation. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The content to display. + + When it changes, this switcher will animate the transition from the old/previous + `content` to the new one. + + Raises: + ValueError: If it is not visible. + """ + + duration: DurationValue = field(default_factory=lambda: Duration(seconds=1)) + """ + The duration of the transition from the old :attr:`content` to the new one. + """ + + reverse_duration: DurationValue = field(default_factory=lambda: Duration(seconds=1)) + """ + The duration of the transition from the new :attr:`content` to the old one. + """ + + switch_in_curve: AnimationCurve = AnimationCurve.LINEAR + """ + The animation curve to use when transitioning in a new :attr:`content`. + """ + + switch_out_curve: AnimationCurve = AnimationCurve.LINEAR + """ + The animation curve to use when transitioning an old :attr:`content` out. + """ + + transition: AnimatedSwitcherTransition = AnimatedSwitcherTransition.FADE + """ + An animation type to transition between new and old :attr:`content`. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/autofill_group.py b/sdk/python/packages/flet/src/flet/controls/core/autofill_group.py new file mode 100644 index 0000000000..61294fc7c9 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/autofill_group.py @@ -0,0 +1,795 @@ +from enum import Enum +from typing import Annotated + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.utils.validation import V + +__all__ = ["AutofillGroup", "AutofillGroupDisposeAction", "AutofillHint"] + + +class AutofillHint(Enum): + """ + Predefined autofill hint identifiers for text fields. + + Each enum value represents semantic input meaning (for example city, + email, or password) and is translated to platform-specific autofill + constants when available. On unsupported platforms, the raw hint string + value is used as-is. + """ + + ADDRESS_CITY = "addressCity" + """ + The input field expects an address locality (city/town). + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY). + * iOS: [addressCity](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + ADDRESS_CITY_AND_STATE = "addressCityAndState" + """ + The input field expects a city name combined with a state name. + + This hint will be translated to the below values on different platforms: + + * iOS: [addressCityAndState](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + ADDRESS_STATE = "addressState" + """ + The input field expects a region/state. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS_REGION](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS_REGION). + * iOS: [addressState](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + BIRTHDAY = "birthday" + """ + The input field expects a person's full birth date. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_BIRTH_DATE_FULL](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_BIRTH_DATE_FULL). + * web: ["bday"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + BIRTHDAY_DAY = "birthdayDay" + """ + The input field expects a person's birth day(of the month). + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_BIRTH_DATE_DAY](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_BIRTH_DATE_DAY). + * web: ["bday-day"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + BIRTHDAY_MONTH = "birthdayMonth" + """ + The input field expects a person's birth month. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_BIRTH_DATE_MONTH](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_BIRTH_DATE_MONTH). + * web: ["bday-month"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + BIRTHDAY_YEAR = "birthdayYear" + """ + The input field expects a person's birth year. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_BIRTH_DATE_YEAR](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_BIRTH_DATE_YEAR). + * web: ["bday-year"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + COUNTRY_CODE = "countryCode" + """ + The input field expects an [ISO 3166-1-alpha-2](https://www.iso.org/standard/63545.html) country code. + + This hint will be translated to the below values on different platforms: + + * web: ["country"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + COUNTRY_NAME = "countryName" + """ + The input field expects a country name. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY). + * iOS: [countryName](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["country-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate" + """ + The input field expects a credit card expiration date. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_CREDIT_CARD_NUMBER](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_CREDIT_CARD_NUMBER). + * web: ["cc-exp"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay" + """ + The input field expects a credit card expiration day. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth" + """ + The input field expects a credit card expiration month. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH). + * web: ["cc-exp-month"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear" + """ + The input field expects a credit card expiration year. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR). + * web: ["cc-exp-year"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_FAMILY_NAME = "creditCardFamilyName" + """ + The input field expects the holder's last/family name as given on a credit card. + + This hint will be translated to the below values on different platforms: + + * web: ["cc-family-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_GIVEN_NAME = "creditCardGivenName" + """ + The input field expects the holder's first/given name as given on a credit card. + + This hint will be translated to the below values on different platforms: + + * web: ["cc-given-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_MIDDLE_NAME = "creditCardMiddleName" + """ + The input field expects the holder's middle name as given on a credit + card. + + This hint will be translated to the below values on different platforms: + + * web: ["cc-additional-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_NAME = "creditCardName" + """ + The input field expects the holder's full name as given on a credit card. + + This hint will be translated to the below values on different platforms: + + * web: ["cc-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_NUMBER = "creditCardNumber" + """ + The input field expects a credit card number. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_CREDIT_CARD_NUMBER](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_CREDIT_CARD_NUMBER). + * iOS: [creditCardNumber](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["cc-number"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode" + """ + The input field expects a credit card security code. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE). + * web: ["cc-csc"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + CREDIT_CARD_TYPE = "creditCardType" + """ + The input field expects the type of a credit card, for example "Visa". + + This hint will be translated to the below values on different platforms: + + * web: ["cc-type"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + EMAIL = "email" + """ + The input field expects an email address. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_EMAIL_ADDRESS](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_EMAIL_ADDRESS). + * iOS: [emailAddress](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["email"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + FAMILY_NAME = "familyName" + """ + The input field expects a person's last/family name. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME_FAMILY](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME_FAMILY). + * iOS: [familyName](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["family-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + FULL_STREET_ADDRESS = "fullStreetAddress" + """ + The input field expects a street address that fully identifies a location. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS). + * iOS: [fullStreetAddress](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["street-address"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + GENDER = "gender" + """ + The input field expects a gender. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_GENDER](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_GENDER). + * web: ["sex"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + GIVEN_NAME = "givenName" + """ + The input field expects a person's first/given name. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME_GIVEN](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME_GIVEN). + * iOS: [givenName](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["given-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + IMPP = "impp" + """ + The input field expects a URL representing an instant messaging protocol + endpoint. + + This hint will be translated to the below values on different platforms: + + * web: ["impp"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + JOB_TITLE = "jobTitle" + """ + The input field expects a job title. + + This hint will be translated to the below values on different platforms: + + * iOS: [jobTitle](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["organization-title"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + LANGUAGE = "language" + """ + The input field expects the preferred language of the user. + + This hint will be translated to the below values on different platforms: + + * web: ["language"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + LOCATION = "location" + """ + The input field expects a location, such as a point of interest, an \ + address,or another way to identify a location. + + This hint will be translated to the below values on different platforms: + + * iOS: [location](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + MIDDLE_INITIAL = "middleInitial" + """ + The input field expects a person's middle initial. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + MIDDLE_NAME = "middleName" + """ + The input field expects a person's middle name. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME_MIDDLE](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME_MIDDLE). + * iOS: [middleName](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["additional-name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + NAME = "name" + """ + The input field expects a person's full name. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME). + * iOS: [name](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["name"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + NAME_PREFIX = "namePrefix" + """ + The input field expects a person's name prefix or title, such as "Dr.". + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME_PREFIX](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME_PREFIX). + * iOS: [namePrefix](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["honorific-prefix"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + NAME_SUFFIX = "nameSuffix" + """ + The input field expects a person's name suffix, such as "Jr.". + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PERSON_NAME_SUFFIX](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PERSON_NAME_SUFFIX). + * iOS: [nameSuffix](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["honorific-suffix"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + NEW_PASSWORD = "newPassword" + """ + The input field expects a newly created password for save/update. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_NEW_PASSWORD](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_NEW_PASSWORD). + * iOS: [newPassword](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["new-password"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + NEW_USERNAME = "newUsername" + """ + The input field expects a newly created username for save/update. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_NEW_USERNAME](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_NEW_USERNAME). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + NICKNAME = "nickname" + """ + The input field expects a nickname. + + This hint will be translated to the below values on different platforms: + + * iOS: [nickname](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["nickname"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + ONE_TIME_CODE = "oneTimeCode" + """ + The input field expects a SMS one-time code. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_SMS_OTP](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_SMS_OTP). + * iOS: [oneTimeCode](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["one-time-code"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + ORGANIZATION_NAME = "organizationName" + """ + The input field expects an organization name corresponding to the person, \ + address, or contact information in the other fields associated with this \ + field. + + This hint will be translated to the below values on different platforms: + + * iOS: [organizationName](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["organization"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + PASSWORD = "password" + """ + The input field expects a password. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PASSWORD](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PASSWORD). + * iOS: [password](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["current-password"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + PHOTO = "photo" + """ + The input field expects a photograph, icon, or other image corresponding \ + to the company, person, address, or contact information in the other \ + fields associated with this field. + + This hint will be translated to the below values on different platforms: + + * web: ["photo"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + POSTAL_ADDRESS = "postalAddress" + """ + The input field expects a postal address. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + POSTAL_ADDRESS_EXTENDED = "postalAddressExtended" + """ + The input field expects an auxiliary address details. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "postalAddressExtendedPostalCode" + """ + The input field expects an extended ZIP/POSTAL code. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + POSTAL_CODE = "postalCode" + """ + The input field expects a postal code. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_POSTAL_CODE](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_POSTAL_CODE). + * iOS: [postalCode](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["postal-code"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LEVEL1 = "streetAddressLevel1" + """ + The first administrative level in the address. + + This is typically the province in which the address is located. + In the United States, this would be the state. In Switzerland, the canton. + In the United Kingdom, the post town. + + This hint will be translated to the below values on different platforms: + + * web: ["address-level1"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LEVEL2 = "streetAddressLevel2" + """ + The second administrative level, in addresses with at least two of them. + In countries with two administrative levels, this would typically be the + city, town, village, or other locality in which the address is located. + + This hint will be translated to the below values on different platforms: + + * web: ["address-level2"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LEVEL3 = "streetAddressLevel3" + """ + The third administrative level, in addresses with at least three \ + administrative levels. + + This hint will be translated to the below values on different platforms: + + * web: ["address-level3"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LEVEL4 = "streetAddressLevel4" + """ + The finest-grained administrative level, in addresses which have four levels. + + This hint will be translated to the below values on different platforms: + + * web: ["address-level4"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LINE1 = "streetAddressLine1" + """ + The input field expects the first line of a street address. + + This hint will be translated to the below values on different platforms: + + * iOS: [streetAddressLine1](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["address-line1"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LINE2 = "streetAddressLine2" + """ + The input field expects the second line of a street address. + + This hint will be translated to the below values on different platforms: + + * iOS: [streetAddressLine2](https://developer.apple.com/documentation/uikit/uitextcontenttype). + As of iOS 14.2 this hint does not trigger autofill. + * web: ["address-line2"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + STREET_ADDRESS_LINE3 = "streetAddressLine3" + """ + The input field expects the third line of a street address. + + This hint will be translated to the below values on different platforms: + + * web: ["address-line3"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + SUB_LOCALITY = "subLocality" + """ + The input field expects a sublocality. + + This hint will be translated to the below values on different platforms: + + * iOS: [sublocality](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER = "telephoneNumber" + """ + The input field expects a telephone number. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PHONE_NUMBER](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PHONE_NUMBER). + * iOS: [telephoneNumber](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["tel"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_AREA_CODE = "telephoneNumberAreaCode" + """ + The input field expects a phone number's area code, with a \ + country-internal prefix applied if applicable. + + This hint will be translated to the below values on different platforms: + + * web: ["tel-area-code"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_COUNTRY_CODE = "telephoneNumberCountryCode" + """ + The input field expects a phone number's country code. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PHONE_COUNTRY_CODE](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PHONE_COUNTRY_CODE). + * web: ["tel-country-code"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_DEVICE = "telephoneNumberDevice" + """ + The input field expects the current device's phone number, usually for \ + Sign Up / OTP flows. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PHONE_NUMBER_DEVICE](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PHONE_NUMBER_DEVICE). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_EXTENSION = "telephoneNumberExtension" + """ + The input field expects a phone number's internal extension code. + + This hint will be translated to the below values on different platforms: + + * web: ["tel-extension"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_LOCAL = "telephoneNumberLocal" + """ + The input field expects a phone number without the country code and area \ + code components. + + This hint will be translated to the below values on different platforms: + + * web: ["tel-local"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_LOCAL_PREFIX = "telephoneNumberLocalPrefix" + """ + The input field expects the first part of the component of the telephone \ + number that follows the area code, when that component is split into two \ + components. + + This hint will be translated to the below values on different platforms: + + * web: ["tel-local-prefix"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_LOCAL_SUFFIX = "telephoneNumberLocalSuffix" + """ + The input field expects the second part of the component of the telephone + number that follows the area code, when that component is split into two + components. + + This hint will be translated to the below values on different platforms: + + * web: ["tel-local-suffix"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TELEPHONE_NUMBER_NATIONAL = "telephoneNumberNational" + """ + The input field expects a phone number without country code. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_PHONE_NATIONAL](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_PHONE_NATIONAL). + * web: ["tel-national"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TRANSACTION_AMOUNT = "transactionAmount" + """ + The amount that the user would like for the transaction \ + (e.g. when entering a bid or sale price). + + This hint will be translated to the below values on different platforms: + + * web: ["transaction-amount"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + TRANSACTION_CURRENCY = "transactionCurrency" + """ + The currency that the user would prefer the transaction to use, in \ + [ISO 4217 currency code](https://www.iso.org/iso-4217-currency-codes.html). + + This hint will be translated to the below values on different platforms: + + * web: ["transaction-currency"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + URL = "url" + """ + The input field expects a URL. + + This hint will be translated to the below values on different platforms: + + * iOS: [URL](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["url"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + USERNAME = "username" + """ + The input field expects a username or an account name. + + This hint will be translated to the below values on different platforms: + + * Android: [AUTOFILL_HINT_USERNAME](https://developer.android.com/reference/androidx/autofill/HintConstants#AUTOFILL_HINT_USERNAME). + * iOS: [username](https://developer.apple.com/documentation/uikit/uitextcontenttype). + * web: ["username"](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofilling-form-controls:-the-autocomplete-attribute). + * Otherwise, the hint string will be used as-is. + """ # noqa: E501 + + +class AutofillGroupDisposeAction(Enum): + """ + Predefined autofill context clean-up actions. + """ + + COMMIT = "commit" + """ + Destroys the current autofill context after informing the platform to save + the user input from it. + """ + + CANCEL = "cancel" + """ + Destroys the current autofill context without saving the user input. + """ + + +@control("AutofillGroup") +class AutofillGroup(Control): + """ + Used to group autofill controls together. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The content of this group. + + Raises: + ValueError: If it is not visible. + """ + + dispose_action: AutofillGroupDisposeAction = AutofillGroupDisposeAction.COMMIT + """ + The action to be run when this group is the topmost and it's being disposed, in \ + order to clean up the current autofill context. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/__init__.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/__init__.py new file mode 100644 index 0000000000..cc6a916541 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/__init__.py @@ -0,0 +1,33 @@ +from .arc import Arc +from .canvas import Canvas, CanvasResizeEvent +from .circle import Circle +from .color import Color +from .fill import Fill +from .image import Image +from .line import Line +from .oval import Oval +from .path import Path +from .points import PointMode, Points +from .rect import Rect +from .shadow import Shadow +from .shape import Shape +from .text import Text + +__all__ = [ + "Arc", + "Canvas", + "CanvasResizeEvent", + "Circle", + "Color", + "Fill", + "Image", + "Line", + "Oval", + "Path", + "PointMode", + "Points", + "Rect", + "Shadow", + "Shape", + "Text", +] diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/arc.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/arc.py new file mode 100644 index 0000000000..b08677adbc --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/arc.py @@ -0,0 +1,67 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.types import Number + +__all__ = ["Arc"] + + +@control("Arc") +class Arc(Shape): + """ + Draws an arc scaled to fit inside the given rectangle. + + It starts from :attr:`start_angle` radians around the oval up to + :attr:`start_angle` + + :attr:`sweep_angle` radians around the oval, with zero radians being the point on + the right hand side of the oval that crosses the horizontal line that + intersects the center of the rectangle and with positive angles going + clockwise around the oval. If :attr:`use_center` is `True`, the arc is closed back + to the center, forming a circle sector. Otherwise, the arc is not closed, + forming a circle segment. + + https://api.flutter.dev/flutter/dart-ui/Canvas/drawArc.html + """ + + x: Number + """ + The x-axis coordinate of the arc's top left point. + """ + + y: Number + """ + The y-axis coordinate of the arc's top left point. + """ + + width: Number = 0 + """ + The width of the rectangle containing the arc's oval. + """ + + height: Number = 0 + """ + The height of the rectangle containing the arc's oval. + """ + + start_angle: Number = 0 + """ + The starting angle in radians to draw arc from. + """ + + sweep_angle: Number = 0 + """ + The length of the arc in radians. + """ + + use_center: bool = False + """ + Whether this arc is closed back to the center, forming a circle sector. If not \ + closed (`False`), this arc forms a circle segment. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw an arc with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py new file mode 100644 index 0000000000..a06bdcad51 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/canvas.py @@ -0,0 +1,133 @@ +from dataclasses import dataclass, field +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import Event, EventHandler +from flet.controls.core.canvas.shape import Shape +from flet.controls.layout_control import LayoutControl +from flet.controls.types import Number + +__all__ = ["Canvas", "CanvasResizeEvent"] + + +@dataclass +class CanvasResizeEvent(Event["Canvas"]): + """ + Event emitted when a :class:`~flet.canvas.Canvas` reports a new rendered size. + + This event is delivered through :attr:`~flet.canvas.Canvas.on_resize` + and carries the latest measured dimensions in logical pixels. + """ + + width: float = field(metadata={"data_field": "w"}) + """ + New width of the canvas. + """ + + height: float = field(metadata={"data_field": "h"}) + """ + New height of the canvas. + """ + + +@control("Canvas") +class Canvas(LayoutControl): + """ + Canvas is a control for drawing arbitrary graphics using a set of primitives or \ + "shapes" such as line, arc, path and text. + + Example: + ```python + cv.Canvas( + width=160, + height=160, + shapes=[ + cv.Rect( + 0, + 0, + 160, + 160, + paint=ft.Paint( + color=ft.Colors.BLUE_100, + style=ft.PaintingStyle.FILL, + ), + ), + cv.Circle( + 80, + 80, + 50, + paint=ft.Paint( + color=ft.Colors.BLUE_400, + style=ft.PaintingStyle.FILL, + ), + ), + ], + ) + ``` + """ + + shapes: list[Shape] = field(default_factory=list) + """ + A list of shapes to draw on this canvas. + """ + + content: Optional[Control] = None + """ + The content of this canvas. + """ + + resize_interval: Number = 10 + """ + Sampling interval in milliseconds for `on_resize` event. + + Setting to `0` calls :attr:`on_resize` immediately + on every change. + """ + + on_resize: Optional[EventHandler[CanvasResizeEvent]] = None + """ + Called when the size of this canvas has changed. + """ + + def before_update(self): + super().before_update() + if self.expand: + if self.width is None: + self.width = float("inf") + if self.height is None: + self.height = float("inf") + + async def capture(self, pixel_ratio: Optional[Number] = None): + """ + Captures the current visual state of the canvas. + + The captured image is stored internally and will be rendered as a background + beneath all subsequently drawn shapes. + + Args: + pixel_ratio: + The pixel density multiplier to use when rendering the capture. + `1.0` means 1 device pixel per logical pixel (no scaling). + Values greater than `1.0` produce higher-resolution captures. + If `None`, the device's default pixel ratio is used. + """ + await self._invoke_method("capture", arguments={"pixel_ratio": pixel_ratio}) + + async def get_capture(self) -> bytes: + """ + Retrieves the most recent canvas capture as PNG bytes. + + Returns: + bytes: The captured image in PNG format, or an empty result + if no capture has been made. + """ + return await self._invoke_method("get_capture") + + async def clear_capture(self): + """ + Clears the previously captured canvas image. + + After clearing, no background will be rendered from a prior capture. + """ + await self._invoke_method("clear_capture") diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/circle.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/circle.py new file mode 100644 index 0000000000..585991a848 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/circle.py @@ -0,0 +1,35 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.types import Number + +__all__ = ["Circle"] + + +@control("Circle") +class Circle(Shape): + """ + Draws a circle. + """ + + x: Number + """ + The x-axis coordinate of the circle's center point. + """ + + y: Number + """ + The y-axis coordinate of the circle's center point. + """ + + radius: Number = 0 + """ + Circle's radius. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw a circle with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/color.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/color.py new file mode 100644 index 0000000000..5c33793de2 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/color.py @@ -0,0 +1,24 @@ +from flet.controls.base_control import control +from flet.controls.colors import Colors +from flet.controls.core.canvas.shape import Shape +from flet.controls.types import BlendMode, ColorValue + +__all__ = ["Color"] + + +@control("Color") +class Color(Shape): + """ + Paints the given `color` onto the canvas, applying the given `blend_mode`, with \ + the given color being the source and the background being the destination. + """ + + color: ColorValue = Colors.BLACK + """ + Color to paint onto the canvas. + """ + + blend_mode: BlendMode = BlendMode.SRC_OVER + """ + Blend mode to apply. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/fill.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/fill.py new file mode 100644 index 0000000000..88e759a91e --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/fill.py @@ -0,0 +1,22 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint + +__all__ = ["Fill"] + + +@control("Fill") +class Fill(Shape): + """ + Fills the canvas with the given :attr:`paint`. + + To fill the canvas with a solid color and blend mode, + consider :class:`~flet.canvas.Color` shape instead. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to fill the canvas with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/image.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/image.py new file mode 100644 index 0000000000..ea5e10c3ef --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/image.py @@ -0,0 +1,45 @@ +from typing import Optional, Union + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.types import Number + + +@control("Image") +class Image(Shape): + """ + Draws an image. + """ + + src: Optional[Union[str, bytes]] = None + """ + Draws an image from a source. + + Accepts URLs/paths, base64 strings, or raw bytes. + """ + + x: Optional[Number] = None + """ + The x-axis coordinate of the image's top-left corner. + """ + + y: Optional[Number] = None + """ + The y-axis coordinate of the image's top-left corner. + """ + + width: Optional[Number] = None + """ + The width of the rectangle to draw the image into. Use image width if None. + """ + + height: Optional[Number] = None + """ + The height of the rectangle to draw the image into. Use image height if None. + """ + + paint: Optional[Paint] = None + """ + A paint to composite the image into canvas. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py new file mode 100644 index 0000000000..46d02a9b89 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/line.py @@ -0,0 +1,44 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.types import Number + +__all__ = ["Line"] + + +@control("Line") +class Line(Shape): + """ + Draws a line between the given points using the given paint. + + Note: + The line is always rendered as a stroke, regardless of the value + of :attr:`paint`'s :attr:`~flet.Paint.style` property. + """ + + x1: Number + """ + The x-axis coordinate of the line's starting point. + """ + + y1: Number + """ + The y-axis coordinate of the line's starting point. + """ + + x2: Number + """ + The x-axis coordinate of the line's end point. + """ + + y2: Number + """ + The y-axis coordinate of the line's end point. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw a line with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py new file mode 100644 index 0000000000..4b7b0e151d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/oval.py @@ -0,0 +1,44 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.types import Number + +__all__ = ["Oval"] + + +@control("Oval") +class Oval(Shape): + """ + Draws an axis-aligned oval that fills the given axis-aligned rectangle with the \ + given :attr:`paint`. + + The :attr:`~flet.Paint.style` property of :attr:`paint` indicates + whether this oval is filled, stroked, or both. + """ + + x: Number + """ + The x-axis coordinate of the oval's top left point. + """ + + y: Number + """ + The y-axis coordinate of the oval's top left point. + """ + + width: Number = 0 + """ + The width of the rectangle containing the oval. + """ + + height: Number = 0 + """ + The height of the rectangle containing the oval. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw an oval with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/path.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/path.py new file mode 100644 index 0000000000..23188d9704 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/path.py @@ -0,0 +1,291 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.base_control import control, value +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint + +__all__ = ["Path"] + + +@control("Path") +class Path(Shape): + """ + Draws a path with given :attr:`elements` + with the given :attr:`paint`. + + Whether this shape is filled, stroked, or both, is controlled by `paint.style`. + If the path is filled, then sub-paths within it are implicitly closed + (see `Path.Close`). + """ + + @value(kw_only=True) + class PathElement: + """ + Base type for elements stored in `Path.elements`. + + Use concrete subclasses such as :class:`MoveTo`, + :class:`LineTo`, :class:`Arc`, and :class:`Close` + to build drawing commands in order. + """ + + _type: Optional[str] = field( + init=False, repr=False, compare=False, default=None + ) + """ + Internal element discriminator used during serialization. + """ + + elements: list[PathElement] = field(default_factory=list) + """ + The list of path elements. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw a path with. + """ + + @value + class MoveTo(PathElement): + """ + Starts a new sub-path at the given point (`x`,`y`). + """ + + x: float + y: float + + def __post_init__(self): + self._type = "MoveTo" + + @value + class LineTo(PathElement): + """ + Adds a straight line segment from the current point to the given point \ + (`x`,`y`). + """ + + x: float + y: float + + def __post_init__(self): + self._type = "LineTo" + + @value + class QuadraticTo(PathElement): + """ + Adds a bezier segment that curves from the current point to the given point \ + (`x`,`y`), using the control points (`cp1x`,`cp1y`) and the weight `w`. + """ + + cp1x: float + cp1y: float + x: float + y: float + w: float = 1 + """ + If the weight is greater than 1, then the curve is a hyperbola; if the weight \ + equals 1, it's a parabola; and if it is less than 1, it is an ellipse. + """ + + def __post_init__(self): + self._type = "QuadraticTo" + + @value + class CubicTo(PathElement): + """ + Adds a cubic bezier segment that curves from the current point to the given \ + point (`x`,`y`), using the control points (`cp1x`,`cp1y`) and (`cp2x`,`cp2y`). + """ + + cp1x: float + cp1y: float + cp2x: float + cp2y: float + x: float + y: float + + def __post_init__(self): + self._type = "CubicTo" + + @value + class SubPath(PathElement): + """ + Adds the sub-path described by `elements` to the given point (`x`,`y`). + """ + + elements: list["Path.PathElement"] + x: float + y: float + + def __post_init__(self): + self._type = "SubPath" + + @value + class Arc(PathElement): + """ + Adds a new sub-path with one arc segment that consists of the arc that follows \ + the edge of the oval bounded by the given rectangle with top left corner at \ + `x` and `y` and dimensions `width` and `height`, from `start_angle` radians \ + around the oval up to `start_angle` + `sweep_angle` radians around the oval, \ + with zero radians being the point on the right hand side of the oval that \ + crosses the horizontal line that intersects the center of the rectangle and \ + with positive angles going clockwise around the oval. + """ + + x: float + """ + Top-left corner `x` of the rectangle bounding the arc. + """ + + y: float + """ + Top-left corner `y` of the rectangle bounding the arc. + """ + + width: float + """ + Width of the rectangle bounding the arc. + """ + + height: float + """ + Height of the rectangle bounding the arc. + """ + + start_angle: float + """ + Starting angle in radians of the arc. + """ + + sweep_angle: float + """ + Sweep angle in radians from `start_angle`. + """ + + def __post_init__(self): + self._type = "Arc" + + @value + class ArcTo(PathElement): + """ + Appends up to four conic curves weighted to describe an oval of `radius` and \ + rotated by `rotation` (measured in degrees and clockwise). + + The first curve begins from the last point in the path and the last ends at `x` + and `y`. The curves follow a path in a direction determined by `clockwise` + (bool) and `large_arc` (bool) in such a way that the sweep angle is always less + than 360 degrees. + + A simple line is appended if either radius is zero or the last point in + the path (`x`,`y`). The radii are scaled to fit the last path point if both are + greater than zero but too small to describe an arc. + """ + + x: float + """ + Destination `x` coordinate of arc endpoint. + """ + + y: float + """ + Destination `y` coordinate of arc endpoint. + """ + + radius: float = 0 + """ + Radius of the arc. + """ + + rotation: float = 0 + """ + Rotation of the arc in degrees. + """ + + large_arc: bool = False + """ + Whether to use the large arc sweep. + """ + + clockwise: bool = True + """ + Whether the arc should be drawn clockwise. + """ + + def __post_init__(self): + self._type = "ArcTo" + + @value + class Oval(PathElement): + """ + Adds a new sub-path that consists of a curve that forms the ellipse that fills \ + the given rectangle. + """ + + x: float + """ + The x-axis coordinate of the top-left of the bounding rectangle. + """ + + y: float + """ + The y-axis coordinate of the top-left of the bounding rectangle. + """ + + width: float + """ + Width of the bounding rectangle. + """ + + height: float + """ + Height of the bounding rectangle. + """ + + def __post_init__(self): + self._type = "Oval" + + @value + class Rect(PathElement): + """ + Adds a rectangle as a new sub-path. + """ + + x: float + """ + The x-axis coordinate of the top-left of the rectangle. + """ + + y: float + """ + The y-axis coordinate of the top-left of the rectangle. + """ + + width: float + """ + Width of the rectangle. + """ + + height: float + """ + Height of the rectangle. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + Optional border radius to round rectangle corners. + """ + + def __post_init__(self): + self._type = "Rect" + + @value + class Close(PathElement): + """ + Closes the last sub-path, as if a straight line had been drawn from the \ + current point to the first point of the sub-path. + """ + + def __post_init__(self): + self._type = "Close" diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/points.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/points.py new file mode 100644 index 0000000000..f9d0b07a8a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/points.py @@ -0,0 +1,60 @@ +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.transform import OffsetValue + +__all__ = ["PointMode", "Points"] + + +class PointMode(Enum): + """ + Defines how a list of points is interpreted when drawing a set of points. + """ + + POINTS = "points" + """ + Draw each point separately. If the `Paint.stroke_cap` is `StrokeCap.ROUND`, then \ + each point is drawn as a circle with the diameter of the `Paint.stroke_width`, \ + filled as described by the `Paint` (ignoring `Paint.style`). Otherwise, each point \ + is drawn as an axis-aligned square with sides of length `Paint.stroke_width`, \ + filled as described by the `Paint` (ignoring `Paint.style`). + """ + + LINES = "lines" + """ + Draw each sequence of two points as a line segment. If the number of points is \ + odd, then the last point is ignored. The lines are stroked as described by the \ + `Paint` (ignoring `Paint.style`). + """ + + POLYGON = "polygon" + """ + Draw the entire sequence of point as one line. The lines are stroked as described \ + by the `Paint` (ignoring `Paint.style`). + """ + + +@control("Points") +class Points(Shape): + """ + Draws a sequence of points according to the given :attr:`point_mode`. + """ + + points: Optional[list[OffsetValue]] = None + """ + The list of offsets describing points. + """ + + point_mode: PointMode = PointMode.POINTS + """ + Defines how a list of points is interpreted when drawing a set of points. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw points with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/rect.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/rect.py new file mode 100644 index 0000000000..6714caec15 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/rect.py @@ -0,0 +1,48 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadius, BorderRadiusValue +from flet.controls.core.canvas.shape import Shape +from flet.controls.painting import Paint +from flet.controls.types import Number + +__all__ = ["Rect"] + + +@control("Rect") +class Rect(Shape): + """ + Draws a rectangle. + """ + + x: Number + """ + The x-axis coordinate of this rectangle's top left point. + """ + + y: Number + """ + The y-axis coordinate of this rectangle's top left point. + """ + + width: Number = 0 + """ + The width of this rectangle. + """ + + height: Number = 0 + """ + The height of this rectangle. + """ + + border_radius: BorderRadiusValue = field( + default_factory=lambda: BorderRadius.all(0) + ) + """ + The border radius of this rectangle. + """ + + paint: Paint = field(default_factory=lambda: Paint()) + """ + A style to draw this rectangle with. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/shadow.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/shadow.py new file mode 100644 index 0000000000..ce177c9fd8 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/shadow.py @@ -0,0 +1,41 @@ +from dataclasses import field + +from flet.controls.base_control import control +from flet.controls.colors import Colors +from flet.controls.core.canvas.path import Path +from flet.controls.core.canvas.shape import Shape +from flet.controls.types import ColorValue, Number + +__all__ = ["Shadow"] + + +@control("Shadow") +class Shadow(Shape): + """ + Draws a shadow for a :attr:`path` representing the given material \ + :attr:`elevation`. + + Note: + The :attr:`transparent_occluder` argument should + be `True` if the occluding object is not opaque. + """ + + path: list[Path.PathElement] = field(default_factory=list) + """ + The list of elements describing the path of this shape. + """ + + color: ColorValue = Colors.BLACK + """ + The shadow's color. + """ + + elevation: Number = 0 + """ + The shadow's elevation. + """ + + transparent_occluder: bool = False + """ + Whether the occluding object is transparent (not opaque). + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/shape.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/shape.py new file mode 100644 index 0000000000..8c4650bc11 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/shape.py @@ -0,0 +1,22 @@ +from flet.controls.base_control import BaseControl + +__all__ = ["Shape"] + + +class Shape(BaseControl): + """ + A base class for canvas shapes. + + See subclasses/implementations: + + - :class:`~flet.canvas.Arc` + - :class:`~flet.canvas.Circle` + - :class:`~flet.canvas.Color` + - :class:`~flet.canvas.Fill` + - :class:`~flet.canvas.Line` + - :class:`~flet.canvas.Oval` + - :class:`~flet.canvas.Path` + - :class:`~flet.canvas.Points` + - :class:`~flet.canvas.Rect` + - :class:`~flet.canvas.Text` + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/canvas/text.py b/sdk/python/packages/flet/src/flet/controls/core/canvas/text.py new file mode 100644 index 0000000000..1c32d636d4 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/canvas/text.py @@ -0,0 +1,80 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.core.canvas.shape import Shape +from flet.controls.core.text_span import TextSpan +from flet.controls.text_style import TextStyle +from flet.controls.types import Number, TextAlign + +__all__ = ["Text"] + + +@control("Text") +class Text(Shape): + """ + Draws :attr:`value` with :attr:`style` at the given (:attr:`x`, :attr:`y`) point. + """ + + x: Number + """ + The x-axis coordinate of the text's `alignment` point. + """ + + y: Number + """ + The y-axis coordinate of the text's `alignment` point. + """ + + value: Optional[str] = None + """ + The text to draw. + """ + + style: Optional[TextStyle] = None + """ + A text style to draw `text` and `spans` with. + """ + + spans: Optional[list[TextSpan]] = None + """ + The list of :class:`~flet.TextSpan` + objects to build a rich text paragraph. + """ + + alignment: Alignment = field(default_factory=lambda: Alignment.TOP_LEFT) + """ + A point within a text rectangle to determine its position and rotation center. + """ + + text_align: TextAlign = TextAlign.START + """ + Text horizontal align. + """ + + max_lines: Optional[int] = None + """ + The maximum number of lines painted. Lines beyond this number are silently \ + dropped. For example, if `max_lines = 1`, then only one line is rendered. + If `max_lines = None`, but `ellipsis != None`, then lines after the first one + that overflows the width constraints are dropped. + """ + + max_width: Optional[Number] = None + """ + The maximum width of the painted text. + + Defaults to `None` - infinity. + """ + + ellipsis: Optional[str] = None + """ + String used to ellipsize overflowing text. + """ + + rotate: Number = 0 + """ + The rotation of this text in radians. Text is rotated around the point determined \ + by `alignment`. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/column.py b/sdk/python/packages/flet/src/flet/controls/core/column.py new file mode 100644 index 0000000000..fa0625c324 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/column.py @@ -0,0 +1,88 @@ +from dataclasses import field + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.types import CrossAxisAlignment, MainAxisAlignment, Number + +__all__ = ["Column"] + + +@control("Column") +class Column(LayoutControl, ScrollableControl, AdaptiveControl): + """ + Arranges child controls vertically, optionally aligning and spacing them within \ + the available space. + + ```python + ft.Column( + width=220, + height=120, + spacing=12, + controls=[ + ft.Text("Daily planning", size=20, weight=ft.FontWeight.W_600), + ft.Text("Review pull requests"), + ft.Text("Ship release"), + ], + ) + ``` + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of controls to display. + """ + + alignment: MainAxisAlignment = MainAxisAlignment.START + """ + How the child Controls should be placed vertically. + """ + + horizontal_alignment: CrossAxisAlignment = CrossAxisAlignment.START + """ + Defines how the :attr:`controls` should be placed horizontally. + """ + + spacing: Number = 10 + """ + Spacing between the `controls`. + + It is applied only when :attr:`alignment` is + `MainAxisAlignment.START`, `MainAxisAlignment.END` or `MainAxisAlignment.CENTER`. + """ + + tight: bool = False + """ + Determines how vertical space is allocated. + + If `False` (default), children expand to fill the available vertical space. + If `True`, only the minimum vertical space required by the children is used. + """ + + wrap: bool = False + """ + Whether the :attr:`controls` should wrap into additional columns (runs) when they \ + don't fit in a single vertical column. + """ + + run_spacing: Number = 10 + """ + The spacing between runs when :attr:`wrap` is `True`. + """ + + run_alignment: MainAxisAlignment = MainAxisAlignment.START + """ + How the runs should be placed in the cross-axis when :attr:`wrap` + is `True`. + """ + + intrinsic_width: bool = False + """ + If `True`, the Column will be as wide as the widest child control. + """ + + def init(self): + super().init() + self._internals["host_expanded"] = True diff --git a/sdk/python/packages/flet/src/flet/controls/core/dismissible.py b/sdk/python/packages/flet/src/flet/controls/core/dismissible.py new file mode 100644 index 0000000000..24c9f06784 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/dismissible.py @@ -0,0 +1,209 @@ +from dataclasses import dataclass, field +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ( + ControlEventHandler, + Event, + EventHandler, +) +from flet.controls.duration import Duration, DurationValue +from flet.controls.layout_control import LayoutControl +from flet.controls.material.snack_bar import DismissDirection +from flet.controls.types import ( + Number, +) +from flet.utils.validation import V + +__all__ = ["Dismissible", "DismissibleDismissEvent", "DismissibleUpdateEvent"] + + +@dataclass +class DismissibleDismissEvent(Event["Dismissible"]): + """ + Event payload for dismissal confirmation and completion callbacks. + + Used by :attr:`~flet.Dismissible.on_confirm_dismiss` and + :attr:`~flet.Dismissible.on_dismiss`. + """ + + direction: DismissDirection + """ + Direction in which the control is being (or was) dismissed. + """ + + +@dataclass +class DismissibleUpdateEvent(Event["Dismissible"]): + """ + Event payload emitted while a dismiss gesture is in progress. + """ + + direction: DismissDirection + """ + Direction of the current drag gesture. + """ + + progress: float + """ + Drag progress from `0.0` to `1.0` relative to dismissal threshold. + """ + + reached: bool + """ + Whether the dismiss threshold is currently reached. + """ + + previous_reached: bool + """ + Whether threshold was reached on the previous update event. + """ + + +@control("Dismissible") +class Dismissible(LayoutControl, AdaptiveControl): + """ + A control that can be dismissed by dragging in the indicated \ + :attr:`dismiss_direction`. + When dragged or flung in the specified :attr:`dismiss_direction`, + its :attr:`content` smoothly slides out of view. + + After completing the sliding animation, if a :attr:`resize_duration` is provided, + this control further animates its height (or width, depending on what is + perpendicular to the :attr:`dismiss_direction`), gradually reducing it to zero + over the specified :attr:`resize_duration`. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The control that is being dismissed. + + Raises: + ValueError: If it is not visible. + """ + + background: Optional[Control] = None + """ + A control that is stacked behind the :attr:`content`. + + If :attr:`secondary_background` is also + specified, then this control only appears when the content has been dragged + down or to the right. + """ + + secondary_background: Optional[Control] = None + """ + A control that is stacked behind the :attr:`content` and is exposed when it has \ + been dragged up or to the left. + + Raises: + ValueError: If it is provided and visible + but the :attr:`background` is not provided and visible. + """ + + dismiss_direction: DismissDirection = DismissDirection.HORIZONTAL + """ + The direction in which the control can be dismissed. + """ + + dismiss_thresholds: dict[DismissDirection, Optional[Number]] = field( + default_factory=dict + ) + """ + The offset threshold the item has to be dragged in order to be considered as \ + dismissed. This is specified as a dictionary where the key is of type \ + :class:`~flet.DismissDirection` and the value is the threshold (a \ + fractional/decimal value between `0.0` and `1.0`, inclusive). + + Example: + ```python + ft.Dismissible( + # ... + dismiss_thresholds={ + ft.DismissDirection.VERTICAL: 0.1, + ft.DismissDirection.START_TO_END: 0.7 + } + ) + ``` + """ + + movement_duration: DurationValue = field( + default_factory=lambda: Duration(milliseconds=200) + ) + """ + The duration for :attr:`content` to dismiss or to come back to original position \ + if not dismissed. + """ + + resize_duration: DurationValue = field( + default_factory=lambda: Duration(milliseconds=300) + ) + """ + The amount of time the control will spend contracting before :attr:`on_dismiss` is \ + called. + """ + + cross_axis_end_offset: Number = 0.0 + """ + Specifies the end offset along the main axis once the :attr:`content` has been \ + dismissed. + + If set to a non-zero value, then this dismissible moves in cross direction + depending on whether it is positive or negative. + """ + + on_update: Optional[EventHandler[DismissibleUpdateEvent]] = None + """ + Called when this control has been dragged. + """ + + on_dismiss: Optional[EventHandler[DismissibleDismissEvent]] = None + """ + Called when this control has been dismissed, after finishing resizing. + """ + + on_confirm_dismiss: Optional[EventHandler[DismissibleDismissEvent]] = None + """ + Gives the app an opportunity to confirm or veto a pending dismissal. + This dismissible cannot be dragged again until this pending dismissal is resolved. + + To resolve the pending dismissal, call the + :meth:`~flet.Dismissible.confirm_dismiss` method + passing it a boolean representing the decision. If `True`, then the control will be + dismissed, otherwise it will be moved back to its original location. + """ + + on_resize: Optional[ControlEventHandler["Dismissible"]] = None + """ + Called when this dismissible changes size, for example, when contracting before \ + being dismissed. + """ + + def before_update(self): + super().before_update() + if (self.secondary_background and self.secondary_background.visible) and not ( + self.background and self.background.visible + ): + raise ValueError( + "secondary_background can only be specified if background is also " + "specified/visible" + ) + + async def confirm_dismiss(self, dismiss: bool): + """ + Resolve a pending dismissal decision triggered by :attr:`on_confirm_dismiss`. + + Call this method from your confirmation flow after handling + :attr:`on_confirm_dismiss`. + + Args: + dismiss: `True` to continue dismissing the control, `False` to cancel + and return it to the original position. + """ + + await self._invoke_method("confirm_dismiss", {"dismiss": dismiss}) diff --git a/sdk/python/packages/flet/src/flet/controls/core/drag_target.py b/sdk/python/packages/flet/src/flet/controls/core/drag_target.py new file mode 100644 index 0000000000..f5bce32bdc --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/drag_target.py @@ -0,0 +1,199 @@ +from dataclasses import dataclass, field +from typing import Annotated, Optional, cast + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import Event, EventHandler +from flet.controls.core.draggable import Draggable +from flet.controls.transform import Offset +from flet.utils.deprecated import deprecated +from flet.utils.validation import V + +__all__ = [ + "DragTarget", + "DragTargetEvent", + "DragTargetLeaveEvent", + "DragWillAcceptEvent", +] + + +@dataclass +class DragWillAcceptEvent(Event["DragTarget"]): + """ + Event payload for :attr:`flet.DragTarget.on_will_accept`. + """ + + src_id: Optional[int] + """ + ID of the :class:`~flet.Draggable` source control, if available. + """ + + src: Draggable = field(init=False) + """ + Source :class:`~flet.Draggable` control resolved from :attr:`src_id`. + """ + + accept: bool + """ + Whether this target will accept the dragged source. + """ + + def __post_init__(self): + if self.src_id is not None: + self.src = cast(Draggable, self.page.get_control(self.src_id)) + + +@dataclass +class DragTargetEvent(Event["DragTarget"]): + """ + Event payload for drag move and accepted-drop callbacks. + """ + + src_id: Optional[int] + """ + ID of the :class:`~flet.Draggable` source control, if available. + """ + + src: Draggable = field(init=False) + """ + Source :class:`~flet.Draggable` control resolved from :attr:`src_id`. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + Pointer position relative to the target bounds. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + Pointer position in the global coordinate space. + """ + + def __post_init__(self): + if self.src_id is not None: + self.src = cast(Draggable, self.page.get_control(self.src_id)) + + @property + @deprecated( + reason="Use `local_position.x` for target-relative coordinates or " + "`global_position.x` for global coordinates instead.", + docs_reason="Use [`local_position.x`][flet.DragTargetEvent.local_position] for target-relative coordinates or " # noqa: E501 + "[`global_position.x`][flet.DragTargetEvent.global_position] for global coordinates instead.", # noqa: E501 + version="0.85.0", + delete_version="0.88.0", + ) + def x(self) -> float: + """ + Horizontal pointer position in the global coordinate space. + """ + + return self.global_position.x + + @property + @deprecated( + reason="Use `local_position.y` for target-relative coordinates or " + "`global_position.y` for global coordinates instead.", + docs_reason="Use [`local_position.y`][flet.DragTargetEvent.local_position] for target-relative coordinates or " # noqa: E501 + "[`global_position.y`][flet.DragTargetEvent.global_position] for global coordinates instead.", # noqa: E501 + version="0.85.0", + delete_version="0.88.0", + ) + def y(self) -> float: + """ + Vertical pointer position in the global coordinate space. + """ + + return self.global_position.y + + @property + @deprecated( + reason="Use `local_position` for target-relative coordinates or " + "`global_position` for global coordinates instead.", + docs_reason="Use [`local_position`][flet.DragTargetEvent.local_position] for target-relative coordinates or " # noqa: E501 + "[`global_position`][flet.DragTargetEvent.global_position] for global coordinates instead.", # noqa: E501 + version="0.85.0", + delete_version="0.88.0", + ) + def offset(self) -> Offset: + """ + Pointer position in global coordinates. + """ + + return self.global_position + + +@dataclass +class DragTargetLeaveEvent(Event["DragTarget"]): + """ + Event payload for :attr:`flet.DragTarget.on_leave`. + """ + + src_id: Optional[int] + """ + ID of the :class:`~flet.Draggable` source control, if available. + """ + + src: Draggable = field(init=False) + """ + Source :class:`~flet.Draggable` control resolved from :attr:`src_id`. + """ + + def __post_init__(self): + if self.src_id is not None: + self.src = cast(Draggable, self.page.get_control(self.src_id)) + + +@control("DragTarget") +class DragTarget(Control): + """ + A control that completes drag operation when a :class:`~flet.Draggable` control is \ + dropped. + + When a `Draggable` is dragged on top of a `DragTarget`, the `DragTarget` is asked + whether it will accept the data the `Draggable` is carrying. The `DragTarget` will + accept incoming drag if it belongs to the same `group` as `Draggable`. If the user + does drop the `Draggable` on top of the `DragTarget` (and the `DragTarget` has + indicated that it will accept the `Draggable`'s data), then the `DragTarget` is + asked to accept the `Draggable`'s data. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The content of this control. + + Raises: + ValueError: If it is not visible. + """ + + group: str = "default" + """ + The group this target belongs to. + + Note: + For a `DragTarget` to accept an incoming drop from a :class:`~flet.Draggable`, + they must both be in the same `group`. + """ + + on_will_accept: Optional[EventHandler[DragWillAcceptEvent]] = None + """ + Called when a :class:`~flet.Draggable` is dragged on this target. + """ + + on_accept: Optional[EventHandler[DragTargetEvent]] = None + """ + Called when the user does drop an acceptable (same :attr:`group`) \ + :class:`~flet.Draggable` on this target. + """ + + on_leave: Optional[EventHandler[DragTargetLeaveEvent]] = None + """ + Called when a :class:`~flet.Draggable` leaves this target. + """ + + on_move: Optional[EventHandler[DragTargetEvent]] = None + """ + Called when a :class:`~flet.Draggable` moves within this target. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/draggable.py b/sdk/python/packages/flet/src/flet/controls/core/draggable.py new file mode 100644 index 0000000000..b1f6ead1dc --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/draggable.py @@ -0,0 +1,109 @@ +from typing import Annotated, Optional + +from flet.controls.alignment import Axis +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.utils.validation import V + +__all__ = ["Draggable"] + + +@control("Draggable") +class Draggable(Control): + """ + A control that can be dragged from to a :class:`~flet.DragTarget`. + + When a draggable control recognizes the start of a drag gesture, it displays the + :attr:`content_feedback` control that tracks the user's finger across the screen. + If the user lifts their finger while on top of a `DragTarget`, this target is + given the opportunity to complete drag-and-drop flow. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The control to display when the draggable is not being dragged. + + If the draggable is being dragged, the + :attr:`content_when_dragging` is displayed instead. + + Raises: + ValueError: If it is not visible. + """ + + group: str = "default" + """ + The group this draggable belongs to. + + Note: + For a :class:`~flet.DragTarget` to accept an incoming drop from a `Draggable`, + they must both be in the same `group`. + """ + + content_when_dragging: Optional[Control] = None + """ + The control to display instead of :attr:`content` when this draggable is being \ + dragged. + + If set, this control visually replaces `content` during an active drag operation, + allowing you to show a different appearance or an "empty" placeholder. + If `None`, the original `content` remains visible while dragging. + """ + + content_feedback: Optional[Control] = None + """ + The control to show under the pointer when a drag is under way. + """ + + axis: Optional[Axis] = None + """ + Restricts the draggable's movement to a specific axis. + + - `Axis.HORIZONTAL`: Only allows horizontal dragging. + - `Axis.VERTICAL`: Only allows vertical dragging. + - `None`: Allows dragging in any direction. + """ + + affinity: Optional[Axis] = None + """ + Specifies the axis along which this control competes with other gestures to \ + initiate a drag. + + - If `None`, the drag starts as soon as a tap down gesture is recognized, + regardless of direction. + - If set to `Axis.HORIZONTAL` or `Axis.VERTICAL`, the control will only initiate a + drag when the gesture matches the specified axis, allowing it to compete + with other gestures in that direction. + """ + + max_simultaneous_drags: Annotated[ + Optional[int], + V.ge(0), + ] = None + """ + Specifies how many simultaneous drag operations are allowed for this draggable. + + - `0` - disables dragging entirely. + - `1` - allows only one drag at a time. + For a better user experience, you may want to provide an "empty" widget for + :attr:`content_when_dragging` + to visually indicate the item is being moved. + - any other positive integer - allows that many concurrent drags. + - `None` - no limit on the number of simultaneous drags. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + on_drag_start: Optional[ControlEventHandler["Draggable"]] = None + """ + Called when this draggable starts being dragged. + """ + + on_drag_complete: Optional[ControlEventHandler["Draggable"]] = None + """ + Called when this draggable is dropped and accepted by a :class:`~flet.DragTarget`. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/flet_app.py b/sdk/python/packages/flet/src/flet/controls/core/flet_app.py new file mode 100644 index 0000000000..62f7e6cc89 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/flet_app.py @@ -0,0 +1,91 @@ +from dataclasses import dataclass +from typing import Any, Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler, Event, EventHandler +from flet.controls.layout_control import LayoutControl + +__all__ = ["FletApp", "FletAppOutputEvent"] + + +@dataclass +class FletAppOutputEvent(Event["FletApp"]): + """One stdout/stderr line from the embedded Pyodide app.""" + + text: str + """The line of text. Pyodide line-buffers stdout/stderr by default, + so each event is typically one `print(...)` worth of output (with + its trailing newline).""" + + is_stderr: bool = False + """True for stderr writes; False for stdout.""" + + +@control("FletApp") +class FletApp(LayoutControl): + """ + Renders another Flet app in the current app, similar to HTML IFrame, but for Flet. + """ + + url: Optional[str] = None + """ + Flet app URL, e.g. `http://localhost:8550` or `flet.sock`. + """ + + args: Optional[dict[str, Any]] = None + """ + Optional dictionary of arguments to pass to the Flet app. + """ + + assets_dir: Optional[str] = None + """ + Base location for assets referenced by the embedded app. On web this + is a URL prefix joined with relative `src` values (e.g. on + `Image`/`Lottie`/`Markdown`); on desktop it is a filesystem path. + """ + + force_pyodide: bool = False + """ + Whether to force the use of Pyodide. + """ + + reconnect_interval_ms: Optional[int] = None + """ + Delay, in milliseconds, between reconnection attempts. + """ + + reconnect_timeout_ms: Optional[int] = None + """ + Total time to try reconnecting. + """ + + show_app_startup_screen: bool = False + """ + Whether to show the app startup screen. + """ + + app_startup_screen_message: Optional[str] = None + """ + Message to display on the app startup screen. + """ + + app_error_message: Optional[str] = None + """ + Template message to display when the app fails to load. + Use `{message}` placeholder to include the error message + and `{details}` to include error details. + """ + + on_error: Optional[ControlEventHandler["FletApp"]] = None + """ + Called when a connection or any unhandled error occurs. + """ + + on_python_output: Optional[EventHandler[FletAppOutputEvent]] = None + """ + Fires once per stdout/stderr write inside the embedded Pyodide app. + Pyodide line-buffers by default, so each event is typically one + `print(...)` call. Only fires for embedded FletApps with + `force_pyodide=True`; root-level Pyodide pages have nowhere to + bubble the event. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py b/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py new file mode 100644 index 0000000000..687ea62124 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/gesture_detector.py @@ -0,0 +1,519 @@ +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler, EventHandler +from flet.controls.events import ( + DragDownEvent, + DragEndEvent, + DragStartEvent, + DragUpdateEvent, + ForcePressEvent, + HoverEvent, + LongPressDownEvent, + LongPressEndEvent, + LongPressMoveUpdateEvent, + LongPressStartEvent, + PointerEvent, + ScaleEndEvent, + ScaleStartEvent, + ScaleUpdateEvent, + ScrollEvent, + TapEvent, + TapMoveEvent, +) +from flet.controls.layout_control import LayoutControl +from flet.controls.types import MouseCursor, PointerDeviceType + +__all__ = ["GestureDetector"] + + +@control("GestureDetector") +class GestureDetector(LayoutControl, AdaptiveControl): + """ + A control that detects gestures. + + Attempts to recognize gestures that correspond to its non-None callbacks. + + If this control has a :attr:`content`, it defers to that child control for + its sizing behavior, else it grows to fit the parent instead. + """ + + content: Optional[Control] = None + """ + A child Control contained by the gesture detector. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The mouse cursor for mouse pointers that are hovering over the control. + """ + + drag_interval: int = 0 + """ + Throttling in milliseconds for horizontal drag, vertical drag and pan update \ + events. + + When a user moves a pointer a lot of events are being generated to do precise + tracking. `drag_interval` allows sending drag update events to a Flet program every + X milliseconds, thus preserving the bandwidth (web and mobile apps). + + `0` means no throttling: all events are sent to a Flet program, + resulting in very smooth tracking. + """ + + hover_interval: int = 0 + """ + Throttling in milliseconds for :attr:`on_hover` event. + """ + + multi_tap_touches: int = 0 + """ + The minimum number of pointers to trigger :attr:`on_multi_tap` event. + """ + + exclude_from_semantics: bool = False + """ + TBD + """ + + on_force_press_start: Optional[EventHandler[ForcePressEvent["GestureDetector"]]] = ( + None + ) + """ + Called when a pointer has pressed with a force exceeding the start pressure. + """ + + on_force_press_peak: Optional[EventHandler[ForcePressEvent["GestureDetector"]]] = ( + None + ) + """ + Called when a pointer has pressed with a force exceeding the peak pressure. + """ + + on_force_press_update: Optional[ + EventHandler[ForcePressEvent["GestureDetector"]] + ] = None + """ + Called for each update after a force press has started. + """ + + on_force_press_end: Optional[EventHandler[ForcePressEvent["GestureDetector"]]] = ( + None + ) + """ + Called when the pointer that triggered a force press is no longer in contact with \ + the screen. + """ + + trackpad_scroll_causes_scale: bool = False + """ + TBD + """ + + allowed_devices: Optional[list[PointerDeviceType]] = None + """ + TBD + """ + + on_tap: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a tap with a primary button has occurred. + """ + + on_tap_down: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that might cause a tap with a primary button has contacted \ + the screen at a particular location. + """ + + on_tap_up: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that will trigger a tap with a primary button has stopped \ + contacting the screen at a particular location. + """ + + on_tap_move: Optional[EventHandler[TapMoveEvent["GestureDetector"]]] = None + """ + Called when a pointer that triggered a tap has moved. + """ + + on_tap_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_tap_down` will not end up causing \ + a tap. + """ + + on_multi_tap: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when multiple pointers contacted the screen. + """ + + on_multi_long_press: Optional[ + EventHandler[LongPressEndEvent["GestureDetector"]] + ] = None + """ + Called when a long press gesture with multiple pointers has been recognized. + """ + + on_secondary_tap: Optional[ControlEventHandler["GestureDetector"]] = None + """ + A tap with a secondary button has occurred. + """ + + on_secondary_tap_down: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that might cause a tap with a secondary button has contacted \ + the screen at a particular location. + """ + + on_secondary_tap_up: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that will trigger a tap with a secondary button has stopped \ + contacting the screen at a particular location. + """ + + on_secondary_tap_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_secondary_tap_down` + will not end up causing a tap. + """ + + on_tertiary_tap_down: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that might cause a tap with a tertiary button has contacted \ + the screen at a particular location. + """ + + on_tertiary_tap_up: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that will trigger a tap with a tertiary button has stopped \ + contacting the screen at a particular location. + """ + + on_tertiary_tap_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_tertiary_tap_down` + will not end up causing a tap. + """ + + on_long_press_down: Optional[ + EventHandler[LongPressDownEvent["GestureDetector"]] + ] = None + """ + Called when a pointer that might cause a long press with a primary button has \ + contacted the screen. + """ + + on_long_press_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_long_press_down` + will not end up causing a long-press. + """ + + on_long_press: Optional[ControlEventHandler["GestureDetector"]] = None + """ + Called when a long press gesture with a primary button has been recognized. + """ + + on_long_press_start: Optional[ + EventHandler[LongPressStartEvent["GestureDetector"]] + ] = None + """ + Triggered when a pointer has remained in contact with the screen at the same \ + location for a long period of time. + """ + + on_long_press_move_update: Optional[ + EventHandler[LongPressMoveUpdateEvent["GestureDetector"]] + ] = None + """ + Called when, after a long press has been accepted, the pointer moves. + """ + + on_long_press_up: Optional[ControlEventHandler["GestureDetector"]] = None + """ + Called when a pointer that has triggered a long press with a primary button is no \ + longer in contact with the screen. + """ + + on_long_press_end: Optional[EventHandler[LongPressEndEvent["GestureDetector"]]] = ( + None + ) + """ + Called when a pointer that has triggered a long-press with a primary button has \ + stopped contacting the screen. + """ + + on_secondary_long_press_down: Optional[ + EventHandler[LongPressDownEvent["GestureDetector"]] + ] = None + """ + Called when a pointer that might cause a long press with a secondary button has \ + contacted the screen. + """ + + on_secondary_long_press_cancel: Optional[ControlEventHandler["GestureDetector"]] = ( + None + ) + """ + The pointer that previously triggered :attr:`on_secondary_long_press_down` + not end up causing a long-press. + """ + + on_secondary_long_press: Optional[ControlEventHandler["GestureDetector"]] = None + """ + Called when a long press gesture with a secondary button has been recognized. + """ + + on_secondary_long_press_start: Optional[ + EventHandler[LongPressStartEvent["GestureDetector"]] + ] = None + """ + Triggered when a pointer has remained in contact with the screen at the same \ + location for a long period of time. + """ + + on_secondary_long_press_move_update: Optional[ + EventHandler[LongPressMoveUpdateEvent["GestureDetector"]] + ] = None + """ + Called when, after a secondary long press has been accepted, the pointer moves. + """ + + on_secondary_long_press_up: Optional[ControlEventHandler["GestureDetector"]] = None + """ + Called when a pointer that has triggered a long press with a secondary button is \ + no longer in contact with the screen. + """ + + on_secondary_long_press_end: Optional[ + EventHandler[LongPressEndEvent["GestureDetector"]] + ] = None + """ + Called when a pointer that has triggered a long-press with a secondary button has \ + stopped contacting the screen. + """ + + on_tertiary_long_press_down: Optional[ + EventHandler[LongPressDownEvent["GestureDetector"]] + ] = None + """ + Called when a pointer that might cause a long press with a tertiary button has \ + contacted the screen. + """ + + on_tertiary_long_press_cancel: Optional[ControlEventHandler["GestureDetector"]] = ( + None + ) + """ + The pointer that previously triggered :attr:`on_tertiary_long_press_down` + will not end up causing a long-press. + """ + + on_tertiary_long_press: Optional[ControlEventHandler["GestureDetector"]] = None + """ + Called when a long press gesture with a tertiary button has been recognized. + """ + + on_tertiary_long_press_start: Optional[ + EventHandler[LongPressStartEvent["GestureDetector"]] + ] = None + """ + Triggered when a pointer has remained in contact with the screen at the same \ + location for a long period of time. + """ + + on_tertiary_long_press_move_update: Optional[ + EventHandler[LongPressMoveUpdateEvent["GestureDetector"]] + ] = None + """ + Called when, after a tertiary long press has been accepted, the pointer moves. + """ + + on_tertiary_long_press_up: Optional[ControlEventHandler["GestureDetector"]] = None + """ + Called when a pointer that has triggered a long press with a tertiary button is no \ + longer in contact with the screen. + """ + + on_tertiary_long_press_end: Optional[ + EventHandler[LongPressEndEvent["GestureDetector"]] + ] = None + """ + Called when a pointer that has triggered a long-press with a tertiary button has \ + stopped contacting the screen. + """ + + on_double_tap: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The user has tapped the screen with a primary button at the same location twice in \ + quick succession. + """ + + on_double_tap_down: Optional[EventHandler[TapEvent["GestureDetector"]]] = None + """ + Called when a pointer that might cause a double tap has contacted the screen at a \ + particular location. + + Triggered immediately after the down event of the second tap. + """ + + on_double_tap_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer sequence that was expected to cause a double tap will not do so. + """ + + on_horizontal_drag_down: Optional[ + EventHandler[DragDownEvent["GestureDetector"]] + ] = None + """ + Called when a pointer has contacted the screen and might begin to move \ + horizontally. + """ + + on_horizontal_drag_start: Optional[ + EventHandler[DragStartEvent["GestureDetector"]] + ] = None + """ + Called when a pointer has contacted the screen with a primary button and has begun \ + to move horizontally. + """ + + on_horizontal_drag_update: Optional[ + EventHandler[DragUpdateEvent["GestureDetector"]] + ] = None + """ + Called when a pointer that is in contact with the screen and moving horizontally \ + has moved in the horizontal direction. + """ + + on_horizontal_drag_end: Optional[EventHandler[DragEndEvent["GestureDetector"]]] = ( + None + ) + """ + Called when a pointer moving horizontally is no longer in contact and was moving \ + at a specific velocity. + """ + + on_horizontal_drag_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_horizontal_drag_down` + will not end up causing a horizontal drag. + """ + + on_vertical_drag_down: Optional[EventHandler[DragDownEvent["GestureDetector"]]] = ( + None + ) + """ + Called when a pointer has contacted the screen and might begin to move vertically. + """ + + on_vertical_drag_start: Optional[ + EventHandler[DragStartEvent["GestureDetector"]] + ] = None + """ + Called when a pointer has contacted the screen and has begun to move vertically. + """ + + on_vertical_drag_update: Optional[ + EventHandler[DragUpdateEvent["GestureDetector"]] + ] = None + """ + A pointer moving vertically has moved in the vertical direction. + """ + + on_vertical_drag_end: Optional[EventHandler[DragEndEvent["GestureDetector"]]] = None + """ + Called when a pointer moving vertically is no longer in contact and was moving at \ + a specific velocity. + """ + + on_vertical_drag_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_vertical_drag_down` + will not end up causing a vertical drag. + """ + + on_pan_down: Optional[EventHandler[DragDownEvent["GestureDetector"]]] = None + """ + Called when a pointer has contacted the screen and might begin to move. + """ + + on_pan_start: Optional[EventHandler[DragStartEvent["GestureDetector"]]] = None + """ + Called when a pointer has contacted the screen and has begun to move. + """ + + on_pan_update: Optional[EventHandler[DragUpdateEvent["GestureDetector"]]] = None + """ + Called when a pointer that is in contact with the screen and moving has moved \ + again. + """ + + on_pan_end: Optional[EventHandler[DragEndEvent["GestureDetector"]]] = None + """ + Called when a pointer is no longer in contact and was moving at a specific \ + velocity. + """ + + on_pan_cancel: Optional[ControlEventHandler["GestureDetector"]] = None + """ + The pointer that previously triggered :attr:`on_pan_down` will not end up causing \ + a pan gesture. + """ + + on_right_pan_start: Optional[EventHandler[PointerEvent["GestureDetector"]]] = None + """ + Pointer has contacted the screen while secondary button pressed and has begun to \ + move. + """ + + on_right_pan_update: Optional[EventHandler[PointerEvent["GestureDetector"]]] = None + """ + A pointer that is in contact with the screen, secondary button pressed and moving \ + has moved again. + """ + + on_right_pan_end: Optional[EventHandler[PointerEvent["GestureDetector"]]] = None + """ + A pointer with secondary button pressed is no longer in contact and was moving at \ + a specific velocity. + """ + + on_scale_start: Optional[EventHandler[ScaleStartEvent["GestureDetector"]]] = None + """ + Called when the pointers in contact with the screen have established a focal point \ + and initial scale of `1.0`. + """ + + on_scale_update: Optional[EventHandler[ScaleUpdateEvent["GestureDetector"]]] = None + """ + TBD + """ + + on_scale_end: Optional[EventHandler[ScaleEndEvent["GestureDetector"]]] = None + """ + TBD + """ + + on_hover: Optional[EventHandler[HoverEvent["GestureDetector"]]] = None + """ + Called when a mouse pointer has entered this control. + """ + + on_enter: Optional[EventHandler[HoverEvent["GestureDetector"]]] = None + """ + Called when a mouse pointer has entered this control. + """ + + on_exit: Optional[EventHandler[HoverEvent["GestureDetector"]]] = None + """ + Called when a mouse pointer has exited this control. + """ + + on_scroll: Optional[EventHandler[ScrollEvent["GestureDetector"]]] = None + """ + TBD + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/grid_view.py b/sdk/python/packages/flet/src/flet/controls/core/grid_view.py new file mode 100644 index 0000000000..b686e249fe --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/grid_view.py @@ -0,0 +1,129 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.types import ClipBehavior, Number + +__all__ = ["GridView"] + + +@control("GridView") +class GridView(LayoutControl, ScrollableControl, AdaptiveControl): + """ + A scrollable, 2D array of controls. + + It is very effective for large lists (thousands of items). + Prefer it over wrapping :class:`~flet.Column`s or + :class:`~flet.Row`s for smooth scrolling. + + ```python + ft.GridView( + width=180, + runs_count=2, + spacing=8, + controls=[ + ft.Container( + width=50, height=50, bgcolor=ft.Colors.PRIMARY, border_radius=8 + ), + ft.Container( + width=50, height=50, bgcolor=ft.Colors.SECONDARY, border_radius=8 + ), + ft.Container( + width=50, height=50, bgcolor=ft.Colors.TERTIARY, border_radius=8 + ), + ft.Container( + width=50, height=50, bgcolor=ft.Colors.ERROR, border_radius=8 + ), + ], + ) + ``` + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of controls to display inside grid. + """ + + horizontal: bool = False + """ + Whether to layout the grid items horizontally. + """ + + reverse: bool = False + """ + Whether the scroll view scrolls in the reading direction. + + For example, if the reading direction is left-to-right and `horizontal` is `True`, + then the scroll view scrolls from left to right when `reverse` is `False` + and from right to left when `reverse` is `True`. + + Similarly, if `horizontal` is `False`, then the scroll view scrolls from top + to bottom when `reverse` is `False` and from bottom to top when `reverse` is `True`. + """ + + runs_count: int = 1 + """ + The number of children in the cross axis. + """ + + max_extent: Optional[int] = None + """ + The maximum width or height of the grid item. + """ + + spacing: Number = 10 + """ + The number of logical pixels between each child along the main axis. + """ + + run_spacing: Number = 10 + """ + The number of logical pixels between each child along the cross axis. + """ + + child_aspect_ratio: Number = 1.0 + """ + The ratio of the cross-axis to the main-axis extent of each child. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of space by which to inset the children. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + The content will be clipped (or not) according to this option. + """ + + semantic_child_count: Optional[int] = None + """ + The number of children that will contribute semantic information. + """ + + cache_extent: Optional[Number] = None + """ + Items that fall in the cache area (area before or after the visible area that are \ + about to become visible when the user scrolls) are laid out even though they are \ + not (yet) visible on screen. + + The cacheExtent describes how many pixels the cache area extends before the leading + edge and after the trailing edge of the viewport. + + The total extent, which the viewport will try to cover with `controls`, is + `cache_extent` before the leading edge + extent of the main axis + `cache_extent` + after the trailing edge. + """ + + build_controls_on_demand: bool = True + """ + TBD + """ + + def __contains__(self, item): + return item in self.controls diff --git a/sdk/python/packages/flet/src/flet/controls/core/hero.py b/sdk/python/packages/flet/src/flet/controls/core/hero.py new file mode 100644 index 0000000000..c9daa19b99 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/hero.py @@ -0,0 +1,46 @@ +from typing import Annotated + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.utils.validation import V + +__all__ = ["Hero"] + + +@control("Hero") +class Hero(LayoutControl): + """ + Marks the :attr:`content` as a shared element for route transitions. + + Place a `Hero` with the same :attr:`tag` in both source and destination views to + animate that control between routes. + """ + + tag: Annotated[ + str, + V.instance_of(str), + ] + """ + A unique identifier used to match source and destination Hero controls. + + Raises: + ValueError: If it is not of type `str`. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The control to display and animate. + + Raises: + ValueError: If it is not visible. + """ + + transition_on_user_gestures: bool = False + """ + Whether to animate when the route is transitioned by a \ + user gesture (for example, iOS back swipe). + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/icon.py b/sdk/python/packages/flet/src/flet/controls/core/icon.py new file mode 100644 index 0000000000..6bd2d47166 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/icon.py @@ -0,0 +1,126 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.box import BoxShadowValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import BlendMode, ColorValue, IconData, Number +from flet.utils.validation import V + +__all__ = ["Icon"] + + +@control("Icon") +class Icon(LayoutControl): + """ + A control that displays an icon from a built-in or custom icon set. + + Icons can be customized in color, size, and visual style using various + parameters such as stroke weight, fill level, and shadows. + + Example: + ```python + ft.Icon(ft.Icons.FAVORITE, color=ft.Colors.PRIMARY, size=40) + ``` + """ + + icon: IconData + """ + The icon to display, selected from a predefined icon set. + + You can explore available icons using the + [Flet Icons Browser](https://examples.flet.dev/icons_browser/). + """ + + color: Optional[ColorValue] = None + """ + The color to use when drawing the icon. + """ + + size: Optional[Number] = None + """ + The size (width and height) of the square area the icon will occupy. + + If not set, a default size will be used. When placing this icon + inside other controls (such as buttons), those controls may also affect sizing. + """ + + semantics_label: Optional[str] = None + """ + An accessibility label for the icon. + + This text is not displayed visually but may be announced by screen readers + or other assistive technologies. + """ + + shadows: Optional[BoxShadowValue] = None + """ + A list of shadows to apply beneath the icon. + + Use multiple shadows to simulate complex lighting effects. + The order of shadows matters for how transparency is blended. + """ + + fill: Annotated[ + Optional[Number], + V.between(0.0, 1.0), + ] = None + """ + The fill amount of the icon, between `0.0` (outline) and `1.0` (solid). + + This feature requires the icon's font to support fill variation. + It can be used to indicate state transitions or selection visually. + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ + + apply_text_scaling: Optional[bool] = None + """ + Whether to scale the icon based on the system or user's preferred text size. + + Useful when placing icons alongside text, ensuring both scale consistently + for better readability and accessibility. + """ + + grade: Optional[Number] = None + """ + A fine-tuning adjustment for the stroke thickness of the icon. + + This requires support from the icon's font. Grade values can be negative or + positive. + It allows precise visual adjustments without changing icon size. + """ + + weight: Annotated[ + Optional[Number], + V.gt(0.0), + ] = None + """ + The stroke weight (thickness) of the icon's lines. + + This requires the icon font to support weight variation. + + Raises: + ValueError: If it is not strictly greater than `0.0`. + """ + + optical_size: Annotated[ + Optional[Number], + V.gt(0.0), + ] = None + """ + Adjusts the icon's visual style for different sizes to maintain clarity and \ + balance. + + This requires the icon font to support optical sizing. + + Raises: + ValueError: If it is not strictly greater than `0.0`. + """ + + blend_mode: Optional[BlendMode] = BlendMode.SRC_OVER + """ + The blend mode used when rendering the icon. + + Blend modes control how the icon's color interacts with the background. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/image.py b/sdk/python/packages/flet/src/flet/controls/core/image.py new file mode 100644 index 0000000000..2c0e346995 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/image.py @@ -0,0 +1,177 @@ +from typing import Optional, Union + +from flet.controls.animation import Animation +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.box import BoxFit, FilterQuality +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + BlendMode, + ColorValue, + ImageRepeat, +) + +__all__ = ["Image"] + + +@control("Image") +class Image(LayoutControl): + """ + Displays an image. + + The following popular formats are supported: JPEG, PNG, SVG, + GIF, Animated GIF, WebP, Animated WebP, BMP, and WBMP. + + Example: + ```python + ft.Image( + src="https://flet.dev/img/logo.svg", + width=100, + height=100, + ) + ``` + """ + + src: Union[str, bytes] + """ + The image source. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + """ + + error_content: Optional[Control] = None + """ + Fallback control to display if the image cannot be loaded from the provided \ + source. + """ + + repeat: ImageRepeat = ImageRepeat.NO_REPEAT + """ + How to paint any portions of the layout bounds not covered by this image. + """ + + fit: Optional[BoxFit] = None + """ + Defines how to inscribe this image into the space allocated during layout. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + Clips this image to have rounded corners. + """ + + color: Optional[ColorValue] = None + """ + If set, this color is blended with each image pixel using \ + :attr:`color_blend_mode`. + """ + + color_blend_mode: Optional[BlendMode] = None + """ + Used to combine :attr:`color` with the image. + + In terms of the blend mode, color is the source and this image is the destination. + """ + + gapless_playback: bool = False + """ + Whether to continue showing the old image (`True`), or briefly show nothing \ + (`False`), when the image provider changes. + + Has no effect on svg images. + """ + + semantics_label: Optional[str] = None + """ + A semantic description of this image. + + Used to provide a description of the image to TalkBack on Android, and VoiceOver + on iOS. + """ + + exclude_from_semantics: bool = False + """ + Whether to exclude this image from semantics. + """ + + filter_quality: FilterQuality = FilterQuality.MEDIUM + """ + The rendering quality of the image. + """ + + placeholder_src: Optional[Union[str, bytes]] = None + """ + A placeholder displayed while the image is loading. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + + If `None`, no placeholder is shown while loading; the :attr:`src` + simply appears (or fades in if :attr:`placeholder_src` or + :attr:`placeholder_fade_out_animation` is not `None`). + + Note: + SVG sources are currently not supported as placeholders. If provided, + this property will be ignored and the :attr:`src` will be + displayed directly instead. + """ + + placeholder_fit: Optional[BoxFit] = None + """ + Defines how to inscribe the placeholder into its space. + + If `None`, default to :attr:`fit`. + """ + + fade_in_animation: Optional[Animation] = None + """ + Fade-in animation of the :attr:`src` image as it appears after loading, replacing \ + the :attr:`placeholder_src`. + + If `None`, defaults to + `Animation(Duration(milliseconds=250), AnimationCurve.EASE_IN_OUT)`, + if :attr:`placeholder_src` or :attr:`placeholder_fade_out_animation` + is not `None`. + """ + + placeholder_fade_out_animation: Optional[Animation] = None + """ + Fade-out animation for the :attr:`placeholder_src`, after the :attr:`src` loads. + + If `None`, defaults to + `Animation(Duration(milliseconds=150), AnimationCurve.EASE_OUT)`, + if :attr:`placeholder_src` or :attr:`fade_in_animation` is not `None`. + """ + + cache_width: Optional[int] = None + """ + The size at which this image should be decoded. + + The image will, however, be rendered to the constraints of the layout regardless + of this parameter. + """ + + cache_height: Optional[int] = None + """ + The size at which this image should be decoded. + + The image will, however, be rendered to the constraints of the layout regardless + of this parameter. + """ + + anti_alias: bool = False + """ + Whether to paint the image with anti-aliasing. + + Anti-aliasing alleviates the sawtooth artifact when this image is rotated. + """ + + def init(self): + super().init() + self._internals["skip_properties"] = ["width", "height"] diff --git a/sdk/python/packages/flet/src/flet/controls/core/interactive_viewer.py b/sdk/python/packages/flet/src/flet/controls/core/interactive_viewer.py new file mode 100644 index 0000000000..1610cf601c --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/interactive_viewer.py @@ -0,0 +1,248 @@ +from dataclasses import field +from typing import Annotated, Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import EventHandler +from flet.controls.duration import DurationValue +from flet.controls.events import ( + ScaleEndEvent, + ScaleStartEvent, + ScaleUpdateEvent, +) +from flet.controls.layout_control import LayoutControl +from flet.controls.margin import Margin, MarginValue +from flet.controls.types import ClipBehavior, Number +from flet.utils.validation import V + +__all__ = ["InteractiveViewer"] + + +@control("InteractiveViewer") +class InteractiveViewer(LayoutControl): + """ + Allows you to pan, zoom, and rotate its :attr:`content`. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The `Control` to be transformed. + + Raises: + ValueError: If it is not visible. + """ + + pan_enabled: bool = True + """ + Whether panning is enabled. + """ + + scale_enabled: bool = True + """ + Whether scaling is enabled. + """ + + trackpad_scroll_causes_scale: bool = False + """ + Whether scrolling up/down on a trackpad should cause scaling instead of panning. + """ + + constrained: bool = True + """ + Whether the normal size constraints at this point in the control tree are applied \ + to the :attr:`content`. + + If set to `False`, then the content will be given infinite constraints. This + is often useful when a content should be bigger than this `InteractiveViewer`. + + For example, for a content which is bigger than the viewport but can be + panned to reveal parts that were initially offscreen, `constrained` must + be set to `False` to allow it to size itself properly. If `constrained` is + `True` and the content can only size itself to the viewport, then areas + initially outside of the viewport will not be able to receive user + interaction events. If experiencing regions of the content that are not + receptive to user gestures, make sure `constrained` is `False` and the content + is sized properly. + """ + + max_scale: Annotated[ + Number, + V.gt(0), + V.ge_field("min_scale"), + ] = 2.5 + """ + The maximum allowed scale. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not greater than or equal to :attr:`min_scale`. + """ + + min_scale: Annotated[ + Number, + V.gt(0), + V.le_field("max_scale"), + ] = 0.8 + """ + The minimum allowed scale. + + The effective scale is limited by the value of :attr:`boundary_margin`. + If scaling would cause the content to be displayed outside the defined boundary, + it is prevented. By default, `boundary_margin` is set to `Margin.all(0)`, + so scaling below `1.0` is typically not possible unless you increase the + `boundary_margin` value. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not less than or equal to :attr:`max_scale`. + """ + + interaction_end_friction_coefficient: Annotated[ + Number, + V.gt(0), + ] = 0.0000135 + """ + Changes the deceleration behavior after a gesture. + + Raises: + ValueError: If it is not strictly greater than `0`. + """ + + scale_factor: Number = 200 + """ + The amount of scale to be performed per pointer scroll. + + Increasing this value above the default causes scaling to feel slower, + while decreasing it causes scaling to feel faster. + + Note: + Has effect only on pointer device scrolling, not pinch to zoom. + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + Defines how to clip the :attr:`content`. + + If set to :attr:`flet.ClipBehavior.NONE`, the :attr:`content` can visually overflow + the bounds of this `InteractiveViewer`, but gesture events (such as pan or zoom) + will only be recognized within the viewer's area. Ensure this `InteractiveViewer` + is sized appropriately when using :attr:`flet.ClipBehavior.NONE`. + """ + + alignment: Optional[Alignment] = None + """ + The alignment of the :attr:`content` within this viewer. + """ + + boundary_margin: MarginValue = field(default_factory=lambda: Margin.all(0)) + """ + A margin for the visible boundaries of the :attr:`content`. + + Any transformation that results in the viewport being able to view outside + of the boundaries will be stopped at the boundary. The boundaries do not + rotate with the rest of the scene, so they are always aligned with the + viewport. + + To produce no boundaries at all, pass an infinite value. + + Defaults to `Margin.all(0)`, which results in boundaries that are the + exact same size and position as the :attr:`content`. + """ + + interaction_update_interval: int = 200 + """ + The interval (in milliseconds) at which the :attr:`on_interaction_update` event is \ + fired. + """ + + on_interaction_start: Optional[ + EventHandler[ScaleStartEvent["InteractiveViewer"]] + ] = None + """ + Called when the user begins a pan or scale gesture. + """ + + on_interaction_update: Optional[ + EventHandler[ScaleUpdateEvent["InteractiveViewer"]] + ] = None + """ + Called when the user updates a pan or scale gesture. + """ + + on_interaction_end: Optional[EventHandler[ScaleEndEvent["InteractiveViewer"]]] = ( + None + ) + """ + Called when the user ends a pan or scale gesture. + """ + + async def reset(self, animation_duration: Optional[DurationValue] = None): + """ + Resets the current transform matrix to identity. + + Args: + animation_duration: Optional animation duration for the reset + transition. If `None`, the reset is applied immediately. + + Notes: + When `animation_duration` is provided, Flutter interpolates from + the current transform to identity using a matrix tween. + """ + await self._invoke_method( + "reset", arguments={"animation_duration": animation_duration} + ) + + async def save_state(self): + """ + Saves a snapshot of the current transform matrix. + + The saved state can later be restored using + :meth:`restore_state`. Calling this method again + overwrites the previously saved snapshot. + """ + await self._invoke_method("save_state") + + async def restore_state(self): + """ + Restores the transform matrix previously captured by + :meth:`save_state`. + + If no state has been saved yet, this method has no effect. + """ + await self._invoke_method("restore_state") + + async def zoom(self, factor: Number): + """ + Applies multiplicative zoom to the current transform. + + Args: + factor: Scale multiplier relative to the current scale. + Values greater than `1` zoom in, values between `0` and `1` + zoom out. + + Note: + The resulting scale is clamped to :attr:`min_scale` and + :attr:`max_scale`. Additional boundary clamping is applied so the + visible viewport remains within :attr:`boundary_margin` limits. + """ + await self._invoke_method("zoom", arguments={"factor": factor}) + + async def pan(self, dx: Number, dy: Number = 0, dz: Number = 0): + """ + Translates the current transform matrix. + + Args: + dx: Horizontal translation delta in logical pixels. + dy: Vertical translation delta in logical pixels. + dz: Z-axis translation delta applied to the transform matrix. + + Note: + XY translation is clamped to the same interaction boundaries used + for gesture-driven panning. `dz` is applied directly to the matrix + and defaults to `0`. + """ + await self._invoke_method("pan", arguments={"dx": dx, "dy": dy, "dz": dz}) diff --git a/sdk/python/packages/flet/src/flet/controls/core/keyboard_listener.py b/sdk/python/packages/flet/src/flet/controls/core/keyboard_listener.py new file mode 100644 index 0000000000..387c5a0cd1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/keyboard_listener.py @@ -0,0 +1,109 @@ +from dataclasses import dataclass +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import Event, EventHandler + +__all__ = [ + "KeyDownEvent", + "KeyRepeatEvent", + "KeyUpEvent", + "KeyboardListener", +] + + +@dataclass +class KeyDownEvent(Event["KeyboardListener"]): + """ + Event triggered when a key is pressed down. + + Typically used to detect the initial press of a key before it is released + or repeated. + """ + + key: str + """ + The key that was pressed down. + + Represents the physical key (e.g., A, Enter, + Shift) that triggered the key down event. + """ + + +@dataclass +class KeyUpEvent(Event["KeyboardListener"]): + """ + Event triggered when a key is released. + + Useful for tracking when a key is no longer being pressed after + a key down or repeat event. + """ + + key: str + """ + The key that was released. + + Indicates which key was previously pressed and has now been lifted. + """ + + +@dataclass +class KeyRepeatEvent(Event["KeyboardListener"]): + """ + Event triggered when a key is held down and repeating. + + This event fires continuously while the key remains pressed, + depending on the system's key repeat rate. + """ + + key: str + """ + The key that is being held down and repeating. + + Represents the physical key that is generating repeat events (e.g., + ArrowDown, Backspace). + """ + + +@control("KeyboardListener") +class KeyboardListener(Control): + """ + A control that calls a callback whenever the user presses or releases a key on a \ + keyboard. + """ + + content: Control + """ + The content control of the keyboard listener. + """ + + autofocus: bool = False + """ + True if this control will be selected as the initial focus when no other node in \ + its scope is currently focused. + """ + + include_semantics: bool = True + """ + Include semantics information in this control. + """ + + on_key_down: Optional[EventHandler[KeyDownEvent]] = None + """ + Fires when a keyboard key is pressed. + """ + + on_key_up: Optional[EventHandler[KeyUpEvent]] = None + """ + Fires when a keyboard key is released. + """ + + on_key_repeat: Optional[EventHandler[KeyRepeatEvent]] = None + """ + Fires when a keyboard key is being hold, causing repeated events. + """ + + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/core/list_view.py b/sdk/python/packages/flet/src/flet/controls/core/list_view.py new file mode 100644 index 0000000000..48fae44f60 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/list_view.py @@ -0,0 +1,133 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.types import ClipBehavior, Number + +__all__ = ["ListView"] + + +@control("ListView") +class ListView(LayoutControl, ScrollableControl, AdaptiveControl): + """ + A scrollable list of controls arranged linearly. + + ListView is the most commonly used scrolling control. It displays its children one + after another in the scroll direction. In the cross axis, the children are required + to fill the ListView. + + ```python + ft.ListView( + controls=[ft.Text(f"Item {i}") for i in range(1, 6)], + ) + ``` + + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of `Control`s to display inside ListView. + """ + + horizontal: bool = False + """ + Whether the :attr:`controls` should be laid out horizontally. + """ + + reverse: bool = False + """ + Whether the scroll view scrolls in the reading direction. + + For example, if the reading direction is left-to-right and + :attr:`horizontal` is `True`, + then the scroll view scrolls from left to right when `reverse` is `False` + and from right to left when `reverse` is `True`. + + Similarly, if `horizontal` is `False`, then the scroll view scrolls from top + to bottom when `reverse` is `False` and from bottom to top when `reverse` is `True`. + """ + + spacing: Number = 0 + """ + The height of divider between the :attr:`controls`. + """ + + item_extent: Optional[Number] = None + """ + A fixed height or width (when :attr:`horizontal` is `True`) of an item to optimize \ + rendering. + + Note: + This property has effect only when :attr:`build_controls_on_demand` + is `True` or :attr:`spacing` is `0`. + """ + + first_item_prototype: bool = False + """ + Whether the dimensions of the first item should be used as a "prototype" for all \ + other items. + + If `True`, their `height` or `width` will be the same as the first item. + """ + + prototype_item: Optional[Control] = None + """ + A control to be used as a "prototype" for all items, i.e. their `height` or \ + `width` will be the same as the `prototype_item`. + + Note: + This property has effect only when :attr:`build_controls_on_demand` + is `True` or :attr:`spacing` is `0`. + """ + + divider_thickness: Number = 0 + """ + If greater than `0` then `Divider` is used as a spacing between list view items. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of space by which to inset the :attr:`controls`. + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + Defines how to clip the :attr:`controls`. + """ + + semantic_child_count: Optional[int] = None + """ + The number of children that will contribute semantic information. + """ + + cache_extent: Optional[Number] = None + """ + The viewport has an area before and after the visible area to cache items that are \ + about to become visible when the user scrolls. + + Items that fall in this cache area are laid out even though they are not (yet) + visible on screen. The `cache_extent` describes how many pixels the cache area + extends before the leading edge and after the trailing edge of the viewport. + + The total extent, which the viewport will try to cover with children, is + `cache_extent` before the leading edge + extent of the main axis + `cache_extent` + after the trailing edge. + + The cache area is also used to implement implicit accessibility scrolling on iOS: + When the accessibility focus moves from an item in the visible viewport to an + invisible item in the cache area, the framework will bring that item into view + with an (implicit) scroll action. + """ + + build_controls_on_demand: bool = True + """ + Whether the :attr:`controls` should be built lazily/on-demand, i.e. only when they \ + are about to become visible. + + This is particularly useful when dealing with a large number of controls. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/markdown.py b/sdk/python/packages/flet/src/flet/controls/core/markdown.py new file mode 100644 index 0000000000..66f10d0058 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/markdown.py @@ -0,0 +1,1040 @@ +from enum import Enum +from typing import Optional, Union + +from flet.controls.base_control import control, value +from flet.controls.box import BoxDecoration +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler, EventHandler +from flet.controls.core.text import TextSelectionChangeEvent +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + MainAxisAlignment, + Number, + TextAlign, + UrlTarget, +) + +__all__ = [ + "Markdown", + "MarkdownCodeTheme", + "MarkdownCustomCodeTheme", + "MarkdownExtensionSet", + "MarkdownStyleSheet", +] + + +class MarkdownExtensionSet(Enum): + """ + Preset markdown syntax extension bundles for :class:`~flet.Markdown`. + + The selected set controls which block/inline syntaxes are enabled while + parsing :attr:`flet.Markdown.value`. + """ + + NONE = "none" + """ + Basic markdown parsing without additional extension bundle. + """ + + COMMON_MARK = "commonMark" + """ + CommonMark-compatible extension set. + """ + + GITHUB_WEB = "gitHubWeb" + """ + GitHub web renderer style extension set. + """ + + GITHUB_FLAVORED = "gitHubFlavored" + """ + GitHub Flavored Markdown (GFM) extension set. + """ + + +@value +class MarkdownStyleSheet: + """ + Style overrides for markdown element rendering. + + Each field customizes one element group (headings, paragraphs, tables, + lists, block quotes, code blocks, etc.). Any `None` field keeps the + control's default styling for that property. + """ + + a_text_style: Optional[TextStyle] = None + """ + Text style for links (``). + """ + + p_text_style: Optional[TextStyle] = None + """ + Text style for paragraph blocks. + """ + + p_padding: Optional[PaddingValue] = None + """ + Padding around paragraph blocks. + """ + + code_text_style: Optional[TextStyle] = None + """ + Text style for inline code spans. + """ + + h1_text_style: Optional[TextStyle] = None + """ + Text style for level-1 headings. + """ + + h1_padding: Optional[PaddingValue] = None + """ + Padding around level-1 headings. + """ + + h2_text_style: Optional[TextStyle] = None + """ + Text style for level-2 headings. + """ + + h2_padding: Optional[PaddingValue] = None + """ + Padding around level-2 headings. + """ + + h3_text_style: Optional[TextStyle] = None + """ + Text style for level-3 headings. + """ + + h3_padding: Optional[PaddingValue] = None + """ + Padding around level-3 headings. + """ + + h4_text_style: Optional[TextStyle] = None + """ + Text style for level-4 headings. + """ + + h4_padding: Optional[PaddingValue] = None + """ + Padding around level-4 headings. + """ + + h5_text_style: Optional[TextStyle] = None + """ + Text style for level-5 headings. + """ + + h5_padding: Optional[PaddingValue] = None + """ + Padding around level-5 headings. + """ + + h6_text_style: Optional[TextStyle] = None + """ + Text style for level-6 headings. + """ + + h6_padding: Optional[PaddingValue] = None + """ + Padding around level-6 headings. + """ + + em_text_style: Optional[TextStyle] = None + """ + Text style for emphasized text. + """ + + strong_text_style: Optional[TextStyle] = None + """ + Text style for strong (bold) text. + """ + + del_text_style: Optional[TextStyle] = None + """ + Text style for deleted/strikethrough text. + """ + + blockquote_text_style: Optional[TextStyle] = None + """ + Text style for blockquote content. + """ + + img_text_style: Optional[TextStyle] = None + """ + Text style for image alt text / fallback labels. + """ + + checkbox_text_style: Optional[TextStyle] = None + """ + Text style for task-list checkbox labels. + """ + + block_spacing: Optional[Number] = None + """ + Vertical spacing between markdown block elements. + """ + + list_indent: Optional[Number] = None + """ + Indentation width for list items. + """ + + list_bullet_text_style: Optional[TextStyle] = None + """ + Text style for list bullets/markers. + """ + + list_bullet_padding: Optional[PaddingValue] = None + """ + Padding around list bullet markers. + """ + + table_head_text_style: Optional[TextStyle] = None + """ + Text style for table header cells. + """ + + table_body_text_style: Optional[TextStyle] = None + """ + Text style for table body cells. + """ + + table_head_text_align: Optional[TextAlign] = None + """ + Text alignment for table header cells. + """ + + table_padding: Optional[PaddingValue] = None + """ + Outer padding around rendered table blocks. + """ + + table_cells_padding: Optional[PaddingValue] = None + """ + Inner padding for each table cell. + """ + + blockquote_padding: Optional[PaddingValue] = None + """ + Inner padding for blockquote container. + """ + + table_cells_decoration: Optional[BoxDecoration] = None + """ + Decoration applied to table cells. + """ + + blockquote_decoration: Optional[BoxDecoration] = None + """ + Decoration applied to blockquote container. + """ + + codeblock_padding: Optional[PaddingValue] = None + """ + Inner padding for fenced code blocks. + """ + + codeblock_decoration: Optional[BoxDecoration] = None + """ + Decoration applied to fenced code blocks. + """ + + horizontal_rule_decoration: Optional[BoxDecoration] = None + """ + Decoration used to render horizontal rule separators. + """ + + blockquote_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for blockquote block content. + """ + + codeblock_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for code block content. + """ + + h1_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for level-1 heading blocks. + """ + + h2_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for level-2 heading blocks. + """ + + h3_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for level-3 heading blocks. + """ + + h4_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for level-4 heading blocks. + """ + + h5_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for level-5 heading blocks. + """ + + h6_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for level-6 heading blocks. + """ + + text_alignment: Optional[MainAxisAlignment] = None + """ + Default alignment for regular text blocks. + """ + + ordered_list_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for ordered list blocks. + """ + + unordered_list_alignment: Optional[MainAxisAlignment] = None + """ + Alignment for unordered list blocks. + """ + + +class MarkdownCodeTheme(Enum): + """ + Built-in code highlighting themes for markdown code blocks. + + Use with :attr:`flet.Markdown.code_theme` to choose + a predefined syntax highlighting palette by name. + """ + + A11Y_DARK = "a11y-dark" + """ + Uses the `a11y-dark` syntax highlighting theme. + """ + A11Y_LIGHT = "a11y-light" + """ + Uses the `a11y-light` syntax highlighting theme. + """ + AGATE = "agate" + """ + Uses the `agate` syntax highlighting theme. + """ + AN_OLD_HOPE = "an-old-hope" + """ + Uses the `an-old-hope` syntax highlighting theme. + """ + ANDROID_STUDIO = "androidstudio" + """ + Uses the `androidstudio` syntax highlighting theme. + """ + ARDUINO_LIGHT = "arduino-light" + """ + Uses the `arduino-light` syntax highlighting theme. + """ + ARTA = "arta" + """ + Uses the `arta` syntax highlighting theme. + """ + ASCETIC = "ascetic" + """ + Uses the `ascetic` syntax highlighting theme. + """ + ATELIER_CAVE_DARK = "atelier-cave-dark" + """ + Uses the `atelier-cave-dark` syntax highlighting theme. + """ + ATELIER_CAVE_LIGHT = "atelier-cave-light" + """ + Uses the `atelier-cave-light` syntax highlighting theme. + """ + ATELIER_DUNE_DARK = "atelier-dune-dark" + """ + Uses the `atelier-dune-dark` syntax highlighting theme. + """ + ATELIER_DUNE_LIGHT = "atelier-dune-light" + """ + Uses the `atelier-dune-light` syntax highlighting theme. + """ + ATELIER_ESTUARY_DARK = "atelier-estuary-dark" + """ + Uses the `atelier-estuary-dark` syntax highlighting theme. + """ + ATELIER_ESTUARY_LIGHT = "atelier-estuary-light" + """ + Uses the `atelier-estuary-light` syntax highlighting theme. + """ + ATELIER_FOREST_DARK = "atelier-forest-dark" + """ + Uses the `atelier-forest-dark` syntax highlighting theme. + """ + ATELIER_FOREST_LIGHT = "atelier-forest-light" + """ + Uses the `atelier-forest-light` syntax highlighting theme. + """ + ATELIER_HEATH_DARK = "atelier-heath-dark" + """ + Uses the `atelier-heath-dark` syntax highlighting theme. + """ + ATELIER_HEATH_LIGHT = "atelier-heath-light" + """ + Uses the `atelier-heath-light` syntax highlighting theme. + """ + ATELIER_LAKESIDE_DARK = "atelier-lakeside-dark" + """ + Uses the `atelier-lakeside-dark` syntax highlighting theme. + """ + ATELIER_LAKESIDE_LIGHT = "atelier-lakeside-light" + """ + Uses the `atelier-lakeside-light` syntax highlighting theme. + """ + ATELIER_PLATEAU_DARK = "atelier-plateau-dark" + """ + Uses the `atelier-plateau-dark` syntax highlighting theme. + """ + ATELIER_PLATEAU_LIGHT = "atelier-plateau-light" + """ + Uses the `atelier-plateau-light` syntax highlighting theme. + """ + ATELIER_SAVANNA_DARK = "atelier-savanna-dark" + """ + Uses the `atelier-savanna-dark` syntax highlighting theme. + """ + ATELIER_SAVANNA_LIGHT = "atelier-savanna-light" + """ + Uses the `atelier-savanna-light` syntax highlighting theme. + """ + ATELIER_SEASIDE_DARK = "atelier-seaside-dark" + """ + Uses the `atelier-seaside-dark` syntax highlighting theme. + """ + ATELIER_SEASIDE_LIGHT = "atelier-seaside-light" + """ + Uses the `atelier-seaside-light` syntax highlighting theme. + """ + ATELIER_SULPHURPOOL_DARK = "atelier-sulphurpool-dark" + """ + Uses the `atelier-sulphurpool-dark` syntax highlighting theme. + """ + ATELIER_SULPHURPOOL_LIGHT = "atelier-sulphurpool-light" + """ + Uses the `atelier-sulphurpool-light` syntax highlighting theme. + """ + ATOM_ONE_DARK_REASONABLE = "atom-one-dark-reasonable" + """ + Uses the `atom-one-dark-reasonable` syntax highlighting theme. + """ + ATOM_ONE_DARK = "atom-one-dark" + """ + Uses the `atom-one-dark` syntax highlighting theme. + """ + ATOM_ONE_LIGHT = "atom-one-light" + """ + Uses the `atom-one-light` syntax highlighting theme. + """ + BROWN_PAPER = "brown-paper" + """ + Uses the `brown-paper` syntax highlighting theme. + """ + CODEPEN_EMBED = "codepen-embed" + """ + Uses the `codepen-embed` syntax highlighting theme. + """ + COLOR_BREWER = "color-brewer" + """ + Uses the `color-brewer` syntax highlighting theme. + """ + DRACULA = "dracula" + """ + Uses the `dracula` syntax highlighting theme. + """ + DARK = "dark" + """ + Uses the `dark` syntax highlighting theme. + """ + DEFAULT = "default" + """ + Uses the `default` syntax highlighting theme. + """ + DOCCO = "docco" + """ + Uses the `docco` syntax highlighting theme. + """ + DRAGULA = "dracula" + """ + Uses the `dracula` syntax highlighting theme. + """ + FAR = "far" + """ + Uses the `far` syntax highlighting theme. + """ + FOUNDATION = "foundation" + """ + Uses the `foundation` syntax highlighting theme. + """ + GITHUB_GIST = "github-gist" + """ + Uses the `github-gist` syntax highlighting theme. + """ + GITHUB = "github" + """ + Uses the `github` syntax highlighting theme. + """ + GML = "gml" + """ + Uses the `gml` syntax highlighting theme. + """ + GOOGLE_CODE = "googlecode" + """ + Uses the `googlecode` syntax highlighting theme. + """ + GRADIENT_DARK = "gradient-dark" + """ + Uses the `gradient-dark` syntax highlighting theme. + """ + GRAYSCALE = "grayscale" + """ + Uses the `grayscale` syntax highlighting theme. + """ + GRUVBOX_DARK = "gruvbox-dark" + """ + Uses the `gruvbox-dark` syntax highlighting theme. + """ + GRUVBOX_LIGHT = "gruvbox-light" + """ + Uses the `gruvbox-light` syntax highlighting theme. + """ + HOPSCOTCH = "hopscotch" + """ + Uses the `hopscotch` syntax highlighting theme. + """ + HYBRID = "hybrid" + """ + Uses the `hybrid` syntax highlighting theme. + """ + IDEA = "idea" + """ + Uses the `idea` syntax highlighting theme. + """ + IR_BLACK = "ir-black" + """ + Uses the `ir-black` syntax highlighting theme. + """ + ISBL_EDITOR_DARK = "isbl-editor-dark" + """ + Uses the `isbl-editor-dark` syntax highlighting theme. + """ + ISBL_EDITOR_LIGHT = "isbl-editor-light" + """ + Uses the `isbl-editor-light` syntax highlighting theme. + """ + KIMBIE_DARK = "kimbie.dark" + """ + Uses the `kimbie.dark` syntax highlighting theme. + """ + KIMBIE_LIGHT = "kimbie.light" + """ + Uses the `kimbie.light` syntax highlighting theme. + """ + LIGHTFAIR = "lightfair" + """ + Uses the `lightfair` syntax highlighting theme. + """ + MAGULA = "magula" + """ + Uses the `magula` syntax highlighting theme. + """ + MONO_BLUE = "mono-blue" + """ + Uses the `mono-blue` syntax highlighting theme. + """ + MONOKAI_SUBLIME = "monokai-sublime" + """ + Uses the `monokai-sublime` syntax highlighting theme. + """ + MONOKAI = "monokai" + """ + Uses the `monokai` syntax highlighting theme. + """ + NIGHT_OWL = "night-owl" + """ + Uses the `night-owl` syntax highlighting theme. + """ + NORD = "nord" + """ + Uses the `nord` syntax highlighting theme. + """ + OBSIDIAN = "obsidian" + """ + Uses the `obsidian` syntax highlighting theme. + """ + OCEAN = "ocean" + """ + Uses the `ocean` syntax highlighting theme. + """ + PARAISEO_DARK = "paraiso-dark" + """ + Uses the `paraiso-dark` syntax highlighting theme. + """ + PARAISEO_LIGHT = "paraiso-light" + """ + Uses the `paraiso-light` syntax highlighting theme. + """ + POJOAQUE = "pojoaque" + """ + Uses the `pojoaque` syntax highlighting theme. + """ + PURE_BASIC = "purebasic" + """ + Uses the `purebasic` syntax highlighting theme. + """ + QT_CREATOR_DARK = "qtcreator_dark" + """ + Uses the `qtcreator_dark` syntax highlighting theme. + """ + QT_CREATOR_LIGHT = "qtcreator_light" + """ + Uses the `qtcreator_light` syntax highlighting theme. + """ + RAILSCASTS = "railscasts" + """ + Uses the `railscasts` syntax highlighting theme. + """ + RAINBOW = "rainbow" + """ + Uses the `rainbow` syntax highlighting theme. + """ + ROUTERS = "routers" + """ + Uses the `routers` syntax highlighting theme. + """ + SCHOOL_BOOK = "school-book" + """ + Uses the `school-book` syntax highlighting theme. + """ + SHADES_OF_PURPLE = "shades-of-purple" + """ + Uses the `shades-of-purple` syntax highlighting theme. + """ + SOLARIZED_DARK = "solarized-dark" + """ + Uses the `solarized-dark` syntax highlighting theme. + """ + SOLARIZED_LIGHT = "solarized-light" + """ + Uses the `solarized-light` syntax highlighting theme. + """ + SUNBURST = "sunburst" + """ + Uses the `sunburst` syntax highlighting theme. + """ + TOMORROW_NIGHT_BLUE = "tomorrow-night-blue" + """ + Uses the `tomorrow-night-blue` syntax highlighting theme. + """ + TOMORROW_NIGHT_BRIGHT = "tomorrow-night-bright" + """ + Uses the `tomorrow-night-bright` syntax highlighting theme. + """ + TOMORROW_NIGHT_EIGHTIES = "tomorrow-night-eighties" + """ + Uses the `tomorrow-night-eighties` syntax highlighting theme. + """ + TOMORROW_NIGHT = "tomorrow-night" + """ + Uses the `tomorrow-night` syntax highlighting theme. + """ + TOMORROW = "tomorrow" + """ + Uses the `tomorrow` syntax highlighting theme. + """ + VS = "vs" + """ + Uses the `vs` syntax highlighting theme. + """ + VS2015 = "vs2015" + """ + Uses the `vs2015` syntax highlighting theme. + """ + XCODE = "xcode" + """ + Uses the `xcode` syntax highlighting theme. + """ + XT256 = "xt256" + """ + Uses the `xt256` syntax highlighting theme. + """ + ZENBURN = "zenburn" + """ + Uses the `zenburn` syntax highlighting theme. + """ + + +@value +class MarkdownCustomCodeTheme: + """ + Custom text-style mapping for code token highlighting. + + Use this as :attr:`flet.Markdown.code_theme` when you + need per-token styling instead of a built-in + :class:`~flet.MarkdownCodeTheme`. + + Field names correspond to code token kinds (for example `keyword`, + `string`, `comment`). Unspecified fields keep default token styling. + """ + + addition: Optional[TextStyle] = None + """ + Style for inserted/added diff tokens. + """ + + attr: Optional[TextStyle] = None + """ + Style for attribute tokens. + """ + + attribute: Optional[TextStyle] = None + """ + Style for alternative attribute token name. + """ + + built_in: Optional[TextStyle] = None + """ + Style for built-in symbol tokens. + """ + + builtin_name: Optional[TextStyle] = None + """ + Style for built-in name tokens. + """ + + bullet: Optional[TextStyle] = None + """ + Style for bullet/list marker tokens. + """ + + class_name: Optional[TextStyle] = None + """ + Style for class name tokens. + """ + + code: Optional[TextStyle] = None + """ + Base style for code text. + """ + + comment: Optional[TextStyle] = None + """ + Style for comment tokens. + """ + + deletion: Optional[TextStyle] = None + """ + Style for removed/deleted diff tokens. + """ + + doctag: Optional[TextStyle] = None + """ + Style for documentation tag tokens. + """ + + emphasis: Optional[TextStyle] = None + """ + Style for emphasized tokens. + """ + + formula: Optional[TextStyle] = None + """ + Style for formula/math tokens. + """ + + function: Optional[TextStyle] = None + """ + Style for function identifier tokens. + """ + + keyword: Optional[TextStyle] = None + """ + Style for keyword tokens. + """ + + link: Optional[TextStyle] = None + """ + Style for link tokens. + """ + + link_label: Optional[TextStyle] = None + """ + Style for link label tokens. + """ + + literal: Optional[TextStyle] = None + """ + Style for literal constant tokens. + """ + + meta: Optional[TextStyle] = None + """ + Style for metadata tokens. + """ + + meta_keyword: Optional[TextStyle] = None + """ + Style for metadata keyword tokens. + """ + + meta_string: Optional[TextStyle] = None + """ + Style for metadata string tokens. + """ + + name: Optional[TextStyle] = None + """ + Style for generic name/identifier tokens. + """ + + number: Optional[TextStyle] = None + """ + Style for numeric literal tokens. + """ + + operator: Optional[TextStyle] = None + """ + Style for operator tokens. + """ + + params: Optional[TextStyle] = None + """ + Style for parameter list tokens. + """ + + pattern_match: Optional[TextStyle] = None + """ + Style for pattern matching tokens. + """ + + quote: Optional[TextStyle] = None + """ + Style for quote/blockquote tokens. + """ + + regexp: Optional[TextStyle] = None + """ + Style for regular expression tokens. + """ + + root: Optional[TextStyle] = None + """ + Base style for root code container. + """ + + section: Optional[TextStyle] = None + """ + Style for section heading tokens. + """ + + selector_attr: Optional[TextStyle] = None + """ + Style for CSS selector attribute tokens. + """ + + selector_class: Optional[TextStyle] = None + """ + Style for CSS selector class tokens. + """ + + selector_id: Optional[TextStyle] = None + """ + Style for CSS selector id tokens. + """ + + selector_pseudo: Optional[TextStyle] = None + """ + Style for CSS selector pseudo-class tokens. + """ + + selector_tag: Optional[TextStyle] = None + """ + Style for CSS selector tag tokens. + """ + + string: Optional[TextStyle] = None + """ + Style for string literal tokens. + """ + + strong: Optional[TextStyle] = None + """ + Style for strong/bold tokens. + """ + + stronge: Optional[TextStyle] = None + """ + Legacy/alternate token key style for strong text. + """ + + subst: Optional[TextStyle] = None + """ + Style for substitution/interpolation tokens. + """ + + subtr: Optional[TextStyle] = None + """ + Legacy/alternate token key style for substitution tokens. + """ + + symbol: Optional[TextStyle] = None + """ + Style for symbol tokens. + """ + + tag: Optional[TextStyle] = None + """ + Style for markup tag tokens. + """ + + template_tag: Optional[TextStyle] = None + """ + Style for template tag tokens. + """ + + template_variable: Optional[TextStyle] = None + """ + Style for template variable tokens. + """ + + title: Optional[TextStyle] = None + """ + Style for title/name tokens. + """ + + type: Optional[TextStyle] = None + """ + Style for type annotation tokens. + """ + + variable: Optional[TextStyle] = None + """ + Style for variable identifier tokens. + """ + + +@control("Markdown") +class Markdown(LayoutControl): + """ + Renders text in markdown format. + + ```python + ft.Markdown( + value="# Welcome\\n\\nThis is **Markdown** rendered in Flet.", + width=260, + ) + ``` + """ + + value: str = "" + """ + Markdown content to render. + """ + + selectable: bool = False + """ + Whether rendered text is selectable or not. + """ + + extension_set: MarkdownExtensionSet = MarkdownExtensionSet.NONE + """ + The extensions to use when rendering the markdown content. + """ + + code_theme: Optional[Union[MarkdownCodeTheme, MarkdownCustomCodeTheme]] = None + """ + A syntax highlighting theme for code blocks. + + Defaults to `MarkdownCodeTheme.GITHUB`. + """ + + auto_follow_links: bool = False + """ + Automatically open URLs in the document. + + If registered, `on_tap_link` event is fired after that. + """ + + shrink_wrap: bool = True + """ + Whether the extent of the scroll view in the scroll direction should be determined \ + by the contents being viewed. + """ + + fit_content: bool = True + """ + Whether to allow the widget to fit the child content. + """ + + soft_line_break: bool = False + """ + The soft line break is used to identify the spaces at the end of a line of text \ + and the leading spaces in the immediately following the line of text. + """ + + auto_follow_links_target: Optional[UrlTarget] = None + """ + Where to open URL in the web mode. + """ + + image_error_content: Optional[Control] = None + """ + The control to display when an image fails to load. + """ + + code_style_sheet: Optional[MarkdownStyleSheet] = None + """ + The styles to use when displaying the code blocks. + """ + + md_style_sheet: Optional[MarkdownStyleSheet] = None + """ + The styles to use when displaying the markdown. + """ + + latex_scale_factor: Optional[float] = None + """ + The scale factor for LaTeX formulas rendering. + Controls the size of rendered mathematical expressions. + """ + + latex_style: Optional[TextStyle] = None + """ + The text style to apply to LaTeX formulas. + Allows customization of font, color, and other text properties + for mathematical expressions. + """ + + on_tap_text: Optional[ControlEventHandler["Markdown"]] = None + """ + Called when some text is clicked/tapped. + """ + + on_selection_change: Optional[ + EventHandler[TextSelectionChangeEvent["Markdown"]] + ] = None + """ + Called when the text selection changes. + """ + + on_tap_link: Optional[ControlEventHandler["Markdown"]] = None + """ + Called when a link within Markdown document is clicked/tapped. + + The :attr:`~flet.Event.data` property of the event handler argument + contains the clickedURL. + + Example: + https://github.com/flet-dev/examples/blob/main/python/controls/information-displays/markdown/markdown-event-example.py + """ # noqa: E501 diff --git a/sdk/python/packages/flet/src/flet/controls/core/merge_semantics.py b/sdk/python/packages/flet/src/flet/controls/core/merge_semantics.py new file mode 100644 index 0000000000..f0ea658789 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/merge_semantics.py @@ -0,0 +1,24 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control + +__all__ = ["MergeSemantics"] + + +@control("MergeSemantics") +class MergeSemantics(Control): + """ + A control that merges the semantics of its descendants. + + Causes all the semantics of the subtree rooted at this node to be merged into one + node in the semantics tree. + + Used by accessibility tools, search engines, and other semantic analysis software + to determine the meaning of the application. + """ + + content: Optional[Control] = None + """ + The `Control` to annotate. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/page_view.py b/sdk/python/packages/flet/src/flet/controls/core/page_view.py new file mode 100644 index 0000000000..d9e4fd36ee --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/page_view.py @@ -0,0 +1,233 @@ +from dataclasses import field +from typing import Annotated, Optional + +from flet.controls.animation import AnimationCurve +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.duration import Duration, DurationValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ClipBehavior, Number +from flet.utils.validation import V + +__all__ = ["PageView"] + + +DEFAULT_ANIMATION_DURATION = Duration(seconds=1) +DEFAULT_ANIMATION_CURVE = AnimationCurve.LINEAR + + +@control("PageView") +class PageView(LayoutControl): + """ + Displays its child :attr:`controls` one page at a time and lets users swipe + between them, similar to a carousel. + + It is helpful for onboarding flows, photo carousels, + or any scenario where content is divided into discrete full-width pages. + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of controls to display, one per page, in the order they should appear. + """ + + selected_index: Annotated[ + int, + V.ge(0), + ] = 0 + """ + The zero-based index of the currently visible page. + + Changing it later on (followed by :meth:`~flet.BaseControl.update`) + jumps to the specified page without animation. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + keep_page: bool = True + """ + Whether this page view should restore the most recently viewed page when rebuilt. + """ + + horizontal: bool = True + """ + Whether the pages should be arranged and scrolled horizontally. + + `False` implies vertical arrangement and scrolling. + """ + + reverse: bool = False + """ + Whether to reverse the order in which pages are read and swiped. + + For example, if the reading direction is left-to-right and + :attr:`horizontal` is `True`, then this page view scrolls from + left to right when `reverse` is `False` and from right to left when + `reverse` is `True`. + + Similarly, if :attr:`horizontal` is `False`, then this page view + scrolls from top to bottom when `reverse` is `False` and from bottom to top + when `reverse` is `True`. + """ + + viewport_fraction: Annotated[ + Number, + V.gt(0), + ] = 1.0 + """ + The fraction of the viewport that each page should occupy in the + scrolling direction (see :attr:`horizontal`). + + For example, `1.0` (default), means each page fills the viewport. + + Raises: + ValueError: If it is not strictly greater than `0`. + """ + + snap: bool = True + """ + Whether the view should snap to exact page boundaries after a drag. + + If the :attr:`pad_ends` is `False` and :attr:`viewport_fraction` < `1.0`, + the page will snap to the beginning of the viewport; otherwise, the page + will snap to the center of the viewport. + """ + + implicit_scrolling: bool = False + """ + Whether to allow adjacent pages to render partially before the user scrolls to them, + enabling smoother transitions and improved accessibility by allowing focus to move + seamlessly between pages during navigation. + + With this flag set to `False`, when accessibility focus reaches the end of + the current page and the user attempts to move it to the next element, the + focus will traverse to the next widget outside of the page view. + + With this flag set to `True`, when accessibility focus reaches the end of + the current page and user attempts to move it to the next element, focus + will traverse to the next page in the page view. + """ + + pad_ends: bool = True + """ + Whether to add padding to both ends of the list. + + If this is set to `True` and :attr:`viewport_fraction` < `1.0`, + padding will be added before the first page and after the last page so they snap + to the center of the viewport when scrolled all the way to the start or end. + + Note: + If :attr:`viewport_fraction` >= 1.0, this property has no effect. + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + Defines how pages are clipped if they overflow their bounds. + """ + + on_change: Optional[ControlEventHandler["PageView"]] = None + """ + Fired when the visible page changes. + + The :attr:`~flet.Event.data` property of the event argument contains + the index of the new page. + """ + + async def go_to_page( + self, + index: int, + animation_duration: DurationValue = DEFAULT_ANIMATION_DURATION, + animation_curve: AnimationCurve = DEFAULT_ANIMATION_CURVE, + ): + """ + Animates to the page at `index`. + + Args: + index: The index of the page to show. + animation_duration: Length of the animation. + animation_curve: The easing curve of the animation. + + Raises: + ValueError: If `index` is negative. + """ + if index < 0: + raise ValueError(f"index must be greater than or equal to 0, got {index}") + + await self._invoke_method( + "go_to_page", + {"index": index, "duration": animation_duration, "curve": animation_curve}, + ) + + async def jump_to_page(self, index: int): + """ + Jumps immediately to the page at `index` without animation, moving the page + position from its current value to the given value without animation nor + range checking. + + Args: + index: The index of the page to show. + + Raises: + ValueError: If `index` is negative. + """ + if index < 0: + raise ValueError(f"index must be greater than or equal to 0, got {index}") + + await self._invoke_method("jump_to_page", {"index": index}) + + async def jump_to(self, value: Number): + """ + Immediately sets the scroll position to the given value, without animation + and without validating whether the value is within bounds. + + Any active scrolling or animation is canceled. + + If the scroll position changes, a start/update/end sequence of scroll + notifications is dispatched. This method does not generate overscroll + notifications. + + After the jump, a ballistic activity is initiated if the value is outside + the valid scroll range. + + Args: + value: The new scroll position. + """ + await self._invoke_method("jump_to", {"value": value}) + + async def next_page( + self, + animation_duration: DurationValue = DEFAULT_ANIMATION_DURATION, + animation_curve: AnimationCurve = DEFAULT_ANIMATION_CURVE, + ): + """ + Animates to the next page. Same as calling + :meth:`~flet.PageView.go_to_page` with `selected_index + 1`. + + Args: + animation_duration: Length of the animation. + animation_curve: The easing curve of the animation. + """ + await self._invoke_method( + "next_page", + {"duration": animation_duration, "curve": animation_curve}, + ) + + async def previous_page( + self, + animation_duration: DurationValue = DEFAULT_ANIMATION_DURATION, + animation_curve: AnimationCurve = DEFAULT_ANIMATION_CURVE, + ): + """ + Animates to the previous page. Same as calling + :meth:`~flet.PageView.go_to_page` with `selected_index - 1`. + + Args: + animation_duration: Length of the animation. + animation_curve: The easing curve of the animation. + """ + await self._invoke_method( + "previous_page", + {"duration": animation_duration, "curve": animation_curve}, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/core/pagelet.py b/sdk/python/packages/flet/src/flet/controls/core/pagelet.py new file mode 100644 index 0000000000..805271d41a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/pagelet.py @@ -0,0 +1,139 @@ +from typing import Annotated, Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar +from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar +from flet.controls.layout_control import LayoutControl +from flet.controls.material.app_bar import AppBar +from flet.controls.material.bottom_app_bar import BottomAppBar +from flet.controls.material.navigation_bar import NavigationBar +from flet.controls.material.navigation_drawer import NavigationDrawer +from flet.controls.transform import OffsetValue +from flet.controls.types import ColorValue, FloatingActionButtonLocation +from flet.utils.validation import V + +__all__ = ["Pagelet"] + + +@control("Pagelet") +class Pagelet(LayoutControl, AdaptiveControl): + """ + Implements the basic Material Design visual layout structure. + + Use it for projects that require a "page within a page" layouts with its own + :class:`~flet.AppBar`, :class:`~flet.BottomAppBar`, :class:`~flet.NavigationDrawer`, + such as demos and galleries. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + A child Control contained by this Pagelet. + + The control in the content of the Pagelet is positioned at the top-left of the + available space between the app bar and the bottom of the Pagelet. + + Raises: + ValueError: If it is not visible. + """ + + appbar: Optional[Union[AppBar, CupertinoAppBar]] = None + """ + An :class:`~flet.AppBar` control to display at the top of the Pagelet. + """ + + navigation_bar: Optional[Union[NavigationBar, CupertinoNavigationBar]] = None + """ + A navigation bar (:class:`~flet.NavigationBar` or \ + :class:`~flet.CupertinoNavigationBar`) control to display at the bottom of the \ + `Pagelet`. + + Note: + If both the `navigation_bar` and :attr:`bottom_appbar` + properties are specified, `navigation_bar` takes precedence and will + be displayed. + """ + + bottom_appbar: Optional[BottomAppBar] = None + """ + A :class:`~flet.BottomAppBar` control to display at the bottom of this Pagelet. + + Note: + If both the `bottom_appbar` and :attr:`navigation_bar` + properties are specified, `bottom_appbar` takes precedence and will + be displayed. + """ + + bottom_sheet: Optional[Control] = None + """ + The persistent bottom sheet to show information that supplements the primary \ + content of this Pagelet. + """ + + drawer: Optional[NavigationDrawer] = None + """ + A :class:`~flet.NavigationDrawer` control to display as a panel sliding from the \ + start edge of the page. + """ + + end_drawer: Optional[NavigationDrawer] = None + """ + A :class:`~flet.NavigationDrawer` control to display as a panel sliding from the \ + end edge of the page. + """ + + floating_action_button: Optional[Control] = None + """ + A :class:`~flet.FloatingActionButton` + control to display on top of this Pagelet's content. + """ + + floating_action_button_location: Optional[ + Union[FloatingActionButtonLocation, OffsetValue] + ] = FloatingActionButtonLocation.END_FLOAT + """ + Defines the position of the :attr:`floating_action_button`. + """ + + bgcolor: Optional[ColorValue] = None + """ + Background color of this Pagelet. + """ + + async def show_drawer(self): + """ + Show the drawer. + + Raises: + ValueError: If no :attr:`drawer` is defined. + """ + if self.drawer is None: + raise ValueError("No drawer defined") + await self._invoke_method("show_drawer") + + async def close_drawer(self): + """ + Close the drawer. + """ + await self._invoke_method("close_drawer") + + async def show_end_drawer(self): + """ + Show the end drawer. + + Raises: + ValueError: If no :attr:`end_drawer` is defined. + """ + if self.end_drawer is None: + raise ValueError("No end_drawer defined") + await self._invoke_method("show_end_drawer") + + async def close_end_drawer(self): + """ + Close the end drawer. + """ + await self._invoke_method("close_end_drawer") diff --git a/sdk/python/packages/flet/src/flet/controls/core/placeholder.py b/sdk/python/packages/flet/src/flet/controls/core/placeholder.py new file mode 100644 index 0000000000..609ce0be84 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/placeholder.py @@ -0,0 +1,49 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.colors import Colors +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ColorValue, Number + +__all__ = ["Placeholder"] + + +@control("Placeholder") +class Placeholder(LayoutControl): + """ + A placeholder box. + + ```python + ft.Placeholder( + expand=True, + color=ft.Colors.RED_500, + ) + ``` + + """ + + content: Optional[Control] = None + """ + An optional `Control` to display inside the placeholder. + """ + + color: ColorValue = Colors.BLUE_GREY_700 + """ + The color of the placeholder box. + """ + + fallback_height: Number = 400.0 + """ + The height to use when the placeholder is in a situation with an unbounded height. + """ + + fallback_width: Number = 400.0 + """ + The width to use when the placeholder is in a situation with an unbounded width. + """ + + stroke_width: Optional[Number] = 2.0 + """ + The width of the lines in the placeholder box. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/reorderable_drag_handle.py b/sdk/python/packages/flet/src/flet/controls/core/reorderable_drag_handle.py new file mode 100644 index 0000000000..fd7e1c3249 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/reorderable_drag_handle.py @@ -0,0 +1,52 @@ +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import MouseCursor +from flet.utils.validation import V + + +@control("ReorderableDragHandle") +class ReorderableDragHandle(LayoutControl, AdaptiveControl): + """ + Used to drag an item in a :class:`~flet.ReorderableListView`. + + It creates a listener for a drag immediately following a pointer down + event over the given :attr:`content` control. + + Example: + ```python + ft.ReorderableListView( + show_default_drag_handles=False, + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), + leading=ft.ReorderableDragHandle( + content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), + mouse_cursor=ft.MouseCursor.GRAB, + ), + ) + for i in range(10) + ], + ) + ``` + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The control for which the application would like to respond to a tap and drag \ + gesture by starting a reordering drag on a reorderable list. + + Raises: + ValueError: If it is not visible. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The mouse cursor for mouse pointers that are hovering over the control. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/responsive_row.py b/sdk/python/packages/flet/src/flet/controls/core/responsive_row.py new file mode 100644 index 0000000000..cbde315559 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/responsive_row.py @@ -0,0 +1,123 @@ +from dataclasses import field +from typing import Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.types import ( + CrossAxisAlignment, + MainAxisAlignment, + Number, + ResponsiveNumber, + ResponsiveRowBreakpoint, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["ResponsiveNumber", "ResponsiveRow", "ResponsiveRowBreakpoint"] + + +@control("ResponsiveRow") +class ResponsiveRow(LayoutControl, ScrollableControl, AdaptiveControl): + """ + Allows aligning child controls to virtual columns. + + By default, a virtual grid has 12 columns, but that can be customized with + :attr:`columns` property. + + Similar to `expand` property, every control has :attr:`~flet.Control.col` + property which allows specifying how many columns a control should span. + + Use :attr:`~flet.ScrollableControl.scroll` to enable vertical scrolling when + the responsive content is taller than the available height. + + Example: + ```python + ft.ResponsiveRow( + controls=[ + ft.Button( + f"Button {i}", + color=ft.Colors.BLUE_GREY_300, + col={ + ft.ResponsiveRowBreakpoint.XS: 12, + ft.ResponsiveRowBreakpoint.MD: 6, + ft.ResponsiveRowBreakpoint.LG: 3, + }, + ) + for i in range(1, 6) + ], + ) + ``` + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of Controls to display. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ctrl.columns > 0 + if isinstance(ctrl.columns, (int, float)) + else all(v > 0 for v in ctrl.columns.values()) + ), + message="columns must be greater than 0 for all breakpoints", + ), + ) + + columns: ResponsiveNumber = 12 + """ + The number of virtual columns to layout children. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If any breakpoint-specific value is not strictly greater than `0`. + """ + + alignment: MainAxisAlignment = MainAxisAlignment.START + """ + Defines how the child :attr:`controls` should be placed horizontally. + """ + + vertical_alignment: CrossAxisAlignment = CrossAxisAlignment.START + """ + Defines how the child :attr:`controls` should be placed vertically. + """ + + spacing: ResponsiveNumber = 10 + """ + The spacing between controls in a row in virtual pixels. + + Note: + Has effect only when :attr:`alignment` is set to + :attr:`flet.MainAxisAlignment.START`, :attr:`flet.MainAxisAlignment.END`, + or :attr:`flet.MainAxisAlignment.CENTER`. + """ + + run_spacing: ResponsiveNumber = 10 + """ + The spacing between runs. + """ + + breakpoints: dict[Union[ResponsiveRowBreakpoint, str], Number] = field( + default_factory=lambda: { + ResponsiveRowBreakpoint.XS: 0, + ResponsiveRowBreakpoint.SM: 576, + ResponsiveRowBreakpoint.MD: 768, + ResponsiveRowBreakpoint.LG: 992, + ResponsiveRowBreakpoint.XL: 1200, + ResponsiveRowBreakpoint.XXL: 1400, + } + ) + """ + Defines the minimum widths (in px) for each breakpoint key used by responsive \ + properties such as :attr:`~flet.Control.col`, :attr:`~flet.ResponsiveRow.spacing`, \ + and :attr:`~flet.ResponsiveRow.run_spacing`. + + Keys can be :class:`~flet.ResponsiveRowBreakpoint` values or custom strings. + Breakpoint names in responsive values must match the names used here. + + The default mirrors Bootstrap breakpoints. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/rotated_box.py b/sdk/python/packages/flet/src/flet/controls/core/rotated_box.py new file mode 100644 index 0000000000..93021d4b49 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/rotated_box.py @@ -0,0 +1,32 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl + +__all__ = ["RotatedBox"] + + +@control("RotatedBox") +class RotatedBox(LayoutControl): + """ + Rotates its :attr:`content` by an integral number of quarter turns. + + Unlike :attr:`flet.LayoutControl.rotate` (which uses + `Transform.rotate` and applies the rotation only at paint time), + `RotatedBox` applies the rotation before layout. This means the control's + rotated dimensions participate in layout and can affect surrounding + controls. + """ + + quarter_turns: int = 0 + """ + The number of clockwise quarter turns. + + For example, `1` rotates by 90 degrees, `2` by 180 degrees. + """ + + content: Optional[Control] = None + """ + The `Control` to rotate. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/row.py b/sdk/python/packages/flet/src/flet/controls/core/row.py new file mode 100644 index 0000000000..70993e8d69 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/row.py @@ -0,0 +1,104 @@ +from dataclasses import field + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.types import CrossAxisAlignment, MainAxisAlignment, Number + +__all__ = ["Row"] + + +@control("Row") +class Row(LayoutControl, ScrollableControl, AdaptiveControl): + """ + Displays its children in a horizontal array. + + To cause a child control to expand and fill the available horizontal space, set + its :attr:`~flet.Control.expand` property. + + Example: + ```python + ft.Row( + controls=[ + ft.Card( + shape=ft.ContinuousRectangleBorder(radius=10), + content=ft.Container( + padding=5, + border_radius=ft.BorderRadius.all(5), + bgcolor=ft.Colors.AMBER_100, + content=ft.Text(f"Control {i}"), + ), + ) + for i in range(1, 6) + ], + ) + ``` + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of Controls to display. + """ + + alignment: MainAxisAlignment = MainAxisAlignment.START + """ + Defines how the child :attr:`controls` should be placed horizontally. + """ + + vertical_alignment: CrossAxisAlignment = CrossAxisAlignment.CENTER + """ + Defines how the child :attr:`controls` should be placed vertically. + + Note: + When :attr:`wrap` is `True`, this property doesn't support + :attr:`flet.CrossAxisAlignment.STRETCH` or + :attr:`flet.CrossAxisAlignment.BASELINE`. If either is used, + :attr:`flet.CrossAxisAlignment.CENTER` will be applied instead. + """ + + spacing: Number = 10 + """ + The spacing between the child :attr:`controls`. + + Note: + Has effect only when :attr:`alignment` is set to + :attr:`flet.MainAxisAlignment.START`, :attr:`flet.MainAxisAlignment.END`, + or :attr:`flet.MainAxisAlignment.CENTER`. + """ + + tight: bool = False + """ + Whether this row should occupy all available horizontal space (`True`), or only as \ + much as needed by its children :attr:`controls` (`False`). + + Note: + Has effect only when :attr:`wrap` is `False`. + """ + + wrap: bool = False + """ + Whether this row should put child :attr:`controls` into additional rows (runs) if \ + they don't fit in a single row. + """ + + run_spacing: Number = 10 + """ + The spacing between runs when :attr:`wrap` is `True`. + """ + + run_alignment: MainAxisAlignment = MainAxisAlignment.START + """ + How the runs should be placed in the cross-axis when :attr:`wrap` is `True`. + """ + + intrinsic_height: bool = False + """ + Whether this row should be as tall as the tallest child control in \ + :attr:`controls`. + """ + + def init(self): + super().init() + self._internals["host_expanded"] = True diff --git a/sdk/python/packages/flet/src/flet/controls/core/safe_area.py b/sdk/python/packages/flet/src/flet/controls/core/safe_area.py new file mode 100644 index 0000000000..d77b98b352 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/safe_area.py @@ -0,0 +1,76 @@ +from typing import Annotated + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.utils.validation import V + +__all__ = ["SafeArea"] + + +@control("SafeArea") +class SafeArea(LayoutControl, AdaptiveControl): + """ + A control that insets its :attr:`content` by sufficient padding to avoid \ + intrusions by the operating system. + + For example, this will indent the `content` by enough to avoid the status bar at + the top of the screen. + + It will also indent the `content` by the amount necessary to avoid the Notch on the + iPhone X, or other similar creative physical features of the display. + + When a :attr:`minimum_padding` is specified, the greater of the minimum padding + or the safe area padding will be applied. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The control to display. + + Raises: + ValueError: If it is not visible. + """ + + avoid_intrusions_left: bool = True + """ + Whether to avoid system intrusions on the left. + """ + + avoid_intrusions_top: bool = True + """ + Whether to avoid system intrusions at the top of the screen, typically the system \ + status bar. + """ + + avoid_intrusions_right: bool = True + """ + Whether to avoid system intrusions on the right. + """ + + avoid_intrusions_bottom: bool = True + """ + Whether to avoid system intrusions on the bottom side of the screen. + """ + + # TODO: improve docstring (remove Flutter specific details) + maintain_bottom_view_padding: bool = False + """ + Specifies whether the `SafeArea` should maintain the bottom \ + `MediaQueryData.viewPadding` instead of the bottom `MediaQueryData.padding`. + + This avoids layout shifts caused by keyboard overlays, useful when flexible + controls are used. + """ + + minimum_padding: PaddingValue = 0 + """ + The minimum padding to apply. + + The greater of the minimum insets and the media padding will be applied. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/screenshot.py b/sdk/python/packages/flet/src/flet/controls/core/screenshot.py new file mode 100644 index 0000000000..dee63cbac0 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/screenshot.py @@ -0,0 +1,41 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.duration import DurationValue +from flet.controls.types import Number + +__all__ = ["Screenshot"] + + +@control("Screenshot") +class Screenshot(Control): + """ + Takes a screenshot of containing control. + """ + + content: Control + """ + The control to be captured. + """ + + async def capture( + self, + pixel_ratio: Optional[Number] = None, + delay: Optional[DurationValue] = None, + ) -> bytes: + """ + Captures a screenshot of the enclosed content control. + + Args: + pixel_ratio: A pixel ratio of the captured screenshot. + If `None`, device-specific pixel ratio will be used. + delay: A delay before taking a screenshot. + The delay will be 20 milliseconds if not specified. + + Returns: + Screenshot in PNG format. + """ + return await self._invoke_method( + "capture", arguments={"pixel_ratio": pixel_ratio, "delay": delay} + ) diff --git a/sdk/python/packages/flet/src/flet/controls/core/semantics.py b/sdk/python/packages/flet/src/flet/controls/core/semantics.py new file mode 100644 index 0000000000..681c17080d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/semantics.py @@ -0,0 +1,294 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.material.badge import BadgeValue +from flet.controls.types import Number + +__all__ = ["Semantics"] + + +@control("Semantics") +class Semantics(Control): + """ + Provides semantic annotations for the control tree, describing the meaning and \ + purpose of controls. + + These annotations are utilized by accessibility tools, search engines, + and semantic analysis software to better understand the structure and + functionality of the application. + """ + + content: Optional[Control] = None + """ + The Control to annotate. + """ + + label: Optional[str] = None + """ + A textual description of the :attr:`content`. + """ + + expanded: Optional[bool] = None + """ + Whether this subtree represents something that can be in an "expanded" or \ + "collapsed" state. + """ + + hidden: Optional[bool] = None + """ + Whether this subtree is currently hidden. + """ + + selected: Optional[bool] = None + """ + Whether this subtree represents something that can be in a selected or unselected \ + state, and what its current state is. + """ + + button: Optional[bool] = None + """ + Whether this subtree represents a button. + """ + + obscured: Optional[bool] = None + """ + Whether :attr:`value` should be obscured. + """ + + multiline: Optional[bool] = None + """ + Whether the :attr:`value` is coming from a field that supports multiline text \ + editing. + """ + + focusable: Optional[bool] = None + """ + Whether the node is able to hold input focus. + """ + + read_only: Optional[bool] = None + """ + Whether this subtree is read only. + """ + + focus: Optional[bool] = None + """ + Whether the node currently holds input focus. + """ + + slider: Optional[bool] = None + """ + Whether this subtree represents a slider. + """ + + tooltip: Optional[str] = None + """ + A textual description of the widget's tooltip. + """ + + badge: Optional[BadgeValue] = None + """ + TBD + """ + + toggled: Optional[bool] = None + """ + Whether this subtree represents a toggle switch or similar widget with an "on" \ + state, and what its current state is. + """ + + max_value_length: Optional[Number] = None + """ + The maximum number of characters that can be entered into an editable text field. + """ + + checked: Optional[bool] = None + """ + Whether this subtree represents a checkbox or similar widget with a "checked" \ + state, and what its current state is. + """ + + value: Optional[str] = None + """ + A textual description of the `value` of the `content` control. + """ + + increased_value: Optional[str] = None + """ + The value that the semantics node represents when it is increased. + """ + + decreased_value: Optional[str] = None + """ + The value that the semantics node represents when it is decreased. + """ + + hint_text: Optional[str] = None + """ + A brief textual description of the result of an action performed on the `content` \ + control. + """ + + on_tap_hint_text: Optional[str] = None + """ + TBD + """ + + current_value_length: Optional[int] = None + """ + The current number of characters that have been entered into an editable text \ + field. + """ + + heading_level: Optional[int] = None + """ + The heading level in the DOM document structure. + """ + + exclude_semantics: bool = False + """ + TBD + """ + + mixed: Optional[bool] = None + """ + Whether this subtree represents a checkbox or similar control with a \ + "half-checked" state or similar, and whether it is currently in this half-checked \ + state. + """ + + on_long_press_hint_text: Optional[str] = None + """ + TBD + """ + + container: Optional[bool] = None + """ + TBD + """ + + live_region: Optional[bool] = None + """ + Whether this subtree should be considered a live region. + """ + + textfield: Optional[bool] = None + """ + Whether this subtree represents a text field. + """ + + link: Optional[bool] = None + """ + Whether this subtree represents a link. + """ + + header: Optional[bool] = None + """ + Whether this subtree represents a header. + """ + + image: Optional[bool] = None + """ + Whether the node represents an image. + """ + + on_tap: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when this control is tapped. + """ + + on_double_tap: Optional[ControlEventHandler["Semantics"]] = None + """ + TBD + """ + + on_increase: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the value represented by the semantics node is increased. + """ + + on_decrease: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the value represented by the semantics node is decreased. + """ + + on_dismiss: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the node is dismissed. + """ + + on_scroll_left: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when a user moves their finger across the screen from right to left. + """ + + on_scroll_right: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when a user moves their finger across the screen from left to right. + """ + + on_scroll_up: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when a user moves their finger across the screen from bottom to top. + """ + + on_scroll_down: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when a user moves their finger across the screen from top to bottom. + """ + + on_copy: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the current selection is copied to the clipboard. + """ + + on_cut: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the current selection is cut to the clipboard. + """ + + on_paste: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the current content of the clipboard is pasted. + """ + + on_long_press: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the node is long-pressed (pressing and holding the screen with the \ + finger for a few seconds without moving it). + """ + + on_move_cursor_forward_by_character: Optional[ControlEventHandler["Semantics"]] = ( + None + ) + """ + Called when the cursor is moved forward by one character. + """ + + on_move_cursor_backward_by_character: Optional[ControlEventHandler["Semantics"]] = ( + None + ) + """ + Called when the cursor is moved backward by one character. + """ + + on_did_gain_accessibility_focus: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the node has gained accessibility focus. + """ + + on_did_lose_accessibility_focus: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when the node has lost accessibility focus. + """ + + on_set_text: Optional[ControlEventHandler["Semantics"]] = None + """ + Called when a user wants to replace the current text in the text field with a new \ + text. + + Voice access users can trigger this handler by speaking type `` to their + Android devices. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/shader_mask.py b/sdk/python/packages/flet/src/flet/controls/core/shader_mask.py new file mode 100644 index 0000000000..6a28f15569 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/shader_mask.py @@ -0,0 +1,56 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.control import Control +from flet.controls.gradients import Gradient +from flet.controls.layout_control import LayoutControl +from flet.controls.types import BlendMode + +__all__ = ["ShaderMask"] + + +@control("ShaderMask") +class ShaderMask(LayoutControl): + """ + Applies a mask generated by a shader to its :attr:`content`. + + For example, it can be used to gradually fade out the edge of a control by + using a :class:`~flet.LinearGradient` mask. + + ```python + ft.ShaderMask( + blend_mode=ft.BlendMode.MULTIPLY, + shader=ft.LinearGradient( + begin=ft.Alignment.CENTER_LEFT, + end=ft.Alignment.CENTER_RIGHT, + colors=[ft.Colors.WHITE, ft.Colors.BLACK], + tile_mode=ft.GradientTileMode.CLAMP, + ), + content=ft.Image( + src="https://picsum.photos/id/288/300/300", + height=300, + fit=ft.BoxFit.FILL, + ) + ``` + """ + + shader: Gradient + """ + Use gradient as a shader. + """ + + content: Optional[Control] = None + """ + The Control to which the :attr:`shader` is applied. + """ + + blend_mode: BlendMode = BlendMode.MODULATE + """ + The blend mode to use when applying the shader to the :attr:`content`. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The radius of the mask. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/shimmer.py b/sdk/python/packages/flet/src/flet/controls/core/shimmer.py new file mode 100644 index 0000000000..445e03d035 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/shimmer.py @@ -0,0 +1,123 @@ +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.duration import DurationValue +from flet.controls.gradients import Gradient +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["Shimmer", "ShimmerDirection"] + + +class ShimmerDirection(Enum): + """ + Direction of the shimmering gradient animation. + """ + + LTR = "ltr" + """ + The shimmer moves from left to right. + """ + + RTL = "rtl" + """ + The shimmer moves from right to left. + """ + + TTB = "ttb" + """ + The shimmer moves from top to bottom. + """ + + BTT = "btt" + """ + The shimmer moves from bottom to top. + """ + + +@control("Shimmer") +class Shimmer(LayoutControl): + """ + Applies an animated shimmering effect to its :attr:`content`. + + Use it to create lightweight loading placeholders or to add motion to + otherwise static layouts. + + ```python + ft.Shimmer( + base_color=ft.Colors.with_opacity(0.3, ft.Colors.GREY_400), + highlight_color=ft.Colors.WHITE, + content=ft.Column( + controls=[ + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ft.Container(height=80, bgcolor=ft.Colors.GREY_300), + ], + ), + ) + ``` + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The control to render with the shimmer effect. + + Raises: + ValueError: If it is not visible. + """ + + gradient: Optional[Gradient] = None + """ + Custom gradient that defines the shimmer colors. + """ + + base_color: Optional[ColorValue] = None + """ + Base color used when no :attr:`gradient` is provided. + """ + + highlight_color: Optional[ColorValue] = None + """ + Highlight color used when no :attr:`gradient` is provided. + """ + + period: DurationValue = 1500 + """ + Duration of a shimmer cycle in milliseconds. + """ + + direction: ShimmerDirection = ShimmerDirection.LTR + """ + Direction of the shimmering animation. + """ + + loop: Annotated[ + Optional[int], + V.ge(0), + ] = 0 + """ + Number of times the animation should repeat. `0` means infinite. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ctrl.gradient is not None + or (ctrl.base_color is not None and ctrl.highlight_color is not None) + ), + message=( + "either gradient or both base_color and highlight_color must be set" + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/core/stack.py b/sdk/python/packages/flet/src/flet/controls/core/stack.py new file mode 100644 index 0000000000..86886e92e2 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/stack.py @@ -0,0 +1,122 @@ +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ClipBehavior + +__all__ = ["Stack", "StackFit"] + + +class StackFit(Enum): + """ + How to size the non-positioned children of a :class:`~flet.Stack`. + """ + + LOOSE = "loose" + """ + The constraints passed to the stack from its parent are loosened. + + For example, if the stack has constraints that force it to `350x600`, then + this would allow the non-positioned children of the stack to have any + width from zero to `350` and any height from zero to `600`. + """ + + EXPAND = "expand" + """ + The constraints passed to the stack from its parent are tightened to the + biggest size allowed. + + For example, if the :class:`~flet.Stack` has loose constraints with a width in the \ + range + `10` to `100` and a height in the range `0` to `600`, then the non-positioned + children of the stack would all be sized as `100` pixels wide and `600` high. + """ + + PASS_THROUGH = "passThrough" + """ + The constraints passed to the stack from its parent are passed unmodified + to the non-positioned children. + + For example, if a :class:`~flet.Stack` is an expanded child of a \ + :class:`~flet.Row`, the + horizontal constraints will be tight and the vertical constraints will be loose. + """ + + +@control("Stack") +class Stack(LayoutControl, AdaptiveControl): + """ + Positions its children on top of each other, following a LIFO (Last In First Out) \ + order. + + This control is useful if you want to overlap several children in a simple way. + For example having some text and an image, overlaid with a gradient and a button + attached to the bottom. + + Stack is also useful if you want to implement implicit animations + (https://flet.dev/docs/cookbook/animations) that require knowing absolute + position of a target value. + + Example: + ```python + ft.Stack( + width=300, + height=300, + controls=[ + ft.Image( + src="https://picsum.photos/300/300", + width=300, + height=300, + fit=ft.BoxFit.CONTAIN, + ), + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.Text( + value="Image title", + color=ft.Colors.SURFACE_TINT, + size=40, + weight=ft.FontWeight.BOLD, + opacity=0.5, + ) + ], + ), + ], + ) + ``` + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of Controls to display. + + For the display order, it follows the order of the list, + so the last control in the list will be displayed on top (LIFO - Last In First Out). + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + The content will be clipped (or not) according to this option. + """ + + alignment: Optional[Alignment] = None + """ + Specifies the alignment for non-positioned (those without explicit alignment \ + properties such as :attr:`~flet.LayoutControl.top` + or :attr:`~flet.LayoutControl.bottom`) and + partially-positioned :attr:`controls`. + """ + + fit: StackFit = StackFit.LOOSE + """ + How to size the non-positioned :attr:`controls`. + """ + + def init(self): + super().init() + self._internals["host_positioned"] = True diff --git a/sdk/python/packages/flet/src/flet/controls/core/text.py b/sdk/python/packages/flet/src/flet/controls/core/text.py new file mode 100644 index 0000000000..798e4dbf85 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/text.py @@ -0,0 +1,412 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ( + ControlEventHandler, + Event, + EventControlType, + EventHandler, +) +from flet.controls.core.text_span import TextSpan +from flet.controls.layout_control import LayoutControl +from flet.controls.text_style import TextOverflow, TextStyle, TextThemeStyle +from flet.controls.types import ( + ColorValue, + FontWeight, + Number, + TextAlign, +) + +__all__ = [ + "Text", + "TextAffinity", + "TextSelection", + "TextSelectionChangeCause", + "TextSelectionChangeEvent", +] + + +class TextAffinity(Enum): + """ + Defines the permissions which can be checked and requested. + """ + + UPSTREAM = "upstream" + """ + The position has affinity for the downstream side of the text position, i.e. in \ + the direction of the end of the string. + """ + DOWNSTREAM = "downstream" + """ + The position has affinity for the upstream side of the text position, i.e. in the \ + direction of the beginning of the string. + """ + + +@dataclass +class TextSelection: + """ + A range of text that represents a selection. + """ + + base_offset: int + """ + The offset at which the selection originates. + """ + + extent_offset: int + """ + The offset at which the selection terminates. + """ + + affinity: "TextAffinity" = TextAffinity.DOWNSTREAM + """ + If the text range is collapsed and has more than one visual location (e.g., occurs \ + at a line break), which of the two locations to use when painting the caret. + """ + + directional: bool = False + """ + Whether this selection has disambiguated its base and extent. + """ + + @property + def start(self) -> int: + """ + The index of the first character in the range. + + Note: + This property is read-only. + """ + if self.base_offset < self.extent_offset: + return self.base_offset + else: + return self.extent_offset + + @property + def end(self) -> int: + """ + The next index after the characters in this range. + + Note: + This property is read-only. + """ + if self.base_offset < self.extent_offset: + return self.extent_offset + else: + return self.base_offset + + @property + def is_valid(self) -> bool: + """ + Whether this range represents a valid position in the text. + + Note: + This property is read-only. + """ + return self.start >= 0 and self.end >= 0 + + @property + def is_collapsed(self) -> bool: + """ + Whether this range is empty (but still potentially placed inside the text). + + Note: + This property is read-only. + """ + return self.start == self.end + + @property + def is_normalized(self) -> bool: + """ + Whether the start of this range precedes the end. + + Note: + This property is read-only. + """ + return self.start <= self.end + + def get_selected_text(self, source_text: str) -> str: + """ + Returns the selected text from the given full text. + + Args: + source_text: The full text to get the selection from. + + Raises: + AssertionError: If the selection is not valid, + i.e. :attr:`is_valid` is `False`. + """ + assert self.is_valid + return source_text[self.start : self.end] + + +class TextSelectionChangeCause(Enum): + """ + Indicates what triggered the change in selected text. + """ + + UNKNOWN = "unknown" + """ + The cause of the selection change is unknown or could not be determined. + """ + + TAP = "tap" + """ + The user tapped on the text and that caused the selection (or the location of the \ + cursor) to change. + """ + + DOUBLE_TAP = "doubleTap" + """ + The user tapped twice in quick succession on the text and that caused the \ + selection (or the location of the cursor) to change. + """ + + LONG_PRESS = "longPress" + """ + The user long-pressed the text and that caused the selection (or the location of \ + the cursor) to change. + """ + + FORCE_PRESS = "forcePress" + """ + The user force-pressed the text and that caused the selection (or the location of \ + the cursor) to change. + """ + + KEYBOARD = "keyboard" + """ + The user used the keyboard to change the selection or the location of the cursor. + + Keyboard-triggered selection changes may be caused by the IME as well as by + accessibility tools (e.g. TalkBack on Android). + """ + + TOOLBAR = "toolbar" + """ + The user used the selection toolbar to change the selection or the location of the \ + cursor. + + An example is when the user taps on select all in the tool bar. + """ + + DRAG = "drag" + """ + The user used the mouse to change the selection by dragging over a piece of text. + """ + + SCRIBBLE = "scribble" + """ + The user used iPadOS 14+ Scribble to change the selection. + """ + + +@dataclass +class TextSelectionChangeEvent(Event[EventControlType]): + """An event emitted when the text selection changes.""" + + selected_text: str + """The selected text.""" + + selection: TextSelection + """The new text selection.""" + + cause: Optional[TextSelectionChangeCause] = None + """The cause of the selection change.""" + + +@control("Text") +class Text(LayoutControl): + """ + Display text. + + It consists of two sources combined to produce the final text: + :attr:`value` and :attr:`spans`. + + Example: + ```python + ft.Text("Hello from Flet!", size=24, weight=ft.FontWeight.W_600) + ``` + """ + + value: str = "" + """ + The text displayed. + """ + + spans: Optional[list[TextSpan]] = None + """ + The list of :class:`~flet.TextSpan` + objects to build a rich text paragraph. + """ + + text_align: TextAlign = TextAlign.START + """ + Text horizontal align. + """ + + font_family: Optional[str] = None + """ + System or custom font family to render text with. See \ + [`Fonts`](https://flet.dev/docs/cookbook/fonts) cookbook guide for \ + instructions on how to import and use custom fonts in your application. + """ + + font_family_fallback: Optional[list[str]] = None + """ + Ordered fallback font families used when a glyph is unavailable in + :attr:`font_family`. + """ + + size: Optional[Number] = None + """ + Text size in virtual pixels. + + Defaults to `14`. + """ + + weight: Optional[FontWeight] = None + """ + Font weight. + + Defaults to `FontWeight.NORMAL`. + """ + + italic: bool = False + """ + Whether to use italic typeface. + """ + + style: Optional[TextStyle] = None + """ + The text's style. + """ + + theme_style: Optional[TextThemeStyle] = None + """ + Pre-defined text style. + """ + + max_lines: Optional[int] = None + """ + An optional maximum number of lines for the text to span, wrapping if necessary. + + If the text exceeds the given number of lines, it will be truncated according to + `overflow`. + + If this is 1, text will not wrap. Otherwise, text will be wrapped at the edge of + the box. + """ + + overflow: TextOverflow = TextOverflow.CLIP + """ + Defines how the text overflows. + """ + + selectable: Optional[bool] = None + """ + Whether the text should be selectable. + + Defaults to `False`. + """ + + no_wrap: Optional[bool] = None + """ + If `False` (default) the text should break at soft line breaks. + + If `True`, the glyphs in the text will be positioned as if there was unlimited + horizontal space. + + Defaults to `False`. + """ + + color: Optional[ColorValue] = None + """ + The text's foreground color. + """ + + bgcolor: Optional[ColorValue] = None + """ + The text's background color. + """ + + semantics_label: Optional[str] = None + """ + An alternative semantics label for this text. + + If present, the semantics of this control will contain this value instead of the + actual text. This will overwrite any of the `TextSpan.semantics_label`s. + + This is useful for replacing abbreviations or shorthands with the full text value: + + ```python + ft.Text("$$", semantics_label="Double dollars") + ``` + """ + + show_selection_cursor: bool = False + """ + Whether to show cursor (blinking caret) when the text is selected. + + Note: + Has effect only when :attr:`selectable` is `True`. + """ + + enable_interactive_selection: bool = True + """ + Whether to enable user interface affordances for changing the text selection. + + For example, setting this to `True` will enable features such as long-pressing to + select text and show the cut/copy/paste menu, and tapping to move the text caret. + On the other hand, when this is `False`, the text selection cannot be adjusted by + the user, text cannot be copied. + + Note: + Has effect only when :attr:`selectable` is `True`. + """ + + selection_cursor_width: Number = 2.0 + """ + Defines how thick the cursor should be. + + The cursor will be drawn under the text. + The cursor width will extend to the right of the boundary between characters for + left-to-right text and to the left for right-to-left text. This corresponds + to extending downstream relative to the selected position. + Negative values may be used to reverse this behavior. + + Note: + Has effect only when :attr:`selectable` is `True`. + """ + + selection_cursor_height: Optional[Number] = None + """ + Defines how tall the cursor should be. + """ + + selection_cursor_color: Optional[ColorValue] = None + """ + The color of the cursor. + + The cursor indicates the current text insertion point. + """ + + on_tap: Optional[ControlEventHandler["Text"]] = None + """ + Called when the user taps on this selectable text. + + Note: + Has effect only when :attr:`selectable` is `True`. + """ + + on_selection_change: Optional[EventHandler[TextSelectionChangeEvent["Text"]]] = None + """ + Called when the user changes the selection of text (including the cursor \ + location). + + Note: + Has effect only when :attr:`selectable` is `True`. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/text_span.py b/sdk/python/packages/flet/src/flet/controls/core/text_span.py new file mode 100644 index 0000000000..b912b308c6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/text_span.py @@ -0,0 +1,104 @@ +from typing import Optional, Union + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.text_style import TextStyle +from flet.controls.types import Url +from flet.utils.validation import V, ValidationRules + +__all__ = ["TextSpan"] + + +@control("TextSpan") +class TextSpan(Control): + """ + A text span. + + Usage Example: As a child of :attr:`flet.Text.spans`. + + For the object to be useful, at least one of :attr:`text` or + :attr:`spans` should be set. + """ + + text: Optional[str] = None + """ + The text contained in this span. + + Note: + If both `text` and :attr:`spans` are defined, + the `text` takes precedence. + """ + + style: Optional[TextStyle] = None + """ + Defines the style of this text span. + """ + + spans: Optional[list["TextSpan"]] = None + """ + Additional spans to include as children. + + Note: + If both `spans` and :attr:`text` are defined, + the `text` takes precedence. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback is provided, + it is fired after that. + """ + + semantics_label: Optional[str] = None + """ + An alternative semantics label for this text. + + If present, the semantics of this control will contain this value instead of the + actual text. + + Raises: + ValueError: If it is set when :attr:`text` is `None`. + """ + + spell_out: Optional[bool] = None + """ + Whether the assistive technologies should spell out this text character by \ + character. + + If the text is 'hello world', setting this to true causes the assistive + technologies, such as VoiceOver or TalkBack, to pronounce + 'h-e-l-l-o-space-w-o-r-l-d' instead of complete words. + This is useful for texts, such as passwords or verification codes. + + If this span contains other text span children, they also inherit the property from + this span unless explicitly set. + + If the property is not set, this text span inherits the spell out setting + from its parent. If this text span does not have a parent or the parent does + not have a spell out setting, this text span does not spell out the text by default. + """ + + on_click: Optional[ControlEventHandler["TextSpan"]] = None + """ + Called when this span is clicked. + """ + + on_enter: Optional[ControlEventHandler["TextSpan"]] = None + """ + Called when a mouse pointer has entered this span. + """ + + on_exit: Optional[ControlEventHandler["TextSpan"]] = None + """ + Called when a mouse pointer has exited this span. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ctrl.text is not None or ctrl.semantics_label is None, + message="semantics_label can be set only when text is not None", + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/core/transparent_pointer.py b/sdk/python/packages/flet/src/flet/controls/core/transparent_pointer.py new file mode 100644 index 0000000000..526bb3037b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/transparent_pointer.py @@ -0,0 +1,26 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl + +__all__ = ["TransparentPointer"] + + +@control("TransparentPointer") +class TransparentPointer(LayoutControl): + """ + TransparentPointer is the solution to ["How to pass through all gestures between two widgets in Stack"](https://stackoverflow.com/questions/65269190/pass-trough-all-gestures-between-two-widgets-in-stack) problem. + + For example, if there is an :class:`~flet.Button` + inside :class:`~flet.Container` with + :class:`~flet.GestureDetector` then tapping on + a button won't be "visible" to a gesture detector behind it. With + `TransparentPointer` a tapping event doesn't stop on a button, but goes up to the + parent, similar to event bubbling in HTML/JS. + """ # noqa: E501 + + content: Optional[Control] = None + """ + The `Control` that should be displayed. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/core/view.py b/sdk/python/packages/flet/src/flet/controls/core/view.py new file mode 100644 index 0000000000..094e248d9b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/view.py @@ -0,0 +1,213 @@ +from dataclasses import field +from typing import Optional, Union + +from flet.controls.base_control import BaseControl, control +from flet.controls.box import BoxDecoration +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.cupertino.cupertino_app_bar import CupertinoAppBar +from flet.controls.cupertino.cupertino_navigation_bar import CupertinoNavigationBar +from flet.controls.layout_control import LayoutControl +from flet.controls.material.app_bar import AppBar +from flet.controls.material.bottom_app_bar import BottomAppBar +from flet.controls.material.floating_action_button import FloatingActionButton +from flet.controls.material.navigation_bar import NavigationBar +from flet.controls.material.navigation_drawer import NavigationDrawer +from flet.controls.padding import Padding, PaddingValue +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.services.service import Service +from flet.controls.transform import OffsetValue +from flet.controls.types import ( + ColorValue, + CrossAxisAlignment, + FloatingActionButtonLocation, + MainAxisAlignment, + Number, +) + +__all__ = ["View"] + + +@control("View") +class View(ScrollableControl, LayoutControl): + """ + View is the top most container for all other controls. + + A root view is automatically created when a new user session started. + From layout perspective the View represents a :class:`~flet.Column` + control, so it has a similar behavior and shares same properties. + """ + + controls: list[BaseControl] = field(default_factory=list) + """ + A list of controls to display. + """ + + route: str = field(default_factory=lambda: "/") + """ + View's route - not currently used by Flet framework, but can be used in a user \ + program to update :attr:`flet.Page.route` when a view popped. + """ + + appbar: Optional[Union[AppBar, CupertinoAppBar]] = None + """ + An :class:`~flet.AppBar` control to display at the top of the `Page`. + """ + + bottom_appbar: Optional[BottomAppBar] = None + """ + A :class:`~flet.BottomAppBar` control to display at the bottom of the `Page`. + """ + + floating_action_button: Optional[FloatingActionButton] = None + """ + A :class:`~flet.FloatingActionButton` control to display on top of `Page` content. + """ + + floating_action_button_location: Optional[ + Union[FloatingActionButtonLocation, OffsetValue] + ] = None + """ + Describes position of :attr:`floating_action_button` + """ + + navigation_bar: Union[NavigationBar, CupertinoNavigationBar, None] = None + """ + A navigation bar (:class:`~flet.NavigationBar` or \ + :class:`~flet.CupertinoNavigationBar`) control to display at the bottom of the \ + `Page`. + """ + + drawer: Optional[NavigationDrawer] = None + """ + A :class:`~flet.NavigationDrawer` control to display as a panel sliding from the \ + start edge of the view. + """ + + end_drawer: Optional[NavigationDrawer] = None + """ + A :class:`~flet.NavigationDrawer` control to display as a panel sliding from the \ + end edge of the view. + """ + + vertical_alignment: MainAxisAlignment = MainAxisAlignment.START + """ + Defines how the child :attr:`controls` should be placed vertically. + """ + + horizontal_alignment: CrossAxisAlignment = CrossAxisAlignment.START + """ + How the child Controls should be placed horizontally. + """ + + spacing: Number = 10 + """ + The vertical spacing between :attr:`controls` on the `Page`. + + Note: + Has effect only when :attr:`vertical_alignment` + is set to :attr:`flet.MainAxisAlignment.START`, + :attr:`flet.MainAxisAlignment.END`, or :attr:`flet.MainAxisAlignment.CENTER`. + """ + + padding: Optional[PaddingValue] = field(default_factory=lambda: Padding.all(10)) + """ + A space between page contents and its edges. + """ + + bgcolor: Optional[ColorValue] = None + """ + Background color of the view. + """ + + decoration: Optional[BoxDecoration] = None + """ + The background decoration. + """ + + foreground_decoration: Optional[BoxDecoration] = None + """ + The foreground decoration. + """ + + fullscreen_dialog: bool = False + """ + If `True`, the view is a fullscreen modal dialog. + """ + + services: list[Service] = field(default_factory=list, metadata={"skip": True}) + """ + A list of :class:`~flet.Service` controls associated with this view. + """ + + can_pop: bool = True + """ + Whether the view can be popped. + """ + + on_confirm_pop: Optional[ControlEventHandler["View"]] = None + """ + An event handler that is called when the view is about to be popped. + You can use this event to confirm or cancel the pop action by calling + :meth:`confirm_pop` method. + """ + + def init(self): + super().init() + self._internals["host_expanded"] = True + + # Magic methods + def __contains__(self, item: Control) -> bool: + return item in self.controls + + async def confirm_pop(self, should_pop: bool) -> None: + """ + Resolves a pending pop-confirmation request for this view. + + Call this from :attr:`on_confirm_pop` to allow or cancel the current + back-navigation attempt. + + Args: + should_pop: `True` to proceed with popping this view, `False` to + keep the view on the navigation stack. + + Notes: + - This method only has effect while a pop confirmation is pending. + - If not called, the frontend confirmation wait times out and the + pop is canceled. + """ + await self._invoke_method("confirm_pop", {"should_pop": should_pop}) + + async def show_drawer(self): + """ + Show the drawer. + + Raises: + ValueError: If no :attr:`drawer` is defined. + """ + if self.drawer is None: + raise ValueError("No drawer defined") + await self._invoke_method("show_drawer") + + async def close_drawer(self): + """ + Close the drawer. + """ + await self._invoke_method("close_drawer") + + async def show_end_drawer(self): + """ + Show the end drawer. + + Raises: + ValueError: If no :attr:`end_drawer` is defined. + """ + if self.end_drawer is None: + raise ValueError("No end_drawer defined") + await self._invoke_method("show_end_drawer") + + async def close_end_drawer(self): + """ + Close the end drawer. + """ + await self._invoke_method("close_end_drawer") diff --git a/sdk/python/packages/flet/src/flet/controls/core/window.py b/sdk/python/packages/flet/src/flet/controls/core/window.py new file mode 100644 index 0000000000..3a08072774 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/window.py @@ -0,0 +1,394 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import BaseControl, control +from flet.controls.control_event import Event, EventControlType, EventHandler +from flet.controls.types import ( + Brightness, + ColorValue, + Number, +) + +__all__ = ["Window", "WindowEvent", "WindowEventType", "WindowResizeEdge"] + + +class WindowEventType(Enum): + """ + Type of native desktop window event. + + Values are reported in :attr:`flet.WindowEvent.type` and + delivered by :attr:`flet.Window.on_event`. Event availability + depends on the operating system and underlying window manager. + """ + + CLOSE = "close" + """The OS requested the window to close.""" + + FOCUS = "focus" + """The window became focused.""" + + BLUR = "blur" + """The window lost focus.""" + + HIDE = "hide" + """The window became hidden.""" + + SHOW = "show" + """The window became visible.""" + + MAXIMIZE = "maximize" + """The window was maximized.""" + + UNMAXIMIZE = "unmaximize" + """The window exited maximized state.""" + + MINIMIZE = "minimize" + """The window was minimized.""" + + RESTORE = "restore" + """The window was restored from a minimized state.""" + + RESIZE = "resize" + """The window size is changing.""" + + RESIZED = "resized" + """The window size changed.""" + + MOVE = "move" + """The window position is changing.""" + + MOVED = "moved" + """The window position changed.""" + + LEAVE_FULL_SCREEN = "leave-full-screen" + """The window exited full-screen mode.""" + + ENTER_FULL_SCREEN = "enter-full-screen" + """The window entered full-screen mode.""" + + +class WindowResizeEdge(Enum): + """ + Edge or corner used by :meth:`flet.Window.start_resizing`. + + The selected value defines which resize handle is used when initiating + native window resizing programmatically. + """ + + TOP = "top" + """Top edge.""" + + LEFT = "left" + """Left edge.""" + + RIGHT = "right" + """Right edge.""" + + BOTTOM = "bottom" + """Bottom edge.""" + + TOP_LEFT = "topLeft" + """Top-left corner.""" + + BOTTOM_LEFT = "bottomLeft" + """Bottom-left corner.""" + + TOP_RIGHT = "topRight" + """Top-right corner.""" + + BOTTOM_RIGHT = "bottomRight" + """Bottom-right corner.""" + + +@dataclass +class WindowEvent(Event[EventControlType]): + """ + Payload for :attr:`flet.Window.on_event` callbacks. + """ + + type: WindowEventType + """ + Native event kind emitted by the desktop window backend. + """ + + +# TODO: raise FletExceptions when a method cant be called on the running platform +@control("Window") +class Window(BaseControl): + """ + Controls the app window. + + Limitation: + This control is for Desktop platforms (macOS, Windows, Linux) only. + """ + + bgcolor: Optional[ColorValue] = None + """ + Sets background color of an application window. + + Tip: + Can be used together with :attr:`flet.Page.bgcolor` to make + a window transparent. + """ + + width: Optional[Number] = None + """ + Defines the width of the app window. + """ + + height: Optional[Number] = None + """ + Defines the height of the app window. + """ + + top: Optional[Number] = None + """ + Defines the vertical position of a native OS window - a distance in virtual pixels \ + from the top edge of the screen. + """ + + left: Optional[Number] = None + """ + Defines the horizontal position of the app window - a distance in virtual pixels \ + from the left edge of the screen. + """ + + max_width: Optional[Number] = None + """ + Defines the maximum width of the app window. + """ + + max_height: Optional[Number] = None + """ + Defines the maximum height of the app window. + """ + + min_width: Optional[Number] = None + """ + Defines the minimum width of the app window. + """ + + min_height: Optional[Number] = None + """ + Defines the minimum height of the app window. + """ + + opacity: Number = 1.0 + """ + Defines the opacity of the app window. + + Raises: + ValueError: If it is not between `0.0` and `1.0` inclusive. + """ + + aspect_ratio: Optional[Number] = None + """ + Defines the aspect ratio of the app window. + """ + + brightness: Optional[Brightness] = None + """ + The brightness of a app window. + """ + + maximized: bool = False + """ + Whether the app window is maximized. + + Set to `True` to maximize programmatically. + """ + + minimized: bool = False + """ + Whether the app window is minimized. + + Set to `True` to minimize programmatically. + """ + + minimizable: bool = True + """ + Whether the app window can be minimized through the window's "Minimize" button. + """ + + maximizable: bool = True + """ + Whether to hide/disable app window's "Maximize" button. + """ + + resizable: bool = True + """ + Whether the app window can be resized. + """ + + movable: bool = True + """ + Whether the app window can be moved. + + Limitation: + Has effect on macOS only. + """ + + full_screen: bool = False + """ + Whether to switch the app's window to fullscreen mode. + """ + + always_on_top: bool = False + """ + Whether the app window should always be displayed on top of other windows/apps. + """ + + always_on_bottom: bool = False + """ + Whether the app window should always be displayed below other windows. + + Limitation: + Has effect on Linux and Windows only. + """ + + prevent_close: bool = False + """ + Set to `True` to intercept the native close signal. + + Could be used to implement app exit confirmation logic. + """ + + skip_task_bar: bool = False + """ + Whether the app window should be hidden from the Task Bar (on Windows) or Dock (on \ + macOS). + """ + + title_bar_hidden: bool = False + """ + Whether to hide the app window's title bar. + """ + + title_bar_buttons_hidden: bool = False + """ + Whether to hide the app window's title bar buttons. + + Limitation: + Has effect on macOS only. + """ + + frameless: bool = False + """ + Whether the app window should be frameless. + """ + + progress_bar: Optional[Number] = None + """ + The value from `0.0` to `1.0` to display a progress bar on Task Bar or Dock. + """ + + focused: bool = True + """ + Whether the app window should be focused. + + Set to `True` to focus programmatically. + """ + + visible: bool = True + """ + Whether to make the app window visible. + + Can be of use when the app starts as hidden. + """ + + shadow: bool = True + """ + Whether to display a shadow around the app window. + """ + + alignment: Optional[Alignment] = None + """ + Defines the alignment of the app window. + """ + + badge_label: Optional[str] = None + """ + Sets a badge label on the app window. + + Limitation: + Has effect on macOS only. + """ + + icon: Optional[str] = None + """ + The icon of the app window. + + The file should have the `.ico` extension. + + Limitation: + Has effect on Windows only. + """ + + ignore_mouse_events: bool = False + """ + Whether the app window should ignore mouse events, passing them to the window \ + below it. If this window has focus, it will still receive keyboard events. + """ + + on_event: Optional[EventHandler[WindowEvent]] = None + """ + Called when app window changes its state. + For example, when the window is maximized or minimized. + """ + + def __post_init__(self, ref) -> None: + super().__post_init__(ref) + self._i = 2 + if self.opacity < 0.0 or self.opacity > 1.0: + raise ValueError( + f"opacity must be between 0.0 and 1.0 inclusive, got {self.opacity}" + ) + + async def wait_until_ready_to_show(self): + """ + Waits until the app window is ready to show. + """ + await self._invoke_method("wait_until_ready_to_show") + + async def destroy(self): + """ + Destroys the app window. + """ + await self._invoke_method("destroy") + + async def center(self): + """ + Centers the app window. + """ + await self._invoke_method("center") + + async def close(self): + """ + Requests graceful closing of the app window. + + This sends a native close request equivalent to pressing the window + close button. If :attr:`prevent_close` is enabled, the close may be + intercepted and reported via :attr:`on_event` with + :attr:`flet.WindowEventType.CLOSE`. + """ + await self._invoke_method("close") + + async def to_front(self): + """ + Brings the app window to the front. + """ + await self._invoke_method("to_front") + + async def start_dragging(self): + """ + Starts dragging the app window. + """ + await self._invoke_method("start_dragging") + + async def start_resizing(self, edge: WindowResizeEdge): + """ + Starts resizing the app window. + """ + await self._invoke_method("start_resizing", {"edge": edge}) diff --git a/sdk/python/packages/flet/src/flet/controls/core/window_drag_area.py b/sdk/python/packages/flet/src/flet/controls/core/window_drag_area.py new file mode 100644 index 0000000000..6b87e55676 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/core/window_drag_area.py @@ -0,0 +1,55 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import EventHandler +from flet.controls.core.window import WindowEvent +from flet.controls.events import DragEndEvent, DragStartEvent +from flet.controls.layout_control import LayoutControl +from flet.utils.validation import V + + +@control("WindowDragArea") +class WindowDragArea(LayoutControl): + """ + It mimics the behavior (drag, move, maximize, restore) of a native OS window title \ + bar on the :attr:`content` control. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The content of this drag area. + + Raises: + ValueError: If it is not visible. + """ + + maximizable: bool = True + """ + Whether double-clicking on the `WindowDragArea` should maximize/maximize the app's \ + window. + """ + + on_double_tap: Optional[EventHandler[WindowEvent["WindowDragArea"]]] = None + """ + Called when the `WindowDragArea` is double-tapped and `maximizable=True`. + + Info: + When a double-tap event is fired, the :attr:`~flet.WindowEvent.type` + property of the event handler argument can only be one of the following: + `WindowEventType.MAXIMIZE`, `WindowEventType.UNMAXIMIZE`. + """ + + on_drag_start: Optional[EventHandler[DragStartEvent["WindowDragArea"]]] = None + """ + Called when a pointer has contacted the screen and has begun to move/drag. + """ + + on_drag_end: Optional[EventHandler[DragEndEvent["WindowDragArea"]]] = None + """ + Called when a pointer that was previously in contact with the screen and \ + moving/dragging is no longer in contact with the screen. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/__init__.py b/sdk/python/packages/flet/src/flet/controls/cupertino/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_action_sheet.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_action_sheet.py new file mode 100644 index 0000000000..c0e4d04b1b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_action_sheet.py @@ -0,0 +1,93 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import StrOrControl +from flet.utils.validation import V, ValidationRules + +__all__ = ["CupertinoActionSheet"] + + +@control("CupertinoActionSheet") +class CupertinoActionSheet(LayoutControl): + """ + An iOS-style action sheet. + + Action sheets are generally used to give the user a choice between + two or more choices for the current context. + + Example: + ```python + sheet = ft.CupertinoActionSheet( + title=ft.Text("Choose an option"), + message=ft.Text("Select what you would like to do"), + cancel=ft.CupertinoActionSheetAction(content=ft.Text("Cancel")), + actions=[ + ft.CupertinoActionSheetAction(content=ft.Text("Save")), + ft.CupertinoActionSheetAction( + content=ft.Text("Delete"), destructive=True + ), + ], + ) + page.show_dialog(ft.CupertinoBottomSheet(sheet)) + ``` + """ + + title: Optional[StrOrControl] = None + """ + A control containing the title of the action sheet. + + Typically a :class:`~flet.Text` control. + """ + + message: Optional[StrOrControl] = None + """ + A control containing a descriptive message that provides more details about the \ + reason for the alert. + + Typically a :class:`~flet.Text` control. + """ + + actions: Optional[list[Control]] = None + """ + A list of action buttons to be shown in the sheet. + + These actions are typically :class:`~flet.CupertinoActionSheetAction`s. + + Raises: + ValueError: If none of :attr:`actions`, :attr:`title`, :attr:`message`, + or :attr:`cancel` are provided. + """ + + cancel: Optional[Control] = None + """ + An optional control to be shown below the actions but grouped separately from \ + them. + + Typically a :class:`~flet.CupertinoActionSheetAction` button. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.actions, list) + and any(action.visible for action in ctrl.actions) + ) + or ( + isinstance(ctrl.title, str) + or (isinstance(ctrl.title, Control) and ctrl.title.visible) + ) + or ( + isinstance(ctrl.message, str) + or (isinstance(ctrl.message, Control) and ctrl.message.visible) + ) + or (ctrl.cancel is not None and ctrl.cancel.visible) + ), + message=( + "This action sheet must have a non-None value for at least one of the " + "following arguments: `actions`, `title`, `message`, or `cancel`" + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_action_sheet_action.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_action_sheet_action.py new file mode 100644 index 0000000000..9a2775ce58 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_action_sheet_action.py @@ -0,0 +1,47 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import MouseCursor, StrOrControl +from flet.utils.validation import V + +__all__ = ["CupertinoActionSheetAction"] + + +@control("CupertinoActionSheetAction") +class CupertinoActionSheetAction(LayoutControl): + """ + An action button typically used in a CupertinoActionSheet. + """ + + content: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The child control to be shown in this action button. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + default: bool = False + """ + Whether this action should receive the style of an emphasized, default action. + """ + + destructive: bool = False + """ + Whether this action should receive the style of a destructive action. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + Defines the mouse cursor for this action button. + """ + + on_click: Optional[ControlEventHandler["CupertinoActionSheetAction"]] = None + """ + Called when this action button is clicked. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_activity_indicator.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_activity_indicator.py new file mode 100644 index 0000000000..39cfa7d51a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_activity_indicator.py @@ -0,0 +1,64 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ColorValue, Number +from flet.utils.validation import V + +__all__ = ["CupertinoActivityIndicator"] + + +@control("CupertinoActivityIndicator") +class CupertinoActivityIndicator(LayoutControl): + """ + An iOS-style activity indicator that spins clockwise. + + ```python + ft.CupertinoActivityIndicator( + radius=30, + color=ft.CupertinoColors.DARK_BACKGROUND_GRAY, + ) + ``` + """ + + radius: Annotated[ + Number, + V.gt(0), + ] = 10 + """ + The radius of this indicator. + + Raises: + ValueError: If it is not strictly greater than `0`. + """ + + color: Optional[ColorValue] = None + """ + Defines the color of this indicator. + """ + + animating: bool = True + """ + Whether this indicator is running its animation. + + Note: + Has no effect if :attr:`progress` is not `None`. + """ + + progress: Annotated[ + Optional[Number], + V.between(0.0, 1.0), + ] = None + """ + Determines the percentage of spinner ticks that will be shown. + + Typical usage would display all ticks, however, this allows for more fine-grained + control such as during pull-to-refresh when the drag-down action shows one tick at + a time as the user continues to drag down. + + Note: + If not `None`, then :attr:`animating` will be ignored. + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_alert_dialog.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_alert_dialog.py new file mode 100644 index 0000000000..04e5cc18a1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_alert_dialog.py @@ -0,0 +1,86 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.animation import Animation, AnimationCurve +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.dialog_control import DialogControl +from flet.controls.duration import Duration +from flet.controls.types import ColorValue, StrOrControl +from flet.utils.validation import V, ValidationRules + +__all__ = ["CupertinoAlertDialog"] + + +@control("CupertinoAlertDialog") +class CupertinoAlertDialog(DialogControl): + """ + An iOS-style alert dialog. + + An alert dialog informs the user about situations that require acknowledgement. An + alert dialog has an optional title and an optional list of actions. The title is + displayed above the content and the actions are displayed below the content. + """ + + modal: bool = False + """ + Whether this dialog cannot be dismissed by clicking the area outside of it. + """ + + title: Optional[StrOrControl] = None + """ + The title of this dialog, displayed in a large font at the top of this dialog. + + Typically a :class:`~flet.Text` control. + """ + + content: Optional[Control] = None + """ + The content of this dialog, displayed in a light font at the center of this \ + dialog. + + Typically a :class:`~flet.Column` that contains + the dialog's :class:`~flet.Text` message. + """ + + actions: list[Control] = field(default_factory=list) + """ + A set of actions that are displayed at the bottom of the dialog. + + Typically this is a list of :class:`~flet.CupertinoDialogAction` controls. + """ + + inset_animation: Animation = field( + default_factory=lambda: Animation( + curve=AnimationCurve.DECELERATE, duration=Duration(milliseconds=100) + ) + ) + """ + The animation style to be used when the system keyboard intrudes into the space \ + that the dialog is placed in. + """ + + barrier_color: Optional[ColorValue] = None + """ + The color of the modal barrier below this dialog. + + If `None`, then :attr:`flet.DialogTheme.barrier_color` is used. + If that is also `None`, the default is `Colors.BLACK_54`. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.title, str) + or (isinstance(ctrl.title, Control) and ctrl.title.visible) + ) + or (isinstance(ctrl.content, Control) and ctrl.content.visible) + or any(action.visible for action in ctrl.actions) + ), + message=( + "CupertinoAlertDialog has nothing to display. Provide at minimum one " + "of the following: title, content, actions" + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_app_bar.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_app_bar.py new file mode 100644 index 0000000000..3bf8ac8007 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_app_bar.py @@ -0,0 +1,160 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.border import Border +from flet.controls.control import Control +from flet.controls.padding import PaddingValue +from flet.controls.types import Brightness, ColorValue, StrOrControl + +__all__ = ["CupertinoAppBar"] + + +@control("CupertinoAppBar") +class CupertinoAppBar(Control): + """ + An iOS-styled app bar. + + Note: + The alignment of the :attr:`title` depends on whether + this app bar is :attr:`large` or not. + If it is `True`, the :attr:`title` is left-aligned and if it + is `False` (the default), the :attr:`title` is centered. + """ + + leading: Optional[Control] = None + """ + A control to display at the start of this app bar. + + Typically the leading control is an :class:`~flet.Icon` or an \ + :class:`~flet.IconButton` . + + If it is `None` and :attr:`automatically_imply_leading` is `True`, + an appropriate button will be automatically created. + """ + + title: Optional[StrOrControl] = None + """ + A string or a control to display in the middle of this app bar. + + Typically a :class:`~flet.Text`. + """ + + trailing: Optional[Control] = None + """ + A Control to place at the end of the app bar. + + Typically used for actions such as searching or editing. + """ + + bgcolor: Optional[ColorValue] = None + """ + The fill color to use for this app bar. + + Default color is defined by current theme. + """ + + automatically_imply_leading: Optional[bool] = None + """ + Whether we should try to imply the :attr:`leading` control if `None`. + + - If `True` and :attr:`leading` is `None`, the app bar will automatically + determine an appropriate leading control. + - If `False` and :attr:`leading` is `None`, + the space is allocated to the :attr:`title`. + - If a :attr:`leading` control is provided, this parameter has no effect. + """ + + automatically_imply_title: Optional[bool] = None + """ + Whether we should try to imply the `title` control if `None`. + + - If True and `title` is `None`, a :class:`~flet.Text` control containing the + current route's title will be automatically filled in. + - If the `title` is not `None`, this parameter has no effect. + """ + + border: Optional[Border] = None + """ + The border of the app bar. By default, a single pixel bottom border side is \ + rendered. + """ + + padding: Optional[PaddingValue] = None + """ + Defines the padding for the contents of the app bar. + + If `None`, the app bar will adopt the following defaults: + + - vertically, contents will be sized to the same height as the app bar itself minus + the status bar. + - horizontally, padding will be `16` pixels according to iOS specifications unless + the leading widget is an automatically inserted back button, in which case the + padding will be `0`. + + Note: + Vertical padding (`top` and `bottom`) won't change the height of this app bar. + """ + + transition_between_routes: bool = True + """ + Determines whether the app bar transitions between routes. + + If `True`, this app bar will animate on top of route transitions when the + destination route also contains a `CupertinoAppBar` or `CupertinoSliverAppBar` with + `transition_between_routes` set to `True`. + + This transition also occurs during edge back swipe gestures, mimicking native iOS + behavior. + + Note: + When enabled, only one app bar can be present per route unless a + `hero_tag` is specified. + """ + + previous_page_title: Optional[str] = None + """ + Manually specify the previous route's title when automatically implying the \ + leading back button. + + Overrides the text shown with the back chevron instead of automatically showing the + previous route's title when :attr:`automatically_imply_leading` is `True`. + + Note: + Has no effect if `leading` is not `None` or if + :attr:`automatically_imply_leading` is `False`. + """ + + brightness: Optional[Brightness] = None + """ + The brightness of the specified :attr:`bgcolor`. + + Setting this value changes the style of the system status bar. It is typically used + to increase the contrast ratio of the system status bar over :attr:`bgcolor`. + + If `None` (the default), its value will be inferred from the relative luminance of + the :attr:`bgcolor`. + """ + + automatic_background_visibility: Optional[bool] = None + """ + Whether the navigation bar should appear transparent when content is scrolled \ + under it. + + If `False`, the navigation bar will display its :attr:`bgcolor`. + """ + + enable_background_filter_blur: Optional[bool] = None + """ + Whether to have a blur effect when a non-opaque :attr:`bgcolor` is used. + + This will only be respected when :attr:`automatic_background_visibility` + is `False` or until content scrolls under the navigation bar. + """ + + large: bool = False + """ + Whether to use a large app bar layout. + + If `True`, the :attr:`title` is left-aligned; + if `False`, the :attr:`title` is centered. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_bottom_sheet.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_bottom_sheet.py new file mode 100644 index 0000000000..58982c2c9a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_bottom_sheet.py @@ -0,0 +1,42 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.dialog_control import DialogControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ColorValue, Number + +__all__ = ["CupertinoBottomSheet"] + + +@control("CupertinoBottomSheet") +class CupertinoBottomSheet(DialogControl): + """ + A Cupertino bottom sheet. + """ + + content: Control + """ + The control to be displayed in this bottom sheet. + """ + + modal: bool = False + """ + Whether this bottom sheet can be dismissed/closed by clicking the area outside of \ + it. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this bottom sheet. + """ + + height: Optional[Number] = None + """ + The height of this bottom sheet. + """ + + padding: Optional[PaddingValue] = None + """ + The sheet's padding. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_button.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_button.py new file mode 100644 index 0000000000..06e6ce8deb --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_button.py @@ -0,0 +1,186 @@ +from dataclasses import field +from enum import Enum +from typing import Annotated, Optional, Union + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadius, BorderRadiusValue +from flet.controls.control_event import ControlEventHandler +from flet.controls.geometry import Size +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + MouseCursor, + Number, + StrOrControl, + Url, +) +from flet.utils.validation import V + +__all__ = ["CupertinoButton", "CupertinoButtonSize"] + + +class CupertinoButtonSize(Enum): + """ + Preset size style for :class:`~flet.CupertinoButton`. + + Influences defaults such as minimum size, padding, border radius, and text style. + """ + + SMALL = "small" + """ + Compact button style with smaller text and tighter sizing. + """ + + MEDIUM = "medium" + """ + Medium button style with regular text and balanced sizing. + """ + + LARGE = "large" + """ + Classic large Cupertino button style. + """ + + +@control("CupertinoButton") +class CupertinoButton(LayoutControl): + """ + An iOS-style button. + + Example: + ```python + ft.CupertinoButton("Tap me") + ``` + """ + + content: Optional[StrOrControl] = None + """ + The content of this button. + """ + + icon: Optional[IconDataOrControl] = None + """ + An icon shown in this button. + """ + + icon_color: Optional[ColorValue] = None + """ + The foreground color of the :attr:`icon`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this button. + """ + + color: Optional[ColorValue] = None + """ + The color of this button's text. + """ + + disabled_bgcolor: Optional[ColorValue] = None + """ + The background color of this button when disabled. + """ + + opacity_on_click: Annotated[ + Number, + V.between(0.0, 1.0), + ] = 0.4 + """ + Defines the opacity of the button when it is clicked. + + When not pressed, the button has an opacity of `1.0`. + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ + + min_size: Optional[Size] = None + """ + The minimum size of this button. + """ + + size: CupertinoButtonSize = CupertinoButtonSize.LARGE + """ + The size of this button. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of space to surround the `content` control inside the bounds of the \ + button. + """ + + alignment: Optional[Alignment] = field(default_factory=lambda: Alignment.CENTER) + """ + The alignment of this button's content. + + Typically buttons are sized to be just big enough to contain the child + and its padding. If the button's size is constrained to a fixed size, + this property defines how the child is aligned within the available space. + """ + + border_radius: BorderRadiusValue = field( + default_factory=lambda: BorderRadius.all(8.0) + ) + """ + The radius of the button's corners when it has a background color. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback is + provided, it is fired after that. + """ + + autofocus: bool = False + """ + Whether this button should be selected as the initial focus when no other node in \ + its scope is currently focused. + """ + + focus_color: Optional[ColorValue] = None + """ + The color to use for the focus highlight for keyboard interactions. + + Defaults to a slightly transparent :attr:`bgcolor`. + If `bgcolor` is `None`, defaults to a slightly transparent + :attr:`flet.CupertinoColors.ACTIVE_BLUE`. + 'Slightly transparent' in this context means the color is used with an opacity + of `0.80`, a brightness of `0.69` and a saturation of `0.835`. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor for a mouse pointer when it enters or is hovering over this button. + """ + + on_click: Optional[ControlEventHandler["CupertinoButton"]] = None + """ + Called when a user clicks this button. + """ + + on_long_press: Optional[ControlEventHandler["CupertinoButton"]] = None + """ + Called when a user long-presses this button. + """ + + on_focus: Optional[ControlEventHandler["CupertinoButton"]] = None + """ + Called when this button receives focus. + """ + + on_blur: Optional[ControlEventHandler["CupertinoButton"]] = None + """ + Called when this button loses focus. + """ + + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py new file mode 100644 index 0000000000..1c2a223e8f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_checkbox.py @@ -0,0 +1,157 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.border import BorderSide +from flet.controls.buttons import OutlinedBorder +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.cupertino.cupertino_colors import CupertinoColors +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + LabelPosition, + MouseCursor, + Number, +) + +__all__ = ["CupertinoCheckbox"] + + +@control("CupertinoCheckbox") +class CupertinoCheckbox(LayoutControl): + """ + A macOS style checkbox. + + Checkbox allows to select one or more items from a group, + or switch between two mutually exclusive options (checked or unchecked, on or off). + + ```python + ft.Column( + intrinsic_width=True, + controls=[ + ft.CupertinoCheckbox(), + ft.CupertinoCheckbox(label="Checked", value=True), + ft.CupertinoCheckbox(label="Disabled", disabled=True), + ], + ) + ``` + """ + + label: Optional[str] = None + """ + A clickable label to display on the right of this checkbox. + """ + + label_position: LabelPosition = LabelPosition.RIGHT + """ + Defines on which side of this checkbox the :attr:`label` should be shown. + """ + + spacing: Optional[Number] = 10 + """ + The space between this checkbox and the :attr:`label`. + """ + + value: Optional[bool] = False + """ + The value of this checkbox. + + - If `True`, this checkbox is checked. + - If `False`, this checkbox is unchecked. + - If `None` and :attr:`tristate` is `True`, + this checkbox is indeterminate (displayed as a dash). + """ + + tristate: bool = False + """ + If `True`, this checkbox's :attr:`value` can be `True`, `False`, or `None`. + """ + + autofocus: bool = False + """ + Whether this checkbox will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + check_color: Optional[ColorValue] = None + """ + The color to use for the check icon when this checkbox is checked. + """ + + active_color: Optional[ColorValue] = CupertinoColors.ACTIVE_BLUE + """ + The color used to fill checkbox when it is checked/selected. + + If :attr:`fill_color` returns a non-null color in the + :attr:`flet.ControlState.SELECTED` state, it will be used instead of this color. + """ + + focus_color: Optional[ColorValue] = None + """ + The color used for this checkbox's border shadow when it has the input focus. + """ + + fill_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color used to fill this checkbox in all or specific :class:`~flet.ControlState` + states. + + :attr:`active_color` is used as fallback color when + the checkbox is in the :attr:`~flet.ControlState.SELECTED` state, + :attr:`flet.CupertinoColors.WHITE` at `50%` opacity is used as fallback color + when this checkbox is in the :attr:`~flet.ControlState.DISABLED` state, and + :attr:`flet.CupertinoColors.WHITE` otherwise. + + Note: + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, and :attr:`flet.ControlState.DEFAULT`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of this checkbox. + + Internally defaults to `RoundedRectangleBorder(radius=4)`. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor for a mouse pointer entering or hovering over this checkbox. + """ + + semantics_label: Optional[str] = None + """ + The semantic label for this checkbox that will be announced by screen readers. + + This is announced by assistive technologies (e.g TalkBack/VoiceOver) and not shown + on the UI. + """ + + border_side: Optional[ControlStateValue[BorderSide]] = None + """ + Defines the checkbox's border sides in all or specific :class:`~flet.ControlState` \ + states. + + Note: + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, :attr:`flet.ControlState.PRESSED`, + :attr:`flet.ControlState.ERROR`, and :attr:`flet.ControlState.DEFAULT`. + """ + + on_change: Optional[ControlEventHandler["CupertinoCheckbox"]] = None + """ + Called when the state of this checkbox is changed. + """ + + on_focus: Optional[ControlEventHandler["CupertinoCheckbox"]] = None + """ + Called when this checkbox has received focus. + """ + + on_blur: Optional[ControlEventHandler["CupertinoCheckbox"]] = None + """ + Called when this checkbox has lost focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_colors.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_colors.py new file mode 100644 index 0000000000..cafe0b66a4 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_colors.py @@ -0,0 +1,155 @@ +""" +url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/cupertino/colors.dart' +output_file="$HOME/cupertino_python_colors.txt" +curl -s $url | python -c ' +import re + +for line in __import__("sys").stdin: + match1 = re.search(r"static const CupertinoDynamicColor ([a-zA-Z0-9_]+)", line) + match2 = re.search(r"static const Color ([a-zA-Z0-9_]+)", line) + if match1: + print("{} = \"{}\"".format(match1.group(1).upper(), match1.group(1))) + elif match2: + print("{} = \"{}\"".format(match2.group(1).upper(), match2.group(1))) +' >> "$output_file" + +--- + +Code to sort the members: +``` +s = sorted(CupertinoColors, key=lambda i: i.name) +for i in s: + print(f'{i.name} = "{i.value}"') +``` +""" # noqa: E501 + +import random +from enum import Enum +from typing import TYPE_CHECKING, Optional, Union + +if TYPE_CHECKING: + from flet.controls.types import ColorValue + +__all__ = ["CupertinoColors"] + + +class CupertinoColors(str, Enum): + """ + Named cupertino colors. + """ + + def __eq__(self, other): + if isinstance(other, str): + return self.value.lower() == other.lower() + if isinstance(other, Enum): + return self.value.lower() == other.value.lower() + return NotImplemented + + def __hash__(self): + return hash(self.value.lower()) + + @staticmethod + def with_opacity(opacity: Union[int, float], color: "ColorValue") -> str: + """ + Returns the color with the specified opacity. + + Args: + opacity: The opacity value between `0.0` and `1.0`. + color: The color to apply opacity to. + + Returns: + A string representing the color with opacity, + in the format `"color,opacity"`. + + Examples: + >>> CupertinoColors.with_opacity(0.5, CupertinoColors.WHITE) + 'white,0.5' + + Raises: + ValueError: If the opacity is not between `0` and `1` (inclusive). + """ + if not (0 <= opacity <= 1): + raise ValueError( + f"opacity must be between 0.0 and 1.0 inclusive, got {opacity}" + ) + color_str = color.value if isinstance(color, Enum) else color + return f"{color_str},{opacity}" + + @staticmethod + def random( + exclude: Optional[list["CupertinoColors"]] = None, + weights: Optional[dict["CupertinoColors", int]] = None, + ) -> Optional["CupertinoColors"]: + """ + Selects a random color, with optional exclusions and weights. + + Args: + exclude: A list of colors members to exclude from the selection. + weights: A dictionary mapping color members to their respective weights for + weighted random selection. + + Returns: + A randomly selected color, or None if all members are excluded. + + Examples: + >>> CupertinoColors.random(exclude=[CupertinoColors.WHITE]) + CupertinoColors.ON_PRIMARY + """ + choices = list(CupertinoColors) + if exclude: + choices = [member for member in choices if member not in exclude] + if not choices: + return None + if weights: + weights_list = [weights.get(c, 1) for c in choices] + return random.choices(choices, weights=weights_list)[0] + return random.choice(choices) + + ACTIVE_BLUE = "activeBlue" + ACTIVE_GREEN = "activeGreen" + ACTIVE_ORANGE = "activeOrange" + BLACK = "cupertinoBlack" + DARK_BACKGROUND_GRAY = "darkBackgroundGray" + DESTRUCTIVE_RED = "destructiveRed" + EXTRA_LIGHT_BACKGROUND_GRAY = "extraLightBackgroundGray" + INACTIVE_GRAY = "inactiveGray" + LABEL = "label" + LIGHT_BACKGROUND_GRAY = "lightBackgroundGray" + LINK = "link" + ON_PRIMARY = "onprimary" + OPAQUE_SEPARATOR = "opaqueSeparator" + PLACEHOLDER_TEXT = "placeholderText" + PRIMARY = "primary" + QUATERNARY_LABEL = "quaternaryLabel" + QUATERNARY_SYSTEM_FILL = "quaternarySystemFill" + SECONDARY_LABEL = "secondaryLabel" + SECONDARY_SYSTEM_BACKGROUND = "secondarySystemBackground" + SECONDARY_SYSTEM_FILL = "secondarySystemFill" + SECONDARY_SYSTEM_GROUPED_BACKGROUND = "secondarySystemGroupedBackground" + SEPARATOR = "separator" + SYSTEM_BACKGROUND = "systemBackground" + SYSTEM_BLUE = "systemBlue" + SYSTEM_BROWN = "systemBrown" + SYSTEM_CYAN = "systemCyan" + SYSTEM_FILL = "systemFill" + SYSTEM_GREEN = "systemGreen" + SYSTEM_GREY = "systemGrey" + SYSTEM_GREY2 = "systemGrey2" + SYSTEM_GREY3 = "systemGrey3" + SYSTEM_GREY4 = "systemGrey4" + SYSTEM_GREY5 = "systemGrey5" + SYSTEM_GREY6 = "systemGrey6" + SYSTEM_GROUPED_BACKGROUND = "systemGroupedBackground" + SYSTEM_INDIGO = "systemIndigo" + SYSTEM_MINT = "systemMint" + SYSTEM_ORANGE = "systemOrange" + SYSTEM_PINK = "systemPink" + SYSTEM_PURPLE = "systemPurple" + SYSTEM_RED = "systemRed" + SYSTEM_TEAL = "systemTeal" + SYSTEM_YELLOW = "systemYellow" + TERTIARY_LABEL = "tertiaryLabel" + TERTIARY_SYSTEM_BACKGROUND = "tertiarySystemBackground" + TERTIARY_SYSTEM_FILL = "tertiarySystemFill" + TERTIARY_SYSTEM_GROUPED_BACKGROUND = "tertiarySystemGroupedBackground" + WHITE = "cupertinoWhite" diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_context_menu.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_context_menu.py new file mode 100644 index 0000000000..e2ada1ad74 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_context_menu.py @@ -0,0 +1,49 @@ +from typing import Annotated + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.utils.validation import V + +__all__ = ["CupertinoContextMenu"] + + +@control("CupertinoContextMenu") +class CupertinoContextMenu(AdaptiveControl): + """ + A full-screen modal route that opens up when the :attr:`content` is long-pressed. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The content of this context menu. + + Info: + When this context menu is long-pressed, the menu will open and this control + will be moved to the new route and be expanded. This allows the content + to resize to fit in its place in the new route, if it doesn't size itself. + + Raises: + ValueError: If it is not visible. + """ + + actions: Annotated[ + list[Control], + V.visible_controls(min_count=1), + ] + """ + A list of action buttons to be shown in the menu. + + Typically :class:`~flet.CupertinoContextMenuAction`s. + + Raises: + ValueError: If it does not contain at least one visible `Control`. + """ + + enable_haptic_feedback: bool = True + """ + Whether a click on the :attr:`actions` should produce haptic feedback. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_context_menu_action.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_context_menu_action.py new file mode 100644 index 0000000000..cf35a13ae0 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_context_menu_action.py @@ -0,0 +1,49 @@ +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.types import IconData, StrOrControl +from flet.utils.validation import V + +__all__ = ["CupertinoContextMenuAction"] + + +@control("CupertinoContextMenuAction") +class CupertinoContextMenuAction(AdaptiveControl): + """ + A cupertino context menu action. + + Typically used as a child of :attr:`flet.CupertinoContextMenu.actions`. + """ + + content: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The content of this action button. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + default: bool = False + """ + Whether this action should receive the style of an emphasized, default action. + """ + + destructive: bool = False + """ + Whether this action should receive the style of a destructive action. + """ + + trailing_icon: Optional[IconData] = None + """ + An icon to display at the right of the :attr:`content` control. + """ + + on_click: Optional[ControlEventHandler["CupertinoContextMenuAction"]] = None + """ + Called when this action button is clicked. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py new file mode 100644 index 0000000000..e5359bf13f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_date_picker.py @@ -0,0 +1,321 @@ +from dataclasses import field +from datetime import date, datetime +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.duration import DateTimeValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ColorValue, Locale, Number +from flet.utils.validation import V + +__all__ = [ + "CupertinoDatePicker", + "CupertinoDatePickerDateOrder", + "CupertinoDatePickerMode", +] + + +class CupertinoDatePickerMode(Enum): + """ + Different display modes of :class:`~flet.CupertinoDatePicker`. + """ + + TIME = "time" + """ + Mode that shows the date in hour, minute, and (optional) an AM/PM designation. + The AM/PM designation is shown only if `CupertinoDatePicker` does not use 24h + format, i.e. if :attr:`~flet.CupertinoDatePicker.use_24h_format` is `False`. + Column order is subject to internationalization. + + Example: `4 | 14 | PM` + """ + + DATE = "date" + """ + Mode that shows the date in month, day of month, and year. + Name of month is spelled in full. + Column order is subject to internationalization. + + Example: `July | 13 | 2012` + """ + + DATE_AND_TIME = "dateAndTime" + """ + Mode that shows the date as day of the week, month, day of month and + the time in hour, minute, and (optional) an AM/PM designation. + The AM/PM designation is shown only if `CupertinoDatePicker` does not use 24h + format, i.e. if :attr:`~flet.CupertinoDatePicker.use_24h_format` is `False`. + Column order is subject to internationalization. + + Example: `Fri Jul 13 | 4 | 14 | PM` + """ + + MONTH_YEAR = "monthYear" + """ + Mode that shows the date in month and year. + Name of month is spelled in full. + Column order is subject to internationalization. + + Example: `July | 2012` + """ + + +class CupertinoDatePickerDateOrder(Enum): + """ + Determines the order of the columns inside + :class:`~flet.CupertinoDatePicker` in date mode. + """ + + DAY_MONTH_YEAR = "dmy" + """ + Order of the columns, from left to right: day, month, year. + + Example: `12 | March | 1996` + """ + + MONTH_DAY_YEAR = "mdy" + """ + Order of the columns, from left to right: month, day, year. + + Example: `March | 12 | 1996` + """ + + YEAR_MONTH_DAY = "ymd" + """ + Order of the columns, from left to right: year, month, day. + + Example: `1996 | March | 12` + """ + + YEAR_DAY_MONTH = "ydm" + """ + Order of the columns, from left to right: year, day, month. + + Example: `1996 | 12 | March` + """ + + +@control("CupertinoDatePicker") +class CupertinoDatePicker(LayoutControl): + """ + An iOS-styled date picker. + """ + + value: DateTimeValue = field(default_factory=lambda: datetime.now()) + """ + The initial date and/or time of the picker. + + Defaults to the present date and time. + + Raises: + ValueError: If it is not greater than or equal to :attr:`first_date`, when + :attr:`first_date` is set. + ValueError: If it is not less than or equal to :attr:`last_date`, when + :attr:`last_date` is set. + ValueError: If its year is not greater than or equal to + :attr:`minimum_year`, when :attr:`date_picker_mode` is + :attr:`flet.CupertinoDatePickerMode.DATE` or + :attr:`flet.CupertinoDatePickerMode.MONTH_YEAR`. + ValueError: If its year is not less than or equal to :attr:`maximum_year`, + when :attr:`maximum_year` is set. + ValueError: If its minute is not a multiple of :attr:`minute_interval`. + """ + + locale: Optional[Locale] = None + """ + The locale for this date picker. It is intended for rare cases where this control \ + should be localized differently from the rest of the page. + + Notes: + - The locale must be supported by Flutter's global localization delegates; + otherwise the override is ignored and the control uses the page or system + locale. + - If `None` (the default), the page or system locale is used. + """ + + first_date: Optional[DateTimeValue] = None + """ + The earliest allowable date that the user can select. + + - If set to `None` (the default), there is no lower date limit. + - When not `None`, one can still scroll the picker to dates earlier than + `first_date`, with the exception that the :attr:`on_change` will not be + called. Once let go, the picker will scroll back to `first_date`. + + Note: + In :attr:`flet.CupertinoDatePickerMode.TIME` mode, a time becomes unselectable + if the datetime produced by combining that particular time and the date part of + :attr:`value` is earlier than `last_date`. So typically, `first_date` needs + to be set to a datetime that is on the same date as :attr:`value`. + """ + + last_date: Optional[DateTimeValue] = None + """ + The latest allowable date that the user can select. + + - If set to `None` (the default), there is no upper date limit. + - When not `None`, one can still scroll the picker to dates later than + `last_date`, with the exception that the :attr:`on_change` will not be called. + Once let go, the picker will scroll back to `last_date`. + + Note: + In :attr:`flet.CupertinoDatePickerMode.TIME` mode, a time becomes unselectable + if the datetime produced by combining that particular time and the date part + of :attr:`value` is later than `last_date`. So typically, `last_date` needs + to be set to a datetime that is on the same date as :attr:`value`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this date picker. + """ + + minute_interval: Annotated[ + int, + V.gt(0), + V.factor_of(60), + ] = 1 + """ + The granularity of the minutes spinner, if it is shown in the current \ + :attr:`date_picker_mode`. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not a factor of `60`. + """ + + minimum_year: int = 1 + """ + Minimum year to which the picker can be scrolled when in \ + :attr:`flet.CupertinoDatePickerMode.DATE` mode. + + Raises: + ValueError: If it is greater than :attr:`value` year. + """ + + maximum_year: Optional[int] = None + """ + Maximum year to which the picker can be scrolled when in \ + :attr:`flet.CupertinoDatePickerMode.DATE` mode. + + Defaults to `None` - no limit. + + Raises: + ValueError: If it is less than :attr:`value` year. + """ + + item_extent: Number = 32.0 + """ + The uniform height of all children. + + Raises: + ValueError: If it is not strictly greater than `0`. + """ + + use_24h_format: bool = False + """ + Whether to use the 24-hour time format. + + If `False`, the 12-hour time format is used. + """ + + show_day_of_week: bool = False + """ + Whether to show day of week alongside day. + + Raises: + ValueError: If it is set when :attr:`date_picker_mode` is not + :attr:`flet.CupertinoDatePickerMode.DATE`. + """ + + date_picker_mode: CupertinoDatePickerMode = CupertinoDatePickerMode.DATE_AND_TIME + """ + The mode of the date picker. + """ + + date_order: Optional[CupertinoDatePickerDateOrder] = None + """ + The order in which the columns inside this picker are displayed. + + Note: + The final order in which the columns are displayed is also influenced by + the :attr:`date_picker_mode`. For example, if `date_picker_mode` is + :attr:`flet.CupertinoDatePickerMode.MONTH_YEAR` + both :attr:`flet.CupertinoDatePickerDateOrder.DAY_MONTH_YEAR` and + :attr:`flet.CupertinoDatePickerDateOrder.MONTH_DAY_YEAR` will result + in the `month|year` order. + """ + + on_change: Optional[ControlEventHandler["CupertinoDatePicker"]] = None + """ + Called when the selected date and/or time changes. + + Will not be called if the new selected value is not valid, + or is not in the range of :attr:`first_date` and :attr:`last_date`. + """ + + def before_update(self): + super().before_update() + + # Normalize value to datetime in case it's a date + if isinstance(self.value, date) and not isinstance(self.value, datetime): + value = datetime.combine(self.value, datetime.min.time()) + else: + value = self.value + + if self.item_extent <= 0: + raise ValueError( + f"item_extent must be strictly greater than 0, got {self.item_extent}" + ) + if self.date_picker_mode == CupertinoDatePickerMode.DATE_AND_TIME: + if self.first_date and value < self.first_date: + raise ValueError( + f"value ({value}) can't be before first_date ({self.first_date})" + ) + if self.last_date and value > self.last_date: + raise ValueError( + f"value ({value}) can't be after last_date ({self.last_date})" + ) + + if self.date_picker_mode in [ + CupertinoDatePickerMode.DATE, + CupertinoDatePickerMode.MONTH_YEAR, + ]: + if not (1 <= self.minimum_year <= value.year): + raise ValueError( + f"value.year ({value.year}) can't be less than minimum_year " + f"({self.minimum_year})" + ) + + if self.maximum_year and value.year > self.maximum_year: + raise ValueError( + f"value.year ({value.year}) can't be greater than maximum_year " + f"({self.maximum_year})" + ) + + if self.first_date and value < self.first_date: + raise ValueError( + f"value ({value}) can't be before first_date ({self.first_date})" + ) + + if self.last_date and value > self.last_date: + raise ValueError( + f"value ({value}) can't be after last_date ({self.last_date})" + ) + + if ( + self.date_picker_mode != CupertinoDatePickerMode.DATE + and self.show_day_of_week + ): + raise ValueError( + "show_day_of_week is only supported when date_picker_mode is " + "CupertinoDatePickerMode.DATE" + ) + + if self.minute_interval > 0 and value.minute % self.minute_interval != 0: + raise ValueError( + f"value.minute ({value.minute}) must be a multiple of minute_interval " + f"({self.minute_interval})" + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_dialog_action.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_dialog_action.py new file mode 100644 index 0000000000..1dc0d34e6e --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_dialog_action.py @@ -0,0 +1,60 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.text_style import TextStyle +from flet.controls.types import StrOrControl +from flet.utils.validation import V + +__all__ = ["CupertinoDialogAction"] + + +@control("CupertinoDialogAction") +class CupertinoDialogAction(Control): + """ + A dialog action button. + + Typically used as a child of :attr:`flet.CupertinoAlertDialog.actions`. + """ + + content: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The content of this action button. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + default: bool = False + """ + Whether this action is a default action. + In this case, the button will have bold text. + + Info: + Multiple actions can have this property set to `True` + in a :class:`~flet.CupertinoAlertDialog`. + """ + + destructive: bool = False + """ + If set to `True`, this button's text color will be red. + + Typically used for actions that destroy objects, + such as an delete that deletes an email etc. + """ + + text_style: Optional[TextStyle] = None + """ + The text style to use for text in this button. + + Can be useful when :attr:`content` is a string. + """ + + on_click: Optional[ControlEventHandler["CupertinoDialogAction"]] = None + """ + Called when a user clicks this button. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_filled_button.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_filled_button.py new file mode 100644 index 0000000000..a0e82140dd --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_filled_button.py @@ -0,0 +1,15 @@ +from flet.controls.base_control import control +from flet.controls.cupertino.cupertino_button import CupertinoButton + +__all__ = ["CupertinoFilledButton"] + + +@control("CupertinoFilledButton") +class CupertinoFilledButton(CupertinoButton): + """ + An iOS-style button filled with default background color. + + ```python + ft.CupertinoFilledButton("Tap me") + ``` + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.json b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.json new file mode 100644 index 0000000000..ccbf8d3902 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.json @@ -0,0 +1 @@ +{"ADD":131072,"ADD_CIRCLED":131073,"ADD_CIRCLED_SOLID":131074,"AIRPLANE":131075,"ALARM":131076,"ALARM_FILL":131077,"ALT":131078,"ANT":131079,"ANT_CIRCLE":131080,"ANT_CIRCLE_FILL":131081,"ANT_FILL":131082,"ANTENNA_RADIOWAVES_LEFT_RIGHT":131083,"APP":131084,"APP_BADGE":131085,"APP_BADGE_FILL":131086,"APP_FILL":131087,"ARCHIVEBOX":131088,"ARCHIVEBOX_FILL":131089,"ARROW_2_CIRCLEPATH":131090,"ARROW_2_CIRCLEPATH_CIRCLE":131091,"ARROW_2_CIRCLEPATH_CIRCLE_FILL":131092,"ARROW_2_SQUAREPATH":131093,"ARROW_3_TRIANGLEPATH":131094,"ARROW_BRANCH":131095,"ARROW_CLOCKWISE":131096,"ARROW_CLOCKWISE_CIRCLE":131097,"ARROW_CLOCKWISE_CIRCLE_FILL":131098,"ARROW_COUNTERCLOCKWISE":131099,"ARROW_COUNTERCLOCKWISE_CIRCLE":131100,"ARROW_COUNTERCLOCKWISE_CIRCLE_FILL":131101,"ARROW_DOWN":131102,"ARROW_DOWN_CIRCLE":131103,"ARROW_DOWN_CIRCLE_FILL":131104,"ARROW_DOWN_DOC":131105,"ARROW_DOWN_DOC_FILL":131106,"ARROW_DOWN_LEFT":131107,"ARROW_DOWN_LEFT_CIRCLE":131108,"ARROW_DOWN_LEFT_CIRCLE_FILL":131109,"ARROW_DOWN_LEFT_SQUARE":131110,"ARROW_DOWN_LEFT_SQUARE_FILL":131111,"ARROW_DOWN_RIGHT":131112,"ARROW_DOWN_RIGHT_ARROW_UP_LEFT":131113,"ARROW_DOWN_RIGHT_CIRCLE":131114,"ARROW_DOWN_RIGHT_CIRCLE_FILL":131115,"ARROW_DOWN_RIGHT_SQUARE":131116,"ARROW_DOWN_RIGHT_SQUARE_FILL":131117,"ARROW_DOWN_SQUARE":131118,"ARROW_DOWN_SQUARE_FILL":131119,"ARROW_DOWN_TO_LINE":131120,"ARROW_DOWN_TO_LINE_ALT":131121,"ARROW_LEFT":131122,"ARROW_LEFT_CIRCLE":131123,"ARROW_LEFT_CIRCLE_FILL":131124,"ARROW_LEFT_RIGHT":131125,"ARROW_LEFT_RIGHT_CIRCLE":131126,"ARROW_LEFT_RIGHT_CIRCLE_FILL":131127,"ARROW_LEFT_RIGHT_SQUARE":131128,"ARROW_LEFT_RIGHT_SQUARE_FILL":131129,"ARROW_LEFT_SQUARE":131130,"ARROW_LEFT_SQUARE_FILL":131131,"ARROW_LEFT_TO_LINE":131132,"ARROW_LEFT_TO_LINE_ALT":131133,"ARROW_MERGE":131134,"ARROW_RIGHT":131135,"ARROW_RIGHT_ARROW_LEFT":131136,"ARROW_RIGHT_ARROW_LEFT_CIRCLE":131137,"ARROW_RIGHT_ARROW_LEFT_CIRCLE_FILL":131138,"ARROW_RIGHT_ARROW_LEFT_SQUARE":131139,"ARROW_RIGHT_ARROW_LEFT_SQUARE_FILL":131140,"ARROW_RIGHT_CIRCLE":131141,"ARROW_RIGHT_CIRCLE_FILL":131142,"ARROW_RIGHT_SQUARE":131143,"ARROW_RIGHT_SQUARE_FILL":131144,"ARROW_RIGHT_TO_LINE":131145,"ARROW_RIGHT_TO_LINE_ALT":131146,"ARROW_SWAP":131147,"ARROW_TURN_DOWN_LEFT":131148,"ARROW_TURN_DOWN_RIGHT":131149,"ARROW_TURN_LEFT_DOWN":131150,"ARROW_TURN_LEFT_UP":131151,"ARROW_TURN_RIGHT_DOWN":131152,"ARROW_TURN_RIGHT_UP":131153,"ARROW_TURN_UP_LEFT":131154,"ARROW_TURN_UP_RIGHT":131155,"ARROW_UP":131156,"ARROW_UP_ARROW_DOWN":131157,"ARROW_UP_ARROW_DOWN_CIRCLE":131158,"ARROW_UP_ARROW_DOWN_CIRCLE_FILL":131159,"ARROW_UP_ARROW_DOWN_SQUARE":131160,"ARROW_UP_ARROW_DOWN_SQUARE_FILL":131161,"ARROW_UP_BIN":131162,"ARROW_UP_BIN_FILL":131163,"ARROW_UP_CIRCLE":131164,"ARROW_UP_CIRCLE_FILL":131165,"ARROW_UP_DOC":131166,"ARROW_UP_DOC_FILL":131167,"ARROW_UP_DOWN":131168,"ARROW_UP_DOWN_CIRCLE":131169,"ARROW_UP_DOWN_CIRCLE_FILL":131170,"ARROW_UP_DOWN_SQUARE":131171,"ARROW_UP_DOWN_SQUARE_FILL":131172,"ARROW_UP_LEFT":131173,"ARROW_UP_LEFT_ARROW_DOWN_RIGHT":131174,"ARROW_UP_LEFT_CIRCLE":131175,"ARROW_UP_LEFT_CIRCLE_FILL":131176,"ARROW_UP_LEFT_SQUARE":131177,"ARROW_UP_LEFT_SQUARE_FILL":131178,"ARROW_UP_RIGHT":131179,"ARROW_UP_RIGHT_CIRCLE":131180,"ARROW_UP_RIGHT_CIRCLE_FILL":131181,"ARROW_UP_RIGHT_DIAMOND":131182,"ARROW_UP_RIGHT_DIAMOND_FILL":131183,"ARROW_UP_RIGHT_SQUARE":131184,"ARROW_UP_RIGHT_SQUARE_FILL":131185,"ARROW_UP_SQUARE":131186,"ARROW_UP_SQUARE_FILL":131187,"ARROW_UP_TO_LINE":131188,"ARROW_UP_TO_LINE_ALT":131189,"ARROW_UTURN_DOWN":131190,"ARROW_UTURN_DOWN_CIRCLE":131191,"ARROW_UTURN_DOWN_CIRCLE_FILL":131192,"ARROW_UTURN_DOWN_SQUARE":131193,"ARROW_UTURN_DOWN_SQUARE_FILL":131194,"ARROW_UTURN_LEFT":131195,"ARROW_UTURN_LEFT_CIRCLE":131196,"ARROW_UTURN_LEFT_CIRCLE_FILL":131197,"ARROW_UTURN_LEFT_SQUARE":131198,"ARROW_UTURN_LEFT_SQUARE_FILL":131199,"ARROW_UTURN_RIGHT":131200,"ARROW_UTURN_RIGHT_CIRCLE":131201,"ARROW_UTURN_RIGHT_CIRCLE_FILL":131202,"ARROW_UTURN_RIGHT_SQUARE":131203,"ARROW_UTURN_RIGHT_SQUARE_FILL":131204,"ARROW_UTURN_UP":131205,"ARROW_UTURN_UP_CIRCLE":131206,"ARROW_UTURN_UP_CIRCLE_FILL":131207,"ARROW_UTURN_UP_SQUARE":131208,"ARROW_UTURN_UP_SQUARE_FILL":131209,"ARROWSHAPE_TURN_UP_LEFT":131210,"ARROWSHAPE_TURN_UP_LEFT_2":131211,"ARROWSHAPE_TURN_UP_LEFT_2_FILL":131212,"ARROWSHAPE_TURN_UP_LEFT_CIRCLE":131213,"ARROWSHAPE_TURN_UP_LEFT_CIRCLE_FILL":131214,"ARROWSHAPE_TURN_UP_LEFT_FILL":131215,"ARROWSHAPE_TURN_UP_RIGHT":131216,"ARROWSHAPE_TURN_UP_RIGHT_CIRCLE":131217,"ARROWSHAPE_TURN_UP_RIGHT_CIRCLE_FILL":131218,"ARROWSHAPE_TURN_UP_RIGHT_FILL":131219,"ARROWTRIANGLE_DOWN":131220,"ARROWTRIANGLE_DOWN_CIRCLE":131221,"ARROWTRIANGLE_DOWN_CIRCLE_FILL":131222,"ARROWTRIANGLE_DOWN_FILL":131223,"ARROWTRIANGLE_DOWN_SQUARE":131224,"ARROWTRIANGLE_DOWN_SQUARE_FILL":131225,"ARROWTRIANGLE_LEFT":131226,"ARROWTRIANGLE_LEFT_CIRCLE":131227,"ARROWTRIANGLE_LEFT_CIRCLE_FILL":131228,"ARROWTRIANGLE_LEFT_FILL":131229,"ARROWTRIANGLE_LEFT_SQUARE":131230,"ARROWTRIANGLE_LEFT_SQUARE_FILL":131231,"ARROWTRIANGLE_RIGHT":131232,"ARROWTRIANGLE_RIGHT_CIRCLE":131233,"ARROWTRIANGLE_RIGHT_CIRCLE_FILL":131234,"ARROWTRIANGLE_RIGHT_FILL":131235,"ARROWTRIANGLE_RIGHT_SQUARE":131236,"ARROWTRIANGLE_RIGHT_SQUARE_FILL":131237,"ARROWTRIANGLE_UP":131238,"ARROWTRIANGLE_UP_CIRCLE":131239,"ARROWTRIANGLE_UP_CIRCLE_FILL":131240,"ARROWTRIANGLE_UP_FILL":131241,"ARROWTRIANGLE_UP_SQUARE":131242,"ARROWTRIANGLE_UP_SQUARE_FILL":131243,"ASTERISK_CIRCLE":131244,"ASTERISK_CIRCLE_FILL":131245,"AT":131246,"AT_BADGE_MINUS":131247,"AT_BADGE_PLUS":131248,"AT_CIRCLE":131249,"AT_CIRCLE_FILL":131250,"BACK":131251,"BACKWARD":131252,"BACKWARD_END":131253,"BACKWARD_END_ALT":131254,"BACKWARD_END_ALT_FILL":131255,"BACKWARD_END_FILL":131256,"BACKWARD_FILL":131257,"BADGE_PLUS_RADIOWAVES_RIGHT":131258,"BAG":131259,"BAG_BADGE_MINUS":131260,"BAG_BADGE_PLUS":131261,"BAG_FILL":131262,"BAG_FILL_BADGE_MINUS":131263,"BAG_FILL_BADGE_PLUS":131264,"BANDAGE":131265,"BANDAGE_FILL":131266,"BARCODE":131267,"BARCODE_VIEWFINDER":131268,"BARS":131269,"BATTERY_0":131270,"BATTERY_100":131271,"BATTERY_25":131272,"BATTERY_25_PERCENT":131273,"BATTERY_75_PERCENT":131274,"BATTERY_CHARGING":131275,"BATTERY_EMPTY":131276,"BATTERY_FULL":131277,"BED_DOUBLE":131278,"BED_DOUBLE_FILL":131279,"BELL":131280,"BELL_CIRCLE":131281,"BELL_CIRCLE_FILL":131282,"BELL_FILL":131283,"BELL_SLASH":131284,"BELL_SLASH_FILL":131285,"BELL_SOLID":131286,"BIN_XMARK":131287,"BIN_XMARK_FILL":131288,"BITCOIN":131289,"BITCOIN_CIRCLE":131290,"BITCOIN_CIRCLE_FILL":131291,"BLUETOOTH":131292,"BOLD":131293,"BOLD_ITALIC_UNDERLINE":131294,"BOLD_UNDERLINE":131295,"BOLT":131296,"BOLT_BADGE_A":131297,"BOLT_BADGE_A_FILL":131298,"BOLT_CIRCLE":131299,"BOLT_CIRCLE_FILL":131300,"BOLT_FILL":131301,"BOLT_HORIZONTAL":131302,"BOLT_HORIZONTAL_CIRCLE":131303,"BOLT_HORIZONTAL_CIRCLE_FILL":131304,"BOLT_HORIZONTAL_FILL":131305,"BOLT_SLASH":131306,"BOLT_SLASH_FILL":131307,"BOOK":131308,"BOOK_CIRCLE":131309,"BOOK_CIRCLE_FILL":131310,"BOOK_FILL":131311,"BOOK_SOLID":131312,"BOOKMARK":131313,"BOOKMARK_FILL":131314,"BOOKMARK_SOLID":131315,"BRIEFCASE":131316,"BRIEFCASE_FILL":131317,"BRIGHTNESS":131318,"BRIGHTNESS_SOLID":131319,"BUBBLE_LEFT":131320,"BUBBLE_LEFT_BUBBLE_RIGHT":131321,"BUBBLE_LEFT_BUBBLE_RIGHT_FILL":131322,"BUBBLE_LEFT_FILL":131323,"BUBBLE_MIDDLE_BOTTOM":131324,"BUBBLE_MIDDLE_BOTTOM_FILL":131325,"BUBBLE_MIDDLE_TOP":131326,"BUBBLE_MIDDLE_TOP_FILL":131327,"BUBBLE_RIGHT":131328,"BUBBLE_RIGHT_FILL":131329,"BUILDING_2_FILL":131330,"BURN":131331,"BURST":131332,"BURST_FILL":131333,"BUS":131334,"CALENDAR":131335,"CALENDAR_BADGE_MINUS":131336,"CALENDAR_BADGE_PLUS":131337,"CALENDAR_CIRCLE":131338,"CALENDAR_CIRCLE_FILL":131339,"CALENDAR_TODAY":131340,"CAMERA":131341,"CAMERA_CIRCLE":131342,"CAMERA_CIRCLE_FILL":131343,"CAMERA_FILL":131344,"CAMERA_ON_RECTANGLE":131345,"CAMERA_ON_RECTANGLE_FILL":131346,"CAMERA_ROTATE":131347,"CAMERA_ROTATE_FILL":131348,"CAMERA_VIEWFINDER":131349,"CAPSLOCK":131350,"CAPSLOCK_FILL":131351,"CAPSULE":131352,"CAPSULE_FILL":131353,"CAPTIONS_BUBBLE":131354,"CAPTIONS_BUBBLE_FILL":131355,"CAR":131356,"CAR_DETAILED":131357,"CAR_FILL":131358,"CART":131359,"CART_BADGE_MINUS":131360,"CART_BADGE_PLUS":131361,"CART_FILL":131362,"CART_FILL_BADGE_MINUS":131363,"CART_FILL_BADGE_PLUS":131364,"CHART_BAR":131365,"CHART_BAR_ALT_FILL":131366,"CHART_BAR_CIRCLE":131367,"CHART_BAR_CIRCLE_FILL":131368,"CHART_BAR_FILL":131369,"CHART_BAR_SQUARE":131370,"CHART_BAR_SQUARE_FILL":131371,"CHART_PIE":131372,"CHART_PIE_FILL":131373,"CHAT_BUBBLE":131374,"CHAT_BUBBLE_2":131375,"CHAT_BUBBLE_2_FILL":131376,"CHAT_BUBBLE_FILL":131377,"CHAT_BUBBLE_TEXT":131378,"CHAT_BUBBLE_TEXT_FILL":131379,"CHECK_MARK":131380,"CHECK_MARK_CIRCLED":131381,"CHECK_MARK_CIRCLED_SOLID":131382,"CHECKMARK":131383,"CHECKMARK_ALT":131384,"CHECKMARK_ALT_CIRCLE":131385,"CHECKMARK_ALT_CIRCLE_FILL":131386,"CHECKMARK_CIRCLE":131387,"CHECKMARK_CIRCLE_FILL":131388,"CHECKMARK_RECTANGLE":131389,"CHECKMARK_RECTANGLE_FILL":131390,"CHECKMARK_SEAL":131391,"CHECKMARK_SEAL_FILL":131392,"CHECKMARK_SHIELD":131393,"CHECKMARK_SHIELD_FILL":131394,"CHECKMARK_SQUARE":131395,"CHECKMARK_SQUARE_FILL":131396,"CHEVRON_BACK":131397,"CHEVRON_COMPACT_DOWN":131398,"CHEVRON_COMPACT_LEFT":131399,"CHEVRON_COMPACT_RIGHT":131400,"CHEVRON_COMPACT_UP":131401,"CHEVRON_DOWN":131402,"CHEVRON_DOWN_CIRCLE":131403,"CHEVRON_DOWN_CIRCLE_FILL":131404,"CHEVRON_DOWN_SQUARE":131405,"CHEVRON_DOWN_SQUARE_FILL":131406,"CHEVRON_FORWARD":131407,"CHEVRON_LEFT":131408,"CHEVRON_LEFT_2":131409,"CHEVRON_LEFT_CIRCLE":131410,"CHEVRON_LEFT_CIRCLE_FILL":131411,"CHEVRON_LEFT_SLASH_CHEVRON_RIGHT":131412,"CHEVRON_LEFT_SQUARE":131413,"CHEVRON_LEFT_SQUARE_FILL":131414,"CHEVRON_RIGHT":131415,"CHEVRON_RIGHT_2":131416,"CHEVRON_RIGHT_CIRCLE":131417,"CHEVRON_RIGHT_CIRCLE_FILL":131418,"CHEVRON_RIGHT_SQUARE":131419,"CHEVRON_RIGHT_SQUARE_FILL":131420,"CHEVRON_UP":131421,"CHEVRON_UP_CHEVRON_DOWN":131422,"CHEVRON_UP_CIRCLE":131423,"CHEVRON_UP_CIRCLE_FILL":131424,"CHEVRON_UP_SQUARE":131425,"CHEVRON_UP_SQUARE_FILL":131426,"CIRCLE":131427,"CIRCLE_BOTTOMTHIRD_SPLIT":131428,"CIRCLE_FILL":131429,"CIRCLE_FILLED":131430,"CIRCLE_GRID_3X3":131431,"CIRCLE_GRID_3X3_FILL":131432,"CIRCLE_GRID_HEX":131433,"CIRCLE_GRID_HEX_FILL":131434,"CIRCLE_LEFTHALF_FILL":131435,"CIRCLE_RIGHTHALF_FILL":131436,"CLEAR":131437,"CLEAR_CIRCLED":131438,"CLEAR_CIRCLED_SOLID":131439,"CLEAR_FILL":131440,"CLEAR_THICK":131441,"CLEAR_THICK_CIRCLED":131442,"CLOCK":131443,"CLOCK_FILL":131444,"CLOCK_SOLID":131445,"CLOUD":131446,"CLOUD_BOLT":131447,"CLOUD_BOLT_FILL":131448,"CLOUD_BOLT_RAIN":131449,"CLOUD_BOLT_RAIN_FILL":131450,"CLOUD_DOWNLOAD":131451,"CLOUD_DOWNLOAD_FILL":131452,"CLOUD_DRIZZLE":131453,"CLOUD_DRIZZLE_FILL":131454,"CLOUD_FILL":131455,"CLOUD_FOG":131456,"CLOUD_FOG_FILL":131457,"CLOUD_HAIL":131458,"CLOUD_HAIL_FILL":131459,"CLOUD_HEAVYRAIN":131460,"CLOUD_HEAVYRAIN_FILL":131461,"CLOUD_MOON":131462,"CLOUD_MOON_BOLT":131463,"CLOUD_MOON_BOLT_FILL":131464,"CLOUD_MOON_FILL":131465,"CLOUD_MOON_RAIN":131466,"CLOUD_MOON_RAIN_FILL":131467,"CLOUD_RAIN":131468,"CLOUD_RAIN_FILL":131469,"CLOUD_SLEET":131470,"CLOUD_SLEET_FILL":131471,"CLOUD_SNOW":131472,"CLOUD_SNOW_FILL":131473,"CLOUD_SUN":131474,"CLOUD_SUN_BOLT":131475,"CLOUD_SUN_BOLT_FILL":131476,"CLOUD_SUN_FILL":131477,"CLOUD_SUN_RAIN":131478,"CLOUD_SUN_RAIN_FILL":131479,"CLOUD_UPLOAD":131480,"CLOUD_UPLOAD_FILL":131481,"COLLECTIONS":131482,"COLLECTIONS_SOLID":131483,"COLOR_FILTER":131484,"COLOR_FILTER_FILL":131485,"COMMAND":131486,"COMPASS":131487,"COMPASS_FILL":131488,"CONTROL":131489,"CONVERSATION_BUBBLE":131490,"CREATE":131491,"CREATE_SOLID":131492,"CREDITCARD":131493,"CREDITCARD_FILL":131494,"CROP":131495,"CROP_ROTATE":131496,"CUBE":131497,"CUBE_BOX":131498,"CUBE_BOX_FILL":131499,"CUBE_FILL":131500,"CURSOR_RAYS":131501,"DECREASE_INDENT":131502,"DECREASE_QUOTELEVEL":131503,"DELETE":131504,"DELETE_LEFT":131505,"DELETE_LEFT_FILL":131506,"DELETE_RIGHT":131507,"DELETE_RIGHT_FILL":131508,"DELETE_SIMPLE":131509,"DELETE_SOLID":131510,"DESKTOPCOMPUTER":131511,"DEVICE_DESKTOP":131512,"DEVICE_LAPTOP":131513,"DEVICE_PHONE_LANDSCAPE":131514,"DEVICE_PHONE_PORTRAIT":131515,"DIAL":131516,"DIAL_FILL":131517,"DIVIDE":131518,"DIVIDE_CIRCLE":131519,"DIVIDE_CIRCLE_FILL":131520,"DIVIDE_SQUARE":131521,"DIVIDE_SQUARE_FILL":131522,"DOC":131523,"DOC_APPEND":131524,"DOC_CHART":131525,"DOC_CHART_FILL":131526,"DOC_CHECKMARK":131527,"DOC_CHECKMARK_FILL":131528,"DOC_CIRCLE":131529,"DOC_CIRCLE_FILL":131530,"DOC_FILL":131531,"DOC_ON_CLIPBOARD":131532,"DOC_ON_CLIPBOARD_FILL":131533,"DOC_ON_DOC":131534,"DOC_ON_DOC_FILL":131535,"DOC_PERSON":131536,"DOC_PERSON_FILL":131537,"DOC_PLAINTEXT":131538,"DOC_RICHTEXT":131539,"DOC_TEXT":131540,"DOC_TEXT_FILL":131541,"DOC_TEXT_SEARCH":131542,"DOC_TEXT_VIEWFINDER":131543,"DOT_RADIOWAVES_LEFT_RIGHT":131544,"DOT_RADIOWAVES_RIGHT":131545,"DOT_SQUARE":131546,"DOT_SQUARE_FILL":131547,"DOUBLE_MUSIC_NOTE":131548,"DOWN_ARROW":131549,"DOWNLOAD_CIRCLE":131550,"DOWNLOAD_CIRCLE_FILL":131551,"DROP":131552,"DROP_FILL":131553,"DROP_TRIANGLE":131554,"DROP_TRIANGLE_FILL":131555,"EAR":131556,"EJECT":131557,"EJECT_FILL":131558,"ELLIPSES_BUBBLE":131559,"ELLIPSES_BUBBLE_FILL":131560,"ELLIPSIS":131561,"ELLIPSIS_CIRCLE":131562,"ELLIPSIS_CIRCLE_FILL":131563,"ELLIPSIS_VERTICAL":131564,"ELLIPSIS_VERTICAL_CIRCLE":131565,"ELLIPSIS_VERTICAL_CIRCLE_FILL":131566,"ENVELOPE":131567,"ENVELOPE_BADGE":131568,"ENVELOPE_BADGE_FILL":131569,"ENVELOPE_CIRCLE":131570,"ENVELOPE_CIRCLE_FILL":131571,"ENVELOPE_FILL":131572,"ENVELOPE_OPEN":131573,"ENVELOPE_OPEN_FILL":131574,"EQUAL":131575,"EQUAL_CIRCLE":131576,"EQUAL_CIRCLE_FILL":131577,"EQUAL_SQUARE":131578,"EQUAL_SQUARE_FILL":131579,"ESCAPE":131580,"EXCLAMATIONMARK":131581,"EXCLAMATIONMARK_BUBBLE":131582,"EXCLAMATIONMARK_BUBBLE_FILL":131583,"EXCLAMATIONMARK_CIRCLE":131584,"EXCLAMATIONMARK_CIRCLE_FILL":131585,"EXCLAMATIONMARK_OCTAGON":131586,"EXCLAMATIONMARK_OCTAGON_FILL":131587,"EXCLAMATIONMARK_SHIELD":131588,"EXCLAMATIONMARK_SHIELD_FILL":131589,"EXCLAMATIONMARK_SQUARE":131590,"EXCLAMATIONMARK_SQUARE_FILL":131591,"EXCLAMATIONMARK_TRIANGLE":131592,"EXCLAMATIONMARK_TRIANGLE_FILL":131593,"EYE":131594,"EYE_FILL":131595,"EYE_SLASH":131596,"EYE_SLASH_FILL":131597,"EYE_SOLID":131598,"EYEDROPPER":131599,"EYEDROPPER_FULL":131600,"EYEDROPPER_HALFFULL":131601,"EYEGLASSES":131602,"F_CURSIVE":131603,"F_CURSIVE_CIRCLE":131604,"F_CURSIVE_CIRCLE_FILL":131605,"FILM":131606,"FILM_FILL":131607,"FLAG":131608,"FLAG_CIRCLE":131609,"FLAG_CIRCLE_FILL":131610,"FLAG_FILL":131611,"FLAG_SLASH":131612,"FLAG_SLASH_FILL":131613,"FLAME":131614,"FLAME_FILL":131615,"FLOPPY_DISK":131616,"FLOWCHART":131617,"FLOWCHART_FILL":131618,"FOLDER":131619,"FOLDER_BADGE_MINUS":131620,"FOLDER_BADGE_PERSON_CROP":131621,"FOLDER_BADGE_PLUS":131622,"FOLDER_CIRCLE":131623,"FOLDER_CIRCLE_FILL":131624,"FOLDER_FILL":131625,"FOLDER_FILL_BADGE_MINUS":131626,"FOLDER_FILL_BADGE_PERSON_CROP":131627,"FOLDER_FILL_BADGE_PLUS":131628,"FOLDER_OPEN":131629,"FOLDER_SOLID":131630,"FORWARD":131631,"FORWARD_END":131632,"FORWARD_END_ALT":131633,"FORWARD_END_ALT_FILL":131634,"FORWARD_END_FILL":131635,"FORWARD_FILL":131636,"FULLSCREEN":131637,"FULLSCREEN_EXIT":131638,"FUNCTION":131639,"FX":131640,"GAME_CONTROLLER":131641,"GAME_CONTROLLER_SOLID":131642,"GAMECONTROLLER":131643,"GAMECONTROLLER_ALT_FILL":131644,"GAMECONTROLLER_FILL":131645,"GAUGE":131646,"GAUGE_BADGE_MINUS":131647,"GAUGE_BADGE_PLUS":131648,"GEAR":131649,"GEAR_ALT":131650,"GEAR_ALT_FILL":131651,"GEAR_BIG":131652,"GEAR_SOLID":131653,"GIFT":131654,"GIFT_ALT":131655,"GIFT_ALT_FILL":131656,"GIFT_FILL":131657,"GLOBE":131658,"GOBACKWARD":131659,"GOBACKWARD_10":131660,"GOBACKWARD_15":131661,"GOBACKWARD_30":131662,"GOBACKWARD_45":131663,"GOBACKWARD_60":131664,"GOBACKWARD_75":131665,"GOBACKWARD_90":131666,"GOBACKWARD_MINUS":131667,"GOFORWARD":131668,"GOFORWARD_10":131669,"GOFORWARD_15":131670,"GOFORWARD_30":131671,"GOFORWARD_45":131672,"GOFORWARD_60":131673,"GOFORWARD_75":131674,"GOFORWARD_90":131675,"GOFORWARD_PLUS":131676,"GRAPH_CIRCLE":131677,"GRAPH_CIRCLE_FILL":131678,"GRAPH_SQUARE":131679,"GRAPH_SQUARE_FILL":131680,"GREATERTHAN":131681,"GREATERTHAN_CIRCLE":131682,"GREATERTHAN_CIRCLE_FILL":131683,"GREATERTHAN_SQUARE":131684,"GREATERTHAN_SQUARE_FILL":131685,"GRID":131686,"GRID_CIRCLE":131687,"GRID_CIRCLE_FILL":131688,"GROUP":131689,"GROUP_SOLID":131690,"GUITARS":131691,"HAMMER":131692,"HAMMER_FILL":131693,"HAND_DRAW":131694,"HAND_DRAW_FILL":131695,"HAND_POINT_LEFT":131696,"HAND_POINT_LEFT_FILL":131697,"HAND_POINT_RIGHT":131698,"HAND_POINT_RIGHT_FILL":131699,"HAND_RAISED":131700,"HAND_RAISED_FILL":131701,"HAND_RAISED_SLASH":131702,"HAND_RAISED_SLASH_FILL":131703,"HAND_THUMBSDOWN":131704,"HAND_THUMBSDOWN_FILL":131705,"HAND_THUMBSUP":131706,"HAND_THUMBSUP_FILL":131707,"HARE":131708,"HARE_FILL":131709,"HEADPHONES":131710,"HEART":131711,"HEART_CIRCLE":131712,"HEART_CIRCLE_FILL":131713,"HEART_FILL":131714,"HEART_SLASH":131715,"HEART_SLASH_CIRCLE":131716,"HEART_SLASH_CIRCLE_FILL":131717,"HEART_SLASH_FILL":131718,"HEART_SOLID":131719,"HELM":131720,"HEXAGON":131721,"HEXAGON_FILL":131722,"HIFISPEAKER":131723,"HIFISPEAKER_FILL":131724,"HOME":131725,"HOURGLASS":131726,"HOURGLASS_BOTTOMHALF_FILL":131727,"HOURGLASS_TOPHALF_FILL":131728,"HOUSE":131729,"HOUSE_ALT":131730,"HOUSE_ALT_FILL":131731,"HOUSE_FILL":131732,"HURRICANE":131733,"INCREASE_INDENT":131734,"INCREASE_QUOTELEVEL":131735,"INFINITE":131736,"INFO":131737,"INFO_CIRCLE":131738,"INFO_CIRCLE_FILL":131739,"ITALIC":131740,"KEYBOARD":131741,"KEYBOARD_CHEVRON_COMPACT_DOWN":131742,"LAB_FLASK":131743,"LAB_FLASK_SOLID":131744,"LARGECIRCLE_FILL_CIRCLE":131745,"LASSO":131746,"LAYERS":131747,"LAYERS_ALT":131748,"LAYERS_ALT_FILL":131749,"LAYERS_FILL":131750,"LEAF_ARROW_CIRCLEPATH":131751,"LEFT_CHEVRON":131752,"LESSTHAN":131753,"LESSTHAN_CIRCLE":131754,"LESSTHAN_CIRCLE_FILL":131755,"LESSTHAN_SQUARE":131756,"LESSTHAN_SQUARE_FILL":131757,"LIGHT_MAX":131758,"LIGHT_MIN":131759,"LIGHTBULB":131760,"LIGHTBULB_FILL":131761,"LIGHTBULB_SLASH":131762,"LIGHTBULB_SLASH_FILL":131763,"LINE_HORIZONTAL_3":131764,"LINE_HORIZONTAL_3_DECREASE":131765,"LINE_HORIZONTAL_3_DECREASE_CIRCLE":131766,"LINE_HORIZONTAL_3_DECREASE_CIRCLE_FILL":131767,"LINK":131768,"LINK_CIRCLE":131769,"LINK_CIRCLE_FILL":131770,"LIST_BULLET":131771,"LIST_BULLET_BELOW_RECTANGLE":131772,"LIST_BULLET_INDENT":131773,"LIST_DASH":131774,"LIST_NUMBER":131775,"LIST_NUMBER_RTL":131776,"LOCATION":131777,"LOCATION_CIRCLE":131778,"LOCATION_CIRCLE_FILL":131779,"LOCATION_FILL":131780,"LOCATION_NORTH":131781,"LOCATION_NORTH_FILL":131782,"LOCATION_NORTH_LINE":131783,"LOCATION_NORTH_LINE_FILL":131784,"LOCATION_SLASH":131785,"LOCATION_SLASH_FILL":131786,"LOCATION_SOLID":131787,"LOCK":131788,"LOCK_CIRCLE":131789,"LOCK_CIRCLE_FILL":131790,"LOCK_FILL":131791,"LOCK_OPEN":131792,"LOCK_OPEN_FILL":131793,"LOCK_ROTATION":131794,"LOCK_ROTATION_OPEN":131795,"LOCK_SHIELD":131796,"LOCK_SHIELD_FILL":131797,"LOCK_SLASH":131798,"LOCK_SLASH_FILL":131799,"LOOP":131800,"LOOP_THICK":131801,"MACWINDOW":131802,"MAIL":131803,"MAIL_SOLID":131804,"MAP":131805,"MAP_FILL":131806,"MAP_PIN":131807,"MAP_PIN_ELLIPSE":131808,"MAP_PIN_SLASH":131809,"MEMORIES":131810,"MEMORIES_BADGE_MINUS":131811,"MEMORIES_BADGE_PLUS":131812,"METRONOME":131813,"MIC":131814,"MIC_CIRCLE":131815,"MIC_CIRCLE_FILL":131816,"MIC_FILL":131817,"MIC_OFF":131818,"MIC_SLASH":131819,"MIC_SLASH_FILL":131820,"MIC_SOLID":131821,"MINUS":131822,"MINUS_CIRCLE":131823,"MINUS_CIRCLE_FILL":131824,"MINUS_CIRCLED":131825,"MINUS_RECTANGLE":131826,"MINUS_RECTANGLE_FILL":131827,"MINUS_SLASH_PLUS":131828,"MINUS_SQUARE":131829,"MINUS_SQUARE_FILL":131830,"MONEY_DOLLAR":131831,"MONEY_DOLLAR_CIRCLE":131832,"MONEY_DOLLAR_CIRCLE_FILL":131833,"MONEY_EURO":131834,"MONEY_EURO_CIRCLE":131835,"MONEY_EURO_CIRCLE_FILL":131836,"MONEY_POUND":131837,"MONEY_POUND_CIRCLE":131838,"MONEY_POUND_CIRCLE_FILL":131839,"MONEY_RUBL":131840,"MONEY_RUBL_CIRCLE":131841,"MONEY_RUBL_CIRCLE_FILL":131842,"MONEY_YEN":131843,"MONEY_YEN_CIRCLE":131844,"MONEY_YEN_CIRCLE_FILL":131845,"MOON":131846,"MOON_CIRCLE":131847,"MOON_CIRCLE_FILL":131848,"MOON_FILL":131849,"MOON_STARS":131850,"MOON_STARS_FILL":131851,"MOON_ZZZ":131852,"MOON_ZZZ_FILL":131853,"MOVE":131854,"MULTIPLY":131855,"MULTIPLY_CIRCLE":131856,"MULTIPLY_CIRCLE_FILL":131857,"MULTIPLY_SQUARE":131858,"MULTIPLY_SQUARE_FILL":131859,"MUSIC_ALBUMS":131860,"MUSIC_ALBUMS_FILL":131861,"MUSIC_HOUSE":131862,"MUSIC_HOUSE_FILL":131863,"MUSIC_MIC":131864,"MUSIC_NOTE":131865,"MUSIC_NOTE_2":131866,"MUSIC_NOTE_LIST":131867,"NEWS":131868,"NEWS_SOLID":131869,"NOSIGN":131870,"NUMBER":131871,"NUMBER_CIRCLE":131872,"NUMBER_CIRCLE_FILL":131873,"NUMBER_SQUARE":131874,"NUMBER_SQUARE_FILL":131875,"OPTION":131876,"PADLOCK":131877,"PADLOCK_SOLID":131878,"PAINTBRUSH":131879,"PAINTBRUSH_FILL":131880,"PANO":131881,"PANO_FILL":131882,"PAPERCLIP":131883,"PAPERPLANE":131884,"PAPERPLANE_FILL":131885,"PARAGRAPH":131886,"PAUSE":131887,"PAUSE_CIRCLE":131888,"PAUSE_CIRCLE_FILL":131889,"PAUSE_FILL":131890,"PAUSE_RECTANGLE":131891,"PAUSE_RECTANGLE_FILL":131892,"PAUSE_SOLID":131893,"PAW":131894,"PAW_SOLID":131895,"PEN":131896,"PENCIL":131897,"PENCIL_CIRCLE":131898,"PENCIL_CIRCLE_FILL":131899,"PENCIL_ELLIPSIS_RECTANGLE":131900,"PENCIL_OUTLINE":131901,"PENCIL_SLASH":131902,"PERCENT":131903,"PERSON":131904,"PERSON_2":131905,"PERSON_2_ALT":131906,"PERSON_2_FILL":131907,"PERSON_2_SQUARE_STACK":131908,"PERSON_2_SQUARE_STACK_FILL":131909,"PERSON_3":131910,"PERSON_3_FILL":131911,"PERSON_ADD":131912,"PERSON_ADD_SOLID":131913,"PERSON_ALT":131914,"PERSON_ALT_CIRCLE":131915,"PERSON_ALT_CIRCLE_FILL":131916,"PERSON_BADGE_MINUS":131917,"PERSON_BADGE_MINUS_FILL":131918,"PERSON_BADGE_PLUS":131919,"PERSON_BADGE_PLUS_FILL":131920,"PERSON_CIRCLE":131921,"PERSON_CIRCLE_FILL":131922,"PERSON_CROP_CIRCLE":131923,"PERSON_CROP_CIRCLE_BADGE_CHECKMARK":131924,"PERSON_CROP_CIRCLE_BADGE_EXCLAM":131925,"PERSON_CROP_CIRCLE_BADGE_MINUS":131926,"PERSON_CROP_CIRCLE_BADGE_PLUS":131927,"PERSON_CROP_CIRCLE_BADGE_XMARK":131928,"PERSON_CROP_CIRCLE_FILL":131929,"PERSON_CROP_CIRCLE_FILL_BADGE_CHECKMARK":131930,"PERSON_CROP_CIRCLE_FILL_BADGE_EXCLAM":131931,"PERSON_CROP_CIRCLE_FILL_BADGE_MINUS":131932,"PERSON_CROP_CIRCLE_FILL_BADGE_PLUS":131933,"PERSON_CROP_CIRCLE_FILL_BADGE_XMARK":131934,"PERSON_CROP_RECTANGLE":131935,"PERSON_CROP_RECTANGLE_FILL":131936,"PERSON_CROP_SQUARE":131937,"PERSON_CROP_SQUARE_FILL":131938,"PERSON_FILL":131939,"PERSON_SOLID":131940,"PERSONALHOTSPOT":131941,"PERSPECTIVE":131942,"PHONE":131943,"PHONE_ARROW_DOWN_LEFT":131944,"PHONE_ARROW_RIGHT":131945,"PHONE_ARROW_UP_RIGHT":131946,"PHONE_BADGE_PLUS":131947,"PHONE_CIRCLE":131948,"PHONE_CIRCLE_FILL":131949,"PHONE_DOWN":131950,"PHONE_DOWN_CIRCLE":131951,"PHONE_DOWN_CIRCLE_FILL":131952,"PHONE_DOWN_FILL":131953,"PHONE_FILL":131954,"PHONE_FILL_ARROW_DOWN_LEFT":131955,"PHONE_FILL_ARROW_RIGHT":131956,"PHONE_FILL_ARROW_UP_RIGHT":131957,"PHONE_FILL_BADGE_PLUS":131958,"PHONE_SOLID":131959,"PHOTO":131960,"PHOTO_CAMERA":131961,"PHOTO_CAMERA_SOLID":131962,"PHOTO_FILL":131963,"PHOTO_FILL_ON_RECTANGLE_FILL":131964,"PHOTO_ON_RECTANGLE":131965,"PIANO":131966,"PIN":131967,"PIN_FILL":131968,"PIN_SLASH":131969,"PIN_SLASH_FILL":131970,"PLACEMARK":131971,"PLACEMARK_FILL":131972,"PLAY":131973,"PLAY_ARROW":131974,"PLAY_ARROW_SOLID":131975,"PLAY_CIRCLE":131976,"PLAY_CIRCLE_FILL":131977,"PLAY_FILL":131978,"PLAY_RECTANGLE":131979,"PLAY_RECTANGLE_FILL":131980,"PLAYPAUSE":131981,"PLAYPAUSE_FILL":131982,"PLUS":131983,"PLUS_APP":131984,"PLUS_APP_FILL":131985,"PLUS_BUBBLE":131986,"PLUS_BUBBLE_FILL":131987,"PLUS_CIRCLE":131988,"PLUS_CIRCLE_FILL":131989,"PLUS_CIRCLED":131990,"PLUS_RECTANGLE":131991,"PLUS_RECTANGLE_FILL":131992,"PLUS_RECTANGLE_FILL_ON_RECTANGLE_FILL":131993,"PLUS_RECTANGLE_ON_RECTANGLE":131994,"PLUS_SLASH_MINUS":131995,"PLUS_SQUARE":131996,"PLUS_SQUARE_FILL":131997,"PLUS_SQUARE_FILL_ON_SQUARE_FILL":131998,"PLUS_SQUARE_ON_SQUARE":131999,"PLUSMINUS":132000,"PLUSMINUS_CIRCLE":132001,"PLUSMINUS_CIRCLE_FILL":132002,"POWER":132003,"PRINTER":132004,"PRINTER_FILL":132005,"PROFILE_CIRCLED":132006,"PROJECTIVE":132007,"PURCHASED":132008,"PURCHASED_CIRCLE":132009,"PURCHASED_CIRCLE_FILL":132010,"QRCODE":132011,"QRCODE_VIEWFINDER":132012,"QUESTION":132013,"QUESTION_CIRCLE":132014,"QUESTION_CIRCLE_FILL":132015,"QUESTION_DIAMOND":132016,"QUESTION_DIAMOND_FILL":132017,"QUESTION_SQUARE":132018,"QUESTION_SQUARE_FILL":132019,"QUOTE_BUBBLE":132020,"QUOTE_BUBBLE_FILL":132021,"RADIOWAVES_LEFT":132022,"RADIOWAVES_RIGHT":132023,"RAYS":132024,"RECORDINGTAPE":132025,"RECTANGLE":132026,"RECTANGLE_3_OFFGRID":132027,"RECTANGLE_3_OFFGRID_FILL":132028,"RECTANGLE_ARROW_UP_RIGHT_ARROW_DOWN_LEFT":132029,"RECTANGLE_ARROW_UP_RIGHT_ARROW_DOWN_LEFT_SLASH":132030,"RECTANGLE_BADGE_CHECKMARK":132031,"RECTANGLE_BADGE_XMARK":132032,"RECTANGLE_COMPRESS_VERTICAL":132033,"RECTANGLE_DOCK":132034,"RECTANGLE_EXPAND_VERTICAL":132035,"RECTANGLE_FILL":132036,"RECTANGLE_FILL_BADGE_CHECKMARK":132037,"RECTANGLE_FILL_BADGE_XMARK":132038,"RECTANGLE_FILL_ON_RECTANGLE_ANGLED_FILL":132039,"RECTANGLE_FILL_ON_RECTANGLE_FILL":132040,"RECTANGLE_GRID_1X2":132041,"RECTANGLE_GRID_1X2_FILL":132042,"RECTANGLE_GRID_2X2":132043,"RECTANGLE_GRID_2X2_FILL":132044,"RECTANGLE_GRID_3X2":132045,"RECTANGLE_GRID_3X2_FILL":132046,"RECTANGLE_ON_RECTANGLE":132047,"RECTANGLE_ON_RECTANGLE_ANGLED":132048,"RECTANGLE_PAPERCLIP":132049,"RECTANGLE_SPLIT_3X1":132050,"RECTANGLE_SPLIT_3X1_FILL":132051,"RECTANGLE_SPLIT_3X3":132052,"RECTANGLE_SPLIT_3X3_FILL":132053,"RECTANGLE_STACK":132054,"RECTANGLE_STACK_BADGE_MINUS":132055,"RECTANGLE_STACK_BADGE_PERSON_CROP":132056,"RECTANGLE_STACK_BADGE_PLUS":132057,"RECTANGLE_STACK_FILL":132058,"RECTANGLE_STACK_FILL_BADGE_MINUS":132059,"RECTANGLE_STACK_FILL_BADGE_PERSON_CROP":132060,"RECTANGLE_STACK_FILL_BADGE_PLUS":132061,"RECTANGLE_STACK_PERSON_CROP":132062,"RECTANGLE_STACK_PERSON_CROP_FILL":132063,"REFRESH":132064,"REFRESH_BOLD":132065,"REFRESH_CIRCLED":132066,"REFRESH_CIRCLED_SOLID":132067,"REFRESH_THICK":132068,"REFRESH_THIN":132069,"REPEAT":132070,"REPEAT_1":132071,"REPLY":132072,"REPLY_ALL":132073,"REPLY_THICK_SOLID":132074,"RESIZE":132075,"RESIZE_H":132076,"RESIZE_V":132077,"RESTART":132078,"RETURN_ICON":132079,"RHOMBUS":132080,"RHOMBUS_FILL":132081,"RIGHT_CHEVRON":132082,"ROCKET":132083,"ROCKET_FILL":132084,"ROSETTE":132085,"ROTATE_LEFT":132086,"ROTATE_LEFT_FILL":132087,"ROTATE_RIGHT":132088,"ROTATE_RIGHT_FILL":132089,"SCISSORS":132090,"SCISSORS_ALT":132091,"SCOPE":132092,"SCRIBBLE":132093,"SEARCH":132094,"SEARCH_CIRCLE":132095,"SEARCH_CIRCLE_FILL":132096,"SELECTION_PIN_IN_OUT":132097,"SETTINGS":132098,"SETTINGS_SOLID":132099,"SHARE":132100,"SHARE_SOLID":132101,"SHARE_UP":132102,"SHIELD":132103,"SHIELD_FILL":132104,"SHIELD_LEFTHALF_FILL":132105,"SHIELD_SLASH":132106,"SHIELD_SLASH_FILL":132107,"SHIFT":132108,"SHIFT_FILL":132109,"SHOPPING_CART":132110,"SHUFFLE":132111,"SHUFFLE_MEDIUM":132112,"SHUFFLE_THICK":132113,"SIDEBAR_LEFT":132114,"SIDEBAR_RIGHT":132115,"SIGNATURE":132116,"SKEW":132117,"SLASH_CIRCLE":132118,"SLASH_CIRCLE_FILL":132119,"SLIDER_HORIZONTAL_3":132120,"SLIDER_HORIZONTAL_BELOW_RECTANGLE":132121,"SLOWMO":132122,"SMALLCIRCLE_CIRCLE":132123,"SMALLCIRCLE_CIRCLE_FILL":132124,"SMALLCIRCLE_FILL_CIRCLE":132125,"SMALLCIRCLE_FILL_CIRCLE_FILL":132126,"SMILEY":132127,"SMILEY_FILL":132128,"SMOKE":132129,"SMOKE_FILL":132130,"SNOW":132131,"SORT_DOWN":132132,"SORT_DOWN_CIRCLE":132133,"SORT_DOWN_CIRCLE_FILL":132134,"SORT_UP":132135,"SORT_UP_CIRCLE":132136,"SORT_UP_CIRCLE_FILL":132137,"SPARKLES":132138,"SPEAKER":132139,"SPEAKER_1":132140,"SPEAKER_1_FILL":132141,"SPEAKER_2":132142,"SPEAKER_2_FILL":132143,"SPEAKER_3":132144,"SPEAKER_3_FILL":132145,"SPEAKER_FILL":132146,"SPEAKER_SLASH":132147,"SPEAKER_SLASH_FILL":132148,"SPEAKER_SLASH_FILL_RTL":132149,"SPEAKER_SLASH_RTL":132150,"SPEAKER_ZZZ":132151,"SPEAKER_ZZZ_FILL":132152,"SPEAKER_ZZZ_FILL_RTL":132153,"SPEAKER_ZZZ_RTL":132154,"SPEEDOMETER":132155,"SPORTSCOURT":132156,"SPORTSCOURT_FILL":132157,"SQUARE":132158,"SQUARE_ARROW_DOWN":132159,"SQUARE_ARROW_DOWN_FILL":132160,"SQUARE_ARROW_DOWN_ON_SQUARE":132161,"SQUARE_ARROW_DOWN_ON_SQUARE_FILL":132162,"SQUARE_ARROW_LEFT":132163,"SQUARE_ARROW_LEFT_FILL":132164,"SQUARE_ARROW_RIGHT":132165,"SQUARE_ARROW_RIGHT_FILL":132166,"SQUARE_ARROW_UP":132167,"SQUARE_ARROW_UP_FILL":132168,"SQUARE_ARROW_UP_ON_SQUARE":132169,"SQUARE_ARROW_UP_ON_SQUARE_FILL":132170,"SQUARE_FAVORITES":132171,"SQUARE_FAVORITES_ALT":132172,"SQUARE_FAVORITES_ALT_FILL":132173,"SQUARE_FAVORITES_FILL":132174,"SQUARE_FILL":132175,"SQUARE_FILL_LINE_VERTICAL_SQUARE":132176,"SQUARE_FILL_LINE_VERTICAL_SQUARE_FILL":132177,"SQUARE_FILL_ON_CIRCLE_FILL":132178,"SQUARE_FILL_ON_SQUARE_FILL":132179,"SQUARE_GRID_2X2":132180,"SQUARE_GRID_2X2_FILL":132181,"SQUARE_GRID_3X2":132182,"SQUARE_GRID_3X2_FILL":132183,"SQUARE_GRID_4X3_FILL":132184,"SQUARE_LEFTHALF_FILL":132185,"SQUARE_LINE_VERTICAL_SQUARE":132186,"SQUARE_LINE_VERTICAL_SQUARE_FILL":132187,"SQUARE_LIST":132188,"SQUARE_LIST_FILL":132189,"SQUARE_ON_CIRCLE":132190,"SQUARE_ON_SQUARE":132191,"SQUARE_PENCIL":132192,"SQUARE_PENCIL_FILL":132193,"SQUARE_RIGHTHALF_FILL":132194,"SQUARE_SPLIT_1X2":132195,"SQUARE_SPLIT_1X2_FILL":132196,"SQUARE_SPLIT_2X1":132197,"SQUARE_SPLIT_2X1_FILL":132198,"SQUARE_SPLIT_2X2":132199,"SQUARE_SPLIT_2X2_FILL":132200,"SQUARE_STACK":132201,"SQUARE_STACK_3D_DOWN_DOTTEDLINE":132202,"SQUARE_STACK_3D_DOWN_RIGHT":132203,"SQUARE_STACK_3D_DOWN_RIGHT_FILL":132204,"SQUARE_STACK_3D_UP":132205,"SQUARE_STACK_3D_UP_FILL":132206,"SQUARE_STACK_3D_UP_SLASH":132207,"SQUARE_STACK_3D_UP_SLASH_FILL":132208,"SQUARE_STACK_FILL":132209,"SQUARES_BELOW_RECTANGLE":132210,"STAR":132211,"STAR_CIRCLE":132212,"STAR_CIRCLE_FILL":132213,"STAR_FILL":132214,"STAR_LEFTHALF_FILL":132215,"STAR_SLASH":132216,"STAR_SLASH_FILL":132217,"STAROFLIFE":132218,"STAROFLIFE_FILL":132219,"STOP":132220,"STOP_CIRCLE":132221,"STOP_CIRCLE_FILL":132222,"STOP_FILL":132223,"STOPWATCH":132224,"STOPWATCH_FILL":132225,"STRIKETHROUGH":132226,"SUIT_CLUB":132227,"SUIT_CLUB_FILL":132228,"SUIT_DIAMOND":132229,"SUIT_DIAMOND_FILL":132230,"SUIT_HEART":132231,"SUIT_HEART_FILL":132232,"SUIT_SPADE":132233,"SUIT_SPADE_FILL":132234,"SUM":132235,"SUN_DUST":132236,"SUN_DUST_FILL":132237,"SUN_HAZE":132238,"SUN_HAZE_FILL":132239,"SUN_MAX":132240,"SUN_MAX_FILL":132241,"SUN_MIN":132242,"SUN_MIN_FILL":132243,"SUNRISE":132244,"SUNRISE_FILL":132245,"SUNSET":132246,"SUNSET_FILL":132247,"SWITCH_CAMERA":132248,"SWITCH_CAMERA_SOLID":132249,"T_BUBBLE":132250,"T_BUBBLE_FILL":132251,"TABLE":132252,"TABLE_BADGE_MORE":132253,"TABLE_BADGE_MORE_FILL":132254,"TABLE_FILL":132255,"TAG":132256,"TAG_CIRCLE":132257,"TAG_CIRCLE_FILL":132258,"TAG_FILL":132259,"TAG_SOLID":132260,"TAGS":132261,"TAGS_SOLID":132262,"TEXT_ALIGNCENTER":132263,"TEXT_ALIGNLEFT":132264,"TEXT_ALIGNRIGHT":132265,"TEXT_APPEND":132266,"TEXT_BADGE_CHECKMARK":132267,"TEXT_BADGE_MINUS":132268,"TEXT_BADGE_PLUS":132269,"TEXT_BADGE_STAR":132270,"TEXT_BADGE_XMARK":132271,"TEXT_BUBBLE":132272,"TEXT_BUBBLE_FILL":132273,"TEXT_CURSOR":132274,"TEXT_INSERT":132275,"TEXT_JUSTIFY":132276,"TEXT_JUSTIFYLEFT":132277,"TEXT_JUSTIFYRIGHT":132278,"TEXT_QUOTE":132279,"TEXTBOX":132280,"TEXTFORMAT":132281,"TEXTFORMAT_123":132282,"TEXTFORMAT_ABC":132283,"TEXTFORMAT_ABC_DOTTEDUNDERLINE":132284,"TEXTFORMAT_ALT":132285,"TEXTFORMAT_SIZE":132286,"TEXTFORMAT_SUBSCRIPT":132287,"TEXTFORMAT_SUPERSCRIPT":132288,"THERMOMETER":132289,"THERMOMETER_SNOWFLAKE":132290,"THERMOMETER_SUN":132291,"TICKET":132292,"TICKET_FILL":132293,"TICKETS":132294,"TICKETS_FILL":132295,"TIME":132296,"TIME_SOLID":132297,"TIMELAPSE":132298,"TIMER":132299,"TIMER_FILL":132300,"TODAY":132301,"TODAY_FILL":132302,"TORNADO":132303,"TORTOISE":132304,"TORTOISE_FILL":132305,"TRAIN_STYLE_ONE":132306,"TRAIN_STYLE_TWO":132307,"TRAM_FILL":132308,"TRASH":132309,"TRASH_CIRCLE":132310,"TRASH_CIRCLE_FILL":132311,"TRASH_FILL":132312,"TRASH_SLASH":132313,"TRASH_SLASH_FILL":132314,"TRAY":132315,"TRAY_2":132316,"TRAY_2_FILL":132317,"TRAY_ARROW_DOWN":132318,"TRAY_ARROW_DOWN_FILL":132319,"TRAY_ARROW_UP":132320,"TRAY_ARROW_UP_FILL":132321,"TRAY_FILL":132322,"TRAY_FULL":132323,"TRAY_FULL_FILL":132324,"TREE":132325,"TRIANGLE":132326,"TRIANGLE_FILL":132327,"TRIANGLE_LEFTHALF_FILL":132328,"TRIANGLE_RIGHTHALF_FILL":132329,"TROPICALSTORM":132330,"TUNINGFORK":132331,"TV":132332,"TV_CIRCLE":132333,"TV_CIRCLE_FILL":132334,"TV_FILL":132335,"TV_MUSIC_NOTE":132336,"TV_MUSIC_NOTE_FILL":132337,"UIWINDOW_SPLIT_2X1":132338,"UMBRELLA":132339,"UMBRELLA_FILL":132340,"UNDERLINE":132341,"UP_ARROW":132342,"UPLOAD_CIRCLE":132343,"UPLOAD_CIRCLE_FILL":132344,"VIDEO_CAMERA":132345,"VIDEO_CAMERA_SOLID":132346,"VIDEOCAM":132347,"VIDEOCAM_CIRCLE":132348,"VIDEOCAM_CIRCLE_FILL":132349,"VIDEOCAM_FILL":132350,"VIEW_2D":132351,"VIEW_3D":132352,"VIEWFINDER":132353,"VIEWFINDER_CIRCLE":132354,"VIEWFINDER_CIRCLE_FILL":132355,"VOLUME_DOWN":132356,"VOLUME_MUTE":132357,"VOLUME_OFF":132358,"VOLUME_UP":132359,"WAND_RAYS":132360,"WAND_RAYS_INVERSE":132361,"WAND_STARS":132362,"WAND_STARS_INVERSE":132363,"WAVEFORM":132364,"WAVEFORM_CIRCLE":132365,"WAVEFORM_CIRCLE_FILL":132366,"WAVEFORM_PATH":132367,"WAVEFORM_PATH_BADGE_MINUS":132368,"WAVEFORM_PATH_BADGE_PLUS":132369,"WAVEFORM_PATH_ECG":132370,"WIFI":132371,"WIFI_EXCLAMATIONMARK":132372,"WIFI_SLASH":132373,"WIND":132374,"WIND_SNOW":132375,"WRENCH":132376,"WRENCH_FILL":132377,"XMARK":132378,"XMARK_CIRCLE":132379,"XMARK_CIRCLE_FILL":132380,"XMARK_OCTAGON":132381,"XMARK_OCTAGON_FILL":132382,"XMARK_RECTANGLE":132383,"XMARK_RECTANGLE_FILL":132384,"XMARK_SEAL":132385,"XMARK_SEAL_FILL":132386,"XMARK_SHIELD":132387,"XMARK_SHIELD_FILL":132388,"XMARK_SQUARE":132389,"XMARK_SQUARE_FILL":132390,"ZOOM_IN":132391,"ZOOM_OUT":132392,"ZZZ":132393} diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.py new file mode 100644 index 0000000000..642e8d285b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import json +import random +from importlib import resources + +from flet.controls.icon_data import IconData + +__all__ = ["CupertinoIcons"] + + +class _CupertinoIconData(IconData, package_name="flet", class_name="CupertinoIcons"): + _DUMMY = -1 + + @classmethod + def _missing_(cls, value): + obj = int.__new__(cls, value) + obj._value_ = value + obj._name_ = f"_ICON_{value}" + cls._value2member_map_[value] = obj + return obj + + +_CupertinoIconData.__name__ = "CupertinoIcons" +_CupertinoIconData.__qualname__ = "CupertinoIcons" + + +class _CupertinoIconsProxy: + __slots__ = ("_map", "_values") + + def __init__(self) -> None: + self._map: dict[str, int] | None = None + self._values: list[_CupertinoIconData] | None = None + + def _load(self) -> None: + if self._map is not None: + return + data = ( + resources.files(__package__) + .joinpath("cupertino_icons.json") + .read_text(encoding="utf-8") + ) + self._map = json.loads(data) + + def _get_member(self, name: str) -> _CupertinoIconData: + self._load() + assert self._map is not None + cls = _CupertinoIconData + existing = cls._member_map_.get(name) + if existing is not None: + return existing + value = self._map[name] + member = int.__new__(cls, value) + member._value_ = value + member._name_ = name + cls._member_map_[name] = member + cls._value2member_map_[value] = member + cls._member_names_.append(name) + return member + + def _get_values(self) -> list[_CupertinoIconData]: + self._load() + if self._values is None: + assert self._map is not None + self._values = [self._get_member(name) for name in self._map] + return self._values + + def __getattr__(self, name: str) -> IconData: + try: + return self._get_member(name) + except KeyError: + raise AttributeError(name) from None + + def __dir__(self) -> list[str]: + self._load() + assert self._map is not None + return sorted(self._map.keys()) + + def __iter__(self): + return iter(self._get_values()) + + def __len__(self) -> int: + self._load() + assert self._map is not None + return len(self._map) + + def random( + self, + exclude: list[IconData] | None = None, + weights: dict[IconData, int] | None = None, + ) -> IconData | None: + choices = list(self._get_values()) + if exclude: + excluded = set(exclude) + choices = [icon for icon in choices if icon not in excluded] + if not choices: + return None + if weights: + weights_list = [weights.get(icon, 1) for icon in choices] + return random.choices(choices, weights=weights_list)[0] + return random.choice(choices) + + +CupertinoIcons = _CupertinoIconsProxy() diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.pyi b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.pyi new file mode 100644 index 0000000000..b81976ba62 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_icons.pyi @@ -0,0 +1,1337 @@ +""" +Flet Cupertino Icons Stub + +To generate/update this file run from the root of the repository: + +``` +uv run .github/scripts/generate_icons.py +``` +""" + +from flet.controls.icon_data import IconData + +__all__ = ["CupertinoIcons"] + +class CupertinoIcons: + ADD: IconData + ADD_CIRCLED: IconData + ADD_CIRCLED_SOLID: IconData + AIRPLANE: IconData + ALARM: IconData + ALARM_FILL: IconData + ALT: IconData + ANT: IconData + ANT_CIRCLE: IconData + ANT_CIRCLE_FILL: IconData + ANT_FILL: IconData + ANTENNA_RADIOWAVES_LEFT_RIGHT: IconData + APP: IconData + APP_BADGE: IconData + APP_BADGE_FILL: IconData + APP_FILL: IconData + ARCHIVEBOX: IconData + ARCHIVEBOX_FILL: IconData + ARROW_2_CIRCLEPATH: IconData + ARROW_2_CIRCLEPATH_CIRCLE: IconData + ARROW_2_CIRCLEPATH_CIRCLE_FILL: IconData + ARROW_2_SQUAREPATH: IconData + ARROW_3_TRIANGLEPATH: IconData + ARROW_BRANCH: IconData + ARROW_CLOCKWISE: IconData + ARROW_CLOCKWISE_CIRCLE: IconData + ARROW_CLOCKWISE_CIRCLE_FILL: IconData + ARROW_COUNTERCLOCKWISE: IconData + ARROW_COUNTERCLOCKWISE_CIRCLE: IconData + ARROW_COUNTERCLOCKWISE_CIRCLE_FILL: IconData + ARROW_DOWN: IconData + ARROW_DOWN_CIRCLE: IconData + ARROW_DOWN_CIRCLE_FILL: IconData + ARROW_DOWN_DOC: IconData + ARROW_DOWN_DOC_FILL: IconData + ARROW_DOWN_LEFT: IconData + ARROW_DOWN_LEFT_CIRCLE: IconData + ARROW_DOWN_LEFT_CIRCLE_FILL: IconData + ARROW_DOWN_LEFT_SQUARE: IconData + ARROW_DOWN_LEFT_SQUARE_FILL: IconData + ARROW_DOWN_RIGHT: IconData + ARROW_DOWN_RIGHT_ARROW_UP_LEFT: IconData + ARROW_DOWN_RIGHT_CIRCLE: IconData + ARROW_DOWN_RIGHT_CIRCLE_FILL: IconData + ARROW_DOWN_RIGHT_SQUARE: IconData + ARROW_DOWN_RIGHT_SQUARE_FILL: IconData + ARROW_DOWN_SQUARE: IconData + ARROW_DOWN_SQUARE_FILL: IconData + ARROW_DOWN_TO_LINE: IconData + ARROW_DOWN_TO_LINE_ALT: IconData + ARROW_LEFT: IconData + ARROW_LEFT_CIRCLE: IconData + ARROW_LEFT_CIRCLE_FILL: IconData + ARROW_LEFT_RIGHT: IconData + ARROW_LEFT_RIGHT_CIRCLE: IconData + ARROW_LEFT_RIGHT_CIRCLE_FILL: IconData + ARROW_LEFT_RIGHT_SQUARE: IconData + ARROW_LEFT_RIGHT_SQUARE_FILL: IconData + ARROW_LEFT_SQUARE: IconData + ARROW_LEFT_SQUARE_FILL: IconData + ARROW_LEFT_TO_LINE: IconData + ARROW_LEFT_TO_LINE_ALT: IconData + ARROW_MERGE: IconData + ARROW_RIGHT: IconData + ARROW_RIGHT_ARROW_LEFT: IconData + ARROW_RIGHT_ARROW_LEFT_CIRCLE: IconData + ARROW_RIGHT_ARROW_LEFT_CIRCLE_FILL: IconData + ARROW_RIGHT_ARROW_LEFT_SQUARE: IconData + ARROW_RIGHT_ARROW_LEFT_SQUARE_FILL: IconData + ARROW_RIGHT_CIRCLE: IconData + ARROW_RIGHT_CIRCLE_FILL: IconData + ARROW_RIGHT_SQUARE: IconData + ARROW_RIGHT_SQUARE_FILL: IconData + ARROW_RIGHT_TO_LINE: IconData + ARROW_RIGHT_TO_LINE_ALT: IconData + ARROW_SWAP: IconData + ARROW_TURN_DOWN_LEFT: IconData + ARROW_TURN_DOWN_RIGHT: IconData + ARROW_TURN_LEFT_DOWN: IconData + ARROW_TURN_LEFT_UP: IconData + ARROW_TURN_RIGHT_DOWN: IconData + ARROW_TURN_RIGHT_UP: IconData + ARROW_TURN_UP_LEFT: IconData + ARROW_TURN_UP_RIGHT: IconData + ARROW_UP: IconData + ARROW_UP_ARROW_DOWN: IconData + ARROW_UP_ARROW_DOWN_CIRCLE: IconData + ARROW_UP_ARROW_DOWN_CIRCLE_FILL: IconData + ARROW_UP_ARROW_DOWN_SQUARE: IconData + ARROW_UP_ARROW_DOWN_SQUARE_FILL: IconData + ARROW_UP_BIN: IconData + ARROW_UP_BIN_FILL: IconData + ARROW_UP_CIRCLE: IconData + ARROW_UP_CIRCLE_FILL: IconData + ARROW_UP_DOC: IconData + ARROW_UP_DOC_FILL: IconData + ARROW_UP_DOWN: IconData + ARROW_UP_DOWN_CIRCLE: IconData + ARROW_UP_DOWN_CIRCLE_FILL: IconData + ARROW_UP_DOWN_SQUARE: IconData + ARROW_UP_DOWN_SQUARE_FILL: IconData + ARROW_UP_LEFT: IconData + ARROW_UP_LEFT_ARROW_DOWN_RIGHT: IconData + ARROW_UP_LEFT_CIRCLE: IconData + ARROW_UP_LEFT_CIRCLE_FILL: IconData + ARROW_UP_LEFT_SQUARE: IconData + ARROW_UP_LEFT_SQUARE_FILL: IconData + ARROW_UP_RIGHT: IconData + ARROW_UP_RIGHT_CIRCLE: IconData + ARROW_UP_RIGHT_CIRCLE_FILL: IconData + ARROW_UP_RIGHT_DIAMOND: IconData + ARROW_UP_RIGHT_DIAMOND_FILL: IconData + ARROW_UP_RIGHT_SQUARE: IconData + ARROW_UP_RIGHT_SQUARE_FILL: IconData + ARROW_UP_SQUARE: IconData + ARROW_UP_SQUARE_FILL: IconData + ARROW_UP_TO_LINE: IconData + ARROW_UP_TO_LINE_ALT: IconData + ARROW_UTURN_DOWN: IconData + ARROW_UTURN_DOWN_CIRCLE: IconData + ARROW_UTURN_DOWN_CIRCLE_FILL: IconData + ARROW_UTURN_DOWN_SQUARE: IconData + ARROW_UTURN_DOWN_SQUARE_FILL: IconData + ARROW_UTURN_LEFT: IconData + ARROW_UTURN_LEFT_CIRCLE: IconData + ARROW_UTURN_LEFT_CIRCLE_FILL: IconData + ARROW_UTURN_LEFT_SQUARE: IconData + ARROW_UTURN_LEFT_SQUARE_FILL: IconData + ARROW_UTURN_RIGHT: IconData + ARROW_UTURN_RIGHT_CIRCLE: IconData + ARROW_UTURN_RIGHT_CIRCLE_FILL: IconData + ARROW_UTURN_RIGHT_SQUARE: IconData + ARROW_UTURN_RIGHT_SQUARE_FILL: IconData + ARROW_UTURN_UP: IconData + ARROW_UTURN_UP_CIRCLE: IconData + ARROW_UTURN_UP_CIRCLE_FILL: IconData + ARROW_UTURN_UP_SQUARE: IconData + ARROW_UTURN_UP_SQUARE_FILL: IconData + ARROWSHAPE_TURN_UP_LEFT: IconData + ARROWSHAPE_TURN_UP_LEFT_2: IconData + ARROWSHAPE_TURN_UP_LEFT_2_FILL: IconData + ARROWSHAPE_TURN_UP_LEFT_CIRCLE: IconData + ARROWSHAPE_TURN_UP_LEFT_CIRCLE_FILL: IconData + ARROWSHAPE_TURN_UP_LEFT_FILL: IconData + ARROWSHAPE_TURN_UP_RIGHT: IconData + ARROWSHAPE_TURN_UP_RIGHT_CIRCLE: IconData + ARROWSHAPE_TURN_UP_RIGHT_CIRCLE_FILL: IconData + ARROWSHAPE_TURN_UP_RIGHT_FILL: IconData + ARROWTRIANGLE_DOWN: IconData + ARROWTRIANGLE_DOWN_CIRCLE: IconData + ARROWTRIANGLE_DOWN_CIRCLE_FILL: IconData + ARROWTRIANGLE_DOWN_FILL: IconData + ARROWTRIANGLE_DOWN_SQUARE: IconData + ARROWTRIANGLE_DOWN_SQUARE_FILL: IconData + ARROWTRIANGLE_LEFT: IconData + ARROWTRIANGLE_LEFT_CIRCLE: IconData + ARROWTRIANGLE_LEFT_CIRCLE_FILL: IconData + ARROWTRIANGLE_LEFT_FILL: IconData + ARROWTRIANGLE_LEFT_SQUARE: IconData + ARROWTRIANGLE_LEFT_SQUARE_FILL: IconData + ARROWTRIANGLE_RIGHT: IconData + ARROWTRIANGLE_RIGHT_CIRCLE: IconData + ARROWTRIANGLE_RIGHT_CIRCLE_FILL: IconData + ARROWTRIANGLE_RIGHT_FILL: IconData + ARROWTRIANGLE_RIGHT_SQUARE: IconData + ARROWTRIANGLE_RIGHT_SQUARE_FILL: IconData + ARROWTRIANGLE_UP: IconData + ARROWTRIANGLE_UP_CIRCLE: IconData + ARROWTRIANGLE_UP_CIRCLE_FILL: IconData + ARROWTRIANGLE_UP_FILL: IconData + ARROWTRIANGLE_UP_SQUARE: IconData + ARROWTRIANGLE_UP_SQUARE_FILL: IconData + ASTERISK_CIRCLE: IconData + ASTERISK_CIRCLE_FILL: IconData + AT: IconData + AT_BADGE_MINUS: IconData + AT_BADGE_PLUS: IconData + AT_CIRCLE: IconData + AT_CIRCLE_FILL: IconData + BACK: IconData + BACKWARD: IconData + BACKWARD_END: IconData + BACKWARD_END_ALT: IconData + BACKWARD_END_ALT_FILL: IconData + BACKWARD_END_FILL: IconData + BACKWARD_FILL: IconData + BADGE_PLUS_RADIOWAVES_RIGHT: IconData + BAG: IconData + BAG_BADGE_MINUS: IconData + BAG_BADGE_PLUS: IconData + BAG_FILL: IconData + BAG_FILL_BADGE_MINUS: IconData + BAG_FILL_BADGE_PLUS: IconData + BANDAGE: IconData + BANDAGE_FILL: IconData + BARCODE: IconData + BARCODE_VIEWFINDER: IconData + BARS: IconData + BATTERY_0: IconData + BATTERY_100: IconData + BATTERY_25: IconData + BATTERY_25_PERCENT: IconData + BATTERY_75_PERCENT: IconData + BATTERY_CHARGING: IconData + BATTERY_EMPTY: IconData + BATTERY_FULL: IconData + BED_DOUBLE: IconData + BED_DOUBLE_FILL: IconData + BELL: IconData + BELL_CIRCLE: IconData + BELL_CIRCLE_FILL: IconData + BELL_FILL: IconData + BELL_SLASH: IconData + BELL_SLASH_FILL: IconData + BELL_SOLID: IconData + BIN_XMARK: IconData + BIN_XMARK_FILL: IconData + BITCOIN: IconData + BITCOIN_CIRCLE: IconData + BITCOIN_CIRCLE_FILL: IconData + BLUETOOTH: IconData + BOLD: IconData + BOLD_ITALIC_UNDERLINE: IconData + BOLD_UNDERLINE: IconData + BOLT: IconData + BOLT_BADGE_A: IconData + BOLT_BADGE_A_FILL: IconData + BOLT_CIRCLE: IconData + BOLT_CIRCLE_FILL: IconData + BOLT_FILL: IconData + BOLT_HORIZONTAL: IconData + BOLT_HORIZONTAL_CIRCLE: IconData + BOLT_HORIZONTAL_CIRCLE_FILL: IconData + BOLT_HORIZONTAL_FILL: IconData + BOLT_SLASH: IconData + BOLT_SLASH_FILL: IconData + BOOK: IconData + BOOK_CIRCLE: IconData + BOOK_CIRCLE_FILL: IconData + BOOK_FILL: IconData + BOOK_SOLID: IconData + BOOKMARK: IconData + BOOKMARK_FILL: IconData + BOOKMARK_SOLID: IconData + BRIEFCASE: IconData + BRIEFCASE_FILL: IconData + BRIGHTNESS: IconData + BRIGHTNESS_SOLID: IconData + BUBBLE_LEFT: IconData + BUBBLE_LEFT_BUBBLE_RIGHT: IconData + BUBBLE_LEFT_BUBBLE_RIGHT_FILL: IconData + BUBBLE_LEFT_FILL: IconData + BUBBLE_MIDDLE_BOTTOM: IconData + BUBBLE_MIDDLE_BOTTOM_FILL: IconData + BUBBLE_MIDDLE_TOP: IconData + BUBBLE_MIDDLE_TOP_FILL: IconData + BUBBLE_RIGHT: IconData + BUBBLE_RIGHT_FILL: IconData + BUILDING_2_FILL: IconData + BURN: IconData + BURST: IconData + BURST_FILL: IconData + BUS: IconData + CALENDAR: IconData + CALENDAR_BADGE_MINUS: IconData + CALENDAR_BADGE_PLUS: IconData + CALENDAR_CIRCLE: IconData + CALENDAR_CIRCLE_FILL: IconData + CALENDAR_TODAY: IconData + CAMERA: IconData + CAMERA_CIRCLE: IconData + CAMERA_CIRCLE_FILL: IconData + CAMERA_FILL: IconData + CAMERA_ON_RECTANGLE: IconData + CAMERA_ON_RECTANGLE_FILL: IconData + CAMERA_ROTATE: IconData + CAMERA_ROTATE_FILL: IconData + CAMERA_VIEWFINDER: IconData + CAPSLOCK: IconData + CAPSLOCK_FILL: IconData + CAPSULE: IconData + CAPSULE_FILL: IconData + CAPTIONS_BUBBLE: IconData + CAPTIONS_BUBBLE_FILL: IconData + CAR: IconData + CAR_DETAILED: IconData + CAR_FILL: IconData + CART: IconData + CART_BADGE_MINUS: IconData + CART_BADGE_PLUS: IconData + CART_FILL: IconData + CART_FILL_BADGE_MINUS: IconData + CART_FILL_BADGE_PLUS: IconData + CHART_BAR: IconData + CHART_BAR_ALT_FILL: IconData + CHART_BAR_CIRCLE: IconData + CHART_BAR_CIRCLE_FILL: IconData + CHART_BAR_FILL: IconData + CHART_BAR_SQUARE: IconData + CHART_BAR_SQUARE_FILL: IconData + CHART_PIE: IconData + CHART_PIE_FILL: IconData + CHAT_BUBBLE: IconData + CHAT_BUBBLE_2: IconData + CHAT_BUBBLE_2_FILL: IconData + CHAT_BUBBLE_FILL: IconData + CHAT_BUBBLE_TEXT: IconData + CHAT_BUBBLE_TEXT_FILL: IconData + CHECK_MARK: IconData + CHECK_MARK_CIRCLED: IconData + CHECK_MARK_CIRCLED_SOLID: IconData + CHECKMARK: IconData + CHECKMARK_ALT: IconData + CHECKMARK_ALT_CIRCLE: IconData + CHECKMARK_ALT_CIRCLE_FILL: IconData + CHECKMARK_CIRCLE: IconData + CHECKMARK_CIRCLE_FILL: IconData + CHECKMARK_RECTANGLE: IconData + CHECKMARK_RECTANGLE_FILL: IconData + CHECKMARK_SEAL: IconData + CHECKMARK_SEAL_FILL: IconData + CHECKMARK_SHIELD: IconData + CHECKMARK_SHIELD_FILL: IconData + CHECKMARK_SQUARE: IconData + CHECKMARK_SQUARE_FILL: IconData + CHEVRON_BACK: IconData + CHEVRON_COMPACT_DOWN: IconData + CHEVRON_COMPACT_LEFT: IconData + CHEVRON_COMPACT_RIGHT: IconData + CHEVRON_COMPACT_UP: IconData + CHEVRON_DOWN: IconData + CHEVRON_DOWN_CIRCLE: IconData + CHEVRON_DOWN_CIRCLE_FILL: IconData + CHEVRON_DOWN_SQUARE: IconData + CHEVRON_DOWN_SQUARE_FILL: IconData + CHEVRON_FORWARD: IconData + CHEVRON_LEFT: IconData + CHEVRON_LEFT_2: IconData + CHEVRON_LEFT_CIRCLE: IconData + CHEVRON_LEFT_CIRCLE_FILL: IconData + CHEVRON_LEFT_SLASH_CHEVRON_RIGHT: IconData + CHEVRON_LEFT_SQUARE: IconData + CHEVRON_LEFT_SQUARE_FILL: IconData + CHEVRON_RIGHT: IconData + CHEVRON_RIGHT_2: IconData + CHEVRON_RIGHT_CIRCLE: IconData + CHEVRON_RIGHT_CIRCLE_FILL: IconData + CHEVRON_RIGHT_SQUARE: IconData + CHEVRON_RIGHT_SQUARE_FILL: IconData + CHEVRON_UP: IconData + CHEVRON_UP_CHEVRON_DOWN: IconData + CHEVRON_UP_CIRCLE: IconData + CHEVRON_UP_CIRCLE_FILL: IconData + CHEVRON_UP_SQUARE: IconData + CHEVRON_UP_SQUARE_FILL: IconData + CIRCLE: IconData + CIRCLE_BOTTOMTHIRD_SPLIT: IconData + CIRCLE_FILL: IconData + CIRCLE_FILLED: IconData + CIRCLE_GRID_3X3: IconData + CIRCLE_GRID_3X3_FILL: IconData + CIRCLE_GRID_HEX: IconData + CIRCLE_GRID_HEX_FILL: IconData + CIRCLE_LEFTHALF_FILL: IconData + CIRCLE_RIGHTHALF_FILL: IconData + CLEAR: IconData + CLEAR_CIRCLED: IconData + CLEAR_CIRCLED_SOLID: IconData + CLEAR_FILL: IconData + CLEAR_THICK: IconData + CLEAR_THICK_CIRCLED: IconData + CLOCK: IconData + CLOCK_FILL: IconData + CLOCK_SOLID: IconData + CLOUD: IconData + CLOUD_BOLT: IconData + CLOUD_BOLT_FILL: IconData + CLOUD_BOLT_RAIN: IconData + CLOUD_BOLT_RAIN_FILL: IconData + CLOUD_DOWNLOAD: IconData + CLOUD_DOWNLOAD_FILL: IconData + CLOUD_DRIZZLE: IconData + CLOUD_DRIZZLE_FILL: IconData + CLOUD_FILL: IconData + CLOUD_FOG: IconData + CLOUD_FOG_FILL: IconData + CLOUD_HAIL: IconData + CLOUD_HAIL_FILL: IconData + CLOUD_HEAVYRAIN: IconData + CLOUD_HEAVYRAIN_FILL: IconData + CLOUD_MOON: IconData + CLOUD_MOON_BOLT: IconData + CLOUD_MOON_BOLT_FILL: IconData + CLOUD_MOON_FILL: IconData + CLOUD_MOON_RAIN: IconData + CLOUD_MOON_RAIN_FILL: IconData + CLOUD_RAIN: IconData + CLOUD_RAIN_FILL: IconData + CLOUD_SLEET: IconData + CLOUD_SLEET_FILL: IconData + CLOUD_SNOW: IconData + CLOUD_SNOW_FILL: IconData + CLOUD_SUN: IconData + CLOUD_SUN_BOLT: IconData + CLOUD_SUN_BOLT_FILL: IconData + CLOUD_SUN_FILL: IconData + CLOUD_SUN_RAIN: IconData + CLOUD_SUN_RAIN_FILL: IconData + CLOUD_UPLOAD: IconData + CLOUD_UPLOAD_FILL: IconData + COLLECTIONS: IconData + COLLECTIONS_SOLID: IconData + COLOR_FILTER: IconData + COLOR_FILTER_FILL: IconData + COMMAND: IconData + COMPASS: IconData + COMPASS_FILL: IconData + CONTROL: IconData + CONVERSATION_BUBBLE: IconData + CREATE: IconData + CREATE_SOLID: IconData + CREDITCARD: IconData + CREDITCARD_FILL: IconData + CROP: IconData + CROP_ROTATE: IconData + CUBE: IconData + CUBE_BOX: IconData + CUBE_BOX_FILL: IconData + CUBE_FILL: IconData + CURSOR_RAYS: IconData + DECREASE_INDENT: IconData + DECREASE_QUOTELEVEL: IconData + DELETE: IconData + DELETE_LEFT: IconData + DELETE_LEFT_FILL: IconData + DELETE_RIGHT: IconData + DELETE_RIGHT_FILL: IconData + DELETE_SIMPLE: IconData + DELETE_SOLID: IconData + DESKTOPCOMPUTER: IconData + DEVICE_DESKTOP: IconData + DEVICE_LAPTOP: IconData + DEVICE_PHONE_LANDSCAPE: IconData + DEVICE_PHONE_PORTRAIT: IconData + DIAL: IconData + DIAL_FILL: IconData + DIVIDE: IconData + DIVIDE_CIRCLE: IconData + DIVIDE_CIRCLE_FILL: IconData + DIVIDE_SQUARE: IconData + DIVIDE_SQUARE_FILL: IconData + DOC: IconData + DOC_APPEND: IconData + DOC_CHART: IconData + DOC_CHART_FILL: IconData + DOC_CHECKMARK: IconData + DOC_CHECKMARK_FILL: IconData + DOC_CIRCLE: IconData + DOC_CIRCLE_FILL: IconData + DOC_FILL: IconData + DOC_ON_CLIPBOARD: IconData + DOC_ON_CLIPBOARD_FILL: IconData + DOC_ON_DOC: IconData + DOC_ON_DOC_FILL: IconData + DOC_PERSON: IconData + DOC_PERSON_FILL: IconData + DOC_PLAINTEXT: IconData + DOC_RICHTEXT: IconData + DOC_TEXT: IconData + DOC_TEXT_FILL: IconData + DOC_TEXT_SEARCH: IconData + DOC_TEXT_VIEWFINDER: IconData + DOT_RADIOWAVES_LEFT_RIGHT: IconData + DOT_RADIOWAVES_RIGHT: IconData + DOT_SQUARE: IconData + DOT_SQUARE_FILL: IconData + DOUBLE_MUSIC_NOTE: IconData + DOWN_ARROW: IconData + DOWNLOAD_CIRCLE: IconData + DOWNLOAD_CIRCLE_FILL: IconData + DROP: IconData + DROP_FILL: IconData + DROP_TRIANGLE: IconData + DROP_TRIANGLE_FILL: IconData + EAR: IconData + EJECT: IconData + EJECT_FILL: IconData + ELLIPSES_BUBBLE: IconData + ELLIPSES_BUBBLE_FILL: IconData + ELLIPSIS: IconData + ELLIPSIS_CIRCLE: IconData + ELLIPSIS_CIRCLE_FILL: IconData + ELLIPSIS_VERTICAL: IconData + ELLIPSIS_VERTICAL_CIRCLE: IconData + ELLIPSIS_VERTICAL_CIRCLE_FILL: IconData + ENVELOPE: IconData + ENVELOPE_BADGE: IconData + ENVELOPE_BADGE_FILL: IconData + ENVELOPE_CIRCLE: IconData + ENVELOPE_CIRCLE_FILL: IconData + ENVELOPE_FILL: IconData + ENVELOPE_OPEN: IconData + ENVELOPE_OPEN_FILL: IconData + EQUAL: IconData + EQUAL_CIRCLE: IconData + EQUAL_CIRCLE_FILL: IconData + EQUAL_SQUARE: IconData + EQUAL_SQUARE_FILL: IconData + ESCAPE: IconData + EXCLAMATIONMARK: IconData + EXCLAMATIONMARK_BUBBLE: IconData + EXCLAMATIONMARK_BUBBLE_FILL: IconData + EXCLAMATIONMARK_CIRCLE: IconData + EXCLAMATIONMARK_CIRCLE_FILL: IconData + EXCLAMATIONMARK_OCTAGON: IconData + EXCLAMATIONMARK_OCTAGON_FILL: IconData + EXCLAMATIONMARK_SHIELD: IconData + EXCLAMATIONMARK_SHIELD_FILL: IconData + EXCLAMATIONMARK_SQUARE: IconData + EXCLAMATIONMARK_SQUARE_FILL: IconData + EXCLAMATIONMARK_TRIANGLE: IconData + EXCLAMATIONMARK_TRIANGLE_FILL: IconData + EYE: IconData + EYE_FILL: IconData + EYE_SLASH: IconData + EYE_SLASH_FILL: IconData + EYE_SOLID: IconData + EYEDROPPER: IconData + EYEDROPPER_FULL: IconData + EYEDROPPER_HALFFULL: IconData + EYEGLASSES: IconData + F_CURSIVE: IconData + F_CURSIVE_CIRCLE: IconData + F_CURSIVE_CIRCLE_FILL: IconData + FILM: IconData + FILM_FILL: IconData + FLAG: IconData + FLAG_CIRCLE: IconData + FLAG_CIRCLE_FILL: IconData + FLAG_FILL: IconData + FLAG_SLASH: IconData + FLAG_SLASH_FILL: IconData + FLAME: IconData + FLAME_FILL: IconData + FLOPPY_DISK: IconData + FLOWCHART: IconData + FLOWCHART_FILL: IconData + FOLDER: IconData + FOLDER_BADGE_MINUS: IconData + FOLDER_BADGE_PERSON_CROP: IconData + FOLDER_BADGE_PLUS: IconData + FOLDER_CIRCLE: IconData + FOLDER_CIRCLE_FILL: IconData + FOLDER_FILL: IconData + FOLDER_FILL_BADGE_MINUS: IconData + FOLDER_FILL_BADGE_PERSON_CROP: IconData + FOLDER_FILL_BADGE_PLUS: IconData + FOLDER_OPEN: IconData + FOLDER_SOLID: IconData + FORWARD: IconData + FORWARD_END: IconData + FORWARD_END_ALT: IconData + FORWARD_END_ALT_FILL: IconData + FORWARD_END_FILL: IconData + FORWARD_FILL: IconData + FULLSCREEN: IconData + FULLSCREEN_EXIT: IconData + FUNCTION: IconData + FX: IconData + GAME_CONTROLLER: IconData + GAME_CONTROLLER_SOLID: IconData + GAMECONTROLLER: IconData + GAMECONTROLLER_ALT_FILL: IconData + GAMECONTROLLER_FILL: IconData + GAUGE: IconData + GAUGE_BADGE_MINUS: IconData + GAUGE_BADGE_PLUS: IconData + GEAR: IconData + GEAR_ALT: IconData + GEAR_ALT_FILL: IconData + GEAR_BIG: IconData + GEAR_SOLID: IconData + GIFT: IconData + GIFT_ALT: IconData + GIFT_ALT_FILL: IconData + GIFT_FILL: IconData + GLOBE: IconData + GOBACKWARD: IconData + GOBACKWARD_10: IconData + GOBACKWARD_15: IconData + GOBACKWARD_30: IconData + GOBACKWARD_45: IconData + GOBACKWARD_60: IconData + GOBACKWARD_75: IconData + GOBACKWARD_90: IconData + GOBACKWARD_MINUS: IconData + GOFORWARD: IconData + GOFORWARD_10: IconData + GOFORWARD_15: IconData + GOFORWARD_30: IconData + GOFORWARD_45: IconData + GOFORWARD_60: IconData + GOFORWARD_75: IconData + GOFORWARD_90: IconData + GOFORWARD_PLUS: IconData + GRAPH_CIRCLE: IconData + GRAPH_CIRCLE_FILL: IconData + GRAPH_SQUARE: IconData + GRAPH_SQUARE_FILL: IconData + GREATERTHAN: IconData + GREATERTHAN_CIRCLE: IconData + GREATERTHAN_CIRCLE_FILL: IconData + GREATERTHAN_SQUARE: IconData + GREATERTHAN_SQUARE_FILL: IconData + GRID: IconData + GRID_CIRCLE: IconData + GRID_CIRCLE_FILL: IconData + GROUP: IconData + GROUP_SOLID: IconData + GUITARS: IconData + HAMMER: IconData + HAMMER_FILL: IconData + HAND_DRAW: IconData + HAND_DRAW_FILL: IconData + HAND_POINT_LEFT: IconData + HAND_POINT_LEFT_FILL: IconData + HAND_POINT_RIGHT: IconData + HAND_POINT_RIGHT_FILL: IconData + HAND_RAISED: IconData + HAND_RAISED_FILL: IconData + HAND_RAISED_SLASH: IconData + HAND_RAISED_SLASH_FILL: IconData + HAND_THUMBSDOWN: IconData + HAND_THUMBSDOWN_FILL: IconData + HAND_THUMBSUP: IconData + HAND_THUMBSUP_FILL: IconData + HARE: IconData + HARE_FILL: IconData + HEADPHONES: IconData + HEART: IconData + HEART_CIRCLE: IconData + HEART_CIRCLE_FILL: IconData + HEART_FILL: IconData + HEART_SLASH: IconData + HEART_SLASH_CIRCLE: IconData + HEART_SLASH_CIRCLE_FILL: IconData + HEART_SLASH_FILL: IconData + HEART_SOLID: IconData + HELM: IconData + HEXAGON: IconData + HEXAGON_FILL: IconData + HIFISPEAKER: IconData + HIFISPEAKER_FILL: IconData + HOME: IconData + HOURGLASS: IconData + HOURGLASS_BOTTOMHALF_FILL: IconData + HOURGLASS_TOPHALF_FILL: IconData + HOUSE: IconData + HOUSE_ALT: IconData + HOUSE_ALT_FILL: IconData + HOUSE_FILL: IconData + HURRICANE: IconData + INCREASE_INDENT: IconData + INCREASE_QUOTELEVEL: IconData + INFINITE: IconData + INFO: IconData + INFO_CIRCLE: IconData + INFO_CIRCLE_FILL: IconData + ITALIC: IconData + KEYBOARD: IconData + KEYBOARD_CHEVRON_COMPACT_DOWN: IconData + LAB_FLASK: IconData + LAB_FLASK_SOLID: IconData + LARGECIRCLE_FILL_CIRCLE: IconData + LASSO: IconData + LAYERS: IconData + LAYERS_ALT: IconData + LAYERS_ALT_FILL: IconData + LAYERS_FILL: IconData + LEAF_ARROW_CIRCLEPATH: IconData + LEFT_CHEVRON: IconData + LESSTHAN: IconData + LESSTHAN_CIRCLE: IconData + LESSTHAN_CIRCLE_FILL: IconData + LESSTHAN_SQUARE: IconData + LESSTHAN_SQUARE_FILL: IconData + LIGHT_MAX: IconData + LIGHT_MIN: IconData + LIGHTBULB: IconData + LIGHTBULB_FILL: IconData + LIGHTBULB_SLASH: IconData + LIGHTBULB_SLASH_FILL: IconData + LINE_HORIZONTAL_3: IconData + LINE_HORIZONTAL_3_DECREASE: IconData + LINE_HORIZONTAL_3_DECREASE_CIRCLE: IconData + LINE_HORIZONTAL_3_DECREASE_CIRCLE_FILL: IconData + LINK: IconData + LINK_CIRCLE: IconData + LINK_CIRCLE_FILL: IconData + LIST_BULLET: IconData + LIST_BULLET_BELOW_RECTANGLE: IconData + LIST_BULLET_INDENT: IconData + LIST_DASH: IconData + LIST_NUMBER: IconData + LIST_NUMBER_RTL: IconData + LOCATION: IconData + LOCATION_CIRCLE: IconData + LOCATION_CIRCLE_FILL: IconData + LOCATION_FILL: IconData + LOCATION_NORTH: IconData + LOCATION_NORTH_FILL: IconData + LOCATION_NORTH_LINE: IconData + LOCATION_NORTH_LINE_FILL: IconData + LOCATION_SLASH: IconData + LOCATION_SLASH_FILL: IconData + LOCATION_SOLID: IconData + LOCK: IconData + LOCK_CIRCLE: IconData + LOCK_CIRCLE_FILL: IconData + LOCK_FILL: IconData + LOCK_OPEN: IconData + LOCK_OPEN_FILL: IconData + LOCK_ROTATION: IconData + LOCK_ROTATION_OPEN: IconData + LOCK_SHIELD: IconData + LOCK_SHIELD_FILL: IconData + LOCK_SLASH: IconData + LOCK_SLASH_FILL: IconData + LOOP: IconData + LOOP_THICK: IconData + MACWINDOW: IconData + MAIL: IconData + MAIL_SOLID: IconData + MAP: IconData + MAP_FILL: IconData + MAP_PIN: IconData + MAP_PIN_ELLIPSE: IconData + MAP_PIN_SLASH: IconData + MEMORIES: IconData + MEMORIES_BADGE_MINUS: IconData + MEMORIES_BADGE_PLUS: IconData + METRONOME: IconData + MIC: IconData + MIC_CIRCLE: IconData + MIC_CIRCLE_FILL: IconData + MIC_FILL: IconData + MIC_OFF: IconData + MIC_SLASH: IconData + MIC_SLASH_FILL: IconData + MIC_SOLID: IconData + MINUS: IconData + MINUS_CIRCLE: IconData + MINUS_CIRCLE_FILL: IconData + MINUS_CIRCLED: IconData + MINUS_RECTANGLE: IconData + MINUS_RECTANGLE_FILL: IconData + MINUS_SLASH_PLUS: IconData + MINUS_SQUARE: IconData + MINUS_SQUARE_FILL: IconData + MONEY_DOLLAR: IconData + MONEY_DOLLAR_CIRCLE: IconData + MONEY_DOLLAR_CIRCLE_FILL: IconData + MONEY_EURO: IconData + MONEY_EURO_CIRCLE: IconData + MONEY_EURO_CIRCLE_FILL: IconData + MONEY_POUND: IconData + MONEY_POUND_CIRCLE: IconData + MONEY_POUND_CIRCLE_FILL: IconData + MONEY_RUBL: IconData + MONEY_RUBL_CIRCLE: IconData + MONEY_RUBL_CIRCLE_FILL: IconData + MONEY_YEN: IconData + MONEY_YEN_CIRCLE: IconData + MONEY_YEN_CIRCLE_FILL: IconData + MOON: IconData + MOON_CIRCLE: IconData + MOON_CIRCLE_FILL: IconData + MOON_FILL: IconData + MOON_STARS: IconData + MOON_STARS_FILL: IconData + MOON_ZZZ: IconData + MOON_ZZZ_FILL: IconData + MOVE: IconData + MULTIPLY: IconData + MULTIPLY_CIRCLE: IconData + MULTIPLY_CIRCLE_FILL: IconData + MULTIPLY_SQUARE: IconData + MULTIPLY_SQUARE_FILL: IconData + MUSIC_ALBUMS: IconData + MUSIC_ALBUMS_FILL: IconData + MUSIC_HOUSE: IconData + MUSIC_HOUSE_FILL: IconData + MUSIC_MIC: IconData + MUSIC_NOTE: IconData + MUSIC_NOTE_2: IconData + MUSIC_NOTE_LIST: IconData + NEWS: IconData + NEWS_SOLID: IconData + NOSIGN: IconData + NUMBER: IconData + NUMBER_CIRCLE: IconData + NUMBER_CIRCLE_FILL: IconData + NUMBER_SQUARE: IconData + NUMBER_SQUARE_FILL: IconData + OPTION: IconData + PADLOCK: IconData + PADLOCK_SOLID: IconData + PAINTBRUSH: IconData + PAINTBRUSH_FILL: IconData + PANO: IconData + PANO_FILL: IconData + PAPERCLIP: IconData + PAPERPLANE: IconData + PAPERPLANE_FILL: IconData + PARAGRAPH: IconData + PAUSE: IconData + PAUSE_CIRCLE: IconData + PAUSE_CIRCLE_FILL: IconData + PAUSE_FILL: IconData + PAUSE_RECTANGLE: IconData + PAUSE_RECTANGLE_FILL: IconData + PAUSE_SOLID: IconData + PAW: IconData + PAW_SOLID: IconData + PEN: IconData + PENCIL: IconData + PENCIL_CIRCLE: IconData + PENCIL_CIRCLE_FILL: IconData + PENCIL_ELLIPSIS_RECTANGLE: IconData + PENCIL_OUTLINE: IconData + PENCIL_SLASH: IconData + PERCENT: IconData + PERSON: IconData + PERSON_2: IconData + PERSON_2_ALT: IconData + PERSON_2_FILL: IconData + PERSON_2_SQUARE_STACK: IconData + PERSON_2_SQUARE_STACK_FILL: IconData + PERSON_3: IconData + PERSON_3_FILL: IconData + PERSON_ADD: IconData + PERSON_ADD_SOLID: IconData + PERSON_ALT: IconData + PERSON_ALT_CIRCLE: IconData + PERSON_ALT_CIRCLE_FILL: IconData + PERSON_BADGE_MINUS: IconData + PERSON_BADGE_MINUS_FILL: IconData + PERSON_BADGE_PLUS: IconData + PERSON_BADGE_PLUS_FILL: IconData + PERSON_CIRCLE: IconData + PERSON_CIRCLE_FILL: IconData + PERSON_CROP_CIRCLE: IconData + PERSON_CROP_CIRCLE_BADGE_CHECKMARK: IconData + PERSON_CROP_CIRCLE_BADGE_EXCLAM: IconData + PERSON_CROP_CIRCLE_BADGE_MINUS: IconData + PERSON_CROP_CIRCLE_BADGE_PLUS: IconData + PERSON_CROP_CIRCLE_BADGE_XMARK: IconData + PERSON_CROP_CIRCLE_FILL: IconData + PERSON_CROP_CIRCLE_FILL_BADGE_CHECKMARK: IconData + PERSON_CROP_CIRCLE_FILL_BADGE_EXCLAM: IconData + PERSON_CROP_CIRCLE_FILL_BADGE_MINUS: IconData + PERSON_CROP_CIRCLE_FILL_BADGE_PLUS: IconData + PERSON_CROP_CIRCLE_FILL_BADGE_XMARK: IconData + PERSON_CROP_RECTANGLE: IconData + PERSON_CROP_RECTANGLE_FILL: IconData + PERSON_CROP_SQUARE: IconData + PERSON_CROP_SQUARE_FILL: IconData + PERSON_FILL: IconData + PERSON_SOLID: IconData + PERSONALHOTSPOT: IconData + PERSPECTIVE: IconData + PHONE: IconData + PHONE_ARROW_DOWN_LEFT: IconData + PHONE_ARROW_RIGHT: IconData + PHONE_ARROW_UP_RIGHT: IconData + PHONE_BADGE_PLUS: IconData + PHONE_CIRCLE: IconData + PHONE_CIRCLE_FILL: IconData + PHONE_DOWN: IconData + PHONE_DOWN_CIRCLE: IconData + PHONE_DOWN_CIRCLE_FILL: IconData + PHONE_DOWN_FILL: IconData + PHONE_FILL: IconData + PHONE_FILL_ARROW_DOWN_LEFT: IconData + PHONE_FILL_ARROW_RIGHT: IconData + PHONE_FILL_ARROW_UP_RIGHT: IconData + PHONE_FILL_BADGE_PLUS: IconData + PHONE_SOLID: IconData + PHOTO: IconData + PHOTO_CAMERA: IconData + PHOTO_CAMERA_SOLID: IconData + PHOTO_FILL: IconData + PHOTO_FILL_ON_RECTANGLE_FILL: IconData + PHOTO_ON_RECTANGLE: IconData + PIANO: IconData + PIN: IconData + PIN_FILL: IconData + PIN_SLASH: IconData + PIN_SLASH_FILL: IconData + PLACEMARK: IconData + PLACEMARK_FILL: IconData + PLAY: IconData + PLAY_ARROW: IconData + PLAY_ARROW_SOLID: IconData + PLAY_CIRCLE: IconData + PLAY_CIRCLE_FILL: IconData + PLAY_FILL: IconData + PLAY_RECTANGLE: IconData + PLAY_RECTANGLE_FILL: IconData + PLAYPAUSE: IconData + PLAYPAUSE_FILL: IconData + PLUS: IconData + PLUS_APP: IconData + PLUS_APP_FILL: IconData + PLUS_BUBBLE: IconData + PLUS_BUBBLE_FILL: IconData + PLUS_CIRCLE: IconData + PLUS_CIRCLE_FILL: IconData + PLUS_CIRCLED: IconData + PLUS_RECTANGLE: IconData + PLUS_RECTANGLE_FILL: IconData + PLUS_RECTANGLE_FILL_ON_RECTANGLE_FILL: IconData + PLUS_RECTANGLE_ON_RECTANGLE: IconData + PLUS_SLASH_MINUS: IconData + PLUS_SQUARE: IconData + PLUS_SQUARE_FILL: IconData + PLUS_SQUARE_FILL_ON_SQUARE_FILL: IconData + PLUS_SQUARE_ON_SQUARE: IconData + PLUSMINUS: IconData + PLUSMINUS_CIRCLE: IconData + PLUSMINUS_CIRCLE_FILL: IconData + POWER: IconData + PRINTER: IconData + PRINTER_FILL: IconData + PROFILE_CIRCLED: IconData + PROJECTIVE: IconData + PURCHASED: IconData + PURCHASED_CIRCLE: IconData + PURCHASED_CIRCLE_FILL: IconData + QRCODE: IconData + QRCODE_VIEWFINDER: IconData + QUESTION: IconData + QUESTION_CIRCLE: IconData + QUESTION_CIRCLE_FILL: IconData + QUESTION_DIAMOND: IconData + QUESTION_DIAMOND_FILL: IconData + QUESTION_SQUARE: IconData + QUESTION_SQUARE_FILL: IconData + QUOTE_BUBBLE: IconData + QUOTE_BUBBLE_FILL: IconData + RADIOWAVES_LEFT: IconData + RADIOWAVES_RIGHT: IconData + RAYS: IconData + RECORDINGTAPE: IconData + RECTANGLE: IconData + RECTANGLE_3_OFFGRID: IconData + RECTANGLE_3_OFFGRID_FILL: IconData + RECTANGLE_ARROW_UP_RIGHT_ARROW_DOWN_LEFT: IconData + RECTANGLE_ARROW_UP_RIGHT_ARROW_DOWN_LEFT_SLASH: IconData + RECTANGLE_BADGE_CHECKMARK: IconData + RECTANGLE_BADGE_XMARK: IconData + RECTANGLE_COMPRESS_VERTICAL: IconData + RECTANGLE_DOCK: IconData + RECTANGLE_EXPAND_VERTICAL: IconData + RECTANGLE_FILL: IconData + RECTANGLE_FILL_BADGE_CHECKMARK: IconData + RECTANGLE_FILL_BADGE_XMARK: IconData + RECTANGLE_FILL_ON_RECTANGLE_ANGLED_FILL: IconData + RECTANGLE_FILL_ON_RECTANGLE_FILL: IconData + RECTANGLE_GRID_1X2: IconData + RECTANGLE_GRID_1X2_FILL: IconData + RECTANGLE_GRID_2X2: IconData + RECTANGLE_GRID_2X2_FILL: IconData + RECTANGLE_GRID_3X2: IconData + RECTANGLE_GRID_3X2_FILL: IconData + RECTANGLE_ON_RECTANGLE: IconData + RECTANGLE_ON_RECTANGLE_ANGLED: IconData + RECTANGLE_PAPERCLIP: IconData + RECTANGLE_SPLIT_3X1: IconData + RECTANGLE_SPLIT_3X1_FILL: IconData + RECTANGLE_SPLIT_3X3: IconData + RECTANGLE_SPLIT_3X3_FILL: IconData + RECTANGLE_STACK: IconData + RECTANGLE_STACK_BADGE_MINUS: IconData + RECTANGLE_STACK_BADGE_PERSON_CROP: IconData + RECTANGLE_STACK_BADGE_PLUS: IconData + RECTANGLE_STACK_FILL: IconData + RECTANGLE_STACK_FILL_BADGE_MINUS: IconData + RECTANGLE_STACK_FILL_BADGE_PERSON_CROP: IconData + RECTANGLE_STACK_FILL_BADGE_PLUS: IconData + RECTANGLE_STACK_PERSON_CROP: IconData + RECTANGLE_STACK_PERSON_CROP_FILL: IconData + REFRESH: IconData + REFRESH_BOLD: IconData + REFRESH_CIRCLED: IconData + REFRESH_CIRCLED_SOLID: IconData + REFRESH_THICK: IconData + REFRESH_THIN: IconData + REPEAT: IconData + REPEAT_1: IconData + REPLY: IconData + REPLY_ALL: IconData + REPLY_THICK_SOLID: IconData + RESIZE: IconData + RESIZE_H: IconData + RESIZE_V: IconData + RESTART: IconData + RETURN_ICON: IconData + RHOMBUS: IconData + RHOMBUS_FILL: IconData + RIGHT_CHEVRON: IconData + ROCKET: IconData + ROCKET_FILL: IconData + ROSETTE: IconData + ROTATE_LEFT: IconData + ROTATE_LEFT_FILL: IconData + ROTATE_RIGHT: IconData + ROTATE_RIGHT_FILL: IconData + SCISSORS: IconData + SCISSORS_ALT: IconData + SCOPE: IconData + SCRIBBLE: IconData + SEARCH: IconData + SEARCH_CIRCLE: IconData + SEARCH_CIRCLE_FILL: IconData + SELECTION_PIN_IN_OUT: IconData + SETTINGS: IconData + SETTINGS_SOLID: IconData + SHARE: IconData + SHARE_SOLID: IconData + SHARE_UP: IconData + SHIELD: IconData + SHIELD_FILL: IconData + SHIELD_LEFTHALF_FILL: IconData + SHIELD_SLASH: IconData + SHIELD_SLASH_FILL: IconData + SHIFT: IconData + SHIFT_FILL: IconData + SHOPPING_CART: IconData + SHUFFLE: IconData + SHUFFLE_MEDIUM: IconData + SHUFFLE_THICK: IconData + SIDEBAR_LEFT: IconData + SIDEBAR_RIGHT: IconData + SIGNATURE: IconData + SKEW: IconData + SLASH_CIRCLE: IconData + SLASH_CIRCLE_FILL: IconData + SLIDER_HORIZONTAL_3: IconData + SLIDER_HORIZONTAL_BELOW_RECTANGLE: IconData + SLOWMO: IconData + SMALLCIRCLE_CIRCLE: IconData + SMALLCIRCLE_CIRCLE_FILL: IconData + SMALLCIRCLE_FILL_CIRCLE: IconData + SMALLCIRCLE_FILL_CIRCLE_FILL: IconData + SMILEY: IconData + SMILEY_FILL: IconData + SMOKE: IconData + SMOKE_FILL: IconData + SNOW: IconData + SORT_DOWN: IconData + SORT_DOWN_CIRCLE: IconData + SORT_DOWN_CIRCLE_FILL: IconData + SORT_UP: IconData + SORT_UP_CIRCLE: IconData + SORT_UP_CIRCLE_FILL: IconData + SPARKLES: IconData + SPEAKER: IconData + SPEAKER_1: IconData + SPEAKER_1_FILL: IconData + SPEAKER_2: IconData + SPEAKER_2_FILL: IconData + SPEAKER_3: IconData + SPEAKER_3_FILL: IconData + SPEAKER_FILL: IconData + SPEAKER_SLASH: IconData + SPEAKER_SLASH_FILL: IconData + SPEAKER_SLASH_FILL_RTL: IconData + SPEAKER_SLASH_RTL: IconData + SPEAKER_ZZZ: IconData + SPEAKER_ZZZ_FILL: IconData + SPEAKER_ZZZ_FILL_RTL: IconData + SPEAKER_ZZZ_RTL: IconData + SPEEDOMETER: IconData + SPORTSCOURT: IconData + SPORTSCOURT_FILL: IconData + SQUARE: IconData + SQUARE_ARROW_DOWN: IconData + SQUARE_ARROW_DOWN_FILL: IconData + SQUARE_ARROW_DOWN_ON_SQUARE: IconData + SQUARE_ARROW_DOWN_ON_SQUARE_FILL: IconData + SQUARE_ARROW_LEFT: IconData + SQUARE_ARROW_LEFT_FILL: IconData + SQUARE_ARROW_RIGHT: IconData + SQUARE_ARROW_RIGHT_FILL: IconData + SQUARE_ARROW_UP: IconData + SQUARE_ARROW_UP_FILL: IconData + SQUARE_ARROW_UP_ON_SQUARE: IconData + SQUARE_ARROW_UP_ON_SQUARE_FILL: IconData + SQUARE_FAVORITES: IconData + SQUARE_FAVORITES_ALT: IconData + SQUARE_FAVORITES_ALT_FILL: IconData + SQUARE_FAVORITES_FILL: IconData + SQUARE_FILL: IconData + SQUARE_FILL_LINE_VERTICAL_SQUARE: IconData + SQUARE_FILL_LINE_VERTICAL_SQUARE_FILL: IconData + SQUARE_FILL_ON_CIRCLE_FILL: IconData + SQUARE_FILL_ON_SQUARE_FILL: IconData + SQUARE_GRID_2X2: IconData + SQUARE_GRID_2X2_FILL: IconData + SQUARE_GRID_3X2: IconData + SQUARE_GRID_3X2_FILL: IconData + SQUARE_GRID_4X3_FILL: IconData + SQUARE_LEFTHALF_FILL: IconData + SQUARE_LINE_VERTICAL_SQUARE: IconData + SQUARE_LINE_VERTICAL_SQUARE_FILL: IconData + SQUARE_LIST: IconData + SQUARE_LIST_FILL: IconData + SQUARE_ON_CIRCLE: IconData + SQUARE_ON_SQUARE: IconData + SQUARE_PENCIL: IconData + SQUARE_PENCIL_FILL: IconData + SQUARE_RIGHTHALF_FILL: IconData + SQUARE_SPLIT_1X2: IconData + SQUARE_SPLIT_1X2_FILL: IconData + SQUARE_SPLIT_2X1: IconData + SQUARE_SPLIT_2X1_FILL: IconData + SQUARE_SPLIT_2X2: IconData + SQUARE_SPLIT_2X2_FILL: IconData + SQUARE_STACK: IconData + SQUARE_STACK_3D_DOWN_DOTTEDLINE: IconData + SQUARE_STACK_3D_DOWN_RIGHT: IconData + SQUARE_STACK_3D_DOWN_RIGHT_FILL: IconData + SQUARE_STACK_3D_UP: IconData + SQUARE_STACK_3D_UP_FILL: IconData + SQUARE_STACK_3D_UP_SLASH: IconData + SQUARE_STACK_3D_UP_SLASH_FILL: IconData + SQUARE_STACK_FILL: IconData + SQUARES_BELOW_RECTANGLE: IconData + STAR: IconData + STAR_CIRCLE: IconData + STAR_CIRCLE_FILL: IconData + STAR_FILL: IconData + STAR_LEFTHALF_FILL: IconData + STAR_SLASH: IconData + STAR_SLASH_FILL: IconData + STAROFLIFE: IconData + STAROFLIFE_FILL: IconData + STOP: IconData + STOP_CIRCLE: IconData + STOP_CIRCLE_FILL: IconData + STOP_FILL: IconData + STOPWATCH: IconData + STOPWATCH_FILL: IconData + STRIKETHROUGH: IconData + SUIT_CLUB: IconData + SUIT_CLUB_FILL: IconData + SUIT_DIAMOND: IconData + SUIT_DIAMOND_FILL: IconData + SUIT_HEART: IconData + SUIT_HEART_FILL: IconData + SUIT_SPADE: IconData + SUIT_SPADE_FILL: IconData + SUM: IconData + SUN_DUST: IconData + SUN_DUST_FILL: IconData + SUN_HAZE: IconData + SUN_HAZE_FILL: IconData + SUN_MAX: IconData + SUN_MAX_FILL: IconData + SUN_MIN: IconData + SUN_MIN_FILL: IconData + SUNRISE: IconData + SUNRISE_FILL: IconData + SUNSET: IconData + SUNSET_FILL: IconData + SWITCH_CAMERA: IconData + SWITCH_CAMERA_SOLID: IconData + T_BUBBLE: IconData + T_BUBBLE_FILL: IconData + TABLE: IconData + TABLE_BADGE_MORE: IconData + TABLE_BADGE_MORE_FILL: IconData + TABLE_FILL: IconData + TAG: IconData + TAG_CIRCLE: IconData + TAG_CIRCLE_FILL: IconData + TAG_FILL: IconData + TAG_SOLID: IconData + TAGS: IconData + TAGS_SOLID: IconData + TEXT_ALIGNCENTER: IconData + TEXT_ALIGNLEFT: IconData + TEXT_ALIGNRIGHT: IconData + TEXT_APPEND: IconData + TEXT_BADGE_CHECKMARK: IconData + TEXT_BADGE_MINUS: IconData + TEXT_BADGE_PLUS: IconData + TEXT_BADGE_STAR: IconData + TEXT_BADGE_XMARK: IconData + TEXT_BUBBLE: IconData + TEXT_BUBBLE_FILL: IconData + TEXT_CURSOR: IconData + TEXT_INSERT: IconData + TEXT_JUSTIFY: IconData + TEXT_JUSTIFYLEFT: IconData + TEXT_JUSTIFYRIGHT: IconData + TEXT_QUOTE: IconData + TEXTBOX: IconData + TEXTFORMAT: IconData + TEXTFORMAT_123: IconData + TEXTFORMAT_ABC: IconData + TEXTFORMAT_ABC_DOTTEDUNDERLINE: IconData + TEXTFORMAT_ALT: IconData + TEXTFORMAT_SIZE: IconData + TEXTFORMAT_SUBSCRIPT: IconData + TEXTFORMAT_SUPERSCRIPT: IconData + THERMOMETER: IconData + THERMOMETER_SNOWFLAKE: IconData + THERMOMETER_SUN: IconData + TICKET: IconData + TICKET_FILL: IconData + TICKETS: IconData + TICKETS_FILL: IconData + TIME: IconData + TIME_SOLID: IconData + TIMELAPSE: IconData + TIMER: IconData + TIMER_FILL: IconData + TODAY: IconData + TODAY_FILL: IconData + TORNADO: IconData + TORTOISE: IconData + TORTOISE_FILL: IconData + TRAIN_STYLE_ONE: IconData + TRAIN_STYLE_TWO: IconData + TRAM_FILL: IconData + TRASH: IconData + TRASH_CIRCLE: IconData + TRASH_CIRCLE_FILL: IconData + TRASH_FILL: IconData + TRASH_SLASH: IconData + TRASH_SLASH_FILL: IconData + TRAY: IconData + TRAY_2: IconData + TRAY_2_FILL: IconData + TRAY_ARROW_DOWN: IconData + TRAY_ARROW_DOWN_FILL: IconData + TRAY_ARROW_UP: IconData + TRAY_ARROW_UP_FILL: IconData + TRAY_FILL: IconData + TRAY_FULL: IconData + TRAY_FULL_FILL: IconData + TREE: IconData + TRIANGLE: IconData + TRIANGLE_FILL: IconData + TRIANGLE_LEFTHALF_FILL: IconData + TRIANGLE_RIGHTHALF_FILL: IconData + TROPICALSTORM: IconData + TUNINGFORK: IconData + TV: IconData + TV_CIRCLE: IconData + TV_CIRCLE_FILL: IconData + TV_FILL: IconData + TV_MUSIC_NOTE: IconData + TV_MUSIC_NOTE_FILL: IconData + UIWINDOW_SPLIT_2X1: IconData + UMBRELLA: IconData + UMBRELLA_FILL: IconData + UNDERLINE: IconData + UP_ARROW: IconData + UPLOAD_CIRCLE: IconData + UPLOAD_CIRCLE_FILL: IconData + VIDEO_CAMERA: IconData + VIDEO_CAMERA_SOLID: IconData + VIDEOCAM: IconData + VIDEOCAM_CIRCLE: IconData + VIDEOCAM_CIRCLE_FILL: IconData + VIDEOCAM_FILL: IconData + VIEW_2D: IconData + VIEW_3D: IconData + VIEWFINDER: IconData + VIEWFINDER_CIRCLE: IconData + VIEWFINDER_CIRCLE_FILL: IconData + VOLUME_DOWN: IconData + VOLUME_MUTE: IconData + VOLUME_OFF: IconData + VOLUME_UP: IconData + WAND_RAYS: IconData + WAND_RAYS_INVERSE: IconData + WAND_STARS: IconData + WAND_STARS_INVERSE: IconData + WAVEFORM: IconData + WAVEFORM_CIRCLE: IconData + WAVEFORM_CIRCLE_FILL: IconData + WAVEFORM_PATH: IconData + WAVEFORM_PATH_BADGE_MINUS: IconData + WAVEFORM_PATH_BADGE_PLUS: IconData + WAVEFORM_PATH_ECG: IconData + WIFI: IconData + WIFI_EXCLAMATIONMARK: IconData + WIFI_SLASH: IconData + WIND: IconData + WIND_SNOW: IconData + WRENCH: IconData + WRENCH_FILL: IconData + XMARK: IconData + XMARK_CIRCLE: IconData + XMARK_CIRCLE_FILL: IconData + XMARK_OCTAGON: IconData + XMARK_OCTAGON_FILL: IconData + XMARK_RECTANGLE: IconData + XMARK_RECTANGLE_FILL: IconData + XMARK_SEAL: IconData + XMARK_SEAL_FILL: IconData + XMARK_SHIELD: IconData + XMARK_SHIELD_FILL: IconData + XMARK_SQUARE: IconData + XMARK_SQUARE_FILL: IconData + ZOOM_IN: IconData + ZOOM_OUT: IconData + ZZZ: IconData diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_list_tile.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_list_tile.py new file mode 100644 index 0000000000..7ff3a4c481 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_list_tile.py @@ -0,0 +1,136 @@ +from typing import Annotated, Optional, Union + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, + StrOrControl, + Url, +) +from flet.utils.validation import V + +__all__ = ["CupertinoListTile"] + + +@control("CupertinoListTile") +class CupertinoListTile(LayoutControl): + """ + An iOS-style list tile. + + The CupertinoListTile is a Cupertino equivalent of the Material \ + :class:`~flet.ListTile`. + + ```python + ft.CupertinoListTile( + title="Notifications", + subtitle="Enabled", + width=400, + leading=ft.Icon(ft.Icons.NOTIFICATIONS_OUTLINED), + trailing=ft.Icon(ft.Icons.CHEVRON_RIGHT), + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + ) + ``` + """ + + title: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The primary content of this list tile. + + Typically a :class:`~flet.Text` control. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + subtitle: Optional[StrOrControl] = None + """ + Additional content displayed below the :attr:`title`. + + Typically a :class:`~flet.Text` control. + """ + + leading: Optional[IconDataOrControl] = None + """ + A control to display before the :attr:`title`. + """ + + trailing: Optional[IconDataOrControl] = None + """ + A control to display after the :attr:`title`. + + Typically an :class:`~flet.Icon` control. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this list tile. + """ + + bgcolor_activated: Optional[ColorValue] = None + """ + The background color of this list tile after it was tapped. + """ + + padding: Optional[PaddingValue] = None + """ + The tile's internal padding. Insets a CupertinoListTile's contents: its \ + :attr:`leading`, :attr:`title`, :attr:`subtitle`, :attr:`additional_info` and \ + :attr:`trailing` controls. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback is + provided, it is fired after that. + """ + + toggle_inputs: bool = False + """ + Whether clicking on this tile should toggle the state of (visible) toggleable \ + controls like :class:`~flet.Radio`, :class:`~flet.Checkbox` or \ + :class:`~flet.Switch` inside it. + """ + + additional_info: Optional[StrOrControl] = None + """ + A `Control` to display on the right of the list tile, before :attr:`trailing`. + + Similar to :attr:`subtitle`, an :attr:`additional_info` + is used to display additional information. + + Typically a :class:`~flet.Text` control. + """ + + leading_size: Optional[Number] = None + """ + Used to constrain the width and height of :attr:`leading` control. + + Defaults to `30.0`, if :attr:`notched` is `True`, else `28.0`. + """ + + leading_to_title: Optional[Number] = None + """ + The horizontal space between :attr:`leading` and :attr:`title`. + + Defaults to `12.0`, if :attr:`notched` is `True`, else `16.0`. + """ + + notched: bool = False + """ + Whether this list tile should be created in an "Inset Grouped" form, known from \ + either iOS Notes or Reminders app. + """ + + on_click: Optional[ControlEventHandler["CupertinoListTile"]] = None + """ + Called when a user clicks/taps the list tile. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_navigation_bar.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_navigation_bar.py new file mode 100644 index 0000000000..4ae8b9f12d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_navigation_bar.py @@ -0,0 +1,90 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.border import Border +from flet.controls.control_event import ControlEventHandler +from flet.controls.cupertino.cupertino_colors import CupertinoColors +from flet.controls.layout_control import LayoutControl +from flet.controls.material.navigation_bar import NavigationBarDestination +from flet.controls.types import ( + ColorValue, + Number, +) +from flet.utils.validation import V + +__all__ = ["CupertinoNavigationBar"] + + +@control("CupertinoNavigationBar") +class CupertinoNavigationBar(LayoutControl): + """ + An iOS-styled bottom navigation tab bar. + + Navigation bars offer a persistent and convenient way to switch between primary + destinations in an app. + """ + + destinations: Annotated[ + list[NavigationBarDestination], + V.visible_controls(min_count=2), + ] + """ + The destinations of this navigation bar. + + Raises: + ValueError: If it does not contain at least + two visible `NavigationBarDestination`s. + """ + + selected_index: int = 0 + """ + The index into :attr:`destinations` for the currently selected \ + :class:`~flet.NavigationBarDestination`. + + Raises: + IndexError: If it is not greater than or equal to `0`. + IndexError: If it is not less than the length of visible + :attr:`destinations`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color of the navigation bar itself. + """ + + active_color: Optional[ColorValue] = None + """ + The foreground color of the icon and title of the selected :attr:`destinations`. + """ + + inactive_color: ColorValue = CupertinoColors.INACTIVE_GRAY + """ + The foreground color of the icon and title of the unselected :attr:`destinations`. + """ + + border: Optional[Border] = None + """ + Defines the border of this navigation bar. + """ + + icon_size: Number = 30 + """ + The size of all destination icons. + """ + + on_change: Optional[ControlEventHandler["CupertinoNavigationBar"]] = None + """ + Called when selected destination changed. + """ + + def before_update(self): + super().before_update() + visible_destinations_count = len([d for d in self.destinations if d.visible]) + if visible_destinations_count >= 2 and not ( + 0 <= self.selected_index < visible_destinations_count + ): + raise IndexError( + f"selected_index ({self.selected_index}) is out of range. " + f"Expected a value between 0 and {visible_destinations_count - 1} " + "inclusive." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_picker.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_picker.py new file mode 100644 index 0000000000..3698d15222 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_picker.py @@ -0,0 +1,118 @@ +from dataclasses import field +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.cupertino.cupertino_colors import CupertinoColors +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + Number, +) +from flet.utils.validation import V + +__all__ = ["CupertinoPicker"] + + +@control("CupertinoPicker") +class CupertinoPicker(LayoutControl): + """ + An iOS-styled picker. + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of controls representing items in this picker. + """ + + item_extent: Annotated[ + Number, + V.gt(0.0), + ] = 32.0 + """ + The uniform height of all :attr:`controls`. + + Raises: + ValueError: If it is not strictly greater than `0.0`. + """ + + selected_index: int = 0 + """ + The index (starting from `0`) of the selected item in the :attr:`controls` list. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this timer picker. + """ + + use_magnifier: bool = False + """ + Whether to use the magnifier for the center item of this picker's wheel. + """ + + looping: bool = False + """ + If `True`, children on a wheel can be scrolled in a loop. + """ + + magnification: Annotated[ + Number, + V.gt(0.0), + ] = 1.0 + """ + The zoomed-in or magnification rate of the magnifier. + + If the value is greater than `1.0`, the item in the center will be zoomed in by that + rate, and it will also be rendered as flat, not cylindrical like the rest of the + list. The item will be zoomed-out if magnification is less than `1.0`. + + Note: + Has effect only if :attr:`use_magnifier` is `True`. + + Raises: + ValueError: If it is not strictly greater than `0.0`. + """ + + squeeze: Annotated[ + Number, + V.gt(0.0), + ] = 1.45 + """ + The angular compactness of the children on the wheel. + + Raises: + ValueError: If it is not strictly greater than `0.0`. + """ + + diameter_ratio: Number = 1.07 + """ + Relative ratio between this picker's height and the simulated cylinder's diameter. + + Smaller values create more pronounced curvatures in the scrollable wheel. + """ + + off_axis_fraction: Number = 0.0 + """ + How much the wheel is horizontally off-center, as a fraction of its width. + """ + + selection_overlay: Optional[Control] = None + """ + A control overlaid on the picker to highlight the selected entry, centered and \ + matching the height of the center row. + + Defaults to a rounded rectangle in iOS 14 style with + :attr:`default_selection_overlay_bgcolor` as background color. + """ + + default_selection_overlay_bgcolor: ColorValue = CupertinoColors.TERTIARY_SYSTEM_FILL + """ + The default background color of the :attr:`selection_overlay`. + """ + + on_change: Optional[ControlEventHandler["CupertinoPicker"]] = None + """ + Called when the selection changes. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_radio.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_radio.py new file mode 100644 index 0000000000..a51268052a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_radio.py @@ -0,0 +1,105 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.colors import Colors +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + LabelPosition, + MouseCursor, +) + +__all__ = ["CupertinoRadio"] + + +@control("CupertinoRadio") +class CupertinoRadio(LayoutControl): + """ + A macOS-styled radio button, allowing the user to select a single option from two \ + or more choices. + + ```python + ft.RadioGroup( + value="option_2", + content=ft.Column( + intrinsic_width=True, + controls=[ + ft.CupertinoRadio(value="option_1", label="Option 1"), + ft.CupertinoRadio(value="option_2", label="Option 2"), + ft.CupertinoRadio(value="option_3", label="Option 3"), + ], + ), + ) + ``` + """ + + label: Optional[str] = None + """ + The clickable label to display on the right of this radio. + """ + + value: str = "" + """ + The value to set to :class:`~flet.RadioGroup` ancestor/parent when this radio is \ + selected. + """ + + label_position: LabelPosition = LabelPosition.RIGHT + """ + The position of the label relative to this radio. + """ + + fill_color: Optional[ColorValue] = None + """ + The color that fills this radio. + """ + + active_color: Optional[ColorValue] = Colors.PRIMARY + """ + The color used to fill this radio when it is selected. + """ + + inactive_color: Optional[ColorValue] = None + """ + The color used to fill this radio when it is not selected. + """ + + autofocus: bool = False + """ + Whether this radio will be selected as the initial focus. + + If there is more than one control on a page with autofocus set, then the first + one added to the page will get focus. + """ + + use_checkmark_style: bool = False + """ + Whether the radio displays in a checkbox style instead of the default radio style. + """ + + toggleable: bool = False + """ + Whether this radio button can return to an indeterminate state by selecting it \ + again when already selected. + """ + + focus_color: Optional[ColorValue] = None + """ + The color for the radio's border when it has the input focus. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor for a mouse pointer when it enters or is hovering over this radio. + """ + + on_focus: Optional[ControlEventHandler["CupertinoRadio"]] = None + """ + Called when this radio has received focus. + """ + + on_blur: Optional[ControlEventHandler["CupertinoRadio"]] = None + """ + Called when this radio has lost focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_segmented_button.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_segmented_button.py new file mode 100644 index 0000000000..b07aec062a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_segmented_button.py @@ -0,0 +1,112 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ColorValue +from flet.utils.validation import V + +__all__ = ["CupertinoSegmentedButton"] + + +@control("CupertinoSegmentedButton") +class CupertinoSegmentedButton(LayoutControl): + """ + An iOS-style segmented button. + + Example: + ```python + ft.CupertinoSegmentedButton( + selected_index=1, + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Three"), + ], + ) + ``` + """ + + controls: Annotated[ + list[Control], + V.visible_controls(min_count=2), + ] + """ + The list of segments to be displayed. + + Raises: + ValueError: If it does not contain at least two visible `Control`s. + """ + + selected_index: int = 0 + """ + The index (starting from 0) of the selected segment in the :attr:`controls` list. + + Raises: + IndexError: If :attr:`selected_index` is out of range relative to the + visible controls. + """ + + selected_color: Optional[ColorValue] = None + """ + The color of this button when it is selected. + """ + + unselected_color: Optional[ColorValue] = None + """ + The color of this button when it is not selected. + """ + + border_color: Optional[ColorValue] = None + """ + The color of this button's border. + """ + + padding: Optional[PaddingValue] = None + """ + This button's padding. + """ + + click_color: Optional[ColorValue] = None + """ + The color used to fill the background of this control when temporarily interacting \ + with through a long press or drag. + + Defaults to the :attr:`selected_color` + with 20% opacity. + """ + + disabled_color: Optional[ColorValue] = None + """ + The color used to fill the background of the segment when it is disabled. + + If `None`, this color will be 50% opacity of the + :attr:`selected_color` when + the segment is selected. If the segment is unselected, this color will be + set to the :attr:`unselected_color`. + """ + + disabled_text_color: Optional[ColorValue] = None + """ + The color used for the text of the segment when it is disabled. + """ + + on_change: Optional[ControlEventHandler["CupertinoSegmentedButton"]] = None + """ + Called when the state of the button is changed - when one of the `controls` is \ + clicked. + """ + + def before_update(self): + super().before_update() + visible_controls_count = len([c for c in self.controls if c.visible]) + if visible_controls_count >= 2 and not ( + 0 <= self.selected_index < visible_controls_count + ): + raise IndexError( + f"selected_index ({self.selected_index}) is out of range. " + f"Expected a value between 0 and {visible_controls_count - 1}, " + "inclusive." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_slider.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_slider.py new file mode 100644 index 0000000000..f8fada5bbb --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_slider.py @@ -0,0 +1,127 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + Number, +) +from flet.utils.validation import V + +__all__ = ["CupertinoSlider"] + + +@control("CupertinoSlider") +class CupertinoSlider(LayoutControl): + """ + An iOS-type slider. + + It provides a visual indication of adjustable content, as well as the current + setting in the total range of content. + + Use a slider when you want people to set defined values (such as volume or + brightness), or when people would benefit from instant feedback on the effect of + setting changes. + + Example: + ```python + ft.CupertinoSlider(value=0.6) + ``` + """ + + value: Annotated[ + Optional[Number], + V.ge_field("min"), + V.le_field("max"), + ] = None + """ + The currently selected value for this slider. + + The slider's thumb is drawn at a position that corresponds to this value. + + Raises: + ValueError: If it is not greater than or equal to :attr:`min`. + ValueError: If it is not less than or equal to :attr:`max`. + """ + + min: Annotated[ + Number, + V.le_field("max"), + V.le_field("value"), + ] = 0.0 + """ + The minimum value the user can select. + + If :attr:`max` is equal to the `min`, then this slider is disabled. + + Raises: + ValueError: If it is not less than or equal to :attr:`max`. + ValueError: If it is not less than or equal to :attr:`value`, when + :attr:`value` is set. + """ + + max: Annotated[ + Number, + V.ge_field("min"), + V.ge_field("value"), + ] = 1.0 + """ + The maximum value the user can select. + + If :attr:`min` is equal to the `max`, then this slider is disabled. + + Raises: + ValueError: If it is not greater than or equal to :attr:`min`. + ValueError: If it is not greater than or equal to :attr:`value`, when + :attr:`value` is set. + """ + + divisions: Optional[int] = None + """ + The number of discrete divisions. + + If `None`, the slider is continuous. + """ + + active_color: Optional[ColorValue] = None + """ + The color to use for the portion of the slider track that is active. + + The "active" side of the slider is the side between the thumb and the minimum + value. + """ + + thumb_color: Optional[ColorValue] = None + """ + The color of this slider's thumb. + """ + + on_change: Optional[ControlEventHandler["CupertinoSlider"]] = None + """ + Called when the state of this slider changed. + """ + + on_change_start: Optional[ControlEventHandler["CupertinoSlider"]] = None + """ + Called when the user starts selecting a new value for this slider. + """ + + on_change_end: Optional[ControlEventHandler["CupertinoSlider"]] = None + """ + Called when the user is done selecting a new value for this slider. + """ + + on_focus: Optional[ControlEventHandler["CupertinoSlider"]] = None + """ + Called when this slider has received focus. + """ + + on_blur: Optional[ControlEventHandler["CupertinoSlider"]] = None + """ + Called when this slider has lost focus. + """ + + def before_update(self): + super().before_update() + self.value = self.value if self.value is not None else self.min diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_sliding_segmented_button.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_sliding_segmented_button.py new file mode 100644 index 0000000000..384fa63bb3 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_sliding_segmented_button.py @@ -0,0 +1,103 @@ +from dataclasses import field +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.cupertino.cupertino_colors import CupertinoColors +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import Padding, PaddingValue +from flet.controls.types import ( + ColorValue, +) +from flet.utils.validation import V + +__all__ = ["CupertinoSlidingSegmentedButton"] + + +@control("CupertinoSlidingSegmentedButton") +class CupertinoSlidingSegmentedButton(LayoutControl): + """ + A cupertino sliding segmented button. + + Example: + ```python + ft.CupertinoSlidingSegmentedButton( + selected_index=1, + controls=[ + ft.Text("One"), + ft.Text("Two"), + ft.Text("Three"), + ], + ) + ``` + """ + + controls: Annotated[ + list[Control], + V.visible_controls(min_count=2), + ] + """ + The list of segments to be displayed. + + Raises: + ValueError: If it does not contain at least two visible `Control`s. + """ + + selected_index: int = 0 + """ + The index (starting from 0) of the selected segment in the :attr:`controls` list. + + Raises: + IndexError: If it is not between `0` and the length of visible + :attr:`controls`, inclusive. + """ + + bgcolor: ColorValue = CupertinoColors.TERTIARY_SYSTEM_FILL + """ + The background color of this button. + """ + + thumb_color: Optional[ColorValue] = None + """ + The color of this button when it is not selected. + """ + + padding: PaddingValue = field( + default_factory=lambda: Padding.symmetric(vertical=2, horizontal=3) + ) + """ + The amount of space by which to inset the :attr:`controls`. + """ + + proportional_width: bool = False + """ + Determine whether segments have proportional widths based on their content. + + If `False`, all segments will have the same width, determined by the longest + segment. If `True`, each segment's width will be determined by its individual + content. + + If the max width of parent constraints is smaller than the width that this control + needs, the segment widths will scale down proportionally to ensure this control + fits within the boundaries; similarly, if the min width of parent constraints is + larger, the segment width will scales up to meet the min width requirement. + """ + + on_change: Optional[ControlEventHandler["CupertinoSlidingSegmentedButton"]] = None + """ + Called when the state of the button is changed - when one of the :attr:`controls` \ + is clicked. + """ + + def before_update(self): + super().before_update() + visible_controls_count = len([c for c in self.controls if c.visible]) + if visible_controls_count >= 2 and not ( + 0 <= self.selected_index < visible_controls_count + ): + raise IndexError( + f"selected_index ({self.selected_index}) is out of range. " + f"Expected a value between 0 and {visible_controls_count - 1}, " + "inclusive." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_switch.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_switch.py new file mode 100644 index 0000000000..356c8389d9 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_switch.py @@ -0,0 +1,158 @@ +from typing import Optional, Union + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + IconData, + LabelPosition, + Number, +) + +__all__ = ["CupertinoSwitch"] + + +@control("CupertinoSwitch") +class CupertinoSwitch(LayoutControl): + """ + An iOS-style switch. + + Used to toggle the on/off state of a single setting. + + Example: + ```python + ft.CupertinoSwitch(value=True) + ``` + """ + + label: Optional[str] = None + """ + The clickable label to display on the right of this switch. + """ + + value: bool = False + """ + The current value of this switch. + """ + + label_position: LabelPosition = LabelPosition.RIGHT + """ + The position of the :attr:`label` relative to this switch. + """ + + thumb_color: Optional[ColorValue] = None + """ + The color of this switch's thumb. + """ + + focus_color: Optional[ColorValue] = None + """ + The color to use for the focus highlight for keyboard interactions. + """ + + autofocus: bool = False + """ + Whether this switch will be selected as the initial focus. + + If there is more than one control on a page with autofocus set, then the first one + added to the page will get focus. + """ + + on_label_color: Optional[ColorValue] = None + """ + The color to use for the accessibility label when the switch is on. + """ + + off_label_color: Optional[ColorValue] = None + """ + The color to use for the accessibility label when the switch is off. + """ + + active_thumb_image_src: Optional[Union[str, bytes]] = None + """ + An image to use on the thumb of this switch when the switch is on. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + """ + + inactive_thumb_image_src: Optional[Union[str, bytes]] = None + """ + An image to use on the thumb of this switch when the switch is off. + + It can be one of the following: + - A URL or local [asset file](https://flet.dev/docs/cookbook/assets) path; + - A base64 string; + - Raw bytes. + """ + + active_track_color: Optional[ColorValue] = None + """ + The color to use on the track when this switch is on. + """ + + inactive_thumb_color: Optional[ColorValue] = None + """ + The color to use on the thumb when this switch is off. + + If `None`, defaults to :attr:`thumb_color`, and if this is also `None`, + defaults to :attr:`flet.CupertinoColors.WHITE`. + """ + + inactive_track_color: Optional[ColorValue] = None + """ + The color to use on the track when this switch is off. + """ + + track_outline_color: Optional[ControlStateValue[ColorValue]] = None + """ + The outline color of this switch's track in various :class:`~flet.ControlState`s. + + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, and :attr:`flet.ControlState.DEFAULT`. + """ + + track_outline_width: Optional[ControlStateValue[Optional[Number]]] = None + """ + The outline width of this switch's track in all or specific \ + :class:`~flet.ControlState`s. + + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, and :attr:`flet.ControlState.DEFAULT`. + """ + + thumb_icon: Optional[ControlStateValue[IconData]] = None + """ + The icon of this Switch's thumb in various :class:`~flet.ControlState`s. + + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, and :attr:`flet.ControlState.DEFAULT`. + """ + + on_change: Optional[ControlEventHandler["CupertinoSwitch"]] = None + """ + Called when the state of this switch is changed. + """ + + on_focus: Optional[ControlEventHandler["CupertinoSwitch"]] = None + """ + Called when this switch has received focus. + """ + + on_blur: Optional[ControlEventHandler["CupertinoSwitch"]] = None + """ + Called when this switch has lost focus. + """ + + on_image_error: Optional[ControlEventHandler["CupertinoSwitch"]] = None + """ + Called when :attr:`active_thumb_image_src` or :attr:`inactive_thumb_image_src` \ + fails to load. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py new file mode 100644 index 0000000000..56c14ce32f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_textfield.py @@ -0,0 +1,138 @@ +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.box import BoxShadowValue, DecorationImage +from flet.controls.gradients import Gradient +from flet.controls.material.textfield import TextField +from flet.controls.padding import Padding, PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import BlendMode + +__all__ = ["CupertinoTextField", "OverlayVisibilityMode"] + + +class OverlayVisibilityMode(Enum): + """ + Visibility of text field overlays based on the state of the current text entry. + """ + + NEVER = "never" + """ + Overlay will never appear regardless of the text entry state. + """ + + EDITING = "editing" + """ + Overlay will only appear when the current text entry is not empty. + + This includes prefilled text that the user did not type in manually. + But does not include text in placeholders. + """ + + NOT_EDITING = "notEditing" + """ + Overlay will only appear when the current text entry is empty. + + This also includes not having prefilled text that the user did not type + in manually. Texts in placeholders are ignored. + """ + + ALWAYS = "always" + """ + Always show the overlay regardless of the text entry state. + """ + + +@control("CupertinoTextField") +class CupertinoTextField(TextField): + """ + An iOS-style text field. + + ```python + ft.CupertinoTextField(placeholder_text="Search") + ``` + """ + + placeholder_text: Optional[str] = None + """ + A lighter colored placeholder hint that appears on the first line of the text \ + field when the text entry is empty. + + Defaults to an empty string. + """ + + placeholder_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for :attr:`placeholder_text`. + """ + + gradient: Optional[Gradient] = None + """ + Configures the gradient background. + """ + + blend_mode: Optional[BlendMode] = None + """ + The blend mode applied to the :attr:`~flet.FormFieldControl.bgcolor` + or :attr:`gradient` background. + """ + + shadows: Optional[BoxShadowValue] = None + """ + A list of shadows behind this text field. + """ + + prefix_visibility_mode: OverlayVisibilityMode = OverlayVisibilityMode.ALWAYS + """ + Defines the visibility of the :attr:`~flet.FormFieldControl.prefix` + control based on the state of text entry. + + Note: + Has no effect if + :attr:`~flet.FormFieldControl.prefix` + is not specified. + """ + + suffix_visibility_mode: OverlayVisibilityMode = OverlayVisibilityMode.ALWAYS + """ + Defines the visibility of the :attr:`~flet.FormFieldControl.suffix` + control based on the state of text entry. + + Note: + Has no effect if + :attr:`~flet.FormFieldControl.suffix` + is not specified. + """ + + clear_button_visibility_mode: OverlayVisibilityMode = OverlayVisibilityMode.NEVER + """ + Defines the visibility of the clear button based on the state of text entry. + + Will appear only if no + :attr:`~flet.FormFieldControl.suffix` + is provided. + """ + + clear_button_semantics_label: Optional[str] = "Clear" + """ + The semantic label for the clear button used by screen readers. + + This will be used by screen reading software to identify the clear button widget. + """ + + image: Optional[DecorationImage] = None + """ + An image to paint above the :attr:`~flet.FormFieldControl.bgcolor` + or :attr:`gradient` background. + """ + + padding: PaddingValue = field(default_factory=lambda: Padding.all(7)) + """ + The padding around the text entry area between the \ + :attr:`~flet.FormFieldControl.prefix` + and :attr:`~flet.FormFieldControl.suffix` + or the clear button when :attr:`clear_button_visibility_mode` + is not :attr:`flet.OverlayVisibilityMode.NEVER`. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py new file mode 100644 index 0000000000..e8f35c91dd --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_timer_picker.py @@ -0,0 +1,157 @@ +from dataclasses import field +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.duration import Duration, DurationValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ColorValue, Number +from flet.utils.validation import V + +__all__ = ["CupertinoTimerPicker", "CupertinoTimerPickerMode"] + + +class CupertinoTimerPickerMode(Enum): + """ + Different modes of :class:`~flet.CupertinoTimerPicker`. + """ + + HOUR_MINUTE = "hm" + """ + Mode that shows the timer duration in hour and minute. + + Examples: `16 hours | 14 min` + """ + + HOUR_MINUTE_SECONDS = "hms" + """ + Mode that shows the timer duration in hour, minute, and second. + + Examples: `16 hours | 14 min | 43 sec` + """ + + MINUTE_SECONDS = "ms" + """ + Mode that shows the timer duration in minute and second. + + Examples: `14 min | 43 sec` + """ + + +@control("CupertinoTimerPicker") +class CupertinoTimerPicker(LayoutControl): + """ + A countdown timer picker in iOS style. + + It can show a countdown duration with hour, minute and second spinners. The + duration is bound between `0` and `23` hours `59` minutes `59` seconds. + + Example: + ```python + ft.CupertinoTimerPicker(value=1000) + ``` + + """ + + value: DurationValue = field(default_factory=lambda: Duration()) + """ + The initial duration of the countdown timer. + + If specified as an integer, it will be assumed to be in seconds. + + Raises: + ValueError: If it is not greater than or equal to `0`. + ValueError: If it is not strictly less than `24` hours. + ValueError: If it is not a multiple of :attr:`minute_interval`. + ValueError: If it is not a multiple of :attr:`second_interval`. + """ + + alignment: Alignment = field(default_factory=lambda: Alignment.CENTER) + """ + Defines how this picker should be positioned within its parent. + """ + + second_interval: Annotated[ + int, + V.gt(0), + V.factor_of(60), + ] = 1 + """ + The granularity of the second spinner. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not a factor of `60`. + """ + + minute_interval: Annotated[ + int, + V.gt(0), + V.factor_of(60), + ] = 1 + """ + The granularity of the minute spinner. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not a factor of `60`. + """ + + mode: CupertinoTimerPickerMode = CupertinoTimerPickerMode.HOUR_MINUTE_SECONDS + """ + The mode of this picker. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this picker. + """ + + item_extent: Number = 32.0 + """ + The uniform height of all children. + + Raises: + ValueError: If it is not strictly greater than `0.0`. + """ + + on_change: Optional[ControlEventHandler["CupertinoTimerPicker"]] = None + """ + Called when the timer's duration changes. + + The :attr:`~flet.Event.data` property of the event + handler contains the new duration value. + Its type matches :attr:`value`: if `value` is a `Duration`, + then `data` is also a `Duration`; otherwise, it is an `int` (seconds). + """ + + def before_update(self): + super().before_update() + # normalize for use in below validation checks + value = ( + self.value + if isinstance(self.value, Duration) + else Duration(seconds=self.value) + ) + if value < Duration(): + raise ValueError("value must be a non-negative duration") + if value >= Duration(hours=24): + raise ValueError( + f"value must be strictly less than 24 hours, got {value.in_hours} hours" + ) + if self.minute_interval > 0 and value.in_minutes % self.minute_interval != 0: + raise ValueError( + f"value ({value.in_minutes} minutes) must be a multiple " + f"of minute_interval ({self.minute_interval})" + ) + if self.second_interval > 0 and value.in_seconds % self.second_interval != 0: + raise ValueError( + f"value ({value.in_seconds} seconds) must be a multiple " + f"of second_interval ({self.second_interval})" + ) + if self.item_extent <= 0: + raise ValueError( + f"item_extent must be strictly greater than 0.0, got {self.item_extent}" + ) diff --git a/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_tinted_button.py b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_tinted_button.py new file mode 100644 index 0000000000..6138b087e6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/cupertino/cupertino_tinted_button.py @@ -0,0 +1,15 @@ +from flet.controls.base_control import control +from flet.controls.cupertino.cupertino_button import CupertinoButton + +__all__ = ["CupertinoTintedButton"] + + +@control("CupertinoTintedButton") +class CupertinoTintedButton(CupertinoButton): + """ + An iOS-style button filled with default background color. + + ```python + ft.CupertinoTintedButton("Tap me") + ``` + """ diff --git a/sdk/python/packages/flet/src/flet/controls/device_info.py b/sdk/python/packages/flet/src/flet/controls/device_info.py new file mode 100644 index 0000000000..8442db5f5f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/device_info.py @@ -0,0 +1,880 @@ +from datetime import datetime +from enum import Enum +from typing import Optional + +from flet.controls.base_control import value + +__all__ = [ + "AndroidBuildVersion", + "AndroidDeviceInfo", + "DeviceInfo", + "IosDeviceInfo", + "IosUtsname", + "LinuxDeviceInfo", + "MacOsDeviceInfo", + "WebBrowserName", + "WebDeviceInfo", + "WindowsDeviceInfo", +] + +from flet.controls.types import Locale + + +@value(kw_only=True) +class DeviceInfo: + """ + Base class for device information. + + Platform-specific classes include: + - :class:`~flet.AndroidDeviceInfo` + - :class:`~flet.IosDeviceInfo` + - :class:`~flet.LinuxDeviceInfo` + - :class:`~flet.MacOsDeviceInfo` + - :class:`~flet.WebDeviceInfo` + - :class:`~flet.WindowsDeviceInfo` + """ + + locales: list[Locale] + """ + The full system-reported supported locales of the device. + + This establishes the language and formatting conventions that application + should, if possible, use to render their user interface. + + The list is ordered in order of priority, with lower-indexed locales being + preferred over higher-indexed ones. The first element is the primary locale. + + The :attr:`flet.Page.on_locale_change` event is called + whenever this value changes. + """ + + +@value(kw_only=True) +class MacOsDeviceInfo(DeviceInfo): + """ + Device information snapshot for macOS hosts. + + Returned by :meth:`flet.Page.get_device_info` when the + current platform is macOS. Includes CPU, memory, model, and OS version + fields collected from native system APIs. + """ + + active_cpus: int + """Number of active CPUs.""" + + arch: str + """Machine CPU architecture. + + Note: + Apple Silicon Macs can return `"x86_64"` if app runs via Rosetta. + """ + + computer_name: str + """Name given to the local machine.""" + + cpu_frequency: int + """Device CPU frequency.""" + + host_name: str + """Operating system type.""" + + kernel_version: str + """Machine kernel version. + + Examples: + - `"Darwin Kernel Version 15.3.0: Thu Dec 10 18:40:58 PST 2015; root:xnu-3248.30.4~1/RELEASE_X86_64"` + - `"Darwin Kernel Version 15.0.0: Wed Dec 9 22:19:38 PST 2015; root:xnu-3248.31.3~2/RELEASE_ARM64_S8000"` + """ # noqa: E501 + + major_version: int + """The major release number, such as `10` in version 10.9.3.""" + + memory_size: int + """Machine's memory size.""" + + minor_version: int + """The minor release number, such as `9` in version 10.9.3.""" + + model: str + """Device model identifier. + + For example: `"MacBookPro18,3"`, `"Mac16,2"`. + """ + + model_name: str + """Device model name. + + For example: `"MacBook Pro (16-inch, 2021)"`, `"iMac (24-inch, 2024)"`. + """ + + os_release: str + """Operating system release number.""" + + patch_version: int + """The update release number, such as `3` in `version 10.9.3`.""" + + system_guid: Optional[str] = None + """Device GUID.""" + + +class WebBrowserName(Enum): + """ + Represents commonly used browsers. + """ + + FIREFOX = "firefox" + """Mozilla Firefox""" + + SAMSUNG_INTERNET = "samsungInternet" + """Samsung Internet Browser""" + + OPERA = "opera" + """Opera Web Browser""" + + MSIE = "msie" + """Microsoft Internet Explorer""" + + EDGE = "edge" + """Microsoft Edge""" + + CHROME = "chrome" + """Google Chrome""" + + SAFARI = "safari" + """Apple Safari""" + + UNKNOWN = "unknown" + """Unknown web browser""" + + +@value(kw_only=True) +class WebDeviceInfo(DeviceInfo): + """ + Information derived from `navigator`. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator + """ + + browser_name: WebBrowserName + """The name of the browser in use.""" + + app_code_name: Optional[str] = None + """The internal 'code' name of the current browser. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/appCodeName + + Note: + Do not rely on this property to return the correct value. + """ + + app_name: Optional[str] = None + """A string with the official name of the browser. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/appName + + Note: + Do not rely on this property to return the correct value. + """ + + app_version: Optional[str] = None + """The version of the browser as a string. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/appVersion + + Note: + Do not rely on this property to return the correct value. + """ + + device_memory: Optional[float] = None + """The amount of device memory in gigabytes. + + This value is an approximation given by rounding to the nearest power of `2` and + dividing that number by `1024`. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/deviceMemory + """ + + language: Optional[str] = None + """A string representing the preferred language of the user, usually the language \ + of the browser UI. + + Will be `None` if unknown. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language + """ + + languages: Optional[list[str]] = None + """A list of strings representing the languages known to the user, by order of \ + preference. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/languages + """ + + platform: Optional[str] = None + """A string representing the platform of the browser. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform + + Note: + Do not rely on this property to return the correct value. + """ + + product: Optional[str] = None + """Always returns `"Gecko"`, on any browser. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/product + + Note: + Do not rely on this property to return the correct value. This property is + kept only for compatibility purposes. + """ + + product_sub: Optional[str] = None + """The build number of the current browser. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/productSub + + Note: + Do not rely on this property to return the correct value. + """ + + user_agent: Optional[str] = None + """The user agent string for the current browser (e.g., 'Mozilla/5.0 ...'). + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgent + """ + + vendor: Optional[str] = None + """The vendor name of the current browser. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vendor + """ + + vendor_sub: Optional[str] = None + """Returns the vendor version number (e.g., '6.1'). + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/vendorSub + + Note: + Do not rely on this property to return the correct value. + """ + + max_touch_points: Optional[int] = None + """The maximum number of simultaneous touch contact points supported by the \ + current device. + + More info: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/maxTouchPoints + """ + + hardware_concurrency: Optional[int] = None + """The number of logical processor cores available. + + More info: + https://developer.mozilla.org/en-US/docs/Web/API/Navigator/hardwareConcurrency + """ + + +@value(kw_only=True) +class AndroidBuildVersion: + """ + Android OS version details derived from `android.os.Build.VERSION`. + + This object is exposed as :attr:`flet.AndroidDeviceInfo.version`. + """ + + code_name: str + """ + The current development codename, or the string "REL" if this is a release build. + """ + + incremental: str + """ + The internal value used by the underlying source control to represent this build. + + Note: + Available only on Android M (API 23) and newer. + """ + + release: str + """The user-visible version string.""" + + sdk: int + """The user-visible SDK version of the framework. + + Possible values are defined in: + https://developer.android.com/reference/android/os/Build.VERSION_CODES.html + """ + + base_os: Optional[str] = None + """The base OS build the product is based on. + + Note: + Available only on Android M (API 23) and newer. + """ + + preview_sdk: Optional[int] = None + """The developer preview revision of a pre-release SDK.""" + + security_patch: Optional[str] = None + """The user-visible security patch level. + + Note: + Available only on Android M (API 23) and newer. + """ + + +@value(kw_only=True) +class AndroidDeviceInfo(DeviceInfo): + """ + Device information snapshot for Android devices and emulators. + + Returned by :meth:`flet.Page.get_device_info` on Android. + """ + + available_ram_size: int + """Total available RAM size in bytes.""" + + board: str + """The name of the underlying board, like `"goldfish"`. + + More info: https://developer.android.com/reference/android/os/Build#BOARD + """ + + bootloader: str + """The system bootloader version number. + + More info: https://developer.android.com/reference/android/os/Build#BOOTLOADER + """ + + brand: str + """The consumer-visible brand with which the product/hardware will be associated, \ + if any. + + More info: https://developer.android.com/reference/android/os/Build#BRAND + """ + + device: str + """The name of the industrial design. + + More info: https://developer.android.com/reference/android/os/Build#DEVICE + """ + + display: str + """A build ID string meant for displaying to the user. + + More info: https://developer.android.com/reference/android/os/Build#DISPLAY + """ + + fingerprint: str + """A string that uniquely identifies this build. + + More info: https://developer.android.com/reference/android/os/Build#FINGERPRINT + """ + + free_disk_size: int + """Free disk size in bytes.""" + + hardware: str + """The name of the hardware (from the kernel command line or /proc). + + More info: https://developer.android.com/reference/android/os/Build#HARDWARE + """ + + host: str + """Hostname. + + More info: https://developer.android.com/reference/android/os/Build#HOST + """ + + id: str + """Either a changelist number, or a label like `"M4-rc20"`. + + More info: https://developer.android.com/reference/android/os/Build#ID + """ + + is_low_ram_device: bool + """`True` if the application is running on a low-RAM device, `False` otherwise.""" + + is_physical_device: bool + """`False` if the application is running in an emulator, `True` otherwise.""" + + manufacturer: str + """The manufacturer of the product/hardware. + + More info: https://developer.android.com/reference/android/os/Build#MANUFACTURER + """ + + model: str + """The end-user-visible name for the end product. + + More info: https://developer.android.com/reference/android/os/Build#MODEL + """ + + name: str + """The name of the device.""" + + physical_ram_size: int + """Total physical RAM size in bytes.""" + + product: str + """The name of the overall product. + + More info: https://developer.android.com/reference/android/os/Build#PRODUCT + """ + + supported_32_bit_abis: list[str] + """An ordered list of 32 bit ABIs supported by this device. + Available only on Android L (API 21) and newer. + + More info: + https://developer.android.com/reference/android/os/Build#SUPPORTED_32_BIT_ABIS + """ + + supported_64_bit_abis: list[str] + """An ordered list of 64 bit ABIs supported by this device. + Available only on Android L (API 21) and newer. + + More info: + https://developer.android.com/reference/android/os/Build#SUPPORTED_64_BIT_ABIS + """ + + supported_abis: list[str] + """An ordered list of ABIs supported by this device. + Available only on Android L (API 21) and newer. + + More info: https://developer.android.com/reference/android/os/Build#SUPPORTED_ABIS + """ + + system_features: list[str] + """Describes what features are available on the current device. + + This can be used to check if the device has, for example, a front-facing + camera, or a touchscreen. However, in many cases this is not the best + API to use. For example, if you are interested in bluetooth, this API + can tell you if the device has a bluetooth radio, but it cannot tell you + if bluetooth is currently enabled, or if you have been granted the + necessary permissions to use it. Please only use this if there is no + other way to determine if a feature is supported. + + This data comes from Android's PackageManager.getSystemAvailableFeatures, + and many of the common feature strings to look for are available in + PackageManager's public documentation: + https://developer.android.com/reference/android/content/pm/PackageManager + """ + + tags: str + """Comma-separated tags describing the build, like `"unsigned,debug"`. + + More info: https://developer.android.com/reference/android/os/Build#TAGS + """ + + total_disk_size: int + """Total disk size in bytes.""" + + type: str + """The type of build, like `"user"` or `"eng"`. + + More info: https://developer.android.com/reference/android/os/Build#TYPE + """ + + version: AndroidBuildVersion + """ + Android operating system version values derived from `android.os.Build.VERSION`. + """ + + +@value(kw_only=True) +class LinuxDeviceInfo(DeviceInfo): + """ + Device information for a Linux system. + + More info: + - https://www.freedesktop.org/software/systemd/man/os-release.html + - https://www.freedesktop.org/software/systemd/man/machine-id.html + """ + + name: str + """A string identifying the operating system, without a version component, and \ + suitable for presentation to the user. + + Examples: `"Fedora"`, `"Debian GNU/Linux"`. + + If not set, defaults to `"Linux"`. + """ + + id: str + """A lower-case string identifying the operating system, excluding any version \ + information and suitable for processing by scripts or usage in generated \ + filenames. + + The ID contains no spaces or other characters outside of 0–9, a–z, '.', '_' and '-'. + + Examples: `"fedora"`, `"debian"`. + + If not set, defaults to `"linux"`. + """ + + pretty_name: str + """A pretty operating system name in a format suitable for presentation to the \ + user. May or may not contain a release code name or OS version of some kind, as \ + suitable. + + Examples: `"Fedora 17 (Beefy Miracle)"`. + + If not set, defaults to `"Linux"`. + """ + + version: Optional[str] = None + """A string identifying the operating system version, excluding any OS name \ + information, possibly including a release code name, and suitable for presentation \ + to the user. + + Examples: `"17"`, `"17 (Beefy Miracle)"`. + + May be `None` on some systems. + """ + + id_like: Optional[list[str]] = None + """A space-separated list of operating system identifiers in the same syntax as \ + the id value. It lists identifiers of operating systems that are closely related \ + to the local operating system in regards to packaging and programming interfaces, \ + for example listing one or more OS identifiers the local OS is a derivative from. + + Examples: an operating system with id `"centos"`, would list `"rhel"` + and `"fedora"`, and an operating system with id `"ubuntu"` would list `"debian"`. + + May be `None` on some systems. + """ + + version_code_name: Optional[str] = None + """A lower-case string identifying the operating system release code name, \ + excluding any OS name information or release version, and suitable for processing \ + by scripts or usage in generated filenames. + + The codename contains no spaces or other characters outside of 0–9, a–z, '.', '_' + and '-'. + + Examples: `"buster"`, `"xenial"`. + + May be `None` on some systems. + """ + + version_id: Optional[str] = None + """A lower-case string identifying the operating system version, excluding any OS \ + name information or release code name, and suitable for processing by scripts or \ + usage in generated filenames. + + The version is mostly numeric, and contains no spaces or other characters outside + of 0–9, a–z, '.', '_' and '-'. + + Examples: `"17"`, `"11.04"`. + + May be `None` on some systems. + """ + + build_id: Optional[str] = None + """A string uniquely identifying the system image used as the origin for a \ + distribution (it is not updated with system updates). The field can be identical \ + between different version_id values as build_id is only a unique identifier to a \ + specific version. + + Examples: `"2013-03-20.3"`, `"201303203"`. + + May be `None` on some systems. + """ + + variant: Optional[str] = None + """A string identifying a specific variant or edition of the operating system \ + suitable for presentation to the user. This field may be used to inform the user \ + that the configuration of this system is subject to a specific divergent set of \ + rules or default configuration settings. + + Examples: `"Server Edition"`, `"Smart Refrigerator Edition"`. + + Note: this field is for display purposes only. The variant_id field should be used + for making programmatic decisions. + + May be `None` on some systems. + """ + + variant_id: Optional[str] = None + """A lower-case string identifying a specific variant or edition of the operating \ + system. This may be interpreted in order to determine a divergent default \ + configuration. + + The variant ID contains no spaces or other characters outside of + 0–9, a–z, '.', '_' and '-'. + + Examples: `"server"`, `"embedded"`. + + May be `None` on some systems. + """ + + machine_id: Optional[str] = None + """A unique machine ID of the local system that is set during installation or \ + boot. + The machine ID is hexadecimal, 32-character, lowercase ID. When decoded from + hexadecimal, this corresponds to a 16-byte/128-bit value. + """ + + +@value(kw_only=True) +class WindowsDeviceInfo(DeviceInfo): + """ + Device information snapshot for Windows systems. + + Returned by :meth:`flet.Page.get_device_info` on Windows. + """ + + computer_name: str + """The computer's fully-qualified DNS name, where available.""" + + number_of_cores: int + """Number of CPU cores on the local machine.""" + + system_memory: int + """The physically installed memory in the computer, in megabytes. + + This may not be the same as available memory. + """ + + user_name: str + + major_version: int + """The major version number of the operating system. + + For example, for Windows 2000, the major version number is `5`. + + For more info, see the table in Remarks: + https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw#remarks + """ # noqa: E501 + + minor_version: int + """The minor version number of the operating system. + + For example, for Windows 2000, the minor version number is `0`. + + For more info, see the table in Remarks: + https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw#remarks + """ # noqa: E501 + + build_number: int + """The build number of the operating system. + + Examples: + - `22000` or greater for Windows 11. + - `10240` or greater for Windows 10. + """ + + platform_id: int + """The operating system platform. + + For Win32 on NT-based operating systems, + RtlGetVersion returns the value `VER_PLATFORM_WIN32_NT`. + """ + + csd_version: str + """The service-pack version string. + + This member contains a string, such as "Service Pack 3", + which indicates the latest service pack installed on the system. + """ + + service_pack_major: int + """The major version number of the latest service pack installed on the system. + + For example, for Service Pack 3, the major version number is three. + If no service pack has been installed, the value is zero. + """ + + service_pack_minor: int + """The minor version number of the latest service pack installed on the system. + + For example, for Service Pack 3, the minor version number is zero. + """ + + suit_mask: int + """The product suites available on the system.""" + + product_type: int + """The product type. + + This member contains additional information about the system. + """ + + reserved: int + """Reserved for future use.""" + + build_lab: str + """Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\BuildLab` registry key. + + For example: `"22000.co_release.210604-1628"`. + """ # noqa: E501 + + build_lab_ex: str + """Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\BuildLabEx` registry key. + + For example: `"22000.1.amd64free.co_release.210604-1628"`. + """ # noqa: E501 + + # digital_product_id: str + + display_version: str + """Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion` registry key. + + For example: `"21H2"`. + """ # noqa: E501 + + edition_id: str + """Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\EditionID` registry key. + """ # noqa: E501 + + install_date: datetime + """Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\InstallDate` registry key. + """ # noqa: E501 + + product_id: str + """Displayed as "Product ID" in Windows Settings. + + Value of the `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProductId` + registry key. + + For example: `"00000-00000-0000-AAAAA"`. + """ # noqa: E501 + + product_name: str + """Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProductName` registry key. + + For example: `"Windows 10 Home Single Language"`. + """ # noqa: E501 + + registered_owner: str + """Value of the `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\RegisteredOwner` registry key. + + For example: `"Microsoft Corporation"`. + """ # noqa: E501 + + release_id: str + """ + Value of the `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ReleaseId` registry key. + + For example: `"1903"`. + """ # noqa: E501 + + device_id: str + """Displayed as "Device ID" in Windows Settings. + + Value of `HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\SQMClient\\MachineId` + registry key. + """ + + +@value +class IosUtsname: + """ + Information derived from `utsname`. + + More info: http://pubs.opengroup.org/onlinepubs/7908799/xsh/sysutsname.h.html + """ + + machine: str + """Hardware type (e.g. `"iPhone7,1"` for iPhone 6 Plus).""" + + node_name: str + """Network node name.""" + + release: str + """Release level.""" + + sys_name: str + """Operating system name.""" + + version: str + """Version level.""" + + +@value(kw_only=True) +class IosDeviceInfo(DeviceInfo): + """ + Device information snapshot for iOS/iPadOS runtimes. + + Returned by :meth:`flet.Page.get_device_info` on iOS. + """ + + available_ram_size: int + """Current unallocated RAM size of the device in megabytes.""" + + free_disk_size: int + """Free disk size in bytes.""" + + is_ios_app_on_mac: bool + """Indicates whether the process is an iPhone or iPad app running on a Mac. + + More info: + https://developer.apple.com/documentation/foundation/nsprocessinfo/3608556-iosapponmac + """ # noqa: E501 + + is_physical_device: bool + """`False` if the application is running in a simulator, `True` otherwise.""" + + localized_model: str + """Localized name of the device model. + + More info: + https://developer.apple.com/documentation/uikit/uidevice/1620029-localizedmodel + """ + + model: str + """Device model according to OS. + + More info: + https://developer.apple.com/documentation/uikit/uidevice/1620044-model + """ + + model_name: str + """Commercial or user-known model name. + + For example: `"iPhone 16 Pro"`, `"iPad Pro 11-Inch 3"` + """ + + name: str + """The device name. + + Note: + - On iOS < 16 returns user-assigned device name. + - On iOS >= 16 returns a generic device name if project has + no entitlement to get user-assigned device name. + + More info: + https://developer.apple.com/documentation/uikit/uidevice/1620015-name + """ + + physical_ram_size: int + """Total physical RAM size of the device in megabytes.""" + + system_name: str + """The name of the current operating system. + + More info: + https://developer.apple.com/documentation/uikit/uidevice/1620054-systemname + """ + + system_version: str + """The current operating system version. + + More info: + https://developer.apple.com/documentation/uikit/uidevice/1620043-systemversion + """ + + total_disk_size: int + """Total disk size in bytes.""" + + utsname: IosUtsname + """Operating system information derived from `sys/utsname.h`.""" + + identifier_for_vendor: Optional[str] = None + """Unique UUID value identifying the current device. + + More info: + https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor + """ diff --git a/sdk/python/packages/flet/src/flet/controls/dialog_control.py b/sdk/python/packages/flet/src/flet/controls/dialog_control.py new file mode 100644 index 0000000000..f5186f8347 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/dialog_control.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.control_event import ControlEventHandler + + +@dataclass(kw_only=True) +class DialogControl(AdaptiveControl): + """ + A base class for dialog controls. + """ + + open: bool = False + """ + Set to `True` to display this dialog. + """ + + on_dismiss: Optional[ControlEventHandler["DialogControl"]] = None + """ + Called when dialog is dismissed. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/duration.py b/sdk/python/packages/flet/src/flet/controls/duration.py new file mode 100644 index 0000000000..e27cfb3ce9 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/duration.py @@ -0,0 +1,248 @@ +from datetime import date, datetime +from typing import Optional, Union + +from flet.controls.base_control import value +from flet.controls.types import Number + +__all__ = [ + "DateTimeValue", + "Duration", + "DurationValue", + "MICROSECONDS_PER_DAY", + "MICROSECONDS_PER_HOUR", + "MICROSECONDS_PER_MILLISECOND", + "MICROSECONDS_PER_MINUTE", + "MICROSECONDS_PER_SECOND", +] + +MICROSECONDS_PER_MILLISECOND = 1_000 +MICROSECONDS_PER_SECOND = 1_000_000 +MICROSECONDS_PER_MINUTE = 60 * MICROSECONDS_PER_SECOND +MICROSECONDS_PER_HOUR = 60 * MICROSECONDS_PER_MINUTE +MICROSECONDS_PER_DAY = 24 * MICROSECONDS_PER_HOUR + + +@value +class Duration: + """ + A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds. + + A Duration represents a difference from one point in time to another. The duration + may be "negative" if the difference is from a later time to an earlier. + """ + + microseconds: int = 0 + """ + The number of microseconds in the duration. + """ + + milliseconds: int = 0 + """ + The number of milliseconds in the duration. + """ + + seconds: int = 0 + """ + The number of seconds in the duration. + """ + + minutes: int = 0 + """ + The number of minutes in the duration. + """ + + hours: int = 0 + """ + The number of hours in the duration. + """ + + days: int = 0 + """ + The number of days in the duration. + """ + + # Class methods + + @classmethod + def from_unit( + cls, + *, + days: int = 0, + hours: int = 0, + minutes: int = 0, + seconds: int = 0, + milliseconds: int = 0, + microseconds: int = 0, + ) -> "Duration": + """Creates a Duration from individual time units.""" + total_microseconds = ( + days * MICROSECONDS_PER_DAY + + hours * MICROSECONDS_PER_HOUR + + minutes * MICROSECONDS_PER_MINUTE + + seconds * MICROSECONDS_PER_SECOND + + milliseconds * MICROSECONDS_PER_MILLISECOND + + microseconds + ) + d, rem = divmod(total_microseconds, MICROSECONDS_PER_DAY) + h, rem = divmod(rem, MICROSECONDS_PER_HOUR) + m, rem = divmod(rem, MICROSECONDS_PER_MINUTE) + s, rem = divmod(rem, MICROSECONDS_PER_SECOND) + ms, us = divmod(rem, MICROSECONDS_PER_MILLISECOND) + + return cls( + days=d, hours=h, minutes=m, seconds=s, milliseconds=ms, microseconds=us + ) + + # Properties + + @property + def in_microseconds(self) -> int: + """Returns total duration in microseconds.""" + return ( + self.microseconds + + self.milliseconds * MICROSECONDS_PER_MILLISECOND + + self.seconds * MICROSECONDS_PER_SECOND + + self.minutes * MICROSECONDS_PER_MINUTE + + self.hours * MICROSECONDS_PER_HOUR + + self.days * MICROSECONDS_PER_DAY + ) + + @property + def in_milliseconds(self) -> int: + """Returns total duration in milliseconds.""" + return self.in_microseconds // MICROSECONDS_PER_MILLISECOND + + @property + def in_seconds(self) -> int: + """Returns total duration in seconds.""" + return self.in_microseconds // MICROSECONDS_PER_SECOND + + @property + def in_minutes(self) -> int: + """Returns total duration in minutes.""" + return self.in_microseconds // MICROSECONDS_PER_MINUTE + + @property + def in_hours(self) -> int: + """Returns total duration in hours.""" + return self.in_microseconds // MICROSECONDS_PER_HOUR + + @property + def in_days(self) -> int: + """Returns total duration in days.""" + return self.in_microseconds // MICROSECONDS_PER_DAY + + @property + def is_negative(self) -> bool: + """Returns True if duration is negative.""" + return self.in_microseconds < 0 + + def abs(self) -> "Duration": + """Returns absolute (non-negative) Duration.""" + return Duration.from_unit(microseconds=abs(self.in_microseconds)) + + # Arithmetics + + def __add__(self, other: "Duration") -> "Duration": + """Adds two Duration instances.""" + if not isinstance(other, Duration): + return NotImplemented + return Duration.from_unit( + microseconds=self.in_microseconds + other.in_microseconds + ) + + def __sub__(self, other: "Duration") -> "Duration": + """Subtracts one Duration from another.""" + if not isinstance(other, Duration): + return NotImplemented + return Duration.from_unit( + microseconds=self.in_microseconds - other.in_microseconds + ) + + def __mul__(self, other: Number) -> "Duration": + """Multiplies Duration by a scalar factor.""" + if not isinstance(other, Number): + return Duration.from_unit(microseconds=round(self.in_microseconds * other)) + return NotImplemented + + def __floordiv__(self, quotient: int) -> "Duration": + """Performs floor division on Duration.""" + if quotient == 0: + raise ZeroDivisionError("Division by zero is not possible") + return Duration.from_unit(microseconds=self.in_microseconds // quotient) + + # Comparisons + + def __eq__(self, other) -> bool: + """Checks equality between Durations.""" + if not isinstance(other, Duration): + return False + return self.in_microseconds == other.in_microseconds + + def __lt__(self, other: "Duration") -> bool: + """Checks if Duration is less than another.""" + if not isinstance(other, Duration): + return False + return self.in_microseconds < other.in_microseconds + + def __le__(self, other: "Duration") -> bool: + """Checks if Duration is less than or equal to another.""" + if not isinstance(other, Duration): + return False + return self.in_microseconds <= other.in_microseconds + + def __gt__(self, other: "Duration") -> bool: + """Checks if Duration is greater than another.""" + if not isinstance(other, Duration): + return False + return self.in_microseconds > other.in_microseconds + + def __ge__(self, other: "Duration") -> bool: + """Checks if Duration is greater than or equal to another.""" + if not isinstance(other, Duration): + return False + return self.in_microseconds >= other.in_microseconds + + # Instance Methods + + def copy( + self, + *, + microseconds: Optional[int] = None, + milliseconds: Optional[int] = None, + seconds: Optional[int] = None, + minutes: Optional[int] = None, + hours: Optional[int] = None, + days: Optional[int] = None, + ) -> "Duration": + """ + Returns a copy of this `Duration` instance with the given fields replaced with \ + the new values. + """ + return Duration( + microseconds=microseconds + if microseconds is not None + else self.microseconds, + milliseconds=milliseconds + if milliseconds is not None + else self.milliseconds, + seconds=seconds if seconds is not None else self.seconds, + minutes=minutes if minutes is not None else self.minutes, + hours=hours if hours is not None else self.hours, + days=days if days is not None else self.days, + ) + + +DurationValue = Union[Duration, int] +"""Type alias for duration values. + +Represents duration as either: +- a :class:`~flet.Duration` object, +- or an integer number of milliseconds (or seconds, depending on context). +""" + +DateTimeValue = Union[datetime, date] +"""Type alias for date/time values. + +Represents either a `datetime` or a `date`. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/embed_json_encoder.py b/sdk/python/packages/flet/src/flet/controls/embed_json_encoder.py new file mode 100644 index 0000000000..d87b70a0f5 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/embed_json_encoder.py @@ -0,0 +1,57 @@ +import enum +import json + +__all__ = ["EmbedJsonEncoder"] + + +class EmbedJsonEncoder(json.JSONEncoder): + """ + JSON encoder that embeds control-like objects by serializing their `__dict__`. + """ + + def default(self, obj): + """ + Serialize an object by converting its attribute dictionary to JSON-safe values. + + Enum keys/values are converted to their raw values and `float("inf")` is + normalized to `"inf"` to avoid JSON serialization failures. + """ + obj_as_dict = self._convert_enums(obj.__dict__) + + # Convert inf to string "inf" to avoid JSON serialization error + for key, value in obj_as_dict.items(): + if value == float("inf"): + obj_as_dict[key] = "inf" + + return obj_as_dict + + def encode(self, o): + """ + Encode an object after recursively converting enum instances in mappings. + """ + return super().encode(self._convert_enums(o)) + + def _convert_enums(self, obj): + """ + Recursively convert enum keys/values to `.value` and drop `None` values. + """ + if isinstance(obj, dict): + return dict( + map( + lambda item: ( + self._convert_enums( + item[0] + if not isinstance(item[0], enum.Enum) + else item[0].value + ), + self._convert_enums( + item[1] + if not isinstance(item[1], enum.Enum) + else item[1].value + ), + ), + filter(lambda item: item[1] is not None, obj.items()), + ) + ) + else: + return obj diff --git a/sdk/python/packages/flet/src/flet/controls/events.py b/sdk/python/packages/flet/src/flet/controls/events.py new file mode 100644 index 0000000000..0fca633c95 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/events.py @@ -0,0 +1,622 @@ +from dataclasses import dataclass, field +from typing import Optional + +from flet.controls.control_event import ControlEvent, Event, EventControlType +from flet.controls.duration import Duration +from flet.controls.transform import Offset +from flet.controls.types import PointerDeviceType + +__all__ = [ + "DragDownEvent", + "DragEndEvent", + "DragStartEvent", + "DragUpdateEvent", + "ForcePressEvent", + "HoverEvent", + "LongPressDownEvent", + "LongPressEndEvent", + "LongPressMoveUpdateEvent", + "LongPressStartEvent", + "MultiTapEvent", + "PointerEvent", + "ScaleEndEvent", + "ScaleStartEvent", + "ScaleUpdateEvent", + "ScrollEvent", + "TapEvent", + "TapMoveEvent", +] + + +@dataclass(kw_only=True) +class TapEvent(Event[EventControlType]): + """ + Payload for tap press/release events. + """ + + kind: Optional[PointerDeviceType] = field( + default=None, metadata={"data_field": "k"} + ) + """ + The kind of the device that initiated the event. + """ + + local_position: Optional[Offset] = field(default=None, metadata={"data_field": "l"}) + """ + The local position at which the pointer contacted the screen. + """ + + global_position: Optional[Offset] = field( + default=None, metadata={"data_field": "g"} + ) + """ + The global position at which the pointer contacted the screen. + """ + + +@dataclass(kw_only=True) +class TapMoveEvent(Event[EventControlType]): + """ + Payload for pointer movement during a tap gesture sequence. + """ + + kind: PointerDeviceType = field(metadata={"data_field": "k"}) + """ + The kind of the device that initiated the event. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position at which the pointer is located. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The global position at which the pointer is located. + """ + + delta: Offset = field(metadata={"data_field": "d"}) + """ + The movement delta since the previous update. + """ + + +@dataclass(kw_only=True) +class MultiTapEvent(ControlEvent): + """ + Result payload for multi-touch tap detection. + """ + + correct_touches: bool = field(metadata={"data_field": "ct"}) + """ + `True` when the active touch count reaches \ + :attr:`flet.GestureDetector.multi_tap_touches`; otherwise `False` is emitted when \ + the sequence is interrupted. + """ + + +@dataclass(kw_only=True) +class LongPressDownEvent(Event[EventControlType]): + """ + Initial long-press candidate event. + + Fired when a pointer goes down and may become a long press, before the + gesture is accepted. + """ + + kind: Optional[PointerDeviceType] = field( + default=None, metadata={"data_field": "k"} + ) + """ + The kind of the device that initiated the event. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position at which the pointer contacted the screen. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The global position at which the pointer contacted the screen. + """ + + +@dataclass(kw_only=True) +class LongPressStartEvent(Event[EventControlType]): + """ + Start payload for an accepted long-press gesture. + """ + + local_position: Optional[Offset] = field(default=None, metadata={"data_field": "l"}) + """ + The local position at which the pointer initially contacted the screen. + """ + + global_position: Optional[Offset] = field( + default=None, metadata={"data_field": "g"} + ) + """ + The global position at which the pointer initially contacted the screen. + """ + + +@dataclass(kw_only=True) +class LongPressMoveUpdateEvent(Event[EventControlType]): + """ + Move update payload after long-press recognition. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The current local position of the pointer. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The current global position of the pointer. + """ + + offset_from_origin: Offset = field(metadata={"data_field": "of"}) + """ + Delta from the point where the long press started, in global coordinates. + """ + + local_offset_from_origin: Offset = field(metadata={"data_field": "lofo"}) + """ + Delta from the point where the long press started, in local coordinates. + """ + + +@dataclass(kw_only=True) +class LongPressEndEvent(Event[EventControlType]): + """ + End payload for a completed long-press gesture. + """ + + local_position: Optional[Offset] = field(default=None, metadata={"data_field": "l"}) + """ + The local position at which the pointer contacted the screen. + """ + + global_position: Optional[Offset] = field( + default=None, metadata={"data_field": "g"} + ) + """ + The global position at which the pointer lifted from the screen. + """ + + velocity: Offset = field(metadata={"data_field": "v"}) + """ + The pointer's velocity when it stopped contacting the screen, in pixels per \ + second. + + Defaults to zero if not specified in the constructor. + """ + + +@dataclass(kw_only=True) +class DragDownEvent(Event[EventControlType]): + """ + Initial contact payload for drag-capable gestures. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position at which the pointer contacted the screen. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The global position at which the pointer contacted the screen. + """ + + +@dataclass(kw_only=True) +class DragStartEvent(Event[EventControlType]): + """ + Start payload for recognized drag gestures. + """ + + kind: PointerDeviceType = field(metadata={"data_field": "k"}) + """ + The kind of the device that initiated the event. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position in the coordinate system of the event receiver at which the \ + pointer contacted the screen. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The global position at which the pointer contacted the screen. + + Defaults to the origin if not specified in the constructor. + """ + + timestamp: Optional[Duration] = field(default=None, metadata={"data_field": "ts"}) + """ + Recorded timestamp of the source pointer event that triggered the drag event. + + Could be `None` if triggered from proxied events such as accessibility. + """ + + +@dataclass(kw_only=True) +class DragUpdateEvent(Event[EventControlType]): + """ + Incremental payload for drag progress updates. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position in the coordinate system of the event receiver at which the \ + pointer contacted the screen. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The pointer's global position when it triggered this update. + """ + + local_delta: Optional[Offset] = field(default=None, metadata={"data_field": "ld"}) + """ + The amount the pointer has moved in the local coordinate space of the event \ + receiver since the start of the drag. + """ + + global_delta: Optional[Offset] = field(default=None, metadata={"data_field": "gd"}) + """ + The amount the pointer has moved in the global coordinate space since the start of \ + the drag. + """ + + primary_delta: Optional[float] = field(default=None, metadata={"data_field": "pd"}) + """ + The amount the pointer has moved along the primary axis in the coordinate space of \ + the event receiver since the previous update. + """ + + timestamp: Optional[Duration] = field(default=None, metadata={"data_field": "ts"}) + """ + Recorded timestamp of the source pointer event that triggered the drag event. + + Could be `None` if triggered from proxied events such as accessibility. + """ + + +@dataclass(kw_only=True) +class DragEndEvent(Event[EventControlType]): + """ + Completion payload for drag gestures. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position in the coordinate system of the event receiver when the drag \ + gesture has been completed. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The global position the pointer is located at when the drag gesture has been \ + completed. + """ + + velocity: Offset = field(metadata={"data_field": "v"}) + """ + The velocity vector the pointer was moving when it stopped contacting the screen, \ + in logical pixels per second. + """ + + primary_velocity: Optional[float] = field( + default=None, metadata={"data_field": "pv"} + ) + """ + The velocity the pointer was moving along the primary axis when it stopped \ + contacting the screen, in logical pixels per second. + """ + + +@dataclass(kw_only=True) +class ForcePressEvent(Event[EventControlType]): + """ + Payload for pressure-based gesture callbacks. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The local position at which the pointer applied pressure. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The global position at which the pointer applied pressure. + """ + + pressure: float = field(metadata={"data_field": "p"}) + """ + The normalized pressure value reported by the device. + """ + + +@dataclass(kw_only=True) +class ScaleStartEvent(Event[EventControlType]): + """ + Start payload for scale/transform interaction sequences. + """ + + local_focal_point: Offset = field(metadata={"data_field": "lfp"}) + """ + The initial focal point of the pointers in contact with the screen, in local \ + coordinates. + """ + + global_focal_point: Offset = field(metadata={"data_field": "gfp"}) + """ + The initial focal point of the pointers in contact with the screen, in global \ + coordinates. + """ + + pointer_count: int = field(metadata={"data_field": "pc"}) + """ + The number of pointers being tracked by the gesture recognizer. + + Typically this is the number of fingers being used to pan the + control using the gesture recognizer. + """ + + timestamp: Optional[Duration] = field(default=None, metadata={"data_field": "ts"}) + """ + Recorded timestamp of the source pointer event that triggered the scale event. + + Could be `None` if triggered from proxied events such as accessibility. + """ + + +@dataclass(kw_only=True) +class ScaleEndEvent(Event[EventControlType]): + """ + End payload for scale/transform interaction sequences. + """ + + pointer_count: int = field(metadata={"data_field": "pc"}) + """ + The number of pointers being tracked by the gesture recognizer. + + Typically this is the number of fingers being used to pan the control + using the gesture recognizer. + """ + + velocity: Offset = field(metadata={"data_field": "v"}) + """ + The velocity of the last pointer to be lifted off of the screen, in pixels per \ + second. + """ + + +@dataclass(kw_only=True) +class ScaleUpdateEvent(Event[EventControlType]): + """ + Continuous payload for scale, pan, and rotation updates. + """ + + local_focal_point: Offset = field(metadata={"data_field": "lfp"}) + """ + The focal point of the pointers in contact with the screen, in local coordinates. + """ + + global_focal_point: Offset = field(metadata={"data_field": "gfp"}) + """ + The focal point of the pointers in contact with the screen, in global coordinates. + """ + + focal_point_delta: Offset = field(metadata={"data_field": "fpd"}) + """ + The amount the gesture's focal point has moved in the coordinate space of the \ + event receiver since the previous update. + """ + + pointer_count: int = field(metadata={"data_field": "pc"}) + """ + The number of pointers being tracked by the gesture recognizer. + + Typically this is the number of fingers being used to pan the widget using the + gesture recognizer. Due to platform limitations, trackpad gestures count as two + fingers even if more than two fingers are used. + """ + + horizontal_scale: float = field(metadata={"data_field": "hs"}) + """ + The scale implied by the average distance along the horizontal axis between the \ + pointers in contact with the screen. + + This value must be greater than or equal to zero. + """ + + vertical_scale: float = field(metadata={"data_field": "vs"}) + """ + The scale implied by the average distance along the vertical axis between the \ + pointers in contact with the screen. + + This value must be greater than or equal to zero. + """ + + scale: float = field(metadata={"data_field": "s"}) + """ + The scale implied by the average distance between the pointers in contact with the \ + screen. + + This value must be greater than or equal to zero. + """ + + rotation: float = field(metadata={"data_field": "rot"}) + """ + The angle (in radians) implied by the first two pointers to enter in contact with \ + the screen. + """ + + timestamp: Optional[Duration] = field(default=None, metadata={"data_field": "ts"}) + """ + Recorded timestamp of the source pointer event that triggered the scale event. + + Could be `None` if triggered from proxied events such as accessibility. + """ + + +@dataclass(kw_only=True) +class PointerEvent(Event[EventControlType]): + """ + Low-level pointer payload with detailed device metrics. + """ + + kind: PointerDeviceType = field(metadata={"data_field": "k"}) + """ + The kind of input device for which the event was generated. + """ + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The position transformed into the event receiver's local coordinate system \ + according to transform. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + Coordinate of the position of the pointer, in logical pixels in the global \ + coordinate space. + """ + + timestamp: Duration = field(metadata={"data_field": "ts"}) + """ + Time of event dispatch, relative to an arbitrary timeline. + """ + + device: float = field(metadata={"data_field": "dev"}) + """ + Unique identifier for the pointing device, reused across interactions. + """ + + pressure: float = field(metadata={"data_field": "ps"}) + """ + The pressure of the touch. + + This value is a number ranging from 0.0, indicating a touch with no discernible + pressure, to 1.0, indicating a touch with "normal" pressure, and possibly beyond, + indicating a stronger touch. + For devices that do not detect pressure (e.g. mice), returns 1.0. + """ + + pressure_min: float = field(metadata={"data_field": "pMin"}) + """ + The minimum value that `pressure` can return for this pointer. + + For devices that do not detect pressure (e.g. mice), returns 1.0. + This will always be a number less than or equal to 1.0. + """ + + pressure_max: float = field(metadata={"data_field": "pMax"}) + """ + The maximum value that `pressure` can return for this pointer. + For devices that do not detect pressure (e.g. mice), returns 1.0. + This will always be a greater than or equal to 1.0. + """ + + distance: float = field(metadata={"data_field": "dist"}) + """ + The distance of the detected object from the input surface. + For instance, this value could be the distance of a stylus or + finger from a touch screen, in arbitrary units on an arbitrary + (not necessarily linear) scale. If the pointer is down, this is 0.0 by definition. + """ + + distance_max: float = field(metadata={"data_field": "distMax"}) + """ + The maximum value that `distance` can return for this pointer. + + If this input device cannot detect "hover touch" input events, + then this will be `0.0`. + """ + + size: float = field(metadata={"data_field": "size"}) + """ + The area of the screen being pressed. + + This value is scaled to a range between 0 and 1. + It can be used to determine fat touch events. This value is only + set on Android and is a device specific approximation within the range + of detectable values. So, for example, the value of 0.1 could mean a + touch with the tip of the finger, 0.2 a touch with full finger, + and 0.3 the full palm. + """ + + radius_major: float = field(metadata={"data_field": "rMj"}) + """ + The radius of the contact ellipse along the major axis, in logical pixels. + """ + + radius_minor: float = field(metadata={"data_field": "rMn"}) + """ + The radius of the contact ellipse along the minor axis, in logical pixels. + """ + + radius_min: float = field(metadata={"data_field": "rMin"}) + """ + The minimum value that could be reported for `radius_major` and `radius_minor` for \ + this pointer, in logical pixels. + """ + + radius_max: float = field(metadata={"data_field": "rMax"}) + """ + The maximum value that could be reported for `radius_major` and `radius_minor` for \ + this pointer, in logical pixels. + """ + + orientation: float = field(metadata={"data_field": "or"}) + """ + The orientation angle of the detected object, in radians. + """ + + tilt: float = field(metadata={"data_field": "tilt"}) + """ + The tilt angle of the detected object, in radians. + """ + + local_delta: Optional[Offset] = field(default=None, metadata={"data_field": "ld"}) + """ + The delta of the pointer's position since the event start, in logical pixels, \ + within the local coordinate space. + """ + + global_delta: Optional[Offset] = field(default=None, metadata={"data_field": "gd"}) + """ + The delta of the pointer's position since the event start, in logical pixels, \ + within the global coordinate space. + """ + + +@dataclass(kw_only=True) +class ScrollEvent(Event[EventControlType]): + """The pointer issued a scroll event.""" + + local_position: Offset = field(metadata={"data_field": "l"}) + """ + The coordinate of the position of the pointer, in logical pixels in the local \ + coordinate space. + """ + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + The coordinate of the position of the pointer, in logical pixels in the global \ + coordinate space. + """ + + scroll_delta: Offset = field(metadata={"data_field": "sd"}) + """ + The amount to scroll, in logical pixels. + """ + + +HoverEvent = PointerEvent diff --git a/sdk/python/packages/flet/src/flet/controls/exceptions.py b/sdk/python/packages/flet/src/flet/controls/exceptions.py new file mode 100644 index 0000000000..88f4440f7d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/exceptions.py @@ -0,0 +1,36 @@ +__all__ = [ + "FletException", + "FletPageDisconnectedException", + "FletUnimplementedPlatformException", + "FletUnsupportedPlatformException", +] + + +class FletException(Exception): + """ + Base class for all Flet exceptions. + + See these subclasses/implementations: + + - :class:`~flet.FletUnsupportedPlatformException` + - :class:`~flet.FletUnimplementedPlatformException` + - :class:`~flet.FletPageDisconnectedException` + """ + + +class FletUnsupportedPlatformException(FletException): + """ + Thrown by operations that are not supported on the current platform. + """ + + +class FletUnimplementedPlatformException(FletUnsupportedPlatformException): + """ + Thrown by operations that have not been implemented yet. + """ + + +class FletPageDisconnectedException(FletException): + """ + Thrown when the page is disconnected. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/geometry.py b/sdk/python/packages/flet/src/flet/controls/geometry.py new file mode 100644 index 0000000000..8130ec8aae --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/geometry.py @@ -0,0 +1,191 @@ +from typing import Optional + +from flet.controls.base_control import value +from flet.controls.transform import Offset +from flet.controls.types import Number + +__all__ = [ + "Rect", + "Size", +] + + +@value +class Size: + """ + A 2D size with width and height. + """ + + width: Number + height: Number + + @property + def aspect_ratio(self) -> float: + """Returns the aspect ratio (width / height).""" + if self.height != 0.0: + return self.width / self.height + if self.width > 0.0: + return float("inf") + if self.width < 0.0: + return float("-inf") + return 0.0 + + def is_infinite(self) -> bool: + """Checks if either dimension is infinite.""" + return self.width == float("inf") or self.height == float("inf") + + def is_finite(self) -> bool: + """Checks if both dimensions are finite.""" + return self.width != float("inf") and self.height != float("inf") + + @classmethod + def square(cls, dimension: Number) -> "Size": + """ + Creates a square `Size` where :attr:`width` + and :attr:`height` are the same. + """ + return Size(dimension, dimension) + + @classmethod + def from_width(cls, width: Number) -> "Size": + """ + Creates a `Size` with the given :attr:`width` + and an infinite :attr:`height`. + """ + return Size(width, float("inf")) + + @classmethod + def from_height(cls, height: Number) -> "Size": + """ + Creates a `Size` with the given :attr:`height` + and an infinite :attr:`width`. + """ + return Size(float("inf"), height) + + @classmethod + def from_radius(cls, radius: Number) -> "Size": + """ + Creates a square `Size` whose :attr:`width` and + :attr:`height` are twice the given radius. + """ + return Size(radius * 2.0, radius * 2.0) + + @classmethod + def zero(cls): + """ + Creates a `Size` whose :attr:`width` and :attr:`height` are both `0.0`. + """ + return Size(0.0, 0.0) + + @classmethod + def infinite(cls): + """ + Creates a `Size` whose :attr:`width` and + :attr:`height` are both positive infinity. + """ + return Size(float("inf"), float("inf")) + + def copy( + self, + *, + width: Optional[Number] = None, + height: Optional[Number] = None, + ) -> "Size": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Size( + width=width if width is not None else self.width, + height=height if height is not None else self.height, + ) + + +@value +class Rect: + """ + A 2D, axis-aligned, floating-point rectangle whose coordinates are relative to a \ + given origin. + """ + + left: Number + """The offset of the left edge of this rectangle from the x-axis.""" + + top: Number + """The offset of the top edge of this rectangle from the y-axis.""" + + right: Number + """The offset of the right edge of this rectangle from the x-axis.""" + + bottom: Number + """The offset of the bottom edge of this rectangle from the y-axis.""" + + @property + def width(self) -> Number: + """The distance between the left and right edges of this rectangle.""" + return self.right - self.left + + @property + def height(self) -> Number: + """The distance between the top and bottom edges of this rectangle.""" + return self.bottom - self.top + + def copy( + self, + *, + left: Optional[Number] = None, + top: Optional[Number] = None, + right: Optional[Number] = None, + bottom: Optional[Number] = None, + ) -> "Rect": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Rect( + left=left if left is not None else self.left, + top=top if top is not None else self.top, + right=right if right is not None else self.right, + bottom=bottom if bottom is not None else self.bottom, + ) + + @property + def size(self) -> Size: + """ + The distance between the upper-left corner and the lower-right corner of this \ + rectangle. + """ + return Size(self.width, self.height) + + @classmethod + def from_lwth( + cls, *, left: Number, top: Number, width: Number, height: Number + ) -> "Rect": + """ + Construct a rectangle from its left and top edges, its width, and its height. + """ + return Rect(left, top, left + width, top + height) + + @classmethod + def from_center(cls, *, center: Offset, width: Number, height: Number): + """ + Constructs a rectangle from its center point, width, and height. + The `center` argument is assumed to be an offset from the origin. + """ + return Rect( + center.x - width / 2, + center.y - height / 2, + center.x + width / 2, + center.y + height / 2, + ) + + @classmethod + def from_points(cls, a: Offset, b: Offset): + """ + Construct the smallest rectangle that encloses the given offsets, treating \ + them as vectors from the origin. + """ + return Rect( + min(a.x, b.x), + min(a.y, b.y), + max(a.x, b.x), + max(a.y, b.y), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/gradients.py b/sdk/python/packages/flet/src/flet/controls/gradients.py new file mode 100644 index 0000000000..12f1d86a71 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/gradients.py @@ -0,0 +1,202 @@ +import math +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import value + +__all__ = [ + "Gradient", + "GradientTileMode", + "LinearGradient", + "RadialGradient", + "SweepGradient", +] + +from flet.controls.types import Number + + +class GradientTileMode(Enum): + """ + Defines what happens at the edge of a gradient. + More information about GradientTileMode + [here](https://api.flutter.dev/flutter/dart-ui/TileMode.html). + """ + + CLAMP = "clamp" + """ + Samples beyond the edge are clamped to the nearest color in the defined inner \ + area. + More information + [here](https://api.flutter.dev/flutter/dart-ui/TileMode.html#clamp). + """ + + DECAL = "decal" + """ + Samples beyond the edge are treated as transparent black. + More information + [here](https://api.flutter.dev/flutter/dart-ui/TileMode.html#decal). + """ + + MIRROR = "mirror" + """ + Samples beyond the edge are mirrored back and forth across the defined area. + More information + [here](https://api.flutter.dev/flutter/dart-ui/TileMode.html#mirror). + """ + + REPEATED = "repeated" + """ + Samples beyond the edge are repeated from the far end of the defined area. + More information + [here](https://api.flutter.dev/flutter/dart-ui/TileMode.html#repeated). + """ + + +@value +class Gradient: + """ + A shader that renders a color gradient. + + There are several types of gradients: + + - `LinearGradient` + - `RadialGradient` + - `SweepGradient` + """ + + colors: list[str] + """ + The colors the gradient should obtain at each of the stops. This list must contain \ + at least two colors. + + If :attr:`stops` is provided, this list must have the same length as it. + """ + + tile_mode: GradientTileMode = GradientTileMode.CLAMP + """ + How this gradient should tile the plane beyond in the region before `begin` and \ + after `end`. + """ + + rotation: Optional[Number] = None + """ + The rotation of the gradient in [radians](https://en.wikipedia.org/wiki/Radian), \ + around the center-point of its bounding box. + """ + + stops: Optional[list[Number]] = None + """ + A list of values from `0.0` to `1.0` that denote fractions along the gradient. + + If provided, this list must have the same length as :attr:`colors`. + If the first value is not `0.0`, then a stop with position `0.0` and a + color equal to the first color in :attr:`colors` is implied. + If the last value is not `1.0`, then a stop with position `1.0` + and a color equal to the last color in :attr:`colors` is implied. + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + + +@value +class LinearGradient(Gradient): + """ + Creates a linear gradient from `begin` to `end`. + + More information on + [here](https://api.flutter.dev/flutter/painting/LinearGradient-class.html). + """ + + begin: Alignment = field(default_factory=lambda: Alignment.CENTER_LEFT) + """ + The offset at which stop `0.0` of the gradient is placed. + """ + + end: Alignment = field(default_factory=lambda: Alignment.CENTER_RIGHT) + """ + The offset at which stop `1.0` of the gradient is placed. + """ + + def __post_init__(self): + self._type = "linear" + + +@value +class RadialGradient(Gradient): + """ + Creates a radial gradient centered at center that ends at radius distance from the \ + center. + + More information + [here](https://api.flutter.dev/flutter/painting/RadialGradient-class.html). + """ + + center: Alignment = field(default_factory=lambda: Alignment.CENTER) + """ + The center of the gradient, as an offset into the `(-1.0, -1.0)` x `(1.0, 1.0)` \ + square describing the gradient which will be mapped onto the paint box. + For example, an alignment of `(0.0, 0.0)` will place the radial + gradient in the center of the box. + """ + + radius: Number = 0.5 + """ + The radius of the gradient, as a fraction of the shortest side of the paint box. + For example, if a radial gradient is painted on a box that is `100.0` pixels wide + and `200.0` pixels tall, then a radius of `1.0` will place the `1.0` stop at + `100.0` pixels from the :attr:`center`. + """ + + focal: Optional[Alignment] = None + """ + The focal point of the gradient. If specified, the gradient will appear to be \ + focused along the vector from :attr:`center` to focal. + """ + + focal_radius: Number = 0.0 + """ + The radius of the focal point of gradient, as a fraction of the shortest side of \ + the paint box. For example, if a radial gradient is painted on a box that is \ + `100.0` pixels wide and `200.0` pixels tall, then a radius of `1.0` will place the \ + `1.0` stop at `100.0` pixels from the focal point. + """ + + def __post_init__(self): + self._type = "radial" + + +@value +class SweepGradient(Gradient): + """ + Creates a sweep gradient centered at center that starts at `start_angle` and ends \ + at `end_angle`. + + More information + [here](https://api.flutter.dev/flutter/painting/SweepGradient-class.html). + """ + + center: Alignment = field(default_factory=lambda: Alignment.CENTER) + """ + The center of the gradient, as an offset into the `(-1.0, -1.0)` x `(1.0, 1.0)` \ + square describing the gradient which will be mapped onto the paint box. + + For example, an :attr:`flet.Alignment.CENTER` will place the sweep gradient + in the center of the box. + """ + + start_angle: Number = 0.0 + """ + The angle in [radians](https://en.wikipedia.org/wiki/Radian) at which stop `0.0` \ + of the gradient is placed. + """ + + end_angle: Number = math.pi * 2 + """ + The angle in [radians](https://en.wikipedia.org/wiki/Radian) at which stop `1.0` \ + of the gradient is placed. + """ + + def __post_init__(self): + self._type = "sweep" diff --git a/sdk/python/packages/flet/src/flet/controls/icon_data.py b/sdk/python/packages/flet/src/flet/controls/icon_data.py new file mode 100644 index 0000000000..ddc69a3827 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/icon_data.py @@ -0,0 +1,78 @@ +import random +from enum import IntEnum +from typing import Optional, TypeVar + +__all__ = ["IconData"] + +T = TypeVar("T", bound="IconData") + + +class IconData(IntEnum): + """ + Represents an icon used in the UI. + + An icon can come from: + + - the Material icon set via the `Icons` icon collection, + - the Cupertino icon set via the `CupertinoIcons` icon collection, + - or a custom icon set defined by the developer. + + Internally, an icon is stored as an integer that encodes icon's index + in its originating code set. + + Encoding structure: + + - Lower 16 bits (bits 0-15): the icon's index. + - Third byte (bits 16-24): the icon set identifier (set ID), + which distinguishes between icon sets like Material, Cupertino, etc. + + This encoding scheme allows a single integer to uniquely represent any icon + across multiple icon sets. + """ + + def __new__(cls: type[T], value: int) -> T: + """ + Create a new IconData enum member. + + Args: + value: The encoded integer representing the icon. + + Returns: + An instance of the enum with the encoded value. + """ + obj = int.__new__(cls, value) + obj._value_ = value + return obj + + @classmethod + def __init_subclass__(cls, **kwargs) -> None: + """ + Hook called when a subclass is defined. Used to attach metadata. + + Keyword Args: + package_name (str): The Flutter package where the icon set is defined. + class_name (str): The name of the Flutter class with icon definitions. + """ + cls._package_name = kwargs.pop("package_name", "") + cls._class_name = kwargs.pop("class_name", "") + super().__init_subclass__(**kwargs) + + @classmethod + def random( + cls: type[T], + exclude: Optional[list[T]] = None, + weights: Optional[dict[T, int]] = None, + ) -> Optional[T]: + """ + Selects a random icon from the subclass enum, with optional exclusions and \ + weights. + """ + choices = list(cls) + if exclude: + choices = [member for member in choices if member not in exclude] + if not choices: + return None + if weights: + weights_list = [weights.get(c, 1) for c in choices] + return random.choices(choices, weights=weights_list)[0] + return random.choice(choices) diff --git a/sdk/python/packages/flet/src/flet/controls/id_counter.py b/sdk/python/packages/flet/src/flet/controls/id_counter.py new file mode 100644 index 0000000000..3432ea9c49 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/id_counter.py @@ -0,0 +1,31 @@ +import itertools +import threading +from typing import Optional + +from flet.utils.locks import NopeLock +from flet.utils.platform_utils import is_pyodide + + +class IdCounter: + """ + Thread-safe incremental id generator used for runtime control identifiers. + """ + + def __init__( + self, start: int = 1, step: int = 1, lock: Optional[threading.Lock] = None + ): + self._counter = itertools.count(start, step) + self._lock = lock or (NopeLock() if is_pyodide() else threading.Lock()) + + def next(self) -> int: + """ + Return the next id value from the counter. + """ + with self._lock: + return next(self._counter) + + def __call__(self) -> int: # for dataclass default_factory + return self.next() + + +ControlId = IdCounter(start=3) diff --git a/sdk/python/packages/flet/src/flet/controls/keys.py b/sdk/python/packages/flet/src/flet/controls/keys.py new file mode 100644 index 0000000000..4aff9be77c --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/keys.py @@ -0,0 +1,78 @@ +from dataclasses import field +from typing import Optional, Union + +__all__ = [ + "Key", + "KeyValue", + "ScrollKey", + "ValueKey", +] + + +def _lazy_value(cls=None, **kwargs): + """Deferred proxy for ``value`` to avoid circular import with base_control.""" + from flet.controls.base_control import value as _v + + if cls is not None: + return _v(cls) + if kwargs: + return _v(**kwargs) + return _v() + + +@_lazy_value +class Key: + """ + Base class for control keys. + + Concrete subclasses define `_type` and therefore behavior on the Flutter + side. Use :class:`~flet.ValueKey` for general control identity and + :class:`~flet.ScrollKey` for scroll-target lookups. + """ + + value: Union[str, int, float, bool] + """ + Stable primitive identifier used to match a control. + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + """Discriminator used on Flutter end to select the key kind.""" + + def __str__(self) -> str: + return str(self.value) + + +@_lazy_value +class ValueKey(Key): + """ + General-purpose key for control identity. + + Prefer it when you need a stable identifier across rebuilds but do not need + scroll-specific behavior. + """ + + def __post_init__(self): + self._type = "value" + + +@_lazy_value +class ScrollKey(Key): + """ + Key type used for imperative scroll targeting. + + Use this key to identify an item when calling + :meth:`flet.ScrollableControl.scroll_to` with + `scroll_key`. + """ + + def __post_init__(self): + self._type = "scroll" + + +KeyValue = Union[ValueKey, ScrollKey, str, int, float, bool] +"""Type alias for control key values. + +Represents keys as either: +- a :class:`~flet.ValueKey` or :class:`~flet.ScrollKey` object, +- or a primitive `str`, `int`, `float`, or `bool` value. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/layout_control.py b/sdk/python/packages/flet/src/flet/controls/layout_control.py new file mode 100644 index 0000000000..d7c4ba9937 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/layout_control.py @@ -0,0 +1,324 @@ +from dataclasses import dataclass, field +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.animation import AnimationValue +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ( + ControlEventHandler, + Event, + EventControlType, + EventHandler, +) +from flet.controls.margin import MarginValue +from flet.controls.transform import ( + Flip, + OffsetValue, + RotateValue, + ScaleValue, + Transform, +) +from flet.controls.types import Number +from flet.utils import deprecated_class + +__all__ = ["ConstrainedControl", "LayoutControl", "LayoutSizeChangeEvent"] + + +@dataclass +class LayoutSizeChangeEvent(Event[EventControlType]): + """ + Event fired when a control's rendered size changes after layout. + """ + + width: float = field(metadata={"data_field": "w"}) + """ + Width of the control after layout. + """ + + height: float = field(metadata={"data_field": "h"}) + """ + Height of the control after layout. + """ + + +@control(kw_only=True) +class LayoutControl(Control): + """ + Base class for visual controls that participate in page layout. + + `LayoutControl` extends :class:`~flet.Control` with common visual layout + capabilities, including: + + - explicit sizing (:attr:`width`, :attr:`height`, :attr:`aspect_ratio`); + - absolute positioning (:attr:`left`, :attr:`top`, :attr:`right`, :attr:`bottom`); + - parent-space placement (:attr:`align`, :attr:`margin`); + - 2D transforms (:attr:`rotate`, :attr:`scale`, :attr:`offset`, + :attr:`flip`, :attr:`transform`); + - implicit animations for those properties (`animate_*`); + - layout/animation lifecycle events (:attr:`on_size_change`, + :attr:`on_animation_end`). + + Use `LayoutControl` as the base for custom visual controls rendered on + the page surface. For popup controls, use :class:`~flet.DialogControl`; + for non-visual integrations, use :class:`~flet.Service`. + """ + + width: Optional[Number] = None + """ + Imposed Control width in virtual pixels. + """ + + height: Optional[Number] = None + """ + Imposed Control height in virtual pixels. + """ + + left: Optional[Number] = None + """ + The distance that the child's left edge is inset from the left of the stack. + + Note: + Effective only if this control is a descendant of one of the following: + :class:`~flet.Stack` control, :attr:`flet.Page.overlay` list. + """ + + top: Optional[Number] = None + """ + The distance that the child's top edge is inset from the top of the stack. + + Note: + Effective only if this control is a descendant of one of the following: + :class:`~flet.Stack` control, :attr:`flet.Page.overlay` list. + """ + + right: Optional[Number] = None + """ + The distance that the child's right edge is inset from the right of the stack. + + Note: + Effective only if this control is a descendant of one of the following: + :class:`~flet.Stack` control, :attr:`flet.Page.overlay` list. + """ + + bottom: Optional[Number] = None + """ + The distance that the child's bottom edge is inset from the bottom of the stack. + + Note: + Effective only if this control is a descendant of one of the following: + :class:`~flet.Stack` control, :attr:`flet.Page.overlay` list. + """ + + align: Optional[Alignment] = None + """ + Alignment of the control within its parent. + """ + + margin: Optional[MarginValue] = None + """ + Sets the margin of the control. + """ + + rotate: Optional[RotateValue] = None + """ + Transforms this control using a rotation around its center. + + The value of `rotate` property could be one of the following types: + + * `number` - a rotation in clockwise radians. Full circle `360°` is `math.pi * 2` + radians, `90°` is `pi / 2`, `45°` is `pi / 4`, etc. + * `Rotate` - allows to specify rotation `angle` as well as `alignment` - + the location of rotation center. + + Example: + ```python + ft.Image( + src="https://picsum.photos/100/100", + width=100, + height=100, + border_radius=5, + rotate=Rotate(angle=0.25 * pi, alignment=ft.Alignment.CENTER_LEFT) + ) + ``` + """ + + scale: Optional[ScaleValue] = None + """ + Scales this control along the 2D plane. Default scale factor is `1.0`, meaning \ + no-scale. + + Setting this property to `0.5`, for example, makes this control twice smaller, + while `2.0` makes it twice larger. + + Different scale multipliers can be specified for `x` and `y` axis, by setting + `Control.scale` property to an instance of `Scale` class. + Either `scale` or `scale_x` and `scale_y` could be specified, but not all of them. + + Example: + ```python + ft.Image( + src="https://picsum.photos/100/100", + width=100, + height=100, + border_radius=5, + scale=ft.Scale(scale_x=2, scale_y=0.5) + ) + ``` + """ + + offset: Optional[OffsetValue] = None + """ + Applies a translation transformation before painting the control. + + The translation is expressed as an `Offset` scaled to the control's size. + So, `Offset(x=0.25, y=0)`, for example, will result in a horizontal translation + of one quarter the width of this control. + + Example + The following example displays container at `0, 0` top left corner of a stack + as transform applies `-1 * 100, -1 * 100` (`offset * control's size`) + horizontal and vertical translations to the control: + + ```python + import flet as ft + + def main(page: ft.Page): + page.add( + ft.Stack( + width=1000, + height=1000, + controls=[ + ft.Container( + bgcolor=ft.Colors.RED, + width=100, + height=100, + left=100, + top=100, + offset=ft.Offset(-1, -1), + ) + ], + ) + ) + + ft.run(main) + ``` + """ + + flip: Optional[Flip] = None + """ + Flips this control horizontally and/or vertically. + + Set to an instance of :class:`~flet.Flip` to mirror across x-axis, y-axis, or both. + """ + + transform: Optional[Transform] = None + """ + Applies a generic matrix transform to this control. + + Set to an instance of :class:`~flet.Transform` with a recorded + :class:`~flet.Matrix4` to describe arbitrary transform sequences. + """ + aspect_ratio: Optional[Number] = None + """ + The aspect ratio of the control. + It is defined as the ratio of :attr:`width` to :attr:`height`. + + Note: + In current implementation, if :attr:`aspect_ratio` is set, :attr:`width` + and :attr:`height` on the same control are ignored for final rendered size. + """ + + animate_opacity: Optional[AnimationValue] = None + """ + Enables implicit animation of the :attr:`~flet.Control.opacity` property. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + animate_size: Optional[AnimationValue] = None + """ + TBD + """ + + animate_position: Optional[AnimationValue] = None + """ + Enables implicit animation of the positioning properties \ + (:attr:`~flet.LayoutControl.left`, :attr:`~flet.LayoutControl.right`, \ + :attr:`~flet.LayoutControl.top` and :attr:`~flet.LayoutControl.bottom`). + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + animate_align: Optional[AnimationValue] = None + """ + Enables implicit animation of the :attr:`~flet.LayoutControl.align` property. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + animate_margin: Optional[AnimationValue] = None + """ + Enables implicit animation of the :attr:`~flet.LayoutControl.margin` property. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + animate_rotation: Optional[AnimationValue] = None + """ + Enables implicit animation of the :attr:`~flet.LayoutControl.rotate` property. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + animate_scale: Optional[AnimationValue] = None + """ + Enables implicit animation of the :attr:`~flet.LayoutControl.scale` property. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + animate_offset: Optional[AnimationValue] = None + """ + Enables implicit animation of the :attr:`~flet.LayoutControl.offset` property. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + size_change_interval: int = 10 + """ + Sampling interval in milliseconds for :attr:`on_size_change` event. + + Setting to `0` calls :attr:`on_size_change` immediately + on every change. + """ + + on_size_change: Optional[EventHandler[LayoutSizeChangeEvent["LayoutControl"]]] = ( + None + ) + """ + Called when the size of this control changes. + + :attr:`size_change_interval` defines how often this event is called. + """ + + on_animation_end: Optional[ControlEventHandler["LayoutControl"]] = None + """ + Called when animation completes. + + Can be used to chain multiple animations. + + The `data` property of the event handler argument contains the name + of the animation. + + More information [here](https://flet.dev/docs/cookbook/animations). + """ + + +@deprecated_class( + reason="Inherit from LayoutControl instead.", + version="0.80.0", + delete_version="1.0", +) +class ConstrainedControl(LayoutControl): + pass diff --git a/sdk/python/packages/flet/src/flet/controls/margin.py b/sdk/python/packages/flet/src/flet/controls/margin.py new file mode 100644 index 0000000000..1eb7ceb165 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/margin.py @@ -0,0 +1,66 @@ +from typing import Union + +from flet.controls.base_control import value +from flet.controls.types import Number + +__all__ = ["Margin", "MarginValue"] + + +@value +class Margin: + """ + `Margin` class has the properties to set margins for all sides of the rectangle. + """ + + left: Number = 0 + """ + The margin applied to the left. + """ + + top: Number = 0 + """ + The margin applied to the top. + """ + + right: Number = 0 + """ + The margin applied to the right. + """ + + bottom: Number = 0 + """ + The margin applied to the bottom. + """ + + @classmethod + def all(cls, value: Number) -> "Margin": + """ + Applies the same margin to all sides. + """ + return Margin(left=value, top=value, right=value, bottom=value) + + @classmethod + def symmetric(cls, *, vertical: Number = 0, horizontal: Number = 0) -> "Margin": + """ + Applies `vertical` margin to top and bottom sides and `horizontal` margin to \ + left and right sides. + """ + return Margin(left=horizontal, top=vertical, right=horizontal, bottom=vertical) + + @classmethod + def only( + cls, *, left: Number = 0, top: Number = 0, right: Number = 0, bottom: Number = 0 + ) -> "Margin": + """ + Applies margin to the specified sides. + """ + return Margin(left=left, top=top, right=right, bottom=bottom) + + +MarginValue = Union[Number, Margin] +"""Type alias for margin values. + +Represents margin as either: +- a single numeric value applied to all sides, +- or an explicit :class:`~flet.Margin` configuration. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/material/__init__.py b/sdk/python/packages/flet/src/flet/controls/material/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py b/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py new file mode 100644 index 0000000000..9292d730c7 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/alert_dialog.py @@ -0,0 +1,255 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.dialog_control import DialogControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ClipBehavior, + ColorValue, + MainAxisAlignment, + Number, + StrOrControl, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["AlertDialog"] + + +@control("AlertDialog") +class AlertDialog(DialogControl): + """ + Can be used to inform the user about situations that require acknowledgement. + + It has an optional :attr:`title` and an optional list of :attr:`actions` . The + `title` is displayed above the :attr:`content` and the `actions` are displayed + below the `content`. + + ```python + ft.AlertDialog( + title=ft.Text("Session expired"), + content=ft.Text("Please sign in again to continue."), + actions=[ft.TextButton("Dismiss")], + open=True, + ) + ``` + """ + + content: Optional[Control] = None + """ + The content of this dialog is displayed in the center of this dialog in a lighter \ + font. + + Typically this is a :class:`~flet.Column` + that contains this dialog's :class:`~flet.Text` message. + """ + + modal: bool = False + """ + Whether dialog can be dismissed/closed by clicking the area outside of it. + """ + + title: Optional[StrOrControl] = None + """ + The title of this dialog is displayed in a large font at its top. + + Typically a :class:`~flet.Text` control. + """ + + actions: list[Control] = field(default_factory=list) + """ + A set of actions that are displayed at the bottom of this dialog. + + Typically this is a list of :class:`~flet.TextButton` controls. + + Raises: + ValueError: If none of :attr:`title`, :attr:`content`, or + :attr:`actions` are provided, as the dialog would have nothing to display. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this dialog's surface. + """ + + elevation: Optional[Number] = None + """ + Defines the elevation (z-coordinate) at which this dialog should appear. + """ + + icon: Optional[Control] = None + """ + A control that is displayed at the top of this dialog. + + Typically a :class:`~flet.Icon` control. + """ + + title_padding: Optional[PaddingValue] = None + """ + Padding around the :attr:`title`. + + If there is no title, no padding will be provided. Otherwise, this padding is used. + + Defaults to `24` pixels on the top, left, and right of the :attr:`title`. + If the :attr:`content` is not `None`, then no bottom padding + is provided (see :attr:`content_padding`). + If it is not set, then an extra `20` pixels of bottom padding is added to separate + the :attr:`title` from the :attr:`actions`. + """ + + content_padding: Optional[PaddingValue] = None + """ + Padding around the :attr:`content`. + + If there is no `content`, no padding will be provided. Otherwise, padding of `20` + pixels is provided above the content to separate the :attr:`content` from + the :attr:`title`, and padding of `24` pixels is provided on the left, right, + and bottom to separate the :attr:`content` from the other edges of this dialog. + """ + + actions_padding: Optional[PaddingValue] = None + """ + Padding around the set of :attr:`actions` at the bottom of this dialog. + + Typically used to provide padding to the button bar between the button bar and the + edges of this dialog. + + If are no actions, then no padding will be included. The padding around the button + bar defaults to zero. + """ + + actions_alignment: Optional[MainAxisAlignment] = None + """ + Defines the horizontal layout of the actions. + + Internally defaults to :attr:`flet.MainAxisAlignment.END`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of this dialog. + + If `None`, defaults to :attr:`flet.DialogTheme.shape`. + If it is also `None`, it defaults to `RoundedRectangleBorder(radius=4.0)`. + """ + + inset_padding: Optional[PaddingValue] = None + """ + Padding around this dialog itself. + + Defaults to `Padding.symmetric(vertical=40, horizontal=24)` - `40` pixels + horizontally and `24` pixels vertically outside of this dialog box. + """ + + icon_padding: Optional[PaddingValue] = None + """ + Padding around the :attr:`icon`. + """ + + action_button_padding: Optional[PaddingValue] = None + """ + The padding that surrounds each button in :attr:`actions`. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color used to paint a drop shadow under this dialog, which reflects this \ + dialog's :attr:`elevation`. + """ + + icon_color: Optional[ColorValue] = None + """ + The color for the Icon in the :attr:`icon` of this dialog. + + If `None`, :attr:`flet.DialogTheme.icon_color` is used. + If that is null, defaults to color scheme's :attr:`flet.ColorScheme.secondary` if + :attr:`flet.Theme.use_material3` is `True`, `Colors.BLACK` otherwise. + """ + + scrollable: bool = False + """ + Determines whether the :attr:`title` and :attr:`content` controls are wrapped in a \ + scrollable. + + This configuration is used when the `title` and `content` are expected to overflow. + Both `title` and `content` are wrapped in a scroll view, allowing all overflowed + content to be visible while still showing the button bar. + """ + + actions_overflow_button_spacing: Optional[Number] = None + """ + The spacing between :attr:`actions` when the `OverflowBar` switches to a column \ + layout because the actions don't fit horizontally. + + If the controls in `actions` do not fit into a single row, they are arranged into a + column. This parameter provides additional vertical space between buttons when it + does overflow. + """ + + alignment: Optional[Alignment] = None + """ + How to align this dialog. + + If `None`, then :attr:`flet.DialogTheme.alignment` is used. + If that is also `None`, the default is :attr:`flet.Alignment.CENTER`. + """ + + content_text_style: Optional[TextStyle] = None + """ + The style for the text in the :attr:`content` of this dialog. + + If `None`, :attr:`flet.DialogTheme.content_text_style` is used. + If that's is also `None`, defaults to + :attr:`flet.TextTheme.body_medium` (if :attr:`flet.Theme.use_material3` is `True`; + :attr:`flet.TextTheme.title_medium` otherwise) of + :attr:`flet.Theme.text_theme`. + """ + + title_text_style: Optional[TextStyle] = None + """ + TBD + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + Defines how the contents of this dialog are clipped (or not) to the given \ + :attr:`shape`. + """ + + semantics_label: Optional[str] = None + """ + The semantic label of this dialog used by accessibility frameworks to announce \ + screen transitions when this dialog is opened and closed. + + On iOS, if this label is not provided, a semantic label will be inferred from the + :attr:`title` if it is not `None`. + """ + + barrier_color: Optional[ColorValue] = None + """ + The color of the modal barrier below this dialog. + + If `None`, then :attr:`flet.DialogTheme.barrier_color` is used. + If that is also `None`, the default is `Colors.BLACK_54`. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.title, str) + or (isinstance(ctrl.title, Control) and ctrl.title.visible) + ) + or (isinstance(ctrl.content, Control) and ctrl.content.visible) + or any(action.visible for action in ctrl.actions) + ), + message=( + "AlertDialog has nothing to display. Provide at minimum one of the " + "following: title, content, actions" + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/app_bar.py b/sdk/python/packages/flet/src/flet/controls/material/app_bar.py new file mode 100644 index 0000000000..9c20344030 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/app_bar.py @@ -0,0 +1,219 @@ +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ClipBehavior, + ColorValue, + Number, + StrOrControl, +) +from flet.utils.validation import V + + +@control("AppBar") +class AppBar(AdaptiveControl): + """ + A material design app bar. + + Example: + ```python + ft.AppBar( + leading=ft.Icon(ft.Icons.MENU), + title=ft.Text("Dashboard"), + bgcolor=ft.Colors.SURFACE_CONTAINER, + actions=[ + ft.IconButton(ft.Icons.SEARCH), + ft.IconButton(ft.Icons.MORE_VERT), + ], + ) + ``` + """ + + leading: Optional[Control] = None + """ + A control to display before the toolbar's :attr:`title`. + + Typically an :class:`~flet.Icon` or :class:`~flet.IconButton` control. + """ + + leading_width: Optional[Number] = None + """ + Defines the width of the :attr:`leading` control. + """ + + automatically_imply_leading: bool = True + """ + Whether we should try to imply the :attr:`leading` control if it is `None`. + + - If `True` and `leading` is `None`, this app bar will automatically determine + an appropriate leading control. + - If `False` and `leading` is `None`, the space is allocated to the :attr:`title`. + - If a `leading` control is provided, this parameter has no effect. + """ + + title: Optional[StrOrControl] = None + """ + The primary Control displayed in this app bar. + + Typically a :class:`~flet.Text` + control that contains a description of the current contents of this app. + + Note: + If :attr:`flet.AdaptiveControl.adaptive` + and this app is opened on an iOS or macOS device, + this :attr:`title` control will be + automatically centered, independent of the value of :attr:`center_title`. + """ + + center_title: Optional[bool] = None + """ + Whether the :attr:`title` should be centered. + + Default value is defined by :attr:`flet.AppBarTheme.center_title` + """ + + toolbar_height: Optional[Number] = None + """ + Defines the height of the toolbar component of this app bar. + """ + + color: Optional[ColorValue] = None + """ + The default color for :class:`~flet.Text` + and :class:`~flet.Icon` controls within this app bar. + + Default color is defined by :attr:`flet.AppBarTheme.color` + """ + + bgcolor: Optional[ColorValue] = None + """ + The fill color to use for this app bar. + + Default color is defined by :attr:`flet.AppBarTheme.bgcolor` + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The app bar's elevation. + + Note: + This effect is only visible when using the Material 2 design + (when :attr:`flet.Theme.use_material3` is `False`). + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + elevation_on_scroll: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation to be used if this app bar has something scrolled underneath it. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color of the shadow below this app bar. + + A shadow is only visible and displayed if the :attr:`elevation` + is greater than zero. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + The content will be clipped (or not) according to this option. + """ + + force_material_transparency: bool = False + """ + Forces this app bar to be transparent (instead of Material's default type). + + This will also remove the visual display of :attr:`bgcolor` + and :attr:`elevation`, and affect other characteristics of this app bar. + """ + + secondary: bool = False + """ + Whether this app bar is not being displayed at the top of the screen. + """ + + title_spacing: Optional[Number] = None + """ + The spacing around :attr:`title` on the horizontal axis. + It is applied even if there are + no :attr:`leading` or :attr:`actions` controls. + + Tip: + If you want :attr:`title` to take all the space available, + set `title_spacing` to `0.0`. + """ + + exclude_header_semantics: bool = False + """ + Whether the :attr:`title` should be wrapped with header :class:`~flet.Semantics`. + """ + + actions: Optional[list[Control]] = None + """ + A list of `Control`s to display in a row after the title control. + + Typically, these controls are :class:`~flet.IconButton`s + representing common operations. For less common operations, consider using a + :class:`~flet.PopupMenuButton` as the last + action. + + Info: + If :attr:`flet.AdaptiveControl.adaptive` is `True` + and this app is opened on an iOS or macOS device, + these `actions` will be automatically placed in a + :class:`~flet.Row`. + This is because :attr:`flet.CupertinoAppBar.trailing` + (which is the counterpart property of `actions`) takes only a single `Control`. + """ + + actions_padding: Optional[PaddingValue] = None + """ + The padding between the :attr:`actions` and the end of this app bar. + """ + + toolbar_opacity: Annotated[ + Number, + V.between(0.0, 1.0), + ] = 1.0 + """ + The opacity of the toolbar. + + - `0.0`: transparent + - `1.0`: fully opaque + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ + + title_text_style: Optional[TextStyle] = None + """ + The style to be used for the :class:`~flet.Text` controls in the :attr:`title`. + """ + + toolbar_text_style: Optional[TextStyle] = None + """ + The style to be used for the :class:`~flet.Text` controls in the app bar's \ + :attr:`leading` and :attr:`actions`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of this app bar's Material as well as its shadow. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py b/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py new file mode 100644 index 0000000000..472fec76fc --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/auto_complete.py @@ -0,0 +1,94 @@ +from dataclasses import dataclass, field +from typing import Optional + +from flet import LayoutControl +from flet.controls.base_control import control, value +from flet.controls.control_event import ControlEventHandler, Event, EventHandler +from flet.controls.types import Number + +__all__ = ["AutoComplete", "AutoCompleteSelectEvent", "AutoCompleteSuggestion"] + + +@value +class AutoCompleteSuggestion: + """ + Represents a suggestion item for the :class:`~flet.AutoComplete` control. + """ + + key: str + """A unique identifier or value used for filtering and selection.""" + + value: str + """The display text shown to the user.""" + + +@dataclass +class AutoCompleteSelectEvent(Event["AutoComplete"]): + """Event representing the selection of a suggestion in the AutoComplete control.""" + + index: int + """ + The index of the selected suggestion from the corresponding \ + :attr:`flet.AutoComplete.suggestions` list. + """ + + selection: AutoCompleteSuggestion + """The selected suggestion.""" + + +@control("AutoComplete") +class AutoComplete(LayoutControl): + """ + Helps the user make a selection by entering some text and choosing from among a \ + list of displayed options. + """ + + value: str = "" + """ + Current text displayed in the input field. + + This value reflects user input even if it does not match any provided suggestion. + """ + + suggestions: list[AutoCompleteSuggestion] = field(default_factory=list) + """ + A list of :class:`~flet.AutoCompleteSuggestion` + controls representing the suggestions to be displayed. + + Note: + - A valid :class:`~flet.AutoCompleteSuggestion` must have at least a + :attr:`~flet.AutoCompleteSuggestion.key` or + :attr:`~flet.AutoCompleteSuggestion.value` specified, else it will be + ignored. If only `key` is provided, `value` will be set to `key` as + fallback and vice versa. + - The internal filtration process of the suggestions (based on their `key`s) + with respect to the user's input is case-insensitive because the + comparison is done in lowercase. + """ + + suggestions_max_height: Number = 200 + """ + The maximum - visual - height of the suggestions list. + """ + + on_select: Optional[EventHandler[AutoCompleteSelectEvent]] = None + """ + Called when a suggestion is selected. + """ + + on_change: Optional[ControlEventHandler["AutoComplete"]] = None + """ + Called when the input text changes. + """ + + @property + def selected_index(self) -> Optional[int]: + """ + The index of the (last) selected suggestion. + + It is `None` until a suggestion has been selected from the UI. + + Note: + This property is read-only. + """ + return getattr(self, "_selected_index", None) diff --git a/sdk/python/packages/flet/src/flet/controls/material/badge.py b/sdk/python/packages/flet/src/flet/controls/material/badge.py new file mode 100644 index 0000000000..eac930d9f2 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/badge.py @@ -0,0 +1,124 @@ +from typing import Optional, Union + +from flet.controls.alignment import Alignment +from flet.controls.base_control import BaseControl, control +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.transform import OffsetValue +from flet.controls.types import ColorValue, Number, StrOrControl + +__all__ = ["Badge", "BadgeValue"] + + +@control("Badge") +class Badge(BaseControl): + """ + Badges are used to show notifications, counts, or status information on navigation \ + items such as :class:`~flet.NavigationBar` or :class:`~flet.NavigationRail` \ + destinations or a button's icon. + + ```python + ft.FilledIconButton( + icon=ft.Icons.PHONE, + badge=ft.Badge(label="3"), + ) + ``` + """ + + label: Optional[StrOrControl] = None + """ + The label of this badge. + + Typically a `1` to `4` characters text. + + If the label is not provided, the badge is shown as a filled circle of + :attr:`small_size` diameter. + + If `label` is provided, it is a :class:`~flet.StadiumBorder` shaped + badge with height equal to :attr:`large_size`. + """ + + offset: Optional[OffsetValue] = None + """ + Combined with `alignment` to determine the location of the :attr:`label` relative \ + to the content. + + Note: + Has effect only used if :attr:`label` is also provided. + """ + + alignment: Optional[Alignment] = None + """ + Aligns the :attr:`~flet.Badge.label` relative to the content of the badge. + + The alignment positions the :attr:`label` in similar way + :attr:`flet.Container.content` is positioned using :attr:`flet.Container.alignment`, + except that the badge alignment is resolved as if the `label` was a + :attr:`large_size` square and :attr:`offset` is added to the result. + + Note: + Has effect only used if :attr:`label` is also provided. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of the :attr:`label`. + """ + + label_visible: bool = True + """ + Whether the :attr:`label` should be visible. + + It can be used to create a badge only shown under certain conditions. + """ + + large_size: Optional[Number] = None + """ + The badge's label height if :attr:`label` is provided. + + If the default value is overridden then it may be useful to also override + :attr:`padding` and :attr:`alignment`. + + Defaults to :attr:`flet.BadgeTheme.large_size`, or if that is `None`, + falls back to `16`. + """ + + padding: Optional[PaddingValue] = None + """ + The padding added to the :attr:`label`. + + Defaults to :attr:`flet.BadgeTheme.padding`, or if that is `None`, + falls back to `4` pixels on the left and right. + + Note: + Has effect only if :attr:`label` is not `None`. + """ + + small_size: Optional[Number] = None + """ + The badge's label diameter if :attr:`label` is not provided. + + Defaults to :attr:`flet.BadgeTheme.small_size`, or if that is `None`, + falls back to `6`. + """ + + text_color: Optional[ColorValue] = None + """ + The color of the text shown in the :attr:`label`. + + It overrides the color of the :attr:`label`'s :attr:`text_style`. + """ + + text_style: Optional[TextStyle] = None + """ + The text style to use for text in the :attr:`label`. + """ + + +BadgeValue = Union[str, Badge] +"""Type alias for badge content values. + +Represents a badge as either: +- a `str` value, rendered as a text label badge, +- or a :class:`~flet.Badge`. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/material/banner.py b/sdk/python/packages/flet/src/flet/controls/material/banner.py new file mode 100644 index 0000000000..ebf4f05dc6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/banner.py @@ -0,0 +1,154 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.dialog_control import DialogControl +from flet.controls.margin import MarginValue +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, + StrOrControl, +) +from flet.utils.validation import V + +__all__ = ["Banner"] + + +@control("Banner") +class Banner(DialogControl): + """ + A banner displays an important, succinct message, and provides actions for users \ + to address (or dismiss the banner). A user action is required for it to be \ + dismissed. + + Banners are displayed at the top of the screen, below a top app bar. They are + persistent and non-modal, allowing the user to either ignore them or interact with + them at any time. + + Example: + ```python + banner = ft.Banner( + leading=ft.Icon(ft.Icons.INFO_OUTLINED, color=ft.Colors.PRIMARY), + content=ft.Text("Backup completed successfully."), + actions=[ft.TextButton("Dismiss")], + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + open=True, + ) + page.show_dialog(banner) + ``` + """ + + content: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The content of this banner. + + Typically a :class:`~flet.Text` control. + + Raises: + ValueError: If :attr:`content` is not visible. + """ + + actions: Annotated[ + list[Control], + V.visible_controls(min_count=1), + ] + """ + The set of actions that are displayed at the bottom or trailing side of this \ + banner. + + Typically this is a list of :class:`~flet.TextButton` + controls. + + Raises: + ValueError: If it does not contain at least one visible `Control`. + """ + + leading: Optional[IconDataOrControl] = None + """ + The leading Control of this banner. + + Typically an :class:`~flet.Icon` control. + """ + + leading_padding: Optional[PaddingValue] = None + """ + The amount of space by which to inset the :attr:`leading` control. + + Defaults to :attr:`flet.BannerTheme.leading_padding`, + or if that is `None`, falls back to `Padding.only(end=16)`. + """ + + content_padding: Optional[PaddingValue] = None + """ + The amount of space by which to inset the :attr:`content`. + + If the actions are below the content, this defaults to + `Padding.only(left=16.0, top=24.0, right=16.0, bottom=4.0)`. + + If the actions are trailing the `content`, this defaults to + `Padding.only(left=16.0, top=2.0)`. + """ + + force_actions_below: bool = False + """ + An override to force the :attr:`actions` to be below the :attr:`content` \ + regardless of how many there are. + + If this is `True`, the :attr:`actions` will be placed below the content. + If this is `False`, the :attr:`actions` will be placed on the trailing side + of the :attr:`content` if `actions` length is `1` and below the `content` + if greater than `1`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color of the surface of this banner. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color of the shadow below this banner. + """ + + divider_color: Optional[ColorValue] = None + """ + The color of the divider. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation of this banner. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + margin: Optional[MarginValue] = None + """ + The amount of space surrounding this banner. + """ + + content_text_style: Optional[TextStyle] = None + """ + The style to be used for the :class:`~flet.Text` controls in the :attr:`content`. + """ + + min_action_bar_height: Number = 52.0 + """ + The minimum action bar height. + """ + + on_visible: Optional[ControlEventHandler["Banner"]] = None + """ + Called when this banner is shown or made visible for the first time. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/bottom_app_bar.py b/sdk/python/packages/flet/src/flet/controls/material/bottom_app_bar.py new file mode 100644 index 0000000000..a55811087f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/bottom_app_bar.py @@ -0,0 +1,113 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ClipBehavior, + ColorValue, + NotchShape, + Number, +) +from flet.utils.validation import V + +__all__ = ["BottomAppBar"] + + +@control("BottomAppBar") +class BottomAppBar(LayoutControl): + """ + A material design bottom app bar. + + ```python + ft.BottomAppBar( + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + content=ft.Row( + alignment=ft.MainAxisAlignment.SPACE_AROUND, + controls=[ + ft.IconButton(ft.Icons.MENU), + ft.IconButton(ft.Icons.SEARCH), + ft.IconButton(ft.Icons.SETTINGS), + ], + ), + ) + ``` + """ + + content: Optional[Control] = None + """ + The content of this bottom app bar. + """ + + bgcolor: Optional[ColorValue] = None + """ + The fill color to use for this app bar. + + If `None`, :attr:`flet.BottomAppBarTheme.bgcolor` is used; + if that is also `None`, then defaults to :attr:`flet.ColorScheme.surface`. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color of the shadow below this app bar. + + If `None`, :attr:`flet.BottomAppBarTheme.shadow_color` is used; + if that is also `None`, then defaults to :attr:`flet.Colors.TRANSPARENT`. + """ + + padding: Optional[PaddingValue] = None + """ + Empty space to inscribe inside a container decoration (background, border). + + If `None`, :attr:`flet.BottomAppBarTheme.padding` is used; + if that is also `None`, then defaults to + `Padding.symmetric(vertical=12.0, horizontal=16.0)`. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Defines how the :attr:`content` of this app bar should be clipped. + + If `None`, defaults to: + - :attr:`flet.ClipBehavior.ANTI_ALIAS` if :attr:`border_radius` + is set and not equal to :meth:`flet.BorderRadius.all`; + - Else :attr:`flet.ClipBehavior.NONE`. + """ + + shape: Optional[NotchShape] = None + """ + The notch that is made for the floating action button. + + If `None`, :attr:`flet.BottomAppBarTheme.shape` is used; + if that is also `None`, then the shape will be rectangular with no notch. + """ + + notch_margin: Number = 4.0 + """ + The margin between the :class:`~flet.FloatingActionButton` and this app bar's notch. + + Note: + Has effect only if :attr:`shape` is not `None`. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The z-coordinate at which to place this bottom app bar relative to its parent. It \ + controls the size of the shadow below this app bar. + + If `None`, :attr:`flet.BottomAppBarTheme.elevation` is used; + if that is also `None`, then defaults to `3`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The border radius to apply when clipping and painting this app bar. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/bottom_sheet.py b/sdk/python/packages/flet/src/flet/controls/material/bottom_sheet.py new file mode 100644 index 0000000000..d3d8dbc887 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/bottom_sheet.py @@ -0,0 +1,137 @@ +from typing import Annotated, Optional + +from flet.controls.animation import AnimationStyle +from flet.controls.base_control import control +from flet.controls.box import BoxConstraints +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.dialog_control import DialogControl +from flet.controls.types import ClipBehavior, ColorValue, Number +from flet.utils.validation import V + +__all__ = ["BottomSheet"] + + +@control("BottomSheet") +class BottomSheet(DialogControl): + """ + A modal bottom sheet. + + Displays a temporary surface anchored to the bottom of the + screen that presents supplemental content or actions. + Prevents interaction with the underlying app while visible. + + Example: + ```python + sheet = ft.BottomSheet( + content=ft.Column( + width=150, + alignment=ft.MainAxisAlignment.CENTER, + horizontal_alignment=ft.CrossAxisAlignment.CENTER, + controls=[ + ft.Text("Choose an option"), + ft.TextButton("Dismiss"), + ], + ) + ) + page.show_dialog(sheet) + ``` + """ + + content: Control + """ + The content of this bottom sheet. + + Tip: + Set :attr:`scrollable` `True` if this content is or contains scrollable + controls (e.g., :class:`~flet.ListView`, :class:`~flet.GridView`) or you plan to + `expand` the :attr:`content` or give it a custom height, else the bottom + sheet might ignore the custom height and stop around mid-screen. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + Defines the size of the shadow below this bottom sheet. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this bottom sheet. + """ + + dismissible: bool = True + """ + Specifies whether this bottom sheet will be dismissed when user taps on the scrim. + """ + + draggable: bool = False + """ + Specifies whether this bottom sheet can be dragged up and down and dismissed by \ + swiping downwards. + """ + + show_drag_handle: bool = False + """ + Whether to display drag handle at the top of sheet or not. + """ + + use_safe_area: bool = True + """ + Specifies whether the sheet will avoid system intrusions on the top, left, and \ + right. + """ + + scrollable: bool = False + """ + Removes the half-height cap so the sheet can grow with its content. + + Set this to `True` whenever the sheet body contains scrollable controls + (e.g., :class:`~flet.ListView`, :class:`~flet.GridView`) or you plan to `expand` the + :attr:`content` or give it a custom height, else the bottom sheet might + ignore the custom height and stop around mid-screen. + """ + + fullscreen: bool = False + """ + Expands the sheet to fill the window/page height. + + If set to `True`, :attr:`scrollable` is internally set to `True` equally, + so the sheet can grow freely to fill the page. + """ + + maintain_bottom_view_insets_padding: bool = True + """ + Adds a padding at the bottom to avoid obstructing this bottom sheet's \ + :attr:`content` with on-screen keyboard or other system elements. + """ + + animation_style: Optional[AnimationStyle] = None + """ + The animation style of this bottom sheet. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + The size constraints to apply to this bottom sheet. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Defines how the content of this bottom sheet should be clipped. + """ + + shape: Optional[OutlinedBorder] = None + """ + Defines the shape of this bottom sheet. + """ + + barrier_color: Optional[ColorValue] = None + """ + The color of the scrim that obscures content behind this bottom sheet. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/button.py b/sdk/python/packages/flet/src/flet/controls/material/button.py new file mode 100644 index 0000000000..55bca37e00 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/button.py @@ -0,0 +1,165 @@ +from dataclasses import field +from typing import Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.icon_data import IconData +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ClipBehavior, + ColorValue, + IconDataOrControl, + Number, + StrOrControl, + Url, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["Button"] + + +@control("Button") +class Button(LayoutControl, AdaptiveControl): + """ + A material button. + + It supports various styles, colors, event handlers for user interaction, + and can be used to display text, icons, etc. + + Example: + ```python + ft.Button(content="Enabled button") + ft.Button(content="Disabled button", disabled=True) + ``` + """ + + content: Optional[StrOrControl] = None + """ + The button's label. + Typically a :class:`~flet.Text` control or a string. + If a string is provided, it will be wrapped in a :class:`~flet.Text` control. + + Raises: + ValueError: If neither `content` nor :attr:`icon` + (string or visible control) is provided. + """ + + icon: Optional[IconDataOrControl] = None + """ + The icon to display inside the button. + Typically an :class:`~flet.Icon` control or an `IconData`. + If an `IconData` is provided, it will be wrapped in an :class:`~flet.Icon` control. + + Raises: + ValueError: If neither `icon` nor :attr:`content` + (string or visible control) is provided. + """ + icon_color: Optional[ColorValue] = None + """ + The color of the icon. + If not specified, defaults to the current foreground color. + """ + + color: Optional[ColorValue] = field(default=None, metadata={"skip": True}) + """ + The button's foreground color. + If not specified, defaults to the theme's primary color. + """ + + bgcolor: Optional[ColorValue] = field(default=None, metadata={"skip": True}) + """ + The button's background color. + If not specified, defaults to the theme's primary color. + """ + + elevation: Number = field(default=1, metadata={"skip": True}) + """ + The button's elevation. + If not specified, defaults to `1`. + """ + + style: Optional[ButtonStyle] = field(default=None, metadata={"skip": True}) + """ + The button's style. + """ + + autofocus: Optional[bool] = None + """ + Whether this button should be focused initially. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + The button's clip behavior. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when the button is clicked. + """ + + on_click: Optional[ControlEventHandler["Button"]] = None + """ + Called when the button is clicked. + """ + + on_long_press: Optional[ControlEventHandler["Button"]] = None + """ + Called when the button is long-pressed. + """ + + on_hover: Optional[ControlEventHandler["Button"]] = None + """ + Called when the button is hovered. + """ + + on_focus: Optional[ControlEventHandler["Button"]] = None + """ + Called when the button is focused. + """ + + on_blur: Optional[ControlEventHandler["Button"]] = None + """ + Called when the button loses focus. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.icon, IconData) + or (isinstance(ctrl.icon, Control) and ctrl.icon.visible) + ) + or ( + isinstance(ctrl.content, str) + or (isinstance(ctrl.content, Control) and ctrl.content.visible) + ) + ), + message=( + "at least icon or content (string or visible Control) must be provided" + ), + ), + ) + + def before_update(self): + super().before_update() + if ( + self.style is not None + or self.color is not None + or self.bgcolor is not None + or self.elevation != 1 + ): + self._internals["style"] = (self.style or ButtonStyle()).copy( + color=self.color, + bgcolor=self.bgcolor, + elevation=self.elevation, + ) + else: + self._internals.pop("style", None) + + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/material/card.py b/sdk/python/packages/flet/src/flet/controls/material/card.py new file mode 100644 index 0000000000..98029d0d1e --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/card.py @@ -0,0 +1,125 @@ +from enum import Enum +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ClipBehavior, ColorValue, Number + +__all__ = ["Card", "CardVariant"] + + +class CardVariant(Enum): + """ + Material card visual style preset. + + Used to define the :attr:`flet.Card.variant`. + """ + + ELEVATED = "elevated" + """ + Standard elevated card style. + """ + + FILLED = "filled" + """ + Filled card style emphasizing container color. + """ + + OUTLINED = "outlined" + """ + Outlined card style with a visible border. + """ + + +@control("Card") +class Card(LayoutControl, AdaptiveControl): + """ + A material design card: a panel with slightly rounded corners and an elevation \ + shadow. + + ```python + ft.Card( + shadow_color=ft.Colors.ON_SURFACE_VARIANT, + content=ft.Container( + width=400, + padding=10, + content=ft.ListTile( + bgcolor=ft.Colors.GREY_400, + leading=ft.Icon(ft.Icons.FOREST), + title=ft.Text("Card Name"), + ), + ), + ) + ``` + """ + + content: Optional[Control] = None + """ + The Control to display inside the card. + + Tip: + To display multiple children, wrap them in a control like :class:`~flet.Row`, + :class:`~flet.Column`, or :class:`~flet.Stack`, which accept + a `controls` list. + """ + + elevation: Optional[Number] = None + """ + The z-coordinate at which to place this card. + Defines the size of the shadow below the card. + + Defaults to :attr:`flet.CardTheme.elevation`, or if that is `None`, + falls back to `1.0`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The card's background color. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color to paint the shadow below this card. + + Defaults to :attr:`flet.CardTheme.shadow_color` + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of this card. + + Defaults to :attr:`flet.CardTheme.shape`, or if that is `None`, + falls back to `RoundedRectangleBorder(radius=12.0)`. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Defines how the :attr:`content` will be clipped. + + Defaults to :attr:`flet.CardTheme.clip_behavior`, + or if that is `None`, falls back to `ClipBehavior.NONE`. + """ + + semantic_container: bool = True + """ + Whether this card represents a single semantic container, or if it instead \ + represents a collection of individual semantic nodes (different types of content). + """ + + show_border_on_foreground: bool = True + """ + Whether the shape of the border should be painted in front of the :attr:`content` \ + or behind. + """ + + variant: CardVariant = CardVariant.ELEVATED + """ + Defines the card variant to be used. + """ + + def init(self): + super().init() + self._internals["skip_properties"] = ["margin"] diff --git a/sdk/python/packages/flet/src/flet/controls/material/checkbox.py b/sdk/python/packages/flet/src/flet/controls/material/checkbox.py new file mode 100644 index 0000000000..086edff697 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/checkbox.py @@ -0,0 +1,191 @@ +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.border import BorderSide +from flet.controls.buttons import OutlinedBorder +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + LabelPosition, + MouseCursor, + Number, + StrOrControl, + VisualDensity, +) + +__all__ = ["Checkbox"] + + +@control("Checkbox") +class Checkbox(LayoutControl, AdaptiveControl): + """ + Checkbox allows to select one or more items from a group, or switch between two \ + mutually exclusive options (checked or unchecked, on or off). + + ```python + ft.Checkbox() + ft.Checkbox(label="Checked", value=True) + ft.Checkbox(label="Disabled", disabled=True) + ``` + """ + + label: Optional[StrOrControl] = None + """ + The clickable label to display on the right of a checkbox. + """ + + value: Optional[bool] = False + """ + The value of this checkbox. + + - If `True`, this checkbox is checked. + - If `False`, this checkbox is unchecked. + - If `None` and :attr:`tristate` is `True`, this checkbox + is indeterminate (displayed as a dash). + """ + + label_position: LabelPosition = LabelPosition.RIGHT + """ + Defines on which side of the checkbox the :attr:`label` should be shown. + """ + + label_style: Optional[TextStyle] = None + """ + The :attr:`label`'s text style. + """ + + tristate: bool = False + """ + If `True` the checkbox's :attr:`value` can be `True`, `False`, or `None`. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + fill_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color that fills this checkbox in all or specific :class:`~flet.ControlState`s. + + Note: + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, and :attr:`flet.ControlState.DEFAULT`. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color of this checkbox's overlay in various :class:`~flet.ControlState` states. + + Note: + Supported states: :attr:`flet.ControlState.PRESSED`, + :attr:`flet.ControlState.SELECTED`, :attr:`flet.ControlState.HOVERED`, + :attr:`flet.ControlState.FOCUSED`, and :attr:`flet.ControlState.DEFAULT`. + """ + + check_color: Optional[ColorValue] = None + """ + The color to use for the check icon when this checkbox is checked. + """ + + active_color: Optional[ColorValue] = None + """ + The color to use when this checkbox is checked. + """ + + hover_color: Optional[ColorValue] = None + """ + The color to use when this checkbox is hovered. + """ + + focus_color: Optional[ColorValue] = None + """ + The color for the checkbox's Material when it has the input focus. + If :attr:`overlay_color` returns a non-None color in the + :attr:`flet.ControlState.FOCUSED` state, it will be used instead. + + Defaults to :attr:`flet.CheckboxTheme.overlay_color` in the + :attr:`flet.ControlState.FOCUSED` state, or if that is `None`, + falls back to :attr:`flet.Theme.focus_color`. + """ + + semantics_label: Optional[str] = None + """ + The semantic label for the checkbox that is not shown in the UI, but will be \ + announced by screen readers in accessibility modes (e.g TalkBack/VoiceOver). + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of the checkbox. + + Defaults to :attr:`flet.CheckboxTheme.shape`, or if that is `None`, + falls back to `RoundedRectangleBorder(radius=2)`. + """ + + splash_radius: Optional[Number] = None + """ + The radius of the circular Material ink response (ripple) in logical pixels. + + Defaults to :attr:`flet.CheckboxTheme.splash_radius`, + or if that is `None`, falls back to `20.0`. + """ + + border_side: Optional[ControlStateValue[BorderSide]] = None + """ + The color and width of this checkbox's border in all or specific \ + :class:`~flet.ControlState`s. + + Defaults to :attr:`flet.CheckboxTheme.border_side`, or if that is `None`, + falls back to `BorderSide` with a width of `2.0`. + + Note: + Supported states: :attr:`flet.ControlState.SELECTED`, + :attr:`flet.ControlState.HOVERED`, :attr:`flet.ControlState.DISABLED`, + :attr:`flet.ControlState.FOCUSED`, :attr:`flet.ControlState.PRESSED`, + :attr:`flet.ControlState.ERROR`, and :attr:`flet.ControlState.DEFAULT`. + """ + + error: bool = False + """ + Whether this checkbox wants to show an error state. + + If `True` this checkbox will + have a different default container color and check color. + """ + + visual_density: Optional[VisualDensity] = None + """ + Defines how compact the checkbox's layout will be. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + checkbox. + + Defaults to :attr:`flet.CheckboxTheme.mouse_cursor`, + or if that is `None`, falls back to `MouseCursor.CLICK`. + """ + + on_change: Optional[ControlEventHandler["Checkbox"]] = None + """ + Called when the state of this checkbox is changed. + """ + + on_focus: Optional[ControlEventHandler["Checkbox"]] = None + """ + Called when this checkbox has received focus. + """ + + on_blur: Optional[ControlEventHandler["Checkbox"]] = None + """ + Called when this checkbox has lost focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/chip.py b/sdk/python/packages/flet/src/flet/controls/material/chip.py new file mode 100644 index 0000000000..f14ca46169 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/chip.py @@ -0,0 +1,274 @@ +from typing import Annotated, Optional + +from flet.controls.animation import AnimationStyle +from flet.controls.base_control import control +from flet.controls.border import BorderSide +from flet.controls.box import BoxConstraints +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ClipBehavior, + ColorValue, + Number, + StrOrControl, + VisualDensity, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["Chip"] + + +@control("Chip") +class Chip(LayoutControl): + """ + Chips are compact elements that represent an attribute, text, entity, or action. + + Example: + ```python + ft.Chip( + label="Explore topics", + leading=ft.Icon(ft.Icons.EXPLORE_OUTLINED), + ) + ``` + """ + + label: StrOrControl + """ + The primary content of this chip. + + Typically a :class:`~flet.Text` control. + """ + + leading: Optional[Control] = None + """ + A `Control` to display to the left of this chip's :attr:`label`. + + Typically the leading control is an :class:`~flet.Icon` or a \ + :class:`~flet.CircleAvatar`. + """ + + selected: bool = False + """ + If :attr:`on_select` event is specified, `selected` property is used to determine \ + whether this chip is selected or not. + """ + + selected_color: Optional[ColorValue] = None + """ + The color used for this chip's background when it is selected. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + A non-negative value which defines the size of the shadow below this chip. + + Defaults to `0`. + + Raises: + ValueError: If :attr:`elevation` is negative. + """ + + bgcolor: Optional[ColorValue] = None + """ + Color to be used for the unselected, enabled chip's background. + """ + + show_checkmark: bool = True + """ + If :attr:`on_select` event is specified and chip is selected, `show_checkmark` is \ + used to determine whether or not to show a checkmark. + """ + + check_color: Optional[ColorValue] = None + """ + The color of this chip's check mark when a check mark is visible. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color used for this chip's background when the elevation is greater than `0` \ + and this chip is not selected. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of the border around this chip. + + Defaults to :attr:`flet.ChipTheme.shape`, or if that is resolves to + `None`, falls back to `RoundedRectangleBorder(radius=8)`. + """ + + padding: Optional[PaddingValue] = None + """ + The padding between the :attr:`label` and the outside shape. + + Defaults to `8` logical pixels on all sides. + """ + + delete_icon: Optional[Control] = None + """ + A `Control` to display to the right of this chip's :attr:`label` + in case :attr:`on_delete` event is specified. + """ + + delete_icon_tooltip: Optional[str] = None + """ + The text to be used for this chip's `delete_icon` tooltip. If not provided or \ + provided with an empty string, the tooltip of the delete icon will not be \ + displayed. + """ + + delete_icon_color: Optional[ColorValue] = None + """ + The color of the :attr:`delete_icon`. + """ + + disabled_color: Optional[ColorValue] = None + """ + The color used for this chip's background if it is disabled. + """ + + label_padding: Optional[PaddingValue] = None + """ + The padding around the :attr:`label`. + + By default, this is `4` logical pixels at the beginning and the end of + the :attr:`label`, and zero on `top` and `bottom`. + """ + + label_text_style: Optional[TextStyle] = None + """ + The style to be applied to this chip's :attr:`label`. + """ + + selected_shadow_color: Optional[ColorValue] = None + """ + The color used for this chip's background when the elevation is greater than `0` \ + and this chip is selected. + """ + + autofocus: bool = False + """ + Whether this chip will be selected as the initial focus. + + If there is more than one control on a page with autofocus set, + then the first one added to the page will get focus. + """ + + color: Optional[ControlStateValue[ColorValue]] = None + """ + The color that fills this chip in various :class:`~flet.ControlState`. + """ + + elevation_on_click: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation to be applied on this chip relative to its parent during the press \ + motion. This controls the size of the shadow below this chip. + + Defaults to `8.0`. + + Raises: + ValueError: If it is not greater than or equal to `0.0`. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + The content will be clipped (or not) according to this option. + """ + + visual_density: Optional[VisualDensity] = None + """ + TBD + """ + + border_side: Optional[BorderSide] = None + """ + Defines the color and weight of this chip's outline. + """ + + leading_size_constraints: Optional[BoxConstraints] = None + """ + The size constraints for the :attr:`leading` control. + + If `None`, it defaults to a minimum size of chip height or label height + (whichever is greater) and a padding of `8.0` pixels on all sides. + """ + + delete_icon_size_constraints: Optional[BoxConstraints] = None + """ + The size constraints for the :attr:`delete_icon` control. + + If `None`, it defaults to a minimum size of chip height or label height + (whichever is greater) and a padding of 8.0 pixels on all sides. + """ + + enable_animation_style: Optional[AnimationStyle] = None + """ + The animation style for the enable and disable animations. + """ + + select_animation_style: Optional[AnimationStyle] = None + """ + The animation style for the select and unselect animations. + """ + + leading_drawer_animation_style: Optional[AnimationStyle] = None + """ + The animation style for the :attr:`leading` control's animations. + """ + + delete_drawer_animation_style: Optional[AnimationStyle] = None + """ + The animation style for the :attr:`delete_icon`'s animations. + """ + + on_click: Optional[ControlEventHandler["Chip"]] = None + """ + Called when the user clicks on this chip. + + Raises: + ValueError: If specified together with :attr:`on_select`. + """ + + on_delete: Optional[ControlEventHandler["Chip"]] = None + """ + Called when the user clicks on the :attr:`delete_icon`. + """ + + on_select: Optional[ControlEventHandler["Chip"]] = None + """ + Called when the user clicks on this chip. + + It internally changes :attr:`selected` property to the opposite value. + + Raises: + ValueError: If specified together with :attr:`on_click`. + """ + + on_focus: Optional[ControlEventHandler["Chip"]] = None + """ + Called when this chip has received focus. + """ + + on_blur: Optional[ControlEventHandler["Chip"]] = None + """ + Called when this chip has lost focus. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ctrl.on_select is None or ctrl.on_click is None, + message="on_select and on_click cannot be used together", + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py b/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py new file mode 100644 index 0000000000..000cce24a6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/circle_avatar.py @@ -0,0 +1,141 @@ +from typing import Annotated, Optional, Union + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + Number, + StrOrControl, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["CircleAvatar"] + + +@control("CircleAvatar") +class CircleAvatar(LayoutControl): + """ + A circle that represents a user. + + If :attr:`foreground_image_src` fails then :attr:`background_image_src` is used, + and if this also fails, then :attr:`bgcolor` is used. + + Example: + ```python + ft.CircleAvatar( + content=ft.Text("AB"), + bgcolor=ft.Colors.PRIMARY, + color=ft.Colors.ON_PRIMARY, + ) + ``` + """ + + content: Optional[StrOrControl] = None + """ + The content of this avatar. + + Typically a :class:`~flet.Text` control. + + Tip: + If this avatar is to have an image, use :attr:`background_image_src` instead. + """ + + foreground_image_src: Optional[Union[str, bytes]] = None + """ + The source (local asset file or URL) of the foreground image in the circle. + + Fallbacks to :attr:`background_image_src`. + + Typically used as profile image. + """ + + background_image_src: Optional[Union[str, bytes]] = None + """ + The source (local asset file or URL) of the background image in the circle. + Changing the background image will cause the avatar to animate to the new image. + + If this avatar is to have the user's initials, use :attr:`content` instead. + + Typically used as a fallback image for :attr:`foreground_image_src`. + """ + + color: Optional[ColorValue] = None + """ + The default color for text in this avatar. + + Defaults to the primary text theme color if no :attr:`bgcolor` is specified. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color with which to fill the circle. + + Changing the background color will cause this avatar to animate to the new color. + """ + + radius: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The size of the avatar, expressed as the radius (half the diameter). + + If set to a non `None` value, then neither :attr:`min_radius` nor + :attr:`max_radius` may be specified. + + Raises: + ValueError: If it is not greater than or equal to `0`. + ValueError: If it is set while :attr:`min_radius` + or :attr:`max_radius` is set. + """ + + min_radius: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The minimum size of the avatar, expressed as the radius (half the diameter). + If set to a non `None` value, then :attr:`radius` must be `None` (default). + + Defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0.0`. + ValueError: If it is set while :attr:`radius` is set. + """ + + max_radius: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The maximum size of the avatar, expressed as the radius (half the diameter). + If set to a non `None` value, then :attr:`radius` must be `None` (default). + + Defaults to `float('inf')` i.e. infinity. + + Raises: + ValueError: If it is not greater than or equal to `0.0`. + ValueError: If it is set while :attr:`radius` is set. + """ + + on_image_error: Optional[ControlEventHandler["CircleAvatar"]] = None + """ + Called when an error occurs while loading the :attr:`background_image_src` or \ + :attr:`foreground_image_src`. + + The :attr:`~flet.Event.data` property of the event handler argument is + a string whose value is either `"background"` or `"foreground"` + indicating the error's origin. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ctrl.radius is None + or (ctrl.min_radius is None and ctrl.max_radius is None) + ), + message="if radius is set, min_radius and max_radius must be None", + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/container.py b/sdk/python/packages/flet/src/flet/controls/material/container.py new file mode 100644 index 0000000000..4b0c4502b4 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/container.py @@ -0,0 +1,248 @@ +from typing import TYPE_CHECKING, Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.alignment import Alignment +from flet.controls.animation import AnimationValue +from flet.controls.base_control import control +from flet.controls.blur import BlurValue +from flet.controls.border import Border +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.box import ( + BoxDecoration, + BoxShadowValue, + BoxShape, + ColorFilter, + DecorationImage, +) +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler, EventHandler +from flet.controls.events import TapEvent +from flet.controls.gradients import Gradient +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + BlendMode, + ClipBehavior, + ColorValue, + ThemeMode, + Url, +) + +__all__ = ["Container"] + +if TYPE_CHECKING: + from flet.controls.theme import Theme + + +@control("Container") +class Container(LayoutControl, AdaptiveControl): + """ + Allows to decorate a control with background color and border and position it with \ + padding, margin and alignment. + """ + + content: Optional[Control] = None + """ + The content of this container. + """ + + padding: Optional[PaddingValue] = None + """ + Empty space to inscribe inside a container decoration (background, border). The \ + child control is placed inside this padding. + """ + + alignment: Optional[Alignment] = None + """ + Defines the alignment of the :attr:`content` inside this container. + + Note: + If `alignment` is non-`None`, this container may expand to fill the + available space from its parent (before positioning its :attr:`content` + within itself according to the given `alignment`) instead of shrinking to its + :attr:`content`. If you need this container to keep a fixed size, give it + container an explicit `width` and/or `height` values, or constrain it via + its parent. + """ + + bgcolor: Optional[ColorValue] = None + """ + Defines the background color of this container. + """ + + gradient: Optional[Gradient] = None + """ + Defines the gradient background of this container. + """ + + blend_mode: Optional[BlendMode] = None + """ + The blend mode applied to the `color` or `gradient` background of the container. + + Defaults to `BlendMode.MODULATE`. + """ + + border: Optional[Border] = None + """ + A border to draw above the background color. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The border radius of this container. + """ + + shape: BoxShape = BoxShape.RECTANGLE + """ + Sets the shape of this container. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Defines how the :attr:`content` of this container is clipped. + + Defaults to `ClipBehavior.ANTI_ALIAS` if :attr:`border_radius` is not `None`; + otherwise `ClipBehavior.NONE`. + """ + + ink: bool = False + """ + `True` to produce ink ripples effect when user clicks this container. + """ + + image: Optional[DecorationImage] = None + """ + An image to paint above the `bgcolor` or `gradient`. If `shape=BoxShape.CIRCLE` \ + then this image is clipped to the circle's boundary; if `border_radius` is not \ + `None` then the image is clipped to the given radii. + """ + + ink_color: Optional[ColorValue] = None + """ + The splash color of the ink response. + """ + + animate: Optional[AnimationValue] = None + """ + Enables container "implicit" animation that gradually changes its values over a \ + period of time. + """ + + blur: Optional[BlurValue] = None + """ + Defines how Gaussian blur effect should be applied under this container. + + Example: + ```python + ft.Stack( + controls=[ + ft.Container( + content=ft.Text("Hello"), + image_src="https://picsum.photos/100/100", + width=100, + height=100, + ), + ft.Container( + width=50, + height=50, + blur=10, + bgcolor="#44CCCC00", + ), + ft.Container( + width=50, + height=50, + left=10, + top=60, + blur=(0, 10), + ), + ft.Container( + top=10, + left=60, + blur=ft.Blur(10, 0, ft.BlurTileMode.MIRROR), + width=50, + height=50, + bgcolor="#44CCCCCC", + border=ft.Border.all(2, ft.Colors.BLACK), + ), + ] + ) + ``` + """ + + shadow: Optional[BoxShadowValue] = None + """ + The shadow(s) below this container. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this container is clicked. + + Additionally, if an :attr:`on_click` callback is provided, + it is fired after that. + """ + + theme: Optional["Theme"] = None + """ + Allows setting a nested theme for all controls inside this container and down its \ + tree. + """ + + dark_theme: Optional["Theme"] = None + """ + Allows setting a nested theme to be used when in dark theme mode for all controls \ + inside the container and down its tree. + """ + + theme_mode: Optional[ThemeMode] = None + """ + "Resets" parent theme and creates a new, unique scheme for all controls inside the \ + container. Otherwise the styles defined in container's :attr:`theme` property \ + override corresponding styles from the parent, inherited theme. + + Defaults to `ThemeMode.SYSTEM`. + """ + + color_filter: Optional[ColorFilter] = None + """ + Applies a color filter to this container. + """ + + ignore_interactions: bool = False + """ + Whether to ignore all interactions with this container and its descendants. + """ + + foreground_decoration: Optional[BoxDecoration] = None + """ + The foreground decoration of this container. + """ + + on_click: Optional[ControlEventHandler["Container"]] = None + """ + Called when a user clicks the container. + + It will not be called if this container is long pressed. + """ + + on_tap_down: Optional[EventHandler[TapEvent["Container"]]] = None + """ + Called when a user clicks the container with or without a long press. + """ + + on_long_press: Optional[ControlEventHandler["Container"]] = None + """ + Called when this container is long-pressed. + """ + + on_hover: Optional[ControlEventHandler["Container"]] = None + """ + Called when a mouse pointer enters or exists the container area. + + The :attr:`~flet.Event.data` property of the event handler argument is a boolean: + `True` when the cursor enters and `False` when it exits this container. + """ + + def init(self): + super().init() + self._internals["skip_properties"] = ["width", "height", "margin"] diff --git a/sdk/python/packages/flet/src/flet/controls/material/context_menu.py b/sdk/python/packages/flet/src/flet/controls/material/context_menu.py new file mode 100644 index 0000000000..f5c7db25f6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/context_menu.py @@ -0,0 +1,202 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import Event, EventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.material.popup_menu_button import PopupMenuItem +from flet.controls.transform import Offset, OffsetValue +from flet.utils.validation import V + +__all__ = [ + "ContextMenu", + "ContextMenuDismissEvent", + "ContextMenuSelectEvent", + "ContextMenuTrigger", +] + + +class ContextMenuTrigger(Enum): + """Defines how a menu is shown for a specific mouse button.""" + + DOWN = "down" + """ + Represents a trigger mode where the menu is shown when the mouse button is pressed \ + down. + """ + + LONG_PRESS = "longPress" + """ + Represents a trigger mode where the menu is shown after a long press of the mouse \ + button. + """ + + +@dataclass(kw_only=True) +class ContextMenuDismissEvent(Event["ContextMenu"]): + """Event fired when a :class:`~flet.ContextMenu` is dismissed.""" + + global_position: Offset = field(metadata={"data_field": "g"}) + """ + Global pointer position in logical pixels. + """ + + local_position: Optional[Offset] = field(default=None, metadata={"data_field": "l"}) + """ + Local pointer position relative to the wrapped control. + """ + + button: Optional[str] = field(default=None, metadata={"data_field": "b"}) + """ + Mouse button that triggered the menu. + + If a string, can be one of: + `"primary"` (linked to :attr:`flet.ContextMenu.primary_items`), + `"secondary"` (linked to :attr:`flet.ContextMenu.secondary_items`), + or `"tertiary"` (linked to :attr:`flet.ContextMenu.tertiary_items`). + """ + + trigger: Optional[ContextMenuTrigger] = field( + default=None, metadata={"data_field": "tr"} + ) + """ + The trigger mode that opened the menu. + """ + + item_count: Optional[int] = field(default=None, metadata={"data_field": "ic"}) + """ + Total number of entries displayed in the corresponding context menu. + """ + + +@dataclass(kw_only=True) +class ContextMenuSelectEvent(ContextMenuDismissEvent): + """Event fired when a :class:`~flet.ContextMenu` item is selected.""" + + item_id: Optional[int] = field(default=None, metadata={"data_field": "id"}) + """ + Internal numeric identifier of the selected menu item. + """ + + item_index: Optional[int] = field(default=None, metadata={"data_field": "idx"}) + """ + Index of the selected menu entry within the rendered list. + """ + + @property + def item(self) -> Optional[PopupMenuItem]: + """The selected menu item.""" + return self.page.get_control(self.item_id) + + +@control("ContextMenu") +class ContextMenu(LayoutControl): + """ + Wraps its :attr:`content` and displays contextual menus for specific mouse events. + + Tip: + On web, call :meth:`~flet.BrowserContextMenu.disable` method of + :attr:`flet.Page.browser_context_menu` to suppress the default browser + context menu before relying on custom menus. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The child control that listens for mouse interaction. + + Raises: + ValueError: If not visible. + """ + + items: list[PopupMenuItem] = field(default_factory=list) + """ + A list of menu items to display in the context menu, when :meth:`open` is called. + """ + + primary_items: list[PopupMenuItem] = field(default_factory=list) + """ + A list of menu items to display in the context menu, for primary (usually left) \ + mouse button actions. + + These items are displayed when the corresponding + :attr:`primary_trigger` is activated. + """ + + secondary_items: list[PopupMenuItem] = field(default_factory=list) + """ + A list of menu items to display in the context menu for secondary (usually right) \ + mouse button actions. + + These items are displayed when the corresponding + :attr:`secondary_trigger` is activated. + """ + + tertiary_items: list[PopupMenuItem] = field(default_factory=list) + """ + A list of menu items to display in the context menu for tertiary (usually middle) \ + mouse button actions. + + These items are displayed when the corresponding + :attr:`tertiary_trigger` is activated. + """ + + primary_trigger: Optional[ContextMenuTrigger] = None + """ + Defines a trigger mode for the display of :attr:`primary_items`. + + If set to `None`, the trigger is disabled. + """ + + secondary_trigger: Optional[ContextMenuTrigger] = ContextMenuTrigger.DOWN + """ + Defines a trigger mode for the display of :attr:`secondary_items`. + + If set to `None`, the trigger is disabled. + """ + + tertiary_trigger: Optional[ContextMenuTrigger] = ContextMenuTrigger.DOWN + """ + Defines a trigger mode for the display of :attr:`tertiary_items`. + + If set to `None`, the trigger is disabled. + """ + + on_select: Optional[EventHandler[ContextMenuSelectEvent]] = None + """ + Fires when a context menu item is selected. + """ + + on_dismiss: Optional[EventHandler[ContextMenuDismissEvent]] = None + """ + Fires when the menu is dismissed without a selection, or when an attempt is made \ + to open the menu but no items are available. + """ + + async def open( + self, + global_position: Optional[OffsetValue] = None, + local_position: Optional[OffsetValue] = None, + ) -> None: + """ + Opens the context menu programmatically, and displays :attr:`items`. + + Args: + global_position: A global coordinate describing where the menu + should appear. If omitted, `local_position` or the center of the + :attr:`content` is used. + local_position: A local coordinate relative to the :attr:`content`. + When provided without `global_position`, the coordinate is translated + to global space automatically. + """ + await self._invoke_method( + "open", + { + "global_position": global_position, + "local_position": local_position, + }, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/datatable.py b/sdk/python/packages/flet/src/flet/controls/material/datatable.py new file mode 100644 index 0000000000..eed55b9029 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/datatable.py @@ -0,0 +1,563 @@ +from dataclasses import dataclass, field +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.border import Border, BorderSide +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.control import Control +from flet.controls.control_event import ( + ControlEventHandler, + Event, + EventHandler, +) +from flet.controls.control_state import ControlStateValue +from flet.controls.events import TapEvent +from flet.controls.gradients import Gradient +from flet.controls.layout_control import LayoutControl +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ClipBehavior, + ColorValue, + MainAxisAlignment, + Number, + StrOrControl, +) +from flet.utils.validation import V + + +@dataclass +class DataColumnSortEvent(Event["DataColumn"]): + """ + Event emitted when a :class:`~flet.DataColumn` requests sorting. + + This event is delivered to :attr:`flet.DataColumn.on_sort` when the user triggers + sorting from a column header. Use :attr:`column_index` and + :attr:`ascending` to update table state (for example, `sort_column_index` and + `sort_ascending` on :class:`~flet.DataTable`). + """ + + column_index: int = field(metadata={"data_field": "ci"}) + """ + Index of the column that requested sorting. + """ + + ascending: bool = field(metadata={"data_field": "asc"}) + """ + Requested sort direction: `True` for ascending, `False` for descending. + """ + + +@control("DataColumn") +class DataColumn(Control): + """ + Column configuration for a :class:`~flet.DataTable`. + """ + + label: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The column heading. + + Typically, this will be a :class:`~flet.Text` control. + It could also be an :class:`~flet.Icon` (typically using size 18), + or a combination of both in a :class:`~flet.Row`. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + numeric: bool = False + """ + Whether this column represents numeric data or not. + + The contents of cells of columns containing numeric data are right-aligned. + """ + + tooltip: Optional[str] = field(default=None, kw_only=True) + """ + The column heading's tooltip. + + This is a longer description of the column heading, for cases where the heading + might have been abbreviated to keep the column width to a reasonable size. + """ + + heading_row_alignment: Optional[MainAxisAlignment] = None + """ + Defines the horizontal layout of the label and sort indicator in the heading row. + """ + + on_sort: Optional[EventHandler[DataColumnSortEvent]] = None + """ + Called when the user asks to sort the table using this column. + + If not set, the column will not be considered sortable. + """ + + def init(self): + super().init() + self._internals["skip_properties"] = ["tooltip"] + + +@control("DataCell") +class DataCell(Control): + """ + The data for a cell of a :class:`~flet.DataTable`. + """ + + content: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The content of this cell. + + Typically a :class:`~flet.Text` control or a :class:`~flet.Dropdown` control. + + If the cell has no data, then a :class:`~flet.Text` control with placeholder text + should be provided instead, and :attr:`placeholder` should be set to + `True`. + + Tip: + To lay out multiple children, set the :attr:`content` to a + container-like control such as :class:`~flet.Row`, :class:`~flet.Column`, or + :class:`~flet.Stack`, which have a `controls` property. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + placeholder: bool = False + """ + Whether the :attr:`content` is actually a placeholder. + + If this is `True`, the default text style for the cell is changed to be appropriate + for placeholder text. + """ + + show_edit_icon: bool = False + """ + Whether to show an edit icon at the end of this cell. + + This does not make the cell actually editable; the caller must implement editing + behavior if desired (initiated from the :attr:`on_tap` callback). + + Note: + If this is set, :attr:`on_tap` should also be set, + otherwise tapping the icon will have no effect. + """ + + on_tap: Optional[ControlEventHandler["DataCell"]] = None + """ + Called if this cell is tapped. + + Note: + If this is `None` (including :attr:`on_double_tap`, :attr:`on_long_press`, + :attr:`on_tap_cancel`, :attr:`on_tap_down`), tapping this cell will + attempt to select its row (if :attr:`flet.DataRow.on_select_change` is \ + provided). + """ + + on_double_tap: Optional[ControlEventHandler["DataCell"]] = None + """ + Called when this cell is double tapped. + + Note: + If this is `None` (including :attr:`on_tap`, :attr:`on_long_press`, + :attr:`on_tap_cancel`, :attr:`on_tap_down`), tapping this cell will + attempt to select its row (if :attr:`flet.DataRow.on_select_change` is \ + provided). + """ + + on_long_press: Optional[ControlEventHandler["DataCell"]] = None + """ + Called if this cell is long-pressed. + + Note: + If this is `None` (including :attr:`on_tap`, :attr:`on_double_tap`, + :attr:`on_tap_cancel`, :attr:`on_tap_down`), tapping this cell will attempt + to select its row (if :attr:`flet.DataRow.on_select_change` is provided). + """ + + on_tap_cancel: Optional[ControlEventHandler["DataCell"]] = None + """ + Called if the user cancels a tap was started on cell. + + Note: + If this is `None` (including :attr:`on_tap`, :attr:`on_double_tap`, + :attr:`on_long_press`, :attr:`on_tap_down`), tapping this cell will + attempt to select its row (if :attr:`flet.DataRow.on_select_change` is \ + provided). + """ + + on_tap_down: Optional[EventHandler[TapEvent["DataCell"]]] = None + """ + Called if this cell is tapped down. + + Note: + If this is `None` (including :attr:`on_tap`, :attr:`on_double_tap`, + :attr:`on_long_press`, :attr:`on_tap_cancel`), tapping this cell will + attempt to select its row (if :attr:`flet.DataRow.on_select_change` is \ + provided). + """ + + +@control("DataRow") +class DataRow(Control): + """ + Row configuration and cell data for a :class:`~flet.DataTable`. + + One row configuration must be provided for each row to display in the table. + + The data for this row of the table is provided in the :attr:`cells` property. + """ + + cells: Annotated[ + list[DataCell], + V.visible_controls(min_count=1), + ] = field(default_factory=list) + """ + The data for this row: a list of :class:`~flet.DataCell` controls. + + Note: + There must be exactly as many cells as there are visible + :attr:`~flet.DataTable.columns` in the table. + + Raises: + ValueError: If it does not contain at least one visible :class:`~flet.DataCell`. + """ + + color: Optional[ControlStateValue[ColorValue]] = None + """ + The color of this row. + + By default, the color is transparent unless selected. Selected rows has a grey + translucent color. + + The effective color can depend on the :class:`~flet.ControlState` + state, if the row is selected, pressed, hovered, focused, disabled or enabled. The + color is painted as an overlay to the row. To make sure that the row's InkWell is + visible (when pressed, hovered and focused), it is recommended to use a translucent + color. + """ + + selected: bool = False + """ + Whether the row is selected. + + If `on_select_change` is non-null for any row in the table, then a checkbox is + shown at the start of each row. If the row is selected (`True`), the checkbox will + be checked and the row will be highlighted. + + Otherwise, the checkbox, if present, will not be checked. + """ + + on_long_press: Optional[ControlEventHandler["DataRow"]] = None + """ + Called when this row is long-pressed. + + If a :class:`~flet.DataCell` in the row has its :attr:`flet.DataCell.on_tap`, + :attr:`flet.DataCell.on_double_tap`, :attr:`flet.DataCell.on_long_press`, + :attr:`flet.DataCell.on_tap_cancel` or :attr:`flet.DataCell.on_tap_down` + callback defined, that callback behavior overrides the gesture behavior of the row + for that particular cell. + """ + + on_select_change: Optional[ControlEventHandler["DataRow"]] = None + """ + Called when the user selects or unselects a selectable row. + + If this is not null, then this row is selectable. The current selection state of + this row is given by selected. + + If any row is selectable, then the table's heading row will have a checkbox that + can be checked to select all selectable rows (and which is checked if all the rows + are selected), and each subsequent row will have a checkbox to toggle just that row. + + A row whose `on_select_change` callback is null is ignored for the purposes of + determining the state of the "all" checkbox, and its checkbox is disabled. + + If a :class:`~flet.DataCell` in the row has its :attr:`flet.DataCell.on_tap` + callback defined, that callback behavior overrides the gesture behavior of the + row for that particular cell. + """ + + def __contains__(self, item): + return item in self.cells + + +@control("DataTable") +class DataTable(LayoutControl): + """ + A Material Design data table. + + Example: + ```python + ft.DataTable( + columns=[ + ft.DataColumn(label=ft.Text("Name")), + ft.DataColumn(label=ft.Text("Role")), + ], + rows=[ + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Alice")), + ft.DataCell(ft.Text("Engineer")), + ] + ), + ft.DataRow( + cells=[ + ft.DataCell(ft.Text("Bob")), + ft.DataCell(ft.Text("Designer")), + ] + ), + ], + ) + ``` + + Tip: + Outgrown this table? Its beefier cousin, `DataTable2` (from the + `flet-datatable2` extension package), adds sticky headers, fixed + rows/columns, per-column widths (fixed or relative `S`/`M`/`L`), + and a few other goodies — handy for large or wide datasets. + """ + + columns: list[DataColumn] + """ + A list of :class:`~flet.DataColumn` controls describing table columns. + + Raises: + ValueError: If there are no visible :attr:`columns`. + """ + + rows: list[DataRow] = field(default_factory=list) + """ + A list of :class:`~flet.DataRow` controls defining table rows. + + Raises: + ValueError: If any visible row does not contain exactly as many visible + :class:`~flet.DataCell`s as there are visible :attr:`columns`. + """ + + sort_ascending: bool = False + """ + Whether the column mentioned in :attr:`sort_column_index`, if any, is sorted in \ + ascending order. + + If `True`, the order is ascending (meaning the rows with the smallest values for + the current sort column are first in the table). + + If `False`, the order is descending (meaning the rows with the smallest values for + the current sort column are last in the table). + """ + + show_checkbox_column: bool = False + """ + Whether the control should display checkboxes for selectable rows. + + If `True`, a checkbox will be placed at the beginning of each row that is + selectable. However, if :attr:`flet.DataRow.on_select_change` + is not set for any row, checkboxes will not be placed, even if this value is `True`. + + If `False`, all rows will not display a checkbox. + """ + + sort_column_index: Optional[int] = None + """ + The current primary sort key's column. + + If specified, indicates that the indicated column is the column by which the data + is sorted. The number must correspond to the index of the relevant column in + :attr:`columns`. + + Setting this will cause the relevant column to have a sort indicator displayed. + + When this is `None`, it implies that the table's sort order does not correspond to + any of the columns. + + Raises: + ValueError: If it is out of range relative to the visible :attr:`columns`. + """ + + show_bottom_border: bool = False + """ + Whether a border at the bottom of the table is displayed. + + By default, a border is not shown at the bottom to allow for a border around the + table defined by decoration. + """ + + border: Optional[Border] = None + """ + The border around the table. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + Border corners. + """ + + horizontal_lines: Optional[BorderSide] = None + """ + Set the color and width of horizontal lines between rows. + """ + + vertical_lines: Optional[BorderSide] = None + """ + Set the color and width of vertical lines between columns. + """ + + checkbox_horizontal_margin: Optional[Number] = None + """ + Horizontal margin around the checkbox, if it is displayed. + """ + + column_spacing: Optional[Number] = None + """ + The horizontal margin between the contents of each data column. + """ + + data_row_color: Optional[ControlStateValue[ColorValue]] = None + """ + The background color for the data rows. + + The effective background color can be made to depend on the + :class:`~flet.ControlState` state, i.e. if the row is selected, pressed, hovered, + focused, disabled or enabled. The color is painted as an overlay to the row. + To make sure that the row's InkWell is visible (when pressed, hovered and focused), + it is recommended to use a translucent background color. + """ + + data_row_min_height: Annotated[ + Optional[Number], + V.le_field("data_row_max_height"), + ] = None + """ + The minimum height of each row (excluding the row that contains column headings). + + Defaults to `48.0`. + + Raises: + ValueError: If it is not less than or equal to :attr:`data_row_max_height`. + """ + + data_row_max_height: Annotated[ + Optional[Number], + V.ge_field("data_row_min_height"), + ] = None + """ + The maximum height of each row (excluding the row that contains column headings). + Set to `float("inf")` for the height of each row to adjust automatically with its + content. + + Defaults to `48.0`. + + Raises: + ValueError: If it is not greater than or equal to :attr:`data_row_min_height`. + """ + + data_text_style: Optional[TextStyle] = None + """ + The text style of the data :attr:`rows`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color for this table. + """ + + gradient: Optional[Gradient] = None + """ + The background gradient of this table. + """ + + divider_thickness: Annotated[ + Number, + V.ge(0), + ] = 1.0 + """ + The width of the divider that appears between :attr:`rows`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + heading_row_color: Optional[ControlStateValue[ColorValue]] = None + """ + The background color for the heading row. + + The effective background color can be made to depend on the + :class:`~flet.ControlState` state, i.e. if the row is pressed, hovered, + focused when sorted. The color is painted as an overlay to the row. To make sure + that the row's InkWell is visible (when pressed, hovered and focused), it is + recommended to use a translucent color. + """ + + heading_row_height: Optional[Number] = None + """ + The height of the heading row. + """ + + heading_text_style: Optional[TextStyle] = None + """ + The text style for the heading row. + """ + + horizontal_margin: Optional[Number] = None + """ + The horizontal margin between the edges of this table and the content in the first \ + and last cells of each row. + + When a checkbox is displayed, it is also the margin between the checkbox the + content in the first data column. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + Defines how the contents of this table are clipped. + """ + + on_select_all: Optional[ControlEventHandler["DataTable"]] = None + """ + Invoked when the user selects or unselects every row, using the checkbox in the \ + heading row. + + If this is `None`, then the :attr:`flet.DataRow.on_select_change` + callback of every :attr:`rows` of this table is invoked appropriately instead. + + Tip: + To control whether a particular row is selectable or not, see + :attr:`flet.DataRow.on_select_change`. This callback is only relevant if + any row is selectable. + """ + + def __contains__(self, item): + return item in self.columns + self.rows + + def before_update(self): + super().before_update() + visible_columns_count = len( + list(filter(lambda column: column.visible, self.columns)) + ) + visible_rows = list(filter(lambda row: row.visible, self.rows)) + if visible_columns_count == 0: + raise ValueError("columns must contain at minimum one visible DataColumn") + if not all( + [ + len([c for c in row.cells if c.visible]) == visible_columns_count + for row in visible_rows + ] + ): + raise ValueError( + f"each visible DataRow must contain exactly as many visible DataCells " + f"as there are visible DataColumns ({visible_columns_count})" + ) + if self.sort_column_index is not None and not ( + 0 <= self.sort_column_index < visible_columns_count + ): + raise ValueError( + f"sort_column_index ({self.sort_column_index}) must be greater than or " + f"equal to 0 and less than the " + f"number of visible columns ({visible_columns_count})" + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/date_picker.py b/sdk/python/packages/flet/src/flet/controls/material/date_picker.py new file mode 100644 index 0000000000..7de5ab9e41 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/date_picker.py @@ -0,0 +1,274 @@ +from dataclasses import dataclass, field +from datetime import datetime +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ( + ControlEventHandler, + Event, + EventHandler, +) +from flet.controls.dialog_control import DialogControl +from flet.controls.duration import DateTimeValue +from flet.controls.material.textfield import KeyboardType +from flet.controls.padding import Padding, PaddingValue +from flet.controls.types import ( + ColorValue, + IconData, + Locale, +) + +__all__ = [ + "DatePicker", + "DatePickerEntryMode", + "DatePickerEntryModeChangeEvent", + "DatePickerMode", +] + + +class DatePickerMode(Enum): + """Initial display of a calendar date picker.""" + + DAY = "day" + """Choosing a month and day.""" + + YEAR = "year" + """Choosing a year.""" + + +class DatePickerEntryMode(Enum): + """Mode of date entry method for the date picker dialog.""" + + CALENDAR = "calendar" + """ + User picks a date from calendar grid. + + Can switch to :attr:`INPUT` by activating a mode button in the dialog. + """ + + INPUT = "input" + """ + User can input the date by typing it into a text field. + + Can switch to :attr:`CALENDAR` by activating a mode button in the dialog. + """ + + CALENDAR_ONLY = "calendarOnly" + """ + User can only pick a date from calendar grid. + + There is no user interface to switch to another mode. + """ + + INPUT_ONLY = "inputOnly" + """ + User can only input the date by typing it into a text field. + + There is no user interface to switch to another mode. + """ + + +@dataclass +class DatePickerEntryModeChangeEvent(Event["DatePicker"]): + """Event fired when the :class:`~flet.DatePicker` entry mode is changed.""" + + entry_mode: DatePickerEntryMode + """The new date picker entry mode.""" + + +@control("DatePicker") +class DatePicker(DialogControl): + """ + A Material-style date picker dialog. + + It can be opened by calling :meth:`flet.Page.show_dialog` method. + + Depending on the :attr:`entry_mode`, it will show either a Calendar + or an Input (TextField) for picking a date. + + ```python + picker = ft.DatePicker() + + ft.Button( + "Pick date", + icon=ft.Icons.CALENDAR_MONTH, + on_click=lambda _: page.show_dialog(picker), + ) + ``` + """ + + value: Optional[DateTimeValue] = None + """ + The selected date that the picker should display. + + Defaults to :attr:`current_date`. + """ + + modal: bool = False + """ + Whether this date picker cannot be dismissed by clicking the area outside of it. + """ + + first_date: DateTimeValue = field( + default_factory=lambda: datetime(year=1900, month=1, day=1) + ) + """ + The earliest allowable date that the user can select. + + Defaults to `January 1, 1900`. + """ + + last_date: DateTimeValue = field( + default_factory=lambda: datetime(year=2050, month=1, day=1) + ) + """ + The latest allowable date that the user can select. + + Defaults to `January 1, 2050`. + """ + + current_date: DateTimeValue = field(default_factory=lambda: datetime.now()) + """ + The date representing today. It will be highlighted in the day grid. + """ + + locale: Optional[Locale] = None + """ + The locale for this date picker dialog. It is intended for (rare) cases where this \ + dialog should be localized differently from the rest of the page. + + It overrides the locale used by the page (see \ + :attr:`flet.Page.locale_configuration`), + but does not participate in page-level locale resolution. + + If set to `None` (the default) or an inexistent/unsupported locale, + the :attr:`~flet.LocaleConfiguration.current_locale` of the + :attr:`flet.Page.locale_configuration` is used as fallback. + """ + + keyboard_type: KeyboardType = KeyboardType.DATETIME + """ + The type of keyboard to use for editing the text. + """ + + date_picker_mode: DatePickerMode = DatePickerMode.DAY + """ + Initial display mode of this picker. + """ + + entry_mode: DatePickerEntryMode = DatePickerEntryMode.CALENDAR + """ + The initial mode of date entry method for the date picker dialog. + """ + + help_text: Optional[str] = None + """ + The text that is displayed at the top of the header. + + This is used to indicate to the user what they are selecting a date for. + + Defaults to `"Select date"`. + """ + + cancel_text: Optional[str] = None + """ + The text that is displayed on the cancel button. + + Defaults to `"Cancel"`. + """ + + confirm_text: Optional[str] = None + """ + The text that is displayed on the confirm button. + + Defaults to `"OK"`. + """ + + error_format_text: Optional[str] = None + """ + The error message displayed below the text field if the entered date is not in the \ + correct format. + + Defaults to `"Invalid format"`. + """ + + error_invalid_text: Optional[str] = None + """ + The error message displayed below the text field if the date is earlier than \ + :attr:`first_date` or later than :attr:`last_date`. + + Defaults to `"Out of range"`. + """ + + field_hint_text: Optional[str] = None + """ + The hint text displayed in the text field. + + The default value is the date format string that depends on your locale. + For example, `'mm/dd/yyyy'` for en_US. + """ + + field_label_text: Optional[str] = None + """ + The label text displayed in the `TextField`. + + If `None`, defaults to the words representing the date format string. + For example, `'Month, Day, Year'` for en_US. + + Defaults to `"Enter Date"`. + """ + + switch_to_calendar_icon: Optional[IconData] = None + """ + The icon displayed in the corner of this picker's dialog when :attr:`entry_mode` \ + is :attr:`flet.DatePickerEntryMode.INPUT`. + + Clicking on this icon changes the :attr:`entry_mode` to + :attr:`flet.DatePickerEntryMode.CALENDAR`. + + If `None`, defaults to `Icons.CALENDAR_TODAY`. + """ + + switch_to_input_icon: Optional[IconData] = None + """ + The icon displayed in the corner of this picker's dialog when :attr:`entry_mode` \ + is :attr:`flet.DatePickerEntryMode.CALENDAR`. + + Clicking on icon changes the :attr:`entry_mode` to + :attr:`flet.DatePickerEntryMode.INPUT`. + + If `None`, defaults to `Icons.EDIT_OUTLINED`. + """ + + barrier_color: Optional[ColorValue] = None + """ + The color of the modal barrier that darkens everything below this picker's dialog. + + If `None`, the :attr:`flet.DialogTheme.barrier_color` is used. + If it is also `None`, then :attr:`flet.Colors.BLACK_54` is used. + """ + + inset_padding: PaddingValue = field( + default_factory=lambda: Padding.symmetric(horizontal=16.0, vertical=24.0) + ) + """ + The amount of padding added to :attr:`~flet.PageMediaData.view_insets` of the \ + :attr:`flet.Page.media` on the outside of this picker's dialog. + + This defines the minimum space between the screen's edges and the dialog. + """ + + on_change: Optional[ControlEventHandler["DatePicker"]] = None + """ + Called when user clicks confirm button. + :attr:`value` is updated with selected date. + + The :attr:`~flet.Event.data` property of the event handler argument + contains the selected date. + """ + + on_entry_mode_change: Optional[EventHandler[DatePickerEntryModeChangeEvent]] = None + """ + Called when the :attr:`entry_mode` is changed from the user interface. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py b/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py new file mode 100644 index 0000000000..c3b2d69134 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/date_range_picker.py @@ -0,0 +1,205 @@ +from dataclasses import field +from datetime import datetime +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ( + ControlEventHandler, +) +from flet.controls.dialog_control import DialogControl +from flet.controls.duration import DateTimeValue +from flet.controls.material.date_picker import DatePickerEntryMode +from flet.controls.material.textfield import KeyboardType +from flet.controls.types import ( + ColorValue, + IconData, + Locale, +) + +__all__ = [ + "DateRangePicker", +] + + +@control("DateRangePicker") +class DateRangePicker(DialogControl): + """ + A Material-style date range picker dialog. + + It can be opened by calling :meth:`flet.Page.show_dialog` method. + + Depending on the :attr:`entry_mode`, it will show either a Calendar + or an Input (text field) for picking a date range. + + ```python + picker = ft.DateRangePicker() + + ft.Button( + "Pick date range", + icon=ft.Icons.DATE_RANGE, + on_click=lambda _: page.show_dialog(picker), + ) + ``` + """ + + start_value: Optional[DateTimeValue] = None + """ + The selected start date that the picker should display. + + Defaults to :attr:`current_date`. + """ + + end_value: Optional[DateTimeValue] = None + """ + The selected end date that the picker should display. + + Defaults to :attr:`current_date`. + """ + + save_text: Optional[str] = None + """ + The label on the save button for the fullscreen calendar mode. + """ + + error_invalid_range_text: Optional[str] = None + """ + The message used when the date range is invalid (e.g. start date is after end \ + date). + """ + + modal: bool = False + """ + Whether this date picker cannot be dismissed by clicking the area outside of it. + """ + + first_date: DateTimeValue = field( + default_factory=lambda: datetime(year=1900, month=1, day=1) + ) + """ + The earliest allowable date on the date range. + """ + + last_date: DateTimeValue = field( + default_factory=lambda: datetime(year=2050, month=1, day=1) + ) + """ + The latest allowable date on the date range. + """ + + current_date: DateTimeValue = field(default_factory=lambda: datetime.now()) + """ + The date representing today. It will be highlighted in the day grid. + """ + + locale: Optional[Locale] = None + """ + The locale for this date picker dialog. It is intended for (rare) cases where this \ + dialog should be localized differently from the rest of the page. + + It overrides the locale used by the page (see \ + :attr:`flet.Page.locale_configuration`), + but does not participate in page-level locale resolution. + + If set to `None` (the default) or an inexistent/unsupported locale, + the :attr:`~flet.LocaleConfiguration.current_locale` of the + :attr:`flet.Page.locale_configuration` is used as fallback. + """ + + keyboard_type: KeyboardType = KeyboardType.DATETIME + """ + The type of keyboard to use for editing the text. + """ + + entry_mode: DatePickerEntryMode = DatePickerEntryMode.CALENDAR + """ + The initial mode of date entry method for the date picker dialog. + """ + + help_text: Optional[str] = None + """ + The text that is displayed at the top of the header. + + This is used to indicate to the user what they are selecting a date for. + """ + + cancel_text: Optional[str] = None + """ + The text that is displayed on the cancel button. + """ + + confirm_text: Optional[str] = None + """ + The text that is displayed on the confirm button. + """ + + error_format_text: Optional[str] = None + """ + The error message displayed below the TextField if the entered date is not in the \ + correct format. + """ + + error_invalid_text: Optional[str] = None + """ + The error message displayed below the TextField if the date is earlier than \ + :attr:`first_date` or later than :attr:`last_date`. + """ + + field_start_hint_text: Optional[str] = None + """ + The text used to prompt the user when no text has been entered in the start field. + """ + + field_end_hint_text: Optional[str] = None + """ + The text used to prompt the user when no text has been entered in the end field. + """ + + field_start_label_text: Optional[str] = None + """ + The label for the start date text input field. + """ + + field_end_label_text: Optional[str] = None + """ + The label for the end date text input field. + """ + + switch_to_calendar_icon: Optional[IconData] = None + """ + The name of the icon displayed in the corner of the dialog when \ + :attr:`entry_mode` is :attr:`flet.DatePickerEntryMode.INPUT`. + + Clicking on this icon changes the `entry_mode` to + :attr:`flet.DatePickerEntryMode.CALENDAR`. + + If `None`, `Icons.CALENDAR_TODAY` is used. + """ + + switch_to_input_icon: Optional[IconData] = None + """ + The name of the icon displayed in the corner of the dialog when \ + :attr:`entry_mode` is :attr:`flet.DatePickerEntryMode.CALENDAR`. + + Clicking on this icon changes the `entry_mode` to + :attr:`flet.DatePickerEntryMode.INPUT`. + + If `None`, `Icons.EDIT_OUTLINED` is used. + """ + + barrier_color: Optional[ColorValue] = None + """ + The color of the modal barrier that darkens everything below the date picker. + + If `None`, the :attr:`flet.DialogTheme.barrier_color` is used. + If it is also `None`, then `Colors.BLACK_54` is used. + """ + + on_change: Optional[ControlEventHandler["DateRangePicker"]] = None + """ + Called when user clicks confirm button. + + :attr:`start_value` and :attr:`end_value` are updated with selected dates. + + The :attr:`~flet.Event.data` property of the event handler + argument contains the selected dates. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/divider.py b/sdk/python/packages/flet/src/flet/controls/material/divider.py new file mode 100644 index 0000000000..5cebde91de --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/divider.py @@ -0,0 +1,100 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.control import Control +from flet.controls.types import ColorValue, Number +from flet.utils.validation import V + +__all__ = ["Divider"] + + +@control("Divider") +class Divider(Control): + """ + A thin horizontal line (divider), with padding on either side. + + ```python + ft.Column( + width=240, + spacing=10, + controls=[ + ft.Text("Section A", weight=ft.FontWeight.W_600), + ft.Divider(), + ft.Text("Section B"), + ], + ) + ``` + """ + + color: Optional[ColorValue] = None + """ + The color to use when painting the line. + + If `None`, :attr:`flet.DividerTheme.color` is used. + """ + + height: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The divider's height extent. The divider itself is always drawn as a horizontal \ + line that is centered within the height specified by this value. + + If `None`, :attr:`flet.DividerTheme.space` is used. + If that's is also `None`, defaults to `16.0`. + + Raises: + ValueError: If :attr:`height` is negative. + """ + + leading_indent: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The amount of empty space to the leading edge of the divider. + + If `None`, :attr:`flet.DividerTheme.leading_indent` is used. + If that's is also `None`, defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + thickness: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The thickness of the line drawn within the divider. + + A divider with a thickness of `0.0` is always drawn as a line with a + height of exactly one device pixel. + + If `None`, :attr:`flet.DividerTheme.thickness` is used. + If that is also `None`, defaults to `0.0`. + + Raises: + ValueError: If :attr:`thickness` is negative. + """ + + trailing_indent: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The amount of empty space to the trailing edge of the divider. + + If `None`, :attr:`flet.DividerTheme.trailing_indent` is used. + If that is also `None`, defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + radius: Optional[BorderRadiusValue] = None + """ + The border radius of the divider. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/dropdown.py b/sdk/python/packages/flet/src/flet/controls/material/dropdown.py new file mode 100644 index 0000000000..75a10f7989 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/dropdown.py @@ -0,0 +1,393 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.buttons import ButtonStyle +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.material.form_field_control import InputBorder +from flet.controls.material.menu_bar import MenuStyle +from flet.controls.material.textfield import InputFilter, TextCapitalization +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, + StrOrControl, + TextAlign, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["Dropdown", "DropdownOption"] + + +@control("DropdownOption") +class DropdownOption(Control): + """ + Represents an item in a dropdown. + """ + + key: Optional[str] = None + """ + Option's key. + + If not specified :attr:`text` will be used as fallback. + + Raises: + ValueError: If neither `key` nor :attr:`text` is provided. + """ + + text: Optional[str] = None + """ + Option's display text. + + If not specified :attr:`key` will be used as fallback. + + Raises: + ValueError: If neither :attr:`key` nor `text` is provided. + """ + + content: Optional[Control] = None + """ + A `Control` to display in this option. If not specified, `text` will be used as \ + fallback, else `text` will be ignored. + """ + + leading_icon: Optional[IconDataOrControl] = None + """ + An optional icon to display before the content or text. + """ + + trailing_icon: Optional[IconDataOrControl] = None + """ + An optional icon to display after the content or text. + """ + + style: Optional[ButtonStyle] = None + """ + Customizes this menu item's appearance. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ctrl.key is not None or ctrl.text is not None, + message="key or text must be specified", + ), + ) + + +Option = DropdownOption + + +@control("Dropdown") +class Dropdown(LayoutControl): + """ + A dropdown control that allows users to select a single option from a list of \ + :attr:`options`. + + Example: + ```python + ft.Dropdown( + width=220, + value="alice", + options=[ + ft.DropdownOption(key="alice", text="Alice"), + ft.DropdownOption(key="bob", text="Bob"), + ], + ) + ``` + """ + + value: Optional[str] = None + """ + The :attr:`~flet.DropdownOption.key` of the dropdown :attr:`options` + corresponding to the selected option. + """ + + options: list[DropdownOption] = field(default_factory=list) + """ + A list of options to display in the dropdown. + """ + + text: Optional[str] = None + """ + The text entered in the text field. + """ + + autofocus: bool = False + """ + Whether the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + text_align: TextAlign = TextAlign.START + """ + The text align for the TextField of the Dropdown. + """ + + elevation: Optional[ControlStateValue[Optional[Number]]] = 8 + """ + The dropdown's menu elevation in various :class:`~flet.ControlState` + states. + """ + + enable_filter: bool = False + """ + Determine if the menu list can be filtered by the text input. Defaults to false. + + If set to true, dropdown menu will show a filtered list. The filtered list will + contain items that match the text provided by the input field, with a + case-insensitive comparison. + """ + + enable_search: bool = True + """ + Determine if the first item that matches the text input can be highlighted. + """ + + editable: bool = False + """ + Whether the dropdown allows editing of the text input field. + """ + + menu_height: Optional[Number] = None + """ + The height of the dropdown menu. + + If this is `None`, the menu will display as many + items as possible on the screen. + """ + + menu_width: Optional[Number] = None + """ + The width of the dropdown menu. + + If this is `None`, the menu width will be the same as + input textfield width. + """ + + menu_style: Optional[MenuStyle] = None + """ + The menu style that defines the visual attributes of the menu. + + The default width of the menu is set to the width of the text field. + """ + + expanded_insets: Optional[PaddingValue] = None + """ + The insets for the expanded dropdown menu. + """ + + selected_suffix: Optional[Control] = None + """ + A control to display after the selected item in the dropdown. + """ + + input_filter: Optional[InputFilter] = None + """ + A filter to apply to the text input field. + """ + + capitalization: Optional[TextCapitalization] = None + """ + Configures how the text input should be capitalized. + """ + + trailing_icon: Optional[IconDataOrControl] = None + """ + An icon to display at the end of the text field. + """ + + leading_icon: Optional[IconDataOrControl] = None + """ + An optional Icon at the front of the text input field inside the decoration box. + + If this is not null, the menu items will have extra paddings to + be aligned with the text in the text field. + """ + + selected_trailing_icon: Optional[IconDataOrControl] = None + """ + An optional icon at the end of the text field to indicate that the text field is \ + pressed. + """ + + bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + The background color of the dropdown menu in various :class:`~flet.ControlState` + states. + """ + + on_select: Optional[ControlEventHandler["Dropdown"]] = None + """ + Called when the selected item of this dropdown has changed. + """ + + on_text_change: Optional[ControlEventHandler["Dropdown"]] = None + """ + Called when the :attr:`text` input of this dropdown has changed. + """ + + on_focus: Optional[ControlEventHandler["Dropdown"]] = None + """ + Called when the control has received focus. + """ + + on_blur: Optional[ControlEventHandler["Dropdown"]] = None + """ + Called when the control has lost focus. + """ + + # From FormField + + error_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for :attr:`error_text`. + """ + + error_text: Optional[str] = None + """ + Text that appears below the input border. + + If non-null, the border's color animates to red and the :attr:`helper_text` is + not shown. + """ + + text_size: Optional[Number] = None + """ + Text size in virtual pixels. + """ + + text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for text in input text field. + """ + + label: Optional[StrOrControl] = None + """ + Optional text that describes the input field. + + When the input field is empty and unfocused, the label is displayed on top of the + input field (i.e., at the same location on the screen where text may be entered in + the input field). When the input field receives focus (or if the field is + non-empty) the label moves above, either vertically adjacent to, or to the center + of the input field. + """ + + label_style: Optional[TextStyle] = None + """ + The :attr:`label`'s text style. + """ + + border: Optional[InputBorder] = None + """ + Border around input. + + Defaults to `InputBorder.OUTLINE`. + """ + + color: Optional[ColorValue] = None + """ + Text color. + """ + + border_width: Number = 1 + """ + The width of the border in virtual pixels. + + Tip: + Set to `0` to completely remove the border. + """ + + border_color: Optional[ColorValue] = None + """ + Border color. + + Tip: + Set to :attr:`flet.Colors.TRANSPARENT` to hide the border. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The border radius applied to the corners of the dropdown input field. + Accepts a value in virtual pixels or a `BorderRadiusValue` object. + If set to `None`, the default border radius defined by the theme or system is used. + """ + + focused_border_width: Optional[Number] = None + """ + Border width in focused state. + """ + + focused_border_color: Optional[ColorValue] = None + """ + Border color in focused state. + """ + + content_padding: Optional[PaddingValue] = None + """ + The padding for the input decoration's container. + """ + + dense: bool = False + """ + Whether the TextField is part of a dense form (i.e., uses less vertical space). + """ + + filled: bool = False + """ + Whether the decoration's container is filled with theme :attr:`fill_color`. + """ + + fill_color: Optional[ColorValue] = None + """ + Background color of the dropdown input text field. + + Note: + Will not be visible if `filled=False`. + """ + + hover_color: Optional[ColorValue] = None + """ + The color of the dropdown input text field when hovered. + """ + + hint_text: Optional[str] = None + """ + Text that suggests what sort of input the field accepts. + + Displayed on top of the input when it's empty and either (a) `label` is null or (b) + the input has the focus. + """ + + hint_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for :attr:`hint_text`. + """ + + helper_text: Optional[str] = None + """ + Text that provides context about the input's value, such as how the value will be \ + used. + + If non-null, the text is displayed below the input decorator, in the same location + as `error_text`. If a non-null `error_text` value is specified then the helper text + is not shown. + """ + + helper_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for :attr:`helper_text`. + """ + + def __contains__(self, item): + return item in self.options + + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py new file mode 100644 index 0000000000..a5136b3b9a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/dropdownm2.py @@ -0,0 +1,225 @@ +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.material.form_field_control import FormFieldControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, +) +from flet.utils.deprecated import deprecated_class +from flet.utils.validation import V, ValidationRules + +__all__ = ["DropdownM2", "Option"] + + +@control("Option") +class Option(Control): + """ + Represents an item in a dropdown. + """ + + key: Optional[str] = None + """ + Option's key. + + If not specified :attr:`text` will be used as fallback. + + Raises: + ValueError: If neither `key` nor :attr:`text` is provided. + """ + + text: Optional[str] = None + """ + Option's display text. + + If not specified :attr:`key` will be used as fallback. + + Raises: + ValueError: If neither :attr:`key` nor `text` is provided. + """ + + content: Optional[Control] = None + """ + A `Control` to display in this option. If not specified, `text` will be used as \ + fallback, else `text` will be ignored. + """ + + alignment: Optional[Alignment] = None + """ + Defines the alignment of this option in it's container. + + Defaults to `Alignment.center_left()`. + """ + + text_style: Optional[TextStyle] = None + """ + Defines the style of the `text`. + """ + + on_click: Optional[ControlEventHandler["Option"]] = None + """ + Called when this option is clicked. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ctrl.key is not None or ctrl.text is not None, + message="key or text must be specified", + ), + ) + + +@deprecated_class( + reason="Use Dropdown instead.", + version="0.84.0", + delete_version="1.0", +) +@control("DropdownM2") +class DropdownM2(FormFieldControl): + """ + A dropdown lets the user select from a number of items. The dropdown shows the \ + currently selected item as well as an arrow that opens a menu for selecting \ + another item. + + Example: + ```python + ft.DropdownM2( + width=220, + value="Alice", + options=[ + ft.dropdownm2.Option(key="Alice", text="Alice"), + ft.dropdownm2.Option(key="Bob", text="Bob"), + ], + ) + ``` + """ + + value: Optional[str] = None + """ + `key` value of the selected option. + """ + + options: Optional[list[Option]] = None + """ + A list of `Option` controls representing items in this dropdown. + """ + + alignment: Optional[Alignment] = None + """ + Defines how the `hint` or the selected item is positioned within this dropdown. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + hint_content: Optional[Control] = None + """ + A placeholder `Control` for the dropdown's value that is displayed when `value` is \ + `None`. + """ + + select_icon: Optional[IconDataOrControl] = None + """ + The [name of the icon](https://flet.dev/docs/types/icons) or `Control` to use \ + for the drop-down select button's icon. + + Defaults to `Icon(ft.Icons.ARROW_DROP_DOWN)`. + """ + + elevation: Number = 8 + """ + The dropdown's elevation. + """ + + item_height: Optional[Number] = None + """ + The height of the items/options in the dropdown menu. + """ + + max_menu_height: Optional[Number] = None + """ + The maximum height of the dropdown menu. + """ + + select_icon_size: Number = 24.0 + """ + The size of the icon button which wraps `select_icon`. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. On \ + Android, for example, setting this to `True` produce a click sound and a \ + long-press will produce a short vibration. + """ + + padding: Optional[PaddingValue] = None + """ + The padding around the visible portion of this dropdown. + """ + + select_icon_enabled_color: Optional[ColorValue] = None + """ + The color of any `Icon` descendant of `select_icon` if this button is enabled. + """ + + select_icon_disabled_color: Optional[ColorValue] = None + """ + The color of any `Icon` descendant of `select_icon` if this button is disabled. + """ + + options_fill_horizontally: bool = True + """ + Whether the dropdown's inner contents to horizontally fill its parent. + By default this button's inner width is the minimum size of its content. + + If `True`, the inner width is expanded to fill its surrounding container. + """ + + disabled_hint_content: Optional[Control] = None + """ + A placeholder `Control` for the dropdown's value that is displayed when `value` is \ + `None` and the dropdown is disabled. + """ + + on_change: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when the selected item of this dropdown has changed. + """ + + on_focus: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when the control has received focus. + """ + + on_blur: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when the control has lost focus. + """ + + on_click: Optional[ControlEventHandler["DropdownM2"]] = None + """ + Called when this dropdown is clicked. + """ + + def before_update(self): + super().before_update() + if ( + self.bgcolor is not None + or self.fill_color is not None + or self.focused_bgcolor is not None + ) and self.filled is None: + self.filled = True # required to display any of the above colors + + def __contains__(self, item): + return item in self.options diff --git a/sdk/python/packages/flet/src/flet/controls/material/elevated_button.py b/sdk/python/packages/flet/src/flet/controls/material/elevated_button.py new file mode 100644 index 0000000000..18706db87d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/elevated_button.py @@ -0,0 +1,13 @@ +from flet.controls.material.button import Button +from flet.utils.deprecated import deprecated_class + +__all__ = ["ElevatedButton"] + + +@deprecated_class( + reason="Use Button instead.", + version="0.80.0", + delete_version="1.0", +) +class ElevatedButton(Button): + pass diff --git a/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py b/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py new file mode 100644 index 0000000000..cb0204f46b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/expansion_panel.py @@ -0,0 +1,205 @@ +from dataclasses import dataclass, field +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ( + Event, + EventHandler, +) +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import Padding, PaddingValue +from flet.controls.scrollable_control import ScrollableControl +from flet.controls.types import ( + ColorValue, + Number, +) +from flet.utils.validation import V + +__all__ = ["ExpansionPanel", "ExpansionPanelList", "ExpansionPanelListChangeEvent"] + + +@dataclass +class ExpansionPanelListChangeEvent(Event["ExpansionPanelList"]): + """ + Payload for :attr:`flet.ExpansionPanelList.on_change` event. + """ + + index: int + """ + The index of the panel in :attr:`flet.ExpansionPanelList.controls` that was toggled. + + Panels with :attr:`~flet.Control.visible` set to `False` are not counted/indexed. + This means the value may differ from the panel's position in the original + :attr:`flet.ExpansionPanelList.controls` list when some panels are invisible. + To map it back, filter :attr:`flet.ExpansionPanelList.controls` to only visible + panels and use this index on that filtered list. + """ + + expanded: bool + """ + Whether the toggled panel is expanded (`True`) or + collapsed (`False`) after the event. + """ + + +@control("ExpansionPanel") +class ExpansionPanel(LayoutControl, AdaptiveControl): + """ + A material expansion panel. It can either be expanded or collapsed. Its body is \ + only visible when it is expanded. + + Example: + ```python + ft.ExpansionPanelList( + width=400, + controls=[ + ft.ExpansionPanel( + header=ft.Text("Shipping address"), + content=ft.Text("123 Market Street, Springfield"), + expanded=True, + ), + ft.ExpansionPanel( + header=ft.Text("Billing address"), + content=ft.Text("Same as shipping"), + ), + ], + ) + ``` + """ + + header: Optional[Control] = None + """ + The control to be found in the header of this panel. + + It is always visible, regardless of whether this panel is expanded or collapsed. + If :attr:`can_tap_header` is `True`, tapping on this `header` will expand or + collapse this panel. + + If this property is `None`, this panel will have a placeholder `Text` as + header. + """ + + content: Optional[Control] = None + """ + The control to be found in the body of this panel. + + It is displayed below the :attr:`header` when this panel is :attr:`expanded`. + + If this property is `None`, this panel will have a placeholder `Text` as + content. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of this panel. + """ + + expanded: bool = False + """ + Whether this panel is in expanded (`True`) or collapsed (`False`) state. + """ + + can_tap_header: bool = False + """ + Whether tapping on this panel's :attr:`header` will expand or collapse it. + """ + + splash_color: Optional[ColorValue] = None + """ + Defines the splash color of this panel if :attr:`can_tap_header` is `True`, or the \ + splash color of the expand/collapse `IconButton` if :attr:`can_tap_header` is \ + `False`. + + If :attr:`can_tap_header` is `False`, and :attr:`flet.Theme.use_material3` is + `True`, this field will be ignored, as :attr:`flet.IconButton.splash_color` + will be ignored, and you should use :attr:`highlight_color` instead. + + If this is `None`, then the icon button will use its default splash color + :attr:`flet.Theme.splash_color`, and this panel will use its default splash color + :attr:`flet.Theme.splash_color` (if :attr:`can_tap_header` is `True`). + """ + + highlight_color: Optional[ColorValue] = None + """ + Defines the highlight color of this panel if :attr:`can_tap_header` is `True`, or \ + the highlight color of the expand/collapse `IconButton` if :attr:`can_tap_header` \ + is `False`. + + If this is `None`, then the icon button will use its default highlight color + :attr:`flet.Theme.highlight_color`, and this panel will use its default highlight + color :attr:`flet.Theme.highlight_color` (if :attr:`can_tap_header` is `True`). + """ + + +@control("ExpansionPanelList") +class ExpansionPanelList(LayoutControl, ScrollableControl): + """ + A material expansion panel list that lays out its children and animates \ + expansions. + + Example: + ```python + ft.ExpansionPanelList( + width=400, + controls=[ + ft.ExpansionPanel( + header=ft.Text("Details"), + content=ft.Text("More information here"), + expanded=True, + ), + ft.ExpansionPanel( + header=ft.Text("History"), + content=ft.Text("View previous updates"), + ), + ], + ) + ``` + """ + + controls: list[ExpansionPanel] = field(default_factory=list) + """ + A list of panels to display. + """ + + divider_color: Optional[ColorValue] = None + """ + The color of the divider when :attr:`flet.ExpansionPanel.expanded` is `False`. + """ + + elevation: Annotated[ + Number, + V.ge(0), + ] = 2 + """ + Defines the elevation of the :attr:`controls`, when expanded. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + expanded_header_padding: PaddingValue = field( + default_factory=lambda: Padding.symmetric(vertical=16.0) + ) + """ + Defines the padding around the header when expanded. + """ + + expand_icon_color: Optional[ColorValue] = None + """ + The color of the icon. + + Defaults to :attr:`flet.Colors.BLACK_54` in light theme mode and + :attr:`flet.Colors.WHITE_60` in dark theme mode. + """ + + spacing: Optional[Number] = None + """ + The size of the gap between the :attr:`controls`s when expanded. + """ + + on_change: Optional[EventHandler[ExpansionPanelListChangeEvent]] = None + """ + Called when an item of :attr:`controls` is expanded or collapsed. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py b/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py new file mode 100644 index 0000000000..2560735c71 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/expansion_tile.py @@ -0,0 +1,358 @@ +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.alignment import Alignment +from flet.controls.animation import AnimationStyle +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ClipBehavior, + ColorValue, + CrossAxisAlignment, + IconDataOrControl, + Number, + StrOrControl, + VisualDensity, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["ExpansionTile", "TileAffinity"] + + +class TileAffinity(Enum): + """ + Where to place a control in controls that use :class:`~flet.ListTile` to position \ + a control next to a label. + """ + + LEADING = "leading" + """ + Positions the control on the leading edge, and the secondary control, if any, on \ + the trailing edge. + """ + + TRAILING = "trailing" + """ + Positions the control on the trailing edge, and the secondary control, if any, on \ + the leading edge. + """ + + PLATFORM = "platform" + """ + Positions the control relative to the text in the fashion that is typical for the \ + current platform, and place the secondary control on the opposite side. + """ + + +@control("ExpansionTile") +class ExpansionTile(LayoutControl, AdaptiveControl): + """ + A single-line ListTile with an expansion arrow icon that expands or collapses the \ + tile to reveal or hide its controls. + + Example: + ```python + ft.ExpansionTile( + width=400, + title="Account", + subtitle="Manage profile and security", + expanded=True, + controls=[ + ft.ListTile(title=ft.Text("Profile")), + ft.ListTile(title=ft.Text("Security")), + ], + ) + ``` + """ + + title: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + A Control to display as primary content of this tile. + + Typically a :class:`~flet.Text` control. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + controls: Optional[list[Control]] = None + """ + The controls to be displayed when this tile :attr:`expanded`. + + Typically a list of :class:`~flet.ListTile` controls. + """ + + subtitle: Optional[StrOrControl] = None + """ + Additional content displayed below the :attr:`title`. + + Typically a :class:`~flet.Text` control. + """ + + leading: Optional[IconDataOrControl] = None + """ + A Control to display before the :attr:`title`. + + Typically a :class:`~flet.CircleAvatar` control. + + Depending on the value of :attr:`affinity`, this control + may replace the rotating expansion arrow icon. + """ + + trailing: Optional[IconDataOrControl] = None + """ + A Control to display after the :attr:`title`. + + Typically an :class:`~flet.Icon` control. + + Depending on the value of :attr:`affinity`, this control + may replace the rotating expansion arrow icon. + """ + + controls_padding: Optional[PaddingValue] = None + """ + Defines the padding around the :attr:`controls`. + + If `None`, :attr:`flet.ExpansionTileTheme.controls_padding` is used; + if that is also `None`, then defaults to `Padding.all(0)`. + """ + + tile_padding: Optional[PaddingValue] = None + """ + Defines the tile's padding. + + Analogous to :attr:`flet.ListTile.content_padding`, this property defines the + insets for the :attr:`leading`, :attr:`title`, :attr:`subtitle` and + :attr:`trailing` controls. It does not inset the expanded + :attr:`controls` widgets. + + If `None`, :attr:`flet.ExpansionTileTheme.tile_padding` is used; + if that is also `None`, then defaults to `Padding.symmetric(horizontal=16.0)`. + """ + + affinity: Optional[TileAffinity] = None + """ + Typically used to force the expansion arrow icon to the tile's :attr:`leading` or \ + :attr:`trailing` edge. + + If `None`, :attr:`flet.ListTileTheme.affinity` is used; + if that is also `None`, then defaults to :attr:`flet.TileAffinity.TRAILING` + (the expansion arrow icon appears on the tile's trailing edge). + """ + + expanded_alignment: Optional[Alignment] = None + """ + Defines the alignment of :attr:`controls`, which are arranged in a column when the \ + tile is expanded. + + If `None`, :attr:`flet.ExpansionTileTheme.expanded_alignment` is used; + if that is also `None`, then defaults to :attr:`flet.Alignment.CENTER`. + """ + + expanded_cross_axis_alignment: CrossAxisAlignment = CrossAxisAlignment.CENTER + """ + Defines the alignment of each child control within :attr:`controls` when the tile \ + is expanded. + + Raises: + ValueError: If set to :attr:`flet.CrossAxisAlignment.BASELINE`. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Defines how the content of this tile is clipped. + + If set and a custom collapsed or expanded shape is provided, + this value determines how this tile is clipped. + + If `None`, :attr:`flet.ExpansionTileTheme.clip_behavior` is used; + if that is also `None`, then defaults to :attr:`flet.ClipBehavior.ANTI_ALIAS`. + """ + + maintain_state: bool = False + """ + A boolean value which defines whether the state of the :attr:`controls` is \ + maintained when this tile :attr:`expanded` and collapses. + + When `True`, the children are kept in the tree while the tile is collapsed. + When `False` (default), the :attr:`controls` are removed from the tree when + the tile is collapsed and recreated upon expansion. + """ + + text_color: Optional[ColorValue] = None + """ + The color of this tile's titles when the sublist is :attr:`expanded`. + + If `None`, :attr:`flet.ExpansionTileTheme.text_color` is used; + if that is also `None`, then defaults to :attr:`~flet.TextTheme.body_large` + of the :attr:`flet.Theme.text_theme`. + """ + + icon_color: Optional[ColorValue] = None + """ + The icon color of this tile's expansion arrow icon when the sublist is \ + :attr:`expanded`. + + If `None`, :attr:`flet.ExpansionTileTheme.icon_color` is used; + if that is also `None`, then defaults to :attr:`flet.ColorScheme.primary` + of the :attr:`flet.Page.theme`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The border shape of this tile when the sublist is :attr:`expanded`. + + If `None`, :attr:`flet.ExpansionTileTheme.shape` is used; + if that is also `None`, then defaults to a :class:`~flet.Border` with vertical sides + of color :attr:`flet.Theme.divider_color`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color to display behind the sublist when :attr:`expanded`. + + If `None`, :attr:`flet.ExpansionTileTheme.bgcolor` is used; + if that is also `None`, then defaults to :attr:`flet.Colors.TRANSPARENT`. + """ + + collapsed_bgcolor: Optional[ColorValue] = None + """ + Defines the background color of this tile when the sublist is collapsed \ + (:attr:`expanded` is False). + + If `None`, :attr:`flet.ExpansionTileTheme.collapsed_bgcolor` is used; + if that is also `None`, then defaults to :attr:`flet.Colors.TRANSPARENT`. + """ + + collapsed_icon_color: Optional[ColorValue] = None + """ + The icon color of this tile's expansion arrow icon when the sublist is collapsed \ + (:attr:`expanded` is False). + + If `None`, :attr:`flet.ExpansionTileTheme.collapsed_icon_color` is used; + if that is also `None`, then defaults to :attr:`flet.ColorScheme.on_surface` + of the :attr:`flet.Page.theme`. + """ + + collapsed_text_color: Optional[ColorValue] = None + """ + The color of this tile's titles when the sublist is collapsed (:attr:`expanded` is \ + False). + + If `None`, :attr:`flet.ExpansionTileTheme.collapsed_text_color` is used; + if that is also `None`, then defaults to :attr:`~flet.TextTheme.body_large` + of the :attr:`flet.Theme.text_theme`. + """ + + collapsed_shape: Optional[OutlinedBorder] = None + """ + The tile's border shape when the sublist is collapsed. + + If `None`, :attr:`flet.ExpansionTileTheme.shape` is used; + if that is also `None`, then defaults to a :class:`~flet.Border` with vertical sides + of color :attr:`flet.Colors.TRANSPARENT`. + """ + + dense: Optional[bool] = None + """ + Whether this list tile is part of a vertically dense list. + + Dense tiles default to having a smaller height. + + It is not recommended to set this property to `True` when in Material3. + + If `None`, then its value is based on :attr:`flet.ListTileTheme.dense`. + """ + + enable_feedback: bool = True + """ + Whether detected gestures should provide acoustic and/or haptic feedback. For \ + example, on Android a tap will produce a clicking sound and a long-press will \ + produce a short vibration, when feedback is enabled. + """ + + show_trailing_icon: bool = True + """ + Whether this tile should build/show a default trailing icon, if :attr:`trailing` \ + is `None`. + """ + + min_tile_height: Optional[Number] = None + """ + The minimum height of this tile. + + If `None`, the default tile heights are `56.0`, `72.0`, and `88.0` for one, two, + and three lines of text respectively. If :attr:`dense` is `True`, these defaults + are changed to `48.0`, `64.0`, and `76.0`. A visual density value or a large title + will also adjust the default tile heights. + """ + + expanded: bool = False + """ + The expansion state of this tile. + + `True` - expanded, `False` - collapsed. + """ + + visual_density: Optional[VisualDensity] = None + """ + Defines how compact this tile's layout will be. + """ + + animation_style: Optional[AnimationStyle] = None + """ + Defines the animation style (curve and duration) for this tile's expansion and \ + collapse. + + If :attr:`flet.AnimationStyle.duration` is provided, it will be used to override + the expansion animation duration. If it is `None`, then + :attr:`flet.AnimationStyle.duration` from the + :attr:`flet.ExpansionTileTheme.animation_style` will be used. If that is also + `None`, `Duration(milliseconds=200)` will be used as default. + + If :attr:`flet.AnimationStyle.curve` is provided, it will be used to override + the expansion animation curve. If it is `None`, then + :attr:`flet.AnimationStyle.curve` from the + :attr:`flet.ExpansionTileTheme.animation_style` will be used. If that is also + `None`, :attr:`flet.AnimationCurve.EASE_IN` will be used as default. + + If :attr:`flet.AnimationStyle.reverse_curve` is provided, it will be used to \ + override + the collapse animation curve. If it is `None`, then + :attr:`flet.AnimationStyle.reverse_curve` from the + :attr:`flet.ExpansionTileTheme.animation_style` will be used. If that is also + `None`, the expansion curve will be used as default. + + Tip: + To disable the animations, use + :meth:`flet.AnimationStyle.no_animation`. + """ + + on_change: Optional[ControlEventHandler["ExpansionTile"]] = None + """ + Called when a user clicks or taps the list tile. + + The :attr:`~flet.Event.data` property of the event handler argument is a boolean + representing the :attr:`expanded` state of the tile after the change. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ctrl.expanded_cross_axis_alignment != CrossAxisAlignment.BASELINE + ), + message=( + "expanded_cross_axis_alignment cannot be CrossAxisAlignment.BASELINE " + "since the expanded controls are aligned in a column, not a row. " + "Try aligning the controls differently." + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/filled_button.py b/sdk/python/packages/flet/src/flet/controls/material/filled_button.py new file mode 100644 index 0000000000..0eee2295e0 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/filled_button.py @@ -0,0 +1,17 @@ +from flet.controls.base_control import control +from flet.controls.material.button import Button + + +@control("FilledButton") +class FilledButton(Button): + """ + Filled buttons have the most visual impact after the \ + :class:`~flet.FloatingActionButton`, and is typically used for important, final \ + actions that complete a flow, like "Save", "Join now", or "Confirm". + + ```python + ft.FilledButton(content="Tap me") + ``` + """ + + pass diff --git a/sdk/python/packages/flet/src/flet/controls/material/filled_tonal_button.py b/sdk/python/packages/flet/src/flet/controls/material/filled_tonal_button.py new file mode 100644 index 0000000000..6853e2f562 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/filled_tonal_button.py @@ -0,0 +1,18 @@ +from flet.controls.base_control import control +from flet.controls.material.button import Button + + +@control("FilledTonalButton") +class FilledTonalButton(Button): + """ + A filled tonal button is an alternative middle ground between FilledButton and \ + OutlinedButton buttons. They're useful in contexts where a lower-priority button \ + requires slightly more emphasis than an outline would give, such as "Next" in an \ + onboarding flow. Tonal buttons use the secondary color mapping. + + ```python + ft.FilledTonalButton(content="Tap me") + ``` + """ + + pass diff --git a/sdk/python/packages/flet/src/flet/controls/material/floating_action_button.py b/sdk/python/packages/flet/src/flet/controls/material/floating_action_button.py new file mode 100644 index 0000000000..1e6270b77c --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/floating_action_button.py @@ -0,0 +1,210 @@ +from typing import Annotated, Optional, Union + +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.icon_data import IconData +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ClipBehavior, + ColorValue, + IconDataOrControl, + MouseCursor, + Number, + StrOrControl, + Url, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["FloatingActionButton"] + + +@control("FloatingActionButton") +class FloatingActionButton(LayoutControl): + """ + A floating action button is a circular icon button that hovers over content to \ + promote a primary action in the application. Floating action button is usually set \ + to `page.floating_action_button`, but can also be added as a regular control at \ + any place on a page. + + Example: + ```python + ft.FloatingActionButton(icon=ft.Icons.ADD) + ``` + """ + + content: Optional[StrOrControl] = None + """ + The content of this button. + + Raises: + ValueError: If neither :attr:`icon` nor a valid `content` + (string or visible Control) is provided. + """ + + icon: Optional[IconDataOrControl] = None + """ + Icon shown in this button. + """ + + bgcolor: Optional[ColorValue] = None + """ + Button background color. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of the FAB's border. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + mini: bool = False + """ + Controls the size of this button. + + By default, floating action buttons are non-mini and have a height and width of + `56.0` logical pixels. Mini floating action buttons have a height and width of + `40.0` logical pixels with a layout width and height of `48.0` logical pixels. + """ + + foreground_color: Optional[ColorValue] = None + """ + The default foreground color for icons and text within this button. + """ + + focus_color: Optional[ColorValue] = None + """ + The color to use for filling this button when it has input focus. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + Defines how the :attr:`content` is clipped. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation of this button. + + Defaults to `6`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + disabled_elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation of this button when disabled. + + Defaults to :attr:`elevation`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + focus_elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation of this button when it has input focus. + + Defaults to `8`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + highlight_elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation of this button when it is highlighted. + + Defaults to `12`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + hover_elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The elevation of this button it is enabled and being hovered over. + + Defaults to `8`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + hover_color: Optional[ColorValue] = None + """ + The color to use for filling this button when hovered. + """ + + splash_color: Optional[ColorValue] = None + """ + The color to use for the ink splash. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. On \ + Android, for example, setting this to `True` will produce a click sound and a \ + long-press will produce a short vibration. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback + is provided, it is fired after that. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + control. + """ + + on_click: Optional[ControlEventHandler["FloatingActionButton"]] = None + """ + Called when a user clicks this button. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.icon, IconData) + or (isinstance(ctrl.icon, Control) and ctrl.icon.visible) + ) + or ( + isinstance(ctrl.content, str) + or (isinstance(ctrl.content, Control) and ctrl.content.visible) + ) + ), + message=( + "at minimum, icon or a content (string or visible Control) " + "must be provided" + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py new file mode 100644 index 0000000000..e6d607a01d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/form_field_control.py @@ -0,0 +1,338 @@ +from enum import Enum +from typing import Optional, Union + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.box import BoxConstraints +from flet.controls.duration import DurationValue +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, + StrOrControl, + VerticalAlignment, +) + + +class InputBorder(Enum): + NONE = "none" + OUTLINE = "outline" + UNDERLINE = "underline" + + +@control(kw_only=True) +class FormFieldControl(LayoutControl): + text_size: Optional[Number] = None + """ + Text size in virtual pixels. + """ + + text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for the text being edited. + """ + + text_vertical_align: Optional[Union[VerticalAlignment, Number]] = None + """ + Defines how the text should be aligned vertically. + + Value can either be a number ranging from `-1.0` (topmost location) to `1.0` + (bottommost location) or of type :class:`~flet.VerticalAlignment` + Defaults to `VerticalAlignment.CENTER`. + """ + + label: Optional[StrOrControl] = None + """ + Optional text that describes the input field. + + When the input field is empty and unfocused, the label is displayed on top of the + input field (i.e., at the same location on the screen where text may be entered in + the input field). When the input field receives focus (or if the field is + non-empty) the label moves above, either vertically adjacent to, or to the center + of the input field. + """ + + label_style: Optional[TextStyle] = None + """ + The text style to use for `label`. + """ + + icon: Optional[IconDataOrControl] = None + """ + The icon to show before the input field and outside of the decoration's container. + """ + + border: InputBorder = InputBorder.OUTLINE + """ + Border around input. + """ + + color: Optional[ColorValue] = None + """ + Text color. + """ + + bgcolor: Optional[ColorValue] = None + """ + TextField background color. + + Note: + Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + """ + + border_width: Optional[Number] = None + """ + The width of the border in virtual pixels. + + Defaults to `1`. + + Tip: + Set to `0` to completely remove the border. + """ + + border_color: Optional[ColorValue] = None + """ + The border color. + + Tip: + Set to :attr:`flet.Colors.TRANSPARENT` to invisible/hide the border. + """ + + focused_color: Optional[ColorValue] = None + """ + The text's color when focused. + """ + + focused_bgcolor: Optional[ColorValue] = None + """ + Background color in focused state. + + Note: + Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + """ + + focused_border_width: Optional[Number] = None + """ + Border width in focused state. + """ + + focused_border_color: Optional[ColorValue] = None + """ + Border color in focused state. + """ + + content_padding: Optional[PaddingValue] = None + """ + The padding for the input decoration's container. + """ + + dense: Optional[bool] = None + """ + Whether this control is part of a dense form (ie, uses less vertical space). + """ + + filled: Optional[bool] = None + """ + If `True` the decoration's container is filled with theme \ + :attr:`~flet.FormFieldControl.fill_color`. + + If `filled=None` (the default), then it is implicitly set to `True` when at least + one of the following is not `None`: :attr:`~flet.FormFieldControl.fill_color`, + :attr:`~flet.FormFieldControl.focused_bgcolor`, + :attr:`~flet.FormFieldControl.hover_color` and \ + :attr:`~flet.FormFieldControl.bgcolor`. + """ + + fill_color: Optional[ColorValue] = None + """ + Background color of TextField. + + Note: + Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + """ + + focus_color: Optional[ColorValue] = None + """ + TBD + """ + + align_label_with_hint: Optional[bool] = None + """ + TBD + """ + + hover_color: Optional[ColorValue] = None + """ + Background color of TextField when hovered. + + Note: + Will not be visible if :attr:`~flet.FormFieldControl.filled` is `False`. + """ + + hint_text: Optional[str] = None + """ + Text that suggests what sort of input the field accepts. + + Displayed on top of the input when the it's empty and either + (a) :attr:`~flet.FormFieldControl.label` is `None` or (b) the input has the focus. + """ + + hint_style: Optional[TextStyle] = None + """ + The text style to use for :attr:`~flet.FormFieldControl.hint_text`. + """ + + hint_fade_duration: Optional[DurationValue] = None + """ + TBD + """ + + hint_max_lines: Optional[int] = None + """ + TBD + """ + + helper: Optional[StrOrControl] = None + """ + Text that provides context about the input's value, such as how the value will be \ + used. + + If non-null, the text is displayed below the input decorator, in the same location + as :attr:`~flet.FormFieldControl.error`. If a non-null + :attr:`~flet.FormFieldControl.error` value is specified then the helper text is not + shown. + """ + + helper_style: Optional[TextStyle] = None + """ + The text style to use for :attr:`~flet.FormFieldControl.helper`. + """ + + helper_max_lines: Optional[int] = None + """ + TBD + """ + + counter: Optional[StrOrControl] = None + """ + A `Control` to place below the line as a character count. + + If `None` or an empty string then nothing will appear in the counter's location. + """ + + counter_style: Optional[TextStyle] = None + """ + The text style to use for `counter`. + """ + + error: Optional[StrOrControl] = None + """ + Text that appears below the input border. + + If non-null, the border's color animates to red + and the :attr:`~flet.FormFieldControl.helper` is not shown. + """ + + error_style: Optional[TextStyle] = None + """ + The text style to use for :attr:`~flet.FormFieldControl.error`. + """ + + error_max_lines: Optional[int] = None + """ + TBD + """ + + prefix: Optional[StrOrControl] = None + """ + A `Control` to place on the line before the input. + + It appears after the :attr:`~flet.FormFieldControl.prefix_icon`, if both are \ + specified. + + This can be used, for example, to add some padding to text that would otherwise be + specified using `prefix`, or to add a custom control in front of the input. + The control's baseline is lined up with the input baseline. + """ + + prefix_icon: Optional[IconDataOrControl] = None + """ + An icon that appears before the editable part of the text field, within the \ + decoration's container. + + If :attr:`~flet.FormFieldControl.prefix` is specified and visible, + this icon will appear to its left. + """ + + prefix_icon_size_constraints: Optional[BoxConstraints] = None + """ + TBD + """ + + prefix_style: Optional[TextStyle] = None + """ + The text style to use for :attr:`~flet.FormFieldControl.prefix`. + """ + + suffix: Optional[StrOrControl] = None + """ + A `Control` to place on the line after the input. + + It appears before the :attr:`~flet.FormFieldControl.suffix_icon`, + if both are specified. + + This can be used, for example, to add some padding to the text that would otherwise + be specified using `suffix`, or to add a custom control after the input. + The control's baseline is lined up with the input baseline. + """ + + suffix_icon: Optional[IconDataOrControl] = None + """ + An icon that appears after the editable part of the text field and after the \ + :attr:`~flet.FormFieldControl.suffix`, within the decoration's container. + """ + + suffix_icon_size_constraints: Optional[BoxConstraints] = None + """ + TBD + """ + + size_constraints: Optional[BoxConstraints] = None + """ + TBD + """ + + collapsed: Optional[bool] = None + """ + TBD + """ + + fit_parent_size: Optional[bool] = None + """ + TBD + """ + + suffix_style: Optional[TextStyle] = None + """ + The text style to use for :attr:`~flet.FormFieldControl.suffix`. + """ + + async def focus(self): + """ + Request focus for this control. + + Example: + ```python + async def main(page: ft.Page): + page.add(ctf := ft.TextField()) + await ctf.focus() + ``` + """ + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/material/icon_button.py b/sdk/python/packages/flet/src/flet/controls/material/icon_button.py new file mode 100644 index 0000000000..d507d817f0 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/icon_button.py @@ -0,0 +1,285 @@ +from dataclasses import field +from typing import Annotated, Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.alignment import Alignment +from flet.controls.base_control import control +from flet.controls.box import BoxConstraints +from flet.controls.buttons import ButtonStyle +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + MouseCursor, + Number, + Url, + VisualDensity, +) +from flet.utils.validation import V + +__all__ = [ + "FilledIconButton", + "FilledTonalIconButton", + "IconButton", + "OutlinedIconButton", +] + + +@control("IconButton") +class IconButton(LayoutControl, AdaptiveControl): + """ + An icon button is a round button with an icon in the middle that reacts to touches \ + by filling with color (ink). + + Icon buttons are commonly used in the toolbars, but they can be used in many other + places as well. + + ```python + ft.IconButton(icon=ft.Icons.FAVORITE, icon_color=ft.Colors.PRIMARY) + ``` + """ + + icon: Optional[IconDataOrControl] = None + """ + An icon to be shown in this button. + """ + + icon_color: Optional[ColorValue] = None + """ + The foreground color of the :attr:`~flet.IconButton.icon`. + """ + + icon_size: Optional[Number] = None + """ + The :attr:`~flet.IconButton.icon`'s size in virtual pixels. + + Defaults to `24`. + """ + + selected: Optional[bool] = None + """ + The optional selection state of this button. + + If this property is not set, the button will behave as a normal push button, + otherwise, the button will toggle between showing :attr:`~flet.IconButton.icon` + (when `False`), and :attr:`~flet.IconButton.selected_icon` (when `True`). + """ + + selected_icon: Optional[IconDataOrControl] = None + """ + The icon to be shown in this button for the 'selected' state. + """ + + selected_icon_color: Optional[ColorValue] = None + """ + The icon color for the 'selected' state of this button. + """ + + bgcolor: Optional[ColorValue] = field(default=None, metadata={"skip": True}) + """ + The background color of this button. + """ + + highlight_color: Optional[ColorValue] = None + """ + The color of this button when it is pressed. + The highlight fades in quickly as this button is pressed/held down. + """ + + style: Optional[ButtonStyle] = None + """ + Customizes this button's appearance. + + Note: + - Only honoured in Material 3 design (:attr:`flet.Theme.use_material3` is \ + `True`). + - If :attr:`flet.Theme.use_material3` is `True`, + any parameters defined in style will be overridden by the + corresponding parameters in this button. + For example, if icon button :attr:`~flet.IconButton.visual_density` + is set to :attr:`flet.VisualDensity.STANDARD` and + style's :attr:`~flet.ButtonStyle.visual_density` is + set to :attr:`flet.VisualDensity.COMPACT`, \ + :attr:`flet.VisualDensity.STANDARD` + will be used. + """ + + autofocus: bool = False + """ + Whether this control will be provided initial focus. If there is more than one \ + control on a page with autofocus set, then the first one added to the page will \ + get focus. + """ + + disabled_color: Optional[ColorValue] = None + """ + The color to use for the icon inside the button when disabled. + """ + + hover_color: Optional[ColorValue] = None + """ + The color of this button when hovered. + """ + + focus_color: Optional[ColorValue] = None + """ + The color of this button when in focus. + """ + + splash_color: Optional[ColorValue] = None + """ + The primary color of this button when it is in the pressed state. + """ + + splash_radius: Annotated[ + Optional[Number], + V.gt(0), + ] = None + """ + The splash radius. + + Note: + This value is honoured only when in Material 2 + (:attr:`flet.Theme.use_material3` is `False`). + + Raises: + ValueError: If it is not strictly greater than `0`. + """ + + alignment: Optional[Alignment] = None + """ + Defines how the icon is positioned within this button. + + Defaults to :attr:`flet.Alignment.CENTER`. + """ + + padding: Optional[PaddingValue] = None + """ + Defines the padding around this button. The entire padded icon will react to input \ + gestures. + + Defaults to `Padding.all(8)`. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. + On Android, for example, setting this to `True` produce a click sound and a + long-press will produce a short vibration. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`~flet.IconButton.on_click` event callback is provided, + it is fired after that. + """ + + mouse_cursor: Optional[MouseCursor] = field(default=None, metadata={"skip": True}) + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + control. + """ + + visual_density: Optional[VisualDensity] = field( + default=None, metadata={"skip": True} + ) + """ + Defines how compact this button's layout will be. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Size constraints for this button. + """ + + on_click: Optional[ControlEventHandler["IconButton"]] = None + """ + Called when a user clicks this button. + """ + + on_long_press: Optional[ControlEventHandler["IconButton"]] = None + """ + Called when the button is long-pressed. + """ + + on_hover: Optional[ControlEventHandler["IconButton"]] = None + """ + Called when the button is hovered. + """ + + on_focus: Optional[ControlEventHandler["IconButton"]] = None + """ + Called when this button has received focus. + """ + + on_blur: Optional[ControlEventHandler["IconButton"]] = None + """ + Called when this button has lost focus. + """ + + def before_update(self): + super().before_update() + if ( + self.style is not None + or self.bgcolor is not None + or self.visual_density is not None + or self.mouse_cursor is not None + ): + self._internals["style"] = (self.style or ButtonStyle()).copy( + bgcolor=self.bgcolor, + visual_density=self.visual_density, + mouse_cursor=self.mouse_cursor, + ) + else: + self._internals.pop("style", None) + + async def focus(self): + """ + Moves focus to this button. + """ + await self._invoke_method("focus") + + +@control("FilledIconButton") +class FilledIconButton(IconButton): + """ + A filled variant of :class:`~flet.IconButton`. + + Filled icon buttons have higher visual impact and should be used for high emphasis + actions, such as turning off a microphone or camera. + + ```python + ft.FilledIconButton(icon=ft.Icons.CHECK) + ``` + """ + + +@control("FilledTonalIconButton") +class FilledTonalIconButton(IconButton): + """ + A filled tonal variant of :class:`~flet.IconButton`. + + Filled tonal icon buttons are a middle ground between filled and + outlined icon buttons. They're useful in contexts where the button requires + slightly more emphasis than an outline would give, such as a secondary action + paired with a high emphasis action. + + ```python + ft.FilledTonalIconButton(icon=ft.Icons.CHECK) + ``` + """ + + +@control("OutlinedIconButton") +class OutlinedIconButton(IconButton): + """ + An outlined variant of :class:`~flet.IconButton`. + + Outlined icon buttons are medium-emphasis buttons. + They're useful when an icon button needs more emphasis than a + standard icon button but less than a filled or filled tonal icon button. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/icons.json b/sdk/python/packages/flet/src/flet/controls/material/icons.json new file mode 100644 index 0000000000..0a6ebe91c8 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/icons.json @@ -0,0 +1 @@ +{"ABC":65536,"ABC_OUTLINED":65537,"ABC_ROUNDED":65538,"ABC_SHARP":65539,"AC_UNIT":65540,"AC_UNIT_OUTLINED":65541,"AC_UNIT_ROUNDED":65542,"AC_UNIT_SHARP":65543,"ACCESS_ALARM":65544,"ACCESS_ALARM_OUTLINED":65545,"ACCESS_ALARM_ROUNDED":65546,"ACCESS_ALARM_SHARP":65547,"ACCESS_ALARMS":65548,"ACCESS_ALARMS_OUTLINED":65549,"ACCESS_ALARMS_ROUNDED":65550,"ACCESS_ALARMS_SHARP":65551,"ACCESS_TIME":65552,"ACCESS_TIME_FILLED":65553,"ACCESS_TIME_FILLED_OUTLINED":65554,"ACCESS_TIME_FILLED_ROUNDED":65555,"ACCESS_TIME_FILLED_SHARP":65556,"ACCESS_TIME_OUTLINED":65557,"ACCESS_TIME_ROUNDED":65558,"ACCESS_TIME_SHARP":65559,"ACCESSIBILITY":65560,"ACCESSIBILITY_NEW":65561,"ACCESSIBILITY_NEW_OUTLINED":65562,"ACCESSIBILITY_NEW_ROUNDED":65563,"ACCESSIBILITY_NEW_SHARP":65564,"ACCESSIBILITY_OUTLINED":65565,"ACCESSIBILITY_ROUNDED":65566,"ACCESSIBILITY_SHARP":65567,"ACCESSIBLE":65568,"ACCESSIBLE_FORWARD":65569,"ACCESSIBLE_FORWARD_OUTLINED":65570,"ACCESSIBLE_FORWARD_ROUNDED":65571,"ACCESSIBLE_FORWARD_SHARP":65572,"ACCESSIBLE_OUTLINED":65573,"ACCESSIBLE_ROUNDED":65574,"ACCESSIBLE_SHARP":65575,"ACCOUNT_BALANCE":65576,"ACCOUNT_BALANCE_OUTLINED":65577,"ACCOUNT_BALANCE_ROUNDED":65578,"ACCOUNT_BALANCE_SHARP":65579,"ACCOUNT_BALANCE_WALLET":65580,"ACCOUNT_BALANCE_WALLET_OUTLINED":65581,"ACCOUNT_BALANCE_WALLET_ROUNDED":65582,"ACCOUNT_BALANCE_WALLET_SHARP":65583,"ACCOUNT_BOX":65584,"ACCOUNT_BOX_OUTLINED":65585,"ACCOUNT_BOX_ROUNDED":65586,"ACCOUNT_BOX_SHARP":65587,"ACCOUNT_CIRCLE":65588,"ACCOUNT_CIRCLE_OUTLINED":65589,"ACCOUNT_CIRCLE_ROUNDED":65590,"ACCOUNT_CIRCLE_SHARP":65591,"ACCOUNT_TREE":65592,"ACCOUNT_TREE_OUTLINED":65593,"ACCOUNT_TREE_ROUNDED":65594,"ACCOUNT_TREE_SHARP":65595,"AD_UNITS":65596,"AD_UNITS_OUTLINED":65597,"AD_UNITS_ROUNDED":65598,"AD_UNITS_SHARP":65599,"ADB":65600,"ADB_OUTLINED":65601,"ADB_ROUNDED":65602,"ADB_SHARP":65603,"ADD":65604,"ADD_A_PHOTO":65605,"ADD_A_PHOTO_OUTLINED":65606,"ADD_A_PHOTO_ROUNDED":65607,"ADD_A_PHOTO_SHARP":65608,"ADD_ALARM":65609,"ADD_ALARM_OUTLINED":65610,"ADD_ALARM_ROUNDED":65611,"ADD_ALARM_SHARP":65612,"ADD_ALERT":65613,"ADD_ALERT_OUTLINED":65614,"ADD_ALERT_ROUNDED":65615,"ADD_ALERT_SHARP":65616,"ADD_BOX":65617,"ADD_BOX_OUTLINED":65618,"ADD_BOX_ROUNDED":65619,"ADD_BOX_SHARP":65620,"ADD_BUSINESS":65621,"ADD_BUSINESS_OUTLINED":65622,"ADD_BUSINESS_ROUNDED":65623,"ADD_BUSINESS_SHARP":65624,"ADD_CALL":65625,"ADD_CARD":65626,"ADD_CARD_OUTLINED":65627,"ADD_CARD_ROUNDED":65628,"ADD_CARD_SHARP":65629,"ADD_CHART":65630,"ADD_CHART_OUTLINED":65631,"ADD_CHART_ROUNDED":65632,"ADD_CHART_SHARP":65633,"ADD_CIRCLE":65634,"ADD_CIRCLE_OUTLINE":65635,"ADD_CIRCLE_OUTLINE_OUTLINED":65636,"ADD_CIRCLE_OUTLINE_ROUNDED":65637,"ADD_CIRCLE_OUTLINE_SHARP":65638,"ADD_CIRCLE_OUTLINED":65639,"ADD_CIRCLE_ROUNDED":65640,"ADD_CIRCLE_SHARP":65641,"ADD_COMMENT":65642,"ADD_COMMENT_OUTLINED":65643,"ADD_COMMENT_ROUNDED":65644,"ADD_COMMENT_SHARP":65645,"ADD_HOME":65646,"ADD_HOME_OUTLINED":65647,"ADD_HOME_ROUNDED":65648,"ADD_HOME_SHARP":65649,"ADD_HOME_WORK":65650,"ADD_HOME_WORK_OUTLINED":65651,"ADD_HOME_WORK_ROUNDED":65652,"ADD_HOME_WORK_SHARP":65653,"ADD_IC_CALL":65654,"ADD_IC_CALL_OUTLINED":65655,"ADD_IC_CALL_ROUNDED":65656,"ADD_IC_CALL_SHARP":65657,"ADD_LINK":65658,"ADD_LINK_OUTLINED":65659,"ADD_LINK_ROUNDED":65660,"ADD_LINK_SHARP":65661,"ADD_LOCATION":65662,"ADD_LOCATION_ALT":65663,"ADD_LOCATION_ALT_OUTLINED":65664,"ADD_LOCATION_ALT_ROUNDED":65665,"ADD_LOCATION_ALT_SHARP":65666,"ADD_LOCATION_OUTLINED":65667,"ADD_LOCATION_ROUNDED":65668,"ADD_LOCATION_SHARP":65669,"ADD_MODERATOR":65670,"ADD_MODERATOR_OUTLINED":65671,"ADD_MODERATOR_ROUNDED":65672,"ADD_MODERATOR_SHARP":65673,"ADD_OUTLINED":65674,"ADD_PHOTO_ALTERNATE":65675,"ADD_PHOTO_ALTERNATE_OUTLINED":65676,"ADD_PHOTO_ALTERNATE_ROUNDED":65677,"ADD_PHOTO_ALTERNATE_SHARP":65678,"ADD_REACTION":65679,"ADD_REACTION_OUTLINED":65680,"ADD_REACTION_ROUNDED":65681,"ADD_REACTION_SHARP":65682,"ADD_ROAD":65683,"ADD_ROAD_OUTLINED":65684,"ADD_ROAD_ROUNDED":65685,"ADD_ROAD_SHARP":65686,"ADD_ROUNDED":65687,"ADD_SHARP":65688,"ADD_SHOPPING_CART":65689,"ADD_SHOPPING_CART_OUTLINED":65690,"ADD_SHOPPING_CART_ROUNDED":65691,"ADD_SHOPPING_CART_SHARP":65692,"ADD_TASK":65693,"ADD_TASK_OUTLINED":65694,"ADD_TASK_ROUNDED":65695,"ADD_TASK_SHARP":65696,"ADD_TO_DRIVE":65697,"ADD_TO_DRIVE_OUTLINED":65698,"ADD_TO_DRIVE_ROUNDED":65699,"ADD_TO_DRIVE_SHARP":65700,"ADD_TO_HOME_SCREEN":65701,"ADD_TO_HOME_SCREEN_OUTLINED":65702,"ADD_TO_HOME_SCREEN_ROUNDED":65703,"ADD_TO_HOME_SCREEN_SHARP":65704,"ADD_TO_PHOTOS":65705,"ADD_TO_PHOTOS_OUTLINED":65706,"ADD_TO_PHOTOS_ROUNDED":65707,"ADD_TO_PHOTOS_SHARP":65708,"ADD_TO_QUEUE":65709,"ADD_TO_QUEUE_OUTLINED":65710,"ADD_TO_QUEUE_ROUNDED":65711,"ADD_TO_QUEUE_SHARP":65712,"ADDCHART":65713,"ADDCHART_OUTLINED":65714,"ADDCHART_ROUNDED":65715,"ADDCHART_SHARP":65716,"ADF_SCANNER":65717,"ADF_SCANNER_OUTLINED":65718,"ADF_SCANNER_ROUNDED":65719,"ADF_SCANNER_SHARP":65720,"ADJUST":65721,"ADJUST_OUTLINED":65722,"ADJUST_ROUNDED":65723,"ADJUST_SHARP":65724,"ADMIN_PANEL_SETTINGS":65725,"ADMIN_PANEL_SETTINGS_OUTLINED":65726,"ADMIN_PANEL_SETTINGS_ROUNDED":65727,"ADMIN_PANEL_SETTINGS_SHARP":65728,"ADOBE":65729,"ADOBE_OUTLINED":65730,"ADOBE_ROUNDED":65731,"ADOBE_SHARP":65732,"ADS_CLICK":65733,"ADS_CLICK_OUTLINED":65734,"ADS_CLICK_ROUNDED":65735,"ADS_CLICK_SHARP":65736,"AGRICULTURE":65737,"AGRICULTURE_OUTLINED":65738,"AGRICULTURE_ROUNDED":65739,"AGRICULTURE_SHARP":65740,"AIR":65741,"AIR_OUTLINED":65742,"AIR_ROUNDED":65743,"AIR_SHARP":65744,"AIRLINE_SEAT_FLAT":65745,"AIRLINE_SEAT_FLAT_ANGLED":65746,"AIRLINE_SEAT_FLAT_ANGLED_OUTLINED":65747,"AIRLINE_SEAT_FLAT_ANGLED_ROUNDED":65748,"AIRLINE_SEAT_FLAT_ANGLED_SHARP":65749,"AIRLINE_SEAT_FLAT_OUTLINED":65750,"AIRLINE_SEAT_FLAT_ROUNDED":65751,"AIRLINE_SEAT_FLAT_SHARP":65752,"AIRLINE_SEAT_INDIVIDUAL_SUITE":65753,"AIRLINE_SEAT_INDIVIDUAL_SUITE_OUTLINED":65754,"AIRLINE_SEAT_INDIVIDUAL_SUITE_ROUNDED":65755,"AIRLINE_SEAT_INDIVIDUAL_SUITE_SHARP":65756,"AIRLINE_SEAT_LEGROOM_EXTRA":65757,"AIRLINE_SEAT_LEGROOM_EXTRA_OUTLINED":65758,"AIRLINE_SEAT_LEGROOM_EXTRA_ROUNDED":65759,"AIRLINE_SEAT_LEGROOM_EXTRA_SHARP":65760,"AIRLINE_SEAT_LEGROOM_NORMAL":65761,"AIRLINE_SEAT_LEGROOM_NORMAL_OUTLINED":65762,"AIRLINE_SEAT_LEGROOM_NORMAL_ROUNDED":65763,"AIRLINE_SEAT_LEGROOM_NORMAL_SHARP":65764,"AIRLINE_SEAT_LEGROOM_REDUCED":65765,"AIRLINE_SEAT_LEGROOM_REDUCED_OUTLINED":65766,"AIRLINE_SEAT_LEGROOM_REDUCED_ROUNDED":65767,"AIRLINE_SEAT_LEGROOM_REDUCED_SHARP":65768,"AIRLINE_SEAT_RECLINE_EXTRA":65769,"AIRLINE_SEAT_RECLINE_EXTRA_OUTLINED":65770,"AIRLINE_SEAT_RECLINE_EXTRA_ROUNDED":65771,"AIRLINE_SEAT_RECLINE_EXTRA_SHARP":65772,"AIRLINE_SEAT_RECLINE_NORMAL":65773,"AIRLINE_SEAT_RECLINE_NORMAL_OUTLINED":65774,"AIRLINE_SEAT_RECLINE_NORMAL_ROUNDED":65775,"AIRLINE_SEAT_RECLINE_NORMAL_SHARP":65776,"AIRLINE_STOPS":65777,"AIRLINE_STOPS_OUTLINED":65778,"AIRLINE_STOPS_ROUNDED":65779,"AIRLINE_STOPS_SHARP":65780,"AIRLINES":65781,"AIRLINES_OUTLINED":65782,"AIRLINES_ROUNDED":65783,"AIRLINES_SHARP":65784,"AIRPLANE_TICKET":65785,"AIRPLANE_TICKET_OUTLINED":65786,"AIRPLANE_TICKET_ROUNDED":65787,"AIRPLANE_TICKET_SHARP":65788,"AIRPLANEMODE_ACTIVE":65789,"AIRPLANEMODE_ACTIVE_OUTLINED":65790,"AIRPLANEMODE_ACTIVE_ROUNDED":65791,"AIRPLANEMODE_ACTIVE_SHARP":65792,"AIRPLANEMODE_INACTIVE":65793,"AIRPLANEMODE_INACTIVE_OUTLINED":65794,"AIRPLANEMODE_INACTIVE_ROUNDED":65795,"AIRPLANEMODE_INACTIVE_SHARP":65796,"AIRPLANEMODE_OFF":65797,"AIRPLANEMODE_OFF_OUTLINED":65798,"AIRPLANEMODE_OFF_ROUNDED":65799,"AIRPLANEMODE_OFF_SHARP":65800,"AIRPLANEMODE_ON":65801,"AIRPLANEMODE_ON_OUTLINED":65802,"AIRPLANEMODE_ON_ROUNDED":65803,"AIRPLANEMODE_ON_SHARP":65804,"AIRPLAY":65805,"AIRPLAY_OUTLINED":65806,"AIRPLAY_ROUNDED":65807,"AIRPLAY_SHARP":65808,"AIRPORT_SHUTTLE":65809,"AIRPORT_SHUTTLE_OUTLINED":65810,"AIRPORT_SHUTTLE_ROUNDED":65811,"AIRPORT_SHUTTLE_SHARP":65812,"ALARM":65813,"ALARM_ADD":65814,"ALARM_ADD_OUTLINED":65815,"ALARM_ADD_ROUNDED":65816,"ALARM_ADD_SHARP":65817,"ALARM_OFF":65818,"ALARM_OFF_OUTLINED":65819,"ALARM_OFF_ROUNDED":65820,"ALARM_OFF_SHARP":65821,"ALARM_ON":65822,"ALARM_ON_OUTLINED":65823,"ALARM_ON_ROUNDED":65824,"ALARM_ON_SHARP":65825,"ALARM_OUTLINED":65826,"ALARM_ROUNDED":65827,"ALARM_SHARP":65828,"ALBUM":65829,"ALBUM_OUTLINED":65830,"ALBUM_ROUNDED":65831,"ALBUM_SHARP":65832,"ALIGN_HORIZONTAL_CENTER":65833,"ALIGN_HORIZONTAL_CENTER_OUTLINED":65834,"ALIGN_HORIZONTAL_CENTER_ROUNDED":65835,"ALIGN_HORIZONTAL_CENTER_SHARP":65836,"ALIGN_HORIZONTAL_LEFT":65837,"ALIGN_HORIZONTAL_LEFT_OUTLINED":65838,"ALIGN_HORIZONTAL_LEFT_ROUNDED":65839,"ALIGN_HORIZONTAL_LEFT_SHARP":65840,"ALIGN_HORIZONTAL_RIGHT":65841,"ALIGN_HORIZONTAL_RIGHT_OUTLINED":65842,"ALIGN_HORIZONTAL_RIGHT_ROUNDED":65843,"ALIGN_HORIZONTAL_RIGHT_SHARP":65844,"ALIGN_VERTICAL_BOTTOM":65845,"ALIGN_VERTICAL_BOTTOM_OUTLINED":65846,"ALIGN_VERTICAL_BOTTOM_ROUNDED":65847,"ALIGN_VERTICAL_BOTTOM_SHARP":65848,"ALIGN_VERTICAL_CENTER":65849,"ALIGN_VERTICAL_CENTER_OUTLINED":65850,"ALIGN_VERTICAL_CENTER_ROUNDED":65851,"ALIGN_VERTICAL_CENTER_SHARP":65852,"ALIGN_VERTICAL_TOP":65853,"ALIGN_VERTICAL_TOP_OUTLINED":65854,"ALIGN_VERTICAL_TOP_ROUNDED":65855,"ALIGN_VERTICAL_TOP_SHARP":65856,"ALL_INBOX":65857,"ALL_INBOX_OUTLINED":65858,"ALL_INBOX_ROUNDED":65859,"ALL_INBOX_SHARP":65860,"ALL_INCLUSIVE":65861,"ALL_INCLUSIVE_OUTLINED":65862,"ALL_INCLUSIVE_ROUNDED":65863,"ALL_INCLUSIVE_SHARP":65864,"ALL_OUT":65865,"ALL_OUT_OUTLINED":65866,"ALL_OUT_ROUNDED":65867,"ALL_OUT_SHARP":65868,"ALT_ROUTE":65869,"ALT_ROUTE_OUTLINED":65870,"ALT_ROUTE_ROUNDED":65871,"ALT_ROUTE_SHARP":65872,"ALTERNATE_EMAIL":65873,"ALTERNATE_EMAIL_OUTLINED":65874,"ALTERNATE_EMAIL_ROUNDED":65875,"ALTERNATE_EMAIL_SHARP":65876,"AMP_STORIES":65877,"AMP_STORIES_OUTLINED":65878,"AMP_STORIES_ROUNDED":65879,"AMP_STORIES_SHARP":65880,"ANALYTICS":65881,"ANALYTICS_OUTLINED":65882,"ANALYTICS_ROUNDED":65883,"ANALYTICS_SHARP":65884,"ANCHOR":65885,"ANCHOR_OUTLINED":65886,"ANCHOR_ROUNDED":65887,"ANCHOR_SHARP":65888,"ANDROID":65889,"ANDROID_OUTLINED":65890,"ANDROID_ROUNDED":65891,"ANDROID_SHARP":65892,"ANIMATION":65893,"ANIMATION_OUTLINED":65894,"ANIMATION_ROUNDED":65895,"ANIMATION_SHARP":65896,"ANNOUNCEMENT":65897,"ANNOUNCEMENT_OUTLINED":65898,"ANNOUNCEMENT_ROUNDED":65899,"ANNOUNCEMENT_SHARP":65900,"AOD":65901,"AOD_OUTLINED":65902,"AOD_ROUNDED":65903,"AOD_SHARP":65904,"APARTMENT":65905,"APARTMENT_OUTLINED":65906,"APARTMENT_ROUNDED":65907,"APARTMENT_SHARP":65908,"API":65909,"API_OUTLINED":65910,"API_ROUNDED":65911,"API_SHARP":65912,"APP_BLOCKING":65913,"APP_BLOCKING_OUTLINED":65914,"APP_BLOCKING_ROUNDED":65915,"APP_BLOCKING_SHARP":65916,"APP_REGISTRATION":65917,"APP_REGISTRATION_OUTLINED":65918,"APP_REGISTRATION_ROUNDED":65919,"APP_REGISTRATION_SHARP":65920,"APP_SETTINGS_ALT":65921,"APP_SETTINGS_ALT_OUTLINED":65922,"APP_SETTINGS_ALT_ROUNDED":65923,"APP_SETTINGS_ALT_SHARP":65924,"APP_SHORTCUT":65925,"APP_SHORTCUT_OUTLINED":65926,"APP_SHORTCUT_ROUNDED":65927,"APP_SHORTCUT_SHARP":65928,"APPLE":65929,"APPLE_OUTLINED":65930,"APPLE_ROUNDED":65931,"APPLE_SHARP":65932,"APPROVAL":65933,"APPROVAL_OUTLINED":65934,"APPROVAL_ROUNDED":65935,"APPROVAL_SHARP":65936,"APPS":65937,"APPS_OUTAGE":65938,"APPS_OUTAGE_OUTLINED":65939,"APPS_OUTAGE_ROUNDED":65940,"APPS_OUTAGE_SHARP":65941,"APPS_OUTLINED":65942,"APPS_ROUNDED":65943,"APPS_SHARP":65944,"ARCHITECTURE":65945,"ARCHITECTURE_OUTLINED":65946,"ARCHITECTURE_ROUNDED":65947,"ARCHITECTURE_SHARP":65948,"ARCHIVE":65949,"ARCHIVE_OUTLINED":65950,"ARCHIVE_ROUNDED":65951,"ARCHIVE_SHARP":65952,"AREA_CHART":65953,"AREA_CHART_OUTLINED":65954,"AREA_CHART_ROUNDED":65955,"AREA_CHART_SHARP":65956,"ARROW_BACK":65957,"ARROW_BACK_IOS":65958,"ARROW_BACK_IOS_NEW":65959,"ARROW_BACK_IOS_NEW_OUTLINED":65960,"ARROW_BACK_IOS_NEW_ROUNDED":65961,"ARROW_BACK_IOS_NEW_SHARP":65962,"ARROW_BACK_IOS_OUTLINED":65963,"ARROW_BACK_IOS_ROUNDED":65964,"ARROW_BACK_IOS_SHARP":65965,"ARROW_BACK_OUTLINED":65966,"ARROW_BACK_ROUNDED":65967,"ARROW_BACK_SHARP":65968,"ARROW_CIRCLE_DOWN":65969,"ARROW_CIRCLE_DOWN_OUTLINED":65970,"ARROW_CIRCLE_DOWN_ROUNDED":65971,"ARROW_CIRCLE_DOWN_SHARP":65972,"ARROW_CIRCLE_LEFT":65973,"ARROW_CIRCLE_LEFT_OUTLINED":65974,"ARROW_CIRCLE_LEFT_ROUNDED":65975,"ARROW_CIRCLE_LEFT_SHARP":65976,"ARROW_CIRCLE_RIGHT":65977,"ARROW_CIRCLE_RIGHT_OUTLINED":65978,"ARROW_CIRCLE_RIGHT_ROUNDED":65979,"ARROW_CIRCLE_RIGHT_SHARP":65980,"ARROW_CIRCLE_UP":65981,"ARROW_CIRCLE_UP_OUTLINED":65982,"ARROW_CIRCLE_UP_ROUNDED":65983,"ARROW_CIRCLE_UP_SHARP":65984,"ARROW_DOWNWARD":65985,"ARROW_DOWNWARD_OUTLINED":65986,"ARROW_DOWNWARD_ROUNDED":65987,"ARROW_DOWNWARD_SHARP":65988,"ARROW_DROP_DOWN":65989,"ARROW_DROP_DOWN_CIRCLE":65990,"ARROW_DROP_DOWN_CIRCLE_OUTLINED":65991,"ARROW_DROP_DOWN_CIRCLE_ROUNDED":65992,"ARROW_DROP_DOWN_CIRCLE_SHARP":65993,"ARROW_DROP_DOWN_OUTLINED":65994,"ARROW_DROP_DOWN_ROUNDED":65995,"ARROW_DROP_DOWN_SHARP":65996,"ARROW_DROP_UP":65997,"ARROW_DROP_UP_OUTLINED":65998,"ARROW_DROP_UP_ROUNDED":65999,"ARROW_DROP_UP_SHARP":66000,"ARROW_FORWARD":66001,"ARROW_FORWARD_IOS":66002,"ARROW_FORWARD_IOS_OUTLINED":66003,"ARROW_FORWARD_IOS_ROUNDED":66004,"ARROW_FORWARD_IOS_SHARP":66005,"ARROW_FORWARD_OUTLINED":66006,"ARROW_FORWARD_ROUNDED":66007,"ARROW_FORWARD_SHARP":66008,"ARROW_LEFT":66009,"ARROW_LEFT_OUTLINED":66010,"ARROW_LEFT_ROUNDED":66011,"ARROW_LEFT_SHARP":66012,"ARROW_OUTWARD":66013,"ARROW_OUTWARD_OUTLINED":66014,"ARROW_OUTWARD_ROUNDED":66015,"ARROW_OUTWARD_SHARP":66016,"ARROW_RIGHT":66017,"ARROW_RIGHT_ALT":66018,"ARROW_RIGHT_ALT_OUTLINED":66019,"ARROW_RIGHT_ALT_ROUNDED":66020,"ARROW_RIGHT_ALT_SHARP":66021,"ARROW_RIGHT_OUTLINED":66022,"ARROW_RIGHT_ROUNDED":66023,"ARROW_RIGHT_SHARP":66024,"ARROW_UPWARD":66025,"ARROW_UPWARD_OUTLINED":66026,"ARROW_UPWARD_ROUNDED":66027,"ARROW_UPWARD_SHARP":66028,"ART_TRACK":66029,"ART_TRACK_OUTLINED":66030,"ART_TRACK_ROUNDED":66031,"ART_TRACK_SHARP":66032,"ARTICLE":66033,"ARTICLE_OUTLINED":66034,"ARTICLE_ROUNDED":66035,"ARTICLE_SHARP":66036,"ASPECT_RATIO":66037,"ASPECT_RATIO_OUTLINED":66038,"ASPECT_RATIO_ROUNDED":66039,"ASPECT_RATIO_SHARP":66040,"ASSESSMENT":66041,"ASSESSMENT_OUTLINED":66042,"ASSESSMENT_ROUNDED":66043,"ASSESSMENT_SHARP":66044,"ASSIGNMENT":66045,"ASSIGNMENT_ADD":66046,"ASSIGNMENT_IND":66047,"ASSIGNMENT_IND_OUTLINED":66048,"ASSIGNMENT_IND_ROUNDED":66049,"ASSIGNMENT_IND_SHARP":66050,"ASSIGNMENT_LATE":66051,"ASSIGNMENT_LATE_OUTLINED":66052,"ASSIGNMENT_LATE_ROUNDED":66053,"ASSIGNMENT_LATE_SHARP":66054,"ASSIGNMENT_OUTLINED":66055,"ASSIGNMENT_RETURN":66056,"ASSIGNMENT_RETURN_OUTLINED":66057,"ASSIGNMENT_RETURN_ROUNDED":66058,"ASSIGNMENT_RETURN_SHARP":66059,"ASSIGNMENT_RETURNED":66060,"ASSIGNMENT_RETURNED_OUTLINED":66061,"ASSIGNMENT_RETURNED_ROUNDED":66062,"ASSIGNMENT_RETURNED_SHARP":66063,"ASSIGNMENT_ROUNDED":66064,"ASSIGNMENT_SHARP":66065,"ASSIGNMENT_TURNED_IN":66066,"ASSIGNMENT_TURNED_IN_OUTLINED":66067,"ASSIGNMENT_TURNED_IN_ROUNDED":66068,"ASSIGNMENT_TURNED_IN_SHARP":66069,"ASSIST_WALKER":66070,"ASSIST_WALKER_OUTLINED":66071,"ASSIST_WALKER_ROUNDED":66072,"ASSIST_WALKER_SHARP":66073,"ASSISTANT":66074,"ASSISTANT_DIRECTION":66075,"ASSISTANT_DIRECTION_OUTLINED":66076,"ASSISTANT_DIRECTION_ROUNDED":66077,"ASSISTANT_DIRECTION_SHARP":66078,"ASSISTANT_NAVIGATION":66079,"ASSISTANT_OUTLINED":66080,"ASSISTANT_PHOTO":66081,"ASSISTANT_PHOTO_OUTLINED":66082,"ASSISTANT_PHOTO_ROUNDED":66083,"ASSISTANT_PHOTO_SHARP":66084,"ASSISTANT_ROUNDED":66085,"ASSISTANT_SHARP":66086,"ASSURED_WORKLOAD":66087,"ASSURED_WORKLOAD_OUTLINED":66088,"ASSURED_WORKLOAD_ROUNDED":66089,"ASSURED_WORKLOAD_SHARP":66090,"ATM":66091,"ATM_OUTLINED":66092,"ATM_ROUNDED":66093,"ATM_SHARP":66094,"ATTACH_EMAIL":66095,"ATTACH_EMAIL_OUTLINED":66096,"ATTACH_EMAIL_ROUNDED":66097,"ATTACH_EMAIL_SHARP":66098,"ATTACH_FILE":66099,"ATTACH_FILE_OUTLINED":66100,"ATTACH_FILE_ROUNDED":66101,"ATTACH_FILE_SHARP":66102,"ATTACH_MONEY":66103,"ATTACH_MONEY_OUTLINED":66104,"ATTACH_MONEY_ROUNDED":66105,"ATTACH_MONEY_SHARP":66106,"ATTACHMENT":66107,"ATTACHMENT_OUTLINED":66108,"ATTACHMENT_ROUNDED":66109,"ATTACHMENT_SHARP":66110,"ATTRACTIONS":66111,"ATTRACTIONS_OUTLINED":66112,"ATTRACTIONS_ROUNDED":66113,"ATTRACTIONS_SHARP":66114,"ATTRIBUTION":66115,"ATTRIBUTION_OUTLINED":66116,"ATTRIBUTION_ROUNDED":66117,"ATTRIBUTION_SHARP":66118,"AUDIO_FILE":66119,"AUDIO_FILE_OUTLINED":66120,"AUDIO_FILE_ROUNDED":66121,"AUDIO_FILE_SHARP":66122,"AUDIOTRACK":66123,"AUDIOTRACK_OUTLINED":66124,"AUDIOTRACK_ROUNDED":66125,"AUDIOTRACK_SHARP":66126,"AUTO_AWESOME":66127,"AUTO_AWESOME_MOSAIC":66128,"AUTO_AWESOME_MOSAIC_OUTLINED":66129,"AUTO_AWESOME_MOSAIC_ROUNDED":66130,"AUTO_AWESOME_MOSAIC_SHARP":66131,"AUTO_AWESOME_MOTION":66132,"AUTO_AWESOME_MOTION_OUTLINED":66133,"AUTO_AWESOME_MOTION_ROUNDED":66134,"AUTO_AWESOME_MOTION_SHARP":66135,"AUTO_AWESOME_OUTLINED":66136,"AUTO_AWESOME_ROUNDED":66137,"AUTO_AWESOME_SHARP":66138,"AUTO_DELETE":66139,"AUTO_DELETE_OUTLINED":66140,"AUTO_DELETE_ROUNDED":66141,"AUTO_DELETE_SHARP":66142,"AUTO_FIX_HIGH":66143,"AUTO_FIX_HIGH_OUTLINED":66144,"AUTO_FIX_HIGH_ROUNDED":66145,"AUTO_FIX_HIGH_SHARP":66146,"AUTO_FIX_NORMAL":66147,"AUTO_FIX_NORMAL_OUTLINED":66148,"AUTO_FIX_NORMAL_ROUNDED":66149,"AUTO_FIX_NORMAL_SHARP":66150,"AUTO_FIX_OFF":66151,"AUTO_FIX_OFF_OUTLINED":66152,"AUTO_FIX_OFF_ROUNDED":66153,"AUTO_FIX_OFF_SHARP":66154,"AUTO_GRAPH":66155,"AUTO_GRAPH_OUTLINED":66156,"AUTO_GRAPH_ROUNDED":66157,"AUTO_GRAPH_SHARP":66158,"AUTO_MODE":66159,"AUTO_MODE_OUTLINED":66160,"AUTO_MODE_ROUNDED":66161,"AUTO_MODE_SHARP":66162,"AUTO_STORIES":66163,"AUTO_STORIES_OUTLINED":66164,"AUTO_STORIES_ROUNDED":66165,"AUTO_STORIES_SHARP":66166,"AUTOFPS_SELECT":66167,"AUTOFPS_SELECT_OUTLINED":66168,"AUTOFPS_SELECT_ROUNDED":66169,"AUTOFPS_SELECT_SHARP":66170,"AUTORENEW":66171,"AUTORENEW_OUTLINED":66172,"AUTORENEW_ROUNDED":66173,"AUTORENEW_SHARP":66174,"AV_TIMER":66175,"AV_TIMER_OUTLINED":66176,"AV_TIMER_ROUNDED":66177,"AV_TIMER_SHARP":66178,"BABY_CHANGING_STATION":66179,"BABY_CHANGING_STATION_OUTLINED":66180,"BABY_CHANGING_STATION_ROUNDED":66181,"BABY_CHANGING_STATION_SHARP":66182,"BACK_HAND":66183,"BACK_HAND_OUTLINED":66184,"BACK_HAND_ROUNDED":66185,"BACK_HAND_SHARP":66186,"BACKPACK":66187,"BACKPACK_OUTLINED":66188,"BACKPACK_ROUNDED":66189,"BACKPACK_SHARP":66190,"BACKSPACE":66191,"BACKSPACE_OUTLINED":66192,"BACKSPACE_ROUNDED":66193,"BACKSPACE_SHARP":66194,"BACKUP":66195,"BACKUP_OUTLINED":66196,"BACKUP_ROUNDED":66197,"BACKUP_SHARP":66198,"BACKUP_TABLE":66199,"BACKUP_TABLE_OUTLINED":66200,"BACKUP_TABLE_ROUNDED":66201,"BACKUP_TABLE_SHARP":66202,"BADGE":66203,"BADGE_OUTLINED":66204,"BADGE_ROUNDED":66205,"BADGE_SHARP":66206,"BAKERY_DINING":66207,"BAKERY_DINING_OUTLINED":66208,"BAKERY_DINING_ROUNDED":66209,"BAKERY_DINING_SHARP":66210,"BALANCE":66211,"BALANCE_OUTLINED":66212,"BALANCE_ROUNDED":66213,"BALANCE_SHARP":66214,"BALCONY":66215,"BALCONY_OUTLINED":66216,"BALCONY_ROUNDED":66217,"BALCONY_SHARP":66218,"BALLOT":66219,"BALLOT_OUTLINED":66220,"BALLOT_ROUNDED":66221,"BALLOT_SHARP":66222,"BAR_CHART":66223,"BAR_CHART_OUTLINED":66224,"BAR_CHART_ROUNDED":66225,"BAR_CHART_SHARP":66226,"BARCODE_READER":66227,"BATCH_PREDICTION":66228,"BATCH_PREDICTION_OUTLINED":66229,"BATCH_PREDICTION_ROUNDED":66230,"BATCH_PREDICTION_SHARP":66231,"BATHROOM":66232,"BATHROOM_OUTLINED":66233,"BATHROOM_ROUNDED":66234,"BATHROOM_SHARP":66235,"BATHTUB":66236,"BATHTUB_OUTLINED":66237,"BATHTUB_ROUNDED":66238,"BATHTUB_SHARP":66239,"BATTERY_0_BAR":66240,"BATTERY_0_BAR_OUTLINED":66241,"BATTERY_0_BAR_ROUNDED":66242,"BATTERY_0_BAR_SHARP":66243,"BATTERY_1_BAR":66244,"BATTERY_1_BAR_OUTLINED":66245,"BATTERY_1_BAR_ROUNDED":66246,"BATTERY_1_BAR_SHARP":66247,"BATTERY_2_BAR":66248,"BATTERY_2_BAR_OUTLINED":66249,"BATTERY_2_BAR_ROUNDED":66250,"BATTERY_2_BAR_SHARP":66251,"BATTERY_3_BAR":66252,"BATTERY_3_BAR_OUTLINED":66253,"BATTERY_3_BAR_ROUNDED":66254,"BATTERY_3_BAR_SHARP":66255,"BATTERY_4_BAR":66256,"BATTERY_4_BAR_OUTLINED":66257,"BATTERY_4_BAR_ROUNDED":66258,"BATTERY_4_BAR_SHARP":66259,"BATTERY_5_BAR":66260,"BATTERY_5_BAR_OUTLINED":66261,"BATTERY_5_BAR_ROUNDED":66262,"BATTERY_5_BAR_SHARP":66263,"BATTERY_6_BAR":66264,"BATTERY_6_BAR_OUTLINED":66265,"BATTERY_6_BAR_ROUNDED":66266,"BATTERY_6_BAR_SHARP":66267,"BATTERY_ALERT":66268,"BATTERY_ALERT_OUTLINED":66269,"BATTERY_ALERT_ROUNDED":66270,"BATTERY_ALERT_SHARP":66271,"BATTERY_CHARGING_FULL":66272,"BATTERY_CHARGING_FULL_OUTLINED":66273,"BATTERY_CHARGING_FULL_ROUNDED":66274,"BATTERY_CHARGING_FULL_SHARP":66275,"BATTERY_FULL":66276,"BATTERY_FULL_OUTLINED":66277,"BATTERY_FULL_ROUNDED":66278,"BATTERY_FULL_SHARP":66279,"BATTERY_SAVER":66280,"BATTERY_SAVER_OUTLINED":66281,"BATTERY_SAVER_ROUNDED":66282,"BATTERY_SAVER_SHARP":66283,"BATTERY_STD":66284,"BATTERY_STD_OUTLINED":66285,"BATTERY_STD_ROUNDED":66286,"BATTERY_STD_SHARP":66287,"BATTERY_UNKNOWN":66288,"BATTERY_UNKNOWN_OUTLINED":66289,"BATTERY_UNKNOWN_ROUNDED":66290,"BATTERY_UNKNOWN_SHARP":66291,"BEACH_ACCESS":66292,"BEACH_ACCESS_OUTLINED":66293,"BEACH_ACCESS_ROUNDED":66294,"BEACH_ACCESS_SHARP":66295,"BED":66296,"BED_OUTLINED":66297,"BED_ROUNDED":66298,"BED_SHARP":66299,"BEDROOM_BABY":66300,"BEDROOM_BABY_OUTLINED":66301,"BEDROOM_BABY_ROUNDED":66302,"BEDROOM_BABY_SHARP":66303,"BEDROOM_CHILD":66304,"BEDROOM_CHILD_OUTLINED":66305,"BEDROOM_CHILD_ROUNDED":66306,"BEDROOM_CHILD_SHARP":66307,"BEDROOM_PARENT":66308,"BEDROOM_PARENT_OUTLINED":66309,"BEDROOM_PARENT_ROUNDED":66310,"BEDROOM_PARENT_SHARP":66311,"BEDTIME":66312,"BEDTIME_OFF":66313,"BEDTIME_OFF_OUTLINED":66314,"BEDTIME_OFF_ROUNDED":66315,"BEDTIME_OFF_SHARP":66316,"BEDTIME_OUTLINED":66317,"BEDTIME_ROUNDED":66318,"BEDTIME_SHARP":66319,"BEENHERE":66320,"BEENHERE_OUTLINED":66321,"BEENHERE_ROUNDED":66322,"BEENHERE_SHARP":66323,"BENTO":66324,"BENTO_OUTLINED":66325,"BENTO_ROUNDED":66326,"BENTO_SHARP":66327,"BIKE_SCOOTER":66328,"BIKE_SCOOTER_OUTLINED":66329,"BIKE_SCOOTER_ROUNDED":66330,"BIKE_SCOOTER_SHARP":66331,"BIOTECH":66332,"BIOTECH_OUTLINED":66333,"BIOTECH_ROUNDED":66334,"BIOTECH_SHARP":66335,"BLENDER":66336,"BLENDER_OUTLINED":66337,"BLENDER_ROUNDED":66338,"BLENDER_SHARP":66339,"BLIND":66340,"BLIND_OUTLINED":66341,"BLIND_ROUNDED":66342,"BLIND_SHARP":66343,"BLINDS":66344,"BLINDS_CLOSED":66345,"BLINDS_CLOSED_OUTLINED":66346,"BLINDS_CLOSED_ROUNDED":66347,"BLINDS_CLOSED_SHARP":66348,"BLINDS_OUTLINED":66349,"BLINDS_ROUNDED":66350,"BLINDS_SHARP":66351,"BLOCK":66352,"BLOCK_FLIPPED":66353,"BLOCK_OUTLINED":66354,"BLOCK_ROUNDED":66355,"BLOCK_SHARP":66356,"BLOODTYPE":66357,"BLOODTYPE_OUTLINED":66358,"BLOODTYPE_ROUNDED":66359,"BLOODTYPE_SHARP":66360,"BLUETOOTH":66361,"BLUETOOTH_AUDIO":66362,"BLUETOOTH_AUDIO_OUTLINED":66363,"BLUETOOTH_AUDIO_ROUNDED":66364,"BLUETOOTH_AUDIO_SHARP":66365,"BLUETOOTH_CONNECTED":66366,"BLUETOOTH_CONNECTED_OUTLINED":66367,"BLUETOOTH_CONNECTED_ROUNDED":66368,"BLUETOOTH_CONNECTED_SHARP":66369,"BLUETOOTH_DISABLED":66370,"BLUETOOTH_DISABLED_OUTLINED":66371,"BLUETOOTH_DISABLED_ROUNDED":66372,"BLUETOOTH_DISABLED_SHARP":66373,"BLUETOOTH_DRIVE":66374,"BLUETOOTH_DRIVE_OUTLINED":66375,"BLUETOOTH_DRIVE_ROUNDED":66376,"BLUETOOTH_DRIVE_SHARP":66377,"BLUETOOTH_OUTLINED":66378,"BLUETOOTH_ROUNDED":66379,"BLUETOOTH_SEARCHING":66380,"BLUETOOTH_SEARCHING_OUTLINED":66381,"BLUETOOTH_SEARCHING_ROUNDED":66382,"BLUETOOTH_SEARCHING_SHARP":66383,"BLUETOOTH_SHARP":66384,"BLUR_CIRCULAR":66385,"BLUR_CIRCULAR_OUTLINED":66386,"BLUR_CIRCULAR_ROUNDED":66387,"BLUR_CIRCULAR_SHARP":66388,"BLUR_LINEAR":66389,"BLUR_LINEAR_OUTLINED":66390,"BLUR_LINEAR_ROUNDED":66391,"BLUR_LINEAR_SHARP":66392,"BLUR_OFF":66393,"BLUR_OFF_OUTLINED":66394,"BLUR_OFF_ROUNDED":66395,"BLUR_OFF_SHARP":66396,"BLUR_ON":66397,"BLUR_ON_OUTLINED":66398,"BLUR_ON_ROUNDED":66399,"BLUR_ON_SHARP":66400,"BOLT":66401,"BOLT_OUTLINED":66402,"BOLT_ROUNDED":66403,"BOLT_SHARP":66404,"BOOK":66405,"BOOK_ONLINE":66406,"BOOK_ONLINE_OUTLINED":66407,"BOOK_ONLINE_ROUNDED":66408,"BOOK_ONLINE_SHARP":66409,"BOOK_OUTLINED":66410,"BOOK_ROUNDED":66411,"BOOK_SHARP":66412,"BOOKMARK":66413,"BOOKMARK_ADD":66414,"BOOKMARK_ADD_OUTLINED":66415,"BOOKMARK_ADD_ROUNDED":66416,"BOOKMARK_ADD_SHARP":66417,"BOOKMARK_ADDED":66418,"BOOKMARK_ADDED_OUTLINED":66419,"BOOKMARK_ADDED_ROUNDED":66420,"BOOKMARK_ADDED_SHARP":66421,"BOOKMARK_BORDER":66422,"BOOKMARK_BORDER_OUTLINED":66423,"BOOKMARK_BORDER_ROUNDED":66424,"BOOKMARK_BORDER_SHARP":66425,"BOOKMARK_OUTLINE":66426,"BOOKMARK_OUTLINE_OUTLINED":66427,"BOOKMARK_OUTLINE_ROUNDED":66428,"BOOKMARK_OUTLINE_SHARP":66429,"BOOKMARK_OUTLINED":66430,"BOOKMARK_REMOVE":66431,"BOOKMARK_REMOVE_OUTLINED":66432,"BOOKMARK_REMOVE_ROUNDED":66433,"BOOKMARK_REMOVE_SHARP":66434,"BOOKMARK_ROUNDED":66435,"BOOKMARK_SHARP":66436,"BOOKMARKS":66437,"BOOKMARKS_OUTLINED":66438,"BOOKMARKS_ROUNDED":66439,"BOOKMARKS_SHARP":66440,"BORDER_ALL":66441,"BORDER_ALL_OUTLINED":66442,"BORDER_ALL_ROUNDED":66443,"BORDER_ALL_SHARP":66444,"BORDER_BOTTOM":66445,"BORDER_BOTTOM_OUTLINED":66446,"BORDER_BOTTOM_ROUNDED":66447,"BORDER_BOTTOM_SHARP":66448,"BORDER_CLEAR":66449,"BORDER_CLEAR_OUTLINED":66450,"BORDER_CLEAR_ROUNDED":66451,"BORDER_CLEAR_SHARP":66452,"BORDER_COLOR":66453,"BORDER_COLOR_OUTLINED":66454,"BORDER_COLOR_ROUNDED":66455,"BORDER_COLOR_SHARP":66456,"BORDER_HORIZONTAL":66457,"BORDER_HORIZONTAL_OUTLINED":66458,"BORDER_HORIZONTAL_ROUNDED":66459,"BORDER_HORIZONTAL_SHARP":66460,"BORDER_INNER":66461,"BORDER_INNER_OUTLINED":66462,"BORDER_INNER_ROUNDED":66463,"BORDER_INNER_SHARP":66464,"BORDER_LEFT":66465,"BORDER_LEFT_OUTLINED":66466,"BORDER_LEFT_ROUNDED":66467,"BORDER_LEFT_SHARP":66468,"BORDER_OUTER":66469,"BORDER_OUTER_OUTLINED":66470,"BORDER_OUTER_ROUNDED":66471,"BORDER_OUTER_SHARP":66472,"BORDER_RIGHT":66473,"BORDER_RIGHT_OUTLINED":66474,"BORDER_RIGHT_ROUNDED":66475,"BORDER_RIGHT_SHARP":66476,"BORDER_STYLE":66477,"BORDER_STYLE_OUTLINED":66478,"BORDER_STYLE_ROUNDED":66479,"BORDER_STYLE_SHARP":66480,"BORDER_TOP":66481,"BORDER_TOP_OUTLINED":66482,"BORDER_TOP_ROUNDED":66483,"BORDER_TOP_SHARP":66484,"BORDER_VERTICAL":66485,"BORDER_VERTICAL_OUTLINED":66486,"BORDER_VERTICAL_ROUNDED":66487,"BORDER_VERTICAL_SHARP":66488,"BOY":66489,"BOY_OUTLINED":66490,"BOY_ROUNDED":66491,"BOY_SHARP":66492,"BRANDING_WATERMARK":66493,"BRANDING_WATERMARK_OUTLINED":66494,"BRANDING_WATERMARK_ROUNDED":66495,"BRANDING_WATERMARK_SHARP":66496,"BREAKFAST_DINING":66497,"BREAKFAST_DINING_OUTLINED":66498,"BREAKFAST_DINING_ROUNDED":66499,"BREAKFAST_DINING_SHARP":66500,"BRIGHTNESS_1":66501,"BRIGHTNESS_1_OUTLINED":66502,"BRIGHTNESS_1_ROUNDED":66503,"BRIGHTNESS_1_SHARP":66504,"BRIGHTNESS_2":66505,"BRIGHTNESS_2_OUTLINED":66506,"BRIGHTNESS_2_ROUNDED":66507,"BRIGHTNESS_2_SHARP":66508,"BRIGHTNESS_3":66509,"BRIGHTNESS_3_OUTLINED":66510,"BRIGHTNESS_3_ROUNDED":66511,"BRIGHTNESS_3_SHARP":66512,"BRIGHTNESS_4":66513,"BRIGHTNESS_4_OUTLINED":66514,"BRIGHTNESS_4_ROUNDED":66515,"BRIGHTNESS_4_SHARP":66516,"BRIGHTNESS_5":66517,"BRIGHTNESS_5_OUTLINED":66518,"BRIGHTNESS_5_ROUNDED":66519,"BRIGHTNESS_5_SHARP":66520,"BRIGHTNESS_6":66521,"BRIGHTNESS_6_OUTLINED":66522,"BRIGHTNESS_6_ROUNDED":66523,"BRIGHTNESS_6_SHARP":66524,"BRIGHTNESS_7":66525,"BRIGHTNESS_7_OUTLINED":66526,"BRIGHTNESS_7_ROUNDED":66527,"BRIGHTNESS_7_SHARP":66528,"BRIGHTNESS_AUTO":66529,"BRIGHTNESS_AUTO_OUTLINED":66530,"BRIGHTNESS_AUTO_ROUNDED":66531,"BRIGHTNESS_AUTO_SHARP":66532,"BRIGHTNESS_HIGH":66533,"BRIGHTNESS_HIGH_OUTLINED":66534,"BRIGHTNESS_HIGH_ROUNDED":66535,"BRIGHTNESS_HIGH_SHARP":66536,"BRIGHTNESS_LOW":66537,"BRIGHTNESS_LOW_OUTLINED":66538,"BRIGHTNESS_LOW_ROUNDED":66539,"BRIGHTNESS_LOW_SHARP":66540,"BRIGHTNESS_MEDIUM":66541,"BRIGHTNESS_MEDIUM_OUTLINED":66542,"BRIGHTNESS_MEDIUM_ROUNDED":66543,"BRIGHTNESS_MEDIUM_SHARP":66544,"BROADCAST_ON_HOME":66545,"BROADCAST_ON_HOME_OUTLINED":66546,"BROADCAST_ON_HOME_ROUNDED":66547,"BROADCAST_ON_HOME_SHARP":66548,"BROADCAST_ON_PERSONAL":66549,"BROADCAST_ON_PERSONAL_OUTLINED":66550,"BROADCAST_ON_PERSONAL_ROUNDED":66551,"BROADCAST_ON_PERSONAL_SHARP":66552,"BROKEN_IMAGE":66553,"BROKEN_IMAGE_OUTLINED":66554,"BROKEN_IMAGE_ROUNDED":66555,"BROKEN_IMAGE_SHARP":66556,"BROWSE_GALLERY":66557,"BROWSE_GALLERY_OUTLINED":66558,"BROWSE_GALLERY_ROUNDED":66559,"BROWSE_GALLERY_SHARP":66560,"BROWSER_NOT_SUPPORTED":66561,"BROWSER_NOT_SUPPORTED_OUTLINED":66562,"BROWSER_NOT_SUPPORTED_ROUNDED":66563,"BROWSER_NOT_SUPPORTED_SHARP":66564,"BROWSER_UPDATED":66565,"BROWSER_UPDATED_OUTLINED":66566,"BROWSER_UPDATED_ROUNDED":66567,"BROWSER_UPDATED_SHARP":66568,"BRUNCH_DINING":66569,"BRUNCH_DINING_OUTLINED":66570,"BRUNCH_DINING_ROUNDED":66571,"BRUNCH_DINING_SHARP":66572,"BRUSH":66573,"BRUSH_OUTLINED":66574,"BRUSH_ROUNDED":66575,"BRUSH_SHARP":66576,"BUBBLE_CHART":66577,"BUBBLE_CHART_OUTLINED":66578,"BUBBLE_CHART_ROUNDED":66579,"BUBBLE_CHART_SHARP":66580,"BUG_REPORT":66581,"BUG_REPORT_OUTLINED":66582,"BUG_REPORT_ROUNDED":66583,"BUG_REPORT_SHARP":66584,"BUILD":66585,"BUILD_CIRCLE":66586,"BUILD_CIRCLE_OUTLINED":66587,"BUILD_CIRCLE_ROUNDED":66588,"BUILD_CIRCLE_SHARP":66589,"BUILD_OUTLINED":66590,"BUILD_ROUNDED":66591,"BUILD_SHARP":66592,"BUNGALOW":66593,"BUNGALOW_OUTLINED":66594,"BUNGALOW_ROUNDED":66595,"BUNGALOW_SHARP":66596,"BURST_MODE":66597,"BURST_MODE_OUTLINED":66598,"BURST_MODE_ROUNDED":66599,"BURST_MODE_SHARP":66600,"BUS_ALERT":66601,"BUS_ALERT_OUTLINED":66602,"BUS_ALERT_ROUNDED":66603,"BUS_ALERT_SHARP":66604,"BUSINESS":66605,"BUSINESS_CENTER":66606,"BUSINESS_CENTER_OUTLINED":66607,"BUSINESS_CENTER_ROUNDED":66608,"BUSINESS_CENTER_SHARP":66609,"BUSINESS_OUTLINED":66610,"BUSINESS_ROUNDED":66611,"BUSINESS_SHARP":66612,"CABIN":66613,"CABIN_OUTLINED":66614,"CABIN_ROUNDED":66615,"CABIN_SHARP":66616,"CABLE":66617,"CABLE_OUTLINED":66618,"CABLE_ROUNDED":66619,"CABLE_SHARP":66620,"CACHED":66621,"CACHED_OUTLINED":66622,"CACHED_ROUNDED":66623,"CACHED_SHARP":66624,"CAKE":66625,"CAKE_OUTLINED":66626,"CAKE_ROUNDED":66627,"CAKE_SHARP":66628,"CALCULATE":66629,"CALCULATE_OUTLINED":66630,"CALCULATE_ROUNDED":66631,"CALCULATE_SHARP":66632,"CALENDAR_MONTH":66633,"CALENDAR_MONTH_OUTLINED":66634,"CALENDAR_MONTH_ROUNDED":66635,"CALENDAR_MONTH_SHARP":66636,"CALENDAR_TODAY":66637,"CALENDAR_TODAY_OUTLINED":66638,"CALENDAR_TODAY_ROUNDED":66639,"CALENDAR_TODAY_SHARP":66640,"CALENDAR_VIEW_DAY":66641,"CALENDAR_VIEW_DAY_OUTLINED":66642,"CALENDAR_VIEW_DAY_ROUNDED":66643,"CALENDAR_VIEW_DAY_SHARP":66644,"CALENDAR_VIEW_MONTH":66645,"CALENDAR_VIEW_MONTH_OUTLINED":66646,"CALENDAR_VIEW_MONTH_ROUNDED":66647,"CALENDAR_VIEW_MONTH_SHARP":66648,"CALENDAR_VIEW_WEEK":66649,"CALENDAR_VIEW_WEEK_OUTLINED":66650,"CALENDAR_VIEW_WEEK_ROUNDED":66651,"CALENDAR_VIEW_WEEK_SHARP":66652,"CALL":66653,"CALL_END":66654,"CALL_END_OUTLINED":66655,"CALL_END_ROUNDED":66656,"CALL_END_SHARP":66657,"CALL_MADE":66658,"CALL_MADE_OUTLINED":66659,"CALL_MADE_ROUNDED":66660,"CALL_MADE_SHARP":66661,"CALL_MERGE":66662,"CALL_MERGE_OUTLINED":66663,"CALL_MERGE_ROUNDED":66664,"CALL_MERGE_SHARP":66665,"CALL_MISSED":66666,"CALL_MISSED_OUTGOING":66667,"CALL_MISSED_OUTGOING_OUTLINED":66668,"CALL_MISSED_OUTGOING_ROUNDED":66669,"CALL_MISSED_OUTGOING_SHARP":66670,"CALL_MISSED_OUTLINED":66671,"CALL_MISSED_ROUNDED":66672,"CALL_MISSED_SHARP":66673,"CALL_OUTLINED":66674,"CALL_RECEIVED":66675,"CALL_RECEIVED_OUTLINED":66676,"CALL_RECEIVED_ROUNDED":66677,"CALL_RECEIVED_SHARP":66678,"CALL_ROUNDED":66679,"CALL_SHARP":66680,"CALL_SPLIT":66681,"CALL_SPLIT_OUTLINED":66682,"CALL_SPLIT_ROUNDED":66683,"CALL_SPLIT_SHARP":66684,"CALL_TO_ACTION":66685,"CALL_TO_ACTION_OUTLINED":66686,"CALL_TO_ACTION_ROUNDED":66687,"CALL_TO_ACTION_SHARP":66688,"CAMERA":66689,"CAMERA_ALT":66690,"CAMERA_ALT_OUTLINED":66691,"CAMERA_ALT_ROUNDED":66692,"CAMERA_ALT_SHARP":66693,"CAMERA_ENHANCE":66694,"CAMERA_ENHANCE_OUTLINED":66695,"CAMERA_ENHANCE_ROUNDED":66696,"CAMERA_ENHANCE_SHARP":66697,"CAMERA_FRONT":66698,"CAMERA_FRONT_OUTLINED":66699,"CAMERA_FRONT_ROUNDED":66700,"CAMERA_FRONT_SHARP":66701,"CAMERA_INDOOR":66702,"CAMERA_INDOOR_OUTLINED":66703,"CAMERA_INDOOR_ROUNDED":66704,"CAMERA_INDOOR_SHARP":66705,"CAMERA_OUTDOOR":66706,"CAMERA_OUTDOOR_OUTLINED":66707,"CAMERA_OUTDOOR_ROUNDED":66708,"CAMERA_OUTDOOR_SHARP":66709,"CAMERA_OUTLINED":66710,"CAMERA_REAR":66711,"CAMERA_REAR_OUTLINED":66712,"CAMERA_REAR_ROUNDED":66713,"CAMERA_REAR_SHARP":66714,"CAMERA_ROLL":66715,"CAMERA_ROLL_OUTLINED":66716,"CAMERA_ROLL_ROUNDED":66717,"CAMERA_ROLL_SHARP":66718,"CAMERA_ROUNDED":66719,"CAMERA_SHARP":66720,"CAMERASWITCH":66721,"CAMERASWITCH_OUTLINED":66722,"CAMERASWITCH_ROUNDED":66723,"CAMERASWITCH_SHARP":66724,"CAMPAIGN":66725,"CAMPAIGN_OUTLINED":66726,"CAMPAIGN_ROUNDED":66727,"CAMPAIGN_SHARP":66728,"CANCEL":66729,"CANCEL_OUTLINED":66730,"CANCEL_PRESENTATION":66731,"CANCEL_PRESENTATION_OUTLINED":66732,"CANCEL_PRESENTATION_ROUNDED":66733,"CANCEL_PRESENTATION_SHARP":66734,"CANCEL_ROUNDED":66735,"CANCEL_SCHEDULE_SEND":66736,"CANCEL_SCHEDULE_SEND_OUTLINED":66737,"CANCEL_SCHEDULE_SEND_ROUNDED":66738,"CANCEL_SCHEDULE_SEND_SHARP":66739,"CANCEL_SHARP":66740,"CANDLESTICK_CHART":66741,"CANDLESTICK_CHART_OUTLINED":66742,"CANDLESTICK_CHART_ROUNDED":66743,"CANDLESTICK_CHART_SHARP":66744,"CAR_CRASH":66745,"CAR_CRASH_OUTLINED":66746,"CAR_CRASH_ROUNDED":66747,"CAR_CRASH_SHARP":66748,"CAR_RENTAL":66749,"CAR_RENTAL_OUTLINED":66750,"CAR_RENTAL_ROUNDED":66751,"CAR_RENTAL_SHARP":66752,"CAR_REPAIR":66753,"CAR_REPAIR_OUTLINED":66754,"CAR_REPAIR_ROUNDED":66755,"CAR_REPAIR_SHARP":66756,"CARD_GIFTCARD":66757,"CARD_GIFTCARD_OUTLINED":66758,"CARD_GIFTCARD_ROUNDED":66759,"CARD_GIFTCARD_SHARP":66760,"CARD_MEMBERSHIP":66761,"CARD_MEMBERSHIP_OUTLINED":66762,"CARD_MEMBERSHIP_ROUNDED":66763,"CARD_MEMBERSHIP_SHARP":66764,"CARD_TRAVEL":66765,"CARD_TRAVEL_OUTLINED":66766,"CARD_TRAVEL_ROUNDED":66767,"CARD_TRAVEL_SHARP":66768,"CARPENTER":66769,"CARPENTER_OUTLINED":66770,"CARPENTER_ROUNDED":66771,"CARPENTER_SHARP":66772,"CASES":66773,"CASES_OUTLINED":66774,"CASES_ROUNDED":66775,"CASES_SHARP":66776,"CASINO":66777,"CASINO_OUTLINED":66778,"CASINO_ROUNDED":66779,"CASINO_SHARP":66780,"CAST":66781,"CAST_CONNECTED":66782,"CAST_CONNECTED_OUTLINED":66783,"CAST_CONNECTED_ROUNDED":66784,"CAST_CONNECTED_SHARP":66785,"CAST_FOR_EDUCATION":66786,"CAST_FOR_EDUCATION_OUTLINED":66787,"CAST_FOR_EDUCATION_ROUNDED":66788,"CAST_FOR_EDUCATION_SHARP":66789,"CAST_OUTLINED":66790,"CAST_ROUNDED":66791,"CAST_SHARP":66792,"CASTLE":66793,"CASTLE_OUTLINED":66794,"CASTLE_ROUNDED":66795,"CASTLE_SHARP":66796,"CATCHING_POKEMON":66797,"CATCHING_POKEMON_OUTLINED":66798,"CATCHING_POKEMON_ROUNDED":66799,"CATCHING_POKEMON_SHARP":66800,"CATEGORY":66801,"CATEGORY_OUTLINED":66802,"CATEGORY_ROUNDED":66803,"CATEGORY_SHARP":66804,"CELEBRATION":66805,"CELEBRATION_OUTLINED":66806,"CELEBRATION_ROUNDED":66807,"CELEBRATION_SHARP":66808,"CELL_TOWER":66809,"CELL_TOWER_OUTLINED":66810,"CELL_TOWER_ROUNDED":66811,"CELL_TOWER_SHARP":66812,"CELL_WIFI":66813,"CELL_WIFI_OUTLINED":66814,"CELL_WIFI_ROUNDED":66815,"CELL_WIFI_SHARP":66816,"CENTER_FOCUS_STRONG":66817,"CENTER_FOCUS_STRONG_OUTLINED":66818,"CENTER_FOCUS_STRONG_ROUNDED":66819,"CENTER_FOCUS_STRONG_SHARP":66820,"CENTER_FOCUS_WEAK":66821,"CENTER_FOCUS_WEAK_OUTLINED":66822,"CENTER_FOCUS_WEAK_ROUNDED":66823,"CENTER_FOCUS_WEAK_SHARP":66824,"CHAIR":66825,"CHAIR_ALT":66826,"CHAIR_ALT_OUTLINED":66827,"CHAIR_ALT_ROUNDED":66828,"CHAIR_ALT_SHARP":66829,"CHAIR_OUTLINED":66830,"CHAIR_ROUNDED":66831,"CHAIR_SHARP":66832,"CHALET":66833,"CHALET_OUTLINED":66834,"CHALET_ROUNDED":66835,"CHALET_SHARP":66836,"CHANGE_CIRCLE":66837,"CHANGE_CIRCLE_OUTLINED":66838,"CHANGE_CIRCLE_ROUNDED":66839,"CHANGE_CIRCLE_SHARP":66840,"CHANGE_HISTORY":66841,"CHANGE_HISTORY_OUTLINED":66842,"CHANGE_HISTORY_ROUNDED":66843,"CHANGE_HISTORY_SHARP":66844,"CHARGING_STATION":66845,"CHARGING_STATION_OUTLINED":66846,"CHARGING_STATION_ROUNDED":66847,"CHARGING_STATION_SHARP":66848,"CHAT":66849,"CHAT_BUBBLE":66850,"CHAT_BUBBLE_OUTLINE":66851,"CHAT_BUBBLE_OUTLINE_OUTLINED":66852,"CHAT_BUBBLE_OUTLINE_ROUNDED":66853,"CHAT_BUBBLE_OUTLINE_SHARP":66854,"CHAT_BUBBLE_OUTLINED":66855,"CHAT_BUBBLE_ROUNDED":66856,"CHAT_BUBBLE_SHARP":66857,"CHAT_OUTLINED":66858,"CHAT_ROUNDED":66859,"CHAT_SHARP":66860,"CHECK":66861,"CHECK_BOX":66862,"CHECK_BOX_OUTLINE_BLANK":66863,"CHECK_BOX_OUTLINE_BLANK_OUTLINED":66864,"CHECK_BOX_OUTLINE_BLANK_ROUNDED":66865,"CHECK_BOX_OUTLINE_BLANK_SHARP":66866,"CHECK_BOX_OUTLINED":66867,"CHECK_BOX_ROUNDED":66868,"CHECK_BOX_SHARP":66869,"CHECK_CIRCLE":66870,"CHECK_CIRCLE_OUTLINE":66871,"CHECK_CIRCLE_OUTLINE_OUTLINED":66872,"CHECK_CIRCLE_OUTLINE_ROUNDED":66873,"CHECK_CIRCLE_OUTLINE_SHARP":66874,"CHECK_CIRCLE_OUTLINED":66875,"CHECK_CIRCLE_ROUNDED":66876,"CHECK_CIRCLE_SHARP":66877,"CHECK_OUTLINED":66878,"CHECK_ROUNDED":66879,"CHECK_SHARP":66880,"CHECKLIST":66881,"CHECKLIST_OUTLINED":66882,"CHECKLIST_ROUNDED":66883,"CHECKLIST_RTL":66884,"CHECKLIST_RTL_OUTLINED":66885,"CHECKLIST_RTL_ROUNDED":66886,"CHECKLIST_RTL_SHARP":66887,"CHECKLIST_SHARP":66888,"CHECKROOM":66889,"CHECKROOM_OUTLINED":66890,"CHECKROOM_ROUNDED":66891,"CHECKROOM_SHARP":66892,"CHEVRON_LEFT":66893,"CHEVRON_LEFT_OUTLINED":66894,"CHEVRON_LEFT_ROUNDED":66895,"CHEVRON_LEFT_SHARP":66896,"CHEVRON_RIGHT":66897,"CHEVRON_RIGHT_OUTLINED":66898,"CHEVRON_RIGHT_ROUNDED":66899,"CHEVRON_RIGHT_SHARP":66900,"CHILD_CARE":66901,"CHILD_CARE_OUTLINED":66902,"CHILD_CARE_ROUNDED":66903,"CHILD_CARE_SHARP":66904,"CHILD_FRIENDLY":66905,"CHILD_FRIENDLY_OUTLINED":66906,"CHILD_FRIENDLY_ROUNDED":66907,"CHILD_FRIENDLY_SHARP":66908,"CHROME_READER_MODE":66909,"CHROME_READER_MODE_OUTLINED":66910,"CHROME_READER_MODE_ROUNDED":66911,"CHROME_READER_MODE_SHARP":66912,"CHURCH":66913,"CHURCH_OUTLINED":66914,"CHURCH_ROUNDED":66915,"CHURCH_SHARP":66916,"CIRCLE":66917,"CIRCLE_NOTIFICATIONS":66918,"CIRCLE_NOTIFICATIONS_OUTLINED":66919,"CIRCLE_NOTIFICATIONS_ROUNDED":66920,"CIRCLE_NOTIFICATIONS_SHARP":66921,"CIRCLE_OUTLINED":66922,"CIRCLE_ROUNDED":66923,"CIRCLE_SHARP":66924,"CLASS_":66925,"CLASS_OUTLINED":66926,"CLASS_ROUNDED":66927,"CLASS_SHARP":66928,"CLEAN_HANDS":66929,"CLEAN_HANDS_OUTLINED":66930,"CLEAN_HANDS_ROUNDED":66931,"CLEAN_HANDS_SHARP":66932,"CLEANING_SERVICES":66933,"CLEANING_SERVICES_OUTLINED":66934,"CLEANING_SERVICES_ROUNDED":66935,"CLEANING_SERVICES_SHARP":66936,"CLEAR":66937,"CLEAR_ALL":66938,"CLEAR_ALL_OUTLINED":66939,"CLEAR_ALL_ROUNDED":66940,"CLEAR_ALL_SHARP":66941,"CLEAR_OUTLINED":66942,"CLEAR_ROUNDED":66943,"CLEAR_SHARP":66944,"CLOSE":66945,"CLOSE_FULLSCREEN":66946,"CLOSE_FULLSCREEN_OUTLINED":66947,"CLOSE_FULLSCREEN_ROUNDED":66948,"CLOSE_FULLSCREEN_SHARP":66949,"CLOSE_OUTLINED":66950,"CLOSE_ROUNDED":66951,"CLOSE_SHARP":66952,"CLOSED_CAPTION":66953,"CLOSED_CAPTION_DISABLED":66954,"CLOSED_CAPTION_DISABLED_OUTLINED":66955,"CLOSED_CAPTION_DISABLED_ROUNDED":66956,"CLOSED_CAPTION_DISABLED_SHARP":66957,"CLOSED_CAPTION_OFF":66958,"CLOSED_CAPTION_OFF_OUTLINED":66959,"CLOSED_CAPTION_OFF_ROUNDED":66960,"CLOSED_CAPTION_OFF_SHARP":66961,"CLOSED_CAPTION_OUTLINED":66962,"CLOSED_CAPTION_ROUNDED":66963,"CLOSED_CAPTION_SHARP":66964,"CLOUD":66965,"CLOUD_CIRCLE":66966,"CLOUD_CIRCLE_OUTLINED":66967,"CLOUD_CIRCLE_ROUNDED":66968,"CLOUD_CIRCLE_SHARP":66969,"CLOUD_DONE":66970,"CLOUD_DONE_OUTLINED":66971,"CLOUD_DONE_ROUNDED":66972,"CLOUD_DONE_SHARP":66973,"CLOUD_DOWNLOAD":66974,"CLOUD_DOWNLOAD_OUTLINED":66975,"CLOUD_DOWNLOAD_ROUNDED":66976,"CLOUD_DOWNLOAD_SHARP":66977,"CLOUD_OFF":66978,"CLOUD_OFF_OUTLINED":66979,"CLOUD_OFF_ROUNDED":66980,"CLOUD_OFF_SHARP":66981,"CLOUD_OUTLINED":66982,"CLOUD_QUEUE":66983,"CLOUD_QUEUE_OUTLINED":66984,"CLOUD_QUEUE_ROUNDED":66985,"CLOUD_QUEUE_SHARP":66986,"CLOUD_ROUNDED":66987,"CLOUD_SHARP":66988,"CLOUD_SYNC":66989,"CLOUD_SYNC_OUTLINED":66990,"CLOUD_SYNC_ROUNDED":66991,"CLOUD_SYNC_SHARP":66992,"CLOUD_UPLOAD":66993,"CLOUD_UPLOAD_OUTLINED":66994,"CLOUD_UPLOAD_ROUNDED":66995,"CLOUD_UPLOAD_SHARP":66996,"CLOUDY_SNOWING":66997,"CO2":66998,"CO2_OUTLINED":66999,"CO2_ROUNDED":67000,"CO2_SHARP":67001,"CO_PRESENT":67002,"CO_PRESENT_OUTLINED":67003,"CO_PRESENT_ROUNDED":67004,"CO_PRESENT_SHARP":67005,"CODE":67006,"CODE_OFF":67007,"CODE_OFF_OUTLINED":67008,"CODE_OFF_ROUNDED":67009,"CODE_OFF_SHARP":67010,"CODE_OUTLINED":67011,"CODE_ROUNDED":67012,"CODE_SHARP":67013,"COFFEE":67014,"COFFEE_MAKER":67015,"COFFEE_MAKER_OUTLINED":67016,"COFFEE_MAKER_ROUNDED":67017,"COFFEE_MAKER_SHARP":67018,"COFFEE_OUTLINED":67019,"COFFEE_ROUNDED":67020,"COFFEE_SHARP":67021,"COLLECTIONS":67022,"COLLECTIONS_BOOKMARK":67023,"COLLECTIONS_BOOKMARK_OUTLINED":67024,"COLLECTIONS_BOOKMARK_ROUNDED":67025,"COLLECTIONS_BOOKMARK_SHARP":67026,"COLLECTIONS_OUTLINED":67027,"COLLECTIONS_ROUNDED":67028,"COLLECTIONS_SHARP":67029,"COLOR_LENS":67030,"COLOR_LENS_OUTLINED":67031,"COLOR_LENS_ROUNDED":67032,"COLOR_LENS_SHARP":67033,"COLORIZE":67034,"COLORIZE_OUTLINED":67035,"COLORIZE_ROUNDED":67036,"COLORIZE_SHARP":67037,"COMMENT":67038,"COMMENT_BANK":67039,"COMMENT_BANK_OUTLINED":67040,"COMMENT_BANK_ROUNDED":67041,"COMMENT_BANK_SHARP":67042,"COMMENT_OUTLINED":67043,"COMMENT_ROUNDED":67044,"COMMENT_SHARP":67045,"COMMENTS_DISABLED":67046,"COMMENTS_DISABLED_OUTLINED":67047,"COMMENTS_DISABLED_ROUNDED":67048,"COMMENTS_DISABLED_SHARP":67049,"COMMIT":67050,"COMMIT_OUTLINED":67051,"COMMIT_ROUNDED":67052,"COMMIT_SHARP":67053,"COMMUTE":67054,"COMMUTE_OUTLINED":67055,"COMMUTE_ROUNDED":67056,"COMMUTE_SHARP":67057,"COMPARE":67058,"COMPARE_ARROWS":67059,"COMPARE_ARROWS_OUTLINED":67060,"COMPARE_ARROWS_ROUNDED":67061,"COMPARE_ARROWS_SHARP":67062,"COMPARE_OUTLINED":67063,"COMPARE_ROUNDED":67064,"COMPARE_SHARP":67065,"COMPASS_CALIBRATION":67066,"COMPASS_CALIBRATION_OUTLINED":67067,"COMPASS_CALIBRATION_ROUNDED":67068,"COMPASS_CALIBRATION_SHARP":67069,"COMPOST":67070,"COMPOST_OUTLINED":67071,"COMPOST_ROUNDED":67072,"COMPOST_SHARP":67073,"COMPRESS":67074,"COMPRESS_OUTLINED":67075,"COMPRESS_ROUNDED":67076,"COMPRESS_SHARP":67077,"COMPUTER":67078,"COMPUTER_OUTLINED":67079,"COMPUTER_ROUNDED":67080,"COMPUTER_SHARP":67081,"CONFIRMATION_NUM":67082,"CONFIRMATION_NUM_OUTLINED":67083,"CONFIRMATION_NUM_ROUNDED":67084,"CONFIRMATION_NUM_SHARP":67085,"CONFIRMATION_NUMBER":67086,"CONFIRMATION_NUMBER_OUTLINED":67087,"CONFIRMATION_NUMBER_ROUNDED":67088,"CONFIRMATION_NUMBER_SHARP":67089,"CONNECT_WITHOUT_CONTACT":67090,"CONNECT_WITHOUT_CONTACT_OUTLINED":67091,"CONNECT_WITHOUT_CONTACT_ROUNDED":67092,"CONNECT_WITHOUT_CONTACT_SHARP":67093,"CONNECTED_TV":67094,"CONNECTED_TV_OUTLINED":67095,"CONNECTED_TV_ROUNDED":67096,"CONNECTED_TV_SHARP":67097,"CONNECTING_AIRPORTS":67098,"CONNECTING_AIRPORTS_OUTLINED":67099,"CONNECTING_AIRPORTS_ROUNDED":67100,"CONNECTING_AIRPORTS_SHARP":67101,"CONSTRUCTION":67102,"CONSTRUCTION_OUTLINED":67103,"CONSTRUCTION_ROUNDED":67104,"CONSTRUCTION_SHARP":67105,"CONTACT_EMERGENCY":67106,"CONTACT_EMERGENCY_OUTLINED":67107,"CONTACT_EMERGENCY_ROUNDED":67108,"CONTACT_EMERGENCY_SHARP":67109,"CONTACT_MAIL":67110,"CONTACT_MAIL_OUTLINED":67111,"CONTACT_MAIL_ROUNDED":67112,"CONTACT_MAIL_SHARP":67113,"CONTACT_PAGE":67114,"CONTACT_PAGE_OUTLINED":67115,"CONTACT_PAGE_ROUNDED":67116,"CONTACT_PAGE_SHARP":67117,"CONTACT_PHONE":67118,"CONTACT_PHONE_OUTLINED":67119,"CONTACT_PHONE_ROUNDED":67120,"CONTACT_PHONE_SHARP":67121,"CONTACT_SUPPORT":67122,"CONTACT_SUPPORT_OUTLINED":67123,"CONTACT_SUPPORT_ROUNDED":67124,"CONTACT_SUPPORT_SHARP":67125,"CONTACTLESS":67126,"CONTACTLESS_OUTLINED":67127,"CONTACTLESS_ROUNDED":67128,"CONTACTLESS_SHARP":67129,"CONTACTS":67130,"CONTACTS_OUTLINED":67131,"CONTACTS_ROUNDED":67132,"CONTACTS_SHARP":67133,"CONTENT_COPY":67134,"CONTENT_COPY_OUTLINED":67135,"CONTENT_COPY_ROUNDED":67136,"CONTENT_COPY_SHARP":67137,"CONTENT_CUT":67138,"CONTENT_CUT_OUTLINED":67139,"CONTENT_CUT_ROUNDED":67140,"CONTENT_CUT_SHARP":67141,"CONTENT_PASTE":67142,"CONTENT_PASTE_GO":67143,"CONTENT_PASTE_GO_OUTLINED":67144,"CONTENT_PASTE_GO_ROUNDED":67145,"CONTENT_PASTE_GO_SHARP":67146,"CONTENT_PASTE_OFF":67147,"CONTENT_PASTE_OFF_OUTLINED":67148,"CONTENT_PASTE_OFF_ROUNDED":67149,"CONTENT_PASTE_OFF_SHARP":67150,"CONTENT_PASTE_OUTLINED":67151,"CONTENT_PASTE_ROUNDED":67152,"CONTENT_PASTE_SEARCH":67153,"CONTENT_PASTE_SEARCH_OUTLINED":67154,"CONTENT_PASTE_SEARCH_ROUNDED":67155,"CONTENT_PASTE_SEARCH_SHARP":67156,"CONTENT_PASTE_SHARP":67157,"CONTRAST":67158,"CONTRAST_OUTLINED":67159,"CONTRAST_ROUNDED":67160,"CONTRAST_SHARP":67161,"CONTROL_CAMERA":67162,"CONTROL_CAMERA_OUTLINED":67163,"CONTROL_CAMERA_ROUNDED":67164,"CONTROL_CAMERA_SHARP":67165,"CONTROL_POINT":67166,"CONTROL_POINT_DUPLICATE":67167,"CONTROL_POINT_DUPLICATE_OUTLINED":67168,"CONTROL_POINT_DUPLICATE_ROUNDED":67169,"CONTROL_POINT_DUPLICATE_SHARP":67170,"CONTROL_POINT_OUTLINED":67171,"CONTROL_POINT_ROUNDED":67172,"CONTROL_POINT_SHARP":67173,"CONVEYOR_BELT":67174,"COOKIE":67175,"COOKIE_OUTLINED":67176,"COOKIE_ROUNDED":67177,"COOKIE_SHARP":67178,"COPY":67179,"COPY_ALL":67180,"COPY_ALL_OUTLINED":67181,"COPY_ALL_ROUNDED":67182,"COPY_ALL_SHARP":67183,"COPY_OUTLINED":67184,"COPY_ROUNDED":67185,"COPY_SHARP":67186,"COPYRIGHT":67187,"COPYRIGHT_OUTLINED":67188,"COPYRIGHT_ROUNDED":67189,"COPYRIGHT_SHARP":67190,"CORONAVIRUS":67191,"CORONAVIRUS_OUTLINED":67192,"CORONAVIRUS_ROUNDED":67193,"CORONAVIRUS_SHARP":67194,"CORPORATE_FARE":67195,"CORPORATE_FARE_OUTLINED":67196,"CORPORATE_FARE_ROUNDED":67197,"CORPORATE_FARE_SHARP":67198,"COTTAGE":67199,"COTTAGE_OUTLINED":67200,"COTTAGE_ROUNDED":67201,"COTTAGE_SHARP":67202,"COUNTERTOPS":67203,"COUNTERTOPS_OUTLINED":67204,"COUNTERTOPS_ROUNDED":67205,"COUNTERTOPS_SHARP":67206,"CREATE":67207,"CREATE_NEW_FOLDER":67208,"CREATE_NEW_FOLDER_OUTLINED":67209,"CREATE_NEW_FOLDER_ROUNDED":67210,"CREATE_NEW_FOLDER_SHARP":67211,"CREATE_OUTLINED":67212,"CREATE_ROUNDED":67213,"CREATE_SHARP":67214,"CREDIT_CARD":67215,"CREDIT_CARD_OFF":67216,"CREDIT_CARD_OFF_OUTLINED":67217,"CREDIT_CARD_OFF_ROUNDED":67218,"CREDIT_CARD_OFF_SHARP":67219,"CREDIT_CARD_OUTLINED":67220,"CREDIT_CARD_ROUNDED":67221,"CREDIT_CARD_SHARP":67222,"CREDIT_SCORE":67223,"CREDIT_SCORE_OUTLINED":67224,"CREDIT_SCORE_ROUNDED":67225,"CREDIT_SCORE_SHARP":67226,"CRIB":67227,"CRIB_OUTLINED":67228,"CRIB_ROUNDED":67229,"CRIB_SHARP":67230,"CRISIS_ALERT":67231,"CRISIS_ALERT_OUTLINED":67232,"CRISIS_ALERT_ROUNDED":67233,"CRISIS_ALERT_SHARP":67234,"CROP":67235,"CROP_16_9":67236,"CROP_16_9_OUTLINED":67237,"CROP_16_9_ROUNDED":67238,"CROP_16_9_SHARP":67239,"CROP_3_2":67240,"CROP_3_2_OUTLINED":67241,"CROP_3_2_ROUNDED":67242,"CROP_3_2_SHARP":67243,"CROP_5_4":67244,"CROP_5_4_OUTLINED":67245,"CROP_5_4_ROUNDED":67246,"CROP_5_4_SHARP":67247,"CROP_7_5":67248,"CROP_7_5_OUTLINED":67249,"CROP_7_5_ROUNDED":67250,"CROP_7_5_SHARP":67251,"CROP_DIN":67252,"CROP_DIN_OUTLINED":67253,"CROP_DIN_ROUNDED":67254,"CROP_DIN_SHARP":67255,"CROP_FREE":67256,"CROP_FREE_OUTLINED":67257,"CROP_FREE_ROUNDED":67258,"CROP_FREE_SHARP":67259,"CROP_LANDSCAPE":67260,"CROP_LANDSCAPE_OUTLINED":67261,"CROP_LANDSCAPE_ROUNDED":67262,"CROP_LANDSCAPE_SHARP":67263,"CROP_ORIGINAL":67264,"CROP_ORIGINAL_OUTLINED":67265,"CROP_ORIGINAL_ROUNDED":67266,"CROP_ORIGINAL_SHARP":67267,"CROP_OUTLINED":67268,"CROP_PORTRAIT":67269,"CROP_PORTRAIT_OUTLINED":67270,"CROP_PORTRAIT_ROUNDED":67271,"CROP_PORTRAIT_SHARP":67272,"CROP_ROTATE":67273,"CROP_ROTATE_OUTLINED":67274,"CROP_ROTATE_ROUNDED":67275,"CROP_ROTATE_SHARP":67276,"CROP_ROUNDED":67277,"CROP_SHARP":67278,"CROP_SQUARE":67279,"CROP_SQUARE_OUTLINED":67280,"CROP_SQUARE_ROUNDED":67281,"CROP_SQUARE_SHARP":67282,"CRUELTY_FREE":67283,"CRUELTY_FREE_OUTLINED":67284,"CRUELTY_FREE_ROUNDED":67285,"CRUELTY_FREE_SHARP":67286,"CSS":67287,"CSS_OUTLINED":67288,"CSS_ROUNDED":67289,"CSS_SHARP":67290,"CURRENCY_BITCOIN":67291,"CURRENCY_BITCOIN_OUTLINED":67292,"CURRENCY_BITCOIN_ROUNDED":67293,"CURRENCY_BITCOIN_SHARP":67294,"CURRENCY_EXCHANGE":67295,"CURRENCY_EXCHANGE_OUTLINED":67296,"CURRENCY_EXCHANGE_ROUNDED":67297,"CURRENCY_EXCHANGE_SHARP":67298,"CURRENCY_FRANC":67299,"CURRENCY_FRANC_OUTLINED":67300,"CURRENCY_FRANC_ROUNDED":67301,"CURRENCY_FRANC_SHARP":67302,"CURRENCY_LIRA":67303,"CURRENCY_LIRA_OUTLINED":67304,"CURRENCY_LIRA_ROUNDED":67305,"CURRENCY_LIRA_SHARP":67306,"CURRENCY_POUND":67307,"CURRENCY_POUND_OUTLINED":67308,"CURRENCY_POUND_ROUNDED":67309,"CURRENCY_POUND_SHARP":67310,"CURRENCY_RUBLE":67311,"CURRENCY_RUBLE_OUTLINED":67312,"CURRENCY_RUBLE_ROUNDED":67313,"CURRENCY_RUBLE_SHARP":67314,"CURRENCY_RUPEE":67315,"CURRENCY_RUPEE_OUTLINED":67316,"CURRENCY_RUPEE_ROUNDED":67317,"CURRENCY_RUPEE_SHARP":67318,"CURRENCY_YEN":67319,"CURRENCY_YEN_OUTLINED":67320,"CURRENCY_YEN_ROUNDED":67321,"CURRENCY_YEN_SHARP":67322,"CURRENCY_YUAN":67323,"CURRENCY_YUAN_OUTLINED":67324,"CURRENCY_YUAN_ROUNDED":67325,"CURRENCY_YUAN_SHARP":67326,"CURTAINS":67327,"CURTAINS_CLOSED":67328,"CURTAINS_CLOSED_OUTLINED":67329,"CURTAINS_CLOSED_ROUNDED":67330,"CURTAINS_CLOSED_SHARP":67331,"CURTAINS_OUTLINED":67332,"CURTAINS_ROUNDED":67333,"CURTAINS_SHARP":67334,"CUT":67335,"CUT_OUTLINED":67336,"CUT_ROUNDED":67337,"CUT_SHARP":67338,"CYCLONE":67339,"CYCLONE_OUTLINED":67340,"CYCLONE_ROUNDED":67341,"CYCLONE_SHARP":67342,"DANGEROUS":67343,"DANGEROUS_OUTLINED":67344,"DANGEROUS_ROUNDED":67345,"DANGEROUS_SHARP":67346,"DARK_MODE":67347,"DARK_MODE_OUTLINED":67348,"DARK_MODE_ROUNDED":67349,"DARK_MODE_SHARP":67350,"DASHBOARD":67351,"DASHBOARD_CUSTOMIZE":67352,"DASHBOARD_CUSTOMIZE_OUTLINED":67353,"DASHBOARD_CUSTOMIZE_ROUNDED":67354,"DASHBOARD_CUSTOMIZE_SHARP":67355,"DASHBOARD_OUTLINED":67356,"DASHBOARD_ROUNDED":67357,"DASHBOARD_SHARP":67358,"DATA_ARRAY":67359,"DATA_ARRAY_OUTLINED":67360,"DATA_ARRAY_ROUNDED":67361,"DATA_ARRAY_SHARP":67362,"DATA_EXPLORATION":67363,"DATA_EXPLORATION_OUTLINED":67364,"DATA_EXPLORATION_ROUNDED":67365,"DATA_EXPLORATION_SHARP":67366,"DATA_OBJECT":67367,"DATA_OBJECT_OUTLINED":67368,"DATA_OBJECT_ROUNDED":67369,"DATA_OBJECT_SHARP":67370,"DATA_SAVER_OFF":67371,"DATA_SAVER_OFF_OUTLINED":67372,"DATA_SAVER_OFF_ROUNDED":67373,"DATA_SAVER_OFF_SHARP":67374,"DATA_SAVER_ON":67375,"DATA_SAVER_ON_OUTLINED":67376,"DATA_SAVER_ON_ROUNDED":67377,"DATA_SAVER_ON_SHARP":67378,"DATA_THRESHOLDING":67379,"DATA_THRESHOLDING_OUTLINED":67380,"DATA_THRESHOLDING_ROUNDED":67381,"DATA_THRESHOLDING_SHARP":67382,"DATA_USAGE":67383,"DATA_USAGE_OUTLINED":67384,"DATA_USAGE_ROUNDED":67385,"DATA_USAGE_SHARP":67386,"DATASET":67387,"DATASET_LINKED":67388,"DATASET_LINKED_OUTLINED":67389,"DATASET_LINKED_ROUNDED":67390,"DATASET_LINKED_SHARP":67391,"DATASET_OUTLINED":67392,"DATASET_ROUNDED":67393,"DATASET_SHARP":67394,"DATE_RANGE":67395,"DATE_RANGE_OUTLINED":67396,"DATE_RANGE_ROUNDED":67397,"DATE_RANGE_SHARP":67398,"DEBLUR":67399,"DEBLUR_OUTLINED":67400,"DEBLUR_ROUNDED":67401,"DEBLUR_SHARP":67402,"DECK":67403,"DECK_OUTLINED":67404,"DECK_ROUNDED":67405,"DECK_SHARP":67406,"DEHAZE":67407,"DEHAZE_OUTLINED":67408,"DEHAZE_ROUNDED":67409,"DEHAZE_SHARP":67410,"DELETE":67411,"DELETE_FOREVER":67412,"DELETE_FOREVER_OUTLINED":67413,"DELETE_FOREVER_ROUNDED":67414,"DELETE_FOREVER_SHARP":67415,"DELETE_OUTLINE":67416,"DELETE_OUTLINE_OUTLINED":67417,"DELETE_OUTLINE_ROUNDED":67418,"DELETE_OUTLINE_SHARP":67419,"DELETE_OUTLINED":67420,"DELETE_ROUNDED":67421,"DELETE_SHARP":67422,"DELETE_SWEEP":67423,"DELETE_SWEEP_OUTLINED":67424,"DELETE_SWEEP_ROUNDED":67425,"DELETE_SWEEP_SHARP":67426,"DELIVERY_DINING":67427,"DELIVERY_DINING_OUTLINED":67428,"DELIVERY_DINING_ROUNDED":67429,"DELIVERY_DINING_SHARP":67430,"DENSITY_LARGE":67431,"DENSITY_LARGE_OUTLINED":67432,"DENSITY_LARGE_ROUNDED":67433,"DENSITY_LARGE_SHARP":67434,"DENSITY_MEDIUM":67435,"DENSITY_MEDIUM_OUTLINED":67436,"DENSITY_MEDIUM_ROUNDED":67437,"DENSITY_MEDIUM_SHARP":67438,"DENSITY_SMALL":67439,"DENSITY_SMALL_OUTLINED":67440,"DENSITY_SMALL_ROUNDED":67441,"DENSITY_SMALL_SHARP":67442,"DEPARTURE_BOARD":67443,"DEPARTURE_BOARD_OUTLINED":67444,"DEPARTURE_BOARD_ROUNDED":67445,"DEPARTURE_BOARD_SHARP":67446,"DESCRIPTION":67447,"DESCRIPTION_OUTLINED":67448,"DESCRIPTION_ROUNDED":67449,"DESCRIPTION_SHARP":67450,"DESELECT":67451,"DESELECT_OUTLINED":67452,"DESELECT_ROUNDED":67453,"DESELECT_SHARP":67454,"DESIGN_SERVICES":67455,"DESIGN_SERVICES_OUTLINED":67456,"DESIGN_SERVICES_ROUNDED":67457,"DESIGN_SERVICES_SHARP":67458,"DESK":67459,"DESK_OUTLINED":67460,"DESK_ROUNDED":67461,"DESK_SHARP":67462,"DESKTOP_ACCESS_DISABLED":67463,"DESKTOP_ACCESS_DISABLED_OUTLINED":67464,"DESKTOP_ACCESS_DISABLED_ROUNDED":67465,"DESKTOP_ACCESS_DISABLED_SHARP":67466,"DESKTOP_MAC":67467,"DESKTOP_MAC_OUTLINED":67468,"DESKTOP_MAC_ROUNDED":67469,"DESKTOP_MAC_SHARP":67470,"DESKTOP_WINDOWS":67471,"DESKTOP_WINDOWS_OUTLINED":67472,"DESKTOP_WINDOWS_ROUNDED":67473,"DESKTOP_WINDOWS_SHARP":67474,"DETAILS":67475,"DETAILS_OUTLINED":67476,"DETAILS_ROUNDED":67477,"DETAILS_SHARP":67478,"DEVELOPER_BOARD":67479,"DEVELOPER_BOARD_OFF":67480,"DEVELOPER_BOARD_OFF_OUTLINED":67481,"DEVELOPER_BOARD_OFF_ROUNDED":67482,"DEVELOPER_BOARD_OFF_SHARP":67483,"DEVELOPER_BOARD_OUTLINED":67484,"DEVELOPER_BOARD_ROUNDED":67485,"DEVELOPER_BOARD_SHARP":67486,"DEVELOPER_MODE":67487,"DEVELOPER_MODE_OUTLINED":67488,"DEVELOPER_MODE_ROUNDED":67489,"DEVELOPER_MODE_SHARP":67490,"DEVICE_HUB":67491,"DEVICE_HUB_OUTLINED":67492,"DEVICE_HUB_ROUNDED":67493,"DEVICE_HUB_SHARP":67494,"DEVICE_THERMOSTAT":67495,"DEVICE_THERMOSTAT_OUTLINED":67496,"DEVICE_THERMOSTAT_ROUNDED":67497,"DEVICE_THERMOSTAT_SHARP":67498,"DEVICE_UNKNOWN":67499,"DEVICE_UNKNOWN_OUTLINED":67500,"DEVICE_UNKNOWN_ROUNDED":67501,"DEVICE_UNKNOWN_SHARP":67502,"DEVICES":67503,"DEVICES_FOLD":67504,"DEVICES_FOLD_OUTLINED":67505,"DEVICES_FOLD_ROUNDED":67506,"DEVICES_FOLD_SHARP":67507,"DEVICES_OTHER":67508,"DEVICES_OTHER_OUTLINED":67509,"DEVICES_OTHER_ROUNDED":67510,"DEVICES_OTHER_SHARP":67511,"DEVICES_OUTLINED":67512,"DEVICES_ROUNDED":67513,"DEVICES_SHARP":67514,"DEW_POINT":67515,"DIALER_SIP":67516,"DIALER_SIP_OUTLINED":67517,"DIALER_SIP_ROUNDED":67518,"DIALER_SIP_SHARP":67519,"DIALPAD":67520,"DIALPAD_OUTLINED":67521,"DIALPAD_ROUNDED":67522,"DIALPAD_SHARP":67523,"DIAMOND":67524,"DIAMOND_OUTLINED":67525,"DIAMOND_ROUNDED":67526,"DIAMOND_SHARP":67527,"DIFFERENCE":67528,"DIFFERENCE_OUTLINED":67529,"DIFFERENCE_ROUNDED":67530,"DIFFERENCE_SHARP":67531,"DINING":67532,"DINING_OUTLINED":67533,"DINING_ROUNDED":67534,"DINING_SHARP":67535,"DINNER_DINING":67536,"DINNER_DINING_OUTLINED":67537,"DINNER_DINING_ROUNDED":67538,"DINNER_DINING_SHARP":67539,"DIRECTIONS":67540,"DIRECTIONS_BIKE":67541,"DIRECTIONS_BIKE_OUTLINED":67542,"DIRECTIONS_BIKE_ROUNDED":67543,"DIRECTIONS_BIKE_SHARP":67544,"DIRECTIONS_BOAT":67545,"DIRECTIONS_BOAT_FILLED":67546,"DIRECTIONS_BOAT_FILLED_OUTLINED":67547,"DIRECTIONS_BOAT_FILLED_ROUNDED":67548,"DIRECTIONS_BOAT_FILLED_SHARP":67549,"DIRECTIONS_BOAT_OUTLINED":67550,"DIRECTIONS_BOAT_ROUNDED":67551,"DIRECTIONS_BOAT_SHARP":67552,"DIRECTIONS_BUS":67553,"DIRECTIONS_BUS_FILLED":67554,"DIRECTIONS_BUS_FILLED_OUTLINED":67555,"DIRECTIONS_BUS_FILLED_ROUNDED":67556,"DIRECTIONS_BUS_FILLED_SHARP":67557,"DIRECTIONS_BUS_OUTLINED":67558,"DIRECTIONS_BUS_ROUNDED":67559,"DIRECTIONS_BUS_SHARP":67560,"DIRECTIONS_CAR":67561,"DIRECTIONS_CAR_FILLED":67562,"DIRECTIONS_CAR_FILLED_OUTLINED":67563,"DIRECTIONS_CAR_FILLED_ROUNDED":67564,"DIRECTIONS_CAR_FILLED_SHARP":67565,"DIRECTIONS_CAR_OUTLINED":67566,"DIRECTIONS_CAR_ROUNDED":67567,"DIRECTIONS_CAR_SHARP":67568,"DIRECTIONS_FERRY":67569,"DIRECTIONS_FERRY_OUTLINED":67570,"DIRECTIONS_FERRY_ROUNDED":67571,"DIRECTIONS_FERRY_SHARP":67572,"DIRECTIONS_OFF":67573,"DIRECTIONS_OFF_OUTLINED":67574,"DIRECTIONS_OFF_ROUNDED":67575,"DIRECTIONS_OFF_SHARP":67576,"DIRECTIONS_OUTLINED":67577,"DIRECTIONS_RAILWAY":67578,"DIRECTIONS_RAILWAY_FILLED":67579,"DIRECTIONS_RAILWAY_FILLED_OUTLINED":67580,"DIRECTIONS_RAILWAY_FILLED_ROUNDED":67581,"DIRECTIONS_RAILWAY_FILLED_SHARP":67582,"DIRECTIONS_RAILWAY_OUTLINED":67583,"DIRECTIONS_RAILWAY_ROUNDED":67584,"DIRECTIONS_RAILWAY_SHARP":67585,"DIRECTIONS_ROUNDED":67586,"DIRECTIONS_RUN":67587,"DIRECTIONS_RUN_OUTLINED":67588,"DIRECTIONS_RUN_ROUNDED":67589,"DIRECTIONS_RUN_SHARP":67590,"DIRECTIONS_SHARP":67591,"DIRECTIONS_SUBWAY":67592,"DIRECTIONS_SUBWAY_FILLED":67593,"DIRECTIONS_SUBWAY_FILLED_OUTLINED":67594,"DIRECTIONS_SUBWAY_FILLED_ROUNDED":67595,"DIRECTIONS_SUBWAY_FILLED_SHARP":67596,"DIRECTIONS_SUBWAY_OUTLINED":67597,"DIRECTIONS_SUBWAY_ROUNDED":67598,"DIRECTIONS_SUBWAY_SHARP":67599,"DIRECTIONS_TRAIN":67600,"DIRECTIONS_TRAIN_OUTLINED":67601,"DIRECTIONS_TRAIN_ROUNDED":67602,"DIRECTIONS_TRAIN_SHARP":67603,"DIRECTIONS_TRANSIT":67604,"DIRECTIONS_TRANSIT_FILLED":67605,"DIRECTIONS_TRANSIT_FILLED_OUTLINED":67606,"DIRECTIONS_TRANSIT_FILLED_ROUNDED":67607,"DIRECTIONS_TRANSIT_FILLED_SHARP":67608,"DIRECTIONS_TRANSIT_OUTLINED":67609,"DIRECTIONS_TRANSIT_ROUNDED":67610,"DIRECTIONS_TRANSIT_SHARP":67611,"DIRECTIONS_WALK":67612,"DIRECTIONS_WALK_OUTLINED":67613,"DIRECTIONS_WALK_ROUNDED":67614,"DIRECTIONS_WALK_SHARP":67615,"DIRTY_LENS":67616,"DIRTY_LENS_OUTLINED":67617,"DIRTY_LENS_ROUNDED":67618,"DIRTY_LENS_SHARP":67619,"DISABLED_BY_DEFAULT":67620,"DISABLED_BY_DEFAULT_OUTLINED":67621,"DISABLED_BY_DEFAULT_ROUNDED":67622,"DISABLED_BY_DEFAULT_SHARP":67623,"DISABLED_VISIBLE":67624,"DISABLED_VISIBLE_OUTLINED":67625,"DISABLED_VISIBLE_ROUNDED":67626,"DISABLED_VISIBLE_SHARP":67627,"DISC_FULL":67628,"DISC_FULL_OUTLINED":67629,"DISC_FULL_ROUNDED":67630,"DISC_FULL_SHARP":67631,"DISCORD":67632,"DISCORD_OUTLINED":67633,"DISCORD_ROUNDED":67634,"DISCORD_SHARP":67635,"DISCOUNT":67636,"DISCOUNT_OUTLINED":67637,"DISCOUNT_ROUNDED":67638,"DISCOUNT_SHARP":67639,"DISPLAY_SETTINGS":67640,"DISPLAY_SETTINGS_OUTLINED":67641,"DISPLAY_SETTINGS_ROUNDED":67642,"DISPLAY_SETTINGS_SHARP":67643,"DIVERSITY_1":67644,"DIVERSITY_1_OUTLINED":67645,"DIVERSITY_1_ROUNDED":67646,"DIVERSITY_1_SHARP":67647,"DIVERSITY_2":67648,"DIVERSITY_2_OUTLINED":67649,"DIVERSITY_2_ROUNDED":67650,"DIVERSITY_2_SHARP":67651,"DIVERSITY_3":67652,"DIVERSITY_3_OUTLINED":67653,"DIVERSITY_3_ROUNDED":67654,"DIVERSITY_3_SHARP":67655,"DND_FORWARDSLASH":67656,"DND_FORWARDSLASH_OUTLINED":67657,"DND_FORWARDSLASH_ROUNDED":67658,"DND_FORWARDSLASH_SHARP":67659,"DNS":67660,"DNS_OUTLINED":67661,"DNS_ROUNDED":67662,"DNS_SHARP":67663,"DO_DISTURB":67664,"DO_DISTURB_ALT":67665,"DO_DISTURB_ALT_OUTLINED":67666,"DO_DISTURB_ALT_ROUNDED":67667,"DO_DISTURB_ALT_SHARP":67668,"DO_DISTURB_OFF":67669,"DO_DISTURB_OFF_OUTLINED":67670,"DO_DISTURB_OFF_ROUNDED":67671,"DO_DISTURB_OFF_SHARP":67672,"DO_DISTURB_ON":67673,"DO_DISTURB_ON_OUTLINED":67674,"DO_DISTURB_ON_ROUNDED":67675,"DO_DISTURB_ON_SHARP":67676,"DO_DISTURB_OUTLINED":67677,"DO_DISTURB_ROUNDED":67678,"DO_DISTURB_SHARP":67679,"DO_NOT_DISTURB":67680,"DO_NOT_DISTURB_ALT":67681,"DO_NOT_DISTURB_ALT_OUTLINED":67682,"DO_NOT_DISTURB_ALT_ROUNDED":67683,"DO_NOT_DISTURB_ALT_SHARP":67684,"DO_NOT_DISTURB_OFF":67685,"DO_NOT_DISTURB_OFF_OUTLINED":67686,"DO_NOT_DISTURB_OFF_ROUNDED":67687,"DO_NOT_DISTURB_OFF_SHARP":67688,"DO_NOT_DISTURB_ON":67689,"DO_NOT_DISTURB_ON_OUTLINED":67690,"DO_NOT_DISTURB_ON_ROUNDED":67691,"DO_NOT_DISTURB_ON_SHARP":67692,"DO_NOT_DISTURB_ON_TOTAL_SILENCE":67693,"DO_NOT_DISTURB_ON_TOTAL_SILENCE_OUTLINED":67694,"DO_NOT_DISTURB_ON_TOTAL_SILENCE_ROUNDED":67695,"DO_NOT_DISTURB_ON_TOTAL_SILENCE_SHARP":67696,"DO_NOT_DISTURB_OUTLINED":67697,"DO_NOT_DISTURB_ROUNDED":67698,"DO_NOT_DISTURB_SHARP":67699,"DO_NOT_STEP":67700,"DO_NOT_STEP_OUTLINED":67701,"DO_NOT_STEP_ROUNDED":67702,"DO_NOT_STEP_SHARP":67703,"DO_NOT_TOUCH":67704,"DO_NOT_TOUCH_OUTLINED":67705,"DO_NOT_TOUCH_ROUNDED":67706,"DO_NOT_TOUCH_SHARP":67707,"DOCK":67708,"DOCK_OUTLINED":67709,"DOCK_ROUNDED":67710,"DOCK_SHARP":67711,"DOCUMENT_SCANNER":67712,"DOCUMENT_SCANNER_OUTLINED":67713,"DOCUMENT_SCANNER_ROUNDED":67714,"DOCUMENT_SCANNER_SHARP":67715,"DOMAIN":67716,"DOMAIN_ADD":67717,"DOMAIN_ADD_OUTLINED":67718,"DOMAIN_ADD_ROUNDED":67719,"DOMAIN_ADD_SHARP":67720,"DOMAIN_DISABLED":67721,"DOMAIN_DISABLED_OUTLINED":67722,"DOMAIN_DISABLED_ROUNDED":67723,"DOMAIN_DISABLED_SHARP":67724,"DOMAIN_OUTLINED":67725,"DOMAIN_ROUNDED":67726,"DOMAIN_SHARP":67727,"DOMAIN_VERIFICATION":67728,"DOMAIN_VERIFICATION_OUTLINED":67729,"DOMAIN_VERIFICATION_ROUNDED":67730,"DOMAIN_VERIFICATION_SHARP":67731,"DONE":67732,"DONE_ALL":67733,"DONE_ALL_OUTLINED":67734,"DONE_ALL_ROUNDED":67735,"DONE_ALL_SHARP":67736,"DONE_OUTLINE":67737,"DONE_OUTLINE_OUTLINED":67738,"DONE_OUTLINE_ROUNDED":67739,"DONE_OUTLINE_SHARP":67740,"DONE_OUTLINED":67741,"DONE_ROUNDED":67742,"DONE_SHARP":67743,"DONUT_LARGE":67744,"DONUT_LARGE_OUTLINED":67745,"DONUT_LARGE_ROUNDED":67746,"DONUT_LARGE_SHARP":67747,"DONUT_SMALL":67748,"DONUT_SMALL_OUTLINED":67749,"DONUT_SMALL_ROUNDED":67750,"DONUT_SMALL_SHARP":67751,"DOOR_BACK_DOOR":67752,"DOOR_BACK_DOOR_OUTLINED":67753,"DOOR_BACK_DOOR_ROUNDED":67754,"DOOR_BACK_DOOR_SHARP":67755,"DOOR_FRONT_DOOR":67756,"DOOR_FRONT_DOOR_OUTLINED":67757,"DOOR_FRONT_DOOR_ROUNDED":67758,"DOOR_FRONT_DOOR_SHARP":67759,"DOOR_SLIDING":67760,"DOOR_SLIDING_OUTLINED":67761,"DOOR_SLIDING_ROUNDED":67762,"DOOR_SLIDING_SHARP":67763,"DOORBELL":67764,"DOORBELL_OUTLINED":67765,"DOORBELL_ROUNDED":67766,"DOORBELL_SHARP":67767,"DOUBLE_ARROW":67768,"DOUBLE_ARROW_OUTLINED":67769,"DOUBLE_ARROW_ROUNDED":67770,"DOUBLE_ARROW_SHARP":67771,"DOWNHILL_SKIING":67772,"DOWNHILL_SKIING_OUTLINED":67773,"DOWNHILL_SKIING_ROUNDED":67774,"DOWNHILL_SKIING_SHARP":67775,"DOWNLOAD":67776,"DOWNLOAD_DONE":67777,"DOWNLOAD_DONE_OUTLINED":67778,"DOWNLOAD_DONE_ROUNDED":67779,"DOWNLOAD_DONE_SHARP":67780,"DOWNLOAD_FOR_OFFLINE":67781,"DOWNLOAD_FOR_OFFLINE_OUTLINED":67782,"DOWNLOAD_FOR_OFFLINE_ROUNDED":67783,"DOWNLOAD_FOR_OFFLINE_SHARP":67784,"DOWNLOAD_OUTLINED":67785,"DOWNLOAD_ROUNDED":67786,"DOWNLOAD_SHARP":67787,"DOWNLOADING":67788,"DOWNLOADING_OUTLINED":67789,"DOWNLOADING_ROUNDED":67790,"DOWNLOADING_SHARP":67791,"DRAFTS":67792,"DRAFTS_OUTLINED":67793,"DRAFTS_ROUNDED":67794,"DRAFTS_SHARP":67795,"DRAG_HANDLE":67796,"DRAG_HANDLE_OUTLINED":67797,"DRAG_HANDLE_ROUNDED":67798,"DRAG_HANDLE_SHARP":67799,"DRAG_INDICATOR":67800,"DRAG_INDICATOR_OUTLINED":67801,"DRAG_INDICATOR_ROUNDED":67802,"DRAG_INDICATOR_SHARP":67803,"DRAW":67804,"DRAW_OUTLINED":67805,"DRAW_ROUNDED":67806,"DRAW_SHARP":67807,"DRIVE_ETA":67808,"DRIVE_ETA_OUTLINED":67809,"DRIVE_ETA_ROUNDED":67810,"DRIVE_ETA_SHARP":67811,"DRIVE_FILE_MOVE":67812,"DRIVE_FILE_MOVE_OUTLINE":67813,"DRIVE_FILE_MOVE_OUTLINED":67814,"DRIVE_FILE_MOVE_ROUNDED":67815,"DRIVE_FILE_MOVE_RTL":67816,"DRIVE_FILE_MOVE_RTL_OUTLINED":67817,"DRIVE_FILE_MOVE_RTL_ROUNDED":67818,"DRIVE_FILE_MOVE_RTL_SHARP":67819,"DRIVE_FILE_MOVE_SHARP":67820,"DRIVE_FILE_RENAME_OUTLINE":67821,"DRIVE_FILE_RENAME_OUTLINE_OUTLINED":67822,"DRIVE_FILE_RENAME_OUTLINE_ROUNDED":67823,"DRIVE_FILE_RENAME_OUTLINE_SHARP":67824,"DRIVE_FOLDER_UPLOAD":67825,"DRIVE_FOLDER_UPLOAD_OUTLINED":67826,"DRIVE_FOLDER_UPLOAD_ROUNDED":67827,"DRIVE_FOLDER_UPLOAD_SHARP":67828,"DRY":67829,"DRY_CLEANING":67830,"DRY_CLEANING_OUTLINED":67831,"DRY_CLEANING_ROUNDED":67832,"DRY_CLEANING_SHARP":67833,"DRY_OUTLINED":67834,"DRY_ROUNDED":67835,"DRY_SHARP":67836,"DUO":67837,"DUO_OUTLINED":67838,"DUO_ROUNDED":67839,"DUO_SHARP":67840,"DVR":67841,"DVR_OUTLINED":67842,"DVR_ROUNDED":67843,"DVR_SHARP":67844,"DYNAMIC_FEED":67845,"DYNAMIC_FEED_OUTLINED":67846,"DYNAMIC_FEED_ROUNDED":67847,"DYNAMIC_FEED_SHARP":67848,"DYNAMIC_FORM":67849,"DYNAMIC_FORM_OUTLINED":67850,"DYNAMIC_FORM_ROUNDED":67851,"DYNAMIC_FORM_SHARP":67852,"E_MOBILEDATA":67853,"E_MOBILEDATA_OUTLINED":67854,"E_MOBILEDATA_ROUNDED":67855,"E_MOBILEDATA_SHARP":67856,"EARBUDS":67857,"EARBUDS_BATTERY":67858,"EARBUDS_BATTERY_OUTLINED":67859,"EARBUDS_BATTERY_ROUNDED":67860,"EARBUDS_BATTERY_SHARP":67861,"EARBUDS_OUTLINED":67862,"EARBUDS_ROUNDED":67863,"EARBUDS_SHARP":67864,"EAST":67865,"EAST_OUTLINED":67866,"EAST_ROUNDED":67867,"EAST_SHARP":67868,"ECO":67869,"ECO_OUTLINED":67870,"ECO_ROUNDED":67871,"ECO_SHARP":67872,"EDGESENSOR_HIGH":67873,"EDGESENSOR_HIGH_OUTLINED":67874,"EDGESENSOR_HIGH_ROUNDED":67875,"EDGESENSOR_HIGH_SHARP":67876,"EDGESENSOR_LOW":67877,"EDGESENSOR_LOW_OUTLINED":67878,"EDGESENSOR_LOW_ROUNDED":67879,"EDGESENSOR_LOW_SHARP":67880,"EDIT":67881,"EDIT_ATTRIBUTES":67882,"EDIT_ATTRIBUTES_OUTLINED":67883,"EDIT_ATTRIBUTES_ROUNDED":67884,"EDIT_ATTRIBUTES_SHARP":67885,"EDIT_CALENDAR":67886,"EDIT_CALENDAR_OUTLINED":67887,"EDIT_CALENDAR_ROUNDED":67888,"EDIT_CALENDAR_SHARP":67889,"EDIT_DOCUMENT":67890,"EDIT_LOCATION":67891,"EDIT_LOCATION_ALT":67892,"EDIT_LOCATION_ALT_OUTLINED":67893,"EDIT_LOCATION_ALT_ROUNDED":67894,"EDIT_LOCATION_ALT_SHARP":67895,"EDIT_LOCATION_OUTLINED":67896,"EDIT_LOCATION_ROUNDED":67897,"EDIT_LOCATION_SHARP":67898,"EDIT_NOTE":67899,"EDIT_NOTE_OUTLINED":67900,"EDIT_NOTE_ROUNDED":67901,"EDIT_NOTE_SHARP":67902,"EDIT_NOTIFICATIONS":67903,"EDIT_NOTIFICATIONS_OUTLINED":67904,"EDIT_NOTIFICATIONS_ROUNDED":67905,"EDIT_NOTIFICATIONS_SHARP":67906,"EDIT_OFF":67907,"EDIT_OFF_OUTLINED":67908,"EDIT_OFF_ROUNDED":67909,"EDIT_OFF_SHARP":67910,"EDIT_OUTLINED":67911,"EDIT_ROAD":67912,"EDIT_ROAD_OUTLINED":67913,"EDIT_ROAD_ROUNDED":67914,"EDIT_ROAD_SHARP":67915,"EDIT_ROUNDED":67916,"EDIT_SHARP":67917,"EDIT_SQUARE":67918,"EGG":67919,"EGG_ALT":67920,"EGG_ALT_OUTLINED":67921,"EGG_ALT_ROUNDED":67922,"EGG_ALT_SHARP":67923,"EGG_OUTLINED":67924,"EGG_ROUNDED":67925,"EGG_SHARP":67926,"EIGHT_K":67927,"EIGHT_K_OUTLINED":67928,"EIGHT_K_PLUS":67929,"EIGHT_K_PLUS_OUTLINED":67930,"EIGHT_K_PLUS_ROUNDED":67931,"EIGHT_K_PLUS_SHARP":67932,"EIGHT_K_ROUNDED":67933,"EIGHT_K_SHARP":67934,"EIGHT_MP":67935,"EIGHT_MP_OUTLINED":67936,"EIGHT_MP_ROUNDED":67937,"EIGHT_MP_SHARP":67938,"EIGHTEEN_MP":67939,"EIGHTEEN_MP_OUTLINED":67940,"EIGHTEEN_MP_ROUNDED":67941,"EIGHTEEN_MP_SHARP":67942,"EIGHTEEN_UP_RATING":67943,"EIGHTEEN_UP_RATING_OUTLINED":67944,"EIGHTEEN_UP_RATING_ROUNDED":67945,"EIGHTEEN_UP_RATING_SHARP":67946,"EJECT":67947,"EJECT_OUTLINED":67948,"EJECT_ROUNDED":67949,"EJECT_SHARP":67950,"ELDERLY":67951,"ELDERLY_OUTLINED":67952,"ELDERLY_ROUNDED":67953,"ELDERLY_SHARP":67954,"ELDERLY_WOMAN":67955,"ELDERLY_WOMAN_OUTLINED":67956,"ELDERLY_WOMAN_ROUNDED":67957,"ELDERLY_WOMAN_SHARP":67958,"ELECTRIC_BIKE":67959,"ELECTRIC_BIKE_OUTLINED":67960,"ELECTRIC_BIKE_ROUNDED":67961,"ELECTRIC_BIKE_SHARP":67962,"ELECTRIC_BOLT":67963,"ELECTRIC_BOLT_OUTLINED":67964,"ELECTRIC_BOLT_ROUNDED":67965,"ELECTRIC_BOLT_SHARP":67966,"ELECTRIC_CAR":67967,"ELECTRIC_CAR_OUTLINED":67968,"ELECTRIC_CAR_ROUNDED":67969,"ELECTRIC_CAR_SHARP":67970,"ELECTRIC_METER":67971,"ELECTRIC_METER_OUTLINED":67972,"ELECTRIC_METER_ROUNDED":67973,"ELECTRIC_METER_SHARP":67974,"ELECTRIC_MOPED":67975,"ELECTRIC_MOPED_OUTLINED":67976,"ELECTRIC_MOPED_ROUNDED":67977,"ELECTRIC_MOPED_SHARP":67978,"ELECTRIC_RICKSHAW":67979,"ELECTRIC_RICKSHAW_OUTLINED":67980,"ELECTRIC_RICKSHAW_ROUNDED":67981,"ELECTRIC_RICKSHAW_SHARP":67982,"ELECTRIC_SCOOTER":67983,"ELECTRIC_SCOOTER_OUTLINED":67984,"ELECTRIC_SCOOTER_ROUNDED":67985,"ELECTRIC_SCOOTER_SHARP":67986,"ELECTRICAL_SERVICES":67987,"ELECTRICAL_SERVICES_OUTLINED":67988,"ELECTRICAL_SERVICES_ROUNDED":67989,"ELECTRICAL_SERVICES_SHARP":67990,"ELEVATOR":67991,"ELEVATOR_OUTLINED":67992,"ELEVATOR_ROUNDED":67993,"ELEVATOR_SHARP":67994,"ELEVEN_MP":67995,"ELEVEN_MP_OUTLINED":67996,"ELEVEN_MP_ROUNDED":67997,"ELEVEN_MP_SHARP":67998,"EMAIL":67999,"EMAIL_OUTLINED":68000,"EMAIL_ROUNDED":68001,"EMAIL_SHARP":68002,"EMERGENCY":68003,"EMERGENCY_OUTLINED":68004,"EMERGENCY_RECORDING":68005,"EMERGENCY_RECORDING_OUTLINED":68006,"EMERGENCY_RECORDING_ROUNDED":68007,"EMERGENCY_RECORDING_SHARP":68008,"EMERGENCY_ROUNDED":68009,"EMERGENCY_SHARE":68010,"EMERGENCY_SHARE_OUTLINED":68011,"EMERGENCY_SHARE_ROUNDED":68012,"EMERGENCY_SHARE_SHARP":68013,"EMERGENCY_SHARP":68014,"EMOJI_EMOTIONS":68015,"EMOJI_EMOTIONS_OUTLINED":68016,"EMOJI_EMOTIONS_ROUNDED":68017,"EMOJI_EMOTIONS_SHARP":68018,"EMOJI_EVENTS":68019,"EMOJI_EVENTS_OUTLINED":68020,"EMOJI_EVENTS_ROUNDED":68021,"EMOJI_EVENTS_SHARP":68022,"EMOJI_FLAGS":68023,"EMOJI_FLAGS_OUTLINED":68024,"EMOJI_FLAGS_ROUNDED":68025,"EMOJI_FLAGS_SHARP":68026,"EMOJI_FOOD_BEVERAGE":68027,"EMOJI_FOOD_BEVERAGE_OUTLINED":68028,"EMOJI_FOOD_BEVERAGE_ROUNDED":68029,"EMOJI_FOOD_BEVERAGE_SHARP":68030,"EMOJI_NATURE":68031,"EMOJI_NATURE_OUTLINED":68032,"EMOJI_NATURE_ROUNDED":68033,"EMOJI_NATURE_SHARP":68034,"EMOJI_OBJECTS":68035,"EMOJI_OBJECTS_OUTLINED":68036,"EMOJI_OBJECTS_ROUNDED":68037,"EMOJI_OBJECTS_SHARP":68038,"EMOJI_PEOPLE":68039,"EMOJI_PEOPLE_OUTLINED":68040,"EMOJI_PEOPLE_ROUNDED":68041,"EMOJI_PEOPLE_SHARP":68042,"EMOJI_SYMBOLS":68043,"EMOJI_SYMBOLS_OUTLINED":68044,"EMOJI_SYMBOLS_ROUNDED":68045,"EMOJI_SYMBOLS_SHARP":68046,"EMOJI_TRANSPORTATION":68047,"EMOJI_TRANSPORTATION_OUTLINED":68048,"EMOJI_TRANSPORTATION_ROUNDED":68049,"EMOJI_TRANSPORTATION_SHARP":68050,"ENERGY_SAVINGS_LEAF":68051,"ENERGY_SAVINGS_LEAF_OUTLINED":68052,"ENERGY_SAVINGS_LEAF_ROUNDED":68053,"ENERGY_SAVINGS_LEAF_SHARP":68054,"ENGINEERING":68055,"ENGINEERING_OUTLINED":68056,"ENGINEERING_ROUNDED":68057,"ENGINEERING_SHARP":68058,"ENHANCE_PHOTO_TRANSLATE":68059,"ENHANCE_PHOTO_TRANSLATE_OUTLINED":68060,"ENHANCE_PHOTO_TRANSLATE_ROUNDED":68061,"ENHANCE_PHOTO_TRANSLATE_SHARP":68062,"ENHANCED_ENCRYPTION":68063,"ENHANCED_ENCRYPTION_OUTLINED":68064,"ENHANCED_ENCRYPTION_ROUNDED":68065,"ENHANCED_ENCRYPTION_SHARP":68066,"EQUALIZER":68067,"EQUALIZER_OUTLINED":68068,"EQUALIZER_ROUNDED":68069,"EQUALIZER_SHARP":68070,"ERROR":68071,"ERROR_OUTLINE":68072,"ERROR_OUTLINE_OUTLINED":68073,"ERROR_OUTLINE_ROUNDED":68074,"ERROR_OUTLINE_SHARP":68075,"ERROR_OUTLINED":68076,"ERROR_ROUNDED":68077,"ERROR_SHARP":68078,"ESCALATOR":68079,"ESCALATOR_OUTLINED":68080,"ESCALATOR_ROUNDED":68081,"ESCALATOR_SHARP":68082,"ESCALATOR_WARNING":68083,"ESCALATOR_WARNING_OUTLINED":68084,"ESCALATOR_WARNING_ROUNDED":68085,"ESCALATOR_WARNING_SHARP":68086,"EURO":68087,"EURO_OUTLINED":68088,"EURO_ROUNDED":68089,"EURO_SHARP":68090,"EURO_SYMBOL":68091,"EURO_SYMBOL_OUTLINED":68092,"EURO_SYMBOL_ROUNDED":68093,"EURO_SYMBOL_SHARP":68094,"EV_STATION":68095,"EV_STATION_OUTLINED":68096,"EV_STATION_ROUNDED":68097,"EV_STATION_SHARP":68098,"EVENT":68099,"EVENT_AVAILABLE":68100,"EVENT_AVAILABLE_OUTLINED":68101,"EVENT_AVAILABLE_ROUNDED":68102,"EVENT_AVAILABLE_SHARP":68103,"EVENT_BUSY":68104,"EVENT_BUSY_OUTLINED":68105,"EVENT_BUSY_ROUNDED":68106,"EVENT_BUSY_SHARP":68107,"EVENT_NOTE":68108,"EVENT_NOTE_OUTLINED":68109,"EVENT_NOTE_ROUNDED":68110,"EVENT_NOTE_SHARP":68111,"EVENT_OUTLINED":68112,"EVENT_REPEAT":68113,"EVENT_REPEAT_OUTLINED":68114,"EVENT_REPEAT_ROUNDED":68115,"EVENT_REPEAT_SHARP":68116,"EVENT_ROUNDED":68117,"EVENT_SEAT":68118,"EVENT_SEAT_OUTLINED":68119,"EVENT_SEAT_ROUNDED":68120,"EVENT_SEAT_SHARP":68121,"EVENT_SHARP":68122,"EXIT_TO_APP":68123,"EXIT_TO_APP_OUTLINED":68124,"EXIT_TO_APP_ROUNDED":68125,"EXIT_TO_APP_SHARP":68126,"EXPAND":68127,"EXPAND_CIRCLE_DOWN":68128,"EXPAND_CIRCLE_DOWN_OUTLINED":68129,"EXPAND_CIRCLE_DOWN_ROUNDED":68130,"EXPAND_CIRCLE_DOWN_SHARP":68131,"EXPAND_LESS":68132,"EXPAND_LESS_OUTLINED":68133,"EXPAND_LESS_ROUNDED":68134,"EXPAND_LESS_SHARP":68135,"EXPAND_MORE":68136,"EXPAND_MORE_OUTLINED":68137,"EXPAND_MORE_ROUNDED":68138,"EXPAND_MORE_SHARP":68139,"EXPAND_OUTLINED":68140,"EXPAND_ROUNDED":68141,"EXPAND_SHARP":68142,"EXPLICIT":68143,"EXPLICIT_OUTLINED":68144,"EXPLICIT_ROUNDED":68145,"EXPLICIT_SHARP":68146,"EXPLORE":68147,"EXPLORE_OFF":68148,"EXPLORE_OFF_OUTLINED":68149,"EXPLORE_OFF_ROUNDED":68150,"EXPLORE_OFF_SHARP":68151,"EXPLORE_OUTLINED":68152,"EXPLORE_ROUNDED":68153,"EXPLORE_SHARP":68154,"EXPOSURE":68155,"EXPOSURE_MINUS_1":68156,"EXPOSURE_MINUS_1_OUTLINED":68157,"EXPOSURE_MINUS_1_ROUNDED":68158,"EXPOSURE_MINUS_1_SHARP":68159,"EXPOSURE_MINUS_2":68160,"EXPOSURE_MINUS_2_OUTLINED":68161,"EXPOSURE_MINUS_2_ROUNDED":68162,"EXPOSURE_MINUS_2_SHARP":68163,"EXPOSURE_NEG_1":68164,"EXPOSURE_NEG_1_OUTLINED":68165,"EXPOSURE_NEG_1_ROUNDED":68166,"EXPOSURE_NEG_1_SHARP":68167,"EXPOSURE_NEG_2":68168,"EXPOSURE_NEG_2_OUTLINED":68169,"EXPOSURE_NEG_2_ROUNDED":68170,"EXPOSURE_NEG_2_SHARP":68171,"EXPOSURE_OUTLINED":68172,"EXPOSURE_PLUS_1":68173,"EXPOSURE_PLUS_1_OUTLINED":68174,"EXPOSURE_PLUS_1_ROUNDED":68175,"EXPOSURE_PLUS_1_SHARP":68176,"EXPOSURE_PLUS_2":68177,"EXPOSURE_PLUS_2_OUTLINED":68178,"EXPOSURE_PLUS_2_ROUNDED":68179,"EXPOSURE_PLUS_2_SHARP":68180,"EXPOSURE_ROUNDED":68181,"EXPOSURE_SHARP":68182,"EXPOSURE_ZERO":68183,"EXPOSURE_ZERO_OUTLINED":68184,"EXPOSURE_ZERO_ROUNDED":68185,"EXPOSURE_ZERO_SHARP":68186,"EXTENSION":68187,"EXTENSION_OFF":68188,"EXTENSION_OFF_OUTLINED":68189,"EXTENSION_OFF_ROUNDED":68190,"EXTENSION_OFF_SHARP":68191,"EXTENSION_OUTLINED":68192,"EXTENSION_ROUNDED":68193,"EXTENSION_SHARP":68194,"FACE":68195,"FACE_2":68196,"FACE_2_OUTLINED":68197,"FACE_2_ROUNDED":68198,"FACE_2_SHARP":68199,"FACE_3":68200,"FACE_3_OUTLINED":68201,"FACE_3_ROUNDED":68202,"FACE_3_SHARP":68203,"FACE_4":68204,"FACE_4_OUTLINED":68205,"FACE_4_ROUNDED":68206,"FACE_4_SHARP":68207,"FACE_5":68208,"FACE_5_OUTLINED":68209,"FACE_5_ROUNDED":68210,"FACE_5_SHARP":68211,"FACE_6":68212,"FACE_6_OUTLINED":68213,"FACE_6_ROUNDED":68214,"FACE_6_SHARP":68215,"FACE_OUTLINED":68216,"FACE_RETOUCHING_NATURAL":68217,"FACE_RETOUCHING_NATURAL_OUTLINED":68218,"FACE_RETOUCHING_NATURAL_ROUNDED":68219,"FACE_RETOUCHING_NATURAL_SHARP":68220,"FACE_RETOUCHING_OFF":68221,"FACE_RETOUCHING_OFF_OUTLINED":68222,"FACE_RETOUCHING_OFF_ROUNDED":68223,"FACE_RETOUCHING_OFF_SHARP":68224,"FACE_ROUNDED":68225,"FACE_SHARP":68226,"FACE_UNLOCK_OUTLINED":68227,"FACE_UNLOCK_ROUNDED":68228,"FACE_UNLOCK_SHARP":68229,"FACEBOOK":68230,"FACEBOOK_OUTLINED":68231,"FACEBOOK_ROUNDED":68232,"FACEBOOK_SHARP":68233,"FACT_CHECK":68234,"FACT_CHECK_OUTLINED":68235,"FACT_CHECK_ROUNDED":68236,"FACT_CHECK_SHARP":68237,"FACTORY":68238,"FACTORY_OUTLINED":68239,"FACTORY_ROUNDED":68240,"FACTORY_SHARP":68241,"FAMILY_RESTROOM":68242,"FAMILY_RESTROOM_OUTLINED":68243,"FAMILY_RESTROOM_ROUNDED":68244,"FAMILY_RESTROOM_SHARP":68245,"FAST_FORWARD":68246,"FAST_FORWARD_OUTLINED":68247,"FAST_FORWARD_ROUNDED":68248,"FAST_FORWARD_SHARP":68249,"FAST_REWIND":68250,"FAST_REWIND_OUTLINED":68251,"FAST_REWIND_ROUNDED":68252,"FAST_REWIND_SHARP":68253,"FASTFOOD":68254,"FASTFOOD_OUTLINED":68255,"FASTFOOD_ROUNDED":68256,"FASTFOOD_SHARP":68257,"FAVORITE":68258,"FAVORITE_BORDER":68259,"FAVORITE_BORDER_OUTLINED":68260,"FAVORITE_BORDER_ROUNDED":68261,"FAVORITE_BORDER_SHARP":68262,"FAVORITE_OUTLINE":68263,"FAVORITE_OUTLINE_OUTLINED":68264,"FAVORITE_OUTLINE_ROUNDED":68265,"FAVORITE_OUTLINE_SHARP":68266,"FAVORITE_OUTLINED":68267,"FAVORITE_ROUNDED":68268,"FAVORITE_SHARP":68269,"FAX":68270,"FAX_OUTLINED":68271,"FAX_ROUNDED":68272,"FAX_SHARP":68273,"FEATURED_PLAY_LIST":68274,"FEATURED_PLAY_LIST_OUTLINED":68275,"FEATURED_PLAY_LIST_ROUNDED":68276,"FEATURED_PLAY_LIST_SHARP":68277,"FEATURED_VIDEO":68278,"FEATURED_VIDEO_OUTLINED":68279,"FEATURED_VIDEO_ROUNDED":68280,"FEATURED_VIDEO_SHARP":68281,"FEED":68282,"FEED_OUTLINED":68283,"FEED_ROUNDED":68284,"FEED_SHARP":68285,"FEEDBACK":68286,"FEEDBACK_OUTLINED":68287,"FEEDBACK_ROUNDED":68288,"FEEDBACK_SHARP":68289,"FEMALE":68290,"FEMALE_OUTLINED":68291,"FEMALE_ROUNDED":68292,"FEMALE_SHARP":68293,"FENCE":68294,"FENCE_OUTLINED":68295,"FENCE_ROUNDED":68296,"FENCE_SHARP":68297,"FESTIVAL":68298,"FESTIVAL_OUTLINED":68299,"FESTIVAL_ROUNDED":68300,"FESTIVAL_SHARP":68301,"FIBER_DVR":68302,"FIBER_DVR_OUTLINED":68303,"FIBER_DVR_ROUNDED":68304,"FIBER_DVR_SHARP":68305,"FIBER_MANUAL_RECORD":68306,"FIBER_MANUAL_RECORD_OUTLINED":68307,"FIBER_MANUAL_RECORD_ROUNDED":68308,"FIBER_MANUAL_RECORD_SHARP":68309,"FIBER_NEW":68310,"FIBER_NEW_OUTLINED":68311,"FIBER_NEW_ROUNDED":68312,"FIBER_NEW_SHARP":68313,"FIBER_PIN":68314,"FIBER_PIN_OUTLINED":68315,"FIBER_PIN_ROUNDED":68316,"FIBER_PIN_SHARP":68317,"FIBER_SMART_RECORD":68318,"FIBER_SMART_RECORD_OUTLINED":68319,"FIBER_SMART_RECORD_ROUNDED":68320,"FIBER_SMART_RECORD_SHARP":68321,"FIFTEEN_MP":68322,"FIFTEEN_MP_OUTLINED":68323,"FIFTEEN_MP_ROUNDED":68324,"FIFTEEN_MP_SHARP":68325,"FILE_COPY":68326,"FILE_COPY_OUTLINED":68327,"FILE_COPY_ROUNDED":68328,"FILE_COPY_SHARP":68329,"FILE_DOWNLOAD":68330,"FILE_DOWNLOAD_DONE":68331,"FILE_DOWNLOAD_DONE_OUTLINED":68332,"FILE_DOWNLOAD_DONE_ROUNDED":68333,"FILE_DOWNLOAD_DONE_SHARP":68334,"FILE_DOWNLOAD_OFF":68335,"FILE_DOWNLOAD_OFF_OUTLINED":68336,"FILE_DOWNLOAD_OFF_ROUNDED":68337,"FILE_DOWNLOAD_OFF_SHARP":68338,"FILE_DOWNLOAD_OUTLINED":68339,"FILE_DOWNLOAD_ROUNDED":68340,"FILE_DOWNLOAD_SHARP":68341,"FILE_OPEN":68342,"FILE_OPEN_OUTLINED":68343,"FILE_OPEN_ROUNDED":68344,"FILE_OPEN_SHARP":68345,"FILE_PRESENT":68346,"FILE_PRESENT_OUTLINED":68347,"FILE_PRESENT_ROUNDED":68348,"FILE_PRESENT_SHARP":68349,"FILE_UPLOAD":68350,"FILE_UPLOAD_OFF":68351,"FILE_UPLOAD_OUTLINED":68352,"FILE_UPLOAD_ROUNDED":68353,"FILE_UPLOAD_SHARP":68354,"FILTER":68355,"FILTER_1":68356,"FILTER_1_OUTLINED":68357,"FILTER_1_ROUNDED":68358,"FILTER_1_SHARP":68359,"FILTER_2":68360,"FILTER_2_OUTLINED":68361,"FILTER_2_ROUNDED":68362,"FILTER_2_SHARP":68363,"FILTER_3":68364,"FILTER_3_OUTLINED":68365,"FILTER_3_ROUNDED":68366,"FILTER_3_SHARP":68367,"FILTER_4":68368,"FILTER_4_OUTLINED":68369,"FILTER_4_ROUNDED":68370,"FILTER_4_SHARP":68371,"FILTER_5":68372,"FILTER_5_OUTLINED":68373,"FILTER_5_ROUNDED":68374,"FILTER_5_SHARP":68375,"FILTER_6":68376,"FILTER_6_OUTLINED":68377,"FILTER_6_ROUNDED":68378,"FILTER_6_SHARP":68379,"FILTER_7":68380,"FILTER_7_OUTLINED":68381,"FILTER_7_ROUNDED":68382,"FILTER_7_SHARP":68383,"FILTER_8":68384,"FILTER_8_OUTLINED":68385,"FILTER_8_ROUNDED":68386,"FILTER_8_SHARP":68387,"FILTER_9":68388,"FILTER_9_OUTLINED":68389,"FILTER_9_PLUS":68390,"FILTER_9_PLUS_OUTLINED":68391,"FILTER_9_PLUS_ROUNDED":68392,"FILTER_9_PLUS_SHARP":68393,"FILTER_9_ROUNDED":68394,"FILTER_9_SHARP":68395,"FILTER_ALT":68396,"FILTER_ALT_OFF":68397,"FILTER_ALT_OFF_OUTLINED":68398,"FILTER_ALT_OFF_ROUNDED":68399,"FILTER_ALT_OFF_SHARP":68400,"FILTER_ALT_OUTLINED":68401,"FILTER_ALT_ROUNDED":68402,"FILTER_ALT_SHARP":68403,"FILTER_B_AND_W":68404,"FILTER_B_AND_W_OUTLINED":68405,"FILTER_B_AND_W_ROUNDED":68406,"FILTER_B_AND_W_SHARP":68407,"FILTER_CENTER_FOCUS":68408,"FILTER_CENTER_FOCUS_OUTLINED":68409,"FILTER_CENTER_FOCUS_ROUNDED":68410,"FILTER_CENTER_FOCUS_SHARP":68411,"FILTER_DRAMA":68412,"FILTER_DRAMA_OUTLINED":68413,"FILTER_DRAMA_ROUNDED":68414,"FILTER_DRAMA_SHARP":68415,"FILTER_FRAMES":68416,"FILTER_FRAMES_OUTLINED":68417,"FILTER_FRAMES_ROUNDED":68418,"FILTER_FRAMES_SHARP":68419,"FILTER_HDR":68420,"FILTER_HDR_OUTLINED":68421,"FILTER_HDR_ROUNDED":68422,"FILTER_HDR_SHARP":68423,"FILTER_LIST":68424,"FILTER_LIST_ALT":68425,"FILTER_LIST_OFF":68426,"FILTER_LIST_OFF_OUTLINED":68427,"FILTER_LIST_OFF_ROUNDED":68428,"FILTER_LIST_OFF_SHARP":68429,"FILTER_LIST_OUTLINED":68430,"FILTER_LIST_ROUNDED":68431,"FILTER_LIST_SHARP":68432,"FILTER_NONE":68433,"FILTER_NONE_OUTLINED":68434,"FILTER_NONE_ROUNDED":68435,"FILTER_NONE_SHARP":68436,"FILTER_OUTLINED":68437,"FILTER_ROUNDED":68438,"FILTER_SHARP":68439,"FILTER_TILT_SHIFT":68440,"FILTER_TILT_SHIFT_OUTLINED":68441,"FILTER_TILT_SHIFT_ROUNDED":68442,"FILTER_TILT_SHIFT_SHARP":68443,"FILTER_VINTAGE":68444,"FILTER_VINTAGE_OUTLINED":68445,"FILTER_VINTAGE_ROUNDED":68446,"FILTER_VINTAGE_SHARP":68447,"FIND_IN_PAGE":68448,"FIND_IN_PAGE_OUTLINED":68449,"FIND_IN_PAGE_ROUNDED":68450,"FIND_IN_PAGE_SHARP":68451,"FIND_REPLACE":68452,"FIND_REPLACE_OUTLINED":68453,"FIND_REPLACE_ROUNDED":68454,"FIND_REPLACE_SHARP":68455,"FINGERPRINT":68456,"FINGERPRINT_OUTLINED":68457,"FINGERPRINT_ROUNDED":68458,"FINGERPRINT_SHARP":68459,"FIRE_EXTINGUISHER":68460,"FIRE_EXTINGUISHER_OUTLINED":68461,"FIRE_EXTINGUISHER_ROUNDED":68462,"FIRE_EXTINGUISHER_SHARP":68463,"FIRE_HYDRANT":68464,"FIRE_HYDRANT_ALT":68465,"FIRE_HYDRANT_ALT_OUTLINED":68466,"FIRE_HYDRANT_ALT_ROUNDED":68467,"FIRE_HYDRANT_ALT_SHARP":68468,"FIRE_TRUCK":68469,"FIRE_TRUCK_OUTLINED":68470,"FIRE_TRUCK_ROUNDED":68471,"FIRE_TRUCK_SHARP":68472,"FIREPLACE":68473,"FIREPLACE_OUTLINED":68474,"FIREPLACE_ROUNDED":68475,"FIREPLACE_SHARP":68476,"FIRST_PAGE":68477,"FIRST_PAGE_OUTLINED":68478,"FIRST_PAGE_ROUNDED":68479,"FIRST_PAGE_SHARP":68480,"FIT_SCREEN":68481,"FIT_SCREEN_OUTLINED":68482,"FIT_SCREEN_ROUNDED":68483,"FIT_SCREEN_SHARP":68484,"FITBIT":68485,"FITBIT_OUTLINED":68486,"FITBIT_ROUNDED":68487,"FITBIT_SHARP":68488,"FITNESS_CENTER":68489,"FITNESS_CENTER_OUTLINED":68490,"FITNESS_CENTER_ROUNDED":68491,"FITNESS_CENTER_SHARP":68492,"FIVE_G":68493,"FIVE_G_OUTLINED":68494,"FIVE_G_ROUNDED":68495,"FIVE_G_SHARP":68496,"FIVE_K":68497,"FIVE_K_OUTLINED":68498,"FIVE_K_PLUS":68499,"FIVE_K_PLUS_OUTLINED":68500,"FIVE_K_PLUS_ROUNDED":68501,"FIVE_K_PLUS_SHARP":68502,"FIVE_K_ROUNDED":68503,"FIVE_K_SHARP":68504,"FIVE_MP":68505,"FIVE_MP_OUTLINED":68506,"FIVE_MP_ROUNDED":68507,"FIVE_MP_SHARP":68508,"FLAG":68509,"FLAG_CIRCLE":68510,"FLAG_CIRCLE_OUTLINED":68511,"FLAG_CIRCLE_ROUNDED":68512,"FLAG_CIRCLE_SHARP":68513,"FLAG_OUTLINED":68514,"FLAG_ROUNDED":68515,"FLAG_SHARP":68516,"FLAKY":68517,"FLAKY_OUTLINED":68518,"FLAKY_ROUNDED":68519,"FLAKY_SHARP":68520,"FLARE":68521,"FLARE_OUTLINED":68522,"FLARE_ROUNDED":68523,"FLARE_SHARP":68524,"FLASH_AUTO":68525,"FLASH_AUTO_OUTLINED":68526,"FLASH_AUTO_ROUNDED":68527,"FLASH_AUTO_SHARP":68528,"FLASH_OFF":68529,"FLASH_OFF_OUTLINED":68530,"FLASH_OFF_ROUNDED":68531,"FLASH_OFF_SHARP":68532,"FLASH_ON":68533,"FLASH_ON_OUTLINED":68534,"FLASH_ON_ROUNDED":68535,"FLASH_ON_SHARP":68536,"FLASHLIGHT_OFF":68537,"FLASHLIGHT_OFF_OUTLINED":68538,"FLASHLIGHT_OFF_ROUNDED":68539,"FLASHLIGHT_OFF_SHARP":68540,"FLASHLIGHT_ON":68541,"FLASHLIGHT_ON_OUTLINED":68542,"FLASHLIGHT_ON_ROUNDED":68543,"FLASHLIGHT_ON_SHARP":68544,"FLATWARE":68545,"FLATWARE_OUTLINED":68546,"FLATWARE_ROUNDED":68547,"FLATWARE_SHARP":68548,"FLIGHT":68549,"FLIGHT_CLASS":68550,"FLIGHT_CLASS_OUTLINED":68551,"FLIGHT_CLASS_ROUNDED":68552,"FLIGHT_CLASS_SHARP":68553,"FLIGHT_LAND":68554,"FLIGHT_LAND_OUTLINED":68555,"FLIGHT_LAND_ROUNDED":68556,"FLIGHT_LAND_SHARP":68557,"FLIGHT_OUTLINED":68558,"FLIGHT_ROUNDED":68559,"FLIGHT_SHARP":68560,"FLIGHT_TAKEOFF":68561,"FLIGHT_TAKEOFF_OUTLINED":68562,"FLIGHT_TAKEOFF_ROUNDED":68563,"FLIGHT_TAKEOFF_SHARP":68564,"FLIP":68565,"FLIP_CAMERA_ANDROID":68566,"FLIP_CAMERA_ANDROID_OUTLINED":68567,"FLIP_CAMERA_ANDROID_ROUNDED":68568,"FLIP_CAMERA_ANDROID_SHARP":68569,"FLIP_CAMERA_IOS":68570,"FLIP_CAMERA_IOS_OUTLINED":68571,"FLIP_CAMERA_IOS_ROUNDED":68572,"FLIP_CAMERA_IOS_SHARP":68573,"FLIP_OUTLINED":68574,"FLIP_ROUNDED":68575,"FLIP_SHARP":68576,"FLIP_TO_BACK":68577,"FLIP_TO_BACK_OUTLINED":68578,"FLIP_TO_BACK_ROUNDED":68579,"FLIP_TO_BACK_SHARP":68580,"FLIP_TO_FRONT":68581,"FLIP_TO_FRONT_OUTLINED":68582,"FLIP_TO_FRONT_ROUNDED":68583,"FLIP_TO_FRONT_SHARP":68584,"FLOOD":68585,"FLOOD_OUTLINED":68586,"FLOOD_ROUNDED":68587,"FLOOD_SHARP":68588,"FLOURESCENT":68589,"FLOURESCENT_OUTLINED":68590,"FLOURESCENT_ROUNDED":68591,"FLOURESCENT_SHARP":68592,"FLUORESCENT":68593,"FLUORESCENT_OUTLINED":68594,"FLUORESCENT_ROUNDED":68595,"FLUORESCENT_SHARP":68596,"FLUTTER_DASH":68597,"FLUTTER_DASH_OUTLINED":68598,"FLUTTER_DASH_ROUNDED":68599,"FLUTTER_DASH_SHARP":68600,"FMD_BAD":68601,"FMD_BAD_OUTLINED":68602,"FMD_BAD_ROUNDED":68603,"FMD_BAD_SHARP":68604,"FMD_GOOD":68605,"FMD_GOOD_OUTLINED":68606,"FMD_GOOD_ROUNDED":68607,"FMD_GOOD_SHARP":68608,"FOGGY":68609,"FOLDER":68610,"FOLDER_COPY":68611,"FOLDER_COPY_OUTLINED":68612,"FOLDER_COPY_ROUNDED":68613,"FOLDER_COPY_SHARP":68614,"FOLDER_DELETE":68615,"FOLDER_DELETE_OUTLINED":68616,"FOLDER_DELETE_ROUNDED":68617,"FOLDER_DELETE_SHARP":68618,"FOLDER_OFF":68619,"FOLDER_OFF_OUTLINED":68620,"FOLDER_OFF_ROUNDED":68621,"FOLDER_OFF_SHARP":68622,"FOLDER_OPEN":68623,"FOLDER_OPEN_OUTLINED":68624,"FOLDER_OPEN_ROUNDED":68625,"FOLDER_OPEN_SHARP":68626,"FOLDER_OUTLINED":68627,"FOLDER_ROUNDED":68628,"FOLDER_SHARED":68629,"FOLDER_SHARED_OUTLINED":68630,"FOLDER_SHARED_ROUNDED":68631,"FOLDER_SHARED_SHARP":68632,"FOLDER_SHARP":68633,"FOLDER_SPECIAL":68634,"FOLDER_SPECIAL_OUTLINED":68635,"FOLDER_SPECIAL_ROUNDED":68636,"FOLDER_SPECIAL_SHARP":68637,"FOLDER_ZIP":68638,"FOLDER_ZIP_OUTLINED":68639,"FOLDER_ZIP_ROUNDED":68640,"FOLDER_ZIP_SHARP":68641,"FOLLOW_THE_SIGNS":68642,"FOLLOW_THE_SIGNS_OUTLINED":68643,"FOLLOW_THE_SIGNS_ROUNDED":68644,"FOLLOW_THE_SIGNS_SHARP":68645,"FONT_DOWNLOAD":68646,"FONT_DOWNLOAD_OFF":68647,"FONT_DOWNLOAD_OFF_OUTLINED":68648,"FONT_DOWNLOAD_OFF_ROUNDED":68649,"FONT_DOWNLOAD_OFF_SHARP":68650,"FONT_DOWNLOAD_OUTLINED":68651,"FONT_DOWNLOAD_ROUNDED":68652,"FONT_DOWNLOAD_SHARP":68653,"FOOD_BANK":68654,"FOOD_BANK_OUTLINED":68655,"FOOD_BANK_ROUNDED":68656,"FOOD_BANK_SHARP":68657,"FOREST":68658,"FOREST_OUTLINED":68659,"FOREST_ROUNDED":68660,"FOREST_SHARP":68661,"FORK_LEFT":68662,"FORK_LEFT_OUTLINED":68663,"FORK_LEFT_ROUNDED":68664,"FORK_LEFT_SHARP":68665,"FORK_RIGHT":68666,"FORK_RIGHT_OUTLINED":68667,"FORK_RIGHT_ROUNDED":68668,"FORK_RIGHT_SHARP":68669,"FORKLIFT":68670,"FORMAT_ALIGN_CENTER":68671,"FORMAT_ALIGN_CENTER_OUTLINED":68672,"FORMAT_ALIGN_CENTER_ROUNDED":68673,"FORMAT_ALIGN_CENTER_SHARP":68674,"FORMAT_ALIGN_JUSTIFY":68675,"FORMAT_ALIGN_JUSTIFY_OUTLINED":68676,"FORMAT_ALIGN_JUSTIFY_ROUNDED":68677,"FORMAT_ALIGN_JUSTIFY_SHARP":68678,"FORMAT_ALIGN_LEFT":68679,"FORMAT_ALIGN_LEFT_OUTLINED":68680,"FORMAT_ALIGN_LEFT_ROUNDED":68681,"FORMAT_ALIGN_LEFT_SHARP":68682,"FORMAT_ALIGN_RIGHT":68683,"FORMAT_ALIGN_RIGHT_OUTLINED":68684,"FORMAT_ALIGN_RIGHT_ROUNDED":68685,"FORMAT_ALIGN_RIGHT_SHARP":68686,"FORMAT_BOLD":68687,"FORMAT_BOLD_OUTLINED":68688,"FORMAT_BOLD_ROUNDED":68689,"FORMAT_BOLD_SHARP":68690,"FORMAT_CLEAR":68691,"FORMAT_CLEAR_OUTLINED":68692,"FORMAT_CLEAR_ROUNDED":68693,"FORMAT_CLEAR_SHARP":68694,"FORMAT_COLOR_FILL":68695,"FORMAT_COLOR_FILL_OUTLINED":68696,"FORMAT_COLOR_FILL_ROUNDED":68697,"FORMAT_COLOR_FILL_SHARP":68698,"FORMAT_COLOR_RESET":68699,"FORMAT_COLOR_RESET_OUTLINED":68700,"FORMAT_COLOR_RESET_ROUNDED":68701,"FORMAT_COLOR_RESET_SHARP":68702,"FORMAT_COLOR_TEXT":68703,"FORMAT_COLOR_TEXT_OUTLINED":68704,"FORMAT_COLOR_TEXT_ROUNDED":68705,"FORMAT_COLOR_TEXT_SHARP":68706,"FORMAT_INDENT_DECREASE":68707,"FORMAT_INDENT_DECREASE_OUTLINED":68708,"FORMAT_INDENT_DECREASE_ROUNDED":68709,"FORMAT_INDENT_DECREASE_SHARP":68710,"FORMAT_INDENT_INCREASE":68711,"FORMAT_INDENT_INCREASE_OUTLINED":68712,"FORMAT_INDENT_INCREASE_ROUNDED":68713,"FORMAT_INDENT_INCREASE_SHARP":68714,"FORMAT_ITALIC":68715,"FORMAT_ITALIC_OUTLINED":68716,"FORMAT_ITALIC_ROUNDED":68717,"FORMAT_ITALIC_SHARP":68718,"FORMAT_LINE_SPACING":68719,"FORMAT_LINE_SPACING_OUTLINED":68720,"FORMAT_LINE_SPACING_ROUNDED":68721,"FORMAT_LINE_SPACING_SHARP":68722,"FORMAT_LIST_BULLETED":68723,"FORMAT_LIST_BULLETED_ADD":68724,"FORMAT_LIST_BULLETED_OUTLINED":68725,"FORMAT_LIST_BULLETED_ROUNDED":68726,"FORMAT_LIST_BULLETED_SHARP":68727,"FORMAT_LIST_NUMBERED":68728,"FORMAT_LIST_NUMBERED_OUTLINED":68729,"FORMAT_LIST_NUMBERED_ROUNDED":68730,"FORMAT_LIST_NUMBERED_RTL":68731,"FORMAT_LIST_NUMBERED_RTL_OUTLINED":68732,"FORMAT_LIST_NUMBERED_RTL_ROUNDED":68733,"FORMAT_LIST_NUMBERED_RTL_SHARP":68734,"FORMAT_LIST_NUMBERED_SHARP":68735,"FORMAT_OVERLINE":68736,"FORMAT_OVERLINE_OUTLINED":68737,"FORMAT_OVERLINE_ROUNDED":68738,"FORMAT_OVERLINE_SHARP":68739,"FORMAT_PAINT":68740,"FORMAT_PAINT_OUTLINED":68741,"FORMAT_PAINT_ROUNDED":68742,"FORMAT_PAINT_SHARP":68743,"FORMAT_QUOTE":68744,"FORMAT_QUOTE_OUTLINED":68745,"FORMAT_QUOTE_ROUNDED":68746,"FORMAT_QUOTE_SHARP":68747,"FORMAT_SHAPES":68748,"FORMAT_SHAPES_OUTLINED":68749,"FORMAT_SHAPES_ROUNDED":68750,"FORMAT_SHAPES_SHARP":68751,"FORMAT_SIZE":68752,"FORMAT_SIZE_OUTLINED":68753,"FORMAT_SIZE_ROUNDED":68754,"FORMAT_SIZE_SHARP":68755,"FORMAT_STRIKETHROUGH":68756,"FORMAT_STRIKETHROUGH_OUTLINED":68757,"FORMAT_STRIKETHROUGH_ROUNDED":68758,"FORMAT_STRIKETHROUGH_SHARP":68759,"FORMAT_TEXTDIRECTION_L_TO_R":68760,"FORMAT_TEXTDIRECTION_L_TO_R_OUTLINED":68761,"FORMAT_TEXTDIRECTION_L_TO_R_ROUNDED":68762,"FORMAT_TEXTDIRECTION_L_TO_R_SHARP":68763,"FORMAT_TEXTDIRECTION_R_TO_L":68764,"FORMAT_TEXTDIRECTION_R_TO_L_OUTLINED":68765,"FORMAT_TEXTDIRECTION_R_TO_L_ROUNDED":68766,"FORMAT_TEXTDIRECTION_R_TO_L_SHARP":68767,"FORMAT_UNDERLINE":68768,"FORMAT_UNDERLINE_OUTLINED":68769,"FORMAT_UNDERLINE_ROUNDED":68770,"FORMAT_UNDERLINE_SHARP":68771,"FORMAT_UNDERLINED":68772,"FORMAT_UNDERLINED_OUTLINED":68773,"FORMAT_UNDERLINED_ROUNDED":68774,"FORMAT_UNDERLINED_SHARP":68775,"FORT":68776,"FORT_OUTLINED":68777,"FORT_ROUNDED":68778,"FORT_SHARP":68779,"FORUM":68780,"FORUM_OUTLINED":68781,"FORUM_ROUNDED":68782,"FORUM_SHARP":68783,"FORWARD":68784,"FORWARD_10":68785,"FORWARD_10_OUTLINED":68786,"FORWARD_10_ROUNDED":68787,"FORWARD_10_SHARP":68788,"FORWARD_30":68789,"FORWARD_30_OUTLINED":68790,"FORWARD_30_ROUNDED":68791,"FORWARD_30_SHARP":68792,"FORWARD_5":68793,"FORWARD_5_OUTLINED":68794,"FORWARD_5_ROUNDED":68795,"FORWARD_5_SHARP":68796,"FORWARD_OUTLINED":68797,"FORWARD_ROUNDED":68798,"FORWARD_SHARP":68799,"FORWARD_TO_INBOX":68800,"FORWARD_TO_INBOX_OUTLINED":68801,"FORWARD_TO_INBOX_ROUNDED":68802,"FORWARD_TO_INBOX_SHARP":68803,"FOUNDATION":68804,"FOUNDATION_OUTLINED":68805,"FOUNDATION_ROUNDED":68806,"FOUNDATION_SHARP":68807,"FOUR_G_MOBILEDATA":68808,"FOUR_G_MOBILEDATA_OUTLINED":68809,"FOUR_G_MOBILEDATA_ROUNDED":68810,"FOUR_G_MOBILEDATA_SHARP":68811,"FOUR_G_PLUS_MOBILEDATA":68812,"FOUR_G_PLUS_MOBILEDATA_OUTLINED":68813,"FOUR_G_PLUS_MOBILEDATA_ROUNDED":68814,"FOUR_G_PLUS_MOBILEDATA_SHARP":68815,"FOUR_K":68816,"FOUR_K_OUTLINED":68817,"FOUR_K_PLUS":68818,"FOUR_K_PLUS_OUTLINED":68819,"FOUR_K_PLUS_ROUNDED":68820,"FOUR_K_PLUS_SHARP":68821,"FOUR_K_ROUNDED":68822,"FOUR_K_SHARP":68823,"FOUR_MP":68824,"FOUR_MP_OUTLINED":68825,"FOUR_MP_ROUNDED":68826,"FOUR_MP_SHARP":68827,"FOURTEEN_MP":68828,"FOURTEEN_MP_OUTLINED":68829,"FOURTEEN_MP_ROUNDED":68830,"FOURTEEN_MP_SHARP":68831,"FREE_BREAKFAST":68832,"FREE_BREAKFAST_OUTLINED":68833,"FREE_BREAKFAST_ROUNDED":68834,"FREE_BREAKFAST_SHARP":68835,"FREE_CANCELLATION":68836,"FREE_CANCELLATION_OUTLINED":68837,"FREE_CANCELLATION_ROUNDED":68838,"FREE_CANCELLATION_SHARP":68839,"FRONT_HAND":68840,"FRONT_HAND_OUTLINED":68841,"FRONT_HAND_ROUNDED":68842,"FRONT_HAND_SHARP":68843,"FRONT_LOADER":68844,"FULLSCREEN":68845,"FULLSCREEN_EXIT":68846,"FULLSCREEN_EXIT_OUTLINED":68847,"FULLSCREEN_EXIT_ROUNDED":68848,"FULLSCREEN_EXIT_SHARP":68849,"FULLSCREEN_OUTLINED":68850,"FULLSCREEN_ROUNDED":68851,"FULLSCREEN_SHARP":68852,"FUNCTIONS":68853,"FUNCTIONS_OUTLINED":68854,"FUNCTIONS_ROUNDED":68855,"FUNCTIONS_SHARP":68856,"G_MOBILEDATA":68857,"G_MOBILEDATA_OUTLINED":68858,"G_MOBILEDATA_ROUNDED":68859,"G_MOBILEDATA_SHARP":68860,"G_TRANSLATE":68861,"G_TRANSLATE_OUTLINED":68862,"G_TRANSLATE_ROUNDED":68863,"G_TRANSLATE_SHARP":68864,"GAMEPAD":68865,"GAMEPAD_OUTLINED":68866,"GAMEPAD_ROUNDED":68867,"GAMEPAD_SHARP":68868,"GAMES":68869,"GAMES_OUTLINED":68870,"GAMES_ROUNDED":68871,"GAMES_SHARP":68872,"GARAGE":68873,"GARAGE_OUTLINED":68874,"GARAGE_ROUNDED":68875,"GARAGE_SHARP":68876,"GAS_METER":68877,"GAS_METER_OUTLINED":68878,"GAS_METER_ROUNDED":68879,"GAS_METER_SHARP":68880,"GAVEL":68881,"GAVEL_OUTLINED":68882,"GAVEL_ROUNDED":68883,"GAVEL_SHARP":68884,"GENERATING_TOKENS":68885,"GENERATING_TOKENS_OUTLINED":68886,"GENERATING_TOKENS_ROUNDED":68887,"GENERATING_TOKENS_SHARP":68888,"GESTURE":68889,"GESTURE_OUTLINED":68890,"GESTURE_ROUNDED":68891,"GESTURE_SHARP":68892,"GET_APP":68893,"GET_APP_OUTLINED":68894,"GET_APP_ROUNDED":68895,"GET_APP_SHARP":68896,"GIF":68897,"GIF_BOX":68898,"GIF_BOX_OUTLINED":68899,"GIF_BOX_ROUNDED":68900,"GIF_BOX_SHARP":68901,"GIF_OUTLINED":68902,"GIF_ROUNDED":68903,"GIF_SHARP":68904,"GIRL":68905,"GIRL_OUTLINED":68906,"GIRL_ROUNDED":68907,"GIRL_SHARP":68908,"GITE":68909,"GITE_OUTLINED":68910,"GITE_ROUNDED":68911,"GITE_SHARP":68912,"GOLF_COURSE":68913,"GOLF_COURSE_OUTLINED":68914,"GOLF_COURSE_ROUNDED":68915,"GOLF_COURSE_SHARP":68916,"GPP_BAD":68917,"GPP_BAD_OUTLINED":68918,"GPP_BAD_ROUNDED":68919,"GPP_BAD_SHARP":68920,"GPP_GOOD":68921,"GPP_GOOD_OUTLINED":68922,"GPP_GOOD_ROUNDED":68923,"GPP_GOOD_SHARP":68924,"GPP_MAYBE":68925,"GPP_MAYBE_OUTLINED":68926,"GPP_MAYBE_ROUNDED":68927,"GPP_MAYBE_SHARP":68928,"GPS_FIXED":68929,"GPS_FIXED_OUTLINED":68930,"GPS_FIXED_ROUNDED":68931,"GPS_FIXED_SHARP":68932,"GPS_NOT_FIXED":68933,"GPS_NOT_FIXED_OUTLINED":68934,"GPS_NOT_FIXED_ROUNDED":68935,"GPS_NOT_FIXED_SHARP":68936,"GPS_OFF":68937,"GPS_OFF_OUTLINED":68938,"GPS_OFF_ROUNDED":68939,"GPS_OFF_SHARP":68940,"GRADE":68941,"GRADE_OUTLINED":68942,"GRADE_ROUNDED":68943,"GRADE_SHARP":68944,"GRADIENT":68945,"GRADIENT_OUTLINED":68946,"GRADIENT_ROUNDED":68947,"GRADIENT_SHARP":68948,"GRADING":68949,"GRADING_OUTLINED":68950,"GRADING_ROUNDED":68951,"GRADING_SHARP":68952,"GRAIN":68953,"GRAIN_OUTLINED":68954,"GRAIN_ROUNDED":68955,"GRAIN_SHARP":68956,"GRAPHIC_EQ":68957,"GRAPHIC_EQ_OUTLINED":68958,"GRAPHIC_EQ_ROUNDED":68959,"GRAPHIC_EQ_SHARP":68960,"GRASS":68961,"GRASS_OUTLINED":68962,"GRASS_ROUNDED":68963,"GRASS_SHARP":68964,"GRID_3X3":68965,"GRID_3X3_OUTLINED":68966,"GRID_3X3_ROUNDED":68967,"GRID_3X3_SHARP":68968,"GRID_4X4":68969,"GRID_4X4_OUTLINED":68970,"GRID_4X4_ROUNDED":68971,"GRID_4X4_SHARP":68972,"GRID_GOLDENRATIO":68973,"GRID_GOLDENRATIO_OUTLINED":68974,"GRID_GOLDENRATIO_ROUNDED":68975,"GRID_GOLDENRATIO_SHARP":68976,"GRID_OFF":68977,"GRID_OFF_OUTLINED":68978,"GRID_OFF_ROUNDED":68979,"GRID_OFF_SHARP":68980,"GRID_ON":68981,"GRID_ON_OUTLINED":68982,"GRID_ON_ROUNDED":68983,"GRID_ON_SHARP":68984,"GRID_VIEW":68985,"GRID_VIEW_OUTLINED":68986,"GRID_VIEW_ROUNDED":68987,"GRID_VIEW_SHARP":68988,"GROUP":68989,"GROUP_ADD":68990,"GROUP_ADD_OUTLINED":68991,"GROUP_ADD_ROUNDED":68992,"GROUP_ADD_SHARP":68993,"GROUP_OFF":68994,"GROUP_OFF_OUTLINED":68995,"GROUP_OFF_ROUNDED":68996,"GROUP_OFF_SHARP":68997,"GROUP_OUTLINED":68998,"GROUP_REMOVE":68999,"GROUP_REMOVE_OUTLINED":69000,"GROUP_REMOVE_ROUNDED":69001,"GROUP_REMOVE_SHARP":69002,"GROUP_ROUNDED":69003,"GROUP_SHARP":69004,"GROUP_WORK":69005,"GROUP_WORK_OUTLINED":69006,"GROUP_WORK_ROUNDED":69007,"GROUP_WORK_SHARP":69008,"GROUPS":69009,"GROUPS_2":69010,"GROUPS_2_OUTLINED":69011,"GROUPS_2_ROUNDED":69012,"GROUPS_2_SHARP":69013,"GROUPS_3":69014,"GROUPS_3_OUTLINED":69015,"GROUPS_3_ROUNDED":69016,"GROUPS_3_SHARP":69017,"GROUPS_OUTLINED":69018,"GROUPS_ROUNDED":69019,"GROUPS_SHARP":69020,"H_MOBILEDATA":69021,"H_MOBILEDATA_OUTLINED":69022,"H_MOBILEDATA_ROUNDED":69023,"H_MOBILEDATA_SHARP":69024,"H_PLUS_MOBILEDATA":69025,"H_PLUS_MOBILEDATA_OUTLINED":69026,"H_PLUS_MOBILEDATA_ROUNDED":69027,"H_PLUS_MOBILEDATA_SHARP":69028,"HAIL":69029,"HAIL_OUTLINED":69030,"HAIL_ROUNDED":69031,"HAIL_SHARP":69032,"HANDSHAKE":69033,"HANDSHAKE_OUTLINED":69034,"HANDSHAKE_ROUNDED":69035,"HANDSHAKE_SHARP":69036,"HANDYMAN":69037,"HANDYMAN_OUTLINED":69038,"HANDYMAN_ROUNDED":69039,"HANDYMAN_SHARP":69040,"HARDWARE":69041,"HARDWARE_OUTLINED":69042,"HARDWARE_ROUNDED":69043,"HARDWARE_SHARP":69044,"HD":69045,"HD_OUTLINED":69046,"HD_ROUNDED":69047,"HD_SHARP":69048,"HDR_AUTO":69049,"HDR_AUTO_OUTLINED":69050,"HDR_AUTO_ROUNDED":69051,"HDR_AUTO_SELECT":69052,"HDR_AUTO_SELECT_OUTLINED":69053,"HDR_AUTO_SELECT_ROUNDED":69054,"HDR_AUTO_SELECT_SHARP":69055,"HDR_AUTO_SHARP":69056,"HDR_ENHANCED_SELECT":69057,"HDR_ENHANCED_SELECT_OUTLINED":69058,"HDR_ENHANCED_SELECT_ROUNDED":69059,"HDR_ENHANCED_SELECT_SHARP":69060,"HDR_OFF":69061,"HDR_OFF_OUTLINED":69062,"HDR_OFF_ROUNDED":69063,"HDR_OFF_SELECT":69064,"HDR_OFF_SELECT_OUTLINED":69065,"HDR_OFF_SELECT_ROUNDED":69066,"HDR_OFF_SELECT_SHARP":69067,"HDR_OFF_SHARP":69068,"HDR_ON":69069,"HDR_ON_OUTLINED":69070,"HDR_ON_ROUNDED":69071,"HDR_ON_SELECT":69072,"HDR_ON_SELECT_OUTLINED":69073,"HDR_ON_SELECT_ROUNDED":69074,"HDR_ON_SELECT_SHARP":69075,"HDR_ON_SHARP":69076,"HDR_PLUS":69077,"HDR_PLUS_OUTLINED":69078,"HDR_PLUS_ROUNDED":69079,"HDR_PLUS_SHARP":69080,"HDR_STRONG":69081,"HDR_STRONG_OUTLINED":69082,"HDR_STRONG_ROUNDED":69083,"HDR_STRONG_SHARP":69084,"HDR_WEAK":69085,"HDR_WEAK_OUTLINED":69086,"HDR_WEAK_ROUNDED":69087,"HDR_WEAK_SHARP":69088,"HEADPHONES":69089,"HEADPHONES_BATTERY":69090,"HEADPHONES_BATTERY_OUTLINED":69091,"HEADPHONES_BATTERY_ROUNDED":69092,"HEADPHONES_BATTERY_SHARP":69093,"HEADPHONES_OUTLINED":69094,"HEADPHONES_ROUNDED":69095,"HEADPHONES_SHARP":69096,"HEADSET":69097,"HEADSET_MIC":69098,"HEADSET_MIC_OUTLINED":69099,"HEADSET_MIC_ROUNDED":69100,"HEADSET_MIC_SHARP":69101,"HEADSET_OFF":69102,"HEADSET_OFF_OUTLINED":69103,"HEADSET_OFF_ROUNDED":69104,"HEADSET_OFF_SHARP":69105,"HEADSET_OUTLINED":69106,"HEADSET_ROUNDED":69107,"HEADSET_SHARP":69108,"HEALING":69109,"HEALING_OUTLINED":69110,"HEALING_ROUNDED":69111,"HEALING_SHARP":69112,"HEALTH_AND_SAFETY":69113,"HEALTH_AND_SAFETY_OUTLINED":69114,"HEALTH_AND_SAFETY_ROUNDED":69115,"HEALTH_AND_SAFETY_SHARP":69116,"HEARING":69117,"HEARING_DISABLED":69118,"HEARING_DISABLED_OUTLINED":69119,"HEARING_DISABLED_ROUNDED":69120,"HEARING_DISABLED_SHARP":69121,"HEARING_OUTLINED":69122,"HEARING_ROUNDED":69123,"HEARING_SHARP":69124,"HEART_BROKEN":69125,"HEART_BROKEN_OUTLINED":69126,"HEART_BROKEN_ROUNDED":69127,"HEART_BROKEN_SHARP":69128,"HEAT_PUMP":69129,"HEAT_PUMP_OUTLINED":69130,"HEAT_PUMP_ROUNDED":69131,"HEAT_PUMP_SHARP":69132,"HEIGHT":69133,"HEIGHT_OUTLINED":69134,"HEIGHT_ROUNDED":69135,"HEIGHT_SHARP":69136,"HELP":69137,"HELP_CENTER":69138,"HELP_CENTER_OUTLINED":69139,"HELP_CENTER_ROUNDED":69140,"HELP_CENTER_SHARP":69141,"HELP_OUTLINE":69142,"HELP_OUTLINE_OUTLINED":69143,"HELP_OUTLINE_ROUNDED":69144,"HELP_OUTLINE_SHARP":69145,"HELP_OUTLINED":69146,"HELP_ROUNDED":69147,"HELP_SHARP":69148,"HEVC":69149,"HEVC_OUTLINED":69150,"HEVC_ROUNDED":69151,"HEVC_SHARP":69152,"HEXAGON":69153,"HEXAGON_OUTLINED":69154,"HEXAGON_ROUNDED":69155,"HEXAGON_SHARP":69156,"HIDE_IMAGE":69157,"HIDE_IMAGE_OUTLINED":69158,"HIDE_IMAGE_ROUNDED":69159,"HIDE_IMAGE_SHARP":69160,"HIDE_SOURCE":69161,"HIDE_SOURCE_OUTLINED":69162,"HIDE_SOURCE_ROUNDED":69163,"HIDE_SOURCE_SHARP":69164,"HIGH_QUALITY":69165,"HIGH_QUALITY_OUTLINED":69166,"HIGH_QUALITY_ROUNDED":69167,"HIGH_QUALITY_SHARP":69168,"HIGHLIGHT":69169,"HIGHLIGHT_ALT":69170,"HIGHLIGHT_ALT_OUTLINED":69171,"HIGHLIGHT_ALT_ROUNDED":69172,"HIGHLIGHT_ALT_SHARP":69173,"HIGHLIGHT_OFF":69174,"HIGHLIGHT_OFF_OUTLINED":69175,"HIGHLIGHT_OFF_ROUNDED":69176,"HIGHLIGHT_OFF_SHARP":69177,"HIGHLIGHT_OUTLINED":69178,"HIGHLIGHT_REMOVE":69179,"HIGHLIGHT_REMOVE_OUTLINED":69180,"HIGHLIGHT_REMOVE_ROUNDED":69181,"HIGHLIGHT_REMOVE_SHARP":69182,"HIGHLIGHT_ROUNDED":69183,"HIGHLIGHT_SHARP":69184,"HIKING":69185,"HIKING_OUTLINED":69186,"HIKING_ROUNDED":69187,"HIKING_SHARP":69188,"HISTORY":69189,"HISTORY_EDU":69190,"HISTORY_EDU_OUTLINED":69191,"HISTORY_EDU_ROUNDED":69192,"HISTORY_EDU_SHARP":69193,"HISTORY_OUTLINED":69194,"HISTORY_ROUNDED":69195,"HISTORY_SHARP":69196,"HISTORY_TOGGLE_OFF":69197,"HISTORY_TOGGLE_OFF_OUTLINED":69198,"HISTORY_TOGGLE_OFF_ROUNDED":69199,"HISTORY_TOGGLE_OFF_SHARP":69200,"HIVE":69201,"HIVE_OUTLINED":69202,"HIVE_ROUNDED":69203,"HIVE_SHARP":69204,"HLS":69205,"HLS_OFF":69206,"HLS_OFF_OUTLINED":69207,"HLS_OFF_ROUNDED":69208,"HLS_OFF_SHARP":69209,"HLS_OUTLINED":69210,"HLS_ROUNDED":69211,"HLS_SHARP":69212,"HOLIDAY_VILLAGE":69213,"HOLIDAY_VILLAGE_OUTLINED":69214,"HOLIDAY_VILLAGE_ROUNDED":69215,"HOLIDAY_VILLAGE_SHARP":69216,"HOME":69217,"HOME_FILLED":69218,"HOME_MAX":69219,"HOME_MAX_OUTLINED":69220,"HOME_MAX_ROUNDED":69221,"HOME_MAX_SHARP":69222,"HOME_MINI":69223,"HOME_MINI_OUTLINED":69224,"HOME_MINI_ROUNDED":69225,"HOME_MINI_SHARP":69226,"HOME_OUTLINED":69227,"HOME_REPAIR_SERVICE":69228,"HOME_REPAIR_SERVICE_OUTLINED":69229,"HOME_REPAIR_SERVICE_ROUNDED":69230,"HOME_REPAIR_SERVICE_SHARP":69231,"HOME_ROUNDED":69232,"HOME_SHARP":69233,"HOME_WORK":69234,"HOME_WORK_OUTLINED":69235,"HOME_WORK_ROUNDED":69236,"HOME_WORK_SHARP":69237,"HORIZONTAL_DISTRIBUTE":69238,"HORIZONTAL_DISTRIBUTE_OUTLINED":69239,"HORIZONTAL_DISTRIBUTE_ROUNDED":69240,"HORIZONTAL_DISTRIBUTE_SHARP":69241,"HORIZONTAL_RULE":69242,"HORIZONTAL_RULE_OUTLINED":69243,"HORIZONTAL_RULE_ROUNDED":69244,"HORIZONTAL_RULE_SHARP":69245,"HORIZONTAL_SPLIT":69246,"HORIZONTAL_SPLIT_OUTLINED":69247,"HORIZONTAL_SPLIT_ROUNDED":69248,"HORIZONTAL_SPLIT_SHARP":69249,"HOT_TUB":69250,"HOT_TUB_OUTLINED":69251,"HOT_TUB_ROUNDED":69252,"HOT_TUB_SHARP":69253,"HOTEL":69254,"HOTEL_CLASS":69255,"HOTEL_CLASS_OUTLINED":69256,"HOTEL_CLASS_ROUNDED":69257,"HOTEL_CLASS_SHARP":69258,"HOTEL_OUTLINED":69259,"HOTEL_ROUNDED":69260,"HOTEL_SHARP":69261,"HOURGLASS_BOTTOM":69262,"HOURGLASS_BOTTOM_OUTLINED":69263,"HOURGLASS_BOTTOM_ROUNDED":69264,"HOURGLASS_BOTTOM_SHARP":69265,"HOURGLASS_DISABLED":69266,"HOURGLASS_DISABLED_OUTLINED":69267,"HOURGLASS_DISABLED_ROUNDED":69268,"HOURGLASS_DISABLED_SHARP":69269,"HOURGLASS_EMPTY":69270,"HOURGLASS_EMPTY_OUTLINED":69271,"HOURGLASS_EMPTY_ROUNDED":69272,"HOURGLASS_EMPTY_SHARP":69273,"HOURGLASS_FULL":69274,"HOURGLASS_FULL_OUTLINED":69275,"HOURGLASS_FULL_ROUNDED":69276,"HOURGLASS_FULL_SHARP":69277,"HOURGLASS_TOP":69278,"HOURGLASS_TOP_OUTLINED":69279,"HOURGLASS_TOP_ROUNDED":69280,"HOURGLASS_TOP_SHARP":69281,"HOUSE":69282,"HOUSE_OUTLINED":69283,"HOUSE_ROUNDED":69284,"HOUSE_SHARP":69285,"HOUSE_SIDING":69286,"HOUSE_SIDING_OUTLINED":69287,"HOUSE_SIDING_ROUNDED":69288,"HOUSE_SIDING_SHARP":69289,"HOUSEBOAT":69290,"HOUSEBOAT_OUTLINED":69291,"HOUSEBOAT_ROUNDED":69292,"HOUSEBOAT_SHARP":69293,"HOW_TO_REG":69294,"HOW_TO_REG_OUTLINED":69295,"HOW_TO_REG_ROUNDED":69296,"HOW_TO_REG_SHARP":69297,"HOW_TO_VOTE":69298,"HOW_TO_VOTE_OUTLINED":69299,"HOW_TO_VOTE_ROUNDED":69300,"HOW_TO_VOTE_SHARP":69301,"HTML":69302,"HTML_OUTLINED":69303,"HTML_ROUNDED":69304,"HTML_SHARP":69305,"HTTP":69306,"HTTP_OUTLINED":69307,"HTTP_ROUNDED":69308,"HTTP_SHARP":69309,"HTTPS":69310,"HTTPS_OUTLINED":69311,"HTTPS_ROUNDED":69312,"HTTPS_SHARP":69313,"HUB":69314,"HUB_OUTLINED":69315,"HUB_ROUNDED":69316,"HUB_SHARP":69317,"HVAC":69318,"HVAC_OUTLINED":69319,"HVAC_ROUNDED":69320,"HVAC_SHARP":69321,"ICE_SKATING":69322,"ICE_SKATING_OUTLINED":69323,"ICE_SKATING_ROUNDED":69324,"ICE_SKATING_SHARP":69325,"ICECREAM":69326,"ICECREAM_OUTLINED":69327,"ICECREAM_ROUNDED":69328,"ICECREAM_SHARP":69329,"IMAGE":69330,"IMAGE_ASPECT_RATIO":69331,"IMAGE_ASPECT_RATIO_OUTLINED":69332,"IMAGE_ASPECT_RATIO_ROUNDED":69333,"IMAGE_ASPECT_RATIO_SHARP":69334,"IMAGE_NOT_SUPPORTED":69335,"IMAGE_NOT_SUPPORTED_OUTLINED":69336,"IMAGE_NOT_SUPPORTED_ROUNDED":69337,"IMAGE_NOT_SUPPORTED_SHARP":69338,"IMAGE_OUTLINED":69339,"IMAGE_ROUNDED":69340,"IMAGE_SEARCH":69341,"IMAGE_SEARCH_OUTLINED":69342,"IMAGE_SEARCH_ROUNDED":69343,"IMAGE_SEARCH_SHARP":69344,"IMAGE_SHARP":69345,"IMAGESEARCH_ROLLER":69346,"IMAGESEARCH_ROLLER_OUTLINED":69347,"IMAGESEARCH_ROLLER_ROUNDED":69348,"IMAGESEARCH_ROLLER_SHARP":69349,"IMPORT_CONTACTS":69350,"IMPORT_CONTACTS_OUTLINED":69351,"IMPORT_CONTACTS_ROUNDED":69352,"IMPORT_CONTACTS_SHARP":69353,"IMPORT_EXPORT":69354,"IMPORT_EXPORT_OUTLINED":69355,"IMPORT_EXPORT_ROUNDED":69356,"IMPORT_EXPORT_SHARP":69357,"IMPORTANT_DEVICES":69358,"IMPORTANT_DEVICES_OUTLINED":69359,"IMPORTANT_DEVICES_ROUNDED":69360,"IMPORTANT_DEVICES_SHARP":69361,"INBOX":69362,"INBOX_OUTLINED":69363,"INBOX_ROUNDED":69364,"INBOX_SHARP":69365,"INCOMPLETE_CIRCLE":69366,"INCOMPLETE_CIRCLE_OUTLINED":69367,"INCOMPLETE_CIRCLE_ROUNDED":69368,"INCOMPLETE_CIRCLE_SHARP":69369,"INDETERMINATE_CHECK_BOX":69370,"INDETERMINATE_CHECK_BOX_OUTLINED":69371,"INDETERMINATE_CHECK_BOX_ROUNDED":69372,"INDETERMINATE_CHECK_BOX_SHARP":69373,"INFO":69374,"INFO_OUTLINE":69375,"INFO_OUTLINE_ROUNDED":69376,"INFO_OUTLINE_SHARP":69377,"INFO_OUTLINED":69378,"INFO_ROUNDED":69379,"INFO_SHARP":69380,"INPUT":69381,"INPUT_OUTLINED":69382,"INPUT_ROUNDED":69383,"INPUT_SHARP":69384,"INSERT_CHART":69385,"INSERT_CHART_OUTLINED":69386,"INSERT_CHART_OUTLINED_OUTLINED":69387,"INSERT_CHART_OUTLINED_ROUNDED":69388,"INSERT_CHART_OUTLINED_SHARP":69389,"INSERT_CHART_ROUNDED":69390,"INSERT_CHART_SHARP":69391,"INSERT_COMMENT":69392,"INSERT_COMMENT_OUTLINED":69393,"INSERT_COMMENT_ROUNDED":69394,"INSERT_COMMENT_SHARP":69395,"INSERT_DRIVE_FILE":69396,"INSERT_DRIVE_FILE_OUTLINED":69397,"INSERT_DRIVE_FILE_ROUNDED":69398,"INSERT_DRIVE_FILE_SHARP":69399,"INSERT_EMOTICON":69400,"INSERT_EMOTICON_OUTLINED":69401,"INSERT_EMOTICON_ROUNDED":69402,"INSERT_EMOTICON_SHARP":69403,"INSERT_INVITATION":69404,"INSERT_INVITATION_OUTLINED":69405,"INSERT_INVITATION_ROUNDED":69406,"INSERT_INVITATION_SHARP":69407,"INSERT_LINK":69408,"INSERT_LINK_OUTLINED":69409,"INSERT_LINK_ROUNDED":69410,"INSERT_LINK_SHARP":69411,"INSERT_PAGE_BREAK":69412,"INSERT_PAGE_BREAK_OUTLINED":69413,"INSERT_PAGE_BREAK_ROUNDED":69414,"INSERT_PAGE_BREAK_SHARP":69415,"INSERT_PHOTO":69416,"INSERT_PHOTO_OUTLINED":69417,"INSERT_PHOTO_ROUNDED":69418,"INSERT_PHOTO_SHARP":69419,"INSIGHTS":69420,"INSIGHTS_OUTLINED":69421,"INSIGHTS_ROUNDED":69422,"INSIGHTS_SHARP":69423,"INSTALL_DESKTOP":69424,"INSTALL_DESKTOP_OUTLINED":69425,"INSTALL_DESKTOP_ROUNDED":69426,"INSTALL_DESKTOP_SHARP":69427,"INSTALL_MOBILE":69428,"INSTALL_MOBILE_OUTLINED":69429,"INSTALL_MOBILE_ROUNDED":69430,"INSTALL_MOBILE_SHARP":69431,"INTEGRATION_INSTRUCTIONS":69432,"INTEGRATION_INSTRUCTIONS_OUTLINED":69433,"INTEGRATION_INSTRUCTIONS_ROUNDED":69434,"INTEGRATION_INSTRUCTIONS_SHARP":69435,"INTERESTS":69436,"INTERESTS_OUTLINED":69437,"INTERESTS_ROUNDED":69438,"INTERESTS_SHARP":69439,"INTERPRETER_MODE":69440,"INTERPRETER_MODE_OUTLINED":69441,"INTERPRETER_MODE_ROUNDED":69442,"INTERPRETER_MODE_SHARP":69443,"INVENTORY":69444,"INVENTORY_2":69445,"INVENTORY_2_OUTLINED":69446,"INVENTORY_2_ROUNDED":69447,"INVENTORY_2_SHARP":69448,"INVENTORY_OUTLINED":69449,"INVENTORY_ROUNDED":69450,"INVENTORY_SHARP":69451,"INVERT_COLORS":69452,"INVERT_COLORS_OFF":69453,"INVERT_COLORS_OFF_OUTLINED":69454,"INVERT_COLORS_OFF_ROUNDED":69455,"INVERT_COLORS_OFF_SHARP":69456,"INVERT_COLORS_ON":69457,"INVERT_COLORS_ON_OUTLINED":69458,"INVERT_COLORS_ON_ROUNDED":69459,"INVERT_COLORS_ON_SHARP":69460,"INVERT_COLORS_OUTLINED":69461,"INVERT_COLORS_ROUNDED":69462,"INVERT_COLORS_SHARP":69463,"IOS_SHARE":69464,"IOS_SHARE_OUTLINED":69465,"IOS_SHARE_ROUNDED":69466,"IOS_SHARE_SHARP":69467,"IRON":69468,"IRON_OUTLINED":69469,"IRON_ROUNDED":69470,"IRON_SHARP":69471,"ISO":69472,"ISO_OUTLINED":69473,"ISO_ROUNDED":69474,"ISO_SHARP":69475,"JAVASCRIPT":69476,"JAVASCRIPT_OUTLINED":69477,"JAVASCRIPT_ROUNDED":69478,"JAVASCRIPT_SHARP":69479,"JOIN_FULL":69480,"JOIN_FULL_OUTLINED":69481,"JOIN_FULL_ROUNDED":69482,"JOIN_FULL_SHARP":69483,"JOIN_INNER":69484,"JOIN_INNER_OUTLINED":69485,"JOIN_INNER_ROUNDED":69486,"JOIN_INNER_SHARP":69487,"JOIN_LEFT":69488,"JOIN_LEFT_OUTLINED":69489,"JOIN_LEFT_ROUNDED":69490,"JOIN_LEFT_SHARP":69491,"JOIN_RIGHT":69492,"JOIN_RIGHT_OUTLINED":69493,"JOIN_RIGHT_ROUNDED":69494,"JOIN_RIGHT_SHARP":69495,"KAYAKING":69496,"KAYAKING_OUTLINED":69497,"KAYAKING_ROUNDED":69498,"KAYAKING_SHARP":69499,"KEBAB_DINING":69500,"KEBAB_DINING_OUTLINED":69501,"KEBAB_DINING_ROUNDED":69502,"KEBAB_DINING_SHARP":69503,"KEY":69504,"KEY_OFF":69505,"KEY_OFF_OUTLINED":69506,"KEY_OFF_ROUNDED":69507,"KEY_OFF_SHARP":69508,"KEY_OUTLINED":69509,"KEY_ROUNDED":69510,"KEY_SHARP":69511,"KEYBOARD":69512,"KEYBOARD_ALT":69513,"KEYBOARD_ALT_OUTLINED":69514,"KEYBOARD_ALT_ROUNDED":69515,"KEYBOARD_ALT_SHARP":69516,"KEYBOARD_ARROW_DOWN":69517,"KEYBOARD_ARROW_DOWN_OUTLINED":69518,"KEYBOARD_ARROW_DOWN_ROUNDED":69519,"KEYBOARD_ARROW_DOWN_SHARP":69520,"KEYBOARD_ARROW_LEFT":69521,"KEYBOARD_ARROW_LEFT_OUTLINED":69522,"KEYBOARD_ARROW_LEFT_ROUNDED":69523,"KEYBOARD_ARROW_LEFT_SHARP":69524,"KEYBOARD_ARROW_RIGHT":69525,"KEYBOARD_ARROW_RIGHT_OUTLINED":69526,"KEYBOARD_ARROW_RIGHT_ROUNDED":69527,"KEYBOARD_ARROW_RIGHT_SHARP":69528,"KEYBOARD_ARROW_UP":69529,"KEYBOARD_ARROW_UP_OUTLINED":69530,"KEYBOARD_ARROW_UP_ROUNDED":69531,"KEYBOARD_ARROW_UP_SHARP":69532,"KEYBOARD_BACKSPACE":69533,"KEYBOARD_BACKSPACE_OUTLINED":69534,"KEYBOARD_BACKSPACE_ROUNDED":69535,"KEYBOARD_BACKSPACE_SHARP":69536,"KEYBOARD_CAPSLOCK":69537,"KEYBOARD_CAPSLOCK_OUTLINED":69538,"KEYBOARD_CAPSLOCK_ROUNDED":69539,"KEYBOARD_CAPSLOCK_SHARP":69540,"KEYBOARD_COMMAND_KEY":69541,"KEYBOARD_COMMAND_KEY_OUTLINED":69542,"KEYBOARD_COMMAND_KEY_ROUNDED":69543,"KEYBOARD_COMMAND_KEY_SHARP":69544,"KEYBOARD_CONTROL":69545,"KEYBOARD_CONTROL_KEY":69546,"KEYBOARD_CONTROL_KEY_OUTLINED":69547,"KEYBOARD_CONTROL_KEY_ROUNDED":69548,"KEYBOARD_CONTROL_KEY_SHARP":69549,"KEYBOARD_CONTROL_OUTLINED":69550,"KEYBOARD_CONTROL_ROUNDED":69551,"KEYBOARD_CONTROL_SHARP":69552,"KEYBOARD_DOUBLE_ARROW_DOWN":69553,"KEYBOARD_DOUBLE_ARROW_DOWN_OUTLINED":69554,"KEYBOARD_DOUBLE_ARROW_DOWN_ROUNDED":69555,"KEYBOARD_DOUBLE_ARROW_DOWN_SHARP":69556,"KEYBOARD_DOUBLE_ARROW_LEFT":69557,"KEYBOARD_DOUBLE_ARROW_LEFT_OUTLINED":69558,"KEYBOARD_DOUBLE_ARROW_LEFT_ROUNDED":69559,"KEYBOARD_DOUBLE_ARROW_LEFT_SHARP":69560,"KEYBOARD_DOUBLE_ARROW_RIGHT":69561,"KEYBOARD_DOUBLE_ARROW_RIGHT_OUTLINED":69562,"KEYBOARD_DOUBLE_ARROW_RIGHT_ROUNDED":69563,"KEYBOARD_DOUBLE_ARROW_RIGHT_SHARP":69564,"KEYBOARD_DOUBLE_ARROW_UP":69565,"KEYBOARD_DOUBLE_ARROW_UP_OUTLINED":69566,"KEYBOARD_DOUBLE_ARROW_UP_ROUNDED":69567,"KEYBOARD_DOUBLE_ARROW_UP_SHARP":69568,"KEYBOARD_HIDE":69569,"KEYBOARD_HIDE_OUTLINED":69570,"KEYBOARD_HIDE_ROUNDED":69571,"KEYBOARD_HIDE_SHARP":69572,"KEYBOARD_OPTION_KEY":69573,"KEYBOARD_OPTION_KEY_OUTLINED":69574,"KEYBOARD_OPTION_KEY_ROUNDED":69575,"KEYBOARD_OPTION_KEY_SHARP":69576,"KEYBOARD_OUTLINED":69577,"KEYBOARD_RETURN":69578,"KEYBOARD_RETURN_OUTLINED":69579,"KEYBOARD_RETURN_ROUNDED":69580,"KEYBOARD_RETURN_SHARP":69581,"KEYBOARD_ROUNDED":69582,"KEYBOARD_SHARP":69583,"KEYBOARD_TAB":69584,"KEYBOARD_TAB_OUTLINED":69585,"KEYBOARD_TAB_ROUNDED":69586,"KEYBOARD_TAB_SHARP":69587,"KEYBOARD_VOICE":69588,"KEYBOARD_VOICE_OUTLINED":69589,"KEYBOARD_VOICE_ROUNDED":69590,"KEYBOARD_VOICE_SHARP":69591,"KING_BED":69592,"KING_BED_OUTLINED":69593,"KING_BED_ROUNDED":69594,"KING_BED_SHARP":69595,"KITCHEN":69596,"KITCHEN_OUTLINED":69597,"KITCHEN_ROUNDED":69598,"KITCHEN_SHARP":69599,"KITESURFING":69600,"KITESURFING_OUTLINED":69601,"KITESURFING_ROUNDED":69602,"KITESURFING_SHARP":69603,"LABEL":69604,"LABEL_IMPORTANT":69605,"LABEL_IMPORTANT_OUTLINE":69606,"LABEL_IMPORTANT_OUTLINE_ROUNDED":69607,"LABEL_IMPORTANT_OUTLINE_SHARP":69608,"LABEL_IMPORTANT_OUTLINED":69609,"LABEL_IMPORTANT_ROUNDED":69610,"LABEL_IMPORTANT_SHARP":69611,"LABEL_OFF":69612,"LABEL_OFF_OUTLINED":69613,"LABEL_OFF_ROUNDED":69614,"LABEL_OFF_SHARP":69615,"LABEL_OUTLINE":69616,"LABEL_OUTLINE_ROUNDED":69617,"LABEL_OUTLINE_SHARP":69618,"LABEL_OUTLINED":69619,"LABEL_ROUNDED":69620,"LABEL_SHARP":69621,"LAN":69622,"LAN_OUTLINED":69623,"LAN_ROUNDED":69624,"LAN_SHARP":69625,"LANDSCAPE":69626,"LANDSCAPE_OUTLINED":69627,"LANDSCAPE_ROUNDED":69628,"LANDSCAPE_SHARP":69629,"LANDSLIDE":69630,"LANDSLIDE_OUTLINED":69631,"LANDSLIDE_ROUNDED":69632,"LANDSLIDE_SHARP":69633,"LANGUAGE":69634,"LANGUAGE_OUTLINED":69635,"LANGUAGE_ROUNDED":69636,"LANGUAGE_SHARP":69637,"LAPTOP":69638,"LAPTOP_CHROMEBOOK":69639,"LAPTOP_CHROMEBOOK_OUTLINED":69640,"LAPTOP_CHROMEBOOK_ROUNDED":69641,"LAPTOP_CHROMEBOOK_SHARP":69642,"LAPTOP_MAC":69643,"LAPTOP_MAC_OUTLINED":69644,"LAPTOP_MAC_ROUNDED":69645,"LAPTOP_MAC_SHARP":69646,"LAPTOP_OUTLINED":69647,"LAPTOP_ROUNDED":69648,"LAPTOP_SHARP":69649,"LAPTOP_WINDOWS":69650,"LAPTOP_WINDOWS_OUTLINED":69651,"LAPTOP_WINDOWS_ROUNDED":69652,"LAPTOP_WINDOWS_SHARP":69653,"LAST_PAGE":69654,"LAST_PAGE_OUTLINED":69655,"LAST_PAGE_ROUNDED":69656,"LAST_PAGE_SHARP":69657,"LAUNCH":69658,"LAUNCH_OUTLINED":69659,"LAUNCH_ROUNDED":69660,"LAUNCH_SHARP":69661,"LAYERS":69662,"LAYERS_CLEAR":69663,"LAYERS_CLEAR_OUTLINED":69664,"LAYERS_CLEAR_ROUNDED":69665,"LAYERS_CLEAR_SHARP":69666,"LAYERS_OUTLINED":69667,"LAYERS_ROUNDED":69668,"LAYERS_SHARP":69669,"LEADERBOARD":69670,"LEADERBOARD_OUTLINED":69671,"LEADERBOARD_ROUNDED":69672,"LEADERBOARD_SHARP":69673,"LEAK_ADD":69674,"LEAK_ADD_OUTLINED":69675,"LEAK_ADD_ROUNDED":69676,"LEAK_ADD_SHARP":69677,"LEAK_REMOVE":69678,"LEAK_REMOVE_OUTLINED":69679,"LEAK_REMOVE_ROUNDED":69680,"LEAK_REMOVE_SHARP":69681,"LEAVE_BAGS_AT_HOME":69682,"LEAVE_BAGS_AT_HOME_OUTLINED":69683,"LEAVE_BAGS_AT_HOME_ROUNDED":69684,"LEAVE_BAGS_AT_HOME_SHARP":69685,"LEGEND_TOGGLE":69686,"LEGEND_TOGGLE_OUTLINED":69687,"LEGEND_TOGGLE_ROUNDED":69688,"LEGEND_TOGGLE_SHARP":69689,"LENS":69690,"LENS_BLUR":69691,"LENS_BLUR_OUTLINED":69692,"LENS_BLUR_ROUNDED":69693,"LENS_BLUR_SHARP":69694,"LENS_OUTLINED":69695,"LENS_ROUNDED":69696,"LENS_SHARP":69697,"LIBRARY_ADD":69698,"LIBRARY_ADD_CHECK":69699,"LIBRARY_ADD_CHECK_OUTLINED":69700,"LIBRARY_ADD_CHECK_ROUNDED":69701,"LIBRARY_ADD_CHECK_SHARP":69702,"LIBRARY_ADD_OUTLINED":69703,"LIBRARY_ADD_ROUNDED":69704,"LIBRARY_ADD_SHARP":69705,"LIBRARY_BOOKS":69706,"LIBRARY_BOOKS_OUTLINED":69707,"LIBRARY_BOOKS_ROUNDED":69708,"LIBRARY_BOOKS_SHARP":69709,"LIBRARY_MUSIC":69710,"LIBRARY_MUSIC_OUTLINED":69711,"LIBRARY_MUSIC_ROUNDED":69712,"LIBRARY_MUSIC_SHARP":69713,"LIGHT":69714,"LIGHT_MODE":69715,"LIGHT_MODE_OUTLINED":69716,"LIGHT_MODE_ROUNDED":69717,"LIGHT_MODE_SHARP":69718,"LIGHT_OUTLINED":69719,"LIGHT_ROUNDED":69720,"LIGHT_SHARP":69721,"LIGHTBULB":69722,"LIGHTBULB_CIRCLE":69723,"LIGHTBULB_CIRCLE_OUTLINED":69724,"LIGHTBULB_CIRCLE_ROUNDED":69725,"LIGHTBULB_CIRCLE_SHARP":69726,"LIGHTBULB_OUTLINE":69727,"LIGHTBULB_OUTLINE_ROUNDED":69728,"LIGHTBULB_OUTLINE_SHARP":69729,"LIGHTBULB_OUTLINED":69730,"LIGHTBULB_ROUNDED":69731,"LIGHTBULB_SHARP":69732,"LINE_AXIS":69733,"LINE_AXIS_OUTLINED":69734,"LINE_AXIS_ROUNDED":69735,"LINE_AXIS_SHARP":69736,"LINE_STYLE":69737,"LINE_STYLE_OUTLINED":69738,"LINE_STYLE_ROUNDED":69739,"LINE_STYLE_SHARP":69740,"LINE_WEIGHT":69741,"LINE_WEIGHT_OUTLINED":69742,"LINE_WEIGHT_ROUNDED":69743,"LINE_WEIGHT_SHARP":69744,"LINEAR_SCALE":69745,"LINEAR_SCALE_OUTLINED":69746,"LINEAR_SCALE_ROUNDED":69747,"LINEAR_SCALE_SHARP":69748,"LINK":69749,"LINK_OFF":69750,"LINK_OFF_OUTLINED":69751,"LINK_OFF_ROUNDED":69752,"LINK_OFF_SHARP":69753,"LINK_OUTLINED":69754,"LINK_ROUNDED":69755,"LINK_SHARP":69756,"LINKED_CAMERA":69757,"LINKED_CAMERA_OUTLINED":69758,"LINKED_CAMERA_ROUNDED":69759,"LINKED_CAMERA_SHARP":69760,"LIQUOR":69761,"LIQUOR_OUTLINED":69762,"LIQUOR_ROUNDED":69763,"LIQUOR_SHARP":69764,"LIST":69765,"LIST_ALT":69766,"LIST_ALT_OUTLINED":69767,"LIST_ALT_ROUNDED":69768,"LIST_ALT_SHARP":69769,"LIST_OUTLINED":69770,"LIST_ROUNDED":69771,"LIST_SHARP":69772,"LIVE_HELP":69773,"LIVE_HELP_OUTLINED":69774,"LIVE_HELP_ROUNDED":69775,"LIVE_HELP_SHARP":69776,"LIVE_TV":69777,"LIVE_TV_OUTLINED":69778,"LIVE_TV_ROUNDED":69779,"LIVE_TV_SHARP":69780,"LIVING":69781,"LIVING_OUTLINED":69782,"LIVING_ROUNDED":69783,"LIVING_SHARP":69784,"LOCAL_ACTIVITY":69785,"LOCAL_ACTIVITY_OUTLINED":69786,"LOCAL_ACTIVITY_ROUNDED":69787,"LOCAL_ACTIVITY_SHARP":69788,"LOCAL_AIRPORT":69789,"LOCAL_AIRPORT_OUTLINED":69790,"LOCAL_AIRPORT_ROUNDED":69791,"LOCAL_AIRPORT_SHARP":69792,"LOCAL_ATM":69793,"LOCAL_ATM_OUTLINED":69794,"LOCAL_ATM_ROUNDED":69795,"LOCAL_ATM_SHARP":69796,"LOCAL_ATTRACTION":69797,"LOCAL_ATTRACTION_OUTLINED":69798,"LOCAL_ATTRACTION_ROUNDED":69799,"LOCAL_ATTRACTION_SHARP":69800,"LOCAL_BAR":69801,"LOCAL_BAR_OUTLINED":69802,"LOCAL_BAR_ROUNDED":69803,"LOCAL_BAR_SHARP":69804,"LOCAL_CAFE":69805,"LOCAL_CAFE_OUTLINED":69806,"LOCAL_CAFE_ROUNDED":69807,"LOCAL_CAFE_SHARP":69808,"LOCAL_CAR_WASH":69809,"LOCAL_CAR_WASH_OUTLINED":69810,"LOCAL_CAR_WASH_ROUNDED":69811,"LOCAL_CAR_WASH_SHARP":69812,"LOCAL_CONVENIENCE_STORE":69813,"LOCAL_CONVENIENCE_STORE_OUTLINED":69814,"LOCAL_CONVENIENCE_STORE_ROUNDED":69815,"LOCAL_CONVENIENCE_STORE_SHARP":69816,"LOCAL_DINING":69817,"LOCAL_DINING_OUTLINED":69818,"LOCAL_DINING_ROUNDED":69819,"LOCAL_DINING_SHARP":69820,"LOCAL_DRINK":69821,"LOCAL_DRINK_OUTLINED":69822,"LOCAL_DRINK_ROUNDED":69823,"LOCAL_DRINK_SHARP":69824,"LOCAL_FIRE_DEPARTMENT":69825,"LOCAL_FIRE_DEPARTMENT_OUTLINED":69826,"LOCAL_FIRE_DEPARTMENT_ROUNDED":69827,"LOCAL_FIRE_DEPARTMENT_SHARP":69828,"LOCAL_FLORIST":69829,"LOCAL_FLORIST_OUTLINED":69830,"LOCAL_FLORIST_ROUNDED":69831,"LOCAL_FLORIST_SHARP":69832,"LOCAL_GAS_STATION":69833,"LOCAL_GAS_STATION_OUTLINED":69834,"LOCAL_GAS_STATION_ROUNDED":69835,"LOCAL_GAS_STATION_SHARP":69836,"LOCAL_GROCERY_STORE":69837,"LOCAL_GROCERY_STORE_OUTLINED":69838,"LOCAL_GROCERY_STORE_ROUNDED":69839,"LOCAL_GROCERY_STORE_SHARP":69840,"LOCAL_HOSPITAL":69841,"LOCAL_HOSPITAL_OUTLINED":69842,"LOCAL_HOSPITAL_ROUNDED":69843,"LOCAL_HOSPITAL_SHARP":69844,"LOCAL_HOTEL":69845,"LOCAL_HOTEL_OUTLINED":69846,"LOCAL_HOTEL_ROUNDED":69847,"LOCAL_HOTEL_SHARP":69848,"LOCAL_LAUNDRY_SERVICE":69849,"LOCAL_LAUNDRY_SERVICE_OUTLINED":69850,"LOCAL_LAUNDRY_SERVICE_ROUNDED":69851,"LOCAL_LAUNDRY_SERVICE_SHARP":69852,"LOCAL_LIBRARY":69853,"LOCAL_LIBRARY_OUTLINED":69854,"LOCAL_LIBRARY_ROUNDED":69855,"LOCAL_LIBRARY_SHARP":69856,"LOCAL_MALL":69857,"LOCAL_MALL_OUTLINED":69858,"LOCAL_MALL_ROUNDED":69859,"LOCAL_MALL_SHARP":69860,"LOCAL_MOVIES":69861,"LOCAL_MOVIES_OUTLINED":69862,"LOCAL_MOVIES_ROUNDED":69863,"LOCAL_MOVIES_SHARP":69864,"LOCAL_OFFER":69865,"LOCAL_OFFER_OUTLINED":69866,"LOCAL_OFFER_ROUNDED":69867,"LOCAL_OFFER_SHARP":69868,"LOCAL_PARKING":69869,"LOCAL_PARKING_OUTLINED":69870,"LOCAL_PARKING_ROUNDED":69871,"LOCAL_PARKING_SHARP":69872,"LOCAL_PHARMACY":69873,"LOCAL_PHARMACY_OUTLINED":69874,"LOCAL_PHARMACY_ROUNDED":69875,"LOCAL_PHARMACY_SHARP":69876,"LOCAL_PHONE":69877,"LOCAL_PHONE_OUTLINED":69878,"LOCAL_PHONE_ROUNDED":69879,"LOCAL_PHONE_SHARP":69880,"LOCAL_PIZZA":69881,"LOCAL_PIZZA_OUTLINED":69882,"LOCAL_PIZZA_ROUNDED":69883,"LOCAL_PIZZA_SHARP":69884,"LOCAL_PLAY":69885,"LOCAL_PLAY_OUTLINED":69886,"LOCAL_PLAY_ROUNDED":69887,"LOCAL_PLAY_SHARP":69888,"LOCAL_POLICE":69889,"LOCAL_POLICE_OUTLINED":69890,"LOCAL_POLICE_ROUNDED":69891,"LOCAL_POLICE_SHARP":69892,"LOCAL_POST_OFFICE":69893,"LOCAL_POST_OFFICE_OUTLINED":69894,"LOCAL_POST_OFFICE_ROUNDED":69895,"LOCAL_POST_OFFICE_SHARP":69896,"LOCAL_PRINT_SHOP":69897,"LOCAL_PRINT_SHOP_OUTLINED":69898,"LOCAL_PRINT_SHOP_ROUNDED":69899,"LOCAL_PRINT_SHOP_SHARP":69900,"LOCAL_PRINTSHOP":69901,"LOCAL_PRINTSHOP_OUTLINED":69902,"LOCAL_PRINTSHOP_ROUNDED":69903,"LOCAL_PRINTSHOP_SHARP":69904,"LOCAL_RESTAURANT":69905,"LOCAL_RESTAURANT_OUTLINED":69906,"LOCAL_RESTAURANT_ROUNDED":69907,"LOCAL_RESTAURANT_SHARP":69908,"LOCAL_SEE":69909,"LOCAL_SEE_OUTLINED":69910,"LOCAL_SEE_ROUNDED":69911,"LOCAL_SEE_SHARP":69912,"LOCAL_SHIPPING":69913,"LOCAL_SHIPPING_OUTLINED":69914,"LOCAL_SHIPPING_ROUNDED":69915,"LOCAL_SHIPPING_SHARP":69916,"LOCAL_TAXI":69917,"LOCAL_TAXI_OUTLINED":69918,"LOCAL_TAXI_ROUNDED":69919,"LOCAL_TAXI_SHARP":69920,"LOCATION_CITY":69921,"LOCATION_CITY_OUTLINED":69922,"LOCATION_CITY_ROUNDED":69923,"LOCATION_CITY_SHARP":69924,"LOCATION_DISABLED":69925,"LOCATION_DISABLED_OUTLINED":69926,"LOCATION_DISABLED_ROUNDED":69927,"LOCATION_DISABLED_SHARP":69928,"LOCATION_HISTORY":69929,"LOCATION_HISTORY_OUTLINED":69930,"LOCATION_HISTORY_ROUNDED":69931,"LOCATION_HISTORY_SHARP":69932,"LOCATION_OFF":69933,"LOCATION_OFF_OUTLINED":69934,"LOCATION_OFF_ROUNDED":69935,"LOCATION_OFF_SHARP":69936,"LOCATION_ON":69937,"LOCATION_ON_OUTLINED":69938,"LOCATION_ON_ROUNDED":69939,"LOCATION_ON_SHARP":69940,"LOCATION_PIN":69941,"LOCATION_SEARCHING":69942,"LOCATION_SEARCHING_OUTLINED":69943,"LOCATION_SEARCHING_ROUNDED":69944,"LOCATION_SEARCHING_SHARP":69945,"LOCK":69946,"LOCK_CLOCK":69947,"LOCK_CLOCK_OUTLINED":69948,"LOCK_CLOCK_ROUNDED":69949,"LOCK_CLOCK_SHARP":69950,"LOCK_OPEN":69951,"LOCK_OPEN_OUTLINED":69952,"LOCK_OPEN_ROUNDED":69953,"LOCK_OPEN_SHARP":69954,"LOCK_OUTLINE":69955,"LOCK_OUTLINE_ROUNDED":69956,"LOCK_OUTLINE_SHARP":69957,"LOCK_OUTLINED":69958,"LOCK_PERSON":69959,"LOCK_PERSON_OUTLINED":69960,"LOCK_PERSON_ROUNDED":69961,"LOCK_PERSON_SHARP":69962,"LOCK_RESET":69963,"LOCK_RESET_OUTLINED":69964,"LOCK_RESET_ROUNDED":69965,"LOCK_RESET_SHARP":69966,"LOCK_ROUNDED":69967,"LOCK_SHARP":69968,"LOGIN":69969,"LOGIN_OUTLINED":69970,"LOGIN_ROUNDED":69971,"LOGIN_SHARP":69972,"LOGO_DEV":69973,"LOGO_DEV_OUTLINED":69974,"LOGO_DEV_ROUNDED":69975,"LOGO_DEV_SHARP":69976,"LOGOUT":69977,"LOGOUT_OUTLINED":69978,"LOGOUT_ROUNDED":69979,"LOGOUT_SHARP":69980,"LOOKS":69981,"LOOKS_3":69982,"LOOKS_3_OUTLINED":69983,"LOOKS_3_ROUNDED":69984,"LOOKS_3_SHARP":69985,"LOOKS_4":69986,"LOOKS_4_OUTLINED":69987,"LOOKS_4_ROUNDED":69988,"LOOKS_4_SHARP":69989,"LOOKS_5":69990,"LOOKS_5_OUTLINED":69991,"LOOKS_5_ROUNDED":69992,"LOOKS_5_SHARP":69993,"LOOKS_6":69994,"LOOKS_6_OUTLINED":69995,"LOOKS_6_ROUNDED":69996,"LOOKS_6_SHARP":69997,"LOOKS_ONE":69998,"LOOKS_ONE_OUTLINED":69999,"LOOKS_ONE_ROUNDED":70000,"LOOKS_ONE_SHARP":70001,"LOOKS_OUTLINED":70002,"LOOKS_ROUNDED":70003,"LOOKS_SHARP":70004,"LOOKS_TWO":70005,"LOOKS_TWO_OUTLINED":70006,"LOOKS_TWO_ROUNDED":70007,"LOOKS_TWO_SHARP":70008,"LOOP":70009,"LOOP_OUTLINED":70010,"LOOP_ROUNDED":70011,"LOOP_SHARP":70012,"LOUPE":70013,"LOUPE_OUTLINED":70014,"LOUPE_ROUNDED":70015,"LOUPE_SHARP":70016,"LOW_PRIORITY":70017,"LOW_PRIORITY_OUTLINED":70018,"LOW_PRIORITY_ROUNDED":70019,"LOW_PRIORITY_SHARP":70020,"LOYALTY":70021,"LOYALTY_OUTLINED":70022,"LOYALTY_ROUNDED":70023,"LOYALTY_SHARP":70024,"LTE_MOBILEDATA":70025,"LTE_MOBILEDATA_OUTLINED":70026,"LTE_MOBILEDATA_ROUNDED":70027,"LTE_MOBILEDATA_SHARP":70028,"LTE_PLUS_MOBILEDATA":70029,"LTE_PLUS_MOBILEDATA_OUTLINED":70030,"LTE_PLUS_MOBILEDATA_ROUNDED":70031,"LTE_PLUS_MOBILEDATA_SHARP":70032,"LUGGAGE":70033,"LUGGAGE_OUTLINED":70034,"LUGGAGE_ROUNDED":70035,"LUGGAGE_SHARP":70036,"LUNCH_DINING":70037,"LUNCH_DINING_OUTLINED":70038,"LUNCH_DINING_ROUNDED":70039,"LUNCH_DINING_SHARP":70040,"LYRICS":70041,"LYRICS_OUTLINED":70042,"LYRICS_ROUNDED":70043,"LYRICS_SHARP":70044,"MACRO_OFF":70045,"MACRO_OFF_OUTLINED":70046,"MACRO_OFF_ROUNDED":70047,"MACRO_OFF_SHARP":70048,"MAIL":70049,"MAIL_LOCK":70050,"MAIL_LOCK_OUTLINED":70051,"MAIL_LOCK_ROUNDED":70052,"MAIL_LOCK_SHARP":70053,"MAIL_OUTLINE":70054,"MAIL_OUTLINE_OUTLINED":70055,"MAIL_OUTLINE_ROUNDED":70056,"MAIL_OUTLINE_SHARP":70057,"MAIL_OUTLINED":70058,"MAIL_ROUNDED":70059,"MAIL_SHARP":70060,"MALE":70061,"MALE_OUTLINED":70062,"MALE_ROUNDED":70063,"MALE_SHARP":70064,"MAN":70065,"MAN_2":70066,"MAN_2_OUTLINED":70067,"MAN_2_ROUNDED":70068,"MAN_2_SHARP":70069,"MAN_3":70070,"MAN_3_OUTLINED":70071,"MAN_3_ROUNDED":70072,"MAN_3_SHARP":70073,"MAN_4":70074,"MAN_4_OUTLINED":70075,"MAN_4_ROUNDED":70076,"MAN_4_SHARP":70077,"MAN_OUTLINED":70078,"MAN_ROUNDED":70079,"MAN_SHARP":70080,"MANAGE_ACCOUNTS":70081,"MANAGE_ACCOUNTS_OUTLINED":70082,"MANAGE_ACCOUNTS_ROUNDED":70083,"MANAGE_ACCOUNTS_SHARP":70084,"MANAGE_HISTORY":70085,"MANAGE_HISTORY_OUTLINED":70086,"MANAGE_HISTORY_ROUNDED":70087,"MANAGE_HISTORY_SHARP":70088,"MANAGE_SEARCH":70089,"MANAGE_SEARCH_OUTLINED":70090,"MANAGE_SEARCH_ROUNDED":70091,"MANAGE_SEARCH_SHARP":70092,"MAP":70093,"MAP_OUTLINED":70094,"MAP_ROUNDED":70095,"MAP_SHARP":70096,"MAPS_HOME_WORK":70097,"MAPS_HOME_WORK_OUTLINED":70098,"MAPS_HOME_WORK_ROUNDED":70099,"MAPS_HOME_WORK_SHARP":70100,"MAPS_UGC":70101,"MAPS_UGC_OUTLINED":70102,"MAPS_UGC_ROUNDED":70103,"MAPS_UGC_SHARP":70104,"MARGIN":70105,"MARGIN_OUTLINED":70106,"MARGIN_ROUNDED":70107,"MARGIN_SHARP":70108,"MARK_AS_UNREAD":70109,"MARK_AS_UNREAD_OUTLINED":70110,"MARK_AS_UNREAD_ROUNDED":70111,"MARK_AS_UNREAD_SHARP":70112,"MARK_CHAT_READ":70113,"MARK_CHAT_READ_OUTLINED":70114,"MARK_CHAT_READ_ROUNDED":70115,"MARK_CHAT_READ_SHARP":70116,"MARK_CHAT_UNREAD":70117,"MARK_CHAT_UNREAD_OUTLINED":70118,"MARK_CHAT_UNREAD_ROUNDED":70119,"MARK_CHAT_UNREAD_SHARP":70120,"MARK_EMAIL_READ":70121,"MARK_EMAIL_READ_OUTLINED":70122,"MARK_EMAIL_READ_ROUNDED":70123,"MARK_EMAIL_READ_SHARP":70124,"MARK_EMAIL_UNREAD":70125,"MARK_EMAIL_UNREAD_OUTLINED":70126,"MARK_EMAIL_UNREAD_ROUNDED":70127,"MARK_EMAIL_UNREAD_SHARP":70128,"MARK_UNREAD_CHAT_ALT":70129,"MARK_UNREAD_CHAT_ALT_OUTLINED":70130,"MARK_UNREAD_CHAT_ALT_ROUNDED":70131,"MARK_UNREAD_CHAT_ALT_SHARP":70132,"MARKUNREAD":70133,"MARKUNREAD_MAILBOX":70134,"MARKUNREAD_MAILBOX_OUTLINED":70135,"MARKUNREAD_MAILBOX_ROUNDED":70136,"MARKUNREAD_MAILBOX_SHARP":70137,"MARKUNREAD_OUTLINED":70138,"MARKUNREAD_ROUNDED":70139,"MARKUNREAD_SHARP":70140,"MASKS":70141,"MASKS_OUTLINED":70142,"MASKS_ROUNDED":70143,"MASKS_SHARP":70144,"MAXIMIZE":70145,"MAXIMIZE_OUTLINED":70146,"MAXIMIZE_ROUNDED":70147,"MAXIMIZE_SHARP":70148,"MEDIA_BLUETOOTH_OFF":70149,"MEDIA_BLUETOOTH_OFF_OUTLINED":70150,"MEDIA_BLUETOOTH_OFF_ROUNDED":70151,"MEDIA_BLUETOOTH_OFF_SHARP":70152,"MEDIA_BLUETOOTH_ON":70153,"MEDIA_BLUETOOTH_ON_OUTLINED":70154,"MEDIA_BLUETOOTH_ON_ROUNDED":70155,"MEDIA_BLUETOOTH_ON_SHARP":70156,"MEDIATION":70157,"MEDIATION_OUTLINED":70158,"MEDIATION_ROUNDED":70159,"MEDIATION_SHARP":70160,"MEDICAL_INFORMATION":70161,"MEDICAL_INFORMATION_OUTLINED":70162,"MEDICAL_INFORMATION_ROUNDED":70163,"MEDICAL_INFORMATION_SHARP":70164,"MEDICAL_SERVICES":70165,"MEDICAL_SERVICES_OUTLINED":70166,"MEDICAL_SERVICES_ROUNDED":70167,"MEDICAL_SERVICES_SHARP":70168,"MEDICATION":70169,"MEDICATION_LIQUID":70170,"MEDICATION_LIQUID_OUTLINED":70171,"MEDICATION_LIQUID_ROUNDED":70172,"MEDICATION_LIQUID_SHARP":70173,"MEDICATION_OUTLINED":70174,"MEDICATION_ROUNDED":70175,"MEDICATION_SHARP":70176,"MEETING_ROOM":70177,"MEETING_ROOM_OUTLINED":70178,"MEETING_ROOM_ROUNDED":70179,"MEETING_ROOM_SHARP":70180,"MEMORY":70181,"MEMORY_OUTLINED":70182,"MEMORY_ROUNDED":70183,"MEMORY_SHARP":70184,"MENU":70185,"MENU_BOOK":70186,"MENU_BOOK_OUTLINED":70187,"MENU_BOOK_ROUNDED":70188,"MENU_BOOK_SHARP":70189,"MENU_OPEN":70190,"MENU_OPEN_OUTLINED":70191,"MENU_OPEN_ROUNDED":70192,"MENU_OPEN_SHARP":70193,"MENU_OUTLINED":70194,"MENU_ROUNDED":70195,"MENU_SHARP":70196,"MERGE":70197,"MERGE_OUTLINED":70198,"MERGE_ROUNDED":70199,"MERGE_SHARP":70200,"MERGE_TYPE":70201,"MERGE_TYPE_OUTLINED":70202,"MERGE_TYPE_ROUNDED":70203,"MERGE_TYPE_SHARP":70204,"MESSAGE":70205,"MESSAGE_OUTLINED":70206,"MESSAGE_ROUNDED":70207,"MESSAGE_SHARP":70208,"MESSENGER":70209,"MESSENGER_OUTLINE":70210,"MESSENGER_OUTLINE_OUTLINED":70211,"MESSENGER_OUTLINE_ROUNDED":70212,"MESSENGER_OUTLINE_SHARP":70213,"MESSENGER_OUTLINED":70214,"MESSENGER_ROUNDED":70215,"MESSENGER_SHARP":70216,"MIC":70217,"MIC_EXTERNAL_OFF":70218,"MIC_EXTERNAL_OFF_OUTLINED":70219,"MIC_EXTERNAL_OFF_ROUNDED":70220,"MIC_EXTERNAL_OFF_SHARP":70221,"MIC_EXTERNAL_ON":70222,"MIC_EXTERNAL_ON_OUTLINED":70223,"MIC_EXTERNAL_ON_ROUNDED":70224,"MIC_EXTERNAL_ON_SHARP":70225,"MIC_NONE":70226,"MIC_NONE_OUTLINED":70227,"MIC_NONE_ROUNDED":70228,"MIC_NONE_SHARP":70229,"MIC_OFF":70230,"MIC_OFF_OUTLINED":70231,"MIC_OFF_ROUNDED":70232,"MIC_OFF_SHARP":70233,"MIC_OUTLINED":70234,"MIC_ROUNDED":70235,"MIC_SHARP":70236,"MICROWAVE":70237,"MICROWAVE_OUTLINED":70238,"MICROWAVE_ROUNDED":70239,"MICROWAVE_SHARP":70240,"MILITARY_TECH":70241,"MILITARY_TECH_OUTLINED":70242,"MILITARY_TECH_ROUNDED":70243,"MILITARY_TECH_SHARP":70244,"MINIMIZE":70245,"MINIMIZE_OUTLINED":70246,"MINIMIZE_ROUNDED":70247,"MINIMIZE_SHARP":70248,"MINOR_CRASH":70249,"MINOR_CRASH_OUTLINED":70250,"MINOR_CRASH_ROUNDED":70251,"MINOR_CRASH_SHARP":70252,"MISCELLANEOUS_SERVICES":70253,"MISCELLANEOUS_SERVICES_OUTLINED":70254,"MISCELLANEOUS_SERVICES_ROUNDED":70255,"MISCELLANEOUS_SERVICES_SHARP":70256,"MISSED_VIDEO_CALL":70257,"MISSED_VIDEO_CALL_OUTLINED":70258,"MISSED_VIDEO_CALL_ROUNDED":70259,"MISSED_VIDEO_CALL_SHARP":70260,"MMS":70261,"MMS_OUTLINED":70262,"MMS_ROUNDED":70263,"MMS_SHARP":70264,"MOBILE_FRIENDLY":70265,"MOBILE_FRIENDLY_OUTLINED":70266,"MOBILE_FRIENDLY_ROUNDED":70267,"MOBILE_FRIENDLY_SHARP":70268,"MOBILE_OFF":70269,"MOBILE_OFF_OUTLINED":70270,"MOBILE_OFF_ROUNDED":70271,"MOBILE_OFF_SHARP":70272,"MOBILE_SCREEN_SHARE":70273,"MOBILE_SCREEN_SHARE_OUTLINED":70274,"MOBILE_SCREEN_SHARE_ROUNDED":70275,"MOBILE_SCREEN_SHARE_SHARP":70276,"MOBILEDATA_OFF":70277,"MOBILEDATA_OFF_OUTLINED":70278,"MOBILEDATA_OFF_ROUNDED":70279,"MOBILEDATA_OFF_SHARP":70280,"MODE":70281,"MODE_COMMENT":70282,"MODE_COMMENT_OUTLINED":70283,"MODE_COMMENT_ROUNDED":70284,"MODE_COMMENT_SHARP":70285,"MODE_EDIT":70286,"MODE_EDIT_OUTLINE":70287,"MODE_EDIT_OUTLINE_OUTLINED":70288,"MODE_EDIT_OUTLINE_ROUNDED":70289,"MODE_EDIT_OUTLINE_SHARP":70290,"MODE_EDIT_OUTLINED":70291,"MODE_EDIT_ROUNDED":70292,"MODE_EDIT_SHARP":70293,"MODE_FAN_OFF":70294,"MODE_FAN_OFF_OUTLINED":70295,"MODE_FAN_OFF_ROUNDED":70296,"MODE_FAN_OFF_SHARP":70297,"MODE_NIGHT":70298,"MODE_NIGHT_OUTLINED":70299,"MODE_NIGHT_ROUNDED":70300,"MODE_NIGHT_SHARP":70301,"MODE_OF_TRAVEL":70302,"MODE_OF_TRAVEL_OUTLINED":70303,"MODE_OF_TRAVEL_ROUNDED":70304,"MODE_OF_TRAVEL_SHARP":70305,"MODE_OUTLINED":70306,"MODE_ROUNDED":70307,"MODE_SHARP":70308,"MODE_STANDBY":70309,"MODE_STANDBY_OUTLINED":70310,"MODE_STANDBY_ROUNDED":70311,"MODE_STANDBY_SHARP":70312,"MODEL_TRAINING":70313,"MODEL_TRAINING_OUTLINED":70314,"MODEL_TRAINING_ROUNDED":70315,"MODEL_TRAINING_SHARP":70316,"MONETIZATION_ON":70317,"MONETIZATION_ON_OUTLINED":70318,"MONETIZATION_ON_ROUNDED":70319,"MONETIZATION_ON_SHARP":70320,"MONEY":70321,"MONEY_OFF":70322,"MONEY_OFF_CSRED":70323,"MONEY_OFF_CSRED_OUTLINED":70324,"MONEY_OFF_CSRED_ROUNDED":70325,"MONEY_OFF_CSRED_SHARP":70326,"MONEY_OFF_OUTLINED":70327,"MONEY_OFF_ROUNDED":70328,"MONEY_OFF_SHARP":70329,"MONEY_OUTLINED":70330,"MONEY_ROUNDED":70331,"MONEY_SHARP":70332,"MONITOR":70333,"MONITOR_HEART":70334,"MONITOR_HEART_OUTLINED":70335,"MONITOR_HEART_ROUNDED":70336,"MONITOR_HEART_SHARP":70337,"MONITOR_OUTLINED":70338,"MONITOR_ROUNDED":70339,"MONITOR_SHARP":70340,"MONITOR_WEIGHT":70341,"MONITOR_WEIGHT_OUTLINED":70342,"MONITOR_WEIGHT_ROUNDED":70343,"MONITOR_WEIGHT_SHARP":70344,"MONOCHROME_PHOTOS":70345,"MONOCHROME_PHOTOS_OUTLINED":70346,"MONOCHROME_PHOTOS_ROUNDED":70347,"MONOCHROME_PHOTOS_SHARP":70348,"MOOD":70349,"MOOD_BAD":70350,"MOOD_BAD_OUTLINED":70351,"MOOD_BAD_ROUNDED":70352,"MOOD_BAD_SHARP":70353,"MOOD_OUTLINED":70354,"MOOD_ROUNDED":70355,"MOOD_SHARP":70356,"MOPED":70357,"MOPED_OUTLINED":70358,"MOPED_ROUNDED":70359,"MOPED_SHARP":70360,"MORE":70361,"MORE_HORIZ":70362,"MORE_HORIZ_OUTLINED":70363,"MORE_HORIZ_ROUNDED":70364,"MORE_HORIZ_SHARP":70365,"MORE_OUTLINED":70366,"MORE_ROUNDED":70367,"MORE_SHARP":70368,"MORE_TIME":70369,"MORE_TIME_OUTLINED":70370,"MORE_TIME_ROUNDED":70371,"MORE_TIME_SHARP":70372,"MORE_VERT":70373,"MORE_VERT_OUTLINED":70374,"MORE_VERT_ROUNDED":70375,"MORE_VERT_SHARP":70376,"MOSQUE":70377,"MOSQUE_OUTLINED":70378,"MOSQUE_ROUNDED":70379,"MOSQUE_SHARP":70380,"MOTION_PHOTOS_AUTO":70381,"MOTION_PHOTOS_AUTO_OUTLINED":70382,"MOTION_PHOTOS_AUTO_ROUNDED":70383,"MOTION_PHOTOS_AUTO_SHARP":70384,"MOTION_PHOTOS_OFF":70385,"MOTION_PHOTOS_OFF_OUTLINED":70386,"MOTION_PHOTOS_OFF_ROUNDED":70387,"MOTION_PHOTOS_OFF_SHARP":70388,"MOTION_PHOTOS_ON":70389,"MOTION_PHOTOS_ON_OUTLINED":70390,"MOTION_PHOTOS_ON_ROUNDED":70391,"MOTION_PHOTOS_ON_SHARP":70392,"MOTION_PHOTOS_PAUSE":70393,"MOTION_PHOTOS_PAUSE_OUTLINED":70394,"MOTION_PHOTOS_PAUSE_ROUNDED":70395,"MOTION_PHOTOS_PAUSE_SHARP":70396,"MOTION_PHOTOS_PAUSED":70397,"MOTION_PHOTOS_PAUSED_OUTLINED":70398,"MOTION_PHOTOS_PAUSED_ROUNDED":70399,"MOTION_PHOTOS_PAUSED_SHARP":70400,"MOTORCYCLE":70401,"MOTORCYCLE_OUTLINED":70402,"MOTORCYCLE_ROUNDED":70403,"MOTORCYCLE_SHARP":70404,"MOUSE":70405,"MOUSE_OUTLINED":70406,"MOUSE_ROUNDED":70407,"MOUSE_SHARP":70408,"MOVE_DOWN":70409,"MOVE_DOWN_OUTLINED":70410,"MOVE_DOWN_ROUNDED":70411,"MOVE_DOWN_SHARP":70412,"MOVE_TO_INBOX":70413,"MOVE_TO_INBOX_OUTLINED":70414,"MOVE_TO_INBOX_ROUNDED":70415,"MOVE_TO_INBOX_SHARP":70416,"MOVE_UP":70417,"MOVE_UP_OUTLINED":70418,"MOVE_UP_ROUNDED":70419,"MOVE_UP_SHARP":70420,"MOVIE":70421,"MOVIE_CREATION":70422,"MOVIE_CREATION_OUTLINED":70423,"MOVIE_CREATION_ROUNDED":70424,"MOVIE_CREATION_SHARP":70425,"MOVIE_EDIT":70426,"MOVIE_FILTER":70427,"MOVIE_FILTER_OUTLINED":70428,"MOVIE_FILTER_ROUNDED":70429,"MOVIE_FILTER_SHARP":70430,"MOVIE_OUTLINED":70431,"MOVIE_ROUNDED":70432,"MOVIE_SHARP":70433,"MOVING":70434,"MOVING_OUTLINED":70435,"MOVING_ROUNDED":70436,"MOVING_SHARP":70437,"MP":70438,"MP_OUTLINED":70439,"MP_ROUNDED":70440,"MP_SHARP":70441,"MULTILINE_CHART":70442,"MULTILINE_CHART_OUTLINED":70443,"MULTILINE_CHART_ROUNDED":70444,"MULTILINE_CHART_SHARP":70445,"MULTIPLE_STOP":70446,"MULTIPLE_STOP_OUTLINED":70447,"MULTIPLE_STOP_ROUNDED":70448,"MULTIPLE_STOP_SHARP":70449,"MULTITRACK_AUDIO":70450,"MULTITRACK_AUDIO_OUTLINED":70451,"MULTITRACK_AUDIO_ROUNDED":70452,"MULTITRACK_AUDIO_SHARP":70453,"MUSEUM":70454,"MUSEUM_OUTLINED":70455,"MUSEUM_ROUNDED":70456,"MUSEUM_SHARP":70457,"MUSIC_NOTE":70458,"MUSIC_NOTE_OUTLINED":70459,"MUSIC_NOTE_ROUNDED":70460,"MUSIC_NOTE_SHARP":70461,"MUSIC_OFF":70462,"MUSIC_OFF_OUTLINED":70463,"MUSIC_OFF_ROUNDED":70464,"MUSIC_OFF_SHARP":70465,"MUSIC_VIDEO":70466,"MUSIC_VIDEO_OUTLINED":70467,"MUSIC_VIDEO_ROUNDED":70468,"MUSIC_VIDEO_SHARP":70469,"MY_LIBRARY_ADD":70470,"MY_LIBRARY_ADD_OUTLINED":70471,"MY_LIBRARY_ADD_ROUNDED":70472,"MY_LIBRARY_ADD_SHARP":70473,"MY_LIBRARY_BOOKS":70474,"MY_LIBRARY_BOOKS_OUTLINED":70475,"MY_LIBRARY_BOOKS_ROUNDED":70476,"MY_LIBRARY_BOOKS_SHARP":70477,"MY_LIBRARY_MUSIC":70478,"MY_LIBRARY_MUSIC_OUTLINED":70479,"MY_LIBRARY_MUSIC_ROUNDED":70480,"MY_LIBRARY_MUSIC_SHARP":70481,"MY_LOCATION":70482,"MY_LOCATION_OUTLINED":70483,"MY_LOCATION_ROUNDED":70484,"MY_LOCATION_SHARP":70485,"NAT":70486,"NAT_OUTLINED":70487,"NAT_ROUNDED":70488,"NAT_SHARP":70489,"NATURE":70490,"NATURE_OUTLINED":70491,"NATURE_PEOPLE":70492,"NATURE_PEOPLE_OUTLINED":70493,"NATURE_PEOPLE_ROUNDED":70494,"NATURE_PEOPLE_SHARP":70495,"NATURE_ROUNDED":70496,"NATURE_SHARP":70497,"NAVIGATE_BEFORE":70498,"NAVIGATE_BEFORE_OUTLINED":70499,"NAVIGATE_BEFORE_ROUNDED":70500,"NAVIGATE_BEFORE_SHARP":70501,"NAVIGATE_NEXT":70502,"NAVIGATE_NEXT_OUTLINED":70503,"NAVIGATE_NEXT_ROUNDED":70504,"NAVIGATE_NEXT_SHARP":70505,"NAVIGATION":70506,"NAVIGATION_OUTLINED":70507,"NAVIGATION_ROUNDED":70508,"NAVIGATION_SHARP":70509,"NEAR_ME":70510,"NEAR_ME_DISABLED":70511,"NEAR_ME_DISABLED_OUTLINED":70512,"NEAR_ME_DISABLED_ROUNDED":70513,"NEAR_ME_DISABLED_SHARP":70514,"NEAR_ME_OUTLINED":70515,"NEAR_ME_ROUNDED":70516,"NEAR_ME_SHARP":70517,"NEARBY_ERROR":70518,"NEARBY_ERROR_OUTLINED":70519,"NEARBY_ERROR_ROUNDED":70520,"NEARBY_ERROR_SHARP":70521,"NEARBY_OFF":70522,"NEARBY_OFF_OUTLINED":70523,"NEARBY_OFF_ROUNDED":70524,"NEARBY_OFF_SHARP":70525,"NEST_CAM_WIRED_STAND":70526,"NEST_CAM_WIRED_STAND_OUTLINED":70527,"NEST_CAM_WIRED_STAND_ROUNDED":70528,"NEST_CAM_WIRED_STAND_SHARP":70529,"NETWORK_CELL":70530,"NETWORK_CELL_OUTLINED":70531,"NETWORK_CELL_ROUNDED":70532,"NETWORK_CELL_SHARP":70533,"NETWORK_CHECK":70534,"NETWORK_CHECK_OUTLINED":70535,"NETWORK_CHECK_ROUNDED":70536,"NETWORK_CHECK_SHARP":70537,"NETWORK_LOCKED":70538,"NETWORK_LOCKED_OUTLINED":70539,"NETWORK_LOCKED_ROUNDED":70540,"NETWORK_LOCKED_SHARP":70541,"NETWORK_PING":70542,"NETWORK_PING_OUTLINED":70543,"NETWORK_PING_ROUNDED":70544,"NETWORK_PING_SHARP":70545,"NETWORK_WIFI":70546,"NETWORK_WIFI_1_BAR":70547,"NETWORK_WIFI_1_BAR_OUTLINED":70548,"NETWORK_WIFI_1_BAR_ROUNDED":70549,"NETWORK_WIFI_1_BAR_SHARP":70550,"NETWORK_WIFI_2_BAR":70551,"NETWORK_WIFI_2_BAR_OUTLINED":70552,"NETWORK_WIFI_2_BAR_ROUNDED":70553,"NETWORK_WIFI_2_BAR_SHARP":70554,"NETWORK_WIFI_3_BAR":70555,"NETWORK_WIFI_3_BAR_OUTLINED":70556,"NETWORK_WIFI_3_BAR_ROUNDED":70557,"NETWORK_WIFI_3_BAR_SHARP":70558,"NETWORK_WIFI_OUTLINED":70559,"NETWORK_WIFI_ROUNDED":70560,"NETWORK_WIFI_SHARP":70561,"NEW_LABEL":70562,"NEW_LABEL_OUTLINED":70563,"NEW_LABEL_ROUNDED":70564,"NEW_LABEL_SHARP":70565,"NEW_RELEASES":70566,"NEW_RELEASES_OUTLINED":70567,"NEW_RELEASES_ROUNDED":70568,"NEW_RELEASES_SHARP":70569,"NEWSPAPER":70570,"NEWSPAPER_OUTLINED":70571,"NEWSPAPER_ROUNDED":70572,"NEWSPAPER_SHARP":70573,"NEXT_PLAN":70574,"NEXT_PLAN_OUTLINED":70575,"NEXT_PLAN_ROUNDED":70576,"NEXT_PLAN_SHARP":70577,"NEXT_WEEK":70578,"NEXT_WEEK_OUTLINED":70579,"NEXT_WEEK_ROUNDED":70580,"NEXT_WEEK_SHARP":70581,"NFC":70582,"NFC_OUTLINED":70583,"NFC_ROUNDED":70584,"NFC_SHARP":70585,"NIGHT_SHELTER":70586,"NIGHT_SHELTER_OUTLINED":70587,"NIGHT_SHELTER_ROUNDED":70588,"NIGHT_SHELTER_SHARP":70589,"NIGHTLIFE":70590,"NIGHTLIFE_OUTLINED":70591,"NIGHTLIFE_ROUNDED":70592,"NIGHTLIFE_SHARP":70593,"NIGHTLIGHT":70594,"NIGHTLIGHT_OUTLINED":70595,"NIGHTLIGHT_ROUND":70596,"NIGHTLIGHT_ROUND_OUTLINED":70597,"NIGHTLIGHT_ROUND_ROUNDED":70598,"NIGHTLIGHT_ROUND_SHARP":70599,"NIGHTLIGHT_ROUNDED":70600,"NIGHTLIGHT_SHARP":70601,"NIGHTS_STAY":70602,"NIGHTS_STAY_OUTLINED":70603,"NIGHTS_STAY_ROUNDED":70604,"NIGHTS_STAY_SHARP":70605,"NINE_K":70606,"NINE_K_OUTLINED":70607,"NINE_K_PLUS":70608,"NINE_K_PLUS_OUTLINED":70609,"NINE_K_PLUS_ROUNDED":70610,"NINE_K_PLUS_SHARP":70611,"NINE_K_ROUNDED":70612,"NINE_K_SHARP":70613,"NINE_MP":70614,"NINE_MP_OUTLINED":70615,"NINE_MP_ROUNDED":70616,"NINE_MP_SHARP":70617,"NINETEEN_MP":70618,"NINETEEN_MP_OUTLINED":70619,"NINETEEN_MP_ROUNDED":70620,"NINETEEN_MP_SHARP":70621,"NO_ACCOUNTS":70622,"NO_ACCOUNTS_OUTLINED":70623,"NO_ACCOUNTS_ROUNDED":70624,"NO_ACCOUNTS_SHARP":70625,"NO_ADULT_CONTENT":70626,"NO_ADULT_CONTENT_OUTLINED":70627,"NO_ADULT_CONTENT_ROUNDED":70628,"NO_ADULT_CONTENT_SHARP":70629,"NO_BACKPACK":70630,"NO_BACKPACK_OUTLINED":70631,"NO_BACKPACK_ROUNDED":70632,"NO_BACKPACK_SHARP":70633,"NO_CELL":70634,"NO_CELL_OUTLINED":70635,"NO_CELL_ROUNDED":70636,"NO_CELL_SHARP":70637,"NO_CRASH":70638,"NO_CRASH_OUTLINED":70639,"NO_CRASH_ROUNDED":70640,"NO_CRASH_SHARP":70641,"NO_DRINKS":70642,"NO_DRINKS_OUTLINED":70643,"NO_DRINKS_ROUNDED":70644,"NO_DRINKS_SHARP":70645,"NO_ENCRYPTION":70646,"NO_ENCRYPTION_GMAILERRORRED":70647,"NO_ENCRYPTION_GMAILERRORRED_OUTLINED":70648,"NO_ENCRYPTION_GMAILERRORRED_ROUNDED":70649,"NO_ENCRYPTION_GMAILERRORRED_SHARP":70650,"NO_ENCRYPTION_OUTLINED":70651,"NO_ENCRYPTION_ROUNDED":70652,"NO_ENCRYPTION_SHARP":70653,"NO_FLASH":70654,"NO_FLASH_OUTLINED":70655,"NO_FLASH_ROUNDED":70656,"NO_FLASH_SHARP":70657,"NO_FOOD":70658,"NO_FOOD_OUTLINED":70659,"NO_FOOD_ROUNDED":70660,"NO_FOOD_SHARP":70661,"NO_LUGGAGE":70662,"NO_LUGGAGE_OUTLINED":70663,"NO_LUGGAGE_ROUNDED":70664,"NO_LUGGAGE_SHARP":70665,"NO_MEALS":70666,"NO_MEALS_OULINE":70667,"NO_MEALS_OUTLINED":70668,"NO_MEALS_ROUNDED":70669,"NO_MEALS_SHARP":70670,"NO_MEETING_ROOM":70671,"NO_MEETING_ROOM_OUTLINED":70672,"NO_MEETING_ROOM_ROUNDED":70673,"NO_MEETING_ROOM_SHARP":70674,"NO_PHOTOGRAPHY":70675,"NO_PHOTOGRAPHY_OUTLINED":70676,"NO_PHOTOGRAPHY_ROUNDED":70677,"NO_PHOTOGRAPHY_SHARP":70678,"NO_SIM":70679,"NO_SIM_OUTLINED":70680,"NO_SIM_ROUNDED":70681,"NO_SIM_SHARP":70682,"NO_STROLLER":70683,"NO_STROLLER_OUTLINED":70684,"NO_STROLLER_ROUNDED":70685,"NO_STROLLER_SHARP":70686,"NO_TRANSFER":70687,"NO_TRANSFER_OUTLINED":70688,"NO_TRANSFER_ROUNDED":70689,"NO_TRANSFER_SHARP":70690,"NOISE_AWARE":70691,"NOISE_AWARE_OUTLINED":70692,"NOISE_AWARE_ROUNDED":70693,"NOISE_AWARE_SHARP":70694,"NOISE_CONTROL_OFF":70695,"NOISE_CONTROL_OFF_OUTLINED":70696,"NOISE_CONTROL_OFF_ROUNDED":70697,"NOISE_CONTROL_OFF_SHARP":70698,"NORDIC_WALKING":70699,"NORDIC_WALKING_OUTLINED":70700,"NORDIC_WALKING_ROUNDED":70701,"NORDIC_WALKING_SHARP":70702,"NORTH":70703,"NORTH_EAST":70704,"NORTH_EAST_OUTLINED":70705,"NORTH_EAST_ROUNDED":70706,"NORTH_EAST_SHARP":70707,"NORTH_OUTLINED":70708,"NORTH_ROUNDED":70709,"NORTH_SHARP":70710,"NORTH_WEST":70711,"NORTH_WEST_OUTLINED":70712,"NORTH_WEST_ROUNDED":70713,"NORTH_WEST_SHARP":70714,"NOT_ACCESSIBLE":70715,"NOT_ACCESSIBLE_OUTLINED":70716,"NOT_ACCESSIBLE_ROUNDED":70717,"NOT_ACCESSIBLE_SHARP":70718,"NOT_INTERESTED":70719,"NOT_INTERESTED_OUTLINED":70720,"NOT_INTERESTED_ROUNDED":70721,"NOT_INTERESTED_SHARP":70722,"NOT_LISTED_LOCATION":70723,"NOT_LISTED_LOCATION_OUTLINED":70724,"NOT_LISTED_LOCATION_ROUNDED":70725,"NOT_LISTED_LOCATION_SHARP":70726,"NOT_STARTED":70727,"NOT_STARTED_OUTLINED":70728,"NOT_STARTED_ROUNDED":70729,"NOT_STARTED_SHARP":70730,"NOTE":70731,"NOTE_ADD":70732,"NOTE_ADD_OUTLINED":70733,"NOTE_ADD_ROUNDED":70734,"NOTE_ADD_SHARP":70735,"NOTE_ALT":70736,"NOTE_ALT_OUTLINED":70737,"NOTE_ALT_ROUNDED":70738,"NOTE_ALT_SHARP":70739,"NOTE_OUTLINED":70740,"NOTE_ROUNDED":70741,"NOTE_SHARP":70742,"NOTES":70743,"NOTES_OUTLINED":70744,"NOTES_ROUNDED":70745,"NOTES_SHARP":70746,"NOTIFICATION_ADD":70747,"NOTIFICATION_ADD_OUTLINED":70748,"NOTIFICATION_ADD_ROUNDED":70749,"NOTIFICATION_ADD_SHARP":70750,"NOTIFICATION_IMPORTANT":70751,"NOTIFICATION_IMPORTANT_OUTLINED":70752,"NOTIFICATION_IMPORTANT_ROUNDED":70753,"NOTIFICATION_IMPORTANT_SHARP":70754,"NOTIFICATIONS":70755,"NOTIFICATIONS_ACTIVE":70756,"NOTIFICATIONS_ACTIVE_OUTLINED":70757,"NOTIFICATIONS_ACTIVE_ROUNDED":70758,"NOTIFICATIONS_ACTIVE_SHARP":70759,"NOTIFICATIONS_NONE":70760,"NOTIFICATIONS_NONE_OUTLINED":70761,"NOTIFICATIONS_NONE_ROUNDED":70762,"NOTIFICATIONS_NONE_SHARP":70763,"NOTIFICATIONS_OFF":70764,"NOTIFICATIONS_OFF_OUTLINED":70765,"NOTIFICATIONS_OFF_ROUNDED":70766,"NOTIFICATIONS_OFF_SHARP":70767,"NOTIFICATIONS_ON":70768,"NOTIFICATIONS_ON_OUTLINED":70769,"NOTIFICATIONS_ON_ROUNDED":70770,"NOTIFICATIONS_ON_SHARP":70771,"NOTIFICATIONS_OUTLINED":70772,"NOTIFICATIONS_PAUSED":70773,"NOTIFICATIONS_PAUSED_OUTLINED":70774,"NOTIFICATIONS_PAUSED_ROUNDED":70775,"NOTIFICATIONS_PAUSED_SHARP":70776,"NOTIFICATIONS_ROUNDED":70777,"NOTIFICATIONS_SHARP":70778,"NOW_WALLPAPER":70779,"NOW_WALLPAPER_OUTLINED":70780,"NOW_WALLPAPER_ROUNDED":70781,"NOW_WALLPAPER_SHARP":70782,"NOW_WIDGETS":70783,"NOW_WIDGETS_OUTLINED":70784,"NOW_WIDGETS_ROUNDED":70785,"NOW_WIDGETS_SHARP":70786,"NUMBERS":70787,"NUMBERS_OUTLINED":70788,"NUMBERS_ROUNDED":70789,"NUMBERS_SHARP":70790,"OFFLINE_BOLT":70791,"OFFLINE_BOLT_OUTLINED":70792,"OFFLINE_BOLT_ROUNDED":70793,"OFFLINE_BOLT_SHARP":70794,"OFFLINE_PIN":70795,"OFFLINE_PIN_OUTLINED":70796,"OFFLINE_PIN_ROUNDED":70797,"OFFLINE_PIN_SHARP":70798,"OFFLINE_SHARE":70799,"OFFLINE_SHARE_OUTLINED":70800,"OFFLINE_SHARE_ROUNDED":70801,"OFFLINE_SHARE_SHARP":70802,"OIL_BARREL":70803,"OIL_BARREL_OUTLINED":70804,"OIL_BARREL_ROUNDED":70805,"OIL_BARREL_SHARP":70806,"ON_DEVICE_TRAINING":70807,"ON_DEVICE_TRAINING_OUTLINED":70808,"ON_DEVICE_TRAINING_ROUNDED":70809,"ON_DEVICE_TRAINING_SHARP":70810,"ONDEMAND_VIDEO":70811,"ONDEMAND_VIDEO_OUTLINED":70812,"ONDEMAND_VIDEO_ROUNDED":70813,"ONDEMAND_VIDEO_SHARP":70814,"ONE_K":70815,"ONE_K_OUTLINED":70816,"ONE_K_PLUS":70817,"ONE_K_PLUS_OUTLINED":70818,"ONE_K_PLUS_ROUNDED":70819,"ONE_K_PLUS_SHARP":70820,"ONE_K_ROUNDED":70821,"ONE_K_SHARP":70822,"ONE_X_MOBILEDATA":70823,"ONE_X_MOBILEDATA_OUTLINED":70824,"ONE_X_MOBILEDATA_ROUNDED":70825,"ONE_X_MOBILEDATA_SHARP":70826,"ONETWOTHREE":70827,"ONETWOTHREE_OUTLINED":70828,"ONETWOTHREE_ROUNDED":70829,"ONETWOTHREE_SHARP":70830,"ONLINE_PREDICTION":70831,"ONLINE_PREDICTION_OUTLINED":70832,"ONLINE_PREDICTION_ROUNDED":70833,"ONLINE_PREDICTION_SHARP":70834,"OPACITY":70835,"OPACITY_OUTLINED":70836,"OPACITY_ROUNDED":70837,"OPACITY_SHARP":70838,"OPEN_IN_BROWSER":70839,"OPEN_IN_BROWSER_OUTLINED":70840,"OPEN_IN_BROWSER_ROUNDED":70841,"OPEN_IN_BROWSER_SHARP":70842,"OPEN_IN_FULL":70843,"OPEN_IN_FULL_OUTLINED":70844,"OPEN_IN_FULL_ROUNDED":70845,"OPEN_IN_FULL_SHARP":70846,"OPEN_IN_NEW":70847,"OPEN_IN_NEW_OFF":70848,"OPEN_IN_NEW_OFF_OUTLINED":70849,"OPEN_IN_NEW_OFF_ROUNDED":70850,"OPEN_IN_NEW_OFF_SHARP":70851,"OPEN_IN_NEW_OUTLINED":70852,"OPEN_IN_NEW_ROUNDED":70853,"OPEN_IN_NEW_SHARP":70854,"OPEN_WITH":70855,"OPEN_WITH_OUTLINED":70856,"OPEN_WITH_ROUNDED":70857,"OPEN_WITH_SHARP":70858,"OTHER_HOUSES":70859,"OTHER_HOUSES_OUTLINED":70860,"OTHER_HOUSES_ROUNDED":70861,"OTHER_HOUSES_SHARP":70862,"OUTBOND":70863,"OUTBOND_OUTLINED":70864,"OUTBOND_ROUNDED":70865,"OUTBOND_SHARP":70866,"OUTBOUND":70867,"OUTBOUND_OUTLINED":70868,"OUTBOUND_ROUNDED":70869,"OUTBOUND_SHARP":70870,"OUTBOX":70871,"OUTBOX_OUTLINED":70872,"OUTBOX_ROUNDED":70873,"OUTBOX_SHARP":70874,"OUTDOOR_GRILL":70875,"OUTDOOR_GRILL_OUTLINED":70876,"OUTDOOR_GRILL_ROUNDED":70877,"OUTDOOR_GRILL_SHARP":70878,"OUTGOING_MAIL":70879,"OUTLET":70880,"OUTLET_OUTLINED":70881,"OUTLET_ROUNDED":70882,"OUTLET_SHARP":70883,"OUTLINED_FLAG":70884,"OUTLINED_FLAG_OUTLINED":70885,"OUTLINED_FLAG_ROUNDED":70886,"OUTLINED_FLAG_SHARP":70887,"OUTPUT":70888,"OUTPUT_OUTLINED":70889,"OUTPUT_ROUNDED":70890,"OUTPUT_SHARP":70891,"PADDING":70892,"PADDING_OUTLINED":70893,"PADDING_ROUNDED":70894,"PADDING_SHARP":70895,"PAGES":70896,"PAGES_OUTLINED":70897,"PAGES_ROUNDED":70898,"PAGES_SHARP":70899,"PAGEVIEW":70900,"PAGEVIEW_OUTLINED":70901,"PAGEVIEW_ROUNDED":70902,"PAGEVIEW_SHARP":70903,"PAID":70904,"PAID_OUTLINED":70905,"PAID_ROUNDED":70906,"PAID_SHARP":70907,"PALETTE":70908,"PALETTE_OUTLINED":70909,"PALETTE_ROUNDED":70910,"PALETTE_SHARP":70911,"PALLET":70912,"PAN_TOOL":70913,"PAN_TOOL_ALT":70914,"PAN_TOOL_ALT_OUTLINED":70915,"PAN_TOOL_ALT_ROUNDED":70916,"PAN_TOOL_ALT_SHARP":70917,"PAN_TOOL_OUTLINED":70918,"PAN_TOOL_ROUNDED":70919,"PAN_TOOL_SHARP":70920,"PANORAMA":70921,"PANORAMA_FISH_EYE":70922,"PANORAMA_FISH_EYE_OUTLINED":70923,"PANORAMA_FISH_EYE_ROUNDED":70924,"PANORAMA_FISH_EYE_SHARP":70925,"PANORAMA_FISHEYE":70926,"PANORAMA_FISHEYE_OUTLINED":70927,"PANORAMA_FISHEYE_ROUNDED":70928,"PANORAMA_FISHEYE_SHARP":70929,"PANORAMA_HORIZONTAL":70930,"PANORAMA_HORIZONTAL_OUTLINED":70931,"PANORAMA_HORIZONTAL_ROUNDED":70932,"PANORAMA_HORIZONTAL_SELECT":70933,"PANORAMA_HORIZONTAL_SELECT_OUTLINED":70934,"PANORAMA_HORIZONTAL_SELECT_ROUNDED":70935,"PANORAMA_HORIZONTAL_SELECT_SHARP":70936,"PANORAMA_HORIZONTAL_SHARP":70937,"PANORAMA_OUTLINED":70938,"PANORAMA_PHOTOSPHERE":70939,"PANORAMA_PHOTOSPHERE_OUTLINED":70940,"PANORAMA_PHOTOSPHERE_ROUNDED":70941,"PANORAMA_PHOTOSPHERE_SELECT":70942,"PANORAMA_PHOTOSPHERE_SELECT_OUTLINED":70943,"PANORAMA_PHOTOSPHERE_SELECT_ROUNDED":70944,"PANORAMA_PHOTOSPHERE_SELECT_SHARP":70945,"PANORAMA_PHOTOSPHERE_SHARP":70946,"PANORAMA_ROUNDED":70947,"PANORAMA_SHARP":70948,"PANORAMA_VERTICAL":70949,"PANORAMA_VERTICAL_OUTLINED":70950,"PANORAMA_VERTICAL_ROUNDED":70951,"PANORAMA_VERTICAL_SELECT":70952,"PANORAMA_VERTICAL_SELECT_OUTLINED":70953,"PANORAMA_VERTICAL_SELECT_ROUNDED":70954,"PANORAMA_VERTICAL_SELECT_SHARP":70955,"PANORAMA_VERTICAL_SHARP":70956,"PANORAMA_WIDE_ANGLE":70957,"PANORAMA_WIDE_ANGLE_OUTLINED":70958,"PANORAMA_WIDE_ANGLE_ROUNDED":70959,"PANORAMA_WIDE_ANGLE_SELECT":70960,"PANORAMA_WIDE_ANGLE_SELECT_OUTLINED":70961,"PANORAMA_WIDE_ANGLE_SELECT_ROUNDED":70962,"PANORAMA_WIDE_ANGLE_SELECT_SHARP":70963,"PANORAMA_WIDE_ANGLE_SHARP":70964,"PARAGLIDING":70965,"PARAGLIDING_OUTLINED":70966,"PARAGLIDING_ROUNDED":70967,"PARAGLIDING_SHARP":70968,"PARK":70969,"PARK_OUTLINED":70970,"PARK_ROUNDED":70971,"PARK_SHARP":70972,"PARTY_MODE":70973,"PARTY_MODE_OUTLINED":70974,"PARTY_MODE_ROUNDED":70975,"PARTY_MODE_SHARP":70976,"PASSWORD":70977,"PASSWORD_OUTLINED":70978,"PASSWORD_ROUNDED":70979,"PASSWORD_SHARP":70980,"PASTE":70981,"PASTE_OUTLINED":70982,"PASTE_ROUNDED":70983,"PASTE_SHARP":70984,"PATTERN":70985,"PATTERN_OUTLINED":70986,"PATTERN_ROUNDED":70987,"PATTERN_SHARP":70988,"PAUSE":70989,"PAUSE_CIRCLE":70990,"PAUSE_CIRCLE_FILLED":70991,"PAUSE_CIRCLE_FILLED_OUTLINED":70992,"PAUSE_CIRCLE_FILLED_ROUNDED":70993,"PAUSE_CIRCLE_FILLED_SHARP":70994,"PAUSE_CIRCLE_OUTLINE":70995,"PAUSE_CIRCLE_OUTLINE_OUTLINED":70996,"PAUSE_CIRCLE_OUTLINE_ROUNDED":70997,"PAUSE_CIRCLE_OUTLINE_SHARP":70998,"PAUSE_CIRCLE_OUTLINED":70999,"PAUSE_CIRCLE_ROUNDED":71000,"PAUSE_CIRCLE_SHARP":71001,"PAUSE_OUTLINED":71002,"PAUSE_PRESENTATION":71003,"PAUSE_PRESENTATION_OUTLINED":71004,"PAUSE_PRESENTATION_ROUNDED":71005,"PAUSE_PRESENTATION_SHARP":71006,"PAUSE_ROUNDED":71007,"PAUSE_SHARP":71008,"PAYMENT":71009,"PAYMENT_OUTLINED":71010,"PAYMENT_ROUNDED":71011,"PAYMENT_SHARP":71012,"PAYMENTS":71013,"PAYMENTS_OUTLINED":71014,"PAYMENTS_ROUNDED":71015,"PAYMENTS_SHARP":71016,"PAYPAL":71017,"PAYPAL_OUTLINED":71018,"PAYPAL_ROUNDED":71019,"PAYPAL_SHARP":71020,"PEDAL_BIKE":71021,"PEDAL_BIKE_OUTLINED":71022,"PEDAL_BIKE_ROUNDED":71023,"PEDAL_BIKE_SHARP":71024,"PENDING":71025,"PENDING_ACTIONS":71026,"PENDING_ACTIONS_OUTLINED":71027,"PENDING_ACTIONS_ROUNDED":71028,"PENDING_ACTIONS_SHARP":71029,"PENDING_OUTLINED":71030,"PENDING_ROUNDED":71031,"PENDING_SHARP":71032,"PENTAGON":71033,"PENTAGON_OUTLINED":71034,"PENTAGON_ROUNDED":71035,"PENTAGON_SHARP":71036,"PEOPLE":71037,"PEOPLE_ALT":71038,"PEOPLE_ALT_OUTLINED":71039,"PEOPLE_ALT_ROUNDED":71040,"PEOPLE_ALT_SHARP":71041,"PEOPLE_OUTLINE":71042,"PEOPLE_OUTLINE_OUTLINED":71043,"PEOPLE_OUTLINE_ROUNDED":71044,"PEOPLE_OUTLINE_SHARP":71045,"PEOPLE_OUTLINED":71046,"PEOPLE_ROUNDED":71047,"PEOPLE_SHARP":71048,"PERCENT":71049,"PERCENT_OUTLINED":71050,"PERCENT_ROUNDED":71051,"PERCENT_SHARP":71052,"PERM_CAMERA_MIC":71053,"PERM_CAMERA_MIC_OUTLINED":71054,"PERM_CAMERA_MIC_ROUNDED":71055,"PERM_CAMERA_MIC_SHARP":71056,"PERM_CONTACT_CAL":71057,"PERM_CONTACT_CAL_OUTLINED":71058,"PERM_CONTACT_CAL_ROUNDED":71059,"PERM_CONTACT_CAL_SHARP":71060,"PERM_CONTACT_CALENDAR":71061,"PERM_CONTACT_CALENDAR_OUTLINED":71062,"PERM_CONTACT_CALENDAR_ROUNDED":71063,"PERM_CONTACT_CALENDAR_SHARP":71064,"PERM_DATA_SETTING":71065,"PERM_DATA_SETTING_OUTLINED":71066,"PERM_DATA_SETTING_ROUNDED":71067,"PERM_DATA_SETTING_SHARP":71068,"PERM_DEVICE_INFO":71069,"PERM_DEVICE_INFO_OUTLINED":71070,"PERM_DEVICE_INFO_ROUNDED":71071,"PERM_DEVICE_INFO_SHARP":71072,"PERM_DEVICE_INFORMATION":71073,"PERM_DEVICE_INFORMATION_OUTLINED":71074,"PERM_DEVICE_INFORMATION_ROUNDED":71075,"PERM_DEVICE_INFORMATION_SHARP":71076,"PERM_IDENTITY":71077,"PERM_IDENTITY_OUTLINED":71078,"PERM_IDENTITY_ROUNDED":71079,"PERM_IDENTITY_SHARP":71080,"PERM_MEDIA":71081,"PERM_MEDIA_OUTLINED":71082,"PERM_MEDIA_ROUNDED":71083,"PERM_MEDIA_SHARP":71084,"PERM_PHONE_MSG":71085,"PERM_PHONE_MSG_OUTLINED":71086,"PERM_PHONE_MSG_ROUNDED":71087,"PERM_PHONE_MSG_SHARP":71088,"PERM_SCAN_WIFI":71089,"PERM_SCAN_WIFI_OUTLINED":71090,"PERM_SCAN_WIFI_ROUNDED":71091,"PERM_SCAN_WIFI_SHARP":71092,"PERSON":71093,"PERSON_2":71094,"PERSON_2_OUTLINED":71095,"PERSON_2_ROUNDED":71096,"PERSON_2_SHARP":71097,"PERSON_3":71098,"PERSON_3_OUTLINED":71099,"PERSON_3_ROUNDED":71100,"PERSON_3_SHARP":71101,"PERSON_4":71102,"PERSON_4_OUTLINED":71103,"PERSON_4_ROUNDED":71104,"PERSON_4_SHARP":71105,"PERSON_ADD":71106,"PERSON_ADD_ALT":71107,"PERSON_ADD_ALT_1":71108,"PERSON_ADD_ALT_1_OUTLINED":71109,"PERSON_ADD_ALT_1_ROUNDED":71110,"PERSON_ADD_ALT_1_SHARP":71111,"PERSON_ADD_ALT_OUTLINED":71112,"PERSON_ADD_ALT_ROUNDED":71113,"PERSON_ADD_ALT_SHARP":71114,"PERSON_ADD_DISABLED":71115,"PERSON_ADD_DISABLED_OUTLINED":71116,"PERSON_ADD_DISABLED_ROUNDED":71117,"PERSON_ADD_DISABLED_SHARP":71118,"PERSON_ADD_OUTLINED":71119,"PERSON_ADD_ROUNDED":71120,"PERSON_ADD_SHARP":71121,"PERSON_OFF":71122,"PERSON_OFF_OUTLINED":71123,"PERSON_OFF_ROUNDED":71124,"PERSON_OFF_SHARP":71125,"PERSON_OUTLINE":71126,"PERSON_OUTLINE_OUTLINED":71127,"PERSON_OUTLINE_ROUNDED":71128,"PERSON_OUTLINE_SHARP":71129,"PERSON_OUTLINED":71130,"PERSON_PIN":71131,"PERSON_PIN_CIRCLE":71132,"PERSON_PIN_CIRCLE_OUTLINED":71133,"PERSON_PIN_CIRCLE_ROUNDED":71134,"PERSON_PIN_CIRCLE_SHARP":71135,"PERSON_PIN_OUTLINED":71136,"PERSON_PIN_ROUNDED":71137,"PERSON_PIN_SHARP":71138,"PERSON_REMOVE":71139,"PERSON_REMOVE_ALT_1":71140,"PERSON_REMOVE_ALT_1_OUTLINED":71141,"PERSON_REMOVE_ALT_1_ROUNDED":71142,"PERSON_REMOVE_ALT_1_SHARP":71143,"PERSON_REMOVE_OUTLINED":71144,"PERSON_REMOVE_ROUNDED":71145,"PERSON_REMOVE_SHARP":71146,"PERSON_ROUNDED":71147,"PERSON_SEARCH":71148,"PERSON_SEARCH_OUTLINED":71149,"PERSON_SEARCH_ROUNDED":71150,"PERSON_SEARCH_SHARP":71151,"PERSON_SHARP":71152,"PERSONAL_INJURY":71153,"PERSONAL_INJURY_OUTLINED":71154,"PERSONAL_INJURY_ROUNDED":71155,"PERSONAL_INJURY_SHARP":71156,"PERSONAL_VIDEO":71157,"PERSONAL_VIDEO_OUTLINED":71158,"PERSONAL_VIDEO_ROUNDED":71159,"PERSONAL_VIDEO_SHARP":71160,"PEST_CONTROL":71161,"PEST_CONTROL_OUTLINED":71162,"PEST_CONTROL_RODENT":71163,"PEST_CONTROL_RODENT_OUTLINED":71164,"PEST_CONTROL_RODENT_ROUNDED":71165,"PEST_CONTROL_RODENT_SHARP":71166,"PEST_CONTROL_ROUNDED":71167,"PEST_CONTROL_SHARP":71168,"PETS":71169,"PETS_OUTLINED":71170,"PETS_ROUNDED":71171,"PETS_SHARP":71172,"PHISHING":71173,"PHISHING_OUTLINED":71174,"PHISHING_ROUNDED":71175,"PHISHING_SHARP":71176,"PHONE":71177,"PHONE_ANDROID":71178,"PHONE_ANDROID_OUTLINED":71179,"PHONE_ANDROID_ROUNDED":71180,"PHONE_ANDROID_SHARP":71181,"PHONE_BLUETOOTH_SPEAKER":71182,"PHONE_BLUETOOTH_SPEAKER_OUTLINED":71183,"PHONE_BLUETOOTH_SPEAKER_ROUNDED":71184,"PHONE_BLUETOOTH_SPEAKER_SHARP":71185,"PHONE_CALLBACK":71186,"PHONE_CALLBACK_OUTLINED":71187,"PHONE_CALLBACK_ROUNDED":71188,"PHONE_CALLBACK_SHARP":71189,"PHONE_DISABLED":71190,"PHONE_DISABLED_OUTLINED":71191,"PHONE_DISABLED_ROUNDED":71192,"PHONE_DISABLED_SHARP":71193,"PHONE_ENABLED":71194,"PHONE_ENABLED_OUTLINED":71195,"PHONE_ENABLED_ROUNDED":71196,"PHONE_ENABLED_SHARP":71197,"PHONE_FORWARDED":71198,"PHONE_FORWARDED_OUTLINED":71199,"PHONE_FORWARDED_ROUNDED":71200,"PHONE_FORWARDED_SHARP":71201,"PHONE_IN_TALK":71202,"PHONE_IN_TALK_OUTLINED":71203,"PHONE_IN_TALK_ROUNDED":71204,"PHONE_IN_TALK_SHARP":71205,"PHONE_IPHONE":71206,"PHONE_IPHONE_OUTLINED":71207,"PHONE_IPHONE_ROUNDED":71208,"PHONE_IPHONE_SHARP":71209,"PHONE_LOCKED":71210,"PHONE_LOCKED_OUTLINED":71211,"PHONE_LOCKED_ROUNDED":71212,"PHONE_LOCKED_SHARP":71213,"PHONE_MISSED":71214,"PHONE_MISSED_OUTLINED":71215,"PHONE_MISSED_ROUNDED":71216,"PHONE_MISSED_SHARP":71217,"PHONE_OUTLINED":71218,"PHONE_PAUSED":71219,"PHONE_PAUSED_OUTLINED":71220,"PHONE_PAUSED_ROUNDED":71221,"PHONE_PAUSED_SHARP":71222,"PHONE_ROUNDED":71223,"PHONE_SHARP":71224,"PHONELINK":71225,"PHONELINK_ERASE":71226,"PHONELINK_ERASE_OUTLINED":71227,"PHONELINK_ERASE_ROUNDED":71228,"PHONELINK_ERASE_SHARP":71229,"PHONELINK_LOCK":71230,"PHONELINK_LOCK_OUTLINED":71231,"PHONELINK_LOCK_ROUNDED":71232,"PHONELINK_LOCK_SHARP":71233,"PHONELINK_OFF":71234,"PHONELINK_OFF_OUTLINED":71235,"PHONELINK_OFF_ROUNDED":71236,"PHONELINK_OFF_SHARP":71237,"PHONELINK_OUTLINED":71238,"PHONELINK_RING":71239,"PHONELINK_RING_OUTLINED":71240,"PHONELINK_RING_ROUNDED":71241,"PHONELINK_RING_SHARP":71242,"PHONELINK_ROUNDED":71243,"PHONELINK_SETUP":71244,"PHONELINK_SETUP_OUTLINED":71245,"PHONELINK_SETUP_ROUNDED":71246,"PHONELINK_SETUP_SHARP":71247,"PHONELINK_SHARP":71248,"PHOTO":71249,"PHOTO_ALBUM":71250,"PHOTO_ALBUM_OUTLINED":71251,"PHOTO_ALBUM_ROUNDED":71252,"PHOTO_ALBUM_SHARP":71253,"PHOTO_CAMERA":71254,"PHOTO_CAMERA_BACK":71255,"PHOTO_CAMERA_BACK_OUTLINED":71256,"PHOTO_CAMERA_BACK_ROUNDED":71257,"PHOTO_CAMERA_BACK_SHARP":71258,"PHOTO_CAMERA_FRONT":71259,"PHOTO_CAMERA_FRONT_OUTLINED":71260,"PHOTO_CAMERA_FRONT_ROUNDED":71261,"PHOTO_CAMERA_FRONT_SHARP":71262,"PHOTO_CAMERA_OUTLINED":71263,"PHOTO_CAMERA_ROUNDED":71264,"PHOTO_CAMERA_SHARP":71265,"PHOTO_FILTER":71266,"PHOTO_FILTER_OUTLINED":71267,"PHOTO_FILTER_ROUNDED":71268,"PHOTO_FILTER_SHARP":71269,"PHOTO_LIBRARY":71270,"PHOTO_LIBRARY_OUTLINED":71271,"PHOTO_LIBRARY_ROUNDED":71272,"PHOTO_LIBRARY_SHARP":71273,"PHOTO_OUTLINED":71274,"PHOTO_ROUNDED":71275,"PHOTO_SHARP":71276,"PHOTO_SIZE_SELECT_ACTUAL":71277,"PHOTO_SIZE_SELECT_ACTUAL_OUTLINED":71278,"PHOTO_SIZE_SELECT_ACTUAL_ROUNDED":71279,"PHOTO_SIZE_SELECT_ACTUAL_SHARP":71280,"PHOTO_SIZE_SELECT_LARGE":71281,"PHOTO_SIZE_SELECT_LARGE_OUTLINED":71282,"PHOTO_SIZE_SELECT_LARGE_ROUNDED":71283,"PHOTO_SIZE_SELECT_LARGE_SHARP":71284,"PHOTO_SIZE_SELECT_SMALL":71285,"PHOTO_SIZE_SELECT_SMALL_OUTLINED":71286,"PHOTO_SIZE_SELECT_SMALL_ROUNDED":71287,"PHOTO_SIZE_SELECT_SMALL_SHARP":71288,"PHP":71289,"PHP_OUTLINED":71290,"PHP_ROUNDED":71291,"PHP_SHARP":71292,"PIANO":71293,"PIANO_OFF":71294,"PIANO_OFF_OUTLINED":71295,"PIANO_OFF_ROUNDED":71296,"PIANO_OFF_SHARP":71297,"PIANO_OUTLINED":71298,"PIANO_ROUNDED":71299,"PIANO_SHARP":71300,"PICTURE_AS_PDF":71301,"PICTURE_AS_PDF_OUTLINED":71302,"PICTURE_AS_PDF_ROUNDED":71303,"PICTURE_AS_PDF_SHARP":71304,"PICTURE_IN_PICTURE":71305,"PICTURE_IN_PICTURE_ALT":71306,"PICTURE_IN_PICTURE_ALT_OUTLINED":71307,"PICTURE_IN_PICTURE_ALT_ROUNDED":71308,"PICTURE_IN_PICTURE_ALT_SHARP":71309,"PICTURE_IN_PICTURE_OUTLINED":71310,"PICTURE_IN_PICTURE_ROUNDED":71311,"PICTURE_IN_PICTURE_SHARP":71312,"PIE_CHART":71313,"PIE_CHART_OUTLINE":71314,"PIE_CHART_OUTLINE_OUTLINED":71315,"PIE_CHART_OUTLINE_ROUNDED":71316,"PIE_CHART_OUTLINE_SHARP":71317,"PIE_CHART_ROUNDED":71318,"PIE_CHART_SHARP":71319,"PIN":71320,"PIN_DROP":71321,"PIN_DROP_OUTLINED":71322,"PIN_DROP_ROUNDED":71323,"PIN_DROP_SHARP":71324,"PIN_END":71325,"PIN_END_OUTLINED":71326,"PIN_END_ROUNDED":71327,"PIN_END_SHARP":71328,"PIN_INVOKE":71329,"PIN_INVOKE_OUTLINED":71330,"PIN_INVOKE_ROUNDED":71331,"PIN_INVOKE_SHARP":71332,"PIN_OUTLINED":71333,"PIN_ROUNDED":71334,"PIN_SHARP":71335,"PINCH":71336,"PINCH_OUTLINED":71337,"PINCH_ROUNDED":71338,"PINCH_SHARP":71339,"PIVOT_TABLE_CHART":71340,"PIVOT_TABLE_CHART_OUTLINED":71341,"PIVOT_TABLE_CHART_ROUNDED":71342,"PIVOT_TABLE_CHART_SHARP":71343,"PIX":71344,"PIX_OUTLINED":71345,"PIX_ROUNDED":71346,"PIX_SHARP":71347,"PLACE":71348,"PLACE_OUTLINED":71349,"PLACE_ROUNDED":71350,"PLACE_SHARP":71351,"PLAGIARISM":71352,"PLAGIARISM_OUTLINED":71353,"PLAGIARISM_ROUNDED":71354,"PLAGIARISM_SHARP":71355,"PLAY_ARROW":71356,"PLAY_ARROW_OUTLINED":71357,"PLAY_ARROW_ROUNDED":71358,"PLAY_ARROW_SHARP":71359,"PLAY_CIRCLE":71360,"PLAY_CIRCLE_FILL":71361,"PLAY_CIRCLE_FILL_OUTLINED":71362,"PLAY_CIRCLE_FILL_ROUNDED":71363,"PLAY_CIRCLE_FILL_SHARP":71364,"PLAY_CIRCLE_FILLED":71365,"PLAY_CIRCLE_FILLED_OUTLINED":71366,"PLAY_CIRCLE_FILLED_ROUNDED":71367,"PLAY_CIRCLE_FILLED_SHARP":71368,"PLAY_CIRCLE_OUTLINE":71369,"PLAY_CIRCLE_OUTLINE_OUTLINED":71370,"PLAY_CIRCLE_OUTLINE_ROUNDED":71371,"PLAY_CIRCLE_OUTLINE_SHARP":71372,"PLAY_CIRCLE_OUTLINED":71373,"PLAY_CIRCLE_ROUNDED":71374,"PLAY_CIRCLE_SHARP":71375,"PLAY_DISABLED":71376,"PLAY_DISABLED_OUTLINED":71377,"PLAY_DISABLED_ROUNDED":71378,"PLAY_DISABLED_SHARP":71379,"PLAY_FOR_WORK":71380,"PLAY_FOR_WORK_OUTLINED":71381,"PLAY_FOR_WORK_ROUNDED":71382,"PLAY_FOR_WORK_SHARP":71383,"PLAY_LESSON":71384,"PLAY_LESSON_OUTLINED":71385,"PLAY_LESSON_ROUNDED":71386,"PLAY_LESSON_SHARP":71387,"PLAYLIST_ADD":71388,"PLAYLIST_ADD_CHECK":71389,"PLAYLIST_ADD_CHECK_CIRCLE":71390,"PLAYLIST_ADD_CHECK_CIRCLE_OUTLINED":71391,"PLAYLIST_ADD_CHECK_CIRCLE_ROUNDED":71392,"PLAYLIST_ADD_CHECK_CIRCLE_SHARP":71393,"PLAYLIST_ADD_CHECK_OUTLINED":71394,"PLAYLIST_ADD_CHECK_ROUNDED":71395,"PLAYLIST_ADD_CHECK_SHARP":71396,"PLAYLIST_ADD_CIRCLE":71397,"PLAYLIST_ADD_CIRCLE_OUTLINED":71398,"PLAYLIST_ADD_CIRCLE_ROUNDED":71399,"PLAYLIST_ADD_CIRCLE_SHARP":71400,"PLAYLIST_ADD_OUTLINED":71401,"PLAYLIST_ADD_ROUNDED":71402,"PLAYLIST_ADD_SHARP":71403,"PLAYLIST_PLAY":71404,"PLAYLIST_PLAY_OUTLINED":71405,"PLAYLIST_PLAY_ROUNDED":71406,"PLAYLIST_PLAY_SHARP":71407,"PLAYLIST_REMOVE":71408,"PLAYLIST_REMOVE_OUTLINED":71409,"PLAYLIST_REMOVE_ROUNDED":71410,"PLAYLIST_REMOVE_SHARP":71411,"PLUMBING":71412,"PLUMBING_OUTLINED":71413,"PLUMBING_ROUNDED":71414,"PLUMBING_SHARP":71415,"PLUS_ONE":71416,"PLUS_ONE_OUTLINED":71417,"PLUS_ONE_ROUNDED":71418,"PLUS_ONE_SHARP":71419,"PODCASTS":71420,"PODCASTS_OUTLINED":71421,"PODCASTS_ROUNDED":71422,"PODCASTS_SHARP":71423,"POINT_OF_SALE":71424,"POINT_OF_SALE_OUTLINED":71425,"POINT_OF_SALE_ROUNDED":71426,"POINT_OF_SALE_SHARP":71427,"POLICY":71428,"POLICY_OUTLINED":71429,"POLICY_ROUNDED":71430,"POLICY_SHARP":71431,"POLL":71432,"POLL_OUTLINED":71433,"POLL_ROUNDED":71434,"POLL_SHARP":71435,"POLYLINE":71436,"POLYLINE_OUTLINED":71437,"POLYLINE_ROUNDED":71438,"POLYLINE_SHARP":71439,"POLYMER":71440,"POLYMER_OUTLINED":71441,"POLYMER_ROUNDED":71442,"POLYMER_SHARP":71443,"POOL":71444,"POOL_OUTLINED":71445,"POOL_ROUNDED":71446,"POOL_SHARP":71447,"PORTABLE_WIFI_OFF":71448,"PORTABLE_WIFI_OFF_OUTLINED":71449,"PORTABLE_WIFI_OFF_ROUNDED":71450,"PORTABLE_WIFI_OFF_SHARP":71451,"PORTRAIT":71452,"PORTRAIT_OUTLINED":71453,"PORTRAIT_ROUNDED":71454,"PORTRAIT_SHARP":71455,"POST_ADD":71456,"POST_ADD_OUTLINED":71457,"POST_ADD_ROUNDED":71458,"POST_ADD_SHARP":71459,"POWER":71460,"POWER_INPUT":71461,"POWER_INPUT_OUTLINED":71462,"POWER_INPUT_ROUNDED":71463,"POWER_INPUT_SHARP":71464,"POWER_OFF":71465,"POWER_OFF_OUTLINED":71466,"POWER_OFF_ROUNDED":71467,"POWER_OFF_SHARP":71468,"POWER_OUTLINED":71469,"POWER_ROUNDED":71470,"POWER_SETTINGS_NEW":71471,"POWER_SETTINGS_NEW_OUTLINED":71472,"POWER_SETTINGS_NEW_ROUNDED":71473,"POWER_SETTINGS_NEW_SHARP":71474,"POWER_SHARP":71475,"PRECISION_MANUFACTURING":71476,"PRECISION_MANUFACTURING_OUTLINED":71477,"PRECISION_MANUFACTURING_ROUNDED":71478,"PRECISION_MANUFACTURING_SHARP":71479,"PREGNANT_WOMAN":71480,"PREGNANT_WOMAN_OUTLINED":71481,"PREGNANT_WOMAN_ROUNDED":71482,"PREGNANT_WOMAN_SHARP":71483,"PRESENT_TO_ALL":71484,"PRESENT_TO_ALL_OUTLINED":71485,"PRESENT_TO_ALL_ROUNDED":71486,"PRESENT_TO_ALL_SHARP":71487,"PREVIEW":71488,"PREVIEW_OUTLINED":71489,"PREVIEW_ROUNDED":71490,"PREVIEW_SHARP":71491,"PRICE_CHANGE":71492,"PRICE_CHANGE_OUTLINED":71493,"PRICE_CHANGE_ROUNDED":71494,"PRICE_CHANGE_SHARP":71495,"PRICE_CHECK":71496,"PRICE_CHECK_OUTLINED":71497,"PRICE_CHECK_ROUNDED":71498,"PRICE_CHECK_SHARP":71499,"PRINT":71500,"PRINT_DISABLED":71501,"PRINT_DISABLED_OUTLINED":71502,"PRINT_DISABLED_ROUNDED":71503,"PRINT_DISABLED_SHARP":71504,"PRINT_OUTLINED":71505,"PRINT_ROUNDED":71506,"PRINT_SHARP":71507,"PRIORITY_HIGH":71508,"PRIORITY_HIGH_OUTLINED":71509,"PRIORITY_HIGH_ROUNDED":71510,"PRIORITY_HIGH_SHARP":71511,"PRIVACY_TIP":71512,"PRIVACY_TIP_OUTLINED":71513,"PRIVACY_TIP_ROUNDED":71514,"PRIVACY_TIP_SHARP":71515,"PRIVATE_CONNECTIVITY":71516,"PRIVATE_CONNECTIVITY_OUTLINED":71517,"PRIVATE_CONNECTIVITY_ROUNDED":71518,"PRIVATE_CONNECTIVITY_SHARP":71519,"PRODUCTION_QUANTITY_LIMITS":71520,"PRODUCTION_QUANTITY_LIMITS_OUTLINED":71521,"PRODUCTION_QUANTITY_LIMITS_ROUNDED":71522,"PRODUCTION_QUANTITY_LIMITS_SHARP":71523,"PROPANE":71524,"PROPANE_OUTLINED":71525,"PROPANE_ROUNDED":71526,"PROPANE_SHARP":71527,"PROPANE_TANK":71528,"PROPANE_TANK_OUTLINED":71529,"PROPANE_TANK_ROUNDED":71530,"PROPANE_TANK_SHARP":71531,"PSYCHOLOGY":71532,"PSYCHOLOGY_ALT":71533,"PSYCHOLOGY_ALT_OUTLINED":71534,"PSYCHOLOGY_ALT_ROUNDED":71535,"PSYCHOLOGY_ALT_SHARP":71536,"PSYCHOLOGY_OUTLINED":71537,"PSYCHOLOGY_ROUNDED":71538,"PSYCHOLOGY_SHARP":71539,"PUBLIC":71540,"PUBLIC_OFF":71541,"PUBLIC_OFF_OUTLINED":71542,"PUBLIC_OFF_ROUNDED":71543,"PUBLIC_OFF_SHARP":71544,"PUBLIC_OUTLINED":71545,"PUBLIC_ROUNDED":71546,"PUBLIC_SHARP":71547,"PUBLISH":71548,"PUBLISH_OUTLINED":71549,"PUBLISH_ROUNDED":71550,"PUBLISH_SHARP":71551,"PUBLISHED_WITH_CHANGES":71552,"PUBLISHED_WITH_CHANGES_OUTLINED":71553,"PUBLISHED_WITH_CHANGES_ROUNDED":71554,"PUBLISHED_WITH_CHANGES_SHARP":71555,"PUNCH_CLOCK":71556,"PUNCH_CLOCK_OUTLINED":71557,"PUNCH_CLOCK_ROUNDED":71558,"PUNCH_CLOCK_SHARP":71559,"PUSH_PIN":71560,"PUSH_PIN_OUTLINED":71561,"PUSH_PIN_ROUNDED":71562,"PUSH_PIN_SHARP":71563,"QR_CODE":71564,"QR_CODE_2":71565,"QR_CODE_2_OUTLINED":71566,"QR_CODE_2_ROUNDED":71567,"QR_CODE_2_SHARP":71568,"QR_CODE_OUTLINED":71569,"QR_CODE_ROUNDED":71570,"QR_CODE_SCANNER":71571,"QR_CODE_SCANNER_OUTLINED":71572,"QR_CODE_SCANNER_ROUNDED":71573,"QR_CODE_SCANNER_SHARP":71574,"QR_CODE_SHARP":71575,"QUERY_BUILDER":71576,"QUERY_BUILDER_OUTLINED":71577,"QUERY_BUILDER_ROUNDED":71578,"QUERY_BUILDER_SHARP":71579,"QUERY_STATS":71580,"QUERY_STATS_OUTLINED":71581,"QUERY_STATS_ROUNDED":71582,"QUERY_STATS_SHARP":71583,"QUESTION_ANSWER":71584,"QUESTION_ANSWER_OUTLINED":71585,"QUESTION_ANSWER_ROUNDED":71586,"QUESTION_ANSWER_SHARP":71587,"QUESTION_MARK":71588,"QUESTION_MARK_OUTLINED":71589,"QUESTION_MARK_ROUNDED":71590,"QUESTION_MARK_SHARP":71591,"QUEUE":71592,"QUEUE_MUSIC":71593,"QUEUE_MUSIC_OUTLINED":71594,"QUEUE_MUSIC_ROUNDED":71595,"QUEUE_MUSIC_SHARP":71596,"QUEUE_OUTLINED":71597,"QUEUE_PLAY_NEXT":71598,"QUEUE_PLAY_NEXT_OUTLINED":71599,"QUEUE_PLAY_NEXT_ROUNDED":71600,"QUEUE_PLAY_NEXT_SHARP":71601,"QUEUE_ROUNDED":71602,"QUEUE_SHARP":71603,"QUICK_CONTACTS_DIALER":71604,"QUICK_CONTACTS_DIALER_OUTLINED":71605,"QUICK_CONTACTS_DIALER_ROUNDED":71606,"QUICK_CONTACTS_DIALER_SHARP":71607,"QUICK_CONTACTS_MAIL":71608,"QUICK_CONTACTS_MAIL_OUTLINED":71609,"QUICK_CONTACTS_MAIL_ROUNDED":71610,"QUICK_CONTACTS_MAIL_SHARP":71611,"QUICKREPLY":71612,"QUICKREPLY_OUTLINED":71613,"QUICKREPLY_ROUNDED":71614,"QUICKREPLY_SHARP":71615,"QUIZ":71616,"QUIZ_OUTLINED":71617,"QUIZ_ROUNDED":71618,"QUIZ_SHARP":71619,"QUORA":71620,"QUORA_OUTLINED":71621,"QUORA_ROUNDED":71622,"QUORA_SHARP":71623,"R_MOBILEDATA":71624,"R_MOBILEDATA_OUTLINED":71625,"R_MOBILEDATA_ROUNDED":71626,"R_MOBILEDATA_SHARP":71627,"RADAR":71628,"RADAR_OUTLINED":71629,"RADAR_ROUNDED":71630,"RADAR_SHARP":71631,"RADIO":71632,"RADIO_BUTTON_CHECKED":71633,"RADIO_BUTTON_CHECKED_OUTLINED":71634,"RADIO_BUTTON_CHECKED_ROUNDED":71635,"RADIO_BUTTON_CHECKED_SHARP":71636,"RADIO_BUTTON_OFF":71637,"RADIO_BUTTON_OFF_OUTLINED":71638,"RADIO_BUTTON_OFF_ROUNDED":71639,"RADIO_BUTTON_OFF_SHARP":71640,"RADIO_BUTTON_ON":71641,"RADIO_BUTTON_ON_OUTLINED":71642,"RADIO_BUTTON_ON_ROUNDED":71643,"RADIO_BUTTON_ON_SHARP":71644,"RADIO_BUTTON_UNCHECKED":71645,"RADIO_BUTTON_UNCHECKED_OUTLINED":71646,"RADIO_BUTTON_UNCHECKED_ROUNDED":71647,"RADIO_BUTTON_UNCHECKED_SHARP":71648,"RADIO_OUTLINED":71649,"RADIO_ROUNDED":71650,"RADIO_SHARP":71651,"RAILWAY_ALERT":71652,"RAILWAY_ALERT_OUTLINED":71653,"RAILWAY_ALERT_ROUNDED":71654,"RAILWAY_ALERT_SHARP":71655,"RAMEN_DINING":71656,"RAMEN_DINING_OUTLINED":71657,"RAMEN_DINING_ROUNDED":71658,"RAMEN_DINING_SHARP":71659,"RAMP_LEFT":71660,"RAMP_LEFT_OUTLINED":71661,"RAMP_LEFT_ROUNDED":71662,"RAMP_LEFT_SHARP":71663,"RAMP_RIGHT":71664,"RAMP_RIGHT_OUTLINED":71665,"RAMP_RIGHT_ROUNDED":71666,"RAMP_RIGHT_SHARP":71667,"RATE_REVIEW":71668,"RATE_REVIEW_OUTLINED":71669,"RATE_REVIEW_ROUNDED":71670,"RATE_REVIEW_SHARP":71671,"RAW_OFF":71672,"RAW_OFF_OUTLINED":71673,"RAW_OFF_ROUNDED":71674,"RAW_OFF_SHARP":71675,"RAW_ON":71676,"RAW_ON_OUTLINED":71677,"RAW_ON_ROUNDED":71678,"RAW_ON_SHARP":71679,"READ_MORE":71680,"READ_MORE_OUTLINED":71681,"READ_MORE_ROUNDED":71682,"READ_MORE_SHARP":71683,"REAL_ESTATE_AGENT":71684,"REAL_ESTATE_AGENT_OUTLINED":71685,"REAL_ESTATE_AGENT_ROUNDED":71686,"REAL_ESTATE_AGENT_SHARP":71687,"REBASE_EDIT":71688,"RECEIPT":71689,"RECEIPT_LONG":71690,"RECEIPT_LONG_OUTLINED":71691,"RECEIPT_LONG_ROUNDED":71692,"RECEIPT_LONG_SHARP":71693,"RECEIPT_OUTLINED":71694,"RECEIPT_ROUNDED":71695,"RECEIPT_SHARP":71696,"RECENT_ACTORS":71697,"RECENT_ACTORS_OUTLINED":71698,"RECENT_ACTORS_ROUNDED":71699,"RECENT_ACTORS_SHARP":71700,"RECOMMEND":71701,"RECOMMEND_OUTLINED":71702,"RECOMMEND_ROUNDED":71703,"RECOMMEND_SHARP":71704,"RECORD_VOICE_OVER":71705,"RECORD_VOICE_OVER_OUTLINED":71706,"RECORD_VOICE_OVER_ROUNDED":71707,"RECORD_VOICE_OVER_SHARP":71708,"RECTANGLE":71709,"RECTANGLE_OUTLINED":71710,"RECTANGLE_ROUNDED":71711,"RECTANGLE_SHARP":71712,"RECYCLING":71713,"RECYCLING_OUTLINED":71714,"RECYCLING_ROUNDED":71715,"RECYCLING_SHARP":71716,"REDDIT":71717,"REDDIT_OUTLINED":71718,"REDDIT_ROUNDED":71719,"REDDIT_SHARP":71720,"REDEEM":71721,"REDEEM_OUTLINED":71722,"REDEEM_ROUNDED":71723,"REDEEM_SHARP":71724,"REDO":71725,"REDO_OUTLINED":71726,"REDO_ROUNDED":71727,"REDO_SHARP":71728,"REDUCE_CAPACITY":71729,"REDUCE_CAPACITY_OUTLINED":71730,"REDUCE_CAPACITY_ROUNDED":71731,"REDUCE_CAPACITY_SHARP":71732,"REFRESH":71733,"REFRESH_OUTLINED":71734,"REFRESH_ROUNDED":71735,"REFRESH_SHARP":71736,"REMEMBER_ME":71737,"REMEMBER_ME_OUTLINED":71738,"REMEMBER_ME_ROUNDED":71739,"REMEMBER_ME_SHARP":71740,"REMOVE":71741,"REMOVE_CIRCLE":71742,"REMOVE_CIRCLE_OUTLINE":71743,"REMOVE_CIRCLE_OUTLINE_OUTLINED":71744,"REMOVE_CIRCLE_OUTLINE_ROUNDED":71745,"REMOVE_CIRCLE_OUTLINE_SHARP":71746,"REMOVE_CIRCLE_OUTLINED":71747,"REMOVE_CIRCLE_ROUNDED":71748,"REMOVE_CIRCLE_SHARP":71749,"REMOVE_DONE":71750,"REMOVE_DONE_OUTLINED":71751,"REMOVE_DONE_ROUNDED":71752,"REMOVE_DONE_SHARP":71753,"REMOVE_FROM_QUEUE":71754,"REMOVE_FROM_QUEUE_OUTLINED":71755,"REMOVE_FROM_QUEUE_ROUNDED":71756,"REMOVE_FROM_QUEUE_SHARP":71757,"REMOVE_MODERATOR":71758,"REMOVE_MODERATOR_OUTLINED":71759,"REMOVE_MODERATOR_ROUNDED":71760,"REMOVE_MODERATOR_SHARP":71761,"REMOVE_OUTLINED":71762,"REMOVE_RED_EYE":71763,"REMOVE_RED_EYE_OUTLINED":71764,"REMOVE_RED_EYE_ROUNDED":71765,"REMOVE_RED_EYE_SHARP":71766,"REMOVE_ROAD":71767,"REMOVE_ROAD_OUTLINED":71768,"REMOVE_ROAD_ROUNDED":71769,"REMOVE_ROAD_SHARP":71770,"REMOVE_ROUNDED":71771,"REMOVE_SHARP":71772,"REMOVE_SHOPPING_CART":71773,"REMOVE_SHOPPING_CART_OUTLINED":71774,"REMOVE_SHOPPING_CART_ROUNDED":71775,"REMOVE_SHOPPING_CART_SHARP":71776,"REORDER":71777,"REORDER_OUTLINED":71778,"REORDER_ROUNDED":71779,"REORDER_SHARP":71780,"REPARTITION":71781,"REPARTITION_OUTLINED":71782,"REPARTITION_ROUNDED":71783,"REPARTITION_SHARP":71784,"REPEAT":71785,"REPEAT_ON":71786,"REPEAT_ON_OUTLINED":71787,"REPEAT_ON_ROUNDED":71788,"REPEAT_ON_SHARP":71789,"REPEAT_ONE":71790,"REPEAT_ONE_ON":71791,"REPEAT_ONE_ON_OUTLINED":71792,"REPEAT_ONE_ON_ROUNDED":71793,"REPEAT_ONE_ON_SHARP":71794,"REPEAT_ONE_OUTLINED":71795,"REPEAT_ONE_ROUNDED":71796,"REPEAT_ONE_SHARP":71797,"REPEAT_OUTLINED":71798,"REPEAT_ROUNDED":71799,"REPEAT_SHARP":71800,"REPLAY":71801,"REPLAY_10":71802,"REPLAY_10_OUTLINED":71803,"REPLAY_10_ROUNDED":71804,"REPLAY_10_SHARP":71805,"REPLAY_30":71806,"REPLAY_30_OUTLINED":71807,"REPLAY_30_ROUNDED":71808,"REPLAY_30_SHARP":71809,"REPLAY_5":71810,"REPLAY_5_OUTLINED":71811,"REPLAY_5_ROUNDED":71812,"REPLAY_5_SHARP":71813,"REPLAY_CIRCLE_FILLED":71814,"REPLAY_CIRCLE_FILLED_OUTLINED":71815,"REPLAY_CIRCLE_FILLED_ROUNDED":71816,"REPLAY_CIRCLE_FILLED_SHARP":71817,"REPLAY_OUTLINED":71818,"REPLAY_ROUNDED":71819,"REPLAY_SHARP":71820,"REPLY":71821,"REPLY_ALL":71822,"REPLY_ALL_OUTLINED":71823,"REPLY_ALL_ROUNDED":71824,"REPLY_ALL_SHARP":71825,"REPLY_OUTLINED":71826,"REPLY_ROUNDED":71827,"REPLY_SHARP":71828,"REPORT":71829,"REPORT_GMAILERRORRED":71830,"REPORT_GMAILERRORRED_OUTLINED":71831,"REPORT_GMAILERRORRED_ROUNDED":71832,"REPORT_GMAILERRORRED_SHARP":71833,"REPORT_OFF":71834,"REPORT_OFF_OUTLINED":71835,"REPORT_OFF_ROUNDED":71836,"REPORT_OFF_SHARP":71837,"REPORT_OUTLINED":71838,"REPORT_PROBLEM":71839,"REPORT_PROBLEM_OUTLINED":71840,"REPORT_PROBLEM_ROUNDED":71841,"REPORT_PROBLEM_SHARP":71842,"REPORT_ROUNDED":71843,"REPORT_SHARP":71844,"REQUEST_PAGE":71845,"REQUEST_PAGE_OUTLINED":71846,"REQUEST_PAGE_ROUNDED":71847,"REQUEST_PAGE_SHARP":71848,"REQUEST_QUOTE":71849,"REQUEST_QUOTE_OUTLINED":71850,"REQUEST_QUOTE_ROUNDED":71851,"REQUEST_QUOTE_SHARP":71852,"RESET_TV":71853,"RESET_TV_OUTLINED":71854,"RESET_TV_ROUNDED":71855,"RESET_TV_SHARP":71856,"RESTART_ALT":71857,"RESTART_ALT_OUTLINED":71858,"RESTART_ALT_ROUNDED":71859,"RESTART_ALT_SHARP":71860,"RESTAURANT":71861,"RESTAURANT_MENU":71862,"RESTAURANT_MENU_OUTLINED":71863,"RESTAURANT_MENU_ROUNDED":71864,"RESTAURANT_MENU_SHARP":71865,"RESTAURANT_OUTLINED":71866,"RESTAURANT_ROUNDED":71867,"RESTAURANT_SHARP":71868,"RESTORE":71869,"RESTORE_FROM_TRASH":71870,"RESTORE_FROM_TRASH_OUTLINED":71871,"RESTORE_FROM_TRASH_ROUNDED":71872,"RESTORE_FROM_TRASH_SHARP":71873,"RESTORE_OUTLINED":71874,"RESTORE_PAGE":71875,"RESTORE_PAGE_OUTLINED":71876,"RESTORE_PAGE_ROUNDED":71877,"RESTORE_PAGE_SHARP":71878,"RESTORE_ROUNDED":71879,"RESTORE_SHARP":71880,"REVIEWS":71881,"REVIEWS_OUTLINED":71882,"REVIEWS_ROUNDED":71883,"REVIEWS_SHARP":71884,"RICE_BOWL":71885,"RICE_BOWL_OUTLINED":71886,"RICE_BOWL_ROUNDED":71887,"RICE_BOWL_SHARP":71888,"RING_VOLUME":71889,"RING_VOLUME_OUTLINED":71890,"RING_VOLUME_ROUNDED":71891,"RING_VOLUME_SHARP":71892,"ROCKET":71893,"ROCKET_LAUNCH":71894,"ROCKET_LAUNCH_OUTLINED":71895,"ROCKET_LAUNCH_ROUNDED":71896,"ROCKET_LAUNCH_SHARP":71897,"ROCKET_OUTLINED":71898,"ROCKET_ROUNDED":71899,"ROCKET_SHARP":71900,"ROLLER_SHADES":71901,"ROLLER_SHADES_CLOSED":71902,"ROLLER_SHADES_CLOSED_OUTLINED":71903,"ROLLER_SHADES_CLOSED_ROUNDED":71904,"ROLLER_SHADES_CLOSED_SHARP":71905,"ROLLER_SHADES_OUTLINED":71906,"ROLLER_SHADES_ROUNDED":71907,"ROLLER_SHADES_SHARP":71908,"ROLLER_SKATING":71909,"ROLLER_SKATING_OUTLINED":71910,"ROLLER_SKATING_ROUNDED":71911,"ROLLER_SKATING_SHARP":71912,"ROOFING":71913,"ROOFING_OUTLINED":71914,"ROOFING_ROUNDED":71915,"ROOFING_SHARP":71916,"ROOM":71917,"ROOM_OUTLINED":71918,"ROOM_PREFERENCES":71919,"ROOM_PREFERENCES_OUTLINED":71920,"ROOM_PREFERENCES_ROUNDED":71921,"ROOM_PREFERENCES_SHARP":71922,"ROOM_ROUNDED":71923,"ROOM_SERVICE":71924,"ROOM_SERVICE_OUTLINED":71925,"ROOM_SERVICE_ROUNDED":71926,"ROOM_SERVICE_SHARP":71927,"ROOM_SHARP":71928,"ROTATE_90_DEGREES_CCW":71929,"ROTATE_90_DEGREES_CCW_OUTLINED":71930,"ROTATE_90_DEGREES_CCW_ROUNDED":71931,"ROTATE_90_DEGREES_CCW_SHARP":71932,"ROTATE_90_DEGREES_CW":71933,"ROTATE_90_DEGREES_CW_OUTLINED":71934,"ROTATE_90_DEGREES_CW_ROUNDED":71935,"ROTATE_90_DEGREES_CW_SHARP":71936,"ROTATE_LEFT":71937,"ROTATE_LEFT_OUTLINED":71938,"ROTATE_LEFT_ROUNDED":71939,"ROTATE_LEFT_SHARP":71940,"ROTATE_RIGHT":71941,"ROTATE_RIGHT_OUTLINED":71942,"ROTATE_RIGHT_ROUNDED":71943,"ROTATE_RIGHT_SHARP":71944,"ROUNDABOUT_LEFT":71945,"ROUNDABOUT_LEFT_OUTLINED":71946,"ROUNDABOUT_LEFT_ROUNDED":71947,"ROUNDABOUT_LEFT_SHARP":71948,"ROUNDABOUT_RIGHT":71949,"ROUNDABOUT_RIGHT_OUTLINED":71950,"ROUNDABOUT_RIGHT_ROUNDED":71951,"ROUNDABOUT_RIGHT_SHARP":71952,"ROUNDED_CORNER":71953,"ROUNDED_CORNER_OUTLINED":71954,"ROUNDED_CORNER_ROUNDED":71955,"ROUNDED_CORNER_SHARP":71956,"ROUTE":71957,"ROUTE_OUTLINED":71958,"ROUTE_ROUNDED":71959,"ROUTE_SHARP":71960,"ROUTER":71961,"ROUTER_OUTLINED":71962,"ROUTER_ROUNDED":71963,"ROUTER_SHARP":71964,"ROWING":71965,"ROWING_OUTLINED":71966,"ROWING_ROUNDED":71967,"ROWING_SHARP":71968,"RSS_FEED":71969,"RSS_FEED_OUTLINED":71970,"RSS_FEED_ROUNDED":71971,"RSS_FEED_SHARP":71972,"RSVP":71973,"RSVP_OUTLINED":71974,"RSVP_ROUNDED":71975,"RSVP_SHARP":71976,"RTT":71977,"RTT_OUTLINED":71978,"RTT_ROUNDED":71979,"RTT_SHARP":71980,"RULE":71981,"RULE_FOLDER":71982,"RULE_FOLDER_OUTLINED":71983,"RULE_FOLDER_ROUNDED":71984,"RULE_FOLDER_SHARP":71985,"RULE_OUTLINED":71986,"RULE_ROUNDED":71987,"RULE_SHARP":71988,"RUN_CIRCLE":71989,"RUN_CIRCLE_OUTLINED":71990,"RUN_CIRCLE_ROUNDED":71991,"RUN_CIRCLE_SHARP":71992,"RUNNING_WITH_ERRORS":71993,"RUNNING_WITH_ERRORS_OUTLINED":71994,"RUNNING_WITH_ERRORS_ROUNDED":71995,"RUNNING_WITH_ERRORS_SHARP":71996,"RV_HOOKUP":71997,"RV_HOOKUP_OUTLINED":71998,"RV_HOOKUP_ROUNDED":71999,"RV_HOOKUP_SHARP":72000,"SAFETY_CHECK":72001,"SAFETY_CHECK_OUTLINED":72002,"SAFETY_CHECK_ROUNDED":72003,"SAFETY_CHECK_SHARP":72004,"SAFETY_DIVIDER":72005,"SAFETY_DIVIDER_OUTLINED":72006,"SAFETY_DIVIDER_ROUNDED":72007,"SAFETY_DIVIDER_SHARP":72008,"SAILING":72009,"SAILING_OUTLINED":72010,"SAILING_ROUNDED":72011,"SAILING_SHARP":72012,"SANITIZER":72013,"SANITIZER_OUTLINED":72014,"SANITIZER_ROUNDED":72015,"SANITIZER_SHARP":72016,"SATELLITE":72017,"SATELLITE_ALT":72018,"SATELLITE_ALT_OUTLINED":72019,"SATELLITE_ALT_ROUNDED":72020,"SATELLITE_ALT_SHARP":72021,"SATELLITE_OUTLINED":72022,"SATELLITE_ROUNDED":72023,"SATELLITE_SHARP":72024,"SAVE":72025,"SAVE_ALT":72026,"SAVE_ALT_OUTLINED":72027,"SAVE_ALT_ROUNDED":72028,"SAVE_ALT_SHARP":72029,"SAVE_AS":72030,"SAVE_AS_OUTLINED":72031,"SAVE_AS_ROUNDED":72032,"SAVE_AS_SHARP":72033,"SAVE_OUTLINED":72034,"SAVE_ROUNDED":72035,"SAVE_SHARP":72036,"SAVED_SEARCH":72037,"SAVED_SEARCH_OUTLINED":72038,"SAVED_SEARCH_ROUNDED":72039,"SAVED_SEARCH_SHARP":72040,"SAVINGS":72041,"SAVINGS_OUTLINED":72042,"SAVINGS_ROUNDED":72043,"SAVINGS_SHARP":72044,"SCALE":72045,"SCALE_OUTLINED":72046,"SCALE_ROUNDED":72047,"SCALE_SHARP":72048,"SCANNER":72049,"SCANNER_OUTLINED":72050,"SCANNER_ROUNDED":72051,"SCANNER_SHARP":72052,"SCATTER_PLOT":72053,"SCATTER_PLOT_OUTLINED":72054,"SCATTER_PLOT_ROUNDED":72055,"SCATTER_PLOT_SHARP":72056,"SCHEDULE":72057,"SCHEDULE_OUTLINED":72058,"SCHEDULE_ROUNDED":72059,"SCHEDULE_SEND":72060,"SCHEDULE_SEND_OUTLINED":72061,"SCHEDULE_SEND_ROUNDED":72062,"SCHEDULE_SEND_SHARP":72063,"SCHEDULE_SHARP":72064,"SCHEMA":72065,"SCHEMA_OUTLINED":72066,"SCHEMA_ROUNDED":72067,"SCHEMA_SHARP":72068,"SCHOOL":72069,"SCHOOL_OUTLINED":72070,"SCHOOL_ROUNDED":72071,"SCHOOL_SHARP":72072,"SCIENCE":72073,"SCIENCE_OUTLINED":72074,"SCIENCE_ROUNDED":72075,"SCIENCE_SHARP":72076,"SCORE":72077,"SCORE_OUTLINED":72078,"SCORE_ROUNDED":72079,"SCORE_SHARP":72080,"SCOREBOARD":72081,"SCOREBOARD_OUTLINED":72082,"SCOREBOARD_ROUNDED":72083,"SCOREBOARD_SHARP":72084,"SCREEN_LOCK_LANDSCAPE":72085,"SCREEN_LOCK_LANDSCAPE_OUTLINED":72086,"SCREEN_LOCK_LANDSCAPE_ROUNDED":72087,"SCREEN_LOCK_LANDSCAPE_SHARP":72088,"SCREEN_LOCK_PORTRAIT":72089,"SCREEN_LOCK_PORTRAIT_OUTLINED":72090,"SCREEN_LOCK_PORTRAIT_ROUNDED":72091,"SCREEN_LOCK_PORTRAIT_SHARP":72092,"SCREEN_LOCK_ROTATION":72093,"SCREEN_LOCK_ROTATION_OUTLINED":72094,"SCREEN_LOCK_ROTATION_ROUNDED":72095,"SCREEN_LOCK_ROTATION_SHARP":72096,"SCREEN_ROTATION":72097,"SCREEN_ROTATION_ALT":72098,"SCREEN_ROTATION_ALT_OUTLINED":72099,"SCREEN_ROTATION_ALT_ROUNDED":72100,"SCREEN_ROTATION_ALT_SHARP":72101,"SCREEN_ROTATION_OUTLINED":72102,"SCREEN_ROTATION_ROUNDED":72103,"SCREEN_ROTATION_SHARP":72104,"SCREEN_SEARCH_DESKTOP":72105,"SCREEN_SEARCH_DESKTOP_OUTLINED":72106,"SCREEN_SEARCH_DESKTOP_ROUNDED":72107,"SCREEN_SEARCH_DESKTOP_SHARP":72108,"SCREEN_SHARE":72109,"SCREEN_SHARE_OUTLINED":72110,"SCREEN_SHARE_ROUNDED":72111,"SCREEN_SHARE_SHARP":72112,"SCREENSHOT":72113,"SCREENSHOT_MONITOR":72114,"SCREENSHOT_MONITOR_OUTLINED":72115,"SCREENSHOT_MONITOR_ROUNDED":72116,"SCREENSHOT_MONITOR_SHARP":72117,"SCREENSHOT_OUTLINED":72118,"SCREENSHOT_ROUNDED":72119,"SCREENSHOT_SHARP":72120,"SCUBA_DIVING":72121,"SCUBA_DIVING_OUTLINED":72122,"SCUBA_DIVING_ROUNDED":72123,"SCUBA_DIVING_SHARP":72124,"SD":72125,"SD_CARD":72126,"SD_CARD_ALERT":72127,"SD_CARD_ALERT_OUTLINED":72128,"SD_CARD_ALERT_ROUNDED":72129,"SD_CARD_ALERT_SHARP":72130,"SD_CARD_OUTLINED":72131,"SD_CARD_ROUNDED":72132,"SD_CARD_SHARP":72133,"SD_OUTLINED":72134,"SD_ROUNDED":72135,"SD_SHARP":72136,"SD_STORAGE":72137,"SD_STORAGE_OUTLINED":72138,"SD_STORAGE_ROUNDED":72139,"SD_STORAGE_SHARP":72140,"SEARCH":72141,"SEARCH_OFF":72142,"SEARCH_OFF_OUTLINED":72143,"SEARCH_OFF_ROUNDED":72144,"SEARCH_OFF_SHARP":72145,"SEARCH_OUTLINED":72146,"SEARCH_ROUNDED":72147,"SEARCH_SHARP":72148,"SECURITY":72149,"SECURITY_OUTLINED":72150,"SECURITY_ROUNDED":72151,"SECURITY_SHARP":72152,"SECURITY_UPDATE":72153,"SECURITY_UPDATE_GOOD":72154,"SECURITY_UPDATE_GOOD_OUTLINED":72155,"SECURITY_UPDATE_GOOD_ROUNDED":72156,"SECURITY_UPDATE_GOOD_SHARP":72157,"SECURITY_UPDATE_OUTLINED":72158,"SECURITY_UPDATE_ROUNDED":72159,"SECURITY_UPDATE_SHARP":72160,"SECURITY_UPDATE_WARNING":72161,"SECURITY_UPDATE_WARNING_OUTLINED":72162,"SECURITY_UPDATE_WARNING_ROUNDED":72163,"SECURITY_UPDATE_WARNING_SHARP":72164,"SEGMENT":72165,"SEGMENT_OUTLINED":72166,"SEGMENT_ROUNDED":72167,"SEGMENT_SHARP":72168,"SELECT_ALL":72169,"SELECT_ALL_OUTLINED":72170,"SELECT_ALL_ROUNDED":72171,"SELECT_ALL_SHARP":72172,"SELF_IMPROVEMENT":72173,"SELF_IMPROVEMENT_OUTLINED":72174,"SELF_IMPROVEMENT_ROUNDED":72175,"SELF_IMPROVEMENT_SHARP":72176,"SELL":72177,"SELL_OUTLINED":72178,"SELL_ROUNDED":72179,"SELL_SHARP":72180,"SEND":72181,"SEND_AND_ARCHIVE":72182,"SEND_AND_ARCHIVE_OUTLINED":72183,"SEND_AND_ARCHIVE_ROUNDED":72184,"SEND_AND_ARCHIVE_SHARP":72185,"SEND_OUTLINED":72186,"SEND_ROUNDED":72187,"SEND_SHARP":72188,"SEND_TIME_EXTENSION":72189,"SEND_TIME_EXTENSION_OUTLINED":72190,"SEND_TIME_EXTENSION_ROUNDED":72191,"SEND_TIME_EXTENSION_SHARP":72192,"SEND_TO_MOBILE":72193,"SEND_TO_MOBILE_OUTLINED":72194,"SEND_TO_MOBILE_ROUNDED":72195,"SEND_TO_MOBILE_SHARP":72196,"SENSOR_DOOR":72197,"SENSOR_DOOR_OUTLINED":72198,"SENSOR_DOOR_ROUNDED":72199,"SENSOR_DOOR_SHARP":72200,"SENSOR_OCCUPIED":72201,"SENSOR_OCCUPIED_OUTLINED":72202,"SENSOR_OCCUPIED_ROUNDED":72203,"SENSOR_OCCUPIED_SHARP":72204,"SENSOR_WINDOW":72205,"SENSOR_WINDOW_OUTLINED":72206,"SENSOR_WINDOW_ROUNDED":72207,"SENSOR_WINDOW_SHARP":72208,"SENSORS":72209,"SENSORS_OFF":72210,"SENSORS_OFF_OUTLINED":72211,"SENSORS_OFF_ROUNDED":72212,"SENSORS_OFF_SHARP":72213,"SENSORS_OUTLINED":72214,"SENSORS_ROUNDED":72215,"SENSORS_SHARP":72216,"SENTIMENT_DISSATISFIED":72217,"SENTIMENT_DISSATISFIED_OUTLINED":72218,"SENTIMENT_DISSATISFIED_ROUNDED":72219,"SENTIMENT_DISSATISFIED_SHARP":72220,"SENTIMENT_NEUTRAL":72221,"SENTIMENT_NEUTRAL_OUTLINED":72222,"SENTIMENT_NEUTRAL_ROUNDED":72223,"SENTIMENT_NEUTRAL_SHARP":72224,"SENTIMENT_SATISFIED":72225,"SENTIMENT_SATISFIED_ALT":72226,"SENTIMENT_SATISFIED_ALT_OUTLINED":72227,"SENTIMENT_SATISFIED_ALT_ROUNDED":72228,"SENTIMENT_SATISFIED_ALT_SHARP":72229,"SENTIMENT_SATISFIED_OUTLINED":72230,"SENTIMENT_SATISFIED_ROUNDED":72231,"SENTIMENT_SATISFIED_SHARP":72232,"SENTIMENT_VERY_DISSATISFIED":72233,"SENTIMENT_VERY_DISSATISFIED_OUTLINED":72234,"SENTIMENT_VERY_DISSATISFIED_ROUNDED":72235,"SENTIMENT_VERY_DISSATISFIED_SHARP":72236,"SENTIMENT_VERY_SATISFIED":72237,"SENTIMENT_VERY_SATISFIED_OUTLINED":72238,"SENTIMENT_VERY_SATISFIED_ROUNDED":72239,"SENTIMENT_VERY_SATISFIED_SHARP":72240,"SET_MEAL":72241,"SET_MEAL_OUTLINED":72242,"SET_MEAL_ROUNDED":72243,"SET_MEAL_SHARP":72244,"SETTINGS":72245,"SETTINGS_ACCESSIBILITY":72246,"SETTINGS_ACCESSIBILITY_OUTLINED":72247,"SETTINGS_ACCESSIBILITY_ROUNDED":72248,"SETTINGS_ACCESSIBILITY_SHARP":72249,"SETTINGS_APPLICATIONS":72250,"SETTINGS_APPLICATIONS_OUTLINED":72251,"SETTINGS_APPLICATIONS_ROUNDED":72252,"SETTINGS_APPLICATIONS_SHARP":72253,"SETTINGS_BACKUP_RESTORE":72254,"SETTINGS_BACKUP_RESTORE_OUTLINED":72255,"SETTINGS_BACKUP_RESTORE_ROUNDED":72256,"SETTINGS_BACKUP_RESTORE_SHARP":72257,"SETTINGS_BLUETOOTH":72258,"SETTINGS_BLUETOOTH_OUTLINED":72259,"SETTINGS_BLUETOOTH_ROUNDED":72260,"SETTINGS_BLUETOOTH_SHARP":72261,"SETTINGS_BRIGHTNESS":72262,"SETTINGS_BRIGHTNESS_OUTLINED":72263,"SETTINGS_BRIGHTNESS_ROUNDED":72264,"SETTINGS_BRIGHTNESS_SHARP":72265,"SETTINGS_CELL":72266,"SETTINGS_CELL_OUTLINED":72267,"SETTINGS_CELL_ROUNDED":72268,"SETTINGS_CELL_SHARP":72269,"SETTINGS_DISPLAY":72270,"SETTINGS_DISPLAY_OUTLINED":72271,"SETTINGS_DISPLAY_ROUNDED":72272,"SETTINGS_DISPLAY_SHARP":72273,"SETTINGS_ETHERNET":72274,"SETTINGS_ETHERNET_OUTLINED":72275,"SETTINGS_ETHERNET_ROUNDED":72276,"SETTINGS_ETHERNET_SHARP":72277,"SETTINGS_INPUT_ANTENNA":72278,"SETTINGS_INPUT_ANTENNA_OUTLINED":72279,"SETTINGS_INPUT_ANTENNA_ROUNDED":72280,"SETTINGS_INPUT_ANTENNA_SHARP":72281,"SETTINGS_INPUT_COMPONENT":72282,"SETTINGS_INPUT_COMPONENT_OUTLINED":72283,"SETTINGS_INPUT_COMPONENT_ROUNDED":72284,"SETTINGS_INPUT_COMPONENT_SHARP":72285,"SETTINGS_INPUT_COMPOSITE":72286,"SETTINGS_INPUT_COMPOSITE_OUTLINED":72287,"SETTINGS_INPUT_COMPOSITE_ROUNDED":72288,"SETTINGS_INPUT_COMPOSITE_SHARP":72289,"SETTINGS_INPUT_HDMI":72290,"SETTINGS_INPUT_HDMI_OUTLINED":72291,"SETTINGS_INPUT_HDMI_ROUNDED":72292,"SETTINGS_INPUT_HDMI_SHARP":72293,"SETTINGS_INPUT_SVIDEO":72294,"SETTINGS_INPUT_SVIDEO_OUTLINED":72295,"SETTINGS_INPUT_SVIDEO_ROUNDED":72296,"SETTINGS_INPUT_SVIDEO_SHARP":72297,"SETTINGS_OUTLINED":72298,"SETTINGS_OVERSCAN":72299,"SETTINGS_OVERSCAN_OUTLINED":72300,"SETTINGS_OVERSCAN_ROUNDED":72301,"SETTINGS_OVERSCAN_SHARP":72302,"SETTINGS_PHONE":72303,"SETTINGS_PHONE_OUTLINED":72304,"SETTINGS_PHONE_ROUNDED":72305,"SETTINGS_PHONE_SHARP":72306,"SETTINGS_POWER":72307,"SETTINGS_POWER_OUTLINED":72308,"SETTINGS_POWER_ROUNDED":72309,"SETTINGS_POWER_SHARP":72310,"SETTINGS_REMOTE":72311,"SETTINGS_REMOTE_OUTLINED":72312,"SETTINGS_REMOTE_ROUNDED":72313,"SETTINGS_REMOTE_SHARP":72314,"SETTINGS_ROUNDED":72315,"SETTINGS_SHARP":72316,"SETTINGS_SUGGEST":72317,"SETTINGS_SUGGEST_OUTLINED":72318,"SETTINGS_SUGGEST_ROUNDED":72319,"SETTINGS_SUGGEST_SHARP":72320,"SETTINGS_SYSTEM_DAYDREAM":72321,"SETTINGS_SYSTEM_DAYDREAM_OUTLINED":72322,"SETTINGS_SYSTEM_DAYDREAM_ROUNDED":72323,"SETTINGS_SYSTEM_DAYDREAM_SHARP":72324,"SETTINGS_VOICE":72325,"SETTINGS_VOICE_OUTLINED":72326,"SETTINGS_VOICE_ROUNDED":72327,"SETTINGS_VOICE_SHARP":72328,"SEVEN_K":72329,"SEVEN_K_OUTLINED":72330,"SEVEN_K_PLUS":72331,"SEVEN_K_PLUS_OUTLINED":72332,"SEVEN_K_PLUS_ROUNDED":72333,"SEVEN_K_PLUS_SHARP":72334,"SEVEN_K_ROUNDED":72335,"SEVEN_K_SHARP":72336,"SEVEN_MP":72337,"SEVEN_MP_OUTLINED":72338,"SEVEN_MP_ROUNDED":72339,"SEVEN_MP_SHARP":72340,"SEVENTEEN_MP":72341,"SEVENTEEN_MP_OUTLINED":72342,"SEVENTEEN_MP_ROUNDED":72343,"SEVENTEEN_MP_SHARP":72344,"SEVERE_COLD":72345,"SEVERE_COLD_OUTLINED":72346,"SEVERE_COLD_ROUNDED":72347,"SEVERE_COLD_SHARP":72348,"SHAPE_LINE":72349,"SHAPE_LINE_OUTLINED":72350,"SHAPE_LINE_ROUNDED":72351,"SHAPE_LINE_SHARP":72352,"SHARE":72353,"SHARE_ARRIVAL_TIME":72354,"SHARE_ARRIVAL_TIME_OUTLINED":72355,"SHARE_ARRIVAL_TIME_ROUNDED":72356,"SHARE_ARRIVAL_TIME_SHARP":72357,"SHARE_LOCATION":72358,"SHARE_LOCATION_OUTLINED":72359,"SHARE_LOCATION_ROUNDED":72360,"SHARE_LOCATION_SHARP":72361,"SHARE_OUTLINED":72362,"SHARE_ROUNDED":72363,"SHARE_SHARP":72364,"SHELVES":72365,"SHIELD":72366,"SHIELD_MOON":72367,"SHIELD_MOON_OUTLINED":72368,"SHIELD_MOON_ROUNDED":72369,"SHIELD_MOON_SHARP":72370,"SHIELD_OUTLINED":72371,"SHIELD_ROUNDED":72372,"SHIELD_SHARP":72373,"SHOP":72374,"SHOP_2":72375,"SHOP_2_OUTLINED":72376,"SHOP_2_ROUNDED":72377,"SHOP_2_SHARP":72378,"SHOP_OUTLINED":72379,"SHOP_ROUNDED":72380,"SHOP_SHARP":72381,"SHOP_TWO":72382,"SHOP_TWO_OUTLINED":72383,"SHOP_TWO_ROUNDED":72384,"SHOP_TWO_SHARP":72385,"SHOPIFY":72386,"SHOPIFY_OUTLINED":72387,"SHOPIFY_ROUNDED":72388,"SHOPIFY_SHARP":72389,"SHOPPING_BAG":72390,"SHOPPING_BAG_OUTLINED":72391,"SHOPPING_BAG_ROUNDED":72392,"SHOPPING_BAG_SHARP":72393,"SHOPPING_BASKET":72394,"SHOPPING_BASKET_OUTLINED":72395,"SHOPPING_BASKET_ROUNDED":72396,"SHOPPING_BASKET_SHARP":72397,"SHOPPING_CART":72398,"SHOPPING_CART_CHECKOUT":72399,"SHOPPING_CART_CHECKOUT_OUTLINED":72400,"SHOPPING_CART_CHECKOUT_ROUNDED":72401,"SHOPPING_CART_CHECKOUT_SHARP":72402,"SHOPPING_CART_OUTLINED":72403,"SHOPPING_CART_ROUNDED":72404,"SHOPPING_CART_SHARP":72405,"SHORT_TEXT":72406,"SHORT_TEXT_OUTLINED":72407,"SHORT_TEXT_ROUNDED":72408,"SHORT_TEXT_SHARP":72409,"SHORTCUT":72410,"SHORTCUT_OUTLINED":72411,"SHORTCUT_ROUNDED":72412,"SHORTCUT_SHARP":72413,"SHOW_CHART":72414,"SHOW_CHART_OUTLINED":72415,"SHOW_CHART_ROUNDED":72416,"SHOW_CHART_SHARP":72417,"SHOWER":72418,"SHOWER_OUTLINED":72419,"SHOWER_ROUNDED":72420,"SHOWER_SHARP":72421,"SHUFFLE":72422,"SHUFFLE_ON":72423,"SHUFFLE_ON_OUTLINED":72424,"SHUFFLE_ON_ROUNDED":72425,"SHUFFLE_ON_SHARP":72426,"SHUFFLE_OUTLINED":72427,"SHUFFLE_ROUNDED":72428,"SHUFFLE_SHARP":72429,"SHUTTER_SPEED":72430,"SHUTTER_SPEED_OUTLINED":72431,"SHUTTER_SPEED_ROUNDED":72432,"SHUTTER_SPEED_SHARP":72433,"SICK":72434,"SICK_OUTLINED":72435,"SICK_ROUNDED":72436,"SICK_SHARP":72437,"SIGN_LANGUAGE":72438,"SIGN_LANGUAGE_OUTLINED":72439,"SIGN_LANGUAGE_ROUNDED":72440,"SIGN_LANGUAGE_SHARP":72441,"SIGNAL_CELLULAR_0_BAR":72442,"SIGNAL_CELLULAR_0_BAR_OUTLINED":72443,"SIGNAL_CELLULAR_0_BAR_ROUNDED":72444,"SIGNAL_CELLULAR_0_BAR_SHARP":72445,"SIGNAL_CELLULAR_4_BAR":72446,"SIGNAL_CELLULAR_4_BAR_OUTLINED":72447,"SIGNAL_CELLULAR_4_BAR_ROUNDED":72448,"SIGNAL_CELLULAR_4_BAR_SHARP":72449,"SIGNAL_CELLULAR_ALT":72450,"SIGNAL_CELLULAR_ALT_1_BAR":72451,"SIGNAL_CELLULAR_ALT_1_BAR_OUTLINED":72452,"SIGNAL_CELLULAR_ALT_1_BAR_ROUNDED":72453,"SIGNAL_CELLULAR_ALT_1_BAR_SHARP":72454,"SIGNAL_CELLULAR_ALT_2_BAR":72455,"SIGNAL_CELLULAR_ALT_2_BAR_OUTLINED":72456,"SIGNAL_CELLULAR_ALT_2_BAR_ROUNDED":72457,"SIGNAL_CELLULAR_ALT_2_BAR_SHARP":72458,"SIGNAL_CELLULAR_ALT_OUTLINED":72459,"SIGNAL_CELLULAR_ALT_ROUNDED":72460,"SIGNAL_CELLULAR_ALT_SHARP":72461,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR":72462,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_OUTLINED":72463,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_ROUNDED":72464,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_SHARP":72465,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR":72466,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_OUTLINED":72467,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_ROUNDED":72468,"SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_SHARP":72469,"SIGNAL_CELLULAR_NO_SIM":72470,"SIGNAL_CELLULAR_NO_SIM_OUTLINED":72471,"SIGNAL_CELLULAR_NO_SIM_ROUNDED":72472,"SIGNAL_CELLULAR_NO_SIM_SHARP":72473,"SIGNAL_CELLULAR_NODATA":72474,"SIGNAL_CELLULAR_NODATA_OUTLINED":72475,"SIGNAL_CELLULAR_NODATA_ROUNDED":72476,"SIGNAL_CELLULAR_NODATA_SHARP":72477,"SIGNAL_CELLULAR_NULL":72478,"SIGNAL_CELLULAR_NULL_OUTLINED":72479,"SIGNAL_CELLULAR_NULL_ROUNDED":72480,"SIGNAL_CELLULAR_NULL_SHARP":72481,"SIGNAL_CELLULAR_OFF":72482,"SIGNAL_CELLULAR_OFF_OUTLINED":72483,"SIGNAL_CELLULAR_OFF_ROUNDED":72484,"SIGNAL_CELLULAR_OFF_SHARP":72485,"SIGNAL_WIFI_0_BAR":72486,"SIGNAL_WIFI_0_BAR_OUTLINED":72487,"SIGNAL_WIFI_0_BAR_ROUNDED":72488,"SIGNAL_WIFI_0_BAR_SHARP":72489,"SIGNAL_WIFI_4_BAR":72490,"SIGNAL_WIFI_4_BAR_LOCK":72491,"SIGNAL_WIFI_4_BAR_LOCK_OUTLINED":72492,"SIGNAL_WIFI_4_BAR_LOCK_ROUNDED":72493,"SIGNAL_WIFI_4_BAR_LOCK_SHARP":72494,"SIGNAL_WIFI_4_BAR_OUTLINED":72495,"SIGNAL_WIFI_4_BAR_ROUNDED":72496,"SIGNAL_WIFI_4_BAR_SHARP":72497,"SIGNAL_WIFI_BAD":72498,"SIGNAL_WIFI_BAD_OUTLINED":72499,"SIGNAL_WIFI_BAD_ROUNDED":72500,"SIGNAL_WIFI_BAD_SHARP":72501,"SIGNAL_WIFI_CONNECTED_NO_INTERNET_4":72502,"SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_OUTLINED":72503,"SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_ROUNDED":72504,"SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_SHARP":72505,"SIGNAL_WIFI_OFF":72506,"SIGNAL_WIFI_OFF_OUTLINED":72507,"SIGNAL_WIFI_OFF_ROUNDED":72508,"SIGNAL_WIFI_OFF_SHARP":72509,"SIGNAL_WIFI_STATUSBAR_4_BAR":72510,"SIGNAL_WIFI_STATUSBAR_4_BAR_OUTLINED":72511,"SIGNAL_WIFI_STATUSBAR_4_BAR_ROUNDED":72512,"SIGNAL_WIFI_STATUSBAR_4_BAR_SHARP":72513,"SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4":72514,"SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_OUTLINED":72515,"SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_ROUNDED":72516,"SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_SHARP":72517,"SIGNAL_WIFI_STATUSBAR_NULL":72518,"SIGNAL_WIFI_STATUSBAR_NULL_OUTLINED":72519,"SIGNAL_WIFI_STATUSBAR_NULL_ROUNDED":72520,"SIGNAL_WIFI_STATUSBAR_NULL_SHARP":72521,"SIGNPOST":72522,"SIGNPOST_OUTLINED":72523,"SIGNPOST_ROUNDED":72524,"SIGNPOST_SHARP":72525,"SIM_CARD":72526,"SIM_CARD_ALERT":72527,"SIM_CARD_ALERT_OUTLINED":72528,"SIM_CARD_ALERT_ROUNDED":72529,"SIM_CARD_ALERT_SHARP":72530,"SIM_CARD_DOWNLOAD":72531,"SIM_CARD_DOWNLOAD_OUTLINED":72532,"SIM_CARD_DOWNLOAD_ROUNDED":72533,"SIM_CARD_DOWNLOAD_SHARP":72534,"SIM_CARD_OUTLINED":72535,"SIM_CARD_ROUNDED":72536,"SIM_CARD_SHARP":72537,"SINGLE_BED":72538,"SINGLE_BED_OUTLINED":72539,"SINGLE_BED_ROUNDED":72540,"SINGLE_BED_SHARP":72541,"SIP":72542,"SIP_OUTLINED":72543,"SIP_ROUNDED":72544,"SIP_SHARP":72545,"SIX_FT_APART":72546,"SIX_FT_APART_OUTLINED":72547,"SIX_FT_APART_ROUNDED":72548,"SIX_FT_APART_SHARP":72549,"SIX_K":72550,"SIX_K_OUTLINED":72551,"SIX_K_PLUS":72552,"SIX_K_PLUS_OUTLINED":72553,"SIX_K_PLUS_ROUNDED":72554,"SIX_K_PLUS_SHARP":72555,"SIX_K_ROUNDED":72556,"SIX_K_SHARP":72557,"SIX_MP":72558,"SIX_MP_OUTLINED":72559,"SIX_MP_ROUNDED":72560,"SIX_MP_SHARP":72561,"SIXTEEN_MP":72562,"SIXTEEN_MP_OUTLINED":72563,"SIXTEEN_MP_ROUNDED":72564,"SIXTEEN_MP_SHARP":72565,"SIXTY_FPS":72566,"SIXTY_FPS_OUTLINED":72567,"SIXTY_FPS_ROUNDED":72568,"SIXTY_FPS_SELECT":72569,"SIXTY_FPS_SELECT_OUTLINED":72570,"SIXTY_FPS_SELECT_ROUNDED":72571,"SIXTY_FPS_SELECT_SHARP":72572,"SIXTY_FPS_SHARP":72573,"SKATEBOARDING":72574,"SKATEBOARDING_OUTLINED":72575,"SKATEBOARDING_ROUNDED":72576,"SKATEBOARDING_SHARP":72577,"SKIP_NEXT":72578,"SKIP_NEXT_OUTLINED":72579,"SKIP_NEXT_ROUNDED":72580,"SKIP_NEXT_SHARP":72581,"SKIP_PREVIOUS":72582,"SKIP_PREVIOUS_OUTLINED":72583,"SKIP_PREVIOUS_ROUNDED":72584,"SKIP_PREVIOUS_SHARP":72585,"SLEDDING":72586,"SLEDDING_OUTLINED":72587,"SLEDDING_ROUNDED":72588,"SLEDDING_SHARP":72589,"SLIDESHOW":72590,"SLIDESHOW_OUTLINED":72591,"SLIDESHOW_ROUNDED":72592,"SLIDESHOW_SHARP":72593,"SLOW_MOTION_VIDEO":72594,"SLOW_MOTION_VIDEO_OUTLINED":72595,"SLOW_MOTION_VIDEO_ROUNDED":72596,"SLOW_MOTION_VIDEO_SHARP":72597,"SMART_BUTTON":72598,"SMART_BUTTON_OUTLINED":72599,"SMART_BUTTON_ROUNDED":72600,"SMART_BUTTON_SHARP":72601,"SMART_DISPLAY":72602,"SMART_DISPLAY_OUTLINED":72603,"SMART_DISPLAY_ROUNDED":72604,"SMART_DISPLAY_SHARP":72605,"SMART_SCREEN":72606,"SMART_SCREEN_OUTLINED":72607,"SMART_SCREEN_ROUNDED":72608,"SMART_SCREEN_SHARP":72609,"SMART_TOY":72610,"SMART_TOY_OUTLINED":72611,"SMART_TOY_ROUNDED":72612,"SMART_TOY_SHARP":72613,"SMARTPHONE":72614,"SMARTPHONE_OUTLINED":72615,"SMARTPHONE_ROUNDED":72616,"SMARTPHONE_SHARP":72617,"SMOKE_FREE":72618,"SMOKE_FREE_OUTLINED":72619,"SMOKE_FREE_ROUNDED":72620,"SMOKE_FREE_SHARP":72621,"SMOKING_ROOMS":72622,"SMOKING_ROOMS_OUTLINED":72623,"SMOKING_ROOMS_ROUNDED":72624,"SMOKING_ROOMS_SHARP":72625,"SMS":72626,"SMS_FAILED":72627,"SMS_FAILED_OUTLINED":72628,"SMS_FAILED_ROUNDED":72629,"SMS_FAILED_SHARP":72630,"SMS_OUTLINED":72631,"SMS_ROUNDED":72632,"SMS_SHARP":72633,"SNAPCHAT":72634,"SNAPCHAT_OUTLINED":72635,"SNAPCHAT_ROUNDED":72636,"SNAPCHAT_SHARP":72637,"SNIPPET_FOLDER":72638,"SNIPPET_FOLDER_OUTLINED":72639,"SNIPPET_FOLDER_ROUNDED":72640,"SNIPPET_FOLDER_SHARP":72641,"SNOOZE":72642,"SNOOZE_OUTLINED":72643,"SNOOZE_ROUNDED":72644,"SNOOZE_SHARP":72645,"SNOWBOARDING":72646,"SNOWBOARDING_OUTLINED":72647,"SNOWBOARDING_ROUNDED":72648,"SNOWBOARDING_SHARP":72649,"SNOWING":72650,"SNOWMOBILE":72651,"SNOWMOBILE_OUTLINED":72652,"SNOWMOBILE_ROUNDED":72653,"SNOWMOBILE_SHARP":72654,"SNOWSHOEING":72655,"SNOWSHOEING_OUTLINED":72656,"SNOWSHOEING_ROUNDED":72657,"SNOWSHOEING_SHARP":72658,"SOAP":72659,"SOAP_OUTLINED":72660,"SOAP_ROUNDED":72661,"SOAP_SHARP":72662,"SOCIAL_DISTANCE":72663,"SOCIAL_DISTANCE_OUTLINED":72664,"SOCIAL_DISTANCE_ROUNDED":72665,"SOCIAL_DISTANCE_SHARP":72666,"SOLAR_POWER":72667,"SOLAR_POWER_OUTLINED":72668,"SOLAR_POWER_ROUNDED":72669,"SOLAR_POWER_SHARP":72670,"SORT":72671,"SORT_BY_ALPHA":72672,"SORT_BY_ALPHA_OUTLINED":72673,"SORT_BY_ALPHA_ROUNDED":72674,"SORT_BY_ALPHA_SHARP":72675,"SORT_OUTLINED":72676,"SORT_ROUNDED":72677,"SORT_SHARP":72678,"SOS":72679,"SOS_OUTLINED":72680,"SOS_ROUNDED":72681,"SOS_SHARP":72682,"SOUP_KITCHEN":72683,"SOUP_KITCHEN_OUTLINED":72684,"SOUP_KITCHEN_ROUNDED":72685,"SOUP_KITCHEN_SHARP":72686,"SOURCE":72687,"SOURCE_OUTLINED":72688,"SOURCE_ROUNDED":72689,"SOURCE_SHARP":72690,"SOUTH":72691,"SOUTH_AMERICA":72692,"SOUTH_AMERICA_OUTLINED":72693,"SOUTH_AMERICA_ROUNDED":72694,"SOUTH_AMERICA_SHARP":72695,"SOUTH_EAST":72696,"SOUTH_EAST_OUTLINED":72697,"SOUTH_EAST_ROUNDED":72698,"SOUTH_EAST_SHARP":72699,"SOUTH_OUTLINED":72700,"SOUTH_ROUNDED":72701,"SOUTH_SHARP":72702,"SOUTH_WEST":72703,"SOUTH_WEST_OUTLINED":72704,"SOUTH_WEST_ROUNDED":72705,"SOUTH_WEST_SHARP":72706,"SPA":72707,"SPA_OUTLINED":72708,"SPA_ROUNDED":72709,"SPA_SHARP":72710,"SPACE_BAR":72711,"SPACE_BAR_OUTLINED":72712,"SPACE_BAR_ROUNDED":72713,"SPACE_BAR_SHARP":72714,"SPACE_DASHBOARD":72715,"SPACE_DASHBOARD_OUTLINED":72716,"SPACE_DASHBOARD_ROUNDED":72717,"SPACE_DASHBOARD_SHARP":72718,"SPATIAL_AUDIO":72719,"SPATIAL_AUDIO_OFF":72720,"SPATIAL_AUDIO_OFF_OUTLINED":72721,"SPATIAL_AUDIO_OFF_ROUNDED":72722,"SPATIAL_AUDIO_OFF_SHARP":72723,"SPATIAL_AUDIO_OUTLINED":72724,"SPATIAL_AUDIO_ROUNDED":72725,"SPATIAL_AUDIO_SHARP":72726,"SPATIAL_TRACKING":72727,"SPATIAL_TRACKING_OUTLINED":72728,"SPATIAL_TRACKING_ROUNDED":72729,"SPATIAL_TRACKING_SHARP":72730,"SPEAKER":72731,"SPEAKER_GROUP":72732,"SPEAKER_GROUP_OUTLINED":72733,"SPEAKER_GROUP_ROUNDED":72734,"SPEAKER_GROUP_SHARP":72735,"SPEAKER_NOTES":72736,"SPEAKER_NOTES_OFF":72737,"SPEAKER_NOTES_OFF_OUTLINED":72738,"SPEAKER_NOTES_OFF_ROUNDED":72739,"SPEAKER_NOTES_OFF_SHARP":72740,"SPEAKER_NOTES_OUTLINED":72741,"SPEAKER_NOTES_ROUNDED":72742,"SPEAKER_NOTES_SHARP":72743,"SPEAKER_OUTLINED":72744,"SPEAKER_PHONE":72745,"SPEAKER_PHONE_OUTLINED":72746,"SPEAKER_PHONE_ROUNDED":72747,"SPEAKER_PHONE_SHARP":72748,"SPEAKER_ROUNDED":72749,"SPEAKER_SHARP":72750,"SPEED":72751,"SPEED_OUTLINED":72752,"SPEED_ROUNDED":72753,"SPEED_SHARP":72754,"SPELLCHECK":72755,"SPELLCHECK_OUTLINED":72756,"SPELLCHECK_ROUNDED":72757,"SPELLCHECK_SHARP":72758,"SPLITSCREEN":72759,"SPLITSCREEN_OUTLINED":72760,"SPLITSCREEN_ROUNDED":72761,"SPLITSCREEN_SHARP":72762,"SPOKE":72763,"SPOKE_OUTLINED":72764,"SPOKE_ROUNDED":72765,"SPOKE_SHARP":72766,"SPORTS":72767,"SPORTS_BAR":72768,"SPORTS_BAR_OUTLINED":72769,"SPORTS_BAR_ROUNDED":72770,"SPORTS_BAR_SHARP":72771,"SPORTS_BASEBALL":72772,"SPORTS_BASEBALL_OUTLINED":72773,"SPORTS_BASEBALL_ROUNDED":72774,"SPORTS_BASEBALL_SHARP":72775,"SPORTS_BASKETBALL":72776,"SPORTS_BASKETBALL_OUTLINED":72777,"SPORTS_BASKETBALL_ROUNDED":72778,"SPORTS_BASKETBALL_SHARP":72779,"SPORTS_CRICKET":72780,"SPORTS_CRICKET_OUTLINED":72781,"SPORTS_CRICKET_ROUNDED":72782,"SPORTS_CRICKET_SHARP":72783,"SPORTS_ESPORTS":72784,"SPORTS_ESPORTS_OUTLINED":72785,"SPORTS_ESPORTS_ROUNDED":72786,"SPORTS_ESPORTS_SHARP":72787,"SPORTS_FOOTBALL":72788,"SPORTS_FOOTBALL_OUTLINED":72789,"SPORTS_FOOTBALL_ROUNDED":72790,"SPORTS_FOOTBALL_SHARP":72791,"SPORTS_GOLF":72792,"SPORTS_GOLF_OUTLINED":72793,"SPORTS_GOLF_ROUNDED":72794,"SPORTS_GOLF_SHARP":72795,"SPORTS_GYMNASTICS":72796,"SPORTS_GYMNASTICS_OUTLINED":72797,"SPORTS_GYMNASTICS_ROUNDED":72798,"SPORTS_GYMNASTICS_SHARP":72799,"SPORTS_HANDBALL":72800,"SPORTS_HANDBALL_OUTLINED":72801,"SPORTS_HANDBALL_ROUNDED":72802,"SPORTS_HANDBALL_SHARP":72803,"SPORTS_HOCKEY":72804,"SPORTS_HOCKEY_OUTLINED":72805,"SPORTS_HOCKEY_ROUNDED":72806,"SPORTS_HOCKEY_SHARP":72807,"SPORTS_KABADDI":72808,"SPORTS_KABADDI_OUTLINED":72809,"SPORTS_KABADDI_ROUNDED":72810,"SPORTS_KABADDI_SHARP":72811,"SPORTS_MARTIAL_ARTS":72812,"SPORTS_MARTIAL_ARTS_OUTLINED":72813,"SPORTS_MARTIAL_ARTS_ROUNDED":72814,"SPORTS_MARTIAL_ARTS_SHARP":72815,"SPORTS_MMA":72816,"SPORTS_MMA_OUTLINED":72817,"SPORTS_MMA_ROUNDED":72818,"SPORTS_MMA_SHARP":72819,"SPORTS_MOTORSPORTS":72820,"SPORTS_MOTORSPORTS_OUTLINED":72821,"SPORTS_MOTORSPORTS_ROUNDED":72822,"SPORTS_MOTORSPORTS_SHARP":72823,"SPORTS_OUTLINED":72824,"SPORTS_ROUNDED":72825,"SPORTS_RUGBY":72826,"SPORTS_RUGBY_OUTLINED":72827,"SPORTS_RUGBY_ROUNDED":72828,"SPORTS_RUGBY_SHARP":72829,"SPORTS_SCORE":72830,"SPORTS_SCORE_OUTLINED":72831,"SPORTS_SCORE_ROUNDED":72832,"SPORTS_SCORE_SHARP":72833,"SPORTS_SHARP":72834,"SPORTS_SOCCER":72835,"SPORTS_SOCCER_OUTLINED":72836,"SPORTS_SOCCER_ROUNDED":72837,"SPORTS_SOCCER_SHARP":72838,"SPORTS_TENNIS":72839,"SPORTS_TENNIS_OUTLINED":72840,"SPORTS_TENNIS_ROUNDED":72841,"SPORTS_TENNIS_SHARP":72842,"SPORTS_VOLLEYBALL":72843,"SPORTS_VOLLEYBALL_OUTLINED":72844,"SPORTS_VOLLEYBALL_ROUNDED":72845,"SPORTS_VOLLEYBALL_SHARP":72846,"SQUARE":72847,"SQUARE_FOOT":72848,"SQUARE_FOOT_OUTLINED":72849,"SQUARE_FOOT_ROUNDED":72850,"SQUARE_FOOT_SHARP":72851,"SQUARE_OUTLINED":72852,"SQUARE_ROUNDED":72853,"SQUARE_SHARP":72854,"SSID_CHART":72855,"SSID_CHART_OUTLINED":72856,"SSID_CHART_ROUNDED":72857,"SSID_CHART_SHARP":72858,"STACKED_BAR_CHART":72859,"STACKED_BAR_CHART_OUTLINED":72860,"STACKED_BAR_CHART_ROUNDED":72861,"STACKED_BAR_CHART_SHARP":72862,"STACKED_LINE_CHART":72863,"STACKED_LINE_CHART_OUTLINED":72864,"STACKED_LINE_CHART_ROUNDED":72865,"STACKED_LINE_CHART_SHARP":72866,"STADIUM":72867,"STADIUM_OUTLINED":72868,"STADIUM_ROUNDED":72869,"STADIUM_SHARP":72870,"STAIRS":72871,"STAIRS_OUTLINED":72872,"STAIRS_ROUNDED":72873,"STAIRS_SHARP":72874,"STAR":72875,"STAR_BORDER":72876,"STAR_BORDER_OUTLINED":72877,"STAR_BORDER_PURPLE500":72878,"STAR_BORDER_PURPLE500_OUTLINED":72879,"STAR_BORDER_PURPLE500_ROUNDED":72880,"STAR_BORDER_PURPLE500_SHARP":72881,"STAR_BORDER_ROUNDED":72882,"STAR_BORDER_SHARP":72883,"STAR_HALF":72884,"STAR_HALF_OUTLINED":72885,"STAR_HALF_ROUNDED":72886,"STAR_HALF_SHARP":72887,"STAR_OUTLINE":72888,"STAR_OUTLINE_OUTLINED":72889,"STAR_OUTLINE_ROUNDED":72890,"STAR_OUTLINE_SHARP":72891,"STAR_OUTLINED":72892,"STAR_PURPLE500":72893,"STAR_PURPLE500_OUTLINED":72894,"STAR_PURPLE500_ROUNDED":72895,"STAR_PURPLE500_SHARP":72896,"STAR_RATE":72897,"STAR_RATE_OUTLINED":72898,"STAR_RATE_ROUNDED":72899,"STAR_RATE_SHARP":72900,"STAR_ROUNDED":72901,"STAR_SHARP":72902,"STARS":72903,"STARS_OUTLINED":72904,"STARS_ROUNDED":72905,"STARS_SHARP":72906,"START":72907,"START_OUTLINED":72908,"START_ROUNDED":72909,"START_SHARP":72910,"STAY_CURRENT_LANDSCAPE":72911,"STAY_CURRENT_LANDSCAPE_OUTLINED":72912,"STAY_CURRENT_LANDSCAPE_ROUNDED":72913,"STAY_CURRENT_LANDSCAPE_SHARP":72914,"STAY_CURRENT_PORTRAIT":72915,"STAY_CURRENT_PORTRAIT_OUTLINED":72916,"STAY_CURRENT_PORTRAIT_ROUNDED":72917,"STAY_CURRENT_PORTRAIT_SHARP":72918,"STAY_PRIMARY_LANDSCAPE":72919,"STAY_PRIMARY_LANDSCAPE_OUTLINED":72920,"STAY_PRIMARY_LANDSCAPE_ROUNDED":72921,"STAY_PRIMARY_LANDSCAPE_SHARP":72922,"STAY_PRIMARY_PORTRAIT":72923,"STAY_PRIMARY_PORTRAIT_OUTLINED":72924,"STAY_PRIMARY_PORTRAIT_ROUNDED":72925,"STAY_PRIMARY_PORTRAIT_SHARP":72926,"STICKY_NOTE_2":72927,"STICKY_NOTE_2_OUTLINED":72928,"STICKY_NOTE_2_ROUNDED":72929,"STICKY_NOTE_2_SHARP":72930,"STOP":72931,"STOP_CIRCLE":72932,"STOP_CIRCLE_OUTLINED":72933,"STOP_CIRCLE_ROUNDED":72934,"STOP_CIRCLE_SHARP":72935,"STOP_OUTLINED":72936,"STOP_ROUNDED":72937,"STOP_SCREEN_SHARE":72938,"STOP_SCREEN_SHARE_OUTLINED":72939,"STOP_SCREEN_SHARE_ROUNDED":72940,"STOP_SCREEN_SHARE_SHARP":72941,"STOP_SHARP":72942,"STORAGE":72943,"STORAGE_OUTLINED":72944,"STORAGE_ROUNDED":72945,"STORAGE_SHARP":72946,"STORE":72947,"STORE_MALL_DIRECTORY":72948,"STORE_MALL_DIRECTORY_OUTLINED":72949,"STORE_MALL_DIRECTORY_ROUNDED":72950,"STORE_MALL_DIRECTORY_SHARP":72951,"STORE_OUTLINED":72952,"STORE_ROUNDED":72953,"STORE_SHARP":72954,"STOREFRONT":72955,"STOREFRONT_OUTLINED":72956,"STOREFRONT_ROUNDED":72957,"STOREFRONT_SHARP":72958,"STORM":72959,"STORM_OUTLINED":72960,"STORM_ROUNDED":72961,"STORM_SHARP":72962,"STRAIGHT":72963,"STRAIGHT_OUTLINED":72964,"STRAIGHT_ROUNDED":72965,"STRAIGHT_SHARP":72966,"STRAIGHTEN":72967,"STRAIGHTEN_OUTLINED":72968,"STRAIGHTEN_ROUNDED":72969,"STRAIGHTEN_SHARP":72970,"STREAM":72971,"STREAM_OUTLINED":72972,"STREAM_ROUNDED":72973,"STREAM_SHARP":72974,"STREETVIEW":72975,"STREETVIEW_OUTLINED":72976,"STREETVIEW_ROUNDED":72977,"STREETVIEW_SHARP":72978,"STRIKETHROUGH_S":72979,"STRIKETHROUGH_S_OUTLINED":72980,"STRIKETHROUGH_S_ROUNDED":72981,"STRIKETHROUGH_S_SHARP":72982,"STROLLER":72983,"STROLLER_OUTLINED":72984,"STROLLER_ROUNDED":72985,"STROLLER_SHARP":72986,"STYLE":72987,"STYLE_OUTLINED":72988,"STYLE_ROUNDED":72989,"STYLE_SHARP":72990,"SUBDIRECTORY_ARROW_LEFT":72991,"SUBDIRECTORY_ARROW_LEFT_OUTLINED":72992,"SUBDIRECTORY_ARROW_LEFT_ROUNDED":72993,"SUBDIRECTORY_ARROW_LEFT_SHARP":72994,"SUBDIRECTORY_ARROW_RIGHT":72995,"SUBDIRECTORY_ARROW_RIGHT_OUTLINED":72996,"SUBDIRECTORY_ARROW_RIGHT_ROUNDED":72997,"SUBDIRECTORY_ARROW_RIGHT_SHARP":72998,"SUBJECT":72999,"SUBJECT_OUTLINED":73000,"SUBJECT_ROUNDED":73001,"SUBJECT_SHARP":73002,"SUBSCRIPT":73003,"SUBSCRIPT_OUTLINED":73004,"SUBSCRIPT_ROUNDED":73005,"SUBSCRIPT_SHARP":73006,"SUBSCRIPTIONS":73007,"SUBSCRIPTIONS_OUTLINED":73008,"SUBSCRIPTIONS_ROUNDED":73009,"SUBSCRIPTIONS_SHARP":73010,"SUBTITLES":73011,"SUBTITLES_OFF":73012,"SUBTITLES_OFF_OUTLINED":73013,"SUBTITLES_OFF_ROUNDED":73014,"SUBTITLES_OFF_SHARP":73015,"SUBTITLES_OUTLINED":73016,"SUBTITLES_ROUNDED":73017,"SUBTITLES_SHARP":73018,"SUBWAY":73019,"SUBWAY_OUTLINED":73020,"SUBWAY_ROUNDED":73021,"SUBWAY_SHARP":73022,"SUMMARIZE":73023,"SUMMARIZE_OUTLINED":73024,"SUMMARIZE_ROUNDED":73025,"SUMMARIZE_SHARP":73026,"SUNNY":73027,"SUNNY_SNOWING":73028,"SUPERSCRIPT":73029,"SUPERSCRIPT_OUTLINED":73030,"SUPERSCRIPT_ROUNDED":73031,"SUPERSCRIPT_SHARP":73032,"SUPERVISED_USER_CIRCLE":73033,"SUPERVISED_USER_CIRCLE_OUTLINED":73034,"SUPERVISED_USER_CIRCLE_ROUNDED":73035,"SUPERVISED_USER_CIRCLE_SHARP":73036,"SUPERVISOR_ACCOUNT":73037,"SUPERVISOR_ACCOUNT_OUTLINED":73038,"SUPERVISOR_ACCOUNT_ROUNDED":73039,"SUPERVISOR_ACCOUNT_SHARP":73040,"SUPPORT":73041,"SUPPORT_AGENT":73042,"SUPPORT_AGENT_OUTLINED":73043,"SUPPORT_AGENT_ROUNDED":73044,"SUPPORT_AGENT_SHARP":73045,"SUPPORT_OUTLINED":73046,"SUPPORT_ROUNDED":73047,"SUPPORT_SHARP":73048,"SURFING":73049,"SURFING_OUTLINED":73050,"SURFING_ROUNDED":73051,"SURFING_SHARP":73052,"SURROUND_SOUND":73053,"SURROUND_SOUND_OUTLINED":73054,"SURROUND_SOUND_ROUNDED":73055,"SURROUND_SOUND_SHARP":73056,"SWAP_CALLS":73057,"SWAP_CALLS_OUTLINED":73058,"SWAP_CALLS_ROUNDED":73059,"SWAP_CALLS_SHARP":73060,"SWAP_HORIZ":73061,"SWAP_HORIZ_OUTLINED":73062,"SWAP_HORIZ_ROUNDED":73063,"SWAP_HORIZ_SHARP":73064,"SWAP_HORIZONTAL_CIRCLE":73065,"SWAP_HORIZONTAL_CIRCLE_OUTLINED":73066,"SWAP_HORIZONTAL_CIRCLE_ROUNDED":73067,"SWAP_HORIZONTAL_CIRCLE_SHARP":73068,"SWAP_VERT":73069,"SWAP_VERT_CIRCLE":73070,"SWAP_VERT_CIRCLE_OUTLINED":73071,"SWAP_VERT_CIRCLE_ROUNDED":73072,"SWAP_VERT_CIRCLE_SHARP":73073,"SWAP_VERT_OUTLINED":73074,"SWAP_VERT_ROUNDED":73075,"SWAP_VERT_SHARP":73076,"SWAP_VERTICAL_CIRCLE":73077,"SWAP_VERTICAL_CIRCLE_OUTLINED":73078,"SWAP_VERTICAL_CIRCLE_ROUNDED":73079,"SWAP_VERTICAL_CIRCLE_SHARP":73080,"SWIPE":73081,"SWIPE_DOWN":73082,"SWIPE_DOWN_ALT":73083,"SWIPE_DOWN_ALT_OUTLINED":73084,"SWIPE_DOWN_ALT_ROUNDED":73085,"SWIPE_DOWN_ALT_SHARP":73086,"SWIPE_DOWN_OUTLINED":73087,"SWIPE_DOWN_ROUNDED":73088,"SWIPE_DOWN_SHARP":73089,"SWIPE_LEFT":73090,"SWIPE_LEFT_ALT":73091,"SWIPE_LEFT_ALT_OUTLINED":73092,"SWIPE_LEFT_ALT_ROUNDED":73093,"SWIPE_LEFT_ALT_SHARP":73094,"SWIPE_LEFT_OUTLINED":73095,"SWIPE_LEFT_ROUNDED":73096,"SWIPE_LEFT_SHARP":73097,"SWIPE_OUTLINED":73098,"SWIPE_RIGHT":73099,"SWIPE_RIGHT_ALT":73100,"SWIPE_RIGHT_ALT_OUTLINED":73101,"SWIPE_RIGHT_ALT_ROUNDED":73102,"SWIPE_RIGHT_ALT_SHARP":73103,"SWIPE_RIGHT_OUTLINED":73104,"SWIPE_RIGHT_ROUNDED":73105,"SWIPE_RIGHT_SHARP":73106,"SWIPE_ROUNDED":73107,"SWIPE_SHARP":73108,"SWIPE_UP":73109,"SWIPE_UP_ALT":73110,"SWIPE_UP_ALT_OUTLINED":73111,"SWIPE_UP_ALT_ROUNDED":73112,"SWIPE_UP_ALT_SHARP":73113,"SWIPE_UP_OUTLINED":73114,"SWIPE_UP_ROUNDED":73115,"SWIPE_UP_SHARP":73116,"SWIPE_VERTICAL":73117,"SWIPE_VERTICAL_OUTLINED":73118,"SWIPE_VERTICAL_ROUNDED":73119,"SWIPE_VERTICAL_SHARP":73120,"SWITCH_ACCESS_SHORTCUT":73121,"SWITCH_ACCESS_SHORTCUT_ADD":73122,"SWITCH_ACCESS_SHORTCUT_ADD_OUTLINED":73123,"SWITCH_ACCESS_SHORTCUT_ADD_ROUNDED":73124,"SWITCH_ACCESS_SHORTCUT_ADD_SHARP":73125,"SWITCH_ACCESS_SHORTCUT_OUTLINED":73126,"SWITCH_ACCESS_SHORTCUT_ROUNDED":73127,"SWITCH_ACCESS_SHORTCUT_SHARP":73128,"SWITCH_ACCOUNT":73129,"SWITCH_ACCOUNT_OUTLINED":73130,"SWITCH_ACCOUNT_ROUNDED":73131,"SWITCH_ACCOUNT_SHARP":73132,"SWITCH_CAMERA":73133,"SWITCH_CAMERA_OUTLINED":73134,"SWITCH_CAMERA_ROUNDED":73135,"SWITCH_CAMERA_SHARP":73136,"SWITCH_LEFT":73137,"SWITCH_LEFT_OUTLINED":73138,"SWITCH_LEFT_ROUNDED":73139,"SWITCH_LEFT_SHARP":73140,"SWITCH_RIGHT":73141,"SWITCH_RIGHT_OUTLINED":73142,"SWITCH_RIGHT_ROUNDED":73143,"SWITCH_RIGHT_SHARP":73144,"SWITCH_VIDEO":73145,"SWITCH_VIDEO_OUTLINED":73146,"SWITCH_VIDEO_ROUNDED":73147,"SWITCH_VIDEO_SHARP":73148,"SYNAGOGUE":73149,"SYNAGOGUE_OUTLINED":73150,"SYNAGOGUE_ROUNDED":73151,"SYNAGOGUE_SHARP":73152,"SYNC":73153,"SYNC_ALT":73154,"SYNC_ALT_OUTLINED":73155,"SYNC_ALT_ROUNDED":73156,"SYNC_ALT_SHARP":73157,"SYNC_DISABLED":73158,"SYNC_DISABLED_OUTLINED":73159,"SYNC_DISABLED_ROUNDED":73160,"SYNC_DISABLED_SHARP":73161,"SYNC_LOCK":73162,"SYNC_LOCK_OUTLINED":73163,"SYNC_LOCK_ROUNDED":73164,"SYNC_LOCK_SHARP":73165,"SYNC_OUTLINED":73166,"SYNC_PROBLEM":73167,"SYNC_PROBLEM_OUTLINED":73168,"SYNC_PROBLEM_ROUNDED":73169,"SYNC_PROBLEM_SHARP":73170,"SYNC_ROUNDED":73171,"SYNC_SHARP":73172,"SYSTEM_SECURITY_UPDATE":73173,"SYSTEM_SECURITY_UPDATE_GOOD":73174,"SYSTEM_SECURITY_UPDATE_GOOD_OUTLINED":73175,"SYSTEM_SECURITY_UPDATE_GOOD_ROUNDED":73176,"SYSTEM_SECURITY_UPDATE_GOOD_SHARP":73177,"SYSTEM_SECURITY_UPDATE_OUTLINED":73178,"SYSTEM_SECURITY_UPDATE_ROUNDED":73179,"SYSTEM_SECURITY_UPDATE_SHARP":73180,"SYSTEM_SECURITY_UPDATE_WARNING":73181,"SYSTEM_SECURITY_UPDATE_WARNING_OUTLINED":73182,"SYSTEM_SECURITY_UPDATE_WARNING_ROUNDED":73183,"SYSTEM_SECURITY_UPDATE_WARNING_SHARP":73184,"SYSTEM_UPDATE":73185,"SYSTEM_UPDATE_ALT":73186,"SYSTEM_UPDATE_ALT_OUTLINED":73187,"SYSTEM_UPDATE_ALT_ROUNDED":73188,"SYSTEM_UPDATE_ALT_SHARP":73189,"SYSTEM_UPDATE_OUTLINED":73190,"SYSTEM_UPDATE_ROUNDED":73191,"SYSTEM_UPDATE_SHARP":73192,"SYSTEM_UPDATE_TV":73193,"SYSTEM_UPDATE_TV_OUTLINED":73194,"SYSTEM_UPDATE_TV_ROUNDED":73195,"SYSTEM_UPDATE_TV_SHARP":73196,"TAB":73197,"TAB_OUTLINED":73198,"TAB_ROUNDED":73199,"TAB_SHARP":73200,"TAB_UNSELECTED":73201,"TAB_UNSELECTED_OUTLINED":73202,"TAB_UNSELECTED_ROUNDED":73203,"TAB_UNSELECTED_SHARP":73204,"TABLE_BAR":73205,"TABLE_BAR_OUTLINED":73206,"TABLE_BAR_ROUNDED":73207,"TABLE_BAR_SHARP":73208,"TABLE_CHART":73209,"TABLE_CHART_OUTLINED":73210,"TABLE_CHART_ROUNDED":73211,"TABLE_CHART_SHARP":73212,"TABLE_RESTAURANT":73213,"TABLE_RESTAURANT_OUTLINED":73214,"TABLE_RESTAURANT_ROUNDED":73215,"TABLE_RESTAURANT_SHARP":73216,"TABLE_ROWS":73217,"TABLE_ROWS_OUTLINED":73218,"TABLE_ROWS_ROUNDED":73219,"TABLE_ROWS_SHARP":73220,"TABLE_VIEW":73221,"TABLE_VIEW_OUTLINED":73222,"TABLE_VIEW_ROUNDED":73223,"TABLE_VIEW_SHARP":73224,"TABLET":73225,"TABLET_ANDROID":73226,"TABLET_ANDROID_OUTLINED":73227,"TABLET_ANDROID_ROUNDED":73228,"TABLET_ANDROID_SHARP":73229,"TABLET_MAC":73230,"TABLET_MAC_OUTLINED":73231,"TABLET_MAC_ROUNDED":73232,"TABLET_MAC_SHARP":73233,"TABLET_OUTLINED":73234,"TABLET_ROUNDED":73235,"TABLET_SHARP":73236,"TAG":73237,"TAG_FACES":73238,"TAG_FACES_OUTLINED":73239,"TAG_FACES_ROUNDED":73240,"TAG_FACES_SHARP":73241,"TAG_OUTLINED":73242,"TAG_ROUNDED":73243,"TAG_SHARP":73244,"TAKEOUT_DINING":73245,"TAKEOUT_DINING_OUTLINED":73246,"TAKEOUT_DINING_ROUNDED":73247,"TAKEOUT_DINING_SHARP":73248,"TAP_AND_PLAY":73249,"TAP_AND_PLAY_OUTLINED":73250,"TAP_AND_PLAY_ROUNDED":73251,"TAP_AND_PLAY_SHARP":73252,"TAPAS":73253,"TAPAS_OUTLINED":73254,"TAPAS_ROUNDED":73255,"TAPAS_SHARP":73256,"TASK":73257,"TASK_ALT":73258,"TASK_ALT_OUTLINED":73259,"TASK_ALT_ROUNDED":73260,"TASK_ALT_SHARP":73261,"TASK_OUTLINED":73262,"TASK_ROUNDED":73263,"TASK_SHARP":73264,"TAXI_ALERT":73265,"TAXI_ALERT_OUTLINED":73266,"TAXI_ALERT_ROUNDED":73267,"TAXI_ALERT_SHARP":73268,"TELEGRAM":73269,"TELEGRAM_OUTLINED":73270,"TELEGRAM_ROUNDED":73271,"TELEGRAM_SHARP":73272,"TEMPLE_BUDDHIST":73273,"TEMPLE_BUDDHIST_OUTLINED":73274,"TEMPLE_BUDDHIST_ROUNDED":73275,"TEMPLE_BUDDHIST_SHARP":73276,"TEMPLE_HINDU":73277,"TEMPLE_HINDU_OUTLINED":73278,"TEMPLE_HINDU_ROUNDED":73279,"TEMPLE_HINDU_SHARP":73280,"TEN_K":73281,"TEN_K_OUTLINED":73282,"TEN_K_ROUNDED":73283,"TEN_K_SHARP":73284,"TEN_MP":73285,"TEN_MP_OUTLINED":73286,"TEN_MP_ROUNDED":73287,"TEN_MP_SHARP":73288,"TERMINAL":73289,"TERMINAL_OUTLINED":73290,"TERMINAL_ROUNDED":73291,"TERMINAL_SHARP":73292,"TERRAIN":73293,"TERRAIN_OUTLINED":73294,"TERRAIN_ROUNDED":73295,"TERRAIN_SHARP":73296,"TEXT_DECREASE":73297,"TEXT_DECREASE_OUTLINED":73298,"TEXT_DECREASE_ROUNDED":73299,"TEXT_DECREASE_SHARP":73300,"TEXT_FIELDS":73301,"TEXT_FIELDS_OUTLINED":73302,"TEXT_FIELDS_ROUNDED":73303,"TEXT_FIELDS_SHARP":73304,"TEXT_FORMAT":73305,"TEXT_FORMAT_OUTLINED":73306,"TEXT_FORMAT_ROUNDED":73307,"TEXT_FORMAT_SHARP":73308,"TEXT_INCREASE":73309,"TEXT_INCREASE_OUTLINED":73310,"TEXT_INCREASE_ROUNDED":73311,"TEXT_INCREASE_SHARP":73312,"TEXT_ROTATE_UP":73313,"TEXT_ROTATE_UP_OUTLINED":73314,"TEXT_ROTATE_UP_ROUNDED":73315,"TEXT_ROTATE_UP_SHARP":73316,"TEXT_ROTATE_VERTICAL":73317,"TEXT_ROTATE_VERTICAL_OUTLINED":73318,"TEXT_ROTATE_VERTICAL_ROUNDED":73319,"TEXT_ROTATE_VERTICAL_SHARP":73320,"TEXT_ROTATION_ANGLEDOWN":73321,"TEXT_ROTATION_ANGLEDOWN_OUTLINED":73322,"TEXT_ROTATION_ANGLEDOWN_ROUNDED":73323,"TEXT_ROTATION_ANGLEDOWN_SHARP":73324,"TEXT_ROTATION_ANGLEUP":73325,"TEXT_ROTATION_ANGLEUP_OUTLINED":73326,"TEXT_ROTATION_ANGLEUP_ROUNDED":73327,"TEXT_ROTATION_ANGLEUP_SHARP":73328,"TEXT_ROTATION_DOWN":73329,"TEXT_ROTATION_DOWN_OUTLINED":73330,"TEXT_ROTATION_DOWN_ROUNDED":73331,"TEXT_ROTATION_DOWN_SHARP":73332,"TEXT_ROTATION_NONE":73333,"TEXT_ROTATION_NONE_OUTLINED":73334,"TEXT_ROTATION_NONE_ROUNDED":73335,"TEXT_ROTATION_NONE_SHARP":73336,"TEXT_SNIPPET":73337,"TEXT_SNIPPET_OUTLINED":73338,"TEXT_SNIPPET_ROUNDED":73339,"TEXT_SNIPPET_SHARP":73340,"TEXTSMS":73341,"TEXTSMS_OUTLINED":73342,"TEXTSMS_ROUNDED":73343,"TEXTSMS_SHARP":73344,"TEXTURE":73345,"TEXTURE_OUTLINED":73346,"TEXTURE_ROUNDED":73347,"TEXTURE_SHARP":73348,"THEATER_COMEDY":73349,"THEATER_COMEDY_OUTLINED":73350,"THEATER_COMEDY_ROUNDED":73351,"THEATER_COMEDY_SHARP":73352,"THEATERS":73353,"THEATERS_OUTLINED":73354,"THEATERS_ROUNDED":73355,"THEATERS_SHARP":73356,"THERMOSTAT":73357,"THERMOSTAT_AUTO":73358,"THERMOSTAT_AUTO_OUTLINED":73359,"THERMOSTAT_AUTO_ROUNDED":73360,"THERMOSTAT_AUTO_SHARP":73361,"THERMOSTAT_OUTLINED":73362,"THERMOSTAT_ROUNDED":73363,"THERMOSTAT_SHARP":73364,"THIRTEEN_MP":73365,"THIRTEEN_MP_OUTLINED":73366,"THIRTEEN_MP_ROUNDED":73367,"THIRTEEN_MP_SHARP":73368,"THIRTY_FPS":73369,"THIRTY_FPS_OUTLINED":73370,"THIRTY_FPS_ROUNDED":73371,"THIRTY_FPS_SELECT":73372,"THIRTY_FPS_SELECT_OUTLINED":73373,"THIRTY_FPS_SELECT_ROUNDED":73374,"THIRTY_FPS_SELECT_SHARP":73375,"THIRTY_FPS_SHARP":73376,"THREE_G_MOBILEDATA":73377,"THREE_G_MOBILEDATA_OUTLINED":73378,"THREE_G_MOBILEDATA_ROUNDED":73379,"THREE_G_MOBILEDATA_SHARP":73380,"THREE_K":73381,"THREE_K_OUTLINED":73382,"THREE_K_PLUS":73383,"THREE_K_PLUS_OUTLINED":73384,"THREE_K_PLUS_ROUNDED":73385,"THREE_K_PLUS_SHARP":73386,"THREE_K_ROUNDED":73387,"THREE_K_SHARP":73388,"THREE_MP":73389,"THREE_MP_OUTLINED":73390,"THREE_MP_ROUNDED":73391,"THREE_MP_SHARP":73392,"THREE_P":73393,"THREE_P_OUTLINED":73394,"THREE_P_ROUNDED":73395,"THREE_P_SHARP":73396,"THREED_ROTATION":73397,"THREED_ROTATION_OUTLINED":73398,"THREED_ROTATION_ROUNDED":73399,"THREED_ROTATION_SHARP":73400,"THREESIXTY":73401,"THREESIXTY_OUTLINED":73402,"THREESIXTY_ROUNDED":73403,"THREESIXTY_SHARP":73404,"THUMB_DOWN":73405,"THUMB_DOWN_ALT":73406,"THUMB_DOWN_ALT_OUTLINED":73407,"THUMB_DOWN_ALT_ROUNDED":73408,"THUMB_DOWN_ALT_SHARP":73409,"THUMB_DOWN_OFF_ALT":73410,"THUMB_DOWN_OFF_ALT_OUTLINED":73411,"THUMB_DOWN_OFF_ALT_ROUNDED":73412,"THUMB_DOWN_OFF_ALT_SHARP":73413,"THUMB_DOWN_OUTLINED":73414,"THUMB_DOWN_ROUNDED":73415,"THUMB_DOWN_SHARP":73416,"THUMB_UP":73417,"THUMB_UP_ALT":73418,"THUMB_UP_ALT_OUTLINED":73419,"THUMB_UP_ALT_ROUNDED":73420,"THUMB_UP_ALT_SHARP":73421,"THUMB_UP_OFF_ALT":73422,"THUMB_UP_OFF_ALT_OUTLINED":73423,"THUMB_UP_OFF_ALT_ROUNDED":73424,"THUMB_UP_OFF_ALT_SHARP":73425,"THUMB_UP_OUTLINED":73426,"THUMB_UP_ROUNDED":73427,"THUMB_UP_SHARP":73428,"THUMBS_UP_DOWN":73429,"THUMBS_UP_DOWN_OUTLINED":73430,"THUMBS_UP_DOWN_ROUNDED":73431,"THUMBS_UP_DOWN_SHARP":73432,"THUNDERSTORM":73433,"THUNDERSTORM_OUTLINED":73434,"THUNDERSTORM_ROUNDED":73435,"THUNDERSTORM_SHARP":73436,"TIKTOK":73437,"TIKTOK_OUTLINED":73438,"TIKTOK_ROUNDED":73439,"TIKTOK_SHARP":73440,"TIME_TO_LEAVE":73441,"TIME_TO_LEAVE_OUTLINED":73442,"TIME_TO_LEAVE_ROUNDED":73443,"TIME_TO_LEAVE_SHARP":73444,"TIMELAPSE":73445,"TIMELAPSE_OUTLINED":73446,"TIMELAPSE_ROUNDED":73447,"TIMELAPSE_SHARP":73448,"TIMELINE":73449,"TIMELINE_OUTLINED":73450,"TIMELINE_ROUNDED":73451,"TIMELINE_SHARP":73452,"TIMER":73453,"TIMER_10":73454,"TIMER_10_OUTLINED":73455,"TIMER_10_ROUNDED":73456,"TIMER_10_SELECT":73457,"TIMER_10_SELECT_OUTLINED":73458,"TIMER_10_SELECT_ROUNDED":73459,"TIMER_10_SELECT_SHARP":73460,"TIMER_10_SHARP":73461,"TIMER_3":73462,"TIMER_3_OUTLINED":73463,"TIMER_3_ROUNDED":73464,"TIMER_3_SELECT":73465,"TIMER_3_SELECT_OUTLINED":73466,"TIMER_3_SELECT_ROUNDED":73467,"TIMER_3_SELECT_SHARP":73468,"TIMER_3_SHARP":73469,"TIMER_OFF":73470,"TIMER_OFF_OUTLINED":73471,"TIMER_OFF_ROUNDED":73472,"TIMER_OFF_SHARP":73473,"TIMER_OUTLINED":73474,"TIMER_ROUNDED":73475,"TIMER_SHARP":73476,"TIPS_AND_UPDATES":73477,"TIPS_AND_UPDATES_OUTLINED":73478,"TIPS_AND_UPDATES_ROUNDED":73479,"TIPS_AND_UPDATES_SHARP":73480,"TIRE_REPAIR":73481,"TIRE_REPAIR_OUTLINED":73482,"TIRE_REPAIR_ROUNDED":73483,"TIRE_REPAIR_SHARP":73484,"TITLE":73485,"TITLE_OUTLINED":73486,"TITLE_ROUNDED":73487,"TITLE_SHARP":73488,"TOC":73489,"TOC_OUTLINED":73490,"TOC_ROUNDED":73491,"TOC_SHARP":73492,"TODAY":73493,"TODAY_OUTLINED":73494,"TODAY_ROUNDED":73495,"TODAY_SHARP":73496,"TOGGLE_OFF":73497,"TOGGLE_OFF_OUTLINED":73498,"TOGGLE_OFF_ROUNDED":73499,"TOGGLE_OFF_SHARP":73500,"TOGGLE_ON":73501,"TOGGLE_ON_OUTLINED":73502,"TOGGLE_ON_ROUNDED":73503,"TOGGLE_ON_SHARP":73504,"TOKEN":73505,"TOKEN_OUTLINED":73506,"TOKEN_ROUNDED":73507,"TOKEN_SHARP":73508,"TOLL":73509,"TOLL_OUTLINED":73510,"TOLL_ROUNDED":73511,"TOLL_SHARP":73512,"TONALITY":73513,"TONALITY_OUTLINED":73514,"TONALITY_ROUNDED":73515,"TONALITY_SHARP":73516,"TOPIC":73517,"TOPIC_OUTLINED":73518,"TOPIC_ROUNDED":73519,"TOPIC_SHARP":73520,"TORNADO":73521,"TORNADO_OUTLINED":73522,"TORNADO_ROUNDED":73523,"TORNADO_SHARP":73524,"TOUCH_APP":73525,"TOUCH_APP_OUTLINED":73526,"TOUCH_APP_ROUNDED":73527,"TOUCH_APP_SHARP":73528,"TOUR":73529,"TOUR_OUTLINED":73530,"TOUR_ROUNDED":73531,"TOUR_SHARP":73532,"TOYS":73533,"TOYS_OUTLINED":73534,"TOYS_ROUNDED":73535,"TOYS_SHARP":73536,"TRACK_CHANGES":73537,"TRACK_CHANGES_OUTLINED":73538,"TRACK_CHANGES_ROUNDED":73539,"TRACK_CHANGES_SHARP":73540,"TRAFFIC":73541,"TRAFFIC_OUTLINED":73542,"TRAFFIC_ROUNDED":73543,"TRAFFIC_SHARP":73544,"TRAIN":73545,"TRAIN_OUTLINED":73546,"TRAIN_ROUNDED":73547,"TRAIN_SHARP":73548,"TRAM":73549,"TRAM_OUTLINED":73550,"TRAM_ROUNDED":73551,"TRAM_SHARP":73552,"TRANSCRIBE":73553,"TRANSCRIBE_OUTLINED":73554,"TRANSCRIBE_ROUNDED":73555,"TRANSCRIBE_SHARP":73556,"TRANSFER_WITHIN_A_STATION":73557,"TRANSFER_WITHIN_A_STATION_OUTLINED":73558,"TRANSFER_WITHIN_A_STATION_ROUNDED":73559,"TRANSFER_WITHIN_A_STATION_SHARP":73560,"TRANSFORM":73561,"TRANSFORM_OUTLINED":73562,"TRANSFORM_ROUNDED":73563,"TRANSFORM_SHARP":73564,"TRANSGENDER":73565,"TRANSGENDER_OUTLINED":73566,"TRANSGENDER_ROUNDED":73567,"TRANSGENDER_SHARP":73568,"TRANSIT_ENTEREXIT":73569,"TRANSIT_ENTEREXIT_OUTLINED":73570,"TRANSIT_ENTEREXIT_ROUNDED":73571,"TRANSIT_ENTEREXIT_SHARP":73572,"TRANSLATE":73573,"TRANSLATE_OUTLINED":73574,"TRANSLATE_ROUNDED":73575,"TRANSLATE_SHARP":73576,"TRAVEL_EXPLORE":73577,"TRAVEL_EXPLORE_OUTLINED":73578,"TRAVEL_EXPLORE_ROUNDED":73579,"TRAVEL_EXPLORE_SHARP":73580,"TRENDING_DOWN":73581,"TRENDING_DOWN_OUTLINED":73582,"TRENDING_DOWN_ROUNDED":73583,"TRENDING_DOWN_SHARP":73584,"TRENDING_FLAT":73585,"TRENDING_FLAT_OUTLINED":73586,"TRENDING_FLAT_ROUNDED":73587,"TRENDING_FLAT_SHARP":73588,"TRENDING_NEUTRAL":73589,"TRENDING_NEUTRAL_OUTLINED":73590,"TRENDING_NEUTRAL_ROUNDED":73591,"TRENDING_NEUTRAL_SHARP":73592,"TRENDING_UP":73593,"TRENDING_UP_OUTLINED":73594,"TRENDING_UP_ROUNDED":73595,"TRENDING_UP_SHARP":73596,"TRIP_ORIGIN":73597,"TRIP_ORIGIN_OUTLINED":73598,"TRIP_ORIGIN_ROUNDED":73599,"TRIP_ORIGIN_SHARP":73600,"TROLLEY":73601,"TROUBLESHOOT":73602,"TROUBLESHOOT_OUTLINED":73603,"TROUBLESHOOT_ROUNDED":73604,"TROUBLESHOOT_SHARP":73605,"TRY_SMS_STAR":73606,"TRY_SMS_STAR_OUTLINED":73607,"TRY_SMS_STAR_ROUNDED":73608,"TRY_SMS_STAR_SHARP":73609,"TSUNAMI":73610,"TSUNAMI_OUTLINED":73611,"TSUNAMI_ROUNDED":73612,"TSUNAMI_SHARP":73613,"TTY":73614,"TTY_OUTLINED":73615,"TTY_ROUNDED":73616,"TTY_SHARP":73617,"TUNE":73618,"TUNE_OUTLINED":73619,"TUNE_ROUNDED":73620,"TUNE_SHARP":73621,"TUNGSTEN":73622,"TUNGSTEN_OUTLINED":73623,"TUNGSTEN_ROUNDED":73624,"TUNGSTEN_SHARP":73625,"TURN_LEFT":73626,"TURN_LEFT_OUTLINED":73627,"TURN_LEFT_ROUNDED":73628,"TURN_LEFT_SHARP":73629,"TURN_RIGHT":73630,"TURN_RIGHT_OUTLINED":73631,"TURN_RIGHT_ROUNDED":73632,"TURN_RIGHT_SHARP":73633,"TURN_SHARP_LEFT":73634,"TURN_SHARP_LEFT_OUTLINED":73635,"TURN_SHARP_LEFT_ROUNDED":73636,"TURN_SHARP_LEFT_SHARP":73637,"TURN_SHARP_RIGHT":73638,"TURN_SHARP_RIGHT_OUTLINED":73639,"TURN_SHARP_RIGHT_ROUNDED":73640,"TURN_SHARP_RIGHT_SHARP":73641,"TURN_SLIGHT_LEFT":73642,"TURN_SLIGHT_LEFT_OUTLINED":73643,"TURN_SLIGHT_LEFT_ROUNDED":73644,"TURN_SLIGHT_LEFT_SHARP":73645,"TURN_SLIGHT_RIGHT":73646,"TURN_SLIGHT_RIGHT_OUTLINED":73647,"TURN_SLIGHT_RIGHT_ROUNDED":73648,"TURN_SLIGHT_RIGHT_SHARP":73649,"TURNED_IN":73650,"TURNED_IN_NOT":73651,"TURNED_IN_NOT_OUTLINED":73652,"TURNED_IN_NOT_ROUNDED":73653,"TURNED_IN_NOT_SHARP":73654,"TURNED_IN_OUTLINED":73655,"TURNED_IN_ROUNDED":73656,"TURNED_IN_SHARP":73657,"TV":73658,"TV_OFF":73659,"TV_OFF_OUTLINED":73660,"TV_OFF_ROUNDED":73661,"TV_OFF_SHARP":73662,"TV_OUTLINED":73663,"TV_ROUNDED":73664,"TV_SHARP":73665,"TWELVE_MP":73666,"TWELVE_MP_OUTLINED":73667,"TWELVE_MP_ROUNDED":73668,"TWELVE_MP_SHARP":73669,"TWENTY_FOUR_MP":73670,"TWENTY_FOUR_MP_OUTLINED":73671,"TWENTY_FOUR_MP_ROUNDED":73672,"TWENTY_FOUR_MP_SHARP":73673,"TWENTY_MP":73674,"TWENTY_MP_OUTLINED":73675,"TWENTY_MP_ROUNDED":73676,"TWENTY_MP_SHARP":73677,"TWENTY_ONE_MP":73678,"TWENTY_ONE_MP_OUTLINED":73679,"TWENTY_ONE_MP_ROUNDED":73680,"TWENTY_ONE_MP_SHARP":73681,"TWENTY_THREE_MP":73682,"TWENTY_THREE_MP_OUTLINED":73683,"TWENTY_THREE_MP_ROUNDED":73684,"TWENTY_THREE_MP_SHARP":73685,"TWENTY_TWO_MP":73686,"TWENTY_TWO_MP_OUTLINED":73687,"TWENTY_TWO_MP_ROUNDED":73688,"TWENTY_TWO_MP_SHARP":73689,"TWO_K":73690,"TWO_K_OUTLINED":73691,"TWO_K_PLUS":73692,"TWO_K_PLUS_OUTLINED":73693,"TWO_K_PLUS_ROUNDED":73694,"TWO_K_PLUS_SHARP":73695,"TWO_K_ROUNDED":73696,"TWO_K_SHARP":73697,"TWO_MP":73698,"TWO_MP_OUTLINED":73699,"TWO_MP_ROUNDED":73700,"TWO_MP_SHARP":73701,"TWO_WHEELER":73702,"TWO_WHEELER_OUTLINED":73703,"TWO_WHEELER_ROUNDED":73704,"TWO_WHEELER_SHARP":73705,"TYPE_SPECIMEN":73706,"TYPE_SPECIMEN_OUTLINED":73707,"TYPE_SPECIMEN_ROUNDED":73708,"TYPE_SPECIMEN_SHARP":73709,"U_TURN_LEFT":73710,"U_TURN_LEFT_OUTLINED":73711,"U_TURN_LEFT_ROUNDED":73712,"U_TURN_LEFT_SHARP":73713,"U_TURN_RIGHT":73714,"U_TURN_RIGHT_OUTLINED":73715,"U_TURN_RIGHT_ROUNDED":73716,"U_TURN_RIGHT_SHARP":73717,"UMBRELLA":73718,"UMBRELLA_OUTLINED":73719,"UMBRELLA_ROUNDED":73720,"UMBRELLA_SHARP":73721,"UNARCHIVE":73722,"UNARCHIVE_OUTLINED":73723,"UNARCHIVE_ROUNDED":73724,"UNARCHIVE_SHARP":73725,"UNDO":73726,"UNDO_OUTLINED":73727,"UNDO_ROUNDED":73728,"UNDO_SHARP":73729,"UNFOLD_LESS":73730,"UNFOLD_LESS_DOUBLE":73731,"UNFOLD_LESS_DOUBLE_OUTLINED":73732,"UNFOLD_LESS_DOUBLE_ROUNDED":73733,"UNFOLD_LESS_DOUBLE_SHARP":73734,"UNFOLD_LESS_OUTLINED":73735,"UNFOLD_LESS_ROUNDED":73736,"UNFOLD_LESS_SHARP":73737,"UNFOLD_MORE":73738,"UNFOLD_MORE_DOUBLE":73739,"UNFOLD_MORE_DOUBLE_OUTLINED":73740,"UNFOLD_MORE_DOUBLE_ROUNDED":73741,"UNFOLD_MORE_DOUBLE_SHARP":73742,"UNFOLD_MORE_OUTLINED":73743,"UNFOLD_MORE_ROUNDED":73744,"UNFOLD_MORE_SHARP":73745,"UNPUBLISHED":73746,"UNPUBLISHED_OUTLINED":73747,"UNPUBLISHED_ROUNDED":73748,"UNPUBLISHED_SHARP":73749,"UNSUBSCRIBE":73750,"UNSUBSCRIBE_OUTLINED":73751,"UNSUBSCRIBE_ROUNDED":73752,"UNSUBSCRIBE_SHARP":73753,"UPCOMING":73754,"UPCOMING_OUTLINED":73755,"UPCOMING_ROUNDED":73756,"UPCOMING_SHARP":73757,"UPDATE":73758,"UPDATE_DISABLED":73759,"UPDATE_DISABLED_OUTLINED":73760,"UPDATE_DISABLED_ROUNDED":73761,"UPDATE_DISABLED_SHARP":73762,"UPDATE_OUTLINED":73763,"UPDATE_ROUNDED":73764,"UPDATE_SHARP":73765,"UPGRADE":73766,"UPGRADE_OUTLINED":73767,"UPGRADE_ROUNDED":73768,"UPGRADE_SHARP":73769,"UPLOAD":73770,"UPLOAD_FILE":73771,"UPLOAD_FILE_OUTLINED":73772,"UPLOAD_FILE_ROUNDED":73773,"UPLOAD_FILE_SHARP":73774,"UPLOAD_OUTLINED":73775,"UPLOAD_ROUNDED":73776,"UPLOAD_SHARP":73777,"USB":73778,"USB_OFF":73779,"USB_OFF_OUTLINED":73780,"USB_OFF_ROUNDED":73781,"USB_OFF_SHARP":73782,"USB_OUTLINED":73783,"USB_ROUNDED":73784,"USB_SHARP":73785,"VACCINES":73786,"VACCINES_OUTLINED":73787,"VACCINES_ROUNDED":73788,"VACCINES_SHARP":73789,"VAPE_FREE":73790,"VAPE_FREE_OUTLINED":73791,"VAPE_FREE_ROUNDED":73792,"VAPE_FREE_SHARP":73793,"VAPING_ROOMS":73794,"VAPING_ROOMS_OUTLINED":73795,"VAPING_ROOMS_ROUNDED":73796,"VAPING_ROOMS_SHARP":73797,"VERIFIED":73798,"VERIFIED_OUTLINED":73799,"VERIFIED_ROUNDED":73800,"VERIFIED_SHARP":73801,"VERIFIED_USER":73802,"VERIFIED_USER_OUTLINED":73803,"VERIFIED_USER_ROUNDED":73804,"VERIFIED_USER_SHARP":73805,"VERTICAL_ALIGN_BOTTOM":73806,"VERTICAL_ALIGN_BOTTOM_OUTLINED":73807,"VERTICAL_ALIGN_BOTTOM_ROUNDED":73808,"VERTICAL_ALIGN_BOTTOM_SHARP":73809,"VERTICAL_ALIGN_CENTER":73810,"VERTICAL_ALIGN_CENTER_OUTLINED":73811,"VERTICAL_ALIGN_CENTER_ROUNDED":73812,"VERTICAL_ALIGN_CENTER_SHARP":73813,"VERTICAL_ALIGN_TOP":73814,"VERTICAL_ALIGN_TOP_OUTLINED":73815,"VERTICAL_ALIGN_TOP_ROUNDED":73816,"VERTICAL_ALIGN_TOP_SHARP":73817,"VERTICAL_DISTRIBUTE":73818,"VERTICAL_DISTRIBUTE_OUTLINED":73819,"VERTICAL_DISTRIBUTE_ROUNDED":73820,"VERTICAL_DISTRIBUTE_SHARP":73821,"VERTICAL_SHADES":73822,"VERTICAL_SHADES_CLOSED":73823,"VERTICAL_SHADES_CLOSED_OUTLINED":73824,"VERTICAL_SHADES_CLOSED_ROUNDED":73825,"VERTICAL_SHADES_CLOSED_SHARP":73826,"VERTICAL_SHADES_OUTLINED":73827,"VERTICAL_SHADES_ROUNDED":73828,"VERTICAL_SHADES_SHARP":73829,"VERTICAL_SPLIT":73830,"VERTICAL_SPLIT_OUTLINED":73831,"VERTICAL_SPLIT_ROUNDED":73832,"VERTICAL_SPLIT_SHARP":73833,"VIBRATION":73834,"VIBRATION_OUTLINED":73835,"VIBRATION_ROUNDED":73836,"VIBRATION_SHARP":73837,"VIDEO_CALL":73838,"VIDEO_CALL_OUTLINED":73839,"VIDEO_CALL_ROUNDED":73840,"VIDEO_CALL_SHARP":73841,"VIDEO_CAMERA_BACK":73842,"VIDEO_CAMERA_BACK_OUTLINED":73843,"VIDEO_CAMERA_BACK_ROUNDED":73844,"VIDEO_CAMERA_BACK_SHARP":73845,"VIDEO_CAMERA_FRONT":73846,"VIDEO_CAMERA_FRONT_OUTLINED":73847,"VIDEO_CAMERA_FRONT_ROUNDED":73848,"VIDEO_CAMERA_FRONT_SHARP":73849,"VIDEO_CHAT":73850,"VIDEO_CHAT_OUTLINED":73851,"VIDEO_CHAT_ROUNDED":73852,"VIDEO_CHAT_SHARP":73853,"VIDEO_COLLECTION":73854,"VIDEO_COLLECTION_OUTLINED":73855,"VIDEO_COLLECTION_ROUNDED":73856,"VIDEO_COLLECTION_SHARP":73857,"VIDEO_FILE":73858,"VIDEO_FILE_OUTLINED":73859,"VIDEO_FILE_ROUNDED":73860,"VIDEO_FILE_SHARP":73861,"VIDEO_LABEL":73862,"VIDEO_LABEL_OUTLINED":73863,"VIDEO_LABEL_ROUNDED":73864,"VIDEO_LABEL_SHARP":73865,"VIDEO_LIBRARY":73866,"VIDEO_LIBRARY_OUTLINED":73867,"VIDEO_LIBRARY_ROUNDED":73868,"VIDEO_LIBRARY_SHARP":73869,"VIDEO_SETTINGS":73870,"VIDEO_SETTINGS_OUTLINED":73871,"VIDEO_SETTINGS_ROUNDED":73872,"VIDEO_SETTINGS_SHARP":73873,"VIDEO_STABLE":73874,"VIDEO_STABLE_OUTLINED":73875,"VIDEO_STABLE_ROUNDED":73876,"VIDEO_STABLE_SHARP":73877,"VIDEOCAM":73878,"VIDEOCAM_OFF":73879,"VIDEOCAM_OFF_OUTLINED":73880,"VIDEOCAM_OFF_ROUNDED":73881,"VIDEOCAM_OFF_SHARP":73882,"VIDEOCAM_OUTLINED":73883,"VIDEOCAM_ROUNDED":73884,"VIDEOCAM_SHARP":73885,"VIDEOGAME_ASSET":73886,"VIDEOGAME_ASSET_OFF":73887,"VIDEOGAME_ASSET_OFF_OUTLINED":73888,"VIDEOGAME_ASSET_OFF_ROUNDED":73889,"VIDEOGAME_ASSET_OFF_SHARP":73890,"VIDEOGAME_ASSET_OUTLINED":73891,"VIDEOGAME_ASSET_ROUNDED":73892,"VIDEOGAME_ASSET_SHARP":73893,"VIEW_AGENDA":73894,"VIEW_AGENDA_OUTLINED":73895,"VIEW_AGENDA_ROUNDED":73896,"VIEW_AGENDA_SHARP":73897,"VIEW_ARRAY":73898,"VIEW_ARRAY_OUTLINED":73899,"VIEW_ARRAY_ROUNDED":73900,"VIEW_ARRAY_SHARP":73901,"VIEW_CAROUSEL":73902,"VIEW_CAROUSEL_OUTLINED":73903,"VIEW_CAROUSEL_ROUNDED":73904,"VIEW_CAROUSEL_SHARP":73905,"VIEW_COLUMN":73906,"VIEW_COLUMN_OUTLINED":73907,"VIEW_COLUMN_ROUNDED":73908,"VIEW_COLUMN_SHARP":73909,"VIEW_COMFORTABLE":73910,"VIEW_COMFORTABLE_OUTLINED":73911,"VIEW_COMFORTABLE_ROUNDED":73912,"VIEW_COMFORTABLE_SHARP":73913,"VIEW_COMFY":73914,"VIEW_COMFY_ALT":73915,"VIEW_COMFY_ALT_OUTLINED":73916,"VIEW_COMFY_ALT_ROUNDED":73917,"VIEW_COMFY_ALT_SHARP":73918,"VIEW_COMFY_OUTLINED":73919,"VIEW_COMFY_ROUNDED":73920,"VIEW_COMFY_SHARP":73921,"VIEW_COMPACT":73922,"VIEW_COMPACT_ALT":73923,"VIEW_COMPACT_ALT_OUTLINED":73924,"VIEW_COMPACT_ALT_ROUNDED":73925,"VIEW_COMPACT_ALT_SHARP":73926,"VIEW_COMPACT_OUTLINED":73927,"VIEW_COMPACT_ROUNDED":73928,"VIEW_COMPACT_SHARP":73929,"VIEW_COZY":73930,"VIEW_COZY_OUTLINED":73931,"VIEW_COZY_ROUNDED":73932,"VIEW_COZY_SHARP":73933,"VIEW_DAY":73934,"VIEW_DAY_OUTLINED":73935,"VIEW_DAY_ROUNDED":73936,"VIEW_DAY_SHARP":73937,"VIEW_HEADLINE":73938,"VIEW_HEADLINE_OUTLINED":73939,"VIEW_HEADLINE_ROUNDED":73940,"VIEW_HEADLINE_SHARP":73941,"VIEW_IN_AR":73942,"VIEW_IN_AR_OUTLINED":73943,"VIEW_IN_AR_ROUNDED":73944,"VIEW_IN_AR_SHARP":73945,"VIEW_KANBAN":73946,"VIEW_KANBAN_OUTLINED":73947,"VIEW_KANBAN_ROUNDED":73948,"VIEW_KANBAN_SHARP":73949,"VIEW_LIST":73950,"VIEW_LIST_OUTLINED":73951,"VIEW_LIST_ROUNDED":73952,"VIEW_LIST_SHARP":73953,"VIEW_MODULE":73954,"VIEW_MODULE_OUTLINED":73955,"VIEW_MODULE_ROUNDED":73956,"VIEW_MODULE_SHARP":73957,"VIEW_QUILT":73958,"VIEW_QUILT_OUTLINED":73959,"VIEW_QUILT_ROUNDED":73960,"VIEW_QUILT_SHARP":73961,"VIEW_SIDEBAR":73962,"VIEW_SIDEBAR_OUTLINED":73963,"VIEW_SIDEBAR_ROUNDED":73964,"VIEW_SIDEBAR_SHARP":73965,"VIEW_STREAM":73966,"VIEW_STREAM_OUTLINED":73967,"VIEW_STREAM_ROUNDED":73968,"VIEW_STREAM_SHARP":73969,"VIEW_TIMELINE":73970,"VIEW_TIMELINE_OUTLINED":73971,"VIEW_TIMELINE_ROUNDED":73972,"VIEW_TIMELINE_SHARP":73973,"VIEW_WEEK":73974,"VIEW_WEEK_OUTLINED":73975,"VIEW_WEEK_ROUNDED":73976,"VIEW_WEEK_SHARP":73977,"VIGNETTE":73978,"VIGNETTE_OUTLINED":73979,"VIGNETTE_ROUNDED":73980,"VIGNETTE_SHARP":73981,"VILLA":73982,"VILLA_OUTLINED":73983,"VILLA_ROUNDED":73984,"VILLA_SHARP":73985,"VISIBILITY":73986,"VISIBILITY_OFF":73987,"VISIBILITY_OFF_OUTLINED":73988,"VISIBILITY_OFF_ROUNDED":73989,"VISIBILITY_OFF_SHARP":73990,"VISIBILITY_OUTLINED":73991,"VISIBILITY_ROUNDED":73992,"VISIBILITY_SHARP":73993,"VOICE_CHAT":73994,"VOICE_CHAT_OUTLINED":73995,"VOICE_CHAT_ROUNDED":73996,"VOICE_CHAT_SHARP":73997,"VOICE_OVER_OFF":73998,"VOICE_OVER_OFF_OUTLINED":73999,"VOICE_OVER_OFF_ROUNDED":74000,"VOICE_OVER_OFF_SHARP":74001,"VOICEMAIL":74002,"VOICEMAIL_OUTLINED":74003,"VOICEMAIL_ROUNDED":74004,"VOICEMAIL_SHARP":74005,"VOLCANO":74006,"VOLCANO_OUTLINED":74007,"VOLCANO_ROUNDED":74008,"VOLCANO_SHARP":74009,"VOLUME_DOWN":74010,"VOLUME_DOWN_ALT":74011,"VOLUME_DOWN_OUTLINED":74012,"VOLUME_DOWN_ROUNDED":74013,"VOLUME_DOWN_SHARP":74014,"VOLUME_MUTE":74015,"VOLUME_MUTE_OUTLINED":74016,"VOLUME_MUTE_ROUNDED":74017,"VOLUME_MUTE_SHARP":74018,"VOLUME_OFF":74019,"VOLUME_OFF_OUTLINED":74020,"VOLUME_OFF_ROUNDED":74021,"VOLUME_OFF_SHARP":74022,"VOLUME_UP":74023,"VOLUME_UP_OUTLINED":74024,"VOLUME_UP_ROUNDED":74025,"VOLUME_UP_SHARP":74026,"VOLUNTEER_ACTIVISM":74027,"VOLUNTEER_ACTIVISM_OUTLINED":74028,"VOLUNTEER_ACTIVISM_ROUNDED":74029,"VOLUNTEER_ACTIVISM_SHARP":74030,"VPN_KEY":74031,"VPN_KEY_OFF":74032,"VPN_KEY_OFF_OUTLINED":74033,"VPN_KEY_OFF_ROUNDED":74034,"VPN_KEY_OFF_SHARP":74035,"VPN_KEY_OUTLINED":74036,"VPN_KEY_ROUNDED":74037,"VPN_KEY_SHARP":74038,"VPN_LOCK":74039,"VPN_LOCK_OUTLINED":74040,"VPN_LOCK_ROUNDED":74041,"VPN_LOCK_SHARP":74042,"VRPANO":74043,"VRPANO_OUTLINED":74044,"VRPANO_ROUNDED":74045,"VRPANO_SHARP":74046,"WALLET":74047,"WALLET_GIFTCARD":74048,"WALLET_GIFTCARD_OUTLINED":74049,"WALLET_GIFTCARD_ROUNDED":74050,"WALLET_GIFTCARD_SHARP":74051,"WALLET_MEMBERSHIP":74052,"WALLET_MEMBERSHIP_OUTLINED":74053,"WALLET_MEMBERSHIP_ROUNDED":74054,"WALLET_MEMBERSHIP_SHARP":74055,"WALLET_OUTLINED":74056,"WALLET_ROUNDED":74057,"WALLET_SHARP":74058,"WALLET_TRAVEL":74059,"WALLET_TRAVEL_OUTLINED":74060,"WALLET_TRAVEL_ROUNDED":74061,"WALLET_TRAVEL_SHARP":74062,"WALLPAPER":74063,"WALLPAPER_OUTLINED":74064,"WALLPAPER_ROUNDED":74065,"WALLPAPER_SHARP":74066,"WAREHOUSE":74067,"WAREHOUSE_OUTLINED":74068,"WAREHOUSE_ROUNDED":74069,"WAREHOUSE_SHARP":74070,"WARNING":74071,"WARNING_AMBER":74072,"WARNING_AMBER_OUTLINED":74073,"WARNING_AMBER_ROUNDED":74074,"WARNING_AMBER_SHARP":74075,"WARNING_OUTLINED":74076,"WARNING_ROUNDED":74077,"WARNING_SHARP":74078,"WASH":74079,"WASH_OUTLINED":74080,"WASH_ROUNDED":74081,"WASH_SHARP":74082,"WATCH":74083,"WATCH_LATER":74084,"WATCH_LATER_OUTLINED":74085,"WATCH_LATER_ROUNDED":74086,"WATCH_LATER_SHARP":74087,"WATCH_OFF":74088,"WATCH_OFF_OUTLINED":74089,"WATCH_OFF_ROUNDED":74090,"WATCH_OFF_SHARP":74091,"WATCH_OUTLINED":74092,"WATCH_ROUNDED":74093,"WATCH_SHARP":74094,"WATER":74095,"WATER_DAMAGE":74096,"WATER_DAMAGE_OUTLINED":74097,"WATER_DAMAGE_ROUNDED":74098,"WATER_DAMAGE_SHARP":74099,"WATER_DROP":74100,"WATER_DROP_OUTLINED":74101,"WATER_DROP_ROUNDED":74102,"WATER_DROP_SHARP":74103,"WATER_OUTLINED":74104,"WATER_ROUNDED":74105,"WATER_SHARP":74106,"WATERFALL_CHART":74107,"WATERFALL_CHART_OUTLINED":74108,"WATERFALL_CHART_ROUNDED":74109,"WATERFALL_CHART_SHARP":74110,"WAVES":74111,"WAVES_OUTLINED":74112,"WAVES_ROUNDED":74113,"WAVES_SHARP":74114,"WAVING_HAND":74115,"WAVING_HAND_OUTLINED":74116,"WAVING_HAND_ROUNDED":74117,"WAVING_HAND_SHARP":74118,"WB_AUTO":74119,"WB_AUTO_OUTLINED":74120,"WB_AUTO_ROUNDED":74121,"WB_AUTO_SHARP":74122,"WB_CLOUDY":74123,"WB_CLOUDY_OUTLINED":74124,"WB_CLOUDY_ROUNDED":74125,"WB_CLOUDY_SHARP":74126,"WB_INCANDESCENT":74127,"WB_INCANDESCENT_OUTLINED":74128,"WB_INCANDESCENT_ROUNDED":74129,"WB_INCANDESCENT_SHARP":74130,"WB_IRIDESCENT":74131,"WB_IRIDESCENT_OUTLINED":74132,"WB_IRIDESCENT_ROUNDED":74133,"WB_IRIDESCENT_SHARP":74134,"WB_SHADE":74135,"WB_SHADE_OUTLINED":74136,"WB_SHADE_ROUNDED":74137,"WB_SHADE_SHARP":74138,"WB_SUNNY":74139,"WB_SUNNY_OUTLINED":74140,"WB_SUNNY_ROUNDED":74141,"WB_SUNNY_SHARP":74142,"WB_TWIGHLIGHT":74143,"WB_TWILIGHT":74144,"WB_TWILIGHT_OUTLINED":74145,"WB_TWILIGHT_ROUNDED":74146,"WB_TWILIGHT_SHARP":74147,"WC":74148,"WC_OUTLINED":74149,"WC_ROUNDED":74150,"WC_SHARP":74151,"WEB":74152,"WEB_ASSET":74153,"WEB_ASSET_OFF":74154,"WEB_ASSET_OFF_OUTLINED":74155,"WEB_ASSET_OFF_ROUNDED":74156,"WEB_ASSET_OFF_SHARP":74157,"WEB_ASSET_OUTLINED":74158,"WEB_ASSET_ROUNDED":74159,"WEB_ASSET_SHARP":74160,"WEB_OUTLINED":74161,"WEB_ROUNDED":74162,"WEB_SHARP":74163,"WEB_STORIES":74164,"WEB_STORIES_OUTLINED":74165,"WEB_STORIES_ROUNDED":74166,"WEB_STORIES_SHARP":74167,"WEBHOOK":74168,"WEBHOOK_OUTLINED":74169,"WEBHOOK_ROUNDED":74170,"WEBHOOK_SHARP":74171,"WECHAT":74172,"WECHAT_OUTLINED":74173,"WECHAT_ROUNDED":74174,"WECHAT_SHARP":74175,"WEEKEND":74176,"WEEKEND_OUTLINED":74177,"WEEKEND_ROUNDED":74178,"WEEKEND_SHARP":74179,"WEST":74180,"WEST_OUTLINED":74181,"WEST_ROUNDED":74182,"WEST_SHARP":74183,"WHATSHOT":74184,"WHATSHOT_OUTLINED":74185,"WHATSHOT_ROUNDED":74186,"WHATSHOT_SHARP":74187,"WHEELCHAIR_PICKUP":74188,"WHEELCHAIR_PICKUP_OUTLINED":74189,"WHEELCHAIR_PICKUP_ROUNDED":74190,"WHEELCHAIR_PICKUP_SHARP":74191,"WHERE_TO_VOTE":74192,"WHERE_TO_VOTE_OUTLINED":74193,"WHERE_TO_VOTE_ROUNDED":74194,"WHERE_TO_VOTE_SHARP":74195,"WIDGETS":74196,"WIDGETS_OUTLINED":74197,"WIDGETS_ROUNDED":74198,"WIDGETS_SHARP":74199,"WIDTH_FULL":74200,"WIDTH_FULL_OUTLINED":74201,"WIDTH_FULL_ROUNDED":74202,"WIDTH_FULL_SHARP":74203,"WIDTH_NORMAL":74204,"WIDTH_NORMAL_OUTLINED":74205,"WIDTH_NORMAL_ROUNDED":74206,"WIDTH_NORMAL_SHARP":74207,"WIDTH_WIDE":74208,"WIDTH_WIDE_OUTLINED":74209,"WIDTH_WIDE_ROUNDED":74210,"WIDTH_WIDE_SHARP":74211,"WIFI":74212,"WIFI_1_BAR":74213,"WIFI_1_BAR_OUTLINED":74214,"WIFI_1_BAR_ROUNDED":74215,"WIFI_1_BAR_SHARP":74216,"WIFI_2_BAR":74217,"WIFI_2_BAR_OUTLINED":74218,"WIFI_2_BAR_ROUNDED":74219,"WIFI_2_BAR_SHARP":74220,"WIFI_CALLING":74221,"WIFI_CALLING_3":74222,"WIFI_CALLING_3_OUTLINED":74223,"WIFI_CALLING_3_ROUNDED":74224,"WIFI_CALLING_3_SHARP":74225,"WIFI_CALLING_OUTLINED":74226,"WIFI_CALLING_ROUNDED":74227,"WIFI_CALLING_SHARP":74228,"WIFI_CHANNEL":74229,"WIFI_CHANNEL_OUTLINED":74230,"WIFI_CHANNEL_ROUNDED":74231,"WIFI_CHANNEL_SHARP":74232,"WIFI_FIND":74233,"WIFI_FIND_OUTLINED":74234,"WIFI_FIND_ROUNDED":74235,"WIFI_FIND_SHARP":74236,"WIFI_LOCK":74237,"WIFI_LOCK_OUTLINED":74238,"WIFI_LOCK_ROUNDED":74239,"WIFI_LOCK_SHARP":74240,"WIFI_OFF":74241,"WIFI_OFF_OUTLINED":74242,"WIFI_OFF_ROUNDED":74243,"WIFI_OFF_SHARP":74244,"WIFI_OUTLINED":74245,"WIFI_PASSWORD":74246,"WIFI_PASSWORD_OUTLINED":74247,"WIFI_PASSWORD_ROUNDED":74248,"WIFI_PASSWORD_SHARP":74249,"WIFI_PROTECTED_SETUP":74250,"WIFI_PROTECTED_SETUP_OUTLINED":74251,"WIFI_PROTECTED_SETUP_ROUNDED":74252,"WIFI_PROTECTED_SETUP_SHARP":74253,"WIFI_ROUNDED":74254,"WIFI_SHARP":74255,"WIFI_TETHERING":74256,"WIFI_TETHERING_ERROR":74257,"WIFI_TETHERING_ERROR_OUTLINED":74258,"WIFI_TETHERING_ERROR_ROUNDED":74259,"WIFI_TETHERING_ERROR_ROUNDED_OUTLINED":74260,"WIFI_TETHERING_ERROR_ROUNDED_ROUNDED":74261,"WIFI_TETHERING_ERROR_ROUNDED_SHARP":74262,"WIFI_TETHERING_ERROR_SHARP":74263,"WIFI_TETHERING_OFF":74264,"WIFI_TETHERING_OFF_OUTLINED":74265,"WIFI_TETHERING_OFF_ROUNDED":74266,"WIFI_TETHERING_OFF_SHARP":74267,"WIFI_TETHERING_OUTLINED":74268,"WIFI_TETHERING_ROUNDED":74269,"WIFI_TETHERING_SHARP":74270,"WIND_POWER":74271,"WIND_POWER_OUTLINED":74272,"WIND_POWER_ROUNDED":74273,"WIND_POWER_SHARP":74274,"WINDOW":74275,"WINDOW_OUTLINED":74276,"WINDOW_ROUNDED":74277,"WINDOW_SHARP":74278,"WINE_BAR":74279,"WINE_BAR_OUTLINED":74280,"WINE_BAR_ROUNDED":74281,"WINE_BAR_SHARP":74282,"WOMAN":74283,"WOMAN_2":74284,"WOMAN_2_OUTLINED":74285,"WOMAN_2_ROUNDED":74286,"WOMAN_2_SHARP":74287,"WOMAN_OUTLINED":74288,"WOMAN_ROUNDED":74289,"WOMAN_SHARP":74290,"WOO_COMMERCE":74291,"WOO_COMMERCE_OUTLINED":74292,"WOO_COMMERCE_ROUNDED":74293,"WOO_COMMERCE_SHARP":74294,"WORDPRESS":74295,"WORDPRESS_OUTLINED":74296,"WORDPRESS_ROUNDED":74297,"WORDPRESS_SHARP":74298,"WORK":74299,"WORK_HISTORY":74300,"WORK_HISTORY_OUTLINED":74301,"WORK_HISTORY_ROUNDED":74302,"WORK_HISTORY_SHARP":74303,"WORK_OFF":74304,"WORK_OFF_OUTLINED":74305,"WORK_OFF_ROUNDED":74306,"WORK_OFF_SHARP":74307,"WORK_OUTLINE":74308,"WORK_OUTLINE_OUTLINED":74309,"WORK_OUTLINE_ROUNDED":74310,"WORK_OUTLINE_SHARP":74311,"WORK_OUTLINED":74312,"WORK_ROUNDED":74313,"WORK_SHARP":74314,"WORKSPACE_PREMIUM":74315,"WORKSPACE_PREMIUM_OUTLINED":74316,"WORKSPACE_PREMIUM_ROUNDED":74317,"WORKSPACE_PREMIUM_SHARP":74318,"WORKSPACES":74319,"WORKSPACES_FILLED":74320,"WORKSPACES_OUTLINE":74321,"WORKSPACES_OUTLINED":74322,"WORKSPACES_ROUNDED":74323,"WORKSPACES_SHARP":74324,"WRAP_TEXT":74325,"WRAP_TEXT_OUTLINED":74326,"WRAP_TEXT_ROUNDED":74327,"WRAP_TEXT_SHARP":74328,"WRONG_LOCATION":74329,"WRONG_LOCATION_OUTLINED":74330,"WRONG_LOCATION_ROUNDED":74331,"WRONG_LOCATION_SHARP":74332,"WYSIWYG":74333,"WYSIWYG_OUTLINED":74334,"WYSIWYG_ROUNDED":74335,"WYSIWYG_SHARP":74336,"YARD":74337,"YARD_OUTLINED":74338,"YARD_ROUNDED":74339,"YARD_SHARP":74340,"YOUTUBE_SEARCHED_FOR":74341,"YOUTUBE_SEARCHED_FOR_OUTLINED":74342,"YOUTUBE_SEARCHED_FOR_ROUNDED":74343,"YOUTUBE_SEARCHED_FOR_SHARP":74344,"ZOOM_IN":74345,"ZOOM_IN_MAP":74346,"ZOOM_IN_MAP_OUTLINED":74347,"ZOOM_IN_MAP_ROUNDED":74348,"ZOOM_IN_MAP_SHARP":74349,"ZOOM_IN_OUTLINED":74350,"ZOOM_IN_ROUNDED":74351,"ZOOM_IN_SHARP":74352,"ZOOM_OUT":74353,"ZOOM_OUT_MAP":74354,"ZOOM_OUT_MAP_OUTLINED":74355,"ZOOM_OUT_MAP_ROUNDED":74356,"ZOOM_OUT_MAP_SHARP":74357,"ZOOM_OUT_OUTLINED":74358,"ZOOM_OUT_ROUNDED":74359,"ZOOM_OUT_SHARP":74360} diff --git a/sdk/python/packages/flet/src/flet/controls/material/icons.py b/sdk/python/packages/flet/src/flet/controls/material/icons.py new file mode 100644 index 0000000000..88c326fb1a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/icons.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import json +import random +from importlib import resources + +from flet.controls.icon_data import IconData + +__all__ = ["Icons"] + + +class _MaterialIconData(IconData, package_name="flet", class_name="Icons"): + _DUMMY = -1 + + @classmethod + def _missing_(cls, value): + obj = int.__new__(cls, value) + obj._value_ = value + obj._name_ = f"_ICON_{value}" + cls._value2member_map_[value] = obj + return obj + + +_MaterialIconData.__name__ = "Icons" +_MaterialIconData.__qualname__ = "Icons" + + +class _IconsProxy: + __slots__ = ("_map", "_values") + + def __init__(self) -> None: + self._map: dict[str, int] | None = None + self._values: list[_MaterialIconData] | None = None + + def _load(self) -> None: + if self._map is not None: + return + data = ( + resources.files(__package__) + .joinpath("icons.json") + .read_text(encoding="utf-8") + ) + self._map = json.loads(data) + + def _get_member(self, name: str) -> _MaterialIconData: + self._load() + assert self._map is not None + cls = _MaterialIconData + existing = cls._member_map_.get(name) + if existing is not None: + return existing + value = self._map[name] + member = int.__new__(cls, value) + member._value_ = value + member._name_ = name + cls._member_map_[name] = member + cls._value2member_map_[value] = member + cls._member_names_.append(name) + return member + + def _get_values(self) -> list[_MaterialIconData]: + self._load() + if self._values is None: + assert self._map is not None + self._values = [self._get_member(name) for name in self._map] + return self._values + + def __getattr__(self, name: str) -> IconData: + try: + return self._get_member(name) + except KeyError: + raise AttributeError(name) from None + + def __dir__(self) -> list[str]: + self._load() + assert self._map is not None + return sorted(self._map.keys()) + + def __iter__(self): + return iter(self._get_values()) + + def __len__(self) -> int: + self._load() + assert self._map is not None + return len(self._map) + + def random( + self, + exclude: list[IconData] | None = None, + weights: dict[IconData, int] | None = None, + ) -> IconData | None: + choices = list(self._get_values()) + if exclude: + excluded = set(exclude) + choices = [icon for icon in choices if icon not in excluded] + if not choices: + return None + if weights: + weights_list = [weights.get(icon, 1) for icon in choices] + return random.choices(choices, weights=weights_list)[0] + return random.choice(choices) + + +Icons = _IconsProxy() diff --git a/sdk/python/packages/flet/src/flet/controls/material/icons.pyi b/sdk/python/packages/flet/src/flet/controls/material/icons.pyi new file mode 100644 index 0000000000..69f2e2c792 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/icons.pyi @@ -0,0 +1,8840 @@ +""" +Flet Material Icons Stub + +To generate/update this file run from the root of the repository: + +``` +uv run .github/scripts/generate_icons.py +``` +""" + +from flet.controls.icon_data import IconData + +__all__ = ["Icons"] + +class Icons: + ABC: IconData + ABC_OUTLINED: IconData + ABC_ROUNDED: IconData + ABC_SHARP: IconData + AC_UNIT: IconData + AC_UNIT_OUTLINED: IconData + AC_UNIT_ROUNDED: IconData + AC_UNIT_SHARP: IconData + ACCESS_ALARM: IconData + ACCESS_ALARM_OUTLINED: IconData + ACCESS_ALARM_ROUNDED: IconData + ACCESS_ALARM_SHARP: IconData + ACCESS_ALARMS: IconData + ACCESS_ALARMS_OUTLINED: IconData + ACCESS_ALARMS_ROUNDED: IconData + ACCESS_ALARMS_SHARP: IconData + ACCESS_TIME: IconData + ACCESS_TIME_FILLED: IconData + ACCESS_TIME_FILLED_OUTLINED: IconData + ACCESS_TIME_FILLED_ROUNDED: IconData + ACCESS_TIME_FILLED_SHARP: IconData + ACCESS_TIME_OUTLINED: IconData + ACCESS_TIME_ROUNDED: IconData + ACCESS_TIME_SHARP: IconData + ACCESSIBILITY: IconData + ACCESSIBILITY_NEW: IconData + ACCESSIBILITY_NEW_OUTLINED: IconData + ACCESSIBILITY_NEW_ROUNDED: IconData + ACCESSIBILITY_NEW_SHARP: IconData + ACCESSIBILITY_OUTLINED: IconData + ACCESSIBILITY_ROUNDED: IconData + ACCESSIBILITY_SHARP: IconData + ACCESSIBLE: IconData + ACCESSIBLE_FORWARD: IconData + ACCESSIBLE_FORWARD_OUTLINED: IconData + ACCESSIBLE_FORWARD_ROUNDED: IconData + ACCESSIBLE_FORWARD_SHARP: IconData + ACCESSIBLE_OUTLINED: IconData + ACCESSIBLE_ROUNDED: IconData + ACCESSIBLE_SHARP: IconData + ACCOUNT_BALANCE: IconData + ACCOUNT_BALANCE_OUTLINED: IconData + ACCOUNT_BALANCE_ROUNDED: IconData + ACCOUNT_BALANCE_SHARP: IconData + ACCOUNT_BALANCE_WALLET: IconData + ACCOUNT_BALANCE_WALLET_OUTLINED: IconData + ACCOUNT_BALANCE_WALLET_ROUNDED: IconData + ACCOUNT_BALANCE_WALLET_SHARP: IconData + ACCOUNT_BOX: IconData + ACCOUNT_BOX_OUTLINED: IconData + ACCOUNT_BOX_ROUNDED: IconData + ACCOUNT_BOX_SHARP: IconData + ACCOUNT_CIRCLE: IconData + ACCOUNT_CIRCLE_OUTLINED: IconData + ACCOUNT_CIRCLE_ROUNDED: IconData + ACCOUNT_CIRCLE_SHARP: IconData + ACCOUNT_TREE: IconData + ACCOUNT_TREE_OUTLINED: IconData + ACCOUNT_TREE_ROUNDED: IconData + ACCOUNT_TREE_SHARP: IconData + AD_UNITS: IconData + AD_UNITS_OUTLINED: IconData + AD_UNITS_ROUNDED: IconData + AD_UNITS_SHARP: IconData + ADB: IconData + ADB_OUTLINED: IconData + ADB_ROUNDED: IconData + ADB_SHARP: IconData + ADD: IconData + ADD_A_PHOTO: IconData + ADD_A_PHOTO_OUTLINED: IconData + ADD_A_PHOTO_ROUNDED: IconData + ADD_A_PHOTO_SHARP: IconData + ADD_ALARM: IconData + ADD_ALARM_OUTLINED: IconData + ADD_ALARM_ROUNDED: IconData + ADD_ALARM_SHARP: IconData + ADD_ALERT: IconData + ADD_ALERT_OUTLINED: IconData + ADD_ALERT_ROUNDED: IconData + ADD_ALERT_SHARP: IconData + ADD_BOX: IconData + ADD_BOX_OUTLINED: IconData + ADD_BOX_ROUNDED: IconData + ADD_BOX_SHARP: IconData + ADD_BUSINESS: IconData + ADD_BUSINESS_OUTLINED: IconData + ADD_BUSINESS_ROUNDED: IconData + ADD_BUSINESS_SHARP: IconData + ADD_CALL: IconData + ADD_CARD: IconData + ADD_CARD_OUTLINED: IconData + ADD_CARD_ROUNDED: IconData + ADD_CARD_SHARP: IconData + ADD_CHART: IconData + ADD_CHART_OUTLINED: IconData + ADD_CHART_ROUNDED: IconData + ADD_CHART_SHARP: IconData + ADD_CIRCLE: IconData + ADD_CIRCLE_OUTLINE: IconData + ADD_CIRCLE_OUTLINE_OUTLINED: IconData + ADD_CIRCLE_OUTLINE_ROUNDED: IconData + ADD_CIRCLE_OUTLINE_SHARP: IconData + ADD_CIRCLE_OUTLINED: IconData + ADD_CIRCLE_ROUNDED: IconData + ADD_CIRCLE_SHARP: IconData + ADD_COMMENT: IconData + ADD_COMMENT_OUTLINED: IconData + ADD_COMMENT_ROUNDED: IconData + ADD_COMMENT_SHARP: IconData + ADD_HOME: IconData + ADD_HOME_OUTLINED: IconData + ADD_HOME_ROUNDED: IconData + ADD_HOME_SHARP: IconData + ADD_HOME_WORK: IconData + ADD_HOME_WORK_OUTLINED: IconData + ADD_HOME_WORK_ROUNDED: IconData + ADD_HOME_WORK_SHARP: IconData + ADD_IC_CALL: IconData + ADD_IC_CALL_OUTLINED: IconData + ADD_IC_CALL_ROUNDED: IconData + ADD_IC_CALL_SHARP: IconData + ADD_LINK: IconData + ADD_LINK_OUTLINED: IconData + ADD_LINK_ROUNDED: IconData + ADD_LINK_SHARP: IconData + ADD_LOCATION: IconData + ADD_LOCATION_ALT: IconData + ADD_LOCATION_ALT_OUTLINED: IconData + ADD_LOCATION_ALT_ROUNDED: IconData + ADD_LOCATION_ALT_SHARP: IconData + ADD_LOCATION_OUTLINED: IconData + ADD_LOCATION_ROUNDED: IconData + ADD_LOCATION_SHARP: IconData + ADD_MODERATOR: IconData + ADD_MODERATOR_OUTLINED: IconData + ADD_MODERATOR_ROUNDED: IconData + ADD_MODERATOR_SHARP: IconData + ADD_OUTLINED: IconData + ADD_PHOTO_ALTERNATE: IconData + ADD_PHOTO_ALTERNATE_OUTLINED: IconData + ADD_PHOTO_ALTERNATE_ROUNDED: IconData + ADD_PHOTO_ALTERNATE_SHARP: IconData + ADD_REACTION: IconData + ADD_REACTION_OUTLINED: IconData + ADD_REACTION_ROUNDED: IconData + ADD_REACTION_SHARP: IconData + ADD_ROAD: IconData + ADD_ROAD_OUTLINED: IconData + ADD_ROAD_ROUNDED: IconData + ADD_ROAD_SHARP: IconData + ADD_ROUNDED: IconData + ADD_SHARP: IconData + ADD_SHOPPING_CART: IconData + ADD_SHOPPING_CART_OUTLINED: IconData + ADD_SHOPPING_CART_ROUNDED: IconData + ADD_SHOPPING_CART_SHARP: IconData + ADD_TASK: IconData + ADD_TASK_OUTLINED: IconData + ADD_TASK_ROUNDED: IconData + ADD_TASK_SHARP: IconData + ADD_TO_DRIVE: IconData + ADD_TO_DRIVE_OUTLINED: IconData + ADD_TO_DRIVE_ROUNDED: IconData + ADD_TO_DRIVE_SHARP: IconData + ADD_TO_HOME_SCREEN: IconData + ADD_TO_HOME_SCREEN_OUTLINED: IconData + ADD_TO_HOME_SCREEN_ROUNDED: IconData + ADD_TO_HOME_SCREEN_SHARP: IconData + ADD_TO_PHOTOS: IconData + ADD_TO_PHOTOS_OUTLINED: IconData + ADD_TO_PHOTOS_ROUNDED: IconData + ADD_TO_PHOTOS_SHARP: IconData + ADD_TO_QUEUE: IconData + ADD_TO_QUEUE_OUTLINED: IconData + ADD_TO_QUEUE_ROUNDED: IconData + ADD_TO_QUEUE_SHARP: IconData + ADDCHART: IconData + ADDCHART_OUTLINED: IconData + ADDCHART_ROUNDED: IconData + ADDCHART_SHARP: IconData + ADF_SCANNER: IconData + ADF_SCANNER_OUTLINED: IconData + ADF_SCANNER_ROUNDED: IconData + ADF_SCANNER_SHARP: IconData + ADJUST: IconData + ADJUST_OUTLINED: IconData + ADJUST_ROUNDED: IconData + ADJUST_SHARP: IconData + ADMIN_PANEL_SETTINGS: IconData + ADMIN_PANEL_SETTINGS_OUTLINED: IconData + ADMIN_PANEL_SETTINGS_ROUNDED: IconData + ADMIN_PANEL_SETTINGS_SHARP: IconData + ADOBE: IconData + ADOBE_OUTLINED: IconData + ADOBE_ROUNDED: IconData + ADOBE_SHARP: IconData + ADS_CLICK: IconData + ADS_CLICK_OUTLINED: IconData + ADS_CLICK_ROUNDED: IconData + ADS_CLICK_SHARP: IconData + AGRICULTURE: IconData + AGRICULTURE_OUTLINED: IconData + AGRICULTURE_ROUNDED: IconData + AGRICULTURE_SHARP: IconData + AIR: IconData + AIR_OUTLINED: IconData + AIR_ROUNDED: IconData + AIR_SHARP: IconData + AIRLINE_SEAT_FLAT: IconData + AIRLINE_SEAT_FLAT_ANGLED: IconData + AIRLINE_SEAT_FLAT_ANGLED_OUTLINED: IconData + AIRLINE_SEAT_FLAT_ANGLED_ROUNDED: IconData + AIRLINE_SEAT_FLAT_ANGLED_SHARP: IconData + AIRLINE_SEAT_FLAT_OUTLINED: IconData + AIRLINE_SEAT_FLAT_ROUNDED: IconData + AIRLINE_SEAT_FLAT_SHARP: IconData + AIRLINE_SEAT_INDIVIDUAL_SUITE: IconData + AIRLINE_SEAT_INDIVIDUAL_SUITE_OUTLINED: IconData + AIRLINE_SEAT_INDIVIDUAL_SUITE_ROUNDED: IconData + AIRLINE_SEAT_INDIVIDUAL_SUITE_SHARP: IconData + AIRLINE_SEAT_LEGROOM_EXTRA: IconData + AIRLINE_SEAT_LEGROOM_EXTRA_OUTLINED: IconData + AIRLINE_SEAT_LEGROOM_EXTRA_ROUNDED: IconData + AIRLINE_SEAT_LEGROOM_EXTRA_SHARP: IconData + AIRLINE_SEAT_LEGROOM_NORMAL: IconData + AIRLINE_SEAT_LEGROOM_NORMAL_OUTLINED: IconData + AIRLINE_SEAT_LEGROOM_NORMAL_ROUNDED: IconData + AIRLINE_SEAT_LEGROOM_NORMAL_SHARP: IconData + AIRLINE_SEAT_LEGROOM_REDUCED: IconData + AIRLINE_SEAT_LEGROOM_REDUCED_OUTLINED: IconData + AIRLINE_SEAT_LEGROOM_REDUCED_ROUNDED: IconData + AIRLINE_SEAT_LEGROOM_REDUCED_SHARP: IconData + AIRLINE_SEAT_RECLINE_EXTRA: IconData + AIRLINE_SEAT_RECLINE_EXTRA_OUTLINED: IconData + AIRLINE_SEAT_RECLINE_EXTRA_ROUNDED: IconData + AIRLINE_SEAT_RECLINE_EXTRA_SHARP: IconData + AIRLINE_SEAT_RECLINE_NORMAL: IconData + AIRLINE_SEAT_RECLINE_NORMAL_OUTLINED: IconData + AIRLINE_SEAT_RECLINE_NORMAL_ROUNDED: IconData + AIRLINE_SEAT_RECLINE_NORMAL_SHARP: IconData + AIRLINE_STOPS: IconData + AIRLINE_STOPS_OUTLINED: IconData + AIRLINE_STOPS_ROUNDED: IconData + AIRLINE_STOPS_SHARP: IconData + AIRLINES: IconData + AIRLINES_OUTLINED: IconData + AIRLINES_ROUNDED: IconData + AIRLINES_SHARP: IconData + AIRPLANE_TICKET: IconData + AIRPLANE_TICKET_OUTLINED: IconData + AIRPLANE_TICKET_ROUNDED: IconData + AIRPLANE_TICKET_SHARP: IconData + AIRPLANEMODE_ACTIVE: IconData + AIRPLANEMODE_ACTIVE_OUTLINED: IconData + AIRPLANEMODE_ACTIVE_ROUNDED: IconData + AIRPLANEMODE_ACTIVE_SHARP: IconData + AIRPLANEMODE_INACTIVE: IconData + AIRPLANEMODE_INACTIVE_OUTLINED: IconData + AIRPLANEMODE_INACTIVE_ROUNDED: IconData + AIRPLANEMODE_INACTIVE_SHARP: IconData + AIRPLANEMODE_OFF: IconData + AIRPLANEMODE_OFF_OUTLINED: IconData + AIRPLANEMODE_OFF_ROUNDED: IconData + AIRPLANEMODE_OFF_SHARP: IconData + AIRPLANEMODE_ON: IconData + AIRPLANEMODE_ON_OUTLINED: IconData + AIRPLANEMODE_ON_ROUNDED: IconData + AIRPLANEMODE_ON_SHARP: IconData + AIRPLAY: IconData + AIRPLAY_OUTLINED: IconData + AIRPLAY_ROUNDED: IconData + AIRPLAY_SHARP: IconData + AIRPORT_SHUTTLE: IconData + AIRPORT_SHUTTLE_OUTLINED: IconData + AIRPORT_SHUTTLE_ROUNDED: IconData + AIRPORT_SHUTTLE_SHARP: IconData + ALARM: IconData + ALARM_ADD: IconData + ALARM_ADD_OUTLINED: IconData + ALARM_ADD_ROUNDED: IconData + ALARM_ADD_SHARP: IconData + ALARM_OFF: IconData + ALARM_OFF_OUTLINED: IconData + ALARM_OFF_ROUNDED: IconData + ALARM_OFF_SHARP: IconData + ALARM_ON: IconData + ALARM_ON_OUTLINED: IconData + ALARM_ON_ROUNDED: IconData + ALARM_ON_SHARP: IconData + ALARM_OUTLINED: IconData + ALARM_ROUNDED: IconData + ALARM_SHARP: IconData + ALBUM: IconData + ALBUM_OUTLINED: IconData + ALBUM_ROUNDED: IconData + ALBUM_SHARP: IconData + ALIGN_HORIZONTAL_CENTER: IconData + ALIGN_HORIZONTAL_CENTER_OUTLINED: IconData + ALIGN_HORIZONTAL_CENTER_ROUNDED: IconData + ALIGN_HORIZONTAL_CENTER_SHARP: IconData + ALIGN_HORIZONTAL_LEFT: IconData + ALIGN_HORIZONTAL_LEFT_OUTLINED: IconData + ALIGN_HORIZONTAL_LEFT_ROUNDED: IconData + ALIGN_HORIZONTAL_LEFT_SHARP: IconData + ALIGN_HORIZONTAL_RIGHT: IconData + ALIGN_HORIZONTAL_RIGHT_OUTLINED: IconData + ALIGN_HORIZONTAL_RIGHT_ROUNDED: IconData + ALIGN_HORIZONTAL_RIGHT_SHARP: IconData + ALIGN_VERTICAL_BOTTOM: IconData + ALIGN_VERTICAL_BOTTOM_OUTLINED: IconData + ALIGN_VERTICAL_BOTTOM_ROUNDED: IconData + ALIGN_VERTICAL_BOTTOM_SHARP: IconData + ALIGN_VERTICAL_CENTER: IconData + ALIGN_VERTICAL_CENTER_OUTLINED: IconData + ALIGN_VERTICAL_CENTER_ROUNDED: IconData + ALIGN_VERTICAL_CENTER_SHARP: IconData + ALIGN_VERTICAL_TOP: IconData + ALIGN_VERTICAL_TOP_OUTLINED: IconData + ALIGN_VERTICAL_TOP_ROUNDED: IconData + ALIGN_VERTICAL_TOP_SHARP: IconData + ALL_INBOX: IconData + ALL_INBOX_OUTLINED: IconData + ALL_INBOX_ROUNDED: IconData + ALL_INBOX_SHARP: IconData + ALL_INCLUSIVE: IconData + ALL_INCLUSIVE_OUTLINED: IconData + ALL_INCLUSIVE_ROUNDED: IconData + ALL_INCLUSIVE_SHARP: IconData + ALL_OUT: IconData + ALL_OUT_OUTLINED: IconData + ALL_OUT_ROUNDED: IconData + ALL_OUT_SHARP: IconData + ALT_ROUTE: IconData + ALT_ROUTE_OUTLINED: IconData + ALT_ROUTE_ROUNDED: IconData + ALT_ROUTE_SHARP: IconData + ALTERNATE_EMAIL: IconData + ALTERNATE_EMAIL_OUTLINED: IconData + ALTERNATE_EMAIL_ROUNDED: IconData + ALTERNATE_EMAIL_SHARP: IconData + AMP_STORIES: IconData + AMP_STORIES_OUTLINED: IconData + AMP_STORIES_ROUNDED: IconData + AMP_STORIES_SHARP: IconData + ANALYTICS: IconData + ANALYTICS_OUTLINED: IconData + ANALYTICS_ROUNDED: IconData + ANALYTICS_SHARP: IconData + ANCHOR: IconData + ANCHOR_OUTLINED: IconData + ANCHOR_ROUNDED: IconData + ANCHOR_SHARP: IconData + ANDROID: IconData + ANDROID_OUTLINED: IconData + ANDROID_ROUNDED: IconData + ANDROID_SHARP: IconData + ANIMATION: IconData + ANIMATION_OUTLINED: IconData + ANIMATION_ROUNDED: IconData + ANIMATION_SHARP: IconData + ANNOUNCEMENT: IconData + ANNOUNCEMENT_OUTLINED: IconData + ANNOUNCEMENT_ROUNDED: IconData + ANNOUNCEMENT_SHARP: IconData + AOD: IconData + AOD_OUTLINED: IconData + AOD_ROUNDED: IconData + AOD_SHARP: IconData + APARTMENT: IconData + APARTMENT_OUTLINED: IconData + APARTMENT_ROUNDED: IconData + APARTMENT_SHARP: IconData + API: IconData + API_OUTLINED: IconData + API_ROUNDED: IconData + API_SHARP: IconData + APP_BLOCKING: IconData + APP_BLOCKING_OUTLINED: IconData + APP_BLOCKING_ROUNDED: IconData + APP_BLOCKING_SHARP: IconData + APP_REGISTRATION: IconData + APP_REGISTRATION_OUTLINED: IconData + APP_REGISTRATION_ROUNDED: IconData + APP_REGISTRATION_SHARP: IconData + APP_SETTINGS_ALT: IconData + APP_SETTINGS_ALT_OUTLINED: IconData + APP_SETTINGS_ALT_ROUNDED: IconData + APP_SETTINGS_ALT_SHARP: IconData + APP_SHORTCUT: IconData + APP_SHORTCUT_OUTLINED: IconData + APP_SHORTCUT_ROUNDED: IconData + APP_SHORTCUT_SHARP: IconData + APPLE: IconData + APPLE_OUTLINED: IconData + APPLE_ROUNDED: IconData + APPLE_SHARP: IconData + APPROVAL: IconData + APPROVAL_OUTLINED: IconData + APPROVAL_ROUNDED: IconData + APPROVAL_SHARP: IconData + APPS: IconData + APPS_OUTAGE: IconData + APPS_OUTAGE_OUTLINED: IconData + APPS_OUTAGE_ROUNDED: IconData + APPS_OUTAGE_SHARP: IconData + APPS_OUTLINED: IconData + APPS_ROUNDED: IconData + APPS_SHARP: IconData + ARCHITECTURE: IconData + ARCHITECTURE_OUTLINED: IconData + ARCHITECTURE_ROUNDED: IconData + ARCHITECTURE_SHARP: IconData + ARCHIVE: IconData + ARCHIVE_OUTLINED: IconData + ARCHIVE_ROUNDED: IconData + ARCHIVE_SHARP: IconData + AREA_CHART: IconData + AREA_CHART_OUTLINED: IconData + AREA_CHART_ROUNDED: IconData + AREA_CHART_SHARP: IconData + ARROW_BACK: IconData + ARROW_BACK_IOS: IconData + ARROW_BACK_IOS_NEW: IconData + ARROW_BACK_IOS_NEW_OUTLINED: IconData + ARROW_BACK_IOS_NEW_ROUNDED: IconData + ARROW_BACK_IOS_NEW_SHARP: IconData + ARROW_BACK_IOS_OUTLINED: IconData + ARROW_BACK_IOS_ROUNDED: IconData + ARROW_BACK_IOS_SHARP: IconData + ARROW_BACK_OUTLINED: IconData + ARROW_BACK_ROUNDED: IconData + ARROW_BACK_SHARP: IconData + ARROW_CIRCLE_DOWN: IconData + ARROW_CIRCLE_DOWN_OUTLINED: IconData + ARROW_CIRCLE_DOWN_ROUNDED: IconData + ARROW_CIRCLE_DOWN_SHARP: IconData + ARROW_CIRCLE_LEFT: IconData + ARROW_CIRCLE_LEFT_OUTLINED: IconData + ARROW_CIRCLE_LEFT_ROUNDED: IconData + ARROW_CIRCLE_LEFT_SHARP: IconData + ARROW_CIRCLE_RIGHT: IconData + ARROW_CIRCLE_RIGHT_OUTLINED: IconData + ARROW_CIRCLE_RIGHT_ROUNDED: IconData + ARROW_CIRCLE_RIGHT_SHARP: IconData + ARROW_CIRCLE_UP: IconData + ARROW_CIRCLE_UP_OUTLINED: IconData + ARROW_CIRCLE_UP_ROUNDED: IconData + ARROW_CIRCLE_UP_SHARP: IconData + ARROW_DOWNWARD: IconData + ARROW_DOWNWARD_OUTLINED: IconData + ARROW_DOWNWARD_ROUNDED: IconData + ARROW_DOWNWARD_SHARP: IconData + ARROW_DROP_DOWN: IconData + ARROW_DROP_DOWN_CIRCLE: IconData + ARROW_DROP_DOWN_CIRCLE_OUTLINED: IconData + ARROW_DROP_DOWN_CIRCLE_ROUNDED: IconData + ARROW_DROP_DOWN_CIRCLE_SHARP: IconData + ARROW_DROP_DOWN_OUTLINED: IconData + ARROW_DROP_DOWN_ROUNDED: IconData + ARROW_DROP_DOWN_SHARP: IconData + ARROW_DROP_UP: IconData + ARROW_DROP_UP_OUTLINED: IconData + ARROW_DROP_UP_ROUNDED: IconData + ARROW_DROP_UP_SHARP: IconData + ARROW_FORWARD: IconData + ARROW_FORWARD_IOS: IconData + ARROW_FORWARD_IOS_OUTLINED: IconData + ARROW_FORWARD_IOS_ROUNDED: IconData + ARROW_FORWARD_IOS_SHARP: IconData + ARROW_FORWARD_OUTLINED: IconData + ARROW_FORWARD_ROUNDED: IconData + ARROW_FORWARD_SHARP: IconData + ARROW_LEFT: IconData + ARROW_LEFT_OUTLINED: IconData + ARROW_LEFT_ROUNDED: IconData + ARROW_LEFT_SHARP: IconData + ARROW_OUTWARD: IconData + ARROW_OUTWARD_OUTLINED: IconData + ARROW_OUTWARD_ROUNDED: IconData + ARROW_OUTWARD_SHARP: IconData + ARROW_RIGHT: IconData + ARROW_RIGHT_ALT: IconData + ARROW_RIGHT_ALT_OUTLINED: IconData + ARROW_RIGHT_ALT_ROUNDED: IconData + ARROW_RIGHT_ALT_SHARP: IconData + ARROW_RIGHT_OUTLINED: IconData + ARROW_RIGHT_ROUNDED: IconData + ARROW_RIGHT_SHARP: IconData + ARROW_UPWARD: IconData + ARROW_UPWARD_OUTLINED: IconData + ARROW_UPWARD_ROUNDED: IconData + ARROW_UPWARD_SHARP: IconData + ART_TRACK: IconData + ART_TRACK_OUTLINED: IconData + ART_TRACK_ROUNDED: IconData + ART_TRACK_SHARP: IconData + ARTICLE: IconData + ARTICLE_OUTLINED: IconData + ARTICLE_ROUNDED: IconData + ARTICLE_SHARP: IconData + ASPECT_RATIO: IconData + ASPECT_RATIO_OUTLINED: IconData + ASPECT_RATIO_ROUNDED: IconData + ASPECT_RATIO_SHARP: IconData + ASSESSMENT: IconData + ASSESSMENT_OUTLINED: IconData + ASSESSMENT_ROUNDED: IconData + ASSESSMENT_SHARP: IconData + ASSIGNMENT: IconData + ASSIGNMENT_ADD: IconData + ASSIGNMENT_IND: IconData + ASSIGNMENT_IND_OUTLINED: IconData + ASSIGNMENT_IND_ROUNDED: IconData + ASSIGNMENT_IND_SHARP: IconData + ASSIGNMENT_LATE: IconData + ASSIGNMENT_LATE_OUTLINED: IconData + ASSIGNMENT_LATE_ROUNDED: IconData + ASSIGNMENT_LATE_SHARP: IconData + ASSIGNMENT_OUTLINED: IconData + ASSIGNMENT_RETURN: IconData + ASSIGNMENT_RETURN_OUTLINED: IconData + ASSIGNMENT_RETURN_ROUNDED: IconData + ASSIGNMENT_RETURN_SHARP: IconData + ASSIGNMENT_RETURNED: IconData + ASSIGNMENT_RETURNED_OUTLINED: IconData + ASSIGNMENT_RETURNED_ROUNDED: IconData + ASSIGNMENT_RETURNED_SHARP: IconData + ASSIGNMENT_ROUNDED: IconData + ASSIGNMENT_SHARP: IconData + ASSIGNMENT_TURNED_IN: IconData + ASSIGNMENT_TURNED_IN_OUTLINED: IconData + ASSIGNMENT_TURNED_IN_ROUNDED: IconData + ASSIGNMENT_TURNED_IN_SHARP: IconData + ASSIST_WALKER: IconData + ASSIST_WALKER_OUTLINED: IconData + ASSIST_WALKER_ROUNDED: IconData + ASSIST_WALKER_SHARP: IconData + ASSISTANT: IconData + ASSISTANT_DIRECTION: IconData + ASSISTANT_DIRECTION_OUTLINED: IconData + ASSISTANT_DIRECTION_ROUNDED: IconData + ASSISTANT_DIRECTION_SHARP: IconData + ASSISTANT_NAVIGATION: IconData + ASSISTANT_OUTLINED: IconData + ASSISTANT_PHOTO: IconData + ASSISTANT_PHOTO_OUTLINED: IconData + ASSISTANT_PHOTO_ROUNDED: IconData + ASSISTANT_PHOTO_SHARP: IconData + ASSISTANT_ROUNDED: IconData + ASSISTANT_SHARP: IconData + ASSURED_WORKLOAD: IconData + ASSURED_WORKLOAD_OUTLINED: IconData + ASSURED_WORKLOAD_ROUNDED: IconData + ASSURED_WORKLOAD_SHARP: IconData + ATM: IconData + ATM_OUTLINED: IconData + ATM_ROUNDED: IconData + ATM_SHARP: IconData + ATTACH_EMAIL: IconData + ATTACH_EMAIL_OUTLINED: IconData + ATTACH_EMAIL_ROUNDED: IconData + ATTACH_EMAIL_SHARP: IconData + ATTACH_FILE: IconData + ATTACH_FILE_OUTLINED: IconData + ATTACH_FILE_ROUNDED: IconData + ATTACH_FILE_SHARP: IconData + ATTACH_MONEY: IconData + ATTACH_MONEY_OUTLINED: IconData + ATTACH_MONEY_ROUNDED: IconData + ATTACH_MONEY_SHARP: IconData + ATTACHMENT: IconData + ATTACHMENT_OUTLINED: IconData + ATTACHMENT_ROUNDED: IconData + ATTACHMENT_SHARP: IconData + ATTRACTIONS: IconData + ATTRACTIONS_OUTLINED: IconData + ATTRACTIONS_ROUNDED: IconData + ATTRACTIONS_SHARP: IconData + ATTRIBUTION: IconData + ATTRIBUTION_OUTLINED: IconData + ATTRIBUTION_ROUNDED: IconData + ATTRIBUTION_SHARP: IconData + AUDIO_FILE: IconData + AUDIO_FILE_OUTLINED: IconData + AUDIO_FILE_ROUNDED: IconData + AUDIO_FILE_SHARP: IconData + AUDIOTRACK: IconData + AUDIOTRACK_OUTLINED: IconData + AUDIOTRACK_ROUNDED: IconData + AUDIOTRACK_SHARP: IconData + AUTO_AWESOME: IconData + AUTO_AWESOME_MOSAIC: IconData + AUTO_AWESOME_MOSAIC_OUTLINED: IconData + AUTO_AWESOME_MOSAIC_ROUNDED: IconData + AUTO_AWESOME_MOSAIC_SHARP: IconData + AUTO_AWESOME_MOTION: IconData + AUTO_AWESOME_MOTION_OUTLINED: IconData + AUTO_AWESOME_MOTION_ROUNDED: IconData + AUTO_AWESOME_MOTION_SHARP: IconData + AUTO_AWESOME_OUTLINED: IconData + AUTO_AWESOME_ROUNDED: IconData + AUTO_AWESOME_SHARP: IconData + AUTO_DELETE: IconData + AUTO_DELETE_OUTLINED: IconData + AUTO_DELETE_ROUNDED: IconData + AUTO_DELETE_SHARP: IconData + AUTO_FIX_HIGH: IconData + AUTO_FIX_HIGH_OUTLINED: IconData + AUTO_FIX_HIGH_ROUNDED: IconData + AUTO_FIX_HIGH_SHARP: IconData + AUTO_FIX_NORMAL: IconData + AUTO_FIX_NORMAL_OUTLINED: IconData + AUTO_FIX_NORMAL_ROUNDED: IconData + AUTO_FIX_NORMAL_SHARP: IconData + AUTO_FIX_OFF: IconData + AUTO_FIX_OFF_OUTLINED: IconData + AUTO_FIX_OFF_ROUNDED: IconData + AUTO_FIX_OFF_SHARP: IconData + AUTO_GRAPH: IconData + AUTO_GRAPH_OUTLINED: IconData + AUTO_GRAPH_ROUNDED: IconData + AUTO_GRAPH_SHARP: IconData + AUTO_MODE: IconData + AUTO_MODE_OUTLINED: IconData + AUTO_MODE_ROUNDED: IconData + AUTO_MODE_SHARP: IconData + AUTO_STORIES: IconData + AUTO_STORIES_OUTLINED: IconData + AUTO_STORIES_ROUNDED: IconData + AUTO_STORIES_SHARP: IconData + AUTOFPS_SELECT: IconData + AUTOFPS_SELECT_OUTLINED: IconData + AUTOFPS_SELECT_ROUNDED: IconData + AUTOFPS_SELECT_SHARP: IconData + AUTORENEW: IconData + AUTORENEW_OUTLINED: IconData + AUTORENEW_ROUNDED: IconData + AUTORENEW_SHARP: IconData + AV_TIMER: IconData + AV_TIMER_OUTLINED: IconData + AV_TIMER_ROUNDED: IconData + AV_TIMER_SHARP: IconData + BABY_CHANGING_STATION: IconData + BABY_CHANGING_STATION_OUTLINED: IconData + BABY_CHANGING_STATION_ROUNDED: IconData + BABY_CHANGING_STATION_SHARP: IconData + BACK_HAND: IconData + BACK_HAND_OUTLINED: IconData + BACK_HAND_ROUNDED: IconData + BACK_HAND_SHARP: IconData + BACKPACK: IconData + BACKPACK_OUTLINED: IconData + BACKPACK_ROUNDED: IconData + BACKPACK_SHARP: IconData + BACKSPACE: IconData + BACKSPACE_OUTLINED: IconData + BACKSPACE_ROUNDED: IconData + BACKSPACE_SHARP: IconData + BACKUP: IconData + BACKUP_OUTLINED: IconData + BACKUP_ROUNDED: IconData + BACKUP_SHARP: IconData + BACKUP_TABLE: IconData + BACKUP_TABLE_OUTLINED: IconData + BACKUP_TABLE_ROUNDED: IconData + BACKUP_TABLE_SHARP: IconData + BADGE: IconData + BADGE_OUTLINED: IconData + BADGE_ROUNDED: IconData + BADGE_SHARP: IconData + BAKERY_DINING: IconData + BAKERY_DINING_OUTLINED: IconData + BAKERY_DINING_ROUNDED: IconData + BAKERY_DINING_SHARP: IconData + BALANCE: IconData + BALANCE_OUTLINED: IconData + BALANCE_ROUNDED: IconData + BALANCE_SHARP: IconData + BALCONY: IconData + BALCONY_OUTLINED: IconData + BALCONY_ROUNDED: IconData + BALCONY_SHARP: IconData + BALLOT: IconData + BALLOT_OUTLINED: IconData + BALLOT_ROUNDED: IconData + BALLOT_SHARP: IconData + BAR_CHART: IconData + BAR_CHART_OUTLINED: IconData + BAR_CHART_ROUNDED: IconData + BAR_CHART_SHARP: IconData + BARCODE_READER: IconData + BATCH_PREDICTION: IconData + BATCH_PREDICTION_OUTLINED: IconData + BATCH_PREDICTION_ROUNDED: IconData + BATCH_PREDICTION_SHARP: IconData + BATHROOM: IconData + BATHROOM_OUTLINED: IconData + BATHROOM_ROUNDED: IconData + BATHROOM_SHARP: IconData + BATHTUB: IconData + BATHTUB_OUTLINED: IconData + BATHTUB_ROUNDED: IconData + BATHTUB_SHARP: IconData + BATTERY_0_BAR: IconData + BATTERY_0_BAR_OUTLINED: IconData + BATTERY_0_BAR_ROUNDED: IconData + BATTERY_0_BAR_SHARP: IconData + BATTERY_1_BAR: IconData + BATTERY_1_BAR_OUTLINED: IconData + BATTERY_1_BAR_ROUNDED: IconData + BATTERY_1_BAR_SHARP: IconData + BATTERY_2_BAR: IconData + BATTERY_2_BAR_OUTLINED: IconData + BATTERY_2_BAR_ROUNDED: IconData + BATTERY_2_BAR_SHARP: IconData + BATTERY_3_BAR: IconData + BATTERY_3_BAR_OUTLINED: IconData + BATTERY_3_BAR_ROUNDED: IconData + BATTERY_3_BAR_SHARP: IconData + BATTERY_4_BAR: IconData + BATTERY_4_BAR_OUTLINED: IconData + BATTERY_4_BAR_ROUNDED: IconData + BATTERY_4_BAR_SHARP: IconData + BATTERY_5_BAR: IconData + BATTERY_5_BAR_OUTLINED: IconData + BATTERY_5_BAR_ROUNDED: IconData + BATTERY_5_BAR_SHARP: IconData + BATTERY_6_BAR: IconData + BATTERY_6_BAR_OUTLINED: IconData + BATTERY_6_BAR_ROUNDED: IconData + BATTERY_6_BAR_SHARP: IconData + BATTERY_ALERT: IconData + BATTERY_ALERT_OUTLINED: IconData + BATTERY_ALERT_ROUNDED: IconData + BATTERY_ALERT_SHARP: IconData + BATTERY_CHARGING_FULL: IconData + BATTERY_CHARGING_FULL_OUTLINED: IconData + BATTERY_CHARGING_FULL_ROUNDED: IconData + BATTERY_CHARGING_FULL_SHARP: IconData + BATTERY_FULL: IconData + BATTERY_FULL_OUTLINED: IconData + BATTERY_FULL_ROUNDED: IconData + BATTERY_FULL_SHARP: IconData + BATTERY_SAVER: IconData + BATTERY_SAVER_OUTLINED: IconData + BATTERY_SAVER_ROUNDED: IconData + BATTERY_SAVER_SHARP: IconData + BATTERY_STD: IconData + BATTERY_STD_OUTLINED: IconData + BATTERY_STD_ROUNDED: IconData + BATTERY_STD_SHARP: IconData + BATTERY_UNKNOWN: IconData + BATTERY_UNKNOWN_OUTLINED: IconData + BATTERY_UNKNOWN_ROUNDED: IconData + BATTERY_UNKNOWN_SHARP: IconData + BEACH_ACCESS: IconData + BEACH_ACCESS_OUTLINED: IconData + BEACH_ACCESS_ROUNDED: IconData + BEACH_ACCESS_SHARP: IconData + BED: IconData + BED_OUTLINED: IconData + BED_ROUNDED: IconData + BED_SHARP: IconData + BEDROOM_BABY: IconData + BEDROOM_BABY_OUTLINED: IconData + BEDROOM_BABY_ROUNDED: IconData + BEDROOM_BABY_SHARP: IconData + BEDROOM_CHILD: IconData + BEDROOM_CHILD_OUTLINED: IconData + BEDROOM_CHILD_ROUNDED: IconData + BEDROOM_CHILD_SHARP: IconData + BEDROOM_PARENT: IconData + BEDROOM_PARENT_OUTLINED: IconData + BEDROOM_PARENT_ROUNDED: IconData + BEDROOM_PARENT_SHARP: IconData + BEDTIME: IconData + BEDTIME_OFF: IconData + BEDTIME_OFF_OUTLINED: IconData + BEDTIME_OFF_ROUNDED: IconData + BEDTIME_OFF_SHARP: IconData + BEDTIME_OUTLINED: IconData + BEDTIME_ROUNDED: IconData + BEDTIME_SHARP: IconData + BEENHERE: IconData + BEENHERE_OUTLINED: IconData + BEENHERE_ROUNDED: IconData + BEENHERE_SHARP: IconData + BENTO: IconData + BENTO_OUTLINED: IconData + BENTO_ROUNDED: IconData + BENTO_SHARP: IconData + BIKE_SCOOTER: IconData + BIKE_SCOOTER_OUTLINED: IconData + BIKE_SCOOTER_ROUNDED: IconData + BIKE_SCOOTER_SHARP: IconData + BIOTECH: IconData + BIOTECH_OUTLINED: IconData + BIOTECH_ROUNDED: IconData + BIOTECH_SHARP: IconData + BLENDER: IconData + BLENDER_OUTLINED: IconData + BLENDER_ROUNDED: IconData + BLENDER_SHARP: IconData + BLIND: IconData + BLIND_OUTLINED: IconData + BLIND_ROUNDED: IconData + BLIND_SHARP: IconData + BLINDS: IconData + BLINDS_CLOSED: IconData + BLINDS_CLOSED_OUTLINED: IconData + BLINDS_CLOSED_ROUNDED: IconData + BLINDS_CLOSED_SHARP: IconData + BLINDS_OUTLINED: IconData + BLINDS_ROUNDED: IconData + BLINDS_SHARP: IconData + BLOCK: IconData + BLOCK_FLIPPED: IconData + BLOCK_OUTLINED: IconData + BLOCK_ROUNDED: IconData + BLOCK_SHARP: IconData + BLOODTYPE: IconData + BLOODTYPE_OUTLINED: IconData + BLOODTYPE_ROUNDED: IconData + BLOODTYPE_SHARP: IconData + BLUETOOTH: IconData + BLUETOOTH_AUDIO: IconData + BLUETOOTH_AUDIO_OUTLINED: IconData + BLUETOOTH_AUDIO_ROUNDED: IconData + BLUETOOTH_AUDIO_SHARP: IconData + BLUETOOTH_CONNECTED: IconData + BLUETOOTH_CONNECTED_OUTLINED: IconData + BLUETOOTH_CONNECTED_ROUNDED: IconData + BLUETOOTH_CONNECTED_SHARP: IconData + BLUETOOTH_DISABLED: IconData + BLUETOOTH_DISABLED_OUTLINED: IconData + BLUETOOTH_DISABLED_ROUNDED: IconData + BLUETOOTH_DISABLED_SHARP: IconData + BLUETOOTH_DRIVE: IconData + BLUETOOTH_DRIVE_OUTLINED: IconData + BLUETOOTH_DRIVE_ROUNDED: IconData + BLUETOOTH_DRIVE_SHARP: IconData + BLUETOOTH_OUTLINED: IconData + BLUETOOTH_ROUNDED: IconData + BLUETOOTH_SEARCHING: IconData + BLUETOOTH_SEARCHING_OUTLINED: IconData + BLUETOOTH_SEARCHING_ROUNDED: IconData + BLUETOOTH_SEARCHING_SHARP: IconData + BLUETOOTH_SHARP: IconData + BLUR_CIRCULAR: IconData + BLUR_CIRCULAR_OUTLINED: IconData + BLUR_CIRCULAR_ROUNDED: IconData + BLUR_CIRCULAR_SHARP: IconData + BLUR_LINEAR: IconData + BLUR_LINEAR_OUTLINED: IconData + BLUR_LINEAR_ROUNDED: IconData + BLUR_LINEAR_SHARP: IconData + BLUR_OFF: IconData + BLUR_OFF_OUTLINED: IconData + BLUR_OFF_ROUNDED: IconData + BLUR_OFF_SHARP: IconData + BLUR_ON: IconData + BLUR_ON_OUTLINED: IconData + BLUR_ON_ROUNDED: IconData + BLUR_ON_SHARP: IconData + BOLT: IconData + BOLT_OUTLINED: IconData + BOLT_ROUNDED: IconData + BOLT_SHARP: IconData + BOOK: IconData + BOOK_ONLINE: IconData + BOOK_ONLINE_OUTLINED: IconData + BOOK_ONLINE_ROUNDED: IconData + BOOK_ONLINE_SHARP: IconData + BOOK_OUTLINED: IconData + BOOK_ROUNDED: IconData + BOOK_SHARP: IconData + BOOKMARK: IconData + BOOKMARK_ADD: IconData + BOOKMARK_ADD_OUTLINED: IconData + BOOKMARK_ADD_ROUNDED: IconData + BOOKMARK_ADD_SHARP: IconData + BOOKMARK_ADDED: IconData + BOOKMARK_ADDED_OUTLINED: IconData + BOOKMARK_ADDED_ROUNDED: IconData + BOOKMARK_ADDED_SHARP: IconData + BOOKMARK_BORDER: IconData + BOOKMARK_BORDER_OUTLINED: IconData + BOOKMARK_BORDER_ROUNDED: IconData + BOOKMARK_BORDER_SHARP: IconData + BOOKMARK_OUTLINE: IconData + BOOKMARK_OUTLINE_OUTLINED: IconData + BOOKMARK_OUTLINE_ROUNDED: IconData + BOOKMARK_OUTLINE_SHARP: IconData + BOOKMARK_OUTLINED: IconData + BOOKMARK_REMOVE: IconData + BOOKMARK_REMOVE_OUTLINED: IconData + BOOKMARK_REMOVE_ROUNDED: IconData + BOOKMARK_REMOVE_SHARP: IconData + BOOKMARK_ROUNDED: IconData + BOOKMARK_SHARP: IconData + BOOKMARKS: IconData + BOOKMARKS_OUTLINED: IconData + BOOKMARKS_ROUNDED: IconData + BOOKMARKS_SHARP: IconData + BORDER_ALL: IconData + BORDER_ALL_OUTLINED: IconData + BORDER_ALL_ROUNDED: IconData + BORDER_ALL_SHARP: IconData + BORDER_BOTTOM: IconData + BORDER_BOTTOM_OUTLINED: IconData + BORDER_BOTTOM_ROUNDED: IconData + BORDER_BOTTOM_SHARP: IconData + BORDER_CLEAR: IconData + BORDER_CLEAR_OUTLINED: IconData + BORDER_CLEAR_ROUNDED: IconData + BORDER_CLEAR_SHARP: IconData + BORDER_COLOR: IconData + BORDER_COLOR_OUTLINED: IconData + BORDER_COLOR_ROUNDED: IconData + BORDER_COLOR_SHARP: IconData + BORDER_HORIZONTAL: IconData + BORDER_HORIZONTAL_OUTLINED: IconData + BORDER_HORIZONTAL_ROUNDED: IconData + BORDER_HORIZONTAL_SHARP: IconData + BORDER_INNER: IconData + BORDER_INNER_OUTLINED: IconData + BORDER_INNER_ROUNDED: IconData + BORDER_INNER_SHARP: IconData + BORDER_LEFT: IconData + BORDER_LEFT_OUTLINED: IconData + BORDER_LEFT_ROUNDED: IconData + BORDER_LEFT_SHARP: IconData + BORDER_OUTER: IconData + BORDER_OUTER_OUTLINED: IconData + BORDER_OUTER_ROUNDED: IconData + BORDER_OUTER_SHARP: IconData + BORDER_RIGHT: IconData + BORDER_RIGHT_OUTLINED: IconData + BORDER_RIGHT_ROUNDED: IconData + BORDER_RIGHT_SHARP: IconData + BORDER_STYLE: IconData + BORDER_STYLE_OUTLINED: IconData + BORDER_STYLE_ROUNDED: IconData + BORDER_STYLE_SHARP: IconData + BORDER_TOP: IconData + BORDER_TOP_OUTLINED: IconData + BORDER_TOP_ROUNDED: IconData + BORDER_TOP_SHARP: IconData + BORDER_VERTICAL: IconData + BORDER_VERTICAL_OUTLINED: IconData + BORDER_VERTICAL_ROUNDED: IconData + BORDER_VERTICAL_SHARP: IconData + BOY: IconData + BOY_OUTLINED: IconData + BOY_ROUNDED: IconData + BOY_SHARP: IconData + BRANDING_WATERMARK: IconData + BRANDING_WATERMARK_OUTLINED: IconData + BRANDING_WATERMARK_ROUNDED: IconData + BRANDING_WATERMARK_SHARP: IconData + BREAKFAST_DINING: IconData + BREAKFAST_DINING_OUTLINED: IconData + BREAKFAST_DINING_ROUNDED: IconData + BREAKFAST_DINING_SHARP: IconData + BRIGHTNESS_1: IconData + BRIGHTNESS_1_OUTLINED: IconData + BRIGHTNESS_1_ROUNDED: IconData + BRIGHTNESS_1_SHARP: IconData + BRIGHTNESS_2: IconData + BRIGHTNESS_2_OUTLINED: IconData + BRIGHTNESS_2_ROUNDED: IconData + BRIGHTNESS_2_SHARP: IconData + BRIGHTNESS_3: IconData + BRIGHTNESS_3_OUTLINED: IconData + BRIGHTNESS_3_ROUNDED: IconData + BRIGHTNESS_3_SHARP: IconData + BRIGHTNESS_4: IconData + BRIGHTNESS_4_OUTLINED: IconData + BRIGHTNESS_4_ROUNDED: IconData + BRIGHTNESS_4_SHARP: IconData + BRIGHTNESS_5: IconData + BRIGHTNESS_5_OUTLINED: IconData + BRIGHTNESS_5_ROUNDED: IconData + BRIGHTNESS_5_SHARP: IconData + BRIGHTNESS_6: IconData + BRIGHTNESS_6_OUTLINED: IconData + BRIGHTNESS_6_ROUNDED: IconData + BRIGHTNESS_6_SHARP: IconData + BRIGHTNESS_7: IconData + BRIGHTNESS_7_OUTLINED: IconData + BRIGHTNESS_7_ROUNDED: IconData + BRIGHTNESS_7_SHARP: IconData + BRIGHTNESS_AUTO: IconData + BRIGHTNESS_AUTO_OUTLINED: IconData + BRIGHTNESS_AUTO_ROUNDED: IconData + BRIGHTNESS_AUTO_SHARP: IconData + BRIGHTNESS_HIGH: IconData + BRIGHTNESS_HIGH_OUTLINED: IconData + BRIGHTNESS_HIGH_ROUNDED: IconData + BRIGHTNESS_HIGH_SHARP: IconData + BRIGHTNESS_LOW: IconData + BRIGHTNESS_LOW_OUTLINED: IconData + BRIGHTNESS_LOW_ROUNDED: IconData + BRIGHTNESS_LOW_SHARP: IconData + BRIGHTNESS_MEDIUM: IconData + BRIGHTNESS_MEDIUM_OUTLINED: IconData + BRIGHTNESS_MEDIUM_ROUNDED: IconData + BRIGHTNESS_MEDIUM_SHARP: IconData + BROADCAST_ON_HOME: IconData + BROADCAST_ON_HOME_OUTLINED: IconData + BROADCAST_ON_HOME_ROUNDED: IconData + BROADCAST_ON_HOME_SHARP: IconData + BROADCAST_ON_PERSONAL: IconData + BROADCAST_ON_PERSONAL_OUTLINED: IconData + BROADCAST_ON_PERSONAL_ROUNDED: IconData + BROADCAST_ON_PERSONAL_SHARP: IconData + BROKEN_IMAGE: IconData + BROKEN_IMAGE_OUTLINED: IconData + BROKEN_IMAGE_ROUNDED: IconData + BROKEN_IMAGE_SHARP: IconData + BROWSE_GALLERY: IconData + BROWSE_GALLERY_OUTLINED: IconData + BROWSE_GALLERY_ROUNDED: IconData + BROWSE_GALLERY_SHARP: IconData + BROWSER_NOT_SUPPORTED: IconData + BROWSER_NOT_SUPPORTED_OUTLINED: IconData + BROWSER_NOT_SUPPORTED_ROUNDED: IconData + BROWSER_NOT_SUPPORTED_SHARP: IconData + BROWSER_UPDATED: IconData + BROWSER_UPDATED_OUTLINED: IconData + BROWSER_UPDATED_ROUNDED: IconData + BROWSER_UPDATED_SHARP: IconData + BRUNCH_DINING: IconData + BRUNCH_DINING_OUTLINED: IconData + BRUNCH_DINING_ROUNDED: IconData + BRUNCH_DINING_SHARP: IconData + BRUSH: IconData + BRUSH_OUTLINED: IconData + BRUSH_ROUNDED: IconData + BRUSH_SHARP: IconData + BUBBLE_CHART: IconData + BUBBLE_CHART_OUTLINED: IconData + BUBBLE_CHART_ROUNDED: IconData + BUBBLE_CHART_SHARP: IconData + BUG_REPORT: IconData + BUG_REPORT_OUTLINED: IconData + BUG_REPORT_ROUNDED: IconData + BUG_REPORT_SHARP: IconData + BUILD: IconData + BUILD_CIRCLE: IconData + BUILD_CIRCLE_OUTLINED: IconData + BUILD_CIRCLE_ROUNDED: IconData + BUILD_CIRCLE_SHARP: IconData + BUILD_OUTLINED: IconData + BUILD_ROUNDED: IconData + BUILD_SHARP: IconData + BUNGALOW: IconData + BUNGALOW_OUTLINED: IconData + BUNGALOW_ROUNDED: IconData + BUNGALOW_SHARP: IconData + BURST_MODE: IconData + BURST_MODE_OUTLINED: IconData + BURST_MODE_ROUNDED: IconData + BURST_MODE_SHARP: IconData + BUS_ALERT: IconData + BUS_ALERT_OUTLINED: IconData + BUS_ALERT_ROUNDED: IconData + BUS_ALERT_SHARP: IconData + BUSINESS: IconData + BUSINESS_CENTER: IconData + BUSINESS_CENTER_OUTLINED: IconData + BUSINESS_CENTER_ROUNDED: IconData + BUSINESS_CENTER_SHARP: IconData + BUSINESS_OUTLINED: IconData + BUSINESS_ROUNDED: IconData + BUSINESS_SHARP: IconData + CABIN: IconData + CABIN_OUTLINED: IconData + CABIN_ROUNDED: IconData + CABIN_SHARP: IconData + CABLE: IconData + CABLE_OUTLINED: IconData + CABLE_ROUNDED: IconData + CABLE_SHARP: IconData + CACHED: IconData + CACHED_OUTLINED: IconData + CACHED_ROUNDED: IconData + CACHED_SHARP: IconData + CAKE: IconData + CAKE_OUTLINED: IconData + CAKE_ROUNDED: IconData + CAKE_SHARP: IconData + CALCULATE: IconData + CALCULATE_OUTLINED: IconData + CALCULATE_ROUNDED: IconData + CALCULATE_SHARP: IconData + CALENDAR_MONTH: IconData + CALENDAR_MONTH_OUTLINED: IconData + CALENDAR_MONTH_ROUNDED: IconData + CALENDAR_MONTH_SHARP: IconData + CALENDAR_TODAY: IconData + CALENDAR_TODAY_OUTLINED: IconData + CALENDAR_TODAY_ROUNDED: IconData + CALENDAR_TODAY_SHARP: IconData + CALENDAR_VIEW_DAY: IconData + CALENDAR_VIEW_DAY_OUTLINED: IconData + CALENDAR_VIEW_DAY_ROUNDED: IconData + CALENDAR_VIEW_DAY_SHARP: IconData + CALENDAR_VIEW_MONTH: IconData + CALENDAR_VIEW_MONTH_OUTLINED: IconData + CALENDAR_VIEW_MONTH_ROUNDED: IconData + CALENDAR_VIEW_MONTH_SHARP: IconData + CALENDAR_VIEW_WEEK: IconData + CALENDAR_VIEW_WEEK_OUTLINED: IconData + CALENDAR_VIEW_WEEK_ROUNDED: IconData + CALENDAR_VIEW_WEEK_SHARP: IconData + CALL: IconData + CALL_END: IconData + CALL_END_OUTLINED: IconData + CALL_END_ROUNDED: IconData + CALL_END_SHARP: IconData + CALL_MADE: IconData + CALL_MADE_OUTLINED: IconData + CALL_MADE_ROUNDED: IconData + CALL_MADE_SHARP: IconData + CALL_MERGE: IconData + CALL_MERGE_OUTLINED: IconData + CALL_MERGE_ROUNDED: IconData + CALL_MERGE_SHARP: IconData + CALL_MISSED: IconData + CALL_MISSED_OUTGOING: IconData + CALL_MISSED_OUTGOING_OUTLINED: IconData + CALL_MISSED_OUTGOING_ROUNDED: IconData + CALL_MISSED_OUTGOING_SHARP: IconData + CALL_MISSED_OUTLINED: IconData + CALL_MISSED_ROUNDED: IconData + CALL_MISSED_SHARP: IconData + CALL_OUTLINED: IconData + CALL_RECEIVED: IconData + CALL_RECEIVED_OUTLINED: IconData + CALL_RECEIVED_ROUNDED: IconData + CALL_RECEIVED_SHARP: IconData + CALL_ROUNDED: IconData + CALL_SHARP: IconData + CALL_SPLIT: IconData + CALL_SPLIT_OUTLINED: IconData + CALL_SPLIT_ROUNDED: IconData + CALL_SPLIT_SHARP: IconData + CALL_TO_ACTION: IconData + CALL_TO_ACTION_OUTLINED: IconData + CALL_TO_ACTION_ROUNDED: IconData + CALL_TO_ACTION_SHARP: IconData + CAMERA: IconData + CAMERA_ALT: IconData + CAMERA_ALT_OUTLINED: IconData + CAMERA_ALT_ROUNDED: IconData + CAMERA_ALT_SHARP: IconData + CAMERA_ENHANCE: IconData + CAMERA_ENHANCE_OUTLINED: IconData + CAMERA_ENHANCE_ROUNDED: IconData + CAMERA_ENHANCE_SHARP: IconData + CAMERA_FRONT: IconData + CAMERA_FRONT_OUTLINED: IconData + CAMERA_FRONT_ROUNDED: IconData + CAMERA_FRONT_SHARP: IconData + CAMERA_INDOOR: IconData + CAMERA_INDOOR_OUTLINED: IconData + CAMERA_INDOOR_ROUNDED: IconData + CAMERA_INDOOR_SHARP: IconData + CAMERA_OUTDOOR: IconData + CAMERA_OUTDOOR_OUTLINED: IconData + CAMERA_OUTDOOR_ROUNDED: IconData + CAMERA_OUTDOOR_SHARP: IconData + CAMERA_OUTLINED: IconData + CAMERA_REAR: IconData + CAMERA_REAR_OUTLINED: IconData + CAMERA_REAR_ROUNDED: IconData + CAMERA_REAR_SHARP: IconData + CAMERA_ROLL: IconData + CAMERA_ROLL_OUTLINED: IconData + CAMERA_ROLL_ROUNDED: IconData + CAMERA_ROLL_SHARP: IconData + CAMERA_ROUNDED: IconData + CAMERA_SHARP: IconData + CAMERASWITCH: IconData + CAMERASWITCH_OUTLINED: IconData + CAMERASWITCH_ROUNDED: IconData + CAMERASWITCH_SHARP: IconData + CAMPAIGN: IconData + CAMPAIGN_OUTLINED: IconData + CAMPAIGN_ROUNDED: IconData + CAMPAIGN_SHARP: IconData + CANCEL: IconData + CANCEL_OUTLINED: IconData + CANCEL_PRESENTATION: IconData + CANCEL_PRESENTATION_OUTLINED: IconData + CANCEL_PRESENTATION_ROUNDED: IconData + CANCEL_PRESENTATION_SHARP: IconData + CANCEL_ROUNDED: IconData + CANCEL_SCHEDULE_SEND: IconData + CANCEL_SCHEDULE_SEND_OUTLINED: IconData + CANCEL_SCHEDULE_SEND_ROUNDED: IconData + CANCEL_SCHEDULE_SEND_SHARP: IconData + CANCEL_SHARP: IconData + CANDLESTICK_CHART: IconData + CANDLESTICK_CHART_OUTLINED: IconData + CANDLESTICK_CHART_ROUNDED: IconData + CANDLESTICK_CHART_SHARP: IconData + CAR_CRASH: IconData + CAR_CRASH_OUTLINED: IconData + CAR_CRASH_ROUNDED: IconData + CAR_CRASH_SHARP: IconData + CAR_RENTAL: IconData + CAR_RENTAL_OUTLINED: IconData + CAR_RENTAL_ROUNDED: IconData + CAR_RENTAL_SHARP: IconData + CAR_REPAIR: IconData + CAR_REPAIR_OUTLINED: IconData + CAR_REPAIR_ROUNDED: IconData + CAR_REPAIR_SHARP: IconData + CARD_GIFTCARD: IconData + CARD_GIFTCARD_OUTLINED: IconData + CARD_GIFTCARD_ROUNDED: IconData + CARD_GIFTCARD_SHARP: IconData + CARD_MEMBERSHIP: IconData + CARD_MEMBERSHIP_OUTLINED: IconData + CARD_MEMBERSHIP_ROUNDED: IconData + CARD_MEMBERSHIP_SHARP: IconData + CARD_TRAVEL: IconData + CARD_TRAVEL_OUTLINED: IconData + CARD_TRAVEL_ROUNDED: IconData + CARD_TRAVEL_SHARP: IconData + CARPENTER: IconData + CARPENTER_OUTLINED: IconData + CARPENTER_ROUNDED: IconData + CARPENTER_SHARP: IconData + CASES: IconData + CASES_OUTLINED: IconData + CASES_ROUNDED: IconData + CASES_SHARP: IconData + CASINO: IconData + CASINO_OUTLINED: IconData + CASINO_ROUNDED: IconData + CASINO_SHARP: IconData + CAST: IconData + CAST_CONNECTED: IconData + CAST_CONNECTED_OUTLINED: IconData + CAST_CONNECTED_ROUNDED: IconData + CAST_CONNECTED_SHARP: IconData + CAST_FOR_EDUCATION: IconData + CAST_FOR_EDUCATION_OUTLINED: IconData + CAST_FOR_EDUCATION_ROUNDED: IconData + CAST_FOR_EDUCATION_SHARP: IconData + CAST_OUTLINED: IconData + CAST_ROUNDED: IconData + CAST_SHARP: IconData + CASTLE: IconData + CASTLE_OUTLINED: IconData + CASTLE_ROUNDED: IconData + CASTLE_SHARP: IconData + CATCHING_POKEMON: IconData + CATCHING_POKEMON_OUTLINED: IconData + CATCHING_POKEMON_ROUNDED: IconData + CATCHING_POKEMON_SHARP: IconData + CATEGORY: IconData + CATEGORY_OUTLINED: IconData + CATEGORY_ROUNDED: IconData + CATEGORY_SHARP: IconData + CELEBRATION: IconData + CELEBRATION_OUTLINED: IconData + CELEBRATION_ROUNDED: IconData + CELEBRATION_SHARP: IconData + CELL_TOWER: IconData + CELL_TOWER_OUTLINED: IconData + CELL_TOWER_ROUNDED: IconData + CELL_TOWER_SHARP: IconData + CELL_WIFI: IconData + CELL_WIFI_OUTLINED: IconData + CELL_WIFI_ROUNDED: IconData + CELL_WIFI_SHARP: IconData + CENTER_FOCUS_STRONG: IconData + CENTER_FOCUS_STRONG_OUTLINED: IconData + CENTER_FOCUS_STRONG_ROUNDED: IconData + CENTER_FOCUS_STRONG_SHARP: IconData + CENTER_FOCUS_WEAK: IconData + CENTER_FOCUS_WEAK_OUTLINED: IconData + CENTER_FOCUS_WEAK_ROUNDED: IconData + CENTER_FOCUS_WEAK_SHARP: IconData + CHAIR: IconData + CHAIR_ALT: IconData + CHAIR_ALT_OUTLINED: IconData + CHAIR_ALT_ROUNDED: IconData + CHAIR_ALT_SHARP: IconData + CHAIR_OUTLINED: IconData + CHAIR_ROUNDED: IconData + CHAIR_SHARP: IconData + CHALET: IconData + CHALET_OUTLINED: IconData + CHALET_ROUNDED: IconData + CHALET_SHARP: IconData + CHANGE_CIRCLE: IconData + CHANGE_CIRCLE_OUTLINED: IconData + CHANGE_CIRCLE_ROUNDED: IconData + CHANGE_CIRCLE_SHARP: IconData + CHANGE_HISTORY: IconData + CHANGE_HISTORY_OUTLINED: IconData + CHANGE_HISTORY_ROUNDED: IconData + CHANGE_HISTORY_SHARP: IconData + CHARGING_STATION: IconData + CHARGING_STATION_OUTLINED: IconData + CHARGING_STATION_ROUNDED: IconData + CHARGING_STATION_SHARP: IconData + CHAT: IconData + CHAT_BUBBLE: IconData + CHAT_BUBBLE_OUTLINE: IconData + CHAT_BUBBLE_OUTLINE_OUTLINED: IconData + CHAT_BUBBLE_OUTLINE_ROUNDED: IconData + CHAT_BUBBLE_OUTLINE_SHARP: IconData + CHAT_BUBBLE_OUTLINED: IconData + CHAT_BUBBLE_ROUNDED: IconData + CHAT_BUBBLE_SHARP: IconData + CHAT_OUTLINED: IconData + CHAT_ROUNDED: IconData + CHAT_SHARP: IconData + CHECK: IconData + CHECK_BOX: IconData + CHECK_BOX_OUTLINE_BLANK: IconData + CHECK_BOX_OUTLINE_BLANK_OUTLINED: IconData + CHECK_BOX_OUTLINE_BLANK_ROUNDED: IconData + CHECK_BOX_OUTLINE_BLANK_SHARP: IconData + CHECK_BOX_OUTLINED: IconData + CHECK_BOX_ROUNDED: IconData + CHECK_BOX_SHARP: IconData + CHECK_CIRCLE: IconData + CHECK_CIRCLE_OUTLINE: IconData + CHECK_CIRCLE_OUTLINE_OUTLINED: IconData + CHECK_CIRCLE_OUTLINE_ROUNDED: IconData + CHECK_CIRCLE_OUTLINE_SHARP: IconData + CHECK_CIRCLE_OUTLINED: IconData + CHECK_CIRCLE_ROUNDED: IconData + CHECK_CIRCLE_SHARP: IconData + CHECK_OUTLINED: IconData + CHECK_ROUNDED: IconData + CHECK_SHARP: IconData + CHECKLIST: IconData + CHECKLIST_OUTLINED: IconData + CHECKLIST_ROUNDED: IconData + CHECKLIST_RTL: IconData + CHECKLIST_RTL_OUTLINED: IconData + CHECKLIST_RTL_ROUNDED: IconData + CHECKLIST_RTL_SHARP: IconData + CHECKLIST_SHARP: IconData + CHECKROOM: IconData + CHECKROOM_OUTLINED: IconData + CHECKROOM_ROUNDED: IconData + CHECKROOM_SHARP: IconData + CHEVRON_LEFT: IconData + CHEVRON_LEFT_OUTLINED: IconData + CHEVRON_LEFT_ROUNDED: IconData + CHEVRON_LEFT_SHARP: IconData + CHEVRON_RIGHT: IconData + CHEVRON_RIGHT_OUTLINED: IconData + CHEVRON_RIGHT_ROUNDED: IconData + CHEVRON_RIGHT_SHARP: IconData + CHILD_CARE: IconData + CHILD_CARE_OUTLINED: IconData + CHILD_CARE_ROUNDED: IconData + CHILD_CARE_SHARP: IconData + CHILD_FRIENDLY: IconData + CHILD_FRIENDLY_OUTLINED: IconData + CHILD_FRIENDLY_ROUNDED: IconData + CHILD_FRIENDLY_SHARP: IconData + CHROME_READER_MODE: IconData + CHROME_READER_MODE_OUTLINED: IconData + CHROME_READER_MODE_ROUNDED: IconData + CHROME_READER_MODE_SHARP: IconData + CHURCH: IconData + CHURCH_OUTLINED: IconData + CHURCH_ROUNDED: IconData + CHURCH_SHARP: IconData + CIRCLE: IconData + CIRCLE_NOTIFICATIONS: IconData + CIRCLE_NOTIFICATIONS_OUTLINED: IconData + CIRCLE_NOTIFICATIONS_ROUNDED: IconData + CIRCLE_NOTIFICATIONS_SHARP: IconData + CIRCLE_OUTLINED: IconData + CIRCLE_ROUNDED: IconData + CIRCLE_SHARP: IconData + CLASS_: IconData + CLASS_OUTLINED: IconData + CLASS_ROUNDED: IconData + CLASS_SHARP: IconData + CLEAN_HANDS: IconData + CLEAN_HANDS_OUTLINED: IconData + CLEAN_HANDS_ROUNDED: IconData + CLEAN_HANDS_SHARP: IconData + CLEANING_SERVICES: IconData + CLEANING_SERVICES_OUTLINED: IconData + CLEANING_SERVICES_ROUNDED: IconData + CLEANING_SERVICES_SHARP: IconData + CLEAR: IconData + CLEAR_ALL: IconData + CLEAR_ALL_OUTLINED: IconData + CLEAR_ALL_ROUNDED: IconData + CLEAR_ALL_SHARP: IconData + CLEAR_OUTLINED: IconData + CLEAR_ROUNDED: IconData + CLEAR_SHARP: IconData + CLOSE: IconData + CLOSE_FULLSCREEN: IconData + CLOSE_FULLSCREEN_OUTLINED: IconData + CLOSE_FULLSCREEN_ROUNDED: IconData + CLOSE_FULLSCREEN_SHARP: IconData + CLOSE_OUTLINED: IconData + CLOSE_ROUNDED: IconData + CLOSE_SHARP: IconData + CLOSED_CAPTION: IconData + CLOSED_CAPTION_DISABLED: IconData + CLOSED_CAPTION_DISABLED_OUTLINED: IconData + CLOSED_CAPTION_DISABLED_ROUNDED: IconData + CLOSED_CAPTION_DISABLED_SHARP: IconData + CLOSED_CAPTION_OFF: IconData + CLOSED_CAPTION_OFF_OUTLINED: IconData + CLOSED_CAPTION_OFF_ROUNDED: IconData + CLOSED_CAPTION_OFF_SHARP: IconData + CLOSED_CAPTION_OUTLINED: IconData + CLOSED_CAPTION_ROUNDED: IconData + CLOSED_CAPTION_SHARP: IconData + CLOUD: IconData + CLOUD_CIRCLE: IconData + CLOUD_CIRCLE_OUTLINED: IconData + CLOUD_CIRCLE_ROUNDED: IconData + CLOUD_CIRCLE_SHARP: IconData + CLOUD_DONE: IconData + CLOUD_DONE_OUTLINED: IconData + CLOUD_DONE_ROUNDED: IconData + CLOUD_DONE_SHARP: IconData + CLOUD_DOWNLOAD: IconData + CLOUD_DOWNLOAD_OUTLINED: IconData + CLOUD_DOWNLOAD_ROUNDED: IconData + CLOUD_DOWNLOAD_SHARP: IconData + CLOUD_OFF: IconData + CLOUD_OFF_OUTLINED: IconData + CLOUD_OFF_ROUNDED: IconData + CLOUD_OFF_SHARP: IconData + CLOUD_OUTLINED: IconData + CLOUD_QUEUE: IconData + CLOUD_QUEUE_OUTLINED: IconData + CLOUD_QUEUE_ROUNDED: IconData + CLOUD_QUEUE_SHARP: IconData + CLOUD_ROUNDED: IconData + CLOUD_SHARP: IconData + CLOUD_SYNC: IconData + CLOUD_SYNC_OUTLINED: IconData + CLOUD_SYNC_ROUNDED: IconData + CLOUD_SYNC_SHARP: IconData + CLOUD_UPLOAD: IconData + CLOUD_UPLOAD_OUTLINED: IconData + CLOUD_UPLOAD_ROUNDED: IconData + CLOUD_UPLOAD_SHARP: IconData + CLOUDY_SNOWING: IconData + CO2: IconData + CO2_OUTLINED: IconData + CO2_ROUNDED: IconData + CO2_SHARP: IconData + CO_PRESENT: IconData + CO_PRESENT_OUTLINED: IconData + CO_PRESENT_ROUNDED: IconData + CO_PRESENT_SHARP: IconData + CODE: IconData + CODE_OFF: IconData + CODE_OFF_OUTLINED: IconData + CODE_OFF_ROUNDED: IconData + CODE_OFF_SHARP: IconData + CODE_OUTLINED: IconData + CODE_ROUNDED: IconData + CODE_SHARP: IconData + COFFEE: IconData + COFFEE_MAKER: IconData + COFFEE_MAKER_OUTLINED: IconData + COFFEE_MAKER_ROUNDED: IconData + COFFEE_MAKER_SHARP: IconData + COFFEE_OUTLINED: IconData + COFFEE_ROUNDED: IconData + COFFEE_SHARP: IconData + COLLECTIONS: IconData + COLLECTIONS_BOOKMARK: IconData + COLLECTIONS_BOOKMARK_OUTLINED: IconData + COLLECTIONS_BOOKMARK_ROUNDED: IconData + COLLECTIONS_BOOKMARK_SHARP: IconData + COLLECTIONS_OUTLINED: IconData + COLLECTIONS_ROUNDED: IconData + COLLECTIONS_SHARP: IconData + COLOR_LENS: IconData + COLOR_LENS_OUTLINED: IconData + COLOR_LENS_ROUNDED: IconData + COLOR_LENS_SHARP: IconData + COLORIZE: IconData + COLORIZE_OUTLINED: IconData + COLORIZE_ROUNDED: IconData + COLORIZE_SHARP: IconData + COMMENT: IconData + COMMENT_BANK: IconData + COMMENT_BANK_OUTLINED: IconData + COMMENT_BANK_ROUNDED: IconData + COMMENT_BANK_SHARP: IconData + COMMENT_OUTLINED: IconData + COMMENT_ROUNDED: IconData + COMMENT_SHARP: IconData + COMMENTS_DISABLED: IconData + COMMENTS_DISABLED_OUTLINED: IconData + COMMENTS_DISABLED_ROUNDED: IconData + COMMENTS_DISABLED_SHARP: IconData + COMMIT: IconData + COMMIT_OUTLINED: IconData + COMMIT_ROUNDED: IconData + COMMIT_SHARP: IconData + COMMUTE: IconData + COMMUTE_OUTLINED: IconData + COMMUTE_ROUNDED: IconData + COMMUTE_SHARP: IconData + COMPARE: IconData + COMPARE_ARROWS: IconData + COMPARE_ARROWS_OUTLINED: IconData + COMPARE_ARROWS_ROUNDED: IconData + COMPARE_ARROWS_SHARP: IconData + COMPARE_OUTLINED: IconData + COMPARE_ROUNDED: IconData + COMPARE_SHARP: IconData + COMPASS_CALIBRATION: IconData + COMPASS_CALIBRATION_OUTLINED: IconData + COMPASS_CALIBRATION_ROUNDED: IconData + COMPASS_CALIBRATION_SHARP: IconData + COMPOST: IconData + COMPOST_OUTLINED: IconData + COMPOST_ROUNDED: IconData + COMPOST_SHARP: IconData + COMPRESS: IconData + COMPRESS_OUTLINED: IconData + COMPRESS_ROUNDED: IconData + COMPRESS_SHARP: IconData + COMPUTER: IconData + COMPUTER_OUTLINED: IconData + COMPUTER_ROUNDED: IconData + COMPUTER_SHARP: IconData + CONFIRMATION_NUM: IconData + CONFIRMATION_NUM_OUTLINED: IconData + CONFIRMATION_NUM_ROUNDED: IconData + CONFIRMATION_NUM_SHARP: IconData + CONFIRMATION_NUMBER: IconData + CONFIRMATION_NUMBER_OUTLINED: IconData + CONFIRMATION_NUMBER_ROUNDED: IconData + CONFIRMATION_NUMBER_SHARP: IconData + CONNECT_WITHOUT_CONTACT: IconData + CONNECT_WITHOUT_CONTACT_OUTLINED: IconData + CONNECT_WITHOUT_CONTACT_ROUNDED: IconData + CONNECT_WITHOUT_CONTACT_SHARP: IconData + CONNECTED_TV: IconData + CONNECTED_TV_OUTLINED: IconData + CONNECTED_TV_ROUNDED: IconData + CONNECTED_TV_SHARP: IconData + CONNECTING_AIRPORTS: IconData + CONNECTING_AIRPORTS_OUTLINED: IconData + CONNECTING_AIRPORTS_ROUNDED: IconData + CONNECTING_AIRPORTS_SHARP: IconData + CONSTRUCTION: IconData + CONSTRUCTION_OUTLINED: IconData + CONSTRUCTION_ROUNDED: IconData + CONSTRUCTION_SHARP: IconData + CONTACT_EMERGENCY: IconData + CONTACT_EMERGENCY_OUTLINED: IconData + CONTACT_EMERGENCY_ROUNDED: IconData + CONTACT_EMERGENCY_SHARP: IconData + CONTACT_MAIL: IconData + CONTACT_MAIL_OUTLINED: IconData + CONTACT_MAIL_ROUNDED: IconData + CONTACT_MAIL_SHARP: IconData + CONTACT_PAGE: IconData + CONTACT_PAGE_OUTLINED: IconData + CONTACT_PAGE_ROUNDED: IconData + CONTACT_PAGE_SHARP: IconData + CONTACT_PHONE: IconData + CONTACT_PHONE_OUTLINED: IconData + CONTACT_PHONE_ROUNDED: IconData + CONTACT_PHONE_SHARP: IconData + CONTACT_SUPPORT: IconData + CONTACT_SUPPORT_OUTLINED: IconData + CONTACT_SUPPORT_ROUNDED: IconData + CONTACT_SUPPORT_SHARP: IconData + CONTACTLESS: IconData + CONTACTLESS_OUTLINED: IconData + CONTACTLESS_ROUNDED: IconData + CONTACTLESS_SHARP: IconData + CONTACTS: IconData + CONTACTS_OUTLINED: IconData + CONTACTS_ROUNDED: IconData + CONTACTS_SHARP: IconData + CONTENT_COPY: IconData + CONTENT_COPY_OUTLINED: IconData + CONTENT_COPY_ROUNDED: IconData + CONTENT_COPY_SHARP: IconData + CONTENT_CUT: IconData + CONTENT_CUT_OUTLINED: IconData + CONTENT_CUT_ROUNDED: IconData + CONTENT_CUT_SHARP: IconData + CONTENT_PASTE: IconData + CONTENT_PASTE_GO: IconData + CONTENT_PASTE_GO_OUTLINED: IconData + CONTENT_PASTE_GO_ROUNDED: IconData + CONTENT_PASTE_GO_SHARP: IconData + CONTENT_PASTE_OFF: IconData + CONTENT_PASTE_OFF_OUTLINED: IconData + CONTENT_PASTE_OFF_ROUNDED: IconData + CONTENT_PASTE_OFF_SHARP: IconData + CONTENT_PASTE_OUTLINED: IconData + CONTENT_PASTE_ROUNDED: IconData + CONTENT_PASTE_SEARCH: IconData + CONTENT_PASTE_SEARCH_OUTLINED: IconData + CONTENT_PASTE_SEARCH_ROUNDED: IconData + CONTENT_PASTE_SEARCH_SHARP: IconData + CONTENT_PASTE_SHARP: IconData + CONTRAST: IconData + CONTRAST_OUTLINED: IconData + CONTRAST_ROUNDED: IconData + CONTRAST_SHARP: IconData + CONTROL_CAMERA: IconData + CONTROL_CAMERA_OUTLINED: IconData + CONTROL_CAMERA_ROUNDED: IconData + CONTROL_CAMERA_SHARP: IconData + CONTROL_POINT: IconData + CONTROL_POINT_DUPLICATE: IconData + CONTROL_POINT_DUPLICATE_OUTLINED: IconData + CONTROL_POINT_DUPLICATE_ROUNDED: IconData + CONTROL_POINT_DUPLICATE_SHARP: IconData + CONTROL_POINT_OUTLINED: IconData + CONTROL_POINT_ROUNDED: IconData + CONTROL_POINT_SHARP: IconData + CONVEYOR_BELT: IconData + COOKIE: IconData + COOKIE_OUTLINED: IconData + COOKIE_ROUNDED: IconData + COOKIE_SHARP: IconData + COPY: IconData + COPY_ALL: IconData + COPY_ALL_OUTLINED: IconData + COPY_ALL_ROUNDED: IconData + COPY_ALL_SHARP: IconData + COPY_OUTLINED: IconData + COPY_ROUNDED: IconData + COPY_SHARP: IconData + COPYRIGHT: IconData + COPYRIGHT_OUTLINED: IconData + COPYRIGHT_ROUNDED: IconData + COPYRIGHT_SHARP: IconData + CORONAVIRUS: IconData + CORONAVIRUS_OUTLINED: IconData + CORONAVIRUS_ROUNDED: IconData + CORONAVIRUS_SHARP: IconData + CORPORATE_FARE: IconData + CORPORATE_FARE_OUTLINED: IconData + CORPORATE_FARE_ROUNDED: IconData + CORPORATE_FARE_SHARP: IconData + COTTAGE: IconData + COTTAGE_OUTLINED: IconData + COTTAGE_ROUNDED: IconData + COTTAGE_SHARP: IconData + COUNTERTOPS: IconData + COUNTERTOPS_OUTLINED: IconData + COUNTERTOPS_ROUNDED: IconData + COUNTERTOPS_SHARP: IconData + CREATE: IconData + CREATE_NEW_FOLDER: IconData + CREATE_NEW_FOLDER_OUTLINED: IconData + CREATE_NEW_FOLDER_ROUNDED: IconData + CREATE_NEW_FOLDER_SHARP: IconData + CREATE_OUTLINED: IconData + CREATE_ROUNDED: IconData + CREATE_SHARP: IconData + CREDIT_CARD: IconData + CREDIT_CARD_OFF: IconData + CREDIT_CARD_OFF_OUTLINED: IconData + CREDIT_CARD_OFF_ROUNDED: IconData + CREDIT_CARD_OFF_SHARP: IconData + CREDIT_CARD_OUTLINED: IconData + CREDIT_CARD_ROUNDED: IconData + CREDIT_CARD_SHARP: IconData + CREDIT_SCORE: IconData + CREDIT_SCORE_OUTLINED: IconData + CREDIT_SCORE_ROUNDED: IconData + CREDIT_SCORE_SHARP: IconData + CRIB: IconData + CRIB_OUTLINED: IconData + CRIB_ROUNDED: IconData + CRIB_SHARP: IconData + CRISIS_ALERT: IconData + CRISIS_ALERT_OUTLINED: IconData + CRISIS_ALERT_ROUNDED: IconData + CRISIS_ALERT_SHARP: IconData + CROP: IconData + CROP_16_9: IconData + CROP_16_9_OUTLINED: IconData + CROP_16_9_ROUNDED: IconData + CROP_16_9_SHARP: IconData + CROP_3_2: IconData + CROP_3_2_OUTLINED: IconData + CROP_3_2_ROUNDED: IconData + CROP_3_2_SHARP: IconData + CROP_5_4: IconData + CROP_5_4_OUTLINED: IconData + CROP_5_4_ROUNDED: IconData + CROP_5_4_SHARP: IconData + CROP_7_5: IconData + CROP_7_5_OUTLINED: IconData + CROP_7_5_ROUNDED: IconData + CROP_7_5_SHARP: IconData + CROP_DIN: IconData + CROP_DIN_OUTLINED: IconData + CROP_DIN_ROUNDED: IconData + CROP_DIN_SHARP: IconData + CROP_FREE: IconData + CROP_FREE_OUTLINED: IconData + CROP_FREE_ROUNDED: IconData + CROP_FREE_SHARP: IconData + CROP_LANDSCAPE: IconData + CROP_LANDSCAPE_OUTLINED: IconData + CROP_LANDSCAPE_ROUNDED: IconData + CROP_LANDSCAPE_SHARP: IconData + CROP_ORIGINAL: IconData + CROP_ORIGINAL_OUTLINED: IconData + CROP_ORIGINAL_ROUNDED: IconData + CROP_ORIGINAL_SHARP: IconData + CROP_OUTLINED: IconData + CROP_PORTRAIT: IconData + CROP_PORTRAIT_OUTLINED: IconData + CROP_PORTRAIT_ROUNDED: IconData + CROP_PORTRAIT_SHARP: IconData + CROP_ROTATE: IconData + CROP_ROTATE_OUTLINED: IconData + CROP_ROTATE_ROUNDED: IconData + CROP_ROTATE_SHARP: IconData + CROP_ROUNDED: IconData + CROP_SHARP: IconData + CROP_SQUARE: IconData + CROP_SQUARE_OUTLINED: IconData + CROP_SQUARE_ROUNDED: IconData + CROP_SQUARE_SHARP: IconData + CRUELTY_FREE: IconData + CRUELTY_FREE_OUTLINED: IconData + CRUELTY_FREE_ROUNDED: IconData + CRUELTY_FREE_SHARP: IconData + CSS: IconData + CSS_OUTLINED: IconData + CSS_ROUNDED: IconData + CSS_SHARP: IconData + CURRENCY_BITCOIN: IconData + CURRENCY_BITCOIN_OUTLINED: IconData + CURRENCY_BITCOIN_ROUNDED: IconData + CURRENCY_BITCOIN_SHARP: IconData + CURRENCY_EXCHANGE: IconData + CURRENCY_EXCHANGE_OUTLINED: IconData + CURRENCY_EXCHANGE_ROUNDED: IconData + CURRENCY_EXCHANGE_SHARP: IconData + CURRENCY_FRANC: IconData + CURRENCY_FRANC_OUTLINED: IconData + CURRENCY_FRANC_ROUNDED: IconData + CURRENCY_FRANC_SHARP: IconData + CURRENCY_LIRA: IconData + CURRENCY_LIRA_OUTLINED: IconData + CURRENCY_LIRA_ROUNDED: IconData + CURRENCY_LIRA_SHARP: IconData + CURRENCY_POUND: IconData + CURRENCY_POUND_OUTLINED: IconData + CURRENCY_POUND_ROUNDED: IconData + CURRENCY_POUND_SHARP: IconData + CURRENCY_RUBLE: IconData + CURRENCY_RUBLE_OUTLINED: IconData + CURRENCY_RUBLE_ROUNDED: IconData + CURRENCY_RUBLE_SHARP: IconData + CURRENCY_RUPEE: IconData + CURRENCY_RUPEE_OUTLINED: IconData + CURRENCY_RUPEE_ROUNDED: IconData + CURRENCY_RUPEE_SHARP: IconData + CURRENCY_YEN: IconData + CURRENCY_YEN_OUTLINED: IconData + CURRENCY_YEN_ROUNDED: IconData + CURRENCY_YEN_SHARP: IconData + CURRENCY_YUAN: IconData + CURRENCY_YUAN_OUTLINED: IconData + CURRENCY_YUAN_ROUNDED: IconData + CURRENCY_YUAN_SHARP: IconData + CURTAINS: IconData + CURTAINS_CLOSED: IconData + CURTAINS_CLOSED_OUTLINED: IconData + CURTAINS_CLOSED_ROUNDED: IconData + CURTAINS_CLOSED_SHARP: IconData + CURTAINS_OUTLINED: IconData + CURTAINS_ROUNDED: IconData + CURTAINS_SHARP: IconData + CUT: IconData + CUT_OUTLINED: IconData + CUT_ROUNDED: IconData + CUT_SHARP: IconData + CYCLONE: IconData + CYCLONE_OUTLINED: IconData + CYCLONE_ROUNDED: IconData + CYCLONE_SHARP: IconData + DANGEROUS: IconData + DANGEROUS_OUTLINED: IconData + DANGEROUS_ROUNDED: IconData + DANGEROUS_SHARP: IconData + DARK_MODE: IconData + DARK_MODE_OUTLINED: IconData + DARK_MODE_ROUNDED: IconData + DARK_MODE_SHARP: IconData + DASHBOARD: IconData + DASHBOARD_CUSTOMIZE: IconData + DASHBOARD_CUSTOMIZE_OUTLINED: IconData + DASHBOARD_CUSTOMIZE_ROUNDED: IconData + DASHBOARD_CUSTOMIZE_SHARP: IconData + DASHBOARD_OUTLINED: IconData + DASHBOARD_ROUNDED: IconData + DASHBOARD_SHARP: IconData + DATA_ARRAY: IconData + DATA_ARRAY_OUTLINED: IconData + DATA_ARRAY_ROUNDED: IconData + DATA_ARRAY_SHARP: IconData + DATA_EXPLORATION: IconData + DATA_EXPLORATION_OUTLINED: IconData + DATA_EXPLORATION_ROUNDED: IconData + DATA_EXPLORATION_SHARP: IconData + DATA_OBJECT: IconData + DATA_OBJECT_OUTLINED: IconData + DATA_OBJECT_ROUNDED: IconData + DATA_OBJECT_SHARP: IconData + DATA_SAVER_OFF: IconData + DATA_SAVER_OFF_OUTLINED: IconData + DATA_SAVER_OFF_ROUNDED: IconData + DATA_SAVER_OFF_SHARP: IconData + DATA_SAVER_ON: IconData + DATA_SAVER_ON_OUTLINED: IconData + DATA_SAVER_ON_ROUNDED: IconData + DATA_SAVER_ON_SHARP: IconData + DATA_THRESHOLDING: IconData + DATA_THRESHOLDING_OUTLINED: IconData + DATA_THRESHOLDING_ROUNDED: IconData + DATA_THRESHOLDING_SHARP: IconData + DATA_USAGE: IconData + DATA_USAGE_OUTLINED: IconData + DATA_USAGE_ROUNDED: IconData + DATA_USAGE_SHARP: IconData + DATASET: IconData + DATASET_LINKED: IconData + DATASET_LINKED_OUTLINED: IconData + DATASET_LINKED_ROUNDED: IconData + DATASET_LINKED_SHARP: IconData + DATASET_OUTLINED: IconData + DATASET_ROUNDED: IconData + DATASET_SHARP: IconData + DATE_RANGE: IconData + DATE_RANGE_OUTLINED: IconData + DATE_RANGE_ROUNDED: IconData + DATE_RANGE_SHARP: IconData + DEBLUR: IconData + DEBLUR_OUTLINED: IconData + DEBLUR_ROUNDED: IconData + DEBLUR_SHARP: IconData + DECK: IconData + DECK_OUTLINED: IconData + DECK_ROUNDED: IconData + DECK_SHARP: IconData + DEHAZE: IconData + DEHAZE_OUTLINED: IconData + DEHAZE_ROUNDED: IconData + DEHAZE_SHARP: IconData + DELETE: IconData + DELETE_FOREVER: IconData + DELETE_FOREVER_OUTLINED: IconData + DELETE_FOREVER_ROUNDED: IconData + DELETE_FOREVER_SHARP: IconData + DELETE_OUTLINE: IconData + DELETE_OUTLINE_OUTLINED: IconData + DELETE_OUTLINE_ROUNDED: IconData + DELETE_OUTLINE_SHARP: IconData + DELETE_OUTLINED: IconData + DELETE_ROUNDED: IconData + DELETE_SHARP: IconData + DELETE_SWEEP: IconData + DELETE_SWEEP_OUTLINED: IconData + DELETE_SWEEP_ROUNDED: IconData + DELETE_SWEEP_SHARP: IconData + DELIVERY_DINING: IconData + DELIVERY_DINING_OUTLINED: IconData + DELIVERY_DINING_ROUNDED: IconData + DELIVERY_DINING_SHARP: IconData + DENSITY_LARGE: IconData + DENSITY_LARGE_OUTLINED: IconData + DENSITY_LARGE_ROUNDED: IconData + DENSITY_LARGE_SHARP: IconData + DENSITY_MEDIUM: IconData + DENSITY_MEDIUM_OUTLINED: IconData + DENSITY_MEDIUM_ROUNDED: IconData + DENSITY_MEDIUM_SHARP: IconData + DENSITY_SMALL: IconData + DENSITY_SMALL_OUTLINED: IconData + DENSITY_SMALL_ROUNDED: IconData + DENSITY_SMALL_SHARP: IconData + DEPARTURE_BOARD: IconData + DEPARTURE_BOARD_OUTLINED: IconData + DEPARTURE_BOARD_ROUNDED: IconData + DEPARTURE_BOARD_SHARP: IconData + DESCRIPTION: IconData + DESCRIPTION_OUTLINED: IconData + DESCRIPTION_ROUNDED: IconData + DESCRIPTION_SHARP: IconData + DESELECT: IconData + DESELECT_OUTLINED: IconData + DESELECT_ROUNDED: IconData + DESELECT_SHARP: IconData + DESIGN_SERVICES: IconData + DESIGN_SERVICES_OUTLINED: IconData + DESIGN_SERVICES_ROUNDED: IconData + DESIGN_SERVICES_SHARP: IconData + DESK: IconData + DESK_OUTLINED: IconData + DESK_ROUNDED: IconData + DESK_SHARP: IconData + DESKTOP_ACCESS_DISABLED: IconData + DESKTOP_ACCESS_DISABLED_OUTLINED: IconData + DESKTOP_ACCESS_DISABLED_ROUNDED: IconData + DESKTOP_ACCESS_DISABLED_SHARP: IconData + DESKTOP_MAC: IconData + DESKTOP_MAC_OUTLINED: IconData + DESKTOP_MAC_ROUNDED: IconData + DESKTOP_MAC_SHARP: IconData + DESKTOP_WINDOWS: IconData + DESKTOP_WINDOWS_OUTLINED: IconData + DESKTOP_WINDOWS_ROUNDED: IconData + DESKTOP_WINDOWS_SHARP: IconData + DETAILS: IconData + DETAILS_OUTLINED: IconData + DETAILS_ROUNDED: IconData + DETAILS_SHARP: IconData + DEVELOPER_BOARD: IconData + DEVELOPER_BOARD_OFF: IconData + DEVELOPER_BOARD_OFF_OUTLINED: IconData + DEVELOPER_BOARD_OFF_ROUNDED: IconData + DEVELOPER_BOARD_OFF_SHARP: IconData + DEVELOPER_BOARD_OUTLINED: IconData + DEVELOPER_BOARD_ROUNDED: IconData + DEVELOPER_BOARD_SHARP: IconData + DEVELOPER_MODE: IconData + DEVELOPER_MODE_OUTLINED: IconData + DEVELOPER_MODE_ROUNDED: IconData + DEVELOPER_MODE_SHARP: IconData + DEVICE_HUB: IconData + DEVICE_HUB_OUTLINED: IconData + DEVICE_HUB_ROUNDED: IconData + DEVICE_HUB_SHARP: IconData + DEVICE_THERMOSTAT: IconData + DEVICE_THERMOSTAT_OUTLINED: IconData + DEVICE_THERMOSTAT_ROUNDED: IconData + DEVICE_THERMOSTAT_SHARP: IconData + DEVICE_UNKNOWN: IconData + DEVICE_UNKNOWN_OUTLINED: IconData + DEVICE_UNKNOWN_ROUNDED: IconData + DEVICE_UNKNOWN_SHARP: IconData + DEVICES: IconData + DEVICES_FOLD: IconData + DEVICES_FOLD_OUTLINED: IconData + DEVICES_FOLD_ROUNDED: IconData + DEVICES_FOLD_SHARP: IconData + DEVICES_OTHER: IconData + DEVICES_OTHER_OUTLINED: IconData + DEVICES_OTHER_ROUNDED: IconData + DEVICES_OTHER_SHARP: IconData + DEVICES_OUTLINED: IconData + DEVICES_ROUNDED: IconData + DEVICES_SHARP: IconData + DEW_POINT: IconData + DIALER_SIP: IconData + DIALER_SIP_OUTLINED: IconData + DIALER_SIP_ROUNDED: IconData + DIALER_SIP_SHARP: IconData + DIALPAD: IconData + DIALPAD_OUTLINED: IconData + DIALPAD_ROUNDED: IconData + DIALPAD_SHARP: IconData + DIAMOND: IconData + DIAMOND_OUTLINED: IconData + DIAMOND_ROUNDED: IconData + DIAMOND_SHARP: IconData + DIFFERENCE: IconData + DIFFERENCE_OUTLINED: IconData + DIFFERENCE_ROUNDED: IconData + DIFFERENCE_SHARP: IconData + DINING: IconData + DINING_OUTLINED: IconData + DINING_ROUNDED: IconData + DINING_SHARP: IconData + DINNER_DINING: IconData + DINNER_DINING_OUTLINED: IconData + DINNER_DINING_ROUNDED: IconData + DINNER_DINING_SHARP: IconData + DIRECTIONS: IconData + DIRECTIONS_BIKE: IconData + DIRECTIONS_BIKE_OUTLINED: IconData + DIRECTIONS_BIKE_ROUNDED: IconData + DIRECTIONS_BIKE_SHARP: IconData + DIRECTIONS_BOAT: IconData + DIRECTIONS_BOAT_FILLED: IconData + DIRECTIONS_BOAT_FILLED_OUTLINED: IconData + DIRECTIONS_BOAT_FILLED_ROUNDED: IconData + DIRECTIONS_BOAT_FILLED_SHARP: IconData + DIRECTIONS_BOAT_OUTLINED: IconData + DIRECTIONS_BOAT_ROUNDED: IconData + DIRECTIONS_BOAT_SHARP: IconData + DIRECTIONS_BUS: IconData + DIRECTIONS_BUS_FILLED: IconData + DIRECTIONS_BUS_FILLED_OUTLINED: IconData + DIRECTIONS_BUS_FILLED_ROUNDED: IconData + DIRECTIONS_BUS_FILLED_SHARP: IconData + DIRECTIONS_BUS_OUTLINED: IconData + DIRECTIONS_BUS_ROUNDED: IconData + DIRECTIONS_BUS_SHARP: IconData + DIRECTIONS_CAR: IconData + DIRECTIONS_CAR_FILLED: IconData + DIRECTIONS_CAR_FILLED_OUTLINED: IconData + DIRECTIONS_CAR_FILLED_ROUNDED: IconData + DIRECTIONS_CAR_FILLED_SHARP: IconData + DIRECTIONS_CAR_OUTLINED: IconData + DIRECTIONS_CAR_ROUNDED: IconData + DIRECTIONS_CAR_SHARP: IconData + DIRECTIONS_FERRY: IconData + DIRECTIONS_FERRY_OUTLINED: IconData + DIRECTIONS_FERRY_ROUNDED: IconData + DIRECTIONS_FERRY_SHARP: IconData + DIRECTIONS_OFF: IconData + DIRECTIONS_OFF_OUTLINED: IconData + DIRECTIONS_OFF_ROUNDED: IconData + DIRECTIONS_OFF_SHARP: IconData + DIRECTIONS_OUTLINED: IconData + DIRECTIONS_RAILWAY: IconData + DIRECTIONS_RAILWAY_FILLED: IconData + DIRECTIONS_RAILWAY_FILLED_OUTLINED: IconData + DIRECTIONS_RAILWAY_FILLED_ROUNDED: IconData + DIRECTIONS_RAILWAY_FILLED_SHARP: IconData + DIRECTIONS_RAILWAY_OUTLINED: IconData + DIRECTIONS_RAILWAY_ROUNDED: IconData + DIRECTIONS_RAILWAY_SHARP: IconData + DIRECTIONS_ROUNDED: IconData + DIRECTIONS_RUN: IconData + DIRECTIONS_RUN_OUTLINED: IconData + DIRECTIONS_RUN_ROUNDED: IconData + DIRECTIONS_RUN_SHARP: IconData + DIRECTIONS_SHARP: IconData + DIRECTIONS_SUBWAY: IconData + DIRECTIONS_SUBWAY_FILLED: IconData + DIRECTIONS_SUBWAY_FILLED_OUTLINED: IconData + DIRECTIONS_SUBWAY_FILLED_ROUNDED: IconData + DIRECTIONS_SUBWAY_FILLED_SHARP: IconData + DIRECTIONS_SUBWAY_OUTLINED: IconData + DIRECTIONS_SUBWAY_ROUNDED: IconData + DIRECTIONS_SUBWAY_SHARP: IconData + DIRECTIONS_TRAIN: IconData + DIRECTIONS_TRAIN_OUTLINED: IconData + DIRECTIONS_TRAIN_ROUNDED: IconData + DIRECTIONS_TRAIN_SHARP: IconData + DIRECTIONS_TRANSIT: IconData + DIRECTIONS_TRANSIT_FILLED: IconData + DIRECTIONS_TRANSIT_FILLED_OUTLINED: IconData + DIRECTIONS_TRANSIT_FILLED_ROUNDED: IconData + DIRECTIONS_TRANSIT_FILLED_SHARP: IconData + DIRECTIONS_TRANSIT_OUTLINED: IconData + DIRECTIONS_TRANSIT_ROUNDED: IconData + DIRECTIONS_TRANSIT_SHARP: IconData + DIRECTIONS_WALK: IconData + DIRECTIONS_WALK_OUTLINED: IconData + DIRECTIONS_WALK_ROUNDED: IconData + DIRECTIONS_WALK_SHARP: IconData + DIRTY_LENS: IconData + DIRTY_LENS_OUTLINED: IconData + DIRTY_LENS_ROUNDED: IconData + DIRTY_LENS_SHARP: IconData + DISABLED_BY_DEFAULT: IconData + DISABLED_BY_DEFAULT_OUTLINED: IconData + DISABLED_BY_DEFAULT_ROUNDED: IconData + DISABLED_BY_DEFAULT_SHARP: IconData + DISABLED_VISIBLE: IconData + DISABLED_VISIBLE_OUTLINED: IconData + DISABLED_VISIBLE_ROUNDED: IconData + DISABLED_VISIBLE_SHARP: IconData + DISC_FULL: IconData + DISC_FULL_OUTLINED: IconData + DISC_FULL_ROUNDED: IconData + DISC_FULL_SHARP: IconData + DISCORD: IconData + DISCORD_OUTLINED: IconData + DISCORD_ROUNDED: IconData + DISCORD_SHARP: IconData + DISCOUNT: IconData + DISCOUNT_OUTLINED: IconData + DISCOUNT_ROUNDED: IconData + DISCOUNT_SHARP: IconData + DISPLAY_SETTINGS: IconData + DISPLAY_SETTINGS_OUTLINED: IconData + DISPLAY_SETTINGS_ROUNDED: IconData + DISPLAY_SETTINGS_SHARP: IconData + DIVERSITY_1: IconData + DIVERSITY_1_OUTLINED: IconData + DIVERSITY_1_ROUNDED: IconData + DIVERSITY_1_SHARP: IconData + DIVERSITY_2: IconData + DIVERSITY_2_OUTLINED: IconData + DIVERSITY_2_ROUNDED: IconData + DIVERSITY_2_SHARP: IconData + DIVERSITY_3: IconData + DIVERSITY_3_OUTLINED: IconData + DIVERSITY_3_ROUNDED: IconData + DIVERSITY_3_SHARP: IconData + DND_FORWARDSLASH: IconData + DND_FORWARDSLASH_OUTLINED: IconData + DND_FORWARDSLASH_ROUNDED: IconData + DND_FORWARDSLASH_SHARP: IconData + DNS: IconData + DNS_OUTLINED: IconData + DNS_ROUNDED: IconData + DNS_SHARP: IconData + DO_DISTURB: IconData + DO_DISTURB_ALT: IconData + DO_DISTURB_ALT_OUTLINED: IconData + DO_DISTURB_ALT_ROUNDED: IconData + DO_DISTURB_ALT_SHARP: IconData + DO_DISTURB_OFF: IconData + DO_DISTURB_OFF_OUTLINED: IconData + DO_DISTURB_OFF_ROUNDED: IconData + DO_DISTURB_OFF_SHARP: IconData + DO_DISTURB_ON: IconData + DO_DISTURB_ON_OUTLINED: IconData + DO_DISTURB_ON_ROUNDED: IconData + DO_DISTURB_ON_SHARP: IconData + DO_DISTURB_OUTLINED: IconData + DO_DISTURB_ROUNDED: IconData + DO_DISTURB_SHARP: IconData + DO_NOT_DISTURB: IconData + DO_NOT_DISTURB_ALT: IconData + DO_NOT_DISTURB_ALT_OUTLINED: IconData + DO_NOT_DISTURB_ALT_ROUNDED: IconData + DO_NOT_DISTURB_ALT_SHARP: IconData + DO_NOT_DISTURB_OFF: IconData + DO_NOT_DISTURB_OFF_OUTLINED: IconData + DO_NOT_DISTURB_OFF_ROUNDED: IconData + DO_NOT_DISTURB_OFF_SHARP: IconData + DO_NOT_DISTURB_ON: IconData + DO_NOT_DISTURB_ON_OUTLINED: IconData + DO_NOT_DISTURB_ON_ROUNDED: IconData + DO_NOT_DISTURB_ON_SHARP: IconData + DO_NOT_DISTURB_ON_TOTAL_SILENCE: IconData + DO_NOT_DISTURB_ON_TOTAL_SILENCE_OUTLINED: IconData + DO_NOT_DISTURB_ON_TOTAL_SILENCE_ROUNDED: IconData + DO_NOT_DISTURB_ON_TOTAL_SILENCE_SHARP: IconData + DO_NOT_DISTURB_OUTLINED: IconData + DO_NOT_DISTURB_ROUNDED: IconData + DO_NOT_DISTURB_SHARP: IconData + DO_NOT_STEP: IconData + DO_NOT_STEP_OUTLINED: IconData + DO_NOT_STEP_ROUNDED: IconData + DO_NOT_STEP_SHARP: IconData + DO_NOT_TOUCH: IconData + DO_NOT_TOUCH_OUTLINED: IconData + DO_NOT_TOUCH_ROUNDED: IconData + DO_NOT_TOUCH_SHARP: IconData + DOCK: IconData + DOCK_OUTLINED: IconData + DOCK_ROUNDED: IconData + DOCK_SHARP: IconData + DOCUMENT_SCANNER: IconData + DOCUMENT_SCANNER_OUTLINED: IconData + DOCUMENT_SCANNER_ROUNDED: IconData + DOCUMENT_SCANNER_SHARP: IconData + DOMAIN: IconData + DOMAIN_ADD: IconData + DOMAIN_ADD_OUTLINED: IconData + DOMAIN_ADD_ROUNDED: IconData + DOMAIN_ADD_SHARP: IconData + DOMAIN_DISABLED: IconData + DOMAIN_DISABLED_OUTLINED: IconData + DOMAIN_DISABLED_ROUNDED: IconData + DOMAIN_DISABLED_SHARP: IconData + DOMAIN_OUTLINED: IconData + DOMAIN_ROUNDED: IconData + DOMAIN_SHARP: IconData + DOMAIN_VERIFICATION: IconData + DOMAIN_VERIFICATION_OUTLINED: IconData + DOMAIN_VERIFICATION_ROUNDED: IconData + DOMAIN_VERIFICATION_SHARP: IconData + DONE: IconData + DONE_ALL: IconData + DONE_ALL_OUTLINED: IconData + DONE_ALL_ROUNDED: IconData + DONE_ALL_SHARP: IconData + DONE_OUTLINE: IconData + DONE_OUTLINE_OUTLINED: IconData + DONE_OUTLINE_ROUNDED: IconData + DONE_OUTLINE_SHARP: IconData + DONE_OUTLINED: IconData + DONE_ROUNDED: IconData + DONE_SHARP: IconData + DONUT_LARGE: IconData + DONUT_LARGE_OUTLINED: IconData + DONUT_LARGE_ROUNDED: IconData + DONUT_LARGE_SHARP: IconData + DONUT_SMALL: IconData + DONUT_SMALL_OUTLINED: IconData + DONUT_SMALL_ROUNDED: IconData + DONUT_SMALL_SHARP: IconData + DOOR_BACK_DOOR: IconData + DOOR_BACK_DOOR_OUTLINED: IconData + DOOR_BACK_DOOR_ROUNDED: IconData + DOOR_BACK_DOOR_SHARP: IconData + DOOR_FRONT_DOOR: IconData + DOOR_FRONT_DOOR_OUTLINED: IconData + DOOR_FRONT_DOOR_ROUNDED: IconData + DOOR_FRONT_DOOR_SHARP: IconData + DOOR_SLIDING: IconData + DOOR_SLIDING_OUTLINED: IconData + DOOR_SLIDING_ROUNDED: IconData + DOOR_SLIDING_SHARP: IconData + DOORBELL: IconData + DOORBELL_OUTLINED: IconData + DOORBELL_ROUNDED: IconData + DOORBELL_SHARP: IconData + DOUBLE_ARROW: IconData + DOUBLE_ARROW_OUTLINED: IconData + DOUBLE_ARROW_ROUNDED: IconData + DOUBLE_ARROW_SHARP: IconData + DOWNHILL_SKIING: IconData + DOWNHILL_SKIING_OUTLINED: IconData + DOWNHILL_SKIING_ROUNDED: IconData + DOWNHILL_SKIING_SHARP: IconData + DOWNLOAD: IconData + DOWNLOAD_DONE: IconData + DOWNLOAD_DONE_OUTLINED: IconData + DOWNLOAD_DONE_ROUNDED: IconData + DOWNLOAD_DONE_SHARP: IconData + DOWNLOAD_FOR_OFFLINE: IconData + DOWNLOAD_FOR_OFFLINE_OUTLINED: IconData + DOWNLOAD_FOR_OFFLINE_ROUNDED: IconData + DOWNLOAD_FOR_OFFLINE_SHARP: IconData + DOWNLOAD_OUTLINED: IconData + DOWNLOAD_ROUNDED: IconData + DOWNLOAD_SHARP: IconData + DOWNLOADING: IconData + DOWNLOADING_OUTLINED: IconData + DOWNLOADING_ROUNDED: IconData + DOWNLOADING_SHARP: IconData + DRAFTS: IconData + DRAFTS_OUTLINED: IconData + DRAFTS_ROUNDED: IconData + DRAFTS_SHARP: IconData + DRAG_HANDLE: IconData + DRAG_HANDLE_OUTLINED: IconData + DRAG_HANDLE_ROUNDED: IconData + DRAG_HANDLE_SHARP: IconData + DRAG_INDICATOR: IconData + DRAG_INDICATOR_OUTLINED: IconData + DRAG_INDICATOR_ROUNDED: IconData + DRAG_INDICATOR_SHARP: IconData + DRAW: IconData + DRAW_OUTLINED: IconData + DRAW_ROUNDED: IconData + DRAW_SHARP: IconData + DRIVE_ETA: IconData + DRIVE_ETA_OUTLINED: IconData + DRIVE_ETA_ROUNDED: IconData + DRIVE_ETA_SHARP: IconData + DRIVE_FILE_MOVE: IconData + DRIVE_FILE_MOVE_OUTLINE: IconData + DRIVE_FILE_MOVE_OUTLINED: IconData + DRIVE_FILE_MOVE_ROUNDED: IconData + DRIVE_FILE_MOVE_RTL: IconData + DRIVE_FILE_MOVE_RTL_OUTLINED: IconData + DRIVE_FILE_MOVE_RTL_ROUNDED: IconData + DRIVE_FILE_MOVE_RTL_SHARP: IconData + DRIVE_FILE_MOVE_SHARP: IconData + DRIVE_FILE_RENAME_OUTLINE: IconData + DRIVE_FILE_RENAME_OUTLINE_OUTLINED: IconData + DRIVE_FILE_RENAME_OUTLINE_ROUNDED: IconData + DRIVE_FILE_RENAME_OUTLINE_SHARP: IconData + DRIVE_FOLDER_UPLOAD: IconData + DRIVE_FOLDER_UPLOAD_OUTLINED: IconData + DRIVE_FOLDER_UPLOAD_ROUNDED: IconData + DRIVE_FOLDER_UPLOAD_SHARP: IconData + DRY: IconData + DRY_CLEANING: IconData + DRY_CLEANING_OUTLINED: IconData + DRY_CLEANING_ROUNDED: IconData + DRY_CLEANING_SHARP: IconData + DRY_OUTLINED: IconData + DRY_ROUNDED: IconData + DRY_SHARP: IconData + DUO: IconData + DUO_OUTLINED: IconData + DUO_ROUNDED: IconData + DUO_SHARP: IconData + DVR: IconData + DVR_OUTLINED: IconData + DVR_ROUNDED: IconData + DVR_SHARP: IconData + DYNAMIC_FEED: IconData + DYNAMIC_FEED_OUTLINED: IconData + DYNAMIC_FEED_ROUNDED: IconData + DYNAMIC_FEED_SHARP: IconData + DYNAMIC_FORM: IconData + DYNAMIC_FORM_OUTLINED: IconData + DYNAMIC_FORM_ROUNDED: IconData + DYNAMIC_FORM_SHARP: IconData + E_MOBILEDATA: IconData + E_MOBILEDATA_OUTLINED: IconData + E_MOBILEDATA_ROUNDED: IconData + E_MOBILEDATA_SHARP: IconData + EARBUDS: IconData + EARBUDS_BATTERY: IconData + EARBUDS_BATTERY_OUTLINED: IconData + EARBUDS_BATTERY_ROUNDED: IconData + EARBUDS_BATTERY_SHARP: IconData + EARBUDS_OUTLINED: IconData + EARBUDS_ROUNDED: IconData + EARBUDS_SHARP: IconData + EAST: IconData + EAST_OUTLINED: IconData + EAST_ROUNDED: IconData + EAST_SHARP: IconData + ECO: IconData + ECO_OUTLINED: IconData + ECO_ROUNDED: IconData + ECO_SHARP: IconData + EDGESENSOR_HIGH: IconData + EDGESENSOR_HIGH_OUTLINED: IconData + EDGESENSOR_HIGH_ROUNDED: IconData + EDGESENSOR_HIGH_SHARP: IconData + EDGESENSOR_LOW: IconData + EDGESENSOR_LOW_OUTLINED: IconData + EDGESENSOR_LOW_ROUNDED: IconData + EDGESENSOR_LOW_SHARP: IconData + EDIT: IconData + EDIT_ATTRIBUTES: IconData + EDIT_ATTRIBUTES_OUTLINED: IconData + EDIT_ATTRIBUTES_ROUNDED: IconData + EDIT_ATTRIBUTES_SHARP: IconData + EDIT_CALENDAR: IconData + EDIT_CALENDAR_OUTLINED: IconData + EDIT_CALENDAR_ROUNDED: IconData + EDIT_CALENDAR_SHARP: IconData + EDIT_DOCUMENT: IconData + EDIT_LOCATION: IconData + EDIT_LOCATION_ALT: IconData + EDIT_LOCATION_ALT_OUTLINED: IconData + EDIT_LOCATION_ALT_ROUNDED: IconData + EDIT_LOCATION_ALT_SHARP: IconData + EDIT_LOCATION_OUTLINED: IconData + EDIT_LOCATION_ROUNDED: IconData + EDIT_LOCATION_SHARP: IconData + EDIT_NOTE: IconData + EDIT_NOTE_OUTLINED: IconData + EDIT_NOTE_ROUNDED: IconData + EDIT_NOTE_SHARP: IconData + EDIT_NOTIFICATIONS: IconData + EDIT_NOTIFICATIONS_OUTLINED: IconData + EDIT_NOTIFICATIONS_ROUNDED: IconData + EDIT_NOTIFICATIONS_SHARP: IconData + EDIT_OFF: IconData + EDIT_OFF_OUTLINED: IconData + EDIT_OFF_ROUNDED: IconData + EDIT_OFF_SHARP: IconData + EDIT_OUTLINED: IconData + EDIT_ROAD: IconData + EDIT_ROAD_OUTLINED: IconData + EDIT_ROAD_ROUNDED: IconData + EDIT_ROAD_SHARP: IconData + EDIT_ROUNDED: IconData + EDIT_SHARP: IconData + EDIT_SQUARE: IconData + EGG: IconData + EGG_ALT: IconData + EGG_ALT_OUTLINED: IconData + EGG_ALT_ROUNDED: IconData + EGG_ALT_SHARP: IconData + EGG_OUTLINED: IconData + EGG_ROUNDED: IconData + EGG_SHARP: IconData + EIGHT_K: IconData + EIGHT_K_OUTLINED: IconData + EIGHT_K_PLUS: IconData + EIGHT_K_PLUS_OUTLINED: IconData + EIGHT_K_PLUS_ROUNDED: IconData + EIGHT_K_PLUS_SHARP: IconData + EIGHT_K_ROUNDED: IconData + EIGHT_K_SHARP: IconData + EIGHT_MP: IconData + EIGHT_MP_OUTLINED: IconData + EIGHT_MP_ROUNDED: IconData + EIGHT_MP_SHARP: IconData + EIGHTEEN_MP: IconData + EIGHTEEN_MP_OUTLINED: IconData + EIGHTEEN_MP_ROUNDED: IconData + EIGHTEEN_MP_SHARP: IconData + EIGHTEEN_UP_RATING: IconData + EIGHTEEN_UP_RATING_OUTLINED: IconData + EIGHTEEN_UP_RATING_ROUNDED: IconData + EIGHTEEN_UP_RATING_SHARP: IconData + EJECT: IconData + EJECT_OUTLINED: IconData + EJECT_ROUNDED: IconData + EJECT_SHARP: IconData + ELDERLY: IconData + ELDERLY_OUTLINED: IconData + ELDERLY_ROUNDED: IconData + ELDERLY_SHARP: IconData + ELDERLY_WOMAN: IconData + ELDERLY_WOMAN_OUTLINED: IconData + ELDERLY_WOMAN_ROUNDED: IconData + ELDERLY_WOMAN_SHARP: IconData + ELECTRIC_BIKE: IconData + ELECTRIC_BIKE_OUTLINED: IconData + ELECTRIC_BIKE_ROUNDED: IconData + ELECTRIC_BIKE_SHARP: IconData + ELECTRIC_BOLT: IconData + ELECTRIC_BOLT_OUTLINED: IconData + ELECTRIC_BOLT_ROUNDED: IconData + ELECTRIC_BOLT_SHARP: IconData + ELECTRIC_CAR: IconData + ELECTRIC_CAR_OUTLINED: IconData + ELECTRIC_CAR_ROUNDED: IconData + ELECTRIC_CAR_SHARP: IconData + ELECTRIC_METER: IconData + ELECTRIC_METER_OUTLINED: IconData + ELECTRIC_METER_ROUNDED: IconData + ELECTRIC_METER_SHARP: IconData + ELECTRIC_MOPED: IconData + ELECTRIC_MOPED_OUTLINED: IconData + ELECTRIC_MOPED_ROUNDED: IconData + ELECTRIC_MOPED_SHARP: IconData + ELECTRIC_RICKSHAW: IconData + ELECTRIC_RICKSHAW_OUTLINED: IconData + ELECTRIC_RICKSHAW_ROUNDED: IconData + ELECTRIC_RICKSHAW_SHARP: IconData + ELECTRIC_SCOOTER: IconData + ELECTRIC_SCOOTER_OUTLINED: IconData + ELECTRIC_SCOOTER_ROUNDED: IconData + ELECTRIC_SCOOTER_SHARP: IconData + ELECTRICAL_SERVICES: IconData + ELECTRICAL_SERVICES_OUTLINED: IconData + ELECTRICAL_SERVICES_ROUNDED: IconData + ELECTRICAL_SERVICES_SHARP: IconData + ELEVATOR: IconData + ELEVATOR_OUTLINED: IconData + ELEVATOR_ROUNDED: IconData + ELEVATOR_SHARP: IconData + ELEVEN_MP: IconData + ELEVEN_MP_OUTLINED: IconData + ELEVEN_MP_ROUNDED: IconData + ELEVEN_MP_SHARP: IconData + EMAIL: IconData + EMAIL_OUTLINED: IconData + EMAIL_ROUNDED: IconData + EMAIL_SHARP: IconData + EMERGENCY: IconData + EMERGENCY_OUTLINED: IconData + EMERGENCY_RECORDING: IconData + EMERGENCY_RECORDING_OUTLINED: IconData + EMERGENCY_RECORDING_ROUNDED: IconData + EMERGENCY_RECORDING_SHARP: IconData + EMERGENCY_ROUNDED: IconData + EMERGENCY_SHARE: IconData + EMERGENCY_SHARE_OUTLINED: IconData + EMERGENCY_SHARE_ROUNDED: IconData + EMERGENCY_SHARE_SHARP: IconData + EMERGENCY_SHARP: IconData + EMOJI_EMOTIONS: IconData + EMOJI_EMOTIONS_OUTLINED: IconData + EMOJI_EMOTIONS_ROUNDED: IconData + EMOJI_EMOTIONS_SHARP: IconData + EMOJI_EVENTS: IconData + EMOJI_EVENTS_OUTLINED: IconData + EMOJI_EVENTS_ROUNDED: IconData + EMOJI_EVENTS_SHARP: IconData + EMOJI_FLAGS: IconData + EMOJI_FLAGS_OUTLINED: IconData + EMOJI_FLAGS_ROUNDED: IconData + EMOJI_FLAGS_SHARP: IconData + EMOJI_FOOD_BEVERAGE: IconData + EMOJI_FOOD_BEVERAGE_OUTLINED: IconData + EMOJI_FOOD_BEVERAGE_ROUNDED: IconData + EMOJI_FOOD_BEVERAGE_SHARP: IconData + EMOJI_NATURE: IconData + EMOJI_NATURE_OUTLINED: IconData + EMOJI_NATURE_ROUNDED: IconData + EMOJI_NATURE_SHARP: IconData + EMOJI_OBJECTS: IconData + EMOJI_OBJECTS_OUTLINED: IconData + EMOJI_OBJECTS_ROUNDED: IconData + EMOJI_OBJECTS_SHARP: IconData + EMOJI_PEOPLE: IconData + EMOJI_PEOPLE_OUTLINED: IconData + EMOJI_PEOPLE_ROUNDED: IconData + EMOJI_PEOPLE_SHARP: IconData + EMOJI_SYMBOLS: IconData + EMOJI_SYMBOLS_OUTLINED: IconData + EMOJI_SYMBOLS_ROUNDED: IconData + EMOJI_SYMBOLS_SHARP: IconData + EMOJI_TRANSPORTATION: IconData + EMOJI_TRANSPORTATION_OUTLINED: IconData + EMOJI_TRANSPORTATION_ROUNDED: IconData + EMOJI_TRANSPORTATION_SHARP: IconData + ENERGY_SAVINGS_LEAF: IconData + ENERGY_SAVINGS_LEAF_OUTLINED: IconData + ENERGY_SAVINGS_LEAF_ROUNDED: IconData + ENERGY_SAVINGS_LEAF_SHARP: IconData + ENGINEERING: IconData + ENGINEERING_OUTLINED: IconData + ENGINEERING_ROUNDED: IconData + ENGINEERING_SHARP: IconData + ENHANCE_PHOTO_TRANSLATE: IconData + ENHANCE_PHOTO_TRANSLATE_OUTLINED: IconData + ENHANCE_PHOTO_TRANSLATE_ROUNDED: IconData + ENHANCE_PHOTO_TRANSLATE_SHARP: IconData + ENHANCED_ENCRYPTION: IconData + ENHANCED_ENCRYPTION_OUTLINED: IconData + ENHANCED_ENCRYPTION_ROUNDED: IconData + ENHANCED_ENCRYPTION_SHARP: IconData + EQUALIZER: IconData + EQUALIZER_OUTLINED: IconData + EQUALIZER_ROUNDED: IconData + EQUALIZER_SHARP: IconData + ERROR: IconData + ERROR_OUTLINE: IconData + ERROR_OUTLINE_OUTLINED: IconData + ERROR_OUTLINE_ROUNDED: IconData + ERROR_OUTLINE_SHARP: IconData + ERROR_OUTLINED: IconData + ERROR_ROUNDED: IconData + ERROR_SHARP: IconData + ESCALATOR: IconData + ESCALATOR_OUTLINED: IconData + ESCALATOR_ROUNDED: IconData + ESCALATOR_SHARP: IconData + ESCALATOR_WARNING: IconData + ESCALATOR_WARNING_OUTLINED: IconData + ESCALATOR_WARNING_ROUNDED: IconData + ESCALATOR_WARNING_SHARP: IconData + EURO: IconData + EURO_OUTLINED: IconData + EURO_ROUNDED: IconData + EURO_SHARP: IconData + EURO_SYMBOL: IconData + EURO_SYMBOL_OUTLINED: IconData + EURO_SYMBOL_ROUNDED: IconData + EURO_SYMBOL_SHARP: IconData + EV_STATION: IconData + EV_STATION_OUTLINED: IconData + EV_STATION_ROUNDED: IconData + EV_STATION_SHARP: IconData + EVENT: IconData + EVENT_AVAILABLE: IconData + EVENT_AVAILABLE_OUTLINED: IconData + EVENT_AVAILABLE_ROUNDED: IconData + EVENT_AVAILABLE_SHARP: IconData + EVENT_BUSY: IconData + EVENT_BUSY_OUTLINED: IconData + EVENT_BUSY_ROUNDED: IconData + EVENT_BUSY_SHARP: IconData + EVENT_NOTE: IconData + EVENT_NOTE_OUTLINED: IconData + EVENT_NOTE_ROUNDED: IconData + EVENT_NOTE_SHARP: IconData + EVENT_OUTLINED: IconData + EVENT_REPEAT: IconData + EVENT_REPEAT_OUTLINED: IconData + EVENT_REPEAT_ROUNDED: IconData + EVENT_REPEAT_SHARP: IconData + EVENT_ROUNDED: IconData + EVENT_SEAT: IconData + EVENT_SEAT_OUTLINED: IconData + EVENT_SEAT_ROUNDED: IconData + EVENT_SEAT_SHARP: IconData + EVENT_SHARP: IconData + EXIT_TO_APP: IconData + EXIT_TO_APP_OUTLINED: IconData + EXIT_TO_APP_ROUNDED: IconData + EXIT_TO_APP_SHARP: IconData + EXPAND: IconData + EXPAND_CIRCLE_DOWN: IconData + EXPAND_CIRCLE_DOWN_OUTLINED: IconData + EXPAND_CIRCLE_DOWN_ROUNDED: IconData + EXPAND_CIRCLE_DOWN_SHARP: IconData + EXPAND_LESS: IconData + EXPAND_LESS_OUTLINED: IconData + EXPAND_LESS_ROUNDED: IconData + EXPAND_LESS_SHARP: IconData + EXPAND_MORE: IconData + EXPAND_MORE_OUTLINED: IconData + EXPAND_MORE_ROUNDED: IconData + EXPAND_MORE_SHARP: IconData + EXPAND_OUTLINED: IconData + EXPAND_ROUNDED: IconData + EXPAND_SHARP: IconData + EXPLICIT: IconData + EXPLICIT_OUTLINED: IconData + EXPLICIT_ROUNDED: IconData + EXPLICIT_SHARP: IconData + EXPLORE: IconData + EXPLORE_OFF: IconData + EXPLORE_OFF_OUTLINED: IconData + EXPLORE_OFF_ROUNDED: IconData + EXPLORE_OFF_SHARP: IconData + EXPLORE_OUTLINED: IconData + EXPLORE_ROUNDED: IconData + EXPLORE_SHARP: IconData + EXPOSURE: IconData + EXPOSURE_MINUS_1: IconData + EXPOSURE_MINUS_1_OUTLINED: IconData + EXPOSURE_MINUS_1_ROUNDED: IconData + EXPOSURE_MINUS_1_SHARP: IconData + EXPOSURE_MINUS_2: IconData + EXPOSURE_MINUS_2_OUTLINED: IconData + EXPOSURE_MINUS_2_ROUNDED: IconData + EXPOSURE_MINUS_2_SHARP: IconData + EXPOSURE_NEG_1: IconData + EXPOSURE_NEG_1_OUTLINED: IconData + EXPOSURE_NEG_1_ROUNDED: IconData + EXPOSURE_NEG_1_SHARP: IconData + EXPOSURE_NEG_2: IconData + EXPOSURE_NEG_2_OUTLINED: IconData + EXPOSURE_NEG_2_ROUNDED: IconData + EXPOSURE_NEG_2_SHARP: IconData + EXPOSURE_OUTLINED: IconData + EXPOSURE_PLUS_1: IconData + EXPOSURE_PLUS_1_OUTLINED: IconData + EXPOSURE_PLUS_1_ROUNDED: IconData + EXPOSURE_PLUS_1_SHARP: IconData + EXPOSURE_PLUS_2: IconData + EXPOSURE_PLUS_2_OUTLINED: IconData + EXPOSURE_PLUS_2_ROUNDED: IconData + EXPOSURE_PLUS_2_SHARP: IconData + EXPOSURE_ROUNDED: IconData + EXPOSURE_SHARP: IconData + EXPOSURE_ZERO: IconData + EXPOSURE_ZERO_OUTLINED: IconData + EXPOSURE_ZERO_ROUNDED: IconData + EXPOSURE_ZERO_SHARP: IconData + EXTENSION: IconData + EXTENSION_OFF: IconData + EXTENSION_OFF_OUTLINED: IconData + EXTENSION_OFF_ROUNDED: IconData + EXTENSION_OFF_SHARP: IconData + EXTENSION_OUTLINED: IconData + EXTENSION_ROUNDED: IconData + EXTENSION_SHARP: IconData + FACE: IconData + FACE_2: IconData + FACE_2_OUTLINED: IconData + FACE_2_ROUNDED: IconData + FACE_2_SHARP: IconData + FACE_3: IconData + FACE_3_OUTLINED: IconData + FACE_3_ROUNDED: IconData + FACE_3_SHARP: IconData + FACE_4: IconData + FACE_4_OUTLINED: IconData + FACE_4_ROUNDED: IconData + FACE_4_SHARP: IconData + FACE_5: IconData + FACE_5_OUTLINED: IconData + FACE_5_ROUNDED: IconData + FACE_5_SHARP: IconData + FACE_6: IconData + FACE_6_OUTLINED: IconData + FACE_6_ROUNDED: IconData + FACE_6_SHARP: IconData + FACE_OUTLINED: IconData + FACE_RETOUCHING_NATURAL: IconData + FACE_RETOUCHING_NATURAL_OUTLINED: IconData + FACE_RETOUCHING_NATURAL_ROUNDED: IconData + FACE_RETOUCHING_NATURAL_SHARP: IconData + FACE_RETOUCHING_OFF: IconData + FACE_RETOUCHING_OFF_OUTLINED: IconData + FACE_RETOUCHING_OFF_ROUNDED: IconData + FACE_RETOUCHING_OFF_SHARP: IconData + FACE_ROUNDED: IconData + FACE_SHARP: IconData + FACE_UNLOCK_OUTLINED: IconData + FACE_UNLOCK_ROUNDED: IconData + FACE_UNLOCK_SHARP: IconData + FACEBOOK: IconData + FACEBOOK_OUTLINED: IconData + FACEBOOK_ROUNDED: IconData + FACEBOOK_SHARP: IconData + FACT_CHECK: IconData + FACT_CHECK_OUTLINED: IconData + FACT_CHECK_ROUNDED: IconData + FACT_CHECK_SHARP: IconData + FACTORY: IconData + FACTORY_OUTLINED: IconData + FACTORY_ROUNDED: IconData + FACTORY_SHARP: IconData + FAMILY_RESTROOM: IconData + FAMILY_RESTROOM_OUTLINED: IconData + FAMILY_RESTROOM_ROUNDED: IconData + FAMILY_RESTROOM_SHARP: IconData + FAST_FORWARD: IconData + FAST_FORWARD_OUTLINED: IconData + FAST_FORWARD_ROUNDED: IconData + FAST_FORWARD_SHARP: IconData + FAST_REWIND: IconData + FAST_REWIND_OUTLINED: IconData + FAST_REWIND_ROUNDED: IconData + FAST_REWIND_SHARP: IconData + FASTFOOD: IconData + FASTFOOD_OUTLINED: IconData + FASTFOOD_ROUNDED: IconData + FASTFOOD_SHARP: IconData + FAVORITE: IconData + FAVORITE_BORDER: IconData + FAVORITE_BORDER_OUTLINED: IconData + FAVORITE_BORDER_ROUNDED: IconData + FAVORITE_BORDER_SHARP: IconData + FAVORITE_OUTLINE: IconData + FAVORITE_OUTLINE_OUTLINED: IconData + FAVORITE_OUTLINE_ROUNDED: IconData + FAVORITE_OUTLINE_SHARP: IconData + FAVORITE_OUTLINED: IconData + FAVORITE_ROUNDED: IconData + FAVORITE_SHARP: IconData + FAX: IconData + FAX_OUTLINED: IconData + FAX_ROUNDED: IconData + FAX_SHARP: IconData + FEATURED_PLAY_LIST: IconData + FEATURED_PLAY_LIST_OUTLINED: IconData + FEATURED_PLAY_LIST_ROUNDED: IconData + FEATURED_PLAY_LIST_SHARP: IconData + FEATURED_VIDEO: IconData + FEATURED_VIDEO_OUTLINED: IconData + FEATURED_VIDEO_ROUNDED: IconData + FEATURED_VIDEO_SHARP: IconData + FEED: IconData + FEED_OUTLINED: IconData + FEED_ROUNDED: IconData + FEED_SHARP: IconData + FEEDBACK: IconData + FEEDBACK_OUTLINED: IconData + FEEDBACK_ROUNDED: IconData + FEEDBACK_SHARP: IconData + FEMALE: IconData + FEMALE_OUTLINED: IconData + FEMALE_ROUNDED: IconData + FEMALE_SHARP: IconData + FENCE: IconData + FENCE_OUTLINED: IconData + FENCE_ROUNDED: IconData + FENCE_SHARP: IconData + FESTIVAL: IconData + FESTIVAL_OUTLINED: IconData + FESTIVAL_ROUNDED: IconData + FESTIVAL_SHARP: IconData + FIBER_DVR: IconData + FIBER_DVR_OUTLINED: IconData + FIBER_DVR_ROUNDED: IconData + FIBER_DVR_SHARP: IconData + FIBER_MANUAL_RECORD: IconData + FIBER_MANUAL_RECORD_OUTLINED: IconData + FIBER_MANUAL_RECORD_ROUNDED: IconData + FIBER_MANUAL_RECORD_SHARP: IconData + FIBER_NEW: IconData + FIBER_NEW_OUTLINED: IconData + FIBER_NEW_ROUNDED: IconData + FIBER_NEW_SHARP: IconData + FIBER_PIN: IconData + FIBER_PIN_OUTLINED: IconData + FIBER_PIN_ROUNDED: IconData + FIBER_PIN_SHARP: IconData + FIBER_SMART_RECORD: IconData + FIBER_SMART_RECORD_OUTLINED: IconData + FIBER_SMART_RECORD_ROUNDED: IconData + FIBER_SMART_RECORD_SHARP: IconData + FIFTEEN_MP: IconData + FIFTEEN_MP_OUTLINED: IconData + FIFTEEN_MP_ROUNDED: IconData + FIFTEEN_MP_SHARP: IconData + FILE_COPY: IconData + FILE_COPY_OUTLINED: IconData + FILE_COPY_ROUNDED: IconData + FILE_COPY_SHARP: IconData + FILE_DOWNLOAD: IconData + FILE_DOWNLOAD_DONE: IconData + FILE_DOWNLOAD_DONE_OUTLINED: IconData + FILE_DOWNLOAD_DONE_ROUNDED: IconData + FILE_DOWNLOAD_DONE_SHARP: IconData + FILE_DOWNLOAD_OFF: IconData + FILE_DOWNLOAD_OFF_OUTLINED: IconData + FILE_DOWNLOAD_OFF_ROUNDED: IconData + FILE_DOWNLOAD_OFF_SHARP: IconData + FILE_DOWNLOAD_OUTLINED: IconData + FILE_DOWNLOAD_ROUNDED: IconData + FILE_DOWNLOAD_SHARP: IconData + FILE_OPEN: IconData + FILE_OPEN_OUTLINED: IconData + FILE_OPEN_ROUNDED: IconData + FILE_OPEN_SHARP: IconData + FILE_PRESENT: IconData + FILE_PRESENT_OUTLINED: IconData + FILE_PRESENT_ROUNDED: IconData + FILE_PRESENT_SHARP: IconData + FILE_UPLOAD: IconData + FILE_UPLOAD_OFF: IconData + FILE_UPLOAD_OUTLINED: IconData + FILE_UPLOAD_ROUNDED: IconData + FILE_UPLOAD_SHARP: IconData + FILTER: IconData + FILTER_1: IconData + FILTER_1_OUTLINED: IconData + FILTER_1_ROUNDED: IconData + FILTER_1_SHARP: IconData + FILTER_2: IconData + FILTER_2_OUTLINED: IconData + FILTER_2_ROUNDED: IconData + FILTER_2_SHARP: IconData + FILTER_3: IconData + FILTER_3_OUTLINED: IconData + FILTER_3_ROUNDED: IconData + FILTER_3_SHARP: IconData + FILTER_4: IconData + FILTER_4_OUTLINED: IconData + FILTER_4_ROUNDED: IconData + FILTER_4_SHARP: IconData + FILTER_5: IconData + FILTER_5_OUTLINED: IconData + FILTER_5_ROUNDED: IconData + FILTER_5_SHARP: IconData + FILTER_6: IconData + FILTER_6_OUTLINED: IconData + FILTER_6_ROUNDED: IconData + FILTER_6_SHARP: IconData + FILTER_7: IconData + FILTER_7_OUTLINED: IconData + FILTER_7_ROUNDED: IconData + FILTER_7_SHARP: IconData + FILTER_8: IconData + FILTER_8_OUTLINED: IconData + FILTER_8_ROUNDED: IconData + FILTER_8_SHARP: IconData + FILTER_9: IconData + FILTER_9_OUTLINED: IconData + FILTER_9_PLUS: IconData + FILTER_9_PLUS_OUTLINED: IconData + FILTER_9_PLUS_ROUNDED: IconData + FILTER_9_PLUS_SHARP: IconData + FILTER_9_ROUNDED: IconData + FILTER_9_SHARP: IconData + FILTER_ALT: IconData + FILTER_ALT_OFF: IconData + FILTER_ALT_OFF_OUTLINED: IconData + FILTER_ALT_OFF_ROUNDED: IconData + FILTER_ALT_OFF_SHARP: IconData + FILTER_ALT_OUTLINED: IconData + FILTER_ALT_ROUNDED: IconData + FILTER_ALT_SHARP: IconData + FILTER_B_AND_W: IconData + FILTER_B_AND_W_OUTLINED: IconData + FILTER_B_AND_W_ROUNDED: IconData + FILTER_B_AND_W_SHARP: IconData + FILTER_CENTER_FOCUS: IconData + FILTER_CENTER_FOCUS_OUTLINED: IconData + FILTER_CENTER_FOCUS_ROUNDED: IconData + FILTER_CENTER_FOCUS_SHARP: IconData + FILTER_DRAMA: IconData + FILTER_DRAMA_OUTLINED: IconData + FILTER_DRAMA_ROUNDED: IconData + FILTER_DRAMA_SHARP: IconData + FILTER_FRAMES: IconData + FILTER_FRAMES_OUTLINED: IconData + FILTER_FRAMES_ROUNDED: IconData + FILTER_FRAMES_SHARP: IconData + FILTER_HDR: IconData + FILTER_HDR_OUTLINED: IconData + FILTER_HDR_ROUNDED: IconData + FILTER_HDR_SHARP: IconData + FILTER_LIST: IconData + FILTER_LIST_ALT: IconData + FILTER_LIST_OFF: IconData + FILTER_LIST_OFF_OUTLINED: IconData + FILTER_LIST_OFF_ROUNDED: IconData + FILTER_LIST_OFF_SHARP: IconData + FILTER_LIST_OUTLINED: IconData + FILTER_LIST_ROUNDED: IconData + FILTER_LIST_SHARP: IconData + FILTER_NONE: IconData + FILTER_NONE_OUTLINED: IconData + FILTER_NONE_ROUNDED: IconData + FILTER_NONE_SHARP: IconData + FILTER_OUTLINED: IconData + FILTER_ROUNDED: IconData + FILTER_SHARP: IconData + FILTER_TILT_SHIFT: IconData + FILTER_TILT_SHIFT_OUTLINED: IconData + FILTER_TILT_SHIFT_ROUNDED: IconData + FILTER_TILT_SHIFT_SHARP: IconData + FILTER_VINTAGE: IconData + FILTER_VINTAGE_OUTLINED: IconData + FILTER_VINTAGE_ROUNDED: IconData + FILTER_VINTAGE_SHARP: IconData + FIND_IN_PAGE: IconData + FIND_IN_PAGE_OUTLINED: IconData + FIND_IN_PAGE_ROUNDED: IconData + FIND_IN_PAGE_SHARP: IconData + FIND_REPLACE: IconData + FIND_REPLACE_OUTLINED: IconData + FIND_REPLACE_ROUNDED: IconData + FIND_REPLACE_SHARP: IconData + FINGERPRINT: IconData + FINGERPRINT_OUTLINED: IconData + FINGERPRINT_ROUNDED: IconData + FINGERPRINT_SHARP: IconData + FIRE_EXTINGUISHER: IconData + FIRE_EXTINGUISHER_OUTLINED: IconData + FIRE_EXTINGUISHER_ROUNDED: IconData + FIRE_EXTINGUISHER_SHARP: IconData + FIRE_HYDRANT: IconData + FIRE_HYDRANT_ALT: IconData + FIRE_HYDRANT_ALT_OUTLINED: IconData + FIRE_HYDRANT_ALT_ROUNDED: IconData + FIRE_HYDRANT_ALT_SHARP: IconData + FIRE_TRUCK: IconData + FIRE_TRUCK_OUTLINED: IconData + FIRE_TRUCK_ROUNDED: IconData + FIRE_TRUCK_SHARP: IconData + FIREPLACE: IconData + FIREPLACE_OUTLINED: IconData + FIREPLACE_ROUNDED: IconData + FIREPLACE_SHARP: IconData + FIRST_PAGE: IconData + FIRST_PAGE_OUTLINED: IconData + FIRST_PAGE_ROUNDED: IconData + FIRST_PAGE_SHARP: IconData + FIT_SCREEN: IconData + FIT_SCREEN_OUTLINED: IconData + FIT_SCREEN_ROUNDED: IconData + FIT_SCREEN_SHARP: IconData + FITBIT: IconData + FITBIT_OUTLINED: IconData + FITBIT_ROUNDED: IconData + FITBIT_SHARP: IconData + FITNESS_CENTER: IconData + FITNESS_CENTER_OUTLINED: IconData + FITNESS_CENTER_ROUNDED: IconData + FITNESS_CENTER_SHARP: IconData + FIVE_G: IconData + FIVE_G_OUTLINED: IconData + FIVE_G_ROUNDED: IconData + FIVE_G_SHARP: IconData + FIVE_K: IconData + FIVE_K_OUTLINED: IconData + FIVE_K_PLUS: IconData + FIVE_K_PLUS_OUTLINED: IconData + FIVE_K_PLUS_ROUNDED: IconData + FIVE_K_PLUS_SHARP: IconData + FIVE_K_ROUNDED: IconData + FIVE_K_SHARP: IconData + FIVE_MP: IconData + FIVE_MP_OUTLINED: IconData + FIVE_MP_ROUNDED: IconData + FIVE_MP_SHARP: IconData + FLAG: IconData + FLAG_CIRCLE: IconData + FLAG_CIRCLE_OUTLINED: IconData + FLAG_CIRCLE_ROUNDED: IconData + FLAG_CIRCLE_SHARP: IconData + FLAG_OUTLINED: IconData + FLAG_ROUNDED: IconData + FLAG_SHARP: IconData + FLAKY: IconData + FLAKY_OUTLINED: IconData + FLAKY_ROUNDED: IconData + FLAKY_SHARP: IconData + FLARE: IconData + FLARE_OUTLINED: IconData + FLARE_ROUNDED: IconData + FLARE_SHARP: IconData + FLASH_AUTO: IconData + FLASH_AUTO_OUTLINED: IconData + FLASH_AUTO_ROUNDED: IconData + FLASH_AUTO_SHARP: IconData + FLASH_OFF: IconData + FLASH_OFF_OUTLINED: IconData + FLASH_OFF_ROUNDED: IconData + FLASH_OFF_SHARP: IconData + FLASH_ON: IconData + FLASH_ON_OUTLINED: IconData + FLASH_ON_ROUNDED: IconData + FLASH_ON_SHARP: IconData + FLASHLIGHT_OFF: IconData + FLASHLIGHT_OFF_OUTLINED: IconData + FLASHLIGHT_OFF_ROUNDED: IconData + FLASHLIGHT_OFF_SHARP: IconData + FLASHLIGHT_ON: IconData + FLASHLIGHT_ON_OUTLINED: IconData + FLASHLIGHT_ON_ROUNDED: IconData + FLASHLIGHT_ON_SHARP: IconData + FLATWARE: IconData + FLATWARE_OUTLINED: IconData + FLATWARE_ROUNDED: IconData + FLATWARE_SHARP: IconData + FLIGHT: IconData + FLIGHT_CLASS: IconData + FLIGHT_CLASS_OUTLINED: IconData + FLIGHT_CLASS_ROUNDED: IconData + FLIGHT_CLASS_SHARP: IconData + FLIGHT_LAND: IconData + FLIGHT_LAND_OUTLINED: IconData + FLIGHT_LAND_ROUNDED: IconData + FLIGHT_LAND_SHARP: IconData + FLIGHT_OUTLINED: IconData + FLIGHT_ROUNDED: IconData + FLIGHT_SHARP: IconData + FLIGHT_TAKEOFF: IconData + FLIGHT_TAKEOFF_OUTLINED: IconData + FLIGHT_TAKEOFF_ROUNDED: IconData + FLIGHT_TAKEOFF_SHARP: IconData + FLIP: IconData + FLIP_CAMERA_ANDROID: IconData + FLIP_CAMERA_ANDROID_OUTLINED: IconData + FLIP_CAMERA_ANDROID_ROUNDED: IconData + FLIP_CAMERA_ANDROID_SHARP: IconData + FLIP_CAMERA_IOS: IconData + FLIP_CAMERA_IOS_OUTLINED: IconData + FLIP_CAMERA_IOS_ROUNDED: IconData + FLIP_CAMERA_IOS_SHARP: IconData + FLIP_OUTLINED: IconData + FLIP_ROUNDED: IconData + FLIP_SHARP: IconData + FLIP_TO_BACK: IconData + FLIP_TO_BACK_OUTLINED: IconData + FLIP_TO_BACK_ROUNDED: IconData + FLIP_TO_BACK_SHARP: IconData + FLIP_TO_FRONT: IconData + FLIP_TO_FRONT_OUTLINED: IconData + FLIP_TO_FRONT_ROUNDED: IconData + FLIP_TO_FRONT_SHARP: IconData + FLOOD: IconData + FLOOD_OUTLINED: IconData + FLOOD_ROUNDED: IconData + FLOOD_SHARP: IconData + FLOURESCENT: IconData + FLOURESCENT_OUTLINED: IconData + FLOURESCENT_ROUNDED: IconData + FLOURESCENT_SHARP: IconData + FLUORESCENT: IconData + FLUORESCENT_OUTLINED: IconData + FLUORESCENT_ROUNDED: IconData + FLUORESCENT_SHARP: IconData + FLUTTER_DASH: IconData + FLUTTER_DASH_OUTLINED: IconData + FLUTTER_DASH_ROUNDED: IconData + FLUTTER_DASH_SHARP: IconData + FMD_BAD: IconData + FMD_BAD_OUTLINED: IconData + FMD_BAD_ROUNDED: IconData + FMD_BAD_SHARP: IconData + FMD_GOOD: IconData + FMD_GOOD_OUTLINED: IconData + FMD_GOOD_ROUNDED: IconData + FMD_GOOD_SHARP: IconData + FOGGY: IconData + FOLDER: IconData + FOLDER_COPY: IconData + FOLDER_COPY_OUTLINED: IconData + FOLDER_COPY_ROUNDED: IconData + FOLDER_COPY_SHARP: IconData + FOLDER_DELETE: IconData + FOLDER_DELETE_OUTLINED: IconData + FOLDER_DELETE_ROUNDED: IconData + FOLDER_DELETE_SHARP: IconData + FOLDER_OFF: IconData + FOLDER_OFF_OUTLINED: IconData + FOLDER_OFF_ROUNDED: IconData + FOLDER_OFF_SHARP: IconData + FOLDER_OPEN: IconData + FOLDER_OPEN_OUTLINED: IconData + FOLDER_OPEN_ROUNDED: IconData + FOLDER_OPEN_SHARP: IconData + FOLDER_OUTLINED: IconData + FOLDER_ROUNDED: IconData + FOLDER_SHARED: IconData + FOLDER_SHARED_OUTLINED: IconData + FOLDER_SHARED_ROUNDED: IconData + FOLDER_SHARED_SHARP: IconData + FOLDER_SHARP: IconData + FOLDER_SPECIAL: IconData + FOLDER_SPECIAL_OUTLINED: IconData + FOLDER_SPECIAL_ROUNDED: IconData + FOLDER_SPECIAL_SHARP: IconData + FOLDER_ZIP: IconData + FOLDER_ZIP_OUTLINED: IconData + FOLDER_ZIP_ROUNDED: IconData + FOLDER_ZIP_SHARP: IconData + FOLLOW_THE_SIGNS: IconData + FOLLOW_THE_SIGNS_OUTLINED: IconData + FOLLOW_THE_SIGNS_ROUNDED: IconData + FOLLOW_THE_SIGNS_SHARP: IconData + FONT_DOWNLOAD: IconData + FONT_DOWNLOAD_OFF: IconData + FONT_DOWNLOAD_OFF_OUTLINED: IconData + FONT_DOWNLOAD_OFF_ROUNDED: IconData + FONT_DOWNLOAD_OFF_SHARP: IconData + FONT_DOWNLOAD_OUTLINED: IconData + FONT_DOWNLOAD_ROUNDED: IconData + FONT_DOWNLOAD_SHARP: IconData + FOOD_BANK: IconData + FOOD_BANK_OUTLINED: IconData + FOOD_BANK_ROUNDED: IconData + FOOD_BANK_SHARP: IconData + FOREST: IconData + FOREST_OUTLINED: IconData + FOREST_ROUNDED: IconData + FOREST_SHARP: IconData + FORK_LEFT: IconData + FORK_LEFT_OUTLINED: IconData + FORK_LEFT_ROUNDED: IconData + FORK_LEFT_SHARP: IconData + FORK_RIGHT: IconData + FORK_RIGHT_OUTLINED: IconData + FORK_RIGHT_ROUNDED: IconData + FORK_RIGHT_SHARP: IconData + FORKLIFT: IconData + FORMAT_ALIGN_CENTER: IconData + FORMAT_ALIGN_CENTER_OUTLINED: IconData + FORMAT_ALIGN_CENTER_ROUNDED: IconData + FORMAT_ALIGN_CENTER_SHARP: IconData + FORMAT_ALIGN_JUSTIFY: IconData + FORMAT_ALIGN_JUSTIFY_OUTLINED: IconData + FORMAT_ALIGN_JUSTIFY_ROUNDED: IconData + FORMAT_ALIGN_JUSTIFY_SHARP: IconData + FORMAT_ALIGN_LEFT: IconData + FORMAT_ALIGN_LEFT_OUTLINED: IconData + FORMAT_ALIGN_LEFT_ROUNDED: IconData + FORMAT_ALIGN_LEFT_SHARP: IconData + FORMAT_ALIGN_RIGHT: IconData + FORMAT_ALIGN_RIGHT_OUTLINED: IconData + FORMAT_ALIGN_RIGHT_ROUNDED: IconData + FORMAT_ALIGN_RIGHT_SHARP: IconData + FORMAT_BOLD: IconData + FORMAT_BOLD_OUTLINED: IconData + FORMAT_BOLD_ROUNDED: IconData + FORMAT_BOLD_SHARP: IconData + FORMAT_CLEAR: IconData + FORMAT_CLEAR_OUTLINED: IconData + FORMAT_CLEAR_ROUNDED: IconData + FORMAT_CLEAR_SHARP: IconData + FORMAT_COLOR_FILL: IconData + FORMAT_COLOR_FILL_OUTLINED: IconData + FORMAT_COLOR_FILL_ROUNDED: IconData + FORMAT_COLOR_FILL_SHARP: IconData + FORMAT_COLOR_RESET: IconData + FORMAT_COLOR_RESET_OUTLINED: IconData + FORMAT_COLOR_RESET_ROUNDED: IconData + FORMAT_COLOR_RESET_SHARP: IconData + FORMAT_COLOR_TEXT: IconData + FORMAT_COLOR_TEXT_OUTLINED: IconData + FORMAT_COLOR_TEXT_ROUNDED: IconData + FORMAT_COLOR_TEXT_SHARP: IconData + FORMAT_INDENT_DECREASE: IconData + FORMAT_INDENT_DECREASE_OUTLINED: IconData + FORMAT_INDENT_DECREASE_ROUNDED: IconData + FORMAT_INDENT_DECREASE_SHARP: IconData + FORMAT_INDENT_INCREASE: IconData + FORMAT_INDENT_INCREASE_OUTLINED: IconData + FORMAT_INDENT_INCREASE_ROUNDED: IconData + FORMAT_INDENT_INCREASE_SHARP: IconData + FORMAT_ITALIC: IconData + FORMAT_ITALIC_OUTLINED: IconData + FORMAT_ITALIC_ROUNDED: IconData + FORMAT_ITALIC_SHARP: IconData + FORMAT_LINE_SPACING: IconData + FORMAT_LINE_SPACING_OUTLINED: IconData + FORMAT_LINE_SPACING_ROUNDED: IconData + FORMAT_LINE_SPACING_SHARP: IconData + FORMAT_LIST_BULLETED: IconData + FORMAT_LIST_BULLETED_ADD: IconData + FORMAT_LIST_BULLETED_OUTLINED: IconData + FORMAT_LIST_BULLETED_ROUNDED: IconData + FORMAT_LIST_BULLETED_SHARP: IconData + FORMAT_LIST_NUMBERED: IconData + FORMAT_LIST_NUMBERED_OUTLINED: IconData + FORMAT_LIST_NUMBERED_ROUNDED: IconData + FORMAT_LIST_NUMBERED_RTL: IconData + FORMAT_LIST_NUMBERED_RTL_OUTLINED: IconData + FORMAT_LIST_NUMBERED_RTL_ROUNDED: IconData + FORMAT_LIST_NUMBERED_RTL_SHARP: IconData + FORMAT_LIST_NUMBERED_SHARP: IconData + FORMAT_OVERLINE: IconData + FORMAT_OVERLINE_OUTLINED: IconData + FORMAT_OVERLINE_ROUNDED: IconData + FORMAT_OVERLINE_SHARP: IconData + FORMAT_PAINT: IconData + FORMAT_PAINT_OUTLINED: IconData + FORMAT_PAINT_ROUNDED: IconData + FORMAT_PAINT_SHARP: IconData + FORMAT_QUOTE: IconData + FORMAT_QUOTE_OUTLINED: IconData + FORMAT_QUOTE_ROUNDED: IconData + FORMAT_QUOTE_SHARP: IconData + FORMAT_SHAPES: IconData + FORMAT_SHAPES_OUTLINED: IconData + FORMAT_SHAPES_ROUNDED: IconData + FORMAT_SHAPES_SHARP: IconData + FORMAT_SIZE: IconData + FORMAT_SIZE_OUTLINED: IconData + FORMAT_SIZE_ROUNDED: IconData + FORMAT_SIZE_SHARP: IconData + FORMAT_STRIKETHROUGH: IconData + FORMAT_STRIKETHROUGH_OUTLINED: IconData + FORMAT_STRIKETHROUGH_ROUNDED: IconData + FORMAT_STRIKETHROUGH_SHARP: IconData + FORMAT_TEXTDIRECTION_L_TO_R: IconData + FORMAT_TEXTDIRECTION_L_TO_R_OUTLINED: IconData + FORMAT_TEXTDIRECTION_L_TO_R_ROUNDED: IconData + FORMAT_TEXTDIRECTION_L_TO_R_SHARP: IconData + FORMAT_TEXTDIRECTION_R_TO_L: IconData + FORMAT_TEXTDIRECTION_R_TO_L_OUTLINED: IconData + FORMAT_TEXTDIRECTION_R_TO_L_ROUNDED: IconData + FORMAT_TEXTDIRECTION_R_TO_L_SHARP: IconData + FORMAT_UNDERLINE: IconData + FORMAT_UNDERLINE_OUTLINED: IconData + FORMAT_UNDERLINE_ROUNDED: IconData + FORMAT_UNDERLINE_SHARP: IconData + FORMAT_UNDERLINED: IconData + FORMAT_UNDERLINED_OUTLINED: IconData + FORMAT_UNDERLINED_ROUNDED: IconData + FORMAT_UNDERLINED_SHARP: IconData + FORT: IconData + FORT_OUTLINED: IconData + FORT_ROUNDED: IconData + FORT_SHARP: IconData + FORUM: IconData + FORUM_OUTLINED: IconData + FORUM_ROUNDED: IconData + FORUM_SHARP: IconData + FORWARD: IconData + FORWARD_10: IconData + FORWARD_10_OUTLINED: IconData + FORWARD_10_ROUNDED: IconData + FORWARD_10_SHARP: IconData + FORWARD_30: IconData + FORWARD_30_OUTLINED: IconData + FORWARD_30_ROUNDED: IconData + FORWARD_30_SHARP: IconData + FORWARD_5: IconData + FORWARD_5_OUTLINED: IconData + FORWARD_5_ROUNDED: IconData + FORWARD_5_SHARP: IconData + FORWARD_OUTLINED: IconData + FORWARD_ROUNDED: IconData + FORWARD_SHARP: IconData + FORWARD_TO_INBOX: IconData + FORWARD_TO_INBOX_OUTLINED: IconData + FORWARD_TO_INBOX_ROUNDED: IconData + FORWARD_TO_INBOX_SHARP: IconData + FOUNDATION: IconData + FOUNDATION_OUTLINED: IconData + FOUNDATION_ROUNDED: IconData + FOUNDATION_SHARP: IconData + FOUR_G_MOBILEDATA: IconData + FOUR_G_MOBILEDATA_OUTLINED: IconData + FOUR_G_MOBILEDATA_ROUNDED: IconData + FOUR_G_MOBILEDATA_SHARP: IconData + FOUR_G_PLUS_MOBILEDATA: IconData + FOUR_G_PLUS_MOBILEDATA_OUTLINED: IconData + FOUR_G_PLUS_MOBILEDATA_ROUNDED: IconData + FOUR_G_PLUS_MOBILEDATA_SHARP: IconData + FOUR_K: IconData + FOUR_K_OUTLINED: IconData + FOUR_K_PLUS: IconData + FOUR_K_PLUS_OUTLINED: IconData + FOUR_K_PLUS_ROUNDED: IconData + FOUR_K_PLUS_SHARP: IconData + FOUR_K_ROUNDED: IconData + FOUR_K_SHARP: IconData + FOUR_MP: IconData + FOUR_MP_OUTLINED: IconData + FOUR_MP_ROUNDED: IconData + FOUR_MP_SHARP: IconData + FOURTEEN_MP: IconData + FOURTEEN_MP_OUTLINED: IconData + FOURTEEN_MP_ROUNDED: IconData + FOURTEEN_MP_SHARP: IconData + FREE_BREAKFAST: IconData + FREE_BREAKFAST_OUTLINED: IconData + FREE_BREAKFAST_ROUNDED: IconData + FREE_BREAKFAST_SHARP: IconData + FREE_CANCELLATION: IconData + FREE_CANCELLATION_OUTLINED: IconData + FREE_CANCELLATION_ROUNDED: IconData + FREE_CANCELLATION_SHARP: IconData + FRONT_HAND: IconData + FRONT_HAND_OUTLINED: IconData + FRONT_HAND_ROUNDED: IconData + FRONT_HAND_SHARP: IconData + FRONT_LOADER: IconData + FULLSCREEN: IconData + FULLSCREEN_EXIT: IconData + FULLSCREEN_EXIT_OUTLINED: IconData + FULLSCREEN_EXIT_ROUNDED: IconData + FULLSCREEN_EXIT_SHARP: IconData + FULLSCREEN_OUTLINED: IconData + FULLSCREEN_ROUNDED: IconData + FULLSCREEN_SHARP: IconData + FUNCTIONS: IconData + FUNCTIONS_OUTLINED: IconData + FUNCTIONS_ROUNDED: IconData + FUNCTIONS_SHARP: IconData + G_MOBILEDATA: IconData + G_MOBILEDATA_OUTLINED: IconData + G_MOBILEDATA_ROUNDED: IconData + G_MOBILEDATA_SHARP: IconData + G_TRANSLATE: IconData + G_TRANSLATE_OUTLINED: IconData + G_TRANSLATE_ROUNDED: IconData + G_TRANSLATE_SHARP: IconData + GAMEPAD: IconData + GAMEPAD_OUTLINED: IconData + GAMEPAD_ROUNDED: IconData + GAMEPAD_SHARP: IconData + GAMES: IconData + GAMES_OUTLINED: IconData + GAMES_ROUNDED: IconData + GAMES_SHARP: IconData + GARAGE: IconData + GARAGE_OUTLINED: IconData + GARAGE_ROUNDED: IconData + GARAGE_SHARP: IconData + GAS_METER: IconData + GAS_METER_OUTLINED: IconData + GAS_METER_ROUNDED: IconData + GAS_METER_SHARP: IconData + GAVEL: IconData + GAVEL_OUTLINED: IconData + GAVEL_ROUNDED: IconData + GAVEL_SHARP: IconData + GENERATING_TOKENS: IconData + GENERATING_TOKENS_OUTLINED: IconData + GENERATING_TOKENS_ROUNDED: IconData + GENERATING_TOKENS_SHARP: IconData + GESTURE: IconData + GESTURE_OUTLINED: IconData + GESTURE_ROUNDED: IconData + GESTURE_SHARP: IconData + GET_APP: IconData + GET_APP_OUTLINED: IconData + GET_APP_ROUNDED: IconData + GET_APP_SHARP: IconData + GIF: IconData + GIF_BOX: IconData + GIF_BOX_OUTLINED: IconData + GIF_BOX_ROUNDED: IconData + GIF_BOX_SHARP: IconData + GIF_OUTLINED: IconData + GIF_ROUNDED: IconData + GIF_SHARP: IconData + GIRL: IconData + GIRL_OUTLINED: IconData + GIRL_ROUNDED: IconData + GIRL_SHARP: IconData + GITE: IconData + GITE_OUTLINED: IconData + GITE_ROUNDED: IconData + GITE_SHARP: IconData + GOLF_COURSE: IconData + GOLF_COURSE_OUTLINED: IconData + GOLF_COURSE_ROUNDED: IconData + GOLF_COURSE_SHARP: IconData + GPP_BAD: IconData + GPP_BAD_OUTLINED: IconData + GPP_BAD_ROUNDED: IconData + GPP_BAD_SHARP: IconData + GPP_GOOD: IconData + GPP_GOOD_OUTLINED: IconData + GPP_GOOD_ROUNDED: IconData + GPP_GOOD_SHARP: IconData + GPP_MAYBE: IconData + GPP_MAYBE_OUTLINED: IconData + GPP_MAYBE_ROUNDED: IconData + GPP_MAYBE_SHARP: IconData + GPS_FIXED: IconData + GPS_FIXED_OUTLINED: IconData + GPS_FIXED_ROUNDED: IconData + GPS_FIXED_SHARP: IconData + GPS_NOT_FIXED: IconData + GPS_NOT_FIXED_OUTLINED: IconData + GPS_NOT_FIXED_ROUNDED: IconData + GPS_NOT_FIXED_SHARP: IconData + GPS_OFF: IconData + GPS_OFF_OUTLINED: IconData + GPS_OFF_ROUNDED: IconData + GPS_OFF_SHARP: IconData + GRADE: IconData + GRADE_OUTLINED: IconData + GRADE_ROUNDED: IconData + GRADE_SHARP: IconData + GRADIENT: IconData + GRADIENT_OUTLINED: IconData + GRADIENT_ROUNDED: IconData + GRADIENT_SHARP: IconData + GRADING: IconData + GRADING_OUTLINED: IconData + GRADING_ROUNDED: IconData + GRADING_SHARP: IconData + GRAIN: IconData + GRAIN_OUTLINED: IconData + GRAIN_ROUNDED: IconData + GRAIN_SHARP: IconData + GRAPHIC_EQ: IconData + GRAPHIC_EQ_OUTLINED: IconData + GRAPHIC_EQ_ROUNDED: IconData + GRAPHIC_EQ_SHARP: IconData + GRASS: IconData + GRASS_OUTLINED: IconData + GRASS_ROUNDED: IconData + GRASS_SHARP: IconData + GRID_3X3: IconData + GRID_3X3_OUTLINED: IconData + GRID_3X3_ROUNDED: IconData + GRID_3X3_SHARP: IconData + GRID_4X4: IconData + GRID_4X4_OUTLINED: IconData + GRID_4X4_ROUNDED: IconData + GRID_4X4_SHARP: IconData + GRID_GOLDENRATIO: IconData + GRID_GOLDENRATIO_OUTLINED: IconData + GRID_GOLDENRATIO_ROUNDED: IconData + GRID_GOLDENRATIO_SHARP: IconData + GRID_OFF: IconData + GRID_OFF_OUTLINED: IconData + GRID_OFF_ROUNDED: IconData + GRID_OFF_SHARP: IconData + GRID_ON: IconData + GRID_ON_OUTLINED: IconData + GRID_ON_ROUNDED: IconData + GRID_ON_SHARP: IconData + GRID_VIEW: IconData + GRID_VIEW_OUTLINED: IconData + GRID_VIEW_ROUNDED: IconData + GRID_VIEW_SHARP: IconData + GROUP: IconData + GROUP_ADD: IconData + GROUP_ADD_OUTLINED: IconData + GROUP_ADD_ROUNDED: IconData + GROUP_ADD_SHARP: IconData + GROUP_OFF: IconData + GROUP_OFF_OUTLINED: IconData + GROUP_OFF_ROUNDED: IconData + GROUP_OFF_SHARP: IconData + GROUP_OUTLINED: IconData + GROUP_REMOVE: IconData + GROUP_REMOVE_OUTLINED: IconData + GROUP_REMOVE_ROUNDED: IconData + GROUP_REMOVE_SHARP: IconData + GROUP_ROUNDED: IconData + GROUP_SHARP: IconData + GROUP_WORK: IconData + GROUP_WORK_OUTLINED: IconData + GROUP_WORK_ROUNDED: IconData + GROUP_WORK_SHARP: IconData + GROUPS: IconData + GROUPS_2: IconData + GROUPS_2_OUTLINED: IconData + GROUPS_2_ROUNDED: IconData + GROUPS_2_SHARP: IconData + GROUPS_3: IconData + GROUPS_3_OUTLINED: IconData + GROUPS_3_ROUNDED: IconData + GROUPS_3_SHARP: IconData + GROUPS_OUTLINED: IconData + GROUPS_ROUNDED: IconData + GROUPS_SHARP: IconData + H_MOBILEDATA: IconData + H_MOBILEDATA_OUTLINED: IconData + H_MOBILEDATA_ROUNDED: IconData + H_MOBILEDATA_SHARP: IconData + H_PLUS_MOBILEDATA: IconData + H_PLUS_MOBILEDATA_OUTLINED: IconData + H_PLUS_MOBILEDATA_ROUNDED: IconData + H_PLUS_MOBILEDATA_SHARP: IconData + HAIL: IconData + HAIL_OUTLINED: IconData + HAIL_ROUNDED: IconData + HAIL_SHARP: IconData + HANDSHAKE: IconData + HANDSHAKE_OUTLINED: IconData + HANDSHAKE_ROUNDED: IconData + HANDSHAKE_SHARP: IconData + HANDYMAN: IconData + HANDYMAN_OUTLINED: IconData + HANDYMAN_ROUNDED: IconData + HANDYMAN_SHARP: IconData + HARDWARE: IconData + HARDWARE_OUTLINED: IconData + HARDWARE_ROUNDED: IconData + HARDWARE_SHARP: IconData + HD: IconData + HD_OUTLINED: IconData + HD_ROUNDED: IconData + HD_SHARP: IconData + HDR_AUTO: IconData + HDR_AUTO_OUTLINED: IconData + HDR_AUTO_ROUNDED: IconData + HDR_AUTO_SELECT: IconData + HDR_AUTO_SELECT_OUTLINED: IconData + HDR_AUTO_SELECT_ROUNDED: IconData + HDR_AUTO_SELECT_SHARP: IconData + HDR_AUTO_SHARP: IconData + HDR_ENHANCED_SELECT: IconData + HDR_ENHANCED_SELECT_OUTLINED: IconData + HDR_ENHANCED_SELECT_ROUNDED: IconData + HDR_ENHANCED_SELECT_SHARP: IconData + HDR_OFF: IconData + HDR_OFF_OUTLINED: IconData + HDR_OFF_ROUNDED: IconData + HDR_OFF_SELECT: IconData + HDR_OFF_SELECT_OUTLINED: IconData + HDR_OFF_SELECT_ROUNDED: IconData + HDR_OFF_SELECT_SHARP: IconData + HDR_OFF_SHARP: IconData + HDR_ON: IconData + HDR_ON_OUTLINED: IconData + HDR_ON_ROUNDED: IconData + HDR_ON_SELECT: IconData + HDR_ON_SELECT_OUTLINED: IconData + HDR_ON_SELECT_ROUNDED: IconData + HDR_ON_SELECT_SHARP: IconData + HDR_ON_SHARP: IconData + HDR_PLUS: IconData + HDR_PLUS_OUTLINED: IconData + HDR_PLUS_ROUNDED: IconData + HDR_PLUS_SHARP: IconData + HDR_STRONG: IconData + HDR_STRONG_OUTLINED: IconData + HDR_STRONG_ROUNDED: IconData + HDR_STRONG_SHARP: IconData + HDR_WEAK: IconData + HDR_WEAK_OUTLINED: IconData + HDR_WEAK_ROUNDED: IconData + HDR_WEAK_SHARP: IconData + HEADPHONES: IconData + HEADPHONES_BATTERY: IconData + HEADPHONES_BATTERY_OUTLINED: IconData + HEADPHONES_BATTERY_ROUNDED: IconData + HEADPHONES_BATTERY_SHARP: IconData + HEADPHONES_OUTLINED: IconData + HEADPHONES_ROUNDED: IconData + HEADPHONES_SHARP: IconData + HEADSET: IconData + HEADSET_MIC: IconData + HEADSET_MIC_OUTLINED: IconData + HEADSET_MIC_ROUNDED: IconData + HEADSET_MIC_SHARP: IconData + HEADSET_OFF: IconData + HEADSET_OFF_OUTLINED: IconData + HEADSET_OFF_ROUNDED: IconData + HEADSET_OFF_SHARP: IconData + HEADSET_OUTLINED: IconData + HEADSET_ROUNDED: IconData + HEADSET_SHARP: IconData + HEALING: IconData + HEALING_OUTLINED: IconData + HEALING_ROUNDED: IconData + HEALING_SHARP: IconData + HEALTH_AND_SAFETY: IconData + HEALTH_AND_SAFETY_OUTLINED: IconData + HEALTH_AND_SAFETY_ROUNDED: IconData + HEALTH_AND_SAFETY_SHARP: IconData + HEARING: IconData + HEARING_DISABLED: IconData + HEARING_DISABLED_OUTLINED: IconData + HEARING_DISABLED_ROUNDED: IconData + HEARING_DISABLED_SHARP: IconData + HEARING_OUTLINED: IconData + HEARING_ROUNDED: IconData + HEARING_SHARP: IconData + HEART_BROKEN: IconData + HEART_BROKEN_OUTLINED: IconData + HEART_BROKEN_ROUNDED: IconData + HEART_BROKEN_SHARP: IconData + HEAT_PUMP: IconData + HEAT_PUMP_OUTLINED: IconData + HEAT_PUMP_ROUNDED: IconData + HEAT_PUMP_SHARP: IconData + HEIGHT: IconData + HEIGHT_OUTLINED: IconData + HEIGHT_ROUNDED: IconData + HEIGHT_SHARP: IconData + HELP: IconData + HELP_CENTER: IconData + HELP_CENTER_OUTLINED: IconData + HELP_CENTER_ROUNDED: IconData + HELP_CENTER_SHARP: IconData + HELP_OUTLINE: IconData + HELP_OUTLINE_OUTLINED: IconData + HELP_OUTLINE_ROUNDED: IconData + HELP_OUTLINE_SHARP: IconData + HELP_OUTLINED: IconData + HELP_ROUNDED: IconData + HELP_SHARP: IconData + HEVC: IconData + HEVC_OUTLINED: IconData + HEVC_ROUNDED: IconData + HEVC_SHARP: IconData + HEXAGON: IconData + HEXAGON_OUTLINED: IconData + HEXAGON_ROUNDED: IconData + HEXAGON_SHARP: IconData + HIDE_IMAGE: IconData + HIDE_IMAGE_OUTLINED: IconData + HIDE_IMAGE_ROUNDED: IconData + HIDE_IMAGE_SHARP: IconData + HIDE_SOURCE: IconData + HIDE_SOURCE_OUTLINED: IconData + HIDE_SOURCE_ROUNDED: IconData + HIDE_SOURCE_SHARP: IconData + HIGH_QUALITY: IconData + HIGH_QUALITY_OUTLINED: IconData + HIGH_QUALITY_ROUNDED: IconData + HIGH_QUALITY_SHARP: IconData + HIGHLIGHT: IconData + HIGHLIGHT_ALT: IconData + HIGHLIGHT_ALT_OUTLINED: IconData + HIGHLIGHT_ALT_ROUNDED: IconData + HIGHLIGHT_ALT_SHARP: IconData + HIGHLIGHT_OFF: IconData + HIGHLIGHT_OFF_OUTLINED: IconData + HIGHLIGHT_OFF_ROUNDED: IconData + HIGHLIGHT_OFF_SHARP: IconData + HIGHLIGHT_OUTLINED: IconData + HIGHLIGHT_REMOVE: IconData + HIGHLIGHT_REMOVE_OUTLINED: IconData + HIGHLIGHT_REMOVE_ROUNDED: IconData + HIGHLIGHT_REMOVE_SHARP: IconData + HIGHLIGHT_ROUNDED: IconData + HIGHLIGHT_SHARP: IconData + HIKING: IconData + HIKING_OUTLINED: IconData + HIKING_ROUNDED: IconData + HIKING_SHARP: IconData + HISTORY: IconData + HISTORY_EDU: IconData + HISTORY_EDU_OUTLINED: IconData + HISTORY_EDU_ROUNDED: IconData + HISTORY_EDU_SHARP: IconData + HISTORY_OUTLINED: IconData + HISTORY_ROUNDED: IconData + HISTORY_SHARP: IconData + HISTORY_TOGGLE_OFF: IconData + HISTORY_TOGGLE_OFF_OUTLINED: IconData + HISTORY_TOGGLE_OFF_ROUNDED: IconData + HISTORY_TOGGLE_OFF_SHARP: IconData + HIVE: IconData + HIVE_OUTLINED: IconData + HIVE_ROUNDED: IconData + HIVE_SHARP: IconData + HLS: IconData + HLS_OFF: IconData + HLS_OFF_OUTLINED: IconData + HLS_OFF_ROUNDED: IconData + HLS_OFF_SHARP: IconData + HLS_OUTLINED: IconData + HLS_ROUNDED: IconData + HLS_SHARP: IconData + HOLIDAY_VILLAGE: IconData + HOLIDAY_VILLAGE_OUTLINED: IconData + HOLIDAY_VILLAGE_ROUNDED: IconData + HOLIDAY_VILLAGE_SHARP: IconData + HOME: IconData + HOME_FILLED: IconData + HOME_MAX: IconData + HOME_MAX_OUTLINED: IconData + HOME_MAX_ROUNDED: IconData + HOME_MAX_SHARP: IconData + HOME_MINI: IconData + HOME_MINI_OUTLINED: IconData + HOME_MINI_ROUNDED: IconData + HOME_MINI_SHARP: IconData + HOME_OUTLINED: IconData + HOME_REPAIR_SERVICE: IconData + HOME_REPAIR_SERVICE_OUTLINED: IconData + HOME_REPAIR_SERVICE_ROUNDED: IconData + HOME_REPAIR_SERVICE_SHARP: IconData + HOME_ROUNDED: IconData + HOME_SHARP: IconData + HOME_WORK: IconData + HOME_WORK_OUTLINED: IconData + HOME_WORK_ROUNDED: IconData + HOME_WORK_SHARP: IconData + HORIZONTAL_DISTRIBUTE: IconData + HORIZONTAL_DISTRIBUTE_OUTLINED: IconData + HORIZONTAL_DISTRIBUTE_ROUNDED: IconData + HORIZONTAL_DISTRIBUTE_SHARP: IconData + HORIZONTAL_RULE: IconData + HORIZONTAL_RULE_OUTLINED: IconData + HORIZONTAL_RULE_ROUNDED: IconData + HORIZONTAL_RULE_SHARP: IconData + HORIZONTAL_SPLIT: IconData + HORIZONTAL_SPLIT_OUTLINED: IconData + HORIZONTAL_SPLIT_ROUNDED: IconData + HORIZONTAL_SPLIT_SHARP: IconData + HOT_TUB: IconData + HOT_TUB_OUTLINED: IconData + HOT_TUB_ROUNDED: IconData + HOT_TUB_SHARP: IconData + HOTEL: IconData + HOTEL_CLASS: IconData + HOTEL_CLASS_OUTLINED: IconData + HOTEL_CLASS_ROUNDED: IconData + HOTEL_CLASS_SHARP: IconData + HOTEL_OUTLINED: IconData + HOTEL_ROUNDED: IconData + HOTEL_SHARP: IconData + HOURGLASS_BOTTOM: IconData + HOURGLASS_BOTTOM_OUTLINED: IconData + HOURGLASS_BOTTOM_ROUNDED: IconData + HOURGLASS_BOTTOM_SHARP: IconData + HOURGLASS_DISABLED: IconData + HOURGLASS_DISABLED_OUTLINED: IconData + HOURGLASS_DISABLED_ROUNDED: IconData + HOURGLASS_DISABLED_SHARP: IconData + HOURGLASS_EMPTY: IconData + HOURGLASS_EMPTY_OUTLINED: IconData + HOURGLASS_EMPTY_ROUNDED: IconData + HOURGLASS_EMPTY_SHARP: IconData + HOURGLASS_FULL: IconData + HOURGLASS_FULL_OUTLINED: IconData + HOURGLASS_FULL_ROUNDED: IconData + HOURGLASS_FULL_SHARP: IconData + HOURGLASS_TOP: IconData + HOURGLASS_TOP_OUTLINED: IconData + HOURGLASS_TOP_ROUNDED: IconData + HOURGLASS_TOP_SHARP: IconData + HOUSE: IconData + HOUSE_OUTLINED: IconData + HOUSE_ROUNDED: IconData + HOUSE_SHARP: IconData + HOUSE_SIDING: IconData + HOUSE_SIDING_OUTLINED: IconData + HOUSE_SIDING_ROUNDED: IconData + HOUSE_SIDING_SHARP: IconData + HOUSEBOAT: IconData + HOUSEBOAT_OUTLINED: IconData + HOUSEBOAT_ROUNDED: IconData + HOUSEBOAT_SHARP: IconData + HOW_TO_REG: IconData + HOW_TO_REG_OUTLINED: IconData + HOW_TO_REG_ROUNDED: IconData + HOW_TO_REG_SHARP: IconData + HOW_TO_VOTE: IconData + HOW_TO_VOTE_OUTLINED: IconData + HOW_TO_VOTE_ROUNDED: IconData + HOW_TO_VOTE_SHARP: IconData + HTML: IconData + HTML_OUTLINED: IconData + HTML_ROUNDED: IconData + HTML_SHARP: IconData + HTTP: IconData + HTTP_OUTLINED: IconData + HTTP_ROUNDED: IconData + HTTP_SHARP: IconData + HTTPS: IconData + HTTPS_OUTLINED: IconData + HTTPS_ROUNDED: IconData + HTTPS_SHARP: IconData + HUB: IconData + HUB_OUTLINED: IconData + HUB_ROUNDED: IconData + HUB_SHARP: IconData + HVAC: IconData + HVAC_OUTLINED: IconData + HVAC_ROUNDED: IconData + HVAC_SHARP: IconData + ICE_SKATING: IconData + ICE_SKATING_OUTLINED: IconData + ICE_SKATING_ROUNDED: IconData + ICE_SKATING_SHARP: IconData + ICECREAM: IconData + ICECREAM_OUTLINED: IconData + ICECREAM_ROUNDED: IconData + ICECREAM_SHARP: IconData + IMAGE: IconData + IMAGE_ASPECT_RATIO: IconData + IMAGE_ASPECT_RATIO_OUTLINED: IconData + IMAGE_ASPECT_RATIO_ROUNDED: IconData + IMAGE_ASPECT_RATIO_SHARP: IconData + IMAGE_NOT_SUPPORTED: IconData + IMAGE_NOT_SUPPORTED_OUTLINED: IconData + IMAGE_NOT_SUPPORTED_ROUNDED: IconData + IMAGE_NOT_SUPPORTED_SHARP: IconData + IMAGE_OUTLINED: IconData + IMAGE_ROUNDED: IconData + IMAGE_SEARCH: IconData + IMAGE_SEARCH_OUTLINED: IconData + IMAGE_SEARCH_ROUNDED: IconData + IMAGE_SEARCH_SHARP: IconData + IMAGE_SHARP: IconData + IMAGESEARCH_ROLLER: IconData + IMAGESEARCH_ROLLER_OUTLINED: IconData + IMAGESEARCH_ROLLER_ROUNDED: IconData + IMAGESEARCH_ROLLER_SHARP: IconData + IMPORT_CONTACTS: IconData + IMPORT_CONTACTS_OUTLINED: IconData + IMPORT_CONTACTS_ROUNDED: IconData + IMPORT_CONTACTS_SHARP: IconData + IMPORT_EXPORT: IconData + IMPORT_EXPORT_OUTLINED: IconData + IMPORT_EXPORT_ROUNDED: IconData + IMPORT_EXPORT_SHARP: IconData + IMPORTANT_DEVICES: IconData + IMPORTANT_DEVICES_OUTLINED: IconData + IMPORTANT_DEVICES_ROUNDED: IconData + IMPORTANT_DEVICES_SHARP: IconData + INBOX: IconData + INBOX_OUTLINED: IconData + INBOX_ROUNDED: IconData + INBOX_SHARP: IconData + INCOMPLETE_CIRCLE: IconData + INCOMPLETE_CIRCLE_OUTLINED: IconData + INCOMPLETE_CIRCLE_ROUNDED: IconData + INCOMPLETE_CIRCLE_SHARP: IconData + INDETERMINATE_CHECK_BOX: IconData + INDETERMINATE_CHECK_BOX_OUTLINED: IconData + INDETERMINATE_CHECK_BOX_ROUNDED: IconData + INDETERMINATE_CHECK_BOX_SHARP: IconData + INFO: IconData + INFO_OUTLINE: IconData + INFO_OUTLINE_ROUNDED: IconData + INFO_OUTLINE_SHARP: IconData + INFO_OUTLINED: IconData + INFO_ROUNDED: IconData + INFO_SHARP: IconData + INPUT: IconData + INPUT_OUTLINED: IconData + INPUT_ROUNDED: IconData + INPUT_SHARP: IconData + INSERT_CHART: IconData + INSERT_CHART_OUTLINED: IconData + INSERT_CHART_OUTLINED_OUTLINED: IconData + INSERT_CHART_OUTLINED_ROUNDED: IconData + INSERT_CHART_OUTLINED_SHARP: IconData + INSERT_CHART_ROUNDED: IconData + INSERT_CHART_SHARP: IconData + INSERT_COMMENT: IconData + INSERT_COMMENT_OUTLINED: IconData + INSERT_COMMENT_ROUNDED: IconData + INSERT_COMMENT_SHARP: IconData + INSERT_DRIVE_FILE: IconData + INSERT_DRIVE_FILE_OUTLINED: IconData + INSERT_DRIVE_FILE_ROUNDED: IconData + INSERT_DRIVE_FILE_SHARP: IconData + INSERT_EMOTICON: IconData + INSERT_EMOTICON_OUTLINED: IconData + INSERT_EMOTICON_ROUNDED: IconData + INSERT_EMOTICON_SHARP: IconData + INSERT_INVITATION: IconData + INSERT_INVITATION_OUTLINED: IconData + INSERT_INVITATION_ROUNDED: IconData + INSERT_INVITATION_SHARP: IconData + INSERT_LINK: IconData + INSERT_LINK_OUTLINED: IconData + INSERT_LINK_ROUNDED: IconData + INSERT_LINK_SHARP: IconData + INSERT_PAGE_BREAK: IconData + INSERT_PAGE_BREAK_OUTLINED: IconData + INSERT_PAGE_BREAK_ROUNDED: IconData + INSERT_PAGE_BREAK_SHARP: IconData + INSERT_PHOTO: IconData + INSERT_PHOTO_OUTLINED: IconData + INSERT_PHOTO_ROUNDED: IconData + INSERT_PHOTO_SHARP: IconData + INSIGHTS: IconData + INSIGHTS_OUTLINED: IconData + INSIGHTS_ROUNDED: IconData + INSIGHTS_SHARP: IconData + INSTALL_DESKTOP: IconData + INSTALL_DESKTOP_OUTLINED: IconData + INSTALL_DESKTOP_ROUNDED: IconData + INSTALL_DESKTOP_SHARP: IconData + INSTALL_MOBILE: IconData + INSTALL_MOBILE_OUTLINED: IconData + INSTALL_MOBILE_ROUNDED: IconData + INSTALL_MOBILE_SHARP: IconData + INTEGRATION_INSTRUCTIONS: IconData + INTEGRATION_INSTRUCTIONS_OUTLINED: IconData + INTEGRATION_INSTRUCTIONS_ROUNDED: IconData + INTEGRATION_INSTRUCTIONS_SHARP: IconData + INTERESTS: IconData + INTERESTS_OUTLINED: IconData + INTERESTS_ROUNDED: IconData + INTERESTS_SHARP: IconData + INTERPRETER_MODE: IconData + INTERPRETER_MODE_OUTLINED: IconData + INTERPRETER_MODE_ROUNDED: IconData + INTERPRETER_MODE_SHARP: IconData + INVENTORY: IconData + INVENTORY_2: IconData + INVENTORY_2_OUTLINED: IconData + INVENTORY_2_ROUNDED: IconData + INVENTORY_2_SHARP: IconData + INVENTORY_OUTLINED: IconData + INVENTORY_ROUNDED: IconData + INVENTORY_SHARP: IconData + INVERT_COLORS: IconData + INVERT_COLORS_OFF: IconData + INVERT_COLORS_OFF_OUTLINED: IconData + INVERT_COLORS_OFF_ROUNDED: IconData + INVERT_COLORS_OFF_SHARP: IconData + INVERT_COLORS_ON: IconData + INVERT_COLORS_ON_OUTLINED: IconData + INVERT_COLORS_ON_ROUNDED: IconData + INVERT_COLORS_ON_SHARP: IconData + INVERT_COLORS_OUTLINED: IconData + INVERT_COLORS_ROUNDED: IconData + INVERT_COLORS_SHARP: IconData + IOS_SHARE: IconData + IOS_SHARE_OUTLINED: IconData + IOS_SHARE_ROUNDED: IconData + IOS_SHARE_SHARP: IconData + IRON: IconData + IRON_OUTLINED: IconData + IRON_ROUNDED: IconData + IRON_SHARP: IconData + ISO: IconData + ISO_OUTLINED: IconData + ISO_ROUNDED: IconData + ISO_SHARP: IconData + JAVASCRIPT: IconData + JAVASCRIPT_OUTLINED: IconData + JAVASCRIPT_ROUNDED: IconData + JAVASCRIPT_SHARP: IconData + JOIN_FULL: IconData + JOIN_FULL_OUTLINED: IconData + JOIN_FULL_ROUNDED: IconData + JOIN_FULL_SHARP: IconData + JOIN_INNER: IconData + JOIN_INNER_OUTLINED: IconData + JOIN_INNER_ROUNDED: IconData + JOIN_INNER_SHARP: IconData + JOIN_LEFT: IconData + JOIN_LEFT_OUTLINED: IconData + JOIN_LEFT_ROUNDED: IconData + JOIN_LEFT_SHARP: IconData + JOIN_RIGHT: IconData + JOIN_RIGHT_OUTLINED: IconData + JOIN_RIGHT_ROUNDED: IconData + JOIN_RIGHT_SHARP: IconData + KAYAKING: IconData + KAYAKING_OUTLINED: IconData + KAYAKING_ROUNDED: IconData + KAYAKING_SHARP: IconData + KEBAB_DINING: IconData + KEBAB_DINING_OUTLINED: IconData + KEBAB_DINING_ROUNDED: IconData + KEBAB_DINING_SHARP: IconData + KEY: IconData + KEY_OFF: IconData + KEY_OFF_OUTLINED: IconData + KEY_OFF_ROUNDED: IconData + KEY_OFF_SHARP: IconData + KEY_OUTLINED: IconData + KEY_ROUNDED: IconData + KEY_SHARP: IconData + KEYBOARD: IconData + KEYBOARD_ALT: IconData + KEYBOARD_ALT_OUTLINED: IconData + KEYBOARD_ALT_ROUNDED: IconData + KEYBOARD_ALT_SHARP: IconData + KEYBOARD_ARROW_DOWN: IconData + KEYBOARD_ARROW_DOWN_OUTLINED: IconData + KEYBOARD_ARROW_DOWN_ROUNDED: IconData + KEYBOARD_ARROW_DOWN_SHARP: IconData + KEYBOARD_ARROW_LEFT: IconData + KEYBOARD_ARROW_LEFT_OUTLINED: IconData + KEYBOARD_ARROW_LEFT_ROUNDED: IconData + KEYBOARD_ARROW_LEFT_SHARP: IconData + KEYBOARD_ARROW_RIGHT: IconData + KEYBOARD_ARROW_RIGHT_OUTLINED: IconData + KEYBOARD_ARROW_RIGHT_ROUNDED: IconData + KEYBOARD_ARROW_RIGHT_SHARP: IconData + KEYBOARD_ARROW_UP: IconData + KEYBOARD_ARROW_UP_OUTLINED: IconData + KEYBOARD_ARROW_UP_ROUNDED: IconData + KEYBOARD_ARROW_UP_SHARP: IconData + KEYBOARD_BACKSPACE: IconData + KEYBOARD_BACKSPACE_OUTLINED: IconData + KEYBOARD_BACKSPACE_ROUNDED: IconData + KEYBOARD_BACKSPACE_SHARP: IconData + KEYBOARD_CAPSLOCK: IconData + KEYBOARD_CAPSLOCK_OUTLINED: IconData + KEYBOARD_CAPSLOCK_ROUNDED: IconData + KEYBOARD_CAPSLOCK_SHARP: IconData + KEYBOARD_COMMAND_KEY: IconData + KEYBOARD_COMMAND_KEY_OUTLINED: IconData + KEYBOARD_COMMAND_KEY_ROUNDED: IconData + KEYBOARD_COMMAND_KEY_SHARP: IconData + KEYBOARD_CONTROL: IconData + KEYBOARD_CONTROL_KEY: IconData + KEYBOARD_CONTROL_KEY_OUTLINED: IconData + KEYBOARD_CONTROL_KEY_ROUNDED: IconData + KEYBOARD_CONTROL_KEY_SHARP: IconData + KEYBOARD_CONTROL_OUTLINED: IconData + KEYBOARD_CONTROL_ROUNDED: IconData + KEYBOARD_CONTROL_SHARP: IconData + KEYBOARD_DOUBLE_ARROW_DOWN: IconData + KEYBOARD_DOUBLE_ARROW_DOWN_OUTLINED: IconData + KEYBOARD_DOUBLE_ARROW_DOWN_ROUNDED: IconData + KEYBOARD_DOUBLE_ARROW_DOWN_SHARP: IconData + KEYBOARD_DOUBLE_ARROW_LEFT: IconData + KEYBOARD_DOUBLE_ARROW_LEFT_OUTLINED: IconData + KEYBOARD_DOUBLE_ARROW_LEFT_ROUNDED: IconData + KEYBOARD_DOUBLE_ARROW_LEFT_SHARP: IconData + KEYBOARD_DOUBLE_ARROW_RIGHT: IconData + KEYBOARD_DOUBLE_ARROW_RIGHT_OUTLINED: IconData + KEYBOARD_DOUBLE_ARROW_RIGHT_ROUNDED: IconData + KEYBOARD_DOUBLE_ARROW_RIGHT_SHARP: IconData + KEYBOARD_DOUBLE_ARROW_UP: IconData + KEYBOARD_DOUBLE_ARROW_UP_OUTLINED: IconData + KEYBOARD_DOUBLE_ARROW_UP_ROUNDED: IconData + KEYBOARD_DOUBLE_ARROW_UP_SHARP: IconData + KEYBOARD_HIDE: IconData + KEYBOARD_HIDE_OUTLINED: IconData + KEYBOARD_HIDE_ROUNDED: IconData + KEYBOARD_HIDE_SHARP: IconData + KEYBOARD_OPTION_KEY: IconData + KEYBOARD_OPTION_KEY_OUTLINED: IconData + KEYBOARD_OPTION_KEY_ROUNDED: IconData + KEYBOARD_OPTION_KEY_SHARP: IconData + KEYBOARD_OUTLINED: IconData + KEYBOARD_RETURN: IconData + KEYBOARD_RETURN_OUTLINED: IconData + KEYBOARD_RETURN_ROUNDED: IconData + KEYBOARD_RETURN_SHARP: IconData + KEYBOARD_ROUNDED: IconData + KEYBOARD_SHARP: IconData + KEYBOARD_TAB: IconData + KEYBOARD_TAB_OUTLINED: IconData + KEYBOARD_TAB_ROUNDED: IconData + KEYBOARD_TAB_SHARP: IconData + KEYBOARD_VOICE: IconData + KEYBOARD_VOICE_OUTLINED: IconData + KEYBOARD_VOICE_ROUNDED: IconData + KEYBOARD_VOICE_SHARP: IconData + KING_BED: IconData + KING_BED_OUTLINED: IconData + KING_BED_ROUNDED: IconData + KING_BED_SHARP: IconData + KITCHEN: IconData + KITCHEN_OUTLINED: IconData + KITCHEN_ROUNDED: IconData + KITCHEN_SHARP: IconData + KITESURFING: IconData + KITESURFING_OUTLINED: IconData + KITESURFING_ROUNDED: IconData + KITESURFING_SHARP: IconData + LABEL: IconData + LABEL_IMPORTANT: IconData + LABEL_IMPORTANT_OUTLINE: IconData + LABEL_IMPORTANT_OUTLINE_ROUNDED: IconData + LABEL_IMPORTANT_OUTLINE_SHARP: IconData + LABEL_IMPORTANT_OUTLINED: IconData + LABEL_IMPORTANT_ROUNDED: IconData + LABEL_IMPORTANT_SHARP: IconData + LABEL_OFF: IconData + LABEL_OFF_OUTLINED: IconData + LABEL_OFF_ROUNDED: IconData + LABEL_OFF_SHARP: IconData + LABEL_OUTLINE: IconData + LABEL_OUTLINE_ROUNDED: IconData + LABEL_OUTLINE_SHARP: IconData + LABEL_OUTLINED: IconData + LABEL_ROUNDED: IconData + LABEL_SHARP: IconData + LAN: IconData + LAN_OUTLINED: IconData + LAN_ROUNDED: IconData + LAN_SHARP: IconData + LANDSCAPE: IconData + LANDSCAPE_OUTLINED: IconData + LANDSCAPE_ROUNDED: IconData + LANDSCAPE_SHARP: IconData + LANDSLIDE: IconData + LANDSLIDE_OUTLINED: IconData + LANDSLIDE_ROUNDED: IconData + LANDSLIDE_SHARP: IconData + LANGUAGE: IconData + LANGUAGE_OUTLINED: IconData + LANGUAGE_ROUNDED: IconData + LANGUAGE_SHARP: IconData + LAPTOP: IconData + LAPTOP_CHROMEBOOK: IconData + LAPTOP_CHROMEBOOK_OUTLINED: IconData + LAPTOP_CHROMEBOOK_ROUNDED: IconData + LAPTOP_CHROMEBOOK_SHARP: IconData + LAPTOP_MAC: IconData + LAPTOP_MAC_OUTLINED: IconData + LAPTOP_MAC_ROUNDED: IconData + LAPTOP_MAC_SHARP: IconData + LAPTOP_OUTLINED: IconData + LAPTOP_ROUNDED: IconData + LAPTOP_SHARP: IconData + LAPTOP_WINDOWS: IconData + LAPTOP_WINDOWS_OUTLINED: IconData + LAPTOP_WINDOWS_ROUNDED: IconData + LAPTOP_WINDOWS_SHARP: IconData + LAST_PAGE: IconData + LAST_PAGE_OUTLINED: IconData + LAST_PAGE_ROUNDED: IconData + LAST_PAGE_SHARP: IconData + LAUNCH: IconData + LAUNCH_OUTLINED: IconData + LAUNCH_ROUNDED: IconData + LAUNCH_SHARP: IconData + LAYERS: IconData + LAYERS_CLEAR: IconData + LAYERS_CLEAR_OUTLINED: IconData + LAYERS_CLEAR_ROUNDED: IconData + LAYERS_CLEAR_SHARP: IconData + LAYERS_OUTLINED: IconData + LAYERS_ROUNDED: IconData + LAYERS_SHARP: IconData + LEADERBOARD: IconData + LEADERBOARD_OUTLINED: IconData + LEADERBOARD_ROUNDED: IconData + LEADERBOARD_SHARP: IconData + LEAK_ADD: IconData + LEAK_ADD_OUTLINED: IconData + LEAK_ADD_ROUNDED: IconData + LEAK_ADD_SHARP: IconData + LEAK_REMOVE: IconData + LEAK_REMOVE_OUTLINED: IconData + LEAK_REMOVE_ROUNDED: IconData + LEAK_REMOVE_SHARP: IconData + LEAVE_BAGS_AT_HOME: IconData + LEAVE_BAGS_AT_HOME_OUTLINED: IconData + LEAVE_BAGS_AT_HOME_ROUNDED: IconData + LEAVE_BAGS_AT_HOME_SHARP: IconData + LEGEND_TOGGLE: IconData + LEGEND_TOGGLE_OUTLINED: IconData + LEGEND_TOGGLE_ROUNDED: IconData + LEGEND_TOGGLE_SHARP: IconData + LENS: IconData + LENS_BLUR: IconData + LENS_BLUR_OUTLINED: IconData + LENS_BLUR_ROUNDED: IconData + LENS_BLUR_SHARP: IconData + LENS_OUTLINED: IconData + LENS_ROUNDED: IconData + LENS_SHARP: IconData + LIBRARY_ADD: IconData + LIBRARY_ADD_CHECK: IconData + LIBRARY_ADD_CHECK_OUTLINED: IconData + LIBRARY_ADD_CHECK_ROUNDED: IconData + LIBRARY_ADD_CHECK_SHARP: IconData + LIBRARY_ADD_OUTLINED: IconData + LIBRARY_ADD_ROUNDED: IconData + LIBRARY_ADD_SHARP: IconData + LIBRARY_BOOKS: IconData + LIBRARY_BOOKS_OUTLINED: IconData + LIBRARY_BOOKS_ROUNDED: IconData + LIBRARY_BOOKS_SHARP: IconData + LIBRARY_MUSIC: IconData + LIBRARY_MUSIC_OUTLINED: IconData + LIBRARY_MUSIC_ROUNDED: IconData + LIBRARY_MUSIC_SHARP: IconData + LIGHT: IconData + LIGHT_MODE: IconData + LIGHT_MODE_OUTLINED: IconData + LIGHT_MODE_ROUNDED: IconData + LIGHT_MODE_SHARP: IconData + LIGHT_OUTLINED: IconData + LIGHT_ROUNDED: IconData + LIGHT_SHARP: IconData + LIGHTBULB: IconData + LIGHTBULB_CIRCLE: IconData + LIGHTBULB_CIRCLE_OUTLINED: IconData + LIGHTBULB_CIRCLE_ROUNDED: IconData + LIGHTBULB_CIRCLE_SHARP: IconData + LIGHTBULB_OUTLINE: IconData + LIGHTBULB_OUTLINE_ROUNDED: IconData + LIGHTBULB_OUTLINE_SHARP: IconData + LIGHTBULB_OUTLINED: IconData + LIGHTBULB_ROUNDED: IconData + LIGHTBULB_SHARP: IconData + LINE_AXIS: IconData + LINE_AXIS_OUTLINED: IconData + LINE_AXIS_ROUNDED: IconData + LINE_AXIS_SHARP: IconData + LINE_STYLE: IconData + LINE_STYLE_OUTLINED: IconData + LINE_STYLE_ROUNDED: IconData + LINE_STYLE_SHARP: IconData + LINE_WEIGHT: IconData + LINE_WEIGHT_OUTLINED: IconData + LINE_WEIGHT_ROUNDED: IconData + LINE_WEIGHT_SHARP: IconData + LINEAR_SCALE: IconData + LINEAR_SCALE_OUTLINED: IconData + LINEAR_SCALE_ROUNDED: IconData + LINEAR_SCALE_SHARP: IconData + LINK: IconData + LINK_OFF: IconData + LINK_OFF_OUTLINED: IconData + LINK_OFF_ROUNDED: IconData + LINK_OFF_SHARP: IconData + LINK_OUTLINED: IconData + LINK_ROUNDED: IconData + LINK_SHARP: IconData + LINKED_CAMERA: IconData + LINKED_CAMERA_OUTLINED: IconData + LINKED_CAMERA_ROUNDED: IconData + LINKED_CAMERA_SHARP: IconData + LIQUOR: IconData + LIQUOR_OUTLINED: IconData + LIQUOR_ROUNDED: IconData + LIQUOR_SHARP: IconData + LIST: IconData + LIST_ALT: IconData + LIST_ALT_OUTLINED: IconData + LIST_ALT_ROUNDED: IconData + LIST_ALT_SHARP: IconData + LIST_OUTLINED: IconData + LIST_ROUNDED: IconData + LIST_SHARP: IconData + LIVE_HELP: IconData + LIVE_HELP_OUTLINED: IconData + LIVE_HELP_ROUNDED: IconData + LIVE_HELP_SHARP: IconData + LIVE_TV: IconData + LIVE_TV_OUTLINED: IconData + LIVE_TV_ROUNDED: IconData + LIVE_TV_SHARP: IconData + LIVING: IconData + LIVING_OUTLINED: IconData + LIVING_ROUNDED: IconData + LIVING_SHARP: IconData + LOCAL_ACTIVITY: IconData + LOCAL_ACTIVITY_OUTLINED: IconData + LOCAL_ACTIVITY_ROUNDED: IconData + LOCAL_ACTIVITY_SHARP: IconData + LOCAL_AIRPORT: IconData + LOCAL_AIRPORT_OUTLINED: IconData + LOCAL_AIRPORT_ROUNDED: IconData + LOCAL_AIRPORT_SHARP: IconData + LOCAL_ATM: IconData + LOCAL_ATM_OUTLINED: IconData + LOCAL_ATM_ROUNDED: IconData + LOCAL_ATM_SHARP: IconData + LOCAL_ATTRACTION: IconData + LOCAL_ATTRACTION_OUTLINED: IconData + LOCAL_ATTRACTION_ROUNDED: IconData + LOCAL_ATTRACTION_SHARP: IconData + LOCAL_BAR: IconData + LOCAL_BAR_OUTLINED: IconData + LOCAL_BAR_ROUNDED: IconData + LOCAL_BAR_SHARP: IconData + LOCAL_CAFE: IconData + LOCAL_CAFE_OUTLINED: IconData + LOCAL_CAFE_ROUNDED: IconData + LOCAL_CAFE_SHARP: IconData + LOCAL_CAR_WASH: IconData + LOCAL_CAR_WASH_OUTLINED: IconData + LOCAL_CAR_WASH_ROUNDED: IconData + LOCAL_CAR_WASH_SHARP: IconData + LOCAL_CONVENIENCE_STORE: IconData + LOCAL_CONVENIENCE_STORE_OUTLINED: IconData + LOCAL_CONVENIENCE_STORE_ROUNDED: IconData + LOCAL_CONVENIENCE_STORE_SHARP: IconData + LOCAL_DINING: IconData + LOCAL_DINING_OUTLINED: IconData + LOCAL_DINING_ROUNDED: IconData + LOCAL_DINING_SHARP: IconData + LOCAL_DRINK: IconData + LOCAL_DRINK_OUTLINED: IconData + LOCAL_DRINK_ROUNDED: IconData + LOCAL_DRINK_SHARP: IconData + LOCAL_FIRE_DEPARTMENT: IconData + LOCAL_FIRE_DEPARTMENT_OUTLINED: IconData + LOCAL_FIRE_DEPARTMENT_ROUNDED: IconData + LOCAL_FIRE_DEPARTMENT_SHARP: IconData + LOCAL_FLORIST: IconData + LOCAL_FLORIST_OUTLINED: IconData + LOCAL_FLORIST_ROUNDED: IconData + LOCAL_FLORIST_SHARP: IconData + LOCAL_GAS_STATION: IconData + LOCAL_GAS_STATION_OUTLINED: IconData + LOCAL_GAS_STATION_ROUNDED: IconData + LOCAL_GAS_STATION_SHARP: IconData + LOCAL_GROCERY_STORE: IconData + LOCAL_GROCERY_STORE_OUTLINED: IconData + LOCAL_GROCERY_STORE_ROUNDED: IconData + LOCAL_GROCERY_STORE_SHARP: IconData + LOCAL_HOSPITAL: IconData + LOCAL_HOSPITAL_OUTLINED: IconData + LOCAL_HOSPITAL_ROUNDED: IconData + LOCAL_HOSPITAL_SHARP: IconData + LOCAL_HOTEL: IconData + LOCAL_HOTEL_OUTLINED: IconData + LOCAL_HOTEL_ROUNDED: IconData + LOCAL_HOTEL_SHARP: IconData + LOCAL_LAUNDRY_SERVICE: IconData + LOCAL_LAUNDRY_SERVICE_OUTLINED: IconData + LOCAL_LAUNDRY_SERVICE_ROUNDED: IconData + LOCAL_LAUNDRY_SERVICE_SHARP: IconData + LOCAL_LIBRARY: IconData + LOCAL_LIBRARY_OUTLINED: IconData + LOCAL_LIBRARY_ROUNDED: IconData + LOCAL_LIBRARY_SHARP: IconData + LOCAL_MALL: IconData + LOCAL_MALL_OUTLINED: IconData + LOCAL_MALL_ROUNDED: IconData + LOCAL_MALL_SHARP: IconData + LOCAL_MOVIES: IconData + LOCAL_MOVIES_OUTLINED: IconData + LOCAL_MOVIES_ROUNDED: IconData + LOCAL_MOVIES_SHARP: IconData + LOCAL_OFFER: IconData + LOCAL_OFFER_OUTLINED: IconData + LOCAL_OFFER_ROUNDED: IconData + LOCAL_OFFER_SHARP: IconData + LOCAL_PARKING: IconData + LOCAL_PARKING_OUTLINED: IconData + LOCAL_PARKING_ROUNDED: IconData + LOCAL_PARKING_SHARP: IconData + LOCAL_PHARMACY: IconData + LOCAL_PHARMACY_OUTLINED: IconData + LOCAL_PHARMACY_ROUNDED: IconData + LOCAL_PHARMACY_SHARP: IconData + LOCAL_PHONE: IconData + LOCAL_PHONE_OUTLINED: IconData + LOCAL_PHONE_ROUNDED: IconData + LOCAL_PHONE_SHARP: IconData + LOCAL_PIZZA: IconData + LOCAL_PIZZA_OUTLINED: IconData + LOCAL_PIZZA_ROUNDED: IconData + LOCAL_PIZZA_SHARP: IconData + LOCAL_PLAY: IconData + LOCAL_PLAY_OUTLINED: IconData + LOCAL_PLAY_ROUNDED: IconData + LOCAL_PLAY_SHARP: IconData + LOCAL_POLICE: IconData + LOCAL_POLICE_OUTLINED: IconData + LOCAL_POLICE_ROUNDED: IconData + LOCAL_POLICE_SHARP: IconData + LOCAL_POST_OFFICE: IconData + LOCAL_POST_OFFICE_OUTLINED: IconData + LOCAL_POST_OFFICE_ROUNDED: IconData + LOCAL_POST_OFFICE_SHARP: IconData + LOCAL_PRINT_SHOP: IconData + LOCAL_PRINT_SHOP_OUTLINED: IconData + LOCAL_PRINT_SHOP_ROUNDED: IconData + LOCAL_PRINT_SHOP_SHARP: IconData + LOCAL_PRINTSHOP: IconData + LOCAL_PRINTSHOP_OUTLINED: IconData + LOCAL_PRINTSHOP_ROUNDED: IconData + LOCAL_PRINTSHOP_SHARP: IconData + LOCAL_RESTAURANT: IconData + LOCAL_RESTAURANT_OUTLINED: IconData + LOCAL_RESTAURANT_ROUNDED: IconData + LOCAL_RESTAURANT_SHARP: IconData + LOCAL_SEE: IconData + LOCAL_SEE_OUTLINED: IconData + LOCAL_SEE_ROUNDED: IconData + LOCAL_SEE_SHARP: IconData + LOCAL_SHIPPING: IconData + LOCAL_SHIPPING_OUTLINED: IconData + LOCAL_SHIPPING_ROUNDED: IconData + LOCAL_SHIPPING_SHARP: IconData + LOCAL_TAXI: IconData + LOCAL_TAXI_OUTLINED: IconData + LOCAL_TAXI_ROUNDED: IconData + LOCAL_TAXI_SHARP: IconData + LOCATION_CITY: IconData + LOCATION_CITY_OUTLINED: IconData + LOCATION_CITY_ROUNDED: IconData + LOCATION_CITY_SHARP: IconData + LOCATION_DISABLED: IconData + LOCATION_DISABLED_OUTLINED: IconData + LOCATION_DISABLED_ROUNDED: IconData + LOCATION_DISABLED_SHARP: IconData + LOCATION_HISTORY: IconData + LOCATION_HISTORY_OUTLINED: IconData + LOCATION_HISTORY_ROUNDED: IconData + LOCATION_HISTORY_SHARP: IconData + LOCATION_OFF: IconData + LOCATION_OFF_OUTLINED: IconData + LOCATION_OFF_ROUNDED: IconData + LOCATION_OFF_SHARP: IconData + LOCATION_ON: IconData + LOCATION_ON_OUTLINED: IconData + LOCATION_ON_ROUNDED: IconData + LOCATION_ON_SHARP: IconData + LOCATION_PIN: IconData + LOCATION_SEARCHING: IconData + LOCATION_SEARCHING_OUTLINED: IconData + LOCATION_SEARCHING_ROUNDED: IconData + LOCATION_SEARCHING_SHARP: IconData + LOCK: IconData + LOCK_CLOCK: IconData + LOCK_CLOCK_OUTLINED: IconData + LOCK_CLOCK_ROUNDED: IconData + LOCK_CLOCK_SHARP: IconData + LOCK_OPEN: IconData + LOCK_OPEN_OUTLINED: IconData + LOCK_OPEN_ROUNDED: IconData + LOCK_OPEN_SHARP: IconData + LOCK_OUTLINE: IconData + LOCK_OUTLINE_ROUNDED: IconData + LOCK_OUTLINE_SHARP: IconData + LOCK_OUTLINED: IconData + LOCK_PERSON: IconData + LOCK_PERSON_OUTLINED: IconData + LOCK_PERSON_ROUNDED: IconData + LOCK_PERSON_SHARP: IconData + LOCK_RESET: IconData + LOCK_RESET_OUTLINED: IconData + LOCK_RESET_ROUNDED: IconData + LOCK_RESET_SHARP: IconData + LOCK_ROUNDED: IconData + LOCK_SHARP: IconData + LOGIN: IconData + LOGIN_OUTLINED: IconData + LOGIN_ROUNDED: IconData + LOGIN_SHARP: IconData + LOGO_DEV: IconData + LOGO_DEV_OUTLINED: IconData + LOGO_DEV_ROUNDED: IconData + LOGO_DEV_SHARP: IconData + LOGOUT: IconData + LOGOUT_OUTLINED: IconData + LOGOUT_ROUNDED: IconData + LOGOUT_SHARP: IconData + LOOKS: IconData + LOOKS_3: IconData + LOOKS_3_OUTLINED: IconData + LOOKS_3_ROUNDED: IconData + LOOKS_3_SHARP: IconData + LOOKS_4: IconData + LOOKS_4_OUTLINED: IconData + LOOKS_4_ROUNDED: IconData + LOOKS_4_SHARP: IconData + LOOKS_5: IconData + LOOKS_5_OUTLINED: IconData + LOOKS_5_ROUNDED: IconData + LOOKS_5_SHARP: IconData + LOOKS_6: IconData + LOOKS_6_OUTLINED: IconData + LOOKS_6_ROUNDED: IconData + LOOKS_6_SHARP: IconData + LOOKS_ONE: IconData + LOOKS_ONE_OUTLINED: IconData + LOOKS_ONE_ROUNDED: IconData + LOOKS_ONE_SHARP: IconData + LOOKS_OUTLINED: IconData + LOOKS_ROUNDED: IconData + LOOKS_SHARP: IconData + LOOKS_TWO: IconData + LOOKS_TWO_OUTLINED: IconData + LOOKS_TWO_ROUNDED: IconData + LOOKS_TWO_SHARP: IconData + LOOP: IconData + LOOP_OUTLINED: IconData + LOOP_ROUNDED: IconData + LOOP_SHARP: IconData + LOUPE: IconData + LOUPE_OUTLINED: IconData + LOUPE_ROUNDED: IconData + LOUPE_SHARP: IconData + LOW_PRIORITY: IconData + LOW_PRIORITY_OUTLINED: IconData + LOW_PRIORITY_ROUNDED: IconData + LOW_PRIORITY_SHARP: IconData + LOYALTY: IconData + LOYALTY_OUTLINED: IconData + LOYALTY_ROUNDED: IconData + LOYALTY_SHARP: IconData + LTE_MOBILEDATA: IconData + LTE_MOBILEDATA_OUTLINED: IconData + LTE_MOBILEDATA_ROUNDED: IconData + LTE_MOBILEDATA_SHARP: IconData + LTE_PLUS_MOBILEDATA: IconData + LTE_PLUS_MOBILEDATA_OUTLINED: IconData + LTE_PLUS_MOBILEDATA_ROUNDED: IconData + LTE_PLUS_MOBILEDATA_SHARP: IconData + LUGGAGE: IconData + LUGGAGE_OUTLINED: IconData + LUGGAGE_ROUNDED: IconData + LUGGAGE_SHARP: IconData + LUNCH_DINING: IconData + LUNCH_DINING_OUTLINED: IconData + LUNCH_DINING_ROUNDED: IconData + LUNCH_DINING_SHARP: IconData + LYRICS: IconData + LYRICS_OUTLINED: IconData + LYRICS_ROUNDED: IconData + LYRICS_SHARP: IconData + MACRO_OFF: IconData + MACRO_OFF_OUTLINED: IconData + MACRO_OFF_ROUNDED: IconData + MACRO_OFF_SHARP: IconData + MAIL: IconData + MAIL_LOCK: IconData + MAIL_LOCK_OUTLINED: IconData + MAIL_LOCK_ROUNDED: IconData + MAIL_LOCK_SHARP: IconData + MAIL_OUTLINE: IconData + MAIL_OUTLINE_OUTLINED: IconData + MAIL_OUTLINE_ROUNDED: IconData + MAIL_OUTLINE_SHARP: IconData + MAIL_OUTLINED: IconData + MAIL_ROUNDED: IconData + MAIL_SHARP: IconData + MALE: IconData + MALE_OUTLINED: IconData + MALE_ROUNDED: IconData + MALE_SHARP: IconData + MAN: IconData + MAN_2: IconData + MAN_2_OUTLINED: IconData + MAN_2_ROUNDED: IconData + MAN_2_SHARP: IconData + MAN_3: IconData + MAN_3_OUTLINED: IconData + MAN_3_ROUNDED: IconData + MAN_3_SHARP: IconData + MAN_4: IconData + MAN_4_OUTLINED: IconData + MAN_4_ROUNDED: IconData + MAN_4_SHARP: IconData + MAN_OUTLINED: IconData + MAN_ROUNDED: IconData + MAN_SHARP: IconData + MANAGE_ACCOUNTS: IconData + MANAGE_ACCOUNTS_OUTLINED: IconData + MANAGE_ACCOUNTS_ROUNDED: IconData + MANAGE_ACCOUNTS_SHARP: IconData + MANAGE_HISTORY: IconData + MANAGE_HISTORY_OUTLINED: IconData + MANAGE_HISTORY_ROUNDED: IconData + MANAGE_HISTORY_SHARP: IconData + MANAGE_SEARCH: IconData + MANAGE_SEARCH_OUTLINED: IconData + MANAGE_SEARCH_ROUNDED: IconData + MANAGE_SEARCH_SHARP: IconData + MAP: IconData + MAP_OUTLINED: IconData + MAP_ROUNDED: IconData + MAP_SHARP: IconData + MAPS_HOME_WORK: IconData + MAPS_HOME_WORK_OUTLINED: IconData + MAPS_HOME_WORK_ROUNDED: IconData + MAPS_HOME_WORK_SHARP: IconData + MAPS_UGC: IconData + MAPS_UGC_OUTLINED: IconData + MAPS_UGC_ROUNDED: IconData + MAPS_UGC_SHARP: IconData + MARGIN: IconData + MARGIN_OUTLINED: IconData + MARGIN_ROUNDED: IconData + MARGIN_SHARP: IconData + MARK_AS_UNREAD: IconData + MARK_AS_UNREAD_OUTLINED: IconData + MARK_AS_UNREAD_ROUNDED: IconData + MARK_AS_UNREAD_SHARP: IconData + MARK_CHAT_READ: IconData + MARK_CHAT_READ_OUTLINED: IconData + MARK_CHAT_READ_ROUNDED: IconData + MARK_CHAT_READ_SHARP: IconData + MARK_CHAT_UNREAD: IconData + MARK_CHAT_UNREAD_OUTLINED: IconData + MARK_CHAT_UNREAD_ROUNDED: IconData + MARK_CHAT_UNREAD_SHARP: IconData + MARK_EMAIL_READ: IconData + MARK_EMAIL_READ_OUTLINED: IconData + MARK_EMAIL_READ_ROUNDED: IconData + MARK_EMAIL_READ_SHARP: IconData + MARK_EMAIL_UNREAD: IconData + MARK_EMAIL_UNREAD_OUTLINED: IconData + MARK_EMAIL_UNREAD_ROUNDED: IconData + MARK_EMAIL_UNREAD_SHARP: IconData + MARK_UNREAD_CHAT_ALT: IconData + MARK_UNREAD_CHAT_ALT_OUTLINED: IconData + MARK_UNREAD_CHAT_ALT_ROUNDED: IconData + MARK_UNREAD_CHAT_ALT_SHARP: IconData + MARKUNREAD: IconData + MARKUNREAD_MAILBOX: IconData + MARKUNREAD_MAILBOX_OUTLINED: IconData + MARKUNREAD_MAILBOX_ROUNDED: IconData + MARKUNREAD_MAILBOX_SHARP: IconData + MARKUNREAD_OUTLINED: IconData + MARKUNREAD_ROUNDED: IconData + MARKUNREAD_SHARP: IconData + MASKS: IconData + MASKS_OUTLINED: IconData + MASKS_ROUNDED: IconData + MASKS_SHARP: IconData + MAXIMIZE: IconData + MAXIMIZE_OUTLINED: IconData + MAXIMIZE_ROUNDED: IconData + MAXIMIZE_SHARP: IconData + MEDIA_BLUETOOTH_OFF: IconData + MEDIA_BLUETOOTH_OFF_OUTLINED: IconData + MEDIA_BLUETOOTH_OFF_ROUNDED: IconData + MEDIA_BLUETOOTH_OFF_SHARP: IconData + MEDIA_BLUETOOTH_ON: IconData + MEDIA_BLUETOOTH_ON_OUTLINED: IconData + MEDIA_BLUETOOTH_ON_ROUNDED: IconData + MEDIA_BLUETOOTH_ON_SHARP: IconData + MEDIATION: IconData + MEDIATION_OUTLINED: IconData + MEDIATION_ROUNDED: IconData + MEDIATION_SHARP: IconData + MEDICAL_INFORMATION: IconData + MEDICAL_INFORMATION_OUTLINED: IconData + MEDICAL_INFORMATION_ROUNDED: IconData + MEDICAL_INFORMATION_SHARP: IconData + MEDICAL_SERVICES: IconData + MEDICAL_SERVICES_OUTLINED: IconData + MEDICAL_SERVICES_ROUNDED: IconData + MEDICAL_SERVICES_SHARP: IconData + MEDICATION: IconData + MEDICATION_LIQUID: IconData + MEDICATION_LIQUID_OUTLINED: IconData + MEDICATION_LIQUID_ROUNDED: IconData + MEDICATION_LIQUID_SHARP: IconData + MEDICATION_OUTLINED: IconData + MEDICATION_ROUNDED: IconData + MEDICATION_SHARP: IconData + MEETING_ROOM: IconData + MEETING_ROOM_OUTLINED: IconData + MEETING_ROOM_ROUNDED: IconData + MEETING_ROOM_SHARP: IconData + MEMORY: IconData + MEMORY_OUTLINED: IconData + MEMORY_ROUNDED: IconData + MEMORY_SHARP: IconData + MENU: IconData + MENU_BOOK: IconData + MENU_BOOK_OUTLINED: IconData + MENU_BOOK_ROUNDED: IconData + MENU_BOOK_SHARP: IconData + MENU_OPEN: IconData + MENU_OPEN_OUTLINED: IconData + MENU_OPEN_ROUNDED: IconData + MENU_OPEN_SHARP: IconData + MENU_OUTLINED: IconData + MENU_ROUNDED: IconData + MENU_SHARP: IconData + MERGE: IconData + MERGE_OUTLINED: IconData + MERGE_ROUNDED: IconData + MERGE_SHARP: IconData + MERGE_TYPE: IconData + MERGE_TYPE_OUTLINED: IconData + MERGE_TYPE_ROUNDED: IconData + MERGE_TYPE_SHARP: IconData + MESSAGE: IconData + MESSAGE_OUTLINED: IconData + MESSAGE_ROUNDED: IconData + MESSAGE_SHARP: IconData + MESSENGER: IconData + MESSENGER_OUTLINE: IconData + MESSENGER_OUTLINE_OUTLINED: IconData + MESSENGER_OUTLINE_ROUNDED: IconData + MESSENGER_OUTLINE_SHARP: IconData + MESSENGER_OUTLINED: IconData + MESSENGER_ROUNDED: IconData + MESSENGER_SHARP: IconData + MIC: IconData + MIC_EXTERNAL_OFF: IconData + MIC_EXTERNAL_OFF_OUTLINED: IconData + MIC_EXTERNAL_OFF_ROUNDED: IconData + MIC_EXTERNAL_OFF_SHARP: IconData + MIC_EXTERNAL_ON: IconData + MIC_EXTERNAL_ON_OUTLINED: IconData + MIC_EXTERNAL_ON_ROUNDED: IconData + MIC_EXTERNAL_ON_SHARP: IconData + MIC_NONE: IconData + MIC_NONE_OUTLINED: IconData + MIC_NONE_ROUNDED: IconData + MIC_NONE_SHARP: IconData + MIC_OFF: IconData + MIC_OFF_OUTLINED: IconData + MIC_OFF_ROUNDED: IconData + MIC_OFF_SHARP: IconData + MIC_OUTLINED: IconData + MIC_ROUNDED: IconData + MIC_SHARP: IconData + MICROWAVE: IconData + MICROWAVE_OUTLINED: IconData + MICROWAVE_ROUNDED: IconData + MICROWAVE_SHARP: IconData + MILITARY_TECH: IconData + MILITARY_TECH_OUTLINED: IconData + MILITARY_TECH_ROUNDED: IconData + MILITARY_TECH_SHARP: IconData + MINIMIZE: IconData + MINIMIZE_OUTLINED: IconData + MINIMIZE_ROUNDED: IconData + MINIMIZE_SHARP: IconData + MINOR_CRASH: IconData + MINOR_CRASH_OUTLINED: IconData + MINOR_CRASH_ROUNDED: IconData + MINOR_CRASH_SHARP: IconData + MISCELLANEOUS_SERVICES: IconData + MISCELLANEOUS_SERVICES_OUTLINED: IconData + MISCELLANEOUS_SERVICES_ROUNDED: IconData + MISCELLANEOUS_SERVICES_SHARP: IconData + MISSED_VIDEO_CALL: IconData + MISSED_VIDEO_CALL_OUTLINED: IconData + MISSED_VIDEO_CALL_ROUNDED: IconData + MISSED_VIDEO_CALL_SHARP: IconData + MMS: IconData + MMS_OUTLINED: IconData + MMS_ROUNDED: IconData + MMS_SHARP: IconData + MOBILE_FRIENDLY: IconData + MOBILE_FRIENDLY_OUTLINED: IconData + MOBILE_FRIENDLY_ROUNDED: IconData + MOBILE_FRIENDLY_SHARP: IconData + MOBILE_OFF: IconData + MOBILE_OFF_OUTLINED: IconData + MOBILE_OFF_ROUNDED: IconData + MOBILE_OFF_SHARP: IconData + MOBILE_SCREEN_SHARE: IconData + MOBILE_SCREEN_SHARE_OUTLINED: IconData + MOBILE_SCREEN_SHARE_ROUNDED: IconData + MOBILE_SCREEN_SHARE_SHARP: IconData + MOBILEDATA_OFF: IconData + MOBILEDATA_OFF_OUTLINED: IconData + MOBILEDATA_OFF_ROUNDED: IconData + MOBILEDATA_OFF_SHARP: IconData + MODE: IconData + MODE_COMMENT: IconData + MODE_COMMENT_OUTLINED: IconData + MODE_COMMENT_ROUNDED: IconData + MODE_COMMENT_SHARP: IconData + MODE_EDIT: IconData + MODE_EDIT_OUTLINE: IconData + MODE_EDIT_OUTLINE_OUTLINED: IconData + MODE_EDIT_OUTLINE_ROUNDED: IconData + MODE_EDIT_OUTLINE_SHARP: IconData + MODE_EDIT_OUTLINED: IconData + MODE_EDIT_ROUNDED: IconData + MODE_EDIT_SHARP: IconData + MODE_FAN_OFF: IconData + MODE_FAN_OFF_OUTLINED: IconData + MODE_FAN_OFF_ROUNDED: IconData + MODE_FAN_OFF_SHARP: IconData + MODE_NIGHT: IconData + MODE_NIGHT_OUTLINED: IconData + MODE_NIGHT_ROUNDED: IconData + MODE_NIGHT_SHARP: IconData + MODE_OF_TRAVEL: IconData + MODE_OF_TRAVEL_OUTLINED: IconData + MODE_OF_TRAVEL_ROUNDED: IconData + MODE_OF_TRAVEL_SHARP: IconData + MODE_OUTLINED: IconData + MODE_ROUNDED: IconData + MODE_SHARP: IconData + MODE_STANDBY: IconData + MODE_STANDBY_OUTLINED: IconData + MODE_STANDBY_ROUNDED: IconData + MODE_STANDBY_SHARP: IconData + MODEL_TRAINING: IconData + MODEL_TRAINING_OUTLINED: IconData + MODEL_TRAINING_ROUNDED: IconData + MODEL_TRAINING_SHARP: IconData + MONETIZATION_ON: IconData + MONETIZATION_ON_OUTLINED: IconData + MONETIZATION_ON_ROUNDED: IconData + MONETIZATION_ON_SHARP: IconData + MONEY: IconData + MONEY_OFF: IconData + MONEY_OFF_CSRED: IconData + MONEY_OFF_CSRED_OUTLINED: IconData + MONEY_OFF_CSRED_ROUNDED: IconData + MONEY_OFF_CSRED_SHARP: IconData + MONEY_OFF_OUTLINED: IconData + MONEY_OFF_ROUNDED: IconData + MONEY_OFF_SHARP: IconData + MONEY_OUTLINED: IconData + MONEY_ROUNDED: IconData + MONEY_SHARP: IconData + MONITOR: IconData + MONITOR_HEART: IconData + MONITOR_HEART_OUTLINED: IconData + MONITOR_HEART_ROUNDED: IconData + MONITOR_HEART_SHARP: IconData + MONITOR_OUTLINED: IconData + MONITOR_ROUNDED: IconData + MONITOR_SHARP: IconData + MONITOR_WEIGHT: IconData + MONITOR_WEIGHT_OUTLINED: IconData + MONITOR_WEIGHT_ROUNDED: IconData + MONITOR_WEIGHT_SHARP: IconData + MONOCHROME_PHOTOS: IconData + MONOCHROME_PHOTOS_OUTLINED: IconData + MONOCHROME_PHOTOS_ROUNDED: IconData + MONOCHROME_PHOTOS_SHARP: IconData + MOOD: IconData + MOOD_BAD: IconData + MOOD_BAD_OUTLINED: IconData + MOOD_BAD_ROUNDED: IconData + MOOD_BAD_SHARP: IconData + MOOD_OUTLINED: IconData + MOOD_ROUNDED: IconData + MOOD_SHARP: IconData + MOPED: IconData + MOPED_OUTLINED: IconData + MOPED_ROUNDED: IconData + MOPED_SHARP: IconData + MORE: IconData + MORE_HORIZ: IconData + MORE_HORIZ_OUTLINED: IconData + MORE_HORIZ_ROUNDED: IconData + MORE_HORIZ_SHARP: IconData + MORE_OUTLINED: IconData + MORE_ROUNDED: IconData + MORE_SHARP: IconData + MORE_TIME: IconData + MORE_TIME_OUTLINED: IconData + MORE_TIME_ROUNDED: IconData + MORE_TIME_SHARP: IconData + MORE_VERT: IconData + MORE_VERT_OUTLINED: IconData + MORE_VERT_ROUNDED: IconData + MORE_VERT_SHARP: IconData + MOSQUE: IconData + MOSQUE_OUTLINED: IconData + MOSQUE_ROUNDED: IconData + MOSQUE_SHARP: IconData + MOTION_PHOTOS_AUTO: IconData + MOTION_PHOTOS_AUTO_OUTLINED: IconData + MOTION_PHOTOS_AUTO_ROUNDED: IconData + MOTION_PHOTOS_AUTO_SHARP: IconData + MOTION_PHOTOS_OFF: IconData + MOTION_PHOTOS_OFF_OUTLINED: IconData + MOTION_PHOTOS_OFF_ROUNDED: IconData + MOTION_PHOTOS_OFF_SHARP: IconData + MOTION_PHOTOS_ON: IconData + MOTION_PHOTOS_ON_OUTLINED: IconData + MOTION_PHOTOS_ON_ROUNDED: IconData + MOTION_PHOTOS_ON_SHARP: IconData + MOTION_PHOTOS_PAUSE: IconData + MOTION_PHOTOS_PAUSE_OUTLINED: IconData + MOTION_PHOTOS_PAUSE_ROUNDED: IconData + MOTION_PHOTOS_PAUSE_SHARP: IconData + MOTION_PHOTOS_PAUSED: IconData + MOTION_PHOTOS_PAUSED_OUTLINED: IconData + MOTION_PHOTOS_PAUSED_ROUNDED: IconData + MOTION_PHOTOS_PAUSED_SHARP: IconData + MOTORCYCLE: IconData + MOTORCYCLE_OUTLINED: IconData + MOTORCYCLE_ROUNDED: IconData + MOTORCYCLE_SHARP: IconData + MOUSE: IconData + MOUSE_OUTLINED: IconData + MOUSE_ROUNDED: IconData + MOUSE_SHARP: IconData + MOVE_DOWN: IconData + MOVE_DOWN_OUTLINED: IconData + MOVE_DOWN_ROUNDED: IconData + MOVE_DOWN_SHARP: IconData + MOVE_TO_INBOX: IconData + MOVE_TO_INBOX_OUTLINED: IconData + MOVE_TO_INBOX_ROUNDED: IconData + MOVE_TO_INBOX_SHARP: IconData + MOVE_UP: IconData + MOVE_UP_OUTLINED: IconData + MOVE_UP_ROUNDED: IconData + MOVE_UP_SHARP: IconData + MOVIE: IconData + MOVIE_CREATION: IconData + MOVIE_CREATION_OUTLINED: IconData + MOVIE_CREATION_ROUNDED: IconData + MOVIE_CREATION_SHARP: IconData + MOVIE_EDIT: IconData + MOVIE_FILTER: IconData + MOVIE_FILTER_OUTLINED: IconData + MOVIE_FILTER_ROUNDED: IconData + MOVIE_FILTER_SHARP: IconData + MOVIE_OUTLINED: IconData + MOVIE_ROUNDED: IconData + MOVIE_SHARP: IconData + MOVING: IconData + MOVING_OUTLINED: IconData + MOVING_ROUNDED: IconData + MOVING_SHARP: IconData + MP: IconData + MP_OUTLINED: IconData + MP_ROUNDED: IconData + MP_SHARP: IconData + MULTILINE_CHART: IconData + MULTILINE_CHART_OUTLINED: IconData + MULTILINE_CHART_ROUNDED: IconData + MULTILINE_CHART_SHARP: IconData + MULTIPLE_STOP: IconData + MULTIPLE_STOP_OUTLINED: IconData + MULTIPLE_STOP_ROUNDED: IconData + MULTIPLE_STOP_SHARP: IconData + MULTITRACK_AUDIO: IconData + MULTITRACK_AUDIO_OUTLINED: IconData + MULTITRACK_AUDIO_ROUNDED: IconData + MULTITRACK_AUDIO_SHARP: IconData + MUSEUM: IconData + MUSEUM_OUTLINED: IconData + MUSEUM_ROUNDED: IconData + MUSEUM_SHARP: IconData + MUSIC_NOTE: IconData + MUSIC_NOTE_OUTLINED: IconData + MUSIC_NOTE_ROUNDED: IconData + MUSIC_NOTE_SHARP: IconData + MUSIC_OFF: IconData + MUSIC_OFF_OUTLINED: IconData + MUSIC_OFF_ROUNDED: IconData + MUSIC_OFF_SHARP: IconData + MUSIC_VIDEO: IconData + MUSIC_VIDEO_OUTLINED: IconData + MUSIC_VIDEO_ROUNDED: IconData + MUSIC_VIDEO_SHARP: IconData + MY_LIBRARY_ADD: IconData + MY_LIBRARY_ADD_OUTLINED: IconData + MY_LIBRARY_ADD_ROUNDED: IconData + MY_LIBRARY_ADD_SHARP: IconData + MY_LIBRARY_BOOKS: IconData + MY_LIBRARY_BOOKS_OUTLINED: IconData + MY_LIBRARY_BOOKS_ROUNDED: IconData + MY_LIBRARY_BOOKS_SHARP: IconData + MY_LIBRARY_MUSIC: IconData + MY_LIBRARY_MUSIC_OUTLINED: IconData + MY_LIBRARY_MUSIC_ROUNDED: IconData + MY_LIBRARY_MUSIC_SHARP: IconData + MY_LOCATION: IconData + MY_LOCATION_OUTLINED: IconData + MY_LOCATION_ROUNDED: IconData + MY_LOCATION_SHARP: IconData + NAT: IconData + NAT_OUTLINED: IconData + NAT_ROUNDED: IconData + NAT_SHARP: IconData + NATURE: IconData + NATURE_OUTLINED: IconData + NATURE_PEOPLE: IconData + NATURE_PEOPLE_OUTLINED: IconData + NATURE_PEOPLE_ROUNDED: IconData + NATURE_PEOPLE_SHARP: IconData + NATURE_ROUNDED: IconData + NATURE_SHARP: IconData + NAVIGATE_BEFORE: IconData + NAVIGATE_BEFORE_OUTLINED: IconData + NAVIGATE_BEFORE_ROUNDED: IconData + NAVIGATE_BEFORE_SHARP: IconData + NAVIGATE_NEXT: IconData + NAVIGATE_NEXT_OUTLINED: IconData + NAVIGATE_NEXT_ROUNDED: IconData + NAVIGATE_NEXT_SHARP: IconData + NAVIGATION: IconData + NAVIGATION_OUTLINED: IconData + NAVIGATION_ROUNDED: IconData + NAVIGATION_SHARP: IconData + NEAR_ME: IconData + NEAR_ME_DISABLED: IconData + NEAR_ME_DISABLED_OUTLINED: IconData + NEAR_ME_DISABLED_ROUNDED: IconData + NEAR_ME_DISABLED_SHARP: IconData + NEAR_ME_OUTLINED: IconData + NEAR_ME_ROUNDED: IconData + NEAR_ME_SHARP: IconData + NEARBY_ERROR: IconData + NEARBY_ERROR_OUTLINED: IconData + NEARBY_ERROR_ROUNDED: IconData + NEARBY_ERROR_SHARP: IconData + NEARBY_OFF: IconData + NEARBY_OFF_OUTLINED: IconData + NEARBY_OFF_ROUNDED: IconData + NEARBY_OFF_SHARP: IconData + NEST_CAM_WIRED_STAND: IconData + NEST_CAM_WIRED_STAND_OUTLINED: IconData + NEST_CAM_WIRED_STAND_ROUNDED: IconData + NEST_CAM_WIRED_STAND_SHARP: IconData + NETWORK_CELL: IconData + NETWORK_CELL_OUTLINED: IconData + NETWORK_CELL_ROUNDED: IconData + NETWORK_CELL_SHARP: IconData + NETWORK_CHECK: IconData + NETWORK_CHECK_OUTLINED: IconData + NETWORK_CHECK_ROUNDED: IconData + NETWORK_CHECK_SHARP: IconData + NETWORK_LOCKED: IconData + NETWORK_LOCKED_OUTLINED: IconData + NETWORK_LOCKED_ROUNDED: IconData + NETWORK_LOCKED_SHARP: IconData + NETWORK_PING: IconData + NETWORK_PING_OUTLINED: IconData + NETWORK_PING_ROUNDED: IconData + NETWORK_PING_SHARP: IconData + NETWORK_WIFI: IconData + NETWORK_WIFI_1_BAR: IconData + NETWORK_WIFI_1_BAR_OUTLINED: IconData + NETWORK_WIFI_1_BAR_ROUNDED: IconData + NETWORK_WIFI_1_BAR_SHARP: IconData + NETWORK_WIFI_2_BAR: IconData + NETWORK_WIFI_2_BAR_OUTLINED: IconData + NETWORK_WIFI_2_BAR_ROUNDED: IconData + NETWORK_WIFI_2_BAR_SHARP: IconData + NETWORK_WIFI_3_BAR: IconData + NETWORK_WIFI_3_BAR_OUTLINED: IconData + NETWORK_WIFI_3_BAR_ROUNDED: IconData + NETWORK_WIFI_3_BAR_SHARP: IconData + NETWORK_WIFI_OUTLINED: IconData + NETWORK_WIFI_ROUNDED: IconData + NETWORK_WIFI_SHARP: IconData + NEW_LABEL: IconData + NEW_LABEL_OUTLINED: IconData + NEW_LABEL_ROUNDED: IconData + NEW_LABEL_SHARP: IconData + NEW_RELEASES: IconData + NEW_RELEASES_OUTLINED: IconData + NEW_RELEASES_ROUNDED: IconData + NEW_RELEASES_SHARP: IconData + NEWSPAPER: IconData + NEWSPAPER_OUTLINED: IconData + NEWSPAPER_ROUNDED: IconData + NEWSPAPER_SHARP: IconData + NEXT_PLAN: IconData + NEXT_PLAN_OUTLINED: IconData + NEXT_PLAN_ROUNDED: IconData + NEXT_PLAN_SHARP: IconData + NEXT_WEEK: IconData + NEXT_WEEK_OUTLINED: IconData + NEXT_WEEK_ROUNDED: IconData + NEXT_WEEK_SHARP: IconData + NFC: IconData + NFC_OUTLINED: IconData + NFC_ROUNDED: IconData + NFC_SHARP: IconData + NIGHT_SHELTER: IconData + NIGHT_SHELTER_OUTLINED: IconData + NIGHT_SHELTER_ROUNDED: IconData + NIGHT_SHELTER_SHARP: IconData + NIGHTLIFE: IconData + NIGHTLIFE_OUTLINED: IconData + NIGHTLIFE_ROUNDED: IconData + NIGHTLIFE_SHARP: IconData + NIGHTLIGHT: IconData + NIGHTLIGHT_OUTLINED: IconData + NIGHTLIGHT_ROUND: IconData + NIGHTLIGHT_ROUND_OUTLINED: IconData + NIGHTLIGHT_ROUND_ROUNDED: IconData + NIGHTLIGHT_ROUND_SHARP: IconData + NIGHTLIGHT_ROUNDED: IconData + NIGHTLIGHT_SHARP: IconData + NIGHTS_STAY: IconData + NIGHTS_STAY_OUTLINED: IconData + NIGHTS_STAY_ROUNDED: IconData + NIGHTS_STAY_SHARP: IconData + NINE_K: IconData + NINE_K_OUTLINED: IconData + NINE_K_PLUS: IconData + NINE_K_PLUS_OUTLINED: IconData + NINE_K_PLUS_ROUNDED: IconData + NINE_K_PLUS_SHARP: IconData + NINE_K_ROUNDED: IconData + NINE_K_SHARP: IconData + NINE_MP: IconData + NINE_MP_OUTLINED: IconData + NINE_MP_ROUNDED: IconData + NINE_MP_SHARP: IconData + NINETEEN_MP: IconData + NINETEEN_MP_OUTLINED: IconData + NINETEEN_MP_ROUNDED: IconData + NINETEEN_MP_SHARP: IconData + NO_ACCOUNTS: IconData + NO_ACCOUNTS_OUTLINED: IconData + NO_ACCOUNTS_ROUNDED: IconData + NO_ACCOUNTS_SHARP: IconData + NO_ADULT_CONTENT: IconData + NO_ADULT_CONTENT_OUTLINED: IconData + NO_ADULT_CONTENT_ROUNDED: IconData + NO_ADULT_CONTENT_SHARP: IconData + NO_BACKPACK: IconData + NO_BACKPACK_OUTLINED: IconData + NO_BACKPACK_ROUNDED: IconData + NO_BACKPACK_SHARP: IconData + NO_CELL: IconData + NO_CELL_OUTLINED: IconData + NO_CELL_ROUNDED: IconData + NO_CELL_SHARP: IconData + NO_CRASH: IconData + NO_CRASH_OUTLINED: IconData + NO_CRASH_ROUNDED: IconData + NO_CRASH_SHARP: IconData + NO_DRINKS: IconData + NO_DRINKS_OUTLINED: IconData + NO_DRINKS_ROUNDED: IconData + NO_DRINKS_SHARP: IconData + NO_ENCRYPTION: IconData + NO_ENCRYPTION_GMAILERRORRED: IconData + NO_ENCRYPTION_GMAILERRORRED_OUTLINED: IconData + NO_ENCRYPTION_GMAILERRORRED_ROUNDED: IconData + NO_ENCRYPTION_GMAILERRORRED_SHARP: IconData + NO_ENCRYPTION_OUTLINED: IconData + NO_ENCRYPTION_ROUNDED: IconData + NO_ENCRYPTION_SHARP: IconData + NO_FLASH: IconData + NO_FLASH_OUTLINED: IconData + NO_FLASH_ROUNDED: IconData + NO_FLASH_SHARP: IconData + NO_FOOD: IconData + NO_FOOD_OUTLINED: IconData + NO_FOOD_ROUNDED: IconData + NO_FOOD_SHARP: IconData + NO_LUGGAGE: IconData + NO_LUGGAGE_OUTLINED: IconData + NO_LUGGAGE_ROUNDED: IconData + NO_LUGGAGE_SHARP: IconData + NO_MEALS: IconData + NO_MEALS_OULINE: IconData + NO_MEALS_OUTLINED: IconData + NO_MEALS_ROUNDED: IconData + NO_MEALS_SHARP: IconData + NO_MEETING_ROOM: IconData + NO_MEETING_ROOM_OUTLINED: IconData + NO_MEETING_ROOM_ROUNDED: IconData + NO_MEETING_ROOM_SHARP: IconData + NO_PHOTOGRAPHY: IconData + NO_PHOTOGRAPHY_OUTLINED: IconData + NO_PHOTOGRAPHY_ROUNDED: IconData + NO_PHOTOGRAPHY_SHARP: IconData + NO_SIM: IconData + NO_SIM_OUTLINED: IconData + NO_SIM_ROUNDED: IconData + NO_SIM_SHARP: IconData + NO_STROLLER: IconData + NO_STROLLER_OUTLINED: IconData + NO_STROLLER_ROUNDED: IconData + NO_STROLLER_SHARP: IconData + NO_TRANSFER: IconData + NO_TRANSFER_OUTLINED: IconData + NO_TRANSFER_ROUNDED: IconData + NO_TRANSFER_SHARP: IconData + NOISE_AWARE: IconData + NOISE_AWARE_OUTLINED: IconData + NOISE_AWARE_ROUNDED: IconData + NOISE_AWARE_SHARP: IconData + NOISE_CONTROL_OFF: IconData + NOISE_CONTROL_OFF_OUTLINED: IconData + NOISE_CONTROL_OFF_ROUNDED: IconData + NOISE_CONTROL_OFF_SHARP: IconData + NORDIC_WALKING: IconData + NORDIC_WALKING_OUTLINED: IconData + NORDIC_WALKING_ROUNDED: IconData + NORDIC_WALKING_SHARP: IconData + NORTH: IconData + NORTH_EAST: IconData + NORTH_EAST_OUTLINED: IconData + NORTH_EAST_ROUNDED: IconData + NORTH_EAST_SHARP: IconData + NORTH_OUTLINED: IconData + NORTH_ROUNDED: IconData + NORTH_SHARP: IconData + NORTH_WEST: IconData + NORTH_WEST_OUTLINED: IconData + NORTH_WEST_ROUNDED: IconData + NORTH_WEST_SHARP: IconData + NOT_ACCESSIBLE: IconData + NOT_ACCESSIBLE_OUTLINED: IconData + NOT_ACCESSIBLE_ROUNDED: IconData + NOT_ACCESSIBLE_SHARP: IconData + NOT_INTERESTED: IconData + NOT_INTERESTED_OUTLINED: IconData + NOT_INTERESTED_ROUNDED: IconData + NOT_INTERESTED_SHARP: IconData + NOT_LISTED_LOCATION: IconData + NOT_LISTED_LOCATION_OUTLINED: IconData + NOT_LISTED_LOCATION_ROUNDED: IconData + NOT_LISTED_LOCATION_SHARP: IconData + NOT_STARTED: IconData + NOT_STARTED_OUTLINED: IconData + NOT_STARTED_ROUNDED: IconData + NOT_STARTED_SHARP: IconData + NOTE: IconData + NOTE_ADD: IconData + NOTE_ADD_OUTLINED: IconData + NOTE_ADD_ROUNDED: IconData + NOTE_ADD_SHARP: IconData + NOTE_ALT: IconData + NOTE_ALT_OUTLINED: IconData + NOTE_ALT_ROUNDED: IconData + NOTE_ALT_SHARP: IconData + NOTE_OUTLINED: IconData + NOTE_ROUNDED: IconData + NOTE_SHARP: IconData + NOTES: IconData + NOTES_OUTLINED: IconData + NOTES_ROUNDED: IconData + NOTES_SHARP: IconData + NOTIFICATION_ADD: IconData + NOTIFICATION_ADD_OUTLINED: IconData + NOTIFICATION_ADD_ROUNDED: IconData + NOTIFICATION_ADD_SHARP: IconData + NOTIFICATION_IMPORTANT: IconData + NOTIFICATION_IMPORTANT_OUTLINED: IconData + NOTIFICATION_IMPORTANT_ROUNDED: IconData + NOTIFICATION_IMPORTANT_SHARP: IconData + NOTIFICATIONS: IconData + NOTIFICATIONS_ACTIVE: IconData + NOTIFICATIONS_ACTIVE_OUTLINED: IconData + NOTIFICATIONS_ACTIVE_ROUNDED: IconData + NOTIFICATIONS_ACTIVE_SHARP: IconData + NOTIFICATIONS_NONE: IconData + NOTIFICATIONS_NONE_OUTLINED: IconData + NOTIFICATIONS_NONE_ROUNDED: IconData + NOTIFICATIONS_NONE_SHARP: IconData + NOTIFICATIONS_OFF: IconData + NOTIFICATIONS_OFF_OUTLINED: IconData + NOTIFICATIONS_OFF_ROUNDED: IconData + NOTIFICATIONS_OFF_SHARP: IconData + NOTIFICATIONS_ON: IconData + NOTIFICATIONS_ON_OUTLINED: IconData + NOTIFICATIONS_ON_ROUNDED: IconData + NOTIFICATIONS_ON_SHARP: IconData + NOTIFICATIONS_OUTLINED: IconData + NOTIFICATIONS_PAUSED: IconData + NOTIFICATIONS_PAUSED_OUTLINED: IconData + NOTIFICATIONS_PAUSED_ROUNDED: IconData + NOTIFICATIONS_PAUSED_SHARP: IconData + NOTIFICATIONS_ROUNDED: IconData + NOTIFICATIONS_SHARP: IconData + NOW_WALLPAPER: IconData + NOW_WALLPAPER_OUTLINED: IconData + NOW_WALLPAPER_ROUNDED: IconData + NOW_WALLPAPER_SHARP: IconData + NOW_WIDGETS: IconData + NOW_WIDGETS_OUTLINED: IconData + NOW_WIDGETS_ROUNDED: IconData + NOW_WIDGETS_SHARP: IconData + NUMBERS: IconData + NUMBERS_OUTLINED: IconData + NUMBERS_ROUNDED: IconData + NUMBERS_SHARP: IconData + OFFLINE_BOLT: IconData + OFFLINE_BOLT_OUTLINED: IconData + OFFLINE_BOLT_ROUNDED: IconData + OFFLINE_BOLT_SHARP: IconData + OFFLINE_PIN: IconData + OFFLINE_PIN_OUTLINED: IconData + OFFLINE_PIN_ROUNDED: IconData + OFFLINE_PIN_SHARP: IconData + OFFLINE_SHARE: IconData + OFFLINE_SHARE_OUTLINED: IconData + OFFLINE_SHARE_ROUNDED: IconData + OFFLINE_SHARE_SHARP: IconData + OIL_BARREL: IconData + OIL_BARREL_OUTLINED: IconData + OIL_BARREL_ROUNDED: IconData + OIL_BARREL_SHARP: IconData + ON_DEVICE_TRAINING: IconData + ON_DEVICE_TRAINING_OUTLINED: IconData + ON_DEVICE_TRAINING_ROUNDED: IconData + ON_DEVICE_TRAINING_SHARP: IconData + ONDEMAND_VIDEO: IconData + ONDEMAND_VIDEO_OUTLINED: IconData + ONDEMAND_VIDEO_ROUNDED: IconData + ONDEMAND_VIDEO_SHARP: IconData + ONE_K: IconData + ONE_K_OUTLINED: IconData + ONE_K_PLUS: IconData + ONE_K_PLUS_OUTLINED: IconData + ONE_K_PLUS_ROUNDED: IconData + ONE_K_PLUS_SHARP: IconData + ONE_K_ROUNDED: IconData + ONE_K_SHARP: IconData + ONE_X_MOBILEDATA: IconData + ONE_X_MOBILEDATA_OUTLINED: IconData + ONE_X_MOBILEDATA_ROUNDED: IconData + ONE_X_MOBILEDATA_SHARP: IconData + ONETWOTHREE: IconData + ONETWOTHREE_OUTLINED: IconData + ONETWOTHREE_ROUNDED: IconData + ONETWOTHREE_SHARP: IconData + ONLINE_PREDICTION: IconData + ONLINE_PREDICTION_OUTLINED: IconData + ONLINE_PREDICTION_ROUNDED: IconData + ONLINE_PREDICTION_SHARP: IconData + OPACITY: IconData + OPACITY_OUTLINED: IconData + OPACITY_ROUNDED: IconData + OPACITY_SHARP: IconData + OPEN_IN_BROWSER: IconData + OPEN_IN_BROWSER_OUTLINED: IconData + OPEN_IN_BROWSER_ROUNDED: IconData + OPEN_IN_BROWSER_SHARP: IconData + OPEN_IN_FULL: IconData + OPEN_IN_FULL_OUTLINED: IconData + OPEN_IN_FULL_ROUNDED: IconData + OPEN_IN_FULL_SHARP: IconData + OPEN_IN_NEW: IconData + OPEN_IN_NEW_OFF: IconData + OPEN_IN_NEW_OFF_OUTLINED: IconData + OPEN_IN_NEW_OFF_ROUNDED: IconData + OPEN_IN_NEW_OFF_SHARP: IconData + OPEN_IN_NEW_OUTLINED: IconData + OPEN_IN_NEW_ROUNDED: IconData + OPEN_IN_NEW_SHARP: IconData + OPEN_WITH: IconData + OPEN_WITH_OUTLINED: IconData + OPEN_WITH_ROUNDED: IconData + OPEN_WITH_SHARP: IconData + OTHER_HOUSES: IconData + OTHER_HOUSES_OUTLINED: IconData + OTHER_HOUSES_ROUNDED: IconData + OTHER_HOUSES_SHARP: IconData + OUTBOND: IconData + OUTBOND_OUTLINED: IconData + OUTBOND_ROUNDED: IconData + OUTBOND_SHARP: IconData + OUTBOUND: IconData + OUTBOUND_OUTLINED: IconData + OUTBOUND_ROUNDED: IconData + OUTBOUND_SHARP: IconData + OUTBOX: IconData + OUTBOX_OUTLINED: IconData + OUTBOX_ROUNDED: IconData + OUTBOX_SHARP: IconData + OUTDOOR_GRILL: IconData + OUTDOOR_GRILL_OUTLINED: IconData + OUTDOOR_GRILL_ROUNDED: IconData + OUTDOOR_GRILL_SHARP: IconData + OUTGOING_MAIL: IconData + OUTLET: IconData + OUTLET_OUTLINED: IconData + OUTLET_ROUNDED: IconData + OUTLET_SHARP: IconData + OUTLINED_FLAG: IconData + OUTLINED_FLAG_OUTLINED: IconData + OUTLINED_FLAG_ROUNDED: IconData + OUTLINED_FLAG_SHARP: IconData + OUTPUT: IconData + OUTPUT_OUTLINED: IconData + OUTPUT_ROUNDED: IconData + OUTPUT_SHARP: IconData + PADDING: IconData + PADDING_OUTLINED: IconData + PADDING_ROUNDED: IconData + PADDING_SHARP: IconData + PAGES: IconData + PAGES_OUTLINED: IconData + PAGES_ROUNDED: IconData + PAGES_SHARP: IconData + PAGEVIEW: IconData + PAGEVIEW_OUTLINED: IconData + PAGEVIEW_ROUNDED: IconData + PAGEVIEW_SHARP: IconData + PAID: IconData + PAID_OUTLINED: IconData + PAID_ROUNDED: IconData + PAID_SHARP: IconData + PALETTE: IconData + PALETTE_OUTLINED: IconData + PALETTE_ROUNDED: IconData + PALETTE_SHARP: IconData + PALLET: IconData + PAN_TOOL: IconData + PAN_TOOL_ALT: IconData + PAN_TOOL_ALT_OUTLINED: IconData + PAN_TOOL_ALT_ROUNDED: IconData + PAN_TOOL_ALT_SHARP: IconData + PAN_TOOL_OUTLINED: IconData + PAN_TOOL_ROUNDED: IconData + PAN_TOOL_SHARP: IconData + PANORAMA: IconData + PANORAMA_FISH_EYE: IconData + PANORAMA_FISH_EYE_OUTLINED: IconData + PANORAMA_FISH_EYE_ROUNDED: IconData + PANORAMA_FISH_EYE_SHARP: IconData + PANORAMA_FISHEYE: IconData + PANORAMA_FISHEYE_OUTLINED: IconData + PANORAMA_FISHEYE_ROUNDED: IconData + PANORAMA_FISHEYE_SHARP: IconData + PANORAMA_HORIZONTAL: IconData + PANORAMA_HORIZONTAL_OUTLINED: IconData + PANORAMA_HORIZONTAL_ROUNDED: IconData + PANORAMA_HORIZONTAL_SELECT: IconData + PANORAMA_HORIZONTAL_SELECT_OUTLINED: IconData + PANORAMA_HORIZONTAL_SELECT_ROUNDED: IconData + PANORAMA_HORIZONTAL_SELECT_SHARP: IconData + PANORAMA_HORIZONTAL_SHARP: IconData + PANORAMA_OUTLINED: IconData + PANORAMA_PHOTOSPHERE: IconData + PANORAMA_PHOTOSPHERE_OUTLINED: IconData + PANORAMA_PHOTOSPHERE_ROUNDED: IconData + PANORAMA_PHOTOSPHERE_SELECT: IconData + PANORAMA_PHOTOSPHERE_SELECT_OUTLINED: IconData + PANORAMA_PHOTOSPHERE_SELECT_ROUNDED: IconData + PANORAMA_PHOTOSPHERE_SELECT_SHARP: IconData + PANORAMA_PHOTOSPHERE_SHARP: IconData + PANORAMA_ROUNDED: IconData + PANORAMA_SHARP: IconData + PANORAMA_VERTICAL: IconData + PANORAMA_VERTICAL_OUTLINED: IconData + PANORAMA_VERTICAL_ROUNDED: IconData + PANORAMA_VERTICAL_SELECT: IconData + PANORAMA_VERTICAL_SELECT_OUTLINED: IconData + PANORAMA_VERTICAL_SELECT_ROUNDED: IconData + PANORAMA_VERTICAL_SELECT_SHARP: IconData + PANORAMA_VERTICAL_SHARP: IconData + PANORAMA_WIDE_ANGLE: IconData + PANORAMA_WIDE_ANGLE_OUTLINED: IconData + PANORAMA_WIDE_ANGLE_ROUNDED: IconData + PANORAMA_WIDE_ANGLE_SELECT: IconData + PANORAMA_WIDE_ANGLE_SELECT_OUTLINED: IconData + PANORAMA_WIDE_ANGLE_SELECT_ROUNDED: IconData + PANORAMA_WIDE_ANGLE_SELECT_SHARP: IconData + PANORAMA_WIDE_ANGLE_SHARP: IconData + PARAGLIDING: IconData + PARAGLIDING_OUTLINED: IconData + PARAGLIDING_ROUNDED: IconData + PARAGLIDING_SHARP: IconData + PARK: IconData + PARK_OUTLINED: IconData + PARK_ROUNDED: IconData + PARK_SHARP: IconData + PARTY_MODE: IconData + PARTY_MODE_OUTLINED: IconData + PARTY_MODE_ROUNDED: IconData + PARTY_MODE_SHARP: IconData + PASSWORD: IconData + PASSWORD_OUTLINED: IconData + PASSWORD_ROUNDED: IconData + PASSWORD_SHARP: IconData + PASTE: IconData + PASTE_OUTLINED: IconData + PASTE_ROUNDED: IconData + PASTE_SHARP: IconData + PATTERN: IconData + PATTERN_OUTLINED: IconData + PATTERN_ROUNDED: IconData + PATTERN_SHARP: IconData + PAUSE: IconData + PAUSE_CIRCLE: IconData + PAUSE_CIRCLE_FILLED: IconData + PAUSE_CIRCLE_FILLED_OUTLINED: IconData + PAUSE_CIRCLE_FILLED_ROUNDED: IconData + PAUSE_CIRCLE_FILLED_SHARP: IconData + PAUSE_CIRCLE_OUTLINE: IconData + PAUSE_CIRCLE_OUTLINE_OUTLINED: IconData + PAUSE_CIRCLE_OUTLINE_ROUNDED: IconData + PAUSE_CIRCLE_OUTLINE_SHARP: IconData + PAUSE_CIRCLE_OUTLINED: IconData + PAUSE_CIRCLE_ROUNDED: IconData + PAUSE_CIRCLE_SHARP: IconData + PAUSE_OUTLINED: IconData + PAUSE_PRESENTATION: IconData + PAUSE_PRESENTATION_OUTLINED: IconData + PAUSE_PRESENTATION_ROUNDED: IconData + PAUSE_PRESENTATION_SHARP: IconData + PAUSE_ROUNDED: IconData + PAUSE_SHARP: IconData + PAYMENT: IconData + PAYMENT_OUTLINED: IconData + PAYMENT_ROUNDED: IconData + PAYMENT_SHARP: IconData + PAYMENTS: IconData + PAYMENTS_OUTLINED: IconData + PAYMENTS_ROUNDED: IconData + PAYMENTS_SHARP: IconData + PAYPAL: IconData + PAYPAL_OUTLINED: IconData + PAYPAL_ROUNDED: IconData + PAYPAL_SHARP: IconData + PEDAL_BIKE: IconData + PEDAL_BIKE_OUTLINED: IconData + PEDAL_BIKE_ROUNDED: IconData + PEDAL_BIKE_SHARP: IconData + PENDING: IconData + PENDING_ACTIONS: IconData + PENDING_ACTIONS_OUTLINED: IconData + PENDING_ACTIONS_ROUNDED: IconData + PENDING_ACTIONS_SHARP: IconData + PENDING_OUTLINED: IconData + PENDING_ROUNDED: IconData + PENDING_SHARP: IconData + PENTAGON: IconData + PENTAGON_OUTLINED: IconData + PENTAGON_ROUNDED: IconData + PENTAGON_SHARP: IconData + PEOPLE: IconData + PEOPLE_ALT: IconData + PEOPLE_ALT_OUTLINED: IconData + PEOPLE_ALT_ROUNDED: IconData + PEOPLE_ALT_SHARP: IconData + PEOPLE_OUTLINE: IconData + PEOPLE_OUTLINE_OUTLINED: IconData + PEOPLE_OUTLINE_ROUNDED: IconData + PEOPLE_OUTLINE_SHARP: IconData + PEOPLE_OUTLINED: IconData + PEOPLE_ROUNDED: IconData + PEOPLE_SHARP: IconData + PERCENT: IconData + PERCENT_OUTLINED: IconData + PERCENT_ROUNDED: IconData + PERCENT_SHARP: IconData + PERM_CAMERA_MIC: IconData + PERM_CAMERA_MIC_OUTLINED: IconData + PERM_CAMERA_MIC_ROUNDED: IconData + PERM_CAMERA_MIC_SHARP: IconData + PERM_CONTACT_CAL: IconData + PERM_CONTACT_CAL_OUTLINED: IconData + PERM_CONTACT_CAL_ROUNDED: IconData + PERM_CONTACT_CAL_SHARP: IconData + PERM_CONTACT_CALENDAR: IconData + PERM_CONTACT_CALENDAR_OUTLINED: IconData + PERM_CONTACT_CALENDAR_ROUNDED: IconData + PERM_CONTACT_CALENDAR_SHARP: IconData + PERM_DATA_SETTING: IconData + PERM_DATA_SETTING_OUTLINED: IconData + PERM_DATA_SETTING_ROUNDED: IconData + PERM_DATA_SETTING_SHARP: IconData + PERM_DEVICE_INFO: IconData + PERM_DEVICE_INFO_OUTLINED: IconData + PERM_DEVICE_INFO_ROUNDED: IconData + PERM_DEVICE_INFO_SHARP: IconData + PERM_DEVICE_INFORMATION: IconData + PERM_DEVICE_INFORMATION_OUTLINED: IconData + PERM_DEVICE_INFORMATION_ROUNDED: IconData + PERM_DEVICE_INFORMATION_SHARP: IconData + PERM_IDENTITY: IconData + PERM_IDENTITY_OUTLINED: IconData + PERM_IDENTITY_ROUNDED: IconData + PERM_IDENTITY_SHARP: IconData + PERM_MEDIA: IconData + PERM_MEDIA_OUTLINED: IconData + PERM_MEDIA_ROUNDED: IconData + PERM_MEDIA_SHARP: IconData + PERM_PHONE_MSG: IconData + PERM_PHONE_MSG_OUTLINED: IconData + PERM_PHONE_MSG_ROUNDED: IconData + PERM_PHONE_MSG_SHARP: IconData + PERM_SCAN_WIFI: IconData + PERM_SCAN_WIFI_OUTLINED: IconData + PERM_SCAN_WIFI_ROUNDED: IconData + PERM_SCAN_WIFI_SHARP: IconData + PERSON: IconData + PERSON_2: IconData + PERSON_2_OUTLINED: IconData + PERSON_2_ROUNDED: IconData + PERSON_2_SHARP: IconData + PERSON_3: IconData + PERSON_3_OUTLINED: IconData + PERSON_3_ROUNDED: IconData + PERSON_3_SHARP: IconData + PERSON_4: IconData + PERSON_4_OUTLINED: IconData + PERSON_4_ROUNDED: IconData + PERSON_4_SHARP: IconData + PERSON_ADD: IconData + PERSON_ADD_ALT: IconData + PERSON_ADD_ALT_1: IconData + PERSON_ADD_ALT_1_OUTLINED: IconData + PERSON_ADD_ALT_1_ROUNDED: IconData + PERSON_ADD_ALT_1_SHARP: IconData + PERSON_ADD_ALT_OUTLINED: IconData + PERSON_ADD_ALT_ROUNDED: IconData + PERSON_ADD_ALT_SHARP: IconData + PERSON_ADD_DISABLED: IconData + PERSON_ADD_DISABLED_OUTLINED: IconData + PERSON_ADD_DISABLED_ROUNDED: IconData + PERSON_ADD_DISABLED_SHARP: IconData + PERSON_ADD_OUTLINED: IconData + PERSON_ADD_ROUNDED: IconData + PERSON_ADD_SHARP: IconData + PERSON_OFF: IconData + PERSON_OFF_OUTLINED: IconData + PERSON_OFF_ROUNDED: IconData + PERSON_OFF_SHARP: IconData + PERSON_OUTLINE: IconData + PERSON_OUTLINE_OUTLINED: IconData + PERSON_OUTLINE_ROUNDED: IconData + PERSON_OUTLINE_SHARP: IconData + PERSON_OUTLINED: IconData + PERSON_PIN: IconData + PERSON_PIN_CIRCLE: IconData + PERSON_PIN_CIRCLE_OUTLINED: IconData + PERSON_PIN_CIRCLE_ROUNDED: IconData + PERSON_PIN_CIRCLE_SHARP: IconData + PERSON_PIN_OUTLINED: IconData + PERSON_PIN_ROUNDED: IconData + PERSON_PIN_SHARP: IconData + PERSON_REMOVE: IconData + PERSON_REMOVE_ALT_1: IconData + PERSON_REMOVE_ALT_1_OUTLINED: IconData + PERSON_REMOVE_ALT_1_ROUNDED: IconData + PERSON_REMOVE_ALT_1_SHARP: IconData + PERSON_REMOVE_OUTLINED: IconData + PERSON_REMOVE_ROUNDED: IconData + PERSON_REMOVE_SHARP: IconData + PERSON_ROUNDED: IconData + PERSON_SEARCH: IconData + PERSON_SEARCH_OUTLINED: IconData + PERSON_SEARCH_ROUNDED: IconData + PERSON_SEARCH_SHARP: IconData + PERSON_SHARP: IconData + PERSONAL_INJURY: IconData + PERSONAL_INJURY_OUTLINED: IconData + PERSONAL_INJURY_ROUNDED: IconData + PERSONAL_INJURY_SHARP: IconData + PERSONAL_VIDEO: IconData + PERSONAL_VIDEO_OUTLINED: IconData + PERSONAL_VIDEO_ROUNDED: IconData + PERSONAL_VIDEO_SHARP: IconData + PEST_CONTROL: IconData + PEST_CONTROL_OUTLINED: IconData + PEST_CONTROL_RODENT: IconData + PEST_CONTROL_RODENT_OUTLINED: IconData + PEST_CONTROL_RODENT_ROUNDED: IconData + PEST_CONTROL_RODENT_SHARP: IconData + PEST_CONTROL_ROUNDED: IconData + PEST_CONTROL_SHARP: IconData + PETS: IconData + PETS_OUTLINED: IconData + PETS_ROUNDED: IconData + PETS_SHARP: IconData + PHISHING: IconData + PHISHING_OUTLINED: IconData + PHISHING_ROUNDED: IconData + PHISHING_SHARP: IconData + PHONE: IconData + PHONE_ANDROID: IconData + PHONE_ANDROID_OUTLINED: IconData + PHONE_ANDROID_ROUNDED: IconData + PHONE_ANDROID_SHARP: IconData + PHONE_BLUETOOTH_SPEAKER: IconData + PHONE_BLUETOOTH_SPEAKER_OUTLINED: IconData + PHONE_BLUETOOTH_SPEAKER_ROUNDED: IconData + PHONE_BLUETOOTH_SPEAKER_SHARP: IconData + PHONE_CALLBACK: IconData + PHONE_CALLBACK_OUTLINED: IconData + PHONE_CALLBACK_ROUNDED: IconData + PHONE_CALLBACK_SHARP: IconData + PHONE_DISABLED: IconData + PHONE_DISABLED_OUTLINED: IconData + PHONE_DISABLED_ROUNDED: IconData + PHONE_DISABLED_SHARP: IconData + PHONE_ENABLED: IconData + PHONE_ENABLED_OUTLINED: IconData + PHONE_ENABLED_ROUNDED: IconData + PHONE_ENABLED_SHARP: IconData + PHONE_FORWARDED: IconData + PHONE_FORWARDED_OUTLINED: IconData + PHONE_FORWARDED_ROUNDED: IconData + PHONE_FORWARDED_SHARP: IconData + PHONE_IN_TALK: IconData + PHONE_IN_TALK_OUTLINED: IconData + PHONE_IN_TALK_ROUNDED: IconData + PHONE_IN_TALK_SHARP: IconData + PHONE_IPHONE: IconData + PHONE_IPHONE_OUTLINED: IconData + PHONE_IPHONE_ROUNDED: IconData + PHONE_IPHONE_SHARP: IconData + PHONE_LOCKED: IconData + PHONE_LOCKED_OUTLINED: IconData + PHONE_LOCKED_ROUNDED: IconData + PHONE_LOCKED_SHARP: IconData + PHONE_MISSED: IconData + PHONE_MISSED_OUTLINED: IconData + PHONE_MISSED_ROUNDED: IconData + PHONE_MISSED_SHARP: IconData + PHONE_OUTLINED: IconData + PHONE_PAUSED: IconData + PHONE_PAUSED_OUTLINED: IconData + PHONE_PAUSED_ROUNDED: IconData + PHONE_PAUSED_SHARP: IconData + PHONE_ROUNDED: IconData + PHONE_SHARP: IconData + PHONELINK: IconData + PHONELINK_ERASE: IconData + PHONELINK_ERASE_OUTLINED: IconData + PHONELINK_ERASE_ROUNDED: IconData + PHONELINK_ERASE_SHARP: IconData + PHONELINK_LOCK: IconData + PHONELINK_LOCK_OUTLINED: IconData + PHONELINK_LOCK_ROUNDED: IconData + PHONELINK_LOCK_SHARP: IconData + PHONELINK_OFF: IconData + PHONELINK_OFF_OUTLINED: IconData + PHONELINK_OFF_ROUNDED: IconData + PHONELINK_OFF_SHARP: IconData + PHONELINK_OUTLINED: IconData + PHONELINK_RING: IconData + PHONELINK_RING_OUTLINED: IconData + PHONELINK_RING_ROUNDED: IconData + PHONELINK_RING_SHARP: IconData + PHONELINK_ROUNDED: IconData + PHONELINK_SETUP: IconData + PHONELINK_SETUP_OUTLINED: IconData + PHONELINK_SETUP_ROUNDED: IconData + PHONELINK_SETUP_SHARP: IconData + PHONELINK_SHARP: IconData + PHOTO: IconData + PHOTO_ALBUM: IconData + PHOTO_ALBUM_OUTLINED: IconData + PHOTO_ALBUM_ROUNDED: IconData + PHOTO_ALBUM_SHARP: IconData + PHOTO_CAMERA: IconData + PHOTO_CAMERA_BACK: IconData + PHOTO_CAMERA_BACK_OUTLINED: IconData + PHOTO_CAMERA_BACK_ROUNDED: IconData + PHOTO_CAMERA_BACK_SHARP: IconData + PHOTO_CAMERA_FRONT: IconData + PHOTO_CAMERA_FRONT_OUTLINED: IconData + PHOTO_CAMERA_FRONT_ROUNDED: IconData + PHOTO_CAMERA_FRONT_SHARP: IconData + PHOTO_CAMERA_OUTLINED: IconData + PHOTO_CAMERA_ROUNDED: IconData + PHOTO_CAMERA_SHARP: IconData + PHOTO_FILTER: IconData + PHOTO_FILTER_OUTLINED: IconData + PHOTO_FILTER_ROUNDED: IconData + PHOTO_FILTER_SHARP: IconData + PHOTO_LIBRARY: IconData + PHOTO_LIBRARY_OUTLINED: IconData + PHOTO_LIBRARY_ROUNDED: IconData + PHOTO_LIBRARY_SHARP: IconData + PHOTO_OUTLINED: IconData + PHOTO_ROUNDED: IconData + PHOTO_SHARP: IconData + PHOTO_SIZE_SELECT_ACTUAL: IconData + PHOTO_SIZE_SELECT_ACTUAL_OUTLINED: IconData + PHOTO_SIZE_SELECT_ACTUAL_ROUNDED: IconData + PHOTO_SIZE_SELECT_ACTUAL_SHARP: IconData + PHOTO_SIZE_SELECT_LARGE: IconData + PHOTO_SIZE_SELECT_LARGE_OUTLINED: IconData + PHOTO_SIZE_SELECT_LARGE_ROUNDED: IconData + PHOTO_SIZE_SELECT_LARGE_SHARP: IconData + PHOTO_SIZE_SELECT_SMALL: IconData + PHOTO_SIZE_SELECT_SMALL_OUTLINED: IconData + PHOTO_SIZE_SELECT_SMALL_ROUNDED: IconData + PHOTO_SIZE_SELECT_SMALL_SHARP: IconData + PHP: IconData + PHP_OUTLINED: IconData + PHP_ROUNDED: IconData + PHP_SHARP: IconData + PIANO: IconData + PIANO_OFF: IconData + PIANO_OFF_OUTLINED: IconData + PIANO_OFF_ROUNDED: IconData + PIANO_OFF_SHARP: IconData + PIANO_OUTLINED: IconData + PIANO_ROUNDED: IconData + PIANO_SHARP: IconData + PICTURE_AS_PDF: IconData + PICTURE_AS_PDF_OUTLINED: IconData + PICTURE_AS_PDF_ROUNDED: IconData + PICTURE_AS_PDF_SHARP: IconData + PICTURE_IN_PICTURE: IconData + PICTURE_IN_PICTURE_ALT: IconData + PICTURE_IN_PICTURE_ALT_OUTLINED: IconData + PICTURE_IN_PICTURE_ALT_ROUNDED: IconData + PICTURE_IN_PICTURE_ALT_SHARP: IconData + PICTURE_IN_PICTURE_OUTLINED: IconData + PICTURE_IN_PICTURE_ROUNDED: IconData + PICTURE_IN_PICTURE_SHARP: IconData + PIE_CHART: IconData + PIE_CHART_OUTLINE: IconData + PIE_CHART_OUTLINE_OUTLINED: IconData + PIE_CHART_OUTLINE_ROUNDED: IconData + PIE_CHART_OUTLINE_SHARP: IconData + PIE_CHART_ROUNDED: IconData + PIE_CHART_SHARP: IconData + PIN: IconData + PIN_DROP: IconData + PIN_DROP_OUTLINED: IconData + PIN_DROP_ROUNDED: IconData + PIN_DROP_SHARP: IconData + PIN_END: IconData + PIN_END_OUTLINED: IconData + PIN_END_ROUNDED: IconData + PIN_END_SHARP: IconData + PIN_INVOKE: IconData + PIN_INVOKE_OUTLINED: IconData + PIN_INVOKE_ROUNDED: IconData + PIN_INVOKE_SHARP: IconData + PIN_OUTLINED: IconData + PIN_ROUNDED: IconData + PIN_SHARP: IconData + PINCH: IconData + PINCH_OUTLINED: IconData + PINCH_ROUNDED: IconData + PINCH_SHARP: IconData + PIVOT_TABLE_CHART: IconData + PIVOT_TABLE_CHART_OUTLINED: IconData + PIVOT_TABLE_CHART_ROUNDED: IconData + PIVOT_TABLE_CHART_SHARP: IconData + PIX: IconData + PIX_OUTLINED: IconData + PIX_ROUNDED: IconData + PIX_SHARP: IconData + PLACE: IconData + PLACE_OUTLINED: IconData + PLACE_ROUNDED: IconData + PLACE_SHARP: IconData + PLAGIARISM: IconData + PLAGIARISM_OUTLINED: IconData + PLAGIARISM_ROUNDED: IconData + PLAGIARISM_SHARP: IconData + PLAY_ARROW: IconData + PLAY_ARROW_OUTLINED: IconData + PLAY_ARROW_ROUNDED: IconData + PLAY_ARROW_SHARP: IconData + PLAY_CIRCLE: IconData + PLAY_CIRCLE_FILL: IconData + PLAY_CIRCLE_FILL_OUTLINED: IconData + PLAY_CIRCLE_FILL_ROUNDED: IconData + PLAY_CIRCLE_FILL_SHARP: IconData + PLAY_CIRCLE_FILLED: IconData + PLAY_CIRCLE_FILLED_OUTLINED: IconData + PLAY_CIRCLE_FILLED_ROUNDED: IconData + PLAY_CIRCLE_FILLED_SHARP: IconData + PLAY_CIRCLE_OUTLINE: IconData + PLAY_CIRCLE_OUTLINE_OUTLINED: IconData + PLAY_CIRCLE_OUTLINE_ROUNDED: IconData + PLAY_CIRCLE_OUTLINE_SHARP: IconData + PLAY_CIRCLE_OUTLINED: IconData + PLAY_CIRCLE_ROUNDED: IconData + PLAY_CIRCLE_SHARP: IconData + PLAY_DISABLED: IconData + PLAY_DISABLED_OUTLINED: IconData + PLAY_DISABLED_ROUNDED: IconData + PLAY_DISABLED_SHARP: IconData + PLAY_FOR_WORK: IconData + PLAY_FOR_WORK_OUTLINED: IconData + PLAY_FOR_WORK_ROUNDED: IconData + PLAY_FOR_WORK_SHARP: IconData + PLAY_LESSON: IconData + PLAY_LESSON_OUTLINED: IconData + PLAY_LESSON_ROUNDED: IconData + PLAY_LESSON_SHARP: IconData + PLAYLIST_ADD: IconData + PLAYLIST_ADD_CHECK: IconData + PLAYLIST_ADD_CHECK_CIRCLE: IconData + PLAYLIST_ADD_CHECK_CIRCLE_OUTLINED: IconData + PLAYLIST_ADD_CHECK_CIRCLE_ROUNDED: IconData + PLAYLIST_ADD_CHECK_CIRCLE_SHARP: IconData + PLAYLIST_ADD_CHECK_OUTLINED: IconData + PLAYLIST_ADD_CHECK_ROUNDED: IconData + PLAYLIST_ADD_CHECK_SHARP: IconData + PLAYLIST_ADD_CIRCLE: IconData + PLAYLIST_ADD_CIRCLE_OUTLINED: IconData + PLAYLIST_ADD_CIRCLE_ROUNDED: IconData + PLAYLIST_ADD_CIRCLE_SHARP: IconData + PLAYLIST_ADD_OUTLINED: IconData + PLAYLIST_ADD_ROUNDED: IconData + PLAYLIST_ADD_SHARP: IconData + PLAYLIST_PLAY: IconData + PLAYLIST_PLAY_OUTLINED: IconData + PLAYLIST_PLAY_ROUNDED: IconData + PLAYLIST_PLAY_SHARP: IconData + PLAYLIST_REMOVE: IconData + PLAYLIST_REMOVE_OUTLINED: IconData + PLAYLIST_REMOVE_ROUNDED: IconData + PLAYLIST_REMOVE_SHARP: IconData + PLUMBING: IconData + PLUMBING_OUTLINED: IconData + PLUMBING_ROUNDED: IconData + PLUMBING_SHARP: IconData + PLUS_ONE: IconData + PLUS_ONE_OUTLINED: IconData + PLUS_ONE_ROUNDED: IconData + PLUS_ONE_SHARP: IconData + PODCASTS: IconData + PODCASTS_OUTLINED: IconData + PODCASTS_ROUNDED: IconData + PODCASTS_SHARP: IconData + POINT_OF_SALE: IconData + POINT_OF_SALE_OUTLINED: IconData + POINT_OF_SALE_ROUNDED: IconData + POINT_OF_SALE_SHARP: IconData + POLICY: IconData + POLICY_OUTLINED: IconData + POLICY_ROUNDED: IconData + POLICY_SHARP: IconData + POLL: IconData + POLL_OUTLINED: IconData + POLL_ROUNDED: IconData + POLL_SHARP: IconData + POLYLINE: IconData + POLYLINE_OUTLINED: IconData + POLYLINE_ROUNDED: IconData + POLYLINE_SHARP: IconData + POLYMER: IconData + POLYMER_OUTLINED: IconData + POLYMER_ROUNDED: IconData + POLYMER_SHARP: IconData + POOL: IconData + POOL_OUTLINED: IconData + POOL_ROUNDED: IconData + POOL_SHARP: IconData + PORTABLE_WIFI_OFF: IconData + PORTABLE_WIFI_OFF_OUTLINED: IconData + PORTABLE_WIFI_OFF_ROUNDED: IconData + PORTABLE_WIFI_OFF_SHARP: IconData + PORTRAIT: IconData + PORTRAIT_OUTLINED: IconData + PORTRAIT_ROUNDED: IconData + PORTRAIT_SHARP: IconData + POST_ADD: IconData + POST_ADD_OUTLINED: IconData + POST_ADD_ROUNDED: IconData + POST_ADD_SHARP: IconData + POWER: IconData + POWER_INPUT: IconData + POWER_INPUT_OUTLINED: IconData + POWER_INPUT_ROUNDED: IconData + POWER_INPUT_SHARP: IconData + POWER_OFF: IconData + POWER_OFF_OUTLINED: IconData + POWER_OFF_ROUNDED: IconData + POWER_OFF_SHARP: IconData + POWER_OUTLINED: IconData + POWER_ROUNDED: IconData + POWER_SETTINGS_NEW: IconData + POWER_SETTINGS_NEW_OUTLINED: IconData + POWER_SETTINGS_NEW_ROUNDED: IconData + POWER_SETTINGS_NEW_SHARP: IconData + POWER_SHARP: IconData + PRECISION_MANUFACTURING: IconData + PRECISION_MANUFACTURING_OUTLINED: IconData + PRECISION_MANUFACTURING_ROUNDED: IconData + PRECISION_MANUFACTURING_SHARP: IconData + PREGNANT_WOMAN: IconData + PREGNANT_WOMAN_OUTLINED: IconData + PREGNANT_WOMAN_ROUNDED: IconData + PREGNANT_WOMAN_SHARP: IconData + PRESENT_TO_ALL: IconData + PRESENT_TO_ALL_OUTLINED: IconData + PRESENT_TO_ALL_ROUNDED: IconData + PRESENT_TO_ALL_SHARP: IconData + PREVIEW: IconData + PREVIEW_OUTLINED: IconData + PREVIEW_ROUNDED: IconData + PREVIEW_SHARP: IconData + PRICE_CHANGE: IconData + PRICE_CHANGE_OUTLINED: IconData + PRICE_CHANGE_ROUNDED: IconData + PRICE_CHANGE_SHARP: IconData + PRICE_CHECK: IconData + PRICE_CHECK_OUTLINED: IconData + PRICE_CHECK_ROUNDED: IconData + PRICE_CHECK_SHARP: IconData + PRINT: IconData + PRINT_DISABLED: IconData + PRINT_DISABLED_OUTLINED: IconData + PRINT_DISABLED_ROUNDED: IconData + PRINT_DISABLED_SHARP: IconData + PRINT_OUTLINED: IconData + PRINT_ROUNDED: IconData + PRINT_SHARP: IconData + PRIORITY_HIGH: IconData + PRIORITY_HIGH_OUTLINED: IconData + PRIORITY_HIGH_ROUNDED: IconData + PRIORITY_HIGH_SHARP: IconData + PRIVACY_TIP: IconData + PRIVACY_TIP_OUTLINED: IconData + PRIVACY_TIP_ROUNDED: IconData + PRIVACY_TIP_SHARP: IconData + PRIVATE_CONNECTIVITY: IconData + PRIVATE_CONNECTIVITY_OUTLINED: IconData + PRIVATE_CONNECTIVITY_ROUNDED: IconData + PRIVATE_CONNECTIVITY_SHARP: IconData + PRODUCTION_QUANTITY_LIMITS: IconData + PRODUCTION_QUANTITY_LIMITS_OUTLINED: IconData + PRODUCTION_QUANTITY_LIMITS_ROUNDED: IconData + PRODUCTION_QUANTITY_LIMITS_SHARP: IconData + PROPANE: IconData + PROPANE_OUTLINED: IconData + PROPANE_ROUNDED: IconData + PROPANE_SHARP: IconData + PROPANE_TANK: IconData + PROPANE_TANK_OUTLINED: IconData + PROPANE_TANK_ROUNDED: IconData + PROPANE_TANK_SHARP: IconData + PSYCHOLOGY: IconData + PSYCHOLOGY_ALT: IconData + PSYCHOLOGY_ALT_OUTLINED: IconData + PSYCHOLOGY_ALT_ROUNDED: IconData + PSYCHOLOGY_ALT_SHARP: IconData + PSYCHOLOGY_OUTLINED: IconData + PSYCHOLOGY_ROUNDED: IconData + PSYCHOLOGY_SHARP: IconData + PUBLIC: IconData + PUBLIC_OFF: IconData + PUBLIC_OFF_OUTLINED: IconData + PUBLIC_OFF_ROUNDED: IconData + PUBLIC_OFF_SHARP: IconData + PUBLIC_OUTLINED: IconData + PUBLIC_ROUNDED: IconData + PUBLIC_SHARP: IconData + PUBLISH: IconData + PUBLISH_OUTLINED: IconData + PUBLISH_ROUNDED: IconData + PUBLISH_SHARP: IconData + PUBLISHED_WITH_CHANGES: IconData + PUBLISHED_WITH_CHANGES_OUTLINED: IconData + PUBLISHED_WITH_CHANGES_ROUNDED: IconData + PUBLISHED_WITH_CHANGES_SHARP: IconData + PUNCH_CLOCK: IconData + PUNCH_CLOCK_OUTLINED: IconData + PUNCH_CLOCK_ROUNDED: IconData + PUNCH_CLOCK_SHARP: IconData + PUSH_PIN: IconData + PUSH_PIN_OUTLINED: IconData + PUSH_PIN_ROUNDED: IconData + PUSH_PIN_SHARP: IconData + QR_CODE: IconData + QR_CODE_2: IconData + QR_CODE_2_OUTLINED: IconData + QR_CODE_2_ROUNDED: IconData + QR_CODE_2_SHARP: IconData + QR_CODE_OUTLINED: IconData + QR_CODE_ROUNDED: IconData + QR_CODE_SCANNER: IconData + QR_CODE_SCANNER_OUTLINED: IconData + QR_CODE_SCANNER_ROUNDED: IconData + QR_CODE_SCANNER_SHARP: IconData + QR_CODE_SHARP: IconData + QUERY_BUILDER: IconData + QUERY_BUILDER_OUTLINED: IconData + QUERY_BUILDER_ROUNDED: IconData + QUERY_BUILDER_SHARP: IconData + QUERY_STATS: IconData + QUERY_STATS_OUTLINED: IconData + QUERY_STATS_ROUNDED: IconData + QUERY_STATS_SHARP: IconData + QUESTION_ANSWER: IconData + QUESTION_ANSWER_OUTLINED: IconData + QUESTION_ANSWER_ROUNDED: IconData + QUESTION_ANSWER_SHARP: IconData + QUESTION_MARK: IconData + QUESTION_MARK_OUTLINED: IconData + QUESTION_MARK_ROUNDED: IconData + QUESTION_MARK_SHARP: IconData + QUEUE: IconData + QUEUE_MUSIC: IconData + QUEUE_MUSIC_OUTLINED: IconData + QUEUE_MUSIC_ROUNDED: IconData + QUEUE_MUSIC_SHARP: IconData + QUEUE_OUTLINED: IconData + QUEUE_PLAY_NEXT: IconData + QUEUE_PLAY_NEXT_OUTLINED: IconData + QUEUE_PLAY_NEXT_ROUNDED: IconData + QUEUE_PLAY_NEXT_SHARP: IconData + QUEUE_ROUNDED: IconData + QUEUE_SHARP: IconData + QUICK_CONTACTS_DIALER: IconData + QUICK_CONTACTS_DIALER_OUTLINED: IconData + QUICK_CONTACTS_DIALER_ROUNDED: IconData + QUICK_CONTACTS_DIALER_SHARP: IconData + QUICK_CONTACTS_MAIL: IconData + QUICK_CONTACTS_MAIL_OUTLINED: IconData + QUICK_CONTACTS_MAIL_ROUNDED: IconData + QUICK_CONTACTS_MAIL_SHARP: IconData + QUICKREPLY: IconData + QUICKREPLY_OUTLINED: IconData + QUICKREPLY_ROUNDED: IconData + QUICKREPLY_SHARP: IconData + QUIZ: IconData + QUIZ_OUTLINED: IconData + QUIZ_ROUNDED: IconData + QUIZ_SHARP: IconData + QUORA: IconData + QUORA_OUTLINED: IconData + QUORA_ROUNDED: IconData + QUORA_SHARP: IconData + R_MOBILEDATA: IconData + R_MOBILEDATA_OUTLINED: IconData + R_MOBILEDATA_ROUNDED: IconData + R_MOBILEDATA_SHARP: IconData + RADAR: IconData + RADAR_OUTLINED: IconData + RADAR_ROUNDED: IconData + RADAR_SHARP: IconData + RADIO: IconData + RADIO_BUTTON_CHECKED: IconData + RADIO_BUTTON_CHECKED_OUTLINED: IconData + RADIO_BUTTON_CHECKED_ROUNDED: IconData + RADIO_BUTTON_CHECKED_SHARP: IconData + RADIO_BUTTON_OFF: IconData + RADIO_BUTTON_OFF_OUTLINED: IconData + RADIO_BUTTON_OFF_ROUNDED: IconData + RADIO_BUTTON_OFF_SHARP: IconData + RADIO_BUTTON_ON: IconData + RADIO_BUTTON_ON_OUTLINED: IconData + RADIO_BUTTON_ON_ROUNDED: IconData + RADIO_BUTTON_ON_SHARP: IconData + RADIO_BUTTON_UNCHECKED: IconData + RADIO_BUTTON_UNCHECKED_OUTLINED: IconData + RADIO_BUTTON_UNCHECKED_ROUNDED: IconData + RADIO_BUTTON_UNCHECKED_SHARP: IconData + RADIO_OUTLINED: IconData + RADIO_ROUNDED: IconData + RADIO_SHARP: IconData + RAILWAY_ALERT: IconData + RAILWAY_ALERT_OUTLINED: IconData + RAILWAY_ALERT_ROUNDED: IconData + RAILWAY_ALERT_SHARP: IconData + RAMEN_DINING: IconData + RAMEN_DINING_OUTLINED: IconData + RAMEN_DINING_ROUNDED: IconData + RAMEN_DINING_SHARP: IconData + RAMP_LEFT: IconData + RAMP_LEFT_OUTLINED: IconData + RAMP_LEFT_ROUNDED: IconData + RAMP_LEFT_SHARP: IconData + RAMP_RIGHT: IconData + RAMP_RIGHT_OUTLINED: IconData + RAMP_RIGHT_ROUNDED: IconData + RAMP_RIGHT_SHARP: IconData + RATE_REVIEW: IconData + RATE_REVIEW_OUTLINED: IconData + RATE_REVIEW_ROUNDED: IconData + RATE_REVIEW_SHARP: IconData + RAW_OFF: IconData + RAW_OFF_OUTLINED: IconData + RAW_OFF_ROUNDED: IconData + RAW_OFF_SHARP: IconData + RAW_ON: IconData + RAW_ON_OUTLINED: IconData + RAW_ON_ROUNDED: IconData + RAW_ON_SHARP: IconData + READ_MORE: IconData + READ_MORE_OUTLINED: IconData + READ_MORE_ROUNDED: IconData + READ_MORE_SHARP: IconData + REAL_ESTATE_AGENT: IconData + REAL_ESTATE_AGENT_OUTLINED: IconData + REAL_ESTATE_AGENT_ROUNDED: IconData + REAL_ESTATE_AGENT_SHARP: IconData + REBASE_EDIT: IconData + RECEIPT: IconData + RECEIPT_LONG: IconData + RECEIPT_LONG_OUTLINED: IconData + RECEIPT_LONG_ROUNDED: IconData + RECEIPT_LONG_SHARP: IconData + RECEIPT_OUTLINED: IconData + RECEIPT_ROUNDED: IconData + RECEIPT_SHARP: IconData + RECENT_ACTORS: IconData + RECENT_ACTORS_OUTLINED: IconData + RECENT_ACTORS_ROUNDED: IconData + RECENT_ACTORS_SHARP: IconData + RECOMMEND: IconData + RECOMMEND_OUTLINED: IconData + RECOMMEND_ROUNDED: IconData + RECOMMEND_SHARP: IconData + RECORD_VOICE_OVER: IconData + RECORD_VOICE_OVER_OUTLINED: IconData + RECORD_VOICE_OVER_ROUNDED: IconData + RECORD_VOICE_OVER_SHARP: IconData + RECTANGLE: IconData + RECTANGLE_OUTLINED: IconData + RECTANGLE_ROUNDED: IconData + RECTANGLE_SHARP: IconData + RECYCLING: IconData + RECYCLING_OUTLINED: IconData + RECYCLING_ROUNDED: IconData + RECYCLING_SHARP: IconData + REDDIT: IconData + REDDIT_OUTLINED: IconData + REDDIT_ROUNDED: IconData + REDDIT_SHARP: IconData + REDEEM: IconData + REDEEM_OUTLINED: IconData + REDEEM_ROUNDED: IconData + REDEEM_SHARP: IconData + REDO: IconData + REDO_OUTLINED: IconData + REDO_ROUNDED: IconData + REDO_SHARP: IconData + REDUCE_CAPACITY: IconData + REDUCE_CAPACITY_OUTLINED: IconData + REDUCE_CAPACITY_ROUNDED: IconData + REDUCE_CAPACITY_SHARP: IconData + REFRESH: IconData + REFRESH_OUTLINED: IconData + REFRESH_ROUNDED: IconData + REFRESH_SHARP: IconData + REMEMBER_ME: IconData + REMEMBER_ME_OUTLINED: IconData + REMEMBER_ME_ROUNDED: IconData + REMEMBER_ME_SHARP: IconData + REMOVE: IconData + REMOVE_CIRCLE: IconData + REMOVE_CIRCLE_OUTLINE: IconData + REMOVE_CIRCLE_OUTLINE_OUTLINED: IconData + REMOVE_CIRCLE_OUTLINE_ROUNDED: IconData + REMOVE_CIRCLE_OUTLINE_SHARP: IconData + REMOVE_CIRCLE_OUTLINED: IconData + REMOVE_CIRCLE_ROUNDED: IconData + REMOVE_CIRCLE_SHARP: IconData + REMOVE_DONE: IconData + REMOVE_DONE_OUTLINED: IconData + REMOVE_DONE_ROUNDED: IconData + REMOVE_DONE_SHARP: IconData + REMOVE_FROM_QUEUE: IconData + REMOVE_FROM_QUEUE_OUTLINED: IconData + REMOVE_FROM_QUEUE_ROUNDED: IconData + REMOVE_FROM_QUEUE_SHARP: IconData + REMOVE_MODERATOR: IconData + REMOVE_MODERATOR_OUTLINED: IconData + REMOVE_MODERATOR_ROUNDED: IconData + REMOVE_MODERATOR_SHARP: IconData + REMOVE_OUTLINED: IconData + REMOVE_RED_EYE: IconData + REMOVE_RED_EYE_OUTLINED: IconData + REMOVE_RED_EYE_ROUNDED: IconData + REMOVE_RED_EYE_SHARP: IconData + REMOVE_ROAD: IconData + REMOVE_ROAD_OUTLINED: IconData + REMOVE_ROAD_ROUNDED: IconData + REMOVE_ROAD_SHARP: IconData + REMOVE_ROUNDED: IconData + REMOVE_SHARP: IconData + REMOVE_SHOPPING_CART: IconData + REMOVE_SHOPPING_CART_OUTLINED: IconData + REMOVE_SHOPPING_CART_ROUNDED: IconData + REMOVE_SHOPPING_CART_SHARP: IconData + REORDER: IconData + REORDER_OUTLINED: IconData + REORDER_ROUNDED: IconData + REORDER_SHARP: IconData + REPARTITION: IconData + REPARTITION_OUTLINED: IconData + REPARTITION_ROUNDED: IconData + REPARTITION_SHARP: IconData + REPEAT: IconData + REPEAT_ON: IconData + REPEAT_ON_OUTLINED: IconData + REPEAT_ON_ROUNDED: IconData + REPEAT_ON_SHARP: IconData + REPEAT_ONE: IconData + REPEAT_ONE_ON: IconData + REPEAT_ONE_ON_OUTLINED: IconData + REPEAT_ONE_ON_ROUNDED: IconData + REPEAT_ONE_ON_SHARP: IconData + REPEAT_ONE_OUTLINED: IconData + REPEAT_ONE_ROUNDED: IconData + REPEAT_ONE_SHARP: IconData + REPEAT_OUTLINED: IconData + REPEAT_ROUNDED: IconData + REPEAT_SHARP: IconData + REPLAY: IconData + REPLAY_10: IconData + REPLAY_10_OUTLINED: IconData + REPLAY_10_ROUNDED: IconData + REPLAY_10_SHARP: IconData + REPLAY_30: IconData + REPLAY_30_OUTLINED: IconData + REPLAY_30_ROUNDED: IconData + REPLAY_30_SHARP: IconData + REPLAY_5: IconData + REPLAY_5_OUTLINED: IconData + REPLAY_5_ROUNDED: IconData + REPLAY_5_SHARP: IconData + REPLAY_CIRCLE_FILLED: IconData + REPLAY_CIRCLE_FILLED_OUTLINED: IconData + REPLAY_CIRCLE_FILLED_ROUNDED: IconData + REPLAY_CIRCLE_FILLED_SHARP: IconData + REPLAY_OUTLINED: IconData + REPLAY_ROUNDED: IconData + REPLAY_SHARP: IconData + REPLY: IconData + REPLY_ALL: IconData + REPLY_ALL_OUTLINED: IconData + REPLY_ALL_ROUNDED: IconData + REPLY_ALL_SHARP: IconData + REPLY_OUTLINED: IconData + REPLY_ROUNDED: IconData + REPLY_SHARP: IconData + REPORT: IconData + REPORT_GMAILERRORRED: IconData + REPORT_GMAILERRORRED_OUTLINED: IconData + REPORT_GMAILERRORRED_ROUNDED: IconData + REPORT_GMAILERRORRED_SHARP: IconData + REPORT_OFF: IconData + REPORT_OFF_OUTLINED: IconData + REPORT_OFF_ROUNDED: IconData + REPORT_OFF_SHARP: IconData + REPORT_OUTLINED: IconData + REPORT_PROBLEM: IconData + REPORT_PROBLEM_OUTLINED: IconData + REPORT_PROBLEM_ROUNDED: IconData + REPORT_PROBLEM_SHARP: IconData + REPORT_ROUNDED: IconData + REPORT_SHARP: IconData + REQUEST_PAGE: IconData + REQUEST_PAGE_OUTLINED: IconData + REQUEST_PAGE_ROUNDED: IconData + REQUEST_PAGE_SHARP: IconData + REQUEST_QUOTE: IconData + REQUEST_QUOTE_OUTLINED: IconData + REQUEST_QUOTE_ROUNDED: IconData + REQUEST_QUOTE_SHARP: IconData + RESET_TV: IconData + RESET_TV_OUTLINED: IconData + RESET_TV_ROUNDED: IconData + RESET_TV_SHARP: IconData + RESTART_ALT: IconData + RESTART_ALT_OUTLINED: IconData + RESTART_ALT_ROUNDED: IconData + RESTART_ALT_SHARP: IconData + RESTAURANT: IconData + RESTAURANT_MENU: IconData + RESTAURANT_MENU_OUTLINED: IconData + RESTAURANT_MENU_ROUNDED: IconData + RESTAURANT_MENU_SHARP: IconData + RESTAURANT_OUTLINED: IconData + RESTAURANT_ROUNDED: IconData + RESTAURANT_SHARP: IconData + RESTORE: IconData + RESTORE_FROM_TRASH: IconData + RESTORE_FROM_TRASH_OUTLINED: IconData + RESTORE_FROM_TRASH_ROUNDED: IconData + RESTORE_FROM_TRASH_SHARP: IconData + RESTORE_OUTLINED: IconData + RESTORE_PAGE: IconData + RESTORE_PAGE_OUTLINED: IconData + RESTORE_PAGE_ROUNDED: IconData + RESTORE_PAGE_SHARP: IconData + RESTORE_ROUNDED: IconData + RESTORE_SHARP: IconData + REVIEWS: IconData + REVIEWS_OUTLINED: IconData + REVIEWS_ROUNDED: IconData + REVIEWS_SHARP: IconData + RICE_BOWL: IconData + RICE_BOWL_OUTLINED: IconData + RICE_BOWL_ROUNDED: IconData + RICE_BOWL_SHARP: IconData + RING_VOLUME: IconData + RING_VOLUME_OUTLINED: IconData + RING_VOLUME_ROUNDED: IconData + RING_VOLUME_SHARP: IconData + ROCKET: IconData + ROCKET_LAUNCH: IconData + ROCKET_LAUNCH_OUTLINED: IconData + ROCKET_LAUNCH_ROUNDED: IconData + ROCKET_LAUNCH_SHARP: IconData + ROCKET_OUTLINED: IconData + ROCKET_ROUNDED: IconData + ROCKET_SHARP: IconData + ROLLER_SHADES: IconData + ROLLER_SHADES_CLOSED: IconData + ROLLER_SHADES_CLOSED_OUTLINED: IconData + ROLLER_SHADES_CLOSED_ROUNDED: IconData + ROLLER_SHADES_CLOSED_SHARP: IconData + ROLLER_SHADES_OUTLINED: IconData + ROLLER_SHADES_ROUNDED: IconData + ROLLER_SHADES_SHARP: IconData + ROLLER_SKATING: IconData + ROLLER_SKATING_OUTLINED: IconData + ROLLER_SKATING_ROUNDED: IconData + ROLLER_SKATING_SHARP: IconData + ROOFING: IconData + ROOFING_OUTLINED: IconData + ROOFING_ROUNDED: IconData + ROOFING_SHARP: IconData + ROOM: IconData + ROOM_OUTLINED: IconData + ROOM_PREFERENCES: IconData + ROOM_PREFERENCES_OUTLINED: IconData + ROOM_PREFERENCES_ROUNDED: IconData + ROOM_PREFERENCES_SHARP: IconData + ROOM_ROUNDED: IconData + ROOM_SERVICE: IconData + ROOM_SERVICE_OUTLINED: IconData + ROOM_SERVICE_ROUNDED: IconData + ROOM_SERVICE_SHARP: IconData + ROOM_SHARP: IconData + ROTATE_90_DEGREES_CCW: IconData + ROTATE_90_DEGREES_CCW_OUTLINED: IconData + ROTATE_90_DEGREES_CCW_ROUNDED: IconData + ROTATE_90_DEGREES_CCW_SHARP: IconData + ROTATE_90_DEGREES_CW: IconData + ROTATE_90_DEGREES_CW_OUTLINED: IconData + ROTATE_90_DEGREES_CW_ROUNDED: IconData + ROTATE_90_DEGREES_CW_SHARP: IconData + ROTATE_LEFT: IconData + ROTATE_LEFT_OUTLINED: IconData + ROTATE_LEFT_ROUNDED: IconData + ROTATE_LEFT_SHARP: IconData + ROTATE_RIGHT: IconData + ROTATE_RIGHT_OUTLINED: IconData + ROTATE_RIGHT_ROUNDED: IconData + ROTATE_RIGHT_SHARP: IconData + ROUNDABOUT_LEFT: IconData + ROUNDABOUT_LEFT_OUTLINED: IconData + ROUNDABOUT_LEFT_ROUNDED: IconData + ROUNDABOUT_LEFT_SHARP: IconData + ROUNDABOUT_RIGHT: IconData + ROUNDABOUT_RIGHT_OUTLINED: IconData + ROUNDABOUT_RIGHT_ROUNDED: IconData + ROUNDABOUT_RIGHT_SHARP: IconData + ROUNDED_CORNER: IconData + ROUNDED_CORNER_OUTLINED: IconData + ROUNDED_CORNER_ROUNDED: IconData + ROUNDED_CORNER_SHARP: IconData + ROUTE: IconData + ROUTE_OUTLINED: IconData + ROUTE_ROUNDED: IconData + ROUTE_SHARP: IconData + ROUTER: IconData + ROUTER_OUTLINED: IconData + ROUTER_ROUNDED: IconData + ROUTER_SHARP: IconData + ROWING: IconData + ROWING_OUTLINED: IconData + ROWING_ROUNDED: IconData + ROWING_SHARP: IconData + RSS_FEED: IconData + RSS_FEED_OUTLINED: IconData + RSS_FEED_ROUNDED: IconData + RSS_FEED_SHARP: IconData + RSVP: IconData + RSVP_OUTLINED: IconData + RSVP_ROUNDED: IconData + RSVP_SHARP: IconData + RTT: IconData + RTT_OUTLINED: IconData + RTT_ROUNDED: IconData + RTT_SHARP: IconData + RULE: IconData + RULE_FOLDER: IconData + RULE_FOLDER_OUTLINED: IconData + RULE_FOLDER_ROUNDED: IconData + RULE_FOLDER_SHARP: IconData + RULE_OUTLINED: IconData + RULE_ROUNDED: IconData + RULE_SHARP: IconData + RUN_CIRCLE: IconData + RUN_CIRCLE_OUTLINED: IconData + RUN_CIRCLE_ROUNDED: IconData + RUN_CIRCLE_SHARP: IconData + RUNNING_WITH_ERRORS: IconData + RUNNING_WITH_ERRORS_OUTLINED: IconData + RUNNING_WITH_ERRORS_ROUNDED: IconData + RUNNING_WITH_ERRORS_SHARP: IconData + RV_HOOKUP: IconData + RV_HOOKUP_OUTLINED: IconData + RV_HOOKUP_ROUNDED: IconData + RV_HOOKUP_SHARP: IconData + SAFETY_CHECK: IconData + SAFETY_CHECK_OUTLINED: IconData + SAFETY_CHECK_ROUNDED: IconData + SAFETY_CHECK_SHARP: IconData + SAFETY_DIVIDER: IconData + SAFETY_DIVIDER_OUTLINED: IconData + SAFETY_DIVIDER_ROUNDED: IconData + SAFETY_DIVIDER_SHARP: IconData + SAILING: IconData + SAILING_OUTLINED: IconData + SAILING_ROUNDED: IconData + SAILING_SHARP: IconData + SANITIZER: IconData + SANITIZER_OUTLINED: IconData + SANITIZER_ROUNDED: IconData + SANITIZER_SHARP: IconData + SATELLITE: IconData + SATELLITE_ALT: IconData + SATELLITE_ALT_OUTLINED: IconData + SATELLITE_ALT_ROUNDED: IconData + SATELLITE_ALT_SHARP: IconData + SATELLITE_OUTLINED: IconData + SATELLITE_ROUNDED: IconData + SATELLITE_SHARP: IconData + SAVE: IconData + SAVE_ALT: IconData + SAVE_ALT_OUTLINED: IconData + SAVE_ALT_ROUNDED: IconData + SAVE_ALT_SHARP: IconData + SAVE_AS: IconData + SAVE_AS_OUTLINED: IconData + SAVE_AS_ROUNDED: IconData + SAVE_AS_SHARP: IconData + SAVE_OUTLINED: IconData + SAVE_ROUNDED: IconData + SAVE_SHARP: IconData + SAVED_SEARCH: IconData + SAVED_SEARCH_OUTLINED: IconData + SAVED_SEARCH_ROUNDED: IconData + SAVED_SEARCH_SHARP: IconData + SAVINGS: IconData + SAVINGS_OUTLINED: IconData + SAVINGS_ROUNDED: IconData + SAVINGS_SHARP: IconData + SCALE: IconData + SCALE_OUTLINED: IconData + SCALE_ROUNDED: IconData + SCALE_SHARP: IconData + SCANNER: IconData + SCANNER_OUTLINED: IconData + SCANNER_ROUNDED: IconData + SCANNER_SHARP: IconData + SCATTER_PLOT: IconData + SCATTER_PLOT_OUTLINED: IconData + SCATTER_PLOT_ROUNDED: IconData + SCATTER_PLOT_SHARP: IconData + SCHEDULE: IconData + SCHEDULE_OUTLINED: IconData + SCHEDULE_ROUNDED: IconData + SCHEDULE_SEND: IconData + SCHEDULE_SEND_OUTLINED: IconData + SCHEDULE_SEND_ROUNDED: IconData + SCHEDULE_SEND_SHARP: IconData + SCHEDULE_SHARP: IconData + SCHEMA: IconData + SCHEMA_OUTLINED: IconData + SCHEMA_ROUNDED: IconData + SCHEMA_SHARP: IconData + SCHOOL: IconData + SCHOOL_OUTLINED: IconData + SCHOOL_ROUNDED: IconData + SCHOOL_SHARP: IconData + SCIENCE: IconData + SCIENCE_OUTLINED: IconData + SCIENCE_ROUNDED: IconData + SCIENCE_SHARP: IconData + SCORE: IconData + SCORE_OUTLINED: IconData + SCORE_ROUNDED: IconData + SCORE_SHARP: IconData + SCOREBOARD: IconData + SCOREBOARD_OUTLINED: IconData + SCOREBOARD_ROUNDED: IconData + SCOREBOARD_SHARP: IconData + SCREEN_LOCK_LANDSCAPE: IconData + SCREEN_LOCK_LANDSCAPE_OUTLINED: IconData + SCREEN_LOCK_LANDSCAPE_ROUNDED: IconData + SCREEN_LOCK_LANDSCAPE_SHARP: IconData + SCREEN_LOCK_PORTRAIT: IconData + SCREEN_LOCK_PORTRAIT_OUTLINED: IconData + SCREEN_LOCK_PORTRAIT_ROUNDED: IconData + SCREEN_LOCK_PORTRAIT_SHARP: IconData + SCREEN_LOCK_ROTATION: IconData + SCREEN_LOCK_ROTATION_OUTLINED: IconData + SCREEN_LOCK_ROTATION_ROUNDED: IconData + SCREEN_LOCK_ROTATION_SHARP: IconData + SCREEN_ROTATION: IconData + SCREEN_ROTATION_ALT: IconData + SCREEN_ROTATION_ALT_OUTLINED: IconData + SCREEN_ROTATION_ALT_ROUNDED: IconData + SCREEN_ROTATION_ALT_SHARP: IconData + SCREEN_ROTATION_OUTLINED: IconData + SCREEN_ROTATION_ROUNDED: IconData + SCREEN_ROTATION_SHARP: IconData + SCREEN_SEARCH_DESKTOP: IconData + SCREEN_SEARCH_DESKTOP_OUTLINED: IconData + SCREEN_SEARCH_DESKTOP_ROUNDED: IconData + SCREEN_SEARCH_DESKTOP_SHARP: IconData + SCREEN_SHARE: IconData + SCREEN_SHARE_OUTLINED: IconData + SCREEN_SHARE_ROUNDED: IconData + SCREEN_SHARE_SHARP: IconData + SCREENSHOT: IconData + SCREENSHOT_MONITOR: IconData + SCREENSHOT_MONITOR_OUTLINED: IconData + SCREENSHOT_MONITOR_ROUNDED: IconData + SCREENSHOT_MONITOR_SHARP: IconData + SCREENSHOT_OUTLINED: IconData + SCREENSHOT_ROUNDED: IconData + SCREENSHOT_SHARP: IconData + SCUBA_DIVING: IconData + SCUBA_DIVING_OUTLINED: IconData + SCUBA_DIVING_ROUNDED: IconData + SCUBA_DIVING_SHARP: IconData + SD: IconData + SD_CARD: IconData + SD_CARD_ALERT: IconData + SD_CARD_ALERT_OUTLINED: IconData + SD_CARD_ALERT_ROUNDED: IconData + SD_CARD_ALERT_SHARP: IconData + SD_CARD_OUTLINED: IconData + SD_CARD_ROUNDED: IconData + SD_CARD_SHARP: IconData + SD_OUTLINED: IconData + SD_ROUNDED: IconData + SD_SHARP: IconData + SD_STORAGE: IconData + SD_STORAGE_OUTLINED: IconData + SD_STORAGE_ROUNDED: IconData + SD_STORAGE_SHARP: IconData + SEARCH: IconData + SEARCH_OFF: IconData + SEARCH_OFF_OUTLINED: IconData + SEARCH_OFF_ROUNDED: IconData + SEARCH_OFF_SHARP: IconData + SEARCH_OUTLINED: IconData + SEARCH_ROUNDED: IconData + SEARCH_SHARP: IconData + SECURITY: IconData + SECURITY_OUTLINED: IconData + SECURITY_ROUNDED: IconData + SECURITY_SHARP: IconData + SECURITY_UPDATE: IconData + SECURITY_UPDATE_GOOD: IconData + SECURITY_UPDATE_GOOD_OUTLINED: IconData + SECURITY_UPDATE_GOOD_ROUNDED: IconData + SECURITY_UPDATE_GOOD_SHARP: IconData + SECURITY_UPDATE_OUTLINED: IconData + SECURITY_UPDATE_ROUNDED: IconData + SECURITY_UPDATE_SHARP: IconData + SECURITY_UPDATE_WARNING: IconData + SECURITY_UPDATE_WARNING_OUTLINED: IconData + SECURITY_UPDATE_WARNING_ROUNDED: IconData + SECURITY_UPDATE_WARNING_SHARP: IconData + SEGMENT: IconData + SEGMENT_OUTLINED: IconData + SEGMENT_ROUNDED: IconData + SEGMENT_SHARP: IconData + SELECT_ALL: IconData + SELECT_ALL_OUTLINED: IconData + SELECT_ALL_ROUNDED: IconData + SELECT_ALL_SHARP: IconData + SELF_IMPROVEMENT: IconData + SELF_IMPROVEMENT_OUTLINED: IconData + SELF_IMPROVEMENT_ROUNDED: IconData + SELF_IMPROVEMENT_SHARP: IconData + SELL: IconData + SELL_OUTLINED: IconData + SELL_ROUNDED: IconData + SELL_SHARP: IconData + SEND: IconData + SEND_AND_ARCHIVE: IconData + SEND_AND_ARCHIVE_OUTLINED: IconData + SEND_AND_ARCHIVE_ROUNDED: IconData + SEND_AND_ARCHIVE_SHARP: IconData + SEND_OUTLINED: IconData + SEND_ROUNDED: IconData + SEND_SHARP: IconData + SEND_TIME_EXTENSION: IconData + SEND_TIME_EXTENSION_OUTLINED: IconData + SEND_TIME_EXTENSION_ROUNDED: IconData + SEND_TIME_EXTENSION_SHARP: IconData + SEND_TO_MOBILE: IconData + SEND_TO_MOBILE_OUTLINED: IconData + SEND_TO_MOBILE_ROUNDED: IconData + SEND_TO_MOBILE_SHARP: IconData + SENSOR_DOOR: IconData + SENSOR_DOOR_OUTLINED: IconData + SENSOR_DOOR_ROUNDED: IconData + SENSOR_DOOR_SHARP: IconData + SENSOR_OCCUPIED: IconData + SENSOR_OCCUPIED_OUTLINED: IconData + SENSOR_OCCUPIED_ROUNDED: IconData + SENSOR_OCCUPIED_SHARP: IconData + SENSOR_WINDOW: IconData + SENSOR_WINDOW_OUTLINED: IconData + SENSOR_WINDOW_ROUNDED: IconData + SENSOR_WINDOW_SHARP: IconData + SENSORS: IconData + SENSORS_OFF: IconData + SENSORS_OFF_OUTLINED: IconData + SENSORS_OFF_ROUNDED: IconData + SENSORS_OFF_SHARP: IconData + SENSORS_OUTLINED: IconData + SENSORS_ROUNDED: IconData + SENSORS_SHARP: IconData + SENTIMENT_DISSATISFIED: IconData + SENTIMENT_DISSATISFIED_OUTLINED: IconData + SENTIMENT_DISSATISFIED_ROUNDED: IconData + SENTIMENT_DISSATISFIED_SHARP: IconData + SENTIMENT_NEUTRAL: IconData + SENTIMENT_NEUTRAL_OUTLINED: IconData + SENTIMENT_NEUTRAL_ROUNDED: IconData + SENTIMENT_NEUTRAL_SHARP: IconData + SENTIMENT_SATISFIED: IconData + SENTIMENT_SATISFIED_ALT: IconData + SENTIMENT_SATISFIED_ALT_OUTLINED: IconData + SENTIMENT_SATISFIED_ALT_ROUNDED: IconData + SENTIMENT_SATISFIED_ALT_SHARP: IconData + SENTIMENT_SATISFIED_OUTLINED: IconData + SENTIMENT_SATISFIED_ROUNDED: IconData + SENTIMENT_SATISFIED_SHARP: IconData + SENTIMENT_VERY_DISSATISFIED: IconData + SENTIMENT_VERY_DISSATISFIED_OUTLINED: IconData + SENTIMENT_VERY_DISSATISFIED_ROUNDED: IconData + SENTIMENT_VERY_DISSATISFIED_SHARP: IconData + SENTIMENT_VERY_SATISFIED: IconData + SENTIMENT_VERY_SATISFIED_OUTLINED: IconData + SENTIMENT_VERY_SATISFIED_ROUNDED: IconData + SENTIMENT_VERY_SATISFIED_SHARP: IconData + SET_MEAL: IconData + SET_MEAL_OUTLINED: IconData + SET_MEAL_ROUNDED: IconData + SET_MEAL_SHARP: IconData + SETTINGS: IconData + SETTINGS_ACCESSIBILITY: IconData + SETTINGS_ACCESSIBILITY_OUTLINED: IconData + SETTINGS_ACCESSIBILITY_ROUNDED: IconData + SETTINGS_ACCESSIBILITY_SHARP: IconData + SETTINGS_APPLICATIONS: IconData + SETTINGS_APPLICATIONS_OUTLINED: IconData + SETTINGS_APPLICATIONS_ROUNDED: IconData + SETTINGS_APPLICATIONS_SHARP: IconData + SETTINGS_BACKUP_RESTORE: IconData + SETTINGS_BACKUP_RESTORE_OUTLINED: IconData + SETTINGS_BACKUP_RESTORE_ROUNDED: IconData + SETTINGS_BACKUP_RESTORE_SHARP: IconData + SETTINGS_BLUETOOTH: IconData + SETTINGS_BLUETOOTH_OUTLINED: IconData + SETTINGS_BLUETOOTH_ROUNDED: IconData + SETTINGS_BLUETOOTH_SHARP: IconData + SETTINGS_BRIGHTNESS: IconData + SETTINGS_BRIGHTNESS_OUTLINED: IconData + SETTINGS_BRIGHTNESS_ROUNDED: IconData + SETTINGS_BRIGHTNESS_SHARP: IconData + SETTINGS_CELL: IconData + SETTINGS_CELL_OUTLINED: IconData + SETTINGS_CELL_ROUNDED: IconData + SETTINGS_CELL_SHARP: IconData + SETTINGS_DISPLAY: IconData + SETTINGS_DISPLAY_OUTLINED: IconData + SETTINGS_DISPLAY_ROUNDED: IconData + SETTINGS_DISPLAY_SHARP: IconData + SETTINGS_ETHERNET: IconData + SETTINGS_ETHERNET_OUTLINED: IconData + SETTINGS_ETHERNET_ROUNDED: IconData + SETTINGS_ETHERNET_SHARP: IconData + SETTINGS_INPUT_ANTENNA: IconData + SETTINGS_INPUT_ANTENNA_OUTLINED: IconData + SETTINGS_INPUT_ANTENNA_ROUNDED: IconData + SETTINGS_INPUT_ANTENNA_SHARP: IconData + SETTINGS_INPUT_COMPONENT: IconData + SETTINGS_INPUT_COMPONENT_OUTLINED: IconData + SETTINGS_INPUT_COMPONENT_ROUNDED: IconData + SETTINGS_INPUT_COMPONENT_SHARP: IconData + SETTINGS_INPUT_COMPOSITE: IconData + SETTINGS_INPUT_COMPOSITE_OUTLINED: IconData + SETTINGS_INPUT_COMPOSITE_ROUNDED: IconData + SETTINGS_INPUT_COMPOSITE_SHARP: IconData + SETTINGS_INPUT_HDMI: IconData + SETTINGS_INPUT_HDMI_OUTLINED: IconData + SETTINGS_INPUT_HDMI_ROUNDED: IconData + SETTINGS_INPUT_HDMI_SHARP: IconData + SETTINGS_INPUT_SVIDEO: IconData + SETTINGS_INPUT_SVIDEO_OUTLINED: IconData + SETTINGS_INPUT_SVIDEO_ROUNDED: IconData + SETTINGS_INPUT_SVIDEO_SHARP: IconData + SETTINGS_OUTLINED: IconData + SETTINGS_OVERSCAN: IconData + SETTINGS_OVERSCAN_OUTLINED: IconData + SETTINGS_OVERSCAN_ROUNDED: IconData + SETTINGS_OVERSCAN_SHARP: IconData + SETTINGS_PHONE: IconData + SETTINGS_PHONE_OUTLINED: IconData + SETTINGS_PHONE_ROUNDED: IconData + SETTINGS_PHONE_SHARP: IconData + SETTINGS_POWER: IconData + SETTINGS_POWER_OUTLINED: IconData + SETTINGS_POWER_ROUNDED: IconData + SETTINGS_POWER_SHARP: IconData + SETTINGS_REMOTE: IconData + SETTINGS_REMOTE_OUTLINED: IconData + SETTINGS_REMOTE_ROUNDED: IconData + SETTINGS_REMOTE_SHARP: IconData + SETTINGS_ROUNDED: IconData + SETTINGS_SHARP: IconData + SETTINGS_SUGGEST: IconData + SETTINGS_SUGGEST_OUTLINED: IconData + SETTINGS_SUGGEST_ROUNDED: IconData + SETTINGS_SUGGEST_SHARP: IconData + SETTINGS_SYSTEM_DAYDREAM: IconData + SETTINGS_SYSTEM_DAYDREAM_OUTLINED: IconData + SETTINGS_SYSTEM_DAYDREAM_ROUNDED: IconData + SETTINGS_SYSTEM_DAYDREAM_SHARP: IconData + SETTINGS_VOICE: IconData + SETTINGS_VOICE_OUTLINED: IconData + SETTINGS_VOICE_ROUNDED: IconData + SETTINGS_VOICE_SHARP: IconData + SEVEN_K: IconData + SEVEN_K_OUTLINED: IconData + SEVEN_K_PLUS: IconData + SEVEN_K_PLUS_OUTLINED: IconData + SEVEN_K_PLUS_ROUNDED: IconData + SEVEN_K_PLUS_SHARP: IconData + SEVEN_K_ROUNDED: IconData + SEVEN_K_SHARP: IconData + SEVEN_MP: IconData + SEVEN_MP_OUTLINED: IconData + SEVEN_MP_ROUNDED: IconData + SEVEN_MP_SHARP: IconData + SEVENTEEN_MP: IconData + SEVENTEEN_MP_OUTLINED: IconData + SEVENTEEN_MP_ROUNDED: IconData + SEVENTEEN_MP_SHARP: IconData + SEVERE_COLD: IconData + SEVERE_COLD_OUTLINED: IconData + SEVERE_COLD_ROUNDED: IconData + SEVERE_COLD_SHARP: IconData + SHAPE_LINE: IconData + SHAPE_LINE_OUTLINED: IconData + SHAPE_LINE_ROUNDED: IconData + SHAPE_LINE_SHARP: IconData + SHARE: IconData + SHARE_ARRIVAL_TIME: IconData + SHARE_ARRIVAL_TIME_OUTLINED: IconData + SHARE_ARRIVAL_TIME_ROUNDED: IconData + SHARE_ARRIVAL_TIME_SHARP: IconData + SHARE_LOCATION: IconData + SHARE_LOCATION_OUTLINED: IconData + SHARE_LOCATION_ROUNDED: IconData + SHARE_LOCATION_SHARP: IconData + SHARE_OUTLINED: IconData + SHARE_ROUNDED: IconData + SHARE_SHARP: IconData + SHELVES: IconData + SHIELD: IconData + SHIELD_MOON: IconData + SHIELD_MOON_OUTLINED: IconData + SHIELD_MOON_ROUNDED: IconData + SHIELD_MOON_SHARP: IconData + SHIELD_OUTLINED: IconData + SHIELD_ROUNDED: IconData + SHIELD_SHARP: IconData + SHOP: IconData + SHOP_2: IconData + SHOP_2_OUTLINED: IconData + SHOP_2_ROUNDED: IconData + SHOP_2_SHARP: IconData + SHOP_OUTLINED: IconData + SHOP_ROUNDED: IconData + SHOP_SHARP: IconData + SHOP_TWO: IconData + SHOP_TWO_OUTLINED: IconData + SHOP_TWO_ROUNDED: IconData + SHOP_TWO_SHARP: IconData + SHOPIFY: IconData + SHOPIFY_OUTLINED: IconData + SHOPIFY_ROUNDED: IconData + SHOPIFY_SHARP: IconData + SHOPPING_BAG: IconData + SHOPPING_BAG_OUTLINED: IconData + SHOPPING_BAG_ROUNDED: IconData + SHOPPING_BAG_SHARP: IconData + SHOPPING_BASKET: IconData + SHOPPING_BASKET_OUTLINED: IconData + SHOPPING_BASKET_ROUNDED: IconData + SHOPPING_BASKET_SHARP: IconData + SHOPPING_CART: IconData + SHOPPING_CART_CHECKOUT: IconData + SHOPPING_CART_CHECKOUT_OUTLINED: IconData + SHOPPING_CART_CHECKOUT_ROUNDED: IconData + SHOPPING_CART_CHECKOUT_SHARP: IconData + SHOPPING_CART_OUTLINED: IconData + SHOPPING_CART_ROUNDED: IconData + SHOPPING_CART_SHARP: IconData + SHORT_TEXT: IconData + SHORT_TEXT_OUTLINED: IconData + SHORT_TEXT_ROUNDED: IconData + SHORT_TEXT_SHARP: IconData + SHORTCUT: IconData + SHORTCUT_OUTLINED: IconData + SHORTCUT_ROUNDED: IconData + SHORTCUT_SHARP: IconData + SHOW_CHART: IconData + SHOW_CHART_OUTLINED: IconData + SHOW_CHART_ROUNDED: IconData + SHOW_CHART_SHARP: IconData + SHOWER: IconData + SHOWER_OUTLINED: IconData + SHOWER_ROUNDED: IconData + SHOWER_SHARP: IconData + SHUFFLE: IconData + SHUFFLE_ON: IconData + SHUFFLE_ON_OUTLINED: IconData + SHUFFLE_ON_ROUNDED: IconData + SHUFFLE_ON_SHARP: IconData + SHUFFLE_OUTLINED: IconData + SHUFFLE_ROUNDED: IconData + SHUFFLE_SHARP: IconData + SHUTTER_SPEED: IconData + SHUTTER_SPEED_OUTLINED: IconData + SHUTTER_SPEED_ROUNDED: IconData + SHUTTER_SPEED_SHARP: IconData + SICK: IconData + SICK_OUTLINED: IconData + SICK_ROUNDED: IconData + SICK_SHARP: IconData + SIGN_LANGUAGE: IconData + SIGN_LANGUAGE_OUTLINED: IconData + SIGN_LANGUAGE_ROUNDED: IconData + SIGN_LANGUAGE_SHARP: IconData + SIGNAL_CELLULAR_0_BAR: IconData + SIGNAL_CELLULAR_0_BAR_OUTLINED: IconData + SIGNAL_CELLULAR_0_BAR_ROUNDED: IconData + SIGNAL_CELLULAR_0_BAR_SHARP: IconData + SIGNAL_CELLULAR_4_BAR: IconData + SIGNAL_CELLULAR_4_BAR_OUTLINED: IconData + SIGNAL_CELLULAR_4_BAR_ROUNDED: IconData + SIGNAL_CELLULAR_4_BAR_SHARP: IconData + SIGNAL_CELLULAR_ALT: IconData + SIGNAL_CELLULAR_ALT_1_BAR: IconData + SIGNAL_CELLULAR_ALT_1_BAR_OUTLINED: IconData + SIGNAL_CELLULAR_ALT_1_BAR_ROUNDED: IconData + SIGNAL_CELLULAR_ALT_1_BAR_SHARP: IconData + SIGNAL_CELLULAR_ALT_2_BAR: IconData + SIGNAL_CELLULAR_ALT_2_BAR_OUTLINED: IconData + SIGNAL_CELLULAR_ALT_2_BAR_ROUNDED: IconData + SIGNAL_CELLULAR_ALT_2_BAR_SHARP: IconData + SIGNAL_CELLULAR_ALT_OUTLINED: IconData + SIGNAL_CELLULAR_ALT_ROUNDED: IconData + SIGNAL_CELLULAR_ALT_SHARP: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_OUTLINED: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_ROUNDED: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_SHARP: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_OUTLINED: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_ROUNDED: IconData + SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_SHARP: IconData + SIGNAL_CELLULAR_NO_SIM: IconData + SIGNAL_CELLULAR_NO_SIM_OUTLINED: IconData + SIGNAL_CELLULAR_NO_SIM_ROUNDED: IconData + SIGNAL_CELLULAR_NO_SIM_SHARP: IconData + SIGNAL_CELLULAR_NODATA: IconData + SIGNAL_CELLULAR_NODATA_OUTLINED: IconData + SIGNAL_CELLULAR_NODATA_ROUNDED: IconData + SIGNAL_CELLULAR_NODATA_SHARP: IconData + SIGNAL_CELLULAR_NULL: IconData + SIGNAL_CELLULAR_NULL_OUTLINED: IconData + SIGNAL_CELLULAR_NULL_ROUNDED: IconData + SIGNAL_CELLULAR_NULL_SHARP: IconData + SIGNAL_CELLULAR_OFF: IconData + SIGNAL_CELLULAR_OFF_OUTLINED: IconData + SIGNAL_CELLULAR_OFF_ROUNDED: IconData + SIGNAL_CELLULAR_OFF_SHARP: IconData + SIGNAL_WIFI_0_BAR: IconData + SIGNAL_WIFI_0_BAR_OUTLINED: IconData + SIGNAL_WIFI_0_BAR_ROUNDED: IconData + SIGNAL_WIFI_0_BAR_SHARP: IconData + SIGNAL_WIFI_4_BAR: IconData + SIGNAL_WIFI_4_BAR_LOCK: IconData + SIGNAL_WIFI_4_BAR_LOCK_OUTLINED: IconData + SIGNAL_WIFI_4_BAR_LOCK_ROUNDED: IconData + SIGNAL_WIFI_4_BAR_LOCK_SHARP: IconData + SIGNAL_WIFI_4_BAR_OUTLINED: IconData + SIGNAL_WIFI_4_BAR_ROUNDED: IconData + SIGNAL_WIFI_4_BAR_SHARP: IconData + SIGNAL_WIFI_BAD: IconData + SIGNAL_WIFI_BAD_OUTLINED: IconData + SIGNAL_WIFI_BAD_ROUNDED: IconData + SIGNAL_WIFI_BAD_SHARP: IconData + SIGNAL_WIFI_CONNECTED_NO_INTERNET_4: IconData + SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_OUTLINED: IconData + SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_ROUNDED: IconData + SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_SHARP: IconData + SIGNAL_WIFI_OFF: IconData + SIGNAL_WIFI_OFF_OUTLINED: IconData + SIGNAL_WIFI_OFF_ROUNDED: IconData + SIGNAL_WIFI_OFF_SHARP: IconData + SIGNAL_WIFI_STATUSBAR_4_BAR: IconData + SIGNAL_WIFI_STATUSBAR_4_BAR_OUTLINED: IconData + SIGNAL_WIFI_STATUSBAR_4_BAR_ROUNDED: IconData + SIGNAL_WIFI_STATUSBAR_4_BAR_SHARP: IconData + SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4: IconData + SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_OUTLINED: IconData + SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_ROUNDED: IconData + SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_SHARP: IconData + SIGNAL_WIFI_STATUSBAR_NULL: IconData + SIGNAL_WIFI_STATUSBAR_NULL_OUTLINED: IconData + SIGNAL_WIFI_STATUSBAR_NULL_ROUNDED: IconData + SIGNAL_WIFI_STATUSBAR_NULL_SHARP: IconData + SIGNPOST: IconData + SIGNPOST_OUTLINED: IconData + SIGNPOST_ROUNDED: IconData + SIGNPOST_SHARP: IconData + SIM_CARD: IconData + SIM_CARD_ALERT: IconData + SIM_CARD_ALERT_OUTLINED: IconData + SIM_CARD_ALERT_ROUNDED: IconData + SIM_CARD_ALERT_SHARP: IconData + SIM_CARD_DOWNLOAD: IconData + SIM_CARD_DOWNLOAD_OUTLINED: IconData + SIM_CARD_DOWNLOAD_ROUNDED: IconData + SIM_CARD_DOWNLOAD_SHARP: IconData + SIM_CARD_OUTLINED: IconData + SIM_CARD_ROUNDED: IconData + SIM_CARD_SHARP: IconData + SINGLE_BED: IconData + SINGLE_BED_OUTLINED: IconData + SINGLE_BED_ROUNDED: IconData + SINGLE_BED_SHARP: IconData + SIP: IconData + SIP_OUTLINED: IconData + SIP_ROUNDED: IconData + SIP_SHARP: IconData + SIX_FT_APART: IconData + SIX_FT_APART_OUTLINED: IconData + SIX_FT_APART_ROUNDED: IconData + SIX_FT_APART_SHARP: IconData + SIX_K: IconData + SIX_K_OUTLINED: IconData + SIX_K_PLUS: IconData + SIX_K_PLUS_OUTLINED: IconData + SIX_K_PLUS_ROUNDED: IconData + SIX_K_PLUS_SHARP: IconData + SIX_K_ROUNDED: IconData + SIX_K_SHARP: IconData + SIX_MP: IconData + SIX_MP_OUTLINED: IconData + SIX_MP_ROUNDED: IconData + SIX_MP_SHARP: IconData + SIXTEEN_MP: IconData + SIXTEEN_MP_OUTLINED: IconData + SIXTEEN_MP_ROUNDED: IconData + SIXTEEN_MP_SHARP: IconData + SIXTY_FPS: IconData + SIXTY_FPS_OUTLINED: IconData + SIXTY_FPS_ROUNDED: IconData + SIXTY_FPS_SELECT: IconData + SIXTY_FPS_SELECT_OUTLINED: IconData + SIXTY_FPS_SELECT_ROUNDED: IconData + SIXTY_FPS_SELECT_SHARP: IconData + SIXTY_FPS_SHARP: IconData + SKATEBOARDING: IconData + SKATEBOARDING_OUTLINED: IconData + SKATEBOARDING_ROUNDED: IconData + SKATEBOARDING_SHARP: IconData + SKIP_NEXT: IconData + SKIP_NEXT_OUTLINED: IconData + SKIP_NEXT_ROUNDED: IconData + SKIP_NEXT_SHARP: IconData + SKIP_PREVIOUS: IconData + SKIP_PREVIOUS_OUTLINED: IconData + SKIP_PREVIOUS_ROUNDED: IconData + SKIP_PREVIOUS_SHARP: IconData + SLEDDING: IconData + SLEDDING_OUTLINED: IconData + SLEDDING_ROUNDED: IconData + SLEDDING_SHARP: IconData + SLIDESHOW: IconData + SLIDESHOW_OUTLINED: IconData + SLIDESHOW_ROUNDED: IconData + SLIDESHOW_SHARP: IconData + SLOW_MOTION_VIDEO: IconData + SLOW_MOTION_VIDEO_OUTLINED: IconData + SLOW_MOTION_VIDEO_ROUNDED: IconData + SLOW_MOTION_VIDEO_SHARP: IconData + SMART_BUTTON: IconData + SMART_BUTTON_OUTLINED: IconData + SMART_BUTTON_ROUNDED: IconData + SMART_BUTTON_SHARP: IconData + SMART_DISPLAY: IconData + SMART_DISPLAY_OUTLINED: IconData + SMART_DISPLAY_ROUNDED: IconData + SMART_DISPLAY_SHARP: IconData + SMART_SCREEN: IconData + SMART_SCREEN_OUTLINED: IconData + SMART_SCREEN_ROUNDED: IconData + SMART_SCREEN_SHARP: IconData + SMART_TOY: IconData + SMART_TOY_OUTLINED: IconData + SMART_TOY_ROUNDED: IconData + SMART_TOY_SHARP: IconData + SMARTPHONE: IconData + SMARTPHONE_OUTLINED: IconData + SMARTPHONE_ROUNDED: IconData + SMARTPHONE_SHARP: IconData + SMOKE_FREE: IconData + SMOKE_FREE_OUTLINED: IconData + SMOKE_FREE_ROUNDED: IconData + SMOKE_FREE_SHARP: IconData + SMOKING_ROOMS: IconData + SMOKING_ROOMS_OUTLINED: IconData + SMOKING_ROOMS_ROUNDED: IconData + SMOKING_ROOMS_SHARP: IconData + SMS: IconData + SMS_FAILED: IconData + SMS_FAILED_OUTLINED: IconData + SMS_FAILED_ROUNDED: IconData + SMS_FAILED_SHARP: IconData + SMS_OUTLINED: IconData + SMS_ROUNDED: IconData + SMS_SHARP: IconData + SNAPCHAT: IconData + SNAPCHAT_OUTLINED: IconData + SNAPCHAT_ROUNDED: IconData + SNAPCHAT_SHARP: IconData + SNIPPET_FOLDER: IconData + SNIPPET_FOLDER_OUTLINED: IconData + SNIPPET_FOLDER_ROUNDED: IconData + SNIPPET_FOLDER_SHARP: IconData + SNOOZE: IconData + SNOOZE_OUTLINED: IconData + SNOOZE_ROUNDED: IconData + SNOOZE_SHARP: IconData + SNOWBOARDING: IconData + SNOWBOARDING_OUTLINED: IconData + SNOWBOARDING_ROUNDED: IconData + SNOWBOARDING_SHARP: IconData + SNOWING: IconData + SNOWMOBILE: IconData + SNOWMOBILE_OUTLINED: IconData + SNOWMOBILE_ROUNDED: IconData + SNOWMOBILE_SHARP: IconData + SNOWSHOEING: IconData + SNOWSHOEING_OUTLINED: IconData + SNOWSHOEING_ROUNDED: IconData + SNOWSHOEING_SHARP: IconData + SOAP: IconData + SOAP_OUTLINED: IconData + SOAP_ROUNDED: IconData + SOAP_SHARP: IconData + SOCIAL_DISTANCE: IconData + SOCIAL_DISTANCE_OUTLINED: IconData + SOCIAL_DISTANCE_ROUNDED: IconData + SOCIAL_DISTANCE_SHARP: IconData + SOLAR_POWER: IconData + SOLAR_POWER_OUTLINED: IconData + SOLAR_POWER_ROUNDED: IconData + SOLAR_POWER_SHARP: IconData + SORT: IconData + SORT_BY_ALPHA: IconData + SORT_BY_ALPHA_OUTLINED: IconData + SORT_BY_ALPHA_ROUNDED: IconData + SORT_BY_ALPHA_SHARP: IconData + SORT_OUTLINED: IconData + SORT_ROUNDED: IconData + SORT_SHARP: IconData + SOS: IconData + SOS_OUTLINED: IconData + SOS_ROUNDED: IconData + SOS_SHARP: IconData + SOUP_KITCHEN: IconData + SOUP_KITCHEN_OUTLINED: IconData + SOUP_KITCHEN_ROUNDED: IconData + SOUP_KITCHEN_SHARP: IconData + SOURCE: IconData + SOURCE_OUTLINED: IconData + SOURCE_ROUNDED: IconData + SOURCE_SHARP: IconData + SOUTH: IconData + SOUTH_AMERICA: IconData + SOUTH_AMERICA_OUTLINED: IconData + SOUTH_AMERICA_ROUNDED: IconData + SOUTH_AMERICA_SHARP: IconData + SOUTH_EAST: IconData + SOUTH_EAST_OUTLINED: IconData + SOUTH_EAST_ROUNDED: IconData + SOUTH_EAST_SHARP: IconData + SOUTH_OUTLINED: IconData + SOUTH_ROUNDED: IconData + SOUTH_SHARP: IconData + SOUTH_WEST: IconData + SOUTH_WEST_OUTLINED: IconData + SOUTH_WEST_ROUNDED: IconData + SOUTH_WEST_SHARP: IconData + SPA: IconData + SPA_OUTLINED: IconData + SPA_ROUNDED: IconData + SPA_SHARP: IconData + SPACE_BAR: IconData + SPACE_BAR_OUTLINED: IconData + SPACE_BAR_ROUNDED: IconData + SPACE_BAR_SHARP: IconData + SPACE_DASHBOARD: IconData + SPACE_DASHBOARD_OUTLINED: IconData + SPACE_DASHBOARD_ROUNDED: IconData + SPACE_DASHBOARD_SHARP: IconData + SPATIAL_AUDIO: IconData + SPATIAL_AUDIO_OFF: IconData + SPATIAL_AUDIO_OFF_OUTLINED: IconData + SPATIAL_AUDIO_OFF_ROUNDED: IconData + SPATIAL_AUDIO_OFF_SHARP: IconData + SPATIAL_AUDIO_OUTLINED: IconData + SPATIAL_AUDIO_ROUNDED: IconData + SPATIAL_AUDIO_SHARP: IconData + SPATIAL_TRACKING: IconData + SPATIAL_TRACKING_OUTLINED: IconData + SPATIAL_TRACKING_ROUNDED: IconData + SPATIAL_TRACKING_SHARP: IconData + SPEAKER: IconData + SPEAKER_GROUP: IconData + SPEAKER_GROUP_OUTLINED: IconData + SPEAKER_GROUP_ROUNDED: IconData + SPEAKER_GROUP_SHARP: IconData + SPEAKER_NOTES: IconData + SPEAKER_NOTES_OFF: IconData + SPEAKER_NOTES_OFF_OUTLINED: IconData + SPEAKER_NOTES_OFF_ROUNDED: IconData + SPEAKER_NOTES_OFF_SHARP: IconData + SPEAKER_NOTES_OUTLINED: IconData + SPEAKER_NOTES_ROUNDED: IconData + SPEAKER_NOTES_SHARP: IconData + SPEAKER_OUTLINED: IconData + SPEAKER_PHONE: IconData + SPEAKER_PHONE_OUTLINED: IconData + SPEAKER_PHONE_ROUNDED: IconData + SPEAKER_PHONE_SHARP: IconData + SPEAKER_ROUNDED: IconData + SPEAKER_SHARP: IconData + SPEED: IconData + SPEED_OUTLINED: IconData + SPEED_ROUNDED: IconData + SPEED_SHARP: IconData + SPELLCHECK: IconData + SPELLCHECK_OUTLINED: IconData + SPELLCHECK_ROUNDED: IconData + SPELLCHECK_SHARP: IconData + SPLITSCREEN: IconData + SPLITSCREEN_OUTLINED: IconData + SPLITSCREEN_ROUNDED: IconData + SPLITSCREEN_SHARP: IconData + SPOKE: IconData + SPOKE_OUTLINED: IconData + SPOKE_ROUNDED: IconData + SPOKE_SHARP: IconData + SPORTS: IconData + SPORTS_BAR: IconData + SPORTS_BAR_OUTLINED: IconData + SPORTS_BAR_ROUNDED: IconData + SPORTS_BAR_SHARP: IconData + SPORTS_BASEBALL: IconData + SPORTS_BASEBALL_OUTLINED: IconData + SPORTS_BASEBALL_ROUNDED: IconData + SPORTS_BASEBALL_SHARP: IconData + SPORTS_BASKETBALL: IconData + SPORTS_BASKETBALL_OUTLINED: IconData + SPORTS_BASKETBALL_ROUNDED: IconData + SPORTS_BASKETBALL_SHARP: IconData + SPORTS_CRICKET: IconData + SPORTS_CRICKET_OUTLINED: IconData + SPORTS_CRICKET_ROUNDED: IconData + SPORTS_CRICKET_SHARP: IconData + SPORTS_ESPORTS: IconData + SPORTS_ESPORTS_OUTLINED: IconData + SPORTS_ESPORTS_ROUNDED: IconData + SPORTS_ESPORTS_SHARP: IconData + SPORTS_FOOTBALL: IconData + SPORTS_FOOTBALL_OUTLINED: IconData + SPORTS_FOOTBALL_ROUNDED: IconData + SPORTS_FOOTBALL_SHARP: IconData + SPORTS_GOLF: IconData + SPORTS_GOLF_OUTLINED: IconData + SPORTS_GOLF_ROUNDED: IconData + SPORTS_GOLF_SHARP: IconData + SPORTS_GYMNASTICS: IconData + SPORTS_GYMNASTICS_OUTLINED: IconData + SPORTS_GYMNASTICS_ROUNDED: IconData + SPORTS_GYMNASTICS_SHARP: IconData + SPORTS_HANDBALL: IconData + SPORTS_HANDBALL_OUTLINED: IconData + SPORTS_HANDBALL_ROUNDED: IconData + SPORTS_HANDBALL_SHARP: IconData + SPORTS_HOCKEY: IconData + SPORTS_HOCKEY_OUTLINED: IconData + SPORTS_HOCKEY_ROUNDED: IconData + SPORTS_HOCKEY_SHARP: IconData + SPORTS_KABADDI: IconData + SPORTS_KABADDI_OUTLINED: IconData + SPORTS_KABADDI_ROUNDED: IconData + SPORTS_KABADDI_SHARP: IconData + SPORTS_MARTIAL_ARTS: IconData + SPORTS_MARTIAL_ARTS_OUTLINED: IconData + SPORTS_MARTIAL_ARTS_ROUNDED: IconData + SPORTS_MARTIAL_ARTS_SHARP: IconData + SPORTS_MMA: IconData + SPORTS_MMA_OUTLINED: IconData + SPORTS_MMA_ROUNDED: IconData + SPORTS_MMA_SHARP: IconData + SPORTS_MOTORSPORTS: IconData + SPORTS_MOTORSPORTS_OUTLINED: IconData + SPORTS_MOTORSPORTS_ROUNDED: IconData + SPORTS_MOTORSPORTS_SHARP: IconData + SPORTS_OUTLINED: IconData + SPORTS_ROUNDED: IconData + SPORTS_RUGBY: IconData + SPORTS_RUGBY_OUTLINED: IconData + SPORTS_RUGBY_ROUNDED: IconData + SPORTS_RUGBY_SHARP: IconData + SPORTS_SCORE: IconData + SPORTS_SCORE_OUTLINED: IconData + SPORTS_SCORE_ROUNDED: IconData + SPORTS_SCORE_SHARP: IconData + SPORTS_SHARP: IconData + SPORTS_SOCCER: IconData + SPORTS_SOCCER_OUTLINED: IconData + SPORTS_SOCCER_ROUNDED: IconData + SPORTS_SOCCER_SHARP: IconData + SPORTS_TENNIS: IconData + SPORTS_TENNIS_OUTLINED: IconData + SPORTS_TENNIS_ROUNDED: IconData + SPORTS_TENNIS_SHARP: IconData + SPORTS_VOLLEYBALL: IconData + SPORTS_VOLLEYBALL_OUTLINED: IconData + SPORTS_VOLLEYBALL_ROUNDED: IconData + SPORTS_VOLLEYBALL_SHARP: IconData + SQUARE: IconData + SQUARE_FOOT: IconData + SQUARE_FOOT_OUTLINED: IconData + SQUARE_FOOT_ROUNDED: IconData + SQUARE_FOOT_SHARP: IconData + SQUARE_OUTLINED: IconData + SQUARE_ROUNDED: IconData + SQUARE_SHARP: IconData + SSID_CHART: IconData + SSID_CHART_OUTLINED: IconData + SSID_CHART_ROUNDED: IconData + SSID_CHART_SHARP: IconData + STACKED_BAR_CHART: IconData + STACKED_BAR_CHART_OUTLINED: IconData + STACKED_BAR_CHART_ROUNDED: IconData + STACKED_BAR_CHART_SHARP: IconData + STACKED_LINE_CHART: IconData + STACKED_LINE_CHART_OUTLINED: IconData + STACKED_LINE_CHART_ROUNDED: IconData + STACKED_LINE_CHART_SHARP: IconData + STADIUM: IconData + STADIUM_OUTLINED: IconData + STADIUM_ROUNDED: IconData + STADIUM_SHARP: IconData + STAIRS: IconData + STAIRS_OUTLINED: IconData + STAIRS_ROUNDED: IconData + STAIRS_SHARP: IconData + STAR: IconData + STAR_BORDER: IconData + STAR_BORDER_OUTLINED: IconData + STAR_BORDER_PURPLE500: IconData + STAR_BORDER_PURPLE500_OUTLINED: IconData + STAR_BORDER_PURPLE500_ROUNDED: IconData + STAR_BORDER_PURPLE500_SHARP: IconData + STAR_BORDER_ROUNDED: IconData + STAR_BORDER_SHARP: IconData + STAR_HALF: IconData + STAR_HALF_OUTLINED: IconData + STAR_HALF_ROUNDED: IconData + STAR_HALF_SHARP: IconData + STAR_OUTLINE: IconData + STAR_OUTLINE_OUTLINED: IconData + STAR_OUTLINE_ROUNDED: IconData + STAR_OUTLINE_SHARP: IconData + STAR_OUTLINED: IconData + STAR_PURPLE500: IconData + STAR_PURPLE500_OUTLINED: IconData + STAR_PURPLE500_ROUNDED: IconData + STAR_PURPLE500_SHARP: IconData + STAR_RATE: IconData + STAR_RATE_OUTLINED: IconData + STAR_RATE_ROUNDED: IconData + STAR_RATE_SHARP: IconData + STAR_ROUNDED: IconData + STAR_SHARP: IconData + STARS: IconData + STARS_OUTLINED: IconData + STARS_ROUNDED: IconData + STARS_SHARP: IconData + START: IconData + START_OUTLINED: IconData + START_ROUNDED: IconData + START_SHARP: IconData + STAY_CURRENT_LANDSCAPE: IconData + STAY_CURRENT_LANDSCAPE_OUTLINED: IconData + STAY_CURRENT_LANDSCAPE_ROUNDED: IconData + STAY_CURRENT_LANDSCAPE_SHARP: IconData + STAY_CURRENT_PORTRAIT: IconData + STAY_CURRENT_PORTRAIT_OUTLINED: IconData + STAY_CURRENT_PORTRAIT_ROUNDED: IconData + STAY_CURRENT_PORTRAIT_SHARP: IconData + STAY_PRIMARY_LANDSCAPE: IconData + STAY_PRIMARY_LANDSCAPE_OUTLINED: IconData + STAY_PRIMARY_LANDSCAPE_ROUNDED: IconData + STAY_PRIMARY_LANDSCAPE_SHARP: IconData + STAY_PRIMARY_PORTRAIT: IconData + STAY_PRIMARY_PORTRAIT_OUTLINED: IconData + STAY_PRIMARY_PORTRAIT_ROUNDED: IconData + STAY_PRIMARY_PORTRAIT_SHARP: IconData + STICKY_NOTE_2: IconData + STICKY_NOTE_2_OUTLINED: IconData + STICKY_NOTE_2_ROUNDED: IconData + STICKY_NOTE_2_SHARP: IconData + STOP: IconData + STOP_CIRCLE: IconData + STOP_CIRCLE_OUTLINED: IconData + STOP_CIRCLE_ROUNDED: IconData + STOP_CIRCLE_SHARP: IconData + STOP_OUTLINED: IconData + STOP_ROUNDED: IconData + STOP_SCREEN_SHARE: IconData + STOP_SCREEN_SHARE_OUTLINED: IconData + STOP_SCREEN_SHARE_ROUNDED: IconData + STOP_SCREEN_SHARE_SHARP: IconData + STOP_SHARP: IconData + STORAGE: IconData + STORAGE_OUTLINED: IconData + STORAGE_ROUNDED: IconData + STORAGE_SHARP: IconData + STORE: IconData + STORE_MALL_DIRECTORY: IconData + STORE_MALL_DIRECTORY_OUTLINED: IconData + STORE_MALL_DIRECTORY_ROUNDED: IconData + STORE_MALL_DIRECTORY_SHARP: IconData + STORE_OUTLINED: IconData + STORE_ROUNDED: IconData + STORE_SHARP: IconData + STOREFRONT: IconData + STOREFRONT_OUTLINED: IconData + STOREFRONT_ROUNDED: IconData + STOREFRONT_SHARP: IconData + STORM: IconData + STORM_OUTLINED: IconData + STORM_ROUNDED: IconData + STORM_SHARP: IconData + STRAIGHT: IconData + STRAIGHT_OUTLINED: IconData + STRAIGHT_ROUNDED: IconData + STRAIGHT_SHARP: IconData + STRAIGHTEN: IconData + STRAIGHTEN_OUTLINED: IconData + STRAIGHTEN_ROUNDED: IconData + STRAIGHTEN_SHARP: IconData + STREAM: IconData + STREAM_OUTLINED: IconData + STREAM_ROUNDED: IconData + STREAM_SHARP: IconData + STREETVIEW: IconData + STREETVIEW_OUTLINED: IconData + STREETVIEW_ROUNDED: IconData + STREETVIEW_SHARP: IconData + STRIKETHROUGH_S: IconData + STRIKETHROUGH_S_OUTLINED: IconData + STRIKETHROUGH_S_ROUNDED: IconData + STRIKETHROUGH_S_SHARP: IconData + STROLLER: IconData + STROLLER_OUTLINED: IconData + STROLLER_ROUNDED: IconData + STROLLER_SHARP: IconData + STYLE: IconData + STYLE_OUTLINED: IconData + STYLE_ROUNDED: IconData + STYLE_SHARP: IconData + SUBDIRECTORY_ARROW_LEFT: IconData + SUBDIRECTORY_ARROW_LEFT_OUTLINED: IconData + SUBDIRECTORY_ARROW_LEFT_ROUNDED: IconData + SUBDIRECTORY_ARROW_LEFT_SHARP: IconData + SUBDIRECTORY_ARROW_RIGHT: IconData + SUBDIRECTORY_ARROW_RIGHT_OUTLINED: IconData + SUBDIRECTORY_ARROW_RIGHT_ROUNDED: IconData + SUBDIRECTORY_ARROW_RIGHT_SHARP: IconData + SUBJECT: IconData + SUBJECT_OUTLINED: IconData + SUBJECT_ROUNDED: IconData + SUBJECT_SHARP: IconData + SUBSCRIPT: IconData + SUBSCRIPT_OUTLINED: IconData + SUBSCRIPT_ROUNDED: IconData + SUBSCRIPT_SHARP: IconData + SUBSCRIPTIONS: IconData + SUBSCRIPTIONS_OUTLINED: IconData + SUBSCRIPTIONS_ROUNDED: IconData + SUBSCRIPTIONS_SHARP: IconData + SUBTITLES: IconData + SUBTITLES_OFF: IconData + SUBTITLES_OFF_OUTLINED: IconData + SUBTITLES_OFF_ROUNDED: IconData + SUBTITLES_OFF_SHARP: IconData + SUBTITLES_OUTLINED: IconData + SUBTITLES_ROUNDED: IconData + SUBTITLES_SHARP: IconData + SUBWAY: IconData + SUBWAY_OUTLINED: IconData + SUBWAY_ROUNDED: IconData + SUBWAY_SHARP: IconData + SUMMARIZE: IconData + SUMMARIZE_OUTLINED: IconData + SUMMARIZE_ROUNDED: IconData + SUMMARIZE_SHARP: IconData + SUNNY: IconData + SUNNY_SNOWING: IconData + SUPERSCRIPT: IconData + SUPERSCRIPT_OUTLINED: IconData + SUPERSCRIPT_ROUNDED: IconData + SUPERSCRIPT_SHARP: IconData + SUPERVISED_USER_CIRCLE: IconData + SUPERVISED_USER_CIRCLE_OUTLINED: IconData + SUPERVISED_USER_CIRCLE_ROUNDED: IconData + SUPERVISED_USER_CIRCLE_SHARP: IconData + SUPERVISOR_ACCOUNT: IconData + SUPERVISOR_ACCOUNT_OUTLINED: IconData + SUPERVISOR_ACCOUNT_ROUNDED: IconData + SUPERVISOR_ACCOUNT_SHARP: IconData + SUPPORT: IconData + SUPPORT_AGENT: IconData + SUPPORT_AGENT_OUTLINED: IconData + SUPPORT_AGENT_ROUNDED: IconData + SUPPORT_AGENT_SHARP: IconData + SUPPORT_OUTLINED: IconData + SUPPORT_ROUNDED: IconData + SUPPORT_SHARP: IconData + SURFING: IconData + SURFING_OUTLINED: IconData + SURFING_ROUNDED: IconData + SURFING_SHARP: IconData + SURROUND_SOUND: IconData + SURROUND_SOUND_OUTLINED: IconData + SURROUND_SOUND_ROUNDED: IconData + SURROUND_SOUND_SHARP: IconData + SWAP_CALLS: IconData + SWAP_CALLS_OUTLINED: IconData + SWAP_CALLS_ROUNDED: IconData + SWAP_CALLS_SHARP: IconData + SWAP_HORIZ: IconData + SWAP_HORIZ_OUTLINED: IconData + SWAP_HORIZ_ROUNDED: IconData + SWAP_HORIZ_SHARP: IconData + SWAP_HORIZONTAL_CIRCLE: IconData + SWAP_HORIZONTAL_CIRCLE_OUTLINED: IconData + SWAP_HORIZONTAL_CIRCLE_ROUNDED: IconData + SWAP_HORIZONTAL_CIRCLE_SHARP: IconData + SWAP_VERT: IconData + SWAP_VERT_CIRCLE: IconData + SWAP_VERT_CIRCLE_OUTLINED: IconData + SWAP_VERT_CIRCLE_ROUNDED: IconData + SWAP_VERT_CIRCLE_SHARP: IconData + SWAP_VERT_OUTLINED: IconData + SWAP_VERT_ROUNDED: IconData + SWAP_VERT_SHARP: IconData + SWAP_VERTICAL_CIRCLE: IconData + SWAP_VERTICAL_CIRCLE_OUTLINED: IconData + SWAP_VERTICAL_CIRCLE_ROUNDED: IconData + SWAP_VERTICAL_CIRCLE_SHARP: IconData + SWIPE: IconData + SWIPE_DOWN: IconData + SWIPE_DOWN_ALT: IconData + SWIPE_DOWN_ALT_OUTLINED: IconData + SWIPE_DOWN_ALT_ROUNDED: IconData + SWIPE_DOWN_ALT_SHARP: IconData + SWIPE_DOWN_OUTLINED: IconData + SWIPE_DOWN_ROUNDED: IconData + SWIPE_DOWN_SHARP: IconData + SWIPE_LEFT: IconData + SWIPE_LEFT_ALT: IconData + SWIPE_LEFT_ALT_OUTLINED: IconData + SWIPE_LEFT_ALT_ROUNDED: IconData + SWIPE_LEFT_ALT_SHARP: IconData + SWIPE_LEFT_OUTLINED: IconData + SWIPE_LEFT_ROUNDED: IconData + SWIPE_LEFT_SHARP: IconData + SWIPE_OUTLINED: IconData + SWIPE_RIGHT: IconData + SWIPE_RIGHT_ALT: IconData + SWIPE_RIGHT_ALT_OUTLINED: IconData + SWIPE_RIGHT_ALT_ROUNDED: IconData + SWIPE_RIGHT_ALT_SHARP: IconData + SWIPE_RIGHT_OUTLINED: IconData + SWIPE_RIGHT_ROUNDED: IconData + SWIPE_RIGHT_SHARP: IconData + SWIPE_ROUNDED: IconData + SWIPE_SHARP: IconData + SWIPE_UP: IconData + SWIPE_UP_ALT: IconData + SWIPE_UP_ALT_OUTLINED: IconData + SWIPE_UP_ALT_ROUNDED: IconData + SWIPE_UP_ALT_SHARP: IconData + SWIPE_UP_OUTLINED: IconData + SWIPE_UP_ROUNDED: IconData + SWIPE_UP_SHARP: IconData + SWIPE_VERTICAL: IconData + SWIPE_VERTICAL_OUTLINED: IconData + SWIPE_VERTICAL_ROUNDED: IconData + SWIPE_VERTICAL_SHARP: IconData + SWITCH_ACCESS_SHORTCUT: IconData + SWITCH_ACCESS_SHORTCUT_ADD: IconData + SWITCH_ACCESS_SHORTCUT_ADD_OUTLINED: IconData + SWITCH_ACCESS_SHORTCUT_ADD_ROUNDED: IconData + SWITCH_ACCESS_SHORTCUT_ADD_SHARP: IconData + SWITCH_ACCESS_SHORTCUT_OUTLINED: IconData + SWITCH_ACCESS_SHORTCUT_ROUNDED: IconData + SWITCH_ACCESS_SHORTCUT_SHARP: IconData + SWITCH_ACCOUNT: IconData + SWITCH_ACCOUNT_OUTLINED: IconData + SWITCH_ACCOUNT_ROUNDED: IconData + SWITCH_ACCOUNT_SHARP: IconData + SWITCH_CAMERA: IconData + SWITCH_CAMERA_OUTLINED: IconData + SWITCH_CAMERA_ROUNDED: IconData + SWITCH_CAMERA_SHARP: IconData + SWITCH_LEFT: IconData + SWITCH_LEFT_OUTLINED: IconData + SWITCH_LEFT_ROUNDED: IconData + SWITCH_LEFT_SHARP: IconData + SWITCH_RIGHT: IconData + SWITCH_RIGHT_OUTLINED: IconData + SWITCH_RIGHT_ROUNDED: IconData + SWITCH_RIGHT_SHARP: IconData + SWITCH_VIDEO: IconData + SWITCH_VIDEO_OUTLINED: IconData + SWITCH_VIDEO_ROUNDED: IconData + SWITCH_VIDEO_SHARP: IconData + SYNAGOGUE: IconData + SYNAGOGUE_OUTLINED: IconData + SYNAGOGUE_ROUNDED: IconData + SYNAGOGUE_SHARP: IconData + SYNC: IconData + SYNC_ALT: IconData + SYNC_ALT_OUTLINED: IconData + SYNC_ALT_ROUNDED: IconData + SYNC_ALT_SHARP: IconData + SYNC_DISABLED: IconData + SYNC_DISABLED_OUTLINED: IconData + SYNC_DISABLED_ROUNDED: IconData + SYNC_DISABLED_SHARP: IconData + SYNC_LOCK: IconData + SYNC_LOCK_OUTLINED: IconData + SYNC_LOCK_ROUNDED: IconData + SYNC_LOCK_SHARP: IconData + SYNC_OUTLINED: IconData + SYNC_PROBLEM: IconData + SYNC_PROBLEM_OUTLINED: IconData + SYNC_PROBLEM_ROUNDED: IconData + SYNC_PROBLEM_SHARP: IconData + SYNC_ROUNDED: IconData + SYNC_SHARP: IconData + SYSTEM_SECURITY_UPDATE: IconData + SYSTEM_SECURITY_UPDATE_GOOD: IconData + SYSTEM_SECURITY_UPDATE_GOOD_OUTLINED: IconData + SYSTEM_SECURITY_UPDATE_GOOD_ROUNDED: IconData + SYSTEM_SECURITY_UPDATE_GOOD_SHARP: IconData + SYSTEM_SECURITY_UPDATE_OUTLINED: IconData + SYSTEM_SECURITY_UPDATE_ROUNDED: IconData + SYSTEM_SECURITY_UPDATE_SHARP: IconData + SYSTEM_SECURITY_UPDATE_WARNING: IconData + SYSTEM_SECURITY_UPDATE_WARNING_OUTLINED: IconData + SYSTEM_SECURITY_UPDATE_WARNING_ROUNDED: IconData + SYSTEM_SECURITY_UPDATE_WARNING_SHARP: IconData + SYSTEM_UPDATE: IconData + SYSTEM_UPDATE_ALT: IconData + SYSTEM_UPDATE_ALT_OUTLINED: IconData + SYSTEM_UPDATE_ALT_ROUNDED: IconData + SYSTEM_UPDATE_ALT_SHARP: IconData + SYSTEM_UPDATE_OUTLINED: IconData + SYSTEM_UPDATE_ROUNDED: IconData + SYSTEM_UPDATE_SHARP: IconData + SYSTEM_UPDATE_TV: IconData + SYSTEM_UPDATE_TV_OUTLINED: IconData + SYSTEM_UPDATE_TV_ROUNDED: IconData + SYSTEM_UPDATE_TV_SHARP: IconData + TAB: IconData + TAB_OUTLINED: IconData + TAB_ROUNDED: IconData + TAB_SHARP: IconData + TAB_UNSELECTED: IconData + TAB_UNSELECTED_OUTLINED: IconData + TAB_UNSELECTED_ROUNDED: IconData + TAB_UNSELECTED_SHARP: IconData + TABLE_BAR: IconData + TABLE_BAR_OUTLINED: IconData + TABLE_BAR_ROUNDED: IconData + TABLE_BAR_SHARP: IconData + TABLE_CHART: IconData + TABLE_CHART_OUTLINED: IconData + TABLE_CHART_ROUNDED: IconData + TABLE_CHART_SHARP: IconData + TABLE_RESTAURANT: IconData + TABLE_RESTAURANT_OUTLINED: IconData + TABLE_RESTAURANT_ROUNDED: IconData + TABLE_RESTAURANT_SHARP: IconData + TABLE_ROWS: IconData + TABLE_ROWS_OUTLINED: IconData + TABLE_ROWS_ROUNDED: IconData + TABLE_ROWS_SHARP: IconData + TABLE_VIEW: IconData + TABLE_VIEW_OUTLINED: IconData + TABLE_VIEW_ROUNDED: IconData + TABLE_VIEW_SHARP: IconData + TABLET: IconData + TABLET_ANDROID: IconData + TABLET_ANDROID_OUTLINED: IconData + TABLET_ANDROID_ROUNDED: IconData + TABLET_ANDROID_SHARP: IconData + TABLET_MAC: IconData + TABLET_MAC_OUTLINED: IconData + TABLET_MAC_ROUNDED: IconData + TABLET_MAC_SHARP: IconData + TABLET_OUTLINED: IconData + TABLET_ROUNDED: IconData + TABLET_SHARP: IconData + TAG: IconData + TAG_FACES: IconData + TAG_FACES_OUTLINED: IconData + TAG_FACES_ROUNDED: IconData + TAG_FACES_SHARP: IconData + TAG_OUTLINED: IconData + TAG_ROUNDED: IconData + TAG_SHARP: IconData + TAKEOUT_DINING: IconData + TAKEOUT_DINING_OUTLINED: IconData + TAKEOUT_DINING_ROUNDED: IconData + TAKEOUT_DINING_SHARP: IconData + TAP_AND_PLAY: IconData + TAP_AND_PLAY_OUTLINED: IconData + TAP_AND_PLAY_ROUNDED: IconData + TAP_AND_PLAY_SHARP: IconData + TAPAS: IconData + TAPAS_OUTLINED: IconData + TAPAS_ROUNDED: IconData + TAPAS_SHARP: IconData + TASK: IconData + TASK_ALT: IconData + TASK_ALT_OUTLINED: IconData + TASK_ALT_ROUNDED: IconData + TASK_ALT_SHARP: IconData + TASK_OUTLINED: IconData + TASK_ROUNDED: IconData + TASK_SHARP: IconData + TAXI_ALERT: IconData + TAXI_ALERT_OUTLINED: IconData + TAXI_ALERT_ROUNDED: IconData + TAXI_ALERT_SHARP: IconData + TELEGRAM: IconData + TELEGRAM_OUTLINED: IconData + TELEGRAM_ROUNDED: IconData + TELEGRAM_SHARP: IconData + TEMPLE_BUDDHIST: IconData + TEMPLE_BUDDHIST_OUTLINED: IconData + TEMPLE_BUDDHIST_ROUNDED: IconData + TEMPLE_BUDDHIST_SHARP: IconData + TEMPLE_HINDU: IconData + TEMPLE_HINDU_OUTLINED: IconData + TEMPLE_HINDU_ROUNDED: IconData + TEMPLE_HINDU_SHARP: IconData + TEN_K: IconData + TEN_K_OUTLINED: IconData + TEN_K_ROUNDED: IconData + TEN_K_SHARP: IconData + TEN_MP: IconData + TEN_MP_OUTLINED: IconData + TEN_MP_ROUNDED: IconData + TEN_MP_SHARP: IconData + TERMINAL: IconData + TERMINAL_OUTLINED: IconData + TERMINAL_ROUNDED: IconData + TERMINAL_SHARP: IconData + TERRAIN: IconData + TERRAIN_OUTLINED: IconData + TERRAIN_ROUNDED: IconData + TERRAIN_SHARP: IconData + TEXT_DECREASE: IconData + TEXT_DECREASE_OUTLINED: IconData + TEXT_DECREASE_ROUNDED: IconData + TEXT_DECREASE_SHARP: IconData + TEXT_FIELDS: IconData + TEXT_FIELDS_OUTLINED: IconData + TEXT_FIELDS_ROUNDED: IconData + TEXT_FIELDS_SHARP: IconData + TEXT_FORMAT: IconData + TEXT_FORMAT_OUTLINED: IconData + TEXT_FORMAT_ROUNDED: IconData + TEXT_FORMAT_SHARP: IconData + TEXT_INCREASE: IconData + TEXT_INCREASE_OUTLINED: IconData + TEXT_INCREASE_ROUNDED: IconData + TEXT_INCREASE_SHARP: IconData + TEXT_ROTATE_UP: IconData + TEXT_ROTATE_UP_OUTLINED: IconData + TEXT_ROTATE_UP_ROUNDED: IconData + TEXT_ROTATE_UP_SHARP: IconData + TEXT_ROTATE_VERTICAL: IconData + TEXT_ROTATE_VERTICAL_OUTLINED: IconData + TEXT_ROTATE_VERTICAL_ROUNDED: IconData + TEXT_ROTATE_VERTICAL_SHARP: IconData + TEXT_ROTATION_ANGLEDOWN: IconData + TEXT_ROTATION_ANGLEDOWN_OUTLINED: IconData + TEXT_ROTATION_ANGLEDOWN_ROUNDED: IconData + TEXT_ROTATION_ANGLEDOWN_SHARP: IconData + TEXT_ROTATION_ANGLEUP: IconData + TEXT_ROTATION_ANGLEUP_OUTLINED: IconData + TEXT_ROTATION_ANGLEUP_ROUNDED: IconData + TEXT_ROTATION_ANGLEUP_SHARP: IconData + TEXT_ROTATION_DOWN: IconData + TEXT_ROTATION_DOWN_OUTLINED: IconData + TEXT_ROTATION_DOWN_ROUNDED: IconData + TEXT_ROTATION_DOWN_SHARP: IconData + TEXT_ROTATION_NONE: IconData + TEXT_ROTATION_NONE_OUTLINED: IconData + TEXT_ROTATION_NONE_ROUNDED: IconData + TEXT_ROTATION_NONE_SHARP: IconData + TEXT_SNIPPET: IconData + TEXT_SNIPPET_OUTLINED: IconData + TEXT_SNIPPET_ROUNDED: IconData + TEXT_SNIPPET_SHARP: IconData + TEXTSMS: IconData + TEXTSMS_OUTLINED: IconData + TEXTSMS_ROUNDED: IconData + TEXTSMS_SHARP: IconData + TEXTURE: IconData + TEXTURE_OUTLINED: IconData + TEXTURE_ROUNDED: IconData + TEXTURE_SHARP: IconData + THEATER_COMEDY: IconData + THEATER_COMEDY_OUTLINED: IconData + THEATER_COMEDY_ROUNDED: IconData + THEATER_COMEDY_SHARP: IconData + THEATERS: IconData + THEATERS_OUTLINED: IconData + THEATERS_ROUNDED: IconData + THEATERS_SHARP: IconData + THERMOSTAT: IconData + THERMOSTAT_AUTO: IconData + THERMOSTAT_AUTO_OUTLINED: IconData + THERMOSTAT_AUTO_ROUNDED: IconData + THERMOSTAT_AUTO_SHARP: IconData + THERMOSTAT_OUTLINED: IconData + THERMOSTAT_ROUNDED: IconData + THERMOSTAT_SHARP: IconData + THIRTEEN_MP: IconData + THIRTEEN_MP_OUTLINED: IconData + THIRTEEN_MP_ROUNDED: IconData + THIRTEEN_MP_SHARP: IconData + THIRTY_FPS: IconData + THIRTY_FPS_OUTLINED: IconData + THIRTY_FPS_ROUNDED: IconData + THIRTY_FPS_SELECT: IconData + THIRTY_FPS_SELECT_OUTLINED: IconData + THIRTY_FPS_SELECT_ROUNDED: IconData + THIRTY_FPS_SELECT_SHARP: IconData + THIRTY_FPS_SHARP: IconData + THREE_G_MOBILEDATA: IconData + THREE_G_MOBILEDATA_OUTLINED: IconData + THREE_G_MOBILEDATA_ROUNDED: IconData + THREE_G_MOBILEDATA_SHARP: IconData + THREE_K: IconData + THREE_K_OUTLINED: IconData + THREE_K_PLUS: IconData + THREE_K_PLUS_OUTLINED: IconData + THREE_K_PLUS_ROUNDED: IconData + THREE_K_PLUS_SHARP: IconData + THREE_K_ROUNDED: IconData + THREE_K_SHARP: IconData + THREE_MP: IconData + THREE_MP_OUTLINED: IconData + THREE_MP_ROUNDED: IconData + THREE_MP_SHARP: IconData + THREE_P: IconData + THREE_P_OUTLINED: IconData + THREE_P_ROUNDED: IconData + THREE_P_SHARP: IconData + THREED_ROTATION: IconData + THREED_ROTATION_OUTLINED: IconData + THREED_ROTATION_ROUNDED: IconData + THREED_ROTATION_SHARP: IconData + THREESIXTY: IconData + THREESIXTY_OUTLINED: IconData + THREESIXTY_ROUNDED: IconData + THREESIXTY_SHARP: IconData + THUMB_DOWN: IconData + THUMB_DOWN_ALT: IconData + THUMB_DOWN_ALT_OUTLINED: IconData + THUMB_DOWN_ALT_ROUNDED: IconData + THUMB_DOWN_ALT_SHARP: IconData + THUMB_DOWN_OFF_ALT: IconData + THUMB_DOWN_OFF_ALT_OUTLINED: IconData + THUMB_DOWN_OFF_ALT_ROUNDED: IconData + THUMB_DOWN_OFF_ALT_SHARP: IconData + THUMB_DOWN_OUTLINED: IconData + THUMB_DOWN_ROUNDED: IconData + THUMB_DOWN_SHARP: IconData + THUMB_UP: IconData + THUMB_UP_ALT: IconData + THUMB_UP_ALT_OUTLINED: IconData + THUMB_UP_ALT_ROUNDED: IconData + THUMB_UP_ALT_SHARP: IconData + THUMB_UP_OFF_ALT: IconData + THUMB_UP_OFF_ALT_OUTLINED: IconData + THUMB_UP_OFF_ALT_ROUNDED: IconData + THUMB_UP_OFF_ALT_SHARP: IconData + THUMB_UP_OUTLINED: IconData + THUMB_UP_ROUNDED: IconData + THUMB_UP_SHARP: IconData + THUMBS_UP_DOWN: IconData + THUMBS_UP_DOWN_OUTLINED: IconData + THUMBS_UP_DOWN_ROUNDED: IconData + THUMBS_UP_DOWN_SHARP: IconData + THUNDERSTORM: IconData + THUNDERSTORM_OUTLINED: IconData + THUNDERSTORM_ROUNDED: IconData + THUNDERSTORM_SHARP: IconData + TIKTOK: IconData + TIKTOK_OUTLINED: IconData + TIKTOK_ROUNDED: IconData + TIKTOK_SHARP: IconData + TIME_TO_LEAVE: IconData + TIME_TO_LEAVE_OUTLINED: IconData + TIME_TO_LEAVE_ROUNDED: IconData + TIME_TO_LEAVE_SHARP: IconData + TIMELAPSE: IconData + TIMELAPSE_OUTLINED: IconData + TIMELAPSE_ROUNDED: IconData + TIMELAPSE_SHARP: IconData + TIMELINE: IconData + TIMELINE_OUTLINED: IconData + TIMELINE_ROUNDED: IconData + TIMELINE_SHARP: IconData + TIMER: IconData + TIMER_10: IconData + TIMER_10_OUTLINED: IconData + TIMER_10_ROUNDED: IconData + TIMER_10_SELECT: IconData + TIMER_10_SELECT_OUTLINED: IconData + TIMER_10_SELECT_ROUNDED: IconData + TIMER_10_SELECT_SHARP: IconData + TIMER_10_SHARP: IconData + TIMER_3: IconData + TIMER_3_OUTLINED: IconData + TIMER_3_ROUNDED: IconData + TIMER_3_SELECT: IconData + TIMER_3_SELECT_OUTLINED: IconData + TIMER_3_SELECT_ROUNDED: IconData + TIMER_3_SELECT_SHARP: IconData + TIMER_3_SHARP: IconData + TIMER_OFF: IconData + TIMER_OFF_OUTLINED: IconData + TIMER_OFF_ROUNDED: IconData + TIMER_OFF_SHARP: IconData + TIMER_OUTLINED: IconData + TIMER_ROUNDED: IconData + TIMER_SHARP: IconData + TIPS_AND_UPDATES: IconData + TIPS_AND_UPDATES_OUTLINED: IconData + TIPS_AND_UPDATES_ROUNDED: IconData + TIPS_AND_UPDATES_SHARP: IconData + TIRE_REPAIR: IconData + TIRE_REPAIR_OUTLINED: IconData + TIRE_REPAIR_ROUNDED: IconData + TIRE_REPAIR_SHARP: IconData + TITLE: IconData + TITLE_OUTLINED: IconData + TITLE_ROUNDED: IconData + TITLE_SHARP: IconData + TOC: IconData + TOC_OUTLINED: IconData + TOC_ROUNDED: IconData + TOC_SHARP: IconData + TODAY: IconData + TODAY_OUTLINED: IconData + TODAY_ROUNDED: IconData + TODAY_SHARP: IconData + TOGGLE_OFF: IconData + TOGGLE_OFF_OUTLINED: IconData + TOGGLE_OFF_ROUNDED: IconData + TOGGLE_OFF_SHARP: IconData + TOGGLE_ON: IconData + TOGGLE_ON_OUTLINED: IconData + TOGGLE_ON_ROUNDED: IconData + TOGGLE_ON_SHARP: IconData + TOKEN: IconData + TOKEN_OUTLINED: IconData + TOKEN_ROUNDED: IconData + TOKEN_SHARP: IconData + TOLL: IconData + TOLL_OUTLINED: IconData + TOLL_ROUNDED: IconData + TOLL_SHARP: IconData + TONALITY: IconData + TONALITY_OUTLINED: IconData + TONALITY_ROUNDED: IconData + TONALITY_SHARP: IconData + TOPIC: IconData + TOPIC_OUTLINED: IconData + TOPIC_ROUNDED: IconData + TOPIC_SHARP: IconData + TORNADO: IconData + TORNADO_OUTLINED: IconData + TORNADO_ROUNDED: IconData + TORNADO_SHARP: IconData + TOUCH_APP: IconData + TOUCH_APP_OUTLINED: IconData + TOUCH_APP_ROUNDED: IconData + TOUCH_APP_SHARP: IconData + TOUR: IconData + TOUR_OUTLINED: IconData + TOUR_ROUNDED: IconData + TOUR_SHARP: IconData + TOYS: IconData + TOYS_OUTLINED: IconData + TOYS_ROUNDED: IconData + TOYS_SHARP: IconData + TRACK_CHANGES: IconData + TRACK_CHANGES_OUTLINED: IconData + TRACK_CHANGES_ROUNDED: IconData + TRACK_CHANGES_SHARP: IconData + TRAFFIC: IconData + TRAFFIC_OUTLINED: IconData + TRAFFIC_ROUNDED: IconData + TRAFFIC_SHARP: IconData + TRAIN: IconData + TRAIN_OUTLINED: IconData + TRAIN_ROUNDED: IconData + TRAIN_SHARP: IconData + TRAM: IconData + TRAM_OUTLINED: IconData + TRAM_ROUNDED: IconData + TRAM_SHARP: IconData + TRANSCRIBE: IconData + TRANSCRIBE_OUTLINED: IconData + TRANSCRIBE_ROUNDED: IconData + TRANSCRIBE_SHARP: IconData + TRANSFER_WITHIN_A_STATION: IconData + TRANSFER_WITHIN_A_STATION_OUTLINED: IconData + TRANSFER_WITHIN_A_STATION_ROUNDED: IconData + TRANSFER_WITHIN_A_STATION_SHARP: IconData + TRANSFORM: IconData + TRANSFORM_OUTLINED: IconData + TRANSFORM_ROUNDED: IconData + TRANSFORM_SHARP: IconData + TRANSGENDER: IconData + TRANSGENDER_OUTLINED: IconData + TRANSGENDER_ROUNDED: IconData + TRANSGENDER_SHARP: IconData + TRANSIT_ENTEREXIT: IconData + TRANSIT_ENTEREXIT_OUTLINED: IconData + TRANSIT_ENTEREXIT_ROUNDED: IconData + TRANSIT_ENTEREXIT_SHARP: IconData + TRANSLATE: IconData + TRANSLATE_OUTLINED: IconData + TRANSLATE_ROUNDED: IconData + TRANSLATE_SHARP: IconData + TRAVEL_EXPLORE: IconData + TRAVEL_EXPLORE_OUTLINED: IconData + TRAVEL_EXPLORE_ROUNDED: IconData + TRAVEL_EXPLORE_SHARP: IconData + TRENDING_DOWN: IconData + TRENDING_DOWN_OUTLINED: IconData + TRENDING_DOWN_ROUNDED: IconData + TRENDING_DOWN_SHARP: IconData + TRENDING_FLAT: IconData + TRENDING_FLAT_OUTLINED: IconData + TRENDING_FLAT_ROUNDED: IconData + TRENDING_FLAT_SHARP: IconData + TRENDING_NEUTRAL: IconData + TRENDING_NEUTRAL_OUTLINED: IconData + TRENDING_NEUTRAL_ROUNDED: IconData + TRENDING_NEUTRAL_SHARP: IconData + TRENDING_UP: IconData + TRENDING_UP_OUTLINED: IconData + TRENDING_UP_ROUNDED: IconData + TRENDING_UP_SHARP: IconData + TRIP_ORIGIN: IconData + TRIP_ORIGIN_OUTLINED: IconData + TRIP_ORIGIN_ROUNDED: IconData + TRIP_ORIGIN_SHARP: IconData + TROLLEY: IconData + TROUBLESHOOT: IconData + TROUBLESHOOT_OUTLINED: IconData + TROUBLESHOOT_ROUNDED: IconData + TROUBLESHOOT_SHARP: IconData + TRY_SMS_STAR: IconData + TRY_SMS_STAR_OUTLINED: IconData + TRY_SMS_STAR_ROUNDED: IconData + TRY_SMS_STAR_SHARP: IconData + TSUNAMI: IconData + TSUNAMI_OUTLINED: IconData + TSUNAMI_ROUNDED: IconData + TSUNAMI_SHARP: IconData + TTY: IconData + TTY_OUTLINED: IconData + TTY_ROUNDED: IconData + TTY_SHARP: IconData + TUNE: IconData + TUNE_OUTLINED: IconData + TUNE_ROUNDED: IconData + TUNE_SHARP: IconData + TUNGSTEN: IconData + TUNGSTEN_OUTLINED: IconData + TUNGSTEN_ROUNDED: IconData + TUNGSTEN_SHARP: IconData + TURN_LEFT: IconData + TURN_LEFT_OUTLINED: IconData + TURN_LEFT_ROUNDED: IconData + TURN_LEFT_SHARP: IconData + TURN_RIGHT: IconData + TURN_RIGHT_OUTLINED: IconData + TURN_RIGHT_ROUNDED: IconData + TURN_RIGHT_SHARP: IconData + TURN_SHARP_LEFT: IconData + TURN_SHARP_LEFT_OUTLINED: IconData + TURN_SHARP_LEFT_ROUNDED: IconData + TURN_SHARP_LEFT_SHARP: IconData + TURN_SHARP_RIGHT: IconData + TURN_SHARP_RIGHT_OUTLINED: IconData + TURN_SHARP_RIGHT_ROUNDED: IconData + TURN_SHARP_RIGHT_SHARP: IconData + TURN_SLIGHT_LEFT: IconData + TURN_SLIGHT_LEFT_OUTLINED: IconData + TURN_SLIGHT_LEFT_ROUNDED: IconData + TURN_SLIGHT_LEFT_SHARP: IconData + TURN_SLIGHT_RIGHT: IconData + TURN_SLIGHT_RIGHT_OUTLINED: IconData + TURN_SLIGHT_RIGHT_ROUNDED: IconData + TURN_SLIGHT_RIGHT_SHARP: IconData + TURNED_IN: IconData + TURNED_IN_NOT: IconData + TURNED_IN_NOT_OUTLINED: IconData + TURNED_IN_NOT_ROUNDED: IconData + TURNED_IN_NOT_SHARP: IconData + TURNED_IN_OUTLINED: IconData + TURNED_IN_ROUNDED: IconData + TURNED_IN_SHARP: IconData + TV: IconData + TV_OFF: IconData + TV_OFF_OUTLINED: IconData + TV_OFF_ROUNDED: IconData + TV_OFF_SHARP: IconData + TV_OUTLINED: IconData + TV_ROUNDED: IconData + TV_SHARP: IconData + TWELVE_MP: IconData + TWELVE_MP_OUTLINED: IconData + TWELVE_MP_ROUNDED: IconData + TWELVE_MP_SHARP: IconData + TWENTY_FOUR_MP: IconData + TWENTY_FOUR_MP_OUTLINED: IconData + TWENTY_FOUR_MP_ROUNDED: IconData + TWENTY_FOUR_MP_SHARP: IconData + TWENTY_MP: IconData + TWENTY_MP_OUTLINED: IconData + TWENTY_MP_ROUNDED: IconData + TWENTY_MP_SHARP: IconData + TWENTY_ONE_MP: IconData + TWENTY_ONE_MP_OUTLINED: IconData + TWENTY_ONE_MP_ROUNDED: IconData + TWENTY_ONE_MP_SHARP: IconData + TWENTY_THREE_MP: IconData + TWENTY_THREE_MP_OUTLINED: IconData + TWENTY_THREE_MP_ROUNDED: IconData + TWENTY_THREE_MP_SHARP: IconData + TWENTY_TWO_MP: IconData + TWENTY_TWO_MP_OUTLINED: IconData + TWENTY_TWO_MP_ROUNDED: IconData + TWENTY_TWO_MP_SHARP: IconData + TWO_K: IconData + TWO_K_OUTLINED: IconData + TWO_K_PLUS: IconData + TWO_K_PLUS_OUTLINED: IconData + TWO_K_PLUS_ROUNDED: IconData + TWO_K_PLUS_SHARP: IconData + TWO_K_ROUNDED: IconData + TWO_K_SHARP: IconData + TWO_MP: IconData + TWO_MP_OUTLINED: IconData + TWO_MP_ROUNDED: IconData + TWO_MP_SHARP: IconData + TWO_WHEELER: IconData + TWO_WHEELER_OUTLINED: IconData + TWO_WHEELER_ROUNDED: IconData + TWO_WHEELER_SHARP: IconData + TYPE_SPECIMEN: IconData + TYPE_SPECIMEN_OUTLINED: IconData + TYPE_SPECIMEN_ROUNDED: IconData + TYPE_SPECIMEN_SHARP: IconData + U_TURN_LEFT: IconData + U_TURN_LEFT_OUTLINED: IconData + U_TURN_LEFT_ROUNDED: IconData + U_TURN_LEFT_SHARP: IconData + U_TURN_RIGHT: IconData + U_TURN_RIGHT_OUTLINED: IconData + U_TURN_RIGHT_ROUNDED: IconData + U_TURN_RIGHT_SHARP: IconData + UMBRELLA: IconData + UMBRELLA_OUTLINED: IconData + UMBRELLA_ROUNDED: IconData + UMBRELLA_SHARP: IconData + UNARCHIVE: IconData + UNARCHIVE_OUTLINED: IconData + UNARCHIVE_ROUNDED: IconData + UNARCHIVE_SHARP: IconData + UNDO: IconData + UNDO_OUTLINED: IconData + UNDO_ROUNDED: IconData + UNDO_SHARP: IconData + UNFOLD_LESS: IconData + UNFOLD_LESS_DOUBLE: IconData + UNFOLD_LESS_DOUBLE_OUTLINED: IconData + UNFOLD_LESS_DOUBLE_ROUNDED: IconData + UNFOLD_LESS_DOUBLE_SHARP: IconData + UNFOLD_LESS_OUTLINED: IconData + UNFOLD_LESS_ROUNDED: IconData + UNFOLD_LESS_SHARP: IconData + UNFOLD_MORE: IconData + UNFOLD_MORE_DOUBLE: IconData + UNFOLD_MORE_DOUBLE_OUTLINED: IconData + UNFOLD_MORE_DOUBLE_ROUNDED: IconData + UNFOLD_MORE_DOUBLE_SHARP: IconData + UNFOLD_MORE_OUTLINED: IconData + UNFOLD_MORE_ROUNDED: IconData + UNFOLD_MORE_SHARP: IconData + UNPUBLISHED: IconData + UNPUBLISHED_OUTLINED: IconData + UNPUBLISHED_ROUNDED: IconData + UNPUBLISHED_SHARP: IconData + UNSUBSCRIBE: IconData + UNSUBSCRIBE_OUTLINED: IconData + UNSUBSCRIBE_ROUNDED: IconData + UNSUBSCRIBE_SHARP: IconData + UPCOMING: IconData + UPCOMING_OUTLINED: IconData + UPCOMING_ROUNDED: IconData + UPCOMING_SHARP: IconData + UPDATE: IconData + UPDATE_DISABLED: IconData + UPDATE_DISABLED_OUTLINED: IconData + UPDATE_DISABLED_ROUNDED: IconData + UPDATE_DISABLED_SHARP: IconData + UPDATE_OUTLINED: IconData + UPDATE_ROUNDED: IconData + UPDATE_SHARP: IconData + UPGRADE: IconData + UPGRADE_OUTLINED: IconData + UPGRADE_ROUNDED: IconData + UPGRADE_SHARP: IconData + UPLOAD: IconData + UPLOAD_FILE: IconData + UPLOAD_FILE_OUTLINED: IconData + UPLOAD_FILE_ROUNDED: IconData + UPLOAD_FILE_SHARP: IconData + UPLOAD_OUTLINED: IconData + UPLOAD_ROUNDED: IconData + UPLOAD_SHARP: IconData + USB: IconData + USB_OFF: IconData + USB_OFF_OUTLINED: IconData + USB_OFF_ROUNDED: IconData + USB_OFF_SHARP: IconData + USB_OUTLINED: IconData + USB_ROUNDED: IconData + USB_SHARP: IconData + VACCINES: IconData + VACCINES_OUTLINED: IconData + VACCINES_ROUNDED: IconData + VACCINES_SHARP: IconData + VAPE_FREE: IconData + VAPE_FREE_OUTLINED: IconData + VAPE_FREE_ROUNDED: IconData + VAPE_FREE_SHARP: IconData + VAPING_ROOMS: IconData + VAPING_ROOMS_OUTLINED: IconData + VAPING_ROOMS_ROUNDED: IconData + VAPING_ROOMS_SHARP: IconData + VERIFIED: IconData + VERIFIED_OUTLINED: IconData + VERIFIED_ROUNDED: IconData + VERIFIED_SHARP: IconData + VERIFIED_USER: IconData + VERIFIED_USER_OUTLINED: IconData + VERIFIED_USER_ROUNDED: IconData + VERIFIED_USER_SHARP: IconData + VERTICAL_ALIGN_BOTTOM: IconData + VERTICAL_ALIGN_BOTTOM_OUTLINED: IconData + VERTICAL_ALIGN_BOTTOM_ROUNDED: IconData + VERTICAL_ALIGN_BOTTOM_SHARP: IconData + VERTICAL_ALIGN_CENTER: IconData + VERTICAL_ALIGN_CENTER_OUTLINED: IconData + VERTICAL_ALIGN_CENTER_ROUNDED: IconData + VERTICAL_ALIGN_CENTER_SHARP: IconData + VERTICAL_ALIGN_TOP: IconData + VERTICAL_ALIGN_TOP_OUTLINED: IconData + VERTICAL_ALIGN_TOP_ROUNDED: IconData + VERTICAL_ALIGN_TOP_SHARP: IconData + VERTICAL_DISTRIBUTE: IconData + VERTICAL_DISTRIBUTE_OUTLINED: IconData + VERTICAL_DISTRIBUTE_ROUNDED: IconData + VERTICAL_DISTRIBUTE_SHARP: IconData + VERTICAL_SHADES: IconData + VERTICAL_SHADES_CLOSED: IconData + VERTICAL_SHADES_CLOSED_OUTLINED: IconData + VERTICAL_SHADES_CLOSED_ROUNDED: IconData + VERTICAL_SHADES_CLOSED_SHARP: IconData + VERTICAL_SHADES_OUTLINED: IconData + VERTICAL_SHADES_ROUNDED: IconData + VERTICAL_SHADES_SHARP: IconData + VERTICAL_SPLIT: IconData + VERTICAL_SPLIT_OUTLINED: IconData + VERTICAL_SPLIT_ROUNDED: IconData + VERTICAL_SPLIT_SHARP: IconData + VIBRATION: IconData + VIBRATION_OUTLINED: IconData + VIBRATION_ROUNDED: IconData + VIBRATION_SHARP: IconData + VIDEO_CALL: IconData + VIDEO_CALL_OUTLINED: IconData + VIDEO_CALL_ROUNDED: IconData + VIDEO_CALL_SHARP: IconData + VIDEO_CAMERA_BACK: IconData + VIDEO_CAMERA_BACK_OUTLINED: IconData + VIDEO_CAMERA_BACK_ROUNDED: IconData + VIDEO_CAMERA_BACK_SHARP: IconData + VIDEO_CAMERA_FRONT: IconData + VIDEO_CAMERA_FRONT_OUTLINED: IconData + VIDEO_CAMERA_FRONT_ROUNDED: IconData + VIDEO_CAMERA_FRONT_SHARP: IconData + VIDEO_CHAT: IconData + VIDEO_CHAT_OUTLINED: IconData + VIDEO_CHAT_ROUNDED: IconData + VIDEO_CHAT_SHARP: IconData + VIDEO_COLLECTION: IconData + VIDEO_COLLECTION_OUTLINED: IconData + VIDEO_COLLECTION_ROUNDED: IconData + VIDEO_COLLECTION_SHARP: IconData + VIDEO_FILE: IconData + VIDEO_FILE_OUTLINED: IconData + VIDEO_FILE_ROUNDED: IconData + VIDEO_FILE_SHARP: IconData + VIDEO_LABEL: IconData + VIDEO_LABEL_OUTLINED: IconData + VIDEO_LABEL_ROUNDED: IconData + VIDEO_LABEL_SHARP: IconData + VIDEO_LIBRARY: IconData + VIDEO_LIBRARY_OUTLINED: IconData + VIDEO_LIBRARY_ROUNDED: IconData + VIDEO_LIBRARY_SHARP: IconData + VIDEO_SETTINGS: IconData + VIDEO_SETTINGS_OUTLINED: IconData + VIDEO_SETTINGS_ROUNDED: IconData + VIDEO_SETTINGS_SHARP: IconData + VIDEO_STABLE: IconData + VIDEO_STABLE_OUTLINED: IconData + VIDEO_STABLE_ROUNDED: IconData + VIDEO_STABLE_SHARP: IconData + VIDEOCAM: IconData + VIDEOCAM_OFF: IconData + VIDEOCAM_OFF_OUTLINED: IconData + VIDEOCAM_OFF_ROUNDED: IconData + VIDEOCAM_OFF_SHARP: IconData + VIDEOCAM_OUTLINED: IconData + VIDEOCAM_ROUNDED: IconData + VIDEOCAM_SHARP: IconData + VIDEOGAME_ASSET: IconData + VIDEOGAME_ASSET_OFF: IconData + VIDEOGAME_ASSET_OFF_OUTLINED: IconData + VIDEOGAME_ASSET_OFF_ROUNDED: IconData + VIDEOGAME_ASSET_OFF_SHARP: IconData + VIDEOGAME_ASSET_OUTLINED: IconData + VIDEOGAME_ASSET_ROUNDED: IconData + VIDEOGAME_ASSET_SHARP: IconData + VIEW_AGENDA: IconData + VIEW_AGENDA_OUTLINED: IconData + VIEW_AGENDA_ROUNDED: IconData + VIEW_AGENDA_SHARP: IconData + VIEW_ARRAY: IconData + VIEW_ARRAY_OUTLINED: IconData + VIEW_ARRAY_ROUNDED: IconData + VIEW_ARRAY_SHARP: IconData + VIEW_CAROUSEL: IconData + VIEW_CAROUSEL_OUTLINED: IconData + VIEW_CAROUSEL_ROUNDED: IconData + VIEW_CAROUSEL_SHARP: IconData + VIEW_COLUMN: IconData + VIEW_COLUMN_OUTLINED: IconData + VIEW_COLUMN_ROUNDED: IconData + VIEW_COLUMN_SHARP: IconData + VIEW_COMFORTABLE: IconData + VIEW_COMFORTABLE_OUTLINED: IconData + VIEW_COMFORTABLE_ROUNDED: IconData + VIEW_COMFORTABLE_SHARP: IconData + VIEW_COMFY: IconData + VIEW_COMFY_ALT: IconData + VIEW_COMFY_ALT_OUTLINED: IconData + VIEW_COMFY_ALT_ROUNDED: IconData + VIEW_COMFY_ALT_SHARP: IconData + VIEW_COMFY_OUTLINED: IconData + VIEW_COMFY_ROUNDED: IconData + VIEW_COMFY_SHARP: IconData + VIEW_COMPACT: IconData + VIEW_COMPACT_ALT: IconData + VIEW_COMPACT_ALT_OUTLINED: IconData + VIEW_COMPACT_ALT_ROUNDED: IconData + VIEW_COMPACT_ALT_SHARP: IconData + VIEW_COMPACT_OUTLINED: IconData + VIEW_COMPACT_ROUNDED: IconData + VIEW_COMPACT_SHARP: IconData + VIEW_COZY: IconData + VIEW_COZY_OUTLINED: IconData + VIEW_COZY_ROUNDED: IconData + VIEW_COZY_SHARP: IconData + VIEW_DAY: IconData + VIEW_DAY_OUTLINED: IconData + VIEW_DAY_ROUNDED: IconData + VIEW_DAY_SHARP: IconData + VIEW_HEADLINE: IconData + VIEW_HEADLINE_OUTLINED: IconData + VIEW_HEADLINE_ROUNDED: IconData + VIEW_HEADLINE_SHARP: IconData + VIEW_IN_AR: IconData + VIEW_IN_AR_OUTLINED: IconData + VIEW_IN_AR_ROUNDED: IconData + VIEW_IN_AR_SHARP: IconData + VIEW_KANBAN: IconData + VIEW_KANBAN_OUTLINED: IconData + VIEW_KANBAN_ROUNDED: IconData + VIEW_KANBAN_SHARP: IconData + VIEW_LIST: IconData + VIEW_LIST_OUTLINED: IconData + VIEW_LIST_ROUNDED: IconData + VIEW_LIST_SHARP: IconData + VIEW_MODULE: IconData + VIEW_MODULE_OUTLINED: IconData + VIEW_MODULE_ROUNDED: IconData + VIEW_MODULE_SHARP: IconData + VIEW_QUILT: IconData + VIEW_QUILT_OUTLINED: IconData + VIEW_QUILT_ROUNDED: IconData + VIEW_QUILT_SHARP: IconData + VIEW_SIDEBAR: IconData + VIEW_SIDEBAR_OUTLINED: IconData + VIEW_SIDEBAR_ROUNDED: IconData + VIEW_SIDEBAR_SHARP: IconData + VIEW_STREAM: IconData + VIEW_STREAM_OUTLINED: IconData + VIEW_STREAM_ROUNDED: IconData + VIEW_STREAM_SHARP: IconData + VIEW_TIMELINE: IconData + VIEW_TIMELINE_OUTLINED: IconData + VIEW_TIMELINE_ROUNDED: IconData + VIEW_TIMELINE_SHARP: IconData + VIEW_WEEK: IconData + VIEW_WEEK_OUTLINED: IconData + VIEW_WEEK_ROUNDED: IconData + VIEW_WEEK_SHARP: IconData + VIGNETTE: IconData + VIGNETTE_OUTLINED: IconData + VIGNETTE_ROUNDED: IconData + VIGNETTE_SHARP: IconData + VILLA: IconData + VILLA_OUTLINED: IconData + VILLA_ROUNDED: IconData + VILLA_SHARP: IconData + VISIBILITY: IconData + VISIBILITY_OFF: IconData + VISIBILITY_OFF_OUTLINED: IconData + VISIBILITY_OFF_ROUNDED: IconData + VISIBILITY_OFF_SHARP: IconData + VISIBILITY_OUTLINED: IconData + VISIBILITY_ROUNDED: IconData + VISIBILITY_SHARP: IconData + VOICE_CHAT: IconData + VOICE_CHAT_OUTLINED: IconData + VOICE_CHAT_ROUNDED: IconData + VOICE_CHAT_SHARP: IconData + VOICE_OVER_OFF: IconData + VOICE_OVER_OFF_OUTLINED: IconData + VOICE_OVER_OFF_ROUNDED: IconData + VOICE_OVER_OFF_SHARP: IconData + VOICEMAIL: IconData + VOICEMAIL_OUTLINED: IconData + VOICEMAIL_ROUNDED: IconData + VOICEMAIL_SHARP: IconData + VOLCANO: IconData + VOLCANO_OUTLINED: IconData + VOLCANO_ROUNDED: IconData + VOLCANO_SHARP: IconData + VOLUME_DOWN: IconData + VOLUME_DOWN_ALT: IconData + VOLUME_DOWN_OUTLINED: IconData + VOLUME_DOWN_ROUNDED: IconData + VOLUME_DOWN_SHARP: IconData + VOLUME_MUTE: IconData + VOLUME_MUTE_OUTLINED: IconData + VOLUME_MUTE_ROUNDED: IconData + VOLUME_MUTE_SHARP: IconData + VOLUME_OFF: IconData + VOLUME_OFF_OUTLINED: IconData + VOLUME_OFF_ROUNDED: IconData + VOLUME_OFF_SHARP: IconData + VOLUME_UP: IconData + VOLUME_UP_OUTLINED: IconData + VOLUME_UP_ROUNDED: IconData + VOLUME_UP_SHARP: IconData + VOLUNTEER_ACTIVISM: IconData + VOLUNTEER_ACTIVISM_OUTLINED: IconData + VOLUNTEER_ACTIVISM_ROUNDED: IconData + VOLUNTEER_ACTIVISM_SHARP: IconData + VPN_KEY: IconData + VPN_KEY_OFF: IconData + VPN_KEY_OFF_OUTLINED: IconData + VPN_KEY_OFF_ROUNDED: IconData + VPN_KEY_OFF_SHARP: IconData + VPN_KEY_OUTLINED: IconData + VPN_KEY_ROUNDED: IconData + VPN_KEY_SHARP: IconData + VPN_LOCK: IconData + VPN_LOCK_OUTLINED: IconData + VPN_LOCK_ROUNDED: IconData + VPN_LOCK_SHARP: IconData + VRPANO: IconData + VRPANO_OUTLINED: IconData + VRPANO_ROUNDED: IconData + VRPANO_SHARP: IconData + WALLET: IconData + WALLET_GIFTCARD: IconData + WALLET_GIFTCARD_OUTLINED: IconData + WALLET_GIFTCARD_ROUNDED: IconData + WALLET_GIFTCARD_SHARP: IconData + WALLET_MEMBERSHIP: IconData + WALLET_MEMBERSHIP_OUTLINED: IconData + WALLET_MEMBERSHIP_ROUNDED: IconData + WALLET_MEMBERSHIP_SHARP: IconData + WALLET_OUTLINED: IconData + WALLET_ROUNDED: IconData + WALLET_SHARP: IconData + WALLET_TRAVEL: IconData + WALLET_TRAVEL_OUTLINED: IconData + WALLET_TRAVEL_ROUNDED: IconData + WALLET_TRAVEL_SHARP: IconData + WALLPAPER: IconData + WALLPAPER_OUTLINED: IconData + WALLPAPER_ROUNDED: IconData + WALLPAPER_SHARP: IconData + WAREHOUSE: IconData + WAREHOUSE_OUTLINED: IconData + WAREHOUSE_ROUNDED: IconData + WAREHOUSE_SHARP: IconData + WARNING: IconData + WARNING_AMBER: IconData + WARNING_AMBER_OUTLINED: IconData + WARNING_AMBER_ROUNDED: IconData + WARNING_AMBER_SHARP: IconData + WARNING_OUTLINED: IconData + WARNING_ROUNDED: IconData + WARNING_SHARP: IconData + WASH: IconData + WASH_OUTLINED: IconData + WASH_ROUNDED: IconData + WASH_SHARP: IconData + WATCH: IconData + WATCH_LATER: IconData + WATCH_LATER_OUTLINED: IconData + WATCH_LATER_ROUNDED: IconData + WATCH_LATER_SHARP: IconData + WATCH_OFF: IconData + WATCH_OFF_OUTLINED: IconData + WATCH_OFF_ROUNDED: IconData + WATCH_OFF_SHARP: IconData + WATCH_OUTLINED: IconData + WATCH_ROUNDED: IconData + WATCH_SHARP: IconData + WATER: IconData + WATER_DAMAGE: IconData + WATER_DAMAGE_OUTLINED: IconData + WATER_DAMAGE_ROUNDED: IconData + WATER_DAMAGE_SHARP: IconData + WATER_DROP: IconData + WATER_DROP_OUTLINED: IconData + WATER_DROP_ROUNDED: IconData + WATER_DROP_SHARP: IconData + WATER_OUTLINED: IconData + WATER_ROUNDED: IconData + WATER_SHARP: IconData + WATERFALL_CHART: IconData + WATERFALL_CHART_OUTLINED: IconData + WATERFALL_CHART_ROUNDED: IconData + WATERFALL_CHART_SHARP: IconData + WAVES: IconData + WAVES_OUTLINED: IconData + WAVES_ROUNDED: IconData + WAVES_SHARP: IconData + WAVING_HAND: IconData + WAVING_HAND_OUTLINED: IconData + WAVING_HAND_ROUNDED: IconData + WAVING_HAND_SHARP: IconData + WB_AUTO: IconData + WB_AUTO_OUTLINED: IconData + WB_AUTO_ROUNDED: IconData + WB_AUTO_SHARP: IconData + WB_CLOUDY: IconData + WB_CLOUDY_OUTLINED: IconData + WB_CLOUDY_ROUNDED: IconData + WB_CLOUDY_SHARP: IconData + WB_INCANDESCENT: IconData + WB_INCANDESCENT_OUTLINED: IconData + WB_INCANDESCENT_ROUNDED: IconData + WB_INCANDESCENT_SHARP: IconData + WB_IRIDESCENT: IconData + WB_IRIDESCENT_OUTLINED: IconData + WB_IRIDESCENT_ROUNDED: IconData + WB_IRIDESCENT_SHARP: IconData + WB_SHADE: IconData + WB_SHADE_OUTLINED: IconData + WB_SHADE_ROUNDED: IconData + WB_SHADE_SHARP: IconData + WB_SUNNY: IconData + WB_SUNNY_OUTLINED: IconData + WB_SUNNY_ROUNDED: IconData + WB_SUNNY_SHARP: IconData + WB_TWIGHLIGHT: IconData + WB_TWILIGHT: IconData + WB_TWILIGHT_OUTLINED: IconData + WB_TWILIGHT_ROUNDED: IconData + WB_TWILIGHT_SHARP: IconData + WC: IconData + WC_OUTLINED: IconData + WC_ROUNDED: IconData + WC_SHARP: IconData + WEB: IconData + WEB_ASSET: IconData + WEB_ASSET_OFF: IconData + WEB_ASSET_OFF_OUTLINED: IconData + WEB_ASSET_OFF_ROUNDED: IconData + WEB_ASSET_OFF_SHARP: IconData + WEB_ASSET_OUTLINED: IconData + WEB_ASSET_ROUNDED: IconData + WEB_ASSET_SHARP: IconData + WEB_OUTLINED: IconData + WEB_ROUNDED: IconData + WEB_SHARP: IconData + WEB_STORIES: IconData + WEB_STORIES_OUTLINED: IconData + WEB_STORIES_ROUNDED: IconData + WEB_STORIES_SHARP: IconData + WEBHOOK: IconData + WEBHOOK_OUTLINED: IconData + WEBHOOK_ROUNDED: IconData + WEBHOOK_SHARP: IconData + WECHAT: IconData + WECHAT_OUTLINED: IconData + WECHAT_ROUNDED: IconData + WECHAT_SHARP: IconData + WEEKEND: IconData + WEEKEND_OUTLINED: IconData + WEEKEND_ROUNDED: IconData + WEEKEND_SHARP: IconData + WEST: IconData + WEST_OUTLINED: IconData + WEST_ROUNDED: IconData + WEST_SHARP: IconData + WHATSHOT: IconData + WHATSHOT_OUTLINED: IconData + WHATSHOT_ROUNDED: IconData + WHATSHOT_SHARP: IconData + WHEELCHAIR_PICKUP: IconData + WHEELCHAIR_PICKUP_OUTLINED: IconData + WHEELCHAIR_PICKUP_ROUNDED: IconData + WHEELCHAIR_PICKUP_SHARP: IconData + WHERE_TO_VOTE: IconData + WHERE_TO_VOTE_OUTLINED: IconData + WHERE_TO_VOTE_ROUNDED: IconData + WHERE_TO_VOTE_SHARP: IconData + WIDGETS: IconData + WIDGETS_OUTLINED: IconData + WIDGETS_ROUNDED: IconData + WIDGETS_SHARP: IconData + WIDTH_FULL: IconData + WIDTH_FULL_OUTLINED: IconData + WIDTH_FULL_ROUNDED: IconData + WIDTH_FULL_SHARP: IconData + WIDTH_NORMAL: IconData + WIDTH_NORMAL_OUTLINED: IconData + WIDTH_NORMAL_ROUNDED: IconData + WIDTH_NORMAL_SHARP: IconData + WIDTH_WIDE: IconData + WIDTH_WIDE_OUTLINED: IconData + WIDTH_WIDE_ROUNDED: IconData + WIDTH_WIDE_SHARP: IconData + WIFI: IconData + WIFI_1_BAR: IconData + WIFI_1_BAR_OUTLINED: IconData + WIFI_1_BAR_ROUNDED: IconData + WIFI_1_BAR_SHARP: IconData + WIFI_2_BAR: IconData + WIFI_2_BAR_OUTLINED: IconData + WIFI_2_BAR_ROUNDED: IconData + WIFI_2_BAR_SHARP: IconData + WIFI_CALLING: IconData + WIFI_CALLING_3: IconData + WIFI_CALLING_3_OUTLINED: IconData + WIFI_CALLING_3_ROUNDED: IconData + WIFI_CALLING_3_SHARP: IconData + WIFI_CALLING_OUTLINED: IconData + WIFI_CALLING_ROUNDED: IconData + WIFI_CALLING_SHARP: IconData + WIFI_CHANNEL: IconData + WIFI_CHANNEL_OUTLINED: IconData + WIFI_CHANNEL_ROUNDED: IconData + WIFI_CHANNEL_SHARP: IconData + WIFI_FIND: IconData + WIFI_FIND_OUTLINED: IconData + WIFI_FIND_ROUNDED: IconData + WIFI_FIND_SHARP: IconData + WIFI_LOCK: IconData + WIFI_LOCK_OUTLINED: IconData + WIFI_LOCK_ROUNDED: IconData + WIFI_LOCK_SHARP: IconData + WIFI_OFF: IconData + WIFI_OFF_OUTLINED: IconData + WIFI_OFF_ROUNDED: IconData + WIFI_OFF_SHARP: IconData + WIFI_OUTLINED: IconData + WIFI_PASSWORD: IconData + WIFI_PASSWORD_OUTLINED: IconData + WIFI_PASSWORD_ROUNDED: IconData + WIFI_PASSWORD_SHARP: IconData + WIFI_PROTECTED_SETUP: IconData + WIFI_PROTECTED_SETUP_OUTLINED: IconData + WIFI_PROTECTED_SETUP_ROUNDED: IconData + WIFI_PROTECTED_SETUP_SHARP: IconData + WIFI_ROUNDED: IconData + WIFI_SHARP: IconData + WIFI_TETHERING: IconData + WIFI_TETHERING_ERROR: IconData + WIFI_TETHERING_ERROR_OUTLINED: IconData + WIFI_TETHERING_ERROR_ROUNDED: IconData + WIFI_TETHERING_ERROR_ROUNDED_OUTLINED: IconData + WIFI_TETHERING_ERROR_ROUNDED_ROUNDED: IconData + WIFI_TETHERING_ERROR_ROUNDED_SHARP: IconData + WIFI_TETHERING_ERROR_SHARP: IconData + WIFI_TETHERING_OFF: IconData + WIFI_TETHERING_OFF_OUTLINED: IconData + WIFI_TETHERING_OFF_ROUNDED: IconData + WIFI_TETHERING_OFF_SHARP: IconData + WIFI_TETHERING_OUTLINED: IconData + WIFI_TETHERING_ROUNDED: IconData + WIFI_TETHERING_SHARP: IconData + WIND_POWER: IconData + WIND_POWER_OUTLINED: IconData + WIND_POWER_ROUNDED: IconData + WIND_POWER_SHARP: IconData + WINDOW: IconData + WINDOW_OUTLINED: IconData + WINDOW_ROUNDED: IconData + WINDOW_SHARP: IconData + WINE_BAR: IconData + WINE_BAR_OUTLINED: IconData + WINE_BAR_ROUNDED: IconData + WINE_BAR_SHARP: IconData + WOMAN: IconData + WOMAN_2: IconData + WOMAN_2_OUTLINED: IconData + WOMAN_2_ROUNDED: IconData + WOMAN_2_SHARP: IconData + WOMAN_OUTLINED: IconData + WOMAN_ROUNDED: IconData + WOMAN_SHARP: IconData + WOO_COMMERCE: IconData + WOO_COMMERCE_OUTLINED: IconData + WOO_COMMERCE_ROUNDED: IconData + WOO_COMMERCE_SHARP: IconData + WORDPRESS: IconData + WORDPRESS_OUTLINED: IconData + WORDPRESS_ROUNDED: IconData + WORDPRESS_SHARP: IconData + WORK: IconData + WORK_HISTORY: IconData + WORK_HISTORY_OUTLINED: IconData + WORK_HISTORY_ROUNDED: IconData + WORK_HISTORY_SHARP: IconData + WORK_OFF: IconData + WORK_OFF_OUTLINED: IconData + WORK_OFF_ROUNDED: IconData + WORK_OFF_SHARP: IconData + WORK_OUTLINE: IconData + WORK_OUTLINE_OUTLINED: IconData + WORK_OUTLINE_ROUNDED: IconData + WORK_OUTLINE_SHARP: IconData + WORK_OUTLINED: IconData + WORK_ROUNDED: IconData + WORK_SHARP: IconData + WORKSPACE_PREMIUM: IconData + WORKSPACE_PREMIUM_OUTLINED: IconData + WORKSPACE_PREMIUM_ROUNDED: IconData + WORKSPACE_PREMIUM_SHARP: IconData + WORKSPACES: IconData + WORKSPACES_FILLED: IconData + WORKSPACES_OUTLINE: IconData + WORKSPACES_OUTLINED: IconData + WORKSPACES_ROUNDED: IconData + WORKSPACES_SHARP: IconData + WRAP_TEXT: IconData + WRAP_TEXT_OUTLINED: IconData + WRAP_TEXT_ROUNDED: IconData + WRAP_TEXT_SHARP: IconData + WRONG_LOCATION: IconData + WRONG_LOCATION_OUTLINED: IconData + WRONG_LOCATION_ROUNDED: IconData + WRONG_LOCATION_SHARP: IconData + WYSIWYG: IconData + WYSIWYG_OUTLINED: IconData + WYSIWYG_ROUNDED: IconData + WYSIWYG_SHARP: IconData + YARD: IconData + YARD_OUTLINED: IconData + YARD_ROUNDED: IconData + YARD_SHARP: IconData + YOUTUBE_SEARCHED_FOR: IconData + YOUTUBE_SEARCHED_FOR_OUTLINED: IconData + YOUTUBE_SEARCHED_FOR_ROUNDED: IconData + YOUTUBE_SEARCHED_FOR_SHARP: IconData + ZOOM_IN: IconData + ZOOM_IN_MAP: IconData + ZOOM_IN_MAP_OUTLINED: IconData + ZOOM_IN_MAP_ROUNDED: IconData + ZOOM_IN_MAP_SHARP: IconData + ZOOM_IN_OUTLINED: IconData + ZOOM_IN_ROUNDED: IconData + ZOOM_IN_SHARP: IconData + ZOOM_OUT: IconData + ZOOM_OUT_MAP: IconData + ZOOM_OUT_MAP_OUTLINED: IconData + ZOOM_OUT_MAP_ROUNDED: IconData + ZOOM_OUT_MAP_SHARP: IconData + ZOOM_OUT_OUTLINED: IconData + ZOOM_OUT_ROUNDED: IconData + ZOOM_OUT_SHARP: IconData diff --git a/sdk/python/packages/flet/src/flet/controls/material/list_tile.py b/sdk/python/packages/flet/src/flet/controls/material/list_tile.py new file mode 100644 index 0000000000..028039ccca --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/list_tile.py @@ -0,0 +1,325 @@ +from enum import Enum +from typing import Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + MouseCursor, + Number, + StrOrControl, + Url, + VisualDensity, +) + +__all__ = ["ListTile", "ListTileStyle", "ListTileTitleAlignment"] + + +class ListTileTitleAlignment(Enum): + """ + Defines how :class:`~flet.ListTile` aligns :attr:`~flet.ListTile.leading` + and :attr:`~flet.ListTile.trailing` relative to the tile's title area. + + The alignment is computed against the text block formed by + :attr:`~flet.ListTile.title` and :attr:`~flet.ListTile.subtitle`. + Use this to tune the visual balance between icon/avatar controls and text, + especially when tiles switch between one-line, two-line, and three-line layouts. + """ + + TOP = "top" + """ + Aligns :attr:`~flet.ListTile.leading` and :attr:`~flet.ListTile.trailing` + toward the top of the title area. + + Top placement respects :attr:`flet.ListTile.min_vertical_padding`. + """ + + CENTER = "center" + """ + Centers :attr:`~flet.ListTile.leading` and :attr:`~flet.ListTile.trailing` + relative to the title/subtitle block. + """ + + BOTTOM = "bottom" + """ + Aligns :attr:`~flet.ListTile.leading` and :attr:`~flet.ListTile.trailing` + toward the bottom of the title area. + + Bottom placement respects :attr:`flet.ListTile.min_vertical_padding`. + """ + + THREE_LINE = "threeLine" + """ + Uses alignment behavior optimized for three-line list tile layouts. + + This is the default alignment style in Material 3. + """ + + TITLE_HEIGHT = "titleHeight" + """ + Uses alignment behavior based on title-height rules from legacy list tile layouts. + + This is the default alignment style in Material 2. + """ + + +class ListTileStyle(Enum): + """ + Defines the title font used for :class:`~flet.ListTile` + descendants of a :class:`~flet.ListTileTheme`. + + List tiles that appear in a Drawer use the theme's TextTheme.body_large text style, + which is a little smaller than the theme's TextTheme.title_medium text style, which + is used by default. + """ + + LIST = "list" + DRAWER = "drawer" + + +@control("ListTile") +class ListTile(LayoutControl, AdaptiveControl): + """ + A single fixed-height row that typically contains some text as well as a leading \ + or trailing icon. + + Example: + ```python + ft.ListTile( + width=400, + leading=ft.Icon(ft.Icons.ACCOUNT_CIRCLE), + title="Jane Doe", + subtitle="Product Manager", + trailing=ft.Icon(ft.Icons.CHEVRON_RIGHT), + bgcolor=ft.Colors.SURFACE_CONTAINER_LOW, + ) + ``` + """ + + title: Optional[StrOrControl] = None + """ + A control to display as primary content of the list tile. + + Typically a :class:`~flet.Text` control. This should not + wrap. To enforce the single line limit, use :attr:`flet.Text.max_lines`. + """ + + subtitle: Optional[StrOrControl] = None + """ + Additional content displayed below the title. + + If :attr:`is_three_line` is `False`, this should not wrap. + If `is_three_line` is `True`, this should be configured to take a maximum of two + lines. + For example, you can use :attr:`flet.Text.max_lines` to enforce the + number of lines. + + Typically a :class:`~flet.Text` control. + """ + + is_three_line: Optional[bool] = None + """ + Whether this list tile is intended to display three lines of text. + + If `True`, then subtitle must be non-null (since it is expected to give the second + and third lines of text). + + If `False`, the list tile is treated as having one line if the subtitle is null and + treated as having two lines if the subtitle is non-null. + + When using a Text control for title and subtitle, you can enforce line limits + using :attr:`flet.Text.max_lines`. + """ + + leading: Optional[IconDataOrControl] = None + """ + A control to display before the :attr:`title`. + """ + + trailing: Optional[IconDataOrControl] = None + """ + A control to display after the :attr:`title`. + + Typically an :class:`~flet.Icon` control. + """ + + content_padding: Optional[PaddingValue] = None + """ + The tile's internal padding. It insets the contents of this tile. + : its `leading`, `title`, + `subtitle`, and `trailing` controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + The list tile's background color. + """ + + splash_color: Optional[ColorValue] = None + """ + The list tile's splash color after the control has been tapped. + """ + + hover_color: Optional[ColorValue] = None + """ + The tile's color when hovered. Only takes effect if :attr:`toggle_inputs` is True \ + or if :attr:`on_click` is provided. + """ + + selected: bool = False + """ + If this tile is also enabled then icons and text are rendered with the same color. + By default the selected color is the theme's primary color. + """ + + dense: Optional[bool] = None + """ + Whether this list tile is part of a vertically dense list. + + Dense list tiles default to a smaller height. + """ + + autofocus: bool = False + """ + `True` if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + toggle_inputs: bool = False + """ + Whether clicking on a list tile should toggle the state of :class:`~flet.Radio`, \ + :class:`~flet.Checkbox` or :class:`~flet.Switch` inside this tile. + """ + + selected_color: Optional[ColorValue] = None + """ + Defines the color used for icons and text when `selected=True`. + """ + + selected_tile_color: Optional[ColorValue] = None + """ + Defines the background color of ListTile when `selected=True`. + """ + + style: Optional[ListTileStyle] = None + """ + Defines the font used for the title. + + Defaults to `ListTileStyle.LIST`. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. + On Android, for example, setting this to `True` produce a click sound and a + long-press will produce a short vibration. + """ + + horizontal_spacing: Optional[Number] = None + """ + The horizontal gap between the `title` and the :attr:`leading` and \ + :attr:`trailing` + controls. + """ + + min_leading_width: Optional[Number] = None + """ + The minimum width allocated for the `leading` control. + """ + + min_vertical_padding: Optional[Number] = None + """ + The minimum padding on the top and bottom of the `title` and `subtitle` controls. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback is provided, + it is fired after that. + """ + + title_alignment: Optional[ListTileTitleAlignment] = None + """ + Defines how `leading` and `trailing` are vertically aligned relative to the titles \ + (`title` and `subtitle`). + + Defaults to `ListTileTitleAlignment.THREE_LINE` in Material 3 or + `ListTileTitleAlignment.TITLE_HEIGHT` in Material 2. + """ + + icon_color: Optional[ColorValue] = None + """ + Defines the default color for the icons present in :attr:`leading` and \ + :attr:`trailing`. + """ + + text_color: Optional[ColorValue] = None + """ + The color used for texts in :attr:`title`, :attr:`subtitle`, :attr:`leading`, and \ + :attr:`trailing`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The tile's shape. + """ + + visual_density: Optional[VisualDensity] = None + """ + Defines how compact the control's layout will be. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + control. The value is :class:`~flet.MouseCursor` + enum. + """ + + title_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` for the :attr:`title` + control. + """ + + subtitle_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` for the `subtitle` control. + """ + + leading_and_trailing_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` for the `leading` and `trailing` controls. + """ + + min_height: Optional[Number] = None + """ + The minimum height allocated for this control. + + If `None` or not set, default tile heights are `56.0`, `72.0`, and `88.0` for one, + two, and three lines of text respectively. + If :attr:`dense` is `True`, these + defaults are changed to `48.0`, `64.0`, and `76.0`. + + Note that, a visual density value or a large title will also adjust the default + tile heights. + """ + + on_click: Optional[ControlEventHandler["ListTile"]] = None + """ + Called when a user clicks or taps the list tile. + """ + + on_long_press: Optional[ControlEventHandler["ListTile"]] = None + """ + Called when the user long-presses on this list tile. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/menu_bar.py b/sdk/python/packages/flet/src/flet/controls/material/menu_bar.py new file mode 100644 index 0000000000..3b2c05a6b3 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/menu_bar.py @@ -0,0 +1,169 @@ +from dataclasses import field +from typing import Annotated, Optional + +from flet.controls.alignment import Alignment +from flet.controls.base_control import control, value +from flet.controls.border import BorderSide +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_state import ControlStateValue +from flet.controls.geometry import Size +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ClipBehavior, + ColorValue, + MouseCursor, + Number, + VisualDensity, +) +from flet.utils.validation import V + +__all__ = ["MenuBar", "MenuStyle"] + + +@value +class MenuStyle: + """ + Defines the visual style/appearance of a menu. + """ + + alignment: Optional[Alignment] = None + """ + Determines the desired alignment of the submenu when opened relative to + the button that opens it. + + If there isn't sufficient space to open the menu with the given alignment, + and there's space on the other side of the button, then the alignment is + swapped to it's opposite (`1` becomes `-1`, etc.), and the menu will try to + appear on the other side of the button. If there isn't enough space there + either, then the menu will be pushed as far over as necessary to display + as much of itself as possible, possibly overlapping the parent button. + """ + + bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + The menu's background fill color. + """ + + shadow_color: Optional[ControlStateValue[ColorValue]] = None + """ + The shadow color of the menu + + The material's elevation shadow can be difficult to see for dark themes, + so by default the menu classes add a semi-transparent overlay to indicate + elevation. + """ + + elevation: Optional[ControlStateValue[Optional[Number]]] = None + """ + The menu's elevation, i.e. the size of the shadow below the menu. + """ + + padding: Optional[ControlStateValue[PaddingValue]] = None + """ + The padding between the menu's boundary and its child. + """ + + side: Optional[ControlStateValue[BorderSide]] = None + """ + The color and weight of the menu's outline. + + This value is combined with :attr:`shape` to create a + shape decorated with an outline. + """ + + shape: Optional[ControlStateValue[OutlinedBorder]] = None + """ + The menu's shape. + + This shape is combined with :attr:`side` to create a + shape decorated with an outline. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + The cursor for a mouse pointer when it enters or is hovering over the menu. + """ + + fixed_size: Optional[ControlStateValue[Size]] = None + """ + The menu's size. + + This size is still constrained by the style's :attr:`min_size` and + :attr:`max_size`. Fixed size dimensions whose value is `float('inf')` are + ignored. + + To specify menus with a fixed width and the default height use + `Size.from_width(320)`. Similarly, to specify a fixed height and the default + width use `Size.from_height(100)`. + """ + + max_size: Optional[ControlStateValue[Size]] = None + """ + The maximum size of the menu itself. + + A :meth:`flet.Size.infinite` or `None` value for this property + means that the menu's maximum size is not constrained. + + This value must be greater than or equal to :attr:`min_size`. + """ + + min_size: Optional[ControlStateValue[Size]] = None + """ + The minimum size of the menu itself. + + This value must be less than or equal to :attr:`max_size`. + """ + + visual_density: Optional[VisualDensity] = None + """ + Defines how compact the menu's layout will be. + """ + + +@control("MenuBar") +class MenuBar(Control): + """ + A menu bar that manages cascading child menus. + + It could be placed anywhere but typically resides above the main body of the + application and defines a menu system for invoking callbacks in response to user + selection of a menu item. + + ```python + ft.MenuBar( + controls=[ + ft.SubmenuButton( + content=ft.Text("Submenu"), + controls=[ + ft.MenuItemButton(content=ft.Text("Item 1")), + ft.MenuItemButton(content=ft.Text("Item 2")), + ft.MenuItemButton(content=ft.Text("Item 3")), + ], + ), + ], + ) + ``` + + """ + + controls: Annotated[ + list[Control], + V.visible_controls(min_count=1), + ] = field(default_factory=list) + """ + A list of top-level menu controls to display in this menu bar. + + Raises: + ValueError: If it does not contain at least one visible `Control`. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + Whether to clip the content of this control or not. + """ + + style: Optional[MenuStyle] = None + """ + The menu bar style. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/menu_item_button.py b/sdk/python/packages/flet/src/flet/controls/material/menu_item_button.py new file mode 100644 index 0000000000..76c92ca0bb --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/menu_item_button.py @@ -0,0 +1,119 @@ +from typing import Optional + +from flet.controls.alignment import Axis +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ClipBehavior, StrOrControl + +__all__ = ["MenuItemButton"] + + +@control("MenuItemButton") +class MenuItemButton(LayoutControl): + """ + A button for use in a MenuBar or on its own, that can be activated by click or \ + keyboard navigation. + + ```python + ft.Row( + controls=[ + ft.MenuItemButton( + content=ft.Text("Yes"), + on_click=lambda e: print("yes"), + ), + ft.MenuItemButton( + content=ft.Text("No"), + on_click=lambda e: print("no"), + ), + ft.MenuItemButton( + content=ft.Text("Maybe"), + on_click=lambda e: print("maybe"), + ), + ], + ) + ``` + + """ + + content: Optional[StrOrControl] = None + """ + The child control or text to be displayed in the center of this button. + + Typically this is the button's label, using a `Text` control. + """ + + close_on_click: bool = True + """ + Defines if the menu will be closed when the `MenuItemButton` is clicked. + """ + + focus_on_hover: bool = True + """ + Determine if hovering can request focus. + """ + + leading: Optional[Control] = None + """ + An optional control to display before the `content`. + + Typically an :class:`~flet.Icon` control. + """ + + trailing: Optional[Control] = None + """ + An optional control to display after the `content`. + + Typically an :class:`~flet.Icon` control. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + Whether to clip the content of this control or not. + """ + + style: Optional[ButtonStyle] = None + """ + Customizes this button's appearance. + """ + + semantic_label: Optional[str] = None + """ + A string that describes the button's action to assistive technologies. + """ + + autofocus: bool = False + """ + Whether this button should automatically request focus. + + Defaults to `False`. + """ + + overflow_axis: Axis = Axis.HORIZONTAL + """ + The direction in which the menu item expands. + + If the menu item button is a descendent of `MenuBar`, then this property is ignored. + """ + + on_click: Optional[ControlEventHandler["MenuItemButton"]] = None + """ + Called when the button is clicked.If not defined the button will be disabled. + """ + + on_hover: Optional[ControlEventHandler["MenuItemButton"]] = None + """ + Called when the button is hovered. + """ + + on_focus: Optional[ControlEventHandler["MenuItemButton"]] = None + """ + Called when the button receives focus. + """ + + on_blur: Optional[ControlEventHandler["MenuItemButton"]] = None + """ + Called when this button loses focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py b/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py new file mode 100644 index 0000000000..cef09dee1b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/navigation_bar.py @@ -0,0 +1,207 @@ +from dataclasses import field +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.border import Border +from flet.controls.buttons import OutlinedBorder +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.duration import DurationValue +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, +) +from flet.utils.validation import V + +__all__ = ["NavigationBar", "NavigationBarDestination", "NavigationBarLabelBehavior"] + + +class NavigationBarLabelBehavior(Enum): + """ + Defines how the destinations' labels will be laid out and when they'll be \ + displayed. + """ + + ALWAYS_SHOW = "alwaysShow" + ALWAYS_HIDE = "alwaysHide" + ONLY_SHOW_SELECTED = "onlyShowSelected" + + +@control("NavigationBarDestination") +class NavigationBarDestination(AdaptiveControl): + """ + Defines the appearance of the button items that are arrayed within the navigation \ + bar. + + The value must be a list of two or more NavigationBarDestination instances. + """ + + icon: IconDataOrControl + """ + The [name of the icon](https://flet.dev/docs/types/icons) or `Control` of the \ + destination. + + Example with icon name: + ``` + icon=ft.Icons.BOOKMARK + ``` + Example with Control: + ``` + icon=ft.Icon(ft.Icons.BOOKMARK) + ``` + + If `selected_icon` is provided, this will only be displayed when the destination is + not selected. + + To make the NavigationBar more accessible, consider choosing an icon with a stroked + and filled version, such as `ft.Icons.CLOUD` and `ft.Icons.CLOUD_QUEUE`. The icon + should be set to the stroked version and `selected_icon` to the filled version. + """ + + label: Optional[str] = None + """ + The text label that appears below the icon of this `NavigationBarDestination`. + """ + + selected_icon: Optional[IconDataOrControl] = None + """ + The [name](https://flet.dev/docs/types/icons) of alternative icon or `Control` \ + displayed when this destination is selected. + + Example with icon name: + ``` + selected_icon=ft.Icons.BOOKMARK + ``` + Example with Control: + ``` + selected_icon=ft.Icon(ft.Icons.BOOKMARK) + ``` + + If this icon is not provided, the NavigationBar will display `icon` in either state. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color of this destination. + """ + + +@control("NavigationBar") +class NavigationBar(LayoutControl, AdaptiveControl): + """ + Material 3 Navigation Bar component. + + Navigation bars offer a persistent and convenient way to switch between primary + destinations in an app. + + ```python + ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.CIRCLE, label="Item 1"), + ft.NavigationBarDestination(icon=ft.Icons.SQUARE, label="Item 2"), + ft.NavigationBarDestination(icon=ft.Icons.HEXAGON, label="Item 3"), + ], + ) + ``` + + """ + + destinations: Annotated[ + list[NavigationBarDestination], + V.visible_controls(min_count=2), + ] = field(default_factory=list) + """ + Defines the appearance of the button items that are arrayed within the navigation \ + bar. + + Raises: + ValueError: If it does not contain at least two visible destinations. + """ + + selected_index: int = 0 + """ + The index into `destinations` for the current selected `NavigationBarDestination` \ + or `None` if no destination is selected. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color of the navigation bar itself. + """ + + label_behavior: Optional[NavigationBarLabelBehavior] = None + """ + Defines how the destinations' labels will be laid out and when they'll be \ + displayed. + + Can be used to show all labels, show only the selected label, or hide all labels. + + Defaults to `NavigationBarLabelBehavior.ALWAYS_SHOW`. + """ + + label_padding: Optional[PaddingValue] = None + """ + The padding around the :attr:`flet.NavigationBarDestination.label`. + """ + + elevation: Optional[Number] = None + """ + The elevation of the navigation bar itself. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color used for the drop shadow to indicate `elevation`. + """ + + indicator_color: Optional[ColorValue] = None + """ + The color of the selected destination indicator. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + The shape of the selected destination indicator. + """ + + border: Optional[Border] = None + """ + TBD + """ + + animation_duration: Optional[DurationValue] = None + """ + The transition time for each destination as it goes between selected and \ + unselected. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The highlight color of the `NavigationBarDestination` in various \ + :class:`~flet.ControlState` states. + + The following :class:`~flet.ControlState` + values are supported: `PRESSED`, `HOVERED` and `FOCUSED`. + """ + + on_change: Optional[ControlEventHandler["NavigationBar"]] = None + """ + Called when selected destination changed. + """ + + def before_update(self): + super().before_update() + visible_destinations_count = len([d for d in self.destinations if d.visible]) + if visible_destinations_count >= 2 and not ( + 0 <= self.selected_index < visible_destinations_count + ): + raise IndexError( + f"selected_index ({self.selected_index}) is out of range. " + f"Expected a value between 0 and {visible_destinations_count - 1} " + "inclusive." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py b/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py new file mode 100644 index 0000000000..fb55dbd330 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/navigation_drawer.py @@ -0,0 +1,167 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.padding import Padding, PaddingValue +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, + StrOrControl, +) + +__all__ = [ + "NavigationDrawer", + "NavigationDrawerDestination", +] + + +@control("NavigationDrawerDestination") +class NavigationDrawerDestination(Control): + """ + A :class:`~NavigationDrawer` destination. + """ + + label: StrOrControl + """ + The label that appears alongside the :attr:`icon` of this destination. + """ + + icon: IconDataOrControl + """ + An icon name (or `Control`) that's displayed for this destination. + + If :attr:`selected_icon` is provided, `icon` will only be displayed when this + destination is not selected. + + The icon will use :attr:`flet.NavigationDrawerTheme.icon_theme`. If this is + `None`, the default :class:`~flet.IconTheme` would use a size of `24.0` and + :attr:`flet.ColorScheme.on_surface_variant`. + """ + + selected_icon: Optional[IconDataOrControl] = None + """ + An icon name (or `Control`) that's displayed for this destination when selected. + + If provided, this destination will fade from :attr:`icon` to `selected_icon` + when this destination goes from unselected to selected state. + + If not provided, :attr:`icon` will be displayed for both + selected and unselected states. + + The icon will use :attr:`flet.NavigationDrawerTheme.icon_theme` with + :attr:`flet.ControlState.SELECTED`. If this is `None`, the default + :class:`~flet.IconTheme` would use a size of `24.0` and + :attr:`flet.ColorScheme.on_secondary_container`. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of the whole rectangular area behind this drawer destination. + + To customize only the indicator color consider using + :attr:`flet.NavigationDrawer.indicator_color`. + + If it is `None`, no background color is set for this destination and + :class:`~flet.NavigationDrawer.bgcolor` will be visible. + """ + + +@control("NavigationDrawer") +class NavigationDrawer(AdaptiveControl): + """ + Material Design Navigation Drawer component. + + Navigation Drawer is a panel that slides in horizontally from the left or right + edge of the view to show primary destinations in an app. + + Example: + ```python + ft.NavigationDrawer( + tile_padding=ft.Padding(top=10), + controls=[ + ft.NavigationDrawerDestination( + icon=ft.Icons.HOME_OUTLINED, + label="Item 1", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.MAIL_OUTLINED, + label="Item 2", + ), + ft.NavigationDrawerDestination( + icon=ft.Icons.SETTINGS_OUTLINED, + label="Item 3", + ), + ], + ) + ``` + """ + + controls: list[Control] = field(default_factory=list) + """ + The list of items to display in this drawer. + + The list typically contains :class:`~flet.NavigationDrawerDestination` + items and/or other controls such as headlines, padding containers, and dividers. + """ + + selected_index: int = 0 + """ + The index for the currently selected :class:`~flet.NavigationDrawerDestination`. + + A valid `selected_index` is an integer between `0` and the number of + destinations minus `1`. For an invalid value, for example `-1`, all + destinations will appear unselected. + """ + + bgcolor: Optional[ColorValue] = None + """ + The color of this navigation drawer. + """ + + elevation: Optional[Number] = None + """ + The elevation of this navigation drawer. + """ + + width: Optional[Number] = None + """ + Width of the drawer in logical pixels. When `None`, falls back to the + Material default (~304dp). + """ + + indicator_color: Optional[ColorValue] = None + """ + The color of the selected destination indicator. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + The shape of the selected destination indicator. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color used for the drop shadow to indicate :attr:`elevation`. + """ + + tile_padding: PaddingValue = field( + default_factory=lambda: Padding.symmetric(horizontal=12) + ) + """ + Defines the padding around destination tiles inside the drawer. + """ + + on_change: Optional[ControlEventHandler["NavigationDrawer"]] = None + """ + Called when the selected destination changed. + """ + + on_dismiss: Optional[ControlEventHandler["NavigationDrawer"]] = None + """ + Called when this drawer is dismissed. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/navigation_rail.py b/sdk/python/packages/flet/src/flet/controls/material/navigation_rail.py new file mode 100644 index 0000000000..e9bf9b9203 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/navigation_rail.py @@ -0,0 +1,318 @@ +from dataclasses import field +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconDataOrControl, + Number, + StrOrControl, +) +from flet.utils.validation import V + +__all__ = ["NavigationRail", "NavigationRailDestination", "NavigationRailLabelType"] + + +class NavigationRailLabelType(Enum): + """ + Defines how destination labels are shown in a :class:`~flet.NavigationRail`. + + This setting affects the non-extended rail layout + (:attr:`~flet.NavigationRail.extended`). When the rail is + extended, labels are shown next to icons regardless of this value. + """ + + NONE = "none" + """ + Hides labels for all destinations. + + Only destination icons are shown. + """ + + ALL = "all" + """ + Shows labels for all destinations. + """ + + SELECTED = "selected" + """ + Shows the label only for the selected destination. + + As selection changes, the visible label transitions to the newly selected + destination. + """ + + +@control("NavigationRailDestination") +class NavigationRailDestination(Control): + """ + Represents a destination in a `NavigationRail`. + """ + + icon: IconDataOrControl + """ + The [name of the icon](https://flet.dev/docs/types/icons) or `Control` of the \ + destination. + + If :attr:`selected_icon` is provided, this will only be displayed when the + destination is not selected. + + To make the NavigationRail more accessible, consider choosing an icon with a stroked + and filled version, such as `Icons.CLOUD` and `Icons.CLOUD_QUEUE`. The icon + should be set to the stroked version and `selected_icon` to the filled version. + """ + + selected_icon: Optional[IconDataOrControl] = None + """ + The [name](https://flet.dev/docs/types/icons) of alternative icon or `Control` \ + displayed when this destination is selected. + + If this icon is not provided, the NavigationRail will display `icon` in either + state. + """ + + label: Optional[StrOrControl] = None + """ + A string or Control representing the destination's label. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of space to inset the destination item. + """ + + indicator_color: Optional[ColorValue] = None + """ + The color of the :attr:`indicator_shape` when this destination is selected. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + The shape of the selection indicator. + """ + + +@control("NavigationRail") +class NavigationRail(LayoutControl): + """ + A material widget that is meant to be displayed at the left or right of an app to \ + navigate between a small number of views, typically between three and five. + + Example: + ```python + ft.NavigationRail( + selected_index=0, + height=200, + width=100, + destinations=[ + ft.NavigationRailDestination(icon=ft.Icons.STAR, label="Star"), + ft.NavigationRailDestination(icon=ft.Icon(ft.Icons.ADD),label="Add"), + ft.NavigationRailDestination(icon=ft.Icons.DELETE, label=ft.Text("Delete") + ], + ) + ``` + + """ + + destinations: list[NavigationRailDestination] = field(default_factory=list) + """ + Defines the appearance of the button items that are arrayed within the navigation \ + rail. + + The value must be a list of two or more `NavigationRailDestination` instances. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + Controls the size of the shadow below the NavigationRail. + + Defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + selected_index: Optional[int] = None + """ + The index into `destinations` for the current selected `NavigationRailDestination` \ + or `None` if no destination is selected. + """ + + extended: bool = False + """ + Indicates that the NavigationRail should be in the extended state. + + The extended state has a wider rail container, and the labels are positioned next to + the icons. `min_extended_width` can be used to set the minimum width of the rail + when it is in this state. + + The rail will implicitly animate between the extended and normal state. + + If the rail is going to be in the extended state, then + :attr:`label_type` should be set to :attr:`flet.NavigationRailLabelType.NONE` + """ + + label_type: Optional[NavigationRailLabelType] = None + """ + Defines the layout and behavior of the labels for the default, unextended \ + navigation rail. + + When a navigation rail is extended, the labels are always shown. + + Defaults to `None` - no labels are shown. + """ + + bgcolor: Optional[ColorValue] = None + """ + Sets the color of the Container that holds all of this NavigationRail's contents. + """ + + indicator_color: Optional[ColorValue] = None + """ + The color of the navigation rail's indicator. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + The shape of the navigation rail's indicator. + + Defaults to :class:`~flet.StadiumBorder`. + """ + + leading: Optional[Control] = None + """ + An optional leading control in the rail that is placed above the destinations. + + Its location is not affected by `group_alignment`. + + Typically a :class:`~flet.FloatingActionButton`, but + may also be a non-button, such as a logo. + """ + + trailing: Optional[Control] = None + """ + An optional trailing control in the rail that is placed below the destinations. + + Its location is affected by `group_alignment`. + + This is commonly a list of additional options or destinations that is usually only + rendered when `extended=True`. + """ + + pin_leading_to_top: bool = True + """ + Whether to pin the :attr:`leading` control to the top of the rail. + + If `False`, the leading control becomes part of the main group together with the + destinations and participates in scrolling/alignment. + """ + + pin_trailing_to_bottom: bool = False + """ + Whether to pin the :attr:`trailing` control to the bottom of the rail. + + If `False`, the trailing control becomes part of the main group together with the + destinations and participates in scrolling/alignment. + """ + + scrollable: bool = False + """ + Whether the main group of :attr:`destinations` should become scrollable when \ + vertical space is insufficient. + + When :attr:`pin_leading_to_top` or :attr:`pin_trailing_to_bottom` are + `False`, the respective controls also become part of the scrollable group. + """ + + min_width: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The smallest possible width for the rail regardless of the destination's icon or \ + label size. + + Defaults to `72`. + + This value also defines the min width and min height of the destinations. + + To make a compact rail, set this to `56` and set + :attr:`label_type` to :attr:`flet.NavigationRailLabelType.NONE` + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + min_extended_width: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The final width when the animation is complete for setting `extended` to `True`. + + Defaults to `256`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + group_alignment: Optional[Number] = None + """ + The vertical alignment for the group of destinations within the rail. + + The NavigationRailDestinations are grouped together with the trailing widget, + between the leading widget and the bottom of the rail. + + The value must be between `-1.0` and `1.0`. + + If `group_alignment` is `-1.0`, then the items are aligned to the top. If + `group_alignment` is `0.0`, then the items are aligned to the center. If + `group_alignment` is `1.0`, then the items are aligned to the bottom. + + Defaults to `-1.0`. + """ + + selected_label_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` of a destination's label when it is selected. + + When a destination is not selected, `unselected_label_text_style` will instead be + used. + """ + + unselected_label_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` of a destination's label when it is not selected. + + When a destination is selected, `selected_label_text_style` will instead be used. + """ + + use_indicator: Optional[bool] = None + """ + Whether to add a rounded navigation indicator behind the selected destination's icon. + + The indicator's shape will be circular if :attr:`label_type` + is :attr:`flet.NavigationRailLabelType.NONE`, or a + :class:`~flet.StadiumBorder` if :attr:`label_type` + is :attr:`flet.NavigationRailLabelType.ALL` or + :attr:`flet.NavigationRailLabelType.SELECTED`. + + If `None`, defaults to + :attr:`flet.NavigationRailTheme.use_indicator`. + If that is also `None`, defaults to :attr:`flet.Theme.use_material3`. + """ # noqa: E501 + + on_change: Optional[ControlEventHandler["NavigationRail"]] = None + """ + Called when selected destination changed. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py b/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py new file mode 100644 index 0000000000..1ad232cdda --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/outlined_button.py @@ -0,0 +1,125 @@ +from typing import Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.icon_data import IconData +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ClipBehavior, + ColorValue, + IconDataOrControl, + StrOrControl, + Url, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["OutlinedButton"] + + +@control("OutlinedButton") +class OutlinedButton(LayoutControl, AdaptiveControl): + """ + Outlined buttons are medium-emphasis buttons. They contain actions that are \ + important, but aren't the primary action in an app. Outlined buttons pair well \ + with filled buttons to indicate an alternative, secondary action. + + Example: + ```python + ft.OutlinedButton(content="Outlined button") + ``` + """ + + content: Optional[StrOrControl] = None + """ + A Control representing custom button content. + + Raises: + ValueError: If neither :attr:`icon` nor `content` is provided. + """ + + icon: Optional[IconDataOrControl] = None + """ + An icon to display in this button. + """ + + icon_color: Optional[ColorValue] = None + """ + Icon color. + """ + + style: Optional[ButtonStyle] = None + """ + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. + + If there is more than one control on a page with autofocus set, then the first one + added to the page will get focus. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + The content will be clipped (or not) according to this option. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback is + provided, it is fired after that. + """ + + on_click: Optional[ControlEventHandler["OutlinedButton"]] = None + """ + Called when a user clicks this button. + """ + + on_long_press: Optional[ControlEventHandler["OutlinedButton"]] = None + """ + Called when this button is long-pressed. + """ + + on_hover: Optional[ControlEventHandler["OutlinedButton"]] = None + """ + Called when a mouse pointer enters or exists this button's response area. + + `data` property of event object contains `true` (string) when cursor enters and + `false` when it exits. + """ + + on_focus: Optional[ControlEventHandler["OutlinedButton"]] = None + """ + Called when this button has received focus. + """ + + on_blur: Optional[ControlEventHandler["OutlinedButton"]] = None + """ + Called when this button has lost focus. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.icon, IconData) + or (isinstance(ctrl.icon, Control) and ctrl.icon.visible) + ) + or ( + isinstance(ctrl.content, str) + or (isinstance(ctrl.content, Control) and ctrl.content.visible) + ) + ), + message="at minimum, icon or content (string or visible Control) " + "must be provided", + ), + ) + + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py b/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py new file mode 100644 index 0000000000..9be3b6cba3 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/popup_menu_button.py @@ -0,0 +1,235 @@ +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.animation import AnimationStyle +from flet.controls.base_control import control +from flet.controls.box import BoxConstraints +from flet.controls.buttons import ButtonStyle, OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ClipBehavior, + ColorValue, + IconDataOrControl, + MouseCursor, + Number, + StrOrControl, +) + + +class PopupMenuPosition(Enum): + """ + Used to configure how the :class:`~flet.PopupMenuButton` positions its popup menu. + """ + + OVER = "over" + """ + Menu is positioned over the anchor. + """ + + UNDER = "under" + """ + Menu is positioned under the anchor. + """ + + +@control("PopupMenuItem") +class PopupMenuItem(Control): + """ + A popup menu item. + """ + + content: Optional[StrOrControl] = None + """ + A `Control` representing custom content of this menu item. + """ + + icon: Optional[IconDataOrControl] = None + """ + An icon to draw before the text label of this menu item. + """ + + checked: Optional[bool] = None + """ + Whether this menu item is checked. + + If set to `True`, a checkmark will be shown on the left of the + :attr:`content`. + """ + + height: Number = 48.0 + """ + The minimum height of this menu item. + """ + + padding: Optional[PaddingValue] = None + """ + The padding of this menu item. + + Defaults to `Padding.symmetric(horizontal=12)`. + + Note: + The :attr:`height` value of this menu item may + influence the applied padding. + + For example, if a `height` greater than the height of the sum of the padding + and a :attr:`content` is provided, then the padding's + effect will not be visible. + """ + + label_text_style: Optional[TextStyle] = None + """ + The text style of the label of this menu item.""" + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + item. + """ + + on_click: Optional[ControlEventHandler["PopupMenuItem"]] = None + """ + Called when a user clicks on this menu item. + """ + + +@control("PopupMenuButton") +class PopupMenuButton(LayoutControl): + """ + An icon button which displays a menu when clicked. + + ```python + ft.PopupMenuButton( + items=[ + ft.PopupMenuItem(content="Sm"), + ft.PopupMenuItem(content="Med"), + ft.PopupMenuItem(content="Lg"), + ], + menu_position=ft.PopupMenuPosition.UNDER, + ) + ``` + + """ + + content: Optional[StrOrControl] = None + """ + A `Control` that will be displayed instead of "more" icon. + """ + + items: list[PopupMenuItem] = field(default_factory=list) + """ + A collection of `PopupMenuItem` controls to display in a dropdown menu. + """ + + icon: Optional[IconDataOrControl] = None + """ + If provided, an icon to draw on the button. + """ + + bgcolor: Optional[ColorValue] = None + """ + The menu's background color. + """ + + icon_color: Optional[ColorValue] = None + """ + The `icon`'s color. + """ + + shadow_color: Optional[ColorValue] = None + """ + The color used to paint the shadow below the menu. + """ + + icon_size: Optional[Number] = None + """ + The `icon`'s size. + """ + + splash_radius: Optional[Number] = None + """ + The splash radius. + """ + + elevation: Optional[Number] = None + """ + The menu's elevation when opened. + + Defaults to `8`. + """ + + menu_position: Optional[PopupMenuPosition] = None + """ + Defines position of the popup menu relative to the button. + + Defaults to `PopupMenuPosition.OVER`. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + The `content` will be clipped (or not) according to this option. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. + + On Android, for example, setting this to `True` produce a click sound and a + long-press will produce a short vibration. + + Defaults to `True`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The menu's shape. + + Defaults to `CircleBorder(radius=10.0)`. + """ + + padding: PaddingValue = 8 + """ + TBD + """ + + menu_padding: Optional[PaddingValue] = None + """ + TBD + """ + + style: Optional[ButtonStyle] = None + """ + TBD + """ + + popup_animation_style: Optional[AnimationStyle] = None + """ + TBD + """ + + size_constraints: Optional[BoxConstraints] = None + """ + TBD + """ + + on_open: Optional[ControlEventHandler["PopupMenuButton"]] = None + """ + Called when the popup menu is shown. + """ + + on_cancel: Optional[ControlEventHandler["PopupMenuButton"]] = None + """ + Called when the user dismisses/cancels the popup menu without selecting an item. + """ + + on_select: Optional[ControlEventHandler["PopupMenuButton"]] = None + """ + TBD + """ + + def __contains__(self, item): + return item in self.items diff --git a/sdk/python/packages/flet/src/flet/controls/material/progress_bar.py b/sdk/python/packages/flet/src/flet/controls/material/progress_bar.py new file mode 100644 index 0000000000..2aff68d6bf --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/progress_bar.py @@ -0,0 +1,138 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ColorValue, Number +from flet.utils.validation import V + +__all__ = ["ProgressBar"] + + +@control("ProgressBar") +class ProgressBar(LayoutControl): + """ + A material design linear progress indicator, also known as a progress bar. + + A control that shows progress along a line. + + Example: + ```python + ft.ProgressBar(width=400, value=0.8) + ``` + """ + + value: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The value of this progress indicator. + + A value of `0.0` means no progress and `1.0` means that progress is complete. The + value will be clamped to be in the range `0.0` - `1.0`. + + Defaults to `None`, meaning that this progress indicator is indeterminate - + displays a predetermined animation that does not indicate how much actual progress + is being made. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + bar_height: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The minimum height of the line used to draw the linear indicator. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + color: Optional[ColorValue] = None + """ + The progress indicator's color. + """ + + bgcolor: Optional[ColorValue] = None + """ + Color of the track being filled by the linear indicator. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The border radius of both the indicator and the track. + + Defaults to `BorderRadius.all(0)` - rectangular shape. + """ + + semantics_label: Optional[str] = None + """ + The semantics label for this progress indicator. + """ + + semantics_value: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The semantics label for this progress indicator. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + stop_indicator_color: Optional[ColorValue] = None + """ + The color of the stop indicator. + + If :attr:`flet.ProgressBar.year_2023` is `True` or :attr:`flet.Theme.use_material3` + is `False`, then no stop indicator will be drawn. + + If not set, then the :attr:`flet.ProgressIndicatorTheme.stop_indicator_color` will + be used. If that is not set, then the :attr:`flet.ColorScheme.primary` will be used. + """ + + stop_indicator_radius: Optional[Number] = None + """ + The radius of the stop indicator. + + If :attr:`flet.ProgressBar.year_2023` is `True` or \ + :attr:`flet.Theme.use_material3` is + `False`, then no stop indicator will be drawn. + + Set `stop_indicator_radius` to `0` to hide the stop indicator. + + If not set, then the :attr:`flet.ProgressIndicatorTheme.stop_indicator_radius` + will be used. If that is not set, then defaults to `2`. + """ + + track_gap: Optional[Number] = None + """ + The gap between the indicator and the track. + + If :attr:`flet.ProgressBar.year_2023` is `True` or + :attr:`flet.Theme.use_material3` is `False`, then no track gap + will be drawn. + + If not set, then the :attr:`flet.ProgressIndicatorTheme.track_gap` will be + used. If that is not set, then defaults to `4`. + + Tip: + Set `track_gap` to `0` to hide the track gap. + """ + + year_2023: Optional[bool] = None + """ + If this is set to `False`, the ProgressBar will use the latest Material Design 3 \ + appearance, which was introduced in December 2023. + + When `True`, the ProgressBar will use the 2023 Material Design 3 appearance. + + If not set, then the :attr:`flet.ProgressIndicatorTheme.year_2023` will be + used, which is `False` by default. + + If :attr:`flet.Theme.use_material3` is `False`, then this property is ignored. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/progress_ring.py b/sdk/python/packages/flet/src/flet/controls/material/progress_ring.py new file mode 100644 index 0000000000..7bae496030 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/progress_ring.py @@ -0,0 +1,133 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.box import BoxConstraints +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ColorValue, Number, StrokeCap + +__all__ = ["ProgressRing"] + + +@control("ProgressRing") +class ProgressRing(LayoutControl): + """ + A material design circular progress indicator, which spins to indicate that the \ + application is busy. + + A control that shows progress along a circle. + + ```python + ft.ProgressRing(value=0.4, padding=ft.Padding.all(10)) + ``` + + """ + + value: Optional[Number] = None + """ + The value of this progress indicator. + + A value of `0.0` means no progress and `1.0` means that progress is complete. + The value will be clamped to be in the range `0.0` - `1.0`. If `None`, this + progress indicator is indeterminate, which means the indicator displays a + predetermined animation that does not indicate how much actual progress is being + made. + """ + + stroke_width: Optional[Number] = None + """ + The width of the line used to draw the circle. + """ + + color: Optional[ColorValue] = None + """ + The progress indicator's color. + """ + + bgcolor: Optional[ColorValue] = None + """ + Color of the circular track being filled by the circular indicator. + """ + + stroke_align: Optional[Number] = None + """ + The relative position of the stroke. + + Value typically ranges be `-1.0` (inside stroke) and `1.0` (outside stroke). + + A value of 0 (center stroke) will center the border on the edge of the control. + + If :attr:`flet.ProgressRing.year_2023` is `True`, then the + default value is `0`. Otherwise, the default value is `-1`. + """ + + stroke_cap: Optional[StrokeCap] = None + """ + The progress indicator's line ending. + """ + + semantics_label: Optional[str] = None + """ + Used to identify the purpose of this progress bar for screen reading software. + """ + + semantics_value: Optional[Number] = None + """ + Used for determinate progress indicators to indicate how much progress has been \ + made. + """ + + track_gap: Optional[Number] = None + """ + The gap between the active indicator and the background track. + + If :attr:`year_2023` is `True` or `Theme.use_material3` is + `False`, then no track gap will be drawn. + + Set `track_gap` to `0` to hide this track gap. + + If `None`, + :attr:`flet.ProgressIndicatorTheme.track_gap` is used. + + If that's is also `None`, defaults to `4.0`. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Defines the minimum and maximum size of the progress indicator. + + If `None`, + :attr:`flet.ProgressIndicatorTheme.size_constraints` + is used. + + If that's is also `None`, defaults to a minimum width and height of `36`. + """ + + padding: Optional[PaddingValue] = None + """ + The padding around the indicator track. + + If `None`, + :attr:`flet.ProgressIndicatorTheme.circular_track_padding` + is used. + + If that's is also `None` and :attr:`year_2023` is `False`, + defaults to `Padding.all(4.0)`. + + Otherwise, defaults to `Padding.all(0.0)`. + """ + + year_2023: Optional[bool] = None + """ + If this is set to `False`, the `ProgressRing` will use the latest Material Design \ + 3 appearance, which was introduced in December 2023. + + When `True`, the `ProgressRing` will use the 2023 Material Design 3 appearance. + + If not set, then the + :attr:`flet.ProgressIndicatorTheme.year_2023` will be + used, which is `False` by default. + + If :attr:`flet.Theme.use_material3` is `False`, then this property + is ignored. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/radio.py b/sdk/python/packages/flet/src/flet/controls/material/radio.py new file mode 100644 index 0000000000..9a6866b5d1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/radio.py @@ -0,0 +1,120 @@ +from typing import Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + LabelPosition, + MouseCursor, + Number, + VisualDensity, +) + +__all__ = ["Radio"] + + +@control("Radio") +class Radio(LayoutControl, AdaptiveControl): + """ + Radio buttons let people select a single option from two or more choices. + + Example: + ```python + ft.RadioGroup( + content=ft.Row( + controls=[ft.Radio(label=f"{i}") for i in range(1, 4)], + alignment=ft.MainAxisAlignment.CENTER, + ) + ) + ``` + """ + + label: str = "" + """ + The clickable label to display on the right of a Radio. + """ + + label_position: LabelPosition = LabelPosition.RIGHT + """ + Defaults to `LabelPosition.RIGHT`. + """ + + label_style: Optional[TextStyle] = None + """ + The label's style. + """ + + value: Optional[str] = None + """ + The value to set to containing `RadioGroup` when the radio is selected. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. + + If there is more than one control on a page with autofocus set, then the first one + added to the page will get focus. + """ + + fill_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color that fills the radio, in all or specific :class:`~flet.ControlState` \ + states. + """ + + active_color: Optional[ColorValue] = None + """ + The color used to fill this radio when it is selected. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The overlay color of this radio in all or specific :class:`~flet.ControlState` \ + states. + """ + + hover_color: Optional[ColorValue] = None + """ + The color of this radio when it is hovered. + """ + + focus_color: Optional[ColorValue] = None + """ + The color of this radio when it has the input focus. + """ + + splash_radius: Optional[Number] = None + """ + The splash radius of the circular Material ink response. + """ + + toggleable: bool = False + """ + Set to `True` if this radio button is allowed to be returned to an indeterminate \ + state by selecting it again when selected. + """ + + visual_density: Optional[VisualDensity] = None + """ + Defines how compact the radio's layout will be. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor for a mouse pointer entering or hovering over this control. + """ + + on_focus: Optional[ControlEventHandler["Radio"]] = None + """ + Called when the control has received focus. + """ + + on_blur: Optional[ControlEventHandler["Radio"]] = None + """ + Called when the control has lost focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/radio_group.py b/sdk/python/packages/flet/src/flet/controls/material/radio_group.py new file mode 100644 index 0000000000..8bd9eaec5b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/radio_group.py @@ -0,0 +1,39 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.utils.validation import V + +__all__ = ["RadioGroup"] + + +@control("RadioGroup") +class RadioGroup(Control): + """ + Radio buttons let people select a single option from two or more choices. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The content of the RadioGroup. + + Typically a list of `Radio` controls nested in a container control, e.g. `Column`, + `Row`. + + Raises: + ValueError: If :attr:`content` is not visible. + """ + + value: Optional[str] = None + """ + Current value of the RadioGroup. + """ + + on_change: Optional[ControlEventHandler["RadioGroup"]] = None + """ + Called when the state of the RadioGroup is changed. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/range_slider.py b/sdk/python/packages/flet/src/flet/controls/material/range_slider.py new file mode 100644 index 0000000000..27454e83d1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/range_slider.py @@ -0,0 +1,180 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ColorValue, + MouseCursor, + Number, +) +from flet.utils.validation import V + +__all__ = ["RangeSlider"] + + +@control("RangeSlider") +class RangeSlider(LayoutControl): + """ + A Material Design range slider. Used to select a range from a range of values. + + A range slider can be used to select from either a continuous or a discrete + set of values. The default is to use a continuous range of values from + :attr:`min` to :attr:`max`. + + Example: + ```python + ft.RangeSlider( + min=0, + max=10, + start_value=2, + divisions=10, + end_value=7, + ) + ``` + """ + + start_value: Annotated[ + Number, + V.ge_field("min"), + V.le_field("end_value"), + ] + """ + The currently selected start value for this slider. + + The left thumb of this slider is drawn at a position that corresponds + to this value. Use :attr:`label` to change the label displayed on the thumb. + + Raises: + ValueError: If it is not greater than or equal to :attr:`min`. + ValueError: If it is not less than or equal to :attr:`end_value`. + """ + + end_value: Annotated[ + Number, + V.le_field("max"), + V.ge_field("start_value"), + ] + """ + The currently selected end value of this slider. + + The right thumb of this slider is drawn at a position that corresponds + to this value. Use :attr:`label` to change the label displayed on the thumb. + + Raises: + ValueError: If it is not less than or equal to :attr:`max`. + ValueError: If it is not greater than or equal to :attr:`start_value`. + """ + + label: Optional[str] = None + """ + A label to show above the slider thumbs when the slider is active. + + It may contain `{value}` which will be replaced with realtime values of + :attr:`start_value` and :attr:`end_value`, in the corresponding slider thumbs. + + If not set, then the labels will not be displayed. + If :attr:`divisions` is not set, this slider is + continuous and labels are not displayed. + """ + + min: Annotated[ + Number, + V.le_field("start_value"), + V.le_field("max"), + ] = 0.0 + """ + The minimum value the user can select. + + If the :attr:`max` is equal to the `min`, then the slider is disabled. + + Raises: + ValueError: If it is not less than or equal to :attr:`start_value`. + ValueError: If it is not less than or equal to :attr:`max`. + """ + + max: Annotated[ + Number, + V.ge_field("end_value"), + V.ge_field("min"), + ] = 1.0 + """ + The maximum value the user can select. + + If the :attr:`max` is equal to the :attr:`min`, then the slider is disabled. + + Raises: + ValueError: If it is not greater than or equal to :attr:`end_value`. + ValueError: If it is not greater than or equal to :attr:`min`. + """ + + divisions: Annotated[ + Optional[int], + V.gt(0), + ] = None + """ + The number of discrete divisions. + + Typically used with :attr:`label` to show the current discrete values. + + If not set, this slider is continuous and :attr:`label` is not displayed. + + Raises: + ValueError: If it is not strictly greater than `0`. + """ + + round: Annotated[ + int, + V.between(0, 20), + ] = 0 + """ + The number of decimals displayed on the :attr:`label` containing `{value}`. + + Defaults to `0` - value rounded to the nearest integer. + + Raises: + ValueError: If it is not between `0` and `20`, inclusive. + """ + + active_color: Optional[ColorValue] = None + """ + The color to use for the portion of the slider track that is active. + + The "active" segment of the range slider is the span between the thumbs. + """ + + inactive_color: Optional[ColorValue] = None + """ + The color for the inactive portions of the slider track. + + The "inactive" segments of the slider are the span of tracks between the min and + the start thumb, and the end thumb and the max. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The highlight color that's typically used to indicate that the range slider thumb \ + is in :attr:`flet.ControlState.HOVERED` or :attr:`flet.ControlState.DRAGGED` \ + state. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + The cursor for a mouse pointer entering or hovering over this control. + """ + + on_change: Optional[ControlEventHandler["RangeSlider"]] = None + """ + Called when the state of this slider is changed. + """ + + on_change_start: Optional[ControlEventHandler["RangeSlider"]] = None + """ + Called when the user starts selecting a new value for this slider. + """ + + on_change_end: Optional[ControlEventHandler["RangeSlider"]] = None + """ + Called when the user is done selecting a new value for this slider. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py b/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py new file mode 100644 index 0000000000..f239be5431 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/reorderable_list_view.py @@ -0,0 +1,169 @@ +from dataclasses import dataclass, field +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ( + Event, + EventHandler, +) +from flet.controls.core.list_view import ListView +from flet.controls.types import MouseCursor, Number + + +@dataclass +class OnReorderEvent(Event["ReorderableListView"]): + """ + Payload for :class:`~flet.ReorderableListView` events related to item + reordering. + """ + + new_index: Optional[int] = None + """ + The new position of the item after the reordering, if available. + + Will be non-`None` only for the following events: + :attr:`~flet.ReorderableListView.on_reorder`, + :attr:`~flet.ReorderableListView.on_reorder_end`. + """ + + old_index: Optional[int] = None + """ + The previous position of the item before the reordering, if available. + + Will be non-`None` only for the following events: + :attr:`~flet.ReorderableListView.on_reorder`, + :attr:`~flet.ReorderableListView.on_reorder_start`. + """ + + +@control("ReorderableListView") +class ReorderableListView(ListView): + """ + A scrollable list of controls that can be reordered. + + Tip: + By default, each child control (from :attr:`controls`) is draggable using an + automatically created drag handle (see + :attr:`show_default_drag_handles`). To customize the draggable area, use + :class:`~flet.ReorderableDragHandle` to define your own drag handle or + region. + + Example: + ```python + ft.ReorderableListView( + controls=[ + ft.ListTile( + title=ft.Text(f"Item {i}"), + bgcolor=ft.Colors.BLUE_GREY_300, + ) + for i in range(1, 6) + ], + ) + ``` + + """ + + controls: list[Control] = field(default_factory=list) + """ + The controls displayed by this :class:`ReorderableListView`. + + Note: + When an item of this list gets reordered, the :attr:`on_reorder` event gets + fired, but it doesn't reorder the `controls` list automatically. So, to keep + `controls` list in sync with the UI, reorder this list inside your + :attr:`on_reorder` event handler. See :attr:`on_reorder` for an example. + """ + + anchor: Number = 0.0 + """ + The relative position of the zero scroll offset. + """ + + auto_scroller_velocity_scalar: Optional[Number] = None + """ + The velocity scalar per pixel over scroll. + + It represents how the velocity scale with the over scroll distance. + The auto-scroll velocity = (distance of overscroll) * velocity scalar. + """ + + header: Optional[Control] = None + """ + A non-reorderable header item to show before :attr:`controls`. + """ + + footer: Optional[Control] = None + """ + A non-reorderable footer item to show after :attr:`controls`. + """ + + show_default_drag_handles: bool = True + """ + Whether to show default drag handles for each :attr:`controls` item. + + If `True`: on desktop platforms, a drag handle is stacked over the + center of each item's trailing edge; on mobile platforms, a long + press anywhere on the item starts a drag. + + The default desktop drag handle is just an `Icons.DRAG_HANDLE` + wrapped by a :class:`~flet.ReorderableDragHandle`. On mobile platforms, the + entire item is wrapped with a :class:`~flet.ReorderableDragHandle`. + + To customize the appearance or layout of drag handles, wrap each + :attr:`controls` item, or a control within each of them, with a + :class:`~flet.ReorderableDragHandle`. For full control over the drag handles, + you might want to set :attr:`show_default_drag_handles` to `False`. + + Example: + ```python + ft.ReorderableListView( + show_default_drag_handles=False, + controls=[ + ft.ListTile( + title=ft.Text(f"Draggable Item {i}", color=ft.Colors.BLACK), + leading=ft.ReorderableDragHandle( + content=ft.Icon(ft.Icons.DRAG_INDICATOR, color=ft.Colors.RED), + mouse_cursor=ft.MouseCursor.GRAB, + ), + ) + for i in range(10) + ], + ) + ``` + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor for a mouse pointer when it enters or is hovering over the drag handle. + """ + + on_reorder: Optional[EventHandler[OnReorderEvent]] = None + """ + Called when a :attr:`controls` item has been dragged to a new location/position. + + Note: + This event does not reorder :attr:`controls` automatically. So, to keep + :attr:`controls` list in sync with the UI, reorder it accordingly inside + your :attr:`on_reorder` event handler. + + Example: + + ```python + def handle_reorder(e: ft.OnReorderEvent): + rlv = e.control + moved_item = rlv.controls.pop(e.old_index) # Remove the reordered item from its old position + rlv.controls.insert(e.new_index, moved_item) # Insert the reordered item into its new position + rlv.update() + ``` + """ # noqa: E501 + + on_reorder_start: Optional[EventHandler[OnReorderEvent]] = None + """ + Called when a :attr:`controls` item drag has started. + """ + + on_reorder_end: Optional[EventHandler[OnReorderEvent]] = None + """ + Called when the dragged :attr:`controls` item is dropped. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/search_bar.py b/sdk/python/packages/flet/src/flet/controls/material/search_bar.py new file mode 100644 index 0000000000..b35a3c73ed --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/search_bar.py @@ -0,0 +1,307 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.border import BorderSide +from flet.controls.box import BoxConstraints +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.material.textfield import KeyboardType, TextCapitalization +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + Number, +) + +__all__ = ["SearchBar"] + + +@control("SearchBar") +class SearchBar(LayoutControl): + """ + Manages a "search view" route that allows the user to select one of the suggested \ + completions for a search query. + + ```python + ft.SearchBar(bar_hint_text="Search...") + ``` + + """ + + controls: list[Control] = field(default_factory=list) + """ + The list of controls to be displayed below the search bar when in search view. + + Typically :class:`~flet.ListTile`s and will be displayed + in a :class:`~flet.ListView`. + """ + + value: str = "" + """ + The text in the search bar. + """ + + bar_leading: Optional[Control] = None + """ + A control to display before the text input field when the search view is close. + + Typically an :class:`~flet.Icon` or an :class:`~flet.IconButton`. + """ + + bar_trailing: Optional[list[Control]] = None + """ + A list of controls to display after the text input field when the search view is \ + close. + + These controls can represent additional modes of searching (e.g voice search), + an avatar, or an overflow menu and are usually not more than two. + """ + + bar_hint_text: Optional[str] = None + """ + Defines the text to be shown in the search bar when it is empty and the search \ + view is close. + + Usually some text that suggests what sort of input the field accepts. + """ + + bar_bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + Defines the background color of the search bar in all or specific \ + :class:`~flet.ControlState` states. + """ + + bar_overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Defines the highlight color that's typically used to indicate that the search bar \ + is in :attr:`~flet.ControlState.FOCUSED`, :attr:`~flet.ControlState.HOVERED`, or \ + :attr:`~flet.ControlState.PRESSED` states. + """ + + bar_shadow_color: Optional[ControlStateValue[ColorValue]] = None + """ + The shadow color of the search bar. + """ + + bar_elevation: Optional[ControlStateValue[Optional[Number]]] = None + """ + The elevation of the search bar. + """ + + bar_border_side: Optional[ControlStateValue[BorderSide]] = None + """ + The color and weight of the search bar's outline. + + This value is combined with :attr:`bar_shape` to + create a shape decorated with an outline. + """ + + bar_shape: Optional[ControlStateValue[OutlinedBorder]] = None + """ + The shape of the search bar. + + This shape is combined with :attr:`bar_border_side` to create a shape + decorated with an outline. + """ + + bar_text_style: Optional[ControlStateValue[TextStyle]] = None + """ + The style to use for the text being edited. + """ + + bar_hint_text_style: Optional[ControlStateValue[TextStyle]] = None + """ + The style to use for the :attr:`flet.SearchBar.bar_hint_text`. + """ + + bar_padding: Optional[ControlStateValue[PaddingValue]] = None + """ + The padding between the search bar's boundary and its contents. + """ + + bar_scroll_padding: PaddingValue = 20 + """ + Configures the padding around a Scrollable when the text field scrolls into view. + + If the bar's text field is partially off-screen or covered (e.g., by the + keyboard), it scrolls into view, ensuring it is positioned at the specified + distance from the Scrollable edges. + """ + + bar_size_constraints: Optional[BoxConstraints] = None + """ + Optional size constraints for the search bar. + """ + + view_leading: Optional[Control] = None + """ + A `Control` to display before the text input field when the search view is open. + + Typically an :class:`~flet.Icon` or an :class:`~flet.IconButton`. + + Defaults to a back button which closes/pops the search view. + """ + + view_trailing: Optional[list[Control]] = None + """ + A list of `Control`s to display after the text input field when the search view is \ + open. + + Defaults to a close button which closes/pops the search view. + """ + + view_elevation: Optional[Number] = None + """ + Defines the elevation of the search view. + """ + + view_bgcolor: Optional[ColorValue] = None + """ + Defines the background color of the search view. + """ + + view_hint_text: Optional[str] = None + """ + Defines the text to be displayed when the search bar's input field is empty. + """ + + view_side: Optional[BorderSide] = None + """ + Defines the color and weight of the search view's outline. + """ + + view_shape: Optional[OutlinedBorder] = None + """ + Defines the shape of the search view. + """ + + view_header_text_style: Optional[TextStyle] = None + """ + Defines the text style of the text being edited on the search view. + """ + + view_hint_text_style: Optional[TextStyle] = None + """ + Defines the text style of :attr:`view_hint_text`. + """ + + view_size_constraints: Optional[BoxConstraints] = None + """ + Optional size constraints for the search view. + + By default, the search view has the same width as the search bar and is 2/3 the + height of the screen. If the width and height of the view are within the + view_size_constraints, the view will show its default size. Otherwise, the size of + the view will be constrained by this property. + """ + + view_header_height: Optional[Number] = None + """ + The height of the search field on the search view. + """ + + view_padding: Optional[PaddingValue] = None + """ + The padding to use for the search view. + + Has no effect if the search view is full-screen. + """ + + view_bar_padding: Optional[PaddingValue] = None + """ + The padding to use for the search view's search bar. + + If null, then the default value is 8.0 horizontally. + """ + + shrink_wrap: Optional[bool] = None + """ + Whether the search view should shrink-wrap its contents. + """ + + divider_color: Optional[ColorValue] = None + """ + The color of the divider when in search view. + """ + + capitalization: Optional[TextCapitalization] = None + """ + Enables automatic on-the-fly capitalization of entered text. + """ + + full_screen: bool = False + """ + Defines whether the search view grows to fill the entire screen when the search \ + bar is tapped. + """ + + keyboard_type: KeyboardType = KeyboardType.TEXT + """ + The type of action button to use for the keyboard. + """ + + autofocus: bool = False + """ + Whether the text field should focus itself if nothing else is already focused. + """ + + on_tap: Optional[ControlEventHandler["SearchBar"]] = None + """ + Called when the search bar is tapped. + """ + + on_tap_outside_bar: Optional[ControlEventHandler["SearchBar"]] = None + """ + Fired when the user taps outside the search bar while the search view is open. + """ + + on_submit: Optional[ControlEventHandler["SearchBar"]] = None + """ + Called when user presses ENTER while focus is on SearchBar. + """ + + on_change: Optional[ControlEventHandler["SearchBar"]] = None + """ + Called when the typed input in the search bar has changed. + """ + + on_focus: Optional[ControlEventHandler["SearchBar"]] = None + """ + Fired when the search bar gains focus. + """ + + on_blur: Optional[ControlEventHandler["SearchBar"]] = None + """ + Fired when the search bar loses focus. + """ + + def __contains__(self, item): + return item in self.controls + + def before_update(self): + super().before_update() + + # Public methods + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") + + async def open_view(self): + """Opens the search view.""" + await self._invoke_method("open_view") + + async def close_view(self, text: Optional[str] = None): + """ + Closes an opened search view. + + Args: + text: The text to set in the search bar when closing the view. If not + provided, the current :attr:`value` of the search bar will be used. + """ + await self._invoke_method( + "close_view", {"text": text if text is not None else self.value} + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py b/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py new file mode 100644 index 0000000000..54c6216032 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/segmented_button.py @@ -0,0 +1,190 @@ +from dataclasses import field +from typing import Annotated, Optional + +from flet.controls.alignment import Axis +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + IconData, + IconDataOrControl, + StrOrControl, +) +from flet.utils.validation import V, ValidationRules + +__all__ = ["Segment", "SegmentedButton"] + + +@control("Segment") +class Segment(Control): + """ + A segment for a :class:`~flet.SegmentedButton`. + """ + + value: str + """ + Used to identify this segment. + """ + + icon: Optional[IconDataOrControl] = None + """ + The icon to be displayed in the segment. + + Typically an :class:`~flet.Icon`. + + Raises: + ValueError: If neither it nor :attr:`label` is set and visible. + """ + + label: Optional[StrOrControl] = None + """ + The label (usually a :class:`~flet.Text`) to be displayed in the segment. + + Raises: + ValueError: If neither it nor :attr:`icon` is set and visible. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: ( + ( + isinstance(ctrl.icon, IconData) + or (isinstance(ctrl.icon, Control) and ctrl.icon.visible) + ) + or ( + isinstance(ctrl.label, str) + or (isinstance(ctrl.label, Control) and ctrl.label.visible) + ) + ), + message="at least icon or label must be set and visible", + ), + ) + + +@control("SegmentedButton") +class SegmentedButton(LayoutControl): + """ + A segmented button control. + """ + + segments: Annotated[ + list[Segment], + V.visible_controls(min_count=1), + ] + """ + The segments of this button. + + Raises: + ValueError: If it does not contain at least one visible `Segment`. + """ + + style: Optional[ButtonStyle] = None + """ + Customizes this button's appearance. + """ + + allow_empty_selection: bool = False + """ + A boolean value that indicates if having no selected segments is allowed. + + If `True`, then it is acceptable for none of the segments to be selected and also + that `selected` can be empty. + + If `False` (the default), there must be at least one segment selected. If the user + taps on the only selected segment it will not be deselected, and `on_change` will + not be called. + + Raises: + ValueError: If :attr:`selected` is empty while + :attr:`allow_empty_selection` is `False`. + """ + + allow_multiple_selection: bool = False + """ + A boolean value that indicates if multiple segments can be selected at one time. + + If `True`, more than one segment can be selected. When selecting a segment, the + other `selected` segments will stay selected. Selecting an already selected segment + will unselect it. + + If `False` (the default), only one segment may be selected at a time. When a segment + is selected, any previously selected segment will be unselected. + + Raises: + ValueError: If :attr:`selected` has more than one item while + :attr:`allow_multiple_selection` is `False`. + """ + + selected: list[str] = field(default_factory=list) + """ + A set of `Segment.value`s that indicate which segments are selected. It is updated \ + when the user (un)selects a segment. + + Raises: + ValueError: If :attr:`selected` violates the constraints defined by + :attr:`allow_empty_selection` or + :attr:`allow_multiple_selection`. + """ + + selected_icon: Optional[IconDataOrControl] = None + """ + An `Icon` control that is used to indicate a segment is selected. + + If `show_selected_icon` is `True` then for `selected` segments this icon will be + shown before the `Segment.label`, replacing the `Segment.icon` if it is specified. + + Defaults to an `Icon` with the `CHECK` icon. + """ + + show_selected_icon: bool = True + """ + A boolean value that indicates if the `selected_icon` is displayed on the \ + `selected` segments. + + If `True`, the `selected_icon` will be displayed at the start of the `selected` + segments. + + If `False`, then the `selected_icon` is not used and will not be displayed on + `selected` segments. + """ + + direction: Optional[Axis] = None + """ + The orientation of the button's `segments`. + + Defaults + to `Axis.HORIZONTAL`. + """ + + padding: Optional[PaddingValue] = None + """ + Defines the button's size and padding. If specified, the button expands to fill \ + its parent's space with this padding. + + When `None`, the button adopts its intrinsic content size. + """ + + on_change: Optional[ControlEventHandler["SegmentedButton"]] = None + """ + Called when the selection changes. + + The :attr:`~flet.Event.data` property of the event handler argument + contains a list of strings identifying the selected segments. + """ + + __validation_rules__: ValidationRules = ( + V.ensure( + lambda ctrl: len(ctrl.selected) > 0 or ctrl.allow_empty_selection, + message="allow_empty_selection must be True for selected to be empty", + ), + V.ensure( + lambda ctrl: len(ctrl.selected) < 2 or ctrl.allow_multiple_selection, + message=( + "allow_multiple_selection must be True for selected to " + "have more than one item" + ), + ), + ) diff --git a/sdk/python/packages/flet/src/flet/controls/material/selection_area.py b/sdk/python/packages/flet/src/flet/controls/material/selection_area.py new file mode 100644 index 0000000000..29f9cff66d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/selection_area.py @@ -0,0 +1,36 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.utils.validation import V + +__all__ = ["SelectionArea"] + + +@control("SelectionArea") +class SelectionArea(Control): + """ + Flet controls are not selectable by default. SelectionArea is used to enable \ + selection for its child control. + """ + + content: Annotated[ + Control, + V.visible_control(), + ] + """ + The child control this selection area applies to. + + If you need to have multiple selectable controls, use container-like controls + like :class:`~flet.Row` or :class:`~flet.Column`, which have a `controls` property + for this purpose. + + Raises: + ValueError: If :attr:`content` is not visible. + """ + + on_change: Optional[ControlEventHandler["SelectionArea"]] = None + """ + Called when the selected content changes. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/slider.py b/sdk/python/packages/flet/src/flet/controls/material/slider.py new file mode 100644 index 0000000000..616d6d5b3f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/slider.py @@ -0,0 +1,264 @@ +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ColorValue, + MouseCursor, + Number, +) +from flet.utils.validation import V + +__all__ = ["Slider", "SliderInteraction"] + + +class SliderInteraction(Enum): + """ + Defines how users can interact with a :class:`~flet.Slider` to change its value. + + Each mode controls whether taps and drag gestures on the slider track are + accepted, and whether interaction is restricted to dragging the thumb. + """ + + TAP_AND_SLIDE = "tapAndSlide" + """ + Allows the user to interact with a slider by tapping or sliding anywhere on the \ + track. + + Essentially all possible interactions are allowed. + + It is different from :attr:`SLIDE_ONLY`, in that when you try + to slide anywhere other than the thumb, the thumb will move to the first + point of contact. + """ + + TAP_ONLY = "tapOnly" + """ + Allows only tap interaction on the slider track. + + Drag/sliding gestures are ignored. + """ + + SLIDE_ONLY = "slideOnly" + """ + Allows only sliding interaction to change the value. + + Track taps are ignored. + """ + + SLIDE_THUMB = "slideThumb" + """ + Allows interaction only by dragging the slider thumb. + + Taps and drag/slide gestures that begin on the track are ignored. + """ + + +@control("Slider") +class Slider(LayoutControl, AdaptiveControl): + """ + A slider provides a visual indication of adjustable content, as well as the \ + current setting in the total range of content. + + Use a slider when you want people to set defined values (such as volume or + brightness), or when people would benefit from instant feedback on the effect + of setting changes. + + Example: + ```python + ft.Slider(label="Slider", value=0.3) + ``` + """ + + value: Annotated[ + Optional[Number], + V.ge_field("min"), + V.le_field("max"), + ] = None + """ + The currently selected value for this slider. + + The slider's thumb is drawn at a position that corresponds to this value. + + Defaults to value of :attr:`min`. + + Raises: + ValueError: If it is not greater than or equal to :attr:`min`. + ValueError: If it is not less than or equal to :attr:`max`. + """ + + label: Optional[str] = None + """ + A label to show above the slider when the slider is active. The value of `label` \ + may contain `{value}` which will be dynamically replaced with a current slider \ + value. For example, `"Volume: {value}"`. + + It is used to display the value of a discrete slider, and it is displayed as + part of the value indicator shape. + + If not set, then the value indicator will not be displayed. + """ + + min: Annotated[ + Number, + V.le_field("max"), + V.le_field("value"), + ] = 0.0 + """ + The minimum value the user can select. + + If the :attr:`max` is equal to the `min`, then this slider is disabled. + + Raises: + ValueError: If it is not less than or equal to :attr:`max`. + ValueError: If it is not less than or equal to :attr:`value`, + when :attr:`value` is set. + """ + + max: Annotated[ + Number, + V.ge_field("min"), + V.ge_field("value"), + ] = 1.0 + """ + The maximum value the user can select. + + If the :attr:`min` is equal to the `max`, then this slider is disabled. + + Raises: + ValueError: If it is not greater than or equal to :attr:`min`. + ValueError: If it is not greater than or equal to :attr:`value`, + when :attr:`value` is set. + """ + + divisions: Optional[int] = None + """ + The number of discrete divisions. + + Typically used with :attr:`label` to show the current discrete value. + + If `None`, this slider is continuous. + """ + + round: int = 0 + """ + The number of decimals displayed on the :attr:`label` + containing :attr:`value`. + + Defaults to `0`, which displays value rounded to the nearest integer. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + active_color: Optional[ColorValue] = None + """ + The color to use for the portion of the slider track that is active. + + The "active" side of the slider is the side between the thumb and the minimum + value. + """ + + inactive_color: Optional[ColorValue] = None + """ + The color for the inactive portion of the slider track. + + The "inactive" side of the slider is the side between the thumb and the maximum + value. + """ + + thumb_color: Optional[ColorValue] = None + """ + The color of the thumb. + """ + + interaction: Optional[SliderInteraction] = None + """ + The allowed way for the user to interact with this slider. + + If `None`, :attr:`flet.SliderTheme.interaction` is used. + If that's is also `None`, defaults to :attr:`flet.SliderInteraction.TAP_AND_SLIDE`. + """ + + secondary_active_color: Optional[ColorValue] = None + """ + The color to use for the portion of the slider track between the thumb and the \ + :attr:`secondary_track_value`. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The highlight color that's typically used to indicate that the range slider thumb \ + is in :attr:`flet.ControlState.HOVERED` or :attr:`flet.ControlState.DRAGGED` \ + states. + """ + + secondary_track_value: Optional[Number] = None + """ + The secondary track value for this slider. + + If not null, a secondary track using `secondary_active_color` is drawn between + the thumb and this value, over the inactive track. If less than `value`, then + the secondary track is not shown. + + It can be ideal for media scenarios such as showing the buffering progress + while the `value` shows the play progress. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + control. + """ + + padding: Optional[PaddingValue] = None + """ + Determines the padding around this slider. + """ + + year_2023: Optional[bool] = None + """ + If this is set to `False`, this slider will use the latest Material Design 3 \ + appearance, which was introduced in December 2023. + + When `True`, the Slider will use the 2023 Material Design 3 appearance. + + If not set, then the :attr:`flet.SliderTheme.year_2023` will be used, which is + `False` by default. + + If :attr:`flet.Theme.use_material3` is `False`, then this property is ignored. + """ + + on_change: Optional[ControlEventHandler["Slider"]] = None + """ + Called when the state of this slider is changed. + """ + + on_change_start: Optional[ControlEventHandler["Slider"]] = None + """ + Called when the user starts selecting a new value for this slider. + """ + + on_change_end: Optional[ControlEventHandler["Slider"]] = None + """ + Called when the user is done selecting a new value for this slider. + """ + + on_focus: Optional[ControlEventHandler["Slider"]] = None + """ + Called when this slider has received focus. + """ + + on_blur: Optional[ControlEventHandler["Slider"]] = None + """ + Called when this slider has lost focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/snack_bar.py b/sdk/python/packages/flet/src/flet/controls/material/snack_bar.py new file mode 100644 index 0000000000..591965ca29 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/snack_bar.py @@ -0,0 +1,324 @@ +from dataclasses import field +from enum import Enum +from typing import Annotated, Optional, Union + +from flet.controls.base_control import control +from flet.controls.buttons import OutlinedBorder +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.dialog_control import DialogControl +from flet.controls.duration import Duration, DurationValue +from flet.controls.margin import MarginValue +from flet.controls.padding import PaddingValue +from flet.controls.types import ( + ClipBehavior, + ColorValue, + Number, + StrOrControl, +) +from flet.utils.validation import V + +__all__ = ["DismissDirection", "SnackBar", "SnackBarAction", "SnackBarBehavior"] + + +class SnackBarBehavior(Enum): + """ + Defines where a :class:`~flet.SnackBar` appears within a page and how it is \ + positioned relative to bottom UI elements. + """ + + FIXED = "fixed" + """ + Anchors the snack bar to the bottom of the page. + + If a :class:`~flet.NavigationBar` is present, the snack bar is shown above it. + Other non-fixed content can be pushed upward while the snack bar is visible. + """ + + FLOATING = "floating" + """ + Displays the snack bar as a floating surface above page content. + + This mode can overlay bottom widgets, such as a :class:`~flet.NavigationBar` and a + bottom-positioned :class:`~flet.FloatingActionButton`. + """ + + +class DismissDirection(Enum): + """ + Defines swipe directions allowed for dismissing a :class:`~flet.SnackBar`. + + The direction controls which drag gestures can close the snack bar when + dismissal is enabled. + """ + + NONE = "none" + """ + Disables swipe-to-dismiss gestures. + """ + + VERTICAL = "vertical" + """ + Allows dismissing by swiping vertically. + + Users can drag either up or down to dismiss. + """ + + HORIZONTAL = "horizontal" + """ + Allows dismissing by swiping horizontally. + + Users can drag either left or right to dismiss. + """ + + END_TO_START = "endToStart" + """ + Allows dismissing toward the end-to-start reading direction. + + For left-to-right locales this is right-to-left; for right-to-left locales + this is left-to-right. + """ + + START_TO_END = "startToEnd" + """ + Allows dismissing toward the start-to-end reading direction. + + For left-to-right locales this is left-to-right; for right-to-left locales + this is right-to-left. + """ + + UP = "up" + """ + Allows dismissing only by swiping upward. + """ + + DOWN = "down" + """ + Allows dismissing only by swiping downward. + """ + + +@control("SnackBar") +class SnackBarAction(Control): + """ + A button that can be used as an action in a :class:`~flet.SnackBar`. + + An action button for a :class:`~flet.SnackBar`. + + Note: + - Snack bar actions are always enabled. Instead of disabling a snack bar + action, avoid including it in the snack bar in the first place. + - Snack bar actions will only respond to first click. + Subsequent clicks/presses are ignored. + """ + + label: str + """ + The button's label. + """ + + text_color: Optional[ColorValue] = None + """ + The button label color. + + If `None`, :attr:`flet.SnackBarTheme.action_text_color` is used. + """ + + disabled_text_color: Optional[ColorValue] = None + """ + The button disabled label color. + This color is shown after the action is dismissed. + """ + + bgcolor: Optional[ColorValue] = None + """ + The button background fill color. + + If `None`, :attr:`flet.SnackBarTheme.action_bgcolor` is used. + """ + + disabled_bgcolor: Optional[ColorValue] = None + """ + The button disabled background color. + This color is shown after the action is dismissed. + + If `None`, :attr:`flet.SnackBarTheme.disabled_action_bgcolor` is used. + """ + + on_click: Optional[ControlEventHandler["SnackBarAction"]] = None + """ + Called when this action button is clicked. + """ + + +@control("SnackBar") +class SnackBar(DialogControl): + """ + A lightweight message with an optional action which briefly displays at the bottom \ + of the screen. + + Example: + ```python + page.show_dialog(ft.SnackBar(ft.Text("Opened snack bar"))) + ``` + """ + + content: Annotated[ + StrOrControl, + V.str_or_visible_control(), + ] + """ + The primary content of the snack bar. + + Typically a :class:`~flet.Text` control. + + Raises: + ValueError: If it is neither a string nor a visible `Control`. + """ + + behavior: Optional[SnackBarBehavior] = None + """ + This defines the behavior and location of the snack bar. + + Defines where a SnackBar should appear within a page and how its location + should be adjusted when the page also includes a :class:`~flet.FloatingActionButton` + or a :class:`~flet.NavigationBar`. + + If `None`, :attr:`flet.SnackBarTheme.behavior` is used. + If that's is also `None`, defaults to :attr:`flet.SnackBarBehavior.FIXED`. + + Note: + - If :attr:`behavior` is :attr:`flet.SnackBarBehavior.FLOATING`, the length of + the bar is defined by either :attr:`width` and :attr:`margin`, and if + both are specified, `width` takes precedence over `margin`. + - :attr:`width` and :attr:`margin` are ignored if :attr:`behavior` + is not :attr:`flet.SnackBarBehavior.FLOATING`. + """ + + dismiss_direction: Optional[DismissDirection] = None + """ + The direction in which the SnackBar can be dismissed. + + If `None`, :attr:`flet.SnackBarTheme.dismiss_direction` is used. + If that's is also `None`, defaults to :attr:`flet.DismissDirection.DOWN`. + """ + + show_close_icon: bool = False + """ + Whether to include a "close" icon widget. + + Tapping the icon will close the snack bar. + """ + + action: Union[str, SnackBarAction, None] = None + """ + An optional action that the user can take based on the snack bar. + + For example, the snack bar might let the user undo the operation that prompted + the snackbar. Snack bars can have at most one action. + + The action should not be "dismiss" or "cancel". + """ + + close_icon_color: Optional[ColorValue] = None + """ + The color of the close icon, if :attr:`show_close_icon` is `True`. + """ + + bgcolor: Optional[ColorValue] = None + """ + SnackBar background color. + """ + + duration: DurationValue = field(default_factory=lambda: Duration(milliseconds=4000)) + """ + The amount of time this snack bar should stay open for. + """ + + margin: Optional[MarginValue] = None + """ + Empty space to surround the snack bar. + + Has effect only when `behavior=SnackBarBehavior.FLOATING` and will be ignored + if `width` is specified. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of padding to apply to the snack bar's content and optional action. + """ + + width: Optional[Number] = None + """ + The width of the snack bar. + + If width is specified, the snack bar will be centered horizontally in the + available space. + + Note: + Has effect only when :attr:`behavior` is :attr:`flet.SnackBarBehavior.FLOATING`. + It can not be used if `margin` is specified. + """ + + elevation: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The z-coordinate at which to place the snack bar. This controls the size of the \ + shadow below the snack bar. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of this snack bar. + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + The :attr:`content` will be clipped (or not) according to this option. + """ + + action_overflow_threshold: Annotated[ + Optional[Number], + V.between(0.0, 1.0), + ] = 0.25 + """ + The percentage threshold for :attr:`action`'s width before it overflows to a new \ + line. + + If the width of the snackbar's :attr:`content` is greater than this percentage + of the width of the snackbar minus the width of its `action`, then the `action` + will appear below the :attr:`content`. + + At a value of `0.0`, the `action` will not overflow to a new line. + + Raises: + ValueError: If it is not between `0.0` and `1.0`, inclusive. + """ + + persist: Optional[bool] = None + """ + Whether the snack bar will stay or auto-dismiss after timeout. + + If `True`, the snack bar remains visible even after the timeout, + until the user taps the action button or the close icon. + + If `False`, the snack bar will be dismissed after the timeout. + + If not provided, but the snackbar :attr:`action` is not null, + the snackbar will persist as well. + """ + + on_action: Optional[ControlEventHandler["SnackBar"]] = None + """ + Called when action button is clicked. + """ + + on_visible: Optional[ControlEventHandler["SnackBar"]] = None + """ + Called the first time that the snackbar is visible within the page. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/submenu_button.py b/sdk/python/packages/flet/src/flet/controls/material/submenu_button.py new file mode 100644 index 0000000000..4d152a8e91 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/submenu_button.py @@ -0,0 +1,118 @@ +from dataclasses import field +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.material.menu_bar import MenuStyle +from flet.controls.transform import OffsetValue +from flet.controls.types import ClipBehavior, StrOrControl + +__all__ = ["SubmenuButton"] + + +@control("SubmenuButton") +class SubmenuButton(LayoutControl): + """ + A menu button that displays a cascading menu. + + Typically used in a :class:`~flet.MenuBar` control. + + ```python + ft.SubmenuButton( + content=ft.Text("Choose text style"), + key="smbutton", + expand=True, + menu_style=ft.MenuStyle( + alignment=ft.Alignment.BOTTOM_LEFT, side=ft.BorderSide(1) + ), + controls=[ + ft.MenuItemButton( + content=ft.Text("Underlined"), + on_click=lambda e: print(f"{e.control.content.value}.on_click"), + ), + ft.MenuItemButton(...), + ..., + ], + ) + ``` + """ + + content: Optional[StrOrControl] = None + """ + The child control to be displayed in the middle portion of this button. + + Typically this is the button's label, using a :class:`~flet.Text` control. + """ + + controls: list[Control] = field(default_factory=list) + """ + A list of controls that appear in the menu when it is opened. + + Typically either :class:`~flet.MenuItemButton` or + `SubMenuButton` controls. + + If this list is empty, then the button for this menu item will be disabled. + """ + + leading: Optional[Control] = None + """ + An optional control to display before the :attr:`content`. + + Typically an :class:`~flet.Icon` control. + """ + + trailing: Optional[Control] = None + """ + An optional control to display after the :attr:`content`. + + Typically an :class:`~flet.Icon` control. + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + Whether to clip the content of this control or not. + """ + + menu_style: Optional[MenuStyle] = None + """ + Customizes this menu's appearance. + """ + + style: Optional[ButtonStyle] = None + """ + Customizes this button's appearance. + """ + + alignment_offset: Optional[OffsetValue] = None + """ + The offset of the menu relative to the alignment origin determined by \ + :attr:`flet.MenuStyle.alignment` on the :attr:`style` attribute. + """ + + on_open: Optional[ControlEventHandler["SubmenuButton"]] = None + """ + Called when the menu is opened. + """ + + on_close: Optional[ControlEventHandler["SubmenuButton"]] = None + """ + Called when the menu is closed. + """ + + on_hover: Optional[ControlEventHandler["SubmenuButton"]] = None + """ + Called when the button is hovered. + """ + + on_focus: Optional[ControlEventHandler["SubmenuButton"]] = None + """ + Called when the button receives focus. + """ + + on_blur: Optional[ControlEventHandler["SubmenuButton"]] = None + """ + Called when this button loses focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/switch.py b/sdk/python/packages/flet/src/flet/controls/material/switch.py new file mode 100644 index 0000000000..fd525807c1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/switch.py @@ -0,0 +1,221 @@ +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.layout_control import LayoutControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + IconData, + LabelPosition, + MouseCursor, + Number, + StrOrControl, +) +from flet.utils.validation import V + +__all__ = ["Switch"] + + +@control("Switch") +class Switch(LayoutControl, AdaptiveControl): + """ + A toggle represents a physical switch that allows someone to choose between two \ + mutually exclusive options. + + For example, "On/Off", "Show/Hide". + + ```python + ft.Switch(label="Unchecked switch", value=False) + ft.Switch(label="Disabled switch", disabled=True) + ``` + """ + + label: Optional[StrOrControl] = None + """ + The clickable label to display on the right of this switch. + """ + + label_position: LabelPosition = LabelPosition.RIGHT + """ + The position of the :attr:`label`, if provided. + """ + + label_text_style: Optional[TextStyle] = None + """ + The :attr:`label`'s text style, when it is a string. + """ + + value: bool = False + """ + Current value of this switch. + """ + + autofocus: bool = False + """ + Whether this switch will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + active_color: Optional[ColorValue] = None + """ + The color to use when this switch is on. + """ + + active_track_color: Optional[ColorValue] = None + """ + The color to use on the track when this switch is on. + + If :attr:`track_color` returns a non-none color in + the `ControlState.SELECTED` state, it will + be used instead of this color. + """ + + focus_color: Optional[ColorValue] = None + """ + The color to use for the focus highlight for keyboard interactions. + """ + + inactive_thumb_color: Optional[ColorValue] = None + """ + The color to use on the thumb when this switch is off. + + Defaults to colors defined in the + [material design specification](https://m3.material.io/components/switch/specs). + + If :attr:`thumb_color` returns a non-none color + in the `ControlState.DEFAULT` state, it will be + used instead of this color. + """ + + inactive_track_color: Optional[ColorValue] = None + """ + The color to use on the track when this switch is off. + + Defaults to colors defined in the + [material design specification](https://m3.material.io/components/switch/specs). + + If :attr:`track_color` returns a non-none color + in the `ControlState.DEFAULT` state, it will be + used instead of this color. + """ + + thumb_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color of this switch's thumb in various :class:`~flet.ControlState` + states. + + The following states are supported: `ControlState.SELECTED`, `ControlState.HOVERED`, + `ControlState.DISABLED`, `ControlState.FOCUSED` and + `ControlState.DEFAULT` (fallback). + """ + + thumb_icon: Optional[ControlStateValue[IconData]] = None + """ + The icon of this Switch's thumb in various :class:`~flet.ControlState` states. + + The following states are supported: `ControlState.SELECTED`, `ControlState.HOVERED`, + `ControlState.DISABLED`, `ControlState.FOCUSED` and + `ControlState.DEFAULT` (fallback). + """ + + track_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color of this switch's track in various :class:`~flet.ControlState` states. + + The following states are supported: `ControlState.SELECTED`, + `ControlState.HOVERED`, `ControlState.DISABLED`, `ControlState.FOCUSED` and + `ControlState.DEFAULT` (fallback). + """ + + adaptive: Optional[bool] = None + """ + Whether an adaptive Switch should be created based on the target platform. + + On iOS and macOS, a :class:`~flet.CupertinoSwitch` is created, + which has matching functionality and presentation as `Switch`, + and the graphics as expected on iOS. On other platforms, + a Material Switch is created. + + Defaults to `False`. See the example of usage + [here](https://flet.dev/docs/controls/cupertinoswitch/#cupertino-material-and-adaptive-switches). + """ # noqa: E501 + + hover_color: Optional[ColorValue] = None + """ + The color to be used when it is being hovered over by the mouse pointer. + """ + + splash_radius: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The radius of the splash effect when the switch is pressed. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color for the switch's Material in various :class:`~flet.ControlState` states. + + The following states are supported: `ControlState.PRESSED`, + `ControlState.SELECTED`, `ControlState.HOVERED`, `ControlState.FOCUSED` and + `ControlState.DEFAULT`. + """ + + track_outline_color: Optional[ControlStateValue[ColorValue]] = None + """ + The outline color of this switch's track in various :class:`~flet.ControlState` + states. + + The following states are supported: `ControlState.SELECTED`, ` + ControlState.HOVERED`, `ControlState.DISABLED`, `ControlState.FOCUSED` and + `ControlState.DEFAULT` (fallback). + """ + + track_outline_width: Optional[ControlStateValue[Optional[Number]]] = None + """ + The outline width of this switch's track in all or specific \ + :class:`~flet.ControlState` states. + + The following states are supported: `ControlState.SELECTED`, + `ControlState.HOVERED`, `ControlState.DISABLED`, + `ControlState.FOCUSED` and `ControlState.DEFAULT` (fallback). + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + control. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of space to surround the child inside the bounds of the Switch. + + Defaults to horizontal padding of 4 pixels. If + :attr:`flet.Theme.use_material3` is false, then there is no + padding by default. + """ + + on_change: Optional[ControlEventHandler["Switch"]] = None + """ + Called when the state of the Switch is changed. + """ + + on_focus: Optional[ControlEventHandler["Switch"]] = None + """ + Called when the control has received focus. + """ + + on_blur: Optional[ControlEventHandler["Switch"]] = None + """ + Called when the control has lost focus. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/tabs.py b/sdk/python/packages/flet/src/flet/controls/material/tabs.py new file mode 100644 index 0000000000..229453cfc5 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/tabs.py @@ -0,0 +1,645 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import Annotated, Optional + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.animation import AnimationCurve +from flet.controls.base_control import control, value +from flet.controls.border import BorderSide +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.colors import Colors +from flet.controls.control import Control +from flet.controls.control_event import ControlEventHandler, Event, EventHandler +from flet.controls.control_state import ControlStateValue +from flet.controls.duration import Duration, DurationValue +from flet.controls.layout_control import LayoutControl +from flet.controls.margin import MarginValue +from flet.controls.material.form_field_control import IconDataOrControl +from flet.controls.padding import Padding, PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ClipBehavior, + ColorValue, + MouseCursor, + Number, + StrOrControl, +) +from flet.utils.validation import V + +__all__ = [ + "Tab", + "TabAlignment", + "TabBar", + "TabBarHoverEvent", + "TabBarIndicatorSize", + "TabBarView", + "TabIndicatorAnimation", + "Tabs", + "UnderlineTabIndicator", +] + + +class TabAlignment(Enum): + """ + Defines how tabs are aligned horizontally in a :class:`~flet.Tabs`. + """ + + START = "start" + """ + If :attr:`flet.TabBar.scrollable` is `True`, tabs are aligned to the start of the \ + :class:`~flet.TabBar`. + """ + + START_OFFSET = "startOffset" + """ + If :attr:`flet.TabBar.scrollable` is `True`, tabs are aligned to the start of the \ + :class:`~flet.TabBar` with an offset of `52.0` pixels. + """ + + FILL = "fill" + """ + If :attr:`flet.TabBar.scrollable` is `False`, tabs are stretched to fill the \ + :class:`~flet.TabBar`. + """ + + CENTER = "center" + """ + Tabs are aligned to the center of the :class:`~flet.TabBar`. + """ + + +class TabIndicatorAnimation(Enum): + """ + Defines how the tab indicator animates when the selected tab changes. + """ + + LINEAR = "linear" + """ + The tab indicator animates linearly. + """ + + ELASTIC = "elastic" + """ + The tab indicator animates with an elastic effect. + """ + + +class TabBarIndicatorSize(Enum): + """ + Defines how the bounds of the selected tab indicator are computed. + """ + + TAB = "tab" + """ + The tab indicator's bounds are as wide as the space occupied by the tab in the tab \ + bar: from the right edge of the previous tab to the left edge of the next tab. + """ + + LABEL = "label" + """ + The tab's bounds are only as wide as the (centered) tab widget itself. + + This value is used to align the tab's label, typically a [Tab] + widget's text or icon, with the selected tab indicator. + """ + + +@dataclass +class TabBarHoverEvent(Event["TabBar"]): + """ + Represents a hover-state change for a tab in a :class:`~flet.TabBar`. + + This event is emitted by :attr:`flet.TabBar.on_hover` when a pointer + enters or exits a tab item. When moving directly from one tab to another, the + handler is typically called twice: first with :attr:`hovering` set to `False` + for the previous tab, then with :attr:`hovering` set to `True` for the next tab. + """ + + hovering: bool + """ + Whether a pointer has entered (`True`) or exited (`False`) the tab bar at \ + :attr:`index`. + """ + + index: int + """ + The index of the tab that is being hovered over. + """ + + +@value +class UnderlineTabIndicator: + border_side: BorderSide = field( + default_factory=lambda: BorderSide(width=2.0, color=Colors.WHITE) + ) + """ + The color and weight of the horizontal line drawn below the selected tab. + """ + + insets: PaddingValue = field(default_factory=lambda: Padding.zero()) + """ + Locates the selected tab's underline relative to the tab's boundary. + + The :attr:`flet.TabBar.indicator_size` property can be used + to define the tab indicator's bounds in terms of its (centered) tab control with + :attr:`flet.TabBarIndicatorSize.LABEL`, or the entire tab + with :attr:`flet.TabBarIndicatorSize.TAB`. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + The radius of the indicator's corners. + + If this value is not `None`, a rounded rectangular tab indicator is + drawn, otherwise rectangular tab indicator is drawn. + """ + + +@control("Tabs") +class Tabs(LayoutControl, AdaptiveControl): + """ + Used for navigating frequently accessed, distinct content categories. Tabs allow \ + for navigation between two or more content views and relies on text headers to \ + articulate the different sections of content. + + Example: + ```python + ft.Tabs( + length=2, + expand=True, + content=ft.Column( + expand=True, + controls=[ + ft.TabBar( + tabs=[ + ft.Tab(label="Overview"), + ft.Tab(label="Settings", icon=ft.Icons.SETTINGS), + ] + ), + ft.TabBarView( + expand=True, + controls=[ + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Overview content"), + ), + ft.Container( + alignment=ft.Alignment.CENTER, + content=ft.Text("Settings content"), + ), + ], + ), + ], + ), + ) + ``` + """ + + content: Control + """ + The content to display. + """ + + length: Annotated[ + int, + V.ge(0), + ] + """ + The total number of tabs. + + Typically greater than one. + + Note: + Must match the length of both :attr:`flet.TabBar.tabs` + and :attr:`flet.TabBarView.controls`. Don't forget to update + it when adding/removing tabs. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + selected_index: int = 0 + """ + The index of the currently selected tab. + + Supports Python-style negative indexing, where `-1` represents the last tab, + `-2` the second to last, and so on. + + Note: + - Must be in range `[-length, length - 1]`. + - Changing the value of this property will internally trigger + :meth:`move_to` with :attr:`animation_duration` and + :attr:`flet.AnimationCurve.EASE` animation curve. To specify + a different animation curve or duration for this particular change, + use :meth:`move_to` directly. + + Raises: + IndexError: If it is not in the range `[-length, length - 1]`. + """ + + animation_duration: DurationValue = field( + default_factory=lambda: Duration(milliseconds=100), + ) + """ + The duration of tab animations. For example, the animation that occurs when the \ + selected tab changes. + """ + + on_change: Optional[ControlEventHandler["Tabs"]] = None + """ + Called when :attr:`selected_index` changes. + + The :attr:`~flet.Event.data` property of the event handler argument + contains the index of the selected tab. + """ + + def before_update(self): + super().before_update() + if self.length >= 0 and not (-self.length <= self.selected_index < self.length): + raise IndexError( + f"selected_index out of range: got {self.selected_index}, " + f"expected in range [-{self.length}, {self.length - 1}]" + ) + + async def move_to( + self, + index: int, + animation_curve: AnimationCurve = AnimationCurve.EASE_IN, + animation_duration: Optional[DurationValue] = None, + ): + """ + Selects the tab at the given `index`. + + Additionally, it triggers :attr:`on_change` event and updates + :attr:`selected_index`. + + Note: + If `index` is negative, it is interpreted as a Python-style negative index + (e.g., -1 refers to the last tab). If the resolved index is already the + currently selected tab, the method returns immediately and does nothing. + + Args: + index: The index of the tab to select. Must be between in range + `[-length, length - 1]`. + animation_curve: The curve to apply to the animation. + animation_duration: The duration of the animation. If `None` (the default), + :attr:`flet.Tabs.animation_duration` will be used. + + Raises: + IndexError: If the `index` is outside the range `[-length, length - 1]`. + """ + if not (-self.length <= index < self.length): + raise IndexError( + f"index out of range: got {index}, expected in range " + f"[-{self.length}, {self.length - 1}]" + ) + + # Resolve negative index to positive + resolved_index = index if index >= 0 else self.length + index + + # Early return if already on this tab + if self.selected_index == resolved_index: + return + + await self._invoke_method( + method_name="move_to", + arguments={ + "index": index, + "curve": animation_curve, + "duration": animation_duration + if animation_duration is not None + else self.animation_duration, + }, + ) + + +@control("TabBarView") +class TabBarView(LayoutControl, AdaptiveControl): + """ + A page view with one child per tab. + + Note: + The length of :attr:`controls` must be the same as the + :attr:`~flet.Tabs.length` property of the ancestor :class:`~flet.Tabs`. + """ + + controls: list[Control] + """ + A list of controls, where each control represents the content of a corresponding \ + tab. So, a control at index `i` in this list is displayed when the \ + :class:`~flet.Tab` at index `i` is selected. + + Note: + The length of this list must be equal to the number of tabs specified in an + ancestor :class:`~flet.Tabs` control. + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + Defines how the :attr:`controls` will be clipped. + """ + + viewport_fraction: Number = 1.0 + """ + The fraction of the viewport that each page should occupy. + + For example, `1.0` (the default), means each page fills + the viewport in the scrolling direction. + """ + + +@control("TabBar") +class TabBar(LayoutControl, AdaptiveControl): + """ + Used for navigating frequently accessed, distinct content categories. Tabs allow \ + for navigation between two or more content views and relies on text headers to \ + articulate the different sections of content. + """ + + tabs: list[Control] + """ + A list of controls. + + Typically :class:`~flet.Tab`s. + """ + + scrollable: bool = True + """ + Whether this tab bar can be scrolled horizontally. + + If `True`, then each tab is as wide as needed for its label and + the entire tab bar is scrollable. Otherwise each tab gets an equal share + of the available space. + """ + + tab_alignment: Optional[TabAlignment] = None + """ + Specifies the horizontal alignment of the tabs within this tab bar. + + If this is `None`, then the value of + :attr:`flet.TabBarTheme.tab_alignment` is used. + If :attr:`flet.TabBarTheme.tab_alignment` is `None` and + :attr:`flet.Theme.use_material3` is `True`, + then :attr:`flet.TabAlignment.START_OFFSET` is used if + :attr:`scrollable` is `True`, + otherwise :attr:`flet.TabAlignment.FILL` is used. + + If :attr:`flet.TabBarTheme.tab_alignment` is `None` + and :attr:`flet.Theme.use_material3` is `False`, + then :attr:`flet.TabAlignment.CENTER` is used if + :attr:`scrollable` is `True`, + otherwise :attr:`flet.TabAlignment.FILL` is used. + + Note: + - If :attr:`scrollable` is `False`, then :attr:`tab_alignment` must be + either :attr:`flet.TabAlignment.FILL` or :attr:`flet.TabAlignment.CENTER`. + - If :attr:`scrollable` is `True`, then :attr:`tab_alignment` must be + :attr:`flet.TabAlignment.START`, :attr:`flet.TabAlignment.START_OFFSET` + or :attr:`flet.TabAlignment.CENTER`. + + Raises: + ValueError: If it is not valid for the current + :attr:`scrollable` configuration. + """ + + divider_color: Optional[ColorValue] = None + """ + The color of the divider. + """ + + indicator_color: Optional[ColorValue] = None + """ + The color of the indicator(line that appears below the selected tab). + + Note: + Will be ignored if :attr:`indicator` or + :attr:`flet.TabBarTheme.indicator` is not `None`. + """ + + indicator: Optional[UnderlineTabIndicator] = None + """ + Defines the appearance of the selected tab indicator. + + If this or :attr:`flet.TabBarTheme.indicator` is not `None`, + :attr:`indicator_color` and + :attr:`indicator_thickness` properties are ignored. + + The indicator's size is based on the tab's bounds. If + :attr:`indicator_size` + is :attr:`flet.TabBarIndicatorSize.TAB`, + the tab's bounds are as wide as the space occupied by the tab in the tab bar. + If :attr:`indicator_size` is + :attr:`flet.TabBarIndicatorSize.LABEL`, + then the tab's bounds are only as wide as the tab control itself. + """ + + indicator_size: Optional[TabBarIndicatorSize] = None + """ + Defines how the selected tab indicator's size is computed. + + The size of the selected tab indicator is defined relative to the + tab's overall bounds if `indicator_size` is + :attr:`flet.TabBarIndicatorSize.TAB` + (the default) or relative to the bounds of the tab's control if + `indicator_size` is :attr:`flet.TabBarIndicatorSize.LABEL`. + + The selected tab's location appearance can be refined further with + the :attr:`indicator_color`, + :attr:`indicator_thickness`, + and :attr:`indicator` properties. + """ + + indicator_animation: Optional[TabIndicatorAnimation] = None + """ + Specifies the animation behavior of the tab indicator. + + If this is `None`, then the value of + :attr:`flet.TabBarTheme.indicator_animation` is used. + If that is also `None`, then the tab indicator will animate linearly if the + :attr:`indicator_size` is + :attr:`flet.TabBarIndicatorSize.TAB`, otherwise it will animate + with an elastic effect if the :attr:`indicator_size` is + :attr:`flet.TabBarIndicatorSize.LABEL`. + """ + + secondary: bool = False + """ + Whether to create a secondary/nested tab bar. + + Secondary tabs are used within a content area to further separate related content + and establish hierarchy. + """ + + label_color: Optional[ColorValue] = None + """ + The color of selected tab labels. + """ + + label_padding: Optional[PaddingValue] = None + """ + The padding around the tab label. + """ + + label_text_style: Optional[TextStyle] = None + """ + The text style of the tab labels. + """ + + unselected_label_color: Optional[ColorValue] = None + """ + The color of unselected tab labels. + """ + + unselected_label_text_style: Optional[TextStyle] = None + """ + The text style of the unselected tab labels. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Defines the ink response focus, hover, and splash colors in various \ + :class:`~flet.ControlState` states. + + The following states are supported: `ControlState.PRESSED`, + `ControlState.HOVERED` and + `ControlState.FOCUSED`. + """ + + divider_height: Optional[Number] = None + """ + The height of the divider. + + If `None`, defaults to + :attr:`flet.TabBarTheme.divider_height`. If this is also + `None`, `1.0` will be used. + """ + + indicator_thickness: Number = 2.0 + """ + The thickness of the indicator. Value must be greater than zero. + + Note: + Will be ignored if :attr:`indicator` or + :attr:`flet.TabBarTheme.indicator` is not `None`. + + Raises: + ValueError: If :attr:`indicator` is `None` and + :attr:`indicator_thickness` is not strictly greater than `0`. + """ + + enable_feedback: Optional[bool] = None + """ + Whether detected gestures should provide acoustic and/or haptic feedback. + + On Android, for example, setting this to `True` produce a click sound and a + long-press will produce a short vibration. + + Defaults to `True`. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor to be displayed when a mouse pointer enters or is hovering over this \ + control. + """ + + padding: Optional[PaddingValue] = None + """ + The padding around the Tabs control. + """ + + splash_border_radius: Optional[BorderRadiusValue] = None + """ + Defines the clipping radius of splashes that extend outside the bounds of the tab. + """ + + on_click: Optional[ControlEventHandler["TabBar"]] = None + """ + Called when a tab is clicked. + + The :attr:`~flet.Event.data` property of the event handler argument + contains the index of the clicked tab. + """ + + on_hover: Optional[EventHandler[TabBarHoverEvent]] = None + """ + Called when a tab's (from :attr:`tabs`) hover state in the tab bar changes. + + When hover is moved from one tab directly to another, this will be called + twice. First to represent hover exiting the initial tab, and then second + for the pointer entering hover over the next tab. + """ + + def __contains__(self, item): + return item in self.tabs + + def before_update(self): + super().before_update() + if self.indicator is None and self.indicator_thickness <= 0.0: + raise ValueError( + f"indicator_thickness must be strictly greater than zero if indicator " + f"is None, got {self.indicator_thickness}" + ) + valid_alignments = ( + [TabAlignment.CENTER, TabAlignment.FILL] + if not self.scrollable + else [TabAlignment.START, TabAlignment.START_OFFSET, TabAlignment.CENTER] + ) + + if ( + self.tab_alignment is not None + and self.tab_alignment not in valid_alignments + ): + raise ValueError( + f"If scrollable is {self.scrollable}, tab_alignment must be one of: " + f"{', '.join(f'TabAlignment.{a.name}' for a in valid_alignments)}." + ) + + +@control("Tab") +class Tab(AdaptiveControl): + """ + A Material Design :class:`~flet.TabBar` tab. + """ + + label: Optional[StrOrControl] = None + """ + The tab's name. Can be either a string or a control. + + Raises: + ValueError: If both :attr:`label` and :attr:`icon` are not set. + """ + + icon: Optional[IconDataOrControl] = None + """ + An icon to display on the left of Tab text. + """ + + height: Optional[Number] = None + """ + The height of the tab. + + If `None`, it will be calculated based on the content of the Tab. When + :attr:`icon` is not `None` along with :attr:`label`, + the default `height` is `72.0` pixels. Without an `icon`, + the `height` is 46.0 pixels. + + Currently, the provided tab height cannot be lower than the default height. + """ + + icon_margin: Optional[MarginValue] = None + """ + The margin added around the tab's icon. + + Only useful when used in combination with :attr:`icon`, + and :attr:`label` is not `None`. + + Defaults to `2` pixels of bottom margin. + If :attr:`flet.Theme.use_material3` is `False`, + then defaults to `10` pixels of bottom margin. + """ + + def before_update(self): + super().before_update() + if not ((self.label is not None) or (self.icon is not None)): + raise ValueError("Tab must have at least label or icon property set") diff --git a/sdk/python/packages/flet/src/flet/controls/material/text_button.py b/sdk/python/packages/flet/src/flet/controls/material/text_button.py new file mode 100644 index 0000000000..ea6806b2db --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/text_button.py @@ -0,0 +1,106 @@ +from typing import Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.control_event import ControlEventHandler +from flet.controls.layout_control import LayoutControl +from flet.controls.types import ( + ClipBehavior, + ColorValue, + IconDataOrControl, + StrOrControl, + Url, +) + +__all__ = ["TextButton"] + + +@control("TextButton") +class TextButton(LayoutControl, AdaptiveControl): + """ + Text buttons are used for the lowest priority actions, especially when presenting \ + multiple options. Text buttons can be placed on a variety of backgrounds. Until \ + the button is interacted with, its container isn’t visible. + + ```python + ft.TextButton( + content="Text Button", + icon=ft.Icons.STAR_BORDER, + icon_color=ft.Colors.BLUE_300, + ) + ``` + """ + + content: Optional[StrOrControl] = None + """ + A Control representing custom button content. + """ + + icon: Optional[IconDataOrControl] = None + """ + An icon to show in this button. + """ + + icon_color: Optional[ColorValue] = None + """ + Icon color. + """ + + style: Optional[ButtonStyle] = None + """ + Defines the style of this button. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. + + If there is more than one control on a page with autofocus set, then the first one + added to the page will get focus. + """ + + url: Optional[Union[str, Url]] = None + """ + The URL to open when this button is clicked. + + Additionally, if :attr:`on_click` event callback is + provided, it is fired after that. + """ + + clip_behavior: ClipBehavior = ClipBehavior.NONE + """ + Defines how the content of this button is clipped. + """ + + on_click: Optional[ControlEventHandler["TextButton"]] = None + """ + Called when a user clicks this button. + """ + + on_long_press: Optional[ControlEventHandler["TextButton"]] = None + """ + Called when this button is long-pressed. + """ + + on_hover: Optional[ControlEventHandler["TextButton"]] = None + """ + Called when a mouse pointer enters or exists this button's response area. + + The :attr:`~flet.Event.data` property of the event handler argument is `True` when + cursor enters and `False` when it exits. + """ + + on_focus: Optional[ControlEventHandler["TextButton"]] = None + """ + Called when this button has received focus. + """ + + on_blur: Optional[ControlEventHandler["TextButton"]] = None + """ + Called when this button has lost focus. + """ + + async def focus(self): + """Requests focus for this control.""" + await self._invoke_method("focus") diff --git a/sdk/python/packages/flet/src/flet/controls/material/textfield.py b/sdk/python/packages/flet/src/flet/controls/material/textfield.py new file mode 100644 index 0000000000..4cd223a7d6 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/textfield.py @@ -0,0 +1,630 @@ +from enum import Enum +from typing import Annotated, Optional, Union + +from flet.controls.adaptive_control import AdaptiveControl +from flet.controls.base_control import BaseControl, control, value +from flet.controls.control_event import ControlEventHandler, EventHandler +from flet.controls.core.autofill_group import AutofillHint +from flet.controls.core.text import TextSelection, TextSelectionChangeEvent +from flet.controls.material.form_field_control import FormFieldControl +from flet.controls.padding import PaddingValue +from flet.controls.text_style import StrutStyle +from flet.controls.types import ( + Brightness, + ClipBehavior, + ColorValue, + MouseCursor, + Number, + TextAlign, +) +from flet.utils.validation import V + +__all__ = [ + "InputFilter", + "KeyboardType", + "NumbersOnlyInputFilter", + "TextCapitalization", + "TextField", + "TextOnlyInputFilter", +] + + +class KeyboardType(Enum): + """ + The type of information for which to optimize the text input control. + + On Android, behavior may vary across device and keyboard provider. + """ + + NONE = "none" + """ + Prevents the OS from showing the on-screen virtual keyboard. + """ + + TEXT = "text" + """ + Optimized for textual information. + + Requests the default platform keyboard. + """ + + MULTILINE = "multiline" + """ + Optimized for multiline textual information. + + Requests the default platform keyboard, but accepts newlines when the + enter key is pressed. This is the input type used for all multiline text + fields. + """ + + NUMBER = "number" + """ + Optimized for unsigned numerical information without a decimal point. + + Requests a default keyboard with ready access to the number keys. + """ + + PHONE = "phone" + """ + Optimized for telephone numbers. + + Requests a keyboard with ready access to the number keys, `"*"`, and `"#"`. + """ + + DATETIME = "datetime" + """ + Optimized for date and time information. + + - On iOS, requests the default keyboard. + - On Android, requests a keyboard with ready + access to the number keys, `":"`, and `"-"`. + """ + + EMAIL = "email" + """ + Optimized for email addresses. + + Requests a keyboard with ready access to the `"@"` and `"."` keys. + """ + + URL = "url" + """ + Optimized for URLs. + + Requests a keyboard with ready access to the `"/"` and `"."` keys. + """ + + VISIBLE_PASSWORD = "visiblePassword" + """ + Optimized for passwords that are visible to the user. + + Requests a keyboard with ready access to both letters and numbers. + """ + + NAME = "name" + """ + Optimized for a person's name. + + - On iOS, requests the [UIKeyboardType.namePhonePad](https://developer.apple.com/documentation/uikit/uikeyboardtype/namephonepad) + keyboard, a keyboard optimized for entering a person’s name or phone number. + Does not support auto-capitalization. + - On Android, requests a keyboard optimized for + [TYPE_TEXT_VARIATION_PERSON_NAME](https://developer.android.com/reference/android/text/InputType#TYPE_TEXT_VARIATION_PERSON_NAME). + """ # noqa: E501 + + STREET_ADDRESS = "streetAddress" + """ + Optimized for postal mailing addresses. + + - On iOS, requests the default keyboard. + - On Android, requests a keyboard optimized for + [TYPE_TEXT_VARIATION_POSTAL_ADDRESS](https://developer.android.com/reference/android/text/InputType#TYPE_TEXT_VARIATION_POSTAL_ADDRESS). + """ # noqa: E501 + + WEB_SEARCH = "webSearch" + """ + Optimized for web searches. + + Requests a keyboard that includes keys useful for web searches as well as URLs. + + - On iOS, requests a default keyboard with ready access to the `"."` key. + In contrast to :attr:`URL`, a space bar is available. + - On Android this is remapped to the :attr:`URL` keyboard type as it always + shows a space bar. + """ + + TWITTER = "twitter" + """ + Optimized for social media. + + Requests a keyboard that includes keys useful for handles and tags. + + - On iOS, requests a default keyboard with ready access to the `"@"` and `"#"` keys. + - On Android this is remapped to the :attr:`EMAIL` keyboard type as it + always shows the `"@"` key. + """ + + +class TextCapitalization(Enum): + """ + Configures how the platform keyboard will select an uppercase or lowercase \ + keyboard. + + Only supports text keyboards, other keyboard types will ignore this + configuration. Capitalization is locale-aware. + """ + + CHARACTERS = "characters" + """ + Uppercase keyboard for each character. + + Info: + Corresponds to `InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS` on Android, and + `UITextAutocapitalizationTypeAllCharacters` on iOS. + """ + + WORDS = "words" + """ + Uppercase keyboard for the first letter of each word. + + Info: + Corresponds to `InputType.TYPE_TEXT_FLAG_CAP_WORDS` on Android, and + `UITextAutocapitalizationTypeWords` on iOS. + """ + + SENTENCES = "sentences" + """ + Uppercase keyboard for the first letter of each sentence. + + Info: + Corresponds to `InputType.TYPE_TEXT_FLAG_CAP_SENTENCES` on Android, and + `UITextAutocapitalizationTypeSentences` on iOS. + """ + + NONE = "none" + """ + Lowercase keyboard. + """ + + +@value +class InputFilter: + """ + An input filter that uses a regular expression to allow or deny/block certain \ + patterns in the input. + """ + + regex_string: str + """ + A regular expression pattern for the filter. + + It is recommended to use raw strings (prefix your string with `r`) for the pattern, + ex: `r"pattern"`. + """ + + allow: bool = True + """ + A boolean value indicating whether to allow or deny/block the matched patterns. + """ + + replacement_string: str = "" + """ + A string used to replace banned/denied patterns. + + Defaults to an empty string. + """ + + multiline: bool = False + """ + Whether this regular expression matches multiple lines. + + If the regexp does match multiple lines, the `"^"` and `"$"` characters match the + beginning and end of lines. If not, the characters match the beginning and end of + the input. + """ + + case_sensitive: bool = True + """ + Whether this regular expression is case sensitive. + + If the regular expression is not case sensitive, it will match an input letter with + a pattern letter even if the two letters are different case versions of the same + letter. + """ + + unicode: bool = False + """ + Whether this regular expression uses Unicode mode. + """ + + dot_all: bool = False + """ + Whether `"."` in this regular expression matches line terminators. + + When false, the `"."` character matches a single character, unless that character + terminates a line. When true, then the `"."` character will match any single + character including line terminators. + + This feature is distinct from `multiline`. They affect the behavior of different + pattern characters, so they can be used together or separately. + """ + + +class NumbersOnlyInputFilter(InputFilter): + """ + Allows only numbers. + """ + + def __init__(self): + super().__init__(regex_string=r"^[0-9]*$", allow=True, replacement_string="") + + +class TextOnlyInputFilter(InputFilter): + """ + Allows only text. + """ + + def __init__(self): + super().__init__(regex_string=r"^[a-zA-Z]*$", allow=True, replacement_string="") + + +@control("TextField") +class TextField(FormFieldControl, AdaptiveControl): + """ + A text field lets the user enter text, either with hardware keyboard or with an \ + onscreen keyboard. + + Example: + ```python + ft.TextField(label="Name", hint_text="Jane Doe") + ``` + """ + + value: str = "" + """ + Current value of this text field. + """ + + selection: Optional[TextSelection] = None + """ + Represents the current text selection or caret position in the field. + + When the user selects text, this property is updated to reflect the selected range. + If no text is selected, it contains an empty range indicating the caret position. + + Setting this property visually updates the field's selection to match the given + value, and hence leads to the :attr:`on_selection_change` event being triggered. + To ensure the selection is visible and the event is fired, the text field must + be focused. Call :meth:`~flet.FormFieldControl.focus` + on the field before setting this property. + """ + + keyboard_type: KeyboardType = KeyboardType.TEXT + """ + The type of keyboard to use for editing the text. + """ + + multiline: bool = False + """ + Whether this field can contain multiple lines of text. + """ + + min_lines: Annotated[ + Optional[int], + V.gt(0), + V.le_field("max_lines"), + ] = None + """ + The minimum number of lines to occupy when the content spans fewer lines. + + This affects the height of the field itself and does not limit the number of lines + that can be entered into the field. + + Defaults to `1`. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not less than or equal to :attr:`max_lines` when both + are set. + """ + + max_lines: Annotated[ + Optional[int], + V.gt(0), + V.ge_field("min_lines"), + ] = None + """ + The maximum number of lines to show at one time, wrapping if necessary. + + This affects the height of the field itself and does not limit the number of lines + that can be entered into the field. + + If this is `1` (the default), the text will not wrap, but will scroll horizontally + instead. + + Raises: + ValueError: If it is not strictly greater than `0`. + ValueError: If it is not greater than or equal to :attr:`min_lines` when + both are set. + """ + + max_length: Annotated[ + Optional[int], + V.or_( + V.gt(0), + V.eq(-1), + message="max_length must be either strictly greater than 0 or equal to -1", + ), + ] = None + """ + Limits a maximum number of characters that can be entered into TextField. + + Raises: + ValueError: If it is not strictly greater than `0` or equal to `-1`. + """ + + password: bool = False + """ + Whether to hide the text being edited. + """ + + can_reveal_password: bool = False + """ + Displays a toggle icon button that allows revealing the entered password. Is shown \ + if both :attr:`password` and `can_reveal_password` are `True`. + + The icon is displayed in the same location as :attr:`~flet.FormFieldControl.suffix` + and in case both `can_reveal_password`/:attr:`password` and `suffix` are + provided, then the :attr:`~flet.FormFieldControl.suffix` won't be shown. + """ + + read_only: bool = False + """ + Whether the text can be changed. + + When this is set to `True`, the text cannot be modified by any shortcut or keyboard + operation. The text is still selectable. + """ + + shift_enter: bool = False + """ + Changes the behavior of `Enter` button in :attr:`multiline` textfield to be \ + chat-like, i.e. new line can be added with `Shift`+`Enter` and pressing just \ + `Enter` fires :attr:`on_submit` event. + """ + + ignore_up_down_keys: bool = False + """ + Whether to intercept Arrow-Up and Arrow-Down when this field has focus. + + When set to `True`, pressing those keys does not move the caret to the beginning + or end of the text respectively. + """ + + text_align: Optional[TextAlign] = None + """ + How the text should be aligned horizontally. + + Defaults to :attr:`flet.TextAlign.LEFT`. + """ + + autofocus: bool = False + """ + True if the control will be selected as the initial focus. If there is more than \ + one control on a page with autofocus set, then the first one added to the page \ + will get focus. + """ + + capitalization: Optional[TextCapitalization] = None + """ + Enables automatic on-the-fly capitalization of entered text. + + Defaults to :attr:`flet.TextCapitalization.NONE`. + """ + + autocorrect: bool = True + """ + Whether to enable autocorrection. + """ + + enable_suggestions: bool = True + """ + Whether to show input suggestions as the user types. + + This flag only affects Android. On iOS, suggestions are tied directly to + `autocorrect`, so that suggestions are only shown when `autocorrect` is `True`. + On Android autocorrection and suggestion are controlled separately. + """ + + smart_dashes_type: bool = True + """ + Whether to allow the platform to automatically format dashes. + + This flag only affects iOS versions 11 and above. As an example of what this does, + two consecutive hyphen characters will be automatically replaced with one en dash, + and three consecutive hyphens will become one em dash. + """ + + smart_quotes_type: bool = True + """ + Whether to allow the platform to automatically format quotes. + + This flag only affects iOS. As an example of what this does, a standard vertical + double quote character will be automatically replaced by a left or right double + quote depending on its position in a word. + """ + + show_cursor: bool = True + """ + Whether the field's cursor is to be shown. + """ + + cursor_color: Optional[ColorValue] = None + """ + The color of TextField cursor. + """ + + cursor_error_color: Optional[ColorValue] = None + """ + TBD + """ + + cursor_width: Number = 2.0 + """ + Sets cursor width. + """ + + cursor_height: Optional[Number] = None + """ + Sets cursor height. + """ + + cursor_radius: Optional[Number] = None + """ + Sets cursor radius. + """ + + selection_color: Optional[ColorValue] = None + """ + The color of TextField selection. + """ + + input_filter: Optional[InputFilter] = None + """ + Provides as-you-type filtering/validation. + + Similar to the :attr:`on_change` callback, the input filters are not applied + when the content of the field is changed programmatically. + """ + + obscuring_character: str = "•" + """ + TBD + """ + + enable_interactive_selection: bool = True + """ + TBD + """ + + enable_ime_personalized_learning: bool = True + """ + TBD + """ + + can_request_focus: bool = True + """ + TBD + """ + + ignore_pointers: bool = False + """ + TBD + """ + + enable_stylus_handwriting: bool = True + """ + TBD + """ + + animate_cursor_opacity: Optional[bool] = None + """ + TBD + """ + + always_call_on_tap: bool = False + """ + TBD + """ + + scroll_padding: PaddingValue = 20 + """ + TBD + """ + + clip_behavior: ClipBehavior = ClipBehavior.HARD_EDGE + """ + TBD + """ + + keyboard_brightness: Optional[Brightness] = None + """ + TBD + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + TBD + """ + + strut_style: Optional[StrutStyle] = None + """ + TBD + """ + + autofill_hints: Optional[Union[AutofillHint, list[AutofillHint]]] = None + """ + Helps the autofill service identify the type of this text input. + + More information + [here](https://api.flutter.dev/flutter/material/TextField/autofillHints.html). + """ + + on_change: Optional[ControlEventHandler["TextField"]] = None + """ + Called when the typed input for the TextField has changed. + """ + + on_selection_change: Optional[ + EventHandler[TextSelectionChangeEvent["TextField"]] + ] = None + """ + Called when the text selection or caret position changes. + + This can be triggered either by user interaction (selecting text or moving + the caret) or programmatically (through the :attr:`selection` property). + """ + + on_click: Optional[ControlEventHandler["TextField"]] = None + """ + TBD + """ + + on_submit: Optional[ControlEventHandler["TextField"]] = None + """ + Called when user presses ENTER while focus is on TextField. + """ + + on_focus: Optional[ControlEventHandler["TextField"]] = None + """ + Called when the control has received focus. + """ + + on_blur: Optional[ControlEventHandler["TextField"]] = None + """ + Called when the control has lost focus. + """ + + on_tap_outside: Optional[ControlEventHandler["TextField"]] = None + """ + TBD + """ + + def _migrate_state(self, other: BaseControl): + super()._migrate_state(other) + if ( + isinstance(other, TextField) + and self.value is None + and self.value != other.value + ): + self.value = other.value + + def before_update(self): + super().before_update() + if ( + self.bgcolor is not None + or self.fill_color is not None + or self.hover_color is not None + or self.focused_color is not None + ) and self.filled is None: + self.filled = True # required to display any of the above colors diff --git a/sdk/python/packages/flet/src/flet/controls/material/time_picker.py b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py new file mode 100644 index 0000000000..e6cab1bd33 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/time_picker.py @@ -0,0 +1,242 @@ +from dataclasses import dataclass, field +from datetime import datetime, time +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ( + ControlEventHandler, + Event, + EventHandler, +) +from flet.controls.dialog_control import DialogControl +from flet.controls.icon_data import IconData +from flet.controls.types import ( + ColorValue, + Locale, + Orientation, +) + +__all__ = [ + "TimePicker", + "TimePickerEntryMode", + "TimePickerEntryModeChangeEvent", + "TimePickerHourFormat", +] + + +class TimePickerHourFormat(Enum): + """ + Defines the hour format for the :class:`~flet.TimePicker` control. + """ + + SYSTEM = "system" + """Respect the host platform setting.""" + + H12 = "h12" + """A 12-hour clock with an AM/PM selector.""" + + H24 = "h24" + """A 24-hour clock without an AM/PM selector.""" + + +class TimePickerEntryMode(Enum): + """ + Interactive input mode of the :class:`~flet.TimePicker` dialog. + + In :attr:`DIAL` mode, a clock dial is displayed, and the user taps or drags + the time they wish to select. In :attr:`INPUT` mode, :class:`~flet.TextField`s are + displayed and the user types in the time they wish to select. + """ + + DIAL = "dial" + """ + User picks time from a clock dial. + + Can switch to :attr:`INPUT` by activating a mode button in the time picker dialog. + """ + + INPUT = "input" + """ + User can input the time by typing it into text fields. + + Can switch to :attr:`DIAL` by activating a mode button in the time picker dialog. + """ + + DIAL_ONLY = "dialOnly" + """ + User can only pick time from a clock dial. + + There is no user interface to switch to another mode. + """ + + INPUT_ONLY = "inputOnly" + """ + User can only input the time by typing it into text fields. + + There is no user interface to switch to another mode. + """ + + +@dataclass +class TimePickerEntryModeChangeEvent(Event["TimePicker"]): + """ + Represents the event triggered when the entry mode of a :class:`~flet.TimePicker` \ + changes. + """ + + entry_mode: TimePickerEntryMode + """The new entry mode.""" + + +@control("TimePicker") +class TimePicker(DialogControl): + """ + A Material-style time picker dialog. + + Can be opened by calling the + :meth:`flet.Page.show_dialog` method. + + Depending on the :attr:`entry_mode`, it will show either a Dial or + an Input (hour and minute text fields) for picking a time. + + Example: + ```python + ft.TimePicker( + open=True, + value=time(1, 2), + entry_mode=ft.TimePickerEntryMode.INPUT_ONLY, + ) + ``` + """ + + value: Optional[time] = field(default_factory=lambda: datetime.now().time()) + """ + The selected time that this picker should display. + + The default value is equal to the current time. + """ + + locale: Optional[Locale] = None + """ + The locale for this time picker dialog. It is intended for (rare) cases where this \ + dialog should be localized differently from the rest of the page. + + It overrides the locale used by the page (see \ + :attr:`flet.Page.locale_configuration`), + but does not participate in page-level locale resolution. + + If set to `None` (the default) or an inexistent/unsupported locale, + the :attr:`~flet.LocaleConfiguration.current_locale` of the + :attr:`flet.Page.locale_configuration` is used as fallback. + """ + + modal: bool = False + """ + Whether this picker cannot be dismissed by clicking the area outside of it. + """ + + entry_mode: TimePickerEntryMode = TimePickerEntryMode.DIAL + """ + The initial mode of time entry method for this picker. + + Defaults to :attr:`flet.TimePickerEntryMode.DIAL`. + """ + + hour_label_text: Optional[str] = None + """ + The text that is displayed below the hour input text field. + + The default value is `"Hour"`. + """ + + minute_label_text: Optional[str] = None + """ + The text that is displayed below the minute input text field. + + The default value is `"Minute"`. + """ + + help_text: Optional[str] = None + """ + The text that is displayed at the top of the header. + + This is used to indicate to the user what they are selecting a time for. + The default value is `"Enter time"`. + """ + + cancel_text: Optional[str] = None + """ + The text that is displayed on the cancel button. + + The default value is `"Cancel"`. + """ + + confirm_text: Optional[str] = None + """ + The text that is displayed on the confirm button. + + The default value is `"OK"`. + """ + + error_invalid_text: Optional[str] = None + """ + The error message displayed below the input text field if the input is not a valid \ + hour/minute. + + The default value is `"Enter a valid time"`. + """ + + orientation: Optional[Orientation] = None + """ + The orientation of the dialog when displayed. + """ + + barrier_color: Optional[ColorValue] = None + """ + The color of the modal barrier that darkens everything below this picker's dialog. + + If `None`, the :attr:`flet.DialogTheme.barrier_color` is used. + If it is also `None`, then :attr:`flet.Colors.BLACK_54` is used. + """ + + switch_to_timer_icon: Optional[IconData] = None + """ + The icon displayed in the corner of this picker's dialog when :attr:`entry_mode` \ + is :attr:`flet.TimePickerEntryMode.INPUT`. + + Clicking on this icon changes the :attr:`entry_mode` to + :attr:`flet.TimePickerEntryMode.DIAL`. + + If `None`, defaults to `Icons.ACCESS_TIME`. + """ + + switch_to_input_icon: Optional[IconData] = None + """ + The icon displayed in the corner of this picker's dialog when :attr:`entry_mode` \ + is :attr:`flet.TimePickerEntryMode.DIAL`. + + Clicking on icon changes the :attr:`entry_mode` to + :attr:`flet.TimePickerEntryMode.INPUT`. + + If `None`, defaults to `Icons.KEYBOARD_OUTLINED`. + """ + + on_change: Optional[ControlEventHandler["TimePicker"]] = None + """ + Called when user clicks confirm button. + + :attr:`value` property is updated with selected time. + Additionally, the :attr:`~flet.Event.data` property of the event handler argument + also contains the selected time. + """ + + on_entry_mode_change: Optional[EventHandler[TimePickerEntryModeChangeEvent]] = None + """ + Called when the :attr:`entry_mode` is changed through the time picker dialog. + """ + + hour_format: TimePickerHourFormat = TimePickerHourFormat.SYSTEM + """ + Defines the hour format of this time picker. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/material/tooltip.py b/sdk/python/packages/flet/src/flet/controls/material/tooltip.py new file mode 100644 index 0000000000..8fe25c3679 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/tooltip.py @@ -0,0 +1,218 @@ +from typing import Optional, Union + +from flet.controls.base_control import value +from flet.controls.box import BoxConstraints, BoxDecoration +from flet.controls.duration import DurationValue +from flet.controls.margin import MarginValue +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.types import ( + ColorValue, + MouseCursor, + Number, + TextAlign, +) + + +class TooltipTriggerMode: + """ + The method of interaction that will trigger a tooltip. + Used in :attr:`flet.Tooltip.trigger_mode` and + :attr:`flet.TooltipTheme.trigger_mode`. + + On desktop, a tooltip will be shown as soon as a pointer hovers over + the widget, regardless of the value of :attr:`flet.Tooltip.trigger_mode`. + """ + + MANUAL = "manual" + + TAP = "tap" + """ + Tooltip will be shown after a single tap. + """ + + LONG_PRESS = "long_press" + """ + Tooltip will be shown after a long press. + """ + + +@value +class Tooltip: + """ + Provide text labels which help explain the function of a button + or other user interface action. + """ + + message: str + """ + The text to display in this tooltip. + """ + + decoration: Optional[BoxDecoration] = None + """ + The background decoration of this tooltip. + + If `None`, :attr:`flet.TooltipTheme.decoration` is used. + If that is also `None`, a default decoration will be picked based + on the current theme mode: + + In light theme mode: + + ```python + ft.BoxDecoration( + border_radius=ft.BorderRadius.all(4.0), + bgcolor=ft.Colors.with_opacity(0.9, ft.Colors.GREY_700), + ) + ``` + + In dark theme mode: + + ```python + ft.BoxDecoration( + border_radius=ft.BorderRadius.all(4.0), + bgcolor=ft.Colors.with_opacity(0.9, ft.Colors.WHITE), + ) + ``` + """ + + enable_feedback: Optional[bool] = None + """ + When `True` (default) the tooltip should provide acoustic and/or haptic feedback. + + For example, on Android a tap will produce a clicking sound and a long-press + will produce a short vibration, when feedback is enabled. + """ + + vertical_offset: Optional[Number] = None + """ + The vertical gap between the control and the displayed tooltip. + + When :attr:`prefer_below` is set to `True` + and tooltips have sufficient space to + display themselves, this property defines how much vertical space + tooltips will position themselves under their corresponding controls. + Otherwise, tooltips will position themselves above their corresponding + controls with the given offset. + """ + + margin: Optional[MarginValue] = None + """ + The empty space that surrounds the tooltip. + + If `None`, :attr:`flet.TooltipTheme.margin` is used. + If that's is also `None`, defaults to `Margin.all(0.0)`. + """ + + padding: Optional[PaddingValue] = None + """ + The amount of space by which to inset the tooltip's content. + + It has the following default values based on the current platform: + + - On mobile platforms: `Padding.symmetric(horizontal=16.0, vertical=4.0)` + - On desktop platforms: `Padding.symmetric(horizontal=8.0, vertical=4.0)` + """ + + bgcolor: Optional[ColorValue] = None + """ + Background color of the tooltip. + """ + + text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` to use for the message of the tooltip. + """ + + text_align: Optional[TextAlign] = None + """ + How the message of the tooltip is aligned horizontally. + + If `None`, :attr:`flet.TooltipTheme.text_align` is used. + If that's is also `None`, defaults to :attr:`flet.TextAlign.START`. + """ + + prefer_below: Optional[bool] = None + """ + Whether the tooltip defaults to being displayed below the control. + + If there is insufficient space to display the tooltip in the preferred + direction, the tooltip will be displayed in the opposite direction. + + If `None`, :attr:`flet.TooltipTheme.prefer_below` is used. + If that's is also `None`, defaults to `True`. + """ + + show_duration: Optional[DurationValue] = None + """ + The length of time that the tooltip will be shown after a long press is released \ + (if triggerMode is :attr:`flet.TooltipTriggerMode.LONG_PRESS`) or a tap is \ + released (if triggerMode is :attr:`flet.TooltipTriggerMode.TAP`). + This property does not affect mouse pointer devices. + + If `None`, :attr:`flet.TooltipTheme.show_duration` is used. + If that's is also `None`, defaults to `1.5` seconds for long press and tap released + """ + + wait_duration: Optional[DurationValue] = None + """ + The length of time, in milliseconds, that a pointer must hover over a tooltip's \ + control before the tooltip will be shown. + + If `None`, :attr:`flet.TooltipTheme.wait_duration` is used. + If that's is also `None`, defaults to `100` milliseconds. + """ + + exit_duration: Optional[DurationValue] = None + """ + The length of time that the tooltip will be shown after a long press is released \ + or a tap is released or mouse pointer exits the control. + + If `None`, :attr:`flet.TooltipTheme.exit_duration` is used. + If that's is also `None`, defaults to 0 milliseconds - no delay. + """ + + tap_to_dismiss: bool = True + """ + Whether the tooltip can be dismissed by tapping on it. + """ + + exclude_from_semantics: Optional[bool] = False + """ + Whether the tooltip's message should be excluded from the semantics tree. + """ + + trigger_mode: Optional[TooltipTriggerMode] = None + """ + The mode of the tooltip's trigger. + + If `None`, :attr:`flet.TooltipTheme.trigger_mode` is used. + If that's is also `None`, defaults to + :attr:`flet.TooltipTriggerMode.LONG_PRESS`. + """ + + mouse_cursor: Optional[MouseCursor] = None + """ + The cursor for a mouse pointer when it enters or is hovering over the content. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Defines the constraints on the size of this tooltip. + + If `None`, :attr:`flet.TooltipTheme.size_constraints` is used. + If that's is also `None`, then a default value will be picked + based on the current platform: + + - on desktop platforms: `BoxConstraints(min_height=24.0)` + - on mobile platforms: `BoxConstraints(min_height=32.0)` + """ + + +TooltipValue = Union[str, Tooltip] +"""Type alias for tooltip values. + +Represents a tooltip as either: +- a `str` message, +- or a :class:`~flet.Tooltip`. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/material/vertical_divider.py b/sdk/python/packages/flet/src/flet/controls/material/vertical_divider.py new file mode 100644 index 0000000000..8303776628 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/material/vertical_divider.py @@ -0,0 +1,115 @@ +from typing import Annotated, Optional + +from flet.controls.base_control import control +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.control import Control +from flet.controls.types import ColorValue, Number +from flet.utils.validation import V + +__all__ = ["VerticalDivider"] + + +@control("VerticalDivider") +class VerticalDivider(Control): + """ + A thin vertical line, with padding on either side. + + In the material design language, this represents a divider. + + Example: + ```python + ft.Row( + width=120, + height=60, + expand=True, + spacing=0, + controls=[ + ft.Container( + bgcolor=ft.Colors.BLUE_GREY_200, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ft.VerticalDivider(), + ft.Container( + bgcolor=ft.Colors.GREY_500, + alignment=ft.Alignment.CENTER, + expand=True, + ), + ], + ) + ``` + + """ + + width: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The divider's width. The divider itself is always drawn as a vertical line that is \ + centered within the width specified by this value. + + If `None`, :attr:`flet.DividerTheme.space` is used. + If that's is also `None`, defaults to `16.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + thickness: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The thickness of this divider. + + Note: + A divider with a thickness of `0.0` is always drawn as a line with a width of + exactly one device pixel. + + If `None`, :attr:`flet.DividerTheme.thickness` is used. + If that's is also `None`, defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + color: Optional[ColorValue] = None + """ + The color to use when painting the line. + + If `None`, :attr:`flet.DividerTheme.color` is used. + """ + + leading_indent: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The amount of empty space to the leading edge of the divider. + + If `None`, :attr:`flet.DividerTheme.leading_indent` is used. + If that's is also `None`, defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + trailing_indent: Annotated[ + Optional[Number], + V.ge(0), + ] = None + """ + The amount of empty space to the trailing edge of the divider. + + If `None`, :attr:`flet.DividerTheme.trailing_indent` is used. + If that's is also `None`, defaults to `0.0`. + + Raises: + ValueError: If it is not greater than or equal to `0`. + """ + + radius: Optional[BorderRadiusValue] = None + """ + The border radius of the divider. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/multi_view.py b/sdk/python/packages/flet/src/flet/controls/multi_view.py new file mode 100644 index 0000000000..54821801f5 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/multi_view.py @@ -0,0 +1,22 @@ +from typing import Any + +from flet.controls.base_control import control +from flet.controls.base_page import BasePage + +__all__ = ["MultiView"] + + +@control() +class MultiView(BasePage): + """ + TBD + """ + + view_id: int + """ + TBD + """ + initial_data: dict[str, Any] + """ + TBD + """ diff --git a/sdk/python/packages/flet/src/flet/controls/object_patch.py b/sdk/python/packages/flet/src/flet/controls/object_patch.py new file mode 100644 index 0000000000..34a8be5baa --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/object_patch.py @@ -0,0 +1,1695 @@ +# +# python-json-patch - An implementation of the JSON Patch format +# https://github.com/stefankoegl/python-json-patch +# +# Copyright (c) 2011 Stefan Kögl +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +import dataclasses +import itertools +import logging +import weakref +from collections.abc import Iterator +from enum import Enum +from typing import Any, Optional + +from flet.controls.keys import Key + +logger = logging.getLogger("flet_object_patch") +logger.setLevel(logging.INFO) + +_ST_ADD = 0 +_ST_REMOVE = 1 + + +class Operation(Enum): + Replace = 0 + Add = 1 + Remove = 2 + Move = 3 + + +class ObjectPatchException(Exception): + """Base Object Patch exception""" + + +class InvalidObjectPatch(ObjectPatchException): + """Raised if an invalid Object Patch is created""" + + +class PatchOperation: + """A single operation inside an Object Patch.""" + + def __init__(self, operation: dict[str, Any]) -> None: + """Initialize an operation wrapper. + + Args: + operation: Patch operation dictionary containing a `path` member. + """ + if not operation.__contains__("path"): + raise InvalidObjectPatch("Operation must have a 'path' member") + + self.location = operation["path"] + self.operation = operation + + def __hash__(self) -> int: + """Return a hash based on the wrapped operation.""" + return hash(frozenset(self.operation.items())) + + def __eq__(self, other: Any) -> bool: + """Return whether another operation wrapper has the same operation.""" + if not isinstance(other, PatchOperation): + return False + return self.operation == other.operation + + def __ne__(self, other: Any) -> bool: + """Return whether another operation wrapper differs from this one.""" + return not (self == other) + + @property + def path(self) -> list[Any]: + """Path to the containing object or list.""" + return self.location[:-1] + + @property + def key(self) -> Any: + """Final path segment affected by this operation.""" + return self.location[-1] + + @key.setter + def key(self, value: Any) -> None: + """Update the final path segment affected by this operation.""" + self.location[-1] = value + self.operation["path"] = self.location + + def walk(self, doc: Any, part: Any) -> Any: + """Walks one step in doc and returns the referenced part""" + + if isinstance(doc, list): + try: + return doc[part] + + except IndexError: + raise ObjectPatchException(f"index '{part}' is out of bounds") from None + + # Else the object is a mapping or supports __getitem__ + # (so assume custom indexing) + try: + if hasattr(doc, "__getitem__"): + return doc[part] + else: + return getattr(doc, str(part)) + + except KeyError: + raise ObjectPatchException(f"member '{part}' not found in {doc}") from None + + def to_last(self, doc: Any) -> Any: + """Resolves ptr until the last step, returns (sub-doc, last-step)""" + + if not self.location: + return doc + + for part in self.location[:-1]: + doc = self.walk(doc, part) + + return doc + + +def _control_setattr(obj: Any, name: str, value: Any) -> None: + """Track plain dataclass mutations for later object diffing. + + Args: + obj: Dataclass instance receiving the assignment. + name: Field name being assigned. + value: New field value. + """ + # For plain dataclasses (no Prop tracking), this hook records the old + # value in __changes so _compare_dataclasses can detect the change. + # Prop-managed fields (on @control/@value types) are fully handled by + # Prop.__set__ and do not go through this path. + control_cls = getattr(type(obj), "__flet_control_cls__", None) + if not name.startswith("_") and ( + name != "data" or not control_cls or not isinstance(obj, control_cls) + ): + prop_defaults = getattr(type(obj), "_prop_defaults", None) + if prop_defaults is not None and name in prop_defaults: + # Prop field: delegate entirely to Prop.__set__ via normal setattr. + pass + else: + if hasattr(obj, "_frozen"): + raise RuntimeError("Frozen controls cannot be updated.") from None + # Track changes for plain-dataclass scalar fields. + changes = getattr(obj, "__changes", None) + if changes is not None: + current = getattr(obj, name, None) + if value == current: + return # no change — skip tracking and notification + if name not in changes: + changes[name] = current # record original on first write + elif value == changes[name]: + del changes[name] # reverted to original — net-zero change + if hasattr(obj, "_notify"): + obj._notify(name, value) + object.__setattr__(obj, name, value) + + +class RemoveOperation(PatchOperation): + """Removes an object property or an array element.""" + + def _on_undo_remove(self, path: list[Any], key: Any) -> Any: + """Adjust this remove after undoing an earlier remove at the same path.""" + if self.path == path: + if self.key >= key: + self.key += 1 + else: + key -= 1 + return key + + def _on_undo_add(self, path: list[Any], key: Any) -> Any: + """Adjust this remove after undoing an earlier add at the same path.""" + if self.path == path: + if self.key > key: + self.key -= 1 + else: + key -= 1 + return key + + +class AddOperation(PatchOperation): + """Adds an object property or an array element.""" + + def _on_undo_remove(self, path: list[Any], key: Any) -> Any: + """Adjust this add after undoing an earlier remove at the same path.""" + if self.path == path: + if self.key > key: + self.key += 1 + else: + key += 1 + return key + + def _on_undo_add(self, path: list[Any], key: Any) -> Any: + """Adjust this add after undoing an earlier add at the same path.""" + if self.path == path: + if self.key > key: + self.key -= 1 + else: + key += 1 + return key + + +class ReplaceOperation(PatchOperation): + """Replaces an object property or an array element by a new value.""" + + def _on_undo_remove(self, path: list[Any], key: Any) -> Any: + """Keep this replace stable when a remove is undone.""" + return key + + def _on_undo_add(self, path: list[Any], key: Any) -> Any: + """Keep this replace stable when an add is undone.""" + return key + + +class MoveOperation(PatchOperation): + """Moves an object property or an array element to a new location.""" + + @property + def from_path(self) -> list[Any]: + """Source path containing the item before the move.""" + return self.operation["from"][:-1] + + @property + def from_key(self) -> Any: + """Final source path segment for the moved item.""" + return self.operation["from"][-1] + + @from_key.setter + def from_key(self, value: Any) -> None: + """Update the final source path segment for the moved item.""" + self.operation["from"][-1] = value + + def _on_undo_remove(self, path: list[Any], key: Any) -> Any: + """Adjust this move after undoing an earlier remove at the same path.""" + if self.from_path == path: + if self.from_key >= key: + self.from_key += 1 + else: + key -= 1 + if self.path == path: + if self.key > key: + self.key += 1 + else: + key += 1 + return key + + def _on_undo_add(self, path: list[Any], key: Any) -> Any: + """Adjust this move after undoing an earlier add at the same path.""" + if self.from_path == path: + if self.from_key > key: + self.from_key -= 1 + else: + key -= 1 + if self.path == path: + if self.key > key: + self.key -= 1 + else: + key += 1 + return key + + +class ObjectPatch: + """An Object Patch is a list of Patch Operations.""" + + def __init__(self, patch: list[dict[str, Any]]) -> None: + """Initialize an object patch. + + Args: + patch: Ordered list of patch operation dictionaries. + """ + self.patch = patch + + def __str__(self) -> str: + """Return the patch operations as a string.""" + return str(self.patch) + + @classmethod + def from_diff( + cls, + src: Any, + dst: Any, + control_cls: type[Any], + parent: Any = None, + path: Optional[list[Any]] = None, + frozen: bool = False, + ) -> tuple["ObjectPatch", list[Any], list[Any]]: + """Create a patch from a source and destination object tree. + + Args: + src: Previous object tree. + dst: New object tree. + control_cls: Base control class used to detect controls. + parent: Parent control for the compared object tree. + path: Initial patch path. + frozen: Whether the comparison should treat objects as immutable. + + Returns: + A tuple containing the patch, added controls, and removed controls. + """ + builder = DiffBuilder( + src, + dst, + control_cls=control_cls, + ) + builder._compare_values(parent, path or [], None, src, dst, frozen=frozen) + + ops = list(builder.execute()) + added = list(builder.get_added_controls()) + removed = list(builder.get_removed_controls()) + + builder.teardown() + + return cls(ops), added, removed + + def to_message(self) -> list[Any]: + """Encode patch operations into the compact protocol message format.""" + state = {"i": 0} + paths = [state["i"]] + state["i"] += 1 + + def encode_path(path: list[Any]) -> list[Any]: + """Encode a patch path into shared path-table coordinates.""" + node = paths + parent = paths + parts = path + len_parts = len(parts) + if len_parts == 0: + return [0, 0] # root object + n = 0 + while n < len_parts - 1: + if len(parent) == 1: + parent.append({}) + node = parent[1].get(parts[n], None) + if node is None: + node = [state["i"]] + parent[1][parts[n]] = node + state["i"] += 1 + parent = node + n += 1 + return [node[0], parts[n]] + + ops = [] + for op in self.patch: + if op["op"] == "remove": + ops.append( + [ + Operation.Remove, + *encode_path(op["path"]), + ] + ) + elif op["op"] == "replace": + ops.append( + [ + Operation.Replace, + *encode_path(op["path"]), + op["value"], + ] + ) + elif op["op"] == "add": + ops.append( + [ + Operation.Add, + *encode_path(op["path"]), + op["value"], + ] + ) + elif op["op"] == "move": + ops.append( + [ + Operation.Move, + *encode_path(op["from"]), + *encode_path(op["path"]), + ] + ) + else: + raise ObjectPatchException(f"Unknown operation: {op['op']}") + + return [paths, *ops] + + +class DiffBuilder: + def __init__( + self, + src_doc: Any, + dst_doc: Any, + control_cls: Optional[type[Any]] = None, + ) -> None: + """Initialize state used while building a diff. + + Args: + src_doc: Previous object tree. + dst_doc: New object tree. + control_cls: Base control class used to detect controls. + """ + self.control_cls = control_cls + self._added_dataclasses = {} + self._removed_dataclasses = {} + self.index_storage = [{}, {}] + self.index_storage2 = [[], []] + self.__root = root = [] + self.src_doc = src_doc + self.dst_doc = dst_doc + root[:] = [root, root, None] + + @staticmethod + def _update_list_snapshot( + snapshots: dict[Any, list[Any]], key: Any, value: list[Any] + ) -> None: + """Store or refresh a shallow snapshot of a list field.""" + snap = snapshots.get(key) + if snap is None: + snapshots[key] = value[:] + return + snap[:] = value + + @staticmethod + def _update_dict_snapshot( + snapshots: dict[Any, dict[Any, Any]], key: Any, value: dict[Any, Any] + ) -> None: + """Store or refresh a shallow snapshot of a dictionary field.""" + snap = snapshots.get(key) + if snap is None: + snapshots[key] = value.copy() + return + snap.clear() + snap.update(value) + + def teardown(self) -> None: + """Break cycles and release strong references to allow GC.""" + # clear indexes + self.index_storage = [{}, {}] + self.index_storage2 = [[], []] + self._added_dataclasses.clear() + self._removed_dataclasses.clear() + + # break the doubly linked list cycle + root = self.__root + if root: + root[:] = [root, root, None] + + # drop references to source/target docs + self.src_doc = None + self.dst_doc = None + + def get_added_controls(self) -> Iterator[Any]: + """Yield controls that were added while building the diff.""" + for key, dc in self._added_dataclasses.items(): + configure_setattr_only = key in self._removed_dataclasses + yield from self._configure_dataclass( + dc, None, False, configure_setattr_only + ) + + def get_removed_controls(self) -> Iterator[Any]: + """Yield controls that were removed while building the diff.""" + for key, dc in self._removed_dataclasses.items(): + recurse = key not in self._added_dataclasses + yield from self._removed_controls(dc, recurse) + + def store_index(self, value: Any, index: list[Any], st: int) -> None: + """Store an operation index for later add/remove pairing.""" + value_type = type(value) + try: + storage = self.index_storage[st] + typed_storage = storage.get(value_type) + if typed_storage is None: + typed_storage = {} + storage[value_type] = typed_storage + stored = typed_storage.get(value) + if stored is None: + typed_storage[value] = [index] + else: + stored.append(index) + + except TypeError: + self.index_storage2[st].append([value_type, value, index]) + + def take_index(self, value: Any, st: int) -> Optional[list[Any]]: + """Take the latest stored operation index matching a value.""" + value_type = type(value) + try: + typed_storage = self.index_storage[st].get(value_type) + if typed_storage is None: + return None + stored = typed_storage.get(value) + if stored: + return stored.pop() + + except TypeError: + storage = self.index_storage2[st] + for i in range(len(storage) - 1, -1, -1): + item_type, item_value, item_index = storage[i] + if item_type is value_type and item_value == value: + storage.pop(i) + return item_index + + def insert(self, op: PatchOperation) -> list[Any]: + """Insert an operation into the internal operation chain.""" + root = self.__root + last = root[0] + last[1] = root[0] = [last, root, op] + return root[0] + + def remove(self, index: list[Any]) -> None: + """Remove an operation node from the internal operation chain.""" + link_prev, link_next, _ = index + link_prev[1] = link_next + link_next[0] = link_prev + index[:] = [] + + def iter_from(self, start: list[Any]) -> Iterator[PatchOperation]: + """Yield operations after a given operation node.""" + root = self.__root + curr = start[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __iter__(self) -> Iterator[PatchOperation]: + """Yield operation nodes in insertion order.""" + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def execute(self) -> Iterator[dict[str, Any]]: + """Yield final patch operations, folding remove/add pairs into replace ops.""" + root = self.__root + curr = root[1] + while curr is not root: + if curr[1] is not root: + op_first, op_second = curr[2], curr[1][2] + if ( + op_first.location == op_second.location + and isinstance(op_first, RemoveOperation) + and isinstance(op_second, AddOperation) + ): + yield ReplaceOperation( + { + "op": "replace", + "path": op_second.location, + "value": op_second.operation["value"], + } + ).operation + curr = curr[1][1] + continue + yield curr[2].operation + curr = curr[1] + + def _index_key(self, item: Any, item_key: Any, path: list[Any]) -> Any: + """ + Return the composite key used to pair add/remove (by control key if present). + """ + return item_key if item_key is not None else item + + def _maybe_compare_dataclasses( + self, parent: Any, path: list[Any], src: Any, dst: Any, frozen: bool + ) -> None: + """ + Compare dataclasses only when both are dataclasses and identity/"frozen" rules \ + allow it. + """ + if not (dataclasses.is_dataclass(src) and dataclasses.is_dataclass(dst)): + return + if not frozen and src is dst: + # Non-frozen in-place: same Python object, use __changes tracking. + self._compare_dataclasses(parent, path, src, dst, False) + elif src is not dst and type(src) is type(dst): + # Different Python objects of the same type. + # Frozen diff always applies; non-frozen applies when they share an + # explicit key (rebuilt object scenario – treat as frozen comparison). + same_explicit_key = ( + not frozen + and get_control_key(src) is not None + and get_control_key(src) == get_control_key(dst) + ) + if frozen or same_explicit_key: + self._compare_dataclasses(parent, path, src, dst, True) + + def _affected_is_list(self, op: PatchOperation) -> bool: + """ + Return True if the item the op affects lives in a list in the destination doc. + We must not rely on op.key’s type because PatchOperation coerces to int. + """ + container = op.to_last(self.dst_doc) + return isinstance(container, list) + + def _emit_move(self, from_loc: list[Any], to_loc: list[Any]) -> None: + """Create and insert a move operation.""" + self.insert(MoveOperation({"op": "move", "from": from_loc, "path": to_loc})) + + def _item_added( + self, + parent: Any, + path: list[Any], + key: Any, + item: Any, + item_key: Any = None, + frozen: bool = False, + ) -> None: + """Record an added item or pair it with a previous remove as a move. + + Args: + parent: Parent control for dataclasses nested in the added item. + path: Path to the containing object or list. + key: Final path segment for the added item. + item: Added value. + item_key: Optional reconciliation key for move detection. + frozen: Whether nested dataclasses should be diffed as immutable. + """ + logger.debug( + f"_item_added: path={path} key={key} item={item} item_key={item_key}" + ) + + index_key = self._index_key(item, item_key, path) + paired_idx = self.take_index(index_key, _ST_REMOVE) + + # A matching 'remove' exists: it's a move (or an in-place update) + if paired_idx is not None: + rem_op: RemoveOperation = paired_idx[2] # the earlier remove + src = rem_op.operation["value"] + dst = item + + # undo bookkeeping for the removed dataclass (it’s coming back) + self._undo_dataclass_removed(src) + + # If the affected sequence is a list, adjust later op indices after removal + if isinstance(rem_op.key, int) and isinstance(key, int): + for v in self.iter_from(paired_idx): + rem_op.key = v._on_undo_remove(rem_op.path, rem_op.key) + + # Drop the paired remove from the chain: we’re going to emit either + # compares or a move + self.remove(paired_idx) + + src_loc = rem_op.location + dst_loc = _path_join(path, key) + + # Compare first (for dataclasses), anchored at source or dest depending + # on whether we move + if src_loc != dst_loc: + # Compare on the source location before we move (matches your tests’ + # expectations) + self._maybe_compare_dataclasses(parent, src_loc, src, dst, frozen) + # Then emit the move + self._emit_move(src_loc, dst_loc) + return + else: + # No move, just in-place updates + self._maybe_compare_dataclasses(parent, dst_loc, src, dst, frozen) + return + + # No matching remove: this is a plain add + add_op = AddOperation( + {"op": "add", "path": _path_join(path, key), "value": item} + ) + add_idx = self.insert(add_op) + self.store_index(index_key, add_idx, _ST_ADD) + self._dataclass_added(item, parent, frozen) + + def _item_removed( + self, + path: list[Any], + key: Any, + item: Any, + item_key: Any = None, + frozen: bool = False, + ) -> None: + """Record a removed item or pair it with a previous add as a move. + + Args: + path: Path to the containing object or list. + key: Final path segment for the removed item. + item: Removed value. + item_key: Optional reconciliation key for move detection. + frozen: Whether nested dataclasses should be diffed as immutable. + """ + logger.debug( + f"_item_removed: path={path} key={key} item={item} item_key={item_key}" + ) + + index_key = self._index_key(item, item_key, path) + rem_op = RemoveOperation( + {"op": "remove", "path": _path_join(path, key), "value": item} + ) + rem_idx = self.insert(rem_op) + + paired_idx = self.take_index(index_key, _ST_ADD) + + # A matching 'add' exists: it's a move (or an in-place update) + if paired_idx is not None: + add_op: AddOperation = paired_idx[2] # the earlier add + src = item + dst = add_op.operation["value"] + + # undo bookkeeping for the added dataclass (it’s being consumed by the move) + self._undo_dataclass_added(dst) + + # If the added op affects a list, adjust later ops after that add + if self._affected_is_list(add_op): + for v in self.iter_from(paired_idx): + add_op.key = v._on_undo_add(add_op.path, add_op.key) + + src_loc = rem_op.location + dst_loc = add_op.location + + # The earlier add no longer stands on its own + self.remove(paired_idx) + + if src_loc != dst_loc: + # If we’re moving, compare anchored at the source BEFORE the move + # (matches your tests) + self._maybe_compare_dataclasses( + dst.parent if hasattr(dst, "parent") else None, + src_loc, + src, + dst, + frozen, + ) + # Turn the just-inserted remove into a move (reuse node) + rem_idx[2] = MoveOperation( + {"op": "move", "from": src_loc, "path": dst_loc} + ) + return + else: + # No move after all; drop the remove from the chain (pair consumed) + self.remove(rem_idx) + # In-place updates only + self._maybe_compare_dataclasses( + dst.parent if hasattr(dst, "parent") else None, + _path_join(add_op.path, add_op.key), + src, + dst, + frozen, + ) + return + + # No matching add: keep the remove and remember this dataclass + self.store_index(index_key, rem_idx, _ST_REMOVE) + self._dataclass_removed(item) + + def _item_replaced(self, path: list[Any], key: Any, item: Any) -> None: + """Record a replacement operation for a value at a path segment.""" + logger.debug("_item_replaced: %s %s %s:", path, key, item) + self.insert( + ReplaceOperation( + { + "op": "replace", + "path": _path_join(path, key), + "value": item, + } + ) + ) + + def _compare_dicts( + self, + parent: Any, + path: list[Any], + src: dict[Any, Any], + dst: dict[Any, Any], + frozen: bool, + ) -> None: + """Compare two dictionaries and emit operations for changed entries.""" + logger.debug("\n_compare_dicts: %s %s %s", path, src, dst) + + src_keys = set(src.keys()) + dst_keys = set(dst.keys()) + added_keys = dst_keys - src_keys + removed_keys = src_keys - dst_keys + + for key in removed_keys: + self._item_removed(path, str(key), src[key], frozen=frozen) + + for key in added_keys: + self._item_added(parent, path, str(key), dst[key], frozen=frozen) + + for key in src_keys & dst_keys: + self._compare_values(parent, path, key, src[key], dst[key], frozen) + + def _compare_lists( + self, + parent: Any, + path: list[Any], + src: list[Any], + dst: list[Any], + frozen: bool, + ) -> None: + """Compare two lists using positional or keyed reconciliation.""" + logger.debug("\n_compare_lists: %s %s %s", path, src, dst) + + # Decide algorithm based on whether any dataclasses are present. + # Pure-primitive / pure-dict lists use the simpler positional algorithm which + # produces minimal diffs for insertion/deletion. Lists that contain at least + # one dataclass use the hybrid keyed algorithm which preserves identity across + # reorders and across Python-object rebuilds (when explicit keys are provided). + has_any_dataclass = any( + dataclasses.is_dataclass(obj) for obj in itertools.chain(src, dst) + ) + + if not has_any_dataclass: + # ----- Positional diff for pure-primitive / pure-dict lists ----- + len_src, len_dst = len(src), len(dst) + max_len = max(len_src, len_dst) + min_len = min(len_src, len_dst) + for key in range(max_len): + if key < min_len: + old, new = src[key], dst[key] + logger.debug( + f"\n\nCOMPARE LIST ITEM: {key}\n\nOLD: {old}\n\nNEW: {new}" + ) + if isinstance(old, dict) and isinstance(new, dict): + self._compare_dicts( + parent, _path_join(path, key), old, new, frozen + ) + elif isinstance(old, list) and isinstance(new, list): + self._compare_lists( + parent, _path_join(path, key), old, new, frozen + ) + elif type(old) is not type(new) or old != new: + self._item_removed(path, key, old, frozen=frozen) + self._item_added(parent, path, key, new, frozen=frozen) + elif len_src > len_dst: + self._item_removed(path, len_dst, src[key], frozen=frozen) + else: + self._item_added(parent, path, key, dst[key], frozen=frozen) + return + + # ----- Hybrid keyed algorithm for lists containing dataclasses ----- + # + # Composite key assignment: + # frozen mode: + # explicit key → ("k", key) – user-provided logical identity + # unkeyed dc → ("pos", n) – positional among unkeyed items + # non-frozen mode: + # explicit key → ("k", key) – allows matching rebuilt objects + # no explicit → ("id", id(obj)) – Python-object identity + # non-dataclass items (primitives): + # always → ("prim", n) – positional among non-dc items + # + # Using tuple-namespaced keys prevents collisions between the four classes. + + def build_keys(items: list[Any]) -> list[tuple[str, Any]]: + """Build reconciliation keys for list items.""" + keys = [] + unkeyed_pos = 0 + prim_pos = 0 + for obj in items: + if dataclasses.is_dataclass(obj): + ek = get_control_key(obj) + if ek is not None: + keys.append(("k", ek)) + elif frozen: + keys.append(("pos", unkeyed_pos)) + unkeyed_pos += 1 + else: + keys.append(("id", id(obj))) + else: + keys.append(("prim", prim_pos)) + prim_pos += 1 + return keys + + src_keys = build_keys(src) + dst_keys = build_keys(dst) + + # Helper: determine effective frozen flag for a matched (old, new) pair. + # A non-frozen pair matched by explicit key (different Python objects) must + # be diffed like a frozen pair since the new object has no __changes log. + def _effective_frozen(old_item: Any, new_item: Any) -> bool: + """Return whether a matched pair must be compared as frozen.""" + if frozen: + return True + if old_item is not new_item: + old_ck = get_control_key(old_item) + if old_ck is not None and old_ck == get_control_key(new_item): + return True + return False + + if src_keys == dst_keys: + # Keys identical and in the same order: positional diff (fast path). + for idx, (old, new) in enumerate(zip(src, dst)): + if isinstance(old, dict) and isinstance(new, dict): + self._compare_dicts(parent, _path_join(path, idx), old, new, frozen) + elif isinstance(old, list) and isinstance(new, list): + self._compare_lists(parent, _path_join(path, idx), old, new, frozen) + elif dataclasses.is_dataclass(old) and dataclasses.is_dataclass(new): + same_type = type(old) is type(new) + same_component_fn = True + if ( + getattr(old, "_c", None) == "C" + and getattr(new, "_c", None) == "C" + ): + same_component_fn = getattr(old, "fn", None) is getattr( + new, "fn", None + ) + if same_type and same_component_fn: + frozen_eff = _effective_frozen(old, new) + self._compare_dataclasses( + parent, _path_join(path, idx), old, new, frozen_eff + ) + else: + # Different types or different component function: use + # remove+add so controls are registered in added/removed + # sets; execute() collapses same-path pairs to replace. + self._item_removed(path, idx, old, frozen=frozen) + self._item_added(parent, path, idx, new, frozen=frozen) + elif type(old) is not type(new) or old != new: + self._item_replaced(path, idx, new) + return + + # -------- Keyed, React-style reconciliation -------- + # We’ll mutate a working copy of the old list so emitted indices are "live". + work = list(src) + work_keys = src_keys[:] + # Map key -> current index in `work` + pos = {key: i for i, key in enumerate(work_keys)} + new_index_by_key = {key: i for i, key in enumerate(dst_keys)} + new_keys_set = set(new_index_by_key.keys()) + + def _reindex(start_idx: int) -> None: + """Refresh current key positions after a work-list mutation.""" + for j in range(start_idx, len(work_keys)): + pos[work_keys[j]] = j + + def _remove_from_work(idx: int) -> tuple[Any, Any]: + """Remove and return an item/key pair from the working list.""" + removed_item = work.pop(idx) + removed_key = work_keys.pop(idx) + pos.pop(removed_key, None) + if idx < len(work_keys): + _reindex(idx) + return removed_item, removed_key + + def _insert_into_work(idx: int, item: Any, key: Any) -> None: + """Insert an item/key pair into the working list.""" + work.insert(idx, item) + work_keys.insert(idx, key) + pos[key] = idx + if idx + 1 <= len(work_keys): + _reindex(idx + 1) + + def emit_replace_at(idx: int, old_item: Any, new_item: Any) -> None: + """Emit updates or replacement for the item currently at an index.""" + # Keying by identity means old_item is often new_item, so we explicitly run + # the dataclass diff even when the instance pointer matches to surface + # property mutations captured by __changes. + if dataclasses.is_dataclass(old_item) and dataclasses.is_dataclass( + new_item + ): + frozen_local = ( + (old_item is not None and hasattr(old_item, "_frozen")) + or (new_item is not None and hasattr(new_item, "_frozen")) + or _effective_frozen(old_item, new_item) + ) + old_control_key = get_control_key(old_item) + new_control_key = get_control_key(new_item) + + def _keys_match() -> bool: + """Return whether optional explicit control keys are compatible.""" + return ( + old_control_key is None + or new_control_key is None + or old_control_key == new_control_key + ) + + same_type = type(old_item) is type(new_item) + same_component_fn = True + # Component controls (type "C") must only be diffed/migrated when + # their underlying component function is the same. Otherwise we + # need a replace to force remount and fresh hook state. + if ( + getattr(old_item, "_c", None) == "C" + and getattr(new_item, "_c", None) == "C" + ): + same_component_fn = getattr(old_item, "fn", None) is getattr( + new_item, "fn", None + ) + + if (not frozen_local and old_item is new_item) or ( + frozen_local + and old_item is not new_item + and same_type + and same_component_fn + and _keys_match() + ): + self._compare_dataclasses( + parent, _path_join(path, idx), old_item, new_item, frozen_local + ) + return + + if type(old_item) is not type(new_item) or old_item != new_item: + if dataclasses.is_dataclass(old_item) or dataclasses.is_dataclass( + new_item + ): + # Controls must go through remove+add so the added/removed + # registries stay consistent; execute() folds adjacent + # same-path pairs into a replace op. + self._item_removed(path, idx, old_item, frozen=frozen) + self._item_added(parent, path, idx, new_item, frozen=frozen) + else: + self._item_replaced(path, idx, new_item) + + # Scan forward through desired new order. + i = 0 + while i < len(dst): + target_key = dst_keys[i] + + # First, delete any items currently at position i that should NOT be here: + # - keys that don't exist anymore + # - or keys that exist but must appear BEFORE i in the new order + # (they are out of place here) + while i < len(work): + cur_key = work_keys[i] + if cur_key not in new_keys_set: + # remove disappearing item at i + self._item_removed( + path, i, work[i], item_key=(cur_key, path), frozen=frozen + ) + _remove_from_work(i) + continue + desired_pos = new_index_by_key[cur_key] + if desired_pos < i: + # this item belongs earlier; it should have already been moved + # before. + # remove it here; it will be re-inserted (moved) where needed. + self._item_removed( + path, i, work[i], item_key=(cur_key, path), frozen=frozen + ) + _remove_from_work(i) + continue + break # current slot is ok to fill with target + + if target_key in pos: + cur_idx = pos[target_key] + old_item = work[cur_idx] + new_item = dst[i] + + if cur_idx == i: + # in place: just emit updates + emit_replace_at(i, old_item, new_item) + else: + # move from cur_idx -> i + # Emit updates anchored at SOURCE (cur_idx) before the move + # (matches your tests) + emit_replace_at(cur_idx, old_item, new_item) + + # Emit move + move_op = MoveOperation( + { + "op": "move", + "from": _path_join(path, cur_idx), + "path": _path_join(path, i), + } + ) + self.insert(move_op) + + # Apply the move in our working model + moved_item, _ = _remove_from_work(cur_idx) + insert_idx = i if cur_idx >= i else i + _insert_into_work(insert_idx, moved_item, target_key) + else: + # brand-new key: add at i + self._item_added( + parent, + path, + i, + dst[i], + item_key=(target_key, path), + frozen=frozen, + ) + _insert_into_work(i, dst[i], target_key) + + i += 1 + + # Finally, remove any trailing leftovers (present in old but not in new) + # We remove from the end so indices stay valid. + j = len(work) - 1 + while j >= 0: + key_j = work_keys[j] + if key_j not in new_keys_set: + self._item_removed( + path, j, work[j], item_key=(key_j, path), frozen=frozen + ) + _remove_from_work(j) + j -= 1 + + def _compare_dataclasses( + self, parent: Any, path: list[Any], src: Any, dst: Any, frozen: bool + ) -> None: + """Compare two dataclass instances and emit field-level operations. + + Args: + parent: Parent control for nested dataclasses. + path: Path to the dataclass being compared. + src: Previous dataclass instance. + dst: New dataclass instance. + frozen: Whether the comparison should scan immutable values instead + of relying on dirty/change tracking. + """ + logger.debug("\n_compare_dataclasses: %s\n\n%s\n%s\n", path, src, dst) + + if ( + self.control_cls + and isinstance(parent, self.control_cls) + and parent.is_isolated() + and parent != self.dst_doc + ): + return # do not update isolated control's children + + if self.control_cls and isinstance(dst, self.control_cls): + if frozen and hasattr(src, "_i"): + dst._migrate_state(src) + if not hasattr(dst, "_initialized"): + orig_frozen = getattr(dst, "_frozen", None) + if orig_frozen is not None: + del dst._frozen + dst.build() + if orig_frozen is not None: + object.__setattr__(dst, "_frozen", orig_frozen) + object.__setattr__(dst, "_initialized", True) + # Reconciled controls are fresh Python objects that take over + # the logical identity (_i) of their predecessor. Two things + # must be stamped on the new instance so the framework keeps + # working for it: + # 1. `_parent` — unset at creation, so `.page` would raise + # "Control must be added to the page first" otherwise. + # 2. `__index` on the session — the new instance must + # replace the old one so click events dispatched to + # `_i` reach the instance that lives in the current + # render tree. We queue the pair (old, new) so + # session.patch_control() reindexes without firing + # did_mount/will_unmount (the logical control wasn't + # added or removed, only reconciled). + if parent is not None and parent is not dst and src is not dst: + dst._parent = weakref.ref(parent) + # Queue both sides so session dedupes lifecycle hooks. + self._dataclass_added(dst, parent, frozen) + self._dataclass_removed(src) + dst._before_update_safe() + + if not frozen: + # In-place (non-frozen) comparison. + # + # Prop-managed scalar/event fields: _dirty (populated by + # Prop.__set__) records which fields changed. Emit a replace with + # the current _values entry — no old-value needed for scalars. + # + # Structural fields (lists, dicts, nested dataclasses): __prev_* + # snapshots from the last protocol serialisation cover both + # reassignment and in-place mutation, so __changes is not needed. + dirty = getattr(dst, "_dirty", None) + prev_lists = getattr(dst, "__prev_lists", {}) + prev_dicts = getattr(dst, "__prev_dicts", {}) + prev_classes = getattr(dst, "__prev_classes", {}) + + if dirty: + _values = getattr(dst, "_values", None) + prop_defaults = getattr(type(dst), "_prop_defaults", None) + fields_map = {f.name: f for f in dataclasses.fields(dst)} + for field_name in dirty: # dict → insertion order preserved + f = fields_map.get(field_name) + if f is None or f.metadata.get("skip", False): + continue + raw = getattr(dst, field_name, None) + + # Structural fields use _compare_values with the old + # snapshot from __prev_*, then update the snapshot. + # They are popped from __prev_* so the loops below do not + # re-process them. + if isinstance(raw, list): + old = prev_lists.pop(field_name, []) + self._compare_values(dst, path, field_name, old, raw, frozen) + self._update_list_snapshot(prev_lists, field_name, raw) + continue + if isinstance(raw, dict): + old = prev_dicts.pop(field_name, {}) + self._compare_values(dst, path, field_name, old, raw, frozen) + self._update_dict_snapshot(prev_dicts, field_name, raw) + continue + if dataclasses.is_dataclass(raw): + old = prev_classes.pop(field_name, None) + self._compare_values(dst, path, field_name, old, raw, frozen) + prev_classes[field_name] = raw + continue + if raw is None: + # Structural → None transition. + if field_name in prev_classes: + old = prev_classes.pop(field_name) + self._compare_values( + dst, path, field_name, old, None, frozen + ) + continue + if field_name in prev_lists: + old = prev_lists.pop(field_name) + self._compare_values( + dst, path, field_name, old, None, frozen + ) + continue + if field_name in prev_dicts: + old = prev_dicts.pop(field_name) + self._compare_values( + dst, path, field_name, old, None, frozen + ) + continue + + # Scalar / event field. + new = ( + _values.get(field_name, prop_defaults[field_name]) + if (_values is not None and prop_defaults is not None) + else raw + ) + if f.name.startswith("on_") and f.metadata.get("event", True): + new = new is not None + logger.debug("\n\n_compare_values:dirty %s %s", field_name, new) + self._item_replaced(path, field_name, new) + dst._dirty.clear() + + # Plain-dataclass scalar changes recorded by _control_setattr. + changes = getattr(dst, "__changes", None) + if changes: + fields_map = ( + fields_map + if dirty + else {f.name: f for f in dataclasses.fields(dst)} + ) + for field_name in list(changes): + f = fields_map.get(field_name) + if f is None or f.metadata.get("skip", False): + continue + new = getattr(dst, field_name) + if f.name.startswith("on_") and f.metadata.get("event", True): + new = new is not None + self._item_replaced(path, field_name, new) + changes.clear() + + processed_structural_fields = set() + + # compare lists + for field_name, old in list(prev_lists.items()): + processed_structural_fields.add(field_name) + new = getattr(dst, field_name) + if not isinstance(new, list): + del prev_lists[field_name] + self._compare_values(dst, path, field_name, old, new, frozen) + if isinstance(new, list): + self._update_list_snapshot(prev_lists, field_name, new) + + # compare dicts + for field_name, old in list(prev_dicts.items()): + processed_structural_fields.add(field_name) + new = getattr(dst, field_name) + if not isinstance(new, dict): + del prev_dicts[field_name] + self._compare_values(dst, path, field_name, old, new, frozen) + if isinstance(new, dict): + self._update_dict_snapshot(prev_dicts, field_name, new) + + # compare dataclasses + for field_name, old in list(prev_classes.items()): + processed_structural_fields.add(field_name) + new = getattr(dst, field_name) + if not dataclasses.is_dataclass(new): + del prev_classes[field_name] + else: + prev_classes[field_name] = new + self._compare_values(dst, path, field_name, old, new, frozen) + + # A structural field is removed from __prev_* when it becomes None. + # After the object has been serialized at least once, a later + # non-empty list/dict or dataclass value in that untracked field means + # a real None -> value restoration and must be patched. Before the + # first serialization there are no snapshots, so the same values are + # just initial state and must not trigger an incremental page update. + has_structural_snapshots = ( + hasattr(dst, "__prev_lists") + or hasattr(dst, "__prev_dicts") + or hasattr(dst, "__prev_classes") + ) + if has_structural_snapshots: + structural_fields = getattr( + type(dst), "_structural_fields", frozenset() + ) + for field_name in structural_fields: + if ( + field_name in processed_structural_fields + or (dirty and field_name in dirty) + or field_name in prev_lists + or field_name in prev_dicts + or field_name in prev_classes + ): + continue + new = getattr(dst, field_name) + if isinstance(new, list) and len(new) > 0: + self._compare_values(dst, path, field_name, None, new, frozen) + self._update_list_snapshot(prev_lists, field_name, new) + elif isinstance(new, dict) and len(new) > 0: + self._compare_values(dst, path, field_name, None, new, frozen) + self._update_dict_snapshot(prev_dicts, field_name, new) + elif dataclasses.is_dataclass(new): + self._compare_values(dst, path, field_name, None, new, frozen) + prev_classes[field_name] = new + else: + # frozen comparison + logger.debug( + "\nfrozen dataclass compare:%s\n\n dst:%s\n\n parent:%s", + src, + dst, + parent, + ) + src_vals = getattr(src, "_values", None) + dst_vals = getattr(dst, "_values", None) + if src_vals is not None and dst_vals is not None: + # Fast path: two focused loops, each proportional to the + # number of fields that actually need comparing. + # + # 1. Structural fields (_i, _c, controls, …) — always compare; + # typically just a handful per control type. + # 2. Active Prop fields — only those non-default on at least + # one side; read directly from _values to skip Prop.__get__. + structural = getattr(type(dst), "_structural_fields", frozenset()) + prop_defaults = getattr(type(dst), "_prop_defaults", {}) + event_fields = getattr(type(dst), "_event_fields", frozenset()) + + for fname in structural: + old = getattr(src, fname) + new = getattr(dst, fname) + self._compare_values(dst, path, fname, old, new, frozen) + + for fname in {**src_vals, **dst_vals}: + default = prop_defaults.get(fname) + old = src_vals.get(fname, default) + new = dst_vals.get(fname, default) + if old is new or old == new: + continue + if fname in event_fields: + old = old is not None + new = new is not None + self._compare_values(dst, path, fname, old, new, frozen) + else: + # Slow path: full field scan (objects without _values). + for field in dataclasses.fields(dst): + if not field.metadata.get("skip", False): + old = getattr(src, field.name) + new = getattr(dst, field.name) + if field.name.startswith("on_") and field.metadata.get( + "event", True + ): + old = old is not None + new = new is not None + self._compare_values(dst, path, field.name, old, new, frozen) + self._dataclass_removed(src) + self._dataclass_added(dst, parent, frozen) + + def _compare_values( + self, + parent: Any, + path: list[Any], + key: Any, + src: Any, + dst: Any, + frozen: bool, + ) -> None: + """Compare two values and dispatch to the correct specialized comparer.""" + logger.debug( + "\n_compare_values: %s %s (Frozen: %s)\n\n%s\n%s\n", + path, + key, + frozen, + src, + dst, + ) + + if isinstance(src, dict) and isinstance(dst, dict): + if (len(src) == 0 and len(dst) > 0) or (len(src) > 0 and len(dst) == 0): + self._item_replaced(path, key, dst) + self._dataclass_removed(src) + self._dataclass_added(dst, parent, frozen) + else: + self._compare_dicts(parent, _path_join(path, key), src, dst, frozen) + + elif isinstance(src, list) and isinstance(dst, list): + if (len(src) == 0 and len(dst) > 0) or (len(src) > 0 and len(dst) == 0): + self._item_replaced(path, key, dst) + self._dataclass_removed(src) + self._dataclass_added(dst, parent, frozen) + else: + self._compare_lists(parent, _path_join(path, key), src, dst, frozen) + + elif dataclasses.is_dataclass(src) and dataclasses.is_dataclass(dst): + frozen = ( + (src is not None and hasattr(src, "_frozen")) + or (dst is not None and hasattr(dst, "_frozen")) + or frozen + ) + + logger.debug( + "\n_compare_values:dataclasses (Frozen: %s) %s %s", frozen, src, dst + ) + + # Component controls (type "C") must only be diffed/migrated when + # their underlying component function is the same. Otherwise we + # need a replace to force remount and fresh hook state. + same_component_fn = True + if getattr(src, "_c", None) == "C" and getattr(dst, "_c", None) == "C": + same_component_fn = getattr(src, "fn", None) is getattr(dst, "fn", None) + + # Respect explicit `key` on single-child dataclass fields the + # same way list reconciliation does: a changed key signals + # "logically different element" and forces remount (remove + + # add) instead of in-place reconciliation. Without this, + # `ft.Container(content=Child(key=..))` silently ignores key + # changes because single-child fields don't go through the + # keyed list path. + keys_match = get_control_key(src) == get_control_key(dst) + + if (not frozen and src is dst) or ( + frozen + and src is not dst + and type(src) is type(dst) + and same_component_fn + and keys_match + ): + self._compare_dataclasses( + parent, _path_join(path, key), src, dst, frozen + ) + elif ( + (not frozen and src is not dst) + or (frozen and type(src) is not type(dst)) + or (frozen and not same_component_fn) + or (frozen and not keys_match) + ): + self._item_replaced(path, key, dst) + self._dataclass_removed(src) + self._dataclass_added(dst, parent, frozen) + + elif type(src) is not type(dst) or src != dst: + logger.debug( + "\n_compare_values:replaced %s %s %s\n\n%s %s", + path, + key, + src, + dst, + frozen, + ) + self._item_replaced(path, key, dst) + self._dataclass_removed(src) + self._dataclass_added(dst, parent, frozen) + + if not frozen: + # Snapshots live on the parent (which owns `key`), not on + # dst (the field's new value). + prev_lists = getattr(parent, "__prev_lists", {}) + prev_dicts = getattr(parent, "__prev_dicts", {}) + prev_classes = getattr(parent, "__prev_classes", {}) + + if isinstance(src, list) and key in prev_lists: + del prev_lists[key] + if isinstance(src, dict) and key in prev_dicts: + del prev_dicts[key] + if dataclasses.is_dataclass(src) and key in prev_classes: + del prev_classes[key] + if isinstance(dst, list) and key is not None: + self._update_list_snapshot(prev_lists, key, dst) + if isinstance(dst, dict) and key is not None: + self._update_dict_snapshot(prev_dicts, key, dst) + if dataclasses.is_dataclass(dst) and key is not None: + prev_classes[key] = dst + + def _dataclass_added(self, item: Any, parent: Any, frozen: bool) -> None: + """Register dataclasses contained in a newly added value.""" + logger.debug("\n\nDataclass added: %s %s %s", item, parent, frozen) + if dataclasses.is_dataclass(item): + if parent: + logger.debug("\n\nAdding parent %s to item: %s", parent, item) + if parent is item: + raise ObjectPatchException(f"Parent is the same as item: {item}") + item._parent = weakref.ref(parent) + else: + logger.debug("\n\nSkip adding parent to item: %s", item) + if frozen: + item._frozen = frozen + + logger.debug("\n_dataclass_added: %s", self._get_dataclass_key(item)) + self._added_dataclasses[self._get_dataclass_key(item)] = item + + elif isinstance(item, dict): + for v in item.values(): + self._dataclass_added(v, parent, frozen) + + elif isinstance(item, list): + for v in item: + self._dataclass_added(v, parent, frozen) + + def _undo_dataclass_added(self, item: Any) -> None: + """Undo added-dataclass bookkeeping after an add pairs with a remove.""" + self._added_dataclasses.pop(self._get_dataclass_key(item), None) + + def _dataclass_removed(self, item: Any) -> None: + """Register dataclasses contained in a removed value.""" + logger.debug("\n\nDataclass removed: %s", item) + if dataclasses.is_dataclass(item): + self._removed_dataclasses[self._get_dataclass_key(item)] = item + + elif isinstance(item, dict): + for v in item.values(): + self._dataclass_removed(v) + + elif isinstance(item, list): + for v in item: + self._dataclass_removed(v) + + def _undo_dataclass_removed(self, item: Any) -> None: + """Undo removed-dataclass bookkeeping after a remove pairs with an add.""" + if dataclasses.is_dataclass(item): + self._removed_dataclasses.pop(self._get_dataclass_key(item), None) + + def _get_dataclass_key(self, item: Any) -> Any: + """Return the registry key used for added/removed dataclass tracking.""" + return ( + item._i + if self.control_cls and isinstance(item, self.control_cls) + else str(id(item)) + ) + + def _configure_dataclass( + self, + item: Any, + parent: Any, + frozen: bool, + configure_setattr_only: bool = False, + ) -> Iterator[Any]: + """Prepare a dataclass subtree for diffing. + + Assigns parent/frozen metadata, builds real controls, and keeps controls + nested inside value objects attached to the nearest actual control parent. + + Args: + item: Object to configure. Non-dataclass values are ignored. + parent: Nearest control parent for `item`, if already known. + frozen: Whether configured dataclasses should be marked as frozen. + configure_setattr_only: Whether to only refresh metadata used by + generated `__setattr__` handlers, without building controls or + recursing through fields. + + Yields: + Controls discovered while walking the dataclass subtree. + """ + if dataclasses.is_dataclass(item): + logger.debug( + "\n_configure_dataclass: %s %s %s", item, frozen, configure_setattr_only + ) + + # In-place updates can re-enter configuration from an object that + # already belongs to a control tree. Reuse that existing parent so + # newly nested children inherit the correct control/page context. + if parent is None: + parent_ref = getattr(item, "_parent", None) + parent = parent_ref() if parent_ref else None + + if parent: + if parent is item: + raise ObjectPatchException(f"Parent is the same as item: {item}") + item._parent = weakref.ref(parent) + + if hasattr(item, "_frozen"): + frozen = item._frozen + elif frozen: + item._frozen = frozen + + item_cls = item.__class__ + if getattr(item_cls, "__flet_control_cls__", None) is None: + item_cls.__flet_control_cls__ = self.control_cls + + if self.control_cls and isinstance(item, self.control_cls): + if not configure_setattr_only: + item.build() + item._before_update_safe() + object.__setattr__(item, "_initialized", True) + yield item + + # recurse through fields + if not configure_setattr_only: + # Value objects can contain controls, but they are not controls + # themselves. Keep nested controls attached to the nearest + # actual control parent so event dispatch can resolve page. + child_parent = ( + item + if self.control_cls and isinstance(item, self.control_cls) + else parent + ) + for field in dataclasses.fields(item): + if not field.metadata.get("skip", False): + yield from self._configure_dataclass( + getattr(item, field.name), child_parent, frozen + ) + + if not frozen: + # Clear _dirty so post-configuration mutations are tracked + # incrementally from a clean baseline. + dst_dirty = getattr(item, "_dirty", None) + if dst_dirty is not None: + dst_dirty.clear() + else: + # Plain dataclass without Prop tracking: install + # _control_setattr to capture scalar changes in __changes. + item_cls = type(item) + if item_cls.__setattr__ is not _control_setattr: + item_cls.__setattr__ = _control_setattr + object.__setattr__(item, "__changes", {}) + + elif isinstance(item, dict): + for v in item.values(): + yield from self._configure_dataclass(v, parent, frozen) + + elif isinstance(item, list): + for v in item: + yield from self._configure_dataclass(v, parent, frozen) + + def _removed_controls(self, item: Any, recurse: bool) -> Iterator[Any]: + """Yield removed controls contained in a value. + + Args: + item: Value that may contain controls. + recurse: Whether to scan dataclass fields when snapshot metadata is + unavailable. + + Yields: + Removed controls discovered in `item`. + """ + if self.control_cls and isinstance(item, self.control_cls): + if hasattr(item, "__prev_lists"): + # recurse through list props + for item_list in getattr(item, "__prev_lists", {}).values(): + yield from self._removed_controls(item_list, recurse) + + # recurse through dict props + for item_dict in getattr(item, "__prev_dicts", {}).values(): + yield from self._removed_controls(item_dict, recurse) + + # recurse through dataclass props + for item_class in getattr(item, "__prev_classes", {}).values(): + yield from self._removed_controls(item_class, recurse) + elif recurse: + # recurse through fields + for field in dataclasses.fields(item): + if not field.metadata.get("skip", False): + yield from self._removed_controls( + getattr(item, field.name), + recurse, + ) + + yield item + + elif isinstance(item, dict): + for v in item.values(): + yield from self._removed_controls(v, recurse) + + elif isinstance(item, list): + for v in item: + yield from self._removed_controls(v, recurse) + + +def get_control_key(obj: Any) -> Any: + """Return the explicit control key for an object, if any.""" + # Fast path: read from _values directly to avoid Prop.__get__ overhead. + _values = getattr(obj, "_values", None) + key = _values.get("key") if _values is not None else getattr(obj, "key", None) + return key.value if isinstance(key, Key) else key + + +def _path_join(path: list[Any], key: Any) -> list[Any]: + """Return a child path by appending `key` when present.""" + if key is None: + return path + return path + [key] diff --git a/sdk/python/packages/flet/src/flet/controls/padding.py b/sdk/python/packages/flet/src/flet/controls/padding.py new file mode 100644 index 0000000000..0883f5501f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/padding.py @@ -0,0 +1,73 @@ +from typing import Union + +from flet.controls.base_control import value +from flet.controls.types import Number + +__all__ = [ + "Padding", + "PaddingValue", +] + + +@value +class Padding: + """ + Defines padding for all sides of a rectangle. + """ + + left: Number = 0 + """ + The padding value for the left side of the rectangle. + """ + + top: Number = 0 + """ + The padding value for the top side of the rectangle. + """ + + right: Number = 0 + """ + The padding value for the right side of the rectangle. + """ + + bottom: Number = 0 + """ + The padding value for the bottom side of the rectangle. + """ + + @classmethod + def all(cls, value: Number) -> "Padding": + """ + Applies the same padding to all sides. + """ + return Padding(left=value, top=value, right=value, bottom=value) + + @classmethod + def symmetric(cls, *, vertical: Number = 0, horizontal: Number = 0) -> "Padding": + """ + Applies `vertical` padding to top and bottom sides and `horizontal` padding to \ + left and right sides. + """ + return Padding(left=horizontal, top=vertical, right=horizontal, bottom=vertical) + + @classmethod + def only( + cls, *, left: Number = 0, top: Number = 0, right: Number = 0, bottom: Number = 0 + ) -> "Padding": + """ + Applies padding to the specified sides. + """ + return Padding(left=left, top=top, right=right, bottom=bottom) + + @classmethod + def zero(cls) -> "Padding": + return Padding.only() + + +PaddingValue = Union[Number, Padding] +"""Type alias for padding values. + +Represents padding as either: +- a single numeric value applied to all sides, +- or an explicit :class:`~flet.Padding` configuration. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/page.py b/sdk/python/packages/flet/src/flet/controls/page.py new file mode 100644 index 0000000000..31729928cf --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/page.py @@ -0,0 +1,1429 @@ +import asyncio +import inspect +import logging +import sys +import threading +import weakref +from collections.abc import Awaitable, Coroutine +from concurrent.futures import CancelledError, Future, ThreadPoolExecutor +from dataclasses import InitVar, dataclass, field +from functools import partial +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Optional, + TypeVar, + Union, +) +from urllib.parse import urlparse + +from flet.auth.authorization import Authorization +from flet.auth.oauth_provider import OAuthProvider +from flet.components.component import Renderer +from flet.components.public_utils import unwrap_component +from flet.controls.base_control import BaseControl, control +from flet.controls.base_page import BasePage +from flet.controls.context import _context_page, context +from flet.controls.control import Control +from flet.controls.control_event import ( + ControlEvent, + ControlEventHandler, + Event, + EventHandler, +) +from flet.controls.core.view import View +from flet.controls.core.window import Window +from flet.controls.device_info import ( + AndroidDeviceInfo, + DeviceInfo, + IosDeviceInfo, + LinuxDeviceInfo, + MacOsDeviceInfo, + WebDeviceInfo, + WindowsDeviceInfo, +) +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.multi_view import MultiView +from flet.controls.query_string import QueryString +from flet.controls.ref import Ref +from flet.controls.services.browser_context_menu import BrowserContextMenu +from flet.controls.services.clipboard import Clipboard +from flet.controls.services.service import Service +from flet.controls.services.shared_preferences import SharedPreferences +from flet.controls.services.storage_paths import StoragePaths +from flet.controls.services.url_launcher import UrlLauncher +from flet.controls.types import ( + AppLifecycleState, + Brightness, + DeviceOrientation, + Locale, + PagePlatform, + Url, + UrlTarget, + Wrapper, +) +from flet.utils import is_pyodide +from flet.utils.deprecated import deprecated +from flet.utils.from_dict import from_dict +from flet.utils.strings import random_string + +if not is_pyodide(): + from flet.auth.authorization_service import AuthorizationService + + AuthorizationImpl = AuthorizationService +else: + AuthorizationImpl = Authorization + +if TYPE_CHECKING: + from flet.messaging.session import Session + from flet.pubsub.pubsub_client import PubSubClient + +try: + from typing import ParamSpec +except ImportError: + from typing_extensions import ParamSpec + + +logger = logging.getLogger("flet") + + +AT = TypeVar("AT", bound=Authorization) +InputT = ParamSpec("InputT") +RetT = TypeVar("RetT") + + +@control("ServiceRegistry") +class ServiceRegistry(Service): + """ + Internal container that hosts page-level service controls. + + Services register themselves through this registry so they can be mounted + under :class:`~flet.Page` and synchronized with the frontend service + bindings. + """ + + _services: list[Service] = field(default_factory=list) + """ + Tracked service instances currently attached to this page. + """ + + def __post_init__(self, ref: Optional[Ref[Any]]): + super().__post_init__(ref) + self._internals["uid"] = random_string(10) + self._lock: threading.Lock = threading.Lock() + + def register_service(self, service: Service): + """ + Registers a service in this registry and pushes an update. + + Args: + service: Service instance to register. + """ + with self._lock: + logger.debug( + f"Registering service {service._c}({service._i}) to registry {self._i}" + ) + self._services.append(service) + self.__internal_update() + + def unregister_services(self): + """ + Unregisters services that are no longer strongly referenced. + + This keeps the registry aligned with live Python references by removing + service instances whose reference count indicates they are no longer in + active use, then updating the control tree if removals happened. + """ + with self._lock: + original_len = len(self._services) + min_refs = 3 if sys.version_info >= (3, 14) else 4 + self._services = [ + service + for service in self._services + if sys.getrefcount(service) > min_refs + ] + removed_count = original_len - len(self._services) + if removed_count > 0: + logger.debug("Removed %s services from the registry", removed_count) + self.__internal_update() + + def __internal_update(self): + """ + Push an update without marking the handler's update-called flag. + + Why: service (un)registration is internal bookkeeping, not a user-driven + `.update()`. Leaving the flag untouched keeps the auto-update behavior + based solely on whether the user called `.update()` themselves. + """ + was_called = context.was_update_called() + self.update() + if not was_called: + context.reset_update_called() + + +@dataclass +class RouteChangeEvent(Event["Page"]): + """ + Event payload for :attr:`flet.Page.on_route_change`. + """ + + route: str + """ + New route value after navigation state changed. + """ + + +@dataclass +class PlatformBrightnessChangeEvent(Event["Page"]): + """ + Event payload for platform brightness changes. + + Delivered to + :attr:`flet.Page.on_platform_brightness_change`. + """ + + brightness: Brightness + """ + Current platform brightness mode. + """ + + +@dataclass +class LocaleChangeEvent(Event["Page"]): + """ + Event payload describing a change in the host platform's locale preferences. + + See also: + - :attr:`flet.Page.on_locale_change`: event called when locale preferences/settings + of the host platform have changed. + """ + + locales: list[Locale] + """ + The full, ordered list of locales reported by the host platform. + + The first item represents the highest-priority locale. + """ + + +@dataclass +class ViewPopEvent(Event["Page"]): + """ + Event payload for view-pop navigation actions. + + Delivered to :attr:`flet.Page.on_view_pop` when the top view + is being popped by system or app-bar back behavior. + """ + + route: str + """ + Route of the view being popped. + """ + + view: Optional[View] = None + """ + Matched :class:`~flet.View` instance for `route`, if found on the page. + """ + + +@dataclass +class ViewsPopUntilEvent(Event["Page"]): + """ + Event payload delivered when :meth:`~flet.Page.pop_views_until` completes \ + navigation. + + Carries the result value back to the destination view. + """ + + route: str + """ + Route of the destination view that remained on the stack. + """ + + result: Any = None + """ + The result value passed from the caller of + :meth:`~flet.Page.pop_views_until`. + """ + + view: Optional[View] = None + """ + Matched :class:`~flet.View` instance for `route`, if found on the page. + """ + + +@dataclass +class KeyboardEvent(Event["Page"]): + """ + Event payload for keyboard key-down notifications. + + Delivered to :attr:`flet.Page.on_keyboard_event`. + """ + + key: str + """ + Human-readable key label for the pressed key. + """ + + shift: bool + """ + Whether Shift was pressed when the key event was emitted. + """ + + ctrl: bool + """ + Whether Control was pressed when the key event was emitted. + """ + + alt: bool + """ + Whether Alt was pressed when the key event was emitted. + """ + + meta: bool + """ + Whether Meta (Command/Windows) was pressed when the key event was emitted. + """ + + +@dataclass +class LoginEvent(Event["Page"]): + """ + Event payload for OAuth login completion. + + Emitted to :attr:`flet.Page.on_login` for both successful and + failed authorization attempts. + """ + + error: Optional[str] + """ + Error code or message when login failed; empty/`None` on success. + """ + + error_description: Optional[str] + """ + Provider-specific error details when login failed. + """ + + +@dataclass +class InvokeMethodResults: + """ + Result envelope for a control invoke-method response. + + Stores the correlation identifier and either a serialized result payload or + an error string. + """ + + method_id: str + """ + Identifier of the invoke-method call this response belongs to. + """ + + result: Optional[str] + """ + Serialized method result payload when the call succeeded. + """ + + error: Optional[str] + """ + Error message when the invoke-method call failed. + """ + + +@dataclass +class AppLifecycleStateChangeEvent(Event["Page"]): + """ + Event payload for app lifecycle transitions. + + Delivered to + :attr:`flet.Page.on_app_lifecycle_state_change`. + """ + + state: AppLifecycleState + """ + New application lifecycle state. + """ + + +@dataclass +class MultiViewAddEvent(Event["Page"]): + """ + Event payload emitted when a new multi-view is created. + + Delivered to :attr:`flet.Page.on_multi_view_add`. + """ + + view_id: int + """ + Unique identifier of the newly created view. + """ + + initial_data: Any + """ + Optional initial payload provided when the view was opened. + """ + + +@dataclass +class MultiViewRemoveEvent(Event["Page"]): + """ + Event payload emitted when a multi-view is removed. + + Delivered to :attr:`flet.Page.on_multi_view_remove`. + """ + + view_id: int + """ + Unique identifier of the removed view. + """ + + +@control("Page", isolated=True, post_init_args=2) +class Page(BasePage): + """ + Page is a container for :class:`~flet.View` controls. + + A page instance and the root view are automatically created when a new + user session started. + """ + + sess: InitVar["Session"] + """ + The session that this page belongs to. + """ + + multi_views: list[MultiView] = field(default_factory=list) + """ + The list of multi-views associated with this page. + """ + + window: Window = field(default_factory=lambda: Window()) + """ + Provides properties/methods/events to monitor and control the app's native OS \ + window. + """ + + route: str = "/" + """ + Gets current app route. + + Note: + This property is read-only. + """ + + web: bool = False + """ + `True` if the application is running in the web browser. + + Note: + This property is read-only. + """ + + pwa: bool = False + """ + `True` if the application is running as Progressive Web App (PWA). + + Note: + This property is read-only. + """ + debug: bool = False + """ + `True` if Flutter client of Flet app is running in debug mode. + + Note: + This property is read-only. + """ + + wasm: bool = False + """ + `True` if the application is running in WebAssembly (WASM) mode. + + Note: + This property is read-only. + """ + + test: bool = False + """ + `True` if the application is running with test mode. + + Note: + This property is read-only. + """ + + multi_view: bool = False + """ + `True` if the application is running with multi-view support. + + Note: + This property is read-only. + """ + + pyodide: bool = False + """ + `True` if the application is running in Pyodide (WebAssembly) mode. + + Note: + This property is read-only. + """ + + platform_brightness: Optional[Brightness] = None + """ + The current brightness mode of the host platform. + + Note: + This property is read-only. + """ + + client_ip: Optional[str] = None + """ + IP address of the connected user. + + Note: + This property is web- and read-only only. + """ + + client_user_agent: Optional[str] = None + """ + Browser details of the connected user. + + Note: + This property is web- and read-only only. + """ + + platform: Optional[PagePlatform] = None + """ + The operating system the application is running on. + """ + + fonts: Optional[dict[str, str]] = None + """ + Defines the custom fonts to be used in the application. + + Value is a dictionary, in which the keys represent the font family name + used for reference and the values: + - Key: The font family name used for reference. + - Value: The font source, either an absolute URL or a relative path to a + local asset. The following font file formats are supported `.ttc`, `.ttf` + and `.otf`. + + Usage example [here](https://flet.dev/docs/cookbook/fonts#importing-fonts). + """ + + on_platform_brightness_change: Optional[ + EventHandler[PlatformBrightnessChangeEvent] + ] = None + """ + Called when brightness of app host platform has changed. + """ + + on_locale_change: Optional[EventHandler[LocaleChangeEvent]] = None + """ + Called when the locale preferences/settings of the host platform have changed. + + For example, when the user updates device language + settings or browser preferred languages. + """ + + on_app_lifecycle_state_change: Optional[ + EventHandler[AppLifecycleStateChangeEvent] + ] = None + """ + Called when app lifecycle state changes. + """ + + on_route_change: Optional[EventHandler[RouteChangeEvent]] = None + """ + Called when page route changes either programmatically, by editing application URL \ + or using browser Back/Forward buttons. + """ + + on_view_pop: Optional[EventHandler[ViewPopEvent]] = None + """ + Called when the user clicks automatic "Back" button in :class:`~flet.AppBar` \ + control. + """ + + on_views_pop_until: Optional[EventHandler[ViewsPopUntilEvent]] = None + """ + Called when :meth:`pop_views_until` reaches the destination view. + + The event carries the result value passed by the caller. + """ + + on_keyboard_event: Optional[EventHandler[KeyboardEvent]] = None + """ + Called when a keyboard key is pressed. + """ + + on_connect: Optional[ControlEventHandler["Page"]] = None + """ + Called when a web user (re-)connects to a page session. + + It is not triggered when an app page is first opened, but is triggered when + the page is refreshed, or Flet web client has re-connected after computer + was unlocked. This event could be used to detect when a web user becomes + "online". + """ + + on_disconnect: Optional[ControlEventHandler["Page"]] = None + """ + Called when a web user disconnects from a page session, i.e. closes browser \ + tab/window. + """ + + on_close: Optional[ControlEventHandler["Page"]] = None + """ + Called when a session has expired after configured amount of time (60 minutes by \ + default). + """ + + on_login: Optional[EventHandler[LoginEvent]] = None + """ + Called upon successful or failed OAuth authorization flow. + + See [Authentication](https://flet.dev/docs/cookbook/authentication#checking-authentication-results) + guide for more information and examples. + """ # noqa: E501 + + on_logout: Optional[ControlEventHandler["Page"]] = None + """ + Called after `page.logout()` call. + """ + + on_error: Optional[ControlEventHandler["Page"]] = None + """ + Called when unhandled exception occurs. + """ + + on_multi_view_add: Optional[EventHandler[MultiViewAddEvent]] = None + """ + TBD + """ + + on_multi_view_remove: Optional[EventHandler[MultiViewRemoveEvent]] = None + """ + TBD + """ + _services: ServiceRegistry = field(default_factory=ServiceRegistry) + + def __post_init__( + self, + ref, + sess: "Session", + ) -> None: + BasePage.__post_init__(self, ref) + self._i = 1 + self.__session = weakref.ref(sess) + self.__last_route = None + self.__query: QueryString = QueryString(self) + self.__authorization: Optional[Authorization] = None + + def get_control(self, id: int) -> Optional[BaseControl]: + """ + Get a control by its `id`. + + Example: + ```python + def main(page: ft.Page): + x = ft.IconButton(ft.Icons.ADD) + page.add(x) + print(type(page.get_control(x._i))) + ``` + """ + return self.session.index.get(id) + + def render( + self, + component: Callable[..., Any], + *args: Any, + **kwargs: Any, + ): + """ + Render a component tree into controls of the root view. + + The rendered result replaces `page.views[0].controls`, then triggers + initial page update and component update scheduler startup. + + Args: + component: Component function to render. + *args: Positional arguments passed to `component`. + **kwargs: Keyword arguments passed to `component`. + """ + + logger.debug("Page.render()") + self._notify = self.__notify + self.views[0].controls = Renderer().render(component, *args, **kwargs) + self.__render() + + def render_views( + self, + component: Callable[..., Any], + *args: Any, + **kwargs: Any, + ): + """ + Render a component tree as the full list of page views. + + The rendered result replaces `page.views`, then triggers initial page + update and component update scheduler startup. + + Args: + component: Component function to render. + *args: Positional arguments passed to `component`. + **kwargs: Keyword arguments passed to `component`. + """ + + logger.debug("Page.render_views()") + self._notify = self.__notify + self.views = Renderer().render(component, *args, **kwargs) + self.__render() + + def __render(self): + """ + Finalize component rendering setup. + + Performs initial page update, enables components mode, and starts + batched updates scheduler for component-driven state changes. + """ + + self.update() + context.enable_components_mode() + self.session.start_updates_scheduler() + + def schedule_update(self): + """ + Queue this page for a deferred batched update. + """ + + self.session.schedule_update(self) + + def update(self, *controls: Control) -> None: + """ + Push pending state changes to the client. + + Args: + *controls: Specific controls to patch. When omitted, patches the + whole page state. + """ + context.mark_update_called() + + if len(controls) == 0: + self.__update(self) + else: + self.__update(*controls) + + def __notify(self, name: str, value: Any): + """ + Schedule page update when reactive component state changes. + + Args: + name: Changed value identifier. + value: New value. + """ + + self.schedule_update() + + def __update(self, *controls: Control): + """ + Send control patches for the provided controls. + + Args: + *controls: Controls whose updates should be sent to the client. + """ + + for c in controls: + self.session.patch_control(c) + + def error(self, message: str) -> None: + """ + Report an application error to the current session/client. + + Args: + message: Error message to send. + """ + + self.session.error(message) + + def before_event(self, e: ControlEvent): + if isinstance(e, RouteChangeEvent): + if self.__last_route == e.route: + return False + self.__last_route = e.route + self.query() + + elif isinstance(e, ViewPopEvent | ViewsPopUntilEvent): + for v in unwrap_component(self.views): + v = unwrap_component(v) + if v.route == e.route: + e.view = v + break + + return super().before_event(e) + + def run_task( + self, + handler: Callable[InputT, Awaitable[RetT]], + *args: InputT.args, + **kwargs: InputT.kwargs, + ) -> Future[RetT]: + """ + Run `handler` coroutine as a new Task in the event loop associated with the \ + current page. + """ + _context_page.set(self) + if not inspect.iscoroutinefunction(handler): + raise TypeError("handler must be a coroutine function") + + future = asyncio.run_coroutine_threadsafe( + handler(*args, **kwargs), self.session.connection.loop + ) + + def _on_completion(f): + """ + Surface background task exceptions to default error handling. + + Args: + f: Completed future returned by `run_coroutine_threadsafe()`. + """ + + try: + exception = f.exception() + if exception: + raise exception + except CancelledError: + pass + + future.add_done_callback(_on_completion) + + return future + + def __context_wrapper(self, handler: Callable[..., Any]) -> Wrapper: + """ + Wrap a callable to execute with this page bound to context vars. + + Args: + handler: Handler function to wrap. + + Returns: + Wrapped callable that restores page context before invocation. + """ + + def wrapper(*args, **kwargs): + """ + Execute wrapped handler with page context initialized. + + Args: + *args: Positional arguments forwarded to wrapped handler. + **kwargs: Keyword arguments forwarded to wrapped handler. + """ + + _context_page.set(self) + handler(*args, **kwargs) + + return wrapper + + def run_thread( + self, + handler: Callable[InputT, Any], + *args: InputT.args, + **kwargs: InputT.kwargs, + ) -> None: + """ + Run `handler` function as a new Thread in the executor associated with the \ + current page. + """ + handler_with_context = self.__context_wrapper(handler) + if is_pyodide(): + handler_with_context(*args, **kwargs) + else: + loop = self.session.connection.loop + loop.call_soon_threadsafe( + loop.run_in_executor, + self.executor, + partial(handler_with_context, *args, **kwargs), + ) + + @deprecated( + "Use push_route() instead.", + version="0.80.0", + delete_version="0.90.0", + show_parentheses=True, + ) + def go( + self, route: str, skip_route_change_event: bool = False, **kwargs: Any + ) -> None: + """ + A helper method that updates [`page.route`](#route), calls \ + [`page.on_route_change`](#on_route_change) event handler to update views and \ + finally calls `page.update()`. + """ + + asyncio.create_task(self.push_route(route, **kwargs)) + + async def push_route(self, route: str, **kwargs: Any) -> None: + """ + Pushes a new navigation route to the browser history stack. + Changing route will fire [`page.on_route_change`](#on_route_change) event + handler. + + Example: + ```python + import asyncio + + import flet as ft + + + def main(page: ft.Page): + page.title = "Routes Example" + + def route_change(): + page.views.clear() + page.views.append( + ft.View( + route="/", + controls=[ + ft.AppBar( + title=ft.Text("Flet app"), + ), + ft.Button( + "Visit Store", + on_click=lambda: asyncio.create_task( + page.push_route("/store") + ), + ), + ], + ) + ) + if page.route == "/store": + page.views.append( + ft.View( + route="/store", + controls=[ + ft.AppBar( + title=ft.Text("Store"), + ), + ft.Button( + "Go Home", + on_click=lambda: asyncio.create_task( + page.push_route("/") + ), + ), + ], + ) + ) + page.update() + + async def view_pop(e): + if e.view is not None: + print("View pop:", e.view) + page.views.remove(e.view) + top_view = page.views[-1] + await page.push_route(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + + route_change() + + + if __name__ == "__main__": + ft.run(main) + ``` + + Args: + route: New navigation route. + **kwargs: Additional query string parameters to be added to the route. + """ + + new_route = route if not kwargs else route + self.query.post(kwargs) + await self._invoke_method( + "push_route", + arguments={"route": new_route}, + ) + + def navigate(self, route: str, **kwargs: Any) -> None: + """ + Navigate to a new route (sync convenience wrapper). + + Equivalent to ``asyncio.create_task(page.push_route(route, **kwargs))``. + Use this in synchronous callbacks (e.g. ``on_click``) where awaiting + is not possible. + + Args: + route: New navigation route. + **kwargs: Additional query string parameters to be added to the route. + """ + asyncio.create_task(self.push_route(route, **kwargs)) + + async def pop_views_until(self, route: str, result: Any = None) -> None: + """ + Pops views from the navigation stack until a view with the given + `route` is found, then delivers `result` via the + :attr:`on_views_pop_until` event. + + Example: + ```python + import flet as ft + + + def main(page: ft.Page): + def on_pop_result(e: ft.ViewsPopUntilEvent): + page.show_dialog(ft.SnackBar(ft.Text(f"Result: {e.result}"))) + + page.on_views_pop_until = on_pop_result + + # ... later, from a deeply nested view: + async def go_back(ev): + await page.pop_views_until("/", result="Done!") + ``` + + Args: + route: Target route to navigate back to. Must match the `route` + of an existing :class:`~flet.View` in :attr:`~flet.Page.views`. + result: Optional value delivered to + :attr:`on_views_pop_until` on the destination view. + + Raises: + ValueError: If no view with the given `route` exists in + :attr:`~flet.Page.views`. + """ + views = unwrap_component(self.views) + + # Find the target view (first match from bottom of the stack) + target_idx = None + for i, v in enumerate(views): + v = unwrap_component(v) + if v.route == route: + target_idx = i + break + + if target_idx is None: + raise ValueError(f"No view found with route '{route}' in page.views") + + # Remove views above the target + del self.views[target_idx + 1 :] + + # Update browser URL + await self.push_route(route) + + # Fire on_views_pop_until for the destination view + if self.on_views_pop_until: + target_view = unwrap_component(views[target_idx]) + e = ViewsPopUntilEvent( + name="views_pop_until", + control=self, + route=route, + result=result, + view=target_view, + ) + await self._trigger_event("views_pop_until", event_data=None, e=e) + + self.update() + + def get_upload_url(self, file_name: str, expires: int) -> str: + """ + Generates presigned upload URL for built-in upload storage: + + * `file_name` - a relative to upload storage path. + * `expires` - a URL time-to-live in seconds. + + Example: + ```python + upload_url = page.get_upload_url("dir/filename.ext", 60) + ``` + + To enable built-in upload storage, provide the `upload_dir ` + argument to `ft.run()` call: + + ```python + ft.run(main, upload_dir="uploads") + ``` + """ + return self.session.connection.get_upload_url(file_name, expires) + + async def login( + self, + provider: OAuthProvider, + fetch_user: bool = True, + fetch_groups: bool = False, + scope: Optional[list[str]] = None, + saved_token: Optional[str] = None, + on_open_authorization_url: Optional[ + Callable[[str], Coroutine[Any, Any, None]] + ] = None, + complete_page_html: Optional[str] = None, + redirect_to_page: Optional[bool] = False, + authorization: type[AT] = AuthorizationImpl, + ) -> AT: + """ + Starts OAuth flow. + + See [Authentication](https://flet.dev/docs/cookbook/authentication) + guide for more information and examples. + """ + self.__authorization = authorization( + provider, + fetch_user=fetch_user, + fetch_groups=fetch_groups, + scope=scope, + ) + if saved_token is None: + authorization_url, state = self.__authorization.get_authorization_data() + auth_attrs = {"state": state} + if complete_page_html: + auth_attrs["completePageHtml"] = complete_page_html + if redirect_to_page: + up = urlparse(provider.redirect_url) + auth_attrs["completePageUrl"] = up._replace( + path=f"{self.session.connection.page_name}{self.route}" + ).geturl() + self.session.connection.oauth_authorize(auth_attrs) + if on_open_authorization_url: + await on_open_authorization_url(authorization_url) + else: + if self.web: + await UrlLauncher().open_window( + authorization_url, title="flet_oauth_signin" + ) + else: + await UrlLauncher().launch_url(authorization_url) + else: + await self.__authorization.dehydrate_token(saved_token) + + e = LoginEvent(name="login", control=self, error="", error_description="") + if self.on_login: + asyncio.create_task(self._trigger_event("login", event_data=None, e=e)) + + return self.__authorization + + async def _authorize_callback(self, data: dict[str, Optional[str]]) -> None: + """ + Complete OAuth flow using callback payload returned by provider. + + Validates state token, optionally closes/foregrounds app UI, exchanges + authorization code for access token, and raises `login` event with + success or failure details. + + Args: + data: OAuth callback query payload (e.g. `state`, `code`, + `error`, `error_description`). + """ + + assert self.__authorization + state = data.get("state") + assert state == self.__authorization.state + + if not self.web: + if self.platform in ["ios", "android"]: + # close web view on mobile + await self.close_in_app_web_view() + else: + # activate desktop window + await self.window.to_front() + e = LoginEvent( + error=data.get("error"), + error_description=data.get("error_description"), + control=self, + name="login", + ) + if not e.error: + # perform token request + + code = data.get("code") + assert code not in [None, ""] + try: + await self.__authorization.request_token(code) + except Exception as ex: + e.error = str(ex) + if self.on_login: + asyncio.create_task(self._trigger_event("login", event_data=None, e=e)) + + def logout(self) -> None: + """ + Clears current authentication context. See \ + [Authentication](https://flet.dev/docs/cookbook/authentication#signing-out) \ + guide for more information and examples. + """ # noqa: E501 + self.__authorization = None + e = ControlEvent(name="logout", control=self) + if self.on_logout: + asyncio.create_task(self._trigger_event("logout", event_data=None, e=e)) + + @deprecated( + "Use UrlLauncher().launch_url() instead.", + version="0.90.0", + show_parentheses=True, + ) + async def launch_url( + self, + url: Union[str, Url], + *, + web_popup_window_name: Optional[Union[str, UrlTarget]] = None, + web_popup_window: bool = False, + web_popup_window_width: Optional[int] = None, + web_popup_window_height: Optional[int] = None, + ) -> None: + """ + Opens a web browser or popup window to a given `url`. + + Args: + url: The URL to open. + web_popup_window_name: Window tab/name to open URL in. Use + :attr:`flet.UrlTarget.SELF` for the same browser tab, + :attr:`flet.UrlTarget.BLANK` for a new browser tab (or in external + application on a mobile device), or a custom name for a named tab. + web_popup_window: Display the URL in a browser popup window. + web_popup_window_width: Popup window width. + web_popup_window_height: Popup window height. + """ + if web_popup_window: + await UrlLauncher().open_window( + url, + title=web_popup_window_name, + width=web_popup_window_width, + height=web_popup_window_height, + ) + else: + await UrlLauncher().launch_url(url) + + @deprecated( + "Use UrlLauncher().can_launch_url() instead.", + version="0.90.0", + show_parentheses=True, + ) + async def can_launch_url(self, url: str) -> bool: + """ + Checks whether the specified URL can be handled by some app installed on the \ + device. + + Args: + url: The URL to check. + + Returns: + `True` if it is possible to verify that there is a handler available. + `False` if there is no handler available, or the application does not + have permission to check. For example: + + - On recent versions of Android and iOS, this will always return `False` + unless the application has been configuration to allow querying the + system for launch support. + - In web mode, this will always return `False` except for a few specific + schemes that are always assumed to be supported (such as http(s)), + as web pages are never allowed to query installed applications. + """ + return await UrlLauncher().can_launch_url(url) + + @deprecated( + "Use UrlLauncher().close_in_app_web_view() instead.", + version="0.90.0", + show_parentheses=True, + ) + async def close_in_app_web_view(self) -> None: + """ + Closes in-app web view opened with `launch_url()`. + + 📱 Mobile only. + """ + await UrlLauncher().close_in_app_web_view() + + @property + def session(self) -> "Session": + """ + The session that this page belongs to. + """ + if sess := self.__session(): + return sess + raise RuntimeError("An attempt to fetch destroyed session.") + + @property + def query(self) -> QueryString: + """ + The query parameters of the current page. + """ + return self.__query + + @property + def url(self) -> Optional[str]: + """ + The URL of the current page. + """ + return self.session.connection.page_url + + @property + def name(self) -> str: + """ + The name of the current page. + """ + return self.session.connection.page_name + + @property + def loop(self) -> asyncio.AbstractEventLoop: + """ + The event loop for the current page. + """ + return self.session.connection.loop + + @property + def executor(self) -> Optional[ThreadPoolExecutor]: + """ + The executor for the current page. + """ + return self.session.connection.executor + + @property + def auth(self) -> Optional[Authorization]: + """ + The current authorization context, or `None` if the user is not authorized. + """ + return self.__authorization + + @property + def pubsub(self) -> "PubSubClient": + """ + The PubSub client for the current page. + """ + return self.session.pubsub_client + + @property + @deprecated( + reason="Use UrlLauncher() instead.", + docs_reason="Use :class:`~flet.UrlLauncher` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def url_launcher(self) -> UrlLauncher: + """ + The UrlLauncher service for the current page. + """ + return UrlLauncher() + + @property + @deprecated( + reason="Use BrowserContextMenu() instead.", + docs_reason="Use :class:`~flet.BrowserContextMenu` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def browser_context_menu(self): + """ + The BrowserContextMenu service for the current page. + """ + + return BrowserContextMenu() + + @property + @deprecated( + reason="Use SharedPreferences() instead.", + docs_reason="Use :class:`~flet.SharedPreferences` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def shared_preferences(self): + """ + The SharedPreferences service for the current page. + """ + + return SharedPreferences() + + @property + @deprecated( + reason="Use Clipboard() instead.", + docs_reason="Use :class:`~flet.Clipboard` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def clipboard(self): + """ + The Clipboard service for the current page. + """ + + return Clipboard() + + @property + @deprecated( + reason="Use StoragePaths() instead.", + docs_reason="Use :class:`~flet.StoragePaths` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def storage_paths(self): + """ + The StoragePaths service for the current page. + """ + + return StoragePaths() + + async def get_device_info(self) -> Optional[DeviceInfo]: + """ + Returns device information. + + Returns: + The device information object for the current platform, + or `None` if unavailable. + """ + info = await self._invoke_method("get_device_info") + + if self.web: + return from_dict(WebDeviceInfo, info) + elif self.platform == PagePlatform.ANDROID: + return from_dict(AndroidDeviceInfo, info) + elif self.platform == PagePlatform.IOS: + return from_dict(IosDeviceInfo, info) + elif self.platform == PagePlatform.MACOS: + return from_dict(MacOsDeviceInfo, info) + elif self.platform == PagePlatform.LINUX: + return from_dict(LinuxDeviceInfo, info) + elif self.platform == PagePlatform.WINDOWS: + return from_dict(WindowsDeviceInfo, info) + else: + return None + + async def set_allowed_device_orientations( + self, orientations: list[DeviceOrientation] + ) -> None: + """ + Constrains the allowed orientations for the app when running on a mobile \ + device. + + Args: + orientations: A list of allowed device orientations. + Set to an empty list to use the system default behavior. + + Raises: + FletUnsupportedPlatformException: If the method is called + on a non-mobile platform. + + Limitations: + - **Android**: On Android 16 (API 36) or later, this method won't be able to + change the orientation of **devices with a display width ≥ 600 dp** + cannot change orientation. For more details see Android 16 docs + [here](https://developer.android.com/about/versions/16/behavior-changes-16#ignore-orientation). + Also, Android limits the [orientations](https://developer.android.com/reference/android/R.attr#screenOrientation) to the following combinations: + - `[]` → `unspecified` + - `[PORTRAIT_UP]` → `portrait` + - `[LANDSCAPE_LEFT]` → `landscape` + - `[PORTRAIT_DOWN]` → `reversePortrait` + - `[PORTRAIT_UP, PORTRAIT_DOWN]` → `userPortrait` + - `[LANDSCAPE_RIGHT]` → `reverseLandscape` + - `[LANDSCAPE_LEFT, LANDSCAPE_RIGHT]` → `userLandscape` + - `[PORTRAIT_UP, LANDSCAPE_LEFT, LANDSCAPE_RIGHT]` → `user` + - `[PORTRAIT_UP, PORTRAIT_DOWN, LANDSCAPE_LEFT, LANDSCAPE_RIGHT]` → + `fullUser` + + - **iOS**: This setting will only be respected on iPad if multitasking is + disabled. + You can decide to opt out of multitasking on iPad, then this will work + but your app will not support Slide Over and Split View multitasking + anymore. Should you decide to opt out of multitasking you can do this by + setting "Requires full screen" to true in the Xcode Deployment Info. + """ # noqa: E501 + if not self.platform.is_mobile(): + raise FletUnsupportedPlatformException( + "set_allowed_device_orientations is only supported on mobile platforms" + ) + await self._invoke_method( + "set_allowed_device_orientations", + arguments={"orientations": orientations}, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/painting.py b/sdk/python/packages/flet/src/flet/controls/painting.py new file mode 100644 index 0000000000..05ce657f34 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/painting.py @@ -0,0 +1,421 @@ +import math +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.base_control import value +from flet.controls.blur import BlurValue +from flet.controls.gradients import GradientTileMode +from flet.controls.transform import OffsetValue +from flet.controls.types import ( + BlendMode, + ColorValue, + Number, + StrokeCap, + StrokeJoin, +) + +__all__ = [ + "Paint", + "PaintGradient", + "PaintLinearGradient", + "PaintRadialGradient", + "PaintSweepGradient", + "PaintingStyle", +] + + +class PaintingStyle(Enum): + """ + Strategy used by :attr:`flet.Paint.style` when drawing geometry. + + Determines whether a shape is rendered as a filled interior or as an + outlined contour. + """ + + FILL = "fill" + """ + Paint the interior of the shape. + + For example, circles and polygons are rendered as solid filled regions. + """ + + STROKE = "stroke" + """ + Paint only the shape outline. + + Stroke thickness and joins/caps are controlled by properties such as + :attr:`flet.Paint.stroke_width`, :attr:`flet.Paint.stroke_join`, and + :attr:`flet.Paint.stroke_cap`. + """ + + +@value(kw_only=True) +class PaintGradient: + """ + Base class for gradients applied via :attr:`flet.Paint.gradient`. + + Use one of its concrete variants: + - :class:`~flet.PaintLinearGradient` + - :class:`~flet.PaintRadialGradient` + - :class:`~flet.PaintSweepGradient` + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + """Internal gradient kind discriminator serialized to Flutter.""" + + +@value +class PaintLinearGradient(PaintGradient): + """ + More information on Linear gradient + [here](https://api.flutter.dev/flutter/dart-ui/Gradient/Gradient.linear.html). + """ + + begin: Optional[OffsetValue] + """ + The offset at which stop `0.0` of the gradient is placed. + """ + + end: Optional[OffsetValue] + """ + The offset at which stop `1.0` of the gradient is placed. + """ + + colors: list[ColorValue] + """ + The colors the gradient should obtain at each of the stops. This list must contain \ + at least two colors. + + Note: + If :attr:`color_stops` is not `None`, + this list must have the same length as `color_stops`. + """ + + color_stops: Optional[list[Number]] = None + """ + A list of values from `0.0` to `1.0` that denote fractions along the gradient. + + Note: + If non-none, this list must have the same length as + :attr:`colors`. + If the first value is not `0.0`, then a stop with position `0.0` and a color + equal to the first color in `colors` is implied. If the last value is not + `1.0`, then a stop with position `1.0` and a color equal to the last color + in `colors` is implied. + """ + + tile_mode: GradientTileMode = GradientTileMode.CLAMP + """ + How this gradient should tile the plane beyond in the region before :attr:`begin` \ + and after :attr:`end`. + """ + + def __post_init__(self): + self._type = "linear" + + def copy( + self, + *, + begin: Optional[OffsetValue] = None, + end: Optional[OffsetValue] = None, + colors: Optional[list[str]] = None, + color_stops: Optional[list[Number]] = None, + tile_mode: Optional[GradientTileMode] = None, + ) -> "PaintLinearGradient": + """ + Returns a copy of this object with the specified properties overridden. + """ + return PaintLinearGradient( + begin=begin if begin is not None else self.begin, + end=end if end is not None else self.end, + colors=colors if colors is not None else self.colors.copy(), + color_stops=color_stops + if color_stops is not None + else (self.color_stops.copy() if self.color_stops is not None else None), + tile_mode=tile_mode if tile_mode is not None else self.tile_mode, + ) + + +@value +class PaintRadialGradient(PaintGradient): + """ + More information on Radial gradient \ + https://api.flutter.dev/flutter/dart-ui/Gradient/Gradient.radial.html + """ + + center: Optional[OffsetValue] + """ + The center of the gradient. + """ + + radius: Number + """ + The radius of the gradient. + """ + + colors: list[ColorValue] + """ + The colors the gradient should obtain at each of \ + the stops. This list must contain at least two colors. + + If `stops` is provided, this list must have the same length as `stops`. + """ + + color_stops: Optional[list[Number]] = None + """ + A list of values from `0.0` to `1.0` that denote fractions along the gradient. + + If provided, this list must have the same length as `colors`. If the first value + is not `0.0`, then a stop with position `0.0` and a color equal to the first color + in `colors` is implied. If the last value is not `1.0`, then a stop with position + `1.0` and a color equal to the last color in `colors` is implied. + """ + + tile_mode: GradientTileMode = GradientTileMode.CLAMP + """ + How this gradient should tile the plane beyond in the region before `begin` and \ + after `end`. + """ + + focal: Optional[OffsetValue] = None + """ + The focal point of the gradient. If specified, the gradient will appear to be \ + focused along the vector from `center` to focal. + """ + + focal_radius: Number = 0.0 + """ + The radius of the focal point of gradient, as a fraction of the shortest side of \ + the paint box. + + For example, if a radial gradient is painted on a box that is `100.0` pixels wide + and `200.0` pixels tall, then a radius of `1.0` will place the `1.0` stop at + `100.0` pixels from the focal point. + """ + + def __post_init__(self): + self._type = "radial" + + def copy( + self, + *, + center: Optional[OffsetValue] = None, + radius: Optional[Number] = None, + colors: Optional[list[str]] = None, + color_stops: Optional[list[Number]] = None, + tile_mode: Optional[GradientTileMode] = None, + focal: Optional[OffsetValue] = None, + focal_radius: Optional[Number] = None, + ) -> "PaintRadialGradient": + """ + Returns a copy of this object with the specified properties overridden. + """ + return PaintRadialGradient( + center=center if center is not None else self.center, + radius=radius if radius is not None else self.radius, + colors=colors if colors is not None else self.colors.copy(), + color_stops=color_stops + if color_stops is not None + else (self.color_stops.copy() if self.color_stops is not None else None), + tile_mode=tile_mode if tile_mode is not None else self.tile_mode, + focal=focal if focal is not None else self.focal, + focal_radius=focal_radius + if focal_radius is not None + else self.focal_radius, + ) + + +@value +class PaintSweepGradient(PaintGradient): + """ + More information on Sweep gradient \ + https://api.flutter.dev/flutter/dart-ui/Gradient/Gradient.sweep.html + """ + + center: Optional[OffsetValue] + """ + The center of the gradient. + """ + + colors: list[str] + """ + The colors the gradient should obtain at each of the stops. This list must contain \ + at least two colors. + + If :attr:`color_stops` is provided, this list must have the same + length as `color_stops`. + """ + + color_stops: Optional[list[Number]] = None + """ + A list of values from `0.0` to `1.0` that denote fractions along the gradient. + + If provided, this list must have the same length as `colors`. If the first value + is not `0.0`, then a stop with position `0.0` and a color equal to the first color + in `colors` is implied. If the last value is not `1.0`, then a stop with position + `1.0` and a color equal to the last color in `colors` is implied. + """ + + tile_mode: GradientTileMode = GradientTileMode.CLAMP + """ + How this gradient should tile the plane beyond in the region before `begin` and \ + after `end`. + """ + + start_angle: Number = 0.0 + """ + The angle in https://en.wikipedia.org/wiki/Radian at which stop 0.0 of the \ + gradient is placed. Defaults to 0.0. + """ + + end_angle: Number = math.pi * 2 + """ + The angle in radians at which stop 1.0 of the gradient is placed. Defaults to \ + math.pi * 2. + """ + + rotation: Optional[Number] = None + """ + The rotation of the gradient in https://en.wikipedia.org/wiki/Radian, around the \ + center-point of its bounding box. + """ + + def __post_init__(self): + self._type = "sweep" + + def copy( + self, + *, + center: Optional[OffsetValue] = None, + colors: Optional[list[str]] = None, + color_stops: Optional[list[Number]] = None, + tile_mode: Optional[GradientTileMode] = None, + start_angle: Optional[Number] = None, + end_angle: Optional[Number] = None, + rotation: Optional[Number] = None, + ) -> "PaintSweepGradient": + """ + Returns a copy of this object with the specified properties overridden. + """ + return PaintSweepGradient( + center=center if center is not None else self.center, + colors=colors if colors is not None else self.colors.copy(), + color_stops=color_stops + if color_stops is not None + else (self.color_stops.copy() if self.color_stops is not None else None), + tile_mode=tile_mode if tile_mode is not None else self.tile_mode, + start_angle=start_angle if start_angle is not None else self.start_angle, + end_angle=end_angle if end_angle is not None else self.end_angle, + rotation=rotation if rotation is not None else self.rotation, + ) + + +@value +class Paint: + """ + A description of the style to use when drawing a shape on the canvas. + """ + + color: Optional[ColorValue] = None + """ + The color to use when stroking or filling a shape. + + Defaults to opaque black. + """ + + blend_mode: Optional[BlendMode] = None + """ + A blend mode to apply when a shape is drawn or a layer is composited. + + Defaults to :attr:`flet.BlendMode.SRC_OVER`. + """ + + blur_image: Optional[BlurValue] = None + """ + Blur image when drawing it on a canvas. + """ + + anti_alias: Optional[bool] = None + """ + Whether to apply anti-aliasing to lines and images drawn on the canvas. + + Defaults to `True`. + """ + + gradient: Optional[PaintGradient] = None + """ + Configures gradient paint. + """ + + stroke_cap: Optional[StrokeCap] = None + """ + TBD + """ + + stroke_join: Optional[StrokeJoin] = None + """ + TBD + """ + + stroke_miter_limit: Optional[Number] = None + """ + TBD + """ + + stroke_width: Optional[Number] = None + """ + TBD + """ + + stroke_dash_pattern: Optional[list[Number]] = None + """ + TBD + """ + + style: Optional[PaintingStyle] = None + """ + TBD + """ + + def copy( + self, + *, + color: Optional[ColorValue] = None, + blend_mode: Optional[BlendMode] = None, + blur_image: Optional[BlurValue] = None, + anti_alias: Optional[bool] = None, + gradient: Optional[PaintGradient] = None, + stroke_cap: Optional[StrokeCap] = None, + stroke_join: Optional[StrokeJoin] = None, + stroke_miter_limit: Optional[Number] = None, + stroke_width: Optional[Number] = None, + stroke_dash_pattern: Optional[list[Number]] = None, + style: Optional[PaintingStyle] = None, + ) -> "Paint": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Paint( + color=color if color is not None else self.color, + blend_mode=blend_mode if blend_mode is not None else self.blend_mode, + blur_image=blur_image if blur_image is not None else self.blur_image, + anti_alias=anti_alias if anti_alias is not None else self.anti_alias, + gradient=gradient if gradient is not None else self.gradient, + stroke_cap=stroke_cap if stroke_cap is not None else self.stroke_cap, + stroke_join=stroke_join if stroke_join is not None else self.stroke_join, + stroke_miter_limit=stroke_miter_limit + if stroke_miter_limit is not None + else self.stroke_miter_limit, + stroke_width=stroke_width + if stroke_width is not None + else self.stroke_width, + stroke_dash_pattern=stroke_dash_pattern + if stroke_dash_pattern is not None + else ( + self.stroke_dash_pattern.copy() + if self.stroke_dash_pattern is not None + else None + ), + style=style if style is not None else self.style, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/query_string.py b/sdk/python/packages/flet/src/flet/controls/query_string.py new file mode 100644 index 0000000000..17589ab638 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/query_string.py @@ -0,0 +1,126 @@ +import re +import urllib.parse +import weakref + +__all__ = ["QueryString", "UrlComponents"] + + +class UrlComponents: + """ + `UrlComponents` are meant to be used internally for decoding-encoding, it has no \ + external use + """ + + def _encode_url_component(self, url: str) -> str: + """ + Function encodes querystring part of URL\n Ex. q=dom & dogs -> q=dom+%26+dogs + """ + return urllib.parse.quote(url) + + def _decode_url_component(self, url: str) -> str: + """ + Function decodes querystring part of URL\n Ex. q=dom+%26+dogs -> q=dom & dogs + """ + return urllib.parse.unquote(url) + + def _is_encoded(self) -> bool: + """ + Function returns True if URL is already encoded + """ + if "?" in self.url: + q_result = self._querystring_part() + return ( + self._decode_url_component( + self.url[q_result.start() + 1 : q_result.end()] + ) + != self.url[q_result.start() + 1 : q_result.end()] + ) + + def _querystring_part(self, url_string: bool = False): + """ + Function sliced url part and returns querystring part.\n Use case: checking \ + querystring part for encode, assigning decoded value + """ + pattern = re.compile(r"\?[\w\D]+") + data = pattern.search(self.url) + return data if url_string is False else self.url[data.start() + 1 : data.end()] + + +class QueryString(UrlComponents): + """ + Note: `QueryString` class is meant to be for internal use inside of page. Hence, \ + methods such as `get()` or `to_dict()` must be\n called from `page` object\n + + Constructor: + `page` takes `Page` class an argument and extracts URL automatically\n + + Methods: + Public: + `get()` method takes `key` an argument and returns value according to + key. (Ex: .../?name=Joe -> `get('name')` -> `Joe`)\n + `to_dict` returns all the key-value pairs of querystring as a `dict`\n + `path` returns url path (Ex: .../products?id=1 -> /products) + + Private(meant to be used only inside of page class): + `post()` method takes key-value pair as an argument and returns + proceeded querystring ready to be merged with URL + + """ + + def __init__(self, page): + self.__page = weakref.ref(page) + self.url = None + + def get(self, key: str) -> str: + """ + Return the query parameter value for `key` from the current URL. + + Raises: + KeyError: If `key` does not exist in the parsed query parameters. + """ + self._data = self.to_dict + return self._data[key] + + def post(self, kwargs: dict): + """ + Build an encoded querystring from key-value pairs. + + Returns: + A querystring that starts with `?` and is ready to append to a URL. + """ + return "?" + urllib.parse.urlencode(kwargs) + + @property + def to_dict(self) -> dict: + """ + Parse the current URL query component into a dictionary. + """ + self._data = urllib.parse.urlparse(self.url).query + return dict(urllib.parse.parse_qsl(self._data)) + + # Path + @property + def path(self): + """ + Return the URL path, normalizing hash-style routes when present. + """ + self._updated_url = self.url.replace("#/", "") if "#" in self.url else self.url + return urllib.parse.urlparse(self._updated_url).path + + def __call__(self): + """ + Call dunder method updates url after updating `Page` + """ + if page := self.__page(): + self.url = page.url + page.route + + # Checking if self.url is encoded and decoding it accordingly + if self._is_encoded(): + self.url = ( + page.url + + urllib.parse.urlparse(self.url).path + + "?" + + self._decode_url_component( + self._querystring_part(url_string=True) + ) + ) diff --git a/sdk/python/packages/flet/src/flet/controls/ref.py b/sdk/python/packages/flet/src/flet/controls/ref.py new file mode 100644 index 0000000000..14538f937d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/ref.py @@ -0,0 +1,29 @@ +import weakref +from typing import Generic, Optional, TypeVar + +T = TypeVar("T", covariant=True) +__all__ = ["Ref"] + + +class Ref(Generic[T]): + """Utility class which allows defining a reference to a control.""" + + def __init__(self, value: Optional[T] = None): + self.current = value + + @property + def current(self) -> Optional[T]: + """ + Referenced object, or `None` if no object is set or it was garbage-collected. + """ + return self._ref() if self._ref else None + + @current.setter + def current(self, value: Optional[T]): + """ + Set referenced object using a weak reference to avoid retaining ownership. + """ + self._ref = weakref.ref(value) if value is not None else None + + def __call__(self) -> Optional[T]: + return self.current diff --git a/sdk/python/packages/flet/src/flet/controls/scrollable_control.py b/sdk/python/packages/flet/src/flet/controls/scrollable_control.py new file mode 100644 index 0000000000..51d7bc7e6e --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/scrollable_control.py @@ -0,0 +1,416 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional, Union + +from flet.controls.animation import AnimationCurve +from flet.controls.base_control import control +from flet.controls.control import Control +from flet.controls.control_event import Event, EventHandler +from flet.controls.duration import DurationValue +from flet.controls.keys import ScrollKey +from flet.controls.types import ( + Number, + ScrollMode, +) + +__all__ = [ + "OnScrollEvent", + "ScrollDirection", + "ScrollType", + "ScrollableControl", + "Scrollbar", + "ScrollbarOrientation", +] + + +class ScrollType(Enum): + """ + The kind of scroll notification emitted by `ScrollableControl`. + """ + + START = "start" + """ + Scrolling has started. + """ + + UPDATE = "update" + """ + Scroll position changed. + + See :attr:`flet.OnScrollEvent.scroll_delta`. + """ + + END = "end" + """ + Scrolling has ended. + """ + + USER = "user" + """ + User scroll direction changed. + + See :attr:`flet.OnScrollEvent.direction`. + """ + + OVERSCROLL = "overscroll" + """ + Viewport was overscrolled. + + See :attr:`~flet.OnScrollEvent.overscroll` and + :attr:`~flet.OnScrollEvent.velocity` are available. + """ + + +class ScrollDirection(Enum): + """ + User scroll direction reported by Flutter user-scroll notifications. + + Used by :attr:`flet.OnScrollEvent.direction` when + :attr:`flet.OnScrollEvent.event_type` is :attr:`flet.ScrollType.USER`. + """ + + IDLE = "idle" + """ + No active user-driven scroll direction. + """ + + FORWARD = "forward" + """ + Scrolling in the forward axis direction. + """ + + REVERSE = "reverse" + """ + Scrolling in the reverse axis direction. + """ + + +class ScrollbarOrientation(Enum): + """ + Defines the edge/side of the viewport where the :class:`~flet.Scrollbar` is shown. + """ + + LEFT = "left" + """ + Places the scrollbar on the left/leading edge of a vertical scrollable. + """ + + RIGHT = "right" + """ + Places the scrollbar on the right/trailing edge of a vertical scrollable. + """ + + TOP = "top" + """ + Places the scrollbar above a horizontal scrollable. + """ + + BOTTOM = "bottom" + """ + Places the scrollbar below a horizontal scrollable. + """ + + +@dataclass +class Scrollbar: + """ + Configures the scrollbar that scrollable controls render for their content. + """ + + thumb_visibility: Optional[bool] = None + """ + Whether this scrollbar's thumb should be always be visible, even when not being + scrolled. When `False`, the scrollbar will be shown during scrolling and + will fade out otherwise. + + If `None`, then :attr:`flet.ScrollbarTheme.thumb_visibility` is used. + If that is also `None`, defaults to `False`. + """ + + track_visibility: Optional[bool] = None + """ + Indicates whether the scrollbar track should be visible, + so long as the :attr:`thumb_visibility` is visible. + + If `None`, then :attr:`flet.ScrollbarTheme.track_visibility` is used. + If that is also `None`, defaults to `False`. + """ + + thickness: Optional[Number] = None + """ + Controls the cross-axis size of the scrollbar in logical pixels. + The thickness of the scrollbar in the cross axis of the scrollable. + + If `None`, the default value is platform dependent: + `4.0` pixels on Android + (:attr:`flet.Page.platform` == :attr:`flet.PagePlatform.ANDROID`) and iOS + (:attr:`flet.Page.platform` == :attr:`flet.PagePlatform.IOS`); + :attr:`flet.ScrollbarTheme.thickness` on the remaining platforms. + """ + + radius: Optional[Number] = None + """ + Circular radius of the scrollbar thumb's rounded rectangle corners in logical + pixels. If `None`, platform defaults are used. + + The radius of the scrollbar thumb's rounded rectangle corners. + + If `None`, the default value is platform dependent: + no radius is applied on Android + (:attr:`flet.Page.platform` == :attr:`flet.PagePlatform.ANDROID`); + `1.5` pixels on iOS (:attr:`flet.Page.platform` == :attr:`flet.PagePlatform.IOS`); + `8.0` pixels on the remaining platforms. + """ + + interactive: Optional[bool] = None + """ + Whether this scroll bar should be interactive and respond to dragging on the + thumb, or tapping in the track area. + + When `False`, the scrollbar will not respond to gesture or hover events, and will + allow to click through it. + + If `None`, defaults to `True`, unless on Android, where it defaults to `False`. + """ + + orientation: Optional[ScrollbarOrientation] = None + """ + Specifies where the scrollbar should appear relative to the scrollable. + + If `None`, for a vertical scroll, defaults to \ + :attr:`flet.ScrollbarOrientation.RIGHT` + for left-to-right text direction and :attr:`flet.ScrollbarOrientation.LEFT` + for right-to-left text direction, while for a horizontal scroll, it defaults to + :attr:`flet.ScrollbarOrientation.BOTTOM`. + + Note: + :attr:`flet.ScrollbarOrientation.TOP` and \ + :attr:`flet.ScrollbarOrientation.BOTTOM` + can only be used with a horizontal scroll; \ + :attr:`flet.ScrollbarOrientation.LEFT` + and :attr:`flet.ScrollbarOrientation.RIGHT` can only be used with a vertical + scroll. + """ + + +@dataclass +class OnScrollEvent(Event["ScrollableControl"]): + """ + Payload for :attr:`flet.ScrollableControl.on_scroll` handlers. + """ + + event_type: ScrollType + """ + Logical type of the scroll notification. + + Determines which optional fields are populated: + + - :attr:`flet.ScrollType.UPDATE`: :attr:`scroll_delta` + - :attr:`flet.ScrollType.USER`: :attr:`direction` + - :attr:`flet.ScrollType.OVERSCROLL`: :attr:`overscroll` and :attr:`velocity` + """ + + pixels: float + """ + Current scroll offset in logical pixels. + """ + + min_scroll_extent: float + """ + Minimum in-range value for :attr:`pixels`. + + :attr:`pixels` may still be :attr:`out_of_range` during overscroll. + For unbounded scrollables this value can be negative infinity. + """ + + max_scroll_extent: float + """ + Maximum in-range value for :attr:`pixels`. + + :attr:`pixels` may still be :attr:`out_of_range` during overscroll. + For unbounded scrollables this value can be positive infinity. + """ + + viewport_dimension: float + """ + Visible viewport extent along the scroll axis, in logical pixels. + """ + + scroll_delta: Optional[float] = None + """ + Delta in logical pixels since the previous update. + + Populated for :attr:`flet.ScrollType.UPDATE` notifications. + """ + + direction: Optional[ScrollDirection] = None + """ + User scroll direction reported by Flutter. + + Populated for :attr:`flet.ScrollType.USER` notifications. + """ + + overscroll: Optional[float] = None + """ + Logical pixels that were prevented from being applied to `pixels`. + + Negative values indicate overscroll on the start side; positive values + indicate overscroll on the end side. Populated for \ + :attr:`flet.ScrollType.OVERSCROLL`. + """ + + velocity: Optional[float] = None + """ + Scroll velocity when overscroll occurred, in logical pixels per second. + + Populated for :attr:`flet.ScrollType.OVERSCROLL`. + """ + + @property + def out_of_range(self) -> bool: + """ + Whether :attr:`pixels` is outside scroll extents. + + Returns: + `True` if :attr:`pixels` < :attr:`min_scroll_extent` or + :attr:`pixels` > :attr:`max_scroll_extent`; otherwise `False`. + """ + return ( + self.pixels < self.min_scroll_extent or self.pixels > self.max_scroll_extent + ) + + @property + def at_edge(self) -> bool: + """ + Whether :attr:`pixels` is exactly at either scroll edge. + + Returns: + `True` when `pixels` equals `min_scroll_extent` or + `max_scroll_extent`; otherwise `False`. + """ + return ( + self.pixels == self.min_scroll_extent + or self.pixels == self.max_scroll_extent + ) + + @property + def extent_before(self) -> float: + """ + Quantity of content conceptually "before" the viewport. + + This corresponds to the content preceding the visible region in the + current scroll direction. + """ + return max(self.pixels - self.min_scroll_extent, 0.0) + + @property + def extent_after(self) -> float: + """ + Quantity of content conceptually "after" the viewport. + + This corresponds to the content following the visible region in the + current scroll direction. + """ + return max(self.max_scroll_extent - self.pixels, 0.0) + + @property + def extent_total(self) -> float: + """ + Total conceptual content extent available to the scrollable. + + Equivalent to: :attr:`max_scroll_extent` - :attr:`min_scroll_extent` + + :attr:`viewport_dimension`. + """ + return self.max_scroll_extent - self.min_scroll_extent + self.viewport_dimension + + +@control(kw_only=True) +class ScrollableControl(Control): + """ + Shared scroll behavior for controls that expose a scrollable viewport. + + This mixin-style control is inherited by controls such as + :class:`~flet.Column`, :class:`~flet.Row`, :class:`~flet.ResponsiveRow`, + :class:`~flet.View`, :class:`~flet.ListView`, and :class:`~flet.GridView`. + It provides a common API for: + + - enabling/disabling scrolling and scrollbar visibility via :attr:`scroll`; + - receiving throttled scroll notifications via :attr:`on_scroll` and + :attr:`scroll_interval`; + - imperatively changing position with :meth:`scroll_to`. + """ + + scroll: Optional[Union[ScrollMode, Scrollbar]] = None + """ + Defines the scroll bar configuration of this control. + + Can be a :class:`~flet.Scrollbar` instance for full control over the appearance of \ + the + scrollbar, or a :class:`~flet.ScrollMode` value, for ready-made scrollbar behaviors. + """ + + auto_scroll: bool = False + """ + Whether the scrollbar should automatically move its position to the end when \ + children updated. + + Note: + Must be `False` for :meth:`scroll_to` method to work. + """ + + scroll_interval: Number = 10 + """ + Throttling in milliseconds for :attr:`on_scroll` event. + """ + + on_scroll: Optional[EventHandler[OnScrollEvent]] = None + """ + Called when scroll position is changed by a user. + """ + + async def scroll_to( + self, + offset: Optional[float] = None, + delta: Optional[float] = None, + scroll_key: Union[ScrollKey, str, int, float, bool, None] = None, + duration: DurationValue = 0, + curve: AnimationCurve = AnimationCurve.EASE, + ): + """ + Moves the scroll position. + + Args: + offset: Absolute scroll target in pixels. A negative value is interpreted + relative to the end (e.g. `-1` to jump to the very end). + delta: Relative scroll change in pixels. Positive values scroll forward, + negative values scroll backward. + scroll_key: Key of the target control to scroll to. + duration: The scroll animation duration. + curve: The scroll animation curve. + + Notes: + - Exactly one of `offset`, `delta` or `scroll_key` should be provided. + - :attr:`auto_scroll` must be `False`. + - This method is ineffective for controls (e.g. + :class:`~flet.ListView`, :class:`~flet.GridView`) that build items \ + dynamically. + + Examples: + ```python + await products.scroll_to(offset=100, duration=1000) + await products.scroll_to(offset=-1, duration=1000) # to the end + await products.scroll_to(delta=50) # forward 50px + await products.scroll_to(scroll_key="item_20", duration=500) + ``` + """ + + await self._invoke_method( + "scroll_to", + { + "offset": offset, + "delta": delta, + "scroll_key": scroll_key, + "duration": duration, + "curve": curve, + }, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/__init__.py b/sdk/python/packages/flet/src/flet/controls/services/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/controls/services/accelerometer.py b/sdk/python/packages/flet/src/flet/controls/services/accelerometer.py new file mode 100644 index 0000000000..7ab0ecbe40 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/accelerometer.py @@ -0,0 +1,98 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.duration import Duration +from flet.controls.services.sensor_error_event import SensorErrorEvent +from flet.controls.services.service import Service +from flet.utils.platform_utils import FletUnsupportedPlatformException + +__all__ = ["Accelerometer", "AccelerometerReadingEvent"] + + +@dataclass(kw_only=True) +class AccelerometerReadingEvent(Event["Accelerometer"]): + """ + Discrete reading from an accelerometer. Accelerometers measure the velocity of the \ + device. Note that these readings include the effects of gravity. + Put simply, you can use accelerometer readings to tell if the device + is moving in a particular direction. + """ + + x: float + """Acceleration along the X axis, in `m/s^2`.""" + + y: float + """Acceleration along the Y axis, in `m/s^2`.""" + + z: float + """Acceleration along the Z axis, in `m/s^2`.""" + + timestamp: datetime + """Event timestamp.""" + + +@control("Accelerometer") +class Accelerometer(Service): + """ + Streams raw accelerometer :class:`flet.AccelerometerReadingEvent`, which describe \ + the acceleration of the device, in `m/s^2`, including the effects of gravity. + + Unlike :class:`~flet.UserAccelerometer`, + this service reports raw data from the accelerometer (physical sensor + embedded in the mobile device) without any post-processing. + + The accelerometer is unable to distinguish between the effect of an + accelerated movement of the device and the effect of the surrounding + gravitational field. This means that, at the surface of Earth, + even if the device is completely still, the reading of :class:`~flet.Accelerometer` + is an acceleration of intensity 9.8 directed upwards (the opposite of + the graviational acceleration). This can be used to infer information + about the position of the device (horizontal/vertical/tilted). + Accelerometer reports zero acceleration if the device is free falling. + + Note: + * Supported platforms: Android, iOS and web. + * Web ignores requested sampling intervals. + """ + + enabled: bool = True + """ + Whether the sensor should be sampled. Disable to stop streaming. + """ + + interval: Optional[Duration] = None + """ + Desired sampling interval provided as a :class:`~flet.Duration`. + Defaults to 200 ms. + + Note that mobile platforms treat this value as a suggestion and the actual + rate can differ depending on hardware and OS limitations. + """ + + cancel_on_error: bool = True + """ + Whether the stream subscription should cancel on the first sensor error. + """ + + on_reading: Optional[EventHandler[AccelerometerReadingEvent]] = None + """ + Fires when a new reading is available. + + `event` exposes `x`, `y`, `z` acceleration values and `timestamp` + (microseconds since epoch). + """ + + on_error: Optional[EventHandler[SensorErrorEvent]] = None + """ + Fired when the platform reports a sensor error (for example when the device does \ + not expose the accelerometer). `event.message` contains the error text. + """ + + def before_update(self): + if not (self.page.web or self.page.platform.is_mobile()): + raise FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on Android, iOS and web." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/barometer.py b/sdk/python/packages/flet/src/flet/controls/services/barometer.py new file mode 100644 index 0000000000..3ba5d9ae94 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/barometer.py @@ -0,0 +1,102 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.duration import Duration +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.sensor_error_event import SensorErrorEvent +from flet.controls.services.service import Service + +__all__ = ["Barometer", "BarometerReadingEvent"] + + +@dataclass(kw_only=True) +class BarometerReadingEvent(Event["Barometer"]): + """ + A sensor sample from a barometer. + + Barometers measure the atmospheric pressure surrounding the sensor, + returning values in hectopascals `hPa`. + + Consider that these samples may be affected by altitude and weather conditions, + and can be used to predict short-term weather changes or determine altitude. + + Note that water-resistant phones or similar sealed devices may experience + pressure fluctuations as the device is held or used, due to changes + in pressure caused by handling the device. + + An altimeter is an example of a general utility for barometer data. + """ + + pressure: float + """Atmospheric pressure reading, in hectopascals (`hPa`).""" + + timestamp: datetime + """Event timestamp.""" + + +@control("Barometer") +class Barometer(Service): + """ + Streams barometer :class:`~flet.BarometerReadingEvent` samples (atmospheric \ + pressure in `hPa`). Useful for altitude calculations and weather-related \ + experiences. + + Note: + * Supported platforms: Android, iOS. + * Barometer APIs are not exposed on the web or desktop platforms. + * iOS ignores custom sampling intervals. + + On iOS you must also include a key called `NSMotionUsageDescription` + in your app's `Info.plist` file. This key provides a message that tells + the user why the app is requesting access to the device's motion data. + Barometer service needs access to motion data to get barometer data. + + For example, add the following to your `pyproject.toml` file: + ```toml + [tool.flet.ios.info] + NSMotionUsageDescription = "This app requires access to the barometer to provide altitude information." + ``` + + **Adding `NSMotionUsageDescription` is a requirement and not doing so will + crash your app when it attempts to access motion data.** + """ # noqa: E501 + + enabled: bool = True + """ + Whether the sensor should be sampled. Disable to stop streaming. + """ + + interval: Optional[Duration] = None + """ + Desired sampling interval provided as a :class:`~flet.Duration`. Defaults to + 200 ms, though + some platforms (such as iOS) ignore custom sampling intervals. + """ + + cancel_on_error: bool = True + """ + Whether the stream subscription should cancel on the first sensor error. + """ + + on_reading: Optional[EventHandler[BarometerReadingEvent]] = None + """ + Fires when a new reading is available. + + `event` contains `pressure` (hPa) and `timestamp` (microseconds + since epoch). + """ + + on_error: Optional[EventHandler[SensorErrorEvent]] = None + """ + Fired when the platform reports a sensor error. `event.message` is the error \ + description. + """ + + def before_update(self): + if self.page.web or not self.page.platform.is_mobile(): + raise FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on Android and iOS." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/battery.py b/sdk/python/packages/flet/src/flet/controls/services/battery.py new file mode 100644 index 0000000000..dc4e5b564b --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/battery.py @@ -0,0 +1,85 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.services.service import Service + +__all__ = ["Battery", "BatteryState", "BatteryStateChangeEvent"] + + +class BatteryState(Enum): + """ + Battery state. + """ + + CHARGING = "charging" + """ + The battery is currently charging. + """ + CONNECTED_NOT_CHARGING = "connectedNotCharging" + """ + The battery is connected to a power source but not charging. + """ + DISCHARGING = "discharging" + """ + The battery is discharging. + """ + FULL = "full" + """ + The battery is fully charged. + """ + UNKNOWN = "unknown" + """ + The battery state is unknown. + """ + + +@dataclass +class BatteryStateChangeEvent(Event["Battery"]): + """ + Event fired when battery state changes. + """ + + state: BatteryState + """ + Current battery state. + """ + + +@control("Battery") +class Battery(Service): + """ + Provides access to device battery information and state changes. + """ + + on_state_change: Optional[EventHandler[BatteryStateChangeEvent]] = None + """ + Called when battery state changes (charging, discharging, full, unknown). + """ + + async def get_battery_level(self) -> Optional[int]: + """ + Gets the current battery level as a percentage, in the range `0` to `100`. + + Returns: + The battery level, or `None` when it is unavailable on the current + environment. + """ + + return await self._invoke_method("get_battery_level") + + async def get_battery_state(self) -> BatteryState: + """ + Returns current battery state. + """ + + return BatteryState(await self._invoke_method("get_battery_state")) + + async def is_in_battery_save_mode(self) -> bool: + """ + Returns `True` if the device is currently in battery save mode. + """ + + return await self._invoke_method("is_in_battery_save_mode") diff --git a/sdk/python/packages/flet/src/flet/controls/services/browser_context_menu.py b/sdk/python/packages/flet/src/flet/controls/services/browser_context_menu.py new file mode 100644 index 0000000000..bfd2478e22 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/browser_context_menu.py @@ -0,0 +1,58 @@ +from flet.controls.base_control import control +from flet.controls.services.service import Service + +__all__ = ["BrowserContextMenu"] + + +@control("BrowserContextMenu") +class BrowserContextMenu(Service): + """ + Controls the browser's context menu on the web platform. + + The context menu is the menu that appears on right clicking or selecting + text in the browser, for example. + + On web, by default, the browser's context menu is enabled and + Flet's context menus are hidden. + + On all non-web platforms, this does nothing. + """ + + def __post_init__(self, ref): + super().__post_init__(ref) + self.__disabled = False + + async def enable(self): + """ + Enable the browser's context menu. + + By default, when the app starts, the browser's context menu is already enabled. + """ + await self._invoke_method("enable_menu") + self.__disabled = False + + async def disable(self): + """ + Disable the browser's context menu. + + By default, when the app starts, the browser's context menu is + already enabled. + """ + await self._invoke_method("disable_menu") + self.__disabled = True + + @property + def disabled(self): + """ + Whether browser context menu disabling is currently requested. + + This flag is managed by this service instance: + - initialized to `False`; + - set to `True` after :meth:`disable`; + - set to `False` after :meth:`enable`. + + Note: + On non-web platforms, browser context menu control is not applicable, + but this property still reflects the last requested state. + """ + return self.__disabled diff --git a/sdk/python/packages/flet/src/flet/controls/services/clipboard.py b/sdk/python/packages/flet/src/flet/controls/services/clipboard.py new file mode 100644 index 0000000000..0a235e6097 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/clipboard.py @@ -0,0 +1,102 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.service import Service +from flet.controls.types import PagePlatform + +__all__ = ["Clipboard"] + + +@control("Clipboard") +class Clipboard(Service): + """ + Provides access to the system clipboard. + """ + + async def set(self, value: str) -> None: + """ + Stores the given data on the clipboard. + + Args: + value: The string data to be stored on the clipboard. + """ + await self._invoke_method("set", {"data": value}) + + async def get(self) -> Optional[str]: + """ + Retrieves data from the clipboard. + + Returns: + The string data retrieved from the clipboard, or `None` + if the clipboard is empty or does not contain string data. + """ + return await self._invoke_method("get") + + async def set_image(self, value: bytes) -> None: + """ + Stores image bytes on the clipboard. + + Args: + value: The image data (in bytes) to be stored on the clipboard. + + Raises: + FletUnsupportedPlatformException: If called on platforms other than the + following: Android, iOS, Web. + """ + if not (self.page.web or self.page.platform.is_mobile()): + raise FletUnsupportedPlatformException( + "set_image is not supported on this platform" + ) + await self._invoke_method("set_image", {"data": value}) + + async def get_image(self) -> Optional[bytes]: + """ + Retrieves image data from the clipboard. + + Returns: + The image data retrieved from the clipboard as bytes, or `None` + if the clipboard is empty or does not contain image data. + """ + return await self._invoke_method("get_image") + + async def set_files(self, files: list[str]) -> bool: + """ + Stores file references on the clipboard. + + Args: + files: A list of file paths. + + Returns: + `True` if the operation succeeded, otherwise `False`. + + Raises: + FletUnsupportedPlatformException: If called on platforms other than the + following: macOS, Windows, Linux. + """ + if self.page.web or not self.page.platform.is_desktop(): + raise FletUnsupportedPlatformException( + "set_files is supported on desktop platforms only" + ) + return await self._invoke_method("set_files", {"files": files}) + + async def get_files(self) -> list[str]: + """ + Retrieves file references from the clipboard. + + Returns: + A list of file references available in the clipboard. + On Android these are typically content URIs. + + Raises: + FletUnsupportedPlatformException: If called on platforms other than the + following: Android, macOS, Windows, Linux. + """ + if self.page.web or ( + not self.page.platform.is_desktop() + and self.page.platform != PagePlatform.ANDROID + ): + raise FletUnsupportedPlatformException( + "get_files is supported on desktop and Android platforms only" + ) + return await self._invoke_method("get_files") diff --git a/sdk/python/packages/flet/src/flet/controls/services/connectivity.py b/sdk/python/packages/flet/src/flet/controls/services/connectivity.py new file mode 100644 index 0000000000..8da43804e1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/connectivity.py @@ -0,0 +1,74 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.services.service import Service + +__all__ = ["Connectivity", "ConnectivityChangeEvent", "ConnectivityType"] + + +class ConnectivityType(Enum): + """ + Connectivity states. + """ + + BLUETOOTH = "bluetooth" + """ + Bluetooth connectivity. + """ + ETHERNET = "ethernet" + """ + Ethernet connectivity. + """ + MOBILE = "mobile" + """ + Mobile data connectivity. + """ + NONE = "none" + """ + No connectivity. + """ + OTHER = "other" + """ + Other connectivity. + """ + VPN = "vpn" + """ + VPN connectivity. + """ + WIFI = "wifi" + """ + Wi-Fi connectivity. + """ + + +@dataclass +class ConnectivityChangeEvent(Event["Connectivity"]): + """Event fired when connectivity changes.""" + + connectivity: list[ConnectivityType] + """ + Current connectivity type(s). + """ + + +@control("Connectivity") +class Connectivity(Service): + """ + Provides device connectivity status and change notifications. + """ + + on_change: Optional[EventHandler[ConnectivityChangeEvent]] = None + """ + Called when connectivity changes. + """ + + async def get_connectivity(self) -> list[ConnectivityType]: + """ + Returns the current connectivity type(s). + """ + + result = await self._invoke_method("get_connectivity") + return [ConnectivityType(r) for r in result] diff --git a/sdk/python/packages/flet/src/flet/controls/services/file_picker.py b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py new file mode 100644 index 0000000000..ba2e954603 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/file_picker.py @@ -0,0 +1,350 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Any, Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.service import Service + +__all__ = [ + "FilePicker", + "FilePickerFile", + "FilePickerFileType", + "FilePickerUploadEvent", + "FilePickerUploadFile", +] + + +class FilePickerFileType(Enum): + """ + Defines the file types that can be selected using the :class:`~flet.FilePicker`. + """ + + ANY = "any" + """ + Allows any file type. + """ + + MEDIA = "media" + """ + A combination of :attr:`VIDEO` and :attr:`IMAGE`. + """ + + IMAGE = "image" + """ + Allows only image files. + """ + + VIDEO = "video" + """ + Allows only video files. + """ + + AUDIO = "audio" + """ + Allows only audio files. + """ + + CUSTOM = "custom" + """ + Allows only the custom file types specified in the `allowed_extensions` list. + """ + + +@dataclass +class FilePickerUploadFile: + """ + Upload descriptor for one file selected by :class:`~flet.FilePicker`. + + Instances are passed to :meth:`flet.FilePicker.upload`. + During upload, Flet resolves the selected file by :attr:`id` first and, + when `id` is absent or not found, falls back to :attr:`name`. + + At least one of :attr:`id` or :attr:`name` should be provided. + """ + + upload_url: str + """ + Upload destination URL. + + Can be an absolute URL or a page-relative URL returned by + :meth:`flet.Page.get_upload_url`. + """ + + method: str = "PUT" + """ + HTTP method used for the upload request, usually `PUT` or `POST`. + """ + + id: Optional[int] = None + """ + Selected file identifier returned by + :meth:`flet.FilePicker.pick_files`. + + This is the preferred lookup key when both `id` and `name` are specified. + """ + + name: Optional[str] = None + """ + Selected file name used as fallback lookup when :attr:`id` is missing + or does not match any currently selected file. + """ + + +@dataclass +class FilePickerFile: + """ + Metadata for a file selected via + :meth:`flet.FilePicker.pick_files`. + + Returned by :meth:`flet.FilePicker.pick_files` and + used as input context for :class:`~flet.FilePickerUploadFile` + when uploading selected files. + """ + + id: int + """ + Selection-scoped file identifier assigned by Flet. + + This value is stable for the current picker selection and is preferred for + upload matching in :class:`~flet.FilePickerUploadFile`. + """ + + name: str + """ + File name (basename), without directory path. + """ + + size: int + """ + File size in bytes. + """ + + path: Optional[str] = None + """ + Absolute path to the selected file, when available. + + Note: + - Web mode always returns `None`. + - On native platforms, this can still be `None` if the platform picker + does not expose a filesystem path. + """ + + bytes: Optional[bytes] = None + """ + File contents. + + Returned only when :meth:`~flet.FilePicker.pick_files` is called with + `with_data=True`. Otherwise this value is `None`. + """ + + +@dataclass +class FilePickerUploadEvent(Event["FilePicker"]): + """ + Event emitted when a file is uploaded via \ + :meth:`flet.FilePicker.upload` method. + """ + + file_name: str + """ + The name of the uploaded file. + """ + + progress: Optional[float] = None + """ + A value from `0.0` to `1.0` representing the progress of the upload. + """ + + error: Optional[str] = None + """ + An error message if the upload failed. + """ + + +@control("FilePicker") +class FilePicker(Service): + """ + A control that allows you to use the native file explorer to pick single or \ + multiple files, with extensions filtering support and upload. + + Danger: Important + On Linux, this control requires + [Zenity](https://help.gnome.org/users/zenity/stable/) when running Flet + as a desktop app. It is not required when running Flet in a browser. + + To install Zenity on Ubuntu/Debian run the following commands: + ```bash + sudo apt-get install zenity + ``` + """ + + on_upload: Optional[EventHandler[FilePickerUploadEvent]] = None + """ + Called when a file is uploaded via :meth:`upload` method. + + This callback is invoked at least twice for each uploaded file: once with `0.0` + :attr:`~flet.FilePickerUploadEvent.progress` before the upload starts, and once with + `1.0` :attr:`~flet.FilePickerUploadEvent.progress` when the upload completes. + + For files larger than 1 MB, additional progress events are emitted + at every 10% increment (for example, `0.1`, `0.2`, ...). + """ + + async def upload(self, files: list[FilePickerUploadFile]): + """ + Uploads picked files to specified upload URLs. + + Before calling this method, :meth:`pick_files` first has to be + called to ensure the internal file picker selection is not empty. + + Once called, Flet asynchronously starts uploading selected files + one-by-one and reports the progress via :attr:`on_upload` event. + + Args: + files: A list of :class:`~flet.FilePickerUploadFile`, where + each item specifies which file to upload, and where + (with `PUT` or `POST`). + """ + await self._invoke_method( + "upload", + {"files": files}, + ) + + async def get_directory_path( + self, + dialog_title: Optional[str] = None, + initial_directory: Optional[str] = None, + ) -> Optional[str]: + """ + Selects a directory and returns its absolute path. + + Args: + dialog_title: The title of the dialog window. Defaults to [`FilePicker`]. + initial_directory: The initial directory where the dialog should open. + + Returns: + The selected directory path or `None` if the dialog was cancelled. + + Raises: + FletUnsupportedPlatformException: If called in web mode. + """ + if self.page.web: + raise FletUnsupportedPlatformException( + "get_directory_path is not supported in web mode" + ) + + return await self._invoke_method( + "get_directory_path", + { + "dialog_title": dialog_title, + "initial_directory": initial_directory, + }, + timeout=3600, + ) + + async def save_file( + self, + dialog_title: Optional[str] = None, + file_name: Optional[str] = None, + initial_directory: Optional[str] = None, + file_type: FilePickerFileType = FilePickerFileType.ANY, + allowed_extensions: Optional[list[str]] = None, + src_bytes: Optional[bytes] = None, + ) -> Optional[str]: + """ + Opens a save file dialog which lets the user select a file path and a file \ + name to save a file. + + Note: + - On desktop this method only opens a dialog for the user to select + a location and file name, and returns the chosen path. The file + itself is not created or saved. + + Args: + dialog_title: The title of the dialog window. + file_name: The default file name. + initial_directory: The initial directory where the dialog should open. + file_type: The file types allowed to be selected. + src_bytes: The contents of a file. Must be provided in web, + iOS or Android modes. + allowed_extensions: The allowed file extensions. Has effect only if + `file_type` is + :attr:`flet.FilePickerFileType.CUSTOM`. + + Raises: + ValueError: If `src_bytes` is not provided, when called in web mode, + on iOS or Android. + ValueError: If `file_name` is not provided in web mode. + """ + + if (self.page.web or self.page.platform.is_mobile()) and not src_bytes: + raise ValueError( + '"src_bytes" is required when saving a file in web mode,' + "or on mobile (Android & iOS)." + ) + if self.page.web and not file_name: + raise ValueError('"file_name" is required when saving a file in web mode.') + + return await self._invoke_method( + "save_file", + { + "dialog_title": dialog_title, + "file_name": file_name, + "initial_directory": initial_directory, + "file_type": file_type, + "allowed_extensions": allowed_extensions, + "src_bytes": src_bytes, + }, + timeout=3600, + ) + + async def pick_files( + self, + dialog_title: Optional[str] = None, + initial_directory: Optional[str] = None, + file_type: FilePickerFileType = FilePickerFileType.ANY, + allowed_extensions: Optional[list[str]] = None, + allow_multiple: bool = False, + with_data: bool = False, + ) -> list[FilePickerFile]: + """ + Opens a pick file dialog. + + Tip: + To upload the picked files, pass them to :meth:`upload` method, + along with their upload URLs. + + Args: + dialog_title: The title of the dialog window. + initial_directory: The initial directory where the dialog should open. + file_type: The file types allowed to be selected. + allow_multiple: Allow the selection of multiple files at once. + with_data: Read selected file contents into + :attr:`~flet.FilePickerFile.bytes`. + allowed_extensions: The allowed file extensions. Has effect only if + `file_type` is :attr:`flet.FilePickerFileType.CUSTOM`. + + Returns: + A list of selected files. + """ + files = await self._invoke_method( + "pick_files", + { + "dialog_title": dialog_title, + "initial_directory": initial_directory, + "file_type": file_type, + "allowed_extensions": allowed_extensions, + "allow_multiple": allow_multiple, + "with_data": with_data, + }, + timeout=3600, + ) + return [FilePickerFile(**self._normalize_file(file)) for file in files] + + def _normalize_file(self, file: dict[str, Any]) -> dict[str, Any]: + value = file.get("bytes") + if isinstance(value, list): + file["bytes"] = bytes(value) + return file diff --git a/sdk/python/packages/flet/src/flet/controls/services/gyroscope.py b/sdk/python/packages/flet/src/flet/controls/services/gyroscope.py new file mode 100644 index 0000000000..978bd73285 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/gyroscope.py @@ -0,0 +1,82 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.duration import Duration +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.sensor_error_event import SensorErrorEvent +from flet.controls.services.service import Service + +__all__ = ["Gyroscope", "GyroscopeReadingEvent"] + + +@dataclass(kw_only=True) +class GyroscopeReadingEvent(Event["Gyroscope"]): + """ + Discrete reading from a gyroscope. + + Gyroscope sample containing device rotation rate (`rad/s`) around each + axis plus the microsecond timestamp. + """ + + x: float + """Rotation rate around the X axis, in `rad/s`.""" + + y: float + """Rotation rate around the Y axis, in `rad/s`.""" + + z: float + """Rotation rate around the Z axis, in `rad/s`.""" + + timestamp: datetime + """Event timestamp.""" + + +@control("Gyroscope") +class Gyroscope(Service): + """ + Streams gyroscope :class:`flet.GyroscopeReadingEvent`, reporting device rotation \ + rate around each axis in `rad/s`. + + Note: + * Supported platforms: Android, iOS and web. + * Web ignores requested sampling intervals. + """ + + enabled: bool = True + """ + Whether the sensor should be sampled. Disable to stop streaming. + """ + + interval: Optional[Duration] = None + """ + Desired sampling interval provided as a :class:`~flet.Duration`. + Defaults to 200 ms. + """ + + cancel_on_error: bool = True + """ + Whether the stream subscription should cancel on the first sensor error. + """ + + on_reading: Optional[EventHandler[GyroscopeReadingEvent]] = None + """ + Fires when a new reading is available. + + `event` contains `x`, `y`, `z` rotation rates and `timestamp` + (microseconds since epoch). + """ + + on_error: Optional[EventHandler[SensorErrorEvent]] = None + """ + Fired when the platform reports a sensor error. `event.message` is the error \ + description. + """ + + def before_update(self): + if not (self.page.web or self.page.platform.is_mobile()): + raise FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on Android, iOS and web." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py b/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py new file mode 100644 index 0000000000..e3e7ebcd46 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/haptic_feedback.py @@ -0,0 +1,42 @@ +from flet.controls.base_control import control +from flet.controls.services.service import Service + +__all__ = ["HapticFeedback"] + + +@control("HapticFeedback") +class HapticFeedback(Service): + """ + Allows access to the haptic feedback interface on the device. + """ + + async def heavy_impact(self): + """ + Provides a haptic feedback corresponding a collision impact with a heavy mass. + """ + await self._invoke_method("heavy_impact") + + async def light_impact(self): + """ + Provides a haptic feedback corresponding a collision impact with a light mass. + """ + await self._invoke_method("light_impact") + + async def medium_impact(self): + """ + Provides a haptic feedback corresponding a collision impact with a medium \ + mass. + """ + await self._invoke_method("medium_impact") + + async def vibrate(self): + """ + Provides vibration haptic feedback to the user for a short duration. + """ + await self._invoke_method("vibrate") + + async def selection_click(self): + """ + TBD + """ + await self._invoke_method("selection_click") diff --git a/sdk/python/packages/flet/src/flet/controls/services/magnetometer.py b/sdk/python/packages/flet/src/flet/controls/services/magnetometer.py new file mode 100644 index 0000000000..389f0eb588 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/magnetometer.py @@ -0,0 +1,89 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.duration import Duration +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.sensor_error_event import SensorErrorEvent +from flet.controls.services.service import Service + +__all__ = ["Magnetometer", "MagnetometerReadingEvent"] + + +@dataclass(kw_only=True) +class MagnetometerReadingEvent(Event["Magnetometer"]): + """ + A sensor sample from a magnetometer. + + Magnetometers measure the ambient magnetic field surrounding the sensor, + returning values in microteslas `μT` for each three-dimensional axis. + + Consider that these samples may bear effects of Earth's magnetic field + as well as local factors such as the metal of the device itself + or nearby magnets, though most devices compensate for these factors. + + A compass is an example of a general utility for magnetometer data. + """ + + x: float + """Ambient magnetic field on the X axis, in microteslas (`uT`).""" + + y: float + """Ambient magnetic field on the Y axis, in `uT`.""" + + z: float + """Ambient magnetic field on the Z axis, in `uT`.""" + + timestamp: datetime + """Event timestamp.""" + + +@control("Magnetometer") +class Magnetometer(Service): + """ + Streams magnetometer :class:`flet.MagnetometerReadingEvent` reporting the ambient \ + magnetic field (`uT`) per axis for compass-style use cases. + + Note: + * Supported platforms: Android, iOS. + * Magnetometer APIs are not available on web. + or desktop, so always handle `on_error` to detect unsupported hardware. + """ + + enabled: bool = True + """ + Whether the sensor should be sampled. Disable to stop streaming. + """ + + interval: Optional[Duration] = None + """ + Desired sampling interval provided as a :class:`~flet.Duration`. + Defaults to 200 ms. + """ + + cancel_on_error: bool = True + """ + Whether the stream subscription should cancel on the first sensor error. + """ + + on_reading: Optional[EventHandler[MagnetometerReadingEvent]] = None + """ + Fires when a new reading is available. + + `event` contains `x`, `y`, `z` magnetic field strengths (uT) + and `timestamp` (microseconds since epoch). + """ + + on_error: Optional[EventHandler[SensorErrorEvent]] = None + """ + Fired when the platform reports a sensor error. `event.message` is the error \ + description. + """ + + def before_update(self): + if self.page.web or not self.page.platform.is_mobile(): + raise FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on Android and iOS." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/screen_brightness.py b/sdk/python/packages/flet/src/flet/controls/services/screen_brightness.py new file mode 100644 index 0000000000..9fc819e9ac --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/screen_brightness.py @@ -0,0 +1,131 @@ +from dataclasses import dataclass +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.service import Service +from flet.controls.types import Number + +__all__ = ["ScreenBrightness", "ScreenBrightnessChangeEvent"] + + +@dataclass +class ScreenBrightnessChangeEvent(Event["ScreenBrightness"]): + """ + Event fired when screen brightness changes. + """ + + brightness: float + """ + The new screen brightness, in range `0.0..1.0`. + """ + + +@control("ScreenBrightness") +class ScreenBrightness(Service): + """ + Provides access to control and observe system and application screen brightness. + + Note: + * Supported platforms: Android, iOS. + + To adjust the system brightness on Android, add the following permission + in your `pyproject.toml` file: + ```toml + [tool.flet.android.permission] + "android.permission.WRITE_SETTINGS" = true + ``` + """ + + on_system_screen_brightness_change: Optional[ + EventHandler[ScreenBrightnessChangeEvent] + ] = None + """ + Called when the **system** screen brightness changes. + """ + + on_application_screen_brightness_change: Optional[ + EventHandler[ScreenBrightnessChangeEvent] + ] = None + """ + Called when the **application** screen brightness changes. + """ + + async def get_system_screen_brightness(self) -> float: + """ + Returns the current system screen brightness, in range `0.0..1.0`. + """ + + return await self._invoke_method("get_system_screen_brightness") + + async def can_change_system_screen_brightness(self) -> bool: + """ + Returns whether the app is allowed to change the system screen brightness. + """ + + return await self._invoke_method("can_change_system_screen_brightness") + + async def set_system_screen_brightness(self, brightness: Number): + """ + Sets the system screen brightness. + """ + + await self._invoke_method("set_system_screen_brightness", {"value": brightness}) + + async def get_application_screen_brightness(self) -> float: + """ + Returns the current application screen brightness, in range `0.0..1.0`. + """ + + return await self._invoke_method("get_application_screen_brightness") + + async def set_application_screen_brightness(self, brightness: Number): + """ + Sets the application screen brightness. + """ + + await self._invoke_method( + "set_application_screen_brightness", {"value": brightness} + ) + + async def reset_application_screen_brightness(self): + """ + Resets the application screen brightness back to the system value. + """ + + await self._invoke_method("reset_application_screen_brightness") + + async def is_animate(self) -> bool: + """ + Returns `True` if brightness changes are animated (platform dependent). + """ + + return await self._invoke_method("is_animate") + + async def set_animate(self, animate: bool): + """ + Enables or disables animation for brightness changes. + """ + + await self._invoke_method("set_animate", {"value": animate}) + + async def is_auto_reset(self) -> bool: + """ + Returns `True` if brightness resets automatically on lifecycle changes. + """ + + return await self._invoke_method("is_auto_reset") + + async def set_auto_reset(self, auto_reset: bool): + """ + Enables or disables automatic reset to system brightness on lifecycle changes. + """ + + await self._invoke_method("set_auto_reset", {"value": auto_reset}) + + def before_update(self): + if self.page.web or not self.page.platform.is_mobile(): + raise FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on Android and iOS." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/semantics_service.py b/sdk/python/packages/flet/src/flet/controls/services/semantics_service.py new file mode 100644 index 0000000000..0990b5ffcd --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/semantics_service.py @@ -0,0 +1,164 @@ +from dataclasses import dataclass +from enum import Enum + +from flet.controls.base_control import control +from flet.controls.services.service import Service +from flet.utils import from_dict + +__all__ = ["AccessibilityFeatures", "Assertiveness", "SemanticsService"] + + +class Assertiveness(Enum): + """ + Determines the assertiveness level of the accessibility announcement. + """ + + POLITE = "polite" + """ + The assistive technology will speak changes whenever the user is idle. + """ + + ASSERTIVE = "assertive" + """ + The assistive technology will interrupt any announcement that it is currently \ + making to notify the user about the change. + + It should only be used for time-sensitive/critical notifications. + """ + + +@dataclass +class AccessibilityFeatures: + """ + Accessibility features that may be enabled by the platform. + + Note: + It is not possible to enable these settings from Flet, instead they are + used by the platform to indicate that additional accessibility features are + enabled. + """ + + accessible_navigation: bool + """ + Whether there is a running accessibility service which is changing the interaction \ + model of the device. + + For example, TalkBack on Android and VoiceOver on iOS enable this flag. + """ + + bold_text: bool + """ + The platform is requesting that text be rendered at a bold font weight. + + Note: + Only supported on iOS and Android API 31+. + """ + + disable_animations: bool + """ + The platform is requesting that animations be disabled or simplified. + """ + + high_contrast: bool + """ + The platform is requesting that UI be rendered with darker colors. + + Note: + Only supported on iOS. + """ + + invert_colors: bool + """ + The platform is inverting the colors of the application. + """ + + reduce_motion: bool + """ + The platform is requesting that certain animations be simplified and parallax \ + effects removed. + + Note: + Only supported on iOS. + """ + + on_off_switch_labels: bool + """ + The platform is requesting to show on/off labels inside switches. + + Note: + Only supported on iOS. + """ + + supports_announcements: bool + """ + Whether the platform supports accessibility announcement API, i.e. + :meth:`flet.SemanticsService.announce_message`. + + Will be `False` on platforms where announcements are deprecated or + unsupported by the underlying platform and `True` on platforms where such + announcements are generally supported without discouragement (ex: iOS, web). + + Note: + Some platforms do not support or discourage the use of + announcement. Using `SemanticsService.announce_message()` on those platforms + may be ignored. Consider using other way to convey message to the + user. For example, Android discourages the uses of direct message + announcement, and rather encourages using other semantic + properties such as :attr:`flet.Semantics.live_region` to convey + message to the user. + """ + + +@control("SemanticsService") +class SemanticsService(Service): + """ + Allows access to the platform's accessibility services. + """ + + async def announce_tooltip(self, message: str): + """ + Sends a semantic announcement of a tooltip. + + Note: + Only supported on Android. + """ + await self._invoke_method("announce_tooltip", arguments={"message": message}) + + async def announce_message( + self, + message: str, + rtl: bool = False, + assertiveness: Assertiveness = Assertiveness.POLITE, + ): + """ + Sends a semantic announcement with the given message. + + Args: + message: The message to be announced. + rtl: Indicates if the message text direction is right-to-left. + assertiveness: The assertiveness level of the announcement. + Only supported on web. + + Notes: + This method should be used for announcements that are not automatically + handled by the system as a result of a UI state change. + """ + await self._invoke_method( + "announce_message", + arguments={ + "message": message, + "rtl": rtl, + "assertiveness": assertiveness, + }, + ) + + async def get_accessibility_features(self) -> AccessibilityFeatures: + """ + Returns the current platform accessibility feature flags. + + Returns: + A snapshot of the platform's accessibility + preferences at the time of invocation. + """ + features = await self._invoke_method("get_accessibility_features") + return from_dict(AccessibilityFeatures, features) diff --git a/sdk/python/packages/flet/src/flet/controls/services/sensor_error_event.py b/sdk/python/packages/flet/src/flet/controls/services/sensor_error_event.py new file mode 100644 index 0000000000..d69c56b636 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/sensor_error_event.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass + +from flet.controls.control_event import Event, EventControlType + +__all__ = ["SensorErrorEvent"] + + +@dataclass(kw_only=True) +class SensorErrorEvent(Event[EventControlType]): + """ + Generic sensor error event. `message` contains the platform error text. + """ + + message: str + """Human-readable description of the sensor error.""" diff --git a/sdk/python/packages/flet/src/flet/controls/services/service.py b/sdk/python/packages/flet/src/flet/controls/services/service.py new file mode 100644 index 0000000000..bcc080862a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/service.py @@ -0,0 +1,19 @@ +import contextlib +from dataclasses import dataclass + +from flet.controls.base_control import BaseControl +from flet.controls.context import context + +__all__ = ["Service"] + + +@dataclass(kw_only=True) +class Service(BaseControl): + """ + Base class for user services. + """ + + def init(self): + super().init() + with contextlib.suppress(RuntimeError): + context.page._services.register_service(self) diff --git a/sdk/python/packages/flet/src/flet/controls/services/shake_detector.py b/sdk/python/packages/flet/src/flet/controls/services/shake_detector.py new file mode 100644 index 0000000000..1e164b0a57 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/shake_detector.py @@ -0,0 +1,40 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import ControlEventHandler +from flet.controls.services.service import Service +from flet.controls.types import Number + +__all__ = ["ShakeDetector"] + + +@control("ShakeDetector") +class ShakeDetector(Service): + """ + Detects phone shakes. + """ + + minimum_shake_count: int = 1 + """ + Number of shakes required before shake is triggered. + """ + + shake_slop_time_ms: int = 500 + """ + Minimum time between shakes, in milliseconds. + """ + + shake_count_reset_time_ms: int = 3000 + """ + Time, in milliseconds, before shake count resets. + """ + + shake_threshold_gravity: Number = 2.7 + """ + Shake detection threshold, in Gs. + """ + + on_shake: Optional[ControlEventHandler["ShakeDetector"]] = None + """ + Called when a shake is detected. + """ diff --git a/sdk/python/packages/flet/src/flet/controls/services/share.py b/sdk/python/packages/flet/src/flet/controls/services/share.py new file mode 100644 index 0000000000..60c39ba7d0 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/share.py @@ -0,0 +1,325 @@ +from collections.abc import Iterable +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.services.service import Service +from flet.controls.transform import Offset +from flet.utils.from_dict import from_dict + +__all__ = [ + "Share", + "ShareCupertinoActivityType", + "ShareFile", + "ShareResult", + "ShareResultStatus", +] + + +class ShareResultStatus(Enum): + """Outcome of a share operation.""" + + SUCCESS = "success" + """The user selected an action.""" + + DISMISSED = "dismissed" + """The user dismissed the share sheet.""" + + UNAVAILABLE = "unavailable" + """Platform cannot report a definite result.""" + + +class ShareCupertinoActivityType(Enum): + """iOS/macOS activity types that can be excluded from the share sheet.""" + + POST_TO_FACEBOOK = "postToFacebook" + """Share to Facebook.""" + + POST_TO_TWITTER = "postToTwitter" + """Share to Twitter.""" + + POST_TO_WEIBO = "postToWeibo" + """Share to Weibo.""" + + MESSAGE = "message" + """Share via Messages.""" + + MAIL = "mail" + """Share via Mail.""" + + PRINT = "print" + """Send to printer.""" + + COPY_TO_PASTEBOARD = "copyToPasteboard" + """Copy to clipboard.""" + + ASSIGN_TO_CONTACT = "assignToContact" + """Assign to contact.""" + + SAVE_TO_CAMERA_ROLL = "saveToCameraRoll" + """Save to camera roll.""" + + ADD_TO_READING_LIST = "addToReadingList" + """Add to reading list.""" + + POST_TO_FLICKR = "postToFlickr" + """Post to Flickr.""" + + POST_TO_VIMEO = "postToVimeo" + """Post to Vimeo.""" + + POST_TO_TENCENT_WEIBO = "postToTencentWeibo" + """Post to Tencent Weibo.""" + + AIR_DROP = "airDrop" + """AirDrop.""" + + OPEN_IN_IBOOKS = "openInIBooks" + """Open in iBooks.""" + + MARKUP_AS_PDF = "markupAsPDF" + """Markup as PDF.""" + + SHARE_PLAY = "sharePlay" + """SharePlay.""" + + COLLABORATION_INVITE_WITH_LINK = "collaborationInviteWithLink" + """Collaboration invite with link.""" + + COLLABORATION_COPY_LINK = "collaborationCopyLink" + """Collaboration copy link.""" + + ADD_TO_HOME_SCREEN = "addToHomeScreen" + """Add to home screen.""" + + +@dataclass +class ShareResult: + """Result returned from the native share sheet.""" + + status: ShareResultStatus + """The outcome of the share operation.""" + raw: str + """The raw string result from the platform.""" + + +@dataclass +class ShareFile: + """Represents a file to share, either from disk or in-memory bytes.""" + + path: Optional[str] = None + """Filesystem path to the file to share.""" + + data: Optional[bytes] = None + """Raw bytes of the file to share.""" + + mime_type: Optional[str] = None + """MIME type of the file.""" + + name: Optional[str] = None + """Optional name of the file.""" + + def __post_init__(self): + if self.path is None and self.data is None: + raise ValueError("Either 'path' or 'data' must be provided.") + + @staticmethod + def from_path(path: str, *, name: Optional[str] = None) -> "ShareFile": + """ + Create ShareFile from a filesystem path. + + Args: + path: Filesystem path to the file. + name: Optional name of the file. + """ + return ShareFile(path=path, name=name) + + @staticmethod + def from_bytes( + data: bytes, *, mime_type: Optional[str] = None, name: Optional[str] = None + ) -> "ShareFile": + """ + Create ShareFile from raw bytes. + + Args: + data: Raw bytes of the file. + mime_type: Optional MIME type of the file. + name: Optional name of the file. + """ + return ShareFile(data=data, mime_type=mime_type, name=name) + + +@dataclass +@control("Share") +class Share(Service): + """ + Shares text, links, or files using the platform share sheet. + """ + + async def share_text( + self, + text: str, + *, + title: Optional[str] = None, + subject: Optional[str] = None, + preview_thumbnail: Optional[ShareFile] = None, + share_position_origin: Optional[Offset] = None, + download_fallback_enabled: bool = True, + mail_to_fallback_enabled: bool = True, + excluded_cupertino_activities: Optional[ + Iterable[ShareCupertinoActivityType] + ] = None, + ) -> ShareResult: + """ + Share plain text with optional subject, title, and thumbnail. + + Args: + text: The text to share. + title: Optional title for the share sheet. + subject: Optional subject for the shared text. + preview_thumbnail: Optional thumbnail file to show in the share sheet. + share_position_origin: Optional position origin for the share sheet. + download_fallback_enabled: Whether to enable download fallback. + mail_to_fallback_enabled: Whether to enable mailto fallback. + excluded_cupertino_activities: Optional list of iOS/macOS activities + to exclude. + """ + + result = await self._invoke_method( + "share_text", + _share_args( + text=text, + title=title, + subject=subject, + preview_thumbnail=preview_thumbnail, + share_position_origin=share_position_origin, + download_fallback_enabled=download_fallback_enabled, + mail_to_fallback_enabled=mail_to_fallback_enabled, + excluded_cupertino_activities=excluded_cupertino_activities, + ), + ) + return from_dict(ShareResult, result) + + async def share_uri( + self, + uri: str, + *, + share_position_origin: Optional[Offset] = None, + excluded_cupertino_activities: Optional[ + Iterable[ShareCupertinoActivityType] + ] = None, + ) -> ShareResult: + """ + Share a link/URI. + + Args: + uri: The URI to share. + share_position_origin: Optional position origin for the share sheet. + excluded_cupertino_activities: Optional list of iOS/macOS activities + to exclude. + """ + + result = await self._invoke_method( + "share_uri", + _share_args( + uri=uri, + share_position_origin=share_position_origin, + excluded_cupertino_activities=excluded_cupertino_activities, + ), + ) + return from_dict(ShareResult, result) + + async def share_files( + self, + files: list[ShareFile], + *, + title: Optional[str] = None, + text: Optional[str] = None, + subject: Optional[str] = None, + preview_thumbnail: Optional[ShareFile] = None, + share_position_origin: Optional[Offset] = None, + download_fallback_enabled: bool = True, + mail_to_fallback_enabled: bool = True, + excluded_cupertino_activities: Optional[ + Iterable[ShareCupertinoActivityType] + ] = None, + ) -> ShareResult: + """ + Share one or more files with optional text/metadata. + + Args: + files: List of ShareFile instances to share. + title: Optional title for the share sheet. + text: Optional text to accompany the files. + subject: Optional subject for the shared files. + preview_thumbnail: Optional thumbnail file to show in the share sheet. + share_position_origin: Optional position origin for the share sheet. + download_fallback_enabled: Whether to enable download fallback. + mail_to_fallback_enabled: Whether to enable mailto fallback. + excluded_cupertino_activities: Optional list of iOS/macOS activities + to exclude. + """ + + if not files: + raise ValueError("files cannot be empty.") + + result = await self._invoke_method( + "share_files", + _share_args( + files=files, + title=title, + text=text, + subject=subject, + preview_thumbnail=preview_thumbnail, + share_position_origin=share_position_origin, + download_fallback_enabled=download_fallback_enabled, + mail_to_fallback_enabled=mail_to_fallback_enabled, + excluded_cupertino_activities=excluded_cupertino_activities, + ), + ) + return from_dict(ShareResult, result) + + +def _share_args( + *, + text: Optional[str] = None, + uri: Optional[str] = None, + title: Optional[str] = None, + subject: Optional[str] = None, + files: Optional[list[ShareFile]] = None, + preview_thumbnail: Optional[ShareFile] = None, + share_position_origin: Optional[Offset] = None, + download_fallback_enabled: bool = True, + mail_to_fallback_enabled: bool = True, + excluded_cupertino_activities: Optional[ + Iterable[ShareCupertinoActivityType] + ] = None, +): + args: dict = {} + if text is not None: + args["text"] = text + if uri is not None: + args["uri"] = uri + if title is not None: + args["title"] = title + if subject is not None: + args["subject"] = subject + if files is not None: + args["files"] = files + if preview_thumbnail is not None: + args["preview_thumbnail"] = preview_thumbnail + if share_position_origin is not None: + args["share_position_origin"] = { + "x": share_position_origin.x, + "y": share_position_origin.y, + } + args["download_fallback_enabled"] = download_fallback_enabled + args["mail_to_fallback_enabled"] = mail_to_fallback_enabled + + if excluded_cupertino_activities: + args["excluded_cupertino_activities"] = [ + a.value for a in excluded_cupertino_activities + ] + + return args diff --git a/sdk/python/packages/flet/src/flet/controls/services/shared_preferences.py b/sdk/python/packages/flet/src/flet/controls/services/shared_preferences.py new file mode 100644 index 0000000000..96bcc71e1d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/shared_preferences.py @@ -0,0 +1,104 @@ +from typing import Optional, TypeAlias, Union + +from flet.controls.base_control import control +from flet.controls.services.service import Service + +__all__ = ["SharedPreferences", "SharedPreferencesValueType"] + +SharedPreferencesValueType: TypeAlias = Union[str, int, float, bool, list[str]] +"""Supported types for :class:`~flet.SharedPreferences` values.""" + + +@control("SharedPreferences") +class SharedPreferences(Service): + """ + Provides access to persistent key-value storage. + """ + + async def set(self, key: str, value: SharedPreferencesValueType) -> bool: + """ + Sets a value for the given key. + + Note: + Due to limitations on Android, it is not possible to set values that start + with any of the following: `VGhpcyBpcyB0aGUgcHJlZml4IGZvciBhIGxpc3Qu`, + `VGhpcyBpcyB0aGUgcHJlZml4IGZvciBCaWdJbnRlZ2Vy`, and + `VGhpcyBpcyB0aGUgcHJlZml4IGZvciBEb3VibGUu`. + + Args: + key: The key to store the value under. + value: The value to store. + + Returns: + `True` if the value was set successfully, `False` otherwise. + + Raises: + ValueError: If `value` is of an unsupported type + (`str`, `int`, `float`, `bool`, and `list[str]`). + """ + if not ( + isinstance(value, (str, int, float, bool)) + or (isinstance(value, list) and all(isinstance(x, str) for x in value)) + ): + raise ValueError( + f"Unsupported value type: {type(value)}. " + "Supported types are: str, int, float, bool, list[str]." + ) + return await self._invoke_method("set", {"key": key, "value": value}) + + async def get(self, key: str) -> Optional[SharedPreferencesValueType]: + """ + Gets the value for the given key. + + Args: + key: The key to retrieve the value for. + + Returns: + The value for the given key, or `None` if the key doesn't exist. + """ + return await self._invoke_method("get", {"key": key}) + + async def contains_key(self, key: str) -> bool: + """ + Checks if the given key exists. + + Args: + key: The key to check for existence. + + Returns: + `True` if the key exists, `False` otherwise. + """ + return await self._invoke_method("contains_key", {"key": key}) + + async def remove(self, key: str) -> bool: + """ + Removes the value for the given key. + + Args: + key: The key to remove. + + Returns: + `True` if the key was removed, `False` if the key didn't exist. + """ + return await self._invoke_method("remove", {"key": key}) + + async def get_keys(self, key_prefix: str) -> list[str]: + """ + Gets all keys with the given prefix. + + Args: + key_prefix: The prefix to filter keys by. + + Returns: + A list of keys that start with the given prefix. + """ + return await self._invoke_method("get_keys", {"key_prefix": key_prefix}) + + async def clear(self) -> bool: + """ + Clears all keys and values. + + Returns: + `True` if the preferences were cleared successfully, `False` otherwise. + """ + return await self._invoke_method("clear") diff --git a/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py b/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py new file mode 100644 index 0000000000..79f3da135a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/storage_paths.py @@ -0,0 +1,206 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.service import Service +from flet.controls.types import PagePlatform + +__all__ = ["StoragePaths"] + + +@control("StoragePaths") +class StoragePaths(Service): + """ + Provides access to commonly used storage paths on the device. + + Note: + Its methods are not supported in web mode. + """ + + async def get_application_cache_directory(self) -> str: + """Returns the path to the application-specific cache directory. + + If this directory does not exist, it is created automatically. + + Returns: + The path to a directory where the application may place cache files. + + Raises: + FletUnsupportedPlatformException: If called on the web platform. + """ + if self.page.web: + raise FletUnsupportedPlatformException( + "get_application_cache_directory is not supported in web mode" + ) + return await self._invoke_method("get_application_cache_directory") + + async def get_application_documents_directory(self) -> str: + """Returns the path to a directory for user-generated data. + + This directory is intended for data that cannot be recreated by your + application. + + For non-user-generated data, consider using: + + - :meth:`get_application_support_directory` + - :meth:`get_application_cache_directory` + - :meth:`get_external_storage_directory` + + Raises: + FletUnsupportedPlatformException: If called on the web platform. + + Returns: + The path to the application documents directory. + """ # noqa: E501 + if self.page.web: + raise FletUnsupportedPlatformException( + "get_application_documents_directory is not supported in web mode" + ) + return await self._invoke_method("get_application_documents_directory") + + async def get_application_support_directory(self) -> str: + """Returns the path to a directory for application support files. + + This directory is created automatically if it does not exist. + Use this for files not exposed to the user. Do not use for user data files. + + Raises: + FletUnsupportedPlatformException: If called on the web platform. + + Returns: + The path to the application support directory. + """ + if self.page.web: + raise FletUnsupportedPlatformException( + "get_application_support_directory is not supported in web mode" + ) + return await self._invoke_method("get_application_support_directory") + + async def get_downloads_directory(self) -> Optional[str]: + """Returns the path to the downloads directory. + + The returned directory may not exist; clients should verify and create it + if necessary. + + Raises: + FletUnsupportedPlatformException: If called on the web platform. + + Returns: + The path to the downloads directory, or None if unavailable. + """ + if self.page.web: + raise FletUnsupportedPlatformException( + "get_downloads_directory is not supported in web mode" + ) + return await self._invoke_method("get_downloads_directory") + + async def get_external_cache_directories(self) -> Optional[list[str]]: + """Returns paths to external cache directories. + + These directories are typically on external storage (e.g., SD cards). + Multiple directories may be available on some devices. + + Raises: + FletUnsupportedPlatformException: If called on the web or + non-Android platforms. + + Returns: + A List of external cache directory paths, or `None` if unavailable. + """ + if self.page.web or self.page.platform != PagePlatform.ANDROID: + raise FletUnsupportedPlatformException( + "get_external_cache_directories is supported only on Android" + ) + return await self._invoke_method("get_external_cache_directories") + + async def get_external_storage_directories(self) -> Optional[list[str]]: + """Returns paths to external storage directories. + + These directories are typically on external storage (e.g., SD cards). + Multiple directories may be available on some devices. + + Raises: + FletUnsupportedPlatformException: If called on the web or + non-Android platforms. + + Returns: + A List of external storage directory paths, or `None` if unavailable. + """ + if self.page.web or self.page.platform != PagePlatform.ANDROID: + raise FletUnsupportedPlatformException( + "get_external_storage_directories is supported only on Android" + ) + return await self._invoke_method("get_external_storage_directories") + + async def get_library_directory(self) -> str: + """Returns the path to the library directory. + + This directory is for persistent, backed-up files not visible to the user + (e.g., sqlite.db). + + Raises: + FletUnsupportedPlatformException: If called on the web or + non-Apple platforms. + + Returns: + The path to the library directory. + """ + if self.page.web or not self.page.platform.is_apple(): + raise FletUnsupportedPlatformException( + "get_library_directory is supported only on iOS and macOS" + ) + return await self._invoke_method("get_library_directory") + + async def get_external_storage_directory(self) -> Optional[str]: + """Returns the path to the top-level external storage directory. + + Raises: + FletUnsupportedPlatformException: If called on the web or + non-Android platforms. + + Returns: + The path to the external storage directory, or `None` if unavailable. + """ + if self.page.web or self.page.platform != PagePlatform.ANDROID: + raise FletUnsupportedPlatformException( + "get_external_storage_directory is supported only on Android" + ) + return await self._invoke_method("get_external_storage_directory") + + async def get_temporary_directory(self) -> str: + """Returns the path to the temporary directory. + + This directory is not backed up and is suitable for storing caches + of downloaded files. + Files may be cleared at any time. + The caller is responsible for managing files within this directory. + + Raises: + FletUnsupportedPlatformException: If called on the web platform. + + Returns: + The path to the temporary directory. + """ + if self.page.web: + raise FletUnsupportedPlatformException( + "get_temporary_directory is not supported in web mode" + ) + return await self._invoke_method("get_temporary_directory") + + async def get_console_log_filename(self) -> str: + """Returns the path to a `console.log` file for debugging. + + This file is located in the + :meth:`flet.StoragePaths.get_application_cache_directory`. + + Raises: + FletUnsupportedPlatformException: If called on the web platform. + + Returns: + The path to the console log file. + """ # noqa: E501 + if self.page.web: + raise FletUnsupportedPlatformException( + "get_console_log_filename is not supported in web mode" + ) + return await self._invoke_method("get_console_log_filename") diff --git a/sdk/python/packages/flet/src/flet/controls/services/url_launcher.py b/sdk/python/packages/flet/src/flet/controls/services/url_launcher.py new file mode 100644 index 0000000000..59bce71e07 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/url_launcher.py @@ -0,0 +1,182 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import Optional, Union + +from flet.controls.base_control import control +from flet.controls.services.service import Service +from flet.controls.types import Url + +__all__ = [ + "BrowserConfiguration", + "LaunchMode", + "UrlLauncher", + "WebViewConfiguration", +] + + +class LaunchMode(Enum): + """ + Preferred launch mode for opening a URL. + """ + + PLATFORM_DEFAULT = "platformDefault" + """Platform decides how to open the URL.""" + + IN_APP_WEB_VIEW = "inAppWebView" + """Load the URL inside an in-app web view.""" + + IN_APP_BROWSER_VIEW = "inAppBrowserView" + """Load the URL inside an in-app browser view (e.g., custom tabs).""" + + EXTERNAL_APPLICATION = "externalApplication" + """Pass the URL to another application to handle.""" + + EXTERNAL_NON_BROWSER_APPLICATION = "externalNonBrowserApplication" + """Pass the URL to a non-browser application to handle.""" + + +@dataclass +class WebViewConfiguration: + """ + Configuration options for in-app web views. + """ + + enable_javascript: bool = True + """Whether JavaScript execution is allowed.""" + + enable_dom_storage: bool = True + """Whether DOM storage is enabled.""" + + headers: dict[str, str] = field(default_factory=dict) + """Additional HTTP headers to include with the request.""" + + +@dataclass +class BrowserConfiguration: + """ + Configuration options for in-app browser views. + """ + + show_title: bool = False + """Whether the browser view should display the page title.""" + + +@control("UrlLauncher") +class UrlLauncher(Service): + """ + Provides access to URL launching capabilities. + """ + + async def launch_url( + self, + url: Union[str, Url], + *, + mode: LaunchMode = LaunchMode.PLATFORM_DEFAULT, + web_view_configuration: Optional[WebViewConfiguration] = None, + browser_configuration: Optional[BrowserConfiguration] = None, + web_only_window_name: Optional[str] = None, + ): + """ + Opens a web browser or in-app view to a given `url`. + + Args: + url: The URL to open. + mode: Preferred launch mode for opening the URL. + web_view_configuration: Optional configuration for in-app web views. + browser_configuration: Optional configuration for in-app browser views. + web_only_window_name: Window name for web-only launches. + """ + await self._invoke_method( + "launch_url", + { + "url": url, + "mode": mode, + "web_view_configuration": web_view_configuration, + "browser_configuration": browser_configuration, + "web_only_window_name": web_only_window_name, + }, + ) + + async def can_launch_url(self, url: Union[str, Url]) -> bool: + """ + Checks whether the specified URL can be handled by some app installed on the \ + device. + + Args: + url: The URL to check. + + Returns: + `True` if it is possible to verify that there is a handler available. + `False` if there is no handler available, + or the application does not have permission to check. For example: + + - On recent versions of Android and iOS, this will always return `False` + unless the application has been configuration to allow querying the + system for launch support. + - On web, this will always return `False` except for a few specific + schemes that are always assumed to be supported (such as http(s)), + as web pages are never allowed to query installed applications. + """ + return await self._invoke_method( + "can_launch_url", + {"url": url}, + ) + + async def close_in_app_web_view(self): + """ + Closes the in-app web view if it is currently open. + """ + await self._invoke_method("close_in_app_web_view") + + async def open_window( + self, + url: Union[str, Url], + *, + title: Optional[str] = None, + width: Optional[float] = None, + height: Optional[float] = None, + ): + """ + Opens a popup browser window in web environments. + + Args: + url: The URL to open in the popup window. + title: The popup window title. + width: Desired popup width in logical pixels. + height: Desired popup height in logical pixels. + """ + await self._invoke_method( + "open_window", + { + "url": url, + "title": title, + "width": width, + "height": height, + }, + ) + + async def supports_launch_mode(self, mode: LaunchMode) -> bool: + """ + Checks whether the specified launch mode is supported. + + Args: + mode: Launch mode to verify. + + Returns: + `True` if the launch mode is supported by the platform; otherwise `False`. + """ + return await self._invoke_method("supports_launch_mode", {"mode": mode}) + + async def supports_close_for_launch_mode(self, mode: LaunchMode) -> bool: + """ + Checks whether `close_in_app_web_view` is supported for a launch mode. + + Args: + mode: Launch mode to verify close support for. + + Returns: + `True` if closing an in-app web view is supported; otherwise `False`. + """ + return await self._invoke_method( + "supports_close_for_launch_mode", {"mode": mode} + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/user_accelerometer.py b/sdk/python/packages/flet/src/flet/controls/services/user_accelerometer.py new file mode 100644 index 0000000000..895b8dfe7e --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/user_accelerometer.py @@ -0,0 +1,90 @@ +from dataclasses import dataclass +from datetime import datetime +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.control_event import Event, EventHandler +from flet.controls.duration import Duration +from flet.controls.exceptions import FletUnsupportedPlatformException +from flet.controls.services.sensor_error_event import SensorErrorEvent +from flet.controls.services.service import Service + +__all__ = ["UserAccelerometer", "UserAccelerometerReadingEvent"] + + +@dataclass(kw_only=True) +class UserAccelerometerReadingEvent(Event["UserAccelerometer"]): + """ + Like :class:`~flet.AccelerometerReadingEvent`, this is a discrete reading from an \ + accelerometer and measures the velocity of the device. However, unlike \ + :class:`~flet.AccelerometerReadingEvent`, this event does not include the effects \ + of \ + gravity. + """ + + x: float + """Linear acceleration along the X axis, gravity removed, in `m/s^2`.""" + + y: float + """Linear acceleration along the Y axis, gravity removed, in `m/s^2`.""" + + z: float + """Linear acceleration along the Z axis, gravity removed, in `m/s^2`.""" + + timestamp: datetime + """Event timestamp.""" + + +@control("UserAccelerometer") +class UserAccelerometer(Service): + """ + Streams linear acceleration readings. + + If the device is still, or is moving along a straight line at constant speed, + the reported acceleration is zero. If the device is moving e.g. towards north + and its speed is increasing, the reported acceleration is towards north; + if it is slowing down, the reported acceleration is towards south; + if it is turning right, the reported acceleration is towards east. + The data of this stream is obtained by filtering out the effect of gravity + from :class:`~flet.AccelerometerReadingEvent`. + + Note: + * Supported platforms: Android, iOS and web. + * Web ignores requested sampling intervals. + """ + + enabled: bool = True + """ + Whether the sensor should be sampled. Disable to stop streaming. + """ + + interval: Optional[Duration] = None + """ + Desired sampling interval provided as a :class:`~flet.Duration`. + Defaults to 200 ms. + """ + + cancel_on_error: bool = True + """ + Whether the stream subscription should cancel on the first sensor error. + """ + + on_reading: Optional[EventHandler[UserAccelerometerReadingEvent]] = None + """ + Fires when a new reading is available. + + `event` contains `x`, `y`, `z` acceleration values and `timestamp` + (microseconds since epoch). + """ + + on_error: Optional[EventHandler[SensorErrorEvent]] = None + """ + Fired when the platform reports a sensor error. `event.message` is the error \ + description. + """ + + def before_update(self): + if not (self.page.web or self.page.platform.is_mobile()): + raise FletUnsupportedPlatformException( + f"{self.__class__.__name__} is only supported on Android, iOS and web." + ) diff --git a/sdk/python/packages/flet/src/flet/controls/services/wakelock.py b/sdk/python/packages/flet/src/flet/controls/services/wakelock.py new file mode 100644 index 0000000000..e22962a730 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/services/wakelock.py @@ -0,0 +1,32 @@ +from flet.controls.base_control import control +from flet.controls.services.service import Service + +__all__ = ["Wakelock"] + + +@control("Wakelock") +class Wakelock(Service): + """ + Prevents the device from sleeping while enabled. + """ + + async def enable(self): + """ + Keeps the device awake. + """ + + await self._invoke_method("enable") + + async def disable(self): + """ + Allows the device to sleep again. + """ + + await self._invoke_method("disable") + + async def is_enabled(self) -> bool: + """ + Returns `True` if the wakelock is currently enabled. + """ + + return await self._invoke_method("is_enabled") diff --git a/sdk/python/packages/flet/src/flet/controls/template_route.py b/sdk/python/packages/flet/src/flet/controls/template_route.py new file mode 100644 index 0000000000..401395bf0a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/template_route.py @@ -0,0 +1,52 @@ +import re + +import repath + +__all__ = ["TemplateRoute"] + + +class TemplateRoute: + """ + Matches a concrete route string against parameterized route templates. + + Instances keep the original route in `route` and expose matched template + parameters as dynamic attributes after a successful call to `match()`. + Parameter attributes captured by a previous match are reset to `None` before + each new matching attempt, preventing stale values from leaking between + checks. + """ + + def __init__(self, route: str) -> None: + self.__last_params = {} + self.route = route + + def match(self, route_template: str) -> bool: + """ + Tries to match this instance route against a route template. + + The template is compiled with `repath.pattern()`. If matching succeeds, + named parameters are stored and also assigned as attributes on this + object (for example, `self.user_id`). If matching fails, previously + captured attributes remain cleared. + + Args: + route_template: Route template in a format supported by + `repath.pattern()`. + + Returns: + `True` if the route matches the template; otherwise `False`. + """ + # remove old properties + for k in self.__last_params: + setattr(self, k, None) + + # perform new match + pattern = repath.pattern(route_template) + match = re.match(pattern, self.route) + + if match: + self.__last_params = match.groupdict() + for k, v in self.__last_params.items(): + setattr(self, k, v) + return True + return False diff --git a/sdk/python/packages/flet/src/flet/controls/text_style.py b/sdk/python/packages/flet/src/flet/controls/text_style.py new file mode 100644 index 0000000000..0130feb346 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/text_style.py @@ -0,0 +1,487 @@ +from enum import Enum, IntFlag +from typing import Optional + +from flet.controls.base_control import value +from flet.controls.box import BoxShadowValue +from flet.controls.painting import Paint +from flet.controls.types import ColorValue, FontWeight, Number + +__all__ = [ + "StrutStyle", + "TextBaseline", + "TextDecoration", + "TextDecorationStyle", + "TextOverflow", + "TextStyle", + "TextThemeStyle", +] + + +class TextOverflow(Enum): + """ + How overflowing text should be handled. + """ + + CLIP = "clip" + """ + Clip the overflowing text to fix its container. + """ + + ELLIPSIS = "ellipsis" + """ + Use an ellipsis to indicate that the text has overflowed. + """ + + FADE = "fade" + """ + Fade the overflowing text to transparent. + """ + + VISIBLE = "visible" + """ + Render overflowing text outside of its container. + """ + + +class TextBaseline(Enum): + """A horizontal line used for aligning text.""" + + ALPHABETIC = "alphabetic" + """ + The horizontal line used to align the bottom of glyphs for alphabetic characters. + """ + + IDEOGRAPHIC = "ideographic" + """ + The horizontal line used to align ideographic characters. + """ + + +class TextThemeStyle(Enum): + """ + Predefined Material text style roles from the active theme. + + Use these values with properties such as :attr:`flet.Text.theme_style` + to reference semantic typography slots (display, headline, title, body, label) + instead of hard-coding font metrics in each control. + """ + + DISPLAY_LARGE = "displayLarge" + """ + Largest display style. + + Intended for very prominent, short text on large surfaces, such as hero headlines. + """ + + DISPLAY_MEDIUM = "displayMedium" + """ + Medium display style. + + Intended for high-impact short text when :attr:`DISPLAY_LARGE` is too dominant. + """ + + DISPLAY_SMALL = "displaySmall" + """ + Smallest display style. + + Intended for concise, emphasized text that still needs display-level prominence. + """ + + HEADLINE_LARGE = "headlineLarge" + """ + Largest headline style. + + Headline styles are below display styles and suit short, high-emphasis headings. + """ + + HEADLINE_MEDIUM = "headlineMedium" + """ + Medium headline style. + + Suitable for section headers and prominent in-content headings. + """ + + HEADLINE_SMALL = "headlineSmall" + """ + Smallest headline style. + + Suitable for compact headline usage on dense layouts. + """ + + TITLE_LARGE = "titleLarge" + """ + Largest title style. + + Titles are typically used for medium-emphasis, short text such as card titles. + """ + + TITLE_MEDIUM = "titleMedium" + """ + Medium title style. + + Suitable for secondary titles and emphasized labels in structured content. + """ + + TITLE_SMALL = "titleSmall" + """ + Smallest title style. + + Suitable for compact title text where space is limited. + """ + + LABEL_LARGE = "labelLarge" + """ + Largest label style. + + Commonly used for component text, such as button labels and prominent captions. + """ + + LABEL_MEDIUM = "labelMedium" + """ + Medium label style. + + Suitable for compact UI labels in controls and supporting interface text. + """ + + LABEL_SMALL = "labelSmall" + """ + Smallest label style. + + Suitable for dense, low-footprint labels and small supporting annotations. + """ + + BODY_LARGE = "bodyLarge" + """ + Largest body style. + + Body styles are intended for longer passages and primary reading content. + """ + + BODY_MEDIUM = "bodyMedium" + """ + Medium body style. + + Common default style for standard paragraph text in Material-themed UIs. + """ + + BODY_SMALL = "bodySmall" + """ + Smallest body style. + + Suitable for secondary body text, footnotes, and compact long-form content. + """ + + +class TextDecoration(IntFlag): + """ + A linear decoration to draw near the text. + """ + + @classmethod + def combine(cls, decorations: list["TextDecoration"]) -> "TextDecoration": + """ + Creates a decoration that paints the union of all the given decorations. + """ + result = cls.NONE + for d in decorations: + result |= d + return result + + NONE = 0 + """ + Do not draw a decoration. + """ + + UNDERLINE = 1 + """ + Draw a line underneath each line of text. + """ + + OVERLINE = 2 + """ + Draw a line above each line of text. + """ + + LINE_THROUGH = 4 + """ + Draw a line through each line of text. + """ + + +class TextDecorationStyle(Enum): + """ + The style in which to draw a text decoration. + """ + + SOLID = "solid" + """ + Draw a solid line. + """ + + DOUBLE = "double" + """ + Draw two lines. + """ + + DOTTED = "dotted" + """ + Draw a dotted line. + """ + + DASHED = "dashed" + """ + Draw a dashed line. + """ + + WAVY = "wavy" + """ + Draw a sinusoidal line. + """ + + +@value +class TextStyle: + """ + A style describing how to format and paint text. + """ + + size: Optional[Number] = None + """ + The size of glyphs (in logical pixels) to use when painting the text. + + Defaults to `14`. + """ + + height: Optional[Number] = None + """ + The height of this text span, as a multiple of the font size. + + See detailed explanation + [here](https://api.flutter.dev/flutter/painting/TextStyle/height.html). + """ + + weight: Optional[FontWeight] = None + """ + The typeface thickness to use when painting the text (e.g., bold). + + Defaults to :attr:`flet.FontWeight.NORMAL`. + """ + + italic: bool = False + """ + Whether to use italic typeface. + """ + + decoration: Optional[TextDecoration] = None + """ + The decorations to paint near the text (e.g., an underline). + """ + + decoration_color: Optional[ColorValue] = None + """ + The color in which to paint the text decorations. + """ + + decoration_thickness: Optional[Number] = None + """ + The thickness of the decoration stroke as a multiplier of the thickness defined by \ + the font. + """ + + decoration_style: Optional[TextDecorationStyle] = None + """ + The style in which to paint the text decorations (e.g., dashed). + + Defaults to `TextDecorationStyle.SOLID`. + """ + + font_family: Optional[str] = None + """ + See https://flet.dev/docs/controls/text#font_family. + """ + + font_family_fallback: Optional[list[str]] = None + """ + Ordered fallback font families to use when glyphs are not available in + :attr:`font_family`. + """ + + color: Optional[ColorValue] = None + """ + Text foreground https://flet.dev/docs/types/colors. + """ + + bgcolor: Optional[ColorValue] = None + """ + Text background https://flet.dev/docs/types/colors. + """ + + shadow: Optional[BoxShadowValue] = None + """ + TBD + """ + + foreground: Optional[Paint] = None + """ + The paint drawn as a foreground for the text. + """ + + letter_spacing: Optional[Number] = None + """ + The amount of space (in logical pixels) to add between each letter. A negative \ + value can be used to bring the letters closer. + """ + + word_spacing: Optional[Number] = None + """ + The amount of space (in logical pixels) to add at each sequence of white-space \ + (i.e. between each word). A negative value can be used to bring the words closer. + """ + + overflow: Optional[TextOverflow] = None + """ + How visual text overflow should be handled. + """ + + baseline: Optional[TextBaseline] = None + """ + The common baseline that should be aligned between this text span and its parent \ + text span, or, for the root text spans, with the line box. + """ + + def copy( + self, + *, + size: Optional[Number] = None, + height: Optional[Number] = None, + weight: Optional[FontWeight] = None, + italic: Optional[bool] = None, + decoration: Optional[TextDecoration] = None, + decoration_color: Optional[ColorValue] = None, + decoration_thickness: Optional[Number] = None, + decoration_style: Optional[TextDecorationStyle] = None, + font_family: Optional[str] = None, + font_family_fallback: Optional[list[str]] = None, + color: Optional[ColorValue] = None, + bgcolor: Optional[ColorValue] = None, + shadow: Optional[BoxShadowValue] = None, + foreground: Optional[Paint] = None, + letter_spacing: Optional[Number] = None, + word_spacing: Optional[Number] = None, + overflow: Optional[TextOverflow] = None, + baseline: Optional[TextBaseline] = None, + ): + """ + Returns a copy of this object with the specified properties overridden. + """ + return TextStyle( + size=size if size is not None else self.size, + height=height if height is not None else self.height, + weight=weight if weight is not None else self.weight, + italic=italic if italic is not None else self.italic, + decoration=decoration if decoration is not None else self.decoration, + decoration_color=decoration_color + if decoration_color is not None + else self.decoration_color, + decoration_thickness=decoration_thickness + if decoration_thickness is not None + else self.decoration_thickness, + decoration_style=decoration_style + if decoration_style is not None + else self.decoration_style, + font_family=font_family if font_family is not None else self.font_family, + font_family_fallback=font_family_fallback + if font_family_fallback is not None + else self.font_family_fallback, + color=color if color is not None else self.color, + bgcolor=bgcolor if bgcolor is not None else self.bgcolor, + shadow=shadow if shadow is not None else self.shadow, + foreground=foreground if foreground is not None else self.foreground, + letter_spacing=letter_spacing + if letter_spacing is not None + else self.letter_spacing, + word_spacing=word_spacing + if word_spacing is not None + else self.word_spacing, + overflow=overflow if overflow is not None else self.overflow, + baseline=baseline if baseline is not None else self.baseline, + ) + + +@value +class StrutStyle: + """ + TBD + """ + + size: Optional[Number] = None + """ + The size of text (in logical pixels) to use when getting metrics from the font. + + Defaults to `14`. + """ + + height: Optional[Number] = None + """ + The minimum height of the strut, as a multiple of :attr:`size`. + + See detailed explanation here: + https://api.flutter.dev/flutter/painting/StrutStyle/height.html + """ + + weight: Optional[FontWeight] = None + """ + The typeface thickness to use when calculating the strut. + + Defaults to :attr:`flet.FontWeight.W_400`. + """ + + italic: bool = False + """ + Whether to use italic typeface. + """ + + font_family: Optional[str] = None + """ + See :attr:`flet.Text.font_family`. + """ + + leading: Optional[Number] = None + """ + The amount of additional space to place between lines when rendering text. + + Defaults to using the font-specified leading value. + """ + + force_strut_height: Optional[bool] = None + """ + Whether the strut height should be forced. + + Defaults to `False`. + """ + + def copy( + self, + *, + size: Optional[Number] = None, + height: Optional[Number] = None, + weight: Optional[FontWeight] = None, + italic: Optional[bool] = None, + font_family: Optional[str] = None, + leading: Optional[Number] = None, + force_strut_height: Optional[bool] = None, + ) -> "StrutStyle": + """ + Returns a copy of this object with the specified properties overridden. + """ + return StrutStyle( + size=size if size is not None else self.size, + height=height if height is not None else self.height, + weight=weight if weight is not None else self.weight, + italic=italic if italic is not None else self.italic, + font_family=font_family if font_family is not None else self.font_family, + leading=leading if leading is not None else self.leading, + force_strut_height=force_strut_height + if force_strut_height is not None + else self.force_strut_height, + ) diff --git a/sdk/python/packages/flet/src/flet/controls/theme.py b/sdk/python/packages/flet/src/flet/controls/theme.py new file mode 100644 index 0000000000..390b043962 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/theme.py @@ -0,0 +1,3430 @@ +from dataclasses import field +from enum import Enum +from typing import Optional + +from flet.controls.alignment import Alignment +from flet.controls.animation import AnimationStyle +from flet.controls.base_control import value +from flet.controls.border import BorderSide +from flet.controls.border_radius import BorderRadiusValue +from flet.controls.box import BoxConstraints, BoxDecoration, BoxShadowValue +from flet.controls.buttons import ButtonStyle, OutlinedBorder +from flet.controls.control_state import ControlStateValue +from flet.controls.duration import DurationValue +from flet.controls.geometry import Size +from flet.controls.margin import MarginValue +from flet.controls.material.expansion_tile import TileAffinity +from flet.controls.material.list_tile import ListTileStyle, ListTileTitleAlignment +from flet.controls.material.menu_bar import MenuStyle +from flet.controls.material.navigation_bar import NavigationBarLabelBehavior +from flet.controls.material.navigation_rail import NavigationRailLabelType +from flet.controls.material.popup_menu_button import PopupMenuPosition +from flet.controls.material.slider import SliderInteraction +from flet.controls.material.snack_bar import DismissDirection, SnackBarBehavior +from flet.controls.material.tabs import ( + TabAlignment, + TabBarIndicatorSize, + TabIndicatorAnimation, + UnderlineTabIndicator, +) +from flet.controls.material.textfield import TextCapitalization +from flet.controls.material.tooltip import TooltipTriggerMode +from flet.controls.padding import PaddingValue +from flet.controls.text_style import TextStyle +from flet.controls.transform import OffsetValue +from flet.controls.types import ( + Brightness, + ClipBehavior, + ColorValue, + IconData, + MainAxisAlignment, + MouseCursor, + NotchShape, + Number, + StrokeCap, + TextAlign, + VisualDensity, +) + + +class PageTransitionTheme(Enum): + """ + Page transition preset for route changes. + + These could, for example, be used together with \ + :class:`~flet.PageTransitionsTheme` to + define per-platform navigation animations. + """ + + NONE = "none" + """ + Disables route transition animation. + """ + + FADE_UPWARDS = "fadeUpwards" + """ + Fade-and-slide transition where the incoming page moves upward, + similar to the one provided by Android O. + """ + + OPEN_UPWARDS = "openUpwards" + """ + Upward reveal transition with clipping/scrim, + matching the transition used on Android P. + """ + + ZOOM = "zoom" + """ + Zoom/fade transition used by modern Material route animations, + similar to the one provided in Android Q. + """ + + CUPERTINO = "cupertino" + """ + Cupertino-style horizontal page transition, + which matches native iOS page transitions. + """ + + PREDICTIVE = "predictive" + """ + Predictive-back transition that allows peeking behind the current route on Android. + """ + + FADE_FORWARDS = "fadeForwards" + """ + Fade-forward Material route transition, similar to the one provided by Android U. + """ + + +@value +class PageTransitionsTheme: + """ + Per-platform mapping of route transition presets. + + Assigned to :attr:`flet.Theme.page_transitions` to + override how Material routes animate on each target platform. + """ + + android: Optional[PageTransitionTheme] = None + """ + Transition preset for Android routes. + + If `None`, defaults to :attr:`flet.PageTransitionTheme.FADE_UPWARDS`. + """ + + ios: Optional[PageTransitionTheme] = None + """ + Transition preset for iOS routes. + + If `None`, defaults to :attr:`flet.PageTransitionTheme.CUPERTINO`. + """ + + linux: Optional[PageTransitionTheme] = None + """ + Transition preset for Linux desktop routes. + + If `None`, defaults to :attr:`flet.PageTransitionTheme.ZOOM`. + """ + + macos: Optional[PageTransitionTheme] = None + """ + Transition preset for macOS desktop routes. + + If `None`, defaults to :attr:`flet.PageTransitionTheme.ZOOM`. + """ + + windows: Optional[PageTransitionTheme] = None + """ + Transition preset for Windows desktop routes. + + If `None`, defaults to :attr:`flet.PageTransitionTheme.ZOOM`. + """ + + +@value +class ColorScheme: + """ + A set of more than 40 colors based on the [Material \ + spec](https://m3.material.io/styles/color/the-color-system/color-roles) that can \ + be used to configure the color properties of most components. + Read more about color schemes in + [here](https://api.flutter.dev/flutter/material/ColorScheme-class.html). + """ + + primary: Optional[ColorValue] = None + """ + The color displayed most frequently across your app's screens and components. + """ + + on_primary: Optional[ColorValue] = field(default=None, metadata={"event": False}) + """ + A color that's clearly legible when drawn on :attr:`primary`. + """ + + primary_container: Optional[ColorValue] = None + """ + A color used for elements needing less emphasis than :attr:`primary`. + """ + + on_primary_container: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that's clearly legible when drawn on :attr:`primary_container`. + """ + + secondary: Optional[ColorValue] = None + """ + An accent color used for less prominent components in the UI, such as filter \ + :class:`~flet.Chip`s, while expanding the opportunity for color expression. + """ + + on_secondary: Optional[ColorValue] = field(default=None, metadata={"event": False}) + """ + A color that's clearly legible when drawn on :attr:`secondary`. + """ + + secondary_container: Optional[ColorValue] = None + """ + A color used for elements needing less emphasis than :attr:`secondary`. + """ + + on_secondary_container: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that's clearly legible when drawn on :attr:`secondary_container`. + """ + + tertiary: Optional[ColorValue] = None + """ + A color used as a contrasting accent that can balance :attr:`primary` and \ + :attr:`secondary` colors or bring heightened attention to an element, such as an \ + input field. + """ + + on_tertiary: Optional[ColorValue] = field(default=None, metadata={"event": False}) + """ + A color that's clearly legible when drawn on :attr:`tertiary`. + """ + + tertiary_container: Optional[ColorValue] = None + """ + A color used for elements needing less emphasis than :attr:`tertiary`. + """ + + on_tertiary_container: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that's clearly legible when drawn on :attr:`tertiary_container`. + """ + + error: Optional[ColorValue] = None + """ + The color to use for input validation errors, e.g. for \ + :attr:`flet.FormFieldControl.error`. + """ + + on_error: Optional[ColorValue] = field(default=None, metadata={"event": False}) + """ + A color that's clearly legible when drawn on :attr:`error`. + """ + + error_container: Optional[ColorValue] = None + """ + A color used for error elements needing less emphasis than :attr:`error`. + """ + + on_error_container: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that's clearly legible when drawn on :attr:`error_container`. + """ + + surface: Optional[ColorValue] = None + """ + The background color for widgets like :class:`~flet.Card`. + """ + + on_surface: Optional[ColorValue] = field(default=None, metadata={"event": False}) + """ + A color that's clearly legible when drawn on :attr:`surface`. + """ + + on_surface_variant: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that's clearly legible when drawn on :attr:`surface_container_highest`. + """ + + outline: Optional[ColorValue] = None + """ + A utility color that creates boundaries and emphasis to improve usability. + """ + + outline_variant: Optional[ColorValue] = None + """ + A utility color that creates boundaries for decorative elements when a 3:1 \ + contrast isn’t required, such as for dividers or decorative elements. + """ + + shadow: Optional[ColorValue] = None + """ + A color use to paint the drop shadows of elevated components. + """ + + scrim: Optional[ColorValue] = None + """ + A color use to paint the scrim around of modal components. + """ + + inverse_surface: Optional[ColorValue] = None + """ + A surface color used for displaying the reverse of what’s seen in the surrounding \ + UI, for example in a :class:`~flet.SnackBar` to bring attention to an alert. + """ + + on_inverse_surface: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that's clearly legible when drawn on :attr:`inverse_surface`. + """ + + inverse_primary: Optional[ColorValue] = None + """ + An accent color used for displaying a highlight color on :attr:`inverse_surface` + backgrounds, like button text in a :class:`~flet.SnackBar`. + """ + + surface_tint: Optional[ColorValue] = None + """ + A color used as an overlay on a surface color to indicate a component's elevation. + """ + + on_primary_fixed: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that is used for text and icons that exist on top of elements having \ + :attr:`primary_fixed` color. + """ + + on_secondary_fixed: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that is used for text and icons that exist on top of elements having \ + :attr:`secondary_fixed` color. + """ + + on_tertiary_fixed: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that is used for text and icons that exist on top of elements having \ + :attr:`tertiary_fixed` color. + """ + + on_primary_fixed_variant: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that provides a lower-emphasis option for text and icons than \ + :attr:`on_primary_fixed`. + """ + + on_secondary_fixed_variant: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that provides a lower-emphasis option for text and icons than \ + :attr:`on_secondary_fixed`. + """ + + on_tertiary_fixed_variant: Optional[ColorValue] = field( + default=None, metadata={"event": False} + ) + """ + A color that provides a lower-emphasis option for text and icons than \ + :attr:`on_tertiary_fixed`. + """ + + primary_fixed: Optional[ColorValue] = None + """ + A substitute for :attr:`primary_container` that's the same color for the dark \ + and light themes. + """ + + secondary_fixed: Optional[ColorValue] = None + """ + A substitute for :attr:`secondary_container` that's the same color for the dark \ + and light themes. + """ + + tertiary_fixed: Optional[ColorValue] = None + """ + A substitute for :attr:`tertiary_container` that's the same color for dark and \ + light themes. + """ + + primary_fixed_dim: Optional[ColorValue] = None + """ + A color used for elements needing more emphasis than :attr:`primary_fixed`. + """ + + secondary_fixed_dim: Optional[ColorValue] = None + """ + A color used for elements needing more emphasis than :attr:`secondary_fixed`. + """ + + surface_bright: Optional[ColorValue] = None + """ + A color that's always the lightest in the dark or light theme. + """ + + surface_container: Optional[ColorValue] = None + """ + A recommended color role for a distinct area within the surface. + """ + + surface_container_high: Optional[ColorValue] = None + """ + A surface container color with a darker tone. + """ + + surface_container_highest: Optional[ColorValue] = None + """ + A surface container color with the darkest tone. It is used to create the most \ + emphasis against the surface. + """ + + surface_container_low: Optional[ColorValue] = None + """ + A surface container color with a lighter tone that creates less emphasis than \ + `surface_container` but more emphasis than :attr:`surface_container_lowest`. + """ + + surface_container_lowest: Optional[ColorValue] = None + """ + A surface container color with the lightest tone and the least emphasis relative \ + to the surface. + """ + + surface_dim: Optional[ColorValue] = None + """ + A color that's always darkest in the dark or light theme. + """ + + tertiary_fixed_dim: Optional[ColorValue] = None + """ + A color used for elements needing more emphasis than :attr:`tertiary_fixed`. + """ + + +@value +class TextTheme: + """ + Customizes :class:`~flet.Text` styles. + + Material 3 design + [defines](http://localhost:3000/docs/controls/text#pre-defined-theme-text-styles) + 5 groups of text styles with 3 sizes in each group: "Display", "Headline", "Title", + "Label" and "Body" which are used across Flet controls. + """ + + body_large: Optional[TextStyle] = None + """ + Largest of the body styles. Body styles are used for longer passages of text. + """ + + body_medium: Optional[TextStyle] = None + """ + Middle size of the body styles. Body styles are used for longer passages of text. + The default text style for Material. + """ + + body_small: Optional[TextStyle] = None + """ + Smallest of the body styles. + """ + + display_large: Optional[TextStyle] = None + """ + Largest of the display styles. As the largest text on the screen, display styles \ + are reserved for short, important text or numerals. They work best on large \ + screens. + """ + + display_medium: Optional[TextStyle] = None + """ + Middle size of the display styles. + """ + + display_small: Optional[TextStyle] = None + """ + Smallest of the display styles. + """ + + headline_large: Optional[TextStyle] = None + """ + Largest of the headline styles. Headline styles are smaller than display styles. + They're best-suited for short, high-emphasis text on smaller screens. + """ + + headline_medium: Optional[TextStyle] = None + """ + Middle size of the headline styles. + """ + + headline_small: Optional[TextStyle] = None + """ + Smallest of the headline styles. + """ + + label_large: Optional[TextStyle] = None + """ + Largest of the label styles. Label styles are smaller, utilitarian styles, used \ + for areas of the UI such as text inside of components or very small supporting \ + text in the content body, like captions. Used for text on :class:`~flet.Button`, \ + :class:`~flet.TextButton` and :class:`~flet.OutlinedButton`. + """ + + label_medium: Optional[TextStyle] = None + """ + Middle size of the label styles. + """ + + label_small: Optional[TextStyle] = None + """ + Smallest of the label styles. + """ + + title_large: Optional[TextStyle] = None + """ + Largest of the title styles. Titles are smaller than headline styles and should be \ + used for shorter, medium-emphasis text. + """ + + title_medium: Optional[TextStyle] = None + """ + Middle size of the title styles. + """ + + title_small: Optional[TextStyle] = None + """ + Smallest of the title styles. + """ + + +@value +class ScrollbarTheme: + """ + Customizes the colors, thickness, and shape of scrollbars across the app. + """ + + thumb_visibility: Optional[ControlStateValue[bool]] = None + """ + Indicates that the scrollbar thumb should be visible, even when a scroll is not \ + underway. When `False`, the scrollbar will be shown during scrolling and will fade \ + out otherwise. When `True`, the scrollbar will always be visible and never fade \ + out. Property value could be either a single boolean value or a dictionary with \ + `ft.ControlState` as keys and boolean as values. + """ + + thickness: Optional[ControlStateValue[Optional[Number]]] = None + """ + The thickness of the scrollbar in the cross axis of the scrollable. Property value \ + could be either a single float value or a dictionary with `ft.ControlState` as \ + keys and float as values. + """ + + track_visibility: Optional[ControlStateValue[bool]] = None + """ + Indicates that the scrollbar track should be visible. When `True`, the scrollbar \ + track will always be visible so long as the thumb is visible. If the scrollbar \ + thumb is not visible, the track will not be visible either. Defaults to `False` \ + when `None`. If this property is `None`, then `ScrollbarTheme.track_visibility` of \ + `Theme.scrollbar_theme` is used. If that is also `None`, the default value is \ + `False`. Property value could be either a single boolean value or a dictionary \ + with `ft.ControlState` as keys and boolean as values. + """ + + radius: Optional[Number] = None + """ + The Radius of the scrollbar thumb's rounded rectangle corners. + """ + + thumb_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default Color of the Scrollbar thumb. The value is either a single \ + color string or `ft.ControlState` dictionary. + """ + + track_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default Color of the Scrollbar track. The value is either a single \ + color string or `ft.ControlState` dictionary. + """ + + track_border_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default Color of the Scrollbar track border. The value is either a \ + single color string or `ft.ControlState` dictionary. + """ + + cross_axis_margin: Optional[Number] = None + """ + Distance from the scrollbar thumb to the nearest cross axis edge in logical \ + pixels. + The scrollbar track consumes this space. Must not be null and defaults to 0. + """ + + main_axis_margin: Optional[Number] = None + """ + Distance from the scrollbar thumb's start and end to the edge of the viewport in \ + logical pixels. It affects the amount of available paint area. The scrollbar track \ + consumes this space. Mustn't be null and defaults to 0. + """ + + min_thumb_length: Optional[Number] = None + """ + The preferred smallest size the scrollbar thumb can shrink to when the total \ + scrollable extent is large, the current visible viewport is small, and the \ + viewport is not overscrolled. + """ + + interactive: Optional[bool] = None + """ + Whether the Scrollbar should be interactive and respond to dragging on the thumb, \ + or tapping in the track area. When `False`, the scrollbar will not respond to \ + gesture or hover events, and will allow to click through it. Defaults to `True` \ + when `None`, unless on Android, which will default to `False` when `None`. + """ + + +@value +class TabBarTheme: + """ + Customizes the appearance of :class:`~flet.TabBar` control across the app. + """ + + indicator_size: Optional[TabBarIndicatorSize] = None + """ + Overrides the default value for :attr:`flet.TabBar.indicator_size`. + """ + + indicator: Optional[UnderlineTabIndicator] = None + """ + Overrides the default value for :attr:`flet.TabBar.indicator`. + """ + + indicator_animation: Optional[TabIndicatorAnimation] = None + """ + Overrides the default value for :attr:`flet.TabBar.indicator_animation`. + """ + + splash_border_radius: Optional[BorderRadiusValue] = None + """ + Overrides the default value for :attr:`flet.TabBar.splash_border_radius`. + """ + + tab_alignment: Optional[TabAlignment] = None + """ + Overrides the default value for :attr:`flet.TabBar.tab_alignment`. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value for :attr:`flet.TabBar.overlay_color`. + """ + + divider_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.TabBar.divider_color`. + """ + + indicator_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.TabBar.indicator_color`. + """ + + mouse_cursor: Optional[ControlStateValue[Optional[MouseCursor]]] = None + """ + Overrides the default value for :attr:`flet.TabBar.mouse_cursor`. + """ + + divider_height: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.TabBar.divider_height`. + """ + + label_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.TabBar.label_color`. + """ + + unselected_label_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.TabBar.unselected_label_color`. + """ + + label_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.TabBar.label_padding`. + """ + + label_text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.TabBar.label_text_style`. + """ + + unselected_label_text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.TabBar.unselected_label_text_style`. + """ + + +@value +class SystemOverlayStyle: + """ + Allows the customization of the mobile's system overlay (which consists of the \ + system status and navigation bars) appearance. + """ + + status_bar_color: Optional[ColorValue] = None + """ + The color of the status bar. + """ + + system_navigation_bar_color: Optional[ColorValue] = None + """ + The color of the system navigation bar. + """ + + system_navigation_bar_divider_color: Optional[ColorValue] = None + """ + The color of the divider between the system navigation bar and the app content. + """ + + enforce_system_navigation_bar_contrast: Optional[bool] = None + """ + Indicates whether the system should enforce contrast for the status bar when \ + setting a transparent status bar. + """ + + enforce_system_status_bar_contrast: Optional[bool] = None + """ + Indicates whether the system should enforce contrast for the navigation bar when \ + setting a transparent navigation bar. + """ + + system_navigation_bar_icon_brightness: Optional[Brightness] = None + """ + The brightness of the system navigation bar icons. + """ + + status_bar_brightness: Optional[Brightness] = None + """ + The brightness of the status bar. + """ + + status_bar_icon_brightness: Optional[Brightness] = None + """ + The brightness of the status bar icons. + """ + + +@value +class DialogTheme: + """ + Customizes the appearance of :class:`~flet.AlertDialog` across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.bgcolor` in all descendant \ + :class:`~flet.AlertDialog` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.shadow_color` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + icon_color: Optional[ColorValue] = None + """ + Used to configure the :class:`~flet.IconTheme` for the \ + :attr:`flet.AlertDialog.icon` \ + control. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.elevation` in all \ + descendant \ + dialog controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.shape` in all descendant \ + :class:`~flet.AlertDialog` controls. + """ + + title_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.title_text_style` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + content_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.content_text_style` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + alignment: Optional[Alignment] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.alignment` in all \ + descendant \ + :class:`~flet.AlertDialog` controls. + """ + + actions_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.actions_padding` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.clip_behavior` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + barrier_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.barrier_color` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + inset_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.AlertDialog.inset_padding` in all \ + descendant :class:`~flet.AlertDialog` controls. + """ + + +@value +class ButtonTheme: + """ + Customizes the appearance of :class:`~flet.Button` across the app. + """ + + style: Optional[ButtonStyle] = None + """ + Overrides the default value of :attr:`flet.Button.style` in all descendant \ + :class:`~flet.Button` controls. + """ + + +@value +class OutlinedButtonTheme: + """ + Customizes the appearance of :class:`~flet.OutlinedButton` across the app. + """ + + style: Optional[ButtonStyle] = None + """ + Overrides the default value of :attr:`flet.OutlinedButton.style` in all descendant \ + :class:`~flet.OutlinedButton` controls. + """ + + +@value +class TextButtonTheme: + """ + Customizes the appearance of :class:`~flet.TextButton` across the app. + """ + + style: Optional[ButtonStyle] = None + """ + Overrides the default value of :attr:`flet.TextButton.style` in all descendant \ + :class:`~flet.TextButton` controls. + """ + + +@value +class FilledButtonTheme: + """ + Customizes the appearance of :class:`~flet.FilledButton` across the app. + """ + + style: Optional[ButtonStyle] = None + """ + Overrides the default value of :attr:`flet.Button.style` + in all descendant \ + :class:`~flet.FilledButton` controls. + """ + + +@value +class IconButtonTheme: + """ + Customizes the appearance of :class:`~flet.IconButton` across the app. + """ + + style: Optional[ButtonStyle] = None + """ + Overrides the default value of :attr:`flet.IconButton.style` in all descendant \ + :class:`~flet.IconButton` controls. + """ + + +@value +class BottomSheetTheme: + """ + Customizes the appearance of :class:`~flet.BottomSheet` across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.bgcolor` in all descendant \ + :class:`~flet.BottomSheet` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.elevation` in all \ + descendant \ + :class:`~flet.BottomSheet` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.shape` in all descendant \ + :class:`~flet.BottomSheet` controls. + """ + + show_drag_handle: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.show_drag_handle` in all \ + descendant :class:`~flet.BottomSheet` controls. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.clip_behavior` in all \ + descendant :class:`~flet.BottomSheet` controls. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.size_constraints` in all \ + descendant :class:`~flet.BottomSheet` controls. + """ + + barrier_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.BottomSheet.barrier_color` in all \ + descendant :class:`~flet.BottomSheet` controls. + """ + + drag_handle_color: Optional[ColorValue] = None + """ + Overrides the default value of drag handle color in all descendant \ + :class:`~flet.BottomSheet` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of shadow color in all descendant \ + :class:`~flet.BottomSheet` controls. + """ + + +@value +class CardTheme: + """ + Customizes the appearance of :class:`~flet.Card` across the app. + """ + + color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Card.clip_behavior` in all descendant \ + :class:`~flet.Card` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Card.shadow_color` in all descendant \ + :class:`~flet.Card` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Card.elevation` in all descendant \ + :class:`~flet.Card` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.Card.shape` in all descendant \ + :class:`~flet.Card` controls. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Overrides the default value of :attr:`flet.Card.clip_behavior` in all descendant \ + :class:`~flet.Card` controls. + """ + + margin: Optional[MarginValue] = None + """ + Overrides the default value of :attr:`flet.Card.margin` in all descendant \ + :class:`~flet.Card` controls. + """ + + +@value +class ChipTheme: + """ + Customizes the appearance of :class:`~flet.Chip` across the app. + """ + + color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Chip.color` in all descendant \ + :class:`~flet.Chip` controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.bgcolor` in all descendant \ + :class:`~flet.Chip` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.shadow_color` in all descendant \ + :class:`~flet.Chip` controls. + """ + + selected_shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.selected_shadow_color` in all \ + descendant :class:`~flet.Chip` controls. + """ + + disabled_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.disabled_color` in all descendant \ + :class:`~flet.Chip` controls. + """ + + selected_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.selected_color` in all descendant \ + :class:`~flet.Chip` controls. + """ + + check_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.check_color` in all descendant \ + :class:`~flet.Chip` controls. + """ + + delete_icon_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Chip.delete_icon_color` in all \ + descendant \ + :class:`~flet.Chip` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Chip.elevation` in all descendant \ + :class:`~flet.Chip` controls. + """ + + elevation_on_click: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Chip.elevation_on_click` in all \ + descendant :class:`~flet.Chip` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.Chip.shape` in all descendant \ + :class:`~flet.Chip` controls. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.Chip.padding` in all descendant \ + :class:`~flet.Chip` controls. + """ + + label_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.Chip.label_padding` in all descendant \ + :class:`~flet.Chip` controls. + """ + + label_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.Chip.label_text_style` in all \ + descendant \ + :class:`~flet.Chip` controls. + """ + + border_side: Optional[BorderSide] = None + """ + Overrides the default value of :attr:`flet.Chip.border_side` in all descendant \ + :class:`~flet.Chip` controls. + """ + + show_checkmark: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.Chip.show_checkmark` in all descendant \ + :class:`~flet.Chip` controls. + """ + + leading_size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value of :attr:`flet.Chip.leading_size_constraints` in all \ + descendant :class:`~flet.Chip` controls. + """ + + delete_icon_size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value of :attr:`flet.Chip.delete_icon_size_constraints` in \ + all \ + descendant :class:`~flet.Chip` controls. + """ + + brightness: Optional[Brightness] = None + """ + Overrides the default value for all chips which affects various base material \ + color choices in the chip rendering. + """ + + # secondary_selected_color: Optional[ColorValue] = None + # secondary_label_text_style: Optional[TextStyle] = None + + +@value +class FloatingActionButtonTheme: + """ + Customizes the appearance of :class:`~flet.FloatingActionButton` + across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Color to be used for the unselected, enabled :class:`~flet.FloatingActionButton`'s \ + background. + """ + + hover_color: Optional[ColorValue] = None + """ + The color to use for filling the button when the button has a pointer hovering \ + over it. + """ + + focus_color: Optional[ColorValue] = None + """ + The color to use for filling the button when the button has input focus. + """ + + foreground_color: Optional[ColorValue] = None + """ + Color to be used for the unselected, enabled :class:`~flet.FloatingActionButton`'s \ + foreground. + """ + + splash_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.FloatingActionButton.splash_color` in \ + all \ + descendant :class:`~flet.FloatingActionButton` controls. + """ + + elevation: Optional[Number] = None + """ + The z-coordinate to be used for the unselected, enabled \ + :class:`~flet.FloatingActionButton`'s elevation foreground. + """ + + focus_elevation: Optional[Number] = None + """ + The z-coordinate at which to place this button relative to its parent when the \ + button has the input focus. + """ + + hover_elevation: Optional[Number] = None + """ + The z-coordinate at which to place this button relative to its parent when the \ + button is enabled and has a pointer hovering over it. + """ + + highlight_elevation: Optional[Number] = None + """ + The z-coordinate to be used for the selected, enabled \ + :class:`~flet.FloatingActionButton`'s elevation foreground. + """ + + disabled_elevation: Optional[Number] = None + """ + The z-coordinate to be used for the disabled :class:`~flet.FloatingActionButton`'s \ + elevation foreground. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.FloatingActionButton.shape` in all \ + descendant :class:`~flet.FloatingActionButton` controls. + """ + + enable_feedback: Optional[bool] = None + """ + If specified, defines the feedback property for :class:`~flet.FloatingActionButton`. + """ + + extended_padding: Optional[PaddingValue] = None + """ + The padding for a :class:`~flet.FloatingActionButton`'s that has both icon and \ + content. + """ + + text_style: Optional[TextStyle] = None + """ + Text style merged into default text style of \ + :attr:`flet.FloatingActionButton.content`. + """ + + icon_label_spacing: Optional[Number] = None + """ + The spacing between the icon and the label for :class:`~flet.FloatingActionButton`. + """ + + extended_size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default size constraints of :class:`~flet.FloatingActionButton` that \ + has \ + both icon and content. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default size constraints of :class:`~flet.FloatingActionButton` that \ + has \ + either icon or content and is not a mini button. + """ + + # large_size_constraints: Optional[BoxConstraints] = None + # small_size_constraints: Optional[BoxConstraints] = None + + +@value +class NavigationRailTheme: + """ + Customizes the appearance of :class:`~flet.NavigationRail` across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Color to be used for the :class:`~flet.NavigationRail`'s background. + """ + + indicator_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.NavigationRail.indicator_color` in all \ + descendant :class:`~flet.NavigationRail` controls. when \ + :attr:`flet.NavigationRailTheme.use_indicator` + is true. + """ + + elevation: Optional[Number] = None + """ + The z-coordinate to be used for the :class:`~flet.NavigationRail`'s elevation. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.NavigationRail.indicator_shape` in all \ + descendant :class:`~flet.NavigationRail` controls. + """ + + unselected_label_text_style: Optional[TextStyle] = None + """ + Overrides the default value of \ + :attr:`flet.NavigationRail.unselected_label_text_style` + in all descendant :class:`~flet.NavigationRail` controls. + """ + + selected_label_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.NavigationRail.selected_label_text_style` + in all descendant :class:`~flet.NavigationRail` controls. + """ + + label_type: Optional[NavigationRailLabelType] = None + """ + The type that defines the layout and behavior of the labels in the \ + :class:`~flet.NavigationRail`. + """ + + min_width: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.NavigationRail.min_width` in all \ + descendant :class:`~flet.NavigationRail` controls when they are not extended. + """ + + min_extended_width: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.NavigationRail.min_extended_width` in \ + all \ + descendant :class:`~flet.NavigationRail` controls when they are extended. + """ + + group_alignment: Optional[Number] = None + """ + The alignment for the :attr:`flet.NavigationRail.destinations` as they are \ + positioned within the :class:`~flet.NavigationRail`. + """ + + use_indicator: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.NavigationRail.use_indicator` in all \ + descendant :class:`~flet.NavigationRail` controls. + """ + + +@value +class AppBarTheme: + """ + Customizes the appearance of :class:`~flet.AppBar` controls across the app. + """ + + color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.AppBar.color` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.AppBar.bgcolor` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.AppBar.shadow_color` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.AppBar.elevation` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.AppBar.shape` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + title_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.AppBar.title_text_style` in all \ + descendant :class:`~flet.AppBar` controls. + """ + + toolbar_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.AppBar.toolbar_text_style` in all \ + descendant :class:`~flet.AppBar` controls. + """ + + center_title: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.AppBar.center_title` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + title_spacing: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.AppBar.title_spacing` in all descendant \ + :class:`~flet.AppBar` controls. + """ + + elevation_on_scroll: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.AppBar.elevation_on_scroll` in all \ + descendant :class:`~flet.AppBar` controls. + """ + + toolbar_height: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.AppBar.toolbar_height` in all \ + descendant \ + :class:`~flet.AppBar` controls. + """ + + actions_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.AppBar.actions_padding` in all \ + descendant \ + :class:`~flet.AppBar` controls. + """ + + +@value +class BottomAppBarTheme: + """ + Customizes the appearance of :class:`~flet.BottomAppBar` controls across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.BottomAppBar.bgcolor` + in all descendant :class:`~flet.BottomAppBar` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.BottomAppBar.shadow_color` in all \ + descendant :class:`~flet.BottomAppBar` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.BottomAppBar.elevation` in all \ + descendant :class:`~flet.BottomAppBar` controls. + """ + + height: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.BottomAppBar.height` in all descendant \ + :class:`~flet.BottomAppBar` controls. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.BottomAppBar.padding` + in all descendant :class:`~flet.BottomAppBar` controls. + """ + + shape: Optional[NotchShape] = None + """ + Overrides the default value of :attr:`flet.BottomAppBar.shape` in all descendant \ + :class:`~flet.BottomAppBar` controls. + """ + + +@value +class RadioTheme: + """ + Defines default property values for descendant :class:`~flet.Radio` controls. + """ + + fill_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Radio.fill_color` in all descendant \ + :class:`~flet.Radio` controls. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Radio.overlay_color` in all descendant \ + :class:`~flet.Radio` controls. + """ + + splash_radius: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Radio.splash_radius` in all descendant \ + :class:`~flet.Radio` controls. + """ + + visual_density: Optional[VisualDensity] = None + """ + Overrides the default value of :attr:`flet.Radio.visual_density` + in all descendant :class:`~flet.Radio` controls. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value of :attr:`flet.Radio.mouse_cursor` + in all descendant :class:`~flet.Radio` controls. + """ + + +@value +class CheckboxTheme: + """ + Defines default property values for descendant :class:`~flet.Checkbox` controls. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Checkbox.overlay_color` in all \ + descendant \ + :class:`~flet.Checkbox` controls. + """ + + check_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Checkbox.check_color` in all descendant \ + :class:`~flet.Checkbox` controls. + """ + + fill_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Checkbox.fill_color` in all descendant \ + :class:`~flet.Checkbox` controls. + """ + + splash_radius: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Checkbox.splash_radius` in all \ + descendant \ + :class:`~flet.Checkbox` controls. + """ + + border_side: Optional[BorderSide] = None + """ + Overrides the default value of :attr:`flet.Checkbox.border_side` in all descendant \ + :class:`~flet.Checkbox` controls. + """ + + visual_density: Optional[VisualDensity] = None + """ + Overrides the default value of :attr:`flet.Checkbox.visual_density` in all \ + descendant :class:`~flet.Checkbox` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.Checkbox.shape` in all descendant \ + :class:`~flet.Checkbox` controls. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value of :attr:`flet.Checkbox.mouse_cursor` in all \ + descendant \ + :class:`~flet.Checkbox` controls. + """ + + +@value +class BadgeTheme: + """ + Defines default property values for descendant :class:`~flet.Badge` controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Badge.bgcolor` in all descendant \ + :class:`~flet.Badge` controls. + """ + + text_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Badge.text_color` in all descendant \ + :class:`~flet.Badge` controls. + """ + + small_size: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Badge.small_size` in all descendant \ + :class:`~flet.Badge` controls. + """ + + large_size: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Badge.large_size` in all descendant \ + :class:`~flet.Badge` controls. + """ + + alignment: Optional[Alignment] = None + """ + Overrides the default value of :attr:`flet.Badge.alignment` in all descendant \ + :class:`~flet.Badge` controls. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.Badge.padding` in all descendant \ + :class:`~flet.Badge` controls. + """ + + offset: Optional[OffsetValue] = None + """ + Overrides the default value of :attr:`flet.Badge.offset` in all descendant \ + :class:`~flet.Badge` controls. + """ + + text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.Badge.text_style` in all descendant \ + :class:`~flet.Badge` controls. + """ + + +@value +class SwitchTheme: + """ + Defines default property values for descendant :class:`~flet.Switch` controls. + """ + + thumb_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Switch.thumb_color` in all descendant \ + :class:`~flet.Switch` controls. + """ + + track_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Switch.track_color` in all descendant \ + :class:`~flet.Switch` controls. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Switch.overlay_color` + in all descendant :class:`~flet.Switch` controls. + """ + + track_outline_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.Switch.track_outline_color` in all \ + descendant :class:`~flet.Switch` controls. + """ + + thumb_icon: Optional[ControlStateValue[IconData]] = None + """ + Overrides the default value of :attr:`flet.Switch.thumb_icon` in all descendant \ + :class:`~flet.Switch` controls. + """ + + track_outline_width: Optional[ControlStateValue[Optional[Number]]] = None + """ + Overrides the default value of :attr:`flet.Switch.track_outline_width` in all \ + descendant :class:`~flet.Switch` controls. + """ + + splash_radius: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Switch.splash_radius` + in all descendant :class:`~flet.Switch` controls. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value of :attr:`flet.Switch.mouse_cursor` in all descendant \ + :class:`~flet.Switch` controls. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.Switch.padding` in all descendant \ + :class:`~flet.Switch` controls. + """ + + +@value +class DividerTheme: + """ + Defines the visual properties of :class:`~flet.Divider`, + :class:`~flet.VerticalDivider`, + dividers between :class:`~flet.ListTile`s, and dividers between rows in \ + :class:`~flet.DataTable`. + """ + + color: Optional[ColorValue] = None + """ + The color of :class:`~flet.Divider`s and :class:`~flet.VerticalDivider`s, also \ + used between :class:`~flet.ListTile`s, between rows in \ + :class:`~flet.DataTable`s, and \ + so forth. + """ + + thickness: Optional[Number] = None + """ + The thickness of the line drawn within the divider. + """ + + space: Optional[Number] = None + """ + The :class:`~flet.Divider`'s height or the :class:`~flet.VerticalDivider`'s width. + + This represents the amount of horizontal or vertical space the divider takes up. + """ + + leading_indent: Optional[Number] = None + """ + The amount of empty space at the leading edge of :class:`~flet.Divider` or top \ + edge of \ + :class:`~flet.VerticalDivider`. + """ + + trailing_indent: Optional[Number] = None + """ + The amount of empty space at the trailing edge of :class:`~flet.Divider` or bottom \ + edge of :class:`~flet.VerticalDivider`. + """ + + +@value +class SnackBarTheme: + """ + Defines default property values for descendant :class:`~flet.SnackBar` controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.SnackBar.bgcolor` in all descendant \ + :class:`~flet.SnackBar` controls. + """ + + action_text_color: Optional[ColorValue] = None + """ + Overrides the default value of `text_color` of :attr:`flet.SnackBar.action` in all \ + descendant :class:`~flet.SnackBar` controls. + """ + + action_bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of `bgcolor` of :attr:`flet.SnackBar.action` in all \ + descendant :class:`~flet.SnackBar` controls. + """ + + close_icon_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.SnackBar.close_icon_color` in all \ + descendant :class:`~flet.SnackBar` controls. + """ + + disabled_action_text_color: Optional[ColorValue] = None + """ + Overrides the default value of `disabled_text_color` of \ + :attr:`flet.SnackBar.action` \ + in all descendant :class:`~flet.SnackBar` controls. + """ + + disabled_action_bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of `disabled_color` of :attr:`flet.SnackBar.action` in \ + all descendant :class:`~flet.SnackBar` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.SnackBar.elevation` in all descendant \ + :class:`~flet.SnackBar` controls. + """ + + content_text_style: Optional[TextStyle] = None + """ + Used to configure the `text_style` property for the [`SnackBar.content`] control. + """ + + width: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.SnackBar.width` in all descendant \ + :class:`~flet.SnackBar` controls. + """ + + show_close_icon: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.SnackBar.show_close_icon` in all \ + descendant :class:`~flet.SnackBar` controls. + """ + + dismiss_direction: Optional[DismissDirection] = None + """ + Overrides the default value of :attr:`flet.SnackBar.dismiss_direction` in all \ + descendant :class:`~flet.SnackBar` controls. + """ + + behavior: Optional[SnackBarBehavior] = None + """ + Overrides the default value of :attr:`flet.SnackBar.behavior` in all descendant \ + :class:`~flet.SnackBar` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.SnackBar.shape` in all descendant \ + :class:`~flet.SnackBar` controls. + """ + + inset_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.SnackBar.margin`. + + This value is only used when behavior is SnackBarBehavior.floating. + """ + + action_overflow_threshold: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.SnackBar.action_overflow_threshold` in \ + all descendant :class:`~flet.SnackBar` controls. + """ + + +@value +class BannerTheme: + """ + Defines default property values for descendant :class:`~flet.Banner` controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Banner.bgcolor` in all descendant \ + :class:`~flet.Banner` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Banner.shadow_color` in all descendant \ + :class:`~flet.Banner` controls. + """ + + divider_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.Banner.divider_color` + in all descendant :class:`~flet.Banner` controls. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.Banner.content_padding` in all \ + descendant \ + :class:`~flet.Banner` controls. + """ + + leading_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.Banner.leading_padding` in all \ + descendant \ + :class:`~flet.Banner` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.Banner.elevation` in all descendant \ + :class:`~flet.Banner` controls. + """ + + content_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.Banner.content_text_style` in all \ + descendant :class:`~flet.Banner` controls. + """ + + +@value +class DatePickerTheme: + """ + Customizes the appearance of :class:`~flet.DatePicker` controls across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default background color of the surface in all descendant \ + :class:`~flet.DatePicker` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default shadow color in all descendant :class:`~flet.DatePicker` \ + controls. + """ + + divider_color: Optional[ColorValue] = None + """ + Overrides the default color used to paint the divider in all descendant \ + :class:`~flet.DatePicker` controls. + """ + + header_bgcolor: Optional[ColorValue] = None + """ + Overrides the header's default background fill color. + + The :class:`~flet.DatePicker`'s header displays the currently selected date. + """ + + today_bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default color used to paint the background of the \ + [`DatePicker.current_date`].[flet.DatePicker.current_date] label in the grid of \ + the :class:`~flet.DatePicker`. + """ + + day_bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default color used to paint the background of the day labels in the \ + grid of the :class:`~flet.DatePicker`. + """ + + day_overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default highlight color that's typically used to indicate that a day \ + in the grid is focused, hovered, or pressed. + """ + + day_foreground_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default color used to paint the day labels in the grid of the \ + :class:`~flet.DatePicker`. + + This will be used instead of the color provided in + :attr:`flet.DatePickerTheme.day_text_style`. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :class:`~flet.DatePicker` elevation. + """ + + range_picker_elevation: Optional[Number] = None + """ + Overrides the default elevation of the full screen DateRangePicker (TBD). + """ + + day_text_style: Optional[TextStyle] = None + """ + Overrides the default text style used for each individual day label in the grid of \ + the :class:`~flet.DatePicker`. + + The color in :attr:`flet.DatePickerTheme.day_text_style` is not + used, :attr:`flet.DatePickerTheme.day_foreground_color` is used instead. + """ + + weekday_text_style: Optional[TextStyle] = None + """ + Overrides the default text style used for the row of weekday labels at the top of \ + the :class:`~flet.DatePicker` grid. + """ + + year_text_style: Optional[TextStyle] = None + """ + Overrides the default text style used to paint each of the year entries in the \ + year selector of the :class:`~flet.DatePicker`. + + The color of the :attr:`flet.DatePickerTheme.year_text_style` is not used, + :attr:`flet.DatePickerTheme.year_foreground_color` is used instead. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :class:`~flet.DatePicker` shape. + + If elevation is greater than zero then a shadow is shown and the shadow's shape + mirrors the shape of the dialog. + """ + + cancel_button_style: Optional[ButtonStyle] = None + """ + Overrides the default style of the cancel button of a :class:`~flet.DatePicker`. + """ + + confirm_button_style: Optional[ButtonStyle] = None + """ + Overrides the default style of the confirm (OK) button of a \ + :class:`~flet.DatePicker`. + """ + + header_foreground_color: Optional[ColorValue] = None + """ + Overrides the header's default color used for text labels and icons. + + The dialog's header displays the currently selected date. + + This is used instead of the color property of + :attr:`flet.DatePickerTheme.header_headline_text_style` + and :attr:`flet.DatePickerTheme.header_help_text_style`. + """ + + header_headline_text_style: Optional[TextStyle] = None + """ + Overrides the header's default headline text style. + + The dialog's header displays the currently selected date. + + The color of the :attr:`flet.DatePickerTheme.header_headline_text_style` + is not used, :attr:`flet.DatePickerTheme.header_foreground_color` is used instead. + """ + + header_help_text_style: Optional[TextStyle] = None + """ + Overrides the header's default help text style. + + The help text (also referred to as "supporting text" in the Material spec) is + usually a prompt to the user at the top of the header (i.e. 'Select date'). + + The color of the `header_help_style` is not used, + :attr:`flet.DatePickerTheme.header_foreground_color` is used instead. + """ + + range_picker_bgcolor: Optional[ColorValue] = None + """ + Overrides the default background color for :class:`~flet.DateRangePicker`. + """ + + range_picker_header_bgcolor: Optional[ColorValue] = None + """ + Overrides the default background fill color for :class:`~flet.DateRangePicker`. + + The dialog's header displays the currently selected date range. + """ + + range_picker_header_foreground_color: Optional[ColorValue] = None + """ + Overrides the default color used for text labels and icons in the header of a full \ + screen :class:`~flet.DateRangePicker`. + + The dialog's header displays the currently selected date range. + + This is used instead of any colors provided by + `range_picker_header_headline_text_style` or + `range_picker_header_help_text_style`. + """ + + today_foreground_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default color used to paint the :attr:`flet.DatePicker.current_date` \ + label in the grid of the dialog's CalendarDatePicker and the corresponding year in \ + the dialog's YearPicker. + + This will be used instead of the color provided in + :attr:`flet.DatePickerTheme.day_text_style`. + """ + + range_picker_shape: Optional[OutlinedBorder] = None + """ + Overrides the default overall shape of a full screen DateRangePicker (TBD). + + If elevation is greater than zero then a shadow is shown and the shadow's shape + mirrors the shape of the dialog. + """ + + range_picker_header_help_text_style: Optional[TextStyle] = None + """ + Overrides the default text style used for the help text of the header of a full \ + screen DateRangePicker (TBD). + + The help text (also referred to as "supporting text" in the Material spec) is + usually a prompt to the user at the top of the header (i.e. 'Select date'). + + The color of the `range_picker_header_help_text_style` is not used, + `range_picker_header_foreground_color` is used instead. + """ + + range_picker_header_headline_text_style: Optional[TextStyle] = None + """ + Overrides the default text style used for the headline text in the header of a \ + full screen :class:`~flet.DateRangePicker`. + + The dialog's header displays the currently selected date range. + + The color of `range_picker_header_headline_text_style` is not used, + `range_picker_header_foreground_color` is used instead. + """ + + range_selection_bgcolor: Optional[ColorValue] = None + """ + Overrides the default background color used to paint days selected between the \ + start and end dates in a :class:`~flet.DateRangePicker`. + """ + + range_selection_overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default highlight color that's typically used to indicate that a \ + date in the selected range of a :class:`~flet.DateRangePicker` is focused, \ + hovered, or \ + pressed. + """ + + today_border_side: Optional[BorderSide] = None + """ + Overrides the border used to paint the :attr:`flet.DatePicker.current_date` label \ + in \ + the grid of the :class:`~flet.DatePicker`. + + The border side's [`BorderSide.color`] is not used, + :attr:`flet.DatePickerTheme.today_foreground_color` is used instead. + """ + + year_bgcolor: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default color used to paint the background of the year labels in the \ + year selector of the of the :class:`~flet.DatePicker`. + """ + + year_foreground_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default color used to paint the year labels in the year selector of \ + the date picker. + + This will be used instead of the color provided in + :attr:`flet.DatePickerTheme.year_text_style`. + """ + + year_overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default highlight color that's typically used to indicate that a \ + year in the year selector is focused, hovered, or pressed. + """ + + day_shape: Optional[ControlStateValue[OutlinedBorder]] = None + """ + Overrides the default shape used to paint the shape decoration of the day labels \ + in the grid of the :class:`~flet.DatePicker`. + + If the selected day is the current day, the provided shape with the value of + :attr:`flet.DatePickerTheme.today_bgcolor` is used to + paint the shape decoration of the day label and the value of + :attr:`flet.DatePickerTheme.today_border_side` and + :attr:`flet.DatePickerTheme.today_foreground_color` + is used to paint the border. + + If the selected day is not the current day, the provided shape with the value of + :attr:`flet.DatePickerTheme.day_bgcolor` is used to paint + the shape decoration of the day label. + """ + + +@value +class TimePickerTheme: + """ + Customizes the appearance of :class:`~flet.TimePicker` controls across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + The background color of a :class:`~flet.TimePicker`. + + If this is null, the time picker defaults to the overall theme's + :attr:`flet.ColorScheme.surface_container_high`. + """ + + day_period_color: Optional[ColorValue] = None + """ + The background color of the AM/PM toggle. + """ + + day_period_text_color: Optional[ColorValue] = None + """ + The color of the day period text that represents AM/PM. + """ + + dial_bgcolor: Optional[ColorValue] = None + """ + The background color of the time picker dial when the entry mode is \ + :attr:`flet.TimePickerEntryMode.DIAL` or :attr:`flet.TimePickerEntryMode.DIAL_ONLY`. + """ + + dial_hand_color: Optional[ColorValue] = None + """ + The color of the time picker dial's hand when the entry mode is \ + :attr:`flet.TimePickerEntryMode.DIAL` or :attr:`flet.TimePickerEntryMode.DIAL_ONLY`. + """ + + dial_text_color: Optional[ColorValue] = None + """ + The color of the dial text that represents specific hours and minutes. + """ + + entry_mode_icon_color: Optional[ColorValue] = None + """ + The color of the entry mode :class:`~flet.IconButton`. + """ + + hour_minute_color: Optional[ColorValue] = None + """ + The background color of the hour and minute header segments. + """ + + hour_minute_text_color: Optional[ColorValue] = None + """ + The color of the header text that represents hours and minutes. + """ + + day_period_button_style: Optional[ButtonStyle] = None + """ + The style of the AM/PM toggle control of a :class:`~flet.TimePicker`. + """ + + cancel_button_style: Optional[ButtonStyle] = None + """ + The style of the cancel button of a :class:`~flet.TimePicker`. + """ + + confirm_button_style: Optional[ButtonStyle] = None + """ + The style of the confirm (OK) button of a :class:`~flet.TimePicker`. + """ + + day_period_text_style: Optional[TextStyle] = None + """ + Used to configure the :class:`~flet.TextStyle` for the AM/PM toggle control. + + If this is null, the time picker defaults to the overall theme's + :attr:`flet.TextTheme.title_medium`. + """ + + dial_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` for the numbers on the time selection dial. + """ + + help_text_style: Optional[TextStyle] = None + """ + Used to configure the :class:`~flet.TextStyle` for the helper text in the \ + header. + """ + + hour_minute_text_style: Optional[TextStyle] = None + """ + Used to configure the :class:`~flet.TextStyle` for the hour/minute controls. + """ + + elevation: Optional[Number] = None + """ + The Material elevation for the time picker dialog. + """ + + shape: Optional[OutlinedBorder] = None + """ + The shape of the Dialog that the time picker is presented in. + """ + + day_period_shape: Optional[OutlinedBorder] = None + """ + The shape of the day period that the :class:`~flet.TimePicker` uses. + """ + + hour_minute_shape: Optional[OutlinedBorder] = None + """ + The shape of the hour and minute controls that the :class:`~flet.TimePicker` + uses. + """ + + day_period_border_side: Optional[BorderSide] = None + """ + The color and weight of the day period's outline. + """ + + padding: Optional[PaddingValue] = None + """ + The padding around the time picker dialog when the entry mode is \ + :attr:`flet.TimePickerEntryMode.DIAL` or :attr:`flet.TimePickerEntryMode.DIAL_ONLY`. + """ + + time_selector_separator_color: Optional[ControlStateValue[ColorValue]] = None + """ + The color of the time selector separator between the hour and minute controls. + """ + + time_selector_separator_text_style: Optional[ControlStateValue[TextStyle]] = None + """ + Used to configure the text style for the time selector separator between the hour \ + and minute controls. + """ + + +@value +class DropdownTheme: + """ + Customizes the appearance of :class:`~flet.Dropdown` across the app. + """ + + menu_style: Optional[MenuStyle] = None + """ + Overrides the default value for :attr:`flet.Dropdown.menu_style`. + """ + + text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.Dropdown.text_style`. + """ + + +@value +class ListTileTheme: + """ + Customizes the appearance of descendant :class:`~flet.ListTile` controls. + """ + + icon_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.icon_color`. + """ + + text_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.text_color`. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.bgcolor`. + """ + + selected_tile_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.selected_tile_color`. + """ + + selected_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.selected_color`. + """ + + is_three_line: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.ListTile.is_three_line`. + """ + + enable_feedback: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.ListTile.enable_feedback`. + """ + + dense: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.ListTile.dense`. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value for :attr:`flet.ListTile.shape`. + """ + + visual_density: Optional[VisualDensity] = None + """ + Overrides the default value for :attr:`flet.ListTile.visual_density`. + """ + + content_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.content_padding`. + """ + + min_vertical_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.ListTile.min_vertical_padding`. + """ + + horizontal_spacing: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ListTile.horizontal_spacing`. + """ + + min_leading_width: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ListTile.min_leading_width`. + """ + + title_text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.ListTile.title_text_style`. + """ + + subtitle_text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.ListTile.subtitle_text_style`. + """ + + leading_and_trailing_text_style: Optional[TextStyle] = None + """ + Overrides the default value for \ + :attr:`flet.ListTile.leading_and_trailing_text_style`. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value for :attr:`flet.ListTile.mouse_cursor`. + """ + + min_height: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ListTile.min_height`. + """ + + affinity: Optional[TileAffinity] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.affinity`. + """ + + style: Optional[ListTileStyle] = None + """ + Overrides the default value for :attr:`flet.ListTile.style`. + """ + + title_alignment: Optional[ListTileTitleAlignment] = None + """ + Overrides the default value for :attr:`flet.ListTile.title_alignment`. + """ + + +@value +class TooltipTheme: + """ + Customizes the appearance of descendant :class:`~flet.Tooltip` controls. + """ + + text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.Tooltip.text_style`. + """ + + enable_feedback: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.Tooltip.enable_feedback`. + """ + + exclude_from_semantics: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.Tooltip.exclude_from_semantics`. + """ + + prefer_below: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.Tooltip.prefer_below`. + """ + + vertical_offset: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.Tooltip.vertical_offset`. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.Tooltip.padding`. + """ + + wait_duration: Optional[DurationValue] = None + """ + Overrides the default value for :attr:`flet.Tooltip.wait_duration`. + """ + + exit_duration: Optional[DurationValue] = None + """ + Overrides the default value for :attr:`flet.Tooltip.exit_duration`. + """ + + show_duration: Optional[DurationValue] = None + """ + Overrides the default value for :attr:`flet.Tooltip.show_duration`. + """ + + margin: Optional[MarginValue] = None + """ + Overrides the default value for :attr:`flet.Tooltip.margin`. + """ + + trigger_mode: Optional[TooltipTriggerMode] = None + """ + Overrides the default value for :attr:`flet.Tooltip.trigger_mode`. + """ + + decoration: Optional[BoxDecoration] = None + """ + Overrides the default value for :attr:`flet.Tooltip.decoration`. + """ + + text_align: Optional[TextAlign] = None + """ + Overrides the default value for :attr:`flet.Tooltip.text_align`. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value for :attr:`flet.Tooltip.size_constraints`. + """ + + +@value +class ExpansionTileTheme: + """ + Customizes the appearance of descendant :class:`~flet.ExpansionTile` + controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.bgcolor`. + """ + + icon_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.icon_color`. + """ + + text_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.text_color`. + """ + + collapsed_bgcolor: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.collapsed_bgcolor`. + """ + + collapsed_icon_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.collapsed_icon_color`. + """ + + clip_behavior: Optional[ClipBehavior] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.clip_behavior`. + """ + + collapsed_text_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.collapsed_text_color`. + """ + + tile_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.tile_padding`. + """ + + expanded_alignment: Optional[Alignment] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.expanded_alignment`. + """ + + controls_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.controls_padding`. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.shape`. + """ + + collapsed_shape: Optional[OutlinedBorder] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.collapsed_shape`. + """ + + animation_style: Optional[AnimationStyle] = None + """ + Overrides the default value for :attr:`flet.ExpansionTile.animation_style`. + """ + + +@value +class SliderTheme: + """ + Customizes the appearance of descendant :class:`~flet.Slider` controls. + """ + + active_track_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.Slider.active_color`. + """ + + inactive_track_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.Slider.inactive_color`. + """ + + thumb_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.Slider.thumb_color`. + """ + + overlay_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.Slider.overlay_color`. + """ + + value_indicator_color: Optional[ColorValue] = None + """ + The color given to the :class:`~flet.Slider`'s value indicator to draw itself with. + """ + + disabled_thumb_color: Optional[ColorValue] = None + """ + The color given to the thumb to draw itself with when the :class:`~flet.Slider` + is disabled. + """ + + value_indicator_text_style: Optional[TextStyle] = None + """ + The :class:`~flet.TextStyle` for the text on the value indicator. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value for :attr:`flet.Slider.mouse_cursor`. + """ + + active_tick_mark_color: Optional[ColorValue] = None + """ + The color of the track's tick marks that are drawn between the \ + :attr:`flet.Slider.min` position and the current thumb position. + """ + + disabled_active_tick_mark_color: Optional[ColorValue] = None + """ + The color of the track's tick marks that are drawn between the current thumb \ + osition and the :attr:`flet.Slider.max` position when the :class:`~flet.Slider` \ + is disabled. + """ + + disabled_active_track_color: Optional[ColorValue] = None + """ + The color of the :class:`~flet.Slider` track between the :attr:`flet.Slider.min` \ + position and the current thumb position when the :class:`~flet.Slider` is disabled. + """ + + disabled_inactive_tick_mark_color: Optional[ColorValue] = None + """ + The color of the track's tick marks that are drawn between the current thumb \ + position and the :attr:`flet.Slider.max` position when the :class:`~flet.Slider` \ + is disabled. + """ + + disabled_inactive_track_color: Optional[ColorValue] = None + """ + The color of the :class:`~flet.Slider` track between the current thumb position \ + and \ + the :attr:`flet.Slider.max` position when the :class:`~flet.Slider` is disabled. + """ + + disabled_secondary_active_track_color: Optional[ColorValue] = None + """ + The color of the :class:`~flet.Slider` track between the current thumb position \ + and \ + the :attr:`flet.Slider.secondary_track_value` position \ + when the :class:`~flet.Slider` is disabled. + """ + + inactive_tick_mark_color: Optional[ColorValue] = None + """ + The color of the track's tick marks that are drawn between the current thumb \ + position and the :attr:`flet.Slider.max` position. + """ + + overlapping_shape_stroke_color: Optional[ColorValue] = None + """ + The color given to the perimeter of the top range thumbs of a \ + :class:`~flet.RangeSlider` when the thumbs are overlapping and the top range \ + value indicator when the value indicators are overlapping. + """ + + min_thumb_separation: Optional[Number] = None + """ + Limits the thumb's separation distance. + + Use this only if you want to control the visual appearance of the thumbs in terms + of a logical pixel value. This can be done when you want a specific look for thumbs + when they are close together. To limit with the real values, rather than logical + pixels, the values can be restricted by the parent. + """ + + secondary_active_track_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.Slider.secondary_active_color`. + """ + + track_height: Optional[Number] = None + """ + The height of the :class:`~flet.Slider` track. + """ + + value_indicator_stroke_color: Optional[ColorValue] = None + """ + The color given to the value indicator shape stroke. + """ + + interaction: Optional[SliderInteraction] = None + """ + Overrides the default value for :attr:`flet.Slider.interaction`. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.Slider.padding`. + """ + + track_gap: Optional[Number] = None + """ + The size of the gap between the active and inactive tracks of the gapped slider \ + track shape. + """ + + thumb_size: Optional[ControlStateValue[Size]] = None + """ + The size of the handle thumb shape thumb. + """ + + year_2023: bool = False + """ + Overrides the default value for :attr:`flet.Slider.year_2023`. + """ + + +@value +class ProgressIndicatorTheme: + """ + Customizes the appearance of progress indicators (:class:`~flet.ProgressBar`, \ + :class:`~flet.ProgressRing`) across the app. + """ + + color: Optional[ColorValue] = None + """ + Overrides the default values for :attr:`flet.ProgressBar.color` and \ + :attr:`flet.ProgressRing.color`. + """ + + circular_track_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ProgressRing.bgcolor`. + """ + + linear_track_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ProgressBar.bgcolor`. + """ + + refresh_bgcolor: Optional[ColorValue] = None + """ + Background color of that fills the circle under the RefreshIndicator (TBD). + """ + + linear_min_height: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ProgressBar.bar_height`. + """ + + border_radius: Optional[BorderRadiusValue] = None + """ + Overrides the default value for :attr:`flet.ProgressBar.border_radius`. + """ + + track_gap: Optional[Number] = None + """ + Overrides the default values for :attr:`flet.ProgressBar.track_gap` and \ + :attr:`flet.ProgressRing.track_gap`. + """ + + circular_track_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.ProgressRing.padding`. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value for :attr:`flet.ProgressRing.size_constraints`. + """ + + stop_indicator_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.ProgressBar.stop_indicator_color`. + """ + + stop_indicator_radius: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ProgressBar.stop_indicator_radius`. + """ + + stroke_align: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ProgressRing.stroke_align`. + """ + + stroke_cap: Optional[StrokeCap] = None + """ + Overrides the default value for :attr:`flet.ProgressRing.stroke_cap`. + """ + + stroke_width: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.ProgressRing.stroke_width`. + """ + + year_2023: bool = False + """ + Overrides the default values for :attr:`flet.ProgressBar.year_2023` and \ + :attr:`flet.ProgressRing.year_2023`. + """ + + +@value +class PopupMenuTheme: + """ + Customizes the appearance of :class:`~flet.PopupMenuButton` across the app. + """ + + color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.bgcolor` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.shadow_color` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + icon_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.icon_color` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + label_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.PopupMenuItem.label_text_style` + in all descendant :class:`~flet.PopupMenuItem` controls. + """ + + enable_feedback: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.enable_feedback` in all \ + descendant :class:`~flet.PopupMenuButton` controls + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.elevation` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + icon_size: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.icon_size` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.shape` in all \ + descendant \ + :class:`~flet.PopupMenuButton` controls. + """ + + menu_position: Optional[PopupMenuPosition] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.menu_position` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + mouse_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value of :attr:`flet.PopupMenuItem.mouse_cursor` in all \ + descendant :class:`~flet.PopupMenuItem` controls. + """ + + menu_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.PopupMenuButton.menu_padding` in all \ + descendant :class:`~flet.PopupMenuButton` controls. + """ + + +@value +class SearchBarTheme: + """ + Customizes the appearance of :class:`~flet.SearchBar` controls across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_bgcolor` in all \ + descendant \ + :class:`~flet.SearchBar` controls. + """ + + text_capitalization: Optional[TextCapitalization] = None + """ + Overrides the default value of :attr:`flet.SearchBar.capitalization` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + shadow_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_shadow_color` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_overlay_color` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + elevation: Optional[ControlStateValue[Optional[Number]]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_elevation` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + text_style: Optional[ControlStateValue[TextStyle]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_text_style` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + hint_style: Optional[ControlStateValue[TextStyle]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_hint_text_style` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + shape: Optional[ControlStateValue[OutlinedBorder]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_shape` in all descendant \ + :class:`~flet.SearchBar` controls. + """ + + padding: Optional[ControlStateValue[PaddingValue]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_padding` in all \ + descendant \ + :class:`~flet.SearchBar` controls. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_size_constraints` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + border_side: Optional[ControlStateValue[BorderSide]] = None + """ + Overrides the default value of :attr:`flet.SearchBar.bar_border_side` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + +@value +class SearchViewTheme: + """ + Customizes the appearance of :class:`~flet.SearchBar` controls across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_bgcolor` in all \ + descendant \ + :class:`~flet.SearchBar` controls. + """ + + divider_color: Optional[ColorValue] = None + """ + Overrides the default value of :attr:`flet.SearchBar.divider_color` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_elevation` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + header_hint_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_hint_text_style` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + header_text_style: Optional[TextStyle] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_header_text_style` in \ + all \ + descendant :class:`~flet.SearchBar` controls. + """ + + shape: Optional[OutlinedBorder] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_shape` in all descendant \ + :class:`~flet.SearchBar` controls. + """ + + border_side: Optional[BorderSide] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_side` in all descendant \ + :class:`~flet.SearchBar` controls. + """ + + size_constraints: Optional[BoxConstraints] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_size_constraints` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + header_height: Optional[Number] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_header_height` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_padding` in all \ + descendant \ + :class:`~flet.SearchBar` controls. + """ + + bar_padding: Optional[PaddingValue] = None + """ + Overrides the default value of :attr:`flet.SearchBar.view_bar_padding` in all \ + descendant :class:`~flet.SearchBar` controls. + """ + + shrink_wrap: Optional[bool] = None + """ + Overrides the default value of :attr:`flet.SearchBar.shrink_wrap` in all \ + descendant \ + :class:`~flet.SearchBar` controls. + """ + + +@value +class NavigationDrawerTheme: + """ + Customizes the appearance of descendant :class:`~flet.NavigationDrawer` + controls. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.NavigationDrawer.bgcolor`. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.NavigationDrawer.shadow_color`. + """ + + indicator_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.NavigationDrawer.indicator_color`. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.NavigationDrawer.elevation`. + """ + + tile_height: Optional[Number] = None + """ + Overrides the default height of :class:`~flet.NavigationDrawerDestination`. + """ + + label_text_style: Optional[ControlStateValue[TextStyle]] = None + """ + The style to merge with the default text style for \ + :class:`~flet.NavigationDrawerDestination` labels. + + Can be used to specify a different style when the label is selected. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + Overrides the default value for :attr:`flet.NavigationDrawer.indicator_shape`. + """ + + indicator_size: Optional[Size] = None + """ + Overrides the default size of the :class:`~flet.NavigationDrawer`'s selection \ + indicator. + """ + + icon_theme: Optional[ControlStateValue["IconTheme"]] = None + """ + The theme to merge with the default icon theme for \ + :class:`~flet.NavigationDrawerDestination` icons. + + Can be used to specify a different icon theme when the icon is selected. + """ + + +@value +class NavigationBarTheme: + """ + Customizes the appearance of :class:`~flet.NavigationBar` + controls across the app. + """ + + bgcolor: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.bgcolor`. + """ + + shadow_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.shadow_color`. + """ + + indicator_color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.indicator_color`. + """ + + overlay_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.overlay_color`. + """ + + elevation: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.elevation`. + """ + + height: Optional[Number] = None + """ + Overrides the default value for :class:`~flet.NavigationBar` height. + """ + + label_text_style: Optional[ControlStateValue[TextStyle]] = None + """ + The style to merge with the default text style for \ + :class:`~flet.NavigationBarDestination` labels. + """ + + indicator_shape: Optional[OutlinedBorder] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.indicator_shape`. + """ + + label_behavior: Optional[NavigationBarLabelBehavior] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.label_behavior`. + """ + + label_padding: Optional[PaddingValue] = None + """ + Overrides the default value for :attr:`flet.NavigationBar.label_padding`. + """ + + +@value +class SegmentedButtonTheme: + """ + Customizes the appearance of :class:`~flet.SegmentedButton` + controls across the app. + """ + + selected_icon: Optional[IconData] = None + """ + Overrides the default value for :attr:`flet.SegmentedButton.selected_icon`. + """ + + style: Optional[ButtonStyle] = None + """ + Overrides the default value for :attr:`flet.SegmentedButton.style`. + """ + + +@value +class IconTheme: + """ + Customizes the appearance of :class:`~flet.Icon` controls across the app. + """ + + color: Optional[ColorValue] = None + """ + Overrides the default value for :attr:`flet.Icon.color`. + """ + + apply_text_scaling: Optional[bool] = None + """ + Overrides the default value for :attr:`flet.Icon.apply_text_scaling`. + """ + + fill: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.Icon.fill`. + """ + + opacity: Optional[Number] = None + """ + An opacity to apply to both explicit and default icon colors. + """ + + size: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.Icon.size`. + """ + + optical_size: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.Icon.optical_size`. + """ + + grade: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.Icon.grade`. + """ + + weight: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.Icon.weight`. + """ + + shadows: Optional[BoxShadowValue] = None + """ + Overrides the default value for :attr:`flet.Icon.shadows`. + """ + + +@value +class DataTableTheme: + """ + Customizes the appearance of :class:`~flet.DataTable` controls across the app. + """ + + checkbox_horizontal_margin: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.checkbox_horizontal_margin`. + """ + + column_spacing: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.column_spacing`. + """ + + data_row_max_height: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.data_row_max_height`. + """ + + data_row_min_height: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.data_row_min_height`. + """ + + data_row_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value for :attr:`flet.DataTable.data_row_color`. + """ + + data_text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.DataTable.data_text_style`. + """ + + divider_thickness: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.divider_thickness`. + """ + + horizontal_margin: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.horizontal_margin`. + """ + + heading_text_style: Optional[TextStyle] = None + """ + Overrides the default value for :attr:`flet.DataTable.heading_text_style`. + """ + + heading_row_color: Optional[ControlStateValue[ColorValue]] = None + """ + Overrides the default value for :attr:`flet.DataTable.heading_row_color`. + """ + + heading_row_height: Optional[Number] = None + """ + Overrides the default value for :attr:`flet.DataTable.heading_row_height`. + """ + + data_row_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value for :class:`~flet.DataRow` mouse cursor. + """ + + decoration: Optional[BoxDecoration] = None + """ + Overrides the default value for :class:`~flet.DataTable` decoration. + """ + + heading_row_alignment: Optional[MainAxisAlignment] = None + """ + Overrides the default value for :attr:`flet.DataColumn.heading_row_alignment`. + """ + + heading_cell_cursor: Optional[ControlStateValue[MouseCursor]] = None + """ + Overrides the default value for :class:`~flet.DataColumn` mouse cursor. + """ + + +@value +class Theme: + """ + Customizes the overall appearance of the application. + """ + + color_scheme_seed: Optional[ColorValue] = None + """ + Overrides the default color scheme seed used to generate + :class:`~flet.ColorScheme`. + The default color is blue. + """ + + font_family: Optional[str] = None + """ + Overrides a default font for the app. + """ + + use_material3: Optional[bool] = None + """ + A temporary flag that can be used to opt-out of Material 3 features. + """ + + appbar_theme: Optional[AppBarTheme] = None + badge_theme: Optional[BadgeTheme] = None + banner_theme: Optional[BannerTheme] = None + bottom_appbar_theme: Optional[BottomAppBarTheme] = None + bottom_sheet_theme: Optional[BottomSheetTheme] = None + card_theme: Optional[CardTheme] = None + checkbox_theme: Optional[CheckboxTheme] = None + chip_theme: Optional[ChipTheme] = None + """ + Customizes the appearance of :class:`~flet.Chip` across the app. + """ + + color_scheme: Optional[ColorScheme] = None + """ + Overrides the default :class:`~flet.ColorScheme` used for the application. + """ + + data_table_theme: Optional[DataTableTheme] = None + """ + Customizes the appearance of :class:`~flet.DataTable` across the app. + """ + + date_picker_theme: Optional[DatePickerTheme] = None + """ + Customizes the appearance of :class:`~flet.DatePicker` across the app. + """ + + dialog_theme: Optional[DialogTheme] = None + """ + Customizes the appearance of :class:`~flet.AlertDialog` across the app. + """ + + divider_theme: Optional[DividerTheme] = None + """ + Defines the visual properties of :class:`~flet.Divider`, \ + :class:`~flet.VerticalDivider`, \ + dividers between :class:`~flet.ListTile`s, and dividers between rows in \ + :class:`~flet.DataTable`. + """ + + divider_color: Optional[ColorValue] = None + """ + Overrides the default color of dividers used in :class:`~flet.Divider`, \ + :class:`~flet.VerticalDivider`, dividers between :class:`~flet.ListTile`s, and \ + dividers \ + between rows in :class:`~flet.DataTable`. + """ + + dropdown_theme: Optional[DropdownTheme] = None + """ + Customizes the appearance of :class:`~flet.Dropdown` across the app. + """ + + button_theme: Optional[ButtonTheme] = None + """ + Customizes the appearance of :class:`~flet.Button` across the app. + """ + + outlined_button_theme: Optional[OutlinedButtonTheme] = None + """ + Customizes the appearance of :class:`~flet.OutlinedButton` across the app. + """ + + text_button_theme: Optional[TextButtonTheme] = None + """ + Customizes the appearance of :class:`~flet.TextButton` across the app. + """ + + filled_button_theme: Optional[FilledButtonTheme] = None + """ + Customizes the appearance of :class:`~flet.FilledButton` across the app. + """ + + icon_button_theme: Optional[IconButtonTheme] = None + """ + Customizes the appearance of :class:`~flet.IconButton` across the app. + """ + + expansion_tile_theme: Optional[ExpansionTileTheme] = None + """ + Customizes the appearance of :class:`~flet.ExpansionTile` across the app. + """ + + floating_action_button_theme: Optional[FloatingActionButtonTheme] = None + """ + Customizes the appearance of :class:`~flet.FloatingActionButton` + across the app. + """ + + icon_theme: Optional[IconTheme] = None + """ + Customizes the appearance of :class:`~flet.Icon` across the app. + """ + + list_tile_theme: Optional[ListTileTheme] = None + """ + Customizes the appearance of :class:`~flet.ListTile` across the app. + """ + + navigation_bar_theme: Optional[NavigationBarTheme] = None + navigation_drawer_theme: Optional[NavigationDrawerTheme] = None + navigation_rail_theme: Optional[NavigationRailTheme] = None + page_transitions: PageTransitionsTheme = field(default_factory=PageTransitionsTheme) + popup_menu_theme: Optional[PopupMenuTheme] = None + splash_color: Optional[ColorValue] = None + highlight_color: Optional[ColorValue] = None + hover_color: Optional[ColorValue] = None + focus_color: Optional[ColorValue] = None + unselected_control_color: Optional[ColorValue] = None + disabled_color: Optional[ColorValue] = None + canvas_color: Optional[ColorValue] = None + scaffold_bgcolor: Optional[ColorValue] = None + """ + Customizes the page background color. + """ + card_bgcolor: Optional[ColorValue] = None + hint_color: Optional[ColorValue] = None + secondary_header_color: Optional[ColorValue] = None + primary_text_theme: Optional[TextTheme] = None + progress_indicator_theme: Optional[ProgressIndicatorTheme] = None + radio_theme: Optional[RadioTheme] = None + scrollbar_theme: Optional[ScrollbarTheme] = None + search_bar_theme: Optional[SearchBarTheme] = None + search_view_theme: Optional[SearchViewTheme] = None + segmented_button_theme: Optional[SegmentedButtonTheme] = None + slider_theme: Optional[SliderTheme] = None + snackbar_theme: Optional[SnackBarTheme] = None + switch_theme: Optional[SwitchTheme] = None + system_overlay_style: Optional[SystemOverlayStyle] = None + tab_bar_theme: Optional[TabBarTheme] = None + text_theme: Optional[TextTheme] = None + time_picker_theme: Optional[TimePickerTheme] = None + tooltip_theme: Optional[TooltipTheme] = None + visual_density: Optional[VisualDensity] = None diff --git a/sdk/python/packages/flet/src/flet/controls/transform.py b/sdk/python/packages/flet/src/flet/controls/transform.py new file mode 100644 index 0000000000..fa42191d4a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/transform.py @@ -0,0 +1,466 @@ +from dataclasses import field +from typing import TYPE_CHECKING, Any, Optional, Union + +from flet.controls.alignment import Alignment +from flet.controls.base_control import value +from flet.controls.types import Number + +if TYPE_CHECKING: + from flet.controls.box import FilterQuality + +__all__ = [ + "Flip", + "Matrix4", + "Offset", + "OffsetValue", + "Rotate", + "RotateValue", + "Scale", + "ScaleValue", + "Transform", +] + + +@value +class Scale: + """ + Scaling configuration for an object. + """ + + scale: Optional[Number] = None + """ + `scale_x` and `scale_y` get the value of `scale` if `scale` is provided. + """ + + scale_x: Optional[Number] = None + """ + The scalar by which to multiply the x-axis. + """ + + scale_y: Optional[Number] = None + """ + The scalar by which to multiply the y-axis. + """ + + alignment: Optional[Alignment] = None + """ + Gives the origin of scale. + """ + + origin: Optional["Offset"] = None + """ + The origin of the coordinate system (relative to the upper left corner), + in logical pixels. + """ + + transform_hit_tests: bool = True + """ + Whether to apply the transformation when performing hit tests. + """ + + filter_quality: Optional["FilterQuality"] = None + """ + The filter quality with which to apply this transform as a bitmap operation. + """ + + def copy( + self, + *, + scale: Optional[Number] = None, + scale_x: Optional[Number] = None, + scale_y: Optional[Number] = None, + alignment: Optional[Alignment] = None, + origin: Optional["Offset"] = None, + transform_hit_tests: Optional[bool] = None, + filter_quality: Optional["FilterQuality"] = None, + ) -> "Scale": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Scale( + scale=scale if scale is not None else self.scale, + scale_x=scale_x if scale_x is not None else self.scale_x, + scale_y=scale_y if scale_y is not None else self.scale_y, + alignment=alignment if alignment is not None else self.alignment, + origin=origin if origin is not None else self.origin, + transform_hit_tests=( + transform_hit_tests + if transform_hit_tests is not None + else self.transform_hit_tests + ), + filter_quality=( + filter_quality if filter_quality is not None else self.filter_quality + ), + ) + + +@value +class Rotate: + """ + Rotation configuration of an object. + """ + + angle: Number + """ + The rotation in clockwise radians. + """ + + alignment: Optional[Alignment] = None + """ + The alignment of the rotation. + """ + + origin: Optional["Offset"] = None + """ + The origin of the coordinate system (relative to the upper left corner), + in logical pixels. + """ + + transform_hit_tests: bool = True + """ + Whether to apply the transformation when performing hit tests. + """ + + filter_quality: Optional["FilterQuality"] = None + """ + The filter quality with which to apply this transform as a bitmap operation. + """ + + def copy( + self, + *, + angle: Optional[Number] = None, + alignment: Optional[Alignment] = None, + origin: Optional["Offset"] = None, + transform_hit_tests: Optional[bool] = None, + filter_quality: Optional["FilterQuality"] = None, + ) -> "Rotate": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Rotate( + angle=angle if angle is not None else self.angle, + alignment=alignment if alignment is not None else self.alignment, + origin=origin if origin is not None else self.origin, + transform_hit_tests=( + transform_hit_tests + if transform_hit_tests is not None + else self.transform_hit_tests + ), + filter_quality=( + filter_quality if filter_quality is not None else self.filter_quality + ), + ) + + +@value +class Offset: + """ + A 2D floating-point offset. + """ + + x: Number = 0 + """ + The horizontal offset. + """ + + y: Number = 0 + """ + The vertical offset. + """ + + transform_hit_tests: bool = True + """ + Whether to apply the transformation when performing hit tests. + """ + + filter_quality: Optional["FilterQuality"] = None + """ + The filter quality with which to apply this transform as a bitmap operation. + """ + + @property + def distance(self) -> float: + """The magnitude of the offset.""" + return (self.x**2 + self.y**2) ** 0.5 + + def copy( + self, + *, + x: Optional[Number] = None, + y: Optional[Number] = None, + transform_hit_tests: Optional[bool] = None, + filter_quality: Optional["FilterQuality"] = None, + ) -> "Offset": + """ + Returns a copy of this object with the specified properties overridden. + """ + return Offset( + x=x if x is not None else self.x, + y=y if y is not None else self.y, + transform_hit_tests=( + transform_hit_tests + if transform_hit_tests is not None + else self.transform_hit_tests + ), + filter_quality=( + filter_quality if filter_quality is not None else self.filter_quality + ), + ) + + +@value +class Flip: + """ + Configuration for :attr:`flet.LayoutControl.flip`. + + Mirrors a control across its x and/or y axis. + """ + + flip_x: bool = False + """ + Whether to flip the x axis. + """ + + flip_y: bool = False + """ + Whether to flip the y axis. + """ + + origin: Optional["Offset"] = None + """ + The origin of the coordinate system (relative to the upper left corner). + """ + + transform_hit_tests: bool = True + """ + Whether to apply the transformation when performing hit tests. + """ + + filter_quality: Optional["FilterQuality"] = None + """ + The filter quality with which to apply this transform as a bitmap operation. + """ + + +@value +class _Matrix4Call: + """ + Internal serialized operation descriptor for :class:`~flet.Matrix4`. + """ + + name: str + args: list[Any] = field(default_factory=list) + + +@value +class Matrix4: + """ + A recorded, replayable Matrix4 transform intent. + + This class records constructors and mutating method calls, then Flet replays + them in Flutter to build a real `Matrix4` for + :attr:`flet.Transform.matrix`. + """ + + ctor: _Matrix4Call = field(default_factory=lambda: _Matrix4Call(name="identity")) + """ + Recorded constructor call. + """ + + ops: list[_Matrix4Call] = field(default_factory=list) + """ + Ordered list of recorded mutating operations. + """ + + @classmethod + def identity(cls) -> "Matrix4": + """ + Creates a matrix initialized with identity transform. + """ + return cls(ctor=_Matrix4Call(name="identity")) + + @classmethod + def translation_values(cls, x: Number, y: Number, z: Number) -> "Matrix4": + """ + Creates a matrix initialized with translation components. + """ + return cls(ctor=_Matrix4Call(name="translation_values", args=[x, y, z])) + + @classmethod + def diagonal3_values(cls, x: Number, y: Number, z: Number) -> "Matrix4": + """ + Creates a matrix initialized with diagonal scale values. + """ + return cls(ctor=_Matrix4Call(name="diagonal3_values", args=[x, y, z])) + + @classmethod + def rotation_z(cls, angle: Number) -> "Matrix4": + """ + Creates a matrix initialized with a z-axis rotation in radians. + """ + return cls(ctor=_Matrix4Call(name="rotation_z", args=[angle])) + + @classmethod + def skew_x(cls, angle: Number) -> "Matrix4": + """ + Creates a matrix initialized with x-axis skew in radians. + """ + return cls(ctor=_Matrix4Call(name="skew_x", args=[angle])) + + @classmethod + def skew_y(cls, angle: Number) -> "Matrix4": + """ + Creates a matrix initialized with y-axis skew in radians. + """ + return cls(ctor=_Matrix4Call(name="skew_y", args=[angle])) + + def translate(self, x: Number, y: Number, z: Number = 0) -> "Matrix4": + """ + Appends translation operation. + """ + self.ops.append(_Matrix4Call(name="translate", args=[x, y, z])) + return self + + def scale( + self, + x: Number, + y: Optional[Number] = None, + z: Optional[Number] = None, + ) -> "Matrix4": + """ + Appends scale operation. + + If only `x` is provided then uniform scale is used. + If `x` and `y` are provided then 2D scale is used. + If all three are provided then 3D scale is used. + """ + args: list[Any] = [x] + if y is None and z is not None: + args.extend([x, z]) + elif y is not None: + args.append(y) + if z is not None: + args.append(z) + self.ops.append(_Matrix4Call(name="scale", args=args)) + return self + + def rotate_z(self, angle: Number) -> "Matrix4": + """ + Appends z-axis rotation operation in radians. + """ + self.ops.append(_Matrix4Call(name="rotate_z", args=[angle])) + return self + + def rotate_x(self, angle: Number) -> "Matrix4": + """ + Appends x-axis rotation operation in radians. + """ + self.ops.append(_Matrix4Call(name="rotate_x", args=[angle])) + return self + + def rotate_y(self, angle: Number) -> "Matrix4": + """ + Appends y-axis rotation operation in radians. + """ + self.ops.append(_Matrix4Call(name="rotate_y", args=[angle])) + return self + + def set_entry(self, row: int, col: int, value: Number) -> "Matrix4": + """ + Appends raw matrix entry mutation. + """ + self.ops.append(_Matrix4Call(name="set_entry", args=[row, col, value])) + return self + + def multiply(self, other: "Matrix4") -> "Matrix4": + """ + Appends multiplication by another recorded matrix. + """ + if not isinstance(other, Matrix4): + raise TypeError("other must be Matrix4") + if other is self: + raise ValueError("other must be a different Matrix4 instance") + self.ops.append(_Matrix4Call(name="multiply", args=[other._snapshot()])) + return self + + def _snapshot(self) -> "Matrix4": + return Matrix4( + ctor=_Matrix4Call( + name=self.ctor.name, + args=self._clone_args(self.ctor.args), + ), + ops=[ + _Matrix4Call(name=op.name, args=self._clone_args(op.args)) + for op in self.ops + ], + ) + + def _clone_args(self, args: list[Any]) -> list[Any]: + cloned: list[Any] = [] + for arg in args: + if isinstance(arg, Matrix4): + cloned.append(arg._snapshot()) + else: + cloned.append(arg) + return cloned + + +@value +class Transform: + """ + Configuration for :attr:`flet.LayoutControl.transform`. + + Applies a generic matrix transform backed by recorded :class:`~flet.Matrix4`. + """ + + matrix: Matrix4 + """ + Matrix transform intent recorded in Python and replayed in Flutter. + """ + + origin: Optional["Offset"] = None + """ + The origin of the coordinate system (relative to the upper left corner). + """ + + alignment: Optional[Alignment] = None + """ + The alignment of the origin, relative to the size of the box. + """ + + transform_hit_tests: bool = True + """ + Whether to apply the transformation when performing hit tests. + """ + + filter_quality: Optional["FilterQuality"] = None + """ + The filter quality with which to apply this transform as a bitmap operation. + """ + + +# typing +RotateValue = Union[Number, Rotate] +"""Type alias for rotation values. + +Represents rotation as either: +- a numeric angle in radians, +- or an explicit :class:`~flet.Rotate` transform. +""" + +ScaleValue = Union[Number, Scale] +"""Type alias for scale values. + +Represents scale as either: +- a numeric uniform scale factor, +- or an explicit :class:`~flet.Scale` transform. +""" + +OffsetValue = Union[Offset, tuple[Number, Number]] +"""Type alias for offset values. + +Represents offset as either: +- an :class:`~flet.Offset` object, +- or an `(x, y)` tuple. +""" diff --git a/sdk/python/packages/flet/src/flet/controls/types.py b/sdk/python/packages/flet/src/flet/controls/types.py new file mode 100644 index 0000000000..8a4fe9f186 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/types.py @@ -0,0 +1,1343 @@ +from dataclasses import field +from enum import Enum +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Optional, + Protocol, + Union, +) + +from flet.controls.base_control import value +from flet.controls.colors import Colors +from flet.controls.cupertino.cupertino_colors import CupertinoColors +from flet.controls.icon_data import IconData + +if TYPE_CHECKING: + from flet.controls.control import Control # noqa + from flet.controls.buttons import ShapeBorder + + +class AppView(Enum): + """ + TBD + """ + + WEB_BROWSER = "web_browser" + FLET_APP = "flet_app" + FLET_APP_WEB = "flet_app_web" + FLET_APP_HIDDEN = "flet_app_hidden" + + +class WebRenderer(Enum): + """ + TBD + """ + + AUTO = "auto" + CANVAS_KIT = "canvaskit" + SKWASM = "skwasm" + + +class RouteUrlStrategy(Enum): + """ + TBD + """ + + PATH = "path" + HASH = "hash" + + +class UrlTarget(Enum): + """ + Specifies where to open a URL. + """ + + BLANK = "blank" + """ + Opens the URL in a new browser tab or window. + """ + + SELF = "_self" + """ + Opens in the same browsing context (i.e., same tab). + """ + + PARENT = "_parent" + """ + Opens in the parent frame, useful with nested iframes. + """ + + TOP = "_top" + """ + Opens in the topmost frame, breaking out of any iframe. + """ + + +@value +class Url: + """ + URL descriptor used by APIs that open links in a browser context. + """ + + url: str + """ + The url to open. + """ + + target: Optional[Union[UrlTarget, str]] = None + """ + Where to open URL in the web mode. + """ + + +class FontWeight(Enum): + """ + The thickness of the glyphs used to draw the text. + """ + + NORMAL = "normal" + """ + The default font weight, equal to `w400`. + """ + + BOLD = "bold" + """ + A commonly used font weight that is heavier than normal, equal to `w700`. + """ + + W_100 = "w100" + """ + Thin, the least thick. + """ + + W_200 = "w200" + """ + Extra-light. + """ + + W_300 = "w300" + """ + Light. + """ + + W_400 = "w400" + """ + Normal / regular / plain. + """ + + W_500 = "w500" + """ + Medium. + """ + + W_600 = "w600" + """ + Semi-bold. + """ + + W_700 = "w700" + """ + Bold. + """ + + W_800 = "w800" + """ + Extra-bold. + """ + + W_900 = "w900" + """ + Black, the most thick. + """ + + +@value +class NotchShape: + """ + A shape with a notch in its outline. + + Typically used as the outline of a 'host' control to make a notch that + accommodates a 'guest' control. + e.g the :class:`~flet.BottomAppBar` may have a notch to accommodate + the :class:`~flet.FloatingActionButton`. + + This class is not intended to be used directly. See usable derivatives: + + - :class:`~flet.AutomaticNotchShape` + - :class:`~flet.CircularRectangleNotchShape` + """ + + _type: Optional[str] = field(init=False, repr=False, compare=False, default=None) + + +@value +class CircularRectangleNotchShape(NotchShape): + """ + A rectangle with a smooth circular notch. + """ + + inverted: bool = False + """ + Whether the notch should be placed at the bottom of the rectangle. + """ + + def __post_init__(self): + self._type = "circular" + + +@value +class AutomaticNotchShape(NotchShape): + """ + A notch sahpe created from :class:`~flet.ShapeBorder`s. + """ + + host: "ShapeBorder" + guest: Optional["ShapeBorder"] = None + + def __post_init__(self): + self._type = "auto" + + +class ResponsiveRowBreakpoint(Enum): + """ + Breakpoint names used by :class:`~flet.ResponsiveRow` and responsive properties \ + such as :attr:`flet.Control.col`. + + To define custom breakpoints, see :attr:`flet.ResponsiveRow.breakpoints`. + """ + + XS = "xs" + """ + Extra small screens. Default min width: `0` px. + """ + + SM = "sm" + """ + Small screens. Default min width: `576` px. + """ + + MD = "md" + """ + Medium screens. Default min width: `768` px. + """ + + LG = "lg" + """ + Large screens. Default min width: `992` px. + """ + + XL = "xl" + """ + Extra-large screens. Default min width: `1200` px. + """ + + XXL = "xxl" + """ + Double extra-large screens. Default min width: `1400` px. + """ + + +Number = Union[int, float] +"""Type alias for numeric values (`int` or `float`).""" + +ResponsiveNumber = Union[dict[Union[str, ResponsiveRowBreakpoint], Number], Number] +"""Type alias for responsive numeric values. + +Represents either: +- a single numeric value used for all breakpoints, +- or a breakpoint-to-value mapping keyed by string or + :class:`~flet.ResponsiveRowBreakpoint`. +""" + + +class MainAxisAlignment(Enum): + """ + How the children should be placed along the main axis. + """ + + START = "start" + """ + Place the children as close to the start of the main axis as possible. + """ + + END = "end" + """ + Place the children as close to the end of the main axis as possible. + """ + + CENTER = "center" + """ + Place the children as close to the middle of the main axis as possible. + """ + + SPACE_BETWEEN = "spaceBetween" + """ + Place the free space evenly between the children. + """ + + SPACE_AROUND = "spaceAround" + """ + Place the free space evenly between the children as well as half of that space \ + before and after the first and last child. + """ + + SPACE_EVENLY = "spaceEvenly" + """ + Place the free space evenly between the children as well as before and after the \ + first and last child. + """ + + +class CrossAxisAlignment(Enum): + """ + How the children should be placed along the cross axis + """ + + START = "start" + """ + Place the children with their start edge aligned with the start side of the cross \ + axis. + """ + + END = "end" + """ + Place the children as close to the end of the cross axis as possible. + """ + + CENTER = "center" + """ + Place the children so that their centers align with the middle of the cross axis. + """ + + STRETCH = "stretch" + """ + Require the children to fill the cross axis. + """ + + BASELINE = "baseline" + """ + Place the children along the cross axis such that their baselines match. + """ + + +class VerticalAlignment(Enum): + """ + The vertical alignment of text within an input box. + """ + + NONE = None + + START = -1.0 + """ + Aligns the text vertically at the topmost location of the TextField. + """ + + END = 1.0 + """ + Aligns the text vertically at the bottommost location of the TextField. + """ + + CENTER = 0.0 + """ + Aligns the text vertically in the center of the TextField. + """ + + +class LabelPosition(Enum): + """ + Position of label in a :class:`~flet.Checkbox`, :class:`~flet.Radio` or \ + :class:`~flet.Switch` + """ + + RIGHT = "right" + """ + The label is positioned to the right of the control. + """ + + LEFT = "left" + """ + The label is positioned to the left of the control. + """ + + +class BlendMode(Enum): + """ + See [BlendMode](https://api.flutter.dev/flutter/dart-ui/BlendMode.html) from \ + Flutter documentation for blend mode examples. + """ + + CLEAR = "clear" + COLOR = "color" + COLOR_BURN = "colorBurn" + COLOR_DODGE = "colorDodge" + DARKEN = "darken" + DIFFERENCE = "difference" + DST = "dst" + DST_A_TOP = "dstATop" + DST_IN = "dstIn" + DST_OUT = "dstOut" + DST_OVER = "dstOver" + EXCLUSION = "exclusion" + HARD_LIGHT = "hardLight" + HUE = "hue" + LIGHTEN = "lighten" + LUMINOSITY = "luminosity" + MODULATE = "modulate" + MULTIPLY = "multiply" + OVERLAY = "overlay" + PLUS = "plus" + SATURATION = "saturation" + SCREEN = "screen" + SOFT_LIGHT = "softLight" + SRC = "src" + SRC_A_TOP = "srcATop" + SRC_IN = "srcIn" + SRC_OUT = "srcOut" + SRC_OVER = "srcOver" + VALUES = "values" + XOR = "xor" + + +class TextAlign(Enum): + """ + The horizontal alignment of text within an input box. + """ + + LEFT = "left" + """ + Align the text on the left edge of the container. + """ + + RIGHT = "right" + """ + Align the text on the right edge of the container. + """ + + CENTER = "center" + """ + Align the text in the center of the container. + """ + + JUSTIFY = "justify" + """ + Stretch lines of text that end with a soft line break to fill the width of the \ + container. + """ + + START = "start" + """ + Align the text on the leading edge of the container. + """ + + END = "end" + """ + Align the text on the trailing edge of the container. + """ + + +class ScrollMode(Enum): + """ + Defines scrolling behavior and scroll bar visibility for scrollable controls. + + When assigned to :attr:`flet.ScrollableControl.scroll`, for example, each value + internally maps to a specific :class:`~flet.Scrollbar` configuration. + """ + + AUTO = "auto" + """ + Scrolling is enabled and scroll bar is only shown when scrolling occurs. + + :class:`~flet.Scrollbar` equivalent: + + ```python + ft.Scrollbar( + thickness=4.0 if page.platform.is_mobile() and not page.web else None, + ) + ``` + """ + + ADAPTIVE = "adaptive" + """ + Scrolling is enabled and scroll bar is always shown when running app as web or \ + desktop. + + :class:`~flet.Scrollbar` equivalent: + + ```python + ft.Scrollbar( + thumb_visibility=page.web or not page.platform.is_mobile(), + thickness=4.0 if page.platform.is_mobile() and not page.web else None, + ) + ``` + """ + + ALWAYS = "always" + """ + Scrolling is enabled and scroll bar is always shown. + + :class:`~flet.Scrollbar` equivalent: + + ```python + ft.Scrollbar( + thumb_visibility=True, + thickness=4.0 if page.platform.is_mobile() and not page.web else None, + ) + ``` + """ + + HIDDEN = "hidden" + """ + Scrolling is enabled, but scroll bar is always hidden. + + :class:`~flet.Scrollbar` equivalent: + + ```python + ft.Scrollbar( + thickness=0, + ) + ``` + """ + + +class ClipBehavior(Enum): + """ + Different ways to clip content. + + See [Clip](https://api.flutter.dev/flutter/dart-ui/Clip.html) + from Flutter documentation for ClipBehavior examples. + """ + + NONE = "none" + """ + No clip at all. + + This is the default option for most widgets: if the content does not overflow the + widget boundary, don't pay any performance cost for clipping. + """ + + ANTI_ALIAS = "antiAlias" + """ + Clip with anti-aliasing. + + This mode has anti-aliased clipping edges, which reduces jagged edges when the clip + shape itself has edges that are diagonal, curved, or otherwise not axis-aligned. + """ + + ANTI_ALIAS_WITH_SAVE_LAYER = "antiAliasWithSaveLayer" + """ + Clip with anti-aliasing and saveLayer immediately following the clip. + """ + + HARD_EDGE = "hardEdge" + """ + Clip, but do not apply anti-aliasing. + + This mode enables clipping, but curves and non-axis-aligned straight lines will be + jagged as no effort is made to anti-alias. + """ + + +class ImageRepeat(Enum): + """ + How to paint any portions of a box not covered by an image. + """ + + NO_REPEAT = "noRepeat" + """Leave uncovered portions of the box transparent.""" + + REPEAT = "repeat" + """Repeat the image in both the x and y directions until the box is filled.""" + + REPEAT_X = "repeatX" + """Repeat the image in the x direction until the box is filled horizontally.""" + + REPEAT_Y = "repeatY" + """Repeat the image in the y direction until the box is filled vertically.""" + + +class PagePlatform(Enum): + """ + Supported platforms for a page, including mobile and desktop systems. Each \ + platform corresponds to a specific operating system or environment. + """ + + IOS = "ios" + ANDROID = "android" + ANDROID_TV = "android_tv" + MACOS = "macos" + WINDOWS = "windows" + LINUX = "linux" + + def is_apple(self) -> bool: + """Whether this PagePlatform instance is an Apple (iOS or macOS) platform.""" + return self in {PagePlatform.IOS, PagePlatform.MACOS} + + def is_mobile(self) -> bool: + """Whether this PagePlatform instance is a mobile (iOS or Android) platform.""" + return self in {PagePlatform.IOS, PagePlatform.ANDROID} + + def is_desktop(self) -> bool: + """ + Whether this PagePlatform instance is a desktop (macOS, Windows, Linux) \ + platform. + """ + return self in {PagePlatform.MACOS, PagePlatform.WINDOWS, PagePlatform.LINUX} + + +class ThemeMode(Enum): + """ + Describes which theme will be used by Flet app. + """ + + SYSTEM = "system" + """ + Use either the light or dark theme based on what the user has selected in the \ + system settings. + """ + + LIGHT = "light" + """ + Always use the light mode regardless of system preference. + """ + + DARK = "dark" + """ + Always use the dark mode (if available) regardless of system preference. + """ + + +class Brightness(Enum): + """ + Describes the contrast of a theme or color palette. + """ + + LIGHT = "light" + """ + The color is light and will require a dark text color to achieve readable \ + contrast. + + For example, the color might be bright white, requiring black text. + """ + + DARK = "dark" + """ + The color is dark and will require a light text color to achieve readable \ + contrast. + + For example, the color might be dark grey, requiring white text. + """ + + +class Orientation(Enum): + """ + Represents the layout orientation. + """ + + PORTRAIT = "portrait" + """ + Orientation with greater height than width. + """ + + LANDSCAPE = "landscape" + """ + Orientation with greater width than height. + """ + + +class DeviceOrientation(Enum): + """ + Supported physical orientations for mobile devices. + """ + + PORTRAIT_UP = "portraitUp" + """ + Device held upright in portrait mode. + """ + + PORTRAIT_DOWN = "portraitDown" + """ + Device held upside-down in portrait mode. + """ + + LANDSCAPE_LEFT = "landscapeLeft" + """ + Device rotated 90° counter-clockwise (home button or primary edge on the right). + """ + + LANDSCAPE_RIGHT = "landscapeRight" + """ + Device rotated 90° clockwise (home button or primary edge on the left). + """ + + +class FloatingActionButtonLocation(Enum): + """ + Defines a position for the :class:`~flet.FloatingActionButton`. + + See [FloatingActionButtonLocation](https://api.flutter.dev/flutter/material/FloatingActionButtonLocation-class.html) + from Flutter documentation for placement location examples. + """ # noqa: E501 + + CENTER_DOCKED = "centerDocked" + CENTER_FLOAT = "centerFloat" + CENTER_TOP = "centerTop" + END_CONTAINED = "endContained" + END_DOCKED = "endDocked" + END_FLOAT = "endFloat" + END_TOP = "endTop" + MINI_CENTER_DOCKED = "miniCenterDocked" + MINI_CENTER_FLOAT = "miniCenterFloat" + MINI_CENTER_TOP = "miniCenterTop" + MINI_END_DOCKED = "miniEndDocked" + MINI_END_FLOAT = "miniEndFloat" + MINI_END_TOP = "miniEndTop" + MINI_START_DOCKED = "miniStartDocked" + MINI_START_FLOAT = "miniStartFloat" + MINI_START_TOP = "miniStartTop" + START_DOCKED = "startDocked" + START_FLOAT = "startFloat" + START_TOP = "startTop" + + +class AppLifecycleState(Enum): + """ + States that an application can be in once it is running. + """ + + SHOW = "show" + """ + The application is shown. + + On mobile platforms, this is usually just before the application replaces another + application in the foreground. + + On desktop platforms, this is just before the application is shown after being + minimized or otherwise made to show at least one view of the application. + + On the web, this is just before a window (or tab) is shown. + """ + + RESUME = "resume" + """ + The application gains input focus. Indicates that the application is entering a \ + state where it is visible, active, and accepting user input. + """ + + HIDE = "hide" + """ + The application is hidden. + + On mobile platforms, this is usually just before the application is replaced by + another application in the foreground. + + On desktop platforms, this is just before the application is hidden by being + minimized or otherwise hiding all views of the application. + + On the web, this is just before a window (or tab) is hidden. + """ + + INACTIVE = "inactive" + """ + The application loses input focus. + + On mobile platforms, this can be during a phone call or when a system dialog is + visible. + + On desktop platforms, this is when all views in an application have lost input + focus but at least one view of the application is still visible. + + On the web, this is when the window (or tab) has lost input focus. + """ + + PAUSE = "pause" + """ + The application is paused. + + On mobile platforms, this happens right before the application is replaced by + another application. + + On desktop platforms and the web, this function is not called. + """ + + DETACH = "detach" + """ + The application has exited, and detached all host views from the engine. + + This callback is only called on iOS and Android. + """ + + RESTART = "restart" + """ + The application is resumed after being paused. + + On mobile platforms, this happens just before this application takes over as the + active application. + + On desktop platforms and the web, this function is not called. + """ + + +class MouseCursor(Enum): + """ + Various mouse cursor types that represent different operations or states. + """ + + ALIAS = "alias" + """ + A cursor indicating that the current operation will create an alias of, or a \ + shortcut of the item. Typically the shape of an arrow with a shortcut icon at the \ + corner. + """ + + ALL_SCROLL = "allScroll" + """ + A cursor indicating scrolling in any direction. Typically the shape of a dot \ + surrounded by 4 arrows. + """ + + BASIC = "basic" + """ + The platform-dependent basic cursor. Typically the shape of an arrow. + """ + + CELL = "cell" + """ + A cursor indicating selectable table cells. Typically the shape of a hollow plus \ + sign. + """ + + CLICK = "click" + """ + A cursor that emphasizes an element being clickable, such as a hyperlink. + Typically the shape of a pointing hand. + """ + + CONTEXT_MENU = "contextMenu" + """ + A cursor indicating somewhere the user can trigger a context menu. Typically the \ + shape of an arrow with a small menu at the corner. + """ + + COPY = "copy" + """ + A cursor indicating that the current operation will copy the item. Typically the \ + shape of an arrow with a boxed plus sign at the corner. + """ + + DISAPPEARING = "disappearing" + """ + A cursor indicating that the current operation will result in the disappearance of \ + the item. Typically the shape of an arrow with a cloud of smoke at the corner. + """ + + FORBIDDEN = "forbidden" + """ + A cursor indicating an operation that will not be carried out. + Typically the shape of a circle with a diagonal line. + """ + + GRAB = "grab" + """ + A cursor indicating something that can be dragged. Typically the shape of an open \ + hand. + """ + + GRABBING = "grabbing" + """ + A cursor indicating something that is being dragged. Typically the shape of a \ + closed hand. + """ + + HELP = "help" + """ + A cursor indicating help information. Typically the shape of a question mark, or \ + an arrow therewith. + """ + + MOVE = "move" + """ + A cursor indicating moving something. Typically the shape of four-way arrow. + """ + + NO_DROP = "noDrop" + """ + A cursor indicating somewhere that the current item may not be dropped. + Typically the shape of a hand with a forbidden sign at the corner. + """ + + NONE = "none" + """ + Hide the cursor. + """ + + PRECISE = "precise" + """ + A cursor indicating precise selection, such as selecting a pixel in a bitmap. + Typically the shape of a crosshair. + """ + + PROGRESS = "progress" + """ + A cursor indicating the status that the program is busy but can still be \ + interacted with. Typically the shape of an arrow with an hourglass or a watch at \ + the corner. + """ + + RESIZE_COLUMN = "resizeColumn" + """ + A cursor indicating resizing a column, or an item horizontally. Typically the \ + shape of arrows pointing left and right with a vertical bar separating them. + """ + + RESIZE_DOWN = "resizeDown" + """ + A cursor indicating resizing an object from its bottom edge. Typically the shape \ + of an arrow pointing down. + """ + + RESIZE_DOWN_LEFT = "resizeDownLeft" + """ + A cursor indicating resizing an object from its bottom-left corner. Typically the \ + shape of an arrow pointing lower left. + """ + + RESIZE_DOWN_RIGHT = "resizeDownRight" + """ + A cursor indicating resizing an object from its bottom-right corner. Typically the \ + shape of an arrow pointing lower right. + """ + + RESIZE_LEFT = "resizeLeft" + """ + A cursor indicating resizing an object from its left edge. Typically the shape of \ + an arrow pointing left. + """ + + RESIZE_LEFT_RIGHT = "resizeLeftRight" + """ + A cursor indicating resizing an object bidirectionally from its left or right \ + edge. + Typically the shape of a bidirectional arrow pointing left and right. + """ + + RESIZE_RIGHT = "resizeRight" + """ + A cursor indicating resizing an object from its right edge. Typically the shape of \ + an arrow pointing right. + """ + + RESIZE_ROW = "resizeRow" + """ + A cursor indicating resizing a row, or an item vertically. Typically the shape of \ + arrows pointing up and down with a horizontal bar separating them. + """ + + RESIZE_UP = "resizeUp" + """ + A cursor indicating resizing an object from its top edge. Typically the shape of \ + an arrow pointing up. + """ + + RESIZE_UP_DOWN = "resizeUpDown" + """ + A cursor indicating resizing an object bidirectionally from its top or bottom \ + edge. + Typically the shape of a bidirectional arrow pointing up and down. + """ + + RESIZE_UP_LEFT = "resizeUpLeft" + """ + A cursor indicating resizing an object from its top-left corner. Typically the \ + shape of an arrow pointing upper left. + """ + + RESIZE_UP_LEFT_DOWN_RIGHT = "resizeUpLeftDownRight" + """ + A cursor indicating resizing an object bidirectionally from its top left or bottom \ + right corner. Typically the shape of a bidirectional arrow pointing upper left and \ + lower right. + """ + + RESIZE_UP_RIGHT = "resizeUpRight" + """ + A cursor indicating resizing an object from its top-right corner. Typically the \ + shape of an arrow pointing upper right. + """ + + RESIZE_UP_RIGHT_DOWN_LEFT = "resizeUpRightDownLeft" + """ + A cursor indicating resizing an object bidirectionally from its top right or \ + bottom left corner. Typically the shape of a bidirectional arrow pointing upper \ + right and lower left. + """ + + TEXT = "text" + """ + A cursor indicating selectable text. Typically the shape of a capital I. + """ + + VERTICAL_TEXT = "verticalText" + """ + A cursor indicating selectable vertical text. Typically the shape of a capital I \ + rotated to be horizontal. + """ + + WAIT = "wait" + """ + A cursor indicating the status that the program is busy and therefore can not be \ + interacted with. Typically the shape of an hourglass or a watch. + + This cursor is not available as a system cursor on macOS. Although macOS displays a + "spinning ball" cursor when busy, it's handled by the OS and not exposed for + applications to choose. + """ + + ZOOM_IN = "zoomIn" + """ + A cursor indicating zooming in. Typically a magnifying glass with a plus sign. + """ + + ZOOM_OUT = "zoomOut" + """ + A cursor indicating zooming out. Typically a magnifying glass with a minus sign. + """ + + +class PointerDeviceType(Enum): + """ + The kind of pointer device. + """ + + TOUCH = "touch" + """ + A touch-based pointer device. + """ + + MOUSE = "mouse" + """ + A mouse-based pointer device. + """ + + STYLUS = "stylus" + """ + A pointer device with a stylus. + """ + + INVERTED_STYLUS = "invertedStylus" + """ + A pointer device with a stylus that has been inverted. + """ + + TRACKPAD = "trackpad" + """ + Gestures from a trackpad. + """ + + UNKNOWN = "unknown" + """ + An unknown pointer device. + """ + + +class StrokeCap(Enum): + """ + Styles to use for line endings. + """ + + ROUND = "round" + """ + Begin and end contours with a semi-circle extension. + """ + + SQUARE = "square" + """ + Begin and end contours with a half square extension. + """ + + BUTT = "butt" + """ + Begin and end contours with a flat edge and no extension. + """ + + +class StrokeJoin(Enum): + """ + Styles to use for line segment joins. + """ + + MITER = "miter" + """ + Joins between line segments form sharp corners. + """ + + ROUND = "round" + """ + Joins between line segments are semi-circular. + """ + + BEVEL = "bevel" + """ + Joins between line segments connect the corners of the butt ends of the line \ + segments to give a beveled appearance. + """ + + +class VisualDensity(Enum): + """ + Defines the visual density of user interface components. + """ + + STANDARD = "standard" + """ + The default/standard profile for visual density. + + This default value represents a visual density that is less dense than + either :attr:`COMFORTABLE` or :attr:`COMPACT`, and corresponds to + density values of zero in both axes. + """ + + COMPACT = "compact" + """ + The profile for a "compact" interpretation of visual density. + + Individual components will interpret the density value independently, making + themselves more visually dense than :attr:`STANDARD` and :attr:`COMFORTABLE` to + different degrees based on the Material Design specification of the + :attr:`COMFORTABLE` setting for their particular use case. + + It corresponds to a density value of `-2` in both axes. + """ + + COMFORTABLE = "comfortable" + """ + The profile for a "comfortable" interpretation of visual density. + + Individual + components will interpret the density value independently, making themselves more + visually dense than :attr:`STANDARD` and less dense than :attr:`COMPACT` + to different degrees based on the Material Design specification of the + comfortable setting for their particular use case. + + It corresponds to a density value of `-1` in both axes. + """ + + ADAPTIVE_PLATFORM_DENSITY = "adaptivePlatformDensity" + """ + Visual density that is adaptive based on the given platform. + + For desktop platforms, this returns :attr:`COMPACT`, and for other platforms, + it returns a default-constructed visual density. + """ + + +@value +class Locale: + """ + An identifier used to select a user's language and formatting preferences. + """ + + language_code: str = "und" + """ + The primary language subtag/code of the locale, e.g `en` for English. + + Its value is case-sensitive and must be a registered subtag in the + [IANA Language Subtag Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry) + with the type "language". If you use a deprecated subtag, it will be internally + modified to its “Preferred-Value”, if it has one. For example: `Locale("he")` + and `Locale("iw")` are equal, and both have the `language_code="he”`, + because `iw` is a deprecated language subtag which has been replaced by `he`. + + When there is no language subtag, this parameter should be set + to `"und"` (the default), which represents an undefined language code. + """ # noqa: E501 + + country_code: Optional[str] = None + """ + The country code or region subtag of the locale, e.g `US` for the United States. + + Its value is case-sensitive and must be a registered subtag in the + [IANA Language Subtag Registry](https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry) + with the type "region". If you use a deprecated subtag, it will be internally + modified to its “Preferred-Value”, if it has one. For example: `Locale("de", "DE")` + and `Locale("de", "DD")` are equal, and both have the `country_code="DE”`, + because `DD` is a deprecated region subtag which has been replaced by `DE`. + + Locales may also be defined without this, to specify a generic fallback for a + particular script. + """ # noqa: E501 + + script_code: Optional[str] = None + """ + The script code/subtag of the locale, e.g. `Hant` for Traditional Chinese or \ + `Hans` for Simplified Chinese. It is especially recommended to set this property \ + explicitly for languages with more than one script. + + Its value must be a valid Unicode Language Identifier script subtag as listed in + [Unicode CLDR supplemental + data](https://github.com/unicode-org/cldr/blob/master/common/validity/script.xml). + """ # noqa: E501 + + def __post_init__(self): + if self.language_code == "": + raise ValueError("language_code cannot be empty") + + @property + def language_tag(self) -> str: + """ + Returns a syntactically valid Unicode BCP47 Locale Identifier. + + See [this](https://www.unicode.org/reports/tr35) for technical details. + + Examples: `en`, `es-419`, `hi-Deva-IN`, `zh-Hans-CN` + """ + return self._raw_to_string("-") + + def __str__(self) -> str: + return self._raw_to_string("_") + + def _raw_to_string(self, separator: str) -> str: + """Returns the locale identifier joined by the given separator. + + Components are ordered as language, script (if any), and country + (if any). Empty or `None` values are omitted. + + Args: + separator: String used to join the subtags. + + Returns: + The formatted locale identifier. + """ + out_parts: list[str] = [self.language_code] + + if self.script_code is not None and self.script_code != "": + out_parts.append(self.script_code) + + if self.country_code is not None and self.country_code != "": + out_parts.append(self.country_code) + + return separator.join(out_parts) + + +@value +class LocaleConfiguration: + """ + Represents the configuration for supported locales and the current locale. + """ + + supported_locales: list[Locale] = field( + default_factory=lambda: [Locale("en", "US")] + ) + """ + A list of locales that the application supports for localization. + + Note: + - Locales unsupported/invalid are ignored. + - Order matters: Locale resolution is performed by progressively relaxing + specificity until a match is found. Matching is attempted in the following + priority order: + + 1. language + script + country + 2. language + script + 3. language + country + 4. language only + 5. country only (only if no language-based match is found) + + When multiple supported locales match at the same priority level, + the first matching locale in `supported_locales` is selected. + If no supported locale matches at any level, the first entry in + `supported_locales` is used as the final fallback. + - For languages with multiple scripts or regional variants, include locales in + increasing order of specificity: language-only → language+script → + language+script+country. Defining all of these variants is not strictly + required, but doing so greatly improves locale resolution and reduces + ambiguous matches. Omitting intermediate fallbacks can lead to incorrect + script or regional selection in edge cases—for example, a Simplified + Chinese user in Taiwan (`zh_Hans_TW`) may incorrectly resolve to + Traditional Chinese if `zh_Hans` and `zh_Hans_CN` are not present. + + Example: Full Chinese support for CN (Mainland China), TW (Taiwan), and HK (Hong + Kong) + ```python + supported_locales = [ + # Generic Chinese (fallback for all Chinese variants) + Locale(language_code="zh"), + + # Script-level variants + Locale(language_code="zh", script_code="Hans"), # Simplified Chinese zh_Hans + Locale(language_code="zh", script_code="Hant"), # Traditional Chinese + zh_Hant + + # Region-specific variants + Locale(language_code="zh", script_code="Hans", country_code="CN"), # + zh_Hans_CN + Locale(language_code="zh", script_code="Hant", country_code="TW"), # + zh_Hant_TW + Locale(language_code="zh", script_code="Hant", country_code="HK"), # + zh_Hant_HK + ] + ``` + """ # noqa: E501 + + current_locale: Optional[Locale] = None + """ + The current locale. + + Note: + - Must be an item of :attr:`supported_locales` to take effect. + - If `None` or invalid/unsupported, the first supported locale in + :attr:`supported_locales` is used. + """ + + def __post_init__(self) -> None: + if not self.supported_locales: + raise ValueError( + "supported_locales must contain at least one locale, " + "as the first entry is used as the final fallback." + ) + + +# Colors +ColorValue = Union[str, Colors, CupertinoColors] +"""Type alias for color values. + +Represents a color and can be: +- a string (representing a color name or hex value), +- a material color from the :class:`~flet.Colors` enum, +- or a Cupertino color from the :class:`~flet.CupertinoColors` enum. + +More information [here](https://flet.dev/docs/cookbook/cookbook/cookbook/colors). +""" + +# Icons +IconDataOrControl = Union[IconData, "Control"] +"""Type alias for icon-like values. + +Represents either: +- an :class:`~flet.IconData` value + (for example, a member of :class:`~flet.Icons` or :class:`~flet.CupertinoIcons`), +- or a custom icon :class:`~flet.Control`. +""" + +# Content +StrOrControl = Union[str, "Control"] +""" +Type alias for string or control values. + +Represents a string or a control and can be: +- a string, which will be converted internally into a :class:`~flet.Text` control, +- or a control. +""" + +# Wrapper +Wrapper = Callable[..., Any] + + +# Protocols +class SupportsStr(Protocol): + """ + Structural protocol for objects that provide a string representation. + """ + + def __str__(self) -> str: ... diff --git a/sdk/python/packages/flet/src/flet/controls/value_types.py b/sdk/python/packages/flet/src/flet/controls/value_types.py new file mode 100644 index 0000000000..934c1db1c0 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/controls/value_types.py @@ -0,0 +1,206 @@ +""" +Lightweight module for the `@value` decorator and related helpers. + +Kept separate from `base_control` to avoid circular imports: value types +(Duration, Alignment, etc.) need `@value` but are imported transitively by +`base_control` itself. +""" + +import dataclasses +import sys +from dataclasses import dataclass +from typing import Any, Optional + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + +__all__ = [ + "Prop", + "Value", + "value", +] + +_UNSET = object() +"""Sentinel for "field not yet in _values" (distinct from None).""" + + +class Prop: + """ + Descriptor for sparse property tracking on `BaseControl` and `Value` + types. + + Each public, non-skip field gets replaced by a `Prop` instance by + `_install_props()`. The descriptor stores only *non-default* values in + `obj._values`, so the frozen diff fast-path only needs to examine the + union of keys from two objects' `_values` dicts rather than scanning + every declared field. + """ + + __slots__ = ("name", "default") + + def __init__(self, name: str, default: Any = _UNSET) -> None: + self.name = name + self.default = default + + def __get__(self, obj: Any, objtype: Any = None) -> Any: + if obj is None: + # Class-level access: return the declared default, matching + # plain @dataclass field behaviour (e.g. TextTheme.display_small + # returns None, not the Prop descriptor). + return self.default if self.default is not _UNSET else self + return obj._values.get(self.name, self.default) + + def __set__(self, obj: Any, value: Any) -> None: + vals = obj._values + old = vals.get(self.name, _UNSET) + # Suppress storing the declared default during construction so + # that _values only holds genuinely non-default values. + if old is _UNSET and value == self.default: + return + if old is not _UNSET and old == value: + return # no change — skip everything + # Frozen controls must not be mutated after construction. + if hasattr(obj, "_frozen"): + raise RuntimeError("Frozen controls cannot be updated.") from None + if value == self.default: + vals.pop(self.name, None) # restore sparseness when back to default + else: + vals[self.name] = value + obj._dirty[self.name] = None + if hasattr(obj, "_notify"): + obj._notify(self.name, value) + + +def _get_raw_descriptor(cls: type, name: str) -> Any: + """Return the raw descriptor for *name* from cls or its MRO without + triggering `__get__`, so we always get the `Prop` object itself.""" + for klass in cls.__mro__: + if name in vars(klass): + return vars(klass)[name] + return None + + +def _install_props(cls: type) -> None: + """ + Replace public dataclass fields with `Prop` descriptors and record + non-Prop fields in `cls._structural_fields`. + """ + structural: set[str] = set() + prop_defaults: dict = {} + event_fields: set[str] = set() + root_defaults: dict = {} + override_props: dict = {} + + for f in dataclasses.fields(cls): + if f.metadata.get("skip", False): + continue + can_use_prop = ( + not f.name.startswith("_") + and f.init is not False + and f.default_factory is dataclasses.MISSING # type: ignore[misc] + ) + if can_use_prop: + if not isinstance(_get_raw_descriptor(cls, f.name), Prop): + default = f.default if f.default is not dataclasses.MISSING else _UNSET + setattr(cls, f.name, Prop(name=f.name, default=default)) + prop = _get_raw_descriptor(cls, f.name) + prop_defaults[f.name] = prop.default + + if f.name.startswith("on_") and f.metadata.get("event", True): + event_fields.add(f.name) + + root_default = _UNSET + for base in reversed(cls.__mro__): + base_dc_fields = getattr(base, "__dataclass_fields__", None) + if base_dc_fields and f.name in base_dc_fields: + bf = base_dc_fields[f.name] + if bf.default is not dataclasses.MISSING: + root_default = bf.default + break + root_defaults[f.name] = root_default + + if ( + prop.default is not _UNSET + and root_default is not _UNSET + and prop.default != root_default + ): + override_props[f.name] = prop.default + else: + structural.add(f.name) + + cls._structural_fields = frozenset(structural) # type: ignore[attr-defined] + cls._prop_defaults = prop_defaults # type: ignore[attr-defined] + cls._event_fields = frozenset(event_fields) # type: ignore[attr-defined] + cls._root_defaults = root_defaults # type: ignore[attr-defined] + cls._override_props = override_props # type: ignore[attr-defined] + + +class _ValueMeta(type): + def __instancecheck__(cls, instance: Any) -> bool: + return cls.__subclasscheck__(type(instance)) + + def __subclasscheck__(cls, subclass: type) -> bool: + return bool(getattr(subclass, "_is_flet_value", False)) + + +class Value(metaclass=_ValueMeta): + """ + Marker class for non-control value types that have sparse `_values` + tracking enabled via `@value`. + + `@value` handles all setup — you never need to inherit from this + class explicitly. It is exposed so that `isinstance(obj, Value)` + checks work in the diff machinery. + """ + + +@dataclass_transform() +def value( + cls: Optional[type] = None, + **dataclass_kwargs: Any, +) -> Any: + """ + Decorator for non-control value types to enable sparse `_values` + tracking. + + Applies `@dataclass` (passing *dataclass_kwargs*) and installs `Prop` + descriptors via `_install_props`. No base class is required — the + decorator wraps `__init__` to inject `_values` and `_dirty` before + the first `Prop.__set__` call, and registers the class as a + `Value` subclass for isinstance checks. + + Usage:: + + @value + class TextStyle: + color: Optional[str] = None + size: Optional[float] = None + + + # or with explicit dataclass kwargs: + @value(eq=False) + class TextStyle: ... + """ + + def _apply(cls: type) -> type: + cls = dataclass(**dataclass_kwargs)(cls) + _install_props(cls) + cls._is_flet_value = True + + orig_init = cls.__init__ + + def _value_init(self: Any, *args: Any, **kwargs: Any) -> None: + object.__setattr__(self, "_values", {}) + object.__setattr__(self, "_dirty", {}) + orig_init(self, *args, **kwargs) + self._dirty.clear() # reset after construction + + cls.__init__ = _value_init + + return cls + + if cls is not None: + return _apply(cls) + return _apply diff --git a/sdk/python/packages/flet/src/flet/core/adaptive_control.py b/sdk/python/packages/flet/src/flet/core/adaptive_control.py deleted file mode 100644 index 0361f8d944..0000000000 --- a/sdk/python/packages/flet/src/flet/core/adaptive_control.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Optional - -from flet.core.control import Control - - -class AdaptiveControl(Control): - def __init__(self, adaptive: Optional[bool] = None): - self.adaptive = adaptive - - # adaptive - @property - def adaptive(self) -> bool: - return self._get_attr("adaptive", data_type="bool", def_value=False) - - @adaptive.setter - def adaptive(self, value: Optional[bool]): - self._set_attr("adaptive", value) diff --git a/sdk/python/packages/flet/src/flet/core/ads/banner.py b/sdk/python/packages/flet/src/flet/core/ads/banner.py deleted file mode 100644 index 9a087b7a26..0000000000 --- a/sdk/python/packages/flet/src/flet/core/ads/banner.py +++ /dev/null @@ -1,116 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.ads.base_ad import BaseAd -from flet.core.animation import AnimationValue -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils import deprecated - - -@deprecated( - reason="BannerAd control has been moved to a separate Python package: https://pypi.org/project/flet-ads. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class BannerAd(BaseAd): - """ - Displays a banner ad. - - ----- - - Online docs: https://flet.dev/docs/controls/bannerad - """ - - def __init__( - self, - unit_id: str, - on_load: OptionalControlEventCallable = None, - on_error: OptionalControlEventCallable = None, - on_open: OptionalControlEventCallable = None, - on_close: OptionalControlEventCallable = None, - on_impression: OptionalControlEventCallable = None, - on_click: OptionalControlEventCallable = None, - on_will_dismiss: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: AnimationValue = None, - animate_size: AnimationValue = None, - animate_position: AnimationValue = None, - animate_rotation: AnimationValue = None, - animate_scale: AnimationValue = None, - animate_offset: AnimationValue = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[str] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - BaseAd.__init__( - self, - unit_id=unit_id, - on_load=on_load, - on_error=on_error, - on_open=on_open, - on_close=on_close, - on_impression=on_impression, - on_click=on_click, - on_will_dismiss=on_will_dismiss, - # - # ConstrainedControl - # - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - def _get_control_name(self): - return "banner_ad" diff --git a/sdk/python/packages/flet/src/flet/core/ads/base_ad.py b/sdk/python/packages/flet/src/flet/core/ads/base_ad.py deleted file mode 100644 index 68ece61c52..0000000000 --- a/sdk/python/packages/flet/src/flet/core/ads/base_ad.py +++ /dev/null @@ -1,174 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - PagePlatform, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class BaseAd(ConstrainedControl): - def __init__( - self, - unit_id: str, - on_load: OptionalControlEventCallable = None, - on_error: OptionalControlEventCallable = None, - on_open: OptionalControlEventCallable = None, - on_close: OptionalControlEventCallable = None, - on_impression: OptionalControlEventCallable = None, - on_click: OptionalControlEventCallable = None, - on_will_dismiss: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: AnimationValue = None, - animate_size: AnimationValue = None, - animate_position: AnimationValue = None, - animate_rotation: AnimationValue = None, - animate_scale: AnimationValue = None, - animate_offset: AnimationValue = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[str] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - self.on_load = on_load - self.on_error = on_error - self.on_open = on_open - self.on_close = on_close - self.on_impression = on_impression - self.on_click = on_click - self.on_will_dismiss = on_will_dismiss - self.unit_id = unit_id - - def before_update(self): - assert self.page.platform in [ - PagePlatform.ANDROID, - PagePlatform.IOS, - ], f"{self.__class__.__name__} is only supported on Mobile (Android and iOS). " - - @property - def unit_id(self) -> str: - return self._get_attr("unitId") - - @unit_id.setter - def unit_id(self, value: str): - self._set_attr("unitId", value) - - # on_load - @property - def on_load(self): - return self._get_event_handler("load") - - @on_load.setter - def on_load(self, handler): - self._add_event_handler("load", handler) - - # on_error - @property - def on_error(self): - return self._get_event_handler("error") - - @on_error.setter - def on_error(self, handler): - self._add_event_handler("error", handler) - - # on_open - @property - def on_open(self): - return self._get_event_handler("open") - - @on_open.setter - def on_open(self, handler): - self._add_event_handler("open", handler) - - # on_close - @property - def on_close(self): - return self._get_event_handler("close") - - @on_close.setter - def on_close(self, handler): - self._add_event_handler("close", handler) - - # on_click - @property - def on_click(self): - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler): - self._add_event_handler("click", handler) - - # on_impression - @property - def on_impression(self): - return self._get_event_handler("impression") - - @on_impression.setter - def on_impression(self, handler): - self._add_event_handler("impression", handler) - - # on_will_dismiss - @property - def on_will_dismiss(self): - return self._get_event_handler("willDismiss") - - @on_will_dismiss.setter - def on_will_dismiss(self, handler): - self._add_event_handler("willDismiss", handler) diff --git a/sdk/python/packages/flet/src/flet/core/ads/interstitial.py b/sdk/python/packages/flet/src/flet/core/ads/interstitial.py deleted file mode 100644 index 35f46dace4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/ads/interstitial.py +++ /dev/null @@ -1,117 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.ads.base_ad import BaseAd -from flet.core.animation import AnimationValue -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils import deprecated - - -@deprecated( - reason="InterstitialAd control has been moved to a separate Python package: https://pypi.org/project/flet-ads. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class InterstitialAd(BaseAd): - """ - Displays a full screen interstitial ad. - - ----- - - Online docs: https://flet.dev/docs/controls/interstitialad - """ - - def __init__( - self, - unit_id: str, - on_load: OptionalControlEventCallable = None, - on_error: OptionalControlEventCallable = None, - on_open: OptionalControlEventCallable = None, - on_close: OptionalControlEventCallable = None, - on_impression: OptionalControlEventCallable = None, - on_click: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: AnimationValue = None, - animate_size: AnimationValue = None, - animate_position: AnimationValue = None, - animate_rotation: AnimationValue = None, - animate_scale: AnimationValue = None, - animate_offset: AnimationValue = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[str] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - BaseAd.__init__( - self, - unit_id=unit_id, - on_load=on_load, - on_error=on_error, - on_open=on_open, - on_close=on_close, - on_impression=on_impression, - on_click=on_click, - # - # ConstrainedControl - # - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - def _get_control_name(self): - return "interstitial_ad" - - def show(self): - self.invoke_method("show") diff --git a/sdk/python/packages/flet/src/flet/core/ads/native.py b/sdk/python/packages/flet/src/flet/core/ads/native.py deleted file mode 100644 index 929b851a85..0000000000 --- a/sdk/python/packages/flet/src/flet/core/ads/native.py +++ /dev/null @@ -1,170 +0,0 @@ -import dataclasses -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.ads.base_ad import BaseAd -from flet.core.animation import AnimationValue -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.types import OffsetValue, ResponsiveNumber, RotateValue, ScaleValue - - -class NativeAdTemplateType(Enum): - SMALL = "small" - MEDIUM = "medium" - - -class NativeTemplateFontStyle(Enum): - NORMAL = "normal" - BOLD = "bold" - ITALIC = "italic" - MONOSPACE = "monospace" - - -@dataclasses.dataclass -class NativeAdTemplateTextStyle: - size: OptionalNumber = dataclasses.field(default=None) - text_color: Optional[str] = dataclasses.field(default=None) - bgcolor: Optional[str] = dataclasses.field(default=None) - style: Optional[NativeTemplateFontStyle] = dataclasses.field(default=None) - - -@dataclasses.dataclass -class NativeAdTemplateStyle: - template_type: Optional[NativeAdTemplateType] = dataclasses.field(default=None) - main_bgcolor: Optional[str] = dataclasses.field(default=None) - corner_radius: OptionalNumber = dataclasses.field(default=None) - call_to_action_text_style: Optional[NativeAdTemplateTextStyle] = dataclasses.field( - default=None - ) - primary_text_style: Optional[NativeAdTemplateTextStyle] = dataclasses.field( - default=None - ) - secondary_text_style: Optional[NativeAdTemplateTextStyle] = dataclasses.field( - default=None - ) - tertiary_text_style: Optional[NativeAdTemplateTextStyle] = dataclasses.field( - default=None - ) - - -class NativeAd(BaseAd): - """ - TBA - - ----- - - Online docs: https://flet.dev/docs/controls/nativead - """ - - def __init__( - self, - unit_id: str = None, - factory_id: str = None, - template_style: NativeAdTemplateStyle = None, - on_load=None, - on_error=None, - on_open=None, - on_close=None, - on_impression=None, - on_click=None, - on_will_dismiss=None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: AnimationValue = None, - animate_size: AnimationValue = None, - animate_position: AnimationValue = None, - animate_rotation: AnimationValue = None, - animate_scale: AnimationValue = None, - animate_offset: AnimationValue = None, - on_animation_end=None, - tooltip: Optional[str] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - BaseAd.__init__( - self, - unit_id=unit_id, - on_load=on_load, - on_error=on_error, - on_open=on_open, - on_close=on_close, - on_impression=on_impression, - on_click=on_click, - on_will_dismiss=on_will_dismiss, - # - # ConstrainedControl - # - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - self.template_style = template_style - self.factory_id = factory_id - - def _get_control_name(self): - return "native_ad" - - def before_update(self): - super().before_update() - self._set_attr_json("templateStyle", self.__template_style) - - @property - def template_style(self): - return self.__template_style - - @template_style.setter - def template_style(self, value): - self.__template_style = value - - # factory_id - @property - def factory_id(self) -> Optional[str]: - return self._get_attr("factoryId") - - @factory_id.setter - def factory_id(self, value: Optional[str]): - self._set_attr("factoryId", value) diff --git a/sdk/python/packages/flet/src/flet/core/alert_dialog.py b/sdk/python/packages/flet/src/flet/core/alert_dialog.py deleted file mode 100644 index 24e8e29a98..0000000000 --- a/sdk/python/packages/flet/src/flet/core/alert_dialog.py +++ /dev/null @@ -1,445 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alignment import Alignment -from flet.core.buttons import OutlinedBorder -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - MainAxisAlignment, - OptionalControlEventCallable, - PaddingValue, -) - - -class AlertDialog(AdaptiveControl): - """ - An alert dialog informs the user about situations that require acknowledgement. An alert dialog has an optional title and an optional list of actions. The title is displayed above the content and the actions are displayed below the content. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.title = "AlertDialog examples" - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - dlg = ft.AlertDialog( - title=ft.Text("Hi, this is a non-modal dialog!"), - on_dismiss=lambda e: page.add(ft.Text("Non-modal dialog dismissed")), - ) - - def handle_close(e): - page.close(dlg_modal) - page.add(ft.Text(f"Modal dialog closed with action: {e.control.text}")) - - dlg_modal = ft.AlertDialog( - modal=True, - title=ft.Text("Please confirm"), - content=ft.Text("Do you really want to delete all those files?"), - actions=[ - ft.TextButton("Yes", on_click=handle_close), - ft.TextButton("No", on_click=handle_close), - ], - actions_alignment=ft.MainAxisAlignment.END, - on_dismiss=lambda e: page.add( - ft.Text("Modal dialog dismissed"), - ), - ) - - page.add( - ft.ElevatedButton("Open dialog", on_click=lambda e: page.open(dlg)), - ft.ElevatedButton("Open modal dialog", on_click=lambda e: page.open(dlg_modal)), - ) - - - ft.app(target=main) - ``` - ----- - - Online docs: https://flet.dev/docs/controls/alertdialog - """ - - def __init__( - self, - modal: bool = False, - title: Optional[Union[Control, str]] = None, - content: Optional[Control] = None, - actions: Optional[List[Control]] = None, - bgcolor: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - icon: Optional[Control] = None, - open: bool = False, - title_padding: Optional[PaddingValue] = None, - content_padding: Optional[PaddingValue] = None, - actions_padding: Optional[PaddingValue] = None, - actions_alignment: Optional[MainAxisAlignment] = None, - shape: Optional[OutlinedBorder] = None, - inset_padding: Optional[PaddingValue] = None, - icon_padding: Optional[PaddingValue] = None, - action_button_padding: Optional[PaddingValue] = None, - surface_tint_color: Optional[ColorValue] = None, - shadow_color: Optional[ColorValue] = None, - icon_color: Optional[ColorValue] = None, - scrollable: Optional[bool] = None, - actions_overflow_button_spacing: OptionalNumber = None, - alignment: Optional[Alignment] = None, - content_text_style: Optional[TextStyle] = None, - title_text_style: Optional[TextStyle] = None, - clip_behavior: Optional[ClipBehavior] = None, - semantics_label: Optional[str] = None, - barrier_color: Optional[ColorValue] = None, - on_dismiss: OptionalControlEventCallable = None, - # - # AdaptiveControl - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.open = open - self.bgcolor = bgcolor - self.elevation = elevation - self.icon = icon - self.modal = modal - self.title = title - self.title_padding = title_padding - self.content = content - self.content_padding = content_padding - self.actions = actions - self.actions_padding = actions_padding - self.actions_alignment = actions_alignment - self.shape = shape - self.inset_padding = inset_padding - self.semantics_label = semantics_label - self.on_dismiss = on_dismiss - self.clip_behavior = clip_behavior - self.action_button_padding = action_button_padding - self.shadow_color = shadow_color - self.surface_tint_color = surface_tint_color - self.icon_padding = icon_padding - self.icon_color = icon_color - self.scrollable = scrollable - self.actions_overflow_button_spacing = actions_overflow_button_spacing - self.alignment = alignment - self.content_text_style = content_text_style - self.title_text_style = title_text_style - self.barrier_color = barrier_color - - def _get_control_name(self): - return "alertdialog" - - def before_update(self): - super().before_update() - assert ( - self.__title or self.__content or self.__actions - ), "AlertDialog has nothing to display. Provide at minimum one of the following: title, content, actions" - self._set_attr_json("actionsPadding", self.__actions_padding) - self._set_attr_json("contentPadding", self.__content_padding) - self._set_attr_json("titlePadding", self.__title_padding) - self._set_attr_json("shape", self.__shape) - self._set_attr_json("insetPadding", self.__inset_padding) - self._set_attr_json("iconPadding", self.__icon_padding) - self._set_attr_json("actionButtonPadding", self.__action_button_padding) - self._set_attr_json("alignment", self.__alignment) - if isinstance(self.__content_text_style, TextStyle): - self._set_attr_json("contentTextStyle", self.__content_text_style) - if isinstance(self.__title_text_style, TextStyle): - self._set_attr_json("titleTextStyle", self.__title_text_style) - - def _get_children(self): - children = [] - if isinstance(self.__title, Control): - self.__title._set_attr_internal("n", "title") - children.append(self.__title) - if self.__icon: - self.__icon._set_attr_internal("n", "icon") - children.append(self.__icon) - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - for action in self.__actions: - action._set_attr_internal("n", "action") - children.append(action) - return children - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # barrier_color - @property - def barrier_color(self) -> Optional[ColorValue]: - return self.__barrier_color - - @barrier_color.setter - def barrier_color(self, value: Optional[ColorValue]): - self.__barrier_color = value - self._set_enum_attr("barrierColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation", data_type="float") - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # actions_overflow_button_spacing - @property - def actions_overflow_button_spacing(self) -> OptionalNumber: - return self._get_attr("actionsOverflowButtonSpacing", data_type="float") - - @actions_overflow_button_spacing.setter - def actions_overflow_button_spacing(self, value: OptionalNumber): - self._set_attr("actionsOverflowButtonSpacing", value) - - # scrollable - @property - def scrollable(self) -> bool: - return self._get_attr("scrollable", data_type="bool", def_value=False) - - @scrollable.setter - def scrollable(self, value: Optional[bool]): - self._set_attr("scrollable", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # content_text_style - @property - def content_text_style(self) -> Optional[TextStyle]: - return self.__content_text_style - - @content_text_style.setter - def content_text_style(self, value: Optional[TextStyle]): - self.__content_text_style = value - - # title_text_style - @property - def title_text_style(self) -> Optional[TextStyle]: - return self.__title_text_style - - @title_text_style.setter - def title_text_style(self, value: Optional[TextStyle]): - self.__title_text_style = value - - # modal - @property - def modal(self) -> bool: - return self._get_attr("modal", data_type="bool", def_value=False) - - @modal.setter - def modal(self, value: Optional[bool]): - self._set_attr("modal", value) - - # title - @property - def title(self) -> Optional[Union[Control, str]]: - return self.__title - - @title.setter - def title(self, value: Optional[Union[Control, str]]): - self.__title = value - if not isinstance(value, Control): - self._set_attr("title", value) - - # icon - @property - def icon(self) -> Optional[Control]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[Control]): - self.__icon = value - - # title_padding - @property - def title_padding(self) -> Optional[PaddingValue]: - return self.__title_padding - - @title_padding.setter - def title_padding(self, value: Optional[PaddingValue]): - self.__title_padding = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # content_padding - @property - def content_padding(self) -> Optional[PaddingValue]: - return self.__content_padding - - @content_padding.setter - def content_padding(self, value: Optional[PaddingValue]): - self.__content_padding = value - - # actions - @property - def actions(self) -> List[Control]: - return self.__actions - - @actions.setter - def actions(self, value: Optional[List[Control]]): - self.__actions = value if value is not None else [] - - # actions_padding - @property - def actions_padding(self) -> Optional[PaddingValue]: - return self.__actions_padding - - @actions_padding.setter - def actions_padding(self, value: Optional[PaddingValue]): - self.__actions_padding = value - - # actions_alignment - @property - def actions_alignment(self) -> Optional[MainAxisAlignment]: - return self.__actions_alignment - - @actions_alignment.setter - def actions_alignment(self, value: Optional[MainAxisAlignment]): - self.__actions_alignment = value - self._set_attr( - "actionsAlignment", - value.value if isinstance(value, MainAxisAlignment) else value, - ) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # inset_padding - @property - def inset_padding(self) -> Optional[PaddingValue]: - return self.__inset_padding - - @inset_padding.setter - def inset_padding(self, value: Optional[PaddingValue]): - self.__inset_padding = value - - # icon_padding - @property - def icon_padding(self) -> Optional[PaddingValue]: - return self.__icon_padding - - @icon_padding.setter - def icon_padding(self, value: Optional[PaddingValue]): - self.__icon_padding = value - - # action_button_padding - @property - def action_button_padding(self) -> Optional[PaddingValue]: - return self.__action_button_padding - - @action_button_padding.setter - def action_button_padding(self, value: Optional[PaddingValue]): - self.__action_button_padding = value - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet/src/flet/core/alignment.py b/sdk/python/packages/flet/src/flet/core/alignment.py deleted file mode 100644 index a3f969ef45..0000000000 --- a/sdk/python/packages/flet/src/flet/core/alignment.py +++ /dev/null @@ -1,25 +0,0 @@ -import dataclasses -from enum import Enum -from typing import Union - - -class Axis(Enum): - HORIZONTAL = "horizontal" - VERTICAL = "vertical" - - -@dataclasses.dataclass -class Alignment: - x: Union[float, int] - y: Union[float, int] - - -bottom_center = Alignment(0, 1) -bottom_left = Alignment(-1, 1) -bottom_right = Alignment(1, 1) -center = Alignment(0, 0) -center_left = Alignment(-1, 0) -center_right = Alignment(1, 0) -top_center = Alignment(0, -1) -top_left = Alignment(-1, -1) -top_right = Alignment(1, -1) diff --git a/sdk/python/packages/flet/src/flet/core/animated_switcher.py b/sdk/python/packages/flet/src/flet/core/animated_switcher.py deleted file mode 100644 index c45bdc0519..0000000000 --- a/sdk/python/packages/flet/src/flet/core/animated_switcher.py +++ /dev/null @@ -1,225 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.animation import AnimationCurve, AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - -TransitionValueString = Literal["fade", "rotation", "scale"] - - -class AnimatedSwitcherTransition(Enum): - FADE = "fade" - ROTATION = "rotation" - SCALE = "scale" - - -class AnimatedSwitcher(ConstrainedControl): - """ - A control that by default does a cross-fade between a new control and the control previously set on the AnimatedSwitcher as a `content`. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - - c1 = ft.Container( - ft.Text("Hello!", style=ft.TextThemeStyle.HEADLINE_MEDIUM), - alignment=ft.alignment.center, - width=200, - height=200, - bgcolor=ft.colors.GREEN, - ) - c2 = ft.Container( - ft.Text("Bye!", size=50), - alignment=ft.alignment.center, - width=200, - height=200, - bgcolor=ft.colors.YELLOW, - ) - c = ft.AnimatedSwitcher( - content=c1, - transition=ft.AnimatedSwitcherTransition.SCALE, - duration=500, - reverse_duration=100, - switch_in_curve=ft.AnimationCurve.BOUNCE_OUT, - switch_out_curve=ft.AnimationCurve.BOUNCE_IN, - ) - - def animate(e): - c.content = c2 if c.content == c1 else c1 - c.update() - - page.add( - c, - ft.ElevatedButton("Animate!", on_click=animate), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/animatedswitcher - """ - - def __init__( - self, - content: Control, - duration: Optional[int] = None, - reverse_duration: Optional[int] = None, - switch_in_curve: Optional[AnimationCurve] = None, - switch_out_curve: Optional[AnimationCurve] = None, - transition: Optional[AnimatedSwitcherTransition] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - self.duration = duration - self.reverse_duration = reverse_duration - self.switch_in_curve = switch_in_curve - self.switch_out_curve = switch_out_curve - self.transition = transition - - def _get_control_name(self): - return "animatedswitcher" - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # duration - @property - def duration(self) -> int: - return self._get_attr("duration", data_type="int", def_value=1000) - - @duration.setter - def duration(self, value: Optional[int]): - self._set_attr("duration", value) - - # reverse_duration - @property - def reverse_duration(self) -> int: - return self._get_attr("reverseDuration", data_type="int", def_value=1000) - - @reverse_duration.setter - def reverse_duration(self, value: Optional[int]): - self._set_attr("reverseDuration", value) - - # switch_in_curve - @property - def switch_in_curve(self) -> Optional[AnimationCurve]: - return self.__switch_in_curve - - @switch_in_curve.setter - def switch_in_curve(self, value: Optional[AnimationCurve]): - self.__switch_in_curve = value - self._set_enum_attr("switchInCurve", value, AnimationCurve) - - # switch_out_curve - @property - def switch_out_curve(self) -> Optional[AnimationCurve]: - return self.__switch_out_curve - - @switch_out_curve.setter - def switch_out_curve(self, value: Optional[AnimationCurve]): - self.__switch_out_curve = value - self._set_enum_attr("switchOutCurve", value, AnimationCurve) - - # transition - @property - def transition(self) -> Optional[AnimatedSwitcherTransition]: - return self.__transition - - @transition.setter - def transition(self, value: Optional[AnimatedSwitcherTransition]): - self.__transition = value - self._set_enum_attr("transition", value, AnimatedSwitcherTransition) diff --git a/sdk/python/packages/flet/src/flet/core/animation.py b/sdk/python/packages/flet/src/flet/core/animation.py deleted file mode 100644 index 3f35fca9b1..0000000000 --- a/sdk/python/packages/flet/src/flet/core/animation.py +++ /dev/null @@ -1,80 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Optional, Union - -from flet.core.types import DurationValue -from flet.utils import deprecated - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class AnimationCurve(Enum): - BOUNCE_IN = "bounceIn" - BOUNCE_IN_OUT = "bounceInOut" - BOUNCE_OUT = "bounceOut" - DECELERATE = "decelerate" - EASE = "ease" - EASE_IN = "easeIn" - EASE_IN_BACK = "easeInBack" - EASE_IN_CIRC = "easeInCirc" - EASE_IN_CUBIC = "easeInCubic" - EASE_IN_EXPO = "easeInExpo" - EASE_IN_OUT = "easeInOut" - EASE_IN_OUT_BACK = "easeInOutBack" - EASE_IN_OUT_CIRC = "easeInOutCirc" - EASE_IN_OUT_CUBIC = "easeInOutCubic" - EASE_IN_OUT_CUBIC_EMPHASIZED = "easeInOutCubicEmphasized" - EASE_IN_OUT_EXPO = "easeInOutExpo" - EASE_IN_OUT_QUAD = "easeInOutQuad" - EASE_IN_OUT_QUART = "easeInOutQuart" - EASE_IN_OUT_QUINT = "easeInOutQuint" - EASE_IN_OUT_SINE = "easeInOutSine" - EASE_IN_QUAD = "easeInQuad" - EASE_IN_QUART = "easeInQuart" - EASE_IN_QUINT = "easeInQuint" - EASE_IN_SINE = "easeInSine" - EASE_IN_TO_LINEAR = "easeInToLinear" - EASE_OUT = "easeOut" - EASE_OUT_BACK = "easeOutBack" - EASE_OUT_CIRC = "easeOutCirc" - EASE_OUT_CUBIC = "easeOutCubic" - EASE_OUT_EXPO = "easeOutExpo" - EASE_OUT_QUAD = "easeOutQuad" - EASE_OUT_QUART = "easeOutQuart" - EASE_OUT_QUINT = "easeOutQuint" - EASE_OUT_SINE = "easeOutSine" - ELASTIC_IN = "elasticIn" - ELASTIC_IN_OUT = "elasticInOut" - ELASTIC_OUT = "elasticOut" - FAST_LINEAR_TO_SLOW_EASE_IN = "fastLinearToSlowEaseIn" - FAST_OUT_SLOWIN = "fastOutSlowIn" - LINEAR = "linear" - LINEAR_TO_EASE_OUT = "linearToEaseOut" - SLOW_MIDDLE = "slowMiddle" - - -@dataclass -class Animation: - duration: DurationValue = None - curve: Optional[AnimationCurve] = None - - -@dataclass -class AnimationStyle: - duration: Optional[DurationValue] = None - reverse_duration: Optional[DurationValue] = None - curve: Optional[AnimationCurve] = None - reverse_curve: Optional[AnimationCurve] = None - - -@deprecated( - reason="Use Animation class instead.", version="0.26.0", delete_version="0.29.0" -) -def implicit(duration: DurationValue, curve: Optional[AnimationCurve] = None): - return Animation(duration=duration, curve=curve) - - -AnimationValue = Union[bool, int, Animation] diff --git a/sdk/python/packages/flet/src/flet/core/app_bar.py b/sdk/python/packages/flet/src/flet/core/app_bar.py deleted file mode 100644 index 9853a16cdf..0000000000 --- a/sdk/python/packages/flet/src/flet/core/app_bar.py +++ /dev/null @@ -1,360 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.buttons import OutlinedBorder -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ClipBehavior, ColorEnums, ColorValue, OptionalNumber - - -class AppBar(AdaptiveControl): - """ - A material design app bar. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def check_item_clicked(e): - e.control.checked = not e.control.checked - page.update() - - page.appbar = ft.AppBar( - leading=ft.Icon(ft.icons.PALETTE), - leading_width=40, - title=ft.Text("AppBar Example"), - center_title=False, - bgcolor=ft.colors.SURFACE_VARIANT, - actions=[ - ft.IconButton(ft.icons.WB_SUNNY_OUTLINED), - ft.IconButton(ft.icons.FILTER_3), - ft.PopupMenuButton( - items=[ - ft.PopupMenuItem(text="Item 1"), - ft.PopupMenuItem(), # divider - ft.PopupMenuItem( - text="Checked item", checked=False, on_click=check_item_clicked - ), - ] - ), - ], - ) - page.add(ft.Text("Body!")) - - ft.app(target=main) - - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/appbar - """ - - def __init__( - self, - leading: Optional[Control] = None, - leading_width: OptionalNumber = None, - automatically_imply_leading: Optional[bool] = None, - title: Optional[Control] = None, - center_title: Optional[bool] = None, - toolbar_height: OptionalNumber = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - elevation_on_scroll: OptionalNumber = None, - shadow_color: Optional[ColorValue] = None, - surface_tint_color: Optional[ColorValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - force_material_transparency: Optional[bool] = None, - is_secondary: Optional[bool] = None, - title_spacing: OptionalNumber = None, - exclude_header_semantics: Optional[bool] = None, - actions: Optional[List[Control]] = None, - toolbar_opacity: OptionalNumber = None, - title_text_style: Optional[TextStyle] = None, - toolbar_text_style: Optional[TextStyle] = None, - shape: Optional[OutlinedBorder] = None, - # - # AdaptiveControl - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - adaptive: Optional[bool] = None, - ): - Control.__init__( - self, ref=ref, visible=visible, disabled=disabled, data=data, rtl=rtl - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.leading = leading - self.leading_width = leading_width - self.automatically_imply_leading = automatically_imply_leading - self.title = title - self.center_title = center_title - self.toolbar_height = toolbar_height - self.color = color - self.bgcolor = bgcolor - self.elevation = elevation - self.actions = actions - self.elevation_on_scroll = elevation_on_scroll - self.shadow_color = shadow_color - self.surface_tint_color = surface_tint_color - self.clip_behavior = clip_behavior - self.force_material_transparency = force_material_transparency - self.is_secondary = is_secondary - self.title_spacing = title_spacing - self.exclude_header_semantics = exclude_header_semantics - self.toolbar_opacity = toolbar_opacity - self.title_text_style = title_text_style - self.toolbar_text_style = toolbar_text_style - self.shape = shape - - def _get_control_name(self): - return "appbar" - - def before_update(self): - super().before_update() - if isinstance(self.__title_text_style, TextStyle): - self._set_attr_json("titleTextStyle", self.__title_text_style) - if isinstance(self.__toolbar_text_style, TextStyle): - self._set_attr_json("toolbarTextStyle", self.__toolbar_text_style) - if isinstance(self.__shape, OutlinedBorder): - self._set_attr_json("shape", self.__shape) - - def _get_children(self): - children = [] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__title: - self.__title._set_attr_internal("n", "title") - children.append(self.__title) - for action in self.__actions: - action._set_attr_internal("n", "action") - children.append(action) - return children - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - """ - A Control to display before the toolbar's title. - - Typically the leading control is an Icon or an IconButton. - """ - self.__leading = value - - # leading_width - @property - def leading_width(self) -> OptionalNumber: - return self._get_attr("leadingWidth") - - @leading_width.setter - def leading_width(self, value: OptionalNumber): - self._set_attr("leadingWidth", value) - - # title_spacing - @property - def title_spacing(self) -> OptionalNumber: - return self._get_attr("titleSpacing", data_type="float") - - @title_spacing.setter - def title_spacing(self, value: OptionalNumber): - self._set_attr("titleSpacing", value) - - # toolbar_opacity - @property - def toolbar_opacity(self) -> float: - return self._get_attr("toolbarOpacity", data_type="float", def_value=1.0) - - @toolbar_opacity.setter - def toolbar_opacity(self, value: OptionalNumber): - assert value is None or ( - 0 <= value <= 1 - ), "toolbar_opacity is out of range (0-1)" - self._set_attr("toolbarOpacity", value) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # title_text_style - @property - def title_text_style(self) -> Optional[TextStyle]: - return self.__title_text_style - - @title_text_style.setter - def title_text_style(self, value: Optional[TextStyle]): - self.__title_text_style = value - - # toolbar_text_style - @property - def toolbar_text_style(self) -> Optional[TextStyle]: - return self.__toolbar_text_style - - @toolbar_text_style.setter - def toolbar_text_style(self, value: Optional[TextStyle]): - self.__toolbar_text_style = value - - # automatically_imply_leading - @property - def automatically_imply_leading(self) -> bool: - return self._get_attr( - "automaticallyImplyLeading", data_type="bool", def_value=True - ) - - @automatically_imply_leading.setter - def automatically_imply_leading(self, value: Optional[bool]): - self._set_attr("automaticallyImplyLeading", value) - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # center_title - @property - def center_title(self) -> bool: - return self._get_attr("centerTitle", data_type="bool", def_value=False) - - @center_title.setter - def center_title(self, value: Optional[bool]): - self._set_attr("centerTitle", value) - - # toolbar_height - @property - def toolbar_height(self) -> OptionalNumber: - return self._get_attr("toolbarHeight") - - @toolbar_height.setter - def toolbar_height(self, value: OptionalNumber): - assert value is None or value >= 0, "toolbar_height cannot be negative" - self._set_attr("toolbarHeight", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # is_secondary - @property - def is_secondary(self) -> bool: - return self._get_attr("isSecondary", data_type="bool", def_value=False) - - @is_secondary.setter - def is_secondary(self, value: Optional[bool]): - self._set_attr("isSecondary", value) - - # exclude_header_semantics - @property - def exclude_header_semantics(self) -> bool: - return self._get_attr( - "excludeHeaderSemantics", data_type="bool", def_value=False - ) - - @exclude_header_semantics.setter - def exclude_header_semantics(self, value: Optional[bool]): - self._set_attr("excludeHeaderSemantics", value) - - # force_material_transparency - @property - def force_material_transparency(self) -> bool: - return self._get_attr( - "forceMaterialTransparency", data_type="bool", def_value=False - ) - - @force_material_transparency.setter - def force_material_transparency(self, value: Optional[bool]): - self._set_attr("forceMaterialTransparency", value) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation cannot be negative" - self._set_attr("elevation", value) - - # elevation_on_scroll - @property - def elevation_on_scroll(self) -> OptionalNumber: - return self._get_attr("elevationOnScroll") - - @elevation_on_scroll.setter - def elevation_on_scroll(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation_on_scroll cannot be negative" - self._set_attr("elevationOnScroll", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self._get_attr("clipBehavior") - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # actions - @property - def actions(self) -> Optional[List[Control]]: - return self.__actions - - @actions.setter - def actions(self, value: Optional[List[Control]]): - self.__actions = value if value is not None else [] diff --git a/sdk/python/packages/flet/src/flet/core/audio.py b/sdk/python/packages/flet/src/flet/core/audio.py deleted file mode 100644 index 0643a9a94e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/audio.py +++ /dev/null @@ -1,298 +0,0 @@ -from enum import Enum -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable, OptionalEventCallable -from flet.utils import deprecated - - -class ReleaseMode(Enum): - RELEASE = "release" - LOOP = "loop" - STOP = "stop" - - -class AudioState(Enum): - STOPPED = "stopped" - PLAYING = "playing" - PAUSED = "paused" - COMPLETED = "completed" - DISPOSED = "disposed" - - -class AudioStateChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.state: AudioState = AudioState(e.data) - - -class AudioPositionChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.position: int = int(e.data) - - -class AudioDurationChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.duration: int = int(e.data) - - -@deprecated( - reason="Audio control has been moved to a separate Python package: https://pypi.org/project/flet-audio. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Audio(Control): - """ - A control to simultaneously play multiple audio files. Works on macOS, Linux, Windows, iOS, Android and web. Based on audioplayers Flutter widget (https://pub.dev/packages/audioplayers). - - Audio control is non-visual and should be added to `page.overlay` list. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - audio1 = ft.Audio( - src="https://luan.xyz/files/audio/ambient_c_motion.mp3", autoplay=True - ) - page.overlay.append(audio1) - page.add( - ft.Text("This is an app with background audio."), - ft.ElevatedButton("Stop playing", on_click=lambda _: audio1.pause()), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/audio - """ - - def __init__( - self, - src: Optional[str] = None, - src_base64: Optional[str] = None, - autoplay: Optional[bool] = None, - volume: OptionalNumber = None, - balance: OptionalNumber = None, - playback_rate: OptionalNumber = None, - release_mode: Optional[ReleaseMode] = None, - on_loaded: OptionalControlEventCallable = None, - on_duration_changed: OptionalEventCallable[AudioDurationChangeEvent] = None, - on_state_changed: OptionalEventCallable[AudioStateChangeEvent] = None, - on_position_changed: OptionalEventCallable[AudioPositionChangeEvent] = None, - on_seek_complete: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - - self.__on_state_changed = EventHandler(lambda e: AudioStateChangeEvent(e)) - self._add_event_handler("state_changed", self.__on_state_changed.get_handler()) - - self.__on_position_changed = EventHandler(lambda e: AudioPositionChangeEvent(e)) - self._add_event_handler( - "position_changed", self.__on_position_changed.get_handler() - ) - - self.__on_duration_changed = EventHandler(lambda e: AudioDurationChangeEvent(e)) - self._add_event_handler( - "duration_changed", self.__on_duration_changed.get_handler() - ) - - self.src = src - self.src_base64 = src_base64 - self.autoplay = autoplay - self.volume = volume - self.balance = balance - self.playback_rate = playback_rate - self.release_mode = release_mode - self.on_loaded = on_loaded - self.on_duration_changed = on_duration_changed - self.on_state_changed = on_state_changed - self.on_position_changed = on_position_changed - self.on_seek_complete = on_seek_complete - - def _get_control_name(self): - return "audio" - - def play(self): - self.invoke_method("play") - - def pause(self): - self.invoke_method("pause") - - def resume(self): - self.invoke_method("resume") - - def release(self): - self.invoke_method("release") - - def seek(self, position_milliseconds: int): - self.invoke_method("seek", {"position": str(position_milliseconds)}) - - def get_duration(self, wait_timeout: Optional[float] = 5) -> Optional[int]: - sr = self.invoke_method( - "get_duration", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - async def get_duration_async( - self, wait_timeout: Optional[float] = 5 - ) -> Optional[int]: - sr = await self.invoke_method_async( - "get_duration", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - def get_current_position(self, wait_timeout: Optional[float] = 5) -> Optional[int]: - sr = self.invoke_method( - "get_current_position", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - async def get_current_position_async( - self, wait_timeout: Optional[float] = 5 - ) -> Optional[int]: - sr = await self.invoke_method_async( - "get_current_position", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - # src - @property - def src(self): - return self._get_attr("src") - - @src.setter - def src(self, value): - self._set_attr("src", value) - - # src_base64 - @property - def src_base64(self): - return self._get_attr("srcBase64") - - @src_base64.setter - def src_base64(self, value): - self._set_attr("srcBase64", value) - - # autoplay - @property - def autoplay(self) -> bool: - return self._get_attr("autoplay", data_type="bool", def_value=False) - - @autoplay.setter - def autoplay(self, value: Optional[bool]): - self._set_attr("autoplay", value) - - # volume - @property - def volume(self) -> OptionalNumber: - return self._get_attr("volume") - - @volume.setter - def volume(self, value: OptionalNumber): - if value is None or (0 <= value <= 1): - self._set_attr("volume", value) - - # balance - @property - def balance(self) -> OptionalNumber: - return self._get_attr("balance") - - @balance.setter - def balance(self, value: OptionalNumber): - if value is None or (-1 <= value <= 1): - self._set_attr("balance", value) - - # playback_rate - @property - def playback_rate(self) -> OptionalNumber: - return self._get_attr("playbackRate") - - @playback_rate.setter - def playback_rate(self, value: OptionalNumber): - if value is None or (0 <= value <= 2): - self._set_attr("playbackRate", value) - - # release_mode - @property - def release_mode(self): - return self._get_attr("releaseMode") - - @release_mode.setter - def release_mode(self, value: Optional[ReleaseMode]): - self._set_enum_attr("releaseMode", value, ReleaseMode) - - # on_loaded - @property - def on_loaded(self): - return self._get_event_handler("loaded") - - @on_loaded.setter - def on_loaded(self, handler: OptionalControlEventCallable): - self._add_event_handler("loaded", handler) - - # on_duration_changed - @property - def on_duration_changed(self): - return self.__on_duration_changed.handler - - @on_duration_changed.setter - def on_duration_changed( - self, handler: OptionalEventCallable[AudioDurationChangeEvent] - ): - self.__on_duration_changed.handler = handler - - # on_state_changed - @property - def on_state_changed(self): - return self.__on_state_changed.handler - - @on_state_changed.setter - def on_state_changed(self, handler: OptionalEventCallable[AudioStateChangeEvent]): - self.__on_state_changed.handler = handler - - # on_position_changed - @property - def on_position_changed(self): - return self.__on_position_changed.handler - - @on_position_changed.setter - def on_position_changed( - self, handler: OptionalEventCallable[AudioPositionChangeEvent] - ): - self.__on_position_changed.handler = handler - self._set_attr("onPositionChanged", True if handler is not None else None) - - # on_seek_complete - @property - def on_seek_complete(self): - return self._get_event_handler("seek_complete") - - @on_seek_complete.setter - def on_seek_complete(self, handler: OptionalControlEventCallable): - self._add_event_handler("seek_complete", handler) diff --git a/sdk/python/packages/flet/src/flet/core/audio_recorder.py b/sdk/python/packages/flet/src/flet/core/audio_recorder.py deleted file mode 100644 index 7fa256a60d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/audio_recorder.py +++ /dev/null @@ -1,314 +0,0 @@ -import json -from enum import Enum -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import OptionalEventCallable -from flet.utils import deprecated - - -class AudioRecorderState(Enum): - STOPPED = "stopped" - RECORDING = "recording" - PAUSED = "paused" - - -class AudioRecorderStateChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.state: AudioRecorderState = AudioRecorderState(e.data) - - -class AudioEncoder(Enum): - AACLC = "aacLc" - AACELD = "aacEld" - AACHE = "aacHe" - AMRNB = "amrNb" - AMRWB = "amrWb" - OPUS = "opus" - FLAC = "flac" - WAV = "wav" - PCM16BITS = "pcm16bits" - - -@deprecated( - reason="AudioRecorder control has been moved to a separate Python package: https://pypi.org/project/flet-audio-recorder. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class AudioRecorder(Control): - """ - A control that allows you to record audio from your device. - - ----- - - Online docs: https://flet.dev/docs/controls/audiorecorder - """ - - def __init__( - self, - audio_encoder: Optional[AudioEncoder] = None, - suppress_noise: Optional[bool] = None, - cancel_echo: Optional[bool] = None, - auto_gain: Optional[bool] = None, - channels_num: OptionalNumber = None, - sample_rate: OptionalNumber = None, - bit_rate: OptionalNumber = None, - on_state_changed: OptionalEventCallable[AudioRecorderStateChangeEvent] = None, - # - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - self.__on_state_changed = EventHandler( - lambda e: AudioRecorderStateChangeEvent(e) - ) - self._add_event_handler("state_changed", self.__on_state_changed.get_handler()) - - self.audio_encoder = audio_encoder - self.suppress_noise = suppress_noise - self.cancel_echo = cancel_echo - self.auto_gain = auto_gain - self.channels_num = channels_num - self.sample_rate = sample_rate - self.bit_rate = bit_rate - self.on_state_changed = on_state_changed - - def _get_control_name(self): - return "audiorecorder" - - def start_recording( - self, output_path: str = None, wait_timeout: Optional[float] = 10 - ) -> bool: - assert ( - self.page.web or output_path - ), "output_path must be provided when not on web" - started = self.invoke_method( - "start_recording", - {"outputPath": output_path}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return started == "true" - - async def start_recording_async( - self, output_path: str = None, wait_timeout: Optional[float] = 10 - ) -> bool: - assert ( - self.page.web or output_path - ), "output_path must be provided when not on web" - started = await self.invoke_method_async( - "start_recording", - {"outputPath": output_path}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return started == "true" - - def is_recording(self, wait_timeout: Optional[float] = 5) -> bool: - recording = self.invoke_method( - "is_recording", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return recording == "true" - - async def is_recording_async(self, wait_timeout: Optional[float] = 5) -> bool: - recording = await self.invoke_method_async( - "is_recording", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return recording == "true" - - def stop_recording(self, wait_timeout: Optional[float] = 5) -> Optional[str]: - return self.invoke_method( - "stop_recording", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - - async def stop_recording_async( - self, wait_timeout: Optional[float] = 10 - ) -> Optional[str]: - return await self.invoke_method_async( - "stop_recording", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - - def cancel_recording(self, wait_timeout: Optional[float] = 5) -> None: - self.invoke_method( - "cancel_recording", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - - def resume_recording(self): - self.invoke_method("resume_recording") - - def pause_recording(self): - self.invoke_method("pause_recording") - - def is_paused(self, wait_timeout: Optional[float] = 5) -> bool: - paused = self.invoke_method( - "is_paused", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return paused == "true" - - async def is_paused_async(self, wait_timeout: Optional[float] = 5) -> bool: - supported = await self.invoke_method_async( - "is_paused", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return supported == "true" - - def is_supported_encoder( - self, encoder: AudioEncoder, wait_timeout: Optional[float] = 5 - ) -> bool: - supported = self.invoke_method( - "is_supported_encoder", - { - "encoder": ( - encoder.value if isinstance(encoder, AudioEncoder) else encoder - ) - }, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return supported == "true" - - async def is_supported_encoder_async( - self, encoder: AudioEncoder, wait_timeout: Optional[float] = 5 - ) -> bool: - supported = await self.invoke_method_async( - "is_supported_encoder", - { - "encoder": ( - encoder.value if isinstance(encoder, AudioEncoder) else encoder - ) - }, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return supported == "true" - - def get_input_devices(self, wait_timeout: Optional[float] = 5) -> dict: - devices = self.invoke_method( - "get_input_devices", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return json.loads(devices) - - async def get_input_devices_async(self, wait_timeout: Optional[float] = 5) -> dict: - devices = await self.invoke_method_async( - "get_input_devices", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return json.loads(devices) - - def has_permission(self, wait_timeout: Optional[float] = 10) -> bool: - p = self.invoke_method( - "has_permission", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return p == "true" - - async def has_permission_async(self, wait_timeout: Optional[float] = 10) -> bool: - p = await self.invoke_method_async( - "has_permission", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return p == "true" - - # audio_encoder - @property - def audio_encoder(self): - return self._get_attr("audioEncoder") - - @audio_encoder.setter - def audio_encoder(self, value: Optional[AudioEncoder]): - self._set_enum_attr("audioEncoder", value, AudioEncoder) - - # suppress_noise - @property - def suppress_noise(self) -> bool: - return self._get_attr("suppressNoise", data_type="bool", def_value=False) - - @suppress_noise.setter - def suppress_noise(self, value: Optional[bool]): - self._set_attr("suppressNoise", value) - - # cancel_echo - @property - def cancel_echo(self) -> bool: - return self._get_attr("cancelEcho", data_type="bool", def_value=False) - - @cancel_echo.setter - def cancel_echo(self, value: Optional[bool]): - self._set_attr("cancelEcho", value) - - # auto_gain - @property - def auto_gain(self) -> bool: - return self._get_attr("autoGain", data_type="bool", def_value=False) - - @auto_gain.setter - def auto_gain(self, value: Optional[bool]): - self._set_attr("autoGain", value) - - # bit_rate - @property - def bit_rate(self) -> OptionalNumber: - return self._get_attr("bitRate") - - @bit_rate.setter - def bit_rate(self, value: OptionalNumber): - self._set_attr("bitRate", value) - - # sample_rate - @property - def sample_rate(self) -> OptionalNumber: - return self._get_attr("sampleRate") - - @sample_rate.setter - def sample_rate(self, value: OptionalNumber): - self._set_attr("sampleRate", value) - - # channels_num - @property - def channels_num(self) -> OptionalNumber: - return self._get_attr("channels") - - @channels_num.setter - def channels_num(self, value: OptionalNumber): - if value is None or value in (1, 2): - self._set_attr("channels", value) - - # on_state_changed - @property - def on_state_changed(self): - return self.__on_state_changed.handler - - @on_state_changed.setter - def on_state_changed( - self, handler: OptionalEventCallable[AudioRecorderStateChangeEvent] - ): - self.__on_state_changed.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/auto_complete.py b/sdk/python/packages/flet/src/flet/core/auto_complete.py deleted file mode 100644 index 24a67a6e55..0000000000 --- a/sdk/python/packages/flet/src/flet/core/auto_complete.py +++ /dev/null @@ -1,104 +0,0 @@ -import json -from dataclasses import dataclass, field -from typing import Any, List, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import OptionalEventCallable - - -@dataclass -class AutoCompleteSuggestion: - key: str = field(default=None) - value: str = field(default=None) - - -class AutoComplete(Control): - """ - Helps the user make a selection by entering some text and choosing from among a list of displayed options. - - ----- - - Online docs: https://flet.dev/docs/controls/autocomplete - """ - - def __init__( - self, - suggestions: Optional[List[AutoCompleteSuggestion]] = None, - suggestions_max_height: OptionalNumber = None, - on_select: OptionalEventCallable["AutoCompleteSelectEvent"] = None, - # - # Control - # - ref: Optional[Ref] = None, - opacity: OptionalNumber = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - opacity=opacity, - visible=visible, - data=data, - ) - - self.__on_select = EventHandler(lambda e: AutoCompleteSelectEvent(e)) - self._add_event_handler("select", self.__on_select.get_handler()) - - self.suggestions = suggestions - self.suggestions_max_height = suggestions_max_height - self.on_select = on_select - - def _get_control_name(self): - return "autocomplete" - - def before_update(self): - self._set_attr_json("suggestions", self.__suggestions) - - # selected_index - @property - def selected_index(self) -> Optional[int]: - return self._get_attr("selectedIndex", data_type="int") - - # suggestions_max_height - @property - def suggestions_max_height(self) -> float: - return self._get_attr( - "suggestionsMaxHeight", data_type="float", def_value=200.0 - ) - - @suggestions_max_height.setter - def suggestions_max_height(self, value: OptionalNumber): - assert value is None or value >= 0, "suggestions_max_height cannot be negative" - self._set_attr("suggestionsMaxHeight", value) - - # suggestions - @property - def suggestions(self) -> Optional[List[AutoCompleteSuggestion]]: - return self.__suggestions - - @suggestions.setter - def suggestions(self, value: Optional[List[str]]): - self.__suggestions = value or [] - - # on_select - @property - def on_select(self) -> OptionalEventCallable["AutoCompleteSelectEvent"]: - return self.__on_select.handler - - @on_select.setter - def on_select(self, handler: OptionalEventCallable["AutoCompleteSelectEvent"]): - self.__on_select.handler = handler - - -class AutoCompleteSelectEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.selection: AutoCompleteSuggestion = AutoCompleteSuggestion( - key=d.get("key"), value=d.get("value") - ) diff --git a/sdk/python/packages/flet/src/flet/core/autofill_group.py b/sdk/python/packages/flet/src/flet/core/autofill_group.py deleted file mode 100644 index c0da155067..0000000000 --- a/sdk/python/packages/flet/src/flet/core/autofill_group.py +++ /dev/null @@ -1,139 +0,0 @@ -from enum import Enum -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref - - -class AutofillHint(Enum): - ADDRESS_CITY = "addressCity" - ADDRESS_CITY_AND_STATE = "addressCityAndState" - ADDRESS_STATE = "addressState" - BIRTHDAY = "birthday" - BIRTHDAY_DAY = "birthdayDay" - BIRTHDAY_MONTH = "birthdayMonth" - BIRTHDAY_YEAR = "birthdayYear" - COUNTRY_CODE = "countryCode" - COUNTRY_NAME = "countryName" - CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate" - CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay" - CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth" - CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear" - CREDIT_CARD_FAMILY_NAME = "creditCardFamilyName" - CREDIT_CARD_GIVEN_NAME = "creditCardGivenName" - CREDIT_CARD_MIDDLE_NAME = "creditCardMiddleName" - CREDIT_CARD_NAME = "creditCardName" - CREDIT_CARD_NUMBER = "creditCardNumber" - CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode" - CREDIT_CARD_TYPE = "creditCardType" - EMAIL = "email" - FAMILY_NAME = "familyName" - FULL_STREET_ADDRESS = "fullStreetAddress" - GENDER = "gender" - GIVEN_NAME = "givenName" - IMPP = "impp" - JOB_TITLE = "jobTitle" - LANGUAGE = "language" - LOCATION = "location" - MIDDLE_INITIAL = "middleInitial" - MIDDLE_NAME = "middleName" - NAME = "name" - NAME_PREFIX = "namePrefix" - NAME_SUFFIX = "nameSuffix" - NEW_PASSWORD = "newPassword" - NEW_USERNAME = "newUsername" - NICKNAME = "nickname" - ONE_TIME_CODE = "oneTimeCode" - ORGANIZATION_NAME = "organizationName" - PASSWORD = "password" - PHOTO = "photo" - POSTAL_ADDRESS = "postalAddress" - POSTAL_ADDRESS_EXTENDED = "postalAddressExtended" - POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "postalAddressExtendedPostalCode" - POSTAL_CODE = "postalCode" - STREET_ADDRESS_LEVEL1 = "streetAddressLevel1" - STREET_ADDRESS_LEVEL2 = "streetAddressLevel2" - STREET_ADDRESS_LEVEL3 = "streetAddressLevel3" - STREET_ADDRESS_LEVEL4 = "streetAddressLevel4" - STREET_ADDRESS_LINE1 = "streetAddressLine1" - STREET_ADDRESS_LINE2 = "streetAddressLine2" - STREET_ADDRESS_LINE3 = "streetAddressLine3" - SUB_LOCALITY = "subLocality" - TELEPHONE_NUMBER = "telephoneNumber" - TELEPHONE_NUMBER_AREA_CODE = "telephoneNumberAreaCode" - TELEPHONE_NUMBER_COUNTRY_CODE = "telephoneNumberCountryCode" - TELEPHONE_NUMBER_DEVICE = "telephoneNumberDevice" - TELEPHONE_NUMBER_EXTENSION = "telephoneNumberExtension" - TELEPHONE_NUMBER_LOCAL = "telephoneNumberLocal" - TELEPHONE_NUMBER_LOCAL_PREFIX = "telephoneNumberLocalPrefix" - TELEPHONE_NUMBER_LOCAL_SUFFIX = "telephoneNumberLocalSuffix" - TELEPHONE_NUMBER_NATIONAL = "telephoneNumberNational" - TRANSACTION_AMOUNT = "transactionAmount" - TRANSACTION_CURRENCY = "transactionCurrency" - URL = "url" - USERNAME = "username" - - -class AutofillGroupDisposeAction(Enum): - COMMIT = "commit" - CANCEL = "cancel" - - -class AutofillGroup(Control): - """ - This control is used to group autofill controls together. - - ----- - - Online docs: https://flet.dev/docs/controls/autofillgroup - """ - - def __init__( - self, - content: Control = None, - dispose_action: Optional[AutofillGroupDisposeAction] = None, - # - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - data=data, - ) - - self.content = content - self.dispose_action = dispose_action - - def _get_control_name(self): - return "autofillgroup" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # dispose_action - @property - def dispose_action(self) -> Optional[AutofillGroupDisposeAction]: - return self.__dispose_action - - @dispose_action.setter - def dispose_action(self, value: Optional[AutofillGroupDisposeAction]): - self.__dispose_action = value - self._set_enum_attr("disposeAction", value, AutofillGroupDisposeAction) diff --git a/sdk/python/packages/flet/src/flet/core/badge.py b/sdk/python/packages/flet/src/flet/core/badge.py deleted file mode 100644 index fb3e65b5f1..0000000000 --- a/sdk/python/packages/flet/src/flet/core/badge.py +++ /dev/null @@ -1,26 +0,0 @@ -from dataclasses import dataclass -from typing import Optional, Union - -from flet.core.alignment import Alignment -from flet.core.text_style import TextStyle -from flet.core.types import ColorValue, OffsetValue, OptionalNumber, PaddingValue - - -@dataclass -class Badge: - """Badges are used to show notifications, counts, or status information on navigation items such as NavigationBar or NavigationRail destinations - or a button's icon.""" - - text: Optional[str] = None - offset: Optional[OffsetValue] = None - alignment: Optional[Alignment] = None - bgcolor: Optional[ColorValue] = None - label_visible: Optional[bool] = None - large_size: OptionalNumber = None - padding: Optional[PaddingValue] = None - small_size: OptionalNumber = None - text_color: Optional[ColorValue] = None - text_style: Optional[TextStyle] = None - - -BadgeValue = Union[str, "Badge"] diff --git a/sdk/python/packages/flet/src/flet/core/banner.py b/sdk/python/packages/flet/src/flet/core/banner.py deleted file mode 100644 index f21ddb05cf..0000000000 --- a/sdk/python/packages/flet/src/flet/core/banner.py +++ /dev/null @@ -1,293 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ( - ColorEnums, - ColorValue, - MarginValue, - OptionalControlEventCallable, - PaddingValue, -) - - -class Banner(Control): - """ - A banner displays an important, succinct message, and provides actions for users to address (or dismiss the banner). A user action is required for it to be dismissed. - - Banners are displayed at the top of the screen, below a top app bar. They are persistent and non-modal, allowing the user to either ignore them or interact with them at any time. - - Example: - ``` - import flet as ft - - - def main(page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def close_banner(e): - page.close(banner) - page.add(ft.Text("Action clicked: " + e.control.text)) - - action_button_style = ft.ButtonStyle(color=ft.colors.BLUE) - banner = ft.Banner( - bgcolor=ft.colors.AMBER_100, - leading=ft.Icon(ft.icons.WARNING_AMBER_ROUNDED, color=ft.colors.AMBER, size=40), - content=ft.Text( - value="Oops, there were some errors while trying to delete the file. What would you like me to do?", - color=ft.colors.BLACK, - ), - actions=[ - ft.TextButton(text="Retry", style=action_button_style, on_click=close_banner), - ft.TextButton(text="Ignore", style=action_button_style, on_click=close_banner), - ft.TextButton(text="Cancel", style=action_button_style, on_click=close_banner), - ], - ) - - page.add(ft.ElevatedButton("Show Banner", on_click=lambda e: page.open(banner))) - - - ft.app(main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/banner - """ - - def __init__( - self, - content: Control, - actions: List[Control], - open: bool = False, - leading: Optional[Control] = None, - leading_padding: Optional[PaddingValue] = None, - content_padding: Optional[PaddingValue] = None, - force_actions_below: Optional[bool] = None, - bgcolor: Optional[ColorValue] = None, - surface_tint_color: Optional[ColorValue] = None, - shadow_color: Optional[ColorValue] = None, - divider_color: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - margin: Optional[MarginValue] = None, - content_text_style: Optional[TextStyle] = None, - min_action_bar_height: OptionalNumber = None, - on_visible: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.open = open - self.leading = leading - self.leading_padding = leading_padding - self.content = content - self.content_padding = content_padding - self.actions = actions - self.force_actions_below = force_actions_below - self.bgcolor = bgcolor - self.surface_tint_color = surface_tint_color - self.shadow_color = shadow_color - self.divider_color = divider_color - self.elevation = elevation - self.margin = margin - self.content_text_style = content_text_style - self.min_action_bar_height = min_action_bar_height - self.on_visible = on_visible - - def _get_control_name(self): - return "banner" - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - assert any( - a.visible for a in self.__actions - ), "actions must contain at minimum one visible action Control" - - self._set_attr_json("contentPadding", self.__content_padding) - self._set_attr_json("leadingPadding", self.__leading_padding) - self._set_attr_json("margin", self.__margin) - if isinstance(self.__content_text_style, TextStyle): - self._set_attr_json("contentTextStyle", self.__content_text_style) - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - for action in self.__actions: - action._set_attr_internal("n", "action") - children = [self.__content] + self.__actions - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - return children - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # modal - @property - def modal(self) -> bool: - return self._get_attr("modal", data_type="bool", def_value=False) - - @modal.setter - def modal(self, value: Optional[bool]): - self._set_attr("modal", value) - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # leading_padding - @property - def leading_padding(self) -> Optional[PaddingValue]: - return self.__leading_padding - - @leading_padding.setter - def leading_padding(self, value: Optional[PaddingValue]): - self.__leading_padding = value - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # content_padding - @property - def content_padding(self) -> Optional[PaddingValue]: - return self.__content_padding - - @content_padding.setter - def content_padding(self, value: Optional[PaddingValue]): - self.__content_padding = value - - # margin - @property - def margin(self) -> Optional[MarginValue]: - return self.__margin - - @margin.setter - def margin(self, value: Optional[MarginValue]): - self.__margin = value - - # actions - @property - def actions(self) -> List[Control]: - return self.__actions - - @actions.setter - def actions(self, value: List[Control]): - self.__actions = value - - # force_actions_below - @property - def force_actions_below(self) -> bool: - return self._get_attr("forceActionsBelow", data_type="bool", def_value=False) - - @force_actions_below.setter - def force_actions_below(self, value: Optional[bool]): - self._set_attr("forceActionsBelow", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # content_text_style - @property - def content_text_style(self) -> Optional[TextStyle]: - return self.__content_text_style - - @content_text_style.setter - def content_text_style(self, value: Optional[TextStyle]): - self.__content_text_style = value - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # divider_color - @property - def divider_color(self) -> Optional[ColorValue]: - return self.__divider_color - - @divider_color.setter - def divider_color(self, value: Optional[ColorValue]): - self.__divider_color = value - self._set_enum_attr("dividerColor", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation", data_type="float") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation_on_scroll cannot be negative" - self._set_attr("elevation", value) - - # min_action_bar_height - @property - def min_action_bar_height(self) -> OptionalNumber: - return self._get_attr("minActionBarHeight", data_type="float", def_value=52.0) - - @min_action_bar_height.setter - def min_action_bar_height(self, value: OptionalNumber): - self._set_attr("minActionBarHeight", value) - - # on_visible - @property - def on_visible(self) -> OptionalControlEventCallable: - return self._get_event_handler("visible") - - @on_visible.setter - def on_visible(self, handler: OptionalControlEventCallable): - self._add_event_handler("visible", handler) diff --git a/sdk/python/packages/flet/src/flet/core/blur.py b/sdk/python/packages/flet/src/flet/core/blur.py deleted file mode 100644 index fdb91617a5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/blur.py +++ /dev/null @@ -1,17 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Optional - - -class BlurTileMode(Enum): - CLAMP = "clamp" - DECAL = "decal" - MIRROR = "mirror" - REPEATED = "repeated" - - -@dataclass -class Blur: - sigma_x: float - sigma_y: float - tile_mode: Optional[BlurTileMode] = None diff --git a/sdk/python/packages/flet/src/flet/core/border.py b/sdk/python/packages/flet/src/flet/core/border.py deleted file mode 100644 index 74d20c2180..0000000000 --- a/sdk/python/packages/flet/src/flet/core/border.py +++ /dev/null @@ -1,46 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Optional, Union - -from flet.core.types import ColorValue, OptionalNumber - - -class BorderSideStrokeAlign(float, Enum): - INSIDE = -1.0 - CENTER = 0.0 - OUTSIDE = 1.0 - - -@dataclass -class BorderSide: - width: OptionalNumber - color: Optional[ColorValue] = None - stroke_align: Union[BorderSideStrokeAlign, OptionalNumber] = None - - -@dataclass -class Border: - top: Optional[BorderSide] = None - right: Optional[BorderSide] = None - bottom: Optional[BorderSide] = None - left: Optional[BorderSide] = None - - -def all(width: Optional[float] = None, color: Optional[ColorValue] = None) -> Border: - bs = BorderSide(width, color) - return Border(left=bs, top=bs, right=bs, bottom=bs) - - -def symmetric( - vertical: Optional[BorderSide] = None, horizontal: Optional[BorderSide] = None -) -> Border: - return Border(left=horizontal, top=vertical, right=horizontal, bottom=vertical) - - -def only( - left: Optional[BorderSide] = None, - top: Optional[BorderSide] = None, - right: Optional[BorderSide] = None, - bottom: Optional[BorderSide] = None, -) -> Border: - return Border(left=left, top=top, right=right, bottom=bottom) diff --git a/sdk/python/packages/flet/src/flet/core/border_radius.py b/sdk/python/packages/flet/src/flet/core/border_radius.py deleted file mode 100644 index bd82d183c6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/border_radius.py +++ /dev/null @@ -1,42 +0,0 @@ -import dataclasses -from typing import Union - - -@dataclasses.dataclass -class BorderRadius: - top_left: Union[float, int] - top_right: Union[float, int] - bottom_left: Union[float, int] - bottom_right: Union[float, int] - - -def all(value: float) -> BorderRadius: - return BorderRadius( - top_left=value, top_right=value, bottom_left=value, bottom_right=value - ) - - -def horizontal(left: float = 0, right: float = 0) -> BorderRadius: - return BorderRadius( - top_left=left, top_right=right, bottom_left=left, bottom_right=right - ) - - -def vertical(top: float = 0, bottom: float = 0) -> BorderRadius: - return BorderRadius( - top_left=top, top_right=top, bottom_left=bottom, bottom_right=bottom - ) - - -def only( - top_left: float = 0, - top_right: float = 0, - bottom_left: float = 0, - bottom_right: float = 0, -) -> BorderRadius: - return BorderRadius( - top_left=top_left, - top_right=top_right, - bottom_left=bottom_left, - bottom_right=bottom_right, - ) diff --git a/sdk/python/packages/flet/src/flet/core/bottom_app_bar.py b/sdk/python/packages/flet/src/flet/core/bottom_app_bar.py deleted file mode 100644 index 725910eef3..0000000000 --- a/sdk/python/packages/flet/src/flet/core/bottom_app_bar.py +++ /dev/null @@ -1,207 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - NotchShape, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class BottomAppBar(ConstrainedControl): - """ - A material design bottom app bar. - - ----- - - Online docs: https://flet.dev/docs/controls/bottomappbar - """ - - def __init__( - self, - content: Optional[Control] = None, - surface_tint_color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - shadow_color: Optional[ColorValue] = None, - padding: Optional[PaddingValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - shape: Optional[NotchShape] = None, - notch_margin: OptionalNumber = None, - elevation: OptionalNumber = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - self.surface_tint_color = surface_tint_color - self.bgcolor = bgcolor - self.shadow_color = shadow_color - self.padding = padding - self.shape = shape - self.clip_behavior = clip_behavior - self.notch_margin = notch_margin - self.elevation = elevation - - def _get_control_name(self): - return "bottomappbar" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - return [self.__content] - return [] - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # shape - @property - def shape(self) -> Optional[NotchShape]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[NotchShape]): - self.__shape = value - self._set_enum_attr("shape", value, NotchShape) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # notch_margin - @property - def notch_margin(self) -> OptionalNumber: - return self._get_attr("notchMargin") - - @notch_margin.setter - def notch_margin(self, value: OptionalNumber): - self._set_attr("notchMargin", value) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation cannot be negative" - self._set_attr("elevation", value) diff --git a/sdk/python/packages/flet/src/flet/core/bottom_sheet.py b/sdk/python/packages/flet/src/flet/core/bottom_sheet.py deleted file mode 100644 index 789c47dd93..0000000000 --- a/sdk/python/packages/flet/src/flet/core/bottom_sheet.py +++ /dev/null @@ -1,255 +0,0 @@ -from typing import Any, Optional - -from flet.core.animation import AnimationStyle -from flet.core.box import BoxConstraints -from flet.core.buttons import OutlinedBorder -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - OptionalControlEventCallable, -) - - -class BottomSheet(Control): - """ - A modal bottom sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the app. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_dismissal(e): - page.add(ft.Text("Bottom sheet dismissed")) - bs = ft.BottomSheet( - on_dismiss=handle_dismissal, - content=ft.Container( - padding=50, - content=ft.Column( - tight=True, - controls=[ - ft.Text("This is bottom sheet's content!"), - ft.ElevatedButton("Close bottom sheet", on_click=lambda _: page.close(bs)), - ], - ), - ), - ) - page.add(ft.ElevatedButton("Display bottom sheet", on_click=lambda _: page.open(bs))) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/bottomsheet - """ - - def __init__( - self, - content: Control, - open: bool = False, - elevation: OptionalNumber = None, - bgcolor: Optional[ColorValue] = None, - dismissible: Optional[bool] = None, - enable_drag: Optional[bool] = None, - show_drag_handle: Optional[bool] = None, - use_safe_area: Optional[bool] = None, - is_scroll_controlled: Optional[bool] = None, - maintain_bottom_view_insets_padding: Optional[bool] = None, - animation_style: Optional[AnimationStyle] = None, - size_constraints: Optional[BoxConstraints] = None, - clip_behavior: Optional[ClipBehavior] = None, - shape: Optional[OutlinedBorder] = None, - on_dismiss: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.open = open - self.elevation = elevation - self.bgcolor = bgcolor - self.dismissible = dismissible - self.enable_drag = enable_drag - self.show_drag_handle = show_drag_handle - self.use_safe_area = use_safe_area - self.is_scroll_controlled = is_scroll_controlled - self.content = content - self.maintain_bottom_view_insets_padding = maintain_bottom_view_insets_padding - self.animation_style = animation_style - self.size_constraints = size_constraints - self.clip_behavior = clip_behavior - self.shape = shape - self.on_dismiss = on_dismiss - - def _get_control_name(self): - return "bottomsheet" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - self._set_attr_json("animationStyle", self.__animation_style) - self._set_attr_json("sizeConstraints", self.__size_constraints) - self._set_attr_json("shape", self.__shape) - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation cannot be negative" - self._set_attr("elevation", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # dismissible - @property - def dismissible(self) -> bool: - return self._get_attr("dismissible", data_type="bool", def_value=True) - - @dismissible.setter - def dismissible(self, value: Optional[bool]): - self._set_attr("dismissible", value) - - # enable_drag - @property - def enable_drag(self) -> bool: - return self._get_attr("enableDrag", data_type="bool", def_value=False) - - @enable_drag.setter - def enable_drag(self, value: Optional[bool]): - self._set_attr("enableDrag", value) - - # show_drag_handle - @property - def show_drag_handle(self) -> bool: - return self._get_attr("showDragHandle", data_type="bool", def_value=False) - - @show_drag_handle.setter - def show_drag_handle(self, value: Optional[bool]): - self._set_attr("showDragHandle", value) - - # use_safe_area - @property - def use_safe_area(self) -> bool: - return self._get_attr("useSafeArea", data_type="bool", def_value=True) - - @use_safe_area.setter - def use_safe_area(self, value: Optional[bool]): - self._set_attr("useSafeArea", value) - - # is_scroll_controlled - @property - def is_scroll_controlled(self) -> bool: - return self._get_attr("isScrollControlled", data_type="bool", def_value=False) - - @is_scroll_controlled.setter - def is_scroll_controlled(self, value: Optional[bool]): - self._set_attr("isScrollControlled", value) - - # maintain_bottom_view_insets_padding - @property - def maintain_bottom_view_insets_padding(self) -> bool: - return self._get_attr( - "maintainBottomViewInsetsPadding", data_type="bool", def_value=True - ) - - @maintain_bottom_view_insets_padding.setter - def maintain_bottom_view_insets_padding(self, value: Optional[bool]): - self._set_attr("maintainBottomViewInsetsPadding", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # animation_style - @property - def animation_style(self) -> Optional[AnimationStyle]: - return self.__animation_style - - @animation_style.setter - def animation_style(self, value: Optional[AnimationStyle]): - self.__animation_style = value - - # size_constraints - @property - def size_constraints(self) -> Optional[BoxConstraints]: - return self.__size_constraints - - @size_constraints.setter - def size_constraints(self, value: Optional[BoxConstraints]): - self.__size_constraints = value - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet/src/flet/core/box.py b/sdk/python/packages/flet/src/flet/core/box.py deleted file mode 100644 index d193bc2fb5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/box.py +++ /dev/null @@ -1,95 +0,0 @@ -from dataclasses import dataclass, field -from enum import Enum -from typing import List, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.border import Border -from flet.core.gradients import Gradient -from flet.core.types import ( - BlendMode, - BorderRadiusValue, - ColorValue, - ImageFit, - ImageRepeat, - Number, - OffsetValue, - OptionalNumber, -) - - -@dataclass -class ColorFilter: - color: Optional[ColorValue] = None - blend_mode: Optional[BlendMode] = None - - -class FilterQuality(Enum): - NONE = "none" - LOW = "low" - MEDIUM = "medium" - HIGH = "high" - - -class ShadowBlurStyle(Enum): - NORMAL = "normal" - SOLID = "solid" - OUTER = "outer" - INNER = "inner" - - -@dataclass -class BoxShadow: - spread_radius: Optional[float] = None - blur_radius: Optional[float] = None - color: Optional[ColorValue] = None - offset: Optional[OffsetValue] = None - blur_style: ShadowBlurStyle = field(default=ShadowBlurStyle.NORMAL) - - -class BoxShape(Enum): - RECTANGLE = "rectangle" - CIRCLE = "circle" - - -@dataclass -class DecorationImage: - src: Optional[str] = None - src_base64: Optional[str] = None - color_filter: Optional[ColorFilter] = None - fit: Optional[ImageFit] = None - alignment: Optional[Alignment] = None - repeat: Optional[ImageRepeat] = None - match_text_direction: Optional[bool] = None - scale: OptionalNumber = None - opacity: OptionalNumber = None - filter_quality: Optional[FilterQuality] = None - invert_colors: Optional[bool] = None - anti_alias: Optional[bool] = None - - -@dataclass -class BoxDecoration: - bgcolor: Optional[ColorValue] = None - image: Optional[DecorationImage] = None - border: Optional[Border] = None - border_radius: Optional[BorderRadiusValue] = None - shadow: Union[None, BoxShadow, List[BoxShadow]] = None - gradient: Optional[Gradient] = None - shape: Optional[BoxShape] = None - blend_mode: Optional[BlendMode] = None - - -@dataclass -class BoxConstraints: - min_width: Number = 0 - min_height: Number = 0 - max_width: Number = float("inf") - max_height: Number = float("inf") - - def __post_init__(self): - assert ( - 0 <= self.min_width <= self.max_width <= float("inf") - ), "min_width and max_width must be between 0 and infinity and min_width must be less than or equal to max_width" - assert ( - 0 <= self.min_height <= self.max_height <= float("inf") - ), "min_height and max_height must be between 0 and infinity and min_height must be less than or equal to max_height" diff --git a/sdk/python/packages/flet/src/flet/core/button.py b/sdk/python/packages/flet/src/flet/core/button.py deleted file mode 100644 index 7ff766b0c8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/button.py +++ /dev/null @@ -1,25 +0,0 @@ -from flet.core.elevated_button import ElevatedButton - - -class Button(ElevatedButton): - """ - Elevated buttons or Buttons are essentially filled tonal buttons with a shadow. To prevent shadow creep, only use them when absolutely necessary, such as when the button requires visual separation from a patterned background. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Basic buttons" - page.add( - ft.Button(text="Button"), - ft.Button("Disabled button", disabled=True), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/elevatedbutton - """ diff --git a/sdk/python/packages/flet/src/flet/core/buttons.py b/sdk/python/packages/flet/src/flet/core/buttons.py deleted file mode 100644 index 61c19a2150..0000000000 --- a/sdk/python/packages/flet/src/flet/core/buttons.py +++ /dev/null @@ -1,91 +0,0 @@ -from dataclasses import dataclass -from typing import Optional - -from flet.core.alignment import Alignment -from flet.core.border import BorderSide -from flet.core.text_style import TextStyle -from flet.core.types import ( - BorderRadiusValue, - ColorValue, - ControlState, - ControlStateValue, - MouseCursor, - OptionalNumber, - PaddingValue, - VisualDensity, -) - - -@dataclass -class OutlinedBorder: - pass - - -@dataclass -class StadiumBorder(OutlinedBorder): - def __post_init__(self): - self.type = "stadium" - - -@dataclass -class RoundedRectangleBorder(OutlinedBorder): - radius: Optional[BorderRadiusValue] = None - - def __post_init__(self): - self.type = "roundedRectangle" - - -@dataclass -class CircleBorder(OutlinedBorder): - def __post_init__(self): - self.type = "circle" - - -@dataclass -class BeveledRectangleBorder(OutlinedBorder): - radius: Optional[BorderRadiusValue] = None - - def __post_init__(self): - self.type = "beveledRectangle" - - -@dataclass -class ContinuousRectangleBorder(OutlinedBorder): - radius: Optional[BorderRadiusValue] = None - - def __post_init__(self): - self.type = "continuousRectangle" - - -@dataclass -class ButtonStyle: - color: ControlStateValue[ColorValue] = None - bgcolor: ControlStateValue[ColorValue] = None - overlay_color: ControlStateValue[ColorValue] = None - shadow_color: ControlStateValue[ColorValue] = None - surface_tint_color: ControlStateValue[ColorValue] = None - elevation: ControlStateValue[OptionalNumber] = None - animation_duration: Optional[int] = None - padding: ControlStateValue[PaddingValue] = None - side: ControlStateValue[BorderSide] = None - shape: ControlStateValue[OutlinedBorder] = None - alignment: Optional[Alignment] = None - enable_feedback: Optional[bool] = None - text_style: ControlStateValue[TextStyle] = None - icon_size: ControlStateValue[OptionalNumber] = None - icon_color: ControlStateValue[ColorValue] = None - visual_density: Optional[VisualDensity] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - - def __post_init__(self): - if not isinstance(self.text_style, dict): - self.text_style = {ControlState.DEFAULT: self.text_style} - - if not isinstance(self.padding, dict): - self.padding = {ControlState.DEFAULT: self.padding} - - if not isinstance(self.side, dict): - self.side = {ControlState.DEFAULT: self.side} - - if not isinstance(self.shape, dict): - self.shape = {ControlState.DEFAULT: self.shape} diff --git a/sdk/python/packages/flet/src/flet/core/canvas/arc.py b/sdk/python/packages/flet/src/flet/core/canvas/arc.py deleted file mode 100644 index 92cce47d49..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/arc.py +++ /dev/null @@ -1,115 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.painting import Paint - - -class Arc(Shape): - def __init__( - self, - x: OptionalNumber = None, - y: OptionalNumber = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - start_angle: OptionalNumber = None, - sweep_angle: OptionalNumber = None, - use_center: Optional[bool] = None, - paint: Optional[Paint] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.x = x - self.y = y - self.width = width - self.height = height - self.start_angle = start_angle - self.sweep_angle = sweep_angle - self.use_center = use_center - self.paint = paint - - def _get_control_name(self): - return "arc" - - def before_update(self): - super().before_update() - self._set_attr_json("paint", self.__paint) - - # x - @property - def x(self) -> OptionalNumber: - return self._get_attr("x") - - @x.setter - def x(self, value: OptionalNumber): - self._set_attr("x", value) - - # y - @property - def y(self) -> OptionalNumber: - return self._get_attr("y") - - @y.setter - def y(self, value: OptionalNumber): - self._set_attr("y", value) - - # width - @property - def width(self) -> OptionalNumber: - return self._get_attr("width") - - @width.setter - def width(self, value: OptionalNumber): - self._set_attr("width", value) - - # height - @property - def height(self) -> OptionalNumber: - return self._get_attr("height") - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # start_angle - @property - def start_angle(self) -> OptionalNumber: - return self._get_attr("startAngle") - - @start_angle.setter - def start_angle(self, value: OptionalNumber): - self._set_attr("startAngle", value) - - # sweep_angle - @property - def sweep_angle(self) -> OptionalNumber: - return self._get_attr("sweepAngle") - - @sweep_angle.setter - def sweep_angle(self, value: OptionalNumber): - self._set_attr("sweepAngle", value) - - # use_center - @property - def use_center(self) -> bool: - return self._get_attr("useCenter", data_type="bool", def_value=False) - - @use_center.setter - def use_center(self, value: Optional[bool]): - self._set_attr("useCenter", value) - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/canvas.py b/sdk/python/packages/flet/src/flet/core/canvas/canvas.py deleted file mode 100644 index 065dc95d13..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/canvas.py +++ /dev/null @@ -1,152 +0,0 @@ -import json -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.canvas.shape import Shape -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Canvas(ConstrainedControl): - def __init__( - self, - shapes: Optional[List[Shape]] = None, - content: Optional[Control] = None, - resize_interval: OptionalNumber = None, - on_resize=None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_resize = EventHandler(lambda e: CanvasResizeEvent(e)) - self._add_event_handler("resize", self.__on_resize.get_handler()) - - self.shapes = shapes - self.content = content - self.resize_interval = resize_interval - self.on_resize = on_resize - - def _get_control_name(self): - return "canvas" - - def _get_children(self): - children = [] - children.extend(self.__shapes) - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - def clean(self): - super().clean() - self.__shapes.clear() - - # shapes - @property - def shapes(self) -> List[Shape]: - return self.__shapes - - @shapes.setter - def shapes(self, value: Optional[List[Shape]]): - self.__shapes = value if value is not None else [] - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # resize_interval - @property - def resize_interval(self) -> OptionalNumber: - return self._get_attr("resizeInterval") - - @resize_interval.setter - def resize_interval(self, value: OptionalNumber): - self._set_attr("resizeInterval", value) - - # on_resize - @property - def on_resize(self) -> OptionalEventCallable["CanvasResizeEvent"]: - return self.__on_resize.handler - - @on_resize.setter - def on_resize(self, handler: OptionalEventCallable["CanvasResizeEvent"]): - self.__on_resize.handler = handler - self._set_attr("onresize", True if handler is not None else None) - - -class CanvasResizeEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.width: float = d.get("w") - self.height: float = d.get("h") diff --git a/sdk/python/packages/flet/src/flet/core/canvas/circle.py b/sdk/python/packages/flet/src/flet/core/canvas/circle.py deleted file mode 100644 index d9a6a4a385..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/circle.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.painting import Paint - - -class Circle(Shape): - def __init__( - self, - x: OptionalNumber = None, - y: OptionalNumber = None, - radius: OptionalNumber = None, - paint: Optional[Paint] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.x = x - self.y = y - self.radius = radius - self.paint = paint - - def _get_control_name(self): - return "circle" - - def before_update(self): - super().before_update() - self._set_attr_json("paint", self.__paint) - - # x - @property - def x(self) -> OptionalNumber: - return self._get_attr("x") - - @x.setter - def x(self, value: OptionalNumber): - self._set_attr("x", value) - - # y - @property - def y(self) -> OptionalNumber: - return self._get_attr("y") - - @y.setter - def y(self, value: OptionalNumber): - self._set_attr("y", value) - - # radius - @property - def radius(self) -> OptionalNumber: - return self._get_attr("radius") - - @radius.setter - def radius(self, value: OptionalNumber): - self._set_attr("radius", value) - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/color.py b/sdk/python/packages/flet/src/flet/core/canvas/color.py deleted file mode 100644 index 00f5225c2d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/color.py +++ /dev/null @@ -1,51 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.types import BlendMode, ColorEnums, ColorValue - - -class Color(Shape): - def __init__( - self, - color: Optional[ColorValue] = None, - blend_mode: Optional[BlendMode] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.color = color - self.blend_mode = blend_mode - - def _get_control_name(self): - return "color" - - def before_update(self): - super().before_update() - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # blend_mode - @property - def blend_mode(self) -> Optional[BlendMode]: - return self.__blend_mode - - @blend_mode.setter - def blend_mode(self, value: Optional[BlendMode]): - self.__blend_mode = value - self._set_attr( - "blendMode", value.value if isinstance(value, BlendMode) else value - ) diff --git a/sdk/python/packages/flet/src/flet/core/canvas/fill.py b/sdk/python/packages/flet/src/flet/core/canvas/fill.py deleted file mode 100644 index 41cdf7b019..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/fill.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.painting import Paint - - -class Fill(Shape): - def __init__( - self, - paint: Optional[Paint] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.paint = paint - - def _get_control_name(self): - return "fill" - - def before_update(self): - super().before_update() - self._set_attr_json("paint", self.__paint) - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/line.py b/sdk/python/packages/flet/src/flet/core/canvas/line.py deleted file mode 100644 index 5e60d18819..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/line.py +++ /dev/null @@ -1,82 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.painting import Paint - - -class Line(Shape): - def __init__( - self, - x1: OptionalNumber = None, - y1: OptionalNumber = None, - x2: OptionalNumber = None, - y2: OptionalNumber = None, - paint: Optional[Paint] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.x1 = x1 - self.y1 = y1 - self.x2 = x2 - self.y2 = y2 - self.paint = paint - - def _get_control_name(self): - return "line" - - def before_update(self): - super().before_update() - self._set_attr_json("paint", self.__paint) - - # x1 - @property - def x1(self) -> OptionalNumber: - return self._get_attr("x1") - - @x1.setter - def x1(self, value: OptionalNumber): - self._set_attr("x1", value) - - # y1 - @property - def y1(self) -> OptionalNumber: - return self._get_attr("y1") - - @y1.setter - def y1(self, value: OptionalNumber): - self._set_attr("y1", value) - - # x2 - @property - def x2(self) -> OptionalNumber: - return self._get_attr("x2") - - @x2.setter - def x2(self, value: OptionalNumber): - self._set_attr("x2", value) - - # y2 - @property - def y2(self) -> OptionalNumber: - return self._get_attr("y2") - - @y2.setter - def y2(self, value: OptionalNumber): - self._set_attr("y2", value) - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/oval.py b/sdk/python/packages/flet/src/flet/core/canvas/oval.py deleted file mode 100644 index 2c0bf02615..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/oval.py +++ /dev/null @@ -1,80 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.painting import Paint - - -class Oval(Shape): - def __init__( - self, - x: OptionalNumber = None, - y: OptionalNumber = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - paint: Optional[Paint] = None, - # base - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.x = x - self.y = y - self.width = width - self.height = height - self.paint = paint - - def _get_control_name(self): - return "oval" - - def before_update(self): - super().before_update() - self._set_attr_json("paint", self.__paint) - - # x - @property - def x(self) -> OptionalNumber: - return self._get_attr("x") - - @x.setter - def x(self, value: OptionalNumber): - self._set_attr("x", value) - - # y - @property - def y(self) -> OptionalNumber: - return self._get_attr("y") - - @y.setter - def y(self, value: OptionalNumber): - self._set_attr("y", value) - - # width - @property - def width(self) -> OptionalNumber: - return self._get_attr("width") - - @width.setter - def width(self, value: OptionalNumber): - self._set_attr("width", value) - - # height - @property - def height(self) -> OptionalNumber: - return self._get_attr("height") - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/path.py b/sdk/python/packages/flet/src/flet/core/canvas/path.py deleted file mode 100644 index 5c5580d3dc..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/path.py +++ /dev/null @@ -1,134 +0,0 @@ -import dataclasses -from typing import Any, List, Optional - -from flet.core.canvas.shape import Shape -from flet.core.painting import Paint -from flet.core.types import BorderRadiusValue - - -class Path(Shape): - @dataclasses.dataclass - class PathElement: - pass - - @dataclasses.dataclass - class MoveTo(PathElement): - x: float - y: float - type: str = dataclasses.field(default="moveto") - - @dataclasses.dataclass - class LineTo(PathElement): - x: float - y: float - type: str = dataclasses.field(default="lineto") - - @dataclasses.dataclass - class QuadraticTo(PathElement): - cp1x: float - cp1y: float - x: float - y: float - w: float = dataclasses.field(default=1) - type: str = dataclasses.field(default="conicto") - - @dataclasses.dataclass - class CubicTo(PathElement): - cp1x: float - cp1y: float - cp2x: float - cp2y: float - x: float - y: float - type: str = dataclasses.field(default="cubicto") - - @dataclasses.dataclass - class SubPath(PathElement): - elements: List["Path.PathElement"] - x: float - y: float - type: str = dataclasses.field(default="subpath") - - @dataclasses.dataclass - class Arc(PathElement): - x: float - y: float - width: float - height: float - start_angle: float - sweep_angle: float - type: str = dataclasses.field(default="arc") - - @dataclasses.dataclass - class ArcTo(PathElement): - x: float - y: float - radius: float = dataclasses.field(default=0) - rotation: float = dataclasses.field(default=0) - large_arc: bool = dataclasses.field(default=False) - clockwise: bool = dataclasses.field(default=True) - type: str = dataclasses.field(default="arcto") - - @dataclasses.dataclass - class Oval(PathElement): - x: float - y: float - width: float - height: float - type: str = dataclasses.field(default="oval") - - @dataclasses.dataclass - class Rect(PathElement): - x: float - y: float - width: float - height: float - border_radius: Optional[BorderRadiusValue] = None - type: str = dataclasses.field(default="rect") - - @dataclasses.dataclass - class Close(PathElement): - type: str = dataclasses.field(default="close") - - def __init__( - self, - elements: Optional[List[PathElement]] = None, - paint: Optional[Paint] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.elements = elements - self.paint = paint - - def _get_control_name(self): - return "path" - - def before_update(self): - super().before_update() - self._set_attr_json("elements", self.__elements) - self._set_attr_json("paint", self.__paint) - - # elements - @property - def elements(self): - return self.__elements - - @elements.setter - def elements(self, value: Optional[List[PathElement]]): - self.__elements = value if value is not None else [] - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/points.py b/sdk/python/packages/flet/src/flet/core/canvas/points.py deleted file mode 100644 index 81def6ecb6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/points.py +++ /dev/null @@ -1,71 +0,0 @@ -from enum import Enum -from typing import Any, List, Optional - -from flet.core.canvas.shape import Shape -from flet.core.painting import Paint -from flet.core.types import OffsetValue - - -class PointMode(Enum): - POINTS = "points" - LINES = "lines" - POLYGON = "polygon" - - -class Points(Shape): - def __init__( - self, - points: Optional[List[OffsetValue]] = None, - point_mode: Optional[PointMode] = None, - paint: Optional[Paint] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.points = points - self.point_mode = point_mode - self.paint = paint - - def _get_control_name(self): - return "points" - - def before_update(self): - super().before_update() - self._set_attr_json("points", self.__points) - self._set_attr_json("paint", self.__paint) - - # point_mode - @property - def point_mode(self) -> Optional[PointMode]: - return self.__point_mode - - @point_mode.setter - def point_mode(self, value: Optional[PointMode]): - self.__point_mode = value - self._set_attr( - "pointMode", value.value if isinstance(value, PointMode) else value - ) - - # points - @property - def points(self) -> Optional[List[OffsetValue]]: - return self.__points - - @points.setter - def points(self, value: Optional[List[OffsetValue]]): - self.__points = value if value is not None else [] - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/rect.py b/sdk/python/packages/flet/src/flet/core/canvas/rect.py deleted file mode 100644 index d775485d06..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/rect.py +++ /dev/null @@ -1,93 +0,0 @@ -from typing import Any, Optional - -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.painting import Paint -from flet.core.types import BorderRadiusValue - - -class Rect(Shape): - def __init__( - self, - x: OptionalNumber = None, - y: OptionalNumber = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - border_radius: Optional[BorderRadiusValue] = None, - paint: Optional[Paint] = None, - # base - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.x = x - self.y = y - self.width = width - self.height = height - self.border_radius = border_radius - self.paint = paint - - def _get_control_name(self): - return "rect" - - def before_update(self): - super().before_update() - self._set_attr_json("borderRadius", self.__border_radius) - self._set_attr_json("paint", self.__paint) - - # x - @property - def x(self) -> OptionalNumber: - return self._get_attr("x") - - @x.setter - def x(self, value: OptionalNumber): - self._set_attr("x", value) - - # y - @property - def y(self) -> OptionalNumber: - return self._get_attr("y") - - @y.setter - def y(self, value: OptionalNumber): - self._set_attr("y", value) - - # width - @property - def width(self) -> OptionalNumber: - return self._get_attr("width") - - @width.setter - def width(self, value: OptionalNumber): - self._set_attr("width", value) - - # height - @property - def height(self) -> OptionalNumber: - return self._get_attr("height") - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # paint - @property - def paint(self) -> Optional[Paint]: - return self.__paint - - @paint.setter - def paint(self, value: Optional[Paint]): - self.__paint = value diff --git a/sdk/python/packages/flet/src/flet/core/canvas/shadow.py b/sdk/python/packages/flet/src/flet/core/canvas/shadow.py deleted file mode 100644 index f983e80568..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/shadow.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.canvas.path import Path -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.types import ColorEnums, ColorValue - - -class Shadow(Shape): - def __init__( - self, - path: Optional[List[Path.PathElement]] = None, - color: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - transparent_occluder: Optional[bool] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.path = path - self.color = color - self.elevation = elevation - self.transparent_occluder = transparent_occluder - - def _get_control_name(self): - return "shadow" - - def before_update(self): - super().before_update() - self._set_attr_json("path", self.__path) - - # path - @property - def path(self): - return self.__path - - @path.setter - def path(self, value: Optional[List[Path.PathElement]]): - self.__path = value if value is not None else [] - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # transparent_occluder - @property - def transparent_occluder(self) -> bool: - return self._get_attr("transparentOccluder", data_type="bool", def_value=False) - - @transparent_occluder.setter - def transparent_occluder(self, value: Optional[bool]): - self._set_attr("transparentOccluder", value) diff --git a/sdk/python/packages/flet/src/flet/core/canvas/shape.py b/sdk/python/packages/flet/src/flet/core/canvas/shape.py deleted file mode 100644 index 6f8066f057..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/shape.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control - - -class Shape(Control): - def __init__( - self, - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) diff --git a/sdk/python/packages/flet/src/flet/core/canvas/text.py b/sdk/python/packages/flet/src/flet/core/canvas/text.py deleted file mode 100644 index 990ce84c25..0000000000 --- a/sdk/python/packages/flet/src/flet/core/canvas/text.py +++ /dev/null @@ -1,160 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.alignment import Alignment -from flet.core.canvas.shape import Shape -from flet.core.control import OptionalNumber -from flet.core.inline_span import InlineSpan -from flet.core.text_style import TextStyle -from flet.core.types import TextAlign - - -class Text(Shape): - def __init__( - self, - x: OptionalNumber = None, - y: OptionalNumber = None, - text: Optional[str] = None, - style: Optional[TextStyle] = None, - spans: Optional[List[InlineSpan]] = None, - alignment: Optional[Alignment] = None, - text_align: Optional[TextAlign] = None, - max_lines: Optional[int] = None, - max_width: OptionalNumber = None, - ellipsis: Optional[str] = None, - rotate: OptionalNumber = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Shape.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.x = x - self.y = y - self.text = text - self.style = style - self.spans = spans - self.alignment = alignment - self.text_align = text_align - self.max_lines = max_lines - self.max_width = max_width - self.ellipsis = ellipsis - self.rotate = rotate - - def _get_control_name(self): - return "text" - - def _get_children(self): - children = [] - children.extend(self.__spans) - return children - - def before_update(self): - super().before_update() - self._set_attr_json("style", self.__style) - self._set_attr_json("alignment", self.__alignment) - - # x - @property - def x(self) -> OptionalNumber: - return self._get_attr("x") - - @x.setter - def x(self, value: OptionalNumber): - self._set_attr("x", value) - - # y - @property - def y(self) -> OptionalNumber: - return self._get_attr("y") - - @y.setter - def y(self, value: OptionalNumber): - self._set_attr("y", value) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # style - @property - def style(self) -> Optional[TextStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[TextStyle]): - self.__style = value - - # spans - @property - def spans(self) -> Optional[List[InlineSpan]]: - return self.__spans - - @spans.setter - def spans(self, value: Optional[List[InlineSpan]]): - self.__spans = value if value is not None else [] - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # text_align - @property - def text_align(self) -> Optional[TextAlign]: - return self.__text_align - - @text_align.setter - def text_align(self, value: Optional[TextAlign]): - self.__text_align = value - self._set_attr( - "textAlign", value.value if isinstance(value, TextAlign) else value - ) - - # max_lines - @property - def max_lines(self) -> Optional[int]: - return self._get_attr("maxLines") - - @max_lines.setter - def max_lines(self, value: Optional[int]): - self._set_attr("maxLines", value) - - # max_width - @property - def max_width(self) -> OptionalNumber: - return self._get_attr("maxWidth") - - @max_width.setter - def max_width(self, value: OptionalNumber): - self._set_attr("maxWidth", value) - - # ellipsis - @property - def ellipsis(self) -> Optional[str]: - return self._get_attr("ellipsis") - - @ellipsis.setter - def ellipsis(self, value: Optional[str]): - self._set_attr("ellipsis", value) - - # rotate - @property - def rotate(self) -> OptionalNumber: - return self._get_attr("rotate") - - @rotate.setter - def rotate(self, value: OptionalNumber): - self._set_attr("rotate", value) diff --git a/sdk/python/packages/flet/src/flet/core/card.py b/sdk/python/packages/flet/src/flet/core/card.py deleted file mode 100644 index b317c5eb20..0000000000 --- a/sdk/python/packages/flet/src/flet/core/card.py +++ /dev/null @@ -1,285 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - MarginValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CardVariant(Enum): - ELEVATED = "elevated" - FILLED = "filled" - OUTLINED = "outlined" - - -class Card(ConstrainedControl, AdaptiveControl): - """ - A material design card: a panel with slightly rounded corners and an elevation shadow. - - Example: - ``` - import flet as ft - - def main(page): - page.title = "Card Example" - page.add( - ft.Card( - content=ft.Container( - content=ft.Column( - [ - ft.ListTile( - leading=ft.Icon(ft.icons.ALBUM), - title=ft.Text("The Enchanted Nightingale"), - subtitle=ft.Text( - "Music by Julie Gable. Lyrics by Sidney Stein." - ), - ), - ft.Row( - [ft.TextButton("Buy tickets"), ft.TextButton("Listen")], - alignment=ft.MainAxisAlignment.END, - ), - ] - ), - width=400, - padding=10, - ) - ) - ) - - ft.app(target=main) - - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/card - """ - - def __init__( - self, - content: Optional[Control] = None, - margin: Optional[MarginValue] = None, - elevation: OptionalNumber = None, - color: Optional[ColorValue] = None, - shadow_color: Optional[ColorValue] = None, - surface_tint_color: Optional[ColorValue] = None, - shape: Optional[OutlinedBorder] = None, - clip_behavior: Optional[ClipBehavior] = None, - is_semantic_container: Optional[bool] = None, - show_border_on_foreground: Optional[bool] = None, - variant: Optional[CardVariant] = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - key: Optional[str] = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.content = content - self.margin = margin - self.elevation = elevation - self.color = color - self.shadow_color = shadow_color - self.surface_tint_color = surface_tint_color - self.shape = shape - self.clip_behavior = clip_behavior - self.is_semantic_container = is_semantic_container - self.show_border_on_foreground = show_border_on_foreground - self.variant = variant - - def _get_control_name(self): - return "card" - - def before_update(self): - super().before_update() - self._set_attr_json("margin", self.__margin) - self._set_attr_json("shape", self.__shape) - - def _get_children(self): - children = [] - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # margin - @property - def margin(self) -> Optional[MarginValue]: - return self.__margin - - @margin.setter - def margin(self, value: Optional[MarginValue]): - self.__margin = value - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # color - @property - def color(self): - return self.__color - - @color.setter - def color(self, value): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # shadow_color - @property - def shadow_color(self): - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self): - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # is_semantic_container - @property - def is_semantic_container(self) -> bool: - return self._get_attr("isSemanticContainer", data_type="bool", def_value=True) - - @is_semantic_container.setter - def is_semantic_container(self, value): - self._set_attr("isSemanticContainer", value) - - # show_border_on_foreground - @property - def show_border_on_foreground(self) -> bool: - return self._get_attr( - "showBorderOnForeground", data_type="bool", def_value=True - ) - - @show_border_on_foreground.setter - def show_border_on_foreground(self, value): - self._set_attr("showBorderOnForeground", value) - - # variant - @property - def variant(self) -> Optional[CardVariant]: - return self.__variant - - @variant.setter - def variant(self, value: Optional[CardVariant]): - self.__variant = value - self._set_enum_attr("variant", value, CardVariant) diff --git a/sdk/python/packages/flet/src/flet/core/charts/bar_chart.py b/sdk/python/packages/flet/src/flet/core/charts/bar_chart.py deleted file mode 100644 index e4953903ac..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/bar_chart.py +++ /dev/null @@ -1,435 +0,0 @@ -import json -from enum import Enum -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import Border, BorderSide -from flet.core.charts.bar_chart_group import BarChartGroup -from flet.core.charts.chart_axis import ChartAxis -from flet.core.charts.chart_grid_lines import ChartGridLines -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class TooltipDirection(Enum): - AUTO = "auto" - TOP = "top" - BOTTOM = "bottom" - - -class BarChart(ConstrainedControl): - def __init__( - self, - bar_groups: Optional[List[BarChartGroup]] = None, - groups_space: OptionalNumber = None, - animate: Optional[AnimationValue] = None, - interactive: Optional[bool] = None, - bgcolor: Optional[ColorValue] = None, - tooltip_bgcolor: Optional[ColorValue] = None, - border: Optional[Border] = None, - horizontal_grid_lines: Optional[ChartGridLines] = None, - vertical_grid_lines: Optional[ChartGridLines] = None, - left_axis: Optional[ChartAxis] = None, - top_axis: Optional[ChartAxis] = None, - right_axis: Optional[ChartAxis] = None, - bottom_axis: Optional[ChartAxis] = None, - baseline_y: OptionalNumber = None, - min_y: OptionalNumber = None, - max_y: OptionalNumber = None, - tooltip_rounded_radius: OptionalNumber = None, - tooltip_margin: OptionalNumber = None, - tooltip_padding: Optional[PaddingValue] = None, - tooltip_max_content_width: OptionalNumber = None, - tooltip_rotate_angle: OptionalNumber = None, - tooltip_tooltip_horizontal_offset: OptionalNumber = None, - tooltip_tooltip_border_side: Optional[BorderSide] = None, - tooltip_fit_inside_horizontally: Optional[bool] = None, - tooltip_fit_inside_vertically: Optional[bool] = None, - tooltip_direction: Optional[TooltipDirection] = None, - on_chart_event: OptionalEventCallable["BarChartEvent"] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_chart_event = EventHandler(lambda e: BarChartEvent(e)) - self._add_event_handler("chart_event", self.__on_chart_event.get_handler()) - - self.bar_groups = bar_groups - self.groups_space = groups_space - self.animate = animate - self.interactive = interactive - self.bgcolor = bgcolor - self.tooltip_bgcolor = tooltip_bgcolor - self.border = border - self.horizontal_grid_lines = horizontal_grid_lines - self.vertical_grid_lines = vertical_grid_lines - self.left_axis = left_axis - self.top_axis = top_axis - self.right_axis = right_axis - self.bottom_axis = bottom_axis - self.baseline_y = baseline_y - self.min_y = min_y - self.max_y = max_y - self.on_chart_event = on_chart_event - self.tooltip_rounded_radius = tooltip_rounded_radius - self.tooltip_margin = tooltip_margin - self.tooltip_padding = tooltip_padding - self.tooltip_direction = tooltip_direction - self.tooltip_max_content_width = tooltip_max_content_width - self.tooltip_rotate_angle = tooltip_rotate_angle - self.tooltip_horizontal_offset = tooltip_tooltip_horizontal_offset - self.tooltip_border_side = tooltip_tooltip_border_side - self.tooltip_fit_inside_horizontally = tooltip_fit_inside_horizontally - self.tooltip_fit_inside_vertically = tooltip_fit_inside_vertically - - def _get_control_name(self): - return "barchart" - - def before_update(self): - super().before_update() - self._set_attr_json("horizontalGridLines", self.__horizontal_grid_lines) - self._set_attr_json("verticalGridLines", self.__vertical_grid_lines) - self._set_attr_json("animate", self.__animate) - self._set_attr_json("border", self.__border) - self._set_attr_json("tooltipBorderSide", self.__tooltip_border_side) - self._set_attr_json("tooltipPadding", self.__tooltip_padding) - - def _get_children(self): - children = [] - for ds in self.__bar_groups: - children.append(ds) - if self.__left_axis: - self.__left_axis._set_attr_internal("n", "l") - children.append(self.__left_axis) - if self.__top_axis: - self.__top_axis._set_attr_internal("n", "t") - children.append(self.__top_axis) - if self.__right_axis: - self.__right_axis._set_attr_internal("n", "r") - children.append(self.__right_axis) - if self.__bottom_axis: - self.__bottom_axis._set_attr_internal("n", "b") - children.append(self.__bottom_axis) - return children - - # bar_groups - @property - def bar_groups(self): - return self.__bar_groups - - @bar_groups.setter - def bar_groups(self, value): - self.__bar_groups = value if value is not None else [] - - # groups_space - @property - def groups_space(self) -> OptionalNumber: - return self._get_attr("groupsSpace", data_type="float") - - @groups_space.setter - def groups_space(self, value: OptionalNumber): - self._set_attr("groupsSpace", value) - - # animate - @property - def animate(self) -> AnimationValue: - return self.__animate - - @animate.setter - def animate(self, value: AnimationValue): - self.__animate = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # interactive - @property - def interactive(self) -> bool: - return self._get_attr("interactive", data_type="bool", def_value=True) - - @interactive.setter - def interactive(self, value: Optional[bool]): - self._set_attr("interactive", value) - - # tooltip_bgcolor - @property - def tooltip_bgcolor(self) -> Optional[str]: - return self.__tooltip_bgcolor - - @tooltip_bgcolor.setter - def tooltip_bgcolor(self, value: Optional[str]): - self.__tooltip_bgcolor = value - self._set_enum_attr("tooltipBgcolor", value, ColorEnums) - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # horizontal_grid_lines - @property - def horizontal_grid_lines(self) -> Optional[ChartGridLines]: - return self.__horizontal_grid_lines - - @horizontal_grid_lines.setter - def horizontal_grid_lines(self, value: Optional[ChartGridLines]): - self.__horizontal_grid_lines = value - - # vertical_grid_lines - @property - def vertical_grid_lines(self) -> Optional[ChartGridLines]: - return self.__vertical_grid_lines - - @vertical_grid_lines.setter - def vertical_grid_lines(self, value: Optional[ChartGridLines]): - self.__vertical_grid_lines = value - - # left_axis - @property - def left_axis(self) -> Optional[ChartAxis]: - return self.__left_axis - - @left_axis.setter - def left_axis(self, value: Optional[ChartAxis]): - self.__left_axis = value - - # top_axis - @property - def top_axis(self) -> Optional[ChartAxis]: - return self.__top_axis - - @top_axis.setter - def top_axis(self, value: Optional[ChartAxis]): - self.__top_axis = value - - # right_axis - @property - def right_axis(self) -> Optional[ChartAxis]: - return self.__right_axis - - @right_axis.setter - def right_axis(self, value: Optional[ChartAxis]): - self.__right_axis = value - - # bottom_axis - @property - def bottom_axis(self) -> Optional[ChartAxis]: - return self.__bottom_axis - - @bottom_axis.setter - def bottom_axis(self, value: Optional[ChartAxis]): - self.__bottom_axis = value - - # baseline_y - @property - def baseline_y(self) -> OptionalNumber: - return self._get_attr("baseliney", data_type="float") - - @baseline_y.setter - def baseline_y(self, value: OptionalNumber): - self._set_attr("baseliney", value) - - # min_y - @property - def min_y(self) -> OptionalNumber: - return self._get_attr("miny", data_type="float") - - @min_y.setter - def min_y(self, value: OptionalNumber): - self._set_attr("miny", value) - - # max_y - @property - def max_y(self) -> OptionalNumber: - return self._get_attr("maxy", data_type="float") - - @max_y.setter - def max_y(self, value: OptionalNumber): - self._set_attr("maxy", value) - - # tooltip_rounded_radius - @property - def tooltip_rounded_radius(self) -> OptionalNumber: - return self._get_attr("tooltipRoundedRadius", data_type="float") - - @tooltip_rounded_radius.setter - def tooltip_rounded_radius(self, value: OptionalNumber): - self._set_attr("tooltipRoundedRadius", value) - - # tooltip_margin - @property - def tooltip_margin(self) -> OptionalNumber: - return self._get_attr("tooltipMargin", data_type="float") - - @tooltip_margin.setter - def tooltip_margin(self, value: OptionalNumber): - self._set_attr("tooltipMargin", value) - - # tooltip_padding - @property - def tooltip_padding(self) -> Optional[PaddingValue]: - return self.__tooltip_padding - - @tooltip_padding.setter - def tooltip_padding(self, value: Optional[PaddingValue]): - self.__tooltip_padding = value - - # tooltip_max_content_width - @property - def tooltip_max_content_width(self) -> OptionalNumber: - return self._get_attr("tooltipMaxContentWidth", data_type="float") - - @tooltip_max_content_width.setter - def tooltip_max_content_width(self, value: OptionalNumber): - self._set_attr("tooltipMaxContentWidth", value) - - # tooltip_rotate_angle - @property - def tooltip_rotate_angle(self) -> OptionalNumber: - return self._get_attr("tooltipRotateAngle", data_type="float") - - @tooltip_rotate_angle.setter - def tooltip_rotate_angle(self, value: OptionalNumber): - self._set_attr("tooltipRotateAngle", value) - - # tooltip_fit_inside_vertically - @property - def tooltip_fit_inside_vertically(self) -> Optional[bool]: - return self._get_attr("tooltipFitInsideVertically", data_type="bool") - - @tooltip_fit_inside_vertically.setter - def tooltip_fit_inside_vertically(self, value: Optional[bool]): - self._set_attr("tooltipFitInsideVertically", value) - - # tooltip_fit_inside_horizontally - @property - def tooltip_fit_inside_horizontally(self) -> Optional[bool]: - return self._get_attr("tooltipFitInsideHorizontally", data_type="bool") - - @tooltip_fit_inside_horizontally.setter - def tooltip_fit_inside_horizontally(self, value: Optional[bool]): - self._set_attr("tooltipFitInsideHorizontally", value) - - # tooltip_border_side - @property - def tooltip_border_side(self) -> Optional[BorderSide]: - return self.__tooltip_border_side - - @tooltip_border_side.setter - def tooltip_border_side(self, value: Optional[BorderSide]): - self.__tooltip_border_side = value - - # tooltip_direction - @property - def tooltip_direction(self) -> Optional[TooltipDirection]: - return self.__tooltip_direction - - @tooltip_direction.setter - def tooltip_direction(self, value: Optional[TooltipDirection]): - self.__tooltip_direction = value - self._set_enum_attr("tooltipDirection", value, TooltipDirection) - - # on_chart_event - @property - def on_chart_event(self) -> OptionalEventCallable["BarChartEvent"]: - return self.__on_chart_event.handler - - @on_chart_event.setter - def on_chart_event(self, handler: OptionalEventCallable["BarChartEvent"]): - self.__on_chart_event.handler = handler - self._set_attr("onChartEvent", True if handler is not None else None) - - -class BarChartEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.type: str = d.get("type") - self.group_index: int = d.get("group_index") - self.rod_index: int = d.get("rod_index") - self.stack_item_index: int = d.get("stack_item_index") diff --git a/sdk/python/packages/flet/src/flet/core/charts/bar_chart_group.py b/sdk/python/packages/flet/src/flet/core/charts/bar_chart_group.py deleted file mode 100644 index d454b00bcb..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/bar_chart_group.py +++ /dev/null @@ -1,80 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.charts.bar_chart_rod import BarChartRod -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref - - -class BarChartGroup(Control): - def __init__( - self, - x: Optional[int] = None, - bar_rods: Optional[List[BarChartRod]] = None, - group_vertically: Optional[bool] = None, - bars_space: OptionalNumber = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.x = x - self.bar_rods = bar_rods - self.group_vertically = group_vertically - self.bars_space = bars_space - - def _get_control_name(self): - return "group" - - def before_update(self): - super().before_update() - - def _get_children(self): - return self.__bar_rods - - # bar_rods - @property - def bar_rods(self): - return self.__bar_rods - - @bar_rods.setter - def bar_rods(self, value): - self.__bar_rods = value if value is not None else [] - - # x - @property - def x(self) -> Optional[int]: - return self._get_attr("x", data_type="int") - - @x.setter - def x(self, value: Optional[int]): - self._set_attr("x", value) - - # group_vertically - @property - def group_vertically(self) -> bool: - return self._get_attr("groupVertically", data_type="bool", def_value=False) - - @group_vertically.setter - def group_vertically(self, value: Optional[bool]): - self._set_attr("groupVertically", value) - - # bars_space - @property - def bars_space(self) -> OptionalNumber: - return self._get_attr("barsSpace", data_type="float") - - @bars_space.setter - def bars_space(self, value: OptionalNumber): - self._set_attr("barsSpace", value) diff --git a/sdk/python/packages/flet/src/flet/core/charts/bar_chart_rod.py b/sdk/python/packages/flet/src/flet/core/charts/bar_chart_rod.py deleted file mode 100644 index d2c7d16a5f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/bar_chart_rod.py +++ /dev/null @@ -1,239 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.badge import BadgeValue -from flet.core.border import BorderSide -from flet.core.charts.bar_chart_rod_stack_item import BarChartRodStackItem -from flet.core.control import Control, OptionalNumber -from flet.core.gradients import Gradient -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import BorderRadiusValue, ColorEnums, ColorValue, TextAlign - - -class BarChartRod(Control): - def __init__( - self, - rod_stack_items: Optional[List[BarChartRodStackItem]] = None, - from_y: OptionalNumber = None, - to_y: OptionalNumber = None, - width: OptionalNumber = None, - color: Optional[ColorValue] = None, - gradient: Optional[Gradient] = None, - border_radius: Optional[BorderRadiusValue] = None, - border_side: Optional[BorderSide] = None, - bg_from_y: OptionalNumber = None, - bg_to_y: OptionalNumber = None, - bg_color: Optional[ColorValue] = None, - bg_gradient: Optional[Gradient] = None, - selected: Optional[bool] = None, - show_tooltip: Optional[bool] = None, - tooltip: Optional[str] = None, - tooltip_style: Optional[TextStyle] = None, - tooltip_align: Optional[TextAlign] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - badge: Optional[BadgeValue] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - badge=badge, - ) - - self.rod_stack_items = rod_stack_items - self.from_y = from_y - self.to_y = to_y - self.width = width - self.color = color - self.gradient = gradient - self.border_side = border_side - self.border_radius = border_radius - self.bg_from_y = bg_from_y - self.bg_to_y = bg_to_y - self.bg_color = bg_color - self.bg_gradient = bg_gradient - self.selected = selected - self.show_tooltip = show_tooltip - self.tooltip = tooltip - self.tooltip_align = tooltip_align - self.tooltip_style = tooltip_style - - def _get_control_name(self): - return "bar_chart_rod" - - def before_update(self): - super().before_update() - self._set_attr_json("gradient", self.__gradient) - self._set_attr_json("borderSide", self.__border_side) - self._set_attr_json("borderRadius", self.__border_radius) - self._set_attr_json("bgGradient", self.__bg_gradient) - - def _get_children(self): - return self.__rod_stack_items - - # rod_stack_items - @property - def rod_stack_items(self): - return self.__rod_stack_items - - @rod_stack_items.setter - def rod_stack_items(self, value): - self.__rod_stack_items = value if value is not None else [] - - # from_y - @property - def from_y(self) -> OptionalNumber: - return self._get_attr("fromY", data_type="float") - - @from_y.setter - def from_y(self, value: OptionalNumber): - self._set_attr("fromY", value) - - # to_y - @property - def to_y(self) -> OptionalNumber: - return self._get_attr("toY", data_type="float") - - @to_y.setter - def to_y(self, value: OptionalNumber): - self._set_attr("toY", value) - - # width - @property - def width(self) -> OptionalNumber: - return self._get_attr("width", data_type="float") - - @width.setter - def width(self, value: OptionalNumber): - self._set_attr("width", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # border_side - @property - def border_side(self) -> Optional[BorderSide]: - return self.__border_side - - @border_side.setter - def border_side(self, value: Optional[BorderSide]): - self.__border_side = value - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # gradient - @property - def gradient(self) -> Optional[Gradient]: - return self.__gradient - - @gradient.setter - def gradient(self, value: Optional[Gradient]): - self.__gradient = value - - # bg_from_y - @property - def bg_from_y(self) -> OptionalNumber: - return self._get_attr("bgFromY", data_type="float") - - @bg_from_y.setter - def bg_from_y(self, value: OptionalNumber): - self._set_attr("bgFromY", value) - - # bg_to_y - @property - def bg_to_y(self) -> OptionalNumber: - return self._get_attr("bgToY", data_type="float") - - @bg_to_y.setter - def bg_to_y(self, value: OptionalNumber): - self._set_attr("bgToY", value) - - # bg_color - @property - def bg_color(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bg_color.setter - def bg_color(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # bg_gradient - @property - def bg_gradient(self) -> Optional[Gradient]: - return self.__bg_gradient - - @bg_gradient.setter - def bg_gradient(self, value: Optional[Gradient]): - self.__bg_gradient = value - - # selected - @property - def selected(self) -> bool: - return self._get_attr("selected", data_type="bool", def_value=False) - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # show_tooltip - @property - def show_tooltip(self) -> bool: - return self._get_attr("showTooltip", data_type="bool", def_value=True) - - @show_tooltip.setter - def show_tooltip(self, value: Optional[bool]): - self._set_attr("showTooltip", value) - - # tooltip - @property - def tooltip(self) -> Optional[str]: - return self._get_attr("tooltip") - - @tooltip.setter - def tooltip(self, value: Optional[str]): - self._set_attr("tooltip", value) - - # tooltip_align - @property - def tooltip_align(self) -> Optional[TextAlign]: - return self.__tooltip_align - - @tooltip_align.setter - def tooltip_align(self, value: Optional[TextAlign]): - self.__tooltip_align = value - self._set_attr( - "tooltipAlign", value.value if isinstance(value, TextAlign) else value - ) - - # tooltip_style - @property - def tooltip_style(self): - return self.__tooltip_style - - @tooltip_style.setter - def tooltip_style(self, value: Optional[TextStyle]): - self.__tooltip_style = value diff --git a/sdk/python/packages/flet/src/flet/core/charts/bar_chart_rod_stack_item.py b/sdk/python/packages/flet/src/flet/core/charts/bar_chart_rod_stack_item.py deleted file mode 100644 index 563ef51137..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/bar_chart_rod_stack_item.py +++ /dev/null @@ -1,80 +0,0 @@ -from typing import Any, Optional - -from flet.core.border import BorderSide -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue - - -class BarChartRodStackItem(Control): - def __init__( - self, - from_y: OptionalNumber = None, - to_y: OptionalNumber = None, - color: Optional[ColorValue] = None, - border_side: Optional[BorderSide] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.from_y = from_y - self.to_y = to_y - self.color = color - self.border_side = border_side - - def _get_control_name(self): - return "stack_item" - - def before_update(self): - super().before_update() - self._set_attr_json("borderSide", self.__border_side) - - # from_y - @property - def from_y(self) -> OptionalNumber: - return self._get_attr("fromY", data_type="float") - - @from_y.setter - def from_y(self, value: OptionalNumber): - self._set_attr("fromY", value) - - # to_y - @property - def to_y(self) -> OptionalNumber: - return self._get_attr("toY", data_type="float") - - @to_y.setter - def to_y(self, value: OptionalNumber): - self._set_attr("toY", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # border_side - @property - def border_side(self) -> Optional[BorderSide]: - return self.__border_side - - @border_side.setter - def border_side(self, value: Optional[BorderSide]): - self.__border_side = value diff --git a/sdk/python/packages/flet/src/flet/core/charts/chart_axis.py b/sdk/python/packages/flet/src/flet/core/charts/chart_axis.py deleted file mode 100644 index c55f47ac6d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/chart_axis.py +++ /dev/null @@ -1,106 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.charts.chart_axis_label import ChartAxisLabel -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref - - -class ChartAxis(Control): - def __init__( - self, - title: Optional[Control] = None, - title_size: OptionalNumber = None, - show_labels: Optional[bool] = None, - labels: Optional[List[ChartAxisLabel]] = None, - labels_interval: OptionalNumber = None, - labels_size: OptionalNumber = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.title = title - self.title_size = title_size - self.show_labels = show_labels - self.labels = labels - self.labels_interval = labels_interval - self.labels_size = labels_size - - def _get_control_name(self): - return "axis" - - def _get_children(self): - children = [] - for label in self.__labels: - label._set_attr_internal("n", "l") - children.append(label) - if self.__title: - self.__title._set_attr_internal("n", "t") - children.append(self.__title) - return children - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # title_size - @property - def title_size(self) -> OptionalNumber: - return self._get_attr("titleSize", data_type="float") - - @title_size.setter - def title_size(self, value: OptionalNumber): - self._set_attr("titleSize", value) - - # show_labels - @property - def show_labels(self) -> bool: - return self._get_attr("showLabels", data_type="bool", def_value=True) - - @show_labels.setter - def show_labels(self, value: Optional[bool]): - self._set_attr("showLabels", value) - - # labels - @property - def labels(self): - return self.__labels - - @labels.setter - def labels(self, value): - self.__labels = value if value is not None else [] - - # labels_interval - @property - def labels_interval(self) -> float: - return self._get_attr("labelsInterval", data_type="float", def_value=1.0) - - @labels_interval.setter - def labels_interval(self, value: OptionalNumber): - self._set_attr("labelsInterval", value) - - # labels_size - @property - def labels_size(self) -> OptionalNumber: - return self._get_attr("labelsSize", data_type="float") - - @labels_size.setter - def labels_size(self, value: OptionalNumber): - self._set_attr("labelsSize", value) diff --git a/sdk/python/packages/flet/src/flet/core/charts/chart_axis_label.py b/sdk/python/packages/flet/src/flet/core/charts/chart_axis_label.py deleted file mode 100644 index 05fbd10b99..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/chart_axis_label.py +++ /dev/null @@ -1,57 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref - - -class ChartAxisLabel(Control): - def __init__( - self, - value: OptionalNumber = None, - label: Optional[Control] = None, - # - # Specific - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.value = value - self.label = label - - def _get_control_name(self): - return "l" - - def _get_children(self): - children = [] - if self.__label: - children.append(self.__label) - return children - - # value - @property - def value(self) -> float: - return self._get_attr("value", data_type="float", def_value=1.0) - - @value.setter - def value(self, value: OptionalNumber): - self._set_attr("value", value) - - # label - @property - def label(self) -> Optional[Control]: - return self.__label - - @label.setter - def label(self, value: Optional[Control]): - self.__label = value diff --git a/sdk/python/packages/flet/src/flet/core/charts/chart_grid_lines.py b/sdk/python/packages/flet/src/flet/core/charts/chart_grid_lines.py deleted file mode 100644 index 1d9e9d6363..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/chart_grid_lines.py +++ /dev/null @@ -1,12 +0,0 @@ -from dataclasses import dataclass -from typing import List, Optional - -from flet.core.types import ColorValue - - -@dataclass -class ChartGridLines: - interval: Optional[float] = None - color: Optional[ColorValue] = None - width: Optional[float] = None - dash_pattern: Optional[List[int]] = None diff --git a/sdk/python/packages/flet/src/flet/core/charts/chart_point_line.py b/sdk/python/packages/flet/src/flet/core/charts/chart_point_line.py deleted file mode 100644 index b1b942b2d2..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/chart_point_line.py +++ /dev/null @@ -1,11 +0,0 @@ -from dataclasses import dataclass, field -from typing import List, Optional - -from flet.core.types import ColorValue - - -@dataclass -class ChartPointLine: - color: Optional[ColorValue] = field(default=None) - width: Optional[float] = field(default=None) - dash_pattern: Optional[List[int]] = field(default=None) diff --git a/sdk/python/packages/flet/src/flet/core/charts/chart_point_shape.py b/sdk/python/packages/flet/src/flet/core/charts/chart_point_shape.py deleted file mode 100644 index 07130a5d2b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/chart_point_shape.py +++ /dev/null @@ -1,41 +0,0 @@ -from dataclasses import dataclass -from typing import Optional - -from flet.core.types import ColorValue, OptionalNumber - - -@dataclass -class ChartPointShape: - pass - - -@dataclass -class ChartCirclePoint(ChartPointShape): - color: Optional[ColorValue] = None - radius: OptionalNumber = None - stroke_color: Optional[ColorValue] = None - stroke_width: OptionalNumber = None - - def __post_init__(self): - self.type = "circle" - - -@dataclass -class ChartSquarePoint(ChartPointShape): - color: Optional[ColorValue] = None - size: OptionalNumber = None - stroke_color: Optional[ColorValue] = None - stroke_width: OptionalNumber = None - - def __post_init__(self): - self.type = "square" - - -@dataclass -class ChartCrossPoint(ChartPointShape): - color: Optional[ColorValue] = None - size: OptionalNumber = None - width: OptionalNumber = None - - def __post_init__(self): - self.type = "cross" diff --git a/sdk/python/packages/flet/src/flet/core/charts/line_chart.py b/sdk/python/packages/flet/src/flet/core/charts/line_chart.py deleted file mode 100644 index 74b3ae54b0..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/line_chart.py +++ /dev/null @@ -1,485 +0,0 @@ -import json -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import Border, BorderSide -from flet.core.charts.chart_axis import ChartAxis -from flet.core.charts.chart_grid_lines import ChartGridLines -from flet.core.charts.line_chart_data import LineChartData -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class LineChart(ConstrainedControl): - def __init__( - self, - data_series: Optional[List[LineChartData]] = None, - animate: Optional[AnimationValue] = None, - interactive: Optional[bool] = None, - point_line_start: OptionalNumber = None, - point_line_end: OptionalNumber = None, - bgcolor: Optional[ColorValue] = None, - tooltip_bgcolor: Optional[ColorValue] = None, - border: Optional[Border] = None, - horizontal_grid_lines: Optional[ChartGridLines] = None, - vertical_grid_lines: Optional[ChartGridLines] = None, - left_axis: Optional[ChartAxis] = None, - top_axis: Optional[ChartAxis] = None, - right_axis: Optional[ChartAxis] = None, - bottom_axis: Optional[ChartAxis] = None, - baseline_x: OptionalNumber = None, - min_x: OptionalNumber = None, - max_x: OptionalNumber = None, - baseline_y: OptionalNumber = None, - min_y: OptionalNumber = None, - max_y: OptionalNumber = None, - tooltip_rounded_radius: OptionalNumber = None, - tooltip_margin: OptionalNumber = None, - tooltip_padding: Optional[PaddingValue] = None, - tooltip_max_content_width: OptionalNumber = None, - tooltip_rotate_angle: OptionalNumber = None, - tooltip_tooltip_horizontal_offset: OptionalNumber = None, - tooltip_tooltip_border_side: Optional[BorderSide] = None, - tooltip_fit_inside_horizontally: Optional[bool] = None, - tooltip_fit_inside_vertically: Optional[bool] = None, - tooltip_show_on_top_of_chart_box_area: Optional[bool] = None, - on_chart_event: OptionalEventCallable["LineChartEvent"] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_chart_event = EventHandler(lambda e: LineChartEvent(e)) - self._add_event_handler("chart_event", self.__on_chart_event.get_handler()) - - self.data_series = data_series - self.animate = animate - self.interactive = interactive - self.point_line_start = point_line_start - self.point_line_end = point_line_end - self.bgcolor = bgcolor - self.tooltip_bgcolor = tooltip_bgcolor - self.border = border - self.horizontal_grid_lines = horizontal_grid_lines - self.vertical_grid_lines = vertical_grid_lines - self.left_axis = left_axis - self.top_axis = top_axis - self.right_axis = right_axis - self.bottom_axis = bottom_axis - self.baseline_x = baseline_x - self.baseline_y = baseline_y - self.min_x = min_x - self.max_x = max_x - self.min_y = min_y - self.max_y = max_y - self.on_chart_event = on_chart_event - self.tooltip_rounded_radius = tooltip_rounded_radius - self.tooltip_margin = tooltip_margin - self.tooltip_padding = tooltip_padding - self.tooltip_max_content_width = tooltip_max_content_width - self.tooltip_rotate_angle = tooltip_rotate_angle - self.tooltip_horizontal_offset = tooltip_tooltip_horizontal_offset - self.tooltip_border_side = tooltip_tooltip_border_side - self.tooltip_fit_inside_horizontally = tooltip_fit_inside_horizontally - self.tooltip_fit_inside_vertically = tooltip_fit_inside_vertically - self.tooltip_show_on_top_of_chart_box_area = ( - tooltip_show_on_top_of_chart_box_area - ) - - def _get_control_name(self): - return "linechart" - - def before_update(self): - super().before_update() - self._set_attr_json("horizontalGridLines", self.__horizontal_grid_lines) - self._set_attr_json("verticalGridLines", self.__vertical_grid_lines) - self._set_attr_json("animate", self.__animate) - self._set_attr_json("border", self.__border) - self._set_attr_json("tooltipBorderSide", self.__tooltip_border_side) - self._set_attr_json("tooltipPadding", self.__tooltip_padding) - - def _get_children(self): - children = [] - for ds in self.__data_series: - children.append(ds) - if self.__left_axis: - self.__left_axis._set_attr_internal("n", "l") - children.append(self.__left_axis) - if self.__top_axis: - self.__top_axis._set_attr_internal("n", "t") - children.append(self.__top_axis) - if self.__right_axis: - self.__right_axis._set_attr_internal("n", "r") - children.append(self.__right_axis) - if self.__bottom_axis: - self.__bottom_axis._set_attr_internal("n", "b") - children.append(self.__bottom_axis) - return children - - # data_series - @property - def data_series(self): - return self.__data_series - - @data_series.setter - def data_series(self, value): - self.__data_series = value if value is not None else [] - - # animate - @property - def animate(self) -> AnimationValue: - return self.__animate - - @animate.setter - def animate(self, value: AnimationValue): - self.__animate = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # interactive - @property - def interactive(self) -> bool: - return self._get_attr("interactive", data_type="bool", def_value=True) - - @interactive.setter - def interactive(self, value: Optional[bool]): - self._set_attr("interactive", value) - - # point_line_start - @property - def point_line_start(self) -> OptionalNumber: - return self._get_attr("pointLineStart", data_type="float") - - @point_line_start.setter - def point_line_start(self, value: OptionalNumber): - self._set_attr("pointLineStart", value) - - # point_line_end - @property - def point_line_end(self) -> OptionalNumber: - return self._get_attr("pointLineEnd", data_type="float") - - @point_line_end.setter - def point_line_end(self, value: OptionalNumber): - self._set_attr("pointLineEnd", value) - - # tooltip_bgcolor - @property - def tooltip_bgcolor(self) -> Optional[str]: - return self.__tooltip_bgcolor - - @tooltip_bgcolor.setter - def tooltip_bgcolor(self, value: Optional[str]): - self.__tooltip_bgcolor = value - self._set_enum_attr("tooltipBgcolor", value, ColorEnums) - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # horizontal_grid_lines - @property - def horizontal_grid_lines(self) -> Optional[ChartGridLines]: - return self.__horizontal_grid_lines - - @horizontal_grid_lines.setter - def horizontal_grid_lines(self, value: Optional[ChartGridLines]): - self.__horizontal_grid_lines = value - - # vertical_grid_lines - @property - def vertical_grid_lines(self) -> Optional[ChartGridLines]: - return self.__vertical_grid_lines - - @vertical_grid_lines.setter - def vertical_grid_lines(self, value: Optional[ChartGridLines]): - self.__vertical_grid_lines = value - - # left_axis - @property - def left_axis(self) -> Optional[ChartAxis]: - return self.__left_axis - - @left_axis.setter - def left_axis(self, value: Optional[ChartAxis]): - self.__left_axis = value - - # top_axis - @property - def top_axis(self) -> Optional[ChartAxis]: - return self.__top_axis - - @top_axis.setter - def top_axis(self, value: Optional[ChartAxis]): - self.__top_axis = value - - # right_axis - @property - def right_axis(self) -> Optional[ChartAxis]: - return self.__right_axis - - @right_axis.setter - def right_axis(self, value: Optional[ChartAxis]): - self.__right_axis = value - - # bottom_axis - @property - def bottom_axis(self) -> Optional[ChartAxis]: - return self.__bottom_axis - - @bottom_axis.setter - def bottom_axis(self, value: Optional[ChartAxis]): - self.__bottom_axis = value - - # baseline_x - @property - def baseline_x(self) -> OptionalNumber: - return self._get_attr("baselinex", data_type="float") - - @baseline_x.setter - def baseline_x(self, value: OptionalNumber): - self._set_attr("baselineX", value) - - # baseline_y - @property - def baseline_y(self) -> OptionalNumber: - return self._get_attr("baselineY", data_type="float") - - @baseline_y.setter - def baseline_y(self, value: OptionalNumber): - self._set_attr("baselineY", value) - - # min_x - @property - def min_x(self) -> OptionalNumber: - return self._get_attr("minX", data_type="float") - - @min_x.setter - def min_x(self, value: OptionalNumber): - self._set_attr("minX", value) - - # max_x - @property - def max_x(self) -> OptionalNumber: - return self._get_attr("maxX", data_type="float") - - @max_x.setter - def max_x(self, value: OptionalNumber): - self._set_attr("maxX", value) - - # min_y - @property - def min_y(self) -> OptionalNumber: - return self._get_attr("minY", data_type="float") - - @min_y.setter - def min_y(self, value: OptionalNumber): - self._set_attr("minY", value) - - # max_y - @property - def max_y(self) -> OptionalNumber: - return self._get_attr("maxY", data_type="float") - - @max_y.setter - def max_y(self, value: OptionalNumber): - self._set_attr("maxY", value) - - # tooltip_rounded_radius - @property - def tooltip_rounded_radius(self) -> OptionalNumber: - return self._get_attr("tooltipRoundedRadius", data_type="float", def_value=4) - - @tooltip_rounded_radius.setter - def tooltip_rounded_radius(self, value: OptionalNumber): - self._set_attr("tooltipRoundedRadius", value) - - # tooltip_margin - @property - def tooltip_margin(self) -> OptionalNumber: - return self._get_attr("tooltipMargin", data_type="float", def_value=16) - - @tooltip_margin.setter - def tooltip_margin(self, value: OptionalNumber): - self._set_attr("tooltipMargin", value) - - # tooltip_padding - @property - def tooltip_padding(self) -> Optional[PaddingValue]: - return self.__tooltip_padding - - @tooltip_padding.setter - def tooltip_padding(self, value: Optional[PaddingValue]): - self.__tooltip_padding = value - - # tooltip_max_content_width - @property - def tooltip_max_content_width(self) -> OptionalNumber: - return self._get_attr( - "tooltipMaxContentWidth", data_type="float", def_value=120 - ) - - @tooltip_max_content_width.setter - def tooltip_max_content_width(self, value: OptionalNumber): - self._set_attr("tooltipMaxContentWidth", value) - - # tooltip_rotate_angle - @property - def tooltip_rotate_angle(self) -> OptionalNumber: - return self._get_attr("tooltipRotateAngle", data_type="float", def_value=0.0) - - @tooltip_rotate_angle.setter - def tooltip_rotate_angle(self, value: OptionalNumber): - self._set_attr("tooltipRotateAngle", value) - - # tooltip_fit_inside_vertically - @property - def tooltip_fit_inside_vertically(self) -> Optional[bool]: - return self._get_attr( - "tooltipFitInsideVertically", data_type="bool", def_value=False - ) - - @tooltip_fit_inside_vertically.setter - def tooltip_fit_inside_vertically(self, value: Optional[bool]): - self._set_attr("tooltipFitInsideVertically", value) - - # tooltip_fit_inside_horizontally - @property - def tooltip_fit_inside_horizontally(self) -> Optional[bool]: - return self._get_attr( - "tooltipFitInsideHorizontally", data_type="bool", def_value=False - ) - - @tooltip_fit_inside_horizontally.setter - def tooltip_fit_inside_horizontally(self, value: Optional[bool]): - self._set_attr("tooltipFitInsideHorizontally", value) - - # tooltip_show_on_top_of_chart_box_area - @property - def tooltip_show_on_top_of_chart_box_area(self) -> Optional[bool]: - return self._get_attr( - "tooltipShowOnTopOfChartBoxArea", data_type="bool", def_value=False - ) - - @tooltip_show_on_top_of_chart_box_area.setter - def tooltip_show_on_top_of_chart_box_area(self, value: Optional[bool]): - self._set_attr("tooltipShowOnTopOfChartBoxArea", value) - - # tooltip_border_side - @property - def tooltip_border_side(self) -> Optional[BorderSide]: - return self.__tooltip_border_side - - @tooltip_border_side.setter - def tooltip_border_side(self, value: Optional[BorderSide]): - self.__tooltip_border_side = value - - # on_chart_event - @property - def on_chart_event(self) -> OptionalEventCallable["LineChartEvent"]: - return self.__on_chart_event.handler - - @on_chart_event.setter - def on_chart_event(self, handler: OptionalEventCallable["LineChartEvent"]): - self.__on_chart_event.handler = handler - self._set_attr("onChartEvent", True if handler is not None else None) - - -class LineChartEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.type: str = d.get("type") - self.spots: List[LineChartEventSpot] = d.get("spots") - - -class LineChartEventSpot: - def __init__(self, bar_index, spot_index): - self.bar_index: int = bar_index - self.spot_index: int = spot_index diff --git a/sdk/python/packages/flet/src/flet/core/charts/line_chart_data.py b/sdk/python/packages/flet/src/flet/core/charts/line_chart_data.py deleted file mode 100644 index f13494f9ed..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/line_chart_data.py +++ /dev/null @@ -1,289 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.box import BoxShadow -from flet.core.charts.chart_point_line import ChartPointLine -from flet.core.charts.chart_point_shape import ChartPointShape -from flet.core.charts.line_chart_data_point import LineChartDataPoint -from flet.core.control import Control, OptionalNumber -from flet.core.gradients import Gradient -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue - - -class LineChartData(Control): - def __init__( - self, - data_points: Optional[List[LineChartDataPoint]] = None, - curved: Optional[bool] = None, - color: Optional[ColorValue] = None, - gradient: Optional[Gradient] = None, - stroke_width: OptionalNumber = None, - stroke_cap_round: Optional[bool] = None, - prevent_curve_over_shooting: Optional[bool] = None, - prevent_curve_over_shooting_threshold: OptionalNumber = None, - dash_pattern: Optional[List[int]] = None, - shadow: Optional[BoxShadow] = None, - above_line_bgcolor: Optional[ColorValue] = None, - above_line_gradient: Optional[Gradient] = None, - above_line_cutoff_y: OptionalNumber = None, - above_line: Optional[ChartPointLine] = None, - below_line_bgcolor: Optional[ColorValue] = None, - below_line_gradient: Optional[Gradient] = None, - below_line_cutoff_y: OptionalNumber = None, - below_line: Optional[ChartPointLine] = None, - selected_below_line: Union[None, bool, ChartPointLine] = None, - point: Union[None, bool, ChartPointShape] = None, - selected_point: Union[None, bool, ChartPointShape] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.data_points = data_points - self.curved = curved - self.color = color - self.gradient = gradient - self.stroke_width = stroke_width - self.stroke_cap_round = stroke_cap_round - self.prevent_curve_over_shooting = prevent_curve_over_shooting - self.prevent_curve_over_shooting_threshold = ( - prevent_curve_over_shooting_threshold - ) - self.shadow = shadow - self.dash_pattern = dash_pattern - self.above_line_bgcolor = above_line_bgcolor - self.above_line_gradient = above_line_gradient - self.above_line_cutoff_y = above_line_cutoff_y - self.above_line = above_line - self.below_line_bgcolor = below_line_bgcolor - self.below_line_gradient = below_line_gradient - self.below_line_cutoff_y = below_line_cutoff_y - self.below_line = below_line - self.selected_below_line = selected_below_line - self.point = point - self.selected_point = selected_point - - def _get_control_name(self): - return "data" - - def before_update(self): - super().before_update() - self._set_attr_json("gradient", self.__gradient) - self._set_attr_json("shadow", self.__shadow) - self._set_attr_json("point", self.__point) - self._set_attr_json("selectedPoint", self.__selected_point) - self._set_attr_json("dashPattern", self.__dash_pattern) - self._set_attr_json("aboveLineGradient", self.__above_line_gradient) - self._set_attr_json("belowLineGradient", self.__below_line_gradient) - self._set_attr_json("aboveLine", self.__above_line) - self._set_attr_json("belowLine", self.__below_line) - self._set_attr_json("selectedBelowLine", self.__selected_below_line) - - def _get_children(self): - return self.__data_points - - # data_points - @property - def data_points(self): - return self.__data_points - - @data_points.setter - def data_points(self, value): - self.__data_points = value if value is not None else [] - - # stroke_width - @property - def stroke_width(self) -> float: - return self._get_attr("strokeWidth", data_type="float", def_value=1.0) - - @stroke_width.setter - def stroke_width(self, value: OptionalNumber): - self._set_attr("strokeWidth", value) - - # curved - @property - def curved(self) -> bool: - return self._get_attr("curved", data_type="bool", def_value=False) - - @curved.setter - def curved(self, value: Optional[bool]): - self._set_attr("curved", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # gradient - @property - def gradient(self) -> Optional[Gradient]: - return self.__gradient - - @gradient.setter - def gradient(self, value: Optional[Gradient]): - self.__gradient = value - - # stroke_cap_round - @property - def stroke_cap_round(self) -> bool: - return self._get_attr("strokeCapRound", data_type="bool", def_value=False) - - @stroke_cap_round.setter - def stroke_cap_round(self, value: Optional[bool]): - self._set_attr("strokeCapRound", value) - - # prevent_curve_over_shooting - @property - def prevent_curve_over_shooting(self) -> bool: - return self._get_attr( - "preventCurveOverShooting", data_type="bool", def_value=False - ) - - @prevent_curve_over_shooting.setter - def prevent_curve_over_shooting(self, value: Optional[bool]): - self._set_attr("preventCurveOverShooting", value) - - # prevent_curve_over_shooting_threshold - @property - def prevent_curve_over_shooting_threshold(self) -> OptionalNumber: - return self._get_attr("preventCurveOverShootingThreshold", data_type="float") - - @prevent_curve_over_shooting_threshold.setter - def prevent_curve_over_shooting_threshold(self, value: OptionalNumber): - self._set_attr("preventCurveOverShootingThreshold", value) - - # dash_pattern - @property - def dash_pattern(self): - return self.__dash_pattern - - @dash_pattern.setter - def dash_pattern(self, value: Optional[List[int]]): - self.__dash_pattern = value - - # shadow - @property - def shadow(self): - return self.__shadow - - @shadow.setter - def shadow(self, value: Optional[BoxShadow]): - self.__shadow = value - - # point - @property - def point(self): - return self.__point - - @point.setter - def point(self, value: Union[None, bool, ChartPointShape]): - self.__point = value - - # selected_point - @property - def selected_point(self): - return self.__selected_point - - @selected_point.setter - def selected_point(self, value: Union[None, bool, ChartPointShape]): - self.__selected_point = value - - # above_line_bgcolor - @property - def above_line_bgcolor(self) -> Optional[str]: - return self.__above_line_bgcolor - - @above_line_bgcolor.setter - def above_line_bgcolor(self, value: Optional[str]): - self.__above_line_bgcolor = value - self._set_enum_attr("aboveLineBgcolor", value, ColorEnums) - - # above_line_gradient - @property - def above_line_gradient(self) -> Optional[Gradient]: - return self.__above_line_gradient - - @above_line_gradient.setter - def above_line_gradient(self, value: Optional[Gradient]): - self.__above_line_gradient = value - - # above_line_cutoff_y - @property - def above_line_cutoff_y(self) -> OptionalNumber: - return self._get_attr("aboveLineCutoffY", data_type="float") - - @above_line_cutoff_y.setter - def above_line_cutoff_y(self, value: OptionalNumber): - self._set_attr("aboveLineCutoffY", value) - - # above_line - @property - def above_line(self) -> Optional[ChartPointLine]: - return self.__above_line - - @above_line.setter - def above_line(self, value: Optional[ChartPointLine]): - self.__above_line = value - - # below_line_bgcolor - @property - def below_line_bgcolor(self) -> Optional[str]: - return self.__below_line_bgcolor - - @below_line_bgcolor.setter - def below_line_bgcolor(self, value: Optional[str]): - self.__below_line_bgcolor = value - self._set_enum_attr("belowLineBgcolor", value, ColorEnums) - - # below_line_gradient - @property - def below_line_gradient(self) -> Optional[Gradient]: - return self.__below_line_gradient - - @below_line_gradient.setter - def below_line_gradient(self, value: Optional[Gradient]): - self.__below_line_gradient = value - - # below_line_cutoff_y - @property - def below_line_cutoff_y(self) -> OptionalNumber: - return self._get_attr("belowLineCutoffY", data_type="float") - - @below_line_cutoff_y.setter - def below_line_cutoff_y(self, value: OptionalNumber): - self._set_attr("belowLineCutoffY", value) - - # below_line - @property - def below_line(self) -> Optional[ChartPointLine]: - return self.__below_line - - @below_line.setter - def below_line(self, value: Optional[ChartPointLine]): - self.__below_line = value - - # selected_below_line - @property - def selected_below_line(self) -> Union[None, bool, ChartPointLine]: - return self.__selected_below_line - - @selected_below_line.setter - def selected_below_line(self, value: Union[None, bool, ChartPointLine]): - self.__selected_below_line = value diff --git a/sdk/python/packages/flet/src/flet/core/charts/line_chart_data_point.py b/sdk/python/packages/flet/src/flet/core/charts/line_chart_data_point.py deleted file mode 100644 index fe3f36f17d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/line_chart_data_point.py +++ /dev/null @@ -1,182 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.badge import BadgeValue -from flet.core.charts.chart_point_line import ChartPointLine -from flet.core.charts.chart_point_shape import ChartPointShape -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import TextAlign - - -class LineChartDataPoint(Control): - def __init__( - self, - x: OptionalNumber = None, - y: OptionalNumber = None, - selected: Optional[bool] = None, - show_tooltip: Optional[bool] = None, - tooltip: Optional[str] = None, - tooltip_style: Optional[TextStyle] = None, - tooltip_align: Optional[TextAlign] = None, - point: Union[None, bool, ChartPointShape] = None, - selected_point: Union[None, bool, ChartPointShape] = None, - show_above_line: Optional[bool] = None, - show_below_line: Optional[bool] = None, - selected_below_line: Union[None, bool, ChartPointLine] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - badge: Optional[BadgeValue] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - badge=badge, - ) - - self.x = x - self.y = y - self.selected = selected - self.show_tooltip = show_tooltip - self.tooltip = tooltip - self.tooltip_align = tooltip_align - self.tooltip_style = tooltip_style - self.point = point - self.selected_point = selected_point - self.show_above_line = show_above_line - self.show_below_line = show_below_line - self.selected_below_line = selected_below_line - - def _get_control_name(self): - return "p" - - def before_update(self): - super().before_update() - self._set_attr_json("tooltipStyle", self.__tooltip_style) - self._set_attr_json("point", self.__point) - self._set_attr_json("selectedPoint", self.__selected_point) - self._set_attr_json("selectedBelowLine", self.__selected_below_line) - - def _get_children(self): - children = [] - return children - - # x - @property - def x(self) -> float: - return self._get_attr("x", data_type="float", def_value=0.0) - - @x.setter - def x(self, value: OptionalNumber): - self._set_attr("x", value) - - # y - @property - def y(self) -> float: - return self._get_attr("y", data_type="float", def_value=0.0) - - @y.setter - def y(self, value: OptionalNumber): - self._set_attr("y", value) - - # selected - @property - def selected(self) -> bool: - return self._get_attr("selected", data_type="bool", def_value=False) - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # show_tooltip - @property - def show_tooltip(self) -> bool: - return self._get_attr("showTooltip", data_type="bool", def_value=True) - - @show_tooltip.setter - def show_tooltip(self, value: Optional[bool]): - self._set_attr("showTooltip", value) - - # tooltip - @property - def tooltip(self) -> Optional[str]: - return self._get_attr("tooltip") - - @tooltip.setter - def tooltip(self, value: Optional[str]): - self._set_attr("tooltip", value) - - # tooltip_align - @property - def tooltip_align(self) -> Optional[TextAlign]: - return self.__tooltip_align - - @tooltip_align.setter - def tooltip_align(self, value: Optional[TextAlign]): - self.__tooltip_align = value - self._set_attr( - "tooltipAlign", value.value if isinstance(value, TextAlign) else value - ) - - # tooltip_style - @property - def tooltip_style(self): - return self.__tooltip_style - - @tooltip_style.setter - def tooltip_style(self, value: Optional[TextStyle]): - self.__tooltip_style = value - - # point - @property - def point(self): - return self.__point - - @point.setter - def point(self, value: Union[None, bool, ChartPointShape]): - self.__point = value - - # selected_point - @property - def selected_point(self): - return self.__selected_point - - @selected_point.setter - def selected_point(self, value: Union[None, bool, ChartPointShape]): - self.__selected_point = value - - # show_above_line - @property - def show_above_line(self) -> bool: - return self._get_attr("showAboveLine", data_type="bool", def_value=True) - - @show_above_line.setter - def show_above_line(self, value: Optional[bool]): - self._set_attr("showAboveLine", value) - - # show_below_line - @property - def show_below_line(self) -> bool: - return self._get_attr("showBelowLine", data_type="bool", def_value=True) - - @show_below_line.setter - def show_below_line(self, value: Optional[bool]): - self._set_attr("showBelowLine", value) - - # selected_below_line - @property - def selected_below_line(self) -> Union[None, bool, ChartPointLine]: - return self.__selected_below_line - - @selected_below_line.setter - def selected_below_line(self, value: Union[None, bool, ChartPointLine]): - self.__selected_below_line = value diff --git a/sdk/python/packages/flet/src/flet/core/charts/pie_chart.py b/sdk/python/packages/flet/src/flet/core/charts/pie_chart.py deleted file mode 100644 index 70370a4bd4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/pie_chart.py +++ /dev/null @@ -1,215 +0,0 @@ -import json -from enum import Enum -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.charts.pie_chart_section import PieChartSection -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class PieChart(ConstrainedControl): - def __init__( - self, - sections: Optional[List[PieChartSection]] = None, - center_space_color: Optional[ColorValue] = None, - center_space_radius: OptionalNumber = None, - sections_space: OptionalNumber = None, - start_degree_offset: OptionalNumber = None, - animate: Optional[AnimationValue] = None, - on_chart_event: OptionalEventCallable["PieChartEvent"] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_chart_event = EventHandler(lambda e: PieChartEvent(e)) - self._add_event_handler("chart_event", self.__on_chart_event.get_handler()) - - self.sections = sections - self.center_space_color = center_space_color - self.center_space_radius = center_space_radius - self.sections_space = sections_space - self.start_degree_offset = start_degree_offset - self.animate = animate - self.on_chart_event = on_chart_event - - def _get_control_name(self): - return "piechart" - - def before_update(self): - super().before_update() - self._set_attr_json("animate", self.__animate) - - def _get_children(self): - children = [] - for ds in self.__sections: - children.append(ds) - return children - - # sections - @property - def sections(self): - return self.__sections - - @sections.setter - def sections(self, value): - self.__sections = value if value is not None else [] - - # center_space_color - @property - def center_space_color(self) -> Optional[ColorValue]: - return self.__center_space_color - - @center_space_color.setter - def center_space_color(self, value: Optional[ColorValue]): - self.__center_space_color = value - self._set_enum_attr("centerSpaceColor", value, ColorEnums) - - # center_space_radius - @property - def center_space_radius(self) -> OptionalNumber: - return self._get_attr("centerSpaceRadius", data_type="float") - - @center_space_radius.setter - def center_space_radius(self, value: OptionalNumber): - self._set_attr("centerSpaceRadius", value) - - # sections_space - @property - def sections_space(self) -> OptionalNumber: - return self._get_attr("sectionsSpace", data_type="float") - - @sections_space.setter - def sections_space(self, value: OptionalNumber): - self._set_attr("sectionsSpace", value) - - # start_degree_offset - @property - def start_degree_offset(self) -> OptionalNumber: - return self._get_attr("startDegreeOffset", data_type="float") - - @start_degree_offset.setter - def start_degree_offset(self, value: OptionalNumber): - self._set_attr("startDegreeOffset", value) - - # animate - @property - def animate(self) -> AnimationValue: - return self.__animate - - @animate.setter - def animate(self, value: AnimationValue): - self.__animate = value - - # on_chart_event - @property - def on_chart_event(self) -> OptionalEventCallable["PieChartEvent"]: - return self.__on_chart_event.handler - - @on_chart_event.setter - def on_chart_event(self, handler: OptionalEventCallable["PieChartEvent"]): - self.__on_chart_event.handler = handler - self._set_attr("onChartEvent", True if handler is not None else None) - - -class PieChartEventType(Enum): - POINTER_ENTER = "pointerEnter" - POINTER_EXIT = "pointerExit" - POINTER_HOVER = "pointerHover" - PAN_CANCEL = "panCancel" - PAN_DOWN = "panDown" - PAN_END = "panEnd" - PAN_START = "panStart" - PAN_UPDATE = "panUpdate" - LONG_PRESS_END = "longPressEnd" - LONG_PRESS_MOVE_UPDATE = "longPressMoveUpdate" - LONG_PRESS_START = "longPressStart" - TAP_CANCEL = "tapCancel" - TAP_DOWN = "tapDown" - TAP_UP = "tapUp" - UNDEFINED = "undefined" - - -class PieChartEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.type: PieChartEventType = PieChartEventType(d.get("type")) - self.section_index: int = d.get("section_index") - self.local_x: Optional[float] = d.get("lx") - self.local_y: Optional[float] = d.get("ly") - # self.radius: float = d["radius"] - # self.angle: float = d["angle"] diff --git a/sdk/python/packages/flet/src/flet/core/charts/pie_chart_section.py b/sdk/python/packages/flet/src/flet/core/charts/pie_chart_section.py deleted file mode 100644 index 8168011f64..0000000000 --- a/sdk/python/packages/flet/src/flet/core/charts/pie_chart_section.py +++ /dev/null @@ -1,144 +0,0 @@ -from typing import Any, Optional - -from flet.core.border import BorderSide -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ColorEnums, ColorValue - - -class PieChartSection(Control): - def __init__( - self, - value: OptionalNumber = None, - radius: OptionalNumber = None, - color: Optional[ColorValue] = None, - border_side: Optional[BorderSide] = None, - title: Optional[str] = None, - title_style: Optional[TextStyle] = None, - title_position: OptionalNumber = None, - badge: Optional[Control] = None, - badge_position: OptionalNumber = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.value = value - self.radius = radius - self.color = color - self.border_side = border_side - self.title = title - self.title_style = title_style - self.title_position = title_position - self.badge = badge - self.badge_position = badge_position - - def _get_control_name(self): - return "section" - - def before_update(self): - super().before_update() - self._set_attr_json("borderSide", self.__border_side) - self._set_attr_json("titleStyle", self.__title_style) - - def _get_children(self): - children = [] - if self.__badge: - self.__badge._set_attr_internal("n", "badge") - children.append(self.__badge) - return children - - # value - @property - def value(self) -> OptionalNumber: - return self._get_attr("value", data_type="float") - - @value.setter - def value(self, value: OptionalNumber): - self._set_attr("value", value) - - # radius - @property - def radius(self) -> OptionalNumber: - return self._get_attr("radius", data_type="float") - - @radius.setter - def radius(self, value: OptionalNumber): - self._set_attr("radius", value) - - # border_side - @property - def border_side(self) -> Optional[BorderSide]: - return self.__border_side - - @border_side.setter - def border_side(self, value: Optional[BorderSide]): - self.__border_side = value - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # badge - @property - def badge(self) -> Optional[Control]: - return self.__badge - - @badge.setter - def badge(self, value: Optional[Control]): - self.__badge = value - - # badge_position - @property - def badge_position(self) -> OptionalNumber: - return self._get_attr("badgePosition", data_type="float") - - @badge_position.setter - def badge_position(self, value: OptionalNumber): - self._set_attr("badgePosition", value) - - # title - @property - def title(self): - return self._get_attr("title") - - @title.setter - def title(self, value: Optional[str]): - self._set_attr("title", value) - - # title_style - @property - def title_style(self): - return self.__title_style - - @title_style.setter - def title_style(self, value: Optional[TextStyle]): - self.__title_style = value - - # title_position - @property - def title_position(self) -> float: - return self._get_attr("titlePosition", data_type="float", def_value=1.0) - - @title_position.setter - def title_position(self, value: OptionalNumber): - self._set_attr("titlePosition", value) diff --git a/sdk/python/packages/flet/src/flet/core/checkbox.py b/sdk/python/packages/flet/src/flet/core/checkbox.py deleted file mode 100644 index cbf61cd388..0000000000 --- a/sdk/python/packages/flet/src/flet/core/checkbox.py +++ /dev/null @@ -1,397 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import BorderSide -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - LabelPosition, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - VisualDensity, -) - - -class Checkbox(ConstrainedControl, AdaptiveControl): - """ - Checkbox allows to select one or more items from a group, or switch between two mutually exclusive options (checked or unchecked, on or off). - - Example: - ``` - import flet as ft - - def main(page): - def button_clicked(e): - t.value = ( - f"Checkboxes values are: {c1.value}, {c2.value}, {c3.value}, {c4.value}, {c5.value}." - ) - page.update() - - t = ft.Text() - c1 = ft.Checkbox(label="Unchecked by default checkbox", value=False) - c2 = ft.Checkbox(label="Undefined by default tristate checkbox", tristate=True) - c3 = ft.Checkbox(label="Checked by default checkbox", value=True) - c4 = ft.Checkbox(label="Disabled checkbox", disabled=True) - c5 = ft.Checkbox( - label="Checkbox with rendered label_position='left'", label_position=ft.LabelPosition.LEFT - ) - b = ft.ElevatedButton(text="Submit", on_click=button_clicked) - page.add(c1, c2, c3, c4, c5, b, t) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/checkbox - """ - - def __init__( - self, - label: Optional[Union[str, Control]] = None, - value: Optional[bool] = None, - label_position: Optional[LabelPosition] = None, - label_style: Optional[TextStyle] = None, - tristate: Optional[bool] = None, - autofocus: Optional[bool] = None, - fill_color: ControlStateValue[ColorValue] = None, - overlay_color: ControlStateValue[ColorValue] = None, - check_color: Optional[ColorValue] = None, - active_color: Optional[ColorValue] = None, - hover_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - semantics_label: Optional[str] = None, - shape: Optional[OutlinedBorder] = None, - splash_radius: OptionalNumber = None, - border_side: ControlStateValue[BorderSide] = None, - is_error: Optional[bool] = None, - visual_density: Optional[VisualDensity] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_change: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.value = value - self.tristate = tristate - self.label = label - self.label_style = label_style - self.label_position = label_position - self.autofocus = autofocus - self.check_color = check_color - self.fill_color = fill_color - self.focus_color = focus_color - self.hover_color = hover_color - self.overlay_color = overlay_color - self.active_color = active_color - self.semantics_label = semantics_label - self.shape = shape - self.splash_radius = splash_radius - self.border_side = border_side - self.is_error = is_error - self.on_change = on_change - self.on_focus = on_focus - self.on_blur = on_blur - self.visual_density = visual_density - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "checkbox" - - def before_update(self): - super().before_update() - self._set_attr_json("fillColor", self.__fill_color, wrap_attr_dict=True) - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json("borderSide", self.__border_side, wrap_attr_dict=True) - self._set_attr_json("shape", self.__shape) - self._set_attr_json("labelStyle", self.__label_style) - - def _get_children(self): - return [self.__label] if isinstance(self.__label, Control) else [] - - # value - @property - def value(self) -> Optional[bool]: - return self._get_attr( - "value", data_type="bool?", def_value=False if not self.tristate else None - ) - - @value.setter - def value(self, value: Optional[bool]): - self._set_attr("value", value) - - # tristate - @property - def tristate(self) -> bool: - return self._get_attr("tristate", data_type="bool", def_value=False) - - @tristate.setter - def tristate(self, value: Optional[bool]): - self._set_attr("tristate", value) - - # label - @property - def label(self) -> Optional[Union[str, Control]]: - return self.__label - - @label.setter - def label(self, value: Optional[Union[str, Control]]): - self.__label = value - if not isinstance(value, Control): - self._set_attr("label", value) - - # label_position - @property - def label_position(self) -> Optional[LabelPosition]: - return self.__label_position - - @label_position.setter - def label_position(self, value: Optional[LabelPosition]): - self.__label_position = value - self._set_enum_attr("labelPosition", value, LabelPosition) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # visual_density - @property - def visual_density(self) -> Optional[VisualDensity]: - return self.__visual_density - - @visual_density.setter - def visual_density(self, value: Optional[VisualDensity]): - self.__visual_density = value - self._set_enum_attr("visualDensity", value, VisualDensity) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # check_color - @property - def check_color(self) -> Optional[ColorValue]: - return self.__check_color - - @check_color.setter - def check_color(self, value: Optional[ColorValue]): - self.__check_color = value - self._set_enum_attr("checkColor", value, ColorEnums) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # hover_color - @property - def hover_color(self) -> Optional[ColorValue]: - return self.__hover_color - - @hover_color.setter - def hover_color(self, value: Optional[ColorValue]): - self.__hover_color = value - self._set_enum_attr("hoverColor", value, ColorEnums) - - # fill_color - @property - def fill_color(self) -> ControlStateValue[ColorValue]: - return self.__fill_color - - @fill_color.setter - def fill_color(self, value: ControlStateValue[ColorValue]): - self.__fill_color = value - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[ColorValue]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[ColorValue]): - self.__overlay_color = value - - # label_style - @property - def label_style(self) -> Optional[TextStyle]: - return self.__label_style - - @label_style.setter - def label_style(self, value: Optional[TextStyle]): - self.__label_style = value - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # splash_radius - @property - def splash_radius(self) -> Optional[float]: - return self._get_attr("splashRadius", data_type="float") - - @splash_radius.setter - def splash_radius(self, value: OptionalNumber): - self._set_attr("splashRadius", value) - - # is_error - @property - def is_error(self) -> bool: - return self._get_attr("isError", data_type="bool", def_value=False) - - @is_error.setter - def is_error(self, value: Optional[bool]): - self._set_attr("isError", value) - - # border_side - @property - def border_side(self) -> ControlStateValue[BorderSide]: - return self.__border_side - - @border_side.setter - def border_side(self, value: ControlStateValue[BorderSide]): - self.__border_side = value - - # on_change - @property - def on_change(self): - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_focus - @property - def on_focus(self): - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self): - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/chip.py b/sdk/python/packages/flet/src/flet/core/chip.py deleted file mode 100644 index b3e414e340..0000000000 --- a/sdk/python/packages/flet/src/flet/core/chip.py +++ /dev/null @@ -1,583 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationStyle, AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import BorderSide -from flet.core.box import BoxConstraints -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - ControlStateValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - VisualDensity, -) - - -class Chip(ConstrainedControl): - """ - Chips are compact elements that represent an attribute, text, entity, or action. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - def save_to_favorites_clicked(e): - e.control.label.value = "Saved to favorites" - e.control.leading = ft.Icon(ft.icons.FAVORITE_OUTLINED) - e.control.disabled = True - page.update() - - def open_google_maps(e): - page.launch_url("https://maps.google.com") - page.update() - - save_to_favourites = ft.Chip( - label=ft.Text("Save to favourites"), - leading=ft.Icon(ft.icons.FAVORITE_BORDER_OUTLINED), - bgcolor=ft.colors.GREEN_200, - disabled_color=ft.colors.GREEN_100, - autofocus=True, - on_click=save_to_favorites_clicked, - ) - - open_in_maps = ft.Chip( - label=ft.Text("9 min walk"), - leading=ft.Icon(ft.icons.MAP_SHARP), - bgcolor=ft.colors.GREEN_200, - on_click=open_google_maps, - ) - - page.add(ft.Row([save_to_favourites, open_in_maps])) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/chip - """ - - def __init__( - self, - label: Control, - leading: Optional[Control] = None, - selected: Optional[bool] = False, - selected_color: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - bgcolor: Optional[ColorValue] = None, - show_checkmark: Optional[bool] = None, - check_color: Optional[ColorValue] = None, - shadow_color: Optional[ColorValue] = None, - shape: Optional[OutlinedBorder] = None, - padding: Optional[PaddingValue] = None, - delete_icon: Optional[Control] = None, - delete_icon_tooltip: Optional[str] = None, - delete_icon_color: Optional[ColorValue] = None, - disabled_color: Optional[ColorValue] = None, - label_padding: Optional[PaddingValue] = None, - label_style: Optional[TextStyle] = None, - selected_shadow_color: Optional[ColorValue] = None, - autofocus: Optional[bool] = None, - surface_tint_color: Optional[ColorValue] = None, - color: ControlStateValue[ColorValue] = None, - click_elevation: OptionalNumber = None, - clip_behavior: Optional[ClipBehavior] = None, - visual_density: Optional[VisualDensity] = None, - border_side: Optional[BorderSide] = None, - leading_size_constraints: Optional[BoxConstraints] = None, - delete_icon_size_constraints: Optional[BoxConstraints] = None, - enable_animation_style: Optional[AnimationStyle] = None, - select_animation_style: Optional[AnimationStyle] = None, - leading_drawer_animation_style: Optional[AnimationStyle] = None, - delete_drawer_animation_style: Optional[AnimationStyle] = None, - on_click: OptionalControlEventCallable = None, - on_delete: OptionalControlEventCallable = None, - on_select: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - key: Optional[str] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.autofocus = autofocus - self.label = label - self.leading = leading - self.bgcolor = bgcolor - self.check_color = check_color - self.selected = selected - self.delete_icon_tooltip = delete_icon_tooltip - self.delete_icon = delete_icon - self.delete_icon_color = delete_icon_color - self.disabled_color = disabled_color - self.elevation = elevation - self.label_padding = label_padding - self.label_style = label_style - self.padding = padding - self.selected_color = selected_color - self.selected_shadow_color = selected_shadow_color - self.shadow_color = shadow_color - self.shape = shape - self.show_checkmark = show_checkmark - self.on_click = on_click - self.on_delete = on_delete - self.on_select = on_select - self.on_focus = on_focus - self.on_blur = on_blur - self.color = color - self.surface_tint_color = surface_tint_color - self.click_elevation = click_elevation - self.clip_behavior = clip_behavior - self.visual_density = visual_density - self.border_side = border_side - self.leading_size_constraints = leading_size_constraints - self.delete_icon_size_constraints = delete_icon_size_constraints - self.enable_animation_style = enable_animation_style - self.select_animation_style = select_animation_style - self.leading_drawer_animation_style = leading_drawer_animation_style - self.delete_drawer_animation_style = delete_drawer_animation_style - - def _get_control_name(self): - return "chip" - - def before_update(self): - super().before_update() - self._set_attr_json("labelPadding", self.__label_padding) - self._set_attr_json("labelStyle", self.__label_style) - self._set_attr_json("padding", self.__padding) - self._set_attr_json("shape", self.__shape) - self._set_attr_json("borderSide", self.__border_side) - self._set_attr_json("color", self.__color, wrap_attr_dict=True) - self._set_attr_json("leadingSizeConstraints", self.__leading_size_constraints) - self._set_attr_json( - "deleteIconSizeConstraints", self.__delete_icon_size_constraints - ) - self._set_attr_json("enableAnimationStyle", self.__enable_animation_style) - self._set_attr_json("selectAnimationStyle", self.__select_animation_style) - self._set_attr_json( - "leadingDrawerAnimationStyle", self.__leading_drawer_animation_style - ) - self._set_attr_json( - "deleteDrawerAnimationStyle", self.__delete_drawer_animation_style - ) - - def _get_children(self): - self.__label._set_attr_internal("n", "label") - children = [self.__label] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__delete_icon: - self.__delete_icon._set_attr_internal("n", "deleteIcon") - children.append(self.__delete_icon) - return children - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # delete_icon_size_constraints - @property - def delete_icon_size_constraints(self) -> Optional[BoxConstraints]: - return self.__delete_icon_size_constraints - - @delete_icon_size_constraints.setter - def delete_icon_size_constraints(self, value: Optional[BoxConstraints]): - self.__delete_icon_size_constraints = value - - # leading_size_constraints - @property - def leading_size_constraints(self) -> Optional[BoxConstraints]: - return self.__leading_size_constraints - - @leading_size_constraints.setter - def leading_size_constraints(self, value: Optional[BoxConstraints]): - self.__leading_size_constraints = value - - # enable_animation_style - @property - def enable_animation_style(self) -> Optional[AnimationStyle]: - return self.__enable_animation_style - - @enable_animation_style.setter - def enable_animation_style(self, value: Optional[AnimationStyle]): - self.__enable_animation_style = value - - # select_animation_style - @property - def select_animation_style(self) -> Optional[AnimationStyle]: - return self.__select_animation_style - - @select_animation_style.setter - def select_animation_style(self, value: Optional[AnimationStyle]): - self.__select_animation_style = value - - # leading_drawer_animation_style - @property - def leading_drawer_animation_style(self) -> Optional[AnimationStyle]: - return self.__leading_drawer_animation_style - - @leading_drawer_animation_style.setter - def leading_drawer_animation_style(self, value: Optional[AnimationStyle]): - self.__leading_drawer_animation_style = value - - # delete_drawer_animation_style - @property - def delete_drawer_animation_style(self) -> Optional[AnimationStyle]: - return self.__delete_drawer_animation_style - - @delete_drawer_animation_style.setter - def delete_drawer_animation_style(self, value: Optional[AnimationStyle]): - self.__delete_drawer_animation_style = value - - # selected - @property - def selected(self) -> bool: - return self._get_attr("selected", data_type="bool", def_value=False) - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # show_checkmark - @property - def show_checkmark(self) -> bool: - return self._get_attr("showCheckmark", data_type="bool", def_value=True) - - @show_checkmark.setter - def show_checkmark(self, value: Optional[bool]): - self._set_attr("showCheckmark", value) - - # delete_icon_tooltip - @property - def delete_icon_tooltip(self) -> Optional[str]: - return self._get_attr("deleteButtonTooltip") - - @delete_icon_tooltip.setter - def delete_icon_tooltip(self, value: Optional[str]): - self._set_attr("deleteButtonTooltip", value) - - # label - @property - def label(self) -> Control: - return self.__label - - @label.setter - def label(self, value: Control): - self.__label = value - - # label_padding - @property - def label_padding(self) -> Optional[PaddingValue]: - return self.__label_padding - - @label_padding.setter - def label_padding(self, value: Optional[PaddingValue]): - self.__label_padding = value - - # label_style - @property - def label_style(self) -> Optional[TextStyle]: - return self.__label_style - - @label_style.setter - def label_style(self, value: Optional[TextStyle]): - self.__label_style = value - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # delete_icon - @property - def delete_icon(self) -> Optional[Control]: - return self.__delete_icon - - @delete_icon.setter - def delete_icon(self, value: Optional[Control]): - self.__delete_icon = value - - # delete_icon_color - @property - def delete_icon_color(self) -> Optional[ColorValue]: - return self.__delete_icon_color - - @delete_icon_color.setter - def delete_icon_color(self, value: Optional[ColorValue]): - self.__delete_icon_color = value - self._set_enum_attr("deleteIconColor", value, ColorEnums) - - # disabled_color - @property - def disabled_color(self) -> Optional[ColorValue]: - return self.__disabled_color - - @disabled_color.setter - def disabled_color(self, value: Optional[ColorValue]): - self.__disabled_color = value - self._set_enum_attr("disabledColor", value, ColorEnums) - - # color - @property - def color(self) -> ControlStateValue[str]: - return self.__color - - @color.setter - def color(self, value: ControlStateValue[str]): - self.__color = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # check_color - @property - def check_color(self) -> Optional[ColorValue]: - return self.__check_color - - @check_color.setter - def check_color(self, value: Optional[ColorValue]): - self.__check_color = value - self._set_enum_attr("checkColor", value, ColorEnums) - - # selected_color - @property - def selected_color(self) -> Optional[ColorValue]: - return self.__selected_color - - @selected_color.setter - def selected_color(self, value: Optional[ColorValue]): - self.__selected_color = value - self._set_enum_attr("selectedColor", value, ColorEnums) - - # selected_shadow_color - @property - def selected_shadow_color(self) -> Optional[ColorValue]: - return self.__selected_shadow_color - - @selected_shadow_color.setter - def selected_shadow_color(self, value: Optional[ColorValue]): - self.__selected_shadow_color = value - self._set_enum_attr("selectedShadowColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation", data_type="float") - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # click_elevation - @property - def click_elevation(self) -> OptionalNumber: - return self._get_attr("clickElevation", data_type="float") - - @click_elevation.setter - def click_elevation(self, value: OptionalNumber): - self._set_attr("clickElevation", value) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # visual_density - @property - def visual_density(self) -> Optional[VisualDensity]: - return self.__visual_density - - @visual_density.setter - def visual_density(self, value: Optional[VisualDensity]): - self.__visual_density = value - self._set_enum_attr("visualDensity", value, VisualDensity) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # border_side - @property - def border_side(self) -> Optional[BorderSide]: - return self.__border_side - - @border_side.setter - def border_side(self, value: Optional[BorderSide]): - self.__border_side = value - - # on_click - @property - def on_click(self): - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - self._set_attr("onclick", True if handler is not None else None) - - # on_delete - @property - def on_delete(self): - return self._get_event_handler("delete") - - @on_delete.setter - def on_delete(self, handler: OptionalControlEventCallable): - self._add_event_handler("delete", handler) - self._set_attr("onDelete", True if handler is not None else None) - - # on_select - @property - def on_select(self): - return self._get_event_handler("select") - - @on_select.setter - def on_select(self, handler: OptionalControlEventCallable): - self._add_event_handler("select", handler) - self._set_attr("onSelect", True if handler is not None else None) - - # on_focus - @property - def on_focus(self): - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self): - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/circle_avatar.py b/sdk/python/packages/flet/src/flet/core/circle_avatar.py deleted file mode 100644 index 94b50faa52..0000000000 --- a/sdk/python/packages/flet/src/flet/core/circle_avatar.py +++ /dev/null @@ -1,255 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CircleAvatar(ConstrainedControl): - """ - A circle that represents a user. - - If `foreground_image_src` fails then `background_image_src` is used. If `background_image_src` fails too, - then `bgcolor` is used. - - Example: - ``` - import flet as ft - - def main(page): - # a "normal" avatar with background image - a1 = ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4", - content=ft.Text("FF"), - ) - # avatar with failing foreground image and fallback text - a2 = ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/_5041459?s=88&v=4", - content=ft.Text("FF"), - ) - # avatar with icon, aka icon with inverse background - a3 = ft.CircleAvatar( - content=ft.Icon(ft.icons.ABC), - ) - # avatar with icon and custom colors - a4 = ft.CircleAvatar( - content=ft.Icon(ft.icons.WARNING_ROUNDED), - color=ft.colors.YELLOW_200, - bgcolor=ft.colors.AMBER_700, - ) - # avatar with online status - a5 = ft.Stack( - [ - ft.CircleAvatar( - foreground_image_src="https://avatars.githubusercontent.com/u/5041459?s=88&v=4" - ), - ft.Container( - content=ft.CircleAvatar(bgcolor=ft.colors.GREEN, radius=5), - alignment=ft.alignment.bottom_left, - ), - ], - width=40, - height=40, - ) - page.add(a1, a2, a3, a4, a5) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/circleavatar - """ - - def __init__( - self, - content: Optional[Control] = None, - foreground_image_src: Optional[str] = None, - background_image_src: Optional[str] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - radius: OptionalNumber = None, - min_radius: OptionalNumber = None, - max_radius: OptionalNumber = None, - on_image_error: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - key: Optional[str] = None, - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.foreground_image_src = foreground_image_src - self.background_image_src = background_image_src - self.radius = radius - self.min_radius = min_radius - self.max_radius = max_radius - self.color = color - self.bgcolor = bgcolor - self.content = content - self.on_image_error = on_image_error - - def _get_control_name(self): - return "circleavatar" - - def _get_children(self): - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - return [self.__content] - return [] - - # foreground_image_src - @property - def foreground_image_src(self) -> Optional[str]: - return self._get_attr("foregroundImageSrc") - - @foreground_image_src.setter - def foreground_image_src(self, value: Optional[str]): - self._set_attr("foregroundImageSrc", value) - - # background_image_src - @property - def background_image_src(self) -> Optional[str]: - return self._get_attr("backgroundImageSrc") - - @background_image_src.setter - def background_image_src(self, value: Optional[str]): - self._set_attr("backgroundImageSrc", value) - - # radius - @property - def radius(self) -> OptionalNumber: - return self._get_attr("radius", data_type="float") - - @radius.setter - def radius(self, value: OptionalNumber): - assert value is None or value >= 0, "radius cannot be negative" - self._set_attr("radius", value) - - # min_radius - @property - def min_radius(self) -> OptionalNumber: - return self._get_attr("minRadius", data_type="float") - - @min_radius.setter - def min_radius(self, value: OptionalNumber): - assert value is None or value >= 0, "min_radius cannot be negative" - self._set_attr("minRadius", value) - - # max_radius - @property - def max_radius(self) -> OptionalNumber: - return self._get_attr("maxRadius", data_type="float") - - @max_radius.setter - def max_radius(self, value: OptionalNumber): - assert value is None or value >= 0, "max_radius cannot be negative" - self._set_attr("maxRadius", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # on_image_error - @property - def on_image_error(self): - return self._get_event_handler("imageError") - - @on_image_error.setter - def on_image_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("imageError", handler) diff --git a/sdk/python/packages/flet/src/flet/core/client_storage.py b/sdk/python/packages/flet/src/flet/core/client_storage.py deleted file mode 100644 index bd8a0fd6eb..0000000000 --- a/sdk/python/packages/flet/src/flet/core/client_storage.py +++ /dev/null @@ -1,101 +0,0 @@ -import json -from typing import Any, List - - -class ClientStorage: - def __init__(self, page): - self.__page = page - - def set(self, key: str, value: Any) -> bool: - jv = self.__page._convert_attr_json(value) - assert jv is not None - return ( - self.__page._invoke_method( - "clientStorage:set", {"key": key, "value": jv}, wait_for_result=True - ) - == "true" - ) - - async def set_async(self, key: str, value: Any) -> bool: - jv = self.__page._convert_attr_json(value) - assert jv is not None - return ( - await self.__page._invoke_method_async( - "clientStorage:set", {"key": key, "value": jv}, wait_for_result=True - ) - ) == "true" - - def get(self, key: str): - jv = self.__page._invoke_method( - "clientStorage:get", {"key": key}, wait_for_result=True - ) - if jv: - return json.loads(json.loads(jv)) - return None - - async def get_async(self, key: str): - jv = await self.__page._invoke_method_async( - "clientStorage:get", {"key": key}, wait_for_result=True - ) - if jv: - return json.loads(json.loads(jv)) - return None - - def contains_key(self, key: str) -> bool: - return ( - self.__page._invoke_method( - "clientStorage:containskey", {"key": key}, wait_for_result=True - ) - == "true" - ) - - async def contains_key_async(self, key: str) -> bool: - return ( - await self.__page._invoke_method_async( - "clientStorage:containskey", {"key": key}, wait_for_result=True - ) - == "true" - ) - - def remove(self, key: str) -> bool: - return ( - self.__page._invoke_method( - "clientStorage:remove", {"key": key}, wait_for_result=True - ) - == "true" - ) - - async def remove_async(self, key: str) -> bool: - return ( - await self.__page._invoke_method_async( - "clientStorage:remove", {"key": key}, wait_for_result=True - ) - ) == "true" - - def get_keys(self, key_prefix: str) -> List[str]: - jr = self.__page._invoke_method( - "clientStorage:getkeys", {"key_prefix": key_prefix}, wait_for_result=True - ) - assert jr is not None - return json.loads(jr) - - async def get_keys_async(self, key_prefix: str) -> List[str]: - jr = await self.__page._invoke_method_async( - "clientStorage:getkeys", {"key_prefix": key_prefix}, wait_for_result=True - ) - assert jr is not None - return json.loads(jr) - - def clear(self) -> bool: - return ( - self.__page._invoke_method("clientStorage:clear", wait_for_result=True) - == "true" - ) - - async def clear_async(self) -> bool: - return ( - await self.__page._invoke_method_async( - "clientStorage:clear", wait_for_result=True - ) - == "true" - ) diff --git a/sdk/python/packages/flet/src/flet/core/colors.py b/sdk/python/packages/flet/src/flet/core/colors.py deleted file mode 100644 index 9d921f45b8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/colors.py +++ /dev/null @@ -1,412 +0,0 @@ -""" -$lines = Get-Content "colors.dart" - -$section = '' - -foreach($line in $lines) { - - if ($line.Contains("case `"")) { - $color = $line.Replace('case "', "").replace('":', "").trim() - $ucolor = $color.toUpper() - "$ucolor = `"$color`"" - } elseif ($line.Contains('Map _plainColors')) { - $section = 'plain' - } elseif ($line.Contains('Map _materialColors')) { - $section = 'primary' - } elseif ($line.Contains('Map _materialAccentColors')) { - $section = 'accent' - } elseif ($line.startswith(' "')) { - $color = $line.split('"')[1] - $ucolor = $color.replace('deep', 'deep_').replace('light', 'light_').replace('grey', '_grey').replace('accent', '_accent').toUpper() - - "$ucolor = `"$color`"" - if ($section -eq 'primary') { - $shades = @(50, 100, 200, 300, 400, 500, 600, 700, 800, 900) - foreach($shade in $shades) { - "$($ucolor)_$shade = `"$($color)$shade`"" - } - } elseif ($section -eq 'accent') { - $shades = @(100, 200, 400, 700) - foreach($shade in $shades) { - "$($ucolor)_$shade = `"$($color)$shade`"" - } - } - } -} -""" - -import random -from enum import Enum -from typing import TYPE_CHECKING, Dict, List, Optional, Union - -if TYPE_CHECKING: - from flet.core.types import ColorValue - - -class Colors(str, Enum): - @staticmethod - def with_opacity(opacity: Union[int, float], color: "ColorValue") -> str: - assert 0 <= opacity <= 1, "opacity must be between 0 and 1" - color_str = color.value if isinstance(color, Enum) else color - return f"{color_str},{opacity}" - - @staticmethod - def random( - exclude: Optional[List["Colors"]] = None, - weights: Optional[Dict["Colors", int]] = None, - ) -> Optional["Colors"]: - """ - Selects a random color, with optional exclusions and weights. - - Args: - exclude: A list of colors members to exclude from the selection. - weights: A dictionary mapping color members to their respective weights for weighted random selection. - - Returns: - A randomly selected color, or None if all members are excluded. - """ - choices = list(Colors) - if exclude: - choices = [member for member in choices if member not in exclude] - if not choices: - return None - if weights: - weights_list = [weights.get(c, 1) for c in choices] - return random.choices(choices, weights=weights_list)[0] - return random.choice(choices) - - PRIMARY = "primary" - ON_PRIMARY = "onprimary" - PRIMARY_CONTAINER = "primarycontainer" - ON_PRIMARY_CONTAINER = "onprimarycontainer" - SECONDARY = "secondary" - ON_SECONDARY = "onsecondary" - SECONDARY_CONTAINER = "secondarycontainer" - ON_SECONDARY_CONTAINER = "onsecondarycontainer" - TERTIARY = "tertiary" - ON_TERTIARY = "ontertiary" - TERTIARY_CONTAINER = "tertiarycontainer" - ON_TERTIARY_CONTAINER = "ontertiarycontainer" - ERROR = "error" - ON_ERROR = "onerror" - ERROR_CONTAINER = "errorcontainer" - ON_ERROR_CONTAINER = "onerrorcontainer" - OUTLINE = "outline" - OUTLINE_VARIANT = "outlinevariant" - SURFACE = "surface" # previously BACKGROUND - ON_SURFACE = "onsurface" # previously ON_BACKGROUND - SURFACE_TINT = "surfacetint" - SURFACE_CONTAINER_HIGHEST = "surfaceContainerHighest" # previously SURFACE_VARIANT - ON_SURFACE_VARIANT = "onsurfacevariant" - INVERSE_SURFACE = "inversesurface" - ON_INVERSE_SURFACE = "oninversesurface" - INVERSE_PRIMARY = "inverseprimary" - SHADOW = "shadow" - SCRIM = "scrim" - - WHITE10 = "white10" - WHITE12 = "white12" - WHITE24 = "white24" - WHITE30 = "white30" - WHITE38 = "white38" - WHITE54 = "white54" - WHITE60 = "white60" - WHITE70 = "white70" - WHITE = "white" - TRANSPARENT = "transparent" - BLACK12 = "black12" - BLACK26 = "black26" - BLACK38 = "black38" - BLACK45 = "black45" - BLACK54 = "black54" - BLACK87 = "black87" - BLACK = "black" - RED = "red" - RED_50 = "red50" - RED_100 = "red100" - RED_200 = "red200" - RED_300 = "red300" - RED_400 = "red400" - RED_500 = "red500" - RED_600 = "red600" - RED_700 = "red700" - RED_800 = "red800" - RED_900 = "red900" - PINK = "pink" - PINK_50 = "pink50" - PINK_100 = "pink100" - PINK_200 = "pink200" - PINK_300 = "pink300" - PINK_400 = "pink400" - PINK_500 = "pink500" - PINK_600 = "pink600" - PINK_700 = "pink700" - PINK_800 = "pink800" - PINK_900 = "pink900" - PURPLE = "purple" - PURPLE_50 = "purple50" - PURPLE_100 = "purple100" - PURPLE_200 = "purple200" - PURPLE_300 = "purple300" - PURPLE_400 = "purple400" - PURPLE_500 = "purple500" - PURPLE_600 = "purple600" - PURPLE_700 = "purple700" - PURPLE_800 = "purple800" - PURPLE_900 = "purple900" - DEEP_PURPLE = "deeppurple" - DEEP_PURPLE_50 = "deeppurple50" - DEEP_PURPLE_100 = "deeppurple100" - DEEP_PURPLE_200 = "deeppurple200" - DEEP_PURPLE_300 = "deeppurple300" - DEEP_PURPLE_400 = "deeppurple400" - DEEP_PURPLE_500 = "deeppurple500" - DEEP_PURPLE_600 = "deeppurple600" - DEEP_PURPLE_700 = "deeppurple700" - DEEP_PURPLE_800 = "deeppurple800" - DEEP_PURPLE_900 = "deeppurple900" - INDIGO = "indigo" - INDIGO_50 = "indigo50" - INDIGO_100 = "indigo100" - INDIGO_200 = "indigo200" - INDIGO_300 = "indigo300" - INDIGO_400 = "indigo400" - INDIGO_500 = "indigo500" - INDIGO_600 = "indigo600" - INDIGO_700 = "indigo700" - INDIGO_800 = "indigo800" - INDIGO_900 = "indigo900" - BLUE = "blue" - BLUE_50 = "blue50" - BLUE_100 = "blue100" - BLUE_200 = "blue200" - BLUE_300 = "blue300" - BLUE_400 = "blue400" - BLUE_500 = "blue500" - BLUE_600 = "blue600" - BLUE_700 = "blue700" - BLUE_800 = "blue800" - BLUE_900 = "blue900" - LIGHT_BLUE = "lightblue" - LIGHT_BLUE_50 = "lightblue50" - LIGHT_BLUE_100 = "lightblue100" - LIGHT_BLUE_200 = "lightblue200" - LIGHT_BLUE_300 = "lightblue300" - LIGHT_BLUE_400 = "lightblue400" - LIGHT_BLUE_500 = "lightblue500" - LIGHT_BLUE_600 = "lightblue600" - LIGHT_BLUE_700 = "lightblue700" - LIGHT_BLUE_800 = "lightblue800" - LIGHT_BLUE_900 = "lightblue900" - CYAN = "cyan" - CYAN_50 = "cyan50" - CYAN_100 = "cyan100" - CYAN_200 = "cyan200" - CYAN_300 = "cyan300" - CYAN_400 = "cyan400" - CYAN_500 = "cyan500" - CYAN_600 = "cyan600" - CYAN_700 = "cyan700" - CYAN_800 = "cyan800" - CYAN_900 = "cyan900" - TEAL = "teal" - TEAL_50 = "teal50" - TEAL_100 = "teal100" - TEAL_200 = "teal200" - TEAL_300 = "teal300" - TEAL_400 = "teal400" - TEAL_500 = "teal500" - TEAL_600 = "teal600" - TEAL_700 = "teal700" - TEAL_800 = "teal800" - TEAL_900 = "teal900" - GREEN = "green" - GREEN_50 = "green50" - GREEN_100 = "green100" - GREEN_200 = "green200" - GREEN_300 = "green300" - GREEN_400 = "green400" - GREEN_500 = "green500" - GREEN_600 = "green600" - GREEN_700 = "green700" - GREEN_800 = "green800" - GREEN_900 = "green900" - LIGHT_GREEN = "lightgreen" - LIGHT_GREEN_50 = "lightgreen50" - LIGHT_GREEN_100 = "lightgreen100" - LIGHT_GREEN_200 = "lightgreen200" - LIGHT_GREEN_300 = "lightgreen300" - LIGHT_GREEN_400 = "lightgreen400" - LIGHT_GREEN_500 = "lightgreen500" - LIGHT_GREEN_600 = "lightgreen600" - LIGHT_GREEN_700 = "lightgreen700" - LIGHT_GREEN_800 = "lightgreen800" - LIGHT_GREEN_900 = "lightgreen900" - LIME = "lime" - LIME_50 = "lime50" - LIME_100 = "lime100" - LIME_200 = "lime200" - LIME_300 = "lime300" - LIME_400 = "lime400" - LIME_500 = "lime500" - LIME_600 = "lime600" - LIME_700 = "lime700" - LIME_800 = "lime800" - LIME_900 = "lime900" - YELLOW = "yellow" - YELLOW_50 = "yellow50" - YELLOW_100 = "yellow100" - YELLOW_200 = "yellow200" - YELLOW_300 = "yellow300" - YELLOW_400 = "yellow400" - YELLOW_500 = "yellow500" - YELLOW_600 = "yellow600" - YELLOW_700 = "yellow700" - YELLOW_800 = "yellow800" - YELLOW_900 = "yellow900" - AMBER = "amber" - AMBER_50 = "amber50" - AMBER_100 = "amber100" - AMBER_200 = "amber200" - AMBER_300 = "amber300" - AMBER_400 = "amber400" - AMBER_500 = "amber500" - AMBER_600 = "amber600" - AMBER_700 = "amber700" - AMBER_800 = "amber800" - AMBER_900 = "amber900" - ORANGE = "orange" - ORANGE_50 = "orange50" - ORANGE_100 = "orange100" - ORANGE_200 = "orange200" - ORANGE_300 = "orange300" - ORANGE_400 = "orange400" - ORANGE_500 = "orange500" - ORANGE_600 = "orange600" - ORANGE_700 = "orange700" - ORANGE_800 = "orange800" - ORANGE_900 = "orange900" - DEEP_ORANGE = "deeporange" - DEEP_ORANGE_50 = "deeporange50" - DEEP_ORANGE_100 = "deeporange100" - DEEP_ORANGE_200 = "deeporange200" - DEEP_ORANGE_300 = "deeporange300" - DEEP_ORANGE_400 = "deeporange400" - DEEP_ORANGE_500 = "deeporange500" - DEEP_ORANGE_600 = "deeporange600" - DEEP_ORANGE_700 = "deeporange700" - DEEP_ORANGE_800 = "deeporange800" - DEEP_ORANGE_900 = "deeporange900" - BROWN = "brown" - BROWN_50 = "brown50" - BROWN_100 = "brown100" - BROWN_200 = "brown200" - BROWN_300 = "brown300" - BROWN_400 = "brown400" - BROWN_500 = "brown500" - BROWN_600 = "brown600" - BROWN_700 = "brown700" - BROWN_800 = "brown800" - BROWN_900 = "brown900" - BLUE_GREY = "bluegrey" - BLUE_GREY_50 = "bluegrey50" - BLUE_GREY_100 = "bluegrey100" - BLUE_GREY_200 = "bluegrey200" - BLUE_GREY_300 = "bluegrey300" - BLUE_GREY_400 = "bluegrey400" - BLUE_GREY_500 = "bluegrey500" - BLUE_GREY_600 = "bluegrey600" - BLUE_GREY_700 = "bluegrey700" - BLUE_GREY_800 = "bluegrey800" - BLUE_GREY_900 = "bluegrey900" - RED_ACCENT = "redaccent" - RED_ACCENT_100 = "redaccent100" - RED_ACCENT_200 = "redaccent200" - RED_ACCENT_400 = "redaccent400" - RED_ACCENT_700 = "redaccent700" - PINK_ACCENT = "pinkaccent" - PINK_ACCENT_100 = "pinkaccent100" - PINK_ACCENT_200 = "pinkaccent200" - PINK_ACCENT_400 = "pinkaccent400" - PINK_ACCENT_700 = "pinkaccent700" - PURPLE_ACCENT = "purpleaccent" - PURPLE_ACCENT_100 = "purpleaccent100" - PURPLE_ACCENT_200 = "purpleaccent200" - PURPLE_ACCENT_400 = "purpleaccent400" - PURPLE_ACCENT_700 = "purpleaccent700" - DEEP_PURPLE_ACCENT = "deeppurpleaccent" - DEEP_PURPLE_ACCENT_100 = "deeppurpleaccent100" - DEEP_PURPLE_ACCENT_200 = "deeppurpleaccent200" - DEEP_PURPLE_ACCENT_400 = "deeppurpleaccent400" - DEEP_PURPLE_ACCENT_700 = "deeppurpleaccent700" - INDIGO_ACCENT = "indigoaccent" - INDIGO_ACCENT_100 = "indigoaccent100" - INDIGO_ACCENT_200 = "indigoaccent200" - INDIGO_ACCENT_400 = "indigoaccent400" - INDIGO_ACCENT_700 = "indigoaccent700" - BLUE_ACCENT = "blueaccent" - BLUE_ACCENT_100 = "blueaccent100" - BLUE_ACCENT_200 = "blueaccent200" - BLUE_ACCENT_400 = "blueaccent400" - BLUE_ACCENT_700 = "blueaccent700" - LIGHT_BLUE_ACCENT = "lightblueaccent" - LIGHT_BLUE_ACCENT_100 = "lightblueaccent100" - LIGHT_BLUE_ACCENT_200 = "lightblueaccent200" - LIGHT_BLUE_ACCENT_400 = "lightblueaccent400" - LIGHT_BLUE_ACCENT_700 = "lightblueaccent700" - CYAN_ACCENT = "cyanaccent" - CYAN_ACCENT_100 = "cyanaccent100" - CYAN_ACCENT_200 = "cyanaccent200" - CYAN_ACCENT_400 = "cyanaccent400" - CYAN_ACCENT_700 = "cyanaccent700" - TEAL_ACCENT = "tealaccent" - TEAL_ACCENT_100 = "tealaccent100" - TEAL_ACCENT_200 = "tealaccent200" - TEAL_ACCENT_400 = "tealaccent400" - TEAL_ACCENT_700 = "tealaccent700" - GREEN_ACCENT = "greenaccent" - GREEN_ACCENT_100 = "greenaccent100" - GREEN_ACCENT_200 = "greenaccent200" - GREEN_ACCENT_400 = "greenaccent400" - GREEN_ACCENT_700 = "greenaccent700" - LIGHT_GREEN_ACCENT = "lightgreenaccent" - LIGHT_GREEN_ACCENT_100 = "lightgreenaccent100" - LIGHT_GREEN_ACCENT_200 = "lightgreenaccent200" - LIGHT_GREEN_ACCENT_400 = "lightgreenaccent400" - LIGHT_GREEN_ACCENT_700 = "lightgreenaccent700" - LIME_ACCENT = "limeaccent" - LIME_ACCENT_100 = "limeaccent100" - LIME_ACCENT_200 = "limeaccent200" - LIME_ACCENT_400 = "limeaccent400" - LIME_ACCENT_700 = "limeaccent700" - YELLOW_ACCENT = "yellowaccent" - YELLOW_ACCENT_100 = "yellowaccent100" - YELLOW_ACCENT_200 = "yellowaccent200" - YELLOW_ACCENT_400 = "yellowaccent400" - YELLOW_ACCENT_700 = "yellowaccent700" - AMBER_ACCENT = "amberaccent" - AMBER_ACCENT_100 = "amberaccent100" - AMBER_ACCENT_200 = "amberaccent200" - AMBER_ACCENT_400 = "amberaccent400" - AMBER_ACCENT_700 = "amberaccent700" - ORANGE_ACCENT = "orangeaccent" - ORANGE_ACCENT_100 = "orangeaccent100" - ORANGE_ACCENT_200 = "orangeaccent200" - ORANGE_ACCENT_400 = "orangeaccent400" - ORANGE_ACCENT_700 = "orangeaccent700" - DEEP_ORANGE_ACCENT = "deeporangeaccent" - DEEP_ORANGE_ACCENT_100 = "deeporangeaccent100" - DEEP_ORANGE_ACCENT_200 = "deeporangeaccent200" - DEEP_ORANGE_ACCENT_400 = "deeporangeaccent400" - DEEP_ORANGE_ACCENT_700 = "deeporangeaccent700" - GREY = "grey" - GREY_50 = "grey50" - GREY_100 = "grey100" - GREY_200 = "grey200" - GREY_300 = "grey300" - GREY_400 = "grey400" - GREY_500 = "grey500" - GREY_600 = "grey600" - GREY_700 = "grey700" - GREY_800 = "grey800" - GREY_900 = "grey900" diff --git a/sdk/python/packages/flet/src/flet/core/column.py b/sdk/python/packages/flet/src/flet/core/column.py deleted file mode 100644 index 8f0e58cee6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/column.py +++ /dev/null @@ -1,244 +0,0 @@ -from typing import Any, Callable, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.scrollable_control import OnScrollEvent, ScrollableControl -from flet.core.types import ( - CrossAxisAlignment, - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - OptionalNumber, - ResponsiveNumber, - RotateValue, - ScaleValue, - ScrollMode, -) - - -class Column(ConstrainedControl, ScrollableControl, AdaptiveControl): - """ - Container allows to decorate a control with background color and border and position it with padding, margin and alignment. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Column example" - - page.add( - ft.Column( - expand=True, - controls=[ - ft.Container( - expand=1, - content=ft.Text("Container 1"), - bgcolor=ft.colors.GREEN_100, - ), - ft.Container( - expand=2, content=ft.Text("Container 2"), bgcolor=ft.colors.RED_100 - ), - ], - ), - ), - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/column - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - alignment: Optional[MainAxisAlignment] = None, - horizontal_alignment: Optional[CrossAxisAlignment] = None, - spacing: OptionalNumber = None, - tight: Optional[bool] = None, - wrap: Optional[bool] = None, - run_spacing: OptionalNumber = None, - run_alignment: Optional[MainAxisAlignment] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - # - # ScrollableControl and AdaptiveControl - # - scroll: Optional[ScrollMode] = None, - auto_scroll: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: Optional[Callable[[OnScrollEvent], None]] = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - ScrollableControl.__init__( - self, - scroll=scroll, - auto_scroll=auto_scroll, - on_scroll_interval=on_scroll_interval, - on_scroll=on_scroll, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.controls = controls - self.horizontal_alignment = horizontal_alignment - self.alignment = alignment - self.spacing = spacing - self.tight = tight - self.wrap = wrap - self.run_spacing = run_spacing - self.run_alignment = run_alignment - - def _get_control_name(self): - return "column" - - def _get_children(self): - return self.__controls - - def __contains__(self, item): - return item in self.__controls - - # Public methods - def clean(self): - super().clean() - self.__controls.clear() - - # tight - @property - def tight(self) -> bool: - return self._get_attr("tight", data_type="bool", def_value=False) - - @tight.setter - def tight(self, value: Optional[bool]): - self._set_attr("tight", value) - - # alignment - @property - def alignment(self) -> Optional[MainAxisAlignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[MainAxisAlignment]): - self.__alignment = value - self._set_enum_attr("alignment", value, MainAxisAlignment) - - # run_alignment - @property - def run_alignment(self) -> Optional[MainAxisAlignment]: - return self.__run_alignment - - @run_alignment.setter - def run_alignment(self, value: Optional[MainAxisAlignment]): - self.__run_alignment = value - self._set_enum_attr("runAlignment", value, MainAxisAlignment) - - # horizontal_alignment - @property - def horizontal_alignment(self) -> Optional[CrossAxisAlignment]: - return self.__horizontal_alignment - - @horizontal_alignment.setter - def horizontal_alignment(self, value: Optional[CrossAxisAlignment]): - self.__horizontal_alignment = value - self._set_enum_attr("horizontalAlignment", value, CrossAxisAlignment) - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self._get_attr("spacing", data_type="float", def_value=10) - - @spacing.setter - def spacing(self, value: OptionalNumber): - self._set_attr("spacing", value) - - # wrap - @property - def wrap(self) -> bool: - return self._get_attr("wrap", data_type="bool", def_value=False) - - @wrap.setter - def wrap(self, value: Optional[bool]): - self._set_attr("wrap", value) - - # run_spacing - @property - def run_spacing(self) -> OptionalNumber: - return self._get_attr("runSpacing", data_type="float") - - @run_spacing.setter - def run_spacing(self, value: OptionalNumber): - self._set_attr("runSpacing", value) - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] diff --git a/sdk/python/packages/flet/src/flet/core/connection.py b/sdk/python/packages/flet/src/flet/core/connection.py deleted file mode 100644 index 31cf512ada..0000000000 --- a/sdk/python/packages/flet/src/flet/core/connection.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import List, Optional - -from flet.core.protocol import Command -from flet.core.pubsub.pubsub_hub import PubSubHub - - -class Connection: - def __init__(self): - self.page_name: str = "" - self.page_url: Optional[str] = None - self.sessions = {} - self.pubsubhub = PubSubHub() - - def send_command(self, session_id: str, command: Command): - raise NotImplementedError() - - def send_commands(self, session_id: str, commands: List[Command]): - raise NotImplementedError() - - def _get_ws_url(self, server: str): - url = server.rstrip("/") - if server.startswith("https://"): - url = url.replace("https://", "wss://") - elif server.startswith("http://"): - url = url.replace("http://", "ws://") - else: - url = "ws://" + url - return url + "/ws" - - def dispose(self): - pass diff --git a/sdk/python/packages/flet/src/flet/core/constrained_control.py b/sdk/python/packages/flet/src/flet/core/constrained_control.py deleted file mode 100644 index 798164157f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/constrained_control.py +++ /dev/null @@ -1,263 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class ConstrainedControl(Control): - def __init__( - self, - ref: Optional[Ref] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - # - # ConstrainedControl specific - # - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - ): - Control.__init__( - self, - ref=ref, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.key = key - self.width = width - self.height = height - self.left = left - self.top = top - self.right = right - self.bottom = bottom - self.scale = scale - self.rotate = rotate - self.offset = offset - self.aspect_ratio = aspect_ratio - self.animate_opacity = animate_opacity - self.animate_size = animate_size - self.animate_position = animate_position - self.animate_rotation = animate_rotation - self.animate_scale = animate_scale - self.animate_offset = animate_offset - self.on_animation_end = on_animation_end - - def before_update(self): - super().before_update() - self._set_attr_json("rotate", self.__rotate) - self._set_attr_json("scale", self.__scale) - self._set_attr_json("offset", self.__offset) - self._set_attr_json("animateOpacity", self.__animate_opacity) - self._set_attr_json("animateSize", self.__animate_size) - self._set_attr_json("animatePosition", self.__animate_position) - self._set_attr_json("animateRotation", self.__animate_rotation) - self._set_attr_json("animateScale", self.__animate_scale) - self._set_attr_json("animateOffset", self.__animate_offset) - - # key - @property - def key(self) -> Optional[str]: - return self._get_attr("key") - - @key.setter - def key(self, value: Optional[str]): - self._set_attr("key", value) - - # width - @property - def width(self) -> OptionalNumber: - """ - Control width. - """ - return self._get_attr("width") - - @width.setter - def width(self, value: OptionalNumber): - self._set_attr("width", value) - - # height - @property - def height(self) -> OptionalNumber: - return self._get_attr("height") - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # left - @property - def left(self) -> OptionalNumber: - return self._get_attr("left") - - @left.setter - def left(self, value: OptionalNumber): - self._set_attr("left", value) - - # top - @property - def top(self) -> OptionalNumber: - return self._get_attr("top") - - @top.setter - def top(self, value: OptionalNumber): - self._set_attr("top", value) - - # right - @property - def right(self) -> OptionalNumber: - return self._get_attr("right") - - @right.setter - def right(self, value: OptionalNumber): - self._set_attr("right", value) - - # bottom - @property - def bottom(self) -> OptionalNumber: - return self._get_attr("bottom") - - @bottom.setter - def bottom(self, value: OptionalNumber): - self._set_attr("bottom", value) - - # rotate - @property - def rotate(self) -> Optional[RotateValue]: - return self.__rotate - - @rotate.setter - def rotate(self, value: Optional[RotateValue]): - self.__rotate = value - - # scale - @property - def scale(self) -> Optional[ScaleValue]: - return self.__scale - - @scale.setter - def scale(self, value: Optional[ScaleValue]): - self.__scale = value - - # offset - @property - def offset(self) -> Optional[OffsetValue]: - return self.__offset - - @offset.setter - def offset(self, value: Optional[OffsetValue]): - self.__offset = value - - # aspect_ratio - @property - def aspect_ratio(self) -> OptionalNumber: - return self._get_attr("aspectRatio") - - @aspect_ratio.setter - def aspect_ratio(self, value: OptionalNumber): - self._set_attr("aspectRatio", value) - - # animate_opacity - @property - def animate_opacity(self) -> Optional[AnimationValue]: - return self.__animate_opacity - - @animate_opacity.setter - def animate_opacity(self, value: Optional[AnimationValue]): - self.__animate_opacity = value - - # animate_size - @property - def animate_size(self) -> Optional[AnimationValue]: - return self.__animate_size - - @animate_size.setter - def animate_size(self, value: Optional[AnimationValue]): - self.__animate_size = value - - # animate_position - @property - def animate_position(self) -> Optional[AnimationValue]: - return self.__animate_position - - @animate_position.setter - def animate_position(self, value: Optional[AnimationValue]): - self.__animate_position = value - - # animate_rotation - @property - def animate_rotation(self) -> Optional[AnimationValue]: - return self.__animate_rotation - - @animate_rotation.setter - def animate_rotation(self, value: Optional[AnimationValue]): - self.__animate_rotation = value - - # animate_scale - @property - def animate_scale(self) -> Optional[AnimationValue]: - return self.__animate_scale - - @animate_scale.setter - def animate_scale(self, value: Optional[AnimationValue]): - self.__animate_scale = value - - # animate_offset - @property - def animate_offset(self) -> Optional[AnimationValue]: - return self.__animate_offset - - @animate_offset.setter - def animate_offset(self, value: Optional[AnimationValue]): - self.__animate_offset = value - - # on_animation_end - @property - def on_animation_end(self) -> OptionalControlEventCallable: - return self._get_event_handler("animation_end") - - @on_animation_end.setter - def on_animation_end(self, handler: OptionalControlEventCallable): - self._add_event_handler("animation_end", handler) - self._set_attr("onAnimationEnd", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/container.py b/sdk/python/packages/flet/src/flet/core/container.py deleted file mode 100644 index 2f404cf453..0000000000 --- a/sdk/python/packages/flet/src/flet/core/container.py +++ /dev/null @@ -1,536 +0,0 @@ -import json -from typing import Any, List, Optional, Tuple, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.blur import Blur -from flet.core.border import Border -from flet.core.box import ( - BoxDecoration, - BoxShadow, - BoxShape, - ColorFilter, - DecorationImage, -) -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.gradients import Gradient -from flet.core.ref import Ref -from flet.core.theme import Theme -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BlendMode, - BorderRadiusValue, - ClipBehavior, - ColorEnums, - ColorValue, - ImageFit, - ImageRepeat, - MarginValue, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - ThemeMode, - UrlTarget, -) -from flet.utils.deprecated import deprecated_property - - -class Container(ConstrainedControl, AdaptiveControl): - """ - Container allows to decorate a control with background color and border and position it with padding, margin and alignment. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Container" - - c1 = ft.Container( - content=ft.Text("Container with background"), - bgcolor=ft.colors.AMBER_100, - padding=5, - ) - page.add(c1) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/container - """ - - def __init__( - self, - content: Optional[Control] = None, - padding: Optional[PaddingValue] = None, - margin: Optional[MarginValue] = None, - alignment: Optional[Alignment] = None, - bgcolor: Optional[ColorValue] = None, - gradient: Optional[Gradient] = None, - blend_mode: Optional[BlendMode] = None, - border: Optional[Border] = None, - border_radius: Optional[BorderRadiusValue] = None, - shape: Optional[BoxShape] = None, - clip_behavior: Optional[ClipBehavior] = None, - ink: Optional[bool] = None, - image: Optional[DecorationImage] = None, - ink_color: Optional[ColorValue] = None, - animate: Optional[AnimationValue] = None, - blur: Union[ - None, float, int, Tuple[Union[float, int], Union[float, int]], Blur - ] = None, - shadow: Union[None, BoxShadow, List[BoxShadow]] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - theme: Optional[Theme] = None, - dark_theme: Optional[Theme] = None, - theme_mode: Optional[ThemeMode] = None, - color_filter: Optional[ColorFilter] = None, - ignore_interactions: Optional[bool] = None, - foreground_decoration: Optional[BoxDecoration] = None, - on_click: OptionalControlEventCallable = None, - on_tap_down: OptionalEventCallable["ContainerTapEvent"] = None, - on_long_press: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__on_tap_down = EventHandler(lambda e: ContainerTapEvent(e)) - self._add_event_handler("tap_down", self.__on_tap_down.get_handler()) - - self.content = content - self.padding = padding - self.margin = margin - self.alignment = alignment - self.bgcolor = bgcolor - self.gradient = gradient - self.blend_mode = blend_mode - self.border = border - self.border_radius = border_radius - self.shape = shape - self.clip_behavior = clip_behavior - self.ink = ink - self.ink_color = ink_color - self.animate = animate - self.blur = blur - self.shadow = shadow - self.url = url - self.url_target = url_target - self.theme = theme - self.dark_theme = dark_theme - self.theme_mode = theme_mode - self.color_filter = color_filter - self.ignore_interactions = ignore_interactions - self.on_click = on_click - self.on_tap_down = on_tap_down - self.on_long_press = on_long_press - self.on_hover = on_hover - self.image = image - self.foreground_decoration = foreground_decoration - - def _get_control_name(self): - return "container" - - def before_update(self): - super().before_update() - assert ( - self.__blend_mode is None - or self.__gradient is not None - or self.bgcolor is not None - ), "blend_mode applies to bgcolor or gradient, but no bgcolor or gradient was provided" - assert ( - self.__shape != BoxShape.CIRCLE or self.__border_radius is None - ), "border_radius is not supported with shape=BoxShape.CIRCLE" - self._set_attr_json("borderRadius", self.__border_radius) - self._set_attr_json("border", self.__border) - self._set_attr_json("margin", self.__margin) - self._set_attr_json("padding", self.__padding) - self._set_attr_json("alignment", self.__alignment) - self._set_attr_json("gradient", self.__gradient) - self._set_attr_json("animate", self.__animate) - self._set_attr_json("blur", self.__blur) - self._set_attr_json("shadow", self.__shadow if self.__shadow else None) - self._set_attr_json("theme", self.__theme) - self._set_attr_json("darkTheme", self.__dark_theme) - self._set_attr_json("colorFilter", self.__color_filter) - self._set_attr_json("image", self.__image) - self._set_attr_json("foregroundDecoration", self.__foreground_decoration) - - def _get_children(self): - children = [] - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - """:obj:`Alignment`, optional: Align the child control within the container. - - Alignment is an instance of `alignment.Alignment` class object with `x` and `y` properties - representing the distance from the center of a rectangle. - """ - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # image - @property - def image(self) -> Optional[DecorationImage]: - return self.__image - - @image.setter - def image(self, value: Optional[DecorationImage]): - self.__image = value - - # foreground_decoration - @property - def foreground_decoration(self) -> Optional[BoxDecoration]: - return self.__foreground_decoration - - @foreground_decoration.setter - def foreground_decoration(self, value: Optional[BoxDecoration]): - self.__foreground_decoration = value - - # margin - @property - def margin(self) -> Optional[MarginValue]: - return self.__margin - - @margin.setter - def margin(self, value: Optional[MarginValue]): - self.__margin = value - - # bgcolor - @property - def bgcolor(self): - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # gradient - @property - def gradient(self) -> Optional[Gradient]: - return self.__gradient - - @gradient.setter - def gradient(self, value: Optional[Gradient]): - self.__gradient = value - - # blend_mode - @property - def blend_mode(self) -> Optional[BlendMode]: - return self.__blend_mode - - @blend_mode.setter - def blend_mode(self, value: Optional[BlendMode]): - self.__blend_mode = value - self._set_enum_attr("blendMode", value, BlendMode) - - # blur - @property - def blur( - self, - ) -> Union[None, float, int, Tuple[Union[float, int], Union[float, int]], Blur]: - return self.__blur - - @blur.setter - def blur( - self, - value: Union[ - None, float, int, Tuple[Union[float, int], Union[float, int]], Blur - ], - ): - self.__blur = value - - # shadow - @property - def shadow(self) -> Union[None, BoxShadow, List[BoxShadow]]: - return self.__shadow - - @shadow.setter - def shadow(self, value: Union[None, BoxShadow, List[BoxShadow]]): - self.__shadow = value if value is not None else [] - - # color_filter - @property - def color_filter(self) -> Optional[ColorFilter]: - return self.__color_filter - - @color_filter.setter - def color_filter(self, value: Optional[ColorFilter]): - self.__color_filter = value - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # ignore_interactions - @property - def ignore_interactions(self) -> Optional[bool]: - return self._get_attr("ignoreInteractions", data_type="bool", def_value=False) - - @ignore_interactions.setter - def ignore_interactions(self, value: Optional[str]): - self._set_attr("ignoreInteractions", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # shape - @property - def shape(self) -> Optional[BoxShape]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[BoxShape]): - self.__shape = value - self._set_enum_attr("shape", value, BoxShape) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # ink - @property - def ink(self) -> bool: - return self._get_attr("ink", data_type="bool", def_value=False) - - @ink.setter - def ink(self, value: Optional[bool]): - self._set_attr("ink", value) - - # ink color - @property - def ink_color(self) -> Optional[ColorValue]: - return self.__ink_color - - @ink_color.setter - def ink_color(self, value: Optional[ColorValue]): - self.__ink_color = value - self._set_enum_attr("inkColor", value, ColorEnums) - - # animate - @property - def animate(self) -> Optional[AnimationValue]: - return self.__animate - - @animate.setter - def animate(self, value: Optional[AnimationValue]): - self.__animate = value - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # theme - @property - def theme(self) -> Optional[Theme]: - return self.__theme - - @theme.setter - def theme(self, value: Optional[Theme]): - self.__theme = value - - # dark_theme - @property - def dark_theme(self) -> Optional[Theme]: - return self.__dark_theme - - @dark_theme.setter - def dark_theme(self, value: Optional[Theme]): - self.__dark_theme = value - - # theme_mode - @property - def theme_mode(self) -> Optional[ThemeMode]: - return self.__theme_mode - - @theme_mode.setter - def theme_mode(self, value: Optional[ThemeMode]): - self.__theme_mode = value - self._set_enum_attr("themeMode", value, ThemeMode) - - # on_click - @property - def on_click(self): - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - self._set_attr("onClick", True if handler is not None else None) - - # on_tap_down - @property - def on_tap_down(self) -> OptionalEventCallable["ContainerTapEvent"]: - return self.__on_tap_down.handler - - @on_tap_down.setter - def on_tap_down(self, handler: OptionalEventCallable["ContainerTapEvent"]): - self.__on_tap_down.handler = handler - self._set_attr("onTapDown", True if handler is not None else None) - - # on_long_press - @property - def on_long_press(self): - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # on_hover - @property - def on_hover(self): - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - self._set_attr("onHover", True if handler is not None else None) - - -class ContainerTapEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") diff --git a/sdk/python/packages/flet/src/flet/core/control.py b/sdk/python/packages/flet/src/flet/core/control.py deleted file mode 100644 index f9f13834e4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/control.py +++ /dev/null @@ -1,610 +0,0 @@ -import datetime as dt -import json -from difflib import SequenceMatcher -from enum import Enum -from typing import ( - TYPE_CHECKING, - Any, - AnyStr, - Dict, - List, - Optional, - Tuple, - Type, - TypeVar, - Union, -) - -from flet.core.badge import Badge, BadgeValue -from flet.core.embed_json_encoder import EmbedJsonEncoder -from flet.core.protocol import Command -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ControlState, - OptionalControlEventCallable, - OptionalNumber, - ResponsiveNumber, - SupportsStr, -) - -if TYPE_CHECKING: - from .page import Page - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - -V = TypeVar("V", str, int, float, bool, Any) -DV = TypeVar("DV", bound=Optional[Any]) - - -class Control: - def __init__( - self, - ref: Optional[Ref] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ) -> None: - super().__init__() - - self.__page: Optional[Page] = None - self.__attrs: Dict[str, Any] = {} - self.__previous_children = [] - self._id = None - self.__uid: Optional[str] = None - - if ref: - ref.current = self - self.expand = expand - self.expand_loose = expand_loose - self.col = col - self.opacity = opacity - self.tooltip = tooltip - self.badge = badge - self.visible = visible - self.disabled = disabled - self.__data: Any = None - self.data = data - self.rtl = rtl - - self.__event_handlers: Dict[str, OptionalControlEventCallable] = {} - self.parent: Optional[Control] = None - - def is_isolated(self) -> bool: - return False - - def build(self): - pass - - def before_update(self): - pass - - def _before_build_command(self) -> None: - # checking if tooltip has getter/setter in inherited class - if "tooltip" not in vars(self.__class__): - self._set_attr_json("tooltip", self.tooltip) - if isinstance(self.badge, (Badge, str)): - self._set_attr_json("badge", self.badge) - else: - self._set_attr("badge", None) - - self._set_attr_json("col", self.__col) - - def did_mount(self): - pass - - def will_unmount(self): - pass - - def _get_children(self) -> "List[Control]": - return [] - - def _get_control_name(self) -> str: - raise NotImplementedError( - "_get_control_name must be overridden in inherited class" - ) - - def _add_event_handler( - self, event_name: str, handler: OptionalControlEventCallable - ) -> None: - self.__event_handlers[event_name] = handler - - def _get_event_handler(self, event_name: str) -> OptionalControlEventCallable: - return self.__event_handlers.get(event_name) - - def _get_attr( - self, - name: str, - def_value: DV = None, - data_type: Union[ - Literal["string", "int", "float", "bool", "bool?"], AnyStr - ] = "string", - ) -> Union[V, DV]: - name = name.lower() - if name not in self.__attrs: - return def_value - s_val = self.__attrs[name][0] - if data_type == "bool" and s_val is not None and isinstance(s_val, str): - return s_val.lower() == "true" - elif data_type == "bool?" and isinstance(s_val, str): - if s_val.lower() == "true": - return True - elif s_val.lower() == "false": - return False - else: - return def_value - elif data_type == "float" and s_val is not None and isinstance(s_val, str): - return float(s_val) - elif data_type == "int" and s_val is not None and isinstance(s_val, str): - return int(s_val) - else: - return s_val - - def _set_attr(self, name: str, value: V, dirty: bool = True) -> None: - self._set_attr_internal(name, value, dirty) - - def _set_enum_attr( - self, - name: str, - value: V, - enum_type: Union[Type[Enum], Tuple[Type[Enum], ...]], - dirty: bool = True, - ) -> None: - self._set_attr_internal( - name, value.value if isinstance(value, enum_type) else value, dirty - ) - - def _get_value_or_list_attr(self, name: str, delimiter: str) -> Union[List[str], V]: - v = self._get_attr(name) - if v and delimiter in v: - return [x.strip() for x in v.split(delimiter)] - return v - - def _set_value_or_list_attr( - self, name: str, value: Union[List[SupportsStr], V], delimiter: str - ) -> None: - if isinstance(value, List): - value = delimiter.join([str(x) for x in value]) - self._set_attr(name, value) - - def _set_attr_internal(self, name: str, value: V, dirty: bool = True) -> None: - name = name.lower() - orig_val = self.__attrs.get(name) - - if value is None: - if orig_val is None: - return - value = "" - - if orig_val is None or orig_val[0] != value: - self.__attrs[name] = (value, dirty) - - def _set_attr_json(self, name: str, value: V, wrap_attr_dict: bool = False) -> None: - ov = self._get_attr(name) - nv = self._convert_attr_json( - self._wrap_attr_dict(value) if wrap_attr_dict else value - ) - if ov != nv: - self._set_attr(name, nv) - - def _convert_attr_json(self, value: V) -> Optional[str]: - return ( - json.dumps(value, cls=EmbedJsonEncoder, separators=(",", ":")) - if value is not None - else None - ) - - def _wrap_attr_dict(self, value: Optional[Union[Dict, Any]]) -> Optional[Dict]: - if value is None or isinstance(value, Dict): - return value - return {ControlState.DEFAULT: value} - - # event_handlers - @property - def event_handlers(self) -> Dict[str, Any]: - return self.__event_handlers - - # _previous_children - @property - def _previous_children(self): - return self.__previous_children - - # _id - @property - def _id(self) -> str: - return self._get_attr("id") - - @_id.setter - def _id(self, value: str): - self._set_attr("id", value) - - # page - @property - def page(self) -> "Optional[Page]": - return self.__page - - @page.setter - def page(self, page: "Optional[Page]"): - self.__page = page - - # uid - @property - def uid(self) -> Optional[str]: - return self.__uid - - # expand - @property - def expand(self) -> Optional[Union[bool, int]]: - return self.__expand - - @expand.setter - def expand(self, value: Optional[Union[bool, int]]): - self.__expand = value - if value and isinstance(value, bool): - value = 1 - self._set_attr("expand", value if value else None) - - # expand_loose - @property - def expand_loose(self) -> bool: - return self._get_attr("expandLoose", data_type="bool", def_value=False) - - @expand_loose.setter - def expand_loose(self, value: Optional[bool]): - self._set_attr("expandLoose", value) - - # rtl - @property - def rtl(self) -> bool: - return self._get_attr("rtl", data_type="bool", def_value=False) - - @rtl.setter - def rtl(self, value: Optional[bool]): - self._set_attr("rtl", value) - - # col - @property - def col(self) -> Optional[ResponsiveNumber]: - return self.__col - - @col.setter - def col(self, value: Optional[ResponsiveNumber]): - self.__col = value - - # opacity - @property - def opacity(self) -> float: - return self._get_attr("opacity", data_type="float", def_value=1.0) - - @opacity.setter - def opacity(self, value: OptionalNumber): - assert ( - value is None or 0.0 <= value <= 1.0 - ), "opacity must be between 0.0 and 1.0" - self._set_attr("opacity", value) - - # visible - @property - def visible(self) -> bool: - return self._get_attr("visible", data_type="bool", def_value=True) - - @visible.setter - def visible(self, value: Optional[bool]): - self._set_attr("visible", value) - - # disabled - @property - def disabled(self) -> bool: - return self._get_attr("disabled", data_type="bool", def_value=False) - - @disabled.setter - def disabled(self, value: Optional[bool]): - self._set_attr("disabled", value) - - # data - @property - def data(self) -> Optional[Any]: - return self.__data - - @data.setter - def data(self, value: Optional[Any]): - self.__data = value - - # public methods - def update(self) -> None: - assert ( - self.__page - ), f"{self.__class__.__qualname__} Control must be added to the page first" - self.__page.update(self) - - def clean(self) -> None: - assert ( - self.__page - ), f"{self.__class__.__qualname__} Control must be added to the page" - self.__page._clean(self) - - def invoke_method( - self, - method_name: str, - arguments: Optional[Dict[str, str]] = None, - wait_for_result: bool = False, - wait_timeout: Optional[float] = 5, - ) -> Optional[str]: - assert ( - self.__page - ), f"{self.__class__.__qualname__} Control must be added to the page first" - if arguments: - # remove items with None values and convert other values to string - arguments = {k: str(v) for k, v in arguments.items() if v is not None} - return self.__page._invoke_method( - control_id=self.uid, - method_name=method_name, - arguments=arguments, - wait_for_result=wait_for_result, - wait_timeout=wait_timeout, - ) - - def invoke_method_async( - self, - method_name: str, - arguments: Optional[Dict[str, str]] = None, - wait_for_result: bool = False, - wait_timeout: Optional[float] = 5, - ): - assert ( - self.__page - ), f"{self.__class__.__qualname__} Control must be added to the page first" - if arguments: - # remove items with None values and convert other values to string - arguments = {k: str(v) for k, v in arguments.items() if v is not None} - return self.__page._invoke_method_async( - control_id=self.uid, - method_name=method_name, - arguments=arguments, - wait_for_result=wait_for_result, - wait_timeout=wait_timeout, - ) - - def copy_attrs(self, dest: Dict[str, Any]) -> None: - for attr_name in sorted(self.__attrs): - attr_name_lower = attr_name.lower() - value, dirty = self.__attrs[attr_name_lower] - - if dirty or value is None: - continue - - if isinstance(value, bool): - sval = str(value).lower() - elif isinstance(value, (dt.datetime, dt.date)): - sval = value.isoformat() - else: - sval = str(value) - - dest[attr_name_lower] = sval - - def build_update_commands( - self, index, commands, added_controls, removed_controls, isolated: bool = False - ) -> None: - update_cmd = self._build_command(update=True) - - if len(update_cmd.attrs) > 0: - update_cmd.name = "set" - commands.append(update_cmd) - if isolated: - return - # go through children - - previous_children = self.__previous_children - current_children = self._get_children() - - hashes = {} - previous_ints = [] - current_ints = [] - - for ctrl in previous_children: - hashes[hash(ctrl)] = ctrl - previous_ints.append(hash(ctrl)) - for ctrl in current_children: - hashes[hash(ctrl)] = ctrl - current_ints.append(hash(ctrl)) - sm = SequenceMatcher(None, previous_ints, current_ints) - - n = 0 - for tag, a1, a2, b1, b2 in sm.get_opcodes(): - if tag == "delete" or tag == "replace": - # deleted controls - - ids = [] - for h in previous_ints[a1:a2]: - ctrl = hashes[h] - # check if re-added control is being deleted - # which means it's a replace - - i = 0 - replaced = False - while i < len(commands): - cmd = commands[i] - if cmd.name == "add" and any( - c for c in cmd.commands if c.attrs.get("id") == ctrl.__uid - ): - # insert delete command before add - - commands.insert(i, Command(0, "remove", [ctrl.__uid])) - replaced = True - break - i += 1 - removed_controls.extend( - self._remove_control_recursively(index, ctrl) - ) - if not replaced: - ids.append(ctrl.__uid) - if len(ids) > 0: - commands.append(Command(0, "remove", ids)) - if tag == "replace": - # add - - for h in current_ints[b1:b2]: - ctrl = hashes[h] - innerCmds = ctrl._build_add_commands( - index=index, added_controls=added_controls - ) - assert self.__uid is not None - ctrl.parent = self # set as parent - commands.append( - Command( - indent=0, - name="add", - attrs={"to": self.__uid, "at": str(n)}, - commands=innerCmds, - ) - ) - n += 1 - elif tag == "equal": - # unchanged control - - for h in previous_ints[a1:a2]: - ctrl = hashes[h] - ctrl.build_update_commands( - index, - commands, - added_controls, - removed_controls, - isolated=ctrl.is_isolated(), - ) - n += 1 - elif tag == "insert": - # add - - for h in current_ints[b1:b2]: - ctrl = hashes[h] - innerCmds = ctrl._build_add_commands( - index=index, added_controls=added_controls - ) - assert self.__uid is not None - ctrl.parent = self # set as parent - commands.append( - Command( - indent=0, - name="add", - attrs={"to": self.__uid, "at": str(n)}, - commands=innerCmds, - ) - ) - n += 1 - self.__previous_children.clear() - self.__previous_children.extend(current_children) - - def _remove_control_recursively(self, index, control: "Control") -> "List[Control]": - removed_controls = [] - - if control.__uid in index: - del index[control.__uid] - - for child in control._get_children(): - removed_controls.extend(self._remove_control_recursively(index, child)) - for child in control._previous_children: - removed_controls.extend(self._remove_control_recursively(index, child)) - removed_controls.append(control) - return removed_controls - - # private methods - def _build_add_commands( - self, indent: int = 0, index=None, added_controls=None - ) -> List[Command]: - if index: - self.page = index["page"] - self.build() - - # remove control from index - if self.__uid and index is not None and self.__uid in index: - del index[self.__uid] - commands = [] - - # main command - command = self._build_command(False) - command.indent = indent - command.values.append(self._get_control_name()) - commands.append(command) - - if added_controls is not None: - added_controls.append(self) - # controls - - children = self._get_children() - for control in children: - childCmd = control._build_add_commands( - indent=indent + 2, index=index, added_controls=added_controls - ) - commands.extend(childCmd) - control.parent = self # set as parent - self.__previous_children.clear() - self.__previous_children.extend(children) - - return commands - - def _build_command(self, update: bool = False) -> Command: - command = Command(0, None, [], {}, []) - - if update and not self.__uid: - return command - self._before_build_command() - self.before_update() - - for attrName in sorted(self.__attrs): - attrName = attrName.lower() - dirty = self.__attrs[attrName][1] - - if (update and not dirty) or attrName == "id": - continue - val = self.__attrs[attrName][0] - sval = "" - if val is None: - continue - elif isinstance(val, bool): - sval = str(val).lower() - elif isinstance(val, dt.datetime) or isinstance(val, dt.date): - sval = val.isoformat() - else: - sval = str(val) - command.attrs[attrName] = sval - self.__attrs[attrName] = (val, False) - id = self.__attrs.get("id") - if not update and self.__uid is not None: - command.attrs["id"] = self.__uid - elif not update and id is not None: - command.attrs["id"] = id - elif update and len(command.attrs) > 0: - assert self.__uid is not None - command.values.append(self.__uid) - return command - - def _dispose(self) -> None: - self.page = None - self.__event_handlers.clear() - - # Magic methods - def __str__(self) -> str: - attrs = {} - for k, v in self.__attrs.items(): - attrs[k] = v[0] - return f"{self._get_control_name()} {attrs}" - - def __repr__(self) -> str: - return ( - f"{self.__class__.__name__}(" - + ", ".join( - f"{k}={v[0]}" if not isinstance(v[0], str) else f"{k}='{v[0]}'" - for k, v in self.__attrs.items() - ) - + ")" - ) diff --git a/sdk/python/packages/flet/src/flet/core/control_event.py b/sdk/python/packages/flet/src/flet/core/control_event.py deleted file mode 100644 index 0532208a9f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/control_event.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Optional - -from flet.core.event import Event - - -class ControlEvent(Event): - def __init__(self, target: str, name: str, data: Optional[str], control, page): - Event.__init__(self, target=target, name=name, data=data) - - self.control = control - self.page = page diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_action_sheet.py b/sdk/python/packages/flet/src/flet/core/cupertino_action_sheet.py deleted file mode 100644 index d717d8be19..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_action_sheet.py +++ /dev/null @@ -1,155 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoActionSheet(ConstrainedControl): - """ - An iOS-style action sheet. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoactionsheet - """ - - def __init__( - self, - title: Optional[Control] = None, - message: Optional[Control] = None, - actions: Optional[List[Control]] = None, - cancel: Optional[Control] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.cancel = cancel - self.title = title - self.message = message - self.actions = actions - - def _get_control_name(self): - return "cupertinoactionsheet" - - def _get_children(self): - children = [] - if self.__cancel: - self.__cancel._set_attr_internal("n", "cancel") - children.append(self.__cancel) - if self.__title: - self.__title._set_attr_internal("n", "title") - children.append(self.__title) - if self.__message: - self.__message._set_attr_internal("n", "message") - children.append(self.__message) - for action in self.__actions: - action._set_attr_internal("n", "action") - children.append(action) - return children - - # cancel - @property - def cancel(self) -> Optional[Control]: - return self.__cancel - - @cancel.setter - def cancel(self, value: Optional[Control]): - self.__cancel = value - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # message - @property - def message(self) -> Optional[Control]: - return self.__message - - @message.setter - def message(self, value: Optional[Control]): - self.__message = value - - # actions - @property - def actions(self) -> List[Control]: - return self.__actions - - @actions.setter - def actions(self, value: Optional[List[Control]]): - self.__actions = value if value is not None else [] diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_action_sheet_action.py b/sdk/python/packages/flet/src/flet/core/cupertino_action_sheet_action.py deleted file mode 100644 index 1fabf455b5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_action_sheet_action.py +++ /dev/null @@ -1,175 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoActionSheetAction(ConstrainedControl): - """ - An action button typically used in a CupertinoActionSheet. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoactionsheetaction - """ - - def __init__( - self, - text: Optional[str] = None, - content: Optional[Control] = None, - is_default_action: Optional[bool] = None, - is_destructive_action: Optional[bool] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_click: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.text = text - self.content = content - self.is_default_action = is_default_action - self.is_destructive_action = is_destructive_action - self.mouse_cursor = mouse_cursor - self.on_click = on_click - - def _get_control_name(self): - return "cupertinoactionsheetaction" - - def _get_children(self): - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - return [self.__content] - return [] - - def before_update(self): - super().before_update() - assert self.text is not None or ( - (self.__content is not None and self.__content.visible) - ), "either text or (visible) content must be provided visible" - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # is_default_action - @property - def is_default_action(self) -> bool: - return self._get_attr("isDefaultAction", data_type="bool", def_value=False) - - @is_default_action.setter - def is_default_action(self, value: Optional[bool]): - self._set_attr("isDefaultAction", value) - - # is_destructive_action - @property - def is_destructive_action(self) -> bool: - return self._get_attr("isDestructiveAction", data_type="bool", def_value=False) - - @is_destructive_action.setter - def is_destructive_action(self, value: Optional[bool]): - self._set_attr("isDestructiveAction", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_activity_indicator.py b/sdk/python/packages/flet/src/flet/core/cupertino_activity_indicator.py deleted file mode 100644 index 41a7f3ba88..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_activity_indicator.py +++ /dev/null @@ -1,119 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoActivityIndicator(ConstrainedControl): - """ - An iOS-style activity indicator that spins clockwise. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoactivityindicator - """ - - def __init__( - self, - radius: OptionalNumber = None, - color: Optional[ColorValue] = None, - animating: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.color = color - self.radius = radius - self.animating = animating - - def _get_control_name(self): - return "cupertinoactivityindicator" - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # animating - @property - def animating(self) -> bool: - return self._get_attr("animating", data_type="bool", def_value=True) - - @animating.setter - def animating(self, value: Optional[bool]): - self._set_attr("animating", value) - - # radius - @property - def radius(self) -> OptionalNumber: - return self._get_attr("radius", data_type="float") - - @radius.setter - def radius(self, value: OptionalNumber): - self._set_attr("radius", value) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_alert_dialog.py b/sdk/python/packages/flet/src/flet/core/cupertino_alert_dialog.py deleted file mode 100644 index 9ae8919893..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_alert_dialog.py +++ /dev/null @@ -1,214 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.animation import Animation -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class CupertinoAlertDialog(Control): - """ - An iOS-style alert dialog. - An alert dialog informs the user about situations that require acknowledgement. An alert dialog has an optional title and an optional list of actions. The title is displayed above the content and the actions are displayed below the content. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.scroll = True - - def handle_action_click(e): - page.add(ft.Text(f"Action clicked: {e.control.text}")) - # e.control is the clicked action button, e.control.parent is the corresponding parent dialog of the button - page.close(e.control.parent) - - cupertino_actions = [ - ft.CupertinoDialogAction( - "Yes", - is_destructive_action=True, - on_click=handle_action_click, - ), - ft.CupertinoDialogAction( - text="No", - is_default_action=False, - on_click=handle_action_click, - ), - ] - - material_actions = [ - ft.TextButton(text="Yes", on_click=handle_action_click), - ft.TextButton(text="No", on_click=handle_action_click), - ] - - page.add( - ft.FilledButton( - text="Open Material Dialog", - on_click=lambda e: page.open( - ft.AlertDialog( - title=ft.Text("Material Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - actions=material_actions, - ) - ), - ), - ft.CupertinoFilledButton( - text="Open Cupertino Dialog", - on_click=lambda e: page.open( - ft.CupertinoAlertDialog( - title=ft.Text("Cupertino Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - actions=cupertino_actions, - ) - ), - ), - ft.FilledButton( - text="Open Adaptive Dialog", - adaptive=True, - on_click=lambda e: page.open( - ft.AlertDialog( - adaptive=True, - title=ft.Text("Adaptive Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - actions=cupertino_actions if page.platform in [ft.PagePlatform.IOS, ft.PagePlatform.MACOS] else material_actions, - ) - ), - ), - ) - - - ft.app(target=main) - ``` - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoalertdialog - """ - - def __init__( - self, - open: bool = False, - modal: bool = False, - title: Optional[Control] = None, - content: Optional[Control] = None, - actions: Optional[List[Control]] = None, - inset_animation: Optional[Animation] = None, - on_dismiss: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - barrier_color: Optional[str] = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.open = open - self.modal = modal - self.title = title - self.content = content - self.actions = actions - self.on_dismiss = on_dismiss - self.barrier_color = barrier_color - self.inset_animation = inset_animation - - def _get_control_name(self): - return "cupertinoalertdialog" - - def before_update(self): - super().before_update() - self._set_attr_json("insetAnimation", self.__inset_animation) - - def _get_children(self): - children = [] - if self.__title: - self.__title._set_attr_internal("n", "title") - children.append(self.__title) - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - for action in self.__actions: - action._set_attr_internal("n", "action") - children.append(action) - return children - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # modal - @property - def modal(self) -> bool: - return self._get_attr("modal", data_type="bool", def_value=False) - - @modal.setter - def modal(self, value: Optional[bool]): - self._set_attr("modal", value) - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # inset_animation - @property - def inset_animation(self) -> Optional[Animation]: - return self.__inset_animation - - @inset_animation.setter - def inset_animation(self, value: Optional[Animation]): - self.__inset_animation = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # barrier_color - @property - def barrier_color(self) -> Optional[str]: - return self._get_attr("barrierColor") - - @barrier_color.setter - def barrier_color(self, value: Optional[str]): - self._set_attr("barrierColor", value) - - # actions - @property - def actions(self) -> List[Control]: - return self.__actions - - @actions.setter - def actions(self, value: Optional[List[Control]]): - self.__actions = value if value is not None else [] - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_app_bar.py b/sdk/python/packages/flet/src/flet/core/cupertino_app_bar.py deleted file mode 100644 index 61a3d23f99..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_app_bar.py +++ /dev/null @@ -1,293 +0,0 @@ -from typing import Any, Optional - -from flet.core.border import Border -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import Brightness, ColorEnums, ColorValue, PaddingValue -from flet.utils.deprecated import deprecated_property - - -class CupertinoAppBar(Control): - """ - An iOS-styled application bar. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.theme_mode = ft.ThemeMode.LIGHT - - page.appbar = ft.CupertinoAppBar( - leading=ft.Icon(ft.icons.PALETTE), - bgcolor=ft.colors.SURFACE_VARIANT, - trailing=ft.Icon(ft.icons.WB_SUNNY_OUTLINED), - middle=ft.Text("AppBar Example"), - ) - page.add(ft.Text("Body!")) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoappbar - """ - - def __init__( - self, - leading: Optional[Control] = None, - middle: Optional[Control] = None, - title: Optional[Control] = None, - trailing: Optional[Control] = None, - bgcolor: Optional[ColorValue] = None, - automatically_imply_leading: Optional[bool] = None, - automatically_imply_middle: Optional[bool] = None, - automatically_imply_title: Optional[bool] = None, - border: Optional[Border] = None, - padding: Optional[PaddingValue] = None, - transition_between_routes: Optional[bool] = None, - previous_page_title: Optional[str] = None, - brightness: Optional[Brightness] = None, - automatic_background_visibility: Optional[bool] = None, - enable_background_filter_blur: Optional[bool] = None, - large: Optional[bool] = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - Control.__init__( - self, ref=ref, visible=visible, disabled=disabled, data=data, rtl=rtl - ) - - self.leading = leading - self.middle = middle - self.title = title - self.automatically_imply_leading = automatically_imply_leading - self.automatically_imply_middle = automatically_imply_middle - self.automatically_imply_title = automatically_imply_title - self.border = border - self.padding = padding - self.trailing = trailing - self.transition_between_routes = transition_between_routes - self.previous_page_title = previous_page_title - self.bgcolor = bgcolor - self.brightness = brightness - self.automatic_background_visibility = automatic_background_visibility - self.enable_background_filter_blur = enable_background_filter_blur - self.large = large - - def _get_control_name(self): - return "cupertinoappbar" - - def before_update(self): - super().before_update() - self._set_attr_json("border", self.__border) - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - children = [] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__title or self.__middle: - t = self.__title or self.__middle - t._set_attr_internal("n", "title") - children.append(t) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - return children - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - """ - A Control to display before the toolbar's title. - - Typically the leading control is an Icon or an IconButton. - """ - self.__leading = value - - # middle - @property - def middle(self) -> Optional[Control]: - deprecated_property( - name="middle", - version="0.27.0", - delete_version="0.30.0", - reason="Use title instead.", - ) - return self.__middle - - @middle.setter - def middle(self, value: Optional[Control]): - self.__middle = value - if value is not None: - deprecated_property( - name="middle", - version="0.27.0", - delete_version="0.30.0", - reason="Use title instead.", - ) - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # automatically_imply_leading - @property - def automatically_imply_leading(self) -> bool: - return self._get_attr( - "automaticallyImplyLeading", data_type="bool", def_value=True - ) - - @automatically_imply_leading.setter - def automatically_imply_leading(self, value: Optional[bool]): - self._set_attr("automaticallyImplyLeading", value) - - # automatically_imply_middle - @property - def automatically_imply_middle(self) -> bool: - deprecated_property( - name="automatically_imply_middle", - version="0.27.0", - delete_version="0.30.0", - reason="Use automatically_imply_title instead.", - ) - return self._get_attr( - "automaticallyImplyMiddle", data_type="bool", def_value=True - ) - - @automatically_imply_middle.setter - def automatically_imply_middle(self, value: Optional[bool]): - self._set_attr("automaticallyImplyMiddle", value) - if value is not None: - deprecated_property( - name="automatically_imply_middle", - version="0.27.0", - delete_version="0.30.0", - reason="Use automatically_imply_title instead.", - ) - - # automatically_imply_title - @property - def automatically_imply_title(self) -> bool: - return self._get_attr( - "automaticallyImplyTitle", data_type="bool", def_value=True - ) - - @automatically_imply_title.setter - def automatically_imply_title(self, value: Optional[bool]): - self._set_attr("automaticallyImplyTitle", value) - - # large - @property - def large(self) -> bool: - return self._get_attr("large", data_type="bool", def_value=False) - - @large.setter - def large(self, value: Optional[bool]): - self._set_attr("large", value) - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # transition_between_routes - @property - def transition_between_routes(self) -> bool: - return self._get_attr( - "transitionBetweenRoutes", data_type="bool", def_value=True - ) - - @transition_between_routes.setter - def transition_between_routes(self, value: Optional[bool]): - self._set_attr("transitionBetweenRoutes", value) - - # previous_page_title - @property - def previous_page_title(self): - return self._get_attr("previousPageTitle") - - @previous_page_title.setter - def previous_page_title(self, value): - self._set_attr("previousPageTitle", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # brightness - @property - def brightness(self) -> Optional[Brightness]: - return self.__brightness - - @brightness.setter - def brightness(self, value: Optional[Brightness]): - self.__brightness = value - self._set_enum_attr("brightness", value, Brightness) - - # automatic_background_visibility - @property - def automatic_background_visibility(self) -> Optional[bool]: - return self._get_attr( - "automaticBackgroundVisibility", data_type="bool", def_value=True - ) - - @automatic_background_visibility.setter - def automatic_background_visibility(self, value: Optional[bool]): - self._set_attr("automaticBackgroundVisibility", value) - - # enable_background_filter_blur - @property - def enable_background_filter_blur(self) -> Optional[bool]: - return self._get_attr("backgroundFilterBlur", data_type="bool", def_value=True) - - @enable_background_filter_blur.setter - def enable_background_filter_blur(self, value: Optional[bool]): - self._set_attr("backgroundFilterBlur", value) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_bottom_sheet.py b/sdk/python/packages/flet/src/flet/core/cupertino_bottom_sheet.py deleted file mode 100644 index c8bc6e3284..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_bottom_sheet.py +++ /dev/null @@ -1,133 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - ColorEnums, - ColorValue, - OptionalControlEventCallable, - PaddingValue, -) - - -class CupertinoBottomSheet(Control): - """ - A Cupertino version of modal bottom sheet. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinobottomsheet - """ - - def __init__( - self, - content: Optional[Control] = None, - open: bool = False, - modal: bool = False, - bgcolor: Optional[ColorValue] = None, - height: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - on_dismiss: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.__content: Optional[Control] = None - - self.open = open - self.modal = modal - self.bgcolor = bgcolor - self.height = height - self.padding = padding - self.content = content - self.on_dismiss = on_dismiss - - def _get_control_name(self): - return "cupertinobottomsheet" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - children = [] - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # modal - @property - def modal(self) -> bool: - return self._get_attr("modal", data_type="bool", def_value=False) - - @modal.setter - def modal(self, value: Optional[bool]): - self._set_attr("modal", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # height - @property - def height(self) -> float: - return self._get_attr("height", data_type="float", def_value=220.0) - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # content - @property - def content(self): - return self.__content - - @content.setter - def content(self, value): - self.__content = value - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_button.py b/sdk/python/packages/flet/src/flet/core/cupertino_button.py deleted file mode 100644 index dae41a3618..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_button.py +++ /dev/null @@ -1,348 +0,0 @@ -import warnings -from typing import Any, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, -) - - -class CupertinoButton(ConstrainedControl): - """ - An iOS-style button. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinobutton - """ - - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - icon_color: Optional[ColorValue] = None, - content: Optional[Control] = None, - bgcolor: Optional[ColorValue] = None, - color: Optional[ColorValue] = None, - disabled_bgcolor: Optional[ColorValue] = None, - opacity_on_click: OptionalNumber = None, - min_size: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - alignment: Optional[Alignment] = None, - border_radius: Optional[BorderRadiusValue] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - autofocus: Optional[bool] = None, - focus_color: Optional[bool] = None, - on_click: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.disabled_bgcolor = disabled_bgcolor - self.text = text - self.icon = icon - self.icon_color = icon_color - self.bgcolor = bgcolor - self.color = color - self.border_radius = border_radius - self.min_size = min_size - self.opacity_on_click = opacity_on_click - self.padding = padding - self.alignment = alignment - self.content = content - self.url = url - self.url_target = url_target - self.on_click = on_click - self.on_long_press = on_long_press - self.on_focus = on_focus - self.on_blur = on_blur - self.autofocus = autofocus - self.focus_color = focus_color - - def _get_control_name(self): - return "cupertinobutton" - - def before_update(self): - super().before_update() - assert ( - self.text or self.icon or (self.__content and self.__content.visible) - ), "at minimum, text, icon or a visible content must be provided" - self._set_attr_json("padding", self.__padding) - self._set_attr_json("borderRadius", self.__border_radius) - self._set_attr_json("alignment", self.__alignment) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # text - @property - def text(self): - return self._get_attr("text") - - @text.setter - def text(self, value): - self._set_attr("text", value) - - # focus_color - @property - def focus_color(self): - return self.__focus_color - - @focus_color.setter - def focus_color(self, value): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # autofocus - @property - def autofocus(self): - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value): - self._set_attr("autofocus", value) - - # icon - @property - def icon(self): - return self.__icon - - @icon.setter - def icon(self, value): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # icon_color - @property - def icon_color(self): - return self.__icon_color - - @icon_color.setter - def icon_color(self, value): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # disabled_bgcolor - @property - def disabled_bgcolor(self) -> Optional[str]: - return self.__disabled_bgcolor - - @disabled_bgcolor.setter - def disabled_bgcolor(self, value: Optional[str]): - self.__disabled_bgcolor = value - self._set_enum_attr("disabledBgcolor", value, ColorEnums) - - # opacity_on_click - @property - def opacity_on_click(self) -> float: - return self._get_attr("opacityOnClick", data_type="float", def_value=0.4) - - @opacity_on_click.setter - def opacity_on_click(self, value: OptionalNumber): - if value is not None: - value = max(0.0, min(value, 1.0)) # make sure 0.0 <= value <= 1.0 - self._set_attr("opacityOnClick", value) - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # min_size - @property - def min_size(self) -> float: - return self._get_attr("minSize", data_type="float", def_value=44.0) - - @min_size.setter - def min_size(self, value: OptionalNumber): - self._set_attr("minSize", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # url - @property - def url(self): - return self._get_attr("url") - - @url.setter - def url(self, value): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("longPress") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("longPress", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_checkbox.py b/sdk/python/packages/flet/src/flet/core/cupertino_checkbox.py deleted file mode 100644 index 7b211151d7..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_checkbox.py +++ /dev/null @@ -1,305 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import BorderSide -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - LabelPosition, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoCheckbox(ConstrainedControl): - """ - A macOS style checkbox. Checkbox allows to select one or more items from a group, or switch between two mutually exclusive options (checked or unchecked, on or off). - - Example: - ``` - import flet as ft - - def main(page): - c = ft.CupertinoCheckbox( - label="Cupertino Checkbox", - active_color=ft.colors.GREEN, - inactive_color=ft.colors.RED, - check_color=ft.colors.BLUE, - ), - page.add(c) - - ft.app(target=main) - ``` - - ----- - Online docs: https://flet.dev/docs/controls/cupertinocheckbox - """ - - def __init__( - self, - label: Optional[str] = None, - label_position: Optional[LabelPosition] = None, - value: Optional[bool] = None, - tristate: Optional[bool] = None, - autofocus: Optional[bool] = None, - check_color: Optional[ColorValue] = None, - active_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - fill_color: ControlStateValue[ColorValue] = None, - shape: Optional[OutlinedBorder] = None, - mouse_cursor: Optional[MouseCursor] = None, - semantics_label: Optional[str] = None, - border_side: ControlStateValue[BorderSide] = None, - on_change: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.tristate = tristate - self.label = label - self.label_position = label_position - self.autofocus = autofocus - self.check_color = check_color - self.active_color = active_color - self.focus_color = focus_color - self.on_change = on_change - self.on_focus = on_focus - self.on_blur = on_blur - self.shape = shape - self.mouse_cursor = mouse_cursor - self.semantics_label = semantics_label - self.border_side = border_side - self.fill_color = fill_color - - def _get_control_name(self): - return "cupertinocheckbox" - - def before_update(self): - super().before_update() - self._set_attr_json("shape", self.__shape) - self._set_attr_json("borderSide", self.__border_side, wrap_attr_dict=True) - self._set_attr_json("fillColor", self.__fill_color, wrap_attr_dict=True) - - # value - @property - def value(self) -> Optional[bool]: - return self._get_attr( - "value", data_type="bool?", def_value=False if not self.tristate else None - ) - - @value.setter - def value(self, value: Optional[bool]): - self._set_attr("value", value) - - # tristate - @property - def tristate(self) -> bool: - return self._get_attr("tristate", data_type="bool", def_value=False) - - @tristate.setter - def tristate(self, value: Optional[bool]): - self._set_attr("tristate", value) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # label_position - @property - def label_position(self) -> Optional[LabelPosition]: - return self.__label_position - - @label_position.setter - def label_position(self, value: Optional[LabelPosition]): - self.__label_position = value - self._set_enum_attr("labelPosition", value, LabelPosition) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # check_color - @property - def check_color(self) -> Optional[ColorValue]: - return self.__check_color - - @check_color.setter - def check_color(self, value: Optional[ColorValue]): - self.__check_color = value - self._set_enum_attr("checkColor", value, ColorEnums) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # fill_color - @property - def fill_color(self) -> ControlStateValue[ColorValue]: - return self.__fill_color - - @fill_color.setter - def fill_color(self, value: ControlStateValue[ColorValue]): - self.__fill_color = value - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # border_side - @property - def border_side(self) -> ControlStateValue[BorderSide]: - return self.__border_side - - @border_side.setter - def border_side(self, value: ControlStateValue[BorderSide]): - self.__border_side = value - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_colors.py b/sdk/python/packages/flet/src/flet/core/cupertino_colors.py deleted file mode 100644 index e44ffbd352..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_colors.py +++ /dev/null @@ -1,117 +0,0 @@ -""" -url='https://raw.githubusercontent.com/flutter/flutter/stable/packages/flutter/lib/src/cupertino/colors.dart' -output_file="$HOME/cupertino_python_colors.txt" -curl -s $url | python -c ' -import re - -for line in __import__("sys").stdin: - match1 = re.search(r"static const CupertinoDynamicColor ([a-zA-Z0-9_]+)", line) - match2 = re.search(r"static const Color ([a-zA-Z0-9_]+)", line) - if match1: - print("{} = \"{}\"".format(match1.group(1).upper(), match1.group(1))) - elif match2: - print("{} = \"{}\"".format(match2.group(1).upper(), match2.group(1))) -' >> "$output_file" -""" - -import random -from enum import Enum -from typing import TYPE_CHECKING, Dict, List, Optional, Union - -if TYPE_CHECKING: - from flet.core.types import ColorValue - - -class CupertinoColors(str, Enum): - @staticmethod - def with_opacity(opacity: Union[int, float], color: "ColorValue") -> str: - """ - Returns the color with the specified opacity. - - Args: - opacity: The opacity value, which must be between 0 and 1. - color: The color value. - - Returns: - A string representing the color value with the specified opacity appended. - - Raises: - AssertionError: If the opacity is not between 0 and 1 (inclusive). - """ - assert 0 <= opacity <= 1, "opacity must be between 0 and 1" - color_str = color.value if isinstance(color, Enum) else color - return f"{color_str},{opacity}" - - @staticmethod - def random( - exclude: Optional[List["CupertinoColors"]] = None, - weights: Optional[Dict["CupertinoColors", int]] = None, - ) -> Optional["CupertinoColors"]: - """ - Selects a random color, with optional exclusions and weights. - - Args: - exclude: A list of colors members to exclude from the selection. - weights: A dictionary mapping color members to their respective weights for weighted random selection. - - Returns: - A randomly selected color, or None if all members are excluded. - """ - choices = list(CupertinoColors) - if exclude: - choices = [member for member in choices if member not in exclude] - if not choices: - return None - if weights: - weights_list = [weights.get(c, 1) for c in choices] - return random.choices(choices, weights=weights_list)[0] - return random.choice(choices) - - PRIMARY = "primary" - ON_PRIMARY = "onprimary" - ACTIVE_BLUE = "activeBlue" - ACTIVE_GREEN = "activeGreen" - ACTIVE_ORANGE = "activeOrange" - WHITE = "cupertinoWhite" - BLACK = "cupertinoBlack" - LIGHT_BACKGROUND_GRAY = "lightBackgroundGray" - EXTRA_LIGHT_BACKGROUND_GRAY = "extraLightBackgroundGray" - DARK_BACKGROUND_GRAY = "darkBackgroundGray" - INACTIVE_GRAY = "inactiveGray" - DESTRUCTIVE_RED = "destructiveRed" - SYSTEM_BLUE = "systemBlue" - SYSTEM_GREEN = "systemGreen" - SYSTEM_MINT = "systemMint" - SYSTEM_INDIGO = "systemIndigo" - SYSTEM_ORANGE = "systemOrange" - SYSTEM_PINK = "systemPink" - SYSTEM_BROWN = "systemBrown" - SYSTEM_PURPLE = "systemPurple" - SYSTEM_RED = "systemRed" - SYSTEM_TEAL = "systemTeal" - SYSTEM_CYAN = "systemCyan" - SYSTEM_YELLOW = "systemYellow" - SYSTEM_GREY = "systemGrey" - SYSTEM_GREY2 = "systemGrey2" - SYSTEM_GREY3 = "systemGrey3" - SYSTEM_GREY4 = "systemGrey4" - SYSTEM_GREY5 = "systemGrey5" - SYSTEM_GREY6 = "systemGrey6" - LABEL = "label" - SECONDARY_LABEL = "secondaryLabel" - TERTIARY_LABEL = "tertiaryLabel" - QUATERNARY_LABEL = "quaternaryLabel" - SYSTEM_FILL = "systemFill" - SECONDARY_SYSTEM_FILL = "secondarySystemFill" - TERTIARY_SYSTEM_FILL = "tertiarySystemFill" - QUATERNARY_SYSTEM_FILL = "quaternarySystemFill" - PLACEHOLDER_TEXT = "placeholderText" - SYSTEM_BACKGROUND = "systemBackground" - SECONDARY_SYSTEM_BACKGROUND = "secondarySystemBackground" - TERTIARY_SYSTEM_BACKGROUND = "tertiarySystemBackground" - SYSTEM_GROUPED_BACKGROUND = "systemGroupedBackground" - SECONDARY_SYSTEM_GROUPED_BACKGROUND = "secondarySystemGroupedBackground" - TERTIARY_SYSTEM_GROUPED_BACKGROUND = "tertiarySystemGroupedBackground" - SEPARATOR = "separator" - OPAQUE_SEPARATOR = "opaqueSeparator" - LINK = "link" diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_context_menu.py b/sdk/python/packages/flet/src/flet/core/cupertino_context_menu.py deleted file mode 100644 index 199f958983..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_context_menu.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.control import Control -from flet.core.ref import Ref - - -class CupertinoContextMenu(AdaptiveControl): - """ - A full-screen modal route that opens up when the content is long-pressed. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinocontextmenu - """ - - def __init__( - self, - content: Control, - actions: List[Control], - enable_haptic_feedback: Optional[bool] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = False, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.enable_haptic_feedback = enable_haptic_feedback - self.content = content - self.actions = actions - - def _get_control_name(self): - return "cupertinocontextmenu" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - for action in self.__actions: - action._set_attr_internal("n", "action") - return [self.__content] + self.__actions - - def before_update(self): - super().before_update() - assert ( - len(self.__actions) > 0 - ), "actions must be provided and at least one must be visible" - - # enable_haptic_feedback - @property - def enable_haptic_feedback(self) -> bool: - return self._get_attr("enableHapticFeedback", data_type="bool", def_value=False) - - @enable_haptic_feedback.setter - def enable_haptic_feedback(self, value: Optional[bool]): - self._set_attr("enableHapticFeedback", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # actions - @property - def actions(self) -> List[Control]: - return self.__actions - - @actions.setter - def actions(self, value: List[Control]): - self.__actions = value diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_context_menu_action.py b/sdk/python/packages/flet/src/flet/core/cupertino_context_menu_action.py deleted file mode 100644 index d1a535ae07..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_context_menu_action.py +++ /dev/null @@ -1,111 +0,0 @@ -from typing import Any, Optional - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import IconEnums, IconValue, OptionalControlEventCallable - - -class CupertinoContextMenuAction(AdaptiveControl): - """ - An action that can be added to a CupertinoContextMenu. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinocontextmenuaction - """ - - def __init__( - self, - text: Optional[str] = None, - content: Optional[Control] = None, - is_default_action: Optional[bool] = None, - is_destructive_action: Optional[bool] = None, - trailing_icon: Optional[IconValue] = None, - on_click: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = False, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.is_default_action = is_default_action - self.is_destructive_action = is_destructive_action - self.content = content - self.trailing_icon = trailing_icon - self.on_click = on_click - self.text = text - - def _get_control_name(self): - return "cupertinocontextmenuaction" - - def _get_children(self): - return [self.__content] if self.__content else [] - - # is_default_action - @property - def is_default_action(self) -> bool: - return self._get_attr("isDefaultAction", data_type="bool", def_value=False) - - @is_default_action.setter - def is_default_action(self, value: Optional[bool]): - self._set_attr("isDefaultAction", value) - - # is_destructive_action - @property - def is_destructive_action(self) -> bool: - return self._get_attr("isDestructiveAction", data_type="bool", def_value=False) - - @is_destructive_action.setter - def is_destructive_action(self, value: Optional[bool]): - self._set_attr("isDestructiveAction", value) - - # trailing_icon - @property - def trailing_icon(self) -> Optional[IconValue]: - return self.__trailing_icon - - @trailing_icon.setter - def trailing_icon(self, value: Optional[IconValue]): - self.__trailing_icon = value - self._set_enum_attr("trailingIcon", value, IconEnums) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_date_picker.py b/sdk/python/packages/flet/src/flet/core/cupertino_date_picker.py deleted file mode 100644 index 2265fdf51d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_date_picker.py +++ /dev/null @@ -1,253 +0,0 @@ -from datetime import datetime -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - DateTimeValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoDatePickerMode(Enum): - TIME = "time" - DATE = "date" - DATE_AND_TIME = "dateAndTime" - MONTH_YEAR = "monthYear" - - -class CupertinoDatePickerDateOrder(Enum): - DAY_MONTH_YEAR = "dmy" - MONTH_YEAR_DAY = "myd" - YEAR_MONTH_DAY = "ymd" - YEAR_DAY_MONTH = "ydm" - - -class CupertinoDatePicker(ConstrainedControl): - """ - An iOS-styled date picker. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinodatepicker - """ - - def __init__( - self, - value: DateTimeValue = datetime.now(), - first_date: Optional[DateTimeValue] = None, - last_date: Optional[DateTimeValue] = None, - bgcolor: Optional[ColorValue] = None, - minute_interval: Optional[int] = None, - minimum_year: Optional[int] = None, - maximum_year: Optional[int] = None, - item_extent: OptionalNumber = None, - use_24h_format: Optional[bool] = None, - date_picker_mode: Optional[CupertinoDatePickerMode] = None, - date_order: Optional[CupertinoDatePickerDateOrder] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.bgcolor = bgcolor - self.minute_interval = minute_interval - self.maximum_year = maximum_year - self.minimum_year = minimum_year - self.item_extent = item_extent - self.first_date = first_date - self.use_24h_format = use_24h_format - self.last_date = last_date - self.date_picker_mode = date_picker_mode - self.date_order = date_order - self.on_change = on_change - - def _get_control_name(self): - return "cupertinodatepicker" - - # value - @property - def value(self) -> datetime: - v = self._get_attr("value") - return datetime.fromisoformat(v) if v else None - - @value.setter - def value(self, value: DateTimeValue): - self._set_attr("value", value.isoformat()) - - # first_date - @property - def first_date(self) -> Optional[datetime]: - v = self._get_attr("firstDate") - return datetime.fromisoformat(v) if v is not None else None - - @first_date.setter - def first_date(self, value: Optional[DateTimeValue]): - self.__first_date = value - self._set_attr("firstDate", value if value is None else value.isoformat()) - - # last_date - @property - def last_date(self) -> Optional[datetime]: - v = self._get_attr("lastDate") - return datetime.fromisoformat(v) if v is not None else None - - @last_date.setter - def last_date(self, value: Optional[DateTimeValue]): - self._set_attr("lastDate", value if value is None else value.isoformat()) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # item_extent - @property - def item_extent(self) -> float: - return self._get_attr("itemExtent", data_type="float", def_value=32.0) - - @item_extent.setter - def item_extent(self, value: OptionalNumber): - assert value is None or value > 0, "item_extent must be greater than 0" - self._set_attr("itemExtent", value) - - # min_year - @property - def min_year(self) -> int: - return self._get_attr("minYear", data_type="int", def_value=1) - - @min_year.setter - def min_year(self, value: Optional[int]): - self._set_attr("minYear", value) - - # max_year - @property - def max_year(self) -> Optional[int]: - return self._get_attr("maxYear", data_type="int") - - @max_year.setter - def max_year(self, value: Optional[int]): - self._set_attr("maxYear", value) - - # minute_interval - @property - def minute_interval(self) -> int: - return self._get_attr("minuteInterval", data_type="int", def_value=1) - - @minute_interval.setter - def minute_interval(self, value: Optional[int]): - assert value is None or ( - value > 0 and 60 % value == 0 - ), "minute_interval must be a positive integer factor of 60" - self._set_attr("minuteInterval", value) - - # use_24h_format - @property - def use_24h_format(self) -> Optional[int]: - return self._get_attr("use24hFormat", data_type="bool", def_value=False) - - @use_24h_format.setter - def use_24h_format(self, value: Optional[int]): - self._set_attr("use24hFormat", value) - - # date_picker_mode - @property - def date_picker_mode(self) -> Optional[CupertinoDatePickerMode]: - return self.__date_picker_mode - - @date_picker_mode.setter - def date_picker_mode(self, value: Optional[CupertinoDatePickerMode]): - self.__date_picker_mode = value - self._set_enum_attr("datePickerMode", value, CupertinoDatePickerMode) - - # date_order - @property - def date_order(self) -> Optional[CupertinoDatePickerDateOrder]: - return self.__date_order - - @date_order.setter - def date_order(self, value: Optional[CupertinoDatePickerDateOrder]): - self.__date_order = value - self._set_enum_attr("dateOrder", value, CupertinoDatePickerDateOrder) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_dialog_action.py b/sdk/python/packages/flet/src/flet/core/cupertino_dialog_action.py deleted file mode 100644 index 614761c2d7..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_dialog_action.py +++ /dev/null @@ -1,158 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import OptionalControlEventCallable - - -class CupertinoDialogAction(Control): - """ - A button typically used in a CupertinoAlertDialog. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def dialog_dismissed(e): - page.add(ft.Text("Dialog dismissed")) - - def handle_action_click(e): - page.add(ft.Text(f"Action clicked: {e.control.text}")) - page.close(cupertino_alert_dialog) - - cupertino_alert_dialog = ft.CupertinoAlertDialog( - title=ft.Text("Cupertino Alert Dialog"), - content=ft.Text("Do you want to delete this file?"), - on_dismiss=dialog_dismissed, - actions=[ - ft.CupertinoDialogAction( - text="Yes", - is_destructive_action=True, - on_click=handle_action_click, - ), - ft.CupertinoDialogAction( - text="No", - is_default_action=True, - on_click=handle_action_click - ), - ], - ) - - page.add( - ft.CupertinoFilledButton( - text="Open CupertinoAlertDialog", - on_click=lambda e: page.open(cupertino_alert_dialog), - ) - ) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinodialogaction - """ - - def __init__( - self, - text: Optional[str] = None, - content: Optional[Control] = None, - is_default_action: Optional[bool] = None, - is_destructive_action: Optional[bool] = None, - text_style: Optional[TextStyle] = None, - on_click: OptionalControlEventCallable = None, - # - # Specific - # - ref: Optional[Ref] = None, - opacity: OptionalNumber = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - opacity=opacity, - visible=visible, - data=data, - ) - - self.text = text - self.content = content - self.on_click = on_click - self.is_default_action = is_default_action - self.is_destructive_action = is_destructive_action - self.text_style = text_style - - def _get_control_name(self): - return "cupertinodialogaction" - - def before_update(self): - super().before_update() - self._set_attr_json("textStyle", self.__text_style) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # is_default_action - @property - def is_default_action(self) -> bool: - return self._get_attr("isDefaultAction", data_type="bool", def_value=False) - - @is_default_action.setter - def is_default_action(self, value: Optional[bool]): - self._set_attr("isDefaultAction", value) - - # is_destructive_action - @property - def is_destructive_action(self) -> bool: - return self._get_attr("isDestructiveAction", data_type="bool", def_value=False) - - @is_destructive_action.setter - def is_destructive_action(self, value: Optional[bool]): - self._set_attr("isDestructiveAction", value) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # text_style - @property - def text_style(self) -> Optional[TextStyle]: - return self.__text_style - - @text_style.setter - def text_style(self, value: Optional[TextStyle]): - self.__text_style = value diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_filled_button.py b/sdk/python/packages/flet/src/flet/core/cupertino_filled_button.py deleted file mode 100644 index eb02dda63b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_filled_button.py +++ /dev/null @@ -1,116 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.badge import BadgeValue -from flet.core.control import Control, OptionalNumber -from flet.core.cupertino_button import CupertinoButton -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - ColorValue, - IconValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - UrlTarget, -) - - -class CupertinoFilledButton(CupertinoButton): - """ - An iOS-style button filled with default background color. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.add( - ft.CupertinoFilledButton(text="OK"), - ) - - ft.app(target=main) - ``` - ----- - - Online docs: https://flet.dev/docs/controls/cupertinofilledbutton - """ - - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - icon_color: Optional[ColorValue] = None, - content: Optional[Control] = None, - disabled_bgcolor: Optional[ColorValue] = None, - opacity_on_click: OptionalNumber = None, - min_size: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - alignment: Optional[Alignment] = None, - border_radius: Optional[BorderRadiusValue] = None, - url: Optional[str] = None, - autofocus: Optional[bool] = None, - focus_color: Optional[bool] = None, - url_target: Optional[UrlTarget] = None, - on_click: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - CupertinoButton.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - # - # Specific - # - color="onPrimary", - bgcolor="primary", - disabled_bgcolor=disabled_bgcolor, - text=text, - icon=icon, - icon_color=icon_color, - content=content, - url=url, - url_target=url_target, - on_click=on_click, - border_radius=border_radius, - min_size=min_size, - opacity_on_click=opacity_on_click, - padding=padding, - alignment=alignment, - autofocus=autofocus, - focus_color=focus_color, - on_long_press=on_long_press, - on_focus=on_focus, - on_blur=on_blur, - ) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_icons.py b/sdk/python/packages/flet/src/flet/core/cupertino_icons.py deleted file mode 100644 index 28b1ea9f2f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_icons.py +++ /dev/null @@ -1,1387 +0,0 @@ -""" -Flet Cupertino Icons - -To generate/update these values run: - -sh ci/generate_cupertino_icons_python.sh -""" - -import random -from enum import Enum -from typing import Dict, List, Optional - - -class CupertinoIcons(str, Enum): - @staticmethod - def random( - exclude: Optional[List["CupertinoIcons"]] = None, - weights: Optional[Dict["CupertinoIcons", int]] = None, - ) -> Optional["CupertinoIcons"]: - """ - Selects a random icon, with optional exclusions and weights. - - Args: - exclude: A list of icons members to exclude from the selection. - weights: A dictionary mapping icon members to their respective weights for weighted random selection. - - Returns: - A randomly selected icon, or None if all members are excluded. - """ - choices = list(CupertinoIcons) - if exclude: - choices = [member for member in choices if member not in exclude] - if not choices: - return None - if weights: - weights_list = [weights.get(c, 1) for c in choices] - return random.choices(choices, weights=weights_list)[0] - return random.choice(choices) - - LEFT_CHEVRON = "cupertino_left_chevron" - RIGHT_CHEVRON = "cupertino_right_chevron" - SHARE = "cupertino_share" - SHARE_SOLID = "cupertino_share_solid" - BOOK = "cupertino_book" - BOOK_SOLID = "cupertino_book_solid" - BOOKMARK = "cupertino_bookmark" - BOOKMARK_SOLID = "cupertino_bookmark_solid" - INFO = "cupertino_info" - REPLY = "cupertino_reply" - CONVERSATION_BUBBLE = "cupertino_conversation_bubble" - PROFILE_CIRCLED = "cupertino_profile_circled" - PLUS_CIRCLED = "cupertino_plus_circled" - MINUS_CIRCLED = "cupertino_minus_circled" - FLAG = "cupertino_flag" - SEARCH = "cupertino_search" - CHECK_MARK = "cupertino_check_mark" - CHECK_MARK_CIRCLED = "cupertino_check_mark_circled" - CHECK_MARK_CIRCLED_SOLID = "cupertino_check_mark_circled_solid" - CIRCLE = "cupertino_circle" - CIRCLE_FILLED = "cupertino_circle_filled" - BACK = "cupertino_back" - FORWARD = "cupertino_forward" - HOME = "cupertino_home" - SHOPPING_CART = "cupertino_shopping_cart" - ELLIPSIS = "cupertino_ellipsis" - PHONE = "cupertino_phone" - PHONE_SOLID = "cupertino_phone_solid" - DOWN_ARROW = "cupertino_down_arrow" - UP_ARROW = "cupertino_up_arrow" - BATTERY_CHARGING = "cupertino_battery_charging" - BATTERY_EMPTY = "cupertino_battery_empty" - BATTERY_FULL = "cupertino_battery_full" - BATTERY_75_PERCENT = "cupertino_battery_75_percent" - BATTERY_25_PERCENT = "cupertino_battery_25_percent" - BLUETOOTH = "cupertino_bluetooth" - RESTART = "cupertino_restart" - REPLY_ALL = "cupertino_reply_all" - REPLY_THICK_SOLID = "cupertino_reply_thick_solid" - SHARE_UP = "cupertino_share_up" - SHUFFLE = "cupertino_shuffle" - SHUFFLE_MEDIUM = "cupertino_shuffle_medium" - SHUFFLE_THICK = "cupertino_shuffle_thick" - PHOTO_CAMERA = "cupertino_photo_camera" - PHOTO_CAMERA_SOLID = "cupertino_photo_camera_solid" - VIDEO_CAMERA = "cupertino_video_camera" - VIDEO_CAMERA_SOLID = "cupertino_video_camera_solid" - SWITCH_CAMERA = "cupertino_switch_camera" - SWITCH_CAMERA_SOLID = "cupertino_switch_camera_solid" - COLLECTIONS = "cupertino_collections" - COLLECTIONS_SOLID = "cupertino_collections_solid" - FOLDER = "cupertino_folder" - FOLDER_SOLID = "cupertino_folder_solid" - FOLDER_OPEN = "cupertino_folder_open" - DELETE = "cupertino_delete" - DELETE_SOLID = "cupertino_delete_solid" - DELETE_SIMPLE = "cupertino_delete_simple" - PEN = "cupertino_pen" - PENCIL = "cupertino_pencil" - CREATE = "cupertino_create" - CREATE_SOLID = "cupertino_create_solid" - REFRESH = "cupertino_refresh" - REFRESH_CIRCLED = "cupertino_refresh_circled" - REFRESH_CIRCLED_SOLID = "cupertino_refresh_circled_solid" - REFRESH_THIN = "cupertino_refresh_thin" - REFRESH_THICK = "cupertino_refresh_thick" - REFRESH_BOLD = "cupertino_refresh_bold" - CLEAR_THICK = "cupertino_clear_thick" - CLEAR_THICK_CIRCLED = "cupertino_clear_thick_circled" - CLEAR = "cupertino_clear" - CLEAR_CIRCLED = "cupertino_clear_circled" - CLEAR_CIRCLED_SOLID = "cupertino_clear_circled_solid" - ADD = "cupertino_add" - ADD_CIRCLED = "cupertino_add_circled" - ADD_CIRCLED_SOLID = "cupertino_add_circled_solid" - GEAR = "cupertino_gear" - GEAR_SOLID = "cupertino_gear_solid" - GEAR_BIG = "cupertino_gear_big" - SETTINGS = "cupertino_settings" - SETTINGS_SOLID = "cupertino_settings_solid" - MUSIC_NOTE = "cupertino_music_note" - DOUBLE_MUSIC_NOTE = "cupertino_double_music_note" - PLAY_ARROW = "cupertino_play_arrow" - PLAY_ARROW_SOLID = "cupertino_play_arrow_solid" - PAUSE = "cupertino_pause" - PAUSE_SOLID = "cupertino_pause_solid" - LOOP = "cupertino_loop" - LOOP_THICK = "cupertino_loop_thick" - VOLUME_DOWN = "cupertino_volume_down" - VOLUME_MUTE = "cupertino_volume_mute" - VOLUME_OFF = "cupertino_volume_off" - VOLUME_UP = "cupertino_volume_up" - FULLSCREEN = "cupertino_fullscreen" - FULLSCREEN_EXIT = "cupertino_fullscreen_exit" - MIC_OFF = "cupertino_mic_off" - MIC = "cupertino_mic" - MIC_SOLID = "cupertino_mic_solid" - CLOCK = "cupertino_clock" - CLOCK_SOLID = "cupertino_clock_solid" - TIME = "cupertino_time" - TIME_SOLID = "cupertino_time_solid" - PADLOCK = "cupertino_padlock" - PADLOCK_SOLID = "cupertino_padlock_solid" - EYE = "cupertino_eye" - EYE_SOLID = "cupertino_eye_solid" - PERSON = "cupertino_person" - PERSON_SOLID = "cupertino_person_solid" - PERSON_ADD = "cupertino_person_add" - PERSON_ADD_SOLID = "cupertino_person_add_solid" - GROUP = "cupertino_group" - GROUP_SOLID = "cupertino_group_solid" - MAIL = "cupertino_mail" - MAIL_SOLID = "cupertino_mail_solid" - LOCATION = "cupertino_location" - LOCATION_SOLID = "cupertino_location_solid" - TAG = "cupertino_tag" - TAG_SOLID = "cupertino_tag_solid" - TAGS = "cupertino_tags" - TAGS_SOLID = "cupertino_tags_solid" - BUS = "cupertino_bus" - CAR = "cupertino_car" - CAR_DETAILED = "cupertino_car_detailed" - TRAIN_STYLE_ONE = "cupertino_train_style_one" - TRAIN_STYLE_TWO = "cupertino_train_style_two" - PAW = "cupertino_paw" - PAW_SOLID = "cupertino_paw_solid" - GAME_CONTROLLER = "cupertino_game_controller" - GAME_CONTROLLER_SOLID = "cupertino_game_controller_solid" - LAB_FLASK = "cupertino_lab_flask" - LAB_FLASK_SOLID = "cupertino_lab_flask_solid" - HEART = "cupertino_heart" - HEART_SOLID = "cupertino_heart_solid" - BELL = "cupertino_bell" - BELL_SOLID = "cupertino_bell_solid" - NEWS = "cupertino_news" - NEWS_SOLID = "cupertino_news_solid" - BRIGHTNESS = "cupertino_brightness" - BRIGHTNESS_SOLID = "cupertino_brightness_solid" - AIRPLANE = "cupertino_airplane" - ALARM = "cupertino_alarm" - ALARM_FILL = "cupertino_alarm_fill" - ALT = "cupertino_alt" - ANT = "cupertino_ant" - ANT_CIRCLE = "cupertino_ant_circle" - ANT_CIRCLE_FILL = "cupertino_ant_circle_fill" - ANT_FILL = "cupertino_ant_fill" - ANTENNA_RADIOWAVES_LEFT_RIGHT = "cupertino_antenna_radiowaves_left_right" - APP = "cupertino_app" - APP_BADGE = "cupertino_app_badge" - APP_BADGE_FILL = "cupertino_app_badge_fill" - APP_FILL = "cupertino_app_fill" - ARCHIVEBOX = "cupertino_archivebox" - ARCHIVEBOX_FILL = "cupertino_archivebox_fill" - ARROW_2_CIRCLEPATH = "cupertino_arrow_2_circlepath" - ARROW_2_CIRCLEPATH_CIRCLE = "cupertino_arrow_2_circlepath_circle" - ARROW_2_CIRCLEPATH_CIRCLE_FILL = "cupertino_arrow_2_circlepath_circle_fill" - ARROW_2_SQUAREPATH = "cupertino_arrow_2_squarepath" - ARROW_3_TRIANGLEPATH = "cupertino_arrow_3_trianglepath" - ARROW_BRANCH = "cupertino_arrow_branch" - ARROW_CLOCKWISE = "cupertino_arrow_clockwise" - ARROW_CLOCKWISE_CIRCLE = "cupertino_arrow_clockwise_circle" - ARROW_CLOCKWISE_CIRCLE_FILL = "cupertino_arrow_clockwise_circle_fill" - ARROW_COUNTERCLOCKWISE = "cupertino_arrow_counterclockwise" - ARROW_COUNTERCLOCKWISE_CIRCLE = "cupertino_arrow_counterclockwise_circle" - ARROW_COUNTERCLOCKWISE_CIRCLE_FILL = "cupertino_arrow_counterclockwise_circle_fill" - ARROW_DOWN = "cupertino_arrow_down" - ARROW_DOWN_CIRCLE = "cupertino_arrow_down_circle" - ARROW_DOWN_CIRCLE_FILL = "cupertino_arrow_down_circle_fill" - ARROW_DOWN_DOC = "cupertino_arrow_down_doc" - ARROW_DOWN_DOC_FILL = "cupertino_arrow_down_doc_fill" - ARROW_DOWN_LEFT = "cupertino_arrow_down_left" - ARROW_DOWN_LEFT_CIRCLE = "cupertino_arrow_down_left_circle" - ARROW_DOWN_LEFT_CIRCLE_FILL = "cupertino_arrow_down_left_circle_fill" - ARROW_DOWN_LEFT_SQUARE = "cupertino_arrow_down_left_square" - ARROW_DOWN_LEFT_SQUARE_FILL = "cupertino_arrow_down_left_square_fill" - ARROW_DOWN_RIGHT = "cupertino_arrow_down_right" - ARROW_DOWN_RIGHT_ARROW_UP_LEFT = "cupertino_arrow_down_right_arrow_up_left" - ARROW_DOWN_RIGHT_CIRCLE = "cupertino_arrow_down_right_circle" - ARROW_DOWN_RIGHT_CIRCLE_FILL = "cupertino_arrow_down_right_circle_fill" - ARROW_DOWN_RIGHT_SQUARE = "cupertino_arrow_down_right_square" - ARROW_DOWN_RIGHT_SQUARE_FILL = "cupertino_arrow_down_right_square_fill" - ARROW_DOWN_SQUARE = "cupertino_arrow_down_square" - ARROW_DOWN_SQUARE_FILL = "cupertino_arrow_down_square_fill" - ARROW_DOWN_TO_LINE = "cupertino_arrow_down_to_line" - ARROW_DOWN_TO_LINE_ALT = "cupertino_arrow_down_to_line_alt" - ARROW_LEFT = "cupertino_arrow_left" - ARROW_LEFT_CIRCLE = "cupertino_arrow_left_circle" - ARROW_LEFT_CIRCLE_FILL = "cupertino_arrow_left_circle_fill" - ARROW_LEFT_RIGHT = "cupertino_arrow_left_right" - ARROW_LEFT_RIGHT_CIRCLE = "cupertino_arrow_left_right_circle" - ARROW_LEFT_RIGHT_CIRCLE_FILL = "cupertino_arrow_left_right_circle_fill" - ARROW_LEFT_RIGHT_SQUARE = "cupertino_arrow_left_right_square" - ARROW_LEFT_RIGHT_SQUARE_FILL = "cupertino_arrow_left_right_square_fill" - ARROW_LEFT_SQUARE = "cupertino_arrow_left_square" - ARROW_LEFT_SQUARE_FILL = "cupertino_arrow_left_square_fill" - ARROW_LEFT_TO_LINE = "cupertino_arrow_left_to_line" - ARROW_LEFT_TO_LINE_ALT = "cupertino_arrow_left_to_line_alt" - ARROW_MERGE = "cupertino_arrow_merge" - ARROW_RIGHT = "cupertino_arrow_right" - ARROW_RIGHT_ARROW_LEFT = "cupertino_arrow_right_arrow_left" - ARROW_RIGHT_ARROW_LEFT_CIRCLE = "cupertino_arrow_right_arrow_left_circle" - ARROW_RIGHT_ARROW_LEFT_CIRCLE_FILL = "cupertino_arrow_right_arrow_left_circle_fill" - ARROW_RIGHT_ARROW_LEFT_SQUARE = "cupertino_arrow_right_arrow_left_square" - ARROW_RIGHT_ARROW_LEFT_SQUARE_FILL = "cupertino_arrow_right_arrow_left_square_fill" - ARROW_RIGHT_CIRCLE = "cupertino_arrow_right_circle" - ARROW_RIGHT_CIRCLE_FILL = "cupertino_arrow_right_circle_fill" - ARROW_RIGHT_SQUARE = "cupertino_arrow_right_square" - ARROW_RIGHT_SQUARE_FILL = "cupertino_arrow_right_square_fill" - ARROW_RIGHT_TO_LINE = "cupertino_arrow_right_to_line" - ARROW_RIGHT_TO_LINE_ALT = "cupertino_arrow_right_to_line_alt" - ARROW_SWAP = "cupertino_arrow_swap" - ARROW_TURN_DOWN_LEFT = "cupertino_arrow_turn_down_left" - ARROW_TURN_DOWN_RIGHT = "cupertino_arrow_turn_down_right" - ARROW_TURN_LEFT_DOWN = "cupertino_arrow_turn_left_down" - ARROW_TURN_LEFT_UP = "cupertino_arrow_turn_left_up" - ARROW_TURN_RIGHT_DOWN = "cupertino_arrow_turn_right_down" - ARROW_TURN_RIGHT_UP = "cupertino_arrow_turn_right_up" - ARROW_TURN_UP_LEFT = "cupertino_arrow_turn_up_left" - ARROW_TURN_UP_RIGHT = "cupertino_arrow_turn_up_right" - ARROW_UP = "cupertino_arrow_up" - ARROW_UP_ARROW_DOWN = "cupertino_arrow_up_arrow_down" - ARROW_UP_ARROW_DOWN_CIRCLE = "cupertino_arrow_up_arrow_down_circle" - ARROW_UP_ARROW_DOWN_CIRCLE_FILL = "cupertino_arrow_up_arrow_down_circle_fill" - ARROW_UP_ARROW_DOWN_SQUARE = "cupertino_arrow_up_arrow_down_square" - ARROW_UP_ARROW_DOWN_SQUARE_FILL = "cupertino_arrow_up_arrow_down_square_fill" - ARROW_UP_BIN = "cupertino_arrow_up_bin" - ARROW_UP_BIN_FILL = "cupertino_arrow_up_bin_fill" - ARROW_UP_CIRCLE = "cupertino_arrow_up_circle" - ARROW_UP_CIRCLE_FILL = "cupertino_arrow_up_circle_fill" - ARROW_UP_DOC = "cupertino_arrow_up_doc" - ARROW_UP_DOC_FILL = "cupertino_arrow_up_doc_fill" - ARROW_UP_DOWN = "cupertino_arrow_up_down" - ARROW_UP_DOWN_CIRCLE = "cupertino_arrow_up_down_circle" - ARROW_UP_DOWN_CIRCLE_FILL = "cupertino_arrow_up_down_circle_fill" - ARROW_UP_DOWN_SQUARE = "cupertino_arrow_up_down_square" - ARROW_UP_DOWN_SQUARE_FILL = "cupertino_arrow_up_down_square_fill" - ARROW_UP_LEFT = "cupertino_arrow_up_left" - ARROW_UP_LEFT_ARROW_DOWN_RIGHT = "cupertino_arrow_up_left_arrow_down_right" - ARROW_UP_LEFT_CIRCLE = "cupertino_arrow_up_left_circle" - ARROW_UP_LEFT_CIRCLE_FILL = "cupertino_arrow_up_left_circle_fill" - ARROW_UP_LEFT_SQUARE = "cupertino_arrow_up_left_square" - ARROW_UP_LEFT_SQUARE_FILL = "cupertino_arrow_up_left_square_fill" - ARROW_UP_RIGHT = "cupertino_arrow_up_right" - ARROW_UP_RIGHT_CIRCLE = "cupertino_arrow_up_right_circle" - ARROW_UP_RIGHT_CIRCLE_FILL = "cupertino_arrow_up_right_circle_fill" - ARROW_UP_RIGHT_DIAMOND = "cupertino_arrow_up_right_diamond" - ARROW_UP_RIGHT_DIAMOND_FILL = "cupertino_arrow_up_right_diamond_fill" - ARROW_UP_RIGHT_SQUARE = "cupertino_arrow_up_right_square" - ARROW_UP_RIGHT_SQUARE_FILL = "cupertino_arrow_up_right_square_fill" - ARROW_UP_SQUARE = "cupertino_arrow_up_square" - ARROW_UP_SQUARE_FILL = "cupertino_arrow_up_square_fill" - ARROW_UP_TO_LINE = "cupertino_arrow_up_to_line" - ARROW_UP_TO_LINE_ALT = "cupertino_arrow_up_to_line_alt" - ARROW_UTURN_DOWN = "cupertino_arrow_uturn_down" - ARROW_UTURN_DOWN_CIRCLE = "cupertino_arrow_uturn_down_circle" - ARROW_UTURN_DOWN_CIRCLE_FILL = "cupertino_arrow_uturn_down_circle_fill" - ARROW_UTURN_DOWN_SQUARE = "cupertino_arrow_uturn_down_square" - ARROW_UTURN_DOWN_SQUARE_FILL = "cupertino_arrow_uturn_down_square_fill" - ARROW_UTURN_LEFT = "cupertino_arrow_uturn_left" - ARROW_UTURN_LEFT_CIRCLE = "cupertino_arrow_uturn_left_circle" - ARROW_UTURN_LEFT_CIRCLE_FILL = "cupertino_arrow_uturn_left_circle_fill" - ARROW_UTURN_LEFT_SQUARE = "cupertino_arrow_uturn_left_square" - ARROW_UTURN_LEFT_SQUARE_FILL = "cupertino_arrow_uturn_left_square_fill" - ARROW_UTURN_RIGHT = "cupertino_arrow_uturn_right" - ARROW_UTURN_RIGHT_CIRCLE = "cupertino_arrow_uturn_right_circle" - ARROW_UTURN_RIGHT_CIRCLE_FILL = "cupertino_arrow_uturn_right_circle_fill" - ARROW_UTURN_RIGHT_SQUARE = "cupertino_arrow_uturn_right_square" - ARROW_UTURN_RIGHT_SQUARE_FILL = "cupertino_arrow_uturn_right_square_fill" - ARROW_UTURN_UP = "cupertino_arrow_uturn_up" - ARROW_UTURN_UP_CIRCLE = "cupertino_arrow_uturn_up_circle" - ARROW_UTURN_UP_CIRCLE_FILL = "cupertino_arrow_uturn_up_circle_fill" - ARROW_UTURN_UP_SQUARE = "cupertino_arrow_uturn_up_square" - ARROW_UTURN_UP_SQUARE_FILL = "cupertino_arrow_uturn_up_square_fill" - ARROWSHAPE_TURN_UP_LEFT = "cupertino_arrowshape_turn_up_left" - ARROWSHAPE_TURN_UP_LEFT_2 = "cupertino_arrowshape_turn_up_left_2" - ARROWSHAPE_TURN_UP_LEFT_2_FILL = "cupertino_arrowshape_turn_up_left_2_fill" - ARROWSHAPE_TURN_UP_LEFT_CIRCLE = "cupertino_arrowshape_turn_up_left_circle" - ARROWSHAPE_TURN_UP_LEFT_CIRCLE_FILL = ( - "cupertino_arrowshape_turn_up_left_circle_fill" - ) - ARROWSHAPE_TURN_UP_LEFT_FILL = "cupertino_arrowshape_turn_up_left_fill" - ARROWSHAPE_TURN_UP_RIGHT = "cupertino_arrowshape_turn_up_right" - ARROWSHAPE_TURN_UP_RIGHT_CIRCLE = "cupertino_arrowshape_turn_up_right_circle" - ARROWSHAPE_TURN_UP_RIGHT_CIRCLE_FILL = ( - "cupertino_arrowshape_turn_up_right_circle_fill" - ) - ARROWSHAPE_TURN_UP_RIGHT_FILL = "cupertino_arrowshape_turn_up_right_fill" - ARROWTRIANGLE_DOWN = "cupertino_arrowtriangle_down" - ARROWTRIANGLE_DOWN_CIRCLE = "cupertino_arrowtriangle_down_circle" - ARROWTRIANGLE_DOWN_CIRCLE_FILL = "cupertino_arrowtriangle_down_circle_fill" - ARROWTRIANGLE_DOWN_FILL = "cupertino_arrowtriangle_down_fill" - ARROWTRIANGLE_DOWN_SQUARE = "cupertino_arrowtriangle_down_square" - ARROWTRIANGLE_DOWN_SQUARE_FILL = "cupertino_arrowtriangle_down_square_fill" - ARROWTRIANGLE_LEFT = "cupertino_arrowtriangle_left" - ARROWTRIANGLE_LEFT_CIRCLE = "cupertino_arrowtriangle_left_circle" - ARROWTRIANGLE_LEFT_CIRCLE_FILL = "cupertino_arrowtriangle_left_circle_fill" - ARROWTRIANGLE_LEFT_FILL = "cupertino_arrowtriangle_left_fill" - ARROWTRIANGLE_LEFT_SQUARE = "cupertino_arrowtriangle_left_square" - ARROWTRIANGLE_LEFT_SQUARE_FILL = "cupertino_arrowtriangle_left_square_fill" - ARROWTRIANGLE_RIGHT = "cupertino_arrowtriangle_right" - ARROWTRIANGLE_RIGHT_CIRCLE = "cupertino_arrowtriangle_right_circle" - ARROWTRIANGLE_RIGHT_CIRCLE_FILL = "cupertino_arrowtriangle_right_circle_fill" - ARROWTRIANGLE_RIGHT_FILL = "cupertino_arrowtriangle_right_fill" - ARROWTRIANGLE_RIGHT_SQUARE = "cupertino_arrowtriangle_right_square" - ARROWTRIANGLE_RIGHT_SQUARE_FILL = "cupertino_arrowtriangle_right_square_fill" - ARROWTRIANGLE_UP = "cupertino_arrowtriangle_up" - ARROWTRIANGLE_UP_CIRCLE = "cupertino_arrowtriangle_up_circle" - ARROWTRIANGLE_UP_CIRCLE_FILL = "cupertino_arrowtriangle_up_circle_fill" - ARROWTRIANGLE_UP_FILL = "cupertino_arrowtriangle_up_fill" - ARROWTRIANGLE_UP_SQUARE = "cupertino_arrowtriangle_up_square" - ARROWTRIANGLE_UP_SQUARE_FILL = "cupertino_arrowtriangle_up_square_fill" - ASTERISK_CIRCLE = "cupertino_asterisk_circle" - ASTERISK_CIRCLE_FILL = "cupertino_asterisk_circle_fill" - AT = "cupertino_at" - AT_BADGE_MINUS = "cupertino_at_badge_minus" - AT_BADGE_PLUS = "cupertino_at_badge_plus" - AT_CIRCLE = "cupertino_at_circle" - AT_CIRCLE_FILL = "cupertino_at_circle_fill" - BACKWARD = "cupertino_backward" - BACKWARD_END = "cupertino_backward_end" - BACKWARD_END_ALT = "cupertino_backward_end_alt" - BACKWARD_END_ALT_FILL = "cupertino_backward_end_alt_fill" - BACKWARD_END_FILL = "cupertino_backward_end_fill" - BACKWARD_FILL = "cupertino_backward_fill" - BADGE_PLUS_RADIOWAVES_RIGHT = "cupertino_badge_plus_radiowaves_right" - BAG = "cupertino_bag" - BAG_BADGE_MINUS = "cupertino_bag_badge_minus" - BAG_BADGE_PLUS = "cupertino_bag_badge_plus" - BAG_FILL = "cupertino_bag_fill" - BAG_FILL_BADGE_MINUS = "cupertino_bag_fill_badge_minus" - BAG_FILL_BADGE_PLUS = "cupertino_bag_fill_badge_plus" - BANDAGE = "cupertino_bandage" - BANDAGE_FILL = "cupertino_bandage_fill" - BARCODE = "cupertino_barcode" - BARCODE_VIEWFINDER = "cupertino_barcode_viewfinder" - BARS = "cupertino_bars" - BATTERY_0 = "cupertino_battery_0" - BATTERY_100 = "cupertino_battery_100" - BATTERY_25 = "cupertino_battery_25" - BED_DOUBLE = "cupertino_bed_double" - BED_DOUBLE_FILL = "cupertino_bed_double_fill" - BELL_CIRCLE = "cupertino_bell_circle" - BELL_CIRCLE_FILL = "cupertino_bell_circle_fill" - BELL_FILL = "cupertino_bell_fill" - BELL_SLASH = "cupertino_bell_slash" - BELL_SLASH_FILL = "cupertino_bell_slash_fill" - BIN_XMARK = "cupertino_bin_xmark" - BIN_XMARK_FILL = "cupertino_bin_xmark_fill" - BITCOIN = "cupertino_bitcoin" - BITCOIN_CIRCLE = "cupertino_bitcoin_circle" - BITCOIN_CIRCLE_FILL = "cupertino_bitcoin_circle_fill" - BOLD = "cupertino_bold" - BOLD_ITALIC_UNDERLINE = "cupertino_bold_italic_underline" - BOLD_UNDERLINE = "cupertino_bold_underline" - BOLT = "cupertino_bolt" - BOLT_BADGE_A = "cupertino_bolt_badge_a" - BOLT_BADGE_A_FILL = "cupertino_bolt_badge_a_fill" - BOLT_CIRCLE = "cupertino_bolt_circle" - BOLT_CIRCLE_FILL = "cupertino_bolt_circle_fill" - BOLT_FILL = "cupertino_bolt_fill" - BOLT_HORIZONTAL = "cupertino_bolt_horizontal" - BOLT_HORIZONTAL_CIRCLE = "cupertino_bolt_horizontal_circle" - BOLT_HORIZONTAL_CIRCLE_FILL = "cupertino_bolt_horizontal_circle_fill" - BOLT_HORIZONTAL_FILL = "cupertino_bolt_horizontal_fill" - BOLT_SLASH = "cupertino_bolt_slash" - BOLT_SLASH_FILL = "cupertino_bolt_slash_fill" - BOOK_CIRCLE = "cupertino_book_circle" - BOOK_CIRCLE_FILL = "cupertino_book_circle_fill" - BOOK_FILL = "cupertino_book_fill" - BOOKMARK_FILL = "cupertino_bookmark_fill" - BRIEFCASE = "cupertino_briefcase" - BRIEFCASE_FILL = "cupertino_briefcase_fill" - BUBBLE_LEFT = "cupertino_bubble_left" - BUBBLE_LEFT_BUBBLE_RIGHT = "cupertino_bubble_left_bubble_right" - BUBBLE_LEFT_BUBBLE_RIGHT_FILL = "cupertino_bubble_left_bubble_right_fill" - BUBBLE_LEFT_FILL = "cupertino_bubble_left_fill" - BUBBLE_MIDDLE_BOTTOM = "cupertino_bubble_middle_bottom" - BUBBLE_MIDDLE_BOTTOM_FILL = "cupertino_bubble_middle_bottom_fill" - BUBBLE_MIDDLE_TOP = "cupertino_bubble_middle_top" - BUBBLE_MIDDLE_TOP_FILL = "cupertino_bubble_middle_top_fill" - BUBBLE_RIGHT = "cupertino_bubble_right" - BUBBLE_RIGHT_FILL = "cupertino_bubble_right_fill" - BUILDING_2_FILL = "cupertino_building_2_fill" - BURN = "cupertino_burn" - BURST = "cupertino_burst" - BURST_FILL = "cupertino_burst_fill" - CALENDAR = "cupertino_calendar" - CALENDAR_BADGE_MINUS = "cupertino_calendar_badge_minus" - CALENDAR_BADGE_PLUS = "cupertino_calendar_badge_plus" - CALENDAR_CIRCLE = "cupertino_calendar_circle" - CALENDAR_CIRCLE_FILL = "cupertino_calendar_circle_fill" - CALENDAR_TODAY = "cupertino_calendar_today" - CAMERA = "cupertino_camera" - CAMERA_CIRCLE = "cupertino_camera_circle" - CAMERA_CIRCLE_FILL = "cupertino_camera_circle_fill" - CAMERA_FILL = "cupertino_camera_fill" - CAMERA_ON_RECTANGLE = "cupertino_camera_on_rectangle" - CAMERA_ON_RECTANGLE_FILL = "cupertino_camera_on_rectangle_fill" - CAMERA_ROTATE = "cupertino_camera_rotate" - CAMERA_ROTATE_FILL = "cupertino_camera_rotate_fill" - CAMERA_VIEWFINDER = "cupertino_camera_viewfinder" - CAPSLOCK = "cupertino_capslock" - CAPSLOCK_FILL = "cupertino_capslock_fill" - CAPSULE = "cupertino_capsule" - CAPSULE_FILL = "cupertino_capsule_fill" - CAPTIONS_BUBBLE = "cupertino_captions_bubble" - CAPTIONS_BUBBLE_FILL = "cupertino_captions_bubble_fill" - CAR_FILL = "cupertino_car_fill" - CART = "cupertino_cart" - CART_BADGE_MINUS = "cupertino_cart_badge_minus" - CART_BADGE_PLUS = "cupertino_cart_badge_plus" - CART_FILL = "cupertino_cart_fill" - CART_FILL_BADGE_MINUS = "cupertino_cart_fill_badge_minus" - CART_FILL_BADGE_PLUS = "cupertino_cart_fill_badge_plus" - CHART_BAR = "cupertino_chart_bar" - CHART_BAR_ALT_FILL = "cupertino_chart_bar_alt_fill" - CHART_BAR_CIRCLE = "cupertino_chart_bar_circle" - CHART_BAR_CIRCLE_FILL = "cupertino_chart_bar_circle_fill" - CHART_BAR_FILL = "cupertino_chart_bar_fill" - CHART_BAR_SQUARE = "cupertino_chart_bar_square" - CHART_BAR_SQUARE_FILL = "cupertino_chart_bar_square_fill" - CHART_PIE = "cupertino_chart_pie" - CHART_PIE_FILL = "cupertino_chart_pie_fill" - CHAT_BUBBLE = "cupertino_chat_bubble" - CHAT_BUBBLE_2 = "cupertino_chat_bubble_2" - CHAT_BUBBLE_2_FILL = "cupertino_chat_bubble_2_fill" - CHAT_BUBBLE_FILL = "cupertino_chat_bubble_fill" - CHAT_BUBBLE_TEXT = "cupertino_chat_bubble_text" - CHAT_BUBBLE_TEXT_FILL = "cupertino_chat_bubble_text_fill" - CHECKMARK = "cupertino_checkmark" - CHECKMARK_ALT = "cupertino_checkmark_alt" - CHECKMARK_ALT_CIRCLE = "cupertino_checkmark_alt_circle" - CHECKMARK_ALT_CIRCLE_FILL = "cupertino_checkmark_alt_circle_fill" - CHECKMARK_CIRCLE = "cupertino_checkmark_circle" - CHECKMARK_CIRCLE_FILL = "cupertino_checkmark_circle_fill" - CHECKMARK_RECTANGLE = "cupertino_checkmark_rectangle" - CHECKMARK_RECTANGLE_FILL = "cupertino_checkmark_rectangle_fill" - CHECKMARK_SEAL = "cupertino_checkmark_seal" - CHECKMARK_SEAL_FILL = "cupertino_checkmark_seal_fill" - CHECKMARK_SHIELD = "cupertino_checkmark_shield" - CHECKMARK_SHIELD_FILL = "cupertino_checkmark_shield_fill" - CHECKMARK_SQUARE = "cupertino_checkmark_square" - CHECKMARK_SQUARE_FILL = "cupertino_checkmark_square_fill" - CHEVRON_BACK = "cupertino_chevron_back" - CHEVRON_COMPACT_DOWN = "cupertino_chevron_compact_down" - CHEVRON_COMPACT_LEFT = "cupertino_chevron_compact_left" - CHEVRON_COMPACT_RIGHT = "cupertino_chevron_compact_right" - CHEVRON_COMPACT_UP = "cupertino_chevron_compact_up" - CHEVRON_DOWN = "cupertino_chevron_down" - CHEVRON_DOWN_CIRCLE = "cupertino_chevron_down_circle" - CHEVRON_DOWN_CIRCLE_FILL = "cupertino_chevron_down_circle_fill" - CHEVRON_DOWN_SQUARE = "cupertino_chevron_down_square" - CHEVRON_DOWN_SQUARE_FILL = "cupertino_chevron_down_square_fill" - CHEVRON_FORWARD = "cupertino_chevron_forward" - CHEVRON_LEFT = "cupertino_chevron_left" - CHEVRON_LEFT_2 = "cupertino_chevron_left_2" - CHEVRON_LEFT_CIRCLE = "cupertino_chevron_left_circle" - CHEVRON_LEFT_CIRCLE_FILL = "cupertino_chevron_left_circle_fill" - CHEVRON_LEFT_SLASH_CHEVRON_RIGHT = "cupertino_chevron_left_slash_chevron_right" - CHEVRON_LEFT_SQUARE = "cupertino_chevron_left_square" - CHEVRON_LEFT_SQUARE_FILL = "cupertino_chevron_left_square_fill" - CHEVRON_RIGHT = "cupertino_chevron_right" - CHEVRON_RIGHT_2 = "cupertino_chevron_right_2" - CHEVRON_RIGHT_CIRCLE = "cupertino_chevron_right_circle" - CHEVRON_RIGHT_CIRCLE_FILL = "cupertino_chevron_right_circle_fill" - CHEVRON_RIGHT_SQUARE = "cupertino_chevron_right_square" - CHEVRON_RIGHT_SQUARE_FILL = "cupertino_chevron_right_square_fill" - CHEVRON_UP = "cupertino_chevron_up" - CHEVRON_UP_CHEVRON_DOWN = "cupertino_chevron_up_chevron_down" - CHEVRON_UP_CIRCLE = "cupertino_chevron_up_circle" - CHEVRON_UP_CIRCLE_FILL = "cupertino_chevron_up_circle_fill" - CHEVRON_UP_SQUARE = "cupertino_chevron_up_square" - CHEVRON_UP_SQUARE_FILL = "cupertino_chevron_up_square_fill" - CIRCLE_BOTTOMTHIRD_SPLIT = "cupertino_circle_bottomthird_split" - CIRCLE_FILL = "cupertino_circle_fill" - CIRCLE_GRID_3X3 = "cupertino_circle_grid_3x3" - CIRCLE_GRID_3X3_FILL = "cupertino_circle_grid_3x3_fill" - CIRCLE_GRID_HEX = "cupertino_circle_grid_hex" - CIRCLE_GRID_HEX_FILL = "cupertino_circle_grid_hex_fill" - CIRCLE_LEFTHALF_FILL = "cupertino_circle_lefthalf_fill" - CIRCLE_RIGHTHALF_FILL = "cupertino_circle_righthalf_fill" - CLEAR_FILL = "cupertino_clear_fill" - CLOCK_FILL = "cupertino_clock_fill" - CLOUD = "cupertino_cloud" - CLOUD_BOLT = "cupertino_cloud_bolt" - CLOUD_BOLT_FILL = "cupertino_cloud_bolt_fill" - CLOUD_BOLT_RAIN = "cupertino_cloud_bolt_rain" - CLOUD_BOLT_RAIN_FILL = "cupertino_cloud_bolt_rain_fill" - CLOUD_DOWNLOAD = "cupertino_cloud_download" - CLOUD_DOWNLOAD_FILL = "cupertino_cloud_download_fill" - CLOUD_DRIZZLE = "cupertino_cloud_drizzle" - CLOUD_DRIZZLE_FILL = "cupertino_cloud_drizzle_fill" - CLOUD_FILL = "cupertino_cloud_fill" - CLOUD_FOG = "cupertino_cloud_fog" - CLOUD_FOG_FILL = "cupertino_cloud_fog_fill" - CLOUD_HAIL = "cupertino_cloud_hail" - CLOUD_HAIL_FILL = "cupertino_cloud_hail_fill" - CLOUD_HEAVYRAIN = "cupertino_cloud_heavyrain" - CLOUD_HEAVYRAIN_FILL = "cupertino_cloud_heavyrain_fill" - CLOUD_MOON = "cupertino_cloud_moon" - CLOUD_MOON_BOLT = "cupertino_cloud_moon_bolt" - CLOUD_MOON_BOLT_FILL = "cupertino_cloud_moon_bolt_fill" - CLOUD_MOON_FILL = "cupertino_cloud_moon_fill" - CLOUD_MOON_RAIN = "cupertino_cloud_moon_rain" - CLOUD_MOON_RAIN_FILL = "cupertino_cloud_moon_rain_fill" - CLOUD_RAIN = "cupertino_cloud_rain" - CLOUD_RAIN_FILL = "cupertino_cloud_rain_fill" - CLOUD_SLEET = "cupertino_cloud_sleet" - CLOUD_SLEET_FILL = "cupertino_cloud_sleet_fill" - CLOUD_SNOW = "cupertino_cloud_snow" - CLOUD_SNOW_FILL = "cupertino_cloud_snow_fill" - CLOUD_SUN = "cupertino_cloud_sun" - CLOUD_SUN_BOLT = "cupertino_cloud_sun_bolt" - CLOUD_SUN_BOLT_FILL = "cupertino_cloud_sun_bolt_fill" - CLOUD_SUN_FILL = "cupertino_cloud_sun_fill" - CLOUD_SUN_RAIN = "cupertino_cloud_sun_rain" - CLOUD_SUN_RAIN_FILL = "cupertino_cloud_sun_rain_fill" - CLOUD_UPLOAD = "cupertino_cloud_upload" - CLOUD_UPLOAD_FILL = "cupertino_cloud_upload_fill" - COLOR_FILTER = "cupertino_color_filter" - COLOR_FILTER_FILL = "cupertino_color_filter_fill" - COMMAND = "cupertino_command" - COMPASS = "cupertino_compass" - COMPASS_FILL = "cupertino_compass_fill" - CONTROL = "cupertino_control" - CREDITCARD = "cupertino_creditcard" - CREDITCARD_FILL = "cupertino_creditcard_fill" - CROP = "cupertino_crop" - CROP_ROTATE = "cupertino_crop_rotate" - CUBE = "cupertino_cube" - CUBE_BOX = "cupertino_cube_box" - CUBE_BOX_FILL = "cupertino_cube_box_fill" - CUBE_FILL = "cupertino_cube_fill" - CURSOR_RAYS = "cupertino_cursor_rays" - DECREASE_INDENT = "cupertino_decrease_indent" - DECREASE_QUOTELEVEL = "cupertino_decrease_quotelevel" - DELETE_LEFT = "cupertino_delete_left" - DELETE_LEFT_FILL = "cupertino_delete_left_fill" - DELETE_RIGHT = "cupertino_delete_right" - DELETE_RIGHT_FILL = "cupertino_delete_right_fill" - DESKTOPCOMPUTER = "cupertino_desktopcomputer" - DEVICE_DESKTOP = "cupertino_device_desktop" - DEVICE_LAPTOP = "cupertino_device_laptop" - DEVICE_PHONE_LANDSCAPE = "cupertino_device_phone_landscape" - DEVICE_PHONE_PORTRAIT = "cupertino_device_phone_portrait" - DIAL = "cupertino_dial" - DIAL_FILL = "cupertino_dial_fill" - DIVIDE = "cupertino_divide" - DIVIDE_CIRCLE = "cupertino_divide_circle" - DIVIDE_CIRCLE_FILL = "cupertino_divide_circle_fill" - DIVIDE_SQUARE = "cupertino_divide_square" - DIVIDE_SQUARE_FILL = "cupertino_divide_square_fill" - DOC = "cupertino_doc" - DOC_APPEND = "cupertino_doc_append" - DOC_CHART = "cupertino_doc_chart" - DOC_CHART_FILL = "cupertino_doc_chart_fill" - DOC_CHECKMARK = "cupertino_doc_checkmark" - DOC_CHECKMARK_FILL = "cupertino_doc_checkmark_fill" - DOC_CIRCLE = "cupertino_doc_circle" - DOC_CIRCLE_FILL = "cupertino_doc_circle_fill" - DOC_FILL = "cupertino_doc_fill" - DOC_ON_CLIPBOARD = "cupertino_doc_on_clipboard" - DOC_ON_CLIPBOARD_FILL = "cupertino_doc_on_clipboard_fill" - DOC_ON_DOC = "cupertino_doc_on_doc" - DOC_ON_DOC_FILL = "cupertino_doc_on_doc_fill" - DOC_PERSON = "cupertino_doc_person" - DOC_PERSON_FILL = "cupertino_doc_person_fill" - DOC_PLAINTEXT = "cupertino_doc_plaintext" - DOC_RICHTEXT = "cupertino_doc_richtext" - DOC_TEXT = "cupertino_doc_text" - DOC_TEXT_FILL = "cupertino_doc_text_fill" - DOC_TEXT_SEARCH = "cupertino_doc_text_search" - DOC_TEXT_VIEWFINDER = "cupertino_doc_text_viewfinder" - DOT_RADIOWAVES_LEFT_RIGHT = "cupertino_dot_radiowaves_left_right" - DOT_RADIOWAVES_RIGHT = "cupertino_dot_radiowaves_right" - DOT_SQUARE = "cupertino_dot_square" - DOT_SQUARE_FILL = "cupertino_dot_square_fill" - DOWNLOAD_CIRCLE = "cupertino_download_circle" - DOWNLOAD_CIRCLE_FILL = "cupertino_download_circle_fill" - DROP = "cupertino_drop" - DROP_FILL = "cupertino_drop_fill" - DROP_TRIANGLE = "cupertino_drop_triangle" - DROP_TRIANGLE_FILL = "cupertino_drop_triangle_fill" - EAR = "cupertino_ear" - EJECT = "cupertino_eject" - EJECT_FILL = "cupertino_eject_fill" - ELLIPSES_BUBBLE = "cupertino_ellipses_bubble" - ELLIPSES_BUBBLE_FILL = "cupertino_ellipses_bubble_fill" - ELLIPSIS_CIRCLE = "cupertino_ellipsis_circle" - ELLIPSIS_CIRCLE_FILL = "cupertino_ellipsis_circle_fill" - ELLIPSIS_VERTICAL = "cupertino_ellipsis_vertical" - ELLIPSIS_VERTICAL_CIRCLE = "cupertino_ellipsis_vertical_circle" - ELLIPSIS_VERTICAL_CIRCLE_FILL = "cupertino_ellipsis_vertical_circle_fill" - ENVELOPE = "cupertino_envelope" - ENVELOPE_BADGE = "cupertino_envelope_badge" - ENVELOPE_BADGE_FILL = "cupertino_envelope_badge_fill" - ENVELOPE_CIRCLE = "cupertino_envelope_circle" - ENVELOPE_CIRCLE_FILL = "cupertino_envelope_circle_fill" - ENVELOPE_FILL = "cupertino_envelope_fill" - ENVELOPE_OPEN = "cupertino_envelope_open" - ENVELOPE_OPEN_FILL = "cupertino_envelope_open_fill" - EQUAL = "cupertino_equal" - EQUAL_CIRCLE = "cupertino_equal_circle" - EQUAL_CIRCLE_FILL = "cupertino_equal_circle_fill" - EQUAL_SQUARE = "cupertino_equal_square" - EQUAL_SQUARE_FILL = "cupertino_equal_square_fill" - ESCAPE = "cupertino_escape" - EXCLAMATIONMARK = "cupertino_exclamationmark" - EXCLAMATIONMARK_BUBBLE = "cupertino_exclamationmark_bubble" - EXCLAMATIONMARK_BUBBLE_FILL = "cupertino_exclamationmark_bubble_fill" - EXCLAMATIONMARK_CIRCLE = "cupertino_exclamationmark_circle" - EXCLAMATIONMARK_CIRCLE_FILL = "cupertino_exclamationmark_circle_fill" - EXCLAMATIONMARK_OCTAGON = "cupertino_exclamationmark_octagon" - EXCLAMATIONMARK_OCTAGON_FILL = "cupertino_exclamationmark_octagon_fill" - EXCLAMATIONMARK_SHIELD = "cupertino_exclamationmark_shield" - EXCLAMATIONMARK_SHIELD_FILL = "cupertino_exclamationmark_shield_fill" - EXCLAMATIONMARK_SQUARE = "cupertino_exclamationmark_square" - EXCLAMATIONMARK_SQUARE_FILL = "cupertino_exclamationmark_square_fill" - EXCLAMATIONMARK_TRIANGLE = "cupertino_exclamationmark_triangle" - EXCLAMATIONMARK_TRIANGLE_FILL = "cupertino_exclamationmark_triangle_fill" - EYE_FILL = "cupertino_eye_fill" - EYE_SLASH = "cupertino_eye_slash" - EYE_SLASH_FILL = "cupertino_eye_slash_fill" - EYEDROPPER = "cupertino_eyedropper" - EYEDROPPER_FULL = "cupertino_eyedropper_full" - EYEDROPPER_HALFFULL = "cupertino_eyedropper_halffull" - EYEGLASSES = "cupertino_eyeglasses" - F_CURSIVE = "cupertino_f_cursive" - F_CURSIVE_CIRCLE = "cupertino_f_cursive_circle" - F_CURSIVE_CIRCLE_FILL = "cupertino_f_cursive_circle_fill" - FILM = "cupertino_film" - FILM_FILL = "cupertino_film_fill" - FLAG_CIRCLE = "cupertino_flag_circle" - FLAG_CIRCLE_FILL = "cupertino_flag_circle_fill" - FLAG_FILL = "cupertino_flag_fill" - FLAG_SLASH = "cupertino_flag_slash" - FLAG_SLASH_FILL = "cupertino_flag_slash_fill" - FLAME = "cupertino_flame" - FLAME_FILL = "cupertino_flame_fill" - FLOPPY_DISK = "cupertino_floppy_disk" - FLOWCHART = "cupertino_flowchart" - FLOWCHART_FILL = "cupertino_flowchart_fill" - FOLDER_BADGE_MINUS = "cupertino_folder_badge_minus" - FOLDER_BADGE_PERSON_CROP = "cupertino_folder_badge_person_crop" - FOLDER_BADGE_PLUS = "cupertino_folder_badge_plus" - FOLDER_CIRCLE = "cupertino_folder_circle" - FOLDER_CIRCLE_FILL = "cupertino_folder_circle_fill" - FOLDER_FILL = "cupertino_folder_fill" - FOLDER_FILL_BADGE_MINUS = "cupertino_folder_fill_badge_minus" - FOLDER_FILL_BADGE_PERSON_CROP = "cupertino_folder_fill_badge_person_crop" - FOLDER_FILL_BADGE_PLUS = "cupertino_folder_fill_badge_plus" - FORWARD_END = "cupertino_forward_end" - FORWARD_END_ALT = "cupertino_forward_end_alt" - FORWARD_END_ALT_FILL = "cupertino_forward_end_alt_fill" - FORWARD_END_FILL = "cupertino_forward_end_fill" - FORWARD_FILL = "cupertino_forward_fill" - FUNCTION = "cupertino_function" - FX = "cupertino_fx" - GAMECONTROLLER = "cupertino_gamecontroller" - GAMECONTROLLER_ALT_FILL = "cupertino_gamecontroller_alt_fill" - GAMECONTROLLER_FILL = "cupertino_gamecontroller_fill" - GAUGE = "cupertino_gauge" - GAUGE_BADGE_MINUS = "cupertino_gauge_badge_minus" - GAUGE_BADGE_PLUS = "cupertino_gauge_badge_plus" - GEAR_ALT = "cupertino_gear_alt" - GEAR_ALT_FILL = "cupertino_gear_alt_fill" - GIFT = "cupertino_gift" - GIFT_ALT = "cupertino_gift_alt" - GIFT_ALT_FILL = "cupertino_gift_alt_fill" - GIFT_FILL = "cupertino_gift_fill" - GLOBE = "cupertino_globe" - GOBACKWARD = "cupertino_gobackward" - GOBACKWARD_10 = "cupertino_gobackward_10" - GOBACKWARD_15 = "cupertino_gobackward_15" - GOBACKWARD_30 = "cupertino_gobackward_30" - GOBACKWARD_45 = "cupertino_gobackward_45" - GOBACKWARD_60 = "cupertino_gobackward_60" - GOBACKWARD_75 = "cupertino_gobackward_75" - GOBACKWARD_90 = "cupertino_gobackward_90" - GOBACKWARD_MINUS = "cupertino_gobackward_minus" - GOFORWARD = "cupertino_goforward" - GOFORWARD_10 = "cupertino_goforward_10" - GOFORWARD_15 = "cupertino_goforward_15" - GOFORWARD_30 = "cupertino_goforward_30" - GOFORWARD_45 = "cupertino_goforward_45" - GOFORWARD_60 = "cupertino_goforward_60" - GOFORWARD_75 = "cupertino_goforward_75" - GOFORWARD_90 = "cupertino_goforward_90" - GOFORWARD_PLUS = "cupertino_goforward_plus" - GRAPH_CIRCLE = "cupertino_graph_circle" - GRAPH_CIRCLE_FILL = "cupertino_graph_circle_fill" - GRAPH_SQUARE = "cupertino_graph_square" - GRAPH_SQUARE_FILL = "cupertino_graph_square_fill" - GREATERTHAN = "cupertino_greaterthan" - GREATERTHAN_CIRCLE = "cupertino_greaterthan_circle" - GREATERTHAN_CIRCLE_FILL = "cupertino_greaterthan_circle_fill" - GREATERTHAN_SQUARE = "cupertino_greaterthan_square" - GREATERTHAN_SQUARE_FILL = "cupertino_greaterthan_square_fill" - GRID = "cupertino_grid" - GRID_CIRCLE = "cupertino_grid_circle" - GRID_CIRCLE_FILL = "cupertino_grid_circle_fill" - GUITARS = "cupertino_guitars" - HAMMER = "cupertino_hammer" - HAMMER_FILL = "cupertino_hammer_fill" - HAND_DRAW = "cupertino_hand_draw" - HAND_DRAW_FILL = "cupertino_hand_draw_fill" - HAND_POINT_LEFT = "cupertino_hand_point_left" - HAND_POINT_LEFT_FILL = "cupertino_hand_point_left_fill" - HAND_POINT_RIGHT = "cupertino_hand_point_right" - HAND_POINT_RIGHT_FILL = "cupertino_hand_point_right_fill" - HAND_RAISED = "cupertino_hand_raised" - HAND_RAISED_FILL = "cupertino_hand_raised_fill" - HAND_RAISED_SLASH = "cupertino_hand_raised_slash" - HAND_RAISED_SLASH_FILL = "cupertino_hand_raised_slash_fill" - HAND_THUMBSDOWN = "cupertino_hand_thumbsdown" - HAND_THUMBSDOWN_FILL = "cupertino_hand_thumbsdown_fill" - HAND_THUMBSUP = "cupertino_hand_thumbsup" - HAND_THUMBSUP_FILL = "cupertino_hand_thumbsup_fill" - HARE = "cupertino_hare" - HARE_FILL = "cupertino_hare_fill" - HEADPHONES = "cupertino_headphones" - HEART_CIRCLE = "cupertino_heart_circle" - HEART_CIRCLE_FILL = "cupertino_heart_circle_fill" - HEART_FILL = "cupertino_heart_fill" - HEART_SLASH = "cupertino_heart_slash" - HEART_SLASH_CIRCLE = "cupertino_heart_slash_circle" - HEART_SLASH_CIRCLE_FILL = "cupertino_heart_slash_circle_fill" - HEART_SLASH_FILL = "cupertino_heart_slash_fill" - HELM = "cupertino_helm" - HEXAGON = "cupertino_hexagon" - HEXAGON_FILL = "cupertino_hexagon_fill" - HIFISPEAKER = "cupertino_hifispeaker" - HIFISPEAKER_FILL = "cupertino_hifispeaker_fill" - HOURGLASS = "cupertino_hourglass" - HOURGLASS_BOTTOMHALF_FILL = "cupertino_hourglass_bottomhalf_fill" - HOURGLASS_TOPHALF_FILL = "cupertino_hourglass_tophalf_fill" - HOUSE = "cupertino_house" - HOUSE_ALT = "cupertino_house_alt" - HOUSE_ALT_FILL = "cupertino_house_alt_fill" - HOUSE_FILL = "cupertino_house_fill" - HURRICANE = "cupertino_hurricane" - INCREASE_INDENT = "cupertino_increase_indent" - INCREASE_QUOTELEVEL = "cupertino_increase_quotelevel" - INFINITE = "cupertino_infinite" - INFO_CIRCLE = "cupertino_info_circle" - INFO_CIRCLE_FILL = "cupertino_info_circle_fill" - ITALIC = "cupertino_italic" - KEYBOARD = "cupertino_keyboard" - KEYBOARD_CHEVRON_COMPACT_DOWN = "cupertino_keyboard_chevron_compact_down" - LARGECIRCLE_FILL_CIRCLE = "cupertino_largecircle_fill_circle" - LASSO = "cupertino_lasso" - LAYERS = "cupertino_layers" - LAYERS_ALT = "cupertino_layers_alt" - LAYERS_ALT_FILL = "cupertino_layers_alt_fill" - LAYERS_FILL = "cupertino_layers_fill" - LEAF_ARROW_CIRCLEPATH = "cupertino_leaf_arrow_circlepath" - LESSTHAN = "cupertino_lessthan" - LESSTHAN_CIRCLE = "cupertino_lessthan_circle" - LESSTHAN_CIRCLE_FILL = "cupertino_lessthan_circle_fill" - LESSTHAN_SQUARE = "cupertino_lessthan_square" - LESSTHAN_SQUARE_FILL = "cupertino_lessthan_square_fill" - LIGHT_MAX = "cupertino_light_max" - LIGHT_MIN = "cupertino_light_min" - LIGHTBULB = "cupertino_lightbulb" - LIGHTBULB_FILL = "cupertino_lightbulb_fill" - LIGHTBULB_SLASH = "cupertino_lightbulb_slash" - LIGHTBULB_SLASH_FILL = "cupertino_lightbulb_slash_fill" - LINE_HORIZONTAL_3 = "cupertino_line_horizontal_3" - LINE_HORIZONTAL_3_DECREASE = "cupertino_line_horizontal_3_decrease" - LINE_HORIZONTAL_3_DECREASE_CIRCLE = "cupertino_line_horizontal_3_decrease_circle" - LINE_HORIZONTAL_3_DECREASE_CIRCLE_FILL = ( - "cupertino_line_horizontal_3_decrease_circle_fill" - ) - LINK = "cupertino_link" - LINK_CIRCLE = "cupertino_link_circle" - LINK_CIRCLE_FILL = "cupertino_link_circle_fill" - LIST_BULLET = "cupertino_list_bullet" - LIST_BULLET_BELOW_RECTANGLE = "cupertino_list_bullet_below_rectangle" - LIST_BULLET_INDENT = "cupertino_list_bullet_indent" - LIST_DASH = "cupertino_list_dash" - LIST_NUMBER = "cupertino_list_number" - LIST_NUMBER_RTL = "cupertino_list_number_rtl" - LOCATION_CIRCLE = "cupertino_location_circle" - LOCATION_CIRCLE_FILL = "cupertino_location_circle_fill" - LOCATION_FILL = "cupertino_location_fill" - LOCATION_NORTH = "cupertino_location_north" - LOCATION_NORTH_FILL = "cupertino_location_north_fill" - LOCATION_NORTH_LINE = "cupertino_location_north_line" - LOCATION_NORTH_LINE_FILL = "cupertino_location_north_line_fill" - LOCATION_SLASH = "cupertino_location_slash" - LOCATION_SLASH_FILL = "cupertino_location_slash_fill" - LOCK = "cupertino_lock" - LOCK_CIRCLE = "cupertino_lock_circle" - LOCK_CIRCLE_FILL = "cupertino_lock_circle_fill" - LOCK_FILL = "cupertino_lock_fill" - LOCK_OPEN = "cupertino_lock_open" - LOCK_OPEN_FILL = "cupertino_lock_open_fill" - LOCK_ROTATION = "cupertino_lock_rotation" - LOCK_ROTATION_OPEN = "cupertino_lock_rotation_open" - LOCK_SHIELD = "cupertino_lock_shield" - LOCK_SHIELD_FILL = "cupertino_lock_shield_fill" - LOCK_SLASH = "cupertino_lock_slash" - LOCK_SLASH_FILL = "cupertino_lock_slash_fill" - MACWINDOW = "cupertino_macwindow" - MAP = "cupertino_map" - MAP_FILL = "cupertino_map_fill" - MAP_PIN = "cupertino_map_pin" - MAP_PIN_ELLIPSE = "cupertino_map_pin_ellipse" - MAP_PIN_SLASH = "cupertino_map_pin_slash" - MEMORIES = "cupertino_memories" - MEMORIES_BADGE_MINUS = "cupertino_memories_badge_minus" - MEMORIES_BADGE_PLUS = "cupertino_memories_badge_plus" - METRONOME = "cupertino_metronome" - MIC_CIRCLE = "cupertino_mic_circle" - MIC_CIRCLE_FILL = "cupertino_mic_circle_fill" - MIC_FILL = "cupertino_mic_fill" - MIC_SLASH = "cupertino_mic_slash" - MIC_SLASH_FILL = "cupertino_mic_slash_fill" - MINUS = "cupertino_minus" - MINUS_CIRCLE = "cupertino_minus_circle" - MINUS_CIRCLE_FILL = "cupertino_minus_circle_fill" - MINUS_RECTANGLE = "cupertino_minus_rectangle" - MINUS_RECTANGLE_FILL = "cupertino_minus_rectangle_fill" - MINUS_SLASH_PLUS = "cupertino_minus_slash_plus" - MINUS_SQUARE = "cupertino_minus_square" - MINUS_SQUARE_FILL = "cupertino_minus_square_fill" - MONEY_DOLLAR = "cupertino_money_dollar" - MONEY_DOLLAR_CIRCLE = "cupertino_money_dollar_circle" - MONEY_DOLLAR_CIRCLE_FILL = "cupertino_money_dollar_circle_fill" - MONEY_EURO = "cupertino_money_euro" - MONEY_EURO_CIRCLE = "cupertino_money_euro_circle" - MONEY_EURO_CIRCLE_FILL = "cupertino_money_euro_circle_fill" - MONEY_POUND = "cupertino_money_pound" - MONEY_POUND_CIRCLE = "cupertino_money_pound_circle" - MONEY_POUND_CIRCLE_FILL = "cupertino_money_pound_circle_fill" - MONEY_RUBL = "cupertino_money_rubl" - MONEY_RUBL_CIRCLE = "cupertino_money_rubl_circle" - MONEY_RUBL_CIRCLE_FILL = "cupertino_money_rubl_circle_fill" - MONEY_YEN = "cupertino_money_yen" - MONEY_YEN_CIRCLE = "cupertino_money_yen_circle" - MONEY_YEN_CIRCLE_FILL = "cupertino_money_yen_circle_fill" - MOON = "cupertino_moon" - MOON_CIRCLE = "cupertino_moon_circle" - MOON_CIRCLE_FILL = "cupertino_moon_circle_fill" - MOON_FILL = "cupertino_moon_fill" - MOON_STARS = "cupertino_moon_stars" - MOON_STARS_FILL = "cupertino_moon_stars_fill" - MOON_ZZZ = "cupertino_moon_zzz" - MOON_ZZZ_FILL = "cupertino_moon_zzz_fill" - MOVE = "cupertino_move" - MULTIPLY = "cupertino_multiply" - MULTIPLY_CIRCLE = "cupertino_multiply_circle" - MULTIPLY_CIRCLE_FILL = "cupertino_multiply_circle_fill" - MULTIPLY_SQUARE = "cupertino_multiply_square" - MULTIPLY_SQUARE_FILL = "cupertino_multiply_square_fill" - MUSIC_ALBUMS = "cupertino_music_albums" - MUSIC_ALBUMS_FILL = "cupertino_music_albums_fill" - MUSIC_HOUSE = "cupertino_music_house" - MUSIC_HOUSE_FILL = "cupertino_music_house_fill" - MUSIC_MIC = "cupertino_music_mic" - MUSIC_NOTE_2 = "cupertino_music_note_2" - MUSIC_NOTE_LIST = "cupertino_music_note_list" - NOSIGN = "cupertino_nosign" - NUMBER = "cupertino_number" - NUMBER_CIRCLE = "cupertino_number_circle" - NUMBER_CIRCLE_FILL = "cupertino_number_circle_fill" - NUMBER_SQUARE = "cupertino_number_square" - NUMBER_SQUARE_FILL = "cupertino_number_square_fill" - OPTION = "cupertino_option" - PAINTBRUSH = "cupertino_paintbrush" - PAINTBRUSH_FILL = "cupertino_paintbrush_fill" - PANO = "cupertino_pano" - PANO_FILL = "cupertino_pano_fill" - PAPERCLIP = "cupertino_paperclip" - PAPERPLANE = "cupertino_paperplane" - PAPERPLANE_FILL = "cupertino_paperplane_fill" - PARAGRAPH = "cupertino_paragraph" - PAUSE_CIRCLE = "cupertino_pause_circle" - PAUSE_CIRCLE_FILL = "cupertino_pause_circle_fill" - PAUSE_FILL = "cupertino_pause_fill" - PAUSE_RECTANGLE = "cupertino_pause_rectangle" - PAUSE_RECTANGLE_FILL = "cupertino_pause_rectangle_fill" - PENCIL_CIRCLE = "cupertino_pencil_circle" - PENCIL_CIRCLE_FILL = "cupertino_pencil_circle_fill" - PENCIL_ELLIPSIS_RECTANGLE = "cupertino_pencil_ellipsis_rectangle" - PENCIL_OUTLINE = "cupertino_pencil_outline" - PENCIL_SLASH = "cupertino_pencil_slash" - PERCENT = "cupertino_percent" - PERSON_2 = "cupertino_person_2" - PERSON_2_ALT = "cupertino_person_2_alt" - PERSON_2_FILL = "cupertino_person_2_fill" - PERSON_2_SQUARE_STACK = "cupertino_person_2_square_stack" - PERSON_2_SQUARE_STACK_FILL = "cupertino_person_2_square_stack_fill" - PERSON_3 = "cupertino_person_3" - PERSON_3_FILL = "cupertino_person_3_fill" - PERSON_ALT = "cupertino_person_alt" - PERSON_ALT_CIRCLE = "cupertino_person_alt_circle" - PERSON_ALT_CIRCLE_FILL = "cupertino_person_alt_circle_fill" - PERSON_BADGE_MINUS = "cupertino_person_badge_minus" - PERSON_BADGE_MINUS_FILL = "cupertino_person_badge_minus_fill" - PERSON_BADGE_PLUS = "cupertino_person_badge_plus" - PERSON_BADGE_PLUS_FILL = "cupertino_person_badge_plus_fill" - PERSON_CIRCLE = "cupertino_person_circle" - PERSON_CIRCLE_FILL = "cupertino_person_circle_fill" - PERSON_CROP_CIRCLE = "cupertino_person_crop_circle" - PERSON_CROP_CIRCLE_BADGE_CHECKMARK = "cupertino_person_crop_circle_badge_checkmark" - PERSON_CROP_CIRCLE_BADGE_EXCLAM = "cupertino_person_crop_circle_badge_exclam" - PERSON_CROP_CIRCLE_BADGE_MINUS = "cupertino_person_crop_circle_badge_minus" - PERSON_CROP_CIRCLE_BADGE_PLUS = "cupertino_person_crop_circle_badge_plus" - PERSON_CROP_CIRCLE_BADGE_XMARK = "cupertino_person_crop_circle_badge_xmark" - PERSON_CROP_CIRCLE_FILL = "cupertino_person_crop_circle_fill" - PERSON_CROP_CIRCLE_FILL_BADGE_CHECKMARK = ( - "cupertino_person_crop_circle_fill_badge_checkmark" - ) - PERSON_CROP_CIRCLE_FILL_BADGE_EXCLAM = ( - "cupertino_person_crop_circle_fill_badge_exclam" - ) - PERSON_CROP_CIRCLE_FILL_BADGE_MINUS = ( - "cupertino_person_crop_circle_fill_badge_minus" - ) - PERSON_CROP_CIRCLE_FILL_BADGE_PLUS = "cupertino_person_crop_circle_fill_badge_plus" - PERSON_CROP_CIRCLE_FILL_BADGE_XMARK = ( - "cupertino_person_crop_circle_fill_badge_xmark" - ) - PERSON_CROP_RECTANGLE = "cupertino_person_crop_rectangle" - PERSON_CROP_RECTANGLE_FILL = "cupertino_person_crop_rectangle_fill" - PERSON_CROP_SQUARE = "cupertino_person_crop_square" - PERSON_CROP_SQUARE_FILL = "cupertino_person_crop_square_fill" - PERSON_FILL = "cupertino_person_fill" - PERSONALHOTSPOT = "cupertino_personalhotspot" - PERSPECTIVE = "cupertino_perspective" - PHONE_ARROW_DOWN_LEFT = "cupertino_phone_arrow_down_left" - PHONE_ARROW_RIGHT = "cupertino_phone_arrow_right" - PHONE_ARROW_UP_RIGHT = "cupertino_phone_arrow_up_right" - PHONE_BADGE_PLUS = "cupertino_phone_badge_plus" - PHONE_CIRCLE = "cupertino_phone_circle" - PHONE_CIRCLE_FILL = "cupertino_phone_circle_fill" - PHONE_DOWN = "cupertino_phone_down" - PHONE_DOWN_CIRCLE = "cupertino_phone_down_circle" - PHONE_DOWN_CIRCLE_FILL = "cupertino_phone_down_circle_fill" - PHONE_DOWN_FILL = "cupertino_phone_down_fill" - PHONE_FILL = "cupertino_phone_fill" - PHONE_FILL_ARROW_DOWN_LEFT = "cupertino_phone_fill_arrow_down_left" - PHONE_FILL_ARROW_RIGHT = "cupertino_phone_fill_arrow_right" - PHONE_FILL_ARROW_UP_RIGHT = "cupertino_phone_fill_arrow_up_right" - PHONE_FILL_BADGE_PLUS = "cupertino_phone_fill_badge_plus" - PHOTO = "cupertino_photo" - PHOTO_FILL = "cupertino_photo_fill" - PHOTO_FILL_ON_RECTANGLE_FILL = "cupertino_photo_fill_on_rectangle_fill" - PHOTO_ON_RECTANGLE = "cupertino_photo_on_rectangle" - PIANO = "cupertino_piano" - PIN = "cupertino_pin" - PIN_FILL = "cupertino_pin_fill" - PIN_SLASH = "cupertino_pin_slash" - PIN_SLASH_FILL = "cupertino_pin_slash_fill" - PLACEMARK = "cupertino_placemark" - PLACEMARK_FILL = "cupertino_placemark_fill" - PLAY = "cupertino_play" - PLAY_CIRCLE = "cupertino_play_circle" - PLAY_CIRCLE_FILL = "cupertino_play_circle_fill" - PLAY_FILL = "cupertino_play_fill" - PLAY_RECTANGLE = "cupertino_play_rectangle" - PLAY_RECTANGLE_FILL = "cupertino_play_rectangle_fill" - PLAYPAUSE = "cupertino_playpause" - PLAYPAUSE_FILL = "cupertino_playpause_fill" - PLUS = "cupertino_plus" - PLUS_APP = "cupertino_plus_app" - PLUS_APP_FILL = "cupertino_plus_app_fill" - PLUS_BUBBLE = "cupertino_plus_bubble" - PLUS_BUBBLE_FILL = "cupertino_plus_bubble_fill" - PLUS_CIRCLE = "cupertino_plus_circle" - PLUS_CIRCLE_FILL = "cupertino_plus_circle_fill" - PLUS_RECTANGLE = "cupertino_plus_rectangle" - PLUS_RECTANGLE_FILL = "cupertino_plus_rectangle_fill" - PLUS_RECTANGLE_FILL_ON_RECTANGLE_FILL = ( - "cupertino_plus_rectangle_fill_on_rectangle_fill" - ) - PLUS_RECTANGLE_ON_RECTANGLE = "cupertino_plus_rectangle_on_rectangle" - PLUS_SLASH_MINUS = "cupertino_plus_slash_minus" - PLUS_SQUARE = "cupertino_plus_square" - PLUS_SQUARE_FILL = "cupertino_plus_square_fill" - PLUS_SQUARE_FILL_ON_SQUARE_FILL = "cupertino_plus_square_fill_on_square_fill" - PLUS_SQUARE_ON_SQUARE = "cupertino_plus_square_on_square" - PLUSMINUS = "cupertino_plusminus" - PLUSMINUS_CIRCLE = "cupertino_plusminus_circle" - PLUSMINUS_CIRCLE_FILL = "cupertino_plusminus_circle_fill" - POWER = "cupertino_power" - PRINTER = "cupertino_printer" - PRINTER_FILL = "cupertino_printer_fill" - PROJECTIVE = "cupertino_projective" - PURCHASED = "cupertino_purchased" - PURCHASED_CIRCLE = "cupertino_purchased_circle" - PURCHASED_CIRCLE_FILL = "cupertino_purchased_circle_fill" - QRCODE = "cupertino_qrcode" - QRCODE_VIEWFINDER = "cupertino_qrcode_viewfinder" - QUESTION = "cupertino_question" - QUESTION_CIRCLE = "cupertino_question_circle" - QUESTION_CIRCLE_FILL = "cupertino_question_circle_fill" - QUESTION_DIAMOND = "cupertino_question_diamond" - QUESTION_DIAMOND_FILL = "cupertino_question_diamond_fill" - QUESTION_SQUARE = "cupertino_question_square" - QUESTION_SQUARE_FILL = "cupertino_question_square_fill" - QUOTE_BUBBLE = "cupertino_quote_bubble" - QUOTE_BUBBLE_FILL = "cupertino_quote_bubble_fill" - RADIOWAVES_LEFT = "cupertino_radiowaves_left" - RADIOWAVES_RIGHT = "cupertino_radiowaves_right" - RAYS = "cupertino_rays" - RECORDINGTAPE = "cupertino_recordingtape" - RECTANGLE = "cupertino_rectangle" - RECTANGLE_3_OFFGRID = "cupertino_rectangle_3_offgrid" - RECTANGLE_3_OFFGRID_FILL = "cupertino_rectangle_3_offgrid_fill" - RECTANGLE_ARROW_UP_RIGHT_ARROW_DOWN_LEFT = ( - "cupertino_rectangle_arrow_up_right_arrow_down_left" - ) - RECTANGLE_ARROW_UP_RIGHT_ARROW_DOWN_LEFT_SLASH = ( - "cupertino_rectangle_arrow_up_right_arrow_down_left_slash" - ) - RECTANGLE_BADGE_CHECKMARK = "cupertino_rectangle_badge_checkmark" - RECTANGLE_BADGE_XMARK = "cupertino_rectangle_badge_xmark" - RECTANGLE_COMPRESS_VERTICAL = "cupertino_rectangle_compress_vertical" - RECTANGLE_DOCK = "cupertino_rectangle_dock" - RECTANGLE_EXPAND_VERTICAL = "cupertino_rectangle_expand_vertical" - RECTANGLE_FILL = "cupertino_rectangle_fill" - RECTANGLE_FILL_BADGE_CHECKMARK = "cupertino_rectangle_fill_badge_checkmark" - RECTANGLE_FILL_BADGE_XMARK = "cupertino_rectangle_fill_badge_xmark" - RECTANGLE_FILL_ON_RECTANGLE_ANGLED_FILL = ( - "cupertino_rectangle_fill_on_rectangle_angled_fill" - ) - RECTANGLE_FILL_ON_RECTANGLE_FILL = "cupertino_rectangle_fill_on_rectangle_fill" - RECTANGLE_GRID_1X2 = "cupertino_rectangle_grid_1x2" - RECTANGLE_GRID_1X2_FILL = "cupertino_rectangle_grid_1x2_fill" - RECTANGLE_GRID_2X2 = "cupertino_rectangle_grid_2x2" - RECTANGLE_GRID_2X2_FILL = "cupertino_rectangle_grid_2x2_fill" - RECTANGLE_GRID_3X2 = "cupertino_rectangle_grid_3x2" - RECTANGLE_GRID_3X2_FILL = "cupertino_rectangle_grid_3x2_fill" - RECTANGLE_ON_RECTANGLE = "cupertino_rectangle_on_rectangle" - RECTANGLE_ON_RECTANGLE_ANGLED = "cupertino_rectangle_on_rectangle_angled" - RECTANGLE_PAPERCLIP = "cupertino_rectangle_paperclip" - RECTANGLE_SPLIT_3X1 = "cupertino_rectangle_split_3x1" - RECTANGLE_SPLIT_3X1_FILL = "cupertino_rectangle_split_3x1_fill" - RECTANGLE_SPLIT_3X3 = "cupertino_rectangle_split_3x3" - RECTANGLE_SPLIT_3X3_FILL = "cupertino_rectangle_split_3x3_fill" - RECTANGLE_STACK = "cupertino_rectangle_stack" - RECTANGLE_STACK_BADGE_MINUS = "cupertino_rectangle_stack_badge_minus" - RECTANGLE_STACK_BADGE_PERSON_CROP = "cupertino_rectangle_stack_badge_person_crop" - RECTANGLE_STACK_BADGE_PLUS = "cupertino_rectangle_stack_badge_plus" - RECTANGLE_STACK_FILL = "cupertino_rectangle_stack_fill" - RECTANGLE_STACK_FILL_BADGE_MINUS = "cupertino_rectangle_stack_fill_badge_minus" - RECTANGLE_STACK_FILL_BADGE_PERSON_CROP = ( - "cupertino_rectangle_stack_fill_badge_person_crop" - ) - RECTANGLE_STACK_FILL_BADGE_PLUS = "cupertino_rectangle_stack_fill_badge_plus" - RECTANGLE_STACK_PERSON_CROP = "cupertino_rectangle_stack_person_crop" - RECTANGLE_STACK_PERSON_CROP_FILL = "cupertino_rectangle_stack_person_crop_fill" - REPEAT = "cupertino_repeat" - REPEAT_1 = "cupertino_repeat_1" - RESIZE = "cupertino_resize" - RESIZE_H = "cupertino_resize_h" - RESIZE_V = "cupertino_resize_v" - RETURN_ICON = "cupertino_return_icon" - RHOMBUS = "cupertino_rhombus" - RHOMBUS_FILL = "cupertino_rhombus_fill" - ROCKET = "cupertino_rocket" - ROCKET_FILL = "cupertino_rocket_fill" - ROSETTE = "cupertino_rosette" - ROTATE_LEFT = "cupertino_rotate_left" - ROTATE_LEFT_FILL = "cupertino_rotate_left_fill" - ROTATE_RIGHT = "cupertino_rotate_right" - ROTATE_RIGHT_FILL = "cupertino_rotate_right_fill" - SCISSORS = "cupertino_scissors" - SCISSORS_ALT = "cupertino_scissors_alt" - SCOPE = "cupertino_scope" - SCRIBBLE = "cupertino_scribble" - SEARCH_CIRCLE = "cupertino_search_circle" - SEARCH_CIRCLE_FILL = "cupertino_search_circle_fill" - SELECTION_PIN_IN_OUT = "cupertino_selection_pin_in_out" - SHIELD = "cupertino_shield" - SHIELD_FILL = "cupertino_shield_fill" - SHIELD_LEFTHALF_FILL = "cupertino_shield_lefthalf_fill" - SHIELD_SLASH = "cupertino_shield_slash" - SHIELD_SLASH_FILL = "cupertino_shield_slash_fill" - SHIFT = "cupertino_shift" - SHIFT_FILL = "cupertino_shift_fill" - SIDEBAR_LEFT = "cupertino_sidebar_left" - SIDEBAR_RIGHT = "cupertino_sidebar_right" - SIGNATURE = "cupertino_signature" - SKEW = "cupertino_skew" - SLASH_CIRCLE = "cupertino_slash_circle" - SLASH_CIRCLE_FILL = "cupertino_slash_circle_fill" - SLIDER_HORIZONTAL_3 = "cupertino_slider_horizontal_3" - SLIDER_HORIZONTAL_BELOW_RECTANGLE = "cupertino_slider_horizontal_below_rectangle" - SLOWMO = "cupertino_slowmo" - SMALLCIRCLE_CIRCLE = "cupertino_smallcircle_circle" - SMALLCIRCLE_CIRCLE_FILL = "cupertino_smallcircle_circle_fill" - SMALLCIRCLE_FILL_CIRCLE = "cupertino_smallcircle_fill_circle" - SMALLCIRCLE_FILL_CIRCLE_FILL = "cupertino_smallcircle_fill_circle_fill" - SMILEY = "cupertino_smiley" - SMILEY_FILL = "cupertino_smiley_fill" - SMOKE = "cupertino_smoke" - SMOKE_FILL = "cupertino_smoke_fill" - SNOW = "cupertino_snow" - SORT_DOWN = "cupertino_sort_down" - SORT_DOWN_CIRCLE = "cupertino_sort_down_circle" - SORT_DOWN_CIRCLE_FILL = "cupertino_sort_down_circle_fill" - SORT_UP = "cupertino_sort_up" - SORT_UP_CIRCLE = "cupertino_sort_up_circle" - SORT_UP_CIRCLE_FILL = "cupertino_sort_up_circle_fill" - SPARKLES = "cupertino_sparkles" - SPEAKER = "cupertino_speaker" - SPEAKER_1 = "cupertino_speaker_1" - SPEAKER_1_FILL = "cupertino_speaker_1_fill" - SPEAKER_2 = "cupertino_speaker_2" - SPEAKER_2_FILL = "cupertino_speaker_2_fill" - SPEAKER_3 = "cupertino_speaker_3" - SPEAKER_3_FILL = "cupertino_speaker_3_fill" - SPEAKER_FILL = "cupertino_speaker_fill" - SPEAKER_SLASH = "cupertino_speaker_slash" - SPEAKER_SLASH_FILL = "cupertino_speaker_slash_fill" - SPEAKER_SLASH_FILL_RTL = "cupertino_speaker_slash_fill_rtl" - SPEAKER_SLASH_RTL = "cupertino_speaker_slash_rtl" - SPEAKER_ZZZ = "cupertino_speaker_zzz" - SPEAKER_ZZZ_FILL = "cupertino_speaker_zzz_fill" - SPEAKER_ZZZ_FILL_RTL = "cupertino_speaker_zzz_fill_rtl" - SPEAKER_ZZZ_RTL = "cupertino_speaker_zzz_rtl" - SPEEDOMETER = "cupertino_speedometer" - SPORTSCOURT = "cupertino_sportscourt" - SPORTSCOURT_FILL = "cupertino_sportscourt_fill" - SQUARE = "cupertino_square" - SQUARE_ARROW_DOWN = "cupertino_square_arrow_down" - SQUARE_ARROW_DOWN_FILL = "cupertino_square_arrow_down_fill" - SQUARE_ARROW_DOWN_ON_SQUARE = "cupertino_square_arrow_down_on_square" - SQUARE_ARROW_DOWN_ON_SQUARE_FILL = "cupertino_square_arrow_down_on_square_fill" - SQUARE_ARROW_LEFT = "cupertino_square_arrow_left" - SQUARE_ARROW_LEFT_FILL = "cupertino_square_arrow_left_fill" - SQUARE_ARROW_RIGHT = "cupertino_square_arrow_right" - SQUARE_ARROW_RIGHT_FILL = "cupertino_square_arrow_right_fill" - SQUARE_ARROW_UP = "cupertino_square_arrow_up" - SQUARE_ARROW_UP_FILL = "cupertino_square_arrow_up_fill" - SQUARE_ARROW_UP_ON_SQUARE = "cupertino_square_arrow_up_on_square" - SQUARE_ARROW_UP_ON_SQUARE_FILL = "cupertino_square_arrow_up_on_square_fill" - SQUARE_FAVORITES = "cupertino_square_favorites" - SQUARE_FAVORITES_ALT = "cupertino_square_favorites_alt" - SQUARE_FAVORITES_ALT_FILL = "cupertino_square_favorites_alt_fill" - SQUARE_FAVORITES_FILL = "cupertino_square_favorites_fill" - SQUARE_FILL = "cupertino_square_fill" - SQUARE_FILL_LINE_VERTICAL_SQUARE = "cupertino_square_fill_line_vertical_square" - SQUARE_FILL_LINE_VERTICAL_SQUARE_FILL = ( - "cupertino_square_fill_line_vertical_square_fill" - ) - SQUARE_FILL_ON_CIRCLE_FILL = "cupertino_square_fill_on_circle_fill" - SQUARE_FILL_ON_SQUARE_FILL = "cupertino_square_fill_on_square_fill" - SQUARE_GRID_2X2 = "cupertino_square_grid_2x2" - SQUARE_GRID_2X2_FILL = "cupertino_square_grid_2x2_fill" - SQUARE_GRID_3X2 = "cupertino_square_grid_3x2" - SQUARE_GRID_3X2_FILL = "cupertino_square_grid_3x2_fill" - SQUARE_GRID_4X3_FILL = "cupertino_square_grid_4x3_fill" - SQUARE_LEFTHALF_FILL = "cupertino_square_lefthalf_fill" - SQUARE_LINE_VERTICAL_SQUARE = "cupertino_square_line_vertical_square" - SQUARE_LINE_VERTICAL_SQUARE_FILL = "cupertino_square_line_vertical_square_fill" - SQUARE_LIST = "cupertino_square_list" - SQUARE_LIST_FILL = "cupertino_square_list_fill" - SQUARE_ON_CIRCLE = "cupertino_square_on_circle" - SQUARE_ON_SQUARE = "cupertino_square_on_square" - SQUARE_PENCIL = "cupertino_square_pencil" - SQUARE_PENCIL_FILL = "cupertino_square_pencil_fill" - SQUARE_RIGHTHALF_FILL = "cupertino_square_righthalf_fill" - SQUARE_SPLIT_1X2 = "cupertino_square_split_1x2" - SQUARE_SPLIT_1X2_FILL = "cupertino_square_split_1x2_fill" - SQUARE_SPLIT_2X1 = "cupertino_square_split_2x1" - SQUARE_SPLIT_2X1_FILL = "cupertino_square_split_2x1_fill" - SQUARE_SPLIT_2X2 = "cupertino_square_split_2x2" - SQUARE_SPLIT_2X2_FILL = "cupertino_square_split_2x2_fill" - SQUARE_STACK = "cupertino_square_stack" - SQUARE_STACK_3D_DOWN_DOTTEDLINE = "cupertino_square_stack_3d_down_dottedline" - SQUARE_STACK_3D_DOWN_RIGHT = "cupertino_square_stack_3d_down_right" - SQUARE_STACK_3D_DOWN_RIGHT_FILL = "cupertino_square_stack_3d_down_right_fill" - SQUARE_STACK_3D_UP = "cupertino_square_stack_3d_up" - SQUARE_STACK_3D_UP_FILL = "cupertino_square_stack_3d_up_fill" - SQUARE_STACK_3D_UP_SLASH = "cupertino_square_stack_3d_up_slash" - SQUARE_STACK_3D_UP_SLASH_FILL = "cupertino_square_stack_3d_up_slash_fill" - SQUARE_STACK_FILL = "cupertino_square_stack_fill" - SQUARES_BELOW_RECTANGLE = "cupertino_squares_below_rectangle" - STAR = "cupertino_star" - STAR_CIRCLE = "cupertino_star_circle" - STAR_CIRCLE_FILL = "cupertino_star_circle_fill" - STAR_FILL = "cupertino_star_fill" - STAR_LEFTHALF_FILL = "cupertino_star_lefthalf_fill" - STAR_SLASH = "cupertino_star_slash" - STAR_SLASH_FILL = "cupertino_star_slash_fill" - STAROFLIFE = "cupertino_staroflife" - STAROFLIFE_FILL = "cupertino_staroflife_fill" - STOP = "cupertino_stop" - STOP_CIRCLE = "cupertino_stop_circle" - STOP_CIRCLE_FILL = "cupertino_stop_circle_fill" - STOP_FILL = "cupertino_stop_fill" - STOPWATCH = "cupertino_stopwatch" - STOPWATCH_FILL = "cupertino_stopwatch_fill" - STRIKETHROUGH = "cupertino_strikethrough" - SUIT_CLUB = "cupertino_suit_club" - SUIT_CLUB_FILL = "cupertino_suit_club_fill" - SUIT_DIAMOND = "cupertino_suit_diamond" - SUIT_DIAMOND_FILL = "cupertino_suit_diamond_fill" - SUIT_HEART = "cupertino_suit_heart" - SUIT_HEART_FILL = "cupertino_suit_heart_fill" - SUIT_SPADE = "cupertino_suit_spade" - SUIT_SPADE_FILL = "cupertino_suit_spade_fill" - SUM = "cupertino_sum" - SUN_DUST = "cupertino_sun_dust" - SUN_DUST_FILL = "cupertino_sun_dust_fill" - SUN_HAZE = "cupertino_sun_haze" - SUN_HAZE_FILL = "cupertino_sun_haze_fill" - SUN_MAX = "cupertino_sun_max" - SUN_MAX_FILL = "cupertino_sun_max_fill" - SUN_MIN = "cupertino_sun_min" - SUN_MIN_FILL = "cupertino_sun_min_fill" - SUNRISE = "cupertino_sunrise" - SUNRISE_FILL = "cupertino_sunrise_fill" - SUNSET = "cupertino_sunset" - SUNSET_FILL = "cupertino_sunset_fill" - T_BUBBLE = "cupertino_t_bubble" - T_BUBBLE_FILL = "cupertino_t_bubble_fill" - TABLE = "cupertino_table" - TABLE_BADGE_MORE = "cupertino_table_badge_more" - TABLE_BADGE_MORE_FILL = "cupertino_table_badge_more_fill" - TABLE_FILL = "cupertino_table_fill" - TAG_CIRCLE = "cupertino_tag_circle" - TAG_CIRCLE_FILL = "cupertino_tag_circle_fill" - TAG_FILL = "cupertino_tag_fill" - TEXT_ALIGNCENTER = "cupertino_text_aligncenter" - TEXT_ALIGNLEFT = "cupertino_text_alignleft" - TEXT_ALIGNRIGHT = "cupertino_text_alignright" - TEXT_APPEND = "cupertino_text_append" - TEXT_BADGE_CHECKMARK = "cupertino_text_badge_checkmark" - TEXT_BADGE_MINUS = "cupertino_text_badge_minus" - TEXT_BADGE_PLUS = "cupertino_text_badge_plus" - TEXT_BADGE_STAR = "cupertino_text_badge_star" - TEXT_BADGE_XMARK = "cupertino_text_badge_xmark" - TEXT_BUBBLE = "cupertino_text_bubble" - TEXT_BUBBLE_FILL = "cupertino_text_bubble_fill" - TEXT_CURSOR = "cupertino_text_cursor" - TEXT_INSERT = "cupertino_text_insert" - TEXT_JUSTIFY = "cupertino_text_justify" - TEXT_JUSTIFYLEFT = "cupertino_text_justifyleft" - TEXT_JUSTIFYRIGHT = "cupertino_text_justifyright" - TEXT_QUOTE = "cupertino_text_quote" - TEXTBOX = "cupertino_textbox" - TEXTFORMAT = "cupertino_textformat" - TEXTFORMAT_123 = "cupertino_textformat_123" - TEXTFORMAT_ABC = "cupertino_textformat_abc" - TEXTFORMAT_ABC_DOTTEDUNDERLINE = "cupertino_textformat_abc_dottedunderline" - TEXTFORMAT_ALT = "cupertino_textformat_alt" - TEXTFORMAT_SIZE = "cupertino_textformat_size" - TEXTFORMAT_SUBSCRIPT = "cupertino_textformat_subscript" - TEXTFORMAT_SUPERSCRIPT = "cupertino_textformat_superscript" - THERMOMETER = "cupertino_thermometer" - THERMOMETER_SNOWFLAKE = "cupertino_thermometer_snowflake" - THERMOMETER_SUN = "cupertino_thermometer_sun" - TICKET = "cupertino_ticket" - TICKET_FILL = "cupertino_ticket_fill" - TICKETS = "cupertino_tickets" - TICKETS_FILL = "cupertino_tickets_fill" - TIMELAPSE = "cupertino_timelapse" - TIMER = "cupertino_timer" - TIMER_FILL = "cupertino_timer_fill" - TODAY = "cupertino_today" - TODAY_FILL = "cupertino_today_fill" - TORNADO = "cupertino_tornado" - TORTOISE = "cupertino_tortoise" - TORTOISE_FILL = "cupertino_tortoise_fill" - TRAM_FILL = "cupertino_tram_fill" - TRASH = "cupertino_trash" - TRASH_CIRCLE = "cupertino_trash_circle" - TRASH_CIRCLE_FILL = "cupertino_trash_circle_fill" - TRASH_FILL = "cupertino_trash_fill" - TRASH_SLASH = "cupertino_trash_slash" - TRASH_SLASH_FILL = "cupertino_trash_slash_fill" - TRAY = "cupertino_tray" - TRAY_2 = "cupertino_tray_2" - TRAY_2_FILL = "cupertino_tray_2_fill" - TRAY_ARROW_DOWN = "cupertino_tray_arrow_down" - TRAY_ARROW_DOWN_FILL = "cupertino_tray_arrow_down_fill" - TRAY_ARROW_UP = "cupertino_tray_arrow_up" - TRAY_ARROW_UP_FILL = "cupertino_tray_arrow_up_fill" - TRAY_FILL = "cupertino_tray_fill" - TRAY_FULL = "cupertino_tray_full" - TRAY_FULL_FILL = "cupertino_tray_full_fill" - TREE = "cupertino_tree" - TRIANGLE = "cupertino_triangle" - TRIANGLE_FILL = "cupertino_triangle_fill" - TRIANGLE_LEFTHALF_FILL = "cupertino_triangle_lefthalf_fill" - TRIANGLE_RIGHTHALF_FILL = "cupertino_triangle_righthalf_fill" - TROPICALSTORM = "cupertino_tropicalstorm" - TUNINGFORK = "cupertino_tuningfork" - TV = "cupertino_tv" - TV_CIRCLE = "cupertino_tv_circle" - TV_CIRCLE_FILL = "cupertino_tv_circle_fill" - TV_FILL = "cupertino_tv_fill" - TV_MUSIC_NOTE = "cupertino_tv_music_note" - TV_MUSIC_NOTE_FILL = "cupertino_tv_music_note_fill" - UIWINDOW_SPLIT_2X1 = "cupertino_uiwindow_split_2x1" - UMBRELLA = "cupertino_umbrella" - UMBRELLA_FILL = "cupertino_umbrella_fill" - UNDERLINE = "cupertino_underline" - UPLOAD_CIRCLE = "cupertino_upload_circle" - UPLOAD_CIRCLE_FILL = "cupertino_upload_circle_fill" - VIDEOCAM = "cupertino_videocam" - VIDEOCAM_CIRCLE = "cupertino_videocam_circle" - VIDEOCAM_CIRCLE_FILL = "cupertino_videocam_circle_fill" - VIDEOCAM_FILL = "cupertino_videocam_fill" - VIEW_2D = "cupertino_view_2d" - VIEW_3D = "cupertino_view_3d" - VIEWFINDER = "cupertino_viewfinder" - VIEWFINDER_CIRCLE = "cupertino_viewfinder_circle" - VIEWFINDER_CIRCLE_FILL = "cupertino_viewfinder_circle_fill" - WAND_RAYS = "cupertino_wand_rays" - WAND_RAYS_INVERSE = "cupertino_wand_rays_inverse" - WAND_STARS = "cupertino_wand_stars" - WAND_STARS_INVERSE = "cupertino_wand_stars_inverse" - WAVEFORM = "cupertino_waveform" - WAVEFORM_CIRCLE = "cupertino_waveform_circle" - WAVEFORM_CIRCLE_FILL = "cupertino_waveform_circle_fill" - WAVEFORM_PATH = "cupertino_waveform_path" - WAVEFORM_PATH_BADGE_MINUS = "cupertino_waveform_path_badge_minus" - WAVEFORM_PATH_BADGE_PLUS = "cupertino_waveform_path_badge_plus" - WAVEFORM_PATH_ECG = "cupertino_waveform_path_ecg" - WIFI = "cupertino_wifi" - WIFI_EXCLAMATIONMARK = "cupertino_wifi_exclamationmark" - WIFI_SLASH = "cupertino_wifi_slash" - WIND = "cupertino_wind" - WIND_SNOW = "cupertino_wind_snow" - WRENCH = "cupertino_wrench" - WRENCH_FILL = "cupertino_wrench_fill" - XMARK = "cupertino_xmark" - XMARK_CIRCLE = "cupertino_xmark_circle" - XMARK_CIRCLE_FILL = "cupertino_xmark_circle_fill" - XMARK_OCTAGON = "cupertino_xmark_octagon" - XMARK_OCTAGON_FILL = "cupertino_xmark_octagon_fill" - XMARK_RECTANGLE = "cupertino_xmark_rectangle" - XMARK_RECTANGLE_FILL = "cupertino_xmark_rectangle_fill" - XMARK_SEAL = "cupertino_xmark_seal" - XMARK_SEAL_FILL = "cupertino_xmark_seal_fill" - XMARK_SHIELD = "cupertino_xmark_shield" - XMARK_SHIELD_FILL = "cupertino_xmark_shield_fill" - XMARK_SQUARE = "cupertino_xmark_square" - XMARK_SQUARE_FILL = "cupertino_xmark_square_fill" - ZOOM_IN = "cupertino_zoom_in" - ZOOM_OUT = "cupertino_zoom_out" - ZZZ = "cupertino_zzz" diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_list_tile.py b/sdk/python/packages/flet/src/flet/core/cupertino_list_tile.py deleted file mode 100644 index 88959fa973..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_list_tile.py +++ /dev/null @@ -1,317 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, -) - - -class CupertinoListTile(ConstrainedControl): - """ - An iOS-style list tile. The CupertinoListTile is a Cupertino equivalent of Material ListTile. - - Example: - - ``` - import flet as ft - - - def main(page: ft.Page): - def tile_clicked(e): - print("Tile Clicked!") - - page.add( - ft.CupertinoListTile( - notched=True, - additional_info=ft.Text("Wed Jan 25"), - bgcolor_activated=ft.colors.AMBER_ACCENT, - leading=ft.Icon(name=ft.cupertino_icons.GAME_CONTROLLER), - title=ft.Text("CupertinoListTile not notched"), - subtitle=ft.Text("Subtitle"), - trailing=ft.Icon(name=ft.cupertino_icons.ALARM), - on_click=tile_clicked, - ), - - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinolisttile - """ - - def __init__( - self, - title: Optional[Control] = None, - subtitle: Optional[Control] = None, - leading: Optional[Control] = None, - trailing: Optional[Control] = None, - bgcolor: Optional[ColorValue] = None, - bgcolor_activated: Optional[str] = None, - padding: Optional[PaddingValue] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - toggle_inputs: Optional[bool] = None, - additional_info: Optional[Control] = None, - leading_size: OptionalNumber = None, - leading_to_title: OptionalNumber = None, - notched: Optional[bool] = None, - on_click: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.leading = leading - self.title = title - self.subtitle = subtitle - self.trailing = trailing - self.bgcolor = bgcolor - self.bgcolor_activated = bgcolor_activated - self.url = url - self.url_target = url_target - self.toggle_inputs = toggle_inputs - self.additional_info = additional_info - self.leading_size = leading_size - self.leading_to_title = leading_to_title - self.padding = padding - self.notched = notched - self.on_click = on_click - - def _get_control_name(self): - return "cupertinolisttile" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - children = [] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__title: - self.__title._set_attr_internal("n", "title") - children.append(self.__title) - if self.__subtitle: - self.__subtitle._set_attr_internal("n", "subtitle") - children.append(self.__subtitle) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - if self.__additional_info: - self.__additional_info._set_attr_internal("n", "additionalInfo") - children.append(self.__additional_info) - return children - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # leading_size - @property - def leading_size(self) -> float: - return self._get_attr("leadingSize", data_type="float", def_value=30.0) - - @leading_size.setter - def leading_size(self, value: OptionalNumber): - self._set_attr("leadingSize", value) - - # leading_to_title - @property - def leading_to_title(self) -> float: - return self._get_attr("leadingToTitle", data_type="float", def_value=12.0) - - @leading_to_title.setter - def leading_to_title(self, value: OptionalNumber): - self._set_attr("leadingToTitle", value) - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # subtitle - @property - def subtitle(self) -> Optional[Control]: - return self.__subtitle - - @subtitle.setter - def subtitle(self, value: Optional[Control]): - self.__subtitle = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # additional_info - @property - def additional_info(self) -> Optional[Control]: - return self.__additional_info - - @additional_info.setter - def additional_info(self, value: Optional[Control]): - self.__additional_info = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # notched - @property - def notched(self) -> bool: - return self._get_attr("notched", data_type="bool", def_value=False) - - @notched.setter - def notched(self, value: Optional[bool]): - self._set_attr("notched", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # bgcolor_activated - @property - def bgcolor_activated(self) -> Optional[str]: - return self._get_attr("bgcolorActivated") - - @bgcolor_activated.setter - def bgcolor_activated(self, value: Optional[str]): - self._set_attr("bgcolorActivated", value) - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # toggle_inputs - @property - def toggle_inputs(self) -> bool: - return self._get_attr("toggleInputs", data_type="bool", def_value=False) - - @toggle_inputs.setter - def toggle_inputs(self, value: Optional[bool]): - self._set_attr("toggleInputs", value) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - self._set_attr("onclick", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_navigation_bar.py b/sdk/python/packages/flet/src/flet/core/cupertino_navigation_bar.py deleted file mode 100644 index e57a49565d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_navigation_bar.py +++ /dev/null @@ -1,219 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.border import Border -from flet.core.constrained_control import ConstrainedControl -from flet.core.navigation_bar import NavigationBarDestination -from flet.core.ref import Ref -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - OptionalNumber, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoNavigationBar(ConstrainedControl): - """ - An iOS-styled bottom navigation tab bar. - - Navigation bars offer a persistent and convenient way to switch between primary destinations in an app. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "CupertinoNavigationBar Example" - page.navigation_bar = ft.CupertinoNavigationBar( - bgcolor=ft.colors.AMBER_100, - inactive_color=ft.colors.GREY, - active_color=ft.colors.BLACK, - on_change=lambda e: print("Selected tab:", e.control.selected_index), - destinations=[ - ft.NavigationBarDestination(icon=ft.icons.EXPLORE, label="Explore"), - ft.NavigationBarDestination(icon=ft.icons.COMMUTE, label="Commute"), - ft.NavigationBarDestination( - icon=ft.icons.BOOKMARK_BORDER, - selected_icon=ft.icons.BOOKMARK, - label="Explore", - ), - ] - ) - page.add(ft.SafeArea(ft.Text("Body!"))) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinonavigationbar - """ - - def __init__( - self, - destinations: Optional[List[NavigationBarDestination]] = None, - selected_index: Optional[int] = None, - bgcolor: Optional[ColorValue] = None, - active_color: Optional[ColorValue] = None, - inactive_color: Optional[ColorValue] = None, - border: Optional[Border] = None, - icon_size: OptionalNumber = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - self.destinations = destinations - self.selected_index = selected_index - self.bgcolor = bgcolor - self.active_color = active_color - self.inactive_color = inactive_color - self.border = border - self.icon_size = icon_size - self.on_change = on_change - - def _get_control_name(self): - return "cupertinonavigationbar" - - def before_update(self) -> None: - super().before_update() - self._set_attr_json("border", self.__border) - - def _get_children(self): - return self.__destinations - - # destinations - @property - def destinations(self) -> Optional[List[NavigationBarDestination]]: - return self.__destinations - - @destinations.setter - def destinations(self, value: Optional[List[NavigationBarDestination]]): - self.__destinations = value if value else [] - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - self._set_attr("selectedIndex", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # inactive_color - @property - def inactive_color(self) -> Optional[ColorValue]: - return self.__inactive_color - - @inactive_color.setter - def inactive_color(self, value: Optional[ColorValue]): - self.__inactive_color = value - self._set_enum_attr("inactiveColor", value, ColorEnums) - - # icon_size - @property - def icon_size(self) -> OptionalNumber: - return self._get_attr("iconSize") - - @icon_size.setter - def icon_size(self, value: OptionalNumber): - self._set_attr("iconSize", value) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_picker.py b/sdk/python/packages/flet/src/flet/core/cupertino_picker.py deleted file mode 100644 index b2326812ce..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_picker.py +++ /dev/null @@ -1,256 +0,0 @@ -from typing import Any, List, Optional, Sequence, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoPicker(ConstrainedControl): - """ - An iOS-styled picker. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinopicker - """ - - def __init__( - self, - controls: Sequence[Control], - item_extent: OptionalNumber = None, - selected_index: Optional[int] = None, - bgcolor: Optional[ColorValue] = None, - use_magnifier: Optional[bool] = None, - looping: Optional[bool] = None, - magnification: OptionalNumber = None, - squeeze: OptionalNumber = None, - diameter_ratio: OptionalNumber = None, - off_axis_fraction: OptionalNumber = None, - selection_overlay: Optional[Control] = None, - default_selection_overlay_bgcolor: Optional[ColorValue] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.squeeze = squeeze - self.bgcolor = bgcolor - self.on_change = on_change - self.magnification = magnification - self.diameter_ratio = diameter_ratio - self.off_axis_fraction = off_axis_fraction - self.use_magnifier = use_magnifier - self.item_extent = item_extent - self.controls = controls - self.looping = looping - self.selected_index = selected_index - self.selection_overlay = selection_overlay - self.default_selection_overlay_bgcolor = default_selection_overlay_bgcolor - - def _get_control_name(self): - return "cupertinopicker" - - def _get_children(self): - children = self.__controls - if self.__selection_overlay: - self.__selection_overlay._set_attr_internal("n", "selection_overlay") - children.append(self.__selection_overlay) - return children - - # squeeze - @property - def squeeze(self) -> float: - return self._get_attr("squeeze", data_type="float", def_value=1.45) - - @squeeze.setter - def squeeze(self, value: OptionalNumber): - if value is not None and value <= 0: - raise ValueError("CupertinoPicker.squeeze must be greater than 0") - self._set_attr("squeeze", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # use_magnifier - @property - def use_magnifier(self) -> bool: - return self._get_attr("useMagnifier", data_type="bool", def_value=False) - - @use_magnifier.setter - def use_magnifier(self, value: Optional[bool]): - self._set_attr("useMagnifier", value) - - # magnification - @property - def magnification(self) -> float: - return self._get_attr("magnification", data_type="float", def_value=1.0) - - @magnification.setter - def magnification(self, value: OptionalNumber): - if value is not None and value <= 0: - raise ValueError("CupertinoPicker.magnification must be greater than 0") - self._set_attr("magnification", value) - - # item_extent - @property - def item_extent(self) -> OptionalNumber: - return self._get_attr("itemExtent", data_type="float") - - @item_extent.setter - def item_extent(self, value: OptionalNumber): - assert ( - value is None or value > 0 - ), "item_extent cannot be negative or equal to 0" - self._set_attr("itemExtent", value) - - # looping - @property - def looping(self) -> bool: - return self._get_attr("looping", data_type="bool", def_value=False) - - @looping.setter - def looping(self, value: Optional[bool]): - self._set_attr("looping", value) - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - self._set_attr("selectedIndex", value) - - # diameter_ratio - @property - def diameter_ratio(self) -> float: - return self._get_attr("diameterRatio", data_type="float", def_value=1.07) - - @diameter_ratio.setter - def diameter_ratio(self, value: OptionalNumber): - self._set_attr("diameterRatio", value) - - # off_axis_fraction - @property - def off_axis_fraction(self) -> float: - return self._get_attr("offAxisFraction", data_type="float", def_value=0.0) - - @off_axis_fraction.setter - def off_axis_fraction(self, value: OptionalNumber): - self._set_attr("offAxisFraction", value) - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - @controls.setter - def controls(self, value: Sequence[Control]): - self.__controls = list(value) - - # selection_overlay - @property - def selection_overlay(self) -> Optional[Control]: - return self.__selection_overlay - - @selection_overlay.setter - def selection_overlay(self, value: Optional[Control]): - self.__selection_overlay = value - - # default_selection_overlay_bgcolor - @property - def default_selection_overlay_bgcolor(self) -> Optional[ColorValue]: - return self.__default_selection_overlay_bgcolor - - @default_selection_overlay_bgcolor.setter - def default_selection_overlay_bgcolor(self, value: Optional[ColorValue]): - self.__default_selection_overlay_bgcolor = value - self._set_enum_attr("defaultSelectionOverlayBgcolor", value, ColorEnums) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_radio.py b/sdk/python/packages/flet/src/flet/core/cupertino_radio.py deleted file mode 100644 index ef861c8e92..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_radio.py +++ /dev/null @@ -1,252 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - LabelPosition, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class CupertinoRadio(ConstrainedControl): - """ - Radio buttons let people select a single option from two or more choices. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoradio - """ - - def __init__( - self, - label: Optional[str] = None, - value: Optional[str] = None, - label_position: Optional[LabelPosition] = None, - fill_color: Optional[ColorValue] = None, - active_color: Optional[ColorValue] = None, - inactive_color: Optional[ColorValue] = None, - autofocus: Optional[bool] = None, - use_checkmark_style: Optional[bool] = None, - toggleable: Optional[bool] = None, - focus_color: Optional[ColorValue] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.label = label - self.label_position = label_position - self.autofocus = autofocus - self.use_checkmark_style = use_checkmark_style - self.fill_color = fill_color - self.active_color = active_color - self.inactive_color = inactive_color - self.on_focus = on_focus - self.on_blur = on_blur - self.focus_color = focus_color - self.toggleable = toggleable - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "cupertinoradio" - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value", def_value="") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # label_position - @property - def label_position(self) -> Optional[LabelPosition]: - return self.__label_position - - @label_position.setter - def label_position(self, value: Optional[LabelPosition]): - self.__label_position = value - self._set_enum_attr("labelPosition", value, LabelPosition) - - # fill_color - @property - def fill_color(self) -> Optional[ColorValue]: - return self.__fill_color - - @fill_color.setter - def fill_color(self, value: Optional[ColorValue]): - self.__fill_color = value - self._set_enum_attr("fillColor", value, ColorEnums) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # toggleable - @property - def toggleable(self) -> bool: - return self._get_attr("toggleable", data_type="bool", def_value=False) - - @toggleable.setter - def toggleable(self, value: Optional[bool]): - self._set_attr("toggleable", value) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # use_checkmark_style - @property - def use_checkmark_style(self) -> bool: - return self._get_attr("useCheckmarkStyle", data_type="bool", def_value=False) - - @use_checkmark_style.setter - def use_checkmark_style(self, value: Optional[bool]): - self._set_attr("useCheckmarkStyle", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # inactive_color - @property - def inactive_color(self) -> Optional[ColorValue]: - return self.__inactive_color - - @inactive_color.setter - def inactive_color(self, value: Optional[ColorValue]): - self.__inactive_color = value - self._set_enum_attr("inactiveColor", value, ColorEnums) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_segmented_button.py b/sdk/python/packages/flet/src/flet/core/cupertino_segmented_button.py deleted file mode 100644 index eee03310b8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_segmented_button.py +++ /dev/null @@ -1,228 +0,0 @@ -from typing import Any, List, Optional, Sequence, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoSegmentedButton(ConstrainedControl): - """ - An iOS-style segmented button. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinosegmentedbutton - """ - - def __init__( - self, - controls: Sequence[Control], - selected_index: Optional[int] = None, - selected_color: Optional[ColorValue] = None, - unselected_color: Optional[ColorValue] = None, - border_color: Optional[ColorValue] = None, - padding: Optional[PaddingValue] = None, - click_color: Optional[ColorValue] = None, - disabled_color: Optional[ColorValue] = None, - disabled_text_color: Optional[ColorValue] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.controls = controls - self.padding = padding - self.border_color = border_color - self.selected_index = selected_index - self.selected_color = selected_color - self.unselected_color = unselected_color - self.on_change = on_change - self.click_color = click_color - self.disabled_color = disabled_color - self.disabled_text_color = disabled_text_color - - def _get_control_name(self): - return "cupertinosegmentedbutton" - - def _get_children(self): - return self.__controls - - def before_update(self): - super().before_update() - assert ( - len(self.__controls) >= 2 - ), "CupertinoSegmentedButton must have at minimum two visible controls" - - def _before_build_command(self): - super()._before_build_command() - self._set_attr_json("padding", self.__padding) - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - @controls.setter - def controls(self, value: Sequence[Control]): - self.__controls = list(value) - - # border_color - @property - def border_color(self) -> Optional[ColorValue]: - return self.__border_color - - @border_color.setter - def border_color(self, value: Optional[ColorValue]): - self.__border_color = value - self._set_enum_attr("borderColor", value, ColorEnums) - - # disabled_color - @property - def disabled_color(self) -> Optional[ColorValue]: - return self.__disabled_color - - @disabled_color.setter - def disabled_color(self, value: Optional[ColorValue]): - self.__disabled_color = value - self._set_enum_attr("disabledColor", value, ColorEnums) - - # disabled_text_color - @property - def disabled_text_color(self) -> Optional[ColorValue]: - return self.__disabled_text_color - - @disabled_text_color.setter - def disabled_text_color(self, value: Optional[ColorValue]): - self.__disabled_text_color = value - self._set_enum_attr("disabledTextColor", value, ColorEnums) - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - if value is not None and not (0 <= value < len(self.controls)): - raise IndexError("selected_index out of range") - self._set_attr("selectedIndex", value) - - # selected_color - @property - def selected_color(self) -> Optional[ColorValue]: - return self.__selected_color - - @selected_color.setter - def selected_color(self, value: Optional[ColorValue]): - self.__selected_color = value - self._set_enum_attr("selectedColor", value, ColorEnums) - - # unselected_color - @property - def unselected_color(self) -> Optional[ColorValue]: - return self.__unselected_color - - @unselected_color.setter - def unselected_color(self, value: Optional[ColorValue]): - self.__unselected_color = value - self._set_enum_attr("unselectedColor", value, ColorEnums) - - # click_color - @property - def click_color(self) -> Optional[ColorValue]: - return self.__click_color - - @click_color.setter - def click_color(self, value: Optional[ColorValue]): - self.__click_color = value - self._set_enum_attr("clickColor", value, ColorEnums) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_slider.py b/sdk/python/packages/flet/src/flet/core/cupertino_slider.py deleted file mode 100644 index 41807d51e4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_slider.py +++ /dev/null @@ -1,245 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoSlider(ConstrainedControl): - """ - An iOS-type slider. - - It provides a visual indication of adjustable content, as well as the current setting in the total range of content. - - Use a slider when you want people to set defined values (such as volume or brightness), or when people would benefit from instant feedback on the effect of setting changes. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoslider - """ - - def __init__( - self, - value: OptionalNumber = None, - min: OptionalNumber = None, - max: OptionalNumber = None, - divisions: Optional[int] = None, - active_color: Optional[ColorValue] = None, - thumb_color: Optional[ColorValue] = None, - on_change: OptionalControlEventCallable = None, - on_change_start: OptionalControlEventCallable = None, - on_change_end: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.min = min - self.max = max - self.divisions = divisions - self.round = round - self.active_color = active_color - self.thumb_color = thumb_color - self.on_change = on_change - self.on_change_start = on_change_start - self.on_change_end = on_change_end - self.on_focus = on_focus - self.on_blur = on_blur - - def _get_control_name(self): - return "cupertinoslider" - - def before_update(self): - super().before_update() - assert ( - self.min is None or self.max is None or self.min <= self.max - ), "min must be less than or equal to max" - assert ( - self.min is None or self.value is None or (self.value >= self.min) - ), "value must be greater than or equal to min" - assert ( - self.max is None or self.value is None or (self.value <= self.max) - ), "value must be less than or equal to max" - - # value - @property - def value(self) -> float: - return self._get_attr("value", data_type="float", def_value=self.min or 0.0) - - @value.setter - def value(self, value: OptionalNumber): - self._set_attr("value", value) - - # min - @property - def min(self) -> float: - return self._get_attr("min", data_type="float", def_value=0.0) - - @min.setter - def min(self, value: OptionalNumber): - self._set_attr("min", value) - - # max - @property - def max(self) -> float: - return self._get_attr("max", data_type="float", def_value=1.0) - - @max.setter - def max(self, value: OptionalNumber): - self._set_attr("max", value) - - # divisions - @property - def divisions(self) -> Optional[int]: - return self._get_attr("divisions", data_type="int") - - @divisions.setter - def divisions(self, value: Optional[int]): - self._set_attr("divisions", value) - - # round - @property - def round(self) -> int: - return self._get_attr("round", data_type="int", def_value=0) - - @round.setter - def round(self, value: Optional[int]): - self._set_attr("round", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # thumb_color - @property - def thumb_color(self) -> Optional[ColorValue]: - return self.__thumb_color - - @thumb_color.setter - def thumb_color(self, value: Optional[ColorValue]): - self.__thumb_color = value - self._set_enum_attr("thumbColor", value, ColorEnums) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_change_start - @property - def on_change_start(self) -> OptionalControlEventCallable: - return self._get_event_handler("change_start") - - @on_change_start.setter - def on_change_start(self, handler: OptionalControlEventCallable): - self._add_event_handler("change_start", handler) - - # on_change_end - @property - def on_change_end(self) -> OptionalControlEventCallable: - return self._get_event_handler("change_end") - - @on_change_end.setter - def on_change_end(self, handler: OptionalControlEventCallable): - self._add_event_handler("change_end", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_sliding_segmented_button.py b/sdk/python/packages/flet/src/flet/core/cupertino_sliding_segmented_button.py deleted file mode 100644 index c37d27fbf1..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_sliding_segmented_button.py +++ /dev/null @@ -1,189 +0,0 @@ -from typing import Any, Optional, Sequence, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoSlidingSegmentedButton(ConstrainedControl): - """ - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoslidingsegmentedbutton - """ - - def __init__( - self, - controls: Sequence[Control], - selected_index: Optional[int] = None, - bgcolor: Optional[ColorValue] = None, - thumb_color: Optional[ColorValue] = None, - padding: Optional[PaddingValue] = None, - proportional_width: Optional[bool] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.controls = controls - self.padding = padding - self.selected_index = selected_index - self.bgcolor = bgcolor - self.thumb_color = thumb_color - self.on_change = on_change - self.proportional_width = proportional_width - - def _get_control_name(self): - return "cupertinoslidingsegmentedbutton" - - def _get_children(self): - return self.__controls - - def before_update(self): - super().before_update() - assert ( - len(self.__controls) >= 2 - ), "CupertinoSlidingSegmentedButton must have at minimum two visible controls" - self._set_attr_json("padding", self.__padding) - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Sequence[Control]): - self.__controls = list(value) - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - assert ( - value is None or 0 <= value <= len(self.controls) - 1 - ), "selected_index out of range" - self._set_attr("selectedIndex", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # proportional_width - - @property - def proportional_width(self) -> Optional[bool]: - return self._get_attr("proportionalWidth", data_type="bool", def_value=False) - - @proportional_width.setter - def proportional_width(self, value: Optional[bool]): - self._set_attr("proportionalWidth", value) - - # thumb_color - @property - def thumb_color(self) -> Optional[ColorValue]: - return self.__thumb_color - - @thumb_color.setter - def thumb_color(self, value: Optional[ColorValue]): - self.__thumb_color = value - self._set_enum_attr("thumbColor", value, ColorEnums) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_switch.py b/sdk/python/packages/flet/src/flet/core/cupertino_switch.py deleted file mode 100644 index 482cd63848..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_switch.py +++ /dev/null @@ -1,395 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - IconValue, - LabelPosition, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils.deprecated import deprecated_property - - -class CupertinoSwitch(ConstrainedControl): - """ - An iOS-style switch. Used to toggle the on/off state of a single setting. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.add( - ft.CupertinoSwitch(label="Cupertino Switch", value=True), - ft.Switch(label="Material Checkbox", value=True), - ft.Container(height=20), - ft.Text( - "Adaptive Switch shows as CupertinoSwitch on macOS and iOS and as Switch on other platforms:" - ), - ft.Switch(adaptive=True, label="Adaptive Switch", value=True), - ) - - ft.app(target=main) - ``` - ----- - - Online docs: https://flet.dev/docs/controls/cupertinoswitch - """ - - def __init__( - self, - label: Optional[str] = None, - value: Optional[bool] = None, - label_position: Optional[LabelPosition] = None, - active_color: Optional[ColorValue] = None, - thumb_color: Optional[ColorValue] = None, - track_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - autofocus: Optional[bool] = None, - on_label_color: Optional[ColorValue] = None, - off_label_color: Optional[ColorValue] = None, - active_thumb_image: Optional[str] = None, - inactive_thumb_image: Optional[str] = None, - active_track_color: Optional[ColorValue] = None, - inactive_thumb_color: Optional[ColorValue] = None, - inactive_track_color: Optional[ColorValue] = None, - track_outline_color: ControlStateValue[ColorValue] = None, - track_outline_width: ControlStateValue[OptionalNumber] = None, - thumb_icon: ControlStateValue[IconValue] = None, - on_change: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - on_image_error: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.label = label - self.label_position = label_position - self.autofocus = autofocus - self.active_color = active_color - self.focus_color = focus_color - self.thumb_color = thumb_color - self.track_color = track_color - self.on_change = on_change - self.on_focus = on_focus - self.on_blur = on_blur - self.on_label_color = on_label_color - self.off_label_color = off_label_color - self.active_thumb_image = active_thumb_image - self.active_track_color = active_track_color - self.inactive_thumb_color = inactive_thumb_color - self.inactive_track_color = inactive_track_color - self.track_outline_color = track_outline_color - self.track_outline_width = track_outline_width - self.thumb_icon = thumb_icon - self.inactive_thumb_image = inactive_thumb_image - self.on_image_error = on_image_error - - def _get_control_name(self): - return "cupertinoswitch" - - def before_update(self): - super().before_update() - self._set_attr_json("thumbColor", self.__thumb_color) - self._set_attr_json("trackColor", self.__track_color) - self._set_attr_json( - "trackOutlineColor", self.__track_outline_color, wrap_attr_dict=True - ) - self._set_attr_json( - "trackOutlineWidth", self.__track_outline_width, wrap_attr_dict=True - ) - self._set_attr_json("thumbIcon", self.__thumb_icon, wrap_attr_dict=True) - - # value - @property - def value(self) -> bool: - return self._get_attr("value", data_type="bool", def_value=False) - - @value.setter - def value(self, value: Optional[bool]): - self._set_attr("value", value) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # active_thumb_image - @property - def active_thumb_image(self) -> Optional[str]: - return self._get_attr("activeThumbImage") - - @active_thumb_image.setter - def active_thumb_image(self, value: Optional[str]): - self._set_attr("activeThumbImage", value) - - # inactive_thumb_image - @property - def inactive_thumb_image(self) -> Optional[str]: - return self._get_attr("inactiveThumbImage") - - @inactive_thumb_image.setter - def inactive_thumb_image(self, value: Optional[str]): - self._set_attr("inactiveThumbImage", value) - - # active_track_color - @property - def active_track_color(self) -> Optional[ColorValue]: - return self.__active_track_color - - @active_track_color.setter - def active_track_color(self, value: Optional[ColorValue]): - self.__active_track_color = value - self._set_enum_attr("activeTrackColor", value, ColorEnums) - - # inactive_track_color - @property - def inactive_track_color(self) -> Optional[ColorValue]: - return self.__inactive_track_color - - @inactive_track_color.setter - def inactive_track_color(self, value: Optional[ColorValue]): - self.__inactive_track_color = value - self._set_enum_attr("inactiveTrackColor", value, ColorEnums) - - # track_outline_color - @property - def track_outline_color(self) -> ControlStateValue[ColorValue]: - return self.__track_outline_color - - @track_outline_color.setter - def track_outline_color(self, value: ControlStateValue[ColorValue]): - self.__track_outline_color = value - - # track_outline_width - @property - def track_outline_width(self) -> ControlStateValue[OptionalNumber]: - return self.__track_outline_width - - @track_outline_width.setter - def track_outline_width(self, value: ControlStateValue[OptionalNumber]): - self.__track_outline_width = value - - # thumb_icon - @property - def thumb_icon(self) -> ControlStateValue[IconValue]: - return self.__thumb_icon - - @thumb_icon.setter - def thumb_icon(self, value: ControlStateValue[IconValue]): - self.__thumb_icon = value - - # label_position - @property - def label_position(self) -> Optional[LabelPosition]: - return self.__label_position - - @label_position.setter - def label_position(self, value: Optional[LabelPosition]): - self.__label_position = value - self._set_enum_attr("labelPosition", value, LabelPosition) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - deprecated_property( - name="active_color", - reason="Use active_track_color instead.", - version="0.26.0", - delete_version="0.29.0", - ) - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - if value is not None: - deprecated_property( - name="active_color", - reason="Use active_track_color instead.", - version="0.26.0", - delete_version="0.29.0", - ) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # thumb_color - @property - def thumb_color(self) -> Optional[ColorValue]: - return self.__thumb_color - - @thumb_color.setter - def thumb_color(self, value: Optional[ColorValue]): - self.__thumb_color = value - - # track_color - @property - def track_color(self) -> Optional[ColorValue]: - deprecated_property( - name="track_color", - reason="Use inactive_track_color instead.", - version="0.26.0", - delete_version="0.29.0", - ) - return self.__track_color - - @track_color.setter - def track_color(self, value: Optional[ColorValue]): - self.__track_color = value - if value is not None: - deprecated_property( - name="track_color", - reason="Use inactive_track_color instead.", - version="0.26.0", - delete_version="0.29.0", - ) - - # on_label_color - @property - def on_label_color(self) -> Optional[ColorValue]: - return self.__on_label_color - - @on_label_color.setter - def on_label_color(self, value: Optional[ColorValue]): - self.__on_label_color = value - self._set_enum_attr("onLabelColor", value, ColorEnums) - - # off_label_color - @property - def off_label_color(self) -> Optional[ColorValue]: - return self.__off_label_color - - @off_label_color.setter - def off_label_color(self, value: Optional[ColorValue]): - self.__off_label_color = value - self._set_enum_attr("offLabelColor", value, ColorEnums) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # on_image_error - @property - def on_image_error(self) -> OptionalControlEventCallable: - return self._get_event_handler("image_error") - - @on_image_error.setter - def on_image_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("image_error", handler) diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_textfield.py b/sdk/python/packages/flet/src/flet/core/cupertino_textfield.py deleted file mode 100644 index 59cb53a905..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_textfield.py +++ /dev/null @@ -1,376 +0,0 @@ -from enum import Enum -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.autofill_group import AutofillHint -from flet.core.badge import BadgeValue -from flet.core.border import Border -from flet.core.box import BoxShadow, DecorationImage -from flet.core.control import Control, OptionalNumber -from flet.core.gradients import Gradient -from flet.core.ref import Ref -from flet.core.text_style import StrutStyle, TextStyle -from flet.core.textfield import InputFilter, KeyboardType, TextCapitalization, TextField -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BlendMode, - BorderRadiusValue, - Brightness, - ClipBehavior, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - TextAlign, -) - - -class VisibilityMode(Enum): - NEVER = "never" - EDITING = "editing" - NOT_EDITING = "notEditing" - ALWAYS = "always" - - -class CupertinoTextField(TextField): - """ - An iOS-style text field. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinotextfield - """ - - def __init__( - self, - placeholder_text: Optional[str] = None, - value: Optional[str] = None, - placeholder_style: Optional[TextStyle] = None, - gradient: Optional[Gradient] = None, - blend_mode: Optional[BlendMode] = None, - shadow: Union[None, BoxShadow, List[BoxShadow]] = None, - prefix_visibility_mode: Optional[VisibilityMode] = None, - suffix_visibility_mode: Optional[VisibilityMode] = None, - clear_button_visibility_mode: Optional[VisibilityMode] = None, - clear_button_semantics_label: Optional[str] = None, - image: Optional[DecorationImage] = None, - padding: Optional[PaddingValue] = None, - # - # TextField - # - keyboard_type: Optional[KeyboardType] = None, - rtl: Optional[bool] = None, - multiline: Optional[bool] = None, - min_lines: Optional[int] = None, - max_lines: Optional[int] = None, - max_length: Optional[int] = None, - password: Optional[bool] = None, - can_reveal_password: Optional[bool] = None, - read_only: Optional[bool] = None, - shift_enter: Optional[bool] = None, - text_align: Optional[TextAlign] = None, - autofocus: Optional[bool] = None, - capitalization: Optional[TextCapitalization] = None, - autocorrect: Optional[bool] = None, - enable_suggestions: Optional[bool] = None, - smart_dashes_type: Optional[bool] = None, - smart_quotes_type: Optional[bool] = None, - cursor_color: Optional[ColorValue] = None, - cursor_width: OptionalNumber = None, - cursor_height: OptionalNumber = None, - cursor_radius: OptionalNumber = None, - show_cursor: Optional[bool] = None, - selection_color: Optional[ColorValue] = None, - input_filter: Optional[InputFilter] = None, - autofill_hints: Union[None, AutofillHint, List[AutofillHint]] = None, - enable_scribble: Optional[bool] = None, - scroll_padding: Optional[PaddingValue] = None, - obscuring_character: Optional[str] = None, - enable_interactive_selection: Optional[bool] = None, - enable_ime_personalized_learning: Optional[bool] = None, - clip_behavior: Optional[ClipBehavior] = None, - keyboard_brightness: Optional[Brightness] = None, - strut_style: Optional[StrutStyle] = None, - animate_cursor_opacity: Optional[bool] = None, - on_click: OptionalControlEventCallable = None, - on_change: OptionalControlEventCallable = None, - on_submit: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - on_tap_outside: OptionalControlEventCallable = None, - # - # FormField - # - text_size: OptionalNumber = None, - text_style: Optional[TextStyle] = None, - border: Optional[Border] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - border_radius: Optional[BorderRadiusValue] = None, - focused_color: Optional[ColorValue] = None, - focused_bgcolor: Optional[ColorValue] = None, - focused_border_width: OptionalNumber = None, - focused_border_color: Optional[ColorValue] = None, - content_padding: Optional[PaddingValue] = None, - dense: Optional[bool] = None, - filled: Optional[bool] = None, - prefix: Optional[Control] = None, - suffix: Optional[Control] = None, - fit_parent_size: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - TextField.__init__( - self, - ref=ref, - key=key, - badge=badge, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - # - # FormField - # - text_size=text_size, - text_style=text_style, - color=color, - bgcolor=bgcolor, - border_radius=border_radius, - focused_color=focused_color, - focused_bgcolor=focused_bgcolor, - focused_border_width=focused_border_width, - focused_border_color=focused_border_color, - content_padding=content_padding, - dense=dense, - filled=filled, - prefix=prefix, - suffix=suffix, - fit_parent_size=fit_parent_size, - # - # TextField - # - value=value, - keyboard_type=keyboard_type, - rtl=rtl, - multiline=multiline, - min_lines=min_lines, - max_lines=max_lines, - max_length=max_length, - password=password, - can_reveal_password=can_reveal_password, - read_only=read_only, - shift_enter=shift_enter, - text_align=text_align, - autofocus=autofocus, - capitalization=capitalization, - autocorrect=autocorrect, - enable_suggestions=enable_suggestions, - smart_dashes_type=smart_dashes_type, - smart_quotes_type=smart_quotes_type, - cursor_color=cursor_color, - cursor_width=cursor_width, - cursor_height=cursor_height, - cursor_radius=cursor_radius, - show_cursor=show_cursor, - selection_color=selection_color, - input_filter=input_filter, - autofill_hints=autofill_hints, - enable_scribble=enable_scribble, - scroll_padding=scroll_padding, - obscuring_character=obscuring_character, - enable_interactive_selection=enable_interactive_selection, - enable_ime_personalized_learning=enable_ime_personalized_learning, - clip_behavior=clip_behavior, - keyboard_brightness=keyboard_brightness, - strut_style=strut_style, - animate_cursor_opacity=animate_cursor_opacity, - on_click=on_click, - on_change=on_change, - on_submit=on_submit, - on_focus=on_focus, - on_blur=on_blur, - on_tap_outside=on_tap_outside, - ) - - self.placeholder_text = placeholder_text - self.placeholder_style = placeholder_style - self.gradient = gradient - self.blend_mode = blend_mode - self.shadow = shadow - self.suffix_visibility_mode = suffix_visibility_mode - self.prefix_visibility_mode = prefix_visibility_mode - self.clear_button_semantics_label = clear_button_semantics_label - self.border = border - self.image = image - self.padding = padding - self.clear_button_visibility_mode = clear_button_visibility_mode - - def _get_control_name(self): - return "cupertinotextfield" - - def before_update(self): - super().before_update() - self._set_attr_json("gradient", self.__gradient) - self._set_attr_json("shadow", self.__shadow if self.__shadow else None) - self._set_attr_json("placeholderStyle", self.__placeholder_style) - self._set_attr_json("border", self.__border) - self._set_attr_json("image", self.__image) - self._set_attr_json("padding", self.__padding) - - # placeholder_text - @property - def placeholder_text(self): - return self._get_attr("placeholderText") - - @placeholder_text.setter - def placeholder_text(self, value): - self._set_attr("placeholderText", value) - - # placeholder_style - @property - def placeholder_style(self): - return self.__placeholder_style - - @placeholder_style.setter - def placeholder_style(self, value: Optional[TextStyle]): - self.__placeholder_style = value - - # gradient - @property - def gradient(self) -> Optional[Gradient]: - return self.__gradient - - @gradient.setter - def gradient(self, value: Optional[Gradient]): - self.__gradient = value - - # blend_mode - @property - def blend_mode(self) -> Optional[BlendMode]: - return self.__blend_mode - - @blend_mode.setter - def blend_mode(self, value: Optional[BlendMode]): - self.__blend_mode = value - self._set_enum_attr("blendMode", value, BlendMode) - - # shadow - @property - def shadow(self) -> Union[None, BoxShadow, List[BoxShadow]]: - return self.__shadow - - @shadow.setter - def shadow(self, value: Union[None, BoxShadow, List[BoxShadow]]): - self.__shadow = value if value is not None else [] - - # image - @property - def image(self) -> Optional[DecorationImage]: - return self.__image - - @image.setter - def image(self, value: Optional[DecorationImage]): - self.__image = value - - # suffix_visibility_mode - @property - def suffix_visibility_mode(self) -> Optional[VisibilityMode]: - return self.__suffix_visibility_mode - - @suffix_visibility_mode.setter - def suffix_visibility_mode(self, value: Optional[VisibilityMode]): - self.__suffix_visibility_mode = value - self._set_enum_attr("suffixVisibilityMode", value, VisibilityMode) - - # clear_button_visibility_mode - @property - def clear_button_visibility_mode(self) -> Optional[VisibilityMode]: - return self.__clear_button_visibility_mode - - @clear_button_visibility_mode.setter - def clear_button_visibility_mode(self, value: Optional[VisibilityMode]): - self.__clear_button_visibility_mode = value - self._set_enum_attr("clearButtonVisibilityMode", value, VisibilityMode) - - # prefix_visibility_mode - @property - def prefix_visibility_mode(self) -> Optional[VisibilityMode]: - return self.__prefix_visibility_mode - - @prefix_visibility_mode.setter - def prefix_visibility_mode(self, value: Optional[VisibilityMode]): - self.__prefix_visibility_mode = value - self._set_enum_attr("prefixVisibilityMode", value, VisibilityMode) - - # clear_button_semantics_label - @property - def clear_button_semantics_label(self) -> Optional[str]: - return self._get_attr("clearButtonSemanticsLabel") - - @clear_button_semantics_label.setter - def clear_button_semantics_label(self, value: Optional[str]): - self._set_attr("clearButtonSemanticsLabel", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value diff --git a/sdk/python/packages/flet/src/flet/core/cupertino_timer_picker.py b/sdk/python/packages/flet/src/flet/core/cupertino_timer_picker.py deleted file mode 100644 index 5241f40f23..0000000000 --- a/sdk/python/packages/flet/src/flet/core/cupertino_timer_picker.py +++ /dev/null @@ -1,201 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class CupertinoTimerPickerMode(Enum): - HOUR_MINUTE = "hm" - HOUR_MINUTE_SECONDS = "hms" - MINUTE_SECONDS = "ms" - - -class CupertinoTimerPicker(ConstrainedControl): - """ - A countdown timer picker in iOS style. - - It can show a countdown duration with hour, minute and second spinners. The duration is bound between 0 and 23 hours 59 minutes 59 seconds. - - ----- - - Online docs: https://flet.dev/docs/controls/cupertinotimerpicker - """ - - def __init__( - self, - value: Optional[int] = None, - alignment: Optional[Alignment] = None, - second_interval: OptionalNumber = None, - minute_interval: OptionalNumber = None, - mode: Optional[CupertinoTimerPickerMode] = None, - bgcolor: Optional[ColorValue] = None, - item_extent: OptionalNumber = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.value = value - self.alignment = alignment - self.mode = mode - self.bgcolor = bgcolor - self.on_change = on_change - self.second_interval = second_interval - self.minute_interval = minute_interval - self.item_extent = item_extent - - def _get_control_name(self): - return "cupertinotimerpicker" - - def before_update(self): - super().before_update() - self._set_attr_json("alignment", self.__alignment) - - # value - @property - def value(self) -> int: - return self._get_attr("value", data_type="int", def_value=0) - - @value.setter - def value(self, value: Optional[int]): - self._set_attr("value", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # second_interval - @property - def second_interval(self) -> int: - return self._get_attr("secondInterval", data_type="int", def_value=1) - - @second_interval.setter - def second_interval(self, value: OptionalNumber): - self._set_attr("secondInterval", value) - - # item_extent - @property - def item_extent(self) -> float: - return self._get_attr("itemExtent", data_type="float", def_value=32.0) - - @item_extent.setter - def item_extent(self, value: OptionalNumber): - self._set_attr("itemExtent", value) - - # minute_interval - @property - def minute_interval(self) -> int: - return self._get_attr("minuteInterval", data_type="int", def_value=1) - - @minute_interval.setter - def minute_interval(self, value: OptionalNumber): - self._set_attr("minuteInterval", value) - - # mode - @property - def mode(self) -> Optional[CupertinoTimerPickerMode]: - return self.__mode - - @mode.setter - def mode(self, value: Optional[CupertinoTimerPickerMode]): - self.__mode = value - self._set_enum_attr("mode", value, CupertinoTimerPickerMode) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/datatable.py b/sdk/python/packages/flet/src/flet/core/datatable.py deleted file mode 100644 index f689f837e5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/datatable.py +++ /dev/null @@ -1,769 +0,0 @@ -import json -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import Border, BorderSide -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.gesture_detector import TapEvent -from flet.core.gradients import Gradient -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - ClipBehavior, - ColorEnums, - ColorValue, - ControlStateValue, - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class DataColumnSortEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.column_index: int = d.get("i") - self.ascending: bool = d.get("a") - - -class DataColumn(Control): - def __init__( - self, - label: Control, - numeric: Optional[bool] = None, - tooltip: Optional[str] = None, - heading_row_alignment: Optional[MainAxisAlignment] = None, - on_sort: OptionalEventCallable[DataColumnSortEvent] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.__on_sort = EventHandler(lambda e: DataColumnSortEvent(e)) - self._add_event_handler("sort", self.__on_sort.get_handler()) - - self.label = label - self.numeric = numeric - self.tooltip = tooltip - self.heading_row_alignment = heading_row_alignment - self.on_sort = on_sort - - def _get_control_name(self): - return "datacolumn" - - def _get_children(self): - self.__label._set_attr_internal("n", "label") - return [self.__label] - - def before_update(self): - super().before_update() - assert self.__label.visible, "label must be visible" - - # label - @property - def label(self) -> Control: - return self.__label - - @label.setter - def label(self, value: Control): - self.__label = value - - # numeric - @property - def numeric(self) -> bool: - return self._get_attr("numeric", data_type="bool", def_value=False) - - @numeric.setter - def numeric(self, value: Optional[bool]): - self._set_attr("numeric", value) - - # tooltip - @property - def tooltip(self) -> Optional[str]: - return self._get_attr("tooltip") - - @tooltip.setter - def tooltip(self, value: Optional[str]): - self._set_attr("tooltip", value) - - # heading_row_alignment - @property - def heading_row_alignment(self) -> Optional[MainAxisAlignment]: - return self.__heading_row_alignment - - @heading_row_alignment.setter - def heading_row_alignment(self, value: Optional[MainAxisAlignment]): - self.__heading_row_alignment = value - self._set_enum_attr("headingRowAlignment", value, MainAxisAlignment) - - # on_sort - @property - def on_sort(self) -> OptionalEventCallable["DataColumnSortEvent"]: - return self.__on_sort.handler - - @on_sort.setter - def on_sort(self, handler: OptionalEventCallable["DataColumnSortEvent"]): - self.__on_sort.handler = handler - self._set_attr("onSort", True if handler is not None else None) - - -class DataCell(Control): - def __init__( - self, - content: Control, - placeholder: Optional[bool] = None, - show_edit_icon: Optional[bool] = None, - on_tap: OptionalControlEventCallable = None, - on_double_tap: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_tap_cancel: OptionalControlEventCallable = None, - on_tap_down: OptionalEventCallable[TapEvent] = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.__on_tap_down = EventHandler(lambda e: TapEvent(e)) - self._add_event_handler("tap_down", self.__on_tap_down.get_handler()) - - self.content = content - self.on_double_tap = on_double_tap - self.on_long_press = on_long_press - self.on_tap = on_tap - self.on_tap_cancel = on_tap_cancel - self.on_tap_down = on_tap_down - self.placeholder = placeholder - self.show_edit_icon = show_edit_icon - - def _get_control_name(self): - return "datacell" - - def _get_children(self): - return [self.__content] - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # placeholder - @property - def placeholder(self) -> bool: - return self._get_attr("placeholder", data_type="bool", def_value=False) - - @placeholder.setter - def placeholder(self, value: Optional[bool]): - self._set_attr("placeholder", value) - - # show_edit_icon - @property - def show_edit_icon(self) -> bool: - return self._get_attr("showEditIcon", data_type="bool", def_value=False) - - @show_edit_icon.setter - def show_edit_icon(self, value: Optional[bool]): - self._set_attr("showEditIcon", value) - - # on_double_tap - @property - def on_double_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("double_tap") - - @on_double_tap.setter - def on_double_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("double_tap", handler) - self._set_attr("onDoubleTap", True if handler is not None else None) - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # on_tap - @property - def on_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap") - - @on_tap.setter - def on_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap", handler) - self._set_attr("onTap", True if handler is not None else None) - - # on_tap_cancel - @property - def on_tap_cancel(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap_cancel") - - @on_tap_cancel.setter - def on_tap_cancel(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap_cancel", handler) - self._set_attr("onTapCancel", True if handler is not None else None) - - # on_tap_down - @property - def on_tap_down(self) -> OptionalEventCallable[TapEvent]: - return self.__on_tap_down.handler - - @on_tap_down.setter - def on_tap_down(self, handler: OptionalEventCallable[TapEvent]): - self.__on_tap_down.handler = handler - self._set_attr("onTapDown", True if handler is not None else None) - - -class DataRow(Control): - def __init__( - self, - cells: List[DataCell], - color: ControlStateValue[ColorValue] = None, - selected: Optional[bool] = None, - on_long_press: OptionalControlEventCallable = None, - on_select_changed: OptionalControlEventCallable = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) - - self.cells = cells - self.color = color - self.selected = selected - self.on_long_press = on_long_press - self.on_select_changed = on_select_changed - - def _get_control_name(self): - return "datarow" - - def __contains__(self, item): - return item in self.__cells - - def before_update(self): - super().before_update() - assert any( - cell.visible for cell in self.__cells - ), "cells must contain at minimum one visible DataCell" - self._set_attr_json("color", self.__color, wrap_attr_dict=True) - - def _get_children(self): - return self.__cells - - # cells - @property - def cells(self) -> List[DataCell]: - return self.__cells - - @cells.setter - def cells(self, value: List[DataCell]): - assert all( - isinstance(cell, DataCell) for cell in value - ), "cells must contain only DataCell instances" - self.__cells = value - - # color - @property - def color(self) -> ControlStateValue[str]: - return self.__color - - @color.setter - def color(self, value: ControlStateValue[str]): - self.__color = value - - # selected - @property - def selected(self) -> bool: - return self._get_attr("selected", data_type="bool", def_value=False) - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # on_select_changed - @property - def on_select_changed(self) -> OptionalControlEventCallable: - return self._get_event_handler("select_changed") - - @on_select_changed.setter - def on_select_changed(self, handler: OptionalControlEventCallable): - self._add_event_handler("select_changed", handler) - self._set_attr("onSelectChanged", True if handler is not None else None) - - -class DataTable(ConstrainedControl): - def __init__( - self, - columns: List[DataColumn], - rows: Optional[List[DataRow]] = None, - sort_ascending: Optional[bool] = None, - show_checkbox_column: Optional[bool] = None, - sort_column_index: Optional[int] = None, - show_bottom_border: Optional[bool] = None, - border: Optional[Border] = None, - border_radius: Optional[BorderRadiusValue] = None, - horizontal_lines: Optional[BorderSide] = None, - vertical_lines: Optional[BorderSide] = None, - checkbox_horizontal_margin: OptionalNumber = None, - column_spacing: OptionalNumber = None, - data_row_color: ControlStateValue[ColorValue] = None, - data_row_min_height: OptionalNumber = None, - data_row_max_height: OptionalNumber = None, - data_text_style: Optional[TextStyle] = None, - bgcolor: Optional[ColorValue] = None, - gradient: Optional[Gradient] = None, - divider_thickness: OptionalNumber = None, - heading_row_color: ControlStateValue[ColorValue] = None, - heading_row_height: OptionalNumber = None, - heading_text_style: Optional[TextStyle] = None, - horizontal_margin: OptionalNumber = None, - clip_behavior: Optional[ClipBehavior] = None, - on_select_all: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.columns = columns - self.rows = rows - self.border = border - self.border_radius = border_radius - self.horizontal_lines = horizontal_lines - self.vertical_lines = vertical_lines - self.bgcolor = bgcolor - self.gradient = gradient - self.divider_thickness = divider_thickness - self.checkbox_horizontal_margin = checkbox_horizontal_margin - self.column_spacing = column_spacing - self.data_row_color = data_row_color - self.data_row_min_height = data_row_min_height - self.data_row_max_height = data_row_max_height - self.data_text_style = data_text_style - self.heading_row_color = heading_row_color - self.heading_row_height = heading_row_height - self.heading_text_style = heading_text_style - self.horizontal_margin = horizontal_margin - self.show_bottom_border = show_bottom_border - self.show_checkbox_column = show_checkbox_column - self.sort_ascending = sort_ascending - self.sort_column_index = sort_column_index - self.on_select_all = on_select_all - self.clip_behavior = clip_behavior - - def _get_control_name(self): - return "datatable" - - def __contains__(self, item): - return item in self.__columns or item in self.__rows - - def before_update(self): - super().before_update() - visible_columns = list(filter(lambda column: column.visible, self.__columns)) - visible_rows = list(filter(lambda row: row.visible, self.__rows)) - assert ( - len(visible_columns) > 0 - ), "columns must contain at minimum one visible DataColumn" - assert all( - len(list(filter(lambda c: c.visible, row.cells))) == len(visible_columns) - for row in visible_rows - ), f"each visible DataRow must contain exactly as many visible DataCells as there are visible DataColumns ({len(visible_columns)})" - assert ( - self.data_row_min_height is None - or self.data_row_max_height is None - or (self.data_row_min_height <= self.data_row_max_height) - ), "data_row_min_height must be less than or equal to data_row_max_height" - assert ( - self.divider_thickness is None or self.divider_thickness >= 0 - ), "divider_thickness must be greater than or equal to 0" - assert self.sort_column_index is None or ( - 0 <= self.sort_column_index < len(visible_columns) - ), f"sort_column_index must be greater than or equal to 0 and less than the number of columns ({len(visible_columns)})" - self._set_attr_json("border", self.__border) - self._set_attr_json("gradient", self.__gradient) - self._set_attr_json("borderRadius", self.__border_radius) - self._set_attr_json("horizontalLines", self.__horizontal_lines) - self._set_attr_json("verticalLines", self.__vertical_lines) - self._set_attr_json("dataRowColor", self.__data_row_color) - self._set_attr_json("headingRowColor", self.__heading_row_color) - self._set_attr_json("dataTextStyle", self.__data_text_style) - self._set_attr_json("headingTextStyle", self.__heading_text_style) - - def _get_children(self): - return self.__columns + self.__rows - - # columns - @property - def columns(self) -> List[DataColumn]: - return self.__columns - - @columns.setter - def columns(self, value: List[DataColumn]): - assert all( - isinstance(column, DataColumn) for column in value - ), "columns must contain only DataColumn instances" - self.__columns = value - - # rows - @property - def rows(self) -> Optional[List[DataRow]]: - return self.__rows - - @rows.setter - def rows(self, value: Optional[List[DataRow]]): - self.__rows = value if value is not None else [] - assert all( - isinstance(row, DataRow) for row in self.__rows - ), "rows must contain only DataRow instances" - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # horizontal_lines - @property - def horizontal_lines(self) -> Optional[BorderSide]: - return self.__horizontal_lines - - @horizontal_lines.setter - def horizontal_lines(self, value: Optional[BorderSide]): - self.__horizontal_lines = value - - # vertical_lines - @property - def vertical_lines(self) -> Optional[BorderSide]: - return self.__vertical_lines - - @vertical_lines.setter - def vertical_lines(self, value: Optional[BorderSide]): - self.__vertical_lines = value - - # checkbox_horizontal_margin - @property - def checkbox_horizontal_margin(self) -> OptionalNumber: - return self._get_attr("checkboxHorizontalMargin") - - @checkbox_horizontal_margin.setter - def checkbox_horizontal_margin(self, value: OptionalNumber): - self._set_attr("checkboxHorizontalMargin", value) - - # column_spacing - @property - def column_spacing(self) -> OptionalNumber: - return self._get_attr("columnSpacing") - - @column_spacing.setter - def column_spacing(self, value: OptionalNumber): - self._set_attr("columnSpacing", value) - - # divider_thickness - @property - def divider_thickness(self) -> float: - return self._get_attr("dividerThickness", data_type="float", def_value=1.0) - - @divider_thickness.setter - def divider_thickness(self, value: OptionalNumber): - self._set_attr("dividerThickness", value) - - # horizontal_margin - @property - def horizontal_margin(self) -> OptionalNumber: - return self._get_attr("horizontalMargin") - - @horizontal_margin.setter - def horizontal_margin(self, value: OptionalNumber): - self._set_attr("horizontalMargin", value) - - # data_row_color - @property - def data_row_color(self) -> ControlStateValue[str]: - return self.__data_row_color - - @data_row_color.setter - def data_row_color(self, value: ControlStateValue[str]): - self.__data_row_color = value - - # data_row_min_height - @property - def data_row_min_height(self) -> OptionalNumber: - return self._get_attr("dataRowMinHeight") - - @data_row_min_height.setter - def data_row_min_height(self, value: OptionalNumber): - self._set_attr("dataRowMinHeight", value) - - # data_row_max_height - @property - def data_row_max_height(self) -> OptionalNumber: - return self._get_attr("dataRowMaxHeight") - - @data_row_max_height.setter - def data_row_max_height(self, value: OptionalNumber): - self._set_attr("dataRowMaxHeight", value) - - # data_text_style - @property - def data_text_style(self) -> Optional[TextStyle]: - return self.__data_text_style - - @data_text_style.setter - def data_text_style(self, value: Optional[TextStyle]): - self.__data_text_style = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # gradient - @property - def gradient(self) -> Optional[Gradient]: - return self.__gradient - - @gradient.setter - def gradient(self, value: Optional[Gradient]): - self.__gradient = value - - # heading_row_color - @property - def heading_row_color(self) -> ControlStateValue[str]: - return self.__heading_row_color - - @heading_row_color.setter - def heading_row_color(self, value: ControlStateValue[str]): - self.__heading_row_color = value - - # heading_row_height - @property - def heading_row_height(self) -> OptionalNumber: - return self._get_attr("headingRowHeight") - - @heading_row_height.setter - def heading_row_height(self, value: OptionalNumber): - self._set_attr("headingRowHeight", value) - - # heading_text_style - @property - def heading_text_style(self) -> Optional[TextStyle]: - return self.__heading_text_style - - @heading_text_style.setter - def heading_text_style(self, value: Optional[TextStyle]): - self.__heading_text_style = value - - # show_bottom_border - @property - def show_bottom_border(self) -> bool: - return self._get_attr("showBottomBorder", data_type="bool", def_value=False) - - @show_bottom_border.setter - def show_bottom_border(self, value: Optional[bool]): - self._set_attr("showBottomBorder", value) - - # show_checkbox_column - @property - def show_checkbox_column(self) -> bool: - return self._get_attr("showCheckboxColumn", data_type="bool", def_value=False) - - @show_checkbox_column.setter - def show_checkbox_column(self, value: Optional[bool]): - self._set_attr("showCheckboxColumn", value) - - # sort_ascending - @property - def sort_ascending(self) -> bool: - return self._get_attr("sortAscending", data_type="bool", def_value=False) - - @sort_ascending.setter - def sort_ascending(self, value: Optional[bool]): - self._set_attr("sortAscending", value) - - # sort_column_index - @property - def sort_column_index(self) -> Optional[int]: - return self._get_attr("sortColumnIndex") - - @sort_column_index.setter - def sort_column_index(self, value: Optional[int]): - self._set_attr("sortColumnIndex", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # on_select_all - @property - def on_select_all(self) -> OptionalControlEventCallable: - return self._get_event_handler("select_all") - - @on_select_all.setter - def on_select_all(self, handler: OptionalControlEventCallable): - self._add_event_handler("select_all", handler) - self._set_attr("onSelectAll", True if handler is not None else None) - - -class Item(Control): - def __init__(self, obj): - Control.__init__(self) - assert obj, "obj cannot be empty" - self.obj = obj - - def _set_attr(self, name, value, dirty=True): - if value is None: - return - - orig_val = self._get_attr(name) - if orig_val is not None: - if isinstance(orig_val, bool): - value = str(value).lower() == "true" - elif isinstance(orig_val, float): - value = float(str(value)) - - self._set_attr_internal(name, value, dirty=False) - if isinstance(self.obj, dict): - self.obj[name] = value - else: - setattr(self.obj, name, value) - - def _fetch_attrs(self): - # reflection - obj = self.obj if isinstance(self.obj, dict) else vars(self.obj) - - for name, val in obj.items(): - data_type = ( - type(val).__name__ if isinstance(val, (bool, float)) else "string" - ) - orig_val = self._get_attr(name, data_type=data_type) - - if val != orig_val: - self._set_attr_internal(name, val, dirty=True) - - def _get_control_name(self): - return "item" diff --git a/sdk/python/packages/flet/src/flet/core/date_picker.py b/sdk/python/packages/flet/src/flet/core/date_picker.py deleted file mode 100644 index 30ddde9ca8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/date_picker.py +++ /dev/null @@ -1,375 +0,0 @@ -from datetime import datetime -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.textfield import KeyboardType -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - DateTimeValue, - IconEnums, - IconValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class DatePickerMode(Enum): - DAY = "day" - YEAR = "year" - - -class DatePickerEntryMode(Enum): - CALENDAR = "calendar" - INPUT = "input" - CALENDAR_ONLY = "calendarOnly" - INPUT_ONLY = "inputOnly" - - -class DatePickerEntryModeChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.entry_mode: Optional[DatePickerEntryMode] = DatePickerEntryMode(e.data) - - -class DatePicker(Control): - """ - A Material-style date picker dialog. - - It is added to [`page.overlay`](page#overlay) and can be opened by setting `open=True` or by calling `Page.open()` method. - - Depending on the `date_picker_entry_mode`, it will show either a Calendar or an Input (TextField) for picking a date. - - Example: - ``` - import flet as ft - - - def main(page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_date_change(e: ft.ControlEvent): - page.add(ft.Text(f"Date changed: {e.control.value.strftime('%Y-%m-%d %H:%M %p')}")) - - cupertino_date_picker = ft.CupertinoDatePicker( - date_picker_mode=ft.CupertinoDatePickerMode.DATE_AND_TIME, - on_change=handle_date_change, - ) - page.add( - ft.CupertinoFilledButton( - "Open CupertinoDatePicker", - on_click=lambda e: page.open( - ft.CupertinoBottomSheet( - cupertino_date_picker, - height=216, - padding=ft.padding.only(top=6), - ) - ), - ) - ) - - - ft.app(main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/datepicker - """ - - def __init__( - self, - open: bool = False, - value: Optional[DateTimeValue] = None, - first_date: DateTimeValue = datetime(year=1900, month=1, day=1), - last_date: DateTimeValue = datetime(year=2050, month=1, day=1), - current_date: DateTimeValue = datetime.now(), - keyboard_type: Optional[KeyboardType] = None, - date_picker_mode: Optional[DatePickerMode] = None, - date_picker_entry_mode: Optional[DatePickerEntryMode] = None, - help_text: Optional[str] = None, - cancel_text: Optional[str] = None, - confirm_text: Optional[str] = None, - error_format_text: Optional[str] = None, - error_invalid_text: Optional[str] = None, - field_hint_text: Optional[str] = None, - field_label_text: Optional[str] = None, - switch_to_calendar_icon: Optional[IconValue] = None, - switch_to_input_icon: Optional[IconValue] = None, - barrier_color: Optional[ColorValue] = None, - on_change: OptionalControlEventCallable = None, - on_dismiss: OptionalControlEventCallable = None, - on_entry_mode_change: OptionalEventCallable[ - "DatePickerEntryModeChangeEvent" - ] = None, - # - # Control - # - ref: Optional[Ref] = None, - expand: Optional[Union[bool, int]] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - tooltip: Optional[TooltipValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_entry_mode_change = EventHandler( - lambda e: DatePickerEntryModeChangeEvent(e) - ) - self._add_event_handler( - "entryModeChange", self.__on_entry_mode_change.get_handler() - ) - - self.value = value - self.first_date = first_date - self.last_date = last_date - self.current_date = current_date - self.keyboard_type = keyboard_type - self.help_text = help_text - self.cancel_text = cancel_text - self.confirm_text = confirm_text - self.error_format_text = error_format_text - self.error_invalid_text = error_invalid_text - self.date_picker_mode = date_picker_mode - self.date_picker_entry_mode = date_picker_entry_mode - self.field_hint_text = field_hint_text - self.field_label_text = field_label_text - self.switch_to_calendar_icon = switch_to_calendar_icon - self.switch_to_input_icon = switch_to_input_icon - self.on_change = on_change - self.on_dismiss = on_dismiss - self.open = open - self.on_entry_mode_change = on_entry_mode_change - self.barrier_color = barrier_color - - def _get_control_name(self): - return "datepicker" - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # value - @property - def value(self) -> Optional[DateTimeValue]: - v = self._get_attr("value") - return datetime.fromisoformat(v) if v else None - - @value.setter - def value(self, value: Optional[DateTimeValue]): - self.__value = value - self._set_attr("value", value if value is None else value.isoformat()) - - @property - def first_date(self) -> DateTimeValue: - return self.__first_date - - @first_date.setter - def first_date(self, value: DateTimeValue): - self.__first_date = value - self._set_attr("firstDate", value.isoformat()) - - # last_date - @property - def last_date(self) -> DateTimeValue: - return self.__last_date - - @last_date.setter - def last_date(self, value: DateTimeValue): - self.__last_date = value - self._set_attr("lastDate", value.isoformat()) - - # current_date - @property - def current_date(self) -> DateTimeValue: - return self.__current_date - - @current_date.setter - def current_date(self, value: DateTimeValue): - self.__current_date = value - self._set_attr("currentDate", value.isoformat()) - - # field_hint_text - @property - def field_hint_text(self) -> Optional[str]: - return self._get_attr("fieldHintText") - - @field_hint_text.setter - def field_hint_text(self, value: Optional[str]): - self._set_attr("fieldHintText", value) - - # field_label_text - @property - def field_label_text(self) -> Optional[str]: - return self._get_attr("fieldLabelText") - - @field_label_text.setter - def field_label_text(self, value: Optional[str]): - self._set_attr("fieldLabelText", value) - - # help_text - @property - def help_text(self) -> Optional[str]: - return self._get_attr("helpText") - - @help_text.setter - def help_text(self, value: Optional[str]): - self._set_attr("helpText", value) - - # cancel_text - @property - def cancel_text(self) -> Optional[str]: - return self._get_attr("cancelText") - - @cancel_text.setter - def cancel_text(self, value: Optional[str]): - self._set_attr("cancelText", value) - - # confirm_text - @property - def confirm_text(self) -> Optional[str]: - return self._get_attr("confirmText") - - @confirm_text.setter - def confirm_text(self, value: Optional[str]): - self._set_attr("confirmText", value) - - # error_format_text - @property - def error_format_text(self) -> Optional[str]: - return self._get_attr("errorFormatText") - - @error_format_text.setter - def error_format_text(self, value: Optional[str]): - self._set_attr("errorFormatText", value) - - # error_invalid_text - @property - def error_invalid_text(self) -> Optional[str]: - return self._get_attr("errorInvalidText") - - @error_invalid_text.setter - def error_invalid_text(self, value: Optional[str]): - self._set_attr("errorInvalidText", value) - - # keyboard_type - @property - def keyboard_type(self) -> Optional[KeyboardType]: - return self.__keyboard_type - - @keyboard_type.setter - def keyboard_type(self, value: Optional[KeyboardType]): - self.__keyboard_type = value - self._set_enum_attr("keyboardType", value, KeyboardType) - - # date_picker_mode - @property - def date_picker_mode(self) -> Optional[DatePickerMode]: - return self.__date_picker_mode - - @date_picker_mode.setter - def date_picker_mode(self, value: Optional[DatePickerMode]): - self.__date_picker_mode = value - self._set_enum_attr("datePickerMode", value, DatePickerMode) - - # date_picker_entry_mode - @property - def date_picker_entry_mode(self) -> Optional[DatePickerEntryMode]: - return self.__date_picker_entry_mode - - @date_picker_entry_mode.setter - def date_picker_entry_mode(self, value: Optional[DatePickerEntryMode]): - self.__date_picker_entry_mode = value - self._set_enum_attr("datePickerEntryMode", value, DatePickerEntryMode) - - # switch_to_calendar_icon - @property - def switch_to_calendar_icon(self) -> Optional[IconValue]: - return self.__switch_to_calendar_icon - - @switch_to_calendar_icon.setter - def switch_to_calendar_icon(self, value: Optional[IconValue]): - self.__switch_to_calendar_icon = value - self._set_enum_attr("switchToCalendarEntryModeIcon", value, IconEnums) - - # switch_to_input_icon - @property - def switch_to_input_icon(self) -> Optional[IconValue]: - return self.__switch_to_input_icon - - @switch_to_input_icon.setter - def switch_to_input_icon(self, value: Optional[IconValue]): - self.__switch_to_input_icon = value - self._set_enum_attr("switchToInputEntryModeIcon", value, IconEnums) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) - - # on_entry_mode_change - @property - def on_entry_mode_change( - self, - ) -> OptionalEventCallable[DatePickerEntryModeChangeEvent]: - return self.__on_entry_mode_change.handler - - @on_entry_mode_change.setter - def on_entry_mode_change( - self, handler: OptionalEventCallable[DatePickerEntryModeChangeEvent] - ): - self.__on_entry_mode_change.handler = handler - - # barrier_color - @property - def barrier_color(self) -> Optional[ColorValue]: - return self.__barrier_color - - @barrier_color.setter - def barrier_color(self, value: Optional[ColorValue]): - self.__barrier_color = value - self._set_enum_attr("barrierColor", value, ColorEnums) diff --git a/sdk/python/packages/flet/src/flet/core/dismissible.py b/sdk/python/packages/flet/src/flet/core/dismissible.py deleted file mode 100644 index 7e281a80e4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/dismissible.py +++ /dev/null @@ -1,297 +0,0 @@ -import json -from typing import Any, Dict, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.snack_bar import DismissDirection -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Dismissible(ConstrainedControl, AdaptiveControl): - """ - A control that can be dismissed by dragging in the indicated `dismiss_direction`. When dragged or flung in the - specified `dismiss_direction`, it's content smoothly slides out of view. - - After completing the sliding animation, if a `resize_duration` is provided, this control further animates its - height (or width, depending on what is perpendicular to the `dismiss_direction`), gradually reducing it to zero - over the specified `resize_duration`. - - ------- - - Online Docs: https://flet.dev/docs/controls/dismissible - """ - - def __init__( - self, - content: Control, - background: Optional[Control] = None, - secondary_background: Optional[Control] = None, - dismiss_direction: Optional[DismissDirection] = None, - dismiss_thresholds: Optional[Dict[DismissDirection, OptionalNumber]] = None, - movement_duration: Optional[int] = None, - resize_duration: Optional[int] = None, - cross_axis_end_offset: OptionalNumber = None, - on_update: OptionalEventCallable["DismissibleUpdateEvent"] = None, - on_dismiss: OptionalEventCallable["DismissibleDismissEvent"] = None, - on_confirm_dismiss: OptionalEventCallable["DismissibleDismissEvent"] = None, - on_resize: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - key: Optional[str] = None, - # - # Adaptive - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__on_dismiss = EventHandler(lambda e: DismissibleDismissEvent(e)) - self.__on_update = EventHandler(lambda e: DismissibleUpdateEvent(e)) - self.__on_confirm_dismiss = EventHandler(lambda e: DismissibleDismissEvent(e)) - - self._add_event_handler("dismiss", self.__on_dismiss.get_handler()) - self._add_event_handler("update", self.__on_update.get_handler()) - self._add_event_handler( - "confirm_dismiss", self.__on_confirm_dismiss.get_handler() - ) - - self.content = content - self.background = background - self.secondary_background = secondary_background - self.dismiss_direction = dismiss_direction - self.dismiss_thresholds = dismiss_thresholds - self.movement_duration = movement_duration - self.resize_duration = resize_duration - self.cross_axis_end_offset = cross_axis_end_offset - self.on_update = on_update - self.on_dismiss = on_dismiss - self.on_confirm_dismiss = on_confirm_dismiss - self.on_resize = on_resize - - def _get_control_name(self): - return "dismissible" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - children = [self.__content] - if self.__background: - self.__background._set_attr_internal("n", "background") - children.append(self.__background) - if self.__secondary_background: - self.__secondary_background._set_attr_internal("n", "secondaryBackground") - children.append(self.__secondary_background) - return children - - def before_update(self): - super().before_update() - self._set_attr_json("dismissThresholds", self.__dismiss_thresholds) - - def confirm_dismiss(self, dismiss: bool): - self.invoke_method("confirm_dismiss", {"dismiss": str(dismiss).lower()}) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # background - @property - def background(self) -> Optional[Control]: - return self.__background - - @background.setter - def background(self, value: Optional[Control]): - self.__background = value - - # secondary_background - @property - def secondary_background(self) -> Optional[Control]: - return self.__secondary_background - - @secondary_background.setter - def secondary_background(self, value: Optional[Control]): - self.__secondary_background = value - - # movementDuration - @property - def movement_duration(self) -> Optional[int]: - return self._get_attr("movementDuration", data_type="int") - - @movement_duration.setter - def movement_duration(self, value: Optional[int]): - self._set_attr("movementDuration", value) - - # resizeDuration - @property - def resize_duration(self) -> Optional[int]: - return self._get_attr("resizeDuration", data_type="int") - - @resize_duration.setter - def resize_duration(self, value: Optional[int]): - self._set_attr("resizeDuration", value) - - # crossAxisEndOffset - @property - def cross_axis_end_offset(self) -> OptionalNumber: - return self._get_attr("crossAxisEndOffset", data_type="float") - - @cross_axis_end_offset.setter - def cross_axis_end_offset(self, value: OptionalNumber): - self._set_attr("crossAxisEndOffset", value) - - # dismissDirection - @property - def dismiss_direction(self) -> Optional[DismissDirection]: - return self.__dismiss_direction - - @dismiss_direction.setter - def dismiss_direction(self, value: Optional[DismissDirection]): - self.__dismiss_direction = value - self._set_enum_attr("dismissDirection", value, DismissDirection) - - # dismissThresholds - @property - def dismiss_thresholds(self) -> Optional[Dict[DismissDirection, OptionalNumber]]: - return self.__dismiss_thresholds - - @dismiss_thresholds.setter - def dismiss_thresholds( - self, value: Optional[Dict[DismissDirection, OptionalNumber]] - ): - self.__dismiss_thresholds = value - - # on_dismiss - @property - def on_dismiss(self) -> OptionalEventCallable["DismissibleDismissEvent"]: - return self.__on_dismiss.handler - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalEventCallable["DismissibleDismissEvent"]): - self.__on_dismiss.handler = handler - self._set_attr("onDismiss", True if handler is not None else None) - - # on_confirm_dismiss - @property - def on_confirm_dismiss(self) -> OptionalEventCallable["DismissibleDismissEvent"]: - return self.__on_confirm_dismiss.handler - - @on_confirm_dismiss.setter - def on_confirm_dismiss( - self, handler: OptionalEventCallable["DismissibleDismissEvent"] - ): - self.__on_confirm_dismiss.handler = handler - self._set_attr("onConfirmDismiss", True if handler is not None else None) - - # on_update - @property - def on_update(self) -> OptionalEventCallable["DismissibleUpdateEvent"]: - return self.__on_update.handler - - @on_update.setter - def on_update(self, handler: OptionalEventCallable["DismissibleUpdateEvent"]): - self.__on_update.handler = handler - self._set_attr("onUpdate", True if handler is not None else None) - - # on_resize - @property - def on_resize(self): - return self._get_event_handler("resize") - - @on_resize.setter - def on_resize(self, handler: OptionalControlEventCallable): - self._add_event_handler("resize", handler) - self._set_attr("onResize", True if handler is not None else None) - - -class DismissibleDismissEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.direction = DismissDirection(e.data) - - -class DismissibleUpdateEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.direction: DismissDirection = DismissDirection(d.get("direction")) - self.progress: float = d.get("progress") - self.reached: bool = d.get("reached") - self.previous_reached: bool = d.get("previous_reached") diff --git a/sdk/python/packages/flet/src/flet/core/divider.py b/sdk/python/packages/flet/src/flet/core/divider.py deleted file mode 100644 index 4c2a8d4c56..0000000000 --- a/sdk/python/packages/flet/src/flet/core/divider.py +++ /dev/null @@ -1,136 +0,0 @@ -from typing import Any, Optional - -from flet.core.badge import BadgeValue -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ColorEnums, ColorValue - - -class Divider(Control): - """ - A thin horizontal line, with padding on either side. - - In the material design language, this represents a divider. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - - page.add( - ft.Column( - [ - ft.Container( - bgcolor=ft.colors.AMBER, - alignment=ft.alignment.center, - expand=True, - ), - ft.Divider(), - ft.Container( - bgcolor=ft.colors.PINK, alignment=ft.alignment.center, expand=True - ), - ], - spacing=0, - expand=True, - ), - ) - - - ft.app(target=main) - - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/divider - """ - - def __init__( - self, - height: OptionalNumber = None, - thickness: OptionalNumber = None, - color: Optional[ColorValue] = None, - leading_indent: OptionalNumber = None, - trailing_indent: OptionalNumber = None, - # - # Control - # - ref: Optional[Ref] = None, - opacity: OptionalNumber = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - opacity=opacity, - tooltip=tooltip, - badge=badge, - visible=visible, - data=data, - ) - - self.height = height - self.thickness = thickness - self.color = color - self.leading_indent = leading_indent - self.trailing_indent = trailing_indent - - def _get_control_name(self): - return "divider" - - # height - @property - def height(self) -> OptionalNumber: - return self._get_attr("height", data_type="float") - - @height.setter - def height(self, value: OptionalNumber): - assert value is None or value >= 0, "height cannot be negative" - self._set_attr("height", value) - - # thickness - @property - def thickness(self) -> OptionalNumber: - return self._get_attr("thickness", data_type="float") - - @thickness.setter - def thickness(self, value: OptionalNumber): - assert value is None or value >= 0, "thickness cannot be negative" - self._set_attr("thickness", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # leading_indent - @property - def leading_indent(self) -> OptionalNumber: - return self._get_attr("leadingIndent", data_type="float") - - @leading_indent.setter - def leading_indent(self, value: OptionalNumber): - assert value is None or value >= 0, "leading_indent cannot be negative" - self._set_attr("leadingIndent", value) - - # trailing_indent - @property - def trailing_indent(self) -> OptionalNumber: - return self._get_attr("trailingIndent", data_type="float") - - @trailing_indent.setter - def trailing_indent(self, value: OptionalNumber): - assert value is None or value >= 0, "trailing_indent cannot be negative" - self._set_attr("trailingIndent", value) diff --git a/sdk/python/packages/flet/src/flet/core/drag_target.py b/sdk/python/packages/flet/src/flet/core/drag_target.py deleted file mode 100644 index 549427902e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/drag_target.py +++ /dev/null @@ -1,214 +0,0 @@ -import json -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable, OptionalEventCallable - - -class DragTarget(Control): - """ - A control that completes drag operation when a `Draggable` widget is dropped. - - When a draggable is dragged on top of a drag target, the drag target is asked whether it will accept the data the draggable is carrying. The drag target will accept incoming drag if it belongs to the same group as draggable. If the user does drop the draggable on top of the drag target (and the drag target has indicated that it will accept the draggable's data), then the drag target is asked to accept the draggable's data. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Drag and Drop example" - - def drag_will_accept(e): - e.control.content.border = ft.border.all( - 2, ft.colors.BLACK45 if e.data == "true" else ft.colors.RED - ) - e.control.update() - - def drag_accept(e: ft.DragTargetEvent): - src = page.get_control(e.src_id) - e.control.content.bgcolor = src.content.bgcolor - e.control.content.border = None - e.control.update() - - def drag_leave(e): - e.control.content.border = None - e.control.update() - - page.add( - ft.Row( - [ - ft.Column( - [ - ft.Draggable( - group="color", - content=ft.Container( - width=50, - height=50, - bgcolor=ft.colors.CYAN, - border_radius=5, - ), - content_feedback=ft.Container( - width=20, - height=20, - bgcolor=ft.colors.CYAN, - border_radius=3, - ), - ), - ft.Draggable( - group="color", - content=ft.Container( - width=50, - height=50, - bgcolor=ft.colors.YELLOW, - border_radius=5, - ), - ), - ft.Draggable( - group="color1", - content=ft.Container( - width=50, - height=50, - bgcolor=ft.colors.GREEN, - border_radius=5, - ), - ), - ] - ), - ft.Container(width=100), - ft.DragTarget( - group="color", - content=ft.Container( - width=50, - height=50, - bgcolor=ft.colors.BLUE_GREY_100, - border_radius=5, - ), - on_will_accept=drag_will_accept, - on_accept=drag_accept, - on_leave=drag_leave, - ), - ] - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/dragtarget - """ - - def __init__( - self, - content: Control, - group: Optional[str] = None, - on_will_accept: OptionalControlEventCallable = None, - on_accept: OptionalEventCallable["DragTargetEvent"] = None, - on_leave: OptionalControlEventCallable = None, - on_move: OptionalEventCallable["DragTargetEvent"] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.__on_accept = EventHandler(lambda e: DragTargetEvent(e)) - self.__on_move = EventHandler(lambda e: DragTargetEvent(e)) - self._add_event_handler("accept", self.__on_accept.get_handler()) - self._add_event_handler("move", self.__on_move.get_handler()) - - self.group = group - self.content = content - self.on_will_accept = on_will_accept - self.on_accept = on_accept - self.on_leave = on_leave - self.on_move = on_move - - def _get_control_name(self): - return "dragtarget" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - # group - @property - def group(self) -> Optional[str]: - return self._get_attr("group") - - @group.setter - def group(self, value: Optional[str]): - self._set_attr("group", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # on_will_accept - @property - def on_will_accept(self) -> OptionalControlEventCallable: - return self._get_event_handler("will_accept") - - @on_will_accept.setter - def on_will_accept(self, handler: OptionalControlEventCallable): - self._add_event_handler("will_accept", handler) - - # on_accept - @property - def on_accept(self) -> OptionalEventCallable["DragTargetEvent"]: - return self.__on_accept.handler - - @on_accept.setter - def on_accept(self, handler: OptionalEventCallable["DragTargetEvent"]): - self.__on_accept.handler = handler - - # on_leave - @property - def on_leave(self) -> OptionalControlEventCallable: - return self._get_event_handler("leave") - - @on_leave.setter - def on_leave(self, handler: OptionalControlEventCallable): - self._add_event_handler("leave", handler) - - # on_move - @property - def on_move(self) -> OptionalEventCallable["DragTargetEvent"]: - return self.__on_move.handler - - @on_move.setter - def on_move(self, handler: OptionalEventCallable["DragTargetEvent"]): - self.__on_move.handler = handler - - -class DragTargetEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.src_id: float = d.get("src_id") - self.x: float = d.get("x") - self.y: float = d.get("y") diff --git a/sdk/python/packages/flet/src/flet/core/draggable.py b/sdk/python/packages/flet/src/flet/core/draggable.py deleted file mode 100644 index c5f565ffc4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/draggable.py +++ /dev/null @@ -1,255 +0,0 @@ -from typing import Any, Optional - -from flet.core.alignment import Axis -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class Draggable(Control): - """ - A control that can be dragged from to a `DragTarget`. - - When a draggable control recognizes the start of a drag gesture, it displays a `content_feedback` control that tracks the user's finger across the screen. If the user lifts their finger while on top of a `DragTarget`, that target is given the opportunity to complete drag-and-drop flow. - - Example: - ``` - import flet - from flet import ( - Column, - Container, - Draggable, - DragTarget, - DragTargetAcceptEvent, - Page, - Row, - border, - colors, - ) - - - def main(page: Page): - page.title = "Drag and Drop example" - - def drag_will_accept(e): - e.control.content.border = border.all( - 2, colors.BLACK45 if e.data == "true" else colors.RED - ) - e.control.update() - - def drag_accept(e: DragTargetAcceptEvent): - src = page.get_control(e.src_id) - e.control.content.bgcolor = src.content.bgcolor - e.control.content.border = None - e.control.update() - - def drag_leave(e): - e.control.content.border = None - e.control.update() - - page.add( - Row( - [ - Column( - [ - Draggable( - group="color", - content=Container( - width=50, - height=50, - bgcolor=colors.CYAN, - border_radius=5, - ), - content_feedback=Container( - width=20, - height=20, - bgcolor=colors.CYAN, - border_radius=3, - ), - ), - Draggable( - group="color", - content=Container( - width=50, - height=50, - bgcolor=colors.YELLOW, - border_radius=5, - ), - ), - Draggable( - group="color1", - content=Container( - width=50, - height=50, - bgcolor=colors.GREEN, - border_radius=5, - ), - ), - ] - ), - Container(width=100), - DragTarget( - group="color", - content=Container( - width=50, - height=50, - bgcolor=colors.BLUE_GREY_100, - border_radius=5, - ), - on_will_accept=drag_will_accept, - on_accept=drag_accept, - on_leave=drag_leave, - ), - ] - ) - ) - - - flet.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/draggable - """ - - def __init__( - self, - content: Control, - group: Optional[str] = None, - content_when_dragging: Optional[Control] = None, - content_feedback: Optional[Control] = None, - axis: Optional[Axis] = None, - affinity: Optional[Axis] = None, - max_simultaneous_drags: Optional[int] = None, - on_drag_start: OptionalControlEventCallable = None, - on_drag_complete: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.group = group - self.content = content - self.content_when_dragging = content_when_dragging - self.content_feedback = content_feedback - self.on_drag_start = on_drag_start - self.on_drag_complete = on_drag_complete - self.axis = axis - self.affinity = affinity - self.max_simultaneous_drags = max_simultaneous_drags - - def _get_control_name(self): - return "draggable" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - children = [self.__content] - if self.__content_when_dragging: - self.__content_when_dragging._set_attr_internal( - "n", "content_when_dragging" - ) - children.append(self.__content_when_dragging) - if self.__content_feedback: - self.__content_feedback._set_attr_internal("n", "content_feedback") - children.append(self.__content_feedback) - return children - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - # group - @property - def group(self) -> Optional[str]: - return self._get_attr("group") - - @group.setter - def group(self, value: Optional[str]): - self._set_attr("group", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # content_when_dragging - @property - def content_when_dragging(self) -> Optional[Control]: - return self.__content_when_dragging - - @content_when_dragging.setter - def content_when_dragging(self, value: Optional[Control]): - self.__content_when_dragging = value - - # content_feedback - @property - def content_feedback(self) -> Optional[Control]: - return self.__content_feedback - - @content_feedback.setter - def content_feedback(self, value: Optional[Control]): - self.__content_feedback = value - - # max_simultaneous_drags - @property - def max_simultaneous_drags(self) -> Optional[int]: - return self._get_attr("maxSimultaneousDrags") - - @max_simultaneous_drags.setter - def max_simultaneous_drags(self, value: Optional[int]): - self._set_attr("maxSimultaneousDrags", value) - - # axis - @property - def axis(self) -> Optional[Axis]: - return self.__axis - - @axis.setter - def axis(self, value: Optional[Axis]): - self.__axis = value - self._set_enum_attr("axis", value, Axis) - - # affinity - @property - def affinity(self) -> Optional[Axis]: - return self.__affinity - - @affinity.setter - def affinity(self, value: Optional[Axis]): - self.__affinity = value - self._set_enum_attr("affinity", value, Axis) - - # on_drag_start - @property - def on_drag_start(self) -> OptionalControlEventCallable: - return self._get_event_handler("dragStart") - - @on_drag_start.setter - def on_drag_start(self, handler: OptionalControlEventCallable): - self._add_event_handler("dragStart", handler) - - # on_drag_complete - @property - def on_drag_complete(self) -> OptionalControlEventCallable: - return self._get_event_handler("dragComplete") - - @on_drag_complete.setter - def on_drag_complete(self, handler: OptionalControlEventCallable): - self._add_event_handler("dragComplete", handler) diff --git a/sdk/python/packages/flet/src/flet/core/dropdown.py b/sdk/python/packages/flet/src/flet/core/dropdown.py deleted file mode 100644 index 5ea85160be..0000000000 --- a/sdk/python/packages/flet/src/flet/core/dropdown.py +++ /dev/null @@ -1,600 +0,0 @@ -import time -import warnings -from typing import Any, Dict, List, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.buttons import ButtonStyle -from flet.core.control import Control, OptionalNumber -from flet.core.form_field_control import FormFieldControl, InputBorder -from flet.core.menu_bar import MenuStyle -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.textfield import InputFilter, TextCapitalization -from flet.core.types import ( - BorderRadiusValue, - ColorValue, - ControlState, - ControlStateValue, - IconEnums, - IconValueOrControl, - Number, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - TextAlign, -) - - -class Option(Control): - def __init__( - self, - key: Optional[str] = None, - text: Optional[str] = None, - content: Optional[Control] = None, - leading_icon: Optional[IconValueOrControl] = None, - trailing_icon: Optional[IconValueOrControl] = None, - style: Optional[ButtonStyle] = None, - alignment: Optional[Alignment] = None, # to be deprecated - text_style: Optional[TextStyle] = None, # to be deprecated - on_click: OptionalControlEventCallable = None, # to be deprecated - # - # Control - # - ref=None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, disabled=disabled, visible=visible, data=data) - self.key = key - self.text = text - self.content = content - self.leading_icon = leading_icon - self.trailing_icon = trailing_icon - self.style = style - - deprecated_properties_list = ["text_style", "on_click", "alignment"] - - for item in deprecated_properties_list: - if eval(item) is not None: - warnings.warn( - f"{item} is deprecated since version 0.27.0 " - f"and will be removed in version 0.30.0.", - category=DeprecationWarning, - stacklevel=2, - ) - - def _get_control_name(self): - return "dropdownoption" - - def _get_children(self): - children = super()._get_children() - if isinstance(self.__leading_icon, Control): - self.__leading_icon._set_attr_internal("n", "leadingIcon") - children.append(self.__leading_icon) - if isinstance(self.__trailing_icon, Control): - self.__trailing_icon._set_attr_internal("n", "trailing_icon") - children.append(self.__trailing_icon) - if isinstance(self.__content, Control): - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - def before_update(self): - super().before_update() - assert ( - self.key is not None or self.text is not None - ), "key or text must be specified" - self._set_attr_json("style", self.__style) - - # key - @property - def key(self) -> Optional[str]: - return self._get_attr("key") - - @key.setter - def key(self, value: Optional[str]): - self._set_attr("key", value) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # leading_icon - @property - def leading_icon(self) -> Optional[IconValueOrControl]: - return self.__leading_icon - - @leading_icon.setter - def leading_icon(self, value: Optional[IconValueOrControl]): - self.__leading_icon = value - if not isinstance(value, Control): - self._set_enum_attr("leadingIcon", value, IconEnums) - - # trailing_icon - @property - def trailing_icon(self) -> Optional[IconValueOrControl]: - return self.__trailing_icon - - @trailing_icon.setter - def trailing_icon(self, value: Optional[IconValueOrControl]): - self.__trailing_icon = value - if not isinstance(value, Control): - self._set_enum_attr("trailingIcon", value, IconEnums) - - -DropdownOption = Option - - -class Dropdown(FormFieldControl): - """ - A dropdown control that allows users to select a single option from a list of options. - ----- - Online docs: https://flet.dev/docs/controls/dropdown - """ - - def __init__( - self, - value: Optional[str] = None, - autofocus: Optional[bool] = None, - text_align: Optional[TextAlign] = None, - elevation: ControlStateValue[OptionalNumber] = None, - options: Optional[List[Option]] = None, - label_content: Optional[str] = None, - enable_filter: Optional[bool] = None, - enable_search: Optional[bool] = None, - editable: Optional[bool] = None, - max_menu_height: OptionalNumber = None, # to be discontinued - menu_height: OptionalNumber = None, - menu_width: OptionalNumber = None, - expanded_insets: PaddingValue = None, - selected_suffix: Optional[Control] = None, - input_filter: Optional[InputFilter] = None, - capitalization: Optional[TextCapitalization] = None, - options_fill_horizontally: Optional[bool] = None, # to be deprecated - padding: Optional[PaddingValue] = None, # to be deprecated - trailing_icon: Optional[IconValueOrControl] = None, - leading_icon: Optional[IconValueOrControl] = None, - select_icon: Optional[IconValueOrControl] = None, # to be deprecated - selected_trailing_icon: Optional[IconValueOrControl] = None, - on_change: OptionalEventCallable = None, - on_focus: OptionalEventCallable = None, - on_blur: OptionalEventCallable = None, - enable_feedback: Optional[bool] = None, # to be deprecated - item_height: OptionalNumber = None, # to be deprecated - alignment: Optional[Alignment] = None, # to be deprecated - hint_content: Optional[Control] = None, # to be deprecated - icon_content: Optional[Control] = None, # to be deprecated - select_icon_size: OptionalNumber = None, # to be deprecated - icon_size: OptionalNumber = None, # to be deprecated - select_icon_enabled_color: Optional[ColorValue] = None, # to be deprecated - icon_enabled_color: Optional[ColorValue] = None, # to be deprecated - select_icon_disabled_color: Optional[ColorValue] = None, # to be deprecated - icon_disabled_color: Optional[ColorValue] = None, # to be deprecated - # - # FormField specific - # - bgcolor: Optional[ColorValue] = None, - error_style: Optional[TextStyle] = None, - error_text: Optional[str] = None, - text_size: OptionalNumber = None, - text_style: Optional[TextStyle] = None, - label: Optional[str] = None, - label_style: Optional[TextStyle] = None, - icon: Optional[IconValueOrControl] = None, # to deprecated - border: Optional[InputBorder] = None, - color: Optional[str] = None, - focused_color: Optional[str] = None, # to be deprecated - focused_bgcolor: Optional[str] = None, # to be deprecated - border_width: OptionalNumber = None, - border_color: Optional[str] = None, - border_radius: Optional[BorderRadiusValue] = None, - focused_border_width: OptionalNumber = None, - focused_border_color: Optional[str] = None, - content_padding: PaddingValue = None, - dense: Optional[bool] = None, - filled: Optional[bool] = None, - fill_color: Optional[str] = None, - hover_color: Optional[str] = None, - hint_text: Optional[str] = None, - hint_style: Optional[TextStyle] = None, - helper_text: Optional[str] = None, - helper_style: Optional[TextStyle] = None, - prefix: Optional[Control] = None, # to be deprecated - prefix_text: Optional[str] = None, # to be deprecated - prefix_style: Optional[TextStyle] = None, # to be deprecated - prefix_icon: Optional[str] = None, # to be deprecated - disabled_hint_content: Optional[Control] = None, # to be deprecated - suffix: Optional[Control] = None, # to be deprecated - suffix_icon: Optional[IconValueOrControl] = None, # to be deprecated - suffix_text: Optional[str] = None, # to be deprecated - suffix_style: Optional[TextStyle] = None, # to be deprecated - counter: Optional[Control] = None, # to be deprecated - counter_text: Optional[str] = None, # to be deprecated - counter_style: Optional[TextStyle] = None, # to be deprecated - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: RotateValue = None, - scale: ScaleValue = None, - offset: OffsetValue = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: AnimationValue = None, - animate_size: AnimationValue = None, - animate_position: AnimationValue = None, - animate_rotation: AnimationValue = None, - animate_scale: AnimationValue = None, - animate_offset: AnimationValue = None, - on_animation_end: OptionalEventCallable = None, - tooltip: Optional[str] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - FormFieldControl.__init__( - self, - text_size=text_size, - text_style=text_style, - label=label, - label_style=label_style, - border=border, - color=color, - border_width=border_width, - border_color=border_color, - border_radius=border_radius, - focused_border_width=focused_border_width, - focused_border_color=focused_border_color, - content_padding=content_padding, - dense=dense, - filled=filled, - fill_color=fill_color, - hover_color=hover_color, - hint_text=hint_text, - hint_style=hint_style, - helper_text=helper_text, - helper_style=helper_style, - error_text=error_text, - error_style=error_style, - prefix_icon=prefix_icon, - ref=ref, - key=key, - width=width, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - deprecated_properties_list = [ - "select_icon_size", - "select_icon_enabled_color", - "select_icon_disabled_color", - "suffix", - "suffix_icon", - "suffix_style", - "suffix_text", - "icon_content", - "icon_enabled_color", - "icon_disabled_color", - "icon_size", - "icon", - "hint_content", - "prefix_text", - "prefix_style", - "prefix", - "prefix_icon", - "focused_color", - "disabled_hint_content", - "alignment", - "focused_bgcolor", - "item_height", - "enable_feedback", - "options_fill_horizontally", - "padding", - "max_menu_height", - ] - - for item in deprecated_properties_list: - if eval(item) is not None: - warnings.warn( - f"{item} is deprecated since version 0.27.0 " - f"and will be removed in version 0.30.0.", - category=DeprecationWarning, - stacklevel=2, - ) - - self.options = options - self.selected_suffix = selected_suffix - self.input_filter = input_filter - self.enable_filter = enable_filter - self.enable_search = enable_search - self.editable = editable - self.menu_height = menu_height - self.menu_width = menu_width - self.expanded_insets = expanded_insets - self.capitalization = capitalization - self.label_content = label_content - self.leading_icon = leading_icon - self.trailing_icon = trailing_icon - self.selected_trailing_icon = selected_trailing_icon - self.select_icon = select_icon - self.on_change = on_change - self.on_focus = on_focus - self.on_blur = on_blur - self.value = value - self.bgcolor = bgcolor - self.elevation = elevation - self.text_align = text_align - self.autofocus = autofocus - - def _get_control_name(self): - return "dropdown" - - def before_update(self): - super().before_update() - self._set_attr_json("bgcolor", self.__bgcolor, wrap_attr_dict=True) - self._set_attr_json("elevation", self.__elevation, wrap_attr_dict=True) - ##self._set_attr_json("inputFilter", self.__input_filter) - ##self._set_attr_json("expandInsets", self.__expanded_insets) - self.expand_loose = self.expand # to fix a display issue - - def _get_children(self): - children = FormFieldControl._get_children(self) + self.__options - if isinstance(self.__leading_icon, Control): - self.__leading_icon._set_attr_internal("n", "leading_icon") - children.append(self.__leading_icon) - if isinstance(self.__select_icon, Control): - self.__select_icon._set_attr_internal("n", "select_icon") - children.append(self.__select_icon) - if isinstance(self.__trailing_icon, Control): - self.__trailing_icon._set_attr_internal("n", "trailing_icon") - children.append(self.__trailing_icon) - if isinstance(self.__selected_trailing_icon, Control): - self.__selected_trailing_icon._set_attr_internal( - "n", "selected_trailing_icon" - ) - children.append(self.__selected_trailing_icon) - return children - - def __contains__(self, item): - return item in self.__options - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # options - @property - def options(self) -> Optional[List[Option]]: - return self.__options - - @options.setter - def options(self, value: Optional[List[Option]]): - self.__options = value if value is not None else [] - - # menu_height - @property - def menu_height(self) -> OptionalNumber: - return self._get_attr("menuHeight", data_type="float") - - @menu_height.setter - def menu_height(self, value: OptionalNumber): - self._set_attr("menuHeight", value) - - # menu_width - @property - def menu_width(self) -> OptionalNumber: - return self._get_attr("menuWidth", data_type="float") - - @menu_width.setter - def menu_width(self, value: OptionalNumber): - self._set_attr("menuWidth", value) - - # editable - @property - def editable(self) -> bool: - return self._get_attr("editable", data_type="bool", def_value=False) - - @editable.setter - def editable(self, value: Optional[bool]): - self._set_attr("editable", value) - - # select_icon - @property - def select_icon(self) -> Optional[IconValueOrControl]: - warnings.warn( - f"select_icon is deprecated since version 0.27.0 " - f"and will be removed in version 0.30.0. Use trailing_icon instead.", - category=DeprecationWarning, - stacklevel=2, - ) - return self.__select_icon - - @select_icon.setter - def select_icon(self, value: Optional[IconValueOrControl]): - self.__select_icon = value - - if not isinstance(value, Control): - self._set_enum_attr("selectIcon", value, IconEnums) - - if value is not None: - warnings.warn( - f"select_icon is deprecated since version 0.27.0 " - f"and will be removed in version 0.30.0. Use trailing_icon instead.", - category=DeprecationWarning, - stacklevel=2, - ) - - # leading_icon - @property - def leading_icon(self) -> Optional[IconValueOrControl]: - return self.__leading_icon - - @leading_icon.setter - def leading_icon(self, value: Optional[IconValueOrControl]): - self.__leading_icon = value - if not isinstance(value, Control): - self._set_enum_attr("leadingIcon", value, IconEnums) - - # trailing_icon - @property - def trailing_icon(self) -> Optional[IconValueOrControl]: - return self.__trailing_icon - - @trailing_icon.setter - def trailing_icon(self, value: Optional[IconValueOrControl]): - self.__trailing_icon = value - if not isinstance(value, Control): - self._set_enum_attr("trailingIcon", value, IconEnums) - - # selected_trailing_icon - @property - def selected_trailing_icon(self) -> Optional[IconValueOrControl]: - return self.__selected_trailing_icon - - @selected_trailing_icon.setter - def selected_trailing_icon(self, value: Optional[IconValueOrControl]): - self.__selected_trailing_icon = value - if not isinstance(value, Control): - self._set_enum_attr("selectedTrailingIcon", value, IconEnums) - - # bgcolor - @property - def bgcolor(self) -> ControlStateValue[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: ControlStateValue[ColorValue]): - self.__bgcolor = value - - # text_align - @property - def text_align(self) -> Optional[TextAlign]: - return self.__text_align - - @text_align.setter - def text_align(self, value: Optional[TextAlign]): - self.__text_align = value - self._set_enum_attr("textAlign", value, TextAlign) - - # elevation - @property - def elevation(self) -> Union[OptionalNumber, Dict[ControlState, Number]]: - return self.__elevation - - @elevation.setter - def elevation(self, value: Union[OptionalNumber, Dict[ControlState, Number]]): - self.__elevation = value - - # enable_filter - @property - def enable_filter(self) -> bool: - return self._get_attr("enableFilter", data_type="bool", def_value=False) - - @enable_filter.setter - def enable_filter(self, value: Optional[bool]): - self._set_attr("enableFilter", value) - - # enable_search - @property - def enable_search(self) -> bool: - return self._get_attr("enableSearch", data_type="bool", def_value=True) - - @enable_search.setter - def enable_search(self, value: Optional[bool]): - self._set_attr("enableSearch", value) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/dropdownm2.py b/sdk/python/packages/flet/src/flet/core/dropdownm2.py deleted file mode 100644 index db4d0ca48b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/dropdownm2.py +++ /dev/null @@ -1,594 +0,0 @@ -import time -import warnings -from typing import Any, List, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxConstraints -from flet.core.control import Control, OptionalNumber -from flet.core.form_field_control import FormFieldControl, InputBorder -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - ColorEnums, - ColorValue, - DurationValue, - IconEnums, - IconValueOrControl, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Option(Control): - def __init__( - self, - key: Optional[str] = None, - text: Optional[str] = None, - content: Optional[Control] = None, - alignment: Optional[Alignment] = None, - text_style: Optional[TextStyle] = None, - on_click: OptionalControlEventCallable = None, - # - # Control - # - ref=None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, disabled=disabled, visible=visible, data=data) - self.key = key - self.text = text - self.content = content - self.on_click = on_click - self.alignment = alignment - self.text_style = text_style - - def _get_control_name(self): - return "dropdownoption" - - def _get_children(self): - children = [] - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - def before_update(self): - super().before_update() - assert ( - self.key is not None or self.text is not None - ), "key or text must be specified" - self._set_attr_json("alignment", self.__alignment) - if isinstance(self.__text_style, TextStyle): - self._set_attr_json("textStyle", self.__text_style) - - # key - @property - def key(self) -> Optional[str]: - return self._get_attr("key") - - @key.setter - def key(self, value: Optional[str]): - self._set_attr("key", value) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # text_style - @property - def text_style(self) -> Optional[TextStyle]: - return self.__text_style - - @text_style.setter - def text_style(self, value: Optional[TextStyle]): - self.__text_style = value - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - -class DropdownM2(FormFieldControl): - """ - A dropdown lets the user select from a number of items. The dropdown shows the currently selected item as well as an arrow that opens a menu for selecting another item. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def button_clicked(e): - t.value = f"Dropdown value is: {dd.value}" - page.update() - - t = ft.Text() - b = ft.ElevatedButton(text="Submit", on_click=button_clicked) - dd = ft.DropdownM2( - width=200, - options=[ - ft.dropdown.Option("Red"), - ft.dropdown.Option("Green"), - ft.dropdown.Option("Blue"), - ], - ) - page.add(dd, b, t) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/dropdown - """ - - def __init__( - self, - value: Optional[str] = None, - options: Optional[List[Option]] = None, - alignment: Optional[Alignment] = None, - autofocus: Optional[bool] = None, - hint_content: Optional[Control] = None, - select_icon: Optional[IconValueOrControl] = None, - elevation: OptionalNumber = None, - item_height: OptionalNumber = None, - max_menu_height: OptionalNumber = None, - select_icon_size: OptionalNumber = None, - enable_feedback: Optional[bool] = None, - padding: Optional[PaddingValue] = None, - select_icon_enabled_color: Optional[ColorValue] = None, - select_icon_disabled_color: Optional[ColorValue] = None, - options_fill_horizontally: Optional[bool] = None, - disabled_hint_content: Optional[Control] = None, - on_change: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - on_click: OptionalControlEventCallable = None, - # - # FormField specific - # - text_size: OptionalNumber = None, - text_style: Optional[TextStyle] = None, - label: Optional[Union[str, Control]] = None, - label_style: Optional[TextStyle] = None, - icon: Optional[IconValueOrControl] = None, - border: Optional[InputBorder] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - border_radius: Optional[BorderRadiusValue] = None, - border_width: OptionalNumber = None, - border_color: Optional[ColorValue] = None, - focused_color: Optional[ColorValue] = None, - focused_bgcolor: Optional[ColorValue] = None, - focused_border_width: OptionalNumber = None, - focused_border_color: Optional[ColorValue] = None, - content_padding: Optional[PaddingValue] = None, - dense: Optional[bool] = None, - filled: Optional[bool] = None, - fill_color: Optional[ColorValue] = None, - hint_text: Optional[str] = None, - hint_style: Optional[TextStyle] = None, - helper: Optional[Control] = None, - helper_text: Optional[str] = None, - helper_style: Optional[TextStyle] = None, - counter: Optional[Control] = None, - counter_text: Optional[str] = None, - counter_style: Optional[TextStyle] = None, - error: Optional[Control] = None, - error_text: Optional[str] = None, - error_style: Optional[TextStyle] = None, - prefix: Optional[Control] = None, - prefix_icon: Optional[IconValueOrControl] = None, - prefix_text: Optional[str] = None, - prefix_style: Optional[TextStyle] = None, - suffix: Optional[Control] = None, - suffix_icon: Optional[IconValueOrControl] = None, - suffix_text: Optional[str] = None, - suffix_style: Optional[TextStyle] = None, - focus_color: Optional[ColorValue] = None, - align_label_with_hint: Optional[bool] = None, - hint_fade_duration: Optional[DurationValue] = None, - hint_max_lines: Optional[int] = None, - helper_max_lines: Optional[int] = None, - error_max_lines: Optional[int] = None, - prefix_icon_size_constraints: Optional[BoxConstraints] = None, - suffix_icon_size_constraints: Optional[BoxConstraints] = None, - size_constraints: Optional[BoxConstraints] = None, - collapsed: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - FormFieldControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - # - # FormField specific - # - text_size=text_size, - text_style=text_style, - label=label, - label_style=label_style, - icon=icon, - border=border, - color=color, - bgcolor=bgcolor, - border_radius=border_radius, - border_width=border_width, - border_color=border_color, - focused_color=focused_color, - focused_bgcolor=focused_bgcolor, - focused_border_width=focused_border_width, - focused_border_color=focused_border_color, - content_padding=content_padding, - dense=dense, - filled=filled, - fill_color=fill_color, - hint_text=hint_text, - hint_style=hint_style, - helper_text=helper_text, - helper=helper, - helper_style=helper_style, - counter=counter, - counter_text=counter_text, - counter_style=counter_style, - error=error, - error_text=error_text, - error_style=error_style, - prefix=prefix, - prefix_icon=prefix_icon, - prefix_text=prefix_text, - prefix_style=prefix_style, - suffix=suffix, - suffix_icon=suffix_icon, - suffix_text=suffix_text, - suffix_style=suffix_style, - focus_color=focus_color, - align_label_with_hint=align_label_with_hint, - hint_fade_duration=hint_fade_duration, - hint_max_lines=hint_max_lines, - helper_max_lines=helper_max_lines, - error_max_lines=error_max_lines, - prefix_icon_size_constraints=prefix_icon_size_constraints, - suffix_icon_size_constraints=suffix_icon_size_constraints, - size_constraints=size_constraints, - collapsed=collapsed, - ) - - self.value = value - self.autofocus = autofocus - self.options = options - self.alignment = alignment - self.elevation = elevation - self.hint_content = hint_content - self.disabled_hint_content = disabled_hint_content - self.select_icon = select_icon - self.padding = padding - self.enable_feedback = enable_feedback - self.on_focus = on_focus - self.on_blur = on_blur - self.on_change = on_change - self.item_height = item_height - self.max_menu_height = max_menu_height - self.select_icon_size = select_icon_size - self.select_icon_enabled_color = select_icon_enabled_color - self.select_icon_disabled_color = select_icon_disabled_color - - self.on_click = on_click - self.options_fill_horizontally = options_fill_horizontally - - warnings.warn( - f"DropdownM2 control is deprecated since version 0.27.0 " - f"and will be removed in version 0.30.0. User Dropdown control instead", - category=DeprecationWarning, - stacklevel=2, - ) - - def _get_control_name(self): - return "dropdownm2" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - self._set_attr_json("alignment", self.__alignment) - if ( - ( - self.bgcolor is not None - or self.fill_color is not None - or self.focused_bgcolor is not None - ) - ) and self.filled is None: - self.filled = True # required to display any of the above colors - - def _get_children(self): - children = FormFieldControl._get_children(self) + self.__options - if isinstance(self.__hint_content, Control): - self.__hint_content._set_attr_internal("n", "hint") - children.append(self.__hint_content) - if isinstance(self.__select_icon, Control): - self.__select_icon._set_attr_internal("n", "selectIcon") - children.append(self.__select_icon) - if isinstance(self.__disabled_hint_content, Control): - self.__disabled_hint_content._set_attr_internal("n", "disabled_hint") - children.append(self.__disabled_hint_content) - return children - - def __contains__(self, item): - return item in self.__options - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # options - @property - def options(self): - return self.__options - - @options.setter - def options(self, value): - self.__options = value if value is not None else [] - - # select_icon - @property - def select_icon(self) -> Optional[IconValueOrControl]: - return self.__select_icon - - @select_icon.setter - def select_icon(self, value: Optional[IconValueOrControl]): - self.__select_icon = value - if not isinstance(value, Control): - self._set_enum_attr("selectIcon", value, IconEnums) - - # hint_content - @property - def hint_content(self) -> Optional[Control]: - return self.__hint_content - - @hint_content.setter - def hint_content(self, value: Optional[Control]): - self.__hint_content = value - - # disabled_hint_content - @property - def disabled_hint_content(self) -> Optional[Control]: - return self.__disabled_hint_content - - @disabled_hint_content.setter - def disabled_hint_content(self, value: Optional[Control]): - self.__disabled_hint_content = value - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # select_icon_enabled_color - @property - def select_icon_enabled_color(self) -> Optional[ColorValue]: - return self.__select_icon_enabled_color - - @select_icon_enabled_color.setter - def select_icon_enabled_color(self, value: Optional[ColorValue]): - self.__select_icon_enabled_color = value - self._set_enum_attr("selectIconEnabledColor", value, ColorEnums) - - # select_icon_disabled_color - @property - def select_icon_disabled_color(self) -> Optional[ColorValue]: - return self.__select_icon_disabled_color - - @select_icon_disabled_color.setter - def select_icon_disabled_color(self, value: Optional[ColorValue]): - self.__select_icon_disabled_color = value - self._set_enum_attr("selectIconDisabledColor", value, ColorEnums) - - # item_height - @property - def item_height(self) -> OptionalNumber: - return self._get_attr("itemHeight", data_type="float") - - @item_height.setter - def item_height(self, value: OptionalNumber): - assert ( - value is None or value >= 48.0 - ), "item_height must be greater than or equal to 48.0" - self._set_attr("itemHeight", value) - - # max_menu_height - @property - def max_menu_height(self) -> OptionalNumber: - return self._get_attr("maxMenuHeight", data_type="float") - - @max_menu_height.setter - def max_menu_height(self, value: OptionalNumber): - self._set_attr("maxMenuHeight", value) - - # select_icon_size - @property - def select_icon_size(self) -> float: - return self._get_attr("selectIconSize", data_type="float", def_value=24.0) - - @select_icon_size.setter - def select_icon_size(self, value: OptionalNumber): - self._set_attr("selectIconSize", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # options_fill_horizontally - @property - def options_fill_horizontally(self) -> bool: - return self._get_attr( - "optionsFillHorizontally", data_type="bool", def_value=False - ) - - @options_fill_horizontally.setter - def options_fill_horizontally(self, value: Optional[bool]): - self._set_attr("optionsFillHorizontally", value) - - # enable_feedback - @property - def enable_feedback(self) -> bool: - return self._get_attr("enableFeedback", data_type="bool", def_value=True) - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # elevation - @property - def elevation(self) -> float: - return self._get_attr("elevation", data_type="float", def_value=8.0) - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) diff --git a/sdk/python/packages/flet/src/flet/core/elevated_button.py b/sdk/python/packages/flet/src/flet/core/elevated_button.py deleted file mode 100644 index a05f2792f8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/elevated_button.py +++ /dev/null @@ -1,344 +0,0 @@ -import time -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, -) - - -class ElevatedButton(ConstrainedControl, AdaptiveControl): - """ - Elevated buttons are essentially filled tonal buttons with a shadow. To prevent shadow creep, only use them when absolutely necessary, such as when the button requires visual separation from a patterned background. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Basic elevated buttons" - page.add( - ft.ElevatedButton(text="Elevated button"), - ft.ElevatedButton("Disabled button", disabled=True), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/elevatedbutton - """ - - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - icon_color: Optional[ColorValue] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - content: Optional[Control] = None, - elevation: OptionalNumber = None, - style: Optional[ButtonStyle] = None, - autofocus: Optional[bool] = None, - clip_behavior: Optional[ClipBehavior] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - on_click: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.text = text - self.color = color - self.bgcolor = bgcolor - self.elevation = elevation - self.style = style - self.icon = icon - self.icon_color = icon_color - self.content = content - self.autofocus = autofocus - self.url = url - self.url_target = url_target - self.on_click = on_click - self.on_long_press = on_long_press - self.on_hover = on_hover - self.on_focus = on_focus - self.on_blur = on_blur - self.clip_behavior = clip_behavior - - def _get_control_name(self): - return "elevatedbutton" - - def before_update(self): - super().before_update() - assert ( - self.text or self.icon or (self.__content and self.__content.visible) - ), "at minimum, text, icon or a visible content must be provided" - style = self.__style or ButtonStyle() - if self.__color is not None: - style.color = self.__color - if self.__bgcolor is not None: - style.bgcolor = self.__bgcolor - if self.__elevation is not None: - style.elevation = self.__elevation - - style.side = self._wrap_attr_dict(style.side) - style.shape = self._wrap_attr_dict(style.shape) - style.padding = self._wrap_attr_dict(style.padding) - style.text_style = self._wrap_attr_dict(style.text_style) - self._set_attr_json("style", style) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self.__elevation - - @elevation.setter - def elevation(self, value: OptionalNumber): - self.__elevation = value - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # on_click - @property - def on_click(self): - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler): - self._add_event_handler("click", handler) - - # on_long_press - @property - def on_long_press(self): - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # on_hover - @property - def on_hover(self) -> OptionalControlEventCallable: - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - self._set_attr("onHover", True if handler is not None else None) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/embed_json_encoder.py b/sdk/python/packages/flet/src/flet/core/embed_json_encoder.py deleted file mode 100644 index fdf0cd6e07..0000000000 --- a/sdk/python/packages/flet/src/flet/core/embed_json_encoder.py +++ /dev/null @@ -1,81 +0,0 @@ -import enum -import json -from typing import Dict - -from flet.core.border import Border, BorderSide -from flet.core.border_radius import BorderRadius -from flet.core.box import BoxConstraints -from flet.core.margin import Margin -from flet.core.padding import Padding - - -class EmbedJsonEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, BorderSide): - obj_as_dict = { - "w": obj.width, - "c": obj.color, - "sa": obj.stroke_align, - } - elif isinstance(obj, Border): - obj_as_dict = { - "l": obj.left, - "t": obj.top, - "r": obj.right, - "b": obj.bottom, - } - elif isinstance(obj, BorderRadius): - obj_as_dict = { - "bl": obj.bottom_left, - "br": obj.bottom_right, - "tl": obj.top_left, - "tr": obj.top_right, - } - elif isinstance(obj, (Margin, Padding)): - obj_as_dict = { - "l": obj.left, - "t": obj.top, - "r": obj.right, - "b": obj.bottom, - } - elif isinstance(obj, BoxConstraints): - obj_as_dict = { - "min_width": obj.min_width, - "max_width": obj.max_width, - "min_height": obj.min_height, - "max_height": obj.max_height, - } - else: - obj_as_dict = self._convert_enums(obj.__dict__) - - # Convert inf to string "inf" to avoid JSON serialization error - for key, value in obj_as_dict.items(): - if value == float("inf"): - obj_as_dict[key] = "inf" - - return obj_as_dict - - def encode(self, o): - return super().encode(self._convert_enums(o)) - - def _convert_enums(self, obj): - if isinstance(obj, Dict): - return dict( - map( - lambda item: ( - self._convert_enums( - item[0] - if not isinstance(item[0], enum.Enum) - else item[0].value - ), - self._convert_enums( - item[1] - if not isinstance(item[1], enum.Enum) - else item[1].value - ), - ), - filter(lambda item: item[1] is not None, obj.items()), - ) - ) - else: - return obj diff --git a/sdk/python/packages/flet/src/flet/core/event.py b/sdk/python/packages/flet/src/flet/core/event.py deleted file mode 100644 index 0c7235b751..0000000000 --- a/sdk/python/packages/flet/src/flet/core/event.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Optional - - -class Event: - def __init__(self, target: str, name: str, data: Optional[str]): - self.target = target - self.name = name - self.data = data - - def __repr__(self): - attrs = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items()) - return f"{self.__class__.__name__}({attrs})" - - def __str__(self): - attrs = ", ".join( - f"{k}={v!r}" - for k, v in self.__dict__.items() - if k not in ["control", "page", "target", "data"] # ignore these keys - ) - return f"{self.__class__.__name__}({attrs}, data={self.data!r})" # reinsert data as last arg diff --git a/sdk/python/packages/flet/src/flet/core/event_handler.py b/sdk/python/packages/flet/src/flet/core/event_handler.py deleted file mode 100644 index 3f5c9a143b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/event_handler.py +++ /dev/null @@ -1,31 +0,0 @@ -import asyncio - -from flet.core.control_event import ControlEvent -from flet.core.types import OptionalControlEventCallable - - -class EventHandler: - def __init__(self, result_converter=None) -> None: - self.__result_converter = result_converter - self.handler: OptionalControlEventCallable = None - - def get_handler(self): - async def fn(e: ControlEvent): - if self.handler is not None: - ce = e - if self.__result_converter is not None: - ce = self.__result_converter(e) - if ce is not None: - ce.target = e.target - ce.name = e.name - ce.data = e.data - ce.control = e.control - ce.page = e.page - - if ce is not None: - if asyncio.iscoroutinefunction(self.handler): - await self.handler(ce) - else: - e.page.run_thread(self.handler, ce) - - return fn diff --git a/sdk/python/packages/flet/src/flet/core/exceptions.py b/sdk/python/packages/flet/src/flet/core/exceptions.py deleted file mode 100644 index 6bab820981..0000000000 --- a/sdk/python/packages/flet/src/flet/core/exceptions.py +++ /dev/null @@ -1,19 +0,0 @@ -class FletException(Exception): - pass - - -class FletUnsupportedPlatformException(FletException): - """ - Thrown by operations that are not supported on the current platform. - """ - - def __init__(self, message: str): - super().__init__(message) - - -class FletUnimplementedPlatformEception(FletUnsupportedPlatformException): - """ - Thrown by operations that have not been implemented yet. - """ - - pass diff --git a/sdk/python/packages/flet/src/flet/core/expansion_panel.py b/sdk/python/packages/flet/src/flet/core/expansion_panel.py deleted file mode 100644 index 37cc9a3d08..0000000000 --- a/sdk/python/packages/flet/src/flet/core/expansion_panel.py +++ /dev/null @@ -1,361 +0,0 @@ -from typing import Any, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class ExpansionPanel(ConstrainedControl, AdaptiveControl): - """ - A material expansion panel. It can either be expanded or collapsed. Its body is only visible when it is expanded. - - ----- - - Online docs: https://flet.dev/docs/controls/expansionpanel - """ - - def __init__( - self, - header: Optional[Control] = None, - content: Optional[Control] = None, - bgcolor: Optional[ColorValue] = None, - expanded: Optional[bool] = None, - can_tap_header: Optional[bool] = None, - splash_color: Optional[ColorValue] = None, - highlight_color: Optional[ColorValue] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - # - # Adaptive - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.header = header - self.content = content - self.bgcolor = bgcolor - self.expanded = expanded - self.can_tap_header = can_tap_header - self.splash_color = splash_color - self.highlight_color = highlight_color - - def _get_control_name(self): - return "expansionpanel" - - def before_update(self): - super().before_update() - - def _get_children(self): - children = [] - if self.__header: - self.__header._set_attr_internal("n", "header") - children.append(self.__header) - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # splash_color - @property - def splash_color(self) -> Optional[ColorValue]: - - return self.__splash_color - - @splash_color.setter - def splash_color(self, value: Optional[ColorValue]): - self.__splash_color = value - self._set_enum_attr("splashColor", value, ColorEnums) - - # highlight_color - @property - def highlight_color(self) -> Optional[ColorValue]: - return self.__highlight_color - - @highlight_color.setter - def highlight_color(self, value: Optional[ColorValue]): - self.__highlight_color = value - self._set_enum_attr("highlightColor", value, ColorEnums) - - # expanded - @property - def expanded(self) -> bool: - return self._get_attr("expanded", data_type="bool", def_value=False) - - @expanded.setter - def expanded(self, value: Optional[bool]): - self._set_attr("expanded", value) - - # can_tap_header - @property - def can_tap_header(self) -> bool: - return self._get_attr("canTapHeader", data_type="bool", def_value=False) - - @can_tap_header.setter - def can_tap_header(self, value: Optional[bool]): - self._set_attr("canTapHeader", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # header - @property - def header(self) -> Optional[Control]: - return self.__header - - @header.setter - def header(self, value: Optional[Control]): - self.__header = value - - -class ExpansionPanelList(ConstrainedControl): - """ - A material expansion panel list that lays out its children and animates expansions. - - ----- - - Online docs: https://flet.dev/docs/controls/expansionpanellist - """ - - def __init__( - self, - controls: Optional[Sequence[ExpansionPanel]] = None, - divider_color: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - expanded_header_padding: Optional[PaddingValue] = None, - expand_icon_color: Optional[ColorValue] = None, - spacing: OptionalNumber = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - self.controls = controls - self.divider_color = divider_color - self.expanded_icon_color = expand_icon_color - self.expanded_header_padding = expanded_header_padding - self.elevation = elevation - self.spacing = spacing - self.on_change = on_change - - def _get_control_name(self): - return "expansionpanellist" - - def before_update(self): - super().before_update() - self._set_attr_json("expandedHeaderPadding", self.__expanded_header_padding) - - def _get_children(self): - children = [] - for c in self.__controls: - c._set_attr_internal("n", "expansionpanel") - children.append(c) - return children - - # divider_color - @property - def divider_color(self) -> Optional[ColorValue]: - return self.__divider_color - - @divider_color.setter - def divider_color(self, value: Optional[ColorValue]): - self.__divider_color = value - self._set_enum_attr("dividerColor", value, ColorEnums) - - # expanded_icon_color - @property - def expanded_icon_color(self) -> Optional[ColorValue]: - return self.__expanded_icon_color - - @expanded_icon_color.setter - def expanded_icon_color(self, value: Optional[ColorValue]): - self.__expanded_icon_color = value - self._set_enum_attr("expandedIconColor", value, ColorEnums) - - # expanded_header_padding - @property - def expanded_header_padding(self) -> Optional[PaddingValue]: - return self.__expanded_header_padding - - @expanded_header_padding.setter - def expanded_header_padding(self, value: Optional[PaddingValue]): - self.__expanded_header_padding = value - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation", data_type="float") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation cannot be negative" - self._set_attr("elevation", value) - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self._get_attr("spacing", data_type="float") - - @spacing.setter - def spacing(self, value: OptionalNumber): - self._set_attr("spacing", value) - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[ExpansionPanel]]): - self.__controls = list(value) if value is not None else [] - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - self._set_attr("onChange", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/expansion_tile.py b/sdk/python/packages/flet/src/flet/core/expansion_tile.py deleted file mode 100644 index 99be19d012..0000000000 --- a/sdk/python/packages/flet/src/flet/core/expansion_tile.py +++ /dev/null @@ -1,451 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - CrossAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - VisualDensity, -) - - -class TileAffinity(Enum): - LEADING = "leading" - TRAILING = "trailing" - PLATFORM = "platform" - - -class ExpansionTile(ConstrainedControl, AdaptiveControl): - """ - A single-line ListTile with an expansion arrow icon that expands or collapses the tile to reveal or hide its controls. - - ----- - - Online docs: https://flet.dev/docs/controls/expansiontile - """ - - def __init__( - self, - title: Control, - controls: Optional[Sequence[Control]] = None, - subtitle: Optional[Control] = None, - leading: Optional[Control] = None, - trailing: Optional[Control] = None, - controls_padding: Optional[PaddingValue] = None, - tile_padding: Optional[PaddingValue] = None, - affinity: Optional[TileAffinity] = None, - expanded_alignment: Optional[Alignment] = None, - expanded_cross_axis_alignment: CrossAxisAlignment = CrossAxisAlignment.CENTER, - clip_behavior: Optional[ClipBehavior] = None, - initially_expanded: Optional[bool] = None, - maintain_state: Optional[bool] = None, - text_color: Optional[ColorValue] = None, - icon_color: Optional[ColorValue] = None, - shape: Optional[OutlinedBorder] = None, - bgcolor: Optional[ColorValue] = None, - collapsed_bgcolor: Optional[ColorValue] = None, - collapsed_icon_color: Optional[ColorValue] = None, - collapsed_text_color: Optional[ColorValue] = None, - collapsed_shape: Optional[OutlinedBorder] = None, - dense: Optional[bool] = None, - enable_feedback: Optional[bool] = None, - show_trailing_icon: Optional[bool] = None, - min_tile_height: OptionalNumber = None, - visual_density: Optional[VisualDensity] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.controls = controls - self.controls_padding = controls_padding - self.expanded_alignment = expanded_alignment - self.expanded_cross_axis_alignment = expanded_cross_axis_alignment - self.tile_padding = tile_padding - self.leading = leading - self.title = title - self.subtitle = subtitle - self.trailing = trailing - self.affinity = affinity - self.clip_behavior = clip_behavior - self.maintain_state = maintain_state - self.initially_expanded = initially_expanded - self.shape = shape - self.text_color = text_color - self.icon_color = icon_color - self.bgcolor = bgcolor - self.collapsed_bgcolor = collapsed_bgcolor - self.collapsed_icon_color = collapsed_icon_color - self.collapsed_text_color = collapsed_text_color - self.collapsed_shape = collapsed_shape - self.on_change = on_change - self.dense = dense - self.enable_feedback = enable_feedback - self.visual_density = visual_density - self.show_trailing_icon = show_trailing_icon - self.min_tile_height = min_tile_height - - def _get_control_name(self): - return "expansiontile" - - def before_update(self): - super().before_update() - assert self.__title.visible, "title must be visible" - self._set_attr_json("expandedAlignment", self.__expanded_alignment) - self._set_attr_json("controlsPadding", self.__controls_padding) - self._set_attr_json("tilePadding", self.__tile_padding) - self._set_attr_json("shape", self.__shape) - self._set_attr_json("collapsedShape", self.__collapsed_shape) - - def _get_children(self): - self.__title._set_attr_internal("n", "title") - children = [self.__title] - for c in self.__controls: - c._set_attr_internal("n", "controls") - children.append(c) - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__subtitle: - self.__subtitle._set_attr_internal("n", "subtitle") - children.append(self.__subtitle) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - return children - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # controls_padding - @property - def controls_padding(self) -> Optional[PaddingValue]: - return self.__controls_padding - - @controls_padding.setter - def controls_padding(self, value: Optional[PaddingValue]): - self.__controls_padding = value - - # tile_padding - @property - def tile_padding(self) -> Optional[PaddingValue]: - return self.__tile_padding - - @tile_padding.setter - def tile_padding(self, value: Optional[PaddingValue]): - self.__tile_padding = value - - # expanded_alignment - @property - def expanded_alignment(self) -> Optional[Alignment]: - return self.__expanded_alignment - - @expanded_alignment.setter - def expanded_alignment(self, value: Optional[Alignment]): - self.__expanded_alignment = value - - # expanded_cross_axis_alignment - @property - def expanded_cross_axis_alignment(self) -> Optional[CrossAxisAlignment]: - return self.__expanded_cross_axis_alignment - - @expanded_cross_axis_alignment.setter - def expanded_cross_axis_alignment(self, value: Optional[CrossAxisAlignment]): - self.__expanded_cross_axis_alignment = value - self._set_enum_attr("crossAxisAlignment", value, CrossAxisAlignment) - - # affinity - @property - def affinity(self) -> Optional[TileAffinity]: - return self.__affinity - - @affinity.setter - def affinity(self, value: Optional[TileAffinity]): - self.__affinity = value - self._set_enum_attr("affinity", value, TileAffinity) - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # subtitle - @property - def subtitle(self) -> Optional[Control]: - return self.__subtitle - - @subtitle.setter - def subtitle(self, value: Optional[Control]): - self.__subtitle = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # dense - @property - def dense(self) -> bool: - return self._get_attr("dense", data_type="bool") - - @dense.setter - def dense(self, value: Optional[bool]): - self._set_attr("dense", value) - - # enable_feedback - @property - def enable_feedback(self) -> bool: - return self._get_attr("enableFeedback", data_type="bool", def_value=True) - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # visual_density - @property - def visual_density(self) -> Optional[VisualDensity]: - return self.__visual_density - - @visual_density.setter - def visual_density(self, value: Optional[VisualDensity]): - self.__visual_density = value - self._set_enum_attr("visualDensity", value, VisualDensity) - - # maintain_state - @property - def maintain_state(self) -> bool: - return self._get_attr("maintainState", data_type="bool", def_value=False) - - @maintain_state.setter - def maintain_state(self, value: Optional[bool]): - self._set_attr("maintainState", value) - - # initially_expanded - @property - def initially_expanded(self) -> bool: - return self._get_attr("initiallyExpanded", data_type="bool", def_value=False) - - @initially_expanded.setter - def initially_expanded(self, value: Optional[bool]): - self._set_attr("initiallyExpanded", value) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # text_color - @property - def text_color(self) -> Optional[ColorValue]: - return self.__text_color - - @text_color.setter - def text_color(self, value: Optional[ColorValue]): - self.__text_color = value - self._set_enum_attr("textColor", value, ColorEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # collapsed_bgcolor - @property - def collapsed_bgcolor(self) -> Optional[str]: - return self.__collapsed_bgcolor - - @collapsed_bgcolor.setter - def collapsed_bgcolor(self, value: Optional[str]): - self.__collapsed_bgcolor = value - self._set_enum_attr("collapsedBgColor", value, ColorEnums) - - # collapsed_icon_color - @property - def collapsed_icon_color(self) -> Optional[ColorValue]: - return self.__collapsed_icon_color - - @collapsed_icon_color.setter - def collapsed_icon_color(self, value: Optional[ColorValue]): - self.__collapsed_icon_color = value - self._set_enum_attr("collapsedIconColor", value, ColorEnums) - - # collapsed_text_color - @property - def collapsed_text_color(self) -> Optional[ColorValue]: - return self.__collapsed_text_color - - @collapsed_text_color.setter - def collapsed_text_color(self, value: Optional[ColorValue]): - self.__collapsed_text_color = value - self._set_enum_attr("collapsedTextColor", value, ColorEnums) - - # collapsed_shape - @property - def collapsed_shape(self) -> Optional[OutlinedBorder]: - return self.__collapsed_shape - - @collapsed_shape.setter - def collapsed_shape(self, value: Optional[OutlinedBorder]): - self.__collapsed_shape = value - - # show_trailing_icon - @property - def show_trailing_icon(self) -> bool: - return self._get_attr("showTrailingIcon", data_type="bool", def_value=True) - - @show_trailing_icon.setter - def show_trailing_icon(self, value: Optional[bool]): - self._set_attr("showTrailingIcon", value) - - # min_tile_height - @property - def min_tile_height(self) -> OptionalNumber: - return self._get_attr("minTileHeight") - - @min_tile_height.setter - def min_tile_height(self, value: OptionalNumber): - self._set_attr("minTileHeight", value) - - # on_change - @property - def on_change(self): - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - self._set_attr("onChange", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/file_picker.py b/sdk/python/packages/flet/src/flet/core/file_picker.py deleted file mode 100644 index 48aad3a631..0000000000 --- a/sdk/python/packages/flet/src/flet/core/file_picker.py +++ /dev/null @@ -1,301 +0,0 @@ -import base64 -import json -from dataclasses import dataclass, field -from enum import Enum -from typing import Any, Callable, List, Optional - -from flet.core.control import Control -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import OptionalEventCallable - - -class FilePickerState(Enum): - PICK_FILES = "pickFiles" - SAVE_FILE = "saveFile" - GET_DIRECTORY_PATH = "getDirectoryPath" - - -class FilePickerFileType(Enum): - ANY = "any" - MEDIA = "media" - IMAGE = "image" - VIDEO = "video" - AUDIO = "audio" - CUSTOM = "custom" - - -@dataclass -class FilePickerUploadFile: - name: str - upload_url: str - id: int = None - method: str = field(default="PUT") - - -@dataclass -class FilePickerFile: - name: str - path: str - size: int - id: int - - -class FilePickerResultEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.error = d.get("error") - self.path: Optional[str] = d.get("path") - self.files: Optional[List[FilePickerFile]] = None - files = d.get("files") - if files is not None and isinstance(files, List): - self.files = [] - for fd in files: - self.files.append(FilePickerFile(**fd)) - - -class FilePickerUploadEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.file_name: str = d.get("file_name") - self.progress: Optional[float] = d.get("progress") - self.error: Optional[str] = d.get("error") - - -class FilePicker(Control): - """ - A control that allows you to use the native file explorer to pick single or multiple files, with extensions filtering support and upload. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def pick_files_result(e: ft.FilePickerResultEvent): - selected_files.value = ( - ", ".join(map(lambda f: f.name, e.files)) if e.files else "Cancelled!" - ) - selected_files.update() - - pick_files_dialog = ft.FilePicker(on_result=pick_files_result) - selected_files = ft.Text() - - page.overlay.append(pick_files_dialog) - - page.add( - ft.Row( - [ - ft.ElevatedButton( - "Pick files", - icon=ft.icons.UPLOAD_FILE, - on_click=lambda _: pick_files_dialog.pick_files( - allow_multiple=True - ), - ), - selected_files, - ] - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/filepicker - """ - - def __init__( - self, - on_result: Optional[Callable[[FilePickerResultEvent], None]] = None, - on_upload: Optional[Callable[[FilePickerUploadEvent], None]] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - data=data, - ) - - def convert_result_event_data(e): - self.__result = FilePickerResultEvent(e) - return self.__result - - self.__on_result = EventHandler(convert_result_event_data) - self._add_event_handler("result", self.__on_result.get_handler()) - - self.__on_upload = EventHandler(lambda e: FilePickerUploadEvent(e)) - self._add_event_handler("upload", self.__on_upload.get_handler()) - - self.__result: Optional[FilePickerResultEvent] = None - self.__upload: List[FilePickerUploadFile] = [] - self.__allowed_extensions: Optional[List[str]] = None - self.__state = None - self.__file_type = None - self.on_result = on_result - self.on_upload = on_upload - - def _get_control_name(self): - return "filepicker" - - def before_update(self): - super().before_update() - self._set_attr_json("allowedExtensions", self.__allowed_extensions) - self._set_attr_json("upload", self.__upload) - - def pick_files( - self, - dialog_title: Optional[str] = None, - initial_directory: Optional[str] = None, - file_type: FilePickerFileType = FilePickerFileType.ANY, - allowed_extensions: Optional[List[str]] = None, - allow_multiple: Optional[bool] = False, - ): - self.state = FilePickerState.PICK_FILES - self.dialog_title = dialog_title - self.initial_directory = initial_directory - self.file_type = file_type - self.allowed_extensions = allowed_extensions - self.allow_multiple = allow_multiple - self.update() - - def save_file( - self, - dialog_title: Optional[str] = None, - file_name: Optional[str] = None, - initial_directory: Optional[str] = None, - file_type: FilePickerFileType = FilePickerFileType.ANY, - allowed_extensions: Optional[List[str]] = None, - src_bytes: Optional[bytes] = None, - ): - self.state = FilePickerState.SAVE_FILE - self.dialog_title = dialog_title - self.file_name = file_name - self.initial_directory = initial_directory - self.file_type = file_type - self.allowed_extensions = allowed_extensions - self.src_bytes = src_bytes - self.update() - - def get_directory_path( - self, - dialog_title: Optional[str] = None, - initial_directory: Optional[str] = None, - ): - self.state = FilePickerState.GET_DIRECTORY_PATH - self.dialog_title = dialog_title - self.initial_directory = initial_directory - self.update() - - def upload(self, files: List[FilePickerUploadFile]): - self.__upload = files - self.update() - - # state - @property - def state(self) -> Optional[FilePickerState]: - return self.__state - - @state.setter - def state(self, value: Optional[FilePickerState]): - self.__state = value - self._set_enum_attr("state", value, FilePickerState) - - # result - @property - def result(self) -> Optional[FilePickerResultEvent]: - return self.__result - - # dialog_title - @property - def dialog_title(self) -> Optional[str]: - return self._get_attr("dialogTitle") - - @dialog_title.setter - def dialog_title(self, value: Optional[str]): - self._set_attr("dialogTitle", value) - - # file_name - @property - def file_name(self) -> Optional[str]: - return self._get_attr("fileName") - - @file_name.setter - def file_name(self, value: Optional[str]): - self._set_attr("fileName", value) - - # initial_directory - @property - def initial_directory(self): - return self._get_attr("initialDirectory") - - @initial_directory.setter - def initial_directory(self, value: Optional[str]): - self._set_attr("initialDirectory", value) - - # file_type - @property - def file_type(self) -> FilePickerFileType: - return self.__file_type - - @file_type.setter - def file_type(self, value: FilePickerFileType): - self.__file_type = value - self._set_enum_attr("fileType", value, FilePickerFileType) - - # allowed_extensions - @property - def allowed_extensions(self) -> Optional[List[str]]: - return self.__allowed_extensions - - @allowed_extensions.setter - def allowed_extensions(self, value: Optional[List[str]]): - self.__allowed_extensions = value - - # allow_multiple - @property - def allow_multiple(self) -> bool: - return self._get_attr("allowMultiple", data_type="bool", def_value=False) - - @allow_multiple.setter - def allow_multiple(self, value: Optional[bool]): - self._set_attr("allowMultiple", value) - - # src_bytes - @property - def src_bytes(self) -> Optional[bytes]: - v = self._get_attr("srcBytes") - return base64.b64decode(v) if v else v - - @src_bytes.setter - def src_bytes(self, value: Optional[bytes]): - self._set_attr( - "srcBytes", base64.b64encode(value).decode("utf-8") if value else value - ) - - # on_result - @property - def on_result(self) -> OptionalEventCallable[FilePickerResultEvent]: - return self.__on_result.handler - - @on_result.setter - def on_result(self, handler: OptionalEventCallable[FilePickerResultEvent]): - self.__on_result.handler = handler - - # on_upload - @property - def on_upload(self): - return self.__on_upload.handler - - @on_upload.setter - def on_upload(self, handler: OptionalEventCallable[FilePickerUploadEvent]): - self.__on_upload.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/filled_button.py b/sdk/python/packages/flet/src/flet/core/filled_button.py deleted file mode 100644 index 7312f82162..0000000000 --- a/sdk/python/packages/flet/src/flet/core/filled_button.py +++ /dev/null @@ -1,30 +0,0 @@ -from flet.core.elevated_button import ElevatedButton - - -class FilledButton(ElevatedButton): - """ - Filled buttons have the most visual impact after the FloatingActionButton (https://flet.dev/docs/controls/floatingactionbutton), and should be used for important, final actions that complete a flow, like Save, Join now, or Confirm. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.title = "Basic filled buttons" - page.add( - ft.FilledButton(text="Filled button"), - ft.FilledButton("Disabled button", disabled=True), - ft.FilledButton("Button with icon", icon="add"), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/filledbutton - """ - - def _get_control_name(self): - return "filledbutton" diff --git a/sdk/python/packages/flet/src/flet/core/filled_tonal_button.py b/sdk/python/packages/flet/src/flet/core/filled_tonal_button.py deleted file mode 100644 index 63dc182394..0000000000 --- a/sdk/python/packages/flet/src/flet/core/filled_tonal_button.py +++ /dev/null @@ -1,30 +0,0 @@ -from flet.core.elevated_button import ElevatedButton - - -class FilledTonalButton(ElevatedButton): - """ - A filled tonal button is an alternative middle ground between FilledButton and OutlinedButton buttons. They’re useful in contexts where a lower-priority button requires slightly more emphasis than an outline would give, such as "Next" in an onboarding flow. Tonal buttons use the secondary color mapping. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.title = "Basic filled tonal buttons" - page.add( - ft.FilledTonalButton(text="Filled tonal button"), - ft.FilledTonalButton("Disabled button", disabled=True), - ft.FilledTonalButton("Button with icon", icon="add"), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/filledtonalbutton - """ - - def _get_control_name(self): - return "filledtonalbutton" diff --git a/sdk/python/packages/flet/src/flet/core/flashlight.py b/sdk/python/packages/flet/src/flet/core/flashlight.py deleted file mode 100644 index 7a242dcc9e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/flashlight.py +++ /dev/null @@ -1,90 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref -from flet.utils import deprecated - - -@deprecated( - reason="Flashlight control has been moved to a separate Python package: https://pypi.org/project/flet-flashlight. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Flashlight(Control): - """ - A control to use FlashLight. Works on iOS and Android. Based on torch_light Flutter widget (https://pub.dev/packages/torch_light). - - Flashlight control is non-visual and should be added to `page.overlay` list. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - flashLight = ft.Flashlight() - page.overlay.append(flashLight) - page.add( - ft.TextButton("toggle", on_click: lambda _: flashlight.toggle()) - ) - - ft.app(target=main) - ``` - - """ - - def __init__( - self, - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - - self.turned_on = False - - def _get_control_name(self): - return "flashlight" - - def turn_on(self, wait_timeout: Optional[int] = 5) -> bool: - sr = self.invoke_method("on", wait_for_result=True, wait_timeout=wait_timeout) - - if int(sr) == 1: - self.turned_on = True - return self.turned_on - - async def turn_on_async(self, wait_timeout: Optional[int] = 5) -> bool: - sr = await self.invoke_method_async( - "on", wait_for_result=True, wait_timeout=wait_timeout - ) - if int(sr) == 1: - self.turned_on = True - return self.turned_on - - def turn_off(self, wait_timeout: Optional[int] = 5) -> bool: - sr = self.invoke_method("off", wait_for_result=True, wait_timeout=wait_timeout) - - if int(sr) == 1: - self.turned_on = False - return self.turned_on - - async def turn_off_async(self, wait_timeout: Optional[int] = 5) -> bool: - sr = await self.invoke_method_async( - "off", wait_for_result=True, wait_timeout=wait_timeout - ) - if int(sr) == 1: - self.turned_on = False - return self.turned_on - - def toggle(self, wait_timeout: Optional[int] = 5) -> bool: - if self.turned_on: - return self.turn_off(wait_timeout) - return self.turn_on(wait_timeout) - - async def toggle_async(self, wait_timeout: Optional[int] = 5) -> bool: - if self.turned_on: - return await self.turn_off_async(wait_timeout) - return await self.turn_on_async(wait_timeout) diff --git a/sdk/python/packages/flet/src/flet/core/flet_app.py b/sdk/python/packages/flet/src/flet/core/flet_app.py deleted file mode 100644 index da95024040..0000000000 --- a/sdk/python/packages/flet/src/flet/core/flet_app.py +++ /dev/null @@ -1,148 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - RotateValue, - ScaleValue, -) - - -class FletApp(ConstrainedControl): - def __init__( - self, - url: Optional[str] = None, - reconnect_interval_ms: Optional[int] = None, - reconnect_timeout_ms: Optional[int] = None, - show_app_startup_screen: Optional[bool] = None, - app_startup_screen_message: Optional[str] = None, - on_error: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.url = url - self.reconnect_interval_ms = reconnect_interval_ms - self.reconnect_timeout_ms = reconnect_timeout_ms - self.show_app_startup_screen = show_app_startup_screen - self.app_startup_screen_message = app_startup_screen_message - self.on_error = on_error - - def _get_control_name(self): - return "fletapp" - - # url - @property - def url(self): - return self._get_attr("url") - - @url.setter - def url(self, value): - self._set_attr("url", value) - - # reconnect_interval_ms - @property - def reconnect_interval_ms(self) -> Optional[int]: - return self._get_attr("reconnectIntervalMs") - - @reconnect_interval_ms.setter - def reconnect_interval_ms(self, value: Optional[int]): - self._set_attr("reconnectIntervalMs", value) - - # reconnect_timeout_ms - @property - def reconnect_timeout_ms(self) -> Optional[int]: - return self._get_attr("reconnectTimeoutMs") - - @reconnect_timeout_ms.setter - def reconnect_timeout_ms(self, value: Optional[int]): - self._set_attr("reconnectTimeoutMs", value) - - # show_app_startup_screen - @property - def show_app_startup_screen(self) -> bool: - return self._get_attr("showAppStartupScreen", data_type="bool", def_value=False) - - @show_app_startup_screen.setter - def show_app_startup_screen(self, value: Optional[bool]): - self._set_attr("showAppStartupScreen", value) - - # app_startup_screen_message - @property - def app_startup_screen_message(self) -> Optional[str]: - return self._get_attr("appStartupScreenMessage") - - @app_startup_screen_message.setter - def app_startup_screen_message(self, value: Optional[str]): - self._set_attr("appStartupScreenMessage", value) - - # on_error - @property - def on_error(self) -> OptionalControlEventCallable: - return self._get_event_handler("error") - - @on_error.setter - def on_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("error", handler) diff --git a/sdk/python/packages/flet/src/flet/core/floating_action_button.py b/sdk/python/packages/flet/src/flet/core/floating_action_button.py deleted file mode 100644 index dd7b9721f8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/floating_action_button.py +++ /dev/null @@ -1,388 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, -) - - -class FloatingActionButton(ConstrainedControl): - """ - A floating action button is a circular icon button that hovers over content to promote a primary action in the application. Floating action button is usually set to `page.floating_action_button`, but can also be added as a regular control at any place on a page. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Floating Action Button" - page.theme_mode = ft.ThemeMode.LIGHT - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - page.auto_scroll = True - page.scroll = ft.ScrollMode.HIDDEN - page.appbar = ft.AppBar( - title=ft.Text( - "Floating Action Button", weight=ft.FontWeight.BOLD, color=ft.colors.BLACK87 - ), - bgcolor=ft.colors.BLUE, - center_title=True, - actions=[ - ft.IconButton(ft.icons.MENU, tooltip="Menu", icon_color=ft.colors.BLACK87) - ], - color=ft.colors.WHITE, - ) - - # keeps track of the number of tiles already added - page.count = 0 - - def fab_pressed(e): - page.add(ft.ListTile(title=ft.Text(f"Tile {page.count}"))) - page.show_snack_bar( - ft.SnackBar(ft.Text("Tile was added successfully!"), open=True) - ) - page.count += 1 - - page.floating_action_button = ft.FloatingActionButton( - icon=ft.icons.ADD, on_click=fab_pressed, bgcolor=ft.colors.LIME_300 - ) - page.add(ft.Text("Press the FAB to add a tile!")) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/floatingactionbutton - """ - - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - bgcolor: Optional[ColorValue] = None, - content: Optional[Control] = None, - shape: Optional[OutlinedBorder] = None, - autofocus: Optional[bool] = None, - mini: Optional[bool] = None, - foreground_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - elevation: OptionalNumber = None, - disabled_elevation: OptionalNumber = None, - focus_elevation: OptionalNumber = None, - highlight_elevation: OptionalNumber = None, - hover_elevation: OptionalNumber = None, - enable_feedback: Optional[bool] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_click: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.text = text - self.icon = icon - self.bgcolor = bgcolor - self.content = content - self.autofocus = autofocus - self.shape = shape - self.mini = mini - self.url = url - self.url_target = url_target - self.on_click = on_click - self.foreground_color = foreground_color - self.focus_color = focus_color - self.clip_behavior = clip_behavior - self.elevation = elevation - self.disabled_elevation = disabled_elevation - self.focus_elevation = focus_elevation - self.highlight_elevation = highlight_elevation - self.hover_elevation = hover_elevation - self.enable_feedback = enable_feedback - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "floatingactionbutton" - - def before_update(self): - super().before_update() - assert ( - self.text or self.icon or (self.__content and self.__content.visible) - ), "at minimum, text, icon or a visible content must be provided" - self._set_attr_json("shape", self.__shape) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # mini - @property - def mini(self) -> bool: - return self._get_attr("mini", data_type="bool", def_value=False) - - @mini.setter - def mini(self, value: Optional[bool]): - self._set_attr("mini", value) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation", data_type="float") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation cannot be negative" - self._set_attr("elevation", value) - - # disabled_elevation - @property - def disabled_elevation(self) -> OptionalNumber: - return self._get_attr("disabledElevation", data_type="float") - - @disabled_elevation.setter - def disabled_elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "disabled_elevation cannot be negative" - self._set_attr("disabledElevation", value) - - # enable_feedback - @property - def enable_feedback(self) -> bool: - return self._get_attr("enableFeedback", data_type="bool", def_value=True) - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # focus_elevation - @property - def focus_elevation(self) -> OptionalNumber: - return self._get_attr("focusElevation", data_type="float") - - @focus_elevation.setter - def focus_elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "focus_elevation cannot be negative" - self._set_attr("focusElevation", value) - - # foreground_color - @property - def foreground_color(self) -> Optional[ColorValue]: - return self.__foreground_color - - @foreground_color.setter - def foreground_color(self, value: Optional[ColorValue]): - self.__foreground_color = value - self._set_enum_attr("foregroundColor", value, ColorEnums) - - # highlight_elevation - @property - def highlight_elevation(self) -> OptionalNumber: - return self._get_attr("highlightElevation", data_type="float") - - @highlight_elevation.setter - def highlight_elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "highlight_elevation cannot be negative" - self._set_attr("highlightElevation", value) - - # hover_elevation - @property - def hover_elevation(self) -> OptionalNumber: - return self._get_attr("hoverElevation", data_type="float") - - @hover_elevation.setter - def hover_elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "hover_elevation cannot be negative" - self._set_attr("hoverElevation", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) diff --git a/sdk/python/packages/flet/src/flet/core/form_field_control.py b/sdk/python/packages/flet/src/flet/core/form_field_control.py deleted file mode 100644 index 51ccc4fee5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/form_field_control.py +++ /dev/null @@ -1,734 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxConstraints -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - ColorEnums, - ColorValue, - DurationValue, - IconEnums, - IconValueOrControl, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - VerticalAlignment, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class InputBorder(Enum): - NONE = "none" - OUTLINE = "outline" - UNDERLINE = "underline" - - -class FormFieldControl(ConstrainedControl): - def __init__( - self, - text_size: OptionalNumber = None, - text_style: Optional[TextStyle] = None, - text_vertical_align: Union[VerticalAlignment, OptionalNumber] = None, - label: Optional[Union[str, Control]] = None, - label_style: Optional[TextStyle] = None, - icon: Optional[IconValueOrControl] = None, - border: Optional[InputBorder] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - border_radius: Optional[BorderRadiusValue] = None, - border_width: OptionalNumber = None, - border_color: Optional[ColorValue] = None, - focused_color: Optional[ColorValue] = None, - focused_bgcolor: Optional[ColorValue] = None, - focused_border_width: OptionalNumber = None, - focused_border_color: Optional[ColorValue] = None, - content_padding: Optional[PaddingValue] = None, - dense: Optional[bool] = None, - filled: Optional[bool] = None, - fill_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - align_label_with_hint: Optional[bool] = None, - hover_color: Optional[ColorValue] = None, - hint_text: Optional[str] = None, - hint_style: Optional[TextStyle] = None, - hint_fade_duration: Optional[DurationValue] = None, - hint_max_lines: Optional[int] = None, - helper: Optional[Control] = None, - helper_text: Optional[str] = None, - helper_style: Optional[TextStyle] = None, - helper_max_lines: Optional[int] = None, - counter: Optional[Control] = None, - counter_text: Optional[str] = None, - counter_style: Optional[TextStyle] = None, - error: Optional[Control] = None, - error_text: Optional[str] = None, - error_style: Optional[TextStyle] = None, - error_max_lines: Optional[int] = None, - prefix: Optional[Control] = None, - prefix_icon: Optional[IconValueOrControl] = None, - prefix_icon_size_constraints: Optional[BoxConstraints] = None, - prefix_text: Optional[str] = None, - prefix_style: Optional[TextStyle] = None, - suffix: Optional[Control] = None, - suffix_icon: Optional[IconValueOrControl] = None, - suffix_icon_size_constraints: Optional[BoxConstraints] = None, - size_constraints: Optional[BoxConstraints] = None, - collapsed: Optional[bool] = None, - fit_parent_size: Optional[bool] = None, - suffix_text: Optional[str] = None, - suffix_style: Optional[TextStyle] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.text_size = text_size - self.text_style = text_style - self.text_vertical_align = text_vertical_align - self.label = label - self.label_style = label_style - self.icon = icon - self.border = border - self.color = color - self.bgcolor = bgcolor - self.border_radius = border_radius - self.border_width = border_width - self.border_color = border_color - self.focused_color = focused_color - self.focused_bgcolor = focused_bgcolor - self.focused_border_width = focused_border_width - self.focused_border_color = focused_border_color - self.content_padding = content_padding - self.filled = filled - self.dense = dense - self.hint_text = hint_text - self.hint_style = hint_style - self.helper = helper - self.helper_text = helper_text - self.helper_style = helper_style - self.counter = counter - self.counter_text = counter_text - self.counter_style = counter_style - self.error = error - self.error_text = error_text - self.error_style = error_style - self.prefix = prefix - self.prefix_icon = prefix_icon - self.prefix_text = prefix_text - self.prefix_style = prefix_style - self.suffix = suffix - self.suffix_icon = suffix_icon - self.suffix_text = suffix_text - self.suffix_style = suffix_style - self.hover_color = hover_color - self.fill_color = fill_color - self.focus_color = focus_color - self.align_label_with_hint = align_label_with_hint - self.hint_fade_duration = hint_fade_duration - self.hint_max_lines = hint_max_lines - self.helper_max_lines = helper_max_lines - self.error_max_lines = error_max_lines - self.prefix_icon_size_constraints = prefix_icon_size_constraints - self.suffix_icon_size_constraints = suffix_icon_size_constraints - self.size_constraints = size_constraints - self.collapsed = collapsed - self.fit_parent_size = fit_parent_size - - def before_update(self): - super().before_update() - self._set_attr_json("borderRadius", self.__border_radius) - self._set_attr_json("contentPadding", self.__content_padding) - self._set_attr_json("textStyle", self.__text_style) - self._set_attr_json("labelStyle", self.__label_style) - self._set_attr_json("hintStyle", self.__hint_style) - self._set_attr_json("helperStyle", self.__helper_style) - self._set_attr_json("counterStyle", self.__counter_style) - self._set_attr_json("errorStyle", self.__error_style) - self._set_attr_json("prefixStyle", self.__prefix_style) - self._set_attr_json("suffixStyle", self.__suffix_style) - self._set_attr_json("hintFadeDuration", self.__hint_fade_duration) - self._set_attr_json( - "prefixIconSizeConstraints", self.__prefix_icon_size_constraints - ) - self._set_attr_json( - "suffixIconSizeConstraints", self.__suffix_icon_size_constraints - ) - self._set_attr_json("sizeConstraints", self.__size_constraints) - if isinstance(self.__suffix_icon, str): - self._set_attr("suffixIcon", self.__suffix_icon) - if isinstance(self.__prefix_icon, str): - self._set_attr("prefixIcon", self.__prefix_icon) - if isinstance(self.__icon, str): - self._set_attr("icon", self.__icon) - if isinstance(self.__label, str): - self._set_attr("label", self.__label) - - def _get_children(self): - children = [] - for control, name in [ - (self.__prefix, "prefix"), - (self.__suffix, "suffix"), - (self.__suffix_icon, "suffix_icon"), - (self.__prefix_icon, "prefix_icon"), - (self.__icon, "icon"), - (self.__counter, "counter"), - (self.__error, "error"), - (self.__helper, "helper"), - (self.__label, "label"), - ]: - if isinstance(control, Control): - control._set_attr_internal("n", name) - children.append(control) - return children - - # text_size - @property - def text_size(self) -> OptionalNumber: - return self._get_attr("textSize") - - @text_size.setter - def text_size(self, value: OptionalNumber): - self._set_attr("textSize", value) - - # text_style - @property - def text_style(self) -> Optional[TextStyle]: - return self.__text_style - - @text_style.setter - def text_style(self, value: Optional[TextStyle]): - self.__text_style = value - - # label - @property - def label(self) -> Optional[Union[str, Control]]: - return self.__label - - @label.setter - def label(self, value: Optional[Union[str, Control]]): - self.__label = value - - # label_style - @property - def label_style(self) -> Optional[TextStyle]: - return self.__label_style - - @label_style.setter - def label_style(self, value: Optional[TextStyle]): - self.__label_style = value - - # icon - @property - def icon(self) -> Optional[IconValueOrControl]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValueOrControl]): - self.__icon = value - if not isinstance(value, Control): - self._set_enum_attr("icon", value, IconEnums) - - # border - @property - def border(self) -> Optional[InputBorder]: - return self.__border - - @border.setter - def border(self, value: Optional[InputBorder]): - self.__border = value - self._set_enum_attr("border", value, InputBorder) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # focus_color - @property - def focus_color(self) -> Optional[str]: - return self._get_attr("focusColor") - - @focus_color.setter - def focus_color(self, value: Optional[str]): - self._set_attr("focusColor", value) - - # align_label_with_hint - @property - def align_label_with_hint(self) -> Optional[bool]: - return self._get_attr("alignLabelWithHint", data_type="bool") - - @align_label_with_hint.setter - def align_label_with_hint(self, value: Optional[bool]): - self._set_attr("alignLabelWithHint", value) - - # fit_parent_size - @property - def fit_parent_size(self) -> Optional[bool]: - return self._get_attr("fitParentSize", data_type="bool", def_value=False) - - @fit_parent_size.setter - def fit_parent_size(self, value: Optional[bool]): - self._set_attr("fitParentSize", value) - - # hint_fade_duration - @property - def hint_fade_duration(self) -> Optional[DurationValue]: - return self.__hint_fade_duration - - @hint_fade_duration.setter - def hint_fade_duration(self, value: Optional[DurationValue]): - self.__hint_fade_duration = value - - # hint_max_lines - @property - def hint_max_lines(self) -> Optional[int]: - return self._get_attr("hintMaxLines", data_type="int") - - @hint_max_lines.setter - def hint_max_lines(self, value: Optional[int]): - self._set_attr("hintMaxLines", value) - - # helper_max_lines - @property - def helper_max_lines(self) -> Optional[int]: - return self._get_attr("helperMaxLines", data_type="int") - - @helper_max_lines.setter - def helper_max_lines(self, value: Optional[int]): - self._set_attr("helperMaxLines", value) - - # error_max_lines - @property - def error_max_lines(self) -> Optional[int]: - return self._get_attr("errorMaxLines", data_type="int") - - @error_max_lines.setter - def error_max_lines(self, value: Optional[int]): - self._set_attr("errorMaxLines", value) - - # prefix_icon_size_constraints - @property - def prefix_icon_size_constraints(self) -> Optional[BoxConstraints]: - return self.__prefix_icon_size_constraints - - @prefix_icon_size_constraints.setter - def prefix_icon_size_constraints(self, value: Optional[BoxConstraints]): - self.__prefix_icon_size_constraints = value - - # suffix_icon_size_constraints - @property - def suffix_icon_size_constraints(self) -> Optional[BoxConstraints]: - return self.__suffix_icon_size_constraints - - @suffix_icon_size_constraints.setter - def suffix_icon_size_constraints(self, value: Optional[BoxConstraints]): - self.__suffix_icon_size_constraints = value - - # size_constraints - @property - def size_constraints(self) -> Optional[BoxConstraints]: - return self.__size_constraints - - @size_constraints.setter - def size_constraints(self, value: Optional[BoxConstraints]): - self.__size_constraints = value - - # collapsed - @property - def collapsed(self) -> Optional[bool]: - return self._get_attr("collapsed", data_type="bool") - - @collapsed.setter - def collapsed(self, value: Optional[bool]): - self._set_attr("collapsed", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # border_width - @property - def border_width(self) -> OptionalNumber: - return self._get_attr("borderWidth") - - @border_width.setter - def border_width(self, value: OptionalNumber): - self._set_attr("borderWidth", value) - - # border_color - @property - def border_color(self) -> Optional[ColorValue]: - return self.__border_color - - @border_color.setter - def border_color(self, value: Optional[ColorValue]): - self.__border_color = value - self._set_enum_attr("borderColor", value, ColorEnums) - - # text_vertical_align - @property - def text_vertical_align(self) -> Union[VerticalAlignment, OptionalNumber]: - return self._get_attr("textVerticalAlign") - - @text_vertical_align.setter - def text_vertical_align(self, value: Union[VerticalAlignment, OptionalNumber]): - v = value.value if isinstance(value, VerticalAlignment) else value - if v is not None: - v = max(-1.0, min(v, 1.0)) # make sure 0.0 <= value <= 1.0 - self._set_attr("textVerticalAlign", v) - - # focused_color - @property - def focused_color(self) -> Optional[ColorValue]: - return self.__focused_color - - @focused_color.setter - def focused_color(self, value: Optional[ColorValue]): - self.__focused_color = value - self._set_enum_attr("focusedColor", value, ColorEnums) - - # focused_bgcolor - @property - def focused_bgcolor(self) -> Optional[str]: - return self.__focused_bgcolor - - @focused_bgcolor.setter - def focused_bgcolor(self, value: Optional[str]): - self.__focused_bgcolor = value - self._set_enum_attr("focusedBgcolor", value, ColorEnums) - - # focused_border_width - @property - def focused_border_width(self) -> OptionalNumber: - return self._get_attr("focusedBorderWidth") - - @focused_border_width.setter - def focused_border_width(self, value: OptionalNumber): - self._set_attr("focusedBorderWidth", value) - - # focused_border_color - @property - def focused_border_color(self) -> Optional[ColorValue]: - return self.__focused_border_color - - @focused_border_color.setter - def focused_border_color(self, value: Optional[ColorValue]): - self.__focused_border_color = value - self._set_enum_attr("focusedBorderColor", value, ColorEnums) - - # content_padding - @property - def content_padding(self) -> Optional[PaddingValue]: - return self.__content_padding - - @content_padding.setter - def content_padding(self, value: Optional[PaddingValue]): - self.__content_padding = value - - # dense - @property - def dense(self) -> bool: - return self._get_attr("dense", data_type="bool", def_value=False) - - @dense.setter - def dense(self, value: Optional[bool]): - self._set_attr("dense", value) - - # filled - @property - def filled(self) -> Optional[bool]: - return self._get_attr("filled", data_type="bool") - - @filled.setter - def filled(self, value: Optional[bool]): - self._set_attr("filled", value) - - # hint_text - @property - def hint_text(self) -> Optional[str]: - return self._get_attr("hintText") - - @hint_text.setter - def hint_text(self, value: Optional[str]): - self._set_attr("hintText", value) - - # hint_style - @property - def hint_style(self) -> Optional[TextStyle]: - return self.__hint_style - - @hint_style.setter - def hint_style(self, value: Optional[TextStyle]): - self.__hint_style = value - - # helper_text - @property - def helper_text(self) -> Optional[str]: - return self._get_attr("helperText") - - @helper_text.setter - def helper_text(self, value: Optional[str]): - self._set_attr("helperText", value) - - # helper_style - @property - def helper_style(self) -> Optional[TextStyle]: - return self.__helper_style - - @helper_style.setter - def helper_style(self, value: Optional[TextStyle]): - self.__helper_style = value - - # counter_text - @property - def counter_text(self) -> Optional[str]: - return self._get_attr("counterText") - - @counter_text.setter - def counter_text(self, value: Optional[str]): - self._set_attr("counterText", value) - - # counter_style - @property - def counter_style(self) -> Optional[TextStyle]: - return self.__counter_style - - @counter_style.setter - def counter_style(self, value: Optional[TextStyle]): - self.__counter_style = value - - # error_text - @property - def error_text(self) -> Optional[str]: - return self._get_attr("errorText") - - @error_text.setter - def error_text(self, value: Optional[str]): - self._set_attr("errorText", value) - - # error_style - @property - def error_style(self) -> Optional[TextStyle]: - return self.__error_style - - @error_style.setter - def error_style(self, value: Optional[TextStyle]): - self.__error_style = value - - # prefix - @property - def prefix(self) -> Optional[Control]: - return self.__prefix - - @prefix.setter - def prefix(self, value: Optional[Control]): - self.__prefix = value - - # error - @property - def error(self) -> Optional[Control]: - return self.__error - - @error.setter - def error(self, value: Optional[Control]): - self.__error = value - - # helper - @property - def helper(self) -> Optional[Control]: - return self.__helper - - @helper.setter - def helper(self, value: Optional[Control]): - self.__helper = value - - # counter - @property - def counter(self) -> Optional[Control]: - return self.__counter - - @counter.setter - def counter(self, value: Optional[Control]): - self.__counter = value - - # prefix_icon - @property - def prefix_icon(self) -> Optional[IconValueOrControl]: - return self.__prefix_icon - - @prefix_icon.setter - def prefix_icon(self, value: Optional[IconValueOrControl]): - self.__prefix_icon = value - if not isinstance(value, Control): - self._set_enum_attr("prefixIcon", value, IconEnums) - - # prefix_text - @property - def prefix_text(self) -> Optional[str]: - return self._get_attr("prefixText") - - @prefix_text.setter - def prefix_text(self, value: Optional[str]): - self._set_attr("prefixText", value) - - # prefix_style - @property - def prefix_style(self) -> Optional[TextStyle]: - return self.__prefix_style - - @prefix_style.setter - def prefix_style(self, value: Optional[TextStyle]): - self.__prefix_style = value - - # suffix - @property - def suffix(self) -> Optional[Control]: - return self.__suffix - - @suffix.setter - def suffix(self, value: Optional[Control]): - self.__suffix = value - - # suffix_icon - @property - def suffix_icon(self) -> Optional[IconValueOrControl]: - return self.__suffix_icon - - @suffix_icon.setter - def suffix_icon(self, value: Optional[IconValueOrControl]): - self.__suffix_icon = value - if not isinstance(value, Control): - self._set_enum_attr("suffixIcon", value, IconEnums) - - # suffix_text - @property - def suffix_text(self) -> Optional[str]: - return self._get_attr("suffixText") - - @suffix_text.setter - def suffix_text(self, value: Optional[str]): - self._set_attr("suffixText", value) - - # suffix_style - @property - def suffix_style(self) -> Optional[TextStyle]: - return self.__suffix_style - - @suffix_style.setter - def suffix_style(self, value: Optional[TextStyle]): - self.__suffix_style = value - - # fill_color - @property - def fill_color(self) -> Optional[ColorValue]: - return self.__fill_color - - @fill_color.setter - def fill_color(self, value: Optional[ColorValue]): - self.__fill_color = value - self._set_enum_attr("fillColor", value, ColorEnums) - - # hover_color - @property - def hover_color(self) -> Optional[ColorValue]: - return self.__hover_color - - @hover_color.setter - def hover_color(self, value: Optional[ColorValue]): - self.__hover_color = value - self._set_enum_attr("hoverColor", value, ColorEnums) diff --git a/sdk/python/packages/flet/src/flet/core/geolocator.py b/sdk/python/packages/flet/src/flet/core/geolocator.py deleted file mode 100644 index 439327dfe9..0000000000 --- a/sdk/python/packages/flet/src/flet/core/geolocator.py +++ /dev/null @@ -1,347 +0,0 @@ -import json -from dataclasses import dataclass -from enum import Enum -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import ( - ColorValue, - DurationValue, - OptionalControlEventCallable, - OptionalEventCallable, - OptionalNumber, -) -from flet.utils import deprecated - - -class GeolocatorPositionAccuracy(Enum): - LOWEST = "lowest" - LOW = "low" - MEDIUM = "medium" - HIGH = "high" - BEST = "best" - BEST_FOR_NAVIGATION = "bestForNavigation" - REDUCED = "reduced" - - -class GeolocatorPermissionStatus(Enum): - DENIED = "denied" - DENIED_FOREVER = "deniedForever" - WHILE_IN_USE = "whileInUse" - ALWAYS = "always" - UNABLE_TO_DETERMINE = "unableToDetermine" - - -class GeolocatorActivityType(Enum): - AUTOMOTIVE_NAVIGATION = "automotiveNavigation" - FITNESS = "fitness" - OTHER_NAVIGATION = "otherNavigation" - AIRBORNE = "airborne" - OTHER = "other" - - -@dataclass -class GeolocatorPosition: - latitude: OptionalNumber = None - longitude: OptionalNumber = None - speed: OptionalNumber = None - altitude: OptionalNumber = None - timestamp: OptionalNumber = None - accuracy: OptionalNumber = None - altitude_accuracy: OptionalNumber = None - heading: OptionalNumber = None - heading_accuracy: OptionalNumber = None - speed_accuracy: OptionalNumber = None - floor: Optional[int] = None - is_mocked: Optional[bool] = None - - -@dataclass -class GeolocatorSettings: - accuracy: Optional[GeolocatorPositionAccuracy] = None - distance_filter: Optional[int] = None - time_limit: Optional[DurationValue] = None - - -@dataclass -class GeolocatorWebSettings(GeolocatorSettings): - maximum_age: Optional[DurationValue] = None - - -@dataclass -class GeolocatorAppleSettings(GeolocatorSettings): - activity_type: Optional[GeolocatorActivityType] = None - pause_location_updates_automatically: Optional[bool] = False - show_background_location_indicator: Optional[bool] = False - allow_background_location_updates: Optional[bool] = True - - -@dataclass -class GeolocatorAndroidSettings(GeolocatorSettings): - force_location_manager: Optional[bool] = False - interval_duration: Optional[DurationValue] = False - foreground_notification_text: Optional[str] = None - foreground_notification_title: Optional[str] = None - foreground_notification_channel_name: Optional[str] = "Background Location" - foreground_notification_enable_wake_lock: Optional[bool] = False - foreground_notification_enable_wifi_lock: Optional[bool] = False - foreground_notification_set_ongoing: Optional[bool] = False - foreground_notification_color: Optional[ColorValue] = None - - -class GeolocatorPositionChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.latitude: float = d.get("lat") - self.longitude: float = d.get("long") - - -@deprecated( - reason="Geolocator control has been moved to a separate Python package: https://pypi.org/project/flet-geolocator. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Geolocator(Control): - """ - A control that allows you to fetch GPS data from your device. - This control is non-visual and should be added to `page.overlay` list. - - ----- - - Online docs: https://flet.dev/docs/controls/geolocator - """ - - def __init__( - self, - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - location_settings: Optional[GeolocatorSettings] = None, - on_position_change: OptionalEventCallable[GeolocatorPositionChangeEvent] = None, - on_error: OptionalControlEventCallable = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - self.__on_position_change = EventHandler( - lambda e: GeolocatorPositionChangeEvent(e) - ) - self._add_event_handler( - "positionChange", self.__on_position_change.get_handler() - ) - self.on_position_change = on_position_change - self.on_error = on_error - self.location_settings = location_settings - - def _get_control_name(self): - return "geolocator" - - def before_update(self): - self._set_attr_json("locationSettings", self.location_settings) - - def get_current_position( - self, - accuracy: Optional[ - GeolocatorPositionAccuracy - ] = GeolocatorPositionAccuracy.BEST, - location_settings: Optional[GeolocatorSettings] = None, - wait_timeout: Optional[float] = 25, - ) -> GeolocatorPosition: - ls = ( - location_settings - or self.location_settings - or GeolocatorSettings(accuracy=accuracy) - ) - output = self.invoke_method( - "get_current_position", - {"location_settings": self._convert_attr_json(ls)}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return ( - GeolocatorPosition(**json.loads(output)) - if output is not None - else GeolocatorPosition() - ) - - async def get_current_position_async( - self, - accuracy: Optional[ - GeolocatorPositionAccuracy - ] = GeolocatorPositionAccuracy.BEST, - location_settings: Optional[GeolocatorSettings] = None, - wait_timeout: Optional[float] = 25, - ) -> GeolocatorPosition: - ls = ( - location_settings - or self.location_settings - or GeolocatorSettings(accuracy=accuracy) - ) - output = await self.invoke_method_async( - "get_current_position", - {"location_settings": self._convert_attr_json(ls)}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return ( - GeolocatorPosition(**json.loads(output)) - if output is not None - else GeolocatorPosition() - ) - - def get_last_known_position( - self, - wait_timeout: Optional[float] = 25, - ) -> GeolocatorPosition: - assert not self.page.web, "get_last_known_position is not supported on web" - output = self.invoke_method( - "get_last_known_position", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return ( - GeolocatorPosition(**json.loads(output)) - if output is not None - else GeolocatorPosition() - ) - - async def get_last_known_position_async( - self, - wait_timeout: Optional[float] = 25, - ) -> GeolocatorPosition: - assert not self.page.web, "get_last_known_position is not supported on web" - output = await self.invoke_method_async( - "get_last_known_position", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return ( - GeolocatorPosition(**json.loads(output)) - if output is not None - else GeolocatorPosition() - ) - - def get_permission_status( - self, wait_timeout: Optional[float] = 25 - ) -> GeolocatorPermissionStatus: - p = self.invoke_method( - "get_permission_status", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return GeolocatorPermissionStatus(p) - - async def get_permission_status_async( - self, wait_timeout: Optional[float] = 25 - ) -> GeolocatorPermissionStatus: - p = await self.invoke_method_async( - "get_permission_status", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return GeolocatorPermissionStatus(p) - - def request_permission( - self, wait_timeout: Optional[float] = 25 - ) -> GeolocatorPermissionStatus: - p = self.invoke_method( - "request_permission", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return GeolocatorPermissionStatus(p) - - async def request_permission_async( - self, wait_timeout: Optional[float] = 25 - ) -> GeolocatorPermissionStatus: - p = await self.invoke_method_async( - "request_permission", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return GeolocatorPermissionStatus(p) - - def is_location_service_enabled(self, wait_timeout: Optional[float] = 10) -> bool: - enabled = self.invoke_method( - "is_location_service_enabled", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return enabled == "true" - - async def is_location_service_enabled_async( - self, wait_timeout: Optional[float] = 10 - ) -> bool: - enabled = await self.invoke_method_async( - "is_location_service_enabled", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return enabled == "true" - - def open_app_settings(self, wait_timeout: Optional[float] = 10) -> bool: - assert not self.page.web, "open_app_settings is not supported on web" - opened = self.invoke_method( - "open_app_settings", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return opened == "true" - - async def open_app_settings_async(self, wait_timeout: Optional[float] = 10) -> bool: - assert not self.page.web, "open_app_settings is not supported on web" - opened = await self.invoke_method_async( - "open_app_settings", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return opened == "true" - - def open_location_settings(self, wait_timeout: Optional[float] = 10) -> bool: - assert not self.page.web, "open_location_settings is not supported on web" - opened = self.invoke_method( - "open_location_settings", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return opened == "true" - - async def open_location_settings_async( - self, wait_timeout: Optional[float] = 10 - ) -> bool: - assert not self.page.web, "open_location_settings is not supported on web" - opened = await self.invoke_method_async( - "open_location_settings", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return opened == "true" - - @property - def on_position_change( - self, - ) -> OptionalEventCallable[GeolocatorPositionChangeEvent]: - return self.__on_position_change.handler - - @on_position_change.setter - def on_position_change( - self, handler: OptionalEventCallable[GeolocatorPositionChangeEvent] - ): - self.__on_position_change.handler = handler - self._set_attr("onPositionChange", True if handler is not None else None) - - @property - def on_error(self) -> OptionalControlEventCallable: - return self._get_attr("error") - - @on_error.setter - def on_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("error", handler) diff --git a/sdk/python/packages/flet/src/flet/core/gesture_detector.py b/sdk/python/packages/flet/src/flet/core/gesture_detector.py deleted file mode 100644 index 1e70105318..0000000000 --- a/sdk/python/packages/flet/src/flet/core/gesture_detector.py +++ /dev/null @@ -1,870 +0,0 @@ -import json -from typing import Any, Optional, Set, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.types import ( - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PointerDeviceType, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class GestureDetector(ConstrainedControl, AdaptiveControl): - """ - A control that detects gestures. - - Attempts to recognize gestures that correspond to its non-null callbacks. - - If this control has a content, it defers to that child control for its sizing behavior. If it does not have a content, it grows to fit the parent instead. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def on_pan_update1(e: ft.DragUpdateEvent): - c.top = max(0, c.top + e.delta_y) - c.left = max(0, c.left + e.delta_x) - c.update() - - def on_pan_update2(e: ft.DragUpdateEvent): - e.control.top = max(0, e.control.top + e.delta_y) - e.control.left = max(0, e.control.left + e.delta_x) - e.control.update() - - gd = ft.GestureDetector( - mouse_cursor=ft.MouseCursor.MOVE, - drag_interval=50, - on_pan_update=on_pan_update1, - ) - - c = ft.Container(gd, bgcolor=ft.colors.AMBER, width=50, height=50, left=0, top=0) - - gd1 = ft.GestureDetector( - mouse_cursor=ft.MouseCursor.MOVE, - drag_interval=10, - on_vertical_drag_update=on_pan_update2, - left=100, - top=100, - content=ft.Container(bgcolor=ft.colors.BLUE, width=50, height=50), - ) - - page.add( ft.Stack([c, gd1], width=1000, height=500)) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/gesturedetector - """ - - def __init__( - self, - content: Optional[Control] = None, - mouse_cursor: Optional[MouseCursor] = None, - drag_interval: Optional[int] = None, - hover_interval: Optional[int] = None, - exclude_from_semantics: Optional[bool] = None, - trackpad_scroll_causes_scale: Optional[bool] = None, - allowed_devices: Optional[Set[PointerDeviceType]] = None, - on_tap: OptionalEventCallable["TapEvent"] = None, - on_tap_down: OptionalEventCallable["TapEvent"] = None, - on_tap_up: OptionalEventCallable["TapEvent"] = None, - on_multi_tap: OptionalEventCallable["TapEvent"] = None, - multi_tap_touches: Optional[int] = None, - on_multi_long_press: OptionalEventCallable["LongPressEndEvent"] = None, - on_secondary_tap: OptionalEventCallable["TapEvent"] = None, - on_secondary_tap_down: OptionalEventCallable["TapEvent"] = None, - on_secondary_tap_up: OptionalEventCallable["TapEvent"] = None, - on_long_press_start: OptionalEventCallable["LongPressEndEvent"] = None, - on_long_press_end: OptionalEventCallable["LongPressEndEvent"] = None, - on_secondary_long_press_start: OptionalEventCallable[ - "LongPressEndEvent" - ] = None, - on_secondary_long_press_end: OptionalEventCallable["LongPressEndEvent"] = None, - on_double_tap: OptionalEventCallable["TapEvent"] = None, - on_double_tap_down: OptionalEventCallable["TapEvent"] = None, - on_horizontal_drag_start: OptionalEventCallable["DragStartEvent"] = None, - on_horizontal_drag_update: OptionalEventCallable["DragUpdateEvent"] = None, - on_horizontal_drag_end: OptionalEventCallable["DragEndEvent"] = None, - on_vertical_drag_start: OptionalEventCallable["DragStartEvent"] = None, - on_vertical_drag_update: OptionalEventCallable["DragUpdateEvent"] = None, - on_vertical_drag_end: OptionalEventCallable["DragEndEvent"] = None, - on_pan_start: OptionalEventCallable["DragStartEvent"] = None, - on_pan_update: OptionalEventCallable["DragUpdateEvent"] = None, - on_pan_end: OptionalEventCallable["DragEndEvent"] = None, - on_scale_start: OptionalEventCallable["ScaleStartEvent"] = None, - on_scale_update: OptionalEventCallable["ScaleUpdateEvent"] = None, - on_scale_end: OptionalEventCallable["ScaleEndEvent"] = None, - on_hover: OptionalEventCallable["HoverEvent"] = None, - on_enter: OptionalEventCallable["HoverEvent"] = None, - on_exit: OptionalEventCallable["HoverEvent"] = None, - on_scroll: OptionalEventCallable["ScrollEvent"] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__on_tap_down = EventHandler(lambda e: TapEvent(e)) - self._add_event_handler("tap_down", self.__on_tap_down.get_handler()) - - self.__on_tap_up = EventHandler(lambda e: TapEvent(e)) - self._add_event_handler("tap_up", self.__on_tap_up.get_handler()) - - self.__on_multi_tap = EventHandler(lambda e: MultiTapEvent(e)) - self._add_event_handler("multi_tap", self.__on_multi_tap.get_handler()) - - self.__on_secondary_tap_down = EventHandler(lambda e: TapEvent(e)) - self._add_event_handler( - "secondary_tap_down", self.__on_secondary_tap_down.get_handler() - ) - - self.__on_secondary_tap_up = EventHandler(lambda e: TapEvent(e)) - self._add_event_handler( - "secondary_tap_up", self.__on_secondary_tap_up.get_handler() - ) - - self.__on_long_press_start = EventHandler(lambda e: LongPressStartEvent(e)) - self._add_event_handler( - "long_press_start", self.__on_long_press_start.get_handler() - ) - - self.__on_long_press_end = EventHandler(lambda e: LongPressEndEvent(e)) - self._add_event_handler( - "long_press_end", self.__on_long_press_end.get_handler() - ) - - self.__on_secondary_long_press_start = EventHandler( - lambda e: LongPressStartEvent(e) - ) - self._add_event_handler( - "secondary_long_press_start", - self.__on_secondary_long_press_start.get_handler(), - ) - - self.__on_secondary_long_press_end = EventHandler( - lambda e: LongPressEndEvent(e) - ) - self._add_event_handler( - "secondary_long_press_end", - self.__on_secondary_long_press_end.get_handler(), - ) - self.__on_double_tap_down = EventHandler(lambda e: TapEvent(e)) - self._add_event_handler( - "double_tap_down", self.__on_double_tap_down.get_handler() - ) - - # on_horizontal_drag - - self.__on_horizontal_drag_start = EventHandler(lambda e: DragStartEvent(e)) - self._add_event_handler( - "horizontal_drag_start", self.__on_horizontal_drag_start.get_handler() - ) - self.__on_horizontal_drag_update = EventHandler(lambda e: DragUpdateEvent(e)) - self._add_event_handler( - "horizontal_drag_update", self.__on_horizontal_drag_update.get_handler() - ) - self.__on_horizontal_drag_end = EventHandler(lambda e: DragEndEvent(e)) - self._add_event_handler( - "horizontal_drag_end", self.__on_horizontal_drag_end.get_handler() - ) - - # on_vertical_drag - - self.__on_vertical_drag_start = EventHandler(lambda e: DragStartEvent(e)) - self._add_event_handler( - "vertical_drag_start", self.__on_vertical_drag_start.get_handler() - ) - self.__on_vertical_drag_update = EventHandler(lambda e: DragUpdateEvent(e)) - self._add_event_handler( - "vertical_drag_update", self.__on_vertical_drag_update.get_handler() - ) - self.__on_vertical_drag_end = EventHandler(lambda e: DragEndEvent(e)) - self._add_event_handler( - "vertical_drag_end", self.__on_vertical_drag_end.get_handler() - ) - - # on_pan - - self.__on_pan_start = EventHandler(lambda e: DragStartEvent(e)) - self._add_event_handler("pan_start", self.__on_pan_start.get_handler()) - self.__on_pan_update = EventHandler(lambda e: DragUpdateEvent(e)) - self._add_event_handler("pan_update", self.__on_pan_update.get_handler()) - self.__on_pan_end = EventHandler(lambda e: DragEndEvent(e)) - self._add_event_handler("pan_end", self.__on_pan_end.get_handler()) - - # on_scale - - self.__on_scale_start = EventHandler(lambda e: ScaleStartEvent(e)) - self._add_event_handler("scale_start", self.__on_scale_start.get_handler()) - self.__on_scale_update = EventHandler(lambda e: ScaleUpdateEvent(e)) - self._add_event_handler("scale_update", self.__on_scale_update.get_handler()) - self.__on_scale_end = EventHandler(lambda e: ScaleEndEvent(e)) - self._add_event_handler("scale_end", self.__on_scale_end.get_handler()) - - # on_hover - - self.__on_hover = EventHandler(lambda e: HoverEvent(e)) - self._add_event_handler("hover", self.__on_hover.get_handler()) - self.__on_enter = EventHandler(lambda e: HoverEvent(e)) - self._add_event_handler("enter", self.__on_enter.get_handler()) - self.__on_exit = EventHandler(lambda e: HoverEvent(e)) - self._add_event_handler("exit", self.__on_exit.get_handler()) - - # on_scroll - self.__on_scroll = EventHandler(lambda e: ScrollEvent(e)) - self._add_event_handler("scroll", self.__on_scroll.get_handler()) - - self.content = content - self.mouse_cursor = mouse_cursor - self.drag_interval = drag_interval - self.hover_interval = hover_interval - self.on_tap = on_tap - self.on_tap_down = on_tap_down - self.on_tap_up = on_tap_up - self.on_multi_tap = on_multi_tap - self.multi_tap_touches = multi_tap_touches - self.on_multi_long_press = on_multi_long_press - self.on_secondary_tap = on_secondary_tap - self.on_secondary_tap_down = on_secondary_tap_down - self.on_secondary_tap_up = on_secondary_tap_up - self.on_long_press_start = on_long_press_start - self.on_long_press_end = on_long_press_end - self.on_secondary_long_press_start = on_secondary_long_press_start - self.on_secondary_long_press_end = on_secondary_long_press_end - self.on_double_tap = on_double_tap - self.on_double_tap_down = on_double_tap_down - self.on_horizontal_drag_start = on_horizontal_drag_start - self.on_horizontal_drag_update = on_horizontal_drag_update - self.on_horizontal_drag_end = on_horizontal_drag_end - self.on_vertical_drag_start = on_vertical_drag_start - self.on_vertical_drag_update = on_vertical_drag_update - self.on_vertical_drag_end = on_vertical_drag_end - self.on_pan_start = on_pan_start - self.on_pan_update = on_pan_update - self.on_pan_end = on_pan_end - self.on_scale_start = on_scale_start - self.on_scale_update = on_scale_update - self.on_scale_end = on_scale_end - self.on_hover = on_hover - self.on_enter = on_enter - self.on_exit = on_exit - self.on_scroll = on_scroll - self.exclude_from_semantics = exclude_from_semantics - self.trackpad_scroll_causes_scale = trackpad_scroll_causes_scale - self.allowed_devices = allowed_devices - - def _get_control_name(self): - return "gesturedetector" - - def before_update(self): - super().before_update() - self._set_attr_json("allowedDevices", self.__allowed_devices) - - def _get_children(self): - children = [] - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # drag_interval - @property - def drag_interval(self) -> Optional[int]: - return self._get_attr("dragInterval", data_type="int") - - @drag_interval.setter - def drag_interval(self, value: Optional[int]): - self._set_attr("dragInterval", value) - - # hover_interval - @property - def hover_interval(self) -> Optional[int]: - return self._get_attr("hoverInterval", data_type="int") - - @hover_interval.setter - def hover_interval(self, value: Optional[int]): - self._set_attr("hoverInterval", value) - - # exclude_from_semantics - @property - def exclude_from_semantics(self) -> Optional[bool]: - return self._get_attr("excludeFromSemantics", data_type="bool", def_value=False) - - @exclude_from_semantics.setter - def exclude_from_semantics(self, value: Optional[bool]): - self._set_attr("excludeFromSemantics", value) - - # trackpad_scroll_causes_scale - @property - def trackpad_scroll_causes_scale(self) -> Optional[bool]: - return self._get_attr( - "trackpadScrollCausesScale", data_type="bool", def_value=False - ) - - @trackpad_scroll_causes_scale.setter - def trackpad_scroll_causes_scale(self, value: Optional[bool]): - self._set_attr("trackpadScrollCausesScale", value) - - # allowed_devices - @property - def allowed_devices(self) -> Optional[Set[PointerDeviceType]]: - return self.__allowed_devices - - @allowed_devices.setter - def allowed_devices(self, value: Optional[Set[PointerDeviceType]]): - self.__allowed_devices = value - - # on_tap - @property - def on_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap") - - @on_tap.setter - def on_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap", handler) - self._set_attr("onTap", True if handler is not None else None) - - # on_tap_down - @property - def on_tap_down(self) -> OptionalEventCallable["TapEvent"]: - return self.__on_tap_down.handler - - @on_tap_down.setter - def on_tap_down(self, handler: OptionalEventCallable["TapEvent"]): - self.__on_tap_down.handler = handler - self._set_attr("onTapDown", True if handler is not None else None) - - # on_tap_up - @property - def on_tap_up(self) -> OptionalEventCallable["TapEvent"]: - return self.__on_tap_up.handler - - @on_tap_up.setter - def on_tap_up(self, handler: OptionalEventCallable["TapEvent"]): - self.__on_tap_up.handler = handler - self._set_attr("onTapUp", True if handler is not None else None) - - # on_multi_tap - @property - def on_multi_tap(self) -> OptionalEventCallable["MultiTapEvent"]: - return self.__on_multi_tap.handler - - @on_multi_tap.setter - def on_multi_tap(self, handler: OptionalEventCallable["MultiTapEvent"]): - self.__on_multi_tap.handler = handler - self._set_attr("onMultiTap", True if handler is not None else None) - - # multi_tap_touches - @property - def multi_tap_touches(self) -> Optional[int]: - return self._get_attr("multiTapTouches") - - @multi_tap_touches.setter - def multi_tap_touches(self, value: Optional[int]): - self._set_attr("multiTapTouches", value) - - # on_multi_long_press - @property - def on_multi_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("multi_long_press") - - @on_multi_long_press.setter - def on_multi_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("multi_long_press", handler) - self._set_attr("onMultiLongPress", True if handler is not None else None) - - # on_secondary_tap - @property - def on_secondary_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("secondary_tap") - - @on_secondary_tap.setter - def on_secondary_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("secondary_tap", handler) - self._set_attr("onSecondaryTap", True if handler is not None else None) - - # on_tap_down - @property - def on_secondary_tap_down(self) -> OptionalEventCallable["TapEvent"]: - return self.__on_secondary_tap_down.handler - - @on_secondary_tap_down.setter - def on_secondary_tap_down(self, handler: OptionalEventCallable["TapEvent"]): - self.__on_secondary_tap_down.handler = handler - self._set_attr("onSecondaryTapDown", True if handler is not None else None) - - # on_secondary_tap_up - @property - def on_secondary_tap_up(self) -> OptionalEventCallable["TapEvent"]: - return self.__on_secondary_tap_up.handler - - @on_secondary_tap_up.setter - def on_secondary_tap_up(self, handler: OptionalEventCallable["TapEvent"]): - self.__on_secondary_tap_up.handler = handler - self._set_attr("onSecondaryTapUp", True if handler is not None else None) - - # on_long_press_start - @property - def on_long_press_start(self) -> OptionalEventCallable["LongPressStartEvent"]: - return self.__on_long_press_start.handler - - @on_long_press_start.setter - def on_long_press_start( - self, handler: OptionalEventCallable["LongPressStartEvent"] - ): - self.__on_long_press_start.handler = handler - self._set_attr("onLongPressStart", True if handler is not None else None) - - # on_long_press_end - @property - def on_long_press_end(self) -> OptionalEventCallable["LongPressEndEvent"]: - return self.__on_long_press_end.handler - - @on_long_press_end.setter - def on_long_press_end(self, handler: OptionalEventCallable["LongPressEndEvent"]): - self.__on_long_press_end.handler = handler - self._set_attr("onLongPressEnd", True if handler is not None else None) - - # on_secondary_long_press_start - @property - def on_secondary_long_press_start( - self, - ) -> OptionalEventCallable["LongPressStartEvent"]: - return self.__on_secondary_long_press_start.handler - - @on_secondary_long_press_start.setter - def on_secondary_long_press_start( - self, handler: OptionalEventCallable["LongPressStartEvent"] - ): - self.__on_secondary_long_press_start.handler = handler - self._set_attr( - "onSecondaryLongPressStart", True if handler is not None else None - ) - - # on_secondary_long_press_end - @property - def on_secondary_long_press_end(self) -> OptionalEventCallable["LongPressEndEvent"]: - return self.__on_secondary_long_press_end.handler - - @on_secondary_long_press_end.setter - def on_secondary_long_press_end( - self, handler: OptionalEventCallable["LongPressEndEvent"] - ): - self.__on_secondary_long_press_end.handler = handler - self._set_attr("onSecondaryLongPressEnd", True if handler is not None else None) - - # on_double_tap - @property - def on_double_tap(self): - return self._get_event_handler("double_tap") - - @on_double_tap.setter - def on_double_tap(self, handler: OptionalEventCallable["TapEvent"]): - self._add_event_handler("double_tap", handler) - self._set_attr("onDoubleTap", True if handler is not None else None) - - # on_double_tap_down - @property - def on_double_tap_down(self) -> OptionalEventCallable["TapEvent"]: - return self.__on_double_tap_down.handler - - @on_double_tap_down.setter - def on_double_tap_down(self, handler: OptionalEventCallable["TapEvent"]): - self.__on_double_tap_down.handler = handler - self._set_attr("onDoubleTapDown", True if handler is not None else None) - - # on_horizontal_drag_start - @property - def on_horizontal_drag_start(self) -> OptionalEventCallable["DragStartEvent"]: - return self.__on_horizontal_drag_start.handler - - @on_horizontal_drag_start.setter - def on_horizontal_drag_start( - self, handler: OptionalEventCallable["DragStartEvent"] - ): - self.__on_horizontal_drag_start.handler = handler - self._set_attr("onHorizontalDragStart", True if handler is not None else None) - - # on_horizontal_drag_update - @property - def on_horizontal_drag_update(self) -> OptionalEventCallable["DragUpdateEvent"]: - return self.__on_horizontal_drag_update.handler - - @on_horizontal_drag_update.setter - def on_horizontal_drag_update( - self, handler: OptionalEventCallable["DragUpdateEvent"] - ): - self.__on_horizontal_drag_update.handler = handler - self._set_attr("onHorizontalDragUpdate", True if handler is not None else None) - - # on_horizontal_drag_end - @property - def on_horizontal_drag_end(self) -> OptionalEventCallable["DragEndEvent"]: - return self.__on_horizontal_drag_end.handler - - @on_horizontal_drag_end.setter - def on_horizontal_drag_end(self, handler: OptionalEventCallable["DragEndEvent"]): - self.__on_horizontal_drag_end.handler = handler - self._set_attr("onHorizontalDragEnd", True if handler is not None else None) - - # on_vertical_drag_start - @property - def on_vertical_drag_start(self) -> OptionalEventCallable["DragStartEvent"]: - return self.__on_vertical_drag_start.handler - - @on_vertical_drag_start.setter - def on_vertical_drag_start(self, handler: OptionalEventCallable["DragStartEvent"]): - self.__on_vertical_drag_start.handler = handler - self._set_attr("onVerticalDragStart", True if handler is not None else None) - - # on_vertical_drag_update - @property - def on_vertical_drag_update(self) -> OptionalEventCallable["DragUpdateEvent"]: - return self.__on_vertical_drag_update.handler - - @on_vertical_drag_update.setter - def on_vertical_drag_update( - self, handler: OptionalEventCallable["DragUpdateEvent"] - ): - self.__on_vertical_drag_update.handler = handler - self._set_attr("onVerticalDragUpdate", True if handler is not None else None) - - # on_vertical_drag_end - @property - def on_vertical_drag_end(self) -> OptionalEventCallable["DragEndEvent"]: - return self.__on_vertical_drag_end.handler - - @on_vertical_drag_end.setter - def on_vertical_drag_end(self, handler: OptionalEventCallable["DragEndEvent"]): - self.__on_vertical_drag_end.handler = handler - self._set_attr("onVerticalDragEnd", True if handler is not None else None) - - # on_pan_start - @property - def on_pan_start(self) -> OptionalEventCallable["DragStartEvent"]: - return self.__on_pan_start.handler - - @on_pan_start.setter - def on_pan_start(self, handler: OptionalEventCallable["DragStartEvent"]): - self.__on_pan_start.handler = handler - self._set_attr("onPanStart", True if handler is not None else None) - - # on_pan_updatevertical_drag - @property - def on_pan_update(self) -> OptionalEventCallable["DragUpdateEvent"]: - return self.__on_pan_update.handler - - @on_pan_update.setter - def on_pan_update(self, handler: OptionalEventCallable["DragUpdateEvent"]): - self.__on_pan_update.handler = handler - self._set_attr("onPanUpdate", True if handler is not None else None) - - # on_pan_end - @property - def on_pan_end(self) -> OptionalEventCallable["DragEndEvent"]: - return self.__on_pan_end.handler - - @on_pan_end.setter - def on_pan_end(self, handler: OptionalEventCallable["DragEndEvent"]): - self.__on_pan_end.handler = handler - self._set_attr("onPanEnd", True if handler is not None else None) - - # on_scale_start - @property - def on_scale_start(self) -> OptionalEventCallable["ScaleStartEvent"]: - return self.__on_scale_start.handler - - @on_scale_start.setter - def on_scale_start(self, handler: OptionalEventCallable["ScaleStartEvent"]): - self.__on_scale_start.handler = handler - self._set_attr("onScaleStart", True if handler is not None else None) - - # on_scale_update - @property - def on_scale_update(self) -> OptionalEventCallable["ScaleUpdateEvent"]: - return self.__on_scale_update.handler - - @on_scale_update.setter - def on_scale_update(self, handler: OptionalEventCallable["ScaleUpdateEvent"]): - self.__on_scale_update.handler = handler - self._set_attr("onScaleUpdate", True if handler is not None else None) - - # on_scale_end - @property - def on_scale_end(self) -> OptionalEventCallable["ScaleEndEvent"]: - return self.__on_scale_end.handler - - @on_scale_end.setter - def on_scale_end(self, handler: OptionalEventCallable["ScaleEndEvent"]): - self.__on_scale_end.handler = handler - self._set_attr("onScaleEnd", True if handler is not None else None) - - # on_hover - @property - def on_hover(self) -> OptionalEventCallable["HoverEvent"]: - return self.__on_hover.handler - - @on_hover.setter - def on_hover(self, handler: OptionalEventCallable["HoverEvent"]): - self.__on_hover.handler = handler - self._set_attr("onHover", True if handler is not None else None) - - # on_enter - @property - def on_enter(self) -> OptionalEventCallable["HoverEvent"]: - return self.__on_enter.handler - - @on_enter.setter - def on_enter(self, handler: OptionalEventCallable["HoverEvent"]): - self.__on_enter.handler = handler - self._set_attr("onEnter", True if handler is not None else None) - - # on_exit - @property - def on_exit(self) -> OptionalEventCallable["HoverEvent"]: - return self.__on_exit.handler - - @on_exit.setter - def on_exit(self, handler: OptionalEventCallable["HoverEvent"]): - self.__on_exit.handler = handler - self._set_attr("onExit", True if handler is not None else None) - - # on_scroll - @property - def on_scroll(self) -> OptionalEventCallable["ScrollEvent"]: - return self.__on_scroll.handler - - @on_scroll.setter - def on_scroll(self, handler: OptionalEventCallable["ScrollEvent"]): - self.__on_scroll.handler = handler - self._set_attr("onScroll", True if handler is not None else None) - - -class TapEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.kind: str = d.get("kind") - - -class MultiTapEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.correct_touches: bool = e.data.lower() == "true" - - -class LongPressStartEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - - -class LongPressEndEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.velocity_x: float = d.get("vx") - self.velocity_y: float = d.get("vy") - - -class DragStartEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.kind: str = d.get("kind") - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.timestamp: Optional[int] = d.get("ts") - - -class DragUpdateEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.delta_x: float = d.get("dx") - self.delta_y: float = d.get("dy") - self.primary_delta: Optional[float] = d.get("pd") - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.timestamp: Optional[int] = d.get("ts") - - -class DragEndEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.primary_velocity: Optional[float] = d.get("pv") - self.velocity_x: float = d.get("vx") - self.velocity_y: float = d.get("vy") - - -class ScaleStartEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.focal_point_x: float = d.get("fpx") - self.focal_point_y: float = d.get("fpy") - self.local_focal_point_x: float = d.get("lfpx") - self.local_focal_point_y: float = d.get("lfpy") - self.pointer_count: int = d.get("pc") - - -class ScaleUpdateEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.focal_point_x: float = d.get("fpx") - self.focal_point_y: float = d.get("fpy") - self.focal_point_delta_x: float = d.get("fpdx") - self.focal_point_delta_y: float = d.get("fpdy") - self.local_focal_point_x: float = d.get("lfpx") - self.local_focal_point_y: float = d.get("lfpy") - self.pointer_count: int = d.get("pc") - self.horizontal_scale: float = d.get("hs") - self.vertical_scale: float = d.get("vs") - self.scale: float = d.get("s") - self.rotation: float = d.get("r") - - -class ScaleEndEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.pointer_count: int = d.get("pc") - self.velocity_x: float = d.get("vx") - self.velocity_y: float = d.get("vy") - - -class HoverEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.timestamp: float = d.get("ts") - self.kind: str = d.get("kind") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.delta_x: Optional[float] = d.get("dx") - self.delta_y: Optional[float] = d.get("dy") - - -class ScrollEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.local_x: float = d.get("lx") - self.local_y: float = d.get("ly") - self.scroll_delta_x: Optional[float] = d.get("dx") - self.scroll_delta_y: Optional[float] = d.get("dy") diff --git a/sdk/python/packages/flet/src/flet/core/gradients.py b/sdk/python/packages/flet/src/flet/core/gradients.py deleted file mode 100644 index 3671f241dc..0000000000 --- a/sdk/python/packages/flet/src/flet/core/gradients.py +++ /dev/null @@ -1,47 +0,0 @@ -import dataclasses -import math -from dataclasses import field -from enum import Enum -from typing import List, Optional, Union - -from flet.core import alignment -from flet.core.alignment import Alignment - - -class GradientTileMode(Enum): - CLAMP = "clamp" - DECAL = "decal" - MIRROR = "mirror" - REPEATED = "repeated" - - -@dataclasses.dataclass -class Gradient: - colors: List[str] - tile_mode: GradientTileMode = field(default=GradientTileMode.CLAMP) - rotation: Union[None, float, int] = field(default=None) - stops: Optional[List[float]] = field(default=None) - - -@dataclasses.dataclass -class LinearGradient(Gradient): - begin: Alignment = field(default_factory=lambda: alignment.center_left) - end: Alignment = field(default_factory=lambda: alignment.center_right) - type: str = field(default="linear") - - -@dataclasses.dataclass -class RadialGradient(Gradient): - center: Alignment = field(default_factory=lambda: alignment.center) - radius: Union[float, int] = field(default=0.5) - focal: Optional[Alignment] = field(default=None) - focal_radius: Union[float, int] = field(default=0.0) - type: str = field(default="radial") - - -@dataclasses.dataclass -class SweepGradient(Gradient): - center: Alignment = field(default_factory=lambda: alignment.center) - start_angle: Union[float, int] = field(default=0.0) - end_angle: Union[float, int] = field(default=math.pi * 2) - type: str = field(default="sweep") diff --git a/sdk/python/packages/flet/src/flet/core/grid_view.py b/sdk/python/packages/flet/src/flet/core/grid_view.py deleted file mode 100644 index ec69b9711d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/grid_view.py +++ /dev/null @@ -1,300 +0,0 @@ -from typing import Any, Callable, List, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.scrollable_control import OnScrollEvent, ScrollableControl -from flet.core.types import ( - ClipBehavior, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class GridView(ConstrainedControl, ScrollableControl, AdaptiveControl): - """ - A scrollable, 2D array of controls. - - GridView is very effective for large lists (thousands of items). Prefer it over wrapping `Column` or `Row` for smooth scrolling. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "GridView Example" - page.theme_mode = ft.ThemeMode.DARK - page.padding = 50 - page.update() - - images = ft.GridView( - expand=1, - runs_count=5, - max_extent=150, - child_aspect_ratio=1.0, - spacing=5, - run_spacing=5, - ) - - page.add(images) - - for i in range(0, 60): - images.controls.append( - ft.Image( - src=f"https://picsum.photos/150/150?{i}", - fit=ft.ImageFit.NONE, - repeat=ft.ImageRepeat.NO_REPEAT, - border_radius=ft.border_radius.all(10), - ) - ) - page.update() - - ft.app(target=main) - - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/gridview - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - horizontal: Optional[bool] = None, - runs_count: Optional[int] = None, - max_extent: Optional[int] = None, - spacing: OptionalNumber = None, - run_spacing: OptionalNumber = None, - child_aspect_ratio: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - semantic_child_count: Optional[int] = None, - build_controls_on_demand: Optional[bool] = None, - cache_extent: OptionalNumber = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - # - # ScrollableControl - # - auto_scroll: Optional[bool] = None, - reverse: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: Optional[Callable[[OnScrollEvent], None]] = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - ScrollableControl.__init__( - self, - auto_scroll=auto_scroll, - reverse=reverse, - on_scroll_interval=on_scroll_interval, - on_scroll=on_scroll, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__controls: List[Control] = [] - self.controls = controls - self.horizontal = horizontal - self.runs_count = runs_count - self.max_extent = max_extent - self.spacing = spacing - self.run_spacing = run_spacing - self.child_aspect_ratio = child_aspect_ratio - self.padding = padding - self.clip_behavior = clip_behavior - self.semantic_child_count = semantic_child_count - self.cache_extent = cache_extent - self.build_controls_on_demand = build_controls_on_demand - - def _get_control_name(self): - return "gridview" - - def __contains__(self, item): - return item in self.__controls - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - return self.__controls - - def clean(self): - super().clean() - self.__controls.clear() - - # build_controls_on_demand - @property - def build_controls_on_demand(self) -> Optional[bool]: - return self._get_attr("buildControlsOnDemand", data_type="bool", def_value=True) - - @build_controls_on_demand.setter - def build_controls_on_demand(self, value: Optional[bool]): - self._set_attr("buildControlsOnDemand", value) - - # horizontal - @property - def horizontal(self) -> bool: - return self._get_attr("horizontal", data_type="bool", def_value=False) - - @horizontal.setter - def horizontal(self, value: Optional[bool]): - self._set_attr("horizontal", value) - - # cache_extent - @property - def cache_extent(self) -> OptionalNumber: - return self._get_attr("cacheExtent") - - @cache_extent.setter - def cache_extent(self, value: OptionalNumber): - self._set_attr("cacheExtent", value) - - # runs_count - @property - def runs_count(self) -> Optional[int]: - return self._get_attr("runsCount") - - @runs_count.setter - def runs_count(self, value: Optional[int]): - self._set_attr("runsCount", value) - - # max_extent - @property - def max_extent(self) -> OptionalNumber: - return self._get_attr("maxExtent") - - @max_extent.setter - def max_extent(self, value: OptionalNumber): - self._set_attr("maxExtent", value) - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self._get_attr("spacing") - - @spacing.setter - def spacing(self, value: OptionalNumber): - self._set_attr("spacing", value) - - # run_spacing - @property - def run_spacing(self) -> OptionalNumber: - return self._get_attr("runSpacing") - - @run_spacing.setter - def run_spacing(self, value: OptionalNumber): - self._set_attr("runSpacing", value) - - # child_aspect_ratio - @property - def child_aspect_ratio(self) -> OptionalNumber: - return self._get_attr("childAspectRatio") - - @child_aspect_ratio.setter - def child_aspect_ratio(self, value: OptionalNumber): - self._set_attr("childAspectRatio", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # semantic_child_count - @property - def semantic_child_count(self) -> Optional[int]: - return self._get_attr("semanticChildCount", data_type="int") - - @semantic_child_count.setter - def semantic_child_count(self, value: Optional[int]): - self._set_attr("semanticChildCount", value) diff --git a/sdk/python/packages/flet/src/flet/core/haptic_feedback.py b/sdk/python/packages/flet/src/flet/core/haptic_feedback.py deleted file mode 100644 index 245ea7872a..0000000000 --- a/sdk/python/packages/flet/src/flet/core/haptic_feedback.py +++ /dev/null @@ -1,63 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref - - -class HapticFeedback(Control): - """ - Allows access to the haptic feedback interface on the device. - - It is non-visual and should be added to `page.overlay` list. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - hf = ft.HapticFeedback() - page.overlay.append(hf) - - page.add( - ft.ElevatedButton("Heavy impact", on_click=lambda _: hf.heavy_impact()), - ft.ElevatedButton("Medium impact", on_click=lambda _: hf.medium_impact()), - ft.ElevatedButton("Light impact", on_click=lambda _: hf.light_impact()), - ft.ElevatedButton("Vibrate", on_click=lambda _: hf.vibrate()), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/hapticfeedback - """ - - def __init__( - self, - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - - def _get_control_name(self): - return "hapticfeedback" - - def is_isolated(self): - return True - - def heavy_impact(self): - self.invoke_method("heavy_impact") - - def light_impact(self): - self.invoke_method("light_impact") - - def medium_impact(self): - self.invoke_method("medium_impact") - - def vibrate(self): - self.invoke_method("vibrate") diff --git a/sdk/python/packages/flet/src/flet/core/icon.py b/sdk/python/packages/flet/src/flet/core/icon.py deleted file mode 100644 index 1a1e04fd42..0000000000 --- a/sdk/python/packages/flet/src/flet/core/icon.py +++ /dev/null @@ -1,239 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxShadow -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BlendMode, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Icon(ConstrainedControl): - """ - Displays a Material icon. - - Icon browser: https://flet-icons-browser.fly.dev/#/ - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.add( - ft.Row( - [ - ft.Icon(name=ft.icons.FAVORITE, color=ft.colors.PINK), - ft.Icon(name=ft.icons.AUDIOTRACK, color=ft.colors.GREEN_400, size=30), - ft.Icon(name=ft.icons.BEACH_ACCESS, color=ft.colors.BLUE, size=50), - ft.Icon(name="settings", color="#c1c1c1"), - ] - ) - ) - - ft.app(target=main) - - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/icon - """ - - def __init__( - self, - name: Optional[IconValue] = None, - color: Optional[ColorValue] = None, - size: OptionalNumber = None, - semantics_label: Optional[str] = None, - shadows: Union[BoxShadow, List[BoxShadow], None] = None, - fill: OptionalNumber = None, - apply_text_scaling: Optional[bool] = None, - grade: OptionalNumber = None, - weight: OptionalNumber = None, - optical_size: OptionalNumber = None, - blend_mode: Optional[BlendMode] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.name = name - self.color = color - self.size = size - self.semantics_label = semantics_label - self.shadows = shadows - self.fill = fill - self.apply_text_scaling = apply_text_scaling - self.grade = grade - self.weight = weight - self.optical_size = optical_size - self.blend_mode = blend_mode - - def _get_control_name(self): - return "icon" - - def before_update(self): - super().before_update() - self._set_attr_json("shadows", self.__shadows) - - # name - @property - def name(self) -> Optional[IconValue]: - return self.__name - - @name.setter - def name(self, value: Optional[IconValue]): - self.__name = value - self._set_enum_attr("name", value, IconEnums) - - # blend_mode - @property - def blend_mode(self) -> Optional[BlendMode]: - return self.__blend_mode - - @blend_mode.setter - def blend_mode(self, value: Optional[BlendMode]): - self.__blend_mode = value - self._set_enum_attr("blendMode", value, BlendMode) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # size - @property - def size(self) -> OptionalNumber: - return self._get_attr("size", data_type="float") - - @size.setter - def size(self, value: OptionalNumber): - self._set_attr("size", value) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # shadows - @property - def shadows(self) -> Union[BoxShadow, List[BoxShadow], None]: - return self.__shadows - - @shadows.setter - def shadows(self, value: Union[BoxShadow, List[BoxShadow], None]): - self.__shadows = value - - # fill - @property - def fill(self) -> OptionalNumber: - return self._get_attr("fill", data_type="float") - - @fill.setter - def fill(self, value: OptionalNumber): - self._set_attr("fill", value) - - # apply_text_scaling - @property - def apply_text_scaling(self) -> Optional[bool]: - return self._get_attr("applyTextScaling", data_type="bool") - - @apply_text_scaling.setter - def apply_text_scaling(self, value: Optional[bool]): - self._set_attr("applyTextScaling", value) - - # grade - @property - def grade(self) -> OptionalNumber: - return self._get_attr("grade", data_type="float") - - @grade.setter - def grade(self, value: OptionalNumber): - self._set_attr("grade", value) - - # weight - @property - def weight(self) -> OptionalNumber: - return self._get_attr("weight", data_type="float") - - @weight.setter - def weight(self, value: OptionalNumber): - self._set_attr("weight", value) - - # optical_size - @property - def optical_size(self) -> OptionalNumber: - return self._get_attr("opticalSize", data_type="float") - - @optical_size.setter - def optical_size(self, value: OptionalNumber): - self._set_attr("opticalSize", value) diff --git a/sdk/python/packages/flet/src/flet/core/icon_button.py b/sdk/python/packages/flet/src/flet/core/icon_button.py deleted file mode 100644 index eeaa52fa8f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/icon_button.py +++ /dev/null @@ -1,484 +0,0 @@ -import time -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxConstraints -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - IconEnums, - IconValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, - VisualDensity, -) - - -class IconButton(ConstrainedControl, AdaptiveControl): - """ - An icon button is a round button with an icon in the middle that reacts to touches by filling with color (ink). - - Icon buttons are commonly used in the toolbars, but they can be used in many other places as well. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Icon buttons" - page.add( - ft.Row( - [ - ft.IconButton( - icon=ft.icons.PAUSE_CIRCLE_FILLED_ROUNDED, - icon_color="blue400", - icon_size=20, - tooltip="Pause record", - ), - ft.IconButton( - icon=ft.icons.DELETE_FOREVER_ROUNDED, - icon_color="pink600", - icon_size=40, - tooltip="Delete record", - ), - ] - ), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/iconbutton - """ - - def __init__( - self, - icon: Optional[IconValue] = None, - icon_color: Optional[ColorValue] = None, - icon_size: OptionalNumber = None, - selected: Optional[bool] = None, - selected_icon: Optional[IconValue] = None, - selected_icon_color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - highlight_color: Optional[ColorValue] = None, - style: Optional[ButtonStyle] = None, - content: Optional[Control] = None, - autofocus: Optional[bool] = None, - disabled_color: Optional[ColorValue] = None, - hover_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - splash_color: Optional[ColorValue] = None, - splash_radius: OptionalNumber = None, - alignment: Optional[Alignment] = None, - padding: Optional[PaddingValue] = None, - enable_feedback: Optional[bool] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - mouse_cursor: Optional[MouseCursor] = None, - visual_density: Optional[VisualDensity] = None, - size_constraints: Optional[BoxConstraints] = None, - on_click: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.icon = icon - self.icon_size = icon_size - self.icon_color = icon_color - self.highlight_color = highlight_color - self.selected_icon = selected_icon - self.selected_icon_color = selected_icon_color - self.selected = selected - self.bgcolor = bgcolor - self.style = style - self.content = content - self.autofocus = autofocus - self.disabled_color = disabled_color - self.hover_color = hover_color - self.alignment = alignment - self.padding = padding - self.enable_feedback = enable_feedback - self.splash_color = splash_color - self.splash_radius = splash_radius - self.focus_color = focus_color - self.url = url - self.url_target = url_target - self.on_click = on_click - self.on_focus = on_focus - self.on_blur = on_blur - self.mouse_cursor = mouse_cursor - self.visual_density = visual_density - self.size_constraints = size_constraints - self.on_long_press = on_long_press - self.on_hover = on_hover - - def _get_control_name(self): - return "iconbutton" - - def before_update(self): - super().before_update() - if self.__style is not None: - self.__style.side = self._wrap_attr_dict(self.__style.side) - self.__style.shape = self._wrap_attr_dict(self.__style.shape) - self.__style.padding = self._wrap_attr_dict(self.__style.padding) - self._set_attr_json("style", self.__style) - self._set_attr_json("alignment", self.__alignment) - self._set_attr_json("padding", self.__padding) - self._set_attr_json("sizeConstraints", self.__size_constraints) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # selected_icon - @property - def selected_icon(self) -> Optional[IconValue]: - return self.__selected_icon - - @selected_icon.setter - def selected_icon(self, value: Optional[IconValue]): - self.__selected_icon = value - self._set_enum_attr("selectedIcon", value, IconEnums) - - # icon_size - @property - def icon_size(self) -> OptionalNumber: - return self._get_attr("iconSize", data_type="float") - - @icon_size.setter - def icon_size(self, value: OptionalNumber): - self._set_attr("iconSize", value) - - # splash_radius - @property - def splash_radius(self) -> OptionalNumber: - return self._get_attr("splashRadius", data_type="float") - - @splash_radius.setter - def splash_radius(self, value: OptionalNumber): - self._set_attr("splashRadius", value) - - # splash_color - @property - def splash_color(self) -> Optional[ColorValue]: - return self.__splash_color - - @splash_color.setter - def splash_color(self, value: Optional[ColorValue]): - self.__splash_color = value - self._set_enum_attr("splashColor", value, ColorEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # highlight_color - @property - def highlight_color(self) -> Optional[ColorValue]: - return self.__highlight_color - - @highlight_color.setter - def highlight_color(self, value: Optional[ColorValue]): - self.__highlight_color = value - self._set_enum_attr("highlightColor", value, ColorEnums) - - # selected_icon_color - @property - def selected_icon_color(self) -> Optional[ColorValue]: - return self.__selected_icon_color - - @selected_icon_color.setter - def selected_icon_color(self, value: Optional[ColorValue]): - self.__selected_icon_color = value - self._set_enum_attr("selectedIconColor", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # hover_color - @property - def hover_color(self) -> Optional[ColorValue]: - return self.__hover_color - - @hover_color.setter - def hover_color(self, value: Optional[ColorValue]): - self.__hover_color = value - self._set_enum_attr("hoverColor", value, ColorEnums) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # disabled_color - @property - def disabled_color(self) -> Optional[ColorValue]: - return self.__disabled_color - - @disabled_color.setter - def disabled_color(self, value: Optional[ColorValue]): - self.__disabled_color = value - self._set_enum_attr("disabledColor", value, ColorEnums) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # size_constraints - @property - def size_constraints(self) -> Optional[BoxConstraints]: - return self.__size_constraints - - @size_constraints.setter - def size_constraints(self, value: Optional[BoxConstraints]): - self.__size_constraints = value - - # selected - @property - def selected(self) -> bool: - return self._get_attr("selected", data_type="bool", def_value=False) - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # enable_feedback - @property - def enable_feedback(self) -> bool: - return self._get_attr("enableFeedback", data_type="bool", def_value=True) - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # visual_density - @property - def visual_density(self) -> Optional[VisualDensity]: - return self.__visual_density - - @visual_density.setter - def visual_density(self, value: Optional[VisualDensity]): - self.__visual_density = value - self._set_enum_attr("visualDensity", value, VisualDensity) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # on_hover - @property - def on_hover(self) -> OptionalControlEventCallable: - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value diff --git a/sdk/python/packages/flet/src/flet/core/icons.py b/sdk/python/packages/flet/src/flet/core/icons.py deleted file mode 100644 index 11cd51464a..0000000000 --- a/sdk/python/packages/flet/src/flet/core/icons.py +++ /dev/null @@ -1,8896 +0,0 @@ -""" -Flet Material Icons - -To generate/update these values run: - -sh ci/generate_material_icons_python.sh -""" - -import random -from enum import Enum -from typing import Dict, List, Optional - - -class Icons(str, Enum): - @staticmethod - def random( - exclude: Optional[List["Icons"]] = None, - weights: Optional[Dict["Icons", int]] = None, - ) -> Optional["Icons"]: - """ - Selects a random icon, with optional exclusions and weights. - - Args: - exclude: A list of icons members to exclude from the selection. - weights: A dictionary mapping icon members to their respective weights for weighted random selection. - - Returns: - A randomly selected icon, or None if all members are excluded. - """ - choices = list(Icons) - if exclude: - choices = [member for member in choices if member not in exclude] - if not choices: - return None - if weights: - weights_list = [weights.get(c, 1) for c in choices] - return random.choices(choices, weights=weights_list)[0] - return random.choice(choices) - - TEN_K = "ten_k" - TEN_K_SHARP = "ten_k_sharp" - TEN_K_ROUNDED = "ten_k_rounded" - TEN_K_OUTLINED = "ten_k_outlined" - TEN_MP = "ten_mp" - TEN_MP_SHARP = "ten_mp_sharp" - TEN_MP_ROUNDED = "ten_mp_rounded" - TEN_MP_OUTLINED = "ten_mp_outlined" - ELEVEN_MP = "eleven_mp" - ELEVEN_MP_SHARP = "eleven_mp_sharp" - ELEVEN_MP_ROUNDED = "eleven_mp_rounded" - ELEVEN_MP_OUTLINED = "eleven_mp_outlined" - ONETWOTHREE = "onetwothree" - ONETWOTHREE_SHARP = "onetwothree_sharp" - ONETWOTHREE_ROUNDED = "onetwothree_rounded" - ONETWOTHREE_OUTLINED = "onetwothree_outlined" - TWELVE_MP = "twelve_mp" - TWELVE_MP_SHARP = "twelve_mp_sharp" - TWELVE_MP_ROUNDED = "twelve_mp_rounded" - TWELVE_MP_OUTLINED = "twelve_mp_outlined" - THIRTEEN_MP = "thirteen_mp" - THIRTEEN_MP_SHARP = "thirteen_mp_sharp" - THIRTEEN_MP_ROUNDED = "thirteen_mp_rounded" - THIRTEEN_MP_OUTLINED = "thirteen_mp_outlined" - FOURTEEN_MP = "fourteen_mp" - FOURTEEN_MP_SHARP = "fourteen_mp_sharp" - FOURTEEN_MP_ROUNDED = "fourteen_mp_rounded" - FOURTEEN_MP_OUTLINED = "fourteen_mp_outlined" - FIFTEEN_MP = "fifteen_mp" - FIFTEEN_MP_SHARP = "fifteen_mp_sharp" - FIFTEEN_MP_ROUNDED = "fifteen_mp_rounded" - FIFTEEN_MP_OUTLINED = "fifteen_mp_outlined" - SIXTEEN_MP = "sixteen_mp" - SIXTEEN_MP_SHARP = "sixteen_mp_sharp" - SIXTEEN_MP_ROUNDED = "sixteen_mp_rounded" - SIXTEEN_MP_OUTLINED = "sixteen_mp_outlined" - SEVENTEEN_MP = "seventeen_mp" - SEVENTEEN_MP_SHARP = "seventeen_mp_sharp" - SEVENTEEN_MP_ROUNDED = "seventeen_mp_rounded" - SEVENTEEN_MP_OUTLINED = "seventeen_mp_outlined" - EIGHTEEN_UP_RATING = "eighteen_up_rating" - EIGHTEEN_UP_RATING_SHARP = "eighteen_up_rating_sharp" - EIGHTEEN_UP_RATING_ROUNDED = "eighteen_up_rating_rounded" - EIGHTEEN_UP_RATING_OUTLINED = "eighteen_up_rating_outlined" - EIGHTEEN_MP = "eighteen_mp" - EIGHTEEN_MP_SHARP = "eighteen_mp_sharp" - EIGHTEEN_MP_ROUNDED = "eighteen_mp_rounded" - EIGHTEEN_MP_OUTLINED = "eighteen_mp_outlined" - NINETEEN_MP = "nineteen_mp" - NINETEEN_MP_SHARP = "nineteen_mp_sharp" - NINETEEN_MP_ROUNDED = "nineteen_mp_rounded" - NINETEEN_MP_OUTLINED = "nineteen_mp_outlined" - ONE_K = "one_k" - ONE_K_SHARP = "one_k_sharp" - ONE_K_ROUNDED = "one_k_rounded" - ONE_K_OUTLINED = "one_k_outlined" - ONE_K_PLUS = "one_k_plus" - ONE_K_PLUS_SHARP = "one_k_plus_sharp" - ONE_K_PLUS_ROUNDED = "one_k_plus_rounded" - ONE_K_PLUS_OUTLINED = "one_k_plus_outlined" - ONE_X_MOBILEDATA = "one_x_mobiledata" - ONE_X_MOBILEDATA_SHARP = "one_x_mobiledata_sharp" - ONE_X_MOBILEDATA_ROUNDED = "one_x_mobiledata_rounded" - ONE_X_MOBILEDATA_OUTLINED = "one_x_mobiledata_outlined" - TWENTY_MP = "twenty_mp" - TWENTY_MP_SHARP = "twenty_mp_sharp" - TWENTY_MP_ROUNDED = "twenty_mp_rounded" - TWENTY_MP_OUTLINED = "twenty_mp_outlined" - TWENTY_ONE_MP = "twenty_one_mp" - TWENTY_ONE_MP_SHARP = "twenty_one_mp_sharp" - TWENTY_ONE_MP_ROUNDED = "twenty_one_mp_rounded" - TWENTY_ONE_MP_OUTLINED = "twenty_one_mp_outlined" - TWENTY_TWO_MP = "twenty_two_mp" - TWENTY_TWO_MP_SHARP = "twenty_two_mp_sharp" - TWENTY_TWO_MP_ROUNDED = "twenty_two_mp_rounded" - TWENTY_TWO_MP_OUTLINED = "twenty_two_mp_outlined" - TWENTY_THREE_MP = "twenty_three_mp" - TWENTY_THREE_MP_SHARP = "twenty_three_mp_sharp" - TWENTY_THREE_MP_ROUNDED = "twenty_three_mp_rounded" - TWENTY_THREE_MP_OUTLINED = "twenty_three_mp_outlined" - TWENTY_FOUR_MP = "twenty_four_mp" - TWENTY_FOUR_MP_SHARP = "twenty_four_mp_sharp" - TWENTY_FOUR_MP_ROUNDED = "twenty_four_mp_rounded" - TWENTY_FOUR_MP_OUTLINED = "twenty_four_mp_outlined" - TWO_K = "two_k" - TWO_K_SHARP = "two_k_sharp" - TWO_K_ROUNDED = "two_k_rounded" - TWO_K_OUTLINED = "two_k_outlined" - TWO_K_PLUS = "two_k_plus" - TWO_K_PLUS_SHARP = "two_k_plus_sharp" - TWO_K_PLUS_ROUNDED = "two_k_plus_rounded" - TWO_K_PLUS_OUTLINED = "two_k_plus_outlined" - TWO_MP = "two_mp" - TWO_MP_SHARP = "two_mp_sharp" - TWO_MP_ROUNDED = "two_mp_rounded" - TWO_MP_OUTLINED = "two_mp_outlined" - THIRTY_FPS = "thirty_fps" - THIRTY_FPS_SHARP = "thirty_fps_sharp" - THIRTY_FPS_ROUNDED = "thirty_fps_rounded" - THIRTY_FPS_OUTLINED = "thirty_fps_outlined" - THIRTY_FPS_SELECT = "thirty_fps_select" - THIRTY_FPS_SELECT_SHARP = "thirty_fps_select_sharp" - THIRTY_FPS_SELECT_ROUNDED = "thirty_fps_select_rounded" - THIRTY_FPS_SELECT_OUTLINED = "thirty_fps_select_outlined" - THREESIXTY = "threesixty" - THREESIXTY_SHARP = "threesixty_sharp" - THREESIXTY_ROUNDED = "threesixty_rounded" - THREESIXTY_OUTLINED = "threesixty_outlined" - THREED_ROTATION = "threed_rotation" - THREED_ROTATION_SHARP = "threed_rotation_sharp" - THREED_ROTATION_ROUNDED = "threed_rotation_rounded" - THREED_ROTATION_OUTLINED = "threed_rotation_outlined" - THREE_G_MOBILEDATA = "three_g_mobiledata" - THREE_G_MOBILEDATA_SHARP = "three_g_mobiledata_sharp" - THREE_G_MOBILEDATA_ROUNDED = "three_g_mobiledata_rounded" - THREE_G_MOBILEDATA_OUTLINED = "three_g_mobiledata_outlined" - THREE_K = "three_k" - THREE_K_SHARP = "three_k_sharp" - THREE_K_ROUNDED = "three_k_rounded" - THREE_K_OUTLINED = "three_k_outlined" - THREE_K_PLUS = "three_k_plus" - THREE_K_PLUS_SHARP = "three_k_plus_sharp" - THREE_K_PLUS_ROUNDED = "three_k_plus_rounded" - THREE_K_PLUS_OUTLINED = "three_k_plus_outlined" - THREE_MP = "three_mp" - THREE_MP_SHARP = "three_mp_sharp" - THREE_MP_ROUNDED = "three_mp_rounded" - THREE_MP_OUTLINED = "three_mp_outlined" - THREE_P = "three_p" - THREE_P_SHARP = "three_p_sharp" - THREE_P_ROUNDED = "three_p_rounded" - THREE_P_OUTLINED = "three_p_outlined" - FOUR_G_MOBILEDATA = "four_g_mobiledata" - FOUR_G_MOBILEDATA_SHARP = "four_g_mobiledata_sharp" - FOUR_G_MOBILEDATA_ROUNDED = "four_g_mobiledata_rounded" - FOUR_G_MOBILEDATA_OUTLINED = "four_g_mobiledata_outlined" - FOUR_G_PLUS_MOBILEDATA = "four_g_plus_mobiledata" - FOUR_G_PLUS_MOBILEDATA_SHARP = "four_g_plus_mobiledata_sharp" - FOUR_G_PLUS_MOBILEDATA_ROUNDED = "four_g_plus_mobiledata_rounded" - FOUR_G_PLUS_MOBILEDATA_OUTLINED = "four_g_plus_mobiledata_outlined" - FOUR_K = "four_k" - FOUR_K_SHARP = "four_k_sharp" - FOUR_K_ROUNDED = "four_k_rounded" - FOUR_K_OUTLINED = "four_k_outlined" - FOUR_K_PLUS = "four_k_plus" - FOUR_K_PLUS_SHARP = "four_k_plus_sharp" - FOUR_K_PLUS_ROUNDED = "four_k_plus_rounded" - FOUR_K_PLUS_OUTLINED = "four_k_plus_outlined" - FOUR_MP = "four_mp" - FOUR_MP_SHARP = "four_mp_sharp" - FOUR_MP_ROUNDED = "four_mp_rounded" - FOUR_MP_OUTLINED = "four_mp_outlined" - FIVE_G = "five_g" - FIVE_G_SHARP = "five_g_sharp" - FIVE_G_ROUNDED = "five_g_rounded" - FIVE_G_OUTLINED = "five_g_outlined" - FIVE_K = "five_k" - FIVE_K_SHARP = "five_k_sharp" - FIVE_K_ROUNDED = "five_k_rounded" - FIVE_K_OUTLINED = "five_k_outlined" - FIVE_K_PLUS = "five_k_plus" - FIVE_K_PLUS_SHARP = "five_k_plus_sharp" - FIVE_K_PLUS_ROUNDED = "five_k_plus_rounded" - FIVE_K_PLUS_OUTLINED = "five_k_plus_outlined" - FIVE_MP = "five_mp" - FIVE_MP_SHARP = "five_mp_sharp" - FIVE_MP_ROUNDED = "five_mp_rounded" - FIVE_MP_OUTLINED = "five_mp_outlined" - SIXTY_FPS = "sixty_fps" - SIXTY_FPS_SHARP = "sixty_fps_sharp" - SIXTY_FPS_ROUNDED = "sixty_fps_rounded" - SIXTY_FPS_OUTLINED = "sixty_fps_outlined" - SIXTY_FPS_SELECT = "sixty_fps_select" - SIXTY_FPS_SELECT_SHARP = "sixty_fps_select_sharp" - SIXTY_FPS_SELECT_ROUNDED = "sixty_fps_select_rounded" - SIXTY_FPS_SELECT_OUTLINED = "sixty_fps_select_outlined" - SIX_FT_APART = "six_ft_apart" - SIX_FT_APART_SHARP = "six_ft_apart_sharp" - SIX_FT_APART_ROUNDED = "six_ft_apart_rounded" - SIX_FT_APART_OUTLINED = "six_ft_apart_outlined" - SIX_K = "six_k" - SIX_K_SHARP = "six_k_sharp" - SIX_K_ROUNDED = "six_k_rounded" - SIX_K_OUTLINED = "six_k_outlined" - SIX_K_PLUS = "six_k_plus" - SIX_K_PLUS_SHARP = "six_k_plus_sharp" - SIX_K_PLUS_ROUNDED = "six_k_plus_rounded" - SIX_K_PLUS_OUTLINED = "six_k_plus_outlined" - SIX_MP = "six_mp" - SIX_MP_SHARP = "six_mp_sharp" - SIX_MP_ROUNDED = "six_mp_rounded" - SIX_MP_OUTLINED = "six_mp_outlined" - SEVEN_K = "seven_k" - SEVEN_K_SHARP = "seven_k_sharp" - SEVEN_K_ROUNDED = "seven_k_rounded" - SEVEN_K_OUTLINED = "seven_k_outlined" - SEVEN_K_PLUS = "seven_k_plus" - SEVEN_K_PLUS_SHARP = "seven_k_plus_sharp" - SEVEN_K_PLUS_ROUNDED = "seven_k_plus_rounded" - SEVEN_K_PLUS_OUTLINED = "seven_k_plus_outlined" - SEVEN_MP = "seven_mp" - SEVEN_MP_SHARP = "seven_mp_sharp" - SEVEN_MP_ROUNDED = "seven_mp_rounded" - SEVEN_MP_OUTLINED = "seven_mp_outlined" - EIGHT_K = "eight_k" - EIGHT_K_SHARP = "eight_k_sharp" - EIGHT_K_ROUNDED = "eight_k_rounded" - EIGHT_K_OUTLINED = "eight_k_outlined" - EIGHT_K_PLUS = "eight_k_plus" - EIGHT_K_PLUS_SHARP = "eight_k_plus_sharp" - EIGHT_K_PLUS_ROUNDED = "eight_k_plus_rounded" - EIGHT_K_PLUS_OUTLINED = "eight_k_plus_outlined" - EIGHT_MP = "eight_mp" - EIGHT_MP_SHARP = "eight_mp_sharp" - EIGHT_MP_ROUNDED = "eight_mp_rounded" - EIGHT_MP_OUTLINED = "eight_mp_outlined" - NINE_K = "nine_k" - NINE_K_SHARP = "nine_k_sharp" - NINE_K_ROUNDED = "nine_k_rounded" - NINE_K_OUTLINED = "nine_k_outlined" - NINE_K_PLUS = "nine_k_plus" - NINE_K_PLUS_SHARP = "nine_k_plus_sharp" - NINE_K_PLUS_ROUNDED = "nine_k_plus_rounded" - NINE_K_PLUS_OUTLINED = "nine_k_plus_outlined" - NINE_MP = "nine_mp" - NINE_MP_SHARP = "nine_mp_sharp" - NINE_MP_ROUNDED = "nine_mp_rounded" - NINE_MP_OUTLINED = "nine_mp_outlined" - ABC = "abc" - ABC_SHARP = "abc_sharp" - ABC_ROUNDED = "abc_rounded" - ABC_OUTLINED = "abc_outlined" - AC_UNIT = "ac_unit" - AC_UNIT_SHARP = "ac_unit_sharp" - AC_UNIT_ROUNDED = "ac_unit_rounded" - AC_UNIT_OUTLINED = "ac_unit_outlined" - ACCESS_ALARM = "access_alarm" - ACCESS_ALARM_SHARP = "access_alarm_sharp" - ACCESS_ALARM_ROUNDED = "access_alarm_rounded" - ACCESS_ALARM_OUTLINED = "access_alarm_outlined" - ACCESS_ALARMS = "access_alarms" - ACCESS_ALARMS_SHARP = "access_alarms_sharp" - ACCESS_ALARMS_ROUNDED = "access_alarms_rounded" - ACCESS_ALARMS_OUTLINED = "access_alarms_outlined" - ACCESS_TIME = "access_time" - ACCESS_TIME_SHARP = "access_time_sharp" - ACCESS_TIME_ROUNDED = "access_time_rounded" - ACCESS_TIME_OUTLINED = "access_time_outlined" - ACCESS_TIME_FILLED = "access_time_filled" - ACCESS_TIME_FILLED_SHARP = "access_time_filled_sharp" - ACCESS_TIME_FILLED_ROUNDED = "access_time_filled_rounded" - ACCESS_TIME_FILLED_OUTLINED = "access_time_filled_outlined" - ACCESSIBILITY = "accessibility" - ACCESSIBILITY_SHARP = "accessibility_sharp" - ACCESSIBILITY_ROUNDED = "accessibility_rounded" - ACCESSIBILITY_OUTLINED = "accessibility_outlined" - ACCESSIBILITY_NEW = "accessibility_new" - ACCESSIBILITY_NEW_SHARP = "accessibility_new_sharp" - ACCESSIBILITY_NEW_ROUNDED = "accessibility_new_rounded" - ACCESSIBILITY_NEW_OUTLINED = "accessibility_new_outlined" - ACCESSIBLE = "accessible" - ACCESSIBLE_SHARP = "accessible_sharp" - ACCESSIBLE_ROUNDED = "accessible_rounded" - ACCESSIBLE_OUTLINED = "accessible_outlined" - ACCESSIBLE_FORWARD = "accessible_forward" - ACCESSIBLE_FORWARD_SHARP = "accessible_forward_sharp" - ACCESSIBLE_FORWARD_ROUNDED = "accessible_forward_rounded" - ACCESSIBLE_FORWARD_OUTLINED = "accessible_forward_outlined" - ACCOUNT_BALANCE = "account_balance" - ACCOUNT_BALANCE_SHARP = "account_balance_sharp" - ACCOUNT_BALANCE_ROUNDED = "account_balance_rounded" - ACCOUNT_BALANCE_OUTLINED = "account_balance_outlined" - ACCOUNT_BALANCE_WALLET = "account_balance_wallet" - ACCOUNT_BALANCE_WALLET_SHARP = "account_balance_wallet_sharp" - ACCOUNT_BALANCE_WALLET_ROUNDED = "account_balance_wallet_rounded" - ACCOUNT_BALANCE_WALLET_OUTLINED = "account_balance_wallet_outlined" - ACCOUNT_BOX = "account_box" - ACCOUNT_BOX_SHARP = "account_box_sharp" - ACCOUNT_BOX_ROUNDED = "account_box_rounded" - ACCOUNT_BOX_OUTLINED = "account_box_outlined" - ACCOUNT_CIRCLE = "account_circle" - ACCOUNT_CIRCLE_SHARP = "account_circle_sharp" - ACCOUNT_CIRCLE_ROUNDED = "account_circle_rounded" - ACCOUNT_CIRCLE_OUTLINED = "account_circle_outlined" - ACCOUNT_TREE = "account_tree" - ACCOUNT_TREE_SHARP = "account_tree_sharp" - ACCOUNT_TREE_ROUNDED = "account_tree_rounded" - ACCOUNT_TREE_OUTLINED = "account_tree_outlined" - AD_UNITS = "ad_units" - AD_UNITS_SHARP = "ad_units_sharp" - AD_UNITS_ROUNDED = "ad_units_rounded" - AD_UNITS_OUTLINED = "ad_units_outlined" - ADB = "adb" - ADB_SHARP = "adb_sharp" - ADB_ROUNDED = "adb_rounded" - ADB_OUTLINED = "adb_outlined" - ADD = "add" - ADD_SHARP = "add_sharp" - ADD_ROUNDED = "add_rounded" - ADD_OUTLINED = "add_outlined" - ADD_A_PHOTO = "add_a_photo" - ADD_A_PHOTO_SHARP = "add_a_photo_sharp" - ADD_A_PHOTO_ROUNDED = "add_a_photo_rounded" - ADD_A_PHOTO_OUTLINED = "add_a_photo_outlined" - ADD_ALARM = "add_alarm" - ADD_ALARM_SHARP = "add_alarm_sharp" - ADD_ALARM_ROUNDED = "add_alarm_rounded" - ADD_ALARM_OUTLINED = "add_alarm_outlined" - ADD_ALERT = "add_alert" - ADD_ALERT_SHARP = "add_alert_sharp" - ADD_ALERT_ROUNDED = "add_alert_rounded" - ADD_ALERT_OUTLINED = "add_alert_outlined" - ADD_BOX = "add_box" - ADD_BOX_SHARP = "add_box_sharp" - ADD_BOX_ROUNDED = "add_box_rounded" - ADD_BOX_OUTLINED = "add_box_outlined" - ADD_BUSINESS = "add_business" - ADD_BUSINESS_SHARP = "add_business_sharp" - ADD_BUSINESS_ROUNDED = "add_business_rounded" - ADD_BUSINESS_OUTLINED = "add_business_outlined" - ADD_CALL = "add_call" - ADD_CARD = "add_card" - ADD_CARD_SHARP = "add_card_sharp" - ADD_CARD_ROUNDED = "add_card_rounded" - ADD_CARD_OUTLINED = "add_card_outlined" - ADD_CHART = "add_chart" - ADD_CHART_SHARP = "add_chart_sharp" - ADD_CHART_ROUNDED = "add_chart_rounded" - ADD_CHART_OUTLINED = "add_chart_outlined" - ADD_CIRCLE = "add_circle" - ADD_CIRCLE_SHARP = "add_circle_sharp" - ADD_CIRCLE_ROUNDED = "add_circle_rounded" - ADD_CIRCLE_OUTLINED = "add_circle_outlined" - ADD_CIRCLE_OUTLINE = "add_circle_outline" - ADD_CIRCLE_OUTLINE_SHARP = "add_circle_outline_sharp" - ADD_CIRCLE_OUTLINE_ROUNDED = "add_circle_outline_rounded" - ADD_CIRCLE_OUTLINE_OUTLINED = "add_circle_outline_outlined" - ADD_COMMENT = "add_comment" - ADD_COMMENT_SHARP = "add_comment_sharp" - ADD_COMMENT_ROUNDED = "add_comment_rounded" - ADD_COMMENT_OUTLINED = "add_comment_outlined" - ADD_HOME = "add_home" - ADD_HOME_SHARP = "add_home_sharp" - ADD_HOME_ROUNDED = "add_home_rounded" - ADD_HOME_OUTLINED = "add_home_outlined" - ADD_HOME_WORK = "add_home_work" - ADD_HOME_WORK_SHARP = "add_home_work_sharp" - ADD_HOME_WORK_ROUNDED = "add_home_work_rounded" - ADD_HOME_WORK_OUTLINED = "add_home_work_outlined" - ADD_IC_CALL = "add_ic_call" - ADD_IC_CALL_SHARP = "add_ic_call_sharp" - ADD_IC_CALL_ROUNDED = "add_ic_call_rounded" - ADD_IC_CALL_OUTLINED = "add_ic_call_outlined" - ADD_LINK = "add_link" - ADD_LINK_SHARP = "add_link_sharp" - ADD_LINK_ROUNDED = "add_link_rounded" - ADD_LINK_OUTLINED = "add_link_outlined" - ADD_LOCATION = "add_location" - ADD_LOCATION_SHARP = "add_location_sharp" - ADD_LOCATION_ROUNDED = "add_location_rounded" - ADD_LOCATION_OUTLINED = "add_location_outlined" - ADD_LOCATION_ALT = "add_location_alt" - ADD_LOCATION_ALT_SHARP = "add_location_alt_sharp" - ADD_LOCATION_ALT_ROUNDED = "add_location_alt_rounded" - ADD_LOCATION_ALT_OUTLINED = "add_location_alt_outlined" - ADD_MODERATOR = "add_moderator" - ADD_MODERATOR_SHARP = "add_moderator_sharp" - ADD_MODERATOR_ROUNDED = "add_moderator_rounded" - ADD_MODERATOR_OUTLINED = "add_moderator_outlined" - ADD_PHOTO_ALTERNATE = "add_photo_alternate" - ADD_PHOTO_ALTERNATE_SHARP = "add_photo_alternate_sharp" - ADD_PHOTO_ALTERNATE_ROUNDED = "add_photo_alternate_rounded" - ADD_PHOTO_ALTERNATE_OUTLINED = "add_photo_alternate_outlined" - ADD_REACTION = "add_reaction" - ADD_REACTION_SHARP = "add_reaction_sharp" - ADD_REACTION_ROUNDED = "add_reaction_rounded" - ADD_REACTION_OUTLINED = "add_reaction_outlined" - ADD_ROAD = "add_road" - ADD_ROAD_SHARP = "add_road_sharp" - ADD_ROAD_ROUNDED = "add_road_rounded" - ADD_ROAD_OUTLINED = "add_road_outlined" - ADD_SHOPPING_CART = "add_shopping_cart" - ADD_SHOPPING_CART_SHARP = "add_shopping_cart_sharp" - ADD_SHOPPING_CART_ROUNDED = "add_shopping_cart_rounded" - ADD_SHOPPING_CART_OUTLINED = "add_shopping_cart_outlined" - ADD_TASK = "add_task" - ADD_TASK_SHARP = "add_task_sharp" - ADD_TASK_ROUNDED = "add_task_rounded" - ADD_TASK_OUTLINED = "add_task_outlined" - ADD_TO_DRIVE = "add_to_drive" - ADD_TO_DRIVE_SHARP = "add_to_drive_sharp" - ADD_TO_DRIVE_ROUNDED = "add_to_drive_rounded" - ADD_TO_DRIVE_OUTLINED = "add_to_drive_outlined" - ADD_TO_HOME_SCREEN = "add_to_home_screen" - ADD_TO_HOME_SCREEN_SHARP = "add_to_home_screen_sharp" - ADD_TO_HOME_SCREEN_ROUNDED = "add_to_home_screen_rounded" - ADD_TO_HOME_SCREEN_OUTLINED = "add_to_home_screen_outlined" - ADD_TO_PHOTOS = "add_to_photos" - ADD_TO_PHOTOS_SHARP = "add_to_photos_sharp" - ADD_TO_PHOTOS_ROUNDED = "add_to_photos_rounded" - ADD_TO_PHOTOS_OUTLINED = "add_to_photos_outlined" - ADD_TO_QUEUE = "add_to_queue" - ADD_TO_QUEUE_SHARP = "add_to_queue_sharp" - ADD_TO_QUEUE_ROUNDED = "add_to_queue_rounded" - ADD_TO_QUEUE_OUTLINED = "add_to_queue_outlined" - ADDCHART = "addchart" - ADDCHART_SHARP = "addchart_sharp" - ADDCHART_ROUNDED = "addchart_rounded" - ADDCHART_OUTLINED = "addchart_outlined" - ADF_SCANNER = "adf_scanner" - ADF_SCANNER_SHARP = "adf_scanner_sharp" - ADF_SCANNER_ROUNDED = "adf_scanner_rounded" - ADF_SCANNER_OUTLINED = "adf_scanner_outlined" - ADJUST = "adjust" - ADJUST_SHARP = "adjust_sharp" - ADJUST_ROUNDED = "adjust_rounded" - ADJUST_OUTLINED = "adjust_outlined" - ADMIN_PANEL_SETTINGS = "admin_panel_settings" - ADMIN_PANEL_SETTINGS_SHARP = "admin_panel_settings_sharp" - ADMIN_PANEL_SETTINGS_ROUNDED = "admin_panel_settings_rounded" - ADMIN_PANEL_SETTINGS_OUTLINED = "admin_panel_settings_outlined" - ADOBE = "adobe" - ADOBE_SHARP = "adobe_sharp" - ADOBE_ROUNDED = "adobe_rounded" - ADOBE_OUTLINED = "adobe_outlined" - ADS_CLICK = "ads_click" - ADS_CLICK_SHARP = "ads_click_sharp" - ADS_CLICK_ROUNDED = "ads_click_rounded" - ADS_CLICK_OUTLINED = "ads_click_outlined" - AGRICULTURE = "agriculture" - AGRICULTURE_SHARP = "agriculture_sharp" - AGRICULTURE_ROUNDED = "agriculture_rounded" - AGRICULTURE_OUTLINED = "agriculture_outlined" - AIR = "air" - AIR_SHARP = "air_sharp" - AIR_ROUNDED = "air_rounded" - AIR_OUTLINED = "air_outlined" - AIRLINE_SEAT_FLAT = "airline_seat_flat" - AIRLINE_SEAT_FLAT_SHARP = "airline_seat_flat_sharp" - AIRLINE_SEAT_FLAT_ROUNDED = "airline_seat_flat_rounded" - AIRLINE_SEAT_FLAT_OUTLINED = "airline_seat_flat_outlined" - AIRLINE_SEAT_FLAT_ANGLED = "airline_seat_flat_angled" - AIRLINE_SEAT_FLAT_ANGLED_SHARP = "airline_seat_flat_angled_sharp" - AIRLINE_SEAT_FLAT_ANGLED_ROUNDED = "airline_seat_flat_angled_rounded" - AIRLINE_SEAT_FLAT_ANGLED_OUTLINED = "airline_seat_flat_angled_outlined" - AIRLINE_SEAT_INDIVIDUAL_SUITE = "airline_seat_individual_suite" - AIRLINE_SEAT_INDIVIDUAL_SUITE_SHARP = "airline_seat_individual_suite_sharp" - AIRLINE_SEAT_INDIVIDUAL_SUITE_ROUNDED = "airline_seat_individual_suite_rounded" - AIRLINE_SEAT_INDIVIDUAL_SUITE_OUTLINED = "airline_seat_individual_suite_outlined" - AIRLINE_SEAT_LEGROOM_EXTRA = "airline_seat_legroom_extra" - AIRLINE_SEAT_LEGROOM_EXTRA_SHARP = "airline_seat_legroom_extra_sharp" - AIRLINE_SEAT_LEGROOM_EXTRA_ROUNDED = "airline_seat_legroom_extra_rounded" - AIRLINE_SEAT_LEGROOM_EXTRA_OUTLINED = "airline_seat_legroom_extra_outlined" - AIRLINE_SEAT_LEGROOM_NORMAL = "airline_seat_legroom_normal" - AIRLINE_SEAT_LEGROOM_NORMAL_SHARP = "airline_seat_legroom_normal_sharp" - AIRLINE_SEAT_LEGROOM_NORMAL_ROUNDED = "airline_seat_legroom_normal_rounded" - AIRLINE_SEAT_LEGROOM_NORMAL_OUTLINED = "airline_seat_legroom_normal_outlined" - AIRLINE_SEAT_LEGROOM_REDUCED = "airline_seat_legroom_reduced" - AIRLINE_SEAT_LEGROOM_REDUCED_SHARP = "airline_seat_legroom_reduced_sharp" - AIRLINE_SEAT_LEGROOM_REDUCED_ROUNDED = "airline_seat_legroom_reduced_rounded" - AIRLINE_SEAT_LEGROOM_REDUCED_OUTLINED = "airline_seat_legroom_reduced_outlined" - AIRLINE_SEAT_RECLINE_EXTRA = "airline_seat_recline_extra" - AIRLINE_SEAT_RECLINE_EXTRA_SHARP = "airline_seat_recline_extra_sharp" - AIRLINE_SEAT_RECLINE_EXTRA_ROUNDED = "airline_seat_recline_extra_rounded" - AIRLINE_SEAT_RECLINE_EXTRA_OUTLINED = "airline_seat_recline_extra_outlined" - AIRLINE_SEAT_RECLINE_NORMAL = "airline_seat_recline_normal" - AIRLINE_SEAT_RECLINE_NORMAL_SHARP = "airline_seat_recline_normal_sharp" - AIRLINE_SEAT_RECLINE_NORMAL_ROUNDED = "airline_seat_recline_normal_rounded" - AIRLINE_SEAT_RECLINE_NORMAL_OUTLINED = "airline_seat_recline_normal_outlined" - AIRLINE_STOPS = "airline_stops" - AIRLINE_STOPS_SHARP = "airline_stops_sharp" - AIRLINE_STOPS_ROUNDED = "airline_stops_rounded" - AIRLINE_STOPS_OUTLINED = "airline_stops_outlined" - AIRLINES = "airlines" - AIRLINES_SHARP = "airlines_sharp" - AIRLINES_ROUNDED = "airlines_rounded" - AIRLINES_OUTLINED = "airlines_outlined" - AIRPLANE_TICKET = "airplane_ticket" - AIRPLANE_TICKET_SHARP = "airplane_ticket_sharp" - AIRPLANE_TICKET_ROUNDED = "airplane_ticket_rounded" - AIRPLANE_TICKET_OUTLINED = "airplane_ticket_outlined" - AIRPLANEMODE_ACTIVE = "airplanemode_active" - AIRPLANEMODE_ACTIVE_SHARP = "airplanemode_active_sharp" - AIRPLANEMODE_ACTIVE_ROUNDED = "airplanemode_active_rounded" - AIRPLANEMODE_ACTIVE_OUTLINED = "airplanemode_active_outlined" - AIRPLANEMODE_INACTIVE = "airplanemode_inactive" - AIRPLANEMODE_INACTIVE_SHARP = "airplanemode_inactive_sharp" - AIRPLANEMODE_INACTIVE_ROUNDED = "airplanemode_inactive_rounded" - AIRPLANEMODE_INACTIVE_OUTLINED = "airplanemode_inactive_outlined" - AIRPLANEMODE_OFF = "airplanemode_off" - AIRPLANEMODE_OFF_SHARP = "airplanemode_off_sharp" - AIRPLANEMODE_OFF_ROUNDED = "airplanemode_off_rounded" - AIRPLANEMODE_OFF_OUTLINED = "airplanemode_off_outlined" - AIRPLANEMODE_ON = "airplanemode_on" - AIRPLANEMODE_ON_SHARP = "airplanemode_on_sharp" - AIRPLANEMODE_ON_ROUNDED = "airplanemode_on_rounded" - AIRPLANEMODE_ON_OUTLINED = "airplanemode_on_outlined" - AIRPLAY = "airplay" - AIRPLAY_SHARP = "airplay_sharp" - AIRPLAY_ROUNDED = "airplay_rounded" - AIRPLAY_OUTLINED = "airplay_outlined" - AIRPORT_SHUTTLE = "airport_shuttle" - AIRPORT_SHUTTLE_SHARP = "airport_shuttle_sharp" - AIRPORT_SHUTTLE_ROUNDED = "airport_shuttle_rounded" - AIRPORT_SHUTTLE_OUTLINED = "airport_shuttle_outlined" - ALARM = "alarm" - ALARM_SHARP = "alarm_sharp" - ALARM_ROUNDED = "alarm_rounded" - ALARM_OUTLINED = "alarm_outlined" - ALARM_ADD = "alarm_add" - ALARM_ADD_SHARP = "alarm_add_sharp" - ALARM_ADD_ROUNDED = "alarm_add_rounded" - ALARM_ADD_OUTLINED = "alarm_add_outlined" - ALARM_OFF = "alarm_off" - ALARM_OFF_SHARP = "alarm_off_sharp" - ALARM_OFF_ROUNDED = "alarm_off_rounded" - ALARM_OFF_OUTLINED = "alarm_off_outlined" - ALARM_ON = "alarm_on" - ALARM_ON_SHARP = "alarm_on_sharp" - ALARM_ON_ROUNDED = "alarm_on_rounded" - ALARM_ON_OUTLINED = "alarm_on_outlined" - ALBUM = "album" - ALBUM_SHARP = "album_sharp" - ALBUM_ROUNDED = "album_rounded" - ALBUM_OUTLINED = "album_outlined" - ALIGN_HORIZONTAL_CENTER = "align_horizontal_center" - ALIGN_HORIZONTAL_CENTER_SHARP = "align_horizontal_center_sharp" - ALIGN_HORIZONTAL_CENTER_ROUNDED = "align_horizontal_center_rounded" - ALIGN_HORIZONTAL_CENTER_OUTLINED = "align_horizontal_center_outlined" - ALIGN_HORIZONTAL_LEFT = "align_horizontal_left" - ALIGN_HORIZONTAL_LEFT_SHARP = "align_horizontal_left_sharp" - ALIGN_HORIZONTAL_LEFT_ROUNDED = "align_horizontal_left_rounded" - ALIGN_HORIZONTAL_LEFT_OUTLINED = "align_horizontal_left_outlined" - ALIGN_HORIZONTAL_RIGHT = "align_horizontal_right" - ALIGN_HORIZONTAL_RIGHT_SHARP = "align_horizontal_right_sharp" - ALIGN_HORIZONTAL_RIGHT_ROUNDED = "align_horizontal_right_rounded" - ALIGN_HORIZONTAL_RIGHT_OUTLINED = "align_horizontal_right_outlined" - ALIGN_VERTICAL_BOTTOM = "align_vertical_bottom" - ALIGN_VERTICAL_BOTTOM_SHARP = "align_vertical_bottom_sharp" - ALIGN_VERTICAL_BOTTOM_ROUNDED = "align_vertical_bottom_rounded" - ALIGN_VERTICAL_BOTTOM_OUTLINED = "align_vertical_bottom_outlined" - ALIGN_VERTICAL_CENTER = "align_vertical_center" - ALIGN_VERTICAL_CENTER_SHARP = "align_vertical_center_sharp" - ALIGN_VERTICAL_CENTER_ROUNDED = "align_vertical_center_rounded" - ALIGN_VERTICAL_CENTER_OUTLINED = "align_vertical_center_outlined" - ALIGN_VERTICAL_TOP = "align_vertical_top" - ALIGN_VERTICAL_TOP_SHARP = "align_vertical_top_sharp" - ALIGN_VERTICAL_TOP_ROUNDED = "align_vertical_top_rounded" - ALIGN_VERTICAL_TOP_OUTLINED = "align_vertical_top_outlined" - ALL_INBOX = "all_inbox" - ALL_INBOX_SHARP = "all_inbox_sharp" - ALL_INBOX_ROUNDED = "all_inbox_rounded" - ALL_INBOX_OUTLINED = "all_inbox_outlined" - ALL_INCLUSIVE = "all_inclusive" - ALL_INCLUSIVE_SHARP = "all_inclusive_sharp" - ALL_INCLUSIVE_ROUNDED = "all_inclusive_rounded" - ALL_INCLUSIVE_OUTLINED = "all_inclusive_outlined" - ALL_OUT = "all_out" - ALL_OUT_SHARP = "all_out_sharp" - ALL_OUT_ROUNDED = "all_out_rounded" - ALL_OUT_OUTLINED = "all_out_outlined" - ALT_ROUTE = "alt_route" - ALT_ROUTE_SHARP = "alt_route_sharp" - ALT_ROUTE_ROUNDED = "alt_route_rounded" - ALT_ROUTE_OUTLINED = "alt_route_outlined" - ALTERNATE_EMAIL = "alternate_email" - ALTERNATE_EMAIL_SHARP = "alternate_email_sharp" - ALTERNATE_EMAIL_ROUNDED = "alternate_email_rounded" - ALTERNATE_EMAIL_OUTLINED = "alternate_email_outlined" - AMP_STORIES = "amp_stories" - AMP_STORIES_SHARP = "amp_stories_sharp" - AMP_STORIES_ROUNDED = "amp_stories_rounded" - AMP_STORIES_OUTLINED = "amp_stories_outlined" - ANALYTICS = "analytics" - ANALYTICS_SHARP = "analytics_sharp" - ANALYTICS_ROUNDED = "analytics_rounded" - ANALYTICS_OUTLINED = "analytics_outlined" - ANCHOR = "anchor" - ANCHOR_SHARP = "anchor_sharp" - ANCHOR_ROUNDED = "anchor_rounded" - ANCHOR_OUTLINED = "anchor_outlined" - ANDROID = "android" - ANDROID_SHARP = "android_sharp" - ANDROID_ROUNDED = "android_rounded" - ANDROID_OUTLINED = "android_outlined" - ANIMATION = "animation" - ANIMATION_SHARP = "animation_sharp" - ANIMATION_ROUNDED = "animation_rounded" - ANIMATION_OUTLINED = "animation_outlined" - ANNOUNCEMENT = "announcement" - ANNOUNCEMENT_SHARP = "announcement_sharp" - ANNOUNCEMENT_ROUNDED = "announcement_rounded" - ANNOUNCEMENT_OUTLINED = "announcement_outlined" - AOD = "aod" - AOD_SHARP = "aod_sharp" - AOD_ROUNDED = "aod_rounded" - AOD_OUTLINED = "aod_outlined" - APARTMENT = "apartment" - APARTMENT_SHARP = "apartment_sharp" - APARTMENT_ROUNDED = "apartment_rounded" - APARTMENT_OUTLINED = "apartment_outlined" - API = "api" - API_SHARP = "api_sharp" - API_ROUNDED = "api_rounded" - API_OUTLINED = "api_outlined" - APP_BLOCKING = "app_blocking" - APP_BLOCKING_SHARP = "app_blocking_sharp" - APP_BLOCKING_ROUNDED = "app_blocking_rounded" - APP_BLOCKING_OUTLINED = "app_blocking_outlined" - APP_REGISTRATION = "app_registration" - APP_REGISTRATION_SHARP = "app_registration_sharp" - APP_REGISTRATION_ROUNDED = "app_registration_rounded" - APP_REGISTRATION_OUTLINED = "app_registration_outlined" - APP_SETTINGS_ALT = "app_settings_alt" - APP_SETTINGS_ALT_SHARP = "app_settings_alt_sharp" - APP_SETTINGS_ALT_ROUNDED = "app_settings_alt_rounded" - APP_SETTINGS_ALT_OUTLINED = "app_settings_alt_outlined" - APP_SHORTCUT = "app_shortcut" - APP_SHORTCUT_SHARP = "app_shortcut_sharp" - APP_SHORTCUT_ROUNDED = "app_shortcut_rounded" - APP_SHORTCUT_OUTLINED = "app_shortcut_outlined" - APPLE = "apple" - APPLE_SHARP = "apple_sharp" - APPLE_ROUNDED = "apple_rounded" - APPLE_OUTLINED = "apple_outlined" - APPROVAL = "approval" - APPROVAL_SHARP = "approval_sharp" - APPROVAL_ROUNDED = "approval_rounded" - APPROVAL_OUTLINED = "approval_outlined" - APPS = "apps" - APPS_SHARP = "apps_sharp" - APPS_ROUNDED = "apps_rounded" - APPS_OUTLINED = "apps_outlined" - APPS_OUTAGE = "apps_outage" - APPS_OUTAGE_SHARP = "apps_outage_sharp" - APPS_OUTAGE_ROUNDED = "apps_outage_rounded" - APPS_OUTAGE_OUTLINED = "apps_outage_outlined" - ARCHITECTURE = "architecture" - ARCHITECTURE_SHARP = "architecture_sharp" - ARCHITECTURE_ROUNDED = "architecture_rounded" - ARCHITECTURE_OUTLINED = "architecture_outlined" - ARCHIVE = "archive" - ARCHIVE_SHARP = "archive_sharp" - ARCHIVE_ROUNDED = "archive_rounded" - ARCHIVE_OUTLINED = "archive_outlined" - AREA_CHART = "area_chart" - AREA_CHART_SHARP = "area_chart_sharp" - AREA_CHART_ROUNDED = "area_chart_rounded" - AREA_CHART_OUTLINED = "area_chart_outlined" - ARROW_BACK = "arrow_back" - ARROW_BACK_SHARP = "arrow_back_sharp" - ARROW_BACK_ROUNDED = "arrow_back_rounded" - ARROW_BACK_OUTLINED = "arrow_back_outlined" - ARROW_BACK_IOS = "arrow_back_ios" - ARROW_BACK_IOS_SHARP = "arrow_back_ios_sharp" - ARROW_BACK_IOS_ROUNDED = "arrow_back_ios_rounded" - ARROW_BACK_IOS_OUTLINED = "arrow_back_ios_outlined" - ARROW_BACK_IOS_NEW = "arrow_back_ios_new" - ARROW_BACK_IOS_NEW_SHARP = "arrow_back_ios_new_sharp" - ARROW_BACK_IOS_NEW_ROUNDED = "arrow_back_ios_new_rounded" - ARROW_BACK_IOS_NEW_OUTLINED = "arrow_back_ios_new_outlined" - ARROW_CIRCLE_DOWN = "arrow_circle_down" - ARROW_CIRCLE_DOWN_SHARP = "arrow_circle_down_sharp" - ARROW_CIRCLE_DOWN_ROUNDED = "arrow_circle_down_rounded" - ARROW_CIRCLE_DOWN_OUTLINED = "arrow_circle_down_outlined" - ARROW_CIRCLE_LEFT = "arrow_circle_left" - ARROW_CIRCLE_LEFT_SHARP = "arrow_circle_left_sharp" - ARROW_CIRCLE_LEFT_ROUNDED = "arrow_circle_left_rounded" - ARROW_CIRCLE_LEFT_OUTLINED = "arrow_circle_left_outlined" - ARROW_CIRCLE_RIGHT = "arrow_circle_right" - ARROW_CIRCLE_RIGHT_SHARP = "arrow_circle_right_sharp" - ARROW_CIRCLE_RIGHT_ROUNDED = "arrow_circle_right_rounded" - ARROW_CIRCLE_RIGHT_OUTLINED = "arrow_circle_right_outlined" - ARROW_CIRCLE_UP = "arrow_circle_up" - ARROW_CIRCLE_UP_SHARP = "arrow_circle_up_sharp" - ARROW_CIRCLE_UP_ROUNDED = "arrow_circle_up_rounded" - ARROW_CIRCLE_UP_OUTLINED = "arrow_circle_up_outlined" - ARROW_DOWNWARD = "arrow_downward" - ARROW_DOWNWARD_SHARP = "arrow_downward_sharp" - ARROW_DOWNWARD_ROUNDED = "arrow_downward_rounded" - ARROW_DOWNWARD_OUTLINED = "arrow_downward_outlined" - ARROW_DROP_DOWN = "arrow_drop_down" - ARROW_DROP_DOWN_SHARP = "arrow_drop_down_sharp" - ARROW_DROP_DOWN_ROUNDED = "arrow_drop_down_rounded" - ARROW_DROP_DOWN_OUTLINED = "arrow_drop_down_outlined" - ARROW_DROP_DOWN_CIRCLE = "arrow_drop_down_circle" - ARROW_DROP_DOWN_CIRCLE_SHARP = "arrow_drop_down_circle_sharp" - ARROW_DROP_DOWN_CIRCLE_ROUNDED = "arrow_drop_down_circle_rounded" - ARROW_DROP_DOWN_CIRCLE_OUTLINED = "arrow_drop_down_circle_outlined" - ARROW_DROP_UP = "arrow_drop_up" - ARROW_DROP_UP_SHARP = "arrow_drop_up_sharp" - ARROW_DROP_UP_ROUNDED = "arrow_drop_up_rounded" - ARROW_DROP_UP_OUTLINED = "arrow_drop_up_outlined" - ARROW_FORWARD = "arrow_forward" - ARROW_FORWARD_SHARP = "arrow_forward_sharp" - ARROW_FORWARD_ROUNDED = "arrow_forward_rounded" - ARROW_FORWARD_OUTLINED = "arrow_forward_outlined" - ARROW_FORWARD_IOS = "arrow_forward_ios" - ARROW_FORWARD_IOS_SHARP = "arrow_forward_ios_sharp" - ARROW_FORWARD_IOS_ROUNDED = "arrow_forward_ios_rounded" - ARROW_FORWARD_IOS_OUTLINED = "arrow_forward_ios_outlined" - ARROW_LEFT = "arrow_left" - ARROW_LEFT_SHARP = "arrow_left_sharp" - ARROW_LEFT_ROUNDED = "arrow_left_rounded" - ARROW_LEFT_OUTLINED = "arrow_left_outlined" - ARROW_OUTWARD = "arrow_outward" - ARROW_OUTWARD_SHARP = "arrow_outward_sharp" - ARROW_OUTWARD_ROUNDED = "arrow_outward_rounded" - ARROW_OUTWARD_OUTLINED = "arrow_outward_outlined" - ARROW_RIGHT = "arrow_right" - ARROW_RIGHT_SHARP = "arrow_right_sharp" - ARROW_RIGHT_ROUNDED = "arrow_right_rounded" - ARROW_RIGHT_OUTLINED = "arrow_right_outlined" - ARROW_RIGHT_ALT = "arrow_right_alt" - ARROW_RIGHT_ALT_SHARP = "arrow_right_alt_sharp" - ARROW_RIGHT_ALT_ROUNDED = "arrow_right_alt_rounded" - ARROW_RIGHT_ALT_OUTLINED = "arrow_right_alt_outlined" - ARROW_UPWARD = "arrow_upward" - ARROW_UPWARD_SHARP = "arrow_upward_sharp" - ARROW_UPWARD_ROUNDED = "arrow_upward_rounded" - ARROW_UPWARD_OUTLINED = "arrow_upward_outlined" - ART_TRACK = "art_track" - ART_TRACK_SHARP = "art_track_sharp" - ART_TRACK_ROUNDED = "art_track_rounded" - ART_TRACK_OUTLINED = "art_track_outlined" - ARTICLE = "article" - ARTICLE_SHARP = "article_sharp" - ARTICLE_ROUNDED = "article_rounded" - ARTICLE_OUTLINED = "article_outlined" - ASPECT_RATIO = "aspect_ratio" - ASPECT_RATIO_SHARP = "aspect_ratio_sharp" - ASPECT_RATIO_ROUNDED = "aspect_ratio_rounded" - ASPECT_RATIO_OUTLINED = "aspect_ratio_outlined" - ASSESSMENT = "assessment" - ASSESSMENT_SHARP = "assessment_sharp" - ASSESSMENT_ROUNDED = "assessment_rounded" - ASSESSMENT_OUTLINED = "assessment_outlined" - ASSIGNMENT = "assignment" - ASSIGNMENT_SHARP = "assignment_sharp" - ASSIGNMENT_ROUNDED = "assignment_rounded" - ASSIGNMENT_OUTLINED = "assignment_outlined" - ASSIGNMENT_ADD = "assignment_add" - ASSIGNMENT_IND = "assignment_ind" - ASSIGNMENT_IND_SHARP = "assignment_ind_sharp" - ASSIGNMENT_IND_ROUNDED = "assignment_ind_rounded" - ASSIGNMENT_IND_OUTLINED = "assignment_ind_outlined" - ASSIGNMENT_LATE = "assignment_late" - ASSIGNMENT_LATE_SHARP = "assignment_late_sharp" - ASSIGNMENT_LATE_ROUNDED = "assignment_late_rounded" - ASSIGNMENT_LATE_OUTLINED = "assignment_late_outlined" - ASSIGNMENT_RETURN = "assignment_return" - ASSIGNMENT_RETURN_SHARP = "assignment_return_sharp" - ASSIGNMENT_RETURN_ROUNDED = "assignment_return_rounded" - ASSIGNMENT_RETURN_OUTLINED = "assignment_return_outlined" - ASSIGNMENT_RETURNED = "assignment_returned" - ASSIGNMENT_RETURNED_SHARP = "assignment_returned_sharp" - ASSIGNMENT_RETURNED_ROUNDED = "assignment_returned_rounded" - ASSIGNMENT_RETURNED_OUTLINED = "assignment_returned_outlined" - ASSIGNMENT_TURNED_IN = "assignment_turned_in" - ASSIGNMENT_TURNED_IN_SHARP = "assignment_turned_in_sharp" - ASSIGNMENT_TURNED_IN_ROUNDED = "assignment_turned_in_rounded" - ASSIGNMENT_TURNED_IN_OUTLINED = "assignment_turned_in_outlined" - ASSIST_WALKER = "assist_walker" - ASSIST_WALKER_SHARP = "assist_walker_sharp" - ASSIST_WALKER_ROUNDED = "assist_walker_rounded" - ASSIST_WALKER_OUTLINED = "assist_walker_outlined" - ASSISTANT = "assistant" - ASSISTANT_SHARP = "assistant_sharp" - ASSISTANT_ROUNDED = "assistant_rounded" - ASSISTANT_OUTLINED = "assistant_outlined" - ASSISTANT_DIRECTION = "assistant_direction" - ASSISTANT_DIRECTION_SHARP = "assistant_direction_sharp" - ASSISTANT_DIRECTION_ROUNDED = "assistant_direction_rounded" - ASSISTANT_DIRECTION_OUTLINED = "assistant_direction_outlined" - ASSISTANT_NAVIGATION = "assistant_navigation" - ASSISTANT_PHOTO = "assistant_photo" - ASSISTANT_PHOTO_SHARP = "assistant_photo_sharp" - ASSISTANT_PHOTO_ROUNDED = "assistant_photo_rounded" - ASSISTANT_PHOTO_OUTLINED = "assistant_photo_outlined" - ASSURED_WORKLOAD = "assured_workload" - ASSURED_WORKLOAD_SHARP = "assured_workload_sharp" - ASSURED_WORKLOAD_ROUNDED = "assured_workload_rounded" - ASSURED_WORKLOAD_OUTLINED = "assured_workload_outlined" - ATM = "atm" - ATM_SHARP = "atm_sharp" - ATM_ROUNDED = "atm_rounded" - ATM_OUTLINED = "atm_outlined" - ATTACH_EMAIL = "attach_email" - ATTACH_EMAIL_SHARP = "attach_email_sharp" - ATTACH_EMAIL_ROUNDED = "attach_email_rounded" - ATTACH_EMAIL_OUTLINED = "attach_email_outlined" - ATTACH_FILE = "attach_file" - ATTACH_FILE_SHARP = "attach_file_sharp" - ATTACH_FILE_ROUNDED = "attach_file_rounded" - ATTACH_FILE_OUTLINED = "attach_file_outlined" - ATTACH_MONEY = "attach_money" - ATTACH_MONEY_SHARP = "attach_money_sharp" - ATTACH_MONEY_ROUNDED = "attach_money_rounded" - ATTACH_MONEY_OUTLINED = "attach_money_outlined" - ATTACHMENT = "attachment" - ATTACHMENT_SHARP = "attachment_sharp" - ATTACHMENT_ROUNDED = "attachment_rounded" - ATTACHMENT_OUTLINED = "attachment_outlined" - ATTRACTIONS = "attractions" - ATTRACTIONS_SHARP = "attractions_sharp" - ATTRACTIONS_ROUNDED = "attractions_rounded" - ATTRACTIONS_OUTLINED = "attractions_outlined" - ATTRIBUTION = "attribution" - ATTRIBUTION_SHARP = "attribution_sharp" - ATTRIBUTION_ROUNDED = "attribution_rounded" - ATTRIBUTION_OUTLINED = "attribution_outlined" - AUDIO_FILE = "audio_file" - AUDIO_FILE_SHARP = "audio_file_sharp" - AUDIO_FILE_ROUNDED = "audio_file_rounded" - AUDIO_FILE_OUTLINED = "audio_file_outlined" - AUDIOTRACK = "audiotrack" - AUDIOTRACK_SHARP = "audiotrack_sharp" - AUDIOTRACK_ROUNDED = "audiotrack_rounded" - AUDIOTRACK_OUTLINED = "audiotrack_outlined" - AUTO_AWESOME = "auto_awesome" - AUTO_AWESOME_SHARP = "auto_awesome_sharp" - AUTO_AWESOME_ROUNDED = "auto_awesome_rounded" - AUTO_AWESOME_OUTLINED = "auto_awesome_outlined" - AUTO_AWESOME_MOSAIC = "auto_awesome_mosaic" - AUTO_AWESOME_MOSAIC_SHARP = "auto_awesome_mosaic_sharp" - AUTO_AWESOME_MOSAIC_ROUNDED = "auto_awesome_mosaic_rounded" - AUTO_AWESOME_MOSAIC_OUTLINED = "auto_awesome_mosaic_outlined" - AUTO_AWESOME_MOTION = "auto_awesome_motion" - AUTO_AWESOME_MOTION_SHARP = "auto_awesome_motion_sharp" - AUTO_AWESOME_MOTION_ROUNDED = "auto_awesome_motion_rounded" - AUTO_AWESOME_MOTION_OUTLINED = "auto_awesome_motion_outlined" - AUTO_DELETE = "auto_delete" - AUTO_DELETE_SHARP = "auto_delete_sharp" - AUTO_DELETE_ROUNDED = "auto_delete_rounded" - AUTO_DELETE_OUTLINED = "auto_delete_outlined" - AUTO_FIX_HIGH = "auto_fix_high" - AUTO_FIX_HIGH_SHARP = "auto_fix_high_sharp" - AUTO_FIX_HIGH_ROUNDED = "auto_fix_high_rounded" - AUTO_FIX_HIGH_OUTLINED = "auto_fix_high_outlined" - AUTO_FIX_NORMAL = "auto_fix_normal" - AUTO_FIX_NORMAL_SHARP = "auto_fix_normal_sharp" - AUTO_FIX_NORMAL_ROUNDED = "auto_fix_normal_rounded" - AUTO_FIX_NORMAL_OUTLINED = "auto_fix_normal_outlined" - AUTO_FIX_OFF = "auto_fix_off" - AUTO_FIX_OFF_SHARP = "auto_fix_off_sharp" - AUTO_FIX_OFF_ROUNDED = "auto_fix_off_rounded" - AUTO_FIX_OFF_OUTLINED = "auto_fix_off_outlined" - AUTO_GRAPH = "auto_graph" - AUTO_GRAPH_SHARP = "auto_graph_sharp" - AUTO_GRAPH_ROUNDED = "auto_graph_rounded" - AUTO_GRAPH_OUTLINED = "auto_graph_outlined" - AUTO_MODE = "auto_mode" - AUTO_MODE_SHARP = "auto_mode_sharp" - AUTO_MODE_ROUNDED = "auto_mode_rounded" - AUTO_MODE_OUTLINED = "auto_mode_outlined" - AUTO_STORIES = "auto_stories" - AUTO_STORIES_SHARP = "auto_stories_sharp" - AUTO_STORIES_ROUNDED = "auto_stories_rounded" - AUTO_STORIES_OUTLINED = "auto_stories_outlined" - AUTOFPS_SELECT = "autofps_select" - AUTOFPS_SELECT_SHARP = "autofps_select_sharp" - AUTOFPS_SELECT_ROUNDED = "autofps_select_rounded" - AUTOFPS_SELECT_OUTLINED = "autofps_select_outlined" - AUTORENEW = "autorenew" - AUTORENEW_SHARP = "autorenew_sharp" - AUTORENEW_ROUNDED = "autorenew_rounded" - AUTORENEW_OUTLINED = "autorenew_outlined" - AV_TIMER = "av_timer" - AV_TIMER_SHARP = "av_timer_sharp" - AV_TIMER_ROUNDED = "av_timer_rounded" - AV_TIMER_OUTLINED = "av_timer_outlined" - BABY_CHANGING_STATION = "baby_changing_station" - BABY_CHANGING_STATION_SHARP = "baby_changing_station_sharp" - BABY_CHANGING_STATION_ROUNDED = "baby_changing_station_rounded" - BABY_CHANGING_STATION_OUTLINED = "baby_changing_station_outlined" - BACK_HAND = "back_hand" - BACK_HAND_SHARP = "back_hand_sharp" - BACK_HAND_ROUNDED = "back_hand_rounded" - BACK_HAND_OUTLINED = "back_hand_outlined" - BACKPACK = "backpack" - BACKPACK_SHARP = "backpack_sharp" - BACKPACK_ROUNDED = "backpack_rounded" - BACKPACK_OUTLINED = "backpack_outlined" - BACKSPACE = "backspace" - BACKSPACE_SHARP = "backspace_sharp" - BACKSPACE_ROUNDED = "backspace_rounded" - BACKSPACE_OUTLINED = "backspace_outlined" - BACKUP = "backup" - BACKUP_SHARP = "backup_sharp" - BACKUP_ROUNDED = "backup_rounded" - BACKUP_OUTLINED = "backup_outlined" - BACKUP_TABLE = "backup_table" - BACKUP_TABLE_SHARP = "backup_table_sharp" - BACKUP_TABLE_ROUNDED = "backup_table_rounded" - BACKUP_TABLE_OUTLINED = "backup_table_outlined" - BADGE = "badge" - BADGE_SHARP = "badge_sharp" - BADGE_ROUNDED = "badge_rounded" - BADGE_OUTLINED = "badge_outlined" - BAKERY_DINING = "bakery_dining" - BAKERY_DINING_SHARP = "bakery_dining_sharp" - BAKERY_DINING_ROUNDED = "bakery_dining_rounded" - BAKERY_DINING_OUTLINED = "bakery_dining_outlined" - BALANCE = "balance" - BALANCE_SHARP = "balance_sharp" - BALANCE_ROUNDED = "balance_rounded" - BALANCE_OUTLINED = "balance_outlined" - BALCONY = "balcony" - BALCONY_SHARP = "balcony_sharp" - BALCONY_ROUNDED = "balcony_rounded" - BALCONY_OUTLINED = "balcony_outlined" - BALLOT = "ballot" - BALLOT_SHARP = "ballot_sharp" - BALLOT_ROUNDED = "ballot_rounded" - BALLOT_OUTLINED = "ballot_outlined" - BAR_CHART = "bar_chart" - BAR_CHART_SHARP = "bar_chart_sharp" - BAR_CHART_ROUNDED = "bar_chart_rounded" - BAR_CHART_OUTLINED = "bar_chart_outlined" - BARCODE_READER = "barcode_reader" - BATCH_PREDICTION = "batch_prediction" - BATCH_PREDICTION_SHARP = "batch_prediction_sharp" - BATCH_PREDICTION_ROUNDED = "batch_prediction_rounded" - BATCH_PREDICTION_OUTLINED = "batch_prediction_outlined" - BATHROOM = "bathroom" - BATHROOM_SHARP = "bathroom_sharp" - BATHROOM_ROUNDED = "bathroom_rounded" - BATHROOM_OUTLINED = "bathroom_outlined" - BATHTUB = "bathtub" - BATHTUB_SHARP = "bathtub_sharp" - BATHTUB_ROUNDED = "bathtub_rounded" - BATHTUB_OUTLINED = "bathtub_outlined" - BATTERY_0_BAR = "battery_0_bar" - BATTERY_0_BAR_SHARP = "battery_0_bar_sharp" - BATTERY_0_BAR_ROUNDED = "battery_0_bar_rounded" - BATTERY_0_BAR_OUTLINED = "battery_0_bar_outlined" - BATTERY_1_BAR = "battery_1_bar" - BATTERY_1_BAR_SHARP = "battery_1_bar_sharp" - BATTERY_1_BAR_ROUNDED = "battery_1_bar_rounded" - BATTERY_1_BAR_OUTLINED = "battery_1_bar_outlined" - BATTERY_2_BAR = "battery_2_bar" - BATTERY_2_BAR_SHARP = "battery_2_bar_sharp" - BATTERY_2_BAR_ROUNDED = "battery_2_bar_rounded" - BATTERY_2_BAR_OUTLINED = "battery_2_bar_outlined" - BATTERY_3_BAR = "battery_3_bar" - BATTERY_3_BAR_SHARP = "battery_3_bar_sharp" - BATTERY_3_BAR_ROUNDED = "battery_3_bar_rounded" - BATTERY_3_BAR_OUTLINED = "battery_3_bar_outlined" - BATTERY_4_BAR = "battery_4_bar" - BATTERY_4_BAR_SHARP = "battery_4_bar_sharp" - BATTERY_4_BAR_ROUNDED = "battery_4_bar_rounded" - BATTERY_4_BAR_OUTLINED = "battery_4_bar_outlined" - BATTERY_5_BAR = "battery_5_bar" - BATTERY_5_BAR_SHARP = "battery_5_bar_sharp" - BATTERY_5_BAR_ROUNDED = "battery_5_bar_rounded" - BATTERY_5_BAR_OUTLINED = "battery_5_bar_outlined" - BATTERY_6_BAR = "battery_6_bar" - BATTERY_6_BAR_SHARP = "battery_6_bar_sharp" - BATTERY_6_BAR_ROUNDED = "battery_6_bar_rounded" - BATTERY_6_BAR_OUTLINED = "battery_6_bar_outlined" - BATTERY_ALERT = "battery_alert" - BATTERY_ALERT_SHARP = "battery_alert_sharp" - BATTERY_ALERT_ROUNDED = "battery_alert_rounded" - BATTERY_ALERT_OUTLINED = "battery_alert_outlined" - BATTERY_CHARGING_FULL = "battery_charging_full" - BATTERY_CHARGING_FULL_SHARP = "battery_charging_full_sharp" - BATTERY_CHARGING_FULL_ROUNDED = "battery_charging_full_rounded" - BATTERY_CHARGING_FULL_OUTLINED = "battery_charging_full_outlined" - BATTERY_FULL = "battery_full" - BATTERY_FULL_SHARP = "battery_full_sharp" - BATTERY_FULL_ROUNDED = "battery_full_rounded" - BATTERY_FULL_OUTLINED = "battery_full_outlined" - BATTERY_SAVER = "battery_saver" - BATTERY_SAVER_SHARP = "battery_saver_sharp" - BATTERY_SAVER_ROUNDED = "battery_saver_rounded" - BATTERY_SAVER_OUTLINED = "battery_saver_outlined" - BATTERY_STD = "battery_std" - BATTERY_STD_SHARP = "battery_std_sharp" - BATTERY_STD_ROUNDED = "battery_std_rounded" - BATTERY_STD_OUTLINED = "battery_std_outlined" - BATTERY_UNKNOWN = "battery_unknown" - BATTERY_UNKNOWN_SHARP = "battery_unknown_sharp" - BATTERY_UNKNOWN_ROUNDED = "battery_unknown_rounded" - BATTERY_UNKNOWN_OUTLINED = "battery_unknown_outlined" - BEACH_ACCESS = "beach_access" - BEACH_ACCESS_SHARP = "beach_access_sharp" - BEACH_ACCESS_ROUNDED = "beach_access_rounded" - BEACH_ACCESS_OUTLINED = "beach_access_outlined" - BED = "bed" - BED_SHARP = "bed_sharp" - BED_ROUNDED = "bed_rounded" - BED_OUTLINED = "bed_outlined" - BEDROOM_BABY = "bedroom_baby" - BEDROOM_BABY_SHARP = "bedroom_baby_sharp" - BEDROOM_BABY_ROUNDED = "bedroom_baby_rounded" - BEDROOM_BABY_OUTLINED = "bedroom_baby_outlined" - BEDROOM_CHILD = "bedroom_child" - BEDROOM_CHILD_SHARP = "bedroom_child_sharp" - BEDROOM_CHILD_ROUNDED = "bedroom_child_rounded" - BEDROOM_CHILD_OUTLINED = "bedroom_child_outlined" - BEDROOM_PARENT = "bedroom_parent" - BEDROOM_PARENT_SHARP = "bedroom_parent_sharp" - BEDROOM_PARENT_ROUNDED = "bedroom_parent_rounded" - BEDROOM_PARENT_OUTLINED = "bedroom_parent_outlined" - BEDTIME = "bedtime" - BEDTIME_SHARP = "bedtime_sharp" - BEDTIME_ROUNDED = "bedtime_rounded" - BEDTIME_OUTLINED = "bedtime_outlined" - BEDTIME_OFF = "bedtime_off" - BEDTIME_OFF_SHARP = "bedtime_off_sharp" - BEDTIME_OFF_ROUNDED = "bedtime_off_rounded" - BEDTIME_OFF_OUTLINED = "bedtime_off_outlined" - BEENHERE = "beenhere" - BEENHERE_SHARP = "beenhere_sharp" - BEENHERE_ROUNDED = "beenhere_rounded" - BEENHERE_OUTLINED = "beenhere_outlined" - BENTO = "bento" - BENTO_SHARP = "bento_sharp" - BENTO_ROUNDED = "bento_rounded" - BENTO_OUTLINED = "bento_outlined" - BIKE_SCOOTER = "bike_scooter" - BIKE_SCOOTER_SHARP = "bike_scooter_sharp" - BIKE_SCOOTER_ROUNDED = "bike_scooter_rounded" - BIKE_SCOOTER_OUTLINED = "bike_scooter_outlined" - BIOTECH = "biotech" - BIOTECH_SHARP = "biotech_sharp" - BIOTECH_ROUNDED = "biotech_rounded" - BIOTECH_OUTLINED = "biotech_outlined" - BLENDER = "blender" - BLENDER_SHARP = "blender_sharp" - BLENDER_ROUNDED = "blender_rounded" - BLENDER_OUTLINED = "blender_outlined" - BLIND = "blind" - BLIND_SHARP = "blind_sharp" - BLIND_ROUNDED = "blind_rounded" - BLIND_OUTLINED = "blind_outlined" - BLINDS = "blinds" - BLINDS_SHARP = "blinds_sharp" - BLINDS_ROUNDED = "blinds_rounded" - BLINDS_OUTLINED = "blinds_outlined" - BLINDS_CLOSED = "blinds_closed" - BLINDS_CLOSED_SHARP = "blinds_closed_sharp" - BLINDS_CLOSED_ROUNDED = "blinds_closed_rounded" - BLINDS_CLOSED_OUTLINED = "blinds_closed_outlined" - BLOCK = "block" - BLOCK_SHARP = "block_sharp" - BLOCK_ROUNDED = "block_rounded" - BLOCK_OUTLINED = "block_outlined" - BLOCK_FLIPPED = "block_flipped" - BLOODTYPE = "bloodtype" - BLOODTYPE_SHARP = "bloodtype_sharp" - BLOODTYPE_ROUNDED = "bloodtype_rounded" - BLOODTYPE_OUTLINED = "bloodtype_outlined" - BLUETOOTH = "bluetooth" - BLUETOOTH_SHARP = "bluetooth_sharp" - BLUETOOTH_ROUNDED = "bluetooth_rounded" - BLUETOOTH_OUTLINED = "bluetooth_outlined" - BLUETOOTH_AUDIO = "bluetooth_audio" - BLUETOOTH_AUDIO_SHARP = "bluetooth_audio_sharp" - BLUETOOTH_AUDIO_ROUNDED = "bluetooth_audio_rounded" - BLUETOOTH_AUDIO_OUTLINED = "bluetooth_audio_outlined" - BLUETOOTH_CONNECTED = "bluetooth_connected" - BLUETOOTH_CONNECTED_SHARP = "bluetooth_connected_sharp" - BLUETOOTH_CONNECTED_ROUNDED = "bluetooth_connected_rounded" - BLUETOOTH_CONNECTED_OUTLINED = "bluetooth_connected_outlined" - BLUETOOTH_DISABLED = "bluetooth_disabled" - BLUETOOTH_DISABLED_SHARP = "bluetooth_disabled_sharp" - BLUETOOTH_DISABLED_ROUNDED = "bluetooth_disabled_rounded" - BLUETOOTH_DISABLED_OUTLINED = "bluetooth_disabled_outlined" - BLUETOOTH_DRIVE = "bluetooth_drive" - BLUETOOTH_DRIVE_SHARP = "bluetooth_drive_sharp" - BLUETOOTH_DRIVE_ROUNDED = "bluetooth_drive_rounded" - BLUETOOTH_DRIVE_OUTLINED = "bluetooth_drive_outlined" - BLUETOOTH_SEARCHING = "bluetooth_searching" - BLUETOOTH_SEARCHING_SHARP = "bluetooth_searching_sharp" - BLUETOOTH_SEARCHING_ROUNDED = "bluetooth_searching_rounded" - BLUETOOTH_SEARCHING_OUTLINED = "bluetooth_searching_outlined" - BLUR_CIRCULAR = "blur_circular" - BLUR_CIRCULAR_SHARP = "blur_circular_sharp" - BLUR_CIRCULAR_ROUNDED = "blur_circular_rounded" - BLUR_CIRCULAR_OUTLINED = "blur_circular_outlined" - BLUR_LINEAR = "blur_linear" - BLUR_LINEAR_SHARP = "blur_linear_sharp" - BLUR_LINEAR_ROUNDED = "blur_linear_rounded" - BLUR_LINEAR_OUTLINED = "blur_linear_outlined" - BLUR_OFF = "blur_off" - BLUR_OFF_SHARP = "blur_off_sharp" - BLUR_OFF_ROUNDED = "blur_off_rounded" - BLUR_OFF_OUTLINED = "blur_off_outlined" - BLUR_ON = "blur_on" - BLUR_ON_SHARP = "blur_on_sharp" - BLUR_ON_ROUNDED = "blur_on_rounded" - BLUR_ON_OUTLINED = "blur_on_outlined" - BOLT = "bolt" - BOLT_SHARP = "bolt_sharp" - BOLT_ROUNDED = "bolt_rounded" - BOLT_OUTLINED = "bolt_outlined" - BOOK = "book" - BOOK_SHARP = "book_sharp" - BOOK_ROUNDED = "book_rounded" - BOOK_OUTLINED = "book_outlined" - BOOK_ONLINE = "book_online" - BOOK_ONLINE_SHARP = "book_online_sharp" - BOOK_ONLINE_ROUNDED = "book_online_rounded" - BOOK_ONLINE_OUTLINED = "book_online_outlined" - BOOKMARK = "bookmark" - BOOKMARK_SHARP = "bookmark_sharp" - BOOKMARK_ROUNDED = "bookmark_rounded" - BOOKMARK_OUTLINED = "bookmark_outlined" - BOOKMARK_ADD = "bookmark_add" - BOOKMARK_ADD_SHARP = "bookmark_add_sharp" - BOOKMARK_ADD_ROUNDED = "bookmark_add_rounded" - BOOKMARK_ADD_OUTLINED = "bookmark_add_outlined" - BOOKMARK_ADDED = "bookmark_added" - BOOKMARK_ADDED_SHARP = "bookmark_added_sharp" - BOOKMARK_ADDED_ROUNDED = "bookmark_added_rounded" - BOOKMARK_ADDED_OUTLINED = "bookmark_added_outlined" - BOOKMARK_BORDER = "bookmark_border" - BOOKMARK_BORDER_SHARP = "bookmark_border_sharp" - BOOKMARK_BORDER_ROUNDED = "bookmark_border_rounded" - BOOKMARK_BORDER_OUTLINED = "bookmark_border_outlined" - BOOKMARK_OUTLINE = "bookmark_outline" - BOOKMARK_OUTLINE_SHARP = "bookmark_outline_sharp" - BOOKMARK_OUTLINE_ROUNDED = "bookmark_outline_rounded" - BOOKMARK_OUTLINE_OUTLINED = "bookmark_outline_outlined" - BOOKMARK_REMOVE = "bookmark_remove" - BOOKMARK_REMOVE_SHARP = "bookmark_remove_sharp" - BOOKMARK_REMOVE_ROUNDED = "bookmark_remove_rounded" - BOOKMARK_REMOVE_OUTLINED = "bookmark_remove_outlined" - BOOKMARKS = "bookmarks" - BOOKMARKS_SHARP = "bookmarks_sharp" - BOOKMARKS_ROUNDED = "bookmarks_rounded" - BOOKMARKS_OUTLINED = "bookmarks_outlined" - BORDER_ALL = "border_all" - BORDER_ALL_SHARP = "border_all_sharp" - BORDER_ALL_ROUNDED = "border_all_rounded" - BORDER_ALL_OUTLINED = "border_all_outlined" - BORDER_BOTTOM = "border_bottom" - BORDER_BOTTOM_SHARP = "border_bottom_sharp" - BORDER_BOTTOM_ROUNDED = "border_bottom_rounded" - BORDER_BOTTOM_OUTLINED = "border_bottom_outlined" - BORDER_CLEAR = "border_clear" - BORDER_CLEAR_SHARP = "border_clear_sharp" - BORDER_CLEAR_ROUNDED = "border_clear_rounded" - BORDER_CLEAR_OUTLINED = "border_clear_outlined" - BORDER_COLOR = "border_color" - BORDER_COLOR_SHARP = "border_color_sharp" - BORDER_COLOR_ROUNDED = "border_color_rounded" - BORDER_COLOR_OUTLINED = "border_color_outlined" - BORDER_HORIZONTAL = "border_horizontal" - BORDER_HORIZONTAL_SHARP = "border_horizontal_sharp" - BORDER_HORIZONTAL_ROUNDED = "border_horizontal_rounded" - BORDER_HORIZONTAL_OUTLINED = "border_horizontal_outlined" - BORDER_INNER = "border_inner" - BORDER_INNER_SHARP = "border_inner_sharp" - BORDER_INNER_ROUNDED = "border_inner_rounded" - BORDER_INNER_OUTLINED = "border_inner_outlined" - BORDER_LEFT = "border_left" - BORDER_LEFT_SHARP = "border_left_sharp" - BORDER_LEFT_ROUNDED = "border_left_rounded" - BORDER_LEFT_OUTLINED = "border_left_outlined" - BORDER_OUTER = "border_outer" - BORDER_OUTER_SHARP = "border_outer_sharp" - BORDER_OUTER_ROUNDED = "border_outer_rounded" - BORDER_OUTER_OUTLINED = "border_outer_outlined" - BORDER_RIGHT = "border_right" - BORDER_RIGHT_SHARP = "border_right_sharp" - BORDER_RIGHT_ROUNDED = "border_right_rounded" - BORDER_RIGHT_OUTLINED = "border_right_outlined" - BORDER_STYLE = "border_style" - BORDER_STYLE_SHARP = "border_style_sharp" - BORDER_STYLE_ROUNDED = "border_style_rounded" - BORDER_STYLE_OUTLINED = "border_style_outlined" - BORDER_TOP = "border_top" - BORDER_TOP_SHARP = "border_top_sharp" - BORDER_TOP_ROUNDED = "border_top_rounded" - BORDER_TOP_OUTLINED = "border_top_outlined" - BORDER_VERTICAL = "border_vertical" - BORDER_VERTICAL_SHARP = "border_vertical_sharp" - BORDER_VERTICAL_ROUNDED = "border_vertical_rounded" - BORDER_VERTICAL_OUTLINED = "border_vertical_outlined" - BOY = "boy" - BOY_SHARP = "boy_sharp" - BOY_ROUNDED = "boy_rounded" - BOY_OUTLINED = "boy_outlined" - BRANDING_WATERMARK = "branding_watermark" - BRANDING_WATERMARK_SHARP = "branding_watermark_sharp" - BRANDING_WATERMARK_ROUNDED = "branding_watermark_rounded" - BRANDING_WATERMARK_OUTLINED = "branding_watermark_outlined" - BREAKFAST_DINING = "breakfast_dining" - BREAKFAST_DINING_SHARP = "breakfast_dining_sharp" - BREAKFAST_DINING_ROUNDED = "breakfast_dining_rounded" - BREAKFAST_DINING_OUTLINED = "breakfast_dining_outlined" - BRIGHTNESS_1 = "brightness_1" - BRIGHTNESS_1_SHARP = "brightness_1_sharp" - BRIGHTNESS_1_ROUNDED = "brightness_1_rounded" - BRIGHTNESS_1_OUTLINED = "brightness_1_outlined" - BRIGHTNESS_2 = "brightness_2" - BRIGHTNESS_2_SHARP = "brightness_2_sharp" - BRIGHTNESS_2_ROUNDED = "brightness_2_rounded" - BRIGHTNESS_2_OUTLINED = "brightness_2_outlined" - BRIGHTNESS_3 = "brightness_3" - BRIGHTNESS_3_SHARP = "brightness_3_sharp" - BRIGHTNESS_3_ROUNDED = "brightness_3_rounded" - BRIGHTNESS_3_OUTLINED = "brightness_3_outlined" - BRIGHTNESS_4 = "brightness_4" - BRIGHTNESS_4_SHARP = "brightness_4_sharp" - BRIGHTNESS_4_ROUNDED = "brightness_4_rounded" - BRIGHTNESS_4_OUTLINED = "brightness_4_outlined" - BRIGHTNESS_5 = "brightness_5" - BRIGHTNESS_5_SHARP = "brightness_5_sharp" - BRIGHTNESS_5_ROUNDED = "brightness_5_rounded" - BRIGHTNESS_5_OUTLINED = "brightness_5_outlined" - BRIGHTNESS_6 = "brightness_6" - BRIGHTNESS_6_SHARP = "brightness_6_sharp" - BRIGHTNESS_6_ROUNDED = "brightness_6_rounded" - BRIGHTNESS_6_OUTLINED = "brightness_6_outlined" - BRIGHTNESS_7 = "brightness_7" - BRIGHTNESS_7_SHARP = "brightness_7_sharp" - BRIGHTNESS_7_ROUNDED = "brightness_7_rounded" - BRIGHTNESS_7_OUTLINED = "brightness_7_outlined" - BRIGHTNESS_AUTO = "brightness_auto" - BRIGHTNESS_AUTO_SHARP = "brightness_auto_sharp" - BRIGHTNESS_AUTO_ROUNDED = "brightness_auto_rounded" - BRIGHTNESS_AUTO_OUTLINED = "brightness_auto_outlined" - BRIGHTNESS_HIGH = "brightness_high" - BRIGHTNESS_HIGH_SHARP = "brightness_high_sharp" - BRIGHTNESS_HIGH_ROUNDED = "brightness_high_rounded" - BRIGHTNESS_HIGH_OUTLINED = "brightness_high_outlined" - BRIGHTNESS_LOW = "brightness_low" - BRIGHTNESS_LOW_SHARP = "brightness_low_sharp" - BRIGHTNESS_LOW_ROUNDED = "brightness_low_rounded" - BRIGHTNESS_LOW_OUTLINED = "brightness_low_outlined" - BRIGHTNESS_MEDIUM = "brightness_medium" - BRIGHTNESS_MEDIUM_SHARP = "brightness_medium_sharp" - BRIGHTNESS_MEDIUM_ROUNDED = "brightness_medium_rounded" - BRIGHTNESS_MEDIUM_OUTLINED = "brightness_medium_outlined" - BROADCAST_ON_HOME = "broadcast_on_home" - BROADCAST_ON_HOME_SHARP = "broadcast_on_home_sharp" - BROADCAST_ON_HOME_ROUNDED = "broadcast_on_home_rounded" - BROADCAST_ON_HOME_OUTLINED = "broadcast_on_home_outlined" - BROADCAST_ON_PERSONAL = "broadcast_on_personal" - BROADCAST_ON_PERSONAL_SHARP = "broadcast_on_personal_sharp" - BROADCAST_ON_PERSONAL_ROUNDED = "broadcast_on_personal_rounded" - BROADCAST_ON_PERSONAL_OUTLINED = "broadcast_on_personal_outlined" - BROKEN_IMAGE = "broken_image" - BROKEN_IMAGE_SHARP = "broken_image_sharp" - BROKEN_IMAGE_ROUNDED = "broken_image_rounded" - BROKEN_IMAGE_OUTLINED = "broken_image_outlined" - BROWSE_GALLERY = "browse_gallery" - BROWSE_GALLERY_SHARP = "browse_gallery_sharp" - BROWSE_GALLERY_ROUNDED = "browse_gallery_rounded" - BROWSE_GALLERY_OUTLINED = "browse_gallery_outlined" - BROWSER_NOT_SUPPORTED = "browser_not_supported" - BROWSER_NOT_SUPPORTED_SHARP = "browser_not_supported_sharp" - BROWSER_NOT_SUPPORTED_ROUNDED = "browser_not_supported_rounded" - BROWSER_NOT_SUPPORTED_OUTLINED = "browser_not_supported_outlined" - BROWSER_UPDATED = "browser_updated" - BROWSER_UPDATED_SHARP = "browser_updated_sharp" - BROWSER_UPDATED_ROUNDED = "browser_updated_rounded" - BROWSER_UPDATED_OUTLINED = "browser_updated_outlined" - BRUNCH_DINING = "brunch_dining" - BRUNCH_DINING_SHARP = "brunch_dining_sharp" - BRUNCH_DINING_ROUNDED = "brunch_dining_rounded" - BRUNCH_DINING_OUTLINED = "brunch_dining_outlined" - BRUSH = "brush" - BRUSH_SHARP = "brush_sharp" - BRUSH_ROUNDED = "brush_rounded" - BRUSH_OUTLINED = "brush_outlined" - BUBBLE_CHART = "bubble_chart" - BUBBLE_CHART_SHARP = "bubble_chart_sharp" - BUBBLE_CHART_ROUNDED = "bubble_chart_rounded" - BUBBLE_CHART_OUTLINED = "bubble_chart_outlined" - BUG_REPORT = "bug_report" - BUG_REPORT_SHARP = "bug_report_sharp" - BUG_REPORT_ROUNDED = "bug_report_rounded" - BUG_REPORT_OUTLINED = "bug_report_outlined" - BUILD = "build" - BUILD_SHARP = "build_sharp" - BUILD_ROUNDED = "build_rounded" - BUILD_OUTLINED = "build_outlined" - BUILD_CIRCLE = "build_circle" - BUILD_CIRCLE_SHARP = "build_circle_sharp" - BUILD_CIRCLE_ROUNDED = "build_circle_rounded" - BUILD_CIRCLE_OUTLINED = "build_circle_outlined" - BUNGALOW = "bungalow" - BUNGALOW_SHARP = "bungalow_sharp" - BUNGALOW_ROUNDED = "bungalow_rounded" - BUNGALOW_OUTLINED = "bungalow_outlined" - BURST_MODE = "burst_mode" - BURST_MODE_SHARP = "burst_mode_sharp" - BURST_MODE_ROUNDED = "burst_mode_rounded" - BURST_MODE_OUTLINED = "burst_mode_outlined" - BUS_ALERT = "bus_alert" - BUS_ALERT_SHARP = "bus_alert_sharp" - BUS_ALERT_ROUNDED = "bus_alert_rounded" - BUS_ALERT_OUTLINED = "bus_alert_outlined" - BUSINESS = "business" - BUSINESS_SHARP = "business_sharp" - BUSINESS_ROUNDED = "business_rounded" - BUSINESS_OUTLINED = "business_outlined" - BUSINESS_CENTER = "business_center" - BUSINESS_CENTER_SHARP = "business_center_sharp" - BUSINESS_CENTER_ROUNDED = "business_center_rounded" - BUSINESS_CENTER_OUTLINED = "business_center_outlined" - CABIN = "cabin" - CABIN_SHARP = "cabin_sharp" - CABIN_ROUNDED = "cabin_rounded" - CABIN_OUTLINED = "cabin_outlined" - CABLE = "cable" - CABLE_SHARP = "cable_sharp" - CABLE_ROUNDED = "cable_rounded" - CABLE_OUTLINED = "cable_outlined" - CACHED = "cached" - CACHED_SHARP = "cached_sharp" - CACHED_ROUNDED = "cached_rounded" - CACHED_OUTLINED = "cached_outlined" - CAKE = "cake" - CAKE_SHARP = "cake_sharp" - CAKE_ROUNDED = "cake_rounded" - CAKE_OUTLINED = "cake_outlined" - CALCULATE = "calculate" - CALCULATE_SHARP = "calculate_sharp" - CALCULATE_ROUNDED = "calculate_rounded" - CALCULATE_OUTLINED = "calculate_outlined" - CALENDAR_MONTH = "calendar_month" - CALENDAR_MONTH_SHARP = "calendar_month_sharp" - CALENDAR_MONTH_ROUNDED = "calendar_month_rounded" - CALENDAR_MONTH_OUTLINED = "calendar_month_outlined" - CALENDAR_TODAY = "calendar_today" - CALENDAR_TODAY_SHARP = "calendar_today_sharp" - CALENDAR_TODAY_ROUNDED = "calendar_today_rounded" - CALENDAR_TODAY_OUTLINED = "calendar_today_outlined" - CALENDAR_VIEW_DAY = "calendar_view_day" - CALENDAR_VIEW_DAY_SHARP = "calendar_view_day_sharp" - CALENDAR_VIEW_DAY_ROUNDED = "calendar_view_day_rounded" - CALENDAR_VIEW_DAY_OUTLINED = "calendar_view_day_outlined" - CALENDAR_VIEW_MONTH = "calendar_view_month" - CALENDAR_VIEW_MONTH_SHARP = "calendar_view_month_sharp" - CALENDAR_VIEW_MONTH_ROUNDED = "calendar_view_month_rounded" - CALENDAR_VIEW_MONTH_OUTLINED = "calendar_view_month_outlined" - CALENDAR_VIEW_WEEK = "calendar_view_week" - CALENDAR_VIEW_WEEK_SHARP = "calendar_view_week_sharp" - CALENDAR_VIEW_WEEK_ROUNDED = "calendar_view_week_rounded" - CALENDAR_VIEW_WEEK_OUTLINED = "calendar_view_week_outlined" - CALL = "call" - CALL_SHARP = "call_sharp" - CALL_ROUNDED = "call_rounded" - CALL_OUTLINED = "call_outlined" - CALL_END = "call_end" - CALL_END_SHARP = "call_end_sharp" - CALL_END_ROUNDED = "call_end_rounded" - CALL_END_OUTLINED = "call_end_outlined" - CALL_MADE = "call_made" - CALL_MADE_SHARP = "call_made_sharp" - CALL_MADE_ROUNDED = "call_made_rounded" - CALL_MADE_OUTLINED = "call_made_outlined" - CALL_MERGE = "call_merge" - CALL_MERGE_SHARP = "call_merge_sharp" - CALL_MERGE_ROUNDED = "call_merge_rounded" - CALL_MERGE_OUTLINED = "call_merge_outlined" - CALL_MISSED = "call_missed" - CALL_MISSED_SHARP = "call_missed_sharp" - CALL_MISSED_ROUNDED = "call_missed_rounded" - CALL_MISSED_OUTLINED = "call_missed_outlined" - CALL_MISSED_OUTGOING = "call_missed_outgoing" - CALL_MISSED_OUTGOING_SHARP = "call_missed_outgoing_sharp" - CALL_MISSED_OUTGOING_ROUNDED = "call_missed_outgoing_rounded" - CALL_MISSED_OUTGOING_OUTLINED = "call_missed_outgoing_outlined" - CALL_RECEIVED = "call_received" - CALL_RECEIVED_SHARP = "call_received_sharp" - CALL_RECEIVED_ROUNDED = "call_received_rounded" - CALL_RECEIVED_OUTLINED = "call_received_outlined" - CALL_SPLIT = "call_split" - CALL_SPLIT_SHARP = "call_split_sharp" - CALL_SPLIT_ROUNDED = "call_split_rounded" - CALL_SPLIT_OUTLINED = "call_split_outlined" - CALL_TO_ACTION = "call_to_action" - CALL_TO_ACTION_SHARP = "call_to_action_sharp" - CALL_TO_ACTION_ROUNDED = "call_to_action_rounded" - CALL_TO_ACTION_OUTLINED = "call_to_action_outlined" - CAMERA = "camera" - CAMERA_SHARP = "camera_sharp" - CAMERA_ROUNDED = "camera_rounded" - CAMERA_OUTLINED = "camera_outlined" - CAMERA_ALT = "camera_alt" - CAMERA_ALT_SHARP = "camera_alt_sharp" - CAMERA_ALT_ROUNDED = "camera_alt_rounded" - CAMERA_ALT_OUTLINED = "camera_alt_outlined" - CAMERA_ENHANCE = "camera_enhance" - CAMERA_ENHANCE_SHARP = "camera_enhance_sharp" - CAMERA_ENHANCE_ROUNDED = "camera_enhance_rounded" - CAMERA_ENHANCE_OUTLINED = "camera_enhance_outlined" - CAMERA_FRONT = "camera_front" - CAMERA_FRONT_SHARP = "camera_front_sharp" - CAMERA_FRONT_ROUNDED = "camera_front_rounded" - CAMERA_FRONT_OUTLINED = "camera_front_outlined" - CAMERA_INDOOR = "camera_indoor" - CAMERA_INDOOR_SHARP = "camera_indoor_sharp" - CAMERA_INDOOR_ROUNDED = "camera_indoor_rounded" - CAMERA_INDOOR_OUTLINED = "camera_indoor_outlined" - CAMERA_OUTDOOR = "camera_outdoor" - CAMERA_OUTDOOR_SHARP = "camera_outdoor_sharp" - CAMERA_OUTDOOR_ROUNDED = "camera_outdoor_rounded" - CAMERA_OUTDOOR_OUTLINED = "camera_outdoor_outlined" - CAMERA_REAR = "camera_rear" - CAMERA_REAR_SHARP = "camera_rear_sharp" - CAMERA_REAR_ROUNDED = "camera_rear_rounded" - CAMERA_REAR_OUTLINED = "camera_rear_outlined" - CAMERA_ROLL = "camera_roll" - CAMERA_ROLL_SHARP = "camera_roll_sharp" - CAMERA_ROLL_ROUNDED = "camera_roll_rounded" - CAMERA_ROLL_OUTLINED = "camera_roll_outlined" - CAMERASWITCH = "cameraswitch" - CAMERASWITCH_SHARP = "cameraswitch_sharp" - CAMERASWITCH_ROUNDED = "cameraswitch_rounded" - CAMERASWITCH_OUTLINED = "cameraswitch_outlined" - CAMPAIGN = "campaign" - CAMPAIGN_SHARP = "campaign_sharp" - CAMPAIGN_ROUNDED = "campaign_rounded" - CAMPAIGN_OUTLINED = "campaign_outlined" - CANCEL = "cancel" - CANCEL_SHARP = "cancel_sharp" - CANCEL_ROUNDED = "cancel_rounded" - CANCEL_OUTLINED = "cancel_outlined" - CANCEL_PRESENTATION = "cancel_presentation" - CANCEL_PRESENTATION_SHARP = "cancel_presentation_sharp" - CANCEL_PRESENTATION_ROUNDED = "cancel_presentation_rounded" - CANCEL_PRESENTATION_OUTLINED = "cancel_presentation_outlined" - CANCEL_SCHEDULE_SEND = "cancel_schedule_send" - CANCEL_SCHEDULE_SEND_SHARP = "cancel_schedule_send_sharp" - CANCEL_SCHEDULE_SEND_ROUNDED = "cancel_schedule_send_rounded" - CANCEL_SCHEDULE_SEND_OUTLINED = "cancel_schedule_send_outlined" - CANDLESTICK_CHART = "candlestick_chart" - CANDLESTICK_CHART_SHARP = "candlestick_chart_sharp" - CANDLESTICK_CHART_ROUNDED = "candlestick_chart_rounded" - CANDLESTICK_CHART_OUTLINED = "candlestick_chart_outlined" - CAR_CRASH = "car_crash" - CAR_CRASH_SHARP = "car_crash_sharp" - CAR_CRASH_ROUNDED = "car_crash_rounded" - CAR_CRASH_OUTLINED = "car_crash_outlined" - CAR_RENTAL = "car_rental" - CAR_RENTAL_SHARP = "car_rental_sharp" - CAR_RENTAL_ROUNDED = "car_rental_rounded" - CAR_RENTAL_OUTLINED = "car_rental_outlined" - CAR_REPAIR = "car_repair" - CAR_REPAIR_SHARP = "car_repair_sharp" - CAR_REPAIR_ROUNDED = "car_repair_rounded" - CAR_REPAIR_OUTLINED = "car_repair_outlined" - CARD_GIFTCARD = "card_giftcard" - CARD_GIFTCARD_SHARP = "card_giftcard_sharp" - CARD_GIFTCARD_ROUNDED = "card_giftcard_rounded" - CARD_GIFTCARD_OUTLINED = "card_giftcard_outlined" - CARD_MEMBERSHIP = "card_membership" - CARD_MEMBERSHIP_SHARP = "card_membership_sharp" - CARD_MEMBERSHIP_ROUNDED = "card_membership_rounded" - CARD_MEMBERSHIP_OUTLINED = "card_membership_outlined" - CARD_TRAVEL = "card_travel" - CARD_TRAVEL_SHARP = "card_travel_sharp" - CARD_TRAVEL_ROUNDED = "card_travel_rounded" - CARD_TRAVEL_OUTLINED = "card_travel_outlined" - CARPENTER = "carpenter" - CARPENTER_SHARP = "carpenter_sharp" - CARPENTER_ROUNDED = "carpenter_rounded" - CARPENTER_OUTLINED = "carpenter_outlined" - CASES = "cases" - CASES_SHARP = "cases_sharp" - CASES_ROUNDED = "cases_rounded" - CASES_OUTLINED = "cases_outlined" - CASINO = "casino" - CASINO_SHARP = "casino_sharp" - CASINO_ROUNDED = "casino_rounded" - CASINO_OUTLINED = "casino_outlined" - CAST = "cast" - CAST_SHARP = "cast_sharp" - CAST_ROUNDED = "cast_rounded" - CAST_OUTLINED = "cast_outlined" - CAST_CONNECTED = "cast_connected" - CAST_CONNECTED_SHARP = "cast_connected_sharp" - CAST_CONNECTED_ROUNDED = "cast_connected_rounded" - CAST_CONNECTED_OUTLINED = "cast_connected_outlined" - CAST_FOR_EDUCATION = "cast_for_education" - CAST_FOR_EDUCATION_SHARP = "cast_for_education_sharp" - CAST_FOR_EDUCATION_ROUNDED = "cast_for_education_rounded" - CAST_FOR_EDUCATION_OUTLINED = "cast_for_education_outlined" - CASTLE = "castle" - CASTLE_SHARP = "castle_sharp" - CASTLE_ROUNDED = "castle_rounded" - CASTLE_OUTLINED = "castle_outlined" - CATCHING_POKEMON = "catching_pokemon" - CATCHING_POKEMON_SHARP = "catching_pokemon_sharp" - CATCHING_POKEMON_ROUNDED = "catching_pokemon_rounded" - CATCHING_POKEMON_OUTLINED = "catching_pokemon_outlined" - CATEGORY = "category" - CATEGORY_SHARP = "category_sharp" - CATEGORY_ROUNDED = "category_rounded" - CATEGORY_OUTLINED = "category_outlined" - CELEBRATION = "celebration" - CELEBRATION_SHARP = "celebration_sharp" - CELEBRATION_ROUNDED = "celebration_rounded" - CELEBRATION_OUTLINED = "celebration_outlined" - CELL_TOWER = "cell_tower" - CELL_TOWER_SHARP = "cell_tower_sharp" - CELL_TOWER_ROUNDED = "cell_tower_rounded" - CELL_TOWER_OUTLINED = "cell_tower_outlined" - CELL_WIFI = "cell_wifi" - CELL_WIFI_SHARP = "cell_wifi_sharp" - CELL_WIFI_ROUNDED = "cell_wifi_rounded" - CELL_WIFI_OUTLINED = "cell_wifi_outlined" - CENTER_FOCUS_STRONG = "center_focus_strong" - CENTER_FOCUS_STRONG_SHARP = "center_focus_strong_sharp" - CENTER_FOCUS_STRONG_ROUNDED = "center_focus_strong_rounded" - CENTER_FOCUS_STRONG_OUTLINED = "center_focus_strong_outlined" - CENTER_FOCUS_WEAK = "center_focus_weak" - CENTER_FOCUS_WEAK_SHARP = "center_focus_weak_sharp" - CENTER_FOCUS_WEAK_ROUNDED = "center_focus_weak_rounded" - CENTER_FOCUS_WEAK_OUTLINED = "center_focus_weak_outlined" - CHAIR = "chair" - CHAIR_SHARP = "chair_sharp" - CHAIR_ROUNDED = "chair_rounded" - CHAIR_OUTLINED = "chair_outlined" - CHAIR_ALT = "chair_alt" - CHAIR_ALT_SHARP = "chair_alt_sharp" - CHAIR_ALT_ROUNDED = "chair_alt_rounded" - CHAIR_ALT_OUTLINED = "chair_alt_outlined" - CHALET = "chalet" - CHALET_SHARP = "chalet_sharp" - CHALET_ROUNDED = "chalet_rounded" - CHALET_OUTLINED = "chalet_outlined" - CHANGE_CIRCLE = "change_circle" - CHANGE_CIRCLE_SHARP = "change_circle_sharp" - CHANGE_CIRCLE_ROUNDED = "change_circle_rounded" - CHANGE_CIRCLE_OUTLINED = "change_circle_outlined" - CHANGE_HISTORY = "change_history" - CHANGE_HISTORY_SHARP = "change_history_sharp" - CHANGE_HISTORY_ROUNDED = "change_history_rounded" - CHANGE_HISTORY_OUTLINED = "change_history_outlined" - CHARGING_STATION = "charging_station" - CHARGING_STATION_SHARP = "charging_station_sharp" - CHARGING_STATION_ROUNDED = "charging_station_rounded" - CHARGING_STATION_OUTLINED = "charging_station_outlined" - CHAT = "chat" - CHAT_SHARP = "chat_sharp" - CHAT_ROUNDED = "chat_rounded" - CHAT_OUTLINED = "chat_outlined" - CHAT_BUBBLE = "chat_bubble" - CHAT_BUBBLE_SHARP = "chat_bubble_sharp" - CHAT_BUBBLE_ROUNDED = "chat_bubble_rounded" - CHAT_BUBBLE_OUTLINED = "chat_bubble_outlined" - CHAT_BUBBLE_OUTLINE = "chat_bubble_outline" - CHAT_BUBBLE_OUTLINE_SHARP = "chat_bubble_outline_sharp" - CHAT_BUBBLE_OUTLINE_ROUNDED = "chat_bubble_outline_rounded" - CHAT_BUBBLE_OUTLINE_OUTLINED = "chat_bubble_outline_outlined" - CHECK = "check" - CHECK_SHARP = "check_sharp" - CHECK_ROUNDED = "check_rounded" - CHECK_OUTLINED = "check_outlined" - CHECK_BOX = "check_box" - CHECK_BOX_SHARP = "check_box_sharp" - CHECK_BOX_ROUNDED = "check_box_rounded" - CHECK_BOX_OUTLINED = "check_box_outlined" - CHECK_BOX_OUTLINE_BLANK = "check_box_outline_blank" - CHECK_BOX_OUTLINE_BLANK_SHARP = "check_box_outline_blank_sharp" - CHECK_BOX_OUTLINE_BLANK_ROUNDED = "check_box_outline_blank_rounded" - CHECK_BOX_OUTLINE_BLANK_OUTLINED = "check_box_outline_blank_outlined" - CHECK_CIRCLE = "check_circle" - CHECK_CIRCLE_SHARP = "check_circle_sharp" - CHECK_CIRCLE_ROUNDED = "check_circle_rounded" - CHECK_CIRCLE_OUTLINED = "check_circle_outlined" - CHECK_CIRCLE_OUTLINE = "check_circle_outline" - CHECK_CIRCLE_OUTLINE_SHARP = "check_circle_outline_sharp" - CHECK_CIRCLE_OUTLINE_ROUNDED = "check_circle_outline_rounded" - CHECK_CIRCLE_OUTLINE_OUTLINED = "check_circle_outline_outlined" - CHECKLIST = "checklist" - CHECKLIST_SHARP = "checklist_sharp" - CHECKLIST_ROUNDED = "checklist_rounded" - CHECKLIST_OUTLINED = "checklist_outlined" - CHECKLIST_RTL = "checklist_rtl" - CHECKLIST_RTL_SHARP = "checklist_rtl_sharp" - CHECKLIST_RTL_ROUNDED = "checklist_rtl_rounded" - CHECKLIST_RTL_OUTLINED = "checklist_rtl_outlined" - CHECKROOM = "checkroom" - CHECKROOM_SHARP = "checkroom_sharp" - CHECKROOM_ROUNDED = "checkroom_rounded" - CHECKROOM_OUTLINED = "checkroom_outlined" - CHEVRON_LEFT = "chevron_left" - CHEVRON_LEFT_SHARP = "chevron_left_sharp" - CHEVRON_LEFT_ROUNDED = "chevron_left_rounded" - CHEVRON_LEFT_OUTLINED = "chevron_left_outlined" - CHEVRON_RIGHT = "chevron_right" - CHEVRON_RIGHT_SHARP = "chevron_right_sharp" - CHEVRON_RIGHT_ROUNDED = "chevron_right_rounded" - CHEVRON_RIGHT_OUTLINED = "chevron_right_outlined" - CHILD_CARE = "child_care" - CHILD_CARE_SHARP = "child_care_sharp" - CHILD_CARE_ROUNDED = "child_care_rounded" - CHILD_CARE_OUTLINED = "child_care_outlined" - CHILD_FRIENDLY = "child_friendly" - CHILD_FRIENDLY_SHARP = "child_friendly_sharp" - CHILD_FRIENDLY_ROUNDED = "child_friendly_rounded" - CHILD_FRIENDLY_OUTLINED = "child_friendly_outlined" - CHROME_READER_MODE = "chrome_reader_mode" - CHROME_READER_MODE_SHARP = "chrome_reader_mode_sharp" - CHROME_READER_MODE_ROUNDED = "chrome_reader_mode_rounded" - CHROME_READER_MODE_OUTLINED = "chrome_reader_mode_outlined" - CHURCH = "church" - CHURCH_SHARP = "church_sharp" - CHURCH_ROUNDED = "church_rounded" - CHURCH_OUTLINED = "church_outlined" - CIRCLE = "circle" - CIRCLE_SHARP = "circle_sharp" - CIRCLE_ROUNDED = "circle_rounded" - CIRCLE_OUTLINED = "circle_outlined" - CIRCLE_NOTIFICATIONS = "circle_notifications" - CIRCLE_NOTIFICATIONS_SHARP = "circle_notifications_sharp" - CIRCLE_NOTIFICATIONS_ROUNDED = "circle_notifications_rounded" - CIRCLE_NOTIFICATIONS_OUTLINED = "circle_notifications_outlined" - CLASS_ = "class_" - CLASS_SHARP = "class_sharp" - CLASS_ROUNDED = "class_rounded" - CLASS_OUTLINED = "class_outlined" - CLEAN_HANDS = "clean_hands" - CLEAN_HANDS_SHARP = "clean_hands_sharp" - CLEAN_HANDS_ROUNDED = "clean_hands_rounded" - CLEAN_HANDS_OUTLINED = "clean_hands_outlined" - CLEANING_SERVICES = "cleaning_services" - CLEANING_SERVICES_SHARP = "cleaning_services_sharp" - CLEANING_SERVICES_ROUNDED = "cleaning_services_rounded" - CLEANING_SERVICES_OUTLINED = "cleaning_services_outlined" - CLEAR = "clear" - CLEAR_SHARP = "clear_sharp" - CLEAR_ROUNDED = "clear_rounded" - CLEAR_OUTLINED = "clear_outlined" - CLEAR_ALL = "clear_all" - CLEAR_ALL_SHARP = "clear_all_sharp" - CLEAR_ALL_ROUNDED = "clear_all_rounded" - CLEAR_ALL_OUTLINED = "clear_all_outlined" - CLOSE = "close" - CLOSE_SHARP = "close_sharp" - CLOSE_ROUNDED = "close_rounded" - CLOSE_OUTLINED = "close_outlined" - CLOSE_FULLSCREEN = "close_fullscreen" - CLOSE_FULLSCREEN_SHARP = "close_fullscreen_sharp" - CLOSE_FULLSCREEN_ROUNDED = "close_fullscreen_rounded" - CLOSE_FULLSCREEN_OUTLINED = "close_fullscreen_outlined" - CLOSED_CAPTION = "closed_caption" - CLOSED_CAPTION_SHARP = "closed_caption_sharp" - CLOSED_CAPTION_ROUNDED = "closed_caption_rounded" - CLOSED_CAPTION_OUTLINED = "closed_caption_outlined" - CLOSED_CAPTION_DISABLED = "closed_caption_disabled" - CLOSED_CAPTION_DISABLED_SHARP = "closed_caption_disabled_sharp" - CLOSED_CAPTION_DISABLED_ROUNDED = "closed_caption_disabled_rounded" - CLOSED_CAPTION_DISABLED_OUTLINED = "closed_caption_disabled_outlined" - CLOSED_CAPTION_OFF = "closed_caption_off" - CLOSED_CAPTION_OFF_SHARP = "closed_caption_off_sharp" - CLOSED_CAPTION_OFF_ROUNDED = "closed_caption_off_rounded" - CLOSED_CAPTION_OFF_OUTLINED = "closed_caption_off_outlined" - CLOUD = "cloud" - CLOUD_SHARP = "cloud_sharp" - CLOUD_ROUNDED = "cloud_rounded" - CLOUD_OUTLINED = "cloud_outlined" - CLOUD_CIRCLE = "cloud_circle" - CLOUD_CIRCLE_SHARP = "cloud_circle_sharp" - CLOUD_CIRCLE_ROUNDED = "cloud_circle_rounded" - CLOUD_CIRCLE_OUTLINED = "cloud_circle_outlined" - CLOUD_DONE = "cloud_done" - CLOUD_DONE_SHARP = "cloud_done_sharp" - CLOUD_DONE_ROUNDED = "cloud_done_rounded" - CLOUD_DONE_OUTLINED = "cloud_done_outlined" - CLOUD_DOWNLOAD = "cloud_download" - CLOUD_DOWNLOAD_SHARP = "cloud_download_sharp" - CLOUD_DOWNLOAD_ROUNDED = "cloud_download_rounded" - CLOUD_DOWNLOAD_OUTLINED = "cloud_download_outlined" - CLOUD_OFF = "cloud_off" - CLOUD_OFF_SHARP = "cloud_off_sharp" - CLOUD_OFF_ROUNDED = "cloud_off_rounded" - CLOUD_OFF_OUTLINED = "cloud_off_outlined" - CLOUD_QUEUE = "cloud_queue" - CLOUD_QUEUE_SHARP = "cloud_queue_sharp" - CLOUD_QUEUE_ROUNDED = "cloud_queue_rounded" - CLOUD_QUEUE_OUTLINED = "cloud_queue_outlined" - CLOUD_SYNC = "cloud_sync" - CLOUD_SYNC_SHARP = "cloud_sync_sharp" - CLOUD_SYNC_ROUNDED = "cloud_sync_rounded" - CLOUD_SYNC_OUTLINED = "cloud_sync_outlined" - CLOUD_UPLOAD = "cloud_upload" - CLOUD_UPLOAD_SHARP = "cloud_upload_sharp" - CLOUD_UPLOAD_ROUNDED = "cloud_upload_rounded" - CLOUD_UPLOAD_OUTLINED = "cloud_upload_outlined" - CLOUDY_SNOWING = "cloudy_snowing" - CO2 = "co2" - CO2_SHARP = "co2_sharp" - CO2_ROUNDED = "co2_rounded" - CO2_OUTLINED = "co2_outlined" - CO_PRESENT = "co_present" - CO_PRESENT_SHARP = "co_present_sharp" - CO_PRESENT_ROUNDED = "co_present_rounded" - CO_PRESENT_OUTLINED = "co_present_outlined" - CODE = "code" - CODE_SHARP = "code_sharp" - CODE_ROUNDED = "code_rounded" - CODE_OUTLINED = "code_outlined" - CODE_OFF = "code_off" - CODE_OFF_SHARP = "code_off_sharp" - CODE_OFF_ROUNDED = "code_off_rounded" - CODE_OFF_OUTLINED = "code_off_outlined" - COFFEE = "coffee" - COFFEE_SHARP = "coffee_sharp" - COFFEE_ROUNDED = "coffee_rounded" - COFFEE_OUTLINED = "coffee_outlined" - COFFEE_MAKER = "coffee_maker" - COFFEE_MAKER_SHARP = "coffee_maker_sharp" - COFFEE_MAKER_ROUNDED = "coffee_maker_rounded" - COFFEE_MAKER_OUTLINED = "coffee_maker_outlined" - COLLECTIONS = "collections" - COLLECTIONS_SHARP = "collections_sharp" - COLLECTIONS_ROUNDED = "collections_rounded" - COLLECTIONS_OUTLINED = "collections_outlined" - COLLECTIONS_BOOKMARK = "collections_bookmark" - COLLECTIONS_BOOKMARK_SHARP = "collections_bookmark_sharp" - COLLECTIONS_BOOKMARK_ROUNDED = "collections_bookmark_rounded" - COLLECTIONS_BOOKMARK_OUTLINED = "collections_bookmark_outlined" - COLOR_LENS = "color_lens" - COLOR_LENS_SHARP = "color_lens_sharp" - COLOR_LENS_ROUNDED = "color_lens_rounded" - COLOR_LENS_OUTLINED = "color_lens_outlined" - COLORIZE = "colorize" - COLORIZE_SHARP = "colorize_sharp" - COLORIZE_ROUNDED = "colorize_rounded" - COLORIZE_OUTLINED = "colorize_outlined" - COMMENT = "comment" - COMMENT_SHARP = "comment_sharp" - COMMENT_ROUNDED = "comment_rounded" - COMMENT_OUTLINED = "comment_outlined" - COMMENT_BANK = "comment_bank" - COMMENT_BANK_SHARP = "comment_bank_sharp" - COMMENT_BANK_ROUNDED = "comment_bank_rounded" - COMMENT_BANK_OUTLINED = "comment_bank_outlined" - COMMENTS_DISABLED = "comments_disabled" - COMMENTS_DISABLED_SHARP = "comments_disabled_sharp" - COMMENTS_DISABLED_ROUNDED = "comments_disabled_rounded" - COMMENTS_DISABLED_OUTLINED = "comments_disabled_outlined" - COMMIT = "commit" - COMMIT_SHARP = "commit_sharp" - COMMIT_ROUNDED = "commit_rounded" - COMMIT_OUTLINED = "commit_outlined" - COMMUTE = "commute" - COMMUTE_SHARP = "commute_sharp" - COMMUTE_ROUNDED = "commute_rounded" - COMMUTE_OUTLINED = "commute_outlined" - COMPARE = "compare" - COMPARE_SHARP = "compare_sharp" - COMPARE_ROUNDED = "compare_rounded" - COMPARE_OUTLINED = "compare_outlined" - COMPARE_ARROWS = "compare_arrows" - COMPARE_ARROWS_SHARP = "compare_arrows_sharp" - COMPARE_ARROWS_ROUNDED = "compare_arrows_rounded" - COMPARE_ARROWS_OUTLINED = "compare_arrows_outlined" - COMPASS_CALIBRATION = "compass_calibration" - COMPASS_CALIBRATION_SHARP = "compass_calibration_sharp" - COMPASS_CALIBRATION_ROUNDED = "compass_calibration_rounded" - COMPASS_CALIBRATION_OUTLINED = "compass_calibration_outlined" - COMPOST = "compost" - COMPOST_SHARP = "compost_sharp" - COMPOST_ROUNDED = "compost_rounded" - COMPOST_OUTLINED = "compost_outlined" - COMPRESS = "compress" - COMPRESS_SHARP = "compress_sharp" - COMPRESS_ROUNDED = "compress_rounded" - COMPRESS_OUTLINED = "compress_outlined" - COMPUTER = "computer" - COMPUTER_SHARP = "computer_sharp" - COMPUTER_ROUNDED = "computer_rounded" - COMPUTER_OUTLINED = "computer_outlined" - CONFIRMATION_NUM = "confirmation_num" - CONFIRMATION_NUM_SHARP = "confirmation_num_sharp" - CONFIRMATION_NUM_ROUNDED = "confirmation_num_rounded" - CONFIRMATION_NUM_OUTLINED = "confirmation_num_outlined" - CONFIRMATION_NUMBER = "confirmation_number" - CONFIRMATION_NUMBER_SHARP = "confirmation_number_sharp" - CONFIRMATION_NUMBER_ROUNDED = "confirmation_number_rounded" - CONFIRMATION_NUMBER_OUTLINED = "confirmation_number_outlined" - CONNECT_WITHOUT_CONTACT = "connect_without_contact" - CONNECT_WITHOUT_CONTACT_SHARP = "connect_without_contact_sharp" - CONNECT_WITHOUT_CONTACT_ROUNDED = "connect_without_contact_rounded" - CONNECT_WITHOUT_CONTACT_OUTLINED = "connect_without_contact_outlined" - CONNECTED_TV = "connected_tv" - CONNECTED_TV_SHARP = "connected_tv_sharp" - CONNECTED_TV_ROUNDED = "connected_tv_rounded" - CONNECTED_TV_OUTLINED = "connected_tv_outlined" - CONNECTING_AIRPORTS = "connecting_airports" - CONNECTING_AIRPORTS_SHARP = "connecting_airports_sharp" - CONNECTING_AIRPORTS_ROUNDED = "connecting_airports_rounded" - CONNECTING_AIRPORTS_OUTLINED = "connecting_airports_outlined" - CONSTRUCTION = "construction" - CONSTRUCTION_SHARP = "construction_sharp" - CONSTRUCTION_ROUNDED = "construction_rounded" - CONSTRUCTION_OUTLINED = "construction_outlined" - CONTACT_EMERGENCY = "contact_emergency" - CONTACT_EMERGENCY_SHARP = "contact_emergency_sharp" - CONTACT_EMERGENCY_ROUNDED = "contact_emergency_rounded" - CONTACT_EMERGENCY_OUTLINED = "contact_emergency_outlined" - CONTACT_MAIL = "contact_mail" - CONTACT_MAIL_SHARP = "contact_mail_sharp" - CONTACT_MAIL_ROUNDED = "contact_mail_rounded" - CONTACT_MAIL_OUTLINED = "contact_mail_outlined" - CONTACT_PAGE = "contact_page" - CONTACT_PAGE_SHARP = "contact_page_sharp" - CONTACT_PAGE_ROUNDED = "contact_page_rounded" - CONTACT_PAGE_OUTLINED = "contact_page_outlined" - CONTACT_PHONE = "contact_phone" - CONTACT_PHONE_SHARP = "contact_phone_sharp" - CONTACT_PHONE_ROUNDED = "contact_phone_rounded" - CONTACT_PHONE_OUTLINED = "contact_phone_outlined" - CONTACT_SUPPORT = "contact_support" - CONTACT_SUPPORT_SHARP = "contact_support_sharp" - CONTACT_SUPPORT_ROUNDED = "contact_support_rounded" - CONTACT_SUPPORT_OUTLINED = "contact_support_outlined" - CONTACTLESS = "contactless" - CONTACTLESS_SHARP = "contactless_sharp" - CONTACTLESS_ROUNDED = "contactless_rounded" - CONTACTLESS_OUTLINED = "contactless_outlined" - CONTACTS = "contacts" - CONTACTS_SHARP = "contacts_sharp" - CONTACTS_ROUNDED = "contacts_rounded" - CONTACTS_OUTLINED = "contacts_outlined" - CONTENT_COPY = "content_copy" - CONTENT_COPY_SHARP = "content_copy_sharp" - CONTENT_COPY_ROUNDED = "content_copy_rounded" - CONTENT_COPY_OUTLINED = "content_copy_outlined" - CONTENT_CUT = "content_cut" - CONTENT_CUT_SHARP = "content_cut_sharp" - CONTENT_CUT_ROUNDED = "content_cut_rounded" - CONTENT_CUT_OUTLINED = "content_cut_outlined" - CONTENT_PASTE = "content_paste" - CONTENT_PASTE_SHARP = "content_paste_sharp" - CONTENT_PASTE_ROUNDED = "content_paste_rounded" - CONTENT_PASTE_OUTLINED = "content_paste_outlined" - CONTENT_PASTE_GO = "content_paste_go" - CONTENT_PASTE_GO_SHARP = "content_paste_go_sharp" - CONTENT_PASTE_GO_ROUNDED = "content_paste_go_rounded" - CONTENT_PASTE_GO_OUTLINED = "content_paste_go_outlined" - CONTENT_PASTE_OFF = "content_paste_off" - CONTENT_PASTE_OFF_SHARP = "content_paste_off_sharp" - CONTENT_PASTE_OFF_ROUNDED = "content_paste_off_rounded" - CONTENT_PASTE_OFF_OUTLINED = "content_paste_off_outlined" - CONTENT_PASTE_SEARCH = "content_paste_search" - CONTENT_PASTE_SEARCH_SHARP = "content_paste_search_sharp" - CONTENT_PASTE_SEARCH_ROUNDED = "content_paste_search_rounded" - CONTENT_PASTE_SEARCH_OUTLINED = "content_paste_search_outlined" - CONTRAST = "contrast" - CONTRAST_SHARP = "contrast_sharp" - CONTRAST_ROUNDED = "contrast_rounded" - CONTRAST_OUTLINED = "contrast_outlined" - CONTROL_CAMERA = "control_camera" - CONTROL_CAMERA_SHARP = "control_camera_sharp" - CONTROL_CAMERA_ROUNDED = "control_camera_rounded" - CONTROL_CAMERA_OUTLINED = "control_camera_outlined" - CONTROL_POINT = "control_point" - CONTROL_POINT_SHARP = "control_point_sharp" - CONTROL_POINT_ROUNDED = "control_point_rounded" - CONTROL_POINT_OUTLINED = "control_point_outlined" - CONTROL_POINT_DUPLICATE = "control_point_duplicate" - CONTROL_POINT_DUPLICATE_SHARP = "control_point_duplicate_sharp" - CONTROL_POINT_DUPLICATE_ROUNDED = "control_point_duplicate_rounded" - CONTROL_POINT_DUPLICATE_OUTLINED = "control_point_duplicate_outlined" - CONVEYOR_BELT = "conveyor_belt" - COOKIE = "cookie" - COOKIE_SHARP = "cookie_sharp" - COOKIE_ROUNDED = "cookie_rounded" - COOKIE_OUTLINED = "cookie_outlined" - COPY = "copy" - COPY_SHARP = "copy_sharp" - COPY_ROUNDED = "copy_rounded" - COPY_OUTLINED = "copy_outlined" - COPY_ALL = "copy_all" - COPY_ALL_SHARP = "copy_all_sharp" - COPY_ALL_ROUNDED = "copy_all_rounded" - COPY_ALL_OUTLINED = "copy_all_outlined" - COPYRIGHT = "copyright" - COPYRIGHT_SHARP = "copyright_sharp" - COPYRIGHT_ROUNDED = "copyright_rounded" - COPYRIGHT_OUTLINED = "copyright_outlined" - CORONAVIRUS = "coronavirus" - CORONAVIRUS_SHARP = "coronavirus_sharp" - CORONAVIRUS_ROUNDED = "coronavirus_rounded" - CORONAVIRUS_OUTLINED = "coronavirus_outlined" - CORPORATE_FARE = "corporate_fare" - CORPORATE_FARE_SHARP = "corporate_fare_sharp" - CORPORATE_FARE_ROUNDED = "corporate_fare_rounded" - CORPORATE_FARE_OUTLINED = "corporate_fare_outlined" - COTTAGE = "cottage" - COTTAGE_SHARP = "cottage_sharp" - COTTAGE_ROUNDED = "cottage_rounded" - COTTAGE_OUTLINED = "cottage_outlined" - COUNTERTOPS = "countertops" - COUNTERTOPS_SHARP = "countertops_sharp" - COUNTERTOPS_ROUNDED = "countertops_rounded" - COUNTERTOPS_OUTLINED = "countertops_outlined" - CREATE = "create" - CREATE_SHARP = "create_sharp" - CREATE_ROUNDED = "create_rounded" - CREATE_OUTLINED = "create_outlined" - CREATE_NEW_FOLDER = "create_new_folder" - CREATE_NEW_FOLDER_SHARP = "create_new_folder_sharp" - CREATE_NEW_FOLDER_ROUNDED = "create_new_folder_rounded" - CREATE_NEW_FOLDER_OUTLINED = "create_new_folder_outlined" - CREDIT_CARD = "credit_card" - CREDIT_CARD_SHARP = "credit_card_sharp" - CREDIT_CARD_ROUNDED = "credit_card_rounded" - CREDIT_CARD_OUTLINED = "credit_card_outlined" - CREDIT_CARD_OFF = "credit_card_off" - CREDIT_CARD_OFF_SHARP = "credit_card_off_sharp" - CREDIT_CARD_OFF_ROUNDED = "credit_card_off_rounded" - CREDIT_CARD_OFF_OUTLINED = "credit_card_off_outlined" - CREDIT_SCORE = "credit_score" - CREDIT_SCORE_SHARP = "credit_score_sharp" - CREDIT_SCORE_ROUNDED = "credit_score_rounded" - CREDIT_SCORE_OUTLINED = "credit_score_outlined" - CRIB = "crib" - CRIB_SHARP = "crib_sharp" - CRIB_ROUNDED = "crib_rounded" - CRIB_OUTLINED = "crib_outlined" - CRISIS_ALERT = "crisis_alert" - CRISIS_ALERT_SHARP = "crisis_alert_sharp" - CRISIS_ALERT_ROUNDED = "crisis_alert_rounded" - CRISIS_ALERT_OUTLINED = "crisis_alert_outlined" - CROP = "crop" - CROP_SHARP = "crop_sharp" - CROP_ROUNDED = "crop_rounded" - CROP_OUTLINED = "crop_outlined" - CROP_16_9 = "crop_16_9" - CROP_16_9_SHARP = "crop_16_9_sharp" - CROP_16_9_ROUNDED = "crop_16_9_rounded" - CROP_16_9_OUTLINED = "crop_16_9_outlined" - CROP_3_2 = "crop_3_2" - CROP_3_2_SHARP = "crop_3_2_sharp" - CROP_3_2_ROUNDED = "crop_3_2_rounded" - CROP_3_2_OUTLINED = "crop_3_2_outlined" - CROP_5_4 = "crop_5_4" - CROP_5_4_SHARP = "crop_5_4_sharp" - CROP_5_4_ROUNDED = "crop_5_4_rounded" - CROP_5_4_OUTLINED = "crop_5_4_outlined" - CROP_7_5 = "crop_7_5" - CROP_7_5_SHARP = "crop_7_5_sharp" - CROP_7_5_ROUNDED = "crop_7_5_rounded" - CROP_7_5_OUTLINED = "crop_7_5_outlined" - CROP_DIN = "crop_din" - CROP_DIN_SHARP = "crop_din_sharp" - CROP_DIN_ROUNDED = "crop_din_rounded" - CROP_DIN_OUTLINED = "crop_din_outlined" - CROP_FREE = "crop_free" - CROP_FREE_SHARP = "crop_free_sharp" - CROP_FREE_ROUNDED = "crop_free_rounded" - CROP_FREE_OUTLINED = "crop_free_outlined" - CROP_LANDSCAPE = "crop_landscape" - CROP_LANDSCAPE_SHARP = "crop_landscape_sharp" - CROP_LANDSCAPE_ROUNDED = "crop_landscape_rounded" - CROP_LANDSCAPE_OUTLINED = "crop_landscape_outlined" - CROP_ORIGINAL = "crop_original" - CROP_ORIGINAL_SHARP = "crop_original_sharp" - CROP_ORIGINAL_ROUNDED = "crop_original_rounded" - CROP_ORIGINAL_OUTLINED = "crop_original_outlined" - CROP_PORTRAIT = "crop_portrait" - CROP_PORTRAIT_SHARP = "crop_portrait_sharp" - CROP_PORTRAIT_ROUNDED = "crop_portrait_rounded" - CROP_PORTRAIT_OUTLINED = "crop_portrait_outlined" - CROP_ROTATE = "crop_rotate" - CROP_ROTATE_SHARP = "crop_rotate_sharp" - CROP_ROTATE_ROUNDED = "crop_rotate_rounded" - CROP_ROTATE_OUTLINED = "crop_rotate_outlined" - CROP_SQUARE = "crop_square" - CROP_SQUARE_SHARP = "crop_square_sharp" - CROP_SQUARE_ROUNDED = "crop_square_rounded" - CROP_SQUARE_OUTLINED = "crop_square_outlined" - CRUELTY_FREE = "cruelty_free" - CRUELTY_FREE_SHARP = "cruelty_free_sharp" - CRUELTY_FREE_ROUNDED = "cruelty_free_rounded" - CRUELTY_FREE_OUTLINED = "cruelty_free_outlined" - CSS = "css" - CSS_SHARP = "css_sharp" - CSS_ROUNDED = "css_rounded" - CSS_OUTLINED = "css_outlined" - CURRENCY_BITCOIN = "currency_bitcoin" - CURRENCY_BITCOIN_SHARP = "currency_bitcoin_sharp" - CURRENCY_BITCOIN_ROUNDED = "currency_bitcoin_rounded" - CURRENCY_BITCOIN_OUTLINED = "currency_bitcoin_outlined" - CURRENCY_EXCHANGE = "currency_exchange" - CURRENCY_EXCHANGE_SHARP = "currency_exchange_sharp" - CURRENCY_EXCHANGE_ROUNDED = "currency_exchange_rounded" - CURRENCY_EXCHANGE_OUTLINED = "currency_exchange_outlined" - CURRENCY_FRANC = "currency_franc" - CURRENCY_FRANC_SHARP = "currency_franc_sharp" - CURRENCY_FRANC_ROUNDED = "currency_franc_rounded" - CURRENCY_FRANC_OUTLINED = "currency_franc_outlined" - CURRENCY_LIRA = "currency_lira" - CURRENCY_LIRA_SHARP = "currency_lira_sharp" - CURRENCY_LIRA_ROUNDED = "currency_lira_rounded" - CURRENCY_LIRA_OUTLINED = "currency_lira_outlined" - CURRENCY_POUND = "currency_pound" - CURRENCY_POUND_SHARP = "currency_pound_sharp" - CURRENCY_POUND_ROUNDED = "currency_pound_rounded" - CURRENCY_POUND_OUTLINED = "currency_pound_outlined" - CURRENCY_RUBLE = "currency_ruble" - CURRENCY_RUBLE_SHARP = "currency_ruble_sharp" - CURRENCY_RUBLE_ROUNDED = "currency_ruble_rounded" - CURRENCY_RUBLE_OUTLINED = "currency_ruble_outlined" - CURRENCY_RUPEE = "currency_rupee" - CURRENCY_RUPEE_SHARP = "currency_rupee_sharp" - CURRENCY_RUPEE_ROUNDED = "currency_rupee_rounded" - CURRENCY_RUPEE_OUTLINED = "currency_rupee_outlined" - CURRENCY_YEN = "currency_yen" - CURRENCY_YEN_SHARP = "currency_yen_sharp" - CURRENCY_YEN_ROUNDED = "currency_yen_rounded" - CURRENCY_YEN_OUTLINED = "currency_yen_outlined" - CURRENCY_YUAN = "currency_yuan" - CURRENCY_YUAN_SHARP = "currency_yuan_sharp" - CURRENCY_YUAN_ROUNDED = "currency_yuan_rounded" - CURRENCY_YUAN_OUTLINED = "currency_yuan_outlined" - CURTAINS = "curtains" - CURTAINS_SHARP = "curtains_sharp" - CURTAINS_ROUNDED = "curtains_rounded" - CURTAINS_OUTLINED = "curtains_outlined" - CURTAINS_CLOSED = "curtains_closed" - CURTAINS_CLOSED_SHARP = "curtains_closed_sharp" - CURTAINS_CLOSED_ROUNDED = "curtains_closed_rounded" - CURTAINS_CLOSED_OUTLINED = "curtains_closed_outlined" - CUT = "cut" - CUT_SHARP = "cut_sharp" - CUT_ROUNDED = "cut_rounded" - CUT_OUTLINED = "cut_outlined" - CYCLONE = "cyclone" - CYCLONE_SHARP = "cyclone_sharp" - CYCLONE_ROUNDED = "cyclone_rounded" - CYCLONE_OUTLINED = "cyclone_outlined" - DANGEROUS = "dangerous" - DANGEROUS_SHARP = "dangerous_sharp" - DANGEROUS_ROUNDED = "dangerous_rounded" - DANGEROUS_OUTLINED = "dangerous_outlined" - DARK_MODE = "dark_mode" - DARK_MODE_SHARP = "dark_mode_sharp" - DARK_MODE_ROUNDED = "dark_mode_rounded" - DARK_MODE_OUTLINED = "dark_mode_outlined" - DASHBOARD = "dashboard" - DASHBOARD_SHARP = "dashboard_sharp" - DASHBOARD_ROUNDED = "dashboard_rounded" - DASHBOARD_OUTLINED = "dashboard_outlined" - DASHBOARD_CUSTOMIZE = "dashboard_customize" - DASHBOARD_CUSTOMIZE_SHARP = "dashboard_customize_sharp" - DASHBOARD_CUSTOMIZE_ROUNDED = "dashboard_customize_rounded" - DASHBOARD_CUSTOMIZE_OUTLINED = "dashboard_customize_outlined" - DATA_ARRAY = "data_array" - DATA_ARRAY_SHARP = "data_array_sharp" - DATA_ARRAY_ROUNDED = "data_array_rounded" - DATA_ARRAY_OUTLINED = "data_array_outlined" - DATA_EXPLORATION = "data_exploration" - DATA_EXPLORATION_SHARP = "data_exploration_sharp" - DATA_EXPLORATION_ROUNDED = "data_exploration_rounded" - DATA_EXPLORATION_OUTLINED = "data_exploration_outlined" - DATA_OBJECT = "data_object" - DATA_OBJECT_SHARP = "data_object_sharp" - DATA_OBJECT_ROUNDED = "data_object_rounded" - DATA_OBJECT_OUTLINED = "data_object_outlined" - DATA_SAVER_OFF = "data_saver_off" - DATA_SAVER_OFF_SHARP = "data_saver_off_sharp" - DATA_SAVER_OFF_ROUNDED = "data_saver_off_rounded" - DATA_SAVER_OFF_OUTLINED = "data_saver_off_outlined" - DATA_SAVER_ON = "data_saver_on" - DATA_SAVER_ON_SHARP = "data_saver_on_sharp" - DATA_SAVER_ON_ROUNDED = "data_saver_on_rounded" - DATA_SAVER_ON_OUTLINED = "data_saver_on_outlined" - DATA_THRESHOLDING = "data_thresholding" - DATA_THRESHOLDING_SHARP = "data_thresholding_sharp" - DATA_THRESHOLDING_ROUNDED = "data_thresholding_rounded" - DATA_THRESHOLDING_OUTLINED = "data_thresholding_outlined" - DATA_USAGE = "data_usage" - DATA_USAGE_SHARP = "data_usage_sharp" - DATA_USAGE_ROUNDED = "data_usage_rounded" - DATA_USAGE_OUTLINED = "data_usage_outlined" - DATASET = "dataset" - DATASET_SHARP = "dataset_sharp" - DATASET_ROUNDED = "dataset_rounded" - DATASET_OUTLINED = "dataset_outlined" - DATASET_LINKED = "dataset_linked" - DATASET_LINKED_SHARP = "dataset_linked_sharp" - DATASET_LINKED_ROUNDED = "dataset_linked_rounded" - DATASET_LINKED_OUTLINED = "dataset_linked_outlined" - DATE_RANGE = "date_range" - DATE_RANGE_SHARP = "date_range_sharp" - DATE_RANGE_ROUNDED = "date_range_rounded" - DATE_RANGE_OUTLINED = "date_range_outlined" - DEBLUR = "deblur" - DEBLUR_SHARP = "deblur_sharp" - DEBLUR_ROUNDED = "deblur_rounded" - DEBLUR_OUTLINED = "deblur_outlined" - DECK = "deck" - DECK_SHARP = "deck_sharp" - DECK_ROUNDED = "deck_rounded" - DECK_OUTLINED = "deck_outlined" - DEHAZE = "dehaze" - DEHAZE_SHARP = "dehaze_sharp" - DEHAZE_ROUNDED = "dehaze_rounded" - DEHAZE_OUTLINED = "dehaze_outlined" - DELETE = "delete" - DELETE_SHARP = "delete_sharp" - DELETE_ROUNDED = "delete_rounded" - DELETE_OUTLINED = "delete_outlined" - DELETE_FOREVER = "delete_forever" - DELETE_FOREVER_SHARP = "delete_forever_sharp" - DELETE_FOREVER_ROUNDED = "delete_forever_rounded" - DELETE_FOREVER_OUTLINED = "delete_forever_outlined" - DELETE_OUTLINE = "delete_outline" - DELETE_OUTLINE_SHARP = "delete_outline_sharp" - DELETE_OUTLINE_ROUNDED = "delete_outline_rounded" - DELETE_OUTLINE_OUTLINED = "delete_outline_outlined" - DELETE_SWEEP = "delete_sweep" - DELETE_SWEEP_SHARP = "delete_sweep_sharp" - DELETE_SWEEP_ROUNDED = "delete_sweep_rounded" - DELETE_SWEEP_OUTLINED = "delete_sweep_outlined" - DELIVERY_DINING = "delivery_dining" - DELIVERY_DINING_SHARP = "delivery_dining_sharp" - DELIVERY_DINING_ROUNDED = "delivery_dining_rounded" - DELIVERY_DINING_OUTLINED = "delivery_dining_outlined" - DENSITY_LARGE = "density_large" - DENSITY_LARGE_SHARP = "density_large_sharp" - DENSITY_LARGE_ROUNDED = "density_large_rounded" - DENSITY_LARGE_OUTLINED = "density_large_outlined" - DENSITY_MEDIUM = "density_medium" - DENSITY_MEDIUM_SHARP = "density_medium_sharp" - DENSITY_MEDIUM_ROUNDED = "density_medium_rounded" - DENSITY_MEDIUM_OUTLINED = "density_medium_outlined" - DENSITY_SMALL = "density_small" - DENSITY_SMALL_SHARP = "density_small_sharp" - DENSITY_SMALL_ROUNDED = "density_small_rounded" - DENSITY_SMALL_OUTLINED = "density_small_outlined" - DEPARTURE_BOARD = "departure_board" - DEPARTURE_BOARD_SHARP = "departure_board_sharp" - DEPARTURE_BOARD_ROUNDED = "departure_board_rounded" - DEPARTURE_BOARD_OUTLINED = "departure_board_outlined" - DESCRIPTION = "description" - DESCRIPTION_SHARP = "description_sharp" - DESCRIPTION_ROUNDED = "description_rounded" - DESCRIPTION_OUTLINED = "description_outlined" - DESELECT = "deselect" - DESELECT_SHARP = "deselect_sharp" - DESELECT_ROUNDED = "deselect_rounded" - DESELECT_OUTLINED = "deselect_outlined" - DESIGN_SERVICES = "design_services" - DESIGN_SERVICES_SHARP = "design_services_sharp" - DESIGN_SERVICES_ROUNDED = "design_services_rounded" - DESIGN_SERVICES_OUTLINED = "design_services_outlined" - DESK = "desk" - DESK_SHARP = "desk_sharp" - DESK_ROUNDED = "desk_rounded" - DESK_OUTLINED = "desk_outlined" - DESKTOP_ACCESS_DISABLED = "desktop_access_disabled" - DESKTOP_ACCESS_DISABLED_SHARP = "desktop_access_disabled_sharp" - DESKTOP_ACCESS_DISABLED_ROUNDED = "desktop_access_disabled_rounded" - DESKTOP_ACCESS_DISABLED_OUTLINED = "desktop_access_disabled_outlined" - DESKTOP_MAC = "desktop_mac" - DESKTOP_MAC_SHARP = "desktop_mac_sharp" - DESKTOP_MAC_ROUNDED = "desktop_mac_rounded" - DESKTOP_MAC_OUTLINED = "desktop_mac_outlined" - DESKTOP_WINDOWS = "desktop_windows" - DESKTOP_WINDOWS_SHARP = "desktop_windows_sharp" - DESKTOP_WINDOWS_ROUNDED = "desktop_windows_rounded" - DESKTOP_WINDOWS_OUTLINED = "desktop_windows_outlined" - DETAILS = "details" - DETAILS_SHARP = "details_sharp" - DETAILS_ROUNDED = "details_rounded" - DETAILS_OUTLINED = "details_outlined" - DEVELOPER_BOARD = "developer_board" - DEVELOPER_BOARD_SHARP = "developer_board_sharp" - DEVELOPER_BOARD_ROUNDED = "developer_board_rounded" - DEVELOPER_BOARD_OUTLINED = "developer_board_outlined" - DEVELOPER_BOARD_OFF = "developer_board_off" - DEVELOPER_BOARD_OFF_SHARP = "developer_board_off_sharp" - DEVELOPER_BOARD_OFF_ROUNDED = "developer_board_off_rounded" - DEVELOPER_BOARD_OFF_OUTLINED = "developer_board_off_outlined" - DEVELOPER_MODE = "developer_mode" - DEVELOPER_MODE_SHARP = "developer_mode_sharp" - DEVELOPER_MODE_ROUNDED = "developer_mode_rounded" - DEVELOPER_MODE_OUTLINED = "developer_mode_outlined" - DEVICE_HUB = "device_hub" - DEVICE_HUB_SHARP = "device_hub_sharp" - DEVICE_HUB_ROUNDED = "device_hub_rounded" - DEVICE_HUB_OUTLINED = "device_hub_outlined" - DEVICE_THERMOSTAT = "device_thermostat" - DEVICE_THERMOSTAT_SHARP = "device_thermostat_sharp" - DEVICE_THERMOSTAT_ROUNDED = "device_thermostat_rounded" - DEVICE_THERMOSTAT_OUTLINED = "device_thermostat_outlined" - DEVICE_UNKNOWN = "device_unknown" - DEVICE_UNKNOWN_SHARP = "device_unknown_sharp" - DEVICE_UNKNOWN_ROUNDED = "device_unknown_rounded" - DEVICE_UNKNOWN_OUTLINED = "device_unknown_outlined" - DEVICES = "devices" - DEVICES_SHARP = "devices_sharp" - DEVICES_ROUNDED = "devices_rounded" - DEVICES_OUTLINED = "devices_outlined" - DEVICES_FOLD = "devices_fold" - DEVICES_FOLD_SHARP = "devices_fold_sharp" - DEVICES_FOLD_ROUNDED = "devices_fold_rounded" - DEVICES_FOLD_OUTLINED = "devices_fold_outlined" - DEVICES_OTHER = "devices_other" - DEVICES_OTHER_SHARP = "devices_other_sharp" - DEVICES_OTHER_ROUNDED = "devices_other_rounded" - DEVICES_OTHER_OUTLINED = "devices_other_outlined" - DEW_POINT = "dew_point" - DIALER_SIP = "dialer_sip" - DIALER_SIP_SHARP = "dialer_sip_sharp" - DIALER_SIP_ROUNDED = "dialer_sip_rounded" - DIALER_SIP_OUTLINED = "dialer_sip_outlined" - DIALPAD = "dialpad" - DIALPAD_SHARP = "dialpad_sharp" - DIALPAD_ROUNDED = "dialpad_rounded" - DIALPAD_OUTLINED = "dialpad_outlined" - DIAMOND = "diamond" - DIAMOND_SHARP = "diamond_sharp" - DIAMOND_ROUNDED = "diamond_rounded" - DIAMOND_OUTLINED = "diamond_outlined" - DIFFERENCE = "difference" - DIFFERENCE_SHARP = "difference_sharp" - DIFFERENCE_ROUNDED = "difference_rounded" - DIFFERENCE_OUTLINED = "difference_outlined" - DINING = "dining" - DINING_SHARP = "dining_sharp" - DINING_ROUNDED = "dining_rounded" - DINING_OUTLINED = "dining_outlined" - DINNER_DINING = "dinner_dining" - DINNER_DINING_SHARP = "dinner_dining_sharp" - DINNER_DINING_ROUNDED = "dinner_dining_rounded" - DINNER_DINING_OUTLINED = "dinner_dining_outlined" - DIRECTIONS = "directions" - DIRECTIONS_SHARP = "directions_sharp" - DIRECTIONS_ROUNDED = "directions_rounded" - DIRECTIONS_OUTLINED = "directions_outlined" - DIRECTIONS_BIKE = "directions_bike" - DIRECTIONS_BIKE_SHARP = "directions_bike_sharp" - DIRECTIONS_BIKE_ROUNDED = "directions_bike_rounded" - DIRECTIONS_BIKE_OUTLINED = "directions_bike_outlined" - DIRECTIONS_BOAT = "directions_boat" - DIRECTIONS_BOAT_SHARP = "directions_boat_sharp" - DIRECTIONS_BOAT_ROUNDED = "directions_boat_rounded" - DIRECTIONS_BOAT_OUTLINED = "directions_boat_outlined" - DIRECTIONS_BOAT_FILLED = "directions_boat_filled" - DIRECTIONS_BOAT_FILLED_SHARP = "directions_boat_filled_sharp" - DIRECTIONS_BOAT_FILLED_ROUNDED = "directions_boat_filled_rounded" - DIRECTIONS_BOAT_FILLED_OUTLINED = "directions_boat_filled_outlined" - DIRECTIONS_BUS = "directions_bus" - DIRECTIONS_BUS_SHARP = "directions_bus_sharp" - DIRECTIONS_BUS_ROUNDED = "directions_bus_rounded" - DIRECTIONS_BUS_OUTLINED = "directions_bus_outlined" - DIRECTIONS_BUS_FILLED = "directions_bus_filled" - DIRECTIONS_BUS_FILLED_SHARP = "directions_bus_filled_sharp" - DIRECTIONS_BUS_FILLED_ROUNDED = "directions_bus_filled_rounded" - DIRECTIONS_BUS_FILLED_OUTLINED = "directions_bus_filled_outlined" - DIRECTIONS_CAR = "directions_car" - DIRECTIONS_CAR_SHARP = "directions_car_sharp" - DIRECTIONS_CAR_ROUNDED = "directions_car_rounded" - DIRECTIONS_CAR_OUTLINED = "directions_car_outlined" - DIRECTIONS_CAR_FILLED = "directions_car_filled" - DIRECTIONS_CAR_FILLED_SHARP = "directions_car_filled_sharp" - DIRECTIONS_CAR_FILLED_ROUNDED = "directions_car_filled_rounded" - DIRECTIONS_CAR_FILLED_OUTLINED = "directions_car_filled_outlined" - DIRECTIONS_FERRY = "directions_ferry" - DIRECTIONS_FERRY_SHARP = "directions_ferry_sharp" - DIRECTIONS_FERRY_ROUNDED = "directions_ferry_rounded" - DIRECTIONS_FERRY_OUTLINED = "directions_ferry_outlined" - DIRECTIONS_OFF = "directions_off" - DIRECTIONS_OFF_SHARP = "directions_off_sharp" - DIRECTIONS_OFF_ROUNDED = "directions_off_rounded" - DIRECTIONS_OFF_OUTLINED = "directions_off_outlined" - DIRECTIONS_RAILWAY = "directions_railway" - DIRECTIONS_RAILWAY_SHARP = "directions_railway_sharp" - DIRECTIONS_RAILWAY_ROUNDED = "directions_railway_rounded" - DIRECTIONS_RAILWAY_OUTLINED = "directions_railway_outlined" - DIRECTIONS_RAILWAY_FILLED = "directions_railway_filled" - DIRECTIONS_RAILWAY_FILLED_SHARP = "directions_railway_filled_sharp" - DIRECTIONS_RAILWAY_FILLED_ROUNDED = "directions_railway_filled_rounded" - DIRECTIONS_RAILWAY_FILLED_OUTLINED = "directions_railway_filled_outlined" - DIRECTIONS_RUN = "directions_run" - DIRECTIONS_RUN_SHARP = "directions_run_sharp" - DIRECTIONS_RUN_ROUNDED = "directions_run_rounded" - DIRECTIONS_RUN_OUTLINED = "directions_run_outlined" - DIRECTIONS_SUBWAY = "directions_subway" - DIRECTIONS_SUBWAY_SHARP = "directions_subway_sharp" - DIRECTIONS_SUBWAY_ROUNDED = "directions_subway_rounded" - DIRECTIONS_SUBWAY_OUTLINED = "directions_subway_outlined" - DIRECTIONS_SUBWAY_FILLED = "directions_subway_filled" - DIRECTIONS_SUBWAY_FILLED_SHARP = "directions_subway_filled_sharp" - DIRECTIONS_SUBWAY_FILLED_ROUNDED = "directions_subway_filled_rounded" - DIRECTIONS_SUBWAY_FILLED_OUTLINED = "directions_subway_filled_outlined" - DIRECTIONS_TRAIN = "directions_train" - DIRECTIONS_TRAIN_SHARP = "directions_train_sharp" - DIRECTIONS_TRAIN_ROUNDED = "directions_train_rounded" - DIRECTIONS_TRAIN_OUTLINED = "directions_train_outlined" - DIRECTIONS_TRANSIT = "directions_transit" - DIRECTIONS_TRANSIT_SHARP = "directions_transit_sharp" - DIRECTIONS_TRANSIT_ROUNDED = "directions_transit_rounded" - DIRECTIONS_TRANSIT_OUTLINED = "directions_transit_outlined" - DIRECTIONS_TRANSIT_FILLED = "directions_transit_filled" - DIRECTIONS_TRANSIT_FILLED_SHARP = "directions_transit_filled_sharp" - DIRECTIONS_TRANSIT_FILLED_ROUNDED = "directions_transit_filled_rounded" - DIRECTIONS_TRANSIT_FILLED_OUTLINED = "directions_transit_filled_outlined" - DIRECTIONS_WALK = "directions_walk" - DIRECTIONS_WALK_SHARP = "directions_walk_sharp" - DIRECTIONS_WALK_ROUNDED = "directions_walk_rounded" - DIRECTIONS_WALK_OUTLINED = "directions_walk_outlined" - DIRTY_LENS = "dirty_lens" - DIRTY_LENS_SHARP = "dirty_lens_sharp" - DIRTY_LENS_ROUNDED = "dirty_lens_rounded" - DIRTY_LENS_OUTLINED = "dirty_lens_outlined" - DISABLED_BY_DEFAULT = "disabled_by_default" - DISABLED_BY_DEFAULT_SHARP = "disabled_by_default_sharp" - DISABLED_BY_DEFAULT_ROUNDED = "disabled_by_default_rounded" - DISABLED_BY_DEFAULT_OUTLINED = "disabled_by_default_outlined" - DISABLED_VISIBLE = "disabled_visible" - DISABLED_VISIBLE_SHARP = "disabled_visible_sharp" - DISABLED_VISIBLE_ROUNDED = "disabled_visible_rounded" - DISABLED_VISIBLE_OUTLINED = "disabled_visible_outlined" - DISC_FULL = "disc_full" - DISC_FULL_SHARP = "disc_full_sharp" - DISC_FULL_ROUNDED = "disc_full_rounded" - DISC_FULL_OUTLINED = "disc_full_outlined" - DISCORD = "discord" - DISCORD_SHARP = "discord_sharp" - DISCORD_ROUNDED = "discord_rounded" - DISCORD_OUTLINED = "discord_outlined" - DISCOUNT = "discount" - DISCOUNT_SHARP = "discount_sharp" - DISCOUNT_ROUNDED = "discount_rounded" - DISCOUNT_OUTLINED = "discount_outlined" - DISPLAY_SETTINGS = "display_settings" - DISPLAY_SETTINGS_SHARP = "display_settings_sharp" - DISPLAY_SETTINGS_ROUNDED = "display_settings_rounded" - DISPLAY_SETTINGS_OUTLINED = "display_settings_outlined" - DIVERSITY_1 = "diversity_1" - DIVERSITY_1_SHARP = "diversity_1_sharp" - DIVERSITY_1_ROUNDED = "diversity_1_rounded" - DIVERSITY_1_OUTLINED = "diversity_1_outlined" - DIVERSITY_2 = "diversity_2" - DIVERSITY_2_SHARP = "diversity_2_sharp" - DIVERSITY_2_ROUNDED = "diversity_2_rounded" - DIVERSITY_2_OUTLINED = "diversity_2_outlined" - DIVERSITY_3 = "diversity_3" - DIVERSITY_3_SHARP = "diversity_3_sharp" - DIVERSITY_3_ROUNDED = "diversity_3_rounded" - DIVERSITY_3_OUTLINED = "diversity_3_outlined" - DND_FORWARDSLASH = "dnd_forwardslash" - DND_FORWARDSLASH_SHARP = "dnd_forwardslash_sharp" - DND_FORWARDSLASH_ROUNDED = "dnd_forwardslash_rounded" - DND_FORWARDSLASH_OUTLINED = "dnd_forwardslash_outlined" - DNS = "dns" - DNS_SHARP = "dns_sharp" - DNS_ROUNDED = "dns_rounded" - DNS_OUTLINED = "dns_outlined" - DO_DISTURB = "do_disturb" - DO_DISTURB_SHARP = "do_disturb_sharp" - DO_DISTURB_ROUNDED = "do_disturb_rounded" - DO_DISTURB_OUTLINED = "do_disturb_outlined" - DO_DISTURB_ALT = "do_disturb_alt" - DO_DISTURB_ALT_SHARP = "do_disturb_alt_sharp" - DO_DISTURB_ALT_ROUNDED = "do_disturb_alt_rounded" - DO_DISTURB_ALT_OUTLINED = "do_disturb_alt_outlined" - DO_DISTURB_OFF = "do_disturb_off" - DO_DISTURB_OFF_SHARP = "do_disturb_off_sharp" - DO_DISTURB_OFF_ROUNDED = "do_disturb_off_rounded" - DO_DISTURB_OFF_OUTLINED = "do_disturb_off_outlined" - DO_DISTURB_ON = "do_disturb_on" - DO_DISTURB_ON_SHARP = "do_disturb_on_sharp" - DO_DISTURB_ON_ROUNDED = "do_disturb_on_rounded" - DO_DISTURB_ON_OUTLINED = "do_disturb_on_outlined" - DO_NOT_DISTURB = "do_not_disturb" - DO_NOT_DISTURB_SHARP = "do_not_disturb_sharp" - DO_NOT_DISTURB_ROUNDED = "do_not_disturb_rounded" - DO_NOT_DISTURB_OUTLINED = "do_not_disturb_outlined" - DO_NOT_DISTURB_ALT = "do_not_disturb_alt" - DO_NOT_DISTURB_ALT_SHARP = "do_not_disturb_alt_sharp" - DO_NOT_DISTURB_ALT_ROUNDED = "do_not_disturb_alt_rounded" - DO_NOT_DISTURB_ALT_OUTLINED = "do_not_disturb_alt_outlined" - DO_NOT_DISTURB_OFF = "do_not_disturb_off" - DO_NOT_DISTURB_OFF_SHARP = "do_not_disturb_off_sharp" - DO_NOT_DISTURB_OFF_ROUNDED = "do_not_disturb_off_rounded" - DO_NOT_DISTURB_OFF_OUTLINED = "do_not_disturb_off_outlined" - DO_NOT_DISTURB_ON = "do_not_disturb_on" - DO_NOT_DISTURB_ON_SHARP = "do_not_disturb_on_sharp" - DO_NOT_DISTURB_ON_ROUNDED = "do_not_disturb_on_rounded" - DO_NOT_DISTURB_ON_OUTLINED = "do_not_disturb_on_outlined" - DO_NOT_DISTURB_ON_TOTAL_SILENCE = "do_not_disturb_on_total_silence" - DO_NOT_DISTURB_ON_TOTAL_SILENCE_SHARP = "do_not_disturb_on_total_silence_sharp" - DO_NOT_DISTURB_ON_TOTAL_SILENCE_ROUNDED = "do_not_disturb_on_total_silence_rounded" - DO_NOT_DISTURB_ON_TOTAL_SILENCE_OUTLINED = ( - "do_not_disturb_on_total_silence_outlined" - ) - DO_NOT_STEP = "do_not_step" - DO_NOT_STEP_SHARP = "do_not_step_sharp" - DO_NOT_STEP_ROUNDED = "do_not_step_rounded" - DO_NOT_STEP_OUTLINED = "do_not_step_outlined" - DO_NOT_TOUCH = "do_not_touch" - DO_NOT_TOUCH_SHARP = "do_not_touch_sharp" - DO_NOT_TOUCH_ROUNDED = "do_not_touch_rounded" - DO_NOT_TOUCH_OUTLINED = "do_not_touch_outlined" - DOCK = "dock" - DOCK_SHARP = "dock_sharp" - DOCK_ROUNDED = "dock_rounded" - DOCK_OUTLINED = "dock_outlined" - DOCUMENT_SCANNER = "document_scanner" - DOCUMENT_SCANNER_SHARP = "document_scanner_sharp" - DOCUMENT_SCANNER_ROUNDED = "document_scanner_rounded" - DOCUMENT_SCANNER_OUTLINED = "document_scanner_outlined" - DOMAIN = "domain" - DOMAIN_SHARP = "domain_sharp" - DOMAIN_ROUNDED = "domain_rounded" - DOMAIN_OUTLINED = "domain_outlined" - DOMAIN_ADD = "domain_add" - DOMAIN_ADD_SHARP = "domain_add_sharp" - DOMAIN_ADD_ROUNDED = "domain_add_rounded" - DOMAIN_ADD_OUTLINED = "domain_add_outlined" - DOMAIN_DISABLED = "domain_disabled" - DOMAIN_DISABLED_SHARP = "domain_disabled_sharp" - DOMAIN_DISABLED_ROUNDED = "domain_disabled_rounded" - DOMAIN_DISABLED_OUTLINED = "domain_disabled_outlined" - DOMAIN_VERIFICATION = "domain_verification" - DOMAIN_VERIFICATION_SHARP = "domain_verification_sharp" - DOMAIN_VERIFICATION_ROUNDED = "domain_verification_rounded" - DOMAIN_VERIFICATION_OUTLINED = "domain_verification_outlined" - DONE = "done" - DONE_SHARP = "done_sharp" - DONE_ROUNDED = "done_rounded" - DONE_OUTLINED = "done_outlined" - DONE_ALL = "done_all" - DONE_ALL_SHARP = "done_all_sharp" - DONE_ALL_ROUNDED = "done_all_rounded" - DONE_ALL_OUTLINED = "done_all_outlined" - DONE_OUTLINE = "done_outline" - DONE_OUTLINE_SHARP = "done_outline_sharp" - DONE_OUTLINE_ROUNDED = "done_outline_rounded" - DONE_OUTLINE_OUTLINED = "done_outline_outlined" - DONUT_LARGE = "donut_large" - DONUT_LARGE_SHARP = "donut_large_sharp" - DONUT_LARGE_ROUNDED = "donut_large_rounded" - DONUT_LARGE_OUTLINED = "donut_large_outlined" - DONUT_SMALL = "donut_small" - DONUT_SMALL_SHARP = "donut_small_sharp" - DONUT_SMALL_ROUNDED = "donut_small_rounded" - DONUT_SMALL_OUTLINED = "donut_small_outlined" - DOOR_BACK_DOOR = "door_back_door" - DOOR_BACK_DOOR_SHARP = "door_back_door_sharp" - DOOR_BACK_DOOR_ROUNDED = "door_back_door_rounded" - DOOR_BACK_DOOR_OUTLINED = "door_back_door_outlined" - DOOR_FRONT_DOOR = "door_front_door" - DOOR_FRONT_DOOR_SHARP = "door_front_door_sharp" - DOOR_FRONT_DOOR_ROUNDED = "door_front_door_rounded" - DOOR_FRONT_DOOR_OUTLINED = "door_front_door_outlined" - DOOR_SLIDING = "door_sliding" - DOOR_SLIDING_SHARP = "door_sliding_sharp" - DOOR_SLIDING_ROUNDED = "door_sliding_rounded" - DOOR_SLIDING_OUTLINED = "door_sliding_outlined" - DOORBELL = "doorbell" - DOORBELL_SHARP = "doorbell_sharp" - DOORBELL_ROUNDED = "doorbell_rounded" - DOORBELL_OUTLINED = "doorbell_outlined" - DOUBLE_ARROW = "double_arrow" - DOUBLE_ARROW_SHARP = "double_arrow_sharp" - DOUBLE_ARROW_ROUNDED = "double_arrow_rounded" - DOUBLE_ARROW_OUTLINED = "double_arrow_outlined" - DOWNHILL_SKIING = "downhill_skiing" - DOWNHILL_SKIING_SHARP = "downhill_skiing_sharp" - DOWNHILL_SKIING_ROUNDED = "downhill_skiing_rounded" - DOWNHILL_SKIING_OUTLINED = "downhill_skiing_outlined" - DOWNLOAD = "download" - DOWNLOAD_SHARP = "download_sharp" - DOWNLOAD_ROUNDED = "download_rounded" - DOWNLOAD_OUTLINED = "download_outlined" - DOWNLOAD_DONE = "download_done" - DOWNLOAD_DONE_SHARP = "download_done_sharp" - DOWNLOAD_DONE_ROUNDED = "download_done_rounded" - DOWNLOAD_DONE_OUTLINED = "download_done_outlined" - DOWNLOAD_FOR_OFFLINE = "download_for_offline" - DOWNLOAD_FOR_OFFLINE_SHARP = "download_for_offline_sharp" - DOWNLOAD_FOR_OFFLINE_ROUNDED = "download_for_offline_rounded" - DOWNLOAD_FOR_OFFLINE_OUTLINED = "download_for_offline_outlined" - DOWNLOADING = "downloading" - DOWNLOADING_SHARP = "downloading_sharp" - DOWNLOADING_ROUNDED = "downloading_rounded" - DOWNLOADING_OUTLINED = "downloading_outlined" - DRAFTS = "drafts" - DRAFTS_SHARP = "drafts_sharp" - DRAFTS_ROUNDED = "drafts_rounded" - DRAFTS_OUTLINED = "drafts_outlined" - DRAG_HANDLE = "drag_handle" - DRAG_HANDLE_SHARP = "drag_handle_sharp" - DRAG_HANDLE_ROUNDED = "drag_handle_rounded" - DRAG_HANDLE_OUTLINED = "drag_handle_outlined" - DRAG_INDICATOR = "drag_indicator" - DRAG_INDICATOR_SHARP = "drag_indicator_sharp" - DRAG_INDICATOR_ROUNDED = "drag_indicator_rounded" - DRAG_INDICATOR_OUTLINED = "drag_indicator_outlined" - DRAW = "draw" - DRAW_SHARP = "draw_sharp" - DRAW_ROUNDED = "draw_rounded" - DRAW_OUTLINED = "draw_outlined" - DRIVE_ETA = "drive_eta" - DRIVE_ETA_SHARP = "drive_eta_sharp" - DRIVE_ETA_ROUNDED = "drive_eta_rounded" - DRIVE_ETA_OUTLINED = "drive_eta_outlined" - DRIVE_FILE_MOVE = "drive_file_move" - DRIVE_FILE_MOVE_SHARP = "drive_file_move_sharp" - DRIVE_FILE_MOVE_ROUNDED = "drive_file_move_rounded" - DRIVE_FILE_MOVE_OUTLINED = "drive_file_move_outlined" - DRIVE_FILE_MOVE_OUTLINE = "drive_file_move_outline" - DRIVE_FILE_MOVE_RTL = "drive_file_move_rtl" - DRIVE_FILE_MOVE_RTL_SHARP = "drive_file_move_rtl_sharp" - DRIVE_FILE_MOVE_RTL_ROUNDED = "drive_file_move_rtl_rounded" - DRIVE_FILE_MOVE_RTL_OUTLINED = "drive_file_move_rtl_outlined" - DRIVE_FILE_RENAME_OUTLINE = "drive_file_rename_outline" - DRIVE_FILE_RENAME_OUTLINE_SHARP = "drive_file_rename_outline_sharp" - DRIVE_FILE_RENAME_OUTLINE_ROUNDED = "drive_file_rename_outline_rounded" - DRIVE_FILE_RENAME_OUTLINE_OUTLINED = "drive_file_rename_outline_outlined" - DRIVE_FOLDER_UPLOAD = "drive_folder_upload" - DRIVE_FOLDER_UPLOAD_SHARP = "drive_folder_upload_sharp" - DRIVE_FOLDER_UPLOAD_ROUNDED = "drive_folder_upload_rounded" - DRIVE_FOLDER_UPLOAD_OUTLINED = "drive_folder_upload_outlined" - DRY = "dry" - DRY_SHARP = "dry_sharp" - DRY_ROUNDED = "dry_rounded" - DRY_OUTLINED = "dry_outlined" - DRY_CLEANING = "dry_cleaning" - DRY_CLEANING_SHARP = "dry_cleaning_sharp" - DRY_CLEANING_ROUNDED = "dry_cleaning_rounded" - DRY_CLEANING_OUTLINED = "dry_cleaning_outlined" - DUO = "duo" - DUO_SHARP = "duo_sharp" - DUO_ROUNDED = "duo_rounded" - DUO_OUTLINED = "duo_outlined" - DVR = "dvr" - DVR_SHARP = "dvr_sharp" - DVR_ROUNDED = "dvr_rounded" - DVR_OUTLINED = "dvr_outlined" - DYNAMIC_FEED = "dynamic_feed" - DYNAMIC_FEED_SHARP = "dynamic_feed_sharp" - DYNAMIC_FEED_ROUNDED = "dynamic_feed_rounded" - DYNAMIC_FEED_OUTLINED = "dynamic_feed_outlined" - DYNAMIC_FORM = "dynamic_form" - DYNAMIC_FORM_SHARP = "dynamic_form_sharp" - DYNAMIC_FORM_ROUNDED = "dynamic_form_rounded" - DYNAMIC_FORM_OUTLINED = "dynamic_form_outlined" - E_MOBILEDATA = "e_mobiledata" - E_MOBILEDATA_SHARP = "e_mobiledata_sharp" - E_MOBILEDATA_ROUNDED = "e_mobiledata_rounded" - E_MOBILEDATA_OUTLINED = "e_mobiledata_outlined" - EARBUDS = "earbuds" - EARBUDS_SHARP = "earbuds_sharp" - EARBUDS_ROUNDED = "earbuds_rounded" - EARBUDS_OUTLINED = "earbuds_outlined" - EARBUDS_BATTERY = "earbuds_battery" - EARBUDS_BATTERY_SHARP = "earbuds_battery_sharp" - EARBUDS_BATTERY_ROUNDED = "earbuds_battery_rounded" - EARBUDS_BATTERY_OUTLINED = "earbuds_battery_outlined" - EAST = "east" - EAST_SHARP = "east_sharp" - EAST_ROUNDED = "east_rounded" - EAST_OUTLINED = "east_outlined" - ECO = "eco" - ECO_SHARP = "eco_sharp" - ECO_ROUNDED = "eco_rounded" - ECO_OUTLINED = "eco_outlined" - EDGESENSOR_HIGH = "edgesensor_high" - EDGESENSOR_HIGH_SHARP = "edgesensor_high_sharp" - EDGESENSOR_HIGH_ROUNDED = "edgesensor_high_rounded" - EDGESENSOR_HIGH_OUTLINED = "edgesensor_high_outlined" - EDGESENSOR_LOW = "edgesensor_low" - EDGESENSOR_LOW_SHARP = "edgesensor_low_sharp" - EDGESENSOR_LOW_ROUNDED = "edgesensor_low_rounded" - EDGESENSOR_LOW_OUTLINED = "edgesensor_low_outlined" - EDIT = "edit" - EDIT_SHARP = "edit_sharp" - EDIT_ROUNDED = "edit_rounded" - EDIT_OUTLINED = "edit_outlined" - EDIT_ATTRIBUTES = "edit_attributes" - EDIT_ATTRIBUTES_SHARP = "edit_attributes_sharp" - EDIT_ATTRIBUTES_ROUNDED = "edit_attributes_rounded" - EDIT_ATTRIBUTES_OUTLINED = "edit_attributes_outlined" - EDIT_CALENDAR = "edit_calendar" - EDIT_CALENDAR_SHARP = "edit_calendar_sharp" - EDIT_CALENDAR_ROUNDED = "edit_calendar_rounded" - EDIT_CALENDAR_OUTLINED = "edit_calendar_outlined" - EDIT_DOCUMENT = "edit_document" - EDIT_LOCATION = "edit_location" - EDIT_LOCATION_SHARP = "edit_location_sharp" - EDIT_LOCATION_ROUNDED = "edit_location_rounded" - EDIT_LOCATION_OUTLINED = "edit_location_outlined" - EDIT_LOCATION_ALT = "edit_location_alt" - EDIT_LOCATION_ALT_SHARP = "edit_location_alt_sharp" - EDIT_LOCATION_ALT_ROUNDED = "edit_location_alt_rounded" - EDIT_LOCATION_ALT_OUTLINED = "edit_location_alt_outlined" - EDIT_NOTE = "edit_note" - EDIT_NOTE_SHARP = "edit_note_sharp" - EDIT_NOTE_ROUNDED = "edit_note_rounded" - EDIT_NOTE_OUTLINED = "edit_note_outlined" - EDIT_NOTIFICATIONS = "edit_notifications" - EDIT_NOTIFICATIONS_SHARP = "edit_notifications_sharp" - EDIT_NOTIFICATIONS_ROUNDED = "edit_notifications_rounded" - EDIT_NOTIFICATIONS_OUTLINED = "edit_notifications_outlined" - EDIT_OFF = "edit_off" - EDIT_OFF_SHARP = "edit_off_sharp" - EDIT_OFF_ROUNDED = "edit_off_rounded" - EDIT_OFF_OUTLINED = "edit_off_outlined" - EDIT_ROAD = "edit_road" - EDIT_ROAD_SHARP = "edit_road_sharp" - EDIT_ROAD_ROUNDED = "edit_road_rounded" - EDIT_ROAD_OUTLINED = "edit_road_outlined" - EDIT_SQUARE = "edit_square" - EGG = "egg" - EGG_SHARP = "egg_sharp" - EGG_ROUNDED = "egg_rounded" - EGG_OUTLINED = "egg_outlined" - EGG_ALT = "egg_alt" - EGG_ALT_SHARP = "egg_alt_sharp" - EGG_ALT_ROUNDED = "egg_alt_rounded" - EGG_ALT_OUTLINED = "egg_alt_outlined" - EJECT = "eject" - EJECT_SHARP = "eject_sharp" - EJECT_ROUNDED = "eject_rounded" - EJECT_OUTLINED = "eject_outlined" - ELDERLY = "elderly" - ELDERLY_SHARP = "elderly_sharp" - ELDERLY_ROUNDED = "elderly_rounded" - ELDERLY_OUTLINED = "elderly_outlined" - ELDERLY_WOMAN = "elderly_woman" - ELDERLY_WOMAN_SHARP = "elderly_woman_sharp" - ELDERLY_WOMAN_ROUNDED = "elderly_woman_rounded" - ELDERLY_WOMAN_OUTLINED = "elderly_woman_outlined" - ELECTRIC_BIKE = "electric_bike" - ELECTRIC_BIKE_SHARP = "electric_bike_sharp" - ELECTRIC_BIKE_ROUNDED = "electric_bike_rounded" - ELECTRIC_BIKE_OUTLINED = "electric_bike_outlined" - ELECTRIC_BOLT = "electric_bolt" - ELECTRIC_BOLT_SHARP = "electric_bolt_sharp" - ELECTRIC_BOLT_ROUNDED = "electric_bolt_rounded" - ELECTRIC_BOLT_OUTLINED = "electric_bolt_outlined" - ELECTRIC_CAR = "electric_car" - ELECTRIC_CAR_SHARP = "electric_car_sharp" - ELECTRIC_CAR_ROUNDED = "electric_car_rounded" - ELECTRIC_CAR_OUTLINED = "electric_car_outlined" - ELECTRIC_METER = "electric_meter" - ELECTRIC_METER_SHARP = "electric_meter_sharp" - ELECTRIC_METER_ROUNDED = "electric_meter_rounded" - ELECTRIC_METER_OUTLINED = "electric_meter_outlined" - ELECTRIC_MOPED = "electric_moped" - ELECTRIC_MOPED_SHARP = "electric_moped_sharp" - ELECTRIC_MOPED_ROUNDED = "electric_moped_rounded" - ELECTRIC_MOPED_OUTLINED = "electric_moped_outlined" - ELECTRIC_RICKSHAW = "electric_rickshaw" - ELECTRIC_RICKSHAW_SHARP = "electric_rickshaw_sharp" - ELECTRIC_RICKSHAW_ROUNDED = "electric_rickshaw_rounded" - ELECTRIC_RICKSHAW_OUTLINED = "electric_rickshaw_outlined" - ELECTRIC_SCOOTER = "electric_scooter" - ELECTRIC_SCOOTER_SHARP = "electric_scooter_sharp" - ELECTRIC_SCOOTER_ROUNDED = "electric_scooter_rounded" - ELECTRIC_SCOOTER_OUTLINED = "electric_scooter_outlined" - ELECTRICAL_SERVICES = "electrical_services" - ELECTRICAL_SERVICES_SHARP = "electrical_services_sharp" - ELECTRICAL_SERVICES_ROUNDED = "electrical_services_rounded" - ELECTRICAL_SERVICES_OUTLINED = "electrical_services_outlined" - ELEVATOR = "elevator" - ELEVATOR_SHARP = "elevator_sharp" - ELEVATOR_ROUNDED = "elevator_rounded" - ELEVATOR_OUTLINED = "elevator_outlined" - EMAIL = "email" - EMAIL_SHARP = "email_sharp" - EMAIL_ROUNDED = "email_rounded" - EMAIL_OUTLINED = "email_outlined" - EMERGENCY = "emergency" - EMERGENCY_SHARP = "emergency_sharp" - EMERGENCY_ROUNDED = "emergency_rounded" - EMERGENCY_OUTLINED = "emergency_outlined" - EMERGENCY_RECORDING = "emergency_recording" - EMERGENCY_RECORDING_SHARP = "emergency_recording_sharp" - EMERGENCY_RECORDING_ROUNDED = "emergency_recording_rounded" - EMERGENCY_RECORDING_OUTLINED = "emergency_recording_outlined" - EMERGENCY_SHARE = "emergency_share" - EMERGENCY_SHARE_SHARP = "emergency_share_sharp" - EMERGENCY_SHARE_ROUNDED = "emergency_share_rounded" - EMERGENCY_SHARE_OUTLINED = "emergency_share_outlined" - EMOJI_EMOTIONS = "emoji_emotions" - EMOJI_EMOTIONS_SHARP = "emoji_emotions_sharp" - EMOJI_EMOTIONS_ROUNDED = "emoji_emotions_rounded" - EMOJI_EMOTIONS_OUTLINED = "emoji_emotions_outlined" - EMOJI_EVENTS = "emoji_events" - EMOJI_EVENTS_SHARP = "emoji_events_sharp" - EMOJI_EVENTS_ROUNDED = "emoji_events_rounded" - EMOJI_EVENTS_OUTLINED = "emoji_events_outlined" - EMOJI_FLAGS = "emoji_flags" - EMOJI_FLAGS_SHARP = "emoji_flags_sharp" - EMOJI_FLAGS_ROUNDED = "emoji_flags_rounded" - EMOJI_FLAGS_OUTLINED = "emoji_flags_outlined" - EMOJI_FOOD_BEVERAGE = "emoji_food_beverage" - EMOJI_FOOD_BEVERAGE_SHARP = "emoji_food_beverage_sharp" - EMOJI_FOOD_BEVERAGE_ROUNDED = "emoji_food_beverage_rounded" - EMOJI_FOOD_BEVERAGE_OUTLINED = "emoji_food_beverage_outlined" - EMOJI_NATURE = "emoji_nature" - EMOJI_NATURE_SHARP = "emoji_nature_sharp" - EMOJI_NATURE_ROUNDED = "emoji_nature_rounded" - EMOJI_NATURE_OUTLINED = "emoji_nature_outlined" - EMOJI_OBJECTS = "emoji_objects" - EMOJI_OBJECTS_SHARP = "emoji_objects_sharp" - EMOJI_OBJECTS_ROUNDED = "emoji_objects_rounded" - EMOJI_OBJECTS_OUTLINED = "emoji_objects_outlined" - EMOJI_PEOPLE = "emoji_people" - EMOJI_PEOPLE_SHARP = "emoji_people_sharp" - EMOJI_PEOPLE_ROUNDED = "emoji_people_rounded" - EMOJI_PEOPLE_OUTLINED = "emoji_people_outlined" - EMOJI_SYMBOLS = "emoji_symbols" - EMOJI_SYMBOLS_SHARP = "emoji_symbols_sharp" - EMOJI_SYMBOLS_ROUNDED = "emoji_symbols_rounded" - EMOJI_SYMBOLS_OUTLINED = "emoji_symbols_outlined" - EMOJI_TRANSPORTATION = "emoji_transportation" - EMOJI_TRANSPORTATION_SHARP = "emoji_transportation_sharp" - EMOJI_TRANSPORTATION_ROUNDED = "emoji_transportation_rounded" - EMOJI_TRANSPORTATION_OUTLINED = "emoji_transportation_outlined" - ENERGY_SAVINGS_LEAF = "energy_savings_leaf" - ENERGY_SAVINGS_LEAF_SHARP = "energy_savings_leaf_sharp" - ENERGY_SAVINGS_LEAF_ROUNDED = "energy_savings_leaf_rounded" - ENERGY_SAVINGS_LEAF_OUTLINED = "energy_savings_leaf_outlined" - ENGINEERING = "engineering" - ENGINEERING_SHARP = "engineering_sharp" - ENGINEERING_ROUNDED = "engineering_rounded" - ENGINEERING_OUTLINED = "engineering_outlined" - ENHANCE_PHOTO_TRANSLATE = "enhance_photo_translate" - ENHANCE_PHOTO_TRANSLATE_SHARP = "enhance_photo_translate_sharp" - ENHANCE_PHOTO_TRANSLATE_ROUNDED = "enhance_photo_translate_rounded" - ENHANCE_PHOTO_TRANSLATE_OUTLINED = "enhance_photo_translate_outlined" - ENHANCED_ENCRYPTION = "enhanced_encryption" - ENHANCED_ENCRYPTION_SHARP = "enhanced_encryption_sharp" - ENHANCED_ENCRYPTION_ROUNDED = "enhanced_encryption_rounded" - ENHANCED_ENCRYPTION_OUTLINED = "enhanced_encryption_outlined" - EQUALIZER = "equalizer" - EQUALIZER_SHARP = "equalizer_sharp" - EQUALIZER_ROUNDED = "equalizer_rounded" - EQUALIZER_OUTLINED = "equalizer_outlined" - ERROR = "error" - ERROR_SHARP = "error_sharp" - ERROR_ROUNDED = "error_rounded" - ERROR_OUTLINED = "error_outlined" - ERROR_OUTLINE = "error_outline" - ERROR_OUTLINE_SHARP = "error_outline_sharp" - ERROR_OUTLINE_ROUNDED = "error_outline_rounded" - ERROR_OUTLINE_OUTLINED = "error_outline_outlined" - ESCALATOR = "escalator" - ESCALATOR_SHARP = "escalator_sharp" - ESCALATOR_ROUNDED = "escalator_rounded" - ESCALATOR_OUTLINED = "escalator_outlined" - ESCALATOR_WARNING = "escalator_warning" - ESCALATOR_WARNING_SHARP = "escalator_warning_sharp" - ESCALATOR_WARNING_ROUNDED = "escalator_warning_rounded" - ESCALATOR_WARNING_OUTLINED = "escalator_warning_outlined" - EURO = "euro" - EURO_SHARP = "euro_sharp" - EURO_ROUNDED = "euro_rounded" - EURO_OUTLINED = "euro_outlined" - EURO_SYMBOL = "euro_symbol" - EURO_SYMBOL_SHARP = "euro_symbol_sharp" - EURO_SYMBOL_ROUNDED = "euro_symbol_rounded" - EURO_SYMBOL_OUTLINED = "euro_symbol_outlined" - EV_STATION = "ev_station" - EV_STATION_SHARP = "ev_station_sharp" - EV_STATION_ROUNDED = "ev_station_rounded" - EV_STATION_OUTLINED = "ev_station_outlined" - EVENT = "event" - EVENT_SHARP = "event_sharp" - EVENT_ROUNDED = "event_rounded" - EVENT_OUTLINED = "event_outlined" - EVENT_AVAILABLE = "event_available" - EVENT_AVAILABLE_SHARP = "event_available_sharp" - EVENT_AVAILABLE_ROUNDED = "event_available_rounded" - EVENT_AVAILABLE_OUTLINED = "event_available_outlined" - EVENT_BUSY = "event_busy" - EVENT_BUSY_SHARP = "event_busy_sharp" - EVENT_BUSY_ROUNDED = "event_busy_rounded" - EVENT_BUSY_OUTLINED = "event_busy_outlined" - EVENT_NOTE = "event_note" - EVENT_NOTE_SHARP = "event_note_sharp" - EVENT_NOTE_ROUNDED = "event_note_rounded" - EVENT_NOTE_OUTLINED = "event_note_outlined" - EVENT_REPEAT = "event_repeat" - EVENT_REPEAT_SHARP = "event_repeat_sharp" - EVENT_REPEAT_ROUNDED = "event_repeat_rounded" - EVENT_REPEAT_OUTLINED = "event_repeat_outlined" - EVENT_SEAT = "event_seat" - EVENT_SEAT_SHARP = "event_seat_sharp" - EVENT_SEAT_ROUNDED = "event_seat_rounded" - EVENT_SEAT_OUTLINED = "event_seat_outlined" - EXIT_TO_APP = "exit_to_app" - EXIT_TO_APP_SHARP = "exit_to_app_sharp" - EXIT_TO_APP_ROUNDED = "exit_to_app_rounded" - EXIT_TO_APP_OUTLINED = "exit_to_app_outlined" - EXPAND = "expand" - EXPAND_SHARP = "expand_sharp" - EXPAND_ROUNDED = "expand_rounded" - EXPAND_OUTLINED = "expand_outlined" - EXPAND_CIRCLE_DOWN = "expand_circle_down" - EXPAND_CIRCLE_DOWN_SHARP = "expand_circle_down_sharp" - EXPAND_CIRCLE_DOWN_ROUNDED = "expand_circle_down_rounded" - EXPAND_CIRCLE_DOWN_OUTLINED = "expand_circle_down_outlined" - EXPAND_LESS = "expand_less" - EXPAND_LESS_SHARP = "expand_less_sharp" - EXPAND_LESS_ROUNDED = "expand_less_rounded" - EXPAND_LESS_OUTLINED = "expand_less_outlined" - EXPAND_MORE = "expand_more" - EXPAND_MORE_SHARP = "expand_more_sharp" - EXPAND_MORE_ROUNDED = "expand_more_rounded" - EXPAND_MORE_OUTLINED = "expand_more_outlined" - EXPLICIT = "explicit" - EXPLICIT_SHARP = "explicit_sharp" - EXPLICIT_ROUNDED = "explicit_rounded" - EXPLICIT_OUTLINED = "explicit_outlined" - EXPLORE = "explore" - EXPLORE_SHARP = "explore_sharp" - EXPLORE_ROUNDED = "explore_rounded" - EXPLORE_OUTLINED = "explore_outlined" - EXPLORE_OFF = "explore_off" - EXPLORE_OFF_SHARP = "explore_off_sharp" - EXPLORE_OFF_ROUNDED = "explore_off_rounded" - EXPLORE_OFF_OUTLINED = "explore_off_outlined" - EXPOSURE = "exposure" - EXPOSURE_SHARP = "exposure_sharp" - EXPOSURE_ROUNDED = "exposure_rounded" - EXPOSURE_OUTLINED = "exposure_outlined" - EXPOSURE_MINUS_1 = "exposure_minus_1" - EXPOSURE_MINUS_1_SHARP = "exposure_minus_1_sharp" - EXPOSURE_MINUS_1_ROUNDED = "exposure_minus_1_rounded" - EXPOSURE_MINUS_1_OUTLINED = "exposure_minus_1_outlined" - EXPOSURE_MINUS_2 = "exposure_minus_2" - EXPOSURE_MINUS_2_SHARP = "exposure_minus_2_sharp" - EXPOSURE_MINUS_2_ROUNDED = "exposure_minus_2_rounded" - EXPOSURE_MINUS_2_OUTLINED = "exposure_minus_2_outlined" - EXPOSURE_NEG_1 = "exposure_neg_1" - EXPOSURE_NEG_1_SHARP = "exposure_neg_1_sharp" - EXPOSURE_NEG_1_ROUNDED = "exposure_neg_1_rounded" - EXPOSURE_NEG_1_OUTLINED = "exposure_neg_1_outlined" - EXPOSURE_NEG_2 = "exposure_neg_2" - EXPOSURE_NEG_2_SHARP = "exposure_neg_2_sharp" - EXPOSURE_NEG_2_ROUNDED = "exposure_neg_2_rounded" - EXPOSURE_NEG_2_OUTLINED = "exposure_neg_2_outlined" - EXPOSURE_PLUS_1 = "exposure_plus_1" - EXPOSURE_PLUS_1_SHARP = "exposure_plus_1_sharp" - EXPOSURE_PLUS_1_ROUNDED = "exposure_plus_1_rounded" - EXPOSURE_PLUS_1_OUTLINED = "exposure_plus_1_outlined" - EXPOSURE_PLUS_2 = "exposure_plus_2" - EXPOSURE_PLUS_2_SHARP = "exposure_plus_2_sharp" - EXPOSURE_PLUS_2_ROUNDED = "exposure_plus_2_rounded" - EXPOSURE_PLUS_2_OUTLINED = "exposure_plus_2_outlined" - EXPOSURE_ZERO = "exposure_zero" - EXPOSURE_ZERO_SHARP = "exposure_zero_sharp" - EXPOSURE_ZERO_ROUNDED = "exposure_zero_rounded" - EXPOSURE_ZERO_OUTLINED = "exposure_zero_outlined" - EXTENSION = "extension" - EXTENSION_SHARP = "extension_sharp" - EXTENSION_ROUNDED = "extension_rounded" - EXTENSION_OUTLINED = "extension_outlined" - EXTENSION_OFF = "extension_off" - EXTENSION_OFF_SHARP = "extension_off_sharp" - EXTENSION_OFF_ROUNDED = "extension_off_rounded" - EXTENSION_OFF_OUTLINED = "extension_off_outlined" - FACE = "face" - FACE_SHARP = "face_sharp" - FACE_ROUNDED = "face_rounded" - FACE_OUTLINED = "face_outlined" - FACE_2 = "face_2" - FACE_2_SHARP = "face_2_sharp" - FACE_2_ROUNDED = "face_2_rounded" - FACE_2_OUTLINED = "face_2_outlined" - FACE_3 = "face_3" - FACE_3_SHARP = "face_3_sharp" - FACE_3_ROUNDED = "face_3_rounded" - FACE_3_OUTLINED = "face_3_outlined" - FACE_4 = "face_4" - FACE_4_SHARP = "face_4_sharp" - FACE_4_ROUNDED = "face_4_rounded" - FACE_4_OUTLINED = "face_4_outlined" - FACE_5 = "face_5" - FACE_5_SHARP = "face_5_sharp" - FACE_5_ROUNDED = "face_5_rounded" - FACE_5_OUTLINED = "face_5_outlined" - FACE_6 = "face_6" - FACE_6_SHARP = "face_6_sharp" - FACE_6_ROUNDED = "face_6_rounded" - FACE_6_OUTLINED = "face_6_outlined" - FACE_RETOUCHING_NATURAL = "face_retouching_natural" - FACE_RETOUCHING_NATURAL_SHARP = "face_retouching_natural_sharp" - FACE_RETOUCHING_NATURAL_ROUNDED = "face_retouching_natural_rounded" - FACE_RETOUCHING_NATURAL_OUTLINED = "face_retouching_natural_outlined" - FACE_RETOUCHING_OFF = "face_retouching_off" - FACE_RETOUCHING_OFF_SHARP = "face_retouching_off_sharp" - FACE_RETOUCHING_OFF_ROUNDED = "face_retouching_off_rounded" - FACE_RETOUCHING_OFF_OUTLINED = "face_retouching_off_outlined" - FACE_UNLOCK_SHARP = "face_unlock_sharp" - FACE_UNLOCK_ROUNDED = "face_unlock_rounded" - FACE_UNLOCK_OUTLINED = "face_unlock_outlined" - FACEBOOK = "facebook" - FACEBOOK_SHARP = "facebook_sharp" - FACEBOOK_ROUNDED = "facebook_rounded" - FACEBOOK_OUTLINED = "facebook_outlined" - FACT_CHECK = "fact_check" - FACT_CHECK_SHARP = "fact_check_sharp" - FACT_CHECK_ROUNDED = "fact_check_rounded" - FACT_CHECK_OUTLINED = "fact_check_outlined" - FACTORY = "factory" - FACTORY_SHARP = "factory_sharp" - FACTORY_ROUNDED = "factory_rounded" - FACTORY_OUTLINED = "factory_outlined" - FAMILY_RESTROOM = "family_restroom" - FAMILY_RESTROOM_SHARP = "family_restroom_sharp" - FAMILY_RESTROOM_ROUNDED = "family_restroom_rounded" - FAMILY_RESTROOM_OUTLINED = "family_restroom_outlined" - FAST_FORWARD = "fast_forward" - FAST_FORWARD_SHARP = "fast_forward_sharp" - FAST_FORWARD_ROUNDED = "fast_forward_rounded" - FAST_FORWARD_OUTLINED = "fast_forward_outlined" - FAST_REWIND = "fast_rewind" - FAST_REWIND_SHARP = "fast_rewind_sharp" - FAST_REWIND_ROUNDED = "fast_rewind_rounded" - FAST_REWIND_OUTLINED = "fast_rewind_outlined" - FASTFOOD = "fastfood" - FASTFOOD_SHARP = "fastfood_sharp" - FASTFOOD_ROUNDED = "fastfood_rounded" - FASTFOOD_OUTLINED = "fastfood_outlined" - FAVORITE = "favorite" - FAVORITE_SHARP = "favorite_sharp" - FAVORITE_ROUNDED = "favorite_rounded" - FAVORITE_OUTLINED = "favorite_outlined" - FAVORITE_BORDER = "favorite_border" - FAVORITE_BORDER_SHARP = "favorite_border_sharp" - FAVORITE_BORDER_ROUNDED = "favorite_border_rounded" - FAVORITE_BORDER_OUTLINED = "favorite_border_outlined" - FAVORITE_OUTLINE = "favorite_outline" - FAVORITE_OUTLINE_SHARP = "favorite_outline_sharp" - FAVORITE_OUTLINE_ROUNDED = "favorite_outline_rounded" - FAVORITE_OUTLINE_OUTLINED = "favorite_outline_outlined" - FAX = "fax" - FAX_SHARP = "fax_sharp" - FAX_ROUNDED = "fax_rounded" - FAX_OUTLINED = "fax_outlined" - FEATURED_PLAY_LIST = "featured_play_list" - FEATURED_PLAY_LIST_SHARP = "featured_play_list_sharp" - FEATURED_PLAY_LIST_ROUNDED = "featured_play_list_rounded" - FEATURED_PLAY_LIST_OUTLINED = "featured_play_list_outlined" - FEATURED_VIDEO = "featured_video" - FEATURED_VIDEO_SHARP = "featured_video_sharp" - FEATURED_VIDEO_ROUNDED = "featured_video_rounded" - FEATURED_VIDEO_OUTLINED = "featured_video_outlined" - FEED = "feed" - FEED_SHARP = "feed_sharp" - FEED_ROUNDED = "feed_rounded" - FEED_OUTLINED = "feed_outlined" - FEEDBACK = "feedback" - FEEDBACK_SHARP = "feedback_sharp" - FEEDBACK_ROUNDED = "feedback_rounded" - FEEDBACK_OUTLINED = "feedback_outlined" - FEMALE = "female" - FEMALE_SHARP = "female_sharp" - FEMALE_ROUNDED = "female_rounded" - FEMALE_OUTLINED = "female_outlined" - FENCE = "fence" - FENCE_SHARP = "fence_sharp" - FENCE_ROUNDED = "fence_rounded" - FENCE_OUTLINED = "fence_outlined" - FESTIVAL = "festival" - FESTIVAL_SHARP = "festival_sharp" - FESTIVAL_ROUNDED = "festival_rounded" - FESTIVAL_OUTLINED = "festival_outlined" - FIBER_DVR = "fiber_dvr" - FIBER_DVR_SHARP = "fiber_dvr_sharp" - FIBER_DVR_ROUNDED = "fiber_dvr_rounded" - FIBER_DVR_OUTLINED = "fiber_dvr_outlined" - FIBER_MANUAL_RECORD = "fiber_manual_record" - FIBER_MANUAL_RECORD_SHARP = "fiber_manual_record_sharp" - FIBER_MANUAL_RECORD_ROUNDED = "fiber_manual_record_rounded" - FIBER_MANUAL_RECORD_OUTLINED = "fiber_manual_record_outlined" - FIBER_NEW = "fiber_new" - FIBER_NEW_SHARP = "fiber_new_sharp" - FIBER_NEW_ROUNDED = "fiber_new_rounded" - FIBER_NEW_OUTLINED = "fiber_new_outlined" - FIBER_PIN = "fiber_pin" - FIBER_PIN_SHARP = "fiber_pin_sharp" - FIBER_PIN_ROUNDED = "fiber_pin_rounded" - FIBER_PIN_OUTLINED = "fiber_pin_outlined" - FIBER_SMART_RECORD = "fiber_smart_record" - FIBER_SMART_RECORD_SHARP = "fiber_smart_record_sharp" - FIBER_SMART_RECORD_ROUNDED = "fiber_smart_record_rounded" - FIBER_SMART_RECORD_OUTLINED = "fiber_smart_record_outlined" - FILE_COPY = "file_copy" - FILE_COPY_SHARP = "file_copy_sharp" - FILE_COPY_ROUNDED = "file_copy_rounded" - FILE_COPY_OUTLINED = "file_copy_outlined" - FILE_DOWNLOAD = "file_download" - FILE_DOWNLOAD_SHARP = "file_download_sharp" - FILE_DOWNLOAD_ROUNDED = "file_download_rounded" - FILE_DOWNLOAD_OUTLINED = "file_download_outlined" - FILE_DOWNLOAD_DONE = "file_download_done" - FILE_DOWNLOAD_DONE_SHARP = "file_download_done_sharp" - FILE_DOWNLOAD_DONE_ROUNDED = "file_download_done_rounded" - FILE_DOWNLOAD_DONE_OUTLINED = "file_download_done_outlined" - FILE_DOWNLOAD_OFF = "file_download_off" - FILE_DOWNLOAD_OFF_SHARP = "file_download_off_sharp" - FILE_DOWNLOAD_OFF_ROUNDED = "file_download_off_rounded" - FILE_DOWNLOAD_OFF_OUTLINED = "file_download_off_outlined" - FILE_OPEN = "file_open" - FILE_OPEN_SHARP = "file_open_sharp" - FILE_OPEN_ROUNDED = "file_open_rounded" - FILE_OPEN_OUTLINED = "file_open_outlined" - FILE_PRESENT = "file_present" - FILE_PRESENT_SHARP = "file_present_sharp" - FILE_PRESENT_ROUNDED = "file_present_rounded" - FILE_PRESENT_OUTLINED = "file_present_outlined" - FILE_UPLOAD = "file_upload" - FILE_UPLOAD_SHARP = "file_upload_sharp" - FILE_UPLOAD_ROUNDED = "file_upload_rounded" - FILE_UPLOAD_OUTLINED = "file_upload_outlined" - FILE_UPLOAD_OFF = "file_upload_off" - FILTER = "filter" - FILTER_SHARP = "filter_sharp" - FILTER_ROUNDED = "filter_rounded" - FILTER_OUTLINED = "filter_outlined" - FILTER_1 = "filter_1" - FILTER_1_SHARP = "filter_1_sharp" - FILTER_1_ROUNDED = "filter_1_rounded" - FILTER_1_OUTLINED = "filter_1_outlined" - FILTER_2 = "filter_2" - FILTER_2_SHARP = "filter_2_sharp" - FILTER_2_ROUNDED = "filter_2_rounded" - FILTER_2_OUTLINED = "filter_2_outlined" - FILTER_3 = "filter_3" - FILTER_3_SHARP = "filter_3_sharp" - FILTER_3_ROUNDED = "filter_3_rounded" - FILTER_3_OUTLINED = "filter_3_outlined" - FILTER_4 = "filter_4" - FILTER_4_SHARP = "filter_4_sharp" - FILTER_4_ROUNDED = "filter_4_rounded" - FILTER_4_OUTLINED = "filter_4_outlined" - FILTER_5 = "filter_5" - FILTER_5_SHARP = "filter_5_sharp" - FILTER_5_ROUNDED = "filter_5_rounded" - FILTER_5_OUTLINED = "filter_5_outlined" - FILTER_6 = "filter_6" - FILTER_6_SHARP = "filter_6_sharp" - FILTER_6_ROUNDED = "filter_6_rounded" - FILTER_6_OUTLINED = "filter_6_outlined" - FILTER_7 = "filter_7" - FILTER_7_SHARP = "filter_7_sharp" - FILTER_7_ROUNDED = "filter_7_rounded" - FILTER_7_OUTLINED = "filter_7_outlined" - FILTER_8 = "filter_8" - FILTER_8_SHARP = "filter_8_sharp" - FILTER_8_ROUNDED = "filter_8_rounded" - FILTER_8_OUTLINED = "filter_8_outlined" - FILTER_9 = "filter_9" - FILTER_9_SHARP = "filter_9_sharp" - FILTER_9_ROUNDED = "filter_9_rounded" - FILTER_9_OUTLINED = "filter_9_outlined" - FILTER_9_PLUS = "filter_9_plus" - FILTER_9_PLUS_SHARP = "filter_9_plus_sharp" - FILTER_9_PLUS_ROUNDED = "filter_9_plus_rounded" - FILTER_9_PLUS_OUTLINED = "filter_9_plus_outlined" - FILTER_ALT = "filter_alt" - FILTER_ALT_SHARP = "filter_alt_sharp" - FILTER_ALT_ROUNDED = "filter_alt_rounded" - FILTER_ALT_OUTLINED = "filter_alt_outlined" - FILTER_ALT_OFF = "filter_alt_off" - FILTER_ALT_OFF_SHARP = "filter_alt_off_sharp" - FILTER_ALT_OFF_ROUNDED = "filter_alt_off_rounded" - FILTER_ALT_OFF_OUTLINED = "filter_alt_off_outlined" - FILTER_B_AND_W = "filter_b_and_w" - FILTER_B_AND_W_SHARP = "filter_b_and_w_sharp" - FILTER_B_AND_W_ROUNDED = "filter_b_and_w_rounded" - FILTER_B_AND_W_OUTLINED = "filter_b_and_w_outlined" - FILTER_CENTER_FOCUS = "filter_center_focus" - FILTER_CENTER_FOCUS_SHARP = "filter_center_focus_sharp" - FILTER_CENTER_FOCUS_ROUNDED = "filter_center_focus_rounded" - FILTER_CENTER_FOCUS_OUTLINED = "filter_center_focus_outlined" - FILTER_DRAMA = "filter_drama" - FILTER_DRAMA_SHARP = "filter_drama_sharp" - FILTER_DRAMA_ROUNDED = "filter_drama_rounded" - FILTER_DRAMA_OUTLINED = "filter_drama_outlined" - FILTER_FRAMES = "filter_frames" - FILTER_FRAMES_SHARP = "filter_frames_sharp" - FILTER_FRAMES_ROUNDED = "filter_frames_rounded" - FILTER_FRAMES_OUTLINED = "filter_frames_outlined" - FILTER_HDR = "filter_hdr" - FILTER_HDR_SHARP = "filter_hdr_sharp" - FILTER_HDR_ROUNDED = "filter_hdr_rounded" - FILTER_HDR_OUTLINED = "filter_hdr_outlined" - FILTER_LIST = "filter_list" - FILTER_LIST_SHARP = "filter_list_sharp" - FILTER_LIST_ROUNDED = "filter_list_rounded" - FILTER_LIST_OUTLINED = "filter_list_outlined" - FILTER_LIST_ALT = "filter_list_alt" - FILTER_LIST_OFF = "filter_list_off" - FILTER_LIST_OFF_SHARP = "filter_list_off_sharp" - FILTER_LIST_OFF_ROUNDED = "filter_list_off_rounded" - FILTER_LIST_OFF_OUTLINED = "filter_list_off_outlined" - FILTER_NONE = "filter_none" - FILTER_NONE_SHARP = "filter_none_sharp" - FILTER_NONE_ROUNDED = "filter_none_rounded" - FILTER_NONE_OUTLINED = "filter_none_outlined" - FILTER_TILT_SHIFT = "filter_tilt_shift" - FILTER_TILT_SHIFT_SHARP = "filter_tilt_shift_sharp" - FILTER_TILT_SHIFT_ROUNDED = "filter_tilt_shift_rounded" - FILTER_TILT_SHIFT_OUTLINED = "filter_tilt_shift_outlined" - FILTER_VINTAGE = "filter_vintage" - FILTER_VINTAGE_SHARP = "filter_vintage_sharp" - FILTER_VINTAGE_ROUNDED = "filter_vintage_rounded" - FILTER_VINTAGE_OUTLINED = "filter_vintage_outlined" - FIND_IN_PAGE = "find_in_page" - FIND_IN_PAGE_SHARP = "find_in_page_sharp" - FIND_IN_PAGE_ROUNDED = "find_in_page_rounded" - FIND_IN_PAGE_OUTLINED = "find_in_page_outlined" - FIND_REPLACE = "find_replace" - FIND_REPLACE_SHARP = "find_replace_sharp" - FIND_REPLACE_ROUNDED = "find_replace_rounded" - FIND_REPLACE_OUTLINED = "find_replace_outlined" - FINGERPRINT = "fingerprint" - FINGERPRINT_SHARP = "fingerprint_sharp" - FINGERPRINT_ROUNDED = "fingerprint_rounded" - FINGERPRINT_OUTLINED = "fingerprint_outlined" - FIRE_EXTINGUISHER = "fire_extinguisher" - FIRE_EXTINGUISHER_SHARP = "fire_extinguisher_sharp" - FIRE_EXTINGUISHER_ROUNDED = "fire_extinguisher_rounded" - FIRE_EXTINGUISHER_OUTLINED = "fire_extinguisher_outlined" - FIRE_HYDRANT = "fire_hydrant" - FIRE_HYDRANT_ALT = "fire_hydrant_alt" - FIRE_HYDRANT_ALT_SHARP = "fire_hydrant_alt_sharp" - FIRE_HYDRANT_ALT_ROUNDED = "fire_hydrant_alt_rounded" - FIRE_HYDRANT_ALT_OUTLINED = "fire_hydrant_alt_outlined" - FIRE_TRUCK = "fire_truck" - FIRE_TRUCK_SHARP = "fire_truck_sharp" - FIRE_TRUCK_ROUNDED = "fire_truck_rounded" - FIRE_TRUCK_OUTLINED = "fire_truck_outlined" - FIREPLACE = "fireplace" - FIREPLACE_SHARP = "fireplace_sharp" - FIREPLACE_ROUNDED = "fireplace_rounded" - FIREPLACE_OUTLINED = "fireplace_outlined" - FIRST_PAGE = "first_page" - FIRST_PAGE_SHARP = "first_page_sharp" - FIRST_PAGE_ROUNDED = "first_page_rounded" - FIRST_PAGE_OUTLINED = "first_page_outlined" - FIT_SCREEN = "fit_screen" - FIT_SCREEN_SHARP = "fit_screen_sharp" - FIT_SCREEN_ROUNDED = "fit_screen_rounded" - FIT_SCREEN_OUTLINED = "fit_screen_outlined" - FITBIT = "fitbit" - FITBIT_SHARP = "fitbit_sharp" - FITBIT_ROUNDED = "fitbit_rounded" - FITBIT_OUTLINED = "fitbit_outlined" - FITNESS_CENTER = "fitness_center" - FITNESS_CENTER_SHARP = "fitness_center_sharp" - FITNESS_CENTER_ROUNDED = "fitness_center_rounded" - FITNESS_CENTER_OUTLINED = "fitness_center_outlined" - FLAG = "flag" - FLAG_SHARP = "flag_sharp" - FLAG_ROUNDED = "flag_rounded" - FLAG_OUTLINED = "flag_outlined" - FLAG_CIRCLE = "flag_circle" - FLAG_CIRCLE_SHARP = "flag_circle_sharp" - FLAG_CIRCLE_ROUNDED = "flag_circle_rounded" - FLAG_CIRCLE_OUTLINED = "flag_circle_outlined" - FLAKY = "flaky" - FLAKY_SHARP = "flaky_sharp" - FLAKY_ROUNDED = "flaky_rounded" - FLAKY_OUTLINED = "flaky_outlined" - FLARE = "flare" - FLARE_SHARP = "flare_sharp" - FLARE_ROUNDED = "flare_rounded" - FLARE_OUTLINED = "flare_outlined" - FLASH_AUTO = "flash_auto" - FLASH_AUTO_SHARP = "flash_auto_sharp" - FLASH_AUTO_ROUNDED = "flash_auto_rounded" - FLASH_AUTO_OUTLINED = "flash_auto_outlined" - FLASH_OFF = "flash_off" - FLASH_OFF_SHARP = "flash_off_sharp" - FLASH_OFF_ROUNDED = "flash_off_rounded" - FLASH_OFF_OUTLINED = "flash_off_outlined" - FLASH_ON = "flash_on" - FLASH_ON_SHARP = "flash_on_sharp" - FLASH_ON_ROUNDED = "flash_on_rounded" - FLASH_ON_OUTLINED = "flash_on_outlined" - FLASHLIGHT_OFF = "flashlight_off" - FLASHLIGHT_OFF_SHARP = "flashlight_off_sharp" - FLASHLIGHT_OFF_ROUNDED = "flashlight_off_rounded" - FLASHLIGHT_OFF_OUTLINED = "flashlight_off_outlined" - FLASHLIGHT_ON = "flashlight_on" - FLASHLIGHT_ON_SHARP = "flashlight_on_sharp" - FLASHLIGHT_ON_ROUNDED = "flashlight_on_rounded" - FLASHLIGHT_ON_OUTLINED = "flashlight_on_outlined" - FLATWARE = "flatware" - FLATWARE_SHARP = "flatware_sharp" - FLATWARE_ROUNDED = "flatware_rounded" - FLATWARE_OUTLINED = "flatware_outlined" - FLIGHT = "flight" - FLIGHT_SHARP = "flight_sharp" - FLIGHT_ROUNDED = "flight_rounded" - FLIGHT_OUTLINED = "flight_outlined" - FLIGHT_CLASS = "flight_class" - FLIGHT_CLASS_SHARP = "flight_class_sharp" - FLIGHT_CLASS_ROUNDED = "flight_class_rounded" - FLIGHT_CLASS_OUTLINED = "flight_class_outlined" - FLIGHT_LAND = "flight_land" - FLIGHT_LAND_SHARP = "flight_land_sharp" - FLIGHT_LAND_ROUNDED = "flight_land_rounded" - FLIGHT_LAND_OUTLINED = "flight_land_outlined" - FLIGHT_TAKEOFF = "flight_takeoff" - FLIGHT_TAKEOFF_SHARP = "flight_takeoff_sharp" - FLIGHT_TAKEOFF_ROUNDED = "flight_takeoff_rounded" - FLIGHT_TAKEOFF_OUTLINED = "flight_takeoff_outlined" - FLIP = "flip" - FLIP_SHARP = "flip_sharp" - FLIP_ROUNDED = "flip_rounded" - FLIP_OUTLINED = "flip_outlined" - FLIP_CAMERA_ANDROID = "flip_camera_android" - FLIP_CAMERA_ANDROID_SHARP = "flip_camera_android_sharp" - FLIP_CAMERA_ANDROID_ROUNDED = "flip_camera_android_rounded" - FLIP_CAMERA_ANDROID_OUTLINED = "flip_camera_android_outlined" - FLIP_CAMERA_IOS = "flip_camera_ios" - FLIP_CAMERA_IOS_SHARP = "flip_camera_ios_sharp" - FLIP_CAMERA_IOS_ROUNDED = "flip_camera_ios_rounded" - FLIP_CAMERA_IOS_OUTLINED = "flip_camera_ios_outlined" - FLIP_TO_BACK = "flip_to_back" - FLIP_TO_BACK_SHARP = "flip_to_back_sharp" - FLIP_TO_BACK_ROUNDED = "flip_to_back_rounded" - FLIP_TO_BACK_OUTLINED = "flip_to_back_outlined" - FLIP_TO_FRONT = "flip_to_front" - FLIP_TO_FRONT_SHARP = "flip_to_front_sharp" - FLIP_TO_FRONT_ROUNDED = "flip_to_front_rounded" - FLIP_TO_FRONT_OUTLINED = "flip_to_front_outlined" - FLOOD = "flood" - FLOOD_SHARP = "flood_sharp" - FLOOD_ROUNDED = "flood_rounded" - FLOOD_OUTLINED = "flood_outlined" - FLOURESCENT = "flourescent" - FLOURESCENT_SHARP = "flourescent_sharp" - FLOURESCENT_ROUNDED = "flourescent_rounded" - FLOURESCENT_OUTLINED = "flourescent_outlined" - FLUORESCENT = "fluorescent" - FLUORESCENT_SHARP = "fluorescent_sharp" - FLUORESCENT_ROUNDED = "fluorescent_rounded" - FLUORESCENT_OUTLINED = "fluorescent_outlined" - FLUTTER_DASH = "flutter_dash" - FLUTTER_DASH_SHARP = "flutter_dash_sharp" - FLUTTER_DASH_ROUNDED = "flutter_dash_rounded" - FLUTTER_DASH_OUTLINED = "flutter_dash_outlined" - FMD_BAD = "fmd_bad" - FMD_BAD_SHARP = "fmd_bad_sharp" - FMD_BAD_ROUNDED = "fmd_bad_rounded" - FMD_BAD_OUTLINED = "fmd_bad_outlined" - FMD_GOOD = "fmd_good" - FMD_GOOD_SHARP = "fmd_good_sharp" - FMD_GOOD_ROUNDED = "fmd_good_rounded" - FMD_GOOD_OUTLINED = "fmd_good_outlined" - FOGGY = "foggy" - FOLDER = "folder" - FOLDER_SHARP = "folder_sharp" - FOLDER_ROUNDED = "folder_rounded" - FOLDER_OUTLINED = "folder_outlined" - FOLDER_COPY = "folder_copy" - FOLDER_COPY_SHARP = "folder_copy_sharp" - FOLDER_COPY_ROUNDED = "folder_copy_rounded" - FOLDER_COPY_OUTLINED = "folder_copy_outlined" - FOLDER_DELETE = "folder_delete" - FOLDER_DELETE_SHARP = "folder_delete_sharp" - FOLDER_DELETE_ROUNDED = "folder_delete_rounded" - FOLDER_DELETE_OUTLINED = "folder_delete_outlined" - FOLDER_OFF = "folder_off" - FOLDER_OFF_SHARP = "folder_off_sharp" - FOLDER_OFF_ROUNDED = "folder_off_rounded" - FOLDER_OFF_OUTLINED = "folder_off_outlined" - FOLDER_OPEN = "folder_open" - FOLDER_OPEN_SHARP = "folder_open_sharp" - FOLDER_OPEN_ROUNDED = "folder_open_rounded" - FOLDER_OPEN_OUTLINED = "folder_open_outlined" - FOLDER_SHARED = "folder_shared" - FOLDER_SHARED_SHARP = "folder_shared_sharp" - FOLDER_SHARED_ROUNDED = "folder_shared_rounded" - FOLDER_SHARED_OUTLINED = "folder_shared_outlined" - FOLDER_SPECIAL = "folder_special" - FOLDER_SPECIAL_SHARP = "folder_special_sharp" - FOLDER_SPECIAL_ROUNDED = "folder_special_rounded" - FOLDER_SPECIAL_OUTLINED = "folder_special_outlined" - FOLDER_ZIP = "folder_zip" - FOLDER_ZIP_SHARP = "folder_zip_sharp" - FOLDER_ZIP_ROUNDED = "folder_zip_rounded" - FOLDER_ZIP_OUTLINED = "folder_zip_outlined" - FOLLOW_THE_SIGNS = "follow_the_signs" - FOLLOW_THE_SIGNS_SHARP = "follow_the_signs_sharp" - FOLLOW_THE_SIGNS_ROUNDED = "follow_the_signs_rounded" - FOLLOW_THE_SIGNS_OUTLINED = "follow_the_signs_outlined" - FONT_DOWNLOAD = "font_download" - FONT_DOWNLOAD_SHARP = "font_download_sharp" - FONT_DOWNLOAD_ROUNDED = "font_download_rounded" - FONT_DOWNLOAD_OUTLINED = "font_download_outlined" - FONT_DOWNLOAD_OFF = "font_download_off" - FONT_DOWNLOAD_OFF_SHARP = "font_download_off_sharp" - FONT_DOWNLOAD_OFF_ROUNDED = "font_download_off_rounded" - FONT_DOWNLOAD_OFF_OUTLINED = "font_download_off_outlined" - FOOD_BANK = "food_bank" - FOOD_BANK_SHARP = "food_bank_sharp" - FOOD_BANK_ROUNDED = "food_bank_rounded" - FOOD_BANK_OUTLINED = "food_bank_outlined" - FOREST = "forest" - FOREST_SHARP = "forest_sharp" - FOREST_ROUNDED = "forest_rounded" - FOREST_OUTLINED = "forest_outlined" - FORK_LEFT = "fork_left" - FORK_LEFT_SHARP = "fork_left_sharp" - FORK_LEFT_ROUNDED = "fork_left_rounded" - FORK_LEFT_OUTLINED = "fork_left_outlined" - FORK_RIGHT = "fork_right" - FORK_RIGHT_SHARP = "fork_right_sharp" - FORK_RIGHT_ROUNDED = "fork_right_rounded" - FORK_RIGHT_OUTLINED = "fork_right_outlined" - FORKLIFT = "forklift" - FORMAT_ALIGN_CENTER = "format_align_center" - FORMAT_ALIGN_CENTER_SHARP = "format_align_center_sharp" - FORMAT_ALIGN_CENTER_ROUNDED = "format_align_center_rounded" - FORMAT_ALIGN_CENTER_OUTLINED = "format_align_center_outlined" - FORMAT_ALIGN_JUSTIFY = "format_align_justify" - FORMAT_ALIGN_JUSTIFY_SHARP = "format_align_justify_sharp" - FORMAT_ALIGN_JUSTIFY_ROUNDED = "format_align_justify_rounded" - FORMAT_ALIGN_JUSTIFY_OUTLINED = "format_align_justify_outlined" - FORMAT_ALIGN_LEFT = "format_align_left" - FORMAT_ALIGN_LEFT_SHARP = "format_align_left_sharp" - FORMAT_ALIGN_LEFT_ROUNDED = "format_align_left_rounded" - FORMAT_ALIGN_LEFT_OUTLINED = "format_align_left_outlined" - FORMAT_ALIGN_RIGHT = "format_align_right" - FORMAT_ALIGN_RIGHT_SHARP = "format_align_right_sharp" - FORMAT_ALIGN_RIGHT_ROUNDED = "format_align_right_rounded" - FORMAT_ALIGN_RIGHT_OUTLINED = "format_align_right_outlined" - FORMAT_BOLD = "format_bold" - FORMAT_BOLD_SHARP = "format_bold_sharp" - FORMAT_BOLD_ROUNDED = "format_bold_rounded" - FORMAT_BOLD_OUTLINED = "format_bold_outlined" - FORMAT_CLEAR = "format_clear" - FORMAT_CLEAR_SHARP = "format_clear_sharp" - FORMAT_CLEAR_ROUNDED = "format_clear_rounded" - FORMAT_CLEAR_OUTLINED = "format_clear_outlined" - FORMAT_COLOR_FILL = "format_color_fill" - FORMAT_COLOR_FILL_SHARP = "format_color_fill_sharp" - FORMAT_COLOR_FILL_ROUNDED = "format_color_fill_rounded" - FORMAT_COLOR_FILL_OUTLINED = "format_color_fill_outlined" - FORMAT_COLOR_RESET = "format_color_reset" - FORMAT_COLOR_RESET_SHARP = "format_color_reset_sharp" - FORMAT_COLOR_RESET_ROUNDED = "format_color_reset_rounded" - FORMAT_COLOR_RESET_OUTLINED = "format_color_reset_outlined" - FORMAT_COLOR_TEXT = "format_color_text" - FORMAT_COLOR_TEXT_SHARP = "format_color_text_sharp" - FORMAT_COLOR_TEXT_ROUNDED = "format_color_text_rounded" - FORMAT_COLOR_TEXT_OUTLINED = "format_color_text_outlined" - FORMAT_INDENT_DECREASE = "format_indent_decrease" - FORMAT_INDENT_DECREASE_SHARP = "format_indent_decrease_sharp" - FORMAT_INDENT_DECREASE_ROUNDED = "format_indent_decrease_rounded" - FORMAT_INDENT_DECREASE_OUTLINED = "format_indent_decrease_outlined" - FORMAT_INDENT_INCREASE = "format_indent_increase" - FORMAT_INDENT_INCREASE_SHARP = "format_indent_increase_sharp" - FORMAT_INDENT_INCREASE_ROUNDED = "format_indent_increase_rounded" - FORMAT_INDENT_INCREASE_OUTLINED = "format_indent_increase_outlined" - FORMAT_ITALIC = "format_italic" - FORMAT_ITALIC_SHARP = "format_italic_sharp" - FORMAT_ITALIC_ROUNDED = "format_italic_rounded" - FORMAT_ITALIC_OUTLINED = "format_italic_outlined" - FORMAT_LINE_SPACING = "format_line_spacing" - FORMAT_LINE_SPACING_SHARP = "format_line_spacing_sharp" - FORMAT_LINE_SPACING_ROUNDED = "format_line_spacing_rounded" - FORMAT_LINE_SPACING_OUTLINED = "format_line_spacing_outlined" - FORMAT_LIST_BULLETED = "format_list_bulleted" - FORMAT_LIST_BULLETED_SHARP = "format_list_bulleted_sharp" - FORMAT_LIST_BULLETED_ROUNDED = "format_list_bulleted_rounded" - FORMAT_LIST_BULLETED_OUTLINED = "format_list_bulleted_outlined" - FORMAT_LIST_BULLETED_ADD = "format_list_bulleted_add" - FORMAT_LIST_NUMBERED = "format_list_numbered" - FORMAT_LIST_NUMBERED_SHARP = "format_list_numbered_sharp" - FORMAT_LIST_NUMBERED_ROUNDED = "format_list_numbered_rounded" - FORMAT_LIST_NUMBERED_OUTLINED = "format_list_numbered_outlined" - FORMAT_LIST_NUMBERED_RTL = "format_list_numbered_rtl" - FORMAT_LIST_NUMBERED_RTL_SHARP = "format_list_numbered_rtl_sharp" - FORMAT_LIST_NUMBERED_RTL_ROUNDED = "format_list_numbered_rtl_rounded" - FORMAT_LIST_NUMBERED_RTL_OUTLINED = "format_list_numbered_rtl_outlined" - FORMAT_OVERLINE = "format_overline" - FORMAT_OVERLINE_SHARP = "format_overline_sharp" - FORMAT_OVERLINE_ROUNDED = "format_overline_rounded" - FORMAT_OVERLINE_OUTLINED = "format_overline_outlined" - FORMAT_PAINT = "format_paint" - FORMAT_PAINT_SHARP = "format_paint_sharp" - FORMAT_PAINT_ROUNDED = "format_paint_rounded" - FORMAT_PAINT_OUTLINED = "format_paint_outlined" - FORMAT_QUOTE = "format_quote" - FORMAT_QUOTE_SHARP = "format_quote_sharp" - FORMAT_QUOTE_ROUNDED = "format_quote_rounded" - FORMAT_QUOTE_OUTLINED = "format_quote_outlined" - FORMAT_SHAPES = "format_shapes" - FORMAT_SHAPES_SHARP = "format_shapes_sharp" - FORMAT_SHAPES_ROUNDED = "format_shapes_rounded" - FORMAT_SHAPES_OUTLINED = "format_shapes_outlined" - FORMAT_SIZE = "format_size" - FORMAT_SIZE_SHARP = "format_size_sharp" - FORMAT_SIZE_ROUNDED = "format_size_rounded" - FORMAT_SIZE_OUTLINED = "format_size_outlined" - FORMAT_STRIKETHROUGH = "format_strikethrough" - FORMAT_STRIKETHROUGH_SHARP = "format_strikethrough_sharp" - FORMAT_STRIKETHROUGH_ROUNDED = "format_strikethrough_rounded" - FORMAT_STRIKETHROUGH_OUTLINED = "format_strikethrough_outlined" - FORMAT_TEXTDIRECTION_L_TO_R = "format_textdirection_l_to_r" - FORMAT_TEXTDIRECTION_L_TO_R_SHARP = "format_textdirection_l_to_r_sharp" - FORMAT_TEXTDIRECTION_L_TO_R_ROUNDED = "format_textdirection_l_to_r_rounded" - FORMAT_TEXTDIRECTION_L_TO_R_OUTLINED = "format_textdirection_l_to_r_outlined" - FORMAT_TEXTDIRECTION_R_TO_L = "format_textdirection_r_to_l" - FORMAT_TEXTDIRECTION_R_TO_L_SHARP = "format_textdirection_r_to_l_sharp" - FORMAT_TEXTDIRECTION_R_TO_L_ROUNDED = "format_textdirection_r_to_l_rounded" - FORMAT_TEXTDIRECTION_R_TO_L_OUTLINED = "format_textdirection_r_to_l_outlined" - FORMAT_UNDERLINE = "format_underline" - FORMAT_UNDERLINE_SHARP = "format_underline_sharp" - FORMAT_UNDERLINE_ROUNDED = "format_underline_rounded" - FORMAT_UNDERLINE_OUTLINED = "format_underline_outlined" - FORMAT_UNDERLINED = "format_underlined" - FORMAT_UNDERLINED_SHARP = "format_underlined_sharp" - FORMAT_UNDERLINED_ROUNDED = "format_underlined_rounded" - FORMAT_UNDERLINED_OUTLINED = "format_underlined_outlined" - FORT = "fort" - FORT_SHARP = "fort_sharp" - FORT_ROUNDED = "fort_rounded" - FORT_OUTLINED = "fort_outlined" - FORUM = "forum" - FORUM_SHARP = "forum_sharp" - FORUM_ROUNDED = "forum_rounded" - FORUM_OUTLINED = "forum_outlined" - FORWARD = "forward" - FORWARD_SHARP = "forward_sharp" - FORWARD_ROUNDED = "forward_rounded" - FORWARD_OUTLINED = "forward_outlined" - FORWARD_10 = "forward_10" - FORWARD_10_SHARP = "forward_10_sharp" - FORWARD_10_ROUNDED = "forward_10_rounded" - FORWARD_10_OUTLINED = "forward_10_outlined" - FORWARD_30 = "forward_30" - FORWARD_30_SHARP = "forward_30_sharp" - FORWARD_30_ROUNDED = "forward_30_rounded" - FORWARD_30_OUTLINED = "forward_30_outlined" - FORWARD_5 = "forward_5" - FORWARD_5_SHARP = "forward_5_sharp" - FORWARD_5_ROUNDED = "forward_5_rounded" - FORWARD_5_OUTLINED = "forward_5_outlined" - FORWARD_TO_INBOX = "forward_to_inbox" - FORWARD_TO_INBOX_SHARP = "forward_to_inbox_sharp" - FORWARD_TO_INBOX_ROUNDED = "forward_to_inbox_rounded" - FORWARD_TO_INBOX_OUTLINED = "forward_to_inbox_outlined" - FOUNDATION = "foundation" - FOUNDATION_SHARP = "foundation_sharp" - FOUNDATION_ROUNDED = "foundation_rounded" - FOUNDATION_OUTLINED = "foundation_outlined" - FREE_BREAKFAST = "free_breakfast" - FREE_BREAKFAST_SHARP = "free_breakfast_sharp" - FREE_BREAKFAST_ROUNDED = "free_breakfast_rounded" - FREE_BREAKFAST_OUTLINED = "free_breakfast_outlined" - FREE_CANCELLATION = "free_cancellation" - FREE_CANCELLATION_SHARP = "free_cancellation_sharp" - FREE_CANCELLATION_ROUNDED = "free_cancellation_rounded" - FREE_CANCELLATION_OUTLINED = "free_cancellation_outlined" - FRONT_HAND = "front_hand" - FRONT_HAND_SHARP = "front_hand_sharp" - FRONT_HAND_ROUNDED = "front_hand_rounded" - FRONT_HAND_OUTLINED = "front_hand_outlined" - FRONT_LOADER = "front_loader" - FULLSCREEN = "fullscreen" - FULLSCREEN_SHARP = "fullscreen_sharp" - FULLSCREEN_ROUNDED = "fullscreen_rounded" - FULLSCREEN_OUTLINED = "fullscreen_outlined" - FULLSCREEN_EXIT = "fullscreen_exit" - FULLSCREEN_EXIT_SHARP = "fullscreen_exit_sharp" - FULLSCREEN_EXIT_ROUNDED = "fullscreen_exit_rounded" - FULLSCREEN_EXIT_OUTLINED = "fullscreen_exit_outlined" - FUNCTIONS = "functions" - FUNCTIONS_SHARP = "functions_sharp" - FUNCTIONS_ROUNDED = "functions_rounded" - FUNCTIONS_OUTLINED = "functions_outlined" - G_MOBILEDATA = "g_mobiledata" - G_MOBILEDATA_SHARP = "g_mobiledata_sharp" - G_MOBILEDATA_ROUNDED = "g_mobiledata_rounded" - G_MOBILEDATA_OUTLINED = "g_mobiledata_outlined" - G_TRANSLATE = "g_translate" - G_TRANSLATE_SHARP = "g_translate_sharp" - G_TRANSLATE_ROUNDED = "g_translate_rounded" - G_TRANSLATE_OUTLINED = "g_translate_outlined" - GAMEPAD = "gamepad" - GAMEPAD_SHARP = "gamepad_sharp" - GAMEPAD_ROUNDED = "gamepad_rounded" - GAMEPAD_OUTLINED = "gamepad_outlined" - GAMES = "games" - GAMES_SHARP = "games_sharp" - GAMES_ROUNDED = "games_rounded" - GAMES_OUTLINED = "games_outlined" - GARAGE = "garage" - GARAGE_SHARP = "garage_sharp" - GARAGE_ROUNDED = "garage_rounded" - GARAGE_OUTLINED = "garage_outlined" - GAS_METER = "gas_meter" - GAS_METER_SHARP = "gas_meter_sharp" - GAS_METER_ROUNDED = "gas_meter_rounded" - GAS_METER_OUTLINED = "gas_meter_outlined" - GAVEL = "gavel" - GAVEL_SHARP = "gavel_sharp" - GAVEL_ROUNDED = "gavel_rounded" - GAVEL_OUTLINED = "gavel_outlined" - GENERATING_TOKENS = "generating_tokens" - GENERATING_TOKENS_SHARP = "generating_tokens_sharp" - GENERATING_TOKENS_ROUNDED = "generating_tokens_rounded" - GENERATING_TOKENS_OUTLINED = "generating_tokens_outlined" - GESTURE = "gesture" - GESTURE_SHARP = "gesture_sharp" - GESTURE_ROUNDED = "gesture_rounded" - GESTURE_OUTLINED = "gesture_outlined" - GET_APP = "get_app" - GET_APP_SHARP = "get_app_sharp" - GET_APP_ROUNDED = "get_app_rounded" - GET_APP_OUTLINED = "get_app_outlined" - GIF = "gif" - GIF_SHARP = "gif_sharp" - GIF_ROUNDED = "gif_rounded" - GIF_OUTLINED = "gif_outlined" - GIF_BOX = "gif_box" - GIF_BOX_SHARP = "gif_box_sharp" - GIF_BOX_ROUNDED = "gif_box_rounded" - GIF_BOX_OUTLINED = "gif_box_outlined" - GIRL = "girl" - GIRL_SHARP = "girl_sharp" - GIRL_ROUNDED = "girl_rounded" - GIRL_OUTLINED = "girl_outlined" - GITE = "gite" - GITE_SHARP = "gite_sharp" - GITE_ROUNDED = "gite_rounded" - GITE_OUTLINED = "gite_outlined" - GOLF_COURSE = "golf_course" - GOLF_COURSE_SHARP = "golf_course_sharp" - GOLF_COURSE_ROUNDED = "golf_course_rounded" - GOLF_COURSE_OUTLINED = "golf_course_outlined" - GPP_BAD = "gpp_bad" - GPP_BAD_SHARP = "gpp_bad_sharp" - GPP_BAD_ROUNDED = "gpp_bad_rounded" - GPP_BAD_OUTLINED = "gpp_bad_outlined" - GPP_GOOD = "gpp_good" - GPP_GOOD_SHARP = "gpp_good_sharp" - GPP_GOOD_ROUNDED = "gpp_good_rounded" - GPP_GOOD_OUTLINED = "gpp_good_outlined" - GPP_MAYBE = "gpp_maybe" - GPP_MAYBE_SHARP = "gpp_maybe_sharp" - GPP_MAYBE_ROUNDED = "gpp_maybe_rounded" - GPP_MAYBE_OUTLINED = "gpp_maybe_outlined" - GPS_FIXED = "gps_fixed" - GPS_FIXED_SHARP = "gps_fixed_sharp" - GPS_FIXED_ROUNDED = "gps_fixed_rounded" - GPS_FIXED_OUTLINED = "gps_fixed_outlined" - GPS_NOT_FIXED = "gps_not_fixed" - GPS_NOT_FIXED_SHARP = "gps_not_fixed_sharp" - GPS_NOT_FIXED_ROUNDED = "gps_not_fixed_rounded" - GPS_NOT_FIXED_OUTLINED = "gps_not_fixed_outlined" - GPS_OFF = "gps_off" - GPS_OFF_SHARP = "gps_off_sharp" - GPS_OFF_ROUNDED = "gps_off_rounded" - GPS_OFF_OUTLINED = "gps_off_outlined" - GRADE = "grade" - GRADE_SHARP = "grade_sharp" - GRADE_ROUNDED = "grade_rounded" - GRADE_OUTLINED = "grade_outlined" - GRADIENT = "gradient" - GRADIENT_SHARP = "gradient_sharp" - GRADIENT_ROUNDED = "gradient_rounded" - GRADIENT_OUTLINED = "gradient_outlined" - GRADING = "grading" - GRADING_SHARP = "grading_sharp" - GRADING_ROUNDED = "grading_rounded" - GRADING_OUTLINED = "grading_outlined" - GRAIN = "grain" - GRAIN_SHARP = "grain_sharp" - GRAIN_ROUNDED = "grain_rounded" - GRAIN_OUTLINED = "grain_outlined" - GRAPHIC_EQ = "graphic_eq" - GRAPHIC_EQ_SHARP = "graphic_eq_sharp" - GRAPHIC_EQ_ROUNDED = "graphic_eq_rounded" - GRAPHIC_EQ_OUTLINED = "graphic_eq_outlined" - GRASS = "grass" - GRASS_SHARP = "grass_sharp" - GRASS_ROUNDED = "grass_rounded" - GRASS_OUTLINED = "grass_outlined" - GRID_3X3 = "grid_3x3" - GRID_3X3_SHARP = "grid_3x3_sharp" - GRID_3X3_ROUNDED = "grid_3x3_rounded" - GRID_3X3_OUTLINED = "grid_3x3_outlined" - GRID_4X4 = "grid_4x4" - GRID_4X4_SHARP = "grid_4x4_sharp" - GRID_4X4_ROUNDED = "grid_4x4_rounded" - GRID_4X4_OUTLINED = "grid_4x4_outlined" - GRID_GOLDENRATIO = "grid_goldenratio" - GRID_GOLDENRATIO_SHARP = "grid_goldenratio_sharp" - GRID_GOLDENRATIO_ROUNDED = "grid_goldenratio_rounded" - GRID_GOLDENRATIO_OUTLINED = "grid_goldenratio_outlined" - GRID_OFF = "grid_off" - GRID_OFF_SHARP = "grid_off_sharp" - GRID_OFF_ROUNDED = "grid_off_rounded" - GRID_OFF_OUTLINED = "grid_off_outlined" - GRID_ON = "grid_on" - GRID_ON_SHARP = "grid_on_sharp" - GRID_ON_ROUNDED = "grid_on_rounded" - GRID_ON_OUTLINED = "grid_on_outlined" - GRID_VIEW = "grid_view" - GRID_VIEW_SHARP = "grid_view_sharp" - GRID_VIEW_ROUNDED = "grid_view_rounded" - GRID_VIEW_OUTLINED = "grid_view_outlined" - GROUP = "group" - GROUP_SHARP = "group_sharp" - GROUP_ROUNDED = "group_rounded" - GROUP_OUTLINED = "group_outlined" - GROUP_ADD = "group_add" - GROUP_ADD_SHARP = "group_add_sharp" - GROUP_ADD_ROUNDED = "group_add_rounded" - GROUP_ADD_OUTLINED = "group_add_outlined" - GROUP_OFF = "group_off" - GROUP_OFF_SHARP = "group_off_sharp" - GROUP_OFF_ROUNDED = "group_off_rounded" - GROUP_OFF_OUTLINED = "group_off_outlined" - GROUP_REMOVE = "group_remove" - GROUP_REMOVE_SHARP = "group_remove_sharp" - GROUP_REMOVE_ROUNDED = "group_remove_rounded" - GROUP_REMOVE_OUTLINED = "group_remove_outlined" - GROUP_WORK = "group_work" - GROUP_WORK_SHARP = "group_work_sharp" - GROUP_WORK_ROUNDED = "group_work_rounded" - GROUP_WORK_OUTLINED = "group_work_outlined" - GROUPS = "groups" - GROUPS_SHARP = "groups_sharp" - GROUPS_ROUNDED = "groups_rounded" - GROUPS_OUTLINED = "groups_outlined" - GROUPS_2 = "groups_2" - GROUPS_2_SHARP = "groups_2_sharp" - GROUPS_2_ROUNDED = "groups_2_rounded" - GROUPS_2_OUTLINED = "groups_2_outlined" - GROUPS_3 = "groups_3" - GROUPS_3_SHARP = "groups_3_sharp" - GROUPS_3_ROUNDED = "groups_3_rounded" - GROUPS_3_OUTLINED = "groups_3_outlined" - H_MOBILEDATA = "h_mobiledata" - H_MOBILEDATA_SHARP = "h_mobiledata_sharp" - H_MOBILEDATA_ROUNDED = "h_mobiledata_rounded" - H_MOBILEDATA_OUTLINED = "h_mobiledata_outlined" - H_PLUS_MOBILEDATA = "h_plus_mobiledata" - H_PLUS_MOBILEDATA_SHARP = "h_plus_mobiledata_sharp" - H_PLUS_MOBILEDATA_ROUNDED = "h_plus_mobiledata_rounded" - H_PLUS_MOBILEDATA_OUTLINED = "h_plus_mobiledata_outlined" - HAIL = "hail" - HAIL_SHARP = "hail_sharp" - HAIL_ROUNDED = "hail_rounded" - HAIL_OUTLINED = "hail_outlined" - HANDSHAKE = "handshake" - HANDSHAKE_SHARP = "handshake_sharp" - HANDSHAKE_ROUNDED = "handshake_rounded" - HANDSHAKE_OUTLINED = "handshake_outlined" - HANDYMAN = "handyman" - HANDYMAN_SHARP = "handyman_sharp" - HANDYMAN_ROUNDED = "handyman_rounded" - HANDYMAN_OUTLINED = "handyman_outlined" - HARDWARE = "hardware" - HARDWARE_SHARP = "hardware_sharp" - HARDWARE_ROUNDED = "hardware_rounded" - HARDWARE_OUTLINED = "hardware_outlined" - HD = "hd" - HD_SHARP = "hd_sharp" - HD_ROUNDED = "hd_rounded" - HD_OUTLINED = "hd_outlined" - HDR_AUTO = "hdr_auto" - HDR_AUTO_SHARP = "hdr_auto_sharp" - HDR_AUTO_ROUNDED = "hdr_auto_rounded" - HDR_AUTO_OUTLINED = "hdr_auto_outlined" - HDR_AUTO_SELECT = "hdr_auto_select" - HDR_AUTO_SELECT_SHARP = "hdr_auto_select_sharp" - HDR_AUTO_SELECT_ROUNDED = "hdr_auto_select_rounded" - HDR_AUTO_SELECT_OUTLINED = "hdr_auto_select_outlined" - HDR_ENHANCED_SELECT = "hdr_enhanced_select" - HDR_ENHANCED_SELECT_SHARP = "hdr_enhanced_select_sharp" - HDR_ENHANCED_SELECT_ROUNDED = "hdr_enhanced_select_rounded" - HDR_ENHANCED_SELECT_OUTLINED = "hdr_enhanced_select_outlined" - HDR_OFF = "hdr_off" - HDR_OFF_SHARP = "hdr_off_sharp" - HDR_OFF_ROUNDED = "hdr_off_rounded" - HDR_OFF_OUTLINED = "hdr_off_outlined" - HDR_OFF_SELECT = "hdr_off_select" - HDR_OFF_SELECT_SHARP = "hdr_off_select_sharp" - HDR_OFF_SELECT_ROUNDED = "hdr_off_select_rounded" - HDR_OFF_SELECT_OUTLINED = "hdr_off_select_outlined" - HDR_ON = "hdr_on" - HDR_ON_SHARP = "hdr_on_sharp" - HDR_ON_ROUNDED = "hdr_on_rounded" - HDR_ON_OUTLINED = "hdr_on_outlined" - HDR_ON_SELECT = "hdr_on_select" - HDR_ON_SELECT_SHARP = "hdr_on_select_sharp" - HDR_ON_SELECT_ROUNDED = "hdr_on_select_rounded" - HDR_ON_SELECT_OUTLINED = "hdr_on_select_outlined" - HDR_PLUS = "hdr_plus" - HDR_PLUS_SHARP = "hdr_plus_sharp" - HDR_PLUS_ROUNDED = "hdr_plus_rounded" - HDR_PLUS_OUTLINED = "hdr_plus_outlined" - HDR_STRONG = "hdr_strong" - HDR_STRONG_SHARP = "hdr_strong_sharp" - HDR_STRONG_ROUNDED = "hdr_strong_rounded" - HDR_STRONG_OUTLINED = "hdr_strong_outlined" - HDR_WEAK = "hdr_weak" - HDR_WEAK_SHARP = "hdr_weak_sharp" - HDR_WEAK_ROUNDED = "hdr_weak_rounded" - HDR_WEAK_OUTLINED = "hdr_weak_outlined" - HEADPHONES = "headphones" - HEADPHONES_SHARP = "headphones_sharp" - HEADPHONES_ROUNDED = "headphones_rounded" - HEADPHONES_OUTLINED = "headphones_outlined" - HEADPHONES_BATTERY = "headphones_battery" - HEADPHONES_BATTERY_SHARP = "headphones_battery_sharp" - HEADPHONES_BATTERY_ROUNDED = "headphones_battery_rounded" - HEADPHONES_BATTERY_OUTLINED = "headphones_battery_outlined" - HEADSET = "headset" - HEADSET_SHARP = "headset_sharp" - HEADSET_ROUNDED = "headset_rounded" - HEADSET_OUTLINED = "headset_outlined" - HEADSET_MIC = "headset_mic" - HEADSET_MIC_SHARP = "headset_mic_sharp" - HEADSET_MIC_ROUNDED = "headset_mic_rounded" - HEADSET_MIC_OUTLINED = "headset_mic_outlined" - HEADSET_OFF = "headset_off" - HEADSET_OFF_SHARP = "headset_off_sharp" - HEADSET_OFF_ROUNDED = "headset_off_rounded" - HEADSET_OFF_OUTLINED = "headset_off_outlined" - HEALING = "healing" - HEALING_SHARP = "healing_sharp" - HEALING_ROUNDED = "healing_rounded" - HEALING_OUTLINED = "healing_outlined" - HEALTH_AND_SAFETY = "health_and_safety" - HEALTH_AND_SAFETY_SHARP = "health_and_safety_sharp" - HEALTH_AND_SAFETY_ROUNDED = "health_and_safety_rounded" - HEALTH_AND_SAFETY_OUTLINED = "health_and_safety_outlined" - HEARING = "hearing" - HEARING_SHARP = "hearing_sharp" - HEARING_ROUNDED = "hearing_rounded" - HEARING_OUTLINED = "hearing_outlined" - HEARING_DISABLED = "hearing_disabled" - HEARING_DISABLED_SHARP = "hearing_disabled_sharp" - HEARING_DISABLED_ROUNDED = "hearing_disabled_rounded" - HEARING_DISABLED_OUTLINED = "hearing_disabled_outlined" - HEART_BROKEN = "heart_broken" - HEART_BROKEN_SHARP = "heart_broken_sharp" - HEART_BROKEN_ROUNDED = "heart_broken_rounded" - HEART_BROKEN_OUTLINED = "heart_broken_outlined" - HEAT_PUMP = "heat_pump" - HEAT_PUMP_SHARP = "heat_pump_sharp" - HEAT_PUMP_ROUNDED = "heat_pump_rounded" - HEAT_PUMP_OUTLINED = "heat_pump_outlined" - HEIGHT = "height" - HEIGHT_SHARP = "height_sharp" - HEIGHT_ROUNDED = "height_rounded" - HEIGHT_OUTLINED = "height_outlined" - HELP = "help" - HELP_SHARP = "help_sharp" - HELP_ROUNDED = "help_rounded" - HELP_OUTLINED = "help_outlined" - HELP_CENTER = "help_center" - HELP_CENTER_SHARP = "help_center_sharp" - HELP_CENTER_ROUNDED = "help_center_rounded" - HELP_CENTER_OUTLINED = "help_center_outlined" - HELP_OUTLINE = "help_outline" - HELP_OUTLINE_SHARP = "help_outline_sharp" - HELP_OUTLINE_ROUNDED = "help_outline_rounded" - HELP_OUTLINE_OUTLINED = "help_outline_outlined" - HEVC = "hevc" - HEVC_SHARP = "hevc_sharp" - HEVC_ROUNDED = "hevc_rounded" - HEVC_OUTLINED = "hevc_outlined" - HEXAGON = "hexagon" - HEXAGON_SHARP = "hexagon_sharp" - HEXAGON_ROUNDED = "hexagon_rounded" - HEXAGON_OUTLINED = "hexagon_outlined" - HIDE_IMAGE = "hide_image" - HIDE_IMAGE_SHARP = "hide_image_sharp" - HIDE_IMAGE_ROUNDED = "hide_image_rounded" - HIDE_IMAGE_OUTLINED = "hide_image_outlined" - HIDE_SOURCE = "hide_source" - HIDE_SOURCE_SHARP = "hide_source_sharp" - HIDE_SOURCE_ROUNDED = "hide_source_rounded" - HIDE_SOURCE_OUTLINED = "hide_source_outlined" - HIGH_QUALITY = "high_quality" - HIGH_QUALITY_SHARP = "high_quality_sharp" - HIGH_QUALITY_ROUNDED = "high_quality_rounded" - HIGH_QUALITY_OUTLINED = "high_quality_outlined" - HIGHLIGHT = "highlight" - HIGHLIGHT_SHARP = "highlight_sharp" - HIGHLIGHT_ROUNDED = "highlight_rounded" - HIGHLIGHT_OUTLINED = "highlight_outlined" - HIGHLIGHT_ALT = "highlight_alt" - HIGHLIGHT_ALT_SHARP = "highlight_alt_sharp" - HIGHLIGHT_ALT_ROUNDED = "highlight_alt_rounded" - HIGHLIGHT_ALT_OUTLINED = "highlight_alt_outlined" - HIGHLIGHT_OFF = "highlight_off" - HIGHLIGHT_OFF_SHARP = "highlight_off_sharp" - HIGHLIGHT_OFF_ROUNDED = "highlight_off_rounded" - HIGHLIGHT_OFF_OUTLINED = "highlight_off_outlined" - HIGHLIGHT_REMOVE = "highlight_remove" - HIGHLIGHT_REMOVE_SHARP = "highlight_remove_sharp" - HIGHLIGHT_REMOVE_ROUNDED = "highlight_remove_rounded" - HIGHLIGHT_REMOVE_OUTLINED = "highlight_remove_outlined" - HIKING = "hiking" - HIKING_SHARP = "hiking_sharp" - HIKING_ROUNDED = "hiking_rounded" - HIKING_OUTLINED = "hiking_outlined" - HISTORY = "history" - HISTORY_SHARP = "history_sharp" - HISTORY_ROUNDED = "history_rounded" - HISTORY_OUTLINED = "history_outlined" - HISTORY_EDU = "history_edu" - HISTORY_EDU_SHARP = "history_edu_sharp" - HISTORY_EDU_ROUNDED = "history_edu_rounded" - HISTORY_EDU_OUTLINED = "history_edu_outlined" - HISTORY_TOGGLE_OFF = "history_toggle_off" - HISTORY_TOGGLE_OFF_SHARP = "history_toggle_off_sharp" - HISTORY_TOGGLE_OFF_ROUNDED = "history_toggle_off_rounded" - HISTORY_TOGGLE_OFF_OUTLINED = "history_toggle_off_outlined" - HIVE = "hive" - HIVE_SHARP = "hive_sharp" - HIVE_ROUNDED = "hive_rounded" - HIVE_OUTLINED = "hive_outlined" - HLS = "hls" - HLS_SHARP = "hls_sharp" - HLS_ROUNDED = "hls_rounded" - HLS_OUTLINED = "hls_outlined" - HLS_OFF = "hls_off" - HLS_OFF_SHARP = "hls_off_sharp" - HLS_OFF_ROUNDED = "hls_off_rounded" - HLS_OFF_OUTLINED = "hls_off_outlined" - HOLIDAY_VILLAGE = "holiday_village" - HOLIDAY_VILLAGE_SHARP = "holiday_village_sharp" - HOLIDAY_VILLAGE_ROUNDED = "holiday_village_rounded" - HOLIDAY_VILLAGE_OUTLINED = "holiday_village_outlined" - HOME = "home" - HOME_SHARP = "home_sharp" - HOME_ROUNDED = "home_rounded" - HOME_OUTLINED = "home_outlined" - HOME_FILLED = "home_filled" - HOME_MAX = "home_max" - HOME_MAX_SHARP = "home_max_sharp" - HOME_MAX_ROUNDED = "home_max_rounded" - HOME_MAX_OUTLINED = "home_max_outlined" - HOME_MINI = "home_mini" - HOME_MINI_SHARP = "home_mini_sharp" - HOME_MINI_ROUNDED = "home_mini_rounded" - HOME_MINI_OUTLINED = "home_mini_outlined" - HOME_REPAIR_SERVICE = "home_repair_service" - HOME_REPAIR_SERVICE_SHARP = "home_repair_service_sharp" - HOME_REPAIR_SERVICE_ROUNDED = "home_repair_service_rounded" - HOME_REPAIR_SERVICE_OUTLINED = "home_repair_service_outlined" - HOME_WORK = "home_work" - HOME_WORK_SHARP = "home_work_sharp" - HOME_WORK_ROUNDED = "home_work_rounded" - HOME_WORK_OUTLINED = "home_work_outlined" - HORIZONTAL_DISTRIBUTE = "horizontal_distribute" - HORIZONTAL_DISTRIBUTE_SHARP = "horizontal_distribute_sharp" - HORIZONTAL_DISTRIBUTE_ROUNDED = "horizontal_distribute_rounded" - HORIZONTAL_DISTRIBUTE_OUTLINED = "horizontal_distribute_outlined" - HORIZONTAL_RULE = "horizontal_rule" - HORIZONTAL_RULE_SHARP = "horizontal_rule_sharp" - HORIZONTAL_RULE_ROUNDED = "horizontal_rule_rounded" - HORIZONTAL_RULE_OUTLINED = "horizontal_rule_outlined" - HORIZONTAL_SPLIT = "horizontal_split" - HORIZONTAL_SPLIT_SHARP = "horizontal_split_sharp" - HORIZONTAL_SPLIT_ROUNDED = "horizontal_split_rounded" - HORIZONTAL_SPLIT_OUTLINED = "horizontal_split_outlined" - HOT_TUB = "hot_tub" - HOT_TUB_SHARP = "hot_tub_sharp" - HOT_TUB_ROUNDED = "hot_tub_rounded" - HOT_TUB_OUTLINED = "hot_tub_outlined" - HOTEL = "hotel" - HOTEL_SHARP = "hotel_sharp" - HOTEL_ROUNDED = "hotel_rounded" - HOTEL_OUTLINED = "hotel_outlined" - HOTEL_CLASS = "hotel_class" - HOTEL_CLASS_SHARP = "hotel_class_sharp" - HOTEL_CLASS_ROUNDED = "hotel_class_rounded" - HOTEL_CLASS_OUTLINED = "hotel_class_outlined" - HOURGLASS_BOTTOM = "hourglass_bottom" - HOURGLASS_BOTTOM_SHARP = "hourglass_bottom_sharp" - HOURGLASS_BOTTOM_ROUNDED = "hourglass_bottom_rounded" - HOURGLASS_BOTTOM_OUTLINED = "hourglass_bottom_outlined" - HOURGLASS_DISABLED = "hourglass_disabled" - HOURGLASS_DISABLED_SHARP = "hourglass_disabled_sharp" - HOURGLASS_DISABLED_ROUNDED = "hourglass_disabled_rounded" - HOURGLASS_DISABLED_OUTLINED = "hourglass_disabled_outlined" - HOURGLASS_EMPTY = "hourglass_empty" - HOURGLASS_EMPTY_SHARP = "hourglass_empty_sharp" - HOURGLASS_EMPTY_ROUNDED = "hourglass_empty_rounded" - HOURGLASS_EMPTY_OUTLINED = "hourglass_empty_outlined" - HOURGLASS_FULL = "hourglass_full" - HOURGLASS_FULL_SHARP = "hourglass_full_sharp" - HOURGLASS_FULL_ROUNDED = "hourglass_full_rounded" - HOURGLASS_FULL_OUTLINED = "hourglass_full_outlined" - HOURGLASS_TOP = "hourglass_top" - HOURGLASS_TOP_SHARP = "hourglass_top_sharp" - HOURGLASS_TOP_ROUNDED = "hourglass_top_rounded" - HOURGLASS_TOP_OUTLINED = "hourglass_top_outlined" - HOUSE = "house" - HOUSE_SHARP = "house_sharp" - HOUSE_ROUNDED = "house_rounded" - HOUSE_OUTLINED = "house_outlined" - HOUSE_SIDING = "house_siding" - HOUSE_SIDING_SHARP = "house_siding_sharp" - HOUSE_SIDING_ROUNDED = "house_siding_rounded" - HOUSE_SIDING_OUTLINED = "house_siding_outlined" - HOUSEBOAT = "houseboat" - HOUSEBOAT_SHARP = "houseboat_sharp" - HOUSEBOAT_ROUNDED = "houseboat_rounded" - HOUSEBOAT_OUTLINED = "houseboat_outlined" - HOW_TO_REG = "how_to_reg" - HOW_TO_REG_SHARP = "how_to_reg_sharp" - HOW_TO_REG_ROUNDED = "how_to_reg_rounded" - HOW_TO_REG_OUTLINED = "how_to_reg_outlined" - HOW_TO_VOTE = "how_to_vote" - HOW_TO_VOTE_SHARP = "how_to_vote_sharp" - HOW_TO_VOTE_ROUNDED = "how_to_vote_rounded" - HOW_TO_VOTE_OUTLINED = "how_to_vote_outlined" - HTML = "html" - HTML_SHARP = "html_sharp" - HTML_ROUNDED = "html_rounded" - HTML_OUTLINED = "html_outlined" - HTTP = "http" - HTTP_SHARP = "http_sharp" - HTTP_ROUNDED = "http_rounded" - HTTP_OUTLINED = "http_outlined" - HTTPS = "https" - HTTPS_SHARP = "https_sharp" - HTTPS_ROUNDED = "https_rounded" - HTTPS_OUTLINED = "https_outlined" - HUB = "hub" - HUB_SHARP = "hub_sharp" - HUB_ROUNDED = "hub_rounded" - HUB_OUTLINED = "hub_outlined" - HVAC = "hvac" - HVAC_SHARP = "hvac_sharp" - HVAC_ROUNDED = "hvac_rounded" - HVAC_OUTLINED = "hvac_outlined" - ICE_SKATING = "ice_skating" - ICE_SKATING_SHARP = "ice_skating_sharp" - ICE_SKATING_ROUNDED = "ice_skating_rounded" - ICE_SKATING_OUTLINED = "ice_skating_outlined" - ICECREAM = "icecream" - ICECREAM_SHARP = "icecream_sharp" - ICECREAM_ROUNDED = "icecream_rounded" - ICECREAM_OUTLINED = "icecream_outlined" - IMAGE = "image" - IMAGE_SHARP = "image_sharp" - IMAGE_ROUNDED = "image_rounded" - IMAGE_OUTLINED = "image_outlined" - IMAGE_ASPECT_RATIO = "image_aspect_ratio" - IMAGE_ASPECT_RATIO_SHARP = "image_aspect_ratio_sharp" - IMAGE_ASPECT_RATIO_ROUNDED = "image_aspect_ratio_rounded" - IMAGE_ASPECT_RATIO_OUTLINED = "image_aspect_ratio_outlined" - IMAGE_NOT_SUPPORTED = "image_not_supported" - IMAGE_NOT_SUPPORTED_SHARP = "image_not_supported_sharp" - IMAGE_NOT_SUPPORTED_ROUNDED = "image_not_supported_rounded" - IMAGE_NOT_SUPPORTED_OUTLINED = "image_not_supported_outlined" - IMAGE_SEARCH = "image_search" - IMAGE_SEARCH_SHARP = "image_search_sharp" - IMAGE_SEARCH_ROUNDED = "image_search_rounded" - IMAGE_SEARCH_OUTLINED = "image_search_outlined" - IMAGESEARCH_ROLLER = "imagesearch_roller" - IMAGESEARCH_ROLLER_SHARP = "imagesearch_roller_sharp" - IMAGESEARCH_ROLLER_ROUNDED = "imagesearch_roller_rounded" - IMAGESEARCH_ROLLER_OUTLINED = "imagesearch_roller_outlined" - IMPORT_CONTACTS = "import_contacts" - IMPORT_CONTACTS_SHARP = "import_contacts_sharp" - IMPORT_CONTACTS_ROUNDED = "import_contacts_rounded" - IMPORT_CONTACTS_OUTLINED = "import_contacts_outlined" - IMPORT_EXPORT = "import_export" - IMPORT_EXPORT_SHARP = "import_export_sharp" - IMPORT_EXPORT_ROUNDED = "import_export_rounded" - IMPORT_EXPORT_OUTLINED = "import_export_outlined" - IMPORTANT_DEVICES = "important_devices" - IMPORTANT_DEVICES_SHARP = "important_devices_sharp" - IMPORTANT_DEVICES_ROUNDED = "important_devices_rounded" - IMPORTANT_DEVICES_OUTLINED = "important_devices_outlined" - INBOX = "inbox" - INBOX_SHARP = "inbox_sharp" - INBOX_ROUNDED = "inbox_rounded" - INBOX_OUTLINED = "inbox_outlined" - INCOMPLETE_CIRCLE = "incomplete_circle" - INCOMPLETE_CIRCLE_SHARP = "incomplete_circle_sharp" - INCOMPLETE_CIRCLE_ROUNDED = "incomplete_circle_rounded" - INCOMPLETE_CIRCLE_OUTLINED = "incomplete_circle_outlined" - INDETERMINATE_CHECK_BOX = "indeterminate_check_box" - INDETERMINATE_CHECK_BOX_SHARP = "indeterminate_check_box_sharp" - INDETERMINATE_CHECK_BOX_ROUNDED = "indeterminate_check_box_rounded" - INDETERMINATE_CHECK_BOX_OUTLINED = "indeterminate_check_box_outlined" - INFO = "info" - INFO_SHARP = "info_sharp" - INFO_ROUNDED = "info_rounded" - INFO_OUTLINED = "info_outlined" - INFO_OUTLINE = "info_outline" - INFO_OUTLINE_SHARP = "info_outline_sharp" - INFO_OUTLINE_ROUNDED = "info_outline_rounded" - INPUT = "input" - INPUT_SHARP = "input_sharp" - INPUT_ROUNDED = "input_rounded" - INPUT_OUTLINED = "input_outlined" - INSERT_CHART = "insert_chart" - INSERT_CHART_SHARP = "insert_chart_sharp" - INSERT_CHART_ROUNDED = "insert_chart_rounded" - INSERT_CHART_OUTLINED = "insert_chart_outlined" - INSERT_CHART_OUTLINED_SHARP = "insert_chart_outlined_sharp" - INSERT_CHART_OUTLINED_ROUNDED = "insert_chart_outlined_rounded" - INSERT_CHART_OUTLINED_OUTLINED = "insert_chart_outlined_outlined" - INSERT_COMMENT = "insert_comment" - INSERT_COMMENT_SHARP = "insert_comment_sharp" - INSERT_COMMENT_ROUNDED = "insert_comment_rounded" - INSERT_COMMENT_OUTLINED = "insert_comment_outlined" - INSERT_DRIVE_FILE = "insert_drive_file" - INSERT_DRIVE_FILE_SHARP = "insert_drive_file_sharp" - INSERT_DRIVE_FILE_ROUNDED = "insert_drive_file_rounded" - INSERT_DRIVE_FILE_OUTLINED = "insert_drive_file_outlined" - INSERT_EMOTICON = "insert_emoticon" - INSERT_EMOTICON_SHARP = "insert_emoticon_sharp" - INSERT_EMOTICON_ROUNDED = "insert_emoticon_rounded" - INSERT_EMOTICON_OUTLINED = "insert_emoticon_outlined" - INSERT_INVITATION = "insert_invitation" - INSERT_INVITATION_SHARP = "insert_invitation_sharp" - INSERT_INVITATION_ROUNDED = "insert_invitation_rounded" - INSERT_INVITATION_OUTLINED = "insert_invitation_outlined" - INSERT_LINK = "insert_link" - INSERT_LINK_SHARP = "insert_link_sharp" - INSERT_LINK_ROUNDED = "insert_link_rounded" - INSERT_LINK_OUTLINED = "insert_link_outlined" - INSERT_PAGE_BREAK = "insert_page_break" - INSERT_PAGE_BREAK_SHARP = "insert_page_break_sharp" - INSERT_PAGE_BREAK_ROUNDED = "insert_page_break_rounded" - INSERT_PAGE_BREAK_OUTLINED = "insert_page_break_outlined" - INSERT_PHOTO = "insert_photo" - INSERT_PHOTO_SHARP = "insert_photo_sharp" - INSERT_PHOTO_ROUNDED = "insert_photo_rounded" - INSERT_PHOTO_OUTLINED = "insert_photo_outlined" - INSIGHTS = "insights" - INSIGHTS_SHARP = "insights_sharp" - INSIGHTS_ROUNDED = "insights_rounded" - INSIGHTS_OUTLINED = "insights_outlined" - INSTALL_DESKTOP = "install_desktop" - INSTALL_DESKTOP_SHARP = "install_desktop_sharp" - INSTALL_DESKTOP_ROUNDED = "install_desktop_rounded" - INSTALL_DESKTOP_OUTLINED = "install_desktop_outlined" - INSTALL_MOBILE = "install_mobile" - INSTALL_MOBILE_SHARP = "install_mobile_sharp" - INSTALL_MOBILE_ROUNDED = "install_mobile_rounded" - INSTALL_MOBILE_OUTLINED = "install_mobile_outlined" - INTEGRATION_INSTRUCTIONS = "integration_instructions" - INTEGRATION_INSTRUCTIONS_SHARP = "integration_instructions_sharp" - INTEGRATION_INSTRUCTIONS_ROUNDED = "integration_instructions_rounded" - INTEGRATION_INSTRUCTIONS_OUTLINED = "integration_instructions_outlined" - INTERESTS = "interests" - INTERESTS_SHARP = "interests_sharp" - INTERESTS_ROUNDED = "interests_rounded" - INTERESTS_OUTLINED = "interests_outlined" - INTERPRETER_MODE = "interpreter_mode" - INTERPRETER_MODE_SHARP = "interpreter_mode_sharp" - INTERPRETER_MODE_ROUNDED = "interpreter_mode_rounded" - INTERPRETER_MODE_OUTLINED = "interpreter_mode_outlined" - INVENTORY = "inventory" - INVENTORY_SHARP = "inventory_sharp" - INVENTORY_ROUNDED = "inventory_rounded" - INVENTORY_OUTLINED = "inventory_outlined" - INVENTORY_2 = "inventory_2" - INVENTORY_2_SHARP = "inventory_2_sharp" - INVENTORY_2_ROUNDED = "inventory_2_rounded" - INVENTORY_2_OUTLINED = "inventory_2_outlined" - INVERT_COLORS = "invert_colors" - INVERT_COLORS_SHARP = "invert_colors_sharp" - INVERT_COLORS_ROUNDED = "invert_colors_rounded" - INVERT_COLORS_OUTLINED = "invert_colors_outlined" - INVERT_COLORS_OFF = "invert_colors_off" - INVERT_COLORS_OFF_SHARP = "invert_colors_off_sharp" - INVERT_COLORS_OFF_ROUNDED = "invert_colors_off_rounded" - INVERT_COLORS_OFF_OUTLINED = "invert_colors_off_outlined" - INVERT_COLORS_ON = "invert_colors_on" - INVERT_COLORS_ON_SHARP = "invert_colors_on_sharp" - INVERT_COLORS_ON_ROUNDED = "invert_colors_on_rounded" - INVERT_COLORS_ON_OUTLINED = "invert_colors_on_outlined" - IOS_SHARE = "ios_share" - IOS_SHARE_SHARP = "ios_share_sharp" - IOS_SHARE_ROUNDED = "ios_share_rounded" - IOS_SHARE_OUTLINED = "ios_share_outlined" - IRON = "iron" - IRON_SHARP = "iron_sharp" - IRON_ROUNDED = "iron_rounded" - IRON_OUTLINED = "iron_outlined" - ISO = "iso" - ISO_SHARP = "iso_sharp" - ISO_ROUNDED = "iso_rounded" - ISO_OUTLINED = "iso_outlined" - JAVASCRIPT = "javascript" - JAVASCRIPT_SHARP = "javascript_sharp" - JAVASCRIPT_ROUNDED = "javascript_rounded" - JAVASCRIPT_OUTLINED = "javascript_outlined" - JOIN_FULL = "join_full" - JOIN_FULL_SHARP = "join_full_sharp" - JOIN_FULL_ROUNDED = "join_full_rounded" - JOIN_FULL_OUTLINED = "join_full_outlined" - JOIN_INNER = "join_inner" - JOIN_INNER_SHARP = "join_inner_sharp" - JOIN_INNER_ROUNDED = "join_inner_rounded" - JOIN_INNER_OUTLINED = "join_inner_outlined" - JOIN_LEFT = "join_left" - JOIN_LEFT_SHARP = "join_left_sharp" - JOIN_LEFT_ROUNDED = "join_left_rounded" - JOIN_LEFT_OUTLINED = "join_left_outlined" - JOIN_RIGHT = "join_right" - JOIN_RIGHT_SHARP = "join_right_sharp" - JOIN_RIGHT_ROUNDED = "join_right_rounded" - JOIN_RIGHT_OUTLINED = "join_right_outlined" - KAYAKING = "kayaking" - KAYAKING_SHARP = "kayaking_sharp" - KAYAKING_ROUNDED = "kayaking_rounded" - KAYAKING_OUTLINED = "kayaking_outlined" - KEBAB_DINING = "kebab_dining" - KEBAB_DINING_SHARP = "kebab_dining_sharp" - KEBAB_DINING_ROUNDED = "kebab_dining_rounded" - KEBAB_DINING_OUTLINED = "kebab_dining_outlined" - KEY = "key" - KEY_SHARP = "key_sharp" - KEY_ROUNDED = "key_rounded" - KEY_OUTLINED = "key_outlined" - KEY_OFF = "key_off" - KEY_OFF_SHARP = "key_off_sharp" - KEY_OFF_ROUNDED = "key_off_rounded" - KEY_OFF_OUTLINED = "key_off_outlined" - KEYBOARD = "keyboard" - KEYBOARD_SHARP = "keyboard_sharp" - KEYBOARD_ROUNDED = "keyboard_rounded" - KEYBOARD_OUTLINED = "keyboard_outlined" - KEYBOARD_ALT = "keyboard_alt" - KEYBOARD_ALT_SHARP = "keyboard_alt_sharp" - KEYBOARD_ALT_ROUNDED = "keyboard_alt_rounded" - KEYBOARD_ALT_OUTLINED = "keyboard_alt_outlined" - KEYBOARD_ARROW_DOWN = "keyboard_arrow_down" - KEYBOARD_ARROW_DOWN_SHARP = "keyboard_arrow_down_sharp" - KEYBOARD_ARROW_DOWN_ROUNDED = "keyboard_arrow_down_rounded" - KEYBOARD_ARROW_DOWN_OUTLINED = "keyboard_arrow_down_outlined" - KEYBOARD_ARROW_LEFT = "keyboard_arrow_left" - KEYBOARD_ARROW_LEFT_SHARP = "keyboard_arrow_left_sharp" - KEYBOARD_ARROW_LEFT_ROUNDED = "keyboard_arrow_left_rounded" - KEYBOARD_ARROW_LEFT_OUTLINED = "keyboard_arrow_left_outlined" - KEYBOARD_ARROW_RIGHT = "keyboard_arrow_right" - KEYBOARD_ARROW_RIGHT_SHARP = "keyboard_arrow_right_sharp" - KEYBOARD_ARROW_RIGHT_ROUNDED = "keyboard_arrow_right_rounded" - KEYBOARD_ARROW_RIGHT_OUTLINED = "keyboard_arrow_right_outlined" - KEYBOARD_ARROW_UP = "keyboard_arrow_up" - KEYBOARD_ARROW_UP_SHARP = "keyboard_arrow_up_sharp" - KEYBOARD_ARROW_UP_ROUNDED = "keyboard_arrow_up_rounded" - KEYBOARD_ARROW_UP_OUTLINED = "keyboard_arrow_up_outlined" - KEYBOARD_BACKSPACE = "keyboard_backspace" - KEYBOARD_BACKSPACE_SHARP = "keyboard_backspace_sharp" - KEYBOARD_BACKSPACE_ROUNDED = "keyboard_backspace_rounded" - KEYBOARD_BACKSPACE_OUTLINED = "keyboard_backspace_outlined" - KEYBOARD_CAPSLOCK = "keyboard_capslock" - KEYBOARD_CAPSLOCK_SHARP = "keyboard_capslock_sharp" - KEYBOARD_CAPSLOCK_ROUNDED = "keyboard_capslock_rounded" - KEYBOARD_CAPSLOCK_OUTLINED = "keyboard_capslock_outlined" - KEYBOARD_COMMAND_KEY = "keyboard_command_key" - KEYBOARD_COMMAND_KEY_SHARP = "keyboard_command_key_sharp" - KEYBOARD_COMMAND_KEY_ROUNDED = "keyboard_command_key_rounded" - KEYBOARD_COMMAND_KEY_OUTLINED = "keyboard_command_key_outlined" - KEYBOARD_CONTROL = "keyboard_control" - KEYBOARD_CONTROL_SHARP = "keyboard_control_sharp" - KEYBOARD_CONTROL_ROUNDED = "keyboard_control_rounded" - KEYBOARD_CONTROL_OUTLINED = "keyboard_control_outlined" - KEYBOARD_CONTROL_KEY = "keyboard_control_key" - KEYBOARD_CONTROL_KEY_SHARP = "keyboard_control_key_sharp" - KEYBOARD_CONTROL_KEY_ROUNDED = "keyboard_control_key_rounded" - KEYBOARD_CONTROL_KEY_OUTLINED = "keyboard_control_key_outlined" - KEYBOARD_DOUBLE_ARROW_DOWN = "keyboard_double_arrow_down" - KEYBOARD_DOUBLE_ARROW_DOWN_SHARP = "keyboard_double_arrow_down_sharp" - KEYBOARD_DOUBLE_ARROW_DOWN_ROUNDED = "keyboard_double_arrow_down_rounded" - KEYBOARD_DOUBLE_ARROW_DOWN_OUTLINED = "keyboard_double_arrow_down_outlined" - KEYBOARD_DOUBLE_ARROW_LEFT = "keyboard_double_arrow_left" - KEYBOARD_DOUBLE_ARROW_LEFT_SHARP = "keyboard_double_arrow_left_sharp" - KEYBOARD_DOUBLE_ARROW_LEFT_ROUNDED = "keyboard_double_arrow_left_rounded" - KEYBOARD_DOUBLE_ARROW_LEFT_OUTLINED = "keyboard_double_arrow_left_outlined" - KEYBOARD_DOUBLE_ARROW_RIGHT = "keyboard_double_arrow_right" - KEYBOARD_DOUBLE_ARROW_RIGHT_SHARP = "keyboard_double_arrow_right_sharp" - KEYBOARD_DOUBLE_ARROW_RIGHT_ROUNDED = "keyboard_double_arrow_right_rounded" - KEYBOARD_DOUBLE_ARROW_RIGHT_OUTLINED = "keyboard_double_arrow_right_outlined" - KEYBOARD_DOUBLE_ARROW_UP = "keyboard_double_arrow_up" - KEYBOARD_DOUBLE_ARROW_UP_SHARP = "keyboard_double_arrow_up_sharp" - KEYBOARD_DOUBLE_ARROW_UP_ROUNDED = "keyboard_double_arrow_up_rounded" - KEYBOARD_DOUBLE_ARROW_UP_OUTLINED = "keyboard_double_arrow_up_outlined" - KEYBOARD_HIDE = "keyboard_hide" - KEYBOARD_HIDE_SHARP = "keyboard_hide_sharp" - KEYBOARD_HIDE_ROUNDED = "keyboard_hide_rounded" - KEYBOARD_HIDE_OUTLINED = "keyboard_hide_outlined" - KEYBOARD_OPTION_KEY = "keyboard_option_key" - KEYBOARD_OPTION_KEY_SHARP = "keyboard_option_key_sharp" - KEYBOARD_OPTION_KEY_ROUNDED = "keyboard_option_key_rounded" - KEYBOARD_OPTION_KEY_OUTLINED = "keyboard_option_key_outlined" - KEYBOARD_RETURN = "keyboard_return" - KEYBOARD_RETURN_SHARP = "keyboard_return_sharp" - KEYBOARD_RETURN_ROUNDED = "keyboard_return_rounded" - KEYBOARD_RETURN_OUTLINED = "keyboard_return_outlined" - KEYBOARD_TAB = "keyboard_tab" - KEYBOARD_TAB_SHARP = "keyboard_tab_sharp" - KEYBOARD_TAB_ROUNDED = "keyboard_tab_rounded" - KEYBOARD_TAB_OUTLINED = "keyboard_tab_outlined" - KEYBOARD_VOICE = "keyboard_voice" - KEYBOARD_VOICE_SHARP = "keyboard_voice_sharp" - KEYBOARD_VOICE_ROUNDED = "keyboard_voice_rounded" - KEYBOARD_VOICE_OUTLINED = "keyboard_voice_outlined" - KING_BED = "king_bed" - KING_BED_SHARP = "king_bed_sharp" - KING_BED_ROUNDED = "king_bed_rounded" - KING_BED_OUTLINED = "king_bed_outlined" - KITCHEN = "kitchen" - KITCHEN_SHARP = "kitchen_sharp" - KITCHEN_ROUNDED = "kitchen_rounded" - KITCHEN_OUTLINED = "kitchen_outlined" - KITESURFING = "kitesurfing" - KITESURFING_SHARP = "kitesurfing_sharp" - KITESURFING_ROUNDED = "kitesurfing_rounded" - KITESURFING_OUTLINED = "kitesurfing_outlined" - LABEL = "label" - LABEL_SHARP = "label_sharp" - LABEL_ROUNDED = "label_rounded" - LABEL_OUTLINED = "label_outlined" - LABEL_IMPORTANT = "label_important" - LABEL_IMPORTANT_SHARP = "label_important_sharp" - LABEL_IMPORTANT_ROUNDED = "label_important_rounded" - LABEL_IMPORTANT_OUTLINED = "label_important_outlined" - LABEL_IMPORTANT_OUTLINE = "label_important_outline" - LABEL_IMPORTANT_OUTLINE_SHARP = "label_important_outline_sharp" - LABEL_IMPORTANT_OUTLINE_ROUNDED = "label_important_outline_rounded" - LABEL_OFF = "label_off" - LABEL_OFF_SHARP = "label_off_sharp" - LABEL_OFF_ROUNDED = "label_off_rounded" - LABEL_OFF_OUTLINED = "label_off_outlined" - LABEL_OUTLINE = "label_outline" - LABEL_OUTLINE_SHARP = "label_outline_sharp" - LABEL_OUTLINE_ROUNDED = "label_outline_rounded" - LAN = "lan" - LAN_SHARP = "lan_sharp" - LAN_ROUNDED = "lan_rounded" - LAN_OUTLINED = "lan_outlined" - LANDSCAPE = "landscape" - LANDSCAPE_SHARP = "landscape_sharp" - LANDSCAPE_ROUNDED = "landscape_rounded" - LANDSCAPE_OUTLINED = "landscape_outlined" - LANDSLIDE = "landslide" - LANDSLIDE_SHARP = "landslide_sharp" - LANDSLIDE_ROUNDED = "landslide_rounded" - LANDSLIDE_OUTLINED = "landslide_outlined" - LANGUAGE = "language" - LANGUAGE_SHARP = "language_sharp" - LANGUAGE_ROUNDED = "language_rounded" - LANGUAGE_OUTLINED = "language_outlined" - LAPTOP = "laptop" - LAPTOP_SHARP = "laptop_sharp" - LAPTOP_ROUNDED = "laptop_rounded" - LAPTOP_OUTLINED = "laptop_outlined" - LAPTOP_CHROMEBOOK = "laptop_chromebook" - LAPTOP_CHROMEBOOK_SHARP = "laptop_chromebook_sharp" - LAPTOP_CHROMEBOOK_ROUNDED = "laptop_chromebook_rounded" - LAPTOP_CHROMEBOOK_OUTLINED = "laptop_chromebook_outlined" - LAPTOP_MAC = "laptop_mac" - LAPTOP_MAC_SHARP = "laptop_mac_sharp" - LAPTOP_MAC_ROUNDED = "laptop_mac_rounded" - LAPTOP_MAC_OUTLINED = "laptop_mac_outlined" - LAPTOP_WINDOWS = "laptop_windows" - LAPTOP_WINDOWS_SHARP = "laptop_windows_sharp" - LAPTOP_WINDOWS_ROUNDED = "laptop_windows_rounded" - LAPTOP_WINDOWS_OUTLINED = "laptop_windows_outlined" - LAST_PAGE = "last_page" - LAST_PAGE_SHARP = "last_page_sharp" - LAST_PAGE_ROUNDED = "last_page_rounded" - LAST_PAGE_OUTLINED = "last_page_outlined" - LAUNCH = "launch" - LAUNCH_SHARP = "launch_sharp" - LAUNCH_ROUNDED = "launch_rounded" - LAUNCH_OUTLINED = "launch_outlined" - LAYERS = "layers" - LAYERS_SHARP = "layers_sharp" - LAYERS_ROUNDED = "layers_rounded" - LAYERS_OUTLINED = "layers_outlined" - LAYERS_CLEAR = "layers_clear" - LAYERS_CLEAR_SHARP = "layers_clear_sharp" - LAYERS_CLEAR_ROUNDED = "layers_clear_rounded" - LAYERS_CLEAR_OUTLINED = "layers_clear_outlined" - LEADERBOARD = "leaderboard" - LEADERBOARD_SHARP = "leaderboard_sharp" - LEADERBOARD_ROUNDED = "leaderboard_rounded" - LEADERBOARD_OUTLINED = "leaderboard_outlined" - LEAK_ADD = "leak_add" - LEAK_ADD_SHARP = "leak_add_sharp" - LEAK_ADD_ROUNDED = "leak_add_rounded" - LEAK_ADD_OUTLINED = "leak_add_outlined" - LEAK_REMOVE = "leak_remove" - LEAK_REMOVE_SHARP = "leak_remove_sharp" - LEAK_REMOVE_ROUNDED = "leak_remove_rounded" - LEAK_REMOVE_OUTLINED = "leak_remove_outlined" - LEAVE_BAGS_AT_HOME = "leave_bags_at_home" - LEAVE_BAGS_AT_HOME_SHARP = "leave_bags_at_home_sharp" - LEAVE_BAGS_AT_HOME_ROUNDED = "leave_bags_at_home_rounded" - LEAVE_BAGS_AT_HOME_OUTLINED = "leave_bags_at_home_outlined" - LEGEND_TOGGLE = "legend_toggle" - LEGEND_TOGGLE_SHARP = "legend_toggle_sharp" - LEGEND_TOGGLE_ROUNDED = "legend_toggle_rounded" - LEGEND_TOGGLE_OUTLINED = "legend_toggle_outlined" - LENS = "lens" - LENS_SHARP = "lens_sharp" - LENS_ROUNDED = "lens_rounded" - LENS_OUTLINED = "lens_outlined" - LENS_BLUR = "lens_blur" - LENS_BLUR_SHARP = "lens_blur_sharp" - LENS_BLUR_ROUNDED = "lens_blur_rounded" - LENS_BLUR_OUTLINED = "lens_blur_outlined" - LIBRARY_ADD = "library_add" - LIBRARY_ADD_SHARP = "library_add_sharp" - LIBRARY_ADD_ROUNDED = "library_add_rounded" - LIBRARY_ADD_OUTLINED = "library_add_outlined" - LIBRARY_ADD_CHECK = "library_add_check" - LIBRARY_ADD_CHECK_SHARP = "library_add_check_sharp" - LIBRARY_ADD_CHECK_ROUNDED = "library_add_check_rounded" - LIBRARY_ADD_CHECK_OUTLINED = "library_add_check_outlined" - LIBRARY_BOOKS = "library_books" - LIBRARY_BOOKS_SHARP = "library_books_sharp" - LIBRARY_BOOKS_ROUNDED = "library_books_rounded" - LIBRARY_BOOKS_OUTLINED = "library_books_outlined" - LIBRARY_MUSIC = "library_music" - LIBRARY_MUSIC_SHARP = "library_music_sharp" - LIBRARY_MUSIC_ROUNDED = "library_music_rounded" - LIBRARY_MUSIC_OUTLINED = "library_music_outlined" - LIGHT = "light" - LIGHT_SHARP = "light_sharp" - LIGHT_ROUNDED = "light_rounded" - LIGHT_OUTLINED = "light_outlined" - LIGHT_MODE = "light_mode" - LIGHT_MODE_SHARP = "light_mode_sharp" - LIGHT_MODE_ROUNDED = "light_mode_rounded" - LIGHT_MODE_OUTLINED = "light_mode_outlined" - LIGHTBULB = "lightbulb" - LIGHTBULB_SHARP = "lightbulb_sharp" - LIGHTBULB_ROUNDED = "lightbulb_rounded" - LIGHTBULB_OUTLINED = "lightbulb_outlined" - LIGHTBULB_CIRCLE = "lightbulb_circle" - LIGHTBULB_CIRCLE_SHARP = "lightbulb_circle_sharp" - LIGHTBULB_CIRCLE_ROUNDED = "lightbulb_circle_rounded" - LIGHTBULB_CIRCLE_OUTLINED = "lightbulb_circle_outlined" - LIGHTBULB_OUTLINE = "lightbulb_outline" - LIGHTBULB_OUTLINE_SHARP = "lightbulb_outline_sharp" - LIGHTBULB_OUTLINE_ROUNDED = "lightbulb_outline_rounded" - LINE_AXIS = "line_axis" - LINE_AXIS_SHARP = "line_axis_sharp" - LINE_AXIS_ROUNDED = "line_axis_rounded" - LINE_AXIS_OUTLINED = "line_axis_outlined" - LINE_STYLE = "line_style" - LINE_STYLE_SHARP = "line_style_sharp" - LINE_STYLE_ROUNDED = "line_style_rounded" - LINE_STYLE_OUTLINED = "line_style_outlined" - LINE_WEIGHT = "line_weight" - LINE_WEIGHT_SHARP = "line_weight_sharp" - LINE_WEIGHT_ROUNDED = "line_weight_rounded" - LINE_WEIGHT_OUTLINED = "line_weight_outlined" - LINEAR_SCALE = "linear_scale" - LINEAR_SCALE_SHARP = "linear_scale_sharp" - LINEAR_SCALE_ROUNDED = "linear_scale_rounded" - LINEAR_SCALE_OUTLINED = "linear_scale_outlined" - LINK = "link" - LINK_SHARP = "link_sharp" - LINK_ROUNDED = "link_rounded" - LINK_OUTLINED = "link_outlined" - LINK_OFF = "link_off" - LINK_OFF_SHARP = "link_off_sharp" - LINK_OFF_ROUNDED = "link_off_rounded" - LINK_OFF_OUTLINED = "link_off_outlined" - LINKED_CAMERA = "linked_camera" - LINKED_CAMERA_SHARP = "linked_camera_sharp" - LINKED_CAMERA_ROUNDED = "linked_camera_rounded" - LINKED_CAMERA_OUTLINED = "linked_camera_outlined" - LIQUOR = "liquor" - LIQUOR_SHARP = "liquor_sharp" - LIQUOR_ROUNDED = "liquor_rounded" - LIQUOR_OUTLINED = "liquor_outlined" - LIST = "list" - LIST_SHARP = "list_sharp" - LIST_ROUNDED = "list_rounded" - LIST_OUTLINED = "list_outlined" - LIST_ALT = "list_alt" - LIST_ALT_SHARP = "list_alt_sharp" - LIST_ALT_ROUNDED = "list_alt_rounded" - LIST_ALT_OUTLINED = "list_alt_outlined" - LIVE_HELP = "live_help" - LIVE_HELP_SHARP = "live_help_sharp" - LIVE_HELP_ROUNDED = "live_help_rounded" - LIVE_HELP_OUTLINED = "live_help_outlined" - LIVE_TV = "live_tv" - LIVE_TV_SHARP = "live_tv_sharp" - LIVE_TV_ROUNDED = "live_tv_rounded" - LIVE_TV_OUTLINED = "live_tv_outlined" - LIVING = "living" - LIVING_SHARP = "living_sharp" - LIVING_ROUNDED = "living_rounded" - LIVING_OUTLINED = "living_outlined" - LOCAL_ACTIVITY = "local_activity" - LOCAL_ACTIVITY_SHARP = "local_activity_sharp" - LOCAL_ACTIVITY_ROUNDED = "local_activity_rounded" - LOCAL_ACTIVITY_OUTLINED = "local_activity_outlined" - LOCAL_AIRPORT = "local_airport" - LOCAL_AIRPORT_SHARP = "local_airport_sharp" - LOCAL_AIRPORT_ROUNDED = "local_airport_rounded" - LOCAL_AIRPORT_OUTLINED = "local_airport_outlined" - LOCAL_ATM = "local_atm" - LOCAL_ATM_SHARP = "local_atm_sharp" - LOCAL_ATM_ROUNDED = "local_atm_rounded" - LOCAL_ATM_OUTLINED = "local_atm_outlined" - LOCAL_ATTRACTION = "local_attraction" - LOCAL_ATTRACTION_SHARP = "local_attraction_sharp" - LOCAL_ATTRACTION_ROUNDED = "local_attraction_rounded" - LOCAL_ATTRACTION_OUTLINED = "local_attraction_outlined" - LOCAL_BAR = "local_bar" - LOCAL_BAR_SHARP = "local_bar_sharp" - LOCAL_BAR_ROUNDED = "local_bar_rounded" - LOCAL_BAR_OUTLINED = "local_bar_outlined" - LOCAL_CAFE = "local_cafe" - LOCAL_CAFE_SHARP = "local_cafe_sharp" - LOCAL_CAFE_ROUNDED = "local_cafe_rounded" - LOCAL_CAFE_OUTLINED = "local_cafe_outlined" - LOCAL_CAR_WASH = "local_car_wash" - LOCAL_CAR_WASH_SHARP = "local_car_wash_sharp" - LOCAL_CAR_WASH_ROUNDED = "local_car_wash_rounded" - LOCAL_CAR_WASH_OUTLINED = "local_car_wash_outlined" - LOCAL_CONVENIENCE_STORE = "local_convenience_store" - LOCAL_CONVENIENCE_STORE_SHARP = "local_convenience_store_sharp" - LOCAL_CONVENIENCE_STORE_ROUNDED = "local_convenience_store_rounded" - LOCAL_CONVENIENCE_STORE_OUTLINED = "local_convenience_store_outlined" - LOCAL_DINING = "local_dining" - LOCAL_DINING_SHARP = "local_dining_sharp" - LOCAL_DINING_ROUNDED = "local_dining_rounded" - LOCAL_DINING_OUTLINED = "local_dining_outlined" - LOCAL_DRINK = "local_drink" - LOCAL_DRINK_SHARP = "local_drink_sharp" - LOCAL_DRINK_ROUNDED = "local_drink_rounded" - LOCAL_DRINK_OUTLINED = "local_drink_outlined" - LOCAL_FIRE_DEPARTMENT = "local_fire_department" - LOCAL_FIRE_DEPARTMENT_SHARP = "local_fire_department_sharp" - LOCAL_FIRE_DEPARTMENT_ROUNDED = "local_fire_department_rounded" - LOCAL_FIRE_DEPARTMENT_OUTLINED = "local_fire_department_outlined" - LOCAL_FLORIST = "local_florist" - LOCAL_FLORIST_SHARP = "local_florist_sharp" - LOCAL_FLORIST_ROUNDED = "local_florist_rounded" - LOCAL_FLORIST_OUTLINED = "local_florist_outlined" - LOCAL_GAS_STATION = "local_gas_station" - LOCAL_GAS_STATION_SHARP = "local_gas_station_sharp" - LOCAL_GAS_STATION_ROUNDED = "local_gas_station_rounded" - LOCAL_GAS_STATION_OUTLINED = "local_gas_station_outlined" - LOCAL_GROCERY_STORE = "local_grocery_store" - LOCAL_GROCERY_STORE_SHARP = "local_grocery_store_sharp" - LOCAL_GROCERY_STORE_ROUNDED = "local_grocery_store_rounded" - LOCAL_GROCERY_STORE_OUTLINED = "local_grocery_store_outlined" - LOCAL_HOSPITAL = "local_hospital" - LOCAL_HOSPITAL_SHARP = "local_hospital_sharp" - LOCAL_HOSPITAL_ROUNDED = "local_hospital_rounded" - LOCAL_HOSPITAL_OUTLINED = "local_hospital_outlined" - LOCAL_HOTEL = "local_hotel" - LOCAL_HOTEL_SHARP = "local_hotel_sharp" - LOCAL_HOTEL_ROUNDED = "local_hotel_rounded" - LOCAL_HOTEL_OUTLINED = "local_hotel_outlined" - LOCAL_LAUNDRY_SERVICE = "local_laundry_service" - LOCAL_LAUNDRY_SERVICE_SHARP = "local_laundry_service_sharp" - LOCAL_LAUNDRY_SERVICE_ROUNDED = "local_laundry_service_rounded" - LOCAL_LAUNDRY_SERVICE_OUTLINED = "local_laundry_service_outlined" - LOCAL_LIBRARY = "local_library" - LOCAL_LIBRARY_SHARP = "local_library_sharp" - LOCAL_LIBRARY_ROUNDED = "local_library_rounded" - LOCAL_LIBRARY_OUTLINED = "local_library_outlined" - LOCAL_MALL = "local_mall" - LOCAL_MALL_SHARP = "local_mall_sharp" - LOCAL_MALL_ROUNDED = "local_mall_rounded" - LOCAL_MALL_OUTLINED = "local_mall_outlined" - LOCAL_MOVIES = "local_movies" - LOCAL_MOVIES_SHARP = "local_movies_sharp" - LOCAL_MOVIES_ROUNDED = "local_movies_rounded" - LOCAL_MOVIES_OUTLINED = "local_movies_outlined" - LOCAL_OFFER = "local_offer" - LOCAL_OFFER_SHARP = "local_offer_sharp" - LOCAL_OFFER_ROUNDED = "local_offer_rounded" - LOCAL_OFFER_OUTLINED = "local_offer_outlined" - LOCAL_PARKING = "local_parking" - LOCAL_PARKING_SHARP = "local_parking_sharp" - LOCAL_PARKING_ROUNDED = "local_parking_rounded" - LOCAL_PARKING_OUTLINED = "local_parking_outlined" - LOCAL_PHARMACY = "local_pharmacy" - LOCAL_PHARMACY_SHARP = "local_pharmacy_sharp" - LOCAL_PHARMACY_ROUNDED = "local_pharmacy_rounded" - LOCAL_PHARMACY_OUTLINED = "local_pharmacy_outlined" - LOCAL_PHONE = "local_phone" - LOCAL_PHONE_SHARP = "local_phone_sharp" - LOCAL_PHONE_ROUNDED = "local_phone_rounded" - LOCAL_PHONE_OUTLINED = "local_phone_outlined" - LOCAL_PIZZA = "local_pizza" - LOCAL_PIZZA_SHARP = "local_pizza_sharp" - LOCAL_PIZZA_ROUNDED = "local_pizza_rounded" - LOCAL_PIZZA_OUTLINED = "local_pizza_outlined" - LOCAL_PLAY = "local_play" - LOCAL_PLAY_SHARP = "local_play_sharp" - LOCAL_PLAY_ROUNDED = "local_play_rounded" - LOCAL_PLAY_OUTLINED = "local_play_outlined" - LOCAL_POLICE = "local_police" - LOCAL_POLICE_SHARP = "local_police_sharp" - LOCAL_POLICE_ROUNDED = "local_police_rounded" - LOCAL_POLICE_OUTLINED = "local_police_outlined" - LOCAL_POST_OFFICE = "local_post_office" - LOCAL_POST_OFFICE_SHARP = "local_post_office_sharp" - LOCAL_POST_OFFICE_ROUNDED = "local_post_office_rounded" - LOCAL_POST_OFFICE_OUTLINED = "local_post_office_outlined" - LOCAL_PRINT_SHOP = "local_print_shop" - LOCAL_PRINT_SHOP_SHARP = "local_print_shop_sharp" - LOCAL_PRINT_SHOP_ROUNDED = "local_print_shop_rounded" - LOCAL_PRINT_SHOP_OUTLINED = "local_print_shop_outlined" - LOCAL_PRINTSHOP = "local_printshop" - LOCAL_PRINTSHOP_SHARP = "local_printshop_sharp" - LOCAL_PRINTSHOP_ROUNDED = "local_printshop_rounded" - LOCAL_PRINTSHOP_OUTLINED = "local_printshop_outlined" - LOCAL_RESTAURANT = "local_restaurant" - LOCAL_RESTAURANT_SHARP = "local_restaurant_sharp" - LOCAL_RESTAURANT_ROUNDED = "local_restaurant_rounded" - LOCAL_RESTAURANT_OUTLINED = "local_restaurant_outlined" - LOCAL_SEE = "local_see" - LOCAL_SEE_SHARP = "local_see_sharp" - LOCAL_SEE_ROUNDED = "local_see_rounded" - LOCAL_SEE_OUTLINED = "local_see_outlined" - LOCAL_SHIPPING = "local_shipping" - LOCAL_SHIPPING_SHARP = "local_shipping_sharp" - LOCAL_SHIPPING_ROUNDED = "local_shipping_rounded" - LOCAL_SHIPPING_OUTLINED = "local_shipping_outlined" - LOCAL_TAXI = "local_taxi" - LOCAL_TAXI_SHARP = "local_taxi_sharp" - LOCAL_TAXI_ROUNDED = "local_taxi_rounded" - LOCAL_TAXI_OUTLINED = "local_taxi_outlined" - LOCATION_CITY = "location_city" - LOCATION_CITY_SHARP = "location_city_sharp" - LOCATION_CITY_ROUNDED = "location_city_rounded" - LOCATION_CITY_OUTLINED = "location_city_outlined" - LOCATION_DISABLED = "location_disabled" - LOCATION_DISABLED_SHARP = "location_disabled_sharp" - LOCATION_DISABLED_ROUNDED = "location_disabled_rounded" - LOCATION_DISABLED_OUTLINED = "location_disabled_outlined" - LOCATION_HISTORY = "location_history" - LOCATION_HISTORY_SHARP = "location_history_sharp" - LOCATION_HISTORY_ROUNDED = "location_history_rounded" - LOCATION_HISTORY_OUTLINED = "location_history_outlined" - LOCATION_OFF = "location_off" - LOCATION_OFF_SHARP = "location_off_sharp" - LOCATION_OFF_ROUNDED = "location_off_rounded" - LOCATION_OFF_OUTLINED = "location_off_outlined" - LOCATION_ON = "location_on" - LOCATION_ON_SHARP = "location_on_sharp" - LOCATION_ON_ROUNDED = "location_on_rounded" - LOCATION_ON_OUTLINED = "location_on_outlined" - LOCATION_PIN = "location_pin" - LOCATION_SEARCHING = "location_searching" - LOCATION_SEARCHING_SHARP = "location_searching_sharp" - LOCATION_SEARCHING_ROUNDED = "location_searching_rounded" - LOCATION_SEARCHING_OUTLINED = "location_searching_outlined" - LOCK = "lock" - LOCK_SHARP = "lock_sharp" - LOCK_ROUNDED = "lock_rounded" - LOCK_OUTLINED = "lock_outlined" - LOCK_CLOCK = "lock_clock" - LOCK_CLOCK_SHARP = "lock_clock_sharp" - LOCK_CLOCK_ROUNDED = "lock_clock_rounded" - LOCK_CLOCK_OUTLINED = "lock_clock_outlined" - LOCK_OPEN = "lock_open" - LOCK_OPEN_SHARP = "lock_open_sharp" - LOCK_OPEN_ROUNDED = "lock_open_rounded" - LOCK_OPEN_OUTLINED = "lock_open_outlined" - LOCK_OUTLINE = "lock_outline" - LOCK_OUTLINE_SHARP = "lock_outline_sharp" - LOCK_OUTLINE_ROUNDED = "lock_outline_rounded" - LOCK_PERSON = "lock_person" - LOCK_PERSON_SHARP = "lock_person_sharp" - LOCK_PERSON_ROUNDED = "lock_person_rounded" - LOCK_PERSON_OUTLINED = "lock_person_outlined" - LOCK_RESET = "lock_reset" - LOCK_RESET_SHARP = "lock_reset_sharp" - LOCK_RESET_ROUNDED = "lock_reset_rounded" - LOCK_RESET_OUTLINED = "lock_reset_outlined" - LOGIN = "login" - LOGIN_SHARP = "login_sharp" - LOGIN_ROUNDED = "login_rounded" - LOGIN_OUTLINED = "login_outlined" - LOGO_DEV = "logo_dev" - LOGO_DEV_SHARP = "logo_dev_sharp" - LOGO_DEV_ROUNDED = "logo_dev_rounded" - LOGO_DEV_OUTLINED = "logo_dev_outlined" - LOGOUT = "logout" - LOGOUT_SHARP = "logout_sharp" - LOGOUT_ROUNDED = "logout_rounded" - LOGOUT_OUTLINED = "logout_outlined" - LOOKS = "looks" - LOOKS_SHARP = "looks_sharp" - LOOKS_ROUNDED = "looks_rounded" - LOOKS_OUTLINED = "looks_outlined" - LOOKS_3 = "looks_3" - LOOKS_3_SHARP = "looks_3_sharp" - LOOKS_3_ROUNDED = "looks_3_rounded" - LOOKS_3_OUTLINED = "looks_3_outlined" - LOOKS_4 = "looks_4" - LOOKS_4_SHARP = "looks_4_sharp" - LOOKS_4_ROUNDED = "looks_4_rounded" - LOOKS_4_OUTLINED = "looks_4_outlined" - LOOKS_5 = "looks_5" - LOOKS_5_SHARP = "looks_5_sharp" - LOOKS_5_ROUNDED = "looks_5_rounded" - LOOKS_5_OUTLINED = "looks_5_outlined" - LOOKS_6 = "looks_6" - LOOKS_6_SHARP = "looks_6_sharp" - LOOKS_6_ROUNDED = "looks_6_rounded" - LOOKS_6_OUTLINED = "looks_6_outlined" - LOOKS_ONE = "looks_one" - LOOKS_ONE_SHARP = "looks_one_sharp" - LOOKS_ONE_ROUNDED = "looks_one_rounded" - LOOKS_ONE_OUTLINED = "looks_one_outlined" - LOOKS_TWO = "looks_two" - LOOKS_TWO_SHARP = "looks_two_sharp" - LOOKS_TWO_ROUNDED = "looks_two_rounded" - LOOKS_TWO_OUTLINED = "looks_two_outlined" - LOOP = "loop" - LOOP_SHARP = "loop_sharp" - LOOP_ROUNDED = "loop_rounded" - LOOP_OUTLINED = "loop_outlined" - LOUPE = "loupe" - LOUPE_SHARP = "loupe_sharp" - LOUPE_ROUNDED = "loupe_rounded" - LOUPE_OUTLINED = "loupe_outlined" - LOW_PRIORITY = "low_priority" - LOW_PRIORITY_SHARP = "low_priority_sharp" - LOW_PRIORITY_ROUNDED = "low_priority_rounded" - LOW_PRIORITY_OUTLINED = "low_priority_outlined" - LOYALTY = "loyalty" - LOYALTY_SHARP = "loyalty_sharp" - LOYALTY_ROUNDED = "loyalty_rounded" - LOYALTY_OUTLINED = "loyalty_outlined" - LTE_MOBILEDATA = "lte_mobiledata" - LTE_MOBILEDATA_SHARP = "lte_mobiledata_sharp" - LTE_MOBILEDATA_ROUNDED = "lte_mobiledata_rounded" - LTE_MOBILEDATA_OUTLINED = "lte_mobiledata_outlined" - LTE_PLUS_MOBILEDATA = "lte_plus_mobiledata" - LTE_PLUS_MOBILEDATA_SHARP = "lte_plus_mobiledata_sharp" - LTE_PLUS_MOBILEDATA_ROUNDED = "lte_plus_mobiledata_rounded" - LTE_PLUS_MOBILEDATA_OUTLINED = "lte_plus_mobiledata_outlined" - LUGGAGE = "luggage" - LUGGAGE_SHARP = "luggage_sharp" - LUGGAGE_ROUNDED = "luggage_rounded" - LUGGAGE_OUTLINED = "luggage_outlined" - LUNCH_DINING = "lunch_dining" - LUNCH_DINING_SHARP = "lunch_dining_sharp" - LUNCH_DINING_ROUNDED = "lunch_dining_rounded" - LUNCH_DINING_OUTLINED = "lunch_dining_outlined" - LYRICS = "lyrics" - LYRICS_SHARP = "lyrics_sharp" - LYRICS_ROUNDED = "lyrics_rounded" - LYRICS_OUTLINED = "lyrics_outlined" - MACRO_OFF = "macro_off" - MACRO_OFF_SHARP = "macro_off_sharp" - MACRO_OFF_ROUNDED = "macro_off_rounded" - MACRO_OFF_OUTLINED = "macro_off_outlined" - MAIL = "mail" - MAIL_SHARP = "mail_sharp" - MAIL_ROUNDED = "mail_rounded" - MAIL_OUTLINED = "mail_outlined" - MAIL_LOCK = "mail_lock" - MAIL_LOCK_SHARP = "mail_lock_sharp" - MAIL_LOCK_ROUNDED = "mail_lock_rounded" - MAIL_LOCK_OUTLINED = "mail_lock_outlined" - MAIL_OUTLINE = "mail_outline" - MAIL_OUTLINE_SHARP = "mail_outline_sharp" - MAIL_OUTLINE_ROUNDED = "mail_outline_rounded" - MAIL_OUTLINE_OUTLINED = "mail_outline_outlined" - MALE = "male" - MALE_SHARP = "male_sharp" - MALE_ROUNDED = "male_rounded" - MALE_OUTLINED = "male_outlined" - MAN = "man" - MAN_SHARP = "man_sharp" - MAN_ROUNDED = "man_rounded" - MAN_OUTLINED = "man_outlined" - MAN_2 = "man_2" - MAN_2_SHARP = "man_2_sharp" - MAN_2_ROUNDED = "man_2_rounded" - MAN_2_OUTLINED = "man_2_outlined" - MAN_3 = "man_3" - MAN_3_SHARP = "man_3_sharp" - MAN_3_ROUNDED = "man_3_rounded" - MAN_3_OUTLINED = "man_3_outlined" - MAN_4 = "man_4" - MAN_4_SHARP = "man_4_sharp" - MAN_4_ROUNDED = "man_4_rounded" - MAN_4_OUTLINED = "man_4_outlined" - MANAGE_ACCOUNTS = "manage_accounts" - MANAGE_ACCOUNTS_SHARP = "manage_accounts_sharp" - MANAGE_ACCOUNTS_ROUNDED = "manage_accounts_rounded" - MANAGE_ACCOUNTS_OUTLINED = "manage_accounts_outlined" - MANAGE_HISTORY = "manage_history" - MANAGE_HISTORY_SHARP = "manage_history_sharp" - MANAGE_HISTORY_ROUNDED = "manage_history_rounded" - MANAGE_HISTORY_OUTLINED = "manage_history_outlined" - MANAGE_SEARCH = "manage_search" - MANAGE_SEARCH_SHARP = "manage_search_sharp" - MANAGE_SEARCH_ROUNDED = "manage_search_rounded" - MANAGE_SEARCH_OUTLINED = "manage_search_outlined" - MAP = "map" - MAP_SHARP = "map_sharp" - MAP_ROUNDED = "map_rounded" - MAP_OUTLINED = "map_outlined" - MAPS_HOME_WORK = "maps_home_work" - MAPS_HOME_WORK_SHARP = "maps_home_work_sharp" - MAPS_HOME_WORK_ROUNDED = "maps_home_work_rounded" - MAPS_HOME_WORK_OUTLINED = "maps_home_work_outlined" - MAPS_UGC = "maps_ugc" - MAPS_UGC_SHARP = "maps_ugc_sharp" - MAPS_UGC_ROUNDED = "maps_ugc_rounded" - MAPS_UGC_OUTLINED = "maps_ugc_outlined" - MARGIN = "margin" - MARGIN_SHARP = "margin_sharp" - MARGIN_ROUNDED = "margin_rounded" - MARGIN_OUTLINED = "margin_outlined" - MARK_AS_UNREAD = "mark_as_unread" - MARK_AS_UNREAD_SHARP = "mark_as_unread_sharp" - MARK_AS_UNREAD_ROUNDED = "mark_as_unread_rounded" - MARK_AS_UNREAD_OUTLINED = "mark_as_unread_outlined" - MARK_CHAT_READ = "mark_chat_read" - MARK_CHAT_READ_SHARP = "mark_chat_read_sharp" - MARK_CHAT_READ_ROUNDED = "mark_chat_read_rounded" - MARK_CHAT_READ_OUTLINED = "mark_chat_read_outlined" - MARK_CHAT_UNREAD = "mark_chat_unread" - MARK_CHAT_UNREAD_SHARP = "mark_chat_unread_sharp" - MARK_CHAT_UNREAD_ROUNDED = "mark_chat_unread_rounded" - MARK_CHAT_UNREAD_OUTLINED = "mark_chat_unread_outlined" - MARK_EMAIL_READ = "mark_email_read" - MARK_EMAIL_READ_SHARP = "mark_email_read_sharp" - MARK_EMAIL_READ_ROUNDED = "mark_email_read_rounded" - MARK_EMAIL_READ_OUTLINED = "mark_email_read_outlined" - MARK_EMAIL_UNREAD = "mark_email_unread" - MARK_EMAIL_UNREAD_SHARP = "mark_email_unread_sharp" - MARK_EMAIL_UNREAD_ROUNDED = "mark_email_unread_rounded" - MARK_EMAIL_UNREAD_OUTLINED = "mark_email_unread_outlined" - MARK_UNREAD_CHAT_ALT = "mark_unread_chat_alt" - MARK_UNREAD_CHAT_ALT_SHARP = "mark_unread_chat_alt_sharp" - MARK_UNREAD_CHAT_ALT_ROUNDED = "mark_unread_chat_alt_rounded" - MARK_UNREAD_CHAT_ALT_OUTLINED = "mark_unread_chat_alt_outlined" - MARKUNREAD = "markunread" - MARKUNREAD_SHARP = "markunread_sharp" - MARKUNREAD_ROUNDED = "markunread_rounded" - MARKUNREAD_OUTLINED = "markunread_outlined" - MARKUNREAD_MAILBOX = "markunread_mailbox" - MARKUNREAD_MAILBOX_SHARP = "markunread_mailbox_sharp" - MARKUNREAD_MAILBOX_ROUNDED = "markunread_mailbox_rounded" - MARKUNREAD_MAILBOX_OUTLINED = "markunread_mailbox_outlined" - MASKS = "masks" - MASKS_SHARP = "masks_sharp" - MASKS_ROUNDED = "masks_rounded" - MASKS_OUTLINED = "masks_outlined" - MAXIMIZE = "maximize" - MAXIMIZE_SHARP = "maximize_sharp" - MAXIMIZE_ROUNDED = "maximize_rounded" - MAXIMIZE_OUTLINED = "maximize_outlined" - MEDIA_BLUETOOTH_OFF = "media_bluetooth_off" - MEDIA_BLUETOOTH_OFF_SHARP = "media_bluetooth_off_sharp" - MEDIA_BLUETOOTH_OFF_ROUNDED = "media_bluetooth_off_rounded" - MEDIA_BLUETOOTH_OFF_OUTLINED = "media_bluetooth_off_outlined" - MEDIA_BLUETOOTH_ON = "media_bluetooth_on" - MEDIA_BLUETOOTH_ON_SHARP = "media_bluetooth_on_sharp" - MEDIA_BLUETOOTH_ON_ROUNDED = "media_bluetooth_on_rounded" - MEDIA_BLUETOOTH_ON_OUTLINED = "media_bluetooth_on_outlined" - MEDIATION = "mediation" - MEDIATION_SHARP = "mediation_sharp" - MEDIATION_ROUNDED = "mediation_rounded" - MEDIATION_OUTLINED = "mediation_outlined" - MEDICAL_INFORMATION = "medical_information" - MEDICAL_INFORMATION_SHARP = "medical_information_sharp" - MEDICAL_INFORMATION_ROUNDED = "medical_information_rounded" - MEDICAL_INFORMATION_OUTLINED = "medical_information_outlined" - MEDICAL_SERVICES = "medical_services" - MEDICAL_SERVICES_SHARP = "medical_services_sharp" - MEDICAL_SERVICES_ROUNDED = "medical_services_rounded" - MEDICAL_SERVICES_OUTLINED = "medical_services_outlined" - MEDICATION = "medication" - MEDICATION_SHARP = "medication_sharp" - MEDICATION_ROUNDED = "medication_rounded" - MEDICATION_OUTLINED = "medication_outlined" - MEDICATION_LIQUID = "medication_liquid" - MEDICATION_LIQUID_SHARP = "medication_liquid_sharp" - MEDICATION_LIQUID_ROUNDED = "medication_liquid_rounded" - MEDICATION_LIQUID_OUTLINED = "medication_liquid_outlined" - MEETING_ROOM = "meeting_room" - MEETING_ROOM_SHARP = "meeting_room_sharp" - MEETING_ROOM_ROUNDED = "meeting_room_rounded" - MEETING_ROOM_OUTLINED = "meeting_room_outlined" - MEMORY = "memory" - MEMORY_SHARP = "memory_sharp" - MEMORY_ROUNDED = "memory_rounded" - MEMORY_OUTLINED = "memory_outlined" - MENU = "menu" - MENU_SHARP = "menu_sharp" - MENU_ROUNDED = "menu_rounded" - MENU_OUTLINED = "menu_outlined" - MENU_BOOK = "menu_book" - MENU_BOOK_SHARP = "menu_book_sharp" - MENU_BOOK_ROUNDED = "menu_book_rounded" - MENU_BOOK_OUTLINED = "menu_book_outlined" - MENU_OPEN = "menu_open" - MENU_OPEN_SHARP = "menu_open_sharp" - MENU_OPEN_ROUNDED = "menu_open_rounded" - MENU_OPEN_OUTLINED = "menu_open_outlined" - MERGE = "merge" - MERGE_SHARP = "merge_sharp" - MERGE_ROUNDED = "merge_rounded" - MERGE_OUTLINED = "merge_outlined" - MERGE_TYPE = "merge_type" - MERGE_TYPE_SHARP = "merge_type_sharp" - MERGE_TYPE_ROUNDED = "merge_type_rounded" - MERGE_TYPE_OUTLINED = "merge_type_outlined" - MESSAGE = "message" - MESSAGE_SHARP = "message_sharp" - MESSAGE_ROUNDED = "message_rounded" - MESSAGE_OUTLINED = "message_outlined" - MESSENGER = "messenger" - MESSENGER_SHARP = "messenger_sharp" - MESSENGER_ROUNDED = "messenger_rounded" - MESSENGER_OUTLINED = "messenger_outlined" - MESSENGER_OUTLINE = "messenger_outline" - MESSENGER_OUTLINE_SHARP = "messenger_outline_sharp" - MESSENGER_OUTLINE_ROUNDED = "messenger_outline_rounded" - MESSENGER_OUTLINE_OUTLINED = "messenger_outline_outlined" - MIC = "mic" - MIC_SHARP = "mic_sharp" - MIC_ROUNDED = "mic_rounded" - MIC_OUTLINED = "mic_outlined" - MIC_EXTERNAL_OFF = "mic_external_off" - MIC_EXTERNAL_OFF_SHARP = "mic_external_off_sharp" - MIC_EXTERNAL_OFF_ROUNDED = "mic_external_off_rounded" - MIC_EXTERNAL_OFF_OUTLINED = "mic_external_off_outlined" - MIC_EXTERNAL_ON = "mic_external_on" - MIC_EXTERNAL_ON_SHARP = "mic_external_on_sharp" - MIC_EXTERNAL_ON_ROUNDED = "mic_external_on_rounded" - MIC_EXTERNAL_ON_OUTLINED = "mic_external_on_outlined" - MIC_NONE = "mic_none" - MIC_NONE_SHARP = "mic_none_sharp" - MIC_NONE_ROUNDED = "mic_none_rounded" - MIC_NONE_OUTLINED = "mic_none_outlined" - MIC_OFF = "mic_off" - MIC_OFF_SHARP = "mic_off_sharp" - MIC_OFF_ROUNDED = "mic_off_rounded" - MIC_OFF_OUTLINED = "mic_off_outlined" - MICROWAVE = "microwave" - MICROWAVE_SHARP = "microwave_sharp" - MICROWAVE_ROUNDED = "microwave_rounded" - MICROWAVE_OUTLINED = "microwave_outlined" - MILITARY_TECH = "military_tech" - MILITARY_TECH_SHARP = "military_tech_sharp" - MILITARY_TECH_ROUNDED = "military_tech_rounded" - MILITARY_TECH_OUTLINED = "military_tech_outlined" - MINIMIZE = "minimize" - MINIMIZE_SHARP = "minimize_sharp" - MINIMIZE_ROUNDED = "minimize_rounded" - MINIMIZE_OUTLINED = "minimize_outlined" - MINOR_CRASH = "minor_crash" - MINOR_CRASH_SHARP = "minor_crash_sharp" - MINOR_CRASH_ROUNDED = "minor_crash_rounded" - MINOR_CRASH_OUTLINED = "minor_crash_outlined" - MISCELLANEOUS_SERVICES = "miscellaneous_services" - MISCELLANEOUS_SERVICES_SHARP = "miscellaneous_services_sharp" - MISCELLANEOUS_SERVICES_ROUNDED = "miscellaneous_services_rounded" - MISCELLANEOUS_SERVICES_OUTLINED = "miscellaneous_services_outlined" - MISSED_VIDEO_CALL = "missed_video_call" - MISSED_VIDEO_CALL_SHARP = "missed_video_call_sharp" - MISSED_VIDEO_CALL_ROUNDED = "missed_video_call_rounded" - MISSED_VIDEO_CALL_OUTLINED = "missed_video_call_outlined" - MMS = "mms" - MMS_SHARP = "mms_sharp" - MMS_ROUNDED = "mms_rounded" - MMS_OUTLINED = "mms_outlined" - MOBILE_FRIENDLY = "mobile_friendly" - MOBILE_FRIENDLY_SHARP = "mobile_friendly_sharp" - MOBILE_FRIENDLY_ROUNDED = "mobile_friendly_rounded" - MOBILE_FRIENDLY_OUTLINED = "mobile_friendly_outlined" - MOBILE_OFF = "mobile_off" - MOBILE_OFF_SHARP = "mobile_off_sharp" - MOBILE_OFF_ROUNDED = "mobile_off_rounded" - MOBILE_OFF_OUTLINED = "mobile_off_outlined" - MOBILE_SCREEN_SHARE = "mobile_screen_share" - MOBILE_SCREEN_SHARE_SHARP = "mobile_screen_share_sharp" - MOBILE_SCREEN_SHARE_ROUNDED = "mobile_screen_share_rounded" - MOBILE_SCREEN_SHARE_OUTLINED = "mobile_screen_share_outlined" - MOBILEDATA_OFF = "mobiledata_off" - MOBILEDATA_OFF_SHARP = "mobiledata_off_sharp" - MOBILEDATA_OFF_ROUNDED = "mobiledata_off_rounded" - MOBILEDATA_OFF_OUTLINED = "mobiledata_off_outlined" - MODE = "mode" - MODE_SHARP = "mode_sharp" - MODE_ROUNDED = "mode_rounded" - MODE_OUTLINED = "mode_outlined" - MODE_COMMENT = "mode_comment" - MODE_COMMENT_SHARP = "mode_comment_sharp" - MODE_COMMENT_ROUNDED = "mode_comment_rounded" - MODE_COMMENT_OUTLINED = "mode_comment_outlined" - MODE_EDIT = "mode_edit" - MODE_EDIT_SHARP = "mode_edit_sharp" - MODE_EDIT_ROUNDED = "mode_edit_rounded" - MODE_EDIT_OUTLINED = "mode_edit_outlined" - MODE_EDIT_OUTLINE = "mode_edit_outline" - MODE_EDIT_OUTLINE_SHARP = "mode_edit_outline_sharp" - MODE_EDIT_OUTLINE_ROUNDED = "mode_edit_outline_rounded" - MODE_EDIT_OUTLINE_OUTLINED = "mode_edit_outline_outlined" - MODE_FAN_OFF = "mode_fan_off" - MODE_FAN_OFF_SHARP = "mode_fan_off_sharp" - MODE_FAN_OFF_ROUNDED = "mode_fan_off_rounded" - MODE_FAN_OFF_OUTLINED = "mode_fan_off_outlined" - MODE_NIGHT = "mode_night" - MODE_NIGHT_SHARP = "mode_night_sharp" - MODE_NIGHT_ROUNDED = "mode_night_rounded" - MODE_NIGHT_OUTLINED = "mode_night_outlined" - MODE_OF_TRAVEL = "mode_of_travel" - MODE_OF_TRAVEL_SHARP = "mode_of_travel_sharp" - MODE_OF_TRAVEL_ROUNDED = "mode_of_travel_rounded" - MODE_OF_TRAVEL_OUTLINED = "mode_of_travel_outlined" - MODE_STANDBY = "mode_standby" - MODE_STANDBY_SHARP = "mode_standby_sharp" - MODE_STANDBY_ROUNDED = "mode_standby_rounded" - MODE_STANDBY_OUTLINED = "mode_standby_outlined" - MODEL_TRAINING = "model_training" - MODEL_TRAINING_SHARP = "model_training_sharp" - MODEL_TRAINING_ROUNDED = "model_training_rounded" - MODEL_TRAINING_OUTLINED = "model_training_outlined" - MONETIZATION_ON = "monetization_on" - MONETIZATION_ON_SHARP = "monetization_on_sharp" - MONETIZATION_ON_ROUNDED = "monetization_on_rounded" - MONETIZATION_ON_OUTLINED = "monetization_on_outlined" - MONEY = "money" - MONEY_SHARP = "money_sharp" - MONEY_ROUNDED = "money_rounded" - MONEY_OUTLINED = "money_outlined" - MONEY_OFF = "money_off" - MONEY_OFF_SHARP = "money_off_sharp" - MONEY_OFF_ROUNDED = "money_off_rounded" - MONEY_OFF_OUTLINED = "money_off_outlined" - MONEY_OFF_CSRED = "money_off_csred" - MONEY_OFF_CSRED_SHARP = "money_off_csred_sharp" - MONEY_OFF_CSRED_ROUNDED = "money_off_csred_rounded" - MONEY_OFF_CSRED_OUTLINED = "money_off_csred_outlined" - MONITOR = "monitor" - MONITOR_SHARP = "monitor_sharp" - MONITOR_ROUNDED = "monitor_rounded" - MONITOR_OUTLINED = "monitor_outlined" - MONITOR_HEART = "monitor_heart" - MONITOR_HEART_SHARP = "monitor_heart_sharp" - MONITOR_HEART_ROUNDED = "monitor_heart_rounded" - MONITOR_HEART_OUTLINED = "monitor_heart_outlined" - MONITOR_WEIGHT = "monitor_weight" - MONITOR_WEIGHT_SHARP = "monitor_weight_sharp" - MONITOR_WEIGHT_ROUNDED = "monitor_weight_rounded" - MONITOR_WEIGHT_OUTLINED = "monitor_weight_outlined" - MONOCHROME_PHOTOS = "monochrome_photos" - MONOCHROME_PHOTOS_SHARP = "monochrome_photos_sharp" - MONOCHROME_PHOTOS_ROUNDED = "monochrome_photos_rounded" - MONOCHROME_PHOTOS_OUTLINED = "monochrome_photos_outlined" - MOOD = "mood" - MOOD_SHARP = "mood_sharp" - MOOD_ROUNDED = "mood_rounded" - MOOD_OUTLINED = "mood_outlined" - MOOD_BAD = "mood_bad" - MOOD_BAD_SHARP = "mood_bad_sharp" - MOOD_BAD_ROUNDED = "mood_bad_rounded" - MOOD_BAD_OUTLINED = "mood_bad_outlined" - MOPED = "moped" - MOPED_SHARP = "moped_sharp" - MOPED_ROUNDED = "moped_rounded" - MOPED_OUTLINED = "moped_outlined" - MORE = "more" - MORE_SHARP = "more_sharp" - MORE_ROUNDED = "more_rounded" - MORE_OUTLINED = "more_outlined" - MORE_HORIZ = "more_horiz" - MORE_HORIZ_SHARP = "more_horiz_sharp" - MORE_HORIZ_ROUNDED = "more_horiz_rounded" - MORE_HORIZ_OUTLINED = "more_horiz_outlined" - MORE_TIME = "more_time" - MORE_TIME_SHARP = "more_time_sharp" - MORE_TIME_ROUNDED = "more_time_rounded" - MORE_TIME_OUTLINED = "more_time_outlined" - MORE_VERT = "more_vert" - MORE_VERT_SHARP = "more_vert_sharp" - MORE_VERT_ROUNDED = "more_vert_rounded" - MORE_VERT_OUTLINED = "more_vert_outlined" - MOSQUE = "mosque" - MOSQUE_SHARP = "mosque_sharp" - MOSQUE_ROUNDED = "mosque_rounded" - MOSQUE_OUTLINED = "mosque_outlined" - MOTION_PHOTOS_AUTO = "motion_photos_auto" - MOTION_PHOTOS_AUTO_SHARP = "motion_photos_auto_sharp" - MOTION_PHOTOS_AUTO_ROUNDED = "motion_photos_auto_rounded" - MOTION_PHOTOS_AUTO_OUTLINED = "motion_photos_auto_outlined" - MOTION_PHOTOS_OFF = "motion_photos_off" - MOTION_PHOTOS_OFF_SHARP = "motion_photos_off_sharp" - MOTION_PHOTOS_OFF_ROUNDED = "motion_photos_off_rounded" - MOTION_PHOTOS_OFF_OUTLINED = "motion_photos_off_outlined" - MOTION_PHOTOS_ON = "motion_photos_on" - MOTION_PHOTOS_ON_SHARP = "motion_photos_on_sharp" - MOTION_PHOTOS_ON_ROUNDED = "motion_photos_on_rounded" - MOTION_PHOTOS_ON_OUTLINED = "motion_photos_on_outlined" - MOTION_PHOTOS_PAUSE = "motion_photos_pause" - MOTION_PHOTOS_PAUSE_SHARP = "motion_photos_pause_sharp" - MOTION_PHOTOS_PAUSE_ROUNDED = "motion_photos_pause_rounded" - MOTION_PHOTOS_PAUSE_OUTLINED = "motion_photos_pause_outlined" - MOTION_PHOTOS_PAUSED = "motion_photos_paused" - MOTION_PHOTOS_PAUSED_SHARP = "motion_photos_paused_sharp" - MOTION_PHOTOS_PAUSED_ROUNDED = "motion_photos_paused_rounded" - MOTION_PHOTOS_PAUSED_OUTLINED = "motion_photos_paused_outlined" - MOTORCYCLE = "motorcycle" - MOTORCYCLE_SHARP = "motorcycle_sharp" - MOTORCYCLE_ROUNDED = "motorcycle_rounded" - MOTORCYCLE_OUTLINED = "motorcycle_outlined" - MOUSE = "mouse" - MOUSE_SHARP = "mouse_sharp" - MOUSE_ROUNDED = "mouse_rounded" - MOUSE_OUTLINED = "mouse_outlined" - MOVE_DOWN = "move_down" - MOVE_DOWN_SHARP = "move_down_sharp" - MOVE_DOWN_ROUNDED = "move_down_rounded" - MOVE_DOWN_OUTLINED = "move_down_outlined" - MOVE_TO_INBOX = "move_to_inbox" - MOVE_TO_INBOX_SHARP = "move_to_inbox_sharp" - MOVE_TO_INBOX_ROUNDED = "move_to_inbox_rounded" - MOVE_TO_INBOX_OUTLINED = "move_to_inbox_outlined" - MOVE_UP = "move_up" - MOVE_UP_SHARP = "move_up_sharp" - MOVE_UP_ROUNDED = "move_up_rounded" - MOVE_UP_OUTLINED = "move_up_outlined" - MOVIE = "movie" - MOVIE_SHARP = "movie_sharp" - MOVIE_ROUNDED = "movie_rounded" - MOVIE_OUTLINED = "movie_outlined" - MOVIE_CREATION = "movie_creation" - MOVIE_CREATION_SHARP = "movie_creation_sharp" - MOVIE_CREATION_ROUNDED = "movie_creation_rounded" - MOVIE_CREATION_OUTLINED = "movie_creation_outlined" - MOVIE_EDIT = "movie_edit" - MOVIE_FILTER = "movie_filter" - MOVIE_FILTER_SHARP = "movie_filter_sharp" - MOVIE_FILTER_ROUNDED = "movie_filter_rounded" - MOVIE_FILTER_OUTLINED = "movie_filter_outlined" - MOVING = "moving" - MOVING_SHARP = "moving_sharp" - MOVING_ROUNDED = "moving_rounded" - MOVING_OUTLINED = "moving_outlined" - MP = "mp" - MP_SHARP = "mp_sharp" - MP_ROUNDED = "mp_rounded" - MP_OUTLINED = "mp_outlined" - MULTILINE_CHART = "multiline_chart" - MULTILINE_CHART_SHARP = "multiline_chart_sharp" - MULTILINE_CHART_ROUNDED = "multiline_chart_rounded" - MULTILINE_CHART_OUTLINED = "multiline_chart_outlined" - MULTIPLE_STOP = "multiple_stop" - MULTIPLE_STOP_SHARP = "multiple_stop_sharp" - MULTIPLE_STOP_ROUNDED = "multiple_stop_rounded" - MULTIPLE_STOP_OUTLINED = "multiple_stop_outlined" - MULTITRACK_AUDIO = "multitrack_audio" - MULTITRACK_AUDIO_SHARP = "multitrack_audio_sharp" - MULTITRACK_AUDIO_ROUNDED = "multitrack_audio_rounded" - MULTITRACK_AUDIO_OUTLINED = "multitrack_audio_outlined" - MUSEUM = "museum" - MUSEUM_SHARP = "museum_sharp" - MUSEUM_ROUNDED = "museum_rounded" - MUSEUM_OUTLINED = "museum_outlined" - MUSIC_NOTE = "music_note" - MUSIC_NOTE_SHARP = "music_note_sharp" - MUSIC_NOTE_ROUNDED = "music_note_rounded" - MUSIC_NOTE_OUTLINED = "music_note_outlined" - MUSIC_OFF = "music_off" - MUSIC_OFF_SHARP = "music_off_sharp" - MUSIC_OFF_ROUNDED = "music_off_rounded" - MUSIC_OFF_OUTLINED = "music_off_outlined" - MUSIC_VIDEO = "music_video" - MUSIC_VIDEO_SHARP = "music_video_sharp" - MUSIC_VIDEO_ROUNDED = "music_video_rounded" - MUSIC_VIDEO_OUTLINED = "music_video_outlined" - MY_LIBRARY_ADD = "my_library_add" - MY_LIBRARY_ADD_SHARP = "my_library_add_sharp" - MY_LIBRARY_ADD_ROUNDED = "my_library_add_rounded" - MY_LIBRARY_ADD_OUTLINED = "my_library_add_outlined" - MY_LIBRARY_BOOKS = "my_library_books" - MY_LIBRARY_BOOKS_SHARP = "my_library_books_sharp" - MY_LIBRARY_BOOKS_ROUNDED = "my_library_books_rounded" - MY_LIBRARY_BOOKS_OUTLINED = "my_library_books_outlined" - MY_LIBRARY_MUSIC = "my_library_music" - MY_LIBRARY_MUSIC_SHARP = "my_library_music_sharp" - MY_LIBRARY_MUSIC_ROUNDED = "my_library_music_rounded" - MY_LIBRARY_MUSIC_OUTLINED = "my_library_music_outlined" - MY_LOCATION = "my_location" - MY_LOCATION_SHARP = "my_location_sharp" - MY_LOCATION_ROUNDED = "my_location_rounded" - MY_LOCATION_OUTLINED = "my_location_outlined" - NAT = "nat" - NAT_SHARP = "nat_sharp" - NAT_ROUNDED = "nat_rounded" - NAT_OUTLINED = "nat_outlined" - NATURE = "nature" - NATURE_SHARP = "nature_sharp" - NATURE_ROUNDED = "nature_rounded" - NATURE_OUTLINED = "nature_outlined" - NATURE_PEOPLE = "nature_people" - NATURE_PEOPLE_SHARP = "nature_people_sharp" - NATURE_PEOPLE_ROUNDED = "nature_people_rounded" - NATURE_PEOPLE_OUTLINED = "nature_people_outlined" - NAVIGATE_BEFORE = "navigate_before" - NAVIGATE_BEFORE_SHARP = "navigate_before_sharp" - NAVIGATE_BEFORE_ROUNDED = "navigate_before_rounded" - NAVIGATE_BEFORE_OUTLINED = "navigate_before_outlined" - NAVIGATE_NEXT = "navigate_next" - NAVIGATE_NEXT_SHARP = "navigate_next_sharp" - NAVIGATE_NEXT_ROUNDED = "navigate_next_rounded" - NAVIGATE_NEXT_OUTLINED = "navigate_next_outlined" - NAVIGATION = "navigation" - NAVIGATION_SHARP = "navigation_sharp" - NAVIGATION_ROUNDED = "navigation_rounded" - NAVIGATION_OUTLINED = "navigation_outlined" - NEAR_ME = "near_me" - NEAR_ME_SHARP = "near_me_sharp" - NEAR_ME_ROUNDED = "near_me_rounded" - NEAR_ME_OUTLINED = "near_me_outlined" - NEAR_ME_DISABLED = "near_me_disabled" - NEAR_ME_DISABLED_SHARP = "near_me_disabled_sharp" - NEAR_ME_DISABLED_ROUNDED = "near_me_disabled_rounded" - NEAR_ME_DISABLED_OUTLINED = "near_me_disabled_outlined" - NEARBY_ERROR = "nearby_error" - NEARBY_ERROR_SHARP = "nearby_error_sharp" - NEARBY_ERROR_ROUNDED = "nearby_error_rounded" - NEARBY_ERROR_OUTLINED = "nearby_error_outlined" - NEARBY_OFF = "nearby_off" - NEARBY_OFF_SHARP = "nearby_off_sharp" - NEARBY_OFF_ROUNDED = "nearby_off_rounded" - NEARBY_OFF_OUTLINED = "nearby_off_outlined" - NEST_CAM_WIRED_STAND = "nest_cam_wired_stand" - NEST_CAM_WIRED_STAND_SHARP = "nest_cam_wired_stand_sharp" - NEST_CAM_WIRED_STAND_ROUNDED = "nest_cam_wired_stand_rounded" - NEST_CAM_WIRED_STAND_OUTLINED = "nest_cam_wired_stand_outlined" - NETWORK_CELL = "network_cell" - NETWORK_CELL_SHARP = "network_cell_sharp" - NETWORK_CELL_ROUNDED = "network_cell_rounded" - NETWORK_CELL_OUTLINED = "network_cell_outlined" - NETWORK_CHECK = "network_check" - NETWORK_CHECK_SHARP = "network_check_sharp" - NETWORK_CHECK_ROUNDED = "network_check_rounded" - NETWORK_CHECK_OUTLINED = "network_check_outlined" - NETWORK_LOCKED = "network_locked" - NETWORK_LOCKED_SHARP = "network_locked_sharp" - NETWORK_LOCKED_ROUNDED = "network_locked_rounded" - NETWORK_LOCKED_OUTLINED = "network_locked_outlined" - NETWORK_PING = "network_ping" - NETWORK_PING_SHARP = "network_ping_sharp" - NETWORK_PING_ROUNDED = "network_ping_rounded" - NETWORK_PING_OUTLINED = "network_ping_outlined" - NETWORK_WIFI = "network_wifi" - NETWORK_WIFI_SHARP = "network_wifi_sharp" - NETWORK_WIFI_ROUNDED = "network_wifi_rounded" - NETWORK_WIFI_OUTLINED = "network_wifi_outlined" - NETWORK_WIFI_1_BAR = "network_wifi_1_bar" - NETWORK_WIFI_1_BAR_SHARP = "network_wifi_1_bar_sharp" - NETWORK_WIFI_1_BAR_ROUNDED = "network_wifi_1_bar_rounded" - NETWORK_WIFI_1_BAR_OUTLINED = "network_wifi_1_bar_outlined" - NETWORK_WIFI_2_BAR = "network_wifi_2_bar" - NETWORK_WIFI_2_BAR_SHARP = "network_wifi_2_bar_sharp" - NETWORK_WIFI_2_BAR_ROUNDED = "network_wifi_2_bar_rounded" - NETWORK_WIFI_2_BAR_OUTLINED = "network_wifi_2_bar_outlined" - NETWORK_WIFI_3_BAR = "network_wifi_3_bar" - NETWORK_WIFI_3_BAR_SHARP = "network_wifi_3_bar_sharp" - NETWORK_WIFI_3_BAR_ROUNDED = "network_wifi_3_bar_rounded" - NETWORK_WIFI_3_BAR_OUTLINED = "network_wifi_3_bar_outlined" - NEW_LABEL = "new_label" - NEW_LABEL_SHARP = "new_label_sharp" - NEW_LABEL_ROUNDED = "new_label_rounded" - NEW_LABEL_OUTLINED = "new_label_outlined" - NEW_RELEASES = "new_releases" - NEW_RELEASES_SHARP = "new_releases_sharp" - NEW_RELEASES_ROUNDED = "new_releases_rounded" - NEW_RELEASES_OUTLINED = "new_releases_outlined" - NEWSPAPER = "newspaper" - NEWSPAPER_SHARP = "newspaper_sharp" - NEWSPAPER_ROUNDED = "newspaper_rounded" - NEWSPAPER_OUTLINED = "newspaper_outlined" - NEXT_PLAN = "next_plan" - NEXT_PLAN_SHARP = "next_plan_sharp" - NEXT_PLAN_ROUNDED = "next_plan_rounded" - NEXT_PLAN_OUTLINED = "next_plan_outlined" - NEXT_WEEK = "next_week" - NEXT_WEEK_SHARP = "next_week_sharp" - NEXT_WEEK_ROUNDED = "next_week_rounded" - NEXT_WEEK_OUTLINED = "next_week_outlined" - NFC = "nfc" - NFC_SHARP = "nfc_sharp" - NFC_ROUNDED = "nfc_rounded" - NFC_OUTLINED = "nfc_outlined" - NIGHT_SHELTER = "night_shelter" - NIGHT_SHELTER_SHARP = "night_shelter_sharp" - NIGHT_SHELTER_ROUNDED = "night_shelter_rounded" - NIGHT_SHELTER_OUTLINED = "night_shelter_outlined" - NIGHTLIFE = "nightlife" - NIGHTLIFE_SHARP = "nightlife_sharp" - NIGHTLIFE_ROUNDED = "nightlife_rounded" - NIGHTLIFE_OUTLINED = "nightlife_outlined" - NIGHTLIGHT = "nightlight" - NIGHTLIGHT_SHARP = "nightlight_sharp" - NIGHTLIGHT_ROUNDED = "nightlight_rounded" - NIGHTLIGHT_OUTLINED = "nightlight_outlined" - NIGHTLIGHT_ROUND = "nightlight_round" - NIGHTLIGHT_ROUND_SHARP = "nightlight_round_sharp" - NIGHTLIGHT_ROUND_ROUNDED = "nightlight_round_rounded" - NIGHTLIGHT_ROUND_OUTLINED = "nightlight_round_outlined" - NIGHTS_STAY = "nights_stay" - NIGHTS_STAY_SHARP = "nights_stay_sharp" - NIGHTS_STAY_ROUNDED = "nights_stay_rounded" - NIGHTS_STAY_OUTLINED = "nights_stay_outlined" - NO_ACCOUNTS = "no_accounts" - NO_ACCOUNTS_SHARP = "no_accounts_sharp" - NO_ACCOUNTS_ROUNDED = "no_accounts_rounded" - NO_ACCOUNTS_OUTLINED = "no_accounts_outlined" - NO_ADULT_CONTENT = "no_adult_content" - NO_ADULT_CONTENT_SHARP = "no_adult_content_sharp" - NO_ADULT_CONTENT_ROUNDED = "no_adult_content_rounded" - NO_ADULT_CONTENT_OUTLINED = "no_adult_content_outlined" - NO_BACKPACK = "no_backpack" - NO_BACKPACK_SHARP = "no_backpack_sharp" - NO_BACKPACK_ROUNDED = "no_backpack_rounded" - NO_BACKPACK_OUTLINED = "no_backpack_outlined" - NO_CELL = "no_cell" - NO_CELL_SHARP = "no_cell_sharp" - NO_CELL_ROUNDED = "no_cell_rounded" - NO_CELL_OUTLINED = "no_cell_outlined" - NO_CRASH = "no_crash" - NO_CRASH_SHARP = "no_crash_sharp" - NO_CRASH_ROUNDED = "no_crash_rounded" - NO_CRASH_OUTLINED = "no_crash_outlined" - NO_DRINKS = "no_drinks" - NO_DRINKS_SHARP = "no_drinks_sharp" - NO_DRINKS_ROUNDED = "no_drinks_rounded" - NO_DRINKS_OUTLINED = "no_drinks_outlined" - NO_ENCRYPTION = "no_encryption" - NO_ENCRYPTION_SHARP = "no_encryption_sharp" - NO_ENCRYPTION_ROUNDED = "no_encryption_rounded" - NO_ENCRYPTION_OUTLINED = "no_encryption_outlined" - NO_ENCRYPTION_GMAILERRORRED = "no_encryption_gmailerrorred" - NO_ENCRYPTION_GMAILERRORRED_SHARP = "no_encryption_gmailerrorred_sharp" - NO_ENCRYPTION_GMAILERRORRED_ROUNDED = "no_encryption_gmailerrorred_rounded" - NO_ENCRYPTION_GMAILERRORRED_OUTLINED = "no_encryption_gmailerrorred_outlined" - NO_FLASH = "no_flash" - NO_FLASH_SHARP = "no_flash_sharp" - NO_FLASH_ROUNDED = "no_flash_rounded" - NO_FLASH_OUTLINED = "no_flash_outlined" - NO_FOOD = "no_food" - NO_FOOD_SHARP = "no_food_sharp" - NO_FOOD_ROUNDED = "no_food_rounded" - NO_FOOD_OUTLINED = "no_food_outlined" - NO_LUGGAGE = "no_luggage" - NO_LUGGAGE_SHARP = "no_luggage_sharp" - NO_LUGGAGE_ROUNDED = "no_luggage_rounded" - NO_LUGGAGE_OUTLINED = "no_luggage_outlined" - NO_MEALS = "no_meals" - NO_MEALS_SHARP = "no_meals_sharp" - NO_MEALS_ROUNDED = "no_meals_rounded" - NO_MEALS_OUTLINED = "no_meals_outlined" - NO_MEALS_OULINE = "no_meals_ouline" - NO_MEETING_ROOM = "no_meeting_room" - NO_MEETING_ROOM_SHARP = "no_meeting_room_sharp" - NO_MEETING_ROOM_ROUNDED = "no_meeting_room_rounded" - NO_MEETING_ROOM_OUTLINED = "no_meeting_room_outlined" - NO_PHOTOGRAPHY = "no_photography" - NO_PHOTOGRAPHY_SHARP = "no_photography_sharp" - NO_PHOTOGRAPHY_ROUNDED = "no_photography_rounded" - NO_PHOTOGRAPHY_OUTLINED = "no_photography_outlined" - NO_SIM = "no_sim" - NO_SIM_SHARP = "no_sim_sharp" - NO_SIM_ROUNDED = "no_sim_rounded" - NO_SIM_OUTLINED = "no_sim_outlined" - NO_STROLLER = "no_stroller" - NO_STROLLER_SHARP = "no_stroller_sharp" - NO_STROLLER_ROUNDED = "no_stroller_rounded" - NO_STROLLER_OUTLINED = "no_stroller_outlined" - NO_TRANSFER = "no_transfer" - NO_TRANSFER_SHARP = "no_transfer_sharp" - NO_TRANSFER_ROUNDED = "no_transfer_rounded" - NO_TRANSFER_OUTLINED = "no_transfer_outlined" - NOISE_AWARE = "noise_aware" - NOISE_AWARE_SHARP = "noise_aware_sharp" - NOISE_AWARE_ROUNDED = "noise_aware_rounded" - NOISE_AWARE_OUTLINED = "noise_aware_outlined" - NOISE_CONTROL_OFF = "noise_control_off" - NOISE_CONTROL_OFF_SHARP = "noise_control_off_sharp" - NOISE_CONTROL_OFF_ROUNDED = "noise_control_off_rounded" - NOISE_CONTROL_OFF_OUTLINED = "noise_control_off_outlined" - NORDIC_WALKING = "nordic_walking" - NORDIC_WALKING_SHARP = "nordic_walking_sharp" - NORDIC_WALKING_ROUNDED = "nordic_walking_rounded" - NORDIC_WALKING_OUTLINED = "nordic_walking_outlined" - NORTH = "north" - NORTH_SHARP = "north_sharp" - NORTH_ROUNDED = "north_rounded" - NORTH_OUTLINED = "north_outlined" - NORTH_EAST = "north_east" - NORTH_EAST_SHARP = "north_east_sharp" - NORTH_EAST_ROUNDED = "north_east_rounded" - NORTH_EAST_OUTLINED = "north_east_outlined" - NORTH_WEST = "north_west" - NORTH_WEST_SHARP = "north_west_sharp" - NORTH_WEST_ROUNDED = "north_west_rounded" - NORTH_WEST_OUTLINED = "north_west_outlined" - NOT_ACCESSIBLE = "not_accessible" - NOT_ACCESSIBLE_SHARP = "not_accessible_sharp" - NOT_ACCESSIBLE_ROUNDED = "not_accessible_rounded" - NOT_ACCESSIBLE_OUTLINED = "not_accessible_outlined" - NOT_INTERESTED = "not_interested" - NOT_INTERESTED_SHARP = "not_interested_sharp" - NOT_INTERESTED_ROUNDED = "not_interested_rounded" - NOT_INTERESTED_OUTLINED = "not_interested_outlined" - NOT_LISTED_LOCATION = "not_listed_location" - NOT_LISTED_LOCATION_SHARP = "not_listed_location_sharp" - NOT_LISTED_LOCATION_ROUNDED = "not_listed_location_rounded" - NOT_LISTED_LOCATION_OUTLINED = "not_listed_location_outlined" - NOT_STARTED = "not_started" - NOT_STARTED_SHARP = "not_started_sharp" - NOT_STARTED_ROUNDED = "not_started_rounded" - NOT_STARTED_OUTLINED = "not_started_outlined" - NOTE = "note" - NOTE_SHARP = "note_sharp" - NOTE_ROUNDED = "note_rounded" - NOTE_OUTLINED = "note_outlined" - NOTE_ADD = "note_add" - NOTE_ADD_SHARP = "note_add_sharp" - NOTE_ADD_ROUNDED = "note_add_rounded" - NOTE_ADD_OUTLINED = "note_add_outlined" - NOTE_ALT = "note_alt" - NOTE_ALT_SHARP = "note_alt_sharp" - NOTE_ALT_ROUNDED = "note_alt_rounded" - NOTE_ALT_OUTLINED = "note_alt_outlined" - NOTES = "notes" - NOTES_SHARP = "notes_sharp" - NOTES_ROUNDED = "notes_rounded" - NOTES_OUTLINED = "notes_outlined" - NOTIFICATION_ADD = "notification_add" - NOTIFICATION_ADD_SHARP = "notification_add_sharp" - NOTIFICATION_ADD_ROUNDED = "notification_add_rounded" - NOTIFICATION_ADD_OUTLINED = "notification_add_outlined" - NOTIFICATION_IMPORTANT = "notification_important" - NOTIFICATION_IMPORTANT_SHARP = "notification_important_sharp" - NOTIFICATION_IMPORTANT_ROUNDED = "notification_important_rounded" - NOTIFICATION_IMPORTANT_OUTLINED = "notification_important_outlined" - NOTIFICATIONS = "notifications" - NOTIFICATIONS_SHARP = "notifications_sharp" - NOTIFICATIONS_ROUNDED = "notifications_rounded" - NOTIFICATIONS_OUTLINED = "notifications_outlined" - NOTIFICATIONS_ACTIVE = "notifications_active" - NOTIFICATIONS_ACTIVE_SHARP = "notifications_active_sharp" - NOTIFICATIONS_ACTIVE_ROUNDED = "notifications_active_rounded" - NOTIFICATIONS_ACTIVE_OUTLINED = "notifications_active_outlined" - NOTIFICATIONS_NONE = "notifications_none" - NOTIFICATIONS_NONE_SHARP = "notifications_none_sharp" - NOTIFICATIONS_NONE_ROUNDED = "notifications_none_rounded" - NOTIFICATIONS_NONE_OUTLINED = "notifications_none_outlined" - NOTIFICATIONS_OFF = "notifications_off" - NOTIFICATIONS_OFF_SHARP = "notifications_off_sharp" - NOTIFICATIONS_OFF_ROUNDED = "notifications_off_rounded" - NOTIFICATIONS_OFF_OUTLINED = "notifications_off_outlined" - NOTIFICATIONS_ON = "notifications_on" - NOTIFICATIONS_ON_SHARP = "notifications_on_sharp" - NOTIFICATIONS_ON_ROUNDED = "notifications_on_rounded" - NOTIFICATIONS_ON_OUTLINED = "notifications_on_outlined" - NOTIFICATIONS_PAUSED = "notifications_paused" - NOTIFICATIONS_PAUSED_SHARP = "notifications_paused_sharp" - NOTIFICATIONS_PAUSED_ROUNDED = "notifications_paused_rounded" - NOTIFICATIONS_PAUSED_OUTLINED = "notifications_paused_outlined" - NOW_WALLPAPER = "now_wallpaper" - NOW_WALLPAPER_SHARP = "now_wallpaper_sharp" - NOW_WALLPAPER_ROUNDED = "now_wallpaper_rounded" - NOW_WALLPAPER_OUTLINED = "now_wallpaper_outlined" - NOW_WIDGETS = "now_widgets" - NOW_WIDGETS_SHARP = "now_widgets_sharp" - NOW_WIDGETS_ROUNDED = "now_widgets_rounded" - NOW_WIDGETS_OUTLINED = "now_widgets_outlined" - NUMBERS = "numbers" - NUMBERS_SHARP = "numbers_sharp" - NUMBERS_ROUNDED = "numbers_rounded" - NUMBERS_OUTLINED = "numbers_outlined" - OFFLINE_BOLT = "offline_bolt" - OFFLINE_BOLT_SHARP = "offline_bolt_sharp" - OFFLINE_BOLT_ROUNDED = "offline_bolt_rounded" - OFFLINE_BOLT_OUTLINED = "offline_bolt_outlined" - OFFLINE_PIN = "offline_pin" - OFFLINE_PIN_SHARP = "offline_pin_sharp" - OFFLINE_PIN_ROUNDED = "offline_pin_rounded" - OFFLINE_PIN_OUTLINED = "offline_pin_outlined" - OFFLINE_SHARE = "offline_share" - OFFLINE_SHARE_SHARP = "offline_share_sharp" - OFFLINE_SHARE_ROUNDED = "offline_share_rounded" - OFFLINE_SHARE_OUTLINED = "offline_share_outlined" - OIL_BARREL = "oil_barrel" - OIL_BARREL_SHARP = "oil_barrel_sharp" - OIL_BARREL_ROUNDED = "oil_barrel_rounded" - OIL_BARREL_OUTLINED = "oil_barrel_outlined" - ON_DEVICE_TRAINING = "on_device_training" - ON_DEVICE_TRAINING_SHARP = "on_device_training_sharp" - ON_DEVICE_TRAINING_ROUNDED = "on_device_training_rounded" - ON_DEVICE_TRAINING_OUTLINED = "on_device_training_outlined" - ONDEMAND_VIDEO = "ondemand_video" - ONDEMAND_VIDEO_SHARP = "ondemand_video_sharp" - ONDEMAND_VIDEO_ROUNDED = "ondemand_video_rounded" - ONDEMAND_VIDEO_OUTLINED = "ondemand_video_outlined" - ONLINE_PREDICTION = "online_prediction" - ONLINE_PREDICTION_SHARP = "online_prediction_sharp" - ONLINE_PREDICTION_ROUNDED = "online_prediction_rounded" - ONLINE_PREDICTION_OUTLINED = "online_prediction_outlined" - OPACITY = "opacity" - OPACITY_SHARP = "opacity_sharp" - OPACITY_ROUNDED = "opacity_rounded" - OPACITY_OUTLINED = "opacity_outlined" - OPEN_IN_BROWSER = "open_in_browser" - OPEN_IN_BROWSER_SHARP = "open_in_browser_sharp" - OPEN_IN_BROWSER_ROUNDED = "open_in_browser_rounded" - OPEN_IN_BROWSER_OUTLINED = "open_in_browser_outlined" - OPEN_IN_FULL = "open_in_full" - OPEN_IN_FULL_SHARP = "open_in_full_sharp" - OPEN_IN_FULL_ROUNDED = "open_in_full_rounded" - OPEN_IN_FULL_OUTLINED = "open_in_full_outlined" - OPEN_IN_NEW = "open_in_new" - OPEN_IN_NEW_SHARP = "open_in_new_sharp" - OPEN_IN_NEW_ROUNDED = "open_in_new_rounded" - OPEN_IN_NEW_OUTLINED = "open_in_new_outlined" - OPEN_IN_NEW_OFF = "open_in_new_off" - OPEN_IN_NEW_OFF_SHARP = "open_in_new_off_sharp" - OPEN_IN_NEW_OFF_ROUNDED = "open_in_new_off_rounded" - OPEN_IN_NEW_OFF_OUTLINED = "open_in_new_off_outlined" - OPEN_WITH = "open_with" - OPEN_WITH_SHARP = "open_with_sharp" - OPEN_WITH_ROUNDED = "open_with_rounded" - OPEN_WITH_OUTLINED = "open_with_outlined" - OTHER_HOUSES = "other_houses" - OTHER_HOUSES_SHARP = "other_houses_sharp" - OTHER_HOUSES_ROUNDED = "other_houses_rounded" - OTHER_HOUSES_OUTLINED = "other_houses_outlined" - OUTBOND = "outbond" - OUTBOND_SHARP = "outbond_sharp" - OUTBOND_ROUNDED = "outbond_rounded" - OUTBOND_OUTLINED = "outbond_outlined" - OUTBOUND = "outbound" - OUTBOUND_SHARP = "outbound_sharp" - OUTBOUND_ROUNDED = "outbound_rounded" - OUTBOUND_OUTLINED = "outbound_outlined" - OUTBOX = "outbox" - OUTBOX_SHARP = "outbox_sharp" - OUTBOX_ROUNDED = "outbox_rounded" - OUTBOX_OUTLINED = "outbox_outlined" - OUTDOOR_GRILL = "outdoor_grill" - OUTDOOR_GRILL_SHARP = "outdoor_grill_sharp" - OUTDOOR_GRILL_ROUNDED = "outdoor_grill_rounded" - OUTDOOR_GRILL_OUTLINED = "outdoor_grill_outlined" - OUTGOING_MAIL = "outgoing_mail" - OUTLET = "outlet" - OUTLET_SHARP = "outlet_sharp" - OUTLET_ROUNDED = "outlet_rounded" - OUTLET_OUTLINED = "outlet_outlined" - OUTLINED_FLAG = "outlined_flag" - OUTLINED_FLAG_SHARP = "outlined_flag_sharp" - OUTLINED_FLAG_ROUNDED = "outlined_flag_rounded" - OUTLINED_FLAG_OUTLINED = "outlined_flag_outlined" - OUTPUT = "output" - OUTPUT_SHARP = "output_sharp" - OUTPUT_ROUNDED = "output_rounded" - OUTPUT_OUTLINED = "output_outlined" - PADDING = "padding" - PADDING_SHARP = "padding_sharp" - PADDING_ROUNDED = "padding_rounded" - PADDING_OUTLINED = "padding_outlined" - PAGES = "pages" - PAGES_SHARP = "pages_sharp" - PAGES_ROUNDED = "pages_rounded" - PAGES_OUTLINED = "pages_outlined" - PAGEVIEW = "pageview" - PAGEVIEW_SHARP = "pageview_sharp" - PAGEVIEW_ROUNDED = "pageview_rounded" - PAGEVIEW_OUTLINED = "pageview_outlined" - PAID = "paid" - PAID_SHARP = "paid_sharp" - PAID_ROUNDED = "paid_rounded" - PAID_OUTLINED = "paid_outlined" - PALETTE = "palette" - PALETTE_SHARP = "palette_sharp" - PALETTE_ROUNDED = "palette_rounded" - PALETTE_OUTLINED = "palette_outlined" - PALLET = "pallet" - PAN_TOOL = "pan_tool" - PAN_TOOL_SHARP = "pan_tool_sharp" - PAN_TOOL_ROUNDED = "pan_tool_rounded" - PAN_TOOL_OUTLINED = "pan_tool_outlined" - PAN_TOOL_ALT = "pan_tool_alt" - PAN_TOOL_ALT_SHARP = "pan_tool_alt_sharp" - PAN_TOOL_ALT_ROUNDED = "pan_tool_alt_rounded" - PAN_TOOL_ALT_OUTLINED = "pan_tool_alt_outlined" - PANORAMA = "panorama" - PANORAMA_SHARP = "panorama_sharp" - PANORAMA_ROUNDED = "panorama_rounded" - PANORAMA_OUTLINED = "panorama_outlined" - PANORAMA_FISH_EYE = "panorama_fish_eye" - PANORAMA_FISH_EYE_SHARP = "panorama_fish_eye_sharp" - PANORAMA_FISH_EYE_ROUNDED = "panorama_fish_eye_rounded" - PANORAMA_FISH_EYE_OUTLINED = "panorama_fish_eye_outlined" - PANORAMA_FISHEYE = "panorama_fisheye" - PANORAMA_FISHEYE_SHARP = "panorama_fisheye_sharp" - PANORAMA_FISHEYE_ROUNDED = "panorama_fisheye_rounded" - PANORAMA_FISHEYE_OUTLINED = "panorama_fisheye_outlined" - PANORAMA_HORIZONTAL = "panorama_horizontal" - PANORAMA_HORIZONTAL_SHARP = "panorama_horizontal_sharp" - PANORAMA_HORIZONTAL_ROUNDED = "panorama_horizontal_rounded" - PANORAMA_HORIZONTAL_OUTLINED = "panorama_horizontal_outlined" - PANORAMA_HORIZONTAL_SELECT = "panorama_horizontal_select" - PANORAMA_HORIZONTAL_SELECT_SHARP = "panorama_horizontal_select_sharp" - PANORAMA_HORIZONTAL_SELECT_ROUNDED = "panorama_horizontal_select_rounded" - PANORAMA_HORIZONTAL_SELECT_OUTLINED = "panorama_horizontal_select_outlined" - PANORAMA_PHOTOSPHERE = "panorama_photosphere" - PANORAMA_PHOTOSPHERE_SHARP = "panorama_photosphere_sharp" - PANORAMA_PHOTOSPHERE_ROUNDED = "panorama_photosphere_rounded" - PANORAMA_PHOTOSPHERE_OUTLINED = "panorama_photosphere_outlined" - PANORAMA_PHOTOSPHERE_SELECT = "panorama_photosphere_select" - PANORAMA_PHOTOSPHERE_SELECT_SHARP = "panorama_photosphere_select_sharp" - PANORAMA_PHOTOSPHERE_SELECT_ROUNDED = "panorama_photosphere_select_rounded" - PANORAMA_PHOTOSPHERE_SELECT_OUTLINED = "panorama_photosphere_select_outlined" - PANORAMA_VERTICAL = "panorama_vertical" - PANORAMA_VERTICAL_SHARP = "panorama_vertical_sharp" - PANORAMA_VERTICAL_ROUNDED = "panorama_vertical_rounded" - PANORAMA_VERTICAL_OUTLINED = "panorama_vertical_outlined" - PANORAMA_VERTICAL_SELECT = "panorama_vertical_select" - PANORAMA_VERTICAL_SELECT_SHARP = "panorama_vertical_select_sharp" - PANORAMA_VERTICAL_SELECT_ROUNDED = "panorama_vertical_select_rounded" - PANORAMA_VERTICAL_SELECT_OUTLINED = "panorama_vertical_select_outlined" - PANORAMA_WIDE_ANGLE = "panorama_wide_angle" - PANORAMA_WIDE_ANGLE_SHARP = "panorama_wide_angle_sharp" - PANORAMA_WIDE_ANGLE_ROUNDED = "panorama_wide_angle_rounded" - PANORAMA_WIDE_ANGLE_OUTLINED = "panorama_wide_angle_outlined" - PANORAMA_WIDE_ANGLE_SELECT = "panorama_wide_angle_select" - PANORAMA_WIDE_ANGLE_SELECT_SHARP = "panorama_wide_angle_select_sharp" - PANORAMA_WIDE_ANGLE_SELECT_ROUNDED = "panorama_wide_angle_select_rounded" - PANORAMA_WIDE_ANGLE_SELECT_OUTLINED = "panorama_wide_angle_select_outlined" - PARAGLIDING = "paragliding" - PARAGLIDING_SHARP = "paragliding_sharp" - PARAGLIDING_ROUNDED = "paragliding_rounded" - PARAGLIDING_OUTLINED = "paragliding_outlined" - PARK = "park" - PARK_SHARP = "park_sharp" - PARK_ROUNDED = "park_rounded" - PARK_OUTLINED = "park_outlined" - PARTY_MODE = "party_mode" - PARTY_MODE_SHARP = "party_mode_sharp" - PARTY_MODE_ROUNDED = "party_mode_rounded" - PARTY_MODE_OUTLINED = "party_mode_outlined" - PASSWORD = "password" - PASSWORD_SHARP = "password_sharp" - PASSWORD_ROUNDED = "password_rounded" - PASSWORD_OUTLINED = "password_outlined" - PASTE = "paste" - PASTE_SHARP = "paste_sharp" - PASTE_ROUNDED = "paste_rounded" - PASTE_OUTLINED = "paste_outlined" - PATTERN = "pattern" - PATTERN_SHARP = "pattern_sharp" - PATTERN_ROUNDED = "pattern_rounded" - PATTERN_OUTLINED = "pattern_outlined" - PAUSE = "pause" - PAUSE_SHARP = "pause_sharp" - PAUSE_ROUNDED = "pause_rounded" - PAUSE_OUTLINED = "pause_outlined" - PAUSE_CIRCLE = "pause_circle" - PAUSE_CIRCLE_SHARP = "pause_circle_sharp" - PAUSE_CIRCLE_ROUNDED = "pause_circle_rounded" - PAUSE_CIRCLE_OUTLINED = "pause_circle_outlined" - PAUSE_CIRCLE_FILLED = "pause_circle_filled" - PAUSE_CIRCLE_FILLED_SHARP = "pause_circle_filled_sharp" - PAUSE_CIRCLE_FILLED_ROUNDED = "pause_circle_filled_rounded" - PAUSE_CIRCLE_FILLED_OUTLINED = "pause_circle_filled_outlined" - PAUSE_CIRCLE_OUTLINE = "pause_circle_outline" - PAUSE_CIRCLE_OUTLINE_SHARP = "pause_circle_outline_sharp" - PAUSE_CIRCLE_OUTLINE_ROUNDED = "pause_circle_outline_rounded" - PAUSE_CIRCLE_OUTLINE_OUTLINED = "pause_circle_outline_outlined" - PAUSE_PRESENTATION = "pause_presentation" - PAUSE_PRESENTATION_SHARP = "pause_presentation_sharp" - PAUSE_PRESENTATION_ROUNDED = "pause_presentation_rounded" - PAUSE_PRESENTATION_OUTLINED = "pause_presentation_outlined" - PAYMENT = "payment" - PAYMENT_SHARP = "payment_sharp" - PAYMENT_ROUNDED = "payment_rounded" - PAYMENT_OUTLINED = "payment_outlined" - PAYMENTS = "payments" - PAYMENTS_SHARP = "payments_sharp" - PAYMENTS_ROUNDED = "payments_rounded" - PAYMENTS_OUTLINED = "payments_outlined" - PAYPAL = "paypal" - PAYPAL_SHARP = "paypal_sharp" - PAYPAL_ROUNDED = "paypal_rounded" - PAYPAL_OUTLINED = "paypal_outlined" - PEDAL_BIKE = "pedal_bike" - PEDAL_BIKE_SHARP = "pedal_bike_sharp" - PEDAL_BIKE_ROUNDED = "pedal_bike_rounded" - PEDAL_BIKE_OUTLINED = "pedal_bike_outlined" - PENDING = "pending" - PENDING_SHARP = "pending_sharp" - PENDING_ROUNDED = "pending_rounded" - PENDING_OUTLINED = "pending_outlined" - PENDING_ACTIONS = "pending_actions" - PENDING_ACTIONS_SHARP = "pending_actions_sharp" - PENDING_ACTIONS_ROUNDED = "pending_actions_rounded" - PENDING_ACTIONS_OUTLINED = "pending_actions_outlined" - PENTAGON = "pentagon" - PENTAGON_SHARP = "pentagon_sharp" - PENTAGON_ROUNDED = "pentagon_rounded" - PENTAGON_OUTLINED = "pentagon_outlined" - PEOPLE = "people" - PEOPLE_SHARP = "people_sharp" - PEOPLE_ROUNDED = "people_rounded" - PEOPLE_OUTLINED = "people_outlined" - PEOPLE_ALT = "people_alt" - PEOPLE_ALT_SHARP = "people_alt_sharp" - PEOPLE_ALT_ROUNDED = "people_alt_rounded" - PEOPLE_ALT_OUTLINED = "people_alt_outlined" - PEOPLE_OUTLINE = "people_outline" - PEOPLE_OUTLINE_SHARP = "people_outline_sharp" - PEOPLE_OUTLINE_ROUNDED = "people_outline_rounded" - PEOPLE_OUTLINE_OUTLINED = "people_outline_outlined" - PERCENT = "percent" - PERCENT_SHARP = "percent_sharp" - PERCENT_ROUNDED = "percent_rounded" - PERCENT_OUTLINED = "percent_outlined" - PERM_CAMERA_MIC = "perm_camera_mic" - PERM_CAMERA_MIC_SHARP = "perm_camera_mic_sharp" - PERM_CAMERA_MIC_ROUNDED = "perm_camera_mic_rounded" - PERM_CAMERA_MIC_OUTLINED = "perm_camera_mic_outlined" - PERM_CONTACT_CAL = "perm_contact_cal" - PERM_CONTACT_CAL_SHARP = "perm_contact_cal_sharp" - PERM_CONTACT_CAL_ROUNDED = "perm_contact_cal_rounded" - PERM_CONTACT_CAL_OUTLINED = "perm_contact_cal_outlined" - PERM_CONTACT_CALENDAR = "perm_contact_calendar" - PERM_CONTACT_CALENDAR_SHARP = "perm_contact_calendar_sharp" - PERM_CONTACT_CALENDAR_ROUNDED = "perm_contact_calendar_rounded" - PERM_CONTACT_CALENDAR_OUTLINED = "perm_contact_calendar_outlined" - PERM_DATA_SETTING = "perm_data_setting" - PERM_DATA_SETTING_SHARP = "perm_data_setting_sharp" - PERM_DATA_SETTING_ROUNDED = "perm_data_setting_rounded" - PERM_DATA_SETTING_OUTLINED = "perm_data_setting_outlined" - PERM_DEVICE_INFO = "perm_device_info" - PERM_DEVICE_INFO_SHARP = "perm_device_info_sharp" - PERM_DEVICE_INFO_ROUNDED = "perm_device_info_rounded" - PERM_DEVICE_INFO_OUTLINED = "perm_device_info_outlined" - PERM_DEVICE_INFORMATION = "perm_device_information" - PERM_DEVICE_INFORMATION_SHARP = "perm_device_information_sharp" - PERM_DEVICE_INFORMATION_ROUNDED = "perm_device_information_rounded" - PERM_DEVICE_INFORMATION_OUTLINED = "perm_device_information_outlined" - PERM_IDENTITY = "perm_identity" - PERM_IDENTITY_SHARP = "perm_identity_sharp" - PERM_IDENTITY_ROUNDED = "perm_identity_rounded" - PERM_IDENTITY_OUTLINED = "perm_identity_outlined" - PERM_MEDIA = "perm_media" - PERM_MEDIA_SHARP = "perm_media_sharp" - PERM_MEDIA_ROUNDED = "perm_media_rounded" - PERM_MEDIA_OUTLINED = "perm_media_outlined" - PERM_PHONE_MSG = "perm_phone_msg" - PERM_PHONE_MSG_SHARP = "perm_phone_msg_sharp" - PERM_PHONE_MSG_ROUNDED = "perm_phone_msg_rounded" - PERM_PHONE_MSG_OUTLINED = "perm_phone_msg_outlined" - PERM_SCAN_WIFI = "perm_scan_wifi" - PERM_SCAN_WIFI_SHARP = "perm_scan_wifi_sharp" - PERM_SCAN_WIFI_ROUNDED = "perm_scan_wifi_rounded" - PERM_SCAN_WIFI_OUTLINED = "perm_scan_wifi_outlined" - PERSON = "person" - PERSON_SHARP = "person_sharp" - PERSON_ROUNDED = "person_rounded" - PERSON_OUTLINED = "person_outlined" - PERSON_2 = "person_2" - PERSON_2_SHARP = "person_2_sharp" - PERSON_2_ROUNDED = "person_2_rounded" - PERSON_2_OUTLINED = "person_2_outlined" - PERSON_3 = "person_3" - PERSON_3_SHARP = "person_3_sharp" - PERSON_3_ROUNDED = "person_3_rounded" - PERSON_3_OUTLINED = "person_3_outlined" - PERSON_4 = "person_4" - PERSON_4_SHARP = "person_4_sharp" - PERSON_4_ROUNDED = "person_4_rounded" - PERSON_4_OUTLINED = "person_4_outlined" - PERSON_ADD = "person_add" - PERSON_ADD_SHARP = "person_add_sharp" - PERSON_ADD_ROUNDED = "person_add_rounded" - PERSON_ADD_OUTLINED = "person_add_outlined" - PERSON_ADD_ALT = "person_add_alt" - PERSON_ADD_ALT_SHARP = "person_add_alt_sharp" - PERSON_ADD_ALT_ROUNDED = "person_add_alt_rounded" - PERSON_ADD_ALT_OUTLINED = "person_add_alt_outlined" - PERSON_ADD_ALT_1 = "person_add_alt_1" - PERSON_ADD_ALT_1_SHARP = "person_add_alt_1_sharp" - PERSON_ADD_ALT_1_ROUNDED = "person_add_alt_1_rounded" - PERSON_ADD_ALT_1_OUTLINED = "person_add_alt_1_outlined" - PERSON_ADD_DISABLED = "person_add_disabled" - PERSON_ADD_DISABLED_SHARP = "person_add_disabled_sharp" - PERSON_ADD_DISABLED_ROUNDED = "person_add_disabled_rounded" - PERSON_ADD_DISABLED_OUTLINED = "person_add_disabled_outlined" - PERSON_OFF = "person_off" - PERSON_OFF_SHARP = "person_off_sharp" - PERSON_OFF_ROUNDED = "person_off_rounded" - PERSON_OFF_OUTLINED = "person_off_outlined" - PERSON_OUTLINE = "person_outline" - PERSON_OUTLINE_SHARP = "person_outline_sharp" - PERSON_OUTLINE_ROUNDED = "person_outline_rounded" - PERSON_OUTLINE_OUTLINED = "person_outline_outlined" - PERSON_PIN = "person_pin" - PERSON_PIN_SHARP = "person_pin_sharp" - PERSON_PIN_ROUNDED = "person_pin_rounded" - PERSON_PIN_OUTLINED = "person_pin_outlined" - PERSON_PIN_CIRCLE = "person_pin_circle" - PERSON_PIN_CIRCLE_SHARP = "person_pin_circle_sharp" - PERSON_PIN_CIRCLE_ROUNDED = "person_pin_circle_rounded" - PERSON_PIN_CIRCLE_OUTLINED = "person_pin_circle_outlined" - PERSON_REMOVE = "person_remove" - PERSON_REMOVE_SHARP = "person_remove_sharp" - PERSON_REMOVE_ROUNDED = "person_remove_rounded" - PERSON_REMOVE_OUTLINED = "person_remove_outlined" - PERSON_REMOVE_ALT_1 = "person_remove_alt_1" - PERSON_REMOVE_ALT_1_SHARP = "person_remove_alt_1_sharp" - PERSON_REMOVE_ALT_1_ROUNDED = "person_remove_alt_1_rounded" - PERSON_REMOVE_ALT_1_OUTLINED = "person_remove_alt_1_outlined" - PERSON_SEARCH = "person_search" - PERSON_SEARCH_SHARP = "person_search_sharp" - PERSON_SEARCH_ROUNDED = "person_search_rounded" - PERSON_SEARCH_OUTLINED = "person_search_outlined" - PERSONAL_INJURY = "personal_injury" - PERSONAL_INJURY_SHARP = "personal_injury_sharp" - PERSONAL_INJURY_ROUNDED = "personal_injury_rounded" - PERSONAL_INJURY_OUTLINED = "personal_injury_outlined" - PERSONAL_VIDEO = "personal_video" - PERSONAL_VIDEO_SHARP = "personal_video_sharp" - PERSONAL_VIDEO_ROUNDED = "personal_video_rounded" - PERSONAL_VIDEO_OUTLINED = "personal_video_outlined" - PEST_CONTROL = "pest_control" - PEST_CONTROL_SHARP = "pest_control_sharp" - PEST_CONTROL_ROUNDED = "pest_control_rounded" - PEST_CONTROL_OUTLINED = "pest_control_outlined" - PEST_CONTROL_RODENT = "pest_control_rodent" - PEST_CONTROL_RODENT_SHARP = "pest_control_rodent_sharp" - PEST_CONTROL_RODENT_ROUNDED = "pest_control_rodent_rounded" - PEST_CONTROL_RODENT_OUTLINED = "pest_control_rodent_outlined" - PETS = "pets" - PETS_SHARP = "pets_sharp" - PETS_ROUNDED = "pets_rounded" - PETS_OUTLINED = "pets_outlined" - PHISHING = "phishing" - PHISHING_SHARP = "phishing_sharp" - PHISHING_ROUNDED = "phishing_rounded" - PHISHING_OUTLINED = "phishing_outlined" - PHONE = "phone" - PHONE_SHARP = "phone_sharp" - PHONE_ROUNDED = "phone_rounded" - PHONE_OUTLINED = "phone_outlined" - PHONE_ANDROID = "phone_android" - PHONE_ANDROID_SHARP = "phone_android_sharp" - PHONE_ANDROID_ROUNDED = "phone_android_rounded" - PHONE_ANDROID_OUTLINED = "phone_android_outlined" - PHONE_BLUETOOTH_SPEAKER = "phone_bluetooth_speaker" - PHONE_BLUETOOTH_SPEAKER_SHARP = "phone_bluetooth_speaker_sharp" - PHONE_BLUETOOTH_SPEAKER_ROUNDED = "phone_bluetooth_speaker_rounded" - PHONE_BLUETOOTH_SPEAKER_OUTLINED = "phone_bluetooth_speaker_outlined" - PHONE_CALLBACK = "phone_callback" - PHONE_CALLBACK_SHARP = "phone_callback_sharp" - PHONE_CALLBACK_ROUNDED = "phone_callback_rounded" - PHONE_CALLBACK_OUTLINED = "phone_callback_outlined" - PHONE_DISABLED = "phone_disabled" - PHONE_DISABLED_SHARP = "phone_disabled_sharp" - PHONE_DISABLED_ROUNDED = "phone_disabled_rounded" - PHONE_DISABLED_OUTLINED = "phone_disabled_outlined" - PHONE_ENABLED = "phone_enabled" - PHONE_ENABLED_SHARP = "phone_enabled_sharp" - PHONE_ENABLED_ROUNDED = "phone_enabled_rounded" - PHONE_ENABLED_OUTLINED = "phone_enabled_outlined" - PHONE_FORWARDED = "phone_forwarded" - PHONE_FORWARDED_SHARP = "phone_forwarded_sharp" - PHONE_FORWARDED_ROUNDED = "phone_forwarded_rounded" - PHONE_FORWARDED_OUTLINED = "phone_forwarded_outlined" - PHONE_IN_TALK = "phone_in_talk" - PHONE_IN_TALK_SHARP = "phone_in_talk_sharp" - PHONE_IN_TALK_ROUNDED = "phone_in_talk_rounded" - PHONE_IN_TALK_OUTLINED = "phone_in_talk_outlined" - PHONE_IPHONE = "phone_iphone" - PHONE_IPHONE_SHARP = "phone_iphone_sharp" - PHONE_IPHONE_ROUNDED = "phone_iphone_rounded" - PHONE_IPHONE_OUTLINED = "phone_iphone_outlined" - PHONE_LOCKED = "phone_locked" - PHONE_LOCKED_SHARP = "phone_locked_sharp" - PHONE_LOCKED_ROUNDED = "phone_locked_rounded" - PHONE_LOCKED_OUTLINED = "phone_locked_outlined" - PHONE_MISSED = "phone_missed" - PHONE_MISSED_SHARP = "phone_missed_sharp" - PHONE_MISSED_ROUNDED = "phone_missed_rounded" - PHONE_MISSED_OUTLINED = "phone_missed_outlined" - PHONE_PAUSED = "phone_paused" - PHONE_PAUSED_SHARP = "phone_paused_sharp" - PHONE_PAUSED_ROUNDED = "phone_paused_rounded" - PHONE_PAUSED_OUTLINED = "phone_paused_outlined" - PHONELINK = "phonelink" - PHONELINK_SHARP = "phonelink_sharp" - PHONELINK_ROUNDED = "phonelink_rounded" - PHONELINK_OUTLINED = "phonelink_outlined" - PHONELINK_ERASE = "phonelink_erase" - PHONELINK_ERASE_SHARP = "phonelink_erase_sharp" - PHONELINK_ERASE_ROUNDED = "phonelink_erase_rounded" - PHONELINK_ERASE_OUTLINED = "phonelink_erase_outlined" - PHONELINK_LOCK = "phonelink_lock" - PHONELINK_LOCK_SHARP = "phonelink_lock_sharp" - PHONELINK_LOCK_ROUNDED = "phonelink_lock_rounded" - PHONELINK_LOCK_OUTLINED = "phonelink_lock_outlined" - PHONELINK_OFF = "phonelink_off" - PHONELINK_OFF_SHARP = "phonelink_off_sharp" - PHONELINK_OFF_ROUNDED = "phonelink_off_rounded" - PHONELINK_OFF_OUTLINED = "phonelink_off_outlined" - PHONELINK_RING = "phonelink_ring" - PHONELINK_RING_SHARP = "phonelink_ring_sharp" - PHONELINK_RING_ROUNDED = "phonelink_ring_rounded" - PHONELINK_RING_OUTLINED = "phonelink_ring_outlined" - PHONELINK_SETUP = "phonelink_setup" - PHONELINK_SETUP_SHARP = "phonelink_setup_sharp" - PHONELINK_SETUP_ROUNDED = "phonelink_setup_rounded" - PHONELINK_SETUP_OUTLINED = "phonelink_setup_outlined" - PHOTO = "photo" - PHOTO_SHARP = "photo_sharp" - PHOTO_ROUNDED = "photo_rounded" - PHOTO_OUTLINED = "photo_outlined" - PHOTO_ALBUM = "photo_album" - PHOTO_ALBUM_SHARP = "photo_album_sharp" - PHOTO_ALBUM_ROUNDED = "photo_album_rounded" - PHOTO_ALBUM_OUTLINED = "photo_album_outlined" - PHOTO_CAMERA = "photo_camera" - PHOTO_CAMERA_SHARP = "photo_camera_sharp" - PHOTO_CAMERA_ROUNDED = "photo_camera_rounded" - PHOTO_CAMERA_OUTLINED = "photo_camera_outlined" - PHOTO_CAMERA_BACK = "photo_camera_back" - PHOTO_CAMERA_BACK_SHARP = "photo_camera_back_sharp" - PHOTO_CAMERA_BACK_ROUNDED = "photo_camera_back_rounded" - PHOTO_CAMERA_BACK_OUTLINED = "photo_camera_back_outlined" - PHOTO_CAMERA_FRONT = "photo_camera_front" - PHOTO_CAMERA_FRONT_SHARP = "photo_camera_front_sharp" - PHOTO_CAMERA_FRONT_ROUNDED = "photo_camera_front_rounded" - PHOTO_CAMERA_FRONT_OUTLINED = "photo_camera_front_outlined" - PHOTO_FILTER = "photo_filter" - PHOTO_FILTER_SHARP = "photo_filter_sharp" - PHOTO_FILTER_ROUNDED = "photo_filter_rounded" - PHOTO_FILTER_OUTLINED = "photo_filter_outlined" - PHOTO_LIBRARY = "photo_library" - PHOTO_LIBRARY_SHARP = "photo_library_sharp" - PHOTO_LIBRARY_ROUNDED = "photo_library_rounded" - PHOTO_LIBRARY_OUTLINED = "photo_library_outlined" - PHOTO_SIZE_SELECT_ACTUAL = "photo_size_select_actual" - PHOTO_SIZE_SELECT_ACTUAL_SHARP = "photo_size_select_actual_sharp" - PHOTO_SIZE_SELECT_ACTUAL_ROUNDED = "photo_size_select_actual_rounded" - PHOTO_SIZE_SELECT_ACTUAL_OUTLINED = "photo_size_select_actual_outlined" - PHOTO_SIZE_SELECT_LARGE = "photo_size_select_large" - PHOTO_SIZE_SELECT_LARGE_SHARP = "photo_size_select_large_sharp" - PHOTO_SIZE_SELECT_LARGE_ROUNDED = "photo_size_select_large_rounded" - PHOTO_SIZE_SELECT_LARGE_OUTLINED = "photo_size_select_large_outlined" - PHOTO_SIZE_SELECT_SMALL = "photo_size_select_small" - PHOTO_SIZE_SELECT_SMALL_SHARP = "photo_size_select_small_sharp" - PHOTO_SIZE_SELECT_SMALL_ROUNDED = "photo_size_select_small_rounded" - PHOTO_SIZE_SELECT_SMALL_OUTLINED = "photo_size_select_small_outlined" - PHP = "php" - PHP_SHARP = "php_sharp" - PHP_ROUNDED = "php_rounded" - PHP_OUTLINED = "php_outlined" - PIANO = "piano" - PIANO_SHARP = "piano_sharp" - PIANO_ROUNDED = "piano_rounded" - PIANO_OUTLINED = "piano_outlined" - PIANO_OFF = "piano_off" - PIANO_OFF_SHARP = "piano_off_sharp" - PIANO_OFF_ROUNDED = "piano_off_rounded" - PIANO_OFF_OUTLINED = "piano_off_outlined" - PICTURE_AS_PDF = "picture_as_pdf" - PICTURE_AS_PDF_SHARP = "picture_as_pdf_sharp" - PICTURE_AS_PDF_ROUNDED = "picture_as_pdf_rounded" - PICTURE_AS_PDF_OUTLINED = "picture_as_pdf_outlined" - PICTURE_IN_PICTURE = "picture_in_picture" - PICTURE_IN_PICTURE_SHARP = "picture_in_picture_sharp" - PICTURE_IN_PICTURE_ROUNDED = "picture_in_picture_rounded" - PICTURE_IN_PICTURE_OUTLINED = "picture_in_picture_outlined" - PICTURE_IN_PICTURE_ALT = "picture_in_picture_alt" - PICTURE_IN_PICTURE_ALT_SHARP = "picture_in_picture_alt_sharp" - PICTURE_IN_PICTURE_ALT_ROUNDED = "picture_in_picture_alt_rounded" - PICTURE_IN_PICTURE_ALT_OUTLINED = "picture_in_picture_alt_outlined" - PIE_CHART = "pie_chart" - PIE_CHART_SHARP = "pie_chart_sharp" - PIE_CHART_ROUNDED = "pie_chart_rounded" - PIE_CHART_OUTLINE = "pie_chart_outline" - PIE_CHART_OUTLINE_SHARP = "pie_chart_outline_sharp" - PIE_CHART_OUTLINE_ROUNDED = "pie_chart_outline_rounded" - PIE_CHART_OUTLINE_OUTLINED = "pie_chart_outline_outlined" - PIN = "pin" - PIN_SHARP = "pin_sharp" - PIN_ROUNDED = "pin_rounded" - PIN_OUTLINED = "pin_outlined" - PIN_DROP = "pin_drop" - PIN_DROP_SHARP = "pin_drop_sharp" - PIN_DROP_ROUNDED = "pin_drop_rounded" - PIN_DROP_OUTLINED = "pin_drop_outlined" - PIN_END = "pin_end" - PIN_END_SHARP = "pin_end_sharp" - PIN_END_ROUNDED = "pin_end_rounded" - PIN_END_OUTLINED = "pin_end_outlined" - PIN_INVOKE = "pin_invoke" - PIN_INVOKE_SHARP = "pin_invoke_sharp" - PIN_INVOKE_ROUNDED = "pin_invoke_rounded" - PIN_INVOKE_OUTLINED = "pin_invoke_outlined" - PINCH = "pinch" - PINCH_SHARP = "pinch_sharp" - PINCH_ROUNDED = "pinch_rounded" - PINCH_OUTLINED = "pinch_outlined" - PIVOT_TABLE_CHART = "pivot_table_chart" - PIVOT_TABLE_CHART_SHARP = "pivot_table_chart_sharp" - PIVOT_TABLE_CHART_ROUNDED = "pivot_table_chart_rounded" - PIVOT_TABLE_CHART_OUTLINED = "pivot_table_chart_outlined" - PIX = "pix" - PIX_SHARP = "pix_sharp" - PIX_ROUNDED = "pix_rounded" - PIX_OUTLINED = "pix_outlined" - PLACE = "place" - PLACE_SHARP = "place_sharp" - PLACE_ROUNDED = "place_rounded" - PLACE_OUTLINED = "place_outlined" - PLAGIARISM = "plagiarism" - PLAGIARISM_SHARP = "plagiarism_sharp" - PLAGIARISM_ROUNDED = "plagiarism_rounded" - PLAGIARISM_OUTLINED = "plagiarism_outlined" - PLAY_ARROW = "play_arrow" - PLAY_ARROW_SHARP = "play_arrow_sharp" - PLAY_ARROW_ROUNDED = "play_arrow_rounded" - PLAY_ARROW_OUTLINED = "play_arrow_outlined" - PLAY_CIRCLE = "play_circle" - PLAY_CIRCLE_SHARP = "play_circle_sharp" - PLAY_CIRCLE_ROUNDED = "play_circle_rounded" - PLAY_CIRCLE_OUTLINED = "play_circle_outlined" - PLAY_CIRCLE_FILL = "play_circle_fill" - PLAY_CIRCLE_FILL_SHARP = "play_circle_fill_sharp" - PLAY_CIRCLE_FILL_ROUNDED = "play_circle_fill_rounded" - PLAY_CIRCLE_FILL_OUTLINED = "play_circle_fill_outlined" - PLAY_CIRCLE_FILLED = "play_circle_filled" - PLAY_CIRCLE_FILLED_SHARP = "play_circle_filled_sharp" - PLAY_CIRCLE_FILLED_ROUNDED = "play_circle_filled_rounded" - PLAY_CIRCLE_FILLED_OUTLINED = "play_circle_filled_outlined" - PLAY_CIRCLE_OUTLINE = "play_circle_outline" - PLAY_CIRCLE_OUTLINE_SHARP = "play_circle_outline_sharp" - PLAY_CIRCLE_OUTLINE_ROUNDED = "play_circle_outline_rounded" - PLAY_CIRCLE_OUTLINE_OUTLINED = "play_circle_outline_outlined" - PLAY_DISABLED = "play_disabled" - PLAY_DISABLED_SHARP = "play_disabled_sharp" - PLAY_DISABLED_ROUNDED = "play_disabled_rounded" - PLAY_DISABLED_OUTLINED = "play_disabled_outlined" - PLAY_FOR_WORK = "play_for_work" - PLAY_FOR_WORK_SHARP = "play_for_work_sharp" - PLAY_FOR_WORK_ROUNDED = "play_for_work_rounded" - PLAY_FOR_WORK_OUTLINED = "play_for_work_outlined" - PLAY_LESSON = "play_lesson" - PLAY_LESSON_SHARP = "play_lesson_sharp" - PLAY_LESSON_ROUNDED = "play_lesson_rounded" - PLAY_LESSON_OUTLINED = "play_lesson_outlined" - PLAYLIST_ADD = "playlist_add" - PLAYLIST_ADD_SHARP = "playlist_add_sharp" - PLAYLIST_ADD_ROUNDED = "playlist_add_rounded" - PLAYLIST_ADD_OUTLINED = "playlist_add_outlined" - PLAYLIST_ADD_CHECK = "playlist_add_check" - PLAYLIST_ADD_CHECK_SHARP = "playlist_add_check_sharp" - PLAYLIST_ADD_CHECK_ROUNDED = "playlist_add_check_rounded" - PLAYLIST_ADD_CHECK_OUTLINED = "playlist_add_check_outlined" - PLAYLIST_ADD_CHECK_CIRCLE = "playlist_add_check_circle" - PLAYLIST_ADD_CHECK_CIRCLE_SHARP = "playlist_add_check_circle_sharp" - PLAYLIST_ADD_CHECK_CIRCLE_ROUNDED = "playlist_add_check_circle_rounded" - PLAYLIST_ADD_CHECK_CIRCLE_OUTLINED = "playlist_add_check_circle_outlined" - PLAYLIST_ADD_CIRCLE = "playlist_add_circle" - PLAYLIST_ADD_CIRCLE_SHARP = "playlist_add_circle_sharp" - PLAYLIST_ADD_CIRCLE_ROUNDED = "playlist_add_circle_rounded" - PLAYLIST_ADD_CIRCLE_OUTLINED = "playlist_add_circle_outlined" - PLAYLIST_PLAY = "playlist_play" - PLAYLIST_PLAY_SHARP = "playlist_play_sharp" - PLAYLIST_PLAY_ROUNDED = "playlist_play_rounded" - PLAYLIST_PLAY_OUTLINED = "playlist_play_outlined" - PLAYLIST_REMOVE = "playlist_remove" - PLAYLIST_REMOVE_SHARP = "playlist_remove_sharp" - PLAYLIST_REMOVE_ROUNDED = "playlist_remove_rounded" - PLAYLIST_REMOVE_OUTLINED = "playlist_remove_outlined" - PLUMBING = "plumbing" - PLUMBING_SHARP = "plumbing_sharp" - PLUMBING_ROUNDED = "plumbing_rounded" - PLUMBING_OUTLINED = "plumbing_outlined" - PLUS_ONE = "plus_one" - PLUS_ONE_SHARP = "plus_one_sharp" - PLUS_ONE_ROUNDED = "plus_one_rounded" - PLUS_ONE_OUTLINED = "plus_one_outlined" - PODCASTS = "podcasts" - PODCASTS_SHARP = "podcasts_sharp" - PODCASTS_ROUNDED = "podcasts_rounded" - PODCASTS_OUTLINED = "podcasts_outlined" - POINT_OF_SALE = "point_of_sale" - POINT_OF_SALE_SHARP = "point_of_sale_sharp" - POINT_OF_SALE_ROUNDED = "point_of_sale_rounded" - POINT_OF_SALE_OUTLINED = "point_of_sale_outlined" - POLICY = "policy" - POLICY_SHARP = "policy_sharp" - POLICY_ROUNDED = "policy_rounded" - POLICY_OUTLINED = "policy_outlined" - POLL = "poll" - POLL_SHARP = "poll_sharp" - POLL_ROUNDED = "poll_rounded" - POLL_OUTLINED = "poll_outlined" - POLYLINE = "polyline" - POLYLINE_SHARP = "polyline_sharp" - POLYLINE_ROUNDED = "polyline_rounded" - POLYLINE_OUTLINED = "polyline_outlined" - POLYMER = "polymer" - POLYMER_SHARP = "polymer_sharp" - POLYMER_ROUNDED = "polymer_rounded" - POLYMER_OUTLINED = "polymer_outlined" - POOL = "pool" - POOL_SHARP = "pool_sharp" - POOL_ROUNDED = "pool_rounded" - POOL_OUTLINED = "pool_outlined" - PORTABLE_WIFI_OFF = "portable_wifi_off" - PORTABLE_WIFI_OFF_SHARP = "portable_wifi_off_sharp" - PORTABLE_WIFI_OFF_ROUNDED = "portable_wifi_off_rounded" - PORTABLE_WIFI_OFF_OUTLINED = "portable_wifi_off_outlined" - PORTRAIT = "portrait" - PORTRAIT_SHARP = "portrait_sharp" - PORTRAIT_ROUNDED = "portrait_rounded" - PORTRAIT_OUTLINED = "portrait_outlined" - POST_ADD = "post_add" - POST_ADD_SHARP = "post_add_sharp" - POST_ADD_ROUNDED = "post_add_rounded" - POST_ADD_OUTLINED = "post_add_outlined" - POWER = "power" - POWER_SHARP = "power_sharp" - POWER_ROUNDED = "power_rounded" - POWER_OUTLINED = "power_outlined" - POWER_INPUT = "power_input" - POWER_INPUT_SHARP = "power_input_sharp" - POWER_INPUT_ROUNDED = "power_input_rounded" - POWER_INPUT_OUTLINED = "power_input_outlined" - POWER_OFF = "power_off" - POWER_OFF_SHARP = "power_off_sharp" - POWER_OFF_ROUNDED = "power_off_rounded" - POWER_OFF_OUTLINED = "power_off_outlined" - POWER_SETTINGS_NEW = "power_settings_new" - POWER_SETTINGS_NEW_SHARP = "power_settings_new_sharp" - POWER_SETTINGS_NEW_ROUNDED = "power_settings_new_rounded" - POWER_SETTINGS_NEW_OUTLINED = "power_settings_new_outlined" - PRECISION_MANUFACTURING = "precision_manufacturing" - PRECISION_MANUFACTURING_SHARP = "precision_manufacturing_sharp" - PRECISION_MANUFACTURING_ROUNDED = "precision_manufacturing_rounded" - PRECISION_MANUFACTURING_OUTLINED = "precision_manufacturing_outlined" - PREGNANT_WOMAN = "pregnant_woman" - PREGNANT_WOMAN_SHARP = "pregnant_woman_sharp" - PREGNANT_WOMAN_ROUNDED = "pregnant_woman_rounded" - PREGNANT_WOMAN_OUTLINED = "pregnant_woman_outlined" - PRESENT_TO_ALL = "present_to_all" - PRESENT_TO_ALL_SHARP = "present_to_all_sharp" - PRESENT_TO_ALL_ROUNDED = "present_to_all_rounded" - PRESENT_TO_ALL_OUTLINED = "present_to_all_outlined" - PREVIEW = "preview" - PREVIEW_SHARP = "preview_sharp" - PREVIEW_ROUNDED = "preview_rounded" - PREVIEW_OUTLINED = "preview_outlined" - PRICE_CHANGE = "price_change" - PRICE_CHANGE_SHARP = "price_change_sharp" - PRICE_CHANGE_ROUNDED = "price_change_rounded" - PRICE_CHANGE_OUTLINED = "price_change_outlined" - PRICE_CHECK = "price_check" - PRICE_CHECK_SHARP = "price_check_sharp" - PRICE_CHECK_ROUNDED = "price_check_rounded" - PRICE_CHECK_OUTLINED = "price_check_outlined" - PRINT = "print" - PRINT_SHARP = "print_sharp" - PRINT_ROUNDED = "print_rounded" - PRINT_OUTLINED = "print_outlined" - PRINT_DISABLED = "print_disabled" - PRINT_DISABLED_SHARP = "print_disabled_sharp" - PRINT_DISABLED_ROUNDED = "print_disabled_rounded" - PRINT_DISABLED_OUTLINED = "print_disabled_outlined" - PRIORITY_HIGH = "priority_high" - PRIORITY_HIGH_SHARP = "priority_high_sharp" - PRIORITY_HIGH_ROUNDED = "priority_high_rounded" - PRIORITY_HIGH_OUTLINED = "priority_high_outlined" - PRIVACY_TIP = "privacy_tip" - PRIVACY_TIP_SHARP = "privacy_tip_sharp" - PRIVACY_TIP_ROUNDED = "privacy_tip_rounded" - PRIVACY_TIP_OUTLINED = "privacy_tip_outlined" - PRIVATE_CONNECTIVITY = "private_connectivity" - PRIVATE_CONNECTIVITY_SHARP = "private_connectivity_sharp" - PRIVATE_CONNECTIVITY_ROUNDED = "private_connectivity_rounded" - PRIVATE_CONNECTIVITY_OUTLINED = "private_connectivity_outlined" - PRODUCTION_QUANTITY_LIMITS = "production_quantity_limits" - PRODUCTION_QUANTITY_LIMITS_SHARP = "production_quantity_limits_sharp" - PRODUCTION_QUANTITY_LIMITS_ROUNDED = "production_quantity_limits_rounded" - PRODUCTION_QUANTITY_LIMITS_OUTLINED = "production_quantity_limits_outlined" - PROPANE = "propane" - PROPANE_SHARP = "propane_sharp" - PROPANE_ROUNDED = "propane_rounded" - PROPANE_OUTLINED = "propane_outlined" - PROPANE_TANK = "propane_tank" - PROPANE_TANK_SHARP = "propane_tank_sharp" - PROPANE_TANK_ROUNDED = "propane_tank_rounded" - PROPANE_TANK_OUTLINED = "propane_tank_outlined" - PSYCHOLOGY = "psychology" - PSYCHOLOGY_SHARP = "psychology_sharp" - PSYCHOLOGY_ROUNDED = "psychology_rounded" - PSYCHOLOGY_OUTLINED = "psychology_outlined" - PSYCHOLOGY_ALT = "psychology_alt" - PSYCHOLOGY_ALT_SHARP = "psychology_alt_sharp" - PSYCHOLOGY_ALT_ROUNDED = "psychology_alt_rounded" - PSYCHOLOGY_ALT_OUTLINED = "psychology_alt_outlined" - PUBLIC = "public" - PUBLIC_SHARP = "public_sharp" - PUBLIC_ROUNDED = "public_rounded" - PUBLIC_OUTLINED = "public_outlined" - PUBLIC_OFF = "public_off" - PUBLIC_OFF_SHARP = "public_off_sharp" - PUBLIC_OFF_ROUNDED = "public_off_rounded" - PUBLIC_OFF_OUTLINED = "public_off_outlined" - PUBLISH = "publish" - PUBLISH_SHARP = "publish_sharp" - PUBLISH_ROUNDED = "publish_rounded" - PUBLISH_OUTLINED = "publish_outlined" - PUBLISHED_WITH_CHANGES = "published_with_changes" - PUBLISHED_WITH_CHANGES_SHARP = "published_with_changes_sharp" - PUBLISHED_WITH_CHANGES_ROUNDED = "published_with_changes_rounded" - PUBLISHED_WITH_CHANGES_OUTLINED = "published_with_changes_outlined" - PUNCH_CLOCK = "punch_clock" - PUNCH_CLOCK_SHARP = "punch_clock_sharp" - PUNCH_CLOCK_ROUNDED = "punch_clock_rounded" - PUNCH_CLOCK_OUTLINED = "punch_clock_outlined" - PUSH_PIN = "push_pin" - PUSH_PIN_SHARP = "push_pin_sharp" - PUSH_PIN_ROUNDED = "push_pin_rounded" - PUSH_PIN_OUTLINED = "push_pin_outlined" - QR_CODE = "qr_code" - QR_CODE_SHARP = "qr_code_sharp" - QR_CODE_ROUNDED = "qr_code_rounded" - QR_CODE_OUTLINED = "qr_code_outlined" - QR_CODE_2 = "qr_code_2" - QR_CODE_2_SHARP = "qr_code_2_sharp" - QR_CODE_2_ROUNDED = "qr_code_2_rounded" - QR_CODE_2_OUTLINED = "qr_code_2_outlined" - QR_CODE_SCANNER = "qr_code_scanner" - QR_CODE_SCANNER_SHARP = "qr_code_scanner_sharp" - QR_CODE_SCANNER_ROUNDED = "qr_code_scanner_rounded" - QR_CODE_SCANNER_OUTLINED = "qr_code_scanner_outlined" - QUERY_BUILDER = "query_builder" - QUERY_BUILDER_SHARP = "query_builder_sharp" - QUERY_BUILDER_ROUNDED = "query_builder_rounded" - QUERY_BUILDER_OUTLINED = "query_builder_outlined" - QUERY_STATS = "query_stats" - QUERY_STATS_SHARP = "query_stats_sharp" - QUERY_STATS_ROUNDED = "query_stats_rounded" - QUERY_STATS_OUTLINED = "query_stats_outlined" - QUESTION_ANSWER = "question_answer" - QUESTION_ANSWER_SHARP = "question_answer_sharp" - QUESTION_ANSWER_ROUNDED = "question_answer_rounded" - QUESTION_ANSWER_OUTLINED = "question_answer_outlined" - QUESTION_MARK = "question_mark" - QUESTION_MARK_SHARP = "question_mark_sharp" - QUESTION_MARK_ROUNDED = "question_mark_rounded" - QUESTION_MARK_OUTLINED = "question_mark_outlined" - QUEUE = "queue" - QUEUE_SHARP = "queue_sharp" - QUEUE_ROUNDED = "queue_rounded" - QUEUE_OUTLINED = "queue_outlined" - QUEUE_MUSIC = "queue_music" - QUEUE_MUSIC_SHARP = "queue_music_sharp" - QUEUE_MUSIC_ROUNDED = "queue_music_rounded" - QUEUE_MUSIC_OUTLINED = "queue_music_outlined" - QUEUE_PLAY_NEXT = "queue_play_next" - QUEUE_PLAY_NEXT_SHARP = "queue_play_next_sharp" - QUEUE_PLAY_NEXT_ROUNDED = "queue_play_next_rounded" - QUEUE_PLAY_NEXT_OUTLINED = "queue_play_next_outlined" - QUICK_CONTACTS_DIALER = "quick_contacts_dialer" - QUICK_CONTACTS_DIALER_SHARP = "quick_contacts_dialer_sharp" - QUICK_CONTACTS_DIALER_ROUNDED = "quick_contacts_dialer_rounded" - QUICK_CONTACTS_DIALER_OUTLINED = "quick_contacts_dialer_outlined" - QUICK_CONTACTS_MAIL = "quick_contacts_mail" - QUICK_CONTACTS_MAIL_SHARP = "quick_contacts_mail_sharp" - QUICK_CONTACTS_MAIL_ROUNDED = "quick_contacts_mail_rounded" - QUICK_CONTACTS_MAIL_OUTLINED = "quick_contacts_mail_outlined" - QUICKREPLY = "quickreply" - QUICKREPLY_SHARP = "quickreply_sharp" - QUICKREPLY_ROUNDED = "quickreply_rounded" - QUICKREPLY_OUTLINED = "quickreply_outlined" - QUIZ = "quiz" - QUIZ_SHARP = "quiz_sharp" - QUIZ_ROUNDED = "quiz_rounded" - QUIZ_OUTLINED = "quiz_outlined" - QUORA = "quora" - QUORA_SHARP = "quora_sharp" - QUORA_ROUNDED = "quora_rounded" - QUORA_OUTLINED = "quora_outlined" - R_MOBILEDATA = "r_mobiledata" - R_MOBILEDATA_SHARP = "r_mobiledata_sharp" - R_MOBILEDATA_ROUNDED = "r_mobiledata_rounded" - R_MOBILEDATA_OUTLINED = "r_mobiledata_outlined" - RADAR = "radar" - RADAR_SHARP = "radar_sharp" - RADAR_ROUNDED = "radar_rounded" - RADAR_OUTLINED = "radar_outlined" - RADIO = "radio" - RADIO_SHARP = "radio_sharp" - RADIO_ROUNDED = "radio_rounded" - RADIO_OUTLINED = "radio_outlined" - RADIO_BUTTON_CHECKED = "radio_button_checked" - RADIO_BUTTON_CHECKED_SHARP = "radio_button_checked_sharp" - RADIO_BUTTON_CHECKED_ROUNDED = "radio_button_checked_rounded" - RADIO_BUTTON_CHECKED_OUTLINED = "radio_button_checked_outlined" - RADIO_BUTTON_OFF = "radio_button_off" - RADIO_BUTTON_OFF_SHARP = "radio_button_off_sharp" - RADIO_BUTTON_OFF_ROUNDED = "radio_button_off_rounded" - RADIO_BUTTON_OFF_OUTLINED = "radio_button_off_outlined" - RADIO_BUTTON_ON = "radio_button_on" - RADIO_BUTTON_ON_SHARP = "radio_button_on_sharp" - RADIO_BUTTON_ON_ROUNDED = "radio_button_on_rounded" - RADIO_BUTTON_ON_OUTLINED = "radio_button_on_outlined" - RADIO_BUTTON_UNCHECKED = "radio_button_unchecked" - RADIO_BUTTON_UNCHECKED_SHARP = "radio_button_unchecked_sharp" - RADIO_BUTTON_UNCHECKED_ROUNDED = "radio_button_unchecked_rounded" - RADIO_BUTTON_UNCHECKED_OUTLINED = "radio_button_unchecked_outlined" - RAILWAY_ALERT = "railway_alert" - RAILWAY_ALERT_SHARP = "railway_alert_sharp" - RAILWAY_ALERT_ROUNDED = "railway_alert_rounded" - RAILWAY_ALERT_OUTLINED = "railway_alert_outlined" - RAMEN_DINING = "ramen_dining" - RAMEN_DINING_SHARP = "ramen_dining_sharp" - RAMEN_DINING_ROUNDED = "ramen_dining_rounded" - RAMEN_DINING_OUTLINED = "ramen_dining_outlined" - RAMP_LEFT = "ramp_left" - RAMP_LEFT_SHARP = "ramp_left_sharp" - RAMP_LEFT_ROUNDED = "ramp_left_rounded" - RAMP_LEFT_OUTLINED = "ramp_left_outlined" - RAMP_RIGHT = "ramp_right" - RAMP_RIGHT_SHARP = "ramp_right_sharp" - RAMP_RIGHT_ROUNDED = "ramp_right_rounded" - RAMP_RIGHT_OUTLINED = "ramp_right_outlined" - RATE_REVIEW = "rate_review" - RATE_REVIEW_SHARP = "rate_review_sharp" - RATE_REVIEW_ROUNDED = "rate_review_rounded" - RATE_REVIEW_OUTLINED = "rate_review_outlined" - RAW_OFF = "raw_off" - RAW_OFF_SHARP = "raw_off_sharp" - RAW_OFF_ROUNDED = "raw_off_rounded" - RAW_OFF_OUTLINED = "raw_off_outlined" - RAW_ON = "raw_on" - RAW_ON_SHARP = "raw_on_sharp" - RAW_ON_ROUNDED = "raw_on_rounded" - RAW_ON_OUTLINED = "raw_on_outlined" - READ_MORE = "read_more" - READ_MORE_SHARP = "read_more_sharp" - READ_MORE_ROUNDED = "read_more_rounded" - READ_MORE_OUTLINED = "read_more_outlined" - REAL_ESTATE_AGENT = "real_estate_agent" - REAL_ESTATE_AGENT_SHARP = "real_estate_agent_sharp" - REAL_ESTATE_AGENT_ROUNDED = "real_estate_agent_rounded" - REAL_ESTATE_AGENT_OUTLINED = "real_estate_agent_outlined" - REBASE_EDIT = "rebase_edit" - RECEIPT = "receipt" - RECEIPT_SHARP = "receipt_sharp" - RECEIPT_ROUNDED = "receipt_rounded" - RECEIPT_OUTLINED = "receipt_outlined" - RECEIPT_LONG = "receipt_long" - RECEIPT_LONG_SHARP = "receipt_long_sharp" - RECEIPT_LONG_ROUNDED = "receipt_long_rounded" - RECEIPT_LONG_OUTLINED = "receipt_long_outlined" - RECENT_ACTORS = "recent_actors" - RECENT_ACTORS_SHARP = "recent_actors_sharp" - RECENT_ACTORS_ROUNDED = "recent_actors_rounded" - RECENT_ACTORS_OUTLINED = "recent_actors_outlined" - RECOMMEND = "recommend" - RECOMMEND_SHARP = "recommend_sharp" - RECOMMEND_ROUNDED = "recommend_rounded" - RECOMMEND_OUTLINED = "recommend_outlined" - RECORD_VOICE_OVER = "record_voice_over" - RECORD_VOICE_OVER_SHARP = "record_voice_over_sharp" - RECORD_VOICE_OVER_ROUNDED = "record_voice_over_rounded" - RECORD_VOICE_OVER_OUTLINED = "record_voice_over_outlined" - RECTANGLE = "rectangle" - RECTANGLE_SHARP = "rectangle_sharp" - RECTANGLE_ROUNDED = "rectangle_rounded" - RECTANGLE_OUTLINED = "rectangle_outlined" - RECYCLING = "recycling" - RECYCLING_SHARP = "recycling_sharp" - RECYCLING_ROUNDED = "recycling_rounded" - RECYCLING_OUTLINED = "recycling_outlined" - REDDIT = "reddit" - REDDIT_SHARP = "reddit_sharp" - REDDIT_ROUNDED = "reddit_rounded" - REDDIT_OUTLINED = "reddit_outlined" - REDEEM = "redeem" - REDEEM_SHARP = "redeem_sharp" - REDEEM_ROUNDED = "redeem_rounded" - REDEEM_OUTLINED = "redeem_outlined" - REDO = "redo" - REDO_SHARP = "redo_sharp" - REDO_ROUNDED = "redo_rounded" - REDO_OUTLINED = "redo_outlined" - REDUCE_CAPACITY = "reduce_capacity" - REDUCE_CAPACITY_SHARP = "reduce_capacity_sharp" - REDUCE_CAPACITY_ROUNDED = "reduce_capacity_rounded" - REDUCE_CAPACITY_OUTLINED = "reduce_capacity_outlined" - REFRESH = "refresh" - REFRESH_SHARP = "refresh_sharp" - REFRESH_ROUNDED = "refresh_rounded" - REFRESH_OUTLINED = "refresh_outlined" - REMEMBER_ME = "remember_me" - REMEMBER_ME_SHARP = "remember_me_sharp" - REMEMBER_ME_ROUNDED = "remember_me_rounded" - REMEMBER_ME_OUTLINED = "remember_me_outlined" - REMOVE = "remove" - REMOVE_SHARP = "remove_sharp" - REMOVE_ROUNDED = "remove_rounded" - REMOVE_OUTLINED = "remove_outlined" - REMOVE_CIRCLE = "remove_circle" - REMOVE_CIRCLE_SHARP = "remove_circle_sharp" - REMOVE_CIRCLE_ROUNDED = "remove_circle_rounded" - REMOVE_CIRCLE_OUTLINED = "remove_circle_outlined" - REMOVE_CIRCLE_OUTLINE = "remove_circle_outline" - REMOVE_CIRCLE_OUTLINE_SHARP = "remove_circle_outline_sharp" - REMOVE_CIRCLE_OUTLINE_ROUNDED = "remove_circle_outline_rounded" - REMOVE_CIRCLE_OUTLINE_OUTLINED = "remove_circle_outline_outlined" - REMOVE_DONE = "remove_done" - REMOVE_DONE_SHARP = "remove_done_sharp" - REMOVE_DONE_ROUNDED = "remove_done_rounded" - REMOVE_DONE_OUTLINED = "remove_done_outlined" - REMOVE_FROM_QUEUE = "remove_from_queue" - REMOVE_FROM_QUEUE_SHARP = "remove_from_queue_sharp" - REMOVE_FROM_QUEUE_ROUNDED = "remove_from_queue_rounded" - REMOVE_FROM_QUEUE_OUTLINED = "remove_from_queue_outlined" - REMOVE_MODERATOR = "remove_moderator" - REMOVE_MODERATOR_SHARP = "remove_moderator_sharp" - REMOVE_MODERATOR_ROUNDED = "remove_moderator_rounded" - REMOVE_MODERATOR_OUTLINED = "remove_moderator_outlined" - REMOVE_RED_EYE = "remove_red_eye" - REMOVE_RED_EYE_SHARP = "remove_red_eye_sharp" - REMOVE_RED_EYE_ROUNDED = "remove_red_eye_rounded" - REMOVE_RED_EYE_OUTLINED = "remove_red_eye_outlined" - REMOVE_ROAD = "remove_road" - REMOVE_ROAD_SHARP = "remove_road_sharp" - REMOVE_ROAD_ROUNDED = "remove_road_rounded" - REMOVE_ROAD_OUTLINED = "remove_road_outlined" - REMOVE_SHOPPING_CART = "remove_shopping_cart" - REMOVE_SHOPPING_CART_SHARP = "remove_shopping_cart_sharp" - REMOVE_SHOPPING_CART_ROUNDED = "remove_shopping_cart_rounded" - REMOVE_SHOPPING_CART_OUTLINED = "remove_shopping_cart_outlined" - REORDER = "reorder" - REORDER_SHARP = "reorder_sharp" - REORDER_ROUNDED = "reorder_rounded" - REORDER_OUTLINED = "reorder_outlined" - REPARTITION = "repartition" - REPARTITION_SHARP = "repartition_sharp" - REPARTITION_ROUNDED = "repartition_rounded" - REPARTITION_OUTLINED = "repartition_outlined" - REPEAT = "repeat" - REPEAT_SHARP = "repeat_sharp" - REPEAT_ROUNDED = "repeat_rounded" - REPEAT_OUTLINED = "repeat_outlined" - REPEAT_ON = "repeat_on" - REPEAT_ON_SHARP = "repeat_on_sharp" - REPEAT_ON_ROUNDED = "repeat_on_rounded" - REPEAT_ON_OUTLINED = "repeat_on_outlined" - REPEAT_ONE = "repeat_one" - REPEAT_ONE_SHARP = "repeat_one_sharp" - REPEAT_ONE_ROUNDED = "repeat_one_rounded" - REPEAT_ONE_OUTLINED = "repeat_one_outlined" - REPEAT_ONE_ON = "repeat_one_on" - REPEAT_ONE_ON_SHARP = "repeat_one_on_sharp" - REPEAT_ONE_ON_ROUNDED = "repeat_one_on_rounded" - REPEAT_ONE_ON_OUTLINED = "repeat_one_on_outlined" - REPLAY = "replay" - REPLAY_SHARP = "replay_sharp" - REPLAY_ROUNDED = "replay_rounded" - REPLAY_OUTLINED = "replay_outlined" - REPLAY_10 = "replay_10" - REPLAY_10_SHARP = "replay_10_sharp" - REPLAY_10_ROUNDED = "replay_10_rounded" - REPLAY_10_OUTLINED = "replay_10_outlined" - REPLAY_30 = "replay_30" - REPLAY_30_SHARP = "replay_30_sharp" - REPLAY_30_ROUNDED = "replay_30_rounded" - REPLAY_30_OUTLINED = "replay_30_outlined" - REPLAY_5 = "replay_5" - REPLAY_5_SHARP = "replay_5_sharp" - REPLAY_5_ROUNDED = "replay_5_rounded" - REPLAY_5_OUTLINED = "replay_5_outlined" - REPLAY_CIRCLE_FILLED = "replay_circle_filled" - REPLAY_CIRCLE_FILLED_SHARP = "replay_circle_filled_sharp" - REPLAY_CIRCLE_FILLED_ROUNDED = "replay_circle_filled_rounded" - REPLAY_CIRCLE_FILLED_OUTLINED = "replay_circle_filled_outlined" - REPLY = "reply" - REPLY_SHARP = "reply_sharp" - REPLY_ROUNDED = "reply_rounded" - REPLY_OUTLINED = "reply_outlined" - REPLY_ALL = "reply_all" - REPLY_ALL_SHARP = "reply_all_sharp" - REPLY_ALL_ROUNDED = "reply_all_rounded" - REPLY_ALL_OUTLINED = "reply_all_outlined" - REPORT = "report" - REPORT_SHARP = "report_sharp" - REPORT_ROUNDED = "report_rounded" - REPORT_OUTLINED = "report_outlined" - REPORT_GMAILERRORRED = "report_gmailerrorred" - REPORT_GMAILERRORRED_SHARP = "report_gmailerrorred_sharp" - REPORT_GMAILERRORRED_ROUNDED = "report_gmailerrorred_rounded" - REPORT_GMAILERRORRED_OUTLINED = "report_gmailerrorred_outlined" - REPORT_OFF = "report_off" - REPORT_OFF_SHARP = "report_off_sharp" - REPORT_OFF_ROUNDED = "report_off_rounded" - REPORT_OFF_OUTLINED = "report_off_outlined" - REPORT_PROBLEM = "report_problem" - REPORT_PROBLEM_SHARP = "report_problem_sharp" - REPORT_PROBLEM_ROUNDED = "report_problem_rounded" - REPORT_PROBLEM_OUTLINED = "report_problem_outlined" - REQUEST_PAGE = "request_page" - REQUEST_PAGE_SHARP = "request_page_sharp" - REQUEST_PAGE_ROUNDED = "request_page_rounded" - REQUEST_PAGE_OUTLINED = "request_page_outlined" - REQUEST_QUOTE = "request_quote" - REQUEST_QUOTE_SHARP = "request_quote_sharp" - REQUEST_QUOTE_ROUNDED = "request_quote_rounded" - REQUEST_QUOTE_OUTLINED = "request_quote_outlined" - RESET_TV = "reset_tv" - RESET_TV_SHARP = "reset_tv_sharp" - RESET_TV_ROUNDED = "reset_tv_rounded" - RESET_TV_OUTLINED = "reset_tv_outlined" - RESTART_ALT = "restart_alt" - RESTART_ALT_SHARP = "restart_alt_sharp" - RESTART_ALT_ROUNDED = "restart_alt_rounded" - RESTART_ALT_OUTLINED = "restart_alt_outlined" - RESTAURANT = "restaurant" - RESTAURANT_SHARP = "restaurant_sharp" - RESTAURANT_ROUNDED = "restaurant_rounded" - RESTAURANT_OUTLINED = "restaurant_outlined" - RESTAURANT_MENU = "restaurant_menu" - RESTAURANT_MENU_SHARP = "restaurant_menu_sharp" - RESTAURANT_MENU_ROUNDED = "restaurant_menu_rounded" - RESTAURANT_MENU_OUTLINED = "restaurant_menu_outlined" - RESTORE = "restore" - RESTORE_SHARP = "restore_sharp" - RESTORE_ROUNDED = "restore_rounded" - RESTORE_OUTLINED = "restore_outlined" - RESTORE_FROM_TRASH = "restore_from_trash" - RESTORE_FROM_TRASH_SHARP = "restore_from_trash_sharp" - RESTORE_FROM_TRASH_ROUNDED = "restore_from_trash_rounded" - RESTORE_FROM_TRASH_OUTLINED = "restore_from_trash_outlined" - RESTORE_PAGE = "restore_page" - RESTORE_PAGE_SHARP = "restore_page_sharp" - RESTORE_PAGE_ROUNDED = "restore_page_rounded" - RESTORE_PAGE_OUTLINED = "restore_page_outlined" - REVIEWS = "reviews" - REVIEWS_SHARP = "reviews_sharp" - REVIEWS_ROUNDED = "reviews_rounded" - REVIEWS_OUTLINED = "reviews_outlined" - RICE_BOWL = "rice_bowl" - RICE_BOWL_SHARP = "rice_bowl_sharp" - RICE_BOWL_ROUNDED = "rice_bowl_rounded" - RICE_BOWL_OUTLINED = "rice_bowl_outlined" - RING_VOLUME = "ring_volume" - RING_VOLUME_SHARP = "ring_volume_sharp" - RING_VOLUME_ROUNDED = "ring_volume_rounded" - RING_VOLUME_OUTLINED = "ring_volume_outlined" - ROCKET = "rocket" - ROCKET_SHARP = "rocket_sharp" - ROCKET_ROUNDED = "rocket_rounded" - ROCKET_OUTLINED = "rocket_outlined" - ROCKET_LAUNCH = "rocket_launch" - ROCKET_LAUNCH_SHARP = "rocket_launch_sharp" - ROCKET_LAUNCH_ROUNDED = "rocket_launch_rounded" - ROCKET_LAUNCH_OUTLINED = "rocket_launch_outlined" - ROLLER_SHADES = "roller_shades" - ROLLER_SHADES_SHARP = "roller_shades_sharp" - ROLLER_SHADES_ROUNDED = "roller_shades_rounded" - ROLLER_SHADES_OUTLINED = "roller_shades_outlined" - ROLLER_SHADES_CLOSED = "roller_shades_closed" - ROLLER_SHADES_CLOSED_SHARP = "roller_shades_closed_sharp" - ROLLER_SHADES_CLOSED_ROUNDED = "roller_shades_closed_rounded" - ROLLER_SHADES_CLOSED_OUTLINED = "roller_shades_closed_outlined" - ROLLER_SKATING = "roller_skating" - ROLLER_SKATING_SHARP = "roller_skating_sharp" - ROLLER_SKATING_ROUNDED = "roller_skating_rounded" - ROLLER_SKATING_OUTLINED = "roller_skating_outlined" - ROOFING = "roofing" - ROOFING_SHARP = "roofing_sharp" - ROOFING_ROUNDED = "roofing_rounded" - ROOFING_OUTLINED = "roofing_outlined" - ROOM = "room" - ROOM_SHARP = "room_sharp" - ROOM_ROUNDED = "room_rounded" - ROOM_OUTLINED = "room_outlined" - ROOM_PREFERENCES = "room_preferences" - ROOM_PREFERENCES_SHARP = "room_preferences_sharp" - ROOM_PREFERENCES_ROUNDED = "room_preferences_rounded" - ROOM_PREFERENCES_OUTLINED = "room_preferences_outlined" - ROOM_SERVICE = "room_service" - ROOM_SERVICE_SHARP = "room_service_sharp" - ROOM_SERVICE_ROUNDED = "room_service_rounded" - ROOM_SERVICE_OUTLINED = "room_service_outlined" - ROTATE_90_DEGREES_CCW = "rotate_90_degrees_ccw" - ROTATE_90_DEGREES_CCW_SHARP = "rotate_90_degrees_ccw_sharp" - ROTATE_90_DEGREES_CCW_ROUNDED = "rotate_90_degrees_ccw_rounded" - ROTATE_90_DEGREES_CCW_OUTLINED = "rotate_90_degrees_ccw_outlined" - ROTATE_90_DEGREES_CW = "rotate_90_degrees_cw" - ROTATE_90_DEGREES_CW_SHARP = "rotate_90_degrees_cw_sharp" - ROTATE_90_DEGREES_CW_ROUNDED = "rotate_90_degrees_cw_rounded" - ROTATE_90_DEGREES_CW_OUTLINED = "rotate_90_degrees_cw_outlined" - ROTATE_LEFT = "rotate_left" - ROTATE_LEFT_SHARP = "rotate_left_sharp" - ROTATE_LEFT_ROUNDED = "rotate_left_rounded" - ROTATE_LEFT_OUTLINED = "rotate_left_outlined" - ROTATE_RIGHT = "rotate_right" - ROTATE_RIGHT_SHARP = "rotate_right_sharp" - ROTATE_RIGHT_ROUNDED = "rotate_right_rounded" - ROTATE_RIGHT_OUTLINED = "rotate_right_outlined" - ROUNDABOUT_LEFT = "roundabout_left" - ROUNDABOUT_LEFT_SHARP = "roundabout_left_sharp" - ROUNDABOUT_LEFT_ROUNDED = "roundabout_left_rounded" - ROUNDABOUT_LEFT_OUTLINED = "roundabout_left_outlined" - ROUNDABOUT_RIGHT = "roundabout_right" - ROUNDABOUT_RIGHT_SHARP = "roundabout_right_sharp" - ROUNDABOUT_RIGHT_ROUNDED = "roundabout_right_rounded" - ROUNDABOUT_RIGHT_OUTLINED = "roundabout_right_outlined" - ROUNDED_CORNER = "rounded_corner" - ROUNDED_CORNER_SHARP = "rounded_corner_sharp" - ROUNDED_CORNER_ROUNDED = "rounded_corner_rounded" - ROUNDED_CORNER_OUTLINED = "rounded_corner_outlined" - ROUTE = "route" - ROUTE_SHARP = "route_sharp" - ROUTE_ROUNDED = "route_rounded" - ROUTE_OUTLINED = "route_outlined" - ROUTER = "router" - ROUTER_SHARP = "router_sharp" - ROUTER_ROUNDED = "router_rounded" - ROUTER_OUTLINED = "router_outlined" - ROWING = "rowing" - ROWING_SHARP = "rowing_sharp" - ROWING_ROUNDED = "rowing_rounded" - ROWING_OUTLINED = "rowing_outlined" - RSS_FEED = "rss_feed" - RSS_FEED_SHARP = "rss_feed_sharp" - RSS_FEED_ROUNDED = "rss_feed_rounded" - RSS_FEED_OUTLINED = "rss_feed_outlined" - RSVP = "rsvp" - RSVP_SHARP = "rsvp_sharp" - RSVP_ROUNDED = "rsvp_rounded" - RSVP_OUTLINED = "rsvp_outlined" - RTT = "rtt" - RTT_SHARP = "rtt_sharp" - RTT_ROUNDED = "rtt_rounded" - RTT_OUTLINED = "rtt_outlined" - RULE = "rule" - RULE_SHARP = "rule_sharp" - RULE_ROUNDED = "rule_rounded" - RULE_OUTLINED = "rule_outlined" - RULE_FOLDER = "rule_folder" - RULE_FOLDER_SHARP = "rule_folder_sharp" - RULE_FOLDER_ROUNDED = "rule_folder_rounded" - RULE_FOLDER_OUTLINED = "rule_folder_outlined" - RUN_CIRCLE = "run_circle" - RUN_CIRCLE_SHARP = "run_circle_sharp" - RUN_CIRCLE_ROUNDED = "run_circle_rounded" - RUN_CIRCLE_OUTLINED = "run_circle_outlined" - RUNNING_WITH_ERRORS = "running_with_errors" - RUNNING_WITH_ERRORS_SHARP = "running_with_errors_sharp" - RUNNING_WITH_ERRORS_ROUNDED = "running_with_errors_rounded" - RUNNING_WITH_ERRORS_OUTLINED = "running_with_errors_outlined" - RV_HOOKUP = "rv_hookup" - RV_HOOKUP_SHARP = "rv_hookup_sharp" - RV_HOOKUP_ROUNDED = "rv_hookup_rounded" - RV_HOOKUP_OUTLINED = "rv_hookup_outlined" - SAFETY_CHECK = "safety_check" - SAFETY_CHECK_SHARP = "safety_check_sharp" - SAFETY_CHECK_ROUNDED = "safety_check_rounded" - SAFETY_CHECK_OUTLINED = "safety_check_outlined" - SAFETY_DIVIDER = "safety_divider" - SAFETY_DIVIDER_SHARP = "safety_divider_sharp" - SAFETY_DIVIDER_ROUNDED = "safety_divider_rounded" - SAFETY_DIVIDER_OUTLINED = "safety_divider_outlined" - SAILING = "sailing" - SAILING_SHARP = "sailing_sharp" - SAILING_ROUNDED = "sailing_rounded" - SAILING_OUTLINED = "sailing_outlined" - SANITIZER = "sanitizer" - SANITIZER_SHARP = "sanitizer_sharp" - SANITIZER_ROUNDED = "sanitizer_rounded" - SANITIZER_OUTLINED = "sanitizer_outlined" - SATELLITE = "satellite" - SATELLITE_SHARP = "satellite_sharp" - SATELLITE_ROUNDED = "satellite_rounded" - SATELLITE_OUTLINED = "satellite_outlined" - SATELLITE_ALT = "satellite_alt" - SATELLITE_ALT_SHARP = "satellite_alt_sharp" - SATELLITE_ALT_ROUNDED = "satellite_alt_rounded" - SATELLITE_ALT_OUTLINED = "satellite_alt_outlined" - SAVE = "save" - SAVE_SHARP = "save_sharp" - SAVE_ROUNDED = "save_rounded" - SAVE_OUTLINED = "save_outlined" - SAVE_ALT = "save_alt" - SAVE_ALT_SHARP = "save_alt_sharp" - SAVE_ALT_ROUNDED = "save_alt_rounded" - SAVE_ALT_OUTLINED = "save_alt_outlined" - SAVE_AS = "save_as" - SAVE_AS_SHARP = "save_as_sharp" - SAVE_AS_ROUNDED = "save_as_rounded" - SAVE_AS_OUTLINED = "save_as_outlined" - SAVED_SEARCH = "saved_search" - SAVED_SEARCH_SHARP = "saved_search_sharp" - SAVED_SEARCH_ROUNDED = "saved_search_rounded" - SAVED_SEARCH_OUTLINED = "saved_search_outlined" - SAVINGS = "savings" - SAVINGS_SHARP = "savings_sharp" - SAVINGS_ROUNDED = "savings_rounded" - SAVINGS_OUTLINED = "savings_outlined" - SCALE = "scale" - SCALE_SHARP = "scale_sharp" - SCALE_ROUNDED = "scale_rounded" - SCALE_OUTLINED = "scale_outlined" - SCANNER = "scanner" - SCANNER_SHARP = "scanner_sharp" - SCANNER_ROUNDED = "scanner_rounded" - SCANNER_OUTLINED = "scanner_outlined" - SCATTER_PLOT = "scatter_plot" - SCATTER_PLOT_SHARP = "scatter_plot_sharp" - SCATTER_PLOT_ROUNDED = "scatter_plot_rounded" - SCATTER_PLOT_OUTLINED = "scatter_plot_outlined" - SCHEDULE = "schedule" - SCHEDULE_SHARP = "schedule_sharp" - SCHEDULE_ROUNDED = "schedule_rounded" - SCHEDULE_OUTLINED = "schedule_outlined" - SCHEDULE_SEND = "schedule_send" - SCHEDULE_SEND_SHARP = "schedule_send_sharp" - SCHEDULE_SEND_ROUNDED = "schedule_send_rounded" - SCHEDULE_SEND_OUTLINED = "schedule_send_outlined" - SCHEMA = "schema" - SCHEMA_SHARP = "schema_sharp" - SCHEMA_ROUNDED = "schema_rounded" - SCHEMA_OUTLINED = "schema_outlined" - SCHOOL = "school" - SCHOOL_SHARP = "school_sharp" - SCHOOL_ROUNDED = "school_rounded" - SCHOOL_OUTLINED = "school_outlined" - SCIENCE = "science" - SCIENCE_SHARP = "science_sharp" - SCIENCE_ROUNDED = "science_rounded" - SCIENCE_OUTLINED = "science_outlined" - SCORE = "score" - SCORE_SHARP = "score_sharp" - SCORE_ROUNDED = "score_rounded" - SCORE_OUTLINED = "score_outlined" - SCOREBOARD = "scoreboard" - SCOREBOARD_SHARP = "scoreboard_sharp" - SCOREBOARD_ROUNDED = "scoreboard_rounded" - SCOREBOARD_OUTLINED = "scoreboard_outlined" - SCREEN_LOCK_LANDSCAPE = "screen_lock_landscape" - SCREEN_LOCK_LANDSCAPE_SHARP = "screen_lock_landscape_sharp" - SCREEN_LOCK_LANDSCAPE_ROUNDED = "screen_lock_landscape_rounded" - SCREEN_LOCK_LANDSCAPE_OUTLINED = "screen_lock_landscape_outlined" - SCREEN_LOCK_PORTRAIT = "screen_lock_portrait" - SCREEN_LOCK_PORTRAIT_SHARP = "screen_lock_portrait_sharp" - SCREEN_LOCK_PORTRAIT_ROUNDED = "screen_lock_portrait_rounded" - SCREEN_LOCK_PORTRAIT_OUTLINED = "screen_lock_portrait_outlined" - SCREEN_LOCK_ROTATION = "screen_lock_rotation" - SCREEN_LOCK_ROTATION_SHARP = "screen_lock_rotation_sharp" - SCREEN_LOCK_ROTATION_ROUNDED = "screen_lock_rotation_rounded" - SCREEN_LOCK_ROTATION_OUTLINED = "screen_lock_rotation_outlined" - SCREEN_ROTATION = "screen_rotation" - SCREEN_ROTATION_SHARP = "screen_rotation_sharp" - SCREEN_ROTATION_ROUNDED = "screen_rotation_rounded" - SCREEN_ROTATION_OUTLINED = "screen_rotation_outlined" - SCREEN_ROTATION_ALT = "screen_rotation_alt" - SCREEN_ROTATION_ALT_SHARP = "screen_rotation_alt_sharp" - SCREEN_ROTATION_ALT_ROUNDED = "screen_rotation_alt_rounded" - SCREEN_ROTATION_ALT_OUTLINED = "screen_rotation_alt_outlined" - SCREEN_SEARCH_DESKTOP = "screen_search_desktop" - SCREEN_SEARCH_DESKTOP_SHARP = "screen_search_desktop_sharp" - SCREEN_SEARCH_DESKTOP_ROUNDED = "screen_search_desktop_rounded" - SCREEN_SEARCH_DESKTOP_OUTLINED = "screen_search_desktop_outlined" - SCREEN_SHARE = "screen_share" - SCREEN_SHARE_SHARP = "screen_share_sharp" - SCREEN_SHARE_ROUNDED = "screen_share_rounded" - SCREEN_SHARE_OUTLINED = "screen_share_outlined" - SCREENSHOT = "screenshot" - SCREENSHOT_SHARP = "screenshot_sharp" - SCREENSHOT_ROUNDED = "screenshot_rounded" - SCREENSHOT_OUTLINED = "screenshot_outlined" - SCREENSHOT_MONITOR = "screenshot_monitor" - SCREENSHOT_MONITOR_SHARP = "screenshot_monitor_sharp" - SCREENSHOT_MONITOR_ROUNDED = "screenshot_monitor_rounded" - SCREENSHOT_MONITOR_OUTLINED = "screenshot_monitor_outlined" - SCUBA_DIVING = "scuba_diving" - SCUBA_DIVING_SHARP = "scuba_diving_sharp" - SCUBA_DIVING_ROUNDED = "scuba_diving_rounded" - SCUBA_DIVING_OUTLINED = "scuba_diving_outlined" - SD = "sd" - SD_SHARP = "sd_sharp" - SD_ROUNDED = "sd_rounded" - SD_OUTLINED = "sd_outlined" - SD_CARD = "sd_card" - SD_CARD_SHARP = "sd_card_sharp" - SD_CARD_ROUNDED = "sd_card_rounded" - SD_CARD_OUTLINED = "sd_card_outlined" - SD_CARD_ALERT = "sd_card_alert" - SD_CARD_ALERT_SHARP = "sd_card_alert_sharp" - SD_CARD_ALERT_ROUNDED = "sd_card_alert_rounded" - SD_CARD_ALERT_OUTLINED = "sd_card_alert_outlined" - SD_STORAGE = "sd_storage" - SD_STORAGE_SHARP = "sd_storage_sharp" - SD_STORAGE_ROUNDED = "sd_storage_rounded" - SD_STORAGE_OUTLINED = "sd_storage_outlined" - SEARCH = "search" - SEARCH_SHARP = "search_sharp" - SEARCH_ROUNDED = "search_rounded" - SEARCH_OUTLINED = "search_outlined" - SEARCH_OFF = "search_off" - SEARCH_OFF_SHARP = "search_off_sharp" - SEARCH_OFF_ROUNDED = "search_off_rounded" - SEARCH_OFF_OUTLINED = "search_off_outlined" - SECURITY = "security" - SECURITY_SHARP = "security_sharp" - SECURITY_ROUNDED = "security_rounded" - SECURITY_OUTLINED = "security_outlined" - SECURITY_UPDATE = "security_update" - SECURITY_UPDATE_SHARP = "security_update_sharp" - SECURITY_UPDATE_ROUNDED = "security_update_rounded" - SECURITY_UPDATE_OUTLINED = "security_update_outlined" - SECURITY_UPDATE_GOOD = "security_update_good" - SECURITY_UPDATE_GOOD_SHARP = "security_update_good_sharp" - SECURITY_UPDATE_GOOD_ROUNDED = "security_update_good_rounded" - SECURITY_UPDATE_GOOD_OUTLINED = "security_update_good_outlined" - SECURITY_UPDATE_WARNING = "security_update_warning" - SECURITY_UPDATE_WARNING_SHARP = "security_update_warning_sharp" - SECURITY_UPDATE_WARNING_ROUNDED = "security_update_warning_rounded" - SECURITY_UPDATE_WARNING_OUTLINED = "security_update_warning_outlined" - SEGMENT = "segment" - SEGMENT_SHARP = "segment_sharp" - SEGMENT_ROUNDED = "segment_rounded" - SEGMENT_OUTLINED = "segment_outlined" - SELECT_ALL = "select_all" - SELECT_ALL_SHARP = "select_all_sharp" - SELECT_ALL_ROUNDED = "select_all_rounded" - SELECT_ALL_OUTLINED = "select_all_outlined" - SELF_IMPROVEMENT = "self_improvement" - SELF_IMPROVEMENT_SHARP = "self_improvement_sharp" - SELF_IMPROVEMENT_ROUNDED = "self_improvement_rounded" - SELF_IMPROVEMENT_OUTLINED = "self_improvement_outlined" - SELL = "sell" - SELL_SHARP = "sell_sharp" - SELL_ROUNDED = "sell_rounded" - SELL_OUTLINED = "sell_outlined" - SEND = "send" - SEND_SHARP = "send_sharp" - SEND_ROUNDED = "send_rounded" - SEND_OUTLINED = "send_outlined" - SEND_AND_ARCHIVE = "send_and_archive" - SEND_AND_ARCHIVE_SHARP = "send_and_archive_sharp" - SEND_AND_ARCHIVE_ROUNDED = "send_and_archive_rounded" - SEND_AND_ARCHIVE_OUTLINED = "send_and_archive_outlined" - SEND_TIME_EXTENSION = "send_time_extension" - SEND_TIME_EXTENSION_SHARP = "send_time_extension_sharp" - SEND_TIME_EXTENSION_ROUNDED = "send_time_extension_rounded" - SEND_TIME_EXTENSION_OUTLINED = "send_time_extension_outlined" - SEND_TO_MOBILE = "send_to_mobile" - SEND_TO_MOBILE_SHARP = "send_to_mobile_sharp" - SEND_TO_MOBILE_ROUNDED = "send_to_mobile_rounded" - SEND_TO_MOBILE_OUTLINED = "send_to_mobile_outlined" - SENSOR_DOOR = "sensor_door" - SENSOR_DOOR_SHARP = "sensor_door_sharp" - SENSOR_DOOR_ROUNDED = "sensor_door_rounded" - SENSOR_DOOR_OUTLINED = "sensor_door_outlined" - SENSOR_OCCUPIED = "sensor_occupied" - SENSOR_OCCUPIED_SHARP = "sensor_occupied_sharp" - SENSOR_OCCUPIED_ROUNDED = "sensor_occupied_rounded" - SENSOR_OCCUPIED_OUTLINED = "sensor_occupied_outlined" - SENSOR_WINDOW = "sensor_window" - SENSOR_WINDOW_SHARP = "sensor_window_sharp" - SENSOR_WINDOW_ROUNDED = "sensor_window_rounded" - SENSOR_WINDOW_OUTLINED = "sensor_window_outlined" - SENSORS = "sensors" - SENSORS_SHARP = "sensors_sharp" - SENSORS_ROUNDED = "sensors_rounded" - SENSORS_OUTLINED = "sensors_outlined" - SENSORS_OFF = "sensors_off" - SENSORS_OFF_SHARP = "sensors_off_sharp" - SENSORS_OFF_ROUNDED = "sensors_off_rounded" - SENSORS_OFF_OUTLINED = "sensors_off_outlined" - SENTIMENT_DISSATISFIED = "sentiment_dissatisfied" - SENTIMENT_DISSATISFIED_SHARP = "sentiment_dissatisfied_sharp" - SENTIMENT_DISSATISFIED_ROUNDED = "sentiment_dissatisfied_rounded" - SENTIMENT_DISSATISFIED_OUTLINED = "sentiment_dissatisfied_outlined" - SENTIMENT_NEUTRAL = "sentiment_neutral" - SENTIMENT_NEUTRAL_SHARP = "sentiment_neutral_sharp" - SENTIMENT_NEUTRAL_ROUNDED = "sentiment_neutral_rounded" - SENTIMENT_NEUTRAL_OUTLINED = "sentiment_neutral_outlined" - SENTIMENT_SATISFIED = "sentiment_satisfied" - SENTIMENT_SATISFIED_SHARP = "sentiment_satisfied_sharp" - SENTIMENT_SATISFIED_ROUNDED = "sentiment_satisfied_rounded" - SENTIMENT_SATISFIED_OUTLINED = "sentiment_satisfied_outlined" - SENTIMENT_SATISFIED_ALT = "sentiment_satisfied_alt" - SENTIMENT_SATISFIED_ALT_SHARP = "sentiment_satisfied_alt_sharp" - SENTIMENT_SATISFIED_ALT_ROUNDED = "sentiment_satisfied_alt_rounded" - SENTIMENT_SATISFIED_ALT_OUTLINED = "sentiment_satisfied_alt_outlined" - SENTIMENT_VERY_DISSATISFIED = "sentiment_very_dissatisfied" - SENTIMENT_VERY_DISSATISFIED_SHARP = "sentiment_very_dissatisfied_sharp" - SENTIMENT_VERY_DISSATISFIED_ROUNDED = "sentiment_very_dissatisfied_rounded" - SENTIMENT_VERY_DISSATISFIED_OUTLINED = "sentiment_very_dissatisfied_outlined" - SENTIMENT_VERY_SATISFIED = "sentiment_very_satisfied" - SENTIMENT_VERY_SATISFIED_SHARP = "sentiment_very_satisfied_sharp" - SENTIMENT_VERY_SATISFIED_ROUNDED = "sentiment_very_satisfied_rounded" - SENTIMENT_VERY_SATISFIED_OUTLINED = "sentiment_very_satisfied_outlined" - SET_MEAL = "set_meal" - SET_MEAL_SHARP = "set_meal_sharp" - SET_MEAL_ROUNDED = "set_meal_rounded" - SET_MEAL_OUTLINED = "set_meal_outlined" - SETTINGS = "settings" - SETTINGS_SHARP = "settings_sharp" - SETTINGS_ROUNDED = "settings_rounded" - SETTINGS_OUTLINED = "settings_outlined" - SETTINGS_ACCESSIBILITY = "settings_accessibility" - SETTINGS_ACCESSIBILITY_SHARP = "settings_accessibility_sharp" - SETTINGS_ACCESSIBILITY_ROUNDED = "settings_accessibility_rounded" - SETTINGS_ACCESSIBILITY_OUTLINED = "settings_accessibility_outlined" - SETTINGS_APPLICATIONS = "settings_applications" - SETTINGS_APPLICATIONS_SHARP = "settings_applications_sharp" - SETTINGS_APPLICATIONS_ROUNDED = "settings_applications_rounded" - SETTINGS_APPLICATIONS_OUTLINED = "settings_applications_outlined" - SETTINGS_BACKUP_RESTORE = "settings_backup_restore" - SETTINGS_BACKUP_RESTORE_SHARP = "settings_backup_restore_sharp" - SETTINGS_BACKUP_RESTORE_ROUNDED = "settings_backup_restore_rounded" - SETTINGS_BACKUP_RESTORE_OUTLINED = "settings_backup_restore_outlined" - SETTINGS_BLUETOOTH = "settings_bluetooth" - SETTINGS_BLUETOOTH_SHARP = "settings_bluetooth_sharp" - SETTINGS_BLUETOOTH_ROUNDED = "settings_bluetooth_rounded" - SETTINGS_BLUETOOTH_OUTLINED = "settings_bluetooth_outlined" - SETTINGS_BRIGHTNESS = "settings_brightness" - SETTINGS_BRIGHTNESS_SHARP = "settings_brightness_sharp" - SETTINGS_BRIGHTNESS_ROUNDED = "settings_brightness_rounded" - SETTINGS_BRIGHTNESS_OUTLINED = "settings_brightness_outlined" - SETTINGS_CELL = "settings_cell" - SETTINGS_CELL_SHARP = "settings_cell_sharp" - SETTINGS_CELL_ROUNDED = "settings_cell_rounded" - SETTINGS_CELL_OUTLINED = "settings_cell_outlined" - SETTINGS_DISPLAY = "settings_display" - SETTINGS_DISPLAY_SHARP = "settings_display_sharp" - SETTINGS_DISPLAY_ROUNDED = "settings_display_rounded" - SETTINGS_DISPLAY_OUTLINED = "settings_display_outlined" - SETTINGS_ETHERNET = "settings_ethernet" - SETTINGS_ETHERNET_SHARP = "settings_ethernet_sharp" - SETTINGS_ETHERNET_ROUNDED = "settings_ethernet_rounded" - SETTINGS_ETHERNET_OUTLINED = "settings_ethernet_outlined" - SETTINGS_INPUT_ANTENNA = "settings_input_antenna" - SETTINGS_INPUT_ANTENNA_SHARP = "settings_input_antenna_sharp" - SETTINGS_INPUT_ANTENNA_ROUNDED = "settings_input_antenna_rounded" - SETTINGS_INPUT_ANTENNA_OUTLINED = "settings_input_antenna_outlined" - SETTINGS_INPUT_COMPONENT = "settings_input_component" - SETTINGS_INPUT_COMPONENT_SHARP = "settings_input_component_sharp" - SETTINGS_INPUT_COMPONENT_ROUNDED = "settings_input_component_rounded" - SETTINGS_INPUT_COMPONENT_OUTLINED = "settings_input_component_outlined" - SETTINGS_INPUT_COMPOSITE = "settings_input_composite" - SETTINGS_INPUT_COMPOSITE_SHARP = "settings_input_composite_sharp" - SETTINGS_INPUT_COMPOSITE_ROUNDED = "settings_input_composite_rounded" - SETTINGS_INPUT_COMPOSITE_OUTLINED = "settings_input_composite_outlined" - SETTINGS_INPUT_HDMI = "settings_input_hdmi" - SETTINGS_INPUT_HDMI_SHARP = "settings_input_hdmi_sharp" - SETTINGS_INPUT_HDMI_ROUNDED = "settings_input_hdmi_rounded" - SETTINGS_INPUT_HDMI_OUTLINED = "settings_input_hdmi_outlined" - SETTINGS_INPUT_SVIDEO = "settings_input_svideo" - SETTINGS_INPUT_SVIDEO_SHARP = "settings_input_svideo_sharp" - SETTINGS_INPUT_SVIDEO_ROUNDED = "settings_input_svideo_rounded" - SETTINGS_INPUT_SVIDEO_OUTLINED = "settings_input_svideo_outlined" - SETTINGS_OVERSCAN = "settings_overscan" - SETTINGS_OVERSCAN_SHARP = "settings_overscan_sharp" - SETTINGS_OVERSCAN_ROUNDED = "settings_overscan_rounded" - SETTINGS_OVERSCAN_OUTLINED = "settings_overscan_outlined" - SETTINGS_PHONE = "settings_phone" - SETTINGS_PHONE_SHARP = "settings_phone_sharp" - SETTINGS_PHONE_ROUNDED = "settings_phone_rounded" - SETTINGS_PHONE_OUTLINED = "settings_phone_outlined" - SETTINGS_POWER = "settings_power" - SETTINGS_POWER_SHARP = "settings_power_sharp" - SETTINGS_POWER_ROUNDED = "settings_power_rounded" - SETTINGS_POWER_OUTLINED = "settings_power_outlined" - SETTINGS_REMOTE = "settings_remote" - SETTINGS_REMOTE_SHARP = "settings_remote_sharp" - SETTINGS_REMOTE_ROUNDED = "settings_remote_rounded" - SETTINGS_REMOTE_OUTLINED = "settings_remote_outlined" - SETTINGS_SUGGEST = "settings_suggest" - SETTINGS_SUGGEST_SHARP = "settings_suggest_sharp" - SETTINGS_SUGGEST_ROUNDED = "settings_suggest_rounded" - SETTINGS_SUGGEST_OUTLINED = "settings_suggest_outlined" - SETTINGS_SYSTEM_DAYDREAM = "settings_system_daydream" - SETTINGS_SYSTEM_DAYDREAM_SHARP = "settings_system_daydream_sharp" - SETTINGS_SYSTEM_DAYDREAM_ROUNDED = "settings_system_daydream_rounded" - SETTINGS_SYSTEM_DAYDREAM_OUTLINED = "settings_system_daydream_outlined" - SETTINGS_VOICE = "settings_voice" - SETTINGS_VOICE_SHARP = "settings_voice_sharp" - SETTINGS_VOICE_ROUNDED = "settings_voice_rounded" - SETTINGS_VOICE_OUTLINED = "settings_voice_outlined" - SEVERE_COLD = "severe_cold" - SEVERE_COLD_SHARP = "severe_cold_sharp" - SEVERE_COLD_ROUNDED = "severe_cold_rounded" - SEVERE_COLD_OUTLINED = "severe_cold_outlined" - SHAPE_LINE = "shape_line" - SHAPE_LINE_SHARP = "shape_line_sharp" - SHAPE_LINE_ROUNDED = "shape_line_rounded" - SHAPE_LINE_OUTLINED = "shape_line_outlined" - SHARE = "share" - SHARE_SHARP = "share_sharp" - SHARE_ROUNDED = "share_rounded" - SHARE_OUTLINED = "share_outlined" - SHARE_ARRIVAL_TIME = "share_arrival_time" - SHARE_ARRIVAL_TIME_SHARP = "share_arrival_time_sharp" - SHARE_ARRIVAL_TIME_ROUNDED = "share_arrival_time_rounded" - SHARE_ARRIVAL_TIME_OUTLINED = "share_arrival_time_outlined" - SHARE_LOCATION = "share_location" - SHARE_LOCATION_SHARP = "share_location_sharp" - SHARE_LOCATION_ROUNDED = "share_location_rounded" - SHARE_LOCATION_OUTLINED = "share_location_outlined" - SHELVES = "shelves" - SHIELD = "shield" - SHIELD_SHARP = "shield_sharp" - SHIELD_ROUNDED = "shield_rounded" - SHIELD_OUTLINED = "shield_outlined" - SHIELD_MOON = "shield_moon" - SHIELD_MOON_SHARP = "shield_moon_sharp" - SHIELD_MOON_ROUNDED = "shield_moon_rounded" - SHIELD_MOON_OUTLINED = "shield_moon_outlined" - SHOP = "shop" - SHOP_SHARP = "shop_sharp" - SHOP_ROUNDED = "shop_rounded" - SHOP_OUTLINED = "shop_outlined" - SHOP_2 = "shop_2" - SHOP_2_SHARP = "shop_2_sharp" - SHOP_2_ROUNDED = "shop_2_rounded" - SHOP_2_OUTLINED = "shop_2_outlined" - SHOP_TWO = "shop_two" - SHOP_TWO_SHARP = "shop_two_sharp" - SHOP_TWO_ROUNDED = "shop_two_rounded" - SHOP_TWO_OUTLINED = "shop_two_outlined" - SHOPIFY = "shopify" - SHOPIFY_SHARP = "shopify_sharp" - SHOPIFY_ROUNDED = "shopify_rounded" - SHOPIFY_OUTLINED = "shopify_outlined" - SHOPPING_BAG = "shopping_bag" - SHOPPING_BAG_SHARP = "shopping_bag_sharp" - SHOPPING_BAG_ROUNDED = "shopping_bag_rounded" - SHOPPING_BAG_OUTLINED = "shopping_bag_outlined" - SHOPPING_BASKET = "shopping_basket" - SHOPPING_BASKET_SHARP = "shopping_basket_sharp" - SHOPPING_BASKET_ROUNDED = "shopping_basket_rounded" - SHOPPING_BASKET_OUTLINED = "shopping_basket_outlined" - SHOPPING_CART = "shopping_cart" - SHOPPING_CART_SHARP = "shopping_cart_sharp" - SHOPPING_CART_ROUNDED = "shopping_cart_rounded" - SHOPPING_CART_OUTLINED = "shopping_cart_outlined" - SHOPPING_CART_CHECKOUT = "shopping_cart_checkout" - SHOPPING_CART_CHECKOUT_SHARP = "shopping_cart_checkout_sharp" - SHOPPING_CART_CHECKOUT_ROUNDED = "shopping_cart_checkout_rounded" - SHOPPING_CART_CHECKOUT_OUTLINED = "shopping_cart_checkout_outlined" - SHORT_TEXT = "short_text" - SHORT_TEXT_SHARP = "short_text_sharp" - SHORT_TEXT_ROUNDED = "short_text_rounded" - SHORT_TEXT_OUTLINED = "short_text_outlined" - SHORTCUT = "shortcut" - SHORTCUT_SHARP = "shortcut_sharp" - SHORTCUT_ROUNDED = "shortcut_rounded" - SHORTCUT_OUTLINED = "shortcut_outlined" - SHOW_CHART = "show_chart" - SHOW_CHART_SHARP = "show_chart_sharp" - SHOW_CHART_ROUNDED = "show_chart_rounded" - SHOW_CHART_OUTLINED = "show_chart_outlined" - SHOWER = "shower" - SHOWER_SHARP = "shower_sharp" - SHOWER_ROUNDED = "shower_rounded" - SHOWER_OUTLINED = "shower_outlined" - SHUFFLE = "shuffle" - SHUFFLE_SHARP = "shuffle_sharp" - SHUFFLE_ROUNDED = "shuffle_rounded" - SHUFFLE_OUTLINED = "shuffle_outlined" - SHUFFLE_ON = "shuffle_on" - SHUFFLE_ON_SHARP = "shuffle_on_sharp" - SHUFFLE_ON_ROUNDED = "shuffle_on_rounded" - SHUFFLE_ON_OUTLINED = "shuffle_on_outlined" - SHUTTER_SPEED = "shutter_speed" - SHUTTER_SPEED_SHARP = "shutter_speed_sharp" - SHUTTER_SPEED_ROUNDED = "shutter_speed_rounded" - SHUTTER_SPEED_OUTLINED = "shutter_speed_outlined" - SICK = "sick" - SICK_SHARP = "sick_sharp" - SICK_ROUNDED = "sick_rounded" - SICK_OUTLINED = "sick_outlined" - SIGN_LANGUAGE = "sign_language" - SIGN_LANGUAGE_SHARP = "sign_language_sharp" - SIGN_LANGUAGE_ROUNDED = "sign_language_rounded" - SIGN_LANGUAGE_OUTLINED = "sign_language_outlined" - SIGNAL_CELLULAR_0_BAR = "signal_cellular_0_bar" - SIGNAL_CELLULAR_0_BAR_SHARP = "signal_cellular_0_bar_sharp" - SIGNAL_CELLULAR_0_BAR_ROUNDED = "signal_cellular_0_bar_rounded" - SIGNAL_CELLULAR_0_BAR_OUTLINED = "signal_cellular_0_bar_outlined" - SIGNAL_CELLULAR_4_BAR = "signal_cellular_4_bar" - SIGNAL_CELLULAR_4_BAR_SHARP = "signal_cellular_4_bar_sharp" - SIGNAL_CELLULAR_4_BAR_ROUNDED = "signal_cellular_4_bar_rounded" - SIGNAL_CELLULAR_4_BAR_OUTLINED = "signal_cellular_4_bar_outlined" - SIGNAL_CELLULAR_ALT = "signal_cellular_alt" - SIGNAL_CELLULAR_ALT_SHARP = "signal_cellular_alt_sharp" - SIGNAL_CELLULAR_ALT_ROUNDED = "signal_cellular_alt_rounded" - SIGNAL_CELLULAR_ALT_OUTLINED = "signal_cellular_alt_outlined" - SIGNAL_CELLULAR_ALT_1_BAR = "signal_cellular_alt_1_bar" - SIGNAL_CELLULAR_ALT_1_BAR_SHARP = "signal_cellular_alt_1_bar_sharp" - SIGNAL_CELLULAR_ALT_1_BAR_ROUNDED = "signal_cellular_alt_1_bar_rounded" - SIGNAL_CELLULAR_ALT_1_BAR_OUTLINED = "signal_cellular_alt_1_bar_outlined" - SIGNAL_CELLULAR_ALT_2_BAR = "signal_cellular_alt_2_bar" - SIGNAL_CELLULAR_ALT_2_BAR_SHARP = "signal_cellular_alt_2_bar_sharp" - SIGNAL_CELLULAR_ALT_2_BAR_ROUNDED = "signal_cellular_alt_2_bar_rounded" - SIGNAL_CELLULAR_ALT_2_BAR_OUTLINED = "signal_cellular_alt_2_bar_outlined" - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR = ( - "signal_cellular_connected_no_internet_0_bar" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_SHARP = ( - "signal_cellular_connected_no_internet_0_bar_sharp" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_ROUNDED = ( - "signal_cellular_connected_no_internet_0_bar_rounded" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BAR_OUTLINED = ( - "signal_cellular_connected_no_internet_0_bar_outlined" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR = ( - "signal_cellular_connected_no_internet_4_bar" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_SHARP = ( - "signal_cellular_connected_no_internet_4_bar_sharp" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_ROUNDED = ( - "signal_cellular_connected_no_internet_4_bar_rounded" - ) - SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BAR_OUTLINED = ( - "signal_cellular_connected_no_internet_4_bar_outlined" - ) - SIGNAL_CELLULAR_NO_SIM = "signal_cellular_no_sim" - SIGNAL_CELLULAR_NO_SIM_SHARP = "signal_cellular_no_sim_sharp" - SIGNAL_CELLULAR_NO_SIM_ROUNDED = "signal_cellular_no_sim_rounded" - SIGNAL_CELLULAR_NO_SIM_OUTLINED = "signal_cellular_no_sim_outlined" - SIGNAL_CELLULAR_NODATA = "signal_cellular_nodata" - SIGNAL_CELLULAR_NODATA_SHARP = "signal_cellular_nodata_sharp" - SIGNAL_CELLULAR_NODATA_ROUNDED = "signal_cellular_nodata_rounded" - SIGNAL_CELLULAR_NODATA_OUTLINED = "signal_cellular_nodata_outlined" - SIGNAL_CELLULAR_NULL = "signal_cellular_null" - SIGNAL_CELLULAR_NULL_SHARP = "signal_cellular_null_sharp" - SIGNAL_CELLULAR_NULL_ROUNDED = "signal_cellular_null_rounded" - SIGNAL_CELLULAR_NULL_OUTLINED = "signal_cellular_null_outlined" - SIGNAL_CELLULAR_OFF = "signal_cellular_off" - SIGNAL_CELLULAR_OFF_SHARP = "signal_cellular_off_sharp" - SIGNAL_CELLULAR_OFF_ROUNDED = "signal_cellular_off_rounded" - SIGNAL_CELLULAR_OFF_OUTLINED = "signal_cellular_off_outlined" - SIGNAL_WIFI_0_BAR = "signal_wifi_0_bar" - SIGNAL_WIFI_0_BAR_SHARP = "signal_wifi_0_bar_sharp" - SIGNAL_WIFI_0_BAR_ROUNDED = "signal_wifi_0_bar_rounded" - SIGNAL_WIFI_0_BAR_OUTLINED = "signal_wifi_0_bar_outlined" - SIGNAL_WIFI_4_BAR = "signal_wifi_4_bar" - SIGNAL_WIFI_4_BAR_SHARP = "signal_wifi_4_bar_sharp" - SIGNAL_WIFI_4_BAR_ROUNDED = "signal_wifi_4_bar_rounded" - SIGNAL_WIFI_4_BAR_OUTLINED = "signal_wifi_4_bar_outlined" - SIGNAL_WIFI_4_BAR_LOCK = "signal_wifi_4_bar_lock" - SIGNAL_WIFI_4_BAR_LOCK_SHARP = "signal_wifi_4_bar_lock_sharp" - SIGNAL_WIFI_4_BAR_LOCK_ROUNDED = "signal_wifi_4_bar_lock_rounded" - SIGNAL_WIFI_4_BAR_LOCK_OUTLINED = "signal_wifi_4_bar_lock_outlined" - SIGNAL_WIFI_BAD = "signal_wifi_bad" - SIGNAL_WIFI_BAD_SHARP = "signal_wifi_bad_sharp" - SIGNAL_WIFI_BAD_ROUNDED = "signal_wifi_bad_rounded" - SIGNAL_WIFI_BAD_OUTLINED = "signal_wifi_bad_outlined" - SIGNAL_WIFI_CONNECTED_NO_INTERNET_4 = "signal_wifi_connected_no_internet_4" - SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_SHARP = ( - "signal_wifi_connected_no_internet_4_sharp" - ) - SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_ROUNDED = ( - "signal_wifi_connected_no_internet_4_rounded" - ) - SIGNAL_WIFI_CONNECTED_NO_INTERNET_4_OUTLINED = ( - "signal_wifi_connected_no_internet_4_outlined" - ) - SIGNAL_WIFI_OFF = "signal_wifi_off" - SIGNAL_WIFI_OFF_SHARP = "signal_wifi_off_sharp" - SIGNAL_WIFI_OFF_ROUNDED = "signal_wifi_off_rounded" - SIGNAL_WIFI_OFF_OUTLINED = "signal_wifi_off_outlined" - SIGNAL_WIFI_STATUSBAR_4_BAR = "signal_wifi_statusbar_4_bar" - SIGNAL_WIFI_STATUSBAR_4_BAR_SHARP = "signal_wifi_statusbar_4_bar_sharp" - SIGNAL_WIFI_STATUSBAR_4_BAR_ROUNDED = "signal_wifi_statusbar_4_bar_rounded" - SIGNAL_WIFI_STATUSBAR_4_BAR_OUTLINED = "signal_wifi_statusbar_4_bar_outlined" - SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4 = ( - "signal_wifi_statusbar_connected_no_internet_4" - ) - SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_SHARP = ( - "signal_wifi_statusbar_connected_no_internet_4_sharp" - ) - SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_ROUNDED = ( - "signal_wifi_statusbar_connected_no_internet_4_rounded" - ) - SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4_OUTLINED = ( - "signal_wifi_statusbar_connected_no_internet_4_outlined" - ) - SIGNAL_WIFI_STATUSBAR_NULL = "signal_wifi_statusbar_null" - SIGNAL_WIFI_STATUSBAR_NULL_SHARP = "signal_wifi_statusbar_null_sharp" - SIGNAL_WIFI_STATUSBAR_NULL_ROUNDED = "signal_wifi_statusbar_null_rounded" - SIGNAL_WIFI_STATUSBAR_NULL_OUTLINED = "signal_wifi_statusbar_null_outlined" - SIGNPOST = "signpost" - SIGNPOST_SHARP = "signpost_sharp" - SIGNPOST_ROUNDED = "signpost_rounded" - SIGNPOST_OUTLINED = "signpost_outlined" - SIM_CARD = "sim_card" - SIM_CARD_SHARP = "sim_card_sharp" - SIM_CARD_ROUNDED = "sim_card_rounded" - SIM_CARD_OUTLINED = "sim_card_outlined" - SIM_CARD_ALERT = "sim_card_alert" - SIM_CARD_ALERT_SHARP = "sim_card_alert_sharp" - SIM_CARD_ALERT_ROUNDED = "sim_card_alert_rounded" - SIM_CARD_ALERT_OUTLINED = "sim_card_alert_outlined" - SIM_CARD_DOWNLOAD = "sim_card_download" - SIM_CARD_DOWNLOAD_SHARP = "sim_card_download_sharp" - SIM_CARD_DOWNLOAD_ROUNDED = "sim_card_download_rounded" - SIM_CARD_DOWNLOAD_OUTLINED = "sim_card_download_outlined" - SINGLE_BED = "single_bed" - SINGLE_BED_SHARP = "single_bed_sharp" - SINGLE_BED_ROUNDED = "single_bed_rounded" - SINGLE_BED_OUTLINED = "single_bed_outlined" - SIP = "sip" - SIP_SHARP = "sip_sharp" - SIP_ROUNDED = "sip_rounded" - SIP_OUTLINED = "sip_outlined" - SKATEBOARDING = "skateboarding" - SKATEBOARDING_SHARP = "skateboarding_sharp" - SKATEBOARDING_ROUNDED = "skateboarding_rounded" - SKATEBOARDING_OUTLINED = "skateboarding_outlined" - SKIP_NEXT = "skip_next" - SKIP_NEXT_SHARP = "skip_next_sharp" - SKIP_NEXT_ROUNDED = "skip_next_rounded" - SKIP_NEXT_OUTLINED = "skip_next_outlined" - SKIP_PREVIOUS = "skip_previous" - SKIP_PREVIOUS_SHARP = "skip_previous_sharp" - SKIP_PREVIOUS_ROUNDED = "skip_previous_rounded" - SKIP_PREVIOUS_OUTLINED = "skip_previous_outlined" - SLEDDING = "sledding" - SLEDDING_SHARP = "sledding_sharp" - SLEDDING_ROUNDED = "sledding_rounded" - SLEDDING_OUTLINED = "sledding_outlined" - SLIDESHOW = "slideshow" - SLIDESHOW_SHARP = "slideshow_sharp" - SLIDESHOW_ROUNDED = "slideshow_rounded" - SLIDESHOW_OUTLINED = "slideshow_outlined" - SLOW_MOTION_VIDEO = "slow_motion_video" - SLOW_MOTION_VIDEO_SHARP = "slow_motion_video_sharp" - SLOW_MOTION_VIDEO_ROUNDED = "slow_motion_video_rounded" - SLOW_MOTION_VIDEO_OUTLINED = "slow_motion_video_outlined" - SMART_BUTTON = "smart_button" - SMART_BUTTON_SHARP = "smart_button_sharp" - SMART_BUTTON_ROUNDED = "smart_button_rounded" - SMART_BUTTON_OUTLINED = "smart_button_outlined" - SMART_DISPLAY = "smart_display" - SMART_DISPLAY_SHARP = "smart_display_sharp" - SMART_DISPLAY_ROUNDED = "smart_display_rounded" - SMART_DISPLAY_OUTLINED = "smart_display_outlined" - SMART_SCREEN = "smart_screen" - SMART_SCREEN_SHARP = "smart_screen_sharp" - SMART_SCREEN_ROUNDED = "smart_screen_rounded" - SMART_SCREEN_OUTLINED = "smart_screen_outlined" - SMART_TOY = "smart_toy" - SMART_TOY_SHARP = "smart_toy_sharp" - SMART_TOY_ROUNDED = "smart_toy_rounded" - SMART_TOY_OUTLINED = "smart_toy_outlined" - SMARTPHONE = "smartphone" - SMARTPHONE_SHARP = "smartphone_sharp" - SMARTPHONE_ROUNDED = "smartphone_rounded" - SMARTPHONE_OUTLINED = "smartphone_outlined" - SMOKE_FREE = "smoke_free" - SMOKE_FREE_SHARP = "smoke_free_sharp" - SMOKE_FREE_ROUNDED = "smoke_free_rounded" - SMOKE_FREE_OUTLINED = "smoke_free_outlined" - SMOKING_ROOMS = "smoking_rooms" - SMOKING_ROOMS_SHARP = "smoking_rooms_sharp" - SMOKING_ROOMS_ROUNDED = "smoking_rooms_rounded" - SMOKING_ROOMS_OUTLINED = "smoking_rooms_outlined" - SMS = "sms" - SMS_SHARP = "sms_sharp" - SMS_ROUNDED = "sms_rounded" - SMS_OUTLINED = "sms_outlined" - SMS_FAILED = "sms_failed" - SMS_FAILED_SHARP = "sms_failed_sharp" - SMS_FAILED_ROUNDED = "sms_failed_rounded" - SMS_FAILED_OUTLINED = "sms_failed_outlined" - SNAPCHAT = "snapchat" - SNAPCHAT_SHARP = "snapchat_sharp" - SNAPCHAT_ROUNDED = "snapchat_rounded" - SNAPCHAT_OUTLINED = "snapchat_outlined" - SNIPPET_FOLDER = "snippet_folder" - SNIPPET_FOLDER_SHARP = "snippet_folder_sharp" - SNIPPET_FOLDER_ROUNDED = "snippet_folder_rounded" - SNIPPET_FOLDER_OUTLINED = "snippet_folder_outlined" - SNOOZE = "snooze" - SNOOZE_SHARP = "snooze_sharp" - SNOOZE_ROUNDED = "snooze_rounded" - SNOOZE_OUTLINED = "snooze_outlined" - SNOWBOARDING = "snowboarding" - SNOWBOARDING_SHARP = "snowboarding_sharp" - SNOWBOARDING_ROUNDED = "snowboarding_rounded" - SNOWBOARDING_OUTLINED = "snowboarding_outlined" - SNOWING = "snowing" - SNOWMOBILE = "snowmobile" - SNOWMOBILE_SHARP = "snowmobile_sharp" - SNOWMOBILE_ROUNDED = "snowmobile_rounded" - SNOWMOBILE_OUTLINED = "snowmobile_outlined" - SNOWSHOEING = "snowshoeing" - SNOWSHOEING_SHARP = "snowshoeing_sharp" - SNOWSHOEING_ROUNDED = "snowshoeing_rounded" - SNOWSHOEING_OUTLINED = "snowshoeing_outlined" - SOAP = "soap" - SOAP_SHARP = "soap_sharp" - SOAP_ROUNDED = "soap_rounded" - SOAP_OUTLINED = "soap_outlined" - SOCIAL_DISTANCE = "social_distance" - SOCIAL_DISTANCE_SHARP = "social_distance_sharp" - SOCIAL_DISTANCE_ROUNDED = "social_distance_rounded" - SOCIAL_DISTANCE_OUTLINED = "social_distance_outlined" - SOLAR_POWER = "solar_power" - SOLAR_POWER_SHARP = "solar_power_sharp" - SOLAR_POWER_ROUNDED = "solar_power_rounded" - SOLAR_POWER_OUTLINED = "solar_power_outlined" - SORT = "sort" - SORT_SHARP = "sort_sharp" - SORT_ROUNDED = "sort_rounded" - SORT_OUTLINED = "sort_outlined" - SORT_BY_ALPHA = "sort_by_alpha" - SORT_BY_ALPHA_SHARP = "sort_by_alpha_sharp" - SORT_BY_ALPHA_ROUNDED = "sort_by_alpha_rounded" - SORT_BY_ALPHA_OUTLINED = "sort_by_alpha_outlined" - SOS = "sos" - SOS_SHARP = "sos_sharp" - SOS_ROUNDED = "sos_rounded" - SOS_OUTLINED = "sos_outlined" - SOUP_KITCHEN = "soup_kitchen" - SOUP_KITCHEN_SHARP = "soup_kitchen_sharp" - SOUP_KITCHEN_ROUNDED = "soup_kitchen_rounded" - SOUP_KITCHEN_OUTLINED = "soup_kitchen_outlined" - SOURCE = "source" - SOURCE_SHARP = "source_sharp" - SOURCE_ROUNDED = "source_rounded" - SOURCE_OUTLINED = "source_outlined" - SOUTH = "south" - SOUTH_SHARP = "south_sharp" - SOUTH_ROUNDED = "south_rounded" - SOUTH_OUTLINED = "south_outlined" - SOUTH_AMERICA = "south_america" - SOUTH_AMERICA_SHARP = "south_america_sharp" - SOUTH_AMERICA_ROUNDED = "south_america_rounded" - SOUTH_AMERICA_OUTLINED = "south_america_outlined" - SOUTH_EAST = "south_east" - SOUTH_EAST_SHARP = "south_east_sharp" - SOUTH_EAST_ROUNDED = "south_east_rounded" - SOUTH_EAST_OUTLINED = "south_east_outlined" - SOUTH_WEST = "south_west" - SOUTH_WEST_SHARP = "south_west_sharp" - SOUTH_WEST_ROUNDED = "south_west_rounded" - SOUTH_WEST_OUTLINED = "south_west_outlined" - SPA = "spa" - SPA_SHARP = "spa_sharp" - SPA_ROUNDED = "spa_rounded" - SPA_OUTLINED = "spa_outlined" - SPACE_BAR = "space_bar" - SPACE_BAR_SHARP = "space_bar_sharp" - SPACE_BAR_ROUNDED = "space_bar_rounded" - SPACE_BAR_OUTLINED = "space_bar_outlined" - SPACE_DASHBOARD = "space_dashboard" - SPACE_DASHBOARD_SHARP = "space_dashboard_sharp" - SPACE_DASHBOARD_ROUNDED = "space_dashboard_rounded" - SPACE_DASHBOARD_OUTLINED = "space_dashboard_outlined" - SPATIAL_AUDIO = "spatial_audio" - SPATIAL_AUDIO_SHARP = "spatial_audio_sharp" - SPATIAL_AUDIO_ROUNDED = "spatial_audio_rounded" - SPATIAL_AUDIO_OUTLINED = "spatial_audio_outlined" - SPATIAL_AUDIO_OFF = "spatial_audio_off" - SPATIAL_AUDIO_OFF_SHARP = "spatial_audio_off_sharp" - SPATIAL_AUDIO_OFF_ROUNDED = "spatial_audio_off_rounded" - SPATIAL_AUDIO_OFF_OUTLINED = "spatial_audio_off_outlined" - SPATIAL_TRACKING = "spatial_tracking" - SPATIAL_TRACKING_SHARP = "spatial_tracking_sharp" - SPATIAL_TRACKING_ROUNDED = "spatial_tracking_rounded" - SPATIAL_TRACKING_OUTLINED = "spatial_tracking_outlined" - SPEAKER = "speaker" - SPEAKER_SHARP = "speaker_sharp" - SPEAKER_ROUNDED = "speaker_rounded" - SPEAKER_OUTLINED = "speaker_outlined" - SPEAKER_GROUP = "speaker_group" - SPEAKER_GROUP_SHARP = "speaker_group_sharp" - SPEAKER_GROUP_ROUNDED = "speaker_group_rounded" - SPEAKER_GROUP_OUTLINED = "speaker_group_outlined" - SPEAKER_NOTES = "speaker_notes" - SPEAKER_NOTES_SHARP = "speaker_notes_sharp" - SPEAKER_NOTES_ROUNDED = "speaker_notes_rounded" - SPEAKER_NOTES_OUTLINED = "speaker_notes_outlined" - SPEAKER_NOTES_OFF = "speaker_notes_off" - SPEAKER_NOTES_OFF_SHARP = "speaker_notes_off_sharp" - SPEAKER_NOTES_OFF_ROUNDED = "speaker_notes_off_rounded" - SPEAKER_NOTES_OFF_OUTLINED = "speaker_notes_off_outlined" - SPEAKER_PHONE = "speaker_phone" - SPEAKER_PHONE_SHARP = "speaker_phone_sharp" - SPEAKER_PHONE_ROUNDED = "speaker_phone_rounded" - SPEAKER_PHONE_OUTLINED = "speaker_phone_outlined" - SPEED = "speed" - SPEED_SHARP = "speed_sharp" - SPEED_ROUNDED = "speed_rounded" - SPEED_OUTLINED = "speed_outlined" - SPELLCHECK = "spellcheck" - SPELLCHECK_SHARP = "spellcheck_sharp" - SPELLCHECK_ROUNDED = "spellcheck_rounded" - SPELLCHECK_OUTLINED = "spellcheck_outlined" - SPLITSCREEN = "splitscreen" - SPLITSCREEN_SHARP = "splitscreen_sharp" - SPLITSCREEN_ROUNDED = "splitscreen_rounded" - SPLITSCREEN_OUTLINED = "splitscreen_outlined" - SPOKE = "spoke" - SPOKE_SHARP = "spoke_sharp" - SPOKE_ROUNDED = "spoke_rounded" - SPOKE_OUTLINED = "spoke_outlined" - SPORTS = "sports" - SPORTS_SHARP = "sports_sharp" - SPORTS_ROUNDED = "sports_rounded" - SPORTS_OUTLINED = "sports_outlined" - SPORTS_BAR = "sports_bar" - SPORTS_BAR_SHARP = "sports_bar_sharp" - SPORTS_BAR_ROUNDED = "sports_bar_rounded" - SPORTS_BAR_OUTLINED = "sports_bar_outlined" - SPORTS_BASEBALL = "sports_baseball" - SPORTS_BASEBALL_SHARP = "sports_baseball_sharp" - SPORTS_BASEBALL_ROUNDED = "sports_baseball_rounded" - SPORTS_BASEBALL_OUTLINED = "sports_baseball_outlined" - SPORTS_BASKETBALL = "sports_basketball" - SPORTS_BASKETBALL_SHARP = "sports_basketball_sharp" - SPORTS_BASKETBALL_ROUNDED = "sports_basketball_rounded" - SPORTS_BASKETBALL_OUTLINED = "sports_basketball_outlined" - SPORTS_CRICKET = "sports_cricket" - SPORTS_CRICKET_SHARP = "sports_cricket_sharp" - SPORTS_CRICKET_ROUNDED = "sports_cricket_rounded" - SPORTS_CRICKET_OUTLINED = "sports_cricket_outlined" - SPORTS_ESPORTS = "sports_esports" - SPORTS_ESPORTS_SHARP = "sports_esports_sharp" - SPORTS_ESPORTS_ROUNDED = "sports_esports_rounded" - SPORTS_ESPORTS_OUTLINED = "sports_esports_outlined" - SPORTS_FOOTBALL = "sports_football" - SPORTS_FOOTBALL_SHARP = "sports_football_sharp" - SPORTS_FOOTBALL_ROUNDED = "sports_football_rounded" - SPORTS_FOOTBALL_OUTLINED = "sports_football_outlined" - SPORTS_GOLF = "sports_golf" - SPORTS_GOLF_SHARP = "sports_golf_sharp" - SPORTS_GOLF_ROUNDED = "sports_golf_rounded" - SPORTS_GOLF_OUTLINED = "sports_golf_outlined" - SPORTS_GYMNASTICS = "sports_gymnastics" - SPORTS_GYMNASTICS_SHARP = "sports_gymnastics_sharp" - SPORTS_GYMNASTICS_ROUNDED = "sports_gymnastics_rounded" - SPORTS_GYMNASTICS_OUTLINED = "sports_gymnastics_outlined" - SPORTS_HANDBALL = "sports_handball" - SPORTS_HANDBALL_SHARP = "sports_handball_sharp" - SPORTS_HANDBALL_ROUNDED = "sports_handball_rounded" - SPORTS_HANDBALL_OUTLINED = "sports_handball_outlined" - SPORTS_HOCKEY = "sports_hockey" - SPORTS_HOCKEY_SHARP = "sports_hockey_sharp" - SPORTS_HOCKEY_ROUNDED = "sports_hockey_rounded" - SPORTS_HOCKEY_OUTLINED = "sports_hockey_outlined" - SPORTS_KABADDI = "sports_kabaddi" - SPORTS_KABADDI_SHARP = "sports_kabaddi_sharp" - SPORTS_KABADDI_ROUNDED = "sports_kabaddi_rounded" - SPORTS_KABADDI_OUTLINED = "sports_kabaddi_outlined" - SPORTS_MARTIAL_ARTS = "sports_martial_arts" - SPORTS_MARTIAL_ARTS_SHARP = "sports_martial_arts_sharp" - SPORTS_MARTIAL_ARTS_ROUNDED = "sports_martial_arts_rounded" - SPORTS_MARTIAL_ARTS_OUTLINED = "sports_martial_arts_outlined" - SPORTS_MMA = "sports_mma" - SPORTS_MMA_SHARP = "sports_mma_sharp" - SPORTS_MMA_ROUNDED = "sports_mma_rounded" - SPORTS_MMA_OUTLINED = "sports_mma_outlined" - SPORTS_MOTORSPORTS = "sports_motorsports" - SPORTS_MOTORSPORTS_SHARP = "sports_motorsports_sharp" - SPORTS_MOTORSPORTS_ROUNDED = "sports_motorsports_rounded" - SPORTS_MOTORSPORTS_OUTLINED = "sports_motorsports_outlined" - SPORTS_RUGBY = "sports_rugby" - SPORTS_RUGBY_SHARP = "sports_rugby_sharp" - SPORTS_RUGBY_ROUNDED = "sports_rugby_rounded" - SPORTS_RUGBY_OUTLINED = "sports_rugby_outlined" - SPORTS_SCORE = "sports_score" - SPORTS_SCORE_SHARP = "sports_score_sharp" - SPORTS_SCORE_ROUNDED = "sports_score_rounded" - SPORTS_SCORE_OUTLINED = "sports_score_outlined" - SPORTS_SOCCER = "sports_soccer" - SPORTS_SOCCER_SHARP = "sports_soccer_sharp" - SPORTS_SOCCER_ROUNDED = "sports_soccer_rounded" - SPORTS_SOCCER_OUTLINED = "sports_soccer_outlined" - SPORTS_TENNIS = "sports_tennis" - SPORTS_TENNIS_SHARP = "sports_tennis_sharp" - SPORTS_TENNIS_ROUNDED = "sports_tennis_rounded" - SPORTS_TENNIS_OUTLINED = "sports_tennis_outlined" - SPORTS_VOLLEYBALL = "sports_volleyball" - SPORTS_VOLLEYBALL_SHARP = "sports_volleyball_sharp" - SPORTS_VOLLEYBALL_ROUNDED = "sports_volleyball_rounded" - SPORTS_VOLLEYBALL_OUTLINED = "sports_volleyball_outlined" - SQUARE = "square" - SQUARE_SHARP = "square_sharp" - SQUARE_ROUNDED = "square_rounded" - SQUARE_OUTLINED = "square_outlined" - SQUARE_FOOT = "square_foot" - SQUARE_FOOT_SHARP = "square_foot_sharp" - SQUARE_FOOT_ROUNDED = "square_foot_rounded" - SQUARE_FOOT_OUTLINED = "square_foot_outlined" - SSID_CHART = "ssid_chart" - SSID_CHART_SHARP = "ssid_chart_sharp" - SSID_CHART_ROUNDED = "ssid_chart_rounded" - SSID_CHART_OUTLINED = "ssid_chart_outlined" - STACKED_BAR_CHART = "stacked_bar_chart" - STACKED_BAR_CHART_SHARP = "stacked_bar_chart_sharp" - STACKED_BAR_CHART_ROUNDED = "stacked_bar_chart_rounded" - STACKED_BAR_CHART_OUTLINED = "stacked_bar_chart_outlined" - STACKED_LINE_CHART = "stacked_line_chart" - STACKED_LINE_CHART_SHARP = "stacked_line_chart_sharp" - STACKED_LINE_CHART_ROUNDED = "stacked_line_chart_rounded" - STACKED_LINE_CHART_OUTLINED = "stacked_line_chart_outlined" - STADIUM = "stadium" - STADIUM_SHARP = "stadium_sharp" - STADIUM_ROUNDED = "stadium_rounded" - STADIUM_OUTLINED = "stadium_outlined" - STAIRS = "stairs" - STAIRS_SHARP = "stairs_sharp" - STAIRS_ROUNDED = "stairs_rounded" - STAIRS_OUTLINED = "stairs_outlined" - STAR = "star" - STAR_SHARP = "star_sharp" - STAR_ROUNDED = "star_rounded" - STAR_OUTLINED = "star_outlined" - STAR_BORDER = "star_border" - STAR_BORDER_SHARP = "star_border_sharp" - STAR_BORDER_ROUNDED = "star_border_rounded" - STAR_BORDER_OUTLINED = "star_border_outlined" - STAR_BORDER_PURPLE500 = "star_border_purple500" - STAR_BORDER_PURPLE500_SHARP = "star_border_purple500_sharp" - STAR_BORDER_PURPLE500_ROUNDED = "star_border_purple500_rounded" - STAR_BORDER_PURPLE500_OUTLINED = "star_border_purple500_outlined" - STAR_HALF = "star_half" - STAR_HALF_SHARP = "star_half_sharp" - STAR_HALF_ROUNDED = "star_half_rounded" - STAR_HALF_OUTLINED = "star_half_outlined" - STAR_OUTLINE = "star_outline" - STAR_OUTLINE_SHARP = "star_outline_sharp" - STAR_OUTLINE_ROUNDED = "star_outline_rounded" - STAR_OUTLINE_OUTLINED = "star_outline_outlined" - STAR_PURPLE500 = "star_purple500" - STAR_PURPLE500_SHARP = "star_purple500_sharp" - STAR_PURPLE500_ROUNDED = "star_purple500_rounded" - STAR_PURPLE500_OUTLINED = "star_purple500_outlined" - STAR_RATE = "star_rate" - STAR_RATE_SHARP = "star_rate_sharp" - STAR_RATE_ROUNDED = "star_rate_rounded" - STAR_RATE_OUTLINED = "star_rate_outlined" - STARS = "stars" - STARS_SHARP = "stars_sharp" - STARS_ROUNDED = "stars_rounded" - STARS_OUTLINED = "stars_outlined" - START = "start" - START_SHARP = "start_sharp" - START_ROUNDED = "start_rounded" - START_OUTLINED = "start_outlined" - STAY_CURRENT_LANDSCAPE = "stay_current_landscape" - STAY_CURRENT_LANDSCAPE_SHARP = "stay_current_landscape_sharp" - STAY_CURRENT_LANDSCAPE_ROUNDED = "stay_current_landscape_rounded" - STAY_CURRENT_LANDSCAPE_OUTLINED = "stay_current_landscape_outlined" - STAY_CURRENT_PORTRAIT = "stay_current_portrait" - STAY_CURRENT_PORTRAIT_SHARP = "stay_current_portrait_sharp" - STAY_CURRENT_PORTRAIT_ROUNDED = "stay_current_portrait_rounded" - STAY_CURRENT_PORTRAIT_OUTLINED = "stay_current_portrait_outlined" - STAY_PRIMARY_LANDSCAPE = "stay_primary_landscape" - STAY_PRIMARY_LANDSCAPE_SHARP = "stay_primary_landscape_sharp" - STAY_PRIMARY_LANDSCAPE_ROUNDED = "stay_primary_landscape_rounded" - STAY_PRIMARY_LANDSCAPE_OUTLINED = "stay_primary_landscape_outlined" - STAY_PRIMARY_PORTRAIT = "stay_primary_portrait" - STAY_PRIMARY_PORTRAIT_SHARP = "stay_primary_portrait_sharp" - STAY_PRIMARY_PORTRAIT_ROUNDED = "stay_primary_portrait_rounded" - STAY_PRIMARY_PORTRAIT_OUTLINED = "stay_primary_portrait_outlined" - STICKY_NOTE_2 = "sticky_note_2" - STICKY_NOTE_2_SHARP = "sticky_note_2_sharp" - STICKY_NOTE_2_ROUNDED = "sticky_note_2_rounded" - STICKY_NOTE_2_OUTLINED = "sticky_note_2_outlined" - STOP = "stop" - STOP_SHARP = "stop_sharp" - STOP_ROUNDED = "stop_rounded" - STOP_OUTLINED = "stop_outlined" - STOP_CIRCLE = "stop_circle" - STOP_CIRCLE_SHARP = "stop_circle_sharp" - STOP_CIRCLE_ROUNDED = "stop_circle_rounded" - STOP_CIRCLE_OUTLINED = "stop_circle_outlined" - STOP_SCREEN_SHARE = "stop_screen_share" - STOP_SCREEN_SHARE_SHARP = "stop_screen_share_sharp" - STOP_SCREEN_SHARE_ROUNDED = "stop_screen_share_rounded" - STOP_SCREEN_SHARE_OUTLINED = "stop_screen_share_outlined" - STORAGE = "storage" - STORAGE_SHARP = "storage_sharp" - STORAGE_ROUNDED = "storage_rounded" - STORAGE_OUTLINED = "storage_outlined" - STORE = "store" - STORE_SHARP = "store_sharp" - STORE_ROUNDED = "store_rounded" - STORE_OUTLINED = "store_outlined" - STORE_MALL_DIRECTORY = "store_mall_directory" - STORE_MALL_DIRECTORY_SHARP = "store_mall_directory_sharp" - STORE_MALL_DIRECTORY_ROUNDED = "store_mall_directory_rounded" - STORE_MALL_DIRECTORY_OUTLINED = "store_mall_directory_outlined" - STOREFRONT = "storefront" - STOREFRONT_SHARP = "storefront_sharp" - STOREFRONT_ROUNDED = "storefront_rounded" - STOREFRONT_OUTLINED = "storefront_outlined" - STORM = "storm" - STORM_SHARP = "storm_sharp" - STORM_ROUNDED = "storm_rounded" - STORM_OUTLINED = "storm_outlined" - STRAIGHT = "straight" - STRAIGHT_SHARP = "straight_sharp" - STRAIGHT_ROUNDED = "straight_rounded" - STRAIGHT_OUTLINED = "straight_outlined" - STRAIGHTEN = "straighten" - STRAIGHTEN_SHARP = "straighten_sharp" - STRAIGHTEN_ROUNDED = "straighten_rounded" - STRAIGHTEN_OUTLINED = "straighten_outlined" - STREAM = "stream" - STREAM_SHARP = "stream_sharp" - STREAM_ROUNDED = "stream_rounded" - STREAM_OUTLINED = "stream_outlined" - STREETVIEW = "streetview" - STREETVIEW_SHARP = "streetview_sharp" - STREETVIEW_ROUNDED = "streetview_rounded" - STREETVIEW_OUTLINED = "streetview_outlined" - STRIKETHROUGH_S = "strikethrough_s" - STRIKETHROUGH_S_SHARP = "strikethrough_s_sharp" - STRIKETHROUGH_S_ROUNDED = "strikethrough_s_rounded" - STRIKETHROUGH_S_OUTLINED = "strikethrough_s_outlined" - STROLLER = "stroller" - STROLLER_SHARP = "stroller_sharp" - STROLLER_ROUNDED = "stroller_rounded" - STROLLER_OUTLINED = "stroller_outlined" - STYLE = "style" - STYLE_SHARP = "style_sharp" - STYLE_ROUNDED = "style_rounded" - STYLE_OUTLINED = "style_outlined" - SUBDIRECTORY_ARROW_LEFT = "subdirectory_arrow_left" - SUBDIRECTORY_ARROW_LEFT_SHARP = "subdirectory_arrow_left_sharp" - SUBDIRECTORY_ARROW_LEFT_ROUNDED = "subdirectory_arrow_left_rounded" - SUBDIRECTORY_ARROW_LEFT_OUTLINED = "subdirectory_arrow_left_outlined" - SUBDIRECTORY_ARROW_RIGHT = "subdirectory_arrow_right" - SUBDIRECTORY_ARROW_RIGHT_SHARP = "subdirectory_arrow_right_sharp" - SUBDIRECTORY_ARROW_RIGHT_ROUNDED = "subdirectory_arrow_right_rounded" - SUBDIRECTORY_ARROW_RIGHT_OUTLINED = "subdirectory_arrow_right_outlined" - SUBJECT = "subject" - SUBJECT_SHARP = "subject_sharp" - SUBJECT_ROUNDED = "subject_rounded" - SUBJECT_OUTLINED = "subject_outlined" - SUBSCRIPT = "subscript" - SUBSCRIPT_SHARP = "subscript_sharp" - SUBSCRIPT_ROUNDED = "subscript_rounded" - SUBSCRIPT_OUTLINED = "subscript_outlined" - SUBSCRIPTIONS = "subscriptions" - SUBSCRIPTIONS_SHARP = "subscriptions_sharp" - SUBSCRIPTIONS_ROUNDED = "subscriptions_rounded" - SUBSCRIPTIONS_OUTLINED = "subscriptions_outlined" - SUBTITLES = "subtitles" - SUBTITLES_SHARP = "subtitles_sharp" - SUBTITLES_ROUNDED = "subtitles_rounded" - SUBTITLES_OUTLINED = "subtitles_outlined" - SUBTITLES_OFF = "subtitles_off" - SUBTITLES_OFF_SHARP = "subtitles_off_sharp" - SUBTITLES_OFF_ROUNDED = "subtitles_off_rounded" - SUBTITLES_OFF_OUTLINED = "subtitles_off_outlined" - SUBWAY = "subway" - SUBWAY_SHARP = "subway_sharp" - SUBWAY_ROUNDED = "subway_rounded" - SUBWAY_OUTLINED = "subway_outlined" - SUMMARIZE = "summarize" - SUMMARIZE_SHARP = "summarize_sharp" - SUMMARIZE_ROUNDED = "summarize_rounded" - SUMMARIZE_OUTLINED = "summarize_outlined" - SUNNY = "sunny" - SUNNY_SNOWING = "sunny_snowing" - SUPERSCRIPT = "superscript" - SUPERSCRIPT_SHARP = "superscript_sharp" - SUPERSCRIPT_ROUNDED = "superscript_rounded" - SUPERSCRIPT_OUTLINED = "superscript_outlined" - SUPERVISED_USER_CIRCLE = "supervised_user_circle" - SUPERVISED_USER_CIRCLE_SHARP = "supervised_user_circle_sharp" - SUPERVISED_USER_CIRCLE_ROUNDED = "supervised_user_circle_rounded" - SUPERVISED_USER_CIRCLE_OUTLINED = "supervised_user_circle_outlined" - SUPERVISOR_ACCOUNT = "supervisor_account" - SUPERVISOR_ACCOUNT_SHARP = "supervisor_account_sharp" - SUPERVISOR_ACCOUNT_ROUNDED = "supervisor_account_rounded" - SUPERVISOR_ACCOUNT_OUTLINED = "supervisor_account_outlined" - SUPPORT = "support" - SUPPORT_SHARP = "support_sharp" - SUPPORT_ROUNDED = "support_rounded" - SUPPORT_OUTLINED = "support_outlined" - SUPPORT_AGENT = "support_agent" - SUPPORT_AGENT_SHARP = "support_agent_sharp" - SUPPORT_AGENT_ROUNDED = "support_agent_rounded" - SUPPORT_AGENT_OUTLINED = "support_agent_outlined" - SURFING = "surfing" - SURFING_SHARP = "surfing_sharp" - SURFING_ROUNDED = "surfing_rounded" - SURFING_OUTLINED = "surfing_outlined" - SURROUND_SOUND = "surround_sound" - SURROUND_SOUND_SHARP = "surround_sound_sharp" - SURROUND_SOUND_ROUNDED = "surround_sound_rounded" - SURROUND_SOUND_OUTLINED = "surround_sound_outlined" - SWAP_CALLS = "swap_calls" - SWAP_CALLS_SHARP = "swap_calls_sharp" - SWAP_CALLS_ROUNDED = "swap_calls_rounded" - SWAP_CALLS_OUTLINED = "swap_calls_outlined" - SWAP_HORIZ = "swap_horiz" - SWAP_HORIZ_SHARP = "swap_horiz_sharp" - SWAP_HORIZ_ROUNDED = "swap_horiz_rounded" - SWAP_HORIZ_OUTLINED = "swap_horiz_outlined" - SWAP_HORIZONTAL_CIRCLE = "swap_horizontal_circle" - SWAP_HORIZONTAL_CIRCLE_SHARP = "swap_horizontal_circle_sharp" - SWAP_HORIZONTAL_CIRCLE_ROUNDED = "swap_horizontal_circle_rounded" - SWAP_HORIZONTAL_CIRCLE_OUTLINED = "swap_horizontal_circle_outlined" - SWAP_VERT = "swap_vert" - SWAP_VERT_SHARP = "swap_vert_sharp" - SWAP_VERT_ROUNDED = "swap_vert_rounded" - SWAP_VERT_OUTLINED = "swap_vert_outlined" - SWAP_VERT_CIRCLE = "swap_vert_circle" - SWAP_VERT_CIRCLE_SHARP = "swap_vert_circle_sharp" - SWAP_VERT_CIRCLE_ROUNDED = "swap_vert_circle_rounded" - SWAP_VERT_CIRCLE_OUTLINED = "swap_vert_circle_outlined" - SWAP_VERTICAL_CIRCLE = "swap_vertical_circle" - SWAP_VERTICAL_CIRCLE_SHARP = "swap_vertical_circle_sharp" - SWAP_VERTICAL_CIRCLE_ROUNDED = "swap_vertical_circle_rounded" - SWAP_VERTICAL_CIRCLE_OUTLINED = "swap_vertical_circle_outlined" - SWIPE = "swipe" - SWIPE_SHARP = "swipe_sharp" - SWIPE_ROUNDED = "swipe_rounded" - SWIPE_OUTLINED = "swipe_outlined" - SWIPE_DOWN = "swipe_down" - SWIPE_DOWN_SHARP = "swipe_down_sharp" - SWIPE_DOWN_ROUNDED = "swipe_down_rounded" - SWIPE_DOWN_OUTLINED = "swipe_down_outlined" - SWIPE_DOWN_ALT = "swipe_down_alt" - SWIPE_DOWN_ALT_SHARP = "swipe_down_alt_sharp" - SWIPE_DOWN_ALT_ROUNDED = "swipe_down_alt_rounded" - SWIPE_DOWN_ALT_OUTLINED = "swipe_down_alt_outlined" - SWIPE_LEFT = "swipe_left" - SWIPE_LEFT_SHARP = "swipe_left_sharp" - SWIPE_LEFT_ROUNDED = "swipe_left_rounded" - SWIPE_LEFT_OUTLINED = "swipe_left_outlined" - SWIPE_LEFT_ALT = "swipe_left_alt" - SWIPE_LEFT_ALT_SHARP = "swipe_left_alt_sharp" - SWIPE_LEFT_ALT_ROUNDED = "swipe_left_alt_rounded" - SWIPE_LEFT_ALT_OUTLINED = "swipe_left_alt_outlined" - SWIPE_RIGHT = "swipe_right" - SWIPE_RIGHT_SHARP = "swipe_right_sharp" - SWIPE_RIGHT_ROUNDED = "swipe_right_rounded" - SWIPE_RIGHT_OUTLINED = "swipe_right_outlined" - SWIPE_RIGHT_ALT = "swipe_right_alt" - SWIPE_RIGHT_ALT_SHARP = "swipe_right_alt_sharp" - SWIPE_RIGHT_ALT_ROUNDED = "swipe_right_alt_rounded" - SWIPE_RIGHT_ALT_OUTLINED = "swipe_right_alt_outlined" - SWIPE_UP = "swipe_up" - SWIPE_UP_SHARP = "swipe_up_sharp" - SWIPE_UP_ROUNDED = "swipe_up_rounded" - SWIPE_UP_OUTLINED = "swipe_up_outlined" - SWIPE_UP_ALT = "swipe_up_alt" - SWIPE_UP_ALT_SHARP = "swipe_up_alt_sharp" - SWIPE_UP_ALT_ROUNDED = "swipe_up_alt_rounded" - SWIPE_UP_ALT_OUTLINED = "swipe_up_alt_outlined" - SWIPE_VERTICAL = "swipe_vertical" - SWIPE_VERTICAL_SHARP = "swipe_vertical_sharp" - SWIPE_VERTICAL_ROUNDED = "swipe_vertical_rounded" - SWIPE_VERTICAL_OUTLINED = "swipe_vertical_outlined" - SWITCH_ACCESS_SHORTCUT = "switch_access_shortcut" - SWITCH_ACCESS_SHORTCUT_SHARP = "switch_access_shortcut_sharp" - SWITCH_ACCESS_SHORTCUT_ROUNDED = "switch_access_shortcut_rounded" - SWITCH_ACCESS_SHORTCUT_OUTLINED = "switch_access_shortcut_outlined" - SWITCH_ACCESS_SHORTCUT_ADD = "switch_access_shortcut_add" - SWITCH_ACCESS_SHORTCUT_ADD_SHARP = "switch_access_shortcut_add_sharp" - SWITCH_ACCESS_SHORTCUT_ADD_ROUNDED = "switch_access_shortcut_add_rounded" - SWITCH_ACCESS_SHORTCUT_ADD_OUTLINED = "switch_access_shortcut_add_outlined" - SWITCH_ACCOUNT = "switch_account" - SWITCH_ACCOUNT_SHARP = "switch_account_sharp" - SWITCH_ACCOUNT_ROUNDED = "switch_account_rounded" - SWITCH_ACCOUNT_OUTLINED = "switch_account_outlined" - SWITCH_CAMERA = "switch_camera" - SWITCH_CAMERA_SHARP = "switch_camera_sharp" - SWITCH_CAMERA_ROUNDED = "switch_camera_rounded" - SWITCH_CAMERA_OUTLINED = "switch_camera_outlined" - SWITCH_LEFT = "switch_left" - SWITCH_LEFT_SHARP = "switch_left_sharp" - SWITCH_LEFT_ROUNDED = "switch_left_rounded" - SWITCH_LEFT_OUTLINED = "switch_left_outlined" - SWITCH_RIGHT = "switch_right" - SWITCH_RIGHT_SHARP = "switch_right_sharp" - SWITCH_RIGHT_ROUNDED = "switch_right_rounded" - SWITCH_RIGHT_OUTLINED = "switch_right_outlined" - SWITCH_VIDEO = "switch_video" - SWITCH_VIDEO_SHARP = "switch_video_sharp" - SWITCH_VIDEO_ROUNDED = "switch_video_rounded" - SWITCH_VIDEO_OUTLINED = "switch_video_outlined" - SYNAGOGUE = "synagogue" - SYNAGOGUE_SHARP = "synagogue_sharp" - SYNAGOGUE_ROUNDED = "synagogue_rounded" - SYNAGOGUE_OUTLINED = "synagogue_outlined" - SYNC = "sync" - SYNC_SHARP = "sync_sharp" - SYNC_ROUNDED = "sync_rounded" - SYNC_OUTLINED = "sync_outlined" - SYNC_ALT = "sync_alt" - SYNC_ALT_SHARP = "sync_alt_sharp" - SYNC_ALT_ROUNDED = "sync_alt_rounded" - SYNC_ALT_OUTLINED = "sync_alt_outlined" - SYNC_DISABLED = "sync_disabled" - SYNC_DISABLED_SHARP = "sync_disabled_sharp" - SYNC_DISABLED_ROUNDED = "sync_disabled_rounded" - SYNC_DISABLED_OUTLINED = "sync_disabled_outlined" - SYNC_LOCK = "sync_lock" - SYNC_LOCK_SHARP = "sync_lock_sharp" - SYNC_LOCK_ROUNDED = "sync_lock_rounded" - SYNC_LOCK_OUTLINED = "sync_lock_outlined" - SYNC_PROBLEM = "sync_problem" - SYNC_PROBLEM_SHARP = "sync_problem_sharp" - SYNC_PROBLEM_ROUNDED = "sync_problem_rounded" - SYNC_PROBLEM_OUTLINED = "sync_problem_outlined" - SYSTEM_SECURITY_UPDATE = "system_security_update" - SYSTEM_SECURITY_UPDATE_SHARP = "system_security_update_sharp" - SYSTEM_SECURITY_UPDATE_ROUNDED = "system_security_update_rounded" - SYSTEM_SECURITY_UPDATE_OUTLINED = "system_security_update_outlined" - SYSTEM_SECURITY_UPDATE_GOOD = "system_security_update_good" - SYSTEM_SECURITY_UPDATE_GOOD_SHARP = "system_security_update_good_sharp" - SYSTEM_SECURITY_UPDATE_GOOD_ROUNDED = "system_security_update_good_rounded" - SYSTEM_SECURITY_UPDATE_GOOD_OUTLINED = "system_security_update_good_outlined" - SYSTEM_SECURITY_UPDATE_WARNING = "system_security_update_warning" - SYSTEM_SECURITY_UPDATE_WARNING_SHARP = "system_security_update_warning_sharp" - SYSTEM_SECURITY_UPDATE_WARNING_ROUNDED = "system_security_update_warning_rounded" - SYSTEM_SECURITY_UPDATE_WARNING_OUTLINED = "system_security_update_warning_outlined" - SYSTEM_UPDATE = "system_update" - SYSTEM_UPDATE_SHARP = "system_update_sharp" - SYSTEM_UPDATE_ROUNDED = "system_update_rounded" - SYSTEM_UPDATE_OUTLINED = "system_update_outlined" - SYSTEM_UPDATE_ALT = "system_update_alt" - SYSTEM_UPDATE_ALT_SHARP = "system_update_alt_sharp" - SYSTEM_UPDATE_ALT_ROUNDED = "system_update_alt_rounded" - SYSTEM_UPDATE_ALT_OUTLINED = "system_update_alt_outlined" - SYSTEM_UPDATE_TV = "system_update_tv" - SYSTEM_UPDATE_TV_SHARP = "system_update_tv_sharp" - SYSTEM_UPDATE_TV_ROUNDED = "system_update_tv_rounded" - SYSTEM_UPDATE_TV_OUTLINED = "system_update_tv_outlined" - TAB = "tab" - TAB_SHARP = "tab_sharp" - TAB_ROUNDED = "tab_rounded" - TAB_OUTLINED = "tab_outlined" - TAB_UNSELECTED = "tab_unselected" - TAB_UNSELECTED_SHARP = "tab_unselected_sharp" - TAB_UNSELECTED_ROUNDED = "tab_unselected_rounded" - TAB_UNSELECTED_OUTLINED = "tab_unselected_outlined" - TABLE_BAR = "table_bar" - TABLE_BAR_SHARP = "table_bar_sharp" - TABLE_BAR_ROUNDED = "table_bar_rounded" - TABLE_BAR_OUTLINED = "table_bar_outlined" - TABLE_CHART = "table_chart" - TABLE_CHART_SHARP = "table_chart_sharp" - TABLE_CHART_ROUNDED = "table_chart_rounded" - TABLE_CHART_OUTLINED = "table_chart_outlined" - TABLE_RESTAURANT = "table_restaurant" - TABLE_RESTAURANT_SHARP = "table_restaurant_sharp" - TABLE_RESTAURANT_ROUNDED = "table_restaurant_rounded" - TABLE_RESTAURANT_OUTLINED = "table_restaurant_outlined" - TABLE_ROWS = "table_rows" - TABLE_ROWS_SHARP = "table_rows_sharp" - TABLE_ROWS_ROUNDED = "table_rows_rounded" - TABLE_ROWS_OUTLINED = "table_rows_outlined" - TABLE_VIEW = "table_view" - TABLE_VIEW_SHARP = "table_view_sharp" - TABLE_VIEW_ROUNDED = "table_view_rounded" - TABLE_VIEW_OUTLINED = "table_view_outlined" - TABLET = "tablet" - TABLET_SHARP = "tablet_sharp" - TABLET_ROUNDED = "tablet_rounded" - TABLET_OUTLINED = "tablet_outlined" - TABLET_ANDROID = "tablet_android" - TABLET_ANDROID_SHARP = "tablet_android_sharp" - TABLET_ANDROID_ROUNDED = "tablet_android_rounded" - TABLET_ANDROID_OUTLINED = "tablet_android_outlined" - TABLET_MAC = "tablet_mac" - TABLET_MAC_SHARP = "tablet_mac_sharp" - TABLET_MAC_ROUNDED = "tablet_mac_rounded" - TABLET_MAC_OUTLINED = "tablet_mac_outlined" - TAG = "tag" - TAG_SHARP = "tag_sharp" - TAG_ROUNDED = "tag_rounded" - TAG_OUTLINED = "tag_outlined" - TAG_FACES = "tag_faces" - TAG_FACES_SHARP = "tag_faces_sharp" - TAG_FACES_ROUNDED = "tag_faces_rounded" - TAG_FACES_OUTLINED = "tag_faces_outlined" - TAKEOUT_DINING = "takeout_dining" - TAKEOUT_DINING_SHARP = "takeout_dining_sharp" - TAKEOUT_DINING_ROUNDED = "takeout_dining_rounded" - TAKEOUT_DINING_OUTLINED = "takeout_dining_outlined" - TAP_AND_PLAY = "tap_and_play" - TAP_AND_PLAY_SHARP = "tap_and_play_sharp" - TAP_AND_PLAY_ROUNDED = "tap_and_play_rounded" - TAP_AND_PLAY_OUTLINED = "tap_and_play_outlined" - TAPAS = "tapas" - TAPAS_SHARP = "tapas_sharp" - TAPAS_ROUNDED = "tapas_rounded" - TAPAS_OUTLINED = "tapas_outlined" - TASK = "task" - TASK_SHARP = "task_sharp" - TASK_ROUNDED = "task_rounded" - TASK_OUTLINED = "task_outlined" - TASK_ALT = "task_alt" - TASK_ALT_SHARP = "task_alt_sharp" - TASK_ALT_ROUNDED = "task_alt_rounded" - TASK_ALT_OUTLINED = "task_alt_outlined" - TAXI_ALERT = "taxi_alert" - TAXI_ALERT_SHARP = "taxi_alert_sharp" - TAXI_ALERT_ROUNDED = "taxi_alert_rounded" - TAXI_ALERT_OUTLINED = "taxi_alert_outlined" - TELEGRAM = "telegram" - TELEGRAM_SHARP = "telegram_sharp" - TELEGRAM_ROUNDED = "telegram_rounded" - TELEGRAM_OUTLINED = "telegram_outlined" - TEMPLE_BUDDHIST = "temple_buddhist" - TEMPLE_BUDDHIST_SHARP = "temple_buddhist_sharp" - TEMPLE_BUDDHIST_ROUNDED = "temple_buddhist_rounded" - TEMPLE_BUDDHIST_OUTLINED = "temple_buddhist_outlined" - TEMPLE_HINDU = "temple_hindu" - TEMPLE_HINDU_SHARP = "temple_hindu_sharp" - TEMPLE_HINDU_ROUNDED = "temple_hindu_rounded" - TEMPLE_HINDU_OUTLINED = "temple_hindu_outlined" - TERMINAL = "terminal" - TERMINAL_SHARP = "terminal_sharp" - TERMINAL_ROUNDED = "terminal_rounded" - TERMINAL_OUTLINED = "terminal_outlined" - TERRAIN = "terrain" - TERRAIN_SHARP = "terrain_sharp" - TERRAIN_ROUNDED = "terrain_rounded" - TERRAIN_OUTLINED = "terrain_outlined" - TEXT_DECREASE = "text_decrease" - TEXT_DECREASE_SHARP = "text_decrease_sharp" - TEXT_DECREASE_ROUNDED = "text_decrease_rounded" - TEXT_DECREASE_OUTLINED = "text_decrease_outlined" - TEXT_FIELDS = "text_fields" - TEXT_FIELDS_SHARP = "text_fields_sharp" - TEXT_FIELDS_ROUNDED = "text_fields_rounded" - TEXT_FIELDS_OUTLINED = "text_fields_outlined" - TEXT_FORMAT = "text_format" - TEXT_FORMAT_SHARP = "text_format_sharp" - TEXT_FORMAT_ROUNDED = "text_format_rounded" - TEXT_FORMAT_OUTLINED = "text_format_outlined" - TEXT_INCREASE = "text_increase" - TEXT_INCREASE_SHARP = "text_increase_sharp" - TEXT_INCREASE_ROUNDED = "text_increase_rounded" - TEXT_INCREASE_OUTLINED = "text_increase_outlined" - TEXT_ROTATE_UP = "text_rotate_up" - TEXT_ROTATE_UP_SHARP = "text_rotate_up_sharp" - TEXT_ROTATE_UP_ROUNDED = "text_rotate_up_rounded" - TEXT_ROTATE_UP_OUTLINED = "text_rotate_up_outlined" - TEXT_ROTATE_VERTICAL = "text_rotate_vertical" - TEXT_ROTATE_VERTICAL_SHARP = "text_rotate_vertical_sharp" - TEXT_ROTATE_VERTICAL_ROUNDED = "text_rotate_vertical_rounded" - TEXT_ROTATE_VERTICAL_OUTLINED = "text_rotate_vertical_outlined" - TEXT_ROTATION_ANGLEDOWN = "text_rotation_angledown" - TEXT_ROTATION_ANGLEDOWN_SHARP = "text_rotation_angledown_sharp" - TEXT_ROTATION_ANGLEDOWN_ROUNDED = "text_rotation_angledown_rounded" - TEXT_ROTATION_ANGLEDOWN_OUTLINED = "text_rotation_angledown_outlined" - TEXT_ROTATION_ANGLEUP = "text_rotation_angleup" - TEXT_ROTATION_ANGLEUP_SHARP = "text_rotation_angleup_sharp" - TEXT_ROTATION_ANGLEUP_ROUNDED = "text_rotation_angleup_rounded" - TEXT_ROTATION_ANGLEUP_OUTLINED = "text_rotation_angleup_outlined" - TEXT_ROTATION_DOWN = "text_rotation_down" - TEXT_ROTATION_DOWN_SHARP = "text_rotation_down_sharp" - TEXT_ROTATION_DOWN_ROUNDED = "text_rotation_down_rounded" - TEXT_ROTATION_DOWN_OUTLINED = "text_rotation_down_outlined" - TEXT_ROTATION_NONE = "text_rotation_none" - TEXT_ROTATION_NONE_SHARP = "text_rotation_none_sharp" - TEXT_ROTATION_NONE_ROUNDED = "text_rotation_none_rounded" - TEXT_ROTATION_NONE_OUTLINED = "text_rotation_none_outlined" - TEXT_SNIPPET = "text_snippet" - TEXT_SNIPPET_SHARP = "text_snippet_sharp" - TEXT_SNIPPET_ROUNDED = "text_snippet_rounded" - TEXT_SNIPPET_OUTLINED = "text_snippet_outlined" - TEXTSMS = "textsms" - TEXTSMS_SHARP = "textsms_sharp" - TEXTSMS_ROUNDED = "textsms_rounded" - TEXTSMS_OUTLINED = "textsms_outlined" - TEXTURE = "texture" - TEXTURE_SHARP = "texture_sharp" - TEXTURE_ROUNDED = "texture_rounded" - TEXTURE_OUTLINED = "texture_outlined" - THEATER_COMEDY = "theater_comedy" - THEATER_COMEDY_SHARP = "theater_comedy_sharp" - THEATER_COMEDY_ROUNDED = "theater_comedy_rounded" - THEATER_COMEDY_OUTLINED = "theater_comedy_outlined" - THEATERS = "theaters" - THEATERS_SHARP = "theaters_sharp" - THEATERS_ROUNDED = "theaters_rounded" - THEATERS_OUTLINED = "theaters_outlined" - THERMOSTAT = "thermostat" - THERMOSTAT_SHARP = "thermostat_sharp" - THERMOSTAT_ROUNDED = "thermostat_rounded" - THERMOSTAT_OUTLINED = "thermostat_outlined" - THERMOSTAT_AUTO = "thermostat_auto" - THERMOSTAT_AUTO_SHARP = "thermostat_auto_sharp" - THERMOSTAT_AUTO_ROUNDED = "thermostat_auto_rounded" - THERMOSTAT_AUTO_OUTLINED = "thermostat_auto_outlined" - THUMB_DOWN = "thumb_down" - THUMB_DOWN_SHARP = "thumb_down_sharp" - THUMB_DOWN_ROUNDED = "thumb_down_rounded" - THUMB_DOWN_OUTLINED = "thumb_down_outlined" - THUMB_DOWN_ALT = "thumb_down_alt" - THUMB_DOWN_ALT_SHARP = "thumb_down_alt_sharp" - THUMB_DOWN_ALT_ROUNDED = "thumb_down_alt_rounded" - THUMB_DOWN_ALT_OUTLINED = "thumb_down_alt_outlined" - THUMB_DOWN_OFF_ALT = "thumb_down_off_alt" - THUMB_DOWN_OFF_ALT_SHARP = "thumb_down_off_alt_sharp" - THUMB_DOWN_OFF_ALT_ROUNDED = "thumb_down_off_alt_rounded" - THUMB_DOWN_OFF_ALT_OUTLINED = "thumb_down_off_alt_outlined" - THUMB_UP = "thumb_up" - THUMB_UP_SHARP = "thumb_up_sharp" - THUMB_UP_ROUNDED = "thumb_up_rounded" - THUMB_UP_OUTLINED = "thumb_up_outlined" - THUMB_UP_ALT = "thumb_up_alt" - THUMB_UP_ALT_SHARP = "thumb_up_alt_sharp" - THUMB_UP_ALT_ROUNDED = "thumb_up_alt_rounded" - THUMB_UP_ALT_OUTLINED = "thumb_up_alt_outlined" - THUMB_UP_OFF_ALT = "thumb_up_off_alt" - THUMB_UP_OFF_ALT_SHARP = "thumb_up_off_alt_sharp" - THUMB_UP_OFF_ALT_ROUNDED = "thumb_up_off_alt_rounded" - THUMB_UP_OFF_ALT_OUTLINED = "thumb_up_off_alt_outlined" - THUMBS_UP_DOWN = "thumbs_up_down" - THUMBS_UP_DOWN_SHARP = "thumbs_up_down_sharp" - THUMBS_UP_DOWN_ROUNDED = "thumbs_up_down_rounded" - THUMBS_UP_DOWN_OUTLINED = "thumbs_up_down_outlined" - THUNDERSTORM = "thunderstorm" - THUNDERSTORM_SHARP = "thunderstorm_sharp" - THUNDERSTORM_ROUNDED = "thunderstorm_rounded" - THUNDERSTORM_OUTLINED = "thunderstorm_outlined" - TIKTOK = "tiktok" - TIKTOK_SHARP = "tiktok_sharp" - TIKTOK_ROUNDED = "tiktok_rounded" - TIKTOK_OUTLINED = "tiktok_outlined" - TIME_TO_LEAVE = "time_to_leave" - TIME_TO_LEAVE_SHARP = "time_to_leave_sharp" - TIME_TO_LEAVE_ROUNDED = "time_to_leave_rounded" - TIME_TO_LEAVE_OUTLINED = "time_to_leave_outlined" - TIMELAPSE = "timelapse" - TIMELAPSE_SHARP = "timelapse_sharp" - TIMELAPSE_ROUNDED = "timelapse_rounded" - TIMELAPSE_OUTLINED = "timelapse_outlined" - TIMELINE = "timeline" - TIMELINE_SHARP = "timeline_sharp" - TIMELINE_ROUNDED = "timeline_rounded" - TIMELINE_OUTLINED = "timeline_outlined" - TIMER = "timer" - TIMER_SHARP = "timer_sharp" - TIMER_ROUNDED = "timer_rounded" - TIMER_OUTLINED = "timer_outlined" - TIMER_10 = "timer_10" - TIMER_10_SHARP = "timer_10_sharp" - TIMER_10_ROUNDED = "timer_10_rounded" - TIMER_10_OUTLINED = "timer_10_outlined" - TIMER_10_SELECT = "timer_10_select" - TIMER_10_SELECT_SHARP = "timer_10_select_sharp" - TIMER_10_SELECT_ROUNDED = "timer_10_select_rounded" - TIMER_10_SELECT_OUTLINED = "timer_10_select_outlined" - TIMER_3 = "timer_3" - TIMER_3_SHARP = "timer_3_sharp" - TIMER_3_ROUNDED = "timer_3_rounded" - TIMER_3_OUTLINED = "timer_3_outlined" - TIMER_3_SELECT = "timer_3_select" - TIMER_3_SELECT_SHARP = "timer_3_select_sharp" - TIMER_3_SELECT_ROUNDED = "timer_3_select_rounded" - TIMER_3_SELECT_OUTLINED = "timer_3_select_outlined" - TIMER_OFF = "timer_off" - TIMER_OFF_SHARP = "timer_off_sharp" - TIMER_OFF_ROUNDED = "timer_off_rounded" - TIMER_OFF_OUTLINED = "timer_off_outlined" - TIPS_AND_UPDATES = "tips_and_updates" - TIPS_AND_UPDATES_SHARP = "tips_and_updates_sharp" - TIPS_AND_UPDATES_ROUNDED = "tips_and_updates_rounded" - TIPS_AND_UPDATES_OUTLINED = "tips_and_updates_outlined" - TIRE_REPAIR = "tire_repair" - TIRE_REPAIR_SHARP = "tire_repair_sharp" - TIRE_REPAIR_ROUNDED = "tire_repair_rounded" - TIRE_REPAIR_OUTLINED = "tire_repair_outlined" - TITLE = "title" - TITLE_SHARP = "title_sharp" - TITLE_ROUNDED = "title_rounded" - TITLE_OUTLINED = "title_outlined" - TOC = "toc" - TOC_SHARP = "toc_sharp" - TOC_ROUNDED = "toc_rounded" - TOC_OUTLINED = "toc_outlined" - TODAY = "today" - TODAY_SHARP = "today_sharp" - TODAY_ROUNDED = "today_rounded" - TODAY_OUTLINED = "today_outlined" - TOGGLE_OFF = "toggle_off" - TOGGLE_OFF_SHARP = "toggle_off_sharp" - TOGGLE_OFF_ROUNDED = "toggle_off_rounded" - TOGGLE_OFF_OUTLINED = "toggle_off_outlined" - TOGGLE_ON = "toggle_on" - TOGGLE_ON_SHARP = "toggle_on_sharp" - TOGGLE_ON_ROUNDED = "toggle_on_rounded" - TOGGLE_ON_OUTLINED = "toggle_on_outlined" - TOKEN = "token" - TOKEN_SHARP = "token_sharp" - TOKEN_ROUNDED = "token_rounded" - TOKEN_OUTLINED = "token_outlined" - TOLL = "toll" - TOLL_SHARP = "toll_sharp" - TOLL_ROUNDED = "toll_rounded" - TOLL_OUTLINED = "toll_outlined" - TONALITY = "tonality" - TONALITY_SHARP = "tonality_sharp" - TONALITY_ROUNDED = "tonality_rounded" - TONALITY_OUTLINED = "tonality_outlined" - TOPIC = "topic" - TOPIC_SHARP = "topic_sharp" - TOPIC_ROUNDED = "topic_rounded" - TOPIC_OUTLINED = "topic_outlined" - TORNADO = "tornado" - TORNADO_SHARP = "tornado_sharp" - TORNADO_ROUNDED = "tornado_rounded" - TORNADO_OUTLINED = "tornado_outlined" - TOUCH_APP = "touch_app" - TOUCH_APP_SHARP = "touch_app_sharp" - TOUCH_APP_ROUNDED = "touch_app_rounded" - TOUCH_APP_OUTLINED = "touch_app_outlined" - TOUR = "tour" - TOUR_SHARP = "tour_sharp" - TOUR_ROUNDED = "tour_rounded" - TOUR_OUTLINED = "tour_outlined" - TOYS = "toys" - TOYS_SHARP = "toys_sharp" - TOYS_ROUNDED = "toys_rounded" - TOYS_OUTLINED = "toys_outlined" - TRACK_CHANGES = "track_changes" - TRACK_CHANGES_SHARP = "track_changes_sharp" - TRACK_CHANGES_ROUNDED = "track_changes_rounded" - TRACK_CHANGES_OUTLINED = "track_changes_outlined" - TRAFFIC = "traffic" - TRAFFIC_SHARP = "traffic_sharp" - TRAFFIC_ROUNDED = "traffic_rounded" - TRAFFIC_OUTLINED = "traffic_outlined" - TRAIN = "train" - TRAIN_SHARP = "train_sharp" - TRAIN_ROUNDED = "train_rounded" - TRAIN_OUTLINED = "train_outlined" - TRAM = "tram" - TRAM_SHARP = "tram_sharp" - TRAM_ROUNDED = "tram_rounded" - TRAM_OUTLINED = "tram_outlined" - TRANSCRIBE = "transcribe" - TRANSCRIBE_SHARP = "transcribe_sharp" - TRANSCRIBE_ROUNDED = "transcribe_rounded" - TRANSCRIBE_OUTLINED = "transcribe_outlined" - TRANSFER_WITHIN_A_STATION = "transfer_within_a_station" - TRANSFER_WITHIN_A_STATION_SHARP = "transfer_within_a_station_sharp" - TRANSFER_WITHIN_A_STATION_ROUNDED = "transfer_within_a_station_rounded" - TRANSFER_WITHIN_A_STATION_OUTLINED = "transfer_within_a_station_outlined" - TRANSFORM = "transform" - TRANSFORM_SHARP = "transform_sharp" - TRANSFORM_ROUNDED = "transform_rounded" - TRANSFORM_OUTLINED = "transform_outlined" - TRANSGENDER = "transgender" - TRANSGENDER_SHARP = "transgender_sharp" - TRANSGENDER_ROUNDED = "transgender_rounded" - TRANSGENDER_OUTLINED = "transgender_outlined" - TRANSIT_ENTEREXIT = "transit_enterexit" - TRANSIT_ENTEREXIT_SHARP = "transit_enterexit_sharp" - TRANSIT_ENTEREXIT_ROUNDED = "transit_enterexit_rounded" - TRANSIT_ENTEREXIT_OUTLINED = "transit_enterexit_outlined" - TRANSLATE = "translate" - TRANSLATE_SHARP = "translate_sharp" - TRANSLATE_ROUNDED = "translate_rounded" - TRANSLATE_OUTLINED = "translate_outlined" - TRAVEL_EXPLORE = "travel_explore" - TRAVEL_EXPLORE_SHARP = "travel_explore_sharp" - TRAVEL_EXPLORE_ROUNDED = "travel_explore_rounded" - TRAVEL_EXPLORE_OUTLINED = "travel_explore_outlined" - TRENDING_DOWN = "trending_down" - TRENDING_DOWN_SHARP = "trending_down_sharp" - TRENDING_DOWN_ROUNDED = "trending_down_rounded" - TRENDING_DOWN_OUTLINED = "trending_down_outlined" - TRENDING_FLAT = "trending_flat" - TRENDING_FLAT_SHARP = "trending_flat_sharp" - TRENDING_FLAT_ROUNDED = "trending_flat_rounded" - TRENDING_FLAT_OUTLINED = "trending_flat_outlined" - TRENDING_NEUTRAL = "trending_neutral" - TRENDING_NEUTRAL_SHARP = "trending_neutral_sharp" - TRENDING_NEUTRAL_ROUNDED = "trending_neutral_rounded" - TRENDING_NEUTRAL_OUTLINED = "trending_neutral_outlined" - TRENDING_UP = "trending_up" - TRENDING_UP_SHARP = "trending_up_sharp" - TRENDING_UP_ROUNDED = "trending_up_rounded" - TRENDING_UP_OUTLINED = "trending_up_outlined" - TRIP_ORIGIN = "trip_origin" - TRIP_ORIGIN_SHARP = "trip_origin_sharp" - TRIP_ORIGIN_ROUNDED = "trip_origin_rounded" - TRIP_ORIGIN_OUTLINED = "trip_origin_outlined" - TROLLEY = "trolley" - TROUBLESHOOT = "troubleshoot" - TROUBLESHOOT_SHARP = "troubleshoot_sharp" - TROUBLESHOOT_ROUNDED = "troubleshoot_rounded" - TROUBLESHOOT_OUTLINED = "troubleshoot_outlined" - TRY_SMS_STAR = "try_sms_star" - TRY_SMS_STAR_SHARP = "try_sms_star_sharp" - TRY_SMS_STAR_ROUNDED = "try_sms_star_rounded" - TRY_SMS_STAR_OUTLINED = "try_sms_star_outlined" - TSUNAMI = "tsunami" - TSUNAMI_SHARP = "tsunami_sharp" - TSUNAMI_ROUNDED = "tsunami_rounded" - TSUNAMI_OUTLINED = "tsunami_outlined" - TTY = "tty" - TTY_SHARP = "tty_sharp" - TTY_ROUNDED = "tty_rounded" - TTY_OUTLINED = "tty_outlined" - TUNE = "tune" - TUNE_SHARP = "tune_sharp" - TUNE_ROUNDED = "tune_rounded" - TUNE_OUTLINED = "tune_outlined" - TUNGSTEN = "tungsten" - TUNGSTEN_SHARP = "tungsten_sharp" - TUNGSTEN_ROUNDED = "tungsten_rounded" - TUNGSTEN_OUTLINED = "tungsten_outlined" - TURN_LEFT = "turn_left" - TURN_LEFT_SHARP = "turn_left_sharp" - TURN_LEFT_ROUNDED = "turn_left_rounded" - TURN_LEFT_OUTLINED = "turn_left_outlined" - TURN_RIGHT = "turn_right" - TURN_RIGHT_SHARP = "turn_right_sharp" - TURN_RIGHT_ROUNDED = "turn_right_rounded" - TURN_RIGHT_OUTLINED = "turn_right_outlined" - TURN_SHARP_LEFT = "turn_sharp_left" - TURN_SHARP_LEFT_SHARP = "turn_sharp_left_sharp" - TURN_SHARP_LEFT_ROUNDED = "turn_sharp_left_rounded" - TURN_SHARP_LEFT_OUTLINED = "turn_sharp_left_outlined" - TURN_SHARP_RIGHT = "turn_sharp_right" - TURN_SHARP_RIGHT_SHARP = "turn_sharp_right_sharp" - TURN_SHARP_RIGHT_ROUNDED = "turn_sharp_right_rounded" - TURN_SHARP_RIGHT_OUTLINED = "turn_sharp_right_outlined" - TURN_SLIGHT_LEFT = "turn_slight_left" - TURN_SLIGHT_LEFT_SHARP = "turn_slight_left_sharp" - TURN_SLIGHT_LEFT_ROUNDED = "turn_slight_left_rounded" - TURN_SLIGHT_LEFT_OUTLINED = "turn_slight_left_outlined" - TURN_SLIGHT_RIGHT = "turn_slight_right" - TURN_SLIGHT_RIGHT_SHARP = "turn_slight_right_sharp" - TURN_SLIGHT_RIGHT_ROUNDED = "turn_slight_right_rounded" - TURN_SLIGHT_RIGHT_OUTLINED = "turn_slight_right_outlined" - TURNED_IN = "turned_in" - TURNED_IN_SHARP = "turned_in_sharp" - TURNED_IN_ROUNDED = "turned_in_rounded" - TURNED_IN_OUTLINED = "turned_in_outlined" - TURNED_IN_NOT = "turned_in_not" - TURNED_IN_NOT_SHARP = "turned_in_not_sharp" - TURNED_IN_NOT_ROUNDED = "turned_in_not_rounded" - TURNED_IN_NOT_OUTLINED = "turned_in_not_outlined" - TV = "tv" - TV_SHARP = "tv_sharp" - TV_ROUNDED = "tv_rounded" - TV_OUTLINED = "tv_outlined" - TV_OFF = "tv_off" - TV_OFF_SHARP = "tv_off_sharp" - TV_OFF_ROUNDED = "tv_off_rounded" - TV_OFF_OUTLINED = "tv_off_outlined" - TWO_WHEELER = "two_wheeler" - TWO_WHEELER_SHARP = "two_wheeler_sharp" - TWO_WHEELER_ROUNDED = "two_wheeler_rounded" - TWO_WHEELER_OUTLINED = "two_wheeler_outlined" - TYPE_SPECIMEN = "type_specimen" - TYPE_SPECIMEN_SHARP = "type_specimen_sharp" - TYPE_SPECIMEN_ROUNDED = "type_specimen_rounded" - TYPE_SPECIMEN_OUTLINED = "type_specimen_outlined" - U_TURN_LEFT = "u_turn_left" - U_TURN_LEFT_SHARP = "u_turn_left_sharp" - U_TURN_LEFT_ROUNDED = "u_turn_left_rounded" - U_TURN_LEFT_OUTLINED = "u_turn_left_outlined" - U_TURN_RIGHT = "u_turn_right" - U_TURN_RIGHT_SHARP = "u_turn_right_sharp" - U_TURN_RIGHT_ROUNDED = "u_turn_right_rounded" - U_TURN_RIGHT_OUTLINED = "u_turn_right_outlined" - UMBRELLA = "umbrella" - UMBRELLA_SHARP = "umbrella_sharp" - UMBRELLA_ROUNDED = "umbrella_rounded" - UMBRELLA_OUTLINED = "umbrella_outlined" - UNARCHIVE = "unarchive" - UNARCHIVE_SHARP = "unarchive_sharp" - UNARCHIVE_ROUNDED = "unarchive_rounded" - UNARCHIVE_OUTLINED = "unarchive_outlined" - UNDO = "undo" - UNDO_SHARP = "undo_sharp" - UNDO_ROUNDED = "undo_rounded" - UNDO_OUTLINED = "undo_outlined" - UNFOLD_LESS = "unfold_less" - UNFOLD_LESS_SHARP = "unfold_less_sharp" - UNFOLD_LESS_ROUNDED = "unfold_less_rounded" - UNFOLD_LESS_OUTLINED = "unfold_less_outlined" - UNFOLD_LESS_DOUBLE = "unfold_less_double" - UNFOLD_LESS_DOUBLE_SHARP = "unfold_less_double_sharp" - UNFOLD_LESS_DOUBLE_ROUNDED = "unfold_less_double_rounded" - UNFOLD_LESS_DOUBLE_OUTLINED = "unfold_less_double_outlined" - UNFOLD_MORE = "unfold_more" - UNFOLD_MORE_SHARP = "unfold_more_sharp" - UNFOLD_MORE_ROUNDED = "unfold_more_rounded" - UNFOLD_MORE_OUTLINED = "unfold_more_outlined" - UNFOLD_MORE_DOUBLE = "unfold_more_double" - UNFOLD_MORE_DOUBLE_SHARP = "unfold_more_double_sharp" - UNFOLD_MORE_DOUBLE_ROUNDED = "unfold_more_double_rounded" - UNFOLD_MORE_DOUBLE_OUTLINED = "unfold_more_double_outlined" - UNPUBLISHED = "unpublished" - UNPUBLISHED_SHARP = "unpublished_sharp" - UNPUBLISHED_ROUNDED = "unpublished_rounded" - UNPUBLISHED_OUTLINED = "unpublished_outlined" - UNSUBSCRIBE = "unsubscribe" - UNSUBSCRIBE_SHARP = "unsubscribe_sharp" - UNSUBSCRIBE_ROUNDED = "unsubscribe_rounded" - UNSUBSCRIBE_OUTLINED = "unsubscribe_outlined" - UPCOMING = "upcoming" - UPCOMING_SHARP = "upcoming_sharp" - UPCOMING_ROUNDED = "upcoming_rounded" - UPCOMING_OUTLINED = "upcoming_outlined" - UPDATE = "update" - UPDATE_SHARP = "update_sharp" - UPDATE_ROUNDED = "update_rounded" - UPDATE_OUTLINED = "update_outlined" - UPDATE_DISABLED = "update_disabled" - UPDATE_DISABLED_SHARP = "update_disabled_sharp" - UPDATE_DISABLED_ROUNDED = "update_disabled_rounded" - UPDATE_DISABLED_OUTLINED = "update_disabled_outlined" - UPGRADE = "upgrade" - UPGRADE_SHARP = "upgrade_sharp" - UPGRADE_ROUNDED = "upgrade_rounded" - UPGRADE_OUTLINED = "upgrade_outlined" - UPLOAD = "upload" - UPLOAD_SHARP = "upload_sharp" - UPLOAD_ROUNDED = "upload_rounded" - UPLOAD_OUTLINED = "upload_outlined" - UPLOAD_FILE = "upload_file" - UPLOAD_FILE_SHARP = "upload_file_sharp" - UPLOAD_FILE_ROUNDED = "upload_file_rounded" - UPLOAD_FILE_OUTLINED = "upload_file_outlined" - USB = "usb" - USB_SHARP = "usb_sharp" - USB_ROUNDED = "usb_rounded" - USB_OUTLINED = "usb_outlined" - USB_OFF = "usb_off" - USB_OFF_SHARP = "usb_off_sharp" - USB_OFF_ROUNDED = "usb_off_rounded" - USB_OFF_OUTLINED = "usb_off_outlined" - VACCINES = "vaccines" - VACCINES_SHARP = "vaccines_sharp" - VACCINES_ROUNDED = "vaccines_rounded" - VACCINES_OUTLINED = "vaccines_outlined" - VAPE_FREE = "vape_free" - VAPE_FREE_SHARP = "vape_free_sharp" - VAPE_FREE_ROUNDED = "vape_free_rounded" - VAPE_FREE_OUTLINED = "vape_free_outlined" - VAPING_ROOMS = "vaping_rooms" - VAPING_ROOMS_SHARP = "vaping_rooms_sharp" - VAPING_ROOMS_ROUNDED = "vaping_rooms_rounded" - VAPING_ROOMS_OUTLINED = "vaping_rooms_outlined" - VERIFIED = "verified" - VERIFIED_SHARP = "verified_sharp" - VERIFIED_ROUNDED = "verified_rounded" - VERIFIED_OUTLINED = "verified_outlined" - VERIFIED_USER = "verified_user" - VERIFIED_USER_SHARP = "verified_user_sharp" - VERIFIED_USER_ROUNDED = "verified_user_rounded" - VERIFIED_USER_OUTLINED = "verified_user_outlined" - VERTICAL_ALIGN_BOTTOM = "vertical_align_bottom" - VERTICAL_ALIGN_BOTTOM_SHARP = "vertical_align_bottom_sharp" - VERTICAL_ALIGN_BOTTOM_ROUNDED = "vertical_align_bottom_rounded" - VERTICAL_ALIGN_BOTTOM_OUTLINED = "vertical_align_bottom_outlined" - VERTICAL_ALIGN_CENTER = "vertical_align_center" - VERTICAL_ALIGN_CENTER_SHARP = "vertical_align_center_sharp" - VERTICAL_ALIGN_CENTER_ROUNDED = "vertical_align_center_rounded" - VERTICAL_ALIGN_CENTER_OUTLINED = "vertical_align_center_outlined" - VERTICAL_ALIGN_TOP = "vertical_align_top" - VERTICAL_ALIGN_TOP_SHARP = "vertical_align_top_sharp" - VERTICAL_ALIGN_TOP_ROUNDED = "vertical_align_top_rounded" - VERTICAL_ALIGN_TOP_OUTLINED = "vertical_align_top_outlined" - VERTICAL_DISTRIBUTE = "vertical_distribute" - VERTICAL_DISTRIBUTE_SHARP = "vertical_distribute_sharp" - VERTICAL_DISTRIBUTE_ROUNDED = "vertical_distribute_rounded" - VERTICAL_DISTRIBUTE_OUTLINED = "vertical_distribute_outlined" - VERTICAL_SHADES = "vertical_shades" - VERTICAL_SHADES_SHARP = "vertical_shades_sharp" - VERTICAL_SHADES_ROUNDED = "vertical_shades_rounded" - VERTICAL_SHADES_OUTLINED = "vertical_shades_outlined" - VERTICAL_SHADES_CLOSED = "vertical_shades_closed" - VERTICAL_SHADES_CLOSED_SHARP = "vertical_shades_closed_sharp" - VERTICAL_SHADES_CLOSED_ROUNDED = "vertical_shades_closed_rounded" - VERTICAL_SHADES_CLOSED_OUTLINED = "vertical_shades_closed_outlined" - VERTICAL_SPLIT = "vertical_split" - VERTICAL_SPLIT_SHARP = "vertical_split_sharp" - VERTICAL_SPLIT_ROUNDED = "vertical_split_rounded" - VERTICAL_SPLIT_OUTLINED = "vertical_split_outlined" - VIBRATION = "vibration" - VIBRATION_SHARP = "vibration_sharp" - VIBRATION_ROUNDED = "vibration_rounded" - VIBRATION_OUTLINED = "vibration_outlined" - VIDEO_CALL = "video_call" - VIDEO_CALL_SHARP = "video_call_sharp" - VIDEO_CALL_ROUNDED = "video_call_rounded" - VIDEO_CALL_OUTLINED = "video_call_outlined" - VIDEO_CAMERA_BACK = "video_camera_back" - VIDEO_CAMERA_BACK_SHARP = "video_camera_back_sharp" - VIDEO_CAMERA_BACK_ROUNDED = "video_camera_back_rounded" - VIDEO_CAMERA_BACK_OUTLINED = "video_camera_back_outlined" - VIDEO_CAMERA_FRONT = "video_camera_front" - VIDEO_CAMERA_FRONT_SHARP = "video_camera_front_sharp" - VIDEO_CAMERA_FRONT_ROUNDED = "video_camera_front_rounded" - VIDEO_CAMERA_FRONT_OUTLINED = "video_camera_front_outlined" - VIDEO_CHAT = "video_chat" - VIDEO_CHAT_SHARP = "video_chat_sharp" - VIDEO_CHAT_ROUNDED = "video_chat_rounded" - VIDEO_CHAT_OUTLINED = "video_chat_outlined" - VIDEO_COLLECTION = "video_collection" - VIDEO_COLLECTION_SHARP = "video_collection_sharp" - VIDEO_COLLECTION_ROUNDED = "video_collection_rounded" - VIDEO_COLLECTION_OUTLINED = "video_collection_outlined" - VIDEO_FILE = "video_file" - VIDEO_FILE_SHARP = "video_file_sharp" - VIDEO_FILE_ROUNDED = "video_file_rounded" - VIDEO_FILE_OUTLINED = "video_file_outlined" - VIDEO_LABEL = "video_label" - VIDEO_LABEL_SHARP = "video_label_sharp" - VIDEO_LABEL_ROUNDED = "video_label_rounded" - VIDEO_LABEL_OUTLINED = "video_label_outlined" - VIDEO_LIBRARY = "video_library" - VIDEO_LIBRARY_SHARP = "video_library_sharp" - VIDEO_LIBRARY_ROUNDED = "video_library_rounded" - VIDEO_LIBRARY_OUTLINED = "video_library_outlined" - VIDEO_SETTINGS = "video_settings" - VIDEO_SETTINGS_SHARP = "video_settings_sharp" - VIDEO_SETTINGS_ROUNDED = "video_settings_rounded" - VIDEO_SETTINGS_OUTLINED = "video_settings_outlined" - VIDEO_STABLE = "video_stable" - VIDEO_STABLE_SHARP = "video_stable_sharp" - VIDEO_STABLE_ROUNDED = "video_stable_rounded" - VIDEO_STABLE_OUTLINED = "video_stable_outlined" - VIDEOCAM = "videocam" - VIDEOCAM_SHARP = "videocam_sharp" - VIDEOCAM_ROUNDED = "videocam_rounded" - VIDEOCAM_OUTLINED = "videocam_outlined" - VIDEOCAM_OFF = "videocam_off" - VIDEOCAM_OFF_SHARP = "videocam_off_sharp" - VIDEOCAM_OFF_ROUNDED = "videocam_off_rounded" - VIDEOCAM_OFF_OUTLINED = "videocam_off_outlined" - VIDEOGAME_ASSET = "videogame_asset" - VIDEOGAME_ASSET_SHARP = "videogame_asset_sharp" - VIDEOGAME_ASSET_ROUNDED = "videogame_asset_rounded" - VIDEOGAME_ASSET_OUTLINED = "videogame_asset_outlined" - VIDEOGAME_ASSET_OFF = "videogame_asset_off" - VIDEOGAME_ASSET_OFF_SHARP = "videogame_asset_off_sharp" - VIDEOGAME_ASSET_OFF_ROUNDED = "videogame_asset_off_rounded" - VIDEOGAME_ASSET_OFF_OUTLINED = "videogame_asset_off_outlined" - VIEW_AGENDA = "view_agenda" - VIEW_AGENDA_SHARP = "view_agenda_sharp" - VIEW_AGENDA_ROUNDED = "view_agenda_rounded" - VIEW_AGENDA_OUTLINED = "view_agenda_outlined" - VIEW_ARRAY = "view_array" - VIEW_ARRAY_SHARP = "view_array_sharp" - VIEW_ARRAY_ROUNDED = "view_array_rounded" - VIEW_ARRAY_OUTLINED = "view_array_outlined" - VIEW_CAROUSEL = "view_carousel" - VIEW_CAROUSEL_SHARP = "view_carousel_sharp" - VIEW_CAROUSEL_ROUNDED = "view_carousel_rounded" - VIEW_CAROUSEL_OUTLINED = "view_carousel_outlined" - VIEW_COLUMN = "view_column" - VIEW_COLUMN_SHARP = "view_column_sharp" - VIEW_COLUMN_ROUNDED = "view_column_rounded" - VIEW_COLUMN_OUTLINED = "view_column_outlined" - VIEW_COMFORTABLE = "view_comfortable" - VIEW_COMFORTABLE_SHARP = "view_comfortable_sharp" - VIEW_COMFORTABLE_ROUNDED = "view_comfortable_rounded" - VIEW_COMFORTABLE_OUTLINED = "view_comfortable_outlined" - VIEW_COMFY = "view_comfy" - VIEW_COMFY_SHARP = "view_comfy_sharp" - VIEW_COMFY_ROUNDED = "view_comfy_rounded" - VIEW_COMFY_OUTLINED = "view_comfy_outlined" - VIEW_COMFY_ALT = "view_comfy_alt" - VIEW_COMFY_ALT_SHARP = "view_comfy_alt_sharp" - VIEW_COMFY_ALT_ROUNDED = "view_comfy_alt_rounded" - VIEW_COMFY_ALT_OUTLINED = "view_comfy_alt_outlined" - VIEW_COMPACT = "view_compact" - VIEW_COMPACT_SHARP = "view_compact_sharp" - VIEW_COMPACT_ROUNDED = "view_compact_rounded" - VIEW_COMPACT_OUTLINED = "view_compact_outlined" - VIEW_COMPACT_ALT = "view_compact_alt" - VIEW_COMPACT_ALT_SHARP = "view_compact_alt_sharp" - VIEW_COMPACT_ALT_ROUNDED = "view_compact_alt_rounded" - VIEW_COMPACT_ALT_OUTLINED = "view_compact_alt_outlined" - VIEW_COZY = "view_cozy" - VIEW_COZY_SHARP = "view_cozy_sharp" - VIEW_COZY_ROUNDED = "view_cozy_rounded" - VIEW_COZY_OUTLINED = "view_cozy_outlined" - VIEW_DAY = "view_day" - VIEW_DAY_SHARP = "view_day_sharp" - VIEW_DAY_ROUNDED = "view_day_rounded" - VIEW_DAY_OUTLINED = "view_day_outlined" - VIEW_HEADLINE = "view_headline" - VIEW_HEADLINE_SHARP = "view_headline_sharp" - VIEW_HEADLINE_ROUNDED = "view_headline_rounded" - VIEW_HEADLINE_OUTLINED = "view_headline_outlined" - VIEW_IN_AR = "view_in_ar" - VIEW_IN_AR_SHARP = "view_in_ar_sharp" - VIEW_IN_AR_ROUNDED = "view_in_ar_rounded" - VIEW_IN_AR_OUTLINED = "view_in_ar_outlined" - VIEW_KANBAN = "view_kanban" - VIEW_KANBAN_SHARP = "view_kanban_sharp" - VIEW_KANBAN_ROUNDED = "view_kanban_rounded" - VIEW_KANBAN_OUTLINED = "view_kanban_outlined" - VIEW_LIST = "view_list" - VIEW_LIST_SHARP = "view_list_sharp" - VIEW_LIST_ROUNDED = "view_list_rounded" - VIEW_LIST_OUTLINED = "view_list_outlined" - VIEW_MODULE = "view_module" - VIEW_MODULE_SHARP = "view_module_sharp" - VIEW_MODULE_ROUNDED = "view_module_rounded" - VIEW_MODULE_OUTLINED = "view_module_outlined" - VIEW_QUILT = "view_quilt" - VIEW_QUILT_SHARP = "view_quilt_sharp" - VIEW_QUILT_ROUNDED = "view_quilt_rounded" - VIEW_QUILT_OUTLINED = "view_quilt_outlined" - VIEW_SIDEBAR = "view_sidebar" - VIEW_SIDEBAR_SHARP = "view_sidebar_sharp" - VIEW_SIDEBAR_ROUNDED = "view_sidebar_rounded" - VIEW_SIDEBAR_OUTLINED = "view_sidebar_outlined" - VIEW_STREAM = "view_stream" - VIEW_STREAM_SHARP = "view_stream_sharp" - VIEW_STREAM_ROUNDED = "view_stream_rounded" - VIEW_STREAM_OUTLINED = "view_stream_outlined" - VIEW_TIMELINE = "view_timeline" - VIEW_TIMELINE_SHARP = "view_timeline_sharp" - VIEW_TIMELINE_ROUNDED = "view_timeline_rounded" - VIEW_TIMELINE_OUTLINED = "view_timeline_outlined" - VIEW_WEEK = "view_week" - VIEW_WEEK_SHARP = "view_week_sharp" - VIEW_WEEK_ROUNDED = "view_week_rounded" - VIEW_WEEK_OUTLINED = "view_week_outlined" - VIGNETTE = "vignette" - VIGNETTE_SHARP = "vignette_sharp" - VIGNETTE_ROUNDED = "vignette_rounded" - VIGNETTE_OUTLINED = "vignette_outlined" - VILLA = "villa" - VILLA_SHARP = "villa_sharp" - VILLA_ROUNDED = "villa_rounded" - VILLA_OUTLINED = "villa_outlined" - VISIBILITY = "visibility" - VISIBILITY_SHARP = "visibility_sharp" - VISIBILITY_ROUNDED = "visibility_rounded" - VISIBILITY_OUTLINED = "visibility_outlined" - VISIBILITY_OFF = "visibility_off" - VISIBILITY_OFF_SHARP = "visibility_off_sharp" - VISIBILITY_OFF_ROUNDED = "visibility_off_rounded" - VISIBILITY_OFF_OUTLINED = "visibility_off_outlined" - VOICE_CHAT = "voice_chat" - VOICE_CHAT_SHARP = "voice_chat_sharp" - VOICE_CHAT_ROUNDED = "voice_chat_rounded" - VOICE_CHAT_OUTLINED = "voice_chat_outlined" - VOICE_OVER_OFF = "voice_over_off" - VOICE_OVER_OFF_SHARP = "voice_over_off_sharp" - VOICE_OVER_OFF_ROUNDED = "voice_over_off_rounded" - VOICE_OVER_OFF_OUTLINED = "voice_over_off_outlined" - VOICEMAIL = "voicemail" - VOICEMAIL_SHARP = "voicemail_sharp" - VOICEMAIL_ROUNDED = "voicemail_rounded" - VOICEMAIL_OUTLINED = "voicemail_outlined" - VOLCANO = "volcano" - VOLCANO_SHARP = "volcano_sharp" - VOLCANO_ROUNDED = "volcano_rounded" - VOLCANO_OUTLINED = "volcano_outlined" - VOLUME_DOWN = "volume_down" - VOLUME_DOWN_SHARP = "volume_down_sharp" - VOLUME_DOWN_ROUNDED = "volume_down_rounded" - VOLUME_DOWN_OUTLINED = "volume_down_outlined" - VOLUME_DOWN_ALT = "volume_down_alt" - VOLUME_MUTE = "volume_mute" - VOLUME_MUTE_SHARP = "volume_mute_sharp" - VOLUME_MUTE_ROUNDED = "volume_mute_rounded" - VOLUME_MUTE_OUTLINED = "volume_mute_outlined" - VOLUME_OFF = "volume_off" - VOLUME_OFF_SHARP = "volume_off_sharp" - VOLUME_OFF_ROUNDED = "volume_off_rounded" - VOLUME_OFF_OUTLINED = "volume_off_outlined" - VOLUME_UP = "volume_up" - VOLUME_UP_SHARP = "volume_up_sharp" - VOLUME_UP_ROUNDED = "volume_up_rounded" - VOLUME_UP_OUTLINED = "volume_up_outlined" - VOLUNTEER_ACTIVISM = "volunteer_activism" - VOLUNTEER_ACTIVISM_SHARP = "volunteer_activism_sharp" - VOLUNTEER_ACTIVISM_ROUNDED = "volunteer_activism_rounded" - VOLUNTEER_ACTIVISM_OUTLINED = "volunteer_activism_outlined" - VPN_KEY = "vpn_key" - VPN_KEY_SHARP = "vpn_key_sharp" - VPN_KEY_ROUNDED = "vpn_key_rounded" - VPN_KEY_OUTLINED = "vpn_key_outlined" - VPN_KEY_OFF = "vpn_key_off" - VPN_KEY_OFF_SHARP = "vpn_key_off_sharp" - VPN_KEY_OFF_ROUNDED = "vpn_key_off_rounded" - VPN_KEY_OFF_OUTLINED = "vpn_key_off_outlined" - VPN_LOCK = "vpn_lock" - VPN_LOCK_SHARP = "vpn_lock_sharp" - VPN_LOCK_ROUNDED = "vpn_lock_rounded" - VPN_LOCK_OUTLINED = "vpn_lock_outlined" - VRPANO = "vrpano" - VRPANO_SHARP = "vrpano_sharp" - VRPANO_ROUNDED = "vrpano_rounded" - VRPANO_OUTLINED = "vrpano_outlined" - WALLET = "wallet" - WALLET_SHARP = "wallet_sharp" - WALLET_ROUNDED = "wallet_rounded" - WALLET_OUTLINED = "wallet_outlined" - WALLET_GIFTCARD = "wallet_giftcard" - WALLET_GIFTCARD_SHARP = "wallet_giftcard_sharp" - WALLET_GIFTCARD_ROUNDED = "wallet_giftcard_rounded" - WALLET_GIFTCARD_OUTLINED = "wallet_giftcard_outlined" - WALLET_MEMBERSHIP = "wallet_membership" - WALLET_MEMBERSHIP_SHARP = "wallet_membership_sharp" - WALLET_MEMBERSHIP_ROUNDED = "wallet_membership_rounded" - WALLET_MEMBERSHIP_OUTLINED = "wallet_membership_outlined" - WALLET_TRAVEL = "wallet_travel" - WALLET_TRAVEL_SHARP = "wallet_travel_sharp" - WALLET_TRAVEL_ROUNDED = "wallet_travel_rounded" - WALLET_TRAVEL_OUTLINED = "wallet_travel_outlined" - WALLPAPER = "wallpaper" - WALLPAPER_SHARP = "wallpaper_sharp" - WALLPAPER_ROUNDED = "wallpaper_rounded" - WALLPAPER_OUTLINED = "wallpaper_outlined" - WAREHOUSE = "warehouse" - WAREHOUSE_SHARP = "warehouse_sharp" - WAREHOUSE_ROUNDED = "warehouse_rounded" - WAREHOUSE_OUTLINED = "warehouse_outlined" - WARNING = "warning" - WARNING_SHARP = "warning_sharp" - WARNING_ROUNDED = "warning_rounded" - WARNING_OUTLINED = "warning_outlined" - WARNING_AMBER = "warning_amber" - WARNING_AMBER_SHARP = "warning_amber_sharp" - WARNING_AMBER_ROUNDED = "warning_amber_rounded" - WARNING_AMBER_OUTLINED = "warning_amber_outlined" - WASH = "wash" - WASH_SHARP = "wash_sharp" - WASH_ROUNDED = "wash_rounded" - WASH_OUTLINED = "wash_outlined" - WATCH = "watch" - WATCH_SHARP = "watch_sharp" - WATCH_ROUNDED = "watch_rounded" - WATCH_OUTLINED = "watch_outlined" - WATCH_LATER = "watch_later" - WATCH_LATER_SHARP = "watch_later_sharp" - WATCH_LATER_ROUNDED = "watch_later_rounded" - WATCH_LATER_OUTLINED = "watch_later_outlined" - WATCH_OFF = "watch_off" - WATCH_OFF_SHARP = "watch_off_sharp" - WATCH_OFF_ROUNDED = "watch_off_rounded" - WATCH_OFF_OUTLINED = "watch_off_outlined" - WATER = "water" - WATER_SHARP = "water_sharp" - WATER_ROUNDED = "water_rounded" - WATER_OUTLINED = "water_outlined" - WATER_DAMAGE = "water_damage" - WATER_DAMAGE_SHARP = "water_damage_sharp" - WATER_DAMAGE_ROUNDED = "water_damage_rounded" - WATER_DAMAGE_OUTLINED = "water_damage_outlined" - WATER_DROP = "water_drop" - WATER_DROP_SHARP = "water_drop_sharp" - WATER_DROP_ROUNDED = "water_drop_rounded" - WATER_DROP_OUTLINED = "water_drop_outlined" - WATERFALL_CHART = "waterfall_chart" - WATERFALL_CHART_SHARP = "waterfall_chart_sharp" - WATERFALL_CHART_ROUNDED = "waterfall_chart_rounded" - WATERFALL_CHART_OUTLINED = "waterfall_chart_outlined" - WAVES = "waves" - WAVES_SHARP = "waves_sharp" - WAVES_ROUNDED = "waves_rounded" - WAVES_OUTLINED = "waves_outlined" - WAVING_HAND = "waving_hand" - WAVING_HAND_SHARP = "waving_hand_sharp" - WAVING_HAND_ROUNDED = "waving_hand_rounded" - WAVING_HAND_OUTLINED = "waving_hand_outlined" - WB_AUTO = "wb_auto" - WB_AUTO_SHARP = "wb_auto_sharp" - WB_AUTO_ROUNDED = "wb_auto_rounded" - WB_AUTO_OUTLINED = "wb_auto_outlined" - WB_CLOUDY = "wb_cloudy" - WB_CLOUDY_SHARP = "wb_cloudy_sharp" - WB_CLOUDY_ROUNDED = "wb_cloudy_rounded" - WB_CLOUDY_OUTLINED = "wb_cloudy_outlined" - WB_INCANDESCENT = "wb_incandescent" - WB_INCANDESCENT_SHARP = "wb_incandescent_sharp" - WB_INCANDESCENT_ROUNDED = "wb_incandescent_rounded" - WB_INCANDESCENT_OUTLINED = "wb_incandescent_outlined" - WB_IRIDESCENT = "wb_iridescent" - WB_IRIDESCENT_SHARP = "wb_iridescent_sharp" - WB_IRIDESCENT_ROUNDED = "wb_iridescent_rounded" - WB_IRIDESCENT_OUTLINED = "wb_iridescent_outlined" - WB_SHADE = "wb_shade" - WB_SHADE_SHARP = "wb_shade_sharp" - WB_SHADE_ROUNDED = "wb_shade_rounded" - WB_SHADE_OUTLINED = "wb_shade_outlined" - WB_SUNNY = "wb_sunny" - WB_SUNNY_SHARP = "wb_sunny_sharp" - WB_SUNNY_ROUNDED = "wb_sunny_rounded" - WB_SUNNY_OUTLINED = "wb_sunny_outlined" - WB_TWIGHLIGHT = "wb_twighlight" - WB_TWILIGHT = "wb_twilight" - WB_TWILIGHT_SHARP = "wb_twilight_sharp" - WB_TWILIGHT_ROUNDED = "wb_twilight_rounded" - WB_TWILIGHT_OUTLINED = "wb_twilight_outlined" - WC = "wc" - WC_SHARP = "wc_sharp" - WC_ROUNDED = "wc_rounded" - WC_OUTLINED = "wc_outlined" - WEB = "web" - WEB_SHARP = "web_sharp" - WEB_ROUNDED = "web_rounded" - WEB_OUTLINED = "web_outlined" - WEB_ASSET = "web_asset" - WEB_ASSET_SHARP = "web_asset_sharp" - WEB_ASSET_ROUNDED = "web_asset_rounded" - WEB_ASSET_OUTLINED = "web_asset_outlined" - WEB_ASSET_OFF = "web_asset_off" - WEB_ASSET_OFF_SHARP = "web_asset_off_sharp" - WEB_ASSET_OFF_ROUNDED = "web_asset_off_rounded" - WEB_ASSET_OFF_OUTLINED = "web_asset_off_outlined" - WEB_STORIES = "web_stories" - WEB_STORIES_SHARP = "web_stories_sharp" - WEB_STORIES_ROUNDED = "web_stories_rounded" - WEB_STORIES_OUTLINED = "web_stories_outlined" - WEBHOOK = "webhook" - WEBHOOK_SHARP = "webhook_sharp" - WEBHOOK_ROUNDED = "webhook_rounded" - WEBHOOK_OUTLINED = "webhook_outlined" - WECHAT = "wechat" - WECHAT_SHARP = "wechat_sharp" - WECHAT_ROUNDED = "wechat_rounded" - WECHAT_OUTLINED = "wechat_outlined" - WEEKEND = "weekend" - WEEKEND_SHARP = "weekend_sharp" - WEEKEND_ROUNDED = "weekend_rounded" - WEEKEND_OUTLINED = "weekend_outlined" - WEST = "west" - WEST_SHARP = "west_sharp" - WEST_ROUNDED = "west_rounded" - WEST_OUTLINED = "west_outlined" - WHATSHOT = "whatshot" - WHATSHOT_SHARP = "whatshot_sharp" - WHATSHOT_ROUNDED = "whatshot_rounded" - WHATSHOT_OUTLINED = "whatshot_outlined" - WHEELCHAIR_PICKUP = "wheelchair_pickup" - WHEELCHAIR_PICKUP_SHARP = "wheelchair_pickup_sharp" - WHEELCHAIR_PICKUP_ROUNDED = "wheelchair_pickup_rounded" - WHEELCHAIR_PICKUP_OUTLINED = "wheelchair_pickup_outlined" - WHERE_TO_VOTE = "where_to_vote" - WHERE_TO_VOTE_SHARP = "where_to_vote_sharp" - WHERE_TO_VOTE_ROUNDED = "where_to_vote_rounded" - WHERE_TO_VOTE_OUTLINED = "where_to_vote_outlined" - WIDGETS = "widgets" - WIDGETS_SHARP = "widgets_sharp" - WIDGETS_ROUNDED = "widgets_rounded" - WIDGETS_OUTLINED = "widgets_outlined" - WIDTH_FULL = "width_full" - WIDTH_FULL_SHARP = "width_full_sharp" - WIDTH_FULL_ROUNDED = "width_full_rounded" - WIDTH_FULL_OUTLINED = "width_full_outlined" - WIDTH_NORMAL = "width_normal" - WIDTH_NORMAL_SHARP = "width_normal_sharp" - WIDTH_NORMAL_ROUNDED = "width_normal_rounded" - WIDTH_NORMAL_OUTLINED = "width_normal_outlined" - WIDTH_WIDE = "width_wide" - WIDTH_WIDE_SHARP = "width_wide_sharp" - WIDTH_WIDE_ROUNDED = "width_wide_rounded" - WIDTH_WIDE_OUTLINED = "width_wide_outlined" - WIFI = "wifi" - WIFI_SHARP = "wifi_sharp" - WIFI_ROUNDED = "wifi_rounded" - WIFI_OUTLINED = "wifi_outlined" - WIFI_1_BAR = "wifi_1_bar" - WIFI_1_BAR_SHARP = "wifi_1_bar_sharp" - WIFI_1_BAR_ROUNDED = "wifi_1_bar_rounded" - WIFI_1_BAR_OUTLINED = "wifi_1_bar_outlined" - WIFI_2_BAR = "wifi_2_bar" - WIFI_2_BAR_SHARP = "wifi_2_bar_sharp" - WIFI_2_BAR_ROUNDED = "wifi_2_bar_rounded" - WIFI_2_BAR_OUTLINED = "wifi_2_bar_outlined" - WIFI_CALLING = "wifi_calling" - WIFI_CALLING_SHARP = "wifi_calling_sharp" - WIFI_CALLING_ROUNDED = "wifi_calling_rounded" - WIFI_CALLING_OUTLINED = "wifi_calling_outlined" - WIFI_CALLING_3 = "wifi_calling_3" - WIFI_CALLING_3_SHARP = "wifi_calling_3_sharp" - WIFI_CALLING_3_ROUNDED = "wifi_calling_3_rounded" - WIFI_CALLING_3_OUTLINED = "wifi_calling_3_outlined" - WIFI_CHANNEL = "wifi_channel" - WIFI_CHANNEL_SHARP = "wifi_channel_sharp" - WIFI_CHANNEL_ROUNDED = "wifi_channel_rounded" - WIFI_CHANNEL_OUTLINED = "wifi_channel_outlined" - WIFI_FIND = "wifi_find" - WIFI_FIND_SHARP = "wifi_find_sharp" - WIFI_FIND_ROUNDED = "wifi_find_rounded" - WIFI_FIND_OUTLINED = "wifi_find_outlined" - WIFI_LOCK = "wifi_lock" - WIFI_LOCK_SHARP = "wifi_lock_sharp" - WIFI_LOCK_ROUNDED = "wifi_lock_rounded" - WIFI_LOCK_OUTLINED = "wifi_lock_outlined" - WIFI_OFF = "wifi_off" - WIFI_OFF_SHARP = "wifi_off_sharp" - WIFI_OFF_ROUNDED = "wifi_off_rounded" - WIFI_OFF_OUTLINED = "wifi_off_outlined" - WIFI_PASSWORD = "wifi_password" - WIFI_PASSWORD_SHARP = "wifi_password_sharp" - WIFI_PASSWORD_ROUNDED = "wifi_password_rounded" - WIFI_PASSWORD_OUTLINED = "wifi_password_outlined" - WIFI_PROTECTED_SETUP = "wifi_protected_setup" - WIFI_PROTECTED_SETUP_SHARP = "wifi_protected_setup_sharp" - WIFI_PROTECTED_SETUP_ROUNDED = "wifi_protected_setup_rounded" - WIFI_PROTECTED_SETUP_OUTLINED = "wifi_protected_setup_outlined" - WIFI_TETHERING = "wifi_tethering" - WIFI_TETHERING_SHARP = "wifi_tethering_sharp" - WIFI_TETHERING_ROUNDED = "wifi_tethering_rounded" - WIFI_TETHERING_OUTLINED = "wifi_tethering_outlined" - WIFI_TETHERING_ERROR = "wifi_tethering_error" - WIFI_TETHERING_ERROR_SHARP = "wifi_tethering_error_sharp" - WIFI_TETHERING_ERROR_ROUNDED = "wifi_tethering_error_rounded" - WIFI_TETHERING_ERROR_OUTLINED = "wifi_tethering_error_outlined" - WIFI_TETHERING_ERROR_ROUNDED_SHARP = "wifi_tethering_error_rounded_sharp" - WIFI_TETHERING_ERROR_ROUNDED_ROUNDED = "wifi_tethering_error_rounded_rounded" - WIFI_TETHERING_ERROR_ROUNDED_OUTLINED = "wifi_tethering_error_rounded_outlined" - WIFI_TETHERING_OFF = "wifi_tethering_off" - WIFI_TETHERING_OFF_SHARP = "wifi_tethering_off_sharp" - WIFI_TETHERING_OFF_ROUNDED = "wifi_tethering_off_rounded" - WIFI_TETHERING_OFF_OUTLINED = "wifi_tethering_off_outlined" - WIND_POWER = "wind_power" - WIND_POWER_SHARP = "wind_power_sharp" - WIND_POWER_ROUNDED = "wind_power_rounded" - WIND_POWER_OUTLINED = "wind_power_outlined" - WINDOW = "window" - WINDOW_SHARP = "window_sharp" - WINDOW_ROUNDED = "window_rounded" - WINDOW_OUTLINED = "window_outlined" - WINE_BAR = "wine_bar" - WINE_BAR_SHARP = "wine_bar_sharp" - WINE_BAR_ROUNDED = "wine_bar_rounded" - WINE_BAR_OUTLINED = "wine_bar_outlined" - WOMAN = "woman" - WOMAN_SHARP = "woman_sharp" - WOMAN_ROUNDED = "woman_rounded" - WOMAN_OUTLINED = "woman_outlined" - WOMAN_2 = "woman_2" - WOMAN_2_SHARP = "woman_2_sharp" - WOMAN_2_ROUNDED = "woman_2_rounded" - WOMAN_2_OUTLINED = "woman_2_outlined" - WOO_COMMERCE = "woo_commerce" - WOO_COMMERCE_SHARP = "woo_commerce_sharp" - WOO_COMMERCE_ROUNDED = "woo_commerce_rounded" - WOO_COMMERCE_OUTLINED = "woo_commerce_outlined" - WORDPRESS = "wordpress" - WORDPRESS_SHARP = "wordpress_sharp" - WORDPRESS_ROUNDED = "wordpress_rounded" - WORDPRESS_OUTLINED = "wordpress_outlined" - WORK = "work" - WORK_SHARP = "work_sharp" - WORK_ROUNDED = "work_rounded" - WORK_OUTLINED = "work_outlined" - WORK_HISTORY = "work_history" - WORK_HISTORY_SHARP = "work_history_sharp" - WORK_HISTORY_ROUNDED = "work_history_rounded" - WORK_HISTORY_OUTLINED = "work_history_outlined" - WORK_OFF = "work_off" - WORK_OFF_SHARP = "work_off_sharp" - WORK_OFF_ROUNDED = "work_off_rounded" - WORK_OFF_OUTLINED = "work_off_outlined" - WORK_OUTLINE = "work_outline" - WORK_OUTLINE_SHARP = "work_outline_sharp" - WORK_OUTLINE_ROUNDED = "work_outline_rounded" - WORK_OUTLINE_OUTLINED = "work_outline_outlined" - WORKSPACE_PREMIUM = "workspace_premium" - WORKSPACE_PREMIUM_SHARP = "workspace_premium_sharp" - WORKSPACE_PREMIUM_ROUNDED = "workspace_premium_rounded" - WORKSPACE_PREMIUM_OUTLINED = "workspace_premium_outlined" - WORKSPACES = "workspaces" - WORKSPACES_SHARP = "workspaces_sharp" - WORKSPACES_ROUNDED = "workspaces_rounded" - WORKSPACES_OUTLINED = "workspaces_outlined" - WORKSPACES_FILLED = "workspaces_filled" - WORKSPACES_OUTLINE = "workspaces_outline" - WRAP_TEXT = "wrap_text" - WRAP_TEXT_SHARP = "wrap_text_sharp" - WRAP_TEXT_ROUNDED = "wrap_text_rounded" - WRAP_TEXT_OUTLINED = "wrap_text_outlined" - WRONG_LOCATION = "wrong_location" - WRONG_LOCATION_SHARP = "wrong_location_sharp" - WRONG_LOCATION_ROUNDED = "wrong_location_rounded" - WRONG_LOCATION_OUTLINED = "wrong_location_outlined" - WYSIWYG = "wysiwyg" - WYSIWYG_SHARP = "wysiwyg_sharp" - WYSIWYG_ROUNDED = "wysiwyg_rounded" - WYSIWYG_OUTLINED = "wysiwyg_outlined" - YARD = "yard" - YARD_SHARP = "yard_sharp" - YARD_ROUNDED = "yard_rounded" - YARD_OUTLINED = "yard_outlined" - YOUTUBE_SEARCHED_FOR = "youtube_searched_for" - YOUTUBE_SEARCHED_FOR_SHARP = "youtube_searched_for_sharp" - YOUTUBE_SEARCHED_FOR_ROUNDED = "youtube_searched_for_rounded" - YOUTUBE_SEARCHED_FOR_OUTLINED = "youtube_searched_for_outlined" - ZOOM_IN = "zoom_in" - ZOOM_IN_SHARP = "zoom_in_sharp" - ZOOM_IN_ROUNDED = "zoom_in_rounded" - ZOOM_IN_OUTLINED = "zoom_in_outlined" - ZOOM_IN_MAP = "zoom_in_map" - ZOOM_IN_MAP_SHARP = "zoom_in_map_sharp" - ZOOM_IN_MAP_ROUNDED = "zoom_in_map_rounded" - ZOOM_IN_MAP_OUTLINED = "zoom_in_map_outlined" - ZOOM_OUT = "zoom_out" - ZOOM_OUT_SHARP = "zoom_out_sharp" - ZOOM_OUT_ROUNDED = "zoom_out_rounded" - ZOOM_OUT_OUTLINED = "zoom_out_outlined" - ZOOM_OUT_MAP = "zoom_out_map" - ZOOM_OUT_MAP_SHARP = "zoom_out_map_sharp" - ZOOM_OUT_MAP_ROUNDED = "zoom_out_map_rounded" - ZOOM_OUT_MAP_OUTLINED = "zoom_out_map_outlined" diff --git a/sdk/python/packages/flet/src/flet/core/image.py b/sdk/python/packages/flet/src/flet/core/image.py deleted file mode 100644 index c277610d78..0000000000 --- a/sdk/python/packages/flet/src/flet/core/image.py +++ /dev/null @@ -1,308 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import FilterQuality -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BlendMode, - BorderRadiusValue, - ColorEnums, - ColorValue, - ImageFit, - ImageRepeat, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class Image(ConstrainedControl): - """ - A control that displays an image. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Image Example" - - img = ft.Image( - src=f"/icons/icon-512.png", - width=100, - height=100, - fit=ft.ImageFit.CONTAIN, - ) - - page.add(img) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/image - """ - - def __init__( - self, - src: Optional[str] = None, - src_base64: Optional[str] = None, - error_content: Optional[Control] = None, - repeat: Optional[ImageRepeat] = None, - fit: Optional[ImageFit] = None, - border_radius: Optional[BorderRadiusValue] = None, - color: Optional[ColorValue] = None, - color_blend_mode: Optional[BlendMode] = None, - gapless_playback: Optional[bool] = None, - semantics_label: Optional[str] = None, - exclude_from_semantics: Optional[bool] = None, - filter_quality: Optional[FilterQuality] = None, - cache_width: Optional[int] = None, - cache_height: Optional[int] = None, - anti_alias: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.src = src - self.src_base64 = src_base64 - self.error_content = error_content - self.fit = fit - self.repeat = repeat - self.border_radius = border_radius - self.color = color - self.color_blend_mode = color_blend_mode - self.gapless_playback = gapless_playback - self.semantics_label = semantics_label - self.exclude_from_semantics = exclude_from_semantics - self.filter_quality = filter_quality - self.cache_width = cache_width - self.cache_height = cache_height - self.anti_alias = anti_alias - - def _get_control_name(self): - return "image" - - def _get_children(self): - if self.__error_content is not None: - self.__error_content._set_attr_internal("n", "error_content") - return [self.__error_content] - return [] - - def before_update(self): - super().before_update() - self._set_attr_json("borderRadius", self.__border_radius) - - # src - @property - def src(self): - return self._get_attr("src") - - @src.setter - def src(self, value: Optional[str]): - self._set_attr("src", value) - - # src_base64 - @property - def src_base64(self): - return self._get_attr("srcBase64") - - @src_base64.setter - def src_base64(self, value: Optional[str]): - self._set_attr("srcBase64", value) - - # fit - @property - def fit(self) -> Optional[ImageFit]: - return self.__fit - - @fit.setter - def fit(self, value: Optional[ImageFit]): - self.__fit = value - self._set_attr("fit", value.value if isinstance(value, ImageFit) else value) - - # filter_quality - @property - def filter_quality(self) -> Optional[FilterQuality]: - return self.__filter_quality - - @filter_quality.setter - def filter_quality(self, value: Optional[FilterQuality]): - self.__filter_quality = value - self._set_attr( - "filterQuality", value.value if isinstance(value, FilterQuality) else value - ) - - # repeat - @property - def repeat(self) -> Optional[ImageRepeat]: - return self.__repeat - - @repeat.setter - def repeat(self, value: Optional[ImageRepeat]): - self.__repeat = value - self._set_enum_attr("repeat", value, ImageRepeat) - - # cache_width - @property - def cache_width(self) -> Optional[int]: - return self._get_attr("cacheWidth", data_type="int") - - @cache_width.setter - def cache_width(self, value: Optional[int]): - self._set_attr("cacheWidth", value) - - # cache_height - @property - def cache_height(self) -> Optional[int]: - return self._get_attr("cacheHeight", data_type="int") - - @cache_height.setter - def cache_height(self, value: Optional[int]): - self._set_attr("cacheHeight", value) - - # anti_alias - @property - def anti_alias(self) -> Optional[bool]: - return self._get_attr("antiAlias", data_type="bool", def_value=False) - - @anti_alias.setter - def anti_alias(self, value: Optional[bool]): - self._set_attr("antiAlias", value) - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # color_blend_mode - @property - def color_blend_mode(self) -> Optional[BlendMode]: - return self.__blend_mode - - @color_blend_mode.setter - def color_blend_mode(self, value: Optional[BlendMode]): - self.__blend_mode = value - self._set_enum_attr("colorBlendMode", value, BlendMode) - - # gapless_playback - @property - def gapless_playback(self) -> bool: - return self._get_attr("gaplessPlayback", data_type="bool", def_value=False) - - @gapless_playback.setter - def gapless_playback(self, value: Optional[bool]): - self._set_attr("gaplessPlayback", value) - - # exclude_from_semantics - @property - def exclude_from_semantics(self) -> bool: - return self._get_attr("excludeFromSemantics", data_type="bool", def_value=False) - - @exclude_from_semantics.setter - def exclude_from_semantics(self, value: Optional[bool]): - self._set_attr("excludeFromSemantics", value) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # error_content - @property - def error_content(self) -> Optional[Control]: - return self.__error_content - - @error_content.setter - def error_content(self, value: Optional[Control]): - self.__error_content = value diff --git a/sdk/python/packages/flet/src/flet/core/inline_span.py b/sdk/python/packages/flet/src/flet/core/inline_span.py deleted file mode 100644 index 59c74fc841..0000000000 --- a/sdk/python/packages/flet/src/flet/core/inline_span.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control - - -class InlineSpan(Control): - def __init__( - self, - # base - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__(self, ref=ref, visible=visible, disabled=disabled, data=data) diff --git a/sdk/python/packages/flet/src/flet/core/interactive_viewer.py b/sdk/python/packages/flet/src/flet/core/interactive_viewer.py deleted file mode 100644 index 652473da55..0000000000 --- a/sdk/python/packages/flet/src/flet/core/interactive_viewer.py +++ /dev/null @@ -1,395 +0,0 @@ -import json -from typing import Any, Callable, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - DurationValue, - MarginValue, - Number, - Offset, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class InteractiveViewerInteractionStartEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.pointer_count: int = d.get("pc") - self.global_focal_point: Offset = Offset(d.get("fp_x"), d.get("fp_y")) - self.local_focal_point: Offset = Offset(d.get("lfp_x"), d.get("lfp_y")) - - -class InteractiveViewerInteractionUpdateEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.pointer_count: int = d.get("pc") - self.global_focal_point: Offset = Offset(d.get("fp_x"), d.get("fp_y")) - self.local_focal_point: Offset = Offset(d.get("lfp_x"), d.get("lfp_y")) - self.scale: float = d.get("s") - self.horizontal_scale: float = d.get("hs") - self.vertical_scale: float = d.get("vs") - self.rotation: float = d.get("rot") - - -class InteractiveViewerInteractionEndEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.pointer_count: int = d.get("pc") - self.scale_velocity: float = d.get("sv") - - -class InteractiveViewer(ConstrainedControl, AdaptiveControl): - """ - InteractiveViewer allows users to pan, zoom, and rotate content. - - ----- - - Online docs: https://flet.dev/docs/controls/interactiveviewer - """ - - def __init__( - self, - content: Control, - pan_enabled: Optional[bool] = None, - scale_enabled: Optional[bool] = None, - trackpad_scroll_causes_scale: Optional[bool] = None, - constrained: Optional[bool] = None, - max_scale: OptionalNumber = None, - min_scale: OptionalNumber = None, - interaction_end_friction_coefficient: OptionalNumber = None, - scale_factor: OptionalNumber = None, - clip_behavior: Optional[ClipBehavior] = None, - alignment: Optional[Alignment] = None, - boundary_margin: Optional[MarginValue] = None, - interaction_update_interval: Optional[int] = None, - on_interaction_start: Optional[ - Callable[[InteractiveViewerInteractionStartEvent], None] - ] = None, - on_interaction_update: Optional[ - Callable[[InteractiveViewerInteractionUpdateEvent], None] - ] = None, - on_interaction_end: Optional[ - Callable[[InteractiveViewerInteractionEndEvent], None] - ] = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__on_interaction_start = EventHandler( - lambda e: InteractiveViewerInteractionStartEvent(e) - ) - self._add_event_handler( - "interaction_start", self.__on_interaction_start.get_handler() - ) - self.__on_interaction_update = EventHandler( - lambda e: InteractiveViewerInteractionUpdateEvent(e) - ) - self._add_event_handler( - "interaction_update", self.__on_interaction_update.get_handler() - ) - self.__on_interaction_end = EventHandler( - lambda e: InteractiveViewerInteractionEndEvent(e) - ) - self._add_event_handler( - "interaction_end", self.__on_interaction_end.get_handler() - ) - - self.content = content - self.pan_enabled = pan_enabled - self.scale_enabled = scale_enabled - self.trackpad_scroll_causes_scale = trackpad_scroll_causes_scale - self.constrained = constrained - self.max_scale = max_scale - self.min_scale = min_scale - self.interaction_end_friction_coefficient = interaction_end_friction_coefficient - self.scale_factor = scale_factor - self.clip_behavior = clip_behavior - self.alignment = alignment - self.boundary_margin = boundary_margin - self.on_interaction_start = on_interaction_start - self.on_interaction_end = on_interaction_end - self.on_interaction_update = on_interaction_update - self.interaction_update_interval = interaction_update_interval - - def _get_control_name(self): - return "interactiveviewer" - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - assert ( - self.max_scale >= self.min_scale - ), "max_scale must be greather than or equal to min_scale" - self._set_attr_json("alignment", self.__alignment) - self._set_attr_json("boundaryMargin", self.__boundary_margin) - - def _get_children(self): - return [self.__content] - - def reset(self, animation_duration: Optional[DurationValue] = None): - self.invoke_method( - "reset", arguments={"duration": self._convert_attr_json(animation_duration)} - ) - - def save_state(self): - self.invoke_method("save_state") - - def restore_state(self): - self.invoke_method("restore_state") - - def zoom(self, factor: Number): - self.invoke_method("zoom", arguments={"factor": str(factor)}) - - def pan(self, dx: Number, dy: Number): - self.invoke_method("pan", arguments={"dx": str(dx), "dy": str(dy)}) - - # min_scale - @property - def min_scale(self) -> float: - return self._get_attr("minScale", data_type="float", def_value=0.8) - - @min_scale.setter - def min_scale(self, value: OptionalNumber): - assert value is None or value > 0, "min_scale must be greater than 0" - self._set_attr("minScale", value) - - # interaction_update_interval - @property - def interaction_update_interval(self) -> int: - return self._get_attr( - "interactionUpdateInterval", data_type="int", def_value=200 - ) - - @interaction_update_interval.setter - def interaction_update_interval(self, value: Optional[int]): - self._set_attr("interactionUpdateInterval", value) - - # max_scale - @property - def max_scale(self) -> float: - return self._get_attr("maxScale", data_type="float", def_value=2.5) - - @max_scale.setter - def max_scale(self, value: OptionalNumber): - assert value is None or value > 0, "max_scale must be greater than 0" - self._set_attr("maxScale", value) - - # interaction_end_friction_coefficient - @property - def interaction_end_friction_coefficient(self) -> float: - return self._get_attr( - "interactionEndFrictionCoefficient", data_type="float", def_value=0.0000135 - ) - - @interaction_end_friction_coefficient.setter - def interaction_end_friction_coefficient(self, value: OptionalNumber): - assert ( - value is None or value > 0 - ), "interaction_end_friction_coefficient must be greater than 0" - self._set_attr("interactionEndFrictionCoefficient", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # pan_enabled - @property - def pan_enabled(self) -> bool: - return self._get_attr("panEnabled", data_type="bool", def_value=True) - - @pan_enabled.setter - def pan_enabled(self, value: Optional[bool]): - self._set_attr("panEnabled", value) - - # scale_enabled - @property - def scale_enabled(self) -> bool: - return self._get_attr("scaleEnabled", data_type="bool", def_value=True) - - @scale_enabled.setter - def scale_enabled(self, value: Optional[bool]): - self._set_attr("scaleEnabled", value) - - # trackpad_scroll_causes_scale - @property - def trackpad_scroll_causes_scale(self) -> bool: - return self._get_attr( - "trackpadScrollCausesScale", data_type="bool", def_value=False - ) - - @trackpad_scroll_causes_scale.setter - def trackpad_scroll_causes_scale(self, value: Optional[bool]): - self._set_attr("trackpadScrollCausesScale", value) - - # constrained - @property - def constrained(self) -> bool: - return self._get_attr("constrained", data_type="bool", def_value=True) - - @constrained.setter - def constrained(self, value: Optional[bool]): - self._set_attr("constrained", value) - - # scale_factor - @property - def scale_factor(self) -> float: - return self._get_attr("scaleFactor", data_type="float", def_value=200) - - @scale_factor.setter - def scale_factor(self, value: OptionalNumber): - self._set_attr("scaleFactor", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # boundary_margin - @property - def boundary_margin(self) -> Optional[MarginValue]: - return self.__boundary_margin - - @boundary_margin.setter - def boundary_margin(self, value: Optional[MarginValue]): - self.__boundary_margin = value - - # on_interaction_start - @property - def on_interaction_start( - self, - ) -> OptionalEventCallable[InteractiveViewerInteractionStartEvent]: - return self.__on_interaction_start.handler - - @on_interaction_start.setter - def on_interaction_start( - self, - handler: OptionalEventCallable[InteractiveViewerInteractionStartEvent], - ): - self.__on_interaction_start.handler = handler - - # on_interaction_update - @property - def on_interaction_update( - self, - ) -> OptionalEventCallable[InteractiveViewerInteractionUpdateEvent]: - return self.__on_interaction_update.handler - - @on_interaction_update.setter - def on_interaction_update( - self, - handler: OptionalEventCallable[InteractiveViewerInteractionUpdateEvent], - ): - self.__on_interaction_update.handler = handler - - # on_interaction_end - @property - def on_interaction_end( - self, - ) -> OptionalEventCallable[InteractiveViewerInteractionEndEvent]: - return self.__on_interaction_end.handler - - @on_interaction_end.setter - def on_interaction_end( - self, handler: OptionalEventCallable[InteractiveViewerInteractionEndEvent] - ): - self.__on_interaction_end.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/list_tile.py b/sdk/python/packages/flet/src/flet/core/list_tile.py deleted file mode 100644 index 3e2b33a810..0000000000 --- a/sdk/python/packages/flet/src/flet/core/list_tile.py +++ /dev/null @@ -1,588 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, - VisualDensity, -) - - -class ListTileTitleAlignment(Enum): - TOP = "top" - CENTER = "center" - BOTTOM = "bottom" - THREE_LINE = "threeLine" - TITLE_HEIGHT = "titleHeight" - - -class ListTileStyle(Enum): - LIST = "list" - DRAWER = "drawer" - - -class ListTile(ConstrainedControl, AdaptiveControl): - """ - A single fixed-height row that typically contains some text as well as a leading or trailing icon. - - Example: - - ``` - import flet as ft - - def main(page): - page.title = "ListTile Example" - page.add( - ft.Card( - content=ft.Container( - width=500, - content=ft.Column( - [ - ft.ListTile( - title=ft.Text("One-line list tile"), - ), - ft.ListTile( - leading=ft.Icon(ft.icons.SETTINGS), - title=ft.Text("One-line selected list tile"), - selected=True, - ), - ], - spacing=0, - ), - padding=ft.padding.symmetric(vertical=10), - ) - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/listtile - """ - - def __init__( - self, - title: Optional[Control] = None, - subtitle: Optional[Control] = None, - is_three_line: Optional[bool] = None, - leading: Optional[Control] = None, - trailing: Optional[Control] = None, - content_padding: PaddingValue = None, - bgcolor: Optional[ColorValue] = None, - bgcolor_activated: Optional[str] = None, - hover_color: Optional[ColorValue] = None, - selected: Optional[bool] = None, - dense: Optional[bool] = None, - autofocus: Optional[bool] = None, - toggle_inputs: Optional[bool] = None, - selected_color: Optional[ColorValue] = None, - selected_tile_color: Optional[ColorValue] = None, - style: Optional[ListTileStyle] = None, - enable_feedback: Optional[bool] = None, - horizontal_spacing: OptionalNumber = None, - min_leading_width: OptionalNumber = None, - min_vertical_padding: OptionalNumber = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - title_alignment: Optional[ListTileTitleAlignment] = None, - icon_color: Optional[ColorValue] = None, - text_color: Optional[ColorValue] = None, - shape: Optional[OutlinedBorder] = None, - visual_density: Optional[VisualDensity] = None, - mouse_cursor: Optional[MouseCursor] = None, - title_text_style: Optional[TextStyle] = None, - subtitle_text_style: Optional[TextStyle] = None, - leading_and_trailing_text_style: Optional[TextStyle] = None, - min_height: OptionalNumber = None, - on_click: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.content_padding = content_padding - self.leading = leading - self.title = title - self.subtitle = subtitle - self.trailing = trailing - self.is_three_line = is_three_line - self.selected = selected - self.dense = dense - self.autofocus = autofocus - self.toggle_inputs = toggle_inputs - self.url = url - self.url_target = url_target - self.bgcolor = bgcolor - self.bgcolor_activated = bgcolor_activated - self.hover_color = hover_color - self.on_click = on_click - self.on_long_press = on_long_press - self.style = style - self.selected_color = selected_color - self.selected_tile_color = selected_tile_color - self.enable_feedback = enable_feedback - self.horizontal_spacing = horizontal_spacing - self.min_leading_width = min_leading_width - self.min_vertical_padding = min_vertical_padding - self.title_alignment = title_alignment - self.icon_color = icon_color - self.text_color = text_color - self.shape = shape - self.visual_density = visual_density - self.mouse_cursor = mouse_cursor - self.title_text_style = title_text_style - self.subtitle_text_style = subtitle_text_style - self.leading_and_trailing_text_style = leading_and_trailing_text_style - self.min_height = min_height - - def _get_control_name(self): - return "listtile" - - def before_update(self): - super().before_update() - self._set_attr_json("contentPadding", self.__content_padding) - if isinstance(self.__shape, OutlinedBorder): - self._set_attr_json("shape", self.__shape) - if isinstance(self.__title_text_style, TextStyle): - self._set_attr_json("titleTextStyle", self.__title_text_style) - if isinstance(self.__subtitle_text_style, TextStyle): - self._set_attr_json("subtitleTextStyle", self.__subtitle_text_style) - if isinstance(self.__leading_and_trailing_text_style, TextStyle): - self._set_attr_json( - "leadingAndTrailingTextStyle", self.__leading_and_trailing_text_style - ) - - def _get_children(self): - children = [] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__title: - self.__title._set_attr_internal("n", "title") - children.append(self.__title) - if self.__subtitle: - self.__subtitle._set_attr_internal("n", "subtitle") - children.append(self.__subtitle) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - return children - - # content_padding - @property - def content_padding(self) -> Optional[PaddingValue]: - return self.__content_padding - - @content_padding.setter - def content_padding(self, value: Optional[PaddingValue]): - self.__content_padding = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # selected_color - @property - def selected_color(self) -> Optional[ColorValue]: - return self.__selected_color - - @selected_color.setter - def selected_color(self, value: Optional[ColorValue]): - self.__selected_color = value - self._set_enum_attr("selectedColor", value, ColorEnums) - - # selected_tile_color - @property - def selected_tile_color(self) -> Optional[ColorValue]: - return self.__selected_tile_color - - @selected_tile_color.setter - def selected_tile_color(self, value: Optional[ColorValue]): - self.__selected_tile_color = value - self._set_enum_attr("selectedTileColor", value, ColorEnums) - - # bgcolor_activated - @property - def bgcolor_activated(self) -> Optional[str]: - return self._get_attr("bgcolorActivated") - - @bgcolor_activated.setter - def bgcolor_activated(self, value: Optional[str]): - self._set_attr("bgcolorActivated", value) - - # min_leading_width - @property - def min_leading_width(self) -> float: - return self._get_attr("minLeadingWidth", data_type="float", def_value=40.0) - - @min_leading_width.setter - def min_leading_width(self, value: OptionalNumber): - self._set_attr("minLeadingWidth", value) - - # horizontal_spacing - @property - def horizontal_spacing(self) -> float: - return self._get_attr("horizontalSpacing", data_type="float", def_value=16.0) - - @horizontal_spacing.setter - def horizontal_spacing(self, value: OptionalNumber): - self._set_attr("horizontalSpacing", value) - - # min_height - @property - def min_height(self) -> OptionalNumber: - return self._get_attr("minHeight", data_type="float") - - @min_height.setter - def min_height(self, value: OptionalNumber): - self._set_attr("minHeight", value) - - # hover_color - @property - def hover_color(self) -> Optional[ColorValue]: - return self.__hover_color - - @hover_color.setter - def hover_color(self, value: Optional[ColorValue]): - self.__hover_color = value - self._set_enum_attr("hoverColor", value, ColorEnums) - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # title - @property - def title(self) -> Optional[Control]: - return self.__title - - @title.setter - def title(self, value: Optional[Control]): - self.__title = value - - # min_vertical_padding - @property - def min_vertical_padding(self) -> float: - return self._get_attr("minVerticalPadding", data_type="float", def_value=4.0) - - @min_vertical_padding.setter - def min_vertical_padding(self, value: OptionalNumber): - self._set_attr("minVerticalPadding", value) - - # subtitle - @property - def subtitle(self) -> Optional[Control]: - return self.__subtitle - - @subtitle.setter - def subtitle(self, value: Optional[Control]): - self.__subtitle = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # is_three_line - @property - def is_three_line(self) -> bool: - return self._get_attr("isThreeLine", data_type="bool", def_value=False) - - @is_three_line.setter - def is_three_line(self, value: Optional[bool]): - self._set_attr("isThreeLine", value) - - # enable_feedback - @property - def enable_feedback(self) -> bool: - return self._get_attr("enableFeedback", data_type="bool", def_value=True) - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # style - @property - def style(self) -> Optional[ListTileStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ListTileStyle]): - self.__style = value - self._set_enum_attr("style", value, ListTileStyle) - - # title_alignment - @property - def title_alignment(self) -> Optional[ListTileTitleAlignment]: - return self.__title_alignment - - @title_alignment.setter - def title_alignment(self, value: Optional[ListTileTitleAlignment]): - self.__title_alignment = value - self._set_enum_attr("titleAlignment", value, ListTileTitleAlignment) - - # selected - @property - def selected(self) -> bool: - return self._get_attr("selected", data_type="bool", def_value=False) - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # dense - @property - def dense(self) -> bool: - return self._get_attr("dense", data_type="bool", def_value=False) - - @dense.setter - def dense(self, value: Optional[bool]): - self._set_attr("dense", value) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # toggle_inputs - @property - def toggle_inputs(self) -> bool: - return self._get_attr("toggleInputs", data_type="bool", def_value=False) - - @toggle_inputs.setter - def toggle_inputs(self, value: Optional[bool]): - self._set_attr("toggleInputs", value) - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # text_color - @property - def text_color(self) -> Optional[ColorValue]: - return self.__text_color - - @text_color.setter - def text_color(self, value: Optional[ColorValue]): - self.__text_color = value - self._set_enum_attr("textColor", value, ColorEnums) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # visual_density - @property - def visual_density(self) -> Optional[VisualDensity]: - return self.__visual_density - - @visual_density.setter - def visual_density(self, value: Optional[VisualDensity]): - self.__visual_density = value - self._set_enum_attr("visualDensity", value, VisualDensity) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # title_text_style - @property - def title_text_style(self) -> Optional[TextStyle]: - return self.__title_text_style - - @title_text_style.setter - def title_text_style(self, value: Optional[TextStyle]): - self.__title_text_style = value - - # subtitle_text_style - @property - def subtitle_text_style(self) -> Optional[TextStyle]: - return self.__subtitle_text_style - - @subtitle_text_style.setter - def subtitle_text_style(self, value: Optional[TextStyle]): - self.__subtitle_text_style = value - - # leading_and_trailing_text_style - @property - def leading_and_trailing_text_style(self) -> Optional[TextStyle]: - return self.__leading_and_trailing_text_style - - @leading_and_trailing_text_style.setter - def leading_and_trailing_text_style(self, value: Optional[TextStyle]): - self.__leading_and_trailing_text_style = value - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - self._set_attr("onclick", True if handler is not None else None) - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/list_view.py b/sdk/python/packages/flet/src/flet/core/list_view.py deleted file mode 100644 index f74389d263..0000000000 --- a/sdk/python/packages/flet/src/flet/core/list_view.py +++ /dev/null @@ -1,279 +0,0 @@ -from typing import Any, List, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.scrollable_control import OnScrollEvent, ScrollableControl -from flet.core.types import ( - ClipBehavior, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class ListView(ConstrainedControl, ScrollableControl, AdaptiveControl): - """ - A scrollable list of controls arranged linearly. - - ListView is the most commonly used scrolling control. It displays its children one after another in the scroll direction. In the cross axis, the children are required to fill the ListView. - - Example: - - ``` - from time import sleep - import flet as ft - - def main(page: ft.Page): - page.title = "Auto-scrolling ListView" - - lv = ft.ListView(expand=1, spacing=10, padding=20, auto_scroll=True) - - count = 1 - - for i in range(0, 60): - lv.controls.append(ft.Text(f"Line {count}")) - count += 1 - - page.add(lv) - - for i in range(0, 60): - sleep(1) - lv.controls.append(ft.Text(f"Line {count}")) - count += 1 - page.update() - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/listview - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - horizontal: Optional[bool] = None, - spacing: OptionalNumber = None, - item_extent: OptionalNumber = None, - first_item_prototype: Optional[bool] = None, - divider_thickness: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - semantic_child_count: Optional[int] = None, - cache_extent: OptionalNumber = None, - build_controls_on_demand: Optional[bool] = None, - # - # ScrollableControl specific - # - auto_scroll: Optional[bool] = None, - reverse: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: OptionalEventCallable[OnScrollEvent] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - ScrollableControl.__init__( - self, - auto_scroll=auto_scroll, - reverse=reverse, - on_scroll_interval=on_scroll_interval, - on_scroll=on_scroll, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__controls: List[Control] = [] - self.controls = controls - self.horizontal = horizontal - self.spacing = spacing - self.divider_thickness = divider_thickness - self.item_extent = item_extent - self.first_item_prototype = first_item_prototype - self.padding = padding - self.clip_behavior = clip_behavior - self.semantic_child_count = semantic_child_count - self.cache_extent = cache_extent - self.build_controls_on_demand = build_controls_on_demand - - def _get_control_name(self): - return "listview" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - return self.__controls - - def clean(self): - super().clean() - self.__controls.clear() - - # horizontal - @property - def horizontal(self) -> bool: - return self._get_attr("horizontal", data_type="bool", def_value=False) - - @horizontal.setter - def horizontal(self, value: Optional[bool]): - self._set_attr("horizontal", value) - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self._get_attr("spacing", data_type="float") - - @spacing.setter - def spacing(self, value: OptionalNumber): - self._set_attr("spacing", value) - - # divider_thickness - @property - def divider_thickness(self) -> OptionalNumber: - return self._get_attr("dividerThickness") - - @divider_thickness.setter - def divider_thickness(self, value: OptionalNumber): - self._set_attr("dividerThickness", value) - - # item_extent - @property - def item_extent(self) -> OptionalNumber: - return self._get_attr("itemExtent") - - @item_extent.setter - def item_extent(self, value: OptionalNumber): - self._set_attr("itemExtent", value) - - # cache_extent - @property - def cache_extent(self) -> OptionalNumber: - return self._get_attr("cacheExtent", data_type="float") - - @cache_extent.setter - def cache_extent(self, value: OptionalNumber): - self._set_attr("cacheExtent", value) - - # first_item_prototype - @property - def first_item_prototype(self) -> bool: - return self._get_attr("firstItemPrototype", data_type="bool", def_value=False) - - @first_item_prototype.setter - def first_item_prototype(self, value: Optional[bool]): - self._set_attr("firstItemPrototype", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # semantic_child_count - @property - def semantic_child_count(self) -> Optional[int]: - return self._get_attr("semanticChildCount", data_type="int") - - @semantic_child_count.setter - def semantic_child_count(self, value: Optional[int]): - self._set_attr("semanticChildCount", value) - - # build_controls_on_demand - @property - def build_controls_on_demand(self) -> Optional[bool]: - return self._get_attr("buildControlsOnDemand", data_type="bool", def_value=True) - - @build_controls_on_demand.setter - def build_controls_on_demand(self, value: Optional[bool]): - self._set_attr("buildControlsOnDemand", value) diff --git a/sdk/python/packages/flet/src/flet/core/local_connection.py b/sdk/python/packages/flet/src/flet/core/local_connection.py deleted file mode 100644 index 19f63c17c6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/local_connection.py +++ /dev/null @@ -1,261 +0,0 @@ -import logging - -import flet.core -from flet.core.connection import Connection -from flet.core.protocol import * - -logger = logging.getLogger(flet.__name__) - - -class LocalConnection(Connection): - def __init__(self): - super().__init__() - self.__control_id = 1 - self._client_details = None - - def _create_register_web_client_response( - self, controls: Optional[Dict[str, Dict[str, Any]]] = None - ): - assert self._client_details - return ClientMessage( - ClientActions.REGISTER_WEB_CLIENT, - RegisterWebClientResponsePayload( - session=SessionPayload( - id=self._client_details.sessionId, - controls=( - controls - if controls is not None - else { - "page": { - "i": "page", - "t": "page", - "p": "", - "c": [], - "route": self._client_details.pageRoute, - "width": self._client_details.pageWidth, - "height": self._client_details.pageHeight, - "windowwidth": self._client_details.windowWidth, - "windowheight": self._client_details.windowHeight, - "windowtop": self._client_details.windowTop, - "windowleft": self._client_details.windowLeft, - "pwa": self._client_details.isPWA, - "web": self._client_details.isWeb, - "debug": self._client_details.isDebug, - "platform": self._client_details.platform, - "platformBrightness": self._client_details.platformBrightness, - "media": self._client_details.media, - } - } - ), - ), - appInactive=False, - error="", - ), - ) - - def _create_session_handler_arg(self): - assert self._client_details - return PageSessionCreatedPayload( - pageName=self._client_details.pageName, - sessionID=self._client_details.sessionId, - ) - - def _create_page_event_handler_arg(self, msg: ClientMessage): - assert self._client_details - web_event = PageEventFromWebPayload(**msg.payload) - return PageEventPayload( - pageName=self._client_details.pageName, - sessionID=self._client_details.sessionId, - eventTarget=web_event.eventTarget, - eventName=web_event.eventName, - eventData=web_event.eventData, - ) - - def _create_update_control_props_handler_arg(self, msg: ClientMessage): - assert self._client_details - return PageEventPayload( - pageName=self._client_details.pageName, - sessionID=self._client_details.sessionId, - eventTarget="page", - eventName="change", - eventData=json.dumps(msg.payload["props"], separators=(",", ":")), - ) - - def _process_command(self, command: Command): - logger.debug(f"_process_command: {command}") - if command.name == "get": - return self._process_get_command(command.values) - elif command.name == "add": - return self._process_add_command(command) - elif command.name == "set": - return self._process_set_command(command.values, command.attrs) - elif command.name == "remove": - return self._process_remove_command(command.values) - elif command.name == "clean": - return self._process_clean_command(command.values) - elif command.name == "invokeMethod": - return self._process_invoke_method_command(command.values, command.attrs) - elif command.name == "error": - return self._process_error_command(command.values) - elif command.name == "getUploadUrl": - return self._process_get_upload_url_command(command.attrs) - elif command.name == "oauthAuthorize": - return self._process_oauth_authorize_command(command.attrs) - raise Exception(f"Unsupported command: {command.name}") - - def _process_add_command(self, command: Command): - top_parent_id = command.attrs.get("to", "page") - top_parent_at = int(command.attrs.get("at", "-1")) - - batch: List[Command] = [] - if len(command.values) > 0: - batch.append(command) - - for sub_cmd in command.commands: - sub_cmd.name = "add" - batch.append(sub_cmd) - - ids = [] - controls = [] - controls_idx = {} - - i = 0 - for cmd in batch: - assert len(cmd.values) > 0, "control type is not specified" - control_type = cmd.values[0].lower() - - parent_id = "" - parent_at = -1 - - # find nearest parentID - pi = i - 1 - while pi >= 0: - if batch[pi].indent < cmd.indent: - parent_id = batch[pi].attrs.get("id", "") - break - pi -= 1 - - # parent wasn't found - use the topmost one - if parent_id == "": - parent_id = top_parent_id - parent_at = top_parent_at - - id = cmd.attrs.get("id", "") - if not id: - id = f"_{self._get_next_control_id()}" - cmd.attrs["id"] = id - - ids.append(id) - - control = {"t": control_type, "i": id, "p": parent_id, "c": []} - controls.append(control) - controls_idx[id] = control - - if parent_at != -1: - control["at"] = str(parent_at) - top_parent_at += 1 - - parent_control = controls_idx.get(parent_id) - if parent_control: - if parent_at != -1: - parent_control["c"].insert(parent_at, id) - else: - parent_control["c"].append(id) - - system_attrs = ["id", "to", "from", "at", "t", "p", "i", "c"] - for k, v in cmd.attrs.items(): - if k not in system_attrs and v: - control[k] = v - - i += 1 - - return " ".join(ids), ClientMessage( - ClientActions.ADD_PAGE_CONTROLS, AddPageControlsPayload(controls=controls) - ) - - def _process_set_command(self, values, attrs): - assert len(values) == 1, '"set" command has wrong number of values' - props = {"i": values[0]} - for k, v in attrs.items(): - props[k] = v - - return "", ClientMessage( - ClientActions.UPDATE_CONTROL_PROPS, UpdateControlPropsPayload(props=[props]) - ) - - def _process_remove_command(self, values): - assert len(values) > 0, '"remove" command has wrong number of values' - return "", ClientMessage( - ClientActions.REMOVE_CONTROL, RemoveControlPayload(ids=values) - ) - - def _process_clean_command(self, values): - assert len(values) > 0, '"clean" command has wrong number of values' - return "", ClientMessage( - ClientActions.CLEAN_CONTROL, CleanControlPayload(ids=values) - ) - - def _process_error_command(self, values): - assert len(values) == 1, '"error" command has wrong number of values' - return "", ClientMessage( - ClientActions.SESSION_CRASHED, SessionCrashedPayload(message=values[0]) - ) - - def _process_invoke_method_command(self, values, attrs): - # "invokeMethod", values=[method_id, method_name], attrs=arguments - assert len(values) == 3, '"invokeMethod" command has wrong number of values' - return "", ClientMessage( - ClientActions.INVOKE_METHOD, - InvokeMethodPayload( - methodId=values[0], - methodName=values[1], - controlId=values[2], - arguments=attrs, - ), - ) - - def _process_get_upload_url_command(self, attrs): - raise Exception("getUploadUrl command is not supported.") - - def _process_oauth_authorize_command(self, attrs): - raise Exception("oauthAuthorize command is not supported.") - - def _process_get_command(self, values: List[str]): - assert len(values) == 2, '"get" command has wrong number of values' - assert self._client_details - ctrl_id = values[0] - prop_name = values[1] - r = "" - if ctrl_id == "page": - if prop_name == "route": - r = self._client_details.pageRoute - elif prop_name == "pwa": - r = self._client_details.isPWA - elif prop_name == "web": - r = self._client_details.isWeb - elif prop_name == "debug": - r = self._client_details.isDebug - elif prop_name == "platform": - r = self._client_details.platform - elif prop_name == "platformBrightness": - r = self._client_details.platformBrightness - elif prop_name == "media": - r = self._client_details.media - elif prop_name == "width": - r = self._client_details.pageWidth - elif prop_name == "height": - r = self._client_details.pageHeight - elif prop_name == "windowWidth": - r = self._client_details.windowWidth - elif prop_name == "windowHeight": - r = self._client_details.windowHeight - elif prop_name == "windowTop": - r = self._client_details.windowTop - elif prop_name == "windowLeft": - r = self._client_details.windowLeft - return r, None - - def _get_next_control_id(self): - r = self.__control_id - self.__control_id += 1 - return r diff --git a/sdk/python/packages/flet/src/flet/core/locks.py b/sdk/python/packages/flet/src/flet/core/locks.py deleted file mode 100644 index 8074d40c9a..0000000000 --- a/sdk/python/packages/flet/src/flet/core/locks.py +++ /dev/null @@ -1,14 +0,0 @@ -class NopeLock: - def __enter__(self): - pass - - def __exit__(self, *args): - pass - - -class AsyncNopeLock: - async def __aenter__(self): - pass - - async def __aexit__(self, *args): - pass diff --git a/sdk/python/packages/flet/src/flet/core/lottie.py b/sdk/python/packages/flet/src/flet/core/lottie.py deleted file mode 100644 index 9b887fb719..0000000000 --- a/sdk/python/packages/flet/src/flet/core/lottie.py +++ /dev/null @@ -1,208 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import FilterQuality -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ImageFit, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils import deprecated - - -@deprecated( - reason="Lottie control has been moved to a separate Python package: https://pypi.org/project/flet-lottie. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Lottie(ConstrainedControl): - """ - Displays lottie animations. - - ----- - - Online docs: https://flet.dev/docs/controls/lottie - """ - - def __init__( - self, - src: Optional[str] = None, - src_base64: Optional[str] = None, - repeat: Optional[bool] = None, - reverse: Optional[bool] = None, - animate: Optional[bool] = None, - background_loading: Optional[bool] = None, - filter_quality: Optional[FilterQuality] = None, - fit: Optional[ImageFit] = None, - on_error=None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.src = src - self.src_base64 = src_base64 - self.repeat = repeat - self.reverse = reverse - self.animate = animate - self.filter_quality = filter_quality - self.fit = fit - self.background_loading = background_loading - self.on_error = on_error - - def _get_control_name(self): - return "lottie" - - # src - @property - def src(self) -> Optional[str]: - return self._get_attr("src") - - @src.setter - def src(self, value: Optional[str]): - self._set_attr("src", value) - - # src_base64 - @property - def src_base64(self) -> Optional[str]: - return self._get_attr("srcBase64") - - @src_base64.setter - def src_base64(self, value: Optional[str]): - self._set_attr("srcBase64", value) - - # repeat - @property - def repeat(self) -> bool: - return self._get_attr("repeat", def_value=True, data_type="bool") - - @repeat.setter - def repeat(self, value: Optional[bool]): - self._set_attr("repeat", value) - - # animate - @property - def animate(self) -> bool: - return self._get_attr("animate", def_value=True, data_type="bool") - - @animate.setter - def animate(self, value: Optional[bool]): - self._set_attr("animate", value) - - # reverse - @property - def reverse(self) -> bool: - return self._get_attr("reverse", def_value=False, data_type="bool") - - @reverse.setter - def reverse(self, value: Optional[bool]): - self._set_attr("reverse", value) - - # filter_quality - @property - def filter_quality(self) -> Optional[FilterQuality]: - return self.__filter_quality - - @filter_quality.setter - def filter_quality(self, value: Optional[FilterQuality]): - self.__filter_quality = value - self._set_enum_attr("filterQuality", value, FilterQuality) - - # fit - @property - def fit(self) -> Optional[ImageFit]: - return self.__fit - - @fit.setter - def fit(self, value: Optional[ImageFit]): - self.__fit = value - self._set_enum_attr("fit", value, ImageFit) - - # background_loading - @property - def background_loading(self) -> Optional[bool]: - return self._get_attr("backgroundLoading", data_type="bool") - - @background_loading.setter - def background_loading(self, value: Optional[bool]): - self._set_attr("backgroundLoading", value) - - # on_error - @property - def on_error(self) -> OptionalControlEventCallable: - return self._get_event_handler("error") - - @on_error.setter - def on_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("error", handler) - self._set_attr("onError", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/map/circle_layer.py b/sdk/python/packages/flet/src/flet/core/map/circle_layer.py deleted file mode 100644 index 27125fec5b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/circle_layer.py +++ /dev/null @@ -1,156 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.control import Control, OptionalNumber -from flet.core.map.map import MapLatitudeLongitude -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue - - -class CircleMarker(Control): - """ - A circular marker displayed on the Map at the specified location through the CircleLayer. - - ----- - - Online docs: https://flet.dev/docs/controls/mapcirclemarker - """ - - def __init__( - self, - radius: Union[int, float], - coordinates: MapLatitudeLongitude, - color: Optional[ColorValue] = None, - border_color: Optional[ColorValue] = None, - border_stroke_width: OptionalNumber = None, - use_radius_in_meter: Optional[bool] = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.coordinates = coordinates - self.color = color - self.border_color = border_color - self.border_stroke_width = border_stroke_width - self.use_radius_in_meter = use_radius_in_meter - self.radius = radius - - def _get_control_name(self): - return "map_circle_marker" - - def before_update(self): - super().before_update() - self._set_attr_json("coordinates", self.__coordinates) - - # use_radius_in_meter - @property - def use_radius_in_meter(self) -> bool: - return self._get_attr("useRadiusInMeter", data_type="bool", def_value=False) - - @use_radius_in_meter.setter - def use_radius_in_meter(self, value: Optional[bool]): - self._set_attr("useRadiusInMeter", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # border_color - @property - def border_color(self) -> Optional[ColorValue]: - return self.__border_color - - @border_color.setter - def border_color(self, value: Optional[ColorValue]): - self.__border_color = value - self._set_enum_attr("borderColor", value, ColorEnums) - - # radius - @property - def radius(self) -> Union[int, float]: - return self._get_attr("radius", data_type="float") - - @radius.setter - def radius(self, value: Union[int, float]): - self._set_attr("radius", value) - - # border_stroke_width - @property - def border_stroke_width(self) -> OptionalNumber: - return self._get_attr("borderStrokeWidth", data_type="float") - - @border_stroke_width.setter - def border_stroke_width(self, value: OptionalNumber): - assert value is None or value >= 0, "border_stroke_width cannot be negative" - self._set_attr("borderStrokeWidth", value) - - # coordinates - @property - def coordinates(self) -> MapLatitudeLongitude: - return self.__coordinates - - @coordinates.setter - def coordinates(self, value: MapLatitudeLongitude): - self.__coordinates = value - - -class CircleLayer(MapLayer): - """ - A layer to display CircleMarkers. - - ----- - - Online docs: https://flet.dev/docs/controls/mapcirclelayer - """ - - def __init__( - self, - circles: List[CircleMarker], - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.circles = circles - - def _get_control_name(self): - return "map_circle_layer" - - def _get_children(self): - return self.__circles - - # circles - @property - def circles(self) -> List[CircleMarker]: - return self.__circles - - @circles.setter - def circles(self, value: List[CircleMarker]): - self.__circles = value diff --git a/sdk/python/packages/flet/src/flet/core/map/map.py b/sdk/python/packages/flet/src/flet/core/map/map.py deleted file mode 100644 index 3617f29311..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/map.py +++ /dev/null @@ -1,653 +0,0 @@ -import json -from dataclasses import dataclass -from enum import Enum, IntFlag -from typing import Any, List, Optional, Tuple, Union - -from flet.core.animation import AnimationCurve, AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.event_handler import EventHandler -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.transform import Offset -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlEvent, - DurationValue, - Number, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PointerDeviceType, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils import deprecated - - -@dataclass -class MapLatitudeLongitude: - latitude: Union[float, int] - longitude: Union[float, int] - - -@dataclass -class MapLatitudeLongitudeBounds: - corner_1: MapLatitudeLongitude - corner_2: MapLatitudeLongitude - - -class MapInteractiveFlag(IntFlag): - NONE = 0 - DRAG = 1 << 0 - FLING_ANIMATION = 1 << 1 - PINCH_MOVE = 1 << 2 - PINCH_ZOOM = 1 << 3 - DOUBLE_TAP_ZOOM = 1 << 4 - DOUBLE_TAP_DRAG_ZOOM = 1 << 5 - SCROLL_WHEEL_ZOOM = 1 << 6 - ROTATE = 1 << 7 - ALL = ( - (1 << 0) - | (1 << 1) - | (1 << 2) - | (1 << 3) - | (1 << 4) - | (1 << 5) - | (1 << 6) - | (1 << 7) - ) - - -class MapMultiFingerGesture(IntFlag): - NONE = 0 - PINCH_MOVE = 1 << 0 - PINCH_ZOOM = 1 << 1 - ROTATE = 1 << 2 - ALL = (1 << 0) | (1 << 1) | (1 << 2) - - -@dataclass -class MapInteractionConfiguration: - enable_multi_finger_gesture_race: Optional[bool] = None - pinch_move_threshold: OptionalNumber = None - scroll_wheel_velocity: OptionalNumber = None - pinch_zoom_threshold: OptionalNumber = None - rotation_threshold: OptionalNumber = None - flags: Optional[MapInteractiveFlag] = None - rotation_win_gestures: Optional[MapMultiFingerGesture] = None - pinch_move_win_gestures: Optional[MapMultiFingerGesture] = None - pinch_zoom_win_gestures: Optional[MapMultiFingerGesture] = None - - -@deprecated( - reason="Map control has been moved to a separate Python package: https://pypi.org/project/flet-map. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Map(ConstrainedControl): - """ - Map Control. - - ----- - - Online docs: https://flet.dev/docs/controls/map - """ - - def __init__( - self, - layers: List[MapLayer], - initial_center: Optional[MapLatitudeLongitude] = None, - initial_rotation: OptionalNumber = None, - initial_zoom: OptionalNumber = None, - interaction_configuration: Optional[MapInteractionConfiguration] = None, - bgcolor: Optional[ColorValue] = None, - keep_alive: Optional[bool] = None, - max_zoom: OptionalNumber = None, - min_zoom: OptionalNumber = None, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - on_init: OptionalControlEventCallable = None, - on_tap: OptionalEventCallable["MapTapEvent"] = None, - on_hover: OptionalEventCallable["MapHoverEvent"] = None, - on_secondary_tap: OptionalEventCallable["MapTapEvent"] = None, - on_long_press: OptionalEventCallable["MapTapEvent"] = None, - on_event: OptionalEventCallable["MapEvent"] = None, - on_position_change: OptionalEventCallable["MapPositionChangeEvent"] = None, - on_pointer_down: OptionalEventCallable["MapPointerEvent"] = None, - on_pointer_cancel: OptionalEventCallable["MapPointerEvent"] = None, - on_pointer_up: OptionalEventCallable["MapPointerEvent"] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.__on_tap = EventHandler(lambda e: MapTapEvent(e)) - self._add_event_handler("tap", self.__on_tap.get_handler()) - - self.__on_hover = EventHandler(lambda e: MapHoverEvent(e)) - self._add_event_handler("hover", self.__on_hover.get_handler()) - - self.__on_secondary_tap = EventHandler(lambda e: MapTapEvent(e)) - self._add_event_handler("secondary_tap", self.__on_secondary_tap.get_handler()) - - self.__on_long_press = EventHandler(lambda e: MapTapEvent(e)) - self._add_event_handler("long_press", self.__on_long_press.get_handler()) - - self.__on_event = EventHandler(lambda e: MapEvent(e)) - self._add_event_handler("event", self.__on_event.get_handler()) - - self.__on_position_change = EventHandler(lambda e: MapPositionChangeEvent(e)) - self._add_event_handler( - "position_change", self.__on_position_change.get_handler() - ) - - self.__on_pointer_down = EventHandler(lambda e: MapPointerEvent(e)) - self._add_event_handler("pointer_down", self.__on_pointer_down.get_handler()) - - self.__on_pointer_cancel = EventHandler(lambda e: MapPointerEvent(e)) - self._add_event_handler( - "pointer_cancel", self.__on_pointer_cancel.get_handler() - ) - - self.__on_pointer_up = EventHandler(lambda e: MapPointerEvent(e)) - self._add_event_handler("pointer_up", self.__on_pointer_up.get_handler()) - - self.layers = layers - self.initial_center = initial_center - self.initial_rotation = initial_rotation - self.initial_zoom = initial_zoom - self.interaction_configuration = interaction_configuration - self.bgcolor = bgcolor - self.keep_alive = keep_alive - self.max_zoom = max_zoom - self.min_zoom = min_zoom - self.animation_curve = animation_curve - self.animation_duration = animation_duration - self.on_tap = on_tap - self.on_hover = on_hover - self.on_secondary_tap = on_secondary_tap - self.on_init = on_init - self.on_long_press = on_long_press - self.on_event = on_event - self.on_position_change = on_position_change - self.on_pointer_down = on_pointer_down - self.on_pointer_cancel = on_pointer_cancel - self.on_pointer_up = on_pointer_up - - def before_update(self): - self._set_attr_json("initialCenter", self.__initial_center) - self._set_attr_json("animationDuration", self.__animation_duration) - self._set_attr_json( - "interactionConfiguration", self.__interaction_configuration - ) - - def rotate_from( - self, - degree: Number, - animation_curve: Optional[AnimationCurve] = None, - ): - self.invoke_method( - "rotate_from", - arguments={ - "degree": degree, - "curve": animation_curve.value if animation_curve else None, - }, - ) - - def reset_rotation( - self, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - ): - self.invoke_method( - "reset_rotation", - arguments={ - "curve": animation_curve.value if animation_curve else None, - "duration": self._convert_attr_json(animation_duration), - }, - ) - - def zoom_in( - self, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - ): - self.invoke_method( - "zoom_in", - arguments={ - "curve": animation_curve.value if animation_curve else None, - "duration": self._convert_attr_json(animation_duration), - }, - ) - - def zoom_out( - self, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - ): - self.invoke_method( - "zoom_out", - arguments={ - "curve": animation_curve.value if animation_curve else None, - "duration": self._convert_attr_json(animation_duration), - }, - ) - - def zoom_to( - self, - zoom: Number, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - ): - self.invoke_method( - "zoom_to", - arguments={ - "zoom": zoom, - "curve": animation_curve.value if animation_curve else None, - "duration": self._convert_attr_json(animation_duration), - }, - ) - - def move_to( - self, - destination: Optional[MapLatitudeLongitude] = None, - zoom: OptionalNumber = None, - rotation: OptionalNumber = None, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - offset: Optional[Union[Offset, Tuple[Union[Number], Union[Number]]]] = None, - ): - if isinstance(offset, tuple): - offset = Offset(offset[0], offset[1]) - self.invoke_method( - "move_to", - arguments={ - "lat": str(destination.latitude) if destination else None, - "long": str(destination.longitude) if destination else None, - "zoom": zoom, - "ox": str(offset.x) if offset else None, - "oy": str(offset.y) if offset else None, - "rot": rotation, - "curve": animation_curve.value if animation_curve else None, - "duration": self._convert_attr_json(animation_duration), - }, - ) - - def center_on( - self, - point: Optional[MapLatitudeLongitude], - zoom: OptionalNumber, - animation_curve: Optional[AnimationCurve] = None, - animation_duration: Optional[DurationValue] = None, - ): - self.invoke_method( - "center_on", - arguments={ - "lat": str(point.latitude) if point else None, - "long": str(point.longitude) if point else None, - "zoom": zoom, - "curve": animation_curve.value if animation_curve else None, - "duration": self._convert_attr_json(animation_duration), - }, - ) - - def _get_control_name(self): - return "map" - - def _get_children(self): - return self.__layers - - # layers - @property - def layers(self) -> List[MapLayer]: - return self.__layers - - @layers.setter - def layers(self, value: List[MapLayer]): - self.__layers = value - - # initial_center - @property - def initial_center(self) -> Optional[MapLatitudeLongitude]: - return self.__initial_center - - @initial_center.setter - def initial_center(self, value: Optional[MapLatitudeLongitude]): - self.__initial_center = value - - # initial_rotation - @property - def initial_rotation(self) -> OptionalNumber: - return self._get_attr("initialRotation", data_type="float") - - @initial_rotation.setter - def initial_rotation(self, value: OptionalNumber): - self._set_attr("initialRotation", value) - - # initial_zoom - @property - def initial_zoom(self) -> OptionalNumber: - return self._get_attr("initialZoom", data_type="float") - - @initial_zoom.setter - def initial_zoom(self, value: OptionalNumber): - self._set_attr("initialZoom", value) - - # interaction_configuration - @property - def interaction_configuration(self) -> Optional[MapInteractionConfiguration]: - return self.__interaction_configuration - - @interaction_configuration.setter - def interaction_configuration(self, value: Optional[MapInteractionConfiguration]): - self.__interaction_configuration = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # keep_alive - @property - def keep_alive(self) -> Optional[bool]: - return self._get_attr("keepAlive", data_type="bool") - - @keep_alive.setter - def keep_alive(self, value: Optional[bool]): - self._set_attr("keepAlive", value) - - # max_zoom - @property - def max_zoom(self) -> OptionalNumber: - return self._get_attr("maxZoom", data_type="float") - - @max_zoom.setter - def max_zoom(self, value: OptionalNumber): - self._set_attr("maxZoom", value) - - # min_zoom - @property - def min_zoom(self) -> OptionalNumber: - return self._get_attr("minZoom", data_type="float") - - @min_zoom.setter - def min_zoom(self, value: OptionalNumber): - self._set_attr("minZoom", value) - - # animation_curve - @property - def animation_curve(self) -> Optional[AnimationCurve]: - return self.__animation_curve - - @animation_curve.setter - def animation_curve(self, value: Optional[AnimationCurve]): - self.__animation_curve = value - self._set_enum_attr("animationCurve", value, AnimationCurve) - - # animation_duration - @property - def animation_duration(self) -> Optional[DurationValue]: - return self.__animation_duration - - @animation_duration.setter - def animation_duration(self, value: Optional[DurationValue]): - self.__animation_duration = value - - # on_tap - @property - def on_tap(self) -> OptionalEventCallable["MapTapEvent"]: - return self.__on_tap.handler - - @on_tap.setter - def on_tap(self, handler: OptionalEventCallable["MapTapEvent"]): - self.__on_tap.handler = handler - self._set_attr("onTap", True if handler is not None else None) - - # on_hover - @property - def on_hover(self) -> OptionalEventCallable["MapHoverEvent"]: - return self.__on_hover.handler - - @on_hover.setter - def on_hover(self, handler: OptionalEventCallable["MapHoverEvent"]): - self.__on_hover.handler = handler - self._set_attr("onHover", True if handler is not None else None) - - # on_secondary_tap - @property - def on_secondary_tap(self) -> OptionalEventCallable["MapTapEvent"]: - return self.__on_secondary_tap.handler - - @on_secondary_tap.setter - def on_secondary_tap(self, handler: OptionalEventCallable["MapTapEvent"]): - self.__on_secondary_tap.handler = handler - self._set_attr("onSecondaryTap", True if handler is not None else None) - - # on_long_press - @property - def on_long_press(self) -> OptionalEventCallable["MapTapEvent"]: - return self.__on_long_press.handler - - @on_long_press.setter - def on_long_press(self, handler: OptionalEventCallable["MapTapEvent"]): - self.__on_long_press.handler = handler - self._set_attr("onLongPress", True if handler is not None else None) - - # on_event - @property - def on_event(self) -> OptionalEventCallable["MapEvent"]: - return self.__on_event.handler - - @on_event.setter - def on_event(self, handler: OptionalEventCallable["MapEvent"]): - self.__on_event.handler = handler - self._set_attr("onEvent", True if handler is not None else None) - - # on_init - @property - def on_init(self) -> OptionalControlEventCallable: - return self._get_event_handler("init") - - @on_init.setter - def on_init(self, handler: OptionalControlEventCallable): - self._add_event_handler("init", handler) - self._set_attr("onInit", True if handler is not None else None) - - # on_position_change - @property - def on_position_change(self) -> OptionalEventCallable["MapPositionChangeEvent"]: - return self.__on_position_change.handler - - @on_position_change.setter - def on_position_change( - self, handler: OptionalEventCallable["MapPositionChangeEvent"] - ): - self.__on_position_change.handler = handler - self._set_attr("onPositionChange", True if handler is not None else None) - - # on_pointer_down - @property - def on_pointer_down(self) -> OptionalEventCallable["MapPointerEvent"]: - return self.__on_pointer_down.handler - - @on_pointer_down.setter - def on_pointer_down(self, handler: OptionalEventCallable["MapPointerEvent"]): - self.__on_pointer_down.handler = handler - self._set_attr("onPointerDown", True if handler is not None else None) - - # on_pointer_cancel - @property - def on_pointer_cancel(self) -> OptionalEventCallable["MapPointerEvent"]: - return self.__on_pointer_cancel.handler - - @on_pointer_cancel.setter - def on_pointer_cancel(self, handler: OptionalEventCallable["MapPointerEvent"]): - self.__on_pointer_cancel.handler = handler - self._set_attr("onPointerCancel", True if handler is not None else None) - - # on_pointer_up - @property - def on_pointer_up(self) -> OptionalEventCallable["MapPointerEvent"]: - return self.__on_pointer_up.handler - - @on_pointer_up.setter - def on_pointer_up(self, handler: OptionalEventCallable["MapPointerEvent"]): - self.__on_pointer_up.handler = handler - self._set_attr("onPointerUp", True if handler is not None else None) - - -class MapEventSource(Enum): - MAP_CONTROLLER = "mapController" - TAP = "tap" - SECONDARY_TAP = "secondaryTap" - LONG_PRESS = "longPress" - DOUBLE_TAP = "doubleTap" - DOUBLE_TAP_HOLD = "doubleTapHold" - DRAG_START = "dragStart" - ON_DRAG = "onDrag" - DRAG_END = "dragEnd" - MULTI_FINGER_GESTURE_START = "multiFingerGestureStart" - ON_MULTI_FINGER = "onMultiFinger" - MULTI_FINGER_GESTURE_END = "multiFingerEnd" - FLING_ANIMATION_CONTROLLER = "flingAnimationController" - DOUBLE_TAP_ZOOM_ANIMATION_CONTROLLER = "doubleTapZoomAnimationController" - INTERACTIVE_FLAGS_CHANGED = "interactiveFlagsChanged" - FIT_CAMERA = "fitCamera" - CUSTOM = "custom" - SCROLL_WHEEL = "scrollWheel" - NON_ROTATED_SIZE_CHANGE = "nonRotatedSizeChange" - CURSOR_KEYBOARD_ROTATION = "cursorKeyboardRotation" - - -class MapTapEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.local_x: Optional[float] = d.get("lx") - self.local_y: Optional[float] = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.coordinates: MapLatitudeLongitude = MapLatitudeLongitude( - d.get("lat"), d.get("long") - ) - - -class MapHoverEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.local_x: Optional[float] = d.get("lx") - self.local_y: Optional[float] = d.get("ly") - self.global_x: float = d.get("gx") - self.global_y: float = d.get("gy") - self.device_type: PointerDeviceType = PointerDeviceType(d.get("kind")) - self.coordinates: MapLatitudeLongitude = MapLatitudeLongitude( - d.get("lat"), d.get("long") - ) - - -class MapPositionChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.min_zoom: Optional[float] = d.get("min_zoom") - self.max_zoom: Optional[float] = d.get("max_zoom") - self.rotation: float = d.get("rot") - self.coordinates: MapLatitudeLongitude = MapLatitudeLongitude( - d.get("lat"), d.get("long") - ) - - -class MapPointerEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.device_type: PointerDeviceType = PointerDeviceType(d.get("kind")) - self.global_y: float = d.get("gy") - self.global_x: float = d.get("gx") - self.coordinates: MapLatitudeLongitude = MapLatitudeLongitude( - d.get("lat"), d.get("long") - ) - - -class MapEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.source: MapEventSource = MapEventSource(d.get("src")) - self.center: MapLatitudeLongitude = MapLatitudeLongitude( - d.get("c_lat"), d.get("c_long") - ) - self.zoom: float = d.get("zoom") - self.min_zoom: float = d.get("min_zoom") - self.max_zoom: float = d.get("max_zoom") - self.rotation: float = d.get("rot") diff --git a/sdk/python/packages/flet/src/flet/core/map/map_layer.py b/sdk/python/packages/flet/src/flet/core/map/map_layer.py deleted file mode 100644 index 34f912fa2c..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/map_layer.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref - - -class MapLayer(Control): - """ - Abstract class for all map layers. - """ - - def __init__( - self, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) diff --git a/sdk/python/packages/flet/src/flet/core/map/marker_layer.py b/sdk/python/packages/flet/src/flet/core/map/marker_layer.py deleted file mode 100644 index 20e2d1ca9d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/marker_layer.py +++ /dev/null @@ -1,183 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.alignment import Alignment -from flet.core.control import Control, OptionalNumber -from flet.core.map.map import MapLatitudeLongitude -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref - - -class Marker(Control): - """ - A marker displayed on the Map at the specified location through the MarkerLayer. - - ----- - - Online docs: https://flet.dev/docs/controls/mapmarker - """ - - def __init__( - self, - content: Control, - coordinates: MapLatitudeLongitude, - rotate: Optional[bool] = None, - height: OptionalNumber = None, - width: OptionalNumber = None, - alignment: Optional[Alignment] = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.content = content - self.coordinates = coordinates - self.rotate = rotate - self.height = height - self.width = width - self.alignment = alignment - - def _get_control_name(self): - return "map_marker" - - def _get_children(self): - return [self.__content] - - def before_update(self): - super().before_update() - self._set_attr_json("alignment", self.__alignment) - self._set_attr_json("coordinates", self.__coordinates) - - # content - @property - def content(self) -> Optional[Alignment]: - return self.__content - - @content.setter - def content(self, value: Optional[Alignment]): - self.__content = value - - # rotate - @property - def rotate(self) -> bool: - return self._get_attr("rotate", data_type="bool", def_value=False) - - @rotate.setter - def rotate(self, value: Optional[bool]): - self._set_attr("rotate", value) - - # height - @property - def height(self) -> float: - return self._get_attr("height", data_type="float", def_value=30.0) - - @height.setter - def height(self, value: OptionalNumber): - assert value is None or value >= 0, "height cannot be negative" - self._set_attr("height", value) - - # width - @property - def width(self) -> float: - return self._get_attr("width", data_type="float", def_value=30.0) - - @width.setter - def width(self, value: OptionalNumber): - assert value is None or value >= 0, "width cannot be negative" - self._set_attr("width", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # coordinates - @property - def coordinates(self) -> MapLatitudeLongitude: - return self.__coordinates - - @coordinates.setter - def coordinates(self, value: MapLatitudeLongitude): - self.__coordinates = value - - -class MarkerLayer(MapLayer): - """ - A layer to display Markers. - - ----- - - Online docs: https://flet.dev/docs/controls/mapmarkerlayer - """ - - def __init__( - self, - markers: List[Marker], - alignment: Optional[Alignment] = None, - rotate: Optional[bool] = None, - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.markers = markers - self.alignment = alignment - self.rotate = rotate - - def _get_control_name(self): - return "map_marker_layer" - - def _get_children(self): - return self.__markers - - def before_update(self): - super().before_update() - self._set_attr_json("alignment", self.__alignment) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # markers - @property - def markers(self) -> List[Marker]: - return self.__markers - - @markers.setter - def markers(self, value: List[Marker]): - self.__markers = value - - # rotate - @property - def rotate(self) -> bool: - return self._get_attr("rotate", data_type="bool", def_value=False) - - @rotate.setter - def rotate(self, value: Optional[bool]): - self._set_attr("rotate", value) diff --git a/sdk/python/packages/flet/src/flet/core/map/polygon_layer.py b/sdk/python/packages/flet/src/flet/core/map/polygon_layer.py deleted file mode 100644 index 6d5034b5c9..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/polygon_layer.py +++ /dev/null @@ -1,262 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.map.map import MapLatitudeLongitude -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ColorEnums, ColorValue, StrokeCap, StrokeJoin - - -class PolygonMarker(Control): - """ - A marker for the PolygonLayer. - - ----- - - Online docs: https://flet.dev/docs/controls/mappolygonmarker - """ - - def __init__( - self, - coordinates: List[MapLatitudeLongitude], - label: Optional[str] = None, - label_text_style: Optional[TextStyle] = None, - border_color: Optional[ColorValue] = None, - color: Optional[ColorValue] = None, - border_stroke_width: OptionalNumber = None, - disable_holes_border: Optional[bool] = None, - rotate_label: Optional[bool] = None, - stroke_cap: Optional[StrokeCap] = None, - stroke_join: Optional[StrokeJoin] = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.coordinates = coordinates - self.label = label - self.label_text_style = label_text_style - self.border_color = border_color - self.color = color - self.border_stroke_width = border_stroke_width - self.disable_holes_border = disable_holes_border - self.rotate_label = rotate_label - self.stroke_cap = stroke_cap - self.stroke_join = stroke_join - - def _get_control_name(self): - return "map_polygon_marker" - - def before_update(self): - super().before_update() - self._set_attr_json("coordinates", self.__coordinates) - if isinstance(self.__label_text_style, TextStyle): - self._set_attr_json("labelTextStyle", self.__label_text_style) - - # stroke_cap - @property - def stroke_cap(self) -> Optional[StrokeCap]: - return self.__stroke_cap - - @stroke_cap.setter - def stroke_cap(self, value: Optional[StrokeCap]): - self.__stroke_cap = value - self._set_enum_attr("strokeCap", value, StrokeCap) - - # stroke_join - @property - def stroke_join(self) -> Optional[StrokeJoin]: - return self.__stroke_join - - @stroke_join.setter - def stroke_join(self, value: Optional[StrokeJoin]): - self.__stroke_join = value - self._set_enum_attr("strokeJoin", value, StrokeJoin) - - # label_text_style - @property - def label_text_style(self) -> Optional[TextStyle]: - return self.__label_text_style - - @label_text_style.setter - def label_text_style(self, value: Optional[TextStyle]): - self.__label_text_style = value - - # rotate_label - @property - def rotate_label(self) -> bool: - return self._get_attr("rotateLabel", data_type="bool", def_value=False) - - @rotate_label.setter - def rotate_label(self, value: Optional[bool]): - self._set_attr("rotateLabel", value) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # disable_holes_border - @property - def disable_holes_border(self) -> bool: - return self._get_attr("disableHolesBorder", data_type="bool", def_value=False) - - @disable_holes_border.setter - def disable_holes_border(self, value: Optional[bool]): - self._set_attr("disableHolesBorder", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # border_color - @property - def border_color(self) -> Optional[ColorValue]: - return self.__border_color - - @border_color.setter - def border_color(self, value: Optional[ColorValue]): - self.__border_color = value - self._set_enum_attr("borderColor", value, ColorEnums) - - # border_stroke_width - @property - def border_stroke_width(self) -> float: - return self._get_attr("borderStrokeWidth", data_type="float", def_value=0.0) - - @border_stroke_width.setter - def border_stroke_width(self, value: OptionalNumber): - assert value is None or value >= 0, "border_stroke_width cannot be negative" - self._set_attr("borderStrokeWidth", value) - - # coordinates - @property - def coordinates(self) -> List[MapLatitudeLongitude]: - return self.__coordinates - - @coordinates.setter - def coordinates(self, value: List[MapLatitudeLongitude]): - self.__coordinates = value - - -class PolygonLayer(MapLayer): - """ - A layer to display PolygonMarkers. - - ----- - - Online docs: https://flet.dev/docs/controls/mappolygonlayer - """ - - def __init__( - self, - polygons: List[PolygonMarker], - polygon_culling: Optional[bool] = None, - polygon_labels: Optional[bool] = None, - draw_labels_last: Optional[bool] = None, - simplification_tolerance: OptionalNumber = None, - use_alternative_rendering: Optional[bool] = None, - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.polygons = polygons - self.polygon_culling = polygon_culling - self.polygon_labels = polygon_labels - self.draw_labels_last = draw_labels_last - self.simplification_tolerance = simplification_tolerance - self.use_alternative_rendering = use_alternative_rendering - - def _get_control_name(self): - return "map_polygon_layer" - - def _get_children(self): - return self.__polygons - - # polygons - @property - def polygons(self) -> List[PolygonMarker]: - return self.__polygons - - @polygons.setter - def polygons(self, value: List[PolygonMarker]): - self.__polygons = value - - # polygon_culling - @property - def polygon_culling(self) -> bool: - return self._get_attr("polygonCulling", data_type="bool", def_value=False) - - @polygon_culling.setter - def polygon_culling(self, value: Optional[bool]): - self._set_attr("polygonCulling", value) - - # use_alternative_rendering - @property - def use_alternative_rendering(self) -> bool: - return self._get_attr( - "useAlternativeRendering", data_type="bool", def_value=False - ) - - @use_alternative_rendering.setter - def use_alternative_rendering(self, value: Optional[bool]): - self._set_attr("useAlternativeRendering", value) - - # polygon_labels - @property - def polygon_labels(self) -> bool: - return self._get_attr("polygonLabels", data_type="bool", def_value=True) - - @polygon_labels.setter - def polygon_labels(self, value: Optional[bool]): - self._set_attr("polygonLabels", value) - - # simplification_tolerance - @property - def simplification_tolerance(self) -> float: - return self._get_attr( - "simplificationTolerance", data_type="float", def_value=0.5 - ) - - @simplification_tolerance.setter - def simplification_tolerance(self, value: OptionalNumber): - self._set_attr("simplificationTolerance", value) - - # draw_labels_last - @property - def draw_labels_last(self) -> bool: - return self._get_attr("drawLabelsLast", data_type="bool", def_value=False) - - @draw_labels_last.setter - def draw_labels_last(self, value: Optional[bool]): - self._set_attr("drawLabelsLast", value) diff --git a/sdk/python/packages/flet/src/flet/core/map/polyline_layer.py b/sdk/python/packages/flet/src/flet/core/map/polyline_layer.py deleted file mode 100644 index 9bc4698bef..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/polyline_layer.py +++ /dev/null @@ -1,292 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Any, List, Optional, Union - -from flet.core.control import Control, OptionalNumber -from flet.core.map.map import MapLatitudeLongitude -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue, StrokeCap, StrokeJoin - - -class PatternFit(Enum): - SCALE_DOWN = "scaleDown" - SCALE_UP = "scaleUp" - APPEND_DOT = "appendDot" - EXTEND_FINAL_DASH = "extendFinalDash" - - -@dataclass -class StrokePattern: - pass - - -@dataclass -class SolidStrokePattern(StrokePattern): - def __post_init__(self): - self.type = "solid" - - -@dataclass -class DashedStrokePattern(StrokePattern): - segments: Optional[List[Union[float, int]]] = None - pattern_fit: Optional[PatternFit] = PatternFit.SCALE_UP - - def __post_init__(self): - self.type = "dashed" - - -@dataclass -class DottedStrokePattern(StrokePattern): - spacing_factor: OptionalNumber = None - pattern_fit: Optional[PatternFit] = PatternFit.SCALE_UP - - def __post_init__(self): - self.type = "dotted" - - -class PolylineMarker(Control): - """ - A marker for the PolylineLayer. - - ----- - - Online docs: https://flet.dev/docs/controls/mappolylinemarker - """ - - def __init__( - self, - coordinates: List[MapLatitudeLongitude], - colors_stop: Optional[List[Union[float, int]]] = None, - gradient_colors: Optional[List[str]] = None, - border_color: Optional[ColorValue] = None, - color: Optional[ColorValue] = None, - stroke_width: OptionalNumber = None, - border_stroke_width: OptionalNumber = None, - use_stroke_width_in_meter: Optional[bool] = None, - stroke_pattern: Optional[StrokePattern] = None, - stroke_cap: Optional[StrokeCap] = None, - stroke_join: Optional[StrokeJoin] = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.coordinates = coordinates - self.border_color = border_color - self.color = color - self.border_stroke_width = border_stroke_width - self.stroke_width = stroke_width - self.stroke_cap = stroke_cap - self.stroke_join = stroke_join - self.colors_stop = colors_stop - self.gradient_colors = gradient_colors - self.use_stroke_width_in_meter = use_stroke_width_in_meter - self.stroke_pattern = stroke_pattern - - def _get_control_name(self): - return "map_polyline_marker" - - def before_update(self): - super().before_update() - self._set_attr_json("coordinates", self.__coordinates) - if isinstance(self.__colors_stop, list): - self._set_attr_json("colorsStop", self.__colors_stop) - if isinstance(self.__gradient_colors, list): - self._set_attr_json("gradientColors", self.__gradient_colors) - self._set_attr_json("strokePattern", self.__stroke_pattern) - - # stroke_cap - @property - def stroke_cap(self) -> Optional[StrokeCap]: - return self.__stroke_cap - - @stroke_cap.setter - def stroke_cap(self, value: Optional[StrokeCap]): - self.__stroke_cap = value - self._set_enum_attr("strokeCap", value, StrokeCap) - - # gradient_colors - @property - def gradient_colors(self) -> Optional[List[str]]: - return self.__gradient_colors - - @gradient_colors.setter - def gradient_colors(self, value: Optional[List[str]]): - self.__gradient_colors = value - - # stroke_pattern - @property - def stroke_pattern(self) -> Optional[StrokePattern]: - return self.__stroke_pattern - - @stroke_pattern.setter - def stroke_pattern(self, value: Optional[StrokePattern]): - self.__stroke_pattern = value - - # colors_stop - @property - def colors_stop(self) -> Optional[List[Union[float, int]]]: - return self.__colors_stop - - @colors_stop.setter - def colors_stop(self, value: Optional[List[Union[float, int]]]): - self.__colors_stop = value - - # stroke_join - @property - def stroke_join(self) -> Optional[StrokeJoin]: - return self.__stroke_join - - @stroke_join.setter - def stroke_join(self, value: Optional[StrokeJoin]): - self.__stroke_join = value - self._set_enum_attr("strokeJoin", value, StrokeJoin) - - # use_stroke_width_in_meter - @property - def use_stroke_width_in_meter(self) -> bool: - return self._get_attr( - "useStrokeWidthInMeter", data_type="bool", def_value=False - ) - - @use_stroke_width_in_meter.setter - def use_stroke_width_in_meter(self, value: Optional[bool]): - self._set_attr("useStrokeWidthInMeter", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # border_color - @property - def border_color(self) -> Optional[ColorValue]: - return self.__border_color - - @border_color.setter - def border_color(self, value: Optional[ColorValue]): - self.__border_color = value - self._set_enum_attr("borderColor", value, ColorEnums) - - # border_stroke_width - @property - def border_stroke_width(self) -> float: - return self._get_attr("borderStrokeWidth", data_type="float", def_value=0.0) - - @border_stroke_width.setter - def border_stroke_width(self, value: OptionalNumber): - assert value is None or value >= 0, "border_stroke_width cannot be negative" - self._set_attr("borderStrokeWidth", value) - - # stroke_width - @property - def stroke_width(self) -> float: - return self._get_attr("strokeWidth", data_type="float", def_value=1.0) - - @stroke_width.setter - def stroke_width(self, value: OptionalNumber): - assert value is None or value >= 0, "stroke_width cannot be negative" - self._set_attr("strokeWidth", value) - - # coordinates - @property - def coordinates(self) -> List[MapLatitudeLongitude]: - return self.__coordinates - - @coordinates.setter - def coordinates(self, value: List[MapLatitudeLongitude]): - self.__coordinates = value - - -class PolylineLayer(MapLayer): - """ - A layer to display PolylineMarkers. - - ----- - - Online docs: https://flet.dev/docs/controls/mappolylinelayer - """ - - def __init__( - self, - polylines: List[PolylineMarker], - culling_margin: OptionalNumber = None, - min_hittable_radius: OptionalNumber = None, - simplify_tolerance: OptionalNumber = None, - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.polylines = polylines - self.culling_margin = culling_margin - self.min_hittable_radius = min_hittable_radius - self.simplify_tolerance = simplify_tolerance - - def _get_control_name(self): - return "map_polyline_layer" - - def _get_children(self): - return self.__polylines - - # polylines - @property - def polylines(self) -> List[PolylineMarker]: - return self.__polylines - - @polylines.setter - def polylines(self, value: List[PolylineMarker]): - self.__polylines = value - - # culling_margin - @property - def culling_margin(self) -> float: - return self._get_attr("cullingMargin", data_type="float", def_value=10.0) - - @culling_margin.setter - def culling_margin(self, value: OptionalNumber): - self._set_attr("cullingMargin", value) - - # simplification_tolerance - @property - def simplification_tolerance(self) -> float: - return self._get_attr( - "simplificationTolerance", data_type="float", def_value=0.4 - ) - - @simplification_tolerance.setter - def simplification_tolerance(self, value: OptionalNumber): - self._set_attr("simplificationTolerance", value) - - # min_hittable_radius - @property - def min_hittable_radius(self) -> float: - return self._get_attr("minHittableRadius", data_type="float", def_value=10.0) - - @min_hittable_radius.setter - def min_hittable_radius(self, value: OptionalNumber): - self._set_attr("minHittableRadius", value) diff --git a/sdk/python/packages/flet/src/flet/core/map/rich_attribution.py b/sdk/python/packages/flet/src/flet/core/map/rich_attribution.py deleted file mode 100644 index c65ff12a64..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/rich_attribution.py +++ /dev/null @@ -1,141 +0,0 @@ -from enum import Enum -from typing import Any, List, Optional - -from flet.core.border_radius import BorderRadius -from flet.core.control import OptionalNumber -from flet.core.map.map_layer import MapLayer -from flet.core.map.text_source_attribution import TextSourceAttribution -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue - - -class AttributionAlignment(Enum): - BOTTOM_LEFT = "bottomLeft" - BOTTOM_RIGHT = "bottomRight" - - -class RichAttribution(MapLayer): - """ - An animated and interactive attribution layer that supports both logos/images and text - (displayed in a popup controlled by an icon button adjacent to the logos). - - ----- - - Online docs: https://flet.dev/docs/controls/maprichattribution - """ - - def __init__( - self, - attributions: List[TextSourceAttribution], - alignment: Optional[AttributionAlignment] = None, - popup_bgcolor: Optional[ColorValue] = None, - popup_border_radius: Optional[BorderRadius] = None, - popup_initial_display_duration: Optional[int] = None, - permanent_height: OptionalNumber = None, - show_flutter_map_attribution: Optional[bool] = None, - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.attributions = attributions - self.alignment = alignment - self.popup_bgcolor = popup_bgcolor - self.permanent_height = permanent_height - self.show_flutter_map_attribution = show_flutter_map_attribution - self.popup_border_radius = popup_border_radius - self.popup_initial_display_duration = popup_initial_display_duration - - def _get_control_name(self): - return "map_rich_attribution" - - def _get_children(self): - return self.attributions - - def before_update(self): - super().before_update() - self._set_attr_json("popupBorderRadius", self.__popup_border_radius) - self._set_attr_json("alignment", self.__alignment) - - # permanent_height - @property - def permanent_height(self) -> float: - return self._get_attr("permanentHeight", data_type="float", def_value=24.0) - - @permanent_height.setter - def permanent_height(self, value: OptionalNumber): - assert value is None or value >= 0, "permanent_height cannot be negative" - self._set_attr("permanentHeight", value) - - # popup_initial_display_duration - @property - def popup_initial_display_duration(self) -> int: - return self._get_attr( - "popupInitialDisplayDuration", data_type="int", def_value=0 - ) - - @popup_initial_display_duration.setter - def popup_initial_display_duration(self, value: Optional[int]): - assert ( - value is None or value >= 0 - ), "popup_initial_display_duration cannot be negative" - self._set_attr("popupInitialDisplayDuration", value) - - # popup_border_radius - @property - def popup_border_radius(self) -> Optional[BorderRadius]: - return self.__popup_border_radius - - @popup_border_radius.setter - def popup_border_radius(self, value: Optional[BorderRadius]): - self.__popup_border_radius = value - - # alignment - @property - def alignment(self) -> Optional[AttributionAlignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[AttributionAlignment]): - self.__alignment = value - self._set_enum_attr("alignment", value, AttributionAlignment) - - # show_flutter_map_attribution - @property - def show_flutter_map_attribution(self) -> bool: - return self._get_attr( - "showFlutterMapAttribution", data_type="bool", def_value=True - ) - - @show_flutter_map_attribution.setter - def show_flutter_map_attribution(self, value: Optional[bool]): - self._set_attr("showFlutterMapAttribution", value) - - # popup_bgcolor - @property - def popup_bgcolor(self) -> Optional[str]: - return self.__popup_bgcolor - - @popup_bgcolor.setter - def popup_bgcolor(self, value: Optional[str]): - self.__popup_bgcolor = value - self._set_enum_attr("popupBgcolor", value, ColorEnums) - - # attributions - @property - def attributions(self) -> List[TextSourceAttribution]: - return self.__attributions - - @attributions.setter - def attributions(self, value: List[TextSourceAttribution]): - self.__attributions = value diff --git a/sdk/python/packages/flet/src/flet/core/map/simple_attribution.py b/sdk/python/packages/flet/src/flet/core/map/simple_attribution.py deleted file mode 100644 index b61f18c88b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/simple_attribution.py +++ /dev/null @@ -1,86 +0,0 @@ -from typing import Any, Optional - -from flet.core.alignment import Alignment -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue, OptionalControlEventCallable - - -class SimpleAttribution(MapLayer): - """ - A simple attribution layer displayed on the Map. - - ----- - - Online docs: https://flet.dev/docs/controls/mapsimpleattribution - """ - - def __init__( - self, - text: str, - alignment: Optional[Alignment] = None, - bgcolor: Optional[ColorValue] = None, - on_click: OptionalControlEventCallable = None, - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.text = text - self.alignment = alignment - self.bgcolor = bgcolor - self.on_click = on_click - - def _get_control_name(self): - return "map_simple_attribution" - - def before_update(self): - super().before_update() - self._set_attr_json("alignment", self.__alignment) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # text - @property - def text(self) -> str: - return self._get_attr("text") - - @text.setter - def text(self, value: str): - self._set_attr("text", value) - - # on_click - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) diff --git a/sdk/python/packages/flet/src/flet/core/map/text_source_attribution.py b/sdk/python/packages/flet/src/flet/core/map/text_source_attribution.py deleted file mode 100644 index e702035fa5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/text_source_attribution.py +++ /dev/null @@ -1,87 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import OptionalControlEventCallable - - -class TextSourceAttribution(Control): - """ - A text source attribution displayed on the Map. - For it to be displayed, it should be part of a RichAttribution.attributions list. - - ----- - - Online docs: https://flet.dev/docs/controls/maptextsourceattribution - """ - - def __init__( - self, - text: str, - text_style: Optional[TextStyle] = None, - prepend_copyright: Optional[bool] = None, - on_click: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.text = text - self.text_style = text_style - self.prepend_copyright = prepend_copyright - self.on_click = on_click - - def _get_control_name(self): - return "map_text_source_attribution" - - def before_update(self): - super().before_update() - if isinstance(self.__text_style, TextStyle): - self._set_attr_json("textStyle", self.__text_style) - - # text_style - @property - def text_style(self) -> Optional[TextStyle]: - return self.__text_style - - @text_style.setter - def text_style(self, value: Optional[TextStyle]): - self.__text_style = value - - # prepend_copyright - @property - def prepend_copyright(self) -> bool: - return self._get_attr("prependCopyright", data_type="bool", def_value=True) - - @prepend_copyright.setter - def prepend_copyright(self, value: Optional[bool]): - self._set_attr("prependCopyright", value) - - # text - @property - def text(self) -> str: - return self._get_attr("text") - - @text.setter - def text(self, value: str): - self._set_attr("text", value) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) diff --git a/sdk/python/packages/flet/src/flet/core/map/tile_layer.py b/sdk/python/packages/flet/src/flet/core/map/tile_layer.py deleted file mode 100644 index a6153cf257..0000000000 --- a/sdk/python/packages/flet/src/flet/core/map/tile_layer.py +++ /dev/null @@ -1,278 +0,0 @@ -from enum import Enum -from typing import Any, Dict, List, Optional - -from flet.core.control import OptionalNumber -from flet.core.map.map import MapLatitudeLongitudeBounds -from flet.core.map.map_layer import MapLayer -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class MapTileLayerEvictErrorTileStrategy(Enum): - DISPOSE = "dispose" - NOT_VISIBLE = "notVisible" - NOT_VISIBLE_RESPECT_MARGIN = "notVisibleRespectMargin" - - -class TileLayer(MapLayer): - """ - The Map's main layer. - Displays square raster images in a continuous grid, sourced from the provided utl_template. - - ----- - - Online docs: https://flet.dev/docs/controls/maptilelayer - """ - - def __init__( - self, - url_template: str, - fallback_url: Optional[str] = None, - subdomains: Optional[List[str]] = None, - tile_bounds: Optional[MapLatitudeLongitudeBounds] = None, - tile_size: OptionalNumber = None, - min_native_zoom: Optional[int] = None, - max_native_zoom: Optional[int] = None, - zoom_reverse: Optional[bool] = None, - zoom_offset: OptionalNumber = None, - keep_buffer: Optional[int] = None, - pan_buffer: Optional[int] = None, - enable_tms: Optional[bool] = None, - keep_alive: Optional[bool] = None, - enable_retina_mode: Optional[bool] = None, - additional_options: Optional[Dict[str, str]] = None, - max_zoom: OptionalNumber = None, - min_zoom: OptionalNumber = None, - error_image_src: Optional[str] = None, - evict_error_tile_strategy: Optional[MapTileLayerEvictErrorTileStrategy] = None, - on_image_error: OptionalControlEventCallable = None, - # - # MapLayer - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - MapLayer.__init__( - self, - ref=ref, - visible=visible, - data=data, - ) - - self.url_template = url_template - self.fallback_url = fallback_url - self.tile_size = tile_size - self.min_native_zoom = min_native_zoom - self.max_native_zoom = max_native_zoom - self.zoom_reverse = zoom_reverse - self.zoom_offset = zoom_offset - self.keep_buffer = keep_buffer - self.pan_buffer = pan_buffer - self.enable_tms = enable_tms - self.keep_alive = keep_alive - self.max_zoom = max_zoom - self.min_zoom = min_zoom - self.error_image_src = error_image_src - self.enable_retina_mode = enable_retina_mode - self.on_image_error = on_image_error - self.tile_bounds = tile_bounds - self.evict_error_tile_strategy = evict_error_tile_strategy - self.subdomains = subdomains - self.additional_options = additional_options - - def _get_control_name(self): - return "map_tile_layer" - - def before_update(self): - super().before_update() - assert self.url_template, "url_template is required" - if isinstance(self.__tile_bounds, MapLatitudeLongitudeBounds): - self._set_attr_json("tileBounds", self.__tile_bounds) - if isinstance(self.__subdomains, list): - self._set_attr_json("subdomains", self.__subdomains) - if isinstance(self.__additional_options, dict): - self._set_attr_json("additionalOptions", self.__additional_options) - - # url_template - @property - def url_template(self) -> str: - return self._get_attr("urlTemplate") - - @url_template.setter - def url_template(self, value: str): - self._set_attr("urlTemplate", value) - - # fallback_url - @property - def fallback_url(self) -> Optional[str]: - return self._get_attr("fallbackUrl") - - @fallback_url.setter - def fallback_url(self, value: Optional[str]): - self._set_attr("fallbackUrl", value) - - # subdomains - @property - def subdomains(self) -> Optional[List[str]]: - return self.__subdomains - - @subdomains.setter - def subdomains(self, value: Optional[List[str]]): - self.__subdomains = value - - # additional_options - @property - def additional_options(self) -> Optional[Dict[str, str]]: - return self.__additional_options - - @additional_options.setter - def additional_options(self, value: Optional[Dict[str, str]]): - self.__additional_options = value - - # tile_bounds - @property - def tile_bounds(self) -> Optional[MapLatitudeLongitudeBounds]: - return self.__tile_bounds - - @tile_bounds.setter - def tile_bounds(self, value: Optional[MapLatitudeLongitudeBounds]): - self.__tile_bounds = value - - # tile_size - @property - def tile_size(self) -> float: - return self._get_attr("tileSize", data_type="float", def_value=256.0) - - @tile_size.setter - def tile_size(self, value: OptionalNumber): - assert value is None or value >= 0, "tile_size cannot be negative" - self._set_attr("tileSize", value) - - # min_native_zoom - @property - def min_native_zoom(self) -> int: - return self._get_attr("minNativeZoom", data_type="int", def_value=0.0) - - @min_native_zoom.setter - def min_native_zoom(self, value: Optional[int]): - assert value is None or value >= 0, "min_native_zoom cannot be negative" - self._set_attr("minNativeZoom", value) - - # max_native_zoom - @property - def max_native_zoom(self) -> int: - return self._get_attr("maxNativeZoom", data_type="int", def_value=19) - - @max_native_zoom.setter - def max_native_zoom(self, value: Optional[int]): - assert value is None or value >= 0, "max_native_zoom cannot be negative" - self._set_attr("maxNativeZoom", value) - - # zoom_reverse - @property - def zoom_reverse(self) -> bool: - return self._get_attr("zoomReverse", data_type="bool", def_value=False) - - @zoom_reverse.setter - def zoom_reverse(self, value: Optional[bool]): - self._set_attr("zoomReverse", value) - - # zoom_offset - @property - def zoom_offset(self) -> float: - return self._get_attr("zoomOffset", data_type="float", def_value=0.0) - - @zoom_offset.setter - def zoom_offset(self, value: OptionalNumber): - assert value is None or value >= 0, "zoom_offset cannot be negative" - self._set_attr("zoomOffset", value) - - # keep_buffer - @property - def keep_buffer(self) -> int: - return self._get_attr("keepBuffer", data_type="int", def_value=2) - - @keep_buffer.setter - def keep_buffer(self, value: Optional[int]): - self._set_attr("keepBuffer", value) - - # pan_buffer - @property - def pan_buffer(self) -> int: - return self._get_attr("panBuffer", data_type="int", def_value=2) - - @pan_buffer.setter - def pan_buffer(self, value: Optional[int]): - self._set_attr("panBuffer", value) - - # enable_tms - @property - def enable_tms(self) -> bool: - return self._get_attr("enableTms", data_type="bool", def_value=False) - - @enable_tms.setter - def enable_tms(self, value: Optional[bool]): - self._set_attr("enableTms", value) - - # enable_retina_mode - @property - def enable_retina_mode(self) -> bool: - return self._get_attr("enableRetinaMode", data_type="bool", def_value=False) - - @enable_retina_mode.setter - def enable_retina_mode(self, value: Optional[bool]): - self._set_attr("enableRetinaMode", value) - - # max_zoom - @property - def max_zoom(self) -> float: - return self._get_attr("maxZoom", data_type="float", def_value=float("inf")) - - @max_zoom.setter - def max_zoom(self, value: OptionalNumber): - assert value is None or value >= 0, "max_zoom cannot be negative" - self._set_attr("maxZoom", value) - - # min_zoom - @property - def min_zoom(self) -> float: - return self._get_attr("minZoom", data_type="float", def_value=0.0) - - @min_zoom.setter - def min_zoom(self, value: OptionalNumber): - assert value is None or value >= 0, "min_zoom cannot be negative" - self._set_attr("minZoom", value) - - # error_image_src - @property - def error_image_src(self) -> Optional[str]: - return self._get_attr("errorImageSrc") - - @error_image_src.setter - def error_image_src(self, value: Optional[str]): - self._set_attr("errorImageSrc", value) - - # evict_error_tile_strategy - @property - def evict_error_tile_strategy(self) -> Optional[MapTileLayerEvictErrorTileStrategy]: - return self.__evict_error_tile_strategy - - @evict_error_tile_strategy.setter - def evict_error_tile_strategy( - self, value: Optional[MapTileLayerEvictErrorTileStrategy] - ): - self.__evict_error_tile_strategy = value - self._set_enum_attr( - "evictErrorTileStrategy", value, MapTileLayerEvictErrorTileStrategy - ) - - # on_image_error - @property - def on_image_error(self) -> OptionalControlEventCallable: - return self._get_event_handler("imageError") - - @on_image_error.setter - def on_image_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("imageError", handler) diff --git a/sdk/python/packages/flet/src/flet/core/margin.py b/sdk/python/packages/flet/src/flet/core/margin.py deleted file mode 100644 index 867b783dc8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/margin.py +++ /dev/null @@ -1,24 +0,0 @@ -import dataclasses -from typing import Union - - -@dataclasses.dataclass -class Margin: - left: Union[float, int] - top: Union[float, int] - right: Union[float, int] - bottom: Union[float, int] - - -def all(value: float) -> Margin: - return Margin(left=value, top=value, right=value, bottom=value) - - -def symmetric(vertical: float = 0, horizontal: float = 0) -> Margin: - return Margin(left=horizontal, top=vertical, right=horizontal, bottom=vertical) - - -def only( - left: float = 0, top: float = 0, right: float = 0, bottom: float = 0 -) -> Margin: - return Margin(left=left, top=top, right=right, bottom=bottom) diff --git a/sdk/python/packages/flet/src/flet/core/markdown.py b/sdk/python/packages/flet/src/flet/core/markdown.py deleted file mode 100644 index e46579a3f3..0000000000 --- a/sdk/python/packages/flet/src/flet/core/markdown.py +++ /dev/null @@ -1,512 +0,0 @@ -from dataclasses import dataclass -from enum import Enum -from typing import Any, Optional, Union, cast - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxDecoration -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.text import TextSelectionChangeEvent -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - TextAlign, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class MarkdownExtensionSet(Enum): - NONE = "none" - COMMON_MARK = "commonMark" - GITHUB_WEB = "gitHubWeb" - GITHUB_FLAVORED = "gitHubFlavored" - - -@dataclass -class MarkdownStyleSheet: - a_text_style: Optional[TextStyle] = None - p_text_style: Optional[TextStyle] = None - p_padding: Optional[PaddingValue] = None - code_text_style: Optional[TextStyle] = None - h1_text_style: Optional[TextStyle] = None - h1_padding: Optional[PaddingValue] = None - h2_text_style: Optional[TextStyle] = None - h2_padding: Optional[PaddingValue] = None - h3_text_style: Optional[TextStyle] = None - h3_padding: Optional[PaddingValue] = None - h4_text_style: Optional[TextStyle] = None - h4_padding: Optional[PaddingValue] = None - h5_text_style: Optional[TextStyle] = None - h5_padding: Optional[PaddingValue] = None - h6_text_style: Optional[TextStyle] = None - h6_padding: Optional[PaddingValue] = None - em_text_style: Optional[TextStyle] = None - strong_text_style: Optional[TextStyle] = None - del_text_style: Optional[TextStyle] = None - blockquote_text_style: Optional[TextStyle] = None - img_text_style: Optional[TextStyle] = None - checkbox_text_style: Optional[TextStyle] = None - block_spacing: OptionalNumber = None - list_indent: OptionalNumber = None - list_bullet_text_style: Optional[TextStyle] = None - list_bullet_padding: Optional[PaddingValue] = None - table_head_text_style: Optional[TextStyle] = None - table_body_text_style: Optional[TextStyle] = None - table_head_text_align: Optional[TextAlign] = None - table_padding: Optional[PaddingValue] = None - table_cells_padding: Optional[PaddingValue] = None - blockquote_padding: Optional[PaddingValue] = None - table_cells_decoration: Optional[BoxDecoration] = None - blockquote_decoration: Optional[BoxDecoration] = None - codeblock_padding: Optional[PaddingValue] = None - codeblock_decoration: Optional[BoxDecoration] = None - horizontal_rule_decoration: Optional[BoxDecoration] = None - blockquote_alignment: Optional[MainAxisAlignment] = None - codeblock_alignment: Optional[MainAxisAlignment] = None - h1_alignment: Optional[MainAxisAlignment] = None - h2_alignment: Optional[MainAxisAlignment] = None - h3_alignment: Optional[MainAxisAlignment] = None - h4_alignment: Optional[MainAxisAlignment] = None - h5_alignment: Optional[MainAxisAlignment] = None - h6_alignment: Optional[MainAxisAlignment] = None - text_alignment: Optional[MainAxisAlignment] = None - ordered_list_alignment: Optional[MainAxisAlignment] = None - unordered_list_alignment: Optional[MainAxisAlignment] = None - - -class MarkdownCodeTheme(Enum): - A11Y_DARK = "a11y-dark" - A11Y_LIGHT = "a11y-light" - AGATE = "agate" - AN_OLD_HOPE = "an-old-hope" - ANDROID_STUDIO = "androidstudio" - ARDUINO_LIGHT = "arduino-light" - ARTA = "arta" - ASCETIC = "ascetic" - ATELIER_CAVE_DARK = "atelier-cave-dark" - ATELIER_CAVE_LIGHT = "atelier-cave-light" - ATELIER_DUNE_DARK = "atelier-dune-dark" - ATELIER_DUNE_LIGHT = "atelier-dune-light" - ATELIER_ESTUARY_DARK = "atelier-estuary-dark" - ATELIER_ESTUARY_LIGHT = "atelier-estuary-light" - ATELIER_FOREST_DARK = "atelier-forest-dark" - ATELIER_FOREST_LIGHT = "atelier-forest-light" - ATELIER_HEATH_DARK = "atelier-heath-dark" - ATELIER_HEATH_LIGHT = "atelier-heath-light" - ATELIER_LAKESIDE_DARK = "atelier-lakeside-dark" - ATELIER_LAKESIDE_LIGHT = "atelier-lakeside-light" - ATELIER_PLATEAU_DARK = "atelier-plateau-dark" - ATELIER_PLATEAU_LIGHT = "atelier-plateau-light" - ATELIER_SAVANNA_DARK = "atelier-savanna-dark" - ATELIER_SAVANNA_LIGHT = "atelier-savanna-light" - ATELIER_SEASIDE_DARK = "atelier-seaside-dark" - ATELIER_SEASIDE_LIGHT = "atelier-seaside-light" - ATELIER_SULPHURPOOL_DARK = "atelier-sulphurpool-dark" - ATELIER_SULPHURPOOL_LIGHT = "atelier-sulphurpool-light" - ATOM_ONE_DARK_REASONABLE = "atom-one-dark-reasonable" - ATOM_ONE_DARK = "atom-one-dark" - ATOM_ONE_LIGHT = "atom-one-light" - BROWN_PAPER = "brown-paper" - CODEPEN_EMBED = "codepen-embed" - COLOR_BREWER = "color-brewer" - DARCULA = "darcula" - DARK = "dark" - DEFAULT = "default" - DOCCO = "docco" - DRAGULA = "dracula" - FAR = "far" - FOUNDATION = "foundation" - GITHUB_GIST = "github-gist" - GITHUB = "github" - GML = "gml" - GOOGLE_CODE = "googlecode" - GRADIENT_DARK = "gradient-dark" - GRAYSCALE = "grayscale" - GRUVBOX_DARK = "gruvbox-dark" - GRUVBOX_LIGHT = "gruvbox-light" - HOPSCOTCH = "hopscotch" - HYBRID = "hybrid" - IDEA = "idea" - IR_BLACK = "ir-black" - ISBL_EDITOR_DARK = "isbl-editor-dark" - ISBL_EDITOR_LIGHT = "isbl-editor-light" - KIMBIE_DARK = "kimbie.dark" - KIMBIE_LIGHT = "kimbie.light" - LIGHTFAIR = "lightfair" - MAGULA = "magula" - MONO_BLUE = "mono-blue" - MONOKAI_SUBLIME = "monokai-sublime" - MONOKAI = "monokai" - NIGHT_OWL = "night-owl" - NORD = "nord" - OBSIDIAN = "obsidian" - OCEAN = "ocean" - PARAISEO_DARK = "paraiso-dark" - PARAISEO_LIGHT = "paraiso-light" - POJOAQUE = "pojoaque" - PURE_BASIC = "purebasic" - QT_CREATOR_DARK = "qtcreator_dark" - QT_CREATOR_LIGHT = "qtcreator_light" - RAILSCASTS = "railscasts" - RAINBOW = "rainbow" - ROUTEROS = "routeros" - SCHOOL_BOOK = "school-book" - SHADES_OF_PURPLE = "shades-of-purple" - SOLARIZED_DARK = "solarized-dark" - SOLARIZED_LIGHT = "solarized-light" - SUNBURST = "sunburst" - TOMORROW_NIGHT_BLUE = "tomorrow-night-blue" - TOMORROW_NIGHT_BRIGHT = "tomorrow-night-bright" - TOMORROW_NIGHT_EIGHTIES = "tomorrow-night-eighties" - TOMORROW_NIGHT = "tomorrow-night" - TOMORROW = "tomorrow" - VS = "vs" - VS2015 = "vs2015" - XCODE = "xcode" - XT256 = "xt256" - ZENBURN = "zenburn" - - -@dataclass -class MarkdownCustomCodeTheme: - addition: Optional[TextStyle] = None - attr: Optional[TextStyle] = None - attribute: Optional[TextStyle] = None - built_in: Optional[TextStyle] = None - builtin_name: Optional[TextStyle] = None - bullet: Optional[TextStyle] = None - class_name: Optional[TextStyle] = None - code: Optional[TextStyle] = None - comment: Optional[TextStyle] = None - deletion: Optional[TextStyle] = None - doctag: Optional[TextStyle] = None - emphasis: Optional[TextStyle] = None - formula: Optional[TextStyle] = None - function: Optional[TextStyle] = None - keyword: Optional[TextStyle] = None - link: Optional[TextStyle] = None - link_label: Optional[TextStyle] = None - literal: Optional[TextStyle] = None - meta: Optional[TextStyle] = None - meta_keyword: Optional[TextStyle] = None - meta_string: Optional[TextStyle] = None - name: Optional[TextStyle] = None - number: Optional[TextStyle] = None - operator: Optional[TextStyle] = None - params: Optional[TextStyle] = None - pattern_match: Optional[TextStyle] = None - quote: Optional[TextStyle] = None - regexp: Optional[TextStyle] = None - root: Optional[TextStyle] = None - section: Optional[TextStyle] = None - selector_attr: Optional[TextStyle] = None - selector_class: Optional[TextStyle] = None - selector_id: Optional[TextStyle] = None - selector_pseudo: Optional[TextStyle] = None - selector_tag: Optional[TextStyle] = None - string: Optional[TextStyle] = None - strong: Optional[TextStyle] = None - stronge: Optional[TextStyle] = None - subst: Optional[TextStyle] = None - subtr: Optional[TextStyle] = None - symbol: Optional[TextStyle] = None - tag: Optional[TextStyle] = None - template_tag: Optional[TextStyle] = None - template_variable: Optional[TextStyle] = None - title: Optional[TextStyle] = None - type: Optional[TextStyle] = None - variable: Optional[TextStyle] = None - - -class Markdown(ConstrainedControl): - """ - Control for rendering text in markdown format. - - ----- - - Online docs: https://flet.dev/docs/controls/markdown - """ - - def __init__( - self, - value: Optional[str] = None, - selectable: Optional[bool] = None, - extension_set: Optional[MarkdownExtensionSet] = None, - code_theme: Optional[Union[MarkdownCodeTheme, MarkdownCustomCodeTheme]] = None, - auto_follow_links: Optional[bool] = None, - shrink_wrap: Optional[bool] = None, - fit_content: Optional[bool] = None, - soft_line_break: Optional[bool] = None, - auto_follow_links_target: Optional[str] = None, - img_error_content: Optional[Control] = None, - code_style_sheet: Optional[MarkdownStyleSheet] = None, - md_style_sheet: Optional[MarkdownStyleSheet] = None, - on_tap_text: OptionalControlEventCallable = None, - on_selection_change: OptionalEventCallable[TextSelectionChangeEvent] = None, - on_tap_link: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_selection_change = EventHandler(lambda e: TextSelectionChangeEvent(e)) - - self._add_event_handler( - "selection_change", self.__on_selection_change.get_handler() - ) - - self.value = value - self.selectable = selectable - self.extension_set = extension_set - self.code_theme = code_theme - self.auto_follow_links = auto_follow_links - self.auto_follow_links_target = auto_follow_links_target - self.on_tap_link = on_tap_link - self.shrink_wrap = shrink_wrap - self.fit_content = fit_content - self.soft_line_break = soft_line_break - self.on_tap_text = on_tap_text - self.on_selection_change = on_selection_change - self.img_error_content = img_error_content - self.code_style_sheet = code_style_sheet - self.md_style_sheet = md_style_sheet - - def _get_control_name(self): - return "markdown" - - def before_update(self): - super().before_update() - self._set_attr_json("codeStyleSheet", self.__code_style_sheet) - self._set_attr_json("mdStyleSheet", self.__md_style_sheet) - self._set_attr_json( - "codeTheme", - self.__code_theme.value - if isinstance(self.__code_theme, MarkdownCodeTheme) - else self.__code_theme, - ) - - def _get_children(self): - if self.__img_error_content is not None: - self.__img_error_content._set_attr_internal("n", "error") - return [self.__img_error_content] - return [] - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # selectable - @property - def selectable(self) -> bool: - return self._get_attr("selectable", data_type="bool", def_value=False) - - @selectable.setter - def selectable(self, value: Optional[bool]): - self._set_attr("selectable", value) - - # shrink_wrap - @property - def shrink_wrap(self) -> bool: - return self._get_attr("shrinkWrap", data_type="bool", def_value=True) - - @shrink_wrap.setter - def shrink_wrap(self, value: Optional[bool]): - self._set_attr("shrinkWrap", value) - - # fit_content - @property - def fit_content(self) -> bool: - return self._get_attr("fitContent", data_type="bool", def_value=True) - - @fit_content.setter - def fit_content(self, value: Optional[bool]): - self._set_attr("fitContent", value) - - # soft_line_break - @property - def soft_line_break(self) -> bool: - return self._get_attr("softLineBreak", data_type="bool", def_value=False) - - @soft_line_break.setter - def soft_line_break(self, value: Optional[bool]): - self._set_attr("softLineBreak", value) - - # extension_set - @property - def extension_set(self) -> Optional[MarkdownExtensionSet]: - return self.__extension_set - - @extension_set.setter - def extension_set(self, value: Optional[MarkdownExtensionSet]): - self.__extension_set = value - self._set_enum_attr("extensionSet", value, MarkdownExtensionSet) - - # code_style_sheet - @property - def code_style_sheet(self) -> Optional[MarkdownStyleSheet]: - return self.__code_style_sheet - - @code_style_sheet.setter - def code_style_sheet(self, value: Optional[MarkdownStyleSheet]): - self.__code_style_sheet = value - - # md_style_sheet - @property - def md_style_sheet(self) -> Optional[MarkdownStyleSheet]: - return self.__md_style_sheet - - @md_style_sheet.setter - def md_style_sheet(self, value: Optional[MarkdownStyleSheet]): - self.__md_style_sheet = value - - # code_theme - @property - def code_theme(self) -> Optional[Union[MarkdownCodeTheme, MarkdownCustomCodeTheme]]: - return self.__code_theme - - @code_theme.setter - def code_theme( - self, value: Optional[Union[MarkdownCodeTheme, MarkdownCustomCodeTheme]] - ): - self.__code_theme = value - - # auto_follow_links - @property - def auto_follow_links(self) -> bool: - return cast( - Optional[bool], - self._get_attr("autoFollowLinks", data_type="bool", def_value=False), - ) - - @auto_follow_links.setter - def auto_follow_links(self, value: Optional[bool]): - self._set_attr("autoFollowLinks", value) - - # auto_follow_links_target - @property - def auto_follow_links_target(self) -> Optional[str]: - return self._get_attr("autoFollowLinksTarget") - - @auto_follow_links_target.setter - def auto_follow_links_target(self, value: Optional[str]): - self._set_attr("autoFollowLinksTarget", value) - - # img_error_content - @property - def img_error_content(self) -> Optional[Control]: - return self.__img_error_content - - @img_error_content.setter - def img_error_content(self, value: Optional[Control]): - self.__img_error_content = value - - # on_tap_link - @property - def on_tap_link(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap_link") - - @on_tap_link.setter - def on_tap_link(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap_link", handler) - - # on_tap_text - @property - def on_tap_text(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap_text") - - @on_tap_text.setter - def on_tap_text(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap_text", handler) - - # on_selection_change - @property - def on_selection_change( - self, - ) -> OptionalEventCallable[TextSelectionChangeEvent]: - return self.__on_selection_change.handler - - @on_selection_change.setter - def on_selection_change( - self, - handler: OptionalEventCallable[TextSelectionChangeEvent], - ): - self.__on_selection_change.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/matplotlib_chart.py b/sdk/python/packages/flet/src/flet/core/matplotlib_chart.py deleted file mode 100644 index 9f3ce015f5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/matplotlib_chart.py +++ /dev/null @@ -1,191 +0,0 @@ -import io -import re -import xml.etree.ElementTree as ET -from typing import Any, Optional, Union - -from flet.core import alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.container import Container -from flet.core.control import OptionalNumber -from flet.core.image import Image -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ImageFit, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - -try: - from matplotlib.figure import Figure -except ImportError: - raise Exception( - 'Install "matplotlib" Python package to use MatplotlibChart control.' - ) - - -class MatplotlibChart(Container): - """ - Displays Matplotlib(https://matplotlib.org/) chart. - - Example: - ``` - import matplotlib - import matplotlib.pyplot as plt - - import flet as ft - from flet.core.matplotlib_chart import MatplotlibChart - - matplotlib.use("svg") - - - def main(page: ft.Page): - - fig, ax = plt.subplots() - - fruits = ["apple", "blueberry", "cherry", "orange"] - counts = [40, 100, 30, 55] - bar_labels = ["red", "blue", "_red", "orange"] - bar_colors = ["tab:red", "tab:blue", "tab:red", "tab:orange"] - - ax.bar(fruits, counts, label=bar_labels, color=bar_colors) - - ax.set_ylabel("fruit supply") - ax.set_title("Fruit supply by kind and color") - ax.legend(title="Fruit color") - - page.add(MatplotlibChart(fig, expand=True)) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/matplotlibchart - """ - - def __init__( - self, - figure: Optional[Figure] = None, - isolated: bool = False, - original_size: bool = False, - transparent: bool = False, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Container.__init__( - self, - ref=ref, - key=key, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.figure = figure - self.isolated = isolated - self.original_size = original_size - self.transparent = transparent - - def is_isolated(self): - return self.__isolated - - def build(self): - self.alignment = alignment.center - self.__img = Image(fit=ImageFit.FILL) - self.content = self.__img - - def before_update(self): - super().before_update() - if self.__figure is not None: - s = io.StringIO() - self.__figure.savefig(s, format="svg", transparent=self.__transparent) - svg = s.getvalue() - - if not self.__original_size: - root = ET.fromstring(svg) - w = float(re.findall(r"\d+", root.attrib["width"])[0]) - h = float(re.findall(r"\d+", root.attrib["height"])[0]) - self.__img.aspect_ratio = w / h - self.__img.src = svg - - # original_size - @property - def original_size(self): - return self.__original_size - - @original_size.setter - def original_size(self, value): - self.__original_size = value - - # isolated - @property - def isolated(self): - return self.__isolated - - @isolated.setter - def isolated(self, value): - self.__isolated = value - - # figure - @property - def figure(self): - return self.__figure - - @figure.setter - def figure(self, value): - self.__figure = value - - # transparent - @property - def transparent(self) -> bool: - return self.__transparent - - @transparent.setter - def transparent(self, value: bool): - self.__transparent = value diff --git a/sdk/python/packages/flet/src/flet/core/menu_bar.py b/sdk/python/packages/flet/src/flet/core/menu_bar.py deleted file mode 100644 index 9103c8c81b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/menu_bar.py +++ /dev/null @@ -1,140 +0,0 @@ -from dataclasses import dataclass -from typing import Any, List, Optional, Sequence, Union - -from flet.core.alignment import Alignment -from flet.core.border import BorderSide -from flet.core.buttons import OutlinedBorder -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import ( - ClipBehavior, - ColorValue, - ControlState, - ControlStateValue, - MouseCursor, - OptionalNumber, - PaddingValue, - ResponsiveNumber, -) - - -@dataclass -class MenuStyle: - alignment: Optional[Alignment] = None - bgcolor: ControlStateValue[ColorValue] = None - shadow_color: ControlStateValue[ColorValue] = None - surface_tint_color: ControlStateValue[ColorValue] = None - elevation: ControlStateValue[OptionalNumber] = None - padding: ControlStateValue[PaddingValue] = None - side: ControlStateValue[BorderSide] = None - shape: ControlStateValue[OutlinedBorder] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - - def __post_init__(self): - if not isinstance(self.padding, dict): - self.padding = {ControlState.DEFAULT: self.padding} - - if not isinstance(self.side, dict): - self.side = {ControlState.DEFAULT: self.side} - - if not isinstance(self.shape, dict): - self.shape = {ControlState.DEFAULT: self.shape} - - -class MenuBar(Control): - """ - A menu bar that manages cascading child menus. - - It could be placed anywhere but typically resides above the main body of the application - and defines a menu system for invoking callbacks in response to user selection of a menu item. - - ----- - - Online docs: https://flet.dev/docs/controls/menubar - """ - - def __init__( - self, - controls: Sequence[Control], - clip_behavior: Optional[ClipBehavior] = None, - style: Optional[MenuStyle] = None, - # - # Control - # - ref: Optional[Ref] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - visible=visible, - disabled=disabled, - data=data, - ) - - self.controls = controls - self.clip_behavior = clip_behavior - self.style = style - - def _get_control_name(self): - return "menubar" - - def before_update(self): - super().before_update() - assert any( - c.visible for c in self.__controls - ), "MenuBar must have at minimum one visible control" - if self.__style is not None: - self.__style.side = self._wrap_attr_dict(self.__style.side) - self.__style.shape = self._wrap_attr_dict(self.__style.shape) - self.__style.mouse_cursor = self._wrap_attr_dict(self.__style.mouse_cursor) - if self.__style.mouse_cursor: - for k, v in self.__style.mouse_cursor.items(): - self.__style.mouse_cursor[k] = ( - v.value if isinstance(v, MouseCursor) else str(v) - ) - self._set_attr_json("style", self.__style) - - def _get_children(self): - return self.__controls - - def __contains__(self, item): - return item in self.__controls - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - @controls.setter - def controls(self, value: Sequence[Control]): - self.__controls = list(value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # style - @property - def style(self) -> Optional[MenuStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[MenuStyle]): - self.__style = value diff --git a/sdk/python/packages/flet/src/flet/core/menu_item_button.py b/sdk/python/packages/flet/src/flet/core/menu_item_button.py deleted file mode 100644 index 0a2273a5ed..0000000000 --- a/sdk/python/packages/flet/src/flet/core/menu_item_button.py +++ /dev/null @@ -1,282 +0,0 @@ -import time -from typing import Any, Optional, Union - -from flet.core.alignment import Axis -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class MenuItemButton(ConstrainedControl): - """ - A button for use in a MenuBar or on its own, that can be activated by click or keyboard navigation. - - ----- - - Online docs: https://flet.dev/docs/controls/menuitembutton - """ - - def __init__( - self, - content: Optional[Control] = None, - close_on_click: Optional[bool] = None, - focus_on_hover: Optional[bool] = None, - leading: Optional[Control] = None, - trailing: Optional[Control] = None, - clip_behavior: Optional[ClipBehavior] = None, - style: Optional[ButtonStyle] = None, - semantic_label: Optional[str] = None, - autofocus: Optional[bool] = None, - overflow_axis: Optional[Axis] = None, - on_click: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - self.leading = leading - self.trailing = trailing - self.clip_behavior = clip_behavior - self.style = style - self.close_on_click = close_on_click - self.focus_on_hover = focus_on_hover - self.on_click = on_click - self.on_hover = on_hover - self.on_focus = on_focus - self.on_blur = on_blur - self.semantic_label = semantic_label - self.autofocus = autofocus - self.overflow_axis = overflow_axis - - def _get_control_name(self): - return "menuitembutton" - - def before_update(self): - super().before_update() - if self.__style is not None: - self.__style.side = self._wrap_attr_dict(self.__style.side) - self.__style.shape = self._wrap_attr_dict(self.__style.shape) - self.__style.padding = self._wrap_attr_dict(self.__style.padding) - self._set_attr_json("style", self.__style) - - def _get_children(self): - children = [] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # focus_on_hover - @property - def focus_on_hover(self) -> bool: - return self._get_attr("focusOnHover", data_type="bool", def_value=True) - - @focus_on_hover.setter - def focus_on_hover(self, value: Optional[bool]): - self._set_attr("focusOnHover", value) - - # close_on_click - @property - def close_on_click(self) -> bool: - return self._get_attr("closeOnClick", data_type="bool", def_value=True) - - @close_on_click.setter - def close_on_click(self, value: Optional[bool]): - self._set_attr("closeOnClick", value) - - # semantic_label - @property - def semantic_label(self) -> Optional[str]: - return self._get_attr("semanticLabel") - - @semantic_label.setter - def semantic_label(self, value: Optional[str]): - self._set_attr("semanticLabel", value) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # overflow_axis - @property - def overflow_axis(self) -> Optional[Axis]: - return self.__overflow_axis - - @overflow_axis.setter - def overflow_axis(self, value: Optional[Axis]): - self.__overflow_axis = value - self._set_enum_attr("overflowAxis", value, Axis) - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # on_click - @property - def on_click(self): - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler): - self._add_event_handler("click", handler) - self._set_attr("onClick", True if handler is not None else None) - - # on_hover - @property - def on_hover(self) -> OptionalControlEventCallable: - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - self._set_attr("onHover", True if handler is not None else None) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/merge_semantics.py b/sdk/python/packages/flet/src/flet/core/merge_semantics.py deleted file mode 100644 index 21539faded..0000000000 --- a/sdk/python/packages/flet/src/flet/core/merge_semantics.py +++ /dev/null @@ -1,58 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref - - -class MergeSemantics(Control): - """ - A control that merges the semantics of its descendants. - - Causes all the semantics of the subtree rooted at this node to be merged into one node in the semantics tree. - - Used by accessibility tools, search engines, and other semantic analysis software to determine the meaning of the application. - - ----- - - Online docs: https://flet.dev/docs/controls/mergesemantics - """ - - def __init__( - self, - content: Optional[Control] = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - - def _get_control_name(self): - return "mergesemantics" - - def _get_children(self): - children = [] - if isinstance(self.__content, Control): - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value diff --git a/sdk/python/packages/flet/src/flet/core/navigation_bar.py b/sdk/python/packages/flet/src/flet/core/navigation_bar.py deleted file mode 100644 index 46869c85b6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/navigation_bar.py +++ /dev/null @@ -1,406 +0,0 @@ -from enum import Enum -from typing import Any, Callable, List, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.border import Border -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - IconEnums, - IconValueOrControl, - OffsetValue, - OptionalControlEventCallable, - OptionalNumber, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class NavigationBarLabelBehavior(Enum): - """Defines how the destinations' labels will be laid out and when they'll be displayed.""" - - ALWAYS_SHOW = "alwaysShow" - ALWAYS_HIDE = "alwaysHide" - ONLY_SHOW_SELECTED = "onlyShowSelected" - - -class NavigationBarDestination(AdaptiveControl, Control): - """Defines the appearance of the button items that are arrayed within the navigation bar. - - The value must be a list of two or more NavigationBarDestination instances.""" - - def __init__( - self, - label: Optional[str] = None, - icon: Optional[IconValueOrControl] = None, - selected_icon: Optional[IconValueOrControl] = None, - bgcolor: Optional[ColorValue] = None, - # - # Control - # - ref: Optional[Ref] = None, - tooltip: Optional[str] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - Control.__init__( - self, - ref=ref, - tooltip=tooltip, - disabled=disabled, - visible=visible, - data=data, - ) - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.label = label - self.icon = icon - self.selected_icon = selected_icon - self.bgcolor = bgcolor - - def _get_control_name(self): - return "navigationbardestination" - - def _get_children(self): - children = [] - if isinstance(self.__icon, Control): - self.__icon._set_attr_internal("n", "icon") - children.append(self.__icon) - if isinstance(self.__selected_icon, Control): - self.__selected_icon._set_attr_internal("n", "selected_icon") - children.append(self.__selected_icon) - return children - - # icon - @property - def icon(self) -> Optional[IconValueOrControl]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValueOrControl]): - self.__icon = value - if not isinstance(value, Control): - self._set_enum_attr("icon", value, IconEnums) - - # selected_icon - @property - def selected_icon(self) -> Optional[IconValueOrControl]: - return self.__selected_icon - - @selected_icon.setter - def selected_icon(self, value: Optional[IconValueOrControl]): - self.__selected_icon = value - if not isinstance(value, Control): - self._set_enum_attr("selectedIcon", value, IconEnums) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # tooltip - @property - def tooltip(self) -> Optional[str]: - return self._get_attr("tooltip") - - @tooltip.setter - def tooltip(self, value: Optional[str]): - self._set_attr("tooltip", value) - - -class NavigationBar(ConstrainedControl, AdaptiveControl): - """ - Material 3 Navigation Bar component. - - Navigation bars offer a persistent and convenient way to switch between primary destinations in an app. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "NavigationBar Example" - page.navigation_bar = ft.NavigationBar( - destinations=[ - ft.NavigationBarDestination(icon=ft.icons.EXPLORE, label="Explore"), - ft.NavigationBarDestination(icon=ft.icons.COMMUTE, label="Commute"), - ft.NavigationBarDestination( - icon=ft.icons.BOOKMARK_BORDER, - selected_icon=ft.icons.BOOKMARK, - label="Explore" - ), - ] - ) - page.add(ft.Text("Body!")) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/navigationbar - """ - - def __init__( - self, - destinations: Optional[List[NavigationBarDestination]] = None, - selected_index: Optional[int] = None, - bgcolor: Optional[ColorValue] = None, - label_behavior: Optional[NavigationBarLabelBehavior] = None, - elevation: OptionalNumber = None, - shadow_color: Optional[ColorValue] = None, - indicator_color: Optional[ColorValue] = None, - indicator_shape: Optional[OutlinedBorder] = None, - surface_tint_color: Optional[ColorValue] = None, - border: Optional[Border] = None, - animation_duration: Optional[int] = None, - overlay_color: ControlStateValue[ColorValue] = None, - label_padding: Optional[PaddingValue] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: Callable[..., None] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.destinations = destinations - self.selected_index = selected_index - self.label_behavior = label_behavior - self.bgcolor = bgcolor - self.elevation = elevation - self.shadow_color = shadow_color - self.indicator_color = indicator_color - self.indicator_shape = indicator_shape - self.surface_tint_color = surface_tint_color - self.border = border - self.on_change = on_change - self.animation_duration = animation_duration - self.overlay_color = overlay_color - self.label_padding = label_padding - - def _get_control_name(self): - return "navigationbar" - - def before_update(self): - super().before_update() - self._set_attr_json("indicatorShape", self.__indicator_shape) - self._set_attr_json("border", self.__border) - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json("labelPadding", self.__label_padding) - - def _get_children(self): - return self.__destinations - - # destinations - @property - def destinations(self) -> Optional[List[NavigationBarDestination]]: - return self.__destinations - - @destinations.setter - def destinations(self, value: Optional[List[NavigationBarDestination]]): - self.__destinations = value if value else [] - - # label_padding - @property - def label_padding(self) -> Optional[PaddingValue]: - return self.__label_padding - - @label_padding.setter - def label_padding(self, value: Optional[PaddingValue]): - self.__label_padding = value - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - self._set_attr("selectedIndex", value) - - # label_behavior - @property - def label_behavior(self) -> Optional[NavigationBarLabelBehavior]: - return self.__label_behavior - - @label_behavior.setter - def label_behavior(self, value: Optional[NavigationBarLabelBehavior]): - self.__label_behavior = value - self._set_enum_attr("labelBehavior", value, NavigationBarLabelBehavior) - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[str]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[str]): - self.__overlay_color = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # indicator_color - @property - def indicator_color(self) -> Optional[ColorValue]: - return self.__indicator_color - - @indicator_color.setter - def indicator_color(self, value: Optional[ColorValue]): - self.__indicator_color = value - self._set_enum_attr("indicatorColor", value, ColorEnums) - - # indicator_shape - @property - def indicator_shape(self) -> Optional[OutlinedBorder]: - return self.__indicator_shape - - @indicator_shape.setter - def indicator_shape(self, value: Optional[OutlinedBorder]): - self.__indicator_shape = value - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # border - @property - def border(self) -> Optional[Border]: - return self.__border - - @border.setter - def border(self, value: Optional[Border]): - self.__border = value - - # animation_duration - @property - def animation_duration(self) -> Optional[int]: - return self._get_attr("animationDuration", data_type="int") - - @animation_duration.setter - def animation_duration(self, value: Optional[int]): - self._set_attr("animationDuration", value) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/navigation_drawer.py b/sdk/python/packages/flet/src/flet/core/navigation_drawer.py deleted file mode 100644 index fb832ee1fd..0000000000 --- a/sdk/python/packages/flet/src/flet/core/navigation_drawer.py +++ /dev/null @@ -1,341 +0,0 @@ -from enum import Enum -from typing import Any, List, Optional, Sequence - -from flet.core.buttons import OutlinedBorder -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import ( - ColorEnums, - ColorValue, - IconEnums, - IconValueOrControl, - OptionalControlEventCallable, - OptionalNumber, - PaddingValue, -) - - -class NavigationDrawerDestination(Control): - """Displays an icon with a label, for use in NavigationDrawer destinations.""" - - def __init__( - self, - label: Optional[str] = None, - icon: Optional[IconValueOrControl] = None, - selected_icon: Optional[IconValueOrControl] = None, - bgcolor: Optional[ColorValue] = None, - # - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - data=data, - visible=visible, - ) - self.label = label - self.bgcolor = bgcolor - self.icon = icon - self.selected_icon = selected_icon - - def _get_control_name(self): - return "navigationdrawerdestination" - - def _get_children(self): - children = [] - if isinstance(self.__icon, Control): - self.__icon._set_attr_internal("n", "icon") - children.append(self.__icon) - if isinstance(self.__selected_icon, Control): - self.__selected_icon._set_attr_internal("n", "selected_icon") - children.append(self.__selected_icon) - return children - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # icon - @property - def icon(self) -> Optional[IconValueOrControl]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValueOrControl]): - self.__icon = value - if not isinstance(value, Control): - self._set_enum_attr("icon", value, IconEnums) - - # selected_icon - @property - def selected_icon(self) -> Optional[IconValueOrControl]: - return self.__selected_icon - - @selected_icon.setter - def selected_icon(self, value: Optional[IconValueOrControl]): - self.__selected_icon = value - if not isinstance(value, Control): - self._set_enum_attr("selectedIcon", value, IconEnums) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - -class NavigationDrawerPosition(Enum): - START = "start" - END = "end" - - -class NavigationDrawer(Control): - """ - Material Design Navigation Drawer component. - - Navigation Drawer is a panel slides in horizontally from the left or right edge of a page to show primary destinations in an app. - - Example: - - ``` - import flet as ft - - - def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_dismissal(e): - page.add(ft.Text("Drawer dismissed")) - - def handle_change(e): - page.add(ft.Text(f"Selected Index changed: {e.selected_index}")) - # page.close(drawer) - - drawer = ft.NavigationDrawer( - on_dismiss=handle_dismissal, - on_change=handle_change, - controls=[ - ft.Container(height=12), - ft.NavigationDrawerDestination( - label="Item 1", - icon=ft.icons.DOOR_BACK_DOOR_OUTLINED, - selected_icon_content=ft.Icon(ft.icons.DOOR_BACK_DOOR), - ), - ft.Divider(thickness=2), - ft.NavigationDrawerDestination( - icon_content=ft.Icon(ft.icons.MAIL_OUTLINED), - label="Item 2", - selected_icon=ft.icons.MAIL, - ), - ft.NavigationDrawerDestination( - icon_content=ft.Icon(ft.icons.PHONE_OUTLINED), - label="Item 3", - selected_icon=ft.icons.PHONE, - ), - ], - ) - - page.add(ft.ElevatedButton("Show drawer", on_click=lambda e: page.open(drawer))) - - - ft.app(main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/navigationdrawer - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - open: bool = False, - selected_index: Optional[int] = None, - bgcolor: Optional[ColorValue] = None, - elevation: OptionalNumber = None, - indicator_color: Optional[ColorValue] = None, - indicator_shape: Optional[OutlinedBorder] = None, - shadow_color: Optional[ColorValue] = None, - surface_tint_color: Optional[ColorValue] = None, - tile_padding: Optional[PaddingValue] = None, - position: Optional[NavigationDrawerPosition] = None, - on_change: OptionalControlEventCallable = None, - on_dismiss: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.open = open - self.controls = controls - self.selected_index = selected_index - self.bgcolor = bgcolor - self.elevation = elevation - self.indicator_color = indicator_color - self.indicator_shape = indicator_shape - self.shadow_color = shadow_color - self.surface_tint_color = surface_tint_color - self.tile_padding = tile_padding - self.position = position - self.on_change = on_change - self.on_dismiss = on_dismiss - - def _get_control_name(self): - return "navigationdrawer" - - def before_update(self): - super().before_update() - self._set_attr_json("indicatorShape", self.__indicator_shape) - self._set_attr_json("tilePadding", self.__tile_padding) - - def _get_children(self): - return self.__controls - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # controls - @property - def controls(self) -> Optional[List[Control]]: - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - self._set_attr("selectedIndex", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # position - @property - def position(self) -> Optional[NavigationDrawerPosition]: - return self.__position - - @position.setter - def position(self, value: Optional[NavigationDrawerPosition]): - self.__position = value or NavigationDrawerPosition.START - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # indicator_color - @property - def indicator_color(self) -> Optional[ColorValue]: - return self.__indicator_color - - @indicator_color.setter - def indicator_color(self, value: Optional[ColorValue]): - self.__indicator_color = value - self._set_enum_attr("indicatorColor", value, ColorEnums) - - # indicator_shape - @property - def indicator_shape(self) -> Optional[OutlinedBorder]: - return self.__indicator_shape - - @indicator_shape.setter - def indicator_shape(self, value: Optional[OutlinedBorder]): - self.__indicator_shape = value - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # tile_padding - @property - def tile_padding(self) -> Optional[PaddingValue]: - return self.__tile_padding - - @tile_padding.setter - def tile_padding(self, value: Optional[PaddingValue]): - self.__tile_padding = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) diff --git a/sdk/python/packages/flet/src/flet/core/navigation_rail.py b/sdk/python/packages/flet/src/flet/core/navigation_rail.py deleted file mode 100644 index fe1ad41798..0000000000 --- a/sdk/python/packages/flet/src/flet/core/navigation_rail.py +++ /dev/null @@ -1,472 +0,0 @@ -from enum import Enum -from typing import Any, Callable, List, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ( - ColorEnums, - ColorValue, - IconEnums, - IconValueOrControl, - OffsetValue, - OptionalControlEventCallable, - OptionalNumber, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class NavigationRailLabelType(Enum): - NONE = "none" - ALL = "all" - SELECTED = "selected" - - -class NavigationRailDestination(Control): - def __init__( - self, - icon: Optional[IconValueOrControl] = None, - selected_icon: Optional[IconValueOrControl] = None, - label: Optional[str] = None, - label_content: Optional[Control] = None, - padding: Optional[PaddingValue] = None, - indicator_color: Optional[ColorValue] = None, - indicator_shape: Optional[OutlinedBorder] = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ) -> None: - Control.__init__(self, ref=ref, disabled=disabled, visible=visible, data=data) - self.label = label - self.icon = icon - self.selected_icon = selected_icon - self.label_content = label_content - self.padding = padding - self.indicator_color = indicator_color - self.indicator_shape = indicator_shape - - def _get_control_name(self): - return "navigationraildestination" - - def before_update(self) -> None: - super().before_update() - self._set_attr_json("padding", self.__padding) - if isinstance(self.__indicator_shape, OutlinedBorder): - self._set_attr_json("indicatorShape", self.__indicator_shape) - - def _get_children(self): - children = [] - if self.__label_content: - self.__label_content._set_attr_internal("n", "label_content") - children.append(self.__label_content) - if isinstance(self.__icon, Control): - self.__icon._set_attr_internal("n", "icon") - children.append(self.__icon) - if isinstance(self.__selected_icon, Control): - self.__selected_icon._set_attr_internal("n", "selected_icon") - children.append(self.__selected_icon) - return children - - # icon - @property - def icon(self) -> Optional[IconValueOrControl]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValueOrControl]): - self.__icon = value - if not isinstance(value, Control): - self._set_enum_attr("icon", value, IconEnums) - - # selected_icon - @property - def selected_icon(self) -> Optional[IconValueOrControl]: - return self.__selected_icon - - @selected_icon.setter - def selected_icon(self, value: Optional[IconValueOrControl]): - self.__selected_icon = value - if not isinstance(value, Control): - self._set_enum_attr("selectedIcon", value, IconEnums) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # label_content - @property - def label_content(self) -> Optional[Control]: - return self.__label_content - - @label_content.setter - def label_content(self, value: Optional[Control]): - self.__label_content = value - - # indicator_color - @property - def indicator_color(self) -> Optional[ColorValue]: - return self.__indicator_color - - @indicator_color.setter - def indicator_color(self, value: Optional[ColorValue]): - self.__indicator_color = value - self._set_enum_attr("indicatorColor", value, ColorEnums) - - # indicator_shape - @property - def indicator_shape(self) -> Optional[OutlinedBorder]: - return self.__indicator_shape - - @indicator_shape.setter - def indicator_shape(self, value: Optional[OutlinedBorder]): - self.__indicator_shape = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - -class NavigationRail(ConstrainedControl): - """ - A material widget that is meant to be displayed at the left or right of an app to navigate between a small number of views, typically between three and five. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - - rail = ft.NavigationRail( - selected_index=1, - label_type=ft.NavigationRailLabelType.ALL, - # extended=True, - min_width=100, - min_extended_width=400, - leading=ft.FloatingActionButton(icon=ft.icons.CREATE, text="Add"), - group_alignment=-0.9, - destinations=[ - ft.NavigationRailDestination( - icon=ft.icons.FAVORITE_BORDER, selected_icon=ft.icons.FAVORITE, label="First" - ), - ft.NavigationRailDestination( - icon_content=ft.Icon(ft.icons.BOOKMARK_BORDER), - selected_icon_content=ft.Icon(ft.icons.BOOKMARK), - label="Second", - ), - ft.NavigationRailDestination( - icon=ft.icons.SETTINGS_OUTLINED, - selected_icon_content=ft.Icon(ft.icons.SETTINGS), - label_content=ft.Text("Settings"), - ), - ], - on_change=lambda e: print("Selected destination:", e.control.selected_index), - ) - - page.add( - ft.Row( - [ - rail, - ft.VerticalDivider(width=1), - ft.Column([ ft.Text("Body!")], alignment=ft.MainAxisAlignment.START, expand=True), - ], - expand=True, - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/navigationrail - """ - - def __init__( - self, - destinations: Optional[List[NavigationRailDestination]] = None, - elevation: OptionalNumber = None, - selected_index: Optional[int] = None, - extended: Optional[bool] = None, - label_type: Optional[NavigationRailLabelType] = None, - bgcolor: Optional[ColorValue] = None, - indicator_color: Optional[ColorValue] = None, - indicator_shape: Optional[OutlinedBorder] = None, - leading: Optional[Control] = None, - trailing: Optional[Control] = None, - min_width: OptionalNumber = None, - min_extended_width: OptionalNumber = None, - group_alignment: OptionalNumber = None, - selected_label_text_style: Optional[TextStyle] = None, - unselected_label_text_style: Optional[TextStyle] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: Callable[..., None] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = False, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.destinations = destinations - self.selected_index = selected_index - self.elevation = elevation - self.extended = extended - self.label_type = label_type - self.bgcolor = bgcolor - self.indicator_color = indicator_color - self.indicator_shape = indicator_shape - self.leading = leading - self.trailing = trailing - self.min_width = min_width - self.min_extended_width = min_extended_width - self.group_alignment = group_alignment - self.on_change = on_change - self.selected_label_text_style = selected_label_text_style - self.unselected_label_text_style = unselected_label_text_style - - def _get_control_name(self): - return "navigationrail" - - def before_update(self): - super().before_update() - if isinstance(self.__indicator_shape, OutlinedBorder): - self._set_attr_json("indicatorShape", self.__indicator_shape) - if isinstance(self.__selected_label_text_style, TextStyle): - self._set_attr_json( - "selectedLabelTextStyle", self.__selected_label_text_style - ) - if isinstance(self.__unselected_label_text_style, TextStyle): - self._set_attr_json( - "unselectedLabelTextStyle", self.__unselected_label_text_style - ) - - def _get_children(self): - children = [] - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - return children + self.__destinations - - # destinations - @property - def destinations(self) -> Optional[List[NavigationRailDestination]]: - return self.__destinations - - @destinations.setter - def destinations(self, value: Optional[List[NavigationRailDestination]]): - self.__destinations = value if value else [] - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - self._set_attr("selectedIndex", value) - - # label_type - @property - def label_type(self) -> Optional[NavigationRailLabelType]: - return self.__label_type - - @label_type.setter - def label_type(self, value: Optional[NavigationRailLabelType]): - self.__label_type = value - self._set_enum_attr("labelType", value, NavigationRailLabelType) - - # indicator_shape - @property - def indicator_shape(self) -> Optional[OutlinedBorder]: - return self.__indicator_shape - - @indicator_shape.setter - def indicator_shape(self, value: Optional[OutlinedBorder]): - self.__indicator_shape = value - - # indicator_color - @property - def indicator_color(self) -> Optional[ColorValue]: - return self.__indicator_color - - @indicator_color.setter - def indicator_color(self, value: Optional[ColorValue]): - self.__indicator_color = value - self._set_enum_attr("indicatorColor", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value > 0, "elevation must be greater than 0" - self._set_attr("elevation", value) - - # extended - @property - def extended(self) -> bool: - return self._get_attr("extended", data_type="bool", def_value=False) - - @extended.setter - def extended(self, value: Optional[bool]): - self._set_attr("extended", value) - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # selected_label_text_style - @property - def selected_label_text_style(self) -> Optional[TextStyle]: - return self.__selected_label_text_style - - @selected_label_text_style.setter - def selected_label_text_style(self, value: Optional[TextStyle]): - self.__selected_label_text_style = value - - # unselected_label_text_style - @property - def unselected_label_text_style(self) -> Optional[TextStyle]: - return self.__unselected_label_text_style - - @unselected_label_text_style.setter - def unselected_label_text_style(self, value: Optional[TextStyle]): - self.__unselected_label_text_style = value - - # min_width - @property - def min_width(self) -> OptionalNumber: - return self._get_attr("minWidth", data_type="float") - - @min_width.setter - def min_width(self, value: OptionalNumber): - self._set_attr("minWidth", value) - - # min_extended_width - @property - def min_extended_width(self) -> OptionalNumber: - return self._get_attr("minExtendedWidth", data_type="float") - - @min_extended_width.setter - def min_extended_width(self, value: OptionalNumber): - self._set_attr("minExtendedWidth", value) - - # group_alignment - @property - def group_alignment(self) -> OptionalNumber: - return self._get_attr("groupAlignment", data_type="float") - - @group_alignment.setter - def group_alignment(self, value: OptionalNumber): - self._set_attr("groupAlignment", value) diff --git a/sdk/python/packages/flet/src/flet/core/outlined_button.py b/sdk/python/packages/flet/src/flet/core/outlined_button.py deleted file mode 100644 index 3c8ca53901..0000000000 --- a/sdk/python/packages/flet/src/flet/core/outlined_button.py +++ /dev/null @@ -1,301 +0,0 @@ -import time -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, -) - - -class OutlinedButton(ConstrainedControl, AdaptiveControl): - """ - Outlined buttons are medium-emphasis buttons. They contain actions that are important, but aren’t the primary action in an app. Outlined buttons pair well with filled buttons to indicate an alternative, secondary action. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Basic outlined buttons" - page.add( - ft.OutlinedButton(text="Outlined button"), - ft.OutlinedButton("Disabled button", disabled=True), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/outlinedbutton - """ - - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - icon_color: Optional[ColorValue] = None, - content: Optional[Control] = None, - style: Optional[ButtonStyle] = None, - autofocus: Optional[bool] = None, - clip_behavior: Optional[ClipBehavior] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - on_click: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.text = text - self.icon = icon - self.icon_color = icon_color - self.style = style - self.content = content - self.autofocus = autofocus - self.url = url - self.url_target = url_target - self.clip_behavior = clip_behavior - self.on_click = on_click - self.on_long_press = on_long_press - self.on_hover = on_hover - self.on_focus = on_focus - self.on_blur = on_blur - - def _get_control_name(self): - return "outlinedbutton" - - def before_update(self): - super().before_update() - assert ( - self.text or self.icon or (self.__content and self.__content.visible) - ), "at minimum, text, icon or a visible content must be provided" - if self.__style is not None: - self.__style.side = self._wrap_attr_dict(self.__style.side) - self.__style.shape = self._wrap_attr_dict(self.__style.shape) - self.__style.padding = self._wrap_attr_dict(self.__style.padding) - self._set_attr_json("style", self.__style) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # on_hover - @property - def on_hover(self) -> OptionalControlEventCallable: - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - self._set_attr("onHover", True if handler is not None else None) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/padding.py b/sdk/python/packages/flet/src/flet/core/padding.py deleted file mode 100644 index fc277000ad..0000000000 --- a/sdk/python/packages/flet/src/flet/core/padding.py +++ /dev/null @@ -1,24 +0,0 @@ -import dataclasses -from typing import Union - - -@dataclasses.dataclass -class Padding: - left: Union[float, int] - top: Union[float, int] - right: Union[float, int] - bottom: Union[float, int] - - -def all(value: float) -> Padding: - return Padding(left=value, top=value, right=value, bottom=value) - - -def symmetric(vertical: float = 0, horizontal: float = 0) -> Padding: - return Padding(left=horizontal, top=vertical, right=horizontal, bottom=vertical) - - -def only( - left: float = 0, top: float = 0, right: float = 0, bottom: float = 0 -) -> Padding: - return Padding(left=left, top=top, right=right, bottom=bottom) diff --git a/sdk/python/packages/flet/src/flet/core/page.py b/sdk/python/packages/flet/src/flet/core/page.py deleted file mode 100644 index 33c70c1186..0000000000 --- a/sdk/python/packages/flet/src/flet/core/page.py +++ /dev/null @@ -1,2028 +0,0 @@ -from __future__ import annotations - -import asyncio -import json -import logging -import threading -import time -import uuid -from concurrent.futures import CancelledError, Future, ThreadPoolExecutor -from contextvars import ContextVar -from dataclasses import dataclass -from datetime import datetime, timedelta, timezone -from functools import partial -from typing import ( - Any, - Awaitable, - Callable, - Coroutine, - Dict, - List, - Optional, - Sequence, - Tuple, - Type, - TypeVar, - Union, - cast, -) -from urllib.parse import urlparse - -import flet.core -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alert_dialog import AlertDialog -from flet.core.alignment import Alignment -from flet.core.animation import AnimationCurve -from flet.core.app_bar import AppBar -from flet.core.banner import Banner -from flet.core.bottom_app_bar import BottomAppBar -from flet.core.bottom_sheet import BottomSheet -from flet.core.box import BoxDecoration -from flet.core.client_storage import ClientStorage -from flet.core.connection import Connection -from flet.core.control import Control -from flet.core.control_event import ControlEvent -from flet.core.cupertino_alert_dialog import CupertinoAlertDialog -from flet.core.cupertino_app_bar import CupertinoAppBar -from flet.core.cupertino_bottom_sheet import CupertinoBottomSheet -from flet.core.cupertino_navigation_bar import CupertinoNavigationBar -from flet.core.event import Event -from flet.core.event_handler import EventHandler -from flet.core.floating_action_button import FloatingActionButton -from flet.core.locks import NopeLock -from flet.core.navigation_bar import NavigationBar -from flet.core.navigation_drawer import NavigationDrawer, NavigationDrawerPosition -from flet.core.padding import Padding -from flet.core.protocol import Command -from flet.core.pubsub.pubsub_client import PubSubClient -from flet.core.querystring import QueryString -from flet.core.scrollable_control import OnScrollEvent -from flet.core.session_storage import SessionStorage -from flet.core.snack_bar import SnackBar -from flet.core.theme import Theme -from flet.core.types import ( - AppLifecycleState, - Brightness, - ColorEnums, - ColorValue, - CrossAxisAlignment, - FloatingActionButtonLocation, - LocaleConfiguration, - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - OptionalNumber, - PaddingValue, - PagePlatform, - ScrollMode, - ThemeMode, - WindowEventType, - Wrapper, -) -from flet.core.view import View -from flet.utils import classproperty, is_pyodide - -try: - from typing import ParamSpec -except ImportError: - from typing_extensions import ParamSpec - - -logger = logging.getLogger(flet.__name__) -try: - from typing import ParamSpec -except ImportError: - from typing_extensions import ParamSpec - -_session_page = ContextVar("flet_session_page", default=None) - - -class context: - @classproperty - def page(cls) -> "Page": - return _session_page.get() - - -try: - from flet.auth.authorization import Authorization - from flet.auth.oauth_provider import OAuthProvider -except ImportError: - - class OAuthProvider: ... - - class Authorization: - def __init__( - self, - provider: OAuthProvider, - fetch_user: bool, - fetch_groups: bool, - scope: Optional[List[str]] = None, - ): ... - - -AT = TypeVar("AT", bound=Authorization) - -InputT = ParamSpec("InputT") -RetT = TypeVar("RetT") - - -class PageDisconnectedException(Exception): - def __init__(self, message): - super().__init__(message) - - -class BrowserContextMenu: - def __init__(self, page: "Page"): - self.page = page - self.__disabled = False - - def enable(self, wait_timeout: Optional[float] = 10): - self.page._invoke_method("enableBrowserContextMenu", wait_timeout=wait_timeout) - self.__disabled = False - - def disable(self, wait_timeout: Optional[float] = 10): - self.page._invoke_method("disableBrowserContextMenu", wait_timeout=wait_timeout) - self.__disabled = True - - @property - def disabled(self) -> bool: - return self.__disabled - - -class Window: - def __init__(self, page: "Page"): - self.page = page - self.__alignment = None - self.__bgcolor = None - self.__on_event = EventHandler(lambda e: WindowEvent(e)) - self.page._add_event_handler( - "window_event", - self.__on_event.get_handler(), - ) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self.page._set_enum_attr("windowBgcolor", value, ColorEnums) - - # width - @property - def width(self) -> OptionalNumber: - w = self.page._get_attr("windowWidth") - return float(w) if w else 0 - - @width.setter - def width(self, value: OptionalNumber): - self.page._set_attr("windowWidth", value) - - # height - @property - def height(self) -> OptionalNumber: - h = self.page._get_attr("windowHeight") - return float(h) if h else 0 - - @height.setter - def height(self, value: OptionalNumber): - self.page._set_attr("windowHeight", value) - - # top - @property - def top(self) -> OptionalNumber: - w = self.page._get_attr("windowTop") - return float(w) if w else 0 - - @top.setter - def top(self, value: OptionalNumber): - self.page._set_attr("windowTop", value) - - # left - @property - def left(self) -> OptionalNumber: - h = self.page._get_attr("windowLeft") - return float(h) if h else 0 - - @left.setter - def left(self, value: OptionalNumber): - self.page._set_attr("windowLeft", value) - - # max_width - @property - def max_width(self) -> OptionalNumber: - return self.page._get_attr("windowMaxWidth") - - @max_width.setter - def max_width(self, value: OptionalNumber): - self.page._set_attr("windowMaxWidth", value) - - # max_height - @property - def max_height(self) -> OptionalNumber: - return self.page._get_attr("windowMaxHeight") - - @max_height.setter - def max_height(self, value: OptionalNumber): - self.page._set_attr("windowMaxHeight", value) - - # min_width - @property - def min_width(self) -> OptionalNumber: - return self.page._get_attr("windowMinWidth") - - @min_width.setter - def min_width(self, value: OptionalNumber): - self.page._set_attr("windowMinWidth", value) - - # min_height - @property - def min_height(self) -> OptionalNumber: - return self.page._get_attr("windowMinHeight") - - @min_height.setter - def min_height(self, value: OptionalNumber): - self.page._set_attr("windowMinHeight", value) - - # opacity - @property - def opacity(self) -> float: - return self.page._get_attr("windowOpacity", data_type="float", def_value=1.0) - - @opacity.setter - def opacity(self, value: OptionalNumber): - self.page._set_attr("windowOpacity", value) - - # maximized - @property - def maximized(self) -> bool: - return self.page._get_attr("windowMaximized", data_type="bool", def_value=False) - - @maximized.setter - def maximized(self, value: Optional[bool]): - self.page._set_attr("windowMaximized", value) - - # minimized - @property - def minimized(self) -> bool: - return self.page._get_attr("windowMinimized", data_type="bool", def_value=False) - - @minimized.setter - def minimized(self, value: Optional[bool]): - self.page._set_attr("windowMinimized", value) - - # minimizable - @property - def minimizable(self) -> bool: - return self.page._get_attr( - "windowMinimizable", data_type="bool", def_value=True - ) - - @minimizable.setter - def minimizable(self, value: Optional[bool]): - self.page._set_attr("windowMinimizable", value) - - # maximizable - @property - def maximizable(self) -> bool: - return self.page._get_attr( - "windowMaximizable", data_type="bool", def_value=True - ) - - @maximizable.setter - def maximizable(self, value: Optional[bool]): - self.page._set_attr("windowMaximizable", value) - - # resizable - @property - def resizable(self) -> bool: - return self.page._get_attr("windowResizable", data_type="bool", def_value=True) - - @resizable.setter - def resizable(self, value: Optional[bool]): - self.page._set_attr("windowResizable", value) - - # movable - @property - def movable(self) -> bool: - return self.page._get_attr("windowMovable", data_type="bool", def_value=True) - - @movable.setter - def movable(self, value: Optional[bool]): - self.page._set_attr("windowMovable", value) - - # full_screen - @property - def full_screen(self) -> bool: - return self.page._get_attr( - "windowFullScreen", data_type="bool", def_value=False - ) - - @full_screen.setter - def full_screen(self, value: Optional[bool]): - self.page._set_attr("windowFullScreen", value) - - # always_on_top - @property - def always_on_top(self) -> bool: - return self.page._get_attr( - "windowAlwaysOnTop", data_type="bool", def_value=False - ) - - @always_on_top.setter - def always_on_top(self, value: Optional[bool]): - self.page._set_attr("windowAlwaysOnTop", value) - - # prevent_close - @property - def prevent_close(self) -> bool: - return self.page._get_attr( - "windowPreventClose", data_type="bool", def_value=False - ) - - @prevent_close.setter - def prevent_close(self, value: Optional[bool]): - self.page._set_attr("windowPreventClose", value) - - # title_bar_hidden - @property - def title_bar_hidden(self) -> bool: - return self.page._get_attr( - "windowTitleBarHidden", data_type="bool", def_value=False - ) - - @title_bar_hidden.setter - def title_bar_hidden(self, value: Optional[bool]): - self.page._set_attr("windowTitleBarHidden", value) - - # title_bar_buttons_hidden - @property - def title_bar_buttons_hidden(self) -> bool: - return self.page._get_attr( - "windowTitleBarButtonsHidden", data_type="bool", def_value=False - ) - - @title_bar_buttons_hidden.setter - def title_bar_buttons_hidden(self, value: Optional[bool]): - self.page._set_attr("windowTitleBarButtonsHidden", value) - - # skip_task_bar - @property - def skip_task_bar(self) -> bool: - return self.page._get_attr( - "windowSkipTaskBar", data_type="bool", def_value=False - ) - - @skip_task_bar.setter - def skip_task_bar(self, value: Optional[bool]): - self.page._set_attr("windowSkipTaskBar", value) - - # frameless - @property - def frameless(self) -> bool: - return self.page._get_attr("windowFrameless", data_type="bool", def_value=False) - - @frameless.setter - def frameless(self, value: Optional[bool]): - self.page._set_attr("windowFrameless", value) - - # progress_bar - @property - def progress_bar(self) -> OptionalNumber: - return self.page._get_attr("windowProgressBar") - - @progress_bar.setter - def progress_bar(self, value: OptionalNumber): - self.page._set_attr("windowProgressBar", value) - - # focused - @property - def focused(self) -> bool: - return self.page._get_attr("windowFocused", data_type="bool", def_value=True) - - @focused.setter - def focused(self, value: Optional[bool]): - self.page._set_attr("windowFocused", value) - - # visible - @property - def visible(self) -> bool: - return self.page._get_attr("windowVisible", data_type="bool", def_value=True) - - @visible.setter - def visible(self, value: Optional[bool]): - self.page._set_attr("windowVisible", value) - - # always_on_bottom - @property - def always_on_bottom(self) -> bool: - return self.page._get_attr( - "windowAlwaysOnBottom", data_type="bool", def_value=False - ) - - @always_on_bottom.setter - def always_on_bottom(self, value: Optional[bool]): - self.page._set_attr("windowAlwaysOnBottom", value) - - # wait_until_ready_to_show - @property - def wait_until_ready_to_show(self) -> bool: - return self.page._get_attr( - "windowWaitUntilReadyToShow", data_type="bool", def_value=False - ) - - @wait_until_ready_to_show.setter - def wait_until_ready_to_show(self, value: Optional[bool]): - self.page._set_attr("windowWaitUntilReadyToShow", value) - - # shadow - @property - def shadow(self) -> bool: - return self.page._get_attr("windowShadow", data_type="bool", def_value=False) - - @shadow.setter - def shadow(self, value: Optional[bool]): - self.page._set_attr("windowShadow", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # badge_label - @property - def badge_label(self) -> Optional[str]: - return self.page._get_attr("windowBadgeLabel") - - @badge_label.setter - def badge_label(self, value: Optional[str]): - self.page._set_attr("windowBadgeLabel", value) - - # icon - @property - def icon(self) -> Optional[str]: - return self.page._get_attr("windowIcon") - - @icon.setter - def icon(self, value: Optional[str]): - self.page._set_attr("windowIcon", value) - - # ignore_mouse_events - @property - def ignore_mouse_events(self) -> bool: - return self.page._get_attr( - "windowIgnoreMouseEvents", data_type="bool", def_value=False - ) - - @ignore_mouse_events.setter - def ignore_mouse_events(self, value: Optional[bool]): - self.page._set_attr("windowIgnoreMouseEvents", value) - - # Methods - def destroy(self): - self.page._set_attr("windowDestroy", True) - self.page.update() - - def center(self) -> None: - self.page._set_attr("windowCenter", str(time.time())) - self.page.update() - - def close(self) -> None: - self.page._set_attr("windowClose", str(time.time())) - self.page.update() - - def to_front(self) -> None: - self.page._invoke_method("windowToFront") - - def start_dragging(self) -> None: - self.page._invoke_method("windowStartDragging") - - # Events - # on_event - @property - def on_event(self) -> OptionalEventCallable["WindowEvent"]: - return self.__on_event.handler - - @on_event.setter - def on_event( - self, - handler: OptionalEventCallable["WindowEvent"], - ): - self.__on_event.handler = handler - - -class Page(AdaptiveControl): - """ - Page is a container for `View` (https://flet.dev/docs/controls/view) controls. - - A page instance and the root view are automatically created when a new user session started. - - Example: - - ``` - import flet as ft - - - def main(page: ft.Page): - page.title = "New page" - page.add(ft.Text("Hello")) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/page - """ - - def __init__( - self, - conn: Connection, - session_id, - loop: asyncio.AbstractEventLoop, - executor: Optional[ThreadPoolExecutor] = None, - ) -> None: - Control.__init__(self) - self._id = "page" - self._Control__uid = "page" - self.__window = Window(self) - self.__browser_context_menu = BrowserContextMenu(self) - self.__conn = conn - self.__next_control_id = 1 - self.__snapshot: Dict[str, Dict[str, Any]] = {} - self.__expires_at = None - self.__query: QueryString = QueryString(page=self) # Querystring - self._session_id = session_id - self.__loop = loop - self.__executor = executor - self._index = {self._Control__uid: self} # index with all page controls - - self.__lock = threading.Lock() if not is_pyodide() else NopeLock() - - self.__views = [View()] - self.__default_view = self.__views[0] - self._controls = self.__default_view.controls - - self.__fonts: Optional[Dict[str, str]] = None - self.__offstage = Offstage() - self.__theme = None - self.__dark_theme = None - self.__locale_configuration = None - self.__theme_mode = ThemeMode.SYSTEM # Default Theme Mode - self.__pubsub: PubSubClient = PubSubClient(conn.pubsubhub, session_id) - self.__client_storage: ClientStorage = ClientStorage(self) - self.__session_storage: SessionStorage = SessionStorage(self) - self.__authorization: Optional[Authorization] = None - - self.__on_close = EventHandler() - self._add_event_handler("close", self.__on_close.get_handler()) - self.__on_platform_brightness_change = EventHandler() - self._add_event_handler( - "platformBrightnessChange", - self.__on_platform_brightness_change.get_handler(), - ) - - self.__on_app_lifecycle_state_change = EventHandler( - lambda e: AppLifecycleStateChangeEvent(e) - ) - self._add_event_handler( - "app_lifecycle_state_change", - self.__on_app_lifecycle_state_change.get_handler(), - ) - self.__on_resized = EventHandler(lambda e: WindowResizeEvent(e)) - self._add_event_handler("resized", self.__on_resized.get_handler()) - - self.__last_route = None - - # authorize/login/logout - - self.__on_login = EventHandler() - self._add_event_handler("authorize", self.__on_authorize_async) - self.__on_logout = EventHandler() - - # route_change - - def convert_route_change_event(e): - if self.__last_route == e.data: - return None # avoid duplicate calls - self.__last_route = e.data - self._set_attr("route", e.data, False) - self.query() # Update query url (required when manually changed from browser) - return RouteChangeEvent(route=e.data) - - self.__on_route_change: EventHandler = EventHandler(convert_route_change_event) - self._add_event_handler("route_change", self.__on_route_change.get_handler()) - - def convert_view_pop_event(e): - # e.data contains route name - view = next((v for v in self.views if v.route == e.data), None) - return ViewPopEvent(view=view) if view in self.views else None - - self.__on_view_pop = EventHandler(convert_view_pop_event) - self._add_event_handler("view_pop", self.__on_view_pop.get_handler()) - - def convert_keyboard_event(e): - d = json.loads(e.data) - return KeyboardEvent(**d) - - self.__on_keyboard_event = EventHandler(convert_keyboard_event) - self._add_event_handler( - "keyboard_event", self.__on_keyboard_event.get_handler() - ) - - def convert_page_media_change_event(e): - d = json.loads(e.data) - return PageMediaData(**d) - - self.__on_page_media_change_event = EventHandler( - convert_page_media_change_event - ) - self._add_event_handler( - "mediaChange", self.__on_page_media_change_event.get_handler() - ) - - self.__method_calls: Dict[str, Union[threading.Event, asyncio.Event]] = {} - self.__method_call_results: Dict[ - Union[threading.Event, asyncio.Event], tuple[Optional[str], Optional[str]] - ] = {} - self._add_event_handler("invoke_method_result", self.__on_invoke_method_result) - - self.__on_connect = EventHandler() - self._add_event_handler("connect", self.__on_connect.get_handler()) - self.__on_disconnect = EventHandler() - self._add_event_handler("disconnect", self.__on_disconnect.get_handler()) - self.__on_error = EventHandler() - self._add_event_handler("error", self.__on_error.get_handler()) - - _session_page.set(self) - - def get_control(self, id: str) -> Control: - return self._index.get(id) - - def before_update(self) -> None: - super().before_update() - self._set_attr_json("fonts", self.__fonts) - self._set_attr_json("theme", self.__theme) - self._set_attr_json("localeConfiguration", self.__locale_configuration) - self._set_attr_json("darkTheme", self.__dark_theme) - self._set_attr_json("windowAlignment", self.__window.alignment) - - def _get_control_name(self): - return "page" - - def _get_children(self): - children = [] - children.extend(self.__views) - children.append(self.__offstage) - return children - - def get_next_control_id(self) -> int: - r = self.__next_control_id - self.__next_control_id += 1 - return r - - async def fetch_page_details_async(self) -> None: - assert self.__conn - props = [ - "route", - "pwa", - "web", - "debug", - "platform", - "platformBrightness", - "media", - "width", - "height", - "windowWidth", - "windowHeight", - "windowTop", - "windowLeft", - "clientIP", - "clientUserAgent", - ] - values = ( - self.__conn.send_commands( - self._session_id, - [Command(0, "get", ["page", prop]) for prop in props], - ) - ).results - for i in range(len(props)): - self._set_attr(props[i], values[i], False) - - async def _connect(self, conn: Connection) -> None: - _session_page.set(self) - self.__conn = conn - self.__expires_at = None - await self.on_event_async(Event("page", "connect", "")) - - async def _disconnect(self, session_timeout_seconds: int) -> None: - self.__expires_at = datetime.now(timezone.utc) + timedelta( - seconds=session_timeout_seconds - ) - await self.on_event_async(Event("page", "disconnect", "")) - - def update(self, *controls) -> None: - with self.__lock: - if len(controls) == 0: - r = self.__update(self) - else: - r = self.__update(*controls) - self.__handle_mount_unmount(*r) - - def add(self, *controls: Control) -> None: - with self.__lock: - self._controls.extend(controls) - r = self.__update(self) - self.__handle_mount_unmount(*r) - - def insert(self, at: int, *controls: Control) -> None: - with self.__lock: - n = at - for control in controls: - self._controls.insert(n, control) - n += 1 - r = self.__update(self) - self.__handle_mount_unmount(*r) - - def remove(self, *controls: Control) -> None: - with self.__lock: - for control in controls: - self._controls.remove(control) - r = self.__update(self) - self.__handle_mount_unmount(*r) - - def remove_at(self, index: int) -> None: - with self.__lock: - self._controls.pop(index) - r = self.__update(self) - self.__handle_mount_unmount(*r) - - def clean(self) -> None: - self._clean(self) - self._controls.clear() - - def _clean(self, control: Control) -> None: - with self.__lock: - control._previous_children.clear() - assert control.uid is not None - removed_controls = [] - for child in control._get_children(): - removed_controls.extend( - self._remove_control_recursively(self.index, child) - ) - self._send_command("clean", [control.uid]) - for c in removed_controls: - c.will_unmount() - - def _close(self) -> None: - self.__pubsub.unsubscribe_all() - removed_controls = self._remove_control_recursively(self.index, self) - for c in removed_controls: - c.will_unmount() - c._dispose() - self._controls.clear() - self._previous_children.clear() - self.__on_view_pop = None - self.__client_storage = None - self.__session_storage = None - self.__conn = None - - def __update(self, *controls: Control) -> Tuple[List[Control], List[Control]]: - if not self.__conn: - raise PageDisconnectedException("Page has been disconnected") - commands, added_controls, removed_controls = self.__prepare_update(*controls) - self.__validate_controls_page(added_controls) - results = self.__conn.send_commands(self._session_id, commands).results - self.__update_control_ids(added_controls, results) - return added_controls, removed_controls - - def __prepare_update( - self, *controls: Control - ) -> Tuple[List[Any], List[Control], List[Control]]: - added_controls = [] - removed_controls = [] - commands = [] - - # build commands - - for control in controls: - control.build_update_commands( - self._index, commands, added_controls, removed_controls - ) - return commands, added_controls, removed_controls - - def __validate_controls_page(self, added_controls: List[Control]) -> None: - for ctrl in added_controls: - if ctrl.page and ctrl.page != self: - raise Exception( - f"Control has already been added to another page: {ctrl}" - ) - - def __update_control_ids( - self, added_controls: List[Control], results: List[Any] - ) -> None: - if len(results) > 0: - n = 0 - for line in results: - for id in line.split(" "): - added_controls[n]._Control__uid = id - - # add to index - self._index[id] = added_controls[n] - - n += 1 - - def __handle_mount_unmount(self, added_controls, removed_controls) -> None: - for ctrl in removed_controls: - ctrl.will_unmount() - ctrl.parent = None # remove parent reference - ctrl.page = None - for ctrl in added_controls: - ctrl.did_mount() - - def error(self, message: str = "") -> None: - with self.__lock: - self._send_command("error", [message]) - - async def on_event_async(self, e: Event) -> None: - logger.debug(f"page.on_event_async: {e.target} {e.name} {e.data}") - - if e.target == "page" and e.name == "change": - with self.__lock: - self.__on_page_change_event(e.data) - elif e.target in self._index: - ce = ControlEvent(e.target, e.name, e.data, self._index[e.target], self) - handler = self._index[e.target].event_handlers.get(e.name) - if handler: - if asyncio.iscoroutinefunction(handler): - await handler(ce) - else: - self.run_thread(handler, ce) - - def __on_page_change_event(self, data: str) -> None: - for props in json.loads(data): - id = props["i"] - if id in self._index: - for name in props: - if name != "i": - self._index[id]._set_attr(name, props[name], dirty=False) - if id in self.__snapshot: - self.__snapshot[id][name] = props[name] - - def run_task( - self, - handler: Callable[InputT, Awaitable[RetT]], - *args: InputT.args, - **kwargs: InputT.kwargs, - ) -> Future[RetT]: - _session_page.set(self) - assert asyncio.iscoroutinefunction(handler) - - future = asyncio.run_coroutine_threadsafe(handler(*args, **kwargs), self.__loop) - - def _on_completion(f): - try: - exception = f.exception() - if exception: - raise exception - except CancelledError: - pass - - future.add_done_callback(_on_completion) - - return future - - def __context_wrapper(self, handler: Callable[..., Any]) -> Wrapper: - def wrapper(*args,**kwargs): - _session_page.set(self) - handler(*args,**kwargs) - - return wrapper - - def run_thread( - self, - handler: Callable[InputT, Any], - *args: InputT.args, - **kwargs: InputT.kwargs, - ) -> None: - handler_with_context = self.__context_wrapper(handler) - if is_pyodide(): - handler_with_context(*args, **kwargs) - else: - assert self.__loop - self.__loop.call_soon_threadsafe( - self.__loop.run_in_executor, - self.__executor, - partial(handler_with_context, *args, **kwargs), - ) - - def go( - self, route: str, skip_route_change_event: bool = False, **kwargs: Any - ) -> None: - self.route = route if not kwargs else route + self.query.post(kwargs) - - if not skip_route_change_event: - self.run_task( - self.__on_route_change.get_handler(), - ControlEvent( - target="page", - name="route_change", - data=self.route, - page=self, - control=self, - ), - ) - self.update() - self.query() # Update query url (required when using go) - - def get_upload_url(self, file_name: str, expires: int) -> str: - r = self._send_command( - "getUploadUrl", attrs={"file": file_name, "expires": str(expires)} - ) - if r.error: - raise Exception(r.error) - return r.result - - def login( - self, - provider: OAuthProvider, - fetch_user: Optional[bool] = True, - fetch_groups: Optional[bool] = False, - scope: Optional[List[str]] = None, - saved_token: Optional[str] = None, - on_open_authorization_url: Optional[Callable[[str], None]] = None, - complete_page_html: Optional[str] = None, - redirect_to_page: Optional[bool] = False, - authorization: Type[AT] = Authorization, - ) -> AT: - self.__authorization = authorization( - provider, - fetch_user=fetch_user, - fetch_groups=fetch_groups, - scope=scope, - ) - if saved_token is None: - authorization_url, state = self.__authorization.get_authorization_data() - auth_attrs = {"state": state} - if complete_page_html: - auth_attrs["completePageHtml"] = complete_page_html - if redirect_to_page: - up = urlparse(provider.redirect_url) - auth_attrs["completePageUrl"] = up._replace( - path=self.__conn.page_name - ).geturl() - result = self._send_command("oauthAuthorize", attrs=auth_attrs) - if result.error != "": - raise Exception(result.error) - if on_open_authorization_url: - on_open_authorization_url(authorization_url) - else: - self.launch_url( - authorization_url, "flet_oauth_signin", web_popup_window=self.web - ) - else: - self.__authorization.dehydrate_token(saved_token) - self.run_task( - self.__on_login.get_handler(), - LoginEvent( - error="", - error_description="", - page=self, - control=self, - target="page", - name="on_login", - data="", - ), - ) - return self.__authorization - - async def login_async( - self, - provider: OAuthProvider, - fetch_user: Optional[bool] = True, - fetch_groups: Optional[bool] = False, - scope: Optional[List[str]] = None, - saved_token: Optional[str] = None, - on_open_authorization_url: Optional[ - Callable[[str], Coroutine[Any, Any, None]] - ] = None, - complete_page_html: Optional[str] = None, - redirect_to_page: Optional[bool] = False, - authorization: Type[AT] = Authorization, - ) -> AT: - self.__authorization = authorization( - provider, - fetch_user=fetch_user, - fetch_groups=fetch_groups, - scope=scope, - ) - if saved_token is None: - authorization_url, state = self.__authorization.get_authorization_data() - auth_attrs = {"state": state} - if complete_page_html: - auth_attrs["completePageHtml"] = complete_page_html - if redirect_to_page: - up = urlparse(provider.redirect_url) - auth_attrs["completePageUrl"] = up._replace( - path=f"{self.__conn.page_name}{self.route}" - ).geturl() - result = self._send_command("oauthAuthorize", attrs=auth_attrs) - if result.error != "": - raise Exception(result.error) - if on_open_authorization_url: - await on_open_authorization_url(authorization_url) - else: - self.launch_url( - authorization_url, "flet_oauth_signin", web_popup_window=self.web - ) - else: - await self.__authorization.dehydrate_token_async(saved_token) - self.run_task( - self.__on_login.get_handler(), - LoginEvent( - error="", - error_description="", - page=self, - control=self, - target="page", - name="on_login", - data="", - ), - ) - return self.__authorization - - async def _authorize_callback_async(self, data: str) -> None: - await self.on_event_async(Event("page", "authorize", json.dumps(data))) - - async def __on_authorize_async(self, e) -> None: - assert self.__authorization - d = json.loads(e.data) - state = d.get("state") - assert state == self.__authorization.state - - if not self.web: - if self.platform in ["ios", "android"]: - # close web view on mobile - self.close_in_app_web_view() - else: - # activate desktop window - self.window.to_front() - login_evt = LoginEvent( - error=d.get("error"), - error_description=d.get("error_description"), - page=self, - control=self, - target="page", - name="on_login", - data="", - ) - if not login_evt.error: - # perform token request - - code = d.get("code") - assert code not in [None, ""] - try: - await self.__authorization.request_token_async(code) - except Exception as ex: - login_evt.error = str(ex) - self.run_task( - self.__on_login.get_handler(), - login_evt, - ) - - def logout(self) -> None: - self.__authorization = None - self.run_task( - self.__on_logout.get_handler(), - ControlEvent( - target="page", name="logout", data="", control=self, page=self - ), - ) - - def _send_command( - self, - name: str, - values: Optional[List[str]] = None, - attrs: Optional[Dict[str, str]] = None, - ): - return self.__conn.send_command( - self._session_id, - Command( - indent=0, - name=name, - values=values if values is not None else [], - attrs=attrs or {}, - ), - ) - - def set_clipboard(self, value: str, wait_timeout: Optional[float] = 10) -> None: - self._invoke_method("setClipboard", {"data": value}, wait_timeout=wait_timeout) - - def get_clipboard(self, wait_timeout: Optional[float] = 10) -> Optional[str]: - return self._invoke_method( - "getClipboard", wait_for_result=True, wait_timeout=wait_timeout - ) - - async def get_clipboard_async( - self, wait_timeout: Optional[float] = 10 - ) -> Optional[str]: - return await self._invoke_method_async( - "getClipboard", wait_for_result=True, wait_timeout=wait_timeout - ) - - def launch_url( - self, - url: str, - web_window_name: Optional[str] = None, - web_popup_window: Optional[bool] = False, - window_width: Optional[int] = None, - window_height: Optional[int] = None, - ) -> None: - args = {"url": url} - if web_window_name: - args["web_window_name"] = web_window_name - if web_popup_window: - args["web_popup_window"] = str(web_popup_window) - if window_width: - args["window_width"] = str(window_width) - if window_height: - args["window_height"] = str(window_height) - self._invoke_method("launchUrl", args) - - def can_launch_url(self, url: str) -> bool: - args = {"url": url} - return self._invoke_method("canLaunchUrl", args, wait_for_result=True) == "true" - - async def can_launch_url_async(self, url: str) -> bool: - args = {"url": url} - return ( - await self._invoke_method_async("canLaunchUrl", args, wait_for_result=True) - == "true" - ) - - def close_in_app_web_view(self) -> None: - self._invoke_method("closeInAppWebView") - - def scroll_to( - self, - offset: Optional[float] = None, - delta: Optional[float] = None, - key: Optional[str] = None, - duration: Optional[int] = None, - curve: Optional[AnimationCurve] = None, - ) -> None: - self.__default_view.scroll_to( - offset=offset, delta=delta, key=key, duration=duration, curve=curve - ) - - def _invoke_method( - self, - method_name: str, - arguments: Optional[Dict[str, str]] = None, - control_id: Optional[str] = "", - wait_for_result: Optional[bool] = False, - wait_timeout: Optional[float] = 5, - ) -> Optional[str]: - method_id = uuid.uuid4().hex - - # register callback - evt: Optional[threading.Event] = None - if wait_for_result: - evt = threading.Event() - self.__method_calls[method_id] = evt - - # call method - result = self._send_command( - "invokeMethod", values=[method_id, method_name, control_id], attrs=arguments - ) - - if result.error != "": - if wait_for_result: - del self.__method_calls[method_id] - raise Exception(result.error) - if not wait_for_result: - return - assert evt is not None - - if not evt.wait(wait_timeout): - del self.__method_calls[method_id] - raise TimeoutError( - f"Timeout waiting for invokeMethod {method_name}({arguments}) call" - ) - - result, err = self.__method_call_results.pop(evt) - if err: - raise Exception(err) - if result is None or result == "null": - return None - return result - - async def _invoke_method_async( - self, - method_name: str, - arguments: Optional[Dict[str, str]] = None, - control_id: Optional[str] = "", - wait_for_result: Optional[bool] = False, - wait_timeout: Optional[float] = 5, - ) -> Optional[str]: - method_id = uuid.uuid4().hex - - # register callback - evt: Optional[asyncio.Event] = None - if wait_for_result: - evt = asyncio.Event() - self.__method_calls[method_id] = evt - - # call method - result = self._send_command( - "invokeMethod", values=[method_id, method_name, control_id], attrs=arguments - ) - - if result.error != "": - if wait_for_result: - del self.__method_calls[method_id] - raise Exception(result.error) - if not wait_for_result: - return - assert evt is not None - - try: - await asyncio.wait_for(evt.wait(), timeout=wait_timeout) - except TimeoutError: - del self.__method_calls[method_id] - raise TimeoutError( - f"Timeout waiting for invokeMethod {method_name}({arguments}) call" - ) - - result, err = self.__method_call_results.pop(evt) - if err: - raise Exception(err) - if result == "null": - return None - return result - - def __on_invoke_method_result(self, e) -> None: - d = json.loads(e.data) - result = InvokeMethodResults(**d) - evt = self.__method_calls.pop(result.method_id, None) - if evt is None: - return - self.__method_call_results[evt] = (result.result, result.error) - evt.set() - - def open(self, control: Control) -> None: - if not hasattr(control, "open"): - raise ValueError(f"{control.__class__.__qualname__} has no open attribute") - - control.open = True - - if isinstance(control, NavigationDrawer): - if control.position == NavigationDrawerPosition.END: - if self.end_drawer != control: - self.end_drawer = control - self.update() - else: - if self.drawer != control: - self.drawer = control - self.update() - else: - if control not in self.__offstage.controls: - self.__offstage.controls.append(control) - self.__offstage.update() - - control.update() - - @staticmethod - def close(control: Control) -> None: - if hasattr(control, "open"): - control.open = False - control.update() - else: - raise ValueError(f"{control.__class__.__qualname__} has no open attribute") - - # query - @property - def query(self) -> QueryString: - return self.__query - - # url - @property - def url(self) -> Optional[str]: - return self.__conn.page_url - - # name - @property - def name(self) -> str: - return self.__conn.page_name - - # connection - @property - def connection(self) -> Optional[Connection]: - return self.__conn - - # snapshot - @property - def snapshot(self) -> Dict[str, Dict[str, Any]]: - return self.__snapshot - - # loop - @property - def loop(self) -> asyncio.AbstractEventLoop: - return self.__loop - - # executor - @property - def executor(self) -> Optional[ThreadPoolExecutor]: - return self.__executor - - # expires_at - @property - def expires_at(self) -> Optional[datetime]: - return self.__expires_at - - # index - @property - def index(self) -> "Dict[str, Page]": - return self._index - - # session_id - @property - def session_id(self) -> Any: - return self._session_id - - # auth - @property - def auth(self) -> Optional[Authorization]: - return self.__authorization - - # pubsub - @property - def pubsub(self) -> PubSubClient: - return self.__pubsub - - # overlay - @property - def overlay(self) -> List[Control]: - return self.__offstage.controls - - # title - @property - def title(self) -> str: - return self._get_attr("title") - - @title.setter - def title(self, value: str): - self._set_attr("title", value) - - # route - @property - def route(self) -> str: - return self._get_attr("route") - - @route.setter - def route(self, value: str): - self._set_attr("route", value) - - # pwa - @property - def pwa(self) -> bool: - return self._get_attr("pwa", data_type="bool", def_value=False) - - # web - @property - def web(self) -> bool: - return cast(bool, self._get_attr("web", data_type="bool", def_value=False)) - - # debug - @property - def debug(self) -> bool: - return cast(bool, self._get_attr("debug", data_type="bool", def_value=False)) - - # platform - @property - def platform(self) -> PagePlatform: - return PagePlatform(self._get_attr("platform")) - - @platform.setter - def platform(self, value: PagePlatform): - self._set_attr( - "platform", value.value if isinstance(value, PagePlatform) else value - ) - - # platform_brightness - @property - def platform_brightness(self) -> Brightness: - brightness = self._get_attr("platformBrightness") - assert brightness - return Brightness(brightness) - - # media - @property - def media(self) -> Optional["PageMediaData"]: - m = self._get_attr("media") - if not isinstance(m, str): - return None - d = json.loads(m) - return PageMediaData(**d) - - # client_ip - @property - def client_ip(self): - return self._get_attr("clientIP") - - # client_user_agent - @property - def client_user_agent(self): - return self._get_attr("clientUserAgent") - - # fonts - @property - def fonts(self) -> Optional[Dict[str, str]]: - return self.__fonts - - @fonts.setter - def fonts(self, value: Optional[Dict[str, str]]): - self.__fonts = value - - # views - @property - def views(self) -> List[View]: - return self.__views - - # controls - @property - def controls(self) -> Optional[List[Control]]: - return self.__default_view.controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__default_view.controls = list(value) if value is not None else [] - - # appbar - @property - def appbar(self) -> Union[AppBar, CupertinoAppBar, None]: - return self.__default_view.appbar - - @appbar.setter - def appbar(self, value: Union[AppBar, CupertinoAppBar, None]): - self.__default_view.appbar = value - - # bottom_appbar - @property - def bottom_appbar(self) -> Optional[BottomAppBar]: - return self.__default_view.bottom_appbar - - @bottom_appbar.setter - def bottom_appbar(self, value: Optional[BottomAppBar]): - self.__default_view.bottom_appbar = value - - # navigation_bar - @property - def navigation_bar(self) -> Optional[Union[NavigationBar, CupertinoNavigationBar]]: - return self.__default_view.navigation_bar - - @navigation_bar.setter - def navigation_bar( - self, - value: Optional[Union[NavigationBar, CupertinoNavigationBar]], - ): - self.__default_view.navigation_bar = value - - # drawer - @property - def drawer(self) -> Optional[NavigationDrawer]: - return self.__default_view.drawer - - @drawer.setter - def drawer(self, value: Optional[NavigationDrawer]): - self.__default_view.drawer = value - - # end_drawer - @property - def end_drawer(self) -> Optional[NavigationDrawer]: - return self.__default_view.end_drawer - - @end_drawer.setter - def end_drawer(self, value: Optional[NavigationDrawer]): - self.__default_view.end_drawer = value - - # decoration - @property - def decoration(self) -> Optional[BoxDecoration]: - return self.__default_view.decoration - - @decoration.setter - def decoration(self, value: Optional[BoxDecoration]): - self.__default_view.decoration = value - - # foreground_decoration - @property - def foreground_decoration(self) -> Optional[BoxDecoration]: - return self.__default_view.foreground_decoration - - @foreground_decoration.setter - def foreground_decoration(self, value: Optional[BoxDecoration]): - self.__default_view.foreground_decoration = value - - # floating_action_button - @property - def floating_action_button(self) -> Optional[FloatingActionButton]: - return self.__default_view.floating_action_button - - @floating_action_button.setter - def floating_action_button(self, value: Optional[FloatingActionButton]): - self.__default_view.floating_action_button = value - - # floating_action_button_location - @property - def floating_action_button_location( - self, - ) -> Union[FloatingActionButtonLocation, OffsetValue]: - return self.__default_view.floating_action_button_location - - @floating_action_button_location.setter - def floating_action_button_location( - self, value: Union[FloatingActionButtonLocation, OffsetValue] - ): - self.__default_view.floating_action_button_location = value - - # horizontal_alignment - @property - def horizontal_alignment(self) -> CrossAxisAlignment: - return self.__default_view.horizontal_alignment - - @horizontal_alignment.setter - def horizontal_alignment(self, value: CrossAxisAlignment): - self.__default_view.horizontal_alignment = value - - # vertical_alignment - @property - def vertical_alignment(self) -> MainAxisAlignment: - return self.__default_view.vertical_alignment - - @vertical_alignment.setter - def vertical_alignment(self, value: MainAxisAlignment): - self.__default_view.vertical_alignment = value - - # window - @property - def window(self) -> Window: - return self.__window - - # browser_context_menu - @property - def browser_context_menu(self) -> BrowserContextMenu: - return self.__browser_context_menu - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self.__default_view.spacing - - @spacing.setter - def spacing(self, value: OptionalNumber): - self.__default_view.spacing = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__default_view.padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__default_view.padding = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__default_view.bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__default_view.bgcolor = value - - # scroll - @property - def scroll(self) -> Optional[ScrollMode]: - return self.__default_view.scroll - - @scroll.setter - def scroll(self, value: Optional[ScrollMode]): - self.__default_view.scroll = value - - # auto_scroll - @property - def auto_scroll(self) -> bool: - return self.__default_view.auto_scroll - - @auto_scroll.setter - def auto_scroll(self, value: Optional[bool]): - self.__default_view.auto_scroll = value - - # client_storage - @property - def client_storage(self) -> ClientStorage: - return self.__client_storage - - # session_storage - @property - def session(self) -> SessionStorage: - return self.__session_storage - - # theme_mode - @property - def theme_mode(self) -> Optional[ThemeMode]: - return self.__theme_mode - - @theme_mode.setter - def theme_mode(self, value: Optional[ThemeMode]): - self.__theme_mode = value - self._set_attr( - "themeMode", value.value if isinstance(value, ThemeMode) else value - ) - - # theme - @property - def theme(self) -> Optional[Theme]: - return self.__theme - - @theme.setter - def theme(self, value: Optional[Theme]): - self.__theme = value - - # dark_theme - @property - def dark_theme(self) -> Optional[Theme]: - return self.__dark_theme - - @dark_theme.setter - def dark_theme(self, value: Optional[Theme]): - self.__dark_theme = value - - # locale_configuration - @property - def locale_configuration(self) -> Optional[LocaleConfiguration]: - return self.__locale_configuration - - @locale_configuration.setter - def locale_configuration(self, value: Optional[LocaleConfiguration]): - self.__locale_configuration = value - - # rtl - @property - def rtl(self) -> bool: - return self._get_attr("rtl", data_type="bool", def_value=False) - - @rtl.setter - def rtl(self, value: Optional[bool]): - self._set_attr("rtl", value) - - # show_semantics_debugger - @property - def show_semantics_debugger(self) -> bool: - return self._get_attr( - "showSemanticsDebugger", data_type="bool", def_value=False - ) - - @show_semantics_debugger.setter - def show_semantics_debugger(self, value: Optional[bool]): - self._set_attr("showSemanticsDebugger", value) - - # width - @property - def width(self) -> OptionalNumber: - w = self._get_attr("width") - return float(w) if w else 0 - - # height - @property - def height(self) -> OptionalNumber: - h = self._get_attr("height") - return float(h) if h else 0 - - # on_scroll_interval - @property - def on_scroll_interval(self) -> OptionalNumber: - return self.__default_view.on_scroll_interval - - @on_scroll_interval.setter - def on_scroll_interval(self, value: OptionalNumber): - self.__default_view.on_scroll_interval = value - - # on_close - @property - def on_close(self) -> OptionalControlEventCallable: - return self.__on_close.handler - - @on_close.setter - def on_close(self, handler: OptionalControlEventCallable): - self.__on_close.handler = handler - - @property - def on_resized(self) -> OptionalEventCallable["WindowResizeEvent"]: - return self.__on_resized.handler - - @on_resized.setter - def on_resized(self, handler: OptionalEventCallable["WindowResizeEvent"]): - self.__on_resized.handler = handler - - # on_platform_brightness_change - @property - def on_platform_brightness_change(self) -> OptionalControlEventCallable: - return self.__on_platform_brightness_change.handler - - @on_platform_brightness_change.setter - def on_platform_brightness_change(self, handler: OptionalControlEventCallable): - self.__on_platform_brightness_change.handler = handler - - # on_app_lifecycle_change - @property - def on_app_lifecycle_state_change( - self, - ) -> OptionalEventCallable["AppLifecycleStateChangeEvent"]: - return self.__on_app_lifecycle_state_change.handler - - @on_app_lifecycle_state_change.setter - def on_app_lifecycle_state_change( - self, handler: OptionalEventCallable["AppLifecycleStateChangeEvent"] - ): - self.__on_app_lifecycle_state_change.handler = handler - - # on_route_change - @property - def on_route_change(self) -> OptionalEventCallable["RouteChangeEvent"]: - return self.__on_route_change.handler - - @on_route_change.setter - def on_route_change(self, handler: OptionalEventCallable["RouteChangeEvent"]): - self.__on_route_change.handler = handler - - # on_view_pop - @property - def on_view_pop(self) -> OptionalEventCallable["ViewPopEvent"]: - return self.__on_view_pop.handler - - @on_view_pop.setter - def on_view_pop(self, handler: OptionalEventCallable["ViewPopEvent"]): - self.__on_view_pop.handler = handler - - # on_keyboard_event - @property - def on_keyboard_event(self) -> OptionalEventCallable["KeyboardEvent"]: - return self.__on_keyboard_event.handler - - @on_keyboard_event.setter - def on_keyboard_event(self, handler: OptionalEventCallable["KeyboardEvent"]): - self.__on_keyboard_event.handler = handler - self._set_attr("onKeyboardEvent", True if handler else None) - - # on_media_change - @property - def on_media_change(self) -> OptionalEventCallable["PageMediaData"]: - return self.__on_page_media_change_event.handler - - @on_media_change.setter - def on_media_change(self, handler: OptionalEventCallable["PageMediaData"]): - self.__on_page_media_change_event.handler = handler - - # on_connect - @property - def on_connect(self) -> OptionalControlEventCallable: - return self.__on_connect.handler - - @on_connect.setter - def on_connect(self, handler: OptionalControlEventCallable): - self.__on_connect.handler = handler - - # on_disconnect - @property - def on_disconnect(self) -> OptionalControlEventCallable: - return self.__on_disconnect.handler - - @on_disconnect.setter - def on_disconnect(self, handler: OptionalControlEventCallable): - self.__on_disconnect.handler = handler - - # on_login - @property - def on_login(self) -> OptionalEventCallable["LoginEvent"]: - return self.__on_login.handler - - @on_login.setter - def on_login(self, handler: OptionalEventCallable["LoginEvent"]): - self.__on_login.handler = handler - - # on_logout - @property - def on_logout(self) -> OptionalControlEventCallable: - return self.__on_logout.handler - - @on_logout.setter - def on_logout(self, handler: OptionalControlEventCallable): - self.__on_logout.handler = handler - - # on_error - @property - def on_error(self) -> OptionalControlEventCallable: - return self.__on_error.handler - - @on_error.setter - def on_error(self, handler: OptionalControlEventCallable): - self.__on_error.handler = handler - - # on_scroll - @property - def on_scroll(self): - return self.__default_view.on_scroll - - @on_scroll.setter - def on_scroll(self, handler: Optional[Callable[[OnScrollEvent], None]]): - self.__default_view.on_scroll = handler - - # Magic methods - def __contains__(self, item: Control) -> bool: - return item in self._controls - - -class Offstage(Control): - def __init__( - self, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ) -> None: - Control.__init__( - self, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__controls: List[Control] = [] - self.__banner = None - self.__snack_bar = None - self.__dialog = None - self.__bottom_sheet = None - self.__splash = None - - def _get_control_name(self): - return "offstage" - - def _get_children(self): - return self.__controls - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - # splash - @property - def splash(self) -> Optional[Control]: - return self.__splash - - @splash.setter - def splash(self, value: Optional[Control]): - self.__splash = value - if value is not None: - self.__controls.append(value) - - # banner - @property - def banner(self) -> Optional[Banner]: - return self.__banner - - @banner.setter - def banner(self, value: Optional[Banner]): - self.__banner = value - if value is not None: - self.__controls.append(value) - - # snack_bar - @property - def snack_bar(self) -> Optional[SnackBar]: - return self.__snack_bar - - @snack_bar.setter - def snack_bar(self, value: Optional[SnackBar]): - self.__snack_bar = value - if value is not None: - self.__controls.append(value) - - # dialog - @property - def dialog(self) -> Optional[Union[AlertDialog, CupertinoAlertDialog]]: - return self.__dialog - - @dialog.setter - def dialog(self, value: Optional[Union[AlertDialog, CupertinoAlertDialog]]): - self.__dialog = value - if value is not None: - self.__controls.append(value) - - # bottom_sheet - @property - def bottom_sheet(self) -> Optional[Union[BottomSheet, CupertinoBottomSheet]]: - return self.__bottom_sheet - - @bottom_sheet.setter - def bottom_sheet(self, value: Optional[Union[BottomSheet, CupertinoBottomSheet]]): - self.__bottom_sheet = value - if value is not None: - self.__controls.append(value) - - -@dataclass -class RouteChangeEvent(ControlEvent): - route: str - - -@dataclass -class ViewPopEvent(ControlEvent): - view: View - - -@dataclass -class KeyboardEvent(ControlEvent): - key: str - shift: bool - ctrl: bool - alt: bool - meta: bool - - -class LoginEvent(ControlEvent): - def __init__( - self, - error: str, - error_description: str, - target: str, - name: str, - data: str, - control, - page, - ) -> None: - super().__init__(target, name, data, control, page) - - self.error = error - self.error_description = error_description - - -@dataclass -class InvokeMethodResults: - method_id: str - result: Optional[str] - error: Optional[str] - - -class PageMediaData(ControlEvent): - def __init__(self, padding, view_padding, view_insets) -> None: - self.padding = Padding( - left=padding["left"], - top=padding["top"], - right=padding["right"], - bottom=padding["bottom"], - ) - self.view_padding = Padding( - left=view_padding["left"], - top=view_padding["top"], - right=view_padding["right"], - bottom=view_padding["bottom"], - ) - self.view_insets = Padding( - left=view_insets["left"], - top=view_insets["top"], - right=view_insets["right"], - bottom=view_insets["bottom"], - ) - - def __str__(self) -> str: - return f"PageMediaData(padding={self.padding}, view_padding={self.view_padding}, view_insets={self.view_insets})" - - -class AppLifecycleStateChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent) -> None: - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.state = AppLifecycleState(e.data) - - -class WindowEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.type = WindowEventType(e.data) - - -class WindowResizeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - size = json.loads(e.data) - self.width: float = size["width"] - self.height: float = size["height"] diff --git a/sdk/python/packages/flet/src/flet/core/pagelet.py b/sdk/python/packages/flet/src/flet/core/pagelet.py deleted file mode 100644 index ee88146b36..0000000000 --- a/sdk/python/packages/flet/src/flet/core/pagelet.py +++ /dev/null @@ -1,314 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.app_bar import AppBar -from flet.core.badge import BadgeValue -from flet.core.bottom_app_bar import BottomAppBar -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.cupertino_app_bar import CupertinoAppBar -from flet.core.cupertino_navigation_bar import CupertinoNavigationBar -from flet.core.floating_action_button import FloatingActionButton -from flet.core.navigation_bar import NavigationBar -from flet.core.navigation_drawer import NavigationDrawer -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - FloatingActionButtonLocation, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Pagelet(ConstrainedControl, AdaptiveControl): - """ - Pagelet implements the basic Material Design visual layout structure. - - Use it for projects that require "page within a page" layouts with its own AppBar, BottomBar, Drawer, such as demos and galleries. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.add( - ft.Pagelet( - appbar=ft.CupertinoAppBar(middle=ft.Text("AppBar title")), - content=ft.Text("This is pagelet"), - ) - ) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/pagelet - """ - - def __init__( - self, - content: Control, - appbar: Union[AppBar, CupertinoAppBar, None] = None, - navigation_bar: Union[NavigationBar, CupertinoNavigationBar, None] = None, - bottom_app_bar: Optional[BottomAppBar] = None, - bottom_sheet: Optional[Control] = None, - drawer: Optional[NavigationDrawer] = None, - end_drawer: Optional[NavigationDrawer] = None, - floating_action_button: Optional[FloatingActionButton] = None, - floating_action_button_location: Union[ - FloatingActionButtonLocation, OffsetValue - ] = None, - bgcolor: Optional[ColorValue] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - key: Optional[str] = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.content = content - self.appbar = appbar - self.bgcolor = bgcolor - self.navigation_bar = navigation_bar - self.bottom_appbar = bottom_app_bar - self.bottom_sheet = bottom_sheet - self.drawer = drawer - self.end_drawer = end_drawer - self.floating_action_button = floating_action_button - self.floating_action_button_location = floating_action_button_location - - def _get_control_name(self): - return "pagelet" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - children = [self.__content] - if self.__appbar: - self.__appbar._set_attr_internal("n", "appbar") - children.append(self.__appbar) - if self.__navigation_bar: - self.__navigation_bar._set_attr_internal("n", "navigationbar") - children.append(self.__navigation_bar) - if self.__bottom_appbar: - self.__bottom_appbar._set_attr_internal("n", "bottomappbar") - children.append(self.__bottom_appbar) - if self.__bottom_sheet: - self.__bottom_sheet._set_attr_internal("n", "bottomsheet") - children.append(self.__bottom_sheet) - if self.__drawer: - self.__drawer._set_attr_internal("n", "drawer") - children.append(self.__drawer) - if self.__end_drawer: - self.__end_drawer._set_attr_internal("n", "enddrawer") - children.append(self.__end_drawer) - if self.__floating_action_button: - self.__floating_action_button._set_attr_internal( - "n", "floatingactionbutton" - ) - children.append(self.__floating_action_button) - return children - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - # Drawer - # - def show_drawer(self, drawer: NavigationDrawer): - self.drawer = drawer - self.drawer.open = True - self.update() - - def close_drawer(self): - if self.drawer is not None: - self.drawer.open = False - self.update() - - # End_drawer - # - def show_end_drawer(self, end_drawer: NavigationDrawer): - self.end_drawer = end_drawer - self.end_drawer.open = True - self.update() - - def close_end_drawer(self): - if self.end_drawer is not None: - self.end_drawer.open = False - self.update() - - # appbar - @property - def appbar(self) -> Union[AppBar, CupertinoAppBar, None]: - return self.__appbar - - @appbar.setter - def appbar(self, value: Union[AppBar, CupertinoAppBar, None]): - self.__appbar = value - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # bottom_appbar - @property - def bottom_appbar(self) -> Optional[BottomAppBar]: - return self.__bottom_appbar - - @bottom_appbar.setter - def bottom_appbar(self, value: Optional[BottomAppBar]): - self.__bottom_appbar = value - - # navigation_bar - @property - def navigation_bar(self) -> Union[NavigationBar, CupertinoNavigationBar, None]: - return self.__navigation_bar - - @navigation_bar.setter - def navigation_bar( - self, - value: Union[NavigationBar, CupertinoNavigationBar, None], - ): - self.__navigation_bar = value - - # bottom_sheet - @property - def bottom_sheet(self) -> Optional[Control]: - return self.__bottom_sheet - - @bottom_sheet.setter - def bottom_sheet( - self, - value: Optional[Control], - ): - self.__bottom_sheet = value - - # drawer - @property - def drawer(self) -> Optional[NavigationDrawer]: - return self.__drawer - - @drawer.setter - def drawer(self, value: Optional[NavigationDrawer]): - self.__drawer = value - - # end_drawer - @property - def end_drawer(self) -> Optional[NavigationDrawer]: - return self.__end_drawer - - @end_drawer.setter - def end_drawer(self, value: Optional[NavigationDrawer]): - self.__end_drawer = value - - # floating_action_button - @property - def floating_action_button(self) -> Optional[FloatingActionButton]: - return self.__floating_action_button - - @floating_action_button.setter - def floating_action_button(self, value: Optional[FloatingActionButton]): - self.__floating_action_button = value - - # floating_action_button_location - @property - def floating_action_button_location( - self, - ) -> Union[FloatingActionButtonLocation, OffsetValue]: - return self.__floating_action_button_location - - @floating_action_button_location.setter - def floating_action_button_location( - self, value: Union[FloatingActionButtonLocation, OffsetValue] - ): - self.__floating_action_button_location = value - self._set_attr( - "floatingActionButtonLocation", - value.value if isinstance(value, FloatingActionButtonLocation) else value, - ) diff --git a/sdk/python/packages/flet/src/flet/core/painting.py b/sdk/python/packages/flet/src/flet/core/painting.py deleted file mode 100644 index 42e2d3af5e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/painting.py +++ /dev/null @@ -1,75 +0,0 @@ -import math -from dataclasses import dataclass, field -from enum import Enum -from typing import List, Optional, Tuple, Union - -from flet.core.blur import Blur -from flet.core.gradients import GradientTileMode -from flet.core.types import BlendMode, ColorValue, OffsetValue, StrokeCap - - -class StrokeJoin(Enum): - MITER = "miter" - ROUND = "round" - BEVEL = "bevel" - - -class PaintingStyle(Enum): - FILL = "fill" - STROKE = "stroke" - - -@dataclass -class PaintGradient: - pass - - -@dataclass -class PaintLinearGradient(PaintGradient): - begin: Optional[OffsetValue] - end: Optional[OffsetValue] - colors: List[str] - color_stops: Optional[List[float]] = None - tile_mode: GradientTileMode = field(default=GradientTileMode.CLAMP) - type: str = field(default="linear") - - -@dataclass -class PaintRadialGradient(PaintGradient): - center: Optional[OffsetValue] - radius: Union[float, int] - colors: List[str] - color_stops: Optional[List[float]] = None - tile_mode: GradientTileMode = field(default=GradientTileMode.CLAMP) - focal: Optional[OffsetValue] = None - focal_radius: Union[float, int] = field(default=0.0) - type: str = field(default="radial") - - -@dataclass -class PaintSweepGradient(PaintGradient): - center: Optional[OffsetValue] - colors: List[str] - color_stops: Optional[List[float]] = None - tile_mode: GradientTileMode = field(default=GradientTileMode.CLAMP) - start_angle: float = field(default=0.0) - end_angle: float = field(default=math.pi * 2) - rotation: Union[None, float, int] = None - type: str = field(default="sweep") - - -@dataclass -class Paint: - color: Optional[ColorValue] = None - blend_mode: Optional[BlendMode] = None - blur_image: Union[ - None, float, int, Tuple[Union[float, int], Union[float, int]], Blur - ] = None - anti_alias: Optional[bool] = None - gradient: Optional[PaintGradient] = None - stroke_cap: Optional[StrokeCap] = None - stroke_join: Optional[StrokeJoin] = None - stroke_miter_limit: Optional[float] = None - stroke_width: Optional[float] = None - stroke_dash_pattern: Optional[List[float]] = None - style: Optional[PaintingStyle] = None diff --git a/sdk/python/packages/flet/src/flet/core/permission_handler.py b/sdk/python/packages/flet/src/flet/core/permission_handler.py deleted file mode 100644 index d0a00e4ede..0000000000 --- a/sdk/python/packages/flet/src/flet/core/permission_handler.py +++ /dev/null @@ -1,150 +0,0 @@ -from enum import Enum -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref -from flet.utils import deprecated - - -class PermissionStatus(Enum): - GRANTED = "granted" - DENIED = "denied" - PERMANENTLY_DENIED = "permanentlyDenied" - LIMITED = "limited" - PROVISIONAL = "provisional" - RESTRICTED = "restricted" - - -class PermissionType(Enum): - ACCESS_MEDIA_LOCATION = "accessMediaLocation" - ACCESS_NOTIFICATION_POLICY = "accessNotificationPolicy" - ACTIVITY_RECOGNITION = "activityRecognition" - APP_TRACKING_TRANSPARENCY = "appTrackingTransparency" - ASSISTANT = "assistant" - AUDIO = "audio" - BACKGROUND_REFRESH = "backgroundRefresh" - BLUETOOTH = "bluetooth" - BLUETOOTH_ADVERTISE = "bluetoothAdvertise" - BLUETOOTH_CONNECT = "bluetoothConnect" - BLUETOOTH_SCAN = "bluetoothScan" - CALENDAR_FULL_ACCESS = "calendarFullAccess" - CALENDAR_WRITE_ONLY = "calendarWriteOnly" - CAMERA = "camera" - CONTACTS = "contacts" - CRITICAL_ALERTS = "criticalAlerts" - IGNORE_BATTERY_OPTIMIZATIONS = "ignoreBatteryOptimizations" - LOCATION = "location" - LOCATION_ALWAYS = "locationAlways" - LOCATION_WHEN_IN_USE = "locationWhenInUse" - MANAGE_EXTERNAL_STORAGE = "manageExternalStorage" - MEDIA_LIBRARY = "mediaLibrary" - MICROPHONE = "microphone" - NEARBY_WIFI_DEVICES = "nearbyWifiDevices" - NOTIFICATION = "notification" - PHONE = "phone" - PHOTOS = "photos" - PHOTOS_ADD_ONLY = "photosAddOnly" - REMINDERS = "reminders" - REQUEST_INSTALL_PACKAGES = "requestInstallPackages" - SCHEDULE_EXACT_ALARM = "scheduleExactAlarm" - SENSORS = "sensors" - SENSORS_ALWAYS = "sensorsAlways" - SMS = "sms" - SPEECH = "speech" - STORAGE = "storage" - SYSTEM_ALERT_WINDOW = "systemAlertWindow" - UNKNOWN = "unknown" - VIDEOS = "videos" - - -@deprecated( - reason="PermissionHandler control has been moved to a separate Python package: https://pypi.org/project/flet-permission-handler. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class PermissionHandler(Control): - """ - A control that allows you check and request permission from your device. - This control is non-visual and should be added to `page.overlay` list. - - ----- - - Online docs: https://flet.dev/docs/controls/permissionhandler - """ - - def __init__( - self, - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - - def _get_control_name(self): - return "permission_handler" - - def check_permission( - self, of: PermissionType, wait_timeout: Optional[float] = 25 - ) -> Optional[PermissionStatus]: - out = self.invoke_method( - "check_permission", - {"of": of.value if isinstance(of, PermissionType) else of}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return PermissionStatus(out) if out is not None else None - - async def check_permission_async( - self, of: PermissionType, wait_timeout: Optional[float] = 25 - ) -> Optional[PermissionStatus]: - out = await self.invoke_method_async( - "check_permission", - {"of": of.value if isinstance(of, PermissionType) else of}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return PermissionStatus(out) if out is not None else None - - def request_permission( - self, of: PermissionType, wait_timeout: Optional[float] = 25 - ) -> Optional[PermissionStatus]: - out = self.invoke_method( - "request_permission", - {"of": of.value if isinstance(of, PermissionType) else of}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return PermissionStatus(out) if out is not None else None - - async def request_permission_async( - self, of: PermissionType, wait_timeout: Optional[float] = 25 - ) -> Optional[PermissionStatus]: - out = await self.invoke_method_async( - "request_permission", - {"of": of.value if isinstance(of, PermissionType) else of}, - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return PermissionStatus(out) if out is not None else None - - def open_app_settings(self, wait_timeout: Optional[float] = 10) -> bool: - opened = self.invoke_method( - "open_app_settings", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return opened == "true" - - async def open_app_settings_async(self, wait_timeout: Optional[float] = 10) -> bool: - opened = await self.invoke_method_async( - "open_app_settings", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return opened == "true" diff --git a/sdk/python/packages/flet/src/flet/core/placeholder.py b/sdk/python/packages/flet/src/flet/core/placeholder.py deleted file mode 100644 index e384523818..0000000000 --- a/sdk/python/packages/flet/src/flet/core/placeholder.py +++ /dev/null @@ -1,160 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Placeholder(ConstrainedControl): - """ - A placeholder box. - - ----- - - Online docs: https://flet.dev/docs/controls/placeholder - """ - - def __init__( - self, - content: Optional[Control] = None, - color: Optional[ColorValue] = None, - fallback_height: OptionalNumber = None, - fallback_width: OptionalNumber = None, - stroke_width: OptionalNumber = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.content = content - self.color = color - self.fallback_height = fallback_height - self.fallback_width = fallback_width - self.stroke_width = stroke_width - - def _get_control_name(self): - return "placeholder" - - def _get_children(self): - return [self.content] if self.content is not None else [] - - # fallback_height - @property - def fallback_height(self) -> float: - return self._get_attr("fallbackHeight", data_type="float", def_value=400.0) - - @fallback_height.setter - def fallback_height(self, value: OptionalNumber): - assert value is None or value >= 0, "fallback_height cannot be negative" - self._set_attr("fallbackHeight", value) - - # fallback_width - @property - def fallback_width(self) -> float: - return self._get_attr("fallbackWidth", data_type="float", def_value=400.0) - - @fallback_width.setter - def fallback_width(self, value: OptionalNumber): - assert value is None or value >= 0, "fallback_width cannot be negative" - self._set_attr("fallbackWidth", value) - - # stroke_width - @property - def stroke_width(self) -> float: - return self._get_attr("strokeWidth", data_type="float", def_value=2.0) - - @stroke_width.setter - def stroke_width(self, value: OptionalNumber): - self._set_attr("strokeWidth", value) - - # color - @property - def color(self) -> str: - return self._get_attr("color", def_value="bluegrey700") - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value diff --git a/sdk/python/packages/flet/src/flet/core/plotly_chart.py b/sdk/python/packages/flet/src/flet/core/plotly_chart.py deleted file mode 100644 index 37c0f563be..0000000000 --- a/sdk/python/packages/flet/src/flet/core/plotly_chart.py +++ /dev/null @@ -1,160 +0,0 @@ -import re -import xml.etree.ElementTree as ET -from typing import Any, Optional, Union - -from flet.core import alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.container import Container -from flet.core.control import OptionalNumber -from flet.core.image import Image -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ImageFit, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - -try: - from plotly.graph_objects import Figure -except ImportError: - raise Exception('Install "plotly" Python package to use PlotlyChart control.') - - -class PlotlyChart(Container): - """ - Displays Plotly(https://plotly.com/python/) chart. - - Example: - ``` - import plotly.express as px - - import flet as ft - from flet.core.plotly_chart import PlotlyChart - - def main(page: ft.Page): - - df = px.data.gapminder().query("continent=='Oceania'") - fig = px.line(df, x="year", y="lifeExp", color="country") - - page.add(PlotlyChart(fig, expand=True)) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/plotlychart - """ - - def __init__( - self, - figure: Optional[Figure] = None, - isolated: bool = False, - original_size: bool = False, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Container.__init__( - self, - ref=ref, - key=key, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.figure = figure - self.isolated = isolated - self.original_size = original_size - - def is_isolated(self): - return self.__isolated - - def build(self): - self.alignment = alignment.center - self.__img = Image(fit=ImageFit.FILL) - self.content = self.__img - - def before_update(self): - super().before_update() - if self.__figure is not None: - svg = self.__figure.to_image(format="svg").decode("utf-8") - - if not self.__original_size: - root = ET.fromstring(svg) - w = float(re.findall(r"\d+", root.attrib["width"])[0]) - h = float(re.findall(r"\d+", root.attrib["height"])[0]) - self.__img.aspect_ratio = w / h - self.__img.src = svg - - # original_size - @property - def original_size(self) -> bool: - return self.__original_size - - @original_size.setter - def original_size(self, value: bool): - self.__original_size = value - - # isolated - @property - def isolated(self) -> bool: - return self.__isolated - - @isolated.setter - def isolated(self, value: bool): - self.__isolated = value - - # figure - @property - def figure(self) -> Optional[Figure]: - return self.__figure - - @figure.setter - def figure(self, value: Optional[Figure]): - self.__figure = value diff --git a/sdk/python/packages/flet/src/flet/core/popup_menu_button.py b/sdk/python/packages/flet/src/flet/core/popup_menu_button.py deleted file mode 100644 index dbde08f185..0000000000 --- a/sdk/python/packages/flet/src/flet/core/popup_menu_button.py +++ /dev/null @@ -1,532 +0,0 @@ -from enum import Enum -from typing import Any, List, Optional, Union - -from flet.core.animation import AnimationStyle, AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxConstraints -from flet.core.buttons import ButtonStyle, OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class PopupMenuPosition(Enum): - OVER = "over" - UNDER = "under" - - -class PopupMenuItem(Control): - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - checked: Optional[bool] = None, - content: Optional[Control] = None, - height: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_click: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - data=data, - tooltip=tooltip, - badge=badge, - ) - - self.checked = checked - self.icon = icon - self.text = text - self.__content: Optional[Control] = None - self.content = content - self.on_click = on_click - self.height = height - self.padding = padding - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "popupmenuitem" - - def _get_children(self): - children = [] - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # checked - @property - def checked(self) -> bool: - return self._get_attr("checked", data_type="bool", def_value=False) - - @checked.setter - def checked(self, value: Optional[bool]): - self._set_attr("checked", value) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self._get_attr("mouseCursor") - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # height - @property - def height(self) -> float: - return self._get_attr("height", data_type="float", def_value=48.0) - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - -class PopupMenuButton(ConstrainedControl): - """ - An icon button which displays a menu when clicked. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def check_item_clicked(e): - e.control.checked = not e.control.checked - page.update() - - pb = ft.PopupMenuButton( - items=[ - ft.PopupMenuItem(text="Item 1"), - ft.PopupMenuItem(icon=ft.icons.POWER_INPUT, text="Check power"), - ft.PopupMenuItem( - content=ft.Row( - [ - ft.Icon(ft.icons.HOURGLASS_TOP_OUTLINED), - ft.Text("Item with a custom content"), - ] - ), - on_click=lambda _: print("Button with a custom content clicked!"), - ), - ft.PopupMenuItem(), # divider - ft.PopupMenuItem( - text="Checked item", checked=False, on_click=check_item_clicked - ), - ] - ) - page.add(pb) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/popupmenubutton - """ - - def __init__( - self, - content: Optional[Control] = None, - items: Optional[List[PopupMenuItem]] = None, - icon: Optional[IconValue] = None, - bgcolor: Optional[ColorValue] = None, - icon_color: Optional[ColorValue] = None, - shadow_color: Optional[ColorValue] = None, - surface_tint_color: Optional[ColorValue] = None, - icon_size: OptionalNumber = None, - splash_radius: OptionalNumber = None, - elevation: OptionalNumber = None, - menu_position: Optional[PopupMenuPosition] = None, - clip_behavior: Optional[ClipBehavior] = None, - enable_feedback: Optional[bool] = None, - shape: Optional[OutlinedBorder] = None, - padding: Optional[PaddingValue] = None, - menu_padding: Optional[PaddingValue] = None, - style: Optional[ButtonStyle] = None, - popup_animation_style: Optional[AnimationStyle] = None, - size_constraints: Optional[BoxConstraints] = None, - on_open: OptionalControlEventCallable = None, - on_cancel: OptionalControlEventCallable = None, - on_select: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - self.items = items - self.icon = icon - self.on_cancel = on_cancel - self.on_open = on_open - self.shape = shape - self.padding = padding - self.menu_padding = menu_padding - self.clip_behavior = clip_behavior - self.bgcolor = bgcolor - self.icon_color = icon_color - self.shadow_color = shadow_color - self.surface_tint_color = surface_tint_color - self.splash_radius = splash_radius - self.icon_size = icon_size - self.elevation = elevation - self.enable_feedback = enable_feedback - self.content = content - self.menu_position = menu_position - self.style = style - self.popup_animation_style = popup_animation_style - self.size_constraints = size_constraints - self.on_select = on_select - - def _get_control_name(self): - return "popupmenubutton" - - def _get_children(self): - children = [] - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children + self.__items - - def __contains__(self, item): - return item in self.__items - - def before_update(self): - super().before_update() - self._set_attr_json("shape", self.__shape) - self._set_attr_json("padding", self.__padding) - self._set_attr_json("menuPadding", self.__menu_padding) - self._set_attr_json("style", self.__style) - self._set_attr_json("popupAnimationStyle", self.__popup_animation_style) - self._set_attr_json("sizeConstraints", self.__size_constraints) - - # items - @property - def items(self) -> Optional[List[PopupMenuItem]]: - return self.__items - - @items.setter - def items(self, value: Optional[List[PopupMenuItem]]): - self.__items = value if value is not None else [] - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # size_constraints - @property - def size_constraints(self) -> Optional[BoxConstraints]: - return self.__size_constraints - - @size_constraints.setter - def size_constraints(self, value: Optional[BoxConstraints]): - self.__size_constraints = value - - # menu_padding - @property - def menu_padding(self) -> Optional[PaddingValue]: - return self.__menu_padding - - @menu_padding.setter - def menu_padding(self, value: Optional[PaddingValue]): - self.__menu_padding = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # shadow_color - @property - def shadow_color(self) -> Optional[ColorValue]: - return self.__shadow_color - - @shadow_color.setter - def shadow_color(self, value: Optional[ColorValue]): - self.__shadow_color = value - self._set_enum_attr("shadowColor", value, ColorEnums) - - # surface_tint_color - @property - def surface_tint_color(self) -> Optional[ColorValue]: - return self.__surface_tint_color - - @surface_tint_color.setter - def surface_tint_color(self, value: Optional[ColorValue]): - self.__surface_tint_color = value - self._set_enum_attr("surfaceTintColor", value, ColorEnums) - - # icon_size - @property - def icon_size(self) -> OptionalNumber: - return self._get_attr("iconSize", data_type="float") - - @icon_size.setter - def icon_size(self, value: OptionalNumber): - self._set_attr("iconSize", value) - - # enable_feedback - @property - def enable_feedback(self) -> bool: - return self._get_attr("enableFeedback", data_type="bool", def_value=True) - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # elevation - @property - def elevation(self) -> float: - return self._get_attr("elevation", data_type="float", def_value=8.0) - - @elevation.setter - def elevation(self, value: OptionalNumber): - self._set_attr("elevation", value) - - # splash_radius - @property - def splash_radius(self) -> OptionalNumber: - return self._get_attr("splashRadius", data_type="float") - - @splash_radius.setter - def splash_radius(self, value: OptionalNumber): - self._set_attr("splashRadius", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # popup_animation_style - @property - def popup_animation_style(self) -> Optional[AnimationStyle]: - return self.__popup_animation_style - - @popup_animation_style.setter - def popup_animation_style(self, value: Optional[AnimationStyle]): - self.__popup_animation_style = value - - # menu_position - @property - def menu_position(self) -> Optional[PopupMenuPosition]: - return self.__menu_position - - @menu_position.setter - def menu_position(self, value: Optional[PopupMenuPosition]): - self.__menu_position = value - self._set_enum_attr("menuPosition", value, PopupMenuPosition) - - # clip_behavior - @property - def clip_behavior(self) -> ClipBehavior: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: ClipBehavior): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # on_cancel - @property - def on_cancel(self) -> OptionalControlEventCallable: - return self._get_event_handler("cancel") - - @on_cancel.setter - def on_cancel(self, handler: OptionalControlEventCallable): - self._add_event_handler("cancel", handler) - - # on_open - @property - def on_open(self) -> OptionalControlEventCallable: - return self._get_event_handler("open") - - @on_open.setter - def on_open(self, handler: OptionalControlEventCallable): - self._add_event_handler("open", handler) - - # on_select - @property - def on_select(self) -> OptionalControlEventCallable: - return self._get_event_handler("select") - - @on_select.setter - def on_select(self, handler: OptionalControlEventCallable): - self._add_event_handler("select", handler) diff --git a/sdk/python/packages/flet/src/flet/core/progress_bar.py b/sdk/python/packages/flet/src/flet/core/progress_bar.py deleted file mode 100644 index 9591b1a676..0000000000 --- a/sdk/python/packages/flet/src/flet/core/progress_bar.py +++ /dev/null @@ -1,269 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils.deprecated import deprecated_property - - -class ProgressBar(ConstrainedControl): - """ - A material design linear progress indicator, also known as a progress bar. - - A control that shows progress along a line. - - Example: - - ``` - from time import sleep - - import flet as ft - - def main(page: ft.Page): - pb = ft.ProgressBar(width=400) - - page.add( - ft.Text("Linear progress indicator", style="headlineSmall"), - ft.Column([ ft.Text("Doing something..."), pb]), - ft.Text("Indeterminate progress bar", style="headlineSmall"), - ft.ProgressBar(width=400, color="amber", bgcolor="#eeeeee"), - ) - - for i in range(0, 101): - pb.value = i * 0.01 - sleep(0.1) - page.update() - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/progressbar - """ - - def __init__( - self, - value: OptionalNumber = None, - bar_height: OptionalNumber = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - border_radius: Optional[BorderRadiusValue] = None, - semantics_label: Optional[str] = None, - semantics_value: OptionalNumber = None, - stop_indicator_color: Optional[ColorValue] = None, - stop_indicator_radius: OptionalNumber = None, - track_gap: OptionalNumber = None, - year_2023: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.bar_height = bar_height - self.color = color - self.bgcolor = bgcolor - self.border_radius = border_radius - self.semantics_label = semantics_label - self.semantics_value = semantics_value - self.stop_indicator_color = stop_indicator_color - self.stop_indicator_radius = stop_indicator_radius - self.track_gap = track_gap - self.year_2023 = year_2023 - - def _get_control_name(self): - return "progressbar" - - def before_update(self): - super().before_update() - self._set_attr_json("borderRadius", self.__border_radius) - - # value - @property - def value(self) -> OptionalNumber: - return self._get_attr("value", data_type="float") - - @value.setter - def value(self, value: OptionalNumber): - assert value is None or value >= 0, "value cannot be negative" - self._set_attr("value", value) - - # bar_height - @property - def bar_height(self) -> OptionalNumber: - return self._get_attr("barHeight", data_type="float") - - @bar_height.setter - def bar_height(self, value: OptionalNumber): - assert value is None or value >= 0, "bar_height cannot be negative" - self._set_attr("barHeight", value) - - # semantics_value - @property - def semantics_value(self) -> OptionalNumber: - return self._get_attr("semanticsValue", data_type="float") - - @semantics_value.setter - def semantics_value(self, value: OptionalNumber): - assert value is None or value >= 0, "semantics_value cannot be negative" - self._set_attr("semanticsValue", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value - - # track_gap - @property - def track_gap(self) -> OptionalNumber: - return self._get_attr("trackGap", data_type="float") - - @track_gap.setter - def track_gap(self, value: OptionalNumber): - self._set_attr("trackGap", value) - - # year_2023 - @property - def year_2023(self) -> Optional[bool]: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - return self._get_attr("year2023", data_type="bool", def_value=True) - - @year_2023.setter - def year_2023(self, value: Optional[bool]): - self._set_attr("year2023", value) - if value is not None: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - - # stop_indicator_color - @property - def stop_indicator_color(self) -> Optional[ColorValue]: - return self.__stop_indicator_color - - @stop_indicator_color.setter - def stop_indicator_color(self, value: Optional[ColorValue]): - self.__stop_indicator_color = value - self._set_enum_attr("stopIndicatorColor", value, ColorEnums) - - # stop_indicator_radius - @property - def stop_indicator_radius(self) -> OptionalNumber: - return self._get_attr("stopIndicatorRadius", data_type="float") - - @stop_indicator_radius.setter - def stop_indicator_radius(self, value: OptionalNumber): - self._set_attr("stopIndicatorRadius", value) diff --git a/sdk/python/packages/flet/src/flet/core/progress_ring.py b/sdk/python/packages/flet/src/flet/core/progress_ring.py deleted file mode 100644 index 2f7d7622a5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/progress_ring.py +++ /dev/null @@ -1,274 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import BoxConstraints -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - StrokeCap, - PaddingValue, -) -from flet.utils.deprecated import deprecated_property - - -class ProgressRing(ConstrainedControl): - """ - A material design circular progress indicator, which spins to indicate that the application is busy. - - A control that shows progress along a circle. - - Example: - - ``` - from time import sleep - import flet as ft - - def main(page: ft.Page): - pr = ft.ProgressRing(width=16, height=16, stroke_width = 2) - - page.add( - ft.Text("Circular progress indicator", style="headlineSmall"), - ft.Row([pr, ft.Text("Wait for the completion...")]), - ft.Text("Indeterminate circular progress", style="headlineSmall"), - ft.Column( - [ft.ProgressRing(), ft.Text("I'm going to run for ages...")], - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - ), - ) - - for i in range(0, 101): - pr.value = i * 0.01 - sleep(0.1) - page.update() - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/progressring - """ - - def __init__( - self, - value: OptionalNumber = None, - stroke_width: OptionalNumber = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - stroke_align: OptionalNumber = None, - stroke_cap: Optional[StrokeCap] = None, - semantics_label: Optional[str] = None, - semantics_value: OptionalNumber = None, - track_gap: OptionalNumber = None, - size_constraints: Optional[BoxConstraints] = None, - padding: Optional[PaddingValue] = None, - year_2023: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.value = value - self.stroke_width = stroke_width - self.color = color - self.bgcolor = bgcolor - self.semantics_label = semantics_label - self.semantics_value = semantics_value - self.stroke_align = stroke_align - self.stroke_cap = stroke_cap - self.track_gap = track_gap - self.size_constraints = size_constraints - self.padding = padding - self.year_2023 = year_2023 - - def _get_control_name(self): - return "progressring" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - self._set_attr_json("sizeConstraints", self.__size_constraints) - - # value - @property - def value(self) -> OptionalNumber: - return self._get_attr("value", data_type="float") - - @value.setter - def value(self, value: OptionalNumber): - self._set_attr("value", value) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # track_gap - @property - def track_gap(self) -> OptionalNumber: - return self._get_attr("trackGap", data_type="float") - - @track_gap.setter - def track_gap(self, value: OptionalNumber): - self._set_attr("trackGap", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # size_constraints - @property - def size_constraints(self) -> Optional[BoxConstraints]: - return self.__size_constraints - - @size_constraints.setter - def size_constraints(self, value: Optional[BoxConstraints]): - self.__size_constraints = value - - # year_2023 - @property - def year_2023(self) -> Optional[bool]: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - return self._get_attr("year2023", data_type="bool", def_value=True) - - @year_2023.setter - def year_2023(self, value: Optional[bool]): - self._set_attr("year2023", value) - if value is not None: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - - # stroke_width - @property - def stroke_width(self) -> float: - return self._get_attr("strokeWidth", data_type="float", def_value=4.0) - - @stroke_width.setter - def stroke_width(self, value: OptionalNumber): - assert value is None or value >= 0, "stroke_width cannot be negative" - self._set_attr("strokeWidth", value) - - # stroke_align - @property - def stroke_align(self) -> float: - return self._get_attr("strokeAlign", data_type="float", def_value=0.0) - - @stroke_align.setter - def stroke_align(self, value: OptionalNumber): - self._set_attr("strokeAlign", value) - - # stroke_cap - @property - def stroke_cap(self) -> Optional[StrokeCap]: - return self.__stroke_cap - - @stroke_cap.setter - def stroke_cap(self, value: Optional[StrokeCap]): - self.__stroke_cap = value - self._set_enum_attr("strokeCap", value, StrokeCap) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) diff --git a/sdk/python/packages/flet/src/flet/core/protocol.py b/sdk/python/packages/flet/src/flet/core/protocol.py deleted file mode 100644 index 6cebebb95d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/protocol.py +++ /dev/null @@ -1,208 +0,0 @@ -import json -from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional - - -class CommandEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, Message): - return obj.__dict__ - elif isinstance(obj, ClientMessage): - return obj.__dict__ - elif isinstance(obj, Command): - d = {} - if obj.indent > 0: - d["i"] = obj.indent - if obj.name is not None: - d["n"] = obj.name - if obj.values and len(obj.values) > 0: - d["v"] = obj.values - if obj.attrs and len(obj.attrs) > 0: - d["a"] = obj.attrs - if obj.commands and len(obj.commands) > 0: - d["c"] = obj.commands - return d - elif isinstance(obj, object): - return obj.__dict__ - return json.JSONEncoder.default(self, obj) - - -class Actions: - REGISTER_HOST_CLIENT = "registerHostClient" - SESSION_CREATED = "sessionCreated" - PAGE_COMMAND_FROM_HOST = "pageCommandFromHost" - PAGE_COMMANDS_BATCH_FROM_HOST = "pageCommandsBatchFromHost" - PAGE_EVENT_TO_HOST = "pageEventToHost" - - -@dataclass -class Command: - indent: int - name: Optional[str] - values: List[str] = field(default_factory=list) - attrs: Dict[str, str] = field(default_factory=dict) - commands: List[Any] = field(default_factory=list) - - def __str__(self): - return f"{self.name} {self.values} {self.attrs}" - - -@dataclass -class Message: - id: str - action: str - payload: Any - - -@dataclass -class PageCommandRequestPayload: - pageName: str - sessionID: str - command: Command - - -@dataclass -class PageCommandResponsePayload: - result: str - error: str - - -@dataclass -class PageCommandsBatchRequestPayload: - pageName: str - sessionID: str - commands: List[Command] - - -@dataclass -class PageCommandsBatchResponsePayload: - results: List[str] - error: str - - -@dataclass -class PageEventPayload: - pageName: str - sessionID: str - eventTarget: str - eventName: str - eventData: str - - -@dataclass -class RegisterHostClientRequestPayload: - hostClientID: Optional[str] - pageName: str - assetsDir: Optional[str] - authToken: Optional[str] - permissions: Optional[str] - - -@dataclass -class RegisterHostClientResponsePayload: - hostClientID: str - pageName: str - sessionID: str - error: str - - -@dataclass -class PageSessionCreatedPayload: - pageName: str - sessionID: str - - -# -# Local client protocol for desktop apps -# - - -class ClientActions: - REGISTER_WEB_CLIENT = "registerWebClient" - PAGE_EVENT_FROM_WEB = "pageEventFromWeb" - SESSION_CRASHED = "sessionCrashed" - INVOKE_METHOD = "invokeMethod" - PAGE_CONTROLS_BATCH = "pageControlsBatch" - ADD_PAGE_CONTROLS = "addPageControls" - UPDATE_CONTROL_PROPS = "updateControlProps" - CLEAN_CONTROL = "cleanControl" - REMOVE_CONTROL = "removeControl" - - -@dataclass -class ClientMessage: - action: str - payload: Any - - -@dataclass -class RegisterWebClientRequestPayload: - pageName: str - pageRoute: str - pageWidth: str - pageHeight: str - windowWidth: str - windowHeight: str - windowTop: str - windowLeft: str - isPWA: str - isWeb: str - isDebug: str - platform: str - platformBrightness: str - media: str - sessionId: str - - -@dataclass -class SessionPayload: - id: str - controls: Dict[str, Dict[str, Any]] - - -@dataclass -class RegisterWebClientResponsePayload: - session: SessionPayload - error: str - appInactive: bool - - -@dataclass -class PageEventFromWebPayload: - eventTarget: str - eventName: str - eventData: str - - -@dataclass -class SessionCrashedPayload: - message: str - - -@dataclass -class InvokeMethodPayload: - methodId: str - methodName: str - controlId: str - arguments: Dict[str, str] - - -@dataclass -class AddPageControlsPayload: - controls: List[Dict[str, Any]] - trimIDs: List[str] = field(default_factory=lambda: []) - - -@dataclass -class UpdateControlPropsPayload: - props: List[Dict[str, str]] - - -@dataclass -class CleanControlPayload: - ids: List[str] - - -@dataclass -class RemoveControlPayload: - ids: List[str] diff --git a/sdk/python/packages/flet/src/flet/core/pubsub/pubsub_client.py b/sdk/python/packages/flet/src/flet/core/pubsub/pubsub_client.py deleted file mode 100644 index 46932a37a4..0000000000 --- a/sdk/python/packages/flet/src/flet/core/pubsub/pubsub_client.py +++ /dev/null @@ -1,40 +0,0 @@ -import logging -from typing import Any, Callable - -import flet.core -from flet.core.pubsub.pubsub_hub import PubSubHub - -logger = logging.getLogger(flet.__name__) - - -class PubSubClient: - def __init__(self, pubsub: PubSubHub, session_id: str): - self.__pubsub = pubsub - self.__session_id = session_id - - def send_all(self, message: Any): - self.__pubsub.send_all(message) - - def send_all_on_topic(self, topic: str, message: Any): - self.__pubsub.send_all_on_topic(topic, message) - - def send_others(self, message: Any): - self.__pubsub.send_others(self.__session_id, message) - - def send_others_on_topic(self, topic: str, message: Any): - self.__pubsub.send_others_on_topic(self.__session_id, topic, message) - - def subscribe(self, handler: Callable): - self.__pubsub.subscribe(self.__session_id, handler) - - def subscribe_topic(self, topic: str, handler: Callable): - self.__pubsub.subscribe_topic(self.__session_id, topic, handler) - - def unsubscribe(self): - self.__pubsub.unsubscribe(self.__session_id) - - def unsubscribe_topic(self, topic: str): - self.__pubsub.unsubscribe_topic(self.__session_id, topic) - - def unsubscribe_all(self): - self.__pubsub.unsubscribe_all(self.__session_id) diff --git a/sdk/python/packages/flet/src/flet/core/pubsub/pubsub_hub.py b/sdk/python/packages/flet/src/flet/core/pubsub/pubsub_hub.py deleted file mode 100644 index 1a69e64980..0000000000 --- a/sdk/python/packages/flet/src/flet/core/pubsub/pubsub_hub.py +++ /dev/null @@ -1,160 +0,0 @@ -import asyncio -import logging -import threading -from concurrent.futures import ThreadPoolExecutor -from typing import Any, Awaitable, Callable, Dict, Iterable, Optional, Union - -import flet.core -from flet.core.locks import NopeLock -from flet.utils import is_pyodide - -logger = logging.getLogger(flet.__name__) - - -class PubSubHub: - def __init__( - self, - loop: Optional[asyncio.AbstractEventLoop] = None, - executor: Optional[ThreadPoolExecutor] = None, - ): - logger.debug("Creating new PubSubHub instance") - self.__loop = loop - self.__executor = executor - self.__lock = threading.Lock() if not is_pyodide() else NopeLock() - self.__subscribers: Dict[ - str, set[Union[Callable, Callable[..., Awaitable[Any]]]] - ] = {} # key: session_id, value: handler - self.__topic_subscribers: Dict[ - str, Dict[str, set[Union[Callable, Callable[..., Awaitable[Any]]]]] - ] = {} # key: topic, value: dict[session_id, handler] - self.__subscriber_topics: Dict[ - str, Dict[str, set[Union[Callable, Callable[..., Awaitable[Any]]]]] - ] = {} # key: session_id, value: dict[topic, handler] - - def send_all(self, message: Any): - logger.debug(f"pubsub.send_all({message})") - with self.__lock: - for handlers in self.__subscribers.values(): - for handler in handlers: - self.__send(handler, [message]) - - def send_all_on_topic(self, topic: str, message: Any): - logger.debug(f"pubsub.send_all_on_topic({topic}, {message})") - with self.__lock: - if topic in self.__topic_subscribers: - for handlers in self.__topic_subscribers[topic].values(): - for handler in handlers: - self.__send(handler, [topic, message]) - - def send_others(self, except_session_id: str, message: Any): - logger.debug(f"pubsub.send_others({except_session_id}, {message})") - with self.__lock: - for session_id, handlers in self.__subscribers.items(): - if except_session_id != session_id: - for handler in handlers: - self.__send(handler, [message]) - - def send_others_on_topic(self, except_session_id: str, topic: str, message: Any): - logger.debug( - f"pubsub.send_others_on_topic({except_session_id}, {topic}, {message})" - ) - with self.__lock: - if topic in self.__topic_subscribers: - for session_id, handlers in self.__topic_subscribers[topic].items(): - if except_session_id != session_id: - for handler in handlers: - self.__send(handler, [topic, message]) - - def subscribe(self, session_id: str, handler: Callable): - logger.debug(f"pubsub.subscribe({session_id})") - with self.__lock: - handlers = self.__subscribers.get(session_id) - if handlers is None: - handlers = set() - self.__subscribers[session_id] = handlers - handlers.add(handler) - - def subscribe_topic( - self, - session_id: str, - topic: str, - handler: Union[Callable, Callable[..., Awaitable[Any]]], - ): - logger.debug(f"pubsub.subscribe_topic({session_id}, {topic})") - with self.__lock: - self.__subscribe_topic(session_id, topic, handler) - - def __subscribe_topic( - self, - session_id: str, - topic: str, - handler: Union[Callable, Callable[..., Awaitable[Any]]], - ): - topic_subscribers = self.__topic_subscribers.get(topic) - if topic_subscribers is None: - topic_subscribers = {} - self.__topic_subscribers[topic] = topic_subscribers - handlers = topic_subscribers.get(session_id) - if handlers is None: - handlers = set() - topic_subscribers[session_id] = handlers - handlers.add(handler) - subscriber_topics = self.__subscriber_topics.get(session_id) - if subscriber_topics is None: - subscriber_topics = {} - self.__subscriber_topics[session_id] = subscriber_topics - handlers = subscriber_topics.get(topic) - if handlers is None: - handlers = set() - subscriber_topics[topic] = handlers - handlers.add(handler) - - def unsubscribe(self, session_id: str): - logger.debug(f"pubsub.unsubscribe({session_id})") - with self.__lock: - self.__unsubscribe(session_id) - - def unsubscribe_topic(self, session_id: str, topic: str): - logger.debug(f"pubsub.unsubscribe({session_id}, {topic})") - with self.__lock: - self.__unsubscribe_topic(session_id, topic) - - def unsubscribe_all(self, session_id: str): - logger.debug(f"pubsub.unsubscribe_all({session_id})") - with self.__lock: - self.__unsubscribe(session_id) - if session_id in self.__subscriber_topics: - for topic in list(self.__subscriber_topics[session_id].keys()): - self.__unsubscribe_topic(session_id, topic) - - def __unsubscribe(self, session_id: str): - logger.debug(f"pubsub.__unsubscribe({session_id})") - self.__subscribers.pop(session_id, None) - - def __unsubscribe_topic(self, session_id: str, topic: str): - logger.debug(f"pubsub.__unsubscribe_topic({session_id}, {topic})") - topic_subscribers = self.__topic_subscribers.get(topic) - if topic_subscribers is not None: - topic_subscribers.pop(session_id, None) - if len(topic_subscribers) == 0: - self.__topic_subscribers.pop(topic, None) - subscriber_topics = self.__subscriber_topics.get(session_id) - if subscriber_topics is not None: - subscriber_topics.pop(topic, None) - if len(subscriber_topics) == 0: - self.__subscriber_topics.pop(session_id, None) - - def __send( - self, handler: Union[Callable, Callable[..., Awaitable[Any]]], args: Iterable - ): - assert self.__loop, "PubSub event loop is not set" - - if asyncio.iscoroutinefunction(handler): - asyncio.run_coroutine_threadsafe(handler(*args), self.__loop) - else: - if self.__executor: - self.__loop.call_soon_threadsafe( - self.__loop.run_in_executor, self.__executor, handler, *args - ) - else: - handler(*args) diff --git a/sdk/python/packages/flet/src/flet/core/querystring.py b/sdk/python/packages/flet/src/flet/core/querystring.py deleted file mode 100644 index 5fb91fa4d5..0000000000 --- a/sdk/python/packages/flet/src/flet/core/querystring.py +++ /dev/null @@ -1,102 +0,0 @@ -import re -import urllib.parse - - -class UrlComponents: - """ - `UrlComponents` are meant to be used internally for decoding-encoding, it has no external use - """ - - def _encode_url_component(self, url: str) -> str: - """ - Function encodes querystring part of URL\n - Ex. q=dom & dogs -> q=dom+%26+dogs - """ - return urllib.parse.quote(url) - - def _decode_url_component(self, url: str) -> str: - """ - Function decodes querystring part of URL\n - Ex. q=dom+%26+dogs -> q=dom & dogs - """ - return urllib.parse.unquote(url) - - def _is_encoded(self) -> bool: - """ - Function returns True if URL is already encoded - """ - if "?" in self.url: - q_result = self._querystring_part() - return ( - self._decode_url_component( - self.url[q_result.start() + 1 : q_result.end()] - ) - != self.url[q_result.start() + 1 : q_result.end()] - ) - - def _querystring_part(self, url_string: bool = False): - """ - Function sliced url part and returns querystring part.\n - Use case: checking querystring part for encode, assiging decoded value - """ - pattern = re.compile(r"\?[\w\D]+") - data = pattern.search(self.url) - return data if url_string is False else self.url[data.start() + 1 : data.end()] - - -class QueryString(UrlComponents): - """ - Note: - `QueryString` class is meant to be for internal use inside of page. Hence, methods such as `get()` or `to_dict()` must be\n - called from `page` object\n - - Constructor: - `page` takes `Page` class an an argument and extracts URL automatically\n - - Methods: - Public: - `get()` method takes `key` an an argument and returns value according to key. (Ex: .../?name=Joe -> `get('name')` -> `Joe`)\n - `to_dict` returns all the key-value pairs of querystring as a `dict`\n - `path` returns url path (Ex: .../products?id=1 -> /products) - - Private(meant to be used only inside of page class): - `post()` method takes key-value pair as an argument and returs proceeded querystring ready to be merged with URL - - """ - - def __init__(self, page=None): - self.page = page - self.url = None - - def get(self, key: str) -> str: - self._data = self.to_dict - return self._data[key] - - def post(self, kwargs: dict): - return "?" + urllib.parse.urlencode(kwargs) - - @property - def to_dict(self) -> dict: - self._data = urllib.parse.urlparse(self.url).query - return dict(urllib.parse.parse_qsl(self._data)) - - # Path - @property - def path(self): - self._updated_url = self.url.replace("#/", "") if "#" in self.url else self.url - return urllib.parse.urlparse(self._updated_url).path - - def __call__(self): - """ - Call dunder method updates url after updating `Page` - """ - self.url = self.page.url + self.page.route - - # Checking if self.url is encoded and decoding it accordingly - if self._is_encoded() is True: - self.url = ( - self.page.url - + urllib.parse.urlparse(self.url).path - + "?" - + self._decode_url_component(self._querystring_part(url_string=True)) - ) diff --git a/sdk/python/packages/flet/src/flet/core/radio.py b/sdk/python/packages/flet/src/flet/core/radio.py deleted file mode 100644 index 04884f9b59..0000000000 --- a/sdk/python/packages/flet/src/flet/core/radio.py +++ /dev/null @@ -1,310 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - LabelPosition, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - VisualDensity, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class Radio(ConstrainedControl, AdaptiveControl): - """ - Radio buttons let people select a single option from two or more choices. - - Example: - ``` - import flet as ft - - def main(page): - def button_clicked(e): - t.value = f"Your favorite color is: {cg.value}" - page.update() - - t = ft.Text() - b = ft.ElevatedButton(text='Submit', on_click=button_clicked) - cg = ft.RadioGroup(content=ft.Column([ - ft.Radio(value="red", label="Red"), - ft.Radio(value="green", label="Green"), - ft.Radio(value="blue", label="Blue")])) - - page.add(ft.Text("Select your favorite color:"), cg, b, t) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/radio - """ - - def __init__( - self, - label: Optional[str] = None, - label_position: Optional[LabelPosition] = None, - label_style: Optional[TextStyle] = None, - value: Optional[str] = None, - autofocus: Optional[bool] = None, - fill_color: ControlStateValue[ColorValue] = None, - active_color: Optional[ColorValue] = None, - overlay_color: ControlStateValue[ColorValue] = None, - hover_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - splash_radius: OptionalNumber = None, - toggleable: Optional[bool] = None, - visual_density: Optional[VisualDensity] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.value = value - self.label = label - self.label_style = label_style - self.label_position = label_position - self.autofocus = autofocus - self.fill_color = fill_color - self.active_color = active_color - self.on_focus = on_focus - self.on_blur = on_blur - self.overlay_color = overlay_color - self.hover_color = hover_color - self.focus_color = focus_color - self.splash_radius = splash_radius - self.toggleable = toggleable - self.visual_density = visual_density - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "radio" - - def before_update(self): - super().before_update() - self._set_attr_json("fillColor", self.__fill_color, wrap_attr_dict=True) - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json("labelStyle", self.__label_style) - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value", def_value="") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # splash_radius - @property - def splash_radius(self) -> OptionalNumber: - return self._get_attr("splashRadius", data_type="float") - - @splash_radius.setter - def splash_radius(self, value: OptionalNumber): - self._set_attr("splashRadius", value) - - # toggleable - @property - def toggleable(self) -> bool: - return self._get_attr("toggleable", data_type="bool", def_value=False) - - @toggleable.setter - def toggleable(self, value: Optional[bool]): - self._set_attr("toggleable", value) - - # visual_density - @property - def visual_density(self) -> Optional[VisualDensity]: - return self.__visual_density - - @visual_density.setter - def visual_density(self, value: Optional[VisualDensity]): - self.__visual_density = value - self._set_enum_attr("visualDensity", value, VisualDensity) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # label_position - @property - def label_position(self) -> Optional[LabelPosition]: - return self.__label_position - - @label_position.setter - def label_position(self, value: Optional[LabelPosition]): - self.__label_position = value - self._set_enum_attr("labelPosition", value, LabelPosition) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # label_style - @property - def label_style(self) -> Optional[TextStyle]: - return self.__label_style - - @label_style.setter - def label_style(self, value: Optional[TextStyle]): - self.__label_style = value - - # fill_color - @property - def fill_color(self) -> ControlStateValue[str]: - return self.__fill_color - - @fill_color.setter - def fill_color(self, value: ControlStateValue[str]): - self.__fill_color = value - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[str]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[str]): - self.__overlay_color = value - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) diff --git a/sdk/python/packages/flet/src/flet/core/radio_group.py b/sdk/python/packages/flet/src/flet/core/radio_group.py deleted file mode 100644 index f095ec4113..0000000000 --- a/sdk/python/packages/flet/src/flet/core/radio_group.py +++ /dev/null @@ -1,102 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class RadioGroup(Control): - """ - Radio buttons let people select a single option from two or more choices. - - Example: - ``` - import flet as ft - - def main(page): - def button_clicked(e): - t.value = f"Your favorite color is: {cg.value}" - page.update() - - t = ft.Text() - b = ft.ElevatedButton(text='Submit', on_click=button_clicked) - cg = ft.RadioGroup(content=ft.Column([ - ft.Radio(value="red", label="Red"), - ft.Radio(value="green", label="Green"), - ft.Radio(value="blue", label="Blue")])) - - page.add(ft.Text("Select your favorite color:"), cg, b, t) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/radio - """ - - def __init__( - self, - content: Control, - value: Optional[str] = None, - on_change: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - opacity: OptionalNumber = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - opacity=opacity, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - self.value = value - self.on_change = on_change - - def _get_control_name(self): - return "radiogroup" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/range_slider.py b/sdk/python/packages/flet/src/flet/core/range_slider.py deleted file mode 100644 index ad303ffc66..0000000000 --- a/sdk/python/packages/flet/src/flet/core/range_slider.py +++ /dev/null @@ -1,317 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class RangeSlider(ConstrainedControl): - """ - A Material Design range slider. Used to select a range from a range of values. - A range slider can be used to select from either a continuous or a discrete set of values. - The default is to use a continuous range of values from min to max. - - Example: - ``` - import flet as ft - - - def range_slider_changed(e): - print(f"On change! Values are ({e.control.start_value}, {e.control.end_value})") - - - def range_slider_started_change(e): - print( - f"On change start! Values are ({e.control.start_value}, {e.control.end_value})" - ) - - - def range_slider_ended_change(e): - print(f"On change end! Values are ({e.control.start_value}, {e.control.end_value})") - - - def main(page: ft.Page): - range_slider = ft.RangeSlider( - min=0, - max=50, - start_value=10, - divisions=10, - end_value=20, - inactive_color=ft.colors.GREEN_300, - active_color=ft.colors.GREEN_700, - overlay_color=ft.colors.GREEN_100, - on_change=range_slider_changed, - on_change_start=range_slider_started_change, - on_change_end=range_slider_ended_change, - label="{value}%", - ) - - page.add( - ft.Column( - horizontal_alignment=ft.CrossAxisAlignment.CENTER, - controls=[ - ft.Text("Range slider", size=20, weight=ft.FontWeight.BOLD), - range_slider, - ], - ) - ) - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/rangeslider - """ - - def __init__( - self, - start_value: float, - end_value: float, - label: Optional[str] = None, - min: OptionalNumber = None, - max: OptionalNumber = None, - divisions: Optional[int] = None, - round: Optional[int] = None, - active_color: Optional[ColorValue] = None, - inactive_color: Optional[ColorValue] = None, - overlay_color: ControlStateValue[ColorValue] = None, - mouse_cursor: ControlStateValue[MouseCursor] = None, - on_change: OptionalControlEventCallable = None, - on_change_start: OptionalControlEventCallable = None, - on_change_end: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.start_value = start_value - self.end_value = end_value - self.label = label - - self.min = min - self.max = max - self.divisions = divisions - self.round = round - self.active_color = active_color - self.inactive_color = inactive_color - self.overlay_color = overlay_color - self.mouse_cursor = mouse_cursor - self.on_change = on_change - self.on_change_start = on_change_start - self.on_change_end = on_change_end - - def _get_control_name(self): - return "rangeslider" - - def before_update(self): - super().before_update() - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json("mouseCursor", self.__mouse_cursor, wrap_attr_dict=True) - - # start_value - @property - def start_value(self) -> float: - return self._get_attr("startValue", data_type="float") - - @start_value.setter - def start_value(self, value: float): - self._set_attr("startValue", value) - - # end_value - @property - def end_value(self) -> float: - return self._get_attr("endValue", data_type="float") - - @end_value.setter - def end_value(self, value: float): - self._set_attr("endValue", value) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # min - @property - def min(self) -> OptionalNumber: - return self._get_attr("min", data_type="float") - - @min.setter - def min(self, value: OptionalNumber): - if value is not None: - if self.max is not None: - assert value <= self.max, "min must be less than or equal to max" - self._set_attr("min", value) - - # max - @property - def max(self) -> OptionalNumber: - return self._get_attr("max", data_type="float") - - @max.setter - def max(self, value: OptionalNumber): - if value is not None: - if self.min is not None: - assert value >= self.min, "max must be greater than or equal to min" - self._set_attr("max", value) - - # divisions - @property - def divisions(self) -> Optional[int]: - return self._get_attr("divisions") - - @divisions.setter - def divisions(self, value: Optional[int]): - self._set_attr("divisions", value) - - # round - @property - def round(self) -> Optional[int]: - return self._get_attr("round") - - @round.setter - def round(self, value: Optional[int]): - self._set_attr("round", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # inactive_color - @property - def inactive_color(self) -> Optional[ColorValue]: - return self.__inactive_color - - @inactive_color.setter - def inactive_color(self, value: Optional[ColorValue]): - self.__inactive_color = value - self._set_enum_attr("inactiveColor", value, ColorEnums) - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[ColorValue]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[ColorValue]): - self.__overlay_color = value - - # mouse_cursor - @property - def mouse_cursor(self) -> ControlStateValue[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: ControlStateValue[MouseCursor]): - self.__mouse_cursor = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_change_start - @property - def on_change_start(self) -> OptionalControlEventCallable: - return self._get_event_handler("change_start") - - @on_change_start.setter - def on_change_start(self, handler: OptionalControlEventCallable): - self._add_event_handler("change_start", handler) - - # on_change_end - @property - def on_change_end(self) -> OptionalControlEventCallable: - return self._get_event_handler("change_end") - - @on_change_end.setter - def on_change_end(self, handler: OptionalControlEventCallable): - self._add_event_handler("change_end", handler) diff --git a/sdk/python/packages/flet/src/flet/core/ref.py b/sdk/python/packages/flet/src/flet/core/ref.py deleted file mode 100644 index 33df0977e6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/ref.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Generic, TypeVar - -T = TypeVar("T") - - -class Ref(Generic[T]): - def __init__(self): - self._current: T = None - - @property - def current(self) -> T: - return self._current - - @current.setter - def current(self, value: T): - self._current = value diff --git a/sdk/python/packages/flet/src/flet/core/reorderable_draggable.py b/sdk/python/packages/flet/src/flet/core/reorderable_draggable.py deleted file mode 100644 index c32c67a8e2..0000000000 --- a/sdk/python/packages/flet/src/flet/core/reorderable_draggable.py +++ /dev/null @@ -1,117 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class ReorderableDraggable(ConstrainedControl, AdaptiveControl): - def __init__( - self, - index: int, - content: Control, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - # - # Adaptive - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.content = content - self.index = index - - def _get_control_name(self): - return "reorderabledraggable" - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # index - @property - def index(self) -> int: - return self._get_attr("index", data_type="int") - - @index.setter - def index(self, value: int): - self._set_attr("index", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value diff --git a/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py b/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py deleted file mode 100644 index aa65a4b82c..0000000000 --- a/sdk/python/packages/flet/src/flet/core/reorderable_list_view.py +++ /dev/null @@ -1,266 +0,0 @@ -import json -from typing import Any, Optional, Sequence, Union - -from flet.core.animation import AnimationValue -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.list_view import ListView -from flet.core.ref import Ref -from flet.core.scrollable_control import OnScrollEvent -from flet.core.types import ( - ClipBehavior, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - MouseCursor, -) - - -class OnReorderEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.new_index: Optional[int] = d.get("new") - self.old_index: Optional[int] = d.get("old") - - -class ReorderableListView(ListView): - """ - A scrollable list of controls that can be reordered. - - ----- - - Online docs: https://flet.dev/docs/controls/reorderablelistview - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - horizontal: Optional[bool] = None, - item_extent: OptionalNumber = None, - first_item_prototype: Optional[bool] = None, - padding: PaddingValue = None, - clip_behavior: Optional[ClipBehavior] = None, - cache_extent: OptionalNumber = None, - anchor: OptionalNumber = None, - auto_scroller_velocity_scalar: OptionalNumber = None, - header: Optional[Control] = None, - footer: Optional[Control] = None, - build_controls_on_demand: Optional[bool] = None, - show_default_drag_handles: Optional[bool] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_reorder: OptionalEventCallable[OnReorderEvent] = None, - on_reorder_start: OptionalEventCallable[OnReorderEvent] = None, - on_reorder_end: OptionalEventCallable[OnReorderEvent] = None, - # - # ScrollableControl - # - auto_scroll: Optional[bool] = None, - reverse: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: OptionalEventCallable[OnScrollEvent] = None, - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: RotateValue = None, - scale: ScaleValue = None, - offset: OffsetValue = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ListView.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - auto_scroll=auto_scroll, - reverse=reverse, - on_scroll_interval=on_scroll_interval, - on_scroll=on_scroll, - adaptive=adaptive, - controls=controls, - horizontal=horizontal, - item_extent=item_extent, - first_item_prototype=first_item_prototype, - padding=padding, - clip_behavior=clip_behavior, - cache_extent=cache_extent, - build_controls_on_demand=build_controls_on_demand, - ) - self.__on_reorder = EventHandler(lambda e: OnReorderEvent(e)) - self._add_event_handler("reorder", self.__on_reorder.get_handler()) - - self.__on_reorder_start = EventHandler(lambda e: OnReorderEvent(e)) - self._add_event_handler("reorder_start", self.__on_reorder_start.get_handler()) - - self.__on_reorder_end = EventHandler(lambda e: OnReorderEvent(e)) - self._add_event_handler("reorder_end", self.__on_reorder_end.get_handler()) - - self.header = header - self.footer = footer - self.on_reorder = on_reorder - self.anchor = anchor - self.auto_scroller_velocity_scalar = auto_scroller_velocity_scalar - self.show_default_drag_handles = show_default_drag_handles - self.mouse_cursor = mouse_cursor - self.on_reorder_start = on_reorder_start - self.on_reorder_end = on_reorder_end - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "reorderablelistview" - - def before_update(self): - super().before_update() - - def _get_children(self): - children = super()._get_children() - if self.header: - self.__header._set_attr_internal("n", "header") - children.append(self.header) - if self.footer: - self.__footer._set_attr_internal("n", "footer") - children.append(self.footer) - return children - - # anchor - @property - def anchor(self) -> OptionalNumber: - return self._get_attr("anchor", data_type="float", def_value=0.0) - - @anchor.setter - def anchor(self, value: OptionalNumber): - self._set_attr("anchor", value) - - # auto_scroller_velocity_scalar - @property - def auto_scroller_velocity_scalar(self) -> OptionalNumber: - return self._get_attr("autoScrollerVelocityScalar", data_type="float") - - @auto_scroller_velocity_scalar.setter - def auto_scroller_velocity_scalar(self, value: OptionalNumber): - self._set_attr("autoScrollerVelocityScalar", value) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # header - @property - def header(self) -> Optional[Control]: - return self.__header - - @header.setter - def header(self, value: Optional[Control]): - self.__header = value - - # footer - @property - def footer(self) -> Optional[Control]: - return self.__footer - - @footer.setter - def footer(self, value: Optional[Control]): - self.__footer = value - - # show_default_drag_handles - @property - def show_default_drag_handles(self) -> Optional[bool]: - return self._get_attr( - "showDefaultDragHandles", data_type="bool", def_value=True - ) - - @show_default_drag_handles.setter - def show_default_drag_handles(self, value: Optional[bool]): - self._set_attr("showDefaultDragHandles", value) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # on_reorder - @property - def on_reorder(self) -> OptionalEventCallable[OnReorderEvent]: - return self.__on_reorder.handler - - @on_reorder.setter - def on_reorder(self, handler: OptionalEventCallable[OnReorderEvent]): - self.__on_reorder.handler = handler - - # on_reorder_start - @property - def on_reorder_start(self) -> OptionalEventCallable[OnReorderEvent]: - return self.__on_reorder_start.handler - - @on_reorder_start.setter - def on_reorder_start(self, handler: OptionalEventCallable[OnReorderEvent]): - self.__on_reorder_start.handler = handler - - # on_reorder_end - @property - def on_reorder_end(self) -> OptionalEventCallable[OnReorderEvent]: - return self.__on_reorder_end.handler - - @on_reorder_end.setter - def on_reorder_end(self, handler: OptionalEventCallable[OnReorderEvent]): - self.__on_reorder_end.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/responsive_row.py b/sdk/python/packages/flet/src/flet/core/responsive_row.py deleted file mode 100644 index 9eb5dd5a6e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/responsive_row.py +++ /dev/null @@ -1,204 +0,0 @@ -from typing import Any, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - CrossAxisAlignment, - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class ResponsiveRow(ConstrainedControl, AdaptiveControl): - """ - ResponsiveRow allows aligning child controls to virtual columns. By default, a virtual grid has 12 columns, but that can be customized with `ResponsiveRow.columns` property. - - Similar to `expand` property, every control now has `col` property which allows specifying how many columns a control should span. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - - page.add( - ft.ResponsiveRow( - [ - ft.TextField(label="TextField 1", col={"md": 4}), - ft.TextField(label="TextField 2", col={"md": 4}), - ft.TextField(label="TextField 3", col={"md": 4}), - ], - run_spacing={"xs": 10}, - ), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/responsiverow - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - columns: Optional[ResponsiveNumber] = None, - alignment: Optional[MainAxisAlignment] = None, - vertical_alignment: Optional[CrossAxisAlignment] = None, - spacing: Optional[ResponsiveNumber] = None, - run_spacing: Optional[ResponsiveNumber] = None, - rtl: Optional[bool] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.controls = controls - self.alignment = alignment - self.vertical_alignment = vertical_alignment - self.spacing = spacing - self.run_spacing = run_spacing - self.columns = columns - - def _get_control_name(self): - return "responsiverow" - - def before_update(self): - super().before_update() - self._set_attr_json("columns", self.__columns) - self._set_attr_json("spacing", self.__spacing) - self._set_attr_json("runSpacing", self.__run_spacing) - - def _get_children(self): - return self.__controls - - def clean(self): - super().clean() - self.__controls.clear() - - # horizontal_alignment - @property - def alignment(self) -> Optional[MainAxisAlignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[MainAxisAlignment]): - self.__alignment = value - self._set_enum_attr("alignment", value, MainAxisAlignment) - - # vertical_alignment - @property - def vertical_alignment(self) -> Optional[CrossAxisAlignment]: - return self.__vertical_alignment - - @vertical_alignment.setter - def vertical_alignment(self, value: Optional[CrossAxisAlignment]): - self.__vertical_alignment = value - self._set_enum_attr("verticalAlignment", value, CrossAxisAlignment) - - # columns - @property - def columns(self) -> Optional[ResponsiveNumber]: - return self.__columns - - @columns.setter - def columns(self, value: Optional[ResponsiveNumber]): - self.__columns = value - - # spacing - @property - def spacing(self) -> Optional[ResponsiveNumber]: - return self.__spacing - - @spacing.setter - def spacing(self, value: Optional[ResponsiveNumber]): - self.__spacing = value - - # run_spacing - @property - def run_spacing(self) -> Optional[ResponsiveNumber]: - return self.__run_spacing - - @run_spacing.setter - def run_spacing(self, value: Optional[ResponsiveNumber]): - self.__run_spacing = value - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] diff --git a/sdk/python/packages/flet/src/flet/core/rive.py b/sdk/python/packages/flet/src/flet/core/rive.py deleted file mode 100644 index 555e3192c6..0000000000 --- a/sdk/python/packages/flet/src/flet/core/rive.py +++ /dev/null @@ -1,194 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ImageFit, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils import deprecated - - -@deprecated( - reason="Rive control has been moved to a separate Python package: https://pypi.org/project/flet-rive. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Rive(ConstrainedControl): - """ - Displays rive animations. - - ----- - - Online docs: https://flet.dev/docs/controls/rive - """ - - def __init__( - self, - src: str, - placeholder: Optional[Control] = None, - artboard: Optional[str] = None, - alignment: Optional[Alignment] = None, - enable_antialiasing: Optional[bool] = None, - use_artboard_size: Optional[bool] = None, - fit: Optional[ImageFit] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.src = src - self.placeholder = placeholder - self.artboard = artboard - self.enable_antialiasing = enable_antialiasing - self.use_artboard_size = use_artboard_size - self.alignment = alignment - self.fit = fit - - def _get_control_name(self): - return "rive" - - def before_update(self): - super().before_update() - assert self.src, "src must be provided" - self._set_attr_json("alignment", self.__alignment) - - def _get_children(self): - if self.__placeholder: - return [self.__placeholder] - return [] - - # src - @property - def src(self) -> Optional[str]: - return self._get_attr("src") - - @src.setter - def src(self, value: Optional[str]): - self._set_attr("src", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # artboard - @property - def artboard(self): - return self._get_attr("artBoard") - - @artboard.setter - def artboard(self, value): - self._set_attr("artBoard", value) - - # enable_antialiasing - @property - def enable_antialiasing(self) -> bool: - return self._get_attr("enableAntiAliasing", def_value=True, data_type="bool") - - @enable_antialiasing.setter - def enable_antialiasing(self, value: Optional[bool]): - self._set_attr("enableAntiAliasing", value) - - # placeholder - @property - def placeholder(self) -> Optional[Control]: - return self.__placeholder - - @placeholder.setter - def placeholder(self, value: Optional[Control]): - self.__placeholder = value - - # use_artboard_size - @property - def use_artboard_size(self) -> bool: - return self._get_attr("useArtBoardSize", def_value=False, data_type="bool") - - @use_artboard_size.setter - def use_artboard_size(self, value: Optional[bool]): - self._set_attr("useArtBoardSize", value) - - # fit - @property - def fit(self) -> Optional[ImageFit]: - return self.__fit - - @fit.setter - def fit(self, value: Optional[ImageFit]): - self.__fit = value - self._set_enum_attr("fit", value, ImageFit) diff --git a/sdk/python/packages/flet/src/flet/core/row.py b/sdk/python/packages/flet/src/flet/core/row.py deleted file mode 100644 index 30553d3397..0000000000 --- a/sdk/python/packages/flet/src/flet/core/row.py +++ /dev/null @@ -1,251 +0,0 @@ -from typing import Any, List, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.scrollable_control import OnScrollEvent, ScrollableControl -from flet.core.types import ( - CrossAxisAlignment, - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - OptionalNumber, - ResponsiveNumber, - RotateValue, - ScaleValue, - ScrollMode, -) - - -class Row(ConstrainedControl, ScrollableControl, AdaptiveControl): - """ - A control that displays its children in a horizontal array. - - To cause a child control to expand and fill the available horizontal space, set its `expand` property. - - Example: - - ``` - import flet as ft - - - def main(page: ft.Page): - page.title = "Row example" - - page.add( - ft.Row( - controls=[ - ft.Container( - expand=1, - content=ft.Text("Container 1"), - bgcolor=ft.colors.GREEN_100, - ), - ft.Container( - expand=2, content=ft.Text("Container 2"), bgcolor=ft.colors.RED_100 - ), - ], - ), - ), - - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/row - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - alignment: Optional[MainAxisAlignment] = None, - vertical_alignment: Optional[CrossAxisAlignment] = None, - spacing: OptionalNumber = None, - tight: Optional[bool] = None, - wrap: Optional[bool] = None, - run_spacing: OptionalNumber = None, - run_alignment: Optional[MainAxisAlignment] = None, - # - # ScrollableControl specific - # - scroll: Optional[ScrollMode] = None, - auto_scroll: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: OptionalEventCallable[OnScrollEvent] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - # - # Adaptive - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - ScrollableControl.__init__( - self, - scroll=scroll, - auto_scroll=auto_scroll, - on_scroll_interval=on_scroll_interval, - on_scroll=on_scroll, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.controls = controls - self.alignment = alignment - self.vertical_alignment = vertical_alignment - self.spacing = spacing - self.tight = tight - self.wrap = wrap - self.run_spacing = run_spacing - self.run_alignment = run_alignment - - def _get_control_name(self): - return "row" - - def _get_children(self): - return self.__controls - - def __contains__(self, item): - return item in self.__controls - - # Public methods - def clean(self): - super().clean() - self.__controls.clear() - - # tight - @property - def tight(self) -> bool: - return self._get_attr("tight", data_type="bool", def_value=False) - - @tight.setter - def tight(self, value: Optional[bool]): - self._set_attr("tight", value) - - # alignment - @property - def alignment(self) -> Optional[MainAxisAlignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[MainAxisAlignment]): - self.__alignment = value - self._set_enum_attr("alignment", value, MainAxisAlignment) - - # run_alignment - @property - def run_alignment(self) -> Optional[MainAxisAlignment]: - return self.__run_alignment - - @run_alignment.setter - def run_alignment(self, value: Optional[MainAxisAlignment]): - self.__run_alignment = value - self._set_enum_attr("runAlignment", value, MainAxisAlignment) - - # vertical_alignment - @property - def vertical_alignment(self) -> Optional[CrossAxisAlignment]: - return self.__vertical_alignment - - @vertical_alignment.setter - def vertical_alignment(self, value: Optional[CrossAxisAlignment]): - self.__vertical_alignment = value - self._set_enum_attr("verticalAlignment", value, CrossAxisAlignment) - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self._get_attr("spacing", data_type="float", def_value=10) - - @spacing.setter - def spacing(self, value: OptionalNumber): - self._set_attr("spacing", value) - - # wrap - @property - def wrap(self) -> bool: - return self._get_attr("wrap", data_type="bool", def_value=False) - - @wrap.setter - def wrap(self, value: Optional[bool]): - self._set_attr("wrap", value) - - # run_spacing - @property - def run_spacing(self) -> OptionalNumber: - return self._get_attr("runSpacing", data_type="float") - - @run_spacing.setter - def run_spacing(self, value: OptionalNumber): - self._set_attr("runSpacing", value) - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value else [] diff --git a/sdk/python/packages/flet/src/flet/core/safe_area.py b/sdk/python/packages/flet/src/flet/core/safe_area.py deleted file mode 100644 index 35af8115d8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/safe_area.py +++ /dev/null @@ -1,177 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class SafeArea(ConstrainedControl, AdaptiveControl): - def __init__( - self, - content: Control, - left: Optional[bool] = None, - top: Optional[bool] = None, - right: Optional[bool] = None, - bottom: Optional[bool] = None, - maintain_bottom_view_padding: Optional[bool] = None, - minimum_padding: Optional[PaddingValue] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - # - # Adaptive - # - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.content = content - self.left = left - self.top = top - self.right = right - self.bottom = bottom - self.maintain_bottom_view_padding = maintain_bottom_view_padding - self.minimum_padding = minimum_padding - - def _get_control_name(self): - return "safearea" - - def before_update(self): - super().before_update() - assert self.__content.visible, "content must be visible" - self._set_attr_json("minimumPadding", self.__minimum_padding) - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # left - @property - def left(self) -> bool: - return self._get_attr("left", data_type="bool", def_value=True) - - @left.setter - def left(self, value: Optional[bool]): - self._set_attr("left", value) - - # top - @property - def top(self) -> bool: - return self._get_attr("top", data_type="bool", def_value=True) - - @top.setter - def top(self, value: Optional[bool]): - self._set_attr("top", value) - - # right - @property - def right(self) -> bool: - return self._get_attr("right", data_type="bool", def_value=True) - - @right.setter - def right(self, value: Optional[bool]): - self._set_attr("right", value) - - # bottom - @property - def bottom(self) -> bool: - return self._get_attr("bottom", data_type="bool", def_value=True) - - @bottom.setter - def bottom(self, value: Optional[bool]): - self._set_attr("bottom", value) - - # maintain_bottom_view_padding - @property - def maintain_bottom_view_padding(self) -> bool: - return self._get_attr( - "maintainBottomViewPadding", data_type="bool", def_value=False - ) - - @maintain_bottom_view_padding.setter - def maintain_bottom_view_padding(self, value: Optional[bool]): - self._set_attr("maintainBottomViewPadding", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # minimum_padding - @property - def minimum_padding(self) -> Optional[PaddingValue]: - return self.__minimum_padding - - @minimum_padding.setter - def minimum_padding(self, value: Optional[PaddingValue]): - self.__minimum_padding = value diff --git a/sdk/python/packages/flet/src/flet/core/scrollable_control.py b/sdk/python/packages/flet/src/flet/core/scrollable_control.py deleted file mode 100644 index 8151c46268..0000000000 --- a/sdk/python/packages/flet/src/flet/core/scrollable_control.py +++ /dev/null @@ -1,122 +0,0 @@ -import json -import time -from typing import Optional - -from flet.core.animation import AnimationCurve -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.types import OptionalEventCallable, ScrollMode - - -class ScrollableControl(Control): - def __init__( - self, - scroll: Optional[ScrollMode] = None, - auto_scroll: Optional[bool] = None, - reverse: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: OptionalEventCallable["OnScrollEvent"] = None, - ): - super().__init__() - self.__on_scroll = EventHandler(lambda e: OnScrollEvent(e)) - self._add_event_handler("onScroll", self.__on_scroll.get_handler()) - - self.scroll = scroll - self.auto_scroll = auto_scroll - self.reverse = reverse - self.on_scroll_interval = on_scroll_interval - self.on_scroll = on_scroll - - def scroll_to( - self, - offset: Optional[float] = None, - delta: Optional[float] = None, - key: Optional[str] = None, - duration: Optional[int] = None, - curve: Optional[AnimationCurve] = None, - ): - m = { - "n": "scroll_to", - "i": str(time.time()), - "p": { - "offset": offset, - "delta": delta, - "key": key, - "duration": duration, - "curve": curve.value if curve is not None else None, - }, - } - self._set_attr_json("method", m) - self.update() - - # scroll - @property - def scroll(self) -> Optional[ScrollMode]: - return self.__scroll - - @scroll.setter - def scroll(self, value: Optional[ScrollMode]): - self.__scroll = value - self._set_attr( - "scroll", - value.value - if isinstance(value, ScrollMode) - else "auto" - if value is True - else None - if value is False - else value, - ) - - # auto_scroll - @property - def auto_scroll(self) -> bool: - return self._get_attr("autoScroll", data_type="bool", def_value=False) - - @auto_scroll.setter - def auto_scroll(self, value: Optional[bool]): - self._set_attr("autoScroll", value) - - # reverse - @property - def reverse(self) -> bool: - return self._get_attr("reverse", data_type="bool", def_value=False) - - @reverse.setter - def reverse(self, value: Optional[bool]): - self._set_attr("reverse", value) - - # on_scroll_interval - @property - def on_scroll_interval(self) -> OptionalNumber: - return self._get_attr("onScrollInterval") - - @on_scroll_interval.setter - def on_scroll_interval(self, value: OptionalNumber): - self._set_attr("onScrollInterval", value) - - # on_scroll - @property - def on_scroll(self) -> OptionalEventCallable["OnScrollEvent"]: - return self.__on_scroll.handler - - @on_scroll.setter - def on_scroll(self, handler: OptionalEventCallable["OnScrollEvent"]): - self.__on_scroll.handler = handler - self._set_attr("onScroll", True if handler is not None else None) - - -class OnScrollEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.event_type: str = d.get("t") - self.pixels: float = d.get("p") - self.min_scroll_extent: float = d.get("minse") - self.max_scroll_extent: float = d.get("maxse") - self.viewport_dimension: float = d.get("vd") - self.scroll_delta: Optional[float] = d.get("sd") - self.direction: Optional[str] = d.get("dir") - self.overscroll: Optional[float] = d.get("os") - self.velocity: Optional[float] = d.get("v") diff --git a/sdk/python/packages/flet/src/flet/core/search_bar.py b/sdk/python/packages/flet/src/flet/core/search_bar.py deleted file mode 100644 index 4026a0922c..0000000000 --- a/sdk/python/packages/flet/src/flet/core/search_bar.py +++ /dev/null @@ -1,623 +0,0 @@ -import time -from typing import Any, Dict, List, Optional, Sequence, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.border import BorderSide -from flet.core.box import BoxConstraints -from flet.core.buttons import OutlinedBorder -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.textfield import KeyboardType, TextCapitalization -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlState, - ControlStateValue, - Number, - OffsetValue, - OptionalControlEventCallable, - OptionalNumber, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class SearchBar(ConstrainedControl): - """ - Manages a "search view" route that allows the user to select one of the suggested completions for a search query. - - ----- - - Online docs: https://flet.dev/docs/controls/searchbar - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - value: Optional[str] = None, - bar_leading: Optional[Control] = None, - bar_trailing: Optional[List[Control]] = None, - bar_hint_text: Optional[str] = None, - bar_bgcolor: ControlStateValue[ColorValue] = None, - bar_overlay_color: ControlStateValue[ColorValue] = None, - bar_shadow_color: ControlStateValue[ColorValue] = None, - bar_surface_tint_color: ControlStateValue[ColorValue] = None, - bar_elevation: ControlStateValue[OptionalNumber] = None, - bar_border_side: ControlStateValue[BorderSide] = None, - bar_shape: ControlStateValue[OutlinedBorder] = None, - bar_text_style: ControlStateValue[TextStyle] = None, - bar_hint_text_style: ControlStateValue[TextStyle] = None, - bar_padding: ControlStateValue[PaddingValue] = None, - bar_scroll_padding: Optional[PaddingValue] = None, - view_leading: Optional[Control] = None, - view_trailing: Optional[List[Control]] = None, - view_elevation: OptionalNumber = None, - view_bgcolor: Optional[ColorValue] = None, - view_hint_text: Optional[str] = None, - view_side: Optional[BorderSide] = None, - view_shape: Optional[OutlinedBorder] = None, - view_header_text_style: Optional[TextStyle] = None, - view_hint_text_style: Optional[TextStyle] = None, - view_size_constraints: Optional[BoxConstraints] = None, - view_header_height: OptionalNumber = None, - divider_color: Optional[ColorValue] = None, - capitalization: Optional[TextCapitalization] = None, - full_screen: Optional[bool] = None, - keyboard_type: Optional[KeyboardType] = None, - view_surface_tint_color: Optional[ColorValue] = None, - autofocus: Optional[bool] = None, - on_tap: OptionalControlEventCallable = None, - on_tap_outside_bar: OptionalControlEventCallable = None, - on_submit: OptionalControlEventCallable = None, - on_change: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.value = value - self.controls = controls - self.bar_leading = bar_leading - self.bar_trailing = bar_trailing - self.bar_hint_text = bar_hint_text - self.bar_bgcolor = bar_bgcolor - self.bar_overlay_color = bar_overlay_color - self.view_leading = view_leading - self.view_trailing = view_trailing - self.view_elevation = view_elevation - self.view_bgcolor = view_bgcolor - self.view_hint_text = view_hint_text - self.view_side = view_side - self.view_shape = view_shape - self.view_header_text_style = view_header_text_style - self.view_hint_text_style = view_hint_text_style - self.divider_color = divider_color - self.full_screen = full_screen - self.capitalization = capitalization - self.on_focus = on_focus - self.on_blur = on_blur - self.on_tap = on_tap - self.on_submit = on_submit - self.on_change = on_change - self.on_tap_outside_bar = on_tap_outside_bar - self.keyboard_type = keyboard_type - self.view_surface_tint_color = view_surface_tint_color - self.autofocus = autofocus - self.view_header_height = view_header_height - self.view_size_constraints = view_size_constraints - self.bar_surface_tint_color = bar_surface_tint_color - self.bar_elevation = bar_elevation - self.bar_border_side = bar_border_side - self.bar_shape = bar_shape - self.bar_text_style = bar_text_style - self.bar_hint_text_style = bar_hint_text_style - self.bar_padding = bar_padding - self.bar_scroll_padding = bar_scroll_padding - self.bar_shadow_color = bar_shadow_color - - def _get_control_name(self): - return "searchbar" - - def __contains__(self, item): - return item in self.__controls - - def before_update(self): - super().before_update() - self._set_attr_json("barBgcolor", self.__bar_bgcolor, wrap_attr_dict=True) - self._set_attr_json( - "barOverlayColor", self.__bar_overlay_color, wrap_attr_dict=True - ) - self._set_attr_json( - "barHintTextStyle", self.__bar_hint_text_style, wrap_attr_dict=True - ) - self._set_attr_json( - "barSurfaceTintColor", self.__bar_surface_tint_color, wrap_attr_dict=True - ) - self._set_attr_json("barElevation", self.__bar_elevation, wrap_attr_dict=True) - self._set_attr_json( - "barBorderSide", self.__bar_border_side, wrap_attr_dict=True - ) - self._set_attr_json("barShape", self.__bar_shape, wrap_attr_dict=True) - self._set_attr_json("barTextStyle", self.__bar_text_style, wrap_attr_dict=True) - self._set_attr_json("barPadding", self.__bar_padding, wrap_attr_dict=True) - self._set_attr_json( - "barShadowColor", self.__bar_shadow_color, wrap_attr_dict=True - ) - self._set_attr_json("viewShape", self.__view_shape) - self._set_attr_json("viewHeaderTextStyle", self.__view_header_text_style) - self._set_attr_json("viewHintTextStyle", self.__view_hint_text_style) - self._set_attr_json("viewSide", self.__view_side) - self._set_attr_json("viewSizeConstraints", self.__view_size_constraints) - self._set_attr_json("barScrollPadding", self.__bar_scroll_padding) - - def _get_children(self): - children = [] - if self.__bar_leading: - self.__bar_leading._set_attr_internal("n", "barLeading") - children.append(self.__bar_leading) - if self.__view_leading: - self.__view_leading._set_attr_internal("n", "viewLeading") - children.append(self.__view_leading) - for i in self.__bar_trailing: - i._set_attr_internal("n", "barTrailing") - children.append(i) - for i in self.__view_trailing: - i._set_attr_internal("n", "viewTrailing") - children.append(i) - for i in self.__controls: - i._set_attr_internal("n", "controls") - children.append(i) - return children - - # Public methods - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - def blur(self): - self._set_attr_json("blur", str(time.time())) - self.update() - - def open_view(self): - m = { - "n": "openView", - "i": str(time.time()), - "p": {}, - } - self._set_attr_json("method", m) - self.update() - - def close_view(self, text: str = ""): - m = { - "n": "closeView", - "i": str(time.time()), - "p": {"text": text}, - } - self.value = text - self._set_attr_json("method", m) - self.update() - - # bar_leading - @property - def bar_leading(self) -> Optional[Control]: - return self.__bar_leading - - @bar_leading.setter - def bar_leading(self, value: Optional[Control]): - self.__bar_leading = value - - # bar_trailing - @property - def bar_trailing(self) -> Optional[List[Control]]: - return self.__bar_trailing - - @bar_trailing.setter - def bar_trailing(self, value: Optional[List[Control]]): - self.__bar_trailing = value if value is not None else [] - - # bar_bgcolor - @property - def bar_bgcolor(self) -> ControlStateValue[str]: - return self.__bar_bgcolor - - @bar_bgcolor.setter - def bar_bgcolor(self, value: ControlStateValue[str]): - self.__bar_bgcolor = value - - # bar_overlay_color - @property - def bar_overlay_color(self) -> ControlStateValue[str]: - return self.__bar_overlay_color - - @bar_overlay_color.setter - def bar_overlay_color(self, value: ControlStateValue[str]): - self.__bar_overlay_color = value - - # bar_shadow_color - @property - def bar_shadow_color(self) -> Union[None, str, Dict[ControlState, str]]: - return self.__bar_shadow_color - - @bar_shadow_color.setter - def bar_shadow_color(self, value: Union[None, str, Dict[ControlState, str]]): - self.__bar_shadow_color = value - - # bar_surface_tint_color - @property - def bar_surface_tint_color(self) -> Union[None, str, Dict[ControlState, str]]: - return self.__bar_surface_tint_color - - @bar_surface_tint_color.setter - def bar_surface_tint_color(self, value: Union[None, str, Dict[ControlState, str]]): - self.__bar_surface_tint_color = value - - # bar_elevation - @property - def bar_elevation(self) -> Union[OptionalNumber, Dict[ControlState, Number]]: - return self.__bar_elevation - - @bar_elevation.setter - def bar_elevation(self, value: Union[OptionalNumber, Dict[ControlState, Number]]): - self.__bar_elevation = value - - # bar_border_side - @property - def bar_border_side( - self, - ) -> ControlStateValue[BorderSide]: - return self.__bar_border_side - - @bar_border_side.setter - def bar_border_side(self, value: ControlStateValue[BorderSide]): - self.__bar_border_side = value - - # bar_shape - @property - def bar_shape( - self, - ) -> ControlStateValue[OutlinedBorder]: - return self.__bar_shape - - @bar_shape.setter - def bar_shape(self, value: ControlStateValue[OutlinedBorder]): - self.__bar_shape = value - - # bar_text_style - @property - def bar_text_style(self) -> ControlStateValue[TextStyle]: - return self.__bar_text_style - - @bar_text_style.setter - def bar_text_style(self, value: ControlStateValue[TextStyle]): - self.__bar_text_style = value - - # bar_hint_text_style - @property - def bar_hint_text_style( - self, - ) -> ControlStateValue[TextStyle]: - return self.__bar_hint_text_style - - @bar_hint_text_style.setter - def bar_hint_text_style(self, value: ControlStateValue[TextStyle]): - self.__bar_hint_text_style = value - - # bar_padding - @property - def bar_padding(self) -> ControlStateValue[PaddingValue]: - return self.__bar_padding - - @bar_padding.setter - def bar_padding(self, value: ControlStateValue[PaddingValue]): - self.__bar_padding = value - - # view_leading - @property - def view_leading(self) -> Optional[Control]: - return self.__view_leading - - @view_leading.setter - def view_leading(self, value: Optional[Control]): - self.__view_leading = value - - # view_surface_tint_color - @property - def view_surface_tint_color(self) -> Optional[ColorValue]: - return self.__view_surface_tint_color - - @view_surface_tint_color.setter - def view_surface_tint_color(self, value: Optional[ColorValue]): - self.__view_surface_tint_color = value - self._set_enum_attr("viewSurfaceTintColor", value, ColorEnums) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # view_trailing - @property - def view_trailing(self) -> Optional[List[Control]]: - return self.__view_trailing - - @view_trailing.setter - def view_trailing(self, value: Optional[List[Control]]): - self.__view_trailing = value if value is not None else [] - - # view_elevation - @property - def view_elevation(self) -> OptionalNumber: - return self._get_attr("viewElevation") - - @view_elevation.setter - def view_elevation(self, value: OptionalNumber): - self._set_attr("viewElevation", value) - - # view_header_height - @property - def view_header_height(self) -> OptionalNumber: - return self._get_attr("viewHeaderHeight") - - @view_header_height.setter - def view_header_height(self, value: OptionalNumber): - self._set_attr("viewHeaderHeight", value) - - # view_bgcolor - @property - def view_bgcolor(self) -> Optional[str]: - return self.__view_bgcolor - - @view_bgcolor.setter - def view_bgcolor(self, value: Optional[str]): - self.__view_bgcolor = value - self._set_enum_attr("viewBgcolor", value, ColorEnums) - - # divider_color - @property - def divider_color(self) -> Optional[ColorValue]: - return self.__divider_color - - @divider_color.setter - def divider_color(self, value: Optional[ColorValue]): - self.__divider_color = value - self._set_enum_attr("dividerColor", value, ColorEnums) - - # bar_hint_text - @property - def bar_hint_text(self) -> Optional[str]: - return self._get_attr("barHintText") - - @bar_hint_text.setter - def bar_hint_text(self, value: Optional[str]): - self._set_attr("barHintText", value) - - # view_hint_text - @property - def view_hint_text(self) -> Optional[str]: - return self._get_attr("viewHintText") - - @view_hint_text.setter - def view_hint_text(self, value: Optional[str]): - self._set_attr("viewHintText", value) - - # view_shape - @property - def view_shape(self) -> Optional[OutlinedBorder]: - return self.__view_shape - - @view_shape.setter - def view_shape(self, value: Optional[OutlinedBorder]): - self.__view_shape = value - - # view_side - @property - def view_side(self) -> Optional[BorderSide]: - return self.__view_side - - @view_side.setter - def view_side(self, value: Optional[BorderSide]): - self.__view_side = value - - # view_size_constraints - @property - def view_size_constraints(self) -> Optional[BoxConstraints]: - return self.__view_size_constraints - - @view_size_constraints.setter - def view_size_constraints(self, value: Optional[BoxConstraints]): - self.__view_size_constraints = value - - # bar_scroll_padding - @property - def bar_scroll_padding(self) -> Optional[PaddingValue]: - return self.__bar_scroll_padding - - @bar_scroll_padding.setter - def bar_scroll_padding(self, value: Optional[PaddingValue]): - self.__bar_scroll_padding = value - - # full_screen - @property - def full_screen(self) -> bool: - return self._get_attr("fullScreen", data_type="bool", def_value=False) - - @full_screen.setter - def full_screen(self, value: Optional[bool]): - self._set_attr("fullScreen", value) - - # capitalization - @property - def capitalization(self) -> TextCapitalization: - return self.__capitalization - - @capitalization.setter - def capitalization(self, value: TextCapitalization): - self.__capitalization = value - self._set_enum_attr("capitalization", value, TextCapitalization) - - # keyboard_type - @property - def keyboard_type(self) -> KeyboardType: - return self.__keyboard_type - - @keyboard_type.setter - def keyboard_type(self, value: KeyboardType): - self.__keyboard_type = value - self._set_enum_attr("keyboardType", value, KeyboardType) - - # view_header_text_style - @property - def view_header_text_style(self): - return self.__view_header_text_style - - @view_header_text_style.setter - def view_header_text_style(self, value: Optional[TextStyle]): - self.__view_header_text_style = value - - # view_hint_text_style - @property - def view_hint_text_style(self): - return self.__view_hint_text_style - - @view_hint_text_style.setter - def view_hint_text_style(self, value: Optional[TextStyle]): - self.__view_hint_text_style = value - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value", def_value="") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - self._set_attr("onchange", True if handler is not None else None) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # on_tap - @property - def on_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap") - - @on_tap.setter - def on_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap", handler) - self._set_attr("ontap", True if handler is not None else None) - - # on_tap_outside_bar - @property - def on_tap_outside_bar(self) -> OptionalControlEventCallable: - return self._get_event_handler("tapOutsideBar") - - @on_tap_outside_bar.setter - def on_tap_outside_bar(self, handler: OptionalControlEventCallable): - self._add_event_handler("tapOutsideBar", handler) - self._set_attr("onTapOutsideBar", True if handler is not None else None) - - # on_submit - @property - def on_submit(self) -> OptionalControlEventCallable: - return self._get_event_handler("submit") - - @on_submit.setter - def on_submit(self, handler: OptionalControlEventCallable): - self._add_event_handler("submit", handler) - self._set_attr("onsubmit", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/segmented_button.py b/sdk/python/packages/flet/src/flet/core/segmented_button.py deleted file mode 100644 index dc6b97e69e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/segmented_button.py +++ /dev/null @@ -1,336 +0,0 @@ -import json -from typing import Any, List, Optional, Set, Union - -from flet.core.alignment import Axis -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Segment(Control): - def __init__( - self, - value: str, - icon: Optional[Control] = None, - label: Optional[Control] = None, - # - # Control - # - ref: Optional[Ref] = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - tooltip: Optional[str] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.value = value - self.label = label - self.icon = icon - self.tooltip = tooltip - - def _get_control_name(self): - return "segment" - - def _get_children(self): - children = [] - if self.__label: - self.__label._set_attr_internal("n", "label") - children.append(self.__label) - if self.__icon: - self.__icon._set_attr_internal("n", "icon") - children.append(self.__icon) - return children - - # label - @property - def label(self) -> Optional[Control]: - return self.__label - - @label.setter - def label(self, value: Optional[Control]): - self.__label = value - - # icon - @property - def icon(self) -> Optional[Control]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[Control]): - self.__icon = value - - # value - @property - def value(self) -> str: - return self._get_attr("value") - - @value.setter - def value(self, value: str): - self._set_attr("value", value) - - # tooltip - @property - def tooltip(self) -> Optional[str]: - return self._get_attr("tooltip") - - @tooltip.setter - def tooltip(self, value: Optional[str]): - self._set_attr("tooltip", value) - - -class SegmentedButton(ConstrainedControl): - """ - A segmented button control. - - ----- - - Online docs: https://flet.dev/docs/controls/segmentedbutton - """ - - def __init__( - self, - segments: List[Segment], - style: Optional[ButtonStyle] = None, - allow_empty_selection: Optional[bool] = None, - allow_multiple_selection: Optional[bool] = None, - selected: Optional[Set] = None, - selected_icon: Optional[Control] = None, - show_selected_icon: Optional[bool] = None, - direction: Optional[Axis] = None, - padding: Optional[PaddingValue] = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - self.segments = segments - self.show_selected_icon = show_selected_icon - self.allow_multiple_selection = allow_multiple_selection - self.allow_empty_selection = allow_empty_selection - self.selected_icon = selected_icon - self.selected = selected - self.style = style - self.direction = direction - self.padding = padding - self.on_change = on_change - - def _get_control_name(self): - return "segmentedbutton" - - def before_update(self): - super().before_update() - assert any( - segment.visible for segment in self.__segments - ), "segments must have at minimum one visible Segment" - assert ( - len(self.selected) > 0 or self.allow_empty_selection - ), "allow_empty_selection must be True for selected to be empty" - assert ( - len(self.selected) < 2 or self.allow_multiple_selection - ), "allow_multiple_selection must be True for selected to have more than one item" - style = self.__style or ButtonStyle() - style.side = self._wrap_attr_dict(style.side) - style.shape = self._wrap_attr_dict(style.shape) - style.padding = self._wrap_attr_dict(style.padding) - self._set_attr_json("style", style) - self._set_attr_json("padding", self.__padding) - - def _get_children(self): - for segment in self.segments: - segment._set_attr_internal("n", "segment") - children: List[Control] = self.__segments - if self.__selected_icon: - self.__selected_icon._set_attr_internal("n", "selectedIcon") - children.append(self.__selected_icon) - return children - - def __contains__(self, item): - return item in self.__segments - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # segments - @property - def segments(self) -> List[Segment]: - return self.__segments - - @segments.setter - def segments(self, value: List[Segment]): - self.__segments = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # allow_empty_selection - @property - def allow_empty_selection(self) -> bool: - return self._get_attr("allowEmptySelection", data_type="bool", def_value=False) - - @allow_empty_selection.setter - def allow_empty_selection(self, value: Optional[bool]): - self._set_attr("allowEmptySelection", value) - - # allow_multiple_selection - @property - def allow_multiple_selection(self) -> bool: - return self._get_attr( - "allowMultipleSelection", data_type="bool", def_value=False - ) - - @allow_multiple_selection.setter - def allow_multiple_selection(self, value: Optional[bool]): - self._set_attr("allowMultipleSelection", value) - - # selected - @property - def selected(self) -> Optional[Set]: - s = self._get_attr("selected") - return set(json.loads(s)) if s else s - - @selected.setter - def selected(self, value: Optional[Set]): - self._set_attr( - "selected", - ( - json.dumps(list(value), separators=(",", ":")) - if value is not None - else None - ), - ) - - # show_selected_icon - @property - def show_selected_icon(self) -> bool: - return self._get_attr("showSelectedIcon", data_type="bool", def_value=True) - - @show_selected_icon.setter - def show_selected_icon(self, value: Optional[bool]): - self._set_attr("showSelectedIcon", value) - - # direction - @property - def direction(self) -> Optional[Axis]: - return self.__direction - - @direction.setter - def direction(self, value: Optional[Axis]): - self.__direction = value - self._set_enum_attr("direction", value, Axis) - - # selected_icon - @property - def selected_icon(self) -> Optional[Control]: - return self.__selected_icon - - @selected_icon.setter - def selected_icon(self, value: Optional[Control]): - self.__selected_icon = value diff --git a/sdk/python/packages/flet/src/flet/core/selection_area.py b/sdk/python/packages/flet/src/flet/core/selection_area.py deleted file mode 100644 index 43c8c6ea2f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/selection_area.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class SelectionArea(Control): - """ - Flet controls are not selectable by default. SelectionArea is used to enable selection for its child control. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.add( - ft.SelectionArea( - content=ft.Column([ft.Text("Selectable text"), ft.Text("Also selectable")]) - ) - ) - page.add(ft.Text("Not selectable")) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/selectionarea - """ - - def __init__( - self, - content: Control, - on_change: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - - self.content = content - self.on_change = on_change - - def _get_control_name(self): - return "selectionarea" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) diff --git a/sdk/python/packages/flet/src/flet/core/semantics.py b/sdk/python/packages/flet/src/flet/core/semantics.py deleted file mode 100644 index cbc620ed7a..0000000000 --- a/sdk/python/packages/flet/src/flet/core/semantics.py +++ /dev/null @@ -1,639 +0,0 @@ -from typing import Any, Optional - -from flet.core.badge import BadgeValue -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class Semantics(Control): - """ - A control that annotates the control tree with a description of the meaning of the widgets. - - Used by accessibility tools, search engines, and other semantic analysis software to determine the meaning of the application. - - ----- - - Online docs: https://flet.dev/docs/controls/semantics - """ - - def __init__( - self, - content: Optional[Control] = None, - label: Optional[str] = None, - expanded: Optional[bool] = None, - hidden: Optional[bool] = None, - selected: Optional[bool] = None, - button: Optional[bool] = None, - obscured: Optional[bool] = None, - multiline: Optional[bool] = None, - focusable: Optional[bool] = None, - read_only: Optional[bool] = None, - focus: Optional[bool] = None, - slider: Optional[bool] = None, - tooltip: Optional[str] = None, - badge: Optional[BadgeValue] = None, - toggled: Optional[bool] = None, - max_value_length: OptionalNumber = None, - checked: Optional[bool] = None, - value: Optional[str] = None, - increased_value: Optional[str] = None, - decreased_value: Optional[str] = None, - hint_text: Optional[str] = None, - on_tap_hint_text: Optional[str] = None, - current_value_length: Optional[int] = None, - heading_level: Optional[int] = None, - exclude_semantics: Optional[bool] = None, - mixed: Optional[bool] = None, - on_long_press_hint_text: Optional[str] = None, - container: Optional[bool] = None, - live_region: Optional[bool] = None, - textfield: Optional[bool] = None, - link: Optional[bool] = None, - header: Optional[bool] = None, - image: Optional[bool] = None, - on_tap: OptionalControlEventCallable = None, - on_double_tap: OptionalControlEventCallable = None, - on_increase: OptionalControlEventCallable = None, - on_decrease: OptionalControlEventCallable = None, - on_dismiss: OptionalControlEventCallable = None, - on_scroll_left: OptionalControlEventCallable = None, - on_scroll_right: OptionalControlEventCallable = None, - on_scroll_up: OptionalControlEventCallable = None, - on_scroll_down: OptionalControlEventCallable = None, - on_copy: OptionalControlEventCallable = None, - on_cut: OptionalControlEventCallable = None, - on_paste: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_move_cursor_forward_by_character: OptionalControlEventCallable = None, - on_move_cursor_backward_by_character: OptionalControlEventCallable = None, - on_did_gain_accessibility_focus: OptionalControlEventCallable = None, - on_did_lose_accessibility_focus: OptionalControlEventCallable = None, - on_set_text: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - visible=visible, - disabled=disabled, - data=data, - badge=badge, - ) - - self.content = content - self.label = label - self.expanded = expanded - self.hidden = hidden - self.selected = selected - self.button = button - self.obscured = obscured - self.multiline = multiline - self.focusable = focusable - self.read_only = read_only - self.focus = focus - self.slider = slider - self.tooltip = tooltip - self.toggled = toggled - self.max_value_length = max_value_length - self.checked = checked - self.value = value - self.increased_value = increased_value - self.decreased_value = decreased_value - self.hint_text = hint_text - self.on_tap_hint_text = on_tap_hint_text - self.on_long_press_hint_text = on_long_press_hint_text - self.container = container - self.live_region = live_region - self.textfield = textfield - self.link = link - self.header = header - self.image = image - self.on_tap = on_tap - self.on_double_tap = on_double_tap - self.on_increase = on_increase - self.on_decrease = on_decrease - self.on_dismiss = on_dismiss - self.on_scroll_left = on_scroll_left - self.on_scroll_right = on_scroll_right - self.on_scroll_up = on_scroll_up - self.on_scroll_down = on_scroll_down - self.on_copy = on_copy - self.on_cut = on_cut - self.on_paste = on_paste - self.on_long_press = on_long_press - self.on_move_cursor_forward_by_character = on_move_cursor_forward_by_character - self.on_move_cursor_backward_by_character = on_move_cursor_backward_by_character - self.on_did_gain_accessibility_focus = on_did_gain_accessibility_focus - self.on_did_lose_accessibility_focus = on_did_lose_accessibility_focus - self.current_value_length = current_value_length - self.heading_level = heading_level - self.exclude_semantics = exclude_semantics - self.mixed = mixed - self.on_set_text = on_set_text - - def _get_control_name(self): - return "semantics" - - def _get_children(self): - children = [] - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # expanded - @property - def expanded(self) -> Optional[bool]: - return self._get_attr("expanded", data_type="bool") - - @expanded.setter - def expanded(self, value: Optional[bool]): - self._set_attr("expanded", value) - - # hidden - @property - def hidden(self): - return self._get_attr("hidden") - - @hidden.setter - def hidden(self, value: Optional[bool]): - self._set_attr("hidden", value) - - # textfield - @property - def textfield(self) -> Optional[bool]: - return self._get_attr("textfield", data_type="bool") - - @textfield.setter - def textfield(self, value: Optional[bool]): - self._set_attr("textfield", value) - - # link - @property - def link(self) -> Optional[bool]: - return self._get_attr("link", data_type="bool") - - @link.setter - def link(self, value: Optional[bool]): - self._set_attr("link", value) - - # image - @property - def image(self) -> Optional[bool]: - return self._get_attr("image", data_type="bool") - - @image.setter - def image(self, value: Optional[bool]): - self._set_attr("image", value) - - # header - @property - def header(self) -> Optional[bool]: - return self._get_attr("header", data_type="bool") - - @header.setter - def header(self, value: Optional[bool]): - self._set_attr("header", value) - - # selected - @property - def selected(self) -> Optional[bool]: - return self._get_attr("selected", data_type="bool") - - @selected.setter - def selected(self, value: Optional[bool]): - self._set_attr("selected", value) - - # button - @property - def button(self) -> Optional[bool]: - return self._get_attr("button", data_type="bool") - - @button.setter - def button(self, value: Optional[bool]): - self._set_attr("button", value) - - # obscured - @property - def obscured(self) -> Optional[bool]: - return self._get_attr("obscured", data_type="bool") - - @obscured.setter - def obscured(self, value: Optional[bool]): - self._set_attr("obscured", value) - - # multiline - @property - def multiline(self) -> Optional[bool]: - return self._get_attr("multiline", data_type="bool") - - @multiline.setter - def multiline(self, value: Optional[bool]): - self._set_attr("multiline", value) - - # focusable - @property - def focusable(self) -> Optional[bool]: - return self._get_attr("focusable", data_type="bool") - - @focusable.setter - def focusable(self, value: Optional[bool]): - self._set_attr("focusable", value) - - # read_only - @property - def read_only(self) -> Optional[bool]: - return self._get_attr("readOnly", data_type="bool") - - @read_only.setter - def read_only(self, value: Optional[bool]): - self._set_attr("readOnly", value) - - # focused - @property - def focused(self) -> Optional[bool]: - return self._get_attr("focused", data_type="bool") - - @focused.setter - def focused(self, value: Optional[bool]): - self._set_attr("focused", value) - - # mixed - @property - def mixed(self) -> Optional[bool]: - return self._get_attr("mixed", data_type="bool") - - @mixed.setter - def mixed(self, value: Optional[bool]): - self._set_attr("mixed", value) - - # exclude_semantics - @property - def exclude_semantics(self) -> bool: - return self._get_attr("excludeSemantics", data_type="bool", def_value=False) - - @exclude_semantics.setter - def exclude_semantics(self, value: Optional[bool]): - self._set_attr("excludeSemantics", value) - - # heading_level - @property - def heading_level(self) -> Optional[int]: - return self._get_attr("headingLevel", data_type="int") - - @heading_level.setter - def heading_level(self, value: Optional[int]): - self._set_attr("headingLevel", value) - - # current_value_length - @property - def current_value_length(self) -> Optional[int]: - return self._get_attr("currentValueLength", data_type="int") - - @current_value_length.setter - def current_value_length(self, value: Optional[int]): - self._set_attr("currentValueLength", value) - - # slider - @property - def slider(self) -> Optional[bool]: - return self._get_attr("slider", data_type="bool") - - @slider.setter - def slider(self, value: Optional[bool]): - self._set_attr("slider", value) - - # tooltip - @property - def tooltip(self) -> Optional[str]: - return self._get_attr("tooltip") - - @tooltip.setter - def tooltip(self, value: Optional[str]): - self._set_attr("tooltip", value) - - # toggled - @property - def toggled(self) -> Optional[bool]: - return self._get_attr("toggled", data_type="bool") - - @toggled.setter - def toggled(self, value: Optional[bool]): - self._set_attr("toggled", value) - - # max_value_length - @property - def max_value_length(self) -> OptionalNumber: - return self._get_attr("maxValueLength") - - @max_value_length.setter - def max_value_length(self, value: OptionalNumber): - self._set_attr("maxValueLength", value) - - # checked - @property - def checked(self) -> Optional[bool]: - return self._get_attr("checked", data_type="bool") - - @checked.setter - def checked(self, value: Optional[bool]): - self._set_attr("checked", value) - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # increased_value - @property - def increased_value(self) -> Optional[str]: - return self._get_attr("increasedValue") - - @increased_value.setter - def increased_value(self, value: Optional[str]): - self._set_attr("increasedValue", value) - - # decreased_value - @property - def decreased_value(self) -> Optional[str]: - return self._get_attr("decreasedValue") - - @decreased_value.setter - def decreased_value(self, value: Optional[str]): - self._set_attr("decreasedValue", value) - - # hint_text - @property - def hint_text(self) -> Optional[str]: - return self._get_attr("hintText") - - @hint_text.setter - def hint_text(self, value: Optional[str]): - self._set_attr("hintText", value) - - # on_long_press_hint_text - @property - def on_long_press_hint_text(self): - return self._get_attr("onLongPressHintText") - - @on_long_press_hint_text.setter - def on_long_press_hint_text(self, value: Optional[bool]): - self._set_attr("onLongPressHintText", value) - - # on_tap_hint_text - @property - def on_tap_hint_text(self): - return self._get_attr("onTapHintText") - - @on_tap_hint_text.setter - def on_tap_hint_text(self, value: Optional[bool]): - self._set_attr("onTapHintText", value) - - # container - @property - def container(self) -> Optional[bool]: - return self._get_attr("container", data_type="bool") - - @container.setter - def container(self, value: Optional[bool]): - self._set_attr("container", value) - - # live_region - @property - def live_region(self) -> Optional[bool]: - return self._get_attr("liveRegion", data_type="bool") - - @live_region.setter - def live_region(self, value: Optional[bool]): - self._set_attr("liveRegion", value) - - # on_tap - @property - def on_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap") - - @on_tap.setter - def on_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap", handler) - self._set_attr("onTap", True if handler is not None else None) - - # on_double_tap - @property - def on_double_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("double_tap") - - @on_double_tap.setter - def on_double_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("double_tap", handler) - self._set_attr("onDoubleTap", True if handler is not None else None) - - # on_increase - @property - def on_increase(self) -> OptionalControlEventCallable: - return self._get_event_handler("increase") - - @on_increase.setter - def on_increase(self, handler: OptionalControlEventCallable): - self._add_event_handler("increase", handler) - self._set_attr("onIncrease", True if handler is not None else None) - - # on_decrease - @property - def on_decrease(self) -> OptionalControlEventCallable: - return self._get_event_handler("decrease") - - @on_decrease.setter - def on_decrease(self, handler: OptionalControlEventCallable): - self._add_event_handler("decrease", handler) - self._set_attr("onDecrease", True if handler is not None else None) - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) - self._set_attr("onDismiss", True if handler is not None else None) - - # on_scroll_left - @property - def on_scroll_left(self) -> OptionalControlEventCallable: - return self._get_event_handler("scroll_left") - - @on_scroll_left.setter - def on_scroll_left(self, handler: OptionalControlEventCallable): - self._add_event_handler("scroll_left", handler) - self._set_attr("onScrollLeft", True if handler is not None else None) - - # on_scroll_right - @property - def on_scroll_right(self) -> OptionalControlEventCallable: - return self._get_event_handler("scroll_right") - - @on_scroll_right.setter - def on_scroll_right(self, handler: OptionalControlEventCallable): - self._add_event_handler("scroll_right", handler) - self._set_attr("onScrollRight", True if handler is not None else None) - - # on_scroll_up - @property - def on_scroll_up(self) -> OptionalControlEventCallable: - return self._get_event_handler("scroll_up") - - @on_scroll_up.setter - def on_scroll_up(self, handler: OptionalControlEventCallable): - self._add_event_handler("scroll_up", handler) - self._set_attr("onScrollUp", True if handler is not None else None) - - # on_scroll_down - @property - def on_scroll_down(self) -> OptionalControlEventCallable: - return self._get_event_handler("scroll_down") - - @on_scroll_down.setter - def on_scroll_down(self, handler: OptionalControlEventCallable): - self._add_event_handler("scroll_down", handler) - self._set_attr("onScrollDown", True if handler is not None else None) - - # on_copy - @property - def on_copy(self) -> OptionalControlEventCallable: - return self._get_event_handler("copy") - - @on_copy.setter - def on_copy(self, handler: OptionalControlEventCallable): - self._add_event_handler("copy", handler) - self._set_attr("onCopy", True if handler is not None else None) - - # on_cut - @property - def on_cut(self) -> OptionalControlEventCallable: - return self._get_event_handler("cut") - - @on_cut.setter - def on_cut(self, handler: OptionalControlEventCallable): - self._add_event_handler("cut", handler) - self._set_attr("onCut", True if handler is not None else None) - - # on_paste - @property - def on_paste(self) -> OptionalControlEventCallable: - return self._get_event_handler("paste") - - @on_paste.setter - def on_paste(self, handler: OptionalControlEventCallable): - self._add_event_handler("paste", handler) - self._set_attr("onPaste", True if handler is not None else None) - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # on_move_cursor_forward_by_character - @property - def on_move_cursor_forward_by_character( - self, - ) -> OptionalControlEventCallable: - return self._get_event_handler("move_cursor_forward_by_character") - - @on_move_cursor_forward_by_character.setter - def on_move_cursor_forward_by_character( - self, handler: OptionalControlEventCallable - ): - self._add_event_handler("move_cursor_forward_by_character", handler) - self._set_attr( - "onMoveCursorForwardByCharacter", True if handler is not None else None - ) - - # on_move_cursor_backward_by_character - @property - def on_move_cursor_backward_by_character( - self, - ) -> OptionalControlEventCallable: - return self._get_event_handler("move_cursor_backward_by_character") - - @on_move_cursor_backward_by_character.setter - def on_move_cursor_backward_by_character( - self, handler: OptionalControlEventCallable - ): - self._add_event_handler("move_cursor_backward_by_character", handler) - self._set_attr( - "onMoveCursorBackwardByCharacter", True if handler is not None else None - ) - - # on_did_gain_accessibility_focus - @property - def on_did_gain_accessibility_focus( - self, - ) -> OptionalControlEventCallable: - return self._get_event_handler("did_gain_accessibility_focus") - - @on_did_gain_accessibility_focus.setter - def on_did_gain_accessibility_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("did_gain_accessibility_focus", handler) - self._set_attr( - "onDidGainAccessibilityFocus", True if handler is not None else None - ) - - # on_did_lose_accessibility_focus - @property - def on_did_lose_accessibility_focus( - self, - ) -> OptionalControlEventCallable: - return self._get_event_handler("did_lose_accessibility_focus") - - @on_did_lose_accessibility_focus.setter - def on_did_lose_accessibility_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("did_lose_accessibility_focus", handler) - self._set_attr( - "onDidLoseAccessibilityFocus", True if handler is not None else None - ) - - # on_set_text - @property - def on_set_text( - self, - ) -> OptionalControlEventCallable: - return self._get_event_handler("set_text") - - @on_set_text.setter - def on_set_text(self, handler: OptionalControlEventCallable): - self._add_event_handler("set_text", handler) - self._set_attr("setText", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/semantics_service.py b/sdk/python/packages/flet/src/flet/core/semantics_service.py deleted file mode 100644 index a51a59b284..0000000000 --- a/sdk/python/packages/flet/src/flet/core/semantics_service.py +++ /dev/null @@ -1,51 +0,0 @@ -from enum import Enum -from typing import Any, Optional - -from flet.core.control import Control -from flet.core.ref import Ref - - -class Assertiveness(Enum): - POLITE = "polite" - ASSERTIVE = "assertive" - - -class SemanticsService(Control): - def __init__( - self, - ref: Optional[Ref] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - data=data, - ) - - def _get_control_name(self): - return "semanticsservice" - - def announce_message( - self, - message: str, - rtl: bool = False, - assertiveness: Assertiveness = Assertiveness.POLITE, - ): - self.invoke_method( - "announce_message", - arguments={ - "message": message, - "rtl": str(rtl), - "assertiveness": assertiveness.value - if isinstance(assertiveness, Assertiveness) - else str(assertiveness), - }, - ) - - def announce_tooltip(self, message: str): - self.invoke_method( - "announce_tooltip", - arguments={ - "message": message, - }, - ) diff --git a/sdk/python/packages/flet/src/flet/core/session_storage.py b/sdk/python/packages/flet/src/flet/core/session_storage.py deleted file mode 100644 index 8da7afe8b0..0000000000 --- a/sdk/python/packages/flet/src/flet/core/session_storage.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Any, Dict, List - - -class SessionStorage: - def __init__(self, page): - self.__page = page - self.__store: Dict[str, Any] = {} - - def set(self, key: str, value: Any): - self.__store[key] = value - - def get(self, key: str): - return self.__store.get(key) - - def contains_key(self, key: str) -> bool: - return key in self.__store - - def remove(self, key: str): - self.__store.pop(key) - - def get_keys(self) -> List[str]: - return list(self.__store.keys()) - - def clear(self): - self.__store.clear() diff --git a/sdk/python/packages/flet/src/flet/core/shader_mask.py b/sdk/python/packages/flet/src/flet/core/shader_mask.py deleted file mode 100644 index 8d641eb229..0000000000 --- a/sdk/python/packages/flet/src/flet/core/shader_mask.py +++ /dev/null @@ -1,180 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.gradients import Gradient -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BlendMode, - BorderRadiusValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class ShaderMask(ConstrainedControl): - """ - A control that applies a mask generated by a shader to its child. - - For example, ShaderMask can be used to gradually fade out the edge of a child by using a `LinearGradient` mask. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.add( - ft.Row( - [ - ft.ShaderMask( - ft.Image(src="https://picsum.photos/100/200?2"), - blend_mode=ft.BlendMode.DST_IN, - shader=ft.LinearGradient( - begin=ft.alignment.top_center, - end=ft.alignment.bottom_center, - colors=[ft.colors.BLACK, ft.colors.TRANSPARENT], - stops=[0.5, 1.0], - ), - border_radius=10, - ), - ] - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/shadermask - """ - - def __init__( - self, - shader: Gradient, - content: Optional[Control] = None, - blend_mode: Optional[BlendMode] = None, - border_radius: Optional[BorderRadiusValue] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - self.blend_mode = blend_mode - self.shader = shader - self.border_radius = border_radius - - def _get_control_name(self): - return "shadermask" - - def before_update(self): - super().before_update() - self._set_attr_json("shader", self.__shader) - self._set_attr_json("borderRadius", self.__border_radius) - - def _get_children(self): - if self.__content: - self.__content._set_attr_internal("n", "content") - return [self.__content] - return [] - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # blend_mode - @property - def blend_mode(self) -> Optional[BlendMode]: - return self.__blend_mode - - @blend_mode.setter - def blend_mode(self, value: Optional[BlendMode]): - self.__blend_mode = value - self._set_enum_attr("blendMode", value, BlendMode) - - # shader - @property - def shader(self) -> Optional[Gradient]: - return self.__shader - - @shader.setter - def shader(self, value: Optional[Gradient]): - self.__shader = value - - # border_radius - @property - def border_radius(self) -> Optional[BorderRadiusValue]: - return self.__border_radius - - @border_radius.setter - def border_radius(self, value: Optional[BorderRadiusValue]): - self.__border_radius = value diff --git a/sdk/python/packages/flet/src/flet/core/shake_detector.py b/sdk/python/packages/flet/src/flet/core/shake_detector.py deleted file mode 100644 index 162d4eb3a9..0000000000 --- a/sdk/python/packages/flet/src/flet/core/shake_detector.py +++ /dev/null @@ -1,109 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import OptionalControlEventCallable - - -class ShakeDetector(Control): - """ - Detects phone shakes. - - It is non-visual and should be added to `page.overlay` list. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - shd = ft.ShakeDetector( - minimum_shake_count=2, - shake_slop_time_ms=300, - shake_count_reset_time_ms=1000, - on_shake=lambda _: print("SHAKE DETECTED!"), - ) - page.overlay.append(shd) - - page.add(ft.Text("Program body")) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/shakedetector - """ - - def __init__( - self, - minimum_shake_count: Optional[int] = None, - shake_slop_time_ms: Optional[int] = None, - shake_count_reset_time_ms: Optional[int] = None, - shake_threshold_gravity: OptionalNumber = None, - on_shake: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - data=data, - ) - - self.minimum_shake_count = minimum_shake_count - self.shake_slop_time_ms = shake_slop_time_ms - self.shake_count_reset_time_ms = shake_count_reset_time_ms - self.shake_threshold_gravity = shake_threshold_gravity - self.on_shake = on_shake - - def _get_control_name(self): - return "shakedetector" - - # minimum_shake_count - @property - def minimum_shake_count(self) -> Optional[int]: - return self._get_attr("minimumShakeCount", data_type="int") - - @minimum_shake_count.setter - def minimum_shake_count(self, value: Optional[int]): - self._set_attr("minimumShakeCount", value) - - # shake_slop_time_ms - @property - def shake_slop_time_ms(self) -> Optional[int]: - return self._get_attr("shakeSlopTimeMS", data_type="int") - - @shake_slop_time_ms.setter - def shake_slop_time_ms(self, value: Optional[int]): - self._set_attr("shakeSlopTimeMS", value) - - # shake_count_reset_time_ms - @property - def shake_count_reset_time_ms(self) -> Optional[int]: - return self._get_attr("shakeCountResetTimeMs", data_type="int") - - @shake_count_reset_time_ms.setter - def shake_count_reset_time_ms(self, value: Optional[int]): - self._set_attr("shakeCountResetTimeMs", value) - - # shake_threshold_gravity - @property - def shake_threshold_gravity(self) -> OptionalNumber: - return self._get_attr("shakeThresholdGravity", data_type="float") - - @shake_threshold_gravity.setter - def shake_threshold_gravity(self, value: OptionalNumber): - self._set_attr("shakeThresholdGravity", value) - - # on_shake - @property - def on_shake(self) -> OptionalControlEventCallable: - return self._get_event_handler("shake") - - @on_shake.setter - def on_shake(self, handler: OptionalControlEventCallable): - self._add_event_handler("shake", handler) diff --git a/sdk/python/packages/flet/src/flet/core/size.py b/sdk/python/packages/flet/src/flet/core/size.py deleted file mode 100644 index 483a0ec1da..0000000000 --- a/sdk/python/packages/flet/src/flet/core/size.py +++ /dev/null @@ -1,73 +0,0 @@ -from dataclasses import dataclass - -from flet.core.types import Number - -__all__ = [ - "Size", - "copy", - "square", - "from_width", - "from_height", - "from_radius", - "zero", - "infinite", -] - - -@dataclass(frozen=True) -class Size: - """ - A class representing a 2D size with width and height. - """ - - width: float - height: float - - @property - def aspect_ratio(self) -> float: - """Returns the aspect ratio (width / height).""" - if self.height != 0.0: - return self.width / self.height - if self.width > 0.0: - return float("inf") - if self.width < 0.0: - return float("-inf") - return 0.0 - - def is_infinite(self) -> bool: - """Checks if either dimension is infinite.""" - return self.width == float("inf") or self.height == float("inf") - - def is_finite(self) -> bool: - """Checks if both dimensions are finite.""" - return self.width != float("inf") and self.height != float("inf") - - -def copy(source: "Size") -> Size: - """Creates a copy of the given Size object.""" - return Size(source.width, source.height) - - -def square(dimension: Number) -> Size: - """Creates a square Size where width and height are the same.""" - return Size(dimension, dimension) - - -def from_width(width: Number) -> Size: - """Creates a Size with the given width and an infinite height.""" - return Size(width, float("inf")) - - -def from_height(height: Number) -> Size: - """Creates a Size with the given height and an infinite width.""" - return Size(float("inf"), height) - - -def from_radius(radius: Number) -> Size: - """Creates a square Size whose width and height are twice the given radius.""" - return Size(radius * 2.0, radius * 2.0) - - -# Constants -zero = Size(0.0, 0.0) -infinite = Size(float("inf"), float("inf")) diff --git a/sdk/python/packages/flet/src/flet/core/slider.py b/sdk/python/packages/flet/src/flet/core/slider.py deleted file mode 100644 index d64ea65f25..0000000000 --- a/sdk/python/packages/flet/src/flet/core/slider.py +++ /dev/null @@ -1,397 +0,0 @@ -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - PaddingValue, -) -from flet.utils.deprecated import deprecated_property - - -class SliderInteraction(Enum): - TAP_AND_SLIDE = "tapAndSlide" - TAP_ONLY = "tapOnly" - SLIDE_ONLY = "slideOnly" - SLIDE_THUMB = "slideThumb" - - -class Slider(ConstrainedControl, AdaptiveControl): - """ - A slider provides a visual indication of adjustable content, as well as the current setting in the total range of content. - - Use a slider when you want people to set defined values (such as volume or brightness), or when people would benefit from instant feedback on the effect of setting changes. - - Example: - ``` - import flet as ft - - def main(page): - page.add( - ft.Text("Slider with value:"), - ft.Slider(value=0.3), - ft.Text("Slider with a custom range and label:"), - ft.Slider(min=0, max=100, divisions=10, label="{value}%")) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/slider - """ - - def __init__( - self, - value: OptionalNumber = None, - label: Optional[str] = None, - min: OptionalNumber = None, - max: OptionalNumber = None, - divisions: Optional[int] = None, - round: Optional[int] = None, - autofocus: Optional[bool] = None, - active_color: Optional[ColorValue] = None, - inactive_color: Optional[ColorValue] = None, - thumb_color: Optional[ColorValue] = None, - interaction: Optional[SliderInteraction] = None, - secondary_active_color: Optional[ColorValue] = None, - overlay_color: ControlStateValue[ColorValue] = None, - secondary_track_value: OptionalNumber = None, - mouse_cursor: Optional[MouseCursor] = None, - padding: Optional[PaddingValue] = None, - year_2023: Optional[bool] = None, - on_change: OptionalControlEventCallable = None, - on_change_start: OptionalControlEventCallable = None, - on_change_end: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.value = value - self.label = label - self.min = min - self.max = max - self.divisions = divisions - self.round = round - self.autofocus = autofocus - self.active_color = active_color - self.inactive_color = inactive_color - self.thumb_color = thumb_color - self.interaction = interaction - self.overlay_color = overlay_color - self.on_change = on_change - self.on_change_start = on_change_start - self.on_change_end = on_change_end - self.on_focus = on_focus - self.on_blur = on_blur - self.secondary_active_color = secondary_active_color - self.secondary_track_value = secondary_track_value - self.mouse_cursor = mouse_cursor - self.padding = padding - self.year_2023 = year_2023 - - def _get_control_name(self): - return "slider" - - def before_update(self): - super().before_update() - assert ( - self.min is None or self.max is None or self.min <= self.max - ), "min must be less than or equal to max" - assert ( - self.min is None or self.value is None or (self.value >= self.min) - ), "value must be greater than or equal to min" - assert ( - self.max is None or self.value is None or (self.value <= self.max) - ), "value must be less than or equal to max" - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json("padding", self.__padding) - - # value - @property - def value(self) -> float: - return self._get_attr("value", data_type="float", def_value=self.min or 0.0) - - @value.setter - def value(self, value: OptionalNumber): - self._set_attr("value", value) - - # label - @property - def label(self) -> Optional[str]: - return self._get_attr("label") - - @label.setter - def label(self, value: Optional[str]): - self._set_attr("label", value) - - # year_2023 - @property - def year_2023(self) -> Optional[bool]: - return self._get_attr("year2023", data_type="bool", def_value=True) - - @year_2023.setter - def year_2023(self, value: Optional[bool]): - self._set_attr("year2023", value) - if value is not None: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # interaction - @property - def interaction(self) -> Optional[SliderInteraction]: - return self.__interaction - - @interaction.setter - def interaction(self, value: Optional[SliderInteraction]): - self.__interaction = value - self._set_enum_attr("interaction", value, SliderInteraction) - - # min - @property - def min(self) -> float: - return self._get_attr("min", data_type="float", def_value=0.0) - - @min.setter - def min(self, value: OptionalNumber): - self._set_attr("min", value) - - # secondary_track_value - @property - def secondary_track_value(self) -> OptionalNumber: - return self._get_attr("secondaryTrackValue", data_type="float") - - @secondary_track_value.setter - def secondary_track_value(self, value: OptionalNumber): - self._set_attr("secondaryTrackValue", value) - - # secondary_active_color - @property - def secondary_active_color(self) -> Optional[ColorValue]: - return self.__secondary_active_color - - @secondary_active_color.setter - def secondary_active_color(self, value: Optional[ColorValue]): - self.__secondary_active_color = value - self._set_enum_attr("secondaryActiveColor", value, ColorEnums) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self._get_attr("mouseCursor") - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # max - @property - def max(self) -> float: - return self._get_attr("max", data_type="float", def_value=1.0) - - @max.setter - def max(self, value: OptionalNumber): - self._set_attr("max", value) - - # divisions - @property - def divisions(self) -> Optional[int]: - return self._get_attr("divisions") - - @divisions.setter - def divisions(self, value: Optional[int]): - self._set_attr("divisions", value) - - # round - @property - def round(self) -> int: - return self._get_attr("round", data_type="int", def_value=0) - - @round.setter - def round(self, value: Optional[int]): - self._set_attr("round", value) - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[str]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[str]): - self.__overlay_color = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # inactive_color - @property - def inactive_color(self) -> Optional[ColorValue]: - return self.__inactive_color - - @inactive_color.setter - def inactive_color(self, value: Optional[ColorValue]): - self.__inactive_color = value - self._set_enum_attr("inactiveColor", value, ColorEnums) - - # thumb_color - @property - def thumb_color(self) -> Optional[ColorValue]: - return self.__thumb_color - - @thumb_color.setter - def thumb_color(self, value: Optional[ColorValue]): - self.__thumb_color = value - self._set_enum_attr("thumbColor", value, ColorEnums) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_change_start - @property - def on_change_start(self) -> OptionalControlEventCallable: - return self._get_event_handler("change_start") - - @on_change_start.setter - def on_change_start(self, handler: OptionalControlEventCallable): - self._add_event_handler("change_start", handler) - - # on_change_end - @property - def on_change_end(self) -> OptionalControlEventCallable: - return self._get_event_handler("change_end") - - @on_change_end.setter - def on_change_end(self, handler: OptionalControlEventCallable): - self._add_event_handler("change_end", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/snack_bar.py b/sdk/python/packages/flet/src/flet/core/snack_bar.py deleted file mode 100644 index c1a3cce73a..0000000000 --- a/sdk/python/packages/flet/src/flet/core/snack_bar.py +++ /dev/null @@ -1,321 +0,0 @@ -from enum import Enum -from typing import Any, Optional - -from flet.core.buttons import OutlinedBorder -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - MarginValue, - OptionalControlEventCallable, - PaddingValue, -) - - -class SnackBarBehavior(Enum): - FIXED = "fixed" - FLOATING = "floating" - - -class DismissDirection(Enum): - NONE = "none" - VERTICAL = "vertical" - HORIZONTAL = "horizontal" - END_TO_START = "endToStart" - START_TO_END = "startToEnd" - UP = "up" - DOWN = "down" - - -class SnackBar(Control): - """ - A lightweight message with an optional action which briefly displays at the bottom of the screen. - - Example: - ``` - import flet as ft - - class Data: - def __init__(self) -> None: - self.counter = 0 - - d = Data() - - def main(page): - - page.snack_bar = ft.SnackBar( - content=ft.Text("Hello, world!"), - action="Alright!", - ) - page.snack_bar.open = True - - def on_click(e): - page.snack_bar = ft.SnackBar(ft.Text(f"Hello {d.counter}")) - page.snack_bar.open = True - d.counter += 1 - page.update() - - page.add(ft.ElevatedButton("Open SnackBar", on_click=on_click)) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/snackbar - """ - - def __init__( - self, - content: Control, - open: bool = False, - behavior: Optional[SnackBarBehavior] = None, - dismiss_direction: Optional[DismissDirection] = None, - show_close_icon: Optional[bool] = False, - action: Optional[str] = None, - action_color: Optional[ColorValue] = None, - close_icon_color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - duration: Optional[int] = None, - margin: Optional[MarginValue] = None, - padding: Optional[PaddingValue] = None, - width: OptionalNumber = None, - elevation: OptionalNumber = None, - shape: Optional[OutlinedBorder] = None, - clip_behavior: Optional[ClipBehavior] = None, - action_overflow_threshold: OptionalNumber = None, - on_action: OptionalControlEventCallable = None, - on_visible: OptionalControlEventCallable = None, - # - # Control - # - ref: Optional[Ref] = None, - disabled: Optional[bool] = None, - visible: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - disabled=disabled, - visible=visible, - data=data, - ) - - self.open = open - self.behavior = behavior - self.dismiss_direction = dismiss_direction - self.show_close_icon = show_close_icon - self.close_icon_color = close_icon_color - self.margin = margin - self.padding = padding - self.width = width - self.content = content - self.action = action - self.action_color = action_color - self.bgcolor = bgcolor - self.duration = duration - self.elevation = elevation - self.on_action = on_action - self.on_visible = on_visible - self.shape = shape - self.clip_behavior = clip_behavior - self.action_overflow_threshold = action_overflow_threshold - - def _get_control_name(self): - return "snackbar" - - def _get_children(self): - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def before_update(self): - super().before_update() - self._set_attr_json("shape", self.__shape) - self._set_attr_json("padding", self.__padding) - self._set_attr_json("margin", self.__margin) - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # show_close_icon - @property - def show_close_icon(self) -> bool: - return self._get_attr("showCloseIcon", data_type="bool", def_value=False) - - @show_close_icon.setter - def show_close_icon(self, value: Optional[bool]): - self._set_attr("showCloseIcon", value) - - # content - @property - def content(self) -> Control: - return self.__content - - @content.setter - def content(self, value: Control): - self.__content = value - - # action - @property - def action(self) -> Optional[str]: - return self._get_attr("action") - - @action.setter - def action(self, value: Optional[str]): - self._set_attr("action", value) - - # action_color - @property - def action_color(self) -> Optional[ColorValue]: - return self.__action_color - - @action_color.setter - def action_color(self, value: Optional[ColorValue]): - self.__action_color = value - self._set_enum_attr("actionColor", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgColor", value, ColorEnums) - - # close_icon_color - @property - def close_icon_color(self) -> Optional[ColorValue]: - return self.__close_icon_color - - @close_icon_color.setter - def close_icon_color(self, value: Optional[ColorValue]): - self.__close_icon_color = value - self._set_enum_attr("closeIconColor", value, ColorEnums) - - # duration - @property - def duration(self) -> Optional[int]: - return self._get_attr("duration", data_type="int") - - @duration.setter - def duration(self, value: Optional[int]): - self._set_attr("duration", value) - - # action_overflow_threshold - @property - def action_overflow_threshold(self) -> float: - return self._get_attr( - "actionOverflowThreshold", data_type="float", def_value=0.25 - ) - - @action_overflow_threshold.setter - def action_overflow_threshold(self, value: OptionalNumber): - assert ( - value is None or 0 <= value <= 1 - ), "action_overflow_threshold must be between 0 and 1 inclusive" - self._set_attr("actionOverflowThreshold", value) - - # behavior - @property - def behavior(self) -> Optional[SnackBarBehavior]: - return self.__behavior - - @behavior.setter - def behavior(self, value: Optional[SnackBarBehavior]): - self.__behavior = value - self._set_enum_attr("behavior", value, SnackBarBehavior) - - # dismissDirection - @property - def dismiss_direction(self) -> Optional[DismissDirection]: - return self.__dismiss_direction - - @dismiss_direction.setter - def dismiss_direction(self, value: Optional[DismissDirection]): - self.__dismiss_direction = value - self._set_enum_attr("dismissDirection", value, DismissDirection) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # margin - @property - def margin(self) -> Optional[MarginValue]: - return self.__margin - - @margin.setter - def margin(self, value: Optional[MarginValue]): - self.__margin = value - - # width - @property - def width(self) -> OptionalNumber: - return self._get_attr("width", data_type="float") - - @width.setter - def width(self, value: OptionalNumber): - self._set_attr("width", value) - - # elevation - @property - def elevation(self) -> OptionalNumber: - return self._get_attr("elevation", data_type="float") - - @elevation.setter - def elevation(self, value: OptionalNumber): - assert value is None or value >= 0, "elevation cannot be negative" - self._set_attr("elevation", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # shape - @property - def shape(self) -> Optional[OutlinedBorder]: - return self.__shape - - @shape.setter - def shape(self, value: Optional[OutlinedBorder]): - self.__shape = value - - # on_action - @property - def on_action(self) -> OptionalControlEventCallable: - return self._get_event_handler("action") - - @on_action.setter - def on_action(self, handler: OptionalControlEventCallable): - self._add_event_handler("action", handler) - - # on_visible - @property - def on_visible(self) -> OptionalControlEventCallable: - return self._get_event_handler("visible") - - @on_visible.setter - def on_visible(self, handler: OptionalControlEventCallable): - self._add_event_handler("visible", handler) diff --git a/sdk/python/packages/flet/src/flet/core/stack.py b/sdk/python/packages/flet/src/flet/core/stack.py deleted file mode 100644 index 4c29fcdd92..0000000000 --- a/sdk/python/packages/flet/src/flet/core/stack.py +++ /dev/null @@ -1,199 +0,0 @@ -from enum import Enum -from typing import Any, List, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ( - ClipBehavior, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class StackFit(Enum): - LOOSE = "loose" - EXPAND = "expand" - PASS_THROUGH = "passThrough" - - -class Stack(ConstrainedControl, AdaptiveControl): - """ - A control that positions its children on top of each other. - - This control is useful if you want to overlap several children in a simple way, for example having some text and an image, overlaid with a gradient and a button attached to the bottom. - - Stack is also useful if you want to implement implicit animations (https://flet.dev/docs/guides/python/animations/) that require knowing absolute position of a target value. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - st = ft.Stack( - controls=[ - ft.Image( - src=f"https://picsum.photos/300/300", - width=300, - height=300, - fit=ft.ImageFit.CONTAIN, - ), - ft.Row( - controls=[ - ft.Text( - "Image title", - color="white", - size=40, - weight="bold", - opacity=0.5, - ) - ], - alignment=ft.MainAxisAlignment.CENTER, - ), - ], - width=300, - height=300, - ) - - page.add(st) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/stack - """ - - def __init__( - self, - controls: Optional[Sequence[Control]] = None, - clip_behavior: Optional[ClipBehavior] = None, - alignment: Optional[Alignment] = None, - fit: Optional[StackFit] = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__controls: List[Control] = [] - self.controls = controls - self.clip_behavior = clip_behavior - self.alignment = alignment - self.fit = fit - - def _get_control_name(self): - return "stack" - - def _get_children(self): - return self.__controls - - def before_update(self): - super().before_update() - self._set_attr_json("alignment", self.__alignment) - - def __contains__(self, item): - return item in self.__controls - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # fit - @property - def fit(self) -> Optional[StackFit]: - return self.__fit - - @fit.setter - def fit(self, value: Optional[StackFit]): - self.__fit = value - self._set_enum_attr("fit", value, StackFit) diff --git a/sdk/python/packages/flet/src/flet/core/submenu_button.py b/sdk/python/packages/flet/src/flet/core/submenu_button.py deleted file mode 100644 index fdd9312912..0000000000 --- a/sdk/python/packages/flet/src/flet/core/submenu_button.py +++ /dev/null @@ -1,281 +0,0 @@ -import time -from typing import Any, Optional, Sequence, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.menu_bar import MenuStyle -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class SubmenuButton(ConstrainedControl): - """ - A menu button that displays a cascading menu. It can be used as part of a MenuBar, or as a standalone control. - - ----- - - Online docs: https://flet.dev/docs/controls/submenubutton - """ - - def __init__( - self, - content: Optional[Control] = None, - controls: Optional[Sequence[Control]] = None, - leading: Optional[Control] = None, - trailing: Optional[Control] = None, - clip_behavior: Optional[ClipBehavior] = None, - menu_style: Optional[MenuStyle] = None, - style: Optional[ButtonStyle] = None, - alignment_offset: Optional[OffsetValue] = None, - on_open: OptionalControlEventCallable = None, - on_close: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - self.controls = controls - self.leading = leading - self.trailing = trailing - self.clip_behavior = clip_behavior - self.style = style - self.menu_style = menu_style - self.alignment_offset = alignment_offset - self.on_open = on_open - self.on_close = on_close - self.on_hover = on_hover - self.on_focus = on_focus - self.on_blur = on_blur - - def _get_control_name(self): - return "submenubutton" - - def before_update(self): - super().before_update() - if self.__style is not None: - self.__style.side = self._wrap_attr_dict(self.__style.side) - self.__style.shape = self._wrap_attr_dict(self.__style.shape) - if self.__menu_style is not None: - self.__menu_style.side = self._wrap_attr_dict(self.__menu_style.side) - self.__menu_style.shape = self._wrap_attr_dict(self.__menu_style.shape) - self._set_attr_json("style", self.__style) - self._set_attr_json("menuStyle", self.__menu_style) - - def _get_children(self): - children = [] - if self.__controls: - for c in self.__controls: - c._set_attr_internal("n", "controls") - children.append(c) - if self.__leading: - self.__leading._set_attr_internal("n", "leading") - children.append(self.__leading) - if self.__trailing: - self.__trailing._set_attr_internal("n", "trailing") - children.append(self.__trailing) - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - return children - - def __contains__(self, item): - return item in self.__controls - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # controls - @property - def controls(self): - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # leading - @property - def leading(self) -> Optional[Control]: - return self.__leading - - @leading.setter - def leading(self, value: Optional[Control]): - self.__leading = value - - # trailing - @property - def trailing(self) -> Optional[Control]: - return self.__trailing - - @trailing.setter - def trailing(self, value: Optional[Control]): - self.__trailing = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # menu_style - @property - def menu_style(self) -> Optional[MenuStyle]: - return self.__menu_style - - @menu_style.setter - def menu_style(self, value: Optional[MenuStyle]): - self.__menu_style = value - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # alignment_offset - @property - def alignment_offset(self) -> Optional[OffsetValue]: - return self.__alignment_offset - - @alignment_offset.setter - def alignment_offset(self, value: Optional[OffsetValue]): - self.__alignment_offset = value - - # on_open - @property - def on_open(self): - return self._get_event_handler("open") - - @on_open.setter - def on_open(self, handler: OptionalControlEventCallable): - self._add_event_handler("open", handler) - self._set_attr("onOpen", True if handler is not None else None) - - # on_close - @property - def on_close(self): - return self._get_event_handler("close") - - @on_close.setter - def on_close(self, handler: OptionalControlEventCallable): - self._add_event_handler("close", handler) - self._set_attr("onClose", True if handler is not None else None) - - # on_hover - @property - def on_hover(self): - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - self._set_attr("onHover", True if handler is not None else None) - - # on_focus - @property - def on_focus(self): - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self): - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/switch.py b/sdk/python/packages/flet/src/flet/core/switch.py deleted file mode 100644 index ec3fbf9b0d..0000000000 --- a/sdk/python/packages/flet/src/flet/core/switch.py +++ /dev/null @@ -1,407 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ControlStateValue, - IconValue, - LabelPosition, - MouseCursor, - OffsetValue, - OnFocusEvent, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, -) - - -class Switch(ConstrainedControl, AdaptiveControl): - """ - A toggle represents a physical switch that allows someone to choose between two mutually exclusive options. - - or example, "On/Off", "Show/Hide". Choosing an option should produce an immediate result. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def theme_changed(e): - page.theme_mode = ( - ft.ThemeMode.DARK - if page.theme_mode == ft.ThemeMode.LIGHT - else ft.ThemeMode.LIGHT - ) - c.label = ( - "Light theme" if page.theme_mode == ft.ThemeMode.LIGHT else "Dark theme" - ) - page.update() - - page.theme_mode = ft.ThemeMode.LIGHT - c = ft.Switch(label="Light theme", on_change=theme_changed) - page.add(c) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/switch - """ - - def __init__( - self, - label: Optional[Union[str, Control]] = None, - label_position: Optional[LabelPosition] = None, - label_style: Optional[TextStyle] = None, - value: Optional[bool] = None, - autofocus: Optional[bool] = None, - active_color: Optional[ColorValue] = None, - active_track_color: Optional[ColorValue] = None, - focus_color: Optional[ColorValue] = None, - inactive_thumb_color: Optional[ColorValue] = None, - inactive_track_color: Optional[ColorValue] = None, - thumb_color: ControlStateValue[ColorValue] = None, - thumb_icon: ControlStateValue[IconValue] = None, - track_color: ControlStateValue[ColorValue] = None, - adaptive: Optional[bool] = None, - hover_color: Optional[ColorValue] = None, - splash_radius: OptionalNumber = None, - overlay_color: ControlStateValue[ColorValue] = None, - track_outline_color: ControlStateValue[ColorValue] = None, - track_outline_width: ControlStateValue[OptionalNumber] = None, - mouse_cursor: Optional[MouseCursor] = None, - on_change: OptionalControlEventCallable = None, - on_focus: OptionalEventCallable[OnFocusEvent] = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.__on_focus = EventHandler(lambda e: OnFocusEvent(e)) - self._add_event_handler("focus", self.__on_focus.get_handler()) - - self.value = value - self.label = label - self.label_style = label_style - self.label_position = label_position - self.autofocus = autofocus - self.active_color = active_color - self.active_track_color = active_track_color - self.focus_color = focus_color - self.inactive_thumb_color = inactive_thumb_color - self.inactive_track_color = inactive_track_color - self.thumb_color = thumb_color - self.thumb_icon = thumb_icon - self.track_color = track_color - self.on_change = on_change - self.on_focus = on_focus - self.on_blur = on_blur - self.hover_color = hover_color - self.splash_radius = splash_radius - self.overlay_color = overlay_color - self.track_outline_color = track_outline_color - self.track_outline_width = track_outline_width - self.mouse_cursor = mouse_cursor - - def _get_control_name(self): - return "switch" - - def before_update(self): - super().before_update() - self._set_attr_json("thumbColor", self.__thumb_color, wrap_attr_dict=True) - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json( - "trackOutlineColor", self.__track_outline_color, wrap_attr_dict=True - ) - self._set_attr_json( - "trackOutlineWidth", self.__track_outline_width, wrap_attr_dict=True - ) - self._set_attr_json("thumbIcon", self.__thumb_icon, wrap_attr_dict=True) - self._set_attr_json("trackColor", self.__track_color, wrap_attr_dict=True) - self._set_attr_json("labelStyle", self.__label_style) - - def _get_children(self): - return [self.__label] if isinstance(self.__label, Control) else [] - - # value - @property - def value(self) -> bool: - return self._get_attr("value", data_type="bool", def_value=False) - - @value.setter - def value(self, value: Optional[bool]): - self._set_attr("value", value) - - # label - @property - def label(self) -> Optional[Union[str, Control]]: - return self.__label - - @label.setter - def label(self, value: Optional[Union[str, Control]]): - self.__label = value - if not isinstance(value, Control): - self._set_attr("label", value) - - # hover_color - @property - def hover_color(self) -> Optional[ColorValue]: - return self.__hover_color - - @hover_color.setter - def hover_color(self, value: Optional[ColorValue]): - self.__hover_color = value - self._set_enum_attr("hoverColor", value, ColorEnums) - - # track_outline_color - @property - def track_outline_color(self) -> ControlStateValue[ColorValue]: - return self.__track_outline_color - - @track_outline_color.setter - def track_outline_color(self, value: ControlStateValue[ColorValue]): - self.__track_outline_color = value - - # track_outline_width - @property - def track_outline_width(self) -> ControlStateValue[OptionalNumber]: - return self.__track_outline_width - - @track_outline_width.setter - def track_outline_width(self, value: ControlStateValue[OptionalNumber]): - self.__track_outline_width = value - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[str]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[str]): - self.__overlay_color = value - - # splash_radius - @property - def splash_radius(self) -> OptionalNumber: - return self._get_attr("splashRadius", data_type="float") - - @splash_radius.setter - def splash_radius(self, value: OptionalNumber): - assert value is None or value >= 0, "splash_radius cannot be negative" - self._set_attr("splashRadius", value) - - # label_style - @property - def label_style(self) -> Optional[TextStyle]: - return self.__label_style - - @label_style.setter - def label_style(self, value: Optional[TextStyle]): - self.__label_style = value - - # label_position - @property - def label_position(self) -> Optional[LabelPosition]: - return self.__label_position - - @label_position.setter - def label_position(self, value: Optional[LabelPosition]): - self.__label_position = value - self._set_enum_attr("labelPosition", value, LabelPosition) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # active_color - @property - def active_color(self) -> Optional[ColorValue]: - return self.__active_color - - @active_color.setter - def active_color(self, value: Optional[ColorValue]): - self.__active_color = value - self._set_enum_attr("activeColor", value, ColorEnums) - - # active_track_color - @property - def active_track_color(self) -> Optional[ColorValue]: - return self.__active_track_color - - @active_track_color.setter - def active_track_color(self, value: Optional[ColorValue]): - self.__active_track_color = value - self._set_enum_attr("activeTrackColor", value, ColorEnums) - - # focus_color - @property - def focus_color(self) -> Optional[ColorValue]: - return self.__focus_color - - @focus_color.setter - def focus_color(self, value: Optional[ColorValue]): - self.__focus_color = value - self._set_enum_attr("focusColor", value, ColorEnums) - - # inactive_thumb_color - @property - def inactive_thumb_color(self) -> Optional[ColorValue]: - return self.__inactive_thumb_color - - @inactive_thumb_color.setter - def inactive_thumb_color(self, value: Optional[ColorValue]): - self.__inactive_thumb_color = value - self._set_enum_attr("inactiveThumbColor", value, ColorEnums) - - # inactive_track_color - @property - def inactive_track_color(self) -> Optional[ColorValue]: - return self.__inactive_track_color - - @inactive_track_color.setter - def inactive_track_color(self, value: Optional[ColorValue]): - self.__inactive_track_color = value - self._set_enum_attr("inactiveTrackColor", value, ColorEnums) - - # thumb_color - @property - def thumb_color(self) -> ControlStateValue[str]: - return self.__thumb_color - - @thumb_color.setter - def thumb_color(self, value: ControlStateValue[str]): - self.__thumb_color = value - - # thumb_icon - @property - def thumb_icon(self) -> ControlStateValue[IconValue]: - return self.__thumb_icon - - @thumb_icon.setter - def thumb_icon(self, value: ControlStateValue[IconValue]): - self.__thumb_icon = value - - # track_color - @property - def track_color(self) -> ControlStateValue[str]: - return self.__track_color - - @track_color.setter - def track_color(self, value: ControlStateValue[str]): - self.__track_color = value - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_focus - @property - def on_focus(self) -> OptionalEventCallable[OnFocusEvent]: - return self.__on_focus.handler - - @on_focus.setter - def on_focus(self, handler: OptionalEventCallable[OnFocusEvent]): - self.__on_focus.handler = handler - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/tabs.py b/sdk/python/packages/flet/src/flet/core/tabs.py deleted file mode 100644 index 42faa6a7b9..0000000000 --- a/sdk/python/packages/flet/src/flet/core/tabs.py +++ /dev/null @@ -1,570 +0,0 @@ -from typing import Any, List, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.border import BorderSide -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.form_field_control import IconValueOrControl -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.types import ( - BorderRadiusValue, - ClipBehavior, - ColorEnums, - ColorValue, - ControlStateValue, - IconEnums, - IconValue, - MarginValue, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - TabAlignment, -) - - -class Tab(AdaptiveControl): - def __init__( - self, - text: Optional[str] = None, - content: Optional[Control] = None, - tab_content: Optional[Control] = None, - icon: Optional[IconValueOrControl] = None, - height: OptionalNumber = None, - icon_margin: Optional[MarginValue] = None, - # - # Control and AdaptiveControl - # - ref: Optional[Ref] = None, - visible: Optional[bool] = None, - adaptive: Optional[bool] = None, - ): - Control.__init__(self, ref=ref, visible=visible) - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.text = text - self.icon = icon - self.content = content - self.tab_content = tab_content - self.height = height - self.icon_margin = icon_margin - - def _get_control_name(self): - return "tab" - - def _get_children(self): - children = [] - if self.__tab_content: - self.__tab_content._set_attr_internal("n", "tab_content") - children.append(self.__tab_content) - if self.__content: - self.__content._set_attr_internal("n", "content") - children.append(self.__content) - if isinstance(self.__icon, Control): - self.__icon._set_attr_internal("n", "icon") - children.append(self.__icon) - return children - - def before_update(self): - super().before_update() - self._set_attr_json("iconMargin", self.__icon_margin) - if isinstance(self.__icon, IconValue): - self._set_enum_attr("icon", self.__icon, IconEnums) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # height - @property - def height(self) -> Optional[float]: - return self._get_attr("height", data_type="float") - - @height.setter - def height(self, value: OptionalNumber): - self._set_attr("height", value) - - # icon - @property - def icon(self) -> Optional[IconValueOrControl]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValueOrControl]): - self.__icon = value - - # tab_content - @property - def tab_content(self) -> Optional[Control]: - return self.__tab_content - - @tab_content.setter - def tab_content(self, value: Optional[Control]): - self.__tab_content = value - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # icon_margin - @property - def icon_margin(self) -> Optional[MarginValue]: - return self.__icon_margin - - @icon_margin.setter - def icon_margin(self, value: Optional[MarginValue]): - self.__icon_margin = value - - -class Tabs(ConstrainedControl, AdaptiveControl): - """ - The Tabs control is used for navigating frequently accessed, distinct content categories. Tabs allow for navigation between two or more content views and relies on text headers to articulate the different sections of content. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - - t = ft.Tabs( - selected_index=1, - animation_duration=300, - tabs=[ - ft.Tab( - text="Tab 1", - content=ft.Container( - content=ft.Text("This is Tab 1"), alignment=ft.alignment.center - ), - ), - ft.Tab( - tab_content=ft.Icon(ft.icons.SEARCH), - content=ft.Text("This is Tab 2"), - ), - ft.Tab( - text="Tab 3", - icon=ft.icons.SETTINGS, - content=ft.Text("This is Tab 3"), - ), - ], - expand=1, - ) - - page.add(t) - - - ft.app(target=main) - - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/tabs - """ - - def __init__( - self, - tabs: Optional[List[Tab]] = None, - selected_index: Optional[int] = None, - scrollable: Optional[bool] = None, - tab_alignment: Optional[TabAlignment] = None, - animation_duration: Optional[int] = None, - divider_color: Optional[ColorValue] = None, - indicator_color: Optional[ColorValue] = None, - indicator_border_radius: Optional[BorderRadiusValue] = None, - indicator_border_side: Optional[BorderSide] = None, - indicator_padding: Optional[PaddingValue] = None, - indicator_tab_size: Optional[bool] = None, - is_secondary: Optional[bool] = None, - label_color: Optional[ColorValue] = None, - label_padding: Optional[PaddingValue] = None, - label_text_style: Optional[TextStyle] = None, - unselected_label_color: Optional[ColorValue] = None, - unselected_label_text_style: Optional[TextStyle] = None, - overlay_color: ControlStateValue[ColorValue] = None, - divider_height: OptionalNumber = None, - indicator_thickness: OptionalNumber = None, - enable_feedback: Optional[str] = None, - mouse_cursor: Optional[MouseCursor] = None, - padding: Optional[PaddingValue] = None, - splash_border_radius: Optional[BorderRadiusValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - on_click: OptionalControlEventCallable = None, - on_change: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - visible=visible, - disabled=disabled, - data=data, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.tabs = tabs - self.selected_index = selected_index - self.scrollable = scrollable - self.tab_alignment = tab_alignment - self.animation_duration = animation_duration - self.divider_color = divider_color - self.label_color = label_color - self.unselected_label_color = unselected_label_color - self.indicator_color = indicator_color - self.indicator_border_radius = indicator_border_radius - self.indicator_border_side = indicator_border_side - self.indicator_padding = indicator_padding - self.indicator_tab_size = indicator_tab_size - self.overlay_color = overlay_color - self.on_change = on_change - self.divider_height = divider_height - self.indicator_thickness = indicator_thickness - self.enable_feedback = enable_feedback - self.is_secondary = is_secondary - self.mouse_cursor = mouse_cursor - self.clip_behavior = clip_behavior - self.label_padding = label_padding - self.label_text_style = label_text_style - self.unselected_label_text_style = unselected_label_text_style - self.padding = padding - self.splash_border_radius = splash_border_radius - self.on_click = on_click - - def _get_control_name(self): - return "tabs" - - def before_update(self): - super().before_update() - self._set_attr_json("overlayColor", self.__overlay_color, wrap_attr_dict=True) - self._set_attr_json("indicatorBorderRadius", self.__indicator_border_radius) - self._set_attr_json("indicatorBorderSide", self.__indicator_border_side) - self._set_attr_json("indicatorPadding", self.__indicator_padding) - self._set_attr_json("labelPadding", self.__label_padding) - self._set_attr_json("labelTextStyle", self.__label_text_style) - self._set_attr_json( - "unselectedLabelTextStyle", self.__unselected_label_text_style - ) - - def _get_children(self): - return self.__tabs - - def __contains__(self, item): - return item in self.__tabs - - # tabs - @property - def tabs(self) -> List[Tab]: - return self.__tabs - - @tabs.setter - def tabs(self, value: Optional[List[Tab]]): - self.__tabs = value if value is not None else [] - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # selected_index - @property - def selected_index(self) -> int: - return self._get_attr("selectedIndex", data_type="int", def_value=0) - - @selected_index.setter - def selected_index(self, value: Optional[int]): - self._set_attr("selectedIndex", value) - - # scrollable - @property - def scrollable(self) -> bool: - return self._get_attr("scrollable", data_type="bool", def_value=True) - - @scrollable.setter - def scrollable(self, value: Optional[bool]): - self._set_attr("scrollable", value) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # is_secondary - @property - def is_secondary(self) -> bool: - return self._get_attr("isSecondary", data_type="bool", def_value=False) - - @is_secondary.setter - def is_secondary(self, value: Optional[bool]): - self._set_attr("isSecondary", value) - - # tab_alignment - @property - def tab_alignment(self) -> Optional[TabAlignment]: - return self.__tab_alignment - - @tab_alignment.setter - def tab_alignment(self, value: Optional[TabAlignment]): - self.__tab_alignment = value - self._set_enum_attr("tabAlignment", value, TabAlignment) - - # animation_duration - @property - def animation_duration(self) -> Optional[int]: - return self._get_attr("animationDuration", data_type="int") - - @animation_duration.setter - def animation_duration(self, value: Optional[int]): - self._set_attr("animationDuration", value) - - # divider_height - @property - def divider_height(self) -> float: - return self._get_attr("dividerHeight", data_type="float", def_value=1.0) - - @divider_height.setter - def divider_height(self, value: OptionalNumber): - self._set_attr("dividerHeight", value) - - # enable_feedback - @property - def enable_feedback(self): - return self._get_attr("enableFeedback") - - @enable_feedback.setter - def enable_feedback(self, value: Optional[bool]): - self._set_attr("enableFeedback", value) - - # indicator_thickness - @property - def indicator_thickness(self) -> float: - return self._get_attr("indicatorThickness", data_type="float", def_value=2.0) - - @indicator_thickness.setter - def indicator_thickness(self, value: OptionalNumber): - assert value is None or value > 0, "indicator_thickness must be greater than 0" - self._set_attr("indicatorThickness", value) - - # divider_color - @property - def divider_color(self) -> Optional[ColorValue]: - return self.__divider_color - - @divider_color.setter - def divider_color(self, value: Optional[ColorValue]): - self.__divider_color = value - self._set_enum_attr("dividerColor", value, ColorEnums) - - # indicator_color - @property - def indicator_color(self) -> Optional[ColorValue]: - return self.__indicator_color - - @indicator_color.setter - def indicator_color(self, value: Optional[ColorValue]): - self.__indicator_color = value - self._set_enum_attr("indicatorColor", value, ColorEnums) - - # indicator_border_radius - @property - def indicator_border_radius(self) -> Optional[BorderRadiusValue]: - return self.__indicator_border_radius - - @indicator_border_radius.setter - def indicator_border_radius(self, value: Optional[BorderRadiusValue]): - self.__indicator_border_radius = value - - # indicator_border_side - @property - def indicator_border_side(self) -> Optional[BorderSide]: - return self.__indicator_border_side - - @indicator_border_side.setter - def indicator_border_side(self, value: Optional[BorderSide]): - self.__indicator_border_side = value - - # indicator_padding - @property - def indicator_padding(self) -> Optional[PaddingValue]: - return self.__indicator_padding - - @indicator_padding.setter - def indicator_padding(self, value: Optional[PaddingValue]): - self.__indicator_padding = value - - # indicator_tab_size - @property - def indicator_tab_size(self) -> bool: - return self._get_attr("indicatorTabSize", data_type="bool", def_value=False) - - @indicator_tab_size.setter - def indicator_tab_size(self, value: Optional[bool]): - self._set_attr("indicatorTabSize", value) - - # label_color - @property - def label_color(self) -> Optional[ColorValue]: - return self.__label_color - - @label_color.setter - def label_color(self, value: Optional[ColorValue]): - self.__label_color = value - self._set_enum_attr("labelColor", value, ColorEnums) - - # unselected_label_color - @property - def unselected_label_color(self) -> Optional[ColorValue]: - return self.__unselected_label_color - - @unselected_label_color.setter - def unselected_label_color(self, value: Optional[ColorValue]): - self.__unselected_label_color = value - self._set_enum_attr("unselectedLabelColor", value, ColorEnums) - - # overlay_color - @property - def overlay_color(self) -> ControlStateValue[ColorValue]: - return self.__overlay_color - - @overlay_color.setter - def overlay_color(self, value: ControlStateValue[ColorValue]): - self.__overlay_color = value - - # label_padding - @property - def label_padding(self) -> Optional[PaddingValue]: - return self.__label_padding - - @label_padding.setter - def label_padding(self, value: Optional[PaddingValue]): - self.__label_padding = value - - # label_text_style - @property - def label_text_style(self) -> Optional[TextStyle]: - return self.__label_text_style - - @label_text_style.setter - def label_text_style(self, value: Optional[TextStyle]): - self.__label_text_style = value - - # unselected_label_text_style - @property - def unselected_label_text_style(self) -> Optional[TextStyle]: - return self.__unselected_label_text_style - - @unselected_label_text_style.setter - def unselected_label_text_style(self, value: Optional[TextStyle]): - self.__unselected_label_text_style = value - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # splash_border_radius - @property - def splash_border_radius(self) -> Optional[BorderRadiusValue]: - return self.__splash_border_radius - - @splash_border_radius.setter - def splash_border_radius(self, value: Optional[BorderRadiusValue]): - self.__splash_border_radius = value - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) diff --git a/sdk/python/packages/flet/src/flet/core/template_route.py b/sdk/python/packages/flet/src/flet/core/template_route.py deleted file mode 100644 index a60e8a8671..0000000000 --- a/sdk/python/packages/flet/src/flet/core/template_route.py +++ /dev/null @@ -1,25 +0,0 @@ -import re - -import repath - - -class TemplateRoute: - def __init__(self, route: str) -> None: - self.__last_params = {} - self.route = route - - def match(self, route_template: str) -> bool: - # remove old properties - for k in self.__last_params: - setattr(self, k, None) - - # perform new match - pattern = repath.pattern(route_template) - match = re.match(pattern, self.route) - - if match: - self.__last_params = match.groupdict() - for k, v in self.__last_params.items(): - setattr(self, k, v) - return True - return False diff --git a/sdk/python/packages/flet/src/flet/core/text.py b/sdk/python/packages/flet/src/flet/core/text.py deleted file mode 100644 index 99ff41b72a..0000000000 --- a/sdk/python/packages/flet/src/flet/core/text.py +++ /dev/null @@ -1,477 +0,0 @@ -import json -from dataclasses import dataclass -from enum import Enum -from typing import Any, List, Optional, Union -from warnings import warn - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.text_span import TextSpan -from flet.core.text_style import TextOverflow, TextStyle, TextThemeStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - FontWeight, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - TextAlign, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class TextAffinity(Enum): - UPSTREAM = "upstream" - DOWNSTREAM = "downstream" - - -@dataclass -class TextSelection: - start: Optional[int] = None - end: Optional[int] = None - selection: Optional[str] = None - base_offset: Optional[int] = None - extent_offset: Optional[int] = None - affinity: Optional[TextAffinity] = None - directional: Optional[bool] = None - collapsed: Optional[bool] = None - valid: Optional[bool] = None - normalized: Optional[bool] = None - - -class TextSelectionChangeCause(Enum): - UNKNOWN = "unknown" - TAP = "tap" - DOUBLE_TAP = "doubleTap" - LONG_PRESS = "longPress" - FORCE_PRESS = "forcePress" - KEYBOARD = "keyboard" - TOOLBAR = "toolbar" - DRAG = "drag" - SCRIBBLE = "scribble" - - -class TextSelectionChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.text: str = d.get("text") - self.cause = TextSelectionChangeCause(d.get("cause")) - start = d.get("start") - end = d.get("end") - self.selection = TextSelection( - start=start, - end=end, - selection=self.text[start:end] if (start != -1 and end != -1) else "", - base_offset=d.get("base_offset"), - extent_offset=d.get("extent_offset"), - affinity=d.get("affinity"), - directional=d.get("directional"), - collapsed=d.get("collapsed"), - valid=d.get("valid"), - normalized=d.get("normalized"), - ) - - -class Text(ConstrainedControl): - """ - Text is a control for displaying text. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Text examples" - - page.add( - ft.Text("Size 10", size=10), - ft.Text("Size 30, Italic", size=20, color="pink600", italic=True), - ft.Text("Limit long text to 2 lines and fading", style=ft.TextThemeStyle.HEADLINE_SMALL), - ft.Text( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur quis nibh vitae purus consectetur facilisis sed vitae ipsum. Quisque faucibus sed nulla placerat sagittis. Phasellus condimentum risus vitae nulla vestibulum auctor. Curabitur scelerisque, nibh eget imperdiet consequat, odio ante tempus diam, sed volutpat nisl erat eget turpis. Sed viverra, diam sit amet blandit vulputate, mi tellus dapibus lorem, vitae vehicula diam mauris placerat diam. Morbi sit amet pretium turpis, et consequat ligula. Nulla velit sem, suscipit sit amet dictum non, tincidunt sed nulla. Aenean pellentesque odio porttitor sagittis aliquam. Nam varius at metus vitae vulputate. Praesent faucibus nibh lorem, eu pretium dolor dictum nec. Phasellus eget dui laoreet, viverra magna vitae, pellentesque diam.", - max_lines=2, - ), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/text - """ - - def __init__( - self, - value: Optional[str] = None, - spans: Optional[List[TextSpan]] = None, - text_align: Optional[TextAlign] = None, - font_family: Optional[str] = None, - size: OptionalNumber = None, - weight: Optional[FontWeight] = None, - italic: Optional[bool] = None, - style: Union[TextThemeStyle, TextStyle, None] = None, - theme_style: Optional[TextThemeStyle] = None, - max_lines: Optional[int] = None, - overflow: Optional[TextOverflow] = None, - selectable: Optional[bool] = None, - no_wrap: Optional[bool] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - semantics_label: Optional[str] = None, - show_selection_cursor: Optional[bool] = None, - enable_interactive_selection: Optional[bool] = None, - selection_cursor_width: OptionalNumber = None, - selection_cursor_height: OptionalNumber = None, - selection_cursor_color: Optional[ColorValue] = None, - on_tap: OptionalControlEventCallable = None, - on_selection_change: OptionalEventCallable[TextSelectionChangeEvent] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - ) - - self.__on_selection_change = EventHandler(lambda e: TextSelectionChangeEvent(e)) - - self._add_event_handler( - "selection_change", self.__on_selection_change.get_handler() - ) - self.value = value - self.spans = spans - self.text_align = text_align - self.font_family = font_family - self.size = size - self.weight = weight - self.italic = italic - self.no_wrap = no_wrap - self.style = style - self.theme_style = theme_style - self.max_lines = max_lines - self.overflow = overflow - self.selectable = selectable - self.color = color - self.bgcolor = bgcolor - self.semantics_label = semantics_label - self.on_tap = on_tap - self.on_selection_change = on_selection_change - self.show_selection_cursor = show_selection_cursor - self.enable_interactive_selection = enable_interactive_selection - self.selection_cursor_width = selection_cursor_width - self.selection_cursor_height = selection_cursor_height - self.selection_cursor_color = selection_cursor_color - - def _get_control_name(self): - return "text" - - def _get_children(self): - return self.__spans - - def before_update(self): - super().before_update() - if isinstance(self.__style, TextStyle): - self._set_attr_json("style", self.__style) - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # spans - @property - def spans(self) -> List[TextSpan]: - return self.__spans - - @spans.setter - def spans(self, value: Optional[List[TextSpan]]): - self.__spans = value if value is not None else [] - - # text_align - @property - def text_align(self) -> Optional[TextAlign]: - return self.__text_align - - @text_align.setter - def text_align(self, value: Optional[TextAlign]): - self.__text_align = value - self._set_enum_attr("textAlign", value, TextAlign) - - # font_family - @property - def font_family(self) -> Optional[str]: - return self._get_attr("fontFamily") - - @font_family.setter - def font_family(self, value: Optional[str]): - self._set_attr("fontFamily", value) - - # size - @property - def size(self) -> OptionalNumber: - return self._get_attr("size", data_type="float") - - @size.setter - def size(self, value: OptionalNumber): - self._set_attr("size", value) - - # weight - @property - def weight(self) -> Optional[FontWeight]: - return self.__weight - - @weight.setter - def weight(self, value: Optional[FontWeight]): - self.__weight = value - self._set_enum_attr("weight", value, FontWeight) - - # style - @property - def style(self) -> Union[TextThemeStyle, TextStyle, None]: - return self.__style - - @style.setter - def style(self, value: Union[TextThemeStyle, TextStyle, None]): - self.__style = value - if isinstance(value, (TextThemeStyle, str)) or value is None: - self._set_attr( - "style", value.value if isinstance(value, TextThemeStyle) else value - ) - if value is not None: - warn( - "If you wish to set the TextThemeStyle, use `Text.theme_style` instead. " - "The `Text.style` property should be used to set the TextStyle only.", - stacklevel=2, - category=DeprecationWarning, - ) - - # theme_style - @property - def theme_style(self) -> Optional[TextThemeStyle]: - return self.__theme_style - - @theme_style.setter - def theme_style(self, value: Optional[TextThemeStyle]): - self.__theme_style = value - self._set_enum_attr("theme_style", value, TextThemeStyle) - - # italic - @property - def italic(self) -> bool: - return self._get_attr("italic", data_type="bool", def_value=False) - - @italic.setter - def italic(self, value: Optional[bool]): - self._set_attr("italic", value) - - # no_wrap - @property - def no_wrap(self) -> bool: - return self._get_attr("italic", data_type="noWrap", def_value=False) - - @no_wrap.setter - def no_wrap(self, value: Optional[bool]): - self._set_attr("noWrap", value) - - # selectable - @property - def selectable(self) -> bool: - return self._get_attr("selectable", data_type="bool", def_value=False) - - @selectable.setter - def selectable(self, value: Optional[bool]): - self._set_attr("selectable", value) - - # max_lines - @property - def max_lines(self) -> Optional[int]: - return self._get_attr("maxLines") - - @max_lines.setter - def max_lines(self, value: Optional[int]): - self._set_attr("maxLines", value) - - # overflow - @property - def overflow(self) -> Optional[TextOverflow]: - return self.__overflow - - @overflow.setter - def overflow(self, value: Optional[TextOverflow]): - self.__overflow = value - self._set_enum_attr("overflow", value, TextOverflow) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # selection_cursor_color - @property - def selection_cursor_color(self) -> Optional[str]: - return self._get_attr("selectionCursorColor") - - @selection_cursor_color.setter - def selection_cursor_color(self, value: Optional[str]): - self._set_attr("selectionCursorColor", value) - - # selection_cursor_height - @property - def selection_cursor_height(self) -> OptionalNumber: - return self._get_attr("selectionCursorHeight", data_type="float") - - @selection_cursor_height.setter - def selection_cursor_height(self, value: OptionalNumber): - self._set_attr("selectionCursorHeight", value) - - # selection_cursor_width - @property - def selection_cursor_width(self) -> OptionalNumber: - return self._get_attr("selectionCursorWidth", data_type="float", def_value=2.0) - - @selection_cursor_width.setter - def selection_cursor_width(self, value: OptionalNumber): - self._set_attr("selectionCursorWidth", value) - - # show_selection_cursor - @property - def show_selection_cursor(self) -> Optional[bool]: - return self._get_attr("showSelectionCursor", data_type="bool", def_value=False) - - @show_selection_cursor.setter - def show_selection_cursor(self, value: Optional[bool]): - self._set_attr("showSelectionCursor", value) - - # enable_interactive_selection - @property - def enable_interactive_selection(self) -> Optional[bool]: - return self._get_attr( - "enableInteractiveSelection", data_type="bool", def_value=True - ) - - @enable_interactive_selection.setter - def enable_interactive_selection(self, value: Optional[bool]): - self._set_attr("enableInteractiveSelection", value) - - # on_tap - @property - def on_tap(self) -> OptionalControlEventCallable: - return self._get_event_handler("tap") - - @on_tap.setter - def on_tap(self, handler: OptionalControlEventCallable): - self._add_event_handler("tap", handler) - - # on_selection_change - @property - def on_selection_change( - self, - ) -> OptionalEventCallable[TextSelectionChangeEvent]: - return self.__on_selection_change.handler - - @on_selection_change.setter - def on_selection_change( - self, handler: OptionalEventCallable[TextSelectionChangeEvent] - ): - self.__on_selection_change.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/text_button.py b/sdk/python/packages/flet/src/flet/core/text_button.py deleted file mode 100644 index 138f627e37..0000000000 --- a/sdk/python/packages/flet/src/flet/core/text_button.py +++ /dev/null @@ -1,298 +0,0 @@ -import time -from typing import Any, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.buttons import ButtonStyle -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ClipBehavior, - ColorEnums, - ColorValue, - IconEnums, - IconValue, - OffsetValue, - OptionalControlEventCallable, - ResponsiveNumber, - RotateValue, - ScaleValue, - UrlTarget, -) - - -class TextButton(ConstrainedControl, AdaptiveControl): - """ - Text buttons are used for the lowest priority actions, especially when presenting multiple options. Text buttons can be placed on a variety of backgrounds. Until the button is interacted with, its container isn’t visible. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.title = "Basic text buttons" - page.add( - ft.TextButton(text="Text button"), - ft.TextButton("Disabled button", disabled=True), - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/textbutton - """ - - def __init__( - self, - text: Optional[str] = None, - icon: Optional[IconValue] = None, - icon_color: Optional[ColorValue] = None, - content: Optional[Control] = None, - style: Optional[ButtonStyle] = None, - autofocus: Optional[bool] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - clip_behavior: Optional[ClipBehavior] = None, - on_click: OptionalControlEventCallable = None, - on_long_press: OptionalControlEventCallable = None, - on_hover: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - adaptive: Optional[bool] = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.text = text - self.icon = icon - self.icon_color = icon_color - self.style = style - self.content = content - self.autofocus = autofocus - self.url = url - self.url_target = url_target - self.clip_behavior = clip_behavior - self.on_click = on_click - self.on_long_press = on_long_press - self.on_hover = on_hover - self.on_focus = on_focus - self.on_blur = on_blur - - def _get_control_name(self): - return "textbutton" - - def before_update(self): - super().before_update() - if self.__style is not None: - self.__style.side = self._wrap_attr_dict(self.__style.side) - self.__style.shape = self._wrap_attr_dict(self.__style.shape) - self.__style.padding = self._wrap_attr_dict(self.__style.padding) - self._set_attr_json("style", self.__style) - - def _get_children(self): - if self.__content is None: - return [] - self.__content._set_attr_internal("n", "content") - return [self.__content] - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # icon - @property - def icon(self) -> Optional[IconValue]: - return self.__icon - - @icon.setter - def icon(self, value: Optional[IconValue]): - self.__icon = value - self._set_enum_attr("icon", value, IconEnums) - - # icon_color - @property - def icon_color(self) -> Optional[ColorValue]: - return self.__icon_color - - @icon_color.setter - def icon_color(self, value: Optional[ColorValue]): - self.__icon_color = value - self._set_enum_attr("iconColor", value, ColorEnums) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # style - @property - def style(self) -> Optional[ButtonStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[ButtonStyle]): - self.__style = value - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # on_long_press - @property - def on_long_press(self) -> OptionalControlEventCallable: - return self._get_event_handler("long_press") - - @on_long_press.setter - def on_long_press(self, handler: OptionalControlEventCallable): - self._add_event_handler("long_press", handler) - self._set_attr("onLongPress", True if handler is not None else None) - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # on_hover - @property - def on_hover(self) -> OptionalControlEventCallable: - return self._get_event_handler("hover") - - @on_hover.setter - def on_hover(self, handler: OptionalControlEventCallable): - self._add_event_handler("hover", handler) - self._set_attr("onHover", True if handler is not None else None) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) diff --git a/sdk/python/packages/flet/src/flet/core/text_span.py b/sdk/python/packages/flet/src/flet/core/text_span.py deleted file mode 100644 index b01333ff98..0000000000 --- a/sdk/python/packages/flet/src/flet/core/text_span.py +++ /dev/null @@ -1,146 +0,0 @@ -from typing import Any, List, Optional - -from flet.core.inline_span import InlineSpan -from flet.core.text_style import TextStyle -from flet.core.types import OptionalControlEventCallable, UrlTarget - - -class TextSpan(InlineSpan): - def __init__( - self, - text: Optional[str] = None, - style: Optional[TextStyle] = None, - spans: Optional[List[InlineSpan]] = None, - url: Optional[str] = None, - url_target: Optional[UrlTarget] = None, - semantics_label: Optional[str] = None, - spell_out: Optional[bool] = None, - on_click: OptionalControlEventCallable = None, - on_enter: OptionalControlEventCallable = None, - on_exit: OptionalControlEventCallable = None, - # - # Control - # - ref=None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - InlineSpan.__init__( - self, ref=ref, visible=visible, disabled=disabled, data=data - ) - - self.text = text - self.style = style - self.spans = spans - self.url = url - self.url_target = url_target - self.semantics_label = semantics_label - self.spell_out = spell_out - self.on_click = on_click - self.on_enter = on_enter - self.on_exit = on_exit - - def _get_control_name(self): - return "textspan" - - def _get_children(self): - return self.__spans - - def before_update(self): - super().before_update() - self._set_attr_json("style", self.__style) - - # text - @property - def text(self) -> Optional[str]: - return self._get_attr("text") - - @text.setter - def text(self, value: Optional[str]): - self._set_attr("text", value) - - # semantics_label - @property - def semantics_label(self) -> Optional[str]: - return self._get_attr("semanticsLabel") - - @semantics_label.setter - def semantics_label(self, value: Optional[str]): - self._set_attr("semanticsLabel", value) - - # spell_out - @property - def spell_out(self) -> Optional[bool]: - return self._get_attr("spellOut") - - @spell_out.setter - def spell_out(self, value: Optional[bool]): - self._set_attr("spellOut", value) - - # style - @property - def style(self) -> Optional[TextStyle]: - return self.__style - - @style.setter - def style(self, value: Optional[TextStyle]): - self.__style = value - - # spans - @property - def spans(self) -> List[InlineSpan]: - return self.__spans - - @spans.setter - def spans(self, value: Optional[List[InlineSpan]]): - self.__spans = value if value is not None else [] - - # url - @property - def url(self) -> Optional[str]: - return self._get_attr("url") - - @url.setter - def url(self, value: Optional[str]): - self._set_attr("url", value) - - # url_target - @property - def url_target(self) -> Optional[UrlTarget]: - return self.__url_target - - @url_target.setter - def url_target(self, value: Optional[UrlTarget]): - self.__url_target = value - self._set_enum_attr("urlTarget", value, UrlTarget) - - # on_click - @property - def on_click(self) -> OptionalControlEventCallable: - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - self._set_attr("onClick", True if handler is not None else None) - - # on_enter - @property - def on_enter(self) -> OptionalControlEventCallable: - return self._get_event_handler("enter") - - @on_enter.setter - def on_enter(self, handler: OptionalControlEventCallable): - self._add_event_handler("enter", handler) - self._set_attr("onEnter", True if handler is not None else None) - - # on_exit - @property - def on_exit(self) -> OptionalControlEventCallable: - return self._get_event_handler("exit") - - @on_exit.setter - def on_exit(self, handler: OptionalControlEventCallable): - self._add_event_handler("exit", handler) - self._set_attr("onExit", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/text_style.py b/sdk/python/packages/flet/src/flet/core/text_style.py deleted file mode 100644 index 0e309af80f..0000000000 --- a/sdk/python/packages/flet/src/flet/core/text_style.py +++ /dev/null @@ -1,84 +0,0 @@ -from dataclasses import dataclass -from enum import Enum, IntFlag -from typing import List, Optional, Union - -from flet.core.box import BoxShadow -from flet.core.painting import Paint -from flet.core.types import ColorValue, FontWeight, OptionalNumber - - -class TextOverflow(Enum): - CLIP = "clip" - ELLIPSIS = "ellipsis" - FADE = "fade" - VISIBLE = "visible" - - -class TextBaseline(Enum): - ALPHABETIC = "alphabetic" - IDEOGRAPHIC = "ideographic" - - -class TextThemeStyle(Enum): - DISPLAY_LARGE = "displayLarge" - DISPLAY_MEDIUM = "displayMedium" - DISPLAY_SMALL = "displaySmall" - HEADLINE_LARGE = "headlineLarge" - HEADLINE_MEDIUM = "headlineMedium" - HEADLINE_SMALL = "headlineSmall" - TITLE_LARGE = "titleLarge" - TITLE_MEDIUM = "titleMedium" - TITLE_SMALL = "titleSmall" - LABEL_LARGE = "labelLarge" - LABEL_MEDIUM = "labelMedium" - LABEL_SMALL = "labelSmall" - BODY_LARGE = "bodyLarge" - BODY_MEDIUM = "bodyMedium" - BODY_SMALL = "bodySmall" - - -class TextDecoration(IntFlag): - NONE = 0 - UNDERLINE = 1 - OVERLINE = 2 - LINE_THROUGH = 4 - - -class TextDecorationStyle(Enum): - SOLID = "solid" - DOUBLE = "double" - DOTTED = "dotted" - DASHED = "dashed" - WAVY = "wavy" - - -@dataclass -class TextStyle: - size: OptionalNumber = None - height: OptionalNumber = None - weight: Optional[FontWeight] = None - italic: Optional[bool] = None - decoration: Optional[TextDecoration] = None - decoration_color: Optional[ColorValue] = None - decoration_thickness: OptionalNumber = None - decoration_style: Optional[TextDecorationStyle] = None - font_family: Optional[str] = None - color: Optional[ColorValue] = None - bgcolor: Optional[ColorValue] = None - shadow: Union[None, BoxShadow, List[BoxShadow]] = None - foreground: Optional[Paint] = None - letter_spacing: OptionalNumber = None - word_spacing: OptionalNumber = None - overflow: Optional[TextOverflow] = None - baseline: Optional[TextBaseline] = None - - -@dataclass -class StrutStyle: - size: OptionalNumber = None - height: OptionalNumber = None - weight: Optional[FontWeight] = None - italic: Optional[bool] = None - font_family: Optional[str] = None - leading: OptionalNumber = None - force_strut_height: Optional[bool] = None diff --git a/sdk/python/packages/flet/src/flet/core/textfield.py b/sdk/python/packages/flet/src/flet/core/textfield.py deleted file mode 100644 index db24c94e56..0000000000 --- a/sdk/python/packages/flet/src/flet/core/textfield.py +++ /dev/null @@ -1,839 +0,0 @@ -import dataclasses -import time -from enum import Enum -from typing import Any, List, Optional, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.animation import AnimationValue -from flet.core.autofill_group import AutofillHint -from flet.core.badge import BadgeValue -from flet.core.box import BoxConstraints -from flet.core.control import Control, OptionalNumber -from flet.core.form_field_control import FormFieldControl, InputBorder -from flet.core.ref import Ref -from flet.core.text_style import StrutStyle, TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - BorderRadiusValue, - Brightness, - ClipBehavior, - ColorEnums, - ColorValue, - DurationValue, - IconValueOrControl, - MouseCursor, - OffsetValue, - OptionalControlEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - TextAlign, - VerticalAlignment, -) - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class KeyboardType(Enum): - NONE = "none" - TEXT = "text" - MULTILINE = "multiline" - NUMBER = "number" - PHONE = "phone" - DATETIME = "datetime" - EMAIL = "email" - URL = "url" - VISIBLE_PASSWORD = "visiblePassword" - NAME = "name" - STREET_ADDRESS = "streetAddress" - - -class TextCapitalization(Enum): - CHARACTERS = "characters" - WORDS = "words" - SENTENCES = "sentences" - - -@dataclasses.dataclass -class InputFilter: - regex_string: str - allow: bool = True - replacement_string: str = "" - multiline: bool = False - case_sensitive: bool = True - unicode: bool = False - dot_all: bool = False - - -class NumbersOnlyInputFilter(InputFilter): - def __init__(self): - super().__init__(regex_string=r"^[0-9]*$", allow=True, replacement_string="") - - -class TextOnlyInputFilter(InputFilter): - def __init__(self): - super().__init__(regex_string=r"^[a-zA-Z]*$", allow=True, replacement_string="") - - -class TextField(FormFieldControl, AdaptiveControl): - """ - A text field lets the user enter text, either with hardware keyboard or with an onscreen keyboard. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - def button_clicked(e): - t.value = f"Textboxes values are: '{tb1.value}', '{tb2.value}', '{tb3.value}', '{tb4.value}', '{tb5.value}'." - page.update() - - t = ft.Text() - tb1 = ft.TextField(label="Standard") - tb2 = ft.TextField(label="Disabled", disabled=True, value="First name") - tb3 = ft.TextField(label="Read-only", read_only=True, value="Last name") - tb4 = ft.TextField(label="With placeholder", hint_text="Please enter text here") - tb5 = ft.TextField(label="With an icon", icon=ft.icons.EMOJI_EMOTIONS) - b = ft.ElevatedButton(text="Submit", on_click=button_clicked) - page.add(tb1, tb2, tb3, tb4, tb5, b, t) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/textfield - """ - - def __init__( - self, - value: Optional[str] = None, - keyboard_type: Optional[KeyboardType] = None, - multiline: Optional[bool] = None, - min_lines: Optional[int] = None, - max_lines: Optional[int] = None, - max_length: Optional[int] = None, - password: Optional[bool] = None, - can_reveal_password: Optional[bool] = None, - read_only: Optional[bool] = None, - shift_enter: Optional[bool] = None, - text_align: Optional[TextAlign] = None, - autofocus: Optional[bool] = None, - capitalization: Optional[TextCapitalization] = None, - autocorrect: Optional[bool] = None, - enable_suggestions: Optional[bool] = None, - smart_dashes_type: Optional[bool] = None, - smart_quotes_type: Optional[bool] = None, - show_cursor: Optional[bool] = None, - cursor_color: Optional[ColorValue] = None, - cursor_error_color: Optional[ColorValue] = None, - cursor_width: OptionalNumber = None, - cursor_height: OptionalNumber = None, - cursor_radius: OptionalNumber = None, - selection_color: Optional[ColorValue] = None, - input_filter: Optional[InputFilter] = None, - obscuring_character: Optional[str] = None, - enable_interactive_selection: Optional[bool] = None, - enable_ime_personalized_learning: Optional[bool] = None, - can_request_focus: Optional[bool] = None, - ignore_pointers: Optional[bool] = None, - enable_scribble: Optional[bool] = None, - animate_cursor_opacity: Optional[bool] = None, - always_call_on_tap: Optional[bool] = None, - scroll_padding: Optional[PaddingValue] = None, - clip_behavior: Optional[ClipBehavior] = None, - keyboard_brightness: Optional[Brightness] = None, - mouse_cursor: Optional[MouseCursor] = None, - strut_style: Optional[StrutStyle] = None, - autofill_hints: Union[None, AutofillHint, List[AutofillHint]] = None, - on_change: OptionalControlEventCallable = None, - on_click: OptionalControlEventCallable = None, - on_submit: OptionalControlEventCallable = None, - on_focus: OptionalControlEventCallable = None, - on_blur: OptionalControlEventCallable = None, - on_tap_outside: OptionalControlEventCallable = None, - # - # FormField - # - text_size: OptionalNumber = None, - text_style: Optional[TextStyle] = None, - text_vertical_align: Union[VerticalAlignment, OptionalNumber] = None, - label: Optional[Union[str, Control]] = None, - label_style: Optional[TextStyle] = None, - icon: Optional[IconValueOrControl] = None, - border: Optional[InputBorder] = None, - color: Optional[ColorValue] = None, - bgcolor: Optional[ColorValue] = None, - border_radius: Optional[BorderRadiusValue] = None, - border_width: OptionalNumber = None, - border_color: Optional[ColorValue] = None, - focused_color: Optional[ColorValue] = None, - focused_bgcolor: Optional[ColorValue] = None, - focused_border_width: OptionalNumber = None, - focused_border_color: Optional[ColorValue] = None, - content_padding: Optional[PaddingValue] = None, - dense: Optional[bool] = None, - filled: Optional[bool] = None, - fill_color: Optional[ColorValue] = None, - hover_color: Optional[ColorValue] = None, - hint_text: Optional[str] = None, - hint_style: Optional[TextStyle] = None, - helper: Optional[Control] = None, - helper_text: Optional[str] = None, - helper_style: Optional[TextStyle] = None, - counter: Optional[Control] = None, - counter_text: Optional[str] = None, - counter_style: Optional[TextStyle] = None, - error: Optional[Control] = None, - error_text: Optional[str] = None, - error_style: Optional[TextStyle] = None, - prefix: Optional[Control] = None, - prefix_icon: Optional[IconValueOrControl] = None, - prefix_text: Optional[str] = None, - prefix_style: Optional[TextStyle] = None, - suffix: Optional[Control] = None, - suffix_icon: Optional[IconValueOrControl] = None, - suffix_text: Optional[str] = None, - suffix_style: Optional[TextStyle] = None, - focus_color: Optional[ColorValue] = None, - align_label_with_hint: Optional[bool] = None, - hint_fade_duration: Optional[DurationValue] = None, - hint_max_lines: Optional[int] = None, - helper_max_lines: Optional[int] = None, - error_max_lines: Optional[int] = None, - prefix_icon_size_constraints: Optional[BoxConstraints] = None, - suffix_icon_size_constraints: Optional[BoxConstraints] = None, - size_constraints: Optional[BoxConstraints] = None, - collapsed: Optional[bool] = None, - fit_parent_size: Optional[bool] = None, - # - # ConstrainedControl and AdaptiveControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - rtl: Optional[bool] = None, - adaptive: Optional[bool] = None, - ): - FormFieldControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - rtl=rtl, - # - # FormField - # - text_size=text_size, - text_style=text_style, - text_vertical_align=text_vertical_align, - label=label, - label_style=label_style, - icon=icon, - border=border, - color=color, - bgcolor=bgcolor, - border_radius=border_radius, - border_width=border_width, - border_color=border_color, - focused_color=focused_color, - focused_bgcolor=focused_bgcolor, - focused_border_width=focused_border_width, - focused_border_color=focused_border_color, - content_padding=content_padding, - dense=dense, - filled=filled, - fill_color=fill_color, - hover_color=hover_color, - hint_text=hint_text, - hint_style=hint_style, - helper=helper, - helper_text=helper_text, - helper_style=helper_style, - counter=counter, - counter_text=counter_text, - counter_style=counter_style, - error=error, - error_text=error_text, - error_style=error_style, - prefix=prefix, - prefix_icon=prefix_icon, - prefix_text=prefix_text, - prefix_style=prefix_style, - suffix=suffix, - suffix_icon=suffix_icon, - suffix_text=suffix_text, - suffix_style=suffix_style, - focus_color=focus_color, - align_label_with_hint=align_label_with_hint, - hint_fade_duration=hint_fade_duration, - hint_max_lines=hint_max_lines, - helper_max_lines=helper_max_lines, - error_max_lines=error_max_lines, - prefix_icon_size_constraints=prefix_icon_size_constraints, - suffix_icon_size_constraints=suffix_icon_size_constraints, - size_constraints=size_constraints, - collapsed=collapsed, - fit_parent_size=fit_parent_size, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.value = value - self.text_style = text_style - self.keyboard_type = keyboard_type - self.text_align = text_align - self.multiline = multiline - self.min_lines = min_lines - self.max_lines = max_lines - self.max_length = max_length - self.read_only = read_only - self.shift_enter = shift_enter - self.password = password - self.can_reveal_password = can_reveal_password - self.autofocus = autofocus - self.capitalization = capitalization - self.autocorrect = autocorrect - self.show_cursor = show_cursor - self.enable_suggestions = enable_suggestions - self.smart_dashes_type = smart_dashes_type - self.smart_quotes_type = smart_quotes_type - self.cursor_color = cursor_color - self.cursor_height = cursor_height - self.cursor_width = cursor_width - self.cursor_radius = cursor_radius - self.selection_color = selection_color - self.input_filter = input_filter - self.autofill_hints = autofill_hints - self.on_change = on_change - self.on_submit = on_submit - self.on_focus = on_focus - self.on_blur = on_blur - self.on_click = on_click - self.obscuring_character = obscuring_character - self.enable_scribble = enable_scribble - self.strut_style = strut_style - self.scroll_padding = scroll_padding - self.cursor_error_color = cursor_error_color - self.keyboard_brightness = keyboard_brightness - self.mouse_cursor = mouse_cursor - self.enable_interactive_selection = enable_interactive_selection - self.enable_ime_personalized_learning = enable_ime_personalized_learning - self.can_request_focus = can_request_focus - self.ignore_pointers = ignore_pointers - self.animate_cursor_opacity = animate_cursor_opacity - self.always_call_on_tap = always_call_on_tap - self.clip_behavior = clip_behavior - self.on_tap_outside = on_tap_outside - - def _get_control_name(self): - return "textfield" - - def before_update(self): - super().before_update() - assert ( - self.max_lines is None - or self.min_lines is None - or self.min_lines <= self.max_lines - ), "min_lines can't be greater than max_lines" - self._set_attr_json("inputFilter", self.__input_filter) - self._set_attr_json("autofillHints", self.__autofill_hints) - self._set_attr_json("scrollPadding", self.__scroll_padding) - self._set_attr_json("strutStyle", self.__strut_style) - if ( - ( - self.bgcolor is not None - or self.fill_color is not None - or self.hover_color is not None - or self.focused_color is not None - ) - ) and self.filled is None: - self.filled = True # required to display any of the above colors - - def focus(self): - self._set_attr_json("focus", str(time.time())) - self.update() - - def blur(self): - self._set_attr_json("blur", str(time.time())) - self.update() - - # value - @property - def value(self) -> Optional[str]: - return self._get_attr("value", def_value="") - - @value.setter - def value(self, value: Optional[str]): - self._set_attr("value", value) - - # strut_style - @property - def strut_style(self) -> Optional[TextStyle]: - return self.__strut_style - - @strut_style.setter - def strut_style(self, value: Optional[TextStyle]): - self.__strut_style = value - - # cursor_error_color - @property - def cursor_error_color(self) -> Optional[str]: - return self._get_attr("cursorErrorColor") - - @cursor_error_color.setter - def cursor_error_color(self, value: Optional[str]): - self._set_attr("cursorErrorColor", value) - - # enable_interactive_selection - @property - def enable_interactive_selection(self) -> bool: - return self._get_attr( - "enableInteractiveSelection", data_type="bool", def_value=True - ) - - @enable_interactive_selection.setter - def enable_interactive_selection(self, value: Optional[bool]): - self._set_attr("enableInteractiveSelection", value) - - # enable_ime_personalized_learning - @property - def enable_ime_personalized_learning(self) -> bool: - return self._get_attr( - "enableIMEPersonalizedLearning", data_type="bool", def_value=True - ) - - @enable_ime_personalized_learning.setter - def enable_ime_personalized_learning(self, value: Optional[bool]): - self._set_attr("enableIMEPersonalizedLearning", value) - - # animate_cursor_opacity - @property - def animate_cursor_opacity(self) -> Optional[bool]: - return self._get_attr("animateCursorOpacity", data_type="bool") - - @animate_cursor_opacity.setter - def animate_cursor_opacity(self, value: Optional[bool]): - self._set_attr("animateCursorOpacity", value) - - # keyboard_type - @property - def keyboard_type(self) -> Optional[KeyboardType]: - return self.__keyboard_type - - @keyboard_type.setter - def keyboard_type(self, value: Optional[KeyboardType]): - self.__keyboard_type = value - self._set_enum_attr("keyboardType", value, KeyboardType) - - # text_align - @property - def text_align(self) -> Optional[TextAlign]: - return self.__text_align - - @text_align.setter - def text_align(self, value: Optional[TextAlign]): - self.__text_align = value - self._set_enum_attr("textAlign", value, TextAlign) - - # multiline - @property - def multiline(self) -> bool: - return self._get_attr("multiline", data_type="bool", def_value=False) - - @multiline.setter - def multiline(self, value: Optional[bool]): - self._set_attr("multiline", value) - - # min_lines - @property - def min_lines(self) -> Optional[int]: - return self._get_attr("minLines") - - @min_lines.setter - def min_lines(self, value: Optional[int]): - assert value is None or value > 0, "min_lines must be greater than 0" - self._set_attr("minLines", value) - - # max_lines - @property - def max_lines(self) -> Optional[int]: - return self._get_attr("maxLines") - - @max_lines.setter - def max_lines(self, value: Optional[int]): - assert value is None or value > 0, "max_lines must be greater than 0" - self._set_attr("maxLines", value) - - # max_length - @property - def max_length(self) -> Optional[int]: - return self._get_attr("maxLength") - - @max_length.setter - def max_length(self, value: Optional[int]): - assert ( - value is None or value == -1 or value > 0 - ), "max_length must be either equal to -1 or greater than 0" - self._set_attr("maxLength", value) - - # obscuring_character - @property - def obscuring_character(self) -> Optional[str]: - return self._get_attr("obscuringCharacter", def_value="•") - - @obscuring_character.setter - def obscuring_character(self, value: Optional[str]): - self._set_attr("obscuringCharacter", value) - - # enable_scribble - @property - def enable_scribble(self) -> bool: - return self._get_attr("enableScribble", data_type="bool", def_value=True) - - @enable_scribble.setter - def enable_scribble(self, value: Optional[bool]): - self._set_attr("enableScribble", value) - - # scroll_padding - @property - def scroll_padding(self) -> Optional[PaddingValue]: - return self.__scroll_padding - - @scroll_padding.setter - def scroll_padding(self, value: Optional[PaddingValue]): - self.__scroll_padding = value - - # keyboard_brightness - @property - def keyboard_brightness(self) -> Optional[Brightness]: - return self.__keyboard_brightness - - @keyboard_brightness.setter - def keyboard_brightness(self, value: Optional[Brightness]): - self.__keyboard_brightness = value - self._set_enum_attr("keyboardBrightness", value, Brightness) - - # mouse_cursor - @property - def mouse_cursor(self) -> Optional[MouseCursor]: - return self.__mouse_cursor - - @mouse_cursor.setter - def mouse_cursor(self, value: Optional[MouseCursor]): - self.__mouse_cursor = value - self._set_enum_attr("mouseCursor", value, MouseCursor) - - # ignore_pointers - @property - def ignore_pointers(self) -> bool: - return self._get_attr("ignorePointers", data_type="bool", def_value=False) - - @ignore_pointers.setter - def ignore_pointers(self, value: Optional[bool]): - self._set_attr("ignorePointers", value) - - # clip_behavior - @property - def clip_behavior(self) -> Optional[ClipBehavior]: - return self.__clip_behavior - - @clip_behavior.setter - def clip_behavior(self, value: Optional[ClipBehavior]): - self.__clip_behavior = value - self._set_enum_attr("clipBehavior", value, ClipBehavior) - - # can_request_focus - @property - def can_request_focus(self) -> bool: - return self._get_attr("canRequestFocus", data_type="bool", def_value=True) - - @can_request_focus.setter - def can_request_focus(self, value: Optional[bool]): - self._set_attr("canRequestFocus", value) - - # always_call_on_tap - @property - def always_call_on_tap(self) -> bool: - return self._get_attr("alwaysCallOnTap", data_type="bool", def_value=False) - - @always_call_on_tap.setter - def always_call_on_tap(self, value: Optional[bool]): - self._set_attr("alwaysCallOnTap", value) - - # read_only - @property - def read_only(self) -> bool: - return self._get_attr("readOnly", data_type="bool", def_value=False) - - @read_only.setter - def read_only(self, value: Optional[bool]): - self._set_attr("readOnly", value) - - # shift_enter - @property - def shift_enter(self) -> bool: - return self._get_attr("shiftEnter", data_type="bool", def_value=False) - - @shift_enter.setter - def shift_enter(self, value: Optional[bool]): - self._set_attr("shiftEnter", value) - - # password - @property - def password(self) -> bool: - return self._get_attr("password", data_type="bool", def_value=False) - - @password.setter - def password(self, value: Optional[bool]): - self._set_attr("password", value) - - # can_reveal_password - @property - def can_reveal_password(self) -> bool: - return self._get_attr("canRevealPassword", data_type="bool", def_value=False) - - @can_reveal_password.setter - def can_reveal_password(self, value: Optional[bool]): - self._set_attr("canRevealPassword", value) - - # autofocus - @property - def autofocus(self) -> bool: - return self._get_attr("autofocus", data_type="bool", def_value=False) - - @autofocus.setter - def autofocus(self, value: Optional[bool]): - self._set_attr("autofocus", value) - - # capitalization - @property - def capitalization(self) -> Optional[TextCapitalization]: - return self.__capitalization - - @capitalization.setter - def capitalization(self, value: Optional[TextCapitalization]): - self.__capitalization = value - self._set_enum_attr("capitalization", value, TextCapitalization) - - # autocorrect - @property - def autocorrect(self) -> bool: - return self._get_attr("autocorrect", data_type="bool", def_value=True) - - @autocorrect.setter - def autocorrect(self, value: Optional[bool]): - self._set_attr("autocorrect", value) - - # show_cursor - @property - def show_cursor(self) -> bool: - return self._get_attr("showCursor", data_type="bool", def_value=True) - - @show_cursor.setter - def show_cursor(self, value: Optional[bool]): - self._set_attr("showCursor", value) - - # enable_suggestions - @property - def enable_suggestions(self) -> bool: - return self._get_attr("enableSuggestions", data_type="bool", def_value=True) - - @enable_suggestions.setter - def enable_suggestions(self, value: Optional[bool]): - self._set_attr("enableSuggestions", value) - - # smart_dashes_type - @property - def smart_dashes_type(self) -> bool: - return self._get_attr("smartDashesType", data_type="bool", def_value=True) - - @smart_dashes_type.setter - def smart_dashes_type(self, value: Optional[bool]): - self._set_attr("smartDashesType", value) - - # smart_quotes_type - @property - def smart_quotes_type(self) -> bool: - return self._get_attr("smartQuotesType", data_type="bool", def_value=True) - - @smart_quotes_type.setter - def smart_quotes_type(self, value: Optional[bool]): - self._set_attr("smartQuotesType", value) - - # cursor_color - @property - def cursor_color(self): - return self.__cursor_color - - @cursor_color.setter - def cursor_color(self, value): - self.__cursor_color = value - self._set_enum_attr("cursorColor", value, ColorEnums) - - # cursor_height - @property - def cursor_height(self) -> OptionalNumber: - return self._get_attr("cursorHeight") - - @cursor_height.setter - def cursor_height(self, value: OptionalNumber): - self._set_attr("cursorHeight", value) - - # cursor_width - @property - def cursor_width(self) -> OptionalNumber: - return self._get_attr("cursorWidth") - - @cursor_width.setter - def cursor_width(self, value: OptionalNumber): - self._set_attr("cursorWidth", value) - - # cursor_radius - @property - def cursor_radius(self) -> OptionalNumber: - return self._get_attr("cursorRadius") - - @cursor_radius.setter - def cursor_radius(self, value: OptionalNumber): - self._set_attr("cursorRadius", value) - - # selection_color - @property - def selection_color(self) -> Optional[ColorValue]: - return self.__selection_color - - @selection_color.setter - def selection_color(self, value: Optional[ColorValue]): - self.__selection_color = value - self._set_enum_attr("selectionColor", value, ColorEnums) - - # input_filter - @property - def input_filter(self) -> Optional[InputFilter]: - return self.__input_filter - - @input_filter.setter - def input_filter(self, value: Optional[InputFilter]): - self.__input_filter = value - - # autofill_hints - @property - def autofill_hints(self) -> Union[None, AutofillHint, List[AutofillHint]]: - return self.__autofill_hints - - @autofill_hints.setter - def autofill_hints(self, value: Union[None, AutofillHint, List[AutofillHint]]): - if value is not None: - if isinstance(value, List): - value = list( - map( - lambda x: x.value if isinstance(x, AutofillHint) else str(x), - value, - ) - ) - elif isinstance(value, AutofillHint): - value = value.value - self.__autofill_hints = value - - # on_change - @property - def on_change(self): - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - self._set_attr("onChange", True if handler is not None else None) - - # on_submit - @property - def on_submit(self) -> OptionalControlEventCallable: - return self._get_event_handler("submit") - - @on_submit.setter - def on_submit(self, handler: OptionalControlEventCallable): - self._add_event_handler("submit", handler) - - # on_focus - @property - def on_focus(self) -> OptionalControlEventCallable: - return self._get_event_handler("focus") - - @on_focus.setter - def on_focus(self, handler: OptionalControlEventCallable): - self._add_event_handler("focus", handler) - - # on_blur - @property - def on_blur(self) -> OptionalControlEventCallable: - return self._get_event_handler("blur") - - @on_blur.setter - def on_blur(self, handler: OptionalControlEventCallable): - self._add_event_handler("blur", handler) - - # on_click - @property - def on_click(self): - return self._get_event_handler("click") - - @on_click.setter - def on_click(self, handler: OptionalControlEventCallable): - self._add_event_handler("click", handler) - - # on_tap_outside - @property - def on_tap_outside(self) -> OptionalControlEventCallable: - return self._get_event_handler("tapOutside") - - @on_tap_outside.setter - def on_tap_outside(self, handler: OptionalControlEventCallable): - self._add_event_handler("tapOutside", handler) - self._set_attr("onTapOutside", True if handler is not None else None) diff --git a/sdk/python/packages/flet/src/flet/core/theme.py b/sdk/python/packages/flet/src/flet/core/theme.py deleted file mode 100644 index 804aae0c70..0000000000 --- a/sdk/python/packages/flet/src/flet/core/theme.py +++ /dev/null @@ -1,1045 +0,0 @@ -from dataclasses import dataclass, field -from enum import Enum -from typing import List, Optional, Union - -from flet.core.alignment import Alignment -from flet.core.border import BorderSide -from flet.core.border_radius import BorderRadius -from flet.core.box import BoxConstraints, BoxDecoration, BoxShadow -from flet.core.buttons import ButtonStyle, OutlinedBorder -from flet.core.menu_bar import MenuStyle -from flet.core.navigation_bar import NavigationBarLabelBehavior -from flet.core.navigation_rail import NavigationRailLabelType -from flet.core.popup_menu_button import PopupMenuPosition -from flet.core.size import Size -from flet.core.slider import SliderInteraction -from flet.core.snack_bar import DismissDirection, SnackBarBehavior -from flet.core.text_style import TextStyle -from flet.core.textfield import TextCapitalization -from flet.core.tooltip import TooltipTriggerMode -from flet.core.types import ( - Brightness, - ClipBehavior, - ColorValue, - ControlState, - ControlStateValue, - DurationValue, - IconValue, - Locale, - MainAxisAlignment, - MarginValue, - MouseCursor, - NotchShape, - OffsetValue, - OptionalNumber, - PaddingValue, - StrokeCap, - TextAlign, - VisualDensity, -) -from flet.utils.deprecated import deprecated_class, deprecated_property - -try: - from typing import Literal -except ImportError: - from typing_extensions import Literal - - -class PageTransitionTheme(Enum): - NONE = "none" - FADE_UPWARDS = "fadeUpwards" - OPEN_UPWARDS = "openUpwards" - ZOOM = "zoom" - CUPERTINO = "cupertino" - PREDICTIVE = "predictive" - FADE_FORWARDS = "fadeForwards" - - -@dataclass -class PageTransitionsTheme: - android: Optional[PageTransitionTheme] = None - ios: Optional[PageTransitionTheme] = None - linux: Optional[PageTransitionTheme] = None - macos: Optional[PageTransitionTheme] = None - windows: Optional[PageTransitionTheme] = None - - -@dataclass -class ColorScheme: - primary: Optional[ColorValue] = None - on_primary: Optional[ColorValue] = None - primary_container: Optional[ColorValue] = None - on_primary_container: Optional[ColorValue] = None - secondary: Optional[ColorValue] = None - on_secondary: Optional[ColorValue] = None - secondary_container: Optional[ColorValue] = None - on_secondary_container: Optional[ColorValue] = None - tertiary: Optional[ColorValue] = None - on_tertiary: Optional[ColorValue] = None - tertiary_container: Optional[ColorValue] = None - on_tertiary_container: Optional[ColorValue] = None - error: Optional[ColorValue] = None - on_error: Optional[ColorValue] = None - error_container: Optional[ColorValue] = None - on_error_container: Optional[ColorValue] = None - background: Optional[ColorValue] = None - on_background: Optional[ColorValue] = None - surface: Optional[ColorValue] = None - on_surface: Optional[ColorValue] = None - surface_variant: Optional[ColorValue] = None - on_surface_variant: Optional[ColorValue] = None - outline: Optional[ColorValue] = None - outline_variant: Optional[ColorValue] = None - shadow: Optional[ColorValue] = None - scrim: Optional[ColorValue] = None - inverse_surface: Optional[ColorValue] = None - on_inverse_surface: Optional[ColorValue] = None - inverse_primary: Optional[ColorValue] = None - surface_tint: Optional[ColorValue] = None - on_primary_fixed: Optional[ColorValue] = None - on_secondary_fixed: Optional[ColorValue] = None - on_tertiary_fixed: Optional[ColorValue] = None - on_primary_fixed_variant: Optional[ColorValue] = None - on_secondary_fixed_variant: Optional[ColorValue] = None - on_tertiary_fixed_variant: Optional[ColorValue] = None - primary_fixed: Optional[ColorValue] = None - secondary_fixed: Optional[ColorValue] = None - tertiary_fixed: Optional[ColorValue] = None - primary_fixed_dim: Optional[ColorValue] = None - secondary_fixed_dim: Optional[ColorValue] = None - surface_bright: Optional[ColorValue] = None - surface_container: Optional[ColorValue] = None - surface_container_high: Optional[ColorValue] = None - surface_container_low: Optional[ColorValue] = None - surface_container_lowest: Optional[ColorValue] = None - surface_dim: Optional[ColorValue] = None - tertiary_fixed_dim: Optional[ColorValue] = None - - -@dataclass -class TextTheme: - body_large: Optional[TextStyle] = None - body_medium: Optional[TextStyle] = None - body_small: Optional[TextStyle] = None - display_large: Optional[TextStyle] = None - display_medium: Optional[TextStyle] = None - display_small: Optional[TextStyle] = None - headline_large: Optional[TextStyle] = None - headline_medium: Optional[TextStyle] = None - headline_small: Optional[TextStyle] = None - label_large: Optional[TextStyle] = None - label_medium: Optional[TextStyle] = None - label_small: Optional[TextStyle] = None - title_large: Optional[TextStyle] = None - title_medium: Optional[TextStyle] = None - title_small: Optional[TextStyle] = None - - -@dataclass -class ScrollbarTheme: - thumb_visibility: ControlStateValue[bool] = None - thickness: ControlStateValue[OptionalNumber] = None - track_visibility: ControlStateValue[bool] = None - radius: Optional[float] = None - thumb_color: ControlStateValue[ColorValue] = None - track_color: ControlStateValue[ColorValue] = None - track_border_color: ControlStateValue[ColorValue] = None - cross_axis_margin: Optional[float] = None - main_axis_margin: Optional[float] = None - min_thumb_length: Optional[float] = None - interactive: Optional[bool] = None - - def __post_init__(self): - if not isinstance(self.thumb_visibility, dict): - self.thumb_visibility = {ControlState.DEFAULT: self.thumb_visibility} - if not isinstance(self.thickness, dict): - self.thickness = {ControlState.DEFAULT: self.thickness} - if not isinstance(self.track_visibility, dict): - self.track_visibility = {ControlState.DEFAULT: self.track_visibility} - if not isinstance(self.thumb_color, dict): - self.thumb_color = {ControlState.DEFAULT: self.thumb_color} - if not isinstance(self.track_color, dict): - self.track_color = {ControlState.DEFAULT: self.track_color} - if not isinstance(self.track_border_color, dict): - self.track_border_color = {ControlState.DEFAULT: self.track_border_color} - - -@dataclass -class TabsTheme: - divider_color: Optional[ColorValue] = None - indicator_border_radius: Optional[BorderRadius] = None - indicator_border_side: Optional[BorderSide] = None - indicator_padding: Optional[PaddingValue] = None - indicator_color: Optional[ColorValue] = None - indicator_tab_size: Optional[bool] = None - label_color: Optional[ColorValue] = None - unselected_label_color: Optional[ColorValue] = None - overlay_color: ControlStateValue[ColorValue] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - label_padding: Optional[PaddingValue] = None - label_text_style: Optional[TextStyle] = None - unselected_label_text_style: Optional[TextStyle] = None - - def __post_init__(self): - if not isinstance(self.overlay_color, dict): - self.overlay_color = {ControlState.DEFAULT: self.overlay_color} - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - - -@dataclass -class SystemOverlayStyle: - status_bar_color: Optional[ColorValue] = None - system_navigation_bar_color: Optional[ColorValue] = None - system_navigation_bar_divider_color: Optional[ColorValue] = None - enforce_system_navigation_bar_contrast: Optional[bool] = None - enforce_system_status_bar_contrast: Optional[bool] = None - system_navigation_bar_icon_brightness: Optional[Brightness] = None - status_bar_brightness: Optional[Brightness] = None - status_bar_icon_brightness: Optional[Brightness] = None - - -@dataclass -class DialogTheme: - bgcolor: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - icon_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - title_text_style: Optional[TextStyle] = None - content_text_style: Optional[TextStyle] = None - alignment: Optional[Alignment] = None - actions_padding: Optional[PaddingValue] = None - clip_behavior: Optional[ClipBehavior] = None - barrier_color: Optional[ColorValue] = None - inset_padding: Optional[PaddingValue] = None - - -@dataclass -class ElevatedButtonTheme: - bgcolor: Optional[ColorValue] = None - foreground_color: Optional[ColorValue] = None - icon_color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - disabled_bgcolor: Optional[ColorValue] = None - disabled_foreground_color: Optional[ColorValue] = None - disabled_icon_color: Optional[ColorValue] = None - overlay_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - padding: Optional[PaddingValue] = None - enable_feedback: Optional[bool] = None - disabled_mouse_cursor: Optional[MouseCursor] = None - enabled_mouse_cursor: Optional[MouseCursor] = None - shape: Optional[OutlinedBorder] = None - text_style: Optional[TextStyle] = None - visual_density: Optional[VisualDensity] = None - border_side: Optional[BorderSide] = None - animation_duration: Optional[DurationValue] = None - alignment: Optional[Alignment] = None - icon_size: OptionalNumber = None - fixed_size: Optional[Size] = None - maximum_size: Optional[Size] = None - minimum_size: Optional[Size] = None - - -@dataclass -class OutlinedButtonTheme(ElevatedButtonTheme): - pass - - -@dataclass -class TextButtonTheme(ElevatedButtonTheme): - pass - - -@dataclass -class FilledButtonTheme(ElevatedButtonTheme): - pass - - -@dataclass -class IconButtonTheme: - # from ElevatedButtonTheme (excluding icon_color, disabled_icon_color, text_style) - bgcolor: Optional[ColorValue] = None - foreground_color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - disabled_bgcolor: Optional[ColorValue] = None - disabled_foreground_color: Optional[ColorValue] = None - overlay_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - padding: Optional[PaddingValue] = None - enable_feedback: Optional[bool] = None - disabled_mouse_cursor: Optional[MouseCursor] = None - enabled_mouse_cursor: Optional[MouseCursor] = None - shape: Optional[OutlinedBorder] = None - visual_density: Optional[VisualDensity] = None - border_side: Optional[BorderSide] = None - animation_duration: Optional[DurationValue] = None - alignment: Optional[Alignment] = None - icon_size: OptionalNumber = None - fixed_size: Optional[Size] = None - maximum_size: Optional[Size] = None - minimum_size: Optional[Size] = None - # Icon Button Theme - focus_color: Optional[ColorValue] = None - highlight_color: Optional[ColorValue] = None - hover_color: Optional[ColorValue] = None - - -@dataclass -class BottomSheetTheme: - bgcolor: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - drag_handle_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - show_drag_handle: Optional[bool] = None - modal_bgcolor: Optional[ColorValue] = None - modal_elevation: OptionalNumber = None - clip_behavior: Optional[ClipBehavior] = None - size_constraints: Optional[BoxConstraints] = None - modal_barrier_color: Optional[ColorValue] = None - - -@dataclass -class CardTheme: - color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - clip_behavior: Optional[ClipBehavior] = None - margin: Optional[MarginValue] = None - - -@dataclass -class ChipTheme: - color: ControlStateValue[ColorValue] = None - bgcolor: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - disabled_color: Optional[ColorValue] = None - selected_color: Optional[ColorValue] = None - checkmark_color: Optional[ColorValue] = None - delete_icon_color: Optional[ColorValue] = None - secondary_selected_color: Optional[ColorValue] = None - selected_shadow_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - click_elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - padding: Optional[PaddingValue] = None - label_padding: Optional[PaddingValue] = None - label_text_style: Optional[TextStyle] = None - secondary_label_text_style: Optional[TextStyle] = None - border_side: Optional[BorderSide] = None - brightness: Optional[Brightness] = None - show_checkmark: Optional[bool] = None - avatar_constraints: Optional[BoxConstraints] = None - delete_icon_size_constraints: Optional[BoxConstraints] = None - - def __post_init__(self): - if not isinstance(self.color, dict): - self.color = {ControlState.DEFAULT: self.color} - - -@dataclass -class FloatingActionButtonTheme: - bgcolor: Optional[ColorValue] = None - hover_color: Optional[ColorValue] = None - focus_color: Optional[ColorValue] = None - foreground_color: Optional[ColorValue] = None - splash_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - focus_elevation: OptionalNumber = None - hover_elevation: OptionalNumber = None - highlight_elevation: OptionalNumber = None - disabled_elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - enable_feedback: Optional[bool] = None - extended_padding: Optional[PaddingValue] = None - extended_text_style: Optional[TextStyle] = None - extended_icon_label_spacing: OptionalNumber = None - extended_size_constraints: Optional[BoxConstraints] = None - size_constraints: Optional[BoxConstraints] = None - large_size_constraints: Optional[BoxConstraints] = None - small_size_constraints: Optional[BoxConstraints] = None - - -@dataclass -class NavigationRailTheme: - bgcolor: Optional[ColorValue] = None - indicator_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - indicator_shape: Optional[OutlinedBorder] = None - unselected_label_text_style: Optional[TextStyle] = None - selected_label_text_style: Optional[TextStyle] = None - label_type: Optional[NavigationRailLabelType] = None - min_width: OptionalNumber = None - min_extended_width: OptionalNumber = None - group_alignment: OptionalNumber = None - use_indicator: Optional[bool] = None - - -@dataclass -class AppBarTheme: - color: Optional[ColorValue] = None - bgcolor: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - foreground_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - title_text_style: Optional[TextStyle] = None - toolbar_text_style: Optional[TextStyle] = None - center_title: Optional[bool] = None - title_spacing: OptionalNumber = None - scroll_elevation: OptionalNumber = None - toolbar_height: OptionalNumber = None - actions_padding: Optional[PaddingValue] = None - - -@dataclass -class BottomAppBarTheme: - color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - height: OptionalNumber = None - padding: Optional[PaddingValue] = None - shape: Optional[NotchShape] = None - - -@dataclass -class RadioTheme: - fill_color: ControlStateValue[ColorValue] = None - overlay_color: ControlStateValue[ColorValue] = None - splash_radius: OptionalNumber = None - height: OptionalNumber = None - visual_density: Optional[VisualDensity] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - - def __post_init__(self): - if not isinstance(self.fill_color, dict): - self.fill_color = {ControlState.DEFAULT: self.fill_color} - if not isinstance(self.overlay_color, dict): - self.overlay_color = {ControlState.DEFAULT: self.overlay_color} - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - - -@dataclass -class CheckboxTheme: - overlay_color: ControlStateValue[ColorValue] = None - check_color: ControlStateValue[ColorValue] = None - fill_color: ControlStateValue[ColorValue] = None - splash_radius: OptionalNumber = None - border_side: Optional[BorderSide] = None - visual_density: Optional[VisualDensity] = None - shape: Optional[OutlinedBorder] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - - def __post_init__(self): - if not isinstance(self.overlay_color, dict): - self.overlay_color = {ControlState.DEFAULT: self.overlay_color} - if not isinstance(self.check_color, dict): - self.check_color = {ControlState.DEFAULT: self.check_color} - if not isinstance(self.fill_color, dict): - self.fill_color = {ControlState.DEFAULT: self.fill_color} - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - - -@dataclass -class BadgeTheme: - bgcolor: Optional[ColorValue] = None - text_color: Optional[ColorValue] = None - small_size: OptionalNumber = None - large_size: OptionalNumber = None - alignment: Optional[Alignment] = None - padding: Optional[PaddingValue] = None - offset: Optional[OffsetValue] = None - text_style: Optional[TextStyle] = None - - -@dataclass -class SwitchTheme: - thumb_color: ControlStateValue[ColorValue] = None - track_color: ControlStateValue[ColorValue] = None - overlay_color: ControlStateValue[ColorValue] = None - track_outline_color: ControlStateValue[ColorValue] = None - thumb_icon: ControlStateValue[str] = None - track_outline_width: ControlStateValue[OptionalNumber] = None - splash_radius: OptionalNumber = None - mouse_cursor: ControlStateValue[MouseCursor] = None - padding: Optional[PaddingValue] = None - - def __post_init__(self): - if not isinstance(self.thumb_color, dict): - self.thumb_color = {ControlState.DEFAULT: self.thumb_color} - if not isinstance(self.track_color, dict): - self.track_color = {ControlState.DEFAULT: self.track_color} - if not isinstance(self.overlay_color, dict): - self.overlay_color = {ControlState.DEFAULT: self.overlay_color} - if not isinstance(self.track_outline_color, dict): - self.track_outline_color = {ControlState.DEFAULT: self.track_outline_color} - if not isinstance(self.thumb_icon, dict): - self.thumb_icon = {ControlState.DEFAULT: self.thumb_icon} - if not isinstance(self.track_outline_width, dict): - self.track_outline_width = {ControlState.DEFAULT: self.track_outline_width} - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - - -@dataclass -class DividerTheme: - color: Optional[ColorValue] = None - thickness: OptionalNumber = None - space: OptionalNumber = None - leading_indent: OptionalNumber = None - trailing_indent: OptionalNumber = None - - -@dataclass -class SnackBarTheme: - bgcolor: Optional[ColorValue] = None - action_text_color: Optional[ColorValue] = None - action_bgcolor: Optional[ColorValue] = None - close_icon_color: Optional[ColorValue] = None - disabled_action_text_color: Optional[ColorValue] = None - disabled_action_bgcolor: Optional[ColorValue] = None - elevation: OptionalNumber = None - content_text_style: Optional[TextStyle] = None - width: OptionalNumber = None - alignment: Optional[Alignment] = None - show_close_icon: Optional[bool] = None - dismiss_direction: Optional[DismissDirection] = None - behavior: Optional[SnackBarBehavior] = None - shape: Optional[OutlinedBorder] = None - inset_padding: Optional[PaddingValue] = None - action_overflow_threshold: OptionalNumber = None - - -@dataclass -class BannerTheme: - bgcolor: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - divider_color: Optional[ColorValue] = None - padding: Optional[PaddingValue] = None - leading_padding: Optional[PaddingValue] = None - elevation: OptionalNumber = None - content_text_style: Optional[TextStyle] = None - - -@dataclass -class DatePickerTheme: - bgcolor: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - divider_color: Optional[ColorValue] = None - header_bgcolor: Optional[ColorValue] = None - today_bgcolor: ControlStateValue[ColorValue] = None - day_bgcolor: ControlStateValue[ColorValue] = None - day_overlay_color: ControlStateValue[ColorValue] = None - day_foreground_color: ControlStateValue[ColorValue] = None - elevation: OptionalNumber = None - range_picker_elevation: OptionalNumber = None - day_text_style: Optional[TextStyle] = None - weekday_text_style: Optional[TextStyle] = None - year_text_style: Optional[TextStyle] = None - shape: Optional[OutlinedBorder] = None - cancel_button_style: Optional[ButtonStyle] = None - confirm_button_style: Optional[ButtonStyle] = None - header_foreground_color: Optional[ColorValue] = None - header_headline_text_style: Optional[TextStyle] = None - header_help_text_style: Optional[TextStyle] = None - range_picker_bgcolor: Optional[ColorValue] = None - range_picker_header_bgcolor: Optional[ColorValue] = None - range_picker_header_foreground_color: Optional[ColorValue] = None - today_foreground_color: ControlStateValue[ColorValue] = None - range_picker_shape: Optional[OutlinedBorder] = None - range_picker_header_help_text_style: Optional[TextStyle] = None - range_picker_header_headline_text_style: Optional[TextStyle] = None - range_picker_surface_tint_color: Optional[ColorValue] = None - range_selection_bgcolor: Optional[ColorValue] = None - range_selection_overlay_color: ControlStateValue[ColorValue] = None - today_border_side: Optional[BorderSide] = None - year_bgcolor: ControlStateValue[ColorValue] = None - year_foreground_color: ControlStateValue[ColorValue] = None - year_overlay_color: ControlStateValue[ColorValue] = None - day_shape: ControlStateValue[OutlinedBorder] = None - locale: Optional[Locale] = None - - def __post_init__(self): - if not isinstance(self.today_bgcolor, dict): - self.today_bgcolor = {ControlState.DEFAULT: self.today_bgcolor} - if not isinstance(self.day_bgcolor, dict): - self.day_bgcolor = {ControlState.DEFAULT: self.day_bgcolor} - if not isinstance(self.day_overlay_color, dict): - self.day_overlay_color = {ControlState.DEFAULT: self.day_overlay_color} - if not isinstance(self.day_foreground_color, dict): - self.day_foreground_color = { - ControlState.DEFAULT: self.day_foreground_color - } - if not isinstance(self.today_foreground_color, dict): - self.today_foreground_color = { - ControlState.DEFAULT: self.today_foreground_color - } - if not isinstance(self.range_selection_overlay_color, dict): - self.range_selection_overlay_color = { - ControlState.DEFAULT: self.range_selection_overlay_color - } - if not isinstance(self.year_bgcolor, dict): - self.year_bgcolor = {ControlState.DEFAULT: self.year_bgcolor} - if not isinstance(self.year_foreground_color, dict): - self.year_foreground_color = { - ControlState.DEFAULT: self.year_foreground_color - } - if not isinstance(self.year_overlay_color, dict): - self.year_overlay_color = {ControlState.DEFAULT: self.year_overlay_color} - if not isinstance(self.day_shape, dict): - self.day_shape = {ControlState.DEFAULT: self.day_shape} - - -@dataclass -class TimePickerTheme: - bgcolor: Optional[ColorValue] = None - day_period_color: Optional[ColorValue] = None - day_period_text_color: Optional[ColorValue] = None - dial_bgcolor: Optional[ColorValue] = None - dial_hand_color: Optional[ColorValue] = None - dial_text_color: Optional[ColorValue] = None - entry_mode_icon_color: Optional[ColorValue] = None - hour_minute_color: Optional[ColorValue] = None - hour_minute_text_color: Optional[ColorValue] = None - day_period_button_style: Optional[ButtonStyle] = None - cancel_button_style: Optional[ButtonStyle] = None - confirm_button_style: Optional[ButtonStyle] = None - day_period_text_style: Optional[TextStyle] = None - dial_text_style: Optional[TextStyle] = None - help_text_style: Optional[TextStyle] = None - hour_minute_text_style: Optional[TextStyle] = None - elevation: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - day_period_shape: Optional[OutlinedBorder] = None - hour_minute_shape: Optional[OutlinedBorder] = None - day_period_border_side: Optional[BorderSide] = None - padding: Optional[PaddingValue] = None - time_selector_separator_color: ControlStateValue[ColorValue] = None - time_selector_separator_text_style: ControlStateValue[TextStyle] = None - - def __post_init__(self): - if not isinstance(self.time_selector_separator_color, dict): - self.time_selector_separator_color = { - ControlState.DEFAULT: self.time_selector_separator_color - } - if not isinstance(self.time_selector_separator_text_style, dict): - self.time_selector_separator_text_style = { - ControlState.DEFAULT: self.time_selector_separator_text_style - } - - -@dataclass -class DropdownMenuTheme: - menu_style: Optional[MenuStyle] = None - text_style: Optional[TextStyle] = None - - -@dataclass -class ListTileTheme: - icon_color: Optional[ColorValue] = None - text_color: Optional[ColorValue] = None - bgcolor: Optional[ColorValue] = None - selected_tile_color: Optional[ColorValue] = None - selected_color: Optional[ColorValue] = None - is_three_line: Optional[bool] = None - enable_feedback: Optional[bool] = None - dense: Optional[bool] = None - shape: Optional[OutlinedBorder] = None - visual_density: Optional[VisualDensity] = None - content_padding: Optional[PaddingValue] = None - min_vertical_padding: Optional[PaddingValue] = None - horizontal_spacing: OptionalNumber = None - min_leading_width: OptionalNumber = None - title_text_style: Optional[TextStyle] = None - subtitle_text_style: Optional[TextStyle] = None - leading_and_trailing_text_style: Optional[TextStyle] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - min_tile_height: OptionalNumber = None - - def __post_init__(self): - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - - -@dataclass -class TooltipTheme: - height: OptionalNumber = None - text_style: Optional[TextStyle] = None - enable_feedback: Optional[bool] = None - exclude_from_semantics: Optional[bool] = None - prefer_below: Optional[bool] = None - vertical_offset: OptionalNumber = None - padding: Optional[PaddingValue] = None - wait_duration: Optional[DurationValue] = None - exit_duration: Optional[DurationValue] = None - show_duration: Optional[DurationValue] = None - margin: Optional[MarginValue] = None - trigger_mode: Optional[TooltipTriggerMode] = None - decoration: Optional[BoxDecoration] = None - text_align: Optional[TextAlign] = None - - -@dataclass -class ExpansionTileTheme: - bgcolor: Optional[ColorValue] = None - icon_color: Optional[ColorValue] = None - text_color: Optional[ColorValue] = None - collapsed_bgcolor: Optional[ColorValue] = None - collapsed_icon_color: Optional[ColorValue] = None - clip_behavior: Optional[ClipBehavior] = None - collapsed_text_color: Optional[ColorValue] = None - tile_padding: Optional[PaddingValue] = None - expanded_alignment: Optional[Alignment] = None - controls_padding: Optional[PaddingValue] = None - - -@dataclass -class SliderTheme: - active_track_color: Optional[ColorValue] = None - inactive_track_color: Optional[ColorValue] = None - thumb_color: Optional[ColorValue] = None - overlay_color: Optional[ColorValue] = None - value_indicator_color: Optional[ColorValue] = None - disabled_thumb_color: Optional[ColorValue] = None - value_indicator_text_style: Optional[TextStyle] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - active_tick_mark_color: Optional[ColorValue] = None - disabled_active_tick_mark_color: Optional[ColorValue] = None - disabled_active_track_color: Optional[ColorValue] = None - disabled_inactive_tick_mark_color: Optional[ColorValue] = None - disabled_inactive_track_color: Optional[ColorValue] = None - disabled_secondary_active_track_color: Optional[ColorValue] = None - inactive_tick_mark_color: Optional[ColorValue] = None - overlapping_shape_stroke_color: Optional[ColorValue] = None - min_thumb_separation: OptionalNumber = None - secondary_active_track_color: Optional[ColorValue] = None - track_height: OptionalNumber = None - value_indicator_stroke_color: Optional[ColorValue] = None - interaction: Optional[SliderInteraction] = None - padding: Optional[PaddingValue] = None - track_gap: OptionalNumber = None - thumb_size: ControlStateValue[Size] = None - year_2023: Optional[bool] = None - - def __post_init__(self): - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - if not isinstance(self.thumb_size, dict): - self.thumb_size = {ControlState.DEFAULT: self.thumb_size} - if self.year_2023 is not None: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - - -@dataclass -class ProgressIndicatorTheme: - color: Optional[ColorValue] = None - circular_track_color: Optional[ColorValue] = None - linear_track_color: Optional[ColorValue] = None - refresh_bgcolor: Optional[ColorValue] = None - linear_min_height: OptionalNumber = None - border_radius: Optional[BorderRadius] = None - track_gap: OptionalNumber = None - circular_track_padding: Optional[PaddingValue] = None - size_constraints: Optional[BoxConstraints] = None - stop_indicator_color: Optional[ColorValue] = None - stop_indicator_radius: OptionalNumber = None - stroke_align: OptionalNumber = None - stroke_cap: Optional[StrokeCap] = None - stroke_width: OptionalNumber = None - year_2023: Optional[bool] = None - - def __post_init__(self): - if self.year_2023 is not None: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 ProgressIndicator appearance. In the future, this flag will default to False.", - ) - - -@dataclass -class PopupMenuTheme: - color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - icon_color: Optional[ColorValue] = None - text_style: Optional[TextStyle] = None - label_text_style: Optional[TextStyle] = None - enable_feedback: Optional[bool] = None - elevation: OptionalNumber = None - icon_size: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - menu_position: Optional[PopupMenuPosition] = None - mouse_cursor: ControlStateValue[MouseCursor] = None - menu_padding: Optional[PaddingValue] = None - - def __post_init__(self): - if not isinstance(self.mouse_cursor, dict): - self.mouse_cursor = {ControlState.DEFAULT: self.mouse_cursor} - if not isinstance(self.thumb_size, dict): - self.thumb_size = {ControlState.DEFAULT: self.thumb_size} - if self.year_2023 is not None: - deprecated_property( - name="year_2023", - version="0.27.0", - delete_version=None, # not known for now - reason="Set this flag to False to opt into the 2024 Slider appearance. In the future, this flag will default to False.", - ) - - -@dataclass -class SearchBarTheme: - bgcolor: Optional[ColorValue] = None - text_capitalization: Optional[TextCapitalization] = None - shadow_color: ControlStateValue[ColorValue] = None - surface_tint_color: ControlStateValue[ColorValue] = None - overlay_color: ControlStateValue[ColorValue] = None - elevation: ControlStateValue[OptionalNumber] = None - text_style: ControlStateValue[TextStyle] = None - hint_style: ControlStateValue[TextStyle] = None - shape: ControlStateValue[OutlinedBorder] = None - padding: ControlStateValue[PaddingValue] = None - size_constraints: Optional[BoxConstraints] = None - border_side: ControlStateValue[BorderSide] = None - - def __post_init__(self): - if not isinstance(self.shadow_color, dict): - self.shadow_color = {ControlState.DEFAULT: self.shadow_color} - if not isinstance(self.surface_tint_color, dict): - self.surface_tint_color = {ControlState.DEFAULT: self.surface_tint_color} - if not isinstance(self.overlay_color, dict): - self.overlay_color = {ControlState.DEFAULT: self.overlay_color} - if not isinstance(self.elevation, dict): - self.elevation = {ControlState.DEFAULT: self.elevation} - if not isinstance(self.text_style, dict): - self.text_style = {ControlState.DEFAULT: self.text_style} - if not isinstance(self.hint_style, dict): - self.hint_style = {ControlState.DEFAULT: self.hint_style} - if not isinstance(self.shape, dict): - self.shape = {ControlState.DEFAULT: self.shape} - if not isinstance(self.padding, dict): - self.padding = {ControlState.DEFAULT: self.padding} - if not isinstance(self.border_side, dict): - self.border_side = {ControlState.DEFAULT: self.border_side} - - -@dataclass -class SearchViewTheme: - bgcolor: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - divider_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - header_hint_text_style: Optional[TextStyle] = None - header_text_style: Optional[TextStyle] = None - shape: Optional[OutlinedBorder] = None - border_side: Optional[BorderSide] = None - size_constraints: Optional[BoxConstraints] = None - header_height: OptionalNumber = None - padding: Optional[PaddingValue] = None - bar_padding: Optional[PaddingValue] = None - shrink_wrap: Optional[bool] = None - - -@dataclass -class NavigationDrawerTheme: - bgcolor: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - indicator_color: Optional[ColorValue] = None - elevation: OptionalNumber = None - tile_height: OptionalNumber = None - label_text_style: ControlStateValue[TextStyle] = None - indicator_shape: Optional[OutlinedBorder] = None - indicator_size: Optional[Size] = None - - def __post_init__(self): - if not isinstance(self.label_text_style, dict): - self.label_text_style = {ControlState.DEFAULT: self.label_text_style} - - -@dataclass -class NavigationBarTheme: - bgcolor: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - surface_tint_color: Optional[ColorValue] = None - indicator_color: Optional[ColorValue] = None - overlay_color: ControlStateValue[ColorValue] = None - elevation: OptionalNumber = None - height: OptionalNumber = None - label_text_style: ControlStateValue[TextStyle] = None - indicator_shape: Optional[OutlinedBorder] = None - label_behavior: Optional[NavigationBarLabelBehavior] = None - label_padding: Optional[PaddingValue] = None - - def __post_init__(self): - if not isinstance(self.label_text_style, dict): - self.label_text_style = {ControlState.DEFAULT: self.label_text_style} - if not isinstance(self.overlay_color, dict): - self.overlay_color = {ControlState.DEFAULT: self.overlay_color} - - -@dataclass -class SegmentedButtonTheme: - selected_icon: Optional[IconValue] = None - style: Optional[ButtonStyle] = None - - -@dataclass -class IconTheme: - color: Optional[ColorValue] = None - apply_text_scaling: Optional[bool] = None - fill: OptionalNumber = None - opacity: OptionalNumber = None - size: OptionalNumber = None - optical_size: OptionalNumber = None - grade: OptionalNumber = None - weight: OptionalNumber = None - shadows: Optional[List[BoxShadow]] = None - - -@dataclass -class DataTableTheme: - checkbox_horizontal_margin: OptionalNumber = None - column_spacing: OptionalNumber = None - data_row_max_height: OptionalNumber = None - data_row_min_height: OptionalNumber = None - data_row_color: ControlStateValue[ColorValue] = None - data_text_style: Optional[TextStyle] = None - divider_thickness: OptionalNumber = None - horizontal_margin: OptionalNumber = None - heading_text_style: Optional[TextStyle] = None - heading_row_color: ControlStateValue[ColorValue] = None - heading_row_height: OptionalNumber = None - data_row_cursor: ControlStateValue[MouseCursor] = None - decoration: Optional[BoxDecoration] = None - heading_row_alignment: Optional[MainAxisAlignment] = None - heading_cell_cursor: ControlStateValue[MouseCursor] = None - - -@deprecated_class( - "Use ElevatedButtonTheme, OutlinedButtonTheme, TextButtonTheme, FilledButtonTheme or IconButtonTheme instead.", - version="0.27.0", - delete_version="0.30.0", -) -@dataclass -class ButtonTheme: - button_color: Optional[ColorValue] = None - disabled_color: Optional[ColorValue] = None - hover_color: Optional[ColorValue] = None - focus_color: Optional[ColorValue] = None - highlight_color: Optional[ColorValue] = None - splash_color: Optional[ColorValue] = None - color_scheme: Optional[ColorScheme] = None - aligned_dropdown: Optional[bool] = None - height: OptionalNumber = None - min_width: OptionalNumber = None - shape: Optional[OutlinedBorder] = None - padding: Optional[PaddingValue] = None - - -@dataclass -class Theme: - color_scheme_seed: Optional[ColorValue] = None - primary_swatch: Optional[ColorValue] = None - font_family: Optional[str] = None - use_material3: Optional[bool] = None - appbar_theme: Optional[AppBarTheme] = None - badge_theme: Optional[BadgeTheme] = None - banner_theme: Optional[BannerTheme] = None - bottom_appbar_theme: Optional[BottomAppBarTheme] = None - bottom_sheet_theme: Optional[BottomSheetTheme] = None - button_theme: Optional[ButtonTheme] = None - card_theme: Optional[CardTheme] = None - checkbox_theme: Optional[CheckboxTheme] = None - chip_theme: Optional[ChipTheme] = None - color_scheme: Optional[ColorScheme] = None - data_table_theme: Optional[DataTableTheme] = None - date_picker_theme: Optional[DatePickerTheme] = None - dialog_theme: Optional[DialogTheme] = None - divider_theme: Optional[DividerTheme] = None - # dropdown_menu_theme: Optional[DropdownMenuTheme] = None - elevated_button_theme: Optional[ElevatedButtonTheme] = None - outlined_button_theme: Optional[OutlinedButtonTheme] = None - text_button_theme: Optional[TextButtonTheme] = None - filled_button_theme: Optional[FilledButtonTheme] = None - icon_button_theme: Optional[IconButtonTheme] = None - expansion_tile_theme: Optional[ExpansionTileTheme] = None - floating_action_button_theme: Optional[FloatingActionButtonTheme] = None - icon_theme: Optional[IconTheme] = None - list_tile_theme: Optional[ListTileTheme] = None - navigation_bar_theme: Optional[NavigationBarTheme] = None - navigation_drawer_theme: Optional[NavigationDrawerTheme] = None - navigation_rail_theme: Optional[NavigationRailTheme] = None - page_transitions: PageTransitionsTheme = field(default_factory=PageTransitionsTheme) - popup_menu_theme: Optional[PopupMenuTheme] = None - splash_color: Optional[ColorValue] = None - highlight_color: Optional[ColorValue] = None - hover_color: Optional[ColorValue] = None - focus_color: Optional[ColorValue] = None - unselected_control_color: Optional[ColorValue] = None - disabled_color: Optional[ColorValue] = None - canvas_color: Optional[ColorValue] = None - scaffold_bgcolor: Optional[ColorValue] = None - card_color: Optional[ColorValue] = None - divider_color: Optional[ColorValue] = None - dialog_bgcolor: Optional[ColorValue] = None - indicator_color: Optional[ColorValue] = None - hint_color: Optional[ColorValue] = None - shadow_color: Optional[ColorValue] = None - secondary_header_color: Optional[ColorValue] = None - primary_color: Optional[ColorValue] = None - primary_color_dark: Optional[ColorValue] = None - primary_color_light: Optional[ColorValue] = None - primary_text_theme: Optional[TextTheme] = None - progress_indicator_theme: Optional[ProgressIndicatorTheme] = None - radio_theme: Optional[RadioTheme] = None - scrollbar_theme: Optional[ScrollbarTheme] = None - search_bar_theme: Optional[SearchBarTheme] = None - search_view_theme: Optional[SearchViewTheme] = None - segmented_button_theme: Optional[SegmentedButtonTheme] = None - slider_theme: Optional[SliderTheme] = None - snackbar_theme: Optional[SnackBarTheme] = None - switch_theme: Optional[SwitchTheme] = None - system_overlay_style: SystemOverlayStyle = field(default_factory=SystemOverlayStyle) - tabs_theme: Optional[TabsTheme] = None - text_theme: Optional[TextTheme] = None - time_picker_theme: Optional[TimePickerTheme] = None - tooltip_theme: Optional[TooltipTheme] = None - visual_density: Optional[VisualDensity] = None - - def __post_init__(self): - if self.button_theme: - deprecated_property( - "button_theme", - "Use elevated_button_theme, outlined_button_theme, text_button_theme, filled_button_theme or icon_button_theme instead.", - version="0.27.0", - delete_version="0.30.0", - ) - if self.dialog_bgcolor: - deprecated_property( - "dialog_bgcolor", - "Use dialog_theme.bgcolor instead.", - version="0.27.0", - delete_version="0.30.0", - ) diff --git a/sdk/python/packages/flet/src/flet/core/time_picker.py b/sdk/python/packages/flet/src/flet/core/time_picker.py deleted file mode 100644 index ce48bef6ea..0000000000 --- a/sdk/python/packages/flet/src/flet/core/time_picker.py +++ /dev/null @@ -1,285 +0,0 @@ -from datetime import datetime, time -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.control import Control, OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OptionalControlEventCallable, - OptionalEventCallable, - Orientation, - ResponsiveNumber, -) - - -class TimePickerEntryMode(Enum): - DIAL = "dial" - INPUT = "input" - DIAL_ONLY = "dialOnly" - INPUT_ONLY = "inputOnly" - - -class TimePickerEntryModeChangeEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.entry_mode: Optional[TimePickerEntryMode] = TimePickerEntryMode(e.data) - - -class TimePicker(Control): - """ - A Material-style time picker dialog. - - It is added to [`page.overlay`](page#overlay) and can be opened by setting `open=True` or by calling `Page.open()` method. - - Depending on the `time_picker_entry_mode`, it will show either a Dial or an Input (hour and minute text fields) for picking a time. - - Example: - ``` - import flet as ft - - - def main(page: ft.Page): - page.horizontal_alignment = ft.CrossAxisAlignment.CENTER - - def handle_change(e): - page.add(ft.Text(f"TimePicker change: {time_picker.value}")) - - def handle_dismissal(e): - page.add(ft.Text(f"TimePicker dismissed: {time_picker.value}")) - - def handle_entry_mode_change(e): - page.add(ft.Text(f"TimePicker Entry mode changed to {e.entry_mode}")) - - time_picker = ft.TimePicker( - confirm_text="Confirm", - error_invalid_text="Time out of range", - help_text="Pick your time slot", - on_change=handle_change, - on_dismiss=handle_dismissal, - on_entry_mode_change=handle_entry_mode_change, - ) - - page.add( - ft.ElevatedButton( - "Pick time", - icon=ft.icons.TIME_TO_LEAVE, - on_click=lambda _: page.open(time_picker), - ) - ) - - - ft.app(main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/time_picker - """ - - def __init__( - self, - value: Optional[time] = datetime.now().time(), - open: bool = False, - time_picker_entry_mode: Optional[TimePickerEntryMode] = None, - hour_label_text: Optional[str] = None, - minute_label_text: Optional[str] = None, - help_text: Optional[str] = None, - cancel_text: Optional[str] = None, - confirm_text: Optional[str] = None, - error_invalid_text: Optional[str] = None, - orientation: Optional[Orientation] = None, - barrier_color: Optional[ColorValue] = None, - on_change: OptionalControlEventCallable = None, - on_dismiss: OptionalControlEventCallable = None, - on_entry_mode_change: OptionalEventCallable[ - TimePickerEntryModeChangeEvent - ] = None, - # - # Control - # - ref: Optional[Ref] = None, - expand: Optional[Union[bool, int]] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - tooltip: Optional[TooltipValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - Control.__init__( - self, - ref=ref, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - tooltip=tooltip, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__on_entry_mode_change = EventHandler( - lambda e: TimePickerEntryModeChangeEvent(e) - ) - self._add_event_handler( - "entryModeChange", self.__on_entry_mode_change.get_handler() - ) - - self.value = value - self.help_text = help_text - self.cancel_text = cancel_text - self.confirm_text = confirm_text - self.error_invalid_text = error_invalid_text - self.hour_label_text = hour_label_text - self.minute_label_text = minute_label_text - self.time_picker_entry_mode = time_picker_entry_mode - self.orientation = orientation - self.on_change = on_change - self.on_dismiss = on_dismiss - self.open = open - self.on_entry_mode_change = on_entry_mode_change - self.barrier_color = barrier_color - - def _get_control_name(self): - return "timepicker" - - # open - @property - def open(self) -> bool: - return self._get_attr("open", data_type="bool", def_value=False) - - @open.setter - def open(self, value: Optional[bool]): - self._set_attr("open", value) - - # value - @property - def value(self) -> time: - v = self._get_attr("value") # format HH:MM - return time(*map(int, v.split(":"))) - - @value.setter - def value(self, value: time): - self._set_attr("value", value.strftime("%H:%M")) - - # hour_label_text - @property - def hour_label_text(self) -> Optional[str]: - return self._get_attr("hourLabelText", def_value=None) - - @hour_label_text.setter - def hour_label_text(self, value: Optional[str]): - self._set_attr("hourLabelText", value) - - # minute_label_text - @property - def minute_label_text(self) -> Optional[str]: - return self._get_attr("minuteLabelText", def_value=None) - - @minute_label_text.setter - def minute_label_text(self, value: Optional[str]): - self._set_attr("minuteLabelText", value) - - # help_text - @property - def help_text(self) -> Optional[str]: - return self._get_attr("helpText", def_value=None) - - @help_text.setter - def help_text(self, value: Optional[str]): - self._set_attr("helpText", value) - - # cancel_text - @property - def cancel_text(self) -> Optional[str]: - return self._get_attr("cancelText", def_value=None) - - @cancel_text.setter - def cancel_text(self, value: Optional[str]): - self._set_attr("cancelText", value) - - # confirm_text - @property - def confirm_text(self) -> Optional[str]: - return self._get_attr("confirmText", def_value=None) - - @confirm_text.setter - def confirm_text(self, value: Optional[str]): - self._set_attr("confirmText", value) - - # error_invalid_text - @property - def error_invalid_text(self) -> Optional[str]: - return self._get_attr("errorInvalidText", def_value=None) - - @error_invalid_text.setter - def error_invalid_text(self, value: Optional[str]): - self._set_attr("errorInvalidText", value) - - # time_picker_entry_mode - @property - def time_picker_entry_mode(self) -> Optional[TimePickerEntryMode]: - return self.__time_picker_entry_mode - - @time_picker_entry_mode.setter - def time_picker_entry_mode(self, value: Optional[TimePickerEntryMode]): - self.__time_picker_entry_mode = value - self._set_enum_attr("timePickerEntryMode", value, TimePickerEntryMode) - - # orientation - @property - def orientation(self) -> Optional[Orientation]: - return self.__orientation - - @orientation.setter - def orientation(self, value: Optional[Orientation]): - self.__orientation = value - self._set_enum_attr("orientation", value, Orientation) - - # on_change - @property - def on_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("change") - - @on_change.setter - def on_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("change", handler) - - # on_dismiss - @property - def on_dismiss(self) -> OptionalControlEventCallable: - return self._get_event_handler("dismiss") - - @on_dismiss.setter - def on_dismiss(self, handler: OptionalControlEventCallable): - self._add_event_handler("dismiss", handler) - - # on_entry_mode_change - @property - def on_entry_mode_change( - self, - ) -> OptionalEventCallable[TimePickerEntryModeChangeEvent]: - return self.__on_entry_mode_change.handler - - @on_entry_mode_change.setter - def on_entry_mode_change( - self, handler: OptionalEventCallable[TimePickerEntryModeChangeEvent] - ): - self.__on_entry_mode_change.handler = handler - - # barrier_color - @property - def barrier_color(self) -> Optional[ColorValue]: - return self.__barrier_color - - @barrier_color.setter - def barrier_color(self, value: Optional[ColorValue]): - self.__barrier_color = value - self._set_enum_attr("barrierColor", value, ColorEnums) diff --git a/sdk/python/packages/flet/src/flet/core/tooltip.py b/sdk/python/packages/flet/src/flet/core/tooltip.py deleted file mode 100644 index 417ddea71e..0000000000 --- a/sdk/python/packages/flet/src/flet/core/tooltip.py +++ /dev/null @@ -1,55 +0,0 @@ -from dataclasses import dataclass -from typing import List, Optional, Union - -from flet.core.border import Border -from flet.core.box import BoxShadow, BoxShape, DecorationImage -from flet.core.gradients import Gradient -from flet.core.text_style import TextStyle -from flet.core.types import ( - BlendMode, - BorderRadiusValue, - ColorValue, - DurationValue, - MarginValue, - OptionalNumber, - PaddingValue, - TextAlign, -) - - -class TooltipTriggerMode: - MANUAL = "manual" - TAP = "tap" - LONG_PRESS = "long_press" - - -@dataclass -class Tooltip: - """Tooltips provide text labels which help explain the function of a button or other user interface action.""" - - message: str - enable_feedback: Optional[bool] = None - height: OptionalNumber = None - vertical_offset: OptionalNumber = None - margin: Optional[MarginValue] = None - padding: Optional[PaddingValue] = None - bgcolor: Optional[ColorValue] = None - image: Optional[DecorationImage] = None - shadow: Optional[List[BoxShadow]] = None - blend_mode: Optional[BlendMode] = None - gradient: Optional[Gradient] = None - border: Optional[Border] = None - border_radius: Optional[BorderRadiusValue] = None - shape: Optional[BoxShape] = None - text_style: Optional[TextStyle] = None - text_align: Optional[TextAlign] = None - prefer_below: Optional[bool] = None - show_duration: Optional[DurationValue] = None - wait_duration: Optional[DurationValue] = None - exit_duration: Optional[DurationValue] = None - enable_tap_to_dismiss: Optional[bool] = None - exclude_from_semantics: Optional[bool] = None - trigger_mode: Optional[TooltipTriggerMode] = None - - -TooltipValue = Union[str, "Tooltip"] diff --git a/sdk/python/packages/flet/src/flet/core/transform.py b/sdk/python/packages/flet/src/flet/core/transform.py deleted file mode 100644 index 6eb08c2ae7..0000000000 --- a/sdk/python/packages/flet/src/flet/core/transform.py +++ /dev/null @@ -1,24 +0,0 @@ -from dataclasses import dataclass, field -from typing import Optional - -from flet.core.alignment import Alignment - - -@dataclass -class Scale: - scale: Optional[float] = field(default=None) - scale_x: Optional[float] = field(default=None) - scale_y: Optional[float] = field(default=None) - alignment: Optional[Alignment] = field(default=None) - - -@dataclass -class Rotate: - angle: float - alignment: Optional[Alignment] = field(default=None) - - -@dataclass -class Offset: - x: float - y: float diff --git a/sdk/python/packages/flet/src/flet/core/transparent_pointer.py b/sdk/python/packages/flet/src/flet/core/transparent_pointer.py deleted file mode 100644 index 0c7dcd7987..0000000000 --- a/sdk/python/packages/flet/src/flet/core/transparent_pointer.py +++ /dev/null @@ -1,99 +0,0 @@ -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - OffsetValue, - OptionalControlEventCallable, - RotateValue, - ScaleValue, -) - - -class TransparentPointer(ConstrainedControl): - def __init__( - self, - content: Optional[Control] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.content = content - - def _get_control_name(self): - return "transparentpointer" - - def _get_children(self): - if self.__content is not None: - self.__content._set_attr_internal("n", "content") - return [self.__content] - return [] - - # content - @property - def content(self) -> Optional[Control]: - return self.__content - - @content.setter - def content(self, value: Optional[Control]): - self.__content = value diff --git a/sdk/python/packages/flet/src/flet/core/types.py b/sdk/python/packages/flet/src/flet/core/types.py deleted file mode 100644 index b85d1a148b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/types.py +++ /dev/null @@ -1,408 +0,0 @@ -from dataclasses import dataclass -from datetime import date, datetime -from enum import Enum -from typing import Any, Callable, Dict, List, Optional, Protocol, Tuple, TypeVar, Union - -from flet.core.border_radius import BorderRadius -from flet.core.colors import Colors -from flet.core.control_event import ControlEvent -from flet.core.cupertino_colors import CupertinoColors -from flet.core.cupertino_icons import CupertinoIcons -from flet.core.event import Event -from flet.core.icons import Icons -from flet.core.margin import Margin -from flet.core.padding import Padding -from flet.core.transform import Offset, Rotate, Scale - -WEB_BROWSER = "web_browser" -FLET_APP = "flet_app" -FLET_APP_WEB = "flet_app_web" -FLET_APP_HIDDEN = "flet_app_hidden" - - -class AppView(Enum): - WEB_BROWSER = "web_browser" - FLET_APP = "flet_app" - FLET_APP_WEB = "flet_app_web" - FLET_APP_HIDDEN = "flet_app_hidden" - - -class WindowEventType(Enum): - CLOSE = "close" - FOCUS = "focus" - BLUR = "blur" - HIDE = "hide" - SHOW = "show" - MAXIMIZE = "maximize" - UNMAXIMIZE = "unmaximize" - MINIMIZE = "minimize" - RESTORE = "restore" - RESIZE = "resize" - RESIZED = "resized" - MOVE = "move" - MOVED = "moved" - LEAVE_FULL_SCREEN = "leave-full-screen" - ENTER_FULL_SCREEN = "enter-full-screen" - - -class WebRenderer(Enum): - AUTO = "auto" - HTML = "html" - CANVAS_KIT = "canvaskit" - - -class UrlTarget(Enum): - BLANK = "blank" - SELF = "_self" - PARENT = "_parent" - TOP = "_top" - - -PaddingValue = Union[int, float, Padding] - -MarginValue = Union[int, float, Margin] - -BorderRadiusValue = Union[int, float, BorderRadius] - -RotateValue = Union[int, float, Rotate] - -ScaleValue = Union[int, float, Scale] - -OffsetValue = Union[Offset, Tuple[Union[float, int], Union[float, int]]] - - -@dataclass -class Duration: - microseconds: int = 0 - milliseconds: int = 0 - seconds: int = 0 - minutes: int = 0 - hours: int = 0 - days: int = 0 - - -DurationValue = Union[int, Duration] - - -class FontWeight(Enum): - NORMAL = "normal" - BOLD = "bold" - W_100 = "w100" - W_200 = "w200" - W_300 = "w300" - W_400 = "w400" - W_500 = "w500" - W_600 = "w600" - W_700 = "w700" - W_800 = "w800" - W_900 = "w900" - - -class NotchShape(Enum): - AUTO = "auto" - CIRCULAR = "circular" - - -Number = Union[int, float] -ResponsiveNumber = Union[Dict[str, Number], Number] -OptionalNumber = Optional[Number] - -# str type alias -OptionalString = Optional[str] - - -class ControlState(Enum): - HOVERED = "hovered" - FOCUSED = "focused" - PRESSED = "pressed" - DRAGGED = "dragged" - SELECTED = "selected" - SCROLLED_UNDER = "scrolledUnder" - DISABLED = "disabled" - ERROR = "error" - DEFAULT = "default" - - -class MainAxisAlignment(Enum): - START = "start" - END = "end" - CENTER = "center" - SPACE_BETWEEN = "spaceBetween" - SPACE_AROUND = "spaceAround" - SPACE_EVENLY = "spaceEvenly" - - -class CrossAxisAlignment(Enum): - START = "start" - END = "end" - CENTER = "center" - STRETCH = "stretch" - BASELINE = "baseline" - - -class VerticalAlignment(Enum): - NONE = None - START = -1.0 - END = 1.0 - CENTER = 0.0 - - -class TabAlignment(Enum): - START = "start" - START_OFFSET = "startOffset" - FILL = "fill" - CENTER = "center" - - -class LabelPosition(Enum): - RIGHT = "right" - LEFT = "left" - - -class BlendMode(Enum): - CLEAR = "clear" - COLOR = "color" - COLOR_BURN = "colorBurn" - COLOR_DODGE = "colorDodge" - DARKEN = "darken" - DIFFERENCE = "difference" - DST = "dst" - DST_A_TOP = "dstATop" - DST_IN = "dstIn" - DST_OUT = "dstOut" - DST_OVER = "dstOver" - EXCLUSION = "exclusion" - HARD_LIGHT = "hardLight" - HUE = "hue" - LIGHTEN = "lighten" - LUMINOSITY = "luminosity" - MODULATE = "modulate" - MULTIPLY = "multiply" - OVERLAY = "overlay" - PLUS = "plus" - SATURATION = "saturation" - SCREEN = "screen" - SOFT_LIGHT = "softLight" - SRC = "src" - SRC_A_TOP = "srcATop" - SRC_IN = "srcIn" - SRC_OUT = "srcOut" - SRC_OVER = "srcOver" - VALUES = "values" - XOR = "xor" - - -class TextAlign(Enum): - LEFT = "left" - RIGHT = "right" - CENTER = "center" - JUSTIFY = "justify" - START = "start" - END = "end" - - -class ScrollMode(Enum): - AUTO = "auto" - ADAPTIVE = "adaptive" - ALWAYS = "always" - HIDDEN = "hidden" - - -class ClipBehavior(Enum): - NONE = "none" - ANTI_ALIAS = "antiAlias" - ANTI_ALIAS_WITH_SAVE_LAYER = "antiAliasWithSaveLayer" - HARD_EDGE = "hardEdge" - - -class ImageFit(Enum): - NONE = "none" - CONTAIN = "contain" - COVER = "cover" - FILL = "fill" - FIT_HEIGHT = "fitHeight" - FIT_WIDTH = "fitWidth" - SCALE_DOWN = "scaleDown" - - -class ImageRepeat(Enum): - NO_REPEAT = "noRepeat" - REPEAT = "repeat" - REPEAT_X = "repeatX" - REPEAT_Y = "repeatY" - - -class PagePlatform(Enum): - IOS = "ios" - ANDROID = "android" - ANDROID_TV = "android_tv" - MACOS = "macos" - WINDOWS = "windows" - LINUX = "linux" - - -class ThemeMode(Enum): - SYSTEM = "system" - LIGHT = "light" - DARK = "dark" - - -class Brightness(Enum): - LIGHT = "light" - DARK = "dark" - - -class Orientation(Enum): - PORTRAIT = "portrait" - LANDSCAPE = "landscape" - - -class FloatingActionButtonLocation(Enum): - CENTER_DOCKED = "centerDocked" - CENTER_FLOAT = "centerFloat" - CENTER_TOP = "centerTop" - END_CONTAINED = "endContained" - END_DOCKED = "endDocked" - END_FLOAT = "endFloat" - END_TOP = "endTop" - MINI_CENTER_DOCKED = "miniCenterDocked" - MINI_CENTER_FLOAT = "miniCenterFloat" - MINI_CENTER_TOP = "miniCenterTop" - MINI_END_DOCKED = "miniEndDocked" - MINI_END_FLOAT = "miniEndFloat" - MINI_END_TOP = "miniEndTop" - MINI_START_DOCKED = "miniStartDocked" - MINI_START_FLOAT = "miniStartFloat" - MINI_START_TOP = "miniStartTop" - START_DOCKED = "startDocked" - START_FLOAT = "startFloat" - START_TOP = "startTop" - - -class AppLifecycleState(Enum): - SHOW = "show" - RESUME = "resume" - HIDE = "hide" - INACTIVE = "inactive" - PAUSE = "pause" - DETACH = "detach" - RESTART = "restart" - - -class MouseCursor(Enum): - ALIAS = "alias" - ALL_SCROLL = "allScroll" - BASIC = "basic" - CELL = "cell" - CLICK = "click" - CONTEXT_MENU = "contextMenu" - COPY = "copy" - DISAPPEARING = "disappearing" - FORBIDDEN = "forbidden" - GRAB = "grab" - GRABBING = "grabbing" - HELP = "help" - MOVE = "move" - NO_DROP = "noDrop" - NONE = "none" - PRECISE = "precise" - PROGRESS = "progress" - RESIZE_COLUMN = "resizeColumn" - RESIZE_DOWN = "resizeDown" - RESIZE_DOWN_LEFT = "resizeDownLeft" - RESIZE_DOWN_RIGHT = "resizeDownRight" - RESIZE_LEFT = "resizeLeft" - RESIZE_LEFT_RIGHT = "resizeLeftRight" - RESIZE_RIGHT = "resizeRight" - RESIZE_ROW = "resizeRow" - RESIZE_UP = "resizeUp" - RESIZE_UP_DOWN = "resizeUpDown" - RESIZE_UP_LEFT = "resizeUpLeft" - RESIZE_UP_LEFT_DOWN_RIGHT = "resizeUpLeftDownRight" - RESIZE_UP_RIGHT = "resizeUpRight" - RESIZE_UP_RIGHT_DOWN_LEFT = "resizeUpRightDownLeft" - TEXT = "text" - VERTICAL_TEXT = "verticalText" - WAIT = "wait" - ZOOM_IN = "zoomIn" - ZOOM_OUT = "zoomOut" - - -class PointerDeviceType(Enum): - TOUCH = "touch" - MOUSE = "mouse" - STYLUS = "stylus" - INVERTED_STYLUS = "invertedStylus" - TRACKPAD = "trackpad" - UNKNOWN = "unknown" - - -class StrokeCap(Enum): - ROUND = "round" - SQUARE = "square" - BUTT = "butt" - - -class StrokeJoin(Enum): - MITER = "miter" - ROUND = "round" - BEVEL = "bevel" - - -class VisualDensity(Enum): - STANDARD = "standard" - COMPACT = "compact" - COMFORTABLE = "comfortable" - ADAPTIVE_PLATFORM_DENSITY = "adaptivePlatformDensity" - - -@dataclass -class Locale: - language_code: Optional[str] = None - country_code: Optional[str] = None - script_code: Optional[str] = None - - -@dataclass -class LocaleConfiguration: - supported_locales: Optional[List[Locale]] = None - current_locale: Optional[Locale] = None - - -# Events -ControlEventType = TypeVar("ControlEventType", bound=ControlEvent) -EventType = TypeVar("EventType", bound=Event) -OptionalEventCallable = Optional[Callable[[EventType], Any]] -OptionalControlEventCallable = Optional[Callable[[ControlEvent], Any]] - - -class OnFocusEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - self.primary: bool = bool(e.data) - - -# Colors -ColorEnums = (Colors, CupertinoColors) -ColorValue = Union[str, Colors, CupertinoColors] - -# Icons -IconEnums = (Icons, CupertinoIcons) -IconValue = Union[str, Icons, CupertinoIcons] -IconValueOrControl = Union[IconValue, "Control"] - -# ControlState -T = TypeVar("T") -ControlStateValue = Union[None, T, Dict[ControlState, T]] - -# DateTime -DateTimeValue = Union[datetime, date] - -# Wrapper -Wrapper = Callable[..., Any] - - -# Protocols -class SupportsStr(Protocol): - def __str__(self) -> str: - ... diff --git a/sdk/python/packages/flet/src/flet/core/vertical_divider.py b/sdk/python/packages/flet/src/flet/core/vertical_divider.py deleted file mode 100644 index f377146f83..0000000000 --- a/sdk/python/packages/flet/src/flet/core/vertical_divider.py +++ /dev/null @@ -1,130 +0,0 @@ -from typing import Any, Optional - -from flet.core.control import Control, OptionalNumber -from flet.core.ref import Ref -from flet.core.types import ColorEnums, ColorValue - - -class VerticalDivider(Control): - """ - A thin vertical line, with padding on either side. - - In the material design language, this represents a divider. - - Example: - - ``` - import flet as ft - - def main(page: ft.Page): - - page.add( - ft.Row( - [ - ft.Container( - bgcolor=ft.colors.ORANGE_300, - alignment=ft.alignment.center, - expand=True, - ), - ft.VerticalDivider(), - ft.Container( - bgcolor=ft.colors.BROWN_400, - alignment=ft.alignment.center, - expand=True, - ), - ], - spacing=0, - expand=True, - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/verticaldivider - """ - - def __init__( - self, - width: OptionalNumber = None, - thickness: OptionalNumber = None, - color: Optional[ColorValue] = None, - leading_indent: OptionalNumber = None, - trailing_indent: OptionalNumber = None, - # - # Control - # - ref: Optional[Ref] = None, - opacity: OptionalNumber = None, - visible: Optional[bool] = None, - data: Any = None, - ): - - Control.__init__( - self, - ref=ref, - opacity=opacity, - visible=visible, - data=data, - ) - - self.width = width - self.thickness = thickness - self.color = color - self.leading_indent = leading_indent - self.trailing_indent = trailing_indent - - def _get_control_name(self): - return "verticaldivider" - - # width - @property - def width(self) -> OptionalNumber: - return self._get_attr("width", data_type="float") - - @width.setter - def width(self, value: OptionalNumber): - assert value is None or value >= 0, "width cannot be negative" - self._set_attr("width", value) - - # thickness - @property - def thickness(self) -> OptionalNumber: - return self._get_attr("thickness", data_type="float") - - @thickness.setter - def thickness(self, value: OptionalNumber): - assert value is None or value >= 0, "thickness cannot be negative" - self._set_attr("thickness", value) - - # color - @property - def color(self) -> Optional[ColorValue]: - return self.__color - - @color.setter - def color(self, value: Optional[ColorValue]): - self.__color = value - self._set_enum_attr("color", value, ColorEnums) - - # leading_indent - @property - def leading_indent(self) -> OptionalNumber: - return self._get_attr("leadingIndent", data_type="float") - - @leading_indent.setter - def leading_indent(self, value: OptionalNumber): - assert value is None or value >= 0, "leading_indent cannot be negative" - self._set_attr("leadingIndent", value) - - # trailing_indent - @property - def trailing_indent(self) -> OptionalNumber: - return self._get_attr("trailingIndent", data_type="float") - - @trailing_indent.setter - def trailing_indent(self, value: OptionalNumber): - assert value is None or value >= 0, "trailing_indent cannot be negative" - self._set_attr("trailingIndent", value) diff --git a/sdk/python/packages/flet/src/flet/core/video.py b/sdk/python/packages/flet/src/flet/core/video.py deleted file mode 100644 index 135ad8b3e8..0000000000 --- a/sdk/python/packages/flet/src/flet/core/video.py +++ /dev/null @@ -1,558 +0,0 @@ -import dataclasses -from enum import Enum -from typing import Any, Dict, List, Optional, Union, cast - -from flet.core.alignment import Alignment -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.box import FilterQuality -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.ref import Ref -from flet.core.text_style import TextStyle -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - ImageFit, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ResponsiveNumber, - RotateValue, - ScaleValue, - TextAlign, -) -from flet.utils import deprecated - - -class PlaylistMode(Enum): - NONE = "none" - SINGLE = "single" - LOOP = "loop" - - -@dataclasses.dataclass -class VideoMedia: - resource: Optional[str] = dataclasses.field(default=None) - http_headers: Optional[Dict[str, str]] = dataclasses.field(default=None) - extras: Optional[Dict[str, str]] = dataclasses.field(default=None) - - -@dataclasses.dataclass -class VideoConfiguration: - output_driver: Optional[str] = dataclasses.field(default=None) - hardware_decoding_api: Optional[str] = dataclasses.field(default=None) - enable_hardware_acceleration: Optional[bool] = dataclasses.field(default=None) - - -@dataclasses.dataclass -class VideoSubtitleConfiguration: - src: Optional[str] = dataclasses.field(default=None) - title: Optional[str] = dataclasses.field(default=None) - language: Optional[str] = dataclasses.field(default=None) - text_style: Optional[TextStyle] = dataclasses.field(default=None) - text_scale_factor: Optional[OptionalNumber] = dataclasses.field(default=None) - text_align: Optional[TextAlign] = dataclasses.field(default=None) - padding: Optional[PaddingValue] = dataclasses.field(default=None) - visible: Optional[bool] = dataclasses.field(default=None) - - -@deprecated( - reason="Video control has been moved to a separate Python package: https://pypi.org/project/flet-video. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class Video(ConstrainedControl): - """ - A control that displays a video from a playlist. - - ----- - - Online docs: https://flet.dev/docs/controls/video - """ - - def __init__( - self, - playlist: Optional[List[VideoMedia]] = None, - title: Optional[str] = None, - fit: Optional[ImageFit] = None, - fill_color: Optional[ColorValue] = None, - wakelock: Optional[bool] = None, - autoplay: Optional[bool] = None, - show_controls: Optional[bool] = None, - muted: Optional[bool] = None, - playlist_mode: Optional[PlaylistMode] = None, - shuffle_playlist: Optional[bool] = None, - volume: OptionalNumber = None, - playback_rate: OptionalNumber = None, - alignment: Optional[Alignment] = None, - filter_quality: Optional[FilterQuality] = None, - pause_upon_entering_background_mode: Optional[bool] = None, - resume_upon_entering_foreground_mode: Optional[bool] = None, - aspect_ratio: OptionalNumber = None, - pitch: OptionalNumber = None, - configuration: Optional[VideoConfiguration] = None, - subtitle_configuration: Optional[VideoSubtitleConfiguration] = None, - on_loaded: OptionalControlEventCallable = None, - on_enter_fullscreen: OptionalControlEventCallable = None, - on_exit_fullscreen: OptionalControlEventCallable = None, - on_error: OptionalControlEventCallable = None, - on_completed: OptionalControlEventCallable = None, - on_track_changed: OptionalControlEventCallable = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - - self.__playlist = playlist or [] - self.subtitle_configuration = subtitle_configuration - self.configuration = configuration - self.fit = fit - self.pitch = pitch - self.fill_color = fill_color - self.volume = volume - self.playback_rate = playback_rate - self.alignment = alignment - self.wakelock = wakelock - self.autoplay = autoplay - self.show_controls = show_controls - self.shuffle_playlist = shuffle_playlist - self.muted = muted - self.title = title - self.filter_quality = filter_quality - self.playlist_mode = playlist_mode - self.pause_upon_entering_background_mode = pause_upon_entering_background_mode - self.resume_upon_entering_foreground_mode = resume_upon_entering_foreground_mode - self.on_enter_fullscreen = on_enter_fullscreen - self.on_exit_fullscreen = on_exit_fullscreen - self.on_loaded = on_loaded - self.on_error = on_error - self.on_completed = on_completed - self.on_track_changed = on_track_changed - - def _get_control_name(self): - return "video" - - def before_update(self): - super().before_update() - self._set_attr_json("alignment", self.__alignment) - self._set_attr_json("playlist", self.__playlist if self.__playlist else None) - if isinstance(self.__subtitle_configuration, VideoSubtitleConfiguration): - self._set_attr_json("subtitleConfiguration", self.__subtitle_configuration) - - if isinstance(self.__configuration, VideoConfiguration): - self._set_attr_json("configuration", self.__configuration) - - def play(self): - self.invoke_method("play") - - def pause(self): - self.invoke_method("pause") - - def play_or_pause(self): - self.invoke_method("play_or_pause") - - def stop(self): - self.invoke_method("stop") - - def next(self): - self.invoke_method("next") - - def previous(self): - self.invoke_method("previous") - - def seek(self, position_milliseconds: int): - self.invoke_method("seek", {"position": str(position_milliseconds)}) - - def jump_to(self, media_index: int): - assert self.__playlist[media_index], "media_index is out of range" - if media_index < 0: - # dart doesn't support negative indexes - media_index = len(self.__playlist) + media_index - self.invoke_method("jump_to", {"media_index": str(media_index)}) - - def playlist_add(self, media: VideoMedia): - assert media.resource, "media has no resource" - self.invoke_method( - "playlist_add", - { - "resource": media.resource, - "http_headers": str(media.http_headers or {}), - "extras": str(media.extras or {}), - }, - ) - self.__playlist.append(media) - - def playlist_remove(self, media_index: int): - assert self.__playlist[media_index], "index out of range" - self.invoke_method("playlist_remove", {"media_index": str(media_index)}) - self.__playlist.pop(media_index) - - def is_playing(self, wait_timeout: Optional[float] = 5) -> bool: - playing = self.invoke_method( - "is_playing", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return playing == "true" - - async def is_playing_async(self, wait_timeout: Optional[float] = 5) -> bool: - playing = await self.invoke_method_async( - "is_playing", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return playing == "true" - - def is_completed(self, wait_timeout: Optional[float] = 5) -> bool: - completed = self.invoke_method( - "is_completed", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return completed == "true" - - async def is_completed_async(self, wait_timeout: Optional[float] = 5) -> bool: - completed = await self.invoke_method_async( - "is_completed", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return completed == "true" - - def get_duration(self, wait_timeout: Optional[float] = 5) -> Optional[int]: - sr = self.invoke_method( - "get_duration", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - async def get_duration_async( - self, wait_timeout: Optional[float] = 5 - ) -> Optional[int]: - sr = await self.invoke_method_async( - "get_duration", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - def get_current_position(self, wait_timeout: Optional[float] = 5) -> Optional[int]: - sr = self.invoke_method( - "get_current_position", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - async def get_current_position_async( - self, wait_timeout: Optional[float] = 5 - ) -> Optional[int]: - sr = await self.invoke_method_async( - "get_current_position", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - return int(sr) if sr else None - - # playlist - @property - def playlist(self) -> Optional[List[VideoMedia]]: - return self.__playlist - - # fit - @property - def fit(self) -> Optional[ImageFit]: - return self.__fit - - @fit.setter - def fit(self, value: Optional[ImageFit]): - self.__fit = value - self._set_attr("fit", value.value if isinstance(value, ImageFit) else value) - - # subtitle_configuration - @property - def subtitle_configuration(self) -> Optional[VideoSubtitleConfiguration]: - return self.__subtitle_configuration - - @subtitle_configuration.setter - def subtitle_configuration(self, value: Optional[VideoSubtitleConfiguration]): - self.__subtitle_configuration = value - - # configuration - @property - def configuration(self) -> Optional[VideoConfiguration]: - return self.__configuration - - @configuration.setter - def configuration(self, value: Optional[VideoConfiguration]): - self.__configuration = value - - # fill_color - @property - def fill_color(self) -> Optional[ColorValue]: - return self.__fill_color - - @fill_color.setter - def fill_color(self, value: Optional[ColorValue]): - self.__fill_color = value - self._set_enum_attr("fillColor", value, ColorEnums) - - # wakelock - @property - def wakelock(self) -> bool: - return self._get_attr("wakelock", data_type="bool", def_value=True) - - @wakelock.setter - def wakelock(self, value: Optional[bool]): - self._set_attr("wakelock", value) - - # autoplay - @property - def autoplay(self) -> bool: - return self._get_attr("autoPlay", data_type="bool", def_value=False) - - @autoplay.setter - def autoplay(self, value: Optional[bool]): - self._set_attr("autoPlay", value) - - # muted - @property - def muted(self) -> bool: - return self._get_attr("muted", data_type="bool", def_value=False) - - @muted.setter - def muted(self, value: Optional[bool]): - self._set_attr("muted", value) - - # shuffle_playlist - @property - def shuffle_playlist(self) -> bool: - return self._get_attr("shufflePlaylist", data_type="bool", def_value=False) - - @shuffle_playlist.setter - def shuffle_playlist(self, value: Optional[bool]): - self._set_attr("shufflePlaylist", value) - - # show_controls - @property - def show_controls(self) -> bool: - return self._get_attr("showControls", data_type="bool", def_value=True) - - @show_controls.setter - def show_controls(self, value: Optional[bool]): - self._set_attr("showControls", value) - - # pitch - @property - def pitch(self) -> OptionalNumber: - return self._get_attr("pitch", data_type="float") - - @pitch.setter - def pitch(self, value: OptionalNumber): - self._set_attr("pitch", value) - - # volume - @property - def volume(self) -> OptionalNumber: - return self._get_attr("volume", data_type="float") - - @volume.setter - def volume(self, value: OptionalNumber): - assert value is None or 0 <= value <= 100, "volume must be between 0 and 100" - self._set_attr("volume", value) - - # playback_rate - @property - def playback_rate(self) -> OptionalNumber: - return self._get_attr("playbackRate", data_type="float") - - @playback_rate.setter - def playback_rate(self, value: OptionalNumber): - self._set_attr("playbackRate", value) - - # title - @property - def title(self) -> Optional[str]: - return self._get_attr("title") - - @title.setter - def title(self, value: Optional[str]): - self._set_attr("title", value) - - # pause_upon_entering_background_mode - @property - def pause_upon_entering_background_mode(self) -> bool: - return cast( - bool, - self._get_attr( - "pauseUponEnteringBackgroundMode", data_type="bool", def_value=True - ), - ) - - @pause_upon_entering_background_mode.setter - def pause_upon_entering_background_mode(self, value: Optional[bool]): - self._set_attr("pauseUponEnteringBackgroundMode", value) - - # resume_upon_entering_foreground_mode - @property - def resume_upon_entering_foreground_mode(self) -> bool: - return cast( - bool, - self._get_attr( - "resumeUponEnteringForegroundMode", data_type="bool", def_value=False - ), - ) - - @resume_upon_entering_foreground_mode.setter - def resume_upon_entering_foreground_mode(self, value: Optional[bool]): - self._set_attr("resumeUponEnteringForegroundMode", value) - - # alignment - @property - def alignment(self) -> Optional[Alignment]: - return self.__alignment - - @alignment.setter - def alignment(self, value: Optional[Alignment]): - self.__alignment = value - - # filter_quality - @property - def filter_quality(self) -> Optional[FilterQuality]: - return self.__filter_quality - - @filter_quality.setter - def filter_quality(self, value: Optional[FilterQuality]): - self.__filter_quality = value - self._set_enum_attr("filterQuality", value, FilterQuality) - - # playlist_mode - @property - def playlist_mode(self) -> Optional[PlaylistMode]: - return self.__playlist_mode - - @playlist_mode.setter - def playlist_mode(self, value: Optional[PlaylistMode]): - self.__playlist_mode = value - self._set_enum_attr("playlistMode", value, PlaylistMode) - - # on_enter_fullscreen - @property - def on_enter_fullscreen(self): - return self._get_event_handler("enter_fullscreen") - - @on_enter_fullscreen.setter - def on_enter_fullscreen(self, handler: OptionalControlEventCallable): - self._add_event_handler("enter_fullscreen", handler) - self._set_attr("onEnterFullscreen", True if handler is not None else None) - - # on_exit_fullscreen - @property - def on_exit_fullscreen(self) -> OptionalControlEventCallable: - return self._get_event_handler("exit_fullscreen") - - @on_exit_fullscreen.setter - def on_exit_fullscreen(self, handler: OptionalControlEventCallable): - self._add_event_handler("exit_fullscreen", handler) - self._set_attr("onExitFullscreen", True if handler is not None else None) - - # on_loaded - @property - def on_loaded(self) -> OptionalControlEventCallable: - return self._get_event_handler("loaded") - - @on_loaded.setter - def on_loaded(self, handler: OptionalControlEventCallable): - self._set_attr("onLoaded", True if handler is not None else None) - self._add_event_handler("loaded", handler) - - # on_error - @property - def on_error(self) -> OptionalControlEventCallable: - return self._get_event_handler("error") - - @on_error.setter - def on_error(self, handler: OptionalControlEventCallable): - self._set_attr("onError", True if handler is not None else None) - self._add_event_handler("error", handler) - - # on_completed - @property - def on_completed(self) -> OptionalControlEventCallable: - return self._get_event_handler("completed") - - @on_completed.setter - def on_completed(self, handler: OptionalControlEventCallable): - self._set_attr("onCompleted", True if handler is not None else None) - self._add_event_handler("completed", handler) - - # on_track_changed - @property - def on_track_changed(self) -> OptionalControlEventCallable: - return self._get_event_handler("track_changed") - - @on_track_changed.setter - def on_track_changed(self, handler: OptionalControlEventCallable): - self._set_attr("onTrackChanged", True if handler is not None else None) - self._add_event_handler("track_changed", handler) diff --git a/sdk/python/packages/flet/src/flet/core/view.py b/sdk/python/packages/flet/src/flet/core/view.py deleted file mode 100644 index 4fdf6fff21..0000000000 --- a/sdk/python/packages/flet/src/flet/core/view.py +++ /dev/null @@ -1,335 +0,0 @@ -from typing import List, Optional, Sequence, Union - -from flet.core.adaptive_control import AdaptiveControl -from flet.core.app_bar import AppBar -from flet.core.bottom_app_bar import BottomAppBar -from flet.core.box import BoxDecoration -from flet.core.control import Control, OptionalNumber -from flet.core.cupertino_app_bar import CupertinoAppBar -from flet.core.cupertino_navigation_bar import CupertinoNavigationBar -from flet.core.floating_action_button import FloatingActionButton -from flet.core.navigation_bar import NavigationBar -from flet.core.navigation_drawer import NavigationDrawer -from flet.core.scrollable_control import OnScrollEvent, ScrollableControl -from flet.core.types import ( - ColorEnums, - ColorValue, - CrossAxisAlignment, - FloatingActionButtonLocation, - MainAxisAlignment, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PaddingValue, - ScrollMode, -) - - -class View(ScrollableControl, AdaptiveControl): - """ - View is the top most container for all other controls. - - A root view is automatically created when a new user session started. From layout perspective the View represents a `Column`(https://flet.dev/docs/controls/column/) control, so it has a similar behavior and shares same properties. - - ----- - - Online docs: https://flet.dev/docs/controls/view - """ - - def __init__( - self, - route: Optional[str] = None, - controls: Optional[Sequence[Control]] = None, - appbar: Union[AppBar, CupertinoAppBar, None] = None, - bottom_appbar: Optional[BottomAppBar] = None, - floating_action_button: Optional[FloatingActionButton] = None, - floating_action_button_location: Union[ - FloatingActionButtonLocation, OffsetValue - ] = None, - navigation_bar: Union[NavigationBar, CupertinoNavigationBar, None] = None, - drawer: Optional[NavigationDrawer] = None, - end_drawer: Optional[NavigationDrawer] = None, - vertical_alignment: Optional[MainAxisAlignment] = None, - horizontal_alignment: Optional[CrossAxisAlignment] = None, - spacing: OptionalNumber = None, - padding: Optional[PaddingValue] = None, - bgcolor: Optional[ColorValue] = None, - decoration: Optional[BoxDecoration] = None, - foreground_decoration: Optional[BoxDecoration] = None, - can_pop: Optional[bool] = None, - on_confirm_pop: OptionalControlEventCallable = None, - # - # ScrollableControl - # - scroll: Optional[ScrollMode] = None, - auto_scroll: Optional[bool] = None, - fullscreen_dialog: Optional[bool] = None, - on_scroll_interval: OptionalNumber = None, - on_scroll: OptionalEventCallable[OnScrollEvent] = None, - # - # AdaptiveControl - # - adaptive: Optional[bool] = None, - ): - Control.__init__(self) - - ScrollableControl.__init__( - self, - scroll=scroll, - auto_scroll=auto_scroll, - on_scroll_interval=on_scroll_interval, - on_scroll=on_scroll, - ) - - AdaptiveControl.__init__(self, adaptive=adaptive) - - self.controls = controls - self.route = route - self.appbar = appbar - self.bottom_appbar = bottom_appbar - self.navigation_bar = navigation_bar - self.drawer = drawer - self.end_drawer = end_drawer - self.floating_action_button = floating_action_button - self.floating_action_button_location = floating_action_button_location - self.vertical_alignment = vertical_alignment - self.horizontal_alignment = horizontal_alignment - self.spacing = spacing - self.padding = padding - self.bgcolor = bgcolor - self.scroll = scroll - self.auto_scroll = auto_scroll - self.fullscreen_dialog = fullscreen_dialog - self.decoration = decoration - self.foreground_decoration = foreground_decoration - self.can_pop = can_pop - self.on_confirm_pop = on_confirm_pop - - def _get_control_name(self): - return "view" - - def before_update(self): - super().before_update() - self._set_attr_json("padding", self.__padding) - if not isinstance( - self.__floating_action_button_location, (FloatingActionButtonLocation, str) - ): - self._set_attr_json( - "floatingActionButtonLocation", self.__floating_action_button_location - ) - self._set_attr_json("decoration", self.__decoration) - self._set_attr_json("foregroundDecoration", self.__foreground_decoration) - - def _get_children(self): - children = [] - if self.__appbar: - children.append(self.__appbar) - if self.__bottom_appbar: - children.append(self.__bottom_appbar) - if self.__fab: - self.__fab._set_attr_internal("n", "fab") - children.append(self.__fab) - if self.__navigation_bar: - children.append(self.__navigation_bar) - if self.__drawer: - self.__drawer._set_attr_internal("n", "drawer_start") - children.append(self.__drawer) - if self.__end_drawer: - self.__end_drawer._set_attr_internal("n", "drawer_end") - children.append(self.__end_drawer) - return children + self.__controls - - def confirm_pop(self, shouldPop: bool): - self.invoke_method("confirm_pop", {"shouldPop": str(shouldPop).lower()}) - - # route - @property - def route(self): - return self._get_attr("route") - - @route.setter - def route(self, value): - self._set_attr("route", value) - - # controls - @property - def controls(self) -> List[Control]: - return self.__controls - - @controls.setter - def controls(self, value: Optional[Sequence[Control]]): - self.__controls = list(value) if value is not None else [] - - # appbar - @property - def appbar(self) -> Union[AppBar, CupertinoAppBar, None]: - return self.__appbar - - @appbar.setter - def appbar(self, value: Union[AppBar, CupertinoAppBar, None]): - self.__appbar = value - - # bottom_appbar - @property - def bottom_appbar(self) -> Optional[BottomAppBar]: - return self.__bottom_appbar - - @bottom_appbar.setter - def bottom_appbar(self, value: Optional[BottomAppBar]): - self.__bottom_appbar = value - - # floating_action_button - @property - def floating_action_button(self) -> Optional[FloatingActionButton]: - return self.__fab - - @floating_action_button.setter - def floating_action_button(self, value: Optional[FloatingActionButton]): - self.__fab = value - - # floating_action_button_location - @property - def floating_action_button_location( - self, - ) -> Union[FloatingActionButtonLocation, OffsetValue]: - return self.__floating_action_button_location - - @floating_action_button_location.setter - def floating_action_button_location( - self, value: Union[FloatingActionButtonLocation, OffsetValue] - ): - self.__floating_action_button_location = value - if isinstance(value, (FloatingActionButtonLocation, str)): - self._set_attr( - "floatingActionButtonLocation", - ( - value.value - if isinstance(value, FloatingActionButtonLocation) - else value - ), - ) - - # navigation_bar - @property - def navigation_bar(self) -> Union[NavigationBar, CupertinoNavigationBar, None]: - return self.__navigation_bar - - @navigation_bar.setter - def navigation_bar(self, value: Union[NavigationBar, CupertinoNavigationBar, None]): - self.__navigation_bar = value - - # drawer - @property - def drawer(self) -> Optional[NavigationDrawer]: - return self.__drawer - - @drawer.setter - def drawer(self, value: Optional[NavigationDrawer]): - self.__drawer = value - - # end_drawer - @property - def end_drawer(self) -> Optional[NavigationDrawer]: - return self.__end_drawer - - @end_drawer.setter - def end_drawer(self, value: Optional[NavigationDrawer]): - self.__end_drawer = value - - # horizontal_alignment - @property - def horizontal_alignment(self) -> CrossAxisAlignment: - return self.__horizontal_alignment - - @horizontal_alignment.setter - def horizontal_alignment(self, value: CrossAxisAlignment): - self.__horizontal_alignment = value - self._set_enum_attr("horizontalAlignment", value, CrossAxisAlignment) - - # vertical_alignment - @property - def vertical_alignment(self) -> MainAxisAlignment: - return self.__vertical_alignment - - @vertical_alignment.setter - def vertical_alignment(self, value: MainAxisAlignment): - self.__vertical_alignment = value - self._set_enum_attr("verticalAlignment", value, MainAxisAlignment) - - # spacing - @property - def spacing(self) -> OptionalNumber: - return self._get_attr("spacing", data_type="float") - - @spacing.setter - def spacing(self, value: OptionalNumber): - self._set_attr("spacing", value) - - # padding - @property - def padding(self) -> Optional[PaddingValue]: - return self.__padding - - @padding.setter - def padding(self, value: Optional[PaddingValue]): - self.__padding = value - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # fullscreen_dialog - @property - def fullscreen_dialog(self) -> bool: - return self._get_attr("fullscreenDialog", data_type="bool", def_value=False) - - @fullscreen_dialog.setter - def fullscreen_dialog(self, value: Optional[bool]): - self._set_attr("fullscreenDialog", value) - - # foreground_decoration - @property - def foreground_decoration(self) -> Optional[BoxDecoration]: - return self.__foreground_decoration - - @foreground_decoration.setter - def foreground_decoration(self, value: Optional[BoxDecoration]): - self.__foreground_decoration = value - - # decoration - @property - def decoration(self) -> Optional[BoxDecoration]: - return self.__decoration - - @decoration.setter - def decoration(self, value: Optional[BoxDecoration]): - self.__decoration = value - - # can_pop - @property - def can_pop(self) -> Optional[bool]: - return self._get_attr("canPop", data_type="bool") - - @can_pop.setter - def can_pop(self, value: Optional[bool]): - self._set_attr("canPop", value) - - # on_confirm_pop - @property - def on_confirm_pop(self): - return self._get_event_handler("confirm_pop") - - @on_confirm_pop.setter - def on_confirm_pop(self, handler: OptionalControlEventCallable): - self._add_event_handler("confirm_pop", handler) - self._set_attr("onConfirmPop", True if handler is not None else None) - - # Magic methods - def __contains__(self, item: Control) -> bool: - return item in self.__controls diff --git a/sdk/python/packages/flet/src/flet/core/webview.py b/sdk/python/packages/flet/src/flet/core/webview.py deleted file mode 100644 index 95b81fec0b..0000000000 --- a/sdk/python/packages/flet/src/flet/core/webview.py +++ /dev/null @@ -1,473 +0,0 @@ -import json -from enum import Enum -from typing import Any, Optional, Union - -from flet.core.animation import AnimationValue -from flet.core.badge import BadgeValue -from flet.core.constrained_control import ConstrainedControl -from flet.core.control import OptionalNumber -from flet.core.control_event import ControlEvent -from flet.core.event_handler import EventHandler -from flet.core.exceptions import FletUnsupportedPlatformException -from flet.core.ref import Ref -from flet.core.tooltip import TooltipValue -from flet.core.types import ( - ColorEnums, - ColorValue, - OffsetValue, - OptionalControlEventCallable, - OptionalEventCallable, - PagePlatform, - ResponsiveNumber, - RotateValue, - ScaleValue, -) -from flet.utils import deprecated - - -class WebviewRequestMethod(Enum): - GET = "get" - POST = "post" - - -class WebviewLogLevelSeverity(Enum): - ERROR = "error" - WARNING = "warning" - DEBUG = "debug" - INFO = "info" - LOG = "log" - - -class WebviewScrollEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.x: float = d.get("x", 0) - self.y: float = d.get("y", 0) - - -class WebviewConsoleMessageEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.message: str = d.get("message") - self.severity_level: WebviewLogLevelSeverity = WebviewLogLevelSeverity( - d.get("level") - ) - - -class WebviewJavaScriptEvent(ControlEvent): - def __init__(self, e: ControlEvent): - super().__init__(e.target, e.name, e.data, e.control, e.page) - d = json.loads(e.data) - self.message: str = d.get("message") - self.url: str = d.get("url") - - -@deprecated( - reason="WebView control has been moved to a separate Python package: https://pypi.org/project/flet-webview. " - + "Read more about this change in Flet blog: https://flet.dev/blog/flet-v-0-26-release-announcement", - version="0.26.0", - delete_version="0.29.0", -) -class WebView(ConstrainedControl): - """ - Easily load webpages while allowing user interaction. - - The `WebView` control is designed exclusively for iOS and Android platforms. - - ## Examples - A simple webview implementation using this class could be like: - - ```python - import flet - - def main(page: flet.Page): - wv = flet.WebView( - "https://flet.dev", - expand=True, - on_page_started=lambda _: print("Page started"), - on_page_ended=lambda _: print("Page ended"), - on_web_resource_error=lambda e: print("Page error:", e.data), - ) - page.add(wv) - - flet.app(main) - ``` - - ## Properties - - ### `url` - - Start the webview by loading the `url` value. - - ### `javascript_enabled` - - Enable or disable the javascript execution of the page. Note that disabling the javascript execution of the page may result unexpected webpage behaviour. - - ### `prevent_link` - - Specify a link to prevent it from downloading. - - ### `bgcolor` - - Set the background color of the webview. - - ## Events - - ### `on_page_started` - - Fires soon as the first loading process of the webpage is started. - - ### `on_page_ended` - - Fires when all the webpage loading processes are ended. - - ### `on_web_resource_error` - - Fires when there is error with loading a webpage resource. - - View docs: [WebView](https://flet.dev/docs/controls/webview) - """ - - def __init__( - self, - url: str, - enable_javascript: Optional[bool] = None, - prevent_link: Optional[str] = None, - bgcolor: Optional[ColorValue] = None, - on_page_started: OptionalControlEventCallable = None, - on_page_ended: OptionalControlEventCallable = None, - on_web_resource_error: OptionalControlEventCallable = None, - on_progress: OptionalControlEventCallable = None, - on_url_change: OptionalControlEventCallable = None, - on_scroll: OptionalEventCallable[WebviewScrollEvent] = None, - on_console_message: OptionalEventCallable[WebviewConsoleMessageEvent] = None, - on_javascript_alert_dialog: OptionalEventCallable[ - WebviewJavaScriptEvent - ] = None, - # - # ConstrainedControl - # - ref: Optional[Ref] = None, - key: Optional[str] = None, - width: OptionalNumber = None, - height: OptionalNumber = None, - left: OptionalNumber = None, - top: OptionalNumber = None, - right: OptionalNumber = None, - bottom: OptionalNumber = None, - expand: Union[None, bool, int] = None, - expand_loose: Optional[bool] = None, - col: Optional[ResponsiveNumber] = None, - opacity: OptionalNumber = None, - rotate: Optional[RotateValue] = None, - scale: Optional[ScaleValue] = None, - offset: Optional[OffsetValue] = None, - aspect_ratio: OptionalNumber = None, - animate_opacity: Optional[AnimationValue] = None, - animate_size: Optional[AnimationValue] = None, - animate_position: Optional[AnimationValue] = None, - animate_rotation: Optional[AnimationValue] = None, - animate_scale: Optional[AnimationValue] = None, - animate_offset: Optional[AnimationValue] = None, - on_animation_end: OptionalControlEventCallable = None, - tooltip: Optional[TooltipValue] = None, - badge: Optional[BadgeValue] = None, - visible: Optional[bool] = None, - disabled: Optional[bool] = None, - data: Any = None, - ): - ConstrainedControl.__init__( - self, - ref=ref, - key=key, - width=width, - height=height, - left=left, - top=top, - right=right, - bottom=bottom, - expand=expand, - expand_loose=expand_loose, - col=col, - opacity=opacity, - rotate=rotate, - scale=scale, - offset=offset, - aspect_ratio=aspect_ratio, - animate_opacity=animate_opacity, - animate_size=animate_size, - animate_position=animate_position, - animate_rotation=animate_rotation, - animate_scale=animate_scale, - animate_offset=animate_offset, - on_animation_end=on_animation_end, - tooltip=tooltip, - badge=badge, - visible=visible, - disabled=disabled, - data=data, - ) - self.__on_scroll = EventHandler(lambda e: WebviewScrollEvent(e)) - self._add_event_handler("scroll", self.__on_scroll.get_handler()) - self.__on_console_message = EventHandler( - lambda e: WebviewConsoleMessageEvent(e) - ) - self._add_event_handler( - "console_message", self.__on_console_message.get_handler() - ) - self.__on_javascript_alert_dialog = EventHandler( - lambda e: WebviewJavaScriptEvent(e) - ) - self._add_event_handler( - "javascript_alert_dialog", self.__on_javascript_alert_dialog.get_handler() - ) - - self.url = url - self.enable_javascript = enable_javascript - self.prevent_link = prevent_link - self.bgcolor = bgcolor - self.on_page_started = on_page_started - self.on_page_ended = on_page_ended - self.on_web_resource_error = on_web_resource_error - self.on_progress = on_progress - self.on_url_change = on_url_change - self.on_scroll = on_scroll - self.on_console_message = on_console_message - self.on_javascript_alert_dialog = on_javascript_alert_dialog - - def _get_control_name(self): - return "webview" - - def _check_mobile_or_mac_platform(self): - assert self.page is not None, "WebView must be added to page first." - if self.page.platform not in [ - PagePlatform.ANDROID, - PagePlatform.IOS, - PagePlatform.MACOS, - ]: - raise FletUnsupportedPlatformException( - "This method is supported on Android, iOS and macOS platforms only." - ) - - def reload(self): - self._check_mobile_or_mac_platform() - self.invoke_method("reload") - - def can_go_back(self, wait_timeout: OptionalNumber = 10) -> bool: - self._check_mobile_or_mac_platform() - return ( - self.invoke_method( - "can_go_back", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - == "true" - ) - - def can_go_forward(self, wait_timeout: OptionalNumber = 10) -> bool: - self._check_mobile_or_mac_platform() - return ( - self.invoke_method( - "can_go_forward", - wait_for_result=True, - wait_timeout=wait_timeout, - ) - == "true" - ) - - def go_back(self): - self._check_mobile_or_mac_platform() - self.invoke_method("go_back") - - def go_forward(self): - self._check_mobile_or_mac_platform() - self.invoke_method("go_forward") - - def enable_zoom(self): - self._check_mobile_or_mac_platform() - self.invoke_method("enable_zoom") - - def disable_zoom(self): - self._check_mobile_or_mac_platform() - self.invoke_method("disable_zoom") - - def clear_cache(self): - self._check_mobile_or_mac_platform() - self.invoke_method("clear_cache") - - def clear_local_storage(self): - self._check_mobile_or_mac_platform() - self.invoke_method("clear_local_storage") - - def get_current_url(self, wait_timeout: OptionalNumber = 10) -> Optional[str]: - self._check_mobile_or_mac_platform() - return self.invoke_method( - "get_current_url", wait_for_result=True, wait_timeout=wait_timeout - ) - - def get_title(self, wait_timeout: OptionalNumber = 10) -> Optional[str]: - self._check_mobile_or_mac_platform() - return self.invoke_method( - "get_title", wait_for_result=True, wait_timeout=wait_timeout - ) - - def get_user_agent(self, wait_timeout: OptionalNumber = 10) -> Optional[str]: - self._check_mobile_or_mac_platform() - return self.invoke_method( - "get_user_agent", wait_for_result=True, wait_timeout=wait_timeout - ) - - def load_file(self, absolute_path: str): - self._check_mobile_or_mac_platform() - self.invoke_method("load_file", arguments={"path": absolute_path}) - - def load_request( - self, url: str, method: WebviewRequestMethod = WebviewRequestMethod.GET - ): - self._check_mobile_or_mac_platform() - self.invoke_method( - "load_request", - arguments={"url": url, "method": method.value}, - ) - - def run_javascript(self, value: str): - self._check_mobile_or_mac_platform() - self.invoke_method("run_javascript", arguments={"value": value}) - - def load_html(self, value: str, base_url: Optional[str] = None): - self._check_mobile_or_mac_platform() - self.invoke_method( - "load_html", arguments={"value": value, "base_url": base_url} - ) - - def scroll_to(self, x: int, y: int): - self._check_mobile_or_mac_platform() - self.invoke_method("scroll_to", arguments={"x": str(x), "y": str(y)}) - - def scroll_by(self, x: int, y: int): - self._check_mobile_or_mac_platform() - self.invoke_method("scroll_by", arguments={"x": str(x), "y": str(y)}) - - # bgcolor - @property - def bgcolor(self) -> Optional[ColorValue]: - return self.__bgcolor - - @bgcolor.setter - def bgcolor(self, value: Optional[ColorValue]): - self.__bgcolor = value - self._set_enum_attr("bgcolor", value, ColorEnums) - - # url - @property - def url(self) -> str: - return self._get_attr("url") - - @url.setter - def url(self, value: str): - self._set_attr("url", value) - if self.page: - self.load_request(value, WebviewRequestMethod.GET) - - # enable_javascript - @property - def enable_javascript(self) -> bool: - return self._get_attr("enableJavascript", data_type="bool", def_value=False) - - @enable_javascript.setter - def enable_javascript(self, value: Optional[bool]): - self._set_attr("enableJavascript", value) - if self.page and value is not None: - self.invoke_method( - "set_javascript_mode", - arguments={"value": str(value)}, - ) - - # prevent_link - @property - def prevent_link(self) -> str: - return self._get_attr("prevent_link") - - @prevent_link.setter - def prevent_link(self, value: str): - self._set_attr("prevent_link", value) - - # on_page_started - @property - def on_page_started(self) -> OptionalControlEventCallable: - return self._get_event_handler("page_started") - - @on_page_started.setter - def on_page_started(self, handler: OptionalControlEventCallable): - self._add_event_handler("page_started", handler) - - # on_page_ended - @property - def on_page_ended(self) -> OptionalControlEventCallable: - return self._get_event_handler("page_ended") - - @on_page_ended.setter - def on_page_ended(self, handler: OptionalControlEventCallable): - self._add_event_handler("page_ended", handler) - - # on_web_resource_error - @property - def on_web_resource_error(self) -> OptionalControlEventCallable: - return self._get_event_handler("web_resource_error") - - @on_web_resource_error.setter - def on_web_resource_error(self, handler: OptionalControlEventCallable): - self._add_event_handler("web_resource_error", handler) - - # on_progress - @property - def on_progress(self) -> OptionalControlEventCallable: - return self._get_event_handler("progress") - - @on_progress.setter - def on_progress(self, handler: OptionalControlEventCallable): - self._add_event_handler("progress", handler) - - # on_url_change - @property - def on_url_change(self) -> OptionalControlEventCallable: - return self._get_event_handler("url_change") - - @on_url_change.setter - def on_url_change(self, handler: OptionalControlEventCallable): - self._add_event_handler("url_change", handler) - - # on_scroll - @property - def on_scroll(self) -> OptionalEventCallable[WebviewScrollEvent]: - return self.__on_scroll.handler - - @on_scroll.setter - def on_scroll(self, handler: OptionalEventCallable[WebviewScrollEvent]): - self.__on_scroll.handler = handler - - # on_console_message - @property - def on_console_message(self) -> OptionalEventCallable[WebviewConsoleMessageEvent]: - return self.__on_console_message.handler - - @on_console_message.setter - def on_console_message( - self, handler: OptionalEventCallable[WebviewConsoleMessageEvent] - ): - self.__on_console_message.handler = handler - - # on_javascript_alert_dialog - @property - def on_javascript_alert_dialog( - self, - ) -> OptionalEventCallable[WebviewJavaScriptEvent]: - return self.__on_javascript_alert_dialog.handler - - @on_javascript_alert_dialog.setter - def on_javascript_alert_dialog( - self, handler: OptionalEventCallable[WebviewJavaScriptEvent] - ): - self.__on_javascript_alert_dialog.handler = handler diff --git a/sdk/python/packages/flet/src/flet/core/window_drag_area.py b/sdk/python/packages/flet/src/flet/core/window_drag_area.py deleted file mode 100644 index 23df8f10d2..0000000000 --- a/sdk/python/packages/flet/src/flet/core/window_drag_area.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import Any - -from flet.core.control import Control -from flet.core.gesture_detector import DragStartEvent, GestureDetector, TapEvent -from flet.core.types import OptionalEventCallable - - -class WindowDragArea(GestureDetector): - """ - A control for drag to move, maximize and restore application window. - - When you have hidden the title bar with `page.window_title_bar_hidden`, you can add this control to move the window position. - - Example: - ``` - import flet as ft - - def main(page: ft.Page): - page.window_title_bar_hidden = True - page.window_title_bar_buttons_hidden = True - - page.add( - ft.Row( - [ - ft.WindowDragArea(ft.Container(ft.Text("Drag this area to move, maximize and restore application window."), bgcolor=ft.colors.AMBER_300, padding=10), expand=True), - ft.IconButton(ft.icons.CLOSE, on_click=lambda _: page.window_close()) - ] - ) - ) - - ft.app(target=main) - ``` - - ----- - - Online docs: https://flet.dev/docs/controls/windowdragarea - """ - - def __init__( - self, - content: Control, - maximizable: bool = True, - on_double_tap: OptionalEventCallable["TapEvent"] = None, - on_pan_start: OptionalEventCallable["DragStartEvent"] = None, - **kwargs: Any, - ): - GestureDetector.__init__( - self, - content=content, - on_double_tap=self.handle_double_tap, - on_pan_start=self.handle_pan_start, - **kwargs, - ) - - self.maximizable = maximizable - self._on_double_tap = on_double_tap - self._on_pan_start = on_pan_start - - def before_update(self): - super().before_update() - assert self.content.visible, "content must be visible" - - def handle_double_tap(self, e: TapEvent): - if self.maximizable and self.page.window.maximizable: - self.page.window.maximized = not self.page.window.maximized - self.page.update() - - if self._on_double_tap is not None and self.page.window.maximized: - self._on_double_tap(e) - - def handle_pan_start(self, e: DragStartEvent): - self.page.window.start_dragging() - if self._on_pan_start is not None: - self._on_pan_start(e) diff --git a/sdk/python/packages/flet/src/flet/fastapi/__init__.py b/sdk/python/packages/flet/src/flet/fastapi/__init__.py index eb2d1fb051..e06e5307d3 100644 --- a/sdk/python/packages/flet/src/flet/fastapi/__init__.py +++ b/sdk/python/packages/flet/src/flet/fastapi/__init__.py @@ -1 +1,17 @@ -from flet_web.fastapi import * +from flet_web.fastapi.app import app +from flet_web.fastapi.flet_app import FletApp +from flet_web.fastapi.flet_app_manager import app_manager +from flet_web.fastapi.flet_fastapi import FastAPI +from flet_web.fastapi.flet_oauth import FletOAuth +from flet_web.fastapi.flet_static_files import FletStaticFiles +from flet_web.fastapi.flet_upload import FletUpload + +__all__ = [ + "FastAPI", + "FletApp", + "FletOAuth", + "FletStaticFiles", + "FletUpload", + "app", + "app_manager", +] diff --git a/sdk/python/packages/flet/src/flet/flet_socket_server.py b/sdk/python/packages/flet/src/flet/flet_socket_server.py deleted file mode 100644 index fbd9f3f878..0000000000 --- a/sdk/python/packages/flet/src/flet/flet_socket_server.py +++ /dev/null @@ -1,205 +0,0 @@ -import asyncio -import json -import logging -import os -import struct -import sys -import tempfile -from concurrent.futures import ThreadPoolExecutor -from pathlib import Path -from typing import List, Optional - -import flet -from flet.core.local_connection import LocalConnection -from flet.core.protocol import ( - ClientActions, - ClientMessage, - Command, - CommandEncoder, - PageCommandResponsePayload, - PageCommandsBatchResponsePayload, - RegisterWebClientRequestPayload, -) -from flet.core.pubsub.pubsub_hub import PubSubHub -from flet.utils import get_free_tcp_port, is_windows, random_string - -logger = logging.getLogger(flet.__name__) - - -class FletSocketServer(LocalConnection): - def __init__( - self, - loop: asyncio.AbstractEventLoop, - port: int = 0, - uds_path: Optional[str] = None, - on_event=None, - on_session_created=None, - blocking=False, - executor: Optional[ThreadPoolExecutor] = None, - ): - super().__init__() - self.__send_queue = asyncio.Queue() - self.__port = port - self.__uds_path = uds_path - self.__on_event = on_event - self.__on_session_created = on_session_created - self.__blocking = blocking - self.__loop = loop - self.__executor = executor - self.pubsubhub = PubSubHub(loop=loop, executor=executor) - self.__running_tasks = set() - - async def start(self): - self.__connected = False - self.__receive_loop_task = None - self.__send_loop_task = None - if is_windows() or self.__port > 0: - # TCP - host = "localhost" - port = self.__port if self.__port > 0 else get_free_tcp_port() - self.page_url = f"tcp://{host}:{port}" - logger.info(f"Starting up TCP server on {host}:{port}") - server = await asyncio.start_server(self.handle_connection, host, port) - else: - # UDS - if not self.__uds_path: - self.__uds_path = str( - Path(tempfile.gettempdir()).joinpath(random_string(10)) - ) - if os.path.exists(self.__uds_path): - os.remove(self.__uds_path) - self.page_url = self.__uds_path - logger.info(f"Starting up UDS server on {self.__uds_path}") - server = await asyncio.start_unix_server( - self.handle_connection, self.__uds_path - ) - - if self.__blocking: - self.__server = None - await server.serve_forever() - else: - self.__server = asyncio.create_task(server.serve_forever()) - - async def handle_connection( - self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter - ): - if not self.__connected: - self.__connected = True - logger.debug("Connected new TCP client") - self.__receive_loop_task = asyncio.create_task(self.__receive_loop(reader)) - self.__send_loop_task = asyncio.create_task(self.__send_loop(writer)) - - async def __receive_loop(self, reader: asyncio.StreamReader): - while True: - try: - raw_msglen = await reader.readexactly(4) - except Exception: - return None - - if not raw_msglen: - return None - msglen = struct.unpack(">I", raw_msglen)[0] - - data = await reader.readexactly(msglen) - await self.__on_message(data.decode("utf-8")) - - async def __send_loop(self, writer: asyncio.StreamWriter): - while True: - message = await self.__send_queue.get() - try: - data = message.encode("utf-8") - msg = struct.pack(">I", len(data)) + data - writer.write(msg) - # await writer.drain() - logger.debug(f"sent to TCP: {len(msg)}") - except Exception: - # re-enqueue the message to repeat it when re-connected - self.__send_queue.put_nowait(message) - raise - - async def __on_message(self, data: str): - logger.debug(f"_on_message: {data}") - msg_dict = json.loads(data) - msg = ClientMessage(**msg_dict) - task = None - if msg.action == ClientActions.REGISTER_WEB_CLIENT: - self._client_details = RegisterWebClientRequestPayload(**msg.payload) - - # register response - self.__send(self._create_register_web_client_response()) - - # start session - if self.__on_session_created is not None: - task = asyncio.create_task( - self.__on_session_created(self._create_session_handler_arg()) - ) - - elif msg.action == ClientActions.PAGE_EVENT_FROM_WEB: - if self.__on_event is not None: - task = asyncio.create_task( - self.__on_event(self._create_page_event_handler_arg(msg)) - ) - - elif msg.action == ClientActions.UPDATE_CONTROL_PROPS: - if self.__on_event is not None: - task = asyncio.create_task( - self.__on_event(self._create_update_control_props_handler_arg(msg)) - ) - else: - # it's something else - raise Exception(f'Unknown message "{msg.action}": {msg.payload}') - - if task: - self.__running_tasks.add(task) - task.add_done_callback(self.__running_tasks.discard) - - def send_command(self, session_id: str, command: Command): - result, message = self._process_command(command) - if message: - self.__send(message) - return PageCommandResponsePayload(result=result, error="") - - def send_commands(self, session_id: str, commands: List[Command]): - results = [] - messages = [] - for command in commands: - result, message = self._process_command(command) - if command.name in ["add", "get"]: - results.append(result) - if message: - messages.append(message) - if len(messages) > 0: - self.__send(ClientMessage(ClientActions.PAGE_CONTROLS_BATCH, messages)) - return PageCommandsBatchResponsePayload(results=results, error="") - - def __send(self, message: ClientMessage): - j = json.dumps(message, cls=CommandEncoder, separators=(",", ":")) - logger.debug(f"__send: {j}") - self.__loop.call_soon_threadsafe(self.__send_queue.put_nowait, j) - - async def close(self): - logger.debug("Closing connection...") - - logger.debug(f"Disconnecting all pages...") - while self.sessions: - _, page = self.sessions.popitem() - await page._disconnect(0) - - if self.__executor: - logger.debug("Shutting down thread pool...") - if sys.version_info >= (3, 9): - self.__executor.shutdown(wait=False, cancel_futures=True) - else: - self.__executor.shutdown(wait=False) - - # close socket - if self.__receive_loop_task: - self.__receive_loop_task.cancel() - if self.__send_loop_task: - self.__send_loop_task.cancel() - if self.__server: - self.__server.cancel() - - # remove UDS path - if self.__uds_path and os.path.exists(self.__uds_path): - os.unlink(self.__uds_path) diff --git a/sdk/python/packages/flet/src/flet/map/__init__.py b/sdk/python/packages/flet/src/flet/map/__init__.py deleted file mode 100644 index c77fe347cf..0000000000 --- a/sdk/python/packages/flet/src/flet/map/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -from flet.core.map.circle_layer import CircleLayer, CircleMarker -from flet.core.map.map import ( - Map, - MapEvent, - MapEventSource, - MapHoverEvent, - MapInteractionConfiguration, - MapInteractiveFlag, - MapLatitudeLongitude, - MapLatitudeLongitudeBounds, - MapMultiFingerGesture, - MapPointerDeviceType, - MapPointerEvent, - MapPositionChangeEvent, - MapTapEvent, -) -from flet.core.map.marker_layer import Marker, MarkerLayer -from flet.core.map.polygon_layer import PolygonLayer, PolygonMarker -from flet.core.map.polyline_layer import ( - DashedStrokePattern, - DottedStrokePattern, - PatternFit, - PolylineLayer, - PolylineMarker, - SolidStrokePattern, -) -from flet.core.map.rich_attribution import RichAttribution -from flet.core.map.simple_attribution import SimpleAttribution -from flet.core.map.text_source_attribution import TextSourceAttribution -from flet.core.map.tile_layer import MapTileLayerEvictErrorTileStrategy, TileLayer diff --git a/sdk/python/packages/flet/src/flet/matplotlib_chart.py b/sdk/python/packages/flet/src/flet/matplotlib_chart.py deleted file mode 100644 index 3907aa9269..0000000000 --- a/sdk/python/packages/flet/src/flet/matplotlib_chart.py +++ /dev/null @@ -1 +0,0 @@ -from flet.core.matplotlib_chart import MatplotlibChart diff --git a/sdk/python/packages/flet/src/flet/messaging/connection.py b/sdk/python/packages/flet/src/flet/messaging/connection.py new file mode 100644 index 0000000000..aa80edd72d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/connection.py @@ -0,0 +1,122 @@ +import logging +from asyncio import AbstractEventLoop +from concurrent.futures import ThreadPoolExecutor +from typing import Any, Optional + +from flet.messaging.protocol import ClientMessage +from flet.pubsub.pubsub_hub import PubSubHub + +logger = logging.getLogger("flet") + + +class Connection: + """ + Base messaging connection interface used by a Flet session. + + Concrete implementations provide transport-specific behavior (for example, + socket or browser-backed messaging) and must implement message sending and + platform-specific service methods. + """ + + def __init__(self): + self.page_name: str = "" + self.page_url: Optional[str] = None + self.__pubsubhub = None + self.__loop: Optional[AbstractEventLoop] = None + self.__executor: Optional[ThreadPoolExecutor] = None + + @property + def loop(self) -> AbstractEventLoop: + """ + Returns the event loop associated with this connection. + + Returns: + Initialized asyncio event loop. + + Raises: + RuntimeError: If the loop has not been assigned. + """ + if self.__loop is None: + raise RuntimeError("Loop not initialized") + return self.__loop + + @loop.setter + def loop(self, value): + self.__loop = value + + @property + def executor(self) -> ThreadPoolExecutor: + """ + Returns the thread pool executor used by this connection. + + Returns: + Initialized thread pool executor. + + Raises: + RuntimeError: If the executor has not been assigned. + """ + if self.__executor is None: + raise RuntimeError("Executor not initialized") + return self.__executor + + @executor.setter + def executor(self, value): + self.__executor = value + + @property + def pubsubhub(self) -> PubSubHub: + """ + Returns the pub/sub hub used to broadcast session messages. + + Returns: + Initialized pub/sub hub instance. + + Raises: + RuntimeError: If the pub/sub hub has not been assigned. + """ + if self.__pubsubhub is None: + raise RuntimeError("PubSubHub not initialized") + return self.__pubsubhub + + @pubsubhub.setter + def pubsubhub(self, value: PubSubHub): + self.__pubsubhub = value + + def send_message(self, message: ClientMessage): + """ + Sends a message to the connected Flet client. + + Args: + message: Client message to send. + """ + raise NotImplementedError() + + def get_upload_url(self, file_name: str, expires: int) -> str: + """ + Returns an upload URL for built-in file upload storage. + + Args: + file_name: Relative path of the file in upload storage. + expires: URL expiration time in seconds. + + Returns: + The upload URL. + """ + raise NotImplementedError() + + def oauth_authorize(self, attrs: dict[str, Any]): + """ + Initiates OAuth authorization on the client side. + + Args: + attrs: Authorization attributes passed to the client transport. + """ + raise NotImplementedError() + + def dispose(self): + """ + Releases connection resources associated with the current session. + + Subclasses can override this method to clean up transport-specific state. + """ + pass diff --git a/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py b/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py new file mode 100644 index 0000000000..73596cb4bc --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/flet_socket_server.py @@ -0,0 +1,452 @@ +import asyncio +import contextlib +import inspect +import logging +import os +import tempfile +import traceback +from collections.abc import Awaitable +from concurrent.futures import ThreadPoolExecutor +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable, Optional + +import msgpack + +from flet.controls.base_control import BaseControl +from flet.messaging.connection import Connection +from flet.messaging.protocol import ( + ClientAction, + ClientMessage, + ControlEventBody, + InvokeMethodResponseBody, + RegisterClientRequestBody, + RegisterClientResponseBody, + UpdateControlPropsBody, + configure_encode_object_for_msgpack, + decode_ext_from_msgpack, +) +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub +from flet.utils import get_free_tcp_port, is_windows, random_string + +if TYPE_CHECKING: + from flet.app import AppCallable + +logger = logging.getLogger("flet") +transport_log = logging.getLogger("flet_transport") + + +class FletSocketServer(Connection): + """ + Socket-based transport for Flet backend messaging. + + This connection accepts a single active client at a time over TCP or Unix domain + socket (UDS), decodes protocol frames, manages session lifecycle, and forwards + outbound messages through an internal send queue. + """ + + def __init__( + self, + loop: asyncio.AbstractEventLoop, + port: int = 0, + uds_path: Optional[str] = None, + on_session_created: Optional[Callable[[Session], Awaitable[Any]]] = None, + before_main: Optional["AppCallable"] = None, + blocking: bool = False, + executor: Optional[ThreadPoolExecutor] = None, + ): + super().__init__() + self.__server = None + self.__send_loop_task: asyncio.Task | None = None + self.__receive_loop_task: asyncio.Task | None = None + self.__connected: bool | None = None + self.__writer: asyncio.StreamWriter | None = None + self.__connection_lock = asyncio.Lock() + self.__connection_token = 0 + self.session = None + self.__send_queue: asyncio.Queue[bytes] | None = None + self.__port = port + self.__uds_path = uds_path + self.__on_session_created = on_session_created + self.__before_main = before_main + self.__blocking = blocking + self.__running_tasks = set() + self.loop = loop + self.executor = executor + self.pubsubhub = PubSubHub(loop=loop, executor=executor) + + async def start(self): + """ + Starts listening for client connections. + + Transport selection: + - TCP on Windows or when `port > 0`; + - UDS on non-Windows when `port == 0`. + + When `blocking=True`, this method waits on `serve_forever()`. Otherwise it + schedules serving in a background task and returns. + """ + self.__connected = False + self.__receive_loop_task = None + self.__send_loop_task = None + self.__writer = None + self.__send_queue = None + if is_windows() or self.__port > 0: + # TCP + host = "localhost" + port = self.__port if self.__port > 0 else get_free_tcp_port() + self.page_url = f"tcp://{host}:{port}" + logger.info("Starting up TCP server on %s:%s", host, port) + self.__server = await asyncio.start_server( + self.handle_connection, host, port + ) + else: + # UDS + if not self.__uds_path: + self.__uds_path = str( + Path(tempfile.gettempdir()).joinpath(random_string(10)) + ) + if os.path.exists(self.__uds_path): + os.remove(self.__uds_path) + self.page_url = self.__uds_path + logger.info("Starting up UDS server on %s", self.__uds_path) + self.__server = await asyncio.start_unix_server( + self.handle_connection, self.__uds_path + ) + + if self.__blocking: + self.__serve_task = None + await self.__server.serve_forever() + else: + self.__serve_task = asyncio.create_task(self.__server.serve_forever()) + + async def handle_connection( + self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter + ): + """ + Handles an incoming socket connection. + + Only one active connection is allowed. A new connection replaces any existing + one, starts paired receive/send loops, and remains active until one loop + completes or the connection is superseded. + + Args: + reader: Socket stream reader. + writer: Socket stream writer. + """ + async with self.__connection_lock: + await self.__terminate_active_connection_locked(reason="replaced") + + self.__connected = True + self.__connection_token += 1 + connection_token = self.__connection_token + self.__writer = writer + send_queue: asyncio.Queue[bytes] = asyncio.Queue() + self.__send_queue = send_queue + + logger.debug("Connected new socket client") + + receive_task = asyncio.create_task( + self.__receive_loop(reader, connection_token) + ) + send_task = asyncio.create_task( + self.__send_loop(writer, send_queue, connection_token) + ) + self.__receive_loop_task = receive_task + self.__send_loop_task = send_task + + try: + _, pending = await asyncio.wait( + [receive_task, send_task], + return_when=asyncio.FIRST_COMPLETED, + ) + + for task in pending: + task.cancel() + with contextlib.suppress(asyncio.CancelledError): + await task + finally: + terminated_active = False + async with self.__connection_lock: + if ( + self.__writer is writer + and self.__connection_token == connection_token + ): + await self.__terminate_active_connection_locked( + reason="client_disconnected" + ) + terminated_active = True + + if not terminated_active: + writer.close() + with contextlib.suppress(Exception): + await writer.wait_closed() + logger.debug("Connection writer closed.") + + async def __terminate_active_connection_locked(self, reason: str) -> None: + """ + Terminates the currently active connection and related tasks. + + Locking contract: + Caller must hold `self.__connection_lock`. + + Actions performed: + - closes current session (if present); + - cancels receive/send and running handler tasks; + - closes active writer and clears connection state. + + Args: + reason: Diagnostic reason used in debug logs. + """ + if not self.__connected and self.__writer is None: + logger.debug("No active connection to terminate.") + return + + logger.debug("Terminating existing connection (%s).", reason) + + session_to_close = self.session + self.session = None + + if session_to_close is not None: + try: + session_to_close.close() + except Exception: + logger.debug("Error closing session.", exc_info=True) + + tasks_to_cancel: list[asyncio.Task] = [] + for task in [ + self.__receive_loop_task, + self.__send_loop_task, + *self.__running_tasks, + ]: + if task and not task.done(): + tasks_to_cancel.append(task) + + if tasks_to_cancel: + for task in tasks_to_cancel: + task.cancel() + with contextlib.suppress(Exception): + await asyncio.gather(*tasks_to_cancel, return_exceptions=True) + + self.__running_tasks.clear() + self.__receive_loop_task = None + self.__send_loop_task = None + + old_writer = self.__writer + self.__writer = None + self.__send_queue = None + self.__connected = False + + if old_writer is not None: + old_writer.close() + with contextlib.suppress(Exception): + await old_writer.wait_closed() + + async def __receive_loop(self, reader: asyncio.StreamReader, connection_token: int): + """ + Reads and dispatches inbound MsgPack frames from the socket. + + The loop exits when: + - socket EOF is reached; + - the connection token no longer matches (connection replaced); + - the task is cancelled. + + Args: + reader: Socket stream reader to consume bytes from. + connection_token: Token identifying the connection generation. + """ + unpacker = msgpack.Unpacker(ext_hook=decode_ext_from_msgpack) + try: + while True: + buf = await reader.read(1024 * 1024) + if not buf: + break + unpacker.feed(buf) + for msg in unpacker: + if self.__connection_token != connection_token: + return + await self.__on_message(msg) + except asyncio.CancelledError: + logger.debug("Receive loop cancelled.") + except Exception as e: + logger.debug("Error receiving socket data from Flet client: %s", e) + finally: + logger.debug("Receive loop exiting.") + + async def __send_loop( + self, + writer: asyncio.StreamWriter, + send_queue: asyncio.Queue[bytes], + connection_token: int, + ): + """ + Sends outbound frames from the queue to the active socket writer. + + The loop exits when the connection token changes (connection replaced) or + when cancelled. + + Args: + writer: Socket writer used to send bytes. + send_queue: Queue of pre-encoded MsgPack frames. + connection_token: Token identifying the connection generation. + """ + try: + while True: + if self.__connection_token != connection_token: + return + message = await send_queue.get() + writer.write(message) + await writer.drain() + except asyncio.CancelledError: + logger.debug("Send loop cancelled.") + except Exception as e: + logger.debug("Error in send loop: %s", e) + finally: + logger.debug("Send loop exiting.") + + async def __on_message(self, data: Any): + """ + Processes one decoded protocol frame from the client. + + Supported actions: + - `REGISTER_CLIENT`: create session, apply initial page patch (for new + sessions), run `before_main`, and send register response; + - `CONTROL_EVENT`: dispatch control event to session; + - `UPDATE_CONTROL_PROPS`: apply property patch to a control; + - `INVOKE_METHOD`: deliver invoke-method response back to session waiter. + + Args: + data: Decoded frame in the form `[action_code, body]`. + + Raises: + RuntimeError: If the action code is unknown. + """ + action = ClientAction(data[0]) + body = data[1] + transport_log.debug("_on_message: %s %s", action, body) + task = None + if action == ClientAction.REGISTER_CLIENT: + req = RegisterClientRequestBody(**body) + + # create new session + self.session = Session(self) + + # apply page patch + if not req.session_id: + self.session.apply_page_patch(req.page) + + register_error = "" + try: + if inspect.iscoroutinefunction(self.__before_main): + await self.__before_main(self.session.page) + elif callable(self.__before_main): + self.__before_main(self.session.page) + except Exception as e: + register_error = f"{e}\n{traceback.format_exc()}" + logger.error("Unhandled error in before_main() handler", exc_info=True) + + # register response + self.send_message( + ClientMessage( + ClientAction.REGISTER_CLIENT, + RegisterClientResponseBody( + session_id=self.session.id, + page_patch=self.session.get_page_patch(), + error=register_error, + ), + ) + ) + + if register_error: + self.session.error(register_error) + elif self.__on_session_created is not None: + task = asyncio.create_task(self.__on_session_created(self.session)) + + elif action == ClientAction.CONTROL_EVENT: + req = ControlEventBody(**body) + task = asyncio.create_task( + self.session.dispatch_event(req.target, req.name, req.data) + ) + + elif action == ClientAction.UPDATE_CONTROL_PROPS: + req = UpdateControlPropsBody(**body) + self.session.apply_patch(req.id, req.props) + + elif action == ClientAction.INVOKE_METHOD: + req = InvokeMethodResponseBody(**body) + self.session.handle_invoke_method_results( + req.control_id, req.call_id, req.result, req.error + ) + + else: + # it's something else + raise RuntimeError(f'Unknown message "{action}": {body}') + + if task: + self.__running_tasks.add(task) + task.add_done_callback(self.__running_tasks.discard) + + def send_message(self, message: ClientMessage): + """ + Encodes and queues an outbound message for the active connection. + + If no active send queue exists (no connected client), the message is dropped. + + Args: + message: Protocol message to send. + """ + transport_log.debug("send_message: %s", message) + m = msgpack.packb( + [message.action, message.body], + default=configure_encode_object_for_msgpack(BaseControl), + ) + if self.__send_queue is not None: + self.__send_queue.put_nowait(m) + + async def close(self): + """ + Gracefully shuts down the socket server and transport resources. + + This method terminates the active connection, stops the listening server, + shuts down the optional executor, cancels serving tasks, and removes a UDS + socket file when used. + """ + logger.debug("Closing connection...") + + async with self.__connection_lock: + await self.__terminate_active_connection_locked(reason="close()") + + if self.__server: + logger.debug("Shutting down TCP server...") + self.__server.close() + await self.__server.wait_closed() + + if self.executor: + logger.debug("Shutting down thread pool...") + self.executor.shutdown(wait=False, cancel_futures=True) + + logger.debug("Cancelling pending tasks...") + + tasks = [ + task + for task in [ + self.__serve_task, + ] + if task + ] + + for task in tasks: + task.cancel() + + try: + await asyncio.wait_for( + asyncio.gather(*tasks, return_exceptions=True), timeout=1.0 + ) + except asyncio.TimeoutError: + logger.warning("Some tasks did not exit in time, skipping.") + except asyncio.CancelledError: + pass + if self.__uds_path and os.path.exists(self.__uds_path): + os.unlink(self.__uds_path) + + logger.debug("Connection closed.") diff --git a/sdk/python/packages/flet/src/flet/messaging/protocol.py b/sdk/python/packages/flet/src/flet/messaging/protocol.py new file mode 100644 index 0000000000..9ddde6e431 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/protocol.py @@ -0,0 +1,491 @@ +import datetime +from dataclasses import dataclass, fields, is_dataclass +from enum import Enum +from typing import Any + +import msgpack + +from flet.controls.duration import Duration +from flet.controls.value_types import _UNSET, Value + + +def _get_root_dataclass_field(cls, field_name): + """ + Returns the field definition from the earliest dataclass in the MRO that declares \ + `field_name`. This lets us recover defaults configured on base controls before \ + subclasses override them. + """ + + for base in reversed(cls.__mro__): + dataclass_fields = getattr(base, "__dataclass_fields__", None) + if dataclass_fields and field_name in dataclass_fields: + return dataclass_fields[field_name] + return None + + +def configure_encode_object_for_msgpack(control_cls): + """ + Builds an object encoder callback for Flet's MessagePack transport. + + The returned function is passed to `msgpack.packb(..., default=...)` and handles + protocol-specific serialization rules for dataclasses, enums, date/time objects, + :class:`~flet.Duration`, and extension values exchanged with Dart. + + Encoding behavior highlights: + - dataclasses are converted to dictionaries with control-aware default pruning; + - event handler fields (`on_*`) are serialized as booleans (`True` when set); + - list/dict/dataclass snapshots are captured into `__prev_*` attributes for patch + diffing unless the object is frozen (`_frozen`); + - datetime/date/time and duration values are encoded as MsgPack extension types; + - callables are rejected to prevent accidental method serialization. + + Args: + control_cls: Base control type used to apply root-dataclass default comparison + rules for Flet controls. + + Returns: + Callable that serializes unsupported objects for MsgPack packing. + """ + + def encode_object_for_msgpack(obj): + """Encode object for MessagePack.""" + if is_dataclass(obj): + r = {} + prev_lists = {} + prev_dicts = {} + prev_classes = {} + + _values = getattr(obj, "_values", None) + _structural_fields = getattr(type(obj), "_structural_fields", None) + is_control = isinstance(obj, control_cls) + + if ( + _values is not None + and _structural_fields is not None + and (is_control or isinstance(obj, Value)) + ): + # ── Fast path for @control / @value types ──────────────────── + # Only non-default values are in _values; structural fields + # (lists, dicts, nested dataclasses, and internal scalars like + # _i / _c) are iterated separately — there are typically very + # few of them. + _event_fields = getattr(type(obj), "_event_fields", frozenset()) + _root_defaults = getattr(type(obj), "_root_defaults", {}) + + # 1. Emit sparse non-default Prop values. + # Even though these are Prop-tracked scalars, their runtime + # value may be a dataclass, list, or dict (e.g. content=…). + # Those must be added to the prev_* snapshots so that the + # next diff can compare old vs new correctly. + for fname, v in _values.items(): + if v is None: + continue + # Skip if the value happens to equal the Dart-side root + # default (e.g. a subclass Prop was set to the base value). + root_def = _root_defaults.get(fname, _UNSET) + if root_def is not _UNSET and v == root_def: + continue + if is_dataclass(v): + r[fname] = v + prev_classes[fname] = v + elif isinstance(v, list): + v = v[:] + # Values stored in _values were assigned explicitly, so + # an empty list is a meaningful override, not a default + # structural field to omit. + r[fname] = v + prev_lists[fname] = v + elif isinstance(v, dict): + v = v.copy() + # Same reasoning as lists above: preserve explicit empty + # dictionaries while keeping structural defaults sparse. + r[fname] = v + prev_dicts[fname] = v + else: + r[fname] = True if fname in _event_fields else v + + # 2. Emit subclass-overridden defaults that are absent from + # _values because they equal the subclass Prop.default. + for fname, v in getattr(type(obj), "_override_props", {}).items(): + if fname not in r and v is not None: + r[fname] = v + + # 3. Structural fields: lists, dicts, nested dataclasses, and + # fixed-scalar internals (_i, _c, …). + obj_dc_fields = type(obj).__dataclass_fields__ + for fname in _structural_fields: + v = getattr(obj, fname) + if isinstance(v, list): + v = v[:] + if len(v) > 0: + r[fname] = v + prev_lists[fname] = v + elif isinstance(v, dict): + v = v.copy() + if len(v) > 0: + r[fname] = v + prev_dicts[fname] = v + elif is_dataclass(v): + r[fname] = v + prev_classes[fname] = v + elif v is not None: + # Scalar structural field (e.g. _i, _c). + fmeta = obj_dc_fields.get(fname) + default_value = fmeta.default if fmeta is not None else _UNSET + root_field = _get_root_dataclass_field(type(obj), fname) + if root_field is not None: + default_value = root_field.default + if v != default_value: + r[fname] = v + else: + # ── Slow path for plain @dataclass types ───────────────────── + for field in fields(obj): + if "skip" in field.metadata: + continue + v = getattr(obj, field.name) + if isinstance(v, list): + v = v[:] + if len(v) > 0: + r[field.name] = v + prev_lists[field.name] = v + elif isinstance(v, dict): + v = v.copy() + if len(v) > 0: + r[field.name] = v + prev_dicts[field.name] = v + elif field.name.startswith("on_") and field.metadata.get( + "event", True + ): + v = v is not None + if v: + r[field.name] = v + elif is_dataclass(v): + r[field.name] = v + prev_classes[field.name] = v + else: + default_value = field.default + if is_control: + root_field = _get_root_dataclass_field( + type(obj), field.name + ) + if root_field is not None: + default_value = root_field.default + if v is not None and (v != default_value or not is_control): + r[field.name] = v + + if not hasattr(obj, "_frozen"): + setattr(obj, "__prev_lists", prev_lists) + setattr(obj, "__prev_dicts", prev_dicts) + setattr(obj, "__prev_classes", prev_classes) + + return r + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, (datetime.datetime, datetime.date)): + if isinstance(obj, datetime.datetime): + if obj.tzinfo is None: # naive + try: + # May fail on Windows for out-of-range values. + # See: https://github.com/flet-dev/flet/issues/5895 + obj = obj.astimezone() + except Exception: + # Attach current local tzinfo or UTC if that fails. + try: + tz = datetime.datetime.now().astimezone().tzinfo + except Exception: + tz = datetime.timezone.utc + obj = obj.replace(tzinfo=tz) + # Normalize to UTC to ensure cross-platform consistency. + obj = obj.astimezone(datetime.timezone.utc) + return msgpack.ExtType(1, obj.isoformat().encode("utf-8")) + elif isinstance(obj, datetime.time): + return msgpack.ExtType(2, obj.strftime("%H:%M").encode("utf-8")) + elif isinstance(obj, Duration): + return msgpack.ExtType(3, obj.in_microseconds) + elif callable(obj): + raise RuntimeError(f"Cannot serialize method: {obj}") from None + return obj + + return encode_object_for_msgpack + + +def decode_ext_from_msgpack(code, data): + """Decode MessagePack extension types used in Flet protocol.""" + if code == 1: + return datetime.datetime.fromisoformat(data.decode("utf-8")) + elif code == 2: + return datetime.time(*map(int, data.decode("utf-8").split(":"))) + elif code == 3: + return Duration.from_unit(microseconds=int(data)) + elif code == 4: + return data.decode("utf-8") + return msgpack.ExtType(code, data) + + +class ClientAction(Enum): + """ + Wire-level action codes exchanged between Python and Dart clients. + + Integer values must stay in sync with Dart `MessageAction` values because + protocol frames are encoded as `[action_code, body]`. + """ + + REGISTER_CLIENT = 1 + """ + Client registration handshake request/response. + """ + + PATCH_CONTROL = 2 + """ + Server-to-client control tree patch payload. + """ + + CONTROL_EVENT = 3 + """ + Client-to-server control event notification. + """ + + UPDATE_CONTROL_PROPS = 4 + """ + Client-to-server incremental control property update. + """ + + INVOKE_METHOD = 5 + """ + Bidirectional control method invocation and result payload. + """ + + SESSION_CRASHED = 6 + """ + Server-to-client fatal session error notification. + """ + + PYTHON_OUTPUT = 7 + """ + Worker-to-Dart stdout/stderr line from an embedded Pyodide app + (only emitted when the host wires `loadPyodide({stdout, stderr})`). + Body shape: `{text: str, is_stderr: bool}`. + """ + + +@dataclass +class ClientMessage: + """ + Top-level protocol frame with action and payload. + + Messages are serialized as a two-item sequence: `[action_code, body]`. + """ + + action: ClientAction + """ + Action discriminator for this message. + """ + + body: Any + """ + Action-specific payload object. + """ + + +@dataclass +class RegisterClientRequestBody: + """ + Payload sent by the client to register with the backend session. + + This is emitted from Dart during startup/reconnect and includes a current page + snapshot that can be used for rehydration. + """ + + session_id: str + """ + Previously assigned session ID, if any. + + Initial registration may provide an empty or null-equivalent value. + """ + + page_name: str + """ + Logical page name derived from the current app URL. + """ + + page: dict[str, Any] + """ + Initial page state snapshot (route, media, window, and related metadata). + """ + + +@dataclass +class SessionPayload: + """ + Session snapshot payload model. + + This structure represents a session identifier plus serialized controls map and is + currently reserved/legacy in the active transport flow. + """ + + id: str + """ + Session identifier. + """ + + controls: dict[str, dict[str, Any]] + """ + Serialized controls keyed by control ID. + """ + + +@dataclass +class RegisterClientResponseBody: + """ + Payload returned by the backend after client registration. + + Contains the active session ID, an initial page patch, and optional startup error + text. + """ + + session_id: str + """ + Assigned backend session ID. + """ + + page_patch: Any + """ + Patch payload used to initialize/update client page state. + """ + + error: str + """ + Startup error details, or empty string when registration succeeded. + """ + + +@dataclass +class PatchControlBody: + """ + Server-to-client control patch message body. + + Applies one patch operation list to the control subtree rooted at `id`. + """ + + id: int + """ + Target root control ID for patch application. + """ + + patch: Any + """ + Serialized patch operations generated by object diffing. + """ + + +@dataclass +class UpdateControlPropsBody: + """ + Client-to-server control property update payload. + + Used when the client updates selected control properties and sends them back to + Python. + """ + + id: int + """ + Target control ID. + """ + + props: Any + """ + Property mapping to apply to the target control. + """ + + +@dataclass +class ControlEventBody: + """ + Client-to-server control event payload. + """ + + target: int + """ + ID of the control that emitted the event. + """ + + name: str + """ + Event name without `on_` prefix. + """ + + data: Any + """ + Event-specific payload. + """ + + +@dataclass +class SessionCrashedBody: + """ + Fatal session error payload sent from server to client. + """ + + message: str + """ + Human-readable crash/error description. + """ + + +@dataclass +class InvokeMethodRequestBody: + """ + Server-to-client method invocation request payload. + + The client resolves `control_id`, invokes `name(args)`, then returns an + `InvokeMethodResponseBody`. + """ + + control_id: int + """ + Target control ID. + """ + + call_id: str + """ + Unique invocation correlation ID. + """ + + name: str + """ + Method name to invoke on the target control. + """ + + args: dict[str, Any] + """ + Invocation arguments payload. + """ + + +@dataclass +class InvokeMethodResponseBody: + """ + Client-to-server method invocation result payload. + + This message correlates to a prior invoke request by `call_id`. + """ + + control_id: int + """ + Target control ID from the original request. + """ + + call_id: str + """ + Correlation ID matching the original invoke request. + """ + + result: Any + """ + Returned method result value. + """ + + error: str + """ + Error message if invocation failed; otherwise null/empty. + """ diff --git a/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py b/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py new file mode 100644 index 0000000000..ee51c4f589 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/pyodide_connection.py @@ -0,0 +1,184 @@ +import asyncio +import inspect +import logging +import traceback +from collections.abc import Awaitable +from typing import TYPE_CHECKING, Any, Callable, Optional + +import flet_js +import msgpack + +from flet.controls.base_control import BaseControl +from flet.messaging.connection import Connection +from flet.messaging.protocol import ( + ClientAction, + ClientMessage, + ControlEventBody, + InvokeMethodResponseBody, + RegisterClientRequestBody, + RegisterClientResponseBody, + UpdateControlPropsBody, + configure_encode_object_for_msgpack, + decode_ext_from_msgpack, +) +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub + +if TYPE_CHECKING: + from flet.app import AppCallable + +logger = logging.getLogger("flet") +transport_log = logging.getLogger("flet_transport") + + +class PyodideConnection(Connection): + """ + Browser-side connection adapter used when Flet runs in Pyodide. + + This transport bridges JavaScript and Python message flow through `flet_js`, + manages a session lifecycle, and routes protocol messages to session handlers. + """ + + def __init__( + self, + on_session_created: Optional[Callable[[Session], Awaitable[Any]]], + before_main: Optional["AppCallable"], + ): + super().__init__() + self.__receive_queue = asyncio.Queue() + self.__on_session_created = on_session_created + self.__before_main = before_main + flet_js.start_connection = self.connect + self.__running_tasks = set() + self.pubsubhub = PubSubHub() + self.loop = asyncio.get_running_loop() + + async def connect(self, send_callback): + """ + Initializes JavaScript bridge callbacks and starts the receive loop. + + Args: + send_callback: JavaScript callback used to send packed protocol messages + from Python to the browser client. + """ + logger.info("Starting Pyodide connection...") + self.page_url = flet_js.documentUrl + self.send_callback = send_callback + asyncio.create_task(self.receive_loop()) + flet_js.send = self.send_from_js + + async def receive_loop(self): + """ + Continuously receives, decodes, and dispatches inbound client messages. + + This loop waits for raw messages queued by `send_from_js()`, decodes MsgPack + payloads, and forwards parsed protocol frames to `__on_message()`. + """ + while True: + data = await self.__receive_queue.get() + message = msgpack.unpackb(data.to_py(), ext_hook=decode_ext_from_msgpack) + await self.__on_message(message) + + def send_from_js(self, message: Any): + """ + Enqueues a raw message delivered from JavaScript. + + Args: + message: JS message payload object expected to expose `to_py()`. + """ + self.__receive_queue.put_nowait(message) + + async def __on_message(self, data: Any): + """ + Processes one decoded protocol frame from the client. + + Supported actions: + - register client and create a new session; + - dispatch control events; + - apply control property updates; + - deliver invoke-method results. + + Args: + data: Decoded protocol frame `[action, body]`. + + Raises: + RuntimeError: If the action type is unknown. + """ + action = ClientAction(data[0]) + body = data[1] + transport_log.debug("_on_message: %s %s", action, body) + task = None + if action == ClientAction.REGISTER_CLIENT: + req = RegisterClientRequestBody(**body) + + # create new session + self.session = Session(self) + + # apply page patch + self.session.apply_page_patch(req.page) + + register_error = "" + try: + if inspect.iscoroutinefunction(self.__before_main): + await self.__before_main(self.session.page) + elif callable(self.__before_main): + self.__before_main(self.session.page) + except Exception as e: + register_error = f"{e}\n{traceback.format_exc()}" + logger.error("Unhandled error in before_main() handler", exc_info=True) + + # register response + self.send_message( + ClientMessage( + ClientAction.REGISTER_CLIENT, + RegisterClientResponseBody( + session_id=self.session.id, + page_patch=self.session.get_page_patch(), + error=register_error, + ), + ) + ) + + # start session + if not register_error and self.__on_session_created is not None: + task = asyncio.create_task(self.__on_session_created(self.session)) + elif register_error: + self.session.error(register_error) + + elif action == ClientAction.CONTROL_EVENT: + req = ControlEventBody(**body) + task = asyncio.create_task( + self.session.dispatch_event(req.target, req.name, req.data) + ) + + elif action == ClientAction.UPDATE_CONTROL_PROPS: + req = UpdateControlPropsBody(**body) + self.session.apply_patch(req.id, req.props) + + elif action == ClientAction.INVOKE_METHOD: + req = InvokeMethodResponseBody(**body) + self.session.handle_invoke_method_results( + req.control_id, req.call_id, req.result, req.error + ) + + else: + # it's something else + raise RuntimeError(f'Unknown message "{action}": {body}') + + if task: + self.__running_tasks.add(task) + task.add_done_callback(self.__running_tasks.discard) + + def send_message(self, message: ClientMessage): + """ + Serializes and sends an outbound protocol message to JavaScript. + + Args: + message: Client message to serialize with MsgPack and send. + """ + transport_log.debug("send_message: %s", message) + m = msgpack.packb( + [message.action, message.body], + default=configure_encode_object_for_msgpack(BaseControl), + ) + self.send_callback(m) diff --git a/sdk/python/packages/flet/src/flet/messaging/session.py b/sdk/python/packages/flet/src/flet/messaging/session.py new file mode 100644 index 0000000000..460e800431 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/session.py @@ -0,0 +1,708 @@ +import asyncio +import dataclasses +import inspect +import logging +import traceback +import weakref +from datetime import datetime, timedelta, timezone +from typing import Any, Optional + +from flet.components.hooks.use_effect import EffectHook +from flet.controls.base_control import BaseControl +from flet.controls.context import _context_page, context +from flet.controls.object_patch import ObjectPatch +from flet.controls.page import Page +from flet.messaging.connection import Connection +from flet.messaging.protocol import ( + ClientAction, + ClientMessage, + InvokeMethodRequestBody, + PatchControlBody, + SessionCrashedBody, +) +from flet.messaging.session_store import SessionStore +from flet.pubsub.pubsub_client import PubSubClient +from flet.utils.object_model import patch_dataclass +from flet.utils.strings import random_string + +logger = logging.getLogger("flet") +patch_logger = logging.getLogger("flet_object_patch") + +__all__ = ["Session"] + + +class Session: + """ + Represents a server-side Flet session. + + A session owns the root :class:`~flet.Page`, tracks mounted controls, dispatches + control events, synchronizes UI patches with the client connection, and coordinates + deferred updates/effects. + """ + + def __init__(self, conn: Connection): + self.__conn = conn + self.__send_buffer: list[ClientMessage] = [] + self.__id = random_string(16) + self.__expires_at = None + self.__index: weakref.WeakValueDictionary[int, BaseControl] = ( + weakref.WeakValueDictionary() + ) + self.__page = Page(self) + self.__index[self.__page._i] = self.__page + self.__store: SessionStore = SessionStore() + self.__pubsub_client = PubSubClient(conn.pubsubhub, self.__id) + self.__method_calls: dict[str, asyncio.Event] = {} + self.__method_call_results: dict[asyncio.Event, tuple[Any, Optional[str]]] = {} + self.__updates_ready: asyncio.Event = asyncio.Event() + self.__pending_updates: set[BaseControl] = set() + self.__pending_effects: list[tuple[weakref.ref[EffectHook], bool]] = [] + self.__updates_task: Optional[asyncio.Task] = None + self.__closed = False + + session_id = self.__id + weakref.finalize( + self, + lambda: logger.info("Session was garbage collected: %s", session_id), + ) + + @property + def connection(self) -> Connection: + """ + Returns the current messaging connection for this session. + + Returns: + Active `Connection` instance. It may be `None` after + :meth:`disconnect` until a reconnect occurs. + """ + return self.__conn + + @property + def id(self): + """ + Returns the unique session identifier. + + Returns: + Randomly generated session ID string. + """ + return self.__id + + @property + def expires_at(self) -> Optional[datetime]: + """ + Returns the UTC expiration timestamp for a disconnected session. + + Returns: + Expiration time in UTC, or `None` when the session is currently connected. + """ + return self.__expires_at + + @property + def index(self): + """ + Returns the live control index for this session. + + Returns: + Weak mapping of control IDs to mounted :class:`~flet.BaseControl` instances. + """ + return self.__index + + @property + def page(self): + """ + Returns the root :class:`~flet.Page` associated with this session. + """ + return self.__page + + @property + def pubsub_client(self) -> PubSubClient: + """ + Returns the session-scoped pub/sub client. + + Returns: + `PubSubClient` bound to this session ID. + """ + return self.__pubsub_client + + @property + def store(self) -> SessionStore: + """ + Returns the key-value store associated with this session. + + Returns: + `SessionStore` instance for session state persistence. + """ + return self.__store + + def attach_connection(self, conn: Connection) -> None: + """ + Attaches or re-attaches this session to an active connection. + + This method resets expiration state and flushes buffered outbound messages. + + Args: + conn: Active connection to bind to this session. + """ + logger.debug("Connect session: %s", self.id) + _context_page.set(self.__page) + self.__conn = conn + self.__expires_at = None + for message in self.__send_buffer: + self.__send_message(message) + self.__send_buffer.clear() + + async def dispatch_connect_event(self) -> None: + """ + Dispatches the page-level `connect` event for this session. + """ + await self.dispatch_event(self.__page._i, "connect", None) + + async def connect(self, conn: Connection) -> None: + """ + Attaches or re-attaches this session to an active connection and then + dispatches the page-level `connect` event. + + Args: + conn: Active connection to bind to this session. + """ + self.attach_connection(conn) + await self.dispatch_connect_event() + + async def disconnect(self, session_timeout_seconds: int) -> None: + """ + Marks the session disconnected and schedules its expiration window. + + The current connection is disposed, `expires_at` is set to now plus + `session_timeout_seconds`, and the page-level `disconnect` event is dispatched. + + Args: + session_timeout_seconds: Grace period before the disconnected session is + considered expired. + """ + logger.debug("Disconnect session: %s", self.id) + self.__expires_at = datetime.now(timezone.utc) + timedelta( + seconds=session_timeout_seconds + ) + self.__send_buffer.clear() + self.__pending_updates.clear() + self.__pending_effects.clear() + self.__updates_ready.clear() + if self.__conn: + self.__conn.dispose() + self.__conn = None + await self.dispatch_event(self.__page._i, "disconnect", None) + + def close(self): + """ + Closes the session and stops background scheduling work. + + This method marks the session as closed, cancels the updates scheduler, + unsubscribes pub/sub handlers, resolves pending invoke-method calls with + a closure error, and dispatches the page-level `close` event. + """ + logger.debug("Closing expired session: %s", self.id) + self.__closed = True + self.__updates_ready.set() + if self.__updates_task and not self.__updates_task.done(): + self.__updates_task.cancel() + self.__pubsub_client.unsubscribe_all() + self.__cancel_method_calls() + asyncio.create_task(self.dispatch_event(self.__page._i, "close", None)) + + def patch_control( + self, + control: BaseControl, + prev_control: Optional[BaseControl] = None, + parent: Any = None, + path: Optional[list[Any]] = None, + frozen: bool = False, + ): + """ + Computes and sends a patch for a control subtree. + + The patch is calculated from `prev_control` to `control`, sent to the client, + and then applied to the local session index by unmounting removed controls and + mounting added controls. + + Args: + control: Current control state to patch from. + prev_control: Previous control snapshot. If `None`, `control` is used. + parent: Parent control context used by patch generation. + path: Tree path used by patch generation. + frozen: Whether object diff should treat controls as frozen. + """ + patch, added_controls, removed_controls = self.__get_update_control_patch( + control=control, + prev_control=prev_control or control, + parent=parent, + path=path, + frozen=frozen, + ) + + patch_logger.debug("\npatch removed_controls (%s):", len(removed_controls)) + for c in removed_controls: + patch_logger.debug(" %s", c) + + for removed_control in removed_controls: + if not any(added._i == removed_control._i for added in added_controls): + removed_control.will_unmount() + self.__index.pop(removed_control._i, None) + + if len(patch) > 1: + self.__send_message( + ClientMessage( + ClientAction.PATCH_CONTROL, + PatchControlBody(parent._i if parent else control._i, patch), + ) + ) + + patch_logger.debug("\npatch added_controls: (%s)", len(added_controls)) + for ac in added_controls: + patch_logger.debug(" %s", ac) + + for added_control in added_controls: + self.__index[added_control._i] = added_control + if not any(removed._i == added_control._i for removed in removed_controls): + added_control.did_mount() + + def apply_patch(self, control_id: int, patch: dict[str, Any]): + """ + Applies a partial property patch to a control in the session index. + + Args: + control_id: Target control ID. + patch: Property/value mapping to apply. + """ + if control := self.__index.get(control_id): + patch_dataclass(control, patch) + + def apply_page_patch(self, patch: dict[str, Any]): + """ + Applies a partial patch to the root page control. + + Args: + patch: Property/value mapping to apply to the page. + """ + self.apply_patch(self.__page._i, patch) + + def get_page_patch(self): + """ + Generates a serialized patch payload for the root page. + + During patch generation, newly discovered controls are indexed and mounted. + + Returns: + Serialized page patch payload suitable for register-client responses. + """ + patch, added_controls, _ = self.__get_update_control_patch( + self.__page, prev_control=None + ) + + for added_control in added_controls: + self.__index[added_control._i] = added_control + added_control.did_mount() + + # patch format: + # [[], , , ...] + # := [, , , ] + return patch[1][3] # [1] - 1st operation -> [3] - Page + + def __is_mounted_control(self, control: BaseControl) -> bool: + try: + return control.page is self.__page + except RuntimeError: + return False + + def __find_live_control( + self, + value: Any, + control_id: int, + parent: Optional[BaseControl] = None, + visited: Optional[set[int]] = None, + ) -> Optional[BaseControl]: + if value is None: + return None + + if visited is None: + visited = set() + + value_id = id(value) + if value_id in visited: + return None + + current_parent = parent + if isinstance(value, BaseControl): + visited.add(value_id) + if parent is not None and parent is not value: + value._parent = weakref.ref(parent) + if value._i == control_id: + return value + current_parent = value + elif dataclasses.is_dataclass(value) or isinstance(value, (list, tuple, dict)): + visited.add(value_id) + + if dataclasses.is_dataclass(value): + for field in dataclasses.fields(value): + if field.metadata.get("skip", False) or field.name == "_parent": + continue + found = self.__find_live_control( + getattr(value, field.name, None), + control_id, + current_parent, + visited, + ) + if found is not None: + return found + elif isinstance(value, dict): + for item in value.values(): + found = self.__find_live_control( + item, control_id, current_parent, visited + ) + if found is not None: + return found + elif isinstance(value, (list, tuple)): + for item in value: + found = self.__find_live_control( + item, control_id, current_parent, visited + ) + if found is not None: + return found + + return None + + def __resolve_event_control(self, control_id: int) -> Optional[BaseControl]: + control = self.__index.get(control_id) + if control is not None and self.__is_mounted_control(control): + return control + + live_control = self.__find_live_control(self.__page, control_id) + if live_control is not None: + if control is not None and control is not live_control: + logger.debug( + "Recovered stale control %s -> %s for event dispatch", + control, + live_control, + ) + self.__index[control_id] = live_control + return live_control + + return control + + # optimizations: + # - disable auto-update + # - auto-update to skip already updated items + # - add-only list + # - disable mount/unmount + + async def dispatch_event( + self, + control_id: int, + event_name: str, + event_data: Any, + ): + """ + Dispatches an event to a control by ID. + + Args: + control_id: Target control ID. + event_name: Event name without the `on_` prefix. + event_data: Raw event payload. + """ + control = self.__resolve_event_control(control_id) + if not control: + logger.debug("Control with ID %s not found.", control_id) + return + + try: + await control._trigger_event(event_name, event_data) + except Exception as e: + logger.error( + "Unhandled error in 'on_%s' handler", event_name, exc_info=True + ) + self.error(f"{e}\n{traceback.format_exc()}") + + async def invoke_method( + self, + control_id: int, + method_name: str, + args: Any, + timeout: Optional[float] = None, + ): + """ + Invokes a client-side control method and waits for the response. + + Args: + control_id: Target control ID. + method_name: Method name to invoke on the client. + args: Method arguments payload. + timeout: Optional timeout in seconds. + + Returns: + Result returned by the client-side method invocation. + + Raises: + TimeoutError: If no invoke-method response is received before timeout. + RuntimeError: If the client reports an invocation error. + """ + call_id = random_string(10) + + # register callback + evt = asyncio.Event() + self.__method_calls[call_id] = evt + + # call method + self.__send_message( + ClientMessage( + ClientAction.INVOKE_METHOD, + InvokeMethodRequestBody( + control_id=control_id, call_id=call_id, name=method_name, args=args + ), + ) + ) + + try: + await asyncio.wait_for(evt.wait(), timeout=timeout) + except TimeoutError: + if call_id in self.__method_calls: + del self.__method_calls[call_id] + raise TimeoutError( + f"Timeout waiting for invokeMethod {method_name}({args}) call" + ) from None + + result, err = self.__method_call_results.pop(evt) + if err: + raise RuntimeError(err) + return result + + def handle_invoke_method_results( + self, control_id: int, call_id: str, result: Any, error: Optional[str] + ): + """ + Stores and signals completion of a pending invoke-method request. + + Args: + control_id: Control ID included in the response. + call_id: Invoke-method call ID. + result: Returned result payload. + error: Optional error message returned by the client. + + Raises: + RuntimeError: If the referenced control is not registered in the session. + """ + if control_id in self.__index: + evt = self.__method_calls.pop(call_id, None) + if evt is None: + return + self.__method_call_results[evt] = (result, error) + evt.set() + else: + raise RuntimeError( + f"Error handling invoke method results. Control with ID {control_id} " + "is not registered." + ) + + def __cancel_method_calls(self): + """ + Resolves all pending invoke-method waits with a session-closed error. + """ + for evt in list(self.__method_calls.values()): + self.__method_call_results[evt] = (None, "Session closed") + evt.set() + + async def after_event(self, control: BaseControl | None): + """ + Runs post-event housekeeping operations. + + This currently performs optional auto-update behavior and unregisters + unreferenced page services. + + Args: + control: Control that handled the event, or `None`. + """ + # call auto-update + if context.auto_update_enabled() and not context.was_update_called(): + await self.__auto_update(control) + context.reset_update_called() + + # unregister unreferenced services + self.page._services.unregister_services() + + async def __auto_update(self, control: BaseControl | None): + """ + Performs auto-update on the nearest eligible isolated ancestor. + + Traverses parent controls until it finds an isolated control that is not + frozen and an active connection exists, then calls `update()` on that control. + + Args: + control: Starting control for parent traversal. + """ + while control: + if ( + control.is_isolated() + and not hasattr(control, "_frozen") + and self.__conn + ): + control.update() + break + control = control.parent + + def error(self, message: str): + """ + Sends a session-crashed message to the connected client. + + Args: + message: Error message to report. + """ + self.__send_message( + ClientMessage(ClientAction.SESSION_CRASHED, SessionCrashedBody(message)) + ) + + def __send_message(self, message: ClientMessage): + """ + Sends a message immediately or buffers it until reconnection. + + Args: + message: Outbound client message. + """ + if self.__conn: + self.__conn.send_message(message) + elif self.__expires_at is not None: + # Session is disconnected and waiting for eviction/reconnect. + # Drop incremental traffic to avoid unbounded buffering. + return + else: + self.__send_buffer.append(message) + + def __get_update_control_patch( + self, + control: BaseControl, + prev_control: Optional[BaseControl], + parent: Any = None, + path: Optional[list[Any]] = None, + frozen: bool = False, + ): + """ + Computes a serialized object patch and control mount/unmount deltas. + + Args: + control: Current control state. + prev_control: Previous control state. + parent: Parent control context for diff generation. + path: Tree path for nested patch generation. + frozen: Whether diff generation should treat controls as frozen. + + Returns: + Tuple of `(patch_message, added_controls, removed_controls)`. + """ + # start_time = datetime.now() + + # calculate patch + patch, added_controls, removed_controls = ObjectPatch.from_diff( + prev_control, + control, + control_cls=BaseControl, + parent=parent, + path=path, + frozen=frozen, + ) + + # end_time = datetime.now() + # elapsed_time = end_time - start_time + # print( + # "Time spent calculating patch: " + # f"{elapsed_time.total_seconds() * 1000:.3f} ms" + # ) + + # print("\n\npatch:", patch) + + return patch.to_message(), added_controls, removed_controls + + def schedule_update(self, control: BaseControl): + """ + Queues a control for update by the background scheduler. + + Args: + control: Control to update. + """ + logger.debug("Schedule_update(%s)", control) + if self.__conn is None and self.__expires_at is not None: + return + self.__pending_updates.add(control) + self.__updates_ready.set() + + def schedule_effect(self, hook: EffectHook, is_cleanup: bool): + """ + Queues an effect hook setup/cleanup operation for scheduler execution. + + Args: + hook: Effect hook to process. + is_cleanup: `True` to run cleanup, `False` to run setup. + """ + logger.debug("Schedule_effect(%s, %s)", hook, is_cleanup) + if self.__conn is None and self.__expires_at is not None: + return + # Hold a strong reference to the hook until it runs. A weakref would + # get cleared when the owning component unmounts and clears + # `_state.hooks` — dropping queued cleanup effects on the floor. + self.__pending_effects.append((hook, is_cleanup)) + self.__updates_ready.set() + + def start_updates_scheduler(self): + """ + Starts the deferred updates/effects scheduler task if not already running. + """ + logger.debug("Starting updates scheduler: %s", self.id) + if self.__updates_task and not self.__updates_task.done(): + return + self.__updates_task = asyncio.create_task(self.__updates_scheduler()) + + async def __updates_scheduler(self): + """ + Background loop that drains queued updates and effect operations. + + The scheduler waits for work signals, updates pending controls, then executes + pending effect hook setup/cleanup callbacks. Errors inside effect processing + are reported to the client via :meth:`error`. + """ + try: + while not self.__closed: + await self.__updates_ready.wait() + self.__updates_ready.clear() + + # Process pending updates + pending_updates = list(self.__pending_updates) + self.__pending_updates.clear() + + for control in pending_updates: + control.update() + + # Process pending effects + pending_effects = list(self.__pending_effects) + self.__pending_effects.clear() + + for effect in pending_effects: + try: + hook = effect[0] + is_cleanup = effect[1] + # print(f"**** Running effect: {hook} {is_cleanup}") + if hook and hook.setup and not is_cleanup: + hook.cancel() + res = None + if inspect.iscoroutinefunction(hook.setup): + hook._setup_task = asyncio.create_task(hook.setup()) + else: + res = hook.setup() + if callable(res): + hook.cleanup = res + elif hook and hook.cleanup and is_cleanup: + hook.cancel() + if inspect.iscoroutinefunction(hook.cleanup): + hook._cleanup_task = asyncio.create_task(hook.cleanup()) + else: + hook.cleanup() + except Exception as ex: + tb = traceback.format_exc() + self.error(f"Exception in effect: {ex}\n{tb}") + except asyncio.CancelledError: + pass diff --git a/sdk/python/packages/flet/src/flet/messaging/session_store.py b/sdk/python/packages/flet/src/flet/messaging/session_store.py new file mode 100644 index 0000000000..e9d40579a1 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/messaging/session_store.py @@ -0,0 +1,73 @@ +from typing import Any + +__all__ = ["SessionStore"] + + +class SessionStore: + """In-memory key-value storage scoped to a user session. + + Note: + In its current implementation, the data stored in a session store + is transient and is not preserved between app restarts. + + Example: + ```python + page.session.store.set("user_name", "Alice") + user_name = page.session.store.get("user_name") + ``` + """ + + def __init__(self): + """Initialize an empty session store.""" + self.__store: dict[str, Any] = {} + + def set(self, key: str, value: Any): + """Store a value under a key. + + Args: + key: Key to store the value under. + value: Value to store. + """ + self.__store[key] = value + + def get(self, key: str): + """Return the value for a key, or ``None`` if missing. + + Args: + key: Key to look up. + + Returns: + The stored value or ``None`` if the key does not exist. + """ + return self.__store.get(key) + + def contains_key(self, key: str) -> bool: + """Check whether a key exists in the store. + + Args: + key: Key to check. + + Returns: + ``True`` if the key exists, otherwise ``False``. + """ + return key in self.__store + + def remove(self, key: str): + """Remove a key from the store. + + Args: + key: Key to remove. + """ + self.__store.pop(key) + + def get_keys(self) -> list[str]: + """Return all keys currently stored. + + Returns: + A list of keys. + """ + return list(self.__store.keys()) + + def clear(self): + """Remove all keys and values from the store.""" + self.__store.clear() diff --git a/sdk/python/packages/flet/src/flet/plotly_chart.py b/sdk/python/packages/flet/src/flet/plotly_chart.py deleted file mode 100644 index 6b6670cbfa..0000000000 --- a/sdk/python/packages/flet/src/flet/plotly_chart.py +++ /dev/null @@ -1 +0,0 @@ -from flet.core.plotly_chart import PlotlyChart diff --git a/sdk/python/packages/flet/src/flet/pubsub/__init__.py b/sdk/python/packages/flet/src/flet/pubsub/__init__.py new file mode 100644 index 0000000000..191ef68833 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/pubsub/__init__.py @@ -0,0 +1,7 @@ +from .pubsub_client import PubSubClient +from .pubsub_hub import PubSubHub + +__all__ = [ + "PubSubClient", + "PubSubHub", +] diff --git a/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py b/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py new file mode 100644 index 0000000000..bca036655e --- /dev/null +++ b/sdk/python/packages/flet/src/flet/pubsub/pubsub_client.py @@ -0,0 +1,103 @@ +import logging +from typing import Any, Callable + +from flet.pubsub.pubsub_hub import PubSubHub + +logger = logging.getLogger("flet") + + +class PubSubClient: + """ + Session-scoped facade over `PubSubHub`. + + This client binds all pub/sub operations to one session ID so callers can + publish and subscribe without passing their session identity explicitly on + each call. + """ + + def __init__(self, pubsub: PubSubHub, session_id: str): + self.__pubsub = pubsub + self.__session_id = session_id + + def send_all(self, message: Any): + """ + Broadcasts a global message to all sessions. + + Args: + message: Payload to publish. + """ + self.__pubsub.send_all(message) + + def send_all_on_topic(self, topic: str, message: Any): + """ + Broadcasts a topic message to all subscribers of `topic`. + + Args: + topic: Topic name to publish on. + message: Payload to publish. + """ + self.__pubsub.send_all_on_topic(topic, message) + + def send_others(self, message: Any): + """ + Broadcasts a global message to all sessions except this client session. + + Args: + message: Payload to publish. + """ + self.__pubsub.send_others(self.__session_id, message) + + def send_others_on_topic(self, topic: str, message: Any): + """ + Broadcasts a topic message excluding this client session. + + Args: + topic: Topic name to publish on. + message: Payload to publish. + """ + self.__pubsub.send_others_on_topic(self.__session_id, topic, message) + + def subscribe(self, handler: Callable): + """ + Subscribes this session to global messages. + + The handler is invoked with one positional argument: `message`. + + Args: + handler: Sync or async callback for global messages. + """ + self.__pubsub.subscribe(self.__session_id, handler) + + def subscribe_topic(self, topic: str, handler: Callable): + """ + Subscribes this session to a topic. + + The handler is invoked with two positional arguments: + `(topic, message)`. + + Args: + topic: Topic name to subscribe to. + handler: Sync or async callback for topic messages. + """ + self.__pubsub.subscribe_topic(self.__session_id, topic, handler) + + def unsubscribe(self): + """ + Removes global subscriptions for this session. + """ + self.__pubsub.unsubscribe(self.__session_id) + + def unsubscribe_topic(self, topic: str): + """ + Removes this session's subscriptions for a specific topic. + + Args: + topic: Topic to unsubscribe from. + """ + self.__pubsub.unsubscribe_topic(self.__session_id, topic) + + def unsubscribe_all(self): + """ + Removes all global and topic subscriptions for this session. + """ + self.__pubsub.unsubscribe_all(self.__session_id) diff --git a/sdk/python/packages/flet/src/flet/pubsub/pubsub_hub.py b/sdk/python/packages/flet/src/flet/pubsub/pubsub_hub.py new file mode 100644 index 0000000000..2f0e6c5b88 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/pubsub/pubsub_hub.py @@ -0,0 +1,286 @@ +import asyncio +import inspect +import logging +import threading +from collections.abc import Awaitable, Iterable +from concurrent.futures import ThreadPoolExecutor +from typing import Any, Callable, Optional, Union + +from flet.utils import is_pyodide +from flet.utils.locks import NopeLock + +logger = logging.getLogger("flet") + + +class PubSubHub: + """ + Thread-safe in-memory pub/sub router scoped to a Flet server process. + + Subscribers are grouped by session ID and optionally by topic. Handlers can + be synchronous callables or async coroutine functions: + - global subscribers receive `(message)`; + - topic subscribers receive `(topic, message)`. + + This hub is used by session-scoped `PubSubClient` + instances to fan out messages between connected sessions. + """ + + def __init__( + self, + loop: Optional[asyncio.AbstractEventLoop] = None, + executor: Optional[ThreadPoolExecutor] = None, + ): + logger.debug("Creating new PubSubHub instance") + self.__loop = loop + self.__executor = executor + self.__lock = threading.Lock() if not is_pyodide() else NopeLock() + self.__subscribers: dict[ + str, set[Union[Callable, Callable[..., Awaitable[Any]]]] + ] = {} # key: session_id, value: handler + self.__topic_subscribers: dict[ + str, dict[str, set[Union[Callable, Callable[..., Awaitable[Any]]]]] + ] = {} # key: topic, value: dict[session_id, handler] + self.__subscriber_topics: dict[ + str, dict[str, set[Union[Callable, Callable[..., Awaitable[Any]]]]] + ] = {} # key: session_id, value: dict[topic, handler] + + def send_all(self, message: Any): + """ + Sends a message to all global subscribers across all sessions. + + Args: + message: Payload to deliver. + """ + logger.debug("pubsub.send_all(%s)", message) + with self.__lock: + for handlers in self.__subscribers.values(): + for handler in handlers: + self.__send(handler, [message]) + + def send_all_on_topic(self, topic: str, message: Any): + """ + Sends a topic message to all subscribers of `topic`. + + Args: + topic: Topic name to broadcast on. + message: Payload to deliver. + """ + logger.debug("pubsub.send_all_on_topic(%s, %s)", topic, message) + with self.__lock: + if topic in self.__topic_subscribers: + for handlers in self.__topic_subscribers[topic].values(): + for handler in handlers: + self.__send(handler, [topic, message]) + + def send_others(self, except_session_id: str, message: Any): + """ + Sends a global message to all sessions except one. + + Args: + except_session_id: Session ID to exclude from delivery. + message: Payload to deliver. + """ + logger.debug("pubsub.send_others(%s, %s)", except_session_id, message) + with self.__lock: + for session_id, handlers in self.__subscribers.items(): + if except_session_id != session_id: + for handler in handlers: + self.__send(handler, [message]) + + def send_others_on_topic(self, except_session_id: str, topic: str, message: Any): + """ + Sends a topic message to all subscribers except one session. + + Args: + except_session_id: Session ID to exclude from delivery. + topic: Topic name to publish on. + message: Payload to deliver. + """ + logger.debug( + "pubsub.send_others_on_topic(%s, %s, %s)", except_session_id, topic, message + ) + with self.__lock: + if topic in self.__topic_subscribers: + for session_id, handlers in self.__topic_subscribers[topic].items(): + if except_session_id != session_id: + for handler in handlers: + self.__send(handler, [topic, message]) + + def subscribe(self, session_id: str, handler: Callable): + """ + Registers a global subscriber for a session. + + The handler will receive one positional argument: `message`. + Duplicate registrations of the same handler are ignored because + handlers are stored in a set. + + Args: + session_id: Session identifier that owns this subscription. + handler: Sync or async callback invoked for global messages. + """ + logger.debug("pubsub.subscribe(%s)", session_id) + with self.__lock: + handlers = self.__subscribers.get(session_id) + if handlers is None: + handlers = set() + self.__subscribers[session_id] = handlers + handlers.add(handler) + + def subscribe_topic( + self, + session_id: str, + topic: str, + handler: Union[Callable, Callable[..., Awaitable[Any]]], + ): + """ + Registers a topic subscriber for a session. + + The handler will receive two positional arguments: `(topic, message)`. + + Args: + session_id: Session identifier that owns this subscription. + topic: Topic name to subscribe to. + handler: Sync or async callback invoked for topic messages. + """ + logger.debug("pubsub.subscribe_topic(%s, %s)", session_id, topic) + with self.__lock: + self.__subscribe_topic(session_id, topic, handler) + + def __subscribe_topic( + self, + session_id: str, + topic: str, + handler: Union[Callable, Callable[..., Awaitable[Any]]], + ): + """ + Internal implementation of topic subscription bookkeeping. + + Maintains both forward (`topic -> session -> handlers`) and reverse + (`session -> topic -> handlers`) indexes for efficient publish and + cleanup operations. + + Args: + session_id: Session identifier that owns this subscription. + topic: Topic name to subscribe to. + handler: Sync or async callback invoked for topic messages. + """ + topic_subscribers = self.__topic_subscribers.get(topic) + if topic_subscribers is None: + topic_subscribers = {} + self.__topic_subscribers[topic] = topic_subscribers + handlers = topic_subscribers.get(session_id) + if handlers is None: + handlers = set() + topic_subscribers[session_id] = handlers + handlers.add(handler) + subscriber_topics = self.__subscriber_topics.get(session_id) + if subscriber_topics is None: + subscriber_topics = {} + self.__subscriber_topics[session_id] = subscriber_topics + handlers = subscriber_topics.get(topic) + if handlers is None: + handlers = set() + subscriber_topics[topic] = handlers + handlers.add(handler) + + def unsubscribe(self, session_id: str): + """ + Removes all global subscribers for a session. + + This does not remove topic subscriptions; use + :meth:`unsubscribe_all` to remove both. + + Args: + session_id: Session identifier to remove. + """ + logger.debug("pubsub.unsubscribe(%s)", session_id) + with self.__lock: + self.__unsubscribe(session_id) + + def unsubscribe_topic(self, session_id: str, topic: str): + """ + Removes all handlers for a specific session/topic pair. + + Args: + session_id: Session identifier to remove from the topic. + topic: Topic to unsubscribe from. + """ + logger.debug("pubsub.unsubscribe(%s, %s)", session_id, topic) + with self.__lock: + self.__unsubscribe_topic(session_id, topic) + + def unsubscribe_all(self, session_id: str): + """ + Removes both global and topic subscriptions for a session. + + Args: + session_id: Session identifier to fully unsubscribe. + """ + logger.debug("pubsub.unsubscribe_all(%s)", session_id) + with self.__lock: + self.__unsubscribe(session_id) + if session_id in self.__subscriber_topics: + for topic in list(self.__subscriber_topics[session_id].keys()): + self.__unsubscribe_topic(session_id, topic) + + def __unsubscribe(self, session_id: str): + """ + Internal helper that removes global subscribers for a session. + + Args: + session_id: Session identifier to remove. + """ + logger.debug("pubsub.__unsubscribe(%s)", session_id) + self.__subscribers.pop(session_id, None) + + def __unsubscribe_topic(self, session_id: str, topic: str): + """ + Internal helper that removes one session/topic subscription entry. + + Cleans up empty topic and session containers after removal. + + Args: + session_id: Session identifier to remove from the topic. + topic: Topic to unsubscribe from. + """ + logger.debug("pubsub.__unsubscribe_topic(%s, %s)", session_id, topic) + topic_subscribers = self.__topic_subscribers.get(topic) + if topic_subscribers is not None: + topic_subscribers.pop(session_id, None) + if len(topic_subscribers) == 0: + self.__topic_subscribers.pop(topic, None) + subscriber_topics = self.__subscriber_topics.get(session_id) + if subscriber_topics is not None: + subscriber_topics.pop(topic, None) + if len(subscriber_topics) == 0: + self.__subscriber_topics.pop(session_id, None) + + def __send( + self, handler: Union[Callable, Callable[..., Awaitable[Any]]], args: Iterable + ): + """ + Dispatches a message to a handler in the configured execution context. + + Async handlers are scheduled on the hub event loop using + `run_coroutine_threadsafe`. Sync handlers are either submitted to the + configured executor or invoked inline when no executor is provided. + + Args: + handler: Subscriber callback to invoke. + args: Positional arguments to pass to the callback. + + Raises: + RuntimeError: If the hub has no event loop configured. + """ + if not self.__loop: + raise RuntimeError("PubSub event loop is not set") + + if inspect.iscoroutinefunction(handler): + asyncio.run_coroutine_threadsafe(handler(*args), self.__loop) + else: + if self.__executor: + self.__loop.call_soon_threadsafe( + self.__loop.run_in_executor, self.__executor, handler, *args + ) + else: + handler(*args) diff --git a/sdk/python/packages/flet/src/flet/py.typed b/sdk/python/packages/flet/src/flet/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sdk/python/packages/flet/src/flet/pyodide_connection.py b/sdk/python/packages/flet/src/flet/pyodide_connection.py deleted file mode 100644 index c058d8a0de..0000000000 --- a/sdk/python/packages/flet/src/flet/pyodide_connection.py +++ /dev/null @@ -1,104 +0,0 @@ -import asyncio -import json -import logging -from typing import List - -import flet_js -from flet.core.local_connection import LocalConnection -from flet.core.protocol import ( - ClientActions, - ClientMessage, - Command, - CommandEncoder, - PageCommandResponsePayload, - PageCommandsBatchResponsePayload, - RegisterWebClientRequestPayload, -) - -import flet - -logger = logging.getLogger(flet.__name__) - - -class PyodideConnection(LocalConnection): - def __init__( - self, - on_event, - on_session_created, - ): - super().__init__() - self.__receive_queue = asyncio.Queue() - self.__on_event = on_event - self.__on_session_created = on_session_created - flet_js.start_connection = self.connect - - async def connect(self, send_callback): - logger.info("Starting Pyodide connection...") - self.page_url = flet_js.documentUrl - self.send_callback = send_callback - asyncio.create_task(self.receive_loop()) - flet_js.send = self.send_from_js - - async def receive_loop(self): - while True: - message = await self.__receive_queue.get() - await self.__on_message(message) - - def send_from_js(self, message: str): - logger.debug(f"Sending data from JavaScript to Python: {message}") - self.__receive_queue.put_nowait(message) - - async def __on_message(self, data: str): - logger.debug(f"_on_message: {data}") - msg_dict = json.loads(data) - msg = ClientMessage(**msg_dict) - if msg.action == ClientActions.REGISTER_WEB_CLIENT: - self._client_details = RegisterWebClientRequestPayload(**msg.payload) - - # register response - self.__send(self._create_register_web_client_response()) - - # start session - if self.__on_session_created is not None: - asyncio.create_task( - self.__on_session_created(self._create_session_handler_arg()) - ) - - elif msg.action == ClientActions.PAGE_EVENT_FROM_WEB: - if self.__on_event is not None: - asyncio.create_task( - self.__on_event(self._create_page_event_handler_arg(msg)) - ) - - elif msg.action == ClientActions.UPDATE_CONTROL_PROPS: - if self.__on_event is not None: - asyncio.create_task( - self.__on_event(self._create_update_control_props_handler_arg(msg)) - ) - else: - # it's something else - raise Exception(f'Unknown message "{msg.action}": {msg.payload}') - - def send_command(self, session_id: str, command: Command): - result, message = self._process_command(command) - if message: - self.__send(message) - return PageCommandResponsePayload(result=result, error="") - - def send_commands(self, session_id: str, commands: List[Command]): - results = [] - messages = [] - for command in commands: - result, message = self._process_command(command) - if command.name in ["add", "get"]: - results.append(result) - if message: - messages.append(message) - if len(messages) > 0: - self.__send(ClientMessage(ClientActions.PAGE_CONTROLS_BATCH, messages)) - return PageCommandsBatchResponsePayload(results=results, error="") - - def __send(self, message: ClientMessage): - j = json.dumps(message, cls=CommandEncoder, separators=(",", ":")) - logger.debug(f"__send: {j}") - self.send_callback(j) diff --git a/sdk/python/packages/flet/src/flet/security/__init__.py b/sdk/python/packages/flet/src/flet/security/__init__.py index 4b8811b3aa..332c131070 100644 --- a/sdk/python/packages/flet/src/flet/security/__init__.py +++ b/sdk/python/packages/flet/src/flet/security/__init__.py @@ -7,21 +7,63 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC -except ImportError: - raise Exception('Install "cryptography" Python package to use Flet security utils.') +except ImportError as e: + raise ImportError( + 'Install "cryptography" Python package to use Flet security utils.' + ) from e def __generate_fernet_key(secret_key: str) -> bytes: + """ + Derives a deterministic Fernet-compatible key from `secret_key`. + + The key is produced by hashing `secret_key` with SHA-256 and URL-safe + Base64-encoding the 32-byte digest. + + Args: + secret_key: Source secret used to derive the key. + + Returns: + URL-safe Base64 key bytes suitable for `Fernet`. + """ key = hashlib.sha256(secret_key.encode()).digest() return base64.urlsafe_b64encode(key) def __generate_fernet_key_kdf(secret_key: str, salt: bytes) -> bytes: + """ + Derives a Fernet-compatible key using PBKDF2-HMAC-SHA256. + + This function uses 600,000 iterations and a caller-provided random `salt`, then + URL-safe Base64-encodes the derived 32-byte key. + + Args: + secret_key: Source secret used for key derivation. + salt: Salt bytes used by PBKDF2. + + Returns: + URL-safe Base64 key bytes suitable for `Fernet`. + """ kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=600000) return base64.urlsafe_b64encode(kdf.derive(secret_key.encode("utf-8"))) def encrypt(plain_text: str, secret_key: str) -> str: + """ + Encrypts UTF-8 text using Fernet with a per-message salt-derived key. + + Output format is `base64url(salt + token)`, where: + - `salt` is 16 random bytes; + - `token` is a Fernet token encrypted with a key derived from `secret_key` and + `salt`. + + Args: + plain_text: Text to encrypt. + secret_key: Secret used to derive the encryption key. + + Returns: + URL-safe Base64 string containing salt-prefixed encrypted payload. + """ salt = os.urandom(16) key = __generate_fernet_key_kdf(secret_key, salt) f = Fernet(key) @@ -31,6 +73,24 @@ def encrypt(plain_text: str, secret_key: str) -> str: def decrypt(encrypted_data: str, secret_key: str) -> str: + """ + Decrypts data produced by `encrypt()`. + + Input format must be `base64url(salt + token)`, where the first 16 bytes are + the PBKDF2 salt and the remaining bytes are a Fernet token. + + Args: + encrypted_data: URL-safe Base64 payload returned by `encrypt()`. + secret_key: Secret used to derive the decryption key. + + Returns: + Decrypted UTF-8 text. + + Raises: + binascii.Error: If `encrypted_data` is not valid Base64. + cryptography.fernet.InvalidToken: If the token cannot be authenticated or + decrypted with the derived key. + """ encrypted_data_bytes = base64.urlsafe_b64decode(encrypted_data) salt = encrypted_data_bytes[:16] key = __generate_fernet_key_kdf(secret_key, salt) @@ -39,6 +99,27 @@ def decrypt(encrypted_data: str, secret_key: str) -> str: def encrypt_aes_gcm_256(plain_text: str, secret_key: str) -> str: + """ + Encrypts UTF-8 text using AES-GCM with a 256-bit key. + + Output format is `base64url(salt + nonce + ciphertext_and_tag)`, where: + - `salt` is 16 random bytes used for PBKDF2 key derivation; + - `nonce` is 32 random bytes used by AES-GCM; + - `ciphertext_and_tag` is the AES-GCM output. + + Key derivation: + 1. derive a salted key with + `__generate_fernet_key_kdf()`; + 2. hash that value with SHA-256; + 3. use the first 32 bytes of the hex digest text as the AES key. + + Args: + plain_text: Text to encrypt. + secret_key: Secret used to derive the encryption key. + + Returns: + URL-safe Base64 string containing salt, nonce, and encrypted payload. + """ nonce = os.urandom(32) salt = os.urandom(16) key = __generate_fernet_key_kdf(secret_key, salt) @@ -50,6 +131,25 @@ def encrypt_aes_gcm_256(plain_text: str, secret_key: str) -> str: def decrypt_aes_gcm_256(encrypted_data: str, secret_key: str) -> str: + """ + Decrypts data produced by `encrypt_aes_gcm_256()`. + + Input format must be `base64url(salt + nonce + ciphertext_and_tag)`, where the + first 16 bytes are salt and the next 32 bytes are AES-GCM nonce. + + Args: + encrypted_data: URL-safe Base64 payload returned by + `encrypt_aes_gcm_256()`. + secret_key: Secret used to derive the decryption key. + + Returns: + Decrypted UTF-8 text. + + Raises: + binascii.Error: If `encrypted_data` is not valid Base64. + cryptography.exceptions.InvalidTag: If authentication fails during AES-GCM + decryption. + """ ciphertext_data_in_bytes = base64.urlsafe_b64decode(encrypted_data) salt = ciphertext_data_in_bytes[:16] key = __generate_fernet_key_kdf(secret_key, salt) diff --git a/sdk/python/packages/flet/src/flet/testing/__init__.py b/sdk/python/packages/flet/src/flet/testing/__init__.py new file mode 100644 index 0000000000..04bc8fcd95 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/testing/__init__.py @@ -0,0 +1,5 @@ +from flet.testing.finder import Finder +from flet.testing.flet_test_app import DisposalMode, FletTestApp +from flet.testing.tester import Tester + +__all__ = ["DisposalMode", "Finder", "FletTestApp", "Tester"] diff --git a/sdk/python/packages/flet/src/flet/testing/finder.py b/sdk/python/packages/flet/src/flet/testing/finder.py new file mode 100644 index 0000000000..69f58df4c2 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/testing/finder.py @@ -0,0 +1,54 @@ +from dataclasses import dataclass + +__all__ = ["Finder"] + + +@dataclass +class Finder: + """ + Finder is used to search for controls by different criteria. + """ + + id: int + """ + Internal finder ID - corresponds to a Finder instance on Dart side. + """ + + count: int + """ + The number of controls found by this finder. + """ + + index: int = 0 + """ + The index of the control to interact with when multiple controls are found. + """ + + @property + def first(self) -> "Finder": + """ + Returns a Finder that finds the first control found by this finder. + """ + if self.count == 0: + raise ValueError("No controls found by this finder.") + return Finder(id=self.id, count=1, index=0) + + @property + def last(self) -> "Finder": + """ + Returns a Finder that finds the last control found by this finder. + """ + if self.count == 0: + raise ValueError("No controls found by this finder.") + return Finder(id=self.id, count=1, index=self.count - 1) + + def at(self, index: int) -> "Finder": + """ + Returns a Finder that finds the control at the given index. + + Args: + index: The index of the control to find. + """ + if index < 0 or index >= self.count: + raise IndexError("Index out of range.") + return Finder(id=self.id, count=1, index=index) diff --git a/sdk/python/packages/flet/src/flet/testing/flet_test_app.py b/sdk/python/packages/flet/src/flet/testing/flet_test_app.py new file mode 100644 index 0000000000..33cf45e15a --- /dev/null +++ b/sdk/python/packages/flet/src/flet/testing/flet_test_app.py @@ -0,0 +1,760 @@ +import asyncio +import inspect +import logging +import os +import platform +import tempfile +from collections.abc import Iterable, Sequence +from enum import Enum +from io import BytesIO +from pathlib import Path +from typing import TYPE_CHECKING, Optional, Union + +import numpy as np +from PIL import Image, ImageSequence +from skimage.metrics import structural_similarity as ssim + +import flet as ft +from flet.controls.control import Control +from flet.testing.tester import Tester +from flet.utils.network import get_free_tcp_port +from flet.utils.platform_utils import get_bool_env_var + +if TYPE_CHECKING: + from flet.app import AppCallable + +__all__ = ["FletTestApp"] + + +class DisposalMode(Enum): + """ + Indicates the way in which a frame is treated after being displayed. + """ + + DEFAULT = 0 + """ + No disposal method specified + """ + + NONE = 1 + """ + Do not dispose + """ + + BACKGROUND = 2 + """ + Restore to background color. + """ + + PREVIOUS = 3 + """ + Restore to previous content. + """ + + +class FletTestApp: + """ + Flet app test controller coordinates running a Python-based Flet app alongside \ + a Flutter integration test. + + This class launches the Python Flet app, starts the Flutter test process, + and facilitates programmatic interaction with the app's controls for + automated UI testing. + + Args: + flutter_app_dir: + Path to the Flutter app directory containing integration tests. + + flet_app_main: + A callable or coroutine function representing the main entry point + of the Flet app under test. This will be invoked with a + :class:`~flet.Page` instance when the app starts. + + assets_dir: + Path to the directory containing static assets for the Flet app. + Defaults to `"assets"` if not provided. + + test_path: + Path to the Python test file. Used to determine the location for + golden screenshot comparisons. + + tcp_port: + TCP port to run the Flet server on. If not specified, a free port + is automatically selected. + + test_platform: + Target platform for the Flutter integration test + (e.g., `"windows"`, `"linux"`, `"macos"`, `"android"`, `"ios"`). + Env override: `FLET_TEST_PLATFORM`. + + test_device: + Target device ID or name for the Flutter integration test. + Env override: `FLET_TEST_DEVICE`. + + capture_golden_screenshots: + If `True`, screenshots taken during tests are stored as golden + reference images. Env override: `FLET_TEST_GOLDEN=1`. + + screenshots_pixel_ratio: + Device pixel ratio to use when capturing screenshots. + Env override: `FLET_TEST_SCREENSHOTS_PIXEL_RATIO`. + + screenshots_similarity_threshold: + Minimum percentage similarity required for screenshot comparisons + to pass. Env override: `FLET_TEST_SCREENSHOTS_SIMILARITY_THRESHOLD`. + + use_http: + If `True`, use HTTP transport instead of TCP for Flet client-server + communication. Env override: `FLET_TEST_USE_HTTP=1`. + + disable_fvm: + If `True`, do not invoke `fvm` when running the Flutter test + process. Env override: `FLET_TEST_DISABLE_FVM=1`. + + skip_pump_and_settle: + If `True`, the initial `pump_and_settle` after app start is skipped. + + Environment Variables: + - `FLET_TEST_PLATFORM`: Overrides `test_platform`. + - `FLET_TEST_DEVICE`: Overrides `test_device`. + - `FLET_TEST_GOLDEN`: Enables golden screenshot capture when set to `1`. + - `FLET_TEST_SCREENSHOTS_PIXEL_RATIO`: Overrides `screenshots_pixel_ratio`. + - `FLET_TEST_SCREENSHOTS_SIMILARITY_THRESHOLD`: + Overrides `screenshots_similarity_threshold`. + - `FLET_TEST_USE_HTTP`: Enables HTTP transport when set to `1`. + - `FLET_TEST_DISABLE_FVM`: Disables `fvm` usage when set to `1`. + """ + + def __init__( + self, + flutter_app_dir: os.PathLike, + flet_app_main: Optional["AppCallable"] = None, + assets_dir: Optional[os.PathLike] = None, + test_path: Optional[str] = None, + tcp_port: Optional[int] = None, + test_platform: Optional[str] = None, + test_device: Optional[str] = None, + capture_golden_screenshots: bool = False, + screenshots_pixel_ratio: float = 2.0, + screenshots_similarity_threshold: float = 99.0, + use_http: bool = False, + disable_fvm: bool = False, + skip_pump_and_settle: bool = False, + ): + self.test_platform = os.getenv("FLET_TEST_PLATFORM", test_platform) + self.test_device = os.getenv("FLET_TEST_DEVICE", test_device) + self.__golden = ( + get_bool_env_var("FLET_TEST_GOLDEN") or capture_golden_screenshots + ) + self.screenshots_pixel_ratio = float( + os.getenv("FLET_TEST_SCREENSHOTS_PIXEL_RATIO", screenshots_pixel_ratio) + ) + self.screenshots_similarity_threshold = float( + os.getenv( + "FLET_TEST_SCREENSHOTS_SIMILARITY_THRESHOLD", + screenshots_similarity_threshold, + ) + ) + self.__disable_fvm = get_bool_env_var("FLET_TEST_DISABLE_FVM") or disable_fvm + self.__use_http = get_bool_env_var("FLET_TEST_USE_HTTP") or use_http + self.__test_path = test_path + self.__flet_app_main = flet_app_main + self.__skip_pump_and_settle = skip_pump_and_settle + self.__flutter_app_dir = flutter_app_dir + self.__assets_dir = assets_dir or "assets" + self.__tcp_port = tcp_port + self.__flutter_process: Optional[asyncio.subprocess.Process] = None + self.__page = None + self.__tester: Tester | None = None + + @property + def page(self) -> ft.Page: + """ + Returns an instance of Flet's app :class:`~flet.Page`. + """ + if self.__page is None: + raise RuntimeError("page is not initialized") + return self.__page + + @property + def tester(self) -> Tester: + """ + Returns an instance of `Tester` class that programmatically \ + interacts with page controls and the test environment. + """ + if self.__tester is None: + raise RuntimeError("tester is not initialized") + return self.__tester + + async def start(self): + """ + Starts Flet app and Flutter integration test process. + """ + + ready = asyncio.Event() + + async def main(page: ft.Page): + """ + Initializes the test page and runs the user-provided Flet app entry point. + + Args: + page: Connected app :class:`~flet.Page` instance. + """ + self.__page = page + self.__tester = Tester() + page.theme_mode = ft.ThemeMode.LIGHT + page.update() + + if inspect.iscoroutinefunction(self.__flet_app_main): + await self.__flet_app_main(page) + elif callable(self.__flet_app_main): + self.__flet_app_main(page) + if not self.__skip_pump_and_settle: + await self.__pump_and_settle_with_timeout("start") + ready.set() + + if not self.__tcp_port: + self.__tcp_port = get_free_tcp_port() + + if self.__use_http: + os.environ["FLET_FORCE_WEB_SERVER"] = "true" + + asyncio.create_task( + ft.run_async( + main, port=self.__tcp_port, assets_dir=str(self.__assets_dir), view=None + ) + ) + print("Started Flet app") + + stdout = asyncio.subprocess.DEVNULL + stderr = asyncio.subprocess.DEVNULL + if logging.getLogger().getEffectiveLevel() == logging.DEBUG: + stdout = None + stderr = None + + flutter_args = ["fvm", "flutter", "test", "integration_test"] + + if self.__disable_fvm: + flutter_args.pop(0) + + if self.test_platform is None: + self.test_platform = { + "Windows": "windows", + "Linux": "linux", + "Darwin": "macos", + }.get(platform.system(), "unknown") + + if not self.test_device: + self.test_device = self.test_platform + + tcp_addr = "10.0.2.2" if self.test_platform == "android" else "127.0.0.1" + protocol = "http" if self.__use_http else "tcp" + + if self.test_device: + flutter_args += ["-d", self.test_device] + + app_url = f"{protocol}://{tcp_addr}:{self.__tcp_port}" + flutter_args += [f"--dart-define=FLET_TEST_APP_URL={app_url}"] + + if not self.__use_http: + temp_path = Path(tempfile.gettempdir()) / "flet_app_pid.txt" + flutter_args += [f"--dart-define=FLET_TEST_PID_FILE_PATH={temp_path}"] + if self.__assets_dir: + flutter_args += [ + f"--dart-define=FLET_TEST_ASSETS_DIR={self.__assets_dir}" + ] + + self.__flutter_process = await asyncio.create_subprocess_exec( + *flutter_args, + cwd=str(self.__flutter_app_dir), + stdout=stdout, + stderr=stderr, + ) + + print("Started Flutter test process.") + print("Waiting for a Flet client to connect...") + + while not ready.is_set(): + await asyncio.sleep(0.2) + if self.__flutter_process.returncode is not None: + raise RuntimeError( + "Flutter process exited early with code " + f"{self.__flutter_process.returncode}" + ) + + async def teardown(self): + """ + Teardown Flutter integration test process. + """ + try: + await self.tester.teardown(timeout=10) + except (RuntimeError, TimeoutError) as e: + print(f"Tester teardown failed: {e}") + + if self.__flutter_process: + print("\nWaiting for Flutter test process to exit...") + try: + await asyncio.wait_for(self.__flutter_process.wait(), timeout=10) + print("Flutter test process has exited.") + except asyncio.TimeoutError: + print("Flutter test process did not exit in time, terminating it...") + self.__flutter_process.terminate() + # Optionally ensure it terminates + try: + await asyncio.wait_for(self.__flutter_process.wait(), timeout=5) + except asyncio.TimeoutError: + print("Force killing Flutter test process...") + self.__flutter_process.kill() + + def resize_page(self, width: int, height: int): + """ + Resizes the page window to the specified width and height. + """ + if self.page.window.width is None or self.page.window.height is None: + return + + chrome_width = self.page.window.width - self.page.width + chrome_height = self.page.window.height - self.page.height + self.page.window.width = width + chrome_width + self.page.window.height = height + chrome_height + + async def wrap_page_controls_in_screenshot( + self, + margin=10, + pump_times: int = 0, + pump_duration: Optional[ft.DurationValue] = None, + ) -> ft.Screenshot: + """ + Wraps provided controls in a Screenshot control. + """ + controls = list(self.page.controls) + self.page.controls = [ + scr := ft.Screenshot( + ft.Column(controls, margin=margin, intrinsic_width=True) + ) + ] # type: ignore + self.page.update() + await self.__pump_and_settle_with_timeout("wrap_page_controls_in_screenshot") + for _ in range(0, pump_times): + await self.tester.pump(duration=pump_duration) + return scr + + async def take_page_controls_screenshot( + self, + pixel_ratio: Optional[float] = None, + pump_times: int = 0, + pump_duration: Optional[ft.DurationValue] = None, + ) -> bytes: + """ + Takes a screenshot of all controls on the current page. + """ + scr = await self.wrap_page_controls_in_screenshot( + pump_times=pump_times, pump_duration=pump_duration + ) + return await scr.capture( + pixel_ratio=pixel_ratio or self.screenshots_pixel_ratio + ) + + async def assert_control_screenshot( + self, + name: str, + control: Control, + pump_times: int = 0, + pump_duration: Optional[ft.DurationValue] = None, + expand_screenshot: bool = False, + similarity_threshold: float = 0, + ): + """ + Adds control to a clean page, takes a screenshot and compares it with a golden \ + copy or takes golden screenshot if `FLET_TEST_GOLDEN=1` environment variable \ + is set. + + Args: + name: Screenshot name - will be used as a base for a screenshot filename. + control: Control to take a screenshot of. + """ + # clean page + self.page.clean() + await self.__pump_and_settle_with_timeout("assert_control_screenshot-clean") + + # add control and take screenshot + screenshot = ft.Screenshot(control, expand=expand_screenshot) + self.page.add(screenshot) + await self.__pump_and_settle_with_timeout("assert_control_screenshot-add") + for _ in range(0, pump_times): + await self.tester.pump(duration=pump_duration) + self.assert_screenshot( + name, + await screenshot.capture(pixel_ratio=self.screenshots_pixel_ratio), + similarity_threshold=similarity_threshold, + ) + + async def __pump_and_settle_with_timeout(self, stage: str): + try: + await self.tester.pump_and_settle(timeout=self.__pump_and_settle_timeout) + except TimeoutError as e: + raise TimeoutError( + f"Timed out during {stage}: " + f"tester.pump_and_settle() did not complete in " + f"{self.__pump_and_settle_timeout} seconds" + ) from e + + def assert_screenshot( + self, name: str, screenshot: bytes, similarity_threshold: float = 0 + ): + """ + Compares provided screenshot with a golden copy or takes golden screenshot if \ + `FLET_TEST_GOLDEN=1` environment variable is set. + + Args: + name: Screenshot name - will be used as a base for a screenshot filename. + screenshot: Screenshot contents in PNG format. + """ + if not self.test_platform: + raise RuntimeError( + "FLET_TEST_PLATFORM environment variable must be set " + "to test with screenshots" + ) + if not self.__test_path: + raise RuntimeError("test_path must be set to test with screenshots") + + golden_image_path = ( + Path(self.__test_path).parent + / "golden" + / self.test_platform + / Path(self.__test_path).stem.removeprefix("test_") + / f"{name.removeprefix('test_')}.png" + ) + + if self.__golden: + golden_image_path.parent.mkdir(parents=True, exist_ok=True) + with open(golden_image_path, "bw") as f: + f.write(screenshot) + else: + if not golden_image_path.exists(): + raise RuntimeError( + f"Golden image for {name} not found: {golden_image_path}" + ) + golden_img = self._load_image_from_file(golden_image_path) + img = self._load_image_from_bytes(screenshot) + similarity = self._compare_images_rgb(golden_img, img) + print(f"Similarity for {name}: {similarity}%") + if similarity_threshold == 0: + similarity_threshold = self.screenshots_similarity_threshold + if similarity <= similarity_threshold: + actual_image_path = ( + golden_image_path.parent + / f"{golden_image_path.parent.stem}_{golden_image_path.stem}_actual.png" # noqa: E501 + ) + with open(actual_image_path, "bw") as f: + f.write(screenshot) + assert similarity > similarity_threshold, ( + f"{name} screenshots are not identical " + f"(similarity: {similarity}% <= {similarity_threshold}%)" + ) + + def _load_image_from_file(self, file_name: Union[str, Path]) -> Image.Image: + """ + Loads an image from disk. + + Args: + file_name: Path to an image file. + + Returns: + Loaded Pillow image object. + """ + return Image.open(file_name) + + def _load_image_from_bytes(self, data: bytes) -> Image.Image: + """ + Loads an image from PNG bytes. + + Args: + data: Image data bytes. + + Returns: + Loaded Pillow image object. + """ + return Image.open(BytesIO(data)) + + def _compare_images_rgb(self, img1: Image.Image, img2: Image.Image) -> float: + """ + Calculates structural similarity between two RGB images. + + If image sizes differ, the second image is resized to match the first image + before comparison. + + Args: + img1: Reference image. + img2: Image to compare. + + Returns: + Similarity percentage in the `0..100` range. + """ + if img1.size != img2.size: + img2 = img2.resize(img1.size) + arr1 = np.array(img1) + arr2 = np.array(img2) + similarity, _ = ssim(arr1, arr2, channel_axis=-1, full=True) + return similarity * 100 + + def create_gif( + self, + image_names: Optional[Iterable[str]] = None, + output_name: str = "", + *, + frames: Optional[Iterable[bytes]] = None, + duration: Union[int, Sequence[int]] = 1000, + loop: int = 0, + disposal: DisposalMode = DisposalMode.DEFAULT, + ) -> Path: + """Create an animated GIF from a sequence of PNG frames. + + Exactly one of ``image_names`` or ``frames`` must be provided. Unlike + :meth:`assert_gif`, this method only writes the GIF and returns its + path; it does not compare against a golden file. + + Args: + image_names: Iterable of file name stems (without ``.png``) in the + order they should appear in the animation. Frames are read from + disk under the test's golden directory. + output_name: Base name for the resulting animation. The ``.gif`` + extension is added automatically and the file is stored in the + same directory as the source frames. + frames: Iterable of PNG-encoded frame bytes to use directly, in the + order they should appear in the animation. Typically paired + with :meth:`Page.take_animation`. + duration: Frame duration in milliseconds. Either a single ``int`` + applied to every frame, or a sequence of ``int`` with one + entry per frame. Pass the same list used for + ``take_animation(frame_delays_ms=...)`` to have the GIF play + at the same pace it was captured. + loop: Number of times the GIF should repeat (``0`` means infinite). + disposal: Frame disposal mode. + + Returns: + Path to the generated GIF file. + + Raises: + ValueError: If neither or both of ``image_names`` / ``frames`` are + given, the input is empty, or a ``duration`` sequence has a + different length than the frame count. + FileNotFoundError: If any referenced image file does not exist. + """ + + if not self.__test_path: + raise ValueError("test_path must be set to create GIF animations") + if not self.test_platform: + raise ValueError("test_platform must be set to create GIF animations") + if (image_names is None) == (frames is None): + raise ValueError("Exactly one of image_names or frames must be provided") + + golden_dir = self._golden_dir() + output = golden_dir / f"{output_name}.gif" + output.parent.mkdir(parents=True, exist_ok=True) + + if image_names is not None: + names = list(image_names) + if not names: + raise ValueError("image_names must contain at least one entry") + frame_bytes_list: list[bytes] = [] + for name in names: + path = golden_dir / f"{name}.png" + if not path.exists(): + raise FileNotFoundError(path) + frame_bytes_list.append(path.read_bytes()) + else: + frame_bytes_list = list(frames or ()) + + gif_bytes = self._frames_to_gif_bytes( + frame_bytes_list, duration, loop, disposal + ) + output.write_bytes(gif_bytes) + return output + + def _golden_dir(self) -> Path: + return ( + Path(self.__test_path).parent + / "golden" + / self.test_platform + / Path(self.__test_path).stem.removeprefix("test_") + ) + + def _frames_to_gif_bytes( + self, + frames: list[bytes], + duration: Union[int, Sequence[int]], + loop: int, + disposal: DisposalMode, + ) -> bytes: + if not frames: + raise ValueError("frames must contain at least one entry") + gif_frames: list[Image.Image] = [] + try: + for frame_bytes in frames: + with Image.open(BytesIO(frame_bytes)) as img: + gif_frames.append( + img.convert("RGB").convert( + "P", palette=Image.ADAPTIVE, colors=256 + ) + ) + + if isinstance(duration, int): + save_duration: Union[int, list[int]] = duration + else: + save_duration = list(duration) + if len(save_duration) != len(gif_frames): + raise ValueError( + f"duration sequence length ({len(save_duration)}) must " + f"match frame count ({len(gif_frames)})" + ) + + first, *rest = gif_frames + out = BytesIO() + first.save( + out, + format="GIF", + save_all=True, + append_images=rest, + duration=save_duration, + loop=loop, + optimize=True, + disposal=disposal.value, + ) + return out.getvalue() + finally: + for frame in gif_frames: + frame.close() + + def _gif_frames_from_bytes(self, data: bytes) -> list[Image.Image]: + frames: list[Image.Image] = [] + with Image.open(BytesIO(data)) as gif: + for frame in ImageSequence.Iterator(gif): + frames.append(frame.convert("RGBA")) + return frames + + def _assert_gif_bytes( + self, name: str, golden_gif_bytes: bytes, actual_gif_bytes: bytes + ) -> None: + golden_frames = self._gif_frames_from_bytes(golden_gif_bytes) + actual_frames = self._gif_frames_from_bytes(actual_gif_bytes) + try: + assert len(golden_frames) == len(actual_frames), ( + f"{name} GIF frame count differs " + f"({len(actual_frames)} != {len(golden_frames)})" + ) + for index, (golden_frame, actual_frame) in enumerate( + zip(golden_frames, actual_frames, strict=True) + ): + similarity = self._compare_images_rgb(golden_frame, actual_frame) + print(f"GIF similarity for {name} frame {index}: {similarity}%") + assert similarity > self.screenshots_similarity_threshold, ( + f"{name} GIF frame {index} differs " + f"(similarity: {similarity}% <= " + f"{self.screenshots_similarity_threshold}%)" + ) + except AssertionError: + actual_gif_path = self._golden_dir() / f"{name}_actual.gif" + actual_gif_path.write_bytes(actual_gif_bytes) + raise + finally: + for frame in golden_frames: + frame.close() + for frame in actual_frames: + frame.close() + + def assert_gif( + self, + name: str, + frames: Iterable[bytes], + *, + duration: Union[int, Sequence[int]] = 1000, + loop: int = 0, + disposal: DisposalMode = DisposalMode.DEFAULT, + similarity_threshold: float = 0, + ): + """Compare an animated GIF built from `frames` against a golden GIF. + + Builds the GIF in memory from the provided frames. If the + `FLET_TEST_GOLDEN=1` environment variable is set, writes the GIF as + the golden reference. Otherwise loads the existing golden GIF from + disk and compares frame-by-frame via structural similarity, saving + an `_actual.gif` next to the golden on mismatch. + + Args: + name: GIF name - will be used as a base for the GIF file name. + frames: Iterable of PNG-encoded frame bytes. Typically the result + of `Page.take_animation(...)`. + duration: Frame duration in milliseconds. Either a single `int` + or a per-frame sequence matching the number of frames. + loop: Number of times the GIF should repeat (`0` means infinite). + disposal: Frame disposal mode. + similarity_threshold: Minimum acceptable per-frame SSIM (%). Uses + `screenshots_similarity_threshold` when `0`. + """ + if not self.test_platform: + raise RuntimeError( + "FLET_TEST_PLATFORM environment variable must be set to test with GIFs" + ) + if not self.__test_path: + raise RuntimeError("test_path must be set to test with GIFs") + + gif_bytes = self._frames_to_gif_bytes(list(frames), duration, loop, disposal) + + golden_gif_path = self._golden_dir() / f"{name.removeprefix('test_')}.gif" + + if self.__golden: + golden_gif_path.parent.mkdir(parents=True, exist_ok=True) + golden_gif_path.write_bytes(gif_bytes) + return + + if not golden_gif_path.exists(): + raise RuntimeError(f"Golden GIF for {name} not found: {golden_gif_path}") + + similarity, frame_count_mismatch = self._compare_gifs( + golden_gif_path, gif_bytes + ) + print(f"Similarity for {name}: {similarity}%") + if similarity_threshold == 0: + similarity_threshold = self.screenshots_similarity_threshold + + if frame_count_mismatch or similarity <= similarity_threshold: + actual_gif_path = ( + golden_gif_path.parent + / f"{golden_gif_path.parent.stem}_{golden_gif_path.stem}_actual.gif" # noqa: E501 + ) + actual_gif_path.write_bytes(gif_bytes) + + if frame_count_mismatch: + raise AssertionError(frame_count_mismatch) + assert similarity > similarity_threshold, ( + f"{name} GIFs are not identical " + f"(similarity: {similarity}% <= {similarity_threshold}%)" + ) + + def _compare_gifs( + self, golden_path: Path, current_bytes: bytes + ) -> tuple[float, Optional[str]]: + """Returns (min-per-frame similarity, frame-count-mismatch message).""" + with ( + Image.open(golden_path) as golden, + Image.open(BytesIO(current_bytes)) as current, + ): + if golden.n_frames != current.n_frames: + return ( + 0.0, + f"GIF frame count mismatch: " + f"golden={golden.n_frames}, current={current.n_frames}", + ) + similarities: list[float] = [] + for i in range(golden.n_frames): + golden.seek(i) + current.seek(i) + similarities.append( + self._compare_images_rgb( + golden.convert("RGB"), current.convert("RGB") + ) + ) + return min(similarities), None + + __pump_and_settle_timeout = 10.0 diff --git a/sdk/python/packages/flet/src/flet/testing/tester.py b/sdk/python/packages/flet/src/flet/testing/tester.py new file mode 100644 index 0000000000..e2ade7b808 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/testing/tester.py @@ -0,0 +1,263 @@ +from typing import Optional + +from flet.controls.base_control import control +from flet.controls.duration import DurationValue +from flet.controls.keys import KeyValue +from flet.controls.services.service import Service +from flet.controls.transform import Offset +from flet.controls.types import IconData +from flet.testing.finder import Finder + +__all__ = ["Tester"] + + +@control("Tester") +class Tester(Service): + """ + Class that programmatically interacts with page controls and the test environment. + """ + + async def pump(self, duration: Optional[DurationValue] = None): + """ + Triggers a frame after duration amount of time. + + Args: + duration: A duration after which to trigger a frame. + """ + return await self._invoke_method("pump", {"duration": duration}) + + async def pump_and_settle( + self, duration: Optional[DurationValue] = None, timeout: Optional[float] = 10 + ): + """ + Repeatedly calls pump until there are no longer any frames scheduled. + This will call `pump` at least once, even if no frames are scheduled when + the function is called, to flush any pending microtasks which may + themselves schedule a frame. + + This essentially waits for all animations to have completed. + + Args: + duration: A duration after which to trigger a frame. + timeout: Maximum seconds to wait for completion. + """ + return await self._invoke_method( + "pump_and_settle", {"duration": duration}, timeout=timeout + ) + + async def find_by_text(self, text: str) -> Finder: + """ + Finds controls containing string equal to the `text` argument. + + Args: + text: The exact text value to search control by. + """ + finder = await self._invoke_method("find_by_text", {"text": text}) + return Finder(**finder) + + async def find_by_text_containing(self, pattern: str) -> Finder: + """ + Finds controls containing specified text pattern. + + Args: + pattern: Regular expression pattern. + """ + finder = await self._invoke_method( + "find_by_text_containing", {"pattern": pattern} + ) + return Finder(**finder) + + async def find_by_key(self, key: KeyValue) -> Finder: + """ + Finds controls by a :class:`~flet.Key` instance or key name. + + Args: + key: A key instance or its name. + """ + finder = await self._invoke_method("find_by_key", {"key": key}) + return Finder(**finder) + + async def find_by_tooltip(self, value: str) -> Finder: + """ + Finds controls by a tooltip. + + Args: + value: Tooltip value. + """ + finder = await self._invoke_method("find_by_tooltip", {"value": value}) + return Finder(**finder) + + async def find_by_icon(self, icon: IconData) -> Finder: + """ + Finds controls by an icon. + + Args: + icon: The Icon to search by. + """ + finder = await self._invoke_method("find_by_icon", {"icon": icon}) + return Finder(**finder) + + async def take_screenshot(self, name: str) -> bytes: + """ + Takes a screenshot of the entire application window. + This method works when testing on iOS and Android only. + + Args: + name: The name of the screenshot. + + Returns: + Screenshot in PNG format. + """ + return await self._invoke_method("take_screenshot", {"name": name}) + + async def tap(self, finder: Finder): + """ + Dispatch a pointer down / pointer up sequence at the center of the given \ + control, assuming it is exposed. + + Args: + finder: Finder to search for a control. + """ + await self._invoke_method( + "tap", {"finder_id": finder.id, "finder_index": finder.index} + ) + + async def mouse_click(self, finder: Finder): + """ + Dispatch a primary mouse click at the center of the given control. + + Args: + finder: Finder to search for a control. + """ + await self._invoke_method( + "mouse_click", {"finder_id": finder.id, "finder_index": finder.index} + ) + + async def right_mouse_click(self, finder: Finder): + """ + Dispatch a secondary mouse click at the center of the given control. + + Args: + finder: Finder to search for a control. + """ + await self._invoke_method( + "right_mouse_click", + {"finder_id": finder.id, "finder_index": finder.index}, + ) + + async def mouse_double_click(self, finder: Finder): + """ + Dispatch a primary mouse double click at the center of the given control. + + Args: + finder: Finder to search for a control. + """ + await self._invoke_method( + "mouse_double_click", + {"finder_id": finder.id, "finder_index": finder.index}, + ) + + async def tap_at(self, offset: Offset): + """ + Dispatch a pointer down / pointer up sequence at the given offset. + + Args: + offset: Offset value at which tap will occur. + """ + await self._invoke_method("tap_at", {"offset": offset}) + + async def mouse_click_at(self, offset: Offset): + """ + Dispatch a primary mouse click at the given offset. + + Args: + offset: Offset value at which the click will occur. + """ + await self._invoke_method("mouse_click_at", {"offset": offset}) + + async def right_mouse_click_at(self, offset: Offset): + """ + Dispatch a secondary mouse click at the given offset. + + Args: + offset: Offset value at which the click will occur. + """ + await self._invoke_method("right_mouse_click_at", {"offset": offset}) + + async def mouse_double_click_at(self, offset: Offset): + """ + Dispatch a primary mouse double click at the given offset. + + Args: + offset: Offset value at which the double click will occur. + """ + await self._invoke_method("mouse_double_click_at", {"offset": offset}) + + async def drag(self, finder: Finder, offset: Offset): + """ + Drag from the center of the given control by the provided offset. + + Args: + finder: Finder to search for a control. + offset: Offset delta to drag by. + """ + await self._invoke_method( + "drag", + {"finder_id": finder.id, "finder_index": finder.index, "offset": offset}, + ) + + async def drag_from(self, start: Offset, offset: Offset): + """ + Drag from the given start offset by the provided offset delta. + + Args: + start: Initial pointer location. + offset: Offset delta to drag by. + """ + await self._invoke_method("drag_from", {"start": start, "offset": offset}) + + async def long_press(self, finder: Finder): + """ + Dispatch a pointer down / pointer up sequence (with a delay of 600 ms between \ + the two events) at the center of the given control, assuming it is exposed. + + Args: + finder: Finder to search for a control. + """ + await self._invoke_method( + "long_press", {"finder_id": finder.id, "finder_index": finder.index} + ) + + async def enter_text(self, finder: Finder, text: str): + """ + Give the text input control specified by `finder` the focus and replace its \ + content with `text`, as if it had been provided by the onscreen keyboard. + + Args: + finder: Finder to search for a control. + text: The text to enter. + """ + await self._invoke_method( + "enter_text", + {"finder_id": finder.id, "finder_index": finder.index, "text": text}, + ) + + async def mouse_hover(self, finder: Finder): + """ + Dispatch a pointer hover event at the center of the given control. + + Args: + finder: Finder to search for a control. + """ + await self._invoke_method( + "mouse_hover", {"finder_id": finder.id, "finder_index": finder.index} + ) + + async def teardown(self, timeout: Optional[float] = 10): + """ + Teardown Flutter integration test and exit Flutter process. + + Args: + timeout: Maximum seconds to wait for teardown acknowledgement. + """ + await self._invoke_method("teardown", timeout=timeout) diff --git a/sdk/python/packages/flet/src/flet/utils/__init__.py b/sdk/python/packages/flet/src/flet/utils/__init__.py index ce8d09f0db..162f491948 100644 --- a/sdk/python/packages/flet/src/flet/utils/__init__.py +++ b/sdk/python/packages/flet/src/flet/utils/__init__.py @@ -1,16 +1,21 @@ from flet.utils.browser import open_in_browser from flet.utils.classproperty import classproperty -from flet.utils.deprecated import deprecated +from flet.utils.deprecated import deprecated, deprecated_class, deprecated_warning +from flet.utils.deprecated_enum import DeprecatedEnumMeta from flet.utils.files import ( cleanup_path, copy_tree, get_current_script_dir, is_within_directory, safe_tar_extractall, + safe_zip_extractall, which, ) +from flet.utils.from_dict import from_dict from flet.utils.hashing import calculate_file_hash, sha1 +from flet.utils.json_utils import to_json from flet.utils.network import get_free_tcp_port, get_local_ip +from flet.utils.object_model import get_param_count, patch_dataclass from flet.utils.once import Once from flet.utils.platform_utils import ( get_arch, @@ -30,3 +35,44 @@ from flet.utils.slugify import slugify from flet.utils.strings import random_string from flet.utils.vector import Vector + +__all__ = [ + "DeprecatedEnumMeta", + "Once", + "Vector", + "calculate_file_hash", + "classproperty", + "cleanup_path", + "copy_tree", + "deprecated", + "deprecated_class", + "deprecated_warning", + "from_dict", + "get_arch", + "get_bool_env_var", + "get_current_script_dir", + "get_free_tcp_port", + "get_local_ip", + "get_param_count", + "get_platform", + "is_android", + "is_asyncio", + "is_embedded", + "is_ios", + "is_linux", + "is_linux_server", + "is_macos", + "is_mobile", + "is_pyodide", + "is_windows", + "is_within_directory", + "open_in_browser", + "patch_dataclass", + "random_string", + "safe_tar_extractall", + "safe_zip_extractall", + "sha1", + "slugify", + "to_json", + "which", +] diff --git a/sdk/python/packages/flet/src/flet/utils/browser.py b/sdk/python/packages/flet/src/flet/utils/browser.py index 494ec86dcf..57d42d2300 100644 --- a/sdk/python/packages/flet/src/flet/utils/browser.py +++ b/sdk/python/packages/flet/src/flet/utils/browser.py @@ -1,9 +1,16 @@ from flet.utils.platform_utils import is_mobile -def open_in_browser(url): +def open_in_browser(url: str): + """ + Opens a URL in the system default browser on non-mobile platforms. + + On mobile targets, this function does nothing. + + Args: + url: URL to open. + """ if not is_mobile(): import webbrowser webbrowser.open(url) - diff --git a/sdk/python/packages/flet/src/flet/utils/classproperty.py b/sdk/python/packages/flet/src/flet/utils/classproperty.py index b6d2cb6a8a..ae8b870dd3 100644 --- a/sdk/python/packages/flet/src/flet/utils/classproperty.py +++ b/sdk/python/packages/flet/src/flet/utils/classproperty.py @@ -1,12 +1,11 @@ -from typing import TypeVar, Type, Any, Callable - +from typing import Any, Callable, TypeVar T = TypeVar("T") class classproperty: - def __init__(self, func: Callable[[Type[T]], Any]) -> None: + def __init__(self, func: Callable[[type[T]], Any]) -> None: self.fget = func - def __get__(self, instance: T, owner: Type[T]) -> Any: + def __get__(self, instance: T, owner: type[T]) -> Any: return self.fget(owner) diff --git a/sdk/python/packages/flet/src/flet/utils/deprecated.py b/sdk/python/packages/flet/src/flet/utils/deprecated.py index 4734dcb01d..0599f024f7 100644 --- a/sdk/python/packages/flet/src/flet/utils/deprecated.py +++ b/sdk/python/packages/flet/src/flet/utils/deprecated.py @@ -1,58 +1,167 @@ +""" +Utilities for runtime deprecation warnings in Flet. + +This module provides: +- decorator-based warnings for functions/methods/classes; +- class-constructor warnings for deprecated classes; +- direct warning helper used by validation rules. +""" + import functools +import sys import warnings -from typing import Optional +from typing import Any, Callable, Optional, TypeVar + +__all__ = ["deprecated", "deprecated_class", "deprecated_warning"] + +_FuncT = TypeVar("_FuncT", bound=Callable[..., Any]) +_ClassT = TypeVar("_ClassT", bound=type[Any]) -def deprecated(reason: str, version: str, delete_version: str, is_method=True): +def _resolve_user_stacklevel(default: int = 2) -> int: """ - A decorator function that marks a function/method/property/event as deprecated. + Return a `warnings.warn` stacklevel that points outside `flet.*` internals. + + This keeps deprecation warnings attributed to user code by default, so they + are visible without requiring explicit warning filter configuration. + """ + + try: + frame = sys._getframe(1) + except Exception: + return default + + stacklevel = 1 + while frame is not None: + module_name = frame.f_globals.get("__name__", "") + if module_name != "flet" and not module_name.startswith("flet."): + return stacklevel + frame = frame.f_back + stacklevel += 1 - :param reason: The reason for deprecation. - :param version: The version from which the function was deprecated. - :param delete_version: The version in which the function will be removed from the API. - :param is_method: if the deprecated item is a method (True) or property/function/event (False) + return default + + +def _warn_deprecation(message: str) -> None: + """Emit a `DeprecationWarning` attributed to user code when possible.""" + warnings.warn( + message, + category=DeprecationWarning, + stacklevel=_resolve_user_stacklevel(), + ) + + +def deprecated( + reason: str, + version: Optional[str] = None, + delete_version: Optional[str] = None, + show_parentheses: bool = False, + docs_reason: Optional[str] = None, +) -> Callable[[_FuncT], _FuncT]: """ + Marks a function, method, or class as deprecated. - def decorator(func): + Args: + reason: The reason for deprecation. + version: The version from which the function was deprecated. + delete_version: The version in which the function will be removed. + show_parentheses: Whether to show parentheses after the function/class name + in the warning. + docs_reason: Optional docs-only reason. This value is ignored at runtime + and is consumed by docs tooling when available. + """ + _ = docs_reason # Consumed by docs tooling; runtime warnings use `reason`. + + def decorator(func: _FuncT) -> _FuncT: @functools.wraps(func) - def new_func(*args, **kwargs): - warnings.warn( - f"{func.__name__}{'()' if is_method else ''} is deprecated since version {version} " - f"and will be removed in version {delete_version}. {reason}", - category=DeprecationWarning, - stacklevel=2, - ) + def wrapper(*args, **kwargs): + msg = f"{func.__name__}{'()' if show_parentheses else ''} is deprecated" + if version: + msg += f" since version {version}" + if delete_version: + msg += f" and will be removed in version {delete_version}" + msg += f". {reason}" + _warn_deprecation(msg) return func(*args, **kwargs) - return new_func + return wrapper # type: ignore[return-value] return decorator -def deprecated_class(reason: str, version: str, delete_version: str): - def decorator(cls): - msg = f"{cls.__name__} is deprecated since version {version} and will be removed in version {delete_version}. {reason}" +def deprecated_class( + reason: str, + version: str, + delete_version: str, + docs_reason: Optional[str] = None, +) -> Callable[[_ClassT], _ClassT]: + """ + Marks a class as deprecated. + + Args: + reason: The reason for deprecation used in runtime warnings. + version: The version from which the class is deprecated. + delete_version: The version in which the class will be removed. + docs_reason: Optional docs-only reason. This value is ignored at runtime + and is consumed by docs tooling when available. + """ + _ = docs_reason # Consumed by docs tooling; runtime warnings use `reason`. + + def decorator(cls: _ClassT) -> _ClassT: + msg = ( + f"{cls.__name__} is deprecated since version {version} and will be removed " + f"in version {delete_version}. {reason}" + ) # Wrap the original __init__ method orig_init = cls.__init__ @functools.wraps(orig_init) def new_init(self, *args, **kwargs): - warnings.warn(msg, category=DeprecationWarning, stacklevel=2) + _warn_deprecation(msg) orig_init(self, *args, **kwargs) cls.__init__ = new_init + + # Wrap the original __post_init__ method + orig_post_init = cls.__post_init__ + + @functools.wraps(orig_post_init) + def new_post_init(self, *args, **kwargs): + _warn_deprecation(msg) + orig_post_init(self, *args, **kwargs) + + cls.__post_init__ = new_post_init + return cls return decorator -def deprecated_property( - name: str, reason: str, version: str, delete_version: Optional[str] = None +def deprecated_warning( + name: str, + reason: str, + version: str, + delete_version: Optional[str] = None, + type: str = "property", ): - warnings.warn( - f"{name} property is deprecated since version {version}" - f"{' and will be removed in version ' + delete_version if delete_version else ''}. {reason}", - category=DeprecationWarning, - stacklevel=2, + """ + Helper function to issue a standardized deprecation warning message. + + Args: + name: The name of the deprecated object. + reason: A short explanation of why the object is deprecated and/or what to + use instead. + version: The version in which the object was marked as deprecated. + delete_version: The version in which the object is scheduled to be + removed (optional). + type: The type of the object being deprecated (e.g., "property"). + Defaults to "property". + """ + delete_version_text = ( + f" and will be removed in version {delete_version}" if delete_version else "" + ) + _warn_deprecation( + f"{name} {type} is deprecated since version {version}{delete_version_text}. " + f"{reason}" ) diff --git a/sdk/python/packages/flet/src/flet/utils/deprecated_enum.py b/sdk/python/packages/flet/src/flet/utils/deprecated_enum.py new file mode 100644 index 0000000000..294bdf8054 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/deprecated_enum.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +import warnings +from enum import EnumMeta + +__all__ = ["DeprecatedEnumMeta"] + + +class DeprecatedEnumMeta(EnumMeta): + """Enum metaclass that supports deprecation aliases. + + Enums can declare `_deprecated_members_` as a mapping of alias name to a tuple + containing the canonical member name and a deprecation message. Accessing an alias + returns the canonical member while emitting a `DeprecationWarning`. + """ + + def _resolve_deprecated(cls, name: str): + """ + Resolve deprecated enum alias to its canonical member. + + Looks up `name` in `_deprecated_members_`, emits a + `warnings.DeprecationWarning` when matched, and + returns the canonical enum member. + + Args: + name: Enum member name requested by caller. + + Returns: + Canonical enum member when `name` is a deprecated alias; otherwise + `None`. + """ + + deprecated = getattr(cls, "_deprecated_members_", {}) + info = deprecated.get(name) + if not info: + return None + target_name, message = info + warnings.warn( + f"{cls.__name__}.{name} is deprecated. {message}", + DeprecationWarning, + stacklevel=2, + ) + return getattr(cls, target_name) + + def __getattr__(cls, name: str): + member = cls._resolve_deprecated(name) + if member is not None: + return member + return super().__getattr__(name) + + def __getitem__(cls, name: str): + member = cls._resolve_deprecated(name) + if member is not None: + return member + return super().__getitem__(name) diff --git a/sdk/python/packages/flet/src/flet/utils/files.py b/sdk/python/packages/flet/src/flet/utils/files.py index 68dca221cc..f63e21ff60 100644 --- a/sdk/python/packages/flet/src/flet/utils/files.py +++ b/sdk/python/packages/flet/src/flet/utils/files.py @@ -4,6 +4,16 @@ def is_within_directory(directory, target): + """ + Checks whether `target` is located within `directory`. + + Args: + directory: Base directory path. + target: Candidate path to validate. + + Returns: + `True` if `target` resolves under `directory`, otherwise `False`. + """ abs_directory = os.path.abspath(directory) abs_target = os.path.abspath(target) @@ -13,23 +23,93 @@ def is_within_directory(directory, target): def safe_tar_extractall(tar, path=".", members=None, *, numeric_owner=False): + """ + Extracts a tar archive after validating member paths. + + The function prevents path traversal by ensuring each archive member resolves + within the destination directory. + + Args: + tar: Open `tarfile.TarFile` object. + path: Destination directory. + members: Optional member subset to extract. + numeric_owner: Whether to use numeric user/group IDs. + + Raises: + RuntimeError: If a member attempts to escape the destination directory. + """ for member in tar.getmembers(): member_path = os.path.join(path, member.name) if not is_within_directory(path, member_path): - raise Exception("Attempted Path Traversal in Tar File") + raise RuntimeError("Attempted Path Traversal in Tar File") tar.extractall(path, members, numeric_owner=numeric_owner) +def safe_zip_extractall(zf, path="."): + """ + Extracts a zip archive after validating member paths. + + The function prevents path traversal by ensuring each archive member resolves + within the destination directory. + + Args: + zf: Open `zipfile.ZipFile` object. + path: Destination directory. + + Raises: + RuntimeError: If a member attempts to escape the destination directory. + """ + for member in zf.namelist(): + member_path = os.path.join(path, member) + if not is_within_directory(path, member_path): + raise RuntimeError("Attempted Path Traversal in Zip File") + + zf.extractall(path) + + def copy_tree(src, dst, ignore=None): + """ + Copies a directory tree into `dst`. + + This wrapper preserves symlinks and allows copying into an existing + destination directory. + + Args: + src: Source directory path. + dst: Destination directory path. + ignore: Optional callable used to ignore names during copy. + + Returns: + The destination directory path. + """ return shutil.copytree(src, dst, ignore=ignore, symlinks=True, dirs_exist_ok=True) # https://stackoverflow.com/questions/377017/test-if-executable-exists-in-python def which(program, exclude_exe=None): + """ + Finds the first executable matching `program` in `PATH`. + + Args: + program: Executable filename to search for. + exclude_exe: Absolute executable path to skip when searching. + + Returns: + Absolute path to the first matching executable, or `None` if not found. + """ import os def is_exe(fpath): + """ + Checks whether `fpath` points to an executable file. + + Args: + fpath: Candidate file path. + + Returns: + `True` if `fpath` exists and is executable, otherwise `False`. + """ return os.path.isfile(fpath) and os.access(fpath, os.X_OK) for path in os.environ["PATH"].split(os.pathsep): @@ -44,6 +124,19 @@ def is_exe(fpath): def cleanup_path(path: str, executable: str): + """ + Removes directories containing a given executable from a PATH-like string. + + The check also removes directories containing Windows launcher variants: + `.bat` and `.cmd`. + + Args: + path: PATH-like string separated by `os.pathsep`. + executable: Executable name to filter out. + + Returns: + Filtered PATH-like string. + """ cleaned_dirs = [] for path_dir in path.split(os.pathsep): found = False @@ -58,5 +151,11 @@ def cleanup_path(path: str, executable: str): def get_current_script_dir(): + """ + Returns the absolute directory of the current script entry point. + + Returns: + Absolute directory path derived from `sys.argv[0]`. + """ pathname = os.path.dirname(sys.argv[0]) return os.path.abspath(pathname) diff --git a/sdk/python/packages/flet/src/flet/utils/from_dict.py b/sdk/python/packages/flet/src/flet/utils/from_dict.py new file mode 100644 index 0000000000..8a19f21bc7 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/from_dict.py @@ -0,0 +1,140 @@ +import dataclasses +import sys +from enum import Enum +from typing import ( + Any, + ForwardRef, + TypeVar, + Union, + get_args, + get_origin, + get_type_hints, +) + +from flet.utils.typing_utils import eval_type + +T = TypeVar("T") + + +def from_dict(cls: type[T], data: Any) -> T: + """ + Converts `data` into an instance of `cls`. + + The function supports dataclasses, nested dataclasses, generic aliases, + `ForwardRef` annotations, enum values, lists, dictionaries, and optionals. + + Args: + cls: Target type to construct. + data: Input value to convert. + + Returns: + Converted value as an instance of `cls` (or compatible type). + """ + # Handle generic types and ForwardRefs + origin = get_origin(cls) or cls + args = get_args(cls) + + # If cls is a generic like Event[T], resolve T + if args: + cls = origin # drop the generic info; dataclasses only apply to the base class + + # If cls is a ForwardRef, resolve it + if isinstance(cls, ForwardRef): + globalns = sys.modules[cls.__module__].__dict__ + cls = eval_type(cls, globalns, None) + + if dataclasses.is_dataclass(cls): + try: + type_hints = get_type_hints( + cls, globalns=sys.modules[cls.__module__].__dict__ + ) + except Exception: + type_hints = {f.name: f.type for f in dataclasses.fields(cls)} # fallback + + init_values = {} + post_values = {} + + for field in dataclasses.fields(cls): + field_name = field.name + field_type = type_hints.get(field_name, field.type) + data_field_name = field.metadata.get("data_field", field_name) + + if data_field_name in data: + value = data[data_field_name] + converted = convert_value(field_type, value) + init_values[field_name] = converted + + # set _prev_* values + post_values[f"_prev_{field_name}"] = converted + + # First create the object using init-only fields + instance = cls(**init_values) + + # Now set the _prev_* fields via setattr (won’t raise errors + # if they're not declared) + for k, v in post_values.items(): + setattr(instance, k, v) + + return instance + + else: + return convert_value(cls, data) + + +def convert_value(field_type: type, value: Any) -> Any: + """ + Converts a value to its appropriate type based on the field_type. + Handles nested dataclasses, enums, lists, dicts, and optionals. + + Args: + field_type: The type to convert the value to. + value: The value to convert. + + Returns: + The converted value. + """ + origin = get_origin(field_type) + args = get_args(field_type) + + # Optional[T] + if origin is Union and type(None) in args: + inner_type = [arg for arg in args if arg is not type(None)][0] + if value is None: + return None + return convert_value(inner_type, value) + + # Enum + if isinstance(field_type, type) and issubclass(field_type, Enum): + return field_type(value) + + # Dataclass + if dataclasses.is_dataclass(field_type) and isinstance(value, dict): + return from_dict(field_type, value) + + # List[T] + if origin is list and isinstance(value, list): + item_type = args[0] + return [convert_value(item_type, item) for item in value] + + # Dict[K, V] + if origin is dict and isinstance(value, dict): + key_type, val_type = args + return { + convert_value(key_type, k): convert_value(val_type, v) + for k, v in value.items() + } + + return value # literal + + +def is_literal(value: Any) -> bool: + """ + Checks if a value is a basic literal (int, float, str, bool, or None). + + Args: + value: The value to check. + + Returns: + True if the value is a literal type; False otherwise. + """ + return isinstance(value, (int, float, str, bool, type(None))) diff --git a/sdk/python/packages/flet/src/flet/utils/griffe_deprecations.py b/sdk/python/packages/flet/src/flet/utils/griffe_deprecations.py new file mode 100644 index 0000000000..d726ae33fa --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/griffe_deprecations.py @@ -0,0 +1,369 @@ +""" +Griffe extension for rendering deprecation details in API docs. + +This extension centralizes deprecation detection for Flet docs. It supports: +- class/function decorators: + - `warnings.deprecated(...)` + - `typing_extensions.deprecated(...)` + - `flet.utils.deprecated(...)` + - `flet.utils.deprecated_class(...)` +- property getters decorated as `@property` and `flet.utils.deprecated(...)` +- attribute metadata: + - `typing.Annotated[..., V.deprecated(...)]` + +Detected deprecations are inserted as a docstring admonition and labeled with +`deprecated`. +""" + +import ast +from typing import Any, Optional, Union + +from griffe import ( + Attribute, + Class, + Docstring, + DocstringSectionAdmonition, + ExprCall, + ExprKeyword, + ExprName, + ExprSubscript, + ExprTuple, + Extension, + Function, +) + +__all__ = ["FletDeprecationsExtension"] + +_ANNOTATED_PATHS = {"typing.Annotated", "typing_extensions.Annotated"} +_V_DEPRECATED_PATH = "flet.utils.validation.V.deprecated" +_PEP702_DECORATORS = {"warnings.deprecated", "typing_extensions.deprecated"} +_FLET_FUNCTION_DECORATORS = { + "flet.utils.deprecated", + "flet.utils.deprecated.deprecated", + "deprecated", +} +_FLET_CLASS_DECORATORS = { + "flet.utils.deprecated_class", + "flet.utils.deprecated.deprecated_class", +} + + +def _text(expr: Any) -> Optional[str]: + """Best-effort extraction of readable text from a Griffe expression.""" + if expr is None: + return None + if isinstance(expr, ExprName): + return expr.name + raw = expr.strip() if isinstance(expr, str) else str(expr).strip() + + if raw == "": + return None + + try: + return str(ast.literal_eval(raw)) + except Exception: + return raw + + +def _split_call_arguments(call: ExprCall) -> tuple[list[Any], dict[str, Any]]: + """Split call arguments into positional and keyword dictionaries.""" + positional: list[Any] = [] + keywords: dict[str, Any] = {} + for arg in call.arguments: + if isinstance(arg, ExprKeyword): + keywords[arg.name] = arg.value + else: + positional.append(arg) + return positional, keywords + + +def _compose_message( + *, + reason: Optional[str], + version: Optional[str], + delete_version: Optional[str], +) -> str: + """ + Compose a concise deprecation summary suitable for a docs admonition. + """ + prefix = "Deprecated." + if version and delete_version: + prefix = ( + f"Deprecated since version `{version}` and scheduled for removal in " + f"`{delete_version}`." + ) + elif version: + prefix = f"Deprecated since version `{version}`." + elif delete_version: + prefix = f"Scheduled for removal in version `{delete_version}`." + + if reason: + return f"{prefix} {reason}".strip() + return prefix + + +def _extract_deprecation_from_decorators(obj: Union[Class, Function]) -> Optional[str]: + """Extract deprecation details from supported class/function decorators.""" + for decorator in obj.decorators or []: + call = decorator.value + path = decorator.callable_path + if not path or not isinstance(call, ExprCall): + continue + + positional, keywords = _split_call_arguments(call) + reason: Optional[str] = None + version: Optional[str] = None + delete_version: Optional[str] = None + + if path in _PEP702_DECORATORS: + if positional: + reason = _text(positional[0]) + if reason is None: + reason = "This API is deprecated." + return _compose_message( + reason=reason, version=version, delete_version=delete_version + ) + + if path in _FLET_FUNCTION_DECORATORS: + reason = _text(keywords.get("reason")) + if reason is None and positional: + reason = _text(positional[0]) + docs_reason = _text(keywords.get("docs_reason")) + + version = _text(keywords.get("version")) + if version is None and len(positional) > 1: + version = _text(positional[1]) + + delete_version = _text(keywords.get("delete_version")) + if delete_version is None and len(positional) > 2: + delete_version = _text(positional[2]) + + return _compose_message( + reason=docs_reason or reason, + version=version, + delete_version=delete_version, + ) + + if path in _FLET_CLASS_DECORATORS: + reason = _text(keywords.get("reason")) + if reason is None and positional: + reason = _text(positional[0]) + docs_reason = _text(keywords.get("docs_reason")) + + version = _text(keywords.get("version")) + if version is None and len(positional) > 1: + version = _text(positional[1]) + + delete_version = _text(keywords.get("delete_version")) + if delete_version is None and len(positional) > 2: + delete_version = _text(positional[2]) + + return _compose_message( + reason=docs_reason or reason, + version=version, + delete_version=delete_version, + ) + + return None + + +def _extract_v_deprecated_call(attribute: Attribute) -> Optional[ExprCall]: + """ + Return the `V.deprecated(...)` call from `Annotated[...]` metadata, if present. + """ + annotation = attribute.annotation + if not isinstance(annotation, ExprSubscript): + return None + if annotation.canonical_path not in _ANNOTATED_PATHS: + return None + if not isinstance(annotation.slice, ExprTuple): + return None + + for metadata in annotation.slice.elements[1:]: + if isinstance(metadata, ExprCall) and ( + metadata.canonical_path == _V_DEPRECATED_PATH + or metadata.canonical_path.endswith(".V.deprecated") + ): + return metadata + return None + + +def _extract_deprecation_from_attribute(attribute: Attribute) -> Optional[str]: + """ + Extract deprecation details from `Annotated[..., V.deprecated(...)]`. + """ + call = _extract_v_deprecated_call(attribute) + if call is None: + return None + + positional, keywords = _split_call_arguments(call) + replacement = _text(keywords.get("replacement")) + if replacement is None and positional: + replacement = _text(positional[0]) + + reason = _text(keywords.get("reason")) + docs_reason = _text(keywords.get("docs_reason")) + selected_reason = docs_reason or reason + if selected_reason is None: + selected_reason = ( + f"Use `{replacement}` instead." + if replacement is not None + else "This property is deprecated." + ) + + version = _text(keywords.get("version")) + delete_version = _text(keywords.get("delete_version")) + + return _compose_message( + reason=selected_reason, + version=version, + delete_version=delete_version, + ) + + +def _ast_decorator_name(expr: ast.AST) -> Optional[str]: + """Return the dotted callable name for a decorator AST node when possible.""" + if isinstance(expr, ast.Call): + return _ast_decorator_name(expr.func) + if isinstance(expr, ast.Name): + return expr.id + if isinstance(expr, ast.Attribute): + parent = _ast_decorator_name(expr.value) + return f"{parent}.{expr.attr}" if parent else expr.attr + return None + + +def _ast_text(expr: Optional[ast.AST]) -> Optional[str]: + """Best-effort extraction of readable text from a Python AST expression.""" + if expr is None: + return None + try: + return str(ast.literal_eval(expr)) + except Exception: + try: + return ast.unparse(expr) + except Exception: + return None + + +def _extract_deprecation_from_property_decorators(node: ast.AST) -> Optional[str]: + """ + Extract deprecation details from a `@property` getter + AST node decorated with `@deprecated`. + + Griffe exposes `@property` getters as `Attribute` objects in the final + object model, so the getter decorators are no longer available there. The + original `FunctionDef` is still passed into `on_attribute_instance`, + which lets us recover the deprecation arguments and transfer them onto the + resulting attribute for docs rendering. + """ + if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): + return None + + has_property = False + deprecated_call: Optional[ast.Call] = None + for decorator in node.decorator_list: + name = _ast_decorator_name(decorator) + if name == "property": + has_property = True + continue + if isinstance(decorator, ast.Call) and name in _FLET_FUNCTION_DECORATORS: + deprecated_call = decorator + + if not has_property or deprecated_call is None: + return None + + positional = list(deprecated_call.args) + keywords = { + keyword.arg: keyword.value + for keyword in deprecated_call.keywords + if keyword.arg is not None + } + + reason = _ast_text(keywords.get("reason")) + if reason is None and positional: + reason = _ast_text(positional[0]) + docs_reason = _ast_text(keywords.get("docs_reason")) + + version = _ast_text(keywords.get("version")) + if version is None and len(positional) > 1: + version = _ast_text(positional[1]) + + delete_version = _ast_text(keywords.get("delete_version")) + if delete_version is None and len(positional) > 2: + delete_version = _ast_text(positional[2]) + + return _compose_message( + reason=docs_reason or reason, + version=version, + delete_version=delete_version, + ) + + +class FletDeprecationsExtension(Extension): + """ + Add deprecation admonitions for supported Flet and PEP 702 patterns. + """ + + def __init__( + self, + kind: str = "warning", + title: str = "Deprecated", + label: Optional[str] = "deprecated", + ) -> None: + super().__init__() + self.kind = kind + self.title = title + self.label = label + + def _insert_message(self, obj: Any, message: str) -> None: + """ + Insert deprecation admonition/label on a Griffe object once. + + The method is idempotent for identical admonition payloads. + """ + if not obj.docstring: + obj.docstring = Docstring("", parent=obj) + + sections = obj.docstring.parsed + for section in sections: + if ( + isinstance(section, DocstringSectionAdmonition) + and section.title == self.title + and getattr(section.value, "contents", None) == message + and getattr(section.value, "kind", None) == self.kind + ): + break + else: + sections.insert( + 0, + DocstringSectionAdmonition( + kind=self.kind, + title=self.title, + text=message, + ), + ) + + if self.label: + obj.labels.add(self.label) + if hasattr(obj, "deprecated"): + obj.deprecated = message + + def on_class_instance(self, *, cls: Class, **kwargs: Any) -> None: # noqa: ARG002 + if message := _extract_deprecation_from_decorators(cls): + self._insert_message(cls, message) + + def on_function_instance(self, *, func: Function, **kwargs: Any) -> None: # noqa: ARG002 + if message := _extract_deprecation_from_decorators(func): + self._insert_message(func, message) + + def on_attribute_instance( + self, *, node: ast.AST, attr: Attribute, **kwargs: Any + ) -> None: # noqa: ARG002 + if message := _extract_deprecation_from_attribute(attr): + self._insert_message(attr, message) + return + # Property getters arrive here as Attributes, so decorator-based + # deprecations must be recovered from the original getter AST node. + if message := _extract_deprecation_from_property_decorators(node): + self._insert_message(attr, message) diff --git a/sdk/python/packages/flet/src/flet/utils/hashing.py b/sdk/python/packages/flet/src/flet/utils/hashing.py index a295ce1966..ea1294cc8b 100644 --- a/sdk/python/packages/flet/src/flet/utils/hashing.py +++ b/sdk/python/packages/flet/src/flet/utils/hashing.py @@ -2,12 +2,36 @@ def sha1(input_string): + """ + Calculates SHA-1 digest for a UTF-8 string. + + Args: + input_string: Input text to hash. + + Returns: + Hexadecimal SHA-1 digest string. + """ sha1_hash = hashlib.sha1() sha1_hash.update(input_string.encode("utf-8")) return sha1_hash.hexdigest() def calculate_file_hash(path, blocksize=65536): + """ + Calculates SHA-256 digest for a file. + + The file is read incrementally using `blocksize` chunks. + + Args: + path: Path to the file. + blocksize: Number of bytes to read per iteration. + + Returns: + Hexadecimal SHA-256 digest string. + + Raises: + OSError: If the file cannot be opened or read. + """ h = hashlib.sha256() with open(path, "rb") as f: while True: diff --git a/sdk/python/packages/flet/src/flet/utils/json_utils.py b/sdk/python/packages/flet/src/flet/utils/json_utils.py new file mode 100644 index 0000000000..214cdef19d --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/json_utils.py @@ -0,0 +1,21 @@ +import json +from typing import Optional + +from flet.controls.embed_json_encoder import EmbedJsonEncoder + + +def to_json(value) -> Optional[str]: + """ + Serializes a value to compact JSON using Flet's embedded encoder. + + Args: + value: Value to serialize. + + Returns: + JSON string without extra whitespace, or `None` when `value` is `None`. + """ + return ( + json.dumps(value, cls=EmbedJsonEncoder, separators=(",", ":")) + if value is not None + else None + ) diff --git a/sdk/python/packages/flet/src/flet/utils/linux_deps.py b/sdk/python/packages/flet/src/flet/utils/linux_deps.py new file mode 100644 index 0000000000..f30b3c3f32 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/linux_deps.py @@ -0,0 +1,36 @@ +"""Canonical Linux apt dependencies used by Flet workflows.""" + +from typing import Final + +linux_dependencies: Final[tuple[str, ...]] = ( + "binutils", + "clang", + "cmake", + "gstreamer1.0-alsa", + "gstreamer1.0-gl", + "gstreamer1.0-gtk3", + "gstreamer1.0-libav", + "gstreamer1.0-plugins-bad", + "gstreamer1.0-plugins-base", + "gstreamer1.0-plugins-good", + "gstreamer1.0-plugins-ugly", + "gstreamer1.0-pulseaudio", + "gstreamer1.0-qt5", + "gstreamer1.0-tools", + "gstreamer1.0-x", + "libasound2-dev", + "libgstreamer-plugins-bad1.0-dev", + "libgstreamer-plugins-base1.0-dev", + "libgstreamer1.0-dev", + "libgtk-3-dev", + "libmpv-dev", + "libsecret-1-0", + "libsecret-1-dev", + "libunwind-dev", + "lld", + "llvm", + "mpv", + "ninja-build", + "pkg-config", +) +"""Linux apt packages required to build Flet Linux apps and client binaries.""" diff --git a/sdk/python/packages/flet/src/flet/utils/locks.py b/sdk/python/packages/flet/src/flet/utils/locks.py new file mode 100644 index 0000000000..b74168121f --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/locks.py @@ -0,0 +1,28 @@ +class NopeLock: + """ + No-op synchronous context manager used in place of a real lock. + + This class provides the same `with` interface as a lock but performs no + synchronization. + """ + + def __enter__(self): + pass + + def __exit__(self, *args): + pass + + +class AsyncNopeLock: + """ + No-op asynchronous context manager used in place of a real async lock. + + This class provides the same `async with` interface as an async lock but + performs no synchronization. + """ + + async def __aenter__(self): + pass + + async def __aexit__(self, *args): + pass diff --git a/sdk/python/packages/flet/src/flet/utils/network.py b/sdk/python/packages/flet/src/flet/utils/network.py index fa45860792..2b54fca1eb 100644 --- a/sdk/python/packages/flet/src/flet/utils/network.py +++ b/sdk/python/packages/flet/src/flet/utils/network.py @@ -1,14 +1,30 @@ - import socket def get_free_tcp_port(): + """ + Returns an available local TCP port selected by the operating system. + + The port is discovered by binding a socket to port `0`. + + Returns: + A TCP port number that was available at discovery time. + """ sock = socket.socket() sock.bind(("", 0)) return sock.getsockname()[1] def get_local_ip(): + """ + Returns the local IPv4 address used for outbound network traffic. + + This function first infers the address by opening a UDP socket to `8.8.8.8`. + If that fails, it falls back to resolving the machine hostname. + + Returns: + Local IPv4 address. + """ try: with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: s.connect(("8.8.8.8", 80)) diff --git a/sdk/python/packages/flet/src/flet/utils/object_model.py b/sdk/python/packages/flet/src/flet/utils/object_model.py new file mode 100644 index 0000000000..de473a39b9 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/object_model.py @@ -0,0 +1,144 @@ +import dataclasses +import inspect +import sys +from enum import Enum +from typing import Any, Union, get_args, get_origin, get_type_hints + +from flet.utils.from_dict import from_dict + + +def patch_dataclass(obj: Any, patch: dict): + """ + Applies a partial update to a dataclass instance in place. + + The function resolves field type hints and updates matching fields from `patch`, + including support for nested dataclasses, lists, enum values, and plain values. + Fields starting with `_` are set directly even when they are not declared in type + hints. + + For ``@control`` / ``@value`` objects (those with ``_values`` and + ``_prop_defaults``), Prop fields are written directly into ``_values`` rather + than going through ``Prop.__set__``. This avoids unnecessary dirty-tracking, + frozen-checks, and ``_notify`` calls — none of which are needed when applying + patches that originate *from* Dart rather than from Python code. + + Args: + obj: Dataclass instance to patch. + patch: Mapping of field names to new values. + """ + cls = obj.__class__ + + try: + frame = inspect.currentframe().f_back + globalns = sys.modules[cls.__module__].__dict__ + localns = frame.f_globals.copy() + localns.update(frame.f_locals) + hints = get_type_hints(cls, globalns=globalns, localns=localns) + except Exception: + hints = {f.name: f.type for f in dataclasses.fields(cls)} # fallback + # print("ERROR: ", cls.__name__, e) + + # For @control / @value objects write Prop fields directly into _values, + # bypassing dirty-tracking and other Prop.__set__ side-effects. + _values = getattr(obj, "_values", None) + _prop_defaults = getattr(type(obj), "_prop_defaults", None) + + def _write(field_name: str, value: Any) -> None: + if ( + _values is not None + and _prop_defaults is not None + and field_name in _prop_defaults + ): + prop_default = _prop_defaults[field_name] + if value == prop_default: + _values.pop(field_name, None) # keep _values sparse + else: + _values[field_name] = value + else: + object.__setattr__(obj, field_name, value) + + for field_name, value in patch.items(): + if field_name in hints: + field_type = hints[field_name] + current_value = getattr(obj, field_name, None) + actual_type = resolve_actual_type(field_type) + + if isinstance(actual_type, str): + continue # unresolved forward ref + + # Nested dataclass patching + if dataclasses.is_dataclass(actual_type) and isinstance(value, dict): + if current_value is None: + _write(field_name, from_dict(actual_type, value)) + else: + patch_dataclass(current_value, value) + + # List of dataclasses or values + elif get_origin(actual_type) is list and isinstance(value, list): + item_type = get_args(actual_type)[0] + if dataclasses.is_dataclass(item_type): + _write(field_name, [from_dict(item_type, item) for item in value]) + else: + _write(field_name, value) + + # Enum + elif is_enum(actual_type): + _write(field_name, actual_type(value)) + + # Simple literal or other value + else: + _write(field_name, value) + elif field_name.startswith("_"): + setattr(obj, field_name, value) + + +def resolve_actual_type(tp: Any) -> Any: + """ + Resolves effective runtime type for common optional annotations. + + For `Optional[T]` (represented as `Union[T, None]`), this function returns `T`. + Other annotations are returned unchanged. + + Args: + tp: Type annotation to resolve. + + Returns: + Resolved type annotation. + """ + origin = get_origin(tp) + args = get_args(tp) + + if origin is Union and len(args) == 2 and type(None) in args: + # It's Optional[T] + return args[0] if args[1] is type(None) else args[1] + + return tp + + +def is_enum(tp: Any) -> bool: + """ + Indicates whether a value is an enum class. + + Args: + tp: Value to check. + + Returns: + `True` if `tp` is a subclass of `enum.Enum`, otherwise `False`. + """ + return isinstance(tp, type) and issubclass(tp, Enum) + + +def get_param_count(fn): + """ + Returns the number of declared parameters for a callable. + + Args: + fn: Callable object to inspect. + + Returns: + Parameter count, or `None` when a signature cannot be determined. + """ + try: + return len(inspect.signature(fn).parameters) + except (ValueError, TypeError): + return None diff --git a/sdk/python/packages/flet/src/flet/utils/once.py b/sdk/python/packages/flet/src/flet/utils/once.py index f583f3ce21..17a0dd5007 100644 --- a/sdk/python/packages/flet/src/flet/utils/once.py +++ b/sdk/python/packages/flet/src/flet/utils/once.py @@ -2,11 +2,32 @@ class Once: + """ + Async helper that runs a coroutine function only once. + + Concurrent callers are synchronized with an `asyncio.Lock` so the + wrapped function executes at most one time per :class:`Once` instance. + """ + def __init__(self): self._lock = asyncio.Lock() self._done = False async def do(self, func, *args, **kwargs): + """ + Executes `func` exactly once for this instance. + + If another coroutine has already completed the call, this method returns + immediately without invoking `func`. + + Args: + func: Async callable to run once. + *args: Positional arguments passed to `func`. + **kwargs: Keyword arguments passed to `func`. + + Raises: + Exception: Propagates any exception raised by `func`. + """ if not self._done: async with self._lock: if not self._done: diff --git a/sdk/python/packages/flet/src/flet/utils/pip.py b/sdk/python/packages/flet/src/flet/utils/pip.py index 9bcbccbc09..5fa17b67c4 100644 --- a/sdk/python/packages/flet/src/flet/utils/pip.py +++ b/sdk/python/packages/flet/src/flet/utils/pip.py @@ -1,12 +1,25 @@ +import os import subprocess import sys +from importlib.util import find_spec import flet.version -def install_flet_package(name: str): - print(f"Installing {name} {flet.version.version} package...", end="") - retcode = subprocess.call( +def _install_with_pip(package_spec: str) -> int: + """ + Installs a package using `pip`. + + Args: + package_spec: Package requirement specifier to install (for example, + `flet-web==0.27.0`). + + Returns: + The `pip` process return code. Returns `1` when `pip` cannot be imported. + """ + if find_spec("pip") is None: + return 1 + return subprocess.call( [ sys.executable, "-m", @@ -14,52 +27,119 @@ def install_flet_package(name: str): "install", "-q", "--disable-pip-version-check", - f"{name}=={flet.version.version}", + package_spec, ] ) + + +def _install_with_uv(package_spec: str) -> int: + """ + Installs a package using `uv pip install`. + + Args: + package_spec: Package requirement specifier to install (for example, + `flet-web==0.27.0`). + + Returns: + The `uv` process return code. Returns `1` when `uv` is not installed. + """ + try: + return subprocess.call(["uv", "pip", "install", package_spec]) + except FileNotFoundError: + return 1 + + +def install_flet_package(name: str): + """ + Installs a Flet package pinned to the current Flet SDK version. + + Installation strategy: + - If `UV` environment variable is set, try `uv` first and then fall back to `pip`. + - Otherwise, try `pip` first and then fall back to `uv`. + + Args: + name: Package name to install. + + Raises: + SystemExit: If package installation fails with both installers. + """ + package_spec = f"{name}=={flet.version.flet_version}" + print(f"Installing {name} {flet.version.flet_version} package...", end="") + if os.environ.get("UV"): + retcode = _install_with_uv(package_spec) + if retcode != 0: + retcode = _install_with_pip(package_spec) + else: + retcode = _install_with_pip(package_spec) + if retcode != 0: + retcode = _install_with_uv(package_spec) if retcode == 0: print("OK") else: print( - f'Unable to upgrade "{name}" package to version {flet.version.version}. Please use "pip install \'flet[all]=={flet.version.version}\' --upgrade" command to upgrade Flet.' + f'Unable to install "{name}" package. Please run ' + f'"pip install {package_spec} --upgrade" ' + f'or "uv pip install {package_spec} --upgrade" ' + f"command." ) exit(1) def ensure_flet_desktop_package_installed(): + """ + Ensures a compatible desktop runtime package is installed. + + If `flet-desktop` is missing or its version differs from the current Flet SDK + version, this function installs the expected package via + `install_flet_package()`. + """ try: - import flet.version import flet_desktop.version - assert ( - not flet_desktop.version.version - or flet_desktop.version.version == flet.version.version - ) - except: + if ( + flet_desktop.version.version + and flet_desktop.version.version != flet.version.flet_version + ): + raise RuntimeError("flet-desktop version mismatch") + except Exception: install_flet_package("flet-desktop") def ensure_flet_web_package_installed(): + """ + Ensures a compatible `flet-web` package is installed. + + If `flet-web` is missing or its version differs from the current Flet SDK + version, this function installs it via + `install_flet_package()`. + """ try: - import flet.version import flet_web.version - assert ( - not flet_web.version.version - or flet_web.version.version == flet.version.version - ) - except: + if ( + flet_web.version.version + and flet_web.version.version != flet.version.flet_version + ): + raise RuntimeError("flet-web version mismatch") + except Exception: install_flet_package("flet-web") def ensure_flet_cli_package_installed(): + """ + Ensures a compatible `flet-cli` package is installed. + + If `flet-cli` is missing or its version differs from the current Flet SDK + version, this function installs it via + `install_flet_package()`. + """ try: - import flet.version import flet_cli.version - assert ( - not flet_cli.version.version - or flet_cli.version.version == flet.version.version - ) - except: + if ( + flet_cli.version.version + and flet_cli.version.version != flet.version.flet_version + ): + raise RuntimeError("flet-cli version mismatch") + except Exception: install_flet_package("flet-cli") diff --git a/sdk/python/packages/flet/src/flet/utils/platform_utils.py b/sdk/python/packages/flet/src/flet/utils/platform_utils.py index 4efdc1403d..fd313bdadb 100644 --- a/sdk/python/packages/flet/src/flet/utils/platform_utils.py +++ b/sdk/python/packages/flet/src/flet/utils/platform_utils.py @@ -2,13 +2,35 @@ import os import sys +from flet.controls.exceptions import FletUnsupportedPlatformException + def get_bool_env_var(name: str): + """ + Parses an environment variable value as a boolean. + + Args: + name: Environment variable name. + + Returns: + `True` when the variable value is `true`, `1`, or `yes` (case-insensitive); + `False` for any other defined value; `None` when the variable is not set. + """ v = os.getenv(name) return v.lower() in ["true", "1", "yes"] if v is not None else None def is_asyncio(): + """ + Indicates whether execution is inside an active asyncio task. + + This function also returns `True` on Pyodide, where the default execution model + is asynchronous even when no current task is available. + + Returns: + `True` when an asyncio task is active or when running on Pyodide, otherwise + `False`. + """ try: return asyncio.current_task() is not None or sys.platform == "emscripten" except RuntimeError: @@ -16,22 +38,52 @@ def is_asyncio(): def is_pyodide(): + """ + Indicates whether Python is running in a Pyodide environment. + + Returns: + `True` when `sys.platform` is `emscripten`, otherwise `False`. + """ return sys.platform == "emscripten" def is_ios(): + """ + Indicates whether the target platform is iOS. + + Returns: + `True` when `FLET_PLATFORM=ios`, otherwise `False`. + """ return os.getenv("FLET_PLATFORM") == "ios" def is_android(): + """ + Indicates whether the target platform is Android. + + Returns: + `True` when `FLET_PLATFORM=android`, otherwise `False`. + """ return os.getenv("FLET_PLATFORM") == "android" def is_embedded(): + """ + Indicates whether a platform is explicitly provided by the embedding runtime. + + Returns: + `True` when `FLET_PLATFORM` is set, otherwise `False`. + """ return os.getenv("FLET_PLATFORM") is not None def is_mobile(): + """ + Indicates whether the target platform is mobile. + + Returns: + `True` when targeting iOS or Android, otherwise `False`. + """ return is_ios() or is_android() @@ -40,19 +92,42 @@ def is_mobile(): def is_windows(): + """ + Indicates whether the current non-mobile host platform is Windows. + + Returns: + `True` on Windows hosts when not targeting mobile, otherwise `False`. + """ return not is_mobile() and platform.system() == "Windows" def is_linux(): + """ + Indicates whether the current non-mobile host platform is Linux. + + Returns: + `True` on Linux hosts when not targeting mobile, otherwise `False`. + """ return not is_mobile() and platform.system() == "Linux" def is_linux_server(): + """ + Indicates whether the current environment is a headless Linux server. + + The environment is considered a Linux server when: + - the host platform is Linux and not mobile; + - it is not Windows Subsystem for Linux (WSL); + - the `DISPLAY` environment variable is not set. + + Returns: + `True` for headless Linux server environments, otherwise `False`. + """ if not is_mobile() and platform.system() == "Linux": # check if it's WSL p = "/proc/version" if os.path.exists(p): - with open(p, "r", encoding="utf-8") as file: + with open(p, encoding="utf-8") as file: if "microsoft" in file.read(): return False # it's WSL, not a server return os.environ.get("DISPLAY") is None @@ -60,10 +135,26 @@ def is_linux_server(): def is_macos(): + """ + Indicates whether the current non-mobile host platform is macOS. + + Returns: + `True` on macOS hosts when not targeting mobile, otherwise `False`. + """ return not is_mobile() and platform.system() == "Darwin" def get_platform(): + """ + Returns the normalized platform identifier used by Flet. + + Returns: + One of: `windows`, `linux`, or `darwin`. + + Raises: + :class:`~flet.FletUnsupportedPlatformException`: If the current platform is + unsupported. + """ p = platform.system() if not is_mobile() else "" if is_windows(): return "windows" @@ -72,10 +163,20 @@ def get_platform(): elif p == "Darwin": return "darwin" else: - raise Exception(f"Unsupported platform: {p}") + raise FletUnsupportedPlatformException(f"Unsupported platform: {p}") def get_arch(): + """ + Returns the normalized CPU architecture identifier used by Flet. + + Returns: + One of: `amd64`, `arm64`, or `arm_7`. + + Raises: + :class:`~flet.FletUnsupportedPlatformException`: If the current architecture is + unsupported. + """ a = platform.machine().lower() if not is_mobile() else "" if a == "x86_64" or a == "amd64": return "amd64" @@ -84,4 +185,4 @@ def get_arch(): elif a.startswith("arm"): return "arm_7" else: - raise Exception(f"Unsupported architecture: {a}") + raise FletUnsupportedPlatformException(f"Unsupported architecture: {a}") diff --git a/sdk/python/packages/flet/src/flet/utils/slugify.py b/sdk/python/packages/flet/src/flet/utils/slugify.py index b547dae715..05a0c322ab 100644 --- a/sdk/python/packages/flet/src/flet/utils/slugify.py +++ b/sdk/python/packages/flet/src/flet/utils/slugify.py @@ -4,7 +4,7 @@ def slugify(value: str) -> str: """ - Converts to lowercase, removes non-word characters (alphanumerics and underscores) + Converts to lowercase, removes non-word characters (alphanumerics and underscores) \ and converts spaces to hyphens. Also strips leading and trailing whitespace. """ value = ( diff --git a/sdk/python/packages/flet/src/flet/utils/strings.py b/sdk/python/packages/flet/src/flet/utils/strings.py index e5ee2d55dc..fa6ced13dc 100644 --- a/sdk/python/packages/flet/src/flet/utils/strings.py +++ b/sdk/python/packages/flet/src/flet/utils/strings.py @@ -3,5 +3,14 @@ def random_string(length): + """ + Generates a cryptographically secure random alphanumeric string. + + Args: + length: Desired output length. + + Returns: + A random string containing ASCII letters and digits. + """ alphabet = string.ascii_letters + string.digits return "".join(secrets.choice(alphabet) for _ in range(length)) diff --git a/sdk/python/packages/flet/src/flet/utils/typing_utils.py b/sdk/python/packages/flet/src/flet/utils/typing_utils.py new file mode 100644 index 0000000000..86b79caaaf --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/typing_utils.py @@ -0,0 +1,29 @@ +from typing import _eval_type + +__all__ = ["eval_type"] + +_EMPTY_TYPE_PARAMS = () + + +def eval_type(annotation, globalns, localns, type_params=_EMPTY_TYPE_PARAMS): + """ + Evaluates a type annotation using runtime namespaces. + + This helper prefers calling `typing._eval_type()` with `type_params` support and + falls back to the older call signature for Python versions that do not accept + `type_params`. + + Args: + annotation: The type annotation object to evaluate. + globalns: Global namespace used to resolve forward references. + localns: Local namespace used to resolve forward references. + type_params: Generic type parameters used by newer Python versions. + + Returns: + The evaluated type annotation. + """ + try: + return _eval_type(annotation, globalns, localns, type_params=type_params) + except TypeError: + # Older Python versions don't accept type_params. + return _eval_type(annotation, globalns, localns) diff --git a/sdk/python/packages/flet/src/flet/utils/validation.py b/sdk/python/packages/flet/src/flet/utils/validation.py new file mode 100644 index 0000000000..70f87f4905 --- /dev/null +++ b/sdk/python/packages/flet/src/flet/utils/validation.py @@ -0,0 +1,1848 @@ +""" +Validation helpers for dataclass-style models, including Flet controls. + +This module provides composable rule objects that are attached to annotated +fields (`typing.Annotated`) and to class-level cross-field declarations +(`__validation_rules__`). + +Primary use cases: +1. Generic dataclass/domain model validation via direct `validate(instance)` calls. +2. Flet outbound validation, where `BaseControl` invokes `validate(self)` + before patch serialization so the invalid state fails on Python side first. + +The public entry points are: +- `V`, the rule-builder namespace used in `Annotated[...]` metadata and + `__validation_rules__`. +- `validate()`, which evaluates the compiled field and class rules for one + instance. +- `FieldRule` and `ClassRule`, lightweight wrappers used by the runtime and + by advanced callers defining custom validation callbacks. +""" + +import sys +from collections.abc import Iterable +from dataclasses import dataclass +from functools import cache +from typing import ( + Annotated, + Any, + Callable, + ClassVar, + Optional, + Union, + get_args, + get_origin, + get_type_hints, +) + +from flet.utils.deprecated import deprecated_warning + +__all__ = [ + "ClassRule", + "FieldRule", + "V", + "ValidationDeclarationError", + "ValidationRules", + "validate", +] + +FieldCheck = Callable[[Any, str, Any], None] +"""Signature for a field-level validator callback.""" + +FieldMessage = Union[str, Callable[[Any, str, Any], str]] +"""Static text or callable used to format a field-level error message.""" + +ClassCheck = Callable[[Any], None] +"""Signature for a class-level validator callback.""" + +ClassMessage = Union[str, Callable[[Any], str]] +"""Static text or callable used to format a class-level error message.""" + +ClassPredicate = Callable[[Any], bool] +"""Boolean predicate used by `V.ensure()`.""" + + +class ValidationDeclarationError(RuntimeError): + """ + Raised when a validation rule declaration is invalid. + + This exception is for authoring mistakes in the validation declaration + itself, such as invalid builder arguments or malformed rule composition. + Runtime validation failures for instance values raise `ValueError` + instead. + """ + + +@dataclass(frozen=True) +class FieldRule: + """ + A single validation rule applied to one annotated field value. + + Instances of this dataclass are usually created via `V.*` helpers and + stored in `Annotated[...]` metadata. + """ + + _check: FieldCheck + + def validate(self, instance: Any, field_name: str, value: Any) -> None: + """ + Validate one field value for a specific instance. + + Args: + instance: Model or control instance currently being validated. + field_name: Name of the field associated with this rule. + value: Current runtime value read from `instance.`. + + Raises: + ValueError: If the wrapped field check rejects `value`. + """ + self._check(instance, field_name, value) + + +@dataclass(frozen=True) +class ClassRule: + """ + A cross-field validation rule evaluated against one class instance. + + Instances of this dataclass are usually created via `V.ensure()` or + declared directly in `__validation_rules__`. + """ + + _check: ClassCheck + + def validate(self, instance: Any) -> None: + """ + Validate one instance against a class-level rule. + + Args: + instance: Model or control instance currently being validated. + + Raises: + ValueError: If the wrapped class check rejects `instance`. + """ + self._check(instance) + + +ValidationRules = ClassVar[tuple[ClassRule, ...]] +"""Alias for class-level `__validation_rules__` tuples.""" + + +@dataclass(frozen=True) +class _ClassValidationSpec: + """ + Compiled validation specification for one class. + + Attributes: + field_rules: Ordered `(field_name, rule)` pairs extracted from + `Annotated[...]` metadata across the class MRO. + class_rules: Ordered class-level rules extracted from + `__validation_rules__` across the class MRO. + """ + + field_rules: tuple[tuple[str, FieldRule], ...] + class_rules: tuple[ClassRule, ...] + + +_DEPRECATED_WARNINGS_KEY = "__deprecated_validation_warnings" +_REPORTED_VALIDATION_ERRORS_KEY = "__reported_validation_errors" + + +def _get_warned_deprecated_fields(instance: Any) -> Optional[set[str]]: + """ + Return a mutable set of already-emitted deprecation warning keys. + + Warnings are tracked on a private runtime attribute so they do not leak into + serialized control data. + + Args: + instance: Model or control instance used to store the warning cache. + + Returns: + A mutable set attached to `instance`, or `None` when the instance does + not allow attaching the private cache attribute. + """ + + warned = getattr(instance, _DEPRECATED_WARNINGS_KEY, None) + if warned is not None: + return warned + + warned = set() + try: + setattr(instance, _DEPRECATED_WARNINGS_KEY, warned) + except Exception: + return None + return warned + + +def _get_reported_validation_errors( + instance: Any, +) -> Optional[set[tuple[str, str]]]: + """ + Return a mutable set of already-reported validation error signatures. + + Signatures are stored on the instance to suppress repeated identical + `ValueError` failures during control auto-update cycles. + + Args: + instance: Model or control instance used to store the error cache. + + Returns: + A mutable set of `(exception_type_name, message)` tuples, or `None` + when the instance does not allow attaching the private cache attribute. + """ + + reported = getattr(instance, _REPORTED_VALIDATION_ERRORS_KEY, None) + if reported is not None: + return reported + + reported = set() + try: + setattr(instance, _REPORTED_VALIDATION_ERRORS_KEY, reported) + except Exception: + return None + return reported + + +def _resolve_field_message( + message: FieldMessage, instance: Any, field_name: str, value: Any +) -> str: + """ + Render a field-level message that may be static text or a callable. + + Args: + message: Static message text or formatter callable. + instance: Model or control instance being validated. + field_name: Field name associated with the error. + value: Runtime field value being validated. + + Returns: + The resolved error message string. + """ + if callable(message): + return message(instance, field_name, value) + return message + + +def _resolve_class_message(message: ClassMessage, instance: Any) -> str: + """ + Render a class-level message that may be static text or a callable. + + Args: + message: Static message text or formatter callable. + instance: Model or control instance being validated. + + Returns: + The resolved error message string. + """ + if callable(message): + return message(instance) + return message + + +def _format_expected_type( + expected_type: Union[type[Any], tuple[type[Any], ...]], +) -> str: + """ + Format expected type names into a readable sentence fragment. + + Args: + expected_type: Single type or tuple of allowed runtime types. + + Returns: + A human-readable type list such as `int` or `int, str, or float`. + """ + if not isinstance(expected_type, tuple): + return expected_type.__name__ + names = [t.__name__ for t in expected_type] + if len(names) == 0: + return "unknown" + if len(names) == 1: + return names[0] + if len(names) == 2: + return f"{names[0]} or {names[1]}" + return f"{', '.join(names[:-1])}, or {names[-1]}" + + +def _format_allowed_values(values: tuple[Any, ...]) -> str: + """ + Format allowed values into a readable sentence fragment. + + Args: + values: Allowed values already materialized as a tuple. + + Returns: + A human-readable value list such as `'a'`, `'a' or 'b'`, or + `'a', 'b', or 'c'`. + """ + value_names = [repr(value) for value in values] + if len(value_names) == 1: + return value_names[0] + if len(value_names) == 2: + return f"{value_names[0]} or {value_names[1]}" + return f"{', '.join(value_names[:-1])}, or {value_names[-1]}" + + +class V: + """ + Validation rule builder namespace. + + Methods return `FieldRule` or `ClassRule` instances which are attached to + class fields (`Annotated[...]`) or class-level `__validation_rules__`. + + Most field-level helpers automatically allow `None` when the field + annotation is optional, and otherwise raise `ValueError` when a runtime + value violates the declared rule. + """ + + @staticmethod + def field(check: FieldCheck) -> FieldRule: + """ + Wrap a custom field validator callback into a `FieldRule`. + + Args: + check: Callback receiving `(instance, field_name, value)`. It should + raise `ValueError` when the field is invalid. + + Returns: + A field rule that delegates validation to `check`. + """ + return FieldRule(check) + + @staticmethod + def deprecated( + replacement: Optional[str] = None, + *, + reason: Optional[str] = None, + docs_reason: Optional[str] = None, + version: str, + delete_version: Optional[str] = None, + ) -> FieldRule: + """ + Emit a one-time deprecation warning when a field value is set. + + This rule is intended for soft-deprecating dataclass/control properties + without changing value flow. It does not mutate field values. + + The warning is emitted once per instance and only when the field value + is not `None`. + + Args: + replacement: Preferred property name used in default message. + reason: Full deprecation reason. When omitted, a + replacement-based message is generated. + docs_reason: Docs-only reason. This value is ignored at + runtime and is consumed by docs tooling when available. + version: Version where deprecation starts. + delete_version: Version where removal is planned. + + Returns: + A field rule that emits a deprecation warning at validation time. + """ + + default_reason = ( + f"Use `{replacement}` instead." + if replacement is not None + else "This property is deprecated." + ) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if value is None: + return + + warning_key = f"{instance.__class__.__name__}.{field_name}" + warned = _get_warned_deprecated_fields(instance) + if warned is not None and warning_key in warned: + return + + deprecated_warning( + name=warning_key, + reason=reason or default_reason, + version=version, + delete_version=delete_version, + type="property", + ) + if warned is not None: + warned.add(warning_key) + + return FieldRule(_check) + + @staticmethod + def ensure( + predicate: ClassPredicate, + *, + message: Optional[ClassMessage] = None, + ) -> ClassRule: + """ + Build a generic cross-field predicate rule. + + When `message` is omitted, a generic fallback is used. + + Args: + predicate: Boolean predicate receiving the instance. It should + return `True` when the instance is valid. + message: Optional static text or formatter used when the predicate + returns `False`. + + Returns: + A class rule that evaluates `predicate` against the instance. + """ + + def _check(instance: Any) -> None: + if not predicate(instance): + if message is not None: + raise ValueError(_resolve_class_message(message, instance)) + predicate_name = getattr(predicate, "__name__", None) + if predicate_name and predicate_name != "": + raise ValueError(f"Validation failed: {predicate_name}") + raise ValueError("Validation failed.") + + return ClassRule(_check) + + @staticmethod + def instance_of( + expected_type: Union[type[Any], tuple[type[Any], ...]], + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate a field value type with an optional custom error message. + + Property docstring Raises wording: + `If it is not of type ...`. + + Args: + expected_type: Allowed runtime type(s). + message: Custom error message/template. + + Returns: + A field rule that checks `isinstance(value, expected_type)`. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if value is None and _resolve_allow_none_for_field( + instance.__class__, field_name + ): + return + if not isinstance(value, expected_type): + if message is None: + raise ValueError( + f"{field_name} must be of type " + f"{_format_expected_type(expected_type)}, got {type(value)}" + ) + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + + return FieldRule(_check) + + @staticmethod + def visible_control( + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a field value is visible, i.e. `Control.visible` is `True`. + + Property docstring Raises wording: `If it is not visible.` + + Args: + message: Custom error text or formatter. + + Returns: + A field rule that accepts only visible controls. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: f"{field_name} must be visible", + ): + return + if getattr(value, "visible", False): + return + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError(f"{field_name} must be visible") + + return FieldRule(_check) + + @staticmethod + def visible_controls( + *, + min_count: int, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a field contains at least `min_count` visible controls. + + Property docstring Raises wording: + - `If it does not contain at least one visible Control.` + - `If it does not contain at least n visible Controls.` + + The field value is expected to be an iterable of controls exposing a + `visible` boolean attribute. + + Args: + min_count: Minimum number of visible controls required. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `min_count` is not greater than or + equal to `1`. + + Returns: + A field rule that counts visible items in the iterable value. + """ + if min_count < 1: + raise ValidationDeclarationError( + f"min_count must be greater than or equal to 1, got {min_count}" + ) + + def _default_error(field_name: str, visible_count: int) -> str: + if min_count == 1: + return ( + f"{field_name} must contain at least one visible Control, " + f"got {visible_count}" + ) + return ( + f"{field_name} must contain at least {min_count} visible Controls, " + f"got {visible_count}" + ) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: _default_error(field_name, 0), + ): + return + + try: + visible_count = sum( + 1 for item in value if getattr(item, "visible", False) + ) + except TypeError as err: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) from err + raise ValueError(_default_error(field_name, 0)) from err + + if visible_count < min_count: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError(_default_error(field_name, visible_count)) + + return FieldRule(_check) + + @staticmethod + def str_or_visible_control( + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a field value is either a string or a visible instance. + + Property docstring Raises wording: + `If it is neither a string nor a visible Control.` + + Args: + message: Custom error text or formatter. + + Returns: + A field rule that accepts either strings or visible controls. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: ( + f"{field_name} must be a string or a visible Control" + ), + ): + return + if isinstance(value, str) or getattr(value, "visible", False): + return + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError(f"{field_name} must be a string or a visible Control") + + return FieldRule(_check) + + @staticmethod + def gt( + bound: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `value > bound`. + + Property docstring Raises wording: + `If it is not strictly greater than ...`. + + Args: + bound: Exclusive lower bound. + message: Custom error text or formatter. + + Returns: + A field rule that enforces a strict lower bound. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be strictly greater than {bound}, " + f"got {current_value}" + ), + ): + return + if value <= bound: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be strictly greater than {bound}, got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def ge( + bound: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `value >= bound`. + + Property docstring Raises wording: + `If it is not greater than or equal to ...`. + + Args: + bound: Inclusive lower bound. + message: Custom error text or formatter. + + Returns: + A field rule that enforces an inclusive lower bound. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be greater than or equal to {bound}, " + f"got {current_value}" + ), + ): + return + if value < bound: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be greater than or equal to {bound}, " + f"got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def lt( + bound: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `value < bound`. + + Property docstring Raises wording: + `If it is not strictly less than ...`. + + Args: + bound: Exclusive upper bound. + message: Custom error text or formatter. + + Returns: + A field rule that enforces a strict upper bound. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be less than {bound}, got {current_value}" + ), + ): + return + if value >= bound: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError(f"{field_name} must be less than {bound}, got {value}") + + return FieldRule(_check) + + @staticmethod + def le( + bound: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `value <= bound`. + + Property docstring Raises wording: + `If it is not less than or equal to ...`. + + Args: + bound: Inclusive upper bound. + message: Custom error text or formatter. + + Returns: + A field rule that enforces an inclusive upper bound. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be less than or equal to {bound}, " + f"got {current_value}" + ), + ): + return + if value > bound: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be less than or equal to {bound}, got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def between( + minimum: Any, + maximum: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `minimum <= value <= maximum`. + + Property docstring Raises wording: + `If it is not between ... and ..., inclusive.` + + Args: + minimum: Inclusive lower bound. + maximum: Inclusive upper bound. + message: Custom error text or formatter. + + Returns: + A field rule that enforces both inclusive bounds. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be between {minimum} and {maximum} inclusive, " + f"got {current_value}" + ), + ): + return + if not (minimum <= value <= maximum): + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be between {minimum} and {maximum} inclusive, " + f"got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def factor_of( + base: int, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a field value is an integer factor of `base`. + + Property docstring Raises wording: + `If it is not a factor of ...`. + + This rule is sign-neutral. To enforce direction, compose with: + - `V.gt(0)` for positive factors, or + - `V.lt(0)` for negative factors. + + Args: + base: The integer that validated values must evenly divide. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `base` is zero or not an integer. + + Returns: + A field rule that accepts only integer factors of `base`. + """ + if not isinstance(base, int) or isinstance(base, bool) or base == 0: + raise ValidationDeclarationError( + f"base must be a non-zero integer, got {base!r}" + ) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be a factor of {base}, got {current_value}" + ), + ): + return + if ( + not isinstance(value, int) + or isinstance(value, bool) + or value == 0 + or base % value != 0 + ): + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be a factor of {base}, got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def multiple_of( + divisor: int, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a field value is an integer multiple of `divisor`. + + Property docstring Raises wording: + `If it is not a multiple of ...`. + + This rule is sign-neutral. To enforce direction, compose with: + - `V.gt(0)` for positive multiples, or + - `V.lt(0)` for negative multiples. + + Args: + divisor: Divisor used for the divisibility check. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `divisor` is zero or not an integer. + + Returns: + A field rule that accepts only integer multiples of `divisor`. + """ + if not isinstance(divisor, int) or isinstance(divisor, bool) or divisor == 0: + raise ValidationDeclarationError( + f"divisor must be a non-zero integer, got {divisor!r}" + ) + normalized_divisor = abs(divisor) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be a multiple of {normalized_divisor}, " + f"got {current_value}" + ), + ): + return + if ( + not isinstance(value, int) + or isinstance(value, bool) + or value % normalized_divisor != 0 + ): + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be a multiple of {normalized_divisor}, " + f"got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def eq( + expected: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `value == expected`. + + Property docstring Raises wording: + `If it is not equal to ...`. + + Args: + expected: Required value. + message: Custom error text or formatter. + + Returns: + A field rule that enforces equality with `expected`. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be equal to {expected}, got {current_value}" + ), + ): + return + if value != expected: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be equal to {expected}, got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def ne( + unexpected: Any, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `value != unexpected`. + + Property docstring Raises wording: + `If it is equal to ...`. + + Args: + unexpected: Disallowed value. + message: Custom error text or formatter. + + Returns: + A field rule that rejects equality with `unexpected`. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must not be equal to {unexpected}, " + f"got {current_value}" + ), + ): + return + if value == unexpected: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must not be equal to {unexpected}, got {value}" + ) + + return FieldRule(_check) + + @staticmethod + def one_of( + allowed_values: Iterable[Any], + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that `value` belongs to a fixed set of allowed values. + + Property docstring Raises wording: + `If it is not one of ...`. + + Args: + allowed_values: Allowed values collection. The iterable is consumed + once and stored as a tuple. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `allowed_values` is empty. + + Returns: + A field rule that accepts only values present in `allowed_values`. + """ + allowed_values_tuple = tuple(allowed_values) + if len(allowed_values_tuple) == 0: + raise ValidationDeclarationError( + "allowed_values must contain at least one value" + ) + + allowed_values_text = _format_allowed_values(allowed_values_tuple) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda current_value: ( + f"{field_name} must be one of {allowed_values_text}, " + f"got {current_value!r}" + ), + ): + return + if value not in allowed_values_tuple: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must be one of {allowed_values_text}, got {value!r}" + ) + + return FieldRule(_check) + + @staticmethod + def or_( + *rules: FieldRule, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that at least one field rule passes. + + Args: + rules: Field rules evaluated in declaration order. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If no rules are provided. + ValidationDeclarationError: If any provided object is not a `FieldRule`. + + Returns: + A field rule that succeeds when any one of `rules` succeeds. + """ + if len(rules) == 0: + raise ValidationDeclarationError("or_ requires at least one field rule") + for rule in rules: + if not isinstance(rule, FieldRule): + raise ValidationDeclarationError("or_ expects only FieldRule instances") + + def _check(instance: Any, field_name: str, value: Any) -> None: + # Fast path: try each rule without catching exceptions first. + # Only fall back to exception collection when all rules fail. + errors: Optional[list[str]] = None + for rule in rules: + try: + rule.validate(instance, field_name, value) + return # first passing rule is enough + except ValueError as err: + if errors is None: + errors = [] + errors.append(str(err)) + + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + + if errors is not None and len(errors) == 1: + raise ValueError(errors[0]) + + joined_errors = "; or ".join(errors or ()) + raise ValueError( + f"{field_name} must satisfy at least one of the allowed " + f"conditions: {joined_errors}" + ) + + return FieldRule(_check) + + @staticmethod + def non_empty( + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a sized field value is non-empty (`len(value) > 0`). + + Property docstring Raises wording: + `If it is empty.` + + Args: + message: Custom error text or formatter. + + Returns: + A field rule that requires a sized, non-empty value. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: ( + f"{field_name} must be a non-empty sized value, got None" + ), + ): + return + + try: + length = len(value) + except TypeError as err: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) from err + raise ValueError( + f"{field_name} must be a non-empty sized value, got {type(value)}" + ) from err + + if length == 0: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError(f"{field_name} must be non-empty") + + return FieldRule(_check) + + @staticmethod + def length_ge( + minimum: int, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a sized field has length greater than or equal to `minimum`. + + Property docstring Raises wording: + `If its length is less than ...`. + + Args: + minimum: Inclusive minimum allowed length. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `minimum` is negative. + + Returns: + A field rule that enforces a minimum length. + """ + if minimum < 0: + raise ValidationDeclarationError( + f"minimum must be greater than or equal to 0, got {minimum}" + ) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: ( + f"{field_name} must have length greater than or equal to " + f"{minimum}, got None" + ), + ): + return + + try: + length = len(value) + except TypeError as err: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) from err + raise ValueError( + f"{field_name} must be a sized value with length greater than " + f"or equal to {minimum}, got {type(value)}" + ) from err + + if length < minimum: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must have length greater than or equal to " + f"{minimum}, got {length}" + ) + + return FieldRule(_check) + + @staticmethod + def length_eq( + expected: int, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a sized field has length equal to `expected`. + + Property docstring Raises wording: + `If its length is not equal to ...`. + + Args: + expected: Required length. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `expected` is negative. + + Returns: + A field rule that enforces an exact length. + """ + if expected < 0: + raise ValidationDeclarationError( + f"expected must be greater than or equal to 0, got {expected}" + ) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: ( + f"{field_name} must have length equal to {expected}, got None" + ), + ): + return + + try: + length = len(value) + except TypeError as err: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) from err + raise ValueError( + f"{field_name} must be a sized value with length equal to " + f"{expected}, got {type(value)}" + ) from err + + if length != expected: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must have length equal to {expected}, got {length}" + ) + + return FieldRule(_check) + + @staticmethod + def length_between( + minimum: int, + maximum: int, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate that a sized field length is between bounds, inclusive. + + Property docstring Raises wording: + `If its length is not between ... and ..., inclusive.` + + Args: + minimum: Inclusive minimum allowed length. + maximum: Inclusive maximum allowed length. + message: Custom error text or formatter. + + Raises: + ValidationDeclarationError: If `minimum` is negative. + ValidationDeclarationError: If `maximum` is less than `minimum`. + + Returns: + A field rule that enforces an inclusive length range. + """ + if minimum < 0: + raise ValidationDeclarationError( + f"minimum must be greater than or equal to 0, got {minimum}" + ) + if maximum < minimum: + raise ValidationDeclarationError( + f"maximum must be greater than or equal to minimum ({minimum}), " + f"got {maximum}" + ) + + def _check(instance: Any, field_name: str, value: Any) -> None: + if _prepare_field_value( + instance=instance, + field_name=field_name, + value=value, + message=message, + default_error=lambda _current_value: ( + f"{field_name} must have length between {minimum} and {maximum} " + f"inclusive, got None" + ), + ): + return + + try: + length = len(value) + except TypeError as err: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) from err + raise ValueError( + f"{field_name} must be a sized value with length between " + f"{minimum} and {maximum} inclusive, got {type(value)}" + ) from err + + if not (minimum <= length <= maximum): + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} must have length between {minimum} and {maximum} " + f"inclusive, got {length}" + ) + + return FieldRule(_check) + + @staticmethod + def gt_field( + other_field: str, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `field_name > other_field` on an instance. + + Property docstring Raises wording: + `If it is not strictly greater than `other_field`.` + + This rule is attached to one field via `Annotated[...]` and compares that + field value against another field in the same instance. + + Args: + other_field: Name of the field on the right side of the comparison. + message: Custom error text or formatter. + + Returns: + A field rule that compares one field against another field value on + the same instance. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + other_value, skip = _prepare_field_comparison_values( + instance=instance, + field_name=field_name, + value=value, + other_field=other_field, + message=message, + default_error=lambda left, right: ( + f"{field_name} ({left}) must be strictly greater than " + f"{other_field} ({right})" + ), + ) + if skip: + return + if value <= other_value: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} ({value}) must be strictly greater than " + f"{other_field} ({other_value})" + ) + + return FieldRule(_check) + + @staticmethod + def ge_field( + other_field: str, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `field_name >= other_field` on an instance. + + Property docstring Raises wording: + `If it is not greater than or equal to `other_field`.` + + This rule is attached to one field via `Annotated[...]` and compares that + field value against another field in the same instance. + + Args: + other_field: Name of the field on the right side of the comparison. + message: Custom error text or formatter. + + Returns: + A field rule that compares one field against another field value on + the same instance. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + other_value, skip = _prepare_field_comparison_values( + instance=instance, + field_name=field_name, + value=value, + other_field=other_field, + message=message, + default_error=lambda left, right: ( + f"{field_name} ({left}) must be greater than or equal to " + f"{other_field} ({right})" + ), + ) + if skip: + return + if value < other_value: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} ({value}) must be greater than or equal to " + f"{other_field} ({other_value})" + ) + + return FieldRule(_check) + + @staticmethod + def lt_field( + other_field: str, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `field_name < other_field` on an instance. + + Property docstring Raises wording: + `If it is not strictly less than `other_field`.` + + This rule is attached to one field via `Annotated[...]` and compares that + field value against another field in the same instance. + + Args: + other_field: Name of the field on the right side of the comparison. + message: Custom error text or formatter. + + Returns: + A field rule that compares one field against another field value on + the same instance. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + other_value, skip = _prepare_field_comparison_values( + instance=instance, + field_name=field_name, + value=value, + other_field=other_field, + message=message, + default_error=lambda left, right: ( + f"{field_name} ({left}) must be strictly less than " + f"{other_field} ({right})" + ), + ) + if skip: + return + if value >= other_value: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} ({value}) must be strictly less than " + f"{other_field} ({other_value})" + ) + + return FieldRule(_check) + + @staticmethod + def le_field( + other_field: str, + *, + message: Optional[FieldMessage] = None, + ) -> FieldRule: + """ + Validate `field_name <= other_field` on an instance. + + Property docstring Raises wording: + `If it is not less than or equal to `other_field`.` + + This rule is attached to one field via `Annotated[...]` and compares that + field value against another field in the same instance. + + Args: + other_field: Name of the field on the right side of the comparison. + message: Custom error text or formatter. + + Returns: + A field rule that compares one field against another field value on + the same instance. + """ + + def _check(instance: Any, field_name: str, value: Any) -> None: + other_value, skip = _prepare_field_comparison_values( + instance=instance, + field_name=field_name, + value=value, + other_field=other_field, + message=message, + default_error=lambda left, right: ( + f"{field_name} ({left}) must be less than or equal to " + f"{other_field} ({right})" + ), + ) + if skip: + return + if value > other_value: + if message is not None: + raise ValueError( + _resolve_field_message(message, instance, field_name, value) + ) + raise ValueError( + f"{field_name} ({value}) must be less than or equal to " + f"{other_field} ({other_value})" + ) + + return FieldRule(_check) + + +def _get_declared_type_hints(cls: type[Any]) -> dict[str, Any]: + """ + Resolve declared annotations for one class with best-effort extras support. + + Only annotations declared directly on `cls` are returned. This allows MRO-based + merging in `_compile_class_spec()` without duplicating inherited members. + + Args: + cls: Class whose locally declared annotations should be resolved. + + Returns: + A mapping of field names to resolved type hints for annotations declared + directly on `cls`. + """ + + annotations = getattr(cls, "__annotations__", {}) + if not annotations: + return {} + + module = sys.modules.get(cls.__module__) + globalns = module.__dict__ if module else None + try: + type_hints = get_type_hints(cls, globalns=globalns, include_extras=True) + except TypeError: + type_hints = get_type_hints(cls, globalns=globalns) + except Exception: + type_hints = annotations + + return {name: type_hints.get(name, hint) for name, hint in annotations.items()} + + +@cache +def _get_effective_type_hints(cls: type[Any]) -> dict[str, Any]: + """ + Resolve effective annotations for `cls`, including inherited fields. + + The result is used for Optional/None inference in field-level rules. + + Args: + cls: Class whose effective annotations should be resolved. + + Returns: + A mapping of field names to resolved type hints after MRO merging. + """ + + module = sys.modules.get(cls.__module__) + globalns = module.__dict__ if module else None + try: + return get_type_hints(cls, globalns=globalns, include_extras=True) + except TypeError: + return get_type_hints(cls, globalns=globalns) + except Exception: + hints: dict[str, Any] = {} + for base in reversed(cls.__mro__): + hints.update(getattr(base, "__annotations__", {})) + return hints + + +def _strip_annotated(annotation: Any) -> Any: + """ + Remove `Annotated[...]` wrapper(s), returning the core annotation type. + + Args: + annotation: Annotation that may contain one or more `Annotated` layers. + + Returns: + The unwrapped base annotation. + """ + + while get_origin(annotation) is Annotated: + annotation = get_args(annotation)[0] + return annotation + + +def _annotation_allows_none(annotation: Any) -> bool: + """ + Return `True` if annotation contains `None` (for example `Optional[T]`). + + Args: + annotation: Annotation to inspect. + + Returns: + `True` when the normalized annotation is a `Union[...]` containing + `NoneType`. + """ + + annotation = _strip_annotated(annotation) + origin = get_origin(annotation) + if origin is Union: + return any(arg is type(None) for arg in get_args(annotation)) + return False + + +@cache +def _resolve_allow_none_for_field(model_cls: type[Any], field_name: str) -> bool: + """ + Resolve `None` allowance for an annotated field on a class. + + Args: + model_cls: Class declaring the field. + field_name: Field name whose effective annotation should be inspected. + + Returns: + `True` when the effective field annotation allows `None`. + """ + annotation = _get_effective_type_hints(model_cls).get(field_name) + if annotation is None: + return False + return _annotation_allows_none(annotation) + + +def _prepare_field_value( + instance: Any, + field_name: str, + value: Any, + message: Optional[FieldMessage], + default_error: Callable[[Any], str], +) -> bool: + """ + Normalize `None` handling for field-level validators. + + Args: + instance: Model or control instance being validated. + field_name: Name of the field currently being validated. + value: Current runtime field value. + message: Optional custom error message or formatter. + default_error: Fallback formatter used when `value` is invalid and no + custom message is provided. + + Returns: + `True` when validation should be skipped because `None` is allowed. + + Raises: + ValueError: If `value` is `None`, the field is not optional, and the + rule should fail immediately. + """ + + if value is not None: + return False + + if _resolve_allow_none_for_field(instance.__class__, field_name): + return True + + if message is not None: + raise ValueError(_resolve_field_message(message, instance, field_name, value)) + raise ValueError(default_error(value)) + + +def _prepare_field_comparison_values( + instance: Any, + field_name: str, + value: Any, + other_field: str, + message: Optional[FieldMessage], + default_error: Callable[[Any, Any], str], +) -> tuple[Any, bool]: + """ + Load and normalize values for a field-vs-field comparison rule. + + Args: + instance: Model or control instance being validated. + field_name: Name of the left-hand field. + value: Current runtime value of the left-hand field. + other_field: Name of the right-hand field. + message: Optional custom error message or formatter. + default_error: Fallback formatter used when either side is invalid and + no custom message is provided. + + Returns: + A tuple of `(other_value, skip_validation)`. Validation is skipped when + either side is `None` and that side is optional. + + Raises: + ValueError: If comparison cannot proceed because a required side is `None`. + """ + + other_value = getattr(instance, other_field) + + if value is not None and other_value is not None: + return other_value, False + + cls = instance.__class__ + if value is None and _resolve_allow_none_for_field(cls, field_name): + return other_value, True + if other_value is None and _resolve_allow_none_for_field(cls, other_field): + return other_value, True + + if message is not None: + raise ValueError(_resolve_field_message(message, instance, field_name, value)) + raise ValueError(default_error(value, other_value)) + + +@cache +def _compile_class_spec(model_cls: type[Any]) -> _ClassValidationSpec: + """ + Compile and cache effective validation rules for one class. + + Rules are merged in MRO order (base to derived) so subclasses can extend + validation behavior deterministically. + + Args: + model_cls: Class whose field and class validation rules should be + compiled. + + Returns: + The cached validation specification for `model_cls`. + """ + + field_rules: list[tuple[str, FieldRule]] = [] + class_rules: list[ClassRule] = [] + + for cls in reversed(model_cls.__mro__): + if cls is object: + continue + + declared_hints = _get_declared_type_hints(cls) + + # A subclass field declaration replaces the inherited field definition, + # so inherited field-level rules for that field must be dropped even if + # the override itself carries no Annotated metadata. + if declared_hints: + declared_field_names = set(declared_hints) + field_rules = [ + (field_name, rule) + for field_name, rule in field_rules + if field_name not in declared_field_names + ] + + # Collect field-level rules from Annotated metadata. + for field_name, hint in declared_hints.items(): + if get_origin(hint) is Annotated: + for metadata in get_args(hint)[1:]: + if isinstance(metadata, FieldRule): + field_rules.append((field_name, metadata)) + + # Collect class-level cross-field rules. + rules = cls.__dict__.get("__validation_rules__", ()) + if rules: + for rule in rules: + if isinstance(rule, ClassRule): + class_rules.append(rule) + + return _ClassValidationSpec(tuple(field_rules), tuple(class_rules)) + + +def validate(instance: Any, *, suppress_repeated_errors: bool = False) -> None: + """ + Run all compiled validators for one instance. + + Field rules are evaluated first, then class-level rules. + Validation stops at the first raised exception. + + Args: + instance: Instance to validate. + suppress_repeated_errors: When `True`, repeated identical `ValueError` + messages for the same instance are suppressed after the first report. + + Raises: + ValueError: If any field or class rule fails and the failure is not + suppressed as a repeated identical error for the same instance. + """ + + spec = _compile_class_spec(instance.__class__) + reported = ( + _get_reported_validation_errors(instance) if suppress_repeated_errors else None + ) + + try: + for field_name, rule in spec.field_rules: + rule.validate(instance, field_name, getattr(instance, field_name)) + for rule in spec.class_rules: + rule.validate(instance) + except ValueError as ex: + if reported is None: + raise + + # Dedup key is `(exception type, message)` so distinct failures for the + # same control instance are still surfaced once. + signature = (ex.__class__.__name__, str(ex)) + if signature in reported: + return + reported.add(signature) + raise + else: + if reported: + # Reset once the control validates successfully again. + reported.clear() diff --git a/sdk/python/packages/flet/src/flet/utils/vector.py b/sdk/python/packages/flet/src/flet/utils/vector.py index 73148d5ffd..d5bf84dce3 100644 --- a/sdk/python/packages/flet/src/flet/utils/vector.py +++ b/sdk/python/packages/flet/src/flet/utils/vector.py @@ -27,7 +27,9 @@ class Vector(complex): >>> Vector(1, 1) + 2 Vector(3.0, 1.0) - >>> Vector(0.1, 0.1) + Vector(0.2, 0.2) == Vector(0.3, 0.3) # Float tolerance 10 decimals + >>> Vector(0.1, 0.1) + Vector(0.2, 0.2) == Vector( + ... 0.3, 0.3 + ... ) # Float tolerance 10 decimals True >>> Vector(2, 3) - Vector(1, 1) Vector(1.0, 2.0) @@ -63,14 +65,24 @@ class Vector(complex): x = complex.real y = complex.imag - __add__ = lambda self, other: type(self)(complex.__add__(self, other)) - __sub__ = lambda self, other: type(self)(complex.__sub__(self, other)) - __mul__ = lambda self, other: type(self)(complex.__mul__(self, other)) - __truediv__ = lambda self, other: type(self)(complex.__truediv__(self, other)) - __len__ = lambda self: 2 - __round__ = lambda self, ndigits=None: type(self)( - round(self.x, ndigits), round(self.y, ndigits) - ) + + def __add__(self, other): + return type(self)(complex.__add__(self, other)) + + def __sub__(self, other): + return type(self)(complex.__sub__(self, other)) + + def __mul__(self, other): + return type(self)(complex.__mul__(self, other)) + + def __truediv__(self, other): + return type(self)(complex.__truediv__(self, other)) + + def __len__(self): + return 2 + + def __round__(self, ndigits=None): + return type(self)(round(self.x, ndigits), round(self.y, ndigits)) def __eq__(self, other): return math.isclose(self.x, other.x, abs_tol=self.abs_tol) and math.isclose( @@ -91,6 +103,16 @@ def __repr__(self): @classmethod def polar(cls, radians, magnitude): + """ + Creates a vector from polar coordinates. + + Args: + radians: Angle in radians. + magnitude: Vector length. + + Returns: + A new `Vector` with Cartesian coordinates rounded to 10 decimals. + """ return cls( round(math.cos(radians) * magnitude, 10), round(math.sin(radians) * magnitude, 10), @@ -98,30 +120,98 @@ def polar(cls, radians, magnitude): @property def magnitude(self): + """ + Returns the vector magnitude. + + This is equivalent to `abs(self)`. + + Returns: + The vector length. + """ return abs(self) @property def degrees(self): + """ + Returns the vector angle in degrees. + + Returns: + Angle measured from the positive x-axis, in degrees. + """ return math.degrees(self.radians) @property def radians(self): + """ + Returns the vector angle in radians. + + Returns: + Angle measured from the positive x-axis, in radians. + """ return math.atan2(self.y, self.x) def with_x(self, value): + """ + Returns a copy with a new x coordinate. + + Args: + value: New x coordinate. + + Returns: + A new `Vector` with updated x and the same y. + """ return type(self)(value, self.y) def with_y(self, value): + """ + Returns a copy with a new y coordinate. + + Args: + value: New y coordinate. + + Returns: + A new `Vector` with updated y and the same x. + """ return type(self)(self.x, value) def with_magnitude(self, value): + """ + Returns a copy scaled to the specified magnitude. + + Args: + value: Target magnitude. + + Returns: + A new `Vector` with the same direction and requested magnitude. + + Raises: + ZeroDivisionError: If this vector has zero magnitude. + """ return self * value / abs(self) def with_radians(self, value): + """ + Returns a copy with a new angle in radians. + + Args: + value: Target angle in radians. + + Returns: + A new `Vector` with the same magnitude and updated angle. + """ magnitude = abs(self) return type(self).polar(value, magnitude) def with_degrees(self, value): + """ + Returns a copy with a new angle in degrees. + + Args: + value: Target angle in degrees. + + Returns: + A new `Vector` with the same magnitude and updated angle. + """ radians = math.radians(value) magnitude = abs(self) return type(self).polar(radians, magnitude) diff --git a/sdk/python/packages/flet/src/flet/version.py b/sdk/python/packages/flet/src/flet/version.py index f3a8f0a4d5..3f0a090f49 100644 --- a/sdk/python/packages/flet/src/flet/version.py +++ b/sdk/python/packages/flet/src/flet/version.py @@ -1,58 +1,146 @@ """Provide the current Flet version.""" -import os +import json import subprocess as sp +import sys from pathlib import Path +from typing import Optional -import flet from flet.utils import is_mobile, is_windows, which -# will be replaced by CI -version = "" +__all__ = [ + "find_repo_root", + "flet_version", + "flutter_version", + "from_git", + "pyodide_version", +] +# set by CI +flet_version = "" +""" +The Flet version in use. -def update_version(): - """Return the current version or default.""" - working = Path().absolute() - os.chdir(Path(flet.__file__).absolute().parent) - in_repo = ( - which("git.exe" if is_windows() else "git") - and sp.run( - ["git", "status"], - capture_output=True, - text=True, - ).returncode - == 0 - ) - - if in_repo: - # NOTE: this may break if there is a tag name starting with - # "v" that isn't a version number - class RepositoryError(OSError): - pass - - git_p = sp.run( - ["git", "describe", "--abbrev=0"], +This value is set explicitly in CI for released packages. When running from +source and no version is provided, it is derived from the nearest Git tag +when available. +""" + +# set by CI +flutter_version = "" +""" +The Flutter SDK version used when building the flet client or packaging +apps with [`flet build`](https://flet.dev/docs/cli/flet-build/). + +This value is set explicitly in CI for released packages. When running from +source and no version is provided, it is resolved from the repository's +`.fvmrc` file when available. +""" + +PYODIDE_VERSION = "0.27.7" +""" +The Pyodide version being used when packaging +with [`flet build web`](https://flet.dev/docs/cli/flet-build/). +""" + + +def from_git() -> Optional[str]: + """Try to get the version from Git tags.""" + repo_root = find_repo_root(Path(__file__).resolve().parent) + if not repo_root: + return None + + git_cmd = "git.exe" if is_windows() else "git" + if not which(git_cmd): + return None + + try: + result = sp.run( + [git_cmd, "describe", "--tags", "--abbrev=0"], + cwd=repo_root, capture_output=True, text=True, + check=True, ) - err = git_p.stderr.strip() + tag = result.stdout.strip() + return tag[1:] if tag.startswith("v") else tag + + except sp.CalledProcessError as e: + # Git is present but no tags / not a valid repo state + print(f"Error getting Git version: {e}", file=sys.stderr) + except OSError as e: + print(f"Error running Git: {e}", file=sys.stderr) + + return None + + +def find_repo_root(start_path: Path) -> Optional[Path]: + """Find the root directory of the Git repository containing the start path. + + Accepts both a regular clone (where `.git` is a directory) and a + worktree (where `.git` is a file containing `gitdir: ...`). + """ + current_path = start_path.resolve() + while current_path != current_path.parent: + if (current_path / ".git").exists(): + return current_path + current_path = current_path.parent + return None + + +def get_flet_version() -> str: + """Return the Flet version, falling back to Git or a default if needed.""" + + # If the version is already set (e.g., replaced by CI), use it + if flet_version: + return flet_version + + # Only try to get the version from Git if the pre-set version is empty. + # This is more likely to happen in a development/source environment. + if not is_mobile(): + git_version = from_git() + if git_version: + return git_version # Use Git version if available + + # If 'flet_version' is still empty after the above (e.g., in a built package + # where CI didn't replace it), fall back to the default version. + # CI replacement is the standard way for packaged versions. + return "0.1.0" + + +def get_flutter_version() -> str: + """ + Return the Flutter SDK version. + + Uses `flutter_version` when set (CI/release builds); otherwise resolves it + from `.fvmrc` in a local development checkout. + """ - if "cannot describe anything" in err: - msg = "You may be using a repo cloned from a fork. " - msg += "If so please clone the original Flet repo" - raise RepositoryError(msg) + # If the version is already set (e.g., replaced by CI), use it + if flutter_version: + return flutter_version - if err: - msg = "Unknown error while fetching the version: {err}" - raise RepositoryError(msg) - version = git_p.stdout.strip()[1:] + if not is_mobile(): + repo_root = find_repo_root(Path(__file__).resolve().parent) + if repo_root: + fvmrc_path = repo_root / ".fvmrc" + try: + v = json.loads(fvmrc_path.read_text(encoding="utf-8"))[ + "flutter" + ].strip() + if not v: + raise ValueError("Empty or missing 'flutter' value") + return v + except Exception as e: + print(f"Error parsing {fvmrc_path!r}: {e}", file=sys.stderr) - else: - version = "0.2.0" - os.chdir(working) - return version + # If 'flutter_version' is still empty after the above (e.g., in a built package + # where CI didn't replace it), fall back to the below default. + # CI replacement is the standard way for packaged versions. + return "0" -if not version and not is_mobile(): - version = update_version() +flutter_version = get_flutter_version() +pyodide_version = PYODIDE_VERSION +flet_version = get_flet_version() +__version__ = flet_version diff --git a/sdk/python/packages/flet/tests/bench_object_patch.py b/sdk/python/packages/flet/tests/bench_object_patch.py new file mode 100644 index 0000000000..d9f3ae83da --- /dev/null +++ b/sdk/python/packages/flet/tests/bench_object_patch.py @@ -0,0 +1,316 @@ +""" +Standalone benchmark for object_patch performance. +Run with: python bench_object_patch.py + +Measures several scenarios before and after optimisations. +""" + +import math +import random +import sys +import time +from typing import Optional + +import flet as ft +from flet.controls.base_control import BaseControl, control +from flet.controls.object_patch import ObjectPatch + +# --------------------------------------------------------------------------- +# Control fixtures +# --------------------------------------------------------------------------- + + +@control("BenchText") +class BenchText(BaseControl): + value: str = "" + + +@control("BenchCard") +class BenchCard(BaseControl): + title: str = "" + subtitle: str = "" + badge: str = "" + enabled: bool = True + selected: bool = False + width: Optional[float] = None + height: Optional[float] = None + color: Optional[str] = None + bgcolor: Optional[str] = None + border_radius: Optional[float] = None + padding: Optional[float] = None + margin: Optional[float] = None + opacity: float = 1.0 + tooltip: Optional[str] = None + visible: bool = True + expand: bool = False + tag: Optional[str] = None + rank: int = 0 + score: float = 0.0 + category: Optional[str] = None + + +# --------------------------------------------------------------------------- +# Timing helper +# --------------------------------------------------------------------------- + + +def _bench(label: str, factory, runs: int = 5) -> float: + durations = [] + for _ in range(runs): + old, new = factory() + t0 = time.perf_counter() + ObjectPatch.from_diff(old, new, control_cls=BaseControl) + durations.append(time.perf_counter() - t0) + best = min(durations) + avg = sum(durations) / len(durations) + print(f" {label:<55} best={best * 1000:7.3f} ms avg={avg * 1000:7.3f} ms") + return best + + +# --------------------------------------------------------------------------- +# Scenario 1: frozen, all-keyed list (existing strong path) +# --------------------------------------------------------------------------- + + +def _frozen_all_keyed(size: int): + rng = random.Random(42) + src_items = [BenchText(value=f"item-{i}", key=i) for i in range(size)] + order = list(range(size)) + rng.shuffle(order) + dst_items = [ + BenchText(value=f"item-{i}" if i % 7 else f"item-{i}*", key=i) for i in order + ] + old = ft.Column(src_items) + old._frozen = True + new = ft.Column(dst_items) + return old, new + + +# --------------------------------------------------------------------------- +# Scenario 2: frozen, mixed keyed/unkeyed list (currently degrades to positional) +# --------------------------------------------------------------------------- + + +def _frozen_mixed_keyed(size: int, keyed_fraction: float = 0.5): + rng = random.Random(99) + threshold = int(size * keyed_fraction) + + def make_items(shuffled=False): + items = [] + for i in range(size): + k = i if i < threshold else None + items.append(BenchText(value=f"item-{i}", key=k)) + if shuffled: + # Shuffle only the keyed items (to force moves in a correct impl) + keyed = [(j, x) for j, x in enumerate(items) if x.key is not None] + rng.shuffle(keyed) + for _new_pos, (orig_pos, item) in enumerate(keyed): + items[orig_pos] = item + return items + + old = ft.Column(make_items(shuffled=False)) + old._frozen = True + new = ft.Column(make_items(shuffled=True)) + return old, new + + +# --------------------------------------------------------------------------- +# Scenario 3: frozen, control with many fields, only a few differ +# --------------------------------------------------------------------------- + + +def _frozen_many_fields(n_controls: int, n_changed: int = 2): + """ + Simulates a list of BenchCard controls where only n_changed fields differ + between old and new. This measures the cost of the full field-scan in frozen + mode (current) vs a future _values-union fast path. + """ + + def make_card(i, mutate=False): + c = BenchCard( + key=i, + title=f"Card {i}", + subtitle=f"Sub {i}", + enabled=True, + rank=i, + score=float(i), + ) + if mutate: + c = BenchCard( + key=i, + title=f"Card {i}", + subtitle=f"Sub {i}", + enabled=True, + rank=i, + score=float(i), + badge="NEW" if i % 10 == 0 else "", # changed + selected=i % 5 == 0, # changed + ) + return c + + src = [make_card(i, mutate=False) for i in range(n_controls)] + dst = [make_card(i, mutate=True) for i in range(n_controls)] + old = ft.Column(src) + old._frozen = True + new = ft.Column(dst) + return old, new + + +# --------------------------------------------------------------------------- +# Scenario 4: non-frozen, list rebuilt each update with same explicit keys +# --------------------------------------------------------------------------- + + +def _nonfrozen_rebuilt_keyed(size: int): + """ + Simulates a declarative-style non-frozen update where the child list is + rebuilt from scratch each time but items carry explicit keys. + Currently: all items are treated as remove+add (identity lost). + After fix: items matched by explicit key and compared in place. + """ + + def make_list(mutate: bool): + items = [] + for i in range(size): + items.append( + BenchText( + value=f"item-{i}" if not mutate or i % 8 else f"item-{i}!", + key=i, + ) + ) + return items + + # Build the "old" list and configure it (simulate it being previously on the page) + old_items = make_list(mutate=False) + old_col = ft.Column(old_items) + # Seed __prev_lists as protocol serialisation would (structural list tracking) + object.__setattr__(old_col, "__prev_lists", {"controls": old_items[:]}) + object.__setattr__(old_col, "__prev_dicts", {}) + object.__setattr__(old_col, "__prev_classes", {}) + + # New list: same keys, new Python objects + new_items = make_list(mutate=True) + old_col.controls = new_items # structural reassignment + new_col = old_col + + return new_col, new_col # src == dst for in-place diff + + +# --------------------------------------------------------------------------- +# Scenario 5: non-frozen, sparse changes on a control with many fields +# --------------------------------------------------------------------------- + + +def _nonfrozen_sparse_changes(n_controls: int): + """ + Each update only 1-2 fields change per control. Measures _dirty-based + Prop tracking overhead (Prop.__set__ → _dirty) vs the old __changes scan. + """ + cards = [] + for i in range(n_controls): + c = BenchCard(key=i, title=f"Card {i}", rank=i, score=float(i)) + cards.append(c) + + col = ft.Column(cards) + object.__setattr__(col, "__prev_lists", {"controls": cards[:]}) + object.__setattr__(col, "__prev_dicts", {}) + object.__setattr__(col, "__prev_classes", {}) + + # Mutate 2 fields on every card + for c in cards: + c.badge = "!" + c.selected = not c.selected + + return col, col + + +# --------------------------------------------------------------------------- +# Scenario 6: sunflower (existing regression test scenario) +# --------------------------------------------------------------------------- + + +def _sunflower(count: int, max_seeds: int = 500): + tau = math.pi * 2 + phi = (math.sqrt(5) + 1) / 2 + + def make_controls(n_filled): + ctrls = [] + for i in range(n_filled): + theta = i * tau / phi + r = math.sqrt(i) / 40 + ctrls.append( + ft.Container( + key=i, + width=5, + height=5, + bgcolor=ft.Colors.ORANGE, + align=ft.Alignment(r * math.cos(theta), -r * math.sin(theta)), + ) + ) + for j in range(n_filled, max_seeds): + ctrls.append( + ft.Container( + key=j, + width=5, + height=5, + bgcolor=ft.Colors.GREY_700, + align=ft.Alignment( + math.cos(tau * j / (max_seeds - 1)) * 0.9, + math.sin(tau * j / (max_seeds - 1)) * 0.9, + ), + ) + ) + return ctrls + + old = ft.Stack(controls=make_controls(count)) + old._frozen = True + new = ft.Stack(controls=make_controls(count + 10)) + return old, new + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + + +def main(): + print(f"\n{'=' * 70}") + print("object_patch benchmark") + print(f"Python {sys.version.split()[0]}") + print(f"{'=' * 70}\n") + + print("--- Scenario 1: frozen, all-keyed list (shuffled) ---") + _bench("size=150", lambda: _frozen_all_keyed(150)) + _bench("size=300", lambda: _frozen_all_keyed(300)) + _bench("size=500", lambda: _frozen_all_keyed(500)) + + print("\n--- Scenario 2: frozen, mixed keyed/unkeyed list (50% keyed) ---") + _bench("size=150", lambda: _frozen_mixed_keyed(150)) + _bench("size=300", lambda: _frozen_mixed_keyed(300)) + _bench("size=500", lambda: _frozen_mixed_keyed(500)) + + print("\n--- Scenario 3: frozen, many-field controls, few fields differ ---") + _bench("100 controls x 20 fields, 2 changed", lambda: _frozen_many_fields(100)) + _bench("300 controls x 20 fields, 2 changed", lambda: _frozen_many_fields(300)) + + print("\n--- Scenario 4: non-frozen, list rebuilt each update (keyed) ---") + _bench("size=100", lambda: _nonfrozen_rebuilt_keyed(100)) + _bench("size=300", lambda: _nonfrozen_rebuilt_keyed(300)) + + print("\n--- Scenario 5: non-frozen, sparse field changes ---") + _bench( + "100 controls, 2 fields changed each", lambda: _nonfrozen_sparse_changes(100) + ) + _bench( + "300 controls, 2 fields changed each", lambda: _nonfrozen_sparse_changes(300) + ) + + print("\n--- Scenario 6: sunflower (500 seeds, +10 per update) ---") + _bench("250 filled", lambda: _sunflower(250)) + _bench("400 filled", lambda: _sunflower(400)) + + print() + + +if __name__ == "__main__": + main() diff --git a/sdk/python/packages/flet/tests/common.py b/sdk/python/packages/flet/tests/common.py new file mode 100644 index 0000000000..081fc837e1 --- /dev/null +++ b/sdk/python/packages/flet/tests/common.py @@ -0,0 +1,136 @@ +import datetime +from dataclasses import field +from typing import Any, Optional + +import msgpack + +import flet as ft + +# import flet as ft +# import flet.canvas as cv +from flet.controls.object_patch import ObjectPatch +from flet.messaging.protocol import configure_encode_object_for_msgpack + + +@ft.control("MyText") +class MyText(ft.BaseControl): + value: str + color_scheme: Optional[ft.ColorScheme] = None + on_select: Optional[ft.EventHandler] = None + + def __str__(self): + return f"{self._c}({self.value}, key={self.key} - {id(self)})" + + +@ft.control("LineChartDataPoint") +class LineChartDataPoint(ft.BaseControl): + x: ft.Number + y: ft.Number + selected: bool = False + + +@ft.control("LineChartData") +class LineChartData(ft.BaseControl): + points: list[LineChartDataPoint] = field(default_factory=list) + curved: bool = False + color: ft.ColorValue = ft.Colors.CYAN + gradient: Optional[ft.Gradient] = None + + +@ft.control("LineChart") +class LineChart(ft.LayoutControl): + data_series: list[LineChartData] = field(default_factory=list) + animation: ft.AnimationValue = field( + default_factory=lambda: ft.Animation( + duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR + ) + ) + interactive: bool = True + + def init(self): + super().init() + self._internals["skip_properties"] = ["tooltip"] + + +def b_pack(data): + return msgpack.packb( + data, default=configure_encode_object_for_msgpack(ft.BaseControl) + ) + + +def b_unpack(packed_data): + return msgpack.unpackb(packed_data) + + +def make_diff(new: Any, old: Any = None, show_details=True): + if old is None: + old = new + start = datetime.datetime.now() + + # 1 -calculate diff + patch, added_controls, removed_controls = ObjectPatch.from_diff( + old, new, control_cls=ft.BaseControl + ) + + patch_message = patch.to_message() + + end = datetime.datetime.now() + + if show_details: + print(f"\n=== Patch in {(end - start).total_seconds() * 1000} ms ===") + for op in patch.patch: + print(op) + print("\n=== Patch message:", patch_message) + + return patch.patch, patch_message, added_controls, removed_controls + + +def make_msg(new: Any, old: Any = None, show_details=True): + patch, patch_message, added_controls, removed_controls = make_diff( + new, old, show_details + ) + + # 3 - build msgpack message + msg = msgpack.packb( + patch_message, default=configure_encode_object_for_msgpack(ft.BaseControl) + ) + + if show_details: + print("\nMessage:", msg) + else: + print("\nMessage length:", len(msg)) + + return msg, patch, patch_message, added_controls, removed_controls + + +def cmp_op(op, cop): + return not ( + (cop["op"] is not None and op["op"] != cop["op"]) + or (cop["path"] is not None and op["path"] != cop["path"]) + or ("from" in cop and cop["from"] is not None and op["from"] != cop["from"]) + or ("value" in cop and cop["value"] is not None and op["value"] != cop["value"]) + or ( + "value_type" in cop + and cop["value_type"] is not None + and not isinstance(op["value"], cop["value_type"]) + ) + ) + + +def cmp_ops(ops, cops): + assert len(ops) == len(cops) + return all(cmp_op(ops[i], cops[i]) for i in range(0, len(ops))) + + +def cmp_ops_unordered(ops, cops): + """Order-insensitive variant of cmp_ops for commutative patch operations.""" + assert len(ops) == len(cops) + remaining = list(cops) + for op in ops: + for i, cop in enumerate(remaining): + if cmp_op(op, cop): + remaining.pop(i) + break + else: + return False + return True diff --git a/sdk/python/packages/flet/tests/conftest.py b/sdk/python/packages/flet/tests/conftest.py new file mode 100644 index 0000000000..0de0cec015 --- /dev/null +++ b/sdk/python/packages/flet/tests/conftest.py @@ -0,0 +1,14 @@ +import pytest + + +def pytest_configure(config): + config.addinivalue_line("markers", "benchmark: manual performance benchmark") + + +def pytest_collection_modifyitems(config, items): + # Auto-skip benchmark tests unless explicitly selected with -m benchmark + if "benchmark" not in (config.getoption("-m") or ""): + skip = pytest.mark.skip(reason="benchmark — run with: pytest -m benchmark -s") + for item in items: + if "benchmark" in item.keywords: + item.add_marker(skip) diff --git a/sdk/python/packages/flet/tests/test_alert_dialog.py b/sdk/python/packages/flet/tests/test_alert_dialog.py deleted file mode 100644 index 55ef23a6bc..0000000000 --- a/sdk/python/packages/flet/tests/test_alert_dialog.py +++ /dev/null @@ -1,41 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.AlertDialog(title=ft.Text("Title")) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["alertdialog"], - attrs={"modal": "false", "open": "false"}, - commands=[], - ), - Command( - indent=2, - name=None, - values=["text"], - attrs={"n": "title", "value": "Title"}, - commands=[], - ), - ], "Test failed" - - -def test_alignment_enum(): - r = ft.AlertDialog( - title=ft.Text("Title"), actions_alignment=ft.MainAxisAlignment.SPACE_AROUND - ) - assert isinstance(r.actions_alignment, ft.MainAxisAlignment) - assert isinstance(r._get_attr("actionsAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["actionsalignment"] == "spaceAround" - - -def test_alignment_str(): - r = ft.AlertDialog(title=ft.Text("Title"), actions_alignment="center") - assert isinstance(r.actions_alignment, str) - assert isinstance(r._get_attr("actionsalignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["actionsalignment"] == "center" diff --git a/sdk/python/packages/flet/tests/test_animated_switcher.py b/sdk/python/packages/flet/tests/test_animated_switcher.py deleted file mode 100644 index 8ec4ba3567..0000000000 --- a/sdk/python/packages/flet/tests/test_animated_switcher.py +++ /dev/null @@ -1,74 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.AnimatedSwitcher(content=ft.Text("Hello!")) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["animatedswitcher"], - attrs={}, - commands=[], - ), - Command( - indent=2, - name=None, - values=["text"], - attrs={"n": "content", "value": "Hello!"}, - commands=[], - ), - ], "Test failed" - - -def test_switch_in_curve_enum(): - r = ft.AnimatedSwitcher(content=ft.Text("Hello!")) - assert r.switch_in_curve is None - assert r._get_attr("switchInCurve") is None - - r = ft.AnimatedSwitcher( - content=ft.Text("Hello!"), switch_in_curve=ft.AnimationCurve.BOUNCE_IN - ) - assert isinstance(r.switch_in_curve, ft.AnimationCurve) - assert r.switch_in_curve == ft.AnimationCurve.BOUNCE_IN - assert r._get_attr("switchInCurve") == "bounceIn" - - r = ft.AnimatedSwitcher(content=ft.Text("Hello!"), switch_in_curve="easeIn") - assert isinstance(r.switch_in_curve, str) - assert r._get_attr("switchInCurve") == "easeIn" - - -def test_switch_out_curve_enum(): - r = ft.AnimatedSwitcher(content=ft.Text("Hello!")) - assert r.switch_out_curve is None - assert r._get_attr("switchOutCurve") is None - - r = ft.AnimatedSwitcher( - content=ft.Text("Hello!"), switch_out_curve=ft.AnimationCurve.BOUNCE_IN - ) - assert isinstance(r.switch_out_curve, ft.AnimationCurve) - assert r.switch_out_curve == ft.AnimationCurve.BOUNCE_IN - assert r._get_attr("switchOutCurve") == "bounceIn" - - r = ft.AnimatedSwitcher(content=ft.Text("Hello!"), switch_out_curve="easeIn") - assert isinstance(r.switch_out_curve, str) - assert r._get_attr("switchOutCurve") == "easeIn" - - -def test_transition_enum(): - r = ft.AnimatedSwitcher(content=ft.Text("Hello!")) - assert r.transition is None - assert r._get_attr("transition") is None - - r = ft.AnimatedSwitcher( - content=ft.Text("Hello!"), transition=ft.AnimatedSwitcherTransition.FADE - ) - assert isinstance(r.transition, ft.AnimatedSwitcherTransition) - assert r.transition == ft.AnimatedSwitcherTransition.FADE - assert r._get_attr("transition") == "fade" - - r = ft.AnimatedSwitcher(content=ft.Text("Hello!"), transition="scale") - assert isinstance(r.transition, str) - assert r._get_attr("transition") == "scale" diff --git a/sdk/python/packages/flet/tests/test_auth_lazy_imports.py b/sdk/python/packages/flet/tests/test_auth_lazy_imports.py new file mode 100644 index 0000000000..0c9430e984 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_auth_lazy_imports.py @@ -0,0 +1,98 @@ +import builtins +import importlib +import sys + +import pytest + + +def _clear_flet_modules(): + """Remove loaded `flet` modules to force fresh import behavior in each test.""" + for module_name in list(sys.modules): + if module_name == "flet" or module_name.startswith("flet."): + del sys.modules[module_name] + + +@pytest.fixture +def fresh_flet_modules(): + """Run a test with a clean flet import state, then restore previous modules.""" + original_flet_modules = { + name: module + for name, module in sys.modules.items() + if name == "flet" or name.startswith("flet.") + } + _clear_flet_modules() + try: + yield + finally: + _clear_flet_modules() + sys.modules.update(original_flet_modules) + + +def _blocked_import_factory(blocked_modules: set[str]): + """Create an import hook that raises for selected top-level module names.""" + original_import = builtins.__import__ + + def blocked_import(name, globals=None, locals=None, fromlist=(), level=0): + """Raise `ModuleNotFoundError` for blocked modules and delegate otherwise.""" + top_name = name.split(".")[0] + if top_name in blocked_modules: + raise ModuleNotFoundError(f"No module named '{top_name}'", name=top_name) + return original_import(name, globals, locals, fromlist, level) + + return blocked_import + + +def test_import_flet_without_httpx_oauthlib(monkeypatch, fresh_flet_modules): + """Ensure `import flet` succeeds when optional auth dependencies are absent.""" + monkeypatch.setattr( + builtins, + "__import__", + _blocked_import_factory({"httpx", "oauthlib"}), + ) + + flet = importlib.import_module("flet") + + assert flet is not None + assert hasattr(flet, "Page") + + +def test_auth_exports_stay_importable_without_httpx_oauthlib( + monkeypatch, fresh_flet_modules +): + """Ensure lazy `flet.auth` exports resolve without importing optional deps.""" + monkeypatch.setattr( + builtins, + "__import__", + _blocked_import_factory({"httpx", "oauthlib"}), + ) + + auth = importlib.import_module("flet.auth") + + assert auth.AuthorizationService.__name__ == "AuthorizationService" + assert auth.GitHubOAuthProvider.__name__ == "GitHubOAuthProvider" + + +def test_authorization_service_loads_oauthlib_on_use(monkeypatch, fresh_flet_modules): + """Ensure oauthlib is required only when auth service logic is actually used.""" + monkeypatch.setattr( + builtins, + "__import__", + _blocked_import_factory({"httpx", "oauthlib"}), + ) + + auth = importlib.import_module("flet.auth") + provider = auth.OAuthProvider( + client_id="client_id", + client_secret="client_secret", + authorization_endpoint="https://example.com/authorize", + token_endpoint="https://example.com/token", + redirect_url="https://example.com/callback", + ) + service = auth.AuthorizationService( + provider=provider, + fetch_user=False, + fetch_groups=False, + ) + + with pytest.raises(ModuleNotFoundError, match="oauthlib"): + service.get_authorization_data() diff --git a/sdk/python/packages/flet/tests/test_base_control.py b/sdk/python/packages/flet/tests/test_base_control.py new file mode 100644 index 0000000000..70001e8ad9 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_base_control.py @@ -0,0 +1,33 @@ +import flet as ft + + +def test_controls_equality(): + t1 = ft.Text("A") + t2 = ft.Text("A") + assert t1 == t2 + + t3 = ft.Text("B", data=1) + t4 = ft.Text("B", data=2) + assert t3 != t4 + + c1 = ft.Column( + [ft.Text("Some text"), ft.Button("Some button")], expand=True, data=1 + ) + c2 = ft.Column( + [ft.Text("Some text"), ft.Button("Some button")], expand=True, data=1 + ) + assert c1 == c2 + + +def test_keys(): + k1 = ft.ValueKey(1) + assert str(k1) == "1" + assert k1._type == "value" + + k2 = ft.ScrollKey("section_a") + assert str(k2) == "section_a" + assert k2._type == "scroll" + + t1 = ft.Text("A", key=ft.ValueKey("1")) + t2 = ft.Text("A", key=ft.ValueKey("1")) + assert t1 == t2 diff --git a/sdk/python/packages/flet/tests/test_checkbox.py b/sdk/python/packages/flet/tests/test_checkbox.py deleted file mode 100644 index d902c76cb8..0000000000 --- a/sdk/python/packages/flet/tests/test_checkbox.py +++ /dev/null @@ -1,33 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Checkbox() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["checkbox"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_label_position_enum(): - r = ft.Checkbox(label_position=ft.LabelPosition.LEFT) - assert isinstance(r.label_position, ft.LabelPosition) - assert isinstance(r._get_attr("labelPosition"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["labelposition"] == "left" - - -def test_label_position_str(): - r = ft.Checkbox(label_position="left") - assert isinstance(r.label_position, str) - assert isinstance(r._get_attr("labelPosition"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["labelposition"] == "left" diff --git a/sdk/python/packages/flet/tests/test_column.py b/sdk/python/packages/flet/tests/test_column.py deleted file mode 100644 index 863ddeaa0b..0000000000 --- a/sdk/python/packages/flet/tests/test_column.py +++ /dev/null @@ -1,72 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Column() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["column"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_alignment_enum(): - r = ft.Column(alignment=ft.MainAxisAlignment.SPACE_AROUND) - assert isinstance(r.alignment, ft.MainAxisAlignment) - assert isinstance(r._get_attr("alignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["alignment"] == "spaceAround" - - -def test_alignment_str(): - r = ft.Column(alignment="center") - assert isinstance(r.alignment, str) - assert isinstance(r._get_attr("alignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["alignment"] == "center" - - -def test_horizontal_alignment_enum(): - r = ft.Column(horizontal_alignment=ft.CrossAxisAlignment.STRETCH) - assert isinstance(r.horizontal_alignment, ft.CrossAxisAlignment) - assert isinstance(r._get_attr("horizontalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["horizontalalignment"] == "stretch" - - -def test_horizontal_alignment_str(): - r = ft.Column(horizontal_alignment="center") - assert isinstance(r.horizontal_alignment, str) - assert isinstance(r._get_attr("horizontalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["horizontalalignment"] == "center" - - -def test_scroll_enum(): - r = ft.Column() - assert r.scroll is None - assert r._get_attr("scroll") is None - - r = ft.Column(scroll=ft.ScrollMode.ALWAYS) - assert isinstance(r.scroll, ft.ScrollMode) - assert r.scroll == ft.ScrollMode.ALWAYS - assert r._get_attr("scroll") == "always" - - r = ft.Column(scroll="adaptive") - assert isinstance(r.scroll, str) - assert r._get_attr("scroll") == "adaptive" - - r = ft.Column(scroll=True) - assert isinstance(r.scroll, bool) - assert r._get_attr("scroll") == "auto" - - r = ft.Column(scroll=False) - assert isinstance(r.scroll, bool) - assert r._get_attr("scroll") is None diff --git a/sdk/python/packages/flet/tests/test_component_diff.py b/sdk/python/packages/flet/tests/test_component_diff.py new file mode 100644 index 0000000000..08997d629b --- /dev/null +++ b/sdk/python/packages/flet/tests/test_component_diff.py @@ -0,0 +1,141 @@ +"""Regression tests for ObjectPatch diff behaviour around Component reconciliation.""" + +import flet as ft +from flet.controls.base_control import BaseControl +from flet.controls.object_patch import ObjectPatch + + +@ft.component +def _CompA(): + return ft.Text("a") + + +@ft.component +def _CompB(): + return ft.Text("b") + + +def _make_container(component_fn): + """Build Container(content=component_fn()) in a fresh renderer context.""" + from flet.components.component import Renderer + + with Renderer().with_context(): + return ft.Container(content=component_fn()) + + +def test_diff_replaces_incompatible_component_in_scalar_field(): + """Changing ``Container.content`` from one Component fn to another must + produce a remove + add (not an in-place migrate), so the new component + receives a fresh ``_i`` and ``did_mount`` is fired. + + Regression: before this fix, ``_compare_values`` called + ``_compare_dataclasses`` on both Components because ``type(src) is + type(dst) == Component``. ``_migrate_state`` then copied ``_i`` from + the old instance to the new one, so the session's add/remove dedup logic + considered the new component already mounted and silently skipped + ``did_mount`` (and thus ``use_effect`` mount setup). + """ + old_root = _make_container(_CompA) + new_root = _make_container(_CompB) + + old_content_i = old_root.content._i + new_content_i_before = new_root.content._i + + _patch, added_controls, removed_controls = ObjectPatch.from_diff( + old_root, new_root, control_cls=BaseControl, frozen=True + ) + + added_ids = {c._i for c in added_controls} + removed_ids = {c._i for c in removed_controls} + + # The new Component must be mounted (in added_controls) AND the old + # Component must be unmounted (in removed_controls) — under distinct ids + # so the session's session.py dedup logic does not cancel the did_mount. + assert new_root.content._i == new_content_i_before, ( + "Incompatible Components must NOT migrate _i" + ) + assert old_content_i in removed_ids, ( + f"old component _i={old_content_i} must be in removed {removed_ids}" + ) + assert new_root.content._i in added_ids, ( + f"new component _i={new_root.content._i} must be in added {added_ids}" + ) + assert new_root.content._i != old_content_i + + +def test_diff_migrates_same_component_fn_when_args_differ(): + """Sanity check: Components with the same ``fn`` but different args (so + they don't compare equal) must still migrate ``_i`` in place, so hook + state survives a re-render. + """ + from flet.components.component import Renderer + + @ft.component + def _Comp(label: str): + return ft.Text(label) + + with Renderer().with_context(): + old_root = ft.Container(content=_Comp("one")) + with Renderer().with_context(): + new_root = ft.Container(content=_Comp("two")) + + old_content_i = old_root.content._i + + ObjectPatch.from_diff(old_root, new_root, control_cls=BaseControl, frozen=True) + + # Migration: same fn → _i copied from old to new. + assert new_root.content._i == old_content_i + + +def test_diff_key_change_on_scalar_field_forces_remount(): + """A `key` change on a single-child dataclass field (e.g. + `Container.content`) must force a remove + add, the same way list + reconciliation does for keyed list items. Without this, patterns like + `ft.Container(content=ft.FletApp(key=str(reload_key)))` silently + ignore key changes — the Control's `key` property flips on Dart but + the Flutter Element/State is kept, so the widget never actually + remounts. + """ + from flet.components.component import Renderer + + with Renderer().with_context(): + old_root = ft.Container(content=ft.Text("hello", key="0")) + with Renderer().with_context(): + new_root = ft.Container(content=ft.Text("hello", key="1")) + + old_content_i = old_root.content._i + new_content_i_before = new_root.content._i + + _patch, added_controls, removed_controls = ObjectPatch.from_diff( + old_root, new_root, control_cls=BaseControl, frozen=True + ) + + added_ids = {c._i for c in added_controls} + removed_ids = {c._i for c in removed_controls} + + # Different key → old Text must be unmounted, new Text mounted with its + # own (not migrated) _i. + assert new_root.content._i == new_content_i_before, ( + "Keyed child must NOT migrate _i from the old instance" + ) + assert old_content_i in removed_ids + assert new_root.content._i in added_ids + assert new_root.content._i != old_content_i + + +def test_diff_same_key_on_scalar_field_reconciles_in_place(): + """Sanity check: when the `key` matches across renders, the child is + reconciled in place (same as no key at all). + """ + from flet.components.component import Renderer + + with Renderer().with_context(): + old_root = ft.Container(content=ft.Text("first", key="same")) + with Renderer().with_context(): + new_root = ft.Container(content=ft.Text("second", key="same")) + + old_content_i = old_root.content._i + + ObjectPatch.from_diff(old_root, new_root, control_cls=BaseControl, frozen=True) + + assert new_root.content._i == old_content_i diff --git a/sdk/python/packages/flet/tests/test_component_effects.py b/sdk/python/packages/flet/tests/test_component_effects.py new file mode 100644 index 0000000000..8a09e43ca3 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_component_effects.py @@ -0,0 +1,62 @@ +from flet.components.component import Component +from flet.components.hooks.use_effect import EffectHook + + +def test_render_effect_changed_deps_runs_cleanup_then_setup_once_each(): + c = Component(fn=lambda: None, args=(), kwargs={}) + c._state.mounted = True + calls: list[bool] = [] + c._schedule_effect = lambda hook, is_cleanup=False: calls.append(is_cleanup) # type: ignore[method-assign] + + c._state.hooks = [ + EffectHook( + c, + setup=lambda: None, + cleanup=lambda: None, + deps=[2], + prev_deps=[1], + ) + ] + + c._run_render_effects() + + assert calls == [True, False] + + +def test_render_effect_unchanged_deps_schedules_nothing(): + c = Component(fn=lambda: None, args=(), kwargs={}) + c._state.mounted = True + calls: list[bool] = [] + c._schedule_effect = lambda hook, is_cleanup=False: calls.append(is_cleanup) # type: ignore[method-assign] + + c._state.hooks = [ + EffectHook( + c, + setup=lambda: None, + cleanup=lambda: None, + deps=[1], + prev_deps=[1], + ) + ] + + c._run_render_effects() + + assert calls == [] + + +def test_will_unmount_releases_cached_render_references(): + c = Component(fn=lambda: None, args=(1, 2, 3), kwargs={"k": "v"}) + c._state.mounted = True + c._b = ["body"] + c._state.last_b = ["memo-body"] + c._state.last_args = ("a", "b") + c._state.last_kwargs = {"x": "y"} + c._contexts = {object(): object()} + + c.will_unmount() + + assert c._b is None + assert c._state.last_b is None + assert c._state.last_args == () + assert c._state.last_kwargs == {} + assert c._contexts == {} diff --git a/sdk/python/packages/flet/tests/test_component_renderer.py b/sdk/python/packages/flet/tests/test_component_renderer.py new file mode 100644 index 0000000000..09479ae73f --- /dev/null +++ b/sdk/python/packages/flet/tests/test_component_renderer.py @@ -0,0 +1,26 @@ +import pytest + +from flet.components.component import Renderer +from flet.components.utils import current_renderer + + +def test_renderer_with_context_binds_and_resets_current_renderer(): + renderer = Renderer() + + with pytest.raises(RuntimeError): + current_renderer() + + with renderer.with_context(): + assert current_renderer() is renderer + + with pytest.raises(RuntimeError): + current_renderer() + + +def test_renderer_with_context_reuses_context_manager_type(): + renderer = Renderer() + + ctx1 = renderer.with_context() + ctx2 = renderer.with_context() + + assert type(ctx1) is type(ctx2) diff --git a/sdk/python/packages/flet/tests/test_container.py b/sdk/python/packages/flet/tests/test_container.py deleted file mode 100644 index f3ede66aaa..0000000000 --- a/sdk/python/packages/flet/tests/test_container.py +++ /dev/null @@ -1,95 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Container() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["container"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_gradient(): - c = ft.Container( - gradient=ft.LinearGradient( - colors=[], - tile_mode=ft.GradientTileMode.MIRROR, - ) - ) - cmd = c._build_add_commands() - assert ( - cmd[0].attrs["gradient"] - == '{"colors":[],"tile_mode":"mirror","begin":{"x":-1,"y":0},"end":{"x":1,"y":0},"type":"linear"}' - ) - - c = ft.Container( - gradient=ft.LinearGradient( - colors=[], - tile_mode=ft.GradientTileMode.REPEATED, - ) - ) - cmd = c._build_add_commands() - assert ( - cmd[0].attrs["gradient"] - == '{"colors":[],"tile_mode":"repeated","begin":{"x":-1,"y":0},"end":{"x":1,"y":0},"type":"linear"}' - ) - - c = ft.Container( - gradient=ft.LinearGradient( - colors=[], - ) - ) - cmd = c._build_add_commands() - assert ( - cmd[0].attrs["gradient"] - == '{"colors":[],"tile_mode":"clamp","begin":{"x":-1,"y":0},"end":{"x":1,"y":0},"type":"linear"}' - ) - - -def test_blend_mode_enum(): - r = ft.Container(blend_mode=ft.BlendMode.LIGHTEN, bgcolor=ft.Colors.RED) - assert isinstance(r.blend_mode, ft.BlendMode) - assert isinstance(r._get_attr("blendMode"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["blendmode"] == "lighten" - - -def test_clip_behavior_enum(): - r = ft.Container() - assert r.clip_behavior is None - assert r._get_attr("clipBehavior") is None - - r = ft.Container(clip_behavior=ft.ClipBehavior.ANTI_ALIAS) - assert isinstance(r.clip_behavior, ft.ClipBehavior) - assert r.clip_behavior == ft.ClipBehavior.ANTI_ALIAS - assert r._get_attr("clipBehavior") == "antiAlias" - - r = ft.Container(clip_behavior=ft.ClipBehavior.NONE) - assert isinstance(r.clip_behavior, ft.ClipBehavior) - assert r._get_attr("clipBehavior") == "none" - - -def test_image_repeat_enum(): - r = ft.Container() - assert r.image is None - - r = ft.Container(image=ft.DecorationImage(repeat=ft.ImageRepeat.REPEAT)) - assert isinstance(r.image.repeat, ft.ImageRepeat) - assert r.image.repeat == ft.ImageRepeat.REPEAT - - -def test_image_fit_enum(): - r = ft.Container() - assert r.image is None - - r = ft.Container(image=ft.DecorationImage(fit=ft.ImageFit.FILL)) - assert isinstance(r.image.fit, ft.ImageFit) - assert r.image.fit == ft.ImageFit.FILL diff --git a/sdk/python/packages/flet/tests/test_dataclasses.py b/sdk/python/packages/flet/tests/test_dataclasses.py new file mode 100644 index 0000000000..a77ed951c2 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_dataclasses.py @@ -0,0 +1,76 @@ +from dataclasses import dataclass, field, fields + + +@dataclass +class Foo: + prop_a: str = "default_a" + prop_b: str = field(default="default_b") + + +class Bar: + prop_a: str = "default_a" + prop_b: str = "default_b" + + +class Baz: + prop_a: str = "default_a" + prop_b: str = "default_b" + + def __eq__(self, value: object) -> bool: + if not isinstance(value, Baz): + return NotImplemented + return self.prop_a == value.prop_a and self.prop_b == value.prop_b + + +def test_default_values(): + foo = Foo() + assert foo.prop_a == "default_a" + + foo_fields = fields(foo) + assert len(foo_fields) == 2 + assert foo_fields[0].default == "default_a" + assert foo_fields[1].default == "default_b" + + +def test_equality_default(): + foo1 = Foo() + foo2 = Foo() + assert foo1 == foo2 + + +def test_equality_with_props(): + foo1 = Foo(prop_a="custom_a", prop_b="custom_b") + foo2 = Foo(prop_a="custom_a", prop_b="custom_b") + assert foo1 == foo2 + + +def test_equality_regular_classes(): + bar1 = Bar() + bar2 = Bar() + assert bar1 != bar2 + + +def test_equality_with_eq_method(): + baz1 = Baz() + baz2 = Baz() + assert baz1 == baz2 + + +def test_lists_equality(): + foo1 = Foo(prop_a="a", prop_b="b") + foo2 = Foo(prop_a="a", prop_b="b") + foo_list1 = [foo1] + foo_list2 = [foo2] + assert foo_list1 == foo_list2 + + bar1 = Bar() + bar2 = Bar() + bar_list1 = [bar1] + bar_list2 = [bar2] + assert bar_list1 != bar_list2 + + baz1 = Baz() + baz2 = Baz() + baz_list1 = [foo1, baz1] + baz_list2 = [foo2, baz2] + assert baz_list1 == baz_list2 diff --git a/sdk/python/packages/flet/tests/test_datatable.py b/sdk/python/packages/flet/tests/test_datatable.py deleted file mode 100644 index 1b08645764..0000000000 --- a/sdk/python/packages/flet/tests/test_datatable.py +++ /dev/null @@ -1,99 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_datatable_instance_no_attrs_set(): - r = ft.DataTable(columns=[ft.DataColumn(label=ft.Text("Header"))]) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command(indent=0, name=None, values=["datatable"], attrs={}, commands=[]), - Command(indent=2, name=None, values=["datacolumn"], attrs={}, commands=[]), - Command( - indent=4, - name=None, - values=["text"], - attrs={"n": "label", "value": "Header"}, - commands=[], - ), - ], "Test failed" - - -def test_datarow_instance_no_attrs_set(): - r = ft.DataRow(cells=[ft.DataCell(content=ft.Text("Cell"))]) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command(indent=0, name=None, values=["datarow"], attrs={}, commands=[]), - Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]), - Command( - indent=4, name=None, values=["text"], attrs={"value": "Cell"}, commands=[] - ), - ], "Test failed" - - -def test_datarow_color_literal_material_state_as_string(): - r = ft.DataRow(cells=[ft.DataCell(content=ft.Text("Cell"))], color="yellow") - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["datarow"], - attrs={"color": '{"default":"yellow"}'}, - commands=[], - ), - Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]), - Command( - indent=4, name=None, values=["text"], attrs={"value": "Cell"}, commands=[] - ), - ], "Test failed" - - -def test_datarow_color_multiple_material_states_as_strings(): - r = ft.DataRow( - cells=[ft.DataCell(content=ft.Text("Cell"))], - color={ - ft.ControlState.SELECTED: "red", - ft.ControlState.HOVERED: "blue", - ft.ControlState.DEFAULT: "yellow", - }, - ) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["datarow"], - attrs={"color": '{"selected":"red","hovered":"blue","default":"yellow"}'}, - commands=[], - ), - Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]), - Command( - indent=4, name=None, values=["text"], attrs={"value": "Cell"}, commands=[] - ), - ], "Test failed" - - -def test_datarow_color_multiple_material_states(): - r = ft.DataRow( - cells=[ft.DataCell(content=ft.Text("Cell"))], - color={ - ft.ControlState.SELECTED: "red", - ft.ControlState.HOVERED: "blue", - ft.ControlState.DEFAULT: "yellow", - }, - ) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["datarow"], - attrs={"color": '{"selected":"red","hovered":"blue","default":"yellow"}'}, - commands=[], - ), - Command(indent=2, name=None, values=["datacell"], attrs={}, commands=[]), - Command( - indent=4, name=None, values=["text"], attrs={"value": "Cell"}, commands=[] - ), - ], "Test failed" diff --git a/sdk/python/packages/flet/tests/test_datetime.py b/sdk/python/packages/flet/tests/test_datetime.py new file mode 100644 index 0000000000..c7a6d76a50 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_datetime.py @@ -0,0 +1,8 @@ +import datetime + + +def test_localdate_serialize(): + dt = datetime.datetime(year=2024, month=1, day=20) + print("\nNaive:", dt.isoformat()) + print("Local:", dt.astimezone().isoformat()) + print("UTC:", dt.astimezone().astimezone(datetime.timezone.utc).isoformat()) diff --git a/sdk/python/packages/flet/tests/test_deprecated.py b/sdk/python/packages/flet/tests/test_deprecated.py new file mode 100644 index 0000000000..3185ebd5a0 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_deprecated.py @@ -0,0 +1,174 @@ +"""Unit tests for runtime deprecation helpers in `flet.utils.deprecated`.""" + +import inspect +import re +import warnings +from dataclasses import dataclass +from types import ModuleType + +import pytest + +import flet as ft +from flet.utils.deprecated import deprecated, deprecated_class, deprecated_warning + + +def test_deprecated_decorator_warns_and_returns_original_result(): + """`@deprecated` should warn and preserve wrapped function behavior.""" + + @deprecated( + reason="Use new_function instead.", + version="1.0.0", + delete_version="2.0.0", + ) + def old_function(value: int) -> int: + return value + 1 + + with pytest.warns( + DeprecationWarning, + match=re.escape( + "old_function is deprecated since version 1.0.0 and will be removed in " + "version 2.0.0. Use new_function instead." + ), + ): + assert old_function(2) == 3 + + +def test_deprecated_decorator_respects_show_parentheses(): + """`show_parentheses=True` should render `name()` in warning text.""" + + @deprecated( + reason="Use new_function instead.", + show_parentheses=True, + ) + def old_function() -> str: + return "ok" + + with pytest.warns( + DeprecationWarning, + match=re.escape("old_function() is deprecated. Use new_function instead."), + ): + assert old_function() == "ok" + + +def test_deprecated_decorator_uses_runtime_reason_not_docs_reason(): + """`docs_reason` is docs-only metadata and must not leak into runtime warnings.""" + + @deprecated( + reason="Runtime guidance only.", + docs_reason="Use :func:`new_function` instead.", + version="1.0.0", + ) + def old_function() -> None: + return None + + with pytest.warns(DeprecationWarning) as captured: + old_function() + + warning_text = str(captured[0].message) + assert "Runtime guidance only." in warning_text + assert "new_function" not in warning_text + + +def test_deprecated_class_warns_on_init_and_post_init(): + """`@deprecated_class` should warn on both init and post-init hooks.""" + + @deprecated_class( + reason="Use NewClass instead.", + docs_reason="Use :class:`NewClass` instead.", + version="1.0.0", + delete_version="2.0.0", + ) + @dataclass + class OldClass: + value: int + + def __post_init__(self): + self.value += 1 + + with warnings.catch_warnings(record=True) as captured: + warnings.simplefilter("always", DeprecationWarning) + obj = OldClass(1) + + assert obj.value == 2 + # __init__ and __post_init__ are both wrapped in deprecated_class. + assert len(captured) == 2 + for warning in captured: + warning_text = str(warning.message) + assert "OldClass is deprecated since version 1.0.0" in warning_text + assert "Use NewClass instead." in warning_text + assert "NewClass" in warning_text + assert ":class:`NewClass`" not in warning_text + + +def test_deprecated_warning_formats_message_with_and_without_delete_version(): + """`deprecated_warning()` should render message variants deterministically.""" + with pytest.warns( + DeprecationWarning, + match=re.escape( + "Sample.old_value property is deprecated since version 1.0.0 and will be " + "removed in version 2.0.0. Use new_value instead." + ), + ): + deprecated_warning( + name="Sample.old_value", + reason="Use new_value instead.", + version="1.0.0", + delete_version="2.0.0", + type="property", + ) + + with pytest.warns( + DeprecationWarning, + match=re.escape( + "Sample.old_value property is deprecated since version 1.0.0. " + "Use new_value instead." + ), + ): + deprecated_warning( + name="Sample.old_value", + reason="Use new_value instead.", + version="1.0.0", + delete_version=None, + type="property", + ) + + +def test_deprecated_warning_points_to_user_code_through_flet_frames(): + """ + Ensure stacklevel skips internal `flet.*` frames and targets user call site. + """ + + flet_internal = ModuleType("flet.fake_internal") + flet_internal.deprecated_warning = deprecated_warning + exec( + ( + "def emit_warning():\n" + " deprecated_warning(\n" + " name='Sample.old_value',\n" + " reason='Use new_value instead.',\n" + " version='0.80.0',\n" + " )\n" + ), + flet_internal.__dict__, + ) + + with warnings.catch_warnings(record=True) as captured: + warnings.simplefilter("always", DeprecationWarning) + expected_line = inspect.currentframe().f_lineno + 1 + flet_internal.emit_warning() + + assert len(captured) == 1 + warning = captured[0] + assert warning.filename == __file__ + assert warning.lineno == expected_line + + +def test_dropdownm2_warns_with_removal_version(): + with pytest.warns( + DeprecationWarning, + match=re.escape( + "DropdownM2 is deprecated since version 0.84.0 and will be removed in " + "version 1.0. Use Dropdown instead." + ), + ): + ft.DropdownM2() diff --git a/sdk/python/packages/flet/tests/test_dropdown.py b/sdk/python/packages/flet/tests/test_dropdown.py deleted file mode 100644 index 768ff1860a..0000000000 --- a/sdk/python/packages/flet/tests/test_dropdown.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.Dropdown() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["dropdown"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_border_enum(): - r = ft.Dropdown() - assert r.border is None - assert r._get_attr("border") is None - - r = ft.Dropdown(border=ft.InputBorder.OUTLINE) - assert isinstance(r.border, ft.InputBorder) - assert r.border == ft.InputBorder.OUTLINE - assert r._get_attr("border") == "outline" - - r = ft.Dropdown(border="none") - assert isinstance(r.border, str) - assert r._get_attr("border") == "none" diff --git a/sdk/python/packages/flet/tests/test_events.py b/sdk/python/packages/flet/tests/test_events.py new file mode 100644 index 0000000000..09060f6bbc --- /dev/null +++ b/sdk/python/packages/flet/tests/test_events.py @@ -0,0 +1,138 @@ +import sys +from typing import ForwardRef, get_args, get_origin, get_type_hints + +from flet.controls.base_page import PageResizeEvent +from flet.controls.control_event import ControlEvent, Event, get_event_field_type +from flet.controls.core.column import Column +from flet.controls.events import TapEvent +from flet.controls.material.button import Button +from flet.controls.material.container import Container +from flet.controls.material.reorderable_list_view import ( + OnReorderEvent, + ReorderableListView, +) +from flet.controls.page import Page +from flet.controls.scrollable_control import OnScrollEvent +from flet.controls.types import PointerDeviceType +from flet.messaging.connection import Connection +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub +from flet.utils.from_dict import from_dict + + +def test_get_event_field_type(): + btn = Button() + on_click_type = get_event_field_type(btn, "on_click") + assert get_origin(on_click_type) is Event + assert get_args(on_click_type)[0] == ForwardRef("Button") + + c = Container() + on_tap_down_type = get_event_field_type(c, "on_tap_down") + assert on_tap_down_type == TapEvent["Container"] + assert on_tap_down_type != ControlEvent + + col = Column() + on_scroll_type = get_event_field_type(col, "on_scroll") + assert on_scroll_type == OnScrollEvent + assert on_scroll_type != ControlEvent + + +def test_get_page_event_field_type(): + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + on_resize_type = get_event_field_type(page, "on_resize") + assert on_resize_type == PageResizeEvent + assert on_resize_type != ControlEvent + + +def test_create_event_typed_data(): + c = Container() + on_tap_down_type = get_event_field_type(c, "on_tap_down") + assert on_tap_down_type == TapEvent["Container"] + + evt = from_dict( + on_tap_down_type, + { + "control": c, + "name": "some_event", + "data": None, + "k": "mouse", + "l": {"x": 1, "y": 2}, + "g": {"x": 4, "y": 5}, + }, + ) + + assert isinstance(evt, TapEvent) + assert evt.kind == PointerDeviceType.MOUSE + assert evt.local_position.x == 1 + assert evt.global_position.y == 5 + assert evt.control == c + assert evt.name == "some_event" + + +def test_create_reorder_event(): + c = ReorderableListView() + on_reorder_type = get_event_field_type(c, "on_reorder") + assert on_reorder_type == OnReorderEvent + + evt = from_dict( + on_reorder_type, + { + "control": c, + "name": "some_event", + "data": None, + "old_index": 0, + "new_index": 1, + }, + ) + + assert isinstance(evt, OnReorderEvent) + assert evt.old_index == 0 + assert evt.new_index == 1 + assert evt.control == c + assert evt.name == "some_event" + + +def test_page_events(): + conn = Connection() + conn.pubsubhub = PubSubHub() + p = Page(sess=Session(conn)) + on_resized_type = get_event_field_type(p, "on_resize") + assert on_resized_type == PageResizeEvent + evt = from_dict( + on_resized_type, + { + "control": p, + "name": "on_resize", + "data": None, + "width": 1, + "height": 2, + }, + ) + + assert isinstance(evt, PageResizeEvent) + + +def test_page_forward_ref_resolution_uses_base_module(): + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + + page_module = sys.modules["flet.controls.page"] + removed = page_module.__dict__.pop("PageResizeEvent", None) + + try: + on_resize_type = get_event_field_type(page, "on_resize") + assert on_resize_type == PageResizeEvent + finally: + if removed is not None: + page_module.PageResizeEvent = removed + + +def test_get_type_hints_control_event_forward_ref(): + def handler(event: ControlEvent) -> None: + pass + + hints = get_type_hints(handler, include_extras=True) + assert hints["event"] == ControlEvent diff --git a/sdk/python/packages/flet/tests/test_file_picker.py b/sdk/python/packages/flet/tests/test_file_picker.py deleted file mode 100644 index b15abb0626..0000000000 --- a/sdk/python/packages/flet/tests/test_file_picker.py +++ /dev/null @@ -1,30 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.FilePicker() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["filepicker"], - attrs={"upload": "[]"}, - commands=[], - ) - ], "Test failed" - - -def test_file_type_enum(): - r = ft.FilePicker() - r.file_type = ft.FilePickerFileType.VIDEO - assert isinstance(r.file_type, ft.FilePickerFileType) - assert r.file_type == ft.FilePickerFileType.VIDEO - assert r._get_attr("fileType") == "video" - - r = ft.FilePicker() - r.file_type = "any" - assert isinstance(r.file_type, str) - assert r._get_attr("fileType") == "any" diff --git a/sdk/python/packages/flet/tests/test_from_dict.py b/sdk/python/packages/flet/tests/test_from_dict.py new file mode 100644 index 0000000000..1418ca0faa --- /dev/null +++ b/sdk/python/packages/flet/tests/test_from_dict.py @@ -0,0 +1,65 @@ +from dataclasses import dataclass +from enum import Enum +from typing import Optional + +from flet.controls.base_page import PageMediaData +from flet.controls.padding import Padding +from flet.utils import from_dict + + +def test_page_media_data(): + pm = from_dict( + PageMediaData, + { + "padding": {"left": 1, "top": 2, "right": 3, "bottom": 4}, + "view_padding": {"left": 1, "top": 2, "right": 3, "bottom": 4}, + "view_insets": {"left": 1, "top": 2, "right": 3, "bottom": 4}, + "device_pixel_ratio": 1, + "orientation": "portrait", + }, + ) + + assert isinstance(pm, PageMediaData) + assert isinstance(pm.padding, Padding) + assert isinstance(pm.view_insets, Padding) + assert isinstance(pm.view_padding, Padding) + assert pm.padding._prev_left == 1 + assert pm.view_insets._prev_top == 2 + + +def test_simple(): + class Status(Enum): + ACTIVE = "active" + INACTIVE = "inactive" + + @dataclass + class Address: + city: str + zip: str + + @dataclass + class User: + name: str + age: Optional[int] + status: Status + address: Optional[Address] + tags: list[str] + metadata: dict[str, int] + + user_data = { + "name": "Alice", + "age": 30, + "status": "active", + "address": {"city": "Springfield", "zip": "12345"}, + "tags": ["admin", "beta"], + "metadata": {"logins": 10, "likes": 42}, + } + + user = from_dict(User, user_data) + assert isinstance(user, User) + assert isinstance(user.address, Address) + assert isinstance(user.status, Status) + assert user._prev_name == "Alice" + assert user._prev_age == 30 + assert user.address._prev_city == "Springfield" + assert user._prev_status == Status.ACTIVE diff --git a/sdk/python/packages/flet/tests/test_griffe_deprecations.py b/sdk/python/packages/flet/tests/test_griffe_deprecations.py new file mode 100644 index 0000000000..14a48966e4 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_griffe_deprecations.py @@ -0,0 +1,256 @@ +"""Tests for docs-facing deprecation extraction via Griffe extension.""" + +from textwrap import dedent + +import pytest + +griffe = pytest.importorskip("griffe") +from griffe import ( # noqa: E402 + DocstringSectionAdmonition, + load_extensions, + temporary_visited_module, +) + + +def _first_deprecation_admonition(obj): + """Return the first `Deprecated` admonition section from an object docstring.""" + if not obj.docstring: + return None + for section in obj.docstring.parsed: + if ( + isinstance(section, DocstringSectionAdmonition) + and section.title == "Deprecated" + ): + return section + return None + + +def _admonition_text(admonition): + """Extract admonition body text from a Griffe admonition section.""" + return admonition.value.contents + + +def test_extension_adds_attribute_admonition_for_v_deprecated(): + """Ensure that `V.deprecated` attributes get a Deprecated admonition.""" + code = dedent( + """ + from typing import Annotated, Optional + from flet.utils.validation import V + + class Control: + old_prop: Annotated[ + Optional[int], + V.deprecated("new_prop", version="0.81.0", delete_version="0.90.0"), + ] = None + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + attr = module["Control"]["old_prop"] + admonition = _first_deprecation_admonition(attr) + assert admonition is not None + text = _admonition_text(admonition) + assert "Deprecated since version `0.81.0`" in text + assert "removal in `0.90.0`" in text + assert "Use `new_prop` instead." in text + assert "deprecated" in attr.labels + + +def test_extension_prefers_docs_reason_for_v_deprecated(): + """Ensure that `docs_reason` overrides `reason` for `V.deprecated` attributes.""" + code = dedent( + """ + from typing import Annotated, Optional + from flet.utils.validation import V + + class Control: + old_prop: Annotated[ + Optional[int], + V.deprecated( + "new_prop", + version="0.81.0", + reason="Use plain text.", + docs_reason="Use :attr:`new_prop` instead.", + ), + ] = None + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + attr = module["Control"]["old_prop"] + admonition = _first_deprecation_admonition(attr) + assert admonition is not None + text = _admonition_text(admonition) + assert "Use :attr:`new_prop` instead." in text + assert "Use plain text." not in text + + +def test_extension_adds_function_admonition_for_flet_decorator(): + """Ensure that `@deprecated` functions get a Deprecated admonition.""" + code = dedent( + """ + from flet.utils.deprecated import deprecated + + @deprecated( + reason="Use `new_func()` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def old_func(): + return None + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + func = module["old_func"] + admonition = _first_deprecation_admonition(func) + assert admonition is not None + text = _admonition_text(admonition) + assert "Deprecated since version `0.80.0`" in text + assert "removal in `0.90.0`" in text + assert "Use `new_func()` instead." in text + assert "deprecated" in func.labels + + +def test_extension_prefers_docs_reason_for_flet_decorator(): + """Ensure that `docs_reason` overrides `reason` for `@deprecated` functions.""" + code = dedent( + """ + from flet.utils.deprecated import deprecated + + @deprecated( + reason="Use plain text.", + docs_reason="Use :func:`new_func` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def old_func(): + return None + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + func = module["old_func"] + admonition = _first_deprecation_admonition(func) + assert admonition is not None + text = _admonition_text(admonition) + assert "Use :func:`new_func` instead." in text + assert "Use plain text." not in text + + +def test_extension_adds_class_admonition_for_deprecated_class(): + """Ensure that `@deprecated_class` classes get a Deprecated admonition.""" + code = dedent( + """ + from flet.utils.deprecated import deprecated_class + + @deprecated_class( + reason="Use `NewControl` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + class OldControl: + pass + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + cls = module["OldControl"] + admonition = _first_deprecation_admonition(cls) + assert admonition is not None + text = _admonition_text(admonition) + assert "Deprecated since version `0.80.0`" in text + assert "removal in `0.90.0`" in text + assert "Use `NewControl` instead." in text + assert "deprecated" in cls.labels + + +def test_extension_prefers_docs_reason_for_deprecated_class(): + """Ensure that `docs_reason` overrides `reason` for `@deprecated_class` classes.""" + code = dedent( + """ + from flet.utils.deprecated import deprecated_class + + @deprecated_class( + reason="Use plain text.", + docs_reason="Use :class:`NewControl` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + class OldControl: + pass + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + cls = module["OldControl"] + admonition = _first_deprecation_admonition(cls) + assert admonition is not None + text = _admonition_text(admonition) + assert "Use :class:`NewControl` instead." in text + assert "Use plain text." not in text + + +def test_extension_adds_attribute_admonition_for_property_getter_deprecated(): + """Ensure that deprecated property getters get a Deprecated admonition.""" + code = dedent( + """ + from flet.utils.deprecated import deprecated + + class Control: + @property + @deprecated( + reason="Use plain text.", + docs_reason="Use :attr:`new_prop` instead.", + version="0.80.0", + delete_version="0.90.0", + ) + def old_prop(self) -> int: + \"\"\"Deprecated property getter.\"\"\" + return 1 + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + attr = module["Control"]["old_prop"] + admonition = _first_deprecation_admonition(attr) + assert admonition is not None + text = _admonition_text(admonition) + assert "Deprecated since version `0.80.0`" in text + assert "removal in `0.90.0`" in text + assert "Use :attr:`new_prop` instead." in text + assert "Use plain text." not in text + assert "deprecated" in attr.labels + assert "property" in attr.labels + + +def test_extension_adds_function_admonition_for_typing_extensions_deprecated(): + """ + Ensure that `typing_extensions.deprecated` functions get a Deprecated admonition. + """ + code = dedent( + """ + from typing_extensions import deprecated + + @deprecated("Use `new_function` instead.") + def old_function(): + return None + """ + ) + with temporary_visited_module( + code, extensions=load_extensions("flet.utils.griffe_deprecations") + ) as module: + func = module["old_function"] + admonition = _first_deprecation_admonition(func) + assert admonition is not None + text = _admonition_text(admonition) + assert "Deprecated." in text + assert "Use `new_function` instead." in text + assert "deprecated" in func.labels diff --git a/sdk/python/packages/flet/tests/test_icons.py b/sdk/python/packages/flet/tests/test_icons.py index 3e8acc2c4b..fde6281771 100644 --- a/sdk/python/packages/flet/tests/test_icons.py +++ b/sdk/python/packages/flet/tests/test_icons.py @@ -18,10 +18,10 @@ def test_cupertino_icons_random_with_weights_and_exclude(): """Test random cupertino icon selection with weights and exclusion list.""" results = [ ft.CupertinoIcons.random( - exclude=[ft.CupertinoIcons.CAMERA], + exclude=[ft.CupertinoIcons.CAMERA_CIRCLE], weights={ft.CupertinoIcons.TABLE: 150}, ) for _ in range(1000) ] - assert ft.CupertinoIcons.CAMERA not in results + assert ft.CupertinoIcons.CAMERA_CIRCLE not in results assert ft.CupertinoIcons.TABLE in results diff --git a/sdk/python/packages/flet/tests/test_image.py b/sdk/python/packages/flet/tests/test_image.py deleted file mode 100644 index 508f26ae26..0000000000 --- a/sdk/python/packages/flet/tests/test_image.py +++ /dev/null @@ -1,68 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_image_add(): - i = ft.Image( - src="https://www.w3schools.com/css/img_5terre.jpg", - ) - assert isinstance(i, ft.Control) - assert isinstance(i, ft.Image) - assert i._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["image"], - attrs={ - "src": "https://www.w3schools.com/css/img_5terre.jpg", - }, - commands=[], - ) - ], "Test failed" - - -def test_color_blend_mode_enum(): - r = ft.Image(color_blend_mode=ft.BlendMode.LIGHTEN) - assert isinstance(r.color_blend_mode, ft.BlendMode) - assert isinstance(r._get_attr("colorBlendMode"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["colorblendmode"] == "lighten" - - -def test_color_blend_mode_str(): - r = ft.Image(color_blend_mode="darken") - assert isinstance(r.color_blend_mode, str) - assert isinstance(r._get_attr("colorBlendMode"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["colorblendmode"] == "darken" - - -def test_repeat_enum(): - r = ft.Image() - assert r.repeat is None - assert r._get_attr("repeat") is None - - r = ft.Image(repeat=ft.ImageRepeat.REPEAT) - assert isinstance(r.repeat, ft.ImageRepeat) - assert r.repeat == ft.ImageRepeat.REPEAT - assert r._get_attr("repeat") == "repeat" - - r = ft.Image(repeat="repeatX") - assert isinstance(r.repeat, str) - assert r._get_attr("repeat") == "repeatX" - - -def test_fit_enum(): - r = ft.Image() - assert r.fit is None - assert r._get_attr("fit") is None - - r = ft.Image(fit=ft.ImageFit.FILL) - assert isinstance(r.fit, ft.ImageFit) - assert r.fit == ft.ImageFit.FILL - assert r._get_attr("fit") == "fill" - - r = ft.Image(fit="none") - assert isinstance(r.fit, str) - assert r._get_attr("fit") == "none" diff --git a/sdk/python/packages/flet/tests/test_markdown.py b/sdk/python/packages/flet/tests/test_markdown.py deleted file mode 100644 index 03d4250f0f..0000000000 --- a/sdk/python/packages/flet/tests/test_markdown.py +++ /dev/null @@ -1,28 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Markdown() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["markdown"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_extension_set_enum(): - r = ft.Markdown() - assert r.extension_set is None - assert r._get_attr("extensionSet") is None - - r = ft.Markdown(extension_set=ft.MarkdownExtensionSet.COMMON_MARK) - assert isinstance(r.extension_set, ft.MarkdownExtensionSet) - assert r.extension_set == ft.MarkdownExtensionSet.COMMON_MARK - assert r._get_attr("extensionSet") == "commonMark" diff --git a/sdk/python/packages/flet/tests/test_moving_children.py b/sdk/python/packages/flet/tests/test_moving_children.py deleted file mode 100644 index 7132580ef6..0000000000 --- a/sdk/python/packages/flet/tests/test_moving_children.py +++ /dev/null @@ -1,44 +0,0 @@ -import random - -import flet as ft - - -def test_moving_children(): - c = ft.Stack() - c._Control__uid = "0" - for i in range(0, 10): - c.controls.append(ft.Container()) - c.controls[i]._Control__uid = f"_{i}" - - index = [] - added_controls = [] - removed_controls = [] - commands = [] - c.build_update_commands(index, commands, added_controls, removed_controls, False) - - def replace_controls(c): - random.shuffle(c.controls) - commands.clear() - - # print("=======") - r = set() - for ctrl in c.controls: - # print(ctrl._Control__uid) - r.add(ctrl._Control__uid) - c.build_update_commands( - index, commands, added_controls, removed_controls, False - ) - for cmd in commands: - if cmd.name == "add": - for sub_cmd in cmd.commands: - # print("add", sub_cmd.attrs["id"], "at", cmd.attrs["at"]) - r.add(sub_cmd.attrs["id"]) - elif cmd.name == "remove": - for v in cmd.values: - # print("remove", v) - r.remove(v) - # print(r) - assert len(r) == len(c.controls) - - for i in range(0, 20): - replace_controls(c) diff --git a/sdk/python/packages/flet/tests/test_navigation_bar.py b/sdk/python/packages/flet/tests/test_navigation_bar.py deleted file mode 100644 index 42987bc9d1..0000000000 --- a/sdk/python/packages/flet/tests/test_navigation_bar.py +++ /dev/null @@ -1,32 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.NavigationBar() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["navigationbar"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_extension_set_enum(): - r = ft.NavigationBar() - assert r.label_behavior is None - assert r._get_attr("labelBehavior") is None - - r = ft.NavigationBar(label_behavior=ft.NavigationBarLabelBehavior.ALWAYS_SHOW) - assert isinstance(r.label_behavior, ft.NavigationBarLabelBehavior) - assert r.label_behavior == ft.NavigationBarLabelBehavior.ALWAYS_SHOW - assert r._get_attr("labelBehavior") == "alwaysShow" - - r = ft.NavigationBar(label_behavior="alwaysHide") - assert isinstance(r.label_behavior, str) - assert r._get_attr("labelBehavior") == "alwaysHide" diff --git a/sdk/python/packages/flet/tests/test_navigation_rail.py b/sdk/python/packages/flet/tests/test_navigation_rail.py deleted file mode 100644 index 2b4774580f..0000000000 --- a/sdk/python/packages/flet/tests/test_navigation_rail.py +++ /dev/null @@ -1,31 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.NavigationRail() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["navigationrail"], - attrs={"rtl": "false"}, - commands=[], - ) - ], "Test failed" - - -def test_extension_set_enum(): - r = ft.NavigationRail() - assert r.label_type is None - assert r._get_attr("labelType") is None - - r = ft.NavigationRail(label_type=ft.NavigationRailLabelType.SELECTED) - assert isinstance(r.label_type, ft.NavigationRailLabelType) - assert r.label_type == ft.NavigationRailLabelType.SELECTED - assert r._get_attr("labelType") == "selected" - - r = ft.NavigationRail(label_type="none") - assert isinstance(r.label_type, str) - assert r._get_attr("labelType") == "none" diff --git a/sdk/python/packages/flet/tests/test_object_diff_frozen.py b/sdk/python/packages/flet/tests/test_object_diff_frozen.py new file mode 100644 index 0000000000..3f9f6b0ea7 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_object_diff_frozen.py @@ -0,0 +1,1331 @@ +from dataclasses import dataclass + +import pytest + +import flet as ft +from flet.components.component import Component +from flet.controls.base_control import BaseControl, control +from flet.controls.object_patch import ObjectPatch + +from .common import ( + LineChart, + LineChartData, + LineChartDataPoint, + MyText, + b_unpack, + cmp_ops, + cmp_ops_unordered, + make_diff, + make_msg, +) + + +def test_compare_roots(): + c1 = {} + c2 = ft.Column() + c2._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert len(patch) == 1 + assert cmp_ops(patch, [{"op": "replace", "path": [], "value_type": ft.Column}]) + + +def test_compare_literals_removed(): + c1 = ft.Column([1, 2, 3, 4, 5, 6, 7, 8]) + c2 = ft.Column([1, 4, 5, 5]) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["controls", 1], "value": 2}, + {"op": "replace", "path": ["controls", 1], "value": 5}, + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + {"op": "remove", "path": ["controls", 4], "value": 6}, + {"op": "remove", "path": ["controls", 4], "value": 7}, + {"op": "remove", "path": ["controls", 4], "value": 8}, + ], + ) + + +def test_compare_literals_added(): + c1 = ft.Column([1, 2, 3, 4, 5]) + c2 = ft.Column([1, 4, 5, 6, 7, 8, 9]) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["controls", 1], "value": 2}, + {"op": "remove", "path": ["controls", 1], "value": 3}, + {"op": "move", "from": ["controls", 1], "path": ["controls", 1]}, + {"op": "add", "path": ["controls", 2], "value": 6}, + {"op": "move", "from": ["controls", 3], "path": ["controls", 2]}, + {"op": "add", "path": ["controls", 4], "value": 7}, + {"op": "add", "path": ["controls", 5], "value": 8}, + {"op": "add", "path": ["controls", 6], "value": 9}, + ], + ) + + +def test_compare_literals_replaced(): + c1 = ft.Column([1, 2]) + c2 = ft.Column([3, 4, 5]) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["controls", 0], "value": 3}, + {"op": "replace", "path": ["controls", 1], "value": 4}, + {"op": "add", "path": ["controls", 2], "value": 5}, + ], + ) + + +def test_compare_objects_replaced_no_keys(): + @dataclass + class Item: + x: int + y: int + + c1 = ft.Column( + [ + Item(3, 1), + Item(4, 1), + ], + ) + c2 = ft.Column( + [ + Item(1, 0), + Item(2, 0), + Item(3, 0), + ] + ) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["controls", 0, "x"], "value": 1}, + {"op": "replace", "path": ["controls", 0, "y"], "value": 0}, + {"op": "replace", "path": ["controls", 1, "x"], "value": 2}, + {"op": "replace", "path": ["controls", 1, "y"], "value": 0}, + {"op": "add", "path": ["controls", 2], "value_type": Item}, + ], + ) + + +def test_compare_objects_replaced_with_control_keys(): + @dataclass + class Item: + key: int + y: int + + c1 = ft.Column( + [ + Item(key=3, y=1), + Item(key=4, y=1), + ], + ) + c2 = ft.Column( + [ + Item(key=1, y=0), + Item(key=2, y=0), + ] + ) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["controls", 0], "value": Item(key=3, y=1)}, + {"op": "replace", "path": ["controls", 0], "value": Item(key=1, y=0)}, + {"op": "add", "path": ["controls", 1], "value": Item(key=2, y=0)}, + ], + ) + assert patch[1]["value"].key == 1 + assert patch[1]["value"].y == 0 + assert patch[2]["value"].key == 2 + assert patch[2]["value"].y == 0 + + +def test_compare_objects_updated_and_moved_with_control_keys(): + @control("Item") + class Item(BaseControl): + y: int + + def __str__(self): + return f"Item(key={self.key}, y={self.y})" + + c1 = ft.Column( + [ + Item(key=2, y=0), + Item(key=1, y=0), + ], + ) + c2 = ft.Column( + [ + Item(key=1, y=1), + Item(key=2, y=2), + ] + ) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["controls", 1, "y"], "value": 1}, + {"op": "move", "from": ["controls", 1], "path": ["controls", 0]}, + {"op": "replace", "path": ["controls", 1, "y"], "value": 2}, + ], + ) + + +def test_compare_objects_added(): + @control("Item") + class Item(BaseControl): + y: int + + def __str__(self): + return f"Item(key={self.key}, y={self.y})" + + c1 = ft.Column( + [ + Item(key=3, y=1), + Item(key=4, y=1), + Item(key=5, y=1), + Item(key=6, y=1), + ], + ) + c2 = ft.Column( + [ + Item(key=1, y=0), + Item(key=2, y=0), + Item(key=4, y=40), + Item(key=3, y=30), + Item(key=5, y=0), + Item(key=6, y=0), + Item(key=7, y=0), + Item(key=8, y=0), + ] + ) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "add", "path": ["controls", 0], "value": Item(key=1, y=0)}, + {"op": "add", "path": ["controls", 1], "value": Item(key=2, y=0)}, + {"op": "replace", "path": ["controls", 3, "y"], "value": 40}, + {"op": "move", "from": ["controls", 3], "path": ["controls", 2]}, + {"op": "replace", "path": ["controls", 3, "y"], "value": 30}, + {"op": "replace", "path": ["controls", 4, "y"], "value": 0}, + {"op": "replace", "path": ["controls", 5, "y"], "value": 0}, + {"op": "add", "path": ["controls", 6], "value": Item(key=7, y=0)}, + {"op": "add", "path": ["controls", 7], "value": Item(key=8, y=0)}, + ], + ) + + +def test_compare_controls(): + def on_scroll(e): + pass + + r1 = ft.Row( + controls=[ft.Text("Hello"), ft.Text("World")], + spacing=10, + scale=ft.Scale(0.5, scale_x=0.1, scale_y=0.2), + vertical_alignment=ft.CrossAxisAlignment.CENTER, + on_scroll=on_scroll, + ) + r2 = ft.Row( + controls=[ft.Text("Hello"), ft.Text("World")], + spacing=10, + scale=ft.Scale(0.5, scale_x=0.1, scale_y=0.2), + vertical_alignment=ft.CrossAxisAlignment.CENTER, + on_scroll=on_scroll, + ) + assert r1 == r2 + + dp1 = LineChartDataPoint(x=10, y=20) + dp2 = LineChartDataPoint(x=10, y=20) + assert dp1 == dp2 + + dp3 = dp2 + assert dp2 is dp3 + + r3 = ft.Row(spacing=20) + r4 = ft.Row(spacing=10) + assert r3 != r4 + + +def test_button_basic_diff(): + b1 = ft.Button(content="Hello") + b2 = ft.Button( + content="Click me", + style=ft.ButtonStyle(color=ft.Colors.RED), + scale=ft.Scale(0.2), + ) + b1._frozen = True + b2._frozen = True + + # initial iteration + patch, _, _, _ = make_diff(b2, {}) + assert not hasattr(b2, "__prev_classes") + assert isinstance(patch[0]["value"], ft.Button) + + # 2nd iteration + patch, _, _, _ = make_diff(b2, b1) + assert len(patch) == 3 + assert cmp_ops_unordered( + patch, + [ + { + "op": "replace", + "path": ["_internals"], + "value": {"style": ft.ButtonStyle(color=ft.Colors.RED, elevation=1)}, + }, + {"op": "replace", "path": ["scale"], "value": ft.Scale(0.2)}, + {"op": "replace", "path": ["content"], "value": "Click me"}, + ], + ) + + # 3rd iteration + b3 = ft.Button(content=ft.Text("Text_1"), style=None, scale=ft.Scale(0.1)) + b3._frozen = True + patch, _, _, _ = make_diff(b3, b2) + assert cmp_ops_unordered( + patch, + [ + { + "op": "replace", + "path": ["_internals"], + "value": {}, + }, + {"op": "replace", "path": ["scale", "scale"], "value": 0.1}, + {"op": "replace", "path": ["content"], "value": ft.Text("Text_1")}, + ], + ) + + +def test_lists_with_key_diff(): + c1 = LineChart( + data_series=[ + LineChartData( + points=[ + LineChartDataPoint(key=0, x=0, y=1), + LineChartDataPoint(key=1, x=1, y=2), + LineChartDataPoint(key=2, x=2, y=3), + ] + ) + ] + ) + c2 = LineChart( + data_series=[ + LineChartData( + points=[ + LineChartDataPoint(key=1, x=1, y=2), + LineChartDataPoint(key=2, x=2, y=2), + LineChartDataPoint(key=3, x=3, y=5), + ] + ) + ] + ) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert c2._frozen + assert c2.data_series[0]._frozen + assert cmp_ops( + patch, + [ + { + "op": "remove", + "path": ["data_series", 0, "points", 0], + "value": LineChartDataPoint(key=0, x=0, y=1), + }, + {"op": "replace", "path": ["data_series", 0, "points", 1, "y"], "value": 2}, + { + "op": "add", + "path": ["data_series", 0, "points", 2], + "value": LineChartDataPoint(key=3, x=3, y=5), + }, + ], + ) + assert patch[2]["value"].x == 3 + assert patch[2]["value"].y == 5 + + +def test_lists_with_no_key_diff(): + c1 = LineChart( + data_series=[ + LineChartData( + points=[ + LineChartDataPoint(x=0, y=1), + LineChartDataPoint(x=1, y=2), + LineChartDataPoint(x=2, y=3), + ] + ) + ] + ) + c2 = LineChart( + data_series=[ + LineChartData( + points=[ + LineChartDataPoint(x=1, y=2), + LineChartDataPoint(x=2, y=2), + LineChartDataPoint(x=3, y=5), + ] + ) + ] + ) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert c2._frozen + assert c2.data_series[0]._frozen + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["data_series", 0, "points", 0, "x"], + "value": 1, + }, + { + "op": "replace", + "path": ["data_series", 0, "points", 0, "y"], + "value": 2, + }, + { + "op": "replace", + "path": ["data_series", 0, "points", 1, "x"], + "value": 2, + }, + { + "op": "replace", + "path": ["data_series", 0, "points", 2, "x"], + "value": 3, + }, + { + "op": "replace", + "path": ["data_series", 0, "points", 2, "y"], + "value": 5, + }, + ], + ) + + +def test_simple_lists_diff_1(): + c1 = LineChart(data_series=[LineChartData(points=[1, 2, 3])]) + c2 = LineChart(data_series=[LineChartData(points=[2, 3, 4])]) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["data_series", 0, "points", 0], "value": 1}, + {"op": "add", "path": ["data_series", 0, "points", 2], "value": 4}, + ], + ) + + +def test_simple_lists_diff_2(): + c1 = LineChart(data_series=[LineChartData(points=[1, 2, 3, 4])]) + c2 = LineChart(data_series=[LineChartData(points=[1, 3, 4])]) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["data_series", 0, "points", 1], "value": 2}, + ], + ) + + +def test_similar_lists_diff(): + c1 = LineChart(data_series=[LineChartData(points=[ft.Scale(0), ft.Scale(1)])]) + c2 = LineChart(data_series=[LineChartData(points=[ft.Scale(1), ft.Scale(2)])]) + c1._frozen = True + patch, _, _, _ = make_diff(c2, c1) + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["data_series", 0, "points", 0, "scale"], + "value": 1, + }, + { + "op": "replace", + "path": ["data_series", 0, "points", 1, "scale"], + "value": 2, + }, + ], + ) + + +def test_lists_in_place(): + c1 = LineChart( + data_series=[ + LineChartData( + points=[ + LineChartDataPoint(x=0, y=1), + LineChartDataPoint(x=1, y=2), + LineChartDataPoint(x=2, y=3), + ] + ) + ] + ) + _, patch, _, _, _ = make_msg(c1, {}) + + # 1st change + c1.data_series[0].points.pop(0) + c1.data_series[0].points[1].y = 10 + c1.data_series[0].points.append(LineChartDataPoint(x=3, y=4)) + c1.data_series.append( + LineChartData( + points=[ + LineChartDataPoint(x=10, y=20), + ] + ) + ) + patch, msg, added_controls, removed_controls = make_diff(c1) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["data_series", 0, "points", 0]}, + { + "op": "replace", + "path": ["data_series", 0, "points", 1, "y"], + "value": 10, + }, + { + "op": "add", + "path": ["data_series", 0, "points", 2], + "value_type": LineChartDataPoint, + }, + {"op": "add", "path": ["data_series", 1], "value_type": LineChartData}, + ], + ) + + +def test_both_frozen_hosted_by_in_place(): + def chart(data): + r = LineChart( + data_series=[ + LineChartData( + points=[ + LineChartDataPoint(key=dp[0], x=dp[0], y=dp[1]) for dp in ds + ] + ) + for ds in data + ] + ) + r._frozen = True + return r + + c = ft.Container(content=chart([[(0, 1), (1, 1), (2, 2)], [(10, 20), (20, 30)]])) + assert not hasattr(c, "_frozen") + _, patch, _, added_controls, removed_controls = make_msg(c, {}) + assert len(added_controls) == 9 + assert len(removed_controls) == 0 + assert hasattr(c, "_dirty") + assert not hasattr(c, "_frozen") + + c.alignment = ft.Alignment.BOTTOM_CENTER + c.bgcolor = ft.Colors.AMBER + ch = chart([[(1, 1), (2, 2), (3, 3)]]) + c.content = ch + patch, _, added_controls, removed_controls = make_diff(c, c) + # for ac in added_controls: + # print("\nADDED CONTROL:", ac) + # for rc in removed_controls: + # print("\nREMOVED CONTROL:", rc) + # 5 x Added controls: LineChart + LineChartData + + # 3 x LineChartDataPoint (2 moved and 1 new) + assert len(added_controls) == 5 + # 3 x Removed controls: LineChart + 2 x LineChartData + 5 x LineChartDataPoint + assert len(removed_controls) == 8 + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["alignment"], "value": ft.Alignment(x=0, y=1)}, + {"op": "replace", "path": ["bgcolor"], "value": ft.Colors.AMBER}, + {"op": "remove", "path": ["content", "data_series", 0, "points", 0]}, + { + "op": "add", + "path": ["content", "data_series", 0, "points", 2], + "value_type": LineChartDataPoint, + }, + { + "op": "remove", + "path": ["content", "data_series", 1], + "value_type": LineChartData, + }, + ], + ) + assert hasattr(ch, "_frozen") + with pytest.raises(Exception, match="Frozen controls cannot be updated."): + ch.width = 100 + + +def test_larger_control_updates(): + c1 = ft.Container( + content=ft.Row([ft.Text("Text 1")]), + bgcolor=ft.Colors.YELLOW, + width=200, + height=100, + scale=ft.Scale(1.0), + ) + c1._frozen = True + c2 = ft.Container( + content=ft.Row([ft.Text("Text 2")]), + bgcolor=ft.Colors.RED, + width=200, + scale=ft.Scale(2.0), + ) + c2._frozen = True + patch, msg, added_controls, removed_controls = make_diff(c2, c1) + assert cmp_ops_unordered( + patch, + [ + {"op": "replace", "path": ["height"], "value": None}, + {"op": "replace", "path": ["scale", "scale"], "value": 2.0}, + { + "op": "replace", + "path": ["content", "controls", 0, "value"], + "value": "Text 2", + }, + {"op": "replace", "path": ["bgcolor"], "value": ft.Colors.RED}, + ], + ) + + +@dataclass +class User: + id: int + name: str + age: int + verified: bool + + +def test_component_single_control_diff(): + comp = Component(fn=lambda: None, args=(), kwargs={}) + old = ft.Button("Hey there!") + new = ft.Button("Hello, world!") + patch, added_controls, removed_controls = ObjectPatch.from_diff( + old, new, control_cls=ft.BaseControl, parent=comp, path=["_b"], frozen=True + ) + assert cmp_ops( + patch.patch, + [{"op": "replace", "path": ["_b", "content"], "value": "Hello, world!"}], + ) + + +def test_component_list_diff(): + comp = Component(fn=lambda: None, args=(), kwargs={}) + old = [ft.Column([ft.Button("Hey there!")])] + new = [ + c1 := ft.Column([btn1 := ft.Button("Hello, world!")]), + txt1 := ft.Text("New control"), + ] + patch, added_controls, removed_controls = ObjectPatch.from_diff( + old, new, control_cls=ft.BaseControl, parent=comp, path=["_b"], frozen=True + ) + assert cmp_ops( + patch.patch, + [ + { + "op": "replace", + "path": ["_b", 0, "controls", 0, "content"], + "value": "Hello, world!", + }, + {"op": "add", "path": ["_b", 1], "value_type": ft.Text}, + ], + ) + assert c1._frozen + assert btn1._frozen + assert txt1._frozen + assert c1.parent == comp + assert btn1.parent == c1 + assert txt1.parent == comp + + +def test_component_list_replaces_when_component_fn_changes(): + def c1_fn(): + return ft.Text("one") + + def c2_fn(): + return ft.Text("two") + + host = Component(fn=lambda: None, args=(), kwargs={}) + old = [Component(fn=c1_fn, args=(), kwargs={})] + new = [Component(fn=c2_fn, args=(), kwargs={})] + + patch, added_controls, removed_controls = ObjectPatch.from_diff( + old, new, control_cls=ft.BaseControl, parent=host, path=["_b"], frozen=True + ) + + assert cmp_ops( + patch.patch, + [ + {"op": "replace", "path": ["_b", 0], "value_type": Component}, + ], + ) + assert any(isinstance(c, Component) for c in added_controls) + assert any(isinstance(c, Component) for c in removed_controls) + + +def test_list_insertions_with_keys(): + col_1 = ft.Column( + [ + MyText("Line 2", key=2), + MyText("Line 4", key=4), + MyText("Line 6", key=6), + MyText("Line 8", key=8), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2 (updated)", key=2), + MyText("Line 3", key=3), + MyText("Line 4 (updated)", key=4), + MyText("Line 5", key=5), + MyText("Line 6 (updated)", key=6), + MyText("Line 7", key=7), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "add", + "path": ["controls", 0], + "value": MyText(key=1, value="Line 1"), + }, + { + "op": "replace", + "path": ["controls", 1, "value"], + "value": "Line 2 (updated)", + }, + { + "op": "add", + "path": ["controls", 2], + "value": MyText(key=3, value="Line 3"), + }, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 4 (updated)", + }, + { + "op": "add", + "path": ["controls", 4], + "value": MyText(key=5, value="Line 5"), + }, + { + "op": "replace", + "path": ["controls", 5, "value"], + "value": "Line 6 (updated)", + }, + { + "op": "replace", + "path": ["controls", 6], + "value": MyText(key=7, value="Line 7"), + }, + ], + ) + + +def test_list_move_1a(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2 (divider)", key=2), + MyText("Line 3", key=3), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 3", key=3), + MyText("Line 2", key=2), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + {"op": "replace", "path": ["controls", 2, "value"], "value": "Line 2"}, + ], + ) + + +def test_list_move_1b(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3 (divider)", key=3), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 3", key=3), + MyText("Line 2", key=2), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["controls", 2, "value"], "value": "Line 3"}, + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + ], + ) + + +def test_list_move_1c(): + col_1 = ft.Column( + [ + MyText("Line 1 (divider)", key=1), + MyText("Line 2 (divider)", key=2), + MyText("Line 3 (divider)", key=3), + MyText("Line 4", key=4), + MyText("Line 5", key=5), + MyText("Line 6 (divider)", key=6), + MyText("Line 7 (divider)", key=7), + MyText("Line 8", key=8), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 8", key=8), + MyText("Line 5", key=5), + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + MyText("Line 4", key=4), + MyText("Line 6", key=6), + MyText("Line 7", key=7), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 7], "path": ["controls", 0]}, + {"op": "move", "from": ["controls", 5], "path": ["controls", 1]}, + {"op": "replace", "path": ["controls", 2, "value"], "value": "Line 1"}, + {"op": "replace", "path": ["controls", 3, "value"], "value": "Line 2"}, + {"op": "replace", "path": ["controls", 4, "value"], "value": "Line 3"}, + {"op": "replace", "path": ["controls", 6, "value"], "value": "Line 6"}, + {"op": "replace", "path": ["controls", 7, "value"], "value": "Line 7"}, + ], + ) + + +def test_list_move_1d(): + col_1 = ft.Column( + [ + MyText("Line 1 (divider)", key=1), + MyText("Line 2 (divider)", key=2), + MyText("Line 3", key=3), + MyText("Line 4", key=4), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 4", key=4), + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 3], "path": ["controls", 0]}, + {"op": "replace", "path": ["controls", 1, "value"], "value": "Line 1"}, + {"op": "replace", "path": ["controls", 2, "value"], "value": "Line 2"}, + ], + ) + + +def test_list_move_2a(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2 (divider)", key=2), + MyText("Line 3", key=3), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 3", key=3), + MyText("Line 1", key=1), + MyText("Line 2", key=2), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 2], "path": ["controls", 0]}, + {"op": "replace", "path": ["controls", 2, "value"], "value": "Line 2"}, + ], + ) + + +def test_list_move_2(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + MyText("Line 4", key=4), + MyText("Line 0", key=0), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2 (updated)", key=2), + MyText("Line 4 (updated)", key=4), + MyText("Line 3 (updated)", key=3), + MyText("Line 0", key=0), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["controls", 1, "value"], + "value": "Line 2 (updated)", + }, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 4 (updated)", + }, + {"op": "move", "from": ["controls", 3], "path": ["controls", 2]}, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 3 (updated)", + }, + ], + ) + + +def test_list_move_3(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 3", key=3), + MyText("Line 2", key=2), + MyText("Line 1 (updated)", key=1), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 2], "path": ["controls", 0]}, + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + { + "op": "replace", + "path": ["controls", 2, "value"], + "value": "Line 1 (updated)", + }, + ], + ) + + +def test_list_move_4(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 3", key=3), + MyText("Line 2 (updated)", key=2), + MyText("Line 1", key=1), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 2], "path": ["controls", 0]}, + { + "op": "replace", + "path": ["controls", 2, "value"], + "value": "Line 2 (updated)", + }, + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + ], + ) + + +def test_list_move_5(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + MyText("Line 4", key=4), + MyText("Line 5", key=5), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1 (updated)", key=1), + MyText("Line 2", key=2), + MyText("Line 4 (updated)", key=4), + MyText("Line 3", key=3), + MyText("Line 5", key=5), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["controls", 0, "value"], + "value": "Line 1 (updated)", + }, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 4 (updated)", + }, + {"op": "move", "from": ["controls", 3], "path": ["controls", 2]}, + ], + ) + + +def test_list_move_6(): + col_1 = ft.Column( + [ + MyText("Line 0", key=0), + MyText("Line 1", key=1), + MyText("Line 2", key=2), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1 (updated)", key=1), + MyText("Line 2 (updated)", key=2), + MyText("Line 3 (updated)", key=3), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "remove", + "path": ["controls", 0], + "value": MyText(key=0, value="Line 0"), + }, + { + "op": "replace", + "path": ["controls", 0, "value"], + "value": "Line 1 (updated)", + }, + { + "op": "replace", + "path": ["controls", 1, "value"], + "value": "Line 2 (updated)", + }, + { + "op": "add", + "path": ["controls", 2], + "value": MyText(key=3, value="Line 3 (updated)"), + }, + ], + ) + + +def test_list_move_7(): + col_1 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 3", key=3), + MyText("Line 4", key=4), + MyText("Line 5", key=5), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 4 (updated)", key=4), + MyText("Line 3", key=3), + MyText("Line 2", key=2), + MyText("Line 5", key=5), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 4 (updated)", + }, + {"op": "move", "from": ["controls", 3], "path": ["controls", 1]}, + {"op": "move", "from": ["controls", 3], "path": ["controls", 2]}, + ], + ) + + +def test_list_move_8_no_keys(): + col_1 = ft.Column( + [ + MyText("Line 1"), + MyText("Line 2"), + MyText("Line 3"), + MyText("Line 4"), + MyText("Line 5"), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1"), + MyText("Line 4 (updated)"), + MyText("Line 3"), + MyText("Line 2"), + MyText("Line 5"), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["controls", 1, "value"], + "value": "Line 4 (updated)", + }, + {"op": "replace", "path": ["controls", 3, "value"], "value": "Line 2"}, + ], + ) + + +def test_list_move_9(): + col_1 = ft.Column( + [ + MyText("Line 3", key=3), + MyText("Line 4", key=4), + MyText("Line 5", key=5), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Line 1", key=1), + MyText("Line 2", key=2), + MyText("Line 4 (updated)", key=4), + MyText("Line 3 (updated)", key=3), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "add", + "path": ["controls", 0], + "value": MyText(key=1, value="Line 1"), + }, + { + "op": "add", + "path": ["controls", 1], + "value": MyText(key=2, value="Line 2"), + }, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 4 (updated)", + }, + {"op": "move", "from": ["controls", 3], "path": ["controls", 2]}, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 3 (updated)", + }, + { + "op": "remove", + "path": ["controls", 4], + "value": MyText(key=5, value="Line 5"), + }, + ], + ) + + +def test_list_move_10(): + col_1 = ft.Column( + [ + MyText("Group 1", key=1), + MyText("Group 2 (divider)", key=2), + MyText("Group 3 (divider)", key=3), + # MyText("Group 4 (divider)", key=4), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Group 1", key=1), + # MyText("Group 4", key=4), + MyText("Group 3", key=3), + MyText("Group 2", key=2), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["controls", 2, "value"], "value": "Group 3"}, + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + {"op": "replace", "path": ["controls", 2, "value"], "value": "Group 2"}, + ], + ) + + +def test_list_move_11(): + col_1 = ft.Column( + [ + # MyText("Group -4", key=-4), + # MyText("Group -3", key=-3), + # MyText("Group -2", key=-2), + # MyText("Group -1", key=-1), + MyText("Group 0", key=0), + MyText("Group 1 (divider)", key=1), + MyText("Group 2 (divider)", key=2), + ] + ) + col_1._frozen = True + col_2 = ft.Column( + [ + MyText("Group 1", key=1), + MyText("Group 2", key=2), + MyText("Group 3", key=3), + # MyText("Group 4", key=4), + ] + ) + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + { + "op": "remove", + "path": ["controls", 0], + "value": MyText(key=0, value="Group 0"), + }, + {"op": "replace", "path": ["controls", 0, "value"], "value": "Group 1"}, + {"op": "replace", "path": ["controls", 1, "value"], "value": "Group 2"}, + { + "op": "add", + "path": ["controls", 2], + "value": MyText(key=3, value="Group 3"), + }, + ], + ) + + +def test_fields_start_with_on(): + t1 = MyText("Text 1") + t2 = MyText( + "Text 2", + color_scheme=ft.ColorScheme(on_surface_variant=ft.Colors.RED), + on_select=lambda e: print("Selected"), + ) + t1._frozen = True + + msg, _, _, _, _ = make_msg(t2, t1, show_details=False) + u_msg = b_unpack(msg) + + expected = [ + [0], + [0, 0, "value", "Text 2"], + [0, 0, "color_scheme", {"on_surface_variant": "red"}], + [0, 0, "on_select", True], + ] + + assert isinstance(u_msg, list) + assert u_msg == expected + + +def test_fields_start_with_on_update(): + t1 = MyText( + "Text 1", + color_scheme=ft.ColorScheme(on_surface_variant=ft.Colors.RED), + on_select=lambda e: print("Selected"), + ) + t2 = MyText( + "Text 2", + color_scheme=ft.ColorScheme(on_surface_variant=ft.Colors.BLUE), + ) + t1._frozen = True + + msg, _, _, _, _ = make_msg(t2, t1, show_details=False) + u_msg = b_unpack(msg) + + expected = [ + [0, {"color_scheme": [1]}], + [0, 0, "value", "Text 2"], + [0, 1, "on_surface_variant", "blue"], + [0, 0, "on_select", False], + ] + + assert isinstance(u_msg, list) + assert u_msg == expected diff --git a/sdk/python/packages/flet/tests/test_object_diff_in_place.py b/sdk/python/packages/flet/tests/test_object_diff_in_place.py new file mode 100644 index 0000000000..43554ed86f --- /dev/null +++ b/sdk/python/packages/flet/tests/test_object_diff_in_place.py @@ -0,0 +1,855 @@ +from dataclasses import field +from typing import Any, Optional + +from pytest import raises + +import flet as ft +from flet.components.component import Component +from flet.controls.base_control import control +from flet.controls.buttons import ButtonStyle +from flet.controls.colors import Colors +from flet.controls.control import Control +from flet.controls.core.gesture_detector import GestureDetector +from flet.controls.core.text import Text +from flet.controls.events import DragUpdateEvent +from flet.controls.material.button import Button + +# import flet as ft +# import flet.canvas as cv +from flet.controls.material.container import Container +from flet.controls.page import Page +from flet.controls.painting import Paint, PaintLinearGradient +from flet.controls.ref import Ref +from flet.controls.services.service import Service +from flet.messaging.connection import Connection +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub + +from .common import ( + LineChart, + LineChartData, + LineChartDataPoint, + MyText, + b_pack, + b_unpack, + cmp_ops, + make_diff, + make_msg, +) + + +@control +class SuperButton(Button): + prop_2: Optional[str] = None + + def init(self): + pass + + def build(self): + print("SuperButton.build()") + assert self.page + + +@control("MyButton") +class MyButton(Button): + prop_1: Optional[str] = None + + +@control("MyService") +class MyService(Service): + prop_1: Optional[str] = None + prop_2: list[int] = field(default_factory=list) + + +@control("Span") +class Span(Control): + text: Optional[str] = None + cls: Optional[str] = None + controls: list[Any] = field(default_factory=list) + head_controls: list[Any] = field(default_factory=list) + + +@control("Div") +class Div(Control): + cls: Optional[str] = None + some_value: Any = None + controls: list[Any] = field(default_factory=list) + + +def test_control_type(): + """Ensure a built-in control keeps its expected protocol type.""" + btn = Button("some button") + assert btn._c == "Button" + + +def test_control_id(): + """Ensure controls receive runtime protocol IDs.""" + btn = Button("some button") + assert btn._i > 0 + + +def test_inherited_control_has_the_same_type(): + """Ensure inherited controls keep the base type when none is overridden.""" + btn = SuperButton(prop_2="2") + assert btn._c == "Button" + + +def test_inherited_control_with_overridden_type(): + """Ensure inherited controls can override their protocol type.""" + btn = MyButton(prop_1="1") + assert btn._c == "MyButton" + + +def test_control_ref(): + """Ensure control refs are populated during control initialization.""" + page_ref = Ref[Page]() + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn), ref=page_ref) + + assert page_ref.current == page + + +def test_optional_structural_value_restored_after_none(): + """Ensure optional structural values emit patches when restored after None.""" + + @ft.value + class OptionalConfig: + value: str = "default" + + @control("OptionalConfigHost") + class OptionalConfigHost(Control): + config: Optional[OptionalConfig] = field( + default_factory=lambda: OptionalConfig() + ) + + host = OptionalConfigHost() + patch, _, _, _ = make_diff(host, show_details=False) + assert patch == [] + + b_pack(host) + + host.config = None + patch, _, _, _ = make_diff(host, show_details=False) + assert patch == [{"op": "replace", "path": ["config"], "value": None}] + + host.config = OptionalConfig(value="restored") + patch, _, _, _ = make_diff(host, show_details=False) + assert len(patch) == 1 + assert patch[0]["op"] == "replace" + assert patch[0]["path"] == ["config"] + assert isinstance(patch[0]["value"], OptionalConfig) + assert patch[0]["value"].value == "restored" + + +def test_list_to_dataclass_change_does_not_re_emit(): + """When a structural field changes type (list ↔ dataclass), the diff emits + exactly one replace for the change and zero ops on the next round. + + The parent's snapshot maps must follow the field across the type + transition — moving from `__prev_lists` to `__prev_classes`` (or back) + so a subsequent diff sees the field as still tracked. + """ + + @ft.value + class Holder: + items: list[int] = field(default_factory=list) + + @ft.value + class ReplacementHolder: + name: str = "x" + + @control("ListOrDataclassHost") + class ListOrDataclassHost(Control): + slot: Any = field(default_factory=Holder) + + host = ListOrDataclassHost() + b_pack(host) # prime snapshots — slot starts as Holder (dataclass) + + # dataclass → list + host.slot = [1, 2, 3] + patch, _, _, _ = make_diff(host, show_details=False) + assert len(patch) == 1 + assert patch[0]["op"] == "replace" + assert patch[0]["path"] == ["slot"] + assert patch[0]["value"] == [1, 2, 3] + + # No further mutation — must produce zero ops. + patch, _, _, _ = make_diff(host, show_details=False) + assert patch == [] + + # list → dataclass + host.slot = ReplacementHolder(name="restored") + patch, _, _, _ = make_diff(host, show_details=False) + assert len(patch) == 1 + assert patch[0]["op"] == "replace" + assert patch[0]["path"] == ["slot"] + assert isinstance(patch[0]["value"], ReplacementHolder) + + # No further mutation — must produce zero ops. + patch, _, _, _ = make_diff(host, show_details=False) + assert patch == [] + + +def test_simple_page(): + """Exercise initial page serialization and several in-place page updates.""" + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + page.controls = [Div(cls="div_1", some_value="Text")] + page.data = 100000 + page.bgcolor = Colors.GREEN + page.fonts = {"font1": "font_url_1", "font2": "font_url_2"} + page.on_login = lambda e: print("on login") + page._services._services.append(MyService(prop_1="Hello", prop_2=[1, 2, 3])) + + # page and window have hard-coded IDs + assert page._i == 1 + assert page.window and page.window._i == 2 + + msg, _, _, added_controls, removed_controls = make_msg(page, {}, show_details=True) + u_msg = b_unpack(msg) + assert len(added_controls) == 8 + assert len(removed_controls) == 0 + + assert page.parent is None + assert page.controls[0].parent == page.views[0] + + print(u_msg) + + assert isinstance(u_msg, list) + assert u_msg[0] == [0] + assert len(u_msg[1]) == 4 + p = u_msg[1][3] + assert p["_i"] > 0 + assert p["on_login"] + assert len(p["views"]) > 0 + assert "on_connect" not in p + # assert u_msg == [ + # [0], + # [ + # 0, + # 0, + # 0, + # { + # "_i": 1, + # "_c": "Page", + # "views": [ + # { + # "_i": 17, + # "_c": "View", + # "controls": [ + # { + # "_i": 29, + # "_c": "Div", + # "cls": "div_1", + # "some_value": "Text", + # } + # ], + # "bgcolor": "green", + # } + # ], + # "_overlay": {"_i": 18, "_c": "Overlay"}, + # "_dialogs": {"_i": 19, "_c": "Dialogs"}, + # "window": {"_i": 2, "_c": "Window"}, + # "browser_context_menu": {"_i": 21, "_c": "BrowserContextMenu"}, + # "shared_preferences": {"_i": 22, "_c": "SharedPreferences"}, + # "clipboard": {"_i": 23, "_c": "Clipboard"}, + # "storage_paths": {"_i": 24, "_c": "StoragePaths"}, + # "url_launcher": {"_i": 25, "_c": "UrlLauncher"}, + # "_services": { + # "_i": 26, + # "_c": "ServiceRegistry", + # "services": [ + # { + # "_i": 30, + # "_c": "MyService", + # "prop_1": "Hello", + # "prop_2": [1, 2, 3], + # } + # ], + # }, + # "fonts": {"font1": "font_url_1", "font2": "font_url_2"}, + # "on_login": True, + # }, + # ], + # ] + + # update sub-tree + page.on_login = None + page.controls[0].some_value = "Another text" + page.controls[0].controls = [ + SuperButton( + "Button 😬", + style=ButtonStyle(color=Colors.RED), + on_click=lambda e: print(e), + opacity=1, + ref=None, + ), + SuperButton("Another Button"), + ] + del page.fonts["font2"] + with raises(RuntimeError): + assert page.controls[0].controls[0].page is None + + page._services._services[0].prop_2 = [2, 6] + + # add 2 new buttons to a list + _, patch, _, added_controls, removed_controls = make_msg(page, show_details=True) + assert hasattr(page.views[0], "_dirty") + assert len(added_controls) == 2 + assert len(removed_controls) == 0 + assert len(patch) == 7 + assert cmp_ops( + patch, + [ + {"op": "replace", "path": ["on_login"], "value": False}, + { + "op": "replace", + "path": ["views", 0, "controls", 0, "some_value"], + "value": "Another text", + }, + { + "op": "replace", + "path": ["views", 0, "controls", 0, "controls"], + # "value": [SuperButton, SuperButton], + }, + {"op": "remove", "path": ["fonts", "font2"], "value": "font_url_2"}, + { + "op": "remove", + "path": ["_services", "_services", 0, "prop_2", 0], + "value": 1, + }, + { + "op": "add", + "path": ["_services", "_services", 0, "prop_2", 1], + "value": 6, + }, + { + "op": "remove", + "path": ["_services", "_services", 0, "prop_2", 2], + "value": 3, + }, + ], + ) + assert len(patch[2]["value"]) == 2 + assert isinstance(patch[2]["value"][0], SuperButton) + assert isinstance(patch[2]["value"][1], SuperButton) + + # replace control in a list + page.controls[0].controls[0] = SuperButton("Foo") + _, patch, _, added_controls, removed_controls = make_msg(page, show_details=True) + # for ac in added_controls: + # print("\nADDED CONTROL:", ac) + # for rc in removed_controls: + # print("\nREMOVED CONTROL:", rc) + assert len(added_controls) == 1 + assert len(removed_controls) == 1 + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["views", 0, "controls", 0, "controls", 0], + "value": SuperButton("Foo"), + }, + ], + ) + + # insert a new button to the start of a list + page.controls[0].controls.insert(0, SuperButton("Bar")) + page.controls[0].controls[1].content = "Baz" + _, patch, _, added_controls, removed_controls = make_msg(page, show_details=True) + assert len(added_controls) == 1 + assert len(removed_controls) == 0 + assert cmp_ops( + patch, + [ + { + "op": "add", + "path": ["views", 0, "controls", 0, "controls", 0], + "value_type": SuperButton, + }, + { + "op": "replace", + "path": ["views", 0, "controls", 0, "controls", 1, "content"], + "value": "Baz", + }, + ], + ) + + page.controls[0].controls.clear() + _, patch, _, added_controls, removed_controls = make_msg(page, show_details=True) + assert len(added_controls) == 0 + assert len(removed_controls) == 3 + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["views", 0, "controls", 0, "controls"], + "value": [], + } + ], + ) + + +def test_floating_action_button(): + """Ensure floating action button and page controls produce expected patches.""" + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + + # initial update + make_msg(page, {}, show_details=True) + + # second update + counter = ft.Text("0", size=50, data=0) + + def btn_click(e): + counter.data += 1 + counter.value = str(counter.data) + counter.update() + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=btn_click + ) + page.controls.append( + ft.SafeArea( + expand=True, + content=ft.Container( + content=counter, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.YELLOW, + expand=True, + ), + ), + ) + + patch, _, added_controls, removed_controls = make_diff(page, show_details=True) + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["views", 0, "floating_action_button"], + "value_type": ft.FloatingActionButton, + }, + {"op": "replace", "path": ["views", 0, "controls"]}, + ], + ) + assert len(patch[1]["value"]) == 1 + assert isinstance(patch[1]["value"][0], ft.SafeArea) + + +def test_changes_tracking(): + """Ensure scalar, dataclass, and list mutations are tracked in-place.""" + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + page.controls.append( + btn := Button(Text("Click me!"), on_click=lambda e: print("clicked!")) + ) + + # initial update + make_msg(page, {}, show_details=True) + + # second update + btn.content = Text("A new button content") + btn.width = 300 + btn.height = 100 + + # t1 = Text("AAA") + # t2 = Text("BBB") + page.controls.append(Text("Line 2")) + + patch, _, added_controls, removed_controls = make_diff(page, show_details=True) + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["views", 0, "controls", 0, "content"], + "value": ft.Text("A new button content"), + }, + { + "op": "replace", + "path": ["views", 0, "controls", 0, "width"], + "value": 300, + }, + { + "op": "replace", + "path": ["views", 0, "controls", 0, "height"], + "value": 100, + }, + { + "op": "add", + "path": ["views", 0, "controls", 1], + "value": ft.Text("Line 2"), + }, + ], + ) + + +def test_large_updates(): + """Exercise patch generation for large nested canvas updates.""" + import flet.canvas as cv + + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + + def pan_update(e: DragUpdateEvent): + pass + + page.controls.append( + Container( + cp := cv.Canvas( + [ + cv.Fill( + Paint( + gradient=PaintLinearGradient( + (0, 0), (600, 600), colors=[Colors.CYAN_50, Colors.GREY] + ) + ) + ), + ], + content=GestureDetector( + on_pan_update=pan_update, + drag_interval=30, + ), + expand=False, + ), + border_radius=5, + width=float("inf"), + expand=True, + ) + ) + + # initial update + _, patch, _, added_controls, removed_controls = make_msg( + page, {}, show_details=True + ) + + # second update + for i in range(1, 1000): + cp.shapes.append( + cv.Line(i + 1, i + 100, i + 10, i + 20, paint=Paint(stroke_width=3)) + ) + + make_msg(cp, show_details=False) + + cp.shapes[100].x1 = 12 + + # third update + for i in range(1, 20): + cp.shapes.append( + cv.Line(i + 1, i + 100, i + 10, i + 20, paint=Paint(stroke_width=3)) + ) + + _, patch, _, added_controls, removed_controls = make_msg(cp, show_details=True) + + +def test_add_remove_lists(): + """Ensure list item removals and additions produce minimal operations.""" + data = [[(0, 1), (1, 2), (2, 3)]] + chart = LineChart( + data_series=[ + LineChartData( + points=[LineChartDataPoint(key=dp[0], x=dp[0], y=dp[1]) for dp in ds] + ) + for ds in data + ] + ) + _, patch, _, _, _ = make_msg(chart, {}) + + # add/remove + chart.data_series[0].points.pop(0) + chart.data_series[0].points.append(LineChartDataPoint(x=3, y=4)) + + patch, _, _, _ = make_diff(chart, chart) + assert cmp_ops( + patch, + [ + {"op": "remove", "path": ["data_series", 0, "points", 0]}, + { + "op": "add", + "path": ["data_series", 0, "points", 2], + "value_type": LineChartDataPoint, + }, + ], + ) + + +def test_reverse_list(): + """Ensure reversing a list is represented as move operations.""" + col = ft.Column([ft.Text("Line 1"), ft.Text("Line 2"), ft.Text("Line 3")]) + _, patch, _, _, _ = make_msg(col, {}) + + # reverse + col.controls.reverse() + patch, _, _, _ = make_diff(col) + assert col.controls[0].value == "Line 3" + assert col.controls[1].value == "Line 2" + assert col.controls[2].value == "Line 1" + assert cmp_ops( + patch, + [ + {"op": "move", "from": ["controls", 2], "path": ["controls", 0]}, + {"op": "move", "from": ["controls", 2], "path": ["controls", 1]}, + ], + ) + + +def test_overriding_controls_with_component(): + """Ensure replacing a controls list with a component is patched correctly.""" + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + + # initial update + make_msg(page, {}, show_details=True) + + # replace .controls with a component + page.controls = Component( + fn=lambda: ft.Text("Hello from component"), args=(), kwargs={} + ) + + patch, _, added_controls, removed_controls = make_diff(page, show_details=True) + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["views", 0, "controls"], + "value_type": Component, + }, + ], + ) + + # second update + page.title = "Something" + page.theme_mode = ft.ThemeMode.DARK + patch, _, added_controls, removed_controls = make_diff(page, show_details=True) + print(patch) + + # 3rd update + page.title = "Bar" + page.theme_mode = ft.ThemeMode.DARK + patch, _, added_controls, removed_controls = make_diff(page, show_details=True) + print(patch) + + +def test_list_insertions(): + """Ensure list replacement and insertion patterns produce stable patches.""" + col = ft.Column( + [ + ft.Text("Line 2"), + ft.Text("Line 4"), + ft.Text("Line 6"), + ft.Text("Line 8"), + ] + ) + _, patch, _, _, _ = make_msg(col, {}) + + # 1st update + col.controls[0] = ft.Text("Line 2 (updated)") + col.controls[1] = ft.Text("Line 4 (updated)") + col.controls[2] = ft.Text("Line 6 (updated)") + + patch, _, _, _ = make_diff(col) + assert cmp_ops( + patch, + [ + { + "op": "remove", + "path": ["controls", 0], + "value": ft.Text("Line 2"), + }, + { + "op": "remove", + "path": ["controls", 0], + "value": ft.Text("Line 4"), + }, + { + "op": "replace", + "path": ["controls", 0], + "value": ft.Text("Line 2 (updated)"), + }, + { + "op": "add", + "path": ["controls", 1], + "value": ft.Text("Line 4 (updated)"), + }, + { + "op": "add", + "path": ["controls", 2], + "value": ft.Text("Line 6 (updated)"), + }, + ], + ) + + # 2nd update + col.controls.insert(0, ft.Text("Line 1")) + col.controls.insert(2, ft.Text("Line 3")) + col.controls.insert(4, ft.Text("Line 5")) + col.controls.insert(6, ft.Text("Line 7")) + col.controls[3].value = "Line 4 (updated again)" + + patch, _, _, _ = make_diff(col) + assert cmp_ops( + patch, + [ + {"op": "add", "path": ["controls", 0], "value": ft.Text("Line 1")}, + {"op": "add", "path": ["controls", 2], "value": ft.Text("Line 3")}, + { + "op": "replace", + "path": ["controls", 3, "value"], + "value": "Line 4 (updated again)", + }, + {"op": "add", "path": ["controls", 4], "value": ft.Text("Line 5")}, + {"op": "add", "path": ["controls", 6], "value": ft.Text("Line 7")}, + ], + ) + + +def test_list_move_1_no_keys(): + """Ensure lists without keys still produce valid move/add/remove patches.""" + line_1 = MyText("Line 1") + line_2 = MyText("Line 2") + line_3 = MyText("Line 3") + line_4 = MyText("Line 4") + line_5 = MyText("Line 5") + + col_1 = [ + line_1, + line_2, + line_3, + line_4, + line_5, + ] + + col_2 = [ + MyText("Line 0"), + line_4, + line_3, + line_5, + MyText("Line 6"), + ] + + patch, msg, added_controls, removed_controls = make_diff(col_2, col_1) + + assert cmp_ops( + patch, + [ + {"op": "remove", "path": [0], "value": MyText("Line 1")}, + {"op": "replace", "path": [0], "value": MyText("Line 0")}, + {"op": "move", "from": [2], "path": [1]}, + {"op": "add", "path": [4], "value": MyText("Line 6")}, + ], + ) + + +def test_fields_start_with_on(): + """Ensure event-like fields and theme fields serialize and update correctly.""" + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + page.controls = [Div(cls="div_1", some_value="Text")] + page.on_login = lambda e: print("on login") + page.theme = ft.Theme( + color_scheme=ft.ColorScheme(on_surface_variant=ft.Colors.RED), + ) + + msg, _, _, _, _ = make_msg(page, {}, show_details=True) + u_msg = b_unpack(msg) + + print(u_msg) + + # page + p = u_msg[1][3] + # print("\n\n", p) + assert p["on_login"] + assert p["theme"]["color_scheme"]["on_surface_variant"] == "red" + + # update + page.on_login = None + page.theme.color_scheme.on_surface_variant = ft.Colors.BLUE + + msg, _, _, _, _ = make_msg(page, show_details=True) + u_msg = b_unpack(msg) + # print("\n\n", u_msg[1]) + assert u_msg[1][2] == "on_login" + assert not u_msg[1][3] + assert u_msg[2][2] == "on_surface_variant" + assert u_msg[2][3] == "blue" + + +def test_list_with_keys_can_be_updated(): + """Ensure keyed list children can receive appended controls.""" + col = ft.Column( + [ + ft.Text("Line 1", key=ft.ScrollKey(1)), + ft.Text("Line 2", key=ft.ScrollKey(2)), + ] + ) + _, patch, _, _, _ = make_msg(col, {}) + + # 1st update + col.controls.append(ft.Text("Line 3", key=ft.ScrollKey(3))) + + patch, _, _, _ = make_diff(col) + assert cmp_ops( + patch, + [ + { + "op": "add", + "path": ["controls", 2], + "value": Text("Line 3", key=ft.ScrollKey(3)), + } + ], + ) + + col.controls[2].value = "Line 3 (updated)" + + +def test_list_without_keys_children_must_be_updated(): + """Ensure unkeyed moved children emit the needed child value updates.""" + col = ft.Column( + [ + ft.Text("Line 1"), + ft.Text("Line 2"), + ft.Text("Line 3"), + ft.Text("Line 4"), + ] + ) + _, patch, _, _, _ = make_msg(col, {}) + + # 1st update + col.controls.insert(0, col.controls.pop(2)) + col.controls[0].value = "Line 3 (updated)" + col.controls[1].value = "Line 1 (updated)" + col.controls[2].value = "Line 2 (updated)" + + patch, _, _, _ = make_diff(col) + assert cmp_ops( + patch, + [ + { + "op": "replace", + "path": ["controls", 2, "value"], + "value": "Line 3 (updated)", + }, + {"op": "move", "from": ["controls", 2], "path": ["controls", 0]}, + { + "op": "replace", + "path": ["controls", 1, "value"], + "value": "Line 1 (updated)", + }, + { + "op": "replace", + "path": ["controls", 2, "value"], + "value": "Line 2 (updated)", + }, + ], + ) diff --git a/sdk/python/packages/flet/tests/test_object_diff_memory_churn.py b/sdk/python/packages/flet/tests/test_object_diff_memory_churn.py new file mode 100644 index 0000000000..d28091acc3 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_object_diff_memory_churn.py @@ -0,0 +1,68 @@ +import gc +import tracemalloc + +import pytest + +import flet as ft +from flet.controls.base_control import BaseControl +from flet.controls.object_patch import ObjectPatch + +pytestmark = pytest.mark.skip(reason="Temporarily disabled") + + +def _make_tree(iteration: int, size: int = 36) -> ft.Column: + controls: list[ft.Text] = [] + offset = iteration % size + for i in range(size): + key = (i + offset) % size + value = f"Item {key}" + if i == (iteration % 7): + value = f"{value}*{iteration % 5}" + controls.append(ft.Text(value=value, key=key)) + return ft.Column(controls=controls) + + +def _object_patch_size(snapshot: tracemalloc.Snapshot) -> int: + total = 0 + for stat in snapshot.statistics("filename"): + frame = stat.traceback[0] + if frame.filename.endswith("flet/controls/object_patch.py"): + total += stat.size + return total + + +def test_object_diff_churn_memory_growth_is_bounded(): + iterations = 480 + sample_step = 80 + warmup = 160 + + previous = _make_tree(0) + previous._frozen = True + + tracemalloc.start(10) + samples: list[int] = [] + try: + for i in range(1, iterations + 1): + current = _make_tree(i) + ObjectPatch.from_diff(previous, current, control_cls=BaseControl) + previous = current + previous._frozen = True + + if i % sample_step == 0: + gc.collect() + samples.append(_object_patch_size(tracemalloc.take_snapshot())) + finally: + tracemalloc.stop() + + steady_state = [ + size for idx, size in enumerate(samples, start=1) if idx * sample_step >= warmup + ] + assert steady_state, samples + + baseline = steady_state[0] + final = steady_state[-1] + max_steady = max(steady_state) + + # In steady state this should stay near a plateau, not grow linearly with churn. + assert final - baseline < 500_000, (baseline, final, steady_state) + assert max_steady - baseline < 700_000, (baseline, max_steady, steady_state) diff --git a/sdk/python/packages/flet/tests/test_object_diff_performance.py b/sdk/python/packages/flet/tests/test_object_diff_performance.py new file mode 100644 index 0000000000..c5aade1235 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_object_diff_performance.py @@ -0,0 +1,123 @@ +import math +import random +import time + +import pytest + +import flet as ft +from flet.controls.base_control import BaseControl, control +from flet.controls.object_patch import ObjectPatch + +MAX_SEEDS = 500 + + +@control("PerfText") +class PerfText(BaseControl): + value: str + + +def _keyed_columns(size: int) -> tuple[ft.Column, ft.Column]: + old_items = [PerfText(value=f"Item {i}", key=i) for i in range(size)] + new_order = list(range(size)) + random.Random(42).shuffle(new_order) + new_items = [ + PerfText(value=f"Item {i}" if i % 5 else f"Item {i}*", key=i) for i in new_order + ] + + old_column = ft.Column(old_items) + old_column._frozen = True + new_column = ft.Column(new_items) + return old_column, new_column + + +def _literal_columns(size: int) -> tuple[ft.Column, ft.Column]: + src = list(range(size)) + dst = src[1:] + [size] + old_column = ft.Column(src) + old_column._frozen = True + new_column = ft.Column(dst) + return old_column, new_column + + +def _time_diff(factory, runs: int = 3) -> tuple[float, list[float]]: + durations: list[float] = [] + for _ in range(runs): + old, new = factory() + start = time.perf_counter() + ObjectPatch.from_diff(old, new, control_cls=BaseControl) + durations.append(time.perf_counter() - start) + return min(durations), durations + + +def test_keyed_diff_scaling_is_near_linear(): + small_best, small_all = _time_diff(lambda: _keyed_columns(150)) + large_best, large_all = _time_diff(lambda: _keyed_columns(300)) + print( + "keyed diff timings", + { + "150": [round(d * 1000, 3) for d in small_all], + "300": [round(d * 1000, 3) for d in large_all], + }, + ) + assert large_best <= small_best * 4, (small_best, large_best) + + +def test_literal_diff_scaling_is_near_linear(): + small_best, small_all = _time_diff(lambda: _literal_columns(200)) + large_best, large_all = _time_diff(lambda: _literal_columns(400)) + print( + "literal diff timings", + { + "200": [round(d * 1000, 3) for d in small_all], + "400": [round(d * 1000, 3) for d in large_all], + }, + ) + assert large_best <= small_best * 3, (small_best, large_best) + + +def _sunflower_controls(count: int) -> list[ft.Container]: + tau = math.pi * 2 + scale_factor = 1 / 40 + phi = (math.sqrt(5) + 1) / 2 + controls: list[ft.Container] = [] + for i in range(count): + theta = i * tau / phi + r = math.sqrt(i) * scale_factor + controls.append( + ft.Container( + key=i, + width=5, + height=5, + bgcolor=ft.Colors.ORANGE, + align=ft.Alignment(r * math.cos(theta), -r * math.sin(theta)), + ) + ) + for j in range(count, MAX_SEEDS): + controls.append( + ft.Container( + key=j, + width=5, + height=5, + bgcolor=ft.Colors.GREY_700, + align=ft.Alignment( + math.cos(tau * j / (MAX_SEEDS - 1)) * 0.9, + math.sin(tau * j / (MAX_SEEDS - 1)) * 0.9, + ), + ) + ) + return controls + + +def _sunflower_stack(count: int) -> tuple[ft.Stack, ft.Stack]: + old_stack = ft.Stack(controls=_sunflower_controls(count)) + old_stack._frozen = True + new_stack = ft.Stack(controls=_sunflower_controls(count + 10)) + return old_stack, new_stack + + +@pytest.mark.skip(reason="Performance test, not a unit test") +def test_sunflower_like_update_is_fast(): + best, runs = _time_diff(lambda: _sunflower_stack(250)) + print("sunflower diff timings", [round(d * 1000, 3) for d in runs]) + # Empirically, anything above ~0.09s is a regression compared to pre-change behavior + assert best <= 0.09, best diff --git a/sdk/python/packages/flet/tests/test_observable.py b/sdk/python/packages/flet/tests/test_observable.py new file mode 100644 index 0000000000..5fbb147939 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_observable.py @@ -0,0 +1,133 @@ +from dataclasses import dataclass, field + +import flet as ft + + +class Foo(ft.Observable): + prop_a: str + prop_b: str + + +@dataclass +class Bar: + f: int + d: list[int] = field(default_factory=list) + + +@dataclass +class Baz(Bar, ft.Observable): + prop_c: int = 3 + prop_d: list[int] = field(default_factory=lambda: [1, 2, 3]) + + def add_item(self, item: int): + self.prop_d.append(item) + + +@dataclass +class Qux(ft.Observable): + prop_e: dict = field(default_factory=dict) + + def update_key(self, key, value): + self.prop_e[key] = value + + +def test_foo_observable(): + changes = [] + + def subscriber(sender, field): + changes.append((sender, field)) + + foo = Foo() + foo.subscribe(subscriber) + + foo.prop_a = "test_value" + assert len(changes) == 1 + assert changes[0][0] == foo + assert changes[0][1] == "prop_a" + + foo.prop_b = "another_value" + assert len(changes) == 2 + assert changes[1][0] == foo + assert changes[1][1] == "prop_b" + + +def test_bar_observable(): + changes = [] + + def subscriber(sender, field): + changes.append((sender, field)) + + baz = Baz(42) + baz.subscribe(subscriber) + + baz.prop_a = "new_value" + assert len(changes) == 1 + assert changes[0][0] == baz + assert changes[0][1] == "prop_a" + + baz.prop_c = 100 + assert len(changes) == 2 + assert changes[1][0] == baz + assert changes[1][1] == "prop_c" + + baz.add_item(5) + assert baz.prop_d == [1, 2, 3, 5] + assert len(changes) == 3 + assert changes[2][0] == baz + assert changes[2][1] == "prop_d" + + baz.f = 60 + assert len(changes) == 4 + assert changes[3][0] == baz + assert changes[3][1] == "f" + + baz.d = [1, 2, 3] + assert len(changes) == 5 + assert changes[4][0] == baz + assert changes[4][1] == "d" + + baz.d.reverse() + assert len(changes) == 6 + assert changes[5][0] == baz + assert changes[5][1] == "d" + + +def test_qux_observable(): + changes = [] + + def subscriber(sender, field): + changes.append((sender, field)) + + qux = Qux() + qux.subscribe(subscriber) + + qux.prop_e = {"key1": "value1"} + assert len(changes) == 1 + assert changes[0][0] == qux + assert changes[0][1] == "prop_e" + + qux.update_key("key2", "value2") + assert qux.prop_e == {"key1": "value1", "key2": "value2"} + assert len(changes) == 2 + assert changes[1][0] == qux + assert changes[1][1] == "prop_e" + + qux.prop_e["key1"] = "updated_value1" + assert qux.prop_e["key1"] == "updated_value1" + assert len(changes) == 3 + assert changes[2][0] == qux + assert changes[2][1] == "prop_e" + + +def test_observable_repr(): + foo = Foo() + initial_repr = repr(foo) + assert "version=0" in initial_repr + + foo.prop_a = "value1" + updated_repr = repr(foo) + assert "version=1" in updated_repr + + foo.prop_b = "value2" + updated_repr_2 = repr(foo) + assert "version=2" in updated_repr_2 diff --git a/sdk/python/packages/flet/tests/test_page.py b/sdk/python/packages/flet/tests/test_page.py deleted file mode 100644 index 52e9adca97..0000000000 --- a/sdk/python/packages/flet/tests/test_page.py +++ /dev/null @@ -1,6 +0,0 @@ -import pytest - - -@pytest.mark.skip(reason="no way of currently testing this") -def test_page(page): - assert page.url != "" and page.url.startswith("http"), "Test failed" diff --git a/sdk/python/packages/flet/tests/test_patch_dataclass.py b/sdk/python/packages/flet/tests/test_patch_dataclass.py new file mode 100644 index 0000000000..a43e48aee8 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_patch_dataclass.py @@ -0,0 +1,303 @@ +from dataclasses import dataclass, field + +import msgpack + +import flet as ft +from flet.controls.base_control import BaseControl, control +from flet.controls.base_page import PageMediaData +from flet.controls.object_patch import ObjectPatch +from flet.controls.padding import Padding +from flet.controls.page import Page +from flet.controls.types import Brightness, PagePlatform +from flet.messaging.connection import Connection +from flet.messaging.protocol import configure_encode_object_for_msgpack +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub +from flet.utils import patch_dataclass + + +def test_simple_patch_dataclass(): + @dataclass + class Config: + retries: int + timeout: float + + @dataclass + class AppSettings: + debug: bool + config: Config + + settings = AppSettings(debug=False, config=Config(retries=3, timeout=1.0)) + + patch = {"debug": True, "config": {"timeout": 2.5}} + + patch_dataclass(settings, patch) + + assert settings.debug + assert isinstance(settings.config, Config) + assert settings.config.timeout == 2.5 + + +def test_encode_emits_overridden_defaults(): + @control("BaseTestControl") + class BaseTestControl(BaseControl): + foo: int = 0 + + @control("ChildTestControl") + class ChildTestControl(BaseTestControl): + foo: int = 5 + + encoder = configure_encode_object_for_msgpack(BaseControl) + encoded = encoder(ChildTestControl()) + + assert encoded["foo"] == 5 + + +def test_value_decorator_registers_value_marker(): + value = ft.Alignment(1, 2) + + assert isinstance(value, ft.Value) + assert issubclass(type(value), ft.Value) + + +def test_encode_uses_value_fast_path(): + encoder = configure_encode_object_for_msgpack(BaseControl) + value = ft.Alignment(1, 2) + + encoded = encoder(value) + + assert encoded == {"x": 1, "y": 2} + assert hasattr(value, "__prev_classes") + assert getattr(value, "__prev_classes") == {} + assert hasattr(value, "__prev_lists") + assert getattr(value, "__prev_lists") == {} + assert hasattr(value, "__prev_dicts") + assert getattr(value, "__prev_dicts") == {} + + +def test_encode_preserves_explicit_empty_value_lists_and_dicts(): + """Explicit empty list/dict values should reach Dart as intentional overrides.""" + + @ft.value + class TestConfiguration: + items: list[int] | None = None + options: dict[str, int] | None = None + + encoder = configure_encode_object_for_msgpack(BaseControl) + encoded = encoder(TestConfiguration(items=[], options={})) + + assert encoded["items"] == [] + assert encoded["options"] == {} + + +def test_encode_keeps_default_structural_empty_lists_sparse(): + """Default structural empty lists should remain omitted from protocol payloads.""" + + @ft.value + class TestConfiguration: + items: list[int] = field(default_factory=list) + + encoder = configure_encode_object_for_msgpack(BaseControl) + encoded = encoder(TestConfiguration()) + + assert "items" not in encoded + + +def test_encode_serializes_nested_controls_in_value_lists(): + """Nested controls in value lists should serialize with control metadata.""" + + @ft.value + class TestConfiguration: + controls: list[ft.Control] | None = None + + value = TestConfiguration(controls=[ft.Text("A")]) + packed = msgpack.packb( + value, + default=configure_encode_object_for_msgpack(BaseControl), + use_bin_type=True, + ) + encoded = msgpack.unpackb(packed, raw=False) + + assert encoded["controls"][0]["_c"] == "Text" + assert encoded["controls"][0]["value"] == "A" + + +def test_controls_inside_value_objects_keep_nearest_control_parent(): + """Controls nested in value objects should still belong to their host control.""" + + @ft.value + class TestConfiguration: + controls: list[ft.Control] | None = None + + @control("HostControl") + class HostControl(BaseControl): + configuration: TestConfiguration | None = None + + nested = ft.IconButton(icon=ft.Icons.PLAY_ARROW, on_click=lambda _: None) + host = HostControl(configuration=TestConfiguration(controls=[nested])) + + ObjectPatch.from_diff(None, host, control_cls=BaseControl) + + assert nested.parent is host + + host = HostControl() + ObjectPatch.from_diff(None, host, control_cls=BaseControl) + nested = ft.IconButton(icon=ft.Icons.PLAY_ARROW, on_click=lambda _: None) + host.configuration = TestConfiguration(controls=[nested]) + + ObjectPatch.from_diff(host, host, control_cls=BaseControl) + + assert nested.parent is host + + +def test_page_patch_dataclass(): + conn = Connection() + conn.pubsubhub = PubSubHub() + page = Page(sess=Session(conn)) + + assert page.window.width is None + assert page.window.height is None + assert page.debug is False + + patch_dataclass( + page, + { + "pwa": False, + "web": False, + "debug": True, + "window": { + "maximized": False, + "minimized": False, + "full_screen": False, + "always_on_top": False, + "focused": True, + "visible": True, + "width": 800.0, + "height": 628.0, + "top": 232.0, + "left": -1360.0, + "opacity": 1.0, + }, + "platform_brightness": "light", + "media": { + "padding": {"top": 0.0, "right": 0.0, "bottom": 0.0, "left": 0.0}, + "view_padding": {"top": 0.0, "right": 0.0, "bottom": 0.0, "left": 0.0}, + "view_insets": {"top": 0.0, "right": 0.0, "bottom": 0.0, "left": 0.0}, + }, + "width": 800.0, + "height": 600.0, + "route": "/", + "platform": "macos", + }, + ) + + # 1 -calculate diff + patch, added_controls, removed_controls = ObjectPatch.from_diff( + None, page, control_cls=BaseControl + ) + + # 2 - convert patch to hierarchy + graph_patch = patch.to_message() + print("Patch 1:", graph_patch) + + msg = msgpack.packb( + graph_patch, default=configure_encode_object_for_msgpack(BaseControl) + ) + + print("Message 1:", msg) + + # print(page) + assert page.window.width == 800.0 + assert page.window.height == 628.0 + assert page.debug is True + # assert page._prev_debug is True + assert page.platform_brightness == Brightness.LIGHT + # assert page._prev_platform_brightness == Brightness.LIGHT + print("page.media:", page.media) + assert isinstance(page.media, PageMediaData) + assert isinstance(page.media.padding, Padding) + assert isinstance(page.media.view_insets, Padding) + assert isinstance(page.media.view_padding, Padding) + # assert page.media.padding._prev_left == 0.0 + # assert page.media.view_insets._prev_top == 0.0 + assert page.platform == PagePlatform.MACOS + + # 1 -calculate diff + patch, _, _ = ObjectPatch.from_diff(page, page, control_cls=BaseControl) + + # 2 - convert patch to hierarchy + graph_patch = patch.to_message() + print("PATCH 1:", graph_patch) + + assert graph_patch == [[0]] + + page.media.padding.left = 1 + page.platform_brightness = Brightness.DARK + page.window.width = 1024 + page.window.height = 768 + + # 1 -calculate diff + patch, _, _ = ObjectPatch.from_diff(page, page, control_cls=BaseControl) + + # 2 - convert patch to hierarchy + graph_patch = patch.to_message() + print("PATCH 2:", graph_patch) + + # TODO - fix tests + # assert graph_patch["window"]["width"] == 1024 + # assert graph_patch["platform_brightness"] == Brightness.DARK + # assert graph_patch["media"]["padding"]["left"] == 1 + + msg = msgpack.packb( + graph_patch, default=configure_encode_object_for_msgpack(BaseControl) + ) + + print("Message 2:", msg) + + +def test_dirty_tracks_changed_fields_and_clears_after_diff(): + @control("DirtyTrackControl") + class DirtyTrackControl(BaseControl): + value: int = 0 + + c = DirtyTrackControl() + + # Configure dataclass tracking internals on initial add. + ObjectPatch.from_diff(None, c, control_cls=BaseControl) + + c.value = 1 + c.value = 2 + + assert "value" in c._dirty + + patch, _, _ = ObjectPatch.from_diff(c, c, control_cls=BaseControl) + + assert len(c._dirty) == 0 + assert any( + op["op"] == "replace" and op["path"] == ["value"] and op["value"] == 2 + for op in patch.patch + ) + + +def test_prev_snapshots_are_released_when_changed_field_becomes_none(): + @control("ListTrackControl") + class ListTrackControl(BaseControl): + items: list[int] | None = None + title: str = "" + + c = ListTrackControl(items=[1], title="a") + + # Configure dataclass tracking internals on initial add. + ObjectPatch.from_diff(None, c, control_cls=BaseControl) + + # Seed __prev_lists with a tracked list snapshot as done by protocol encoding. + setattr(c, "__prev_lists", {"items": [1, 2]}) + assert "items" in getattr(c, "__prev_lists") + + # Change list field to None and another field afterwards; __prev_lists must still + # release "items" regardless of other changed field values. + c.items = None + c.title = "b" + ObjectPatch.from_diff(c, c, control_cls=BaseControl) + + assert "items" not in getattr(c, "__prev_lists") diff --git a/sdk/python/packages/flet/tests/test_radio.py b/sdk/python/packages/flet/tests/test_radio.py deleted file mode 100644 index c78bc7584e..0000000000 --- a/sdk/python/packages/flet/tests/test_radio.py +++ /dev/null @@ -1,33 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Radio() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["radio"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_label_position_enum(): - r = ft.Radio(label_position=ft.LabelPosition.LEFT) - assert isinstance(r.label_position, ft.LabelPosition) - assert isinstance(r._get_attr("labelPosition"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["labelposition"] == "left" - - -def test_label_position_str(): - r = ft.Radio(label_position="left") - assert isinstance(r.label_position, str) - assert isinstance(r._get_attr("labelPosition"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["labelposition"] == "left" diff --git a/sdk/python/packages/flet/tests/test_responsive_row.py b/sdk/python/packages/flet/tests/test_responsive_row.py deleted file mode 100644 index ee790b0f9e..0000000000 --- a/sdk/python/packages/flet/tests/test_responsive_row.py +++ /dev/null @@ -1,49 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.ResponsiveRow() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["responsiverow"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_alignment_enum(): - r = ft.ResponsiveRow(alignment=ft.MainAxisAlignment.SPACE_AROUND) - assert isinstance(r.alignment, ft.MainAxisAlignment) - assert isinstance(r._get_attr("alignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["alignment"] == "spaceAround" - - -def test_alignment_str(): - r = ft.ResponsiveRow(alignment="center") - assert isinstance(r.alignment, str) - assert isinstance(r._get_attr("alignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["alignment"] == "center" - - -def test_vertical_alignment_enum(): - r = ft.ResponsiveRow(vertical_alignment=ft.CrossAxisAlignment.STRETCH) - assert isinstance(r.vertical_alignment, ft.CrossAxisAlignment) - assert isinstance(r._get_attr("verticalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["verticalalignment"] == "stretch" - - -def test_vertical_alignment_str(): - r = ft.ResponsiveRow(vertical_alignment="center") - assert isinstance(r.vertical_alignment, str) - assert isinstance(r._get_attr("verticalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["verticalalignment"] == "center" diff --git a/sdk/python/packages/flet/tests/test_row.py b/sdk/python/packages/flet/tests/test_row.py deleted file mode 100644 index 4750bbdda1..0000000000 --- a/sdk/python/packages/flet/tests/test_row.py +++ /dev/null @@ -1,72 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Row() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["row"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_alignment_enum(): - r = ft.Row(alignment=ft.MainAxisAlignment.SPACE_AROUND) - assert isinstance(r.alignment, ft.MainAxisAlignment) - assert isinstance(r._get_attr("alignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["alignment"] == "spaceAround" - - -def test_alignment_str(): - r = ft.Row(alignment="center") - assert isinstance(r.alignment, str) - assert isinstance(r._get_attr("alignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["alignment"] == "center" - - -def test_vertical_alignment_enum(): - r = ft.Row(vertical_alignment=ft.CrossAxisAlignment.STRETCH) - assert isinstance(r.vertical_alignment, ft.CrossAxisAlignment) - assert isinstance(r._get_attr("verticalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["verticalalignment"] == "stretch" - - -def test_vertical_alignment_str(): - r = ft.Row(vertical_alignment="center") - assert isinstance(r.vertical_alignment, str) - assert isinstance(r._get_attr("verticalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["verticalalignment"] == "center" - - -def test_scroll_enum(): - r = ft.Row() - assert r.scroll is None - assert r._get_attr("scroll") is None - - r = ft.Row(scroll=ft.ScrollMode.ALWAYS) - assert isinstance(r.scroll, ft.ScrollMode) - assert r.scroll == ft.ScrollMode.ALWAYS - assert r._get_attr("scroll") == "always" - - r = ft.Row(scroll="adaptive") - assert isinstance(r.scroll, str) - assert r._get_attr("scroll") == "adaptive" - - r = ft.Row(scroll=True) - assert isinstance(r.scroll, bool) - assert r._get_attr("scroll") == "auto" - - r = ft.Row(scroll=False) - assert isinstance(r.scroll, bool) - assert r._get_attr("scroll") is None diff --git a/sdk/python/packages/flet/tests/test_session_disconnect_buffering.py b/sdk/python/packages/flet/tests/test_session_disconnect_buffering.py new file mode 100644 index 0000000000..ba561a41fb --- /dev/null +++ b/sdk/python/packages/flet/tests/test_session_disconnect_buffering.py @@ -0,0 +1,72 @@ +from datetime import datetime, timezone + +from flet.components.component import Component +from flet.components.hooks.use_effect import EffectHook +from flet.messaging.connection import Connection +from flet.messaging.protocol import ClientAction, ClientMessage, SessionCrashedBody +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub + + +class _RecordingConnection(Connection): + def __init__(self): + super().__init__() + self.messages = [] + + def send_message(self, message): + self.messages.append(message) + + +def test_disconnected_session_drops_incremental_messages(): + conn = Connection() + conn.pubsubhub = PubSubHub() + session = Session(conn) + session._Session__conn = None + session._Session__expires_at = datetime.now(timezone.utc) + + session._Session__send_message( # type: ignore[attr-defined] + ClientMessage(ClientAction.SESSION_CRASHED, SessionCrashedBody("x")) + ) + + assert session._Session__send_buffer == [] + + +def test_disconnected_session_ignores_scheduled_updates_and_effects(): + conn = Connection() + conn.pubsubhub = PubSubHub() + session = Session(conn) + session._Session__conn = None + session._Session__expires_at = datetime.now(timezone.utc) + + session.schedule_update(session.page) + hook = EffectHook( + Component(fn=lambda: None, args=(), kwargs={}), + setup=lambda: None, + ) + session.schedule_effect(hook, is_cleanup=False) + + assert len(session._Session__pending_updates) == 0 + assert len(session._Session__pending_effects) == 0 + + +def test_attach_connection_restores_state_and_flushes_buffer(): + initial_conn = Connection() + initial_conn.pubsubhub = PubSubHub() + session = Session(initial_conn) + + buffered_message = ClientMessage( + ClientAction.SESSION_CRASHED, SessionCrashedBody("buffered") + ) + session._Session__conn = None + session._Session__expires_at = datetime.now(timezone.utc) + session._Session__send_buffer = [buffered_message] + + new_conn = _RecordingConnection() + new_conn.pubsubhub = PubSubHub() + + session.attach_connection(new_conn) + + assert session.connection is new_conn + assert session.expires_at is None + assert session._Session__send_buffer == [] + assert new_conn.messages == [buffered_message] diff --git a/sdk/python/packages/flet/tests/test_shader_mask.py b/sdk/python/packages/flet/tests/test_shader_mask.py deleted file mode 100644 index 4b1e097da8..0000000000 --- a/sdk/python/packages/flet/tests/test_shader_mask.py +++ /dev/null @@ -1,39 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.ShaderMask(shader=ft.LinearGradient(colors=[ft.Colors.BLUE])) - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["shadermask"], - attrs={ - "shader": '{"colors":["blue"],"tile_mode":"clamp","begin":{"x":-1,"y":0},"end":{"x":1,"y":0},"type":"linear"}' - }, - commands=[], - ) - ], "Test failed" - - -def test_blend_mode_enum(): - r = ft.ShaderMask( - shader=ft.LinearGradient(colors=[ft.Colors.BLUE]), - blend_mode=ft.BlendMode.LIGHTEN, - ) - assert isinstance(r.blend_mode, ft.BlendMode) - assert isinstance(r._get_attr("blendMode"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["blendmode"] == "lighten" - - -def test_blend_mode_str(): - r = ft.ShaderMask( - shader=ft.LinearGradient(colors=[ft.Colors.BLUE]), blend_mode="darken" - ) - assert isinstance(r.blend_mode, str) - assert isinstance(r._get_attr("blendMode"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["blendmode"] == "darken" diff --git a/sdk/python/packages/flet/tests/test_skip_double_update.py b/sdk/python/packages/flet/tests/test_skip_double_update.py new file mode 100644 index 0000000000..d96ce14f4c --- /dev/null +++ b/sdk/python/packages/flet/tests/test_skip_double_update.py @@ -0,0 +1,184 @@ +"""Tests for skipping auto-update when .update() was already called.""" + +from unittest.mock import AsyncMock, MagicMock, patch + +import pytest + +from flet.controls.context import UpdateBehavior, _update_behavior_context_var, context +from flet.messaging.connection import Connection +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub + + +@pytest.fixture(autouse=True) +def _fresh_update_behavior(): + """Ensure each test starts with a clean UpdateBehavior.""" + token = _update_behavior_context_var.set(UpdateBehavior()) + yield + _update_behavior_context_var.reset(token) + + +def _make_session(): + conn = Connection() + conn.pubsubhub = PubSubHub() + return Session(conn) + + +# --- Context flag unit tests --- + + +def test_update_called_flag_defaults_to_false(): + assert context.was_update_called() is False + + +def test_mark_update_called_sets_flag(): + context.mark_update_called() + assert context.was_update_called() is True + + +def test_reset_update_called_clears_flag(): + context.mark_update_called() + context.reset_update_called() + assert context.was_update_called() is False + + +def test_reset_auto_update_starts_with_clean_flag(): + context.mark_update_called() + context.reset_auto_update() + assert context.was_update_called() is False + + +# --- after_event integration tests --- + + +@pytest.mark.asyncio +async def test_after_event_skips_auto_update_when_update_was_called(): + session = _make_session() + context.mark_update_called() + + with patch.object( + session, "_Session__auto_update", new_callable=AsyncMock + ) as mock_auto: + await session.after_event(session.page) + mock_auto.assert_not_called() + + +@pytest.mark.asyncio +async def test_after_event_runs_auto_update_when_update_was_not_called(): + session = _make_session() + + with patch.object( + session, "_Session__auto_update", new_callable=AsyncMock + ) as mock_auto: + await session.after_event(session.page) + mock_auto.assert_called_once_with(session.page) + + +@pytest.mark.asyncio +async def test_after_event_resets_flag_after_check(): + session = _make_session() + context.mark_update_called() + + with patch.object(session, "_Session__auto_update", new_callable=AsyncMock): + await session.after_event(session.page) + + assert context.was_update_called() is False + + +@pytest.mark.asyncio +async def test_after_event_resets_flag_even_when_auto_update_disabled(): + session = _make_session() + context.mark_update_called() + context.disable_auto_update() + + with patch.object(session, "_Session__auto_update", new_callable=AsyncMock): + await session.after_event(session.page) + + assert context.was_update_called() is False + + +# --- Generator handler simulation --- + + +@pytest.mark.asyncio +async def test_generator_handler_flag_resets_between_yields(): + """Simulate a generator handler where after_event is called after each yield. + + First yield: .update() was called -> skip auto-update + Second yield: no .update() called -> auto-update fires + """ + session = _make_session() + + with patch.object( + session, "_Session__auto_update", new_callable=AsyncMock + ) as mock_auto: + # First yield segment: user called .update() + context.mark_update_called() + await session.after_event(session.page) + assert mock_auto.call_count == 0 + + # Second yield segment: no .update() called + await session.after_event(session.page) + assert mock_auto.call_count == 1 + + +# --- Page.update() marks the flag --- + + +def test_page_update_marks_flag(): + session = _make_session() + page = session.page + + # Page.update() internally calls patch_control which needs a real connection, + # so we mock __update to isolate the flag-setting behavior. + with patch.object(page, "_Page__update"): + page.update() + + assert context.was_update_called() is True + + +# --- Service (un)registration does not flip the user's update-called flag --- +# +# Services like FilePicker register themselves via an internal `self.update()` +# during `__post_init__`. Before this fix, that flipped the update-called flag, +# which made auto-update think the user had manually called `.update()` and +# suppressed the post-handler auto-update. + + +def _fake_service(): + svc = MagicMock() + svc._c = "FakeService" + svc._i = 999 + return svc + + +def test_register_service_preserves_unset_flag(): + session = _make_session() + registry = session.page._services + + with patch.object(registry, "update"): + assert context.was_update_called() is False + registry.register_service(_fake_service()) + assert context.was_update_called() is False + + +def test_register_service_preserves_set_flag(): + session = _make_session() + registry = session.page._services + + with patch.object(registry, "update"): + context.mark_update_called() + registry.register_service(_fake_service()) + assert context.was_update_called() is True + + +def test_unregister_services_preserves_unset_flag(): + session = _make_session() + registry = session.page._services + # Seed with a service whose refcount is low enough to be filtered out. + registry._services.append(_fake_service()) + + with patch.object(registry, "update"): + assert context.was_update_called() is False + registry.unregister_services() + assert context.was_update_called() is False diff --git a/sdk/python/packages/flet/tests/test_stack.py b/sdk/python/packages/flet/tests/test_stack.py deleted file mode 100644 index ff046ab2e4..0000000000 --- a/sdk/python/packages/flet/tests/test_stack.py +++ /dev/null @@ -1,32 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Stack() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["stack"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_clip_behavior_enum(): - r = ft.Stack() - assert r.clip_behavior is None - assert r._get_attr("clipBehavior") is None - - r = ft.Stack(clip_behavior=ft.ClipBehavior.ANTI_ALIAS) - assert isinstance(r.clip_behavior, ft.ClipBehavior) - assert r.clip_behavior == ft.ClipBehavior.ANTI_ALIAS - assert r._get_attr("clipBehavior") == "antiAlias" - - r = ft.Stack(clip_behavior="none") - assert isinstance(r.clip_behavior, str) - assert r._get_attr("clipBehavior") == "none" diff --git a/sdk/python/packages/flet/tests/test_switch.py b/sdk/python/packages/flet/tests/test_switch.py deleted file mode 100644 index 06d718f854..0000000000 --- a/sdk/python/packages/flet/tests/test_switch.py +++ /dev/null @@ -1,33 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.Switch() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["switch"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_label_position_enum(): - r = ft.Switch(label_position=ft.LabelPosition.LEFT) - assert isinstance(r.label_position, ft.LabelPosition) - assert isinstance(r._get_attr("labelPosition"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["labelposition"] == "left" - - -def test_label_position_str(): - r = ft.Switch(label_position="left") - assert isinstance(r.label_position, str) - assert isinstance(r._get_attr("labelPosition"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["labelposition"] == "left" diff --git a/sdk/python/packages/flet/tests/test_text.py b/sdk/python/packages/flet/tests/test_text.py deleted file mode 100644 index b7514ab2e0..0000000000 --- a/sdk/python/packages/flet/tests/test_text.py +++ /dev/null @@ -1,76 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.Text() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["text"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_text_align_enum(): - r = ft.Text() - assert r.text_align is None - assert r._get_attr("textAlign") is None - - r = ft.Text(text_align=ft.TextAlign.RIGHT) - assert isinstance(r.text_align, ft.TextAlign) - assert r.text_align == ft.TextAlign.RIGHT - assert r._get_attr("textAlign") == "right" - - r = ft.Text(text_align="left") - assert isinstance(r.text_align, str) - assert r._get_attr("textAlign") == "left" - - -def test_text_style_enum(): - r = ft.Text() - assert r.style is None - assert r._get_attr("style") is None - - r = ft.Text(style=ft.TextThemeStyle.DISPLAY_LARGE) - assert isinstance(r.style, ft.TextThemeStyle) - assert r.style == ft.TextThemeStyle.DISPLAY_LARGE - assert r._get_attr("style") == "displayLarge" - - r = ft.Text(style="bodyMedium") - assert isinstance(r.style, str) - assert r._get_attr("style") == "bodyMedium" - - -def test_text_overflow_enum(): - r = ft.Text() - assert r.overflow is None - assert r._get_attr("overflow") is None - - r = ft.Text(overflow=ft.TextOverflow.ELLIPSIS) - assert isinstance(r.overflow, ft.TextOverflow) - assert r.overflow == ft.TextOverflow.ELLIPSIS - assert r._get_attr("overflow") == "ellipsis" - - r = ft.Text(overflow="fade") - assert isinstance(r.overflow, str) - assert r._get_attr("overflow") == "fade" - - -def test_weight_enum(): - r = ft.Text() - assert r.weight is None - assert r._get_attr("weight") is None - - r = ft.Text(weight=ft.FontWeight.BOLD) - assert isinstance(r.weight, ft.FontWeight) - assert r.weight == ft.FontWeight.BOLD - assert r._get_attr("weight") == "bold" - - r = ft.Text(weight="w100") - assert isinstance(r.weight, str) - assert r._get_attr("weight") == "w100" diff --git a/sdk/python/packages/flet/tests/test_textfield.py b/sdk/python/packages/flet/tests/test_textfield.py deleted file mode 100644 index d75a38215f..0000000000 --- a/sdk/python/packages/flet/tests/test_textfield.py +++ /dev/null @@ -1,100 +0,0 @@ -import flet as ft -from flet.core.protocol import Command - - -def test_instance_no_attrs_set(): - r = ft.TextField() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["textfield"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_text_align_enum(): - r = ft.TextField(text_align=ft.TextAlign.LEFT) - assert isinstance(r.text_align, ft.TextAlign) - assert isinstance(r._get_attr("textAlign"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["textalign"] == "left" - - -def test_text_align_str(): - r = ft.TextField(text_align="left") - assert isinstance(r.text_align, str) - assert isinstance(r._get_attr("textAlign"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["textalign"] == "left" - - -def test_keyboard_type_enum(): - r = ft.TextField() - assert r.keyboard_type is None - assert r._get_attr("keyboardType") is None - - r = ft.TextField(keyboard_type=ft.KeyboardType.NONE) - assert isinstance(r.keyboard_type, ft.KeyboardType) - assert r.keyboard_type == ft.KeyboardType.NONE - assert r._get_attr("keyboardType") == "none" - - r = ft.TextField(keyboard_type="phone") - assert isinstance(r.keyboard_type, str) - assert r._get_attr("keyboardType") == "phone" - - -def test_capitalization_enum(): - r = ft.TextField() - assert r.capitalization is None - assert r._get_attr("capitalization") is None - - r = ft.TextField(capitalization=ft.TextCapitalization.WORDS) - assert isinstance(r.capitalization, ft.TextCapitalization) - assert r.capitalization == ft.TextCapitalization.WORDS - assert r._get_attr("capitalization") == "words" - - r = ft.TextField(capitalization="sentences") - assert isinstance(r.capitalization, str) - assert r._get_attr("capitalization") == "sentences" - - -def test_border_enum(): - r = ft.TextField() - assert r.border is None - assert r._get_attr("border") is None - - r = ft.TextField(border=ft.InputBorder.OUTLINE) - assert isinstance(r.border, ft.InputBorder) - assert r.border == ft.InputBorder.OUTLINE - assert r._get_attr("border") == "outline" - - r = ft.TextField(border="none") - assert isinstance(r.border, str) - assert r._get_attr("border") == "none" - - -def test_bgcolor_sets_filled(): - r = ft.TextField() - r.bgcolor = ft.Colors.BLUE - cmd = r._build_add_commands() - assert r.filled is not None and r.filled - assert r._get_attr("filled") is not None and r._get_attr("filled") - - r = ft.TextField(bgcolor=ft.Colors.BLUE) - cmd = r._build_add_commands() - assert r.filled is not None and r.filled - assert r._get_attr("filled") is not None and r._get_attr("filled") - - r = ft.TextField(bgcolor=ft.Colors.BLUE, filled=True) - cmd = r._build_add_commands() - assert r.filled is not None and r.filled - assert r._get_attr("filled") is not None and r._get_attr("filled") - - r = ft.TextField(bgcolor=ft.Colors.BLUE, filled=False) - cmd = r._build_add_commands() - assert r.filled is not None and not r.filled - assert r._get_attr("filled") is not None and not r._get_attr("filled") diff --git a/sdk/python/packages/flet/tests/test_use_dialog.py b/sdk/python/packages/flet/tests/test_use_dialog.py new file mode 100644 index 0000000000..15d5bea48c --- /dev/null +++ b/sdk/python/packages/flet/tests/test_use_dialog.py @@ -0,0 +1,582 @@ +import asyncio +import weakref +from dataclasses import dataclass + +import pytest + +import flet as ft +from flet.components.component import Component, Renderer +from flet.controls.base_control import BaseControl +from flet.controls.context import _context_page +from flet.controls.control_event import ControlEvent +from flet.messaging.connection import Connection +from flet.messaging.protocol import ClientAction, configure_encode_object_for_msgpack +from flet.messaging.session import Session +from flet.pubsub.pubsub_hub import PubSubHub + + +class FakeSession: + def __init__(self): + self.patch_calls: list[tuple[object, dict]] = [] + self.scheduled_updates: list[object] = [] + self.index: dict[int, object] = {} + + def patch_control(self, control, **kwargs): + self.patch_calls.append((control, kwargs)) + control_id = getattr(control, "_i", None) + if control_id is not None: + self.index[control_id] = control + + def schedule_update(self, control): + self.scheduled_updates.append(control) + + def schedule_effect(self, hook, is_cleanup): + pass + + async def after_event(self, control): + pass + + +class _RecordingConnection(Connection): + def __init__(self): + super().__init__() + self.messages = [] + + def send_message(self, message): + self.messages.append(message) + + +def render_component(component: Component, page: ft.Page) -> None: + component._state.hook_cursor = 0 + token = _context_page.set(page) + try: + renderer = Renderer(component) + with renderer.with_context(), renderer._Frame(renderer, component): + component.fn(*component.args, **component.kwargs) + finally: + _context_page.reset(token) + + +def create_page() -> tuple[ft.Page, FakeSession]: + session = FakeSession() + page = ft.Page(sess=session) + page._dialogs._parent = weakref.ref(page) + return page, session + + +async def flush_async(turns: int = 5) -> None: + for _ in range(turns): + await asyncio.sleep(0) + + +def crash_messages(conn: _RecordingConnection): + return [m for m in conn.messages if m.action == ClientAction.SESSION_CRASHED] + + +def find_filled_button(session: Session, label: str) -> ft.FilledButton: + matches = [ + c + for c in session.index.values() + if isinstance(c, ft.FilledButton) and c.content == label + ] + assert len(matches) == 1 + return matches[0] + + +@pytest.mark.asyncio +async def test_use_dialog_waits_for_dismiss_before_removing_dialog(): + page, session = create_page() + show = True + dismiss_calls: list[str] = [] + + def body(): + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("Hello"), + on_dismiss=lambda e: dismiss_calls.append(e.name), + ) + if show + else None + ) + + component = Component(fn=body, args=(), kwargs={}) + + render_component(component, page) + + assert session.scheduled_updates == [page._dialogs] + assert len(page._dialogs.controls) == 1 + + dialog = page._dialogs.controls[0] + session.patch_calls.clear() + session.scheduled_updates.clear() + + show = False + render_component(component, page) + + assert page._dialogs.controls == [dialog] + assert dialog.open is False + # Dismiss patches the dialog directly — `open=False` is a single op on + # the dialog's own `_i`, which both (a) avoids a list-diff on + # `_dialogs.controls` (whose `__prev_lists` snapshot may be out of + # sync after an intervening frozen-diff `_i` migration), and (b) gives + # Flutter an unambiguous "this dialog is closing" signal. + assert len(session.patch_calls) == 1 + assert session.patch_calls[0] == (dialog, {}) + + await dialog.on_dismiss(ControlEvent(control=dialog, name="dismiss", data=None)) + + assert page._dialogs.controls == [] + assert dismiss_calls == ["dismiss"] + assert session.patch_calls[-1] == (page._dialogs, {}) + + +@pytest.mark.asyncio +async def test_use_dialog_unmount_keeps_dialog_until_dismiss_event(): + page, session = create_page() + dismiss_calls: list[str] = [] + + def body(): + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("Hello"), + on_dismiss=lambda e: dismiss_calls.append(e.name), + ) + ) + + component = Component(fn=body, args=(), kwargs={}) + render_component(component, page) + + dialog = page._dialogs.controls[0] + session.patch_calls.clear() + session.scheduled_updates.clear() + component._schedule_effect = lambda hook, is_cleanup=False: ( + hook.cleanup() if is_cleanup and hook.cleanup else None + ) + + component.will_unmount() + + assert page._dialogs.controls == [dialog] + assert dialog.open is False + # Unmount cleanup patches the dialog directly — same approach as the + # regular dismiss path, for the same reason. + assert len(session.patch_calls) == 1 + assert session.patch_calls[0] == (dialog, {}) + + await dialog.on_dismiss(ControlEvent(control=dialog, name="dismiss", data=None)) + + assert page._dialogs.controls == [] + assert dismiss_calls == ["dismiss"] + assert session.patch_calls[-1] == (page._dialogs, {}) + + +@pytest.mark.asyncio +async def test_show_dialog_still_removes_dialog_on_dismiss(): + page, session = create_page() + dismiss_calls: list[str] = [] + dialog = ft.AlertDialog( + title=ft.Text("Hello"), + on_dismiss=lambda e: dismiss_calls.append(e.name), + ) + + page.show_dialog(dialog) + + assert page._dialogs.controls == [dialog] + assert dialog.open is True + assert session.patch_calls == [(page._dialogs, {})] + + await dialog.on_dismiss(ControlEvent(control=dialog, name="dismiss", data=None)) + + assert page._dialogs.controls == [] + assert dismiss_calls == ["dismiss"] + assert session.patch_calls[-1] == (page._dialogs, {}) + + +@pytest.mark.asyncio +async def test_use_dialog_dismiss_and_show_in_same_tick_each_emit_their_own_patch(): + """Regression: two sibling `use_dialog` hosts rendering in the same tick — + one dismissing, one showing — each emit their own patch: + - The dismissing host patches its dialog directly with `open=False`. + - The showing host appends to `_dialogs.controls` and schedules a + `_dialogs` update to flush the new entry to Flutter. + + These are non-conflicting writers (disjoint `_i`s on the Dart side), + so landing them as separate messages is safe. + """ + page, session = create_page() + alert_open = True + toast_text: str | None = None + + def alert_host(): + ft.use_dialog(ft.AlertDialog(title=ft.Text("alert")) if alert_open else None) + + def toast_host(): + ft.use_dialog(ft.SnackBar(content=ft.Text(toast_text)) if toast_text else None) + + alert_c = Component(fn=alert_host, args=(), kwargs={}) + toast_c = Component(fn=toast_host, args=(), kwargs={}) + + # Initial render: alert shown, toast absent. + render_component(alert_c, page) + render_component(toast_c, page) + + alert_dialog = page._dialogs.controls[0] + assert alert_dialog.open is True + session.patch_calls.clear() + session.scheduled_updates.clear() + + # Same-tick flip: dismiss the alert AND show the toast. + alert_open = False + toast_text = "hello" + render_component(alert_c, page) + render_component(toast_c, page) + + # The alert is still present (waiting for Flutter's dismiss event) but + # its `open` is False. + assert alert_dialog in page._dialogs.controls + assert alert_dialog.open is False + # The snackbar was appended. + assert len(page._dialogs.controls) == 2 + snackbar = page._dialogs.controls[1] + assert snackbar.open is True + + # Dismiss patches the alert directly with open=False. + assert session.patch_calls == [(alert_dialog, {})] + # Show schedules the `_dialogs` list for update so the new snackbar + # entry is flushed to Flutter. + assert session.scheduled_updates == [page._dialogs] + + +def test_use_dialog_reopen_while_dismissing_appends_fresh_dialog(): + """Regression: if a new dialog is passed *while the previous one is + still dismissing* (client hasn't finished the pop animation so the old + dialog is still in `_dialogs.controls` with `open=False`), the hook + must append the new dialog as a fresh entry instead of reusing the + old one's `_i`. Otherwise Flutter's AlertDialogControl — still + holding `_open=True` from the dismissing one — sees + `open == True == lastOpen` and never re-runs `showDialog`, so the new + dialog is stuck off-screen until Flutter garbage-collects the old + route (or never). + """ + page, _ = create_page() + first = True + + def body(): + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("first" if first else "second"), + ) + ) + + component = Component(fn=body, args=(), kwargs={}) + + # Initial render — dialog #1 is open. + render_component(component, page) + first_dialog = page._dialogs.controls[0] + assert first_dialog.open is True + + # Simulate the server-side dismiss path used by this hook: flip the + # open flag but leave the dialog in `_dialogs.controls` (Flutter's + # dismiss animation owns the removal). + first_dialog.open = False + + # User opens a new dialog while #1 is still dismissing. + first = False + render_component(component, page) + + # Both dialogs coexist — dismissing + freshly showing — so they must + # have distinct `_i` values and the new one must be live and open. + assert first_dialog in page._dialogs.controls + assert first_dialog.open is False + assert len(page._dialogs.controls) == 2 + second_dialog = page._dialogs.controls[1] + assert second_dialog is not first_dialog + assert second_dialog._i != first_dialog._i + assert second_dialog.open is True + + +def test_use_dialog_sibling_rerender_emits_frozen_diff(): + """Regression: when a component re-renders with a fresh dialog instance + that has the same content, the hook must emit a *frozen* diff against + the previous dialog. The frozen path migrates `_i` from the previous + instance onto the new one (via `_migrate_state`), so Flutter sees the + same Control on both sides — preserving the dialog route, TextField + cursor, animation state, etc. + """ + page, session = create_page() + + def body(): + ft.use_dialog(ft.AlertDialog(title=ft.Text("Hello"))) + + component = Component(fn=body, args=(), kwargs={}) + render_component(component, page) + + first_dialog = page._dialogs.controls[0] + session.patch_calls.clear() + session.scheduled_updates.clear() + + # Sibling re-render: same component body, fresh dialog instance. + render_component(component, page) + + # Overlay list still has exactly one dialog at the same index. + assert len(page._dialogs.controls) == 1 + # Exactly one frozen diff call — against the previous dialog — so + # `_migrate_state` takes the `_i` off `first_dialog` onto the new + # instance. No separate `schedule_update` (the frozen patch is the + # only message). + assert len(session.patch_calls) == 1 + patched, kwargs = session.patch_calls[0] + assert patched is page._dialogs.controls[0] + assert kwargs.get("prev_control") is first_dialog + assert kwargs.get("frozen") is True + assert session.scheduled_updates == [] + + +def test_use_dialog_open_rerender_updates_live_dialog_content(): + """Regression: re-rendering with updated props/closures while the + dialog is open must propagate to the mounted overlay entry so the + live dialog sees the latest `disabled`, `on_click` closure, etc. + + The frozen diff both emits the field deltas (Dart side) and updates + the Python list entry to point at the fresh dialog (whose `_i` has + been migrated from the previous instance), so subsequent event + dispatch reaches the live closures. + """ + page, _session = create_page() + comment = "" + submitted: list[str] = [] + + def body(): + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("Compose"), + actions=[ + ft.TextButton( + "Save", + disabled=not comment.strip(), + on_click=lambda: submitted.append(comment), + ) + ], + ) + ) + + component = Component(fn=body, args=(), kwargs={}) + + render_component(component, page) + + first_dialog = page._dialogs.controls[0] + assert first_dialog.actions[0].disabled is True + + comment = "Ship it" + render_component(component, page) + + # Overlay still has exactly one dialog. The entry now points at the + # fresh instance whose closures reflect the latest render. + assert len(page._dialogs.controls) == 1 + mounted = page._dialogs.controls[0] + assert mounted.actions[0].disabled is False + mounted.actions[0].on_click() + assert submitted == ["Ship it"] + + +def test_use_dialog_rerender_preserves_dialogs_prev_lists_snapshot(): + """Regression: after a frozen-patch re-render swaps the dialog instance + in `_dialogs.controls[idx]`, `_dialogs.__prev_lists['controls']` must + keep pointing at the live list contents — not at the now-discarded + previous Python object. + + If it falls out of sync, a later `_dialogs.update()` triggered by an + unrelated caller (e.g. `page.show_dialog(SnackBar)` from a toast) + diffs the fresh list against the stale snapshot, sees different + `id()` for the same logical dialog, and emits a full REPLACE. On + Dart that creates a new Control with `_open` unset, the next build + re-enters the show branch and pushes a second DialogRoute on top of + the existing one, and subsequent `open=False` patches only close + the first — leaving the dialog stuck open with a double-dim barrier. + """ + page, _ = create_page() + + counter = 0 + + def body(): + ft.use_dialog(ft.AlertDialog(title=ft.Text(f"dialog #{counter}"))) + + component = Component(fn=body, args=(), kwargs={}) + + render_component(component, page) + mounted = page._dialogs.controls[0] + + # Simulate the MsgPack encoder having serialized `_dialogs` once, which + # is what populates `__prev_lists` on the real protocol path. Without + # that, the scenario the regression covers can't arise. + object.__setattr__( + page._dialogs, "__prev_lists", {"controls": page._dialogs.controls[:]} + ) + + # Frozen-patch re-render → the hook swaps in a fresh AlertDialog. + counter += 1 + render_component(component, page) + + swapped = page._dialogs.controls[0] + assert swapped is not mounted # instance was replaced + + prev_snapshot = getattr(page._dialogs, "__prev_lists")["controls"] + # The snapshot must track the live list. If it still holds the old + # Python object, a later `_dialogs.update()` will diff incorrectly. + assert prev_snapshot[0] is swapped + + +@pytest.mark.asyncio +async def test_use_dialog_dispatch_event_survives_reopen_after_sibling_rerender(): + @ft.observable + @dataclass + class DialogState: + toast: str | None = None + create_count: int = 0 + + state = DialogState() + state_context = ft.create_context(state) + + @ft.component + def SnackbarHost(): + s = ft.use_context(state_context) + ft.use_dialog( + ft.SnackBar( + content=ft.Text(s.toast), + on_dismiss=lambda e: setattr(s, "toast", None), + ) + if s.toast + else None + ) + return ft.Container(width=0, height=0) + + @ft.component + def VersionsHost(): + s = ft.use_context(state_context) + create_open, set_create_open = ft.use_state(False) + comment, set_comment = ft.use_state("") + + async def create(): + if not comment.strip(): + return + s.create_count += 1 + s.toast = f"Created {s.create_count}" + set_comment("") + set_create_open(False) + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Create version"), + actions=[ + ft.Button( + "Cancel", + on_click=lambda: set_create_open(False), + ), + ft.FilledButton( + "Create", + on_click=lambda: asyncio.create_task(create()), + ), + ], + on_dismiss=lambda: set_create_open(False), + ) + if create_open + else None + ) + + return ft.Column( + controls=[ + ft.FilledButton( + "Create version", + on_click=lambda: (set_comment("v"), set_create_open(True)), + ) + ] + ) + + @ft.component + def App(): + return state_context(state, lambda: [VersionsHost(), SnackbarHost()]) + + conn = _RecordingConnection() + conn.pubsubhub = PubSubHub() + session = Session(conn) + token = _context_page.set(session.page) + + try: + session.page.render(App) + session.get_page_patch() + await flush_async() + + outer = find_filled_button(session, "Create version") + await session.dispatch_event(outer._i, "click", None) + await flush_async() + assert crash_messages(conn) == [] + + inner = session.page._dialogs.controls[-1].actions[1] + await inner._trigger_event("click", None) + await flush_async() + assert crash_messages(conn) == [] + assert state.create_count == 1 + + outer = find_filled_button(session, "Create version") + await session.dispatch_event(outer._i, "click", None) + await flush_async() + assert crash_messages(conn) == [] + + inner = session.page._dialogs.controls[-1].actions[1] + await inner._trigger_event("click", None) + await flush_async() + assert crash_messages(conn) == [] + assert state.create_count == 2 + finally: + session.close() + await flush_async() + _context_page.reset(token) + + +@pytest.mark.asyncio +async def test_dispatch_event_recovers_live_control_when_index_stale(): + clicks: list[str] = [] + + conn = _RecordingConnection() + conn.pubsubhub = PubSubHub() + session = Session(conn) + + live_button = ft.FilledButton( + "Create version", on_click=lambda e: clicks.append("live") + ) + stale_button = ft.FilledButton( + "Create version", on_click=lambda e: clicks.append("stale") + ) + object.__setattr__(live_button, "_i", stale_button._i) + session.page.controls = [ft.Column(controls=[live_button])] + + token = _context_page.set(session.page) + try: + session.get_page_patch() + session.index[live_button._i] = stale_button + + await session.dispatch_event(live_button._i, "click", None) + await flush_async() + + assert clicks == ["live"] + assert crash_messages(conn) == [] + assert session.index[live_button._i] is live_button + finally: + session.close() + await flush_async() + _context_page.reset(token) + + +def test_prepare_dialog_does_not_store_callbacks_in_serialized_fields(): + page, _ = create_page() + dialog = ft.AlertDialog( + title=ft.Text("Hello"), + on_dismiss=lambda e: None, + ) + + page._prepare_dialog(dialog) + + encoded = configure_encode_object_for_msgpack(BaseControl)(dialog) + + assert encoded["on_dismiss"] is True + assert "_internals" not in encoded diff --git a/sdk/python/packages/flet/tests/test_validation.py b/sdk/python/packages/flet/tests/test_validation.py new file mode 100644 index 0000000000..583787da01 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_validation.py @@ -0,0 +1,800 @@ +import re +import warnings +from dataclasses import dataclass, field +from typing import Annotated, Optional + +import pytest + +from flet.utils.validation import ( + ClassRule, + V, + ValidationDeclarationError, + ValidationRules, + validate, +) + + +@dataclass +class _Visible: + visible: bool = True + + +def test_field_wrapper_and_class_rule_delegate_callbacks(): + """Verify `V.field()` and `ClassRule(...)` execute provided callbacks.""" + called: dict[str, object] = {} + + def check_field(ctrl, field_name, value): + called["field"] = (field_name, value, ctrl.marker) + + def check_control(ctrl): + called["control"] = ctrl.marker + + @dataclass + class Sample: + marker: str = "ok" + value: Annotated[int, V.field(check_field)] = 7 + __validation_rules__: ValidationRules = (ClassRule(check_control),) + + validate(Sample()) + + assert called["field"] == ("value", 7, "ok") + assert called["control"] == "ok" + + +def test_ensure_default_messages_for_named_and_lambda_predicates(): + """Check fallback `V.ensure()` error messages for named and lambda predicates.""" + + def always_false(_ctrl): + return False + + @dataclass + class NamedPredicateControl: + __validation_rules__: ValidationRules = (V.ensure(always_false),) + + with pytest.raises(ValueError, match="Validation failed: always_false"): + validate(NamedPredicateControl()) + + @dataclass + class LambdaPredicateControl: + __validation_rules__: ValidationRules = (V.ensure(lambda _ctrl: False),) + + with pytest.raises(ValueError, match="Validation failed."): + validate(LambdaPredicateControl()) + + +def test_ensure_uses_custom_message_and_allows_pass(): + """ + Confirm `V.ensure()` accepts passing values and emits callable custom messages. + """ + + @dataclass + class Sample: + ok: bool = True + name: str = "alpha" + __validation_rules__: ValidationRules = ( + V.ensure(lambda ctrl: ctrl.ok, message=lambda ctrl: f"{ctrl.name} failed"), + ) + + validate(Sample(ok=True)) + + with pytest.raises(ValueError, match="alpha failed"): + validate(Sample(ok=False)) + + +def test_deprecated_warns_when_field_is_set(): + """Ensure deprecated field rules emit a warning only for non-None values.""" + + @dataclass + class Sample: + old_value: Annotated[ + Optional[int], + V.deprecated("new_value", version="0.80.0", delete_version="0.90.0"), + ] = None + + validate(Sample(old_value=None)) + + with pytest.warns( + DeprecationWarning, + match=( + r"Sample\.old_value property is deprecated since version 0\.80\.0 " + r"and will be removed in version 0\.90\.0\. " + r"Use `new_value` instead\." + ), + ): + validate(Sample(old_value=3)) + + +def test_deprecated_warns_once_per_instance(): + """Verify repeated validation of one instance does not re-emit warnings.""" + + @dataclass + class Sample: + old_value: Annotated[ + Optional[int], V.deprecated("new_value", version="0.80.0") + ] = None + + sample = Sample(old_value=1) + with warnings.catch_warnings(record=True) as captured: + warnings.simplefilter("always", DeprecationWarning) + validate(sample) + validate(sample) + + deprecations = [w for w in captured if issubclass(w.category, DeprecationWarning)] + assert len(deprecations) == 1 + + +def test_deprecated_allows_custom_reason(): + """Confirm custom deprecation text overrides replacement-based default text.""" + + @dataclass + class Sample: + old_value: Annotated[ + Optional[int], + V.deprecated( + version="0.80.0", + reason="Use `new_value` for a wider range of values.", + ), + ] = None + + with pytest.warns( + DeprecationWarning, + match=re.escape( + "Sample.old_value property is deprecated since version 0.80.0. " + "Use `new_value` for a wider range of values." + ), + ): + validate(Sample(old_value=5)) + + +def test_deprecated_ignores_docs_reason_for_runtime_warning(): + """Ensure docs-specific reason text does not affect runtime warnings.""" + + @dataclass + class Sample: + old_value: Annotated[ + Optional[int], + V.deprecated( + "new_value", + version="0.80.0", + reason="Use plain runtime guidance.", + docs_reason="Use :attr:`new_value` instead.", + ), + ] = None + + with pytest.warns( + DeprecationWarning, + match=re.escape( + "Sample.old_value property is deprecated since version 0.80.0. " + "Use plain runtime guidance." + ), + ): + validate(Sample(old_value=5)) + + +def test_validate_suppress_repeated_errors_is_opt_in(): + """Ensure repeated validation errors are raised unless suppression is enabled.""" + + @dataclass + class Sample: + value: Annotated[int, V.gt(0.0)] = -1 + + with pytest.raises(ValueError, match="value must be strictly greater than 0.0"): + validate(Sample(value=-1)) + + with pytest.raises(ValueError, match="value must be strictly greater than 0.0"): + validate(Sample(value=-1)) + + +def test_validate_suppresses_repeated_identical_errors_per_instance(): + """Suppress the same ValueError on subsequent validations of one instance.""" + + @dataclass + class Sample: + value: Annotated[int, V.gt(0.0)] = -1 + + sample = Sample(value=-1) + + with pytest.raises(ValueError, match="value must be strictly greater than 0.0"): + validate(sample, suppress_repeated_errors=True) + + # Same validation error is suppressed on repeated calls for one instance. + validate(sample, suppress_repeated_errors=True) + + +def test_validate_suppression_resets_after_success(): + """A successful validation clears suppression so future repeats raise again.""" + + @dataclass + class Sample: + value: Annotated[int, V.gt(0.0)] = -1 + + sample = Sample(value=-1) + + with pytest.raises(ValueError, match="value must be strictly greater than 0.0"): + validate(sample, suppress_repeated_errors=True) + validate(sample, suppress_repeated_errors=True) + + sample.value = 1 + validate(sample, suppress_repeated_errors=True) + + sample.value = -1 + with pytest.raises(ValueError, match="value must be strictly greater than 0.0"): + validate(sample, suppress_repeated_errors=True) + + +def test_instance_of_supports_optional_none_and_expected_types(): + """ + Ensure `V.instance_of()` allows `None` when the field annotation is `Optional`. + """ + + @dataclass + class Sample: + value: Annotated[Optional[int], V.instance_of(int)] = None + + validate(Sample(value=None)) + validate(Sample(value=5)) + + +def test_instance_of_reports_default_type_errors(): + """Validate default type error formatting for `V.instance_of()` tuples.""" + + @dataclass + class Sample: + value: Annotated[int, V.instance_of((int, str, float))] = 0 + + with pytest.raises( + ValueError, + match="value must be of type int, str, or float, got ", + ): + validate(Sample(value=[])) # type: ignore[arg-type] + + +def test_instance_of_uses_custom_message_callable(): + """Verify `V.instance_of()` uses a callable custom error message.""" + + @dataclass + class Sample: + value: Annotated[int, V.instance_of(int, message=lambda *_: "wrong type")] = 0 # type: ignore[arg-type] + + with pytest.raises(ValueError, match="wrong type"): + validate(Sample(value="x")) # type: ignore[arg-type] + + +def test_visible_control_accepts_visible_and_optional_none(): + """Check `V.visible_control()` accepts visible controls and optional `None`.""" + + @dataclass + class OptionalSample: + child: Annotated[Optional[_Visible], V.visible_control()] = None + + validate(OptionalSample(child=None)) + validate(OptionalSample(child=_Visible(visible=True))) + + +def test_visible_control_fails_for_hidden_or_none_with_custom_message(): + """ + Ensure `V.visible_control()` rejects hidden/required-None values with custom text. + """ + + @dataclass + class RequiredSample: + child: Annotated[_Visible, V.visible_control(message="child invalid")] = field( + default_factory=_Visible + ) + + with pytest.raises(ValueError, match="child invalid"): + validate(RequiredSample(child=_Visible(visible=False))) + + with pytest.raises(ValueError, match="child invalid"): + validate(RequiredSample(child=None)) # type: ignore[arg-type] + + +def test_visible_controls_validates_min_count_and_default_messages(): + """ + Cover `V.visible_controls()` min-count validation and default failure messages. + """ + with pytest.raises( + ValidationDeclarationError, + match="min_count must be greater than or equal to 1, got 0", + ): + V.visible_controls(min_count=0) + + @dataclass + class OneRequired: + children: Annotated[list[_Visible], V.visible_controls(min_count=1)] = field( + default_factory=list + ) + + @dataclass + class TwoRequired: + children: Annotated[list[_Visible], V.visible_controls(min_count=2)] = field( + default_factory=list + ) + + with pytest.raises( + ValueError, + match="children must contain at least one visible Control, got 0", + ): + validate(OneRequired(children=[])) + + with pytest.raises( + ValueError, + match="children must contain at least 2 visible Controls, got 1", + ): + validate( + TwoRequired(children=[_Visible(visible=True), _Visible(visible=False)]) + ) + + with pytest.raises( + ValueError, + match="children must contain at least one visible Control, got 0", + ): + validate(OneRequired(children=123)) # type: ignore[arg-type] + + +def test_visible_controls_uses_custom_message_on_type_error_and_count_mismatch(): + """Ensure `V.visible_controls()` applies custom messages for all failure modes.""" + + @dataclass + class Sample: + children: Annotated[ + list[_Visible], V.visible_controls(min_count=2, message="bad children") + ] = field(default_factory=list) + + with pytest.raises(ValueError, match="bad children"): + validate(Sample(children=42)) # type: ignore[arg-type] + + with pytest.raises(ValueError, match="bad children"): + validate(Sample(children=[_Visible(True), _Visible(False)])) + + +def test_str_or_visible_control_allows_string_or_visible_control(): + """ + Verify `V.str_or_visible_control()` accepts only string or visible control values. + """ + + @dataclass + class Sample: + label: Annotated[object, V.str_or_visible_control()] + + validate(Sample(label="text")) + validate(Sample(label=_Visible(visible=True))) + + with pytest.raises(ValueError, match="label must be a string or a visible Control"): + validate(Sample(label=_Visible(visible=False))) + + +@pytest.mark.parametrize( + ("rule", "valid_value", "invalid_value", "error_message"), + [ + (V.gt(5), 6, 5, "value must be strictly greater than 5, got 5"), + (V.ge(5), 5, 4, "value must be greater than or equal to 5, got 4"), + (V.lt(5), 4, 5, "value must be less than 5, got 5"), + (V.le(5), 5, 6, "value must be less than or equal to 5, got 6"), + ( + V.between(2, 4), + 3, + 5, + "value must be between 2 and 4 inclusive, got 5", + ), + ], +) +def test_numeric_rules(rule, valid_value, invalid_value, error_message): + """Parametrically validate scalar comparison rules and their default messages.""" + + @dataclass + class Sample: + value: Annotated[int, rule] = valid_value + + validate(Sample(value=valid_value)) + with pytest.raises(ValueError, match=error_message): + validate(Sample(value=invalid_value)) + + +def test_numeric_rules_handle_optional_none_and_custom_message_for_required_none(): + """ + Verify scalar rules skip optional `None` and fail required `None` with custom text. + """ + + @dataclass + class OptionalSample: + value: Annotated[Optional[int], V.gt(0)] = None + + validate(OptionalSample(value=None)) + + @dataclass + class RequiredSample: + value: Annotated[int, V.gt(0, message="missing number")] = 1 + + with pytest.raises(ValueError, match="missing number"): + validate(RequiredSample(value=None)) # type: ignore[arg-type] + + +@pytest.mark.parametrize( + ("rule", "valid_value", "invalid_value", "error_message"), + [ + ( + V.factor_of(60), + -15, + 7, + "value must be a factor of 60, got 7", + ), + ( + V.multiple_of(-5), + -15, + 14, + "value must be a multiple of 5, got 14", + ), + ], +) +def test_divisibility_rules(rule, valid_value, invalid_value, error_message): + """Validate factor/multiple helpers and their default error messages.""" + + @dataclass + class Sample: + value: Annotated[int, rule] + + validate(Sample(value=valid_value)) + with pytest.raises(ValueError, match=re.escape(error_message)): + validate(Sample(value=invalid_value)) + + +def test_divisibility_rules_support_optional_none_and_custom_message(): + """Ensure divisibility rules honor optional-None inference and custom text.""" + + @dataclass + class OptionalSample: + value: Annotated[Optional[int], V.factor_of(60)] = None + + @dataclass + class RequiredSample: + value: Annotated[int, V.multiple_of(5, message="bad multiple")] + + validate(OptionalSample(value=None)) + + with pytest.raises(ValueError, match="bad multiple"): + validate(RequiredSample(value=6)) + + +def test_divisibility_rules_validate_builder_arguments(): + """Verify declaration-time validation for divisor/base arguments.""" + + with pytest.raises( + ValidationDeclarationError, match="base must be a non-zero integer" + ): + V.factor_of(0) + + with pytest.raises( + ValidationDeclarationError, match="divisor must be a non-zero integer" + ): + V.multiple_of(0) + + +@pytest.mark.parametrize( + ("rule", "valid_value", "invalid_value", "error_message"), + [ + (V.eq(5), 5, 4, "value must be equal to 5, got 4"), + (V.ne(5), 4, 5, "value must not be equal to 5, got 5"), + ( + V.one_of(("small", "medium", "large")), + "medium", + "x-large", + "value must be one of 'small', 'medium', or 'large', got 'x-large'", + ), + ], +) +def test_equality_and_membership_rules(rule, valid_value, invalid_value, error_message): + """Validate equality/membership rules and their default error messages.""" + + @dataclass + class Sample: + value: Annotated[object, rule] + + validate(Sample(value=valid_value)) + with pytest.raises(ValueError, match=re.escape(error_message)): + validate(Sample(value=invalid_value)) + + +def test_one_of_requires_non_empty_allowed_values(): + """Ensure `V.one_of()` rejects empty allowed-value collections.""" + with pytest.raises( + ValidationDeclarationError, + match="allowed_values must contain at least one value", + ): + V.one_of(()) + + +def test_or_rule_accepts_when_any_rule_passes_and_composes_default_error(): + """ + Verify `V.or_()` accepts if any nested rule passes and combines failures by default. + """ + + @dataclass + class Sample: + value: Annotated[int, V.or_(V.eq(-1), V.gt(0))] + + validate(Sample(value=-1)) + validate(Sample(value=2)) + + with pytest.raises( + ValueError, + match=re.escape( + "value must satisfy at least one of the allowed conditions: " + "value must be equal to -1, got 0; or " + "value must be strictly greater than 0, got 0" + ), + ): + validate(Sample(value=0)) + + +def test_or_rule_uses_custom_message_and_validates_arguments(): + """Ensure `V.or_()` supports custom messages and validates builder input.""" + + @dataclass + class Sample: + value: Annotated[int, V.or_(V.eq(1), V.eq(2), message="invalid choice")] + + with pytest.raises(ValueError, match="invalid choice"): + validate(Sample(value=3)) + + with pytest.raises( + ValidationDeclarationError, match="or_ requires at least one field rule" + ): + V.or_() + + with pytest.raises( + ValidationDeclarationError, match="or_ expects only FieldRule instances" + ): + V.or_(V.eq(1), "bad") # type: ignore[arg-type] + + +def test_non_empty_rule_default_messages_and_optional_none_inference(): + """ + Validate `V.non_empty()` behavior for empty values, type errors, + and optional `None`. + """ + + @dataclass + class RequiredSample: + value: Annotated[list[int], V.non_empty()] = field(default_factory=list) + + @dataclass + class OptionalSample: + value: Annotated[Optional[list[int]], V.non_empty()] = None + + with pytest.raises(ValueError, match="value must be non-empty"): + validate(RequiredSample(value=[])) + + with pytest.raises( + ValueError, + match=re.escape("value must be a non-empty sized value, got "), + ): + validate(RequiredSample(value=123)) # type: ignore[arg-type] + + validate(OptionalSample(value=None)) + + +def test_length_rules_default_messages_builder_checks_and_custom_message(): + """Cover length-rule defaults and builder constraints.""" + + with pytest.raises( + ValidationDeclarationError, + match="minimum must be greater than or equal to 0, got -1", + ): + V.length_ge(-1) + + with pytest.raises( + ValidationDeclarationError, + match="expected must be greater than or equal to 0, got -1", + ): + V.length_eq(-1) + + with pytest.raises( + ValidationDeclarationError, + match=re.escape("maximum must be greater than or equal to minimum (2), got 1"), + ): + V.length_between(2, 1) + + @dataclass + class MinLength: + value: Annotated[str, V.length_ge(2)] + + @dataclass + class BetweenLength: + value: Annotated[list[int], V.length_between(1, 2, message="length invalid")] + + @dataclass + class EqLength: + value: Annotated[str, V.length_eq(3)] + + validate(MinLength(value="ok")) + with pytest.raises( + ValueError, + match="value must have length greater than or equal to 2, got 1", + ): + validate(MinLength(value="x")) + + validate(EqLength(value="abc")) + with pytest.raises( + ValueError, + match="value must have length equal to 3, got 2", + ): + validate(EqLength(value="ab")) + + with pytest.raises(ValueError, match="length invalid"): + validate(BetweenLength(value=[])) + + with pytest.raises(ValueError, match="length invalid"): + validate(BetweenLength(value=123)) # type: ignore[arg-type] + + +@pytest.mark.parametrize( + ("rule", "valid_pair", "invalid_pair", "error_message"), + [ + ( + V.gt_field("other"), + (3, 2), + (2, 2), + "current (2) must be strictly greater than other (2)", + ), + ( + V.ge_field("other"), + (2, 2), + (1, 2), + "current (1) must be greater than or equal to other (2)", + ), + ( + V.lt_field("other"), + (1, 2), + (2, 2), + "current (2) must be strictly less than other (2)", + ), + ( + V.le_field("other"), + (2, 2), + (3, 2), + "current (3) must be less than or equal to other (2)", + ), + ], +) +def test_field_comparison_rules(rule, valid_pair, invalid_pair, error_message): + """Parametrically validate field-to-field comparison rules and default messages.""" + + @dataclass + class Sample: + current: Annotated[int, rule] = valid_pair[0] + other: int = valid_pair[1] + + validate(Sample(current=valid_pair[0], other=valid_pair[1])) + with pytest.raises(ValueError, match=re.escape(error_message)): + validate(Sample(current=invalid_pair[0], other=invalid_pair[1])) + + +def test_field_comparison_rules_skip_when_optional_side_is_none(): + """ + Ensure field comparison rules skip when either annotated optional side is `None`. + """ + + @dataclass + class CurrentOptional: + current: Annotated[Optional[int], V.gt_field("other")] + other: int + + @dataclass + class OtherOptional: + current: Annotated[int, V.gt_field("other")] + other: Optional[int] = None + + validate(CurrentOptional(current=None, other=3)) + validate(OtherOptional(current=5, other=None)) + + +def test_field_comparison_rules_use_custom_message_for_required_none(): + """ + Confirm field comparison rules use custom messages when required values are `None`. + """ + + @dataclass + class Sample: + current: Annotated[int, V.gt_field("other", message="comparison failed")] + other: int + + with pytest.raises(ValueError, match="comparison failed"): + validate(Sample(current=None, other=1)) # type: ignore[arg-type] + + +def test_validate_runs_field_rules_before_class_rules(): + """Verify field-level validation runs before class-level validation.""" + events: list[str] = [] + + def fail_field(_ctrl, _field_name, _value): + events.append("field") + raise ValueError("field failed") + + def run_control(_ctrl): + events.append("control") + + @dataclass + class Sample: + value: Annotated[int, V.field(fail_field)] = 1 + __validation_rules__: ValidationRules = (ClassRule(run_control),) + + with pytest.raises(ValueError, match="field failed"): + validate(Sample()) + + assert events == ["field"] + + +def test_validate_merges_mro_rules_in_base_to_child_order(): + """Ensure compiled validation rules follow MRO base-to-child ordering semantics.""" + + def field_rule(tag: str): + return V.field(lambda ctrl, _field_name, _value: ctrl.events.append(tag)) + + def control_rule(tag: str): + return ClassRule(lambda ctrl: ctrl.events.append(tag)) + + @dataclass + class Base: + events: list[str] = field(default_factory=list) + base_value: Annotated[int, field_rule("base_field")] = 1 + __validation_rules__: ValidationRules = (control_rule("base_control"),) + + @dataclass + class Child(Base): + child_value: Annotated[int, field_rule("child_field")] = 2 + __validation_rules__ = ( + control_rule("child_control"), + "not-a-rule", + ) + + child = Child() + validate(child) + + assert child.events == [ + "base_field", + "child_field", + "base_control", + "child_control", + ] + + +def test_validate_child_field_override_replaces_inherited_field_rules(): + """Ensure a child field declaration replaces inherited field-level rules.""" + + def field_rule(tag: str): + return V.field(lambda ctrl, _field_name, _value: ctrl.events.append(tag)) + + @dataclass + class Base: + events: list[str] = field(default_factory=list) + value: Annotated[int, field_rule("base_field")] = 1 + + @dataclass + class Child(Base): + value: Annotated[int, field_rule("child_field")] = 2 + + child = Child() + validate(child) + + assert child.events == ["child_field"] + + +def test_validate_child_plain_override_clears_inherited_field_comparison_rules(): + """Ensure non-annotated child overrides clear inherited field comparison rules.""" + + @dataclass + class Base: + current: Annotated[Optional[int], V.le_field("other")] = None + other: Annotated[Optional[int], V.ge_field("current")] = None + + @dataclass + class Child(Base): + current: None = field( + init=False, repr=False, compare=False, metadata={"skip": True} + ) + other: None = field( + init=False, repr=False, compare=False, metadata={"skip": True} + ) + + validate(Child()) diff --git a/sdk/python/packages/flet/tests/test_validation_benchmark.py b/sdk/python/packages/flet/tests/test_validation_benchmark.py new file mode 100644 index 0000000000..cdcdc0ad89 --- /dev/null +++ b/sdk/python/packages/flet/tests/test_validation_benchmark.py @@ -0,0 +1,128 @@ +""" +Benchmark: validation overhead in _before_update_safe(). + +Compares declarative Annotated + V.* validation (current) against +the imperative if/raise baseline that existed on main. + +Run with: pytest tests/test_validation_benchmark.py -s -m benchmark +""" + +import statistics +import time +import warnings + +import pytest + +import flet as ft + +WARMUP = 50 +ITERATIONS = 500 + + +def _make_controls(n: int) -> list: + """Create a realistic mix of controls with validated fields.""" + controls = [] + for i in range(n): + kind = i % 6 + if kind == 0: + controls.append(ft.Slider(value=0.5, min=0, max=1)) + elif kind == 1: + controls.append( + ft.RangeSlider(start_value=0.2, end_value=0.8, min=0, max=1) + ) + elif kind == 2: + controls.append(ft.TextField(label="test", max_length=100)) + elif kind == 3: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + controls.append(ft.Icon(ft.Icons.FAVORITE)) + elif kind == 4: + controls.append(ft.Text(value="hello", opacity=0.8)) + elif kind == 5: + controls.append(ft.Divider(thickness=2, height=10)) + return controls + + +def _bench_before_update(controls: list, iterations: int) -> list[float]: + """Time _before_update_safe() across all controls, repeated `iterations` times.""" + timings = [] + for _ in range(iterations): + start = time.perf_counter_ns() + for ctrl in controls: + ctrl._before_update_safe() + elapsed_us = (time.perf_counter_ns() - start) / 1_000 + timings.append(elapsed_us) + return timings + + +def _bench_construction(n: int, iterations: int) -> list[float]: + """Time control construction to check for __init__-time overhead.""" + timings = [] + for _ in range(iterations): + start = time.perf_counter_ns() + _make_controls(n) + elapsed_us = (time.perf_counter_ns() - start) / 1_000 + timings.append(elapsed_us) + return timings + + +def _report(label: str, timings: list[float], n_controls: int) -> dict: + med = statistics.median(timings) + p95 = sorted(timings)[int(len(timings) * 0.95)] + mean = statistics.mean(timings) + per_ctrl = med / n_controls if n_controls else 0 + print(f" {label}:") + print( + f" median={med:.1f}us mean={mean:.1f}us " + f"p95={p95:.1f}us per_ctrl={per_ctrl:.2f}us" + ) + return {"median": med, "p95": p95, "mean": mean, "per_ctrl": per_ctrl} + + +@pytest.mark.benchmark +class TestValidationBenchmark: + """ + Validation performance benchmarks. + + Baseline (main, imperative if/raise): + 50 controls: ~0.68 us/ctrl + 200 controls: ~1.04 us/ctrl + 500 controls: ~1.02 us/ctrl + + PR before optimization: + 50 controls: ~10.17 us/ctrl + 200 controls: ~10.25 us/ctrl + 500 controls: ~10.22 us/ctrl + + PR after optimization (cached _resolve_allow_none_for_field, + fast-path for non-None in _prepare_field_value, guarded reported.clear): + 50 controls: ~2.00 us/ctrl + 200 controls: ~2.34 us/ctrl + 500 controls: ~2.34 us/ctrl + """ + + @pytest.mark.parametrize("n_controls", [50, 200, 500]) + def test_before_update_safe(self, n_controls: int): + controls = _make_controls(n_controls) + + # Warmup + _bench_before_update(controls, WARMUP) + + timings = _bench_before_update(controls, ITERATIONS) + stats = _report( + f"_before_update_safe ({n_controls} controls)", timings, n_controls + ) + + # Soft assertion: flag if regression exceeds 5 us/ctrl + assert stats["per_ctrl"] < 5.0, ( + f"Validation overhead too high: {stats['per_ctrl']:.2f} us/ctrl " + f"(threshold: 5.0 us/ctrl)" + ) + + @pytest.mark.parametrize("n_controls", [50, 200, 500]) + def test_construction(self, n_controls: int): + # Warmup + _bench_construction(n_controls, WARMUP) + + timings = _bench_construction(n_controls, ITERATIONS) + _report(f"construction ({n_controls} controls)", timings, n_controls) diff --git a/sdk/python/packages/flet/tests/test_version.py b/sdk/python/packages/flet/tests/test_version.py new file mode 100644 index 0000000000..9d9622adbb --- /dev/null +++ b/sdk/python/packages/flet/tests/test_version.py @@ -0,0 +1,43 @@ +"""Regression tests for `flet.version.find_repo_root`.""" + +from pathlib import Path + +from flet.version import find_repo_root + + +def test_find_repo_root_regular_clone(tmp_path): + """A directory whose ancestor contains `.git` (as a directory, i.e. a + regular clone) should be detected as a repo root. + """ + (tmp_path / ".git").mkdir() + nested = tmp_path / "a" / "b" / "c" + nested.mkdir(parents=True) + + assert find_repo_root(nested) == tmp_path.resolve() + + +def test_find_repo_root_worktree(tmp_path): + """In a git worktree, `.git` is a regular file (`gitdir: ...`), not a + directory. `find_repo_root` must still detect the worktree root. + """ + worktree = tmp_path / "worktree" + worktree.mkdir() + (worktree / ".git").write_text( + "gitdir: /some/path/.git/worktrees/mybranch\n", encoding="utf-8" + ) + nested = worktree / "a" / "b" + nested.mkdir(parents=True) + + assert find_repo_root(nested) == worktree.resolve() + + +def test_find_repo_root_not_in_repo(tmp_path): + """If no `.git` entry is found up to the filesystem root, returns None.""" + nested = tmp_path / "a" / "b" + nested.mkdir(parents=True) + + # tmp_path itself may live under a repo on CI (the sandbox), so we can't + # assert None here unconditionally. We only assert that when it does find + # a root, the root is an ancestor of `nested` (sanity). + result = find_repo_root(nested) + assert result is None or Path(nested).resolve().is_relative_to(result) diff --git a/sdk/python/packages/flet/tests/test_view.py b/sdk/python/packages/flet/tests/test_view.py deleted file mode 100644 index a137baed86..0000000000 --- a/sdk/python/packages/flet/tests/test_view.py +++ /dev/null @@ -1,72 +0,0 @@ -from flet.core.protocol import Command - -import flet as ft - - -def test_instance_no_attrs_set(): - r = ft.View() - assert isinstance(r, ft.Control) - assert r._build_add_commands() == [ - Command( - indent=0, - name=None, - values=["view"], - attrs={}, - commands=[], - ) - ], "Test failed" - - -def test_horizontal_alignment_enum(): - r = ft.View(horizontal_alignment=ft.CrossAxisAlignment.STRETCH) - assert isinstance(r.horizontal_alignment, ft.CrossAxisAlignment) - assert isinstance(r._get_attr("horizontalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["horizontalalignment"] == "stretch" - - -def test_horizontal_alignment_str(): - r = ft.View(horizontal_alignment="center") - assert isinstance(r.horizontal_alignment, str) - assert isinstance(r._get_attr("horizontalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["horizontalalignment"] == "center" - - -def test_vertical_alignment_enum(): - r = ft.View(vertical_alignment=ft.MainAxisAlignment.CENTER) - assert isinstance(r.vertical_alignment, ft.MainAxisAlignment) - assert isinstance(r._get_attr("verticalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["verticalalignment"] == "center" - - -def test_vertical_alignment_str(): - r = ft.View(vertical_alignment="center") - assert isinstance(r.vertical_alignment, str) - assert isinstance(r._get_attr("verticalAlignment"), str) - cmd = r._build_add_commands() - assert cmd[0].attrs["verticalalignment"] == "center" - - -def test_scroll_enum(): - r = ft.View() - assert r.scroll is None - assert r._get_attr("scroll") is None - - r = ft.View(scroll=ft.ScrollMode.ALWAYS) - assert isinstance(r.scroll, ft.ScrollMode) - assert r.scroll == ft.ScrollMode.ALWAYS - assert r._get_attr("scroll") == "always" - - r = ft.View(scroll="adaptive") - assert isinstance(r.scroll, str) - assert r._get_attr("scroll") == "adaptive" - - r = ft.View(scroll=True) - assert isinstance(r.scroll, bool) - assert r._get_attr("scroll") == "auto" - - r = ft.View(scroll=False) - assert isinstance(r.scroll, bool) - assert r._get_attr("scroll") is None diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 10e005f0fd..8a805efb35 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -4,12 +4,29 @@ version = "0.1.0" description = "" authors = [{name = "Appveyor Systems Inc.", email ="hello@flet.dev"}] license = "Apache-2.0" -requires-python = ">=3.10,<3.14" +requires-python = ">=3.10,<3.15" dependencies = [ "flet", "flet-cli", "flet-desktop", - "flet-web" + "flet-web", + "flet-ads", + "flet-audio", + "flet-audio-recorder", + "flet-camera", + "flet-charts", + "flet-code-editor", + "flet-color-pickers", + "flet-datatable2", + "flet-flashlight", + "flet-geolocator", + "flet-lottie", + "flet-map", + "flet-permission-handler", + "flet-rive", + "flet-secure-storage", + "flet-video", + "flet-webview", ] [tool.uv.sources] @@ -17,34 +34,93 @@ flet = { workspace = true } flet-cli = { workspace = true } flet-desktop = { workspace = true } flet-web = { workspace = true } +flet-ads = { workspace = true } +flet-audio = { workspace = true } +flet-audio-recorder = { workspace = true } +flet-camera = { workspace = true } +flet-charts = { workspace = true } +flet-datatable2 = { workspace = true } +flet-flashlight = { workspace = true } +flet-geolocator = { workspace = true } +flet-lottie = { workspace = true } +flet-map = { workspace = true } +flet-permission-handler = { workspace = true } +flet-rive = { workspace = true } +flet-secure-storage = { workspace = true } +flet-video = { workspace = true } +flet-webview = { workspace = true } +flet-code-editor = { workspace = true } +flet-color-pickers = { workspace = true } [tool.uv.workspace] members = ["packages/*"] [dependency-groups] -dev = [ +test = [ "pytest >=7.2.0", + "pytest_asyncio >=1.1.0", +] +dev = [ "tomlkit >=0.11.6", "cryptography >=39.0.0", - "pyinstaller >=6.6.0", "pillow >=10.3.0", "pre-commit >=2.21.0", - "hypercorn >=0.14.4", - "gunicorn >=21.2.0", "pypi-cleanup==0.1.4", - "matplotlib >=3.10.1", - "plotly >=6.0.1", "pandas >=2.2.3", - "ruff>=0.11.7", + "numpy >=2.2.0", + "scikit-image >=0.25.2", + "ruff >=0.13.1", + "matplotlib>=3.10.7", + "plotly>=6.4.0", + "kaleido>=1.2.0", + { include-group = 'test' }, +] +docs-coverage = [ + "docstr-coverage >=2.3.2", ] +docs = [ + { include-group = 'docs-coverage' }, +] +all = [ + { include-group = 'dev' }, + { include-group = 'docs' }, +] + [tool.ruff] line-length = 88 target-version = "py39" fix = true show-fixes = true +exclude = [ + ".github" +] [tool.ruff.lint] +pydocstyle = { convention = 'google' } +isort = { known-first-party = [ + "flet", + "flet_cli", + "flet_desktop", + "flet_web", + "flet_ads", + "flet_audio", + "flet_audio_recorder", + "flet_camera", + "flet_charts", + "flet_color_pickers", + "flet_datatable2", + "flet_flashlight", + "flet_geolocator", + "flet_lottie", + "flet_map", + "flet_permission_handler", + "flet_rive", + "flet_secure_storage", + "flet_video", + "flet_webview" +] } +preview = true select = [ # pycodestyle "E", @@ -59,9 +135,17 @@ select = [ # isort "I" ] -preview = true [tool.ruff.format] quote-style = "double" indent-style = "space" line-ending = "auto" +docstring-code-format = true +docstring-code-line-length = 80 + + +[tool.pytest.ini_options] +pythonpath = ["."] + +[tool.setuptools.packages.find] +include = ["packages*"] diff --git a/sdk/python/templates/.gitignore b/sdk/python/templates/.gitignore new file mode 100644 index 0000000000..e60466c0ac --- /dev/null +++ b/sdk/python/templates/.gitignore @@ -0,0 +1,3 @@ +# Un-ignore files that parent .gitignore excludes +!lib/ +!*.manifest diff --git a/sdk/python/templates/app/.gitignore b/sdk/python/templates/app/.gitignore new file mode 100644 index 0000000000..e43b0f9889 --- /dev/null +++ b/sdk/python/templates/app/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/sdk/python/templates/app/app/cookiecutter.json b/sdk/python/templates/app/app/cookiecutter.json new file mode 100644 index 0000000000..6c048d1ec5 --- /dev/null +++ b/sdk/python/templates/app/app/cookiecutter.json @@ -0,0 +1,9 @@ +{ + "out_dir": "", + "project_name": "", + "flet_version": "", + "description": "", + "app_display_name": "{{cookiecutter.project_name.replace('-','_').split('_')|map('capitalize')|join}}", + "sep": "/", + "platform": "" +} diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore new file mode 100644 index 0000000000..adb31b9c42 --- /dev/null +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +*.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Flet +storage/ diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/README.md b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/README.md new file mode 100644 index 0000000000..9a0dc73ebc --- /dev/null +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/README.md @@ -0,0 +1,69 @@ +# {{ cookiecutter.app_display_name }} app + +## Run the app + +### uv + +Run as a desktop app: + +```bash +uv run flet run +``` + +Run as a web app: + +```bash +uv run flet run --web +``` + +For more details on running the app, refer to the [Getting Started Guide](https://flet.dev/docs/). + +## Build the app + +### Android + +```bash +flet build apk -v +``` + +For more details on building and signing `.apk` or `.aab`, refer to the [Android Packaging Guide](https://flet.dev/docs/publish/android/). + +### iOS + +```bash +flet build ipa -v +``` + +For more details on building and signing `.ipa`, refer to the [iOS Packaging Guide](https://flet.dev/docs/publish/ios/). + +### macOS + +```bash +flet build macos -v +``` + +For more details on building macOS package, refer to the [macOS Packaging Guide](https://flet.dev/docs/publish/macos/). + +### Linux + +```bash +flet build linux -v +``` + +For more details on building Linux package, refer to the [Linux Packaging Guide](https://flet.dev/docs/publish/linux/). + +### Windows + +```bash +flet build windows -v +``` + +For more details on building Windows package, refer to the [Windows Packaging Guide](https://flet.dev/docs/publish/windows/). + +### Web + +```bash +flet build web -v +``` + +For more details on building Web app, refer to the [Web Packaging Guide](https://flet.dev/docs/publish/web/). diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml new file mode 100644 index 0000000000..28ce4eda91 --- /dev/null +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/pyproject.toml @@ -0,0 +1,31 @@ +[project] +name = "{{cookiecutter.project_name}}" +version = "0.1.0" +description = "{{cookiecutter.description}}" +readme = "README.md" +requires-python = ">=3.10" +authors = [ + { name = "Flet developer", email = "you@example.com" } +] +dependencies = [ + "flet>={{cookiecutter.flet_version}}" +] + +[dependency-groups] +dev = [ + "flet-cli>={{cookiecutter.flet_version}}", + "flet-desktop>={{cookiecutter.flet_version}}", + "flet-web>={{cookiecutter.flet_version}}", +] + +[tool.flet] +{%- if cookiecutter.platform == "linux" %} +desktop_flavor = "light" # Change to "full" to use flet-audio and flet-video +{%- endif %} +org = "com.mycompany" +product = "{{cookiecutter.project_name}}" +company = "Flet" +copyright = "Copyright (C) 2023-2026 by Flet" + +[tool.flet.app] +path = "src" diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/assets/icon.png b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/assets/icon.png new file mode 100644 index 0000000000..bebc6d55c8 Binary files /dev/null and b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/assets/icon.png differ diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/assets/splash_android.png b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/assets/splash_android.png new file mode 100644 index 0000000000..8772f3fa14 Binary files /dev/null and b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/assets/splash_android.png differ diff --git a/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py new file mode 100644 index 0000000000..f8dda08180 --- /dev/null +++ b/sdk/python/templates/app/app/{{cookiecutter.out_dir}}/src/main.py @@ -0,0 +1,25 @@ +import flet as ft + + +def main(page: ft.Page): + counter = ft.Text("0", size=50, data=0) + + def increment_click(e): + counter.data += 1 + counter.value = str(counter.data) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=increment_click + ) + page.add( + ft.SafeArea( + expand=True, + content=ft.Container( + content=counter, + alignment=ft.Alignment.CENTER, + ), + ) + ) + + +ft.run(main) diff --git a/sdk/python/templates/app/extension/.gitignore b/sdk/python/templates/app/extension/.gitignore new file mode 100644 index 0000000000..3a0458a495 --- /dev/null +++ b/sdk/python/templates/app/extension/.gitignore @@ -0,0 +1,14 @@ +*.egg-info/ +develop-eggs/ +.DS_store + +# Python-generated files +__pycache__/ +*.py[oc] +build/ +dist/ +wheels/ +*.egg-info + +# Virtual environments +.venv diff --git a/sdk/python/templates/app/extension/cookiecutter.json b/sdk/python/templates/app/extension/cookiecutter.json new file mode 100644 index 0000000000..e09e58ddb4 --- /dev/null +++ b/sdk/python/templates/app/extension/cookiecutter.json @@ -0,0 +1,10 @@ +{ + "out_dir": "", + "project_name": "", + "project_name_underscore": "{{cookiecutter.project_name.replace('-','_')}}", + "flet_version": "", + "description": "", + "control_name": "{{cookiecutter.project_name.replace('-','_').split('_')|map('capitalize')|join}}", + "sep": "/", + "platform": "" +} diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/LICENSE b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/LICENSE new file mode 100644 index 0000000000..ba75c69f7f --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md new file mode 100644 index 0000000000..00c9c68e54 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/README.md @@ -0,0 +1,37 @@ +# {{cookiecutter.project_name}} +{{cookiecutter.control_name}} control for Flet + +## Installation + +Add dependency to `pyproject.toml` of your Flet app: + +* **Git dependency** + +Link to git repository: + +``` +dependencies = [ + "{{cookiecutter.project_name}} @ git+https://github.com/MyGithubAccount/{{cookiecutter.project_name}}", + "flet>={{cookiecutter.flet_version}}", +] +``` + +* **uv/pip dependency** + +If the package is published on pypi.org: + +``` +dependencies = [ + "{{cookiecutter.project_name}}", + "flet>={{cookiecutter.flet_version}}", +] +``` + +Build your app: +``` +flet build macos -v +``` + +## Documentation + +[Link to documentation](https://MyGithubAccount.github.io/{{cookiecutter.project_name}}/) diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/docs/index.md b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/docs/index.md new file mode 100644 index 0000000000..73e1e0a37b --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/docs/index.md @@ -0,0 +1,32 @@ +# Introduction + +{{cookiecutter.control_name}} for Flet. + +## Examples + +``` +import flet as ft + +from {{cookiecutter.project_name_underscore}} import {{cookiecutter.control_name}} + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + + ft.Container(height=150, width=300, alignment = ft.Alignment.CENTER, bgcolor=ft.Colors.PURPLE_200, content={{cookiecutter.control_name}}( + tooltip="My new {{cookiecutter.control_name}} Control tooltip", + value = "My new {{cookiecutter.control_name}} Flet Control", + ),), + + ) + + +ft.run(main) +``` + +## Classes + +[{{cookiecutter.control_name}}]({{cookiecutter.control_name}}.md) diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/docs/{{cookiecutter.control_name}}.md b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/docs/{{cookiecutter.control_name}}.md new file mode 100644 index 0000000000..0e443dd92c --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/docs/{{cookiecutter.control_name}}.md @@ -0,0 +1 @@ +:::src.{{cookiecutter.project_name_underscore}}.{{cookiecutter.project_name_underscore}} diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/.gitignore b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/.gitignore new file mode 100644 index 0000000000..2ad6aeb18d --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Flet +storage/ diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/README.md b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/README.md new file mode 100644 index 0000000000..903246d9e6 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/README.md @@ -0,0 +1,15 @@ +# Flet app + +A simple Flet app. + +To run the app when using `uv`: + +``` +uv run flet run [app_directory] +``` + +To run the app whenin using `pip`: + +``` +flet run [app_directory] +``` diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/pyproject.toml b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/pyproject.toml new file mode 100644 index 0000000000..e87ead6965 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/pyproject.toml @@ -0,0 +1,48 @@ +[project] +name = "{{cookiecutter.project_name}}-example" +version = "1.0.0" +description = "" +readme = "README.md" +requires-python = ">=3.10" +authors = [ + { name = "Flet developer", email = "you@example.com" } +] +dependencies = [ + "{{cookiecutter.project_name}}", + "flet>={{cookiecutter.flet_version}}", +] + +[dependency-groups] +dev = [ + "flet-cli>={{cookiecutter.flet_version}}", +{%- if cookiecutter.platform == "linux" %} + "flet-desktop-light>={{cookiecutter.flet_version}}", +{%- else %} + "flet-desktop>={{cookiecutter.flet_version}}", +{%- endif %} + "flet-web>={{cookiecutter.flet_version}}", +] + +[tool.flet] +# org name in reverse domain name notation, e.g. "com.mycompany". +# Combined with project.name to build bundle ID for iOS and Android apps +org = "com.mycompany" + +# project display name that is used as an app title on Android and iOS home screens, +# shown in window titles and about app dialogs on desktop. +product = "{{cookiecutter.project_name}}-example" + +# company name to display in about app dialogs +company = "Flet" + +# copyright text to display in about app dialogs +copyright = "Copyright (C) 2026 by MyCompany" + +[tool.flet.app] +path = "src" + +[tool.flet.dev_packages] +{{cookiecutter.project_name}} = "..{{cookiecutter.sep}}.." # relative path + +[tool.uv.sources] +{{cookiecutter.project_name}} = { path = "..{{cookiecutter.sep}}..{{cookiecutter.sep}}", editable = true } diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/src/main.py b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/src/main.py new file mode 100644 index 0000000000..02e127cf8e --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/examples/{{cookiecutter.project_name_underscore}}_example/src/main.py @@ -0,0 +1,20 @@ +import flet as ft + +from {{cookiecutter.project_name_underscore}} import {{cookiecutter.control_name}} + + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + + ft.Container(height=150, width=300, alignment = ft.Alignment.CENTER, bgcolor=ft.Colors.PURPLE_200, content={{cookiecutter.control_name}}( + tooltip="My new {{cookiecutter.control_name}} Control tooltip", + value = "My new {{cookiecutter.control_name}} Flet Control", + ),), + + ) + + +ft.run(main) diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/mkdocs.yml b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/mkdocs.yml new file mode 100644 index 0000000000..8a34495f61 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/mkdocs.yml @@ -0,0 +1,7 @@ +site_name: {{cookiecutter.control_name}} + +theme: + name: "material" + +plugins: + - mkdocstrings diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/pyproject.toml b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/pyproject.toml new file mode 100644 index 0000000000..7cae12d4bf --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/pyproject.toml @@ -0,0 +1,35 @@ +[project] +name = "{{cookiecutter.project_name}}" +version = "0.1.0" +description = "{{cookiecutter.control_name}} control for Flet" +readme = "README.md" +requires-python = ">=3.10" +authors = [ + { name = "Flet contributors", email = "you@example.com" } +] +dependencies = [ + "flet>={{cookiecutter.flet_version}}", +] + +[dependency-groups] +dev = [ + "mkdocs", + "mkdocs-material", + "mkdocstrings[python]" +] + +[project.urls] +Homepage = "https://mydomain.dev" +Documentation = "https://github.com/MyGithubAccount/{{cookiecutter.project_name}}" +Repository = "https://github.com/MyGithubAccount/{{cookiecutter.project_name}}" +Issues = "https://github.com/MyGithubAccount/{{cookiecutter.project_name}}/issues" + +[tool.setuptools.package-data] +"flutter.{{cookiecutter.project_name_underscore}}" = ["**/*"] + +[tool.setuptools] +license-files = [] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/.gitignore b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/.gitignore new file mode 100644 index 0000000000..93ae689a61 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/.gitignore @@ -0,0 +1,31 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +build/ +.flutter-plugins +.flutter-plugins-dependencies diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/src/extension.dart b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/src/extension.dart new file mode 100644 index 0000000000..ae4e571918 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/src/extension.dart @@ -0,0 +1,16 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/widgets.dart'; + +import '{{cookiecutter.project_name_underscore}}.dart'; + +class Extension extends FletExtension { + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "{{cookiecutter.control_name}}": + return {{cookiecutter.control_name}}Control(control: control); + default: + return null; + } + } +} diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/src/{{cookiecutter.project_name_underscore}}.dart b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/src/{{cookiecutter.project_name_underscore}}.dart new file mode 100644 index 0000000000..f36d6f2769 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/src/{{cookiecutter.project_name_underscore}}.dart @@ -0,0 +1,19 @@ +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; + +class {{cookiecutter.control_name}}Control extends StatelessWidget { + final Control control; + + const {{cookiecutter.control_name}}Control({ + super.key, + required this.control, + }); + + @override + Widget build(BuildContext context) { + String text = control.getString("value", "")!; + Widget myControl = Text(text); + + return LayoutControl(control: control, child: myControl); + } +} diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/{{cookiecutter.project_name_underscore}}.dart b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/{{cookiecutter.project_name_underscore}}.dart new file mode 100644 index 0000000000..86ed7d30cb --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/lib/{{cookiecutter.project_name_underscore}}.dart @@ -0,0 +1,3 @@ +library {{cookiecutter.project_name_underscore}}; + +export "src/extension.dart" show Extension; diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/pubspec.yaml b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/pubspec.yaml new file mode 100644 index 0000000000..57ed5e41fe --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/flutter/{{cookiecutter.project_name_underscore}}/pubspec.yaml @@ -0,0 +1,20 @@ +name: {{cookiecutter.project_name_underscore}} +description: Flet {{cookiecutter.control_name}} control +version: 0.1.0 +publish_to: none + +environment: + sdk: '>=3.3.0 <4.0.0' + flutter: ">=1.17.0" + +dependencies: + flet: ^{{cookiecutter.flet_version}} + flutter: + sdk: flutter + + # your dependencies here + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/.gitignore b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/.gitignore new file mode 100644 index 0000000000..c10c4529c6 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/.gitignore @@ -0,0 +1,131 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# VS Code +.vscode/ + +# mac +.DS_store diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/__init__.py b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/__init__.py new file mode 100644 index 0000000000..b3afa77ab6 --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/__init__.py @@ -0,0 +1 @@ +from {{cookiecutter.project_name_underscore}}.{{cookiecutter.project_name_underscore}} import {{cookiecutter.control_name}} diff --git a/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/{{cookiecutter.project_name_underscore}}.py b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/{{cookiecutter.project_name_underscore}}.py new file mode 100644 index 0000000000..41493d71bc --- /dev/null +++ b/sdk/python/templates/app/extension/{{cookiecutter.out_dir}}/src/{{cookiecutter.project_name_underscore}}/{{cookiecutter.project_name_underscore}}.py @@ -0,0 +1,12 @@ +from enum import Enum +from typing import Any, Optional + +import flet as ft + +@ft.control("{{cookiecutter.control_name}}") +class {{cookiecutter.control_name}}(ft.LayoutControl): + """ + {{cookiecutter.control_name}} Control description. + """ + + value: str diff --git a/sdk/python/templates/build/.gitattributes b/sdk/python/templates/build/.gitattributes new file mode 100644 index 0000000000..dfe0770424 --- /dev/null +++ b/sdk/python/templates/build/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/sdk/python/templates/build/.gitignore b/sdk/python/templates/build/.gitignore new file mode 100644 index 0000000000..e43b0f9889 --- /dev/null +++ b/sdk/python/templates/build/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/sdk/python/templates/build/cookiecutter.json b/sdk/python/templates/build/cookiecutter.json new file mode 100644 index 0000000000..405dfb8dfa --- /dev/null +++ b/sdk/python/templates/build/cookiecutter.json @@ -0,0 +1,35 @@ +{ + "out_dir": "", + "python_module_name": "main", + "project_name": "", + "project_name_slug": "", + "project_description": "", + "artifact_name": "{{ cookiecutter.project_name }}", + "product_name": "{{ cookiecutter.project_name }}", + "org_name": "{{ cookiecutter.org_name if 'org_name' in cookiecutter else 'com.flet' }}", + "company_name": "Your Company", + "copyright": "Copyright (c) 2026 Your Company", + "flutter": null, + "sep": "/", + "bundle_id": "{{ cookiecutter.bundle_id if 'bundle_id' in cookiecutter else cookiecutter.org_name + '.' + cookiecutter.project_name_slug }}", + "org_name_2": "{{ cookiecutter.bundle_id.rsplit('.', 1)[0] if 'bundle_id' in cookiecutter else cookiecutter.org_name if 'org_name' in cookiecutter else 'com.flet' }}", + "ios_provisioning_profile": "", + "ios_export_method": "", + "ios_signing_certificate": "", + "ios_export_options": {}, + "ios_team_id": "", + "package_name": "{{ cookiecutter.bundle_id.rsplit('.', 1)[-1].replace('-', '_') if 'bundle_id' in cookiecutter else cookiecutter.project_name }}", + "kotlin_dir": "{{ cookiecutter.org_name_2.replace('.', cookiecutter.sep) }}{{ cookiecutter.sep }}{{ cookiecutter.package_name }}{{ cookiecutter.sep }}", + "base_url": "/", + "route_url_strategy": "path", + "web_renderer": "canvaskit", + "use_color_emoji": false, + "pwa_background_color": "#FFFFFF", + "pwa_theme_color": "#0175C2", + "split_per_abi": false, + "no_cdn": false, + "no_wasm": false, + "options": null, + "pyproject": null, + "_extensions": ["cookiecutter_extensions.FletExtension"] +} diff --git a/sdk/python/templates/build/cookiecutter_extensions.py b/sdk/python/templates/build/cookiecutter_extensions.py new file mode 100644 index 0000000000..89719c3c83 --- /dev/null +++ b/sdk/python/templates/build/cookiecutter_extensions.py @@ -0,0 +1,22 @@ +from jinja2 import pass_context +from jinja2.ext import Extension + + +class FletExtension(Extension): + def __init__(self, environment): + super(FletExtension, self).__init__(environment) + environment.globals["get_pyproject"] = self.get_pyproject + + @pass_context + def get_pyproject(self, context, setting): + pyproject = context.get("cookiecutter", {}).get("pyproject", {}) + + if not setting: + return pyproject + + d = pyproject + for k in setting.split("."): + d = d.get(k) + if d is None: + return None + return d diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/.gitignore b/sdk/python/templates/build/{{cookiecutter.out_dir}}/.gitignore new file mode 100644 index 0000000000..fdb2b34ee2 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/.gitignore @@ -0,0 +1,46 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release + +/pubspec.lock diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/.metadata b/sdk/python/templates/build/{{cookiecutter.out_dir}}/.metadata new file mode 100644 index 0000000000..a778330bdc --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "d211f42860350d914a5ad8102f9ec32764dc6d06" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + - platform: android + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + - platform: ios + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + - platform: linux + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + - platform: macos + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + - platform: web + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + - platform: windows + create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/.vars b/sdk/python/templates/build/{{cookiecutter.out_dir}}/.vars new file mode 100644 index 0000000000..8f87770b2d --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/.vars @@ -0,0 +1,3 @@ +{% for key, value in cookiecutter.items() -%} +{{ key }}: {{ value }} +{% endfor %} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/README.md b/sdk/python/templates/build/{{cookiecutter.out_dir}}/README.md new file mode 100644 index 0000000000..6cb1666fbd --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/README.md @@ -0,0 +1,30 @@ +# {{ cookiecutter.product_name }} + +{{ cookiecutter.project_description }} + +## Template variables + +* `{{ cookiecutter.project_name }}` - project identifier (lowercase, no spaces, i.e. "snake_case") used for bundle IDs and package names. +* `{{ cookiecutter.project_description }}` - project description. +* `{{ cookiecutter.artifact_name }}` - executable or bundle name on disk. +* `{{ cookiecutter.product_name }}` - display name shown in window titles and about app dialogs. +* `{{ cookiecutter.org_name }}` - org name in reverse domain name notation, e.g. `com.mycompany.myproject`. +* `{{ cookiecutter.company_name }}` - the name of the company. +* `{{ cookiecutter.copyright }}` - the copyright notice. + +## Icons + +* iOS - `assets/icon_ios.png` (or any supported image format). Recommended minimum image size is 1024 px. Image should not be transparent (have alpha channel). Defaults to `assets/icon.png` with alpha-channel automatically removed. +* Android - `assets/icon_android.png` (or any supported image format). Recommended minimum image size is 192 px. Defaults to `assets/icon.png`. +* Web - `assets/icon_web.png` (or any supported image format). Recommended minimum image size is 512 px. Defaults to `assets/icon.png`. If `assets/favicon.png` file is provided it will be used unmodified (copied to `web/favicon.png`). +* Windows - `assets/icon_windows.png` (or any supported image format). ICO will be produced of 256 px size. Defaults to `assets/icon.png`. If `assets/icon_windows.ico` file is provided it will be just copied to `windows/runner/resources/app_icon.ico` unmodified. +* macOS - `assets/icon_macos.png` (or any supported image format). Recommended minimum image size is 1024 px. Defaults to `assets/icon.png`. + +## Splash screens + +* iOS (light) - `assets/splash_ios.png` (or any supported image format). Defaults to `assets/splash.png` and then `assets/icon.png`. +* iOS (dark) - `assets/splash_dark_ios.png` (or any supported image format). Defaults to light iOS splash, then to `assets/splash_dark.png`, then to `assets/splash.png` and then `assets/icon.png`. +* Android (light) - `assets/splash_android.png` (or any supported image format). Defaults to `assets/splash.png` and then `assets/icon.png`. +* Android (dark) - `assets/splash_dark_android.png` (or any supported image format). Defaults to light Android splash, then to `assets/splash_dark.png`, then to `assets/splash.png` and then `assets/icon.png`. +* Web (light) - `assets/splash_web.png` (or any supported image format). Defaults to `assets/splash.png` and then `assets/icon.png`. +* Web (dark) - `assets/splash_dark_web.png` (or any supported image format). Defaults to light web splash, then `assets/splash_dark.png`, then to `assets/splash.png` and then `assets/icon.png`. diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/analysis_options.yaml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/analysis_options.yaml new file mode 100644 index 0000000000..0d2902135c --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/.gitignore b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/.gitignore new file mode 100644 index 0000000000..6f568019d3 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts new file mode 100644 index 0000000000..0e25dd99ee --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/build.gradle.kts @@ -0,0 +1,103 @@ +import java.util.Properties + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +val localProperties = Properties().apply { + val localPropertiesFile = rootProject.file("local.properties") + if (localPropertiesFile.exists()) { + localPropertiesFile.inputStream().use { load(it) } + } +} + +val flutterVersionCode = localProperties.getProperty("flutter.versionCode")?.toIntOrNull() ?: 1 +val flutterVersionName = localProperties.getProperty("flutter.versionName") ?: "1.0" + +android { + namespace = "{{ cookiecutter.org_name_2 }}.{{ cookiecutter.package_name }}" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + packaging { + jniLibs { + useLegacyPackaging = true + keepDebugSymbols += listOf( + "*/arm64-v8a/libpython*.so", + "*/armeabi-v7a/libpython*.so", + "*/x86/libpython*.so", + "*/x86_64/libpython*.so", + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_17.toString() + } + + sourceSets["main"].java.srcDir("src/main/kotlin") + + {% set min_sdk_version = get_pyproject("tool.flet.android.min_sdk_version") %} + {% set target_sdk_version = get_pyproject("tool.flet.android.target_sdk_version") %} + + defaultConfig { + applicationId = "{{ cookiecutter.org_name_2 }}.{{ cookiecutter.package_name }}" + val resolvedMinSdk = {{ min_sdk_version if min_sdk_version else "flutter.minSdkVersion" }} + minSdk = resolvedMinSdk + val resolvedTargetSdk = {{ target_sdk_version if target_sdk_version else "flutter.targetSdkVersion" }} + targetSdk = resolvedTargetSdk + versionCode = flutterVersionCode + versionName = flutterVersionName + + println("Gradle build config:") + println(" minSdkVersion: $resolvedMinSdk") + println(" targetSdkVersion: $resolvedTargetSdk") + println(" versionCode: $flutterVersionCode") + println(" versionName: $flutterVersionName") + +// flet: split_per_abi {% if not cookiecutter.split_per_abi %} + ndk { + {% if cookiecutter.options.target_arch %} + abiFilters += listOf({% for arch in cookiecutter.options.target_arch %}"{{ arch }}"{% if not loop.last %}, {% endif %}{% endfor %}) + {% else %} + abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") + {% endif %} + } +// flet: end of split_per_abi {% endif %} + } + +// flet: android_signing {% if cookiecutter.options.android_signing %} + signingConfigs { + create("release") { + keyAlias = System.getenv("FLET_ANDROID_SIGNING_KEY_ALIAS") + keyPassword = System.getenv("FLET_ANDROID_SIGNING_KEY_PASSWORD") + storeFile = System.getenv("FLET_ANDROID_SIGNING_KEY_STORE")?.let { file(it) } + storePassword = System.getenv("FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD") + } + } +// flet: end of android_signing {% endif %} + + buildTypes { + release { +// flet: android_signing {% if cookiecutter.options.android_signing %} + signingConfig = signingConfigs.getByName("release") +// {% else %} + signingConfig = signingConfigs.getByName("debug") +// flet: end of android_signing {% endif %} + } + } +} + +flutter { + source = "../.." +} + +dependencies {} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/proguard-rules.pro b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/proguard-rules.pro new file mode 100644 index 0000000000..9d5bb305cb --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/proguard-rules.pro @@ -0,0 +1,2 @@ +-keep class com.flet.serious_python_android.** { *; } +-keepnames class * { *; } diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/debug/AndroidManifest.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000..b4c200d8d3 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/AndroidManifest.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..e81aae6543 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/kotlin/{{ cookiecutter.kotlin_dir }}/MainActivity.kt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/kotlin/{{ cookiecutter.kotlin_dir }}/MainActivity.kt new file mode 100644 index 0000000000..8ab8e074ba --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/kotlin/{{ cookiecutter.kotlin_dir }}/MainActivity.kt @@ -0,0 +1,5 @@ +package {{ cookiecutter.org_name_2 }}.{{ cookiecutter.package_name }} + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/drawable-v21/launch_background.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000000..f74085f3f6 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/drawable/launch_background.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000..304732f884 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..db77bb4b7b Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..17987b79bb Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..09d4391482 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..d5f1c8d34e Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..4d6372eebd Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/values-night/styles.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000..06952be745 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/values/styles.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000..cb1ef88056 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/xml/provider_paths.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/xml/provider_paths.xml new file mode 100644 index 0000000000..89a7e378cb --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/main/res/xml/provider_paths.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/profile/AndroidManifest.xml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000..b4c200d8d3 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/build.gradle.kts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/build.gradle.kts new file mode 100644 index 0000000000..dbee657bb5 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/build.gradle.kts @@ -0,0 +1,24 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = + rootProject.layout.buildDirectory + .dir("../../build") + .get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/gradle.properties b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/gradle.properties new file mode 100644 index 0000000000..fbee1d8cda --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/gradle.properties @@ -0,0 +1,2 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/gradle/wrapper/gradle-wrapper.properties b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..e4ef43fb98 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/settings.gradle.kts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/settings.gradle.kts new file mode 100644 index 0000000000..e095d7c1e5 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/android/settings.gradle.kts @@ -0,0 +1,27 @@ +pluginManagement { + val flutterSdkPath = + run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + settings.extra["flutterSdkPath"] = flutterSdkPath + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.11.1" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false +} + +include(":app") diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/images/favicon.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/images/favicon.png new file mode 100644 index 0000000000..d5bcf9e86d Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/images/favicon.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/images/icon.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/images/icon.png new file mode 100644 index 0000000000..bebc6d55c8 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/images/icon.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/.gitignore b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/.gitignore new file mode 100644 index 0000000000..7a7f9873ad --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/AppFrameworkInfo.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000000..9625e105df --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/Debug.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000000..ec97fc6f30 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/Release.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000000..c4855bfe20 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Podfile b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Podfile new file mode 100644 index 0000000000..4cd22bb57c --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Podfile @@ -0,0 +1,101 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +=begin +{% set permission_mapping = { + "PERMISSION_EVENTS": ["NSCalendarsUsageDescription", "NSCalendarWriteOnlyAccessUsageDescription"], + "PERMISSION_EVENTS_FULL_ACCESS": ["NSCalendarsFullAccessUsageDescription"], + "PERMISSION_REMINDERS": ["NSRemindersFullAccessUsageDescription"], + "PERMISSION_CONTACTS": ["NSContactsUsageDescription"], + "PERMISSION_CAMERA": ["NSCameraUsageDescription"], + "PERMISSION_MICROPHONE": ["NSMicrophoneUsageDescription"], + "PERMISSION_SPEECH_RECOGNIZER": ["NSSpeechRecognitionUsageDescription"], + "PERMISSION_PHOTOS": ["NSPhotoLibraryUsageDescription"], + "PERMISSION_PHOTOS_ADD_ONLY": ["NSPhotoLibraryAddUsageDescription"], + "PERMISSION_LOCATION": [ + "NSLocationUsageDescription", + "NSLocationAlwaysAndWhenInUseUsageDescription", + "NSLocationWhenInUseUsageDescription" + ], + "PERMISSION_LOCATION_WHENINUSE": ["NSLocationWhenInUseUsageDescription"], + "PERMISSION_MEDIA_LIBRARY": ["NSAppleMusicUsageDescription"], + "PERMISSION_SENSORS": ["NSMotionUsageDescription"], + "PERMISSION_BLUETOOTH": ["NSBluetoothAlwaysUsageDescription", "NSBluetoothPeripheralUsageDescription"], + "PERMISSION_APP_TRACKING_TRANSPARENCY": ["NSUserTrackingUsageDescription"], + "PERMISSION_CRITICAL_ALERTS": ["UNAuthorizationOptionCriticalAlert"], + "PERMISSION_ASSISTANT": ["NSSiriUsageDescription"] +} %} +=end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + # Ensure rive_native's setup script runs from the project root so pubspec.yaml is found in CI. + if target.name == 'rive_native' + target.shell_script_build_phases.each do |phase| + script = phase.shell_script + next unless script&.include?('rive_native:setup') + next if script.include?('PROJECT_ROOT="${SRCROOT}/../.."') + + phase.shell_script = script.sub( + "set -e\n", + "set -e\nPROJECT_ROOT=\"${SRCROOT}/../..\"\ncd \"$PROJECT_ROOT\"\n" + ) + end + end + + target.build_configurations.each do |config| + config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ + '$(inherited)', + + {%- for macro, plist_keys in permission_mapping.items() %} + {%- set ns = namespace(enabled=False) %} + {%- for key in plist_keys %} + {%- if key in cookiecutter.options.info_plist %} + {%- set ns.enabled = True %} + {%- endif %} + {%- endfor %} + {%- if ns.enabled %} + '{{ macro }}=1', + {%- endif %} + {%- endfor %} + ] + end + end +end diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.pbxproj b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..5307d392a3 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,644 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{ cookiecutter.artifact_name }}.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807E294A63A400263BE5 /* Frameworks */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = "{{ cookiecutter.artifact_name }}"; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; +{% if cookiecutter.ios_team_id %} + DEVELOPMENT_TEAM = "{{ cookiecutter.ios_team_id }}"; +{% endif %} +{% if cookiecutter.ios_signing_certificate %} + CODE_SIGN_IDENTITY = "{{ cookiecutter.ios_signing_certificate }}"; +{% endif %} +{% if cookiecutter.ios_provisioning_profile %} + PROVISIONING_PROFILE_SPECIFIER = "{{ cookiecutter.ios_provisioning_profile }}"; +{% endif %} + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}; + PRODUCT_NAME = "{{ cookiecutter.artifact_name }}"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{ cookiecutter.artifact_name }}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{{ cookiecutter.artifact_name }}"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{ cookiecutter.artifact_name }}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{{ cookiecutter.artifact_name }}"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{ cookiecutter.artifact_name }}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{{ cookiecutter.artifact_name }}"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; +{% if cookiecutter.ios_team_id %} + DEVELOPMENT_TEAM = "{{ cookiecutter.ios_team_id }}"; +{% endif %} +{% if cookiecutter.ios_signing_certificate %} + CODE_SIGN_IDENTITY = "{{ cookiecutter.ios_signing_certificate }}"; +{% endif %} +{% if cookiecutter.ios_provisioning_profile %} + PROVISIONING_PROFILE_SPECIFIER = "{{ cookiecutter.ios_provisioning_profile }}"; +{% endif %} + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}; + PRODUCT_NAME = "{{ cookiecutter.artifact_name }}"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; +{% if cookiecutter.ios_team_id %} + DEVELOPMENT_TEAM = "{{ cookiecutter.ios_team_id }}"; +{% endif %} +{% if cookiecutter.ios_signing_certificate %} + CODE_SIGN_IDENTITY = "{{ cookiecutter.ios_signing_certificate }}"; +{% endif %} +{% if cookiecutter.ios_provisioning_profile %} + PROVISIONING_PROFILE_SPECIFIER = "{{ cookiecutter.ios_provisioning_profile }}"; +{% endif %} + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}; + PRODUCT_NAME = "{{ cookiecutter.artifact_name }}"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..919434a625 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..724d08c8d9 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/contents.xcworkspacedata b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/AppDelegate.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000..b636303481 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..d36b1fab2d --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000..dc9ada4725 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000..7353c41ecf Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000..797d452e45 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000..6ed2d933e1 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000..4cd7b0099c Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000..fe730945a0 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000000..321773cd85 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000000..797d452e45 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000..502f463a9b Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000..0ec3034392 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000..0ec3034392 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000..e9f5fea27c Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000..84ac32ae7d Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000000..8953cba090 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000..0467bf12aa Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000000..0bedcf2fd4 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000..9da19eacad Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000000..b5b843ad3b --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Base.lproj/LaunchScreen.storyboard b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000..f2e259c7c9 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Base.lproj/Main.storyboard b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..f3c28516fb --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Info.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Info.plist new file mode 100644 index 0000000000..0efecc6c81 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Info.plist @@ -0,0 +1,100 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + {{ cookiecutter.product_name }} + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + {{ cookiecutter.project_name }} + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + FlutterDeepLinkingEnabled + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + {{ cookiecutter.options.deep_linking.host }} + CFBundleURLSchemes + + {{ cookiecutter.options.deep_linking.scheme }} + + + + + + {% macro render_value(value) -%} + {% if value is string -%} + {{ value }} + {% elif value is boolean -%} + <{{ "true" if value else "false" }}/> + {% elif value is integer -%} + {{ value }} + {% elif value is float -%} + {{ value }} + {% elif value is mapping -%} + + {{ render_dict(value) }} + + {% elif value is sequence -%} {# Support for lists/arrays #} + + {% for item in value -%} + {{ render_value(item) }} + {% endfor -%} + + {% endif -%} + {% endmacro -%} + {% macro render_dict(d) -%} + {% for key, value in d.items() -%} + {{ key }} + {{ render_value(value) }} + {% endfor -%} + {% endmacro -%} + {{ render_dict(cookiecutter.options.info_plist) }} + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Runner-Bridging-Header.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000000..308a2a560b --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/RunnerTests/RunnerTests.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..86a7c3b1b6 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/exportOptions.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/exportOptions.plist new file mode 100644 index 0000000000..87a970021f --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/ios/exportOptions.plist @@ -0,0 +1,53 @@ + + + + + method + {{ cookiecutter.ios_export_method }} + provisioningProfiles + + {{ cookiecutter.bundle_id }} + {{ cookiecutter.ios_provisioning_profile }} + + + {% if cookiecutter.ios_team_id %} + teamID + {{ cookiecutter.ios_team_id }} + {% endif %} + + {% if cookiecutter.ios_signing_certificate %} + signingCertificate + {{ cookiecutter.ios_signing_certificate }} + {% endif %} + + {% macro render_dict(d) -%} + {% for key, value in d.items() -%} + {{ key }} + {% if value is string -%} + {{ value }} + {% elif value is boolean -%} + <{{ "true" if value else "false" }}/> + {% elif value is mapping -%} + + {{ render_dict(value) }} + + {% elif value is sequence -%} {# Support for lists/arrays #} + + {% for item in value -%} + {% if item is string -%} + {{ item }} + {% elif item is boolean -%} + <{{ "true" if item else "false" }}/> + {% elif item is mapping -%} + + {{ render_dict(item) }} + + {% endif -%} + {% endfor -%} + + {% endif -%} + {% endfor -%} + {% endmacro -%} + {{ render_dict(cookiecutter.ios_export_options) }} + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart new file mode 100644 index 0000000000..a4adf44dcf --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/main.dart @@ -0,0 +1,386 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:ui'; + +import 'package:flet/flet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart' as path_provider; +import 'package:serious_python/serious_python.dart'; +import 'package:flutter_web_plugins/url_strategy.dart'; +import 'package:window_manager/window_manager.dart'; + +import "python.dart"; + +{% for dep in cookiecutter.flutter.dependencies %} +import 'package:{{ dep }}/{{ dep }}.dart' as {{ dep }}; +{% endfor %} + +/* +{% set show_boot_screen = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.boot_screen.show") + or get_pyproject("tool.flet.app.boot_screen.show") + or False %} +{% set boot_screen_message = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.boot_screen.message") + or get_pyproject("tool.flet.app.boot_screen.message") %} + +{% set show_startup_screen = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.startup_screen.show") + or get_pyproject("tool.flet.app.startup_screen.show") + or False %} +{% set startup_screen_message = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.startup_screen.message") + or get_pyproject("tool.flet.app.startup_screen.message") %} + +{% set hide_window_on_start = get_pyproject("tool.flet." ~ cookiecutter.options.config_platform ~ ".app.hide_window_on_start") + or get_pyproject("tool.flet.app.hide_window_on_start") %} + +show_boot_screen: {{ show_boot_screen }} +boot_screen_message: {{ boot_screen_message }} +show_startup_screen: {{ show_startup_screen }} +startup_screen_message: {{ startup_screen_message }} +hide_window_on_start: {{ hide_window_on_start }} +*/ + +const bool isRelease = bool.fromEnvironment('dart.vm.product'); + +const assetPath = "app/app.zip"; +const pythonModuleName = "{{ cookiecutter.python_module_name }}"; +final showAppBootScreen = bool.tryParse("{{ show_boot_screen }}".toLowerCase()) ?? false; +const appBootScreenMessage = '{{ boot_screen_message | default("Preparing the app for its first launch…", true) }}'; +final showAppStartupScreen = bool.tryParse("{{ show_startup_screen }}".toLowerCase()) ?? false; +const appStartupScreenMessage = '{{ startup_screen_message | default("Getting things ready…", true) }}'; +final hideWindowOnStart = bool.tryParse("{{ hide_window_on_start }}".toLowerCase()) ?? false; + +List extensions = [ +{% for dep in cookiecutter.flutter.dependencies %} +{{ dep }}.Extension(), +{% endfor %} +]; + +String outLogFilename = ""; + +// global vars +List _args = []; +String pageUrl = ""; +String assetsDir = ""; +String appDir = ""; +Map environmentVariables = Map.from(Platform.environment); + +void main(List args) async { + + FletDeepLinkingBootstrap.install(); + + _args = List.from(args); + + var devPageUrl = const String.fromEnvironment("FLET_PAGE_URL"); + if (devPageUrl != "") { + _args.addAll([devPageUrl, "--debug"]); + } + + for (var ext in extensions) { + ext.ensureInitialized(); + } + + runApp(FutureBuilder( + future: prepareApp(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + // OK - start Python program + return kIsWeb || (isDesktopPlatform() && _args.isNotEmpty) + ? FletApp( + pageUrl: pageUrl, + assetsDir: assetsDir, + showAppStartupScreen: showAppStartupScreen, + appStartupScreenMessage: appStartupScreenMessage, + extensions: extensions) + : FutureBuilder( + future: runPythonApp(args), + builder: + (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData || snapshot.hasError) { + // error or premature finish + return MaterialApp( + builder: (context, _) => ErrorScreen( + title: "Error running app", + text: snapshot.data ?? snapshot.error.toString()), + ); + } else { + // no result of error + return FletApp( + pageUrl: pageUrl, + assetsDir: assetsDir, + showAppStartupScreen: showAppStartupScreen, + appStartupScreenMessage: appStartupScreenMessage, + extensions: extensions); + } + }); + } else if (snapshot.hasError) { + // error + return MaterialApp( + builder: (context, _) => ErrorScreen( + title: "Error starting app", + text: snapshot.error.toString())); + } else { + // loading + return MaterialApp( + builder: (context, _) => showAppBootScreen ? const BootScreen() : const BlankScreen()); + } + })); +} + +Future prepareApp() async { + if (!_args.contains("--debug") && isRelease) { + // ignore: avoid_returning_null_for_void + debugPrint = (String? message, {int? wrapWidth}) => null; + } else { + _args.remove("--debug"); + } + + await setupDesktop(hideWindowOnStart: hideWindowOnStart); + + if (kIsWeb) { + // web mode - connect via HTTP + pageUrl = Uri.base.toString(); + var routeUrlStrategy = getFletRouteUrlStrategy(); + if (routeUrlStrategy == "path") { + usePathUrlStrategy(); + } + assetsDir = getAssetsDir(); + } else if (_args.isNotEmpty && isDesktopPlatform()) { + // developer mode + debugPrint("Flet app is running in Developer mode"); + pageUrl = _args[0]; + if (_args.length > 1) { + var pidFilePath = _args[1]; + debugPrint("Args contain a path to PID file: $pidFilePath}"); + var pidFile = await File(pidFilePath).create(); + await pidFile.writeAsString("$pid"); + } + if (_args.length > 2) { + assetsDir = _args[2]; + debugPrint("Args contain a path assets directory: $assetsDir}"); + } + } else { + // production mode + // extract app from asset + appDir = await extractAssetZip(assetPath, checkHash: true); + + // set current directory to app path + Directory.current = appDir; + + assetsDir = path.join(appDir, "assets"); + + // configure apps DATA and TEMP directories + WidgetsFlutterBinding.ensureInitialized(); + + var appTempPath = (await path_provider.getApplicationCacheDirectory()).path; + var appDataPath = + (await path_provider.getApplicationDocumentsDirectory()).path; + + if (defaultTargetPlatform != TargetPlatform.iOS && + defaultTargetPlatform != TargetPlatform.android) { + // append app name to the path and create dir + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + appDataPath = path.join(appDataPath, "flet", packageInfo.packageName); + if (!await Directory(appDataPath).exists()) { + await Directory(appDataPath).create(recursive: true); + } + } + + environmentVariables.putIfAbsent("FLET_APP_STORAGE_DATA", () => appDataPath); + environmentVariables.putIfAbsent("FLET_APP_STORAGE_TEMP", () => appTempPath); + + outLogFilename = path.join(appTempPath, "console.log"); + environmentVariables.putIfAbsent("FLET_APP_CONSOLE", () => outLogFilename); + + environmentVariables.putIfAbsent( + "FLET_PLATFORM", () => defaultTargetPlatform.name.toLowerCase()); + + if (defaultTargetPlatform == TargetPlatform.windows) { + // use TCP on Windows + var tcpPort = await getUnusedPort(); + pageUrl = "tcp://localhost:$tcpPort"; + environmentVariables.putIfAbsent("FLET_SERVER_PORT", () => tcpPort.toString()); + } else { + // use UDS on other platforms + pageUrl = "flet_$pid.sock"; + environmentVariables.putIfAbsent("FLET_SERVER_UDS_PATH", () => pageUrl); + } + } + + if (!kIsWeb && assetsDir.isNotEmpty) { + environmentVariables.putIfAbsent("FLET_ASSETS_DIR", () => assetsDir); + } + + return ""; +} + +Future runPythonApp(List args) async { + var argvItems = args.map((a) => "\"${a.replaceAll('"', '\\"')}\""); + var argv = "[${argvItems.isNotEmpty ? argvItems.join(',') : '""'}]"; + var script = pythonScript + .replaceAll("{outLogFilename}", outLogFilename.replaceAll("\\", "\\\\")) + .replaceAll('{module_name}', pythonModuleName) + .replaceAll('{argv}', argv); + + var completer = Completer(); + + ServerSocket outSocketServer; + String socketAddr = ""; + StringBuffer pythonOut = StringBuffer(); + + if (defaultTargetPlatform == TargetPlatform.windows) { + var tcpAddr = "127.0.0.1"; + outSocketServer = await ServerSocket.bind(tcpAddr, 0); + debugPrint( + 'Python output TCP Server is listening on port ${outSocketServer.port}'); + socketAddr = "$tcpAddr:${outSocketServer.port}"; + } else { + socketAddr = "stdout_$pid.sock"; + if (await File(socketAddr).exists()) { + await File(socketAddr).delete(); + } + outSocketServer = await ServerSocket.bind( + InternetAddress(socketAddr, type: InternetAddressType.unix), 0); + debugPrint('Python output Socket Server is listening on $socketAddr'); + } + + environmentVariables.putIfAbsent("FLET_PYTHON_CALLBACK_SOCKET_ADDR", () => socketAddr); + + void closeOutServer() async { + outSocketServer.close(); + + int exitCode = int.tryParse(pythonOut.toString().trim()) ?? 0; + + if (exitCode == errorExitCode) { + var out = ""; + if (await File(outLogFilename).exists()) { + out = await File(outLogFilename).readAsString(); + } + completer.complete(out); + } else { + exit(exitCode); + } + } + + outSocketServer.listen((client) { + debugPrint( + 'Connection from: ${client.remoteAddress.address}:${client.remotePort}'); + client.listen((data) { + var s = String.fromCharCodes(data); + pythonOut.write(s); + }, onError: (error) { + client.close(); + closeOutServer(); + }, onDone: () { + client.close(); + closeOutServer(); + }); + }); + + // run python async + SeriousPython.runProgram(path.join(appDir, "$pythonModuleName.pyc"), + script: script, environmentVariables: environmentVariables); + + // wait for client connection to close + return completer.future; +} + +class ErrorScreen extends StatelessWidget { + final String title; + final String text; + + const ErrorScreen({super.key, required this.title, required this.text}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Container( + padding: const EdgeInsets.all(8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + title, + style: Theme.of(context).textTheme.titleMedium, + ), + TextButton.icon( + onPressed: () { + Clipboard.setData(ClipboardData(text: text)); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Copied to clipboard')), + ); + }, + icon: const Icon( + Icons.copy, + size: 16, + ), + label: const Text("Copy"), + ) + ], + ), + Expanded( + child: SingleChildScrollView( + child: SelectableText(text, + style: Theme.of(context).textTheme.bodySmall), + )) + ], + ), + )), + ); + } +} + +class BootScreen extends StatelessWidget { + const BootScreen({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox( + width: 30, + height: 30, + child: CircularProgressIndicator(strokeWidth: 3), + ), + const SizedBox( + height: 10, + ), + Text(appBootScreenMessage, style: Theme.of(context).textTheme.bodySmall,) + ], + ), + ), + ); + } +} + +class BlankScreen extends StatelessWidget { + const BlankScreen({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return const Scaffold( + body: SizedBox.shrink(), + ); + } +} + +Future getUnusedPort() { + return ServerSocket.bind("127.0.0.1", 0).then((socket) { + var port = socket.port; + socket.close(); + return port; + }); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart new file mode 100644 index 0000000000..770dff1818 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/lib/python.dart @@ -0,0 +1,104 @@ +const errorExitCode = 100; + +const pythonScript = """ +import os, runpy, socket, sys, traceback + +# fix for cryptography package +os.environ["CRYPTOGRAPHY_OPENSSL_NO_LEGACY"] = "1" + +# fix for: https://github.com/flet-dev/serious-python/issues/85#issuecomment-2065000974 +os.environ["OPENBLAS_NUM_THREADS"] = "1" + +def initialize_ctypes(): + import ctypes.util + import os + import pathlib + import sys + + android_native_lib_dir = os.getenv("ANDROID_NATIVE_LIBRARY_DIR") + + def find_library_override_imp(name: str): + if name is None: + return None + if pathlib.Path(name).exists(): + return name + if sys.platform == "ios": + for lf in [ + f"Frameworks/{name}.framework/{name}", + f"Frameworks/lib{name}.framework/lib{name}", + ]: + lib_path = pathlib.Path(sys.executable).parent.joinpath(lf) + if lib_path.exists(): + return str(lib_path) + elif android_native_lib_dir: + for lf in [f"lib{name}.so", f"{name}.so", name]: + lib_path = pathlib.Path(android_native_lib_dir).joinpath(lf) + if lib_path.exists(): + return str(lib_path) + return None + + find_library_original = ctypes.util.find_library + + def find_library_override(name): + return find_library_override_imp(name) or find_library_original(name) + + ctypes.util.find_library = find_library_override + + CDLL_init_original = ctypes.CDLL.__init__ + + def CDLL_init_override(self, name, *args, **kwargs): + CDLL_init_original( + self, find_library_override_imp(name) or name, *args, **kwargs + ) + + ctypes.CDLL.__init__ = CDLL_init_override + +initialize_ctypes() + +out_file = open("{outLogFilename}", "w+", buffering=1) + +callback_socket_addr = os.getenv("FLET_PYTHON_CALLBACK_SOCKET_ADDR") +if ":" in callback_socket_addr: + addr, port = callback_socket_addr.split(":") + callback_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + callback_socket.connect((addr, int(port))) +else: + callback_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + callback_socket.connect(callback_socket_addr) + +sys.stdout = sys.stderr = out_file + +def flet_exit(code=0): + callback_socket.sendall(str(code).encode()) + out_file.close() + callback_socket.close() + +sys.exit = flet_exit + +ex = None +try: + import certifi + + os.environ["REQUESTS_CA_BUNDLE"] = certifi.where() + os.environ["SSL_CERT_FILE"] = certifi.where() + + if os.getenv("FLET_PLATFORM") == "android": + import ssl + + def create_default_context( + purpose=ssl.Purpose.SERVER_AUTH, *, cafile=None, capath=None, cadata=None + ): + return ssl.create_default_context( + purpose=purpose, cafile=certifi.where(), capath=capath, cadata=cadata + ) + + ssl._create_default_https_context = create_default_context + + sys.argv = {argv} + runpy.run_module("{module_name}", run_name="__main__") +except Exception as e: + ex = e + traceback.print_exception(e) + +sys.exit(0 if ex is None else 100) +"""; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/.gitignore b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/.gitignore new file mode 100644 index 0000000000..d3896c9844 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt new file mode 100644 index 0000000000..c72838044f --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/CMakeLists.txt @@ -0,0 +1,170 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the application target. The on-disk name is set as OUTPUT_NAME to keep +# Flutter tooling behavior intact. +set(BINARY_NAME "{{ cookiecutter.project_name }}") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "{{ cookiecutter.bundle_id }}") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror -Wno-unused-variable -Wno-unused-function) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + OUTPUT_NAME "{{ cookiecutter.artifact_name }}" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + +# Link mimalloc when media_kit_libs_linux exposes it. This must happen after +# generated plugins are included so MIMALLOC_LIB is initialized. +# mimalloc.o references pthread_*, so pair it with Threads::Threads — modern +# ld --as-needed won't pull libpthread in transitively through other DSOs. +if(MIMALLOC_LIB) + find_package(Threads REQUIRED) + target_link_libraries(${BINARY_NAME} PRIVATE ${MIMALLOC_LIB} Threads::Threads) +endif() + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Link bundled libraries from plugins into main executable to enable dlopen +# with only library name. +# Will NOT be needed once: https://github.com/flutter/engine/pull/28525 lands in Flutter channel we are using +# Alternative approach is to update plugin's RUNPATH before packaging: +# chrpath -r \$ORIGIN ./build/linux/arm64/release/bundle/lib/libserious_python_linux_plugin.so +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + if(${plugin}_bundled_libraries) + target_link_libraries( + ${BINARY_NAME} + PRIVATE + ${${plugin}_bundled_libraries} + ) + endif() +endforeach(plugin) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/CMakeLists.txt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000000..d5bd01648a --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..bbb2d0116e --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,35 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) record_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); + record_linux_plugin_register_with_registrar(record_linux_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); + g_autoptr(FlPluginRegistrar) serious_python_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "SeriousPythonLinuxPlugin"); + serious_python_linux_plugin_register_with_registrar(serious_python_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); + g_autoptr(FlPluginRegistrar) window_to_front_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin"); + window_to_front_plugin_register_with_registrar(window_to_front_registrar); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..e0f0a47bc0 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..29205a3f7e --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/flutter/generated_plugins.cmake @@ -0,0 +1,29 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + record_linux + screen_retriever_linux + serious_python_linux + url_launcher_linux + window_manager + window_to_front +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc new file mode 100644 index 0000000000..e7c5c54370 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc new file mode 100644 index 0000000000..633f33c6dc --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.cc @@ -0,0 +1,124 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "{{ cookiecutter.product_name }}"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "{{ cookiecutter.product_name }}"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_realize(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.h new file mode 100644 index 0000000000..72271d5e41 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/.gitignore b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/.gitignore new file mode 100644 index 0000000000..746adbb6b9 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/Flutter-Debug.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000000..4b81f9b2d2 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/Flutter-Release.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000000..5caa9d1579 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000000..adf3563a93 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,30 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import package_info_plus +import path_provider_foundation +import record_darwin +import screen_retriever_macos +import serious_python_darwin +import shared_preferences_foundation +import url_launcher_macos +import wakelock_plus +import window_manager +import window_to_front + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) + ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) + SeriousPythonPlugin.register(with: registry.registrar(forPlugin: "SeriousPythonPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) + WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) + WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Podfile b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Podfile new file mode 100644 index 0000000000..325d6aea0e --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Podfile @@ -0,0 +1,56 @@ +platform :osx, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + # Ensure rive_native's setup script runs from the project root so pubspec.yaml is found in CI. + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + next unless target.name == 'rive_native' + + target.shell_script_build_phases.each do |phase| + script = phase.shell_script + next unless script&.include?('rive_native:setup') + next if script.include?('PROJECT_ROOT="${SRCROOT}/../.."') + + phase.shell_script = script.sub( + "set -e\n", + "set -e\nPROJECT_ROOT=\"${SRCROOT}/../..\"\ncd \"$PROJECT_ROOT\"\n" + ) + end + end +end diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..bb413260d2 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,729 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( +{% if 'flet_rive' in cookiecutter.flutter.dependencies %} + A1B2C3D4E5F60718293A4B5C /* Rive Native Setup */, +{% endif %} + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* {{ cookiecutter.artifact_name }}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{ cookiecutter.artifact_name }}.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* {{ cookiecutter.artifact_name }}.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* {{ cookiecutter.artifact_name }}.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ +{% if 'flet_rive' in cookiecutter.flutter.dependencies %} + A1B2C3D4E5F60718293A4B5C /* Rive Native Setup */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Rive Native Setup"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\nPROJECT_ROOT=\"${PROJECT_DIR}/..\"\ncd \"$PROJECT_ROOT\"\nDART_BIN=\"${FLUTTER_ROOT}/bin/dart\"\nif [ ! -x \"$DART_BIN\" ]; then\n DART_BIN=\"$(command -v dart || true)\"\nfi\nif [ -z \"$DART_BIN\" ]; then\n echo \"error: dart not found; cannot run rive_native:setup\" >&2\n exit 1\nfi\necho \"Running rive_native setup for macos...\"\n\"$DART_BIN\" run rive_native:setup --verbose --clean --platform macos\n"; + }; +{% endif %} + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{ cookiecutter.artifact_name }}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{{ cookiecutter.artifact_name }}"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{ cookiecutter.artifact_name }}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{{ cookiecutter.artifact_name }}"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }}.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{ cookiecutter.artifact_name }}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{{ cookiecutter.artifact_name }}"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000..0a5b27e97f --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcworkspace/contents.xcworkspacedata b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..1d526a16ed --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000000..b3c1761412 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..a2ec33f19f --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000..82b6f9d9a3 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000..13b35eba55 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000..0a3f5fa40f Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000000..bdb57226d5 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000000..f083318e09 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000000..326c0e72c9 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000..2f1632cfdd Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Base.lproj/MainMenu.xib b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000000..b10048093b --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/AppInfo.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000000..1f4f8510e2 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's bundle name on disk. +PRODUCT_NAME = {{ cookiecutter.artifact_name }} + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = {{ cookiecutter.bundle_id }} + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = {{ cookiecutter.copyright }}. All rights reserved. diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Debug.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000000..36b0fd9464 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Release.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000000..dff4f49561 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Warnings.xcconfig b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000000..42bcbf4780 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/DebugProfile.entitlements b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000000..479c845309 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,34 @@ + + + + + {% macro render_value(value) -%} + {% if value is string -%} + {{ value }} + {% elif value is boolean -%} + <{{ "true" if value else "false" }} /> + {% elif value is integer -%} + {{ value }} + {% elif value is float -%} + {{ value }} + {% elif value is mapping -%} + + {{ render_dict(value) }} + + {% elif value is sequence -%} + + {% for item in value -%} + {{ render_value(item) }} + {% endfor -%} + + {% endif -%} + {% endmacro -%} + {% macro render_dict(d) -%} + {% for key, value in d.items() -%} + {{ key }} + {{ render_value(value) }} + {% endfor -%} + {% endmacro -%} + {{ render_dict(cookiecutter.options.macos_entitlements) }} + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Info.plist b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Info.plist new file mode 100644 index 0000000000..7478f18f4e --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Info.plist @@ -0,0 +1,63 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDisplayName + {{ cookiecutter.product_name }} + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + {% macro render_value(value) -%} + {% if value is string -%} + {{ value }} + {% elif value is boolean -%} + <{{ "true" if value else "false" }}/> + {% elif value is integer -%} + {{ value }} + {% elif value is float -%} + {{ value }} + {% elif value is mapping -%} + + {{ render_dict(value) }} + + {% elif value is sequence -%} {# Support for lists/arrays #} + + {% for item in value -%} + {{ render_value(item) }} + {% endfor -%} + + {% endif -%} + {% endmacro -%} + {% macro render_dict(d) -%} + {% for key, value in d.items() -%} + {{ key }} + {{ render_value(value) }} + {% endfor -%} + {% endmacro -%} + {{ render_dict(cookiecutter.options.info_plist) }} + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/MainFlutterWindow.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000000..319d00230f --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,21 @@ +import Cocoa +import FlutterMacOS +import window_manager + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } + + override public func order(_ place: NSWindow.OrderingMode, relativeTo otherWin: Int) { + super.order(place, relativeTo: otherWin) + hiddenWindowAtLaunch() + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Release.entitlements b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Release.entitlements new file mode 100644 index 0000000000..479c845309 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/Runner/Release.entitlements @@ -0,0 +1,34 @@ + + + + + {% macro render_value(value) -%} + {% if value is string -%} + {{ value }} + {% elif value is boolean -%} + <{{ "true" if value else "false" }} /> + {% elif value is integer -%} + {{ value }} + {% elif value is float -%} + {{ value }} + {% elif value is mapping -%} + + {{ render_dict(value) }} + + {% elif value is sequence -%} + + {% for item in value -%} + {{ render_value(item) }} + {% endfor -%} + + {% endif -%} + {% endmacro -%} + {% macro render_dict(d) -%} + {% for key, value in d.items() -%} + {{ key }} + {{ render_value(value) }} + {% endfor -%} + {% endmacro -%} + {{ render_dict(cookiecutter.options.macos_entitlements) }} + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/RunnerTests/RunnerTests.swift b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000..5418c9f539 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml b/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml new file mode 100644 index 0000000000..8046108d96 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/pubspec.yaml @@ -0,0 +1,134 @@ +name: '{{ cookiecutter.project_name }}' +description: '{{ cookiecutter.project_description }}' +publish_to: 'none' + +version: 1.0.0+1 + +environment: + sdk: '>=3.1.5 <4.0.0' + +dependencies: + flutter: + sdk: flutter + flutter_web_plugins: + sdk: flutter + + cupertino_icons: ^1.0.8 + + flet: + path: ../../../../../packages/flet + serious_python: 1.0.0 + + package_info_plus: ^9.0.0 + path_provider: ^2.1.4 + path: ^1.9.0 + window_manager: ^0.5.1 + +# {% if 'flet_geolocator' in cookiecutter.flutter.dependencies %} +# geolocator: ^12.0.0 +# geolocator_android: ^4.6.0 +# {% endif %} + +dependency_overrides: + flet: + path: ../../../../../packages/flet + device_info_plus: 12.3.0 # remove that in May, 2026 once CI moved to macOS 26 + connectivity_plus: 7.0.0 # remove that in May, 2026 once CI moved to macOS 26 + +dev_dependencies: + flutter_launcher_icons: ^0.14.1 + flutter_native_splash: ^2.4.1 + flutter_lints: ^2.0.0 + +flutter: + + uses-material-design: true + + assets: + - app/app.zip + - app/app.zip.hash + +# dart run flutter_launcher_icons +flutter_launcher_icons: + image_path: "images/icon.png" + + android: true + image_path_android: "images/icon.png" + adaptive_icon_background: '#ffffff' + adaptive_icon_foreground: images/icon.png + + ios: true + image_path_ios: "images/icon.png" + remove_alpha_ios: true + + web: + generate: true + image_path: "images/icon.png" + windows: + generate: true + image_path: "images/icon.png" + icon_size: 256 + macos: + generate: true + image_path: "images/icon.png" + +# dart run flutter_native_splash:create +flutter_native_splash: + # color or background_image is the only required parameter. Use color to set the background + # of your splash screen to a solid color. Use background_image to set the background of your + # splash screen to a png image. This is useful for gradients. The image will be stretch to the + # size of the app. Only one parameter can be used, color and background_image cannot both be set. + color: "#ffffff" + + # The image parameter allows you to specify an image used in the splash screen. It must be a + # png file and should be sized for 4x pixel density. + image: "images/icon.png" + + # The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background + # and image when the device is in dark mode. If they are not specified, the app will use the + # parameters from above. If the image_dark parameter is specified, color_dark or + # background_image_dark must be specified. color_dark and background_image_dark cannot both be + # set. + color_dark: "#222222" + #background_image_dark: "assets/dark-background.png" + image_dark: "images/icon.png" + #branding_dark: assets/dart_dark.png + + # Android 12 handles the splash screen differently than previous versions. Please visit + # https://developer.android.com/guide/topics/ui/splash-screen + # Following are Android 12 specific parameter. + android_12: + # The image parameter sets the splash screen icon image. If this parameter is not specified, + # the app's launcher icon will be used instead. + # Please note that the splash screen will be clipped to a circle on the center of the screen. + # App icon with an icon background: This should be 960×960 pixels, and fit within a circle + # 640 pixels in diameter. + # App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle + # 768 pixels in diameter. + image: "images/icon.png" + + # The image_dark, color_dark, icon_background_color_dark, and branding_dark set values that + # apply when the device is in dark mode. If they are not specified, the app will use the + # parameters from above. + image_dark: "images/icon.png" + + # The android, ios and web parameters can be used to disable generating a splash screen on a given + # platform. + android: true + ios: true + web: true + + # Platform specific images can be specified with the following parameters, which will override + # the respective parameter. You may specify all, selected, or none of these parameters: + #color_android: "#42a5f5" + #color_dark_android: "#042a49" + #color_ios: "#42a5f5" + #color_dark_ios: "#042a49" + #color_web: "#42a5f5" + #color_dark_web: "#042a49" + image_android: "images/icon.png" + image_dark_android: "images/icon.png" + image_ios: "images/icon.png" + image_dark_ios: "images/icon.png" + image_web: "images/icon.png" + image_dark_web: "images/icon.png" diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/assets/FontManifest.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/assets/FontManifest.json new file mode 100644 index 0000000000..360da2126c --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/assets/FontManifest.json @@ -0,0 +1,28 @@ +[ + { + "family": "MaterialIcons", + "fonts": [ + { + "asset": "fonts/MaterialIcons-Regular.otf" + } + ] + }, + {% if cookiecutter.no_cdn %} + { + "family": "Roboto", + "fonts": [ + { + "asset": "fonts/roboto.woff2" + } + ] + }, + {% endif %} + { + "family": "packages/cupertino_icons/CupertinoIcons", + "fonts": [ + { + "asset": "packages/cupertino_icons/assets/CupertinoIcons.ttf" + } + ] + } +] diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/assets/fonts/roboto.woff2 b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/assets/fonts/roboto.woff2 new file mode 100644 index 0000000000..8fa8d2ae93 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/assets/fonts/roboto.woff2 differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/canvaskit.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/canvaskit.js new file mode 100644 index 0000000000..da4dfcc2d6 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/canvaskit.js @@ -0,0 +1,192 @@ + +var CanvasKitInit = (() => { + var _scriptName = import.meta.url; + + return ( +function(moduleArg = {}) { + var moduleRtn; + +var r=moduleArg,ba,ca,da=new Promise((a,b)=>{ba=a;ca=b}),fa="object"==typeof window,ia="function"==typeof importScripts; +(function(a){a.ce=a.ce||[];a.ce.push(function(){a.MakeSWCanvasSurface=function(b){var c=b,e="undefined"!==typeof OffscreenCanvas&&c instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&c instanceof HTMLCanvasElement||e||(c=document.getElementById(b),c)))throw"Canvas with id "+b+" was not found";if(b=a.MakeSurface(c.width,c.height))b.Ae=c;return b};a.MakeCanvasSurface||(a.MakeCanvasSurface=a.MakeSWCanvasSurface);a.MakeSurface=function(b,c){var e={width:b,height:c,colorType:a.ColorType.RGBA_8888, +alphaType:a.AlphaType.Unpremul,colorSpace:a.ColorSpace.SRGB},f=b*c*4,k=a._malloc(f);if(e=a.Surface._makeRasterDirect(e,k,4*b))e.Ae=null,e.$e=b,e.Xe=c,e.Ye=f,e.He=k,e.getCanvas().clear(a.TRANSPARENT);return e};a.MakeRasterDirectSurface=function(b,c,e){return a.Surface._makeRasterDirect(b,c.byteOffset,e)};a.Surface.prototype.flush=function(b){a.$d(this.Zd);this._flush();if(this.Ae){var c=new Uint8ClampedArray(a.HEAPU8.buffer,this.He,this.Ye);c=new ImageData(c,this.$e,this.Xe);b?this.Ae.getContext("2d").putImageData(c, +0,0,b[0],b[1],b[2]-b[0],b[3]-b[1]):this.Ae.getContext("2d").putImageData(c,0,0)}};a.Surface.prototype.dispose=function(){this.He&&a._free(this.He);this.delete()};a.$d=a.$d||function(){};a.Be=a.Be||function(){return null}})})(r); +(function(a){a.ce=a.ce||[];a.ce.push(function(){function b(l,p,v){return l&&l.hasOwnProperty(p)?l[p]:v}function c(l){var p=ja(ka);ka[p]=l;return p}function e(l){return l.naturalHeight||l.videoHeight||l.displayHeight||l.height}function f(l){return l.naturalWidth||l.videoWidth||l.displayWidth||l.width}function k(l,p,v,w){l.bindTexture(l.TEXTURE_2D,p);w||v.alphaType!==a.AlphaType.Premul||l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);return p}function n(l,p,v){v||p.alphaType!==a.AlphaType.Premul|| +l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);l.bindTexture(l.TEXTURE_2D,null)}a.GetWebGLContext=function(l,p){if(!l)throw"null canvas passed into makeWebGLContext";var v={alpha:b(p,"alpha",1),depth:b(p,"depth",1),stencil:b(p,"stencil",8),antialias:b(p,"antialias",0),premultipliedAlpha:b(p,"premultipliedAlpha",1),preserveDrawingBuffer:b(p,"preserveDrawingBuffer",0),preferLowPowerToHighPerformance:b(p,"preferLowPowerToHighPerformance",0),failIfMajorPerformanceCaveat:b(p,"failIfMajorPerformanceCaveat", +0),enableExtensionsByDefault:b(p,"enableExtensionsByDefault",1),explicitSwapControl:b(p,"explicitSwapControl",0),renderViaOffscreenBackBuffer:b(p,"renderViaOffscreenBackBuffer",0)};v.majorVersion=p&&p.majorVersion?p.majorVersion:"undefined"!==typeof WebGL2RenderingContext?2:1;if(v.explicitSwapControl)throw"explicitSwapControl is not supported";l=na(l,v);if(!l)return 0;oa(l);z.le.getExtension("WEBGL_debug_renderer_info");return l};a.deleteContext=function(l){z===pa[l]&&(z=null);"object"==typeof JSEvents&& +JSEvents.Af(pa[l].le.canvas);pa[l]&&pa[l].le.canvas&&(pa[l].le.canvas.Ve=void 0);pa[l]=null};a._setTextureCleanup({deleteTexture:function(l,p){var v=ka[p];v&&pa[l].le.deleteTexture(v);ka[p]=null}});a.MakeWebGLContext=function(l){if(!this.$d(l))return null;var p=this._MakeGrContext();if(!p)return null;p.Zd=l;var v=p.delete.bind(p);p["delete"]=function(){a.$d(this.Zd);v()}.bind(p);return z.Je=p};a.MakeGrContext=a.MakeWebGLContext;a.GrDirectContext.prototype.getResourceCacheLimitBytes=function(){a.$d(this.Zd); +this._getResourceCacheLimitBytes()};a.GrDirectContext.prototype.getResourceCacheUsageBytes=function(){a.$d(this.Zd);this._getResourceCacheUsageBytes()};a.GrDirectContext.prototype.releaseResourcesAndAbandonContext=function(){a.$d(this.Zd);this._releaseResourcesAndAbandonContext()};a.GrDirectContext.prototype.setResourceCacheLimitBytes=function(l){a.$d(this.Zd);this._setResourceCacheLimitBytes(l)};a.MakeOnScreenGLSurface=function(l,p,v,w,A,D){if(!this.$d(l.Zd))return null;p=void 0===A||void 0===D? +this._MakeOnScreenGLSurface(l,p,v,w):this._MakeOnScreenGLSurface(l,p,v,w,A,D);if(!p)return null;p.Zd=l.Zd;return p};a.MakeRenderTarget=function(){var l=arguments[0];if(!this.$d(l.Zd))return null;if(3===arguments.length){var p=this._MakeRenderTargetWH(l,arguments[1],arguments[2]);if(!p)return null}else if(2===arguments.length){if(p=this._MakeRenderTargetII(l,arguments[1]),!p)return null}else return null;p.Zd=l.Zd;return p};a.MakeWebGLCanvasSurface=function(l,p,v){p=p||null;var w=l,A="undefined"!== +typeof OffscreenCanvas&&w instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&w instanceof HTMLCanvasElement||A||(w=document.getElementById(l),w)))throw"Canvas with id "+l+" was not found";l=this.GetWebGLContext(w,v);if(!l||0>l)throw"failed to create webgl context: err "+l;l=this.MakeWebGLContext(l);p=this.MakeOnScreenGLSurface(l,w.width,w.height,p);return p?p:(p=w.cloneNode(!0),w.parentNode.replaceChild(p,w),p.classList.add("ck-replaced"),a.MakeSWCanvasSurface(p))};a.MakeCanvasSurface= +a.MakeWebGLCanvasSurface;a.Surface.prototype.makeImageFromTexture=function(l,p){a.$d(this.Zd);l=c(l);if(p=this._makeImageFromTexture(this.Zd,l,p))p.ue=l;return p};a.Surface.prototype.makeImageFromTextureSource=function(l,p,v){p||={height:e(l),width:f(l),colorType:a.ColorType.RGBA_8888,alphaType:v?a.AlphaType.Premul:a.AlphaType.Unpremul};p.colorSpace||(p.colorSpace=a.ColorSpace.SRGB);a.$d(this.Zd);var w=z.le;v=k(w,w.createTexture(),p,v);2===z.version?w.texImage2D(w.TEXTURE_2D,0,w.RGBA,p.width,p.height, +0,w.RGBA,w.UNSIGNED_BYTE,l):w.texImage2D(w.TEXTURE_2D,0,w.RGBA,w.RGBA,w.UNSIGNED_BYTE,l);n(w,p);this._resetContext();return this.makeImageFromTexture(v,p)};a.Surface.prototype.updateTextureFromSource=function(l,p,v){if(l.ue){a.$d(this.Zd);var w=l.getImageInfo(),A=z.le,D=k(A,ka[l.ue],w,v);2===z.version?A.texImage2D(A.TEXTURE_2D,0,A.RGBA,f(p),e(p),0,A.RGBA,A.UNSIGNED_BYTE,p):A.texImage2D(A.TEXTURE_2D,0,A.RGBA,A.RGBA,A.UNSIGNED_BYTE,p);n(A,w,v);this._resetContext();ka[l.ue]=null;l.ue=c(D);w.colorSpace= +l.getColorSpace();p=this._makeImageFromTexture(this.Zd,l.ue,w);v=l.Yd.ae;A=l.Yd.ee;l.Yd.ae=p.Yd.ae;l.Yd.ee=p.Yd.ee;p.Yd.ae=v;p.Yd.ee=A;p.delete();w.colorSpace.delete()}};a.MakeLazyImageFromTextureSource=function(l,p,v){p||={height:e(l),width:f(l),colorType:a.ColorType.RGBA_8888,alphaType:v?a.AlphaType.Premul:a.AlphaType.Unpremul};p.colorSpace||(p.colorSpace=a.ColorSpace.SRGB);var w={makeTexture:function(){var A=z,D=A.le,I=k(D,D.createTexture(),p,v);2===A.version?D.texImage2D(D.TEXTURE_2D,0,D.RGBA, +p.width,p.height,0,D.RGBA,D.UNSIGNED_BYTE,l):D.texImage2D(D.TEXTURE_2D,0,D.RGBA,D.RGBA,D.UNSIGNED_BYTE,l);n(D,p,v);return c(I)},freeSrc:function(){}};"VideoFrame"===l.constructor.name&&(w.freeSrc=function(){l.close()});return a.Image._makeFromGenerator(p,w)};a.$d=function(l){return l?oa(l):!1};a.Be=function(){return z&&z.Je&&!z.Je.isDeleted()?z.Je:null}})})(r); +(function(a){function b(g){return(f(255*g[3])<<24|f(255*g[0])<<16|f(255*g[1])<<8|f(255*g[2])<<0)>>>0}function c(g){if(g&&g._ck)return g;if(g instanceof Float32Array){for(var d=Math.floor(g.length/4),h=new Uint32Array(d),m=0;mx;x++)a.HEAPF32[t+m]=g[u][x],m++;g=h}else g=0;d.he=g}else throw"Invalid argument to copyFlexibleColorArray, Not a color array "+typeof g;return d}function p(g){if(!g)return 0;var d=aa.toTypedArray();if(g.length){if(6===g.length||9===g.length)return n(g,"HEAPF32",P),6===g.length&&a.HEAPF32.set(Vc,6+P/4),P;if(16===g.length)return d[0]=g[0],d[1]=g[1],d[2]=g[3],d[3]=g[4],d[4]=g[5],d[5]=g[7],d[6]=g[12],d[7]=g[13],d[8]=g[15],P;throw"invalid matrix size"; +}if(void 0===g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m41;d[3]=g.m12;d[4]=g.m22;d[5]=g.m42;d[6]=g.m14;d[7]=g.m24;d[8]=g.m44;return P}function v(g){if(!g)return 0;var d=X.toTypedArray();if(g.length){if(16!==g.length&&6!==g.length&&9!==g.length)throw"invalid matrix size";if(16===g.length)return n(g,"HEAPF32",la);d.fill(0);d[0]=g[0];d[1]=g[1];d[3]=g[2];d[4]=g[3];d[5]=g[4];d[7]=g[5];d[10]=1;d[12]=g[6];d[13]=g[7];d[15]=g[8];6===g.length&&(d[12]=0,d[13]=0,d[15]=1);return la}if(void 0=== +g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m31;d[3]=g.m41;d[4]=g.m12;d[5]=g.m22;d[6]=g.m32;d[7]=g.m42;d[8]=g.m13;d[9]=g.m23;d[10]=g.m33;d[11]=g.m43;d[12]=g.m14;d[13]=g.m24;d[14]=g.m34;d[15]=g.m44;return la}function w(g,d){return n(g,"HEAPF32",d||ha)}function A(g,d,h,m){var t=Ea.toTypedArray();t[0]=g;t[1]=d;t[2]=h;t[3]=m;return ha}function D(g){for(var d=new Float32Array(4),h=0;4>h;h++)d[h]=a.HEAPF32[g/4+h];return d}function I(g,d){return n(g,"HEAPF32",d||V)}function Q(g,d){return n(g, +"HEAPF32",d||tb)}a.Color=function(g,d,h,m){void 0===m&&(m=1);return a.Color4f(f(g)/255,f(d)/255,f(h)/255,m)};a.ColorAsInt=function(g,d,h,m){void 0===m&&(m=255);return(f(m)<<24|f(g)<<16|f(d)<<8|f(h)<<0&268435455)>>>0};a.Color4f=function(g,d,h,m){void 0===m&&(m=1);return Float32Array.of(g,d,h,m)};Object.defineProperty(a,"TRANSPARENT",{get:function(){return a.Color4f(0,0,0,0)}});Object.defineProperty(a,"BLACK",{get:function(){return a.Color4f(0,0,0,1)}});Object.defineProperty(a,"WHITE",{get:function(){return a.Color4f(1, +1,1,1)}});Object.defineProperty(a,"RED",{get:function(){return a.Color4f(1,0,0,1)}});Object.defineProperty(a,"GREEN",{get:function(){return a.Color4f(0,1,0,1)}});Object.defineProperty(a,"BLUE",{get:function(){return a.Color4f(0,0,1,1)}});Object.defineProperty(a,"YELLOW",{get:function(){return a.Color4f(1,1,0,1)}});Object.defineProperty(a,"CYAN",{get:function(){return a.Color4f(0,1,1,1)}});Object.defineProperty(a,"MAGENTA",{get:function(){return a.Color4f(1,0,1,1)}});a.getColorComponents=function(g){return[Math.floor(255* +g[0]),Math.floor(255*g[1]),Math.floor(255*g[2]),g[3]]};a.parseColorString=function(g,d){g=g.toLowerCase();if(g.startsWith("#")){d=255;switch(g.length){case 9:d=parseInt(g.slice(7,9),16);case 7:var h=parseInt(g.slice(1,3),16);var m=parseInt(g.slice(3,5),16);var t=parseInt(g.slice(5,7),16);break;case 5:d=17*parseInt(g.slice(4,5),16);case 4:h=17*parseInt(g.slice(1,2),16),m=17*parseInt(g.slice(2,3),16),t=17*parseInt(g.slice(3,4),16)}return a.Color(h,m,t,d/255)}return g.startsWith("rgba")?(g=g.slice(5, +-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("rgb")?(g=g.slice(4,-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("gray(")||g.startsWith("hsl")||!d||(g=d[g],void 0===g)?a.BLACK:g};a.multiplyByAlpha=function(g,d){g=g.slice();g[3]=Math.max(0,Math.min(g[3]*d,1));return g};a.Malloc=function(g,d){var h=a._malloc(d*g.BYTES_PER_ELEMENT);return{_ck:!0,length:d,byteOffset:h,qe:null,subarray:function(m,t){m=this.toTypedArray().subarray(m,t);m._ck=!0;return m},toTypedArray:function(){if(this.qe&& +this.qe.length)return this.qe;this.qe=new g(a.HEAPU8.buffer,h,d);this.qe._ck=!0;return this.qe}}};a.Free=function(g){a._free(g.byteOffset);g.byteOffset=0;g.toTypedArray=null;g.qe=null};var P=0,aa,la=0,X,ha=0,Ea,ea,V=0,Ub,Aa=0,Vb,ub=0,Wb,vb=0,$a,Ma=0,Xb,tb=0,Yb,Zb=0,Vc=Float32Array.of(0,0,1);a.onRuntimeInitialized=function(){function g(d,h,m,t,u,x,C){x||(x=4*t.width,t.colorType===a.ColorType.RGBA_F16?x*=2:t.colorType===a.ColorType.RGBA_F32&&(x*=4));var G=x*t.height;var F=u?u.byteOffset:a._malloc(G); +if(C?!d._readPixels(t,F,x,h,m,C):!d._readPixels(t,F,x,h,m))return u||a._free(F),null;if(u)return u.toTypedArray();switch(t.colorType){case a.ColorType.RGBA_8888:case a.ColorType.RGBA_F16:d=(new Uint8Array(a.HEAPU8.buffer,F,G)).slice();break;case a.ColorType.RGBA_F32:d=(new Float32Array(a.HEAPU8.buffer,F,G)).slice();break;default:return null}a._free(F);return d}Ea=a.Malloc(Float32Array,4);ha=Ea.byteOffset;X=a.Malloc(Float32Array,16);la=X.byteOffset;aa=a.Malloc(Float32Array,9);P=aa.byteOffset;Xb=a.Malloc(Float32Array, +12);tb=Xb.byteOffset;Yb=a.Malloc(Float32Array,12);Zb=Yb.byteOffset;ea=a.Malloc(Float32Array,4);V=ea.byteOffset;Ub=a.Malloc(Float32Array,4);Aa=Ub.byteOffset;Vb=a.Malloc(Float32Array,3);ub=Vb.byteOffset;Wb=a.Malloc(Float32Array,3);vb=Wb.byteOffset;$a=a.Malloc(Int32Array,4);Ma=$a.byteOffset;a.ColorSpace.SRGB=a.ColorSpace._MakeSRGB();a.ColorSpace.DISPLAY_P3=a.ColorSpace._MakeDisplayP3();a.ColorSpace.ADOBE_RGB=a.ColorSpace._MakeAdobeRGB();a.GlyphRunFlags={IsWhiteSpace:a._GlyphRunFlags_isWhiteSpace};a.Path.MakeFromCmds= +function(d){var h=n(d,"HEAPF32"),m=a.Path._MakeFromCmds(h,d.length);k(h,d);return m};a.Path.MakeFromVerbsPointsWeights=function(d,h,m){var t=n(d,"HEAPU8"),u=n(h,"HEAPF32"),x=n(m,"HEAPF32"),C=a.Path._MakeFromVerbsPointsWeights(t,d.length,u,h.length,x,m&&m.length||0);k(t,d);k(u,h);k(x,m);return C};a.Path.prototype.addArc=function(d,h,m){d=I(d);this._addArc(d,h,m);return this};a.Path.prototype.addCircle=function(d,h,m,t){this._addCircle(d,h,m,!!t);return this};a.Path.prototype.addOval=function(d,h,m){void 0=== +m&&(m=1);d=I(d);this._addOval(d,!!h,m);return this};a.Path.prototype.addPath=function(){var d=Array.prototype.slice.call(arguments),h=d[0],m=!1;"boolean"===typeof d[d.length-1]&&(m=d.pop());if(1===d.length)this._addPath(h,1,0,0,0,1,0,0,0,1,m);else if(2===d.length)d=d[1],this._addPath(h,d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1,m);else if(7===d.length||10===d.length)this._addPath(h,d[1],d[2],d[3],d[4],d[5],d[6],d[7]||0,d[8]||0,d[9]||1,m);else return null;return this};a.Path.prototype.addPoly= +function(d,h){var m=n(d,"HEAPF32");this._addPoly(m,d.length/2,h);k(m,d);return this};a.Path.prototype.addRect=function(d,h){d=I(d);this._addRect(d,!!h);return this};a.Path.prototype.addRRect=function(d,h){d=Q(d);this._addRRect(d,!!h);return this};a.Path.prototype.addVerbsPointsWeights=function(d,h,m){var t=n(d,"HEAPU8"),u=n(h,"HEAPF32"),x=n(m,"HEAPF32");this._addVerbsPointsWeights(t,d.length,u,h.length,x,m&&m.length||0);k(t,d);k(u,h);k(x,m)};a.Path.prototype.arc=function(d,h,m,t,u,x){d=a.LTRBRect(d- +m,h-m,d+m,h+m);u=(u-t)/Math.PI*180-360*!!x;x=new a.Path;x.addArc(d,t/Math.PI*180,u);this.addPath(x,!0);x.delete();return this};a.Path.prototype.arcToOval=function(d,h,m,t){d=I(d);this._arcToOval(d,h,m,t);return this};a.Path.prototype.arcToRotated=function(d,h,m,t,u,x,C){this._arcToRotated(d,h,m,!!t,!!u,x,C);return this};a.Path.prototype.arcToTangent=function(d,h,m,t,u){this._arcToTangent(d,h,m,t,u);return this};a.Path.prototype.close=function(){this._close();return this};a.Path.prototype.conicTo= +function(d,h,m,t,u){this._conicTo(d,h,m,t,u);return this};a.Path.prototype.computeTightBounds=function(d){this._computeTightBounds(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.cubicTo=function(d,h,m,t,u,x){this._cubicTo(d,h,m,t,u,x);return this};a.Path.prototype.dash=function(d,h,m){return this._dash(d,h,m)?this:null};a.Path.prototype.getBounds=function(d){this._getBounds(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.lineTo=function(d, +h){this._lineTo(d,h);return this};a.Path.prototype.moveTo=function(d,h){this._moveTo(d,h);return this};a.Path.prototype.offset=function(d,h){this._transform(1,0,d,0,1,h,0,0,1);return this};a.Path.prototype.quadTo=function(d,h,m,t){this._quadTo(d,h,m,t);return this};a.Path.prototype.rArcTo=function(d,h,m,t,u,x,C){this._rArcTo(d,h,m,t,u,x,C);return this};a.Path.prototype.rConicTo=function(d,h,m,t,u){this._rConicTo(d,h,m,t,u);return this};a.Path.prototype.rCubicTo=function(d,h,m,t,u,x){this._rCubicTo(d, +h,m,t,u,x);return this};a.Path.prototype.rLineTo=function(d,h){this._rLineTo(d,h);return this};a.Path.prototype.rMoveTo=function(d,h){this._rMoveTo(d,h);return this};a.Path.prototype.rQuadTo=function(d,h,m,t){this._rQuadTo(d,h,m,t);return this};a.Path.prototype.stroke=function(d){d=d||{};d.width=d.width||1;d.miter_limit=d.miter_limit||4;d.cap=d.cap||a.StrokeCap.Butt;d.join=d.join||a.StrokeJoin.Miter;d.precision=d.precision||1;return this._stroke(d)?this:null};a.Path.prototype.transform=function(){if(1=== +arguments.length){var d=arguments[0];this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1)}else if(6===arguments.length||9===arguments.length)d=arguments,this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1);else throw"transform expected to take 1 or 9 arguments. Got "+arguments.length;return this};a.Path.prototype.trim=function(d,h,m){return this._trim(d,h,!!m)?this:null};a.Image.prototype.encodeToBytes=function(d,h){var m=a.Be();d=d||a.ImageFormat.PNG;h=h||100; +return m?this._encodeToBytes(d,h,m):this._encodeToBytes(d,h)};a.Image.prototype.makeShaderCubic=function(d,h,m,t,u){u=p(u);return this._makeShaderCubic(d,h,m,t,u)};a.Image.prototype.makeShaderOptions=function(d,h,m,t,u){u=p(u);return this._makeShaderOptions(d,h,m,t,u)};a.Image.prototype.readPixels=function(d,h,m,t,u){var x=a.Be();return g(this,d,h,m,t,u,x)};a.Canvas.prototype.clear=function(d){a.$d(this.Zd);d=w(d);this._clear(d)};a.Canvas.prototype.clipRRect=function(d,h,m){a.$d(this.Zd);d=Q(d);this._clipRRect(d, +h,m)};a.Canvas.prototype.clipRect=function(d,h,m){a.$d(this.Zd);d=I(d);this._clipRect(d,h,m)};a.Canvas.prototype.concat=function(d){a.$d(this.Zd);d=v(d);this._concat(d)};a.Canvas.prototype.drawArc=function(d,h,m,t,u){a.$d(this.Zd);d=I(d);this._drawArc(d,h,m,t,u)};a.Canvas.prototype.drawAtlas=function(d,h,m,t,u,x,C){if(d&&t&&h&&m&&h.length===m.length){a.$d(this.Zd);u||(u=a.BlendMode.SrcOver);var G=n(h,"HEAPF32"),F=n(m,"HEAPF32"),S=m.length/4,T=n(c(x),"HEAPU32");if(C&&"B"in C&&"C"in C)this._drawAtlasCubic(d, +F,G,T,S,u,C.B,C.C,t);else{let q=a.FilterMode.Linear,y=a.MipmapMode.None;C&&(q=C.filter,"mipmap"in C&&(y=C.mipmap));this._drawAtlasOptions(d,F,G,T,S,u,q,y,t)}k(G,h);k(F,m);k(T,x)}};a.Canvas.prototype.drawCircle=function(d,h,m,t){a.$d(this.Zd);this._drawCircle(d,h,m,t)};a.Canvas.prototype.drawColor=function(d,h){a.$d(this.Zd);d=w(d);void 0!==h?this._drawColor(d,h):this._drawColor(d)};a.Canvas.prototype.drawColorInt=function(d,h){a.$d(this.Zd);this._drawColorInt(d,h||a.BlendMode.SrcOver)};a.Canvas.prototype.drawColorComponents= +function(d,h,m,t,u){a.$d(this.Zd);d=A(d,h,m,t);void 0!==u?this._drawColor(d,u):this._drawColor(d)};a.Canvas.prototype.drawDRRect=function(d,h,m){a.$d(this.Zd);d=Q(d,tb);h=Q(h,Zb);this._drawDRRect(d,h,m)};a.Canvas.prototype.drawImage=function(d,h,m,t){a.$d(this.Zd);this._drawImage(d,h,m,t||null)};a.Canvas.prototype.drawImageCubic=function(d,h,m,t,u,x){a.$d(this.Zd);this._drawImageCubic(d,h,m,t,u,x||null)};a.Canvas.prototype.drawImageOptions=function(d,h,m,t,u,x){a.$d(this.Zd);this._drawImageOptions(d, +h,m,t,u,x||null)};a.Canvas.prototype.drawImageNine=function(d,h,m,t,u){a.$d(this.Zd);h=n(h,"HEAP32",Ma);m=I(m);this._drawImageNine(d,h,m,t,u||null)};a.Canvas.prototype.drawImageRect=function(d,h,m,t,u){a.$d(this.Zd);I(h,V);I(m,Aa);this._drawImageRect(d,V,Aa,t,!!u)};a.Canvas.prototype.drawImageRectCubic=function(d,h,m,t,u,x){a.$d(this.Zd);I(h,V);I(m,Aa);this._drawImageRectCubic(d,V,Aa,t,u,x||null)};a.Canvas.prototype.drawImageRectOptions=function(d,h,m,t,u,x){a.$d(this.Zd);I(h,V);I(m,Aa);this._drawImageRectOptions(d, +V,Aa,t,u,x||null)};a.Canvas.prototype.drawLine=function(d,h,m,t,u){a.$d(this.Zd);this._drawLine(d,h,m,t,u)};a.Canvas.prototype.drawOval=function(d,h){a.$d(this.Zd);d=I(d);this._drawOval(d,h)};a.Canvas.prototype.drawPaint=function(d){a.$d(this.Zd);this._drawPaint(d)};a.Canvas.prototype.drawParagraph=function(d,h,m){a.$d(this.Zd);this._drawParagraph(d,h,m)};a.Canvas.prototype.drawPatch=function(d,h,m,t,u){if(24>d.length)throw"Need 12 cubic points";if(h&&4>h.length)throw"Need 4 colors";if(m&&8>m.length)throw"Need 4 shader coordinates"; +a.$d(this.Zd);const x=n(d,"HEAPF32"),C=h?n(c(h),"HEAPU32"):0,G=m?n(m,"HEAPF32"):0;t||(t=a.BlendMode.Modulate);this._drawPatch(x,C,G,t,u);k(G,m);k(C,h);k(x,d)};a.Canvas.prototype.drawPath=function(d,h){a.$d(this.Zd);this._drawPath(d,h)};a.Canvas.prototype.drawPicture=function(d){a.$d(this.Zd);this._drawPicture(d)};a.Canvas.prototype.drawPoints=function(d,h,m){a.$d(this.Zd);var t=n(h,"HEAPF32");this._drawPoints(d,t,h.length/2,m);k(t,h)};a.Canvas.prototype.drawRRect=function(d,h){a.$d(this.Zd);d=Q(d); +this._drawRRect(d,h)};a.Canvas.prototype.drawRect=function(d,h){a.$d(this.Zd);d=I(d);this._drawRect(d,h)};a.Canvas.prototype.drawRect4f=function(d,h,m,t,u){a.$d(this.Zd);this._drawRect4f(d,h,m,t,u)};a.Canvas.prototype.drawShadow=function(d,h,m,t,u,x,C){a.$d(this.Zd);var G=n(u,"HEAPF32"),F=n(x,"HEAPF32");h=n(h,"HEAPF32",ub);m=n(m,"HEAPF32",vb);this._drawShadow(d,h,m,t,G,F,C);k(G,u);k(F,x)};a.getShadowLocalBounds=function(d,h,m,t,u,x,C){d=p(d);m=n(m,"HEAPF32",ub);t=n(t,"HEAPF32",vb);if(!this._getShadowLocalBounds(d, +h,m,t,u,x,V))return null;h=ea.toTypedArray();return C?(C.set(h),C):h.slice()};a.Canvas.prototype.drawTextBlob=function(d,h,m,t){a.$d(this.Zd);this._drawTextBlob(d,h,m,t)};a.Canvas.prototype.drawVertices=function(d,h,m){a.$d(this.Zd);this._drawVertices(d,h,m)};a.Canvas.prototype.getDeviceClipBounds=function(d){this._getDeviceClipBounds(Ma);var h=$a.toTypedArray();d?d.set(h):d=h.slice();return d};a.Canvas.prototype.quickReject=function(d){d=I(d);return this._quickReject(d)};a.Canvas.prototype.getLocalToDevice= +function(){this._getLocalToDevice(la);for(var d=la,h=Array(16),m=0;16>m;m++)h[m]=a.HEAPF32[d/4+m];return h};a.Canvas.prototype.getTotalMatrix=function(){this._getTotalMatrix(P);for(var d=Array(9),h=0;9>h;h++)d[h]=a.HEAPF32[P/4+h];return d};a.Canvas.prototype.makeSurface=function(d){d=this._makeSurface(d);d.Zd=this.Zd;return d};a.Canvas.prototype.readPixels=function(d,h,m,t,u){a.$d(this.Zd);return g(this,d,h,m,t,u)};a.Canvas.prototype.saveLayer=function(d,h,m,t,u){h=I(h);return this._saveLayer(d|| +null,h,m||null,t||0,u||a.TileMode.Clamp)};a.Canvas.prototype.writePixels=function(d,h,m,t,u,x,C,G){if(d.byteLength%(h*m))throw"pixels length must be a multiple of the srcWidth * srcHeight";a.$d(this.Zd);var F=d.byteLength/(h*m);x=x||a.AlphaType.Unpremul;C=C||a.ColorType.RGBA_8888;G=G||a.ColorSpace.SRGB;var S=F*h;F=n(d,"HEAPU8");h=this._writePixels({width:h,height:m,colorType:C,alphaType:x,colorSpace:G},F,S,t,u);k(F,d);return h};a.ColorFilter.MakeBlend=function(d,h,m){d=w(d);m=m||a.ColorSpace.SRGB; +return a.ColorFilter._MakeBlend(d,h,m)};a.ColorFilter.MakeMatrix=function(d){if(!d||20!==d.length)throw"invalid color matrix";var h=n(d,"HEAPF32"),m=a.ColorFilter._makeMatrix(h);k(h,d);return m};a.ContourMeasure.prototype.getPosTan=function(d,h){this._getPosTan(d,V);d=ea.toTypedArray();return h?(h.set(d),h):d.slice()};a.ImageFilter.prototype.getOutputBounds=function(d,h,m){d=I(d,V);h=p(h);this._getOutputBounds(d,h,Ma);h=$a.toTypedArray();return m?(m.set(h),m):h.slice()};a.ImageFilter.MakeDropShadow= +function(d,h,m,t,u,x){u=w(u,ha);return a.ImageFilter._MakeDropShadow(d,h,m,t,u,x)};a.ImageFilter.MakeDropShadowOnly=function(d,h,m,t,u,x){u=w(u,ha);return a.ImageFilter._MakeDropShadowOnly(d,h,m,t,u,x)};a.ImageFilter.MakeImage=function(d,h,m,t){m=I(m,V);t=I(t,Aa);if("B"in h&&"C"in h)return a.ImageFilter._MakeImageCubic(d,h.B,h.C,m,t);const u=h.filter;let x=a.MipmapMode.None;"mipmap"in h&&(x=h.mipmap);return a.ImageFilter._MakeImageOptions(d,u,x,m,t)};a.ImageFilter.MakeMatrixTransform=function(d,h, +m){d=p(d);if("B"in h&&"C"in h)return a.ImageFilter._MakeMatrixTransformCubic(d,h.B,h.C,m);const t=h.filter;let u=a.MipmapMode.None;"mipmap"in h&&(u=h.mipmap);return a.ImageFilter._MakeMatrixTransformOptions(d,t,u,m)};a.Paint.prototype.getColor=function(){this._getColor(ha);return D(ha)};a.Paint.prototype.setColor=function(d,h){h=h||null;d=w(d);this._setColor(d,h)};a.Paint.prototype.setColorComponents=function(d,h,m,t,u){u=u||null;d=A(d,h,m,t);this._setColor(d,u)};a.Path.prototype.getPoint=function(d, +h){this._getPoint(d,V);d=ea.toTypedArray();return h?(h[0]=d[0],h[1]=d[1],h):d.slice(0,2)};a.Picture.prototype.makeShader=function(d,h,m,t,u){t=p(t);u=I(u);return this._makeShader(d,h,m,t,u)};a.Picture.prototype.cullRect=function(d){this._cullRect(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.PictureRecorder.prototype.beginRecording=function(d,h){d=I(d);return this._beginRecording(d,!!h)};a.Surface.prototype.getCanvas=function(){var d=this._getCanvas();d.Zd=this.Zd;return d};a.Surface.prototype.makeImageSnapshot= +function(d){a.$d(this.Zd);d=n(d,"HEAP32",Ma);return this._makeImageSnapshot(d)};a.Surface.prototype.makeSurface=function(d){a.$d(this.Zd);d=this._makeSurface(d);d.Zd=this.Zd;return d};a.Surface.prototype.Ze=function(d,h){this.te||(this.te=this.getCanvas());return requestAnimationFrame(function(){a.$d(this.Zd);d(this.te);this.flush(h)}.bind(this))};a.Surface.prototype.requestAnimationFrame||(a.Surface.prototype.requestAnimationFrame=a.Surface.prototype.Ze);a.Surface.prototype.We=function(d,h){this.te|| +(this.te=this.getCanvas());requestAnimationFrame(function(){a.$d(this.Zd);d(this.te);this.flush(h);this.dispose()}.bind(this))};a.Surface.prototype.drawOnce||(a.Surface.prototype.drawOnce=a.Surface.prototype.We);a.PathEffect.MakeDash=function(d,h){h||=0;if(!d.length||1===d.length%2)throw"Intervals array must have even length";var m=n(d,"HEAPF32");h=a.PathEffect._MakeDash(m,d.length,h);k(m,d);return h};a.PathEffect.MakeLine2D=function(d,h){h=p(h);return a.PathEffect._MakeLine2D(d,h)};a.PathEffect.MakePath2D= +function(d,h){d=p(d);return a.PathEffect._MakePath2D(d,h)};a.Shader.MakeColor=function(d,h){h=h||null;d=w(d);return a.Shader._MakeColor(d,h)};a.Shader.Blend=a.Shader.MakeBlend;a.Shader.Color=a.Shader.MakeColor;a.Shader.MakeLinearGradient=function(d,h,m,t,u,x,C,G){G=G||null;var F=l(m),S=n(t,"HEAPF32");C=C||0;x=p(x);var T=ea.toTypedArray();T.set(d);T.set(h,2);d=a.Shader._MakeLinearGradient(V,F.he,F.colorType,S,F.count,u,C,x,G);k(F.he,m);t&&k(S,t);return d};a.Shader.MakeRadialGradient=function(d,h,m, +t,u,x,C,G){G=G||null;var F=l(m),S=n(t,"HEAPF32");C=C||0;x=p(x);d=a.Shader._MakeRadialGradient(d[0],d[1],h,F.he,F.colorType,S,F.count,u,C,x,G);k(F.he,m);t&&k(S,t);return d};a.Shader.MakeSweepGradient=function(d,h,m,t,u,x,C,G,F,S){S=S||null;var T=l(m),q=n(t,"HEAPF32");C=C||0;G=G||0;F=F||360;x=p(x);d=a.Shader._MakeSweepGradient(d,h,T.he,T.colorType,q,T.count,u,G,F,C,x,S);k(T.he,m);t&&k(q,t);return d};a.Shader.MakeTwoPointConicalGradient=function(d,h,m,t,u,x,C,G,F,S){S=S||null;var T=l(u),q=n(x,"HEAPF32"); +F=F||0;G=p(G);var y=ea.toTypedArray();y.set(d);y.set(m,2);d=a.Shader._MakeTwoPointConicalGradient(V,h,t,T.he,T.colorType,q,T.count,C,F,G,S);k(T.he,u);x&&k(q,x);return d};a.Vertices.prototype.bounds=function(d){this._bounds(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.ce&&a.ce.forEach(function(d){d()})};a.computeTonalColors=function(g){var d=n(g.ambient,"HEAPF32"),h=n(g.spot,"HEAPF32");this._computeTonalColors(d,h);var m={ambient:D(d),spot:D(h)};k(d,g.ambient);k(h,g.spot);return m}; +a.LTRBRect=function(g,d,h,m){return Float32Array.of(g,d,h,m)};a.XYWHRect=function(g,d,h,m){return Float32Array.of(g,d,g+h,d+m)};a.LTRBiRect=function(g,d,h,m){return Int32Array.of(g,d,h,m)};a.XYWHiRect=function(g,d,h,m){return Int32Array.of(g,d,g+h,d+m)};a.RRectXY=function(g,d,h){return Float32Array.of(g[0],g[1],g[2],g[3],d,h,d,h,d,h,d,h)};a.MakeAnimatedImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeAnimatedImage(d,g.byteLength))? +g:null};a.MakeImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeImage(d,g.byteLength))?g:null};var ab=null;a.MakeImageFromCanvasImageSource=function(g){var d=g.width,h=g.height;ab||=document.createElement("canvas");ab.width=d;ab.height=h;var m=ab.getContext("2d",{willReadFrequently:!0});m.drawImage(g,0,0);g=m.getImageData(0,0,d,h);return a.MakeImage({width:d,height:h,alphaType:a.AlphaType.Unpremul,colorType:a.ColorType.RGBA_8888,colorSpace:a.ColorSpace.SRGB}, +g.data,4*d)};a.MakeImage=function(g,d,h){var m=a._malloc(d.length);a.HEAPU8.set(d,m);return a._MakeImage(g,m,d.length,h)};a.MakeVertices=function(g,d,h,m,t,u){var x=t&&t.length||0,C=0;h&&h.length&&(C|=1);m&&m.length&&(C|=2);void 0===u||u||(C|=4);g=new a._VerticesBuilder(g,d.length/2,x,C);n(d,"HEAPF32",g.positions());g.texCoords()&&n(h,"HEAPF32",g.texCoords());g.colors()&&n(c(m),"HEAPU32",g.colors());g.indices()&&n(t,"HEAPU16",g.indices());return g.detach()};(function(g){g.ce=g.ce||[];g.ce.push(function(){function d(q){q&& +(q.dir=0===q.dir?g.TextDirection.RTL:g.TextDirection.LTR);return q}function h(q){if(!q||!q.length)return[];for(var y=[],M=0;Md)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.Font.prototype.getGlyphIntercepts= +function(g,d,h,m){var t=n(g,"HEAPU16"),u=n(d,"HEAPF32");return this._getGlyphIntercepts(t,g.length,!(g&&g._ck),u,d.length,!(d&&d._ck),h,m)};a.Font.prototype.getGlyphWidths=function(g,d,h){var m=n(g,"HEAPU16"),t=a._malloc(4*g.length);this._getGlyphWidthBounds(m,g.length,t,0,d||null);d=new Float32Array(a.HEAPU8.buffer,t,g.length);k(m,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.FontMgr.FromData=function(){if(!arguments.length)return null;var g=arguments;1===g.length&& +Array.isArray(g[0])&&(g=arguments[0]);if(!g.length)return null;for(var d=[],h=[],m=0;md)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.TextBlob.MakeOnPath=function(g,d,h,m){if(g&&g.length&&d&&d.countPoints()){if(1===d.countPoints())return this.MakeFromText(g,h);m||=0;var t=h.getGlyphIDs(g);t=h.getGlyphWidths(t);var u=[];d=new a.ContourMeasureIter(d,!1,1);for(var x= +d.next(),C=new Float32Array(4),G=0;Gx.length()){x.delete();x=d.next();if(!x){g=g.substring(0,G);break}m=F/2}x.getPosTan(m,C);var S=C[2],T=C[3];u.push(S,T,C[0]-F/2*S,C[1]-F/2*T);m+=F/2}g=this.MakeFromRSXform(g,u,h);x&&x.delete();d.delete();return g}};a.TextBlob.MakeFromRSXform=function(g,d,h){var m=qa(g)+1,t=a._malloc(m);ra(g,t,m);g=n(d,"HEAPF32");h=a.TextBlob._MakeFromRSXform(t,m-1,g,h);a._free(t);return h?h:null};a.TextBlob.MakeFromRSXformGlyphs=function(g, +d,h){var m=n(g,"HEAPU16");d=n(d,"HEAPF32");h=a.TextBlob._MakeFromRSXformGlyphs(m,2*g.length,d,h);k(m,g);return h?h:null};a.TextBlob.MakeFromGlyphs=function(g,d){var h=n(g,"HEAPU16");d=a.TextBlob._MakeFromGlyphs(h,2*g.length,d);k(h,g);return d?d:null};a.TextBlob.MakeFromText=function(g,d){var h=qa(g)+1,m=a._malloc(h);ra(g,m,h);g=a.TextBlob._MakeFromText(m,h-1,d);a._free(m);return g?g:null};a.MallocGlyphIDs=function(g){return a.Malloc(Uint16Array,g)}});a.ce=a.ce||[];a.ce.push(function(){a.MakePicture= +function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._MakePicture(d,g.byteLength))?g:null}});a.ce=a.ce||[];a.ce.push(function(){a.RuntimeEffect.Make=function(g,d){return a.RuntimeEffect._Make(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.MakeForBlender=function(g,d){return a.RuntimeEffect._MakeForBlender(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.prototype.makeShader=function(g,d){var h= +!g._ck,m=n(g,"HEAPF32");d=p(d);return this._makeShader(m,4*g.length,h,d)};a.RuntimeEffect.prototype.makeShaderWithChildren=function(g,d,h){var m=!g._ck,t=n(g,"HEAPF32");h=p(h);for(var u=[],x=0;x{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),ua=a=>fetch(a,{credentials:"same-origin"}).then(b=>b.ok?b.arrayBuffer():Promise.reject(Error(b.status+" : "+b.url))); +var xa=console.log.bind(console),ya=console.error.bind(console);Object.assign(r,sa);sa=null;var za,Ba=!1,Ca,B,Da,Fa,E,H,J,Ga;function Ha(){var a=za.buffer;r.HEAP8=Ca=new Int8Array(a);r.HEAP16=Da=new Int16Array(a);r.HEAPU8=B=new Uint8Array(a);r.HEAPU16=Fa=new Uint16Array(a);r.HEAP32=E=new Int32Array(a);r.HEAPU32=H=new Uint32Array(a);r.HEAPF32=J=new Float32Array(a);r.HEAPF64=Ga=new Float64Array(a)}var Ia=[],Ja=[],Ka=[],La=0,Na=null,Oa=null; +function Pa(a){a="Aborted("+a+")";ya(a);Ba=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ca(a);throw a;}var Qa=a=>a.startsWith("data:application/octet-stream;base64,"),Ra;function Sa(a){return ua(a).then(b=>new Uint8Array(b),()=>{if(va)var b=va(a);else throw"both async and sync fetching of the wasm failed";return b})}function Ta(a,b,c){return Sa(a).then(e=>WebAssembly.instantiate(e,b)).then(c,e=>{ya(`failed to asynchronously prepare wasm: ${e}`);Pa(e)})} +function Ua(a,b){var c=Ra;return"function"!=typeof WebAssembly.instantiateStreaming||Qa(c)||"function"!=typeof fetch?Ta(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){ya(`wasm streaming compile failed: ${f}`);ya("falling back to ArrayBuffer instantiation");return Ta(c,a,b)}))}function Va(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}var Wa=a=>{a.forEach(b=>b(r))},Xa=r.noExitRuntime||!0; +class Ya{constructor(a){this.ae=a-24}} +var Za=0,bb=0,cb="undefined"!=typeof TextDecoder?new TextDecoder:void 0,db=(a,b=0,c=NaN)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e}, +eb={},fb=a=>{for(;a.length;){var b=a.pop();a.pop()(b)}};function gb(a){return this.fromWireType(H[a>>2])} +var hb={},ib={},jb={},kb,mb=(a,b,c)=>{function e(l){l=c(l);if(l.length!==a.length)throw new kb("Mismatched type converter count");for(var p=0;pjb[l]=b);var f=Array(b.length),k=[],n=0;b.forEach((l,p)=>{ib.hasOwnProperty(l)?f[p]=ib[l]:(k.push(l),hb.hasOwnProperty(l)||(hb[l]=[]),hb[l].push(()=>{f[p]=ib[l];++n;n===k.length&&e(f)}))});0===k.length&&e(f)},nb,K=a=>{for(var b="";B[a];)b+=nb[B[a++]];return b},L; +function ob(a,b,c={}){var e=b.name;if(!a)throw new L(`type "${e}" must have a positive integer typeid pointer`);if(ib.hasOwnProperty(a)){if(c.lf)return;throw new L(`Cannot register type '${e}' twice`);}ib[a]=b;delete jb[a];hb.hasOwnProperty(a)&&(b=hb[a],delete hb[a],b.forEach(f=>f()))}function lb(a,b,c={}){return ob(a,b,c)} +var pb=a=>{throw new L(a.Yd.de.be.name+" instance already deleted");},qb=!1,rb=()=>{},sb=(a,b,c)=>{if(b===c)return a;if(void 0===c.ge)return null;a=sb(a,b,c.ge);return null===a?null:c.cf(a)},yb={},zb={},Ab=(a,b)=>{if(void 0===b)throw new L("ptr should not be undefined");for(;a.ge;)b=a.ye(b),a=a.ge;return zb[b]},Cb=(a,b)=>{if(!b.de||!b.ae)throw new kb("makeClassHandle requires ptr and ptrType");if(!!b.ie!==!!b.ee)throw new kb("Both smartPtrType and smartPtr must be specified");b.count={value:1};return Bb(Object.create(a, +{Yd:{value:b,writable:!0}}))},Bb=a=>{if("undefined"===typeof FinalizationRegistry)return Bb=b=>b,a;qb=new FinalizationRegistry(b=>{b=b.Yd;--b.count.value;0===b.count.value&&(b.ee?b.ie.ne(b.ee):b.de.be.ne(b.ae))});Bb=b=>{var c=b.Yd;c.ee&&qb.register(b,{Yd:c},b);return b};rb=b=>{qb.unregister(b)};return Bb(a)},Db=[];function Eb(){} +var Fb=(a,b)=>Object.defineProperty(b,"name",{value:a}),Gb=(a,b,c)=>{if(void 0===a[b].fe){var e=a[b];a[b]=function(...f){if(!a[b].fe.hasOwnProperty(f.length))throw new L(`Function '${c}' called with an invalid number of arguments (${f.length}) - expects one of (${a[b].fe})!`);return a[b].fe[f.length].apply(this,f)};a[b].fe=[];a[b].fe[e.oe]=e}},Hb=(a,b,c)=>{if(r.hasOwnProperty(a)){if(void 0===c||void 0!==r[a].fe&&void 0!==r[a].fe[c])throw new L(`Cannot register public name '${a}' twice`);Gb(r,a,a); +if(r[a].fe.hasOwnProperty(c))throw new L(`Cannot register multiple overloads of a function with the same number of arguments (${c})!`);r[a].fe[c]=b}else r[a]=b,r[a].oe=c},Ib=a=>{a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?`_${a}`:a};function Jb(a,b,c,e,f,k,n,l){this.name=a;this.constructor=b;this.se=c;this.ne=e;this.ge=f;this.ff=k;this.ye=n;this.cf=l;this.pf=[]} +var Kb=(a,b,c)=>{for(;b!==c;){if(!b.ye)throw new L(`Expected null or instance of ${c.name}, got an instance of ${b.name}`);a=b.ye(a);b=b.ge}return a};function Lb(a,b){if(null===b){if(this.Ke)throw new L(`null is not a valid ${this.name}`);return 0}if(!b.Yd)throw new L(`Cannot pass "${Mb(b)}" as a ${this.name}`);if(!b.Yd.ae)throw new L(`Cannot pass deleted object as a pointer of type ${this.name}`);return Kb(b.Yd.ae,b.Yd.de.be,this.be)} +function Nb(a,b){if(null===b){if(this.Ke)throw new L(`null is not a valid ${this.name}`);if(this.De){var c=this.Le();null!==a&&a.push(this.ne,c);return c}return 0}if(!b||!b.Yd)throw new L(`Cannot pass "${Mb(b)}" as a ${this.name}`);if(!b.Yd.ae)throw new L(`Cannot pass deleted object as a pointer of type ${this.name}`);if(!this.Ce&&b.Yd.de.Ce)throw new L(`Cannot convert argument of type ${b.Yd.ie?b.Yd.ie.name:b.Yd.de.name} to parameter type ${this.name}`);c=Kb(b.Yd.ae,b.Yd.de.be,this.be);if(this.De){if(void 0=== +b.Yd.ee)throw new L("Passing raw pointer to smart pointer is illegal");switch(this.uf){case 0:if(b.Yd.ie===this)c=b.Yd.ee;else throw new L(`Cannot convert argument of type ${b.Yd.ie?b.Yd.ie.name:b.Yd.de.name} to parameter type ${this.name}`);break;case 1:c=b.Yd.ee;break;case 2:if(b.Yd.ie===this)c=b.Yd.ee;else{var e=b.clone();c=this.qf(c,Ob(()=>e["delete"]()));null!==a&&a.push(this.ne,c)}break;default:throw new L("Unsupporting sharing policy");}}return c} +function Pb(a,b){if(null===b){if(this.Ke)throw new L(`null is not a valid ${this.name}`);return 0}if(!b.Yd)throw new L(`Cannot pass "${Mb(b)}" as a ${this.name}`);if(!b.Yd.ae)throw new L(`Cannot pass deleted object as a pointer of type ${this.name}`);if(b.Yd.de.Ce)throw new L(`Cannot convert argument of type ${b.Yd.de.name} to parameter type ${this.name}`);return Kb(b.Yd.ae,b.Yd.de.be,this.be)} +function Qb(a,b,c,e,f,k,n,l,p,v,w){this.name=a;this.be=b;this.Ke=c;this.Ce=e;this.De=f;this.nf=k;this.uf=n;this.Se=l;this.Le=p;this.qf=v;this.ne=w;f||void 0!==b.ge?this.toWireType=Nb:(this.toWireType=e?Lb:Pb,this.ke=null)} +var Rb=(a,b,c)=>{if(!r.hasOwnProperty(a))throw new kb("Replacing nonexistent public symbol");void 0!==r[a].fe&&void 0!==c?r[a].fe[c]=b:(r[a]=b,r[a].oe=c)},N,Sb=(a,b,c=[])=>{a.includes("j")?(a=a.replace(/p/g,"i"),b=(0,r["dynCall_"+a])(b,...c)):b=N.get(b)(...c);return b},Tb=(a,b)=>(...c)=>Sb(a,b,c),O=(a,b)=>{a=K(a);var c=a.includes("j")?Tb(a,b):N.get(b);if("function"!=typeof c)throw new L(`unknown function pointer with signature ${a}: ${b}`);return c},ac,dc=a=>{a=bc(a);var b=K(a);cc(a);return b},ec= +(a,b)=>{function c(k){f[k]||ib[k]||(jb[k]?jb[k].forEach(c):(e.push(k),f[k]=!0))}var e=[],f={};b.forEach(c);throw new ac(`${a}: `+e.map(dc).join([", "]));};function fc(a){for(var b=1;bk)throw new L("argTypes array size mismatch! Must at least get return value and 'this' types!");var n=null!==b[1]&&null!==c,l=fc(b),p="void"!==b[0].name,v=k-2,w=Array(v),A=[],D=[];return Fb(a,function(...I){D.length=0;A.length=n?2:1;A[0]=f;if(n){var Q=b[1].toWireType(D,this);A[1]=Q}for(var P=0;P{for(var c=[],e=0;e>2]);return c},ic=a=>{a=a.trim();const b=a.indexOf("(");return-1!==b?a.substr(0,b):a},jc=[],kc=[],lc=a=>{9{if(!a)throw new L("Cannot use deleted val. handle = "+a);return kc[a]},Ob=a=>{switch(a){case void 0:return 2;case null:return 4;case !0:return 6;case !1:return 8;default:const b=jc.pop()||kc.length;kc[b]=a;kc[b+1]=1;return b}},nc={name:"emscripten::val",fromWireType:a=>{var b=mc(a);lc(a); +return b},toWireType:(a,b)=>Ob(b),je:8,readValueFromPointer:gb,ke:null},oc=(a,b,c)=>{switch(b){case 1:return c?function(e){return this.fromWireType(Ca[e])}:function(e){return this.fromWireType(B[e])};case 2:return c?function(e){return this.fromWireType(Da[e>>1])}:function(e){return this.fromWireType(Fa[e>>1])};case 4:return c?function(e){return this.fromWireType(E[e>>2])}:function(e){return this.fromWireType(H[e>>2])};default:throw new TypeError(`invalid integer width (${b}): ${a}`);}},pc=(a,b)=> +{var c=ib[a];if(void 0===c)throw a=`${b} has unknown type ${dc(a)}`,new L(a);return c},Mb=a=>{if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a},qc=(a,b)=>{switch(b){case 4:return function(c){return this.fromWireType(J[c>>2])};case 8:return function(c){return this.fromWireType(Ga[c>>3])};default:throw new TypeError(`invalid float width (${b}): ${a}`);}},rc=(a,b,c)=>{switch(b){case 1:return c?e=>Ca[e]:e=>B[e];case 2:return c?e=>Da[e>>1]:e=>Fa[e>> +1];case 4:return c?e=>E[e>>2]:e=>H[e>>2];default:throw new TypeError(`invalid integer width (${b}): ${a}`);}},ra=(a,b,c)=>{var e=B;if(!(0=n){var l=a.charCodeAt(++k);n=65536+((n&1023)<<10)|l&1023}if(127>=n){if(b>=c)break;e[b++]=n}else{if(2047>=n){if(b+1>=c)break;e[b++]=192|n>>6}else{if(65535>=n){if(b+2>=c)break;e[b++]=224|n>>12}else{if(b+3>=c)break;e[b++]=240|n>>18;e[b++]=128|n>>12&63}e[b++]=128|n>>6& +63}e[b++]=128|n&63}}e[b]=0;return b-f},qa=a=>{for(var b=0,c=0;c=e?b++:2047>=e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}return b},sc="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0,tc=(a,b)=>{var c=a>>1;for(var e=c+b/2;!(c>=e)&&Fa[c];)++c;c<<=1;if(32=b/2);++e){var f=Da[a+2*e>>1];if(0==f)break;c+=String.fromCharCode(f)}return c},uc=(a,b,c)=>{c??=2147483647;if(2>c)return 0;c-=2;var e= +b;c=c<2*a.length?c/2:a.length;for(var f=0;f>1]=a.charCodeAt(f),b+=2;Da[b>>1]=0;return b-e},vc=a=>2*a.length,wc=(a,b)=>{for(var c=0,e="";!(c>=b/4);){var f=E[a+4*c>>2];if(0==f)break;++c;65536<=f?(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023)):e+=String.fromCharCode(f)}return e},xc=(a,b,c)=>{c??=2147483647;if(4>c)return 0;var e=b;c=e+c-4;for(var f=0;f=k){var n=a.charCodeAt(++f);k=65536+((k&1023)<<10)|n&1023}E[b>>2]=k;b+= +4;if(b+4>c)break}E[b>>2]=0;return b-e},yc=a=>{for(var b=0,c=0;c=e&&++c;b+=4}return b},zc=(a,b,c)=>{var e=[];a=a.toWireType(e,c);e.length&&(H[b>>2]=Ob(e));return a},Ac=[],Bc={},Cc=a=>{var b=Bc[a];return void 0===b?K(a):b},Dc=()=>{function a(b){b.$$$embind_global$$$=b;var c="object"==typeof $$$embind_global$$$&&b.$$$embind_global$$$==b;c||delete b.$$$embind_global$$$;return c}if("object"==typeof globalThis)return globalThis;if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$; +"object"==typeof global&&a(global)?$$$embind_global$$$=global:"object"==typeof self&&a(self)&&($$$embind_global$$$=self);if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;throw Error("unable to get global object.");},Ec=a=>{var b=Ac.length;Ac.push(a);return b},Fc=(a,b)=>{for(var c=Array(a),e=0;e>2],"parameter "+e);return c},Gc=Reflect.construct,R,Hc=a=>{var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=(c,e)=>b.vertexAttribDivisorANGLE(c, +e),a.drawArraysInstanced=(c,e,f,k)=>b.drawArraysInstancedANGLE(c,e,f,k),a.drawElementsInstanced=(c,e,f,k,n)=>b.drawElementsInstancedANGLE(c,e,f,k,n))},Ic=a=>{var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=()=>b.createVertexArrayOES(),a.deleteVertexArray=c=>b.deleteVertexArrayOES(c),a.bindVertexArray=c=>b.bindVertexArrayOES(c),a.isVertexArray=c=>b.isVertexArrayOES(c))},Jc=a=>{var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=(c,e)=>b.drawBuffersWEBGL(c,e))},Kc=a=> +{var b="ANGLE_instanced_arrays EXT_blend_minmax EXT_disjoint_timer_query EXT_frag_depth EXT_shader_texture_load EXT_sRGB OES_element_index_uint OES_fbo_render_mipmap OES_standard_derivatives OES_texture_float OES_texture_half_float OES_texture_half_float_linear OES_vertex_array_object WEBGL_color_buffer_float WEBGL_depth_texture WEBGL_draw_buffers EXT_color_buffer_float EXT_conservative_depth EXT_disjoint_timer_query_webgl2 EXT_texture_norm16 NV_shader_noperspective_interpolation WEBGL_clip_cull_distance EXT_clip_control EXT_color_buffer_half_float EXT_depth_clamp EXT_float_blend EXT_polygon_offset_clamp EXT_texture_compression_bptc EXT_texture_compression_rgtc EXT_texture_filter_anisotropic KHR_parallel_shader_compile OES_texture_float_linear WEBGL_blend_func_extended WEBGL_compressed_texture_astc WEBGL_compressed_texture_etc WEBGL_compressed_texture_etc1 WEBGL_compressed_texture_s3tc WEBGL_compressed_texture_s3tc_srgb WEBGL_debug_renderer_info WEBGL_debug_shaders WEBGL_lose_context WEBGL_multi_draw WEBGL_polygon_mode".split(" "); +return(a.getSupportedExtensions()||[]).filter(c=>b.includes(c))},Lc=1,Mc=[],Nc=[],Oc=[],Pc=[],ka=[],Qc=[],Rc=[],pa=[],Sc=[],Tc=[],Uc=[],Wc={},Xc={},Yc=4,Zc=0,ja=a=>{for(var b=Lc++,c=a.length;c{for(var f=0;f>2]=n}},na=(a,b)=>{a.Ne||(a.Ne=a.getContext,a.getContext=function(e,f){f=a.Ne(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1{var c=ja(pa),e={handle:c,attributes:b,version:b.majorVersion,le:a};a.canvas&&(a.canvas.Ve=e);pa[c]=e;("undefined"==typeof b.df||b.df)&&bd(e);return c},oa=a=>{z=pa[a];r.vf=R=z?.le;return!(a&&!R)},bd=a=>{a||=z;if(!a.mf){a.mf=!0;var b=a.le;b.zf=b.getExtension("WEBGL_multi_draw");b.xf=b.getExtension("EXT_polygon_offset_clamp");b.wf=b.getExtension("EXT_clip_control");b.Bf=b.getExtension("WEBGL_polygon_mode");Hc(b);Ic(b);Jc(b);b.Pe=b.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"); +b.Re=b.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance");2<=a.version&&(b.me=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.me)b.me=b.getExtension("EXT_disjoint_timer_query");Kc(b).forEach(c=>{c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}},z,U,cd=(a,b)=>{R.bindFramebuffer(a,Oc[b])},dd=a=>{R.bindVertexArray(Rc[a])},ed=a=>R.clear(a),fd=(a,b,c,e)=>R.clearColor(a,b,c,e),gd=a=>R.clearStencil(a),hd=(a,b)=>{for(var c=0;c>2];R.deleteVertexArray(Rc[e]);Rc[e]=null}},jd=[],kd=(a,b)=>{$c(a,b,"createVertexArray",Rc)};function ld(){var a=Kc(R);return a=a.concat(a.map(b=>"GL_"+b))} +var md=(a,b,c)=>{if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&(U||=1280);return;case 34814:case 36345:e=0;break;case 34466:var f=R.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>z.version){U||=1282;return}e=ld().length;break;case 33307:case 33308:if(2>z.version){U||=1280;return}e=33307==a?3:0}if(void 0===e)switch(f=R.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":U||=1280;return;case "object":if(null===f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e= +0;break;default:U||=1280;return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a>2]=f[a];break;case 2:J[b+4*a>>2]=f[a];break;case 4:Ca[b+a]=f[a]?1:0}return}try{e=f.name|0}catch(k){U||=1280;ya(`GL_INVALID_ENUM in glGet${c}v: Unknown object returned from WebGL getParameter(${a})! (error: ${k})`);return}}break;default:U||=1280;ya(`GL_INVALID_ENUM in glGet${c}v: Native code calling glGet${c}v(${a}) and it returns ${f} of type ${typeof f}!`); +return}switch(c){case 1:c=e;H[b>>2]=c;H[b+4>>2]=(c-H[b>>2])/4294967296;break;case 0:E[b>>2]=e;break;case 2:J[b>>2]=e;break;case 4:Ca[b]=e?1:0}}else U||=1281},and=(a,b)=>md(a,b,0),od=(a,b,c)=>{if(c){a=Sc[a];b=2>z.version?R.me.getQueryObjectEXT(a,b):R.getQueryParameter(a,b);var e;"boolean"==typeof b?e=b?1:0:e=b;H[c>>2]=e;H[c+4>>2]=(e-H[c>>2])/4294967296}else U||=1281},qd=a=>{var b=qa(a)+1,c=pd(b);c&&ra(a,c,b);return c},rd=a=>{var b=Wc[a];if(!b){switch(a){case 7939:b=qd(ld().join(" "));break;case 7936:case 7937:case 37445:case 37446:(b= +R.getParameter(a))||(U||=1280);b=b?qd(b):0;break;case 7938:b=R.getParameter(7938);var c=`OpenGL ES 2.0 (${b})`;2<=z.version&&(c=`OpenGL ES 3.0 (${b})`);b=qd(c);break;case 35724:b=R.getParameter(35724);c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b=`OpenGL ES GLSL ES ${c[1]} (${b})`);b=qd(b);break;default:U||=1280}Wc[a]=b}return b},sd=(a,b)=>{if(2>z.version)return U||=1282,0;var c=Xc[a];if(c)return 0>b||b>=c.length?(U||=1281,0):c[b];switch(a){case 7939:return c= +ld().map(qd),c=Xc[a]=c,0>b||b>=c.length?(U||=1281,0):c[b];default:return U||=1280,0}},td=a=>"]"==a.slice(-1)&&a.lastIndexOf("["),ud=a=>{a-=5120;return 0==a?Ca:1==a?B:2==a?Da:4==a?E:6==a?J:5==a||28922==a||28520==a||30779==a||30782==a?H:Fa},vd=(a,b,c,e,f)=>{a=ud(a);b=e*((Zc||c)*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*a.BYTES_PER_ELEMENT+Yc-1&-Yc);return a.subarray(f>>>31-Math.clz32(a.BYTES_PER_ELEMENT),f+b>>>31-Math.clz32(a.BYTES_PER_ELEMENT))},Y=a=>{var b=R.bf;if(b){var c= +b.xe[a];"number"==typeof c&&(b.xe[a]=c=R.getUniformLocation(b,b.Te[a]+(0{if(!zd){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:"./this.program"},b;for(b in yd)void 0===yd[b]?delete a[b]:a[b]=yd[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);zd=c}return zd},zd,Bd=[null,[],[]]; +kb=r.InternalError=class extends Error{constructor(a){super(a);this.name="InternalError"}};for(var Cd=Array(256),Dd=0;256>Dd;++Dd)Cd[Dd]=String.fromCharCode(Dd);nb=Cd;L=r.BindingError=class extends Error{constructor(a){super(a);this.name="BindingError"}}; +Object.assign(Eb.prototype,{isAliasOf:function(a){if(!(this instanceof Eb&&a instanceof Eb))return!1;var b=this.Yd.de.be,c=this.Yd.ae;a.Yd=a.Yd;var e=a.Yd.de.be;for(a=a.Yd.ae;b.ge;)c=b.ye(c),b=b.ge;for(;e.ge;)a=e.ye(a),e=e.ge;return b===e&&c===a},clone:function(){this.Yd.ae||pb(this);if(this.Yd.we)return this.Yd.count.value+=1,this;var a=Bb,b=Object,c=b.create,e=Object.getPrototypeOf(this),f=this.Yd;a=a(c.call(b,e,{Yd:{value:{count:f.count,ve:f.ve,we:f.we,ae:f.ae,de:f.de,ee:f.ee,ie:f.ie}}}));a.Yd.count.value+= +1;a.Yd.ve=!1;return a},["delete"](){this.Yd.ae||pb(this);if(this.Yd.ve&&!this.Yd.we)throw new L("Object already scheduled for deletion");rb(this);var a=this.Yd;--a.count.value;0===a.count.value&&(a.ee?a.ie.ne(a.ee):a.de.be.ne(a.ae));this.Yd.we||(this.Yd.ee=void 0,this.Yd.ae=void 0)},isDeleted:function(){return!this.Yd.ae},deleteLater:function(){this.Yd.ae||pb(this);if(this.Yd.ve&&!this.Yd.we)throw new L("Object already scheduled for deletion");Db.push(this);this.Yd.ve=!0;return this}}); +Object.assign(Qb.prototype,{gf(a){this.Se&&(a=this.Se(a));return a},Oe(a){this.ne?.(a)},je:8,readValueFromPointer:gb,fromWireType:function(a){function b(){return this.De?Cb(this.be.se,{de:this.nf,ae:c,ie:this,ee:a}):Cb(this.be.se,{de:this,ae:a})}var c=this.gf(a);if(!c)return this.Oe(a),null;var e=Ab(this.be,c);if(void 0!==e){if(0===e.Yd.count.value)return e.Yd.ae=c,e.Yd.ee=a,e.clone();e=e.clone();this.Oe(a);return e}e=this.be.ff(c);e=yb[e];if(!e)return b.call(this);e=this.Ce?e.af:e.pointerType;var f= +sb(c,this.be,e.be);return null===f?b.call(this):this.De?Cb(e.be.se,{de:e,ae:f,ie:this,ee:a}):Cb(e.be.se,{de:e,ae:f})}});ac=r.UnboundTypeError=((a,b)=>{var c=Fb(b,function(e){this.name=b;this.message=e;e=Error(e).stack;void 0!==e&&(this.stack=this.toString()+"\n"+e.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(a.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`};return c})(Error,"UnboundTypeError"); +kc.push(0,1,void 0,1,null,1,!0,1,!1,1);r.count_emval_handles=()=>kc.length/2-5-jc.length;for(var Ed=0;32>Ed;++Ed)jd.push(Array(Ed));var Fd=new Float32Array(288);for(Ed=0;288>=Ed;++Ed)wd[Ed]=Fd.subarray(0,Ed);var Gd=new Int32Array(288);for(Ed=0;288>=Ed;++Ed)xd[Ed]=Gd.subarray(0,Ed); +var Vd={F:(a,b,c)=>{var e=new Ya(a);H[e.ae+16>>2]=0;H[e.ae+4>>2]=b;H[e.ae+8>>2]=c;Za=a;bb++;throw Za;},V:function(){return 0},vd:()=>{},ud:function(){return 0},td:()=>{},sd:()=>{},U:function(){},rd:()=>{},and:()=>{Pa("")},B:a=>{var b=eb[a];delete eb[a];var c=b.Le,e=b.ne,f=b.Qe,k=f.map(n=>n.kf).concat(f.map(n=>n.sf));mb([a],k,n=>{var l={};f.forEach((p,v)=>{var w=n[v],A=p.hf,D=p.jf,I=n[v+f.length],Q=p.rf,P=p.tf;l[p.ef]={read:aa=>w.fromWireType(A(D,aa)),write:(aa,la)=>{var X=[];Q(P,aa,I.toWireType(X, +la));fb(X)}}});return[{name:b.name,fromWireType:p=>{var v={},w;for(w in l)v[w]=l[w].read(p);e(p);return v},toWireType:(p,v)=>{for(var w in l)if(!(w in v))throw new TypeError(`Missing field: "${w}"`);var A=c();for(w in l)l[w].write(A,v[w]);null!==p&&p.push(e,A);return A},je:8,readValueFromPointer:gb,ke:e}]})},Y:()=>{},md:(a,b,c,e)=>{b=K(b);lb(a,{name:b,fromWireType:function(f){return!!f},toWireType:function(f,k){return k?c:e},je:8,readValueFromPointer:function(f){return this.fromWireType(B[f])},ke:null})}, +l:(a,b,c,e,f,k,n,l,p,v,w,A,D)=>{w=K(w);k=O(f,k);l&&=O(n,l);v&&=O(p,v);D=O(A,D);var I=Ib(w);Hb(I,function(){ec(`Cannot construct ${w} due to unbound types`,[e])});mb([a,b,c],e?[e]:[],Q=>{Q=Q[0];if(e){var P=Q.be;var aa=P.se}else aa=Eb.prototype;Q=Fb(w,function(...Ea){if(Object.getPrototypeOf(this)!==la)throw new L("Use 'new' to construct "+w);if(void 0===X.pe)throw new L(w+" has no accessible constructor");var ea=X.pe[Ea.length];if(void 0===ea)throw new L(`Tried to invoke ctor of ${w} with invalid number of parameters (${Ea.length}) - expected (${Object.keys(X.pe).toString()}) parameters instead!`); +return ea.apply(this,Ea)});var la=Object.create(aa,{constructor:{value:Q}});Q.prototype=la;var X=new Jb(w,Q,la,D,P,k,l,v);if(X.ge){var ha;(ha=X.ge).ze??(ha.ze=[]);X.ge.ze.push(X)}P=new Qb(w,X,!0,!1,!1);ha=new Qb(w+"*",X,!1,!1,!1);aa=new Qb(w+" const*",X,!1,!0,!1);yb[a]={pointerType:ha,af:aa};Rb(I,Q);return[P,ha,aa]})},e:(a,b,c,e,f,k,n)=>{var l=hc(c,e);b=K(b);b=ic(b);k=O(f,k);mb([],[a],p=>{function v(){ec(`Cannot call ${w} due to unbound types`,l)}p=p[0];var w=`${p.name}.${b}`;b.startsWith("@@")&& +(b=Symbol[b.substring(2)]);var A=p.be.constructor;void 0===A[b]?(v.oe=c-1,A[b]=v):(Gb(A,b,w),A[b].fe[c-1]=v);mb([],l,D=>{D=[D[0],null].concat(D.slice(1));D=gc(w,D,null,k,n);void 0===A[b].fe?(D.oe=c-1,A[b]=D):A[b].fe[c-1]=D;if(p.be.ze)for(const I of p.be.ze)I.constructor.hasOwnProperty(b)||(I.constructor[b]=D);return[]});return[]})},z:(a,b,c,e,f,k)=>{var n=hc(b,c);f=O(e,f);mb([],[a],l=>{l=l[0];var p=`constructor ${l.name}`;void 0===l.be.pe&&(l.be.pe=[]);if(void 0!==l.be.pe[b-1])throw new L(`Cannot register multiple constructors with identical number of parameters (${b- +1}) for class '${l.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);l.be.pe[b-1]=()=>{ec(`Cannot construct ${l.name} due to unbound types`,n)};mb([],n,v=>{v.splice(1,0,null);l.be.pe[b-1]=gc(p,v,null,f,k);return[]});return[]})},a:(a,b,c,e,f,k,n,l)=>{var p=hc(c,e);b=K(b);b=ic(b);k=O(f,k);mb([],[a],v=>{function w(){ec(`Cannot call ${A} due to unbound types`,p)}v=v[0];var A=`${v.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);l&&v.be.pf.push(b); +var D=v.be.se,I=D[b];void 0===I||void 0===I.fe&&I.className!==v.name&&I.oe===c-2?(w.oe=c-2,w.className=v.name,D[b]=w):(Gb(D,b,A),D[b].fe[c-2]=w);mb([],p,Q=>{Q=gc(A,Q,v,k,n);void 0===D[b].fe?(Q.oe=c-2,D[b]=Q):D[b].fe[c-2]=Q;return[]});return[]})},q:(a,b,c)=>{a=K(a);mb([],[b],e=>{e=e[0];r[a]=e.fromWireType(c);return[]})},ld:a=>lb(a,nc),j:(a,b,c,e)=>{function f(){}b=K(b);f.values={};lb(a,{name:b,constructor:f,fromWireType:function(k){return this.constructor.values[k]},toWireType:(k,n)=>n.value,je:8, +readValueFromPointer:oc(b,c,e),ke:null});Hb(b,f)},b:(a,b,c)=>{var e=pc(a,"enum");b=K(b);a=e.constructor;e=Object.create(e.constructor.prototype,{value:{value:c},constructor:{value:Fb(`${e.name}_${b}`,function(){})}});a.values[c]=e;a[b]=e},S:(a,b,c)=>{b=K(b);lb(a,{name:b,fromWireType:e=>e,toWireType:(e,f)=>f,je:8,readValueFromPointer:qc(b,c),ke:null})},w:(a,b,c,e,f,k)=>{var n=hc(b,c);a=K(a);a=ic(a);f=O(e,f);Hb(a,function(){ec(`Cannot call ${a} due to unbound types`,n)},b-1);mb([],n,l=>{l=[l[0],null].concat(l.slice(1)); +Rb(a,gc(a,l,null,f,k),b-1);return[]})},C:(a,b,c,e,f)=>{b=K(b);-1===f&&(f=4294967295);f=l=>l;if(0===e){var k=32-8*c;f=l=>l<>>k}var n=b.includes("unsigned")?function(l,p){return p>>>0}:function(l,p){return p};lb(a,{name:b,fromWireType:f,toWireType:n,je:8,readValueFromPointer:rc(b,c,0!==e),ke:null})},p:(a,b,c)=>{function e(k){return new f(Ca.buffer,H[k+4>>2],H[k>>2])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=K(c);lb(a,{name:c,fromWireType:e, +je:8,readValueFromPointer:e},{lf:!0})},o:(a,b,c,e,f,k,n,l,p,v,w,A)=>{c=K(c);k=O(f,k);l=O(n,l);v=O(p,v);A=O(w,A);mb([a],[b],D=>{D=D[0];return[new Qb(c,D.be,!1,!1,!0,D,e,k,l,v,A)]})},R:(a,b)=>{b=K(b);var c="std::string"===b;lb(a,{name:b,fromWireType:function(e){var f=H[e>>2],k=e+4;if(c)for(var n=k,l=0;l<=f;++l){var p=k+l;if(l==f||0==B[p]){n=n?db(B,n,p-n):"";if(void 0===v)var v=n;else v+=String.fromCharCode(0),v+=n;n=p+1}}else{v=Array(f);for(l=0;l>2]=n;if(c&&k)ra(f,p,n+1);else if(k)for(k=0;k{c=K(c);if(2===b){var e=tc;var f=uc;var k=vc;var n=l=>Fa[l>>1]}else 4===b&&(e=wc,f=xc,k=yc,n=l=>H[l>>2]);lb(a,{name:c,fromWireType:l=>{for(var p=H[l>>2],v,w=l+4,A=0;A<=p;++A){var D=l+4+A*b;if(A==p||0==n(D))w=e(w,D-w),void 0===v?v=w:(v+=String.fromCharCode(0),v+=w),w=D+b}cc(l);return v},toWireType:(l,p)=>{if("string"!=typeof p)throw new L(`Cannot pass non-string to C++ string type ${c}`);var v=k(p),w=pd(4+v+b); +H[w>>2]=v/b;f(p,w+4,v+b);null!==l&&l.push(cc,w);return w},je:8,readValueFromPointer:gb,ke(l){cc(l)}})},A:(a,b,c,e,f,k)=>{eb[a]={name:K(b),Le:O(c,e),ne:O(f,k),Qe:[]}},d:(a,b,c,e,f,k,n,l,p,v)=>{eb[a].Qe.push({ef:K(b),kf:c,hf:O(e,f),jf:k,sf:n,rf:O(l,p),tf:v})},kd:(a,b)=>{b=K(b);lb(a,{yf:!0,name:b,je:0,fromWireType:()=>{},toWireType:()=>{}})},jd:()=>1,id:()=>{throw Infinity;},E:(a,b,c)=>{a=mc(a);b=pc(b,"emval::as");return zc(b,c,a)},L:(a,b,c,e)=>{a=Ac[a];b=mc(b);return a(null,b,c,e)},t:(a,b,c,e,f)=>{a= +Ac[a];b=mc(b);c=Cc(c);return a(b,b[c],e,f)},c:lc,K:a=>{if(0===a)return Ob(Dc());a=Cc(a);return Ob(Dc()[a])},n:(a,b,c)=>{var e=Fc(a,b),f=e.shift();a--;var k=Array(a);b=`methodCaller<(${e.map(n=>n.name).join(", ")}) => ${f.name}>`;return Ec(Fb(b,(n,l,p,v)=>{for(var w=0,A=0;A{a=mc(a);b=mc(b);return Ob(a[b])},H:a=>{9Ob([]),f:a=>Ob(Cc(a)),D:()=>Ob({}),hd:a=>{a=mc(a); +return!a},m:a=>{var b=mc(a);fb(b);lc(a)},h:(a,b,c)=>{a=mc(a);b=mc(b);c=mc(c);a[b]=c},g:(a,b)=>{a=pc(a,"_emval_take_value");a=a.readValueFromPointer(b);return Ob(a)},X:function(){return-52},W:function(){},gd:(a,b,c,e)=>{var f=(new Date).getFullYear(),k=(new Date(f,0,1)).getTimezoneOffset();f=(new Date(f,6,1)).getTimezoneOffset();H[a>>2]=60*Math.max(k,f);E[b>>2]=Number(k!=f);b=n=>{var l=Math.abs(n);return`UTC${0<=n?"-":"+"}${String(Math.floor(l/60)).padStart(2,"0")}${String(l%60).padStart(2,"0")}`}; +a=b(k);b=b(f);fperformance.now(),ed:a=>R.activeTexture(a),dd:(a,b)=>{R.attachShader(Nc[a],Qc[b])},cd:(a,b)=>{R.beginQuery(a,Sc[b])},bd:(a,b)=>{R.me.beginQueryEXT(a,Sc[b])},ad:(a,b,c)=>{R.bindAttribLocation(Nc[a],b,c?db(B,c):"")},$c:(a,b)=>{35051==a?R.Ie=b:35052==a&&(R.re=b);R.bindBuffer(a,Mc[b])},_c:cd,Zc:(a,b)=>{R.bindRenderbuffer(a,Pc[b])},Yc:(a,b)=>{R.bindSampler(a,Tc[b])},Xc:(a,b)=>{R.bindTexture(a,ka[b])},Wc:dd,Vc:dd,Uc:(a,b,c,e)=>R.blendColor(a, +b,c,e),Tc:a=>R.blendEquation(a),Sc:(a,b)=>R.blendFunc(a,b),Rc:(a,b,c,e,f,k,n,l,p,v)=>R.blitFramebuffer(a,b,c,e,f,k,n,l,p,v),Qc:(a,b,c,e)=>{2<=z.version?c&&b?R.bufferData(a,B,e,c,b):R.bufferData(a,b,e):R.bufferData(a,c?B.subarray(c,c+b):b,e)},Pc:(a,b,c,e)=>{2<=z.version?c&&R.bufferSubData(a,b,B,e,c):R.bufferSubData(a,b,B.subarray(e,e+c))},Oc:a=>R.checkFramebufferStatus(a),Nc:ed,Mc:fd,Lc:gd,Kc:(a,b,c,e)=>R.clientWaitSync(Uc[a],b,(c>>>0)+4294967296*e),Jc:(a,b,c,e)=>{R.colorMask(!!a,!!b,!!c,!!e)},Ic:a=> +{R.compileShader(Qc[a])},Hc:(a,b,c,e,f,k,n,l)=>{2<=z.version?R.re||!n?R.compressedTexImage2D(a,b,c,e,f,k,n,l):R.compressedTexImage2D(a,b,c,e,f,k,B,l,n):R.compressedTexImage2D(a,b,c,e,f,k,B.subarray(l,l+n))},Gc:(a,b,c,e,f,k,n,l,p)=>{2<=z.version?R.re||!l?R.compressedTexSubImage2D(a,b,c,e,f,k,n,l,p):R.compressedTexSubImage2D(a,b,c,e,f,k,n,B,p,l):R.compressedTexSubImage2D(a,b,c,e,f,k,n,B.subarray(p,p+l))},Fc:(a,b,c,e,f)=>R.copyBufferSubData(a,b,c,e,f),Ec:(a,b,c,e,f,k,n,l)=>R.copyTexSubImage2D(a,b,c, +e,f,k,n,l),Dc:()=>{var a=ja(Nc),b=R.createProgram();b.name=a;b.Ge=b.Ee=b.Fe=0;b.Me=1;Nc[a]=b;return a},Cc:a=>{var b=ja(Qc);Qc[b]=R.createShader(a);return b},Bc:a=>R.cullFace(a),Ac:(a,b)=>{for(var c=0;c>2],f=Mc[e];f&&(R.deleteBuffer(f),f.name=0,Mc[e]=null,e==R.Ie&&(R.Ie=0),e==R.re&&(R.re=0))}},zc:(a,b)=>{for(var c=0;c>2],f=Oc[e];f&&(R.deleteFramebuffer(f),f.name=0,Oc[e]=null)}},yc:a=>{if(a){var b=Nc[a];b?(R.deleteProgram(b),b.name=0,Nc[a]=null):U||=1281}}, +xc:(a,b)=>{for(var c=0;c>2],f=Sc[e];f&&(R.deleteQuery(f),Sc[e]=null)}},wc:(a,b)=>{for(var c=0;c>2],f=Sc[e];f&&(R.me.deleteQueryEXT(f),Sc[e]=null)}},vc:(a,b)=>{for(var c=0;c>2],f=Pc[e];f&&(R.deleteRenderbuffer(f),f.name=0,Pc[e]=null)}},uc:(a,b)=>{for(var c=0;c>2],f=Tc[e];f&&(R.deleteSampler(f),f.name=0,Tc[e]=null)}},tc:a=>{if(a){var b=Qc[a];b?(R.deleteShader(b),Qc[a]=null):U||=1281}},sc:a=>{if(a){var b=Uc[a];b? +(R.deleteSync(b),b.name=0,Uc[a]=null):U||=1281}},rc:(a,b)=>{for(var c=0;c>2],f=ka[e];f&&(R.deleteTexture(f),f.name=0,ka[e]=null)}},qc:hd,pc:hd,oc:a=>{R.depthMask(!!a)},nc:a=>R.disable(a),mc:a=>{R.disableVertexAttribArray(a)},lc:(a,b,c)=>{R.drawArrays(a,b,c)},kc:(a,b,c,e)=>{R.drawArraysInstanced(a,b,c,e)},jc:(a,b,c,e,f)=>{R.Pe.drawArraysInstancedBaseInstanceWEBGL(a,b,c,e,f)},ic:(a,b)=>{for(var c=jd[a],e=0;e>2];R.drawBuffers(c)},hc:(a,b,c,e)=>{R.drawElements(a, +b,c,e)},gc:(a,b,c,e,f)=>{R.drawElementsInstanced(a,b,c,e,f)},fc:(a,b,c,e,f,k,n)=>{R.Pe.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,b,c,e,f,k,n)},ec:(a,b,c,e,f,k)=>{R.drawElements(a,e,f,k)},dc:a=>R.enable(a),cc:a=>{R.enableVertexAttribArray(a)},bc:a=>R.endQuery(a),ac:a=>{R.me.endQueryEXT(a)},$b:(a,b)=>(a=R.fenceSync(a,b))?(b=ja(Uc),a.name=b,Uc[b]=a,b):0,_b:()=>R.finish(),Zb:()=>R.flush(),Yb:(a,b,c,e)=>{R.framebufferRenderbuffer(a,b,c,Pc[e])},Xb:(a,b,c,e,f)=>{R.framebufferTexture2D(a,b,c,ka[e], +f)},Wb:a=>R.frontFace(a),Vb:(a,b)=>{$c(a,b,"createBuffer",Mc)},Ub:(a,b)=>{$c(a,b,"createFramebuffer",Oc)},Tb:(a,b)=>{$c(a,b,"createQuery",Sc)},Sb:(a,b)=>{for(var c=0;c>2]=0;break}var f=ja(Sc);e.name=f;Sc[f]=e;E[b+4*c>>2]=f}},Rb:(a,b)=>{$c(a,b,"createRenderbuffer",Pc)},Qb:(a,b)=>{$c(a,b,"createSampler",Tc)},Pb:(a,b)=>{$c(a,b,"createTexture",ka)},Ob:kd,Nb:kd,Mb:a=>R.generateMipmap(a),Lb:(a,b,c)=>{c?E[c>>2]=R.getBufferParameter(a, +b):U||=1281},Kb:()=>{var a=R.getError()||U;U=0;return a},Jb:(a,b)=>md(a,b,2),Ib:(a,b,c,e)=>{a=R.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;E[e>>2]=a},Hb:and,Gb:(a,b,c,e)=>{a=R.getProgramInfoLog(Nc[a]);null===a&&(a="(unknown error)");b=0>2]=b)},Fb:(a,b,c)=>{if(c)if(a>=Lc)U||=1281;else if(a=Nc[a],35716==b)a=R.getProgramInfoLog(a),null===a&&(a="(unknown error)"),E[c>>2]=a.length+1;else if(35719==b){if(!a.Ge){var e= +R.getProgramParameter(a,35718);for(b=0;b>2]=a.Ge}else if(35722==b){if(!a.Ee)for(e=R.getProgramParameter(a,35721),b=0;b>2]=a.Ee}else if(35381==b){if(!a.Fe)for(e=R.getProgramParameter(a,35382),b=0;b>2]=a.Fe}else E[c>>2]=R.getProgramParameter(a,b);else U||=1281},Eb:od,Db:od,Cb:(a,b,c)=>{if(c){a= +R.getQueryParameter(Sc[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;E[c>>2]=e}else U||=1281},Bb:(a,b,c)=>{if(c){a=R.me.getQueryObjectEXT(Sc[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;E[c>>2]=e}else U||=1281},Ab:(a,b,c)=>{c?E[c>>2]=R.getQuery(a,b):U||=1281},zb:(a,b,c)=>{c?E[c>>2]=R.me.getQueryEXT(a,b):U||=1281},yb:(a,b,c)=>{c?E[c>>2]=R.getRenderbufferParameter(a,b):U||=1281},xb:(a,b,c,e)=>{a=R.getShaderInfoLog(Qc[a]);null===a&&(a="(unknown error)");b=0>2]=b)},wb:(a,b,c,e)=> +{a=R.getShaderPrecisionFormat(a,b);E[c>>2]=a.rangeMin;E[c+4>>2]=a.rangeMax;E[e>>2]=a.precision},vb:(a,b,c)=>{c?35716==b?(a=R.getShaderInfoLog(Qc[a]),null===a&&(a="(unknown error)"),E[c>>2]=a?a.length+1:0):35720==b?(a=R.getShaderSource(Qc[a]),E[c>>2]=a?a.length+1:0):E[c>>2]=R.getShaderParameter(Qc[a],b):U||=1281},ub:rd,tb:sd,sb:(a,b)=>{b=b?db(B,b):"";if(a=Nc[a]){var c=a,e=c.xe,f=c.Ue,k;if(!e){c.xe=e={};c.Te={};var n=R.getProgramParameter(c,35718);for(k=0;k>>0,f=b.slice(0,k));if((f=a.Ue[f])&&e{for(var e=jd[b],f=0;f>2];R.invalidateFramebuffer(a,e)},qb:(a,b,c,e,f,k,n)=>{for(var l=jd[b],p=0;p>2];R.invalidateSubFramebuffer(a,l,e,f,k,n)},pb:a=>R.isSync(Uc[a]), +ob:a=>(a=ka[a])?R.isTexture(a):0,nb:a=>R.lineWidth(a),mb:a=>{a=Nc[a];R.linkProgram(a);a.xe=0;a.Ue={}},lb:(a,b,c,e,f,k)=>{R.Re.multiDrawArraysInstancedBaseInstanceWEBGL(a,E,b>>2,E,c>>2,E,e>>2,H,f>>2,k)},kb:(a,b,c,e,f,k,n,l)=>{R.Re.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,E,b>>2,c,E,e>>2,E,f>>2,E,k>>2,H,n>>2,l)},jb:(a,b)=>{3317==a?Yc=b:3314==a&&(Zc=b);R.pixelStorei(a,b)},ib:(a,b)=>{R.me.queryCounterEXT(Sc[a],b)},hb:a=>R.readBuffer(a),gb:(a,b,c,e,f,k,n)=>{if(2<=z.version)if(R.Ie)R.readPixels(a, +b,c,e,f,k,n);else{var l=ud(k);n>>>=31-Math.clz32(l.BYTES_PER_ELEMENT);R.readPixels(a,b,c,e,f,k,l,n)}else(l=vd(k,f,c,e,n))?R.readPixels(a,b,c,e,f,k,l):U||=1280},fb:(a,b,c,e)=>R.renderbufferStorage(a,b,c,e),eb:(a,b,c,e,f)=>R.renderbufferStorageMultisample(a,b,c,e,f),db:(a,b,c)=>{R.samplerParameterf(Tc[a],b,c)},cb:(a,b,c)=>{R.samplerParameteri(Tc[a],b,c)},bb:(a,b,c)=>{R.samplerParameteri(Tc[a],b,E[c>>2])},ab:(a,b,c,e)=>R.scissor(a,b,c,e),$a:(a,b,c,e)=>{for(var f="",k=0;k>2])? +db(B,n,e?H[e+4*k>>2]:void 0):"";f+=n}R.shaderSource(Qc[a],f)},_a:(a,b,c)=>R.stencilFunc(a,b,c),Za:(a,b,c,e)=>R.stencilFuncSeparate(a,b,c,e),Ya:a=>R.stencilMask(a),Xa:(a,b)=>R.stencilMaskSeparate(a,b),Wa:(a,b,c)=>R.stencilOp(a,b,c),Va:(a,b,c,e)=>R.stencilOpSeparate(a,b,c,e),Ua:(a,b,c,e,f,k,n,l,p)=>{if(2<=z.version){if(R.re){R.texImage2D(a,b,c,e,f,k,n,l,p);return}if(p){var v=ud(l);p>>>=31-Math.clz32(v.BYTES_PER_ELEMENT);R.texImage2D(a,b,c,e,f,k,n,l,v,p);return}}v=p?vd(l,n,e,f,p):null;R.texImage2D(a, +b,c,e,f,k,n,l,v)},Ta:(a,b,c)=>R.texParameterf(a,b,c),Sa:(a,b,c)=>{R.texParameterf(a,b,J[c>>2])},Ra:(a,b,c)=>R.texParameteri(a,b,c),Qa:(a,b,c)=>{R.texParameteri(a,b,E[c>>2])},Pa:(a,b,c,e,f)=>R.texStorage2D(a,b,c,e,f),Oa:(a,b,c,e,f,k,n,l,p)=>{if(2<=z.version){if(R.re){R.texSubImage2D(a,b,c,e,f,k,n,l,p);return}if(p){var v=ud(l);R.texSubImage2D(a,b,c,e,f,k,n,l,v,p>>>31-Math.clz32(v.BYTES_PER_ELEMENT));return}}p=p?vd(l,n,f,k,p):null;R.texSubImage2D(a,b,c,e,f,k,n,l,p)},Na:(a,b)=>{R.uniform1f(Y(a),b)},Ma:(a, +b,c)=>{if(2<=z.version)b&&R.uniform1fv(Y(a),J,c>>2,b);else{if(288>=b)for(var e=wd[b],f=0;f>2];else e=J.subarray(c>>2,c+4*b>>2);R.uniform1fv(Y(a),e)}},La:(a,b)=>{R.uniform1i(Y(a),b)},Ka:(a,b,c)=>{if(2<=z.version)b&&R.uniform1iv(Y(a),E,c>>2,b);else{if(288>=b)for(var e=xd[b],f=0;f>2];else e=E.subarray(c>>2,c+4*b>>2);R.uniform1iv(Y(a),e)}},Ja:(a,b,c)=>{R.uniform2f(Y(a),b,c)},Ia:(a,b,c)=>{if(2<=z.version)b&&R.uniform2fv(Y(a),J,c>>2,2*b);else{if(144>=b){b*=2;for(var e= +wd[b],f=0;f>2],e[f+1]=J[c+(4*f+4)>>2]}else e=J.subarray(c>>2,c+8*b>>2);R.uniform2fv(Y(a),e)}},Ha:(a,b,c)=>{R.uniform2i(Y(a),b,c)},Ga:(a,b,c)=>{if(2<=z.version)b&&R.uniform2iv(Y(a),E,c>>2,2*b);else{if(144>=b){b*=2;for(var e=xd[b],f=0;f>2],e[f+1]=E[c+(4*f+4)>>2]}else e=E.subarray(c>>2,c+8*b>>2);R.uniform2iv(Y(a),e)}},Fa:(a,b,c,e)=>{R.uniform3f(Y(a),b,c,e)},Ea:(a,b,c)=>{if(2<=z.version)b&&R.uniform3fv(Y(a),J,c>>2,3*b);else{if(96>=b){b*=3;for(var e=wd[b],f=0;f< +b;f+=3)e[f]=J[c+4*f>>2],e[f+1]=J[c+(4*f+4)>>2],e[f+2]=J[c+(4*f+8)>>2]}else e=J.subarray(c>>2,c+12*b>>2);R.uniform3fv(Y(a),e)}},Da:(a,b,c,e)=>{R.uniform3i(Y(a),b,c,e)},Ca:(a,b,c)=>{if(2<=z.version)b&&R.uniform3iv(Y(a),E,c>>2,3*b);else{if(96>=b){b*=3;for(var e=xd[b],f=0;f>2],e[f+1]=E[c+(4*f+4)>>2],e[f+2]=E[c+(4*f+8)>>2]}else e=E.subarray(c>>2,c+12*b>>2);R.uniform3iv(Y(a),e)}},Ba:(a,b,c,e,f)=>{R.uniform4f(Y(a),b,c,e,f)},Aa:(a,b,c)=>{if(2<=z.version)b&&R.uniform4fv(Y(a),J,c>>2,4* +b);else{if(72>=b){var e=wd[4*b],f=J;c>>=2;b*=4;for(var k=0;k>2,c+16*b>>2);R.uniform4fv(Y(a),e)}},za:(a,b,c,e,f)=>{R.uniform4i(Y(a),b,c,e,f)},ya:(a,b,c)=>{if(2<=z.version)b&&R.uniform4iv(Y(a),E,c>>2,4*b);else{if(72>=b){b*=4;for(var e=xd[b],f=0;f>2],e[f+1]=E[c+(4*f+4)>>2],e[f+2]=E[c+(4*f+8)>>2],e[f+3]=E[c+(4*f+12)>>2]}else e=E.subarray(c>>2,c+16*b>>2);R.uniform4iv(Y(a),e)}},xa:(a,b,c,e)=> +{if(2<=z.version)b&&R.uniformMatrix2fv(Y(a),!!c,J,e>>2,4*b);else{if(72>=b){b*=4;for(var f=wd[b],k=0;k>2],f[k+1]=J[e+(4*k+4)>>2],f[k+2]=J[e+(4*k+8)>>2],f[k+3]=J[e+(4*k+12)>>2]}else f=J.subarray(e>>2,e+16*b>>2);R.uniformMatrix2fv(Y(a),!!c,f)}},wa:(a,b,c,e)=>{if(2<=z.version)b&&R.uniformMatrix3fv(Y(a),!!c,J,e>>2,9*b);else{if(32>=b){b*=9;for(var f=wd[b],k=0;k>2],f[k+1]=J[e+(4*k+4)>>2],f[k+2]=J[e+(4*k+8)>>2],f[k+3]=J[e+(4*k+12)>>2],f[k+4]=J[e+(4*k+16)>>2],f[k+ +5]=J[e+(4*k+20)>>2],f[k+6]=J[e+(4*k+24)>>2],f[k+7]=J[e+(4*k+28)>>2],f[k+8]=J[e+(4*k+32)>>2]}else f=J.subarray(e>>2,e+36*b>>2);R.uniformMatrix3fv(Y(a),!!c,f)}},va:(a,b,c,e)=>{if(2<=z.version)b&&R.uniformMatrix4fv(Y(a),!!c,J,e>>2,16*b);else{if(18>=b){var f=wd[16*b],k=J;e>>=2;b*=16;for(var n=0;n>2,e+64*b>>2);R.uniformMatrix4fv(Y(a),!!c,f)}},ua:a=>{a=Nc[a];R.useProgram(a);R.bf=a},ta:(a,b)=>R.vertexAttrib1f(a,b),sa:(a,b)=>{R.vertexAttrib2f(a,J[b>>2],J[b+4>>2])},ra:(a,b)=>{R.vertexAttrib3f(a,J[b>>2],J[b+4>>2],J[b+8>>2])},qa:(a,b)=>{R.vertexAttrib4f(a,J[b>>2],J[b+4>>2],J[b+8>>2],J[b+12>>2])},pa:(a,b)=>{R.vertexAttribDivisor(a,b)},oa:(a,b,c,e,f)=>{R.vertexAttribIPointer(a,b,c,e,f)},na:(a,b,c,e,f,k)=>{R.vertexAttribPointer(a,b,c, +!!e,f,k)},ma:(a,b,c,e)=>R.viewport(a,b,c,e),la:(a,b,c,e)=>{R.waitSync(Uc[a],b,(c>>>0)+4294967296*e)},ka:a=>{var b=B.length;a>>>=0;if(2147483648=c;c*=2){var e=b*(1+1/c);e=Math.min(e,a+100663296);a:{e=(Math.min(2147483648,65536*Math.ceil(Math.max(a,e)/65536))-za.buffer.byteLength+65535)/65536|0;try{za.grow(e);Ha();var f=1;break a}catch(k){}f=void 0}if(f)return!0}return!1},ja:()=>z?z.handle:0,qd:(a,b)=>{var c=0;Ad().forEach((e,f)=>{var k=b+c;f=H[a+4*f>>2]=k;for(k=0;k{var c=Ad();H[a>>2]=c.length;var e=0;c.forEach(f=>e+=f.length+1);H[b>>2]=e;return 0},ia:a=>{Xa||(Ba=!0);throw new Va(a);},N:()=>52,_:function(){return 52},od:()=>52,Z:function(){return 70},T:(a,b,c,e)=>{for(var f=0,k=0;k>2],l=H[b+4>>2];b+=8;for(var p=0;p>2]=f;return 0},ha:cd,ga:ed,fa:fd,ea:gd,J:and,Q:rd,da:sd,k:Hd,u:Id,i:Jd,I:Kd, +ca:Ld,P:Md,O:And,s:Od,x:Pd,r:Qd,v:Rd,ba:Sd,aa:Td,$:Ud},Z=function(){function a(c){Z=c.exports;za=Z.wd;Ha();N=Z.zd;Ja.unshift(Z.xd);La--;0==La&&(null!==Na&&(clearInterval(Na),Na=null),Oa&&(c=Oa,Oa=null,c()));return Z}var b={a:Vd};La++;if(r.instantiateWasm)try{return r.instantiateWasm(b,a)}catch(c){ya(`Module.instantiateWasm callback failed with error: ${c}`),ca(c)}Ra??=r.locateFile?Qa("canvaskit.wasm")?"canvaskit.wasm":ta+"canvaskit.wasm":(new URL("canvaskit.wasm",import.meta.url)).href; +Ua(b,function(c){a(c.instance)}).catch(ca);return{}}(),bc=a=>(bc=Z.yd)(a),pd=r._malloc=a=>(pd=r._malloc=Z.Ad)(a),cc=r._free=a=>(cc=r._free=Z.Bd)(a),Wd=(a,b)=>(Wd=Z.Cd)(a,b),Xd=a=>(Xd=Z.Dd)(a),Yd=()=>(Yd=Z.Ed)();r.dynCall_viji=(a,b,c,e,f)=>(r.dynCall_viji=Z.Fd)(a,b,c,e,f);r.dynCall_vijiii=(a,b,c,e,f,k,n)=>(r.dynCall_vijiii=Z.Gd)(a,b,c,e,f,k,n);r.dynCall_viiiiij=(a,b,c,e,f,k,n,l)=>(r.dynCall_viiiiij=Z.Hd)(a,b,c,e,f,k,n,l);r.dynCall_iiiji=(a,b,c,e,f,k)=>(r.dynCall_iiiji=Z.Id)(a,b,c,e,f,k); +r.dynCall_jii=(a,b,c)=>(r.dynCall_jii=Z.Jd)(a,b,c);r.dynCall_vij=(a,b,c,e)=>(r.dynCall_vij=Z.Kd)(a,b,c,e);r.dynCall_jiiiiii=(a,b,c,e,f,k,n)=>(r.dynCall_jiiiiii=Z.Ld)(a,b,c,e,f,k,n);r.dynCall_jiiiiji=(a,b,c,e,f,k,n,l)=>(r.dynCall_jiiiiji=Z.Md)(a,b,c,e,f,k,n,l);r.dynCall_ji=(a,b)=>(r.dynCall_ji=Z.And)(a,b);r.dynCall_iijj=(a,b,c,e,f,k)=>(r.dynCall_iijj=Z.Od)(a,b,c,e,f,k);r.dynCall_iiji=(a,b,c,e,f)=>(r.dynCall_iiji=Z.Pd)(a,b,c,e,f); +r.dynCall_iijjiii=(a,b,c,e,f,k,n,l,p)=>(r.dynCall_iijjiii=Z.Qd)(a,b,c,e,f,k,n,l,p);r.dynCall_iij=(a,b,c,e)=>(r.dynCall_iij=Z.Rd)(a,b,c,e);r.dynCall_vijjjii=(a,b,c,e,f,k,n,l,p,v)=>(r.dynCall_vijjjii=Z.Sd)(a,b,c,e,f,k,n,l,p,v);r.dynCall_jiji=(a,b,c,e,f)=>(r.dynCall_jiji=Z.Td)(a,b,c,e,f);r.dynCall_viijii=(a,b,c,e,f,k,n)=>(r.dynCall_viijii=Z.Ud)(a,b,c,e,f,k,n);r.dynCall_iiiiij=(a,b,c,e,f,k,n)=>(r.dynCall_iiiiij=Z.Vd)(a,b,c,e,f,k,n); +r.dynCall_iiiiijj=(a,b,c,e,f,k,n,l,p)=>(r.dynCall_iiiiijj=Z.Wd)(a,b,c,e,f,k,n,l,p);r.dynCall_iiiiiijj=(a,b,c,e,f,k,n,l,p,v)=>(r.dynCall_iiiiiijj=Z.Xd)(a,b,c,e,f,k,n,l,p,v);function Rd(a,b,c,e,f){var k=Yd();try{N.get(a)(b,c,e,f)}catch(n){Xd(k);if(n!==n+0)throw n;Wd(1,0)}}function Id(a,b,c){var e=Yd();try{return N.get(a)(b,c)}catch(f){Xd(e);if(f!==f+0)throw f;Wd(1,0)}}function Pd(a,b,c){var e=Yd();try{N.get(a)(b,c)}catch(f){Xd(e);if(f!==f+0)throw f;Wd(1,0)}} +function Hd(a,b){var c=Yd();try{return N.get(a)(b)}catch(e){Xd(c);if(e!==e+0)throw e;Wd(1,0)}}function Od(a,b){var c=Yd();try{N.get(a)(b)}catch(e){Xd(c);if(e!==e+0)throw e;Wd(1,0)}}function Jd(a,b,c,e){var f=Yd();try{return N.get(a)(b,c,e)}catch(k){Xd(f);if(k!==k+0)throw k;Wd(1,0)}}function Ud(a,b,c,e,f,k,n,l,p,v){var w=Yd();try{N.get(a)(b,c,e,f,k,n,l,p,v)}catch(A){Xd(w);if(A!==A+0)throw A;Wd(1,0)}}function Qd(a,b,c,e){var f=Yd();try{N.get(a)(b,c,e)}catch(k){Xd(f);if(k!==k+0)throw k;Wd(1,0)}} +function Td(a,b,c,e,f,k,n){var l=Yd();try{N.get(a)(b,c,e,f,k,n)}catch(p){Xd(l);if(p!==p+0)throw p;Wd(1,0)}}function Md(a,b,c,e,f,k,n,l){var p=Yd();try{return N.get(a)(b,c,e,f,k,n,l)}catch(v){Xd(p);if(v!==v+0)throw v;Wd(1,0)}}function Sd(a,b,c,e,f,k){var n=Yd();try{N.get(a)(b,c,e,f,k)}catch(l){Xd(n);if(l!==l+0)throw l;Wd(1,0)}}function Kd(a,b,c,e,f){var k=Yd();try{return N.get(a)(b,c,e,f)}catch(n){Xd(k);if(n!==n+0)throw n;Wd(1,0)}} +function And(a,b,c,e,f,k,n,l,p,v){var w=Yd();try{return N.get(a)(b,c,e,f,k,n,l,p,v)}catch(A){Xd(w);if(A!==A+0)throw A;Wd(1,0)}}function Ld(a,b,c,e,f,k,n){var l=Yd();try{return N.get(a)(b,c,e,f,k,n)}catch(p){Xd(l);if(p!==p+0)throw p;Wd(1,0)}}var Zd,$d;Oa=function ae(){Zd||be();Zd||(Oa=ae)};function be(){if(!(0\28SkColorSpace*\29 +241:__memcpy +242:SkString::~SkString\28\29 +243:__memset +244:GrGLSLShaderBuilder::codeAppendf\28char\20const*\2c\20...\29 +245:SkColorInfo::~SkColorInfo\28\29 +246:SkData::~SkData\28\29 +247:SkString::SkString\28\29 +248:memmove +249:uprv_free_74 +250:SkContainerAllocator::allocate\28int\2c\20double\29 +251:memcmp +252:SkString::insert\28unsigned\20long\2c\20char\20const*\29 +253:SkDebugf\28char\20const*\2c\20...\29 +254:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::~__func\28\29 +255:uprv_malloc_74 +256:strlen +257:SkPath::~SkPath\28\29 +258:hb_blob_destroy +259:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\29 +260:SkArenaAlloc::ensureSpace\28unsigned\20int\2c\20unsigned\20int\29 +261:sk_report_container_overflow_and_die\28\29 +262:SkSL::ErrorReporter::error\28SkSL::Position\2c\20std::__2::basic_string_view>\29 +263:ft_mem_free +264:strcmp +265:SkRasterPipeline::append\28SkRasterPipelineOp\2c\20void*\29 +266:SkString::SkString\28char\20const*\29 +267:emscripten::default_smart_ptr_trait>::share\28void*\29 +268:FT_MulFix +269:__wasm_setjmp_test +270:SkTDStorage::append\28\29 +271:SkMatrix::computeTypeMask\28\29\20const +272:SkWriter32::growToAtLeast\28unsigned\20long\29 +273:GrGpuResource::notifyARefCntIsZero\28GrIORef::LastRemovedRef\29\20const +274:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\2c\20unsigned\20long\29 +275:fmaxf +276:std::__2::basic_string\2c\20std::__2::allocator>::size\5babi:nn180100\5d\28\29\20const +277:SkString::SkString\28SkString&&\29 +278:SkSL::Pool::AllocMemory\28unsigned\20long\29 +279:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:ne180100\5d\28\29\20const +280:GrColorInfo::~GrColorInfo\28\29 +281:SkIRect::intersect\28SkIRect\20const&\2c\20SkIRect\20const&\29 +282:GrBackendFormat::~GrBackendFormat\28\29 +283:std::__2::basic_string\2c\20std::__2::allocator>::insert\28unsigned\20long\2c\20char\20const*\29 +284:GrContext_Base::caps\28\29\20const +285:icu_74::UnicodeString::~UnicodeString\28\29 +286:icu_74::UMemory::operator\20delete\28void*\29 +287:SkPaint::~SkPaint\28\29 +288:void\20emscripten::internal::raw_destructor\28SkContourMeasure*\29 +289:SkTDStorage::~SkTDStorage\28\29 +290:std::__2::vector>::__throw_length_error\5babi:ne180100\5d\28\29\20const +291:SkSL::RP::Generator::pushExpression\28SkSL::Expression\20const&\2c\20bool\29 +292:SkTDStorage::SkTDStorage\28int\29 +293:SkStrokeRec::getStyle\28\29\20const +294:SkString::SkString\28SkString\20const&\29 +295:sk_malloc_throw\28unsigned\20long\2c\20unsigned\20long\29 +296:icu_74::MaybeStackArray::~MaybeStackArray\28\29 +297:SkFontMgr*\20emscripten::base::convertPointer\28skia::textlayout::TypefaceFontProvider*\29 +298:hb_ot_map_builder_t::add_feature\28unsigned\20int\2c\20hb_ot_map_feature_flags_t\2c\20unsigned\20int\29 +299:SkMatrix::mapRect\28SkRect*\2c\20SkRect\20const&\2c\20SkApplyPerspectiveClip\29\20const +300:SkBitmap::~SkBitmap\28\29 +301:fminf +302:SkArenaAlloc::installFooter\28char*\20\28*\29\28char*\29\2c\20unsigned\20int\29 +303:icu_74::CharString::append\28char\20const*\2c\20int\2c\20UErrorCode&\29 +304:SkArenaAlloc::allocObjectWithFooter\28unsigned\20int\2c\20unsigned\20int\29 +305:hb_buffer_t::make_room_for\28unsigned\20int\2c\20unsigned\20int\29 +306:strncmp +307:SkArenaAlloc::~SkArenaAlloc\28\29 +308:skia_private::TArray::push_back\28SkPoint\20const&\29 +309:SkString::operator=\28SkString&&\29 +310:SkSemaphore::osSignal\28int\29 +311:SkPath::SkPath\28\29 +312:skia_png_error +313:hb_buffer_t::message\28hb_font_t*\2c\20char\20const*\2c\20...\29 +314:SkSL::Parser::nextRawToken\28\29 +315:SkMatrix::computePerspectiveTypeMask\28\29\20const +316:icu_74::StringPiece::StringPiece\28char\20const*\29 +317:std::__2::__shared_weak_count::__release_weak\28\29 +318:SkSemaphore::osWait\28\29 +319:SkColorInfo::SkColorInfo\28SkColorInfo\20const&\29 +320:ft_mem_realloc +321:SkIntersections::insert\28double\2c\20double\2c\20SkDPoint\20const&\29 +322:FT_DivFix +323:SkString::appendf\28char\20const*\2c\20...\29 +324:uprv_isASCIILetter_74 +325:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +326:skia_png_free +327:utext_setNativeIndex_74 +328:utext_getNativeIndex_74 +329:ures_closeBundle\28UResourceBundle*\2c\20signed\20char\29 +330:std::__throw_bad_array_new_length\5babi:ne180100\5d\28\29 +331:skia_png_crc_finish +332:SkPath::lineTo\28float\2c\20float\29 +333:SkMatrix::setTranslate\28float\2c\20float\29 +334:skia_png_chunk_benign_error +335:SkChecksum::Hash32\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20int\29 +336:SkMatrix::mapPoints\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +337:SkBlitter::~SkBlitter\28\29 +338:ft_mem_qrealloc +339:skia_png_warning +340:SkColorInfo::bytesPerPixel\28\29\20const +341:OT::VarData::get_delta\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20OT::VarRegionList\20const&\2c\20float*\29\20const +342:GrGLExtensions::has\28char\20const*\29\20const +343:icu_74::MaybeStackArray::MaybeStackArray\28\29 +344:SkPaint::SkPaint\28SkPaint\20const&\29 +345:FT_Stream_Seek +346:emscripten_builtin_malloc +347:GrVertexChunkBuilder::allocChunk\28int\29 +348:dlrealloc +349:OT::DeltaSetIndexMap::map\28unsigned\20int\29\20const +350:strchr +351:SkReadBuffer::readUInt\28\29 +352:SkMatrix::reset\28\29 +353:SkImageInfo::MakeUnknown\28int\2c\20int\29 +354:GrSurfaceProxyView::asRenderTargetProxy\28\29\20const +355:skia_private::TArray::push_back\28unsigned\20long\20const&\29 +356:hb_lazy_loader_t\2c\20hb_face_t\2c\2028u\2c\20hb_blob_t>::do_destroy\28hb_blob_t*\29 +357:SkBitmap::SkBitmap\28\29 +358:skia_private::TArray::push_back\28unsigned\20char&&\29 +359:SkPath::SkPath\28SkPath\20const&\29 +360:strstr +361:SkPaint::SkPaint\28\29 +362:ft_validator_error +363:skia_private::TArray\2c\20true>::push_back\28sk_sp&&\29 +364:hb_buffer_t::_set_glyph_flags\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +365:SkOpPtT::segment\28\29\20const +366:GrTextureGenerator::isTextureGenerator\28\29\20const +367:skgpu::Swizzle::Swizzle\28char\20const*\29 +368:sk_malloc_flags\28unsigned\20long\2c\20unsigned\20int\29 +369:SkSL::Parser::expect\28SkSL::Token::Kind\2c\20char\20const*\2c\20SkSL::Token*\29 +370:SkImageGenerator::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +371:SkMatrix::invertNonIdentity\28SkMatrix*\29\20const +372:uhash_close_74 +373:SkSL::RP::Builder::appendInstruction\28SkSL::RP::BuilderOp\2c\20SkSL::RP::Builder::SlotList\2c\20int\2c\20int\2c\20int\2c\20int\29 +374:FT_Stream_ReadUShort +375:skia_private::TArray::push_back\28SkSL::RP::Instruction&&\29 +376:skia_png_get_uint_32 +377:skia_png_calculate_crc +378:std::__2::basic_string\2c\20std::__2::allocator>::resize\5babi:nn180100\5d\28unsigned\20long\29 +379:SkSL::GLSLCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +380:std::__2::basic_string\2c\20std::__2::allocator>::__get_pointer\5babi:nn180100\5d\28\29 +381:std::__2::__throw_bad_function_call\5babi:ne180100\5d\28\29 +382:SkRect::join\28SkRect\20const&\29 +383:SkPoint::Length\28float\2c\20float\29 +384:GrImageInfo::GrImageInfo\28GrImageInfo\20const&\29 +385:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +386:std::__2::locale::~locale\28\29 +387:icu_74::CharString::append\28char\2c\20UErrorCode&\29 +388:SkLoadICULib\28\29 +389:ucptrie_internalSmallIndex_74 +390:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28char\29 +391:skia_private::TArray::push_back\28SkString&&\29 +392:SkPathRef::Editor::Editor\28sk_sp*\2c\20int\2c\20int\2c\20int\29 +393:SkRect::intersect\28SkRect\20const&\29 +394:SkRasterPipeline::uncheckedAppend\28SkRasterPipelineOp\2c\20void*\29 +395:SkPath::getBounds\28\29\20const +396:strcpy +397:skia_private::TArray>\2c\20true>::operator=\28skia_private::TArray>\2c\20true>&&\29 +398:hb_blob_reference +399:emscripten_builtin_calloc +400:cf2_stack_popFixed +401:SkJSONWriter::appendName\28char\20const*\29 +402:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +403:SkRect::setBoundsCheck\28SkPoint\20const*\2c\20int\29 +404:SkCachedData::internalUnref\28bool\29\20const +405:GrProcessor::operator\20new\28unsigned\20long\29 +406:FT_MulDiv +407:std::__2::to_string\28int\29 +408:icu_74::UnicodeString::doAppend\28char16_t\20const*\2c\20int\2c\20int\29 +409:std::__2::ios_base::getloc\28\29\20const +410:SkRuntimeEffect::uniformSize\28\29\20const +411:SkJSONWriter::beginValue\28bool\29 +412:umtx_unlock_74 +413:subtag_matches\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20int\29 +414:skia_png_read_push_finish_row +415:skia::textlayout::TextStyle::~TextStyle\28\29 +416:hb_blob_make_immutable +417:SkString::operator=\28char\20const*\29 +418:SkColorInfo::operator=\28SkColorInfo&&\29 +419:hb_ot_map_builder_t::add_pause\28unsigned\20int\2c\20bool\20\28*\29\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29\29 +420:embind_init_Paragraph\28\29::$_10::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +421:VP8GetValue +422:SkSemaphore::~SkSemaphore\28\29 +423:SkReadBuffer::setInvalid\28\29 +424:SkColorInfo::operator=\28SkColorInfo\20const&\29 +425:uhash_get_74 +426:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28\29 +427:skgpu::ganesh::SurfaceContext::caps\28\29\20const +428:icu_74::UnicodeSet::~UnicodeSet\28\29 +429:icu_74::UnicodeSet::contains\28int\29\20const +430:SkRegion::~SkRegion\28\29 +431:SkPoint::normalize\28\29 +432:SkImageGenerator::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +433:utext_next32_74 +434:jdiv_round_up +435:SkSL::RP::Builder::binary_op\28SkSL::RP::BuilderOp\2c\20int\29 +436:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +437:jzero_far +438:SkPathRef::growForVerb\28int\2c\20float\29 +439:SkColorInfo::SkColorInfo\28SkColorInfo&&\29 +440:SkArenaAlloc::SkArenaAlloc\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +441:FT_Stream_ExitFrame +442:skia_png_write_data +443:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +444:abort +445:SkMatrix::setConcat\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +446:umtx_lock_74 +447:skia_private::TArray::push_back_raw\28int\29 +448:hb_blob_get_data_writable +449:__shgetc +450:SkSL::SymbolTable::addWithoutOwnershipOrDie\28SkSL::Symbol*\29 +451:SkBlitter::~SkBlitter\28\29_1455 +452:FT_Stream_GetUShort +453:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28wchar_t\20const*\29 +454:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28char\20const*\29 +455:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +456:SkPoint::scale\28float\2c\20SkPoint*\29\20const +457:SkIRect\20skif::Mapping::map\28SkIRect\20const&\2c\20SkMatrix\20const&\29 +458:sktext::gpu::BagOfBytes::~BagOfBytes\28\29 +459:icu_74::UVector32::expandCapacity\28int\2c\20UErrorCode&\29 +460:SkSL::String::printf\28char\20const*\2c\20...\29 +461:GrSurfaceProxyView::asTextureProxy\28\29\20const +462:GrOp::GenOpClassID\28\29 +463:round +464:SkStringPrintf\28char\20const*\2c\20...\29 +465:RoughlyEqualUlps\28float\2c\20float\29 +466:GrGLSLVaryingHandler::addVarying\28char\20const*\2c\20GrGLSLVarying*\2c\20GrGLSLVaryingHandler::Interpolation\29 +467:skia_png_chunk_error +468:SkTDStorage::reserve\28int\29 +469:SkPath::Iter::next\28SkPoint*\29 +470:SkDynamicMemoryWStream::write\28void\20const*\2c\20unsigned\20long\29 +471:GrQuad::MakeFromRect\28SkRect\20const&\2c\20SkMatrix\20const&\29 +472:GrFragmentProcessor::ProgramImpl::invokeChild\28int\2c\20char\20const*\2c\20char\20const*\2c\20GrFragmentProcessor::ProgramImpl::EmitArgs&\2c\20std::__2::basic_string_view>\29 +473:SkSurfaceProps::SkSurfaceProps\28\29 +474:SkStrikeSpec::~SkStrikeSpec\28\29 +475:SkSL::TProgramVisitor::visitStatement\28SkSL::Statement\20const&\29 +476:SkSL::RP::Builder::discard_stack\28int\2c\20int\29 +477:SkRecord::grow\28\29 +478:SkRGBA4f<\28SkAlphaType\293>::toBytes_RGBA\28\29\20const +479:GrProcessor::operator\20new\28unsigned\20long\2c\20unsigned\20long\29 +480:skgpu::ganesh::SurfaceDrawContext::addDrawOp\28GrClip\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::function\20const&\29 +481:skgpu::ResourceKeyHash\28unsigned\20int\20const*\2c\20unsigned\20long\29 +482:icu_74::UVector::elementAt\28int\29\20const +483:hb_face_reference_table +484:VP8LoadFinalBytes +485:SkSL::FunctionDeclaration::description\28\29\20const +486:SkPictureRecord::addDraw\28DrawType\2c\20unsigned\20long*\29::'lambda'\28\29::operator\28\29\28\29\20const +487:SkPath::conicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\29 +488:SkCanvas::predrawNotify\28bool\29 +489:OT::Layout::Common::Coverage::get_coverage\28unsigned\20int\29\20const +490:std::__2::__cloc\28\29 +491:sscanf +492:SkStream::readS32\28int*\29 +493:SkPath::moveTo\28float\2c\20float\29 +494:SkMatrix::postTranslate\28float\2c\20float\29 +495:GrSkSLFP::GrSkSLFP\28sk_sp\2c\20char\20const*\2c\20GrSkSLFP::OptFlags\29 +496:GrBackendFormat::GrBackendFormat\28\29 +497:icu_74::umtx_initImplPreInit\28icu_74::UInitOnce&\29 +498:icu_74::umtx_initImplPostInit\28icu_74::UInitOnce&\29 +499:__multf3 +500:VP8LReadBits +501:SkTDStorage::append\28int\29 +502:SkSL::evaluate_n_way_intrinsic\28SkSL::Context\20const&\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +503:SkMatrix::setScale\28float\2c\20float\29 +504:GrOpsRenderPass::setScissorRect\28SkIRect\20const&\29 +505:GrOpsRenderPass::bindPipeline\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +506:GrCaps::getDefaultBackendFormat\28GrColorType\2c\20skgpu::Renderable\29\20const +507:skia_private::TArray::push_back_raw\28int\29 +508:hb_draw_funcs_t::start_path\28void*\2c\20hb_draw_state_t&\29 +509:SkRuntimeEffect::MakeForShader\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +510:GrSimpleMeshDrawOpHelper::~GrSimpleMeshDrawOpHelper\28\29 +511:GrProcessorSet::GrProcessorSet\28GrPaint&&\29 +512:GrBackendFormats::AsGLFormat\28GrBackendFormat\20const&\29 +513:FT_Stream_EnterFrame +514:uprv_realloc_74 +515:std::__2::locale::id::__get\28\29 +516:std::__2::locale::facet::facet\5babi:nn180100\5d\28unsigned\20long\29 +517:emscripten_longjmp +518:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29 +519:SkPath::reset\28\29 +520:SkPath::operator=\28SkPath\20const&\29 +521:SkColorSpaceXformSteps::SkColorSpaceXformSteps\28SkColorSpace\20const*\2c\20SkAlphaType\2c\20SkColorSpace\20const*\2c\20SkAlphaType\29 +522:OT::hb_ot_apply_context_t::match_properties_mark\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +523:GrGeometryProcessor::AttributeSet::initImplicit\28GrGeometryProcessor::Attribute\20const*\2c\20int\29 +524:GrContext_Base::contextID\28\29\20const +525:AlmostEqualUlps\28float\2c\20float\29 +526:udata_close_74 +527:ucln_common_registerCleanup_74 +528:std::__2::locale::__imp::install\28std::__2::locale::facet*\2c\20long\29 +529:skia_png_read_data +530:SkSpinlock::contendedAcquire\28\29 +531:SkSL::PipelineStage::PipelineStageCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +532:SkPaint::setStyle\28SkPaint::Style\29 +533:SkMatrix::setRectToRect\28SkRect\20const&\2c\20SkRect\20const&\2c\20SkMatrix::ScaleToFit\29 +534:SkDPoint::approximatelyEqual\28SkDPoint\20const&\29\20const +535:GrSurfaceProxy::backingStoreDimensions\28\29\20const +536:GrOpsRenderPass::bindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +537:uprv_asciitolower_74 +538:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +539:skgpu::ganesh::SurfaceContext::drawingManager\28\29 +540:skgpu::UniqueKey::GenerateDomain\28\29 +541:_uhash_create\28int\20\28*\29\28UElement\29\2c\20signed\20char\20\28*\29\28UElement\2c\20UElement\29\2c\20signed\20char\20\28*\29\28UElement\2c\20UElement\29\2c\20int\2c\20UErrorCode*\29 +542:SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0::operator\28\29\28SkSL::FunctionDefinition\20const*\2c\20SkSL::FunctionDefinition\20const*\29\20const +543:SkSL::ConstructorCompound::MakeFromConstants\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20double\20const*\29 +544:SkPath::isEmpty\28\29\20const +545:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29 +546:SkBlockAllocator::reset\28\29 +547:GrMeshDrawOp::GrMeshDrawOp\28unsigned\20int\29 +548:FT_RoundFix +549:std::__2::unique_ptr::~unique_ptr\5babi:nn180100\5d\28\29 +550:std::__2::unique_ptr::unique_ptr\5babi:nn180100\5d\28unsigned\20char*\2c\20std::__2::__dependent_type\2c\20true>::__good_rval_ref_type\29 +551:icu_74::UnicodeSet::UnicodeSet\28\29 +552:cf2_stack_pushFixed +553:__multi3 +554:SkSL::RP::Builder::push_duplicates\28int\29 +555:SkColorInfo::refColorSpace\28\29\20const +556:SkBitmapDevice::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +557:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20SkFilterMode\2c\20SkMipmapMode\29 +558:GrGLSLVaryingHandler::addPassThroughAttribute\28GrShaderVar\20const&\2c\20char\20const*\2c\20GrGLSLVaryingHandler::Interpolation\29 +559:GrFragmentProcessor::registerChild\28std::__2::unique_ptr>\2c\20SkSL::SampleUsage\29 +560:FT_Stream_ReleaseFrame +561:323 +562:std::__2::istreambuf_iterator>::operator*\5babi:nn180100\5d\28\29\20const +563:skia::textlayout::TextStyle::TextStyle\28skia::textlayout::TextStyle\20const&\29 +564:sk_srgb_singleton\28\29 +565:hb_buffer_t::merge_clusters_impl\28unsigned\20int\2c\20unsigned\20int\29 +566:SkWStream::writePackedUInt\28unsigned\20long\29 +567:SkString::equals\28SkString\20const&\29\20const +568:SkSL::RP::Builder::push_constant_i\28int\2c\20int\29 +569:SkSL::BreakStatement::~BreakStatement\28\29 +570:SkPath::isFinite\28\29\20const +571:SkPaint::setShader\28sk_sp\29 +572:SkNullBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +573:SkCanvas::concat\28SkMatrix\20const&\29 +574:SkBitmap::setImmutable\28\29 +575:GrPipeline::visitProxies\28std::__2::function\20const&\29\20const +576:GrGeometryProcessor::GrGeometryProcessor\28GrProcessor::ClassID\29 +577:void\20emscripten::internal::raw_destructor\28GrDirectContext*\29 +578:std::__2::istreambuf_iterator>::operator*\5babi:nn180100\5d\28\29\20const +579:icu_74::UnicodeSet::add\28int\2c\20int\29 +580:SkSL::fold_expression\28SkSL::Position\2c\20double\2c\20SkSL::Type\20const*\29 +581:SkSL::Type::MakeAliasType\28std::__2::basic_string_view>\2c\20SkSL::Type\20const&\29 +582:SkSL::RP::Generator::binaryOp\28SkSL::Type\20const&\2c\20SkSL::RP::Generator::TypedOps\20const&\29 +583:GrGeometryProcessor::Attribute&\20skia_private::TArray::emplace_back\28char\20const\20\28&\29\20\5b10\5d\2c\20GrVertexAttribType&&\2c\20SkSLType&&\29 +584:FT_Stream_ReadByte +585:Cr_z_crc32 +586:skia_png_push_save_buffer +587:skcms_Transform +588:hb_face_t::load_num_glyphs\28\29\20const +589:hb_face_get_glyph_count +590:cosf +591:SkString::operator=\28SkString\20const&\29 +592:SkSL::RP::SlotManager::getVariableSlots\28SkSL::Variable\20const&\29 +593:SkSL::RP::Builder::unary_op\28SkSL::RP::BuilderOp\2c\20int\29 +594:SkReadBuffer::readScalar\28\29 +595:SkPaint::setBlendMode\28SkBlendMode\29 +596:GrProcessorSet::visitProxies\28std::__2::function\20const&\29\20const +597:GrGLTexture::target\28\29\20const +598:ures_getByKey_74 +599:u_strlen_74 +600:std::__2::__throw_overflow_error\5babi:nn180100\5d\28char\20const*\29 +601:fma +602:SkSurface_Base::aboutToDraw\28SkSurface::ContentChangeMode\29 +603:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression\20const&\29 +604:SkSL::Pool::FreeMemory\28void*\29 +605:SkDPoint::ApproximatelyEqual\28SkPoint\20const&\2c\20SkPoint\20const&\29 +606:SkBitmap::SkBitmap\28SkBitmap\20const&\29 +607:FT_Stream_ReadULong +608:370 +609:std::__2::unique_ptr>*\20std::__2::vector>\2c\20std::__2::allocator>>>::__push_back_slow_path>>\28std::__2::unique_ptr>&&\29 +610:std::__2::basic_string\2c\20std::__2::allocator>::__init_copy_ctor_external\28char\20const*\2c\20unsigned\20long\29 +611:skip_spaces +612:sk_realloc_throw\28void*\2c\20unsigned\20long\29 +613:fmodf +614:emscripten::smart_ptr_trait>::get\28sk_sp\20const&\29 +615:cff2_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +616:cff1_path_procs_extents_t::curve\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +617:cff1_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +618:bool\20OT::Layout::Common::Coverage::collect_coverage\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>>\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>*\29\20const +619:SkSL::Type::toCompound\28SkSL::Context\20const&\2c\20int\2c\20int\29\20const +620:SkPath::transform\28SkMatrix\20const&\2c\20SkPath*\2c\20SkApplyPerspectiveClip\29\20const +621:SkPath::quadTo\28float\2c\20float\2c\20float\2c\20float\29 +622:SkPaint::SkPaint\28SkPaint&&\29 +623:SkCanvas::save\28\29 +624:SkBlockAllocator::addBlock\28int\2c\20int\29 +625:SkBitmap::tryAllocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29 +626:GrThreadSafeCache::VertexData::~VertexData\28\29 +627:GrShape::asPath\28SkPath*\2c\20bool\29\20const +628:GrShaderVar::appendDecl\28GrShaderCaps\20const*\2c\20SkString*\29\20const +629:GrPixmapBase::~GrPixmapBase\28\29 +630:GrGLSLVaryingHandler::emitAttributes\28GrGeometryProcessor\20const&\29 +631:FT_Stream_ReadFields +632:uhash_put_74 +633:std::__2::unique_ptr::reset\5babi:nn180100\5d\28unsigned\20char*\29 +634:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +635:skia_private::TArray::push_back\28SkPaint\20const&\29 +636:icu_74::UnicodeString::getChar32At\28int\29\20const +637:icu_74::CharStringByteSink::CharStringByteSink\28icu_74::CharString*\29 +638:ft_mem_qalloc +639:__wasm_setjmp +640:SkSL::SymbolTable::~SymbolTable\28\29 +641:SkRasterClip::~SkRasterClip\28\29 +642:SkPixmap::reset\28SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +643:SkPathRef::~SkPathRef\28\29 +644:SkPath::countPoints\28\29\20const +645:SkPaint::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +646:SkPaint::canComputeFastBounds\28\29\20const +647:SkOpPtT::contains\28SkOpPtT\20const*\29\20const +648:SkOpAngle::segment\28\29\20const +649:SkMatrix::preConcat\28SkMatrix\20const&\29 +650:SkMatrix::mapVectors\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +651:SkMasks::getRed\28unsigned\20int\29\20const +652:SkMasks::getGreen\28unsigned\20int\29\20const +653:SkMasks::getBlue\28unsigned\20int\29\20const +654:SkColorSpace::MakeSRGB\28\29 +655:GrProcessorSet::~GrProcessorSet\28\29 +656:GrMeshDrawOp::createProgramInfo\28GrMeshDrawTarget*\29 +657:AutoLayerForImageFilter::~AutoLayerForImageFilter\28\29 +658:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +659:png_icc_profile_error +660:operator==\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +661:machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>::operator=\28machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\20const&\29 +662:icu_74::UnicodeString::UnicodeString\28icu_74::UnicodeString\20const&\29 +663:icu_74::UnicodeSet::compact\28\29 +664:emscripten::internal::MethodInvoker::invoke\28int\20\28SkAnimatedImage::*\20const&\29\28\29\2c\20SkAnimatedImage*\29 +665:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20SkBlendMode\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20SkBlendMode\29 +666:emscripten::default_smart_ptr_trait>::construct_null\28\29 +667:VP8GetSignedValue +668:SkSL::Type::MakeVectorType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\29 +669:SkRasterPipeline::SkRasterPipeline\28SkArenaAlloc*\29 +670:SkPoint::setLength\28float\29 +671:SkImageGenerator::onIsValid\28GrRecordingContext*\29\20const +672:SkColorInfo::shiftPerPixel\28\29\20const +673:GrTextureProxy::mipmapped\28\29\20const +674:GrGpuResource::~GrGpuResource\28\29 +675:FT_Stream_GetULong +676:Cr_z__tr_flush_bits +677:void\20emscripten::internal::raw_destructor>\28sk_sp*\29 +678:uhash_setKeyDeleter_74 +679:uhash_init_74 +680:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +681:std::__2::__throw_bad_optional_access\5babi:ne180100\5d\28\29 +682:skgpu::UniqueKey::operator=\28skgpu::UniqueKey\20const&\29 +683:sk_double_nearly_zero\28double\29 +684:icu_74::UnicodeString::tempSubString\28int\2c\20int\29\20const +685:icu_74::Locale::~Locale\28\29 +686:hb_font_get_glyph +687:ft_mem_alloc +688:fit_linear\28skcms_Curve\20const*\2c\20int\2c\20float\2c\20float*\2c\20float*\2c\20float*\29 +689:expf +690:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29 +691:_output_with_dotted_circle\28hb_buffer_t*\29 +692:WebPSafeMalloc +693:SkSafeMath::Mul\28unsigned\20long\2c\20unsigned\20long\29 +694:SkSL::GLSLCodeGenerator::writeIdentifier\28std::__2::basic_string_view>\29 +695:SkSL::GLSLCodeGenerator::getTypeName\28SkSL::Type\20const&\29 +696:SkRGBA4f<\28SkAlphaType\293>::FromColor\28unsigned\20int\29 +697:SkPath::Iter::Iter\28SkPath\20const&\2c\20bool\29 +698:SkMatrix::postConcat\28SkMatrix\20const&\29 +699:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_3::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +700:SkGlyph::rowBytes\28\29\20const +701:SkDrawable::getFlattenableType\28\29\20const +702:SkDrawable::getBounds\28\29 +703:SkData::MakeWithCopy\28void\20const*\2c\20unsigned\20long\29 +704:SkDCubic::ptAtT\28double\29\20const +705:SkColorInfo::SkColorInfo\28\29 +706:SkAAClipBlitter::~SkAAClipBlitter\28\29 +707:GrOpFlushState::drawMesh\28GrSimpleMesh\20const&\29 +708:GrImageInfo::GrImageInfo\28SkImageInfo\20const&\29 +709:DefaultGeoProc::Impl::~Impl\28\29 +710:void\20emscripten::internal::MemberAccess::setWire\28int\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\2c\20int\29 +711:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:nn180100\5d\28\29\20const +712:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_size\5babi:nn180100\5d\28unsigned\20long\29 +713:std::__2::basic_string\2c\20std::__2::allocator>::__is_long\5babi:nn180100\5d\28\29\20const +714:skif::LayerSpace::mapRect\28skif::LayerSpace\20const&\29\20const +715:skia::textlayout::Cluster::run\28\29\20const +716:out +717:jpeg_fill_bit_buffer +718:int\20emscripten::internal::MemberAccess::getWire\28int\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\29 +719:icu_74::UnicodeSet::add\28int\29 +720:icu_74::ReorderingBuffer::appendZeroCC\28char16_t\20const*\2c\20char16_t\20const*\2c\20UErrorCode&\29 +721:SkTextBlob::~SkTextBlob\28\29 +722:SkString::data\28\29 +723:SkShaderBase::SkShaderBase\28\29 +724:SkSL::Type::coerceExpression\28std::__2::unique_ptr>\2c\20SkSL::Context\20const&\29\20const +725:SkSL::Type::MakeGenericType\28char\20const*\2c\20SkSpan\2c\20SkSL::Type\20const*\29 +726:SkSL::ConstantFolder::GetConstantValueForVariable\28SkSL::Expression\20const&\29 +727:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29 +728:SkRegion::SkRegion\28\29 +729:SkRecords::FillBounds::adjustForSaveLayerPaints\28SkRect*\2c\20int\29\20const +730:SkPathStroker::lineTo\28SkPoint\20const&\2c\20SkPath::Iter\20const*\29 +731:SkPaint::setPathEffect\28sk_sp\29 +732:SkPaint::setMaskFilter\28sk_sp\29 +733:SkPaint::setColor\28unsigned\20int\29 +734:SkPaint::setColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\29 +735:SkOpContourBuilder::flush\28\29 +736:SkImageFilter::getInput\28int\29\20const +737:SkCanvas::~SkCanvas\28\29_1620 +738:SkCanvas::restoreToCount\28int\29 +739:SkCanvas::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +740:SkAutoPixmapStorage::~SkAutoPixmapStorage\28\29 +741:GrMatrixEffect::Make\28SkMatrix\20const&\2c\20std::__2::unique_ptr>\29 +742:GrContext_Base::options\28\29\20const +743:u_memcpy_74 +744:std::__2::char_traits::assign\5babi:nn180100\5d\28char&\2c\20char\20const&\29 +745:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +746:std::__2::__check_grouping\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int&\29 +747:skia_png_malloc +748:skia_png_chunk_report +749:skgpu::ganesh::SurfaceDrawContext::drawFilledQuad\28GrClip\20const*\2c\20GrPaint&&\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\29 +750:png_write_complete_chunk +751:pad +752:icu_74::UnicodeString::UnicodeString\28char16_t\20const*\29 +753:hb_lockable_set_t::fini\28hb_mutex_t&\29 +754:__ashlti3 +755:\28anonymous\20namespace\29::makeTargetInfo\28SkEncodedInfo\2c\20void\20\28*\29\28char*\2c\20char\20const*\2c\20int\2c\20int\29\29 +756:SkWBuffer::writeNoSizeCheck\28void\20const*\2c\20unsigned\20long\29 +757:SkTCoincident::setPerp\28SkTCurve\20const&\2c\20double\2c\20SkDPoint\20const&\2c\20SkTCurve\20const&\29 +758:SkStrokeRec::SkStrokeRec\28SkStrokeRec::InitStyle\29 +759:SkString::printf\28char\20const*\2c\20...\29 +760:SkSL::Type::MakeMatrixType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\2c\20signed\20char\29 +761:SkSL::Operator::tightOperatorName\28\29\20const +762:SkReadBuffer::readColor4f\28SkRGBA4f<\28SkAlphaType\293>*\29 +763:SkPixmap::reset\28\29 +764:SkPictureData::requiredPaint\28SkReadBuffer*\29\20const +765:SkPath::cubicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +766:SkPath::close\28\29 +767:SkPaintToGrPaint\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +768:SkMatrix::mapXY\28float\2c\20float\2c\20SkPoint*\29\20const +769:SkFindUnitQuadRoots\28float\2c\20float\2c\20float\2c\20float*\29 +770:SkDeque::push_back\28\29 +771:SkCanvas::internalQuickReject\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\29 +772:SkBinaryWriteBuffer::writeBool\28bool\29 +773:OT::hb_paint_context_t::return_t\20OT::Paint::dispatch\28OT::hb_paint_context_t*\29\20const +774:GrShape::bounds\28\29\20const +775:GrProgramInfo::GrProgramInfo\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrGeometryProcessor\20const*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +776:GrPixmapBase::GrPixmapBase\28GrImageInfo\2c\20void*\2c\20unsigned\20long\29 +777:GrColorInfo::GrColorInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\29 +778:FT_Outline_Translate +779:FT_Load_Glyph +780:FT_GlyphLoader_CheckPoints +781:FT_Get_Char_Index +782:DefaultGeoProc::~DefaultGeoProc\28\29 +783:545 +784:utext_current32_74 +785:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +786:std::__2::basic_string\2c\20std::__2::allocator>::__set_short_size\5babi:nn180100\5d\28unsigned\20long\29 +787:sinf +788:icu_74::UVector::removeAllElements\28\29 +789:icu_74::BMPSet::~BMPSet\28\29_13388 +790:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28GrDirectContext&\2c\20unsigned\20long\29\2c\20GrDirectContext*\2c\20unsigned\20long\29 +791:SkRasterPipeline::extend\28SkRasterPipeline\20const&\29 +792:SkMatrixPriv::MapRect\28SkM44\20const&\2c\20SkRect\20const&\29 +793:SkMatrix::preTranslate\28float\2c\20float\29 +794:SkMatrix::mapRadius\28float\29\20const +795:SkJSONWriter::appendf\28char\20const*\2c\20...\29 +796:SkIRect::join\28SkIRect\20const&\29 +797:SkData::MakeWithProc\28void\20const*\2c\20unsigned\20long\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +798:SkData::MakeUninitialized\28unsigned\20long\29 +799:SkDQuad::RootsValidT\28double\2c\20double\2c\20double\2c\20double*\29 +800:SkDLine::nearPoint\28SkDPoint\20const&\2c\20bool*\29\20const +801:SkColorSpaceXformSteps::apply\28float*\29\20const +802:SkCachedData::internalRef\28bool\29\20const +803:SkBitmap::installPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29 +804:GrSurface::RefCntedReleaseProc::~RefCntedReleaseProc\28\29 +805:GrStyle::initPathEffect\28sk_sp\29 +806:GrProcessor::operator\20delete\28void*\29 +807:GrGpuResource::hasRef\28\29\20const +808:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::~Impl\28\29 +809:GrBufferAllocPool::~GrBufferAllocPool\28\29_8797 +810:FT_Stream_Skip +811:u_terminateUChars_74 +812:strncpy +813:std::__2::numpunct::thousands_sep\5babi:nn180100\5d\28\29\20const +814:std::__2::numpunct::grouping\5babi:nn180100\5d\28\29\20const +815:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +816:skia_png_malloc_warn +817:rewind\28GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +818:icu_74::BytesTrie::~BytesTrie\28\29 +819:icu_74::BytesTrie::next\28int\29 +820:cf2_stack_popInt +821:SkUTF::NextUTF8\28char\20const**\2c\20char\20const*\29 +822:SkSL::TProgramVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +823:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29 +824:SkRegion::setRect\28SkIRect\20const&\29 +825:SkPaint::setColorFilter\28sk_sp\29 +826:SkImageInfo::MakeA8\28int\2c\20int\29 +827:SkImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +828:SkDrawBase::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20bool\2c\20bool\2c\20SkBlitter*\29\20const +829:SkData::MakeEmpty\28\29 +830:SkColorInfo::makeColorType\28SkColorType\29\20const +831:SkCodec::~SkCodec\28\29 +832:SkAAClip::isRect\28\29\20const +833:GrSurface::ComputeSize\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20bool\29 +834:GrSimpleMeshDrawOpHelper::GrSimpleMeshDrawOpHelper\28GrProcessorSet*\2c\20GrAAType\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +835:GrGeometryProcessor::ProgramImpl::SetTransform\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrResourceHandle\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix*\29 +836:GrDrawingManager::flushIfNecessary\28\29 +837:GrBlendFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkBlendMode\2c\20bool\29 +838:FT_Stream_ExtractFrame +839:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +840:skia_png_malloc_base +841:skgpu::ganesh::AsView\28GrRecordingContext*\2c\20SkImage\20const*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +842:skcms_TransferFunction_eval +843:pow +844:icu_74::UnicodeString::setToBogus\28\29 +845:icu_74::UnicodeString::releaseBuffer\28int\29 +846:icu_74::UnicodeSet::_appendToPat\28icu_74::UnicodeString&\2c\20int\2c\20signed\20char\29 +847:icu_74::UVector::~UVector\28\29 +848:hb_ot_face_t::init0\28hb_face_t*\29 +849:__addtf3 +850:SkTDStorage::reset\28\29 +851:SkSL::RP::Builder::label\28int\29 +852:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +853:SkRuntimeEffect::MakeForColorFilter\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +854:SkReadBuffer::skip\28unsigned\20long\2c\20unsigned\20long\29 +855:SkPath::countVerbs\28\29\20const +856:SkMatrix::set9\28float\20const*\29 +857:SkMatrix::getMaxScale\28\29\20const +858:SkImageInfo::computeByteSize\28unsigned\20long\29\20const +859:SkImageInfo::Make\28int\2c\20int\2c\20SkColorType\2c\20SkAlphaType\2c\20sk_sp\29 +860:SkFontMgr::countFamilies\28\29\20const +861:SkDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +862:SkBlockAllocator::SkBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\2c\20unsigned\20long\29 +863:SkBlender::Mode\28SkBlendMode\29 +864:ReadHuffmanCode +865:GrSurfaceProxy::~GrSurfaceProxy\28\29 +866:GrRenderTask::makeClosed\28GrRecordingContext*\29 +867:GrGpuBuffer::unmap\28\29 +868:GrCaps::getReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +869:GrBufferAllocPool::reset\28\29 +870:AAT::Lookup>::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +871:ures_hasNext_74 +872:std::__2::char_traits::assign\5babi:nn180100\5d\28wchar_t&\2c\20wchar_t\20const&\29 +873:std::__2::char_traits::copy\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +874:std::__2::basic_string\2c\20std::__2::allocator>::begin\5babi:nn180100\5d\28\29 +875:std::__2::__next_prime\28unsigned\20long\29 +876:std::__2::__libcpp_snprintf_l\28char*\2c\20unsigned\20long\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +877:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29 +878:sk_sp::~sk_sp\28\29 +879:memchr +880:locale_get_default_74 +881:is_equal\28std::type_info\20const*\2c\20std::type_info\20const*\2c\20bool\29 +882:hb_buffer_t::sync\28\29 +883:cbrtf +884:__floatsitf +885:WebPSafeCalloc +886:StreamRemainingLengthIsBelow\28SkStream*\2c\20unsigned\20long\29 +887:SkSL::RP::Builder::swizzle\28int\2c\20SkSpan\29 +888:SkSL::Parser::expression\28\29 +889:SkRuntimeEffect::Uniform::sizeInBytes\28\29\20const +890:SkRGBA4f<\28SkAlphaType\293>::toSkColor\28\29\20const +891:SkPath::isConvex\28\29\20const +892:SkImageFilter_Base::getChildOutputLayerBounds\28int\2c\20skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +893:SkImageFilter_Base::getChildInputLayerBounds\28int\2c\20skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +894:SkImageFilter_Base::SkImageFilter_Base\28sk_sp\20const*\2c\20int\2c\20std::__2::optional\29 +895:SkDynamicMemoryWStream::detachAsData\28\29 +896:SkDQuad::ptAtT\28double\29\20const +897:SkDLine::exactPoint\28SkDPoint\20const&\29\20const +898:SkDConic::ptAtT\28double\29\20const +899:SkConic::chopIntoQuadsPOW2\28SkPoint*\2c\20int\29\20const +900:SkColorInfo::makeAlphaType\28SkAlphaType\29\20const +901:SkCanvas::restore\28\29 +902:SkCanvas::drawImage\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +903:SkBitmap::setInfo\28SkImageInfo\20const&\2c\20unsigned\20long\29 +904:SkAAClip::Builder::addRun\28int\2c\20int\2c\20unsigned\20int\2c\20int\29 +905:GrSkSLFP::addChild\28std::__2::unique_ptr>\2c\20bool\29 +906:GrResourceProvider::findResourceByUniqueKey\28skgpu::UniqueKey\20const&\29 +907:GrGLSLShaderBuilder::appendTextureLookup\28SkString*\2c\20GrResourceHandle\2c\20char\20const*\29\20const +908:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\29 +909:GrFragmentProcessor::cloneAndRegisterAllChildProcessors\28GrFragmentProcessor\20const&\29 +910:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::~SwizzleFragmentProcessor\28\29 +911:GrBackendFormat::GrBackendFormat\28GrBackendFormat\20const&\29 +912:AutoLayerForImageFilter::AutoLayerForImageFilter\28SkCanvas*\2c\20SkPaint\20const&\2c\20SkRect\20const*\2c\20bool\29 +913:AutoFTAccess::AutoFTAccess\28SkTypeface_FreeType\20const*\29 +914:AlmostPequalUlps\28float\2c\20float\29 +915:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Module\20const*\29 +916:std::__2::pair>*\20std::__2::vector>\2c\20std::__2::allocator>>>::__emplace_back_slow_path>\28unsigned\20int\20const&\2c\20sk_sp&&\29 +917:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20char\29\20const +918:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:ne180100\5d<0>\28char\20const*\29 +919:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_cap\5babi:nn180100\5d\28unsigned\20long\29 +920:snprintf +921:skia_png_reset_crc +922:skia_png_benign_error +923:icu_74::UnicodeString::operator=\28icu_74::UnicodeString\20const&\29 +924:icu_74::UnicodeString::doReplace\28int\2c\20int\2c\20char16_t\20const*\2c\20int\2c\20int\29 +925:icu_74::UnicodeString::UnicodeString\28signed\20char\2c\20icu_74::ConstChar16Ptr\2c\20int\29 +926:icu_74::UVector::adoptElement\28void*\2c\20UErrorCode&\29 +927:icu_74::MlBreakEngine::initKeyValue\28UResourceBundle*\2c\20char\20const*\2c\20char\20const*\2c\20icu_74::Hashtable&\2c\20UErrorCode&\29 +928:icu_74::ByteSinkUtil::appendUnchanged\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20icu_74::ByteSink&\2c\20unsigned\20int\2c\20icu_74::Edits*\2c\20UErrorCode&\29 +929:hb_buffer_t::sync_so_far\28\29 +930:hb_buffer_t::move_to\28unsigned\20int\29 +931:VP8ExitCritical +932:SkTDStorage::resize\28int\29 +933:SkStrokeRec::SkStrokeRec\28SkPaint\20const&\2c\20float\29 +934:SkStream::readPackedUInt\28unsigned\20long*\29 +935:SkSize\20skif::Mapping::map\28SkSize\20const&\2c\20SkMatrix\20const&\29 +936:SkSL::Type::coercionCost\28SkSL::Type\20const&\29\20const +937:SkSL::Type::clone\28SkSL::Context\20const&\2c\20SkSL::SymbolTable*\29\20const +938:SkSL::RP::Generator::writeStatement\28SkSL::Statement\20const&\29 +939:SkSL::Parser::operatorRight\28SkSL::Parser::AutoDepth&\2c\20SkSL::OperatorKind\2c\20std::__2::unique_ptr>\20\28SkSL::Parser::*\29\28\29\2c\20std::__2::unique_ptr>&\29 +940:SkRuntimeEffectBuilder::writableUniformData\28\29 +941:SkRuntimeEffect::findUniform\28std::__2::basic_string_view>\29\20const +942:SkResourceCache::Key::init\28void*\2c\20unsigned\20long\20long\2c\20unsigned\20long\29 +943:SkReadBuffer::skip\28unsigned\20long\29 +944:SkReadBuffer::readFlattenable\28SkFlattenable::Type\29 +945:SkRRect::initializeRect\28SkRect\20const&\29 +946:SkPaint::asBlendMode\28\29\20const +947:SkImageFilter_Base::getFlattenableType\28\29\20const +948:SkGlyph::path\28\29\20const +949:SkConic::computeQuadPOW2\28float\29\20const +950:SkAAClip::quickContains\28int\2c\20int\2c\20int\2c\20int\29\20const +951:OT::GDEF::accelerator_t::mark_set_covers\28unsigned\20int\2c\20unsigned\20int\29\20const +952:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\29 +953:GrRenderTargetProxy::arenas\28\29 +954:GrOpFlushState::caps\28\29\20const +955:GrGpuResource::hasNoCommandBufferUsages\28\29\20const +956:GrGeometryProcessor::ProgramImpl::WriteLocalCoord\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20GrShaderVar\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +957:GrGLTextureParameters::SamplerOverriddenState::SamplerOverriddenState\28\29 +958:GrGLGpu::deleteFramebuffer\28unsigned\20int\29 +959:GrDrawOpAtlas::~GrDrawOpAtlas\28\29 +960:FT_Get_Module +961:Cr_z__tr_flush_block +962:AlmostBequalUlps\28float\2c\20float\29 +963:utext_previous32_74 +964:ures_getByKeyWithFallback_74 +965:std::__2::pair::type\2c\20std::__2::__unwrap_ref_decay::type>\20std::__2::make_pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +966:std::__2::numpunct::truename\5babi:nn180100\5d\28\29\20const +967:std::__2::moneypunct::do_grouping\28\29\20const +968:std::__2::locale::use_facet\28std::__2::locale::id&\29\20const +969:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29\20const +970:std::__2::basic_string\2c\20std::__2::allocator>::empty\5babi:nn180100\5d\28\29\20const +971:sktext::gpu::BagOfBytes::needMoreBytes\28int\2c\20int\29 +972:skia_png_save_int_32 +973:skia_png_safecat +974:skia_png_gamma_significant +975:skgpu::ganesh::SurfaceContext::readPixels\28GrDirectContext*\2c\20GrPixmap\2c\20SkIPoint\29 +976:icu_74::UnicodeString::setTo\28signed\20char\2c\20icu_74::ConstChar16Ptr\2c\20int\29 +977:icu_74::UnicodeString::getBuffer\28int\29 +978:icu_74::UnicodeString::doAppend\28icu_74::UnicodeString\20const&\2c\20int\2c\20int\29 +979:icu_74::UVector32::~UVector32\28\29 +980:icu_74::RuleBasedBreakIterator::handleNext\28\29 +981:icu_74::Locale::Locale\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +982:hb_font_get_nominal_glyph +983:hb_buffer_t::clear_output\28\29 +984:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28SkPaint\20const&\29\2c\20SkCanvas*\2c\20SkPaint*\29 +985:emscripten::internal::FunctionInvoker::invoke\28unsigned\20long\20\28**\29\28GrDirectContext&\29\2c\20GrDirectContext*\29 +986:cff_parse_num +987:\28anonymous\20namespace\29::write_trc_tag\28skcms_Curve\20const&\29 +988:T_CString_toLowerCase_74 +989:SkWStream::writeScalarAsText\28float\29 +990:SkTSect::SkTSect\28SkTCurve\20const&\29 +991:SkString::set\28char\20const*\2c\20unsigned\20long\29 +992:SkSL::compile_and_shrink\28SkSL::Compiler*\2c\20SkSL::ProgramKind\2c\20SkSL::ModuleType\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::Module\20const*\29 +993:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Context\20const&\2c\20SkSL::Symbol*\29 +994:SkSL::Swizzle::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29 +995:SkSL::String::Separator\28\29::Output::~Output\28\29 +996:SkSL::Parser::layoutInt\28\29 +997:SkSL::Parser::expectIdentifier\28SkSL::Token*\29 +998:SkSL::GetModuleData\28SkSL::ModuleType\2c\20char\20const*\29 +999:SkSL::Expression::description\28\29\20const +1000:SkRegion::Cliperator::next\28\29 +1001:SkRegion::Cliperator::Cliperator\28SkRegion\20const&\2c\20SkIRect\20const&\29 +1002:SkRRect::setOval\28SkRect\20const&\29 +1003:SkPictureRecorder::~SkPictureRecorder\28\29 +1004:SkPathRef::CreateEmpty\28\29 +1005:SkPath::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +1006:SkPath::addPath\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPath::AddPathMode\29 +1007:SkPaint::operator=\28SkPaint&&\29 +1008:SkNoDestructor::SkNoDestructor\28SkSL::String::Separator\28\29::Output&&\29 +1009:SkMasks::getAlpha\28unsigned\20int\29\20const +1010:SkM44::setConcat\28SkM44\20const&\2c\20SkM44\20const&\29 +1011:SkImageFilters::Crop\28SkRect\20const&\2c\20SkTileMode\2c\20sk_sp\29 +1012:SkImageFilter_Base::getChildOutput\28int\2c\20skif::Context\20const&\29\20const +1013:SkIDChangeListener::List::List\28\29 +1014:SkData::MakeFromMalloc\28void\20const*\2c\20unsigned\20long\29 +1015:SkDRect::setBounds\28SkTCurve\20const&\29 +1016:SkColorSpace::Equals\28SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +1017:SkColorFilter::isAlphaUnchanged\28\29\20const +1018:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +1019:SkCanvas::translate\28float\2c\20float\29 +1020:SkBitmapCache::Rec::getKey\28\29\20const +1021:SafeDecodeSymbol +1022:PS_Conv_ToFixed +1023:OT::hb_ot_apply_context_t::hb_ot_apply_context_t\28unsigned\20int\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20hb_blob_t*\29 +1024:GrTriangulator::Line::intersect\28GrTriangulator::Line\20const&\2c\20SkPoint*\29\20const +1025:GrSimpleMeshDrawOpHelper::isCompatible\28GrSimpleMeshDrawOpHelper\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +1026:GrQuad::MakeFromSkQuad\28SkPoint\20const*\2c\20SkMatrix\20const&\29 +1027:GrOpsRenderPass::bindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +1028:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkISize\20const&\29 +1029:GrGLSLShaderBuilder::appendTextureLookup\28GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +1030:GrColorInfo::GrColorInfo\28SkColorInfo\20const&\29 +1031:FT_Stream_Read +1032:AlmostDequalUlps\28double\2c\20double\29 +1033:795 +1034:utrace_exit_74 +1035:utrace_entry_74 +1036:ures_getNextResource_74 +1037:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\29 +1038:tt_face_get_name +1039:strrchr +1040:std::__2::to_string\28long\20long\29 +1041:std::__2::__libcpp_locale_guard::~__libcpp_locale_guard\5babi:nn180100\5d\28\29 +1042:std::__2::__libcpp_locale_guard::__libcpp_locale_guard\5babi:nn180100\5d\28__locale_struct*&\29 +1043:skif::FilterResult::~FilterResult\28\29 +1044:skia_png_app_error +1045:skgpu::ganesh::SurfaceFillContext::getOpsTask\28\29 +1046:log2f +1047:llround +1048:icu_74::UnicodeString::doIndexOf\28char16_t\2c\20int\2c\20int\29\20const +1049:hb_sanitize_context_t::return_t\20OT::Paint::dispatch\28hb_sanitize_context_t*\29\20const +1050:hb_ot_layout_lookup_would_substitute +1051:hb_lazy_loader_t\2c\20hb_face_t\2c\2025u\2c\20OT::GSUB_accelerator_t>::do_destroy\28OT::GSUB_accelerator_t*\29 +1052:ft_module_get_service +1053:__sindf +1054:__shlim +1055:__cosdf +1056:\28anonymous\20namespace\29::init_resb_result\28UResourceDataEntry*\2c\20unsigned\20int\2c\20char\20const*\2c\20int\2c\20UResourceDataEntry*\2c\20char\20const*\2c\20int\2c\20UResourceBundle*\2c\20UErrorCode*\29 +1057:SkTiff::ImageFileDirectory::getEntryValuesGeneric\28unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20int\2c\20void*\29\20const +1058:SkSurface::getCanvas\28\29 +1059:SkSL::cast_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +1060:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitType\28SkSL::Type\20const&\29 +1061:SkSL::Variable::initialValue\28\29\20const +1062:SkSL::SymbolTable::addArrayDimension\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20int\29 +1063:SkSL::StringStream::str\28\29\20const +1064:SkSL::RP::Program::appendCopy\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20std::byte*\2c\20SkSL::RP::ProgramOp\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29\20const +1065:SkSL::RP::Generator::makeLValue\28SkSL::Expression\20const&\2c\20bool\29 +1066:SkSL::GLSLCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1067:SkSL::Analysis::UpdateVariableRefKind\28SkSL::Expression*\2c\20SkSL::VariableRefKind\2c\20SkSL::ErrorReporter*\29 +1068:SkRegion::setEmpty\28\29 +1069:SkRasterPipeline::run\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +1070:SkRasterPipeline::appendLoadDst\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +1071:SkRRect::setRectRadii\28SkRect\20const&\2c\20SkPoint\20const*\29 +1072:SkPointPriv::DistanceToLineSegmentBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +1073:SkPath::arcTo\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +1074:SkPaint::setImageFilter\28sk_sp\29 +1075:SkOpSpanBase::contains\28SkOpSegment\20const*\29\20const +1076:SkMipmap::ComputeLevelCount\28int\2c\20int\29 +1077:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint\20const*\2c\20int\29\20const +1078:SkMatrix::isSimilarity\28float\29\20const +1079:SkMD5::bytesWritten\28\29\20const +1080:SkKnownRuntimeEffects::GetKnownRuntimeEffect\28SkKnownRuntimeEffects::StableKey\29 +1081:SkIDChangeListener::List::~List\28\29 +1082:SkIDChangeListener::List::changed\28\29 +1083:SkColorFilter::filterColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\2c\20SkColorSpace*\29\20const +1084:SkCodec::applyColorXform\28void*\2c\20void\20const*\2c\20int\29\20const +1085:SkCanvas::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +1086:SkAutoPixmapStorage::SkAutoPixmapStorage\28\29 +1087:RunBasedAdditiveBlitter::flush\28\29 +1088:GrSurface::onRelease\28\29 +1089:GrStyledShape::unstyledKeySize\28\29\20const +1090:GrShape::convex\28bool\29\20const +1091:GrRecordingContext::threadSafeCache\28\29 +1092:GrProxyProvider::caps\28\29\20const +1093:GrOp::GrOp\28unsigned\20int\29 +1094:GrMakeUncachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +1095:GrGLSLShaderBuilder::getMangledFunctionName\28char\20const*\29 +1096:GrGLGpu::bindBuffer\28GrGpuBufferType\2c\20GrBuffer\20const*\29 +1097:GrGLAttribArrayState::set\28GrGLGpu*\2c\20int\2c\20GrBuffer\20const*\2c\20GrVertexAttribType\2c\20SkSLType\2c\20int\2c\20unsigned\20long\2c\20int\29 +1098:GrAAConvexTessellator::Ring::computeNormals\28GrAAConvexTessellator\20const&\29 +1099:GrAAConvexTessellator::Ring::computeBisectors\28GrAAConvexTessellator\20const&\29 +1100:FT_Activate_Size +1101:Cr_z_adler32 +1102:864 +1103:865 +1104:vsnprintf +1105:uprv_toupper_74 +1106:ucptrie_getRange_74 +1107:u_strchr_74 +1108:top12 +1109:toSkImageInfo\28SimpleImageInfo\20const&\29 +1110:std::__2::vector>::__destroy_vector::__destroy_vector\5babi:nn180100\5d\28std::__2::vector>&\29 +1111:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +1112:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\2c\20std::__2::allocator>\28char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +1113:std::__2::__tree\2c\20std::__2::__map_value_compare\2c\20std::__2::less\2c\20true>\2c\20std::__2::allocator>>::destroy\28std::__2::__tree_node\2c\20void*>*\29 +1114:std::__2::__num_put_base::__identify_padding\28char*\2c\20char*\2c\20std::__2::ios_base\20const&\29 +1115:std::__2::__num_get_base::__get_base\28std::__2::ios_base&\29 +1116:std::__2::__libcpp_asprintf_l\28char**\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +1117:skia_private::THashTable::Traits>::removeSlot\28int\29 +1118:skia_png_zstream_error +1119:skia::textlayout::TextLine::iterateThroughVisualRuns\28bool\2c\20std::__2::function\2c\20float*\29>\20const&\29\20const +1120:skia::textlayout::ParagraphImpl::cluster\28unsigned\20long\29 +1121:skia::textlayout::Cluster::runOrNull\28\29\20const +1122:skgpu::ganesh::SurfaceFillContext::replaceOpsTask\28\29 +1123:skcms_TransferFunction_getType +1124:res_getStringNoTrace_74 +1125:non-virtual\20thunk\20to\20GrOpFlushState::allocator\28\29 +1126:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1127:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1128:icu_74::UnicodeString::unBogus\28\29 +1129:icu_74::UnicodeSetStringSpan::~UnicodeSetStringSpan\28\29 +1130:icu_74::SimpleFilteredSentenceBreakIterator::operator==\28icu_74::BreakIterator\20const&\29\20const +1131:icu_74::Locale::init\28char\20const*\2c\20signed\20char\29 +1132:icu_74::Edits::addUnchanged\28int\29 +1133:hb_serialize_context_t::pop_pack\28bool\29 +1134:hb_buffer_reverse +1135:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1136:getenv +1137:afm_parser_read_vals +1138:__extenddftf2 +1139:\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1140:\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1141:\28anonymous\20namespace\29::colrv1_transform\28FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\2c\20SkCanvas*\2c\20SkMatrix*\29 +1142:WebPRescalerImport +1143:SkTDStorage::removeShuffle\28int\29 +1144:SkString::SkString\28char\20const*\2c\20unsigned\20long\29 +1145:SkStrike::digestFor\28skglyph::ActionType\2c\20SkPackedGlyphID\29 +1146:SkSL::VariableReference::VariableReference\28SkSL::Position\2c\20SkSL::Variable\20const*\2c\20SkSL::VariableRefKind\29 +1147:SkSL::SymbolTable::lookup\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +1148:SkSL::ProgramUsage::get\28SkSL::Variable\20const&\29\20const +1149:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29 +1150:SkSL::InlineCandidateAnalyzer::visitExpression\28std::__2::unique_ptr>*\29 +1151:SkSL::GLSLCodeGenerator::write\28std::__2::basic_string_view>\29 +1152:SkSL::GLSLCodeGenerator::getTypePrecision\28SkSL::Type\20const&\29 +1153:SkReadBuffer::readByteArray\28void*\2c\20unsigned\20long\29 +1154:SkRBuffer::read\28void*\2c\20unsigned\20long\29 +1155:SkPictureData::optionalPaint\28SkReadBuffer*\29\20const +1156:SkPath::isRect\28SkRect*\2c\20bool*\2c\20SkPathDirection*\29\20const +1157:SkPath::getGenerationID\28\29\20const +1158:SkPaint::setStrokeWidth\28float\29 +1159:SkOpSegment::nextChase\28SkOpSpanBase**\2c\20int*\2c\20SkOpSpan**\2c\20SkOpSpanBase**\29\20const +1160:SkMemoryStream::Make\28sk_sp\29 +1161:SkMatrix::preScale\28float\2c\20float\29 +1162:SkMatrix::postScale\28float\2c\20float\29 +1163:SkMask::computeImageSize\28\29\20const +1164:SkIntersections::removeOne\28int\29 +1165:SkImageInfo::Make\28int\2c\20int\2c\20SkColorType\2c\20SkAlphaType\29 +1166:SkDevice::makeSpecial\28SkBitmap\20const&\29 +1167:SkDLine::ptAtT\28double\29\20const +1168:SkBlockMemoryStream::getLength\28\29\20const +1169:SkBitmap::peekPixels\28SkPixmap*\29\20const +1170:SkAAClip::setEmpty\28\29 +1171:PS_Conv_Strtol +1172:OT::Layout::GSUB_impl::SubstLookup*\20hb_serialize_context_t::push\28\29 +1173:GrTriangulator::makeConnectingEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\2c\20int\29 +1174:GrTextureProxy::~GrTextureProxy\28\29 +1175:GrSimpleMeshDrawOpHelper::createProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1176:GrResourceAllocator::addInterval\28GrSurfaceProxy*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20GrResourceAllocator::ActualUse\2c\20GrResourceAllocator::AllowRecycling\29 +1177:GrRecordingContextPriv::makeSFCWithFallback\28GrImageInfo\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1178:GrGpuBuffer::updateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +1179:GrGLTextureParameters::NonsamplerState::NonsamplerState\28\29 +1180:GrGLSLShaderBuilder::~GrGLSLShaderBuilder\28\29 +1181:GrGLSLProgramBuilder::nameVariable\28char\2c\20char\20const*\2c\20bool\29 +1182:GrGLGpu::prepareToDraw\28GrPrimitiveType\29 +1183:GrGLFormatFromGLEnum\28unsigned\20int\29 +1184:GrBackendTexture::getBackendFormat\28\29\20const +1185:GrBackendFormats::MakeGL\28unsigned\20int\2c\20unsigned\20int\29 +1186:GrBackendFormatToCompressionType\28GrBackendFormat\20const&\29 +1187:FilterLoop24_C +1188:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +1189:AAT::Lookup::sanitize\28hb_sanitize_context_t*\29\20const +1190:utext_close_74 +1191:ures_open_74 +1192:ures_getStringByKey_74 +1193:ures_getKey_74 +1194:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +1195:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +1196:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +1197:ulocimp_getLanguage_74\28char\20const*\2c\20char\20const**\2c\20UErrorCode&\29 +1198:uhash_puti_74 +1199:u_terminateChars_74 +1200:std::__2::vector>::size\5babi:nn180100\5d\28\29\20const +1201:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +1202:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\20const*\2c\20char\20const*\29\20const +1203:std::__2::enable_if::type\20skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::AddTrianglesWhenChopping\2c\20skgpu::tess::DiscardFlatCurves>::writeTriangleStack\28skgpu::tess::MiddleOutPolygonTriangulator::PoppedTriangleStack&&\29 +1204:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +1205:std::__2::basic_string\2c\20std::__2::allocator>::__get_long_cap\5babi:nn180100\5d\28\29\20const +1206:skif::LayerSpace::ceil\28\29\20const +1207:skia_private::THashTable::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +1208:skia_private::TArray::push_back\28float\20const&\29 +1209:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +1210:skia_png_write_finish_row +1211:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29 +1212:skcms_GetTagBySignature +1213:scalbn +1214:icu_74::UnicodeSet::applyPattern\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29 +1215:icu_74::Normalizer2Impl::getFCD16FromNormData\28int\29\20const +1216:icu_74::Locale::Locale\28\29 +1217:icu_74::Edits::addReplace\28int\2c\20int\29 +1218:icu_74::BytesTrie::readValue\28unsigned\20char\20const*\2c\20int\29 +1219:hb_lazy_loader_t\2c\20hb_face_t\2c\2024u\2c\20OT::GDEF_accelerator_t>::do_destroy\28OT::GDEF_accelerator_t*\29 +1220:hb_buffer_get_glyph_infos +1221:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1222:get_gsubgpos_table\28hb_face_t*\2c\20unsigned\20int\29 +1223:exp2f +1224:embind_init_Paragraph\28\29::$_5::__invoke\28skia::textlayout::ParagraphBuilderImpl&\29 +1225:cff2_path_param_t::line_to\28CFF::point_t\20const&\29 +1226:cff1_path_param_t::line_to\28CFF::point_t\20const&\29 +1227:cf2_stack_getReal +1228:cf2_hintmap_map +1229:antifilldot8\28int\2c\20int\2c\20int\2c\20int\2c\20SkBlitter*\2c\20bool\29 +1230:afm_stream_skip_spaces +1231:WebPRescalerInit +1232:WebPRescalerExportRow +1233:SkWStream::writeDecAsText\28int\29 +1234:SkTypeface::fontStyle\28\29\20const +1235:SkTextBlobBuilder::allocInternal\28SkFont\20const&\2c\20SkTextBlob::GlyphPositioning\2c\20int\2c\20int\2c\20SkPoint\2c\20SkRect\20const*\29 +1236:SkTDStorage::append\28void\20const*\2c\20int\29 +1237:SkString::Rec::Make\28char\20const*\2c\20unsigned\20long\29::$_0::operator\28\29\28\29\20const +1238:SkShaders::Color\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\29 +1239:SkShader::makeWithLocalMatrix\28SkMatrix\20const&\29\20const +1240:SkSL::Parser::assignmentExpression\28\29 +1241:SkSL::ConstructorSplat::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1242:SkSL::ConstructorScalarCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1243:SkResourceCache::Find\28SkResourceCache::Key\20const&\2c\20bool\20\28*\29\28SkResourceCache::Rec\20const&\2c\20void*\29\2c\20void*\29 +1244:SkRegion::SkRegion\28SkIRect\20const&\29 +1245:SkRect::toQuad\28SkPoint*\29\20const +1246:SkRasterPipeline::appendTransferFunction\28skcms_TransferFunction\20const&\29 +1247:SkRasterPipeline::appendStore\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +1248:SkRasterClip::SkRasterClip\28\29 +1249:SkRRect::checkCornerContainment\28float\2c\20float\29\20const +1250:SkPictureData::getImage\28SkReadBuffer*\29\20const +1251:SkPathMeasure::getLength\28\29 +1252:SkPathBuilder::~SkPathBuilder\28\29 +1253:SkPathBuilder::detach\28\29 +1254:SkPathBuilder::SkPathBuilder\28\29 +1255:SkPath::addPoly\28SkPoint\20const*\2c\20int\2c\20bool\29 +1256:SkPaint::refPathEffect\28\29\20const +1257:SkMipmap::getLevel\28int\2c\20SkMipmap::Level*\29\20const +1258:SkJSONWriter::appendCString\28char\20const*\2c\20char\20const*\29 +1259:SkIntersections::setCoincident\28int\29 +1260:SkImageFilter_Base::flatten\28SkWriteBuffer&\29\20const +1261:SkDrawBase::SkDrawBase\28\29 +1262:SkDescriptor::operator==\28SkDescriptor\20const&\29\20const +1263:SkDLine::NearPointV\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1264:SkDLine::NearPointH\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1265:SkDLine::ExactPointV\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1266:SkDLine::ExactPointH\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1267:SkColorSpaceXformSteps::apply\28SkRasterPipeline*\29\20const +1268:SkCanvas::drawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +1269:SkCanvas::drawColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +1270:SkCanvas::aboutToDraw\28SkPaint\20const&\2c\20SkRect\20const*\2c\20SkEnumBitMask\29 +1271:SkBulkGlyphMetrics::~SkBulkGlyphMetrics\28\29 +1272:SkBulkGlyphMetrics::SkBulkGlyphMetrics\28SkStrikeSpec\20const&\29 +1273:SkBlockAllocator::releaseBlock\28SkBlockAllocator::Block*\29 +1274:SkBitmap::asImage\28\29\20const +1275:SkAAClipBlitterWrapper::SkAAClipBlitterWrapper\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1276:OT::MVAR::get_var\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29\20const +1277:OT::GDEF_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1278:GrXferProcessor::GrXferProcessor\28GrProcessor::ClassID\2c\20bool\2c\20GrProcessorAnalysisCoverage\29 +1279:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20GrCaps\20const&\2c\20float\20const*\29 +1280:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\29 +1281:GrSimpleMeshDrawOpHelper::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20bool*\29 +1282:GrRecordingContext::OwnedArenas::get\28\29 +1283:GrProxyProvider::createProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\29 +1284:GrProxyProvider::assignUniqueKeyToProxy\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\29 +1285:GrProcessorSet::finalize\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrCaps\20const&\2c\20GrClampType\2c\20SkRGBA4f<\28SkAlphaType\292>*\29 +1286:GrOpFlushState::allocator\28\29 +1287:GrOp::cutChain\28\29 +1288:GrMeshDrawTarget::makeVertexWriter\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +1289:GrGpuResource::GrGpuResource\28GrGpu*\2c\20std::__2::basic_string_view>\29 +1290:GrGeometryProcessor::TextureSampler::reset\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +1291:GrGeometryProcessor::AttributeSet::Iter::operator++\28\29 +1292:GrGeometryProcessor::AttributeSet::Iter::operator*\28\29\20const +1293:GrGLTextureParameters::set\28GrGLTextureParameters::SamplerOverriddenState\20const*\2c\20GrGLTextureParameters::NonsamplerState\20const&\2c\20unsigned\20long\20long\29 +1294:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29 +1295:GrBackendTexture::~GrBackendTexture\28\29 +1296:FT_Outline_Get_CBox +1297:FT_Get_Sfnt_Table +1298:utf8_prevCharSafeBody_74 +1299:ures_getString_74 +1300:ulocimp_getScript_74\28char\20const*\2c\20char\20const**\2c\20UErrorCode&\29 +1301:uhash_open_74 +1302:u_UCharsToChars_74 +1303:std::__2::moneypunct::negative_sign\5babi:nn180100\5d\28\29\20const +1304:std::__2::moneypunct::neg_format\5babi:nn180100\5d\28\29\20const +1305:std::__2::moneypunct::do_pos_format\28\29\20const +1306:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +1307:std::__2::char_traits::copy\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20unsigned\20long\29 +1308:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1309:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1310:std::__2::basic_string\2c\20std::__2::allocator>::__set_size\5babi:nn180100\5d\28unsigned\20long\29 +1311:std::__2::basic_string\2c\20std::__2::allocator>::__get_short_size\5babi:nn180100\5d\28\29\20const +1312:std::__2::basic_string\2c\20std::__2::allocator>::__assign_external\28char\20const*\2c\20unsigned\20long\29 +1313:std::__2::__unwrap_iter_impl\2c\20true>::__unwrap\5babi:nn180100\5d\28std::__2::__wrap_iter\29 +1314:std::__2::__itoa::__append2\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1315:sktext::gpu::GlyphVector::glyphs\28\29\20const +1316:sktext::SkStrikePromise::SkStrikePromise\28sktext::SkStrikePromise&&\29 +1317:skif::FilterResult::resolve\28skif::Context\20const&\2c\20skif::LayerSpace\2c\20bool\29\20const +1318:skif::FilterResult::analyzeBounds\28SkMatrix\20const&\2c\20SkIRect\20const&\2c\20skif::FilterResult::BoundsScope\29\20const +1319:skia_private::THashMap::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +1320:skia_png_read_finish_row +1321:skia_png_handle_unknown +1322:skia_png_gamma_correct +1323:skia_png_colorspace_sync +1324:skia_png_app_warning +1325:skia::textlayout::TextStyle::operator=\28skia::textlayout::TextStyle\20const&\29 +1326:skia::textlayout::TextLine::offset\28\29\20const +1327:skia::textlayout::Run::placeholderStyle\28\29\20const +1328:skgpu::ganesh::SurfaceFillContext::fillRectWithFP\28SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +1329:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20std::__2::basic_string_view>\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1330:skgpu::ganesh::SurfaceContext::PixelTransferResult::~PixelTransferResult\28\29 +1331:skgpu::ganesh::ClipStack::SaveRecord::state\28\29\20const +1332:sk_doubles_nearly_equal_ulps\28double\2c\20double\2c\20unsigned\20char\29 +1333:ps_parser_to_token +1334:icu_74::UnicodeString::moveIndex32\28int\2c\20int\29\20const +1335:icu_74::UnicodeString::cloneArrayIfNeeded\28int\2c\20int\2c\20signed\20char\2c\20int**\2c\20signed\20char\29 +1336:icu_74::UnicodeSet::span\28char16_t\20const*\2c\20int\2c\20USetSpanCondition\29\20const +1337:icu_74::UVector::indexOf\28void*\2c\20int\29\20const +1338:icu_74::UVector::addElement\28void*\2c\20UErrorCode&\29 +1339:icu_74::UVector32::UVector32\28UErrorCode&\29 +1340:icu_74::RuleCharacterIterator::next\28int\2c\20signed\20char&\2c\20UErrorCode&\29 +1341:icu_74::ReorderingBuffer::appendBMP\28char16_t\2c\20unsigned\20char\2c\20UErrorCode&\29 +1342:icu_74::LSR::deleteOwned\28\29 +1343:icu_74::ICUServiceKey::prefix\28icu_74::UnicodeString&\29\20const +1344:icu_74::CharString::appendInvariantChars\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29 +1345:icu_74::CharString::appendInvariantChars\28char16_t\20const*\2c\20int\2c\20UErrorCode&\29 +1346:icu_74::BreakIterator::buildInstance\28icu_74::Locale\20const&\2c\20char\20const*\2c\20UErrorCode&\29 +1347:hb_face_t::load_upem\28\29\20const +1348:hb_buffer_t::merge_out_clusters\28unsigned\20int\2c\20unsigned\20int\29 +1349:hb_buffer_t::enlarge\28unsigned\20int\29 +1350:hb_buffer_destroy +1351:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20SkCanvas::PointMode\2c\20unsigned\20long\2c\20int\2c\20SkPaint&\29\2c\20SkCanvas*\2c\20SkCanvas::PointMode\2c\20unsigned\20long\2c\20int\2c\20SkPaint*\29 +1352:cff_index_init +1353:cf2_glyphpath_curveTo +1354:bool\20std::__2::operator!=\5babi:nn180100\5d\28std::__2::__wrap_iter\20const&\2c\20std::__2::__wrap_iter\20const&\29 +1355:atan2f +1356:__isspace +1357:WebPCopyPlane +1358:SkTextBlobBuilder::TightRunBounds\28SkTextBlob::RunRecord\20const&\29 +1359:SkTMaskGamma_build_correcting_lut\28unsigned\20char*\2c\20unsigned\20int\2c\20float\2c\20SkColorSpaceLuminance\20const&\2c\20float\29 +1360:SkSurface_Raster::type\28\29\20const +1361:SkString::swap\28SkString&\29 +1362:SkString::reset\28\29 +1363:SkSampler::Fill\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::ZeroInitialized\29 +1364:SkSL::Type::MakeTextureType\28char\20const*\2c\20SpvDim_\2c\20bool\2c\20bool\2c\20bool\2c\20SkSL::Type::TextureAccess\29 +1365:SkSL::Type::MakeSpecialType\28char\20const*\2c\20char\20const*\2c\20SkSL::Type::TypeKind\29 +1366:SkSL::RP::Builder::push_slots_or_immutable\28SkSL::RP::SlotRange\2c\20SkSL::RP::BuilderOp\29 +1367:SkSL::RP::Builder::push_clone_from_stack\28SkSL::RP::SlotRange\2c\20int\2c\20int\29 +1368:SkSL::Program::~Program\28\29 +1369:SkSL::PipelineStage::PipelineStageCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1370:SkSL::Operator::isAssignment\28\29\20const +1371:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mul\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +1372:SkSL::InlineCandidateAnalyzer::visitStatement\28std::__2::unique_ptr>*\2c\20bool\29 +1373:SkSL::GLSLCodeGenerator::writeModifiers\28SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20bool\29 +1374:SkSL::ExpressionStatement::Make\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +1375:SkSL::ConstructorCompound::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +1376:SkSL::Analysis::IsSameExpressionTree\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +1377:SkSL::AliasType::resolve\28\29\20const +1378:SkResourceCache::Add\28SkResourceCache::Rec*\2c\20void*\29 +1379:SkRegion::writeToMemory\28void*\29\20const +1380:SkReadBuffer::readMatrix\28SkMatrix*\29 +1381:SkReadBuffer::readBool\28\29 +1382:SkRasterPipeline::appendConstantColor\28SkArenaAlloc*\2c\20float\20const*\29 +1383:SkRasterClip::setRect\28SkIRect\20const&\29 +1384:SkRasterClip::SkRasterClip\28SkRasterClip\20const&\29 +1385:SkPathWriter::isClosed\28\29\20const +1386:SkPathMeasure::~SkPathMeasure\28\29 +1387:SkPathMeasure::SkPathMeasure\28SkPath\20const&\2c\20bool\2c\20float\29 +1388:SkPath::swap\28SkPath&\29 +1389:SkParse::FindScalars\28char\20const*\2c\20float*\2c\20int\29 +1390:SkPaint::operator=\28SkPaint\20const&\29 +1391:SkOpSpan::computeWindSum\28\29 +1392:SkOpSegment::existing\28double\2c\20SkOpSegment\20const*\29\20const +1393:SkOpSegment::addCurveTo\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkPathWriter*\29\20const +1394:SkOpPtT::find\28SkOpSegment\20const*\29\20const +1395:SkOpCoincidence::addEndMovedSpans\28SkOpSpan\20const*\2c\20SkOpSpanBase\20const*\29 +1396:SkNoDrawCanvas::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +1397:SkMakeImageFromRasterBitmap\28SkBitmap\20const&\2c\20SkCopyPixelsMode\29 +1398:SkImage_Ganesh::SkImage_Ganesh\28sk_sp\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20SkColorInfo\29 +1399:SkImageInfo::makeColorSpace\28sk_sp\29\20const +1400:SkImageInfo::computeOffset\28int\2c\20int\2c\20unsigned\20long\29\20const +1401:SkImage::refColorSpace\28\29\20const +1402:SkGlyph::imageSize\28\29\20const +1403:SkGetICULib\28\29 +1404:SkFont::textToGlyphs\28void\20const*\2c\20unsigned\20long\2c\20SkTextEncoding\2c\20unsigned\20short*\2c\20int\29\20const +1405:SkFont::setSubpixel\28bool\29 +1406:SkDraw::SkDraw\28\29 +1407:SkDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +1408:SkData::MakeZeroInitialized\28unsigned\20long\29 +1409:SkColorTypeIsAlwaysOpaque\28SkColorType\29 +1410:SkColorFilter::makeComposed\28sk_sp\29\20const +1411:SkCodec::SkCodec\28SkEncodedInfo&&\2c\20skcms_PixelFormat\2c\20std::__2::unique_ptr>\2c\20SkEncodedOrigin\29 +1412:SkChopQuadAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +1413:SkCanvas::drawImageRect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +1414:SkBmpCodec::getDstRow\28int\2c\20int\29\20const +1415:SkAutoDescriptor::SkAutoDescriptor\28\29 +1416:SkAAClipBlitterWrapper::init\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1417:SkAAClipBlitterWrapper::SkAAClipBlitterWrapper\28\29 +1418:GrTriangulator::Comparator::sweep_lt\28SkPoint\20const&\2c\20SkPoint\20const&\29\20const +1419:GrTextureProxy::textureType\28\29\20const +1420:GrSurfaceProxy::createSurfaceImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\29\20const +1421:GrStyledShape::writeUnstyledKey\28unsigned\20int*\29\20const +1422:GrStyledShape::simplify\28\29 +1423:GrSkSLFP::setInput\28std::__2::unique_ptr>\29 +1424:GrSimpleMeshDrawOpHelperWithStencil::GrSimpleMeshDrawOpHelperWithStencil\28GrProcessorSet*\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +1425:GrShape::operator=\28GrShape\20const&\29 +1426:GrResourceProvider::createPatternedIndexBuffer\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\2c\20skgpu::UniqueKey\20const*\29 +1427:GrRenderTarget::~GrRenderTarget\28\29 +1428:GrRecordingContextPriv::makeSC\28GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +1429:GrOpFlushState::detachAppliedClip\28\29 +1430:GrGpuBuffer::map\28\29 +1431:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\29 +1432:GrGLSLShaderBuilder::declAppend\28GrShaderVar\20const&\29 +1433:GrGLGpu::didDrawTo\28GrRenderTarget*\29 +1434:GrFragmentProcessors::Make\28GrRecordingContext*\2c\20SkColorFilter\20const*\2c\20std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1435:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +1436:GrCaps::validateSurfaceParams\28SkISize\20const&\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20GrTextureType\29\20const +1437:GrBufferAllocPool::putBack\28unsigned\20long\29 +1438:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29::$_0::operator\28\29\28SkIRect\2c\20SkIRect\29\20const +1439:GrBackendTexture::GrBackendTexture\28\29 +1440:GrAAConvexTessellator::createInsetRing\28GrAAConvexTessellator::Ring\20const&\2c\20GrAAConvexTessellator::Ring*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +1441:FT_Stream_GetByte +1442:FT_Set_Transform +1443:FT_Add_Module +1444:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +1445:AlmostLessOrEqualUlps\28float\2c\20float\29 +1446:ActiveEdge::intersect\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29\20const +1447:wrapper_cmp +1448:void\20std::__2::reverse\5babi:nn180100\5d\28char*\2c\20char*\29 +1449:void\20std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__do_rehash\28unsigned\20long\29 +1450:void\20emscripten::internal::MemberAccess::setWire\28bool\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\2c\20bool\29 +1451:utrace_data_74 +1452:utf8_nextCharSafeBody_74 +1453:utext_setup_74 +1454:uhash_openSize_74 +1455:uhash_nextElement_74 +1456:u_charType_74 +1457:tanf +1458:std::__2::vector>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29 +1459:std::__2::vector>::__alloc\5babi:nn180100\5d\28\29 +1460:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ios_base&\2c\20wchar_t\29 +1461:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ios_base&\2c\20char\29 +1462:std::__2::char_traits::to_int_type\5babi:nn180100\5d\28char\29 +1463:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1464:std::__2::basic_ios>::~basic_ios\28\29 +1465:std::__2::basic_ios>::setstate\5babi:nn180100\5d\28unsigned\20int\29 +1466:std::__2::__compressed_pair_elem::__compressed_pair_elem\5babi:nn180100\5d\28void\20\28*&&\29\28void*\29\29 +1467:sktext::gpu::GlyphVector::~GlyphVector\28\29 +1468:sktext::StrikeMutationMonitor::~StrikeMutationMonitor\28\29 +1469:sktext::StrikeMutationMonitor::StrikeMutationMonitor\28sktext::StrikeForGPU*\29 +1470:skif::RoundOut\28SkRect\29 +1471:skif::LayerSpace::contains\28skif::LayerSpace\20const&\29\20const +1472:skif::FilterResult::AutoSurface::snap\28\29 +1473:skif::FilterResult::AutoSurface::AutoSurface\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult::PixelBoundary\2c\20bool\2c\20SkSurfaceProps\20const*\29 +1474:skif::Backend::~Backend\28\29_2311 +1475:skia_private::TArray::push_back\28skif::FilterResult::Builder::SampledFilterResult&&\29 +1476:skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>::~STArray\28\29 +1477:skia_png_chunk_unknown_handling +1478:skia::textlayout::TextStyle::TextStyle\28\29 +1479:skia::textlayout::TextLine::iterateThroughSingleRunByStyles\28skia::textlayout::TextLine::TextAdjustment\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::StyleType\2c\20std::__2::function\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\20const&\29\20const +1480:skgpu::ganesh::SurfaceFillContext::internalClear\28SkIRect\20const*\2c\20std::__2::array\2c\20bool\29 +1481:skgpu::ganesh::SurfaceDrawContext::fillRectToRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +1482:skgpu::SkSLToBackend\28SkSL::ShaderCaps\20const*\2c\20bool\20\28*\29\28SkSL::Program&\2c\20SkSL::ShaderCaps\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\29\2c\20char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20skgpu::ShaderErrorHandler*\29 +1483:skgpu::GetApproxSize\28SkISize\29 +1484:skcms_Matrix3x3_invert +1485:res_getTableItemByKey_74 +1486:read_curve\28unsigned\20char\20const*\2c\20unsigned\20int\2c\20skcms_Curve*\2c\20unsigned\20int*\29 +1487:icu_74::UnicodeString::operator=\28icu_74::UnicodeString&&\29 +1488:icu_74::UnicodeString::doEquals\28icu_74::UnicodeString\20const&\2c\20int\29\20const +1489:icu_74::UnicodeSet::ensureCapacity\28int\29 +1490:icu_74::UnicodeSet::clear\28\29 +1491:icu_74::UVector::UVector\28void\20\28*\29\28void*\29\2c\20signed\20char\20\28*\29\28UElement\2c\20UElement\29\2c\20UErrorCode&\29 +1492:icu_74::UVector32::setElementAt\28int\2c\20int\29 +1493:icu_74::RuleCharacterIterator::setPos\28icu_74::RuleCharacterIterator::Pos\20const&\29 +1494:icu_74::ResourceTable::findValue\28char\20const*\2c\20icu_74::ResourceValue&\29\20const +1495:icu_74::Locale::operator=\28icu_74::Locale\20const&\29 +1496:icu_74::CharString::extract\28char*\2c\20int\2c\20UErrorCode&\29\20const +1497:hb_vector_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>\2c\20false>::push\28\29 +1498:hb_font_t::scale_glyph_extents\28hb_glyph_extents_t*\29 +1499:hb_buffer_append +1500:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1501:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1502:emscripten::internal::MethodInvoker\29\2c\20void\2c\20SkFont*\2c\20sk_sp>::invoke\28void\20\28SkFont::*\20const&\29\28sk_sp\29\2c\20SkFont*\2c\20sk_sp*\29 +1503:emscripten::internal::Invoker::invoke\28unsigned\20long\20\28*\29\28\29\29 +1504:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +1505:cos +1506:char*\20std::__2::__rewrap_iter\5babi:nn180100\5d>\28char*\2c\20char*\29 +1507:cf2_glyphpath_lineTo +1508:bool\20emscripten::internal::MemberAccess::getWire\28bool\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\29 +1509:alloc_small +1510:af_latin_hints_compute_segments +1511:_hb_glyph_info_set_unicode_props\28hb_glyph_info_t*\2c\20hb_buffer_t*\29 +1512:__wasi_syscall_ret +1513:__lshrti3 +1514:__letf2 +1515:__cxx_global_array_dtor_5556 +1516:\28anonymous\20namespace\29::SkBlurImageFilter::~SkBlurImageFilter\28\29 +1517:SkUTF::UTF8ToUTF16\28unsigned\20short*\2c\20int\2c\20char\20const*\2c\20unsigned\20long\29 +1518:SkUTF::ToUTF16\28int\2c\20unsigned\20short*\29 +1519:SkTextBlobBuilder::~SkTextBlobBuilder\28\29 +1520:SkTextBlobBuilder::ConservativeRunBounds\28SkTextBlob::RunRecord\20const&\29 +1521:SkSwizzler::swizzle\28void*\2c\20unsigned\20char\20const*\29 +1522:SkSurfaces::RenderTarget\28GrRecordingContext*\2c\20skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20int\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const*\2c\20bool\2c\20bool\29 +1523:SkSurface::makeImageSnapshot\28\29 +1524:SkString::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +1525:SkString::insertUnichar\28unsigned\20long\2c\20int\29 +1526:SkStrikeSpec::findOrCreateScopedStrike\28sktext::StrikeForGPUCacheInterface*\29\20const +1527:SkStrikeCache::GlobalStrikeCache\28\29 +1528:SkShader::isAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +1529:SkSL::is_constant_value\28SkSL::Expression\20const&\2c\20double\29 +1530:SkSL::evaluate_pairwise_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +1531:SkSL::\28anonymous\20namespace\29::ReturnsOnAllPathsVisitor::visitStatement\28SkSL::Statement\20const&\29 +1532:SkSL::Type::MakeScalarType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type::NumberKind\2c\20signed\20char\2c\20signed\20char\29 +1533:SkSL::RP::Generator::pushBinaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +1534:SkSL::RP::Builder::push_clone\28int\2c\20int\29 +1535:SkSL::ProgramUsage::remove\28SkSL::Statement\20const*\29 +1536:SkSL::Parser::statement\28bool\29 +1537:SkSL::Operator::determineBinaryType\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\29\20const +1538:SkSL::ModifierFlags::description\28\29\20const +1539:SkSL::Layout::paddedDescription\28\29\20const +1540:SkSL::FieldAccess::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20int\2c\20SkSL::FieldAccessOwnerKind\29 +1541:SkSL::ConstructorCompoundCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1542:SkSL::Compiler::~Compiler\28\29 +1543:SkRuntimeEffect::findChild\28std::__2::basic_string_view>\29\20const +1544:SkRect\20skif::Mapping::map\28SkRect\20const&\2c\20SkMatrix\20const&\29 +1545:SkRectPriv::Subtract\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkIRect*\29 +1546:SkPictureRecorder::SkPictureRecorder\28\29 +1547:SkPictureData::~SkPictureData\28\29 +1548:SkPathMeasure::nextContour\28\29 +1549:SkPathMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29 +1550:SkPathBuilder::lineTo\28SkPoint\29 +1551:SkPath::getPoint\28int\29\20const +1552:SkPath::getLastPt\28SkPoint*\29\20const +1553:SkPaint::setBlender\28sk_sp\29 +1554:SkPaint::setAlphaf\28float\29 +1555:SkOpSegment::addT\28double\29 +1556:SkNoPixelsDevice::ClipState&\20skia_private::TArray::emplace_back\28SkIRect&&\2c\20bool&&\2c\20bool&&\29 +1557:SkNextID::ImageID\28\29 +1558:SkMessageBus::Inbox::Inbox\28unsigned\20int\29 +1559:SkMaskFilterBase::getFlattenableType\28\29\20const +1560:SkImage_Lazy::generator\28\29\20const +1561:SkImage_Base::~SkImage_Base\28\29 +1562:SkImage_Base::SkImage_Base\28SkImageInfo\20const&\2c\20unsigned\20int\29 +1563:SkImageInfo::Make\28SkISize\2c\20SkColorType\2c\20SkAlphaType\2c\20sk_sp\29 +1564:SkImage::isAlphaOnly\28\29\20const +1565:SkFont::getWidthsBounds\28unsigned\20short\20const*\2c\20int\2c\20float*\2c\20SkRect*\2c\20SkPaint\20const*\29\20const +1566:SkFont::getMetrics\28SkFontMetrics*\29\20const +1567:SkFont::SkFont\28sk_sp\2c\20float\29 +1568:SkFont::SkFont\28\29 +1569:SkDrawBase::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20SkRect\20const*\29\20const +1570:SkDevice::setGlobalCTM\28SkM44\20const&\29 +1571:SkConvertPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +1572:SkConic::chopAt\28float\2c\20SkConic*\29\20const +1573:SkColorTypeBytesPerPixel\28SkColorType\29 +1574:SkColorSpaceSingletonFactory::Make\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +1575:SkColorSpace::gammaIsLinear\28\29\20const +1576:SkColorSpace::MakeRGB\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +1577:SkColorFilter::asAColorMode\28unsigned\20int*\2c\20SkBlendMode*\29\20const +1578:SkCodec::fillIncompleteImage\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::ZeroInitialized\2c\20int\2c\20int\29 +1579:SkCanvas::saveLayer\28SkRect\20const*\2c\20SkPaint\20const*\29 +1580:SkCanvas::drawPaint\28SkPaint\20const&\29 +1581:SkCanvas::ImageSetEntry::~ImageSetEntry\28\29 +1582:SkBulkGlyphMetrics::glyphs\28SkSpan\29 +1583:SkBitmap::operator=\28SkBitmap&&\29 +1584:SkBitmap::getGenerationID\28\29\20const +1585:SkArenaAllocWithReset::reset\28\29 +1586:OT::Layout::GPOS_impl::AnchorFormat3::sanitize\28hb_sanitize_context_t*\29\20const +1587:OT::GSUB_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1588:OT::GDEF::get_mark_attachment_type\28unsigned\20int\29\20const +1589:OT::GDEF::get_glyph_class\28unsigned\20int\29\20const +1590:OT::CmapSubtable::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +1591:GrTriangulator::Edge::disconnect\28\29 +1592:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\2c\20bool\29 +1593:GrSurfaceProxyView::mipmapped\28\29\20const +1594:GrSurfaceProxy::instantiateImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::UniqueKey\20const*\29 +1595:GrSimpleMeshDrawOpHelperWithStencil::isCompatible\28GrSimpleMeshDrawOpHelperWithStencil\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +1596:GrSimpleMeshDrawOpHelperWithStencil::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20bool*\29 +1597:GrShape::simplifyRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20unsigned\20int\29 +1598:GrQuad::projectedBounds\28\29\20const +1599:GrProcessorSet::MakeEmptySet\28\29 +1600:GrPorterDuffXPFactory::SimpleSrcOverXP\28\29 +1601:GrPixmap::Allocate\28GrImageInfo\20const&\29 +1602:GrPathTessellationShader::MakeSimpleTriangleShader\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +1603:GrMakeCachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\29 +1604:GrImageInfo::operator=\28GrImageInfo&&\29 +1605:GrImageInfo::makeColorType\28GrColorType\29\20const +1606:GrGpuResource::setUniqueKey\28skgpu::UniqueKey\20const&\29 +1607:GrGpuResource::release\28\29 +1608:GrGpuResource::isPurgeable\28\29\20const +1609:GrGeometryProcessor::textureSampler\28int\29\20const +1610:GrGeometryProcessor::AttributeSet::end\28\29\20const +1611:GrGeometryProcessor::AttributeSet::begin\28\29\20const +1612:GrGLSLShaderBuilder::addFeature\28unsigned\20int\2c\20char\20const*\29 +1613:GrGLGpu::clearErrorsAndCheckForOOM\28\29 +1614:GrGLGpu::bindSurfaceFBOForPixelOps\28GrSurface*\2c\20int\2c\20unsigned\20int\2c\20GrGLGpu::TempFBOTarget\29 +1615:GrGLCompileAndAttachShader\28GrGLContext\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20bool\2c\20GrThreadSafePipelineBuilder::Stats*\2c\20skgpu::ShaderErrorHandler*\29 +1616:GrDirectContextPriv::flushSurfaces\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +1617:GrDefaultGeoProcFactory::Make\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +1618:GrConvertPixels\28GrPixmap\20const&\2c\20GrCPixmap\20const&\2c\20bool\29 +1619:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +1620:GrColorInfo::GrColorInfo\28\29 +1621:GrBlurUtils::convolve_gaussian_1d\28skgpu::ganesh::SurfaceFillContext*\2c\20GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\2c\20SkIRect\20const&\2c\20SkAlphaType\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\29 +1622:GrBackendFormat::operator=\28GrBackendFormat\20const&\29 +1623:FT_GlyphLoader_Rewind +1624:FT_Done_Face +1625:Cr_z_inflate +1626:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +1627:void\20std::__2::__stable_sort\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +1628:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20unsigned\20int*&\2c\20unsigned\20int*&\29 +1629:void\20icu_74::\28anonymous\20namespace\29::MixedBlocks::extend\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\29 +1630:utext_nativeLength_74 +1631:ures_openDirect_74 +1632:ures_getStringWithAlias\28UResourceBundle\20const*\2c\20unsigned\20int\2c\20int\2c\20int*\2c\20UErrorCode*\29 +1633:ures_getStringByKeyWithFallback_74 +1634:ulocimp_getKeywordValue_74 +1635:ulocimp_getCountry_74\28char\20const*\2c\20char\20const**\2c\20UErrorCode&\29 +1636:ulocimp_forLanguageTag_74 +1637:uenum_close_74 +1638:udata_getMemory_74 +1639:ucptrie_openFromBinary_74 +1640:u_charsToUChars_74 +1641:toupper +1642:top12_17160 +1643:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1644:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1645:std::__2::ctype::narrow\5babi:nn180100\5d\28char\2c\20char\29\20const +1646:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28wchar_t\20const*\29 +1647:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1648:std::__2::basic_streambuf>::~basic_streambuf\28\29 +1649:std::__2::basic_streambuf>::setg\5babi:nn180100\5d\28char*\2c\20char*\2c\20char*\29 +1650:std::__2::__num_get::__stage2_int_loop\28wchar_t\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20wchar_t\20const*\29 +1651:std::__2::__num_get::__stage2_int_loop\28char\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20char\20const*\29 +1652:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1653:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1654:src_p\28unsigned\20char\2c\20unsigned\20char\29 +1655:skif::LayerSpace::inverseMapRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29\20const +1656:skif::FilterResult::subset\28skif::LayerSpace\20const&\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +1657:skif::FilterResult::operator=\28skif::FilterResult&&\29 +1658:skia_private::THashMap::operator\5b\5d\28SkSL::Variable\20const*\20const&\29 +1659:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +1660:skia_private::TArray::resize_back\28int\29 +1661:skia_png_sig_cmp +1662:skia_png_get_valid +1663:skia_png_gamma_8bit_correct +1664:skia_png_free_data +1665:skia_png_destroy_read_struct +1666:skia_png_chunk_warning +1667:skia::textlayout::TextLine::measureTextInsideOneRun\28skia::textlayout::SkRange\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20float\2c\20bool\2c\20skia::textlayout::TextLine::TextAdjustment\29\20const +1668:skia::textlayout::Run::positionX\28unsigned\20long\29\20const +1669:skia::textlayout::Run::Run\28skia::textlayout::ParagraphImpl*\2c\20SkShaper::RunHandler::RunInfo\20const&\2c\20unsigned\20long\2c\20float\2c\20bool\2c\20float\2c\20unsigned\20long\2c\20float\29 +1670:skia::textlayout::ParagraphCacheKey::operator==\28skia::textlayout::ParagraphCacheKey\20const&\29\20const +1671:skia::textlayout::FontCollection::enableFontFallback\28\29 +1672:skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\294>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\298>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::ReplicateLineEndPoints\2c\20skgpu::tess::TrackJoinControlPoints>::chopAndWriteCubics\28skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20int\29 +1673:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::vertexSize\28\29\20const +1674:skgpu::ganesh::Device::readSurfaceView\28\29 +1675:skgpu::ganesh::ClipStack::clip\28skgpu::ganesh::ClipStack::RawElement&&\29 +1676:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::RawElement\20const&\29\20const +1677:skgpu::ganesh::ClipStack::RawElement::RawElement\28SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\2c\20SkClipOp\29 +1678:skgpu::Swizzle::asString\28\29\20const +1679:skgpu::ScratchKey::GenerateResourceType\28\29 +1680:skgpu::GetBlendFormula\28bool\2c\20bool\2c\20SkBlendMode\29 +1681:skcms_Transform::$_2::operator\28\29\28skcms_Curve\20const*\2c\20int\29\20const +1682:sbrk +1683:ps_tofixedarray +1684:processPropertySeq\28UBiDi*\2c\20LevState*\2c\20unsigned\20char\2c\20int\2c\20int\29 +1685:png_format_buffer +1686:png_check_keyword +1687:nextafterf +1688:jpeg_huff_decode +1689:init_entry\28char\20const*\2c\20char\20const*\2c\20UErrorCode*\29 +1690:icu_74::UnicodeString::countChar32\28int\2c\20int\29\20const +1691:icu_74::UnicodeString::UnicodeString\28char\20const*\2c\20int\2c\20icu_74::UnicodeString::EInvariant\29 +1692:icu_74::UnicodeSet::setToBogus\28\29 +1693:icu_74::UnicodeSet::getRangeStart\28int\29\20const +1694:icu_74::UnicodeSet::getRangeEnd\28int\29\20const +1695:icu_74::UnicodeSet::getRangeCount\28\29\20const +1696:icu_74::UVector::UVector\28void\20\28*\29\28void*\29\2c\20signed\20char\20\28*\29\28UElement\2c\20UElement\29\2c\20int\2c\20UErrorCode&\29 +1697:icu_74::UVector32::addElement\28int\2c\20UErrorCode&\29 +1698:icu_74::UVector32::UVector32\28int\2c\20UErrorCode&\29 +1699:icu_74::UCharsTrie::next\28int\29 +1700:icu_74::UCharsTrie::branchNext\28char16_t\20const*\2c\20int\2c\20int\29 +1701:icu_74::StackUResourceBundle::StackUResourceBundle\28\29 +1702:icu_74::ReorderingBuffer::appendSupplementary\28int\2c\20unsigned\20char\2c\20UErrorCode&\29 +1703:icu_74::Norm2AllModes::createNFCInstance\28UErrorCode&\29 +1704:icu_74::LanguageBreakEngine::LanguageBreakEngine\28\29 +1705:icu_74::LSR::LSR\28char\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20int\2c\20UErrorCode&\29 +1706:icu_74::CharacterProperties::getInclusionsForProperty\28UProperty\2c\20UErrorCode&\29 +1707:icu_74::CharString::ensureCapacity\28int\2c\20int\2c\20UErrorCode&\29 +1708:hb_unicode_funcs_destroy +1709:hb_serialize_context_t::pop_discard\28\29 +1710:hb_lazy_loader_t\2c\20hb_face_t\2c\205u\2c\20OT::hmtx_accelerator_t>::do_destroy\28OT::hmtx_accelerator_t*\29 +1711:hb_lazy_loader_t\2c\20hb_face_t\2c\2015u\2c\20OT::glyf_accelerator_t>::do_destroy\28OT::glyf_accelerator_t*\29 +1712:hb_font_t::get_glyph_h_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +1713:hb_buffer_t::next_glyph\28\29 +1714:hb_buffer_set_flags +1715:hb_blob_create_sub_blob +1716:hb_array_t::hash\28\29\20const +1717:hairquad\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +1718:fmt_u +1719:flush_pending +1720:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\29\2c\20SkPath*\29 +1721:do_fixed +1722:destroy_face +1723:decltype\28fp\28\28SkRecords::NoOp*\29\28nullptr\29\29\29\20SkRecord::Record::mutate\28SkRecord::Destroyer&\29 +1724:char*\20const&\20std::__2::max\5babi:nn180100\5d\28char*\20const&\2c\20char*\20const&\29 +1725:cf2_stack_pushInt +1726:cf2_interpT2CharString +1727:cf2_glyphpath_moveTo +1728:bool\20hb_hashmap_t::set_with_hash\28unsigned\20int\20const&\2c\20unsigned\20int\2c\20unsigned\20int\20const&\2c\20bool\29 +1729:_isVariantSubtag\28char\20const*\2c\20int\29 +1730:_hb_ot_metrics_get_position_common\28hb_font_t*\2c\20hb_ot_metrics_tag_t\2c\20int*\29 +1731:_getStringOrCopyKey\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char16_t*\2c\20int\2c\20UErrorCode*\29 +1732:__tandf +1733:__syscall_ret +1734:__floatunsitf +1735:__cxa_allocate_exception +1736:\28anonymous\20namespace\29::PathGeoBuilder::createMeshAndPutBackReserve\28\29 +1737:\28anonymous\20namespace\29::MeshOp::fixedFunctionFlags\28\29\20const +1738:\28anonymous\20namespace\29::DrawAtlasOpImpl::fixedFunctionFlags\28\29\20const +1739:WebPDemuxGetI +1740:VP8LDoFillBitWindow +1741:VP8LClear +1742:TT_Get_MM_Var +1743:SkWStream::writeScalar\28float\29 +1744:SkTypeface::isFixedPitch\28\29\20const +1745:SkTypeface::MakeEmpty\28\29 +1746:SkTSect::BinarySearch\28SkTSect*\2c\20SkTSect*\2c\20SkIntersections*\29 +1747:SkTConic::operator\5b\5d\28int\29\20const +1748:SkTBlockList::reset\28\29 +1749:SkTBlockList::reset\28\29 +1750:SkString::insertU32\28unsigned\20long\2c\20unsigned\20int\29 +1751:SkSpecialImages::MakeDeferredFromGpu\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1752:SkShaders::MatrixRec::applyForFragmentProcessor\28SkMatrix\20const&\29\20const +1753:SkShaders::MatrixRec::MatrixRec\28SkMatrix\20const&\29 +1754:SkScan::FillRect\28SkRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +1755:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +1756:SkSL::optimize_comparison\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20bool\20\28*\29\28double\2c\20double\29\29 +1757:SkSL::coalesce_n_way_vector\28SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +1758:SkSL::Type::convertArraySize\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20long\20long\29\20const +1759:SkSL::String::appendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20...\29 +1760:SkSL::RP::Generator::returnComplexity\28SkSL::FunctionDefinition\20const*\29 +1761:SkSL::RP::Builder::dot_floats\28int\29 +1762:SkSL::ProgramUsage::get\28SkSL::FunctionDeclaration\20const&\29\20const +1763:SkSL::Parser::type\28SkSL::Modifiers*\29 +1764:SkSL::Parser::modifiers\28\29 +1765:SkSL::ConstructorDiagonalMatrix::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1766:SkSL::ConstructorArrayCast::~ConstructorArrayCast\28\29 +1767:SkSL::ConstantFolder::MakeConstantValueForVariable\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +1768:SkSL::Compiler::Compiler\28\29 +1769:SkSL::Analysis::IsTrivialExpression\28SkSL::Expression\20const&\29 +1770:SkRuntimeEffectPriv::CanDraw\28SkCapabilities\20const*\2c\20SkRuntimeEffect\20const*\29 +1771:SkRuntimeEffectBuilder::makeShader\28SkMatrix\20const*\29\20const +1772:SkRegion::setPath\28SkPath\20const&\2c\20SkRegion\20const&\29 +1773:SkRegion::operator=\28SkRegion\20const&\29 +1774:SkRegion::op\28SkRegion\20const&\2c\20SkRegion\20const&\2c\20SkRegion::Op\29 +1775:SkRegion::Iterator::next\28\29 +1776:SkRasterPipeline::compile\28\29\20const +1777:SkRasterPipeline::appendClampIfNormalized\28SkImageInfo\20const&\29 +1778:SkRasterClip::translate\28int\2c\20int\2c\20SkRasterClip*\29\20const +1779:SkRasterClip::op\28SkIRect\20const&\2c\20SkClipOp\29 +1780:SkRRect::transform\28SkMatrix\20const&\2c\20SkRRect*\29\20const +1781:SkPixmap::extractSubset\28SkPixmap*\2c\20SkIRect\20const&\29\20const +1782:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20SkBBHFactory*\29 +1783:SkPathWriter::finishContour\28\29 +1784:SkPathStroker::cubicPerpRay\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +1785:SkPathMeasure::getPosTan\28float\2c\20SkPoint*\2c\20SkPoint*\29 +1786:SkPath::getSegmentMasks\28\29\20const +1787:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\29 +1788:SkPaintPriv::ComputeLuminanceColor\28SkPaint\20const&\29 +1789:SkPaint::nothingToDraw\28\29\20const +1790:SkPaint::isSrcOver\28\29\20const +1791:SkOpAngle::linesOnOriginalSide\28SkOpAngle\20const*\29 +1792:SkNotifyBitmapGenIDIsStale\28unsigned\20int\29 +1793:SkNoDrawCanvas::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +1794:SkMipmap::Build\28SkPixmap\20const&\2c\20SkDiscardableMemory*\20\28*\29\28unsigned\20long\29\2c\20bool\29 +1795:SkMeshSpecification::~SkMeshSpecification\28\29 +1796:SkMemoryStream::SkMemoryStream\28void\20const*\2c\20unsigned\20long\2c\20bool\29 +1797:SkMatrix::setSinCos\28float\2c\20float\2c\20float\2c\20float\29 +1798:SkMatrix::setRSXform\28SkRSXform\20const&\29 +1799:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint3\20const*\2c\20int\29\20const +1800:SkMaskBuilder::AllocImage\28unsigned\20long\2c\20SkMaskBuilder::AllocType\29 +1801:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_2D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1802:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_1D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1803:SkIntersections::insertNear\28double\2c\20double\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29 +1804:SkIntersections::flip\28\29 +1805:SkImageFilters::Empty\28\29 +1806:SkImageFilter_Base::~SkImageFilter_Base\28\29 +1807:SkGlyph::drawable\28\29\20const +1808:SkFont::unicharToGlyph\28int\29\20const +1809:SkFont::setTypeface\28sk_sp\29 +1810:SkFont::setHinting\28SkFontHinting\29 +1811:SkFindQuadMaxCurvature\28SkPoint\20const*\29 +1812:SkEvalCubicAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29 +1813:SkDrawTiler::SkDrawTiler\28SkBitmapDevice*\2c\20SkRect\20const*\29 +1814:SkDevice::accessPixels\28SkPixmap*\29 +1815:SkDeque::SkDeque\28unsigned\20long\2c\20void*\2c\20unsigned\20long\2c\20int\29 +1816:SkDCubic::FindExtrema\28double\20const*\2c\20double*\29 +1817:SkCodec::getPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const*\29 +1818:SkCanvas::internalRestore\28\29 +1819:SkCanvas::init\28sk_sp\29 +1820:SkCanvas::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +1821:SkBlendMode_AsCoeff\28SkBlendMode\2c\20SkBlendModeCoeff*\2c\20SkBlendModeCoeff*\29 +1822:SkBlendMode\20SkReadBuffer::read32LE\28SkBlendMode\29 +1823:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29 +1824:SkAutoPixmapStorage::tryAlloc\28SkImageInfo\20const&\29 +1825:SkAAClip::SkAAClip\28\29 +1826:Read255UShort +1827:OT::glyf_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1828:OT::VariationStore::sanitize\28hb_sanitize_context_t*\29\20const +1829:OT::Layout::GPOS_impl::ValueFormat::sanitize_value_devices\28hb_sanitize_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\29\20const +1830:OT::Layout::GPOS_impl::ValueFormat::apply_value\28OT::hb_ot_apply_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\2c\20hb_glyph_position_t&\29\20const +1831:GrTriangulator::VertexList::insert\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\29 +1832:GrTriangulator::Poly::addEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Side\2c\20GrTriangulator*\29 +1833:GrTriangulator::EdgeList::remove\28GrTriangulator::Edge*\29 +1834:GrStyledShape::operator=\28GrStyledShape\20const&\29 +1835:GrSimpleMeshDrawOpHelperWithStencil::createProgramInfoWithStencil\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1836:GrResourceCache::purgeAsNeeded\28\29 +1837:GrRenderTask::addDependency\28GrDrawingManager*\2c\20GrSurfaceProxy*\2c\20skgpu::Mipmapped\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +1838:GrRenderTask::GrRenderTask\28\29 +1839:GrRenderTarget::onRelease\28\29 +1840:GrProxyProvider::findOrCreateProxyByUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxy::UseAllocator\29 +1841:GrProcessorSet::operator==\28GrProcessorSet\20const&\29\20const +1842:GrPathUtils::generateQuadraticPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +1843:GrMeshDrawOp::QuadHelper::QuadHelper\28GrMeshDrawTarget*\2c\20unsigned\20long\2c\20int\29 +1844:GrIsStrokeHairlineOrEquivalent\28GrStyle\20const&\2c\20SkMatrix\20const&\2c\20float*\29 +1845:GrImageContext::abandoned\28\29 +1846:GrGpuResource::registerWithCache\28skgpu::Budgeted\29 +1847:GrGpuBuffer::isMapped\28\29\20const +1848:GrGpu::submitToGpu\28GrSubmitInfo\20const&\29 +1849:GrGpu::didWriteToSurface\28GrSurface*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const*\2c\20unsigned\20int\29\20const +1850:GrGeometryProcessor::ProgramImpl::setupUniformColor\28GrGLSLFPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20GrResourceHandle*\29 +1851:GrGLGpu::flushRenderTarget\28GrGLRenderTarget*\2c\20bool\29 +1852:GrFragmentProcessor::visitTextureEffects\28std::__2::function\20const&\29\20const +1853:GrFragmentProcessor::visitProxies\28std::__2::function\20const&\29\20const +1854:GrFragmentProcessor::MakeColor\28SkRGBA4f<\28SkAlphaType\292>\29 +1855:GrBufferAllocPool::makeSpace\28unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\29 +1856:GrBackendTextures::GetGLTextureInfo\28GrBackendTexture\20const&\2c\20GrGLTextureInfo*\29 +1857:FilterLoop26_C +1858:FT_Vector_Transform +1859:FT_Vector_NormLen +1860:FT_Outline_Transform +1861:CFF::dict_opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +1862:AlmostBetweenUlps\28float\2c\20float\2c\20float\29 +1863:1625 +1864:1626 +1865:1627 +1866:1628 +1867:1629 +1868:1630 +1869:1631 +1870:void\20extend_pts<\28SkPaint::Cap\292>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1871:void\20extend_pts<\28SkPaint::Cap\291>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1872:utext_openUChars_74 +1873:utext_char32At_74 +1874:ures_openWithType\28UResourceBundle*\2c\20char\20const*\2c\20char\20const*\2c\20UResOpenType\2c\20UErrorCode*\29 +1875:ures_getSize_74 +1876:udata_openChoice_74 +1877:ucptrie_internalSmallU8Index_74 +1878:ucptrie_get_74 +1879:ubidi_getMemory_74 +1880:ubidi_getClass_74 +1881:transform\28unsigned\20int*\2c\20unsigned\20char\20const*\29 +1882:toUpperOrTitle\28int\2c\20int\20\28*\29\28void*\2c\20signed\20char\29\2c\20void*\2c\20char16_t\20const**\2c\20int\2c\20signed\20char\29 +1883:strtoul +1884:strtod +1885:strcspn +1886:std::__2::locale::locale\28std::__2::locale\20const&\29 +1887:std::__2::locale::classic\28\29 +1888:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const +1889:std::__2::chrono::__libcpp_steady_clock_now\28\29 +1890:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28char\20const*\29 +1891:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20char\20const*\29 +1892:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +1893:std::__2::__wrap_iter\20std::__2::vector>::__insert_with_size\5babi:ne180100\5d\28std::__2::__wrap_iter\2c\20float\20const*\2c\20float\20const*\2c\20long\29 +1894:std::__2::__throw_bad_variant_access\5babi:ne180100\5d\28\29 +1895:std::__2::__split_buffer>::push_front\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +1896:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20wchar_t&\29 +1897:std::__2::__num_get::__do_widen\28std::__2::ios_base&\2c\20wchar_t*\29\20const +1898:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20char&\29 +1899:std::__2::__itoa::__append1\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1900:sktext::gpu::VertexFiller::vertexStride\28SkMatrix\20const&\29\20const +1901:skif::RoundIn\28SkRect\29 +1902:skif::LayerSpace::round\28\29\20const +1903:skif::FilterResult::applyTransform\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkSamplingOptions\20const&\29\20const +1904:skif::FilterResult::Builder::~Builder\28\29 +1905:skif::FilterResult::Builder::Builder\28skif::Context\20const&\29 +1906:skia_private::THashTable::Traits>::resize\28int\29 +1907:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +1908:skia_private::TArray::resize_back\28int\29 +1909:skia_private::TArray::push_back_raw\28int\29 +1910:skia_png_set_progressive_read_fn +1911:skia_png_set_longjmp_fn +1912:skia_png_set_interlace_handling +1913:skia_png_reciprocal +1914:skia_png_read_chunk_header +1915:skia_png_get_io_ptr +1916:skia_png_calloc +1917:skia::textlayout::TextLine::~TextLine\28\29 +1918:skia::textlayout::ParagraphStyle::ParagraphStyle\28skia::textlayout::ParagraphStyle\20const&\29 +1919:skia::textlayout::ParagraphCacheKey::~ParagraphCacheKey\28\29 +1920:skia::textlayout::OneLineShaper::RunBlock*\20std::__2::vector>::__emplace_back_slow_path\28skia::textlayout::OneLineShaper::RunBlock&\29 +1921:skia::textlayout::FontCollection::findTypefaces\28std::__2::vector>\20const&\2c\20SkFontStyle\2c\20std::__2::optional\20const&\29 +1922:skia::textlayout::Cluster::trimmedWidth\28unsigned\20long\29\20const +1923:skgpu::ganesh::TextureOp::BatchSizeLimiter::createOp\28GrTextureSetEntry*\2c\20int\2c\20GrAAType\29 +1924:skgpu::ganesh::SurfaceFillContext::fillWithFP\28std::__2::unique_ptr>\29 +1925:skgpu::ganesh::SurfaceDrawContext::drawShapeUsingPathRenderer\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\2c\20bool\29 +1926:skgpu::ganesh::SurfaceDrawContext::drawRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const*\29 +1927:skgpu::ganesh::SurfaceDrawContext::drawRRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20GrStyle\20const&\29 +1928:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29 +1929:skgpu::ganesh::SmallPathAtlasMgr::reset\28\29 +1930:skgpu::ganesh::QuadPerEdgeAA::CalcIndexBufferOption\28GrAAType\2c\20int\29 +1931:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29::$_0::operator\28\29\28GrSurfaceProxyView\20const&\29\20const +1932:skgpu::ganesh::Device::targetProxy\28\29 +1933:skgpu::ganesh::ClipStack::getConservativeBounds\28\29\20const +1934:skgpu::TAsyncReadResult::addTransferResult\28skgpu::ganesh::SurfaceContext::PixelTransferResult\20const&\2c\20SkISize\2c\20unsigned\20long\2c\20skgpu::TClientMappedBufferManager*\29 +1935:skgpu::Swizzle::apply\28SkRasterPipeline*\29\20const +1936:skgpu::Plot::resetRects\28\29 +1937:skcms_TransferFunction_invert +1938:res_getTableItemByIndex_74 +1939:res_getArrayItem_74 +1940:ps_dimension_add_t1stem +1941:powf +1942:log +1943:jcopy_sample_rows +1944:icu_74::initSingletons\28char\20const*\2c\20UErrorCode&\29 +1945:icu_74::\28anonymous\20namespace\29::AliasReplacer::replaceLanguage\28bool\2c\20bool\2c\20bool\2c\20icu_74::UVector&\2c\20UErrorCode&\29 +1946:icu_74::UnicodeString::doReplace\28int\2c\20int\2c\20icu_74::UnicodeString\20const&\2c\20int\2c\20int\29 +1947:icu_74::UnicodeString::append\28int\29 +1948:icu_74::UnicodeSetStringSpan::UnicodeSetStringSpan\28icu_74::UnicodeSet\20const&\2c\20icu_74::UVector\20const&\2c\20unsigned\20int\29 +1949:icu_74::UnicodeSet::spanUTF8\28char\20const*\2c\20int\2c\20USetSpanCondition\29\20const +1950:icu_74::UnicodeSet::spanBack\28char16_t\20const*\2c\20int\2c\20USetSpanCondition\29\20const +1951:icu_74::UnicodeSet::spanBackUTF8\28char\20const*\2c\20int\2c\20USetSpanCondition\29\20const +1952:icu_74::UnicodeSet::retain\28int\20const*\2c\20int\2c\20signed\20char\29 +1953:icu_74::UnicodeSet::removeAllStrings\28\29 +1954:icu_74::UnicodeSet::operator=\28icu_74::UnicodeSet\20const&\29 +1955:icu_74::UnicodeSet::complement\28\29 +1956:icu_74::UnicodeSet::_add\28icu_74::UnicodeString\20const&\29 +1957:icu_74::UVector32::setSize\28int\29 +1958:icu_74::UCharsTrieBuilder::write\28char16_t\20const*\2c\20int\29 +1959:icu_74::StringEnumeration::~StringEnumeration\28\29 +1960:icu_74::RuleCharacterIterator::getPos\28icu_74::RuleCharacterIterator::Pos&\29\20const +1961:icu_74::RuleBasedBreakIterator::BreakCache::populatePreceding\28UErrorCode&\29 +1962:icu_74::ResourceDataValue::~ResourceDataValue\28\29 +1963:icu_74::ReorderingBuffer::previousCC\28\29 +1964:icu_74::Normalizer2Impl::compose\28char16_t\20const*\2c\20char16_t\20const*\2c\20signed\20char\2c\20signed\20char\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +1965:icu_74::Normalizer2Factory::getNFCImpl\28UErrorCode&\29 +1966:icu_74::LocaleUtility::initLocaleFromName\28icu_74::UnicodeString\20const&\2c\20icu_74::Locale&\29 +1967:icu_74::LocaleKeyFactory::~LocaleKeyFactory\28\29 +1968:icu_74::Locale::setToBogus\28\29 +1969:icu_74::LSR::indexForRegion\28char\20const*\29 +1970:icu_74::LSR::LSR\28icu_74::StringPiece\2c\20icu_74::StringPiece\2c\20icu_74::StringPiece\2c\20int\2c\20UErrorCode&\29 +1971:icu_74::BreakIterator::createInstance\28icu_74::Locale\20const&\2c\20int\2c\20UErrorCode&\29 +1972:hb_font_t::mults_changed\28\29 +1973:hb_font_t::has_func\28unsigned\20int\29 +1974:hb_buffer_create_similar +1975:ft_service_list_lookup +1976:fseek +1977:fflush +1978:expm1 +1979:emscripten::internal::MethodInvoker::invoke\28void\20\28GrDirectContext::*\20const&\29\28\29\2c\20GrDirectContext*\29 +1980:emscripten::internal::Invoker>::invoke\28sk_sp\20\28*\29\28\29\29 +1981:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +1982:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28SkFont&\29\2c\20SkFont*\29 +1983:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkCanvas\20const&\2c\20unsigned\20long\29\2c\20SkCanvas*\2c\20unsigned\20long\29 +1984:decltype\28fp.sanitize\28this\2c\20std::forward\28fp1\29\29\29\20hb_sanitize_context_t::_dispatch\2c\20true>\2c\20OT::ChainContextFormat3\20const*>\28OT::OffsetTo\2c\20true>\20const&\2c\20hb_priority<1u>\2c\20OT::ChainContextFormat3\20const*&&\29 +1985:crc32_z +1986:char*\20sktext::gpu::BagOfBytes::allocateBytesFor\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +1987:cf2_hintmap_insertHint +1988:cf2_hintmap_build +1989:cf2_glyphpath_pushPrevElem +1990:bool\20std::__2::__less::operator\28\29\5babi:nn180100\5d\28unsigned\20int\20const&\2c\20unsigned\20long\20const&\29\20const +1991:blit_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +1992:afm_stream_read_one +1993:af_shaper_get_cluster +1994:af_latin_hints_link_segments +1995:af_latin_compute_stem_width +1996:af_glyph_hints_reload +1997:acosf +1998:__sin +1999:__cos +2000:\28anonymous\20namespace\29::PathSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +2001:VP8LHuffmanTablesDeallocate +2002:UDataMemory_createNewInstance_74 +2003:SkWriter32::writeSampling\28SkSamplingOptions\20const&\29 +2004:SkVertices::Builder::detach\28\29 +2005:SkUTF::NextUTF8WithReplacement\28char\20const**\2c\20char\20const*\29 +2006:SkTypeface_FreeType::~SkTypeface_FreeType\28\29 +2007:SkTypeface_FreeType::FaceRec::~FaceRec\28\29 +2008:SkTypeface::SkTypeface\28SkFontStyle\20const&\2c\20bool\29 +2009:SkTextBlob::RunRecord::textSizePtr\28\29\20const +2010:SkTMultiMap::remove\28skgpu::ScratchKey\20const&\2c\20GrGpuResource\20const*\29 +2011:SkTMultiMap::insert\28skgpu::ScratchKey\20const&\2c\20GrGpuResource*\29 +2012:SkTDStorage::insert\28int\2c\20int\2c\20void\20const*\29 +2013:SkTDPQueue<\28anonymous\20namespace\29::RunIteratorQueue::Entry\2c\20&\28anonymous\20namespace\29::RunIteratorQueue::CompareEntry\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\2c\20\28int*\20\28*\29\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\290>::insert\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\29 +2014:SkSwizzler::Make\28SkEncodedInfo\20const&\2c\20unsigned\20int\20const*\2c\20SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20SkIRect\20const*\29 +2015:SkSurfaces::Raster\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20SkSurfaceProps\20const*\29 +2016:SkSurface_Base::~SkSurface_Base\28\29 +2017:SkString::resize\28unsigned\20long\29 +2018:SkStrikeSpec::SkStrikeSpec\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +2019:SkStrikeSpec::MakeMask\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +2020:SkStrikeSpec::MakeCanonicalized\28SkFont\20const&\2c\20SkPaint\20const*\29 +2021:SkStrikeCache::findOrCreateStrike\28SkStrikeSpec\20const&\29 +2022:SkStrike::unlock\28\29 +2023:SkStrike::lock\28\29 +2024:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +2025:SkShaders::MatrixRec::apply\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2026:SkShaders::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29 +2027:SkScan::FillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\29 +2028:SkScalerContext_FreeType::emboldenIfNeeded\28FT_FaceRec_*\2c\20FT_GlyphSlotRec_*\2c\20unsigned\20short\29 +2029:SkSafeMath::Add\28unsigned\20long\2c\20unsigned\20long\29 +2030:SkSL::Type::displayName\28\29\20const +2031:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20double\2c\20SkSL::Position\29\20const +2032:SkSL::RP::SlotManager::addSlotDebugInfoForGroup\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20int*\2c\20bool\29 +2033:SkSL::RP::Generator::foldComparisonOp\28SkSL::Operator\2c\20int\29 +2034:SkSL::RP::Builder::branch_if_no_lanes_active\28int\29 +2035:SkSL::PrefixExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +2036:SkSL::Parser::parseArrayDimensions\28SkSL::Position\2c\20SkSL::Type\20const**\29 +2037:SkSL::Parser::arraySize\28long\20long*\29 +2038:SkSL::Operator::operatorName\28\29\20const +2039:SkSL::ModifierFlags::paddedDescription\28\29\20const +2040:SkSL::ExpressionArray::clone\28\29\20const +2041:SkSL::ConstantFolder::GetConstantValue\28SkSL::Expression\20const&\2c\20double*\29 +2042:SkSL::ConstantFolder::GetConstantInt\28SkSL::Expression\20const&\2c\20long\20long*\29 +2043:SkSL::Compiler::convertProgram\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::ProgramSettings\20const&\29 +2044:SkResourceCache::remove\28SkResourceCache::Rec*\29 +2045:SkRegion::op\28SkRegion\20const&\2c\20SkIRect\20const&\2c\20SkRegion::Op\29 +2046:SkRegion::Iterator::Iterator\28SkRegion\20const&\29 +2047:SkRecords::FillBounds::bounds\28SkRecords::DrawArc\20const&\29\20const +2048:SkReadBuffer::setMemory\28void\20const*\2c\20unsigned\20long\29 +2049:SkRasterClip::SkRasterClip\28SkIRect\20const&\29 +2050:SkRRect::writeToMemory\28void*\29\20const +2051:SkRRect::setRectXY\28SkRect\20const&\2c\20float\2c\20float\29 +2052:SkPointPriv::DistanceToLineBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPointPriv::Side*\29 +2053:SkPoint::setNormalize\28float\2c\20float\29 +2054:SkPngCodecBase::~SkPngCodecBase\28\29 +2055:SkPixmapUtils::SwapWidthHeight\28SkImageInfo\20const&\29 +2056:SkPictureRecorder::finishRecordingAsPicture\28\29 +2057:SkPathPriv::ComputeFirstDirection\28SkPath\20const&\29 +2058:SkPathEdgeIter::SkPathEdgeIter\28SkPath\20const&\29 +2059:SkPath::rewind\28\29 +2060:SkPath::isLine\28SkPoint*\29\20const +2061:SkPath::incReserve\28int\2c\20int\2c\20int\29 +2062:SkPath::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2063:SkPaint::setStrokeCap\28SkPaint::Cap\29 +2064:SkPaint::refShader\28\29\20const +2065:SkOpSpan::setWindSum\28int\29 +2066:SkOpSegment::markDone\28SkOpSpan*\29 +2067:SkOpSegment::markAndChaseWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int\2c\20int\2c\20SkOpSpanBase**\29 +2068:SkOpContourBuilder::addCurve\28SkPath::Verb\2c\20SkPoint\20const*\2c\20float\29 +2069:SkOpAngle::starter\28\29 +2070:SkOpAngle::insert\28SkOpAngle*\29 +2071:SkMatrixPriv::InverseMapRect\28SkMatrix\20const&\2c\20SkRect*\2c\20SkRect\20const&\29 +2072:SkMatrix::setSinCos\28float\2c\20float\29 +2073:SkMatrix::decomposeScale\28SkSize*\2c\20SkMatrix*\29\20const +2074:SkMaskFilter::MakeBlur\28SkBlurStyle\2c\20float\2c\20bool\29 +2075:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29 +2076:SkMD5::write\28void\20const*\2c\20unsigned\20long\29 +2077:SkLineClipper::IntersectLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\29 +2078:SkImage_GaneshBase::SkImage_GaneshBase\28sk_sp\2c\20SkImageInfo\2c\20unsigned\20int\29 +2079:SkImageGenerator::onRefEncodedData\28\29 +2080:SkImage::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\29\20const +2081:SkImage::makeRasterImage\28GrDirectContext*\2c\20SkImage::CachingHint\29\20const +2082:SkIDChangeListener::SkIDChangeListener\28\29 +2083:SkIDChangeListener::List::reset\28\29 +2084:SkGradientBaseShader::flatten\28SkWriteBuffer&\29\20const +2085:SkFontMgr::RefEmpty\28\29 +2086:SkFont::setEdging\28SkFont::Edging\29 +2087:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda0'\28\29::operator\28\29\28\29\20const +2088:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda'\28\29::operator\28\29\28\29\20const +2089:SkEvalQuadAt\28SkPoint\20const*\2c\20float\29 +2090:SkEncodedInfo::makeImageInfo\28\29\20const +2091:SkEdgeClipper::next\28SkPoint*\29 +2092:SkDevice::scalerContextFlags\28\29\20const +2093:SkConic::evalAt\28float\2c\20SkPoint*\2c\20SkPoint*\29\20const +2094:SkColorInfo::SkColorInfo\28SkColorType\2c\20SkAlphaType\2c\20sk_sp\29 +2095:SkColorFilters::Blend\28unsigned\20int\2c\20SkBlendMode\29 +2096:SkCodec::skipScanlines\28int\29 +2097:SkChopCubicAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +2098:SkCapabilities::RasterBackend\28\29 +2099:SkCanvas::topDevice\28\29\20const +2100:SkCanvas::saveLayer\28SkCanvas::SaveLayerRec\20const&\29 +2101:SkCanvas::imageInfo\28\29\20const +2102:SkCanvas::drawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +2103:SkCanvas::drawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +2104:SkCanvas::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +2105:SkBmpBaseCodec::~SkBmpBaseCodec\28\29 +2106:SkBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +2107:SkBitmap::operator=\28SkBitmap\20const&\29 +2108:SkBitmap::extractSubset\28SkBitmap*\2c\20SkIRect\20const&\29\20const +2109:SkBitmap::SkBitmap\28SkBitmap&&\29 +2110:SkBinaryWriteBuffer::writeByteArray\28void\20const*\2c\20unsigned\20long\29 +2111:SkBinaryWriteBuffer::SkBinaryWriteBuffer\28SkSerialProcs\20const&\29 +2112:SkBaseShadowTessellator::handleLine\28SkPoint\20const&\29 +2113:SkAAClip::setRegion\28SkRegion\20const&\29 +2114:SaveErrorCode +2115:R +2116:OT::hb_ot_apply_context_t::_set_glyph_class\28unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +2117:OT::cmap::find_subtable\28unsigned\20int\2c\20unsigned\20int\29\20const +2118:GrXPFactory::FromBlendMode\28SkBlendMode\29 +2119:GrTriangulator::setBottom\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2120:GrTriangulator::mergeCollinearEdges\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2121:GrThreadSafeCache::find\28skgpu::UniqueKey\20const&\29 +2122:GrThreadSafeCache::add\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2123:GrThreadSafeCache::Entry::makeEmpty\28\29 +2124:GrSurfaceProxyView::operator==\28GrSurfaceProxyView\20const&\29\20const +2125:GrSurfaceProxyView::Copy\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\29 +2126:GrSurfaceProxyPriv::doLazyInstantiation\28GrResourceProvider*\29 +2127:GrSurfaceProxy::isFunctionallyExact\28\29\20const +2128:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20sk_sp*\29 +2129:GrSimpleMeshDrawOpHelperWithStencil::fixedFunctionFlags\28\29\20const +2130:GrSimpleMeshDrawOpHelper::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20GrProcessorAnalysisColor*\29 +2131:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrProcessorSet&&\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrPipeline::InputFlags\2c\20GrUserStencilSettings\20const*\29 +2132:GrSimpleMeshDrawOpHelper::CreatePipeline\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20skgpu::Swizzle\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrProcessorSet&&\2c\20GrPipeline::InputFlags\29 +2133:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20void\20const*\2c\20skgpu::UniqueKey\20const&\29 +2134:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20skgpu::UniqueKey\20const&\2c\20void\20\28*\29\28skgpu::VertexWriter\2c\20unsigned\20long\29\29 +2135:GrResourceCache::findAndRefScratchResource\28skgpu::ScratchKey\20const&\29 +2136:GrRecordingContextPriv::makeSFC\28GrImageInfo\2c\20std::__2::basic_string_view>\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2137:GrQuadUtils::TessellationHelper::Vertices::moveAlong\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +2138:GrQuad::asRect\28SkRect*\29\20const +2139:GrProcessorSet::GrProcessorSet\28GrProcessorSet&&\29 +2140:GrPathUtils::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +2141:GrGpu::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +2142:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +2143:GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +2144:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +2145:GrGLSLColorSpaceXformHelper::emitCode\28GrGLSLUniformHandler*\2c\20GrColorSpaceXform\20const*\2c\20unsigned\20int\29 +2146:GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +2147:GrGLRenderTarget::bindInternal\28unsigned\20int\2c\20bool\29 +2148:GrGLGpu::getErrorAndCheckForOOM\28\29 +2149:GrGLGpu::bindTexture\28int\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20GrGLTexture*\29 +2150:GrFragmentProcessor::visitWithImpls\28std::__2::function\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\20const +2151:GrFragmentProcessor::ColorMatrix\28std::__2::unique_ptr>\2c\20float\20const*\2c\20bool\2c\20bool\2c\20bool\29 +2152:GrDrawingManager::appendTask\28sk_sp\29 +2153:GrColorInfo::GrColorInfo\28GrColorInfo\20const&\29 +2154:GrCaps::isFormatCompressed\28GrBackendFormat\20const&\29\20const +2155:GrAAConvexTessellator::lineTo\28SkPoint\20const&\2c\20GrAAConvexTessellator::CurveState\29 +2156:FT_Stream_OpenMemory +2157:FT_Select_Charmap +2158:FT_Get_Next_Char +2159:FT_Get_Module_Interface +2160:FT_Done_Size +2161:DecodeImageStream +2162:CFF::opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +2163:CFF::Charset::get_glyph\28unsigned\20int\2c\20unsigned\20int\29\20const +2164:1926 +2165:1927 +2166:1928 +2167:wuffs_gif__decoder__num_decoded_frames +2168:wmemchr +2169:void\20std::__2::reverse\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t*\29 +2170:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29_15865 +2171:void\20merge_sort<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +2172:void\20merge_sort<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +2173:void\20icu_74::\28anonymous\20namespace\29::MixedBlocks::extend\28unsigned\20int\20const*\2c\20int\2c\20int\2c\20int\29 +2174:void\20emscripten::internal::MemberAccess::setWire\28float\20StrokeOpts::*\20const&\2c\20StrokeOpts&\2c\20float\29 +2175:validate_offsetToRestore\28SkReadBuffer*\2c\20unsigned\20long\29 +2176:utrie2_enum_74 +2177:utext_clone_74 +2178:ustr_hashUCharsN_74 +2179:ures_getValueWithFallback_74 +2180:uprv_isInvariantUString_74 +2181:umutablecptrie_set_74 +2182:umutablecptrie_close_74 +2183:uloc_getVariant_74 +2184:uhash_setValueDeleter_74 +2185:uenum_next_74 +2186:ubidi_setPara_74 +2187:ubidi_getVisualRun_74 +2188:ubidi_getRuns_74 +2189:u_strstr_74 +2190:u_getPropertyValueEnum_74 +2191:u_getIntPropertyValue_74 +2192:tt_set_mm_blend +2193:tt_face_get_ps_name +2194:tt_face_get_location +2195:trinkle +2196:strtox_17334 +2197:std::__2::unique_ptr::release\5babi:nn180100\5d\28\29 +2198:std::__2::pair\2c\20void*>*>\2c\20bool>\20std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__emplace_unique_key_args\2c\20std::__2::tuple<>>\28GrTriangulator::Vertex*\20const&\2c\20std::__2::piecewise_construct_t\20const&\2c\20std::__2::tuple&&\2c\20std::__2::tuple<>&&\29 +2199:std::__2::pair::pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +2200:std::__2::moneypunct::do_decimal_point\28\29\20const +2201:std::__2::moneypunct::do_decimal_point\28\29\20const +2202:std::__2::istreambuf_iterator>::istreambuf_iterator\5babi:nn180100\5d\28std::__2::basic_istream>&\29 +2203:std::__2::ios_base::good\5babi:nn180100\5d\28\29\20const +2204:std::__2::default_delete\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair\2c\20SkIcuBreakIteratorCache::Request\2c\20skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair\2c\20SkIcuBreakIteratorCache::Request\2c\20skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair>::Slot>::type\20std::__2::default_delete\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair\2c\20SkIcuBreakIteratorCache::Request\2c\20skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair\2c\20SkIcuBreakIteratorCache::Request\2c\20skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair>::Slot>\28skia_private::THashTable\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair\2c\20SkIcuBreakIteratorCache::Request\2c\20skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair>::Slot*\29\20const +2205:std::__2::ctype::toupper\5babi:nn180100\5d\28char\29\20const +2206:std::__2::chrono::duration>::duration\5babi:nn180100\5d\28long\20long\20const&\29 +2207:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +2208:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +2209:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +2210:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +2211:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +2212:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +2213:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +2214:std::__2::basic_string\2c\20std::__2::allocator>&\20std::__2::basic_string\2c\20std::__2::allocator>::__assign_no_alias\28char\20const*\2c\20unsigned\20long\29 +2215:std::__2::basic_streambuf>::__pbump\5babi:nn180100\5d\28long\29 +2216:std::__2::basic_iostream>::~basic_iostream\28\29_17552 +2217:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::allocator&\2c\20wchar_t*\2c\20unsigned\20long\29 +2218:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::allocator&\2c\20char*\2c\20unsigned\20long\29 +2219:std::__2::__shared_count::__release_shared\5babi:nn180100\5d\28\29 +2220:std::__2::__num_put_base::__format_int\28char*\2c\20char\20const*\2c\20bool\2c\20unsigned\20int\29 +2221:std::__2::__num_put_base::__format_float\28char*\2c\20char\20const*\2c\20unsigned\20int\29 +2222:std::__2::__itoa::__append8\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2223:sktext::gpu::VertexFiller::deviceRectAndCheckTransform\28SkMatrix\20const&\29\20const +2224:sktext::gpu::TextBlob::Key::operator==\28sktext::gpu::TextBlob::Key\20const&\29\20const +2225:sktext::gpu::GlyphVector::packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29 +2226:sktext::SkStrikePromise::strike\28\29 +2227:skif::\28anonymous\20namespace\29::downscale_step_count\28float\29 +2228:skif::LayerSpace::relevantSubset\28skif::LayerSpace\2c\20SkTileMode\29\20const +2229:skif::FilterResult::getAnalyzedShaderView\28skif::Context\20const&\2c\20SkSamplingOptions\20const&\2c\20SkEnumBitMask\29\20const +2230:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20bool\2c\20SkBlender\20const*\29\20const +2231:skif::FilterResult::applyCrop\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkTileMode\29\20const +2232:skif::Context::~Context\28\29 +2233:skia_private::THashTable\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair>::resize\28int\29 +2234:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +2235:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::removeSlot\28int\29 +2236:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +2237:skia_private::THashTable\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair\2c\20SkIcuBreakIteratorCache::Request\2c\20skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::Pair&&\2c\20unsigned\20int\29 +2238:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot::emplace\28sk_sp&&\2c\20unsigned\20int\29 +2239:skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::~THashMap\28\29 +2240:skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::THashMap\28std::initializer_list>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>\29 +2241:skia_private::TArray::move\28void*\29 +2242:skia_private::TArray::Plane\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +2243:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +2244:skia_private::TArray::operator=\28skia_private::TArray&&\29 +2245:skia_private::TArray\2c\20true>::push_back\28SkRGBA4f<\28SkAlphaType\293>&&\29 +2246:skia_png_set_text_2 +2247:skia_png_set_palette_to_rgb +2248:skia_png_handle_IHDR +2249:skia_png_handle_IEND +2250:skia::textlayout::operator==\28skia::textlayout::FontArguments\20const&\2c\20skia::textlayout::FontArguments\20const&\29 +2251:skia::textlayout::TextWrapper::TextStretch::extend\28skia::textlayout::Cluster*\29 +2252:skia::textlayout::FontCollection::getFontManagerOrder\28\29\20const +2253:skia::textlayout::FontArguments::FontArguments\28skia::textlayout::FontArguments\20const&\29 +2254:skia::textlayout::Decorations::calculateGaps\28skia::textlayout::TextLine::ClipContext\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\29 +2255:skia::textlayout::Cluster::isSoftBreak\28\29\20const +2256:skia::textlayout::Cluster::Cluster\28skia::textlayout::ParagraphImpl*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkSpan\2c\20float\2c\20float\29 +2257:skia::textlayout::Block&\20skia_private::TArray::emplace_back\28unsigned\20long&&\2c\20unsigned\20long&&\2c\20skia::textlayout::TextStyle\20const&\29 +2258:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::fixedFunctionFlags\28\29\20const +2259:skgpu::ganesh::SurfaceFillContext::fillRectWithFP\28SkIRect\20const&\2c\20SkMatrix\20const&\2c\20std::__2::unique_ptr>\29 +2260:skgpu::ganesh::SurfaceFillContext::SurfaceFillContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +2261:skgpu::ganesh::SurfaceDrawContext::drawShape\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\29 +2262:skgpu::ganesh::SurfaceDrawContext::drawPaint\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\29 +2263:skgpu::ganesh::SurfaceDrawContext::MakeWithFallback\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2264:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29 +2265:skgpu::ganesh::SurfaceContext::PixelTransferResult::operator=\28skgpu::ganesh::SurfaceContext::PixelTransferResult&&\29 +2266:skgpu::ganesh::SmallPathAtlasMgr::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +2267:skgpu::ganesh::OpsTask::~OpsTask\28\29 +2268:skgpu::ganesh::OpsTask::setColorLoadOp\28GrLoadOp\2c\20std::__2::array\29 +2269:skgpu::ganesh::OpsTask::deleteOps\28\29 +2270:skgpu::ganesh::FillRectOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +2271:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29::$_0::operator\28\29\28int\29\20const +2272:skgpu::ganesh::ClipStack::~ClipStack\28\29 +2273:skgpu::TClientMappedBufferManager::~TClientMappedBufferManager\28\29 +2274:skgpu::TAsyncReadResult::Plane&\20skia_private::TArray::Plane\2c\20false>::emplace_back\2c\20unsigned\20long&>\28sk_sp&&\2c\20unsigned\20long&\29 +2275:skgpu::Plot::addSubImage\28int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +2276:skgpu::GetLCDBlendFormula\28SkBlendMode\29 +2277:skcms_TransferFunction_isHLGish +2278:skcms_Matrix3x3_concat +2279:sk_srgb_linear_singleton\28\29 +2280:sk_sp::reset\28SkPathRef*\29 +2281:sk_sp*\20std::__2::vector\2c\20std::__2::allocator>>::__push_back_slow_path\20const&>\28sk_sp\20const&\29 +2282:shr +2283:shl +2284:setRegionCheck\28SkRegion*\2c\20SkRegion\20const&\29 +2285:res_findResource_74 +2286:read_header\28SkStream*\2c\20SkPngChunkReader*\2c\20SkCodec**\2c\20png_struct_def**\2c\20png_info_def**\29 +2287:read_curves\28unsigned\20char\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skcms_Curve*\29 +2288:qsort +2289:ps_dimension_set_mask_bits +2290:operator==\28SkPath\20const&\2c\20SkPath\20const&\29 +2291:mbrtowc +2292:jround_up +2293:jpeg_make_d_derived_tbl +2294:jpeg_destroy +2295:init\28\29 +2296:ilogbf +2297:icu_74::locale_set_default_internal\28char\20const*\2c\20UErrorCode&\29 +2298:icu_74::compute\28int\2c\20icu_74::ReadArray2D\20const&\2c\20icu_74::ReadArray2D\20const&\2c\20icu_74::ReadArray1D\20const&\2c\20icu_74::ReadArray1D\20const&\2c\20icu_74::Array1D&\2c\20icu_74::Array1D&\2c\20icu_74::Array1D&\29 +2299:icu_74::UnicodeString::getChar32Start\28int\29\20const +2300:icu_74::UnicodeString::fromUTF8\28icu_74::StringPiece\29 +2301:icu_74::UnicodeString::extract\28int\2c\20int\2c\20char*\2c\20int\2c\20icu_74::UnicodeString::EInvariant\29\20const +2302:icu_74::UnicodeString::copyFrom\28icu_74::UnicodeString\20const&\2c\20signed\20char\29 +2303:icu_74::UnicodeSet::freeze\28\29 +2304:icu_74::UnicodeSet::copyFrom\28icu_74::UnicodeSet\20const&\2c\20signed\20char\29 +2305:icu_74::UnicodeSet::add\28int\20const*\2c\20int\2c\20signed\20char\29 +2306:icu_74::UnicodeSet::_toPattern\28icu_74::UnicodeString&\2c\20signed\20char\29\20const +2307:icu_74::UnicodeSet::UnicodeSet\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29 +2308:icu_74::UVector::removeElementAt\28int\29 +2309:icu_74::UDataPathIterator::next\28UErrorCode*\29 +2310:icu_74::StringTrieBuilder::writeNode\28int\2c\20int\2c\20int\29 +2311:icu_74::StringEnumeration::StringEnumeration\28\29 +2312:icu_74::SimpleFilteredSentenceBreakIterator::breakExceptionAt\28int\29 +2313:icu_74::RuleBasedBreakIterator::DictionaryCache::reset\28\29 +2314:icu_74::RuleBasedBreakIterator::BreakCache::reset\28int\2c\20int\29 +2315:icu_74::RuleBasedBreakIterator::BreakCache::populateNear\28int\2c\20UErrorCode&\29 +2316:icu_74::RuleBasedBreakIterator::BreakCache::populateFollowing\28\29 +2317:icu_74::ResourceDataValue::getBinary\28int&\2c\20UErrorCode&\29\20const +2318:icu_74::ResourceDataValue::getArray\28UErrorCode&\29\20const +2319:icu_74::ResourceArray::getValue\28int\2c\20icu_74::ResourceValue&\29\20const +2320:icu_74::ReorderingBuffer::init\28int\2c\20UErrorCode&\29 +2321:icu_74::Normalizer2Impl::makeFCD\28char16_t\20const*\2c\20char16_t\20const*\2c\20icu_74::ReorderingBuffer*\2c\20UErrorCode&\29\20const +2322:icu_74::Normalizer2Impl::hasCompBoundaryBefore\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\29\20const +2323:icu_74::Normalizer2Impl::decomposeShort\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20icu_74::Normalizer2Impl::StopAt\2c\20signed\20char\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +2324:icu_74::Normalizer2Impl::addPropertyStarts\28USetAdder\20const*\2c\20UErrorCode&\29\20const +2325:icu_74::ICU_Utility::skipWhitespace\28icu_74::UnicodeString\20const&\2c\20int&\2c\20signed\20char\29 +2326:icu_74::CheckedArrayByteSink::CheckedArrayByteSink\28char*\2c\20int\29 +2327:hb_ucd_get_unicode_funcs +2328:hb_syllabic_insert_dotted_circles\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +2329:hb_shape_full +2330:hb_serialize_context_t::~hb_serialize_context_t\28\29 +2331:hb_serialize_context_t::resolve_links\28\29 +2332:hb_serialize_context_t::reset\28\29 +2333:hb_lazy_loader_t\2c\20hb_face_t\2c\2016u\2c\20OT::cff1_accelerator_t>::do_destroy\28OT::cff1_accelerator_t*\29 +2334:hb_language_from_string +2335:hb_font_destroy +2336:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2337:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2338:get_sof +2339:ftell +2340:ft_var_readpackedpoints +2341:ft_mem_strdup +2342:ft_glyphslot_done +2343:float\20emscripten::internal::MemberAccess::getWire\28float\20StrokeOpts::*\20const&\2c\20StrokeOpts&\29 +2344:fill_window +2345:exp +2346:encodeImage\28GrDirectContext*\2c\20sk_sp\2c\20SkEncodedImageFormat\2c\20int\29 +2347:emscripten::val\20MakeTypedArray\28int\2c\20float\20const*\29 +2348:emscripten::internal::MethodInvoker::invoke\28float\20\28SkContourMeasure::*\20const&\29\28\29\20const\2c\20SkContourMeasure\20const*\29 +2349:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\29\2c\20unsigned\20long\2c\20unsigned\20long\29 +2350:dquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2351:do_clip_op\28SkReadBuffer*\2c\20SkCanvas*\2c\20SkRegion::Op\2c\20SkClipOp*\29 +2352:do_anti_hairline\28int\2c\20int\2c\20int\2c\20int\2c\20SkIRect\20const*\2c\20SkBlitter*\29 +2353:doWriteReverse\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +2354:doWriteForward\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +2355:dline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2356:dispose_chunk +2357:direct_blur_y\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2358:decltype\28fp\28\28SkRecords::NoOp\29\28\29\29\29\20SkRecord::Record::visit\28SkRecords::Draw&\29\20const +2359:dcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2360:dconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2361:crop_rect_edge\28SkRect\20const&\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float*\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +2362:createPath\28char\20const*\2c\20int\2c\20char\20const*\2c\20int\2c\20char\20const*\2c\20icu_74::CharString&\2c\20UErrorCode*\29 +2363:char\20const*\20std::__2::__rewrap_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +2364:cff_slot_load +2365:cff_parse_real +2366:cff_index_get_sid_string +2367:cff_index_access_element +2368:cf2_doStems +2369:cf2_doFlex +2370:buffer_verify_error\28hb_buffer_t*\2c\20hb_font_t*\2c\20char\20const*\2c\20...\29 +2371:blur_y_rect\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2372:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29::$_0::operator\28\29\28unsigned\20char*\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29\20const +2373:auto\20std::__2::__unwrap_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +2374:af_sort_and_quantize_widths +2375:af_glyph_hints_align_weak_points +2376:af_glyph_hints_align_strong_points +2377:af_face_globals_new +2378:af_cjk_compute_stem_width +2379:add_huff_table +2380:addPoint\28UBiDi*\2c\20int\2c\20int\29 +2381:_addExtensionToList\28ExtensionListEntry**\2c\20ExtensionListEntry*\2c\20signed\20char\29 +2382:__uselocale +2383:__math_xflow +2384:__cxxabiv1::__base_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +2385:\28anonymous\20namespace\29::make_vertices_spec\28bool\2c\20bool\29 +2386:\28anonymous\20namespace\29::gather_lines_and_quads\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\29::$_1::operator\28\29\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20bool\29\20const +2387:\28anonymous\20namespace\29::draw_stencil_rect\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrHardClip\20const&\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +2388:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2389:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2390:\28anonymous\20namespace\29::CacheImpl::removeInternal\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +2391:WriteRingBuffer +2392:WebPRescalerExport +2393:WebPInitAlphaProcessing +2394:WebPFreeDecBuffer +2395:WebPDemuxDelete +2396:VP8SetError +2397:VP8LInverseTransform +2398:VP8LDelete +2399:VP8LColorCacheClear +2400:UDataMemory_init_74 +2401:TT_Load_Context +2402:StringBuffer\20apply_format_string<1024>\28char\20const*\2c\20void*\2c\20char\20\28&\29\20\5b1024\5d\2c\20SkString*\29 +2403:SkYUVAPixmaps::operator=\28SkYUVAPixmaps\20const&\29 +2404:SkYUVAPixmapInfo::SupportedDataTypes::enableDataType\28SkYUVAPixmapInfo::DataType\2c\20int\29 +2405:SkWriter32::writeMatrix\28SkMatrix\20const&\29 +2406:SkWriter32::snapshotAsData\28\29\20const +2407:SkVertices::uniqueID\28\29\20const +2408:SkVertices::approximateSize\28\29\20const +2409:SkUnicode::convertUtf8ToUtf16\28char\20const*\2c\20int\29 +2410:SkUTF::UTF16ToUTF8\28char*\2c\20int\2c\20unsigned\20short\20const*\2c\20unsigned\20long\29 +2411:SkTypefaceCache::NewTypefaceID\28\29 +2412:SkTextBlobRunIterator::next\28\29 +2413:SkTextBlobRunIterator::SkTextBlobRunIterator\28SkTextBlob\20const*\29 +2414:SkTextBlobBuilder::make\28\29 +2415:SkTextBlobBuilder::SkTextBlobBuilder\28\29 +2416:SkTSpan::closestBoundedT\28SkDPoint\20const&\29\20const +2417:SkTSect::updateBounded\28SkTSpan*\2c\20SkTSpan*\2c\20SkTSpan*\29 +2418:SkTSect::trim\28SkTSpan*\2c\20SkTSect*\29 +2419:SkTDStorage::erase\28int\2c\20int\29 +2420:SkTDPQueue::percolateUpIfNecessary\28int\29 +2421:SkSurfaceProps::SkSurfaceProps\28unsigned\20int\2c\20SkPixelGeometry\2c\20float\2c\20float\29 +2422:SkStrokerPriv::JoinFactory\28SkPaint::Join\29 +2423:SkStrokeRec::setStrokeStyle\28float\2c\20bool\29 +2424:SkStrokeRec::setFillStyle\28\29 +2425:SkStrokeRec::applyToPath\28SkPath*\2c\20SkPath\20const&\29\20const +2426:SkString::set\28char\20const*\29 +2427:SkStrikeSpec::findOrCreateStrike\28\29\20const +2428:SkStrikeSpec::MakeWithNoDevice\28SkFont\20const&\2c\20SkPaint\20const*\29 +2429:SkStrike::glyph\28SkGlyphDigest\29 +2430:SkSharedMutex::SkSharedMutex\28\29 +2431:SkShadowTessellator::MakeSpot\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkPoint3\20const&\2c\20float\2c\20bool\2c\20bool\29 +2432:SkShaders::Empty\28\29 +2433:SkShaders::Color\28unsigned\20int\29 +2434:SkShaderBase::appendRootStages\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2435:SkScalerContext::~SkScalerContext\28\29_4001 +2436:SkSL::write_stringstream\28SkSL::StringStream\20const&\2c\20SkSL::OutputStream&\29 +2437:SkSL::evaluate_3_way_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +2438:SkSL::VarDeclaration::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\2c\20std::__2::unique_ptr>\29 +2439:SkSL::Type::priority\28\29\20const +2440:SkSL::Type::checkIfUsableInArray\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +2441:SkSL::SymbolTable::takeOwnershipOfString\28std::__2::basic_string\2c\20std::__2::allocator>\29 +2442:SkSL::SymbolTable::isBuiltinType\28std::__2::basic_string_view>\29\20const +2443:SkSL::SampleUsage::merge\28SkSL::SampleUsage\20const&\29 +2444:SkSL::RP::SlotManager::mapVariableToSlots\28SkSL::Variable\20const&\2c\20SkSL::RP::SlotRange\29 +2445:SkSL::RP::Program::appendStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkSL::RP::Callbacks*\2c\20SkSpan\29\20const +2446:SkSL::RP::Generator::pushVectorizedExpression\28SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +2447:SkSL::RP::DynamicIndexLValue::dynamicSlotRange\28\29 +2448:SkSL::RP::Builder::ternary_op\28SkSL::RP::BuilderOp\2c\20int\29 +2449:SkSL::RP::Builder::simplifyPopSlotsUnmasked\28SkSL::RP::SlotRange*\29 +2450:SkSL::RP::Builder::pop_slots_unmasked\28SkSL::RP::SlotRange\29 +2451:SkSL::RP::Builder::exchange_src\28\29 +2452:SkSL::ProgramUsage::remove\28SkSL::ProgramElement\20const&\29 +2453:SkSL::ProgramUsage::isDead\28SkSL::Variable\20const&\29\20const +2454:SkSL::Pool::~Pool\28\29 +2455:SkSL::PipelineStage::PipelineStageCodeGenerator::typedVariable\28SkSL::Type\20const&\2c\20std::__2::basic_string_view>\29 +2456:SkSL::PipelineStage::PipelineStageCodeGenerator::typeName\28SkSL::Type\20const&\29 +2457:SkSL::MethodReference::~MethodReference\28\29_6850 +2458:SkSL::MethodReference::~MethodReference\28\29 +2459:SkSL::LiteralType::priority\28\29\20const +2460:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sub\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +2461:SkSL::IndexExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +2462:SkSL::GLSLCodeGenerator::writeAnyConstructor\28SkSL::AnyConstructor\20const&\2c\20SkSL::OperatorPrecedence\29 +2463:SkSL::Compiler::errorText\28bool\29 +2464:SkSL::Block::Make\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2465:SkSL::Block::MakeBlock\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2466:SkSL::Analysis::DetectVarDeclarationWithoutScope\28SkSL::Statement\20const&\2c\20SkSL::ErrorReporter*\29 +2467:SkRuntimeEffectPriv::TransformUniforms\28SkSpan\2c\20sk_sp\2c\20SkColorSpace\20const*\29 +2468:SkRuntimeEffect::getRPProgram\28SkSL::DebugTracePriv*\29\20const +2469:SkRegion::getBoundaryPath\28SkPath*\29\20const +2470:SkRegion::Spanerator::next\28int*\2c\20int*\29 +2471:SkRegion::SkRegion\28SkRegion\20const&\29 +2472:SkReduceOrder::Quad\28SkPoint\20const*\2c\20SkPoint*\29 +2473:SkRectPriv::ClosestDisjointEdge\28SkIRect\20const&\2c\20SkIRect\20const&\29 +2474:SkReadBuffer::skipByteArray\28unsigned\20long*\29 +2475:SkReadBuffer::readSampling\28\29 +2476:SkReadBuffer::readRRect\28SkRRect*\29 +2477:SkReadBuffer::checkInt\28int\2c\20int\29 +2478:SkRasterPipeline::appendMatrix\28SkArenaAlloc*\2c\20SkMatrix\20const&\29 +2479:SkQuads::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +2480:SkQuadraticEdge::updateQuadratic\28\29 +2481:SkPngCodecBase::applyXformRow\28void*\2c\20unsigned\20char\20const*\29 +2482:SkPngCodec::processData\28\29 +2483:SkPixmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +2484:SkPictureRecord::~SkPictureRecord\28\29 +2485:SkPicture::~SkPicture\28\29_3429 +2486:SkPathStroker::quadStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2487:SkPathStroker::preJoinTo\28SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\2c\20bool\29 +2488:SkPathStroker::intersectRay\28SkQuadConstruct*\2c\20SkPathStroker::IntersectRayType\29\20const +2489:SkPathStroker::cubicStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2490:SkPathStroker::conicStroke\28SkConic\20const&\2c\20SkQuadConstruct*\29 +2491:SkPathMeasure::isClosed\28\29 +2492:SkPathEffectBase::getFlattenableType\28\29\20const +2493:SkPathBuilder::moveTo\28SkPoint\29 +2494:SkPathBuilder::incReserve\28int\2c\20int\29 +2495:SkPathBuilder::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2496:SkPath::isLastContourClosed\28\29\20const +2497:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2498:SkPaintToGrPaintReplaceShader\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::unique_ptr>\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +2499:SkPaint::setStrokeMiter\28float\29 +2500:SkPaint::setStrokeJoin\28SkPaint::Join\29 +2501:SkOpSpanBase::mergeMatches\28SkOpSpanBase*\29 +2502:SkOpSpanBase::addOpp\28SkOpSpanBase*\29 +2503:SkOpSegment::subDivide\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkDCurve*\29\20const +2504:SkOpSegment::release\28SkOpSpan\20const*\29 +2505:SkOpSegment::operand\28\29\20const +2506:SkOpSegment::moveNearby\28\29 +2507:SkOpSegment::markAndChaseDone\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpSpanBase**\29 +2508:SkOpSegment::isClose\28double\2c\20SkOpSegment\20const*\29\20const +2509:SkOpSegment::init\28SkPoint*\2c\20float\2c\20SkOpContour*\2c\20SkPath::Verb\29 +2510:SkOpSegment::addT\28double\2c\20SkPoint\20const&\29 +2511:SkOpCoincidence::fixUp\28SkOpPtT*\2c\20SkOpPtT\20const*\29 +2512:SkOpCoincidence::add\28SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\29 +2513:SkOpCoincidence::addMissing\28bool*\29 +2514:SkOpCoincidence::addIfMissing\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20double\2c\20double\2c\20SkOpSegment*\2c\20SkOpSegment*\2c\20bool*\29 +2515:SkOpCoincidence::addExpanded\28\29 +2516:SkOpAngle::set\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +2517:SkOpAngle::lineOnOneSide\28SkDPoint\20const&\2c\20SkDVector\20const&\2c\20SkOpAngle\20const*\2c\20bool\29\20const +2518:SkNoPixelsDevice::ClipState::op\28SkClipOp\2c\20SkM44\20const&\2c\20SkRect\20const&\2c\20bool\2c\20bool\29 +2519:SkNoDestructor>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>>::SkNoDestructor\28skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>&&\29 +2520:SkMatrix\20skif::Mapping::map\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +2521:SkMatrixPriv::DifferentialAreaScale\28SkMatrix\20const&\2c\20SkPoint\20const&\29 +2522:SkMatrix::writeToMemory\28void*\29\20const +2523:SkMatrix::preservesRightAngles\28float\29\20const +2524:SkM44::normalizePerspective\28\29 +2525:SkLatticeIter::~SkLatticeIter\28\29 +2526:SkLatticeIter::next\28SkIRect*\2c\20SkRect*\2c\20bool*\2c\20unsigned\20int*\29 +2527:SkJpegCodec::ReadHeader\28SkStream*\2c\20SkCodec**\2c\20JpegDecoderMgr**\2c\20std::__2::unique_ptr>\29 +2528:SkJSONWriter::endObject\28\29 +2529:SkJSONWriter::endArray\28\29 +2530:SkImages::RasterFromBitmap\28SkBitmap\20const&\29 +2531:SkImage_Lazy::Validator::Validator\28sk_sp\2c\20SkColorType\20const*\2c\20sk_sp\29 +2532:SkImageShader::MakeSubset\28sk_sp\2c\20SkRect\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +2533:SkImageFilters::MatrixTransform\28SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20sk_sp\29 +2534:SkImageFilters::Image\28sk_sp\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\29 +2535:SkImageFilters::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +2536:SkImage::readPixels\28GrDirectContext*\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +2537:SkImage::readPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +2538:SkHalfToFloat\28unsigned\20short\29 +2539:SkGradientShader::MakeSweep\28float\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +2540:SkGradientShader::MakeRadial\28SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +2541:SkGradientBaseShader::commonAsAGradient\28SkShaderBase::GradientInfo*\29\20const +2542:SkGradientBaseShader::ValidGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\29 +2543:SkGradientBaseShader::SkGradientBaseShader\28SkGradientBaseShader::Descriptor\20const&\2c\20SkMatrix\20const&\29 +2544:SkGradientBaseShader::MakeDegenerateGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20float\20const*\2c\20int\2c\20sk_sp\2c\20SkTileMode\29 +2545:SkGradientBaseShader::Descriptor::~Descriptor\28\29 +2546:SkGradientBaseShader::Descriptor::Descriptor\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\29 +2547:SkGlyph::setPath\28SkArenaAlloc*\2c\20SkPath\20const*\2c\20bool\2c\20bool\29 +2548:SkFontMgr::matchFamilyStyleCharacter\28char\20const*\2c\20SkFontStyle\20const&\2c\20char\20const**\2c\20int\2c\20int\29\20const +2549:SkFont::setSize\28float\29 +2550:SkEvalQuadAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +2551:SkEncodedInfo::~SkEncodedInfo\28\29 +2552:SkEmptyFontMgr::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +2553:SkDrawableList::~SkDrawableList\28\29 +2554:SkDrawable::draw\28SkCanvas*\2c\20SkMatrix\20const*\29 +2555:SkData::PrivateNewWithCopy\28void\20const*\2c\20unsigned\20long\29::$_0::operator\28\29\28\29\20const +2556:SkDashPathEffect::Make\28float\20const*\2c\20int\2c\20float\29 +2557:SkDQuad::monotonicInX\28\29\20const +2558:SkDCubic::dxdyAtT\28double\29\20const +2559:SkDCubic::RootsValidT\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +2560:SkCubicEdge::updateCubic\28\29 +2561:SkConicalGradient::~SkConicalGradient\28\29 +2562:SkColorSpace::MakeSRGBLinear\28\29 +2563:SkColorFilters::Blend\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\2c\20SkBlendMode\29 +2564:SkColorFilterPriv::MakeGaussian\28\29 +2565:SkColorConverter::SkColorConverter\28unsigned\20int\20const*\2c\20int\29 +2566:SkCodec::startScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const*\29 +2567:SkCodec::handleFrameIndex\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20std::__2::function\29 +2568:SkCodec::getScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +2569:SkChopQuadAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +2570:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\20const*\2c\20int\29 +2571:SkChopCubicAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +2572:SkCharToGlyphCache::SkCharToGlyphCache\28\29 +2573:SkCanvas::getTotalMatrix\28\29\20const +2574:SkCanvas::getLocalToDevice\28\29\20const +2575:SkCanvas::getLocalClipBounds\28\29\20const +2576:SkCanvas::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +2577:SkCanvas::drawAtlas\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +2578:SkCanvas::concat\28SkM44\20const&\29 +2579:SkCanvas::SkCanvas\28SkBitmap\20const&\29 +2580:SkCanvas::ImageSetEntry::ImageSetEntry\28SkCanvas::ImageSetEntry\20const&\29 +2581:SkBmpCodec::ReadHeader\28SkStream*\2c\20bool\2c\20std::__2::unique_ptr>*\29 +2582:SkBlurMaskFilterImpl::computeXformedSigma\28SkMatrix\20const&\29\20const +2583:SkBlitter::blitRectRegion\28SkIRect\20const&\2c\20SkRegion\20const&\29 +2584:SkBlendMode_ShouldPreScaleCoverage\28SkBlendMode\2c\20bool\29 +2585:SkBlendMode_AppendStages\28SkBlendMode\2c\20SkRasterPipeline*\29 +2586:SkBitmap::tryAllocPixels\28SkBitmap::Allocator*\29 +2587:SkBitmap::readPixels\28SkPixmap\20const&\2c\20int\2c\20int\29\20const +2588:SkBitmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +2589:SkBitmap::installPixels\28SkPixmap\20const&\29 +2590:SkBitmap::allocPixels\28SkImageInfo\20const&\29 +2591:SkBaseShadowTessellator::handleQuad\28SkPoint\20const*\29 +2592:SkAutoDescriptor::~SkAutoDescriptor\28\29 +2593:SkAnimatedImage::getFrameCount\28\29\20const +2594:SkAAClip::~SkAAClip\28\29 +2595:SkAAClip::setPath\28SkPath\20const&\2c\20SkIRect\20const&\2c\20bool\29 +2596:SkAAClip::op\28SkAAClip\20const&\2c\20SkClipOp\29 +2597:ReadHuffmanCode_16831 +2598:OT::vmtx_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2599:OT::hb_ot_layout_lookup_accelerator_t*\20OT::hb_ot_layout_lookup_accelerator_t::create\28OT::Layout::GSUB_impl::SubstLookup\20const&\29 +2600:OT::hb_ot_apply_context_t::replace_glyph\28unsigned\20int\29 +2601:OT::cff1_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2602:OT::apply_lookup\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20OT::LookupRecord\20const*\2c\20unsigned\20int\29 +2603:OT::Layout::GPOS_impl::ValueFormat::get_device\28OT::IntType\20const*\2c\20bool*\2c\20void\20const*\2c\20hb_sanitize_context_t&\29 +2604:OT::Layout::GPOS_impl::AnchorFormat3::get_anchor\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20float*\2c\20float*\29\20const +2605:OT::Layout::GPOS_impl::AnchorFormat2::get_anchor\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20float*\2c\20float*\29\20const +2606:OT::HVARVVAR::sanitize\28hb_sanitize_context_t*\29\20const +2607:OT::GPOS_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2608:OT::ClassDef::get_class\28unsigned\20int\29\20const +2609:JpegDecoderMgr::~JpegDecoderMgr\28\29 +2610:GrTriangulator::simplify\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +2611:GrTriangulator::setTop\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2612:GrTriangulator::mergeCoincidentVertices\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29\20const +2613:GrTriangulator::Vertex*\20SkArenaAlloc::make\28SkPoint&\2c\20int&&\29 +2614:GrThreadSafeCache::remove\28skgpu::UniqueKey\20const&\29 +2615:GrThreadSafeCache::internalFind\28skgpu::UniqueKey\20const&\29 +2616:GrThreadSafeCache::internalAdd\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2617:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29 +2618:GrTexture::markMipmapsClean\28\29 +2619:GrTessellationShader::MakePipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedClip&&\2c\20GrProcessorSet&&\29 +2620:GrSurfaceProxyView::concatSwizzle\28skgpu::Swizzle\29 +2621:GrSurfaceProxy::LazyCallbackResult::LazyCallbackResult\28sk_sp\29 +2622:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20GrSurfaceProxy::RectsMustMatch\2c\20sk_sp*\29 +2623:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +2624:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +2625:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrPipeline\20const*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrUserStencilSettings\20const*\29 +2626:GrShape::simplifyLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\29 +2627:GrShape::reset\28\29 +2628:GrShape::conservativeContains\28SkPoint\20const&\29\20const +2629:GrSWMaskHelper::init\28SkIRect\20const&\29 +2630:GrResourceProvider::createNonAAQuadIndexBuffer\28\29 +2631:GrResourceProvider::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\2c\20GrResourceProvider::ZeroInit\29 +2632:GrRenderTask::addTarget\28GrDrawingManager*\2c\20sk_sp\29 +2633:GrRenderTarget::~GrRenderTarget\28\29_9551 +2634:GrRecordingContextPriv::createDevice\28skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\2c\20skgpu::ganesh::Device::InitContents\29 +2635:GrQuadUtils::WillUseHairline\28GrQuad\20const&\2c\20GrAAType\2c\20GrQuadAAFlags\29 +2636:GrQuadUtils::CropToRect\28SkRect\20const&\2c\20GrAA\2c\20DrawQuad*\2c\20bool\29 +2637:GrProxyProvider::processInvalidUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\2c\20GrProxyProvider::InvalidateGPUResource\29 +2638:GrPorterDuffXPFactory::Get\28SkBlendMode\29 +2639:GrPixmap::operator=\28GrPixmap&&\29 +2640:GrPathUtils::scaleToleranceToSrc\28float\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +2641:GrPathUtils::quadraticPointCount\28SkPoint\20const*\2c\20float\29 +2642:GrPathUtils::cubicPointCount\28SkPoint\20const*\2c\20float\29 +2643:GrPaint::setPorterDuffXPFactory\28SkBlendMode\29 +2644:GrPaint::GrPaint\28GrPaint\20const&\29 +2645:GrOpsRenderPass::draw\28int\2c\20int\29 +2646:GrOpsRenderPass::drawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +2647:GrMeshDrawOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +2648:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29 +2649:GrGradientShader::MakeGradientFP\28SkGradientBaseShader\20const&\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\2c\20std::__2::unique_ptr>\2c\20SkMatrix\20const*\29 +2650:GrGpuResource::getContext\28\29 +2651:GrGpu::writePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +2652:GrGLTexture::onSetLabel\28\29 +2653:GrGLTexture::onRelease\28\29 +2654:GrGLTexture::onAbandon\28\29 +2655:GrGLTexture::backendFormat\28\29\20const +2656:GrGLSLUniformHandler::addInputSampler\28skgpu::Swizzle\20const&\2c\20char\20const*\29 +2657:GrGLSLShaderBuilder::appendFunctionDecl\28SkSLType\2c\20char\20const*\2c\20SkSpan\29 +2658:GrGLSLProgramBuilder::fragmentProcessorHasCoordsParam\28GrFragmentProcessor\20const*\29\20const +2659:GrGLRenderTarget::onRelease\28\29 +2660:GrGLRenderTarget::onAbandon\28\29 +2661:GrGLGpu::resolveRenderFBOs\28GrGLRenderTarget*\2c\20SkIRect\20const&\2c\20GrGLRenderTarget::ResolveDirection\2c\20bool\29 +2662:GrGLGpu::flushBlendAndColorWrite\28skgpu::BlendInfo\20const&\2c\20skgpu::Swizzle\20const&\29 +2663:GrGLGpu::deleteSync\28__GLsync*\29 +2664:GrGLGetVersionFromString\28char\20const*\29 +2665:GrGLFinishCallbacks::callAll\28bool\29 +2666:GrGLCheckLinkStatus\28GrGLGpu\20const*\2c\20unsigned\20int\2c\20bool\2c\20skgpu::ShaderErrorHandler*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const**\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +2667:GrGLCaps::maxRenderTargetSampleCount\28GrGLFormat\29\20const +2668:GrFragmentProcessors::Make\28SkBlenderBase\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20GrFPArgs\20const&\29 +2669:GrFragmentProcessor::isEqual\28GrFragmentProcessor\20const&\29\20const +2670:GrFragmentProcessor::asTextureEffect\28\29\20const +2671:GrFragmentProcessor::Rect\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRect\29 +2672:GrFragmentProcessor::ModulateRGBA\28std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +2673:GrDrawingManager::~GrDrawingManager\28\29 +2674:GrDrawingManager::removeRenderTasks\28\29 +2675:GrDrawingManager::getPathRenderer\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\2c\20bool\2c\20skgpu::ganesh::PathRendererChain::DrawType\2c\20skgpu::ganesh::PathRenderer::StencilSupport*\29 +2676:GrDrawOpAtlas::compact\28skgpu::AtlasToken\29 +2677:GrCpuBuffer::ref\28\29\20const +2678:GrContext_Base::~GrContext_Base\28\29 +2679:GrContext_Base::defaultBackendFormat\28SkColorType\2c\20skgpu::Renderable\29\20const +2680:GrColorSpaceXform::XformKey\28GrColorSpaceXform\20const*\29 +2681:GrColorSpaceXform::Make\28SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +2682:GrColorSpaceXform::Make\28GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +2683:GrColorInfo::operator=\28GrColorInfo\20const&\29 +2684:GrCaps::supportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +2685:GrCaps::getFallbackColorTypeAndFormat\28GrColorType\2c\20int\29\20const +2686:GrCaps::areColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +2687:GrBufferAllocPool::~GrBufferAllocPool\28\29 +2688:GrBlurUtils::DrawShapeWithMaskFilter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\29 +2689:GrBaseContextPriv::getShaderErrorHandler\28\29\20const +2690:GrBackendTexture::GrBackendTexture\28GrBackendTexture\20const&\29 +2691:GrBackendRenderTarget::getBackendFormat\28\29\20const +2692:GrBackendFormat::operator==\28GrBackendFormat\20const&\29\20const +2693:GrAAConvexTessellator::createOuterRing\28GrAAConvexTessellator::Ring\20const&\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring*\29 +2694:GrAAConvexTessellator::createInsetRings\28GrAAConvexTessellator::Ring&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring**\29 +2695:FindSortableTop\28SkOpContourHead*\29 +2696:FT_Stream_Close +2697:FT_Set_Charmap +2698:FT_Select_Metrics +2699:FT_Outline_Decompose +2700:FT_Open_Face +2701:FT_New_Size +2702:FT_Load_Sfnt_Table +2703:FT_GlyphLoader_Add +2704:FT_Get_Color_Glyph_Paint +2705:FT_Get_Color_Glyph_Layer +2706:FT_Done_Library +2707:FT_CMap_New +2708:End +2709:DecodeImageData\28sk_sp\29 +2710:Current_Ratio +2711:Cr_z__tr_stored_block +2712:ClipParams_unpackRegionOp\28SkReadBuffer*\2c\20unsigned\20int\29 +2713:CircleOp::Circle&\20skia_private::TArray::emplace_back\28CircleOp::Circle&&\29 +2714:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +2715:AlmostEqualUlps_Pin\28float\2c\20float\29 +2716:2478 +2717:2479 +2718:2480 +2719:2481 +2720:2482 +2721:2483 +2722:wuffs_lzw__decoder__workbuf_len +2723:wuffs_gif__decoder__decode_image_config +2724:wuffs_gif__decoder__decode_frame_config +2725:winding_mono_quad\28SkPoint\20const*\2c\20float\2c\20float\2c\20int*\29 +2726:winding_mono_conic\28SkConic\20const&\2c\20float\2c\20float\2c\20int*\29 +2727:week_num +2728:wcrtomb +2729:wchar_t\20const*\20std::__2::find\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const&\29 +2730:void\20std::__2::__sort4\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +2731:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +2732:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +2733:void\20std::__2::__inplace_merge\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +2734:void\20sort_r_simple\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\2c\20void*\29\2c\20void*\29 +2735:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29_15931 +2736:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29 +2737:void\20SkTIntroSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29>\28int\2c\20double*\2c\20int\2c\20void\20SkTQSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29\20const&\29 +2738:void\20SkTIntroSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29>\28int\2c\20SkEdge*\2c\20int\2c\20void\20SkTQSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29\20const&\29 +2739:vfprintf +2740:valid_args\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20unsigned\20long*\29 +2741:utf8_back1SafeBody_74 +2742:uscript_getShortName_74 +2743:uscript_getScript_74 +2744:ures_appendResPath\28UResourceBundle*\2c\20char\20const*\2c\20int\2c\20UErrorCode*\29 +2745:uprv_strnicmp_74 +2746:uprv_strdup_74 +2747:uprv_sortArray_74 +2748:uprv_min_74 +2749:uprv_mapFile_74 +2750:uprv_compareASCIIPropertyNames_74 +2751:update_offset_to_base\28char\20const*\2c\20long\29 +2752:update_box +2753:umutablecptrie_get_74 +2754:ultag_isUnicodeLocaleAttributes_74 +2755:ultag_isPrivateuseValueSubtags_74 +2756:ulocimp_getKeywords_74 +2757:ulocimp_canonicalize_74 +2758:uloc_openKeywords_74 +2759:uhash_remove_74 +2760:uhash_hashChars_74 +2761:uhash_getiAndFound_74 +2762:uhash_compareChars_74 +2763:udata_getHashTable\28UErrorCode&\29 +2764:ucstrTextAccess\28UText*\2c\20long\20long\2c\20signed\20char\29 +2765:u_strToUTF8_74 +2766:u_strToUTF8WithSub_74 +2767:u_strCompare_74 +2768:u_getUnicodeProperties_74 +2769:u_getDataDirectory_74 +2770:u_charMirror_74 +2771:tt_size_reset +2772:tt_sbit_decoder_load_metrics +2773:tt_face_find_bdf_prop +2774:tolower +2775:toTextStyle\28SimpleTextStyle\20const&\29 +2776:t1_cmap_unicode_done +2777:subdivide_cubic_to\28SkPath*\2c\20SkPoint\20const*\2c\20int\29 +2778:subdivide\28SkConic\20const&\2c\20SkPoint*\2c\20int\29 +2779:subQuickSort\28char*\2c\20int\2c\20int\2c\20int\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\2c\20void\20const*\29\2c\20void\20const*\2c\20void*\2c\20void*\29 +2780:strtox +2781:strtoull_l +2782:strcat +2783:std::logic_error::~logic_error\28\29_19048 +2784:std::__2::vector>::__append\28unsigned\20long\29 +2785:std::__2::vector>::push_back\5babi:ne180100\5d\28float&&\29 +2786:std::__2::vector>::__append\28unsigned\20long\29 +2787:std::__2::vector<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20std::__2::allocator<\28anonymous\20namespace\29::CacheImpl::Value*>>::__throw_length_error\5babi:ne180100\5d\28\29\20const +2788:std::__2::vector>::reserve\28unsigned\20long\29 +2789:std::__2::vector\2c\20std::__2::allocator>>::push_back\5babi:ne180100\5d\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +2790:std::__2::unique_ptr<\28anonymous\20namespace\29::SoftwarePathData\2c\20std::__2::default_delete<\28anonymous\20namespace\29::SoftwarePathData>>::reset\5babi:ne180100\5d\28\28anonymous\20namespace\29::SoftwarePathData*\29 +2791:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2792:std::__2::time_put>>::~time_put\28\29_18584 +2793:std::__2::priority_queue>\2c\20GrAATriangulator::EventComparator>::push\28GrAATriangulator::Event*\20const&\29 +2794:std::__2::pair\2c\20std::__2::allocator>>>::~pair\28\29 +2795:std::__2::locale::operator=\28std::__2::locale\20const&\29 +2796:std::__2::locale::locale\28\29 +2797:std::__2::locale::__imp::acquire\28\29 +2798:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\29 +2799:std::__2::ios_base::~ios_base\28\29 +2800:std::__2::ios_base::init\28void*\29 +2801:std::__2::ios_base::clear\28unsigned\20int\29 +2802:std::__2::fpos<__mbstate_t>::fpos\5babi:nn180100\5d\28long\20long\29 +2803:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:ne180100\5d\28SkAnimatedImage::Frame&\2c\20SkAnimatedImage::Frame&\29 +2804:std::__2::default_delete::operator\28\29\5babi:ne180100\5d\28sktext::gpu::TextBlobRedrawCoordinator*\29\20const +2805:std::__2::char_traits::move\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +2806:std::__2::char_traits::assign\5babi:nn180100\5d\28char*\2c\20unsigned\20long\2c\20char\29 +2807:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_17635 +2808:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29 +2809:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +2810:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28wchar_t\29 +2811:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +2812:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::allocator\20const&\29 +2813:std::__2::basic_string\2c\20std::__2::allocator>::__make_iterator\5babi:nn180100\5d\28char*\29 +2814:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +2815:std::__2::basic_string\2c\20std::__2::allocator>::__init_copy_ctor_external\28char16_t\20const*\2c\20unsigned\20long\29 +2816:std::__2::basic_streambuf>::step\5babi:nn180100\5d\28char*\2c\20char*\29 +2817:std::__2::basic_streambuf>::basic_streambuf\28\29 +2818:std::__2::basic_ostream>::~basic_ostream\28\29_17534 +2819:std::__2::basic_istream>::~basic_istream\28\29_17493 +2820:std::__2::basic_istream>::sentry::sentry\28std::__2::basic_istream>&\2c\20bool\29 +2821:std::__2::basic_iostream>::~basic_iostream\28\29_17555 +2822:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +2823:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +2824:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +2825:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +2826:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +2827:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +2828:std::__2::__to_address_helper\2c\20void>::__call\5babi:nn180100\5d\28std::__2::__wrap_iter\20const&\29 +2829:std::__2::__throw_length_error\5babi:ne180100\5d\28char\20const*\29 +2830:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +2831:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20wchar_t*\2c\20wchar_t&\2c\20wchar_t&\29 +2832:std::__2::__num_get::__stage2_float_loop\28wchar_t\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20wchar_t*\29 +2833:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20char*\2c\20char&\2c\20char&\29 +2834:std::__2::__num_get::__stage2_float_loop\28char\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20char*\29 +2835:std::__2::__libcpp_wcrtomb_l\5babi:nn180100\5d\28char*\2c\20wchar_t\2c\20__mbstate_t*\2c\20__locale_struct*\29 +2836:std::__2::__itoa::__base_10_u32\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2837:std::__2::__itoa::__append6\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2838:std::__2::__itoa::__append4\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2839:std::__2::__call_once\28unsigned\20long\20volatile&\2c\20void*\2c\20void\20\28*\29\28void*\29\29 +2840:sktext::gpu::VertexFiller::flatten\28SkWriteBuffer&\29\20const +2841:sktext::gpu::VertexFiller::Make\28skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20SkRect\2c\20SkSpan\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::FillerType\29 +2842:sktext::gpu::SubRunContainer::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20SkRefCnt\20const*\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +2843:sktext::gpu::SubRunAllocator::SubRunAllocator\28int\29 +2844:sktext::gpu::StrikeCache::internalPurge\28unsigned\20long\29 +2845:sktext::gpu::GlyphVector::flatten\28SkWriteBuffer&\29\20const +2846:sktext::gpu::GlyphVector::Make\28sktext::SkStrikePromise&&\2c\20SkSpan\2c\20sktext::gpu::SubRunAllocator*\29 +2847:sktext::gpu::BagOfBytes::MinimumSizeWithOverhead\28int\2c\20int\2c\20int\2c\20int\29::'lambda'\28\29::operator\28\29\28\29\20const +2848:sktext::SkStrikePromise::flatten\28SkWriteBuffer&\29\20const +2849:sktext::GlyphRunBuilder::makeGlyphRunList\28sktext::GlyphRun\20const&\2c\20SkPaint\20const&\2c\20SkPoint\29 +2850:sktext::GlyphRun::GlyphRun\28SkFont\20const&\2c\20SkSpan\2c\20SkSpan\2c\20SkSpan\2c\20SkSpan\2c\20SkSpan\29 +2851:skpaint_to_grpaint_impl\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::optional>>\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +2852:skip_literal_string +2853:skif::\28anonymous\20namespace\29::are_axes_nearly_integer_aligned\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29 +2854:skif::FilterResult::applyColorFilter\28skif::Context\20const&\2c\20sk_sp\29\20const +2855:skif::FilterResult::FilterResult\28\29 +2856:skif::FilterResult::Builder::outputBounds\28std::__2::optional>\29\20const +2857:skif::FilterResult::Builder::drawShader\28sk_sp\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +2858:skif::FilterResult::Builder::createInputShaders\28skif::LayerSpace\20const&\2c\20bool\29 +2859:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +2860:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +2861:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::set\28skia_private::THashMap>\2c\20SkGoodHash>::Pair\29 +2862:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +2863:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +2864:skia_private::THashTable::Traits>::resize\28int\29 +2865:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::resize\28int\29 +2866:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::find\28GrProgramDesc\20const&\29\20const +2867:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +2868:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrTextureProxy*&&\29 +2869:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +2870:skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::set\28SkSL::Variable\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +2871:skia_private::THashMap::set\28SkSL::SymbolTable::SymbolKey\2c\20SkSL::Symbol*\29 +2872:skia_private::THashMap::set\28SkSL::FunctionDeclaration\20const*\2c\20SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::FunctionState\29 +2873:skia_private::THashMap\2c\20SkIcuBreakIteratorCache::Request::Hash>::set\28SkIcuBreakIteratorCache::Request\2c\20sk_sp\29 +2874:skia_private::TArray::resize_back\28int\29 +2875:skia_private::TArray\2c\20false>::move\28void*\29 +2876:skia_private::TArray::operator=\28skia_private::TArray&&\29 +2877:skia_private::TArray::push_back\28SkRasterPipeline_MemoryCtxInfo&&\29 +2878:skia_private::TArray::push_back_raw\28int\29 +2879:skia_private::TArray::resize_back\28int\29 +2880:skia_png_write_chunk +2881:skia_png_set_sBIT +2882:skia_png_set_read_fn +2883:skia_png_set_packing +2884:skia_png_save_uint_32 +2885:skia_png_reciprocal2 +2886:skia_png_realloc_array +2887:skia_png_read_start_row +2888:skia_png_read_IDAT_data +2889:skia_png_handle_zTXt +2890:skia_png_handle_tRNS +2891:skia_png_handle_tIME +2892:skia_png_handle_tEXt +2893:skia_png_handle_sRGB +2894:skia_png_handle_sPLT +2895:skia_png_handle_sCAL +2896:skia_png_handle_sBIT +2897:skia_png_handle_pHYs +2898:skia_png_handle_pCAL +2899:skia_png_handle_oFFs +2900:skia_png_handle_iTXt +2901:skia_png_handle_iCCP +2902:skia_png_handle_hIST +2903:skia_png_handle_gAMA +2904:skia_png_handle_cHRM +2905:skia_png_handle_bKGD +2906:skia_png_handle_as_unknown +2907:skia_png_handle_PLTE +2908:skia_png_do_strip_channel +2909:skia_png_destroy_write_struct +2910:skia_png_destroy_info_struct +2911:skia_png_compress_IDAT +2912:skia_png_combine_row +2913:skia_png_colorspace_set_sRGB +2914:skia_png_check_fp_string +2915:skia_png_check_fp_number +2916:skia::textlayout::TypefaceFontStyleSet::createTypeface\28int\29 +2917:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::$_0::operator\28\29\28sk_sp\2c\20sk_sp\29\20const +2918:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const +2919:skia::textlayout::TextLine::getGlyphPositionAtCoordinate\28float\29 +2920:skia::textlayout::Run::isResolved\28\29\20const +2921:skia::textlayout::Run::copyTo\28SkTextBlobBuilder&\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +2922:skia::textlayout::ParagraphImpl::buildClusterTable\28\29 +2923:skia::textlayout::OneLineShaper::~OneLineShaper\28\29 +2924:skia::textlayout::FontCollection::setDefaultFontManager\28sk_sp\29 +2925:skia::textlayout::FontCollection::FontCollection\28\29 +2926:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::flush\28GrMeshDrawTarget*\2c\20skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::FlushInfo*\29\20const +2927:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::~Impl\28\29 +2928:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::programInfo\28\29 +2929:skgpu::ganesh::SurfaceFillContext::discard\28\29 +2930:skgpu::ganesh::SurfaceDrawContext::internalStencilClear\28SkIRect\20const*\2c\20bool\29 +2931:skgpu::ganesh::SurfaceDrawContext::drawPath\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrStyle\20const&\29 +2932:skgpu::ganesh::SurfaceDrawContext::attemptQuadOptimization\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20DrawQuad*\2c\20GrPaint*\29 +2933:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +2934:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29::$_0::operator\28\29\28GrSurfaceProxyView\2c\20SkIRect\29\20const +2935:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +2936:skgpu::ganesh::QuadPerEdgeAA::MinColorType\28SkRGBA4f<\28SkAlphaType\292>\29 +2937:skgpu::ganesh::PathRendererChain::PathRendererChain\28GrRecordingContext*\2c\20skgpu::ganesh::PathRendererChain::Options\20const&\29 +2938:skgpu::ganesh::PathRenderer::getStencilSupport\28GrStyledShape\20const&\29\20const +2939:skgpu::ganesh::PathCurveTessellator::draw\28GrOpFlushState*\29\20const +2940:skgpu::ganesh::OpsTask::recordOp\28std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const*\2c\20GrCaps\20const&\29 +2941:skgpu::ganesh::FilterAndMipmapHaveNoEffect\28GrQuad\20const&\2c\20GrQuad\20const&\29 +2942:skgpu::ganesh::FillRectOp::MakeNonAARect\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +2943:skgpu::ganesh::FillRRectOp::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +2944:skgpu::ganesh::Device::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +2945:skgpu::ganesh::Device::drawImageQuadDirect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +2946:skgpu::ganesh::Device::Make\28std::__2::unique_ptr>\2c\20SkAlphaType\2c\20skgpu::ganesh::Device::InitContents\29 +2947:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::setup_dashed_rect\28SkRect\20const&\2c\20skgpu::VertexWriter&\2c\20SkMatrix\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashCap\29 +2948:skgpu::ganesh::ClipStack::SaveRecord::invalidateMasks\28GrProxyProvider*\2c\20SkTBlockList*\29 +2949:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::SaveRecord\20const&\29\20const +2950:skgpu::ganesh::AtlasTextOp::operator\20new\28unsigned\20long\29 +2951:skgpu::ganesh::AtlasTextOp::Geometry::Make\28sktext::gpu::AtlasSubRun\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\2c\20sk_sp&&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkArenaAlloc*\29 +2952:skgpu::ganesh::AtlasRenderTask::addAtlasDrawOp\28std::__2::unique_ptr>\2c\20GrCaps\20const&\29 +2953:skcms_TransferFunction_isPQish +2954:skcms_MaxRoundtripError +2955:sk_sp::~sk_sp\28\29 +2956:sk_free_releaseproc\28void\20const*\2c\20void*\29 +2957:siprintf +2958:sift +2959:shallowTextClone\28UText*\2c\20UText\20const*\2c\20UErrorCode*\29 +2960:select_curve_ops\28skcms_Curve\20const*\2c\20int\2c\20OpAndArg*\29 +2961:rotate\28SkDCubic\20const&\2c\20int\2c\20int\2c\20SkDCubic&\29 +2962:res_getResource_74 +2963:read_metadata\28std::__2::vector>\20const&\2c\20unsigned\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +2964:read_header\28SkStream*\2c\20SkISize*\29 +2965:quad_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +2966:psh_globals_set_scale +2967:ps_parser_skip_PS_token +2968:ps_builder_done +2969:png_text_compress +2970:png_inflate_read +2971:png_inflate_claim +2972:png_image_size +2973:png_default_warning +2974:png_colorspace_endpoints_match +2975:png_build_16bit_table +2976:normalize +2977:next_marker +2978:morphpoints\28SkPoint*\2c\20SkPoint\20const*\2c\20int\2c\20SkPathMeasure&\2c\20float\29 +2979:make_unpremul_effect\28std::__2::unique_ptr>\29 +2980:long\20std::__2::__libcpp_atomic_refcount_decrement\5babi:nn180100\5d\28long&\29 +2981:long\20const&\20std::__2::min\5babi:nn180100\5d\28long\20const&\2c\20long\20const&\29 +2982:log1p +2983:locale_getKeywordsStart_74 +2984:load_truetype_glyph +2985:loadParentsExceptRoot\28UResourceDataEntry*&\2c\20char*\2c\20int\2c\20signed\20char\2c\20char*\2c\20UErrorCode*\29 +2986:line_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +2987:lang_find_or_insert\28char\20const*\29 +2988:jpeg_calc_output_dimensions +2989:jpeg_CreateDecompress +2990:inner_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +2991:inflate_table +2992:increment_simple_rowgroup_ctr +2993:icu_74::spanOneUTF8\28icu_74::UnicodeSet\20const&\2c\20unsigned\20char\20const*\2c\20int\29 +2994:icu_74::enumGroupNames\28icu_74::UCharNames*\2c\20unsigned\20short\20const*\2c\20int\2c\20int\2c\20signed\20char\20\28*\29\28void*\2c\20int\2c\20UCharNameChoice\2c\20char\20const*\2c\20int\29\2c\20void*\2c\20UCharNameChoice\29 +2995:icu_74::\28anonymous\20namespace\29::appendResult\28char16_t*\2c\20int\2c\20int\2c\20int\2c\20char16_t\20const*\2c\20int\2c\20unsigned\20int\2c\20icu_74::Edits*\29 +2996:icu_74::\28anonymous\20namespace\29::AliasReplacer::replace\28icu_74::Locale\20const&\2c\20icu_74::CharString&\2c\20UErrorCode&\29::$_0::__invoke\28UElement\2c\20UElement\29 +2997:icu_74::XLikelySubtagsData::readStrings\28icu_74::ResourceTable\20const&\2c\20char\20const*\2c\20icu_74::ResourceValue&\2c\20icu_74::LocalMemory&\2c\20int&\2c\20UErrorCode&\29 +2998:icu_74::UniqueCharStrings::addByValue\28icu_74::UnicodeString\2c\20UErrorCode&\29 +2999:icu_74::UnicodeString::getTerminatedBuffer\28\29 +3000:icu_74::UnicodeString::doCompare\28int\2c\20int\2c\20char16_t\20const*\2c\20int\2c\20int\29\20const +3001:icu_74::UnicodeString::UnicodeString\28char16_t\20const*\2c\20int\29 +3002:icu_74::UnicodeSet::retainAll\28icu_74::UnicodeSet\20const&\29 +3003:icu_74::UnicodeSet::remove\28int\2c\20int\29 +3004:icu_74::UnicodeSet::exclusiveOr\28int\20const*\2c\20int\2c\20signed\20char\29 +3005:icu_74::UnicodeSet::ensureBufferCapacity\28int\29 +3006:icu_74::UnicodeSet::applyIntPropertyValue\28UProperty\2c\20int\2c\20UErrorCode&\29 +3007:icu_74::UnicodeSet::applyFilter\28signed\20char\20\28*\29\28int\2c\20void*\29\2c\20void*\2c\20icu_74::UnicodeSet\20const*\2c\20UErrorCode&\29 +3008:icu_74::UnicodeSet::UnicodeSet\28icu_74::UnicodeSet\20const&\29 +3009:icu_74::UVector::sort\28int\20\28*\29\28UElement\2c\20UElement\29\2c\20UErrorCode&\29 +3010:icu_74::UVector::removeElement\28void*\29 +3011:icu_74::UVector::insertElementAt\28void*\2c\20int\2c\20UErrorCode&\29 +3012:icu_74::UStack::UStack\28void\20\28*\29\28void*\29\2c\20signed\20char\20\28*\29\28UElement\2c\20UElement\29\2c\20UErrorCode&\29 +3013:icu_74::UCharsTrieBuilder::add\28icu_74::UnicodeString\20const&\2c\20int\2c\20UErrorCode&\29 +3014:icu_74::StringTrieBuilder::~StringTrieBuilder\28\29 +3015:icu_74::StringPiece::compare\28icu_74::StringPiece\29 +3016:icu_74::SimpleFilteredSentenceBreakIterator::internalNext\28int\29 +3017:icu_74::RuleCharacterIterator::atEnd\28\29\20const +3018:icu_74::ResourceDataValue::getTable\28UErrorCode&\29\20const +3019:icu_74::ResourceDataValue::getString\28int&\2c\20UErrorCode&\29\20const +3020:icu_74::ReorderingBuffer::append\28char16_t\20const*\2c\20int\2c\20signed\20char\2c\20unsigned\20char\2c\20unsigned\20char\2c\20UErrorCode&\29 +3021:icu_74::PatternProps::isWhiteSpace\28int\29 +3022:icu_74::Normalizer2Impl::~Normalizer2Impl\28\29 +3023:icu_74::Normalizer2Impl::decompose\28int\2c\20unsigned\20short\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +3024:icu_74::Normalizer2Impl::decompose\28char16_t\20const*\2c\20char16_t\20const*\2c\20icu_74::ReorderingBuffer*\2c\20UErrorCode&\29\20const +3025:icu_74::Normalizer2Impl::decomposeShort\28char16_t\20const*\2c\20char16_t\20const*\2c\20signed\20char\2c\20signed\20char\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +3026:icu_74::Norm2AllModes::~Norm2AllModes\28\29 +3027:icu_74::Norm2AllModes::createInstance\28icu_74::Normalizer2Impl*\2c\20UErrorCode&\29 +3028:icu_74::LocaleUtility::initNameFromLocale\28icu_74::Locale\20const&\2c\20icu_74::UnicodeString&\29 +3029:icu_74::LocaleBuilder::~LocaleBuilder\28\29 +3030:icu_74::Locale::getKeywordValue\28icu_74::StringPiece\2c\20icu_74::ByteSink&\2c\20UErrorCode&\29\20const +3031:icu_74::Locale::getDefault\28\29 +3032:icu_74::LoadedNormalizer2Impl::load\28char\20const*\2c\20char\20const*\2c\20UErrorCode&\29 +3033:icu_74::ICUServiceKey::~ICUServiceKey\28\29 +3034:icu_74::ICUResourceBundleFactory::~ICUResourceBundleFactory\28\29 +3035:icu_74::ICULocaleService::~ICULocaleService\28\29 +3036:icu_74::EmojiProps::getSingleton\28UErrorCode&\29 +3037:icu_74::Edits::reset\28\29 +3038:icu_74::DictionaryBreakEngine::~DictionaryBreakEngine\28\29 +3039:icu_74::ByteSinkUtil::appendChange\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20char16_t\20const*\2c\20int\2c\20icu_74::ByteSink&\2c\20icu_74::Edits*\2c\20UErrorCode&\29 +3040:icu_74::BreakIterator::makeInstance\28icu_74::Locale\20const&\2c\20int\2c\20UErrorCode&\29 +3041:hb_vector_t::push\28\29 +3042:hb_tag_from_string +3043:hb_shape_plan_destroy +3044:hb_script_get_horizontal_direction +3045:hb_paint_extents_context_t::push_clip\28hb_extents_t\29 +3046:hb_ot_color_palette_get_colors +3047:hb_lazy_loader_t\2c\20hb_face_t\2c\203u\2c\20OT::cmap_accelerator_t>::do_destroy\28OT::cmap_accelerator_t*\29 +3048:hb_lazy_loader_t\2c\20hb_face_t\2c\2039u\2c\20OT::SVG_accelerator_t>::do_destroy\28OT::SVG_accelerator_t*\29 +3049:hb_hashmap_t::alloc\28unsigned\20int\29 +3050:hb_font_funcs_destroy +3051:hb_face_get_upem +3052:hb_face_destroy +3053:hb_draw_cubic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +3054:hb_buffer_set_segment_properties +3055:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3056:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3057:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3058:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3059:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3060:hb_blob_create +3061:haircubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3062:gray_render_line +3063:get_vendor\28char\20const*\29 +3064:get_renderer\28char\20const*\2c\20GrGLExtensions\20const&\29 +3065:get_layer_mapping_and_bounds\28SkSpan>\2c\20SkMatrix\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\2c\20float\29 +3066:get_joining_type\28unsigned\20int\2c\20hb_unicode_general_category_t\29 +3067:getDefaultScript\28icu_74::CharString\20const&\2c\20icu_74::CharString\20const&\29 +3068:generate_distance_field_from_image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\29 +3069:ft_var_readpackeddeltas +3070:ft_var_get_item_delta +3071:ft_var_done_item_variation_store +3072:ft_glyphslot_alloc_bitmap +3073:freelocale +3074:free_pool +3075:fquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3076:fp_barrierf +3077:fline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3078:fixN0c\28BracketData*\2c\20int\2c\20int\2c\20unsigned\20char\29 +3079:fiprintf +3080:findFirstExisting\28char\20const*\2c\20char*\2c\20char\20const*\2c\20UResOpenType\2c\20signed\20char*\2c\20signed\20char*\2c\20signed\20char*\2c\20UErrorCode*\29 +3081:fcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3082:fconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3083:fclose +3084:expm1f +3085:exp2 +3086:emscripten::internal::MethodInvoker::invoke\28void\20\28SkFont::*\20const&\29\28float\29\2c\20SkFont*\2c\20float\29 +3087:emscripten::internal::Invoker>\2c\20SimpleParagraphStyle\2c\20sk_sp>::invoke\28std::__2::unique_ptr>\20\28*\29\28SimpleParagraphStyle\2c\20sk_sp\29\2c\20SimpleParagraphStyle*\2c\20sk_sp*\29 +3088:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28SkFontMgr&\2c\20int\29\2c\20SkFontMgr*\2c\20int\29 +3089:do_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +3090:do_putc +3091:doLoadFromCommonData\28signed\20char\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20signed\20char\20\28*\29\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29\2c\20void*\2c\20UErrorCode*\2c\20UErrorCode*\29 +3092:deserialize_image\28sk_sp\2c\20SkDeserialProcs\2c\20std::__2::optional\29 +3093:decompose\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\2c\20unsigned\20int\29 +3094:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0>\28skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0&&\29::'lambda'\28char*\29::__invoke\28char*\29 +3095:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool&\2c\20GrPipeline*&\2c\20GrUserStencilSettings\20const*&&\2c\20\28anonymous\20namespace\29::DrawAtlasPathShader*&\2c\20GrPrimitiveType&&\2c\20GrXferBarrierFlags&\2c\20GrLoadOp&\29::'lambda'\28void*\29>\28GrProgramInfo&&\29::'lambda'\28char*\29::__invoke\28char*\29 +3096:cubic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3097:conic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3098:compute_ULong_sum +3099:char\20const*\20std::__2::find\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const&\29 +3100:cff_index_get_pointers +3101:cff2_path_param_t::move_to\28CFF::point_t\20const&\29 +3102:cff1_path_param_t::move_to\28CFF::point_t\20const&\29 +3103:cf2_glyphpath_computeOffset +3104:build_tree +3105:bool\20std::__2::__is_pointer_in_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const*\29 +3106:bool\20OT::glyf_impl::Glyph::get_points\28hb_font_t*\2c\20OT::glyf_accelerator_t\20const&\2c\20contour_point_vector_t&\2c\20contour_point_vector_t*\2c\20head_maxp_info_t*\2c\20unsigned\20int*\2c\20bool\2c\20bool\2c\20bool\2c\20hb_array_t\2c\20hb_map_t*\2c\20unsigned\20int\2c\20unsigned\20int*\29\20const +3107:bool\20OT::glyf_accelerator_t::get_points\28hb_font_t*\2c\20unsigned\20int\2c\20OT::glyf_accelerator_t::points_aggregator_t\29\20const +3108:bool\20OT::GSUBGPOSVersion1_2::sanitize\28hb_sanitize_context_t*\29\20const +3109:bool\20OT::GSUBGPOSVersion1_2::sanitize\28hb_sanitize_context_t*\29\20const +3110:blit_aaa_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +3111:atan +3112:alloc_large +3113:af_glyph_hints_done +3114:add_quad\28SkPoint\20const*\2c\20skia_private::TArray*\29 +3115:acos +3116:aaa_fill_path\28SkPath\20const&\2c\20SkIRect\20const&\2c\20AdditiveBlitter*\2c\20int\2c\20int\2c\20bool\2c\20bool\2c\20bool\29 +3117:_get_path\28OT::cff1::accelerator_t\20const*\2c\20hb_font_t*\2c\20unsigned\20int\2c\20hb_draw_session_t&\2c\20bool\2c\20CFF::point_t*\29 +3118:_get_bounds\28OT::cff1::accelerator_t\20const*\2c\20unsigned\20int\2c\20bounds_t&\2c\20bool\29 +3119:_enumPropertyStartsRange\28void\20const*\2c\20int\2c\20int\2c\20unsigned\20int\29 +3120:_embind_register_bindings +3121:_canonicalize\28char\20const*\2c\20icu_74::ByteSink&\2c\20unsigned\20int\2c\20UErrorCode*\29 +3122:__trunctfdf2 +3123:__towrite +3124:__toread +3125:__subtf3 +3126:__strchrnul +3127:__rem_pio2f +3128:__rem_pio2 +3129:__math_uflowf +3130:__math_oflowf +3131:__fwritex +3132:__cxxabiv1::__class_type_info::process_static_type_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\29\20const +3133:__cxxabiv1::__class_type_info::process_static_type_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\29\20const +3134:__cxxabiv1::__class_type_info::process_found_base_class\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +3135:__cxxabiv1::__base_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +3136:\28anonymous\20namespace\29::ulayout_ensureData\28UErrorCode&\29 +3137:\28anonymous\20namespace\29::shape_contains_rect\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const&\2c\20bool\29 +3138:\28anonymous\20namespace\29::getRange\28void\20const*\2c\20int\2c\20unsigned\20int\20\28*\29\28void\20const*\2c\20unsigned\20int\29\2c\20void\20const*\2c\20unsigned\20int*\29 +3139:\28anonymous\20namespace\29::generateFacePathCOLRv1\28FT_FaceRec_*\2c\20unsigned\20short\2c\20SkPath*\29 +3140:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads_with_constraint\28SkPoint\20const*\2c\20float\2c\20SkPathFirstDirection\2c\20skia_private::TArray*\2c\20int\29 +3141:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\2c\20int\2c\20bool\2c\20bool\29 +3142:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const +3143:\28anonymous\20namespace\29::bloat_quad\28SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkMatrix\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +3144:\28anonymous\20namespace\29::SkEmptyTypeface::onMakeClone\28SkFontArguments\20const&\29\20const +3145:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29_5808 +3146:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29 +3147:\28anonymous\20namespace\29::SkBlurImageFilter::mapSigma\28skif::Mapping\20const&\2c\20bool\29\20const +3148:\28anonymous\20namespace\29::DrawAtlasOpImpl::visitProxies\28std::__2::function\20const&\29\20const +3149:\28anonymous\20namespace\29::DrawAtlasOpImpl::programInfo\28\29 +3150:\28anonymous\20namespace\29::DrawAtlasOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +3151:\28anonymous\20namespace\29::DirectMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +3152:\28anonymous\20namespace\29::DirectMaskSubRun::glyphs\28\29\20const +3153:WebPRescaleNeededLines +3154:WebPInitDecBufferInternal +3155:WebPInitCustomIo +3156:WebPGetFeaturesInternal +3157:WebPDemuxGetFrame +3158:VP8LInitBitReader +3159:VP8LColorIndexInverseTransformAlpha +3160:VP8InitIoInternal +3161:VP8InitBitReader +3162:UDatamemory_assign_74 +3163:T_CString_toUpperCase_74 +3164:TT_Vary_Apply_Glyph_Deltas +3165:TT_Set_Var_Design +3166:SkWuffsCodec::decodeFrame\28\29 +3167:SkVertices::MakeCopy\28SkVertices::VertexMode\2c\20int\2c\20SkPoint\20const*\2c\20SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20short\20const*\29 +3168:SkVertices::Builder::texCoords\28\29 +3169:SkVertices::Builder::positions\28\29 +3170:SkVertices::Builder::init\28SkVertices::Desc\20const&\29 +3171:SkVertices::Builder::colors\28\29 +3172:SkVertices::Builder::Builder\28SkVertices::VertexMode\2c\20int\2c\20int\2c\20unsigned\20int\29 +3173:SkUnicodes::ICU::Make\28\29 +3174:SkUnicode_icu::extractPositions\28char\20const*\2c\20int\2c\20SkUnicode::BreakType\2c\20char\20const*\2c\20std::__2::function\20const&\29 +3175:SkTypeface_FreeType::MakeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29 +3176:SkTypeface::getTableSize\28unsigned\20int\29\20const +3177:SkTiff::ImageFileDirectory::getEntryTag\28unsigned\20short\29\20const +3178:SkTiff::ImageFileDirectory::MakeFromOffset\28sk_sp\2c\20bool\2c\20unsigned\20int\2c\20bool\29 +3179:SkTextBlobRunIterator::positioning\28\29\20const +3180:SkTSpan::splitAt\28SkTSpan*\2c\20double\2c\20SkArenaAlloc*\29 +3181:SkTSect::computePerpendiculars\28SkTSect*\2c\20SkTSpan*\2c\20SkTSpan*\29 +3182:SkTDStorage::insert\28int\29 +3183:SkTDStorage::calculateSizeOrDie\28int\29::$_0::operator\28\29\28\29\20const +3184:SkTDPQueue::percolateDownIfNecessary\28int\29 +3185:SkTConic::hullIntersects\28SkDConic\20const&\2c\20bool*\29\20const +3186:SkSurface_Base::SkSurface_Base\28int\2c\20int\2c\20SkSurfaceProps\20const*\29 +3187:SkStrokerPriv::CapFactory\28SkPaint::Cap\29 +3188:SkStrokeRec::getInflationRadius\28\29\20const +3189:SkString::equals\28char\20const*\29\20const +3190:SkStrikeSpec::MakeTransformMask\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +3191:SkStrikeSpec::MakePath\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\29 +3192:SkShapers::HB::ShapeDontWrapOrReorder\28sk_sp\2c\20sk_sp\29 +3193:SkShaper::TrivialRunIterator::endOfCurrentRun\28\29\20const +3194:SkShaper::TrivialRunIterator::atEnd\28\29\20const +3195:SkShaper::MakeFontMgrRunIterator\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20sk_sp\29 +3196:SkShadowTessellator::MakeAmbient\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20bool\29 +3197:SkScan::HairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3198:SkScan::FillTriangle\28SkPoint\20const*\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3199:SkScan::FillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3200:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3201:SkScan::AntiHairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3202:SkScan::AntiHairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3203:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\2c\20bool\29 +3204:SkScalerContextRec::CachedMaskGamma\28unsigned\20char\2c\20unsigned\20char\29 +3205:SkScalerContextFTUtils::drawSVGGlyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +3206:SkScalarInterpFunc\28float\2c\20float\20const*\2c\20float\20const*\2c\20int\29 +3207:SkSLTypeString\28SkSLType\29 +3208:SkSL::simplify_negation\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\29 +3209:SkSL::simplify_matrix_multiplication\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3210:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +3211:SkSL::build_argument_type_list\28SkSpan>\20const>\29 +3212:SkSL::\28anonymous\20namespace\29::SwitchCaseContainsExit::visitStatement\28SkSL::Statement\20const&\29 +3213:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::returnsInputAlpha\28SkSL::Expression\20const&\29 +3214:SkSL::\28anonymous\20namespace\29::ConstantExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +3215:SkSL::Variable::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\29 +3216:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29\20const +3217:SkSL::Type::MakeSamplerType\28char\20const*\2c\20SkSL::Type\20const&\29 +3218:SkSL::SymbolTable::moveSymbolTo\28SkSL::SymbolTable*\2c\20SkSL::Symbol*\2c\20SkSL::Context\20const&\29 +3219:SkSL::SymbolTable::isType\28std::__2::basic_string_view>\29\20const +3220:SkSL::Symbol::instantiate\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +3221:SkSL::StructType::slotCount\28\29\20const +3222:SkSL::ReturnStatement::~ReturnStatement\28\29_6426 +3223:SkSL::ReturnStatement::~ReturnStatement\28\29 +3224:SkSL::RP::UnownedLValueSlice::~UnownedLValueSlice\28\29 +3225:SkSL::RP::Generator::pushTernaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +3226:SkSL::RP::Generator::pushStructuredComparison\28SkSL::RP::LValue*\2c\20SkSL::Operator\2c\20SkSL::RP::LValue*\2c\20SkSL::Type\20const&\29 +3227:SkSL::RP::Generator::pushMatrixMultiply\28SkSL::RP::LValue*\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3228:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29 +3229:SkSL::RP::Builder::push_uniform\28SkSL::RP::SlotRange\29 +3230:SkSL::RP::Builder::merge_condition_mask\28\29 +3231:SkSL::RP::Builder::jump\28int\29 +3232:SkSL::RP::Builder::branch_if_no_active_lanes_on_stack_top_equal\28int\2c\20int\29 +3233:SkSL::ProgramUsage::~ProgramUsage\28\29 +3234:SkSL::ProgramUsage::add\28SkSL::ProgramElement\20const&\29 +3235:SkSL::Pool::detachFromThread\28\29 +3236:SkSL::PipelineStage::ConvertProgram\28SkSL::Program\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20SkSL::PipelineStage::Callbacks*\29 +3237:SkSL::Parser::unaryExpression\28\29 +3238:SkSL::Parser::swizzle\28SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::basic_string_view>\2c\20SkSL::Position\29 +3239:SkSL::Parser::block\28bool\2c\20std::__2::unique_ptr>*\29 +3240:SkSL::Operator::getBinaryPrecedence\28\29\20const +3241:SkSL::ModuleLoader::loadVertexModule\28SkSL::Compiler*\29 +3242:SkSL::ModuleLoader::loadGPUModule\28SkSL::Compiler*\29 +3243:SkSL::ModuleLoader::loadFragmentModule\28SkSL::Compiler*\29 +3244:SkSL::ModifierFlags::checkPermittedFlags\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\29\20const +3245:SkSL::Mangler::uniqueName\28std::__2::basic_string_view>\2c\20SkSL::SymbolTable*\29 +3246:SkSL::LiteralType::slotType\28unsigned\20long\29\20const +3247:SkSL::Layout::operator==\28SkSL::Layout\20const&\29\20const +3248:SkSL::Layout::checkPermittedLayout\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkEnumBitMask\29\20const +3249:SkSL::Inliner::analyze\28std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\29 +3250:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29 +3251:SkSL::GLSLCodeGenerator::writeLiteral\28SkSL::Literal\20const&\29 +3252:SkSL::GLSLCodeGenerator::writeFunctionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +3253:SkSL::ForStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3254:SkSL::FieldAccess::description\28SkSL::OperatorPrecedence\29\20const +3255:SkSL::Expression::isIncomplete\28SkSL::Context\20const&\29\20const +3256:SkSL::Expression::compareConstant\28SkSL::Expression\20const&\29\20const +3257:SkSL::DebugTracePriv::~DebugTracePriv\28\29 +3258:SkSL::Context::Context\28SkSL::BuiltinTypes\20const&\2c\20SkSL::ErrorReporter&\29 +3259:SkSL::ConstructorArrayCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +3260:SkSL::ConstructorArray::~ConstructorArray\28\29 +3261:SkSL::ConstructorArray::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +3262:SkSL::Analysis::GetReturnComplexity\28SkSL::FunctionDefinition\20const&\29 +3263:SkSL::Analysis::CallsColorTransformIntrinsics\28SkSL::Program\20const&\29 +3264:SkSL::AliasType::bitWidth\28\29\20const +3265:SkRuntimeEffectPriv::VarAsUniform\28SkSL::Variable\20const&\2c\20SkSL::Context\20const&\2c\20unsigned\20long*\29 +3266:SkRuntimeEffectPriv::UniformsAsSpan\28SkSpan\2c\20sk_sp\2c\20bool\2c\20SkColorSpace\20const*\2c\20SkArenaAlloc*\29 +3267:SkRuntimeEffect::source\28\29\20const +3268:SkRuntimeEffect::makeShader\28sk_sp\2c\20SkSpan\2c\20SkMatrix\20const*\29\20const +3269:SkRuntimeEffect::MakeForBlender\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +3270:SkResourceCache::checkMessages\28\29 +3271:SkResourceCache::NewCachedData\28unsigned\20long\29 +3272:SkRegion::translate\28int\2c\20int\2c\20SkRegion*\29\20const +3273:SkReduceOrder::Cubic\28SkPoint\20const*\2c\20SkPoint*\29 +3274:SkRectPriv::QuadContainsRectMask\28SkM44\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20float\29 +3275:SkRecords::PreCachedPath::PreCachedPath\28SkPath\20const&\29 +3276:SkRecords::FillBounds::pushSaveBlock\28SkPaint\20const*\2c\20bool\29 +3277:SkRecordDraw\28SkRecord\20const&\2c\20SkCanvas*\2c\20SkPicture\20const*\20const*\2c\20SkDrawable*\20const*\2c\20int\2c\20SkBBoxHierarchy\20const*\2c\20SkPicture::AbortCallback*\29 +3278:SkReadBuffer::readPoint\28SkPoint*\29 +3279:SkReadBuffer::readPath\28SkPath*\29 +3280:SkReadBuffer::readByteArrayAsData\28\29 +3281:SkRasterPipeline_<256ul>::SkRasterPipeline_\28\29 +3282:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29 +3283:SkRasterPipelineBlitter::blitRectWithTrace\28int\2c\20int\2c\20int\2c\20int\2c\20bool\29 +3284:SkRasterPipelineBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +3285:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29 +3286:SkRasterPipeline::appendLoad\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +3287:SkRasterClip::op\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkClipOp\2c\20bool\29 +3288:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29 +3289:SkRRect::scaleRadii\28\29 +3290:SkRRect::AreRectAndRadiiValid\28SkRect\20const&\2c\20SkPoint\20const*\29 +3291:SkRBuffer::skip\28unsigned\20long\29 +3292:SkPngEncoderImpl::~SkPngEncoderImpl\28\29 +3293:SkPngEncoder::Make\28SkWStream*\2c\20SkPixmap\20const&\2c\20SkPngEncoder::Options\20const&\29 +3294:SkPngDecoder::IsPng\28void\20const*\2c\20unsigned\20long\29 +3295:SkPixmap::setColorSpace\28sk_sp\29 +3296:SkPixelRef::~SkPixelRef\28\29 +3297:SkPixelRef::notifyPixelsChanged\28\29 +3298:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20sk_sp\29 +3299:SkPictureRecord::addPathToHeap\28SkPath\20const&\29 +3300:SkPictureData::getPath\28SkReadBuffer*\29\20const +3301:SkPicture::serialize\28SkWStream*\2c\20SkSerialProcs\20const*\2c\20SkRefCntSet*\2c\20bool\29\20const +3302:SkPathWriter::update\28SkOpPtT\20const*\29 +3303:SkPathStroker::strokeCloseEnough\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20SkQuadConstruct*\29\20const +3304:SkPathStroker::finishContour\28bool\2c\20bool\29 +3305:SkPathRef::reset\28\29 +3306:SkPathRef::isRRect\28SkRRect*\2c\20bool*\2c\20unsigned\20int*\29\20const +3307:SkPathRef::addGenIDChangeListener\28sk_sp\29 +3308:SkPathPriv::IsRectContour\28SkPath\20const&\2c\20bool\2c\20int*\2c\20SkPoint\20const**\2c\20bool*\2c\20SkPathDirection*\2c\20SkRect*\29 +3309:SkPathEffectBase::onAsPoints\28SkPathEffectBase::PointData*\2c\20SkPath\20const&\2c\20SkStrokeRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\29\20const +3310:SkPathEffect::filterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\29\20const +3311:SkPathBuilder::quadTo\28SkPoint\2c\20SkPoint\29 +3312:SkPathBuilder::cubicTo\28SkPoint\2c\20SkPoint\2c\20SkPoint\29 +3313:SkPath::writeToMemory\28void*\29\20const +3314:SkPath::reversePathTo\28SkPath\20const&\29 +3315:SkPath::rQuadTo\28float\2c\20float\2c\20float\2c\20float\29 +3316:SkPath::contains\28float\2c\20float\29\20const +3317:SkPath::arcTo\28float\2c\20float\2c\20float\2c\20SkPath::ArcSize\2c\20SkPathDirection\2c\20float\2c\20float\29 +3318:SkPath::approximateBytesUsed\28\29\20const +3319:SkPath::addCircle\28float\2c\20float\2c\20float\2c\20SkPathDirection\29 +3320:SkPath::Rect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3321:SkParse::FindScalar\28char\20const*\2c\20float*\29 +3322:SkPairPathEffect::flatten\28SkWriteBuffer&\29\20const +3323:SkPaintToGrPaintWithBlend\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +3324:SkPaint::refImageFilter\28\29\20const +3325:SkPaint::refBlender\28\29\20const +3326:SkPaint::getBlendMode_or\28SkBlendMode\29\20const +3327:SkPackARGB_as_RGBA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +3328:SkPackARGB_as_BGRA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +3329:SkOpSpan::setOppSum\28int\29 +3330:SkOpSegment::markAndChaseWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int\2c\20SkOpSpanBase**\29 +3331:SkOpSegment::markAllDone\28\29 +3332:SkOpSegment::activeWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +3333:SkOpPtT::contains\28SkOpSegment\20const*\29\20const +3334:SkOpEdgeBuilder::closeContour\28SkPoint\20const&\2c\20SkPoint\20const&\29 +3335:SkOpCoincidence::releaseDeleted\28\29 +3336:SkOpCoincidence::markCollapsed\28SkOpPtT*\29 +3337:SkOpCoincidence::findOverlaps\28SkOpCoincidence*\29\20const +3338:SkOpCoincidence::expand\28\29 +3339:SkOpCoincidence::apply\28\29 +3340:SkOpAngle::orderable\28SkOpAngle*\29 +3341:SkOpAngle::computeSector\28\29 +3342:SkNullBlitter::~SkNullBlitter\28\29 +3343:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\2c\20sk_sp\29 +3344:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\29 +3345:SkMessageBus::BufferFinishedMessage\2c\20GrDirectContext::DirectContextID\2c\20false>::Get\28\29 +3346:SkMemoryStream::SkMemoryStream\28sk_sp\29 +3347:SkMatrix::setRotate\28float\29 +3348:SkMatrix::setPolyToPoly\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20int\29 +3349:SkMatrix::postSkew\28float\2c\20float\29 +3350:SkMatrix::invert\28SkMatrix*\29\20const +3351:SkMatrix::getMinScale\28\29\20const +3352:SkMatrix::getMinMaxScales\28float*\29\20const +3353:SkMaskBuilder::PrepareDestination\28int\2c\20int\2c\20SkMask\20const&\29 +3354:SkMakeBitmapShaderForPaint\28SkPaint\20const&\2c\20SkBitmap\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20SkCopyPixelsMode\29 +3355:SkLineClipper::ClipLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\2c\20bool\29 +3356:SkLRUCache::~SkLRUCache\28\29 +3357:SkJSONWriter::separator\28bool\29 +3358:SkIntersections::intersectRay\28SkDQuad\20const&\2c\20SkDLine\20const&\29 +3359:SkIntersections::intersectRay\28SkDLine\20const&\2c\20SkDLine\20const&\29 +3360:SkIntersections::intersectRay\28SkDCubic\20const&\2c\20SkDLine\20const&\29 +3361:SkIntersections::intersectRay\28SkDConic\20const&\2c\20SkDLine\20const&\29 +3362:SkIntersections::cleanUpParallelLines\28bool\29 +3363:SkImage_Raster::onPeekBitmap\28\29\20const +3364:SkImage_Raster::SkImage_Raster\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20int\29 +3365:SkImage_Ganesh::~SkImage_Ganesh\28\29 +3366:SkImageShader::Make\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +3367:SkImageInfo::Make\28SkISize\2c\20SkColorType\2c\20SkAlphaType\29 +3368:SkImageInfo::MakeN32Premul\28SkISize\29 +3369:SkImageGenerator::getPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\29 +3370:SkImageGenerator::SkImageGenerator\28SkImageInfo\20const&\2c\20unsigned\20int\29 +3371:SkImageFilters::Blur\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +3372:SkImageFilter_Base::getInputBounds\28skif::Mapping\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\29\20const +3373:SkImageFilter_Base::filterImage\28skif::Context\20const&\29\20const +3374:SkImageFilter_Base::affectsTransparentBlack\28\29\20const +3375:SkImage::width\28\29\20const +3376:SkImage::hasMipmaps\28\29\20const +3377:SkIcuBreakIteratorCache::makeBreakIterator\28SkUnicode::BreakType\2c\20char\20const*\29 +3378:SkIDChangeListener::List::add\28sk_sp\29 +3379:SkGradientShader::MakeTwoPointConical\28SkPoint\20const&\2c\20float\2c\20SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3380:SkGradientShader::MakeLinear\28SkPoint\20const*\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3381:SkGradientBaseShader::AppendInterpolatedToDstStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20bool\2c\20SkGradientShader::Interpolation\20const&\2c\20SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +3382:SkGlyph::setPath\28SkArenaAlloc*\2c\20SkScalerContext*\29 +3383:SkGlyph::mask\28\29\20const +3384:SkFontPriv::ApproximateTransformedTextSize\28SkFont\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\20const&\29 +3385:SkFontMgr::matchFamily\28char\20const*\29\20const +3386:SkFindCubicMaxCurvature\28SkPoint\20const*\2c\20float*\29 +3387:SkExif::parse_ifd\28SkExif::Metadata&\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20bool\2c\20bool\29 +3388:SkEncoder::encodeRows\28int\29 +3389:SkEncodedInfo::ICCProfile::Make\28sk_sp\29 +3390:SkEmptyFontMgr::onMatchFamilyStyleCharacter\28char\20const*\2c\20SkFontStyle\20const&\2c\20char\20const**\2c\20int\2c\20int\29\20const +3391:SkEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkIRect\20const*\2c\20int\29 +3392:SkDynamicMemoryWStream::padToAlign4\28\29 +3393:SkDrawable::SkDrawable\28\29 +3394:SkDrawBase::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29\20const +3395:SkDrawBase::drawDevicePoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\2c\20SkDevice*\29\20const +3396:SkDraw::drawBitmap\28SkBitmap\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29\20const +3397:SkDevice::simplifyGlyphRunRSXFormAndRedraw\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +3398:SkDevice::setDeviceCoordinateSystem\28SkM44\20const&\2c\20SkM44\20const&\2c\20SkM44\20const&\2c\20int\2c\20int\29 +3399:SkDevice::SkDevice\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +3400:SkDataTable::at\28int\2c\20unsigned\20long*\29\20const +3401:SkData::MakeFromStream\28SkStream*\2c\20unsigned\20long\29 +3402:SkDQuad::dxdyAtT\28double\29\20const +3403:SkDQuad::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +3404:SkDQuad::FindExtrema\28double\20const*\2c\20double*\29 +3405:SkDCubic::subDivide\28double\2c\20double\29\20const +3406:SkDCubic::searchRoots\28double*\2c\20int\2c\20double\2c\20SkDCubic::SearchAxis\2c\20double*\29\20const +3407:SkDCubic::Coefficients\28double\20const*\2c\20double*\2c\20double*\2c\20double*\2c\20double*\29 +3408:SkDConic::dxdyAtT\28double\29\20const +3409:SkDConic::FindExtrema\28double\20const*\2c\20float\2c\20double*\29 +3410:SkCopyStreamToData\28SkStream*\29 +3411:SkContourMeasure_segTo\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20float\2c\20SkPath*\29 +3412:SkContourMeasureIter::next\28\29 +3413:SkContourMeasureIter::Impl::compute_quad_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3414:SkContourMeasureIter::Impl::compute_cubic_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3415:SkContourMeasureIter::Impl::compute_conic_segs\28SkConic\20const&\2c\20float\2c\20int\2c\20SkPoint\20const&\2c\20int\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20int\29 +3416:SkContourMeasure::getPosTan\28float\2c\20SkPoint*\2c\20SkPoint*\29\20const +3417:SkConic::evalAt\28float\29\20const +3418:SkConic::TransformW\28SkPoint\20const*\2c\20float\2c\20SkMatrix\20const&\29 +3419:SkColorSpace::transferFn\28skcms_TransferFunction*\29\20const +3420:SkColorSpace::toXYZD50\28skcms_Matrix3x3*\29\20const +3421:SkColorSpace::serialize\28\29\20const +3422:SkColorPalette::SkColorPalette\28unsigned\20int\20const*\2c\20int\29 +3423:SkColor4fPrepForDst\28SkRGBA4f<\28SkAlphaType\293>\2c\20GrColorInfo\20const&\29 +3424:SkCodec::startIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const*\29 +3425:SkCodec::outputScanline\28int\29\20const +3426:SkChopMonoCubicAtY\28SkPoint\20const*\2c\20float\2c\20SkPoint*\29 +3427:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\2c\20float\29 +3428:SkCanvas::setMatrix\28SkM44\20const&\29 +3429:SkCanvas::scale\28float\2c\20float\29 +3430:SkCanvas::private_draw_shadow_rec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +3431:SkCanvas::peekPixels\28SkPixmap*\29 +3432:SkCanvas::onResetClip\28\29 +3433:SkCanvas::onClipShader\28sk_sp\2c\20SkClipOp\29 +3434:SkCanvas::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +3435:SkCanvas::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3436:SkCanvas::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3437:SkCanvas::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3438:SkCanvas::internal_private_resetClip\28\29 +3439:SkCanvas::internalSaveLayer\28SkCanvas::SaveLayerRec\20const&\2c\20SkCanvas::SaveLayerStrategy\2c\20bool\29 +3440:SkCanvas::internalDrawDeviceWithFilter\28SkDevice*\2c\20SkDevice*\2c\20SkSpan>\2c\20SkPaint\20const&\2c\20SkCanvas::DeviceCompatibleWithFilter\2c\20SkColorInfo\20const&\2c\20float\2c\20SkTileMode\2c\20bool\29 +3441:SkCanvas::experimental_DrawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +3442:SkCanvas::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +3443:SkCanvas::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +3444:SkCanvas::drawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +3445:SkCanvas::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +3446:SkCanvas::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +3447:SkCanvas::drawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +3448:SkCanvas::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +3449:SkCanvas::attemptBlurredRRectDraw\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20SkEnumBitMask\29 +3450:SkCanvas::SkCanvas\28SkIRect\20const&\29 +3451:SkCachedData::~SkCachedData\28\29 +3452:SkCTMShader::~SkCTMShader\28\29_4795 +3453:SkBmpRLECodec::setPixel\28void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20char\29 +3454:SkBmpCodec::prepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +3455:SkBlockMemoryStream::getPosition\28\29\20const +3456:SkBlitterClipper::apply\28SkBlitter*\2c\20SkRegion\20const*\2c\20SkIRect\20const*\29 +3457:SkBlitter::blitRegion\28SkRegion\20const&\29 +3458:SkBitmapDevice::Create\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\2c\20SkRasterHandleAllocator*\29 +3459:SkBitmapDevice::BDDraw::~BDDraw\28\29 +3460:SkBitmapCacheDesc::Make\28SkImage\20const*\29 +3461:SkBitmap::writePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +3462:SkBitmap::setPixels\28void*\29 +3463:SkBitmap::pixelRefOrigin\28\29\20const +3464:SkBitmap::notifyPixelsChanged\28\29\20const +3465:SkBitmap::isImmutable\28\29\20const +3466:SkBitmap::allocPixels\28\29 +3467:SkBinaryWriteBuffer::writeScalarArray\28float\20const*\2c\20unsigned\20int\29 +3468:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29_5548 +3469:SkBaseShadowTessellator::handleCubic\28SkMatrix\20const&\2c\20SkPoint*\29 +3470:SkBaseShadowTessellator::handleConic\28SkMatrix\20const&\2c\20SkPoint*\2c\20float\29 +3471:SkAutoPathBoundsUpdate::SkAutoPathBoundsUpdate\28SkPath*\2c\20SkRect\20const&\29 +3472:SkAutoDescriptor::SkAutoDescriptor\28SkAutoDescriptor&&\29 +3473:SkArenaAllocWithReset::SkArenaAllocWithReset\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +3474:SkAnimatedImage::decodeNextFrame\28\29 +3475:SkAnimatedImage::Frame::copyTo\28SkAnimatedImage::Frame*\29\20const +3476:SkAnalyticQuadraticEdge::updateQuadratic\28\29 +3477:SkAnalyticCubicEdge::updateCubic\28bool\29 +3478:SkAlphaRuns::reset\28int\29 +3479:SkAAClip::setRect\28SkIRect\20const&\29 +3480:Simplify\28SkPath\20const&\2c\20SkPath*\29 +3481:ReconstructRow +3482:R_17108 +3483:OpAsWinding::nextEdge\28Contour&\2c\20OpAsWinding::Edge\29 +3484:OT::sbix::sanitize\28hb_sanitize_context_t*\29\20const +3485:OT::post::accelerator_t::cmp_gids\28void\20const*\2c\20void\20const*\2c\20void*\29 +3486:OT::gvar::sanitize_shallow\28hb_sanitize_context_t*\29\20const +3487:OT::fvar::sanitize\28hb_sanitize_context_t*\29\20const +3488:OT::cmap_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3489:OT::cmap::sanitize\28hb_sanitize_context_t*\29\20const +3490:OT::avar::sanitize\28hb_sanitize_context_t*\29\20const +3491:OT::VarRegionList::evaluate\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +3492:OT::VVAR::sanitize\28hb_sanitize_context_t*\29\20const +3493:OT::Rule::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +3494:OT::OpenTypeFontFile::sanitize\28hb_sanitize_context_t*\29\20const +3495:OT::MVAR::sanitize\28hb_sanitize_context_t*\29\20const +3496:OT::Layout::GSUB_impl::SubstLookup::serialize_ligature\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20hb_sorted_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\29 +3497:OT::Layout::GSUB::get_lookup\28unsigned\20int\29\20const +3498:OT::Layout::GPOS_impl::MarkArray::apply\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20OT::Layout::GPOS_impl::AnchorMatrix\20const&\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +3499:OT::GDEFVersion1_2::sanitize\28hb_sanitize_context_t*\29\20const +3500:OT::Device::get_y_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3501:OT::Device::get_x_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3502:OT::ClipList::get_extents\28unsigned\20int\2c\20hb_glyph_extents_t*\2c\20OT::VarStoreInstancer\20const&\29\20const +3503:OT::ChainRule::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +3504:OT::CPAL::sanitize\28hb_sanitize_context_t*\29\20const +3505:OT::COLR::sanitize\28hb_sanitize_context_t*\29\20const +3506:OT::COLR::paint_glyph\28hb_font_t*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29\20const +3507:MakeRasterCopyPriv\28SkPixmap\20const&\2c\20unsigned\20int\29 +3508:LineQuadraticIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineQuadraticIntersections::PinTPoint\29 +3509:LineQuadraticIntersections::checkCoincident\28\29 +3510:LineQuadraticIntersections::addLineNearEndPoints\28\29 +3511:LineCubicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineCubicIntersections::PinTPoint\29 +3512:LineCubicIntersections::checkCoincident\28\29 +3513:LineCubicIntersections::addLineNearEndPoints\28\29 +3514:LineConicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineConicIntersections::PinTPoint\29 +3515:LineConicIntersections::checkCoincident\28\29 +3516:LineConicIntersections::addLineNearEndPoints\28\29 +3517:Ins_UNKNOWN +3518:GrXferProcessor::GrXferProcessor\28GrProcessor::ClassID\29 +3519:GrVertexChunkBuilder::~GrVertexChunkBuilder\28\29 +3520:GrTriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +3521:GrTriangulator::splitEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +3522:GrTriangulator::pathToPolys\28float\2c\20SkRect\20const&\2c\20bool*\29 +3523:GrTriangulator::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20GrTriangulator::VertexList*\2c\20int\29\20const +3524:GrTriangulator::emitTriangle\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20skgpu::VertexWriter\29\20const +3525:GrTriangulator::checkForIntersection\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +3526:GrTriangulator::applyFillType\28int\29\20const +3527:GrTriangulator::EdgeList::insert\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +3528:GrTriangulator::Edge::intersect\28GrTriangulator::Edge\20const&\2c\20SkPoint*\2c\20unsigned\20char*\29\20const +3529:GrTriangulator::Edge::insertBelow\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +3530:GrTriangulator::Edge::insertAbove\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +3531:GrToGLStencilFunc\28GrStencilTest\29 +3532:GrThreadSafeCache::~GrThreadSafeCache\28\29 +3533:GrThreadSafeCache::dropAllRefs\28\29 +3534:GrTextureRenderTargetProxy::callbackDesc\28\29\20const +3535:GrTextureProxy::clearUniqueKey\28\29 +3536:GrTexture::GrTexture\28GrGpu*\2c\20SkISize\20const&\2c\20skgpu::Protected\2c\20GrTextureType\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +3537:GrTexture::ComputeScratchKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20skgpu::ScratchKey*\29 +3538:GrSurfaceProxyView::asTextureProxyRef\28\29\20const +3539:GrSurfaceProxy::GrSurfaceProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +3540:GrSurfaceProxy::GrSurfaceProxy\28sk_sp\2c\20SkBackingFit\2c\20GrSurfaceProxy::UseAllocator\29 +3541:GrSurface::setRelease\28sk_sp\29 +3542:GrStyledShape::styledBounds\28\29\20const +3543:GrStyledShape::asLine\28SkPoint*\2c\20bool*\29\20const +3544:GrStyledShape::addGenIDChangeListener\28sk_sp\29\20const +3545:GrSimpleMeshDrawOpHelper::fixedFunctionFlags\28\29\20const +3546:GrShape::setRRect\28SkRRect\20const&\29 +3547:GrShape::segmentMask\28\29\20const +3548:GrResourceProvider::assignUniqueKeyToResource\28skgpu::UniqueKey\20const&\2c\20GrGpuResource*\29 +3549:GrResourceCache::releaseAll\28\29 +3550:GrResourceCache::refAndMakeResourceMRU\28GrGpuResource*\29 +3551:GrResourceCache::getNextTimestamp\28\29 +3552:GrRenderTask::addDependency\28GrRenderTask*\29 +3553:GrRenderTargetProxy::canUseStencil\28GrCaps\20const&\29\20const +3554:GrRecordingContextPriv::addOnFlushCallbackObject\28GrOnFlushCallbackObject*\29 +3555:GrRecordingContext::~GrRecordingContext\28\29 +3556:GrRecordingContext::abandonContext\28\29 +3557:GrQuadUtils::TessellationHelper::Vertices::moveTo\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +3558:GrQuadUtils::TessellationHelper::EdgeEquations::reset\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\29 +3559:GrQuadUtils::ResolveAAType\28GrAAType\2c\20GrQuadAAFlags\2c\20GrQuad\20const&\2c\20GrAAType*\2c\20GrQuadAAFlags*\29 +3560:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::append\28GrQuad\20const&\2c\20\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA&&\2c\20GrQuad\20const*\29 +3561:GrPixmap::GrPixmap\28GrImageInfo\2c\20void*\2c\20unsigned\20long\29 +3562:GrPipeline::GrPipeline\28GrPipeline::InitArgs\20const&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29 +3563:GrPersistentCacheUtils::UnpackCachedShaders\28SkReadBuffer*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20int\2c\20GrPersistentCacheUtils::ShaderMetadata*\29 +3564:GrPathUtils::convertCubicToQuads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\29 +3565:GrPathTessellationShader::Make\28GrShaderCaps\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::tess::PatchAttribs\29 +3566:GrOp::chainConcat\28std::__2::unique_ptr>\29 +3567:GrMeshDrawOp::PatternHelper::PatternHelper\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +3568:GrMemoryPool::Make\28unsigned\20long\2c\20unsigned\20long\29 +3569:GrMakeKeyFromImageID\28skgpu::UniqueKey*\2c\20unsigned\20int\2c\20SkIRect\20const&\29 +3570:GrImageInfo::GrImageInfo\28GrColorInfo\20const&\2c\20SkISize\20const&\29 +3571:GrGpuResource::removeScratchKey\28\29 +3572:GrGpuResource::registerWithCacheWrapped\28GrWrapCacheable\29 +3573:GrGpuResource::dumpMemoryStatisticsPriv\28SkTraceMemoryDump*\2c\20SkString\20const&\2c\20char\20const*\2c\20unsigned\20long\29\20const +3574:GrGpuBuffer::onGpuMemorySize\28\29\20const +3575:GrGpu::resolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +3576:GrGpu::executeFlushInfo\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20std::__2::optional\2c\20skgpu::MutableTextureState\20const*\29 +3577:GrGeometryProcessor::TextureSampler::TextureSampler\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +3578:GrGeometryProcessor::ProgramImpl::ComputeMatrixKeys\28GrShaderCaps\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\29 +3579:GrGLUniformHandler::getUniformVariable\28GrResourceHandle\29\20const +3580:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_12320 +3581:GrGLSemaphore::GrGLSemaphore\28GrGLGpu*\2c\20bool\29 +3582:GrGLSLVaryingHandler::~GrGLSLVaryingHandler\28\29 +3583:GrGLSLShaderBuilder::emitFunction\28SkSLType\2c\20char\20const*\2c\20SkSpan\2c\20char\20const*\29 +3584:GrGLSLProgramDataManager::setSkMatrix\28GrResourceHandle\2c\20SkMatrix\20const&\29\20const +3585:GrGLSLProgramBuilder::writeFPFunction\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +3586:GrGLSLProgramBuilder::invokeFP\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +3587:GrGLSLProgramBuilder::addRTFlipUniform\28char\20const*\29 +3588:GrGLSLFragmentShaderBuilder::dstColor\28\29 +3589:GrGLSLBlend::BlendKey\28SkBlendMode\29 +3590:GrGLProgramBuilder::~GrGLProgramBuilder\28\29 +3591:GrGLProgramBuilder::computeCountsAndStrides\28unsigned\20int\2c\20GrGeometryProcessor\20const&\2c\20bool\29 +3592:GrGLGpu::flushScissor\28GrScissorState\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +3593:GrGLGpu::flushClearColor\28std::__2::array\29 +3594:GrGLGpu::createTexture\28SkISize\2c\20GrGLFormat\2c\20unsigned\20int\2c\20skgpu::Renderable\2c\20GrGLTextureParameters::SamplerOverriddenState*\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +3595:GrGLGpu::copySurfaceAsDraw\28GrSurface*\2c\20bool\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +3596:GrGLGpu::HWVertexArrayState::bindInternalVertexArray\28GrGLGpu*\2c\20GrBuffer\20const*\29 +3597:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +3598:GrGLBuffer::Make\28GrGLGpu*\2c\20unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +3599:GrGLAttribArrayState::enableVertexArrays\28GrGLGpu\20const*\2c\20int\2c\20GrPrimitiveRestart\29 +3600:GrFragmentProcessors::make_effect_fp\28sk_sp\2c\20char\20const*\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkSpan\2c\20GrFPArgs\20const&\29 +3601:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkMatrix\20const&\29 +3602:GrFragmentProcessors::MakeChildFP\28SkRuntimeEffect::ChildPtr\20const&\2c\20GrFPArgs\20const&\29 +3603:GrFragmentProcessors::IsSupported\28SkMaskFilter\20const*\29 +3604:GrFragmentProcessor::makeProgramImpl\28\29\20const +3605:GrFragmentProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +3606:GrFragmentProcessor::MulInputByChildAlpha\28std::__2::unique_ptr>\29 +3607:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +3608:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29 +3609:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3610:GrDynamicAtlas::makeNode\28GrDynamicAtlas::Node*\2c\20int\2c\20int\2c\20int\2c\20int\29 +3611:GrDynamicAtlas::instantiate\28GrOnFlushResourceProvider*\2c\20sk_sp\29 +3612:GrDrawingManager::setLastRenderTask\28GrSurfaceProxy\20const*\2c\20GrRenderTask*\29 +3613:GrDrawingManager::flushSurfaces\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +3614:GrDrawOpAtlas::updatePlot\28GrDeferredUploadTarget*\2c\20skgpu::AtlasLocator*\2c\20skgpu::Plot*\29 +3615:GrDirectContext::resetContext\28unsigned\20int\29 +3616:GrDirectContext::getResourceCacheLimit\28\29\20const +3617:GrDefaultGeoProcFactory::MakeForDeviceSpace\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +3618:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20sk_sp\29 +3619:GrColorSpaceXform::apply\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +3620:GrColorSpaceXform::Equals\28GrColorSpaceXform\20const*\2c\20GrColorSpaceXform\20const*\29 +3621:GrBufferAllocPool::unmap\28\29 +3622:GrBlurUtils::can_filter_mask\28SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect*\29 +3623:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29 +3624:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +3625:GrBackendTextures::MakeGL\28int\2c\20int\2c\20skgpu::Mipmapped\2c\20GrGLTextureInfo\20const&\2c\20sk_sp\2c\20std::__2::basic_string_view>\29 +3626:GrBackendFormatStencilBits\28GrBackendFormat\20const&\29 +3627:GrBackendFormat::asMockCompressionType\28\29\20const +3628:GrAATriangulator::~GrAATriangulator\28\29 +3629:GrAAConvexTessellator::fanRing\28GrAAConvexTessellator::Ring\20const&\29 +3630:GrAAConvexTessellator::computePtAlongBisector\28int\2c\20SkPoint\20const&\2c\20int\2c\20float\2c\20SkPoint*\29\20const +3631:GetVariationDesignPosition\28FT_FaceRec_*\2c\20SkFontArguments::VariationPosition::Coordinate*\2c\20int\29 +3632:GetAxes\28FT_FaceRec_*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\29 +3633:FT_Stream_ReadAt +3634:FT_Set_Char_Size +3635:FT_Request_Metrics +3636:FT_New_Library +3637:FT_Hypot +3638:FT_Get_Var_Design_Coordinates +3639:FT_Get_Paint +3640:FT_Get_MM_Var +3641:FT_Get_Advance +3642:FT_Add_Default_Modules +3643:DecodeImageData +3644:Cr_z_inflate_table +3645:Cr_z_inflateReset +3646:Cr_z_deflateEnd +3647:Cr_z_copy_with_crc +3648:Compute_Point_Displacement +3649:BuildHuffmanTable +3650:BrotliWarmupBitReader +3651:BrotliDecoderHuffmanTreeGroupInit +3652:AAT::track::sanitize\28hb_sanitize_context_t*\29\20const +3653:AAT::ltag::sanitize\28hb_sanitize_context_t*\29\20const +3654:AAT::StateTable::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +3655:AAT::Lookup>\2c\20OT::IntType\2c\20false>>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3656:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +3657:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +3658:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +3659:3421 +3660:3422 +3661:3423 +3662:3424 +3663:3425 +3664:3426 +3665:3427 +3666:3428 +3667:3429 +3668:3430 +3669:3431 +3670:3432 +3671:3433 +3672:3434 +3673:3435 +3674:3436 +3675:3437 +3676:3438 +3677:3439 +3678:3440 +3679:3441 +3680:3442 +3681:3443 +3682:3444 +3683:3445 +3684:3446 +3685:3447 +3686:3448 +3687:zeroinfnan +3688:xyz_almost_equal\28skcms_Matrix3x3\20const&\2c\20skcms_Matrix3x3\20const&\29 +3689:wuffs_lzw__decoder__transform_io +3690:wuffs_gif__decoder__set_quirk_enabled +3691:wuffs_gif__decoder__restart_frame +3692:wuffs_gif__decoder__num_animation_loops +3693:wuffs_gif__decoder__frame_dirty_rect +3694:wuffs_gif__decoder__decode_up_to_id_part1 +3695:wuffs_gif__decoder__decode_frame +3696:write_vertex_position\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrShaderVar\20const&\2c\20SkMatrix\20const&\2c\20char\20const*\2c\20GrShaderVar*\2c\20GrResourceHandle*\29 +3697:write_passthrough_vertex_position\28GrGLSLVertexBuilder*\2c\20GrShaderVar\20const&\2c\20GrShaderVar*\29 +3698:write_buf +3699:wctomb +3700:wchar_t*\20std::__2::copy\5babi:nn180100\5d\2c\20wchar_t*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20wchar_t*\29 +3701:wchar_t*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20std::__2::__element_count\29 +3702:walk_simple_edges\28SkEdge*\2c\20SkBlitter*\2c\20int\2c\20int\29 +3703:vsscanf +3704:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20long\29 +3705:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28SkString*\2c\20SkString*\2c\20long\29 +3706:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28SkFontArguments::VariationPosition::Coordinate*\2c\20SkFontArguments::VariationPosition::Coordinate*\2c\20long\29 +3707:void\20std::__2::basic_string\2c\20std::__2::allocator>::__init\28wchar_t\20const*\2c\20wchar_t\20const*\29 +3708:void\20std::__2::basic_string\2c\20std::__2::allocator>::__init\28char*\2c\20char*\29 +3709:void\20std::__2::__tree_balance_after_insert\5babi:ne180100\5d*>\28std::__2::__tree_node_base*\2c\20std::__2::__tree_node_base*\29 +3710:void\20std::__2::__stable_sort_move\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\29 +3711:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +3712:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\29 +3713:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +3714:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +3715:void\20std::__2::__sift_up\5babi:ne180100\5d*>>\28std::__2::__wrap_iter*>\2c\20std::__2::__wrap_iter*>\2c\20GrGeometryProcessor::ProgramImpl::emitTransformCode\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\29::$_0&\2c\20std::__2::iterator_traits*>>::difference_type\29 +3716:void\20std::__2::__optional_storage_base::__assign_from\5babi:ne180100\5d\20const&>\28std::__2::__optional_copy_assign_base\20const&\29 +3717:void\20std::__2::__introsort\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +3718:void\20std::__2::__introsort\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\2c\20std::__2::iterator_traits<\28anonymous\20namespace\29::Entry*>::difference_type\2c\20bool\29 +3719:void\20std::__2::__introsort\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +3720:void\20std::__2::__introsort\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +3721:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20char*&\2c\20char*&\29 +3722:void\20sorted_merge<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +3723:void\20sorted_merge<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +3724:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29_15609 +3725:void\20skgpu::ganesh::SurfaceFillContext::clear<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\20const&\29 +3726:void\20hair_path<\28SkPaint::Cap\292>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3727:void\20hair_path<\28SkPaint::Cap\291>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3728:void\20hair_path<\28SkPaint::Cap\290>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3729:void\20emscripten::internal::raw_destructor>\28sk_sp*\29 +3730:void\20emscripten::internal::MemberAccess>::setWire\28sk_sp\20SkRuntimeEffect::TracedShader::*\20const&\2c\20SkRuntimeEffect::TracedShader&\2c\20sk_sp*\29 +3731:void\20emscripten::internal::MemberAccess::setWire\28SimpleFontStyle\20SimpleStrutStyle::*\20const&\2c\20SimpleStrutStyle&\2c\20SimpleFontStyle*\29 +3732:void\20\28anonymous\20namespace\29::copyFT2LCD16\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\29 +3733:void\20SkTIntroSort\28int\2c\20int*\2c\20int\2c\20DistanceLessThan\20const&\29 +3734:void\20SkTIntroSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29>\28int\2c\20float*\2c\20int\2c\20void\20SkTQSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29\20const&\29 +3735:void\20SkTIntroSort\28int\2c\20SkString*\2c\20int\2c\20bool\20\20const\28&\29\28SkString\20const&\2c\20SkString\20const&\29\29 +3736:void\20SkTIntroSort\28int\2c\20SkOpRayHit**\2c\20int\2c\20bool\20\20const\28&\29\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29\29 +3737:void\20SkTIntroSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29>\28int\2c\20SkOpContour*\2c\20int\2c\20void\20SkTQSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29\20const&\29 +3738:void\20SkTIntroSort>\2c\20SkCodec::Result*\29::Entry\2c\20SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29::EntryLessThan>\28int\2c\20SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29::Entry*\2c\20int\2c\20SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29::EntryLessThan\20const&\29 +3739:void\20SkTIntroSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29>\28int\2c\20SkClosestRecord\20const*\2c\20int\2c\20void\20SkTQSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29\20const&\29 +3740:void\20SkTIntroSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29>\28int\2c\20SkAnalyticEdge*\2c\20int\2c\20void\20SkTQSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29\20const&\29 +3741:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\20const\28&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +3742:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\28*\20const&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +3743:void\20SkTIntroSort\28int\2c\20Edge*\2c\20int\2c\20EdgeLT\20const&\29 +3744:void\20AAT::StateTableDriver::drive::driver_context_t>\28AAT::LigatureSubtable::driver_context_t*\2c\20AAT::hb_aat_apply_context_t*\29::'lambda0'\28\29::operator\28\29\28\29\20const +3745:virtual\20thunk\20to\20GrGLTexture::onSetLabel\28\29 +3746:virtual\20thunk\20to\20GrGLTexture::backendFormat\28\29\20const +3747:vfiprintf +3748:validate_texel_levels\28SkISize\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20GrCaps\20const*\29 +3749:utf8TextClose\28UText*\29 +3750:utf8TextAccess\28UText*\2c\20long\20long\2c\20signed\20char\29 +3751:utext_openConstUnicodeString_74 +3752:utext_moveIndex32_74 +3753:utext_getPreviousNativeIndex_74 +3754:utext_extract_74 +3755:ustrcase_mapWithOverlap_74 +3756:ures_resetIterator_74 +3757:ures_initStackObject_74 +3758:ures_getInt_74 +3759:ures_getIntVector_74 +3760:ures_copyResb_74 +3761:uprv_stricmp_74 +3762:uprv_getMaxValues_74 +3763:uprv_compareInvAscii_74 +3764:upropsvec_addPropertyStarts_74 +3765:uprops_getSource_74 +3766:uprops_addPropertyStarts_74 +3767:unsigned\20short\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3768:unsigned\20long\20long\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3769:unsigned\20long\20const&\20std::__2::min\5babi:nn180100\5d\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29 +3770:unsigned\20int\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3771:unsigned\20int\20const*\20std::__2::lower_bound\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20unsigned\20long\20const&\29 +3772:unorm_getFCD16_74 +3773:ultag_isUnicodeLocaleKey_74 +3774:ultag_isScriptSubtag_74 +3775:ultag_isLanguageSubtag_74 +3776:ultag_isExtensionSubtags_74 +3777:ultag_getTKeyStart_74 +3778:ulocimp_toBcpType_74 +3779:uloc_toUnicodeLocaleType_74 +3780:uloc_toUnicodeLocaleKey_74 +3781:uloc_setKeywordValue_74 +3782:uloc_getTableStringWithFallback_74 +3783:uloc_getScript_74 +3784:uloc_getName_74 +3785:uloc_getLanguage_74 +3786:uloc_getDisplayName_74 +3787:uloc_getCountry_74 +3788:uloc_canonicalize_74 +3789:uenum_unext_74 +3790:udata_open_74 +3791:udata_checkCommonData_74 +3792:ucptrie_internalU8PrevIndex_74 +3793:uchar_addPropertyStarts_74 +3794:ucase_toFullUpper_74 +3795:ucase_toFullLower_74 +3796:ucase_toFullFolding_74 +3797:ucase_getTypeOrIgnorable_74 +3798:ucase_addPropertyStarts_74 +3799:ubidi_getPairedBracketType_74 +3800:ubidi_close_74 +3801:u_unescapeAt_74 +3802:u_strFindFirst_74 +3803:u_memrchr_74 +3804:u_memmove_74 +3805:u_memcmp_74 +3806:u_hasBinaryProperty_74 +3807:u_getPropertyEnum_74 +3808:tt_size_run_prep +3809:tt_size_done_bytecode +3810:tt_sbit_decoder_load_image +3811:tt_face_vary_cvt +3812:tt_face_palette_set +3813:tt_face_load_cvt +3814:tt_face_get_metrics +3815:tt_done_blend +3816:tt_delta_interpolate +3817:tt_cmap4_next +3818:tt_cmap4_char_map_linear +3819:tt_cmap4_char_map_binary +3820:tt_cmap14_get_def_chars +3821:tt_cmap13_next +3822:tt_cmap12_next +3823:tt_cmap12_init +3824:tt_cmap12_char_map_binary +3825:tt_apply_mvar +3826:toParagraphStyle\28SimpleParagraphStyle\20const&\29 +3827:toBytes\28sk_sp\29 +3828:tanhf +3829:t1_lookup_glyph_by_stdcharcode_ps +3830:t1_builder_close_contour +3831:t1_builder_check_points +3832:strtoull +3833:strtoll_l +3834:strtol +3835:strspn +3836:stream_close +3837:store_int +3838:std::logic_error::~logic_error\28\29 +3839:std::logic_error::logic_error\28char\20const*\29 +3840:std::exception::exception\5babi:nn180100\5d\28\29 +3841:std::__2::vector>::max_size\28\29\20const +3842:std::__2::vector>::capacity\5babi:nn180100\5d\28\29\20const +3843:std::__2::vector>::__construct_at_end\28unsigned\20long\29 +3844:std::__2::vector>::__clear\5babi:nn180100\5d\28\29 +3845:std::__2::vector>::__base_destruct_at_end\5babi:nn180100\5d\28std::__2::locale::facet**\29 +3846:std::__2::vector>::insert\28std::__2::__wrap_iter\2c\20float&&\29 +3847:std::__2::vector>::__append\28unsigned\20long\29 +3848:std::__2::unique_ptr::operator=\5babi:nn180100\5d\28std::__2::unique_ptr&&\29 +3849:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3850:std::__2::unique_ptr>::operator=\5babi:ne180100\5d\28std::nullptr_t\29 +3851:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkCanvas::Layer*\29 +3852:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda0'\28\29::operator\28\29\28\29\20const +3853:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +3854:std::__2::to_string\28unsigned\20long\29 +3855:std::__2::to_chars_result\20std::__2::__to_chars_itoa\5babi:nn180100\5d\28char*\2c\20char*\2c\20unsigned\20int\2c\20std::__2::integral_constant\29 +3856:std::__2::time_put>>::~time_put\28\29 +3857:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3858:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3859:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3860:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3861:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3862:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3863:std::__2::reverse_iterator::operator++\5babi:nn180100\5d\28\29 +3864:std::__2::reverse_iterator::operator*\5babi:nn180100\5d\28\29\20const +3865:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t*\29\20const +3866:std::__2::pair\2c\20void*>*>\2c\20bool>\20std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__emplace_unique_key_args\2c\20std::__2::tuple<>>\28GrFragmentProcessor\20const*\20const&\2c\20std::__2::piecewise_construct_t\20const&\2c\20std::__2::tuple&&\2c\20std::__2::tuple<>&&\29 +3867:std::__2::pair*>\2c\20bool>\20std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__emplace_unique_key_args\28int\20const&\2c\20int\20const&\29 +3868:std::__2::pair\2c\20std::__2::allocator>>>::pair\5babi:ne180100\5d\28std::__2::pair\2c\20std::__2::allocator>>>&&\29 +3869:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +3870:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28wchar_t\29 +3871:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28char\29 +3872:std::__2::optional&\20std::__2::optional::operator=\5babi:ne180100\5d\28SkPath\20const&\29 +3873:std::__2::numpunct::~numpunct\28\29 +3874:std::__2::numpunct::~numpunct\28\29 +3875:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +3876:std::__2::num_get>>\20const&\20std::__2::use_facet\5babi:nn180100\5d>>>\28std::__2::locale\20const&\29 +3877:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +3878:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3879:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3880:std::__2::moneypunct::do_negative_sign\28\29\20const +3881:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3882:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3883:std::__2::moneypunct::do_negative_sign\28\29\20const +3884:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20wchar_t*&\2c\20wchar_t*\29 +3885:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20char*&\2c\20char*\29 +3886:std::__2::locale::facet**\20std::__2::__construct_at\5babi:nn180100\5d\28std::__2::locale::facet**\29 +3887:std::__2::locale::__imp::~__imp\28\29 +3888:std::__2::locale::__imp::release\28\29 +3889:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20std::__2::random_access_iterator_tag\29 +3890:std::__2::iterator_traits\2c\20std::__2::allocator>\20const*>::difference_type\20std::__2::distance\5babi:nn180100\5d\2c\20std::__2::allocator>\20const*>\28std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +3891:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28char*\2c\20char*\29 +3892:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::random_access_iterator_tag\29 +3893:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +3894:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +3895:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +3896:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +3897:std::__2::ios_base::width\5babi:nn180100\5d\28long\29 +3898:std::__2::ios_base::imbue\28std::__2::locale\20const&\29 +3899:std::__2::ios_base::__call_callbacks\28std::__2::ios_base::event\29 +3900:std::__2::hash::operator\28\29\28skia::textlayout::FontArguments\20const&\29\20const +3901:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d\28char&\2c\20char&\29 +3902:std::__2::deque>::__add_back_capacity\28\29 +3903:std::__2::default_delete::operator\28\29\5babi:ne180100\5d\28sktext::GlyphRunBuilder*\29\20const +3904:std::__2::default_delete\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot>::type\20std::__2::default_delete\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot>\28skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot*\29\20const +3905:std::__2::default_delete\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot>::type\20std::__2::default_delete\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot>\28skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot*\29\20const +3906:std::__2::ctype::~ctype\28\29 +3907:std::__2::codecvt::~codecvt\28\29 +3908:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +3909:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char32_t\20const*\2c\20char32_t\20const*\2c\20char32_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +3910:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +3911:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char32_t*\2c\20char32_t*\2c\20char32_t*&\29\20const +3912:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +3913:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +3914:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char16_t*\2c\20char16_t*\2c\20char16_t*&\29\20const +3915:std::__2::char_traits::not_eof\5babi:nn180100\5d\28int\29 +3916:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28\29\20const +3917:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29 +3918:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +3919:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20wchar_t\20const*\29 +3920:std::__2::basic_string\2c\20std::__2::allocator>::resize\28unsigned\20long\2c\20char\29 +3921:std::__2::basic_string\2c\20std::__2::allocator>::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +3922:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20char\29 +3923:std::__2::basic_string\2c\20std::__2::allocator>::basic_string>\2c\200>\28std::__2::basic_string_view>\20const&\29 +3924:std::__2::basic_string\2c\20std::__2::allocator>::__null_terminate_at\5babi:nn180100\5d\28char*\2c\20unsigned\20long\29 +3925:std::__2::basic_string\2c\20std::__2::allocator>&\20std::__2::basic_string\2c\20std::__2::allocator>::__assign_no_alias\28char\20const*\2c\20unsigned\20long\29 +3926:std::__2::basic_string\2c\20std::__2::allocator>&\20skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::emplace_back\28char\20const*&&\29 +3927:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +3928:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +3929:std::__2::basic_streambuf>::sputc\5babi:nn180100\5d\28char\29 +3930:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +3931:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +3932:std::__2::basic_ostream>::~basic_ostream\28\29_17536 +3933:std::__2::basic_ostream>::sentry::~sentry\28\29 +3934:std::__2::basic_ostream>::sentry::sentry\28std::__2::basic_ostream>&\29 +3935:std::__2::basic_ostream>::operator<<\28float\29 +3936:std::__2::basic_ostream>::flush\28\29 +3937:std::__2::basic_istream>::~basic_istream\28\29_17495 +3938:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::__sso_allocator&\2c\20std::__2::locale::facet**\2c\20unsigned\20long\29 +3939:std::__2::allocator::deallocate\5babi:nn180100\5d\28wchar_t*\2c\20unsigned\20long\29 +3940:std::__2::allocator::allocate\5babi:nn180100\5d\28unsigned\20long\29 +3941:std::__2::allocator::allocate\5babi:nn180100\5d\28unsigned\20long\29 +3942:std::__2::__wrap_iter\20std::__2::vector>::__insert_with_size\5babi:ne180100\5d>\2c\20std::__2::reverse_iterator>>\28std::__2::__wrap_iter\2c\20std::__2::reverse_iterator>\2c\20std::__2::reverse_iterator>\2c\20long\29 +3943:std::__2::__wrap_iter\20std::__2::vector>::__insert_with_size\5babi:ne180100\5d\2c\20std::__2::__wrap_iter>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20long\29 +3944:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +3945:std::__2::__time_put::__time_put\5babi:nn180100\5d\28\29 +3946:std::__2::__time_put::__do_put\28char*\2c\20char*&\2c\20tm\20const*\2c\20char\2c\20char\29\20const +3947:std::__2::__split_buffer>::push_back\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +3948:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3949:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +3950:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +3951:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +3952:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +3953:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20wchar_t&\2c\20wchar_t&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +3954:std::__2::__money_put::__format\28wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20unsigned\20int\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +3955:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20char&\2c\20char&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +3956:std::__2::__money_put::__format\28char*\2c\20char*&\2c\20char*&\2c\20unsigned\20int\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +3957:std::__2::__libcpp_sscanf_l\28char\20const*\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +3958:std::__2::__libcpp_mbrtowc_l\5babi:nn180100\5d\28wchar_t*\2c\20char\20const*\2c\20unsigned\20long\2c\20__mbstate_t*\2c\20__locale_struct*\29 +3959:std::__2::__libcpp_mb_cur_max_l\5babi:nn180100\5d\28__locale_struct*\29 +3960:std::__2::__libcpp_deallocate\5babi:nn180100\5d\28void*\2c\20unsigned\20long\2c\20unsigned\20long\29 +3961:std::__2::__libcpp_allocate\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\29 +3962:std::__2::__is_overaligned_for_new\5babi:nn180100\5d\28unsigned\20long\29 +3963:std::__2::__function::__value_func::swap\5babi:ne180100\5d\28std::__2::__function::__value_func&\29 +3964:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +3965:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +3966:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +3967:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::destroy\28\29 +3968:std::__2::__constexpr_wcslen\5babi:nn180100\5d\28wchar_t\20const*\29 +3969:std::__2::__compressed_pair_elem\2c\20std::__2::allocator>::__rep\2c\200\2c\20false>::__compressed_pair_elem\5babi:nn180100\5d\28std::__2::__value_init_tag\29 +3970:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::__sso_allocator&\2c\20unsigned\20long\29 +3971:start_input_pass +3972:sktext::gpu::can_use_direct\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +3973:sktext::gpu::build_distance_adjust_table\28float\29 +3974:sktext::gpu::VertexFiller::opMaskType\28\29\20const +3975:sktext::gpu::VertexFiller::isLCD\28\29\20const +3976:sktext::gpu::VertexFiller::fillVertexData\28int\2c\20int\2c\20SkSpan\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkIRect\2c\20void*\29\20const +3977:sktext::gpu::TextBlobRedrawCoordinator::internalRemove\28sktext::gpu::TextBlob*\29 +3978:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_2::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +3979:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_0::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +3980:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29 +3981:sktext::gpu::SubRunContainer::EstimateAllocSize\28sktext::GlyphRunList\20const&\29 +3982:sktext::gpu::SubRunAllocator::SubRunAllocator\28char*\2c\20int\2c\20int\29 +3983:sktext::gpu::StrikeCache::~StrikeCache\28\29 +3984:sktext::gpu::SlugImpl::Make\28SkMatrix\20const&\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\29 +3985:sktext::gpu::BagOfBytes::BagOfBytes\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29::$_1::operator\28\29\28\29\20const +3986:sktext::glyphrun_source_bounds\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkZip\2c\20SkSpan\29 +3987:sktext::SkStrikePromise::resetStrike\28\29 +3988:sktext::GlyphRunList::makeBlob\28\29\20const +3989:sktext::GlyphRunBuilder::blobToGlyphRunList\28SkTextBlob\20const&\2c\20SkPoint\29 +3990:sktext::GlyphRun*\20std::__2::vector>::__emplace_back_slow_path&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&>\28SkFont\20const&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\29 +3991:skstd::to_string\28float\29 +3992:skpathutils::FillPathWithPaint\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkPath*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29 +3993:skjpeg_err_exit\28jpeg_common_struct*\29 +3994:skip_string +3995:skip_procedure +3996:skif::\28anonymous\20namespace\29::decompose_transform\28SkMatrix\20const&\2c\20SkPoint\2c\20SkMatrix*\2c\20SkMatrix*\29 +3997:skif::Mapping::adjustLayerSpace\28SkMatrix\20const&\29 +3998:skif::FilterResult::imageAndOffset\28skif::Context\20const&\29\20const +3999:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20SkBlender\20const*\29\20const +4000:skif::FilterResult::MakeFromImage\28skif::Context\20const&\2c\20sk_sp\2c\20SkRect\2c\20skif::ParameterSpace\2c\20SkSamplingOptions\20const&\29 +4001:skif::FilterResult::FilterResult\28sk_sp\2c\20skif::LayerSpace\20const&\29 +4002:skif::Context::withNewSource\28skif::FilterResult\20const&\29\20const +4003:skia_private::THashTable::Traits>::set\28unsigned\20long\20long\29 +4004:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::set\28std::__2::basic_string_view>\29 +4005:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::resize\28int\29 +4006:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4007:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::removeSlot\28int\29 +4008:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::resize\28int\29 +4009:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair&&\29 +4010:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair&&\29 +4011:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4012:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\29 +4013:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::operator=\28skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>\20const&\29 +4014:skia_private::THashTable::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4015:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair&&\29 +4016:skia_private::THashTable::Pair\2c\20SkSL::Analysis::SpecializedCallKey\2c\20skia_private::THashMap::Pair>::set\28skia_private::THashMap::Pair\29 +4017:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4018:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4019:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::resize\28int\29 +4020:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28skgpu::ganesh::SmallPathShapeData*&&\29 +4021:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4022:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::resize\28int\29 +4023:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::resize\28int\29 +4024:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::uncheckedSet\28\28anonymous\20namespace\29::CacheImpl::Value*&&\29 +4025:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::resize\28int\29 +4026:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +4027:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +4028:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +4029:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +4030:skia_private::THashTable::resize\28int\29 +4031:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::removeIfExists\28unsigned\20int\20const&\29 +4032:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +4033:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::uncheckedSet\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*&&\29 +4034:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +4035:skia_private::THashTable::AdaptedTraits>::set\28GrThreadSafeCache::Entry*\29 +4036:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4037:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +4038:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4039:skia_private::THashTable::Traits>::resize\28int\29 +4040:skia_private::THashSet::add\28FT_Opaque_Paint_\29 +4041:skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +4042:skia_private::THashMap>\2c\20SkGoodHash>::remove\28SkImageFilter\20const*\20const&\29 +4043:skia_private::TArray::push_back_raw\28int\29 +4044:skia_private::TArray::resize_back\28int\29 +4045:skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::checkRealloc\28int\2c\20double\29 +4046:skia_private::TArray::~TArray\28\29 +4047:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4048:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4049:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4050:skia_private::TArray::BufferFinishedMessage\2c\20false>::operator=\28skia_private::TArray::BufferFinishedMessage\2c\20false>&&\29 +4051:skia_private::TArray::BufferFinishedMessage\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +4052:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4053:skia_private::TArray\29::ReorderedArgument\2c\20false>::push_back\28SkSL::optimize_constructor_swizzle\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ConstructorCompound\20const&\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29::ReorderedArgument&&\29 +4054:skia_private::TArray::TArray\28skia_private::TArray&&\29 +4055:skia_private::TArray::swap\28skia_private::TArray&\29 +4056:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +4057:skia_private::TArray::push_back_raw\28int\29 +4058:skia_private::TArray::push_back_raw\28int\29 +4059:skia_private::TArray::push_back_raw\28int\29 +4060:skia_private::TArray::move_back_n\28int\2c\20GrTextureProxy**\29 +4061:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4062:skia_private::TArray::push_back_n\28int\2c\20EllipticalRRectOp::RRect\20const*\29 +4063:skia_png_zfree +4064:skia_png_write_zTXt +4065:skia_png_write_tIME +4066:skia_png_write_tEXt +4067:skia_png_write_iTXt +4068:skia_png_set_write_fn +4069:skia_png_set_unknown_chunks +4070:skia_png_set_strip_16 +4071:skia_png_set_read_user_transform_fn +4072:skia_png_set_read_user_chunk_fn +4073:skia_png_set_option +4074:skia_png_set_mem_fn +4075:skia_png_set_expand_gray_1_2_4_to_8 +4076:skia_png_set_error_fn +4077:skia_png_set_compression_level +4078:skia_png_set_IHDR +4079:skia_png_read_filter_row +4080:skia_png_process_IDAT_data +4081:skia_png_icc_set_sRGB +4082:skia_png_icc_check_tag_table +4083:skia_png_icc_check_header +4084:skia_png_get_uint_31 +4085:skia_png_get_sBIT +4086:skia_png_get_rowbytes +4087:skia_png_get_error_ptr +4088:skia_png_get_IHDR +4089:skia_png_do_swap +4090:skia_png_do_read_transformations +4091:skia_png_do_read_interlace +4092:skia_png_do_packswap +4093:skia_png_do_invert +4094:skia_png_do_gray_to_rgb +4095:skia_png_do_expand +4096:skia_png_do_check_palette_indexes +4097:skia_png_do_bgr +4098:skia_png_destroy_png_struct +4099:skia_png_destroy_gamma_table +4100:skia_png_create_png_struct +4101:skia_png_create_info_struct +4102:skia_png_crc_read +4103:skia_png_colorspace_sync_info +4104:skia_png_check_IHDR +4105:skia::textlayout::TypefaceFontStyleSet::matchStyle\28SkFontStyle\20const&\29 +4106:skia::textlayout::TextStyle::matchOneAttribute\28skia::textlayout::StyleType\2c\20skia::textlayout::TextStyle\20const&\29\20const +4107:skia::textlayout::TextStyle::equals\28skia::textlayout::TextStyle\20const&\29\20const +4108:skia::textlayout::TextShadow::operator!=\28skia::textlayout::TextShadow\20const&\29\20const +4109:skia::textlayout::TextLine::paint\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\29 +4110:skia::textlayout::TextLine::iterateThroughClustersInGlyphsOrder\28bool\2c\20bool\2c\20std::__2::function\20const&\29\20const::$_0::operator\28\29\28unsigned\20long\20const&\29\20const +4111:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkRect\29::operator\28\29\28SkRect\29\20const +4112:skia::textlayout::TextLine::getMetrics\28\29\20const +4113:skia::textlayout::TextLine::ensureTextBlobCachePopulated\28\29 +4114:skia::textlayout::TextLine::buildTextBlob\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +4115:skia::textlayout::TextLine::TextLine\28skia::textlayout::ParagraphImpl*\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20skia::textlayout::InternalLineMetrics\29 +4116:skia::textlayout::TextLine&\20skia_private::TArray::emplace_back&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&>\28skia::textlayout::ParagraphImpl*&&\2c\20SkPoint&\2c\20SkPoint&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&\29 +4117:skia::textlayout::Run::shift\28skia::textlayout::Cluster\20const*\2c\20float\29 +4118:skia::textlayout::Run::newRunBuffer\28\29 +4119:skia::textlayout::Run::findLimitingGlyphClusters\28skia::textlayout::SkRange\29\20const +4120:skia::textlayout::Run::addSpacesAtTheEnd\28float\2c\20skia::textlayout::Cluster*\29 +4121:skia::textlayout::ParagraphStyle::effective_align\28\29\20const +4122:skia::textlayout::ParagraphStyle::ParagraphStyle\28\29 +4123:skia::textlayout::ParagraphPainter::DecorationStyle::DecorationStyle\28unsigned\20int\2c\20float\2c\20std::__2::optional\29 +4124:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29 +4125:skia::textlayout::ParagraphImpl::text\28skia::textlayout::SkRange\29 +4126:skia::textlayout::ParagraphImpl::resolveStrut\28\29 +4127:skia::textlayout::ParagraphImpl::getGlyphInfoAtUTF16Offset\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +4128:skia::textlayout::ParagraphImpl::getGlyphClusterAt\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +4129:skia::textlayout::ParagraphImpl::findPreviousGraphemeBoundary\28unsigned\20long\29\20const +4130:skia::textlayout::ParagraphImpl::computeEmptyMetrics\28\29 +4131:skia::textlayout::ParagraphImpl::clusters\28skia::textlayout::SkRange\29 +4132:skia::textlayout::ParagraphImpl::block\28unsigned\20long\29 +4133:skia::textlayout::ParagraphCacheValue::~ParagraphCacheValue\28\29 +4134:skia::textlayout::ParagraphCacheKey::ParagraphCacheKey\28skia::textlayout::ParagraphImpl\20const*\29 +4135:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29 +4136:skia::textlayout::ParagraphBuilderImpl::make\28skia::textlayout::ParagraphStyle\20const&\2c\20sk_sp\2c\20sk_sp\29 +4137:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\2c\20bool\29 +4138:skia::textlayout::ParagraphBuilderImpl::ParagraphBuilderImpl\28skia::textlayout::ParagraphStyle\20const&\2c\20sk_sp\2c\20sk_sp\29 +4139:skia::textlayout::Paragraph::~Paragraph\28\29 +4140:skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29 +4141:skia::textlayout::FontCollection::~FontCollection\28\29 +4142:skia::textlayout::FontCollection::matchTypeface\28SkString\20const&\2c\20SkFontStyle\29 +4143:skia::textlayout::FontCollection::defaultFallback\28int\2c\20SkFontStyle\2c\20SkString\20const&\29 +4144:skia::textlayout::FontCollection::FamilyKey::Hasher::operator\28\29\28skia::textlayout::FontCollection::FamilyKey\20const&\29\20const +4145:skgpu::tess::\28anonymous\20namespace\29::write_curve_index_buffer_base_index\28skgpu::VertexWriter\2c\20unsigned\20long\2c\20unsigned\20short\29 +4146:skgpu::tess::StrokeIterator::next\28\29 +4147:skgpu::tess::StrokeIterator::finishOpenContour\28\29 +4148:skgpu::tess::PreChopPathCurves\28float\2c\20SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +4149:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29 +4150:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::SmallPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20GrUserStencilSettings\20const*\29 +4151:skgpu::ganesh::\28anonymous\20namespace\29::ChopPathIfNecessary\28SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkStrokeRec\20const&\2c\20SkPath*\29 +4152:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::recordDraw\28GrMeshDrawTarget*\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20int\2c\20unsigned\20short*\29 +4153:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::AAFlatteningConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20float\2c\20SkStrokeRec::Style\2c\20SkPaint::Join\2c\20float\2c\20GrUserStencilSettings\20const*\29 +4154:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::AAConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrUserStencilSettings\20const*\29 +4155:skgpu::ganesh::TextureOp::Make\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20SkBlendMode\2c\20GrAAType\2c\20DrawQuad*\2c\20SkRect\20const*\29 +4156:skgpu::ganesh::TessellationPathRenderer::IsSupported\28GrCaps\20const&\29 +4157:skgpu::ganesh::SurfaceFillContext::fillRectToRectWithFP\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +4158:skgpu::ganesh::SurfaceFillContext::blitTexture\28GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\29 +4159:skgpu::ganesh::SurfaceFillContext::addOp\28std::__2::unique_ptr>\29 +4160:skgpu::ganesh::SurfaceFillContext::addDrawOp\28std::__2::unique_ptr>\29 +4161:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29_10063 +4162:skgpu::ganesh::SurfaceDrawContext::drawVertices\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20sk_sp\2c\20GrPrimitiveType*\2c\20bool\29 +4163:skgpu::ganesh::SurfaceDrawContext::drawTexturedQuad\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkBlendMode\2c\20DrawQuad*\2c\20SkRect\20const*\29 +4164:skgpu::ganesh::SurfaceDrawContext::drawTexture\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkBlendMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +4165:skgpu::ganesh::SurfaceDrawContext::drawStrokedLine\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPoint\20const*\2c\20SkStrokeRec\20const&\29 +4166:skgpu::ganesh::SurfaceDrawContext::drawRegion\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrStyle\20const&\2c\20GrUserStencilSettings\20const*\29 +4167:skgpu::ganesh::SurfaceDrawContext::drawOval\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\29 +4168:skgpu::ganesh::SurfaceDrawContext::SurfaceDrawContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +4169:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29 +4170:skgpu::ganesh::SurfaceContext::writePixels\28GrDirectContext*\2c\20GrCPixmap\2c\20SkIPoint\29 +4171:skgpu::ganesh::SurfaceContext::copy\28sk_sp\2c\20SkIRect\2c\20SkIPoint\29 +4172:skgpu::ganesh::SurfaceContext::copyScaled\28sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20SkFilterMode\29 +4173:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +4174:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::FinishContext::~FinishContext\28\29 +4175:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +4176:skgpu::ganesh::SurfaceContext::SurfaceContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +4177:skgpu::ganesh::StrokeTessellator::draw\28GrOpFlushState*\29\20const +4178:skgpu::ganesh::StrokeTessellateOp::prePrepareTessellator\28GrTessellationShader::ProgramArgs&&\2c\20GrAppliedClip&&\29 +4179:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::NonAAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrSimpleMeshDrawOpHelper::InputFlags\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\2c\20GrAAType\29 +4180:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::AAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::RectInfo\20const&\2c\20bool\29 +4181:skgpu::ganesh::StencilMaskHelper::drawShape\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20SkRegion::Op\2c\20GrAA\29 +4182:skgpu::ganesh::SoftwarePathRenderer::DrawAroundInvPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29 +4183:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11557 +4184:skgpu::ganesh::SmallPathAtlasMgr::findOrCreate\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +4185:skgpu::ganesh::SmallPathAtlasMgr::deleteCacheEntry\28skgpu::ganesh::SmallPathShapeData*\29 +4186:skgpu::ganesh::ShadowRRectOp::Make\28GrRecordingContext*\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20float\2c\20float\29 +4187:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::RegionOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +4188:skgpu::ganesh::RasterAsView\28GrRecordingContext*\2c\20SkImage_Raster\20const*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +4189:skgpu::ganesh::QuadPerEdgeAA::Tessellator::append\28GrQuad*\2c\20GrQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\29 +4190:skgpu::ganesh::QuadPerEdgeAA::Tessellator::Tessellator\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29 +4191:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::initializeAttrs\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29 +4192:skgpu::ganesh::QuadPerEdgeAA::IssueDraw\28GrCaps\20const&\2c\20GrOpsRenderPass*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +4193:skgpu::ganesh::QuadPerEdgeAA::GetIndexBuffer\28GrMeshDrawTarget*\2c\20skgpu::ganesh::QuadPerEdgeAA::IndexBufferOption\29 +4194:skgpu::ganesh::PathTessellateOp::usesMSAA\28\29\20const +4195:skgpu::ganesh::PathTessellateOp::prepareTessellator\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +4196:skgpu::ganesh::PathTessellateOp::PathTessellateOp\28SkArenaAlloc*\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\2c\20SkRect\20const&\29 +4197:skgpu::ganesh::PathStencilCoverOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +4198:skgpu::ganesh::PathInnerTriangulateOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +4199:skgpu::ganesh::PathCurveTessellator::~PathCurveTessellator\28\29 +4200:skgpu::ganesh::PathCurveTessellator::prepareWithTriangles\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20GrTriangulator::BreadcrumbTriangleList*\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +4201:skgpu::ganesh::OpsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +4202:skgpu::ganesh::OpsTask::onExecute\28GrOpFlushState*\29 +4203:skgpu::ganesh::OpsTask::addOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +4204:skgpu::ganesh::OpsTask::addDrawOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +4205:skgpu::ganesh::OpsTask::OpsTask\28GrDrawingManager*\2c\20GrSurfaceProxyView\2c\20GrAuditTrail*\2c\20sk_sp\29 +4206:skgpu::ganesh::OpsTask::OpChain::tryConcat\28skgpu::ganesh::OpsTask::OpChain::List*\2c\20GrProcessorSet::Analysis\2c\20GrDstProxyView\20const&\2c\20GrAppliedClip\20const*\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrAuditTrail*\29 +4207:skgpu::ganesh::MakeFragmentProcessorFromView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +4208:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29 +4209:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29 +4210:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::NonAALatticeOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20std::__2::unique_ptr>\2c\20SkRect\20const&\29 +4211:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20GrAA\29 +4212:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::FillRRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29 +4213:skgpu::ganesh::DrawAtlasPathOp::prepareProgram\28GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +4214:skgpu::ganesh::Device::replaceBackingProxy\28SkSurface::ContentChangeMode\2c\20sk_sp\2c\20GrColorType\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +4215:skgpu::ganesh::Device::makeSpecial\28SkBitmap\20const&\29 +4216:skgpu::ganesh::Device::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +4217:skgpu::ganesh::Device::drawEdgeAAImage\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20SkTileMode\29 +4218:skgpu::ganesh::Device::discard\28\29 +4219:skgpu::ganesh::Device::android_utils_clipAsRgn\28SkRegion*\29\20const +4220:skgpu::ganesh::DefaultPathRenderer::internalDrawPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20bool\29 +4221:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +4222:skgpu::ganesh::CopyView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\2c\20std::__2::basic_string_view>\29 +4223:skgpu::ganesh::ClipStack::clipPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrAA\2c\20SkClipOp\29 +4224:skgpu::ganesh::ClipStack::SaveRecord::replaceWithElement\28skgpu::ganesh::ClipStack::RawElement&&\2c\20SkTBlockList*\29 +4225:skgpu::ganesh::ClipStack::SaveRecord::addElement\28skgpu::ganesh::ClipStack::RawElement&&\2c\20SkTBlockList*\29 +4226:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::Draw\20const&\29\20const +4227:skgpu::ganesh::AtlasTextOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +4228:skgpu::ganesh::AtlasTextOp::AtlasTextOp\28skgpu::ganesh::AtlasTextOp::MaskType\2c\20bool\2c\20int\2c\20SkRect\2c\20skgpu::ganesh::AtlasTextOp::Geometry*\2c\20GrColorInfo\20const&\2c\20GrPaint&&\29 +4229:skgpu::ganesh::AtlasRenderTask::stencilAtlasRect\28GrRecordingContext*\2c\20SkRect\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrUserStencilSettings\20const*\29 +4230:skgpu::ganesh::AtlasRenderTask::addPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIPoint\2c\20int\2c\20int\2c\20bool\2c\20SkIPoint16*\29 +4231:skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +4232:skgpu::ganesh::AtlasPathRenderer::addPathToAtlas\28GrRecordingContext*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRect\20const&\2c\20SkIRect*\2c\20SkIPoint16*\2c\20bool*\2c\20std::__2::function\20const&\29 +4233:skgpu::ganesh::AsFragmentProcessor\28GrRecordingContext*\2c\20SkImage\20const*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +4234:skgpu::TiledTextureUtils::OptimizeSampleArea\28SkISize\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkRect*\2c\20SkRect*\2c\20SkMatrix*\29 +4235:skgpu::TClientMappedBufferManager::process\28\29 +4236:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29 +4237:skgpu::RectanizerSkyline::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +4238:skgpu::Plot::Plot\28int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20SkColorType\2c\20unsigned\20long\29 +4239:skgpu::GetReducedBlendModeInfo\28SkBlendMode\29 +4240:skgpu::CreateIntegralTable\28int\29 +4241:skgpu::BlendFuncName\28SkBlendMode\29 +4242:skcms_private::baseline::exec_stages\28skcms_private::Op\20const*\2c\20void\20const**\2c\20char\20const*\2c\20char*\2c\20int\29 +4243:skcms_private::baseline::clut\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20float\20vector\5b4\5d*\2c\20float\20vector\5b4\5d*\2c\20float\20vector\5b4\5d*\2c\20float\20vector\5b4\5d*\29 +4244:skcms_ApproximatelyEqualProfiles +4245:sk_sp*\20std::__2::vector\2c\20std::__2::allocator>>::__emplace_back_slow_path>\28sk_sp&&\29 +4246:sk_sp\20sk_make_sp\2c\20SkSurfaceProps\20const*&>\28SkImageInfo\20const&\2c\20sk_sp&&\2c\20SkSurfaceProps\20const*&\29 +4247:sk_sp*\20emscripten::internal::MemberAccess>::getWire\28sk_sp\20SkRuntimeEffect::TracedShader::*\20const&\2c\20SkRuntimeEffect::TracedShader&\29 +4248:sk_fopen\28char\20const*\2c\20SkFILE_Flags\29 +4249:sk_fgetsize\28_IO_FILE*\29 +4250:sk_fclose\28_IO_FILE*\29 +4251:sk_error_fn\28png_struct_def*\2c\20char\20const*\29 +4252:setup_masks_arabic_plan\28arabic_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_script_t\29 +4253:set_khr_debug_label\28GrGLGpu*\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +4254:setThrew +4255:setCommonICUData\28UDataMemory*\2c\20signed\20char\2c\20UErrorCode*\29 +4256:serialize_image\28SkImage\20const*\2c\20SkSerialProcs\29 +4257:send_tree +4258:sect_with_vertical\28SkPoint\20const*\2c\20float\29 +4259:sect_with_horizontal\28SkPoint\20const*\2c\20float\29 +4260:scanexp +4261:scalbnl +4262:rewind_if_necessary\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +4263:resolveImplicitLevels\28UBiDi*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +4264:reset_and_decode_image_config\28wuffs_gif__decoder__struct*\2c\20wuffs_base__image_config__struct*\2c\20wuffs_base__io_buffer__struct*\2c\20SkStream*\29 +4265:res_unload_74 +4266:res_countArrayItems_74 +4267:renderbuffer_storage_msaa\28GrGLGpu*\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +4268:recursive_edge_intersect\28GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20SkPoint*\2c\20double*\2c\20double*\29 +4269:reclassify_vertex\28TriangulationVertex*\2c\20SkPoint\20const*\2c\20int\2c\20ReflexHash*\2c\20SkTInternalLList*\29 +4270:quad_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4271:quad_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4272:quad_in_line\28SkPoint\20const*\29 +4273:psh_hint_table_init +4274:psh_hint_table_find_strong_points +4275:psh_hint_table_activate_mask +4276:psh_hint_align +4277:psh_glyph_interpolate_strong_points +4278:psh_glyph_interpolate_other_points +4279:psh_glyph_interpolate_normal_points +4280:psh_blues_set_zones +4281:ps_parser_load_field +4282:ps_dimension_end +4283:ps_dimension_done +4284:ps_builder_start_point +4285:printf_core +4286:position_cluster\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29 +4287:portable::uniform_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4288:portable::set_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4289:portable::memset64\28unsigned\20long\20long*\2c\20unsigned\20long\20long\2c\20int\29 +4290:portable::copy_from_indirect_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4291:portable::copy_2_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4292:portable::check_decal_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4293:pop_arg +4294:pntz +4295:png_inflate +4296:png_deflate_claim +4297:png_decompress_chunk +4298:png_cache_unknown_chunk +4299:operator_new_impl\28unsigned\20long\29 +4300:operator==\28SkPaint\20const&\2c\20SkPaint\20const&\29 +4301:open_face +4302:openCommonData\28char\20const*\2c\20int\2c\20UErrorCode*\29 +4303:offsetTOCEntryCount\28UDataMemory\20const*\29 +4304:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::vertexStride\28SkMatrix\20const&\29\20const +4305:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29_12559 +4306:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29 +4307:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +4308:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::glyphs\28\29\20const +4309:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::glyphCount\28\29\20const +4310:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2564 +4311:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +4312:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::size\28\29\20const +4313:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +4314:nearly_equal\28double\2c\20double\29 +4315:mbsrtowcs +4316:map_quad_general\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20SkMatrix\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +4317:make_tiled_gradient\28GrFPArgs\20const&\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20bool\2c\20bool\29 +4318:make_premul_effect\28std::__2::unique_ptr>\29 +4319:make_dual_interval_colorizer\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20float\29 +4320:make_clamped_gradient\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20bool\29 +4321:make_bmp_proxy\28GrProxyProvider*\2c\20SkBitmap\20const&\2c\20GrColorType\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +4322:longest_match +4323:long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4324:long\20long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4325:long\20double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +4326:load_post_names +4327:line_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4328:line_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4329:legalfunc$_embind_register_bigint +4330:jpeg_open_backing_store +4331:jpeg_consume_input +4332:jpeg_alloc_huff_table +4333:jinit_upsampler +4334:is_leap +4335:isSpecialTypeCodepoints\28char\20const*\29 +4336:isMatchAtCPBoundary\28char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*\29 +4337:internal_memalign +4338:int\20icu_74::\28anonymous\20namespace\29::MixedBlocks::findBlock\28unsigned\20short\20const*\2c\20unsigned\20short\20const*\2c\20int\29\20const +4339:int\20icu_74::\28anonymous\20namespace\29::MixedBlocks::findBlock\28unsigned\20short\20const*\2c\20unsigned\20int\20const*\2c\20int\29\20const +4340:insertRootBundle\28UResourceDataEntry*&\2c\20UErrorCode*\29 +4341:init_error_limit +4342:init_block +4343:icu_74::set32x64Bits\28unsigned\20int*\2c\20int\2c\20int\29 +4344:icu_74::getExtName\28unsigned\20int\2c\20char*\2c\20unsigned\20short\29 +4345:icu_74::compareUnicodeString\28UElement\2c\20UElement\29 +4346:icu_74::cloneUnicodeString\28UElement*\2c\20UElement*\29 +4347:icu_74::\28anonymous\20namespace\29::mungeCharName\28char*\2c\20char\20const*\2c\20int\29 +4348:icu_74::\28anonymous\20namespace\29::MutableCodePointTrie::getDataBlock\28int\29 +4349:icu_74::XLikelySubtagsData::readLSREncodedStrings\28icu_74::ResourceTable\20const&\2c\20char\20const*\2c\20icu_74::ResourceValue&\2c\20icu_74::ResourceArray\20const&\2c\20icu_74::LocalMemory&\2c\20int&\2c\20UErrorCode&\29 +4350:icu_74::XLikelySubtags::~XLikelySubtags\28\29 +4351:icu_74::XLikelySubtags::initLikelySubtags\28UErrorCode&\29 +4352:icu_74::UnicodeString::setCharAt\28int\2c\20char16_t\29 +4353:icu_74::UnicodeString::indexOf\28char16_t\20const*\2c\20int\2c\20int\2c\20int\2c\20int\29\20const +4354:icu_74::UnicodeString::doReverse\28int\2c\20int\29 +4355:icu_74::UnicodeSetStringSpan::span\28char16_t\20const*\2c\20int\2c\20USetSpanCondition\29\20const +4356:icu_74::UnicodeSetStringSpan::spanUTF8\28unsigned\20char\20const*\2c\20int\2c\20USetSpanCondition\29\20const +4357:icu_74::UnicodeSetStringSpan::spanBack\28char16_t\20const*\2c\20int\2c\20USetSpanCondition\29\20const +4358:icu_74::UnicodeSetStringSpan::spanBackUTF8\28unsigned\20char\20const*\2c\20int\2c\20USetSpanCondition\29\20const +4359:icu_74::UnicodeSet::set\28int\2c\20int\29 +4360:icu_74::UnicodeSet::setPattern\28char16_t\20const*\2c\20int\29 +4361:icu_74::UnicodeSet::remove\28int\29 +4362:icu_74::UnicodeSet::removeAll\28icu_74::UnicodeSet\20const&\29 +4363:icu_74::UnicodeSet::matches\28icu_74::Replaceable\20const&\2c\20int&\2c\20int\2c\20signed\20char\29 +4364:icu_74::UnicodeSet::matchesIndexValue\28unsigned\20char\29\20const +4365:icu_74::UnicodeSet::clone\28\29\20const +4366:icu_74::UnicodeSet::cloneAsThawed\28\29\20const +4367:icu_74::UnicodeSet::applyPattern\28icu_74::RuleCharacterIterator&\2c\20icu_74::SymbolTable\20const*\2c\20icu_74::UnicodeString&\2c\20unsigned\20int\2c\20icu_74::UnicodeSet&\20\28icu_74::UnicodeSet::*\29\28int\29\2c\20int\2c\20UErrorCode&\29 +4368:icu_74::UnicodeSet::applyPatternIgnoreSpace\28icu_74::UnicodeString\20const&\2c\20icu_74::ParsePosition&\2c\20icu_74::SymbolTable\20const*\2c\20UErrorCode&\29 +4369:icu_74::UnicodeSet::add\28icu_74::UnicodeString\20const&\29 +4370:icu_74::UnicodeSet::addAll\28icu_74::UnicodeSet\20const&\29 +4371:icu_74::UnicodeSet::_generatePattern\28icu_74::UnicodeString&\2c\20signed\20char\29\20const +4372:icu_74::UnicodeSet::UnicodeSet\28int\2c\20int\29 +4373:icu_74::UVector::sortedInsert\28void*\2c\20int\20\28*\29\28UElement\2c\20UElement\29\2c\20UErrorCode&\29 +4374:icu_74::UVector::setElementAt\28void*\2c\20int\29 +4375:icu_74::UVector::assign\28icu_74::UVector\20const&\2c\20void\20\28*\29\28UElement*\2c\20UElement*\29\2c\20UErrorCode&\29 +4376:icu_74::UVector::UVector\28UErrorCode&\29 +4377:icu_74::UStringSet::~UStringSet\28\29_13551 +4378:icu_74::UStringSet::~UStringSet\28\29 +4379:icu_74::UDataPathIterator::UDataPathIterator\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20signed\20char\2c\20UErrorCode*\29 +4380:icu_74::UCharsTrieBuilder::build\28UStringTrieBuildOption\2c\20UErrorCode&\29 +4381:icu_74::UCharsTrieBuilder::UCharsTrieBuilder\28UErrorCode&\29 +4382:icu_74::UCharsTrie::nextForCodePoint\28int\29 +4383:icu_74::UCharsTrie::Iterator::next\28UErrorCode&\29 +4384:icu_74::UCharsTrie::Iterator::branchNext\28char16_t\20const*\2c\20int\2c\20UErrorCode&\29 +4385:icu_74::UCharCharacterIterator::setText\28icu_74::ConstChar16Ptr\2c\20int\29 +4386:icu_74::StringTrieBuilder::writeBranchSubNode\28int\2c\20int\2c\20int\2c\20int\29 +4387:icu_74::StringTrieBuilder::LinearMatchNode::operator==\28icu_74::StringTrieBuilder::Node\20const&\29\20const +4388:icu_74::StringTrieBuilder::LinearMatchNode::markRightEdgesFirst\28int\29 +4389:icu_74::RuleCharacterIterator::skipIgnored\28int\29 +4390:icu_74::RuleBasedBreakIterator::~RuleBasedBreakIterator\28\29 +4391:icu_74::RuleBasedBreakIterator::handleSafePrevious\28int\29 +4392:icu_74::RuleBasedBreakIterator::RuleBasedBreakIterator\28UErrorCode*\29 +4393:icu_74::RuleBasedBreakIterator::DictionaryCache::~DictionaryCache\28\29 +4394:icu_74::RuleBasedBreakIterator::DictionaryCache::populateDictionary\28int\2c\20int\2c\20int\2c\20int\29 +4395:icu_74::RuleBasedBreakIterator::BreakCache::seek\28int\29 +4396:icu_74::RuleBasedBreakIterator::BreakCache::current\28\29 +4397:icu_74::ResourceDataValue::getIntVector\28int&\2c\20UErrorCode&\29\20const +4398:icu_74::ReorderingBuffer::equals\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\29\20const +4399:icu_74::RBBIDataWrapper::removeReference\28\29 +4400:icu_74::PropNameData::getPropertyOrValueEnum\28int\2c\20char\20const*\29 +4401:icu_74::Normalizer2WithImpl::normalizeSecondAndAppend\28icu_74::UnicodeString&\2c\20icu_74::UnicodeString\20const&\2c\20signed\20char\2c\20UErrorCode&\29\20const +4402:icu_74::Normalizer2WithImpl::isNormalized\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +4403:icu_74::Normalizer2Impl::recompose\28icu_74::ReorderingBuffer&\2c\20int\2c\20signed\20char\29\20const +4404:icu_74::Normalizer2Impl::init\28int\20const*\2c\20UCPTrie\20const*\2c\20unsigned\20short\20const*\2c\20unsigned\20char\20const*\29 +4405:icu_74::Normalizer2Impl::findNextFCDBoundary\28char16_t\20const*\2c\20char16_t\20const*\29\20const +4406:icu_74::Normalizer2Impl::decomposeUTF8\28unsigned\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20icu_74::ByteSink*\2c\20icu_74::Edits*\2c\20UErrorCode&\29\20const +4407:icu_74::Normalizer2Impl::composeUTF8\28unsigned\20int\2c\20signed\20char\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20icu_74::ByteSink*\2c\20icu_74::Edits*\2c\20UErrorCode&\29\20const +4408:icu_74::Normalizer2Impl::composeQuickCheck\28char16_t\20const*\2c\20char16_t\20const*\2c\20signed\20char\2c\20UNormalizationCheckResult*\29\20const +4409:icu_74::Normalizer2Factory::getNFKC_CFImpl\28UErrorCode&\29 +4410:icu_74::Normalizer2Factory::getInstance\28UNormalizationMode\2c\20UErrorCode&\29 +4411:icu_74::Normalizer2::getNFCInstance\28UErrorCode&\29 +4412:icu_74::NoopNormalizer2::normalizeSecondAndAppend\28icu_74::UnicodeString&\2c\20icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +4413:icu_74::NoopNormalizer2::isNormalized\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +4414:icu_74::MlBreakEngine::~MlBreakEngine\28\29 +4415:icu_74::LocaleUtility::canonicalLocaleString\28icu_74::UnicodeString\20const*\2c\20icu_74::UnicodeString&\29 +4416:icu_74::LocaleKeyFactory::LocaleKeyFactory\28int\29 +4417:icu_74::LocaleKey::LocaleKey\28icu_74::UnicodeString\20const&\2c\20icu_74::UnicodeString\20const&\2c\20icu_74::UnicodeString\20const*\2c\20int\29 +4418:icu_74::LocaleBuilder::build\28UErrorCode&\29 +4419:icu_74::LocaleBuilder::LocaleBuilder\28\29 +4420:icu_74::LocaleBased::setLocaleIDs\28char\20const*\2c\20char\20const*\29 +4421:icu_74::Locale::setKeywordValue\28char\20const*\2c\20char\20const*\2c\20UErrorCode&\29 +4422:icu_74::Locale::operator=\28icu_74::Locale&&\29 +4423:icu_74::Locale::operator==\28icu_74::Locale\20const&\29\20const +4424:icu_74::Locale::createKeywords\28UErrorCode&\29\20const +4425:icu_74::Locale::createFromName\28char\20const*\29 +4426:icu_74::LaoBreakEngine::divideUpDictionaryRange\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +4427:icu_74::LSR::operator=\28icu_74::LSR&&\29 +4428:icu_74::InitCanonIterData::doInit\28icu_74::Normalizer2Impl*\2c\20UErrorCode&\29 +4429:icu_74::ICU_Utility::shouldAlwaysBeEscaped\28int\29 +4430:icu_74::ICU_Utility::isUnprintable\28int\29 +4431:icu_74::ICU_Utility::escape\28icu_74::UnicodeString&\2c\20int\29 +4432:icu_74::ICUServiceKey::parseSuffix\28icu_74::UnicodeString&\29 +4433:icu_74::ICUService::~ICUService\28\29 +4434:icu_74::ICUService::getVisibleIDs\28icu_74::UVector&\2c\20UErrorCode&\29\20const +4435:icu_74::ICUService::clearServiceCache\28\29 +4436:icu_74::ICUNotifier::~ICUNotifier\28\29 +4437:icu_74::Hashtable::put\28icu_74::UnicodeString\20const&\2c\20void*\2c\20UErrorCode&\29 +4438:icu_74::Edits::copyErrorTo\28UErrorCode&\29\20const +4439:icu_74::DecomposeNormalizer2::hasBoundaryBefore\28int\29\20const +4440:icu_74::DecomposeNormalizer2::hasBoundaryAfter\28int\29\20const +4441:icu_74::CjkBreakEngine::~CjkBreakEngine\28\29 +4442:icu_74::CjkBreakEngine::CjkBreakEngine\28icu_74::DictionaryMatcher*\2c\20icu_74::LanguageType\2c\20UErrorCode&\29 +4443:icu_74::CharString::truncate\28int\29 +4444:icu_74::CharString::cloneData\28UErrorCode&\29\20const +4445:icu_74::CharString*\20icu_74::MemoryPool::create\28char\20const*&\2c\20UErrorCode&\29 +4446:icu_74::CharString*\20icu_74::MemoryPool::create<>\28\29 +4447:icu_74::CanonIterData::addToStartSet\28int\2c\20int\2c\20UErrorCode&\29 +4448:icu_74::BytesTrie::branchNext\28unsigned\20char\20const*\2c\20int\2c\20int\29 +4449:icu_74::ByteSinkUtil::appendCodePoint\28int\2c\20int\2c\20icu_74::ByteSink&\2c\20icu_74::Edits*\29 +4450:icu_74::BreakIterator::getLocale\28ULocDataLocaleType\2c\20UErrorCode&\29\20const +4451:icu_74::BreakIterator::getLocaleID\28ULocDataLocaleType\2c\20UErrorCode&\29\20const +4452:icu_74::BreakIterator::createCharacterInstance\28icu_74::Locale\20const&\2c\20UErrorCode&\29 +4453:hb_vector_t\2c\20false>::alloc\28unsigned\20int\2c\20bool\29 +4454:hb_vector_t::push\28\29 +4455:hb_vector_t\2c\20false>::resize\28int\2c\20bool\2c\20bool\29 +4456:hb_utf8_t::next\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20int*\2c\20unsigned\20int\29 +4457:hb_unicode_script +4458:hb_unicode_mirroring_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +4459:hb_unicode_funcs_t::is_default_ignorable\28unsigned\20int\29 +4460:hb_shape_plan_key_t::init\28bool\2c\20hb_face_t*\2c\20hb_segment_properties_t\20const*\2c\20hb_feature_t\20const*\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20char\20const*\20const*\29 +4461:hb_shape_plan_create2 +4462:hb_serialize_context_t::fini\28\29 +4463:hb_sanitize_context_t::return_t\20AAT::ChainSubtable::dispatch\28hb_sanitize_context_t*\29\20const +4464:hb_sanitize_context_t::return_t\20AAT::ChainSubtable::dispatch\28hb_sanitize_context_t*\29\20const +4465:hb_paint_extents_paint_linear_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +4466:hb_paint_extents_get_funcs\28\29 +4467:hb_paint_extents_context_t::hb_paint_extents_context_t\28\29 +4468:hb_ot_map_t::fini\28\29 +4469:hb_ot_layout_table_select_script +4470:hb_ot_layout_table_get_lookup_count +4471:hb_ot_layout_table_find_feature_variations +4472:hb_ot_layout_table_find_feature\28hb_face_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +4473:hb_ot_layout_script_select_language +4474:hb_ot_layout_language_get_required_feature +4475:hb_ot_layout_language_find_feature +4476:hb_ot_layout_has_substitution +4477:hb_ot_layout_feature_with_variations_get_lookups +4478:hb_ot_layout_collect_features_map +4479:hb_ot_font_set_funcs +4480:hb_lazy_loader_t::do_destroy\28hb_draw_funcs_t*\29 +4481:hb_lazy_loader_t\2c\20hb_face_t\2c\2038u\2c\20OT::sbix_accelerator_t>::create\28hb_face_t*\29 +4482:hb_lazy_loader_t\2c\20hb_face_t\2c\207u\2c\20OT::post_accelerator_t>::do_destroy\28OT::post_accelerator_t*\29 +4483:hb_lazy_loader_t\2c\20hb_face_t\2c\2017u\2c\20OT::cff2_accelerator_t>::do_destroy\28OT::cff2_accelerator_t*\29 +4484:hb_lazy_loader_t\2c\20hb_face_t\2c\2037u\2c\20OT::CBDT_accelerator_t>::do_destroy\28OT::CBDT_accelerator_t*\29 +4485:hb_language_matches +4486:hb_indic_get_categories\28unsigned\20int\29 +4487:hb_hashmap_t::fetch_item\28hb_serialize_context_t::object_t\20const*\20const&\2c\20unsigned\20int\29\20const +4488:hb_hashmap_t::alloc\28unsigned\20int\29 +4489:hb_font_t::get_glyph_v_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +4490:hb_font_t::get_glyph_contour_point_for_origin\28unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20int*\2c\20int*\29 +4491:hb_font_set_variations +4492:hb_font_set_funcs +4493:hb_font_get_variation_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +4494:hb_font_get_glyph_h_advance +4495:hb_font_get_glyph_extents +4496:hb_font_get_font_h_extents_nil\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +4497:hb_font_funcs_set_variation_glyph_func +4498:hb_font_funcs_set_nominal_glyphs_func +4499:hb_font_funcs_set_nominal_glyph_func +4500:hb_font_funcs_set_glyph_h_advances_func +4501:hb_font_funcs_set_glyph_extents_func +4502:hb_font_funcs_create +4503:hb_draw_move_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +4504:hb_draw_funcs_set_quadratic_to_func +4505:hb_draw_funcs_set_move_to_func +4506:hb_draw_funcs_set_line_to_func +4507:hb_draw_funcs_set_cubic_to_func +4508:hb_draw_funcs_create +4509:hb_draw_extents_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +4510:hb_buffer_t::sort\28unsigned\20int\2c\20unsigned\20int\2c\20int\20\28*\29\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29\29 +4511:hb_buffer_t::output_info\28hb_glyph_info_t\20const&\29 +4512:hb_buffer_t::message_impl\28hb_font_t*\2c\20char\20const*\2c\20void*\29 +4513:hb_buffer_t::leave\28\29 +4514:hb_buffer_t::delete_glyphs_inplace\28bool\20\28*\29\28hb_glyph_info_t\20const*\29\29 +4515:hb_buffer_t::clear_positions\28\29 +4516:hb_buffer_set_length +4517:hb_buffer_get_glyph_positions +4518:hb_buffer_diff +4519:hb_buffer_create +4520:hb_buffer_clear_contents +4521:hb_buffer_add_utf8 +4522:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +4523:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +4524:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +4525:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +4526:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +4527:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +4528:hb_aat_layout_remove_deleted_glyphs\28hb_buffer_t*\29 +4529:hair_cubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4530:getint +4531:get_win_string +4532:get_dst_swizzle_and_store\28GrColorType\2c\20SkRasterPipelineOp*\2c\20LumMode*\2c\20bool*\2c\20bool*\29 +4533:get_driver_and_version\28GrGLStandard\2c\20GrGLVendor\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +4534:getFallbackData\28UResourceBundle\20const*\2c\20char\20const**\2c\20unsigned\20int*\2c\20UErrorCode*\29 +4535:gen_key\28skgpu::KeyBuilder*\2c\20GrProgramInfo\20const&\2c\20GrCaps\20const&\29 +4536:gen_fp_key\28GrFragmentProcessor\20const&\2c\20GrCaps\20const&\2c\20skgpu::KeyBuilder*\29 +4537:gather_uniforms_and_check_for_main\28SkSL::Program\20const&\2c\20std::__2::vector>*\2c\20std::__2::vector>*\2c\20SkRuntimeEffect::Uniform::Flags\2c\20unsigned\20long*\29 +4538:fwrite +4539:ft_var_to_normalized +4540:ft_var_load_item_variation_store +4541:ft_var_load_hvvar +4542:ft_var_load_avar +4543:ft_var_get_value_pointer +4544:ft_var_apply_tuple +4545:ft_validator_init +4546:ft_mem_strcpyn +4547:ft_hash_num_lookup +4548:ft_glyphslot_set_bitmap +4549:ft_glyphslot_preset_bitmap +4550:ft_corner_orientation +4551:ft_corner_is_flat +4552:frexp +4553:free_entry\28UResourceDataEntry*\29 +4554:fread +4555:fp_force_eval +4556:fp_barrier_17148 +4557:fopen +4558:fold_opacity_layer_color_to_paint\28SkPaint\20const*\2c\20bool\2c\20SkPaint*\29 +4559:fmodl +4560:float\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +4561:fill_shadow_rec\28SkPath\20const&\2c\20SkPoint3\20const&\2c\20SkPoint3\20const&\2c\20float\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkDrawShadowRec*\29 +4562:fill_inverse_cmap +4563:fileno +4564:examine_app0 +4565:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29\2c\20SkCanvas*\2c\20SkPath*\2c\20SkClipOp\2c\20bool\29 +4566:emscripten::internal::MethodInvoker\20\28SkAnimatedImage::*\29\28\29\2c\20sk_sp\2c\20SkAnimatedImage*>::invoke\28sk_sp\20\28SkAnimatedImage::*\20const&\29\28\29\2c\20SkAnimatedImage*\29 +4567:emscripten::internal::Invoker\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20sk_sp\29\2c\20sk_sp*\2c\20sk_sp*\29 +4568:emscripten::internal::Invoker\2c\20SkBlendMode\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29\2c\20SkBlendMode\2c\20sk_sp*\2c\20sk_sp*\29 +4569:emscripten::internal::Invoker\2c\20SkBlendMode>::invoke\28sk_sp\20\28*\29\28SkBlendMode\29\2c\20SkBlendMode\29 +4570:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4571:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\29 +4572:emscripten::internal::FunctionInvoker\29\2c\20void\2c\20SkPaint&\2c\20unsigned\20long\2c\20sk_sp>::invoke\28void\20\28**\29\28SkPaint&\2c\20unsigned\20long\2c\20sk_sp\29\2c\20SkPaint*\2c\20unsigned\20long\2c\20sk_sp*\29 +4573:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29\2c\20SkCanvas*\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +4574:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +4575:emscripten::internal::FunctionInvoker\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +4576:emscripten::internal::FunctionInvoker\20\28*\29\28SkCanvas&\2c\20SimpleImageInfo\29\2c\20sk_sp\2c\20SkCanvas&\2c\20SimpleImageInfo>::invoke\28sk_sp\20\28**\29\28SkCanvas&\2c\20SimpleImageInfo\29\2c\20SkCanvas*\2c\20SimpleImageInfo*\29 +4577:emscripten::internal::FunctionInvoker::invoke\28int\20\28**\29\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SkFont*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +4578:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20SkPath\20const&\2c\20SkPathOp\29\2c\20SkPath*\2c\20SkPath*\2c\20SkPathOp\29 +4579:embind_init_builtin\28\29 +4580:embind_init_Skia\28\29 +4581:embind_init_Paragraph\28\29::$_0::__invoke\28SimpleParagraphStyle\2c\20sk_sp\29 +4582:embind_init_Paragraph\28\29 +4583:embind_init_ParagraphGen\28\29 +4584:edge_line_needs_recursion\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4585:draw_nine\28SkMask\20const&\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\2c\20bool\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +4586:dquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4587:dquad_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4588:double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +4589:doOpenChoice\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20signed\20char\20\28*\29\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29\2c\20void*\2c\20UErrorCode*\29 +4590:doLoadFromIndividualFiles\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20signed\20char\20\28*\29\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29\2c\20void*\2c\20UErrorCode*\2c\20UErrorCode*\29 +4591:dline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4592:dline_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4593:deflate_stored +4594:decompose_current_character\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\29 +4595:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::Make\28SkArenaAlloc*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4596:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&\2c\20skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathCurveTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4597:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4598:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker\2c\20int&>\28int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4599:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkShaderBase\20const&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTransformShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4600:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4601:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29>\28GrThreadSafeCache::Entry&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4602:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29::'lambda'\28void*\29>\28GrResourceAllocator::Register&&\29 +4603:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrRRectShadowGeoProc::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4604:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28GrQuadEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4605:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrPipeline::InitArgs&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29::'lambda'\28void*\29>\28GrPipeline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4606:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldA8TextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20float\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4607:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28DefaultGeoProc::Make\28SkArenaAlloc*\2c\20unsigned\20int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29 +4608:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28CircleGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4609:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>>::__generic_construct\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__ctor\2c\20std::__2::unique_ptr>>>&\2c\20std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&>\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&\29 +4610:decltype\28_dispatch\28fp\2c\20\28hb_priority<16u>\29\28\29\29\29\20hb_sanitize_context_t::dispatch\28OT::DeltaSetIndexMap\20const&\29 +4611:dcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4612:dcubic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4613:dconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4614:dconic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4615:data_destroy_arabic\28void*\29 +4616:data_create_arabic\28hb_ot_shape_plan_t\20const*\29 +4617:cycle +4618:cubic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4619:cubic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4620:create_colorindex +4621:copysignl +4622:copy_bitmap_subset\28SkBitmap\20const&\2c\20SkIRect\20const&\29 +4623:conic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4624:conic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4625:compute_pos_tan\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +4626:compute_intersection\28OffsetSegment\20const&\2c\20OffsetSegment\20const&\2c\20SkPoint*\2c\20float*\2c\20float*\29 +4627:compress_block +4628:compose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +4629:compare_offsets +4630:clipHandlesSprite\28SkRasterClip\20const&\2c\20int\2c\20int\2c\20SkPixmap\20const&\29 +4631:clamp\28SkPoint\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Comparator\20const&\29 +4632:checkint +4633:check_inverse_on_empty_return\28SkRegion*\2c\20SkPath\20const&\2c\20SkRegion\20const&\29 +4634:charIterTextAccess\28UText*\2c\20long\20long\2c\20signed\20char\29 +4635:char*\20std::__2::copy_n\5babi:nn180100\5d\28char\20const*\2c\20unsigned\20long\2c\20char*\29 +4636:char*\20std::__2::copy\5babi:nn180100\5d\2c\20char*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20char*\29 +4637:char*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20std::__2::__element_count\29 +4638:cff_vstore_done +4639:cff_subfont_load +4640:cff_subfont_done +4641:cff_size_select +4642:cff_parser_run +4643:cff_make_private_dict +4644:cff_load_private_dict +4645:cff_index_get_name +4646:cff_get_kerning +4647:cff_blend_build_vector +4648:cf2_getSeacComponent +4649:cf2_computeDarkening +4650:cf2_arrstack_push +4651:cbrt +4652:build_ycc_rgb_table +4653:bracketProcessChar\28BracketData*\2c\20int\29 +4654:bool\20std::__2::operator==\5babi:nn180100\5d\28std::__2::unique_ptr\20const&\2c\20std::nullptr_t\29 +4655:bool\20std::__2::operator!=\5babi:ne180100\5d\28std::__2::variant\20const&\2c\20std::__2::variant\20const&\29 +4656:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +4657:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\29 +4658:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +4659:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +4660:bool\20is_parallel\28SkDLine\20const&\2c\20SkTCurve\20const&\29 +4661:bool\20hb_hashmap_t::set_with_hash\28hb_serialize_context_t::object_t*&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool\29 +4662:bool\20apply_string\28OT::hb_ot_apply_context_t*\2c\20GSUBProxy::Lookup\20const&\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\29 +4663:bool\20OT::hb_accelerate_subtables_context_t::cache_func_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\2c\20bool\29 +4664:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4665:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4666:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4667:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4668:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4669:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4670:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4671:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4672:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4673:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4674:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4675:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4676:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4677:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4678:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4679:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4680:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4681:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4682:bool\20OT::OffsetTo\2c\20true>::serialize_serialize\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&>\28hb_serialize_context_t*\2c\20hb_map_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&\29 +4683:bool\20GrTTopoSort_Visit\28GrRenderTask*\2c\20unsigned\20int*\29 +4684:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +4685:bits_to_runs\28SkBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\2c\20long\2c\20unsigned\20char\29 +4686:barycentric_coords\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +4687:auto\20std::__2::__unwrap_range\5babi:nn180100\5d\2c\20std::__2::__wrap_iter>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\29 +4688:atanf +4689:apply_forward\28OT::hb_ot_apply_context_t*\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\2c\20unsigned\20int\29 +4690:apply_alpha_and_colorfilter\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20SkPaint\20const&\29 +4691:append_multitexture_lookup\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20int\2c\20GrGLSLVarying\20const&\2c\20char\20const*\2c\20char\20const*\29 +4692:append_color_output\28PorterDuffXferProcessor\20const&\2c\20GrGLSLXPFragmentBuilder*\2c\20skgpu::BlendFormula::OutputType\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +4693:af_loader_compute_darkening +4694:af_latin_metrics_scale_dim +4695:af_latin_hints_detect_features +4696:af_latin_hint_edges +4697:af_hint_normal_stem +4698:af_cjk_metrics_scale_dim +4699:af_cjk_metrics_scale +4700:af_cjk_metrics_init_widths +4701:af_cjk_hints_init +4702:af_cjk_hints_detect_features +4703:af_cjk_hints_compute_blue_edges +4704:af_cjk_hints_apply +4705:af_cjk_hint_edges +4706:af_cjk_get_standard_widths +4707:af_axis_hints_new_edge +4708:adler32 +4709:a_ctz_32 +4710:_uhash_remove\28UHashtable*\2c\20UElement\29 +4711:_uhash_rehash\28UHashtable*\2c\20UErrorCode*\29 +4712:_uhash_put\28UHashtable*\2c\20UElement\2c\20UElement\2c\20signed\20char\2c\20UErrorCode*\29 +4713:_iup_worker_interpolate +4714:_isUnicodeExtensionSubtag\28int&\2c\20char\20const*\2c\20int\29 +4715:_isTransformedExtensionSubtag\28int&\2c\20char\20const*\2c\20int\29 +4716:_hb_preprocess_text_vowel_constraints\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +4717:_hb_ot_shape +4718:_hb_options_init\28\29 +4719:_hb_font_create\28hb_face_t*\29 +4720:_hb_fallback_shape +4721:_glyf_get_advance_with_var_unscaled\28hb_font_t*\2c\20unsigned\20int\2c\20bool\29 +4722:_getVariant\28char\20const*\2c\20char\2c\20icu_74::ByteSink&\2c\20signed\20char\29 +4723:__vfprintf_internal +4724:__trunctfsf2 +4725:__tan +4726:__strftime_l +4727:__rem_pio2_large +4728:__overflow +4729:__nl_langinfo_l +4730:__newlocale +4731:__munmap +4732:__mmap +4733:__math_xflowf +4734:__math_invalidf +4735:__loc_is_allocated +4736:__isxdigit_l +4737:__isdigit_l +4738:__getf2 +4739:__get_locale +4740:__ftello_unlocked +4741:__fstatat +4742:__fseeko_unlocked +4743:__floatscan +4744:__expo2 +4745:__dynamic_cast +4746:__divtf3 +4747:__cxxabiv1::__base_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +4748:_ZZN19GrGeometryProcessor11ProgramImpl17collectTransformsEP19GrGLSLVertexBuilderP20GrGLSLVaryingHandlerP20GrGLSLUniformHandler12GrShaderTypeRK11GrShaderVarSA_RK10GrPipelineEN3$_0clISE_EEvRT_RK19GrFragmentProcessorbPSJ_iNS0_9BaseCoordE +4749:\28anonymous\20namespace\29::write_text_tag\28char\20const*\29 +4750:\28anonymous\20namespace\29::write_mAB_or_mBA_tag\28unsigned\20int\2c\20skcms_Curve\20const*\2c\20skcms_Curve\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20skcms_Curve\20const*\2c\20skcms_Matrix3x4\20const*\29 +4751:\28anonymous\20namespace\29::set_uv_quad\28SkPoint\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +4752:\28anonymous\20namespace\29::safe_to_ignore_subset_rect\28GrAAType\2c\20SkFilterMode\2c\20DrawQuad\20const&\2c\20SkRect\20const&\29 +4753:\28anonymous\20namespace\29::morphology_pass\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20\28anonymous\20namespace\29::MorphType\2c\20\28anonymous\20namespace\29::MorphDirection\2c\20int\29 +4754:\28anonymous\20namespace\29::make_non_convex_fill_op\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20skgpu::ganesh::FillPathFlags\2c\20GrAAType\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\29 +4755:\28anonymous\20namespace\29::is_newer_better\28SkData*\2c\20SkData*\29 +4756:\28anonymous\20namespace\29::get_glyph_run_intercepts\28sktext::GlyphRun\20const&\2c\20SkPaint\20const&\2c\20float\20const*\2c\20float*\2c\20int*\29 +4757:\28anonymous\20namespace\29::get_cicp_trfn\28skcms_TransferFunction\20const&\29 +4758:\28anonymous\20namespace\29::get_cicp_primaries\28skcms_Matrix3x3\20const&\29 +4759:\28anonymous\20namespace\29::getStringArray\28ResourceData\20const*\2c\20icu_74::ResourceArray\20const&\2c\20icu_74::UnicodeString*\2c\20int\2c\20UErrorCode&\29 +4760:\28anonymous\20namespace\29::getInclusionsForSource\28UPropertySource\2c\20UErrorCode&\29 +4761:\28anonymous\20namespace\29::draw_to_sw_mask\28GrSWMaskHelper*\2c\20skgpu::ganesh::ClipStack::Element\20const&\2c\20bool\29 +4762:\28anonymous\20namespace\29::draw_tiled_image\28SkCanvas*\2c\20std::__2::function\20\28SkIRect\29>\2c\20SkISize\2c\20int\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkSamplingOptions\29 +4763:\28anonymous\20namespace\29::determine_clipped_src_rect\28SkIRect\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkISize\20const&\2c\20SkRect\20const*\29 +4764:\28anonymous\20namespace\29::create_hb_face\28SkTypeface\20const&\29::$_0::__invoke\28void*\29 +4765:\28anonymous\20namespace\29::copyFTBitmap\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\29 +4766:\28anonymous\20namespace\29::colrv1_start_glyph\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20unsigned\20short\2c\20FT_Color_Root_Transform_\2c\20skia_private::THashSet*\29 +4767:\28anonymous\20namespace\29::colrv1_draw_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\29 +4768:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29 +4769:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29 +4770:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29 +4771:\28anonymous\20namespace\29::TriangulatingPathOp::TriangulatingPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +4772:\28anonymous\20namespace\29::TriangulatingPathOp::Triangulate\28GrEagerVertexAllocator*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool*\29 +4773:\28anonymous\20namespace\29::TriangulatingPathOp::CreateKey\28skgpu::UniqueKey*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\29 +4774:\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +4775:\28anonymous\20namespace\29::TextureOpImpl::propagateCoverageAAThroughoutChain\28\29 +4776:\28anonymous\20namespace\29::TextureOpImpl::characterize\28\28anonymous\20namespace\29::TextureOpImpl::Desc*\29\20const +4777:\28anonymous\20namespace\29::TextureOpImpl::appendQuad\28DrawQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\29 +4778:\28anonymous\20namespace\29::TextureOpImpl::Make\28GrRecordingContext*\2c\20GrTextureSetEntry*\2c\20int\2c\20int\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20GrAAType\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +4779:\28anonymous\20namespace\29::TextureOpImpl::FillInVertices\28GrCaps\20const&\2c\20\28anonymous\20namespace\29::TextureOpImpl*\2c\20\28anonymous\20namespace\29::TextureOpImpl::Desc*\2c\20char*\29 +4780:\28anonymous\20namespace\29::SpotVerticesFactory::makeVertices\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint*\29\20const +4781:\28anonymous\20namespace\29::SkImageImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +4782:\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +4783:\28anonymous\20namespace\29::RunIteratorQueue::advanceRuns\28\29 +4784:\28anonymous\20namespace\29::RPBlender::RPBlender\28SkColorType\2c\20SkColorType\2c\20SkAlphaType\2c\20bool\29 +4785:\28anonymous\20namespace\29::Pass::blur\28int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +4786:\28anonymous\20namespace\29::MipLevelHelper::allocAndInit\28SkArenaAlloc*\2c\20SkSamplingOptions\20const&\2c\20SkTileMode\2c\20SkTileMode\29 +4787:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29 +4788:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20sk_sp\2c\20GrPrimitiveType\20const*\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +4789:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMesh\20const&\2c\20skia_private::TArray>\2c\20true>\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +4790:\28anonymous\20namespace\29::MeshOp::Mesh::Mesh\28SkMesh\20const&\29 +4791:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29 +4792:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29 +4793:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineStruct\28char\20const*\29 +4794:\28anonymous\20namespace\29::FillRectOpImpl::tessellate\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29\20const +4795:\28anonymous\20namespace\29::FillRectOpImpl::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +4796:\28anonymous\20namespace\29::FillRectOpImpl::FillRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +4797:\28anonymous\20namespace\29::EllipticalRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRRect\20const&\29 +4798:\28anonymous\20namespace\29::DrawAtlasOpImpl::DrawAtlasOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrAAType\2c\20int\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\29 +4799:\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29_12540 +4800:\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29 +4801:\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +4802:\28anonymous\20namespace\29::DirectMaskSubRun::glyphCount\28\29\20const +4803:\28anonymous\20namespace\29::DefaultPathOp::programInfo\28\29 +4804:\28anonymous\20namespace\29::DefaultPathOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +4805:\28anonymous\20namespace\29::DefaultPathOp::DefaultPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +4806:\28anonymous\20namespace\29::ClipGeometry\20\28anonymous\20namespace\29::get_clip_geometry\28skgpu::ganesh::ClipStack::SaveRecord\20const&\2c\20skgpu::ganesh::ClipStack::Draw\20const&\29 +4807:\28anonymous\20namespace\29::CircularRRectEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +4808:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29 +4809:\28anonymous\20namespace\29::CachedTessellations::CachedTessellations\28\29 +4810:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29 +4811:\28anonymous\20namespace\29::AAHairlineOp::AAHairlineOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIRect\2c\20float\2c\20GrUserStencilSettings\20const*\29 +4812:WebPResetDecParams +4813:WebPRescalerGetScaledDimensions +4814:WebPMultRows +4815:WebPMultARGBRows +4816:WebPIoInitFromOptions +4817:WebPInitUpsamplers +4818:WebPFlipBuffer +4819:WebPDemuxGetChunk +4820:WebPCopyDecBufferPixels +4821:WebPAllocateDecBuffer +4822:WebGLTextureImageGenerator::~WebGLTextureImageGenerator\28\29 +4823:VP8RemapBitReader +4824:VP8LHuffmanTablesAllocate +4825:VP8LDspInit +4826:VP8LConvertFromBGRA +4827:VP8LColorCacheInit +4828:VP8LColorCacheCopy +4829:VP8LBuildHuffmanTable +4830:VP8LBitReaderSetBuffer +4831:VP8InitScanline +4832:VP8GetInfo +4833:VP8BitReaderSetBuffer +4834:Update_Max +4835:TransformOne_C +4836:TT_Set_Named_Instance +4837:TT_Hint_Glyph +4838:StoreFrame +4839:SortContourList\28SkOpContourHead**\2c\20bool\2c\20bool\29 +4840:SkYUVAPixmapInfo::isSupported\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\29\20const +4841:SkWuffsCodec::seekFrame\28int\29 +4842:SkWuffsCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +4843:SkWuffsCodec::onIncrementalDecodeTwoPass\28\29 +4844:SkWuffsCodec::decodeFrameConfig\28\29 +4845:SkWriter32::writeString\28char\20const*\2c\20unsigned\20long\29 +4846:SkWriteICCProfile\28skcms_ICCProfile\20const*\2c\20char\20const*\29 +4847:SkWebpDecoder::IsWebp\28void\20const*\2c\20unsigned\20long\29 +4848:SkWebpCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29 +4849:SkWbmpDecoder::IsWbmp\28void\20const*\2c\20unsigned\20long\29 +4850:SkWbmpCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29 +4851:SkWStream::SizeOfPackedUInt\28unsigned\20long\29 +4852:SkWBuffer::padToAlign4\28\29 +4853:SkVertices::Builder::indices\28\29 +4854:SkUnicode_icu::extractWords\28unsigned\20short*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +4855:SkUnicode::convertUtf16ToUtf8\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4856:SkUTF::NextUTF16\28unsigned\20short\20const**\2c\20unsigned\20short\20const*\29 +4857:SkTypeface_FreeType::FaceRec::Make\28SkTypeface_FreeType\20const*\29 +4858:SkTypeface_Custom::onGetFamilyName\28SkString*\29\20const +4859:SkTypeface::textToGlyphs\28void\20const*\2c\20unsigned\20long\2c\20SkTextEncoding\2c\20unsigned\20short*\2c\20int\29\20const +4860:SkTypeface::serialize\28SkWStream*\2c\20SkTypeface::SerializeBehavior\29\20const +4861:SkTypeface::openStream\28int*\29\20const +4862:SkTypeface::onGetFixedPitch\28\29\20const +4863:SkTypeface::getVariationDesignPosition\28SkFontArguments::VariationPosition::Coordinate*\2c\20int\29\20const +4864:SkTypeface::getFamilyName\28SkString*\29\20const +4865:SkTransformShader::update\28SkMatrix\20const&\29 +4866:SkTransformShader::SkTransformShader\28SkShaderBase\20const&\2c\20bool\29 +4867:SkTiff::ImageFileDirectory::getEntryRawData\28unsigned\20short\2c\20unsigned\20short*\2c\20unsigned\20short*\2c\20unsigned\20int*\2c\20unsigned\20char\20const**\2c\20unsigned\20long*\29\20const +4868:SkTextBlobBuilder::allocRunPos\28SkFont\20const&\2c\20int\2c\20SkRect\20const*\29 +4869:SkTextBlob::getIntercepts\28float\20const*\2c\20float*\2c\20SkPaint\20const*\29\20const +4870:SkTextBlob::RunRecord::StorageSize\28unsigned\20int\2c\20unsigned\20int\2c\20SkTextBlob::GlyphPositioning\2c\20SkSafeMath*\29 +4871:SkTextBlob::MakeFromText\28void\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20SkTextEncoding\29 +4872:SkTextBlob::MakeFromRSXform\28void\20const*\2c\20unsigned\20long\2c\20SkRSXform\20const*\2c\20SkFont\20const&\2c\20SkTextEncoding\29 +4873:SkTextBlob::Iter::experimentalNext\28SkTextBlob::Iter::ExperimentalRun*\29 +4874:SkTextBlob::Iter::Iter\28SkTextBlob\20const&\29 +4875:SkTaskGroup::wait\28\29 +4876:SkTaskGroup::add\28std::__2::function\29 +4877:SkTSpan::onlyEndPointsInCommon\28SkTSpan\20const*\2c\20bool*\2c\20bool*\2c\20bool*\29 +4878:SkTSpan::linearIntersects\28SkTCurve\20const&\29\20const +4879:SkTSect::removeAllBut\28SkTSpan\20const*\2c\20SkTSpan*\2c\20SkTSect*\29 +4880:SkTSect::intersects\28SkTSpan*\2c\20SkTSect*\2c\20SkTSpan*\2c\20int*\29 +4881:SkTSect::deleteEmptySpans\28\29 +4882:SkTSect::addSplitAt\28SkTSpan*\2c\20double\29 +4883:SkTSect::addForPerp\28SkTSpan*\2c\20double\29 +4884:SkTSect::EndsEqual\28SkTSect\20const*\2c\20SkTSect\20const*\2c\20SkIntersections*\29 +4885:SkTMultiMap::~SkTMultiMap\28\29 +4886:SkTMaskGamma<3\2c\203\2c\203>::SkTMaskGamma\28float\2c\20float\29 +4887:SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::find\28SkImageFilterCacheKey\20const&\29\20const +4888:SkTDStorage::calculateSizeOrDie\28int\29::$_1::operator\28\29\28\29\20const +4889:SkTDStorage::SkTDStorage\28SkTDStorage&&\29 +4890:SkTCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +4891:SkTConic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +4892:SkTConic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +4893:SkTConic::controlsInside\28\29\20const +4894:SkTConic::collapsed\28\29\20const +4895:SkTBlockList::reset\28\29 +4896:SkTBlockList::reset\28\29 +4897:SkTBlockList::push_back\28GrGLProgramDataManager::GLUniformInfo\20const&\29 +4898:SkSwizzler::MakeSimple\28int\2c\20SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20SkIRect\20const*\29 +4899:SkSurfaces::WrapPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkSurfaceProps\20const*\29 +4900:SkSurface_Base::outstandingImageSnapshot\28\29\20const +4901:SkSurface_Base::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +4902:SkSurface_Base::onCapabilities\28\29 +4903:SkStrokeRec::setHairlineStyle\28\29 +4904:SkStrokeRec::SkStrokeRec\28SkPaint\20const&\2c\20SkPaint::Style\2c\20float\29 +4905:SkStrokeRec::GetInflationRadius\28SkPaint::Join\2c\20float\2c\20SkPaint::Cap\2c\20float\29 +4906:SkString::insertHex\28unsigned\20long\2c\20unsigned\20int\2c\20int\29 +4907:SkString::appendVAList\28char\20const*\2c\20void*\29 +4908:SkString::SkString\28std::__2::basic_string_view>\29 +4909:SkString*\20std::__2::vector>::__emplace_back_slow_path\28char\20const*&\29 +4910:SkStrikeSpec::SkStrikeSpec\28SkStrikeSpec\20const&\29 +4911:SkStrikeSpec::ShouldDrawAsPath\28SkPaint\20const&\2c\20SkFont\20const&\2c\20SkMatrix\20const&\29 +4912:SkStrike::~SkStrike\28\29 +4913:SkStream::readS8\28signed\20char*\29 +4914:SkStream::readS16\28short*\29 +4915:SkStrSplit\28char\20const*\2c\20char\20const*\2c\20SkStrSplitMode\2c\20skia_private::TArray*\29 +4916:SkStrAppendS32\28char*\2c\20int\29 +4917:SkSpriteBlitter_Memcpy::~SkSpriteBlitter_Memcpy\28\29 +4918:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +4919:SkSpecialImages::AsBitmap\28SkSpecialImage\20const*\2c\20SkBitmap*\29 +4920:SkSharedMutex::releaseShared\28\29 +4921:SkShapers::unicode::BidiRunIterator\28sk_sp\2c\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20char\29 +4922:SkShapers::HB::ScriptRunIterator\28char\20const*\2c\20unsigned\20long\29 +4923:SkShaper::MakeStdLanguageRunIterator\28char\20const*\2c\20unsigned\20long\29 +4924:SkShaders::MatrixRec::concat\28SkMatrix\20const&\29\20const +4925:SkShaders::Blend\28sk_sp\2c\20sk_sp\2c\20sk_sp\29 +4926:SkShaderUtils::VisitLineByLine\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::function\20const&\29 +4927:SkShaderUtils::PrettyPrint\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4928:SkShaderUtils::GLSLPrettyPrint::parseUntil\28char\20const*\29 +4929:SkShaderBlurAlgorithm::renderBlur\28SkRuntimeEffectBuilder*\2c\20SkFilterMode\2c\20SkISize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +4930:SkShaderBlurAlgorithm::evalBlur1D\28float\2c\20int\2c\20SkV2\2c\20sk_sp\2c\20SkIRect\2c\20SkTileMode\2c\20SkIRect\29\20const +4931:SkShaderBlurAlgorithm::Compute2DBlurOffsets\28SkISize\2c\20std::__2::array&\29 +4932:SkShaderBlurAlgorithm::Compute2DBlurKernel\28SkSize\2c\20SkISize\2c\20std::__2::array&\29 +4933:SkShaderBlurAlgorithm::Compute1DBlurLinearKernel\28float\2c\20int\2c\20std::__2::array&\29 +4934:SkShaderBase::getFlattenableType\28\29\20const +4935:SkShaderBase::asLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +4936:SkShader::makeWithColorFilter\28sk_sp\29\20const +4937:SkScan::PathRequiresTiling\28SkIRect\20const&\29 +4938:SkScan::HairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +4939:SkScan::AntiFrameRect\28SkRect\20const&\2c\20SkPoint\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +4940:SkScan::AntiFillXRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +4941:SkScan::AntiFillRect\28SkRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +4942:SkScan::AAAFillPath\28SkPath\20const&\2c\20SkBlitter*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +4943:SkScalerContext_FreeType::updateGlyphBoundsIfSubpixel\28SkGlyph\20const&\2c\20SkRect*\2c\20bool\29 +4944:SkScalerContext_FreeType::shouldSubpixelBitmap\28SkGlyph\20const&\2c\20SkMatrix\20const&\29 +4945:SkScalerContextRec::useStrokeForFakeBold\28\29 +4946:SkScalerContextRec::getSingleMatrix\28SkMatrix*\29\20const +4947:SkScalerContextFTUtils::drawCOLRv1Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +4948:SkScalerContextFTUtils::drawCOLRv0Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +4949:SkScalerContext::internalMakeGlyph\28SkPackedGlyphID\2c\20SkMask::Format\2c\20SkArenaAlloc*\29 +4950:SkScalerContext::internalGetPath\28SkGlyph&\2c\20SkArenaAlloc*\29 +4951:SkScalerContext::getFontMetrics\28SkFontMetrics*\29 +4952:SkScalerContext::SkScalerContext\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +4953:SkScalerContext::PreprocessRec\28SkTypeface\20const&\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const&\29 +4954:SkScalerContext::MakeRecAndEffects\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\2c\20SkScalerContextRec*\2c\20SkScalerContextEffects*\29 +4955:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +4956:SkScalerContext::GetMaskPreBlend\28SkScalerContextRec\20const&\29 +4957:SkScalerContext::AutoDescriptorGivenRecAndEffects\28SkScalerContextRec\20const&\2c\20SkScalerContextEffects\20const&\2c\20SkAutoDescriptor*\29 +4958:SkSampledCodec::sampledDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const&\29 +4959:SkSampledCodec::accountForNativeScaling\28int*\2c\20int*\29\20const +4960:SkSampledCodec::SkSampledCodec\28SkCodec*\29 +4961:SkSL::zero_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\29 +4962:SkSL::type_to_sksltype\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSLType*\29 +4963:SkSL::stoi\28std::__2::basic_string_view>\2c\20long\20long*\29 +4964:SkSL::splat_scalar\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +4965:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_2::operator\28\29\28int\29\20const +4966:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_1::operator\28\29\28int\29\20const +4967:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_0::operator\28\29\28int\29\20const +4968:SkSL::negate_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +4969:SkSL::make_reciprocal_expression\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29 +4970:SkSL::index_out_of_range\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20long\20long\2c\20SkSL::Expression\20const&\29 +4971:SkSL::get_struct_definitions_from_module\28SkSL::Program&\2c\20SkSL::Module\20const&\2c\20std::__2::vector>*\29 +4972:SkSL::find_existing_declaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20SkSL::IntrinsicKind\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray>\2c\20true>&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration**\29::$_0::operator\28\29\28\29\20const +4973:SkSL::extract_matrix\28SkSL::Expression\20const*\2c\20float*\29 +4974:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +4975:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_4::operator\28\29\28int\29\20const +4976:SkSL::\28anonymous\20namespace\29::check_valid_uniform_type\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Context\20const&\2c\20bool\29::$_0::operator\28\29\28\29\20const +4977:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +4978:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +4979:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +4980:SkSL::VariableReference::setRefKind\28SkSL::VariableRefKind\29 +4981:SkSL::Variable::setVarDeclaration\28SkSL::VarDeclaration*\29 +4982:SkSL::Variable::setGlobalVarDeclaration\28SkSL::GlobalVarDeclaration*\29 +4983:SkSL::Variable::globalVarDeclaration\28\29\20const +4984:SkSL::Variable::Make\28SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20std::__2::basic_string_view>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20bool\2c\20SkSL::VariableStorage\29 +4985:SkSL::Variable::MakeScratchVariable\28SkSL::Context\20const&\2c\20SkSL::Mangler&\2c\20std::__2::basic_string_view>\2c\20SkSL::Type\20const*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>\29 +4986:SkSL::VarDeclaration::Make\28SkSL::Context\20const&\2c\20SkSL::Variable*\2c\20SkSL::Type\20const*\2c\20int\2c\20std::__2::unique_ptr>\29 +4987:SkSL::VarDeclaration::ErrorCheck\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Type\20const*\2c\20SkSL::VariableStorage\29 +4988:SkSL::TypeReference::description\28SkSL::OperatorPrecedence\29\20const +4989:SkSL::TypeReference::VerifyType\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Position\29 +4990:SkSL::TypeReference::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\29 +4991:SkSL::Type::MakeStructType\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20bool\29 +4992:SkSL::Type::MakeLiteralType\28char\20const*\2c\20SkSL::Type\20const&\2c\20signed\20char\29 +4993:SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::addDeclaringElement\28SkSL::ProgramElement\20const*\29 +4994:SkSL::Transform::EliminateDeadFunctions\28SkSL::Program&\29 +4995:SkSL::ToGLSL\28SkSL::Program&\2c\20SkSL::ShaderCaps\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\29 +4996:SkSL::TernaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +4997:SkSL::SymbolTable::insertNewParent\28\29 +4998:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Symbol*\29 +4999:SkSL::Swizzle::MaskString\28skia_private::FixedArray<4\2c\20signed\20char>\20const&\29 +5000:SkSL::SwitchStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +5001:SkSL::SwitchCase::Make\28SkSL::Position\2c\20long\20long\2c\20std::__2::unique_ptr>\29 +5002:SkSL::SwitchCase::MakeDefault\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +5003:SkSL::StructType::StructType\28SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20int\2c\20bool\2c\20bool\29 +5004:SkSL::String::vappendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20void*\29 +5005:SkSL::SingleArgumentConstructor::argumentSpan\28\29 +5006:SkSL::RP::stack_usage\28SkSL::RP::Instruction\20const&\29 +5007:SkSL::RP::UnownedLValueSlice::isWritable\28\29\20const +5008:SkSL::RP::UnownedLValueSlice::dynamicSlotRange\28\29 +5009:SkSL::RP::Program::~Program\28\29 +5010:SkSL::RP::LValue::swizzle\28\29 +5011:SkSL::RP::Generator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\29 +5012:SkSL::RP::Generator::writeFunction\28SkSL::IRNode\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSpan>\20const>\29 +5013:SkSL::RP::Generator::storeImmutableValueToSlots\28skia_private::TArray\20const&\2c\20SkSL::RP::SlotRange\29 +5014:SkSL::RP::Generator::pushVariableReferencePartial\28SkSL::VariableReference\20const&\2c\20SkSL::RP::SlotRange\29 +5015:SkSL::RP::Generator::pushPrefixExpression\28SkSL::Operator\2c\20SkSL::Expression\20const&\29 +5016:SkSL::RP::Generator::pushIntrinsic\28SkSL::IntrinsicKind\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +5017:SkSL::RP::Generator::pushImmutableData\28SkSL::Expression\20const&\29 +5018:SkSL::RP::Generator::pushAbsFloatIntrinsic\28int\29 +5019:SkSL::RP::Generator::getImmutableValueForExpression\28SkSL::Expression\20const&\2c\20skia_private::TArray*\29 +5020:SkSL::RP::Generator::foldWithMultiOp\28SkSL::RP::BuilderOp\2c\20int\29 +5021:SkSL::RP::Generator::findPreexistingImmutableData\28skia_private::TArray\20const&\29 +5022:SkSL::RP::Builder::push_slots_or_immutable_indirect\28SkSL::RP::SlotRange\2c\20int\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::BuilderOp\29 +5023:SkSL::RP::Builder::push_condition_mask\28\29 +5024:SkSL::RP::Builder::pad_stack\28int\29 +5025:SkSL::RP::Builder::copy_stack_to_slots\28SkSL::RP::SlotRange\2c\20int\29 +5026:SkSL::RP::Builder::branch_if_any_lanes_active\28int\29 +5027:SkSL::ProgramVisitor::visit\28SkSL::Program\20const&\29 +5028:SkSL::ProgramUsage::remove\28SkSL::Expression\20const*\29 +5029:SkSL::ProgramUsage::add\28SkSL::Statement\20const*\29 +5030:SkSL::ProgramUsage::add\28SkSL::Expression\20const*\29 +5031:SkSL::Pool::attachToThread\28\29 +5032:SkSL::PipelineStage::PipelineStageCodeGenerator::functionName\28SkSL::FunctionDeclaration\20const&\2c\20int\29 +5033:SkSL::PipelineStage::PipelineStageCodeGenerator::functionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +5034:SkSL::PipelineStage::PipelineStageCodeGenerator::forEachSpecialization\28SkSL::FunctionDeclaration\20const&\2c\20std::__2::function\20const&\29 +5035:SkSL::Parser::~Parser\28\29 +5036:SkSL::Parser::varDeclarations\28\29 +5037:SkSL::Parser::varDeclarationsOrExpressionStatement\28\29 +5038:SkSL::Parser::switchCaseBody\28SkSL::ExpressionArray*\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>*\2c\20std::__2::unique_ptr>\29 +5039:SkSL::Parser::statementOrNop\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +5040:SkSL::Parser::shiftExpression\28\29 +5041:SkSL::Parser::relationalExpression\28\29 +5042:SkSL::Parser::parameter\28std::__2::unique_ptr>*\29 +5043:SkSL::Parser::multiplicativeExpression\28\29 +5044:SkSL::Parser::logicalXorExpression\28\29 +5045:SkSL::Parser::logicalAndExpression\28\29 +5046:SkSL::Parser::localVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +5047:SkSL::Parser::intLiteral\28long\20long*\29 +5048:SkSL::Parser::globalVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +5049:SkSL::Parser::equalityExpression\28\29 +5050:SkSL::Parser::directive\28bool\29 +5051:SkSL::Parser::declarations\28\29 +5052:SkSL::Parser::checkNext\28SkSL::Token::Kind\2c\20SkSL::Token*\29 +5053:SkSL::Parser::bitwiseXorExpression\28\29 +5054:SkSL::Parser::bitwiseOrExpression\28\29 +5055:SkSL::Parser::bitwiseAndExpression\28\29 +5056:SkSL::Parser::additiveExpression\28\29 +5057:SkSL::Parser::Parser\28SkSL::Compiler*\2c\20SkSL::ProgramSettings\20const&\2c\20SkSL::ProgramKind\2c\20std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20std::__2::default_delete\2c\20std::__2::allocator>>>\29 +5058:SkSL::MultiArgumentConstructor::argumentSpan\28\29 +5059:SkSL::ModuleTypeToString\28SkSL::ModuleType\29 +5060:SkSL::ModuleLoader::~ModuleLoader\28\29 +5061:SkSL::ModuleLoader::loadPublicModule\28SkSL::Compiler*\29 +5062:SkSL::ModuleLoader::Get\28\29 +5063:SkSL::MatrixType::bitWidth\28\29\20const +5064:SkSL::MakeRasterPipelineProgram\28SkSL::Program\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSL::DebugTracePriv*\2c\20bool\29 +5065:SkSL::Layout::description\28\29\20const +5066:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_length\28std::__2::array\20const&\29 +5067:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_add\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +5068:SkSL::InterfaceBlock::~InterfaceBlock\28\29 +5069:SkSL::Inliner::candidateCanBeInlined\28SkSL::InlineCandidate\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20skia_private::THashMap*\29 +5070:SkSL::IfStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +5071:SkSL::GLSLCodeGenerator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\2c\20bool\29 +5072:SkSL::GLSLCodeGenerator::writeProgramElement\28SkSL::ProgramElement\20const&\29 +5073:SkSL::GLSLCodeGenerator::writeMinAbsHack\28SkSL::Expression&\2c\20SkSL::Expression&\29 +5074:SkSL::GLSLCodeGenerator::generateCode\28\29 +5075:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::visitStatementPtr\28std::__2::unique_ptr>&\29 +5076:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::addLocalVariable\28SkSL::Variable\20const*\2c\20SkSL::Position\29 +5077:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29_6960 +5078:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29 +5079:SkSL::FunctionDeclaration::mangledName\28\29\20const +5080:SkSL::FunctionDeclaration::determineFinalTypes\28SkSL::ExpressionArray\20const&\2c\20skia_private::STArray<8\2c\20SkSL::Type\20const*\2c\20true>*\2c\20SkSL::Type\20const**\29\20const +5081:SkSL::FunctionDeclaration::FunctionDeclaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20SkSL::Type\20const*\2c\20SkSL::IntrinsicKind\29 +5082:SkSL::FunctionDebugInfo*\20std::__2::vector>::__push_back_slow_path\28SkSL::FunctionDebugInfo&&\29 +5083:SkSL::FunctionCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +5084:SkSL::FunctionCall::FindBestFunctionForCall\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const*\2c\20SkSL::ExpressionArray\20const&\29 +5085:SkSL::FunctionCall::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +5086:SkSL::ForStatement::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +5087:SkSL::FindIntrinsicKind\28std::__2::basic_string_view>\29 +5088:SkSL::FieldAccess::~FieldAccess\28\29_6847 +5089:SkSL::FieldAccess::~FieldAccess\28\29 +5090:SkSL::ExpressionStatement::Convert\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +5091:SkSL::DoStatement::~DoStatement\28\29_6830 +5092:SkSL::DoStatement::~DoStatement\28\29 +5093:SkSL::DebugTracePriv::setSource\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +5094:SkSL::ConstructorScalarCast::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +5095:SkSL::ConstructorMatrixResize::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +5096:SkSL::Constructor::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +5097:SkSL::ConstantFolder::Simplify\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +5098:SkSL::Compiler::writeErrorCount\28\29 +5099:SkSL::Compiler::initializeContext\28SkSL::Module\20const*\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\2c\20std::__2::basic_string_view>\2c\20SkSL::ModuleType\29 +5100:SkSL::Compiler::cleanupContext\28\29 +5101:SkSL::ChildCall::~ChildCall\28\29_6765 +5102:SkSL::ChildCall::~ChildCall\28\29 +5103:SkSL::ChildCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Variable\20const&\2c\20SkSL::ExpressionArray\29 +5104:SkSL::BinaryExpression::isAssignmentIntoVariable\28\29 +5105:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\2c\20SkSL::Type\20const*\29 +5106:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29 +5107:SkSL::Analysis::IsConstantExpression\28SkSL::Expression\20const&\29 +5108:SkSL::Analysis::IsAssignable\28SkSL::Expression&\2c\20SkSL::Analysis::AssignmentInfo*\2c\20SkSL::ErrorReporter*\29 +5109:SkSL::Analysis::GetLoopUnrollInfo\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\20const&\2c\20SkSL::Statement\20const*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Expression\20const*\2c\20SkSL::Statement\20const*\2c\20SkSL::ErrorReporter*\29 +5110:SkSL::Analysis::GetLoopControlFlowInfo\28SkSL::Statement\20const&\29 +5111:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +5112:SkSL::AliasType::numberKind\28\29\20const +5113:SkSL::AliasType::isOrContainsBool\28\29\20const +5114:SkSL::AliasType::isOrContainsAtomic\28\29\20const +5115:SkSL::AliasType::isAllowedInES2\28\29\20const +5116:SkRuntimeShader::~SkRuntimeShader\28\29 +5117:SkRuntimeEffectPriv::WriteChildEffects\28SkWriteBuffer&\2c\20SkSpan\29 +5118:SkRuntimeEffectPriv::TransformUniforms\28SkSpan\2c\20sk_sp\2c\20SkColorSpaceXformSteps\20const&\29 +5119:SkRuntimeEffect::~SkRuntimeEffect\28\29 +5120:SkRuntimeEffect::makeShader\28sk_sp\2c\20sk_sp*\2c\20unsigned\20long\2c\20SkMatrix\20const*\29\20const +5121:SkRuntimeEffect::makeColorFilter\28sk_sp\2c\20SkSpan\29\20const +5122:SkRuntimeEffect::TracedShader*\20emscripten::internal::raw_constructor\28\29 +5123:SkRuntimeEffect::MakeInternal\28std::__2::unique_ptr>\2c\20SkRuntimeEffect::Options\20const&\2c\20SkSL::ProgramKind\29 +5124:SkRuntimeEffect::ChildPtr&\20skia_private::TArray::emplace_back&>\28sk_sp&\29 +5125:SkRuntimeBlender::flatten\28SkWriteBuffer&\29\20const +5126:SkRgnBuilder::~SkRgnBuilder\28\29 +5127:SkResourceCache::PostPurgeSharedID\28unsigned\20long\20long\29 +5128:SkResourceCache::GetDiscardableFactory\28\29 +5129:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::rowBytes\28int\29\20const +5130:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +5131:SkRegion::Spanerator::Spanerator\28SkRegion\20const&\2c\20int\2c\20int\2c\20int\29 +5132:SkRegion::Oper\28SkRegion\20const&\2c\20SkRegion\20const&\2c\20SkRegion::Op\2c\20SkRegion*\29 +5133:SkRefCntSet::~SkRefCntSet\28\29 +5134:SkRefCntBase::internal_dispose\28\29\20const +5135:SkReduceOrder::reduce\28SkDQuad\20const&\29 +5136:SkReduceOrder::Conic\28SkConic\20const&\2c\20SkPoint*\29 +5137:SkRectClipBlitter::requestRowsPreserved\28\29\20const +5138:SkRectClipBlitter::allocBlitMemory\28unsigned\20long\29 +5139:SkRect::intersect\28SkRect\20const&\2c\20SkRect\20const&\29 +5140:SkRecords::TypedMatrix::TypedMatrix\28SkMatrix\20const&\29 +5141:SkRecordOptimize\28SkRecord*\29 +5142:SkRecordFillBounds\28SkRect\20const&\2c\20SkRecord\20const&\2c\20SkRect*\2c\20SkBBoxHierarchy::Metadata*\29 +5143:SkRecord::bytesUsed\28\29\20const +5144:SkReadPixelsRec::trim\28int\2c\20int\29 +5145:SkReadBuffer::setDeserialProcs\28SkDeserialProcs\20const&\29 +5146:SkReadBuffer::readString\28unsigned\20long*\29 +5147:SkReadBuffer::readRegion\28SkRegion*\29 +5148:SkReadBuffer::readRect\28\29 +5149:SkReadBuffer::readPoint3\28SkPoint3*\29 +5150:SkReadBuffer::readPad32\28void*\2c\20unsigned\20long\29 +5151:SkReadBuffer::readArray\28void*\2c\20unsigned\20long\2c\20unsigned\20long\29 +5152:SkRasterPipeline::tailPointer\28\29 +5153:SkRasterPipeline::appendSetRGB\28SkArenaAlloc*\2c\20float\20const*\29 +5154:SkRasterPipeline::addMemoryContext\28SkRasterPipeline_MemoryCtx*\2c\20int\2c\20bool\2c\20bool\29 +5155:SkRasterClipStack::SkRasterClipStack\28int\2c\20int\29 +5156:SkRTreeFactory::operator\28\29\28\29\20const +5157:SkRTree::search\28SkRTree::Node*\2c\20SkRect\20const&\2c\20std::__2::vector>*\29\20const +5158:SkRTree::bulkLoad\28std::__2::vector>*\2c\20int\29 +5159:SkRTree::allocateNodeAtLevel\28unsigned\20short\29 +5160:SkRSXform::toQuad\28float\2c\20float\2c\20SkPoint*\29\20const +5161:SkRRect::isValid\28\29\20const +5162:SkRRect::computeType\28\29 +5163:SkRGBA4f<\28SkAlphaType\292>\20skgpu::Swizzle::applyTo<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\29\20const +5164:SkRBuffer::skipToAlign4\28\29 +5165:SkQuads::EvalAt\28double\2c\20double\2c\20double\2c\20double\29 +5166:SkQuadraticEdge::setQuadraticWithoutUpdate\28SkPoint\20const*\2c\20int\29 +5167:SkPtrSet::reset\28\29 +5168:SkPtrSet::copyToArray\28void**\29\20const +5169:SkPtrSet::add\28void*\29 +5170:SkPoint::Normalize\28SkPoint*\29 +5171:SkPngEncoder::Encode\28GrDirectContext*\2c\20SkImage\20const*\2c\20SkPngEncoder::Options\20const&\29 +5172:SkPngDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +5173:SkPngCodecBase::initializeXformParams\28\29 +5174:SkPngCodecBase::initializeSwizzler\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20bool\2c\20int\29 +5175:SkPngCodecBase::SkPngCodecBase\28SkEncodedInfo&&\2c\20std::__2::unique_ptr>\29 +5176:SkPngCodec::initializeXforms\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +5177:SkPixmapUtils::Orient\28SkPixmap\20const&\2c\20SkPixmap\20const&\2c\20SkEncodedOrigin\29 +5178:SkPixmap::erase\28unsigned\20int\2c\20SkIRect\20const&\29\20const +5179:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const +5180:SkPixelRef::getGenerationID\28\29\20const +5181:SkPixelRef::addGenIDChangeListener\28sk_sp\29 +5182:SkPixelRef::SkPixelRef\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +5183:SkPictureShader::CachedImageInfo::makeImage\28sk_sp\2c\20SkPicture\20const*\29\20const +5184:SkPictureShader::CachedImageInfo::Make\28SkRect\20const&\2c\20SkMatrix\20const&\2c\20SkColorType\2c\20SkColorSpace*\2c\20int\2c\20SkSurfaceProps\20const&\29 +5185:SkPictureRecord::endRecording\28\29 +5186:SkPictureRecord::beginRecording\28\29 +5187:SkPicturePriv::Flatten\28sk_sp\2c\20SkWriteBuffer&\29 +5188:SkPicturePlayback::draw\28SkCanvas*\2c\20SkPicture::AbortCallback*\2c\20SkReadBuffer*\29 +5189:SkPictureData::parseBufferTag\28SkReadBuffer&\2c\20unsigned\20int\2c\20unsigned\20int\29 +5190:SkPictureData::getPicture\28SkReadBuffer*\29\20const +5191:SkPictureData::getDrawable\28SkReadBuffer*\29\20const +5192:SkPictureData::flatten\28SkWriteBuffer&\29\20const +5193:SkPictureData::flattenToBuffer\28SkWriteBuffer&\2c\20bool\29\20const +5194:SkPictureData::SkPictureData\28SkPictureRecord\20const&\2c\20SkPictInfo\20const&\29 +5195:SkPicture::backport\28\29\20const +5196:SkPicture::SkPicture\28\29 +5197:SkPicture::MakeFromStreamPriv\28SkStream*\2c\20SkDeserialProcs\20const*\2c\20SkTypefacePlayback*\2c\20int\29 +5198:SkPerlinNoiseShader::type\28\29\20const +5199:SkPerlinNoiseShader::getPaintingData\28\29\20const +5200:SkPathWriter::assemble\28\29 +5201:SkPathWriter::SkPathWriter\28SkPath&\29 +5202:SkPathRef::resetToSize\28int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +5203:SkPathRef::SkPathRef\28SkSpan\2c\20SkSpan\2c\20SkSpan\2c\20unsigned\20int\29 +5204:SkPathPriv::IsNestedFillRects\28SkPath\20const&\2c\20SkRect*\2c\20SkPathDirection*\29 +5205:SkPathPriv::CreateDrawArcPath\28SkPath*\2c\20SkArc\20const&\2c\20bool\29 +5206:SkPathEffectBase::PointData::~PointData\28\29 +5207:SkPathEffect::filterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +5208:SkPathBuilder::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +5209:SkPath::writeToMemoryAsRRect\28void*\29\20const +5210:SkPath::setLastPt\28float\2c\20float\29 +5211:SkPath::reverseAddPath\28SkPath\20const&\29 +5212:SkPath::readFromMemory\28void\20const*\2c\20unsigned\20long\29 +5213:SkPath::offset\28float\2c\20float\2c\20SkPath*\29\20const +5214:SkPath::isZeroLengthSincePoint\28int\29\20const +5215:SkPath::isRRect\28SkRRect*\29\20const +5216:SkPath::isOval\28SkRect*\29\20const +5217:SkPath::conservativelyContainsRect\28SkRect\20const&\29\20const +5218:SkPath::computeConvexity\28\29\20const +5219:SkPath::addPath\28SkPath\20const&\2c\20float\2c\20float\2c\20SkPath::AddPathMode\29 +5220:SkPath::Polygon\28SkPoint\20const*\2c\20int\2c\20bool\2c\20SkPathFillType\2c\20bool\29 +5221:SkPath2DPathEffect::Make\28SkMatrix\20const&\2c\20SkPath\20const&\29 +5222:SkParsePath::ToSVGString\28SkPath\20const&\2c\20SkParsePath::PathEncoding\29::$_0::operator\28\29\28char\2c\20SkPoint\20const*\2c\20unsigned\20long\29\20const +5223:SkParseEncodedOrigin\28void\20const*\2c\20unsigned\20long\2c\20SkEncodedOrigin*\29 +5224:SkPaintPriv::ShouldDither\28SkPaint\20const&\2c\20SkColorType\29 +5225:SkPaintPriv::Overwrites\28SkPaint\20const*\2c\20SkPaintPriv::ShaderOverrideOpacity\29 +5226:SkPaint::setStroke\28bool\29 +5227:SkPaint::reset\28\29 +5228:SkPaint::refColorFilter\28\29\20const +5229:SkOpSpanBase::merge\28SkOpSpan*\29 +5230:SkOpSpanBase::globalState\28\29\20const +5231:SkOpSpan::sortableTop\28SkOpContour*\29 +5232:SkOpSpan::release\28SkOpPtT\20const*\29 +5233:SkOpSpan::insertCoincidence\28SkOpSegment\20const*\2c\20bool\2c\20bool\29 +5234:SkOpSpan::init\28SkOpSegment*\2c\20SkOpSpan*\2c\20double\2c\20SkPoint\20const&\29 +5235:SkOpSegment::updateWindingReverse\28SkOpAngle\20const*\29 +5236:SkOpSegment::oppXor\28\29\20const +5237:SkOpSegment::moveMultiples\28\29 +5238:SkOpSegment::isXor\28\29\20const +5239:SkOpSegment::computeSum\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpAngle::IncludeType\29 +5240:SkOpSegment::collapsed\28double\2c\20double\29\20const +5241:SkOpSegment::addExpanded\28double\2c\20SkOpSpanBase\20const*\2c\20bool*\29 +5242:SkOpSegment::activeAngle\28SkOpSpanBase*\2c\20SkOpSpanBase**\2c\20SkOpSpanBase**\2c\20bool*\29 +5243:SkOpSegment::UseInnerWinding\28int\2c\20int\29 +5244:SkOpPtT::ptAlreadySeen\28SkOpPtT\20const*\29\20const +5245:SkOpPtT::contains\28SkOpSegment\20const*\2c\20double\29\20const +5246:SkOpGlobalState::SkOpGlobalState\28SkOpContourHead*\2c\20SkArenaAlloc*\29 +5247:SkOpEdgeBuilder::preFetch\28\29 +5248:SkOpEdgeBuilder::init\28\29 +5249:SkOpEdgeBuilder::finish\28\29 +5250:SkOpContourBuilder::addConic\28SkPoint*\2c\20float\29 +5251:SkOpContour::addQuad\28SkPoint*\29 +5252:SkOpContour::addCubic\28SkPoint*\29 +5253:SkOpContour::addConic\28SkPoint*\2c\20float\29 +5254:SkOpCoincidence::release\28SkOpSegment\20const*\29 +5255:SkOpCoincidence::mark\28\29 +5256:SkOpCoincidence::markCollapsed\28SkCoincidentSpans*\2c\20SkOpPtT*\29 +5257:SkOpCoincidence::fixUp\28SkCoincidentSpans*\2c\20SkOpPtT*\2c\20SkOpPtT\20const*\29 +5258:SkOpCoincidence::contains\28SkCoincidentSpans\20const*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\29\20const +5259:SkOpCoincidence::checkOverlap\28SkCoincidentSpans*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20SkTDArray*\29\20const +5260:SkOpCoincidence::addOrOverlap\28SkOpSegment*\2c\20SkOpSegment*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20bool*\29 +5261:SkOpAngle::tangentsDiverge\28SkOpAngle\20const*\2c\20double\29 +5262:SkOpAngle::setSpans\28\29 +5263:SkOpAngle::setSector\28\29 +5264:SkOpAngle::previous\28\29\20const +5265:SkOpAngle::midToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +5266:SkOpAngle::loopCount\28\29\20const +5267:SkOpAngle::loopContains\28SkOpAngle\20const*\29\20const +5268:SkOpAngle::lastMarked\28\29\20const +5269:SkOpAngle::endToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +5270:SkOpAngle::alignmentSameSide\28SkOpAngle\20const*\2c\20int*\29\20const +5271:SkOpAngle::after\28SkOpAngle*\29 +5272:SkOffsetSimplePolygon\28SkPoint\20const*\2c\20int\2c\20SkRect\20const&\2c\20float\2c\20SkTDArray*\2c\20SkTDArray*\29 +5273:SkNoDrawCanvas::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +5274:SkNoDrawCanvas::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +5275:SkMipmapBuilder::level\28int\29\20const +5276:SkMipmap::countLevels\28\29\20const +5277:SkMeshSpecification::Varying*\20std::__2::vector>::__push_back_slow_path\28SkMeshSpecification::Varying&&\29 +5278:SkMeshSpecification::Attribute*\20std::__2::vector>::__push_back_slow_path\28SkMeshSpecification::Attribute&&\29 +5279:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2558 +5280:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +5281:SkMeshPriv::CpuBuffer::size\28\29\20const +5282:SkMeshPriv::CpuBuffer::peek\28\29\20const +5283:SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +5284:SkMatrix::setRotate\28float\2c\20float\2c\20float\29 +5285:SkMatrix::mapRectScaleTranslate\28SkRect*\2c\20SkRect\20const&\29\20const +5286:SkMatrix::isFinite\28\29\20const +5287:SkMatrix::RotTrans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +5288:SkMaskSwizzler::swizzle\28void*\2c\20unsigned\20char\20const*\29 +5289:SkMaskFilterBase::NinePatch::~NinePatch\28\29 +5290:SkMask::computeTotalImageSize\28\29\20const +5291:SkMakeResourceCacheSharedIDForBitmap\28unsigned\20int\29 +5292:SkMD5::finish\28\29 +5293:SkMD5::SkMD5\28\29 +5294:SkMD5::Digest::toHexString\28\29\20const +5295:SkM44::preTranslate\28float\2c\20float\2c\20float\29 +5296:SkM44::postTranslate\28float\2c\20float\2c\20float\29 +5297:SkLinearColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +5298:SkLineParameters::cubicEndPoints\28SkDCubic\20const&\29 +5299:SkLatticeIter::SkLatticeIter\28SkCanvas::Lattice\20const&\2c\20SkRect\20const&\29 +5300:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::~SkLRUCache\28\29 +5301:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::reset\28\29 +5302:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::insert\28GrProgramDesc\20const&\2c\20std::__2::unique_ptr>\29 +5303:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_matrix_conv_effect\28SkKnownRuntimeEffects::\28anonymous\20namespace\29::MatrixConvolutionImpl\2c\20SkRuntimeEffect::Options\20const&\29::$_0::operator\28\29\28int\2c\20SkRuntimeEffect::Options\20const&\29\20const +5304:SkJpegMetadataDecoderImpl::SkJpegMetadataDecoderImpl\28std::__2::vector>\29 +5305:SkJpegDecoder::IsJpeg\28void\20const*\2c\20unsigned\20long\29 +5306:SkJpegCodec::readRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20SkCodec::Options\20const&\2c\20int*\29 +5307:SkJpegCodec::initializeSwizzler\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20bool\29 +5308:SkJSONWriter::appendString\28char\20const*\2c\20unsigned\20long\29 +5309:SkIsSimplePolygon\28SkPoint\20const*\2c\20int\29 +5310:SkInvert4x4Matrix\28float\20const*\2c\20float*\29 +5311:SkInvert3x3Matrix\28float\20const*\2c\20float*\29 +5312:SkInvert2x2Matrix\28float\20const*\2c\20float*\29 +5313:SkIntersections::vertical\28SkDQuad\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5314:SkIntersections::vertical\28SkDLine\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5315:SkIntersections::vertical\28SkDCubic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5316:SkIntersections::vertical\28SkDConic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5317:SkIntersections::mostOutside\28double\2c\20double\2c\20SkDPoint\20const&\29\20const +5318:SkIntersections::intersect\28SkDQuad\20const&\2c\20SkDLine\20const&\29 +5319:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDQuad\20const&\29 +5320:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDLine\20const&\29 +5321:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDConic\20const&\29 +5322:SkIntersections::intersect\28SkDConic\20const&\2c\20SkDQuad\20const&\29 +5323:SkIntersections::intersect\28SkDConic\20const&\2c\20SkDLine\20const&\29 +5324:SkIntersections::insertCoincident\28double\2c\20double\2c\20SkDPoint\20const&\29 +5325:SkIntersections::horizontal\28SkDQuad\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5326:SkIntersections::horizontal\28SkDLine\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5327:SkIntersections::horizontal\28SkDCubic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5328:SkIntersections::horizontal\28SkDConic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5329:SkImages::RasterFromPixmap\28SkPixmap\20const&\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +5330:SkImages::RasterFromData\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\29 +5331:SkImages::DeferredFromGenerator\28std::__2::unique_ptr>\29 +5332:SkImage_Raster::onPeekMips\28\29\20const +5333:SkImage_Lazy::~SkImage_Lazy\28\29_4622 +5334:SkImage_Lazy::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +5335:SkImage_GaneshBase::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +5336:SkImage_Base::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +5337:SkImage_Base::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +5338:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_1::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +5339:SkImageInfo::validRowBytes\28unsigned\20long\29\20const +5340:SkImageInfo::MakeN32Premul\28int\2c\20int\29 +5341:SkImageGenerator::~SkImageGenerator\28\29_901 +5342:SkImageFilters::ColorFilter\28sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +5343:SkImageFilter_Base::getCTMCapability\28\29\20const +5344:SkImageFilterCache::Get\28SkImageFilterCache::CreateIfNecessary\29 +5345:SkImageFilter::computeFastBounds\28SkRect\20const&\29\20const +5346:SkImage::withMipmaps\28sk_sp\29\20const +5347:SkImage::peekPixels\28SkPixmap*\29\20const +5348:SkImage::height\28\29\20const +5349:SkIcuBreakIteratorCache::purgeIfNeeded\28\29 +5350:SkIcoDecoder::IsIco\28void\20const*\2c\20unsigned\20long\29 +5351:SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29 +5352:SkGradientBaseShader::~SkGradientBaseShader\28\29 +5353:SkGradientBaseShader::AppendGradientFillStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const*\2c\20float\20const*\2c\20int\29 +5354:SkGlyphRunListPainterCPU::SkGlyphRunListPainterCPU\28SkSurfaceProps\20const&\2c\20SkColorType\2c\20SkColorSpace*\29 +5355:SkGlyph::setImage\28SkArenaAlloc*\2c\20SkScalerContext*\29 +5356:SkGlyph::setDrawable\28SkArenaAlloc*\2c\20SkScalerContext*\29 +5357:SkGlyph::pathIsHairline\28\29\20const +5358:SkGlyph::mask\28SkPoint\29\20const +5359:SkGifDecoder::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::SelectionPolicy\2c\20SkCodec::Result*\29 +5360:SkGifDecoder::IsGif\28void\20const*\2c\20unsigned\20long\29 +5361:SkGenerateDistanceFieldFromA8Image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20unsigned\20long\29 +5362:SkGaussFilter::SkGaussFilter\28double\29 +5363:SkFrameHolder::setAlphaAndRequiredFrame\28SkFrame*\29 +5364:SkFrame::fillIn\28SkCodec::FrameInfo*\2c\20bool\29\20const +5365:SkFontStyleSet_Custom::appendTypeface\28sk_sp\29 +5366:SkFontStyleSet_Custom::SkFontStyleSet_Custom\28SkString\29 +5367:SkFontScanner_FreeType::scanInstance\28SkStreamAsset*\2c\20int\2c\20int\2c\20SkString*\2c\20SkFontStyle*\2c\20bool*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\2c\20skia_private::STArray<4\2c\20SkFontArguments::VariationPosition::Coordinate\2c\20true>*\29\20const +5368:SkFontScanner_FreeType::computeAxisValues\28skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>\20const&\2c\20SkFontArguments::VariationPosition\2c\20SkFontArguments::VariationPosition\2c\20int*\2c\20SkString\20const&\2c\20SkFontStyle*\29 +5369:SkFontPriv::GetFontBounds\28SkFont\20const&\29 +5370:SkFontMgr_Custom::onMakeFromStreamArgs\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29\20const +5371:SkFontMgr::matchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +5372:SkFontMgr::makeFromStream\28std::__2::unique_ptr>\2c\20int\29\20const +5373:SkFontMgr::makeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29\20const +5374:SkFontMgr::legacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +5375:SkFontDescriptor::SkFontStyleWidthForWidthAxisValue\28float\29 +5376:SkFontDescriptor::SkFontDescriptor\28\29 +5377:SkFont::setupForAsPaths\28SkPaint*\29 +5378:SkFont::setSkewX\28float\29 +5379:SkFont::setLinearMetrics\28bool\29 +5380:SkFont::setEmbolden\28bool\29 +5381:SkFont::operator==\28SkFont\20const&\29\20const +5382:SkFont::getPaths\28unsigned\20short\20const*\2c\20int\2c\20void\20\28*\29\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29\2c\20void*\29\20const +5383:SkFlattenable::RegisterFlattenablesIfNeeded\28\29 +5384:SkFlattenable::PrivateInitializer::InitEffects\28\29 +5385:SkFlattenable::NameToFactory\28char\20const*\29 +5386:SkFlattenable::FactoryToName\28sk_sp\20\28*\29\28SkReadBuffer&\29\29 +5387:SkFindQuadExtrema\28float\2c\20float\2c\20float\2c\20float*\29 +5388:SkFindCubicExtrema\28float\2c\20float\2c\20float\2c\20float\2c\20float*\29 +5389:SkFactorySet::~SkFactorySet\28\29 +5390:SkEmptyPicture::approximateBytesUsed\28\29\20const +5391:SkEdgeClipper::clipQuad\28SkPoint\20const*\2c\20SkRect\20const&\29 +5392:SkEdgeClipper::ClipPath\28SkPath\20const&\2c\20SkRect\20const&\2c\20bool\2c\20void\20\28*\29\28SkEdgeClipper*\2c\20bool\2c\20void*\29\2c\20void*\29 +5393:SkEdgeBuilder::buildEdges\28SkPath\20const&\2c\20SkIRect\20const*\29 +5394:SkDynamicMemoryWStream::bytesWritten\28\29\20const +5395:SkDrawableList::newDrawableSnapshot\28\29 +5396:SkDrawTreatAAStrokeAsHairline\28float\2c\20SkMatrix\20const&\2c\20float*\29 +5397:SkDrawShadowMetrics::GetSpotShadowTransform\28SkPoint3\20const&\2c\20float\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkRect\20const&\2c\20bool\2c\20SkMatrix*\2c\20float*\29 +5398:SkDrawShadowMetrics::GetLocalBounds\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect*\29 +5399:SkDrawBase::drawPaint\28SkPaint\20const&\29\20const +5400:SkDrawBase::DrawToMask\28SkPath\20const&\2c\20SkIRect\20const&\2c\20SkMaskFilter\20const*\2c\20SkMatrix\20const*\2c\20SkMaskBuilder*\2c\20SkMaskBuilder::CreateMode\2c\20SkStrokeRec::InitStyle\29 +5401:SkDraw::drawSprite\28SkBitmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29\20const +5402:SkDiscretePathEffectImpl::flatten\28SkWriteBuffer&\29\20const +5403:SkDiscretePathEffect::Make\28float\2c\20float\2c\20unsigned\20int\29 +5404:SkDevice::getRelativeTransform\28SkDevice\20const&\29\20const +5405:SkDevice::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +5406:SkDevice::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +5407:SkDevice::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +5408:SkDevice::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +5409:SkDescriptor::addEntry\28unsigned\20int\2c\20unsigned\20long\2c\20void\20const*\29 +5410:SkDeque::Iter::next\28\29 +5411:SkDeque::Iter::Iter\28SkDeque\20const&\2c\20SkDeque::Iter::IterStart\29 +5412:SkData::MakeSubset\28SkData\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +5413:SkDashPath::InternalFilter\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20float\20const*\2c\20int\2c\20float\2c\20int\2c\20float\2c\20float\2c\20SkDashPath::StrokeRecApplication\29 +5414:SkDashPath::CalcDashParameters\28float\2c\20float\20const*\2c\20int\2c\20float*\2c\20int*\2c\20float*\2c\20float*\29 +5415:SkDRect::setBounds\28SkDQuad\20const&\2c\20SkDQuad\20const&\2c\20double\2c\20double\29 +5416:SkDRect::setBounds\28SkDCubic\20const&\2c\20SkDCubic\20const&\2c\20double\2c\20double\29 +5417:SkDRect::setBounds\28SkDConic\20const&\2c\20SkDConic\20const&\2c\20double\2c\20double\29 +5418:SkDQuad::subDivide\28double\2c\20double\29\20const +5419:SkDQuad::monotonicInY\28\29\20const +5420:SkDQuad::isLinear\28int\2c\20int\29\20const +5421:SkDQuad::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +5422:SkDPoint::approximatelyDEqual\28SkDPoint\20const&\29\20const +5423:SkDCurveSweep::setCurveHullSweep\28SkPath::Verb\29 +5424:SkDCurve::nearPoint\28SkPath::Verb\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29\20const +5425:SkDCubic::monotonicInX\28\29\20const +5426:SkDCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +5427:SkDCubic::hullIntersects\28SkDPoint\20const*\2c\20int\2c\20bool*\29\20const +5428:SkDConic::subDivide\28double\2c\20double\29\20const +5429:SkCubics::RootsReal\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +5430:SkCubicEdge::setCubicWithoutUpdate\28SkPoint\20const*\2c\20int\2c\20bool\29 +5431:SkCubicClipper::ChopMonoAtY\28SkPoint\20const*\2c\20float\2c\20float*\29 +5432:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20SkArenaAlloc*\2c\20sk_sp\29 +5433:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkArenaAlloc*\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +5434:SkContourMeasureIter::~SkContourMeasureIter\28\29 +5435:SkContourMeasureIter::SkContourMeasureIter\28SkPath\20const&\2c\20bool\2c\20float\29 +5436:SkContourMeasure::length\28\29\20const +5437:SkContourMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29\20const +5438:SkConic::BuildUnitArc\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkRotationDirection\2c\20SkMatrix\20const*\2c\20SkConic*\29 +5439:SkComputeRadialSteps\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float*\2c\20float*\2c\20int*\29 +5440:SkCompressedDataSize\28SkTextureCompressionType\2c\20SkISize\2c\20skia_private::TArray*\2c\20bool\29 +5441:SkColorTypeValidateAlphaType\28SkColorType\2c\20SkAlphaType\2c\20SkAlphaType*\29 +5442:SkColorToPMColor4f\28unsigned\20int\2c\20GrColorInfo\20const&\29 +5443:SkColorSpaceLuminance::Fetch\28float\29 +5444:SkColorSpace::toProfile\28skcms_ICCProfile*\29\20const +5445:SkColorSpace::makeLinearGamma\28\29\20const +5446:SkColorSpace::isSRGB\28\29\20const +5447:SkColorMatrix_RGB2YUV\28SkYUVColorSpace\2c\20float*\29 +5448:SkColorInfo::makeColorSpace\28sk_sp\29\20const +5449:SkColorFilterShader::Make\28sk_sp\2c\20float\2c\20sk_sp\29 +5450:SkColor4fXformer::SkColor4fXformer\28SkGradientBaseShader\20const*\2c\20SkColorSpace*\2c\20bool\29 +5451:SkCoincidentSpans::extend\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\29 +5452:SkCodecs::get_decoders_for_editing\28\29 +5453:SkCodec::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +5454:SkCodec::initializeColorXform\28SkImageInfo\20const&\2c\20SkEncodedInfo::Alpha\2c\20bool\29 +5455:SkChopQuadAtMaxCurvature\28SkPoint\20const*\2c\20SkPoint*\29 +5456:SkChopQuadAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +5457:SkChopMonoCubicAtX\28SkPoint\20const*\2c\20float\2c\20SkPoint*\29 +5458:SkChopCubicAtInflections\28SkPoint\20const*\2c\20SkPoint*\29 +5459:SkCharToGlyphCache::findGlyphIndex\28int\29\20const +5460:SkCanvasPriv::WriteLattice\28void*\2c\20SkCanvas::Lattice\20const&\29 +5461:SkCanvasPriv::ReadLattice\28SkReadBuffer&\2c\20SkCanvas::Lattice*\29 +5462:SkCanvasPriv::GetDstClipAndMatrixCounts\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20int*\2c\20int*\29 +5463:SkCanvas::~SkCanvas\28\29 +5464:SkCanvas::skew\28float\2c\20float\29 +5465:SkCanvas::only_axis_aligned_saveBehind\28SkRect\20const*\29 +5466:SkCanvas::getDeviceClipBounds\28\29\20const +5467:SkCanvas::experimental_DrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +5468:SkCanvas::drawVertices\28sk_sp\20const&\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +5469:SkCanvas::drawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +5470:SkCanvas::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +5471:SkCanvas::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +5472:SkCanvas::drawImageNine\28SkImage\20const*\2c\20SkIRect\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +5473:SkCanvas::drawClippedToSaveBehind\28SkPaint\20const&\29 +5474:SkCanvas::drawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +5475:SkCanvas::didTranslate\28float\2c\20float\29 +5476:SkCanvas::clipShader\28sk_sp\2c\20SkClipOp\29 +5477:SkCanvas::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +5478:SkCanvas::SkCanvas\28sk_sp\29 +5479:SkCanvas::ImageSetEntry::ImageSetEntry\28\29 +5480:SkCachedData::SkCachedData\28void*\2c\20unsigned\20long\29 +5481:SkCachedData::SkCachedData\28unsigned\20long\2c\20SkDiscardableMemory*\29 +5482:SkCTMShader::isOpaque\28\29\20const +5483:SkBulkGlyphMetricsAndPaths::glyphs\28SkSpan\29 +5484:SkBmpStandardCodec::decodeIcoMask\28SkStream*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\29 +5485:SkBmpMaskCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +5486:SkBmpDecoder::IsBmp\28void\20const*\2c\20unsigned\20long\29 +5487:SkBmpCodec::SkBmpCodec\28SkEncodedInfo&&\2c\20std::__2::unique_ptr>\2c\20unsigned\20short\2c\20SkCodec::SkScanlineOrder\29 +5488:SkBmpBaseCodec::SkBmpBaseCodec\28SkEncodedInfo&&\2c\20std::__2::unique_ptr>\2c\20unsigned\20short\2c\20SkCodec::SkScanlineOrder\29 +5489:SkBlurMask::ConvertRadiusToSigma\28float\29 +5490:SkBlurMask::ComputeBlurredScanline\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20unsigned\20int\2c\20float\29 +5491:SkBlurMask::BlurRect\28float\2c\20SkMaskBuilder*\2c\20SkRect\20const&\2c\20SkBlurStyle\2c\20SkIPoint*\2c\20SkMaskBuilder::CreateMode\29 +5492:SkBlurEngine::GetRasterBlurEngine\28\29 +5493:SkBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +5494:SkBlitter::Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +5495:SkBlitter::ChooseSprite\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkArenaAlloc*\2c\20sk_sp\29 +5496:SkBlenderBase::asBlendMode\28\29\20const +5497:SkBlenderBase::affectsTransparentBlack\28\29\20const +5498:SkBlendShader::~SkBlendShader\28\29_4721 +5499:SkBlendShader::~SkBlendShader\28\29 +5500:SkBitmapImageGetPixelRef\28SkImage\20const*\29 +5501:SkBitmapDevice::SkBitmapDevice\28SkBitmap\20const&\2c\20SkSurfaceProps\20const&\2c\20void*\29 +5502:SkBitmapCache::Rec::install\28SkBitmap*\29 +5503:SkBitmapCache::Rec::diagnostic_only_getDiscardable\28\29\20const +5504:SkBitmapCache::Find\28SkBitmapCacheDesc\20const&\2c\20SkBitmap*\29 +5505:SkBitmapCache::Alloc\28SkBitmapCacheDesc\20const&\2c\20SkImageInfo\20const&\2c\20SkPixmap*\29 +5506:SkBitmapCache::Add\28std::__2::unique_ptr\2c\20SkBitmap*\29 +5507:SkBitmap::setPixelRef\28sk_sp\2c\20int\2c\20int\29 +5508:SkBitmap::setAlphaType\28SkAlphaType\29 +5509:SkBitmap::reset\28\29 +5510:SkBitmap::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\29\20const +5511:SkBitmap::getAddr\28int\2c\20int\29\20const +5512:SkBitmap::allocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29::$_0::operator\28\29\28\29\20const +5513:SkBitmap::HeapAllocator::allocPixelRef\28SkBitmap*\29 +5514:SkBinaryWriteBuffer::writeFlattenable\28SkFlattenable\20const*\29 +5515:SkBinaryWriteBuffer::writeColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +5516:SkBigPicture::SkBigPicture\28SkRect\20const&\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20sk_sp\2c\20unsigned\20long\29 +5517:SkBezierQuad::IntersectWithHorizontalLine\28SkSpan\2c\20float\2c\20float*\29 +5518:SkBezierCubic::IntersectWithHorizontalLine\28SkSpan\2c\20float\2c\20float*\29 +5519:SkBasicEdgeBuilder::~SkBasicEdgeBuilder\28\29 +5520:SkBaseShadowTessellator::finishPathPolygon\28\29 +5521:SkBaseShadowTessellator::computeConvexShadow\28float\2c\20float\2c\20bool\29 +5522:SkBaseShadowTessellator::computeConcaveShadow\28float\2c\20float\29 +5523:SkBaseShadowTessellator::clipUmbraPoint\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint*\29 +5524:SkBaseShadowTessellator::addInnerPoint\28SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20int*\29 +5525:SkBaseShadowTessellator::addEdge\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20bool\2c\20bool\29 +5526:SkBaseShadowTessellator::addArc\28SkPoint\20const&\2c\20float\2c\20bool\29 +5527:SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint\28\29 +5528:SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint\28SkCanvas*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\2c\20SkRect\20const&\29 +5529:SkAndroidCodecAdapter::~SkAndroidCodecAdapter\28\29 +5530:SkAndroidCodecAdapter::SkAndroidCodecAdapter\28SkCodec*\29 +5531:SkAndroidCodec::~SkAndroidCodec\28\29 +5532:SkAndroidCodec::getAndroidPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const*\29 +5533:SkAndroidCodec::SkAndroidCodec\28SkCodec*\29 +5534:SkAnalyticEdge::update\28int\2c\20bool\29 +5535:SkAnalyticEdge::updateLine\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +5536:SkAnalyticEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\29 +5537:SkAAClip::operator=\28SkAAClip\20const&\29 +5538:SkAAClip::op\28SkIRect\20const&\2c\20SkClipOp\29 +5539:SkAAClip::Builder::flushRow\28bool\29 +5540:SkAAClip::Builder::finish\28SkAAClip*\29 +5541:SkAAClip::Builder::Blitter::~Blitter\28\29 +5542:SkAAClip::Builder::Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +5543:Sk2DPathEffect::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +5544:SimpleImageInfo*\20emscripten::internal::raw_constructor\28\29 +5545:SimpleFontStyle*\20emscripten::internal::MemberAccess::getWire\28SimpleFontStyle\20SimpleStrutStyle::*\20const&\2c\20SimpleStrutStyle&\29 +5546:Shift +5547:SharedGenerator::isTextureGenerator\28\29 +5548:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29_4037 +5549:RgnOper::addSpan\28int\2c\20int\20const*\2c\20int\20const*\29 +5550:ReadBase128 +5551:PorterDuffXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +5552:PathSegment::init\28\29 +5553:PathAddVerbsPointsWeights\28SkPath&\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +5554:ParseSingleImage +5555:ParseHeadersInternal +5556:PS_Conv_ASCIIHexDecode +5557:Op\28SkPath\20const&\2c\20SkPath\20const&\2c\20SkPathOp\2c\20SkPath*\29 +5558:OpAsWinding::markReverse\28Contour*\2c\20Contour*\29 +5559:OpAsWinding::getDirection\28Contour&\29 +5560:OpAsWinding::checkContainerChildren\28Contour*\2c\20Contour*\29 +5561:OffsetEdge::computeCrossingDistance\28OffsetEdge\20const*\29 +5562:OT::sbix::accelerator_t::get_png_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +5563:OT::sbix::accelerator_t::choose_strike\28hb_font_t*\29\20const +5564:OT::post_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5565:OT::hmtxvmtx::accelerator_t::get_advance_with_var_unscaled\28unsigned\20int\2c\20hb_font_t*\2c\20float*\29\20const +5566:OT::hmtx_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5567:OT::hb_ot_layout_lookup_accelerator_t*\20OT::hb_ot_layout_lookup_accelerator_t::create\28OT::Layout::GPOS_impl::PosLookup\20const&\29 +5568:OT::hb_kern_machine_t::kern\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20bool\29\20const +5569:OT::hb_accelerate_subtables_context_t::return_t\20OT::Context::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +5570:OT::hb_accelerate_subtables_context_t::return_t\20OT::ChainContext::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +5571:OT::glyf_accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\29\20const +5572:OT::glyf_accelerator_t::get_advance_with_var_unscaled\28hb_font_t*\2c\20unsigned\20int\2c\20bool\29\20const +5573:OT::cmap::accelerator_t::get_variation_glyph\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_cache_t<21u\2c\2016u\2c\208u\2c\20true>*\29\20const +5574:OT::cff2_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5575:OT::cff2::accelerator_templ_t>::~accelerator_templ_t\28\29 +5576:OT::cff2::accelerator_templ_t>::_fini\28\29 +5577:OT::cff1::lookup_expert_subset_charset_for_sid\28unsigned\20int\29 +5578:OT::cff1::lookup_expert_charset_for_sid\28unsigned\20int\29 +5579:OT::cff1::accelerator_templ_t>::~accelerator_templ_t\28\29 +5580:OT::cff1::accelerator_templ_t>::_fini\28\29 +5581:OT::TupleVariationData::unpack_points\28OT::IntType\20const*&\2c\20hb_vector_t&\2c\20OT::IntType\20const*\29 +5582:OT::SBIXStrike::get_glyph_blob\28unsigned\20int\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20unsigned\20int\2c\20unsigned\20int*\29\20const +5583:OT::RuleSet::sanitize\28hb_sanitize_context_t*\29\20const +5584:OT::RuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +5585:OT::RecordListOf::sanitize\28hb_sanitize_context_t*\29\20const +5586:OT::RecordListOf::sanitize\28hb_sanitize_context_t*\29\20const +5587:OT::PaintTranslate::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5588:OT::PaintSolid::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5589:OT::PaintSkewAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5590:OT::PaintSkew::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5591:OT::PaintScaleUniformAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5592:OT::PaintScaleUniform::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5593:OT::PaintScaleAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5594:OT::PaintScale::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5595:OT::PaintRotateAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5596:OT::PaintLinearGradient::sanitize\28hb_sanitize_context_t*\29\20const +5597:OT::PaintLinearGradient::sanitize\28hb_sanitize_context_t*\29\20const +5598:OT::Lookup::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +5599:OT::Layout::propagate_attachment_offsets\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +5600:OT::Layout::GSUB_impl::MultipleSubstFormat1_2::sanitize\28hb_sanitize_context_t*\29\20const +5601:OT::Layout::GSUB_impl::Ligature::apply\28OT::hb_ot_apply_context_t*\29\20const +5602:OT::Layout::GPOS_impl::reverse_cursive_minor_offset\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +5603:OT::Layout::GPOS_impl::MarkBasePosFormat1_2::sanitize\28hb_sanitize_context_t*\29\20const +5604:OT::Layout::GPOS_impl::MarkArray::sanitize\28hb_sanitize_context_t*\29\20const +5605:OT::Layout::GPOS_impl::AnchorMatrix::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +5606:OT::IndexSubtableRecord::get_image_data\28unsigned\20int\2c\20void\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +5607:OT::FeatureVariationRecord::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5608:OT::FeatureParams::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +5609:OT::ContextFormat3::sanitize\28hb_sanitize_context_t*\29\20const +5610:OT::ContextFormat2_5::sanitize\28hb_sanitize_context_t*\29\20const +5611:OT::ContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +5612:OT::ContextFormat1_4::sanitize\28hb_sanitize_context_t*\29\20const +5613:OT::ColorStop::get_color_stop\28OT::hb_paint_context_t*\2c\20hb_color_stop_t*\2c\20unsigned\20int\2c\20OT::VarStoreInstancer\20const&\29\20const +5614:OT::ColorLine::static_get_extend\28hb_color_line_t*\2c\20void*\2c\20void*\29 +5615:OT::CmapSubtableFormat4::accelerator_t::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +5616:OT::ChainRuleSet::sanitize\28hb_sanitize_context_t*\29\20const +5617:OT::ChainRuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +5618:OT::ChainContextFormat3::sanitize\28hb_sanitize_context_t*\29\20const +5619:OT::ChainContextFormat2_5::sanitize\28hb_sanitize_context_t*\29\20const +5620:OT::ChainContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +5621:OT::ChainContextFormat1_4::sanitize\28hb_sanitize_context_t*\29\20const +5622:OT::CBDT_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5623:OT::CBDT::accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +5624:OT::Affine2x3::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5625:MakeOnScreenGLSurface\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int\29 +5626:Load_SBit_Png +5627:LineCubicIntersections::intersectRay\28double*\29 +5628:LineCubicIntersections::VerticalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +5629:LineCubicIntersections::HorizontalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +5630:Launch +5631:JpegDecoderMgr::returnFalse\28char\20const*\29 +5632:JpegDecoderMgr::getEncodedColor\28SkEncodedInfo::Color*\29 +5633:JSObjectFromLineMetrics\28skia::textlayout::LineMetrics&\29 +5634:JSObjectFromGlyphInfo\28skia::textlayout::Paragraph::GlyphInfo&\29 +5635:Ins_DELTAP +5636:HandleCoincidence\28SkOpContourHead*\2c\20SkOpCoincidence*\29 +5637:GrWritePixelsTask::~GrWritePixelsTask\28\29 +5638:GrWaitRenderTask::~GrWaitRenderTask\28\29 +5639:GrVertexBufferAllocPool::makeSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +5640:GrVertexBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +5641:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20SkPathFillType\2c\20skgpu::VertexWriter\29\20const +5642:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20GrEagerVertexAllocator*\29\20const +5643:GrTriangulator::mergeEdgesBelow\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +5644:GrTriangulator::mergeEdgesAbove\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +5645:GrTriangulator::makeSortedVertex\28SkPoint\20const&\2c\20unsigned\20char\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29\20const +5646:GrTriangulator::makeEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\29 +5647:GrTriangulator::computeBisector\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\29\20const +5648:GrTriangulator::appendQuadraticToContour\28SkPoint\20const*\2c\20float\2c\20GrTriangulator::VertexList*\29\20const +5649:GrTriangulator::SortMesh\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +5650:GrTriangulator::FindEnclosingEdges\28GrTriangulator::Vertex\20const&\2c\20GrTriangulator::EdgeList\20const&\2c\20GrTriangulator::Edge**\2c\20GrTriangulator::Edge**\29 +5651:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29 +5652:GrThreadSafeCache::findVertsWithData\28skgpu::UniqueKey\20const&\29 +5653:GrThreadSafeCache::addVertsWithData\28skgpu::UniqueKey\20const&\2c\20sk_sp\2c\20bool\20\28*\29\28SkData*\2c\20SkData*\29\29 +5654:GrThreadSafeCache::Entry::set\28skgpu::UniqueKey\20const&\2c\20sk_sp\29 +5655:GrThreadSafeCache::CreateLazyView\28GrDirectContext*\2c\20GrColorType\2c\20SkISize\2c\20GrSurfaceOrigin\2c\20SkBackingFit\29 +5656:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29 +5657:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29 +5658:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28GrCaps\20const&\2c\20std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\2c\20std::__2::basic_string_view>\29 +5659:GrTextureProxyPriv::setDeferredUploader\28std::__2::unique_ptr>\29 +5660:GrTextureProxy::setUniqueKey\28GrProxyProvider*\2c\20skgpu::UniqueKey\20const&\29 +5661:GrTextureProxy::ProxiesAreCompatibleAsDynamicState\28GrSurfaceProxy\20const*\2c\20GrSurfaceProxy\20const*\29 +5662:GrTextureProxy::GrTextureProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29_9815 +5663:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::$_1::operator\28\29\28int\2c\20GrSamplerState::WrapMode\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20float\29\20const +5664:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_2::operator\28\29\28GrTextureEffect::ShaderMode\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +5665:GrTexture::markMipmapsDirty\28\29 +5666:GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +5667:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29 +5668:GrSurfaceProxyPriv::exactify\28\29 +5669:GrSurfaceProxy::GrSurfaceProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +5670:GrStyledShape::setInheritedKey\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +5671:GrStyledShape::asRRect\28SkRRect*\2c\20bool*\29\20const +5672:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20SkPaint\20const&\2c\20GrStyledShape::DoSimplify\29 +5673:GrStyle::~GrStyle\28\29 +5674:GrStyle::applyToPath\28SkPath*\2c\20SkStrokeRec::InitStyle*\2c\20SkPath\20const&\2c\20float\29\20const +5675:GrStyle::applyPathEffect\28SkPath*\2c\20SkStrokeRec*\2c\20SkPath\20const&\29\20const +5676:GrStencilSettings::SetClipBitSettings\28bool\29 +5677:GrStagingBufferManager::detachBuffers\28\29 +5678:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineStruct\28char\20const*\29 +5679:GrShape::simplify\28unsigned\20int\29 +5680:GrShape::setRect\28SkRect\20const&\29 +5681:GrShape::conservativeContains\28SkRect\20const&\29\20const +5682:GrShape::closed\28\29\20const +5683:GrSWMaskHelper::toTextureView\28GrRecordingContext*\2c\20SkBackingFit\29 +5684:GrSWMaskHelper::drawShape\28GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +5685:GrSWMaskHelper::drawShape\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +5686:GrResourceProvider::writePixels\28sk_sp\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\29\20const +5687:GrResourceProvider::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +5688:GrResourceProvider::prepareLevels\28GrBackendFormat\20const&\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\2c\20skia_private::AutoSTArray<14\2c\20GrMipLevel>*\2c\20skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>*\29\20const +5689:GrResourceProvider::getExactScratch\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5690:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5691:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20GrColorType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMipLevel\20const*\2c\20std::__2::basic_string_view>\29 +5692:GrResourceProvider::createApproxTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5693:GrResourceCache::~GrResourceCache\28\29 +5694:GrResourceCache::removeResource\28GrGpuResource*\29 +5695:GrResourceCache::processFreedGpuResources\28\29 +5696:GrResourceCache::insertResource\28GrGpuResource*\29 +5697:GrResourceCache::didChangeBudgetStatus\28GrGpuResource*\29 +5698:GrResourceAllocator::~GrResourceAllocator\28\29 +5699:GrResourceAllocator::planAssignment\28\29 +5700:GrResourceAllocator::expire\28unsigned\20int\29 +5701:GrRenderTask::makeSkippable\28\29 +5702:GrRenderTask::isInstantiated\28\29\20const +5703:GrRenderTarget::GrRenderTarget\28GrGpu*\2c\20SkISize\20const&\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20sk_sp\29 +5704:GrRecordingContext::init\28\29 +5705:GrRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRRect\20const&\2c\20GrShaderCaps\20const&\29 +5706:GrQuadUtils::TessellationHelper::reset\28GrQuad\20const&\2c\20GrQuad\20const*\29 +5707:GrQuadUtils::TessellationHelper::outset\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuad*\2c\20GrQuad*\29 +5708:GrQuadUtils::TessellationHelper::adjustDegenerateVertices\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuadUtils::TessellationHelper::Vertices*\29 +5709:GrQuadUtils::TessellationHelper::OutsetRequest::reset\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\2c\20GrQuad::Type\2c\20skvx::Vec<4\2c\20float>\20const&\29 +5710:GrQuadUtils::TessellationHelper::EdgeVectors::reset\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20GrQuad::Type\29 +5711:GrQuadUtils::ClipToW0\28DrawQuad*\2c\20DrawQuad*\29 +5712:GrQuad::bounds\28\29\20const +5713:GrProxyProvider::~GrProxyProvider\28\29 +5714:GrProxyProvider::wrapBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\2c\20GrIOType\2c\20sk_sp\29 +5715:GrProxyProvider::removeUniqueKeyFromProxy\28GrTextureProxy*\29 +5716:GrProxyProvider::createLazyProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20GrInternalSurfaceFlags\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +5717:GrProxyProvider::contextID\28\29\20const +5718:GrProxyProvider::adoptUniqueKeyFromSurface\28GrTextureProxy*\2c\20GrSurface\20const*\29 +5719:GrPixmapBase::clip\28SkISize\2c\20SkIPoint*\29 +5720:GrPixmap::GrPixmap\28GrImageInfo\2c\20sk_sp\2c\20unsigned\20long\29 +5721:GrPipeline::GrPipeline\28GrPipeline::InitArgs\20const&\2c\20sk_sp\2c\20GrAppliedHardClip\20const&\29 +5722:GrPersistentCacheUtils::GetType\28SkReadBuffer*\29 +5723:GrPathUtils::QuadUVMatrix::set\28SkPoint\20const*\29 +5724:GrPathTessellationShader::MakeStencilOnlyPipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedHardClip\20const&\2c\20GrPipeline::InputFlags\29 +5725:GrPaint::setCoverageSetOpXPFactory\28SkRegion::Op\2c\20bool\29 +5726:GrOvalOpFactory::MakeOvalOp\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\2c\20GrShaderCaps\20const*\29 +5727:GrOpsRenderPass::drawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +5728:GrOpsRenderPass::drawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +5729:GrOpsRenderPass::drawIndexPattern\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +5730:GrOpFlushState::reset\28\29 +5731:GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp\28GrOp\20const*\2c\20SkRect\20const&\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +5732:GrOpFlushState::addASAPUpload\28std::__2::function&\29>&&\29 +5733:GrOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +5734:GrOp::combineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +5735:GrOnFlushResourceProvider::instantiateProxy\28GrSurfaceProxy*\29 +5736:GrMeshDrawTarget::allocMesh\28\29 +5737:GrMeshDrawOp::PatternHelper::init\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +5738:GrMeshDrawOp::CombinedQuadCountWillOverflow\28GrAAType\2c\20bool\2c\20int\29 +5739:GrMemoryPool::allocate\28unsigned\20long\29 +5740:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::changed\28\29 +5741:GrIndexBufferAllocPool::makeSpace\28int\2c\20sk_sp*\2c\20int*\29 +5742:GrIndexBufferAllocPool::makeSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +5743:GrImageInfo::refColorSpace\28\29\20const +5744:GrImageInfo::minRowBytes\28\29\20const +5745:GrImageInfo::makeDimensions\28SkISize\29\20const +5746:GrImageInfo::bpp\28\29\20const +5747:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20int\2c\20int\29 +5748:GrImageContext::abandonContext\28\29 +5749:GrGpuResource::removeUniqueKey\28\29 +5750:GrGpuResource::makeBudgeted\28\29 +5751:GrGpuResource::getResourceName\28\29\20const +5752:GrGpuResource::abandon\28\29 +5753:GrGpuResource::CreateUniqueID\28\29 +5754:GrGpu::~GrGpu\28\29 +5755:GrGpu::regenerateMipMapLevels\28GrTexture*\29 +5756:GrGpu::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5757:GrGpu::createTextureCommon\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +5758:GrGeometryProcessor::AttributeSet::addToKey\28skgpu::KeyBuilder*\29\20const +5759:GrGLVertexArray::invalidateCachedState\28\29 +5760:GrGLTextureParameters::invalidate\28\29 +5761:GrGLTexture::MakeWrapped\28GrGLGpu*\2c\20GrMipmapStatus\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrWrapCacheable\2c\20GrIOType\2c\20std::__2::basic_string_view>\29 +5762:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20skgpu::Budgeted\2c\20GrGLTexture::Desc\20const&\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +5763:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +5764:GrGLSLVaryingHandler::getFragDecls\28SkString*\2c\20SkString*\29\20const +5765:GrGLSLVaryingHandler::addAttribute\28GrShaderVar\20const&\29 +5766:GrGLSLUniformHandler::liftUniformToVertexShader\28GrProcessor\20const&\2c\20SkString\29 +5767:GrGLSLShaderBuilder::finalize\28unsigned\20int\29 +5768:GrGLSLShaderBuilder::emitFunction\28char\20const*\2c\20char\20const*\29 +5769:GrGLSLShaderBuilder::emitFunctionPrototype\28char\20const*\29 +5770:GrGLSLShaderBuilder::appendTextureLookupAndBlend\28char\20const*\2c\20SkBlendMode\2c\20GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +5771:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29::$_0::operator\28\29\28char\20const*\2c\20GrResourceHandle\2c\20skcms_TFType\29\20const +5772:GrGLSLShaderBuilder::addLayoutQualifier\28char\20const*\2c\20GrGLSLShaderBuilder::InterfaceQualifier\29 +5773:GrGLSLShaderBuilder::GrGLSLShaderBuilder\28GrGLSLProgramBuilder*\29 +5774:GrGLSLProgramDataManager::setRuntimeEffectUniforms\28SkSpan\2c\20SkSpan\20const>\2c\20SkSpan\2c\20void\20const*\29\20const +5775:GrGLSLProgramBuilder::~GrGLSLProgramBuilder\28\29 +5776:GrGLSLBlend::SetBlendModeUniformData\28GrGLSLProgramDataManager\20const&\2c\20GrResourceHandle\2c\20SkBlendMode\29 +5777:GrGLSLBlend::BlendExpression\28GrProcessor\20const*\2c\20GrGLSLUniformHandler*\2c\20GrResourceHandle*\2c\20char\20const*\2c\20char\20const*\2c\20SkBlendMode\29 +5778:GrGLRenderTarget::GrGLRenderTarget\28GrGLGpu*\2c\20SkISize\20const&\2c\20GrGLFormat\2c\20int\2c\20GrGLRenderTarget::IDs\20const&\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5779:GrGLProgramDataManager::set4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +5780:GrGLProgramDataManager::set2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +5781:GrGLProgramBuilder::uniformHandler\28\29 +5782:GrGLProgramBuilder::PrecompileProgram\28GrDirectContext*\2c\20GrGLPrecompiledProgram*\2c\20SkData\20const&\29::$_0::operator\28\29\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\29\20const +5783:GrGLProgramBuilder::CreateProgram\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrGLPrecompiledProgram\20const*\29 +5784:GrGLProgram::~GrGLProgram\28\29 +5785:GrGLMakeAssembledWebGLInterface\28void*\2c\20void\20\28*\20\28*\29\28void*\2c\20char\20const*\29\29\28\29\29 +5786:GrGLGpu::~GrGLGpu\28\29 +5787:GrGLGpu::uploadTexData\28SkISize\2c\20unsigned\20int\2c\20SkIRect\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20long\2c\20GrMipLevel\20const*\2c\20int\29 +5788:GrGLGpu::uploadCompressedTexData\28SkTextureCompressionType\2c\20GrGLFormat\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20unsigned\20int\2c\20void\20const*\2c\20unsigned\20long\29 +5789:GrGLGpu::uploadColorToTex\28GrGLFormat\2c\20SkISize\2c\20unsigned\20int\2c\20std::__2::array\2c\20unsigned\20int\29 +5790:GrGLGpu::readOrTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20int\29 +5791:GrGLGpu::getTimerQueryResult\28unsigned\20int\29 +5792:GrGLGpu::getCompatibleStencilIndex\28GrGLFormat\29 +5793:GrGLGpu::createRenderTargetObjects\28GrGLTexture::Desc\20const&\2c\20int\2c\20GrGLRenderTarget::IDs*\29 +5794:GrGLGpu::createCompressedTexture2D\28SkISize\2c\20SkTextureCompressionType\2c\20GrGLFormat\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrGLTextureParameters::SamplerOverriddenState*\29 +5795:GrGLGpu::bindFramebuffer\28unsigned\20int\2c\20unsigned\20int\29 +5796:GrGLGpu::ProgramCache::reset\28\29 +5797:GrGLGpu::ProgramCache::findOrCreateProgramImpl\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrThreadSafePipelineBuilder::Stats::ProgramCacheResult*\29 +5798:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29 +5799:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\29 +5800:GrGLFormatIsCompressed\28GrGLFormat\29 +5801:GrGLFinishCallbacks::check\28\29 +5802:GrGLContext::~GrGLContext\28\29_12021 +5803:GrGLContext::~GrGLContext\28\29 +5804:GrGLCaps::~GrGLCaps\28\29 +5805:GrGLCaps::getTexSubImageExternalFormatAndType\28GrGLFormat\2c\20GrColorType\2c\20GrColorType\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +5806:GrGLCaps::getTexSubImageDefaultFormatTypeAndColorType\28GrGLFormat\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20GrColorType*\29\20const +5807:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrGLFormat\29\20const +5808:GrGLCaps::formatSupportsTexStorage\28GrGLFormat\29\20const +5809:GrGLCaps::canCopyAsDraw\28GrGLFormat\2c\20bool\2c\20bool\29\20const +5810:GrGLCaps::canCopyAsBlit\28GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20SkRect\20const&\2c\20bool\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29\20const +5811:GrFragmentProcessor::~GrFragmentProcessor\28\29 +5812:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +5813:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +5814:GrFragmentProcessor::ProgramImpl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +5815:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::Make\28std::__2::unique_ptr>\29 +5816:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +5817:GrFragmentProcessor::ClampOutput\28std::__2::unique_ptr>\29 +5818:GrFixedClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +5819:GrFixedClip::getConservativeBounds\28\29\20const +5820:GrFixedClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +5821:GrExternalTextureGenerator::GrExternalTextureGenerator\28SkImageInfo\20const&\29 +5822:GrEagerDynamicVertexAllocator::unlock\28int\29 +5823:GrDynamicAtlas::readView\28GrCaps\20const&\29\20const +5824:GrDrawingManager::getLastRenderTask\28GrSurfaceProxy\20const*\29\20const +5825:GrDrawingManager::flush\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +5826:GrDrawOpAtlasConfig::atlasDimensions\28skgpu::MaskFormat\29\20const +5827:GrDrawOpAtlasConfig::GrDrawOpAtlasConfig\28int\2c\20unsigned\20long\29 +5828:GrDrawOpAtlas::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +5829:GrDrawOpAtlas::Make\28GrProxyProvider*\2c\20GrBackendFormat\20const&\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20int\2c\20int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20GrDrawOpAtlas::AllowMultitexturing\2c\20skgpu::PlotEvictionCallback*\2c\20std::__2::basic_string_view>\29 +5830:GrDistanceFieldA8TextGeoProc::onTextureSampler\28int\29\20const +5831:GrDistanceFieldA8TextGeoProc::addNewViews\28GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\29 +5832:GrDisableColorXPFactory::MakeXferProcessor\28\29 +5833:GrDirectContextPriv::validPMUPMConversionExists\28\29 +5834:GrDirectContext::~GrDirectContext\28\29 +5835:GrDirectContext::onGetSmallPathAtlasMgr\28\29 +5836:GrDirectContext::getResourceCacheLimits\28int*\2c\20unsigned\20long*\29\20const +5837:GrCopyRenderTask::~GrCopyRenderTask\28\29 +5838:GrCopyRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +5839:GrCopyBaseMipMapToView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Budgeted\29 +5840:GrContext_Base::threadSafeProxy\28\29 +5841:GrContext_Base::maxSurfaceSampleCountForColorType\28SkColorType\29\20const +5842:GrContext_Base::backend\28\29\20const +5843:GrColorInfo::makeColorType\28GrColorType\29\20const +5844:GrColorInfo::isLinearlyBlended\28\29\20const +5845:GrColorFragmentProcessorAnalysis::GrColorFragmentProcessorAnalysis\28GrProcessorAnalysisColor\20const&\2c\20std::__2::unique_ptr>\20const*\2c\20int\29 +5846:GrClip::IsPixelAligned\28SkRect\20const&\29 +5847:GrCaps::surfaceSupportsWritePixels\28GrSurface\20const*\29\20const +5848:GrCaps::getDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\2c\20bool\29\20const +5849:GrCPixmap::GrCPixmap\28GrPixmap\20const&\29 +5850:GrBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\2c\20unsigned\20long*\29 +5851:GrBufferAllocPool::createBlock\28unsigned\20long\29 +5852:GrBufferAllocPool::CpuBufferCache::makeBuffer\28unsigned\20long\2c\20bool\29 +5853:GrBlurUtils::draw_shape_with_mask_filter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\29 +5854:GrBlurUtils::draw_mask\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrPaint&&\2c\20GrSurfaceProxyView\29 +5855:GrBlurUtils::convolve_gaussian\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20SkIRect\2c\20SkIRect\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkBackingFit\29 +5856:GrBlurUtils::\28anonymous\20namespace\29::make_texture_effect\28GrCaps\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20GrSamplerState\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkISize\20const&\29 +5857:GrBitmapTextGeoProc::addNewViews\28GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\29 +5858:GrBitmapTextGeoProc::GrBitmapTextGeoProc\28GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29 +5859:GrBicubicEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +5860:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +5861:GrBackendTextures::MakeGL\28int\2c\20int\2c\20skgpu::Mipmapped\2c\20GrGLTextureInfo\20const&\2c\20std::__2::basic_string_view>\29 +5862:GrBackendTexture::operator=\28GrBackendTexture\20const&\29 +5863:GrBackendRenderTargets::MakeGL\28int\2c\20int\2c\20int\2c\20int\2c\20GrGLFramebufferInfo\20const&\29 +5864:GrBackendRenderTargets::GetGLFramebufferInfo\28GrBackendRenderTarget\20const&\2c\20GrGLFramebufferInfo*\29 +5865:GrBackendRenderTarget::~GrBackendRenderTarget\28\29 +5866:GrBackendRenderTarget::isProtected\28\29\20const +5867:GrBackendFormatBytesPerBlock\28GrBackendFormat\20const&\29 +5868:GrBackendFormat::makeTexture2D\28\29\20const +5869:GrBackendFormat::isMockStencilFormat\28\29\20const +5870:GrBackendFormat::MakeMock\28GrColorType\2c\20SkTextureCompressionType\2c\20bool\29 +5871:GrAuditTrail::opsCombined\28GrOp\20const*\2c\20GrOp\20const*\29 +5872:GrAttachment::ComputeSharedAttachmentUniqueKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\2c\20skgpu::UniqueKey*\29 +5873:GrAtlasManager::~GrAtlasManager\28\29 +5874:GrAtlasManager::getViews\28skgpu::MaskFormat\2c\20unsigned\20int*\29 +5875:GrAtlasManager::freeAll\28\29 +5876:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::EventList*\2c\20GrTriangulator::Comparator\20const&\29\20const +5877:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrAATriangulator::EventList*\29\20const +5878:GrAATriangulator::collapseOverlapRegions\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\2c\20GrAATriangulator::EventComparator\29 +5879:GrAAConvexTessellator::quadTo\28SkPoint\20const*\29 +5880:GetShapedLines\28skia::textlayout::Paragraph&\29 +5881:GetLargeValue +5882:FontMgrRunIterator::endOfCurrentRun\28\29\20const +5883:FontMgrRunIterator::atEnd\28\29\20const +5884:FinishRow +5885:FindUndone\28SkOpContourHead*\29 +5886:FT_Stream_Free +5887:FT_Sfnt_Table_Info +5888:FT_Select_Size +5889:FT_Render_Glyph_Internal +5890:FT_Remove_Module +5891:FT_Outline_Get_Orientation +5892:FT_Outline_EmboldenXY +5893:FT_New_GlyphSlot +5894:FT_Match_Size +5895:FT_List_Iterate +5896:FT_List_Find +5897:FT_List_Finalize +5898:FT_GlyphLoader_CheckSubGlyphs +5899:FT_Get_Postscript_Name +5900:FT_Get_Paint_Layers +5901:FT_Get_PS_Font_Info +5902:FT_Get_Glyph_Name +5903:FT_Get_FSType_Flags +5904:FT_Get_Colorline_Stops +5905:FT_Get_Color_Glyph_ClipBox +5906:FT_Bitmap_Convert +5907:EllipticalRRectOp::~EllipticalRRectOp\28\29_11254 +5908:EllipticalRRectOp::~EllipticalRRectOp\28\29 +5909:EllipticalRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +5910:EllipticalRRectOp::RRect&\20skia_private::TArray::emplace_back\28EllipticalRRectOp::RRect&&\29 +5911:EllipticalRRectOp::EllipticalRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20SkPoint\2c\20bool\29 +5912:EllipseOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\29 +5913:EllipseOp::EllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20EllipseOp::DeviceSpaceParams\20const&\2c\20SkStrokeRec\20const&\29 +5914:EllipseGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +5915:DecodeVarLenUint8 +5916:DecodeContextMap +5917:DIEllipseOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\29 +5918:DIEllipseOp::DIEllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20DIEllipseOp::DeviceSpaceParams\20const&\2c\20SkMatrix\20const&\29 +5919:CustomXP::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +5920:CustomXP::makeProgramImpl\28\29\20const::Impl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +5921:Cr_z_zcfree +5922:Cr_z_deflateReset +5923:Cr_z_deflate +5924:Cr_z_crc32_z +5925:CoverageSetOpXP::onIsEqual\28GrXferProcessor\20const&\29\20const +5926:Contour*\20std::__2::vector>::__emplace_back_slow_path\28SkRect&\2c\20int&\2c\20int&\29 +5927:CircularRRectOp::~CircularRRectOp\28\29_11231 +5928:CircularRRectOp::~CircularRRectOp\28\29 +5929:CircularRRectOp::CircularRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +5930:CircleOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +5931:CircleOp::CircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +5932:CircleGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +5933:CheckDecBuffer +5934:CFF::path_procs_t::vvcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5935:CFF::path_procs_t::vlineto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5936:CFF::path_procs_t::vhcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5937:CFF::path_procs_t::rrcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5938:CFF::path_procs_t::rlineto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5939:CFF::path_procs_t::rlinecurve\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5940:CFF::path_procs_t::rcurveline\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5941:CFF::path_procs_t::hvcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5942:CFF::path_procs_t::hlineto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5943:CFF::path_procs_t::hhcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5944:CFF::path_procs_t::hflex\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5945:CFF::path_procs_t::hflex1\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5946:CFF::path_procs_t::flex\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5947:CFF::path_procs_t::flex1\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5948:CFF::dict_interpreter_t\2c\20CFF::interp_env_t>::interpret\28CFF::cff1_private_dict_values_base_t&\29 +5949:CFF::cff2_cs_opset_t::process_blend\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\29 +5950:CFF::FDSelect3_4\2c\20OT::IntType>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +5951:CFF::Charset::get_sid\28unsigned\20int\2c\20unsigned\20int\2c\20CFF::code_pair_t*\29\20const +5952:CFF::CFFIndex>::get_size\28\29\20const +5953:CFF::CFF2FDSelect::get_fd\28unsigned\20int\29\20const +5954:ButtCapDashedCircleOp::ButtCapDashedCircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5955:BrotliTransformDictionaryWord +5956:BrotliEnsureRingBuffer +5957:AutoLayerForImageFilter::addMaskFilterLayer\28SkRect\20const*\29 +5958:AsWinding\28SkPath\20const&\2c\20SkPath*\29 +5959:AngleWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\2c\20bool*\29 +5960:AddIntersectTs\28SkOpContour*\2c\20SkOpContour*\2c\20SkOpCoincidence*\29 +5961:ActiveEdgeList::replace\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +5962:ActiveEdgeList::remove\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +5963:ActiveEdgeList::insert\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +5964:AAT::hb_aat_apply_context_t::return_t\20AAT::ChainSubtable::dispatch\28AAT::hb_aat_apply_context_t*\29\20const +5965:AAT::hb_aat_apply_context_t::return_t\20AAT::ChainSubtable::dispatch\28AAT::hb_aat_apply_context_t*\29\20const +5966:AAT::ankr::get_anchor\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +5967:AAT::TrackData::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5968:AAT::TrackData::get_tracking\28void\20const*\2c\20float\29\20const +5969:AAT::StateTable::EntryData>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +5970:AAT::StateTable::EntryData>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +5971:AAT::StateTable::EntryData>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +5972:AAT::RearrangementSubtable::driver_context_t::transition\28AAT::StateTableDriver*\2c\20AAT::Entry\20const&\29 +5973:AAT::NoncontextualSubtable::apply\28AAT::hb_aat_apply_context_t*\29\20const +5974:AAT::Lookup>::sanitize\28hb_sanitize_context_t*\29\20const +5975:AAT::Lookup>::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +5976:AAT::InsertionSubtable::driver_context_t::transition\28AAT::StateTableDriver::EntryData>*\2c\20AAT::Entry::EntryData>\20const&\29 +5977:5739 +5978:5740 +5979:5741 +5980:5742 +5981:5743 +5982:5744 +5983:5745 +5984:5746 +5985:5747 +5986:5748 +5987:5749 +5988:5750 +5989:5751 +5990:5752 +5991:5753 +5992:5754 +5993:5755 +5994:5756 +5995:5757 +5996:5758 +5997:5759 +5998:5760 +5999:5761 +6000:5762 +6001:5763 +6002:5764 +6003:5765 +6004:5766 +6005:5767 +6006:5768 +6007:5769 +6008:5770 +6009:5771 +6010:5772 +6011:5773 +6012:5774 +6013:5775 +6014:5776 +6015:5777 +6016:5778 +6017:5779 +6018:5780 +6019:5781 +6020:5782 +6021:5783 +6022:5784 +6023:5785 +6024:5786 +6025:5787 +6026:5788 +6027:5789 +6028:5790 +6029:5791 +6030:5792 +6031:5793 +6032:5794 +6033:5795 +6034:5796 +6035:5797 +6036:5798 +6037:5799 +6038:5800 +6039:5801 +6040:5802 +6041:5803 +6042:5804 +6043:5805 +6044:5806 +6045:5807 +6046:5808 +6047:5809 +6048:5810 +6049:5811 +6050:5812 +6051:5813 +6052:5814 +6053:5815 +6054:5816 +6055:5817 +6056:5818 +6057:5819 +6058:5820 +6059:5821 +6060:5822 +6061:5823 +6062:5824 +6063:5825 +6064:ycck_cmyk_convert +6065:ycc_rgb_convert +6066:ycc_rgb565_convert +6067:ycc_rgb565D_convert +6068:xyzd50_to_lab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +6069:xyzd50_to_hcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +6070:wuffs_gif__decoder__tell_me_more +6071:wuffs_gif__decoder__set_report_metadata +6072:wuffs_gif__decoder__num_decoded_frame_configs +6073:wuffs_base__pixel_swizzler__xxxxxxxx__index_binary_alpha__src_over +6074:wuffs_base__pixel_swizzler__xxxxxxxx__index__src +6075:wuffs_base__pixel_swizzler__xxxx__index_binary_alpha__src_over +6076:wuffs_base__pixel_swizzler__xxxx__index__src +6077:wuffs_base__pixel_swizzler__xxx__index_binary_alpha__src_over +6078:wuffs_base__pixel_swizzler__xxx__index__src +6079:wuffs_base__pixel_swizzler__transparent_black_src_over +6080:wuffs_base__pixel_swizzler__transparent_black_src +6081:wuffs_base__pixel_swizzler__copy_1_1 +6082:wuffs_base__pixel_swizzler__bgr_565__index_binary_alpha__src_over +6083:wuffs_base__pixel_swizzler__bgr_565__index__src +6084:webgl_get_gl_proc\28void*\2c\20char\20const*\29 +6085:void\20std::__2::__call_once_proxy\5babi:nn180100\5d>\28void*\29 +6086:void\20std::__2::__call_once_proxy\5babi:ne180100\5d>\28void*\29 +6087:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +6088:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +6089:void\20emscripten::internal::raw_destructor>\28sk_sp*\29 +6090:void\20emscripten::internal::raw_destructor\28SkVertices::Builder*\29 +6091:void\20emscripten::internal::raw_destructor\28SkRuntimeEffect::TracedShader*\29 +6092:void\20emscripten::internal::raw_destructor\28SkPictureRecorder*\29 +6093:void\20emscripten::internal::raw_destructor\28SkPath*\29 +6094:void\20emscripten::internal::raw_destructor\28SkPaint*\29 +6095:void\20emscripten::internal::raw_destructor\28SkContourMeasureIter*\29 +6096:void\20emscripten::internal::raw_destructor\28SimpleImageInfo*\29 +6097:void\20emscripten::internal::MemberAccess::setWire\28SimpleTextStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\2c\20SimpleTextStyle*\29 +6098:void\20emscripten::internal::MemberAccess::setWire\28SimpleStrutStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\2c\20SimpleStrutStyle*\29 +6099:void\20emscripten::internal::MemberAccess>::setWire\28sk_sp\20SimpleImageInfo::*\20const&\2c\20SimpleImageInfo&\2c\20sk_sp*\29 +6100:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::TypefaceFontProvider*\29 +6101:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::ParagraphBuilderImpl*\29 +6102:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::Paragraph*\29 +6103:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::FontCollection*\29 +6104:void\20const*\20emscripten::internal::getActualType\28SkVertices*\29 +6105:void\20const*\20emscripten::internal::getActualType\28SkVertices::Builder*\29 +6106:void\20const*\20emscripten::internal::getActualType\28SkTypeface*\29 +6107:void\20const*\20emscripten::internal::getActualType\28SkTextBlob*\29 +6108:void\20const*\20emscripten::internal::getActualType\28SkSurface*\29 +6109:void\20const*\20emscripten::internal::getActualType\28SkShader*\29 +6110:void\20const*\20emscripten::internal::getActualType\28SkSL::DebugTrace*\29 +6111:void\20const*\20emscripten::internal::getActualType\28SkRuntimeEffect*\29 +6112:void\20const*\20emscripten::internal::getActualType\28SkPictureRecorder*\29 +6113:void\20const*\20emscripten::internal::getActualType\28SkPicture*\29 +6114:void\20const*\20emscripten::internal::getActualType\28SkPathEffect*\29 +6115:void\20const*\20emscripten::internal::getActualType\28SkPath*\29 +6116:void\20const*\20emscripten::internal::getActualType\28SkPaint*\29 +6117:void\20const*\20emscripten::internal::getActualType\28SkMaskFilter*\29 +6118:void\20const*\20emscripten::internal::getActualType\28SkImageFilter*\29 +6119:void\20const*\20emscripten::internal::getActualType\28SkImage*\29 +6120:void\20const*\20emscripten::internal::getActualType\28SkFontMgr*\29 +6121:void\20const*\20emscripten::internal::getActualType\28SkFont*\29 +6122:void\20const*\20emscripten::internal::getActualType\28SkContourMeasureIter*\29 +6123:void\20const*\20emscripten::internal::getActualType\28SkContourMeasure*\29 +6124:void\20const*\20emscripten::internal::getActualType\28SkColorSpace*\29 +6125:void\20const*\20emscripten::internal::getActualType\28SkColorFilter*\29 +6126:void\20const*\20emscripten::internal::getActualType\28SkCanvas*\29 +6127:void\20const*\20emscripten::internal::getActualType\28SkBlender*\29 +6128:void\20const*\20emscripten::internal::getActualType\28SkAnimatedImage*\29 +6129:void\20const*\20emscripten::internal::getActualType\28GrDirectContext*\29 +6130:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6131:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6132:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6133:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6134:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6135:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6136:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6137:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6138:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6139:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6140:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6141:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6142:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6143:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6144:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6145:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6146:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6147:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6148:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6149:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6150:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6151:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6152:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6153:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6154:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6155:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6156:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6157:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6158:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6159:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6160:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6161:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6162:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6163:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6164:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6165:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6166:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6167:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6168:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6169:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6170:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6171:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6172:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6173:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6174:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6175:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6176:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6177:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6178:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6179:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6180:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6181:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6182:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6183:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6184:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6185:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6186:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6187:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6188:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6189:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6190:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6191:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6192:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6193:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6194:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6195:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6196:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6197:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6198:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6199:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6200:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6201:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6202:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6203:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6204:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6205:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6206:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6207:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6208:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6209:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6210:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6211:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6212:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6213:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6214:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6215:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6216:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6217:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6218:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6219:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6220:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6221:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6222:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6223:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6224:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6225:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +6226:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6227:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6228:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&fast_swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6229:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&fast_swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6230:void\20SkSwizzler::SkipLeading8888ZerosThen<&swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6231:void\20SkSwizzler::SkipLeading8888ZerosThen<&swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6232:void\20SkSwizzler::SkipLeading8888ZerosThen<&swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6233:void\20SkSwizzler::SkipLeading8888ZerosThen<&sample4\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6234:void\20SkSwizzler::SkipLeading8888ZerosThen<&fast_swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6235:void\20SkSwizzler::SkipLeading8888ZerosThen<&fast_swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6236:void\20SkSwizzler::SkipLeading8888ZerosThen<&fast_swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6237:void\20SkSwizzler::SkipLeading8888ZerosThen<©\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6238:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_17639 +6239:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +6240:virtual\20thunk\20to\20std::__2::basic_ostream>::~basic_ostream\28\29_17537 +6241:virtual\20thunk\20to\20std::__2::basic_ostream>::~basic_ostream\28\29 +6242:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29_17496 +6243:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29 +6244:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_17557 +6245:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +6246:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9869 +6247:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +6248:virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +6249:virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +6250:virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +6251:virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +6252:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29_9820 +6253:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29 +6254:virtual\20thunk\20to\20GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +6255:virtual\20thunk\20to\20GrTextureProxy::instantiate\28GrResourceProvider*\29 +6256:virtual\20thunk\20to\20GrTextureProxy::getUniqueKey\28\29\20const +6257:virtual\20thunk\20to\20GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +6258:virtual\20thunk\20to\20GrTextureProxy::callbackDesc\28\29\20const +6259:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29\20const +6260:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29 +6261:virtual\20thunk\20to\20GrTexture::onGpuMemorySize\28\29\20const +6262:virtual\20thunk\20to\20GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +6263:virtual\20thunk\20to\20GrTexture::asTexture\28\29\20const +6264:virtual\20thunk\20to\20GrTexture::asTexture\28\29 +6265:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9588 +6266:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +6267:virtual\20thunk\20to\20GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +6268:virtual\20thunk\20to\20GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +6269:virtual\20thunk\20to\20GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +6270:virtual\20thunk\20to\20GrRenderTargetProxy::callbackDesc\28\29\20const +6271:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29\20const +6272:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29 +6273:virtual\20thunk\20to\20GrRenderTarget::onRelease\28\29 +6274:virtual\20thunk\20to\20GrRenderTarget::onAbandon\28\29 +6275:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29\20const +6276:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29 +6277:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_12330 +6278:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +6279:virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +6280:virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +6281:virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +6282:virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +6283:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29_12297 +6284:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29 +6285:virtual\20thunk\20to\20GrGLTexture::onRelease\28\29 +6286:virtual\20thunk\20to\20GrGLTexture::onAbandon\28\29 +6287:virtual\20thunk\20to\20GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +6288:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10614 +6289:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +6290:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::onFinalize\28\29 +6291:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29_12269 +6292:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29 +6293:virtual\20thunk\20to\20GrGLRenderTarget::onRelease\28\29 +6294:virtual\20thunk\20to\20GrGLRenderTarget::onGpuMemorySize\28\29\20const +6295:virtual\20thunk\20to\20GrGLRenderTarget::onAbandon\28\29 +6296:virtual\20thunk\20to\20GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +6297:virtual\20thunk\20to\20GrGLRenderTarget::backendFormat\28\29\20const +6298:utf8TextMapOffsetToNative\28UText\20const*\29 +6299:utf8TextMapIndexToUTF16\28UText\20const*\2c\20long\20long\29 +6300:utf8TextLength\28UText*\29 +6301:utf8TextExtract\28UText*\2c\20long\20long\2c\20long\20long\2c\20char16_t*\2c\20int\2c\20UErrorCode*\29 +6302:utf8TextClone\28UText*\2c\20UText\20const*\2c\20signed\20char\2c\20UErrorCode*\29 +6303:utext_openUTF8_74 +6304:ustrcase_internalToUpper_74 +6305:ustrcase_internalFold_74 +6306:ures_loc_resetLocales\28UEnumeration*\2c\20UErrorCode*\29 +6307:ures_loc_nextLocale\28UEnumeration*\2c\20int*\2c\20UErrorCode*\29 +6308:ures_loc_countLocales\28UEnumeration*\2c\20UErrorCode*\29 +6309:ures_loc_closeLocales\28UEnumeration*\29 +6310:ures_cleanup\28\29 +6311:unistrTextReplace\28UText*\2c\20long\20long\2c\20long\20long\2c\20char16_t\20const*\2c\20int\2c\20UErrorCode*\29 +6312:unistrTextLength\28UText*\29 +6313:unistrTextExtract\28UText*\2c\20long\20long\2c\20long\20long\2c\20char16_t*\2c\20int\2c\20UErrorCode*\29 +6314:unistrTextCopy\28UText*\2c\20long\20long\2c\20long\20long\2c\20long\20long\2c\20signed\20char\2c\20UErrorCode*\29 +6315:unistrTextClose\28UText*\29 +6316:unistrTextClone\28UText*\2c\20UText\20const*\2c\20signed\20char\2c\20UErrorCode*\29 +6317:unistrTextAccess\28UText*\2c\20long\20long\2c\20signed\20char\29 +6318:uloc_kw_resetKeywords\28UEnumeration*\2c\20UErrorCode*\29 +6319:uloc_kw_nextKeyword\28UEnumeration*\2c\20int*\2c\20UErrorCode*\29 +6320:uloc_kw_countKeywords\28UEnumeration*\2c\20UErrorCode*\29 +6321:uloc_kw_closeKeywords\28UEnumeration*\29 +6322:uloc_key_type_cleanup\28\29 +6323:uloc_getDefault_74 +6324:uloc_forLanguageTag_74 +6325:uhash_hashUnicodeString_74 +6326:uhash_hashUChars_74 +6327:uhash_hashIChars_74 +6328:uhash_deleteHashtable_74 +6329:uhash_compareUnicodeString_74 +6330:uhash_compareUChars_74 +6331:uhash_compareLong_74 +6332:uhash_compareIChars_74 +6333:uenum_unextDefault_74 +6334:udata_cleanup\28\29 +6335:ucstrTextLength\28UText*\29 +6336:ucstrTextExtract\28UText*\2c\20long\20long\2c\20long\20long\2c\20char16_t*\2c\20int\2c\20UErrorCode*\29 +6337:ucstrTextClone\28UText*\2c\20UText\20const*\2c\20signed\20char\2c\20UErrorCode*\29 +6338:ubrk_setUText_74 +6339:ubrk_setText_74 +6340:ubrk_preceding_74 +6341:ubrk_open_74 +6342:ubrk_next_74 +6343:ubrk_getRuleStatus_74 +6344:ubrk_first_74 +6345:ubrk_current_74 +6346:ubidi_reorderVisual_74 +6347:ubidi_openSized_74 +6348:ubidi_getLevelAt_74 +6349:ubidi_getLength_74 +6350:ubidi_getDirection_74 +6351:u_strToUpper_74 +6352:u_isspace_74 +6353:u_iscntrl_74 +6354:u_isWhitespace_74 +6355:u_errorName_74 +6356:tt_vadvance_adjust +6357:tt_slot_init +6358:tt_size_select +6359:tt_size_reset_iterator +6360:tt_size_request +6361:tt_size_init +6362:tt_size_done +6363:tt_sbit_decoder_load_png +6364:tt_sbit_decoder_load_compound +6365:tt_sbit_decoder_load_byte_aligned +6366:tt_sbit_decoder_load_bit_aligned +6367:tt_property_set +6368:tt_property_get +6369:tt_name_ascii_from_utf16 +6370:tt_name_ascii_from_other +6371:tt_hadvance_adjust +6372:tt_glyph_load +6373:tt_get_var_blend +6374:tt_get_interface +6375:tt_get_glyph_name +6376:tt_get_cmap_info +6377:tt_get_advances +6378:tt_face_set_sbit_strike +6379:tt_face_load_strike_metrics +6380:tt_face_load_sbit_image +6381:tt_face_load_sbit +6382:tt_face_load_post +6383:tt_face_load_pclt +6384:tt_face_load_os2 +6385:tt_face_load_name +6386:tt_face_load_maxp +6387:tt_face_load_kern +6388:tt_face_load_hmtx +6389:tt_face_load_hhea +6390:tt_face_load_head +6391:tt_face_load_gasp +6392:tt_face_load_font_dir +6393:tt_face_load_cpal +6394:tt_face_load_colr +6395:tt_face_load_cmap +6396:tt_face_load_bhed +6397:tt_face_load_any +6398:tt_face_init +6399:tt_face_goto_table +6400:tt_face_get_paint_layers +6401:tt_face_get_paint +6402:tt_face_get_kerning +6403:tt_face_get_colr_layer +6404:tt_face_get_colr_glyph_paint +6405:tt_face_get_colorline_stops +6406:tt_face_get_color_glyph_clipbox +6407:tt_face_free_sbit +6408:tt_face_free_ps_names +6409:tt_face_free_name +6410:tt_face_free_cpal +6411:tt_face_free_colr +6412:tt_face_done +6413:tt_face_colr_blend_layer +6414:tt_driver_init +6415:tt_cvt_ready_iterator +6416:tt_cmap_unicode_init +6417:tt_cmap_unicode_char_next +6418:tt_cmap_unicode_char_index +6419:tt_cmap_init +6420:tt_cmap8_validate +6421:tt_cmap8_get_info +6422:tt_cmap8_char_next +6423:tt_cmap8_char_index +6424:tt_cmap6_validate +6425:tt_cmap6_get_info +6426:tt_cmap6_char_next +6427:tt_cmap6_char_index +6428:tt_cmap4_validate +6429:tt_cmap4_init +6430:tt_cmap4_get_info +6431:tt_cmap4_char_next +6432:tt_cmap4_char_index +6433:tt_cmap2_validate +6434:tt_cmap2_get_info +6435:tt_cmap2_char_next +6436:tt_cmap2_char_index +6437:tt_cmap14_variants +6438:tt_cmap14_variant_chars +6439:tt_cmap14_validate +6440:tt_cmap14_init +6441:tt_cmap14_get_info +6442:tt_cmap14_done +6443:tt_cmap14_char_variants +6444:tt_cmap14_char_var_isdefault +6445:tt_cmap14_char_var_index +6446:tt_cmap14_char_next +6447:tt_cmap13_validate +6448:tt_cmap13_get_info +6449:tt_cmap13_char_next +6450:tt_cmap13_char_index +6451:tt_cmap12_validate +6452:tt_cmap12_get_info +6453:tt_cmap12_char_next +6454:tt_cmap12_char_index +6455:tt_cmap10_validate +6456:tt_cmap10_get_info +6457:tt_cmap10_char_next +6458:tt_cmap10_char_index +6459:tt_cmap0_validate +6460:tt_cmap0_get_info +6461:tt_cmap0_char_next +6462:tt_cmap0_char_index +6463:transform_scanline_rgbA\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6464:transform_scanline_memcpy\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6465:transform_scanline_bgra_1010102_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6466:transform_scanline_bgra_1010102\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6467:transform_scanline_bgra_10101010_xr_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6468:transform_scanline_bgra_10101010_xr\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6469:transform_scanline_bgr_101010x_xr\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6470:transform_scanline_bgr_101010x\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6471:transform_scanline_bgrA\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6472:transform_scanline_RGBX\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6473:transform_scanline_F32_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6474:transform_scanline_F32\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6475:transform_scanline_F16_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6476:transform_scanline_F16\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6477:transform_scanline_F16F16F16x\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6478:transform_scanline_BGRX\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6479:transform_scanline_BGRA\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6480:transform_scanline_A8_to_GrayAlpha\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6481:transform_scanline_565\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6482:transform_scanline_444\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6483:transform_scanline_4444\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6484:transform_scanline_101010x\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6485:transform_scanline_1010102_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6486:transform_scanline_1010102\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +6487:t2_hints_stems +6488:t2_hints_open +6489:t1_make_subfont +6490:t1_hints_stem +6491:t1_hints_open +6492:t1_decrypt +6493:t1_decoder_parse_metrics +6494:t1_decoder_init +6495:t1_decoder_done +6496:t1_cmap_unicode_init +6497:t1_cmap_unicode_char_next +6498:t1_cmap_unicode_char_index +6499:t1_cmap_std_done +6500:t1_cmap_std_char_next +6501:t1_cmap_std_char_index +6502:t1_cmap_standard_init +6503:t1_cmap_expert_init +6504:t1_cmap_custom_init +6505:t1_cmap_custom_done +6506:t1_cmap_custom_char_next +6507:t1_cmap_custom_char_index +6508:t1_builder_start_point +6509:t1_builder_init +6510:t1_builder_add_point1 +6511:t1_builder_add_point +6512:t1_builder_add_contour +6513:swizzle_small_index_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6514:swizzle_small_index_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6515:swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6516:swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6517:swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6518:swizzle_rgba16_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6519:swizzle_rgba16_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6520:swizzle_rgba16_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6521:swizzle_rgba16_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6522:swizzle_rgb_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6523:swizzle_rgb_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6524:swizzle_rgb_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6525:swizzle_rgb16_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6526:swizzle_rgb16_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6527:swizzle_rgb16_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6528:swizzle_mask32_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6529:swizzle_mask32_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6530:swizzle_mask32_to_rgba_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6531:swizzle_mask32_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6532:swizzle_mask32_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6533:swizzle_mask32_to_bgra_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6534:swizzle_mask32_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6535:swizzle_mask24_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6536:swizzle_mask24_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6537:swizzle_mask24_to_rgba_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6538:swizzle_mask24_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6539:swizzle_mask24_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6540:swizzle_mask24_to_bgra_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6541:swizzle_mask24_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6542:swizzle_mask16_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6543:swizzle_mask16_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6544:swizzle_mask16_to_rgba_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6545:swizzle_mask16_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6546:swizzle_mask16_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6547:swizzle_mask16_to_bgra_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6548:swizzle_mask16_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6549:swizzle_index_to_n32_skipZ\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6550:swizzle_index_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6551:swizzle_index_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6552:swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6553:swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6554:swizzle_grayalpha_to_a8\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6555:swizzle_gray_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6556:swizzle_gray_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6557:swizzle_cmyk_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6558:swizzle_cmyk_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6559:swizzle_cmyk_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6560:swizzle_bit_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6561:swizzle_bit_to_grayscale\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6562:swizzle_bit_to_f16\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6563:swizzle_bit_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6564:swizzle_bgr_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6565:string_read +6566:std::exception::what\28\29\20const +6567:std::bad_variant_access::what\28\29\20const +6568:std::bad_optional_access::what\28\29\20const +6569:std::bad_array_new_length::what\28\29\20const +6570:std::bad_alloc::what\28\29\20const +6571:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +6572:std::__2::unique_ptr>::operator=\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +6573:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20tm\20const*\2c\20char\2c\20char\29\20const +6574:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20tm\20const*\2c\20char\2c\20char\29\20const +6575:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6576:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6577:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6578:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6579:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6580:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +6581:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6582:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6583:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6584:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6585:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +6586:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +6587:std::__2::numpunct::~numpunct\28\29_18520 +6588:std::__2::numpunct::do_truename\28\29\20const +6589:std::__2::numpunct::do_grouping\28\29\20const +6590:std::__2::numpunct::do_falsename\28\29\20const +6591:std::__2::numpunct::~numpunct\28\29_18518 +6592:std::__2::numpunct::do_truename\28\29\20const +6593:std::__2::numpunct::do_thousands_sep\28\29\20const +6594:std::__2::numpunct::do_grouping\28\29\20const +6595:std::__2::numpunct::do_falsename\28\29\20const +6596:std::__2::numpunct::do_decimal_point\28\29\20const +6597:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20void\20const*\29\20const +6598:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\29\20const +6599:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\20long\29\20const +6600:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\29\20const +6601:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20long\29\20const +6602:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +6603:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20double\29\20const +6604:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20bool\29\20const +6605:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20void\20const*\29\20const +6606:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\29\20const +6607:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\20long\29\20const +6608:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\29\20const +6609:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20long\29\20const +6610:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +6611:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20double\29\20const +6612:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20bool\29\20const +6613:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +6614:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +6615:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +6616:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +6617:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6618:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +6619:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +6620:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +6621:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +6622:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +6623:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +6624:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +6625:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +6626:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6627:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +6628:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +6629:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +6630:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +6631:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6632:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +6633:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6634:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +6635:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +6636:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6637:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +6638:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6639:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6640:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6641:std::__2::locale::__imp::~__imp\28\29_18398 +6642:std::__2::ios_base::~ios_base\28\29_17761 +6643:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +6644:std::__2::ctype::do_toupper\28wchar_t\29\20const +6645:std::__2::ctype::do_toupper\28wchar_t*\2c\20wchar_t\20const*\29\20const +6646:std::__2::ctype::do_tolower\28wchar_t\29\20const +6647:std::__2::ctype::do_tolower\28wchar_t*\2c\20wchar_t\20const*\29\20const +6648:std::__2::ctype::do_scan_not\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6649:std::__2::ctype::do_scan_is\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6650:std::__2::ctype::do_narrow\28wchar_t\2c\20char\29\20const +6651:std::__2::ctype::do_narrow\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20char\2c\20char*\29\20const +6652:std::__2::ctype::do_is\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20unsigned\20long*\29\20const +6653:std::__2::ctype::do_is\28unsigned\20long\2c\20wchar_t\29\20const +6654:std::__2::ctype::~ctype\28\29_18446 +6655:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +6656:std::__2::ctype::do_toupper\28char\29\20const +6657:std::__2::ctype::do_toupper\28char*\2c\20char\20const*\29\20const +6658:std::__2::ctype::do_tolower\28char\29\20const +6659:std::__2::ctype::do_tolower\28char*\2c\20char\20const*\29\20const +6660:std::__2::ctype::do_narrow\28char\2c\20char\29\20const +6661:std::__2::ctype::do_narrow\28char\20const*\2c\20char\20const*\2c\20char\2c\20char*\29\20const +6662:std::__2::collate::do_transform\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6663:std::__2::collate::do_hash\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6664:std::__2::collate::do_compare\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6665:std::__2::collate::do_transform\28char\20const*\2c\20char\20const*\29\20const +6666:std::__2::collate::do_hash\28char\20const*\2c\20char\20const*\29\20const +6667:std::__2::collate::do_compare\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +6668:std::__2::codecvt::~codecvt\28\29_18464 +6669:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const +6670:std::__2::codecvt::do_out\28__mbstate_t&\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +6671:std::__2::codecvt::do_max_length\28\29\20const +6672:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +6673:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20wchar_t*\2c\20wchar_t*\2c\20wchar_t*&\29\20const +6674:std::__2::codecvt::do_encoding\28\29\20const +6675:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +6676:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29_17631 +6677:std::__2::basic_stringbuf\2c\20std::__2::allocator>::underflow\28\29 +6678:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +6679:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +6680:std::__2::basic_stringbuf\2c\20std::__2::allocator>::pbackfail\28int\29 +6681:std::__2::basic_stringbuf\2c\20std::__2::allocator>::overflow\28int\29 +6682:std::__2::basic_streambuf>::~basic_streambuf\28\29_17469 +6683:std::__2::basic_streambuf>::xsputn\28char\20const*\2c\20long\29 +6684:std::__2::basic_streambuf>::xsgetn\28char*\2c\20long\29 +6685:std::__2::basic_streambuf>::uflow\28\29 +6686:std::__2::basic_streambuf>::setbuf\28char*\2c\20long\29 +6687:std::__2::basic_streambuf>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +6688:std::__2::basic_streambuf>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +6689:std::__2::bad_function_call::what\28\29\20const +6690:std::__2::__time_get_c_storage::__x\28\29\20const +6691:std::__2::__time_get_c_storage::__weeks\28\29\20const +6692:std::__2::__time_get_c_storage::__r\28\29\20const +6693:std::__2::__time_get_c_storage::__months\28\29\20const +6694:std::__2::__time_get_c_storage::__c\28\29\20const +6695:std::__2::__time_get_c_storage::__am_pm\28\29\20const +6696:std::__2::__time_get_c_storage::__X\28\29\20const +6697:std::__2::__time_get_c_storage::__x\28\29\20const +6698:std::__2::__time_get_c_storage::__weeks\28\29\20const +6699:std::__2::__time_get_c_storage::__r\28\29\20const +6700:std::__2::__time_get_c_storage::__months\28\29\20const +6701:std::__2::__time_get_c_storage::__c\28\29\20const +6702:std::__2::__time_get_c_storage::__am_pm\28\29\20const +6703:std::__2::__time_get_c_storage::__X\28\29\20const +6704:std::__2::__shared_ptr_pointer<_IO_FILE*\2c\20void\20\28*\29\28_IO_FILE*\29\2c\20std::__2::allocator<_IO_FILE>>::__on_zero_shared\28\29 +6705:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7523 +6706:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6707:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +6708:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7808 +6709:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6710:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +6711:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_6236 +6712:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6713:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6714:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6715:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6716:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6717:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6718:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6719:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6720:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6721:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6722:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6723:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6724:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6725:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6726:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6727:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6728:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6729:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6730:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6731:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +6732:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6733:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +6734:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +6735:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6736:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +6737:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6738:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6739:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6740:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6741:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6742:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6743:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6744:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6745:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6746:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6747:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6748:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6749:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6750:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6751:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6752:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6753:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6754:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6755:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6756:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6757:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6758:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6759:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6760:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6761:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6762:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6763:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6764:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6765:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6766:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6767:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6768:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6769:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6770:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6771:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6772:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6773:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6774:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6775:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6776:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20float&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20SkPoint&&\2c\20SkPoint&&\2c\20skia::textlayout::InternalLineMetrics&&\2c\20bool&&\29 +6777:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>*\29\20const +6778:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28\29\20const +6779:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::operator\28\29\28skia::textlayout::Cluster*&&\29 +6780:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28std::__2::__function::__base*\29\20const +6781:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28\29\20const +6782:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6783:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28\29\20const +6784:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20SkSpan&&\2c\20float&\2c\20unsigned\20long&&\2c\20unsigned\20char&&\29 +6785:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28std::__2::__function::__base\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>*\29\20const +6786:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28\29\20const +6787:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::operator\28\29\28skia::textlayout::Block&&\2c\20skia_private::TArray&&\29 +6788:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28std::__2::__function::__base\29>*\29\20const +6789:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28\29\20const +6790:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::operator\28\29\28sk_sp&&\29 +6791:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28std::__2::__function::__base\29>*\29\20const +6792:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28\29\20const +6793:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::operator\28\29\28skia::textlayout::SkRange&&\29 +6794:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28std::__2::__function::__base\29>*\29\20const +6795:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28\29\20const +6796:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +6797:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +6798:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +6799:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29_10051 +6800:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29 +6801:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::operator\28\29\28void*&&\2c\20void\20const*&&\29 +6802:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy_deallocate\28\29 +6803:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy\28\29 +6804:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6805:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28\29\20const +6806:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6807:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6808:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6809:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6810:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6811:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6812:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +6813:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6814:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6815:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +6816:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6817:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6818:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +6819:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6820:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6821:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +6822:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +6823:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +6824:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::operator\28\29\28sktext::gpu::GlyphVector*&&\2c\20int&&\2c\20int&&\2c\20skgpu::MaskFormat&&\2c\20int&&\29 +6825:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28std::__2::__function::__base\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>*\29\20const +6826:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28\29\20const +6827:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::operator\28\29\28GrSurfaceProxy\20const*&&\29 +6828:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6829:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28\29\20const +6830:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +6831:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +6832:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +6833:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +6834:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +6835:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +6836:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +6837:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6838:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +6839:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6840:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6841:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6842:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6843:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +6844:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6845:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6846:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::operator\28\29\28\29 +6847:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6848:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28\29\20const +6849:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6850:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6851:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6852:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6853:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6854:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6855:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6856:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6857:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6858:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6859:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6860:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6861:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6862:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6863:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6864:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6865:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6866:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6867:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6868:std::__2::__function::__func>*\29::'lambda'\28int\2c\20int\29\2c\20std::__2::allocator>*\29::'lambda'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::operator\28\29\28int&&\2c\20int&&\29 +6869:std::__2::__function::__func>*\29::'lambda'\28int\2c\20int\29\2c\20std::__2::allocator>*\29::'lambda'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::__clone\28std::__2::__function::__base*\29\20const +6870:std::__2::__function::__func>*\29::'lambda'\28int\2c\20int\29\2c\20std::__2::allocator>*\29::'lambda'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::__clone\28\29\20const +6871:std::__2::__function::__func*\29::'lambda0'\28int\2c\20int\29\2c\20std::__2::allocator*\29::'lambda0'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::operator\28\29\28int&&\2c\20int&&\29 +6872:std::__2::__function::__func*\29::'lambda0'\28int\2c\20int\29\2c\20std::__2::allocator*\29::'lambda0'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::__clone\28std::__2::__function::__base*\29\20const +6873:std::__2::__function::__func*\29::'lambda0'\28int\2c\20int\29\2c\20std::__2::allocator*\29::'lambda0'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::__clone\28\29\20const +6874:std::__2::__function::__func*\29::'lambda'\28int\2c\20int\29\2c\20std::__2::allocator*\29::'lambda'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::operator\28\29\28int&&\2c\20int&&\29 +6875:std::__2::__function::__func*\29::'lambda'\28int\2c\20int\29\2c\20std::__2::allocator*\29::'lambda'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::__clone\28std::__2::__function::__base*\29\20const +6876:std::__2::__function::__func*\29::'lambda'\28int\2c\20int\29\2c\20std::__2::allocator*\29::'lambda'\28int\2c\20int\29>\2c\20void\20\28int\2c\20int\29>::__clone\28\29\20const +6877:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29_4367 +6878:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29 +6879:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +6880:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy_deallocate\28\29 +6881:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy\28\29 +6882:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6883:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6884:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +6885:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6886:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +6887:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6888:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6889:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6890:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6891:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6892:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6893:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::operator\28\29\28SkSL::Variable\20const&\29 +6894:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6895:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28\29\20const +6896:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::operator\28\29\28int&&\2c\20SkSL::Variable\20const*&&\2c\20SkSL::Expression\20const*&&\29 +6897:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6898:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28\29\20const +6899:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::operator\28\29\28unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\29 +6900:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +6901:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +6902:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +6903:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +6904:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::operator\28\29\28SkVertices\20const*&&\2c\20SkBlendMode&&\2c\20SkPaint\20const&\2c\20float&&\2c\20float&&\2c\20bool&&\29 +6905:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6906:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28\29\20const +6907:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::operator\28\29\28SkIRect\20const&\29 +6908:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6909:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28\29\20const +6910:std::__2::__function::__func\2c\20SkCodec::Result\20\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int\29>::operator\28\29\28SkImageInfo\20const&\2c\20void*&&\2c\20unsigned\20long&&\2c\20SkCodec::Options\20const&\2c\20int&&\29 +6911:std::__2::__function::__func\2c\20SkCodec::Result\20\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int\29>::__clone\28std::__2::__function::__base*\29\20const +6912:std::__2::__function::__func\2c\20SkCodec::Result\20\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int\29>::__clone\28\29\20const +6913:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9913 +6914:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +6915:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6916:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +6917:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +6918:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6919:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6920:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9511 +6921:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +6922:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6923:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +6924:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +6925:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6926:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6927:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9518 +6928:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +6929:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6930:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +6931:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +6932:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6933:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6934:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::operator\28\29\28GrTextureProxy*&&\2c\20SkIRect&&\2c\20GrColorType&&\2c\20void\20const*&&\2c\20unsigned\20long&&\29 +6935:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +6936:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28\29\20const +6937:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::operator\28\29\28GrBackendTexture&&\29 +6938:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28std::__2::__function::__base*\29\20const +6939:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28\29\20const +6940:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6941:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6942:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6943:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6944:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6945:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6946:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6947:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6948:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6949:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6950:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6951:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6952:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6953:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6954:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6955:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6956:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6957:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6958:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29_9015 +6959:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +6960:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +6961:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +6962:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29_9022 +6963:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +6964:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +6965:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +6966:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +6967:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +6968:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +6969:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::operator\28\29\28int&&\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*&&\29 +6970:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6971:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::__clone\28\29\20const +6972:start_pass_upsample +6973:start_pass_phuff_decoder +6974:start_pass_merged_upsample +6975:start_pass_main +6976:start_pass_huff_decoder +6977:start_pass_dpost +6978:start_pass_2_quant +6979:start_pass_1_quant +6980:start_pass +6981:start_output_pass +6982:start_input_pass_16918 +6983:srgb_to_hwb\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +6984:srgb_to_hsl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +6985:srcover_p\28unsigned\20char\2c\20unsigned\20char\29 +6986:sn_write +6987:sktext::gpu::post_purge_blob_message\28unsigned\20int\2c\20unsigned\20int\29 +6988:sktext::gpu::TextBlob::~TextBlob\28\29_12664 +6989:sktext::gpu::TextBlob::~TextBlob\28\29 +6990:sktext::gpu::SubRun::~SubRun\28\29 +6991:sktext::gpu::SlugImpl::~SlugImpl\28\29_12490 +6992:sktext::gpu::SlugImpl::~SlugImpl\28\29 +6993:sktext::gpu::SlugImpl::sourceBounds\28\29\20const +6994:sktext::gpu::SlugImpl::sourceBoundsWithOrigin\28\29\20const +6995:sktext::gpu::SlugImpl::doFlatten\28SkWriteBuffer&\29\20const +6996:sktext::gpu::SDFMaskFilterImpl::getTypeName\28\29\20const +6997:sktext::gpu::SDFMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +6998:sktext::gpu::SDFMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +6999:skip_variable +7000:skif::\28anonymous\20namespace\29::RasterBackend::~RasterBackend\28\29 +7001:skif::\28anonymous\20namespace\29::RasterBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +7002:skif::\28anonymous\20namespace\29::RasterBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +7003:skif::\28anonymous\20namespace\29::RasterBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +7004:skif::\28anonymous\20namespace\29::RasterBackend::getBlurEngine\28\29\20const +7005:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10709 +7006:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +7007:skif::\28anonymous\20namespace\29::GaneshBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +7008:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +7009:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +7010:skif::\28anonymous\20namespace\29::GaneshBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +7011:skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +7012:skia_png_zalloc +7013:skia_png_write_rows +7014:skia_png_write_info +7015:skia_png_write_end +7016:skia_png_user_version_check +7017:skia_png_set_text +7018:skia_png_set_sRGB +7019:skia_png_set_keep_unknown_chunks +7020:skia_png_set_iCCP +7021:skia_png_set_gray_to_rgb +7022:skia_png_set_filter +7023:skia_png_set_filler +7024:skia_png_read_update_info +7025:skia_png_read_info +7026:skia_png_read_image +7027:skia_png_read_end +7028:skia_png_push_fill_buffer +7029:skia_png_process_data +7030:skia_png_default_write_data +7031:skia_png_default_read_data +7032:skia_png_default_flush +7033:skia_png_create_read_struct +7034:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29_7993 +7035:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29 +7036:skia::textlayout::TypefaceFontStyleSet::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +7037:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29_7986 +7038:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29 +7039:skia::textlayout::TypefaceFontProvider::onMatchFamily\28char\20const*\29\20const +7040:skia::textlayout::TypefaceFontProvider::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +7041:skia::textlayout::TypefaceFontProvider::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +7042:skia::textlayout::TypefaceFontProvider::onGetFamilyName\28int\2c\20SkString*\29\20const +7043:skia::textlayout::TypefaceFontProvider::onCreateStyleSet\28int\29\20const +7044:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29_7836 +7045:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29 +7046:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +7047:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +7048:skia::textlayout::PositionWithAffinity*\20emscripten::internal::raw_constructor\28\29 +7049:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29_7650 +7050:skia::textlayout::ParagraphImpl::visit\28std::__2::function\20const&\29 +7051:skia::textlayout::ParagraphImpl::updateTextAlign\28skia::textlayout::TextAlign\29 +7052:skia::textlayout::ParagraphImpl::updateForegroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +7053:skia::textlayout::ParagraphImpl::updateFontSize\28unsigned\20long\2c\20unsigned\20long\2c\20float\29 +7054:skia::textlayout::ParagraphImpl::updateBackgroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +7055:skia::textlayout::ParagraphImpl::unresolvedGlyphs\28\29 +7056:skia::textlayout::ParagraphImpl::unresolvedCodepoints\28\29 +7057:skia::textlayout::ParagraphImpl::paint\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\29 +7058:skia::textlayout::ParagraphImpl::paint\28SkCanvas*\2c\20float\2c\20float\29 +7059:skia::textlayout::ParagraphImpl::markDirty\28\29 +7060:skia::textlayout::ParagraphImpl::lineNumber\28\29 +7061:skia::textlayout::ParagraphImpl::layout\28float\29 +7062:skia::textlayout::ParagraphImpl::getWordBoundary\28unsigned\20int\29 +7063:skia::textlayout::ParagraphImpl::getRectsForRange\28unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +7064:skia::textlayout::ParagraphImpl::getRectsForPlaceholders\28\29 +7065:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +7066:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29 +7067:skia::textlayout::ParagraphImpl::getLineNumberAt\28unsigned\20long\29\20const +7068:skia::textlayout::ParagraphImpl::getLineNumberAtUTF16Offset\28unsigned\20long\29 +7069:skia::textlayout::ParagraphImpl::getLineMetrics\28std::__2::vector>&\29 +7070:skia::textlayout::ParagraphImpl::getLineMetricsAt\28int\2c\20skia::textlayout::LineMetrics*\29\20const +7071:skia::textlayout::ParagraphImpl::getGlyphPositionAtCoordinate\28float\2c\20float\29 +7072:skia::textlayout::ParagraphImpl::getFonts\28\29\20const +7073:skia::textlayout::ParagraphImpl::getFontAt\28unsigned\20long\29\20const +7074:skia::textlayout::ParagraphImpl::getFontAtUTF16Offset\28unsigned\20long\29 +7075:skia::textlayout::ParagraphImpl::getClosestUTF16GlyphInfoAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +7076:skia::textlayout::ParagraphImpl::getClosestGlyphClusterAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +7077:skia::textlayout::ParagraphImpl::getActualTextRange\28int\2c\20bool\29\20const +7078:skia::textlayout::ParagraphImpl::extendedVisit\28std::__2::function\20const&\29 +7079:skia::textlayout::ParagraphImpl::containsEmoji\28SkTextBlob*\29 +7080:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29::$_0::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +7081:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29 +7082:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29_7590 +7083:skia::textlayout::ParagraphBuilderImpl::pushStyle\28skia::textlayout::TextStyle\20const&\29 +7084:skia::textlayout::ParagraphBuilderImpl::pop\28\29 +7085:skia::textlayout::ParagraphBuilderImpl::peekStyle\28\29 +7086:skia::textlayout::ParagraphBuilderImpl::getText\28\29 +7087:skia::textlayout::ParagraphBuilderImpl::getParagraphStyle\28\29\20const +7088:skia::textlayout::ParagraphBuilderImpl::addText\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +7089:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\2c\20unsigned\20long\29 +7090:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\29 +7091:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\29 +7092:skia::textlayout::ParagraphBuilderImpl::Reset\28\29 +7093:skia::textlayout::ParagraphBuilderImpl::RequiresClientICU\28\29 +7094:skia::textlayout::ParagraphBuilderImpl::Build\28\29 +7095:skia::textlayout::Paragraph::getMinIntrinsicWidth\28\29 +7096:skia::textlayout::Paragraph::getMaxWidth\28\29 +7097:skia::textlayout::Paragraph::getMaxIntrinsicWidth\28\29 +7098:skia::textlayout::Paragraph::getLongestLine\28\29 +7099:skia::textlayout::Paragraph::getIdeographicBaseline\28\29 +7100:skia::textlayout::Paragraph::getHeight\28\29 +7101:skia::textlayout::Paragraph::getAlphabeticBaseline\28\29 +7102:skia::textlayout::Paragraph::didExceedMaxLines\28\29 +7103:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29_7738 +7104:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29 +7105:skia::textlayout::OneLineShaper::~OneLineShaper\28\29_7516 +7106:skia::textlayout::OneLineShaper::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +7107:skia::textlayout::OneLineShaper::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +7108:skia::textlayout::LangIterator::~LangIterator\28\29_7572 +7109:skia::textlayout::LangIterator::~LangIterator\28\29 +7110:skia::textlayout::LangIterator::endOfCurrentRun\28\29\20const +7111:skia::textlayout::LangIterator::currentLanguage\28\29\20const +7112:skia::textlayout::LangIterator::consume\28\29 +7113:skia::textlayout::LangIterator::atEnd\28\29\20const +7114:skia::textlayout::FontCollection::~FontCollection\28\29_7485 +7115:skia::textlayout::CanvasParagraphPainter::translate\28float\2c\20float\29 +7116:skia::textlayout::CanvasParagraphPainter::save\28\29 +7117:skia::textlayout::CanvasParagraphPainter::restore\28\29 +7118:skia::textlayout::CanvasParagraphPainter::drawTextShadow\28sk_sp\20const&\2c\20float\2c\20float\2c\20unsigned\20int\2c\20float\29 +7119:skia::textlayout::CanvasParagraphPainter::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20std::__2::variant\20const&\29 +7120:skia::textlayout::CanvasParagraphPainter::drawRect\28SkRect\20const&\2c\20std::__2::variant\20const&\29 +7121:skia::textlayout::CanvasParagraphPainter::drawPath\28SkPath\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +7122:skia::textlayout::CanvasParagraphPainter::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +7123:skia::textlayout::CanvasParagraphPainter::drawFilledRect\28SkRect\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +7124:skia::textlayout::CanvasParagraphPainter::clipRect\28SkRect\20const&\29 +7125:skgpu::tess::FixedCountWedges::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +7126:skgpu::tess::FixedCountWedges::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +7127:skgpu::tess::FixedCountStrokes::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +7128:skgpu::tess::FixedCountCurves::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +7129:skgpu::tess::FixedCountCurves::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +7130:skgpu::ganesh::texture_proxy_view_from_planes\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20skgpu::Budgeted\29::$_0::__invoke\28void*\2c\20void*\29 +7131:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29_11583 +7132:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::visitProxies\28std::__2::function\20const&\29\20const +7133:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7134:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7135:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7136:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::name\28\29\20const +7137:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::fixedFunctionFlags\28\29\20const +7138:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7139:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::name\28\29\20const +7140:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7141:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7142:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7143:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +7144:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29_11459 +7145:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29 +7146:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::name\28\29\20const +7147:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7148:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7149:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29_10856 +7150:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29 +7151:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +7152:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7153:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7154:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7155:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7156:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::name\28\29\20const +7157:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::fixedFunctionFlags\28\29\20const +7158:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7159:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29_10799 +7160:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29 +7161:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +7162:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7163:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7164:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7165:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7166:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::name\28\29\20const +7167:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7168:skgpu::ganesh::TriangulatingPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7169:skgpu::ganesh::TriangulatingPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7170:skgpu::ganesh::TriangulatingPathRenderer::name\28\29\20const +7171:skgpu::ganesh::TessellationPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +7172:skgpu::ganesh::TessellationPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +7173:skgpu::ganesh::TessellationPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7174:skgpu::ganesh::TessellationPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7175:skgpu::ganesh::TessellationPathRenderer::name\28\29\20const +7176:skgpu::ganesh::SurfaceDrawContext::willReplaceOpsTask\28skgpu::ganesh::OpsTask*\2c\20skgpu::ganesh::OpsTask*\29 +7177:skgpu::ganesh::SurfaceDrawContext::canDiscardPreviousOpsOnFullClear\28\29\20const +7178:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29_8986 +7179:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +7180:skgpu::ganesh::SurfaceContext::asyncReadPixels\28GrDirectContext*\2c\20SkIRect\20const&\2c\20SkColorType\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +7181:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29_11654 +7182:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29 +7183:skgpu::ganesh::StrokeTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +7184:skgpu::ganesh::StrokeTessellateOp::usesStencil\28\29\20const +7185:skgpu::ganesh::StrokeTessellateOp::onPrepare\28GrOpFlushState*\29 +7186:skgpu::ganesh::StrokeTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7187:skgpu::ganesh::StrokeTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7188:skgpu::ganesh::StrokeTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7189:skgpu::ganesh::StrokeTessellateOp::name\28\29\20const +7190:skgpu::ganesh::StrokeTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7191:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29_11632 +7192:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29 +7193:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +7194:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::programInfo\28\29 +7195:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7196:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7197:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7198:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::name\28\29\20const +7199:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7200:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29_11621 +7201:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29 +7202:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +7203:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::programInfo\28\29 +7204:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7205:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7206:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7207:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7208:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::name\28\29\20const +7209:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7210:skgpu::ganesh::StencilClip::~StencilClip\28\29_10001 +7211:skgpu::ganesh::StencilClip::~StencilClip\28\29 +7212:skgpu::ganesh::StencilClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +7213:skgpu::ganesh::StencilClip::getConservativeBounds\28\29\20const +7214:skgpu::ganesh::StencilClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +7215:skgpu::ganesh::SoftwarePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7216:skgpu::ganesh::SoftwarePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7217:skgpu::ganesh::SoftwarePathRenderer::name\28\29\20const +7218:skgpu::ganesh::SmallPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7219:skgpu::ganesh::SmallPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7220:skgpu::ganesh::SmallPathRenderer::name\28\29\20const +7221:skgpu::ganesh::SmallPathAtlasMgr::preFlush\28GrOnFlushResourceProvider*\29 +7222:skgpu::ganesh::SmallPathAtlasMgr::postFlush\28skgpu::AtlasToken\29 +7223:skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +7224:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29_11530 +7225:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29 +7226:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::visitProxies\28std::__2::function\20const&\29\20const +7227:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::programInfo\28\29 +7228:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +7229:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7230:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7231:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7232:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::name\28\29\20const +7233:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7234:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_quad_generic\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7235:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7236:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7237:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7238:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7239:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7240:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7241:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +7242:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29_11519 +7243:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29 +7244:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::onTextureSampler\28int\29\20const +7245:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::name\28\29\20const +7246:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7247:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7248:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7249:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +7250:skgpu::ganesh::PathWedgeTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +7251:skgpu::ganesh::PathTessellator::~PathTessellator\28\29 +7252:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29_11494 +7253:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29 +7254:skgpu::ganesh::PathTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +7255:skgpu::ganesh::PathTessellateOp::usesStencil\28\29\20const +7256:skgpu::ganesh::PathTessellateOp::onPrepare\28GrOpFlushState*\29 +7257:skgpu::ganesh::PathTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7258:skgpu::ganesh::PathTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7259:skgpu::ganesh::PathTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7260:skgpu::ganesh::PathTessellateOp::name\28\29\20const +7261:skgpu::ganesh::PathTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7262:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29_11477 +7263:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29 +7264:skgpu::ganesh::PathStencilCoverOp::visitProxies\28std::__2::function\20const&\29\20const +7265:skgpu::ganesh::PathStencilCoverOp::onPrepare\28GrOpFlushState*\29 +7266:skgpu::ganesh::PathStencilCoverOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7267:skgpu::ganesh::PathStencilCoverOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7268:skgpu::ganesh::PathStencilCoverOp::name\28\29\20const +7269:skgpu::ganesh::PathStencilCoverOp::fixedFunctionFlags\28\29\20const +7270:skgpu::ganesh::PathStencilCoverOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7271:skgpu::ganesh::PathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +7272:skgpu::ganesh::PathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +7273:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29_11453 +7274:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29 +7275:skgpu::ganesh::PathInnerTriangulateOp::visitProxies\28std::__2::function\20const&\29\20const +7276:skgpu::ganesh::PathInnerTriangulateOp::onPrepare\28GrOpFlushState*\29 +7277:skgpu::ganesh::PathInnerTriangulateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7278:skgpu::ganesh::PathInnerTriangulateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7279:skgpu::ganesh::PathInnerTriangulateOp::name\28\29\20const +7280:skgpu::ganesh::PathInnerTriangulateOp::fixedFunctionFlags\28\29\20const +7281:skgpu::ganesh::PathInnerTriangulateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7282:skgpu::ganesh::PathCurveTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +7283:skgpu::ganesh::OpsTask::~OpsTask\28\29_11392 +7284:skgpu::ganesh::OpsTask::onPrepare\28GrOpFlushState*\29 +7285:skgpu::ganesh::OpsTask::onPrePrepare\28GrRecordingContext*\29 +7286:skgpu::ganesh::OpsTask::onMakeSkippable\28\29 +7287:skgpu::ganesh::OpsTask::onIsUsed\28GrSurfaceProxy*\29\20const +7288:skgpu::ganesh::OpsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +7289:skgpu::ganesh::OpsTask::endFlush\28GrDrawingManager*\29 +7290:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29_11364 +7291:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::visitProxies\28std::__2::function\20const&\29\20const +7292:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7293:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7294:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7295:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7296:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::name\28\29\20const +7297:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7298:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29_11376 +7299:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29 +7300:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::onTextureSampler\28int\29\20const +7301:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::name\28\29\20const +7302:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7303:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7304:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7305:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +7306:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29_11155 +7307:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29 +7308:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +7309:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::programInfo\28\29 +7310:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +7311:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7312:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7313:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7314:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::name\28\29\20const +7315:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7316:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::clipToShape\28skgpu::ganesh::SurfaceDrawContext*\2c\20SkClipOp\2c\20SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\29 +7317:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29_11172 +7318:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29 +7319:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::name\28\29\20const +7320:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7321:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +7322:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7323:skgpu::ganesh::DrawableOp::~DrawableOp\28\29_11145 +7324:skgpu::ganesh::DrawableOp::~DrawableOp\28\29 +7325:skgpu::ganesh::DrawableOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7326:skgpu::ganesh::DrawableOp::name\28\29\20const +7327:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29_11048 +7328:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29 +7329:skgpu::ganesh::DrawAtlasPathOp::visitProxies\28std::__2::function\20const&\29\20const +7330:skgpu::ganesh::DrawAtlasPathOp::onPrepare\28GrOpFlushState*\29 +7331:skgpu::ganesh::DrawAtlasPathOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7332:skgpu::ganesh::DrawAtlasPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7333:skgpu::ganesh::DrawAtlasPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7334:skgpu::ganesh::DrawAtlasPathOp::name\28\29\20const +7335:skgpu::ganesh::DrawAtlasPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7336:skgpu::ganesh::Device::~Device\28\29_8610 +7337:skgpu::ganesh::Device::~Device\28\29 +7338:skgpu::ganesh::Device::strikeDeviceInfo\28\29\20const +7339:skgpu::ganesh::Device::snapSpecial\28SkIRect\20const&\2c\20bool\29 +7340:skgpu::ganesh::Device::snapSpecialScaled\28SkIRect\20const&\2c\20SkISize\20const&\29 +7341:skgpu::ganesh::Device::replaceClip\28SkIRect\20const&\29 +7342:skgpu::ganesh::Device::recordingContext\28\29\20const +7343:skgpu::ganesh::Device::pushClipStack\28\29 +7344:skgpu::ganesh::Device::popClipStack\28\29 +7345:skgpu::ganesh::Device::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +7346:skgpu::ganesh::Device::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +7347:skgpu::ganesh::Device::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +7348:skgpu::ganesh::Device::onClipShader\28sk_sp\29 +7349:skgpu::ganesh::Device::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +7350:skgpu::ganesh::Device::makeSpecial\28SkImage\20const*\29 +7351:skgpu::ganesh::Device::isClipWideOpen\28\29\20const +7352:skgpu::ganesh::Device::isClipRect\28\29\20const +7353:skgpu::ganesh::Device::isClipEmpty\28\29\20const +7354:skgpu::ganesh::Device::isClipAntiAliased\28\29\20const +7355:skgpu::ganesh::Device::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +7356:skgpu::ganesh::Device::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +7357:skgpu::ganesh::Device::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +7358:skgpu::ganesh::Device::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +7359:skgpu::ganesh::Device::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +7360:skgpu::ganesh::Device::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +7361:skgpu::ganesh::Device::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +7362:skgpu::ganesh::Device::drawPaint\28SkPaint\20const&\29 +7363:skgpu::ganesh::Device::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +7364:skgpu::ganesh::Device::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +7365:skgpu::ganesh::Device::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +7366:skgpu::ganesh::Device::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +7367:skgpu::ganesh::Device::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +7368:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +7369:skgpu::ganesh::Device::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +7370:skgpu::ganesh::Device::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +7371:skgpu::ganesh::Device::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +7372:skgpu::ganesh::Device::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +7373:skgpu::ganesh::Device::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +7374:skgpu::ganesh::Device::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +7375:skgpu::ganesh::Device::devClipBounds\28\29\20const +7376:skgpu::ganesh::Device::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +7377:skgpu::ganesh::Device::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +7378:skgpu::ganesh::Device::convertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +7379:skgpu::ganesh::Device::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +7380:skgpu::ganesh::Device::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +7381:skgpu::ganesh::Device::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +7382:skgpu::ganesh::Device::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +7383:skgpu::ganesh::Device::android_utils_clipWithStencil\28\29 +7384:skgpu::ganesh::DefaultPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +7385:skgpu::ganesh::DefaultPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +7386:skgpu::ganesh::DefaultPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7387:skgpu::ganesh::DefaultPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7388:skgpu::ganesh::DefaultPathRenderer::name\28\29\20const +7389:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::name\28\29\20const +7390:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7391:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7392:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7393:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::name\28\29\20const +7394:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +7395:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7396:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +7397:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29_10971 +7398:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29 +7399:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::visitProxies\28std::__2::function\20const&\29\20const +7400:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::programInfo\28\29 +7401:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +7402:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7403:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7404:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7405:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::name\28\29\20const +7406:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::fixedFunctionFlags\28\29\20const +7407:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7408:skgpu::ganesh::DashLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7409:skgpu::ganesh::DashLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7410:skgpu::ganesh::DashLinePathRenderer::name\28\29\20const +7411:skgpu::ganesh::ClipStack::~ClipStack\28\29_8572 +7412:skgpu::ganesh::ClipStack::preApply\28SkRect\20const&\2c\20GrAA\29\20const +7413:skgpu::ganesh::ClipStack::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +7414:skgpu::ganesh::ClearOp::~ClearOp\28\29 +7415:skgpu::ganesh::ClearOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7416:skgpu::ganesh::ClearOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7417:skgpu::ganesh::ClearOp::name\28\29\20const +7418:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29_10943 +7419:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29 +7420:skgpu::ganesh::AtlasTextOp::visitProxies\28std::__2::function\20const&\29\20const +7421:skgpu::ganesh::AtlasTextOp::onPrepareDraws\28GrMeshDrawTarget*\29 +7422:skgpu::ganesh::AtlasTextOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +7423:skgpu::ganesh::AtlasTextOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7424:skgpu::ganesh::AtlasTextOp::name\28\29\20const +7425:skgpu::ganesh::AtlasTextOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +7426:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29_10922 +7427:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29 +7428:skgpu::ganesh::AtlasRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +7429:skgpu::ganesh::AtlasRenderTask::onExecute\28GrOpFlushState*\29 +7430:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10886 +7431:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +7432:skgpu::ganesh::AtlasPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7433:skgpu::ganesh::AtlasPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7434:skgpu::ganesh::AtlasPathRenderer::name\28\29\20const +7435:skgpu::ganesh::AALinearizingConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7436:skgpu::ganesh::AALinearizingConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7437:skgpu::ganesh::AALinearizingConvexPathRenderer::name\28\29\20const +7438:skgpu::ganesh::AAHairLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7439:skgpu::ganesh::AAHairLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7440:skgpu::ganesh::AAHairLinePathRenderer::name\28\29\20const +7441:skgpu::ganesh::AAConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +7442:skgpu::ganesh::AAConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +7443:skgpu::ganesh::AAConvexPathRenderer::name\28\29\20const +7444:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29_10045 +7445:skgpu::TAsyncReadResult::rowBytes\28int\29\20const +7446:skgpu::TAsyncReadResult::data\28int\29\20const +7447:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29_9478 +7448:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29 +7449:skgpu::StringKeyBuilder::appendComment\28char\20const*\29 +7450:skgpu::StringKeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +7451:skgpu::ShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\2c\20bool\29 +7452:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29_12416 +7453:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29 +7454:skgpu::RectanizerSkyline::reset\28\29 +7455:skgpu::RectanizerSkyline::percentFull\28\29\20const +7456:skgpu::RectanizerPow2::reset\28\29 +7457:skgpu::RectanizerPow2::percentFull\28\29\20const +7458:skgpu::RectanizerPow2::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +7459:skgpu::Plot::~Plot\28\29_12391 +7460:skgpu::Plot::~Plot\28\29 +7461:skgpu::KeyBuilder::~KeyBuilder\28\29 +7462:skgpu::KeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +7463:skgpu::DefaultShaderErrorHandler\28\29::DefaultShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\29 +7464:sk_write_fn\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20long\29 +7465:sk_sp*\20emscripten::internal::MemberAccess>::getWire\28sk_sp\20SimpleImageInfo::*\20const&\2c\20SimpleImageInfo&\29 +7466:sk_read_user_chunk\28png_struct_def*\2c\20png_unknown_chunk_t*\29 +7467:sk_mmap_releaseproc\28void\20const*\2c\20void*\29 +7468:sk_ft_stream_io\28FT_StreamRec_*\2c\20unsigned\20long\2c\20unsigned\20char*\2c\20unsigned\20long\29 +7469:sk_ft_realloc\28FT_MemoryRec_*\2c\20long\2c\20long\2c\20void*\29 +7470:sk_ft_free\28FT_MemoryRec_*\2c\20void*\29 +7471:sk_ft_alloc\28FT_MemoryRec_*\2c\20long\29 +7472:sk_dataref_releaseproc\28void\20const*\2c\20void*\29 +7473:sfnt_table_info +7474:sfnt_load_face +7475:sfnt_is_postscript +7476:sfnt_is_alphanumeric +7477:sfnt_init_face +7478:sfnt_get_ps_name +7479:sfnt_get_name_index +7480:sfnt_get_name_id +7481:sfnt_get_interface +7482:sfnt_get_glyph_name +7483:sfnt_get_charset_id +7484:sfnt_done_face +7485:setup_syllables_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7486:setup_syllables_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7487:setup_syllables_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7488:setup_syllables_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7489:setup_masks_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7490:setup_masks_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7491:setup_masks_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7492:setup_masks_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7493:setup_masks_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7494:setup_masks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7495:service_cleanup\28\29 +7496:sep_upsample +7497:self_destruct +7498:scriptGetMaxValue\28IntProperty\20const&\2c\20UProperty\29 +7499:save_marker +7500:sample8\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7501:sample6\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7502:sample4\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7503:sample2\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7504:sample1\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7505:rgb_rgb_convert +7506:rgb_rgb565_convert +7507:rgb_rgb565D_convert +7508:rgb_gray_convert +7509:reverse_hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +7510:reverse_hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +7511:reset_marker_reader +7512:reset_input_controller +7513:reset_error_mgr +7514:request_virt_sarray +7515:request_virt_barray +7516:reorder_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7517:reorder_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7518:reorder_marks_hebrew\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +7519:reorder_marks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +7520:reorder_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7521:release_data\28void*\2c\20void*\29 +7522:record_stch\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7523:record_rphf_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7524:record_pref_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7525:realize_virt_arrays +7526:read_restart_marker +7527:read_markers +7528:read_data_from_FT_Stream +7529:rbbi_cleanup_74 +7530:quantize_ord_dither +7531:quantize_fs_dither +7532:quantize3_ord_dither +7533:putil_cleanup\28\29 +7534:psnames_get_service +7535:pshinter_get_t2_funcs +7536:pshinter_get_t1_funcs +7537:pshinter_get_globals_funcs +7538:psh_globals_new +7539:psh_globals_destroy +7540:psaux_get_glyph_name +7541:ps_table_release +7542:ps_table_new +7543:ps_table_done +7544:ps_table_add +7545:ps_property_set +7546:ps_property_get +7547:ps_parser_to_token_array +7548:ps_parser_to_int +7549:ps_parser_to_fixed_array +7550:ps_parser_to_fixed +7551:ps_parser_to_coord_array +7552:ps_parser_to_bytes +7553:ps_parser_skip_spaces +7554:ps_parser_load_field_table +7555:ps_parser_init +7556:ps_hints_t2mask +7557:ps_hints_t2counter +7558:ps_hints_t1stem3 +7559:ps_hints_t1reset +7560:ps_hints_close +7561:ps_hints_apply +7562:ps_hinter_init +7563:ps_hinter_done +7564:ps_get_standard_strings +7565:ps_get_macintosh_name +7566:ps_decoder_init +7567:ps_builder_init +7568:progress_monitor\28jpeg_common_struct*\29 +7569:process_data_simple_main +7570:process_data_crank_post +7571:process_data_context_main +7572:prescan_quantize +7573:preprocess_text_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7574:preprocess_text_thai\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7575:preprocess_text_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7576:preprocess_text_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7577:prepare_for_output_pass +7578:premultiply_data +7579:premul_rgb\28SkRGBA4f<\28SkAlphaType\292>\29 +7580:premul_polar\28SkRGBA4f<\28SkAlphaType\292>\29 +7581:postprocess_glyphs_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +7582:post_process_prepass +7583:post_process_2pass +7584:post_process_1pass +7585:portable::xy_to_unit_angle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7586:portable::xy_to_radius\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7587:portable::xy_to_2pt_conical_well_behaved\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7588:portable::xy_to_2pt_conical_strip\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7589:portable::xy_to_2pt_conical_smaller\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7590:portable::xy_to_2pt_conical_greater\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7591:portable::xy_to_2pt_conical_focal_on_circle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7592:portable::xor_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7593:portable::white_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7594:portable::unpremul_polar\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7595:portable::unpremul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7596:portable::uniform_color_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7597:portable::trace_var\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7598:portable::trace_scope\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7599:portable::trace_line\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7600:portable::trace_exit\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7601:portable::trace_enter\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7602:portable::tan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7603:portable::swizzle_copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7604:portable::swizzle_copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7605:portable::swizzle_copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7606:portable::swizzle_copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7607:portable::swizzle_copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7608:portable::swizzle_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7609:portable::swizzle_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7610:portable::swizzle_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7611:portable::swizzle_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7612:portable::swizzle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7613:portable::swap_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7614:portable::swap_rb_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7615:portable::swap_rb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7616:portable::sub_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7617:portable::sub_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7618:portable::sub_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7619:portable::sub_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7620:portable::sub_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7621:portable::sub_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7622:portable::sub_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7623:portable::sub_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7624:portable::sub_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7625:portable::sub_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7626:portable::store_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7627:portable::store_src_a\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7628:portable::store_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7629:portable::store_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7630:portable::store_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7631:portable::store_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7632:portable::store_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7633:portable::store_r8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7634:portable::store_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7635:portable::store_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7636:portable::store_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7637:portable::store_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7638:portable::store_device_xy01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7639:portable::store_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7640:portable::store_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7641:portable::store_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7642:portable::store_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7643:portable::store_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7644:portable::store_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7645:portable::store_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7646:portable::store_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7647:portable::store_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7648:portable::store_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7649:portable::store_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7650:portable::store_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7651:portable::start_pipeline\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkRasterPipelineStage*\2c\20SkSpan\2c\20unsigned\20char*\29 +7652:portable::stack_rewind\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7653:portable::stack_checkpoint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7654:portable::srcover_rgba_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7655:portable::srcover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7656:portable::srcout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7657:portable::srcin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7658:portable::srcatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7659:portable::sqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7660:portable::splat_4_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7661:portable::splat_3_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7662:portable::splat_2_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7663:portable::softlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7664:portable::smoothstep_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7665:portable::sin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7666:portable::shuffle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7667:portable::set_base_pointer\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7668:portable::seed_shader\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7669:portable::screen\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7670:portable::scale_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7671:portable::scale_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7672:portable::scale_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7673:portable::scale_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7674:portable::saturation\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7675:portable::rgb_to_hsl\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7676:portable::repeat_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7677:portable::repeat_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7678:portable::repeat_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7679:portable::refract_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7680:portable::reenable_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7681:portable::rect_memset64\28unsigned\20long\20long*\2c\20unsigned\20long\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +7682:portable::rect_memset32\28unsigned\20int*\2c\20unsigned\20int\2c\20int\2c\20unsigned\20long\2c\20int\29 +7683:portable::rect_memset16\28unsigned\20short*\2c\20unsigned\20short\2c\20int\2c\20unsigned\20long\2c\20int\29 +7684:portable::premul_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7685:portable::premul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7686:portable::pow_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7687:portable::plus_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7688:portable::perlin_noise\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7689:portable::parametric\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7690:portable::overlay\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7691:portable::negate_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7692:portable::multiply\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7693:portable::mul_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7694:portable::mul_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7695:portable::mul_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7696:portable::mul_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7697:portable::mul_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7698:portable::mul_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7699:portable::mul_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7700:portable::mul_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7701:portable::mul_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7702:portable::mul_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7703:portable::mul_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7704:portable::mul_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7705:portable::move_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7706:portable::move_dst_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7707:portable::modulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7708:portable::mod_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7709:portable::mod_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7710:portable::mod_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7711:portable::mod_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7712:portable::mod_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7713:portable::mix_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7714:portable::mix_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7715:portable::mix_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7716:portable::mix_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7717:portable::mix_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7718:portable::mix_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7719:portable::mix_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7720:portable::mix_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7721:portable::mix_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7722:portable::mix_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7723:portable::mirror_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7724:portable::mirror_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7725:portable::mirror_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7726:portable::mipmap_linear_update\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7727:portable::mipmap_linear_init\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7728:portable::mipmap_linear_finish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7729:portable::min_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7730:portable::min_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7731:portable::min_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7732:portable::min_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7733:portable::min_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7734:portable::min_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7735:portable::min_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7736:portable::min_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7737:portable::min_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7738:portable::min_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7739:portable::min_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7740:portable::min_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7741:portable::min_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7742:portable::min_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7743:portable::min_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7744:portable::min_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7745:portable::merge_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7746:portable::merge_inv_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7747:portable::merge_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7748:portable::memset32\28unsigned\20int*\2c\20unsigned\20int\2c\20int\29 +7749:portable::memset16\28unsigned\20short*\2c\20unsigned\20short\2c\20int\29 +7750:portable::max_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7751:portable::max_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7752:portable::max_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7753:portable::max_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7754:portable::max_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7755:portable::max_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7756:portable::max_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7757:portable::max_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7758:portable::max_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7759:portable::max_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7760:portable::max_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7761:portable::max_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7762:portable::max_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7763:portable::max_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7764:portable::max_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7765:portable::max_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7766:portable::matrix_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7767:portable::matrix_scale_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7768:portable::matrix_perspective\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7769:portable::matrix_multiply_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7770:portable::matrix_multiply_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7771:portable::matrix_multiply_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7772:portable::matrix_4x5\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7773:portable::matrix_4x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7774:portable::matrix_3x4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7775:portable::matrix_3x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7776:portable::matrix_2x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7777:portable::mask_off_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7778:portable::mask_off_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7779:portable::mask_2pt_conical_nan\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7780:portable::mask_2pt_conical_degenerates\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7781:portable::luminosity\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7782:portable::log_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7783:portable::log2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7784:portable::load_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7785:portable::load_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7786:portable::load_rgf16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7787:portable::load_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7788:portable::load_rg88_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7789:portable::load_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7790:portable::load_rg1616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7791:portable::load_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7792:portable::load_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7793:portable::load_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7794:portable::load_f32_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7795:portable::load_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7796:portable::load_f16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7797:portable::load_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7798:portable::load_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7799:portable::load_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7800:portable::load_af16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7801:portable::load_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7802:portable::load_a8_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7803:portable::load_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7804:portable::load_a16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7805:portable::load_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7806:portable::load_8888_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7807:portable::load_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7808:portable::load_565_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7809:portable::load_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7810:portable::load_4444_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7811:portable::load_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7812:portable::load_16161616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7813:portable::load_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7814:portable::load_10x6_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7815:portable::load_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7816:portable::load_1010102_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7817:portable::load_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7818:portable::load_1010102_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7819:portable::load_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7820:portable::load_10101010_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7821:portable::load_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7822:portable::lighten\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7823:portable::lerp_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7824:portable::lerp_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7825:portable::lerp_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7826:portable::lerp_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7827:portable::just_return\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7828:portable::jump\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7829:portable::invsqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7830:portable::invsqrt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7831:portable::invsqrt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7832:portable::invsqrt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7833:portable::inverted_CMYK_to_RGB1\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7834:portable::inverted_CMYK_to_BGR1\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7835:portable::inverse_mat4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7836:portable::inverse_mat3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7837:portable::inverse_mat2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7838:portable::init_lane_masks\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7839:portable::hue\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7840:portable::hsl_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7841:portable::hardlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7842:portable::gray_to_RGB1\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7843:portable::grayA_to_rgbA\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7844:portable::grayA_to_RGBA\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7845:portable::gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7846:portable::gauss_a_to_rgba\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7847:portable::gather_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7848:portable::gather_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7849:portable::gather_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7850:portable::gather_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7851:portable::gather_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7852:portable::gather_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7853:portable::gather_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7854:portable::gather_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7855:portable::gather_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7856:portable::gather_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7857:portable::gather_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7858:portable::gather_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7859:portable::gather_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7860:portable::gather_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7861:portable::gather_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7862:portable::gather_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7863:portable::gamma_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7864:portable::force_opaque_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7865:portable::force_opaque\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7866:portable::floor_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7867:portable::floor_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7868:portable::floor_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7869:portable::floor_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7870:portable::exp_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7871:portable::exp2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7872:portable::exclusion\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7873:portable::exchange_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7874:portable::evenly_spaced_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7875:portable::evenly_spaced_2_stop_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7876:portable::emboss\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7877:portable::dstover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7878:portable::dstout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7879:portable::dstin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7880:portable::dstatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7881:portable::dot_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7882:portable::dot_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7883:portable::dot_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7884:portable::div_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7885:portable::div_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7886:portable::div_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7887:portable::div_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7888:portable::div_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7889:portable::div_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7890:portable::div_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7891:portable::div_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7892:portable::div_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7893:portable::div_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7894:portable::div_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7895:portable::div_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7896:portable::div_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7897:portable::div_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7898:portable::div_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7899:portable::dither\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7900:portable::difference\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7901:portable::decal_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7902:portable::decal_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7903:portable::decal_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7904:portable::darken\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7905:portable::css_oklab_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7906:portable::css_oklab_gamut_map_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7907:portable::css_lab_to_xyz\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7908:portable::css_hwb_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7909:portable::css_hsl_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7910:portable::css_hcl_to_lab\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7911:portable::cos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7912:portable::copy_uniform\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7913:portable::copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7914:portable::copy_slot_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7915:portable::copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7916:portable::copy_immutable_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7917:portable::copy_constant\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7918:portable::copy_4_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7919:portable::copy_4_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7920:portable::copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7921:portable::copy_4_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7922:portable::copy_3_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7923:portable::copy_3_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7924:portable::copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7925:portable::copy_3_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7926:portable::copy_2_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7927:portable::copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7928:portable::continue_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7929:portable::colordodge\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7930:portable::colorburn\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7931:portable::color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7932:portable::cmpne_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7933:portable::cmpne_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7934:portable::cmpne_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7935:portable::cmpne_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7936:portable::cmpne_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7937:portable::cmpne_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7938:portable::cmpne_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7939:portable::cmpne_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7940:portable::cmpne_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7941:portable::cmpne_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7942:portable::cmpne_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7943:portable::cmpne_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7944:portable::cmplt_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7945:portable::cmplt_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7946:portable::cmplt_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7947:portable::cmplt_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7948:portable::cmplt_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7949:portable::cmplt_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7950:portable::cmplt_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7951:portable::cmplt_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7952:portable::cmplt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7953:portable::cmplt_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7954:portable::cmplt_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7955:portable::cmplt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7956:portable::cmplt_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7957:portable::cmplt_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7958:portable::cmplt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7959:portable::cmplt_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7960:portable::cmplt_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7961:portable::cmplt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7962:portable::cmple_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7963:portable::cmple_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7964:portable::cmple_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7965:portable::cmple_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7966:portable::cmple_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7967:portable::cmple_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7968:portable::cmple_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7969:portable::cmple_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7970:portable::cmple_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7971:portable::cmple_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7972:portable::cmple_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7973:portable::cmple_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7974:portable::cmple_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7975:portable::cmple_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7976:portable::cmple_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7977:portable::cmple_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7978:portable::cmple_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7979:portable::cmple_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7980:portable::cmpeq_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7981:portable::cmpeq_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7982:portable::cmpeq_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7983:portable::cmpeq_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7984:portable::cmpeq_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7985:portable::cmpeq_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7986:portable::cmpeq_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7987:portable::cmpeq_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7988:portable::cmpeq_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7989:portable::cmpeq_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7990:portable::cmpeq_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7991:portable::cmpeq_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7992:portable::clear\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7993:portable::clamp_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7994:portable::clamp_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7995:portable::clamp_gamut\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7996:portable::clamp_a_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7997:portable::clamp_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7998:portable::ceil_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7999:portable::ceil_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8000:portable::ceil_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8001:portable::ceil_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8002:portable::cast_to_uint_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8003:portable::cast_to_uint_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8004:portable::cast_to_uint_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8005:portable::cast_to_uint_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8006:portable::cast_to_int_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8007:portable::cast_to_int_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8008:portable::cast_to_int_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8009:portable::cast_to_int_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8010:portable::cast_to_float_from_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8011:portable::cast_to_float_from_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8012:portable::cast_to_float_from_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8013:portable::cast_to_float_from_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8014:portable::cast_to_float_from_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8015:portable::cast_to_float_from_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8016:portable::cast_to_float_from_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8017:portable::cast_to_float_from_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8018:portable::case_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8019:portable::callback\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8020:portable::byte_tables\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8021:portable::bt709_luminance_or_luma_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8022:portable::bt709_luminance_or_luma_to_alpha\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8023:portable::branch_if_no_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8024:portable::branch_if_no_active_lanes_eq\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8025:portable::branch_if_any_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8026:portable::branch_if_all_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8027:portable::blit_row_s32a_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +8028:portable::black_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8029:portable::bitwise_xor_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8030:portable::bitwise_xor_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8031:portable::bitwise_xor_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8032:portable::bitwise_xor_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8033:portable::bitwise_xor_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8034:portable::bitwise_xor_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8035:portable::bitwise_or_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8036:portable::bitwise_or_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8037:portable::bitwise_or_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8038:portable::bitwise_or_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8039:portable::bitwise_or_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8040:portable::bitwise_and_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8041:portable::bitwise_and_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8042:portable::bitwise_and_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8043:portable::bitwise_and_imm_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8044:portable::bitwise_and_imm_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8045:portable::bitwise_and_imm_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8046:portable::bitwise_and_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8047:portable::bitwise_and_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8048:portable::bitwise_and_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8049:portable::bilinear_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8050:portable::bilinear_py\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8051:portable::bilinear_px\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8052:portable::bilinear_ny\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8053:portable::bilinear_nx\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8054:portable::bilerp_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8055:portable::bicubic_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8056:portable::bicubic_p3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8057:portable::bicubic_p3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8058:portable::bicubic_p1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8059:portable::bicubic_p1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8060:portable::bicubic_n3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8061:portable::bicubic_n3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8062:portable::bicubic_n1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8063:portable::bicubic_n1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8064:portable::bicubic_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8065:portable::atan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8066:portable::atan2_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8067:portable::asin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8068:portable::alter_2pt_conical_unswap\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8069:portable::alter_2pt_conical_compensate_focal\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8070:portable::alpha_to_red_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8071:portable::alpha_to_red\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8072:portable::alpha_to_gray_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8073:portable::alpha_to_gray\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8074:portable::add_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8075:portable::add_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8076:portable::add_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8077:portable::add_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8078:portable::add_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8079:portable::add_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8080:portable::add_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8081:portable::add_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8082:portable::add_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8083:portable::add_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8084:portable::add_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8085:portable::add_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8086:portable::acos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8087:portable::accumulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8088:portable::abs_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8089:portable::abs_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8090:portable::abs_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8091:portable::abs_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8092:portable::RGB_to_RGB1\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +8093:portable::RGB_to_BGR1\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +8094:portable::RGBA_to_rgbA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +8095:portable::RGBA_to_bgrA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +8096:portable::RGBA_to_BGRA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +8097:portable::PQish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8098:portable::HLGish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8099:portable::HLGinvish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8100:pop_arg_long_double +8101:pointerTOCLookupFn\28UDataMemory\20const*\2c\20char\20const*\2c\20int*\2c\20UErrorCode*\29 +8102:png_read_filter_row_up +8103:png_read_filter_row_sub +8104:png_read_filter_row_path_multibyte_pixel +8105:png_read_filter_row_path_1byte_pixel +8106:png_read_filter_row_avg +8107:pass2_no_dither +8108:pass2_fs_dither +8109:override_features_khmer\28hb_ot_shape_planner_t*\29 +8110:override_features_indic\28hb_ot_shape_planner_t*\29 +8111:override_features_hangul\28hb_ot_shape_planner_t*\29 +8112:output_message\28jpeg_common_struct*\29 +8113:output_message +8114:operator\20delete\28void*\2c\20unsigned\20long\29 +8115:offsetTOCLookupFn\28UDataMemory\20const*\2c\20char\20const*\2c\20int*\2c\20UErrorCode*\29 +8116:null_convert +8117:noop_upsample +8118:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_17637 +8119:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +8120:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_17556 +8121:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +8122:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10722 +8123:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10721 +8124:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10719 +8125:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +8126:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +8127:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +8128:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11558 +8129:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +8130:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +8131:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10890 +8132:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +8133:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +8134:non-virtual\20thunk\20to\20icu_74::UnicodeSet::~UnicodeSet\28\29_14432 +8135:non-virtual\20thunk\20to\20icu_74::UnicodeSet::~UnicodeSet\28\29 +8136:non-virtual\20thunk\20to\20icu_74::UnicodeSet::toPattern\28icu_74::UnicodeString&\2c\20signed\20char\29\20const +8137:non-virtual\20thunk\20to\20icu_74::UnicodeSet::matches\28icu_74::Replaceable\20const&\2c\20int&\2c\20int\2c\20signed\20char\29 +8138:non-virtual\20thunk\20to\20icu_74::UnicodeSet::matchesIndexValue\28unsigned\20char\29\20const +8139:non-virtual\20thunk\20to\20icu_74::UnicodeSet::addMatchSetTo\28icu_74::UnicodeSet&\29\20const +8140:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +8141:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +8142:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +8143:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +8144:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +8145:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12591 +8146:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +8147:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +8148:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +8149:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::glyphCount\28\29\20const +8150:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +8151:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +8152:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +8153:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +8154:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +8155:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +8156:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9867 +8157:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +8158:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +8159:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +8160:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +8161:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +8162:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29_9399 +8163:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29 +8164:non-virtual\20thunk\20to\20GrOpFlushState::writeView\28\29\20const +8165:non-virtual\20thunk\20to\20GrOpFlushState::usesMSAASurface\28\29\20const +8166:non-virtual\20thunk\20to\20GrOpFlushState::threadSafeCache\28\29\20const +8167:non-virtual\20thunk\20to\20GrOpFlushState::strikeCache\28\29\20const +8168:non-virtual\20thunk\20to\20GrOpFlushState::smallPathAtlasManager\28\29\20const +8169:non-virtual\20thunk\20to\20GrOpFlushState::sampledProxyArray\28\29 +8170:non-virtual\20thunk\20to\20GrOpFlushState::rtProxy\28\29\20const +8171:non-virtual\20thunk\20to\20GrOpFlushState::resourceProvider\28\29\20const +8172:non-virtual\20thunk\20to\20GrOpFlushState::renderPassBarriers\28\29\20const +8173:non-virtual\20thunk\20to\20GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +8174:non-virtual\20thunk\20to\20GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +8175:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndirectDraws\28int\29 +8176:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndices\28int\29 +8177:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +8178:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +8179:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +8180:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +8181:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +8182:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +8183:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +8184:non-virtual\20thunk\20to\20GrOpFlushState::dstProxyView\28\29\20const +8185:non-virtual\20thunk\20to\20GrOpFlushState::detachAppliedClip\28\29 +8186:non-virtual\20thunk\20to\20GrOpFlushState::deferredUploadTarget\28\29 +8187:non-virtual\20thunk\20to\20GrOpFlushState::colorLoadOp\28\29\20const +8188:non-virtual\20thunk\20to\20GrOpFlushState::caps\28\29\20const +8189:non-virtual\20thunk\20to\20GrOpFlushState::atlasManager\28\29\20const +8190:non-virtual\20thunk\20to\20GrOpFlushState::appliedClip\28\29\20const +8191:non-virtual\20thunk\20to\20GrGpuBuffer::~GrGpuBuffer\28\29 +8192:non-virtual\20thunk\20to\20GrGpuBuffer::unref\28\29\20const +8193:non-virtual\20thunk\20to\20GrGpuBuffer::ref\28\29\20const +8194:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_12325 +8195:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +8196:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onSetLabel\28\29 +8197:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +8198:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +8199:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +8200:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +8201:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::backendFormat\28\29\20const +8202:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10612 +8203:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +8204:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +8205:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +8206:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::dstColor\28\29 +8207:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29_11967 +8208:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29 +8209:new_color_map_2_quant +8210:new_color_map_1_quant +8211:merged_2v_upsample +8212:merged_1v_upsample +8213:locale_cleanup\28\29 +8214:lin_srgb_to_oklab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +8215:lin_srgb_to_okhcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +8216:legalstub$dynCall_vijjjii +8217:legalstub$dynCall_vijiii +8218:legalstub$dynCall_viji +8219:legalstub$dynCall_vij +8220:legalstub$dynCall_viijii +8221:legalstub$dynCall_viiiiij +8222:legalstub$dynCall_jiji +8223:legalstub$dynCall_jiiiiji +8224:legalstub$dynCall_jiiiiii +8225:legalstub$dynCall_jii +8226:legalstub$dynCall_ji +8227:legalstub$dynCall_iijjiii +8228:legalstub$dynCall_iijj +8229:legalstub$dynCall_iiji +8230:legalstub$dynCall_iij +8231:legalstub$dynCall_iiiji +8232:legalstub$dynCall_iiiiijj +8233:legalstub$dynCall_iiiiij +8234:legalstub$dynCall_iiiiiijj +8235:lcd_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +8236:layoutGetMaxValue\28IntProperty\20const&\2c\20UProperty\29 +8237:jpeg_start_output +8238:jpeg_start_decompress +8239:jpeg_skip_scanlines +8240:jpeg_save_markers +8241:jpeg_resync_to_restart +8242:jpeg_read_scanlines +8243:jpeg_read_raw_data +8244:jpeg_read_header +8245:jpeg_input_complete +8246:jpeg_idct_islow +8247:jpeg_idct_ifast +8248:jpeg_idct_float +8249:jpeg_idct_9x9 +8250:jpeg_idct_7x7 +8251:jpeg_idct_6x6 +8252:jpeg_idct_5x5 +8253:jpeg_idct_4x4 +8254:jpeg_idct_3x3 +8255:jpeg_idct_2x2 +8256:jpeg_idct_1x1 +8257:jpeg_idct_16x16 +8258:jpeg_idct_15x15 +8259:jpeg_idct_14x14 +8260:jpeg_idct_13x13 +8261:jpeg_idct_12x12 +8262:jpeg_idct_11x11 +8263:jpeg_idct_10x10 +8264:jpeg_finish_output +8265:jpeg_destroy_decompress +8266:jpeg_crop_scanline +8267:is_deleted_glyph\28hb_glyph_info_t\20const*\29 +8268:isRegionalIndicator\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8269:isPOSIX_xdigit\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8270:isPOSIX_print\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8271:isPOSIX_graph\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8272:isPOSIX_blank\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8273:isPOSIX_alnum\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8274:isNormInert\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8275:isMirrored\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8276:isJoinControl\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8277:isIDSUnaryOperator\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8278:isIDCompatMathStart\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8279:isIDCompatMathContinue\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8280:isCanonSegmentStarter\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8281:isBidiControl\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8282:isAcceptable\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29 +8283:int_upsample +8284:initial_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8285:icu_74::uprv_normalizer2_cleanup\28\29 +8286:icu_74::uprv_loaded_normalizer2_cleanup\28\29 +8287:icu_74::unames_cleanup\28\29 +8288:icu_74::umtx_init\28\29 +8289:icu_74::umtx_cleanup\28\29 +8290:icu_74::sortComparator\28void\20const*\2c\20void\20const*\2c\20void\20const*\29 +8291:icu_74::segmentStarterMapper\28void\20const*\2c\20unsigned\20int\29 +8292:icu_74::isAcceptable\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29 +8293:icu_74::compareElementStrings\28void\20const*\2c\20void\20const*\2c\20void\20const*\29 +8294:icu_74::cacheDeleter\28void*\29 +8295:icu_74::\28anonymous\20namespace\29::versionFilter\28int\2c\20void*\29 +8296:icu_74::\28anonymous\20namespace\29::utf16_caseContextIterator\28void*\2c\20signed\20char\29 +8297:icu_74::\28anonymous\20namespace\29::numericValueFilter\28int\2c\20void*\29 +8298:icu_74::\28anonymous\20namespace\29::intPropertyFilter\28int\2c\20void*\29 +8299:icu_74::\28anonymous\20namespace\29::emojiprops_cleanup\28\29 +8300:icu_74::\28anonymous\20namespace\29::cleanup\28\29 +8301:icu_74::\28anonymous\20namespace\29::cleanupKnownCanonicalized\28\29 +8302:icu_74::\28anonymous\20namespace\29::AliasReplacer::replace\28icu_74::Locale\20const&\2c\20icu_74::CharString&\2c\20UErrorCode&\29::$_1::__invoke\28void*\29 +8303:icu_74::\28anonymous\20namespace\29::AliasReplacer::AliasReplacer\28UErrorCode\29::'lambda'\28UElement\2c\20UElement\29::__invoke\28UElement\2c\20UElement\29 +8304:icu_74::\28anonymous\20namespace\29::AliasData::cleanup\28\29 +8305:icu_74::UnicodeString::~UnicodeString\28\29_14524 +8306:icu_74::UnicodeString::handleReplaceBetween\28int\2c\20int\2c\20icu_74::UnicodeString\20const&\29 +8307:icu_74::UnicodeString::getLength\28\29\20const +8308:icu_74::UnicodeString::getDynamicClassID\28\29\20const +8309:icu_74::UnicodeString::getCharAt\28int\29\20const +8310:icu_74::UnicodeString::extractBetween\28int\2c\20int\2c\20icu_74::UnicodeString&\29\20const +8311:icu_74::UnicodeString::copy\28int\2c\20int\2c\20int\29 +8312:icu_74::UnicodeString::clone\28\29\20const +8313:icu_74::UnicodeSet::~UnicodeSet\28\29_14431 +8314:icu_74::UnicodeSet::toPattern\28icu_74::UnicodeString&\2c\20signed\20char\29\20const +8315:icu_74::UnicodeSet::size\28\29\20const +8316:icu_74::UnicodeSet::retain\28int\2c\20int\29 +8317:icu_74::UnicodeSet::operator==\28icu_74::UnicodeSet\20const&\29\20const +8318:icu_74::UnicodeSet::isEmpty\28\29\20const +8319:icu_74::UnicodeSet::hashCode\28\29\20const +8320:icu_74::UnicodeSet::getDynamicClassID\28\29\20const +8321:icu_74::UnicodeSet::contains\28int\2c\20int\29\20const +8322:icu_74::UnicodeSet::containsAll\28icu_74::UnicodeSet\20const&\29\20const +8323:icu_74::UnicodeSet::complement\28int\2c\20int\29 +8324:icu_74::UnicodeSet::complementAll\28icu_74::UnicodeSet\20const&\29 +8325:icu_74::UnicodeSet::addMatchSetTo\28icu_74::UnicodeSet&\29\20const +8326:icu_74::UnhandledEngine::~UnhandledEngine\28\29_13399 +8327:icu_74::UnhandledEngine::~UnhandledEngine\28\29 +8328:icu_74::UnhandledEngine::handles\28int\2c\20char\20const*\29\20const +8329:icu_74::UnhandledEngine::handleCharacter\28int\29 +8330:icu_74::UnhandledEngine::findBreaks\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8331:icu_74::UVector::~UVector\28\29_14816 +8332:icu_74::UVector::getDynamicClassID\28\29\20const +8333:icu_74::UVector32::~UVector32\28\29_14840 +8334:icu_74::UVector32::getDynamicClassID\28\29\20const +8335:icu_74::UStack::getDynamicClassID\28\29\20const +8336:icu_74::UCharsTrieBuilder::~UCharsTrieBuilder\28\29_14171 +8337:icu_74::UCharsTrieBuilder::~UCharsTrieBuilder\28\29 +8338:icu_74::UCharsTrieBuilder::write\28int\29 +8339:icu_74::UCharsTrieBuilder::writeValueAndType\28signed\20char\2c\20int\2c\20int\29 +8340:icu_74::UCharsTrieBuilder::writeValueAndFinal\28int\2c\20signed\20char\29 +8341:icu_74::UCharsTrieBuilder::writeElementUnits\28int\2c\20int\2c\20int\29 +8342:icu_74::UCharsTrieBuilder::writeDeltaTo\28int\29 +8343:icu_74::UCharsTrieBuilder::skipElementsBySomeUnits\28int\2c\20int\2c\20int\29\20const +8344:icu_74::UCharsTrieBuilder::indexOfElementWithNextUnit\28int\2c\20int\2c\20char16_t\29\20const +8345:icu_74::UCharsTrieBuilder::getMinLinearMatch\28\29\20const +8346:icu_74::UCharsTrieBuilder::getLimitOfLinearMatch\28int\2c\20int\2c\20int\29\20const +8347:icu_74::UCharsTrieBuilder::getElementValue\28int\29\20const +8348:icu_74::UCharsTrieBuilder::getElementUnit\28int\2c\20int\29\20const +8349:icu_74::UCharsTrieBuilder::getElementStringLength\28int\29\20const +8350:icu_74::UCharsTrieBuilder::createLinearMatchNode\28int\2c\20int\2c\20int\2c\20icu_74::StringTrieBuilder::Node*\29\20const +8351:icu_74::UCharsTrieBuilder::countElementUnits\28int\2c\20int\2c\20int\29\20const +8352:icu_74::UCharsTrieBuilder::UCTLinearMatchNode::write\28icu_74::StringTrieBuilder&\29 +8353:icu_74::UCharsTrieBuilder::UCTLinearMatchNode::operator==\28icu_74::StringTrieBuilder::Node\20const&\29\20const +8354:icu_74::UCharsDictionaryMatcher::~UCharsDictionaryMatcher\28\29_13531 +8355:icu_74::UCharsDictionaryMatcher::~UCharsDictionaryMatcher\28\29 +8356:icu_74::UCharsDictionaryMatcher::matches\28UText*\2c\20int\2c\20int\2c\20int*\2c\20int*\2c\20int*\2c\20int*\29\20const +8357:icu_74::UCharCharacterIterator::setIndex\28int\29 +8358:icu_74::UCharCharacterIterator::setIndex32\28int\29 +8359:icu_74::UCharCharacterIterator::previous\28\29 +8360:icu_74::UCharCharacterIterator::previous32\28\29 +8361:icu_74::UCharCharacterIterator::operator==\28icu_74::ForwardCharacterIterator\20const&\29\20const +8362:icu_74::UCharCharacterIterator::next\28\29 +8363:icu_74::UCharCharacterIterator::nextPostInc\28\29 +8364:icu_74::UCharCharacterIterator::next32\28\29 +8365:icu_74::UCharCharacterIterator::next32PostInc\28\29 +8366:icu_74::UCharCharacterIterator::move\28int\2c\20icu_74::CharacterIterator::EOrigin\29 +8367:icu_74::UCharCharacterIterator::move32\28int\2c\20icu_74::CharacterIterator::EOrigin\29 +8368:icu_74::UCharCharacterIterator::last\28\29 +8369:icu_74::UCharCharacterIterator::last32\28\29 +8370:icu_74::UCharCharacterIterator::hashCode\28\29\20const +8371:icu_74::UCharCharacterIterator::hasPrevious\28\29 +8372:icu_74::UCharCharacterIterator::hasNext\28\29 +8373:icu_74::UCharCharacterIterator::getText\28icu_74::UnicodeString&\29 +8374:icu_74::UCharCharacterIterator::getDynamicClassID\28\29\20const +8375:icu_74::UCharCharacterIterator::first\28\29 +8376:icu_74::UCharCharacterIterator::firstPostInc\28\29 +8377:icu_74::UCharCharacterIterator::first32\28\29 +8378:icu_74::UCharCharacterIterator::first32PostInc\28\29 +8379:icu_74::UCharCharacterIterator::current\28\29\20const +8380:icu_74::UCharCharacterIterator::current32\28\29\20const +8381:icu_74::UCharCharacterIterator::clone\28\29\20const +8382:icu_74::ThaiBreakEngine::~ThaiBreakEngine\28\29_13511 +8383:icu_74::ThaiBreakEngine::~ThaiBreakEngine\28\29 +8384:icu_74::ThaiBreakEngine::divideUpDictionaryRange\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8385:icu_74::StringTrieBuilder::SplitBranchNode::write\28icu_74::StringTrieBuilder&\29 +8386:icu_74::StringTrieBuilder::SplitBranchNode::operator==\28icu_74::StringTrieBuilder::Node\20const&\29\20const +8387:icu_74::StringTrieBuilder::SplitBranchNode::markRightEdgesFirst\28int\29 +8388:icu_74::StringTrieBuilder::Node::markRightEdgesFirst\28int\29 +8389:icu_74::StringTrieBuilder::ListBranchNode::write\28icu_74::StringTrieBuilder&\29 +8390:icu_74::StringTrieBuilder::ListBranchNode::operator==\28icu_74::StringTrieBuilder::Node\20const&\29\20const +8391:icu_74::StringTrieBuilder::ListBranchNode::markRightEdgesFirst\28int\29 +8392:icu_74::StringTrieBuilder::IntermediateValueNode::write\28icu_74::StringTrieBuilder&\29 +8393:icu_74::StringTrieBuilder::IntermediateValueNode::operator==\28icu_74::StringTrieBuilder::Node\20const&\29\20const +8394:icu_74::StringTrieBuilder::IntermediateValueNode::markRightEdgesFirst\28int\29 +8395:icu_74::StringTrieBuilder::FinalValueNode::write\28icu_74::StringTrieBuilder&\29 +8396:icu_74::StringTrieBuilder::FinalValueNode::operator==\28icu_74::StringTrieBuilder::Node\20const&\29\20const +8397:icu_74::StringTrieBuilder::BranchHeadNode::write\28icu_74::StringTrieBuilder&\29 +8398:icu_74::StringEnumeration::unext\28int*\2c\20UErrorCode&\29 +8399:icu_74::StringEnumeration::snext\28UErrorCode&\29 +8400:icu_74::StringEnumeration::operator==\28icu_74::StringEnumeration\20const&\29\20const +8401:icu_74::StringEnumeration::operator!=\28icu_74::StringEnumeration\20const&\29\20const +8402:icu_74::StringEnumeration::next\28int*\2c\20UErrorCode&\29 +8403:icu_74::SimpleLocaleKeyFactory::~SimpleLocaleKeyFactory\28\29_14046 +8404:icu_74::SimpleLocaleKeyFactory::~SimpleLocaleKeyFactory\28\29 +8405:icu_74::SimpleLocaleKeyFactory::updateVisibleIDs\28icu_74::Hashtable&\2c\20UErrorCode&\29\20const +8406:icu_74::SimpleLocaleKeyFactory::getDynamicClassID\28\29\20const +8407:icu_74::SimpleLocaleKeyFactory::create\28icu_74::ICUServiceKey\20const&\2c\20icu_74::ICUService\20const*\2c\20UErrorCode&\29\20const +8408:icu_74::SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator\28\29_13556 +8409:icu_74::SimpleFilteredSentenceBreakIterator::~SimpleFilteredSentenceBreakIterator\28\29 +8410:icu_74::SimpleFilteredSentenceBreakIterator::setText\28icu_74::UnicodeString\20const&\29 +8411:icu_74::SimpleFilteredSentenceBreakIterator::setText\28UText*\2c\20UErrorCode&\29 +8412:icu_74::SimpleFilteredSentenceBreakIterator::refreshInputText\28UText*\2c\20UErrorCode&\29 +8413:icu_74::SimpleFilteredSentenceBreakIterator::previous\28\29 +8414:icu_74::SimpleFilteredSentenceBreakIterator::preceding\28int\29 +8415:icu_74::SimpleFilteredSentenceBreakIterator::next\28int\29 +8416:icu_74::SimpleFilteredSentenceBreakIterator::next\28\29 +8417:icu_74::SimpleFilteredSentenceBreakIterator::last\28\29 +8418:icu_74::SimpleFilteredSentenceBreakIterator::isBoundary\28int\29 +8419:icu_74::SimpleFilteredSentenceBreakIterator::getUText\28UText*\2c\20UErrorCode&\29\20const +8420:icu_74::SimpleFilteredSentenceBreakIterator::getText\28\29\20const +8421:icu_74::SimpleFilteredSentenceBreakIterator::following\28int\29 +8422:icu_74::SimpleFilteredSentenceBreakIterator::first\28\29 +8423:icu_74::SimpleFilteredSentenceBreakIterator::current\28\29\20const +8424:icu_74::SimpleFilteredSentenceBreakIterator::createBufferClone\28void*\2c\20int&\2c\20UErrorCode&\29 +8425:icu_74::SimpleFilteredSentenceBreakIterator::clone\28\29\20const +8426:icu_74::SimpleFilteredSentenceBreakIterator::adoptText\28icu_74::CharacterIterator*\29 +8427:icu_74::SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData\28\29_13553 +8428:icu_74::SimpleFilteredSentenceBreakData::~SimpleFilteredSentenceBreakData\28\29 +8429:icu_74::SimpleFilteredBreakIteratorBuilder::~SimpleFilteredBreakIteratorBuilder\28\29_13568 +8430:icu_74::SimpleFilteredBreakIteratorBuilder::~SimpleFilteredBreakIteratorBuilder\28\29 +8431:icu_74::SimpleFilteredBreakIteratorBuilder::unsuppressBreakAfter\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29 +8432:icu_74::SimpleFilteredBreakIteratorBuilder::suppressBreakAfter\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29 +8433:icu_74::SimpleFilteredBreakIteratorBuilder::build\28icu_74::BreakIterator*\2c\20UErrorCode&\29 +8434:icu_74::SimpleFactory::~SimpleFactory\28\29_13958 +8435:icu_74::SimpleFactory::~SimpleFactory\28\29 +8436:icu_74::SimpleFactory::updateVisibleIDs\28icu_74::Hashtable&\2c\20UErrorCode&\29\20const +8437:icu_74::SimpleFactory::getDynamicClassID\28\29\20const +8438:icu_74::SimpleFactory::getDisplayName\28icu_74::UnicodeString\20const&\2c\20icu_74::Locale\20const&\2c\20icu_74::UnicodeString&\29\20const +8439:icu_74::SimpleFactory::create\28icu_74::ICUServiceKey\20const&\2c\20icu_74::ICUService\20const*\2c\20UErrorCode&\29\20const +8440:icu_74::ServiceEnumeration::~ServiceEnumeration\28\29_14022 +8441:icu_74::ServiceEnumeration::~ServiceEnumeration\28\29 +8442:icu_74::ServiceEnumeration::snext\28UErrorCode&\29 +8443:icu_74::ServiceEnumeration::reset\28UErrorCode&\29 +8444:icu_74::ServiceEnumeration::getDynamicClassID\28\29\20const +8445:icu_74::ServiceEnumeration::count\28UErrorCode&\29\20const +8446:icu_74::ServiceEnumeration::clone\28\29\20const +8447:icu_74::RuleBasedBreakIterator::~RuleBasedBreakIterator\28\29_13889 +8448:icu_74::RuleBasedBreakIterator::setText\28icu_74::UnicodeString\20const&\29 +8449:icu_74::RuleBasedBreakIterator::setText\28UText*\2c\20UErrorCode&\29 +8450:icu_74::RuleBasedBreakIterator::refreshInputText\28UText*\2c\20UErrorCode&\29 +8451:icu_74::RuleBasedBreakIterator::previous\28\29 +8452:icu_74::RuleBasedBreakIterator::preceding\28int\29 +8453:icu_74::RuleBasedBreakIterator::operator==\28icu_74::BreakIterator\20const&\29\20const +8454:icu_74::RuleBasedBreakIterator::next\28int\29 +8455:icu_74::RuleBasedBreakIterator::next\28\29 +8456:icu_74::RuleBasedBreakIterator::last\28\29 +8457:icu_74::RuleBasedBreakIterator::isBoundary\28int\29 +8458:icu_74::RuleBasedBreakIterator::hashCode\28\29\20const +8459:icu_74::RuleBasedBreakIterator::getUText\28UText*\2c\20UErrorCode&\29\20const +8460:icu_74::RuleBasedBreakIterator::getText\28\29\20const +8461:icu_74::RuleBasedBreakIterator::getRules\28\29\20const +8462:icu_74::RuleBasedBreakIterator::getRuleStatus\28\29\20const +8463:icu_74::RuleBasedBreakIterator::getRuleStatusVec\28int*\2c\20int\2c\20UErrorCode&\29 +8464:icu_74::RuleBasedBreakIterator::getDynamicClassID\28\29\20const +8465:icu_74::RuleBasedBreakIterator::getBinaryRules\28unsigned\20int&\29 +8466:icu_74::RuleBasedBreakIterator::following\28int\29 +8467:icu_74::RuleBasedBreakIterator::first\28\29 +8468:icu_74::RuleBasedBreakIterator::current\28\29\20const +8469:icu_74::RuleBasedBreakIterator::createBufferClone\28void*\2c\20int&\2c\20UErrorCode&\29 +8470:icu_74::RuleBasedBreakIterator::clone\28\29\20const +8471:icu_74::RuleBasedBreakIterator::adoptText\28icu_74::CharacterIterator*\29 +8472:icu_74::RuleBasedBreakIterator::BreakCache::~BreakCache\28\29_13874 +8473:icu_74::RuleBasedBreakIterator::BreakCache::~BreakCache\28\29 +8474:icu_74::ResourceDataValue::~ResourceDataValue\28\29_14678 +8475:icu_74::ResourceDataValue::isNoInheritanceMarker\28\29\20const +8476:icu_74::ResourceDataValue::getUInt\28UErrorCode&\29\20const +8477:icu_74::ResourceDataValue::getType\28\29\20const +8478:icu_74::ResourceDataValue::getStringOrFirstOfArray\28UErrorCode&\29\20const +8479:icu_74::ResourceDataValue::getStringArray\28icu_74::UnicodeString*\2c\20int\2c\20UErrorCode&\29\20const +8480:icu_74::ResourceDataValue::getStringArrayOrStringAsArray\28icu_74::UnicodeString*\2c\20int\2c\20UErrorCode&\29\20const +8481:icu_74::ResourceDataValue::getInt\28UErrorCode&\29\20const +8482:icu_74::ResourceDataValue::getAliasString\28int&\2c\20UErrorCode&\29\20const +8483:icu_74::ResourceBundle::~ResourceBundle\28\29_13929 +8484:icu_74::ResourceBundle::~ResourceBundle\28\29 +8485:icu_74::ResourceBundle::getDynamicClassID\28\29\20const +8486:icu_74::ParsePosition::getDynamicClassID\28\29\20const +8487:icu_74::Normalizer2WithImpl::spanQuickCheckYes\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +8488:icu_74::Normalizer2WithImpl::normalize\28icu_74::UnicodeString\20const&\2c\20icu_74::UnicodeString&\2c\20UErrorCode&\29\20const +8489:icu_74::Normalizer2WithImpl::normalizeSecondAndAppend\28icu_74::UnicodeString&\2c\20icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +8490:icu_74::Normalizer2WithImpl::getRawDecomposition\28int\2c\20icu_74::UnicodeString&\29\20const +8491:icu_74::Normalizer2WithImpl::getDecomposition\28int\2c\20icu_74::UnicodeString&\29\20const +8492:icu_74::Normalizer2WithImpl::getCombiningClass\28int\29\20const +8493:icu_74::Normalizer2WithImpl::composePair\28int\2c\20int\29\20const +8494:icu_74::Normalizer2WithImpl::append\28icu_74::UnicodeString&\2c\20icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +8495:icu_74::Normalizer2Impl::~Normalizer2Impl\28\29_13813 +8496:icu_74::Normalizer2::normalizeUTF8\28unsigned\20int\2c\20icu_74::StringPiece\2c\20icu_74::ByteSink&\2c\20icu_74::Edits*\2c\20UErrorCode&\29\20const +8497:icu_74::Normalizer2::isNormalizedUTF8\28icu_74::StringPiece\2c\20UErrorCode&\29\20const +8498:icu_74::NoopNormalizer2::spanQuickCheckYes\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +8499:icu_74::NoopNormalizer2::normalize\28icu_74::UnicodeString\20const&\2c\20icu_74::UnicodeString&\2c\20UErrorCode&\29\20const +8500:icu_74::NoopNormalizer2::normalizeUTF8\28unsigned\20int\2c\20icu_74::StringPiece\2c\20icu_74::ByteSink&\2c\20icu_74::Edits*\2c\20UErrorCode&\29\20const +8501:icu_74::MlBreakEngine::~MlBreakEngine\28\29_13729 +8502:icu_74::LocaleKeyFactory::~LocaleKeyFactory\28\29_14005 +8503:icu_74::LocaleKeyFactory::updateVisibleIDs\28icu_74::Hashtable&\2c\20UErrorCode&\29\20const +8504:icu_74::LocaleKeyFactory::handlesKey\28icu_74::ICUServiceKey\20const&\2c\20UErrorCode&\29\20const +8505:icu_74::LocaleKeyFactory::getDynamicClassID\28\29\20const +8506:icu_74::LocaleKeyFactory::getDisplayName\28icu_74::UnicodeString\20const&\2c\20icu_74::Locale\20const&\2c\20icu_74::UnicodeString&\29\20const +8507:icu_74::LocaleKeyFactory::create\28icu_74::ICUServiceKey\20const&\2c\20icu_74::ICUService\20const*\2c\20UErrorCode&\29\20const +8508:icu_74::LocaleKey::~LocaleKey\28\29_13992 +8509:icu_74::LocaleKey::~LocaleKey\28\29 +8510:icu_74::LocaleKey::prefix\28icu_74::UnicodeString&\29\20const +8511:icu_74::LocaleKey::isFallbackOf\28icu_74::UnicodeString\20const&\29\20const +8512:icu_74::LocaleKey::getDynamicClassID\28\29\20const +8513:icu_74::LocaleKey::fallback\28\29 +8514:icu_74::LocaleKey::currentLocale\28icu_74::Locale&\29\20const +8515:icu_74::LocaleKey::currentID\28icu_74::UnicodeString&\29\20const +8516:icu_74::LocaleKey::currentDescriptor\28icu_74::UnicodeString&\29\20const +8517:icu_74::LocaleKey::canonicalLocale\28icu_74::Locale&\29\20const +8518:icu_74::LocaleKey::canonicalID\28icu_74::UnicodeString&\29\20const +8519:icu_74::LocaleBuilder::~LocaleBuilder\28\29_13599 +8520:icu_74::Locale::~Locale\28\29_13626 +8521:icu_74::Locale::getDynamicClassID\28\29\20const +8522:icu_74::LoadedNormalizer2Impl::~LoadedNormalizer2Impl\28\29_13587 +8523:icu_74::LoadedNormalizer2Impl::~LoadedNormalizer2Impl\28\29 +8524:icu_74::LoadedNormalizer2Impl::isAcceptable\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29 +8525:icu_74::LaoBreakEngine::~LaoBreakEngine\28\29_13515 +8526:icu_74::LaoBreakEngine::~LaoBreakEngine\28\29 +8527:icu_74::LSTMBreakEngine::~LSTMBreakEngine\28\29_13713 +8528:icu_74::LSTMBreakEngine::~LSTMBreakEngine\28\29 +8529:icu_74::LSTMBreakEngine::name\28\29\20const +8530:icu_74::LSTMBreakEngine::divideUpDictionaryRange\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8531:icu_74::KhmerBreakEngine::~KhmerBreakEngine\28\29_13523 +8532:icu_74::KhmerBreakEngine::~KhmerBreakEngine\28\29 +8533:icu_74::KhmerBreakEngine::divideUpDictionaryRange\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8534:icu_74::KeywordEnumeration::~KeywordEnumeration\28\29_13650 +8535:icu_74::KeywordEnumeration::~KeywordEnumeration\28\29 +8536:icu_74::KeywordEnumeration::snext\28UErrorCode&\29 +8537:icu_74::KeywordEnumeration::reset\28UErrorCode&\29 +8538:icu_74::KeywordEnumeration::next\28int*\2c\20UErrorCode&\29 +8539:icu_74::KeywordEnumeration::getDynamicClassID\28\29\20const +8540:icu_74::KeywordEnumeration::count\28UErrorCode&\29\20const +8541:icu_74::KeywordEnumeration::clone\28\29\20const +8542:icu_74::ICUServiceKey::~ICUServiceKey\28\29_13946 +8543:icu_74::ICUServiceKey::isFallbackOf\28icu_74::UnicodeString\20const&\29\20const +8544:icu_74::ICUServiceKey::getDynamicClassID\28\29\20const +8545:icu_74::ICUServiceKey::currentDescriptor\28icu_74::UnicodeString&\29\20const +8546:icu_74::ICUServiceKey::canonicalID\28icu_74::UnicodeString&\29\20const +8547:icu_74::ICUService::unregister\28void\20const*\2c\20UErrorCode&\29 +8548:icu_74::ICUService::reset\28\29 +8549:icu_74::ICUService::registerInstance\28icu_74::UObject*\2c\20icu_74::UnicodeString\20const&\2c\20signed\20char\2c\20UErrorCode&\29 +8550:icu_74::ICUService::registerFactory\28icu_74::ICUServiceFactory*\2c\20UErrorCode&\29 +8551:icu_74::ICUService::reInitializeFactories\28\29 +8552:icu_74::ICUService::notifyListener\28icu_74::EventListener&\29\20const +8553:icu_74::ICUService::isDefault\28\29\20const +8554:icu_74::ICUService::getKey\28icu_74::ICUServiceKey&\2c\20icu_74::UnicodeString*\2c\20UErrorCode&\29\20const +8555:icu_74::ICUService::createSimpleFactory\28icu_74::UObject*\2c\20icu_74::UnicodeString\20const&\2c\20signed\20char\2c\20UErrorCode&\29 +8556:icu_74::ICUService::createKey\28icu_74::UnicodeString\20const*\2c\20UErrorCode&\29\20const +8557:icu_74::ICUService::clearCaches\28\29 +8558:icu_74::ICUService::acceptsListener\28icu_74::EventListener\20const&\29\20const +8559:icu_74::ICUResourceBundleFactory::~ICUResourceBundleFactory\28\29_14040 +8560:icu_74::ICUResourceBundleFactory::handleCreate\28icu_74::Locale\20const&\2c\20int\2c\20icu_74::ICUService\20const*\2c\20UErrorCode&\29\20const +8561:icu_74::ICUResourceBundleFactory::getSupportedIDs\28UErrorCode&\29\20const +8562:icu_74::ICUResourceBundleFactory::getDynamicClassID\28\29\20const +8563:icu_74::ICUNotifier::removeListener\28icu_74::EventListener\20const*\2c\20UErrorCode&\29 +8564:icu_74::ICUNotifier::notifyChanged\28\29 +8565:icu_74::ICUNotifier::addListener\28icu_74::EventListener\20const*\2c\20UErrorCode&\29 +8566:icu_74::ICULocaleService::registerInstance\28icu_74::UObject*\2c\20icu_74::UnicodeString\20const&\2c\20signed\20char\2c\20UErrorCode&\29 +8567:icu_74::ICULocaleService::registerInstance\28icu_74::UObject*\2c\20icu_74::Locale\20const&\2c\20int\2c\20int\2c\20UErrorCode&\29 +8568:icu_74::ICULocaleService::registerInstance\28icu_74::UObject*\2c\20icu_74::Locale\20const&\2c\20int\2c\20UErrorCode&\29 +8569:icu_74::ICULocaleService::registerInstance\28icu_74::UObject*\2c\20icu_74::Locale\20const&\2c\20UErrorCode&\29 +8570:icu_74::ICULocaleService::getAvailableLocales\28\29\20const +8571:icu_74::ICULocaleService::createKey\28icu_74::UnicodeString\20const*\2c\20int\2c\20UErrorCode&\29\20const +8572:icu_74::ICULocaleService::createKey\28icu_74::UnicodeString\20const*\2c\20UErrorCode&\29\20const +8573:icu_74::ICULanguageBreakFactory::~ICULanguageBreakFactory\28\29_13405 +8574:icu_74::ICULanguageBreakFactory::~ICULanguageBreakFactory\28\29 +8575:icu_74::ICULanguageBreakFactory::loadEngineFor\28int\2c\20char\20const*\29 +8576:icu_74::ICULanguageBreakFactory::loadDictionaryMatcherFor\28UScriptCode\29 +8577:icu_74::ICULanguageBreakFactory::getEngineFor\28int\2c\20char\20const*\29 +8578:icu_74::ICULanguageBreakFactory::addExternalEngine\28icu_74::ExternalBreakEngine*\2c\20UErrorCode&\29 +8579:icu_74::ICUBreakIteratorService::~ICUBreakIteratorService\28\29_13432 +8580:icu_74::ICUBreakIteratorService::~ICUBreakIteratorService\28\29 +8581:icu_74::ICUBreakIteratorService::isDefault\28\29\20const +8582:icu_74::ICUBreakIteratorService::handleDefault\28icu_74::ICUServiceKey\20const&\2c\20icu_74::UnicodeString*\2c\20UErrorCode&\29\20const +8583:icu_74::ICUBreakIteratorService::cloneInstance\28icu_74::UObject*\29\20const +8584:icu_74::ICUBreakIteratorFactory::~ICUBreakIteratorFactory\28\29_13430 +8585:icu_74::ICUBreakIteratorFactory::~ICUBreakIteratorFactory\28\29 +8586:icu_74::ICUBreakIteratorFactory::handleCreate\28icu_74::Locale\20const&\2c\20int\2c\20icu_74::ICUService\20const*\2c\20UErrorCode&\29\20const +8587:icu_74::GraphemeClusterVectorizer::vectorize\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20icu_74::UVector32&\2c\20UErrorCode&\29\20const +8588:icu_74::FCDNormalizer2::spanQuickCheckYes\28char16_t\20const*\2c\20char16_t\20const*\2c\20UErrorCode&\29\20const +8589:icu_74::FCDNormalizer2::normalize\28char16_t\20const*\2c\20char16_t\20const*\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +8590:icu_74::FCDNormalizer2::normalizeAndAppend\28char16_t\20const*\2c\20char16_t\20const*\2c\20signed\20char\2c\20icu_74::UnicodeString&\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +8591:icu_74::FCDNormalizer2::isInert\28int\29\20const +8592:icu_74::EmojiProps::isAcceptable\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29 +8593:icu_74::DictionaryBreakEngine::setCharacters\28icu_74::UnicodeSet\20const&\29 +8594:icu_74::DictionaryBreakEngine::handles\28int\2c\20char\20const*\29\20const +8595:icu_74::DictionaryBreakEngine::findBreaks\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8596:icu_74::DecomposeNormalizer2::spanQuickCheckYes\28char16_t\20const*\2c\20char16_t\20const*\2c\20UErrorCode&\29\20const +8597:icu_74::DecomposeNormalizer2::normalize\28char16_t\20const*\2c\20char16_t\20const*\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +8598:icu_74::DecomposeNormalizer2::normalizeUTF8\28unsigned\20int\2c\20icu_74::StringPiece\2c\20icu_74::ByteSink&\2c\20icu_74::Edits*\2c\20UErrorCode&\29\20const +8599:icu_74::DecomposeNormalizer2::normalizeAndAppend\28char16_t\20const*\2c\20char16_t\20const*\2c\20signed\20char\2c\20icu_74::UnicodeString&\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +8600:icu_74::DecomposeNormalizer2::isNormalizedUTF8\28icu_74::StringPiece\2c\20UErrorCode&\29\20const +8601:icu_74::DecomposeNormalizer2::isInert\28int\29\20const +8602:icu_74::DecomposeNormalizer2::getQuickCheck\28int\29\20const +8603:icu_74::ConstArray2D::get\28int\2c\20int\29\20const +8604:icu_74::ConstArray1D::get\28int\29\20const +8605:icu_74::ComposeNormalizer2::spanQuickCheckYes\28char16_t\20const*\2c\20char16_t\20const*\2c\20UErrorCode&\29\20const +8606:icu_74::ComposeNormalizer2::quickCheck\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +8607:icu_74::ComposeNormalizer2::normalize\28char16_t\20const*\2c\20char16_t\20const*\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +8608:icu_74::ComposeNormalizer2::normalizeUTF8\28unsigned\20int\2c\20icu_74::StringPiece\2c\20icu_74::ByteSink&\2c\20icu_74::Edits*\2c\20UErrorCode&\29\20const +8609:icu_74::ComposeNormalizer2::normalizeAndAppend\28char16_t\20const*\2c\20char16_t\20const*\2c\20signed\20char\2c\20icu_74::UnicodeString&\2c\20icu_74::ReorderingBuffer&\2c\20UErrorCode&\29\20const +8610:icu_74::ComposeNormalizer2::isNormalized\28icu_74::UnicodeString\20const&\2c\20UErrorCode&\29\20const +8611:icu_74::ComposeNormalizer2::isNormalizedUTF8\28icu_74::StringPiece\2c\20UErrorCode&\29\20const +8612:icu_74::ComposeNormalizer2::isInert\28int\29\20const +8613:icu_74::ComposeNormalizer2::hasBoundaryBefore\28int\29\20const +8614:icu_74::ComposeNormalizer2::hasBoundaryAfter\28int\29\20const +8615:icu_74::ComposeNormalizer2::getQuickCheck\28int\29\20const +8616:icu_74::CodePointsVectorizer::vectorize\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20icu_74::UVector32&\2c\20UErrorCode&\29\20const +8617:icu_74::CjkBreakEngine::~CjkBreakEngine\28\29_13527 +8618:icu_74::CjkBreakEngine::divideUpDictionaryRange\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8619:icu_74::CheckedArrayByteSink::Reset\28\29 +8620:icu_74::CheckedArrayByteSink::GetAppendBuffer\28int\2c\20int\2c\20char*\2c\20int\2c\20int*\29 +8621:icu_74::CheckedArrayByteSink::Append\28char\20const*\2c\20int\29 +8622:icu_74::CharacterIterator::firstPostInc\28\29 +8623:icu_74::CharacterIterator::first32PostInc\28\29 +8624:icu_74::CharStringByteSink::GetAppendBuffer\28int\2c\20int\2c\20char*\2c\20int\2c\20int*\29 +8625:icu_74::CharStringByteSink::Append\28char\20const*\2c\20int\29 +8626:icu_74::BytesDictionaryMatcher::~BytesDictionaryMatcher\28\29_13535 +8627:icu_74::BytesDictionaryMatcher::~BytesDictionaryMatcher\28\29 +8628:icu_74::BytesDictionaryMatcher::matches\28UText*\2c\20int\2c\20int\2c\20int*\2c\20int*\2c\20int*\2c\20int*\29\20const +8629:icu_74::BurmeseBreakEngine::~BurmeseBreakEngine\28\29_13519 +8630:icu_74::BurmeseBreakEngine::~BurmeseBreakEngine\28\29 +8631:icu_74::BreakIterator::getRuleStatusVec\28int*\2c\20int\2c\20UErrorCode&\29 +8632:icu_74::BreakEngineWrapper::~BreakEngineWrapper\28\29_13411 +8633:icu_74::BreakEngineWrapper::~BreakEngineWrapper\28\29 +8634:icu_74::BreakEngineWrapper::handles\28int\2c\20char\20const*\29\20const +8635:icu_74::BreakEngineWrapper::findBreaks\28UText*\2c\20int\2c\20int\2c\20icu_74::UVector32&\2c\20signed\20char\2c\20UErrorCode&\29\20const +8636:icu_74::BMPSet::contains\28int\29\20const +8637:icu_74::Array1D::~Array1D\28\29_13700 +8638:icu_74::Array1D::~Array1D\28\29 +8639:icu_74::Array1D::get\28int\29\20const +8640:hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +8641:hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +8642:hb_unicode_script_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +8643:hb_unicode_general_category_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +8644:hb_ucd_script\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +8645:hb_ucd_mirroring\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +8646:hb_ucd_general_category\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +8647:hb_ucd_decompose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20void*\29 +8648:hb_ucd_compose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8649:hb_ucd_combining_class\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +8650:hb_syllabic_clear_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8651:hb_paint_sweep_gradient_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8652:hb_paint_push_transform_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8653:hb_paint_push_clip_rectangle_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8654:hb_paint_image_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +8655:hb_paint_extents_push_transform\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8656:hb_paint_extents_push_group\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +8657:hb_paint_extents_push_clip_rectangle\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8658:hb_paint_extents_push_clip_glyph\28hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_font_t*\2c\20void*\29 +8659:hb_paint_extents_pop_transform\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +8660:hb_paint_extents_pop_group\28hb_paint_funcs_t*\2c\20void*\2c\20hb_paint_composite_mode_t\2c\20void*\29 +8661:hb_paint_extents_pop_clip\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +8662:hb_paint_extents_paint_sweep_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8663:hb_paint_extents_paint_image\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +8664:hb_paint_extents_paint_color\28hb_paint_funcs_t*\2c\20void*\2c\20int\2c\20unsigned\20int\2c\20void*\29 +8665:hb_outline_recording_pen_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8666:hb_outline_recording_pen_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +8667:hb_outline_recording_pen_line_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +8668:hb_outline_recording_pen_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8669:hb_outline_recording_pen_close_path\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +8670:hb_ot_paint_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +8671:hb_ot_map_t::lookup_map_t::cmp\28void\20const*\2c\20void\20const*\29 +8672:hb_ot_map_t::feature_map_t::cmp\28void\20const*\2c\20void\20const*\29 +8673:hb_ot_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +8674:hb_ot_get_variation_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8675:hb_ot_get_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +8676:hb_ot_get_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8677:hb_ot_get_glyph_v_origin\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8678:hb_ot_get_glyph_v_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +8679:hb_ot_get_glyph_name\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +8680:hb_ot_get_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +8681:hb_ot_get_glyph_from_name\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +8682:hb_ot_get_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +8683:hb_ot_get_font_v_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +8684:hb_ot_get_font_h_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +8685:hb_ot_draw_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +8686:hb_font_paint_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +8687:hb_font_get_variation_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8688:hb_font_get_nominal_glyphs_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +8689:hb_font_get_nominal_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8690:hb_font_get_nominal_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8691:hb_font_get_glyph_v_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8692:hb_font_get_glyph_v_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8693:hb_font_get_glyph_v_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +8694:hb_font_get_glyph_v_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +8695:hb_font_get_glyph_v_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +8696:hb_font_get_glyph_v_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +8697:hb_font_get_glyph_name_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +8698:hb_font_get_glyph_name_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +8699:hb_font_get_glyph_h_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8700:hb_font_get_glyph_h_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8701:hb_font_get_glyph_h_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +8702:hb_font_get_glyph_h_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +8703:hb_font_get_glyph_h_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +8704:hb_font_get_glyph_h_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +8705:hb_font_get_glyph_from_name_default\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +8706:hb_font_get_glyph_extents_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +8707:hb_font_get_glyph_extents_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +8708:hb_font_get_glyph_contour_point_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8709:hb_font_get_glyph_contour_point_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +8710:hb_font_get_font_v_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +8711:hb_font_get_font_h_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +8712:hb_font_draw_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +8713:hb_draw_quadratic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8714:hb_draw_quadratic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8715:hb_draw_move_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +8716:hb_draw_line_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +8717:hb_draw_extents_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8718:hb_draw_extents_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8719:hb_draw_cubic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +8720:hb_draw_close_path_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +8721:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +8722:hb_aat_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +8723:hb_aat_map_builder_t::feature_event_t::cmp\28void\20const*\2c\20void\20const*\29 +8724:hashStringTrieNode\28UElement\29 +8725:hashEntry\28UElement\29 +8726:hasFullCompositionExclusion\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8727:hasEmojiProperty\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +8728:h2v2_upsample +8729:h2v2_merged_upsample_565D +8730:h2v2_merged_upsample_565 +8731:h2v2_merged_upsample +8732:h2v2_fancy_upsample +8733:h2v1_upsample +8734:h2v1_merged_upsample_565D +8735:h2v1_merged_upsample_565 +8736:h2v1_merged_upsample +8737:h2v1_fancy_upsample +8738:grayscale_convert +8739:gray_rgb_convert +8740:gray_rgb565_convert +8741:gray_rgb565D_convert +8742:gray_raster_render +8743:gray_raster_new +8744:gray_raster_done +8745:gray_move_to +8746:gray_line_to +8747:gray_cubic_to +8748:gray_conic_to +8749:get_sk_marker_list\28jpeg_decompress_struct*\29 +8750:get_sfnt_table +8751:get_interesting_appn +8752:getVo\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8753:getTrailCombiningClass\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8754:getScript\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8755:getNumericType\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8756:getNormQuickCheck\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8757:getLeadCombiningClass\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8758:getJoiningType\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8759:getJoiningGroup\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8760:getInSC\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8761:getInPC\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8762:getHangulSyllableType\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8763:getGeneralCategory\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8764:getCombiningClass\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8765:getBiDiPairedBracketType\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8766:getBiDiClass\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +8767:fullsize_upsample +8768:ft_smooth_transform +8769:ft_smooth_set_mode +8770:ft_smooth_render +8771:ft_smooth_overlap_spans +8772:ft_smooth_lcd_spans +8773:ft_smooth_init +8774:ft_smooth_get_cbox +8775:ft_gzip_free +8776:ft_gzip_alloc +8777:ft_ansi_stream_io +8778:ft_ansi_stream_close +8779:fquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +8780:format_message +8781:fmt_fp +8782:fline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +8783:first_axis_intersection\28double\20const*\2c\20bool\2c\20double\2c\20double*\29 +8784:finish_pass1 +8785:finish_output_pass +8786:finish_input_pass +8787:final_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8788:fcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +8789:fconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +8790:fast_swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8791:fast_swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8792:fast_swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8793:fast_swizzle_rgb_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8794:fast_swizzle_rgb_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8795:fast_swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8796:fast_swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8797:fast_swizzle_gray_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8798:fast_swizzle_cmyk_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8799:fast_swizzle_cmyk_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8800:error_exit +8801:error_callback +8802:equalStringTrieNodes\28UElement\2c\20UElement\29 +8803:emscripten_stack_get_current +8804:emscripten::internal::MethodInvoker\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20void\2c\20SkCanvas*\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&>::invoke\28void\20\28SkCanvas::*\20const&\29\28sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20SkPaint*\29 +8805:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint*\29 +8806:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\2c\20SkPaint*\29 +8807:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\2c\20float\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\29 +8808:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\29\2c\20SkCanvas*\2c\20float\2c\20float\29 +8809:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28SkPath\20const&\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20SkPath*\2c\20SkPaint*\29 +8810:emscripten::internal::MethodInvoker\20\28skia::textlayout::Paragraph::*\29\28unsigned\20int\29\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::Paragraph*\2c\20unsigned\20int>::invoke\28skia::textlayout::SkRange\20\28skia::textlayout::Paragraph::*\20const&\29\28unsigned\20int\29\2c\20skia::textlayout::Paragraph*\2c\20unsigned\20int\29 +8811:emscripten::internal::MethodInvoker::invoke\28skia::textlayout::PositionWithAffinity\20\28skia::textlayout::Paragraph::*\20const&\29\28float\2c\20float\29\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +8812:emscripten::internal::MethodInvoker\20\28SkVertices::Builder::*\29\28\29\2c\20sk_sp\2c\20SkVertices::Builder*>::invoke\28sk_sp\20\28SkVertices::Builder::*\20const&\29\28\29\2c\20SkVertices::Builder*\29 +8813:emscripten::internal::MethodInvoker::invoke\28int\20\28skia::textlayout::Paragraph::*\20const&\29\28unsigned\20long\29\20const\2c\20skia::textlayout::Paragraph\20const*\2c\20unsigned\20long\29 +8814:emscripten::internal::MethodInvoker::invoke\28bool\20\28SkPath::*\20const&\29\28float\2c\20float\29\20const\2c\20SkPath\20const*\2c\20float\2c\20float\29 +8815:emscripten::internal::MethodInvoker::invoke\28SkPath&\20\28SkPath::*\20const&\29\28bool\29\2c\20SkPath*\2c\20bool\29 +8816:emscripten::internal::Invoker::invoke\28SkVertices::Builder*\20\28*\29\28SkVertices::VertexMode&&\2c\20int&&\2c\20int&&\2c\20unsigned\20int&&\29\2c\20SkVertices::VertexMode\2c\20int\2c\20int\2c\20unsigned\20int\29 +8817:emscripten::internal::Invoker&&\2c\20float&&\2c\20float&&\2c\20float&&>::invoke\28SkFont*\20\28*\29\28sk_sp&&\2c\20float&&\2c\20float&&\2c\20float&&\29\2c\20sk_sp*\2c\20float\2c\20float\2c\20float\29 +8818:emscripten::internal::Invoker&&\2c\20float&&>::invoke\28SkFont*\20\28*\29\28sk_sp&&\2c\20float&&\29\2c\20sk_sp*\2c\20float\29 +8819:emscripten::internal::Invoker&&>::invoke\28SkFont*\20\28*\29\28sk_sp&&\29\2c\20sk_sp*\29 +8820:emscripten::internal::Invoker::invoke\28SkContourMeasureIter*\20\28*\29\28SkPath\20const&\2c\20bool&&\2c\20float&&\29\2c\20SkPath*\2c\20bool\2c\20float\29 +8821:emscripten::internal::Invoker::invoke\28SkCanvas*\20\28*\29\28float&&\2c\20float&&\29\2c\20float\2c\20float\29 +8822:emscripten::internal::Invoker::invoke\28void\20\28*\29\28unsigned\20long\2c\20unsigned\20long\29\2c\20unsigned\20long\2c\20unsigned\20long\29 +8823:emscripten::internal::Invoker::invoke\28void\20\28*\29\28emscripten::val\29\2c\20emscripten::_EM_VAL*\29 +8824:emscripten::internal::Invoker::invoke\28unsigned\20long\20\28*\29\28unsigned\20long\29\2c\20unsigned\20long\29 +8825:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont*\29 +8826:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont*\29 +8827:emscripten::internal::Invoker\2c\20sk_sp\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20int\2c\20int\2c\20sk_sp*\2c\20int\2c\20int\29 +8828:emscripten::internal::Invoker\2c\20sk_sp\2c\20int\2c\20int\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\29\2c\20sk_sp*\2c\20int\2c\20int\2c\20sk_sp*\29 +8829:emscripten::internal::Invoker\2c\20sk_sp\2c\20int\2c\20int>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20int\2c\20int\29 +8830:emscripten::internal::Invoker\2c\20sk_sp\2c\20SimpleImageInfo>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20SimpleImageInfo\29\2c\20sk_sp*\2c\20SimpleImageInfo*\29 +8831:emscripten::internal::Invoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\29 +8832:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +8833:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20sk_sp\29\2c\20unsigned\20long\2c\20sk_sp*\29 +8834:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +8835:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +8836:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29\2c\20float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29 +8837:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +8838:emscripten::internal::Invoker\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val>::invoke\28sk_sp\20\28*\29\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\2c\20emscripten::_EM_VAL*\29 +8839:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20int\2c\20float>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20int\2c\20float\29\2c\20unsigned\20long\2c\20int\2c\20float\29 +8840:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20SkPath>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20SkPath\29\2c\20unsigned\20long\2c\20SkPath*\29 +8841:emscripten::internal::Invoker\2c\20float\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28float\2c\20unsigned\20long\29\2c\20float\2c\20unsigned\20long\29 +8842:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20unsigned\20int>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20unsigned\20int\29\2c\20float\2c\20float\2c\20unsigned\20int\29 +8843:emscripten::internal::Invoker\2c\20float>::invoke\28sk_sp\20\28*\29\28float\29\2c\20float\29 +8844:emscripten::internal::Invoker\2c\20SkPath\20const&\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style>::invoke\28sk_sp\20\28*\29\28SkPath\20const&\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style\29\2c\20SkPath*\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style\29 +8845:emscripten::internal::Invoker\2c\20SkBlurStyle\2c\20float\2c\20bool>::invoke\28sk_sp\20\28*\29\28SkBlurStyle\2c\20float\2c\20bool\29\2c\20SkBlurStyle\2c\20float\2c\20bool\29 +8846:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20float\2c\20float\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20float\2c\20float\2c\20sk_sp\29\2c\20unsigned\20long\2c\20float\2c\20float\2c\20sk_sp*\29 +8847:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp\29\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp*\29 +8848:emscripten::internal::Invoker\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\29\2c\20sk_sp*\29 +8849:emscripten::internal::Invoker\2c\20sk_sp\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\29 +8850:emscripten::internal::Invoker\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +8851:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20sk_sp\29\2c\20float\2c\20float\2c\20sk_sp*\29 +8852:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp\29\2c\20float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp*\29 +8853:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20SkTileMode\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\29\2c\20float\2c\20float\2c\20SkTileMode\2c\20sk_sp*\29 +8854:emscripten::internal::Invoker\2c\20SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp\2c\20sk_sp\29\2c\20SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp*\2c\20sk_sp*\29 +8855:emscripten::internal::Invoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28SimpleImageInfo\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\29\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\29 +8856:emscripten::internal::Invoker\2c\20SimpleImageInfo\2c\20emscripten::val>::invoke\28sk_sp\20\28*\29\28SimpleImageInfo\2c\20emscripten::val\29\2c\20SimpleImageInfo*\2c\20emscripten::_EM_VAL*\29 +8857:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20int\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\29 +8858:emscripten::internal::Invoker>::invoke\28sk_sp\20\28*\29\28\29\29 +8859:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20SkBlendMode\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20SkBlendMode\2c\20sk_sp\29\2c\20unsigned\20long\2c\20SkBlendMode\2c\20sk_sp*\29 +8860:emscripten::internal::Invoker\2c\20sk_sp\20const&\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\20const&\2c\20sk_sp\29\2c\20sk_sp*\2c\20sk_sp*\29 +8861:emscripten::internal::Invoker\2c\20float\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20sk_sp\2c\20sk_sp\29\2c\20float\2c\20sk_sp*\2c\20sk_sp*\29 +8862:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28unsigned\20long\2c\20int\29\2c\20unsigned\20long\2c\20int\29 +8863:emscripten::internal::Invoker\2c\20std::__2::allocator>>::invoke\28emscripten::val\20\28*\29\28std::__2::basic_string\2c\20std::__2::allocator>\29\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\29 +8864:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28emscripten::val\2c\20emscripten::val\2c\20float\29\2c\20emscripten::_EM_VAL*\2c\20emscripten::_EM_VAL*\2c\20float\29 +8865:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28SkPath\20const&\2c\20SkPath\20const&\2c\20float\29\2c\20SkPath*\2c\20SkPath*\2c\20float\29 +8866:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28SkPath\20const&\2c\20SkPath\20const&\2c\20SkPathOp\29\2c\20SkPath*\2c\20SkPath*\2c\20SkPathOp\29 +8867:emscripten::internal::Invoker::invoke\28bool\20\28*\29\28unsigned\20long\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\29\2c\20unsigned\20long\2c\20SkPath*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\29 +8868:emscripten::internal::Invoker\2c\20sk_sp>::invoke\28bool\20\28*\29\28sk_sp\2c\20sk_sp\29\2c\20sk_sp*\2c\20sk_sp*\29 +8869:emscripten::internal::Invoker::invoke\28bool\20\28*\29\28SkPath\20const&\2c\20SkPath\20const&\29\2c\20SkPath*\2c\20SkPath*\29 +8870:emscripten::internal::Invoker\2c\20int\2c\20int>::invoke\28SkRuntimeEffect::TracedShader\20\28*\29\28sk_sp\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20int\2c\20int\29 +8871:emscripten::internal::Invoker::invoke\28SkPath\20\28*\29\28unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +8872:emscripten::internal::FunctionInvoker\2c\20unsigned\20long\29\2c\20void\2c\20skia::textlayout::TypefaceFontProvider&\2c\20sk_sp\2c\20unsigned\20long>::invoke\28void\20\28**\29\28skia::textlayout::TypefaceFontProvider&\2c\20sk_sp\2c\20unsigned\20long\29\2c\20skia::textlayout::TypefaceFontProvider*\2c\20sk_sp*\2c\20unsigned\20long\29 +8873:emscripten::internal::FunctionInvoker\2c\20std::__2::allocator>\29\2c\20void\2c\20skia::textlayout::ParagraphBuilderImpl&\2c\20std::__2::basic_string\2c\20std::__2::allocator>>::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\29 +8874:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20float\2c\20float\2c\20skia::textlayout::PlaceholderAlignment\2c\20skia::textlayout::TextBaseline\2c\20float\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20float\2c\20float\2c\20skia::textlayout::PlaceholderAlignment\2c\20skia::textlayout::TextBaseline\2c\20float\29 +8875:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\2c\20SkPaint\2c\20SkPaint\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20SimpleTextStyle*\2c\20SkPaint*\2c\20SkPaint*\29 +8876:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20SimpleTextStyle*\29 +8877:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +8878:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +8879:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +8880:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29 +8881:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +8882:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20SkPath\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29\2c\20SkPath*\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +8883:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkContourMeasure&\2c\20float\2c\20unsigned\20long\29\2c\20SkContourMeasure*\2c\20float\2c\20unsigned\20long\29 +8884:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont*\2c\20SkPaint*\29 +8885:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\2c\20SkPaint*\29 +8886:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +8887:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +8888:emscripten::internal::FunctionInvoker\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +8889:emscripten::internal::FunctionInvoker\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +8890:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont*\2c\20SkPaint*\29 +8891:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint*\29 +8892:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20int\29\2c\20SkCanvas*\2c\20SkPath*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20int\29 +8893:emscripten::internal::FunctionInvoker\2c\20std::__2::allocator>\20\28*\29\28SkSL::DebugTrace\20const*\29\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::DebugTrace\20const*>::invoke\28std::__2::basic_string\2c\20std::__2::allocator>\20\28**\29\28SkSL::DebugTrace\20const*\29\2c\20SkSL::DebugTrace\20const*\29 +8894:emscripten::internal::FunctionInvoker\20\28*\29\28SkFontMgr&\2c\20unsigned\20long\2c\20int\29\2c\20sk_sp\2c\20SkFontMgr&\2c\20unsigned\20long\2c\20int>::invoke\28sk_sp\20\28**\29\28SkFontMgr&\2c\20unsigned\20long\2c\20int\29\2c\20SkFontMgr*\2c\20unsigned\20long\2c\20int\29 +8895:emscripten::internal::FunctionInvoker\20\28*\29\28SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29\2c\20sk_sp\2c\20SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val>::invoke\28sk_sp\20\28**\29\28SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29\2c\20SkFontMgr*\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\2c\20emscripten::_EM_VAL*\29 +8896:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29\2c\20sk_sp\2c\20sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29 +8897:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29\2c\20sk_sp\2c\20sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29 +8898:emscripten::internal::FunctionInvoker\20\28*\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SkRuntimeEffect*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +8899:emscripten::internal::FunctionInvoker\20\28*\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29\2c\20SkRuntimeEffect*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29 +8900:emscripten::internal::FunctionInvoker\20\28*\29\28SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SkPicture*\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +8901:emscripten::internal::FunctionInvoker\20\28*\29\28SkPictureRecorder&\29\2c\20sk_sp\2c\20SkPictureRecorder&>::invoke\28sk_sp\20\28**\29\28SkPictureRecorder&\29\2c\20SkPictureRecorder*\29 +8902:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\29\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28**\29\28sk_sp\29\2c\20sk_sp*\29 +8903:emscripten::internal::FunctionInvoker\20\28*\29\28SkSurface&\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkSurface&\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkSurface&\2c\20unsigned\20long\29\2c\20SkSurface*\2c\20unsigned\20long\29 +8904:emscripten::internal::FunctionInvoker\20\28*\29\28SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo\29\2c\20sk_sp\2c\20SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo>::invoke\28sk_sp\20\28**\29\28SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo\29\2c\20SkSurface*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo*\29 +8905:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\29\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28**\29\28sk_sp\29\2c\20sk_sp*\29 +8906:emscripten::internal::FunctionInvoker\20\28*\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29\2c\20sk_sp\2c\20SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool>::invoke\28sk_sp\20\28**\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29\2c\20SkRuntimeEffect*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +8907:emscripten::internal::FunctionInvoker::invoke\28int\20\28**\29\28SkCanvas&\2c\20SkPaint\29\2c\20SkCanvas*\2c\20SkPaint*\29 +8908:emscripten::internal::FunctionInvoker::invoke\28int\20\28**\29\28SkCanvas&\2c\20SkPaint\20const*\2c\20unsigned\20long\2c\20SkImageFilter\20const*\2c\20unsigned\20int\2c\20SkTileMode\29\2c\20SkCanvas*\2c\20SkPaint\20const*\2c\20unsigned\20long\2c\20SkImageFilter\20const*\2c\20unsigned\20int\2c\20SkTileMode\29 +8909:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28skia::textlayout::Paragraph&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29\2c\20skia::textlayout::Paragraph*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +8910:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28skia::textlayout::Paragraph&\2c\20float\2c\20float\29\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +8911:emscripten::internal::FunctionInvoker\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29\2c\20emscripten::val\2c\20sk_sp\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*>::invoke\28emscripten::val\20\28**\29\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29\2c\20sk_sp*\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29 +8912:emscripten::internal::FunctionInvoker\2c\20SkEncodedImageFormat\2c\20int\29\2c\20emscripten::val\2c\20sk_sp\2c\20SkEncodedImageFormat\2c\20int>::invoke\28emscripten::val\20\28**\29\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\29\2c\20sk_sp*\2c\20SkEncodedImageFormat\2c\20int\29 +8913:emscripten::internal::FunctionInvoker\29\2c\20emscripten::val\2c\20sk_sp>::invoke\28emscripten::val\20\28**\29\28sk_sp\29\2c\20sk_sp*\29 +8914:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20float\2c\20float\29\2c\20SkFont*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20float\2c\20float\29 +8915:emscripten::internal::FunctionInvoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29\2c\20bool\2c\20sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*>::invoke\28bool\20\28**\29\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29\2c\20sk_sp*\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29 +8916:emscripten::internal::FunctionInvoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29\2c\20bool\2c\20sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int>::invoke\28bool\20\28**\29\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +8917:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\29 +8918:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20bool\29\2c\20SkPath*\2c\20float\2c\20float\2c\20bool\29 +8919:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20StrokeOpts\29\2c\20SkPath*\2c\20StrokeOpts*\29 +8920:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkCanvas&\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29\2c\20SkCanvas*\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +8921:emscripten::internal::FunctionInvoker::invoke\28SkPath\20\28**\29\28SkPath\20const&\29\2c\20SkPath*\29 +8922:emscripten::internal::FunctionInvoker::invoke\28SkPath\20\28**\29\28SkContourMeasure&\2c\20float\2c\20float\2c\20bool\29\2c\20SkContourMeasure*\2c\20float\2c\20float\2c\20bool\29 +8923:emscripten::internal::FunctionInvoker::invoke\28SkPaint\20\28**\29\28SkPaint\20const&\29\2c\20SkPaint*\29 +8924:emscripten::internal::FunctionInvoker::invoke\28SimpleImageInfo\20\28**\29\28SkSurface&\29\2c\20SkSurface*\29 +8925:emscripten::internal::FunctionInvoker::invoke\28RuntimeEffectUniform\20\28**\29\28SkRuntimeEffect&\2c\20int\29\2c\20SkRuntimeEffect*\2c\20int\29 +8926:emit_message +8927:embind_init_Skia\28\29::$_9::__invoke\28SkAnimatedImage&\29 +8928:embind_init_Skia\28\29::$_99::__invoke\28SkPath&\2c\20unsigned\20long\2c\20int\2c\20bool\29 +8929:embind_init_Skia\28\29::$_98::__invoke\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\29 +8930:embind_init_Skia\28\29::$_97::__invoke\28SkPath&\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20int\29 +8931:embind_init_Skia\28\29::$_96::__invoke\28SkPath&\2c\20unsigned\20long\2c\20float\2c\20float\29 +8932:embind_init_Skia\28\29::$_95::__invoke\28unsigned\20long\2c\20SkPath\29 +8933:embind_init_Skia\28\29::$_94::__invoke\28float\2c\20unsigned\20long\29 +8934:embind_init_Skia\28\29::$_93::__invoke\28unsigned\20long\2c\20int\2c\20float\29 +8935:embind_init_Skia\28\29::$_92::__invoke\28\29 +8936:embind_init_Skia\28\29::$_91::__invoke\28\29 +8937:embind_init_Skia\28\29::$_90::__invoke\28sk_sp\2c\20sk_sp\29 +8938:embind_init_Skia\28\29::$_8::__invoke\28emscripten::val\29 +8939:embind_init_Skia\28\29::$_89::__invoke\28SkPaint&\2c\20unsigned\20int\2c\20sk_sp\29 +8940:embind_init_Skia\28\29::$_88::__invoke\28SkPaint&\2c\20unsigned\20int\29 +8941:embind_init_Skia\28\29::$_87::__invoke\28SkPaint&\2c\20unsigned\20long\2c\20sk_sp\29 +8942:embind_init_Skia\28\29::$_86::__invoke\28SkPaint&\2c\20unsigned\20long\29 +8943:embind_init_Skia\28\29::$_85::__invoke\28SkPaint\20const&\29 +8944:embind_init_Skia\28\29::$_84::__invoke\28SkBlurStyle\2c\20float\2c\20bool\29 +8945:embind_init_Skia\28\29::$_83::__invoke\28float\2c\20float\2c\20sk_sp\29 +8946:embind_init_Skia\28\29::$_82::__invoke\28unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp\29 +8947:embind_init_Skia\28\29::$_81::__invoke\28unsigned\20long\2c\20float\2c\20float\2c\20sk_sp\29 +8948:embind_init_Skia\28\29::$_80::__invoke\28sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +8949:embind_init_Skia\28\29::$_7::__invoke\28GrDirectContext&\2c\20unsigned\20long\29 +8950:embind_init_Skia\28\29::$_79::__invoke\28sk_sp\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\29 +8951:embind_init_Skia\28\29::$_78::__invoke\28float\2c\20float\2c\20sk_sp\29 +8952:embind_init_Skia\28\29::$_77::__invoke\28float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp\29 +8953:embind_init_Skia\28\29::$_76::__invoke\28float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp\29 +8954:embind_init_Skia\28\29::$_75::__invoke\28sk_sp\29 +8955:embind_init_Skia\28\29::$_74::__invoke\28SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp\2c\20sk_sp\29 +8956:embind_init_Skia\28\29::$_73::__invoke\28float\2c\20float\2c\20sk_sp\29 +8957:embind_init_Skia\28\29::$_72::__invoke\28sk_sp\2c\20sk_sp\29 +8958:embind_init_Skia\28\29::$_71::__invoke\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\29 +8959:embind_init_Skia\28\29::$_70::__invoke\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29 +8960:embind_init_Skia\28\29::$_6::__invoke\28GrDirectContext&\29 +8961:embind_init_Skia\28\29::$_69::__invoke\28SkImageFilter\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +8962:embind_init_Skia\28\29::$_68::__invoke\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +8963:embind_init_Skia\28\29::$_67::__invoke\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29 +8964:embind_init_Skia\28\29::$_66::__invoke\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29 +8965:embind_init_Skia\28\29::$_65::__invoke\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29 +8966:embind_init_Skia\28\29::$_64::__invoke\28sk_sp\29 +8967:embind_init_Skia\28\29::$_63::__invoke\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29 +8968:embind_init_Skia\28\29::$_62::__invoke\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\29 +8969:embind_init_Skia\28\29::$_61::__invoke\28sk_sp\29 +8970:embind_init_Skia\28\29::$_60::__invoke\28sk_sp\29 +8971:embind_init_Skia\28\29::$_5::__invoke\28GrDirectContext&\29 +8972:embind_init_Skia\28\29::$_59::__invoke\28SkFontMgr&\2c\20unsigned\20long\2c\20int\29 +8973:embind_init_Skia\28\29::$_58::__invoke\28SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29 +8974:embind_init_Skia\28\29::$_57::__invoke\28SkFontMgr&\2c\20int\29 +8975:embind_init_Skia\28\29::$_56::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20int\29 +8976:embind_init_Skia\28\29::$_55::__invoke\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20float\2c\20float\29 +8977:embind_init_Skia\28\29::$_54::__invoke\28SkFont&\29 +8978:embind_init_Skia\28\29::$_53::__invoke\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +8979:embind_init_Skia\28\29::$_52::__invoke\28SkFont&\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPaint*\29 +8980:embind_init_Skia\28\29::$_51::__invoke\28SkContourMeasure&\2c\20float\2c\20float\2c\20bool\29 +8981:embind_init_Skia\28\29::$_50::__invoke\28SkContourMeasure&\2c\20float\2c\20unsigned\20long\29 +8982:embind_init_Skia\28\29::$_4::__invoke\28unsigned\20long\2c\20unsigned\20long\29 +8983:embind_init_Skia\28\29::$_49::__invoke\28unsigned\20long\29 +8984:embind_init_Skia\28\29::$_48::__invoke\28unsigned\20long\2c\20SkBlendMode\2c\20sk_sp\29 +8985:embind_init_Skia\28\29::$_47::__invoke\28SkCanvas&\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +8986:embind_init_Skia\28\29::$_46::__invoke\28SkCanvas&\2c\20SkPaint\29 +8987:embind_init_Skia\28\29::$_45::__invoke\28SkCanvas&\2c\20SkPaint\20const*\2c\20unsigned\20long\2c\20SkImageFilter\20const*\2c\20unsigned\20int\2c\20SkTileMode\29 +8988:embind_init_Skia\28\29::$_44::__invoke\28SkCanvas&\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +8989:embind_init_Skia\28\29::$_43::__invoke\28SkCanvas&\2c\20SimpleImageInfo\29 +8990:embind_init_Skia\28\29::$_42::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +8991:embind_init_Skia\28\29::$_41::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +8992:embind_init_Skia\28\29::$_40::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +8993:embind_init_Skia\28\29::$_3::__invoke\28unsigned\20long\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\29 +8994:embind_init_Skia\28\29::$_39::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +8995:embind_init_Skia\28\29::$_38::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29 +8996:embind_init_Skia\28\29::$_37::__invoke\28SkCanvas&\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20int\29 +8997:embind_init_Skia\28\29::$_36::__invoke\28SkCanvas&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +8998:embind_init_Skia\28\29::$_35::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +8999:embind_init_Skia\28\29::$_34::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +9000:embind_init_Skia\28\29::$_33::__invoke\28SkCanvas&\2c\20SkCanvas::PointMode\2c\20unsigned\20long\2c\20int\2c\20SkPaint&\29 +9001:embind_init_Skia\28\29::$_32::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9002:embind_init_Skia\28\29::$_31::__invoke\28SkCanvas&\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +9003:embind_init_Skia\28\29::$_30::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +9004:embind_init_Skia\28\29::$_2::__invoke\28SimpleImageInfo\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\29 +9005:embind_init_Skia\28\29::$_29::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +9006:embind_init_Skia\28\29::$_28::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +9007:embind_init_Skia\28\29::$_27::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\20const*\2c\20bool\29 +9008:embind_init_Skia\28\29::$_26::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +9009:embind_init_Skia\28\29::$_25::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +9010:embind_init_Skia\28\29::$_24::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +9011:embind_init_Skia\28\29::$_23::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +9012:embind_init_Skia\28\29::$_22::__invoke\28SkCanvas&\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29 +9013:embind_init_Skia\28\29::$_21::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +9014:embind_init_Skia\28\29::$_20::__invoke\28SkCanvas&\2c\20unsigned\20int\2c\20SkBlendMode\29 +9015:embind_init_Skia\28\29::$_1::__invoke\28unsigned\20long\2c\20unsigned\20long\29 +9016:embind_init_Skia\28\29::$_19::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkBlendMode\29 +9017:embind_init_Skia\28\29::$_18::__invoke\28SkCanvas&\2c\20unsigned\20long\29 +9018:embind_init_Skia\28\29::$_17::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +9019:embind_init_Skia\28\29::$_16::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +9020:embind_init_Skia\28\29::$_15::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +9021:embind_init_Skia\28\29::$_14::__invoke\28SkCanvas&\2c\20unsigned\20long\29 +9022:embind_init_Skia\28\29::$_149::__invoke\28SkVertices::Builder&\29 +9023:embind_init_Skia\28\29::$_148::__invoke\28SkVertices::Builder&\29 +9024:embind_init_Skia\28\29::$_147::__invoke\28SkVertices::Builder&\29 +9025:embind_init_Skia\28\29::$_146::__invoke\28SkVertices::Builder&\29 +9026:embind_init_Skia\28\29::$_145::__invoke\28SkVertices&\2c\20unsigned\20long\29 +9027:embind_init_Skia\28\29::$_144::__invoke\28SkTypeface&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +9028:embind_init_Skia\28\29::$_143::__invoke\28unsigned\20long\2c\20int\29 +9029:embind_init_Skia\28\29::$_142::__invoke\28\29 +9030:embind_init_Skia\28\29::$_141::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +9031:embind_init_Skia\28\29::$_140::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +9032:embind_init_Skia\28\29::$_13::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29 +9033:embind_init_Skia\28\29::$_139::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +9034:embind_init_Skia\28\29::$_138::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +9035:embind_init_Skia\28\29::$_137::__invoke\28SkSurface&\29 +9036:embind_init_Skia\28\29::$_136::__invoke\28SkSurface&\29 +9037:embind_init_Skia\28\29::$_135::__invoke\28SkSurface&\29 +9038:embind_init_Skia\28\29::$_134::__invoke\28SkSurface&\2c\20SimpleImageInfo\29 +9039:embind_init_Skia\28\29::$_133::__invoke\28SkSurface&\2c\20unsigned\20long\29 +9040:embind_init_Skia\28\29::$_132::__invoke\28SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo\29 +9041:embind_init_Skia\28\29::$_131::__invoke\28SkSurface&\29 +9042:embind_init_Skia\28\29::$_130::__invoke\28SkSurface&\29 +9043:embind_init_Skia\28\29::$_12::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29 +9044:embind_init_Skia\28\29::$_129::__invoke\28SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\29 +9045:embind_init_Skia\28\29::$_128::__invoke\28SkRuntimeEffect&\2c\20int\29 +9046:embind_init_Skia\28\29::$_127::__invoke\28SkRuntimeEffect&\2c\20int\29 +9047:embind_init_Skia\28\29::$_126::__invoke\28SkRuntimeEffect&\29 +9048:embind_init_Skia\28\29::$_125::__invoke\28SkRuntimeEffect&\29 +9049:embind_init_Skia\28\29::$_124::__invoke\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +9050:embind_init_Skia\28\29::$_123::__invoke\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +9051:embind_init_Skia\28\29::$_122::__invoke\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29 +9052:embind_init_Skia\28\29::$_121::__invoke\28sk_sp\2c\20int\2c\20int\29 +9053:embind_init_Skia\28\29::$_120::__invoke\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29 +9054:embind_init_Skia\28\29::$_11::__invoke\28SkCanvas&\2c\20unsigned\20long\29 +9055:embind_init_Skia\28\29::$_119::__invoke\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29 +9056:embind_init_Skia\28\29::$_118::__invoke\28SkSL::DebugTrace\20const*\29 +9057:embind_init_Skia\28\29::$_117::__invoke\28unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +9058:embind_init_Skia\28\29::$_116::__invoke\28float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29 +9059:embind_init_Skia\28\29::$_115::__invoke\28float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +9060:embind_init_Skia\28\29::$_114::__invoke\28float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +9061:embind_init_Skia\28\29::$_113::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +9062:embind_init_Skia\28\29::$_112::__invoke\28float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29 +9063:embind_init_Skia\28\29::$_111::__invoke\28unsigned\20long\2c\20sk_sp\29 +9064:embind_init_Skia\28\29::$_110::operator\28\29\28SkPicture&\29\20const::'lambda'\28SkImage*\2c\20void*\29::__invoke\28SkImage*\2c\20void*\29 +9065:embind_init_Skia\28\29::$_110::__invoke\28SkPicture&\29 +9066:embind_init_Skia\28\29::$_10::__invoke\28SkAnimatedImage&\29 +9067:embind_init_Skia\28\29::$_109::__invoke\28SkPicture&\2c\20unsigned\20long\29 +9068:embind_init_Skia\28\29::$_108::__invoke\28SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +9069:embind_init_Skia\28\29::$_107::__invoke\28SkPictureRecorder&\29 +9070:embind_init_Skia\28\29::$_106::__invoke\28SkPictureRecorder&\2c\20unsigned\20long\2c\20bool\29 +9071:embind_init_Skia\28\29::$_105::__invoke\28SkPath&\2c\20unsigned\20long\29 +9072:embind_init_Skia\28\29::$_104::__invoke\28SkPath&\2c\20unsigned\20long\29 +9073:embind_init_Skia\28\29::$_103::__invoke\28SkPath&\2c\20int\2c\20unsigned\20long\29 +9074:embind_init_Skia\28\29::$_102::__invoke\28SkPath&\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\29 +9075:embind_init_Skia\28\29::$_101::__invoke\28SkPath&\2c\20unsigned\20long\2c\20bool\29 +9076:embind_init_Skia\28\29::$_100::__invoke\28SkPath&\2c\20unsigned\20long\2c\20bool\29 +9077:embind_init_Skia\28\29::$_0::__invoke\28unsigned\20long\2c\20unsigned\20long\29 +9078:embind_init_Paragraph\28\29::$_9::__invoke\28skia::textlayout::ParagraphBuilderImpl&\29 +9079:embind_init_Paragraph\28\29::$_8::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20float\2c\20float\2c\20skia::textlayout::PlaceholderAlignment\2c\20skia::textlayout::TextBaseline\2c\20float\29 +9080:embind_init_Paragraph\28\29::$_7::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\2c\20SkPaint\2c\20SkPaint\29 +9081:embind_init_Paragraph\28\29::$_6::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\29 +9082:embind_init_Paragraph\28\29::$_4::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +9083:embind_init_Paragraph\28\29::$_3::__invoke\28emscripten::val\2c\20emscripten::val\2c\20float\29 +9084:embind_init_Paragraph\28\29::$_2::__invoke\28SimpleParagraphStyle\2c\20sk_sp\29 +9085:embind_init_Paragraph\28\29::$_19::__invoke\28skia::textlayout::FontCollection&\2c\20sk_sp\20const&\29 +9086:embind_init_Paragraph\28\29::$_18::__invoke\28\29 +9087:embind_init_Paragraph\28\29::$_17::__invoke\28skia::textlayout::TypefaceFontProvider&\2c\20sk_sp\2c\20unsigned\20long\29 +9088:embind_init_Paragraph\28\29::$_16::__invoke\28\29 +9089:dispose_external_texture\28void*\29 +9090:deleteJSTexture\28void*\29 +9091:deflate_slow +9092:deflate_fast +9093:defaultGetValue\28IntProperty\20const&\2c\20int\2c\20UProperty\29 +9094:defaultGetMaxValue\28IntProperty\20const&\2c\20UProperty\29 +9095:defaultContains\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +9096:decompress_smooth_data +9097:decompress_onepass +9098:decompress_data +9099:decompose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9100:decompose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9101:decompose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9102:decode_mcu_DC_refine +9103:decode_mcu_DC_first +9104:decode_mcu_AC_refine +9105:decode_mcu_AC_first +9106:decode_mcu +9107:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::Make\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20bool\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9108:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\2c\20GrShaderCaps\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::\28anonymous\20namespace\29::HullShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9109:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9110:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9111:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&>\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathTessellator::PathDrawList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9112:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29>\28skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20sk_sp\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9113:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Make\28SkArenaAlloc*\2c\20GrAAType\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9114:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerSkyline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9115:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerPow2&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9116:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make*\20SkArenaAlloc::make>\28\29::'lambda'\28void*\29>\28sk_sp&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9117:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc>\28\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TextureOpImpl::Desc&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9118:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TentPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9119:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::SimpleTriangleShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9120:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9121:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader\2c\20bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*\2c\20GrShaderCaps\20const&>\28bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*&&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::DrawAtlasPathShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9122:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&>\28SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::BoundingBoxShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9123:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20unsigned\20char&&\29::'lambda'\28void*\29>\28Sprite_D32_S32&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9124:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTriColorShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9125:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTCubic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9126:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTConic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9127:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\29::'lambda'\28void*\29>\28SkSpriteBlitter_Memcpy&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9128:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&>\28SkPixmap\20const&\2c\20SkArenaAlloc*&\2c\20sk_sp&\29::'lambda'\28void*\29>\28SkRasterPipelineSpriteBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9129:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkArenaAlloc*&\29::'lambda'\28void*\29>\28SkRasterPipelineBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9130:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkNullBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9131:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkImage_Base\20const*&&\2c\20SkMatrix\20const&\2c\20SkMipmapMode&\29::'lambda'\28void*\29>\28SkMipmapAccessor&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9132:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::PathData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9133:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::DrawableData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9134:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\29>>::Node*\20SkArenaAlloc::make&\29>>::Node\2c\20std::__2::function&\29>>\28std::__2::function&\29>&&\29::'lambda'\28void*\29>\28SkArenaAllocList&\29>>::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9135:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node\2c\20std::__2::function&\29>\2c\20skgpu::AtlasToken>\28std::__2::function&\29>&&\2c\20skgpu::AtlasToken&&\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9136:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node>\28\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9137:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Coverage_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9138:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28GrSimpleMesh&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9139:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29::'lambda'\28void*\29>\28GrResourceAllocator::Register&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9140:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPath\20const&\2c\20SkArenaAlloc*\20const&\29::'lambda'\28void*\29>\28GrInnerFanTriangulator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9141:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldLCDTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20GrDistanceFieldLCDTextGeoProc::DistanceAdjust\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9142:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29>\28GrBitmapTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9143:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrAppliedClip&&\29::'lambda'\28void*\29>\28GrAppliedClip&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9144:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28EllipseGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9145:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28DefaultGeoProc::Make\28SkArenaAlloc*\2c\20unsigned\20int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9146:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9147:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&\29 +9148:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9149:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9150:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9151:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +9152:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9153:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&\29 +9154:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9155:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9156:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9157:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +9158:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +9159:deallocate_buffer_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9160:ddquad_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9161:ddquad_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9162:ddline_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9163:ddline_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9164:ddcubic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9165:ddcubic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9166:ddconic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9167:ddconic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9168:data_destroy_use\28void*\29 +9169:data_create_use\28hb_ot_shape_plan_t\20const*\29 +9170:data_create_khmer\28hb_ot_shape_plan_t\20const*\29 +9171:data_create_indic\28hb_ot_shape_plan_t\20const*\29 +9172:data_create_hangul\28hb_ot_shape_plan_t\20const*\29 +9173:copy\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +9174:convert_bytes_to_data +9175:consume_markers +9176:consume_data +9177:computeTonalColors\28unsigned\20long\2c\20unsigned\20long\29 +9178:compose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9179:compose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9180:compose_hebrew\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9181:compare_ppem +9182:compare_myanmar_order\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +9183:compare_combining_class\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +9184:compareKeywordStructs\28void\20const*\2c\20void\20const*\2c\20void\20const*\29 +9185:compareEntries\28UElement\2c\20UElement\29 +9186:color_quantize3 +9187:color_quantize +9188:collect_features_use\28hb_ot_shape_planner_t*\29 +9189:collect_features_myanmar\28hb_ot_shape_planner_t*\29 +9190:collect_features_khmer\28hb_ot_shape_planner_t*\29 +9191:collect_features_indic\28hb_ot_shape_planner_t*\29 +9192:collect_features_hangul\28hb_ot_shape_planner_t*\29 +9193:collect_features_arabic\28hb_ot_shape_planner_t*\29 +9194:clip\28SkPath\20const&\2c\20SkHalfPlane\20const&\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +9195:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitStatement\28SkSL::Statement\20const&\29 +9196:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9197:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitExpression\28SkSL::Expression\20const&\29 +9198:charIterTextLength\28UText*\29 +9199:charIterTextExtract\28UText*\2c\20long\20long\2c\20long\20long\2c\20char16_t*\2c\20int\2c\20UErrorCode*\29 +9200:charIterTextClose\28UText*\29 +9201:charIterTextClone\28UText*\2c\20UText\20const*\2c\20signed\20char\2c\20UErrorCode*\29 +9202:changesWhenNFKC_Casefolded\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +9203:changesWhenCasefolded\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +9204:cff_slot_init +9205:cff_slot_done +9206:cff_size_request +9207:cff_size_init +9208:cff_size_done +9209:cff_sid_to_glyph_name +9210:cff_set_var_design +9211:cff_set_mm_weightvector +9212:cff_set_mm_blend +9213:cff_set_instance +9214:cff_random +9215:cff_ps_has_glyph_names +9216:cff_ps_get_font_info +9217:cff_ps_get_font_extra +9218:cff_parse_vsindex +9219:cff_parse_private_dict +9220:cff_parse_multiple_master +9221:cff_parse_maxstack +9222:cff_parse_font_matrix +9223:cff_parse_font_bbox +9224:cff_parse_cid_ros +9225:cff_parse_blend +9226:cff_metrics_adjust +9227:cff_hadvance_adjust +9228:cff_glyph_load +9229:cff_get_var_design +9230:cff_get_var_blend +9231:cff_get_standard_encoding +9232:cff_get_ros +9233:cff_get_ps_name +9234:cff_get_name_index +9235:cff_get_mm_weightvector +9236:cff_get_mm_var +9237:cff_get_mm_blend +9238:cff_get_is_cid +9239:cff_get_interface +9240:cff_get_glyph_name +9241:cff_get_glyph_data +9242:cff_get_cmap_info +9243:cff_get_cid_from_glyph_index +9244:cff_get_advances +9245:cff_free_glyph_data +9246:cff_fd_select_get +9247:cff_face_init +9248:cff_face_done +9249:cff_driver_init +9250:cff_done_blend +9251:cff_decoder_prepare +9252:cff_decoder_init +9253:cff_cmap_unicode_init +9254:cff_cmap_unicode_char_next +9255:cff_cmap_unicode_char_index +9256:cff_cmap_encoding_init +9257:cff_cmap_encoding_done +9258:cff_cmap_encoding_char_next +9259:cff_cmap_encoding_char_index +9260:cff_builder_start_point +9261:cff_builder_init +9262:cff_builder_add_point1 +9263:cff_builder_add_point +9264:cff_builder_add_contour +9265:cff_blend_check_vector +9266:cf2_free_instance +9267:cf2_decoder_parse_charstrings +9268:cf2_builder_moveTo +9269:cf2_builder_lineTo +9270:cf2_builder_cubeTo +9271:caseBinaryPropertyContains\28BinaryProperty\20const&\2c\20int\2c\20UProperty\29 +9272:bw_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +9273:bw_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9274:bw_pt_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9275:bw_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9276:bw_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9277:breakiterator_cleanup\28\29 +9278:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::SpotVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +9279:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::AmbientVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +9280:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9281:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9282:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9283:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9284:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9285:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9286:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9287:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9288:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9289:blur_y_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9290:blur_y_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9291:blur_y_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9292:blur_y_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9293:blur_x_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9294:blur_x_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9295:blur_x_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9296:blur_x_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9297:blit_row_s32a_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9298:blit_row_s32_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9299:blit_row_s32_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9300:biDiGetMaxValue\28IntProperty\20const&\2c\20UProperty\29 +9301:argb32_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +9302:arabic_fallback_shape\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9303:alwaysSaveTypefaceBytes\28SkTypeface*\2c\20void*\29 +9304:alloc_sarray +9305:alloc_barray +9306:afm_parser_parse +9307:afm_parser_init +9308:afm_parser_done +9309:afm_compare_kern_pairs +9310:af_property_set +9311:af_property_get +9312:af_latin_metrics_scale +9313:af_latin_metrics_init +9314:af_latin_hints_init +9315:af_latin_hints_apply +9316:af_latin_get_standard_widths +9317:af_indic_metrics_init +9318:af_indic_hints_apply +9319:af_get_interface +9320:af_face_globals_free +9321:af_dummy_hints_init +9322:af_dummy_hints_apply +9323:af_cjk_metrics_init +9324:af_autofitter_load_glyph +9325:af_autofitter_init +9326:access_virt_sarray +9327:access_virt_barray +9328:aa_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9329:aa_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9330:aa_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9331:_hb_ot_font_destroy\28void*\29 +9332:_hb_glyph_info_is_default_ignorable\28hb_glyph_info_t\20const*\29 +9333:_hb_face_for_data_reference_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +9334:_hb_face_for_data_closure_destroy\28void*\29 +9335:_hb_clear_substitution_flags\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9336:_emscripten_stack_restore +9337:__wasm_call_ctors +9338:__stdio_write +9339:__stdio_seek +9340:__stdio_read +9341:__stdio_close +9342:__getTypeName +9343:__cxxabiv1::__vmi_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +9344:__cxxabiv1::__vmi_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +9345:__cxxabiv1::__vmi_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +9346:__cxxabiv1::__si_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +9347:__cxxabiv1::__si_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +9348:__cxxabiv1::__si_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +9349:__cxxabiv1::__class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +9350:__cxxabiv1::__class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +9351:__cxxabiv1::__class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +9352:__cxxabiv1::__class_type_info::can_catch\28__cxxabiv1::__shim_type_info\20const*\2c\20void*&\29\20const +9353:__cxx_global_array_dtor_9983 +9354:__cxx_global_array_dtor_9594 +9355:__cxx_global_array_dtor_8579 +9356:__cxx_global_array_dtor_8190 +9357:__cxx_global_array_dtor_8007 +9358:__cxx_global_array_dtor_3975 +9359:__cxx_global_array_dtor_2241 +9360:__cxx_global_array_dtor_2113 +9361:__cxx_global_array_dtor_14872 +9362:__cxx_global_array_dtor_10689 +9363:__cxx_global_array_dtor.88 +9364:__cxx_global_array_dtor.73 +9365:__cxx_global_array_dtor.58 +9366:__cxx_global_array_dtor.45 +9367:__cxx_global_array_dtor.43 +9368:__cxx_global_array_dtor.41 +9369:__cxx_global_array_dtor.39 +9370:__cxx_global_array_dtor.37 +9371:__cxx_global_array_dtor.35 +9372:__cxx_global_array_dtor.34 +9373:__cxx_global_array_dtor.32 +9374:__cxx_global_array_dtor.1_14873 +9375:__cxx_global_array_dtor.139 +9376:__cxx_global_array_dtor.136 +9377:__cxx_global_array_dtor.112 +9378:__cxx_global_array_dtor.1 +9379:__cxx_global_array_dtor +9380:\28anonymous\20namespace\29::uprops_cleanup\28\29 +9381:\28anonymous\20namespace\29::ulayout_isAcceptable\28void*\2c\20char\20const*\2c\20char\20const*\2c\20UDataInfo\20const*\29 +9382:\28anonymous\20namespace\29::skhb_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +9383:\28anonymous\20namespace\29::skhb_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9384:\28anonymous\20namespace\29::skhb_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9385:\28anonymous\20namespace\29::skhb_glyph_h_advance\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9386:\28anonymous\20namespace\29::skhb_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9387:\28anonymous\20namespace\29::skhb_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9388:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29::$_0::__invoke\28void*\29 +9389:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +9390:\28anonymous\20namespace\29::make_morphology\28\28anonymous\20namespace\29::MorphType\2c\20SkSize\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +9391:\28anonymous\20namespace\29::make_drop_shadow_graph\28SkPoint\2c\20SkSize\2c\20SkRGBA4f<\28SkAlphaType\293>\2c\20sk_sp\2c\20bool\2c\20sk_sp\2c\20std::__2::optional\20const&\29 +9392:\28anonymous\20namespace\29::extension_compare\28SkString\20const&\2c\20SkString\20const&\29 +9393:\28anonymous\20namespace\29::characterproperties_cleanup\28\29 +9394:\28anonymous\20namespace\29::_set_add\28USet*\2c\20int\29 +9395:\28anonymous\20namespace\29::_set_addString\28USet*\2c\20char16_t\20const*\2c\20int\29 +9396:\28anonymous\20namespace\29::_set_addRange\28USet*\2c\20int\2c\20int\29 +9397:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29_4552 +9398:\28anonymous\20namespace\29::YUVPlanesRec::getCategory\28\29\20const +9399:\28anonymous\20namespace\29::YUVPlanesRec::diagnostic_only_getDiscardable\28\29\20const +9400:\28anonymous\20namespace\29::YUVPlanesRec::bytesUsed\28\29\20const +9401:\28anonymous\20namespace\29::YUVPlanesRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +9402:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29_11719 +9403:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29 +9404:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29_11703 +9405:\28anonymous\20namespace\29::TriangulatingPathOp::visitProxies\28std::__2::function\20const&\29\20const +9406:\28anonymous\20namespace\29::TriangulatingPathOp::programInfo\28\29 +9407:\28anonymous\20namespace\29::TriangulatingPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +9408:\28anonymous\20namespace\29::TriangulatingPathOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9409:\28anonymous\20namespace\29::TriangulatingPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9410:\28anonymous\20namespace\29::TriangulatingPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9411:\28anonymous\20namespace\29::TriangulatingPathOp::name\28\29\20const +9412:\28anonymous\20namespace\29::TriangulatingPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9413:\28anonymous\20namespace\29::TransformedMaskSubRun::unflattenSize\28\29\20const +9414:\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9415:\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +9416:\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9417:\28anonymous\20namespace\29::TransformedMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +9418:\28anonymous\20namespace\29::TransformedMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +9419:\28anonymous\20namespace\29::TransformedMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +9420:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29_11679 +9421:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29 +9422:\28anonymous\20namespace\29::TextureOpImpl::visitProxies\28std::__2::function\20const&\29\20const +9423:\28anonymous\20namespace\29::TextureOpImpl::programInfo\28\29 +9424:\28anonymous\20namespace\29::TextureOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +9425:\28anonymous\20namespace\29::TextureOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9426:\28anonymous\20namespace\29::TextureOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9427:\28anonymous\20namespace\29::TextureOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9428:\28anonymous\20namespace\29::TextureOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9429:\28anonymous\20namespace\29::TextureOpImpl::name\28\29\20const +9430:\28anonymous\20namespace\29::TextureOpImpl::fixedFunctionFlags\28\29\20const +9431:\28anonymous\20namespace\29::TextureOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9432:\28anonymous\20namespace\29::TentPass::startBlur\28\29 +9433:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +9434:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +9435:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +9436:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29_11724 +9437:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29 +9438:\28anonymous\20namespace\29::StaticVertexAllocator::unlock\28int\29 +9439:\28anonymous\20namespace\29::StaticVertexAllocator::lock\28unsigned\20long\2c\20int\29 +9440:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::currentScript\28\29\20const +9441:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::consume\28\29 +9442:\28anonymous\20namespace\29::SkUbrkGetLocaleByType::getLocaleByType\28UBreakIterator\20const*\2c\20ULocDataLocaleType\2c\20UErrorCode*\29 +9443:\28anonymous\20namespace\29::SkUbrkClone::clone\28UBreakIterator\20const*\2c\20UErrorCode*\29 +9444:\28anonymous\20namespace\29::SkShaderImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9445:\28anonymous\20namespace\29::SkShaderImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9446:\28anonymous\20namespace\29::SkShaderImageFilter::getTypeName\28\29\20const +9447:\28anonymous\20namespace\29::SkShaderImageFilter::flatten\28SkWriteBuffer&\29\20const +9448:\28anonymous\20namespace\29::SkShaderImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9449:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9450:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9451:\28anonymous\20namespace\29::SkMorphologyImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9452:\28anonymous\20namespace\29::SkMorphologyImageFilter::getTypeName\28\29\20const +9453:\28anonymous\20namespace\29::SkMorphologyImageFilter::flatten\28SkWriteBuffer&\29\20const +9454:\28anonymous\20namespace\29::SkMorphologyImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9455:\28anonymous\20namespace\29::SkMergeImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9456:\28anonymous\20namespace\29::SkMergeImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9457:\28anonymous\20namespace\29::SkMergeImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9458:\28anonymous\20namespace\29::SkMergeImageFilter::getTypeName\28\29\20const +9459:\28anonymous\20namespace\29::SkMergeImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9460:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9461:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9462:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9463:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::getTypeName\28\29\20const +9464:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::flatten\28SkWriteBuffer&\29\20const +9465:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9466:\28anonymous\20namespace\29::SkImageImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9467:\28anonymous\20namespace\29::SkImageImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9468:\28anonymous\20namespace\29::SkImageImageFilter::getTypeName\28\29\20const +9469:\28anonymous\20namespace\29::SkImageImageFilter::flatten\28SkWriteBuffer&\29\20const +9470:\28anonymous\20namespace\29::SkImageImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9471:\28anonymous\20namespace\29::SkFTGeometrySink::Quad\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +9472:\28anonymous\20namespace\29::SkFTGeometrySink::Move\28FT_Vector_\20const*\2c\20void*\29 +9473:\28anonymous\20namespace\29::SkFTGeometrySink::Line\28FT_Vector_\20const*\2c\20void*\29 +9474:\28anonymous\20namespace\29::SkFTGeometrySink::Cubic\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +9475:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +9476:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFamilyName\28SkString*\29\20const +9477:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +9478:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateFamilyNameIterator\28\29\20const +9479:\28anonymous\20namespace\29::SkEmptyTypeface::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +9480:\28anonymous\20namespace\29::SkEmptyTypeface::MakeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29 +9481:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9482:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9483:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9484:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::getTypeName\28\29\20const +9485:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::flatten\28SkWriteBuffer&\29\20const +9486:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9487:\28anonymous\20namespace\29::SkCropImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9488:\28anonymous\20namespace\29::SkCropImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9489:\28anonymous\20namespace\29::SkCropImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9490:\28anonymous\20namespace\29::SkCropImageFilter::onAffectsTransparentBlack\28\29\20const +9491:\28anonymous\20namespace\29::SkCropImageFilter::getTypeName\28\29\20const +9492:\28anonymous\20namespace\29::SkCropImageFilter::flatten\28SkWriteBuffer&\29\20const +9493:\28anonymous\20namespace\29::SkCropImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9494:\28anonymous\20namespace\29::SkComposeImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9495:\28anonymous\20namespace\29::SkComposeImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9496:\28anonymous\20namespace\29::SkComposeImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9497:\28anonymous\20namespace\29::SkComposeImageFilter::getTypeName\28\29\20const +9498:\28anonymous\20namespace\29::SkComposeImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9499:\28anonymous\20namespace\29::SkColorFilterImageFilter::onIsColorFilterNode\28SkColorFilter**\29\20const +9500:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9501:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9502:\28anonymous\20namespace\29::SkColorFilterImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9503:\28anonymous\20namespace\29::SkColorFilterImageFilter::onAffectsTransparentBlack\28\29\20const +9504:\28anonymous\20namespace\29::SkColorFilterImageFilter::getTypeName\28\29\20const +9505:\28anonymous\20namespace\29::SkColorFilterImageFilter::flatten\28SkWriteBuffer&\29\20const +9506:\28anonymous\20namespace\29::SkColorFilterImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9507:\28anonymous\20namespace\29::SkBlurImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9508:\28anonymous\20namespace\29::SkBlurImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9509:\28anonymous\20namespace\29::SkBlurImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9510:\28anonymous\20namespace\29::SkBlurImageFilter::getTypeName\28\29\20const +9511:\28anonymous\20namespace\29::SkBlurImageFilter::flatten\28SkWriteBuffer&\29\20const +9512:\28anonymous\20namespace\29::SkBlurImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9513:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29_5785 +9514:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29 +9515:\28anonymous\20namespace\29::SkBlendImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +9516:\28anonymous\20namespace\29::SkBlendImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +9517:\28anonymous\20namespace\29::SkBlendImageFilter::onFilterImage\28skif::Context\20const&\29\20const +9518:\28anonymous\20namespace\29::SkBlendImageFilter::onAffectsTransparentBlack\28\29\20const +9519:\28anonymous\20namespace\29::SkBlendImageFilter::getTypeName\28\29\20const +9520:\28anonymous\20namespace\29::SkBlendImageFilter::flatten\28SkWriteBuffer&\29\20const +9521:\28anonymous\20namespace\29::SkBlendImageFilter::computeFastBounds\28SkRect\20const&\29\20const +9522:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29_8003 +9523:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29 +9524:\28anonymous\20namespace\29::SkBidiIterator_icu::getLevelAt\28int\29 +9525:\28anonymous\20namespace\29::SkBidiIterator_icu::getLength\28\29 +9526:\28anonymous\20namespace\29::SimpleTriangleShader::name\28\29\20const +9527:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +9528:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +9529:\28anonymous\20namespace\29::ShaperHarfBuzz::~ShaperHarfBuzz\28\29_14902 +9530:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20float\2c\20SkShaper::RunHandler*\29\20const +9531:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +9532:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20bool\2c\20float\2c\20SkShaper::RunHandler*\29\20const +9533:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::~ShapeDontWrapOrReorder\28\29 +9534:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::wrap\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::BiDiRunIterator\20const&\2c\20SkShaper::LanguageRunIterator\20const&\2c\20SkShaper::ScriptRunIterator\20const&\2c\20SkShaper::FontRunIterator\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +9535:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29_5571 +9536:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29 +9537:\28anonymous\20namespace\29::ShadowInvalidator::changed\28\29 +9538:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29_11542 +9539:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29 +9540:\28anonymous\20namespace\29::ShadowCircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +9541:\28anonymous\20namespace\29::ShadowCircularRRectOp::programInfo\28\29 +9542:\28anonymous\20namespace\29::ShadowCircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +9543:\28anonymous\20namespace\29::ShadowCircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9544:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9545:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9546:\28anonymous\20namespace\29::ShadowCircularRRectOp::name\28\29\20const +9547:\28anonymous\20namespace\29::ShadowCircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9548:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12572 +9549:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +9550:\28anonymous\20namespace\29::SDFTSubRun::vertexStride\28SkMatrix\20const&\29\20const +9551:\28anonymous\20namespace\29::SDFTSubRun::vertexFiller\28\29\20const +9552:\28anonymous\20namespace\29::SDFTSubRun::unflattenSize\28\29\20const +9553:\28anonymous\20namespace\29::SDFTSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +9554:\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9555:\28anonymous\20namespace\29::SDFTSubRun::glyphs\28\29\20const +9556:\28anonymous\20namespace\29::SDFTSubRun::glyphCount\28\29\20const +9557:\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9558:\28anonymous\20namespace\29::SDFTSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +9559:\28anonymous\20namespace\29::SDFTSubRun::doFlatten\28SkWriteBuffer&\29\20const +9560:\28anonymous\20namespace\29::SDFTSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +9561:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29_2425 +9562:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29 +9563:\28anonymous\20namespace\29::RectsBlurRec::getCategory\28\29\20const +9564:\28anonymous\20namespace\29::RectsBlurRec::diagnostic_only_getDiscardable\28\29\20const +9565:\28anonymous\20namespace\29::RectsBlurRec::bytesUsed\28\29\20const +9566:\28anonymous\20namespace\29::RectsBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +9567:\28anonymous\20namespace\29::RasterShaderBlurAlgorithm::makeDevice\28SkImageInfo\20const&\29\20const +9568:\28anonymous\20namespace\29::RasterBlurEngine::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +9569:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::maxSigma\28\29\20const +9570:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +9571:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29_2419 +9572:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29 +9573:\28anonymous\20namespace\29::RRectBlurRec::getCategory\28\29\20const +9574:\28anonymous\20namespace\29::RRectBlurRec::diagnostic_only_getDiscardable\28\29\20const +9575:\28anonymous\20namespace\29::RRectBlurRec::bytesUsed\28\29\20const +9576:\28anonymous\20namespace\29::RRectBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +9577:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29_12636 +9578:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29 +9579:\28anonymous\20namespace\29::PathSubRun::unflattenSize\28\29\20const +9580:\28anonymous\20namespace\29::PathSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +9581:\28anonymous\20namespace\29::PathSubRun::doFlatten\28SkWriteBuffer&\29\20const +9582:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29_1325 +9583:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29 +9584:\28anonymous\20namespace\29::MipMapRec::getCategory\28\29\20const +9585:\28anonymous\20namespace\29::MipMapRec::diagnostic_only_getDiscardable\28\29\20const +9586:\28anonymous\20namespace\29::MipMapRec::bytesUsed\28\29\20const +9587:\28anonymous\20namespace\29::MipMapRec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +9588:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29_11765 +9589:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29 +9590:\28anonymous\20namespace\29::MiddleOutShader::name\28\29\20const +9591:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +9592:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +9593:\28anonymous\20namespace\29::MiddleOutShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +9594:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29_11068 +9595:\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const +9596:\28anonymous\20namespace\29::MeshOp::programInfo\28\29 +9597:\28anonymous\20namespace\29::MeshOp::onPrepareDraws\28GrMeshDrawTarget*\29 +9598:\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9599:\28anonymous\20namespace\29::MeshOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9600:\28anonymous\20namespace\29::MeshOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9601:\28anonymous\20namespace\29::MeshOp::name\28\29\20const +9602:\28anonymous\20namespace\29::MeshOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9603:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29_11095 +9604:\28anonymous\20namespace\29::MeshGP::onTextureSampler\28int\29\20const +9605:\28anonymous\20namespace\29::MeshGP::name\28\29\20const +9606:\28anonymous\20namespace\29::MeshGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +9607:\28anonymous\20namespace\29::MeshGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +9608:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29_11108 +9609:\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +9610:\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +9611:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +9612:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +9613:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +9614:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +9615:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMangledName\28char\20const*\29 +9616:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMainName\28\29 +9617:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +9618:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +9619:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +9620:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareFunction\28char\20const*\29 +9621:\28anonymous\20namespace\29::ImageFromPictureRec::~ImageFromPictureRec\28\29_4828 +9622:\28anonymous\20namespace\29::ImageFromPictureRec::~ImageFromPictureRec\28\29 +9623:\28anonymous\20namespace\29::ImageFromPictureRec::getCategory\28\29\20const +9624:\28anonymous\20namespace\29::ImageFromPictureRec::bytesUsed\28\29\20const +9625:\28anonymous\20namespace\29::ImageFromPictureRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +9626:\28anonymous\20namespace\29::HQDownSampler::buildLevel\28SkPixmap\20const&\2c\20SkPixmap\20const&\29 +9627:\28anonymous\20namespace\29::GaussPass::startBlur\28\29 +9628:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +9629:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +9630:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +9631:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29_11185 +9632:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29 +9633:\28anonymous\20namespace\29::FillRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +9634:\28anonymous\20namespace\29::FillRectOpImpl::programInfo\28\29 +9635:\28anonymous\20namespace\29::FillRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +9636:\28anonymous\20namespace\29::FillRectOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9637:\28anonymous\20namespace\29::FillRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9638:\28anonymous\20namespace\29::FillRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9639:\28anonymous\20namespace\29::FillRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9640:\28anonymous\20namespace\29::FillRectOpImpl::name\28\29\20const +9641:\28anonymous\20namespace\29::FillRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9642:\28anonymous\20namespace\29::EllipticalRRectEffect::onMakeProgramImpl\28\29\20const +9643:\28anonymous\20namespace\29::EllipticalRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +9644:\28anonymous\20namespace\29::EllipticalRRectEffect::name\28\29\20const +9645:\28anonymous\20namespace\29::EllipticalRRectEffect::clone\28\29\20const +9646:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +9647:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +9648:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29_12644 +9649:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29 +9650:\28anonymous\20namespace\29::DrawableSubRun::unflattenSize\28\29\20const +9651:\28anonymous\20namespace\29::DrawableSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +9652:\28anonymous\20namespace\29::DrawableSubRun::doFlatten\28SkWriteBuffer&\29\20const +9653:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29_11053 +9654:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29 +9655:\28anonymous\20namespace\29::DrawAtlasPathShader::onTextureSampler\28int\29\20const +9656:\28anonymous\20namespace\29::DrawAtlasPathShader::name\28\29\20const +9657:\28anonymous\20namespace\29::DrawAtlasPathShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +9658:\28anonymous\20namespace\29::DrawAtlasPathShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +9659:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +9660:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +9661:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29_11025 +9662:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29 +9663:\28anonymous\20namespace\29::DrawAtlasOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +9664:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9665:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9666:\28anonymous\20namespace\29::DrawAtlasOpImpl::name\28\29\20const +9667:\28anonymous\20namespace\29::DrawAtlasOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9668:\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +9669:\28anonymous\20namespace\29::DirectMaskSubRun::unflattenSize\28\29\20const +9670:\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9671:\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +9672:\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9673:\28anonymous\20namespace\29::DirectMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +9674:\28anonymous\20namespace\29::DirectMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +9675:\28anonymous\20namespace\29::DirectMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +9676:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29_11010 +9677:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29 +9678:\28anonymous\20namespace\29::DefaultPathOp::visitProxies\28std::__2::function\20const&\29\20const +9679:\28anonymous\20namespace\29::DefaultPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +9680:\28anonymous\20namespace\29::DefaultPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9681:\28anonymous\20namespace\29::DefaultPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9682:\28anonymous\20namespace\29::DefaultPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9683:\28anonymous\20namespace\29::DefaultPathOp::name\28\29\20const +9684:\28anonymous\20namespace\29::DefaultPathOp::fixedFunctionFlags\28\29\20const +9685:\28anonymous\20namespace\29::DefaultPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9686:\28anonymous\20namespace\29::CircularRRectEffect::onMakeProgramImpl\28\29\20const +9687:\28anonymous\20namespace\29::CircularRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +9688:\28anonymous\20namespace\29::CircularRRectEffect::name\28\29\20const +9689:\28anonymous\20namespace\29::CircularRRectEffect::clone\28\29\20const +9690:\28anonymous\20namespace\29::CircularRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +9691:\28anonymous\20namespace\29::CircularRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +9692:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29_5565 +9693:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29 +9694:\28anonymous\20namespace\29::CachedTessellationsRec::getCategory\28\29\20const +9695:\28anonymous\20namespace\29::CachedTessellationsRec::bytesUsed\28\29\20const +9696:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29_5563 +9697:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29_2243 +9698:\28anonymous\20namespace\29::CacheImpl::set\28SkImageFilterCacheKey\20const&\2c\20SkImageFilter\20const*\2c\20skif::FilterResult\20const&\29 +9699:\28anonymous\20namespace\29::CacheImpl::purge\28\29 +9700:\28anonymous\20namespace\29::CacheImpl::purgeByImageFilter\28SkImageFilter\20const*\29 +9701:\28anonymous\20namespace\29::CacheImpl::get\28SkImageFilterCacheKey\20const&\2c\20skif::FilterResult*\29\20const +9702:\28anonymous\20namespace\29::BoundingBoxShader::name\28\29\20const +9703:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +9704:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +9705:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +9706:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29_10832 +9707:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29 +9708:\28anonymous\20namespace\29::AAHairlineOp::visitProxies\28std::__2::function\20const&\29\20const +9709:\28anonymous\20namespace\29::AAHairlineOp::onPrepareDraws\28GrMeshDrawTarget*\29 +9710:\28anonymous\20namespace\29::AAHairlineOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9711:\28anonymous\20namespace\29::AAHairlineOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +9712:\28anonymous\20namespace\29::AAHairlineOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +9713:\28anonymous\20namespace\29::AAHairlineOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +9714:\28anonymous\20namespace\29::AAHairlineOp::name\28\29\20const +9715:\28anonymous\20namespace\29::AAHairlineOp::fixedFunctionFlags\28\29\20const +9716:\28anonymous\20namespace\29::AAHairlineOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +9717:YuvToRgbaRow +9718:YuvToRgba4444Row +9719:YuvToRgbRow +9720:YuvToRgb565Row +9721:YuvToBgraRow +9722:YuvToBgrRow +9723:YuvToArgbRow +9724:Write_CVT_Stretched +9725:Write_CVT +9726:WebPYuv444ToRgba_C +9727:WebPYuv444ToRgba4444_C +9728:WebPYuv444ToRgb_C +9729:WebPYuv444ToRgb565_C +9730:WebPYuv444ToBgra_C +9731:WebPYuv444ToBgr_C +9732:WebPYuv444ToArgb_C +9733:WebPRescalerImportRowShrink_C +9734:WebPRescalerImportRowExpand_C +9735:WebPRescalerExportRowShrink_C +9736:WebPRescalerExportRowExpand_C +9737:WebPMultRow_C +9738:WebPMultARGBRow_C +9739:WebPConvertRGBA32ToUV_C +9740:WebPConvertARGBToUV_C +9741:WebGLTextureImageGenerator::~WebGLTextureImageGenerator\28\29_890 +9742:WebGLTextureImageGenerator::generateExternalTexture\28GrRecordingContext*\2c\20skgpu::Mipmapped\29 +9743:Vertish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +9744:Vertish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +9745:VerticalUnfilter_C +9746:VerticalFilter_C +9747:VertState::Triangles\28VertState*\29 +9748:VertState::TrianglesX\28VertState*\29 +9749:VertState::TriangleStrip\28VertState*\29 +9750:VertState::TriangleStripX\28VertState*\29 +9751:VertState::TriangleFan\28VertState*\29 +9752:VertState::TriangleFanX\28VertState*\29 +9753:VR4_C +9754:VP8LTransformColorInverse_C +9755:VP8LPredictor9_C +9756:VP8LPredictor8_C +9757:VP8LPredictor7_C +9758:VP8LPredictor6_C +9759:VP8LPredictor5_C +9760:VP8LPredictor4_C +9761:VP8LPredictor3_C +9762:VP8LPredictor2_C +9763:VP8LPredictor1_C +9764:VP8LPredictor13_C +9765:VP8LPredictor12_C +9766:VP8LPredictor11_C +9767:VP8LPredictor10_C +9768:VP8LPredictor0_C +9769:VP8LConvertBGRAToRGB_C +9770:VP8LConvertBGRAToRGBA_C +9771:VP8LConvertBGRAToRGBA4444_C +9772:VP8LConvertBGRAToRGB565_C +9773:VP8LConvertBGRAToBGR_C +9774:VP8LAddGreenToBlueAndRed_C +9775:VLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +9776:VLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +9777:VL4_C +9778:VFilter8i_C +9779:VFilter8_C +9780:VFilter16i_C +9781:VFilter16_C +9782:VE8uv_C +9783:VE4_C +9784:VE16_C +9785:UpsampleRgbaLinePair_C +9786:UpsampleRgba4444LinePair_C +9787:UpsampleRgbLinePair_C +9788:UpsampleRgb565LinePair_C +9789:UpsampleBgraLinePair_C +9790:UpsampleBgrLinePair_C +9791:UpsampleArgbLinePair_C +9792:UnresolvedCodepoints\28skia::textlayout::Paragraph&\29 +9793:UnicodeString_charAt\28int\2c\20void*\29 +9794:TransformWHAT_C +9795:TransformUV_C +9796:TransformTwo_C +9797:TransformDC_C +9798:TransformDCUV_C +9799:TransformAC3_C +9800:ToSVGString\28SkPath\20const&\29 +9801:ToCmds\28SkPath\20const&\29 +9802:TT_Set_MM_Blend +9803:TT_RunIns +9804:TT_Load_Simple_Glyph +9805:TT_Load_Glyph_Header +9806:TT_Load_Composite_Glyph +9807:TT_Get_Var_Design +9808:TT_Get_MM_Blend +9809:TT_Forget_Glyph_Frame +9810:TT_Access_Glyph_Frame +9811:TM8uv_C +9812:TM4_C +9813:TM16_C +9814:Sync +9815:SquareCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +9816:Sprite_D32_S32::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +9817:SkWuffsFrameHolder::onGetFrame\28int\29\20const +9818:SkWuffsCodec::~SkWuffsCodec\28\29_13344 +9819:SkWuffsCodec::~SkWuffsCodec\28\29 +9820:SkWuffsCodec::onIncrementalDecode\28int*\29 +9821:SkWuffsCodec::onGetRepetitionCount\28\29 +9822:SkWuffsCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9823:SkWuffsCodec::onGetFrameInfo\28int\2c\20SkCodec::FrameInfo*\29\20const +9824:SkWuffsCodec::onGetFrameCount\28\29 +9825:SkWuffsCodec::getFrameHolder\28\29\20const +9826:SkWuffsCodec::getEncodedData\28\29\20const +9827:SkWriteICCProfile\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +9828:SkWebpDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +9829:SkWebpCodec::~SkWebpCodec\28\29_13024 +9830:SkWebpCodec::~SkWebpCodec\28\29 +9831:SkWebpCodec::onGetValidSubset\28SkIRect*\29\20const +9832:SkWebpCodec::onGetRepetitionCount\28\29 +9833:SkWebpCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9834:SkWebpCodec::onGetFrameInfo\28int\2c\20SkCodec::FrameInfo*\29\20const +9835:SkWebpCodec::onGetFrameCount\28\29 +9836:SkWebpCodec::getFrameHolder\28\29\20const +9837:SkWebpCodec::FrameHolder::~FrameHolder\28\29_13022 +9838:SkWebpCodec::FrameHolder::~FrameHolder\28\29 +9839:SkWebpCodec::FrameHolder::onGetFrame\28int\29\20const +9840:SkWeakRefCnt::internal_dispose\28\29\20const +9841:SkWbmpDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +9842:SkWbmpCodec::~SkWbmpCodec\28\29_6156 +9843:SkWbmpCodec::~SkWbmpCodec\28\29 +9844:SkWbmpCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +9845:SkWbmpCodec::onSkipScanlines\28int\29 +9846:SkWbmpCodec::onRewind\28\29 +9847:SkWbmpCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +9848:SkWbmpCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9849:SkWbmpCodec::getSampler\28bool\29 +9850:SkWbmpCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +9851:SkVertices::Builder*\20emscripten::internal::operator_new\28SkVertices::VertexMode&&\2c\20int&&\2c\20int&&\2c\20unsigned\20int&&\29 +9852:SkUserTypeface::~SkUserTypeface\28\29_5452 +9853:SkUserTypeface::~SkUserTypeface\28\29 +9854:SkUserTypeface::onOpenStream\28int*\29\20const +9855:SkUserTypeface::onGetUPEM\28\29\20const +9856:SkUserTypeface::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +9857:SkUserTypeface::onGetFamilyName\28SkString*\29\20const +9858:SkUserTypeface::onFilterRec\28SkScalerContextRec*\29\20const +9859:SkUserTypeface::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +9860:SkUserTypeface::onCountGlyphs\28\29\20const +9861:SkUserTypeface::onComputeBounds\28SkRect*\29\20const +9862:SkUserTypeface::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +9863:SkUserTypeface::getGlyphToUnicodeMap\28int*\29\20const +9864:SkUserScalerContext::~SkUserScalerContext\28\29 +9865:SkUserScalerContext::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +9866:SkUserScalerContext::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +9867:SkUserScalerContext::generateImage\28SkGlyph\20const&\2c\20void*\29 +9868:SkUserScalerContext::generateFontMetrics\28SkFontMetrics*\29 +9869:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::~DrawableMatrixWrapper\28\29_5472 +9870:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::~DrawableMatrixWrapper\28\29 +9871:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::onGetBounds\28\29 +9872:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::onDraw\28SkCanvas*\29 +9873:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::onApproximateBytesUsed\28\29 +9874:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29 +9875:SkUnicode_icu::~SkUnicode_icu\28\29_8010 +9876:SkUnicode_icu::~SkUnicode_icu\28\29 +9877:SkUnicode_icu::toUpper\28SkString\20const&\2c\20char\20const*\29 +9878:SkUnicode_icu::toUpper\28SkString\20const&\29 +9879:SkUnicode_icu::reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29 +9880:SkUnicode_icu::makeBreakIterator\28char\20const*\2c\20SkUnicode::BreakType\29 +9881:SkUnicode_icu::makeBreakIterator\28SkUnicode::BreakType\29 +9882:SkUnicode_icu::makeBidiIterator\28unsigned\20short\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +9883:SkUnicode_icu::makeBidiIterator\28char\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +9884:SkUnicode_icu::isWhitespace\28int\29 +9885:SkUnicode_icu::isTabulation\28int\29 +9886:SkUnicode_icu::isSpace\28int\29 +9887:SkUnicode_icu::isRegionalIndicator\28int\29 +9888:SkUnicode_icu::isIdeographic\28int\29 +9889:SkUnicode_icu::isHardBreak\28int\29 +9890:SkUnicode_icu::isEmoji\28int\29 +9891:SkUnicode_icu::isEmojiModifier\28int\29 +9892:SkUnicode_icu::isEmojiModifierBase\28int\29 +9893:SkUnicode_icu::isEmojiComponent\28int\29 +9894:SkUnicode_icu::isControl\28int\29 +9895:SkUnicode_icu::getWords\28char\20const*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +9896:SkUnicode_icu::getUtf8Words\28char\20const*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +9897:SkUnicode_icu::getSentences\28char\20const*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +9898:SkUnicode_icu::getBidiRegions\28char\20const*\2c\20int\2c\20SkUnicode::TextDirection\2c\20std::__2::vector>*\29 +9899:SkUnicode_icu::computeCodeUnitFlags\28char16_t*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +9900:SkUnicode_icu::computeCodeUnitFlags\28char*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +9901:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29_14866 +9902:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29 +9903:SkUnicodeBidiRunIterator::endOfCurrentRun\28\29\20const +9904:SkUnicodeBidiRunIterator::currentLevel\28\29\20const +9905:SkUnicodeBidiRunIterator::consume\28\29 +9906:SkUnicodeBidiRunIterator::atEnd\28\29\20const +9907:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29_8181 +9908:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29 +9909:SkTypeface_FreeTypeStream::onOpenStream\28int*\29\20const +9910:SkTypeface_FreeTypeStream::onMakeFontData\28\29\20const +9911:SkTypeface_FreeTypeStream::onMakeClone\28SkFontArguments\20const&\29\20const +9912:SkTypeface_FreeTypeStream::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +9913:SkTypeface_FreeType::onGlyphMaskNeedsCurrentColor\28\29\20const +9914:SkTypeface_FreeType::onGetVariationDesignPosition\28SkFontArguments::VariationPosition::Coordinate*\2c\20int\29\20const +9915:SkTypeface_FreeType::onGetVariationDesignParameters\28SkFontParameters::Variation::Axis*\2c\20int\29\20const +9916:SkTypeface_FreeType::onGetUPEM\28\29\20const +9917:SkTypeface_FreeType::onGetTableTags\28unsigned\20int*\29\20const +9918:SkTypeface_FreeType::onGetTableData\28unsigned\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20void*\29\20const +9919:SkTypeface_FreeType::onGetPostScriptName\28SkString*\29\20const +9920:SkTypeface_FreeType::onGetKerningPairAdjustments\28unsigned\20short\20const*\2c\20int\2c\20int*\29\20const +9921:SkTypeface_FreeType::onGetAdvancedMetrics\28\29\20const +9922:SkTypeface_FreeType::onFilterRec\28SkScalerContextRec*\29\20const +9923:SkTypeface_FreeType::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +9924:SkTypeface_FreeType::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +9925:SkTypeface_FreeType::onCreateFamilyNameIterator\28\29\20const +9926:SkTypeface_FreeType::onCountGlyphs\28\29\20const +9927:SkTypeface_FreeType::onCopyTableData\28unsigned\20int\29\20const +9928:SkTypeface_FreeType::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +9929:SkTypeface_FreeType::getPostScriptGlyphNames\28SkString*\29\20const +9930:SkTypeface_FreeType::getGlyphToUnicodeMap\28int*\29\20const +9931:SkTypeface_Empty::~SkTypeface_Empty\28\29 +9932:SkTypeface_Custom::~SkTypeface_Custom\28\29_8124 +9933:SkTypeface_Custom::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +9934:SkTypeface::onOpenExistingStream\28int*\29\20const +9935:SkTypeface::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +9936:SkTypeface::onCopyTableData\28unsigned\20int\29\20const +9937:SkTypeface::onComputeBounds\28SkRect*\29\20const +9938:SkTrimPE::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9939:SkTrimPE::getTypeName\28\29\20const +9940:SkTriColorShader::type\28\29\20const +9941:SkTriColorShader::isOpaque\28\29\20const +9942:SkTriColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9943:SkTransformShader::type\28\29\20const +9944:SkTransformShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9945:SkTQuad::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +9946:SkTQuad::setBounds\28SkDRect*\29\20const +9947:SkTQuad::ptAtT\28double\29\20const +9948:SkTQuad::make\28SkArenaAlloc&\29\20const +9949:SkTQuad::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +9950:SkTQuad::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +9951:SkTQuad::dxdyAtT\28double\29\20const +9952:SkTQuad::debugInit\28\29 +9953:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29_4000 +9954:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29 +9955:SkTCubic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +9956:SkTCubic::setBounds\28SkDRect*\29\20const +9957:SkTCubic::ptAtT\28double\29\20const +9958:SkTCubic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +9959:SkTCubic::make\28SkArenaAlloc&\29\20const +9960:SkTCubic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +9961:SkTCubic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +9962:SkTCubic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +9963:SkTCubic::dxdyAtT\28double\29\20const +9964:SkTCubic::debugInit\28\29 +9965:SkTCubic::controlsInside\28\29\20const +9966:SkTCubic::collapsed\28\29\20const +9967:SkTConic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +9968:SkTConic::setBounds\28SkDRect*\29\20const +9969:SkTConic::ptAtT\28double\29\20const +9970:SkTConic::make\28SkArenaAlloc&\29\20const +9971:SkTConic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +9972:SkTConic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +9973:SkTConic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +9974:SkTConic::dxdyAtT\28double\29\20const +9975:SkTConic::debugInit\28\29 +9976:SkSwizzler::onSetSampleX\28int\29 +9977:SkSwizzler::fillWidth\28\29\20const +9978:SkSweepGradient::getTypeName\28\29\20const +9979:SkSweepGradient::flatten\28SkWriteBuffer&\29\20const +9980:SkSweepGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +9981:SkSweepGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +9982:SkSurface_Raster::~SkSurface_Raster\28\29_4713 +9983:SkSurface_Raster::~SkSurface_Raster\28\29 +9984:SkSurface_Raster::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +9985:SkSurface_Raster::onRestoreBackingMutability\28\29 +9986:SkSurface_Raster::onNewSurface\28SkImageInfo\20const&\29 +9987:SkSurface_Raster::onNewImageSnapshot\28SkIRect\20const*\29 +9988:SkSurface_Raster::onNewCanvas\28\29 +9989:SkSurface_Raster::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +9990:SkSurface_Raster::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +9991:SkSurface_Raster::imageInfo\28\29\20const +9992:SkSurface_Ganesh::~SkSurface_Ganesh\28\29_11726 +9993:SkSurface_Ganesh::~SkSurface_Ganesh\28\29 +9994:SkSurface_Ganesh::replaceBackendTexture\28GrBackendTexture\20const&\2c\20GrSurfaceOrigin\2c\20SkSurface::ContentChangeMode\2c\20void\20\28*\29\28void*\29\2c\20void*\29 +9995:SkSurface_Ganesh::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +9996:SkSurface_Ganesh::onWait\28int\2c\20GrBackendSemaphore\20const*\2c\20bool\29 +9997:SkSurface_Ganesh::onNewSurface\28SkImageInfo\20const&\29 +9998:SkSurface_Ganesh::onNewImageSnapshot\28SkIRect\20const*\29 +9999:SkSurface_Ganesh::onNewCanvas\28\29 +10000:SkSurface_Ganesh::onIsCompatible\28GrSurfaceCharacterization\20const&\29\20const +10001:SkSurface_Ganesh::onGetRecordingContext\28\29\20const +10002:SkSurface_Ganesh::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10003:SkSurface_Ganesh::onDiscard\28\29 +10004:SkSurface_Ganesh::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +10005:SkSurface_Ganesh::onCharacterize\28GrSurfaceCharacterization*\29\20const +10006:SkSurface_Ganesh::onCapabilities\28\29 +10007:SkSurface_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10008:SkSurface_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10009:SkSurface_Ganesh::imageInfo\28\29\20const +10010:SkSurface_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10011:SkSurface::imageInfo\28\29\20const +10012:SkSurface::height\28\29\20const +10013:SkString*\20std::__2::vector>::__emplace_back_slow_path\28char\20const*&\2c\20int&&\29 +10014:SkStrikeCache::~SkStrikeCache\28\29_4244 +10015:SkStrikeCache::~SkStrikeCache\28\29 +10016:SkStrikeCache::findOrCreateScopedStrike\28SkStrikeSpec\20const&\29 +10017:SkStrike::~SkStrike\28\29_4231 +10018:SkStrike::strikePromise\28\29 +10019:SkStrike::roundingSpec\28\29\20const +10020:SkStrike::prepareForPath\28SkGlyph*\29 +10021:SkStrike::prepareForImage\28SkGlyph*\29 +10022:SkStrike::prepareForDrawable\28SkGlyph*\29 +10023:SkStrike::getDescriptor\28\29\20const +10024:SkSpriteBlitter_Memcpy::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10025:SkSpriteBlitter::~SkSpriteBlitter\28\29_1501 +10026:SkSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +10027:SkSpriteBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10028:SkSpriteBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10029:SkSpriteBlitter::blitH\28int\2c\20int\2c\20int\29 +10030:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29_4123 +10031:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29 +10032:SkSpecialImage_Raster::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +10033:SkSpecialImage_Raster::getSize\28\29\20const +10034:SkSpecialImage_Raster::backingStoreDimensions\28\29\20const +10035:SkSpecialImage_Raster::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +10036:SkSpecialImage_Raster::asImage\28\29\20const +10037:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29_10775 +10038:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29 +10039:SkSpecialImage_Gpu::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +10040:SkSpecialImage_Gpu::getSize\28\29\20const +10041:SkSpecialImage_Gpu::backingStoreDimensions\28\29\20const +10042:SkSpecialImage_Gpu::asImage\28\29\20const +10043:SkSpecialImage::~SkSpecialImage\28\29 +10044:SkSpecialImage::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +10045:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29_14859 +10046:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29 +10047:SkShaper::TrivialLanguageRunIterator::currentLanguage\28\29\20const +10048:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29_7567 +10049:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29 +10050:SkShaper::TrivialBiDiRunIterator::currentLevel\28\29\20const +10051:SkShaderBlurAlgorithm::maxSigma\28\29\20const +10052:SkShaderBlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +10053:SkScan::HairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10054:SkScan::HairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10055:SkScan::HairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10056:SkScan::AntiHairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10057:SkScan::AntiHairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10058:SkScan::AntiHairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10059:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10060:SkScalingCodec::onGetScaledDimensions\28float\29\20const +10061:SkScalingCodec::onDimensionsSupported\28SkISize\20const&\29 +10062:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29_8156 +10063:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29 +10064:SkScalerContext_FreeType::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +10065:SkScalerContext_FreeType::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +10066:SkScalerContext_FreeType::generateImage\28SkGlyph\20const&\2c\20void*\29 +10067:SkScalerContext_FreeType::generateFontMetrics\28SkFontMetrics*\29 +10068:SkScalerContext_FreeType::generateDrawable\28SkGlyph\20const&\29 +10069:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::~SkScalerContext_Empty\28\29 +10070:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +10071:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +10072:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateFontMetrics\28SkFontMetrics*\29 +10073:SkSampledCodec::onGetSampledDimensions\28int\29\20const +10074:SkSampledCodec::onGetAndroidPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const&\29 +10075:SkSRGBColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +10076:SkSRGBColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +10077:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_3::__invoke\28double\2c\20double\29 +10078:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_2::__invoke\28double\2c\20double\29 +10079:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_1::__invoke\28double\2c\20double\29 +10080:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_0::__invoke\28double\2c\20double\29 +10081:SkSL::remove_break_statements\28std::__2::unique_ptr>&\29::RemoveBreaksWriter::visitStatementPtr\28std::__2::unique_ptr>&\29 +10082:SkSL::hoist_vardecl_symbols_into_outer_scope\28SkSL::Context\20const&\2c\20SkSL::Block\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::SymbolTable*\29::SymbolHoister::visitStatement\28SkSL::Statement\20const&\29 +10083:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29_7363 +10084:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29 +10085:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29_7356 +10086:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29 +10087:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +10088:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitExpressionPtr\28std::__2::unique_ptr>&\29 +10089:SkSL::count_returns_at_end_of_control_flow\28SkSL::FunctionDefinition\20const&\29::CountReturnsAtEndOfControlFlow::visitStatement\28SkSL::Statement\20const&\29 +10090:SkSL::\28anonymous\20namespace\29::VariableWriteVisitor::visitExpression\28SkSL::Expression\20const&\29 +10091:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10092:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitExpression\28SkSL::Expression\20const&\29 +10093:SkSL::\28anonymous\20namespace\29::ReturnsNonOpaqueColorVisitor::visitStatement\28SkSL::Statement\20const&\29 +10094:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitStatement\28SkSL::Statement\20const&\29 +10095:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10096:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitStatement\28SkSL::Statement\20const&\29 +10097:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitStatement\28SkSL::Statement\20const&\29 +10098:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10099:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitExpression\28SkSL::Expression\20const&\29 +10100:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10101:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +10102:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29_6469 +10103:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29 +10104:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitExpression\28SkSL::Expression\20const&\29 +10105:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29_6494 +10106:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29 +10107:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitStatement\28SkSL::Statement\20const&\29 +10108:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitExpression\28SkSL::Expression\20const&\29 +10109:SkSL::VectorType::isOrContainsBool\28\29\20const +10110:SkSL::VectorType::isAllowedInUniform\28SkSL::Position*\29\20const +10111:SkSL::VectorType::isAllowedInES2\28\29\20const +10112:SkSL::VariableReference::clone\28SkSL::Position\29\20const +10113:SkSL::Variable::~Variable\28\29_7306 +10114:SkSL::Variable::~Variable\28\29 +10115:SkSL::Variable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +10116:SkSL::Variable::mangledName\28\29\20const +10117:SkSL::Variable::layout\28\29\20const +10118:SkSL::Variable::description\28\29\20const +10119:SkSL::VarDeclaration::~VarDeclaration\28\29_7304 +10120:SkSL::VarDeclaration::~VarDeclaration\28\29 +10121:SkSL::VarDeclaration::description\28\29\20const +10122:SkSL::TypeReference::clone\28SkSL::Position\29\20const +10123:SkSL::Type::minimumValue\28\29\20const +10124:SkSL::Type::maximumValue\28\29\20const +10125:SkSL::Type::matches\28SkSL::Type\20const&\29\20const +10126:SkSL::Type::isAllowedInUniform\28SkSL::Position*\29\20const +10127:SkSL::Type::fields\28\29\20const +10128:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29_7389 +10129:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29 +10130:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::visitStatementPtr\28std::__2::unique_ptr>&\29 +10131:SkSL::Tracer::var\28int\2c\20int\29 +10132:SkSL::Tracer::scope\28int\29 +10133:SkSL::Tracer::line\28int\29 +10134:SkSL::Tracer::exit\28int\29 +10135:SkSL::Tracer::enter\28int\29 +10136:SkSL::TextureType::textureAccess\28\29\20const +10137:SkSL::TextureType::isMultisampled\28\29\20const +10138:SkSL::TextureType::isDepth\28\29\20const +10139:SkSL::TernaryExpression::~TernaryExpression\28\29_7089 +10140:SkSL::TernaryExpression::~TernaryExpression\28\29 +10141:SkSL::TernaryExpression::description\28SkSL::OperatorPrecedence\29\20const +10142:SkSL::TernaryExpression::clone\28SkSL::Position\29\20const +10143:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression&\29 +10144:SkSL::Swizzle::description\28SkSL::OperatorPrecedence\29\20const +10145:SkSL::Swizzle::clone\28SkSL::Position\29\20const +10146:SkSL::SwitchStatement::description\28\29\20const +10147:SkSL::SwitchCase::description\28\29\20const +10148:SkSL::StructType::slotType\28unsigned\20long\29\20const +10149:SkSL::StructType::isOrContainsUnsizedArray\28\29\20const +10150:SkSL::StructType::isOrContainsBool\28\29\20const +10151:SkSL::StructType::isOrContainsAtomic\28\29\20const +10152:SkSL::StructType::isOrContainsArray\28\29\20const +10153:SkSL::StructType::isInterfaceBlock\28\29\20const +10154:SkSL::StructType::isBuiltin\28\29\20const +10155:SkSL::StructType::isAllowedInUniform\28SkSL::Position*\29\20const +10156:SkSL::StructType::isAllowedInES2\28\29\20const +10157:SkSL::StructType::fields\28\29\20const +10158:SkSL::StructDefinition::description\28\29\20const +10159:SkSL::StringStream::~StringStream\28\29_12742 +10160:SkSL::StringStream::~StringStream\28\29 +10161:SkSL::StringStream::write\28void\20const*\2c\20unsigned\20long\29 +10162:SkSL::StringStream::writeText\28char\20const*\29 +10163:SkSL::StringStream::write8\28unsigned\20char\29 +10164:SkSL::SingleArgumentConstructor::~SingleArgumentConstructor\28\29 +10165:SkSL::Setting::description\28SkSL::OperatorPrecedence\29\20const +10166:SkSL::Setting::clone\28SkSL::Position\29\20const +10167:SkSL::ScalarType::priority\28\29\20const +10168:SkSL::ScalarType::numberKind\28\29\20const +10169:SkSL::ScalarType::minimumValue\28\29\20const +10170:SkSL::ScalarType::maximumValue\28\29\20const +10171:SkSL::ScalarType::isOrContainsBool\28\29\20const +10172:SkSL::ScalarType::isAllowedInUniform\28SkSL::Position*\29\20const +10173:SkSL::ScalarType::isAllowedInES2\28\29\20const +10174:SkSL::ScalarType::bitWidth\28\29\20const +10175:SkSL::SamplerType::textureAccess\28\29\20const +10176:SkSL::SamplerType::isMultisampled\28\29\20const +10177:SkSL::SamplerType::isDepth\28\29\20const +10178:SkSL::SamplerType::isArrayedTexture\28\29\20const +10179:SkSL::SamplerType::dimensions\28\29\20const +10180:SkSL::ReturnStatement::description\28\29\20const +10181:SkSL::RP::VariableLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10182:SkSL::RP::VariableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10183:SkSL::RP::VariableLValue::isWritable\28\29\20const +10184:SkSL::RP::VariableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10185:SkSL::RP::UnownedLValueSlice::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10186:SkSL::RP::UnownedLValueSlice::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10187:SkSL::RP::UnownedLValueSlice::fixedSlotRange\28SkSL::RP::Generator*\29 +10188:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29_6721 +10189:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29 +10190:SkSL::RP::SwizzleLValue::swizzle\28\29 +10191:SkSL::RP::SwizzleLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10192:SkSL::RP::SwizzleLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10193:SkSL::RP::SwizzleLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10194:SkSL::RP::ScratchLValue::~ScratchLValue\28\29_6735 +10195:SkSL::RP::ScratchLValue::~ScratchLValue\28\29 +10196:SkSL::RP::ScratchLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10197:SkSL::RP::ScratchLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10198:SkSL::RP::LValueSlice::~LValueSlice\28\29_6719 +10199:SkSL::RP::LValueSlice::~LValueSlice\28\29 +10200:SkSL::RP::LValue::~LValue\28\29_6711 +10201:SkSL::RP::ImmutableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10202:SkSL::RP::ImmutableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10203:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29_6728 +10204:SkSL::RP::DynamicIndexLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10205:SkSL::RP::DynamicIndexLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10206:SkSL::RP::DynamicIndexLValue::isWritable\28\29\20const +10207:SkSL::RP::DynamicIndexLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10208:SkSL::ProgramVisitor::visitStatementPtr\28std::__2::unique_ptr>\20const&\29 +10209:SkSL::ProgramVisitor::visitExpressionPtr\28std::__2::unique_ptr>\20const&\29 +10210:SkSL::PrefixExpression::~PrefixExpression\28\29_7019 +10211:SkSL::PrefixExpression::~PrefixExpression\28\29 +10212:SkSL::PrefixExpression::description\28SkSL::OperatorPrecedence\29\20const +10213:SkSL::PrefixExpression::clone\28SkSL::Position\29\20const +10214:SkSL::PostfixExpression::description\28SkSL::OperatorPrecedence\29\20const +10215:SkSL::PostfixExpression::clone\28SkSL::Position\29\20const +10216:SkSL::Poison::description\28SkSL::OperatorPrecedence\29\20const +10217:SkSL::Poison::clone\28SkSL::Position\29\20const +10218:SkSL::PipelineStage::Callbacks::getMainName\28\29 +10219:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29_6422 +10220:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29 +10221:SkSL::Parser::Checkpoint::ForwardingErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +10222:SkSL::Nop::description\28\29\20const +10223:SkSL::MultiArgumentConstructor::~MultiArgumentConstructor\28\29 +10224:SkSL::ModifiersDeclaration::description\28\29\20const +10225:SkSL::MethodReference::description\28SkSL::OperatorPrecedence\29\20const +10226:SkSL::MethodReference::clone\28SkSL::Position\29\20const +10227:SkSL::MatrixType::slotCount\28\29\20const +10228:SkSL::MatrixType::rows\28\29\20const +10229:SkSL::MatrixType::isAllowedInES2\28\29\20const +10230:SkSL::LiteralType::minimumValue\28\29\20const +10231:SkSL::LiteralType::maximumValue\28\29\20const +10232:SkSL::LiteralType::isOrContainsBool\28\29\20const +10233:SkSL::Literal::getConstantValue\28int\29\20const +10234:SkSL::Literal::description\28SkSL::OperatorPrecedence\29\20const +10235:SkSL::Literal::compareConstant\28SkSL::Expression\20const&\29\20const +10236:SkSL::Literal::clone\28SkSL::Position\29\20const +10237:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_uintBitsToFloat\28double\2c\20double\2c\20double\29 +10238:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_trunc\28double\2c\20double\2c\20double\29 +10239:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tanh\28double\2c\20double\2c\20double\29 +10240:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tan\28double\2c\20double\2c\20double\29 +10241:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_step\28double\2c\20double\2c\20double\29 +10242:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sqrt\28double\2c\20double\2c\20double\29 +10243:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_smoothstep\28double\2c\20double\2c\20double\29 +10244:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sinh\28double\2c\20double\2c\20double\29 +10245:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sin\28double\2c\20double\2c\20double\29 +10246:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_saturate\28double\2c\20double\2c\20double\29 +10247:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_radians\28double\2c\20double\2c\20double\29 +10248:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_pow\28double\2c\20double\2c\20double\29 +10249:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mod\28double\2c\20double\2c\20double\29 +10250:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mix\28double\2c\20double\2c\20double\29 +10251:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_min\28double\2c\20double\2c\20double\29 +10252:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_max\28double\2c\20double\2c\20double\29 +10253:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_matrixCompMult\28double\2c\20double\2c\20double\29 +10254:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log\28double\2c\20double\2c\20double\29 +10255:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log2\28double\2c\20double\2c\20double\29 +10256:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_inversesqrt\28double\2c\20double\2c\20double\29 +10257:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_intBitsToFloat\28double\2c\20double\2c\20double\29 +10258:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fract\28double\2c\20double\2c\20double\29 +10259:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fma\28double\2c\20double\2c\20double\29 +10260:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floor\28double\2c\20double\2c\20double\29 +10261:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToUint\28double\2c\20double\2c\20double\29 +10262:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToInt\28double\2c\20double\2c\20double\29 +10263:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp\28double\2c\20double\2c\20double\29 +10264:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp2\28double\2c\20double\2c\20double\29 +10265:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_degrees\28double\2c\20double\2c\20double\29 +10266:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cosh\28double\2c\20double\2c\20double\29 +10267:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cos\28double\2c\20double\2c\20double\29 +10268:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_clamp\28double\2c\20double\2c\20double\29 +10269:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_ceil\28double\2c\20double\2c\20double\29 +10270:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atanh\28double\2c\20double\2c\20double\29 +10271:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan\28double\2c\20double\2c\20double\29 +10272:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan2\28double\2c\20double\2c\20double\29 +10273:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asinh\28double\2c\20double\2c\20double\29 +10274:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asin\28double\2c\20double\2c\20double\29 +10275:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acosh\28double\2c\20double\2c\20double\29 +10276:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acos\28double\2c\20double\2c\20double\29 +10277:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_abs\28double\2c\20double\2c\20double\29 +10278:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_notEqual\28double\2c\20double\29 +10279:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThan\28double\2c\20double\29 +10280:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThanEqual\28double\2c\20double\29 +10281:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThan\28double\2c\20double\29 +10282:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThanEqual\28double\2c\20double\29 +10283:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_equal\28double\2c\20double\29 +10284:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_dot\28double\2c\20double\2c\20double\29 +10285:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_any\28double\2c\20double\2c\20double\29 +10286:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_all\28double\2c\20double\2c\20double\29 +10287:SkSL::InterfaceBlock::~InterfaceBlock\28\29_6986 +10288:SkSL::InterfaceBlock::description\28\29\20const +10289:SkSL::IndexExpression::~IndexExpression\28\29_6983 +10290:SkSL::IndexExpression::~IndexExpression\28\29 +10291:SkSL::IndexExpression::description\28SkSL::OperatorPrecedence\29\20const +10292:SkSL::IndexExpression::clone\28SkSL::Position\29\20const +10293:SkSL::IfStatement::~IfStatement\28\29_6976 +10294:SkSL::IfStatement::~IfStatement\28\29 +10295:SkSL::IfStatement::description\28\29\20const +10296:SkSL::GlobalVarDeclaration::description\28\29\20const +10297:SkSL::GenericType::slotType\28unsigned\20long\29\20const +10298:SkSL::GenericType::coercibleTypes\28\29\20const +10299:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29_12817 +10300:SkSL::FunctionReference::description\28SkSL::OperatorPrecedence\29\20const +10301:SkSL::FunctionReference::clone\28SkSL::Position\29\20const +10302:SkSL::FunctionPrototype::description\28\29\20const +10303:SkSL::FunctionDefinition::description\28\29\20const +10304:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29_6967 +10305:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29 +10306:SkSL::FunctionCall::description\28SkSL::OperatorPrecedence\29\20const +10307:SkSL::FunctionCall::clone\28SkSL::Position\29\20const +10308:SkSL::ForStatement::~ForStatement\28\29_6858 +10309:SkSL::ForStatement::~ForStatement\28\29 +10310:SkSL::ForStatement::description\28\29\20const +10311:SkSL::FieldSymbol::description\28\29\20const +10312:SkSL::FieldAccess::clone\28SkSL::Position\29\20const +10313:SkSL::Extension::description\28\29\20const +10314:SkSL::ExtendedVariable::~ExtendedVariable\28\29_7308 +10315:SkSL::ExtendedVariable::~ExtendedVariable\28\29 +10316:SkSL::ExtendedVariable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +10317:SkSL::ExtendedVariable::mangledName\28\29\20const +10318:SkSL::ExtendedVariable::layout\28\29\20const +10319:SkSL::ExtendedVariable::interfaceBlock\28\29\20const +10320:SkSL::ExtendedVariable::detachDeadInterfaceBlock\28\29 +10321:SkSL::ExpressionStatement::description\28\29\20const +10322:SkSL::Expression::getConstantValue\28int\29\20const +10323:SkSL::EmptyExpression::description\28SkSL::OperatorPrecedence\29\20const +10324:SkSL::EmptyExpression::clone\28SkSL::Position\29\20const +10325:SkSL::DoStatement::description\28\29\20const +10326:SkSL::DiscardStatement::description\28\29\20const +10327:SkSL::DebugTracePriv::~DebugTracePriv\28\29_7339 +10328:SkSL::DebugTracePriv::dump\28SkWStream*\29\20const +10329:SkSL::CountReturnsWithLimit::visitStatement\28SkSL::Statement\20const&\29 +10330:SkSL::ContinueStatement::description\28\29\20const +10331:SkSL::ConstructorStruct::clone\28SkSL::Position\29\20const +10332:SkSL::ConstructorSplat::getConstantValue\28int\29\20const +10333:SkSL::ConstructorSplat::clone\28SkSL::Position\29\20const +10334:SkSL::ConstructorScalarCast::clone\28SkSL::Position\29\20const +10335:SkSL::ConstructorMatrixResize::getConstantValue\28int\29\20const +10336:SkSL::ConstructorMatrixResize::clone\28SkSL::Position\29\20const +10337:SkSL::ConstructorDiagonalMatrix::getConstantValue\28int\29\20const +10338:SkSL::ConstructorDiagonalMatrix::clone\28SkSL::Position\29\20const +10339:SkSL::ConstructorCompoundCast::clone\28SkSL::Position\29\20const +10340:SkSL::ConstructorCompound::clone\28SkSL::Position\29\20const +10341:SkSL::ConstructorArrayCast::clone\28SkSL::Position\29\20const +10342:SkSL::ConstructorArray::clone\28SkSL::Position\29\20const +10343:SkSL::Compiler::CompilerErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +10344:SkSL::CodeGenerator::~CodeGenerator\28\29 +10345:SkSL::ChildCall::description\28SkSL::OperatorPrecedence\29\20const +10346:SkSL::ChildCall::clone\28SkSL::Position\29\20const +10347:SkSL::BreakStatement::description\28\29\20const +10348:SkSL::Block::~Block\28\29_6760 +10349:SkSL::Block::~Block\28\29 +10350:SkSL::Block::isEmpty\28\29\20const +10351:SkSL::Block::description\28\29\20const +10352:SkSL::BinaryExpression::~BinaryExpression\28\29_6753 +10353:SkSL::BinaryExpression::~BinaryExpression\28\29 +10354:SkSL::BinaryExpression::description\28SkSL::OperatorPrecedence\29\20const +10355:SkSL::BinaryExpression::clone\28SkSL::Position\29\20const +10356:SkSL::ArrayType::slotType\28unsigned\20long\29\20const +10357:SkSL::ArrayType::slotCount\28\29\20const +10358:SkSL::ArrayType::matches\28SkSL::Type\20const&\29\20const +10359:SkSL::ArrayType::isUnsizedArray\28\29\20const +10360:SkSL::ArrayType::isOrContainsUnsizedArray\28\29\20const +10361:SkSL::ArrayType::isBuiltin\28\29\20const +10362:SkSL::ArrayType::isAllowedInUniform\28SkSL::Position*\29\20const +10363:SkSL::AnyConstructor::getConstantValue\28int\29\20const +10364:SkSL::AnyConstructor::description\28SkSL::OperatorPrecedence\29\20const +10365:SkSL::AnyConstructor::compareConstant\28SkSL::Expression\20const&\29\20const +10366:SkSL::Analysis::\28anonymous\20namespace\29::LoopControlFlowVisitor::visitStatement\28SkSL::Statement\20const&\29 +10367:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29::IsDynamicallyUniformExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +10368:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29::IsCompileTimeConstantVisitor::visitExpression\28SkSL::Expression\20const&\29 +10369:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29::HasSideEffectsVisitor::visitExpression\28SkSL::Expression\20const&\29 +10370:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29_6537 +10371:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29 +10372:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::visitExpression\28SkSL::Expression\20const&\29 +10373:SkSL::Analysis::ContainsVariable\28SkSL::Expression\20const&\2c\20SkSL::Variable\20const&\29::ContainsVariableVisitor::visitExpression\28SkSL::Expression\20const&\29 +10374:SkSL::Analysis::ContainsRTAdjust\28SkSL::Expression\20const&\29::ContainsRTAdjustVisitor::visitExpression\28SkSL::Expression\20const&\29 +10375:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29_6463 +10376:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29 +10377:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitExpression\28SkSL::Expression\20const&\29 +10378:SkSL::AliasType::textureAccess\28\29\20const +10379:SkSL::AliasType::slotType\28unsigned\20long\29\20const +10380:SkSL::AliasType::slotCount\28\29\20const +10381:SkSL::AliasType::rows\28\29\20const +10382:SkSL::AliasType::priority\28\29\20const +10383:SkSL::AliasType::isVector\28\29\20const +10384:SkSL::AliasType::isUnsizedArray\28\29\20const +10385:SkSL::AliasType::isStruct\28\29\20const +10386:SkSL::AliasType::isScalar\28\29\20const +10387:SkSL::AliasType::isMultisampled\28\29\20const +10388:SkSL::AliasType::isMatrix\28\29\20const +10389:SkSL::AliasType::isLiteral\28\29\20const +10390:SkSL::AliasType::isInterfaceBlock\28\29\20const +10391:SkSL::AliasType::isDepth\28\29\20const +10392:SkSL::AliasType::isArrayedTexture\28\29\20const +10393:SkSL::AliasType::isArray\28\29\20const +10394:SkSL::AliasType::dimensions\28\29\20const +10395:SkSL::AliasType::componentType\28\29\20const +10396:SkSL::AliasType::columns\28\29\20const +10397:SkSL::AliasType::coercibleTypes\28\29\20const +10398:SkRuntimeShader::~SkRuntimeShader\28\29_4839 +10399:SkRuntimeShader::type\28\29\20const +10400:SkRuntimeShader::isOpaque\28\29\20const +10401:SkRuntimeShader::getTypeName\28\29\20const +10402:SkRuntimeShader::flatten\28SkWriteBuffer&\29\20const +10403:SkRuntimeShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10404:SkRuntimeEffect::~SkRuntimeEffect\28\29_3950 +10405:SkRuntimeEffect::MakeFromSource\28SkString\2c\20SkRuntimeEffect::Options\20const&\2c\20SkSL::ProgramKind\29 +10406:SkRuntimeColorFilter::~SkRuntimeColorFilter\28\29_5777 +10407:SkRuntimeColorFilter::~SkRuntimeColorFilter\28\29 +10408:SkRuntimeColorFilter::onIsAlphaUnchanged\28\29\20const +10409:SkRuntimeColorFilter::getTypeName\28\29\20const +10410:SkRuntimeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10411:SkRuntimeBlender::~SkRuntimeBlender\28\29_3917 +10412:SkRuntimeBlender::~SkRuntimeBlender\28\29 +10413:SkRuntimeBlender::onAppendStages\28SkStageRec\20const&\29\20const +10414:SkRuntimeBlender::getTypeName\28\29\20const +10415:SkRgnClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10416:SkRgnClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10417:SkRgnClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10418:SkRgnClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10419:SkRgnClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10420:SkRgnClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10421:SkRgnBuilder::~SkRgnBuilder\28\29_3882 +10422:SkRgnBuilder::blitH\28int\2c\20int\2c\20int\29 +10423:SkResourceCache::SetTotalByteLimit\28unsigned\20long\29 +10424:SkResourceCache::GetTotalBytesUsed\28\29 +10425:SkResourceCache::GetTotalByteLimit\28\29 +10426:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29_4661 +10427:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29 +10428:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::data\28int\29\20const +10429:SkRefCntSet::~SkRefCntSet\28\29_2054 +10430:SkRefCntSet::incPtr\28void*\29 +10431:SkRefCntSet::decPtr\28void*\29 +10432:SkRectClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10433:SkRectClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10434:SkRectClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10435:SkRectClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10436:SkRectClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10437:SkRectClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10438:SkRecorder::~SkRecorder\28\29_3831 +10439:SkRecorder::~SkRecorder\28\29 +10440:SkRecorder::willSave\28\29 +10441:SkRecorder::onResetClip\28\29 +10442:SkRecorder::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10443:SkRecorder::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +10444:SkRecorder::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10445:SkRecorder::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +10446:SkRecorder::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10447:SkRecorder::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10448:SkRecorder::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10449:SkRecorder::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10450:SkRecorder::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +10451:SkRecorder::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +10452:SkRecorder::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10453:SkRecorder::onDrawPaint\28SkPaint\20const&\29 +10454:SkRecorder::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10455:SkRecorder::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +10456:SkRecorder::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10457:SkRecorder::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +10458:SkRecorder::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10459:SkRecorder::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +10460:SkRecorder::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10461:SkRecorder::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10462:SkRecorder::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +10463:SkRecorder::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10464:SkRecorder::onDrawBehind\28SkPaint\20const&\29 +10465:SkRecorder::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +10466:SkRecorder::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +10467:SkRecorder::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +10468:SkRecorder::onDoSaveBehind\28SkRect\20const*\29 +10469:SkRecorder::onClipShader\28sk_sp\2c\20SkClipOp\29 +10470:SkRecorder::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10471:SkRecorder::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10472:SkRecorder::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10473:SkRecorder::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10474:SkRecorder::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +10475:SkRecorder::didTranslate\28float\2c\20float\29 +10476:SkRecorder::didSetM44\28SkM44\20const&\29 +10477:SkRecorder::didScale\28float\2c\20float\29 +10478:SkRecorder::didRestore\28\29 +10479:SkRecorder::didConcat44\28SkM44\20const&\29 +10480:SkRecordedDrawable::~SkRecordedDrawable\28\29_3778 +10481:SkRecordedDrawable::~SkRecordedDrawable\28\29 +10482:SkRecordedDrawable::onMakePictureSnapshot\28\29 +10483:SkRecordedDrawable::onGetBounds\28\29 +10484:SkRecordedDrawable::onDraw\28SkCanvas*\29 +10485:SkRecordedDrawable::onApproximateBytesUsed\28\29 +10486:SkRecordedDrawable::getTypeName\28\29\20const +10487:SkRecordedDrawable::flatten\28SkWriteBuffer&\29\20const +10488:SkRecord::~SkRecord\28\29_3732 +10489:SkRecord::~SkRecord\28\29 +10490:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29_1506 +10491:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29 +10492:SkRasterPipelineSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +10493:SkRasterPipelineSpriteBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10494:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29_3686 +10495:SkRasterPipelineBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10496:SkRasterPipelineBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10497:SkRasterPipelineBlitter::blitH\28int\2c\20int\2c\20int\29 +10498:SkRasterPipelineBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10499:SkRasterPipelineBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10500:SkRasterPipelineBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10501:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_3::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10502:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_2::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10503:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_1::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10504:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_0::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10505:SkRadialGradient::getTypeName\28\29\20const +10506:SkRadialGradient::flatten\28SkWriteBuffer&\29\20const +10507:SkRadialGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10508:SkRadialGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +10509:SkRTree::~SkRTree\28\29_3621 +10510:SkRTree::~SkRTree\28\29 +10511:SkRTree::search\28SkRect\20const&\2c\20std::__2::vector>*\29\20const +10512:SkRTree::insert\28SkRect\20const*\2c\20int\29 +10513:SkRTree::bytesUsed\28\29\20const +10514:SkPtrSet::~SkPtrSet\28\29 +10515:SkPngNormalDecoder::~SkPngNormalDecoder\28\29 +10516:SkPngNormalDecoder::setRange\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +10517:SkPngNormalDecoder::decode\28int*\29 +10518:SkPngNormalDecoder::decodeAllRows\28void*\2c\20unsigned\20long\2c\20int*\29 +10519:SkPngNormalDecoder::RowCallback\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20int\2c\20int\29 +10520:SkPngNormalDecoder::AllRowsCallback\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20int\2c\20int\29 +10521:SkPngInterlacedDecoder::~SkPngInterlacedDecoder\28\29_12999 +10522:SkPngInterlacedDecoder::~SkPngInterlacedDecoder\28\29 +10523:SkPngInterlacedDecoder::setRange\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +10524:SkPngInterlacedDecoder::decode\28int*\29 +10525:SkPngInterlacedDecoder::decodeAllRows\28void*\2c\20unsigned\20long\2c\20int*\29 +10526:SkPngInterlacedDecoder::InterlacedRowCallback\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20int\2c\20int\29 +10527:SkPngEncoderImpl::~SkPngEncoderImpl\28\29_12864 +10528:SkPngEncoderImpl::onFinishEncoding\28\29 +10529:SkPngEncoderImpl::onEncodeRow\28SkSpan\29 +10530:SkPngEncoderBase::~SkPngEncoderBase\28\29 +10531:SkPngEncoderBase::onEncodeRows\28int\29 +10532:SkPngCompositeChunkReader::~SkPngCompositeChunkReader\28\29_13007 +10533:SkPngCompositeChunkReader::~SkPngCompositeChunkReader\28\29 +10534:SkPngCompositeChunkReader::readChunk\28char\20const*\2c\20void\20const*\2c\20unsigned\20long\29 +10535:SkPngCodecBase::initializeXforms\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20int\29 +10536:SkPngCodecBase::getSampler\28bool\29 +10537:SkPngCodec::~SkPngCodec\28\29_12991 +10538:SkPngCodec::onTryGetTrnsChunk\28\29 +10539:SkPngCodec::onTryGetPlteChunk\28\29 +10540:SkPngCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +10541:SkPngCodec::onRewind\28\29 +10542:SkPngCodec::onIncrementalDecode\28int*\29 +10543:SkPngCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +10544:SkPngCodec::onGetGainmapInfo\28SkGainmapInfo*\29 +10545:SkPngCodec::onGetGainmapCodec\28SkGainmapInfo*\2c\20std::__2::unique_ptr>*\29 +10546:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_2::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10547:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_1::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10548:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_0::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10549:SkPixelRef::~SkPixelRef\28\29_3552 +10550:SkPictureShader::~SkPictureShader\28\29_4823 +10551:SkPictureShader::~SkPictureShader\28\29 +10552:SkPictureShader::type\28\29\20const +10553:SkPictureShader::getTypeName\28\29\20const +10554:SkPictureShader::flatten\28SkWriteBuffer&\29\20const +10555:SkPictureShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10556:SkPictureRecorder*\20emscripten::internal::operator_new\28\29 +10557:SkPictureRecord::~SkPictureRecord\28\29_3536 +10558:SkPictureRecord::willSave\28\29 +10559:SkPictureRecord::willRestore\28\29 +10560:SkPictureRecord::onResetClip\28\29 +10561:SkPictureRecord::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10562:SkPictureRecord::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +10563:SkPictureRecord::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10564:SkPictureRecord::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +10565:SkPictureRecord::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10566:SkPictureRecord::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10567:SkPictureRecord::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10568:SkPictureRecord::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10569:SkPictureRecord::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +10570:SkPictureRecord::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +10571:SkPictureRecord::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10572:SkPictureRecord::onDrawPaint\28SkPaint\20const&\29 +10573:SkPictureRecord::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10574:SkPictureRecord::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10575:SkPictureRecord::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +10576:SkPictureRecord::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10577:SkPictureRecord::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10578:SkPictureRecord::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10579:SkPictureRecord::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +10580:SkPictureRecord::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10581:SkPictureRecord::onDrawBehind\28SkPaint\20const&\29 +10582:SkPictureRecord::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +10583:SkPictureRecord::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +10584:SkPictureRecord::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +10585:SkPictureRecord::onDoSaveBehind\28SkRect\20const*\29 +10586:SkPictureRecord::onClipShader\28sk_sp\2c\20SkClipOp\29 +10587:SkPictureRecord::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10588:SkPictureRecord::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10589:SkPictureRecord::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10590:SkPictureRecord::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10591:SkPictureRecord::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +10592:SkPictureRecord::didTranslate\28float\2c\20float\29 +10593:SkPictureRecord::didSetM44\28SkM44\20const&\29 +10594:SkPictureRecord::didScale\28float\2c\20float\29 +10595:SkPictureRecord::didConcat44\28SkM44\20const&\29 +10596:SkPictureData::serialize\28SkWStream*\2c\20SkSerialProcs\20const&\2c\20SkRefCntSet*\2c\20bool\29\20const::DevNull::write\28void\20const*\2c\20unsigned\20long\29 +10597:SkPerlinNoiseShader::~SkPerlinNoiseShader\28\29_4807 +10598:SkPerlinNoiseShader::~SkPerlinNoiseShader\28\29 +10599:SkPerlinNoiseShader::getTypeName\28\29\20const +10600:SkPerlinNoiseShader::flatten\28SkWriteBuffer&\29\20const +10601:SkPerlinNoiseShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10602:SkPath::setIsVolatile\28bool\29 +10603:SkPath::setFillType\28SkPathFillType\29 +10604:SkPath::isVolatile\28\29\20const +10605:SkPath::getFillType\28\29\20const +10606:SkPath2DPathEffectImpl::~SkPath2DPathEffectImpl\28\29_5611 +10607:SkPath2DPathEffectImpl::~SkPath2DPathEffectImpl\28\29 +10608:SkPath2DPathEffectImpl::next\28SkPoint\20const&\2c\20int\2c\20int\2c\20SkPath*\29\20const +10609:SkPath2DPathEffectImpl::getTypeName\28\29\20const +10610:SkPath2DPathEffectImpl::getFactory\28\29\20const +10611:SkPath2DPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +10612:SkPath2DPathEffectImpl::CreateProc\28SkReadBuffer&\29 +10613:SkPath1DPathEffectImpl::~SkPath1DPathEffectImpl\28\29_5585 +10614:SkPath1DPathEffectImpl::~SkPath1DPathEffectImpl\28\29 +10615:SkPath1DPathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +10616:SkPath1DPathEffectImpl::next\28SkPath*\2c\20float\2c\20SkPathMeasure&\29\20const +10617:SkPath1DPathEffectImpl::getTypeName\28\29\20const +10618:SkPath1DPathEffectImpl::getFactory\28\29\20const +10619:SkPath1DPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +10620:SkPath1DPathEffectImpl::begin\28float\29\20const +10621:SkPath1DPathEffectImpl::CreateProc\28SkReadBuffer&\29 +10622:SkPath1DPathEffect::Make\28SkPath\20const&\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style\29 +10623:SkPath*\20emscripten::internal::operator_new\28\29 +10624:SkPairPathEffect::~SkPairPathEffect\28\29_3373 +10625:SkPaint::setDither\28bool\29 +10626:SkPaint::setAntiAlias\28bool\29 +10627:SkPaint::getStrokeMiter\28\29\20const +10628:SkPaint::getStrokeJoin\28\29\20const +10629:SkPaint::getStrokeCap\28\29\20const +10630:SkPaint*\20emscripten::internal::operator_new\28\29 +10631:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29_8200 +10632:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29 +10633:SkOTUtils::LocalizedStrings_SingleName::next\28SkTypeface::LocalizedString*\29 +10634:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29_7449 +10635:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29 +10636:SkOTUtils::LocalizedStrings_NameTable::next\28SkTypeface::LocalizedString*\29 +10637:SkNoPixelsDevice::~SkNoPixelsDevice\28\29_1937 +10638:SkNoPixelsDevice::~SkNoPixelsDevice\28\29 +10639:SkNoPixelsDevice::replaceClip\28SkIRect\20const&\29 +10640:SkNoPixelsDevice::pushClipStack\28\29 +10641:SkNoPixelsDevice::popClipStack\28\29 +10642:SkNoPixelsDevice::onClipShader\28sk_sp\29 +10643:SkNoPixelsDevice::isClipWideOpen\28\29\20const +10644:SkNoPixelsDevice::isClipRect\28\29\20const +10645:SkNoPixelsDevice::isClipEmpty\28\29\20const +10646:SkNoPixelsDevice::isClipAntiAliased\28\29\20const +10647:SkNoPixelsDevice::devClipBounds\28\29\20const +10648:SkNoPixelsDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10649:SkNoPixelsDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +10650:SkNoPixelsDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +10651:SkNoPixelsDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +10652:SkNoPixelsDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +10653:SkNoDrawCanvas::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +10654:SkNoDrawCanvas::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +10655:SkMipmap::~SkMipmap\28\29_2577 +10656:SkMipmap::~SkMipmap\28\29 +10657:SkMipmap::onDataChange\28void*\2c\20void*\29 +10658:SkMemoryStream::~SkMemoryStream\28\29_4192 +10659:SkMemoryStream::~SkMemoryStream\28\29 +10660:SkMemoryStream::setMemory\28void\20const*\2c\20unsigned\20long\2c\20bool\29 +10661:SkMemoryStream::seek\28unsigned\20long\29 +10662:SkMemoryStream::rewind\28\29 +10663:SkMemoryStream::read\28void*\2c\20unsigned\20long\29 +10664:SkMemoryStream::peek\28void*\2c\20unsigned\20long\29\20const +10665:SkMemoryStream::onFork\28\29\20const +10666:SkMemoryStream::onDuplicate\28\29\20const +10667:SkMemoryStream::move\28long\29 +10668:SkMemoryStream::isAtEnd\28\29\20const +10669:SkMemoryStream::getMemoryBase\28\29 +10670:SkMemoryStream::getLength\28\29\20const +10671:SkMemoryStream::getData\28\29\20const +10672:SkMatrixColorFilter::onIsAlphaUnchanged\28\29\20const +10673:SkMatrixColorFilter::onAsAColorMatrix\28float*\29\20const +10674:SkMatrixColorFilter::getTypeName\28\29\20const +10675:SkMatrixColorFilter::flatten\28SkWriteBuffer&\29\20const +10676:SkMatrixColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10677:SkMatrix::Trans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10678:SkMatrix::Trans_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10679:SkMatrix::Scale_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10680:SkMatrix::Scale_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10681:SkMatrix::ScaleTrans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10682:SkMatrix::Poly4Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +10683:SkMatrix::Poly3Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +10684:SkMatrix::Poly2Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +10685:SkMatrix::Persp_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10686:SkMatrix::Persp_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10687:SkMatrix::Identity_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10688:SkMatrix::Identity_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10689:SkMatrix::Affine_vpts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10690:SkMaskSwizzler::onSetSampleX\28int\29 +10691:SkMaskFilterBase::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +10692:SkMaskFilterBase::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +10693:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29_2386 +10694:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29 +10695:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29_3562 +10696:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29 +10697:SkLumaColorFilter::Make\28\29 +10698:SkLocalMatrixShader::~SkLocalMatrixShader\28\29_4788 +10699:SkLocalMatrixShader::~SkLocalMatrixShader\28\29 +10700:SkLocalMatrixShader::type\28\29\20const +10701:SkLocalMatrixShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +10702:SkLocalMatrixShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +10703:SkLocalMatrixShader::makeAsALocalMatrixShader\28SkMatrix*\29\20const +10704:SkLocalMatrixShader::isOpaque\28\29\20const +10705:SkLocalMatrixShader::isConstant\28\29\20const +10706:SkLocalMatrixShader::getTypeName\28\29\20const +10707:SkLocalMatrixShader::flatten\28SkWriteBuffer&\29\20const +10708:SkLocalMatrixShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10709:SkLocalMatrixShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10710:SkLinearGradient::getTypeName\28\29\20const +10711:SkLinearGradient::flatten\28SkWriteBuffer&\29\20const +10712:SkLinearGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10713:SkLine2DPathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +10714:SkLine2DPathEffectImpl::nextSpan\28int\2c\20int\2c\20int\2c\20SkPath*\29\20const +10715:SkLine2DPathEffectImpl::getTypeName\28\29\20const +10716:SkLine2DPathEffectImpl::getFactory\28\29\20const +10717:SkLine2DPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +10718:SkLine2DPathEffectImpl::CreateProc\28SkReadBuffer&\29 +10719:SkJpegMetadataDecoderImpl::~SkJpegMetadataDecoderImpl\28\29_12921 +10720:SkJpegMetadataDecoderImpl::~SkJpegMetadataDecoderImpl\28\29 +10721:SkJpegMetadataDecoderImpl::getISOGainmapMetadata\28bool\29\20const +10722:SkJpegMetadataDecoderImpl::getICCProfileData\28bool\29\20const +10723:SkJpegMetadataDecoderImpl::getExifMetadata\28bool\29\20const +10724:SkJpegMemorySourceMgr::skipInputBytes\28unsigned\20long\2c\20unsigned\20char\20const*&\2c\20unsigned\20long&\29 +10725:SkJpegMemorySourceMgr::initSource\28unsigned\20char\20const*&\2c\20unsigned\20long&\29 +10726:SkJpegDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +10727:SkJpegCodec::~SkJpegCodec\28\29_12877 +10728:SkJpegCodec::~SkJpegCodec\28\29 +10729:SkJpegCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +10730:SkJpegCodec::onSkipScanlines\28int\29 +10731:SkJpegCodec::onRewind\28\29 +10732:SkJpegCodec::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +10733:SkJpegCodec::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +10734:SkJpegCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +10735:SkJpegCodec::onGetScaledDimensions\28float\29\20const +10736:SkJpegCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +10737:SkJpegCodec::onGetGainmapCodec\28SkGainmapInfo*\2c\20std::__2::unique_ptr>*\29 +10738:SkJpegCodec::onDimensionsSupported\28SkISize\20const&\29 +10739:SkJpegCodec::getSampler\28bool\29 +10740:SkJpegCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +10741:SkJpegBufferedSourceMgr::~SkJpegBufferedSourceMgr\28\29_12930 +10742:SkJpegBufferedSourceMgr::~SkJpegBufferedSourceMgr\28\29 +10743:SkJpegBufferedSourceMgr::skipInputBytes\28unsigned\20long\2c\20unsigned\20char\20const*&\2c\20unsigned\20long&\29 +10744:SkJpegBufferedSourceMgr::initSource\28unsigned\20char\20const*&\2c\20unsigned\20long&\29 +10745:SkJpegBufferedSourceMgr::fillInputBuffer\28unsigned\20char\20const*&\2c\20unsigned\20long&\29 +10746:SkImage_Raster::~SkImage_Raster\28\29_4631 +10747:SkImage_Raster::~SkImage_Raster\28\29 +10748:SkImage_Raster::onReinterpretColorSpace\28sk_sp\29\20const +10749:SkImage_Raster::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +10750:SkImage_Raster::onPeekPixels\28SkPixmap*\29\20const +10751:SkImage_Raster::onMakeWithMipmaps\28sk_sp\29\20const +10752:SkImage_Raster::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +10753:SkImage_Raster::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +10754:SkImage_Raster::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +10755:SkImage_Raster::onHasMipmaps\28\29\20const +10756:SkImage_Raster::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +10757:SkImage_Raster::notifyAddedToRasterCache\28\29\20const +10758:SkImage_Raster::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +10759:SkImage_LazyTexture::readPixelsProxy\28GrDirectContext*\2c\20SkPixmap\20const&\29\20const +10760:SkImage_LazyTexture::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +10761:SkImage_Lazy::~SkImage_Lazy\28\29 +10762:SkImage_Lazy::onReinterpretColorSpace\28sk_sp\29\20const +10763:SkImage_Lazy::onRefEncoded\28\29\20const +10764:SkImage_Lazy::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +10765:SkImage_Lazy::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +10766:SkImage_Lazy::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +10767:SkImage_Lazy::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +10768:SkImage_Lazy::onIsProtected\28\29\20const +10769:SkImage_Lazy::isValid\28GrRecordingContext*\29\20const +10770:SkImage_Lazy::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +10771:SkImage_GaneshBase::~SkImage_GaneshBase\28\29 +10772:SkImage_GaneshBase::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +10773:SkImage_GaneshBase::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +10774:SkImage_GaneshBase::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +10775:SkImage_GaneshBase::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +10776:SkImage_GaneshBase::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +10777:SkImage_GaneshBase::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +10778:SkImage_GaneshBase::isValid\28GrRecordingContext*\29\20const +10779:SkImage_GaneshBase::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +10780:SkImage_GaneshBase::directContext\28\29\20const +10781:SkImage_Ganesh::~SkImage_Ganesh\28\29_10733 +10782:SkImage_Ganesh::textureSize\28\29\20const +10783:SkImage_Ganesh::onReinterpretColorSpace\28sk_sp\29\20const +10784:SkImage_Ganesh::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +10785:SkImage_Ganesh::onIsProtected\28\29\20const +10786:SkImage_Ganesh::onHasMipmaps\28\29\20const +10787:SkImage_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +10788:SkImage_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +10789:SkImage_Ganesh::generatingSurfaceIsDeleted\28\29 +10790:SkImage_Ganesh::flush\28GrDirectContext*\2c\20GrFlushInfo\20const&\29\20const +10791:SkImage_Ganesh::asView\28GrRecordingContext*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29\20const +10792:SkImage_Ganesh::asFragmentProcessor\28GrRecordingContext*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29\20const +10793:SkImage_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +10794:SkImage_Base::notifyAddedToRasterCache\28\29\20const +10795:SkImage_Base::makeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +10796:SkImage_Base::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +10797:SkImage_Base::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +10798:SkImage_Base::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +10799:SkImage_Base::makeColorSpace\28skgpu::graphite::Recorder*\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +10800:SkImage_Base::makeColorSpace\28GrDirectContext*\2c\20sk_sp\29\20const +10801:SkImage_Base::isTextureBacked\28\29\20const +10802:SkImage_Base::isLazyGenerated\28\29\20const +10803:SkImageShader::~SkImageShader\28\29_4773 +10804:SkImageShader::~SkImageShader\28\29 +10805:SkImageShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +10806:SkImageShader::isOpaque\28\29\20const +10807:SkImageShader::getTypeName\28\29\20const +10808:SkImageShader::flatten\28SkWriteBuffer&\29\20const +10809:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10810:SkImageGenerator::~SkImageGenerator\28\29 +10811:SkImageFilters::Compose\28sk_sp\2c\20sk_sp\29 +10812:SkImage::~SkImage\28\29 +10813:SkIcoDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +10814:SkIcoCodec::~SkIcoCodec\28\29_12952 +10815:SkIcoCodec::~SkIcoCodec\28\29 +10816:SkIcoCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +10817:SkIcoCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +10818:SkIcoCodec::onSkipScanlines\28int\29 +10819:SkIcoCodec::onIncrementalDecode\28int*\29 +10820:SkIcoCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +10821:SkIcoCodec::onGetScanlineOrder\28\29\20const +10822:SkIcoCodec::onGetScaledDimensions\28float\29\20const +10823:SkIcoCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +10824:SkIcoCodec::onDimensionsSupported\28SkISize\20const&\29 +10825:SkIcoCodec::getSampler\28bool\29 +10826:SkIcoCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +10827:SkGradientBaseShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +10828:SkGradientBaseShader::isOpaque\28\29\20const +10829:SkGradientBaseShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10830:SkGifDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +10831:SkGaussianColorFilter::getTypeName\28\29\20const +10832:SkGaussianColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10833:SkGammaColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +10834:SkGammaColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +10835:SkGainmapInfo::serialize\28\29\20const +10836:SkGainmapInfo::SerializeVersion\28\29 +10837:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29_8127 +10838:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29 +10839:SkFontStyleSet_Custom::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +10840:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29_8193 +10841:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29 +10842:SkFontScanner_FreeType::scanFile\28SkStreamAsset*\2c\20int*\29\20const +10843:SkFontScanner_FreeType::scanFace\28SkStreamAsset*\2c\20int\2c\20int*\29\20const +10844:SkFontScanner_FreeType::getFactoryId\28\29\20const +10845:SkFontMgr_Custom::~SkFontMgr_Custom\28\29_8129 +10846:SkFontMgr_Custom::~SkFontMgr_Custom\28\29 +10847:SkFontMgr_Custom::onMatchFamily\28char\20const*\29\20const +10848:SkFontMgr_Custom::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +10849:SkFontMgr_Custom::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +10850:SkFontMgr_Custom::onMakeFromFile\28char\20const*\2c\20int\29\20const +10851:SkFontMgr_Custom::onMakeFromData\28sk_sp\2c\20int\29\20const +10852:SkFontMgr_Custom::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +10853:SkFontMgr_Custom::onGetFamilyName\28int\2c\20SkString*\29\20const +10854:SkFont::setScaleX\28float\29 +10855:SkFont::setEmbeddedBitmaps\28bool\29 +10856:SkFont::isEmbolden\28\29\20const +10857:SkFont::getSkewX\28\29\20const +10858:SkFont::getSize\28\29\20const +10859:SkFont::getScaleX\28\29\20const +10860:SkFont*\20emscripten::internal::operator_new\2c\20float\2c\20float\2c\20float>\28sk_sp&&\2c\20float&&\2c\20float&&\2c\20float&&\29 +10861:SkFont*\20emscripten::internal::operator_new\2c\20float>\28sk_sp&&\2c\20float&&\29 +10862:SkFont*\20emscripten::internal::operator_new>\28sk_sp&&\29 +10863:SkFont*\20emscripten::internal::operator_new\28\29 +10864:SkFILEStream::~SkFILEStream\28\29_4146 +10865:SkFILEStream::~SkFILEStream\28\29 +10866:SkFILEStream::seek\28unsigned\20long\29 +10867:SkFILEStream::rewind\28\29 +10868:SkFILEStream::read\28void*\2c\20unsigned\20long\29 +10869:SkFILEStream::onFork\28\29\20const +10870:SkFILEStream::onDuplicate\28\29\20const +10871:SkFILEStream::move\28long\29 +10872:SkFILEStream::isAtEnd\28\29\20const +10873:SkFILEStream::getPosition\28\29\20const +10874:SkFILEStream::getLength\28\29\20const +10875:SkEncoder::~SkEncoder\28\29 +10876:SkEmptyShader::getTypeName\28\29\20const +10877:SkEmptyPicture::~SkEmptyPicture\28\29 +10878:SkEmptyPicture::cullRect\28\29\20const +10879:SkEmptyFontMgr::onMatchFamily\28char\20const*\29\20const +10880:SkEdgeBuilder::~SkEdgeBuilder\28\29 +10881:SkEdgeBuilder::build\28SkPath\20const&\2c\20SkIRect\20const*\2c\20bool\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +10882:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29_4176 +10883:SkDrawable::onMakePictureSnapshot\28\29 +10884:SkDrawBase::~SkDrawBase\28\29 +10885:SkDraw::paintMasks\28SkZip\2c\20SkPaint\20const&\29\20const +10886:SkDiscretePathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +10887:SkDiscretePathEffectImpl::getTypeName\28\29\20const +10888:SkDiscretePathEffectImpl::getFactory\28\29\20const +10889:SkDiscretePathEffectImpl::computeFastBounds\28SkRect*\29\20const +10890:SkDiscretePathEffectImpl::CreateProc\28SkReadBuffer&\29 +10891:SkDevice::~SkDevice\28\29 +10892:SkDevice::strikeDeviceInfo\28\29\20const +10893:SkDevice::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10894:SkDevice::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10895:SkDevice::drawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20sk_sp\2c\20SkPaint\20const&\29 +10896:SkDevice::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +10897:SkDevice::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10898:SkDevice::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +10899:SkDevice::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10900:SkDevice::drawCoverageMask\28SkSpecialImage\20const*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +10901:SkDevice::drawBlurredRRect\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20float\29 +10902:SkDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +10903:SkDevice::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +10904:SkDevice::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +10905:SkDashImpl::~SkDashImpl\28\29_5626 +10906:SkDashImpl::~SkDashImpl\28\29 +10907:SkDashImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +10908:SkDashImpl::onAsPoints\28SkPathEffectBase::PointData*\2c\20SkPath\20const&\2c\20SkStrokeRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\29\20const +10909:SkDashImpl::getTypeName\28\29\20const +10910:SkDashImpl::flatten\28SkWriteBuffer&\29\20const +10911:SkDashImpl::asADash\28SkPathEffectBase::DashInfo*\29\20const +10912:SkCustomTypefaceBuilder::MakeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29 +10913:SkCornerPathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +10914:SkCornerPathEffectImpl::getTypeName\28\29\20const +10915:SkCornerPathEffectImpl::getFactory\28\29\20const +10916:SkCornerPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +10917:SkCornerPathEffectImpl::CreateProc\28SkReadBuffer&\29 +10918:SkCornerPathEffect::Make\28float\29 +10919:SkContourMeasureIter*\20emscripten::internal::operator_new\28SkPath\20const&\2c\20bool&&\2c\20float&&\29 +10920:SkContourMeasure::~SkContourMeasure\28\29_1860 +10921:SkContourMeasure::~SkContourMeasure\28\29 +10922:SkContourMeasure::isClosed\28\29\20const +10923:SkConicalGradient::getTypeName\28\29\20const +10924:SkConicalGradient::flatten\28SkWriteBuffer&\29\20const +10925:SkConicalGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10926:SkConicalGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +10927:SkComposePathEffect::~SkComposePathEffect\28\29 +10928:SkComposePathEffect::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +10929:SkComposePathEffect::getTypeName\28\29\20const +10930:SkComposePathEffect::computeFastBounds\28SkRect*\29\20const +10931:SkComposeColorFilter::onIsAlphaUnchanged\28\29\20const +10932:SkComposeColorFilter::getTypeName\28\29\20const +10933:SkComposeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10934:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29_5739 +10935:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29 +10936:SkColorSpaceXformColorFilter::getTypeName\28\29\20const +10937:SkColorSpaceXformColorFilter::flatten\28SkWriteBuffer&\29\20const +10938:SkColorSpaceXformColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10939:SkColorShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +10940:SkColorShader::isOpaque\28\29\20const +10941:SkColorShader::getTypeName\28\29\20const +10942:SkColorShader::flatten\28SkWriteBuffer&\29\20const +10943:SkColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10944:SkColorPalette::~SkColorPalette\28\29_5970 +10945:SkColorPalette::~SkColorPalette\28\29 +10946:SkColorFilters::SRGBToLinearGamma\28\29 +10947:SkColorFilters::LinearToSRGBGamma\28\29 +10948:SkColorFilters::Lerp\28float\2c\20sk_sp\2c\20sk_sp\29 +10949:SkColorFilters::Compose\28sk_sp\20const&\2c\20sk_sp\29 +10950:SkColorFilterShader::~SkColorFilterShader\28\29_4737 +10951:SkColorFilterShader::~SkColorFilterShader\28\29 +10952:SkColorFilterShader::isOpaque\28\29\20const +10953:SkColorFilterShader::getTypeName\28\29\20const +10954:SkColorFilterShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10955:SkColorFilterBase::onFilterColor4f\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkColorSpace*\29\20const +10956:SkCodecPriv::PremultiplyARGBasRGBA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10957:SkCodecPriv::PremultiplyARGBasBGRA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10958:SkCodecImageGenerator::~SkCodecImageGenerator\28\29_5967 +10959:SkCodecImageGenerator::~SkCodecImageGenerator\28\29 +10960:SkCodecImageGenerator::onRefEncodedData\28\29 +10961:SkCodecImageGenerator::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +10962:SkCodecImageGenerator::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +10963:SkCodecImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +10964:SkCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +10965:SkCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +10966:SkCodec::onOutputScanline\28int\29\20const +10967:SkCodec::onGetScaledDimensions\28float\29\20const +10968:SkCodec::getEncodedData\28\29\20const +10969:SkCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +10970:SkCanvas::rotate\28float\2c\20float\2c\20float\29 +10971:SkCanvas::recordingContext\28\29\20const +10972:SkCanvas::recorder\28\29\20const +10973:SkCanvas::onPeekPixels\28SkPixmap*\29 +10974:SkCanvas::onNewSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +10975:SkCanvas::onImageInfo\28\29\20const +10976:SkCanvas::onGetProps\28SkSurfaceProps*\2c\20bool\29\20const +10977:SkCanvas::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10978:SkCanvas::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +10979:SkCanvas::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10980:SkCanvas::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +10981:SkCanvas::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10982:SkCanvas::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10983:SkCanvas::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10984:SkCanvas::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10985:SkCanvas::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +10986:SkCanvas::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +10987:SkCanvas::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10988:SkCanvas::onDrawPaint\28SkPaint\20const&\29 +10989:SkCanvas::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10990:SkCanvas::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +10991:SkCanvas::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10992:SkCanvas::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +10993:SkCanvas::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10994:SkCanvas::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +10995:SkCanvas::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10996:SkCanvas::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10997:SkCanvas::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +10998:SkCanvas::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10999:SkCanvas::onDrawBehind\28SkPaint\20const&\29 +11000:SkCanvas::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +11001:SkCanvas::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +11002:SkCanvas::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +11003:SkCanvas::onDiscard\28\29 +11004:SkCanvas::onConvertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11005:SkCanvas::onAccessTopLayerPixels\28SkPixmap*\29 +11006:SkCanvas::isClipRect\28\29\20const +11007:SkCanvas::isClipEmpty\28\29\20const +11008:SkCanvas::getSaveCount\28\29\20const +11009:SkCanvas::getBaseLayerSize\28\29\20const +11010:SkCanvas::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +11011:SkCanvas::drawPicture\28sk_sp\20const&\29 +11012:SkCanvas::drawCircle\28float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +11013:SkCanvas*\20emscripten::internal::operator_new\28float&&\2c\20float&&\29 +11014:SkCanvas*\20emscripten::internal::operator_new\28\29 +11015:SkCachedData::~SkCachedData\28\29_1596 +11016:SkCTMShader::~SkCTMShader\28\29 +11017:SkCTMShader::isConstant\28\29\20const +11018:SkCTMShader::getTypeName\28\29\20const +11019:SkCTMShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11020:SkCTMShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11021:SkBreakIterator_icu::~SkBreakIterator_icu\28\29_8052 +11022:SkBreakIterator_icu::~SkBreakIterator_icu\28\29 +11023:SkBreakIterator_icu::status\28\29 +11024:SkBreakIterator_icu::setText\28char\20const*\2c\20int\29 +11025:SkBreakIterator_icu::setText\28char16_t\20const*\2c\20int\29 +11026:SkBreakIterator_icu::next\28\29 +11027:SkBreakIterator_icu::isDone\28\29 +11028:SkBreakIterator_icu::first\28\29 +11029:SkBreakIterator_icu::current\28\29 +11030:SkBmpStandardCodec::~SkBmpStandardCodec\28\29_6140 +11031:SkBmpStandardCodec::~SkBmpStandardCodec\28\29 +11032:SkBmpStandardCodec::onPrepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +11033:SkBmpStandardCodec::onInIco\28\29\20const +11034:SkBmpStandardCodec::getSampler\28bool\29 +11035:SkBmpStandardCodec::decodeRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +11036:SkBmpRLESampler::onSetSampleX\28int\29 +11037:SkBmpRLESampler::fillWidth\28\29\20const +11038:SkBmpRLECodec::~SkBmpRLECodec\28\29_6124 +11039:SkBmpRLECodec::~SkBmpRLECodec\28\29 +11040:SkBmpRLECodec::skipRows\28int\29 +11041:SkBmpRLECodec::onPrepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +11042:SkBmpRLECodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +11043:SkBmpRLECodec::getSampler\28bool\29 +11044:SkBmpRLECodec::decodeRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +11045:SkBmpMaskCodec::~SkBmpMaskCodec\28\29_6109 +11046:SkBmpMaskCodec::~SkBmpMaskCodec\28\29 +11047:SkBmpMaskCodec::onPrepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +11048:SkBmpMaskCodec::getSampler\28bool\29 +11049:SkBmpMaskCodec::decodeRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +11050:SkBmpDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +11051:SkBmpCodec::~SkBmpCodec\28\29 +11052:SkBmpCodec::skipRows\28int\29 +11053:SkBmpCodec::onSkipScanlines\28int\29 +11054:SkBmpCodec::onRewind\28\29 +11055:SkBmpCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +11056:SkBmpCodec::onGetScanlineOrder\28\29\20const +11057:SkBlurMaskFilterImpl::getTypeName\28\29\20const +11058:SkBlurMaskFilterImpl::flatten\28SkWriteBuffer&\29\20const +11059:SkBlurMaskFilterImpl::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11060:SkBlurMaskFilterImpl::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11061:SkBlurMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +11062:SkBlurMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +11063:SkBlurMaskFilterImpl::asImageFilter\28SkMatrix\20const&\29\20const +11064:SkBlurMaskFilterImpl::asABlur\28SkMaskFilterBase::BlurRec*\29\20const +11065:SkBlockMemoryStream::~SkBlockMemoryStream\28\29_4201 +11066:SkBlockMemoryStream::~SkBlockMemoryStream\28\29 +11067:SkBlockMemoryStream::seek\28unsigned\20long\29 +11068:SkBlockMemoryStream::rewind\28\29 +11069:SkBlockMemoryStream::read\28void*\2c\20unsigned\20long\29 +11070:SkBlockMemoryStream::peek\28void*\2c\20unsigned\20long\29\20const +11071:SkBlockMemoryStream::onFork\28\29\20const +11072:SkBlockMemoryStream::onDuplicate\28\29\20const +11073:SkBlockMemoryStream::move\28long\29 +11074:SkBlockMemoryStream::isAtEnd\28\29\20const +11075:SkBlockMemoryStream::getMemoryBase\28\29 +11076:SkBlockMemoryRefCnt::~SkBlockMemoryRefCnt\28\29_4199 +11077:SkBlockMemoryRefCnt::~SkBlockMemoryRefCnt\28\29 +11078:SkBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11079:SkBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11080:SkBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11081:SkBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11082:SkBlitter::allocBlitMemory\28unsigned\20long\29 +11083:SkBlendShader::getTypeName\28\29\20const +11084:SkBlendShader::flatten\28SkWriteBuffer&\29\20const +11085:SkBlendShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11086:SkBlendModeColorFilter::onIsAlphaUnchanged\28\29\20const +11087:SkBlendModeColorFilter::onAsAColorMode\28unsigned\20int*\2c\20SkBlendMode*\29\20const +11088:SkBlendModeColorFilter::getTypeName\28\29\20const +11089:SkBlendModeColorFilter::flatten\28SkWriteBuffer&\29\20const +11090:SkBlendModeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11091:SkBlendModeBlender::onAppendStages\28SkStageRec\20const&\29\20const +11092:SkBlendModeBlender::getTypeName\28\29\20const +11093:SkBlendModeBlender::flatten\28SkWriteBuffer&\29\20const +11094:SkBlendModeBlender::asBlendMode\28\29\20const +11095:SkBitmapDevice::~SkBitmapDevice\28\29_1381 +11096:SkBitmapDevice::~SkBitmapDevice\28\29 +11097:SkBitmapDevice::snapSpecial\28SkIRect\20const&\2c\20bool\29 +11098:SkBitmapDevice::setImmutable\28\29 +11099:SkBitmapDevice::replaceClip\28SkIRect\20const&\29 +11100:SkBitmapDevice::pushClipStack\28\29 +11101:SkBitmapDevice::popClipStack\28\29 +11102:SkBitmapDevice::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +11103:SkBitmapDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +11104:SkBitmapDevice::onPeekPixels\28SkPixmap*\29 +11105:SkBitmapDevice::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11106:SkBitmapDevice::onClipShader\28sk_sp\29 +11107:SkBitmapDevice::onAccessPixels\28SkPixmap*\29 +11108:SkBitmapDevice::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +11109:SkBitmapDevice::makeSpecial\28SkImage\20const*\29 +11110:SkBitmapDevice::makeSpecial\28SkBitmap\20const&\29 +11111:SkBitmapDevice::isClipWideOpen\28\29\20const +11112:SkBitmapDevice::isClipRect\28\29\20const +11113:SkBitmapDevice::isClipEmpty\28\29\20const +11114:SkBitmapDevice::isClipAntiAliased\28\29\20const +11115:SkBitmapDevice::getRasterHandle\28\29\20const +11116:SkBitmapDevice::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +11117:SkBitmapDevice::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11118:SkBitmapDevice::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +11119:SkBitmapDevice::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +11120:SkBitmapDevice::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +11121:SkBitmapDevice::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +11122:SkBitmapDevice::drawPaint\28SkPaint\20const&\29 +11123:SkBitmapDevice::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +11124:SkBitmapDevice::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11125:SkBitmapDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +11126:SkBitmapDevice::devClipBounds\28\29\20const +11127:SkBitmapDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +11128:SkBitmapDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +11129:SkBitmapDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +11130:SkBitmapDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +11131:SkBitmapDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +11132:SkBitmapDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +11133:SkBitmapCache::Rec::~Rec\28\29_1314 +11134:SkBitmapCache::Rec::~Rec\28\29 +11135:SkBitmapCache::Rec::postAddInstall\28void*\29 +11136:SkBitmapCache::Rec::getCategory\28\29\20const +11137:SkBitmapCache::Rec::canBePurged\28\29 +11138:SkBitmapCache::Rec::bytesUsed\28\29\20const +11139:SkBitmapCache::Rec::ReleaseProc\28void*\2c\20void*\29 +11140:SkBitmapCache::Rec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +11141:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29_4488 +11142:SkBinaryWriteBuffer::write\28SkM44\20const&\29 +11143:SkBinaryWriteBuffer::writeTypeface\28SkTypeface*\29 +11144:SkBinaryWriteBuffer::writeString\28std::__2::basic_string_view>\29 +11145:SkBinaryWriteBuffer::writeStream\28SkStream*\2c\20unsigned\20long\29 +11146:SkBinaryWriteBuffer::writeScalar\28float\29 +11147:SkBinaryWriteBuffer::writeSampling\28SkSamplingOptions\20const&\29 +11148:SkBinaryWriteBuffer::writeRegion\28SkRegion\20const&\29 +11149:SkBinaryWriteBuffer::writeRect\28SkRect\20const&\29 +11150:SkBinaryWriteBuffer::writePoint\28SkPoint\20const&\29 +11151:SkBinaryWriteBuffer::writePointArray\28SkPoint\20const*\2c\20unsigned\20int\29 +11152:SkBinaryWriteBuffer::writePoint3\28SkPoint3\20const&\29 +11153:SkBinaryWriteBuffer::writePath\28SkPath\20const&\29 +11154:SkBinaryWriteBuffer::writePaint\28SkPaint\20const&\29 +11155:SkBinaryWriteBuffer::writePad32\28void\20const*\2c\20unsigned\20long\29 +11156:SkBinaryWriteBuffer::writeMatrix\28SkMatrix\20const&\29 +11157:SkBinaryWriteBuffer::writeImage\28SkImage\20const*\29 +11158:SkBinaryWriteBuffer::writeColor4fArray\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20unsigned\20int\29 +11159:SkBigPicture::~SkBigPicture\28\29_1258 +11160:SkBigPicture::~SkBigPicture\28\29 +11161:SkBigPicture::playback\28SkCanvas*\2c\20SkPicture::AbortCallback*\29\20const +11162:SkBigPicture::cullRect\28\29\20const +11163:SkBigPicture::approximateOpCount\28bool\29\20const +11164:SkBigPicture::approximateBytesUsed\28\29\20const +11165:SkBidiICUFactory::errorName\28UErrorCode\29\20const +11166:SkBidiICUFactory::bidi_setPara\28UBiDi*\2c\20char16_t\20const*\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20UErrorCode*\29\20const +11167:SkBidiICUFactory::bidi_reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29\20const +11168:SkBidiICUFactory::bidi_openSized\28int\2c\20int\2c\20UErrorCode*\29\20const +11169:SkBidiICUFactory::bidi_getLevelAt\28UBiDi\20const*\2c\20int\29\20const +11170:SkBidiICUFactory::bidi_getLength\28UBiDi\20const*\29\20const +11171:SkBidiICUFactory::bidi_getDirection\28UBiDi\20const*\29\20const +11172:SkBidiICUFactory::bidi_close_callback\28\29\20const +11173:SkBezierCubic::Subdivide\28double\20const*\2c\20double\2c\20double*\29 +11174:SkBasicEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +11175:SkBasicEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +11176:SkBasicEdgeBuilder::addQuad\28SkPoint\20const*\29 +11177:SkBasicEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +11178:SkBasicEdgeBuilder::addLine\28SkPoint\20const*\29 +11179:SkBasicEdgeBuilder::addCubic\28SkPoint\20const*\29 +11180:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29 +11181:SkBBoxHierarchy::insert\28SkRect\20const*\2c\20SkBBoxHierarchy::Metadata\20const*\2c\20int\29 +11182:SkArenaAlloc::SkipPod\28char*\29 +11183:SkArenaAlloc::NextBlock\28char*\29 +11184:SkAnimatedImage::~SkAnimatedImage\28\29_7407 +11185:SkAnimatedImage::~SkAnimatedImage\28\29 +11186:SkAnimatedImage::reset\28\29 +11187:SkAnimatedImage::onGetBounds\28\29 +11188:SkAnimatedImage::onDraw\28SkCanvas*\29 +11189:SkAnimatedImage::getRepetitionCount\28\29\20const +11190:SkAnimatedImage::getCurrentFrame\28\29 +11191:SkAnimatedImage::currentFrameDuration\28\29 +11192:SkAndroidCodecAdapter::onGetSupportedSubset\28SkIRect*\29\20const +11193:SkAndroidCodecAdapter::onGetSampledDimensions\28int\29\20const +11194:SkAndroidCodecAdapter::onGetAndroidPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const&\29 +11195:SkAnalyticEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +11196:SkAnalyticEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +11197:SkAnalyticEdgeBuilder::addQuad\28SkPoint\20const*\29 +11198:SkAnalyticEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +11199:SkAnalyticEdgeBuilder::addLine\28SkPoint\20const*\29 +11200:SkAnalyticEdgeBuilder::addCubic\28SkPoint\20const*\29 +11201:SkAAClipBlitter::~SkAAClipBlitter\28\29_1214 +11202:SkAAClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11203:SkAAClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11204:SkAAClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11205:SkAAClipBlitter::blitH\28int\2c\20int\2c\20int\29 +11206:SkAAClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11207:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_1::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +11208:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_0::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +11209:SkAAClip::Builder::Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11210:SkAAClip::Builder::Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11211:SkAAClip::Builder::Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11212:SkAAClip::Builder::Blitter::blitH\28int\2c\20int\2c\20int\29 +11213:SkAAClip::Builder::Blitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11214:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29_1482 +11215:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29 +11216:SkA8_Coverage_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11217:SkA8_Coverage_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11218:SkA8_Coverage_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11219:SkA8_Coverage_Blitter::blitH\28int\2c\20int\2c\20int\29 +11220:SkA8_Coverage_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11221:SkA8_Blitter::~SkA8_Blitter\28\29_1484 +11222:SkA8_Blitter::~SkA8_Blitter\28\29 +11223:SkA8_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11224:SkA8_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11225:SkA8_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11226:SkA8_Blitter::blitH\28int\2c\20int\2c\20int\29 +11227:SkA8_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11228:SkA8Blitter_Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +11229:Sk2DPathEffect::nextSpan\28int\2c\20int\2c\20int\2c\20SkPath*\29\20const +11230:Sk2DPathEffect::flatten\28SkWriteBuffer&\29\20const +11231:SimpleVFilter16i_C +11232:SimpleVFilter16_C +11233:SimpleTextStyle*\20emscripten::internal::raw_constructor\28\29 +11234:SimpleTextStyle*\20emscripten::internal::MemberAccess::getWire\28SimpleTextStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\29 +11235:SimpleStrutStyle*\20emscripten::internal::raw_constructor\28\29 +11236:SimpleStrutStyle*\20emscripten::internal::MemberAccess::getWire\28SimpleStrutStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\29 +11237:SimpleParagraphStyle*\20emscripten::internal::raw_constructor\28\29 +11238:SimpleHFilter16i_C +11239:SimpleHFilter16_C +11240:SimpleFontStyle*\20emscripten::internal::raw_constructor\28\29 +11241:ShaderPDXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11242:ShaderPDXferProcessor::name\28\29\20const +11243:ShaderPDXferProcessor::makeProgramImpl\28\29\20const +11244:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11245:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11246:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11247:RuntimeEffectUniform*\20emscripten::internal::raw_constructor\28\29 +11248:RuntimeEffectRPCallbacks::toLinearSrgb\28void\20const*\29 +11249:RuntimeEffectRPCallbacks::fromLinearSrgb\28void\20const*\29 +11250:RuntimeEffectRPCallbacks::appendShader\28int\29 +11251:RuntimeEffectRPCallbacks::appendColorFilter\28int\29 +11252:RuntimeEffectRPCallbacks::appendBlender\28int\29 +11253:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29 +11254:RunBasedAdditiveBlitter::getRealBlitter\28bool\29 +11255:RunBasedAdditiveBlitter::flush_if_y_changed\28int\2c\20int\29 +11256:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11257:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11258:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11259:Round_Up_To_Grid +11260:Round_To_Half_Grid +11261:Round_To_Grid +11262:Round_To_Double_Grid +11263:Round_Super_45 +11264:Round_Super +11265:Round_None +11266:Round_Down_To_Grid +11267:RoundJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11268:RoundCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +11269:Reset +11270:Read_CVT_Stretched +11271:Read_CVT +11272:RD4_C +11273:Project_y +11274:Project +11275:ProcessRows +11276:PredictorAdd9_C +11277:PredictorAdd8_C +11278:PredictorAdd7_C +11279:PredictorAdd6_C +11280:PredictorAdd5_C +11281:PredictorAdd4_C +11282:PredictorAdd3_C +11283:PredictorAdd2_C +11284:PredictorAdd1_C +11285:PredictorAdd13_C +11286:PredictorAdd12_C +11287:PredictorAdd11_C +11288:PredictorAdd10_C +11289:PredictorAdd0_C +11290:PrePostInverseBlitterProc\28SkBlitter*\2c\20int\2c\20bool\29 +11291:PorterDuffXferProcessor::onHasSecondaryOutput\28\29\20const +11292:PorterDuffXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11293:PorterDuffXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11294:PorterDuffXferProcessor::name\28\29\20const +11295:PorterDuffXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11296:PorterDuffXferProcessor::makeProgramImpl\28\29\20const +11297:ParseVP8X +11298:PackRGB_C +11299:PDLCDXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +11300:PDLCDXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11301:PDLCDXferProcessor::name\28\29\20const +11302:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +11303:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11304:PDLCDXferProcessor::makeProgramImpl\28\29\20const +11305:OT::match_glyph\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11306:OT::match_coverage\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11307:OT::match_class_cached\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11308:OT::match_class_cached2\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11309:OT::match_class_cached1\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11310:OT::match_class\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11311:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GSUB_impl::SubstLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +11312:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GPOS_impl::PosLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +11313:OT::cff1::accelerator_t::gname_t::cmp\28void\20const*\2c\20void\20const*\29 +11314:OT::Layout::Common::RangeRecord::cmp_range\28void\20const*\2c\20void\20const*\29 +11315:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +11316:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +11317:OT::CmapSubtableFormat4::accelerator_t::get_glyph_func\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +11318:Move_CVT_Stretched +11319:Move_CVT +11320:MiterJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11321:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29_4031 +11322:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29 +11323:MaskAdditiveBlitter::getWidth\28\29 +11324:MaskAdditiveBlitter::getRealBlitter\28bool\29 +11325:MaskAdditiveBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11326:MaskAdditiveBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11327:MaskAdditiveBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11328:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11329:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11330:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11331:MapAlpha_C +11332:MapARGB_C +11333:MakeRenderTarget\28sk_sp\2c\20int\2c\20int\29 +11334:MakeRenderTarget\28sk_sp\2c\20SimpleImageInfo\29 +11335:MakePathFromVerbsPointsWeights\28unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +11336:MakePathFromSVGString\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11337:MakePathFromOp\28SkPath\20const&\2c\20SkPath\20const&\2c\20SkPathOp\29 +11338:MakePathFromInterpolation\28SkPath\20const&\2c\20SkPath\20const&\2c\20float\29 +11339:MakePathFromCmds\28unsigned\20long\2c\20int\29 +11340:MakeOnScreenGLSurface\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\29 +11341:MakeImageFromGenerator\28SimpleImageInfo\2c\20emscripten::val\29 +11342:MakeGrContext\28\29 +11343:MakeAsWinding\28SkPath\20const&\29 +11344:LD4_C +11345:JpegDecoderMgr::returnFailure\28char\20const*\2c\20SkCodec::Result\29 +11346:JpegDecoderMgr::init\28\29 +11347:JpegDecoderMgr::SourceMgr::SkipInputData\28jpeg_decompress_struct*\2c\20long\29 +11348:JpegDecoderMgr::SourceMgr::InitSource\28jpeg_decompress_struct*\29 +11349:JpegDecoderMgr::SourceMgr::FillInputBuffer\28jpeg_decompress_struct*\29 +11350:JpegDecoderMgr::JpegDecoderMgr\28SkStream*\29 +11351:IsValidSimpleFormat +11352:IsValidExtendedFormat +11353:InverseBlitter::blitH\28int\2c\20int\2c\20int\29 +11354:Init +11355:HorizontalUnfilter_C +11356:HorizontalFilter_C +11357:Horish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +11358:Horish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +11359:HasAlpha8b_C +11360:HasAlpha32b_C +11361:HU4_C +11362:HLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +11363:HLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +11364:HFilter8i_C +11365:HFilter8_C +11366:HFilter16i_C +11367:HFilter16_C +11368:HE8uv_C +11369:HE4_C +11370:HE16_C +11371:HD4_C +11372:GradientUnfilter_C +11373:GradientFilter_C +11374:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11375:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11376:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const +11377:GrYUVtoRGBEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11378:GrYUVtoRGBEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11379:GrYUVtoRGBEffect::name\28\29\20const +11380:GrYUVtoRGBEffect::clone\28\29\20const +11381:GrXferProcessor::ProgramImpl::emitWriteSwizzle\28GrGLSLXPFragmentBuilder*\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20char\20const*\29\20const +11382:GrXferProcessor::ProgramImpl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11383:GrXferProcessor::ProgramImpl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +11384:GrWritePixelsTask::~GrWritePixelsTask\28\29_9942 +11385:GrWritePixelsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +11386:GrWritePixelsTask::onExecute\28GrOpFlushState*\29 +11387:GrWritePixelsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11388:GrWaitRenderTask::~GrWaitRenderTask\28\29_9932 +11389:GrWaitRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +11390:GrWaitRenderTask::onExecute\28GrOpFlushState*\29 +11391:GrWaitRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11392:GrTriangulator::~GrTriangulator\28\29 +11393:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29_9922 +11394:GrTransferFromRenderTask::onExecute\28GrOpFlushState*\29 +11395:GrTransferFromRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11396:GrThreadSafeCache::Trampoline::~Trampoline\28\29_9908 +11397:GrThreadSafeCache::Trampoline::~Trampoline\28\29 +11398:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29_9875 +11399:GrTextureResolveRenderTask::onExecute\28GrOpFlushState*\29 +11400:GrTextureResolveRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11401:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9865 +11402:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +11403:GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +11404:GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +11405:GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +11406:GrTextureProxy::~GrTextureProxy\28\29_9819 +11407:GrTextureProxy::~GrTextureProxy\28\29_9817 +11408:GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +11409:GrTextureProxy::instantiate\28GrResourceProvider*\29 +11410:GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +11411:GrTextureProxy::callbackDesc\28\29\20const +11412:GrTextureEffect::~GrTextureEffect\28\29_10424 +11413:GrTextureEffect::~GrTextureEffect\28\29 +11414:GrTextureEffect::onMakeProgramImpl\28\29\20const +11415:GrTextureEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11416:GrTextureEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11417:GrTextureEffect::name\28\29\20const +11418:GrTextureEffect::clone\28\29\20const +11419:GrTextureEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11420:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11421:GrTexture::onGpuMemorySize\28\29\20const +11422:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29_8593 +11423:GrTDeferredProxyUploader>::freeData\28\29 +11424:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29_11608 +11425:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29 +11426:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::freeData\28\29 +11427:GrSurfaceProxy::getUniqueKey\28\29\20const +11428:GrSurface::~GrSurface\28\29 +11429:GrSurface::getResourceType\28\29\20const +11430:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29_11788 +11431:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29 +11432:GrStrokeTessellationShader::name\28\29\20const +11433:GrStrokeTessellationShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11434:GrStrokeTessellationShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11435:GrStrokeTessellationShader::Impl::~Impl\28\29_11791 +11436:GrStrokeTessellationShader::Impl::~Impl\28\29 +11437:GrStrokeTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11438:GrStrokeTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11439:GrSkSLFP::~GrSkSLFP\28\29_10380 +11440:GrSkSLFP::~GrSkSLFP\28\29 +11441:GrSkSLFP::onMakeProgramImpl\28\29\20const +11442:GrSkSLFP::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11443:GrSkSLFP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11444:GrSkSLFP::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11445:GrSkSLFP::clone\28\29\20const +11446:GrSkSLFP::Impl::~Impl\28\29_10389 +11447:GrSkSLFP::Impl::~Impl\28\29 +11448:GrSkSLFP::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11449:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11450:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11451:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11452:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11453:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::getMangledName\28char\20const*\29 +11454:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11455:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +11456:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +11457:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareFunction\28char\20const*\29 +11458:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11459:GrSimpleMesh*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29::'lambda'\28char*\29::__invoke\28char*\29 +11460:GrRingBuffer::FinishSubmit\28void*\29 +11461:GrResourceCache::CompareTimestamp\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29 +11462:GrRenderTask::~GrRenderTask\28\29 +11463:GrRenderTask::disown\28GrDrawingManager*\29 +11464:GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9586 +11465:GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +11466:GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +11467:GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +11468:GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +11469:GrRenderTargetProxy::callbackDesc\28\29\20const +11470:GrRecordingContext::~GrRecordingContext\28\29_9528 +11471:GrRecordingContext::abandoned\28\29 +11472:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29_10363 +11473:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29 +11474:GrRRectShadowGeoProc::onTextureSampler\28int\29\20const +11475:GrRRectShadowGeoProc::name\28\29\20const +11476:GrRRectShadowGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11477:GrRRectShadowGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11478:GrQuadEffect::name\28\29\20const +11479:GrQuadEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11480:GrQuadEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11481:GrQuadEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11482:GrQuadEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11483:GrPorterDuffXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11484:GrPorterDuffXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11485:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29_10300 +11486:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29 +11487:GrPerlinNoise2Effect::onMakeProgramImpl\28\29\20const +11488:GrPerlinNoise2Effect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11489:GrPerlinNoise2Effect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11490:GrPerlinNoise2Effect::name\28\29\20const +11491:GrPerlinNoise2Effect::clone\28\29\20const +11492:GrPerlinNoise2Effect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11493:GrPerlinNoise2Effect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11494:GrPathTessellationShader::Impl::~Impl\28\29 +11495:GrPathTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11496:GrPathTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11497:GrOpsRenderPass::~GrOpsRenderPass\28\29 +11498:GrOpsRenderPass::onExecuteDrawable\28std::__2::unique_ptr>\29 +11499:GrOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11500:GrOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11501:GrOpFlushState::~GrOpFlushState\28\29_9385 +11502:GrOpFlushState::~GrOpFlushState\28\29 +11503:GrOpFlushState::writeView\28\29\20const +11504:GrOpFlushState::usesMSAASurface\28\29\20const +11505:GrOpFlushState::tokenTracker\28\29 +11506:GrOpFlushState::threadSafeCache\28\29\20const +11507:GrOpFlushState::strikeCache\28\29\20const +11508:GrOpFlushState::smallPathAtlasManager\28\29\20const +11509:GrOpFlushState::sampledProxyArray\28\29 +11510:GrOpFlushState::rtProxy\28\29\20const +11511:GrOpFlushState::resourceProvider\28\29\20const +11512:GrOpFlushState::renderPassBarriers\28\29\20const +11513:GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +11514:GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +11515:GrOpFlushState::putBackIndirectDraws\28int\29 +11516:GrOpFlushState::putBackIndices\28int\29 +11517:GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +11518:GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +11519:GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +11520:GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +11521:GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +11522:GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +11523:GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +11524:GrOpFlushState::dstProxyView\28\29\20const +11525:GrOpFlushState::colorLoadOp\28\29\20const +11526:GrOpFlushState::atlasManager\28\29\20const +11527:GrOpFlushState::appliedClip\28\29\20const +11528:GrOpFlushState::addInlineUpload\28std::__2::function&\29>&&\29 +11529:GrOp::~GrOp\28\29 +11530:GrOnFlushCallbackObject::postFlush\28skgpu::AtlasToken\29 +11531:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11532:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11533:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const +11534:GrModulateAtlasCoverageEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11535:GrModulateAtlasCoverageEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11536:GrModulateAtlasCoverageEffect::name\28\29\20const +11537:GrModulateAtlasCoverageEffect::clone\28\29\20const +11538:GrMeshDrawOp::onPrepare\28GrOpFlushState*\29 +11539:GrMeshDrawOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11540:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11541:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11542:GrMatrixEffect::onMakeProgramImpl\28\29\20const +11543:GrMatrixEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11544:GrMatrixEffect::name\28\29\20const +11545:GrMatrixEffect::clone\28\29\20const +11546:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29_9987 +11547:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29 +11548:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::$_0::__invoke\28void\20const*\2c\20void*\29 +11549:GrImageContext::~GrImageContext\28\29_9319 +11550:GrImageContext::~GrImageContext\28\29 +11551:GrHardClip::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +11552:GrGpuResource::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +11553:GrGpuBuffer::~GrGpuBuffer\28\29 +11554:GrGpuBuffer::unref\28\29\20const +11555:GrGpuBuffer::getResourceType\28\29\20const +11556:GrGpuBuffer::computeScratchKey\28skgpu::ScratchKey*\29\20const +11557:GrGpu::endTimerQuery\28GrTimerQuery\20const&\29 +11558:GrGeometryProcessor::onTextureSampler\28int\29\20const +11559:GrGeometryProcessor::ProgramImpl::~ProgramImpl\28\29 +11560:GrGLVaryingHandler::~GrGLVaryingHandler\28\29 +11561:GrGLUniformHandler::~GrGLUniformHandler\28\29_12346 +11562:GrGLUniformHandler::~GrGLUniformHandler\28\29 +11563:GrGLUniformHandler::samplerVariable\28GrResourceHandle\29\20const +11564:GrGLUniformHandler::samplerSwizzle\28GrResourceHandle\29\20const +11565:GrGLUniformHandler::internalAddUniformArray\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20bool\2c\20int\2c\20char\20const**\29 +11566:GrGLUniformHandler::getUniformCStr\28GrResourceHandle\29\20const +11567:GrGLUniformHandler::appendUniformDecls\28GrShaderFlags\2c\20SkString*\29\20const +11568:GrGLUniformHandler::addSampler\28GrBackendFormat\20const&\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20GrShaderCaps\20const*\29 +11569:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +11570:GrGLTextureRenderTarget::onSetLabel\28\29 +11571:GrGLTextureRenderTarget::onRelease\28\29 +11572:GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +11573:GrGLTextureRenderTarget::onAbandon\28\29 +11574:GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +11575:GrGLTextureRenderTarget::backendFormat\28\29\20const +11576:GrGLTexture::~GrGLTexture\28\29_12295 +11577:GrGLTexture::~GrGLTexture\28\29 +11578:GrGLTexture::textureParamsModified\28\29 +11579:GrGLTexture::onStealBackendTexture\28GrBackendTexture*\2c\20std::__2::function*\29 +11580:GrGLTexture::getBackendTexture\28\29\20const +11581:GrGLSemaphore::~GrGLSemaphore\28\29_12272 +11582:GrGLSemaphore::~GrGLSemaphore\28\29 +11583:GrGLSemaphore::setIsOwned\28\29 +11584:GrGLSemaphore::backendSemaphore\28\29\20const +11585:GrGLSLVertexBuilder::~GrGLSLVertexBuilder\28\29 +11586:GrGLSLVertexBuilder::onFinalize\28\29 +11587:GrGLSLUniformHandler::inputSamplerSwizzle\28GrResourceHandle\29\20const +11588:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10608 +11589:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +11590:GrGLSLFragmentShaderBuilder::primaryColorOutputIsInOut\28\29\20const +11591:GrGLSLFragmentShaderBuilder::onFinalize\28\29 +11592:GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +11593:GrGLSLFragmentShaderBuilder::forceHighPrecision\28\29 +11594:GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +11595:GrGLRenderTarget::~GrGLRenderTarget\28\29_12267 +11596:GrGLRenderTarget::~GrGLRenderTarget\28\29 +11597:GrGLRenderTarget::onGpuMemorySize\28\29\20const +11598:GrGLRenderTarget::getBackendRenderTarget\28\29\20const +11599:GrGLRenderTarget::completeStencilAttachment\28GrAttachment*\2c\20bool\29 +11600:GrGLRenderTarget::canAttemptStencilAttachment\28bool\29\20const +11601:GrGLRenderTarget::backendFormat\28\29\20const +11602:GrGLRenderTarget::alwaysClearStencil\28\29\20const +11603:GrGLProgramDataManager::~GrGLProgramDataManager\28\29_12243 +11604:GrGLProgramDataManager::~GrGLProgramDataManager\28\29 +11605:GrGLProgramDataManager::setMatrix4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11606:GrGLProgramDataManager::setMatrix4f\28GrResourceHandle\2c\20float\20const*\29\20const +11607:GrGLProgramDataManager::setMatrix3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11608:GrGLProgramDataManager::setMatrix3f\28GrResourceHandle\2c\20float\20const*\29\20const +11609:GrGLProgramDataManager::setMatrix2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11610:GrGLProgramDataManager::setMatrix2f\28GrResourceHandle\2c\20float\20const*\29\20const +11611:GrGLProgramDataManager::set4iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11612:GrGLProgramDataManager::set4i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\2c\20int\29\20const +11613:GrGLProgramDataManager::set4f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\2c\20float\29\20const +11614:GrGLProgramDataManager::set3iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11615:GrGLProgramDataManager::set3i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\29\20const +11616:GrGLProgramDataManager::set3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11617:GrGLProgramDataManager::set3f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\29\20const +11618:GrGLProgramDataManager::set2iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11619:GrGLProgramDataManager::set2i\28GrResourceHandle\2c\20int\2c\20int\29\20const +11620:GrGLProgramDataManager::set2f\28GrResourceHandle\2c\20float\2c\20float\29\20const +11621:GrGLProgramDataManager::set1iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11622:GrGLProgramDataManager::set1i\28GrResourceHandle\2c\20int\29\20const +11623:GrGLProgramDataManager::set1fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11624:GrGLProgramDataManager::set1f\28GrResourceHandle\2c\20float\29\20const +11625:GrGLProgramBuilder::~GrGLProgramBuilder\28\29_12381 +11626:GrGLProgramBuilder::varyingHandler\28\29 +11627:GrGLProgramBuilder::caps\28\29\20const +11628:GrGLProgram::~GrGLProgram\28\29_12201 +11629:GrGLOpsRenderPass::~GrGLOpsRenderPass\28\29 +11630:GrGLOpsRenderPass::onSetScissorRect\28SkIRect\20const&\29 +11631:GrGLOpsRenderPass::onEnd\28\29 +11632:GrGLOpsRenderPass::onDraw\28int\2c\20int\29 +11633:GrGLOpsRenderPass::onDrawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +11634:GrGLOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11635:GrGLOpsRenderPass::onDrawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +11636:GrGLOpsRenderPass::onDrawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +11637:GrGLOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11638:GrGLOpsRenderPass::onClear\28GrScissorState\20const&\2c\20std::__2::array\29 +11639:GrGLOpsRenderPass::onClearStencilClip\28GrScissorState\20const&\2c\20bool\29 +11640:GrGLOpsRenderPass::onBindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +11641:GrGLOpsRenderPass::onBindPipeline\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +11642:GrGLOpsRenderPass::onBindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +11643:GrGLOpsRenderPass::onBegin\28\29 +11644:GrGLOpsRenderPass::inlineUpload\28GrOpFlushState*\2c\20std::__2::function&\29>&\29 +11645:GrGLInterface::~GrGLInterface\28\29_12178 +11646:GrGLInterface::~GrGLInterface\28\29 +11647:GrGLGpu::~GrGLGpu\28\29_12048 +11648:GrGLGpu::xferBarrier\28GrRenderTarget*\2c\20GrXferBarrierType\29 +11649:GrGLGpu::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +11650:GrGLGpu::willExecute\28\29 +11651:GrGLGpu::waitSemaphore\28GrSemaphore*\29 +11652:GrGLGpu::submit\28GrOpsRenderPass*\29 +11653:GrGLGpu::startTimerQuery\28\29 +11654:GrGLGpu::stagingBufferManager\28\29 +11655:GrGLGpu::refPipelineBuilder\28\29 +11656:GrGLGpu::prepareTextureForCrossContextUsage\28GrTexture*\29 +11657:GrGLGpu::precompileShader\28SkData\20const&\2c\20SkData\20const&\29 +11658:GrGLGpu::pipelineBuilder\28\29 +11659:GrGLGpu::onWritePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +11660:GrGLGpu::onWrapRenderableBackendTexture\28GrBackendTexture\20const&\2c\20int\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +11661:GrGLGpu::onWrapCompressedBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +11662:GrGLGpu::onWrapBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\2c\20GrIOType\29 +11663:GrGLGpu::onWrapBackendRenderTarget\28GrBackendRenderTarget\20const&\29 +11664:GrGLGpu::onUpdateCompressedBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20void\20const*\2c\20unsigned\20long\29 +11665:GrGLGpu::onTransferPixelsTo\28GrTexture*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +11666:GrGLGpu::onTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\29 +11667:GrGLGpu::onTransferFromBufferToBuffer\28sk_sp\2c\20unsigned\20long\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +11668:GrGLGpu::onSubmitToGpu\28GrSubmitInfo\20const&\29 +11669:GrGLGpu::onResolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +11670:GrGLGpu::onResetTextureBindings\28\29 +11671:GrGLGpu::onResetContext\28unsigned\20int\29 +11672:GrGLGpu::onRegenerateMipMapLevels\28GrTexture*\29 +11673:GrGLGpu::onReadPixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20unsigned\20long\29 +11674:GrGLGpu::onGetOpsRenderPass\28GrRenderTarget*\2c\20bool\2c\20GrAttachment*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const&\2c\20GrOpsRenderPass::LoadAndStoreInfo\20const&\2c\20GrOpsRenderPass::StencilLoadAndStoreInfo\20const&\2c\20skia_private::TArray\20const&\2c\20GrXferBarrierFlags\29 +11675:GrGLGpu::onDumpJSON\28SkJSONWriter*\29\20const +11676:GrGLGpu::onCreateTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +11677:GrGLGpu::onCreateCompressedTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20void\20const*\2c\20unsigned\20long\29 +11678:GrGLGpu::onCreateCompressedBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\29 +11679:GrGLGpu::onCreateBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +11680:GrGLGpu::onCreateBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +11681:GrGLGpu::onCopySurface\28GrSurface*\2c\20SkIRect\20const&\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +11682:GrGLGpu::onClearBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20std::__2::array\29 +11683:GrGLGpu::makeStencilAttachment\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\29 +11684:GrGLGpu::makeSemaphore\28bool\29 +11685:GrGLGpu::makeMSAAAttachment\28SkISize\2c\20GrBackendFormat\20const&\2c\20int\2c\20skgpu::Protected\2c\20GrMemoryless\29 +11686:GrGLGpu::insertSemaphore\28GrSemaphore*\29 +11687:GrGLGpu::getPreferredStencilFormat\28GrBackendFormat\20const&\29 +11688:GrGLGpu::finishOutstandingGpuWork\28\29 +11689:GrGLGpu::endTimerQuery\28GrTimerQuery\20const&\29 +11690:GrGLGpu::disconnect\28GrGpu::DisconnectType\29 +11691:GrGLGpu::deleteBackendTexture\28GrBackendTexture\20const&\29 +11692:GrGLGpu::compile\28GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\29 +11693:GrGLGpu::checkFinishedCallbacks\28\29 +11694:GrGLGpu::addFinishedCallback\28skgpu::AutoCallback\2c\20std::__2::optional\29 +11695:GrGLGpu::ProgramCache::~ProgramCache\28\29_12159 +11696:GrGLGpu::ProgramCache::~ProgramCache\28\29 +11697:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20unsigned\20int\2c\20float\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29 +11698:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29 +11699:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29 +11700:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\29\29::'lambda'\28void\20const*\2c\20float\29::__invoke\28void\20const*\2c\20float\29 +11701:GrGLFunction::GrGLFunction\28void\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +11702:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28__GLsync*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29 +11703:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +11704:GrGLCaps::~GrGLCaps\28\29_12015 +11705:GrGLCaps::surfaceSupportsReadPixels\28GrSurface\20const*\29\20const +11706:GrGLCaps::supportedWritePixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +11707:GrGLCaps::onSurfaceSupportsWritePixels\28GrSurface\20const*\29\20const +11708:GrGLCaps::onSupportsDynamicMSAA\28GrRenderTargetProxy\20const*\29\20const +11709:GrGLCaps::onSupportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +11710:GrGLCaps::onIsWindowRectanglesSupportedForRT\28GrBackendRenderTarget\20const&\29\20const +11711:GrGLCaps::onGetReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +11712:GrGLCaps::onGetDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\29\20const +11713:GrGLCaps::onGetDefaultBackendFormat\28GrColorType\29\20const +11714:GrGLCaps::onDumpJSON\28SkJSONWriter*\29\20const +11715:GrGLCaps::onCanCopySurface\28GrSurfaceProxy\20const*\2c\20SkIRect\20const&\2c\20GrSurfaceProxy\20const*\2c\20SkIRect\20const&\29\20const +11716:GrGLCaps::onAreColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +11717:GrGLCaps::onApplyOptionsOverrides\28GrContextOptions\20const&\29 +11718:GrGLCaps::maxRenderTargetSampleCount\28GrBackendFormat\20const&\29\20const +11719:GrGLCaps::makeDesc\28GrRenderTarget*\2c\20GrProgramInfo\20const&\2c\20GrCaps::ProgramDescOverrideFlags\29\20const +11720:GrGLCaps::isFormatTexturable\28GrBackendFormat\20const&\2c\20GrTextureType\29\20const +11721:GrGLCaps::isFormatSRGB\28GrBackendFormat\20const&\29\20const +11722:GrGLCaps::isFormatRenderable\28GrBackendFormat\20const&\2c\20int\29\20const +11723:GrGLCaps::isFormatCopyable\28GrBackendFormat\20const&\29\20const +11724:GrGLCaps::isFormatAsColorTypeRenderable\28GrColorType\2c\20GrBackendFormat\20const&\2c\20int\29\20const +11725:GrGLCaps::getWriteSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +11726:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrBackendFormat\20const&\29\20const +11727:GrGLCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +11728:GrGLCaps::getBackendFormatFromCompressionType\28SkTextureCompressionType\29\20const +11729:GrGLCaps::computeFormatKey\28GrBackendFormat\20const&\29\20const +11730:GrGLBuffer::~GrGLBuffer\28\29_11965 +11731:GrGLBuffer::~GrGLBuffer\28\29 +11732:GrGLBuffer::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +11733:GrGLBuffer::onUpdateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +11734:GrGLBuffer::onUnmap\28GrGpuBuffer::MapType\29 +11735:GrGLBuffer::onSetLabel\28\29 +11736:GrGLBuffer::onRelease\28\29 +11737:GrGLBuffer::onMap\28GrGpuBuffer::MapType\29 +11738:GrGLBuffer::onClearToZero\28\29 +11739:GrGLBuffer::onAbandon\28\29 +11740:GrGLBackendTextureData::~GrGLBackendTextureData\28\29_11939 +11741:GrGLBackendTextureData::~GrGLBackendTextureData\28\29 +11742:GrGLBackendTextureData::isSameTexture\28GrBackendTextureData\20const*\29\20const +11743:GrGLBackendTextureData::isProtected\28\29\20const +11744:GrGLBackendTextureData::getBackendFormat\28\29\20const +11745:GrGLBackendTextureData::equal\28GrBackendTextureData\20const*\29\20const +11746:GrGLBackendTextureData::copyTo\28SkAnySubclass&\29\20const +11747:GrGLBackendRenderTargetData::getBackendFormat\28\29\20const +11748:GrGLBackendRenderTargetData::equal\28GrBackendRenderTargetData\20const*\29\20const +11749:GrGLBackendRenderTargetData::copyTo\28SkAnySubclass&\29\20const +11750:GrGLBackendFormatData::toString\28\29\20const +11751:GrGLBackendFormatData::stencilBits\28\29\20const +11752:GrGLBackendFormatData::equal\28GrBackendFormatData\20const*\29\20const +11753:GrGLBackendFormatData::desc\28\29\20const +11754:GrGLBackendFormatData::copyTo\28SkAnySubclass&\29\20const +11755:GrGLBackendFormatData::compressionType\28\29\20const +11756:GrGLBackendFormatData::channelMask\28\29\20const +11757:GrGLBackendFormatData::bytesPerBlock\28\29\20const +11758:GrGLAttachment::~GrGLAttachment\28\29 +11759:GrGLAttachment::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +11760:GrGLAttachment::onSetLabel\28\29 +11761:GrGLAttachment::onRelease\28\29 +11762:GrGLAttachment::onAbandon\28\29 +11763:GrGLAttachment::backendFormat\28\29\20const +11764:GrFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11765:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11766:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const +11767:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11768:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11769:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::name\28\29\20const +11770:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11771:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::clone\28\29\20const +11772:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11773:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const +11774:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::name\28\29\20const +11775:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::clone\28\29\20const +11776:GrFragmentProcessor::ProgramImpl::~ProgramImpl\28\29 +11777:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11778:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const +11779:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::name\28\29\20const +11780:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::clone\28\29\20const +11781:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11782:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const +11783:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::name\28\29\20const +11784:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11785:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::clone\28\29\20const +11786:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11787:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const +11788:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::name\28\29\20const +11789:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11790:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::clone\28\29\20const +11791:GrFixedClip::~GrFixedClip\28\29_9094 +11792:GrFixedClip::~GrFixedClip\28\29 +11793:GrExternalTextureGenerator::onGenerateTexture\28GrRecordingContext*\2c\20SkImageInfo\20const&\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +11794:GrEagerDynamicVertexAllocator::lock\28unsigned\20long\2c\20int\29 +11795:GrDynamicAtlas::~GrDynamicAtlas\28\29_9065 +11796:GrDynamicAtlas::~GrDynamicAtlas\28\29 +11797:GrDrawOp::usesStencil\28\29\20const +11798:GrDrawOp::usesMSAA\28\29\20const +11799:GrDrawOp::fixedFunctionFlags\28\29\20const +11800:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29_10256 +11801:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29 +11802:GrDistanceFieldPathGeoProc::onTextureSampler\28int\29\20const +11803:GrDistanceFieldPathGeoProc::name\28\29\20const +11804:GrDistanceFieldPathGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11805:GrDistanceFieldPathGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11806:GrDistanceFieldPathGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11807:GrDistanceFieldPathGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11808:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29_10260 +11809:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29 +11810:GrDistanceFieldLCDTextGeoProc::name\28\29\20const +11811:GrDistanceFieldLCDTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11812:GrDistanceFieldLCDTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11813:GrDistanceFieldLCDTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11814:GrDistanceFieldLCDTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11815:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29_10252 +11816:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29 +11817:GrDistanceFieldA8TextGeoProc::name\28\29\20const +11818:GrDistanceFieldA8TextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11819:GrDistanceFieldA8TextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11820:GrDistanceFieldA8TextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11821:GrDistanceFieldA8TextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11822:GrDisableColorXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11823:GrDisableColorXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11824:GrDirectContext::~GrDirectContext\28\29_8966 +11825:GrDirectContext::releaseResourcesAndAbandonContext\28\29 +11826:GrDirectContext::init\28\29 +11827:GrDirectContext::abandoned\28\29 +11828:GrDirectContext::abandonContext\28\29 +11829:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29_8596 +11830:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29 +11831:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29_9089 +11832:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29 +11833:GrCpuVertexAllocator::unlock\28int\29 +11834:GrCpuVertexAllocator::lock\28unsigned\20long\2c\20int\29 +11835:GrCpuBuffer::unref\28\29\20const +11836:GrCoverageSetOpXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11837:GrCoverageSetOpXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11838:GrCopyRenderTask::~GrCopyRenderTask\28\29_8926 +11839:GrCopyRenderTask::onMakeSkippable\28\29 +11840:GrCopyRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +11841:GrCopyRenderTask::onExecute\28GrOpFlushState*\29 +11842:GrCopyRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11843:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11844:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11845:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const +11846:GrConvexPolyEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11847:GrConvexPolyEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11848:GrConvexPolyEffect::name\28\29\20const +11849:GrConvexPolyEffect::clone\28\29\20const +11850:GrContext_Base::~GrContext_Base\28\29_8906 +11851:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29_8894 +11852:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29 +11853:GrContextThreadSafeProxy::isValidCharacterizationForVulkan\28sk_sp\2c\20bool\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20bool\2c\20bool\29 +11854:GrConicEffect::name\28\29\20const +11855:GrConicEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11856:GrConicEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11857:GrConicEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11858:GrConicEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11859:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29_8878 +11860:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29 +11861:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11862:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11863:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const +11864:GrColorSpaceXformEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11865:GrColorSpaceXformEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11866:GrColorSpaceXformEffect::name\28\29\20const +11867:GrColorSpaceXformEffect::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11868:GrColorSpaceXformEffect::clone\28\29\20const +11869:GrCaps::~GrCaps\28\29 +11870:GrCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +11871:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29_10165 +11872:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29 +11873:GrBitmapTextGeoProc::onTextureSampler\28int\29\20const +11874:GrBitmapTextGeoProc::name\28\29\20const +11875:GrBitmapTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11876:GrBitmapTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11877:GrBitmapTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11878:GrBitmapTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11879:GrBicubicEffect::onMakeProgramImpl\28\29\20const +11880:GrBicubicEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11881:GrBicubicEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11882:GrBicubicEffect::name\28\29\20const +11883:GrBicubicEffect::clone\28\29\20const +11884:GrBicubicEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11885:GrBicubicEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11886:GrAttachment::onGpuMemorySize\28\29\20const +11887:GrAttachment::getResourceType\28\29\20const +11888:GrAttachment::computeScratchKey\28skgpu::ScratchKey*\29\20const +11889:GrAtlasManager::~GrAtlasManager\28\29_11820 +11890:GrAtlasManager::preFlush\28GrOnFlushResourceProvider*\29 +11891:GrAtlasManager::postFlush\28skgpu::AtlasToken\29 +11892:GrAATriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +11893:GetRectsForRange\28skia::textlayout::Paragraph&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +11894:GetRectsForPlaceholders\28skia::textlayout::Paragraph&\29 +11895:GetLineMetrics\28skia::textlayout::Paragraph&\29 +11896:GetLineMetricsAt\28skia::textlayout::Paragraph&\2c\20unsigned\20long\29 +11897:GetGlyphInfoAt\28skia::textlayout::Paragraph&\2c\20unsigned\20long\29 +11898:GetCoeffsFast +11899:GetCoeffsAlt +11900:GetClosestGlyphInfoAtCoordinate\28skia::textlayout::Paragraph&\2c\20float\2c\20float\29 +11901:FontMgrRunIterator::~FontMgrRunIterator\28\29_14853 +11902:FontMgrRunIterator::~FontMgrRunIterator\28\29 +11903:FontMgrRunIterator::currentFont\28\29\20const +11904:FontMgrRunIterator::consume\28\29 +11905:ExtractGreen_C +11906:ExtractAlpha_C +11907:ExtractAlphaRows +11908:ExternalWebGLTexture::~ExternalWebGLTexture\28\29_904 +11909:ExternalWebGLTexture::~ExternalWebGLTexture\28\29 +11910:ExternalWebGLTexture::getBackendTexture\28\29 +11911:ExternalWebGLTexture::dispose\28\29 +11912:ExportAlphaRGBA4444 +11913:ExportAlpha +11914:Equals\28SkPath\20const&\2c\20SkPath\20const&\29 +11915:EmitYUV +11916:EmitSampledRGB +11917:EmitRescaledYUV +11918:EmitRescaledRGB +11919:EmitRescaledAlphaYUV +11920:EmitRescaledAlphaRGB +11921:EmitFancyRGB +11922:EmitAlphaYUV +11923:EmitAlphaRGBA4444 +11924:EmitAlphaRGB +11925:EllipticalRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11926:EllipticalRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11927:EllipticalRRectOp::name\28\29\20const +11928:EllipticalRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11929:EllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11930:EllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11931:EllipseOp::name\28\29\20const +11932:EllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11933:EllipseGeometryProcessor::name\28\29\20const +11934:EllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11935:EllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11936:EllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11937:Dual_Project +11938:DitherCombine8x8_C +11939:DispatchAlpha_C +11940:DispatchAlphaToGreen_C +11941:DisableColorXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11942:DisableColorXP::name\28\29\20const +11943:DisableColorXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11944:DisableColorXP::makeProgramImpl\28\29\20const +11945:Direct_Move_Y +11946:Direct_Move_X +11947:Direct_Move_Orig_Y +11948:Direct_Move_Orig_X +11949:Direct_Move_Orig +11950:Direct_Move +11951:DefaultGeoProc::name\28\29\20const +11952:DefaultGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11953:DefaultGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11954:DefaultGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11955:DefaultGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11956:DataFontLoader::loadSystemFonts\28SkFontScanner\20const*\2c\20skia_private::TArray\2c\20true>*\29\20const +11957:DataCacheElement_deleter\28void*\29 +11958:DIEllipseOp::~DIEllipseOp\28\29_11323 +11959:DIEllipseOp::~DIEllipseOp\28\29 +11960:DIEllipseOp::visitProxies\28std::__2::function\20const&\29\20const +11961:DIEllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11962:DIEllipseOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +11963:DIEllipseOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11964:DIEllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11965:DIEllipseOp::name\28\29\20const +11966:DIEllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11967:DIEllipseGeometryProcessor::name\28\29\20const +11968:DIEllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11969:DIEllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11970:DIEllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11971:DC8uv_C +11972:DC8uvNoTop_C +11973:DC8uvNoTopLeft_C +11974:DC8uvNoLeft_C +11975:DC4_C +11976:DC16_C +11977:DC16NoTop_C +11978:DC16NoTopLeft_C +11979:DC16NoLeft_C +11980:CustomXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11981:CustomXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11982:CustomXP::xferBarrierType\28GrCaps\20const&\29\20const +11983:CustomXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11984:CustomXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11985:CustomXP::name\28\29\20const +11986:CustomXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11987:CustomXP::makeProgramImpl\28\29\20const +11988:CustomTeardown +11989:CustomSetup +11990:CustomPut +11991:Current_Ppem_Stretched +11992:Current_Ppem +11993:Cr_z_zcalloc +11994:CoverageSetOpXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11995:CoverageSetOpXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11996:CoverageSetOpXP::name\28\29\20const +11997:CoverageSetOpXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11998:CoverageSetOpXP::makeProgramImpl\28\29\20const +11999:CopyPath\28SkPath\20const&\29 +12000:ConvertRGB24ToY_C +12001:ConvertBGR24ToY_C +12002:ConvertARGBToY_C +12003:ColorTableEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +12004:ColorTableEffect::onMakeProgramImpl\28\29\20const +12005:ColorTableEffect::name\28\29\20const +12006:ColorTableEffect::clone\28\29\20const +12007:CircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +12008:CircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12009:CircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12010:CircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12011:CircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12012:CircularRRectOp::name\28\29\20const +12013:CircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12014:CircleOp::~CircleOp\28\29_11297 +12015:CircleOp::~CircleOp\28\29 +12016:CircleOp::visitProxies\28std::__2::function\20const&\29\20const +12017:CircleOp::programInfo\28\29 +12018:CircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12019:CircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12020:CircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12021:CircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12022:CircleOp::name\28\29\20const +12023:CircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12024:CircleGeometryProcessor::name\28\29\20const +12025:CircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12026:CircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12027:CircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12028:CanInterpolate\28SkPath\20const&\2c\20SkPath\20const&\29 +12029:ButtCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +12030:ButtCapDashedCircleOp::visitProxies\28std::__2::function\20const&\29\20const +12031:ButtCapDashedCircleOp::programInfo\28\29 +12032:ButtCapDashedCircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12033:ButtCapDashedCircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12034:ButtCapDashedCircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12035:ButtCapDashedCircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12036:ButtCapDashedCircleOp::name\28\29\20const +12037:ButtCapDashedCircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12038:ButtCapDashedCircleGeometryProcessor::name\28\29\20const +12039:ButtCapDashedCircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12040:ButtCapDashedCircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12041:ButtCapDashedCircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12042:BrotliDefaultAllocFunc +12043:BluntJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +12044:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +12045:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +12046:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const +12047:BlendFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +12048:BlendFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12049:BlendFragmentProcessor::name\28\29\20const +12050:BlendFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +12051:BlendFragmentProcessor::clone\28\29\20const +12052:AutoCleanPng::infoCallback\28unsigned\20long\29 +12053:AutoCleanPng::decodeBounds\28\29 +12054:ApplyTrim\28SkPath&\2c\20float\2c\20float\2c\20bool\29 +12055:ApplyTransform\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +12056:ApplyStroke\28SkPath&\2c\20StrokeOpts\29 +12057:ApplySimplify\28SkPath&\29 +12058:ApplyRewind\28SkPath&\29 +12059:ApplyReset\28SkPath&\29 +12060:ApplyRQuadTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\29 +12061:ApplyRMoveTo\28SkPath&\2c\20float\2c\20float\29 +12062:ApplyRLineTo\28SkPath&\2c\20float\2c\20float\29 +12063:ApplyRCubicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +12064:ApplyRConicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +12065:ApplyRArcToArcSize\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29 +12066:ApplyQuadTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\29 +12067:ApplyPathOp\28SkPath&\2c\20SkPath\20const&\2c\20SkPathOp\29 +12068:ApplyMoveTo\28SkPath&\2c\20float\2c\20float\29 +12069:ApplyLineTo\28SkPath&\2c\20float\2c\20float\29 +12070:ApplyDash\28SkPath&\2c\20float\2c\20float\2c\20float\29 +12071:ApplyCubicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +12072:ApplyConicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +12073:ApplyClose\28SkPath&\29 +12074:ApplyArcToTangent\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +12075:ApplyArcToArcSize\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29 +12076:ApplyAlphaMultiply_C +12077:ApplyAlphaMultiply_16b_C +12078:ApplyAddPath\28SkPath&\2c\20SkPath\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +12079:AlphaReplace_C +12080:$_3::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +12081:$_2::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 +12082:$_1::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +12083:$_0::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/canvaskit.wasm b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/canvaskit.wasm new file mode 100644 index 0000000000..efb875788e Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/canvaskit.wasm differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/chromium/canvaskit.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/chromium/canvaskit.js new file mode 100644 index 0000000000..681234db52 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/chromium/canvaskit.js @@ -0,0 +1,192 @@ + +var CanvasKitInit = (() => { + var _scriptName = import.meta.url; + + return ( +function(moduleArg = {}) { + var moduleRtn; + +var r=moduleArg,ba,ca,da=new Promise((a,b)=>{ba=a;ca=b}),fa="object"==typeof window,ia="function"==typeof importScripts; +(function(a){a.Xd=a.Xd||[];a.Xd.push(function(){a.MakeSWCanvasSurface=function(b){var c=b,e="undefined"!==typeof OffscreenCanvas&&c instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&c instanceof HTMLCanvasElement||e||(c=document.getElementById(b),c)))throw"Canvas with id "+b+" was not found";if(b=a.MakeSurface(c.width,c.height))b.ue=c;return b};a.MakeCanvasSurface||(a.MakeCanvasSurface=a.MakeSWCanvasSurface);a.MakeSurface=function(b,c){var e={width:b,height:c,colorType:a.ColorType.RGBA_8888, +alphaType:a.AlphaType.Unpremul,colorSpace:a.ColorSpace.SRGB},f=b*c*4,k=a._malloc(f);if(e=a.Surface._makeRasterDirect(e,k,4*b))e.ue=null,e.Ue=b,e.Re=c,e.Se=f,e.Be=k,e.getCanvas().clear(a.TRANSPARENT);return e};a.MakeRasterDirectSurface=function(b,c,e){return a.Surface._makeRasterDirect(b,c.byteOffset,e)};a.Surface.prototype.flush=function(b){a.Ud(this.Td);this._flush();if(this.ue){var c=new Uint8ClampedArray(a.HEAPU8.buffer,this.Be,this.Se);c=new ImageData(c,this.Ue,this.Re);b?this.ue.getContext("2d").putImageData(c, +0,0,b[0],b[1],b[2]-b[0],b[3]-b[1]):this.ue.getContext("2d").putImageData(c,0,0)}};a.Surface.prototype.dispose=function(){this.Be&&a._free(this.Be);this.delete()};a.Ud=a.Ud||function(){};a.ve=a.ve||function(){return null}})})(r); +(function(a){a.Xd=a.Xd||[];a.Xd.push(function(){function b(l,q,v){return l&&l.hasOwnProperty(q)?l[q]:v}function c(l){var q=ja(ka);ka[q]=l;return q}function e(l){return l.naturalHeight||l.videoHeight||l.displayHeight||l.height}function f(l){return l.naturalWidth||l.videoWidth||l.displayWidth||l.width}function k(l,q,v,w){l.bindTexture(l.TEXTURE_2D,q);w||v.alphaType!==a.AlphaType.Premul||l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);return q}function n(l,q,v){v||q.alphaType!==a.AlphaType.Premul|| +l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);l.bindTexture(l.TEXTURE_2D,null)}a.GetWebGLContext=function(l,q){if(!l)throw"null canvas passed into makeWebGLContext";var v={alpha:b(q,"alpha",1),depth:b(q,"depth",1),stencil:b(q,"stencil",8),antialias:b(q,"antialias",0),premultipliedAlpha:b(q,"premultipliedAlpha",1),preserveDrawingBuffer:b(q,"preserveDrawingBuffer",0),preferLowPowerToHighPerformance:b(q,"preferLowPowerToHighPerformance",0),failIfMajorPerformanceCaveat:b(q,"failIfMajorPerformanceCaveat", +0),enableExtensionsByDefault:b(q,"enableExtensionsByDefault",1),explicitSwapControl:b(q,"explicitSwapControl",0),renderViaOffscreenBackBuffer:b(q,"renderViaOffscreenBackBuffer",0)};v.majorVersion=q&&q.majorVersion?q.majorVersion:"undefined"!==typeof WebGL2RenderingContext?2:1;if(v.explicitSwapControl)throw"explicitSwapControl is not supported";l=na(l,v);if(!l)return 0;oa(l);z.fe.getExtension("WEBGL_debug_renderer_info");return l};a.deleteContext=function(l){z===pa[l]&&(z=null);"object"==typeof JSEvents&& +JSEvents.uf(pa[l].fe.canvas);pa[l]&&pa[l].fe.canvas&&(pa[l].fe.canvas.Pe=void 0);pa[l]=null};a._setTextureCleanup({deleteTexture:function(l,q){var v=ka[q];v&&pa[l].fe.deleteTexture(v);ka[q]=null}});a.MakeWebGLContext=function(l){if(!this.Ud(l))return null;var q=this._MakeGrContext();if(!q)return null;q.Td=l;var v=q.delete.bind(q);q["delete"]=function(){a.Ud(this.Td);v()}.bind(q);return z.De=q};a.MakeGrContext=a.MakeWebGLContext;a.GrDirectContext.prototype.getResourceCacheLimitBytes=function(){a.Ud(this.Td); +this._getResourceCacheLimitBytes()};a.GrDirectContext.prototype.getResourceCacheUsageBytes=function(){a.Ud(this.Td);this._getResourceCacheUsageBytes()};a.GrDirectContext.prototype.releaseResourcesAndAbandonContext=function(){a.Ud(this.Td);this._releaseResourcesAndAbandonContext()};a.GrDirectContext.prototype.setResourceCacheLimitBytes=function(l){a.Ud(this.Td);this._setResourceCacheLimitBytes(l)};a.MakeOnScreenGLSurface=function(l,q,v,w,A,D){if(!this.Ud(l.Td))return null;q=void 0===A||void 0===D? +this._MakeOnScreenGLSurface(l,q,v,w):this._MakeOnScreenGLSurface(l,q,v,w,A,D);if(!q)return null;q.Td=l.Td;return q};a.MakeRenderTarget=function(){var l=arguments[0];if(!this.Ud(l.Td))return null;if(3===arguments.length){var q=this._MakeRenderTargetWH(l,arguments[1],arguments[2]);if(!q)return null}else if(2===arguments.length){if(q=this._MakeRenderTargetII(l,arguments[1]),!q)return null}else return null;q.Td=l.Td;return q};a.MakeWebGLCanvasSurface=function(l,q,v){q=q||null;var w=l,A="undefined"!== +typeof OffscreenCanvas&&w instanceof OffscreenCanvas;if(!("undefined"!==typeof HTMLCanvasElement&&w instanceof HTMLCanvasElement||A||(w=document.getElementById(l),w)))throw"Canvas with id "+l+" was not found";l=this.GetWebGLContext(w,v);if(!l||0>l)throw"failed to create webgl context: err "+l;l=this.MakeWebGLContext(l);q=this.MakeOnScreenGLSurface(l,w.width,w.height,q);return q?q:(q=w.cloneNode(!0),w.parentNode.replaceChild(q,w),q.classList.add("ck-replaced"),a.MakeSWCanvasSurface(q))};a.MakeCanvasSurface= +a.MakeWebGLCanvasSurface;a.Surface.prototype.makeImageFromTexture=function(l,q){a.Ud(this.Td);l=c(l);if(q=this._makeImageFromTexture(this.Td,l,q))q.oe=l;return q};a.Surface.prototype.makeImageFromTextureSource=function(l,q,v){q||={height:e(l),width:f(l),colorType:a.ColorType.RGBA_8888,alphaType:v?a.AlphaType.Premul:a.AlphaType.Unpremul};q.colorSpace||(q.colorSpace=a.ColorSpace.SRGB);a.Ud(this.Td);var w=z.fe;v=k(w,w.createTexture(),q,v);2===z.version?w.texImage2D(w.TEXTURE_2D,0,w.RGBA,q.width,q.height, +0,w.RGBA,w.UNSIGNED_BYTE,l):w.texImage2D(w.TEXTURE_2D,0,w.RGBA,w.RGBA,w.UNSIGNED_BYTE,l);n(w,q);this._resetContext();return this.makeImageFromTexture(v,q)};a.Surface.prototype.updateTextureFromSource=function(l,q,v){if(l.oe){a.Ud(this.Td);var w=l.getImageInfo(),A=z.fe,D=k(A,ka[l.oe],w,v);2===z.version?A.texImage2D(A.TEXTURE_2D,0,A.RGBA,f(q),e(q),0,A.RGBA,A.UNSIGNED_BYTE,q):A.texImage2D(A.TEXTURE_2D,0,A.RGBA,A.RGBA,A.UNSIGNED_BYTE,q);n(A,w,v);this._resetContext();ka[l.oe]=null;l.oe=c(D);w.colorSpace= +l.getColorSpace();q=this._makeImageFromTexture(this.Td,l.oe,w);v=l.Sd.Vd;A=l.Sd.Zd;l.Sd.Vd=q.Sd.Vd;l.Sd.Zd=q.Sd.Zd;q.Sd.Vd=v;q.Sd.Zd=A;q.delete();w.colorSpace.delete()}};a.MakeLazyImageFromTextureSource=function(l,q,v){q||={height:e(l),width:f(l),colorType:a.ColorType.RGBA_8888,alphaType:v?a.AlphaType.Premul:a.AlphaType.Unpremul};q.colorSpace||(q.colorSpace=a.ColorSpace.SRGB);var w={makeTexture:function(){var A=z,D=A.fe,I=k(D,D.createTexture(),q,v);2===A.version?D.texImage2D(D.TEXTURE_2D,0,D.RGBA, +q.width,q.height,0,D.RGBA,D.UNSIGNED_BYTE,l):D.texImage2D(D.TEXTURE_2D,0,D.RGBA,D.RGBA,D.UNSIGNED_BYTE,l);n(D,q,v);return c(I)},freeSrc:function(){}};"VideoFrame"===l.constructor.name&&(w.freeSrc=function(){l.close()});return a.Image._makeFromGenerator(q,w)};a.Ud=function(l){return l?oa(l):!1};a.ve=function(){return z&&z.De&&!z.De.isDeleted()?z.De:null}})})(r); +(function(a){function b(g){return(f(255*g[3])<<24|f(255*g[0])<<16|f(255*g[1])<<8|f(255*g[2])<<0)>>>0}function c(g){if(g&&g._ck)return g;if(g instanceof Float32Array){for(var d=Math.floor(g.length/4),h=new Uint32Array(d),m=0;mx;x++)a.HEAPF32[t+m]=g[u][x],m++;g=h}else g=0;d.be=g}else throw"Invalid argument to copyFlexibleColorArray, Not a color array "+typeof g;return d}function q(g){if(!g)return 0;var d=aa.toTypedArray();if(g.length){if(6===g.length||9===g.length)return n(g,"HEAPF32",O),6===g.length&&a.HEAPF32.set(Vc,6+O/4),O;if(16===g.length)return d[0]=g[0],d[1]=g[1],d[2]=g[3],d[3]=g[4],d[4]=g[5],d[5]=g[7],d[6]=g[12],d[7]=g[13],d[8]=g[15],O;throw"invalid matrix size"; +}if(void 0===g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m41;d[3]=g.m12;d[4]=g.m22;d[5]=g.m42;d[6]=g.m14;d[7]=g.m24;d[8]=g.m44;return O}function v(g){if(!g)return 0;var d=X.toTypedArray();if(g.length){if(16!==g.length&&6!==g.length&&9!==g.length)throw"invalid matrix size";if(16===g.length)return n(g,"HEAPF32",la);d.fill(0);d[0]=g[0];d[1]=g[1];d[3]=g[2];d[4]=g[3];d[5]=g[4];d[7]=g[5];d[10]=1;d[12]=g[6];d[13]=g[7];d[15]=g[8];6===g.length&&(d[12]=0,d[13]=0,d[15]=1);return la}if(void 0=== +g.m11)throw"invalid matrix argument";d[0]=g.m11;d[1]=g.m21;d[2]=g.m31;d[3]=g.m41;d[4]=g.m12;d[5]=g.m22;d[6]=g.m32;d[7]=g.m42;d[8]=g.m13;d[9]=g.m23;d[10]=g.m33;d[11]=g.m43;d[12]=g.m14;d[13]=g.m24;d[14]=g.m34;d[15]=g.m44;return la}function w(g,d){return n(g,"HEAPF32",d||ha)}function A(g,d,h,m){var t=Ea.toTypedArray();t[0]=g;t[1]=d;t[2]=h;t[3]=m;return ha}function D(g){for(var d=new Float32Array(4),h=0;4>h;h++)d[h]=a.HEAPF32[g/4+h];return d}function I(g,d){return n(g,"HEAPF32",d||V)}function P(g,d){return n(g, +"HEAPF32",d||tb)}a.Color=function(g,d,h,m){void 0===m&&(m=1);return a.Color4f(f(g)/255,f(d)/255,f(h)/255,m)};a.ColorAsInt=function(g,d,h,m){void 0===m&&(m=255);return(f(m)<<24|f(g)<<16|f(d)<<8|f(h)<<0&268435455)>>>0};a.Color4f=function(g,d,h,m){void 0===m&&(m=1);return Float32Array.of(g,d,h,m)};Object.defineProperty(a,"TRANSPARENT",{get:function(){return a.Color4f(0,0,0,0)}});Object.defineProperty(a,"BLACK",{get:function(){return a.Color4f(0,0,0,1)}});Object.defineProperty(a,"WHITE",{get:function(){return a.Color4f(1, +1,1,1)}});Object.defineProperty(a,"RED",{get:function(){return a.Color4f(1,0,0,1)}});Object.defineProperty(a,"GREEN",{get:function(){return a.Color4f(0,1,0,1)}});Object.defineProperty(a,"BLUE",{get:function(){return a.Color4f(0,0,1,1)}});Object.defineProperty(a,"YELLOW",{get:function(){return a.Color4f(1,1,0,1)}});Object.defineProperty(a,"CYAN",{get:function(){return a.Color4f(0,1,1,1)}});Object.defineProperty(a,"MAGENTA",{get:function(){return a.Color4f(1,0,1,1)}});a.getColorComponents=function(g){return[Math.floor(255* +g[0]),Math.floor(255*g[1]),Math.floor(255*g[2]),g[3]]};a.parseColorString=function(g,d){g=g.toLowerCase();if(g.startsWith("#")){d=255;switch(g.length){case 9:d=parseInt(g.slice(7,9),16);case 7:var h=parseInt(g.slice(1,3),16);var m=parseInt(g.slice(3,5),16);var t=parseInt(g.slice(5,7),16);break;case 5:d=17*parseInt(g.slice(4,5),16);case 4:h=17*parseInt(g.slice(1,2),16),m=17*parseInt(g.slice(2,3),16),t=17*parseInt(g.slice(3,4),16)}return a.Color(h,m,t,d/255)}return g.startsWith("rgba")?(g=g.slice(5, +-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("rgb")?(g=g.slice(4,-1),g=g.split(","),a.Color(+g[0],+g[1],+g[2],e(g[3]))):g.startsWith("gray(")||g.startsWith("hsl")||!d||(g=d[g],void 0===g)?a.BLACK:g};a.multiplyByAlpha=function(g,d){g=g.slice();g[3]=Math.max(0,Math.min(g[3]*d,1));return g};a.Malloc=function(g,d){var h=a._malloc(d*g.BYTES_PER_ELEMENT);return{_ck:!0,length:d,byteOffset:h,ke:null,subarray:function(m,t){m=this.toTypedArray().subarray(m,t);m._ck=!0;return m},toTypedArray:function(){if(this.ke&& +this.ke.length)return this.ke;this.ke=new g(a.HEAPU8.buffer,h,d);this.ke._ck=!0;return this.ke}}};a.Free=function(g){a._free(g.byteOffset);g.byteOffset=0;g.toTypedArray=null;g.ke=null};var O=0,aa,la=0,X,ha=0,Ea,ea,V=0,Ub,Aa=0,Vb,ub=0,Wb,vb=0,$a,Ma=0,Xb,tb=0,Yb,Zb=0,Vc=Float32Array.of(0,0,1);a.onRuntimeInitialized=function(){function g(d,h,m,t,u,x,C){x||(x=4*t.width,t.colorType===a.ColorType.RGBA_F16?x*=2:t.colorType===a.ColorType.RGBA_F32&&(x*=4));var G=x*t.height;var F=u?u.byteOffset:a._malloc(G); +if(C?!d._readPixels(t,F,x,h,m,C):!d._readPixels(t,F,x,h,m))return u||a._free(F),null;if(u)return u.toTypedArray();switch(t.colorType){case a.ColorType.RGBA_8888:case a.ColorType.RGBA_F16:d=(new Uint8Array(a.HEAPU8.buffer,F,G)).slice();break;case a.ColorType.RGBA_F32:d=(new Float32Array(a.HEAPU8.buffer,F,G)).slice();break;default:return null}a._free(F);return d}Ea=a.Malloc(Float32Array,4);ha=Ea.byteOffset;X=a.Malloc(Float32Array,16);la=X.byteOffset;aa=a.Malloc(Float32Array,9);O=aa.byteOffset;Xb=a.Malloc(Float32Array, +12);tb=Xb.byteOffset;Yb=a.Malloc(Float32Array,12);Zb=Yb.byteOffset;ea=a.Malloc(Float32Array,4);V=ea.byteOffset;Ub=a.Malloc(Float32Array,4);Aa=Ub.byteOffset;Vb=a.Malloc(Float32Array,3);ub=Vb.byteOffset;Wb=a.Malloc(Float32Array,3);vb=Wb.byteOffset;$a=a.Malloc(Int32Array,4);Ma=$a.byteOffset;a.ColorSpace.SRGB=a.ColorSpace._MakeSRGB();a.ColorSpace.DISPLAY_P3=a.ColorSpace._MakeDisplayP3();a.ColorSpace.ADOBE_RGB=a.ColorSpace._MakeAdobeRGB();a.GlyphRunFlags={IsWhiteSpace:a._GlyphRunFlags_isWhiteSpace};a.Path.MakeFromCmds= +function(d){var h=n(d,"HEAPF32"),m=a.Path._MakeFromCmds(h,d.length);k(h,d);return m};a.Path.MakeFromVerbsPointsWeights=function(d,h,m){var t=n(d,"HEAPU8"),u=n(h,"HEAPF32"),x=n(m,"HEAPF32"),C=a.Path._MakeFromVerbsPointsWeights(t,d.length,u,h.length,x,m&&m.length||0);k(t,d);k(u,h);k(x,m);return C};a.Path.prototype.addArc=function(d,h,m){d=I(d);this._addArc(d,h,m);return this};a.Path.prototype.addCircle=function(d,h,m,t){this._addCircle(d,h,m,!!t);return this};a.Path.prototype.addOval=function(d,h,m){void 0=== +m&&(m=1);d=I(d);this._addOval(d,!!h,m);return this};a.Path.prototype.addPath=function(){var d=Array.prototype.slice.call(arguments),h=d[0],m=!1;"boolean"===typeof d[d.length-1]&&(m=d.pop());if(1===d.length)this._addPath(h,1,0,0,0,1,0,0,0,1,m);else if(2===d.length)d=d[1],this._addPath(h,d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1,m);else if(7===d.length||10===d.length)this._addPath(h,d[1],d[2],d[3],d[4],d[5],d[6],d[7]||0,d[8]||0,d[9]||1,m);else return null;return this};a.Path.prototype.addPoly= +function(d,h){var m=n(d,"HEAPF32");this._addPoly(m,d.length/2,h);k(m,d);return this};a.Path.prototype.addRect=function(d,h){d=I(d);this._addRect(d,!!h);return this};a.Path.prototype.addRRect=function(d,h){d=P(d);this._addRRect(d,!!h);return this};a.Path.prototype.addVerbsPointsWeights=function(d,h,m){var t=n(d,"HEAPU8"),u=n(h,"HEAPF32"),x=n(m,"HEAPF32");this._addVerbsPointsWeights(t,d.length,u,h.length,x,m&&m.length||0);k(t,d);k(u,h);k(x,m)};a.Path.prototype.arc=function(d,h,m,t,u,x){d=a.LTRBRect(d- +m,h-m,d+m,h+m);u=(u-t)/Math.PI*180-360*!!x;x=new a.Path;x.addArc(d,t/Math.PI*180,u);this.addPath(x,!0);x.delete();return this};a.Path.prototype.arcToOval=function(d,h,m,t){d=I(d);this._arcToOval(d,h,m,t);return this};a.Path.prototype.arcToRotated=function(d,h,m,t,u,x,C){this._arcToRotated(d,h,m,!!t,!!u,x,C);return this};a.Path.prototype.arcToTangent=function(d,h,m,t,u){this._arcToTangent(d,h,m,t,u);return this};a.Path.prototype.close=function(){this._close();return this};a.Path.prototype.conicTo= +function(d,h,m,t,u){this._conicTo(d,h,m,t,u);return this};a.Path.prototype.computeTightBounds=function(d){this._computeTightBounds(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.cubicTo=function(d,h,m,t,u,x){this._cubicTo(d,h,m,t,u,x);return this};a.Path.prototype.dash=function(d,h,m){return this._dash(d,h,m)?this:null};a.Path.prototype.getBounds=function(d){this._getBounds(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.Path.prototype.lineTo=function(d, +h){this._lineTo(d,h);return this};a.Path.prototype.moveTo=function(d,h){this._moveTo(d,h);return this};a.Path.prototype.offset=function(d,h){this._transform(1,0,d,0,1,h,0,0,1);return this};a.Path.prototype.quadTo=function(d,h,m,t){this._quadTo(d,h,m,t);return this};a.Path.prototype.rArcTo=function(d,h,m,t,u,x,C){this._rArcTo(d,h,m,t,u,x,C);return this};a.Path.prototype.rConicTo=function(d,h,m,t,u){this._rConicTo(d,h,m,t,u);return this};a.Path.prototype.rCubicTo=function(d,h,m,t,u,x){this._rCubicTo(d, +h,m,t,u,x);return this};a.Path.prototype.rLineTo=function(d,h){this._rLineTo(d,h);return this};a.Path.prototype.rMoveTo=function(d,h){this._rMoveTo(d,h);return this};a.Path.prototype.rQuadTo=function(d,h,m,t){this._rQuadTo(d,h,m,t);return this};a.Path.prototype.stroke=function(d){d=d||{};d.width=d.width||1;d.miter_limit=d.miter_limit||4;d.cap=d.cap||a.StrokeCap.Butt;d.join=d.join||a.StrokeJoin.Miter;d.precision=d.precision||1;return this._stroke(d)?this:null};a.Path.prototype.transform=function(){if(1=== +arguments.length){var d=arguments[0];this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1)}else if(6===arguments.length||9===arguments.length)d=arguments,this._transform(d[0],d[1],d[2],d[3],d[4],d[5],d[6]||0,d[7]||0,d[8]||1);else throw"transform expected to take 1 or 9 arguments. Got "+arguments.length;return this};a.Path.prototype.trim=function(d,h,m){return this._trim(d,h,!!m)?this:null};a.Image.prototype.encodeToBytes=function(d,h){var m=a.ve();d=d||a.ImageFormat.PNG;h=h||100; +return m?this._encodeToBytes(d,h,m):this._encodeToBytes(d,h)};a.Image.prototype.makeShaderCubic=function(d,h,m,t,u){u=q(u);return this._makeShaderCubic(d,h,m,t,u)};a.Image.prototype.makeShaderOptions=function(d,h,m,t,u){u=q(u);return this._makeShaderOptions(d,h,m,t,u)};a.Image.prototype.readPixels=function(d,h,m,t,u){var x=a.ve();return g(this,d,h,m,t,u,x)};a.Canvas.prototype.clear=function(d){a.Ud(this.Td);d=w(d);this._clear(d)};a.Canvas.prototype.clipRRect=function(d,h,m){a.Ud(this.Td);d=P(d);this._clipRRect(d, +h,m)};a.Canvas.prototype.clipRect=function(d,h,m){a.Ud(this.Td);d=I(d);this._clipRect(d,h,m)};a.Canvas.prototype.concat=function(d){a.Ud(this.Td);d=v(d);this._concat(d)};a.Canvas.prototype.drawArc=function(d,h,m,t,u){a.Ud(this.Td);d=I(d);this._drawArc(d,h,m,t,u)};a.Canvas.prototype.drawAtlas=function(d,h,m,t,u,x,C){if(d&&t&&h&&m&&h.length===m.length){a.Ud(this.Td);u||(u=a.BlendMode.SrcOver);var G=n(h,"HEAPF32"),F=n(m,"HEAPF32"),S=m.length/4,T=n(c(x),"HEAPU32");if(C&&"B"in C&&"C"in C)this._drawAtlasCubic(d, +F,G,T,S,u,C.B,C.C,t);else{let p=a.FilterMode.Linear,y=a.MipmapMode.None;C&&(p=C.filter,"mipmap"in C&&(y=C.mipmap));this._drawAtlasOptions(d,F,G,T,S,u,p,y,t)}k(G,h);k(F,m);k(T,x)}};a.Canvas.prototype.drawCircle=function(d,h,m,t){a.Ud(this.Td);this._drawCircle(d,h,m,t)};a.Canvas.prototype.drawColor=function(d,h){a.Ud(this.Td);d=w(d);void 0!==h?this._drawColor(d,h):this._drawColor(d)};a.Canvas.prototype.drawColorInt=function(d,h){a.Ud(this.Td);this._drawColorInt(d,h||a.BlendMode.SrcOver)};a.Canvas.prototype.drawColorComponents= +function(d,h,m,t,u){a.Ud(this.Td);d=A(d,h,m,t);void 0!==u?this._drawColor(d,u):this._drawColor(d)};a.Canvas.prototype.drawDRRect=function(d,h,m){a.Ud(this.Td);d=P(d,tb);h=P(h,Zb);this._drawDRRect(d,h,m)};a.Canvas.prototype.drawImage=function(d,h,m,t){a.Ud(this.Td);this._drawImage(d,h,m,t||null)};a.Canvas.prototype.drawImageCubic=function(d,h,m,t,u,x){a.Ud(this.Td);this._drawImageCubic(d,h,m,t,u,x||null)};a.Canvas.prototype.drawImageOptions=function(d,h,m,t,u,x){a.Ud(this.Td);this._drawImageOptions(d, +h,m,t,u,x||null)};a.Canvas.prototype.drawImageNine=function(d,h,m,t,u){a.Ud(this.Td);h=n(h,"HEAP32",Ma);m=I(m);this._drawImageNine(d,h,m,t,u||null)};a.Canvas.prototype.drawImageRect=function(d,h,m,t,u){a.Ud(this.Td);I(h,V);I(m,Aa);this._drawImageRect(d,V,Aa,t,!!u)};a.Canvas.prototype.drawImageRectCubic=function(d,h,m,t,u,x){a.Ud(this.Td);I(h,V);I(m,Aa);this._drawImageRectCubic(d,V,Aa,t,u,x||null)};a.Canvas.prototype.drawImageRectOptions=function(d,h,m,t,u,x){a.Ud(this.Td);I(h,V);I(m,Aa);this._drawImageRectOptions(d, +V,Aa,t,u,x||null)};a.Canvas.prototype.drawLine=function(d,h,m,t,u){a.Ud(this.Td);this._drawLine(d,h,m,t,u)};a.Canvas.prototype.drawOval=function(d,h){a.Ud(this.Td);d=I(d);this._drawOval(d,h)};a.Canvas.prototype.drawPaint=function(d){a.Ud(this.Td);this._drawPaint(d)};a.Canvas.prototype.drawParagraph=function(d,h,m){a.Ud(this.Td);this._drawParagraph(d,h,m)};a.Canvas.prototype.drawPatch=function(d,h,m,t,u){if(24>d.length)throw"Need 12 cubic points";if(h&&4>h.length)throw"Need 4 colors";if(m&&8>m.length)throw"Need 4 shader coordinates"; +a.Ud(this.Td);const x=n(d,"HEAPF32"),C=h?n(c(h),"HEAPU32"):0,G=m?n(m,"HEAPF32"):0;t||(t=a.BlendMode.Modulate);this._drawPatch(x,C,G,t,u);k(G,m);k(C,h);k(x,d)};a.Canvas.prototype.drawPath=function(d,h){a.Ud(this.Td);this._drawPath(d,h)};a.Canvas.prototype.drawPicture=function(d){a.Ud(this.Td);this._drawPicture(d)};a.Canvas.prototype.drawPoints=function(d,h,m){a.Ud(this.Td);var t=n(h,"HEAPF32");this._drawPoints(d,t,h.length/2,m);k(t,h)};a.Canvas.prototype.drawRRect=function(d,h){a.Ud(this.Td);d=P(d); +this._drawRRect(d,h)};a.Canvas.prototype.drawRect=function(d,h){a.Ud(this.Td);d=I(d);this._drawRect(d,h)};a.Canvas.prototype.drawRect4f=function(d,h,m,t,u){a.Ud(this.Td);this._drawRect4f(d,h,m,t,u)};a.Canvas.prototype.drawShadow=function(d,h,m,t,u,x,C){a.Ud(this.Td);var G=n(u,"HEAPF32"),F=n(x,"HEAPF32");h=n(h,"HEAPF32",ub);m=n(m,"HEAPF32",vb);this._drawShadow(d,h,m,t,G,F,C);k(G,u);k(F,x)};a.getShadowLocalBounds=function(d,h,m,t,u,x,C){d=q(d);m=n(m,"HEAPF32",ub);t=n(t,"HEAPF32",vb);if(!this._getShadowLocalBounds(d, +h,m,t,u,x,V))return null;h=ea.toTypedArray();return C?(C.set(h),C):h.slice()};a.Canvas.prototype.drawTextBlob=function(d,h,m,t){a.Ud(this.Td);this._drawTextBlob(d,h,m,t)};a.Canvas.prototype.drawVertices=function(d,h,m){a.Ud(this.Td);this._drawVertices(d,h,m)};a.Canvas.prototype.getDeviceClipBounds=function(d){this._getDeviceClipBounds(Ma);var h=$a.toTypedArray();d?d.set(h):d=h.slice();return d};a.Canvas.prototype.quickReject=function(d){d=I(d);return this._quickReject(d)};a.Canvas.prototype.getLocalToDevice= +function(){this._getLocalToDevice(la);for(var d=la,h=Array(16),m=0;16>m;m++)h[m]=a.HEAPF32[d/4+m];return h};a.Canvas.prototype.getTotalMatrix=function(){this._getTotalMatrix(O);for(var d=Array(9),h=0;9>h;h++)d[h]=a.HEAPF32[O/4+h];return d};a.Canvas.prototype.makeSurface=function(d){d=this._makeSurface(d);d.Td=this.Td;return d};a.Canvas.prototype.readPixels=function(d,h,m,t,u){a.Ud(this.Td);return g(this,d,h,m,t,u)};a.Canvas.prototype.saveLayer=function(d,h,m,t,u){h=I(h);return this._saveLayer(d|| +null,h,m||null,t||0,u||a.TileMode.Clamp)};a.Canvas.prototype.writePixels=function(d,h,m,t,u,x,C,G){if(d.byteLength%(h*m))throw"pixels length must be a multiple of the srcWidth * srcHeight";a.Ud(this.Td);var F=d.byteLength/(h*m);x=x||a.AlphaType.Unpremul;C=C||a.ColorType.RGBA_8888;G=G||a.ColorSpace.SRGB;var S=F*h;F=n(d,"HEAPU8");h=this._writePixels({width:h,height:m,colorType:C,alphaType:x,colorSpace:G},F,S,t,u);k(F,d);return h};a.ColorFilter.MakeBlend=function(d,h,m){d=w(d);m=m||a.ColorSpace.SRGB; +return a.ColorFilter._MakeBlend(d,h,m)};a.ColorFilter.MakeMatrix=function(d){if(!d||20!==d.length)throw"invalid color matrix";var h=n(d,"HEAPF32"),m=a.ColorFilter._makeMatrix(h);k(h,d);return m};a.ContourMeasure.prototype.getPosTan=function(d,h){this._getPosTan(d,V);d=ea.toTypedArray();return h?(h.set(d),h):d.slice()};a.ImageFilter.prototype.getOutputBounds=function(d,h,m){d=I(d,V);h=q(h);this._getOutputBounds(d,h,Ma);h=$a.toTypedArray();return m?(m.set(h),m):h.slice()};a.ImageFilter.MakeDropShadow= +function(d,h,m,t,u,x){u=w(u,ha);return a.ImageFilter._MakeDropShadow(d,h,m,t,u,x)};a.ImageFilter.MakeDropShadowOnly=function(d,h,m,t,u,x){u=w(u,ha);return a.ImageFilter._MakeDropShadowOnly(d,h,m,t,u,x)};a.ImageFilter.MakeImage=function(d,h,m,t){m=I(m,V);t=I(t,Aa);if("B"in h&&"C"in h)return a.ImageFilter._MakeImageCubic(d,h.B,h.C,m,t);const u=h.filter;let x=a.MipmapMode.None;"mipmap"in h&&(x=h.mipmap);return a.ImageFilter._MakeImageOptions(d,u,x,m,t)};a.ImageFilter.MakeMatrixTransform=function(d,h, +m){d=q(d);if("B"in h&&"C"in h)return a.ImageFilter._MakeMatrixTransformCubic(d,h.B,h.C,m);const t=h.filter;let u=a.MipmapMode.None;"mipmap"in h&&(u=h.mipmap);return a.ImageFilter._MakeMatrixTransformOptions(d,t,u,m)};a.Paint.prototype.getColor=function(){this._getColor(ha);return D(ha)};a.Paint.prototype.setColor=function(d,h){h=h||null;d=w(d);this._setColor(d,h)};a.Paint.prototype.setColorComponents=function(d,h,m,t,u){u=u||null;d=A(d,h,m,t);this._setColor(d,u)};a.Path.prototype.getPoint=function(d, +h){this._getPoint(d,V);d=ea.toTypedArray();return h?(h[0]=d[0],h[1]=d[1],h):d.slice(0,2)};a.Picture.prototype.makeShader=function(d,h,m,t,u){t=q(t);u=I(u);return this._makeShader(d,h,m,t,u)};a.Picture.prototype.cullRect=function(d){this._cullRect(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.PictureRecorder.prototype.beginRecording=function(d,h){d=I(d);return this._beginRecording(d,!!h)};a.Surface.prototype.getCanvas=function(){var d=this._getCanvas();d.Td=this.Td;return d};a.Surface.prototype.makeImageSnapshot= +function(d){a.Ud(this.Td);d=n(d,"HEAP32",Ma);return this._makeImageSnapshot(d)};a.Surface.prototype.makeSurface=function(d){a.Ud(this.Td);d=this._makeSurface(d);d.Td=this.Td;return d};a.Surface.prototype.Te=function(d,h){this.ne||(this.ne=this.getCanvas());return requestAnimationFrame(function(){a.Ud(this.Td);d(this.ne);this.flush(h)}.bind(this))};a.Surface.prototype.requestAnimationFrame||(a.Surface.prototype.requestAnimationFrame=a.Surface.prototype.Te);a.Surface.prototype.Qe=function(d,h){this.ne|| +(this.ne=this.getCanvas());requestAnimationFrame(function(){a.Ud(this.Td);d(this.ne);this.flush(h);this.dispose()}.bind(this))};a.Surface.prototype.drawOnce||(a.Surface.prototype.drawOnce=a.Surface.prototype.Qe);a.PathEffect.MakeDash=function(d,h){h||=0;if(!d.length||1===d.length%2)throw"Intervals array must have even length";var m=n(d,"HEAPF32");h=a.PathEffect._MakeDash(m,d.length,h);k(m,d);return h};a.PathEffect.MakeLine2D=function(d,h){h=q(h);return a.PathEffect._MakeLine2D(d,h)};a.PathEffect.MakePath2D= +function(d,h){d=q(d);return a.PathEffect._MakePath2D(d,h)};a.Shader.MakeColor=function(d,h){h=h||null;d=w(d);return a.Shader._MakeColor(d,h)};a.Shader.Blend=a.Shader.MakeBlend;a.Shader.Color=a.Shader.MakeColor;a.Shader.MakeLinearGradient=function(d,h,m,t,u,x,C,G){G=G||null;var F=l(m),S=n(t,"HEAPF32");C=C||0;x=q(x);var T=ea.toTypedArray();T.set(d);T.set(h,2);d=a.Shader._MakeLinearGradient(V,F.be,F.colorType,S,F.count,u,C,x,G);k(F.be,m);t&&k(S,t);return d};a.Shader.MakeRadialGradient=function(d,h,m, +t,u,x,C,G){G=G||null;var F=l(m),S=n(t,"HEAPF32");C=C||0;x=q(x);d=a.Shader._MakeRadialGradient(d[0],d[1],h,F.be,F.colorType,S,F.count,u,C,x,G);k(F.be,m);t&&k(S,t);return d};a.Shader.MakeSweepGradient=function(d,h,m,t,u,x,C,G,F,S){S=S||null;var T=l(m),p=n(t,"HEAPF32");C=C||0;G=G||0;F=F||360;x=q(x);d=a.Shader._MakeSweepGradient(d,h,T.be,T.colorType,p,T.count,u,G,F,C,x,S);k(T.be,m);t&&k(p,t);return d};a.Shader.MakeTwoPointConicalGradient=function(d,h,m,t,u,x,C,G,F,S){S=S||null;var T=l(u),p=n(x,"HEAPF32"); +F=F||0;G=q(G);var y=ea.toTypedArray();y.set(d);y.set(m,2);d=a.Shader._MakeTwoPointConicalGradient(V,h,t,T.be,T.colorType,p,T.count,C,F,G,S);k(T.be,u);x&&k(p,x);return d};a.Vertices.prototype.bounds=function(d){this._bounds(V);var h=ea.toTypedArray();return d?(d.set(h),d):h.slice()};a.Xd&&a.Xd.forEach(function(d){d()})};a.computeTonalColors=function(g){var d=n(g.ambient,"HEAPF32"),h=n(g.spot,"HEAPF32");this._computeTonalColors(d,h);var m={ambient:D(d),spot:D(h)};k(d,g.ambient);k(h,g.spot);return m}; +a.LTRBRect=function(g,d,h,m){return Float32Array.of(g,d,h,m)};a.XYWHRect=function(g,d,h,m){return Float32Array.of(g,d,g+h,d+m)};a.LTRBiRect=function(g,d,h,m){return Int32Array.of(g,d,h,m)};a.XYWHiRect=function(g,d,h,m){return Int32Array.of(g,d,g+h,d+m)};a.RRectXY=function(g,d,h){return Float32Array.of(g[0],g[1],g[2],g[3],d,h,d,h,d,h,d,h)};a.MakeAnimatedImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeAnimatedImage(d,g.byteLength))? +g:null};a.MakeImageFromEncoded=function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._decodeImage(d,g.byteLength))?g:null};var ab=null;a.MakeImageFromCanvasImageSource=function(g){var d=g.width,h=g.height;ab||=document.createElement("canvas");ab.width=d;ab.height=h;var m=ab.getContext("2d",{willReadFrequently:!0});m.drawImage(g,0,0);g=m.getImageData(0,0,d,h);return a.MakeImage({width:d,height:h,alphaType:a.AlphaType.Unpremul,colorType:a.ColorType.RGBA_8888,colorSpace:a.ColorSpace.SRGB}, +g.data,4*d)};a.MakeImage=function(g,d,h){var m=a._malloc(d.length);a.HEAPU8.set(d,m);return a._MakeImage(g,m,d.length,h)};a.MakeVertices=function(g,d,h,m,t,u){var x=t&&t.length||0,C=0;h&&h.length&&(C|=1);m&&m.length&&(C|=2);void 0===u||u||(C|=4);g=new a._VerticesBuilder(g,d.length/2,x,C);n(d,"HEAPF32",g.positions());g.texCoords()&&n(h,"HEAPF32",g.texCoords());g.colors()&&n(c(m),"HEAPU32",g.colors());g.indices()&&n(t,"HEAPU16",g.indices());return g.detach()};(function(g){g.Xd=g.Xd||[];g.Xd.push(function(){function d(p){p&& +(p.dir=0===p.dir?g.TextDirection.RTL:g.TextDirection.LTR);return p}function h(p){if(!p||!p.length)return[];for(var y=[],M=0;Md)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.Font.prototype.getGlyphIntercepts= +function(g,d,h,m){var t=n(g,"HEAPU16"),u=n(d,"HEAPF32");return this._getGlyphIntercepts(t,g.length,!(g&&g._ck),u,d.length,!(d&&d._ck),h,m)};a.Font.prototype.getGlyphWidths=function(g,d,h){var m=n(g,"HEAPU16"),t=a._malloc(4*g.length);this._getGlyphWidthBounds(m,g.length,t,0,d||null);d=new Float32Array(a.HEAPU8.buffer,t,g.length);k(m,g);if(h)return h.set(d),a._free(t),h;g=Float32Array.from(d);a._free(t);return g};a.FontMgr.FromData=function(){if(!arguments.length)return null;var g=arguments;1===g.length&& +Array.isArray(g[0])&&(g=arguments[0]);if(!g.length)return null;for(var d=[],h=[],m=0;md)return a._free(g),null;t=new Uint16Array(a.HEAPU8.buffer,g,d);if(h)return h.set(t),a._free(g),h;h=Uint16Array.from(t);a._free(g);return h};a.TextBlob.MakeOnPath=function(g,d,h,m){if(g&&g.length&&d&&d.countPoints()){if(1===d.countPoints())return this.MakeFromText(g,h);m||=0;var t=h.getGlyphIDs(g);t=h.getGlyphWidths(t);var u=[];d=new a.ContourMeasureIter(d,!1,1);for(var x= +d.next(),C=new Float32Array(4),G=0;Gx.length()){x.delete();x=d.next();if(!x){g=g.substring(0,G);break}m=F/2}x.getPosTan(m,C);var S=C[2],T=C[3];u.push(S,T,C[0]-F/2*S,C[1]-F/2*T);m+=F/2}g=this.MakeFromRSXform(g,u,h);x&&x.delete();d.delete();return g}};a.TextBlob.MakeFromRSXform=function(g,d,h){var m=qa(g)+1,t=a._malloc(m);ra(g,t,m);g=n(d,"HEAPF32");h=a.TextBlob._MakeFromRSXform(t,m-1,g,h);a._free(t);return h?h:null};a.TextBlob.MakeFromRSXformGlyphs=function(g, +d,h){var m=n(g,"HEAPU16");d=n(d,"HEAPF32");h=a.TextBlob._MakeFromRSXformGlyphs(m,2*g.length,d,h);k(m,g);return h?h:null};a.TextBlob.MakeFromGlyphs=function(g,d){var h=n(g,"HEAPU16");d=a.TextBlob._MakeFromGlyphs(h,2*g.length,d);k(h,g);return d?d:null};a.TextBlob.MakeFromText=function(g,d){var h=qa(g)+1,m=a._malloc(h);ra(g,m,h);g=a.TextBlob._MakeFromText(m,h-1,d);a._free(m);return g?g:null};a.MallocGlyphIDs=function(g){return a.Malloc(Uint16Array,g)}});a.Xd=a.Xd||[];a.Xd.push(function(){a.MakePicture= +function(g){g=new Uint8Array(g);var d=a._malloc(g.byteLength);a.HEAPU8.set(g,d);return(g=a._MakePicture(d,g.byteLength))?g:null}});a.Xd=a.Xd||[];a.Xd.push(function(){a.RuntimeEffect.Make=function(g,d){return a.RuntimeEffect._Make(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.MakeForBlender=function(g,d){return a.RuntimeEffect._MakeForBlender(g,{onError:d||function(h){console.log("RuntimeEffect error",h)}})};a.RuntimeEffect.prototype.makeShader=function(g,d){var h= +!g._ck,m=n(g,"HEAPF32");d=q(d);return this._makeShader(m,4*g.length,h,d)};a.RuntimeEffect.prototype.makeShaderWithChildren=function(g,d,h){var m=!g._ck,t=n(g,"HEAPF32");h=q(h);for(var u=[],x=0;x{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),ua=a=>fetch(a,{credentials:"same-origin"}).then(b=>b.ok?b.arrayBuffer():Promise.reject(Error(b.status+" : "+b.url))); +var xa=console.log.bind(console),ya=console.error.bind(console);Object.assign(r,sa);sa=null;var za,Ba=!1,Ca,B,Da,Fa,E,H,J,Ga;function Ha(){var a=za.buffer;r.HEAP8=Ca=new Int8Array(a);r.HEAP16=Da=new Int16Array(a);r.HEAPU8=B=new Uint8Array(a);r.HEAPU16=Fa=new Uint16Array(a);r.HEAP32=E=new Int32Array(a);r.HEAPU32=H=new Uint32Array(a);r.HEAPF32=J=new Float32Array(a);r.HEAPF64=Ga=new Float64Array(a)}var Ia=[],Ja=[],Ka=[],La=0,Na=null,Oa=null; +function Pa(a){a="Aborted("+a+")";ya(a);Ba=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ca(a);throw a;}var Qa=a=>a.startsWith("data:application/octet-stream;base64,"),Ra;function Sa(a){return ua(a).then(b=>new Uint8Array(b),()=>{if(va)var b=va(a);else throw"both async and sync fetching of the wasm failed";return b})}function Ta(a,b,c){return Sa(a).then(e=>WebAssembly.instantiate(e,b)).then(c,e=>{ya(`failed to asynchronously prepare wasm: ${e}`);Pa(e)})} +function Ua(a,b){var c=Ra;return"function"!=typeof WebAssembly.instantiateStreaming||Qa(c)||"function"!=typeof fetch?Ta(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){ya(`wasm streaming compile failed: ${f}`);ya("falling back to ArrayBuffer instantiation");return Ta(c,a,b)}))}function Va(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}var Wa=a=>{a.forEach(b=>b(r))},Xa=r.noExitRuntime||!0; +class Ya{constructor(a){this.Vd=a-24}} +var Za=0,bb=0,cb="undefined"!=typeof TextDecoder?new TextDecoder:void 0,db=(a,b=0,c=NaN)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e}, +eb={},fb=a=>{for(;a.length;){var b=a.pop();a.pop()(b)}};function gb(a){return this.fromWireType(H[a>>2])} +var hb={},ib={},jb={},kb,mb=(a,b,c)=>{function e(l){l=c(l);if(l.length!==a.length)throw new kb("Mismatched type converter count");for(var q=0;qjb[l]=b);var f=Array(b.length),k=[],n=0;b.forEach((l,q)=>{ib.hasOwnProperty(l)?f[q]=ib[l]:(k.push(l),hb.hasOwnProperty(l)||(hb[l]=[]),hb[l].push(()=>{f[q]=ib[l];++n;n===k.length&&e(f)}))});0===k.length&&e(f)},nb,K=a=>{for(var b="";B[a];)b+=nb[B[a++]];return b},L; +function ob(a,b,c={}){var e=b.name;if(!a)throw new L(`type "${e}" must have a positive integer typeid pointer`);if(ib.hasOwnProperty(a)){if(c.ef)return;throw new L(`Cannot register type '${e}' twice`);}ib[a]=b;delete jb[a];hb.hasOwnProperty(a)&&(b=hb[a],delete hb[a],b.forEach(f=>f()))}function lb(a,b,c={}){return ob(a,b,c)} +var pb=a=>{throw new L(a.Sd.Yd.Wd.name+" instance already deleted");},qb=!1,rb=()=>{},sb=(a,b,c)=>{if(b===c)return a;if(void 0===c.ae)return null;a=sb(a,b,c.ae);return null===a?null:c.Xe(a)},yb={},zb={},Ab=(a,b)=>{if(void 0===b)throw new L("ptr should not be undefined");for(;a.ae;)b=a.se(b),a=a.ae;return zb[b]},Cb=(a,b)=>{if(!b.Yd||!b.Vd)throw new kb("makeClassHandle requires ptr and ptrType");if(!!b.ce!==!!b.Zd)throw new kb("Both smartPtrType and smartPtr must be specified");b.count={value:1};return Bb(Object.create(a, +{Sd:{value:b,writable:!0}}))},Bb=a=>{if("undefined"===typeof FinalizationRegistry)return Bb=b=>b,a;qb=new FinalizationRegistry(b=>{b=b.Sd;--b.count.value;0===b.count.value&&(b.Zd?b.ce.he(b.Zd):b.Yd.Wd.he(b.Vd))});Bb=b=>{var c=b.Sd;c.Zd&&qb.register(b,{Sd:c},b);return b};rb=b=>{qb.unregister(b)};return Bb(a)},Db=[];function Eb(){} +var Fb=(a,b)=>Object.defineProperty(b,"name",{value:a}),Gb=(a,b,c)=>{if(void 0===a[b].$d){var e=a[b];a[b]=function(...f){if(!a[b].$d.hasOwnProperty(f.length))throw new L(`Function '${c}' called with an invalid number of arguments (${f.length}) - expects one of (${a[b].$d})!`);return a[b].$d[f.length].apply(this,f)};a[b].$d=[];a[b].$d[e.ie]=e}},Hb=(a,b,c)=>{if(r.hasOwnProperty(a)){if(void 0===c||void 0!==r[a].$d&&void 0!==r[a].$d[c])throw new L(`Cannot register public name '${a}' twice`);Gb(r,a,a); +if(r[a].$d.hasOwnProperty(c))throw new L(`Cannot register multiple overloads of a function with the same number of arguments (${c})!`);r[a].$d[c]=b}else r[a]=b,r[a].ie=c},Ib=a=>{a=a.replace(/[^a-zA-Z0-9_]/g,"$");var b=a.charCodeAt(0);return 48<=b&&57>=b?`_${a}`:a};function Jb(a,b,c,e,f,k,n,l){this.name=a;this.constructor=b;this.me=c;this.he=e;this.ae=f;this.$e=k;this.se=n;this.Xe=l;this.hf=[]} +var Kb=(a,b,c)=>{for(;b!==c;){if(!b.se)throw new L(`Expected null or instance of ${c.name}, got an instance of ${b.name}`);a=b.se(a);b=b.ae}return a};function Lb(a,b){if(null===b){if(this.Ee)throw new L(`null is not a valid ${this.name}`);return 0}if(!b.Sd)throw new L(`Cannot pass "${Mb(b)}" as a ${this.name}`);if(!b.Sd.Vd)throw new L(`Cannot pass deleted object as a pointer of type ${this.name}`);return Kb(b.Sd.Vd,b.Sd.Yd.Wd,this.Wd)} +function Nb(a,b){if(null===b){if(this.Ee)throw new L(`null is not a valid ${this.name}`);if(this.xe){var c=this.Fe();null!==a&&a.push(this.he,c);return c}return 0}if(!b||!b.Sd)throw new L(`Cannot pass "${Mb(b)}" as a ${this.name}`);if(!b.Sd.Vd)throw new L(`Cannot pass deleted object as a pointer of type ${this.name}`);if(!this.we&&b.Sd.Yd.we)throw new L(`Cannot convert argument of type ${b.Sd.ce?b.Sd.ce.name:b.Sd.Yd.name} to parameter type ${this.name}`);c=Kb(b.Sd.Vd,b.Sd.Yd.Wd,this.Wd);if(this.xe){if(void 0=== +b.Sd.Zd)throw new L("Passing raw pointer to smart pointer is illegal");switch(this.nf){case 0:if(b.Sd.ce===this)c=b.Sd.Zd;else throw new L(`Cannot convert argument of type ${b.Sd.ce?b.Sd.ce.name:b.Sd.Yd.name} to parameter type ${this.name}`);break;case 1:c=b.Sd.Zd;break;case 2:if(b.Sd.ce===this)c=b.Sd.Zd;else{var e=b.clone();c=this.jf(c,Ob(()=>e["delete"]()));null!==a&&a.push(this.he,c)}break;default:throw new L("Unsupporting sharing policy");}}return c} +function Pb(a,b){if(null===b){if(this.Ee)throw new L(`null is not a valid ${this.name}`);return 0}if(!b.Sd)throw new L(`Cannot pass "${Mb(b)}" as a ${this.name}`);if(!b.Sd.Vd)throw new L(`Cannot pass deleted object as a pointer of type ${this.name}`);if(b.Sd.Yd.we)throw new L(`Cannot convert argument of type ${b.Sd.Yd.name} to parameter type ${this.name}`);return Kb(b.Sd.Vd,b.Sd.Yd.Wd,this.Wd)} +function Qb(a,b,c,e,f,k,n,l,q,v,w){this.name=a;this.Wd=b;this.Ee=c;this.we=e;this.xe=f;this.gf=k;this.nf=n;this.Me=l;this.Fe=q;this.jf=v;this.he=w;f||void 0!==b.ae?this.toWireType=Nb:(this.toWireType=e?Lb:Pb,this.ee=null)} +var Rb=(a,b,c)=>{if(!r.hasOwnProperty(a))throw new kb("Replacing nonexistent public symbol");void 0!==r[a].$d&&void 0!==c?r[a].$d[c]=b:(r[a]=b,r[a].ie=c)},N,Sb=(a,b,c=[])=>{a.includes("j")?(a=a.replace(/p/g,"i"),b=(0,r["dynCall_"+a])(b,...c)):b=N.get(b)(...c);return b},Tb=(a,b)=>(...c)=>Sb(a,b,c),Q=(a,b)=>{a=K(a);var c=a.includes("j")?Tb(a,b):N.get(b);if("function"!=typeof c)throw new L(`unknown function pointer with signature ${a}: ${b}`);return c},ac,dc=a=>{a=bc(a);var b=K(a);cc(a);return b},ec= +(a,b)=>{function c(k){f[k]||ib[k]||(jb[k]?jb[k].forEach(c):(e.push(k),f[k]=!0))}var e=[],f={};b.forEach(c);throw new ac(`${a}: `+e.map(dc).join([", "]));};function fc(a){for(var b=1;bk)throw new L("argTypes array size mismatch! Must at least get return value and 'this' types!");var n=null!==b[1]&&null!==c,l=fc(b),q="void"!==b[0].name,v=k-2,w=Array(v),A=[],D=[];return Fb(a,function(...I){D.length=0;A.length=n?2:1;A[0]=f;if(n){var P=b[1].toWireType(D,this);A[1]=P}for(var O=0;O{for(var c=[],e=0;e>2]);return c},ic=a=>{a=a.trim();const b=a.indexOf("(");return-1!==b?a.substr(0,b):a},jc=[],kc=[],lc=a=>{9{if(!a)throw new L("Cannot use deleted val. handle = "+a);return kc[a]},Ob=a=>{switch(a){case void 0:return 2;case null:return 4;case !0:return 6;case !1:return 8;default:const b=jc.pop()||kc.length;kc[b]=a;kc[b+1]=1;return b}},nc={name:"emscripten::val",fromWireType:a=>{var b=mc(a);lc(a); +return b},toWireType:(a,b)=>Ob(b),de:8,readValueFromPointer:gb,ee:null},oc=(a,b,c)=>{switch(b){case 1:return c?function(e){return this.fromWireType(Ca[e])}:function(e){return this.fromWireType(B[e])};case 2:return c?function(e){return this.fromWireType(Da[e>>1])}:function(e){return this.fromWireType(Fa[e>>1])};case 4:return c?function(e){return this.fromWireType(E[e>>2])}:function(e){return this.fromWireType(H[e>>2])};default:throw new TypeError(`invalid integer width (${b}): ${a}`);}},pc=(a,b)=> +{var c=ib[a];if(void 0===c)throw a=`${b} has unknown type ${dc(a)}`,new L(a);return c},Mb=a=>{if(null===a)return"null";var b=typeof a;return"object"===b||"array"===b||"function"===b?a.toString():""+a},qc=(a,b)=>{switch(b){case 4:return function(c){return this.fromWireType(J[c>>2])};case 8:return function(c){return this.fromWireType(Ga[c>>3])};default:throw new TypeError(`invalid float width (${b}): ${a}`);}},rc=(a,b,c)=>{switch(b){case 1:return c?e=>Ca[e]:e=>B[e];case 2:return c?e=>Da[e>>1]:e=>Fa[e>> +1];case 4:return c?e=>E[e>>2]:e=>H[e>>2];default:throw new TypeError(`invalid integer width (${b}): ${a}`);}},ra=(a,b,c)=>{var e=B;if(!(0=n){var l=a.charCodeAt(++k);n=65536+((n&1023)<<10)|l&1023}if(127>=n){if(b>=c)break;e[b++]=n}else{if(2047>=n){if(b+1>=c)break;e[b++]=192|n>>6}else{if(65535>=n){if(b+2>=c)break;e[b++]=224|n>>12}else{if(b+3>=c)break;e[b++]=240|n>>18;e[b++]=128|n>>12&63}e[b++]=128|n>>6& +63}e[b++]=128|n&63}}e[b]=0;return b-f},qa=a=>{for(var b=0,c=0;c=e?b++:2047>=e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}return b},sc="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0,tc=(a,b)=>{var c=a>>1;for(var e=c+b/2;!(c>=e)&&Fa[c];)++c;c<<=1;if(32=b/2);++e){var f=Da[a+2*e>>1];if(0==f)break;c+=String.fromCharCode(f)}return c},uc=(a,b,c)=>{c??=2147483647;if(2>c)return 0;c-=2;var e= +b;c=c<2*a.length?c/2:a.length;for(var f=0;f>1]=a.charCodeAt(f),b+=2;Da[b>>1]=0;return b-e},vc=a=>2*a.length,wc=(a,b)=>{for(var c=0,e="";!(c>=b/4);){var f=E[a+4*c>>2];if(0==f)break;++c;65536<=f?(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023)):e+=String.fromCharCode(f)}return e},xc=(a,b,c)=>{c??=2147483647;if(4>c)return 0;var e=b;c=e+c-4;for(var f=0;f=k){var n=a.charCodeAt(++f);k=65536+((k&1023)<<10)|n&1023}E[b>>2]=k;b+= +4;if(b+4>c)break}E[b>>2]=0;return b-e},yc=a=>{for(var b=0,c=0;c=e&&++c;b+=4}return b},zc=(a,b,c)=>{var e=[];a=a.toWireType(e,c);e.length&&(H[b>>2]=Ob(e));return a},Ac=[],Bc={},Cc=a=>{var b=Bc[a];return void 0===b?K(a):b},Dc=()=>{function a(b){b.$$$embind_global$$$=b;var c="object"==typeof $$$embind_global$$$&&b.$$$embind_global$$$==b;c||delete b.$$$embind_global$$$;return c}if("object"==typeof globalThis)return globalThis;if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$; +"object"==typeof global&&a(global)?$$$embind_global$$$=global:"object"==typeof self&&a(self)&&($$$embind_global$$$=self);if("object"==typeof $$$embind_global$$$)return $$$embind_global$$$;throw Error("unable to get global object.");},Ec=a=>{var b=Ac.length;Ac.push(a);return b},Fc=(a,b)=>{for(var c=Array(a),e=0;e>2],"parameter "+e);return c},Gc=Reflect.construct,R,Hc=a=>{var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=(c,e)=>b.vertexAttribDivisorANGLE(c, +e),a.drawArraysInstanced=(c,e,f,k)=>b.drawArraysInstancedANGLE(c,e,f,k),a.drawElementsInstanced=(c,e,f,k,n)=>b.drawElementsInstancedANGLE(c,e,f,k,n))},Ic=a=>{var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=()=>b.createVertexArrayOES(),a.deleteVertexArray=c=>b.deleteVertexArrayOES(c),a.bindVertexArray=c=>b.bindVertexArrayOES(c),a.isVertexArray=c=>b.isVertexArrayOES(c))},Jc=a=>{var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=(c,e)=>b.drawBuffersWEBGL(c,e))},Kc=a=> +{var b="ANGLE_instanced_arrays EXT_blend_minmax EXT_disjoint_timer_query EXT_frag_depth EXT_shader_texture_load EXT_sRGB OES_element_index_uint OES_fbo_render_mipmap OES_standard_derivatives OES_texture_float OES_texture_half_float OES_texture_half_float_linear OES_vertex_array_object WEBGL_color_buffer_float WEBGL_depth_texture WEBGL_draw_buffers EXT_color_buffer_float EXT_conservative_depth EXT_disjoint_timer_query_webgl2 EXT_texture_norm16 NV_shader_noperspective_interpolation WEBGL_clip_cull_distance EXT_clip_control EXT_color_buffer_half_float EXT_depth_clamp EXT_float_blend EXT_polygon_offset_clamp EXT_texture_compression_bptc EXT_texture_compression_rgtc EXT_texture_filter_anisotropic KHR_parallel_shader_compile OES_texture_float_linear WEBGL_blend_func_extended WEBGL_compressed_texture_astc WEBGL_compressed_texture_etc WEBGL_compressed_texture_etc1 WEBGL_compressed_texture_s3tc WEBGL_compressed_texture_s3tc_srgb WEBGL_debug_renderer_info WEBGL_debug_shaders WEBGL_lose_context WEBGL_multi_draw WEBGL_polygon_mode".split(" "); +return(a.getSupportedExtensions()||[]).filter(c=>b.includes(c))},Lc=1,Mc=[],Nc=[],Oc=[],Pc=[],ka=[],Qc=[],Rc=[],pa=[],Sc=[],Tc=[],Uc=[],Wc={},Xc={},Yc=4,Zc=0,ja=a=>{for(var b=Lc++,c=a.length;c{for(var f=0;f>2]=n}},na=(a,b)=>{a.He||(a.He=a.getContext,a.getContext=function(e,f){f=a.He(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1{var c=ja(pa),e={handle:c,attributes:b,version:b.majorVersion,fe:a};a.canvas&&(a.canvas.Pe=e);pa[c]=e;("undefined"==typeof b.Ye||b.Ye)&&bd(e);return c},oa=a=>{z=pa[a];r.pf=R=z?.fe;return!(a&&!R)},bd=a=>{a||=z;if(!a.ff){a.ff=!0;var b=a.fe;b.tf=b.getExtension("WEBGL_multi_draw");b.rf=b.getExtension("EXT_polygon_offset_clamp");b.qf=b.getExtension("EXT_clip_control");b.vf=b.getExtension("WEBGL_polygon_mode");Hc(b);Ic(b);Jc(b);b.Je=b.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"); +b.Le=b.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance");2<=a.version&&(b.ge=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.ge)b.ge=b.getExtension("EXT_disjoint_timer_query");Kc(b).forEach(c=>{c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}},z,U,cd=(a,b)=>{R.bindFramebuffer(a,Oc[b])},dd=a=>{R.bindVertexArray(Rc[a])},ed=a=>R.clear(a),fd=(a,b,c,e)=>R.clearColor(a,b,c,e),gd=a=>R.clearStencil(a),hd=(a,b)=>{for(var c=0;c>2];R.deleteVertexArray(Rc[e]);Rc[e]=null}},jd=[],kd=(a,b)=>{$c(a,b,"createVertexArray",Rc)};function ld(){var a=Kc(R);return a=a.concat(a.map(b=>"GL_"+b))} +var md=(a,b,c)=>{if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&(U||=1280);return;case 34814:case 36345:e=0;break;case 34466:var f=R.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>z.version){U||=1282;return}e=ld().length;break;case 33307:case 33308:if(2>z.version){U||=1280;return}e=33307==a?3:0}if(void 0===e)switch(f=R.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":U||=1280;return;case "object":if(null===f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e= +0;break;default:U||=1280;return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a>2]=f[a];break;case 2:J[b+4*a>>2]=f[a];break;case 4:Ca[b+a]=f[a]?1:0}return}try{e=f.name|0}catch(k){U||=1280;ya(`GL_INVALID_ENUM in glGet${c}v: Unknown object returned from WebGL getParameter(${a})! (error: ${k})`);return}}break;default:U||=1280;ya(`GL_INVALID_ENUM in glGet${c}v: Native code calling glGet${c}v(${a}) and it returns ${f} of type ${typeof f}!`); +return}switch(c){case 1:c=e;H[b>>2]=c;H[b+4>>2]=(c-H[b>>2])/4294967296;break;case 0:E[b>>2]=e;break;case 2:J[b>>2]=e;break;case 4:Ca[b]=e?1:0}}else U||=1281},and=(a,b)=>md(a,b,0),od=(a,b,c)=>{if(c){a=Sc[a];b=2>z.version?R.ge.getQueryObjectEXT(a,b):R.getQueryParameter(a,b);var e;"boolean"==typeof b?e=b?1:0:e=b;H[c>>2]=e;H[c+4>>2]=(e-H[c>>2])/4294967296}else U||=1281},qd=a=>{var b=qa(a)+1,c=pd(b);c&&ra(a,c,b);return c},rd=a=>{var b=Wc[a];if(!b){switch(a){case 7939:b=qd(ld().join(" "));break;case 7936:case 7937:case 37445:case 37446:(b= +R.getParameter(a))||(U||=1280);b=b?qd(b):0;break;case 7938:b=R.getParameter(7938);var c=`OpenGL ES 2.0 (${b})`;2<=z.version&&(c=`OpenGL ES 3.0 (${b})`);b=qd(c);break;case 35724:b=R.getParameter(35724);c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b=`OpenGL ES GLSL ES ${c[1]} (${b})`);b=qd(b);break;default:U||=1280}Wc[a]=b}return b},sd=(a,b)=>{if(2>z.version)return U||=1282,0;var c=Xc[a];if(c)return 0>b||b>=c.length?(U||=1281,0):c[b];switch(a){case 7939:return c= +ld().map(qd),c=Xc[a]=c,0>b||b>=c.length?(U||=1281,0):c[b];default:return U||=1280,0}},td=a=>"]"==a.slice(-1)&&a.lastIndexOf("["),ud=a=>{a-=5120;return 0==a?Ca:1==a?B:2==a?Da:4==a?E:6==a?J:5==a||28922==a||28520==a||30779==a||30782==a?H:Fa},vd=(a,b,c,e,f)=>{a=ud(a);b=e*((Zc||c)*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*a.BYTES_PER_ELEMENT+Yc-1&-Yc);return a.subarray(f>>>31-Math.clz32(a.BYTES_PER_ELEMENT),f+b>>>31-Math.clz32(a.BYTES_PER_ELEMENT))},Y=a=>{var b=R.We;if(b){var c= +b.re[a];"number"==typeof c&&(b.re[a]=c=R.getUniformLocation(b,b.Ne[a]+(0{if(!zd){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:"./this.program"},b;for(b in yd)void 0===yd[b]?delete a[b]:a[b]=yd[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);zd=c}return zd},zd,Bd=[null,[],[]]; +kb=r.InternalError=class extends Error{constructor(a){super(a);this.name="InternalError"}};for(var Cd=Array(256),Dd=0;256>Dd;++Dd)Cd[Dd]=String.fromCharCode(Dd);nb=Cd;L=r.BindingError=class extends Error{constructor(a){super(a);this.name="BindingError"}}; +Object.assign(Eb.prototype,{isAliasOf:function(a){if(!(this instanceof Eb&&a instanceof Eb))return!1;var b=this.Sd.Yd.Wd,c=this.Sd.Vd;a.Sd=a.Sd;var e=a.Sd.Yd.Wd;for(a=a.Sd.Vd;b.ae;)c=b.se(c),b=b.ae;for(;e.ae;)a=e.se(a),e=e.ae;return b===e&&c===a},clone:function(){this.Sd.Vd||pb(this);if(this.Sd.qe)return this.Sd.count.value+=1,this;var a=Bb,b=Object,c=b.create,e=Object.getPrototypeOf(this),f=this.Sd;a=a(c.call(b,e,{Sd:{value:{count:f.count,pe:f.pe,qe:f.qe,Vd:f.Vd,Yd:f.Yd,Zd:f.Zd,ce:f.ce}}}));a.Sd.count.value+= +1;a.Sd.pe=!1;return a},["delete"](){this.Sd.Vd||pb(this);if(this.Sd.pe&&!this.Sd.qe)throw new L("Object already scheduled for deletion");rb(this);var a=this.Sd;--a.count.value;0===a.count.value&&(a.Zd?a.ce.he(a.Zd):a.Yd.Wd.he(a.Vd));this.Sd.qe||(this.Sd.Zd=void 0,this.Sd.Vd=void 0)},isDeleted:function(){return!this.Sd.Vd},deleteLater:function(){this.Sd.Vd||pb(this);if(this.Sd.pe&&!this.Sd.qe)throw new L("Object already scheduled for deletion");Db.push(this);this.Sd.pe=!0;return this}}); +Object.assign(Qb.prototype,{af(a){this.Me&&(a=this.Me(a));return a},Ie(a){this.he?.(a)},de:8,readValueFromPointer:gb,fromWireType:function(a){function b(){return this.xe?Cb(this.Wd.me,{Yd:this.gf,Vd:c,ce:this,Zd:a}):Cb(this.Wd.me,{Yd:this,Vd:a})}var c=this.af(a);if(!c)return this.Ie(a),null;var e=Ab(this.Wd,c);if(void 0!==e){if(0===e.Sd.count.value)return e.Sd.Vd=c,e.Sd.Zd=a,e.clone();e=e.clone();this.Ie(a);return e}e=this.Wd.$e(c);e=yb[e];if(!e)return b.call(this);e=this.we?e.Ve:e.pointerType;var f= +sb(c,this.Wd,e.Wd);return null===f?b.call(this):this.xe?Cb(e.Wd.me,{Yd:e,Vd:f,ce:this,Zd:a}):Cb(e.Wd.me,{Yd:e,Vd:f})}});ac=r.UnboundTypeError=((a,b)=>{var c=Fb(b,function(e){this.name=b;this.message=e;e=Error(e).stack;void 0!==e&&(this.stack=this.toString()+"\n"+e.replace(/^Error(:[^\n]*)?\n/,""))});c.prototype=Object.create(a.prototype);c.prototype.constructor=c;c.prototype.toString=function(){return void 0===this.message?this.name:`${this.name}: ${this.message}`};return c})(Error,"UnboundTypeError"); +kc.push(0,1,void 0,1,null,1,!0,1,!1,1);r.count_emval_handles=()=>kc.length/2-5-jc.length;for(var Ed=0;32>Ed;++Ed)jd.push(Array(Ed));var Fd=new Float32Array(288);for(Ed=0;288>=Ed;++Ed)wd[Ed]=Fd.subarray(0,Ed);var Gd=new Int32Array(288);for(Ed=0;288>=Ed;++Ed)xd[Ed]=Gd.subarray(0,Ed); +var Vd={F:(a,b,c)=>{var e=new Ya(a);H[e.Vd+16>>2]=0;H[e.Vd+4>>2]=b;H[e.Vd+8>>2]=c;Za=a;bb++;throw Za;},U:function(){return 0},ud:()=>{},td:function(){return 0},sd:()=>{},rd:function(){},qd:()=>{},md:()=>{Pa("")},B:a=>{var b=eb[a];delete eb[a];var c=b.Fe,e=b.he,f=b.Ke,k=f.map(n=>n.df).concat(f.map(n=>n.lf));mb([a],k,n=>{var l={};f.forEach((q,v)=>{var w=n[v],A=q.bf,D=q.cf,I=n[v+f.length],P=q.kf,O=q.mf;l[q.Ze]={read:aa=>w.fromWireType(A(D,aa)),write:(aa,la)=>{var X=[];P(O,aa,I.toWireType(X,la));fb(X)}}}); +return[{name:b.name,fromWireType:q=>{var v={},w;for(w in l)v[w]=l[w].read(q);e(q);return v},toWireType:(q,v)=>{for(var w in l)if(!(w in v))throw new TypeError(`Missing field: "${w}"`);var A=c();for(w in l)l[w].write(A,v[w]);null!==q&&q.push(e,A);return A},de:8,readValueFromPointer:gb,ee:e}]})},X:()=>{},ld:(a,b,c,e)=>{b=K(b);lb(a,{name:b,fromWireType:function(f){return!!f},toWireType:function(f,k){return k?c:e},de:8,readValueFromPointer:function(f){return this.fromWireType(B[f])},ee:null})},l:(a,b, +c,e,f,k,n,l,q,v,w,A,D)=>{w=K(w);k=Q(f,k);l&&=Q(n,l);v&&=Q(q,v);D=Q(A,D);var I=Ib(w);Hb(I,function(){ec(`Cannot construct ${w} due to unbound types`,[e])});mb([a,b,c],e?[e]:[],P=>{P=P[0];if(e){var O=P.Wd;var aa=O.me}else aa=Eb.prototype;P=Fb(w,function(...Ea){if(Object.getPrototypeOf(this)!==la)throw new L("Use 'new' to construct "+w);if(void 0===X.je)throw new L(w+" has no accessible constructor");var ea=X.je[Ea.length];if(void 0===ea)throw new L(`Tried to invoke ctor of ${w} with invalid number of parameters (${Ea.length}) - expected (${Object.keys(X.je).toString()}) parameters instead!`); +return ea.apply(this,Ea)});var la=Object.create(aa,{constructor:{value:P}});P.prototype=la;var X=new Jb(w,P,la,D,O,k,l,v);if(X.ae){var ha;(ha=X.ae).te??(ha.te=[]);X.ae.te.push(X)}O=new Qb(w,X,!0,!1,!1);ha=new Qb(w+"*",X,!1,!1,!1);aa=new Qb(w+" const*",X,!1,!0,!1);yb[a]={pointerType:ha,Ve:aa};Rb(I,P);return[O,ha,aa]})},e:(a,b,c,e,f,k,n)=>{var l=hc(c,e);b=K(b);b=ic(b);k=Q(f,k);mb([],[a],q=>{function v(){ec(`Cannot call ${w} due to unbound types`,l)}q=q[0];var w=`${q.name}.${b}`;b.startsWith("@@")&& +(b=Symbol[b.substring(2)]);var A=q.Wd.constructor;void 0===A[b]?(v.ie=c-1,A[b]=v):(Gb(A,b,w),A[b].$d[c-1]=v);mb([],l,D=>{D=[D[0],null].concat(D.slice(1));D=gc(w,D,null,k,n);void 0===A[b].$d?(D.ie=c-1,A[b]=D):A[b].$d[c-1]=D;if(q.Wd.te)for(const I of q.Wd.te)I.constructor.hasOwnProperty(b)||(I.constructor[b]=D);return[]});return[]})},z:(a,b,c,e,f,k)=>{var n=hc(b,c);f=Q(e,f);mb([],[a],l=>{l=l[0];var q=`constructor ${l.name}`;void 0===l.Wd.je&&(l.Wd.je=[]);if(void 0!==l.Wd.je[b-1])throw new L(`Cannot register multiple constructors with identical number of parameters (${b- +1}) for class '${l.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);l.Wd.je[b-1]=()=>{ec(`Cannot construct ${l.name} due to unbound types`,n)};mb([],n,v=>{v.splice(1,0,null);l.Wd.je[b-1]=gc(q,v,null,f,k);return[]});return[]})},a:(a,b,c,e,f,k,n,l)=>{var q=hc(c,e);b=K(b);b=ic(b);k=Q(f,k);mb([],[a],v=>{function w(){ec(`Cannot call ${A} due to unbound types`,q)}v=v[0];var A=`${v.name}.${b}`;b.startsWith("@@")&&(b=Symbol[b.substring(2)]);l&&v.Wd.hf.push(b); +var D=v.Wd.me,I=D[b];void 0===I||void 0===I.$d&&I.className!==v.name&&I.ie===c-2?(w.ie=c-2,w.className=v.name,D[b]=w):(Gb(D,b,A),D[b].$d[c-2]=w);mb([],q,P=>{P=gc(A,P,v,k,n);void 0===D[b].$d?(P.ie=c-2,D[b]=P):D[b].$d[c-2]=P;return[]});return[]})},q:(a,b,c)=>{a=K(a);mb([],[b],e=>{e=e[0];r[a]=e.fromWireType(c);return[]})},kd:a=>lb(a,nc),j:(a,b,c,e)=>{function f(){}b=K(b);f.values={};lb(a,{name:b,constructor:f,fromWireType:function(k){return this.constructor.values[k]},toWireType:(k,n)=>n.value,de:8, +readValueFromPointer:oc(b,c,e),ee:null});Hb(b,f)},b:(a,b,c)=>{var e=pc(a,"enum");b=K(b);a=e.constructor;e=Object.create(e.constructor.prototype,{value:{value:c},constructor:{value:Fb(`${e.name}_${b}`,function(){})}});a.values[c]=e;a[b]=e},R:(a,b,c)=>{b=K(b);lb(a,{name:b,fromWireType:e=>e,toWireType:(e,f)=>f,de:8,readValueFromPointer:qc(b,c),ee:null})},w:(a,b,c,e,f,k)=>{var n=hc(b,c);a=K(a);a=ic(a);f=Q(e,f);Hb(a,function(){ec(`Cannot call ${a} due to unbound types`,n)},b-1);mb([],n,l=>{l=[l[0],null].concat(l.slice(1)); +Rb(a,gc(a,l,null,f,k),b-1);return[]})},C:(a,b,c,e,f)=>{b=K(b);-1===f&&(f=4294967295);f=l=>l;if(0===e){var k=32-8*c;f=l=>l<>>k}var n=b.includes("unsigned")?function(l,q){return q>>>0}:function(l,q){return q};lb(a,{name:b,fromWireType:f,toWireType:n,de:8,readValueFromPointer:rc(b,c,0!==e),ee:null})},p:(a,b,c)=>{function e(k){return new f(Ca.buffer,H[k+4>>2],H[k>>2])}var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][b];c=K(c);lb(a,{name:c,fromWireType:e, +de:8,readValueFromPointer:e},{ef:!0})},o:(a,b,c,e,f,k,n,l,q,v,w,A)=>{c=K(c);k=Q(f,k);l=Q(n,l);v=Q(q,v);A=Q(w,A);mb([a],[b],D=>{D=D[0];return[new Qb(c,D.Wd,!1,!1,!0,D,e,k,l,v,A)]})},Q:(a,b)=>{b=K(b);var c="std::string"===b;lb(a,{name:b,fromWireType:function(e){var f=H[e>>2],k=e+4;if(c)for(var n=k,l=0;l<=f;++l){var q=k+l;if(l==f||0==B[q]){n=n?db(B,n,q-n):"";if(void 0===v)var v=n;else v+=String.fromCharCode(0),v+=n;n=q+1}}else{v=Array(f);for(l=0;l>2]=n;if(c&&k)ra(f,q,n+1);else if(k)for(k=0;k{c=K(c);if(2===b){var e=tc;var f=uc;var k=vc;var n=l=>Fa[l>>1]}else 4===b&&(e=wc,f=xc,k=yc,n=l=>H[l>>2]);lb(a,{name:c,fromWireType:l=>{for(var q=H[l>>2],v,w=l+4,A=0;A<=q;++A){var D=l+4+A*b;if(A==q||0==n(D))w=e(w,D-w),void 0===v?v=w:(v+=String.fromCharCode(0),v+=w),w=D+b}cc(l);return v},toWireType:(l,q)=>{if("string"!=typeof q)throw new L(`Cannot pass non-string to C++ string type ${c}`);var v=k(q),w=pd(4+v+b); +H[w>>2]=v/b;f(q,w+4,v+b);null!==l&&l.push(cc,w);return w},de:8,readValueFromPointer:gb,ee(l){cc(l)}})},A:(a,b,c,e,f,k)=>{eb[a]={name:K(b),Fe:Q(c,e),he:Q(f,k),Ke:[]}},d:(a,b,c,e,f,k,n,l,q,v)=>{eb[a].Ke.push({Ze:K(b),df:c,bf:Q(e,f),cf:k,lf:n,kf:Q(l,q),mf:v})},jd:(a,b)=>{b=K(b);lb(a,{sf:!0,name:b,de:0,fromWireType:()=>{},toWireType:()=>{}})},id:()=>1,hd:()=>{throw Infinity;},E:(a,b,c)=>{a=mc(a);b=pc(b,"emval::as");return zc(b,c,a)},L:(a,b,c,e)=>{a=Ac[a];b=mc(b);return a(null,b,c,e)},t:(a,b,c,e,f)=>{a= +Ac[a];b=mc(b);c=Cc(c);return a(b,b[c],e,f)},c:lc,K:a=>{if(0===a)return Ob(Dc());a=Cc(a);return Ob(Dc()[a])},n:(a,b,c)=>{var e=Fc(a,b),f=e.shift();a--;var k=Array(a);b=`methodCaller<(${e.map(n=>n.name).join(", ")}) => ${f.name}>`;return Ec(Fb(b,(n,l,q,v)=>{for(var w=0,A=0;A{a=mc(a);b=mc(b);return Ob(a[b])},H:a=>{9Ob([]),f:a=>Ob(Cc(a)),D:()=>Ob({}),gd:a=>{a=mc(a); +return!a},m:a=>{var b=mc(a);fb(b);lc(a)},h:(a,b,c)=>{a=mc(a);b=mc(b);c=mc(c);a[b]=c},g:(a,b)=>{a=pc(a,"_emval_take_value");a=a.readValueFromPointer(b);return Ob(a)},W:function(){return-52},V:function(){},fd:(a,b,c,e)=>{var f=(new Date).getFullYear(),k=(new Date(f,0,1)).getTimezoneOffset();f=(new Date(f,6,1)).getTimezoneOffset();H[a>>2]=60*Math.max(k,f);E[b>>2]=Number(k!=f);b=n=>{var l=Math.abs(n);return`UTC${0<=n?"-":"+"}${String(Math.floor(l/60)).padStart(2,"0")}${String(l%60).padStart(2,"0")}`}; +a=b(k);b=b(f);fperformance.now(),dd:a=>R.activeTexture(a),cd:(a,b)=>{R.attachShader(Nc[a],Qc[b])},bd:(a,b)=>{R.beginQuery(a,Sc[b])},ad:(a,b)=>{R.ge.beginQueryEXT(a,Sc[b])},$c:(a,b,c)=>{R.bindAttribLocation(Nc[a],b,c?db(B,c):"")},_c:(a,b)=>{35051==a?R.Ce=b:35052==a&&(R.le=b);R.bindBuffer(a,Mc[b])},Zc:cd,Yc:(a,b)=>{R.bindRenderbuffer(a,Pc[b])},Xc:(a,b)=>{R.bindSampler(a,Tc[b])},Wc:(a,b)=>{R.bindTexture(a,ka[b])},Vc:dd,Uc:dd,Tc:(a,b,c,e)=>R.blendColor(a, +b,c,e),Sc:a=>R.blendEquation(a),Rc:(a,b)=>R.blendFunc(a,b),Qc:(a,b,c,e,f,k,n,l,q,v)=>R.blitFramebuffer(a,b,c,e,f,k,n,l,q,v),Pc:(a,b,c,e)=>{2<=z.version?c&&b?R.bufferData(a,B,e,c,b):R.bufferData(a,b,e):R.bufferData(a,c?B.subarray(c,c+b):b,e)},Oc:(a,b,c,e)=>{2<=z.version?c&&R.bufferSubData(a,b,B,e,c):R.bufferSubData(a,b,B.subarray(e,e+c))},Nc:a=>R.checkFramebufferStatus(a),Mc:ed,Lc:fd,Kc:gd,Jc:(a,b,c,e)=>R.clientWaitSync(Uc[a],b,(c>>>0)+4294967296*e),Ic:(a,b,c,e)=>{R.colorMask(!!a,!!b,!!c,!!e)},Hc:a=> +{R.compileShader(Qc[a])},Gc:(a,b,c,e,f,k,n,l)=>{2<=z.version?R.le||!n?R.compressedTexImage2D(a,b,c,e,f,k,n,l):R.compressedTexImage2D(a,b,c,e,f,k,B,l,n):R.compressedTexImage2D(a,b,c,e,f,k,B.subarray(l,l+n))},Fc:(a,b,c,e,f,k,n,l,q)=>{2<=z.version?R.le||!l?R.compressedTexSubImage2D(a,b,c,e,f,k,n,l,q):R.compressedTexSubImage2D(a,b,c,e,f,k,n,B,q,l):R.compressedTexSubImage2D(a,b,c,e,f,k,n,B.subarray(q,q+l))},Ec:(a,b,c,e,f)=>R.copyBufferSubData(a,b,c,e,f),Dc:(a,b,c,e,f,k,n,l)=>R.copyTexSubImage2D(a,b,c, +e,f,k,n,l),Cc:()=>{var a=ja(Nc),b=R.createProgram();b.name=a;b.Ae=b.ye=b.ze=0;b.Ge=1;Nc[a]=b;return a},Bc:a=>{var b=ja(Qc);Qc[b]=R.createShader(a);return b},Ac:a=>R.cullFace(a),zc:(a,b)=>{for(var c=0;c>2],f=Mc[e];f&&(R.deleteBuffer(f),f.name=0,Mc[e]=null,e==R.Ce&&(R.Ce=0),e==R.le&&(R.le=0))}},yc:(a,b)=>{for(var c=0;c>2],f=Oc[e];f&&(R.deleteFramebuffer(f),f.name=0,Oc[e]=null)}},xc:a=>{if(a){var b=Nc[a];b?(R.deleteProgram(b),b.name=0,Nc[a]=null):U||=1281}}, +wc:(a,b)=>{for(var c=0;c>2],f=Sc[e];f&&(R.deleteQuery(f),Sc[e]=null)}},vc:(a,b)=>{for(var c=0;c>2],f=Sc[e];f&&(R.ge.deleteQueryEXT(f),Sc[e]=null)}},uc:(a,b)=>{for(var c=0;c>2],f=Pc[e];f&&(R.deleteRenderbuffer(f),f.name=0,Pc[e]=null)}},tc:(a,b)=>{for(var c=0;c>2],f=Tc[e];f&&(R.deleteSampler(f),f.name=0,Tc[e]=null)}},sc:a=>{if(a){var b=Qc[a];b?(R.deleteShader(b),Qc[a]=null):U||=1281}},rc:a=>{if(a){var b=Uc[a];b? +(R.deleteSync(b),b.name=0,Uc[a]=null):U||=1281}},qc:(a,b)=>{for(var c=0;c>2],f=ka[e];f&&(R.deleteTexture(f),f.name=0,ka[e]=null)}},pc:hd,oc:hd,nc:a=>{R.depthMask(!!a)},mc:a=>R.disable(a),lc:a=>{R.disableVertexAttribArray(a)},kc:(a,b,c)=>{R.drawArrays(a,b,c)},jc:(a,b,c,e)=>{R.drawArraysInstanced(a,b,c,e)},ic:(a,b,c,e,f)=>{R.Je.drawArraysInstancedBaseInstanceWEBGL(a,b,c,e,f)},hc:(a,b)=>{for(var c=jd[a],e=0;e>2];R.drawBuffers(c)},gc:(a,b,c,e)=>{R.drawElements(a, +b,c,e)},fc:(a,b,c,e,f)=>{R.drawElementsInstanced(a,b,c,e,f)},ec:(a,b,c,e,f,k,n)=>{R.Je.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,b,c,e,f,k,n)},dc:(a,b,c,e,f,k)=>{R.drawElements(a,e,f,k)},cc:a=>R.enable(a),bc:a=>{R.enableVertexAttribArray(a)},ac:a=>R.endQuery(a),$b:a=>{R.ge.endQueryEXT(a)},_b:(a,b)=>(a=R.fenceSync(a,b))?(b=ja(Uc),a.name=b,Uc[b]=a,b):0,Zb:()=>R.finish(),Yb:()=>R.flush(),Xb:(a,b,c,e)=>{R.framebufferRenderbuffer(a,b,c,Pc[e])},Wb:(a,b,c,e,f)=>{R.framebufferTexture2D(a,b,c,ka[e], +f)},Vb:a=>R.frontFace(a),Ub:(a,b)=>{$c(a,b,"createBuffer",Mc)},Tb:(a,b)=>{$c(a,b,"createFramebuffer",Oc)},Sb:(a,b)=>{$c(a,b,"createQuery",Sc)},Rb:(a,b)=>{for(var c=0;c>2]=0;break}var f=ja(Sc);e.name=f;Sc[f]=e;E[b+4*c>>2]=f}},Qb:(a,b)=>{$c(a,b,"createRenderbuffer",Pc)},Pb:(a,b)=>{$c(a,b,"createSampler",Tc)},Ob:(a,b)=>{$c(a,b,"createTexture",ka)},Nb:kd,Mb:kd,Lb:a=>R.generateMipmap(a),Kb:(a,b,c)=>{c?E[c>>2]=R.getBufferParameter(a, +b):U||=1281},Jb:()=>{var a=R.getError()||U;U=0;return a},Ib:(a,b)=>md(a,b,2),Hb:(a,b,c,e)=>{a=R.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;E[e>>2]=a},Gb:and,Fb:(a,b,c,e)=>{a=R.getProgramInfoLog(Nc[a]);null===a&&(a="(unknown error)");b=0>2]=b)},Eb:(a,b,c)=>{if(c)if(a>=Lc)U||=1281;else if(a=Nc[a],35716==b)a=R.getProgramInfoLog(a),null===a&&(a="(unknown error)"),E[c>>2]=a.length+1;else if(35719==b){if(!a.Ae){var e= +R.getProgramParameter(a,35718);for(b=0;b>2]=a.Ae}else if(35722==b){if(!a.ye)for(e=R.getProgramParameter(a,35721),b=0;b>2]=a.ye}else if(35381==b){if(!a.ze)for(e=R.getProgramParameter(a,35382),b=0;b>2]=a.ze}else E[c>>2]=R.getProgramParameter(a,b);else U||=1281},Db:od,Cb:od,Bb:(a,b,c)=>{if(c){a= +R.getQueryParameter(Sc[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;E[c>>2]=e}else U||=1281},Ab:(a,b,c)=>{if(c){a=R.ge.getQueryObjectEXT(Sc[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;E[c>>2]=e}else U||=1281},zb:(a,b,c)=>{c?E[c>>2]=R.getQuery(a,b):U||=1281},yb:(a,b,c)=>{c?E[c>>2]=R.ge.getQueryEXT(a,b):U||=1281},xb:(a,b,c)=>{c?E[c>>2]=R.getRenderbufferParameter(a,b):U||=1281},wb:(a,b,c,e)=>{a=R.getShaderInfoLog(Qc[a]);null===a&&(a="(unknown error)");b=0>2]=b)},vb:(a,b,c,e)=> +{a=R.getShaderPrecisionFormat(a,b);E[c>>2]=a.rangeMin;E[c+4>>2]=a.rangeMax;E[e>>2]=a.precision},ub:(a,b,c)=>{c?35716==b?(a=R.getShaderInfoLog(Qc[a]),null===a&&(a="(unknown error)"),E[c>>2]=a?a.length+1:0):35720==b?(a=R.getShaderSource(Qc[a]),E[c>>2]=a?a.length+1:0):E[c>>2]=R.getShaderParameter(Qc[a],b):U||=1281},tb:rd,sb:sd,rb:(a,b)=>{b=b?db(B,b):"";if(a=Nc[a]){var c=a,e=c.re,f=c.Oe,k;if(!e){c.re=e={};c.Ne={};var n=R.getProgramParameter(c,35718);for(k=0;k>>0,f=b.slice(0,k));if((f=a.Oe[f])&&e{for(var e=jd[b],f=0;f>2];R.invalidateFramebuffer(a,e)},pb:(a,b,c,e,f,k,n)=>{for(var l=jd[b],q=0;q>2];R.invalidateSubFramebuffer(a,l,e,f,k,n)},ob:a=>R.isSync(Uc[a]), +nb:a=>(a=ka[a])?R.isTexture(a):0,mb:a=>R.lineWidth(a),lb:a=>{a=Nc[a];R.linkProgram(a);a.re=0;a.Oe={}},kb:(a,b,c,e,f,k)=>{R.Le.multiDrawArraysInstancedBaseInstanceWEBGL(a,E,b>>2,E,c>>2,E,e>>2,H,f>>2,k)},jb:(a,b,c,e,f,k,n,l)=>{R.Le.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,E,b>>2,c,E,e>>2,E,f>>2,E,k>>2,H,n>>2,l)},ib:(a,b)=>{3317==a?Yc=b:3314==a&&(Zc=b);R.pixelStorei(a,b)},hb:(a,b)=>{R.ge.queryCounterEXT(Sc[a],b)},gb:a=>R.readBuffer(a),fb:(a,b,c,e,f,k,n)=>{if(2<=z.version)if(R.Ce)R.readPixels(a, +b,c,e,f,k,n);else{var l=ud(k);n>>>=31-Math.clz32(l.BYTES_PER_ELEMENT);R.readPixels(a,b,c,e,f,k,l,n)}else(l=vd(k,f,c,e,n))?R.readPixels(a,b,c,e,f,k,l):U||=1280},eb:(a,b,c,e)=>R.renderbufferStorage(a,b,c,e),db:(a,b,c,e,f)=>R.renderbufferStorageMultisample(a,b,c,e,f),cb:(a,b,c)=>{R.samplerParameterf(Tc[a],b,c)},bb:(a,b,c)=>{R.samplerParameteri(Tc[a],b,c)},ab:(a,b,c)=>{R.samplerParameteri(Tc[a],b,E[c>>2])},$a:(a,b,c,e)=>R.scissor(a,b,c,e),_a:(a,b,c,e)=>{for(var f="",k=0;k>2])? +db(B,n,e?H[e+4*k>>2]:void 0):"";f+=n}R.shaderSource(Qc[a],f)},Za:(a,b,c)=>R.stencilFunc(a,b,c),Ya:(a,b,c,e)=>R.stencilFuncSeparate(a,b,c,e),Xa:a=>R.stencilMask(a),Wa:(a,b)=>R.stencilMaskSeparate(a,b),Va:(a,b,c)=>R.stencilOp(a,b,c),Ua:(a,b,c,e)=>R.stencilOpSeparate(a,b,c,e),Ta:(a,b,c,e,f,k,n,l,q)=>{if(2<=z.version){if(R.le){R.texImage2D(a,b,c,e,f,k,n,l,q);return}if(q){var v=ud(l);q>>>=31-Math.clz32(v.BYTES_PER_ELEMENT);R.texImage2D(a,b,c,e,f,k,n,l,v,q);return}}v=q?vd(l,n,e,f,q):null;R.texImage2D(a, +b,c,e,f,k,n,l,v)},Sa:(a,b,c)=>R.texParameterf(a,b,c),Ra:(a,b,c)=>{R.texParameterf(a,b,J[c>>2])},Qa:(a,b,c)=>R.texParameteri(a,b,c),Pa:(a,b,c)=>{R.texParameteri(a,b,E[c>>2])},Oa:(a,b,c,e,f)=>R.texStorage2D(a,b,c,e,f),Na:(a,b,c,e,f,k,n,l,q)=>{if(2<=z.version){if(R.le){R.texSubImage2D(a,b,c,e,f,k,n,l,q);return}if(q){var v=ud(l);R.texSubImage2D(a,b,c,e,f,k,n,l,v,q>>>31-Math.clz32(v.BYTES_PER_ELEMENT));return}}q=q?vd(l,n,f,k,q):null;R.texSubImage2D(a,b,c,e,f,k,n,l,q)},Ma:(a,b)=>{R.uniform1f(Y(a),b)},La:(a, +b,c)=>{if(2<=z.version)b&&R.uniform1fv(Y(a),J,c>>2,b);else{if(288>=b)for(var e=wd[b],f=0;f>2];else e=J.subarray(c>>2,c+4*b>>2);R.uniform1fv(Y(a),e)}},Ka:(a,b)=>{R.uniform1i(Y(a),b)},Ja:(a,b,c)=>{if(2<=z.version)b&&R.uniform1iv(Y(a),E,c>>2,b);else{if(288>=b)for(var e=xd[b],f=0;f>2];else e=E.subarray(c>>2,c+4*b>>2);R.uniform1iv(Y(a),e)}},Ia:(a,b,c)=>{R.uniform2f(Y(a),b,c)},Ha:(a,b,c)=>{if(2<=z.version)b&&R.uniform2fv(Y(a),J,c>>2,2*b);else{if(144>=b){b*=2;for(var e= +wd[b],f=0;f>2],e[f+1]=J[c+(4*f+4)>>2]}else e=J.subarray(c>>2,c+8*b>>2);R.uniform2fv(Y(a),e)}},Ga:(a,b,c)=>{R.uniform2i(Y(a),b,c)},Fa:(a,b,c)=>{if(2<=z.version)b&&R.uniform2iv(Y(a),E,c>>2,2*b);else{if(144>=b){b*=2;for(var e=xd[b],f=0;f>2],e[f+1]=E[c+(4*f+4)>>2]}else e=E.subarray(c>>2,c+8*b>>2);R.uniform2iv(Y(a),e)}},Ea:(a,b,c,e)=>{R.uniform3f(Y(a),b,c,e)},Da:(a,b,c)=>{if(2<=z.version)b&&R.uniform3fv(Y(a),J,c>>2,3*b);else{if(96>=b){b*=3;for(var e=wd[b],f=0;f< +b;f+=3)e[f]=J[c+4*f>>2],e[f+1]=J[c+(4*f+4)>>2],e[f+2]=J[c+(4*f+8)>>2]}else e=J.subarray(c>>2,c+12*b>>2);R.uniform3fv(Y(a),e)}},Ca:(a,b,c,e)=>{R.uniform3i(Y(a),b,c,e)},Ba:(a,b,c)=>{if(2<=z.version)b&&R.uniform3iv(Y(a),E,c>>2,3*b);else{if(96>=b){b*=3;for(var e=xd[b],f=0;f>2],e[f+1]=E[c+(4*f+4)>>2],e[f+2]=E[c+(4*f+8)>>2]}else e=E.subarray(c>>2,c+12*b>>2);R.uniform3iv(Y(a),e)}},Aa:(a,b,c,e,f)=>{R.uniform4f(Y(a),b,c,e,f)},za:(a,b,c)=>{if(2<=z.version)b&&R.uniform4fv(Y(a),J,c>>2,4* +b);else{if(72>=b){var e=wd[4*b],f=J;c>>=2;b*=4;for(var k=0;k>2,c+16*b>>2);R.uniform4fv(Y(a),e)}},ya:(a,b,c,e,f)=>{R.uniform4i(Y(a),b,c,e,f)},xa:(a,b,c)=>{if(2<=z.version)b&&R.uniform4iv(Y(a),E,c>>2,4*b);else{if(72>=b){b*=4;for(var e=xd[b],f=0;f>2],e[f+1]=E[c+(4*f+4)>>2],e[f+2]=E[c+(4*f+8)>>2],e[f+3]=E[c+(4*f+12)>>2]}else e=E.subarray(c>>2,c+16*b>>2);R.uniform4iv(Y(a),e)}},wa:(a,b,c,e)=> +{if(2<=z.version)b&&R.uniformMatrix2fv(Y(a),!!c,J,e>>2,4*b);else{if(72>=b){b*=4;for(var f=wd[b],k=0;k>2],f[k+1]=J[e+(4*k+4)>>2],f[k+2]=J[e+(4*k+8)>>2],f[k+3]=J[e+(4*k+12)>>2]}else f=J.subarray(e>>2,e+16*b>>2);R.uniformMatrix2fv(Y(a),!!c,f)}},va:(a,b,c,e)=>{if(2<=z.version)b&&R.uniformMatrix3fv(Y(a),!!c,J,e>>2,9*b);else{if(32>=b){b*=9;for(var f=wd[b],k=0;k>2],f[k+1]=J[e+(4*k+4)>>2],f[k+2]=J[e+(4*k+8)>>2],f[k+3]=J[e+(4*k+12)>>2],f[k+4]=J[e+(4*k+16)>>2],f[k+ +5]=J[e+(4*k+20)>>2],f[k+6]=J[e+(4*k+24)>>2],f[k+7]=J[e+(4*k+28)>>2],f[k+8]=J[e+(4*k+32)>>2]}else f=J.subarray(e>>2,e+36*b>>2);R.uniformMatrix3fv(Y(a),!!c,f)}},ua:(a,b,c,e)=>{if(2<=z.version)b&&R.uniformMatrix4fv(Y(a),!!c,J,e>>2,16*b);else{if(18>=b){var f=wd[16*b],k=J;e>>=2;b*=16;for(var n=0;n>2,e+64*b>>2);R.uniformMatrix4fv(Y(a),!!c,f)}},ta:a=>{a=Nc[a];R.useProgram(a);R.We=a},sa:(a,b)=>R.vertexAttrib1f(a,b),ra:(a,b)=>{R.vertexAttrib2f(a,J[b>>2],J[b+4>>2])},qa:(a,b)=>{R.vertexAttrib3f(a,J[b>>2],J[b+4>>2],J[b+8>>2])},pa:(a,b)=>{R.vertexAttrib4f(a,J[b>>2],J[b+4>>2],J[b+8>>2],J[b+12>>2])},oa:(a,b)=>{R.vertexAttribDivisor(a,b)},na:(a,b,c,e,f)=>{R.vertexAttribIPointer(a,b,c,e,f)},ma:(a,b,c,e,f,k)=>{R.vertexAttribPointer(a,b,c, +!!e,f,k)},la:(a,b,c,e)=>R.viewport(a,b,c,e),ka:(a,b,c,e)=>{R.waitSync(Uc[a],b,(c>>>0)+4294967296*e)},ja:a=>{var b=B.length;a>>>=0;if(2147483648=c;c*=2){var e=b*(1+1/c);e=Math.min(e,a+100663296);a:{e=(Math.min(2147483648,65536*Math.ceil(Math.max(a,e)/65536))-za.buffer.byteLength+65535)/65536|0;try{za.grow(e);Ha();var f=1;break a}catch(k){}f=void 0}if(f)return!0}return!1},ia:()=>z?z.handle:0,pd:(a,b)=>{var c=0;Ad().forEach((e,f)=>{var k=b+c;f=H[a+4*f>>2]=k;for(k=0;k{var c=Ad();H[a>>2]=c.length;var e=0;c.forEach(f=>e+=f.length+1);H[b>>2]=e;return 0},ha:a=>{Xa||(Ba=!0);throw new Va(a);},T:()=>52,Z:function(){return 52},and:()=>52,Y:function(){return 70},S:(a,b,c,e)=>{for(var f=0,k=0;k>2],l=H[b+4>>2];b+=8;for(var q=0;q>2]=f;return 0},ga:cd,fa:ed,ea:fd,da:gd,J:and,P:rd,ca:sd,k:Hd,u:Id,i:Jd,I:Kd, +ba:Ld,O:Md,N:And,s:Od,x:Pd,r:Qd,v:Rd,aa:Sd,$:Td,_:Ud},Z=function(){function a(c){Z=c.exports;za=Z.vd;Ha();N=Z.yd;Ja.unshift(Z.wd);La--;0==La&&(null!==Na&&(clearInterval(Na),Na=null),Oa&&(c=Oa,Oa=null,c()));return Z}var b={a:Vd};La++;if(r.instantiateWasm)try{return r.instantiateWasm(b,a)}catch(c){ya(`Module.instantiateWasm callback failed with error: ${c}`),ca(c)}Ra??=r.locateFile?Qa("canvaskit.wasm")?"canvaskit.wasm":ta+"canvaskit.wasm":(new URL("canvaskit.wasm",import.meta.url)).href;Ua(b, +function(c){a(c.instance)}).catch(ca);return{}}(),bc=a=>(bc=Z.xd)(a),pd=r._malloc=a=>(pd=r._malloc=Z.zd)(a),cc=r._free=a=>(cc=r._free=Z.Ad)(a),Wd=(a,b)=>(Wd=Z.Bd)(a,b),Xd=a=>(Xd=Z.Cd)(a),Yd=()=>(Yd=Z.Dd)();r.dynCall_viji=(a,b,c,e,f)=>(r.dynCall_viji=Z.Ed)(a,b,c,e,f);r.dynCall_vijiii=(a,b,c,e,f,k,n)=>(r.dynCall_vijiii=Z.Fd)(a,b,c,e,f,k,n);r.dynCall_viiiiij=(a,b,c,e,f,k,n,l)=>(r.dynCall_viiiiij=Z.Gd)(a,b,c,e,f,k,n,l);r.dynCall_jii=(a,b,c)=>(r.dynCall_jii=Z.Hd)(a,b,c); +r.dynCall_vij=(a,b,c,e)=>(r.dynCall_vij=Z.Id)(a,b,c,e);r.dynCall_jiiiiii=(a,b,c,e,f,k,n)=>(r.dynCall_jiiiiii=Z.Jd)(a,b,c,e,f,k,n);r.dynCall_jiiiiji=(a,b,c,e,f,k,n,l)=>(r.dynCall_jiiiiji=Z.Kd)(a,b,c,e,f,k,n,l);r.dynCall_ji=(a,b)=>(r.dynCall_ji=Z.Ld)(a,b);r.dynCall_iijj=(a,b,c,e,f,k)=>(r.dynCall_iijj=Z.Md)(a,b,c,e,f,k);r.dynCall_jiji=(a,b,c,e,f)=>(r.dynCall_jiji=Z.And)(a,b,c,e,f);r.dynCall_viijii=(a,b,c,e,f,k,n)=>(r.dynCall_viijii=Z.Od)(a,b,c,e,f,k,n); +r.dynCall_iiiiij=(a,b,c,e,f,k,n)=>(r.dynCall_iiiiij=Z.Pd)(a,b,c,e,f,k,n);r.dynCall_iiiiijj=(a,b,c,e,f,k,n,l,q)=>(r.dynCall_iiiiijj=Z.Qd)(a,b,c,e,f,k,n,l,q);r.dynCall_iiiiiijj=(a,b,c,e,f,k,n,l,q,v)=>(r.dynCall_iiiiiijj=Z.Rd)(a,b,c,e,f,k,n,l,q,v);function Rd(a,b,c,e,f){var k=Yd();try{N.get(a)(b,c,e,f)}catch(n){Xd(k);if(n!==n+0)throw n;Wd(1,0)}}function Id(a,b,c){var e=Yd();try{return N.get(a)(b,c)}catch(f){Xd(e);if(f!==f+0)throw f;Wd(1,0)}} +function Pd(a,b,c){var e=Yd();try{N.get(a)(b,c)}catch(f){Xd(e);if(f!==f+0)throw f;Wd(1,0)}}function Hd(a,b){var c=Yd();try{return N.get(a)(b)}catch(e){Xd(c);if(e!==e+0)throw e;Wd(1,0)}}function Od(a,b){var c=Yd();try{N.get(a)(b)}catch(e){Xd(c);if(e!==e+0)throw e;Wd(1,0)}}function Jd(a,b,c,e){var f=Yd();try{return N.get(a)(b,c,e)}catch(k){Xd(f);if(k!==k+0)throw k;Wd(1,0)}}function Ud(a,b,c,e,f,k,n,l,q,v){var w=Yd();try{N.get(a)(b,c,e,f,k,n,l,q,v)}catch(A){Xd(w);if(A!==A+0)throw A;Wd(1,0)}} +function Qd(a,b,c,e){var f=Yd();try{N.get(a)(b,c,e)}catch(k){Xd(f);if(k!==k+0)throw k;Wd(1,0)}}function Td(a,b,c,e,f,k,n){var l=Yd();try{N.get(a)(b,c,e,f,k,n)}catch(q){Xd(l);if(q!==q+0)throw q;Wd(1,0)}}function Md(a,b,c,e,f,k,n,l){var q=Yd();try{return N.get(a)(b,c,e,f,k,n,l)}catch(v){Xd(q);if(v!==v+0)throw v;Wd(1,0)}}function Sd(a,b,c,e,f,k){var n=Yd();try{N.get(a)(b,c,e,f,k)}catch(l){Xd(n);if(l!==l+0)throw l;Wd(1,0)}} +function Kd(a,b,c,e,f){var k=Yd();try{return N.get(a)(b,c,e,f)}catch(n){Xd(k);if(n!==n+0)throw n;Wd(1,0)}}function And(a,b,c,e,f,k,n,l,q,v){var w=Yd();try{return N.get(a)(b,c,e,f,k,n,l,q,v)}catch(A){Xd(w);if(A!==A+0)throw A;Wd(1,0)}}function Ld(a,b,c,e,f,k,n){var l=Yd();try{return N.get(a)(b,c,e,f,k,n)}catch(q){Xd(l);if(q!==q+0)throw q;Wd(1,0)}}var Zd,$d;Oa=function ae(){Zd||be();Zd||(Oa=ae)}; +function be(){if(!(0\28SkColorSpace*\29 +240:__memcpy +241:SkString::~SkString\28\29 +242:__memset +243:GrGLSLShaderBuilder::codeAppendf\28char\20const*\2c\20...\29 +244:SkColorInfo::~SkColorInfo\28\29 +245:SkData::~SkData\28\29 +246:SkString::SkString\28\29 +247:SkContainerAllocator::allocate\28int\2c\20double\29 +248:memmove +249:SkString::insert\28unsigned\20long\2c\20char\20const*\29 +250:SkDebugf\28char\20const*\2c\20...\29 +251:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::~__func\28\29 +252:SkPath::~SkPath\28\29 +253:hb_blob_destroy +254:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\29 +255:memcmp +256:sk_report_container_overflow_and_die\28\29 +257:SkArenaAlloc::ensureSpace\28unsigned\20int\2c\20unsigned\20int\29 +258:SkSL::ErrorReporter::error\28SkSL::Position\2c\20std::__2::basic_string_view>\29 +259:ft_mem_free +260:SkRasterPipeline::append\28SkRasterPipelineOp\2c\20void*\29 +261:SkString::SkString\28char\20const*\29 +262:FT_MulFix +263:emscripten::default_smart_ptr_trait>::share\28void*\29 +264:__wasm_setjmp_test +265:SkTDStorage::append\28\29 +266:SkMatrix::computeTypeMask\28\29\20const +267:SkWriter32::growToAtLeast\28unsigned\20long\29 +268:GrGpuResource::notifyARefCntIsZero\28GrIORef::LastRemovedRef\29\20const +269:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\2c\20unsigned\20long\29 +270:fmaxf +271:std::__2::basic_string\2c\20std::__2::allocator>::size\5babi:nn180100\5d\28\29\20const +272:SkString::SkString\28SkString&&\29 +273:SkSL::Pool::AllocMemory\28unsigned\20long\29 +274:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:ne180100\5d\28\29\20const +275:strlen +276:GrColorInfo::~GrColorInfo\28\29 +277:SkIRect::intersect\28SkIRect\20const&\2c\20SkIRect\20const&\29 +278:GrBackendFormat::~GrBackendFormat\28\29 +279:std::__2::basic_string\2c\20std::__2::allocator>::insert\28unsigned\20long\2c\20char\20const*\29 +280:std::__2::vector>::__throw_length_error\5babi:ne180100\5d\28\29\20const +281:GrContext_Base::caps\28\29\20const +282:SkPaint::~SkPaint\28\29 +283:SkTDStorage::~SkTDStorage\28\29 +284:SkSL::RP::Generator::pushExpression\28SkSL::Expression\20const&\2c\20bool\29 +285:void\20emscripten::internal::raw_destructor\28SkContourMeasure*\29 +286:SkTDStorage::SkTDStorage\28int\29 +287:SkStrokeRec::getStyle\28\29\20const +288:sk_malloc_throw\28unsigned\20long\2c\20unsigned\20long\29 +289:strcmp +290:SkString::SkString\28SkString\20const&\29 +291:hb_ot_map_builder_t::add_feature\28unsigned\20int\2c\20hb_ot_map_feature_flags_t\2c\20unsigned\20int\29 +292:SkMatrix::mapRect\28SkRect*\2c\20SkRect\20const&\2c\20SkApplyPerspectiveClip\29\20const +293:SkBitmap::~SkBitmap\28\29 +294:fminf +295:SkArenaAlloc::installFooter\28char*\20\28*\29\28char*\29\2c\20unsigned\20int\29 +296:SkArenaAlloc::allocObjectWithFooter\28unsigned\20int\2c\20unsigned\20int\29 +297:hb_buffer_t::make_room_for\28unsigned\20int\2c\20unsigned\20int\29 +298:SkArenaAlloc::~SkArenaAlloc\28\29 +299:skia_private::TArray::push_back\28SkPoint\20const&\29 +300:SkString::operator=\28SkString&&\29 +301:SkSemaphore::osSignal\28int\29 +302:std::__2::__shared_weak_count::__release_weak\28\29 +303:SkPath::SkPath\28\29 +304:skia_png_error +305:hb_buffer_t::message\28hb_font_t*\2c\20char\20const*\2c\20...\29 +306:SkSL::Parser::nextRawToken\28\29 +307:SkFontMgr*\20emscripten::base::convertPointer\28skia::textlayout::TypefaceFontProvider*\29 +308:SkMatrix::computePerspectiveTypeMask\28\29\20const +309:strncmp +310:SkColorInfo::SkColorInfo\28SkColorInfo\20const&\29 +311:SkSemaphore::osWait\28\29 +312:ft_mem_realloc +313:SkIntersections::insert\28double\2c\20double\2c\20SkDPoint\20const&\29 +314:FT_DivFix +315:SkString::appendf\28char\20const*\2c\20...\29 +316:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +317:skia_png_free +318:std::__throw_bad_array_new_length\5babi:ne180100\5d\28\29 +319:skia_png_crc_finish +320:SkPath::lineTo\28float\2c\20float\29 +321:SkMatrix::setTranslate\28float\2c\20float\29 +322:skia_png_chunk_benign_error +323:SkChecksum::Hash32\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20int\29 +324:SkMatrix::mapPoints\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +325:ft_mem_qrealloc +326:skia_png_warning +327:SkColorInfo::bytesPerPixel\28\29\20const +328:OT::VarData::get_delta\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20OT::VarRegionList\20const&\2c\20float*\29\20const +329:GrGLExtensions::has\28char\20const*\29\20const +330:SkPaint::SkPaint\28SkPaint\20const&\29 +331:FT_Stream_Seek +332:skia_private::TArray::push_back\28unsigned\20long\20const&\29 +333:emscripten_builtin_malloc +334:GrVertexChunkBuilder::allocChunk\28int\29 +335:dlrealloc +336:OT::DeltaSetIndexMap::map\28unsigned\20int\29\20const +337:SkReadBuffer::readUInt\28\29 +338:SkMatrix::reset\28\29 +339:SkImageInfo::MakeUnknown\28int\2c\20int\29 +340:GrSurfaceProxyView::asRenderTargetProxy\28\29\20const +341:hb_lazy_loader_t\2c\20hb_face_t\2c\2028u\2c\20hb_blob_t>::do_destroy\28hb_blob_t*\29 +342:SkBlitter::~SkBlitter\28\29 +343:SkBitmap::SkBitmap\28\29 +344:skia_private::TArray::push_back\28unsigned\20char&&\29 +345:SkPath::SkPath\28SkPath\20const&\29 +346:SkPaint::SkPaint\28\29 +347:ft_validator_error +348:SkImageGenerator::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +349:skia_private::TArray\2c\20true>::push_back\28sk_sp&&\29 +350:hb_buffer_t::_set_glyph_flags\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +351:SkOpPtT::segment\28\29\20const +352:skgpu::Swizzle::Swizzle\28char\20const*\29 +353:sk_malloc_flags\28unsigned\20long\2c\20unsigned\20int\29 +354:SkSL::Parser::expect\28SkSL::Token::Kind\2c\20char\20const*\2c\20SkSL::Token*\29 +355:GrTextureGenerator::isTextureGenerator\28\29\20const +356:strstr +357:SkMatrix::invertNonIdentity\28SkMatrix*\29\20const +358:SkSL::RP::Builder::appendInstruction\28SkSL::RP::BuilderOp\2c\20SkSL::RP::Builder::SlotList\2c\20int\2c\20int\2c\20int\2c\20int\29 +359:FT_Stream_ReadUShort +360:skia_private::TArray::push_back\28SkSL::RP::Instruction&&\29 +361:skia_png_get_uint_32 +362:skia_png_calculate_crc +363:std::__2::basic_string\2c\20std::__2::allocator>::resize\5babi:nn180100\5d\28unsigned\20long\29 +364:SkSL::GLSLCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +365:std::__2::basic_string\2c\20std::__2::allocator>::__get_pointer\5babi:nn180100\5d\28\29 +366:SkRect::join\28SkRect\20const&\29 +367:SkPoint::Length\28float\2c\20float\29 +368:GrImageInfo::GrImageInfo\28GrImageInfo\20const&\29 +369:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +370:std::__2::__throw_bad_function_call\5babi:ne180100\5d\28\29 +371:std::__2::locale::~locale\28\29 +372:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28char\29 +373:skia_private::TArray::push_back\28SkString&&\29 +374:SkPathRef::Editor::Editor\28sk_sp*\2c\20int\2c\20int\2c\20int\29 +375:SkRect::intersect\28SkRect\20const&\29 +376:SkRasterPipeline::uncheckedAppend\28SkRasterPipelineOp\2c\20void*\29 +377:SkPath::getBounds\28\29\20const +378:skia_private::TArray>\2c\20true>::operator=\28skia_private::TArray>\2c\20true>&&\29 +379:hb_blob_reference +380:emscripten_builtin_calloc +381:cf2_stack_popFixed +382:SkJSONWriter::appendName\28char\20const*\29 +383:SkRect::setBoundsCheck\28SkPoint\20const*\2c\20int\29 +384:SkCachedData::internalUnref\28bool\29\20const +385:GrProcessor::operator\20new\28unsigned\20long\29 +386:FT_MulDiv +387:std::__2::to_string\28int\29 +388:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +389:std::__2::ios_base::getloc\28\29\20const +390:SkRuntimeEffect::uniformSize\28\29\20const +391:SkJSONWriter::beginValue\28bool\29 +392:subtag_matches\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20int\29 +393:skia_png_read_push_finish_row +394:skia::textlayout::TextStyle::~TextStyle\28\29 +395:hb_blob_make_immutable +396:SkString::operator=\28char\20const*\29 +397:SkColorInfo::operator=\28SkColorInfo&&\29 +398:hb_ot_map_builder_t::add_pause\28unsigned\20int\2c\20bool\20\28*\29\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29\29 +399:VP8GetValue +400:SkReadBuffer::setInvalid\28\29 +401:SkColorInfo::operator=\28SkColorInfo\20const&\29 +402:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28\29 +403:skgpu::ganesh::SurfaceContext::caps\28\29\20const +404:SkSemaphore::~SkSemaphore\28\29 +405:SkRegion::~SkRegion\28\29 +406:SkPoint::normalize\28\29 +407:jdiv_round_up +408:SkSL::RP::Builder::binary_op\28SkSL::RP::BuilderOp\2c\20int\29 +409:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +410:jzero_far +411:SkPathRef::growForVerb\28int\2c\20float\29 +412:SkImageGenerator::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +413:SkColorInfo::SkColorInfo\28SkColorInfo&&\29 +414:SkArenaAlloc::SkArenaAlloc\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +415:FT_Stream_ExitFrame +416:skia_png_write_data +417:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +418:SkMatrix::setConcat\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +419:skia_private::TArray::push_back_raw\28int\29 +420:hb_blob_get_data_writable +421:__shgetc +422:SkSL::SymbolTable::addWithoutOwnershipOrDie\28SkSL::Symbol*\29 +423:SkBlitter::~SkBlitter\28\29_1457 +424:FT_Stream_GetUShort +425:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28wchar_t\20const*\29 +426:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28char\20const*\29 +427:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +428:SkPoint::scale\28float\2c\20SkPoint*\29\20const +429:SkNullBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +430:SkIRect\20skif::Mapping::map\28SkIRect\20const&\2c\20SkMatrix\20const&\29 +431:sktext::gpu::BagOfBytes::~BagOfBytes\28\29 +432:SkSL::String::printf\28char\20const*\2c\20...\29 +433:GrSurfaceProxyView::asTextureProxy\28\29\20const +434:GrOp::GenOpClassID\28\29 +435:round +436:SkStringPrintf\28char\20const*\2c\20...\29 +437:RoughlyEqualUlps\28float\2c\20float\29 +438:GrGLSLVaryingHandler::addVarying\28char\20const*\2c\20GrGLSLVarying*\2c\20GrGLSLVaryingHandler::Interpolation\29 +439:skia_png_chunk_error +440:SkTDStorage::reserve\28int\29 +441:SkPath::Iter::next\28SkPoint*\29 +442:SkDynamicMemoryWStream::write\28void\20const*\2c\20unsigned\20long\29 +443:GrQuad::MakeFromRect\28SkRect\20const&\2c\20SkMatrix\20const&\29 +444:GrFragmentProcessor::ProgramImpl::invokeChild\28int\2c\20char\20const*\2c\20char\20const*\2c\20GrFragmentProcessor::ProgramImpl::EmitArgs&\2c\20std::__2::basic_string_view>\29 +445:SkSurfaceProps::SkSurfaceProps\28\29 +446:SkStrikeSpec::~SkStrikeSpec\28\29 +447:SkSL::TProgramVisitor::visitStatement\28SkSL::Statement\20const&\29 +448:SkSL::RP::Builder::discard_stack\28int\2c\20int\29 +449:SkRecord::grow\28\29 +450:SkRGBA4f<\28SkAlphaType\293>::toBytes_RGBA\28\29\20const +451:GrProcessor::operator\20new\28unsigned\20long\2c\20unsigned\20long\29 +452:skgpu::ganesh::SurfaceDrawContext::addDrawOp\28GrClip\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::function\20const&\29 +453:skgpu::ResourceKeyHash\28unsigned\20int\20const*\2c\20unsigned\20long\29 +454:hb_face_reference_table +455:VP8LoadFinalBytes +456:SkSL::FunctionDeclaration::description\28\29\20const +457:SkPictureRecord::addDraw\28DrawType\2c\20unsigned\20long*\29::'lambda'\28\29::operator\28\29\28\29\20const +458:SkPath::conicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\29 +459:SkCanvas::predrawNotify\28bool\29 +460:OT::Layout::Common::Coverage::get_coverage\28unsigned\20int\29\20const +461:std::__2::__cloc\28\29 +462:sscanf +463:SkStream::readS32\28int*\29 +464:SkPath::moveTo\28float\2c\20float\29 +465:SkMatrix::postTranslate\28float\2c\20float\29 +466:GrSkSLFP::GrSkSLFP\28sk_sp\2c\20char\20const*\2c\20GrSkSLFP::OptFlags\29 +467:GrBackendFormat::GrBackendFormat\28\29 +468:__multf3 +469:VP8LReadBits +470:SkTDStorage::append\28int\29 +471:SkSL::evaluate_n_way_intrinsic\28SkSL::Context\20const&\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +472:SkMatrix::setScale\28float\2c\20float\29 +473:GrOpsRenderPass::setScissorRect\28SkIRect\20const&\29 +474:GrOpsRenderPass::bindPipeline\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +475:GrCaps::getDefaultBackendFormat\28GrColorType\2c\20skgpu::Renderable\29\20const +476:skia_private::TArray::push_back_raw\28int\29 +477:hb_draw_funcs_t::start_path\28void*\2c\20hb_draw_state_t&\29 +478:SkRuntimeEffect::MakeForShader\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +479:GrSimpleMeshDrawOpHelper::~GrSimpleMeshDrawOpHelper\28\29 +480:GrProcessorSet::GrProcessorSet\28GrPaint&&\29 +481:GrBackendFormats::AsGLFormat\28GrBackendFormat\20const&\29 +482:FT_Stream_EnterFrame +483:std::__2::locale::id::__get\28\29 +484:std::__2::locale::facet::facet\5babi:nn180100\5d\28unsigned\20long\29 +485:emscripten_longjmp +486:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29 +487:SkPath::reset\28\29 +488:SkPath::operator=\28SkPath\20const&\29 +489:SkColorSpaceXformSteps::SkColorSpaceXformSteps\28SkColorSpace\20const*\2c\20SkAlphaType\2c\20SkColorSpace\20const*\2c\20SkAlphaType\29 +490:OT::hb_ot_apply_context_t::match_properties_mark\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +491:GrGeometryProcessor::AttributeSet::initImplicit\28GrGeometryProcessor::Attribute\20const*\2c\20int\29 +492:GrContext_Base::contextID\28\29\20const +493:AlmostEqualUlps\28float\2c\20float\29 +494:std::__2::locale::__imp::install\28std::__2::locale::facet*\2c\20long\29 +495:skia_png_read_data +496:SkSpinlock::contendedAcquire\28\29 +497:SkSL::PipelineStage::PipelineStageCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +498:SkPaint::setStyle\28SkPaint::Style\29 +499:SkMatrix::setRectToRect\28SkRect\20const&\2c\20SkRect\20const&\2c\20SkMatrix::ScaleToFit\29 +500:SkDPoint::approximatelyEqual\28SkDPoint\20const&\29\20const +501:GrSurfaceProxy::backingStoreDimensions\28\29\20const +502:GrOpsRenderPass::bindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +503:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +504:skgpu::ganesh::SurfaceContext::drawingManager\28\29 +505:skgpu::UniqueKey::GenerateDomain\28\29 +506:SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0::operator\28\29\28SkSL::FunctionDefinition\20const*\2c\20SkSL::FunctionDefinition\20const*\29\20const +507:SkSL::ConstructorCompound::MakeFromConstants\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20double\20const*\29 +508:SkPath::isEmpty\28\29\20const +509:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29 +510:SkBlockAllocator::reset\28\29 +511:GrMeshDrawOp::GrMeshDrawOp\28unsigned\20int\29 +512:FT_RoundFix +513:std::__2::unique_ptr::~unique_ptr\5babi:nn180100\5d\28\29 +514:std::__2::unique_ptr::unique_ptr\5babi:nn180100\5d\28unsigned\20char*\2c\20std::__2::__dependent_type\2c\20true>::__good_rval_ref_type\29 +515:cf2_stack_pushFixed +516:abort +517:__multi3 +518:SkSL::RP::Builder::push_duplicates\28int\29 +519:SkColorInfo::refColorSpace\28\29\20const +520:SkBitmapDevice::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +521:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20SkFilterMode\2c\20SkMipmapMode\29 +522:GrGLSLVaryingHandler::addPassThroughAttribute\28GrShaderVar\20const&\2c\20char\20const*\2c\20GrGLSLVaryingHandler::Interpolation\29 +523:GrFragmentProcessor::registerChild\28std::__2::unique_ptr>\2c\20SkSL::SampleUsage\29 +524:FT_Stream_ReleaseFrame +525:288 +526:std::__2::istreambuf_iterator>::operator*\5babi:nn180100\5d\28\29\20const +527:skia::textlayout::TextStyle::TextStyle\28skia::textlayout::TextStyle\20const&\29 +528:sk_srgb_singleton\28\29 +529:hb_buffer_t::merge_clusters_impl\28unsigned\20int\2c\20unsigned\20int\29 +530:SkWStream::writePackedUInt\28unsigned\20long\29 +531:SkSL::RP::Builder::push_constant_i\28int\2c\20int\29 +532:SkSL::BreakStatement::~BreakStatement\28\29 +533:SkPath::isFinite\28\29\20const +534:SkPaint::setShader\28sk_sp\29 +535:SkNullBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +536:SkCanvas::concat\28SkMatrix\20const&\29 +537:SkBitmap::setImmutable\28\29 +538:GrPipeline::visitProxies\28std::__2::function\20const&\29\20const +539:GrGeometryProcessor::GrGeometryProcessor\28GrProcessor::ClassID\29 +540:std::__2::istreambuf_iterator>::operator*\5babi:nn180100\5d\28\29\20const +541:SkSL::fold_expression\28SkSL::Position\2c\20double\2c\20SkSL::Type\20const*\29 +542:SkSL::Type::MakeAliasType\28std::__2::basic_string_view>\2c\20SkSL::Type\20const&\29 +543:SkSL::RP::Generator::binaryOp\28SkSL::Type\20const&\2c\20SkSL::RP::Generator::TypedOps\20const&\29 +544:GrGeometryProcessor::Attribute&\20skia_private::TArray::emplace_back\28char\20const\20\28&\29\20\5b10\5d\2c\20GrVertexAttribType&&\2c\20SkSLType&&\29 +545:FT_Stream_ReadByte +546:Cr_z_crc32 +547:skia_png_push_save_buffer +548:skcms_Transform +549:hb_face_t::load_num_glyphs\28\29\20const +550:hb_face_get_glyph_count +551:cosf +552:SkString::operator=\28SkString\20const&\29 +553:SkSL::RP::SlotManager::getVariableSlots\28SkSL::Variable\20const&\29 +554:SkSL::RP::Builder::unary_op\28SkSL::RP::BuilderOp\2c\20int\29 +555:SkReadBuffer::readScalar\28\29 +556:SkPaint::setBlendMode\28SkBlendMode\29 +557:GrProcessorSet::visitProxies\28std::__2::function\20const&\29\20const +558:GrGLTexture::target\28\29\20const +559:fma +560:SkSurface_Base::aboutToDraw\28SkSurface::ContentChangeMode\29 +561:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression\20const&\29 +562:SkSL::Pool::FreeMemory\28void*\29 +563:SkDPoint::ApproximatelyEqual\28SkPoint\20const&\2c\20SkPoint\20const&\29 +564:SkBitmap::SkBitmap\28SkBitmap\20const&\29 +565:FT_Stream_ReadULong +566:std::__2::unique_ptr>*\20std::__2::vector>\2c\20std::__2::allocator>>>::__push_back_slow_path>>\28std::__2::unique_ptr>&&\29 +567:std::__2::basic_string\2c\20std::__2::allocator>::__init_copy_ctor_external\28char\20const*\2c\20unsigned\20long\29 +568:std::__2::__throw_overflow_error\5babi:nn180100\5d\28char\20const*\29 +569:skip_spaces +570:sk_realloc_throw\28void*\2c\20unsigned\20long\29 +571:fmodf +572:emscripten::smart_ptr_trait>::get\28sk_sp\20const&\29 +573:cff2_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +574:cff1_path_procs_extents_t::curve\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +575:cff1_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +576:bool\20OT::Layout::Common::Coverage::collect_coverage\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>>\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>*\29\20const +577:SkString::equals\28SkString\20const&\29\20const +578:SkSL::Type::toCompound\28SkSL::Context\20const&\2c\20int\2c\20int\29\20const +579:SkPath::transform\28SkMatrix\20const&\2c\20SkPath*\2c\20SkApplyPerspectiveClip\29\20const +580:SkPath::quadTo\28float\2c\20float\2c\20float\2c\20float\29 +581:SkPaint::SkPaint\28SkPaint&&\29 +582:SkCanvas::save\28\29 +583:SkBlockAllocator::addBlock\28int\2c\20int\29 +584:SkBitmap::tryAllocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29 +585:GrThreadSafeCache::VertexData::~VertexData\28\29 +586:GrShape::asPath\28SkPath*\2c\20bool\29\20const +587:GrShaderVar::appendDecl\28GrShaderCaps\20const*\2c\20SkString*\29\20const +588:GrPixmapBase::~GrPixmapBase\28\29 +589:GrGLSLVaryingHandler::emitAttributes\28GrGeometryProcessor\20const&\29 +590:FT_Stream_ReadFields +591:void\20emscripten::internal::raw_destructor\28GrDirectContext*\29 +592:std::__2::unique_ptr::reset\5babi:nn180100\5d\28unsigned\20char*\29 +593:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +594:skia_private::TArray::push_back\28SkPaint\20const&\29 +595:ft_mem_qalloc +596:__wasm_setjmp +597:SkSL::SymbolTable::~SymbolTable\28\29 +598:SkRasterClip::~SkRasterClip\28\29 +599:SkPixmap::reset\28SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +600:SkPathRef::~SkPathRef\28\29 +601:SkPath::countPoints\28\29\20const +602:SkPaint::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +603:SkPaint::canComputeFastBounds\28\29\20const +604:SkOpPtT::contains\28SkOpPtT\20const*\29\20const +605:SkOpAngle::segment\28\29\20const +606:SkMatrix::preConcat\28SkMatrix\20const&\29 +607:SkMatrix::mapVectors\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +608:SkMasks::getRed\28unsigned\20int\29\20const +609:SkMasks::getGreen\28unsigned\20int\29\20const +610:SkMasks::getBlue\28unsigned\20int\29\20const +611:SkColorSpace::MakeSRGB\28\29 +612:GrProcessorSet::~GrProcessorSet\28\29 +613:GrMeshDrawOp::createProgramInfo\28GrMeshDrawTarget*\29 +614:AutoLayerForImageFilter::~AutoLayerForImageFilter\28\29 +615:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +616:png_icc_profile_error +617:operator==\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +618:machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>::operator=\28machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\20const&\29 +619:emscripten::internal::MethodInvoker::invoke\28int\20\28SkAnimatedImage::*\20const&\29\28\29\2c\20SkAnimatedImage*\29 +620:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20SkBlendMode\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20SkBlendMode\29 +621:emscripten::default_smart_ptr_trait>::construct_null\28\29 +622:VP8GetSignedValue +623:SkSL::Type::MakeVectorType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\29 +624:SkRasterPipeline::SkRasterPipeline\28SkArenaAlloc*\29 +625:SkPoint::setLength\28float\29 +626:SkColorInfo::shiftPerPixel\28\29\20const +627:GrTextureProxy::mipmapped\28\29\20const +628:GrGpuResource::~GrGpuResource\28\29 +629:FT_Stream_GetULong +630:Cr_z__tr_flush_bits +631:394 +632:void\20emscripten::internal::raw_destructor>\28sk_sp*\29 +633:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +634:std::__2::__throw_bad_optional_access\5babi:ne180100\5d\28\29 +635:skgpu::UniqueKey::operator=\28skgpu::UniqueKey\20const&\29 +636:sk_double_nearly_zero\28double\29 +637:hb_font_get_glyph +638:ft_mem_alloc +639:fit_linear\28skcms_Curve\20const*\2c\20int\2c\20float\2c\20float*\2c\20float*\2c\20float*\29 +640:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29 +641:_output_with_dotted_circle\28hb_buffer_t*\29 +642:WebPSafeMalloc +643:SkSafeMath::Mul\28unsigned\20long\2c\20unsigned\20long\29 +644:SkSL::GLSLCodeGenerator::writeIdentifier\28std::__2::basic_string_view>\29 +645:SkSL::GLSLCodeGenerator::getTypeName\28SkSL::Type\20const&\29 +646:SkRGBA4f<\28SkAlphaType\293>::FromColor\28unsigned\20int\29 +647:SkPath::Iter::Iter\28SkPath\20const&\2c\20bool\29 +648:SkMatrix::postConcat\28SkMatrix\20const&\29 +649:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_3::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +650:SkGlyph::rowBytes\28\29\20const +651:SkDrawable::getFlattenableType\28\29\20const +652:SkDrawable::getBounds\28\29 +653:SkData::MakeWithCopy\28void\20const*\2c\20unsigned\20long\29 +654:SkDCubic::ptAtT\28double\29\20const +655:SkColorInfo::SkColorInfo\28\29 +656:SkAAClipBlitter::~SkAAClipBlitter\28\29 +657:GrOpFlushState::drawMesh\28GrSimpleMesh\20const&\29 +658:GrImageInfo::GrImageInfo\28SkImageInfo\20const&\29 +659:DefaultGeoProc::Impl::~Impl\28\29 +660:void\20emscripten::internal::MemberAccess::setWire\28int\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\2c\20int\29 +661:uprv_malloc_skia +662:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:nn180100\5d\28\29\20const +663:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_size\5babi:nn180100\5d\28unsigned\20long\29 +664:std::__2::basic_string\2c\20std::__2::allocator>::__is_long\5babi:nn180100\5d\28\29\20const +665:skif::LayerSpace::mapRect\28skif::LayerSpace\20const&\29\20const +666:skia::textlayout::Cluster::run\28\29\20const +667:out +668:jpeg_fill_bit_buffer +669:int\20emscripten::internal::MemberAccess::getWire\28int\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\29 +670:SkTextBlob::~SkTextBlob\28\29 +671:SkString::data\28\29 +672:SkShaderBase::SkShaderBase\28\29 +673:SkSL::Type::coerceExpression\28std::__2::unique_ptr>\2c\20SkSL::Context\20const&\29\20const +674:SkSL::Type::MakeGenericType\28char\20const*\2c\20SkSpan\2c\20SkSL::Type\20const*\29 +675:SkSL::ConstantFolder::GetConstantValueForVariable\28SkSL::Expression\20const&\29 +676:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29 +677:SkRegion::SkRegion\28\29 +678:SkRecords::FillBounds::adjustForSaveLayerPaints\28SkRect*\2c\20int\29\20const +679:SkPathStroker::lineTo\28SkPoint\20const&\2c\20SkPath::Iter\20const*\29 +680:SkPaint::setPathEffect\28sk_sp\29 +681:SkPaint::setMaskFilter\28sk_sp\29 +682:SkPaint::setColor\28unsigned\20int\29 +683:SkPaint::setColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\29 +684:SkOpContourBuilder::flush\28\29 +685:SkImageFilter::getInput\28int\29\20const +686:SkCanvas::~SkCanvas\28\29_1622 +687:SkCanvas::restoreToCount\28int\29 +688:SkCanvas::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +689:SkAutoPixmapStorage::~SkAutoPixmapStorage\28\29 +690:GrMatrixEffect::Make\28SkMatrix\20const&\2c\20std::__2::unique_ptr>\29 +691:GrContext_Base::options\28\29\20const +692:std::__2::char_traits::assign\5babi:nn180100\5d\28char&\2c\20char\20const&\29 +693:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +694:std::__2::__check_grouping\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int&\29 +695:skia_png_malloc +696:skia_png_chunk_report +697:skgpu::ganesh::SurfaceDrawContext::drawFilledQuad\28GrClip\20const*\2c\20GrPaint&&\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\29 +698:png_write_complete_chunk +699:pad +700:hb_lockable_set_t::fini\28hb_mutex_t&\29 +701:__ashlti3 +702:\28anonymous\20namespace\29::makeTargetInfo\28SkEncodedInfo\2c\20void\20\28*\29\28char*\2c\20char\20const*\2c\20int\2c\20int\29\29 +703:SkWBuffer::writeNoSizeCheck\28void\20const*\2c\20unsigned\20long\29 +704:SkTCoincident::setPerp\28SkTCurve\20const&\2c\20double\2c\20SkDPoint\20const&\2c\20SkTCurve\20const&\29 +705:SkStrokeRec::SkStrokeRec\28SkStrokeRec::InitStyle\29 +706:SkString::printf\28char\20const*\2c\20...\29 +707:SkSL::Type::MakeMatrixType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\2c\20signed\20char\29 +708:SkSL::Operator::tightOperatorName\28\29\20const +709:SkReadBuffer::readColor4f\28SkRGBA4f<\28SkAlphaType\293>*\29 +710:SkPixmap::reset\28\29 +711:SkPictureData::requiredPaint\28SkReadBuffer*\29\20const +712:SkPath::cubicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +713:SkPath::close\28\29 +714:SkPaintToGrPaint\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +715:SkMatrix::mapXY\28float\2c\20float\2c\20SkPoint*\29\20const +716:SkFindUnitQuadRoots\28float\2c\20float\2c\20float\2c\20float*\29 +717:SkDeque::push_back\28\29 +718:SkCanvas::internalQuickReject\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\29 +719:SkBinaryWriteBuffer::writeBool\28bool\29 +720:OT::hb_paint_context_t::return_t\20OT::Paint::dispatch\28OT::hb_paint_context_t*\29\20const +721:GrShape::bounds\28\29\20const +722:GrProgramInfo::GrProgramInfo\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrGeometryProcessor\20const*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +723:GrPixmapBase::GrPixmapBase\28GrImageInfo\2c\20void*\2c\20unsigned\20long\29 +724:GrColorInfo::GrColorInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\29 +725:FT_Outline_Translate +726:FT_Load_Glyph +727:FT_GlyphLoader_CheckPoints +728:FT_Get_Char_Index +729:DefaultGeoProc::~DefaultGeoProc\28\29 +730:493 +731:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +732:std::__2::basic_string\2c\20std::__2::allocator>::__set_short_size\5babi:nn180100\5d\28unsigned\20long\29 +733:sinf +734:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28GrDirectContext&\2c\20unsigned\20long\29\2c\20GrDirectContext*\2c\20unsigned\20long\29 +735:SkRasterPipeline::extend\28SkRasterPipeline\20const&\29 +736:SkMatrixPriv::MapRect\28SkM44\20const&\2c\20SkRect\20const&\29 +737:SkMatrix::preTranslate\28float\2c\20float\29 +738:SkMatrix::mapRadius\28float\29\20const +739:SkJSONWriter::appendf\28char\20const*\2c\20...\29 +740:SkImageGenerator::onIsValid\28GrRecordingContext*\29\20const +741:SkImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +742:SkIRect::join\28SkIRect\20const&\29 +743:SkData::MakeWithProc\28void\20const*\2c\20unsigned\20long\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +744:SkData::MakeUninitialized\28unsigned\20long\29 +745:SkDQuad::RootsValidT\28double\2c\20double\2c\20double\2c\20double*\29 +746:SkDLine::nearPoint\28SkDPoint\20const&\2c\20bool*\29\20const +747:SkColorSpaceXformSteps::apply\28float*\29\20const +748:SkCachedData::internalRef\28bool\29\20const +749:SkBitmap::installPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29 +750:GrSurface::RefCntedReleaseProc::~RefCntedReleaseProc\28\29 +751:GrStyle::initPathEffect\28sk_sp\29 +752:GrProcessor::operator\20delete\28void*\29 +753:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::~Impl\28\29 +754:GrBufferAllocPool::~GrBufferAllocPool\28\29_8772 +755:FT_Stream_Skip +756:std::__2::numpunct::thousands_sep\5babi:nn180100\5d\28\29\20const +757:std::__2::numpunct::grouping\5babi:nn180100\5d\28\29\20const +758:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +759:skia_png_malloc_warn +760:rewind\28GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +761:cf2_stack_popInt +762:SkSL::TProgramVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +763:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29 +764:SkRegion::setRect\28SkIRect\20const&\29 +765:SkPaint::setColorFilter\28sk_sp\29 +766:SkImageInfo::MakeA8\28int\2c\20int\29 +767:SkDrawBase::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20bool\2c\20bool\2c\20SkBlitter*\29\20const +768:SkData::MakeEmpty\28\29 +769:SkColorInfo::makeColorType\28SkColorType\29\20const +770:SkCodec::~SkCodec\28\29 +771:SkAAClip::isRect\28\29\20const +772:GrSurface::ComputeSize\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20bool\29 +773:GrSimpleMeshDrawOpHelper::GrSimpleMeshDrawOpHelper\28GrProcessorSet*\2c\20GrAAType\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +774:GrGeometryProcessor::ProgramImpl::SetTransform\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrResourceHandle\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix*\29 +775:GrDrawingManager::flushIfNecessary\28\29 +776:GrBlendFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkBlendMode\2c\20bool\29 +777:FT_Stream_ExtractFrame +778:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +779:skia_png_malloc_base +780:skgpu::ganesh::AsView\28GrRecordingContext*\2c\20SkImage\20const*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +781:skcms_TransferFunction_eval +782:pow +783:hb_ot_face_t::init0\28hb_face_t*\29 +784:__addtf3 +785:SkUTF::NextUTF8\28char\20const**\2c\20char\20const*\29 +786:SkTDStorage::reset\28\29 +787:SkSL::RP::Builder::label\28int\29 +788:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +789:SkRuntimeEffect::MakeForColorFilter\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +790:SkReadBuffer::skip\28unsigned\20long\2c\20unsigned\20long\29 +791:SkPath::countVerbs\28\29\20const +792:SkMatrix::set9\28float\20const*\29 +793:SkMatrix::getMaxScale\28\29\20const +794:SkImageInfo::computeByteSize\28unsigned\20long\29\20const +795:SkImageInfo::Make\28int\2c\20int\2c\20SkColorType\2c\20SkAlphaType\2c\20sk_sp\29 +796:SkFontMgr::countFamilies\28\29\20const +797:SkDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +798:SkBlockAllocator::SkBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\2c\20unsigned\20long\29 +799:SkBlender::Mode\28SkBlendMode\29 +800:ReadHuffmanCode +801:GrSurfaceProxy::~GrSurfaceProxy\28\29 +802:GrRenderTask::makeClosed\28GrRecordingContext*\29 +803:GrGpuBuffer::unmap\28\29 +804:GrCaps::getReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +805:GrBufferAllocPool::reset\28\29 +806:AAT::Lookup>::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +807:uprv_realloc_skia +808:std::__2::char_traits::assign\5babi:nn180100\5d\28wchar_t&\2c\20wchar_t\20const&\29 +809:std::__2::char_traits::copy\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +810:std::__2::basic_string\2c\20std::__2::allocator>::begin\5babi:nn180100\5d\28\29 +811:std::__2::__next_prime\28unsigned\20long\29 +812:std::__2::__libcpp_snprintf_l\28char*\2c\20unsigned\20long\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +813:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29 +814:sk_sp::~sk_sp\28\29 +815:memchr +816:is_equal\28std::type_info\20const*\2c\20std::type_info\20const*\2c\20bool\29 +817:hb_buffer_t::sync\28\29 +818:cbrtf +819:__floatsitf +820:WebPSafeCalloc +821:StreamRemainingLengthIsBelow\28SkStream*\2c\20unsigned\20long\29 +822:SkSL::RP::Builder::swizzle\28int\2c\20SkSpan\29 +823:SkSL::Parser::expression\28\29 +824:SkRuntimeEffect::Uniform::sizeInBytes\28\29\20const +825:SkRGBA4f<\28SkAlphaType\293>::toSkColor\28\29\20const +826:SkPath::isConvex\28\29\20const +827:SkImageFilter_Base::getChildOutputLayerBounds\28int\2c\20skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +828:SkImageFilter_Base::getChildInputLayerBounds\28int\2c\20skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +829:SkImageFilter_Base::SkImageFilter_Base\28sk_sp\20const*\2c\20int\2c\20std::__2::optional\29 +830:SkDynamicMemoryWStream::detachAsData\28\29 +831:SkDQuad::ptAtT\28double\29\20const +832:SkDLine::exactPoint\28SkDPoint\20const&\29\20const +833:SkDConic::ptAtT\28double\29\20const +834:SkConic::chopIntoQuadsPOW2\28SkPoint*\2c\20int\29\20const +835:SkColorInfo::makeAlphaType\28SkAlphaType\29\20const +836:SkCanvas::restore\28\29 +837:SkCanvas::drawImage\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +838:SkBitmap::setInfo\28SkImageInfo\20const&\2c\20unsigned\20long\29 +839:SkAAClip::Builder::addRun\28int\2c\20int\2c\20unsigned\20int\2c\20int\29 +840:GrSkSLFP::addChild\28std::__2::unique_ptr>\2c\20bool\29 +841:GrResourceProvider::findResourceByUniqueKey\28skgpu::UniqueKey\20const&\29 +842:GrGpuResource::hasRef\28\29\20const +843:GrGLSLShaderBuilder::appendTextureLookup\28SkString*\2c\20GrResourceHandle\2c\20char\20const*\29\20const +844:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\29 +845:GrFragmentProcessor::cloneAndRegisterAllChildProcessors\28GrFragmentProcessor\20const&\29 +846:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::~SwizzleFragmentProcessor\28\29 +847:GrBackendFormat::GrBackendFormat\28GrBackendFormat\20const&\29 +848:AutoLayerForImageFilter::AutoLayerForImageFilter\28SkCanvas*\2c\20SkPaint\20const&\2c\20SkRect\20const*\2c\20bool\29 +849:AutoFTAccess::AutoFTAccess\28SkTypeface_FreeType\20const*\29 +850:AlmostPequalUlps\28float\2c\20float\29 +851:strchr +852:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Module\20const*\29 +853:std::__2::pair>*\20std::__2::vector>\2c\20std::__2::allocator>>>::__emplace_back_slow_path>\28unsigned\20int\20const&\2c\20sk_sp&&\29 +854:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20char\29\20const +855:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:ne180100\5d<0>\28char\20const*\29 +856:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_cap\5babi:nn180100\5d\28unsigned\20long\29 +857:snprintf +858:skia_png_reset_crc +859:skia_png_benign_error +860:hb_buffer_t::sync_so_far\28\29 +861:hb_buffer_t::move_to\28unsigned\20int\29 +862:VP8ExitCritical +863:SkTDStorage::resize\28int\29 +864:SkStrokeRec::SkStrokeRec\28SkPaint\20const&\2c\20float\29 +865:SkStream::readPackedUInt\28unsigned\20long*\29 +866:SkSize\20skif::Mapping::map\28SkSize\20const&\2c\20SkMatrix\20const&\29 +867:SkSL::Type::coercionCost\28SkSL::Type\20const&\29\20const +868:SkSL::Type::clone\28SkSL::Context\20const&\2c\20SkSL::SymbolTable*\29\20const +869:SkSL::RP::Generator::writeStatement\28SkSL::Statement\20const&\29 +870:SkSL::Parser::operatorRight\28SkSL::Parser::AutoDepth&\2c\20SkSL::OperatorKind\2c\20std::__2::unique_ptr>\20\28SkSL::Parser::*\29\28\29\2c\20std::__2::unique_ptr>&\29 +871:SkRuntimeEffectBuilder::writableUniformData\28\29 +872:SkRuntimeEffect::findUniform\28std::__2::basic_string_view>\29\20const +873:SkResourceCache::Key::init\28void*\2c\20unsigned\20long\20long\2c\20unsigned\20long\29 +874:SkReadBuffer::skip\28unsigned\20long\29 +875:SkReadBuffer::readFlattenable\28SkFlattenable::Type\29 +876:SkRRect::initializeRect\28SkRect\20const&\29 +877:SkPaint::asBlendMode\28\29\20const +878:SkImageFilter_Base::getFlattenableType\28\29\20const +879:SkGlyph::path\28\29\20const +880:SkConic::computeQuadPOW2\28float\29\20const +881:SkAAClip::quickContains\28int\2c\20int\2c\20int\2c\20int\29\20const +882:OT::GDEF::accelerator_t::mark_set_covers\28unsigned\20int\2c\20unsigned\20int\29\20const +883:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\29 +884:GrRenderTargetProxy::arenas\28\29 +885:GrOpFlushState::caps\28\29\20const +886:GrGpuResource::hasNoCommandBufferUsages\28\29\20const +887:GrGeometryProcessor::ProgramImpl::WriteLocalCoord\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20GrShaderVar\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +888:GrGLTextureParameters::SamplerOverriddenState::SamplerOverriddenState\28\29 +889:GrGLGpu::deleteFramebuffer\28unsigned\20int\29 +890:GrDrawOpAtlas::~GrDrawOpAtlas\28\29 +891:FT_Get_Module +892:Cr_z__tr_flush_block +893:AlmostBequalUlps\28float\2c\20float\29 +894:std::__2::pair::type\2c\20std::__2::__unwrap_ref_decay::type>\20std::__2::make_pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +895:std::__2::numpunct::truename\5babi:nn180100\5d\28\29\20const +896:std::__2::moneypunct::do_grouping\28\29\20const +897:std::__2::locale::use_facet\28std::__2::locale::id&\29\20const +898:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29\20const +899:std::__2::basic_string\2c\20std::__2::allocator>::empty\5babi:nn180100\5d\28\29\20const +900:sktext::gpu::BagOfBytes::needMoreBytes\28int\2c\20int\29 +901:skia_png_save_int_32 +902:skia_png_safecat +903:skia_png_gamma_significant +904:skgpu::ganesh::SurfaceContext::readPixels\28GrDirectContext*\2c\20GrPixmap\2c\20SkIPoint\29 +905:hb_font_get_nominal_glyph +906:hb_buffer_t::clear_output\28\29 +907:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28SkPaint\20const&\29\2c\20SkCanvas*\2c\20SkPaint*\29 +908:emscripten::internal::FunctionInvoker::invoke\28unsigned\20long\20\28**\29\28GrDirectContext&\29\2c\20GrDirectContext*\29 +909:cff_parse_num +910:\28anonymous\20namespace\29::write_trc_tag\28skcms_Curve\20const&\29 +911:SkWStream::writeScalarAsText\28float\29 +912:SkTSect::SkTSect\28SkTCurve\20const&\29 +913:SkString::set\28char\20const*\2c\20unsigned\20long\29 +914:SkSL::compile_and_shrink\28SkSL::Compiler*\2c\20SkSL::ProgramKind\2c\20SkSL::ModuleType\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::Module\20const*\29 +915:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Context\20const&\2c\20SkSL::Symbol*\29 +916:SkSL::Swizzle::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29 +917:SkSL::String::Separator\28\29::Output::~Output\28\29 +918:SkSL::Parser::layoutInt\28\29 +919:SkSL::Parser::expectIdentifier\28SkSL::Token*\29 +920:SkSL::GetModuleData\28SkSL::ModuleType\2c\20char\20const*\29 +921:SkSL::Expression::description\28\29\20const +922:SkRegion::Cliperator::next\28\29 +923:SkRegion::Cliperator::Cliperator\28SkRegion\20const&\2c\20SkIRect\20const&\29 +924:SkRRect::setOval\28SkRect\20const&\29 +925:SkPictureRecorder::~SkPictureRecorder\28\29 +926:SkPathRef::CreateEmpty\28\29 +927:SkPath::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +928:SkPath::addPath\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPath::AddPathMode\29 +929:SkPaint::operator=\28SkPaint&&\29 +930:SkNoDestructor::SkNoDestructor\28SkSL::String::Separator\28\29::Output&&\29 +931:SkMasks::getAlpha\28unsigned\20int\29\20const +932:SkM44::setConcat\28SkM44\20const&\2c\20SkM44\20const&\29 +933:SkImageFilters::Crop\28SkRect\20const&\2c\20SkTileMode\2c\20sk_sp\29 +934:SkImageFilter_Base::getChildOutput\28int\2c\20skif::Context\20const&\29\20const +935:SkIDChangeListener::List::List\28\29 +936:SkData::MakeFromMalloc\28void\20const*\2c\20unsigned\20long\29 +937:SkDRect::setBounds\28SkTCurve\20const&\29 +938:SkColorSpace::Equals\28SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +939:SkColorFilter::isAlphaUnchanged\28\29\20const +940:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +941:SkCanvas::translate\28float\2c\20float\29 +942:SkBitmapCache::Rec::getKey\28\29\20const +943:SafeDecodeSymbol +944:PS_Conv_ToFixed +945:OT::hb_ot_apply_context_t::hb_ot_apply_context_t\28unsigned\20int\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20hb_blob_t*\29 +946:GrTriangulator::Line::intersect\28GrTriangulator::Line\20const&\2c\20SkPoint*\29\20const +947:GrSimpleMeshDrawOpHelper::isCompatible\28GrSimpleMeshDrawOpHelper\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +948:GrQuad::MakeFromSkQuad\28SkPoint\20const*\2c\20SkMatrix\20const&\29 +949:GrOpsRenderPass::bindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +950:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkISize\20const&\29 +951:GrGLSLShaderBuilder::appendTextureLookup\28GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +952:GrColorInfo::GrColorInfo\28SkColorInfo\20const&\29 +953:FT_Stream_Read +954:AlmostDequalUlps\28double\2c\20double\29 +955:718 +956:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\29 +957:tt_face_get_name +958:std::__2::to_string\28long\20long\29 +959:std::__2::__libcpp_locale_guard::~__libcpp_locale_guard\5babi:nn180100\5d\28\29 +960:std::__2::__libcpp_locale_guard::__libcpp_locale_guard\5babi:nn180100\5d\28__locale_struct*&\29 +961:skif::FilterResult::~FilterResult\28\29 +962:skia_png_app_error +963:skgpu::ganesh::SurfaceFillContext::getOpsTask\28\29 +964:log2f +965:llround +966:hb_sanitize_context_t::return_t\20OT::Paint::dispatch\28hb_sanitize_context_t*\29\20const +967:hb_ot_layout_lookup_would_substitute +968:hb_lazy_loader_t\2c\20hb_face_t\2c\2025u\2c\20OT::GSUB_accelerator_t>::do_destroy\28OT::GSUB_accelerator_t*\29 +969:ft_module_get_service +970:expf +971:__sindf +972:__shlim +973:__cosdf +974:SkTiff::ImageFileDirectory::getEntryValuesGeneric\28unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20int\2c\20void*\29\20const +975:SkSurface::getCanvas\28\29 +976:SkSL::cast_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +977:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitType\28SkSL::Type\20const&\29 +978:SkSL::Variable::initialValue\28\29\20const +979:SkSL::SymbolTable::addArrayDimension\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20int\29 +980:SkSL::StringStream::str\28\29\20const +981:SkSL::RP::Program::appendCopy\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20std::byte*\2c\20SkSL::RP::ProgramOp\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29\20const +982:SkSL::RP::Generator::makeLValue\28SkSL::Expression\20const&\2c\20bool\29 +983:SkSL::GLSLCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +984:SkSL::Analysis::UpdateVariableRefKind\28SkSL::Expression*\2c\20SkSL::VariableRefKind\2c\20SkSL::ErrorReporter*\29 +985:SkRegion::setEmpty\28\29 +986:SkRasterPipeline::run\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +987:SkRasterPipeline::appendLoadDst\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +988:SkRRect::setRectRadii\28SkRect\20const&\2c\20SkPoint\20const*\29 +989:SkPointPriv::DistanceToLineSegmentBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +990:SkPath::arcTo\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +991:SkPaint::setImageFilter\28sk_sp\29 +992:SkOpSpanBase::contains\28SkOpSegment\20const*\29\20const +993:SkMipmap::ComputeLevelCount\28int\2c\20int\29 +994:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint\20const*\2c\20int\29\20const +995:SkMatrix::isSimilarity\28float\29\20const +996:SkKnownRuntimeEffects::GetKnownRuntimeEffect\28SkKnownRuntimeEffects::StableKey\29 +997:SkIDChangeListener::List::~List\28\29 +998:SkIDChangeListener::List::changed\28\29 +999:SkColorFilter::filterColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\2c\20SkColorSpace*\29\20const +1000:SkCodec::applyColorXform\28void*\2c\20void\20const*\2c\20int\29\20const +1001:SkCanvas::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +1002:SkAutoPixmapStorage::SkAutoPixmapStorage\28\29 +1003:RunBasedAdditiveBlitter::flush\28\29 +1004:GrSurface::onRelease\28\29 +1005:GrStyledShape::unstyledKeySize\28\29\20const +1006:GrShape::convex\28bool\29\20const +1007:GrRecordingContext::threadSafeCache\28\29 +1008:GrProxyProvider::caps\28\29\20const +1009:GrOp::GrOp\28unsigned\20int\29 +1010:GrMakeUncachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +1011:GrGLSLShaderBuilder::getMangledFunctionName\28char\20const*\29 +1012:GrGLGpu::bindBuffer\28GrGpuBufferType\2c\20GrBuffer\20const*\29 +1013:GrGLAttribArrayState::set\28GrGLGpu*\2c\20int\2c\20GrBuffer\20const*\2c\20GrVertexAttribType\2c\20SkSLType\2c\20int\2c\20unsigned\20long\2c\20int\29 +1014:GrAAConvexTessellator::Ring::computeNormals\28GrAAConvexTessellator\20const&\29 +1015:GrAAConvexTessellator::Ring::computeBisectors\28GrAAConvexTessellator\20const&\29 +1016:FT_Activate_Size +1017:Cr_z_adler32 +1018:781 +1019:782 +1020:vsnprintf +1021:top12 +1022:toSkImageInfo\28SimpleImageInfo\20const&\29 +1023:std::__2::vector>::__destroy_vector::__destroy_vector\5babi:nn180100\5d\28std::__2::vector>&\29 +1024:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +1025:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\2c\20std::__2::allocator>\28char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +1026:std::__2::__tree\2c\20std::__2::__map_value_compare\2c\20std::__2::less\2c\20true>\2c\20std::__2::allocator>>::destroy\28std::__2::__tree_node\2c\20void*>*\29 +1027:std::__2::__num_put_base::__identify_padding\28char*\2c\20char*\2c\20std::__2::ios_base\20const&\29 +1028:std::__2::__num_get_base::__get_base\28std::__2::ios_base&\29 +1029:std::__2::__libcpp_asprintf_l\28char**\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +1030:skia_private::THashTable::Traits>::removeSlot\28int\29 +1031:skia_png_zstream_error +1032:skia::textlayout::TextLine::iterateThroughVisualRuns\28bool\2c\20std::__2::function\2c\20float*\29>\20const&\29\20const +1033:skia::textlayout::ParagraphImpl::cluster\28unsigned\20long\29 +1034:skia::textlayout::Cluster::runOrNull\28\29\20const +1035:skgpu::ganesh::SurfaceFillContext::replaceOpsTask\28\29 +1036:skcms_TransferFunction_getType +1037:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1038:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1039:hb_serialize_context_t::pop_pack\28bool\29 +1040:hb_buffer_reverse +1041:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1042:afm_parser_read_vals +1043:__extenddftf2 +1044:\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1045:\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1046:\28anonymous\20namespace\29::colrv1_transform\28FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\2c\20SkCanvas*\2c\20SkMatrix*\29 +1047:WebPRescalerImport +1048:SkTDStorage::removeShuffle\28int\29 +1049:SkString::SkString\28char\20const*\2c\20unsigned\20long\29 +1050:SkStrike::digestFor\28skglyph::ActionType\2c\20SkPackedGlyphID\29 +1051:SkSL::VariableReference::VariableReference\28SkSL::Position\2c\20SkSL::Variable\20const*\2c\20SkSL::VariableRefKind\29 +1052:SkSL::SymbolTable::lookup\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +1053:SkSL::ProgramUsage::get\28SkSL::Variable\20const&\29\20const +1054:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29 +1055:SkSL::InlineCandidateAnalyzer::visitExpression\28std::__2::unique_ptr>*\29 +1056:SkSL::GLSLCodeGenerator::write\28std::__2::basic_string_view>\29 +1057:SkSL::GLSLCodeGenerator::getTypePrecision\28SkSL::Type\20const&\29 +1058:SkReadBuffer::readByteArray\28void*\2c\20unsigned\20long\29 +1059:SkRBuffer::read\28void*\2c\20unsigned\20long\29 +1060:SkPictureData::optionalPaint\28SkReadBuffer*\29\20const +1061:SkPath::isRect\28SkRect*\2c\20bool*\2c\20SkPathDirection*\29\20const +1062:SkPath::getGenerationID\28\29\20const +1063:SkPaint::setStrokeWidth\28float\29 +1064:SkOpSegment::nextChase\28SkOpSpanBase**\2c\20int*\2c\20SkOpSpan**\2c\20SkOpSpanBase**\29\20const +1065:SkMemoryStream::Make\28sk_sp\29 +1066:SkMatrix::preScale\28float\2c\20float\29 +1067:SkMatrix::postScale\28float\2c\20float\29 +1068:SkMask::computeImageSize\28\29\20const +1069:SkIntersections::removeOne\28int\29 +1070:SkImageInfo::Make\28int\2c\20int\2c\20SkColorType\2c\20SkAlphaType\29 +1071:SkDevice::makeSpecial\28SkBitmap\20const&\29 +1072:SkDLine::ptAtT\28double\29\20const +1073:SkBitmap::peekPixels\28SkPixmap*\29\20const +1074:SkAAClip::setEmpty\28\29 +1075:PS_Conv_Strtol +1076:OT::Layout::GSUB_impl::SubstLookup*\20hb_serialize_context_t::push\28\29 +1077:GrTriangulator::makeConnectingEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\2c\20int\29 +1078:GrTextureProxy::~GrTextureProxy\28\29 +1079:GrSimpleMeshDrawOpHelper::createProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1080:GrResourceAllocator::addInterval\28GrSurfaceProxy*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20GrResourceAllocator::ActualUse\2c\20GrResourceAllocator::AllowRecycling\29 +1081:GrRecordingContextPriv::makeSFCWithFallback\28GrImageInfo\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1082:GrGpuBuffer::updateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +1083:GrGLTextureParameters::NonsamplerState::NonsamplerState\28\29 +1084:GrGLSLShaderBuilder::~GrGLSLShaderBuilder\28\29 +1085:GrGLSLProgramBuilder::nameVariable\28char\2c\20char\20const*\2c\20bool\29 +1086:GrGLGpu::prepareToDraw\28GrPrimitiveType\29 +1087:GrGLFormatFromGLEnum\28unsigned\20int\29 +1088:GrBackendTexture::getBackendFormat\28\29\20const +1089:GrBackendFormats::MakeGL\28unsigned\20int\2c\20unsigned\20int\29 +1090:GrBackendFormatToCompressionType\28GrBackendFormat\20const&\29 +1091:FilterLoop24_C +1092:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +1093:AAT::Lookup::sanitize\28hb_sanitize_context_t*\29\20const +1094:uprv_free_skia +1095:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +1096:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +1097:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +1098:strcpy +1099:std::__2::vector>::size\5babi:nn180100\5d\28\29\20const +1100:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +1101:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\20const*\2c\20char\20const*\29\20const +1102:std::__2::enable_if::type\20skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::AddTrianglesWhenChopping\2c\20skgpu::tess::DiscardFlatCurves>::writeTriangleStack\28skgpu::tess::MiddleOutPolygonTriangulator::PoppedTriangleStack&&\29 +1103:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +1104:std::__2::char_traits::eq_int_type\5babi:nn180100\5d\28int\2c\20int\29 +1105:std::__2::basic_string\2c\20std::__2::allocator>::__get_long_cap\5babi:nn180100\5d\28\29\20const +1106:skif::LayerSpace::ceil\28\29\20const +1107:skia_private::THashTable::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +1108:skia_private::TArray::push_back\28float\20const&\29 +1109:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +1110:skia_png_write_finish_row +1111:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29 +1112:skcms_GetTagBySignature +1113:scalbn +1114:hb_lazy_loader_t\2c\20hb_face_t\2c\2024u\2c\20OT::GDEF_accelerator_t>::do_destroy\28OT::GDEF_accelerator_t*\29 +1115:hb_buffer_get_glyph_infos +1116:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1117:get_gsubgpos_table\28hb_face_t*\2c\20unsigned\20int\29 +1118:exp2f +1119:cff2_path_param_t::line_to\28CFF::point_t\20const&\29 +1120:cff1_path_param_t::line_to\28CFF::point_t\20const&\29 +1121:cf2_stack_getReal +1122:cf2_hintmap_map +1123:antifilldot8\28int\2c\20int\2c\20int\2c\20int\2c\20SkBlitter*\2c\20bool\29 +1124:afm_stream_skip_spaces +1125:WebPRescalerInit +1126:WebPRescalerExportRow +1127:SkWStream::writeDecAsText\28int\29 +1128:SkTypeface::fontStyle\28\29\20const +1129:SkTextBlobBuilder::allocInternal\28SkFont\20const&\2c\20SkTextBlob::GlyphPositioning\2c\20int\2c\20int\2c\20SkPoint\2c\20SkRect\20const*\29 +1130:SkTDStorage::append\28void\20const*\2c\20int\29 +1131:SkString::Rec::Make\28char\20const*\2c\20unsigned\20long\29::$_0::operator\28\29\28\29\20const +1132:SkShaders::Color\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\29 +1133:SkShader::makeWithLocalMatrix\28SkMatrix\20const&\29\20const +1134:SkSL::Parser::assignmentExpression\28\29 +1135:SkSL::ConstructorSplat::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1136:SkSL::ConstructorScalarCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1137:SkResourceCache::Find\28SkResourceCache::Key\20const&\2c\20bool\20\28*\29\28SkResourceCache::Rec\20const&\2c\20void*\29\2c\20void*\29 +1138:SkRegion::SkRegion\28SkIRect\20const&\29 +1139:SkRect::toQuad\28SkPoint*\29\20const +1140:SkRasterPipeline::appendTransferFunction\28skcms_TransferFunction\20const&\29 +1141:SkRasterPipeline::appendStore\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +1142:SkRasterClip::SkRasterClip\28\29 +1143:SkRRect::checkCornerContainment\28float\2c\20float\29\20const +1144:SkPictureData::getImage\28SkReadBuffer*\29\20const +1145:SkPathMeasure::getLength\28\29 +1146:SkPathBuilder::~SkPathBuilder\28\29 +1147:SkPathBuilder::detach\28\29 +1148:SkPathBuilder::SkPathBuilder\28\29 +1149:SkPath::addPoly\28SkPoint\20const*\2c\20int\2c\20bool\29 +1150:SkPaint::refPathEffect\28\29\20const +1151:SkMipmap::getLevel\28int\2c\20SkMipmap::Level*\29\20const +1152:SkMD5::bytesWritten\28\29\20const +1153:SkJSONWriter::appendCString\28char\20const*\2c\20char\20const*\29 +1154:SkIntersections::setCoincident\28int\29 +1155:SkImageFilter_Base::flatten\28SkWriteBuffer&\29\20const +1156:SkDrawBase::SkDrawBase\28\29 +1157:SkDescriptor::operator==\28SkDescriptor\20const&\29\20const +1158:SkDLine::NearPointV\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1159:SkDLine::NearPointH\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1160:SkDLine::ExactPointV\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1161:SkDLine::ExactPointH\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +1162:SkColorSpaceXformSteps::apply\28SkRasterPipeline*\29\20const +1163:SkCanvas::drawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +1164:SkCanvas::drawColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +1165:SkCanvas::aboutToDraw\28SkPaint\20const&\2c\20SkRect\20const*\2c\20SkEnumBitMask\29 +1166:SkBulkGlyphMetrics::~SkBulkGlyphMetrics\28\29 +1167:SkBulkGlyphMetrics::SkBulkGlyphMetrics\28SkStrikeSpec\20const&\29 +1168:SkBlockAllocator::releaseBlock\28SkBlockAllocator::Block*\29 +1169:SkBitmap::asImage\28\29\20const +1170:SkAAClipBlitterWrapper::SkAAClipBlitterWrapper\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1171:OT::MVAR::get_var\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29\20const +1172:OT::GDEF_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1173:GrXferProcessor::GrXferProcessor\28GrProcessor::ClassID\2c\20bool\2c\20GrProcessorAnalysisCoverage\29 +1174:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20GrCaps\20const&\2c\20float\20const*\29 +1175:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\29 +1176:GrSimpleMeshDrawOpHelper::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20bool*\29 +1177:GrRecordingContext::OwnedArenas::get\28\29 +1178:GrProxyProvider::createProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\29 +1179:GrProxyProvider::assignUniqueKeyToProxy\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\29 +1180:GrProcessorSet::finalize\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrCaps\20const&\2c\20GrClampType\2c\20SkRGBA4f<\28SkAlphaType\292>*\29 +1181:GrOpFlushState::allocator\28\29 +1182:GrOp::cutChain\28\29 +1183:GrMeshDrawTarget::makeVertexWriter\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +1184:GrGpuResource::GrGpuResource\28GrGpu*\2c\20std::__2::basic_string_view>\29 +1185:GrGeometryProcessor::TextureSampler::reset\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +1186:GrGeometryProcessor::AttributeSet::Iter::operator++\28\29 +1187:GrGeometryProcessor::AttributeSet::Iter::operator*\28\29\20const +1188:GrGLTextureParameters::set\28GrGLTextureParameters::SamplerOverriddenState\20const*\2c\20GrGLTextureParameters::NonsamplerState\20const&\2c\20unsigned\20long\20long\29 +1189:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29 +1190:GrBackendTexture::~GrBackendTexture\28\29 +1191:FT_Outline_Get_CBox +1192:FT_Get_Sfnt_Table +1193:std::__2::moneypunct::negative_sign\5babi:nn180100\5d\28\29\20const +1194:std::__2::moneypunct::neg_format\5babi:nn180100\5d\28\29\20const +1195:std::__2::moneypunct::frac_digits\5babi:nn180100\5d\28\29\20const +1196:std::__2::moneypunct::do_pos_format\28\29\20const +1197:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +1198:std::__2::char_traits::copy\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20unsigned\20long\29 +1199:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1200:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1201:std::__2::basic_string\2c\20std::__2::allocator>::__set_size\5babi:nn180100\5d\28unsigned\20long\29 +1202:std::__2::basic_string\2c\20std::__2::allocator>::__get_short_size\5babi:nn180100\5d\28\29\20const +1203:std::__2::basic_string\2c\20std::__2::allocator>::__assign_external\28char\20const*\2c\20unsigned\20long\29 +1204:std::__2::__unwrap_iter_impl\2c\20true>::__unwrap\5babi:nn180100\5d\28std::__2::__wrap_iter\29 +1205:std::__2::__itoa::__append2\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1206:sktext::gpu::GlyphVector::glyphs\28\29\20const +1207:sktext::SkStrikePromise::SkStrikePromise\28sktext::SkStrikePromise&&\29 +1208:skif::FilterResult::resolve\28skif::Context\20const&\2c\20skif::LayerSpace\2c\20bool\29\20const +1209:skif::FilterResult::analyzeBounds\28SkMatrix\20const&\2c\20SkIRect\20const&\2c\20skif::FilterResult::BoundsScope\29\20const +1210:skia_private::THashMap::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +1211:skia_png_read_finish_row +1212:skia_png_handle_unknown +1213:skia_png_gamma_correct +1214:skia_png_colorspace_sync +1215:skia_png_app_warning +1216:skia::textlayout::TextStyle::operator=\28skia::textlayout::TextStyle\20const&\29 +1217:skia::textlayout::TextLine::offset\28\29\20const +1218:skia::textlayout::Run::placeholderStyle\28\29\20const +1219:skgpu::ganesh::SurfaceFillContext::fillRectWithFP\28SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +1220:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20std::__2::basic_string_view>\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1221:skgpu::ganesh::SurfaceContext::PixelTransferResult::~PixelTransferResult\28\29 +1222:skgpu::ganesh::ClipStack::SaveRecord::state\28\29\20const +1223:sk_doubles_nearly_equal_ulps\28double\2c\20double\2c\20unsigned\20char\29 +1224:ps_parser_to_token +1225:non-virtual\20thunk\20to\20GrOpFlushState::allocator\28\29 +1226:hb_face_t::load_upem\28\29\20const +1227:hb_buffer_t::merge_out_clusters\28unsigned\20int\2c\20unsigned\20int\29 +1228:hb_buffer_t::enlarge\28unsigned\20int\29 +1229:hb_buffer_destroy +1230:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20SkCanvas::PointMode\2c\20unsigned\20long\2c\20int\2c\20SkPaint&\29\2c\20SkCanvas*\2c\20SkCanvas::PointMode\2c\20unsigned\20long\2c\20int\2c\20SkPaint*\29 +1231:cff_index_init +1232:cf2_glyphpath_curveTo +1233:bool\20std::__2::operator!=\5babi:nn180100\5d\28std::__2::__wrap_iter\20const&\2c\20std::__2::__wrap_iter\20const&\29 +1234:atan2f +1235:__isspace +1236:WebPCopyPlane +1237:SkTextBlobBuilder::TightRunBounds\28SkTextBlob::RunRecord\20const&\29 +1238:SkTMaskGamma_build_correcting_lut\28unsigned\20char*\2c\20unsigned\20int\2c\20float\2c\20SkColorSpaceLuminance\20const&\2c\20float\29 +1239:SkSurface_Raster::type\28\29\20const +1240:SkString::swap\28SkString&\29 +1241:SkString::reset\28\29 +1242:SkSampler::Fill\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::ZeroInitialized\29 +1243:SkSL::Type::MakeTextureType\28char\20const*\2c\20SpvDim_\2c\20bool\2c\20bool\2c\20bool\2c\20SkSL::Type::TextureAccess\29 +1244:SkSL::Type::MakeSpecialType\28char\20const*\2c\20char\20const*\2c\20SkSL::Type::TypeKind\29 +1245:SkSL::RP::Builder::push_slots_or_immutable\28SkSL::RP::SlotRange\2c\20SkSL::RP::BuilderOp\29 +1246:SkSL::RP::Builder::push_clone_from_stack\28SkSL::RP::SlotRange\2c\20int\2c\20int\29 +1247:SkSL::Program::~Program\28\29 +1248:SkSL::PipelineStage::PipelineStageCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1249:SkSL::Operator::isAssignment\28\29\20const +1250:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mul\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +1251:SkSL::InlineCandidateAnalyzer::visitStatement\28std::__2::unique_ptr>*\2c\20bool\29 +1252:SkSL::GLSLCodeGenerator::writeModifiers\28SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20bool\29 +1253:SkSL::ExpressionStatement::Make\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +1254:SkSL::ConstructorCompound::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +1255:SkSL::Analysis::IsSameExpressionTree\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +1256:SkSL::AliasType::resolve\28\29\20const +1257:SkResourceCache::Add\28SkResourceCache::Rec*\2c\20void*\29 +1258:SkRegion::writeToMemory\28void*\29\20const +1259:SkReadBuffer::readMatrix\28SkMatrix*\29 +1260:SkReadBuffer::readBool\28\29 +1261:SkRasterPipeline::appendConstantColor\28SkArenaAlloc*\2c\20float\20const*\29 +1262:SkRasterClip::setRect\28SkIRect\20const&\29 +1263:SkRasterClip::SkRasterClip\28SkRasterClip\20const&\29 +1264:SkPathWriter::isClosed\28\29\20const +1265:SkPathMeasure::~SkPathMeasure\28\29 +1266:SkPathMeasure::SkPathMeasure\28SkPath\20const&\2c\20bool\2c\20float\29 +1267:SkPath::swap\28SkPath&\29 +1268:SkParse::FindScalars\28char\20const*\2c\20float*\2c\20int\29 +1269:SkPaint::operator=\28SkPaint\20const&\29 +1270:SkOpSpan::computeWindSum\28\29 +1271:SkOpSegment::existing\28double\2c\20SkOpSegment\20const*\29\20const +1272:SkOpSegment::addCurveTo\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkPathWriter*\29\20const +1273:SkOpPtT::find\28SkOpSegment\20const*\29\20const +1274:SkOpCoincidence::addEndMovedSpans\28SkOpSpan\20const*\2c\20SkOpSpanBase\20const*\29 +1275:SkNoDrawCanvas::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +1276:SkMakeImageFromRasterBitmap\28SkBitmap\20const&\2c\20SkCopyPixelsMode\29 +1277:SkImage_Ganesh::SkImage_Ganesh\28sk_sp\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20SkColorInfo\29 +1278:SkImageInfo::makeColorSpace\28sk_sp\29\20const +1279:SkImageInfo::computeOffset\28int\2c\20int\2c\20unsigned\20long\29\20const +1280:SkImage::refColorSpace\28\29\20const +1281:SkGlyph::imageSize\28\29\20const +1282:SkFont::textToGlyphs\28void\20const*\2c\20unsigned\20long\2c\20SkTextEncoding\2c\20unsigned\20short*\2c\20int\29\20const +1283:SkFont::setSubpixel\28bool\29 +1284:SkDraw::SkDraw\28\29 +1285:SkData::MakeZeroInitialized\28unsigned\20long\29 +1286:SkColorTypeIsAlwaysOpaque\28SkColorType\29 +1287:SkColorFilter::makeComposed\28sk_sp\29\20const +1288:SkCodec::SkCodec\28SkEncodedInfo&&\2c\20skcms_PixelFormat\2c\20std::__2::unique_ptr>\2c\20SkEncodedOrigin\29 +1289:SkChopQuadAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +1290:SkCanvas::drawImageRect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +1291:SkBmpCodec::getDstRow\28int\2c\20int\29\20const +1292:SkBlockMemoryStream::getLength\28\29\20const +1293:SkAutoDescriptor::SkAutoDescriptor\28\29 +1294:SkAAClipBlitterWrapper::init\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1295:SkAAClipBlitterWrapper::SkAAClipBlitterWrapper\28\29 +1296:GrTriangulator::Comparator::sweep_lt\28SkPoint\20const&\2c\20SkPoint\20const&\29\20const +1297:GrTextureProxy::textureType\28\29\20const +1298:GrSurfaceProxy::createSurfaceImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\29\20const +1299:GrStyledShape::writeUnstyledKey\28unsigned\20int*\29\20const +1300:GrStyledShape::simplify\28\29 +1301:GrSkSLFP::setInput\28std::__2::unique_ptr>\29 +1302:GrSimpleMeshDrawOpHelperWithStencil::GrSimpleMeshDrawOpHelperWithStencil\28GrProcessorSet*\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +1303:GrShape::operator=\28GrShape\20const&\29 +1304:GrResourceProvider::createPatternedIndexBuffer\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\2c\20skgpu::UniqueKey\20const*\29 +1305:GrRenderTarget::~GrRenderTarget\28\29 +1306:GrRecordingContextPriv::makeSC\28GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +1307:GrOpFlushState::detachAppliedClip\28\29 +1308:GrGpuBuffer::map\28\29 +1309:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\29 +1310:GrGLSLShaderBuilder::declAppend\28GrShaderVar\20const&\29 +1311:GrGLGpu::didDrawTo\28GrRenderTarget*\29 +1312:GrFragmentProcessors::Make\28GrRecordingContext*\2c\20SkColorFilter\20const*\2c\20std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1313:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +1314:GrCaps::validateSurfaceParams\28SkISize\20const&\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20GrTextureType\29\20const +1315:GrBufferAllocPool::putBack\28unsigned\20long\29 +1316:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29::$_0::operator\28\29\28SkIRect\2c\20SkIRect\29\20const +1317:GrBackendTexture::GrBackendTexture\28\29 +1318:GrAAConvexTessellator::createInsetRing\28GrAAConvexTessellator::Ring\20const&\2c\20GrAAConvexTessellator::Ring*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +1319:FT_Stream_GetByte +1320:FT_Set_Transform +1321:FT_Add_Module +1322:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +1323:AlmostLessOrEqualUlps\28float\2c\20float\29 +1324:ActiveEdge::intersect\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29\20const +1325:wrapper_cmp +1326:void\20std::__2::reverse\5babi:nn180100\5d\28char*\2c\20char*\29 +1327:void\20std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__do_rehash\28unsigned\20long\29 +1328:void\20emscripten::internal::MemberAccess::setWire\28bool\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\2c\20bool\29 +1329:tanf +1330:std::__2::vector>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29 +1331:std::__2::vector>::__alloc\5babi:nn180100\5d\28\29 +1332:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ios_base&\2c\20wchar_t\29 +1333:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ios_base&\2c\20char\29 +1334:std::__2::char_traits::to_int_type\5babi:nn180100\5d\28char\29 +1335:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1336:std::__2::basic_ios>::~basic_ios\28\29 +1337:std::__2::basic_ios>::setstate\5babi:nn180100\5d\28unsigned\20int\29 +1338:std::__2::__compressed_pair_elem::__compressed_pair_elem\5babi:nn180100\5d\28void\20\28*&&\29\28void*\29\29 +1339:sktext::gpu::GlyphVector::~GlyphVector\28\29 +1340:sktext::StrikeMutationMonitor::~StrikeMutationMonitor\28\29 +1341:sktext::StrikeMutationMonitor::StrikeMutationMonitor\28sktext::StrikeForGPU*\29 +1342:skif::RoundOut\28SkRect\29 +1343:skif::LayerSpace::contains\28skif::LayerSpace\20const&\29\20const +1344:skif::FilterResult::AutoSurface::snap\28\29 +1345:skif::FilterResult::AutoSurface::AutoSurface\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult::PixelBoundary\2c\20bool\2c\20SkSurfaceProps\20const*\29 +1346:skif::Backend::~Backend\28\29_2313 +1347:skia_private::TArray::push_back\28skif::FilterResult::Builder::SampledFilterResult&&\29 +1348:skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>::~STArray\28\29 +1349:skia_png_chunk_unknown_handling +1350:skia::textlayout::TextStyle::TextStyle\28\29 +1351:skia::textlayout::TextLine::iterateThroughSingleRunByStyles\28skia::textlayout::TextLine::TextAdjustment\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::StyleType\2c\20std::__2::function\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\20const&\29\20const +1352:skgpu::ganesh::SurfaceFillContext::internalClear\28SkIRect\20const*\2c\20std::__2::array\2c\20bool\29 +1353:skgpu::ganesh::SurfaceDrawContext::fillRectToRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +1354:skgpu::SkSLToBackend\28SkSL::ShaderCaps\20const*\2c\20bool\20\28*\29\28SkSL::Program&\2c\20SkSL::ShaderCaps\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\29\2c\20char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20skgpu::ShaderErrorHandler*\29 +1355:skgpu::GetApproxSize\28SkISize\29 +1356:skcms_Matrix3x3_invert +1357:read_curve\28unsigned\20char\20const*\2c\20unsigned\20int\2c\20skcms_Curve*\2c\20unsigned\20int*\29 +1358:hb_vector_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>\2c\20false>::push\28\29 +1359:hb_font_t::scale_glyph_extents\28hb_glyph_extents_t*\29 +1360:hb_buffer_append +1361:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1362:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1363:emscripten::internal::MethodInvoker\29\2c\20void\2c\20SkFont*\2c\20sk_sp>::invoke\28void\20\28SkFont::*\20const&\29\28sk_sp\29\2c\20SkFont*\2c\20sk_sp*\29 +1364:emscripten::internal::Invoker::invoke\28unsigned\20long\20\28*\29\28\29\29 +1365:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +1366:cos +1367:char*\20std::__2::__rewrap_iter\5babi:nn180100\5d>\28char*\2c\20char*\29 +1368:cf2_glyphpath_lineTo +1369:bool\20emscripten::internal::MemberAccess::getWire\28bool\20RuntimeEffectUniform::*\20const&\2c\20RuntimeEffectUniform&\29 +1370:alloc_small +1371:af_latin_hints_compute_segments +1372:_hb_glyph_info_set_unicode_props\28hb_glyph_info_t*\2c\20hb_buffer_t*\29 +1373:__lshrti3 +1374:__letf2 +1375:__cxx_global_array_dtor_5558 +1376:\28anonymous\20namespace\29::SkBlurImageFilter::~SkBlurImageFilter\28\29 +1377:SkUTF::UTF8ToUTF16\28unsigned\20short*\2c\20int\2c\20char\20const*\2c\20unsigned\20long\29 +1378:SkUTF::ToUTF16\28int\2c\20unsigned\20short*\29 +1379:SkTextBlobBuilder::~SkTextBlobBuilder\28\29 +1380:SkTextBlobBuilder::ConservativeRunBounds\28SkTextBlob::RunRecord\20const&\29 +1381:SkSwizzler::swizzle\28void*\2c\20unsigned\20char\20const*\29 +1382:SkSurfaces::RenderTarget\28GrRecordingContext*\2c\20skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20int\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const*\2c\20bool\2c\20bool\29 +1383:SkSurface::makeImageSnapshot\28\29 +1384:SkString::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +1385:SkString::insertUnichar\28unsigned\20long\2c\20int\29 +1386:SkStrikeSpec::findOrCreateScopedStrike\28sktext::StrikeForGPUCacheInterface*\29\20const +1387:SkStrikeCache::GlobalStrikeCache\28\29 +1388:SkShader::isAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +1389:SkSL::is_constant_value\28SkSL::Expression\20const&\2c\20double\29 +1390:SkSL::evaluate_pairwise_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +1391:SkSL::\28anonymous\20namespace\29::ReturnsOnAllPathsVisitor::visitStatement\28SkSL::Statement\20const&\29 +1392:SkSL::Type::MakeScalarType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type::NumberKind\2c\20signed\20char\2c\20signed\20char\29 +1393:SkSL::RP::Generator::pushBinaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +1394:SkSL::RP::Builder::push_clone\28int\2c\20int\29 +1395:SkSL::ProgramUsage::remove\28SkSL::Statement\20const*\29 +1396:SkSL::Parser::statement\28bool\29 +1397:SkSL::Operator::determineBinaryType\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\29\20const +1398:SkSL::ModifierFlags::description\28\29\20const +1399:SkSL::Layout::paddedDescription\28\29\20const +1400:SkSL::FieldAccess::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20int\2c\20SkSL::FieldAccessOwnerKind\29 +1401:SkSL::ConstructorCompoundCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1402:SkSL::Compiler::~Compiler\28\29 +1403:SkRuntimeEffect::findChild\28std::__2::basic_string_view>\29\20const +1404:SkRect\20skif::Mapping::map\28SkRect\20const&\2c\20SkMatrix\20const&\29 +1405:SkRectPriv::Subtract\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkIRect*\29 +1406:SkPictureRecorder::SkPictureRecorder\28\29 +1407:SkPictureData::~SkPictureData\28\29 +1408:SkPathMeasure::nextContour\28\29 +1409:SkPathMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29 +1410:SkPathBuilder::lineTo\28SkPoint\29 +1411:SkPath::getPoint\28int\29\20const +1412:SkPath::getLastPt\28SkPoint*\29\20const +1413:SkPaint::setBlender\28sk_sp\29 +1414:SkPaint::setAlphaf\28float\29 +1415:SkOpSegment::addT\28double\29 +1416:SkNoPixelsDevice::ClipState&\20skia_private::TArray::emplace_back\28SkIRect&&\2c\20bool&&\2c\20bool&&\29 +1417:SkNextID::ImageID\28\29 +1418:SkMessageBus::Inbox::Inbox\28unsigned\20int\29 +1419:SkImage_Lazy::generator\28\29\20const +1420:SkImage_Base::~SkImage_Base\28\29 +1421:SkImage_Base::SkImage_Base\28SkImageInfo\20const&\2c\20unsigned\20int\29 +1422:SkImageInfo::Make\28SkISize\2c\20SkColorType\2c\20SkAlphaType\2c\20sk_sp\29 +1423:SkImage::isAlphaOnly\28\29\20const +1424:SkFont::getWidthsBounds\28unsigned\20short\20const*\2c\20int\2c\20float*\2c\20SkRect*\2c\20SkPaint\20const*\29\20const +1425:SkFont::getMetrics\28SkFontMetrics*\29\20const +1426:SkFont::SkFont\28sk_sp\2c\20float\29 +1427:SkFont::SkFont\28\29 +1428:SkDrawBase::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20SkRect\20const*\29\20const +1429:SkDevice::setGlobalCTM\28SkM44\20const&\29 +1430:SkDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +1431:SkConvertPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +1432:SkConic::chopAt\28float\2c\20SkConic*\29\20const +1433:SkColorTypeBytesPerPixel\28SkColorType\29 +1434:SkColorSpaceSingletonFactory::Make\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +1435:SkColorSpace::gammaIsLinear\28\29\20const +1436:SkColorSpace::MakeRGB\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +1437:SkColorFilter::asAColorMode\28unsigned\20int*\2c\20SkBlendMode*\29\20const +1438:SkCodec::fillIncompleteImage\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::ZeroInitialized\2c\20int\2c\20int\29 +1439:SkCanvas::saveLayer\28SkRect\20const*\2c\20SkPaint\20const*\29 +1440:SkCanvas::drawPaint\28SkPaint\20const&\29 +1441:SkCanvas::ImageSetEntry::~ImageSetEntry\28\29 +1442:SkBulkGlyphMetrics::glyphs\28SkSpan\29 +1443:SkBitmap::operator=\28SkBitmap&&\29 +1444:SkBitmap::getGenerationID\28\29\20const +1445:SkArenaAllocWithReset::reset\28\29 +1446:OT::Layout::GPOS_impl::AnchorFormat3::sanitize\28hb_sanitize_context_t*\29\20const +1447:OT::GSUB_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1448:OT::GDEF::get_mark_attachment_type\28unsigned\20int\29\20const +1449:OT::GDEF::get_glyph_class\28unsigned\20int\29\20const +1450:OT::CmapSubtable::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +1451:GrTriangulator::Edge::disconnect\28\29 +1452:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\2c\20bool\29 +1453:GrSurfaceProxyView::mipmapped\28\29\20const +1454:GrSurfaceProxy::instantiateImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::UniqueKey\20const*\29 +1455:GrSimpleMeshDrawOpHelperWithStencil::isCompatible\28GrSimpleMeshDrawOpHelperWithStencil\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +1456:GrSimpleMeshDrawOpHelperWithStencil::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20bool*\29 +1457:GrShape::simplifyRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20unsigned\20int\29 +1458:GrQuad::projectedBounds\28\29\20const +1459:GrProcessorSet::MakeEmptySet\28\29 +1460:GrPorterDuffXPFactory::SimpleSrcOverXP\28\29 +1461:GrPixmap::Allocate\28GrImageInfo\20const&\29 +1462:GrPathTessellationShader::MakeSimpleTriangleShader\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +1463:GrMakeCachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\29 +1464:GrImageInfo::operator=\28GrImageInfo&&\29 +1465:GrImageInfo::makeColorType\28GrColorType\29\20const +1466:GrGpuResource::setUniqueKey\28skgpu::UniqueKey\20const&\29 +1467:GrGpuResource::release\28\29 +1468:GrGpuResource::isPurgeable\28\29\20const +1469:GrGeometryProcessor::textureSampler\28int\29\20const +1470:GrGeometryProcessor::AttributeSet::end\28\29\20const +1471:GrGeometryProcessor::AttributeSet::begin\28\29\20const +1472:GrGLSLShaderBuilder::addFeature\28unsigned\20int\2c\20char\20const*\29 +1473:GrGLGpu::clearErrorsAndCheckForOOM\28\29 +1474:GrGLGpu::bindSurfaceFBOForPixelOps\28GrSurface*\2c\20int\2c\20unsigned\20int\2c\20GrGLGpu::TempFBOTarget\29 +1475:GrGLCompileAndAttachShader\28GrGLContext\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20bool\2c\20GrThreadSafePipelineBuilder::Stats*\2c\20skgpu::ShaderErrorHandler*\29 +1476:GrDirectContextPriv::flushSurfaces\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +1477:GrDefaultGeoProcFactory::Make\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +1478:GrConvertPixels\28GrPixmap\20const&\2c\20GrCPixmap\20const&\2c\20bool\29 +1479:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +1480:GrColorInfo::GrColorInfo\28\29 +1481:GrBlurUtils::convolve_gaussian_1d\28skgpu::ganesh::SurfaceFillContext*\2c\20GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\2c\20SkIRect\20const&\2c\20SkAlphaType\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\29 +1482:GrBackendFormat::operator=\28GrBackendFormat\20const&\29 +1483:FT_GlyphLoader_Rewind +1484:FT_Done_Face +1485:Cr_z_inflate +1486:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +1487:wmemchr +1488:void\20std::__2::__stable_sort\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +1489:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20unsigned\20int*&\2c\20unsigned\20int*&\29 +1490:toupper +1491:top12_15700 +1492:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1493:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1494:std::__2::ctype::narrow\5babi:nn180100\5d\28char\2c\20char\29\20const +1495:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28wchar_t\20const*\29 +1496:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1497:std::__2::basic_streambuf>::~basic_streambuf\28\29 +1498:std::__2::basic_streambuf>::setg\5babi:nn180100\5d\28char*\2c\20char*\2c\20char*\29 +1499:std::__2::__num_get::__stage2_int_loop\28wchar_t\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20wchar_t\20const*\29 +1500:std::__2::__num_get::__stage2_int_loop\28char\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20char\20const*\29 +1501:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1502:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1503:src_p\28unsigned\20char\2c\20unsigned\20char\29 +1504:skif::LayerSpace::inverseMapRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29\20const +1505:skif::FilterResult::subset\28skif::LayerSpace\20const&\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +1506:skif::FilterResult::operator=\28skif::FilterResult&&\29 +1507:skia_private::THashMap::operator\5b\5d\28SkSL::Variable\20const*\20const&\29 +1508:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +1509:skia_private::TArray::resize_back\28int\29 +1510:skia_png_sig_cmp +1511:skia_png_get_valid +1512:skia_png_gamma_8bit_correct +1513:skia_png_free_data +1514:skia_png_destroy_read_struct +1515:skia_png_chunk_warning +1516:skia::textlayout::TextLine::measureTextInsideOneRun\28skia::textlayout::SkRange\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20float\2c\20bool\2c\20skia::textlayout::TextLine::TextAdjustment\29\20const +1517:skia::textlayout::Run::positionX\28unsigned\20long\29\20const +1518:skia::textlayout::Run::Run\28skia::textlayout::ParagraphImpl*\2c\20SkShaper::RunHandler::RunInfo\20const&\2c\20unsigned\20long\2c\20float\2c\20bool\2c\20float\2c\20unsigned\20long\2c\20float\29 +1519:skia::textlayout::ParagraphCacheKey::operator==\28skia::textlayout::ParagraphCacheKey\20const&\29\20const +1520:skia::textlayout::FontCollection::enableFontFallback\28\29 +1521:skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\294>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\298>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::ReplicateLineEndPoints\2c\20skgpu::tess::TrackJoinControlPoints>::chopAndWriteCubics\28skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20int\29 +1522:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::vertexSize\28\29\20const +1523:skgpu::ganesh::Device::readSurfaceView\28\29 +1524:skgpu::ganesh::ClipStack::clip\28skgpu::ganesh::ClipStack::RawElement&&\29 +1525:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::RawElement\20const&\29\20const +1526:skgpu::ganesh::ClipStack::RawElement::RawElement\28SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\2c\20SkClipOp\29 +1527:skgpu::Swizzle::asString\28\29\20const +1528:skgpu::ScratchKey::GenerateResourceType\28\29 +1529:skgpu::GetBlendFormula\28bool\2c\20bool\2c\20SkBlendMode\29 +1530:skcms_Transform::$_2::operator\28\29\28skcms_Curve\20const*\2c\20int\29\20const +1531:sbrk +1532:ps_tofixedarray +1533:processPropertySeq\28UBiDi*\2c\20LevState*\2c\20unsigned\20char\2c\20int\2c\20int\29 +1534:png_format_buffer +1535:png_check_keyword +1536:nextafterf +1537:jpeg_huff_decode +1538:hb_unicode_funcs_destroy +1539:hb_serialize_context_t::pop_discard\28\29 +1540:hb_lazy_loader_t\2c\20hb_face_t\2c\205u\2c\20OT::hmtx_accelerator_t>::do_destroy\28OT::hmtx_accelerator_t*\29 +1541:hb_lazy_loader_t\2c\20hb_face_t\2c\2015u\2c\20OT::glyf_accelerator_t>::do_destroy\28OT::glyf_accelerator_t*\29 +1542:hb_font_t::get_glyph_h_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +1543:hb_buffer_t::next_glyph\28\29 +1544:hb_buffer_set_flags +1545:hb_blob_create_sub_blob +1546:hb_array_t::hash\28\29\20const +1547:hairquad\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +1548:fmt_u +1549:flush_pending +1550:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\29\2c\20SkPath*\29 +1551:do_fixed +1552:destroy_face +1553:decltype\28fp\28\28SkRecords::NoOp*\29\28nullptr\29\29\29\20SkRecord::Record::mutate\28SkRecord::Destroyer&\29 +1554:char*\20const&\20std::__2::max\5babi:nn180100\5d\28char*\20const&\2c\20char*\20const&\29 +1555:cf2_stack_pushInt +1556:cf2_interpT2CharString +1557:cf2_glyphpath_moveTo +1558:bool\20hb_hashmap_t::set_with_hash\28unsigned\20int\20const&\2c\20unsigned\20int\2c\20unsigned\20int\20const&\2c\20bool\29 +1559:_hb_ot_metrics_get_position_common\28hb_font_t*\2c\20hb_ot_metrics_tag_t\2c\20int*\29 +1560:__wasi_syscall_ret +1561:__tandf +1562:__floatunsitf +1563:__cxa_allocate_exception +1564:\28anonymous\20namespace\29::PathGeoBuilder::createMeshAndPutBackReserve\28\29 +1565:\28anonymous\20namespace\29::MeshOp::fixedFunctionFlags\28\29\20const +1566:\28anonymous\20namespace\29::DrawAtlasOpImpl::fixedFunctionFlags\28\29\20const +1567:WebPDemuxGetI +1568:VP8LDoFillBitWindow +1569:VP8LClear +1570:TT_Get_MM_Var +1571:SkWStream::writeScalar\28float\29 +1572:SkTypeface::isFixedPitch\28\29\20const +1573:SkTypeface::MakeEmpty\28\29 +1574:SkTSect::BinarySearch\28SkTSect*\2c\20SkTSect*\2c\20SkIntersections*\29 +1575:SkTConic::operator\5b\5d\28int\29\20const +1576:SkTBlockList::reset\28\29 +1577:SkTBlockList::reset\28\29 +1578:SkString::insertU32\28unsigned\20long\2c\20unsigned\20int\29 +1579:SkSpecialImages::MakeDeferredFromGpu\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1580:SkShaders::MatrixRec::applyForFragmentProcessor\28SkMatrix\20const&\29\20const +1581:SkShaders::MatrixRec::MatrixRec\28SkMatrix\20const&\29 +1582:SkScan::FillRect\28SkRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +1583:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +1584:SkSL::optimize_comparison\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20bool\20\28*\29\28double\2c\20double\29\29 +1585:SkSL::coalesce_n_way_vector\28SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +1586:SkSL::Type::convertArraySize\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20long\20long\29\20const +1587:SkSL::String::appendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20...\29 +1588:SkSL::RP::Generator::returnComplexity\28SkSL::FunctionDefinition\20const*\29 +1589:SkSL::RP::Builder::dot_floats\28int\29 +1590:SkSL::ProgramUsage::get\28SkSL::FunctionDeclaration\20const&\29\20const +1591:SkSL::Parser::type\28SkSL::Modifiers*\29 +1592:SkSL::Parser::modifiers\28\29 +1593:SkSL::ConstructorDiagonalMatrix::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1594:SkSL::ConstructorArrayCast::~ConstructorArrayCast\28\29 +1595:SkSL::ConstantFolder::MakeConstantValueForVariable\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +1596:SkSL::Compiler::Compiler\28\29 +1597:SkSL::Analysis::IsTrivialExpression\28SkSL::Expression\20const&\29 +1598:SkRuntimeEffectPriv::CanDraw\28SkCapabilities\20const*\2c\20SkRuntimeEffect\20const*\29 +1599:SkRuntimeEffectBuilder::makeShader\28SkMatrix\20const*\29\20const +1600:SkRegion::setPath\28SkPath\20const&\2c\20SkRegion\20const&\29 +1601:SkRegion::operator=\28SkRegion\20const&\29 +1602:SkRegion::op\28SkRegion\20const&\2c\20SkRegion\20const&\2c\20SkRegion::Op\29 +1603:SkRegion::Iterator::next\28\29 +1604:SkRasterPipeline::compile\28\29\20const +1605:SkRasterPipeline::appendClampIfNormalized\28SkImageInfo\20const&\29 +1606:SkRasterClip::translate\28int\2c\20int\2c\20SkRasterClip*\29\20const +1607:SkRasterClip::op\28SkIRect\20const&\2c\20SkClipOp\29 +1608:SkRRect::transform\28SkMatrix\20const&\2c\20SkRRect*\29\20const +1609:SkPixmap::extractSubset\28SkPixmap*\2c\20SkIRect\20const&\29\20const +1610:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20SkBBHFactory*\29 +1611:SkPathWriter::finishContour\28\29 +1612:SkPathStroker::cubicPerpRay\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +1613:SkPathMeasure::getPosTan\28float\2c\20SkPoint*\2c\20SkPoint*\29 +1614:SkPath::getSegmentMasks\28\29\20const +1615:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\29 +1616:SkPaintPriv::ComputeLuminanceColor\28SkPaint\20const&\29 +1617:SkPaint::nothingToDraw\28\29\20const +1618:SkPaint::isSrcOver\28\29\20const +1619:SkOpAngle::linesOnOriginalSide\28SkOpAngle\20const*\29 +1620:SkNotifyBitmapGenIDIsStale\28unsigned\20int\29 +1621:SkNoDrawCanvas::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +1622:SkMipmap::Build\28SkPixmap\20const&\2c\20SkDiscardableMemory*\20\28*\29\28unsigned\20long\29\2c\20bool\29 +1623:SkMeshSpecification::~SkMeshSpecification\28\29 +1624:SkMemoryStream::SkMemoryStream\28void\20const*\2c\20unsigned\20long\2c\20bool\29 +1625:SkMatrix::setSinCos\28float\2c\20float\2c\20float\2c\20float\29 +1626:SkMatrix::setRSXform\28SkRSXform\20const&\29 +1627:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint3\20const*\2c\20int\29\20const +1628:SkMaskFilterBase::getFlattenableType\28\29\20const +1629:SkMaskBuilder::AllocImage\28unsigned\20long\2c\20SkMaskBuilder::AllocType\29 +1630:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_2D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1631:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_1D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1632:SkIntersections::insertNear\28double\2c\20double\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29 +1633:SkIntersections::flip\28\29 +1634:SkImageFilters::Empty\28\29 +1635:SkImageFilter_Base::~SkImageFilter_Base\28\29 +1636:SkGlyph::drawable\28\29\20const +1637:SkFont::unicharToGlyph\28int\29\20const +1638:SkFont::setTypeface\28sk_sp\29 +1639:SkFont::setHinting\28SkFontHinting\29 +1640:SkFindQuadMaxCurvature\28SkPoint\20const*\29 +1641:SkEvalCubicAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29 +1642:SkDrawTiler::SkDrawTiler\28SkBitmapDevice*\2c\20SkRect\20const*\29 +1643:SkDevice::accessPixels\28SkPixmap*\29 +1644:SkDeque::SkDeque\28unsigned\20long\2c\20void*\2c\20unsigned\20long\2c\20int\29 +1645:SkDCubic::FindExtrema\28double\20const*\2c\20double*\29 +1646:SkCodec::getPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const*\29 +1647:SkCanvas::internalRestore\28\29 +1648:SkCanvas::init\28sk_sp\29 +1649:SkCanvas::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +1650:SkBlendMode_AsCoeff\28SkBlendMode\2c\20SkBlendModeCoeff*\2c\20SkBlendModeCoeff*\29 +1651:SkBlendMode\20SkReadBuffer::read32LE\28SkBlendMode\29 +1652:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29 +1653:SkAutoPixmapStorage::tryAlloc\28SkImageInfo\20const&\29 +1654:SkAAClip::SkAAClip\28\29 +1655:Read255UShort +1656:OT::glyf_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +1657:OT::VariationStore::sanitize\28hb_sanitize_context_t*\29\20const +1658:OT::Layout::GPOS_impl::ValueFormat::sanitize_value_devices\28hb_sanitize_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\29\20const +1659:OT::Layout::GPOS_impl::ValueFormat::apply_value\28OT::hb_ot_apply_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\2c\20hb_glyph_position_t&\29\20const +1660:GrTriangulator::VertexList::insert\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\29 +1661:GrTriangulator::Poly::addEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Side\2c\20GrTriangulator*\29 +1662:GrTriangulator::EdgeList::remove\28GrTriangulator::Edge*\29 +1663:GrStyledShape::operator=\28GrStyledShape\20const&\29 +1664:GrSimpleMeshDrawOpHelperWithStencil::createProgramInfoWithStencil\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1665:GrResourceCache::purgeAsNeeded\28\29 +1666:GrRenderTask::addDependency\28GrDrawingManager*\2c\20GrSurfaceProxy*\2c\20skgpu::Mipmapped\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +1667:GrRenderTask::GrRenderTask\28\29 +1668:GrRenderTarget::onRelease\28\29 +1669:GrProxyProvider::findOrCreateProxyByUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxy::UseAllocator\29 +1670:GrProcessorSet::operator==\28GrProcessorSet\20const&\29\20const +1671:GrPathUtils::generateQuadraticPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +1672:GrMeshDrawOp::QuadHelper::QuadHelper\28GrMeshDrawTarget*\2c\20unsigned\20long\2c\20int\29 +1673:GrIsStrokeHairlineOrEquivalent\28GrStyle\20const&\2c\20SkMatrix\20const&\2c\20float*\29 +1674:GrImageContext::abandoned\28\29 +1675:GrGpuResource::registerWithCache\28skgpu::Budgeted\29 +1676:GrGpuBuffer::isMapped\28\29\20const +1677:GrGpu::submitToGpu\28GrSubmitInfo\20const&\29 +1678:GrGpu::didWriteToSurface\28GrSurface*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const*\2c\20unsigned\20int\29\20const +1679:GrGeometryProcessor::ProgramImpl::setupUniformColor\28GrGLSLFPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20GrResourceHandle*\29 +1680:GrGLGpu::flushRenderTarget\28GrGLRenderTarget*\2c\20bool\29 +1681:GrFragmentProcessor::visitTextureEffects\28std::__2::function\20const&\29\20const +1682:GrFragmentProcessor::visitProxies\28std::__2::function\20const&\29\20const +1683:GrFragmentProcessor::MakeColor\28SkRGBA4f<\28SkAlphaType\292>\29 +1684:GrBufferAllocPool::makeSpace\28unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\29 +1685:GrBackendTextures::GetGLTextureInfo\28GrBackendTexture\20const&\2c\20GrGLTextureInfo*\29 +1686:FilterLoop26_C +1687:FT_Vector_Transform +1688:FT_Vector_NormLen +1689:FT_Outline_Transform +1690:CFF::dict_opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +1691:AlmostBetweenUlps\28float\2c\20float\2c\20float\29 +1692:1455 +1693:1456 +1694:1457 +1695:1458 +1696:void\20extend_pts<\28SkPaint::Cap\292>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1697:void\20extend_pts<\28SkPaint::Cap\291>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1698:ubidi_getMemory_skia +1699:transform\28unsigned\20int*\2c\20unsigned\20char\20const*\29 +1700:strcspn +1701:std::__2::vector>::__append\28unsigned\20long\29 +1702:std::__2::locale::locale\28std::__2::locale\20const&\29 +1703:std::__2::locale::classic\28\29 +1704:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const +1705:std::__2::chrono::__libcpp_steady_clock_now\28\29 +1706:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28char\20const*\29 +1707:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20char\20const*\29 +1708:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +1709:std::__2::__wrap_iter\20std::__2::vector>::__insert_with_size\5babi:ne180100\5d\28std::__2::__wrap_iter\2c\20float\20const*\2c\20float\20const*\2c\20long\29 +1710:std::__2::__throw_bad_variant_access\5babi:ne180100\5d\28\29 +1711:std::__2::__split_buffer>::push_front\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +1712:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20wchar_t&\29 +1713:std::__2::__num_get::__do_widen\28std::__2::ios_base&\2c\20wchar_t*\29\20const +1714:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20char&\29 +1715:std::__2::__itoa::__append1\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1716:sktext::gpu::VertexFiller::vertexStride\28SkMatrix\20const&\29\20const +1717:skif::RoundIn\28SkRect\29 +1718:skif::LayerSpace::round\28\29\20const +1719:skif::FilterResult::applyTransform\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkSamplingOptions\20const&\29\20const +1720:skif::FilterResult::Builder::~Builder\28\29 +1721:skif::FilterResult::Builder::Builder\28skif::Context\20const&\29 +1722:skia_private::THashTable::Traits>::resize\28int\29 +1723:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +1724:skia_private::TArray::resize_back\28int\29 +1725:skia_private::TArray::push_back_raw\28int\29 +1726:skia_png_set_progressive_read_fn +1727:skia_png_set_longjmp_fn +1728:skia_png_set_interlace_handling +1729:skia_png_reciprocal +1730:skia_png_read_chunk_header +1731:skia_png_get_io_ptr +1732:skia_png_calloc +1733:skia::textlayout::TextLine::~TextLine\28\29 +1734:skia::textlayout::ParagraphStyle::ParagraphStyle\28skia::textlayout::ParagraphStyle\20const&\29 +1735:skia::textlayout::ParagraphCacheKey::~ParagraphCacheKey\28\29 +1736:skia::textlayout::OneLineShaper::RunBlock*\20std::__2::vector>::__emplace_back_slow_path\28skia::textlayout::OneLineShaper::RunBlock&\29 +1737:skia::textlayout::FontCollection::findTypefaces\28std::__2::vector>\20const&\2c\20SkFontStyle\2c\20std::__2::optional\20const&\29 +1738:skia::textlayout::Cluster::trimmedWidth\28unsigned\20long\29\20const +1739:skgpu::ganesh::TextureOp::BatchSizeLimiter::createOp\28GrTextureSetEntry*\2c\20int\2c\20GrAAType\29 +1740:skgpu::ganesh::SurfaceFillContext::fillWithFP\28std::__2::unique_ptr>\29 +1741:skgpu::ganesh::SurfaceDrawContext::drawShapeUsingPathRenderer\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\2c\20bool\29 +1742:skgpu::ganesh::SurfaceDrawContext::drawRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const*\29 +1743:skgpu::ganesh::SurfaceDrawContext::drawRRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20GrStyle\20const&\29 +1744:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29 +1745:skgpu::ganesh::SmallPathAtlasMgr::reset\28\29 +1746:skgpu::ganesh::QuadPerEdgeAA::CalcIndexBufferOption\28GrAAType\2c\20int\29 +1747:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29::$_0::operator\28\29\28GrSurfaceProxyView\20const&\29\20const +1748:skgpu::ganesh::Device::targetProxy\28\29 +1749:skgpu::ganesh::ClipStack::getConservativeBounds\28\29\20const +1750:skgpu::TAsyncReadResult::addTransferResult\28skgpu::ganesh::SurfaceContext::PixelTransferResult\20const&\2c\20SkISize\2c\20unsigned\20long\2c\20skgpu::TClientMappedBufferManager*\29 +1751:skgpu::Swizzle::apply\28SkRasterPipeline*\29\20const +1752:skgpu::Plot::resetRects\28\29 +1753:skcms_TransferFunction_invert +1754:ps_dimension_add_t1stem +1755:powf +1756:log +1757:jcopy_sample_rows +1758:hb_font_t::mults_changed\28\29 +1759:hb_font_t::has_func\28unsigned\20int\29 +1760:hb_buffer_create_similar +1761:getenv +1762:ft_service_list_lookup +1763:fseek +1764:fflush +1765:expm1 +1766:emscripten::internal::MethodInvoker::invoke\28void\20\28GrDirectContext::*\20const&\29\28\29\2c\20GrDirectContext*\29 +1767:emscripten::internal::Invoker>::invoke\28sk_sp\20\28*\29\28\29\29 +1768:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +1769:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28SkFont&\29\2c\20SkFont*\29 +1770:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkCanvas\20const&\2c\20unsigned\20long\29\2c\20SkCanvas*\2c\20unsigned\20long\29 +1771:decltype\28fp.sanitize\28this\2c\20std::forward\28fp1\29\29\29\20hb_sanitize_context_t::_dispatch\2c\20true>\2c\20OT::ChainContextFormat3\20const*>\28OT::OffsetTo\2c\20true>\20const&\2c\20hb_priority<1u>\2c\20OT::ChainContextFormat3\20const*&&\29 +1772:crc32_z +1773:char*\20sktext::gpu::BagOfBytes::allocateBytesFor\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +1774:cf2_hintmap_insertHint +1775:cf2_hintmap_build +1776:cf2_glyphpath_pushPrevElem +1777:bool\20std::__2::__less::operator\28\29\5babi:nn180100\5d\28unsigned\20int\20const&\2c\20unsigned\20long\20const&\29\20const +1778:blit_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +1779:afm_stream_read_one +1780:af_shaper_get_cluster +1781:af_latin_hints_link_segments +1782:af_latin_compute_stem_width +1783:af_glyph_hints_reload +1784:acosf +1785:__syscall_ret +1786:__sin +1787:__cos +1788:VP8LHuffmanTablesDeallocate +1789:SkWriter32::writeSampling\28SkSamplingOptions\20const&\29 +1790:SkVertices::Builder::detach\28\29 +1791:SkUTF::NextUTF8WithReplacement\28char\20const**\2c\20char\20const*\29 +1792:SkTypeface_FreeType::~SkTypeface_FreeType\28\29 +1793:SkTypeface_FreeType::FaceRec::~FaceRec\28\29 +1794:SkTypeface::SkTypeface\28SkFontStyle\20const&\2c\20bool\29 +1795:SkTextBlob::RunRecord::textSizePtr\28\29\20const +1796:SkTMultiMap::remove\28skgpu::ScratchKey\20const&\2c\20GrGpuResource\20const*\29 +1797:SkTMultiMap::insert\28skgpu::ScratchKey\20const&\2c\20GrGpuResource*\29 +1798:SkTDStorage::insert\28int\2c\20int\2c\20void\20const*\29 +1799:SkTDPQueue<\28anonymous\20namespace\29::RunIteratorQueue::Entry\2c\20&\28anonymous\20namespace\29::RunIteratorQueue::CompareEntry\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\2c\20\28int*\20\28*\29\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\290>::insert\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\29 +1800:SkSwizzler::Make\28SkEncodedInfo\20const&\2c\20unsigned\20int\20const*\2c\20SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20SkIRect\20const*\29 +1801:SkSurfaces::Raster\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20SkSurfaceProps\20const*\29 +1802:SkSurface_Base::~SkSurface_Base\28\29 +1803:SkString::resize\28unsigned\20long\29 +1804:SkStrikeSpec::SkStrikeSpec\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +1805:SkStrikeSpec::MakeMask\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +1806:SkStrikeSpec::MakeCanonicalized\28SkFont\20const&\2c\20SkPaint\20const*\29 +1807:SkStrikeCache::findOrCreateStrike\28SkStrikeSpec\20const&\29 +1808:SkStrike::unlock\28\29 +1809:SkStrike::lock\28\29 +1810:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +1811:SkShaders::MatrixRec::apply\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +1812:SkShaders::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29 +1813:SkScan::FillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\29 +1814:SkScalerContext_FreeType::emboldenIfNeeded\28FT_FaceRec_*\2c\20FT_GlyphSlotRec_*\2c\20unsigned\20short\29 +1815:SkSafeMath::Add\28unsigned\20long\2c\20unsigned\20long\29 +1816:SkSL::Type::displayName\28\29\20const +1817:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20double\2c\20SkSL::Position\29\20const +1818:SkSL::RP::SlotManager::addSlotDebugInfoForGroup\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20int*\2c\20bool\29 +1819:SkSL::RP::Generator::foldComparisonOp\28SkSL::Operator\2c\20int\29 +1820:SkSL::RP::Builder::branch_if_no_lanes_active\28int\29 +1821:SkSL::PrefixExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +1822:SkSL::Parser::parseArrayDimensions\28SkSL::Position\2c\20SkSL::Type\20const**\29 +1823:SkSL::Parser::arraySize\28long\20long*\29 +1824:SkSL::Operator::operatorName\28\29\20const +1825:SkSL::ModifierFlags::paddedDescription\28\29\20const +1826:SkSL::ExpressionArray::clone\28\29\20const +1827:SkSL::ConstantFolder::GetConstantValue\28SkSL::Expression\20const&\2c\20double*\29 +1828:SkSL::ConstantFolder::GetConstantInt\28SkSL::Expression\20const&\2c\20long\20long*\29 +1829:SkSL::Compiler::convertProgram\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::ProgramSettings\20const&\29 +1830:SkResourceCache::remove\28SkResourceCache::Rec*\29 +1831:SkRegion::op\28SkRegion\20const&\2c\20SkIRect\20const&\2c\20SkRegion::Op\29 +1832:SkRegion::Iterator::Iterator\28SkRegion\20const&\29 +1833:SkRecords::FillBounds::bounds\28SkRecords::DrawArc\20const&\29\20const +1834:SkReadBuffer::setMemory\28void\20const*\2c\20unsigned\20long\29 +1835:SkRasterClip::SkRasterClip\28SkIRect\20const&\29 +1836:SkRRect::writeToMemory\28void*\29\20const +1837:SkRRect::setRectXY\28SkRect\20const&\2c\20float\2c\20float\29 +1838:SkPointPriv::DistanceToLineBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPointPriv::Side*\29 +1839:SkPoint::setNormalize\28float\2c\20float\29 +1840:SkPngCodecBase::~SkPngCodecBase\28\29 +1841:SkPixmapUtils::SwapWidthHeight\28SkImageInfo\20const&\29 +1842:SkPictureRecorder::finishRecordingAsPicture\28\29 +1843:SkPathPriv::ComputeFirstDirection\28SkPath\20const&\29 +1844:SkPathEdgeIter::SkPathEdgeIter\28SkPath\20const&\29 +1845:SkPath::rewind\28\29 +1846:SkPath::isLine\28SkPoint*\29\20const +1847:SkPath::incReserve\28int\2c\20int\2c\20int\29 +1848:SkPath::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +1849:SkPaint::setStrokeCap\28SkPaint::Cap\29 +1850:SkPaint::refShader\28\29\20const +1851:SkOpSpan::setWindSum\28int\29 +1852:SkOpSegment::markDone\28SkOpSpan*\29 +1853:SkOpSegment::markAndChaseWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int\2c\20int\2c\20SkOpSpanBase**\29 +1854:SkOpContourBuilder::addCurve\28SkPath::Verb\2c\20SkPoint\20const*\2c\20float\29 +1855:SkOpAngle::starter\28\29 +1856:SkOpAngle::insert\28SkOpAngle*\29 +1857:SkMatrixPriv::InverseMapRect\28SkMatrix\20const&\2c\20SkRect*\2c\20SkRect\20const&\29 +1858:SkMatrix::setSinCos\28float\2c\20float\29 +1859:SkMatrix::decomposeScale\28SkSize*\2c\20SkMatrix*\29\20const +1860:SkMaskFilter::MakeBlur\28SkBlurStyle\2c\20float\2c\20bool\29 +1861:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29 +1862:SkMD5::write\28void\20const*\2c\20unsigned\20long\29 +1863:SkLineClipper::IntersectLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\29 +1864:SkImage_GaneshBase::SkImage_GaneshBase\28sk_sp\2c\20SkImageInfo\2c\20unsigned\20int\29 +1865:SkImageGenerator::onRefEncodedData\28\29 +1866:SkImage::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\29\20const +1867:SkImage::makeRasterImage\28GrDirectContext*\2c\20SkImage::CachingHint\29\20const +1868:SkIDChangeListener::SkIDChangeListener\28\29 +1869:SkIDChangeListener::List::reset\28\29 +1870:SkGradientBaseShader::flatten\28SkWriteBuffer&\29\20const +1871:SkFontMgr::RefEmpty\28\29 +1872:SkFont::setEdging\28SkFont::Edging\29 +1873:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda0'\28\29::operator\28\29\28\29\20const +1874:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda'\28\29::operator\28\29\28\29\20const +1875:SkEvalQuadAt\28SkPoint\20const*\2c\20float\29 +1876:SkEncodedInfo::makeImageInfo\28\29\20const +1877:SkEdgeClipper::next\28SkPoint*\29 +1878:SkDevice::scalerContextFlags\28\29\20const +1879:SkConic::evalAt\28float\2c\20SkPoint*\2c\20SkPoint*\29\20const +1880:SkColorInfo::SkColorInfo\28SkColorType\2c\20SkAlphaType\2c\20sk_sp\29 +1881:SkColorFilters::Blend\28unsigned\20int\2c\20SkBlendMode\29 +1882:SkCodec::skipScanlines\28int\29 +1883:SkChopCubicAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +1884:SkCapabilities::RasterBackend\28\29 +1885:SkCanvas::topDevice\28\29\20const +1886:SkCanvas::saveLayer\28SkCanvas::SaveLayerRec\20const&\29 +1887:SkCanvas::imageInfo\28\29\20const +1888:SkCanvas::drawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +1889:SkCanvas::drawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +1890:SkCanvas::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +1891:SkBmpBaseCodec::~SkBmpBaseCodec\28\29 +1892:SkBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +1893:SkBitmap::operator=\28SkBitmap\20const&\29 +1894:SkBitmap::extractSubset\28SkBitmap*\2c\20SkIRect\20const&\29\20const +1895:SkBitmap::SkBitmap\28SkBitmap&&\29 +1896:SkBinaryWriteBuffer::writeByteArray\28void\20const*\2c\20unsigned\20long\29 +1897:SkBinaryWriteBuffer::SkBinaryWriteBuffer\28SkSerialProcs\20const&\29 +1898:SkBaseShadowTessellator::handleLine\28SkPoint\20const&\29 +1899:SkAAClip::setRegion\28SkRegion\20const&\29 +1900:SaveErrorCode +1901:R +1902:OT::hb_ot_apply_context_t::_set_glyph_class\28unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +1903:OT::cmap::find_subtable\28unsigned\20int\2c\20unsigned\20int\29\20const +1904:GrXPFactory::FromBlendMode\28SkBlendMode\29 +1905:GrTriangulator::setBottom\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +1906:GrTriangulator::mergeCollinearEdges\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +1907:GrThreadSafeCache::find\28skgpu::UniqueKey\20const&\29 +1908:GrThreadSafeCache::add\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +1909:GrThreadSafeCache::Entry::makeEmpty\28\29 +1910:GrSurfaceProxyView::operator==\28GrSurfaceProxyView\20const&\29\20const +1911:GrSurfaceProxyView::Copy\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\29 +1912:GrSurfaceProxyPriv::doLazyInstantiation\28GrResourceProvider*\29 +1913:GrSurfaceProxy::isFunctionallyExact\28\29\20const +1914:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20sk_sp*\29 +1915:GrSimpleMeshDrawOpHelperWithStencil::fixedFunctionFlags\28\29\20const +1916:GrSimpleMeshDrawOpHelper::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20GrProcessorAnalysisColor*\29 +1917:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrProcessorSet&&\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrPipeline::InputFlags\2c\20GrUserStencilSettings\20const*\29 +1918:GrSimpleMeshDrawOpHelper::CreatePipeline\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20skgpu::Swizzle\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrProcessorSet&&\2c\20GrPipeline::InputFlags\29 +1919:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20void\20const*\2c\20skgpu::UniqueKey\20const&\29 +1920:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20skgpu::UniqueKey\20const&\2c\20void\20\28*\29\28skgpu::VertexWriter\2c\20unsigned\20long\29\29 +1921:GrResourceCache::findAndRefScratchResource\28skgpu::ScratchKey\20const&\29 +1922:GrRecordingContextPriv::makeSFC\28GrImageInfo\2c\20std::__2::basic_string_view>\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1923:GrQuadUtils::TessellationHelper::Vertices::moveAlong\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1924:GrQuad::asRect\28SkRect*\29\20const +1925:GrProcessorSet::GrProcessorSet\28GrProcessorSet&&\29 +1926:GrPathUtils::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +1927:GrGpu::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +1928:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +1929:GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +1930:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +1931:GrGLSLColorSpaceXformHelper::emitCode\28GrGLSLUniformHandler*\2c\20GrColorSpaceXform\20const*\2c\20unsigned\20int\29 +1932:GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +1933:GrGLRenderTarget::bindInternal\28unsigned\20int\2c\20bool\29 +1934:GrGLGpu::getErrorAndCheckForOOM\28\29 +1935:GrGLGpu::bindTexture\28int\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20GrGLTexture*\29 +1936:GrFragmentProcessor::visitWithImpls\28std::__2::function\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\20const +1937:GrFragmentProcessor::ColorMatrix\28std::__2::unique_ptr>\2c\20float\20const*\2c\20bool\2c\20bool\2c\20bool\29 +1938:GrDrawingManager::appendTask\28sk_sp\29 +1939:GrColorInfo::GrColorInfo\28GrColorInfo\20const&\29 +1940:GrCaps::isFormatCompressed\28GrBackendFormat\20const&\29\20const +1941:GrAAConvexTessellator::lineTo\28SkPoint\20const&\2c\20GrAAConvexTessellator::CurveState\29 +1942:FT_Stream_OpenMemory +1943:FT_Select_Charmap +1944:FT_Get_Next_Char +1945:FT_Get_Module_Interface +1946:FT_Done_Size +1947:DecodeImageStream +1948:CFF::opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +1949:CFF::Charset::get_glyph\28unsigned\20int\2c\20unsigned\20int\29\20const +1950:1713 +1951:1714 +1952:1715 +1953:1716 +1954:1717 +1955:wuffs_gif__decoder__num_decoded_frames +1956:void\20std::__2::reverse\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t*\29 +1957:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29_14370 +1958:void\20merge_sort<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +1959:void\20merge_sort<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +1960:void\20emscripten::internal::MemberAccess::setWire\28float\20StrokeOpts::*\20const&\2c\20StrokeOpts&\2c\20float\29 +1961:validate_offsetToRestore\28SkReadBuffer*\2c\20unsigned\20long\29 +1962:ubidi_setPara_skia +1963:ubidi_getVisualRun_skia +1964:ubidi_getRuns_skia +1965:ubidi_getClass_skia +1966:tt_set_mm_blend +1967:tt_face_get_ps_name +1968:tt_face_get_location +1969:trinkle +1970:std::__2::unique_ptr::release\5babi:nn180100\5d\28\29 +1971:std::__2::pair\2c\20void*>*>\2c\20bool>\20std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__emplace_unique_key_args\2c\20std::__2::tuple<>>\28GrTriangulator::Vertex*\20const&\2c\20std::__2::piecewise_construct_t\20const&\2c\20std::__2::tuple&&\2c\20std::__2::tuple<>&&\29 +1972:std::__2::pair::pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +1973:std::__2::moneypunct::do_decimal_point\28\29\20const +1974:std::__2::moneypunct::do_decimal_point\28\29\20const +1975:std::__2::istreambuf_iterator>::istreambuf_iterator\5babi:nn180100\5d\28std::__2::basic_istream>&\29 +1976:std::__2::ios_base::good\5babi:nn180100\5d\28\29\20const +1977:std::__2::ctype::toupper\5babi:nn180100\5d\28char\29\20const +1978:std::__2::chrono::duration>::duration\5babi:nn180100\5d\28long\20long\20const&\29 +1979:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +1980:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +1981:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +1982:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +1983:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +1984:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +1985:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +1986:std::__2::basic_string\2c\20std::__2::allocator>&\20std::__2::basic_string\2c\20std::__2::allocator>::__assign_no_alias\28char\20const*\2c\20unsigned\20long\29 +1987:std::__2::basic_streambuf>::__pbump\5babi:nn180100\5d\28long\29 +1988:std::__2::basic_iostream>::~basic_iostream\28\29_16074 +1989:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::allocator&\2c\20wchar_t*\2c\20unsigned\20long\29 +1990:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::allocator&\2c\20char*\2c\20unsigned\20long\29 +1991:std::__2::__shared_count::__release_shared\5babi:nn180100\5d\28\29 +1992:std::__2::__num_put_base::__format_int\28char*\2c\20char\20const*\2c\20bool\2c\20unsigned\20int\29 +1993:std::__2::__num_put_base::__format_float\28char*\2c\20char\20const*\2c\20unsigned\20int\29 +1994:std::__2::__itoa::__append8\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1995:sktext::gpu::VertexFiller::deviceRectAndCheckTransform\28SkMatrix\20const&\29\20const +1996:sktext::gpu::TextBlob::Key::operator==\28sktext::gpu::TextBlob::Key\20const&\29\20const +1997:sktext::gpu::GlyphVector::packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29 +1998:sktext::SkStrikePromise::strike\28\29 +1999:skif::\28anonymous\20namespace\29::downscale_step_count\28float\29 +2000:skif::LayerSpace::relevantSubset\28skif::LayerSpace\2c\20SkTileMode\29\20const +2001:skif::FilterResult::getAnalyzedShaderView\28skif::Context\20const&\2c\20SkSamplingOptions\20const&\2c\20SkEnumBitMask\29\20const +2002:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20bool\2c\20SkBlender\20const*\29\20const +2003:skif::FilterResult::applyCrop\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkTileMode\29\20const +2004:skif::Context::~Context\28\29 +2005:skia_private::THashTable\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair>::resize\28int\29 +2006:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +2007:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::removeSlot\28int\29 +2008:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +2009:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot::emplace\28sk_sp&&\2c\20unsigned\20int\29 +2010:skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::~THashMap\28\29 +2011:skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::THashMap\28std::initializer_list>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>\29 +2012:skia_private::TArray::move\28void*\29 +2013:skia_private::TArray::Plane\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +2014:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +2015:skia_private::TArray::operator=\28skia_private::TArray&&\29 +2016:skia_private::TArray\2c\20true>::push_back\28SkRGBA4f<\28SkAlphaType\293>&&\29 +2017:skia_png_set_text_2 +2018:skia_png_set_palette_to_rgb +2019:skia_png_handle_IHDR +2020:skia_png_handle_IEND +2021:skia::textlayout::operator==\28skia::textlayout::FontArguments\20const&\2c\20skia::textlayout::FontArguments\20const&\29 +2022:skia::textlayout::TextWrapper::TextStretch::extend\28skia::textlayout::Cluster*\29 +2023:skia::textlayout::FontCollection::getFontManagerOrder\28\29\20const +2024:skia::textlayout::FontArguments::FontArguments\28skia::textlayout::FontArguments\20const&\29 +2025:skia::textlayout::Decorations::calculateGaps\28skia::textlayout::TextLine::ClipContext\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\29 +2026:skia::textlayout::Cluster::isSoftBreak\28\29\20const +2027:skia::textlayout::Cluster::Cluster\28skia::textlayout::ParagraphImpl*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkSpan\2c\20float\2c\20float\29 +2028:skia::textlayout::Block&\20skia_private::TArray::emplace_back\28unsigned\20long&&\2c\20unsigned\20long&&\2c\20skia::textlayout::TextStyle\20const&\29 +2029:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::fixedFunctionFlags\28\29\20const +2030:skgpu::ganesh::SurfaceFillContext::fillRectWithFP\28SkIRect\20const&\2c\20SkMatrix\20const&\2c\20std::__2::unique_ptr>\29 +2031:skgpu::ganesh::SurfaceFillContext::SurfaceFillContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +2032:skgpu::ganesh::SurfaceDrawContext::drawShape\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\29 +2033:skgpu::ganesh::SurfaceDrawContext::drawPaint\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\29 +2034:skgpu::ganesh::SurfaceDrawContext::MakeWithFallback\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2035:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29 +2036:skgpu::ganesh::SurfaceContext::PixelTransferResult::operator=\28skgpu::ganesh::SurfaceContext::PixelTransferResult&&\29 +2037:skgpu::ganesh::SmallPathAtlasMgr::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +2038:skgpu::ganesh::OpsTask::~OpsTask\28\29 +2039:skgpu::ganesh::OpsTask::setColorLoadOp\28GrLoadOp\2c\20std::__2::array\29 +2040:skgpu::ganesh::OpsTask::deleteOps\28\29 +2041:skgpu::ganesh::FillRectOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +2042:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29::$_0::operator\28\29\28int\29\20const +2043:skgpu::ganesh::ClipStack::~ClipStack\28\29 +2044:skgpu::TClientMappedBufferManager::~TClientMappedBufferManager\28\29 +2045:skgpu::TAsyncReadResult::Plane&\20skia_private::TArray::Plane\2c\20false>::emplace_back\2c\20unsigned\20long&>\28sk_sp&&\2c\20unsigned\20long&\29 +2046:skgpu::Plot::addSubImage\28int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +2047:skgpu::GetLCDBlendFormula\28SkBlendMode\29 +2048:skcms_TransferFunction_isHLGish +2049:skcms_Matrix3x3_concat +2050:sk_srgb_linear_singleton\28\29 +2051:sk_sp::reset\28SkPathRef*\29 +2052:sk_sp*\20std::__2::vector\2c\20std::__2::allocator>>::__push_back_slow_path\20const&>\28sk_sp\20const&\29 +2053:shr +2054:shl +2055:setRegionCheck\28SkRegion*\2c\20SkRegion\20const&\29 +2056:read_header\28SkStream*\2c\20SkPngChunkReader*\2c\20SkCodec**\2c\20png_struct_def**\2c\20png_info_def**\29 +2057:read_curves\28unsigned\20char\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skcms_Curve*\29 +2058:qsort +2059:ps_dimension_set_mask_bits +2060:operator==\28SkPath\20const&\2c\20SkPath\20const&\29 +2061:mbrtowc +2062:jround_up +2063:jpeg_make_d_derived_tbl +2064:jpeg_destroy +2065:ilogbf +2066:hb_ucd_get_unicode_funcs +2067:hb_syllabic_insert_dotted_circles\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +2068:hb_shape_full +2069:hb_serialize_context_t::~hb_serialize_context_t\28\29 +2070:hb_serialize_context_t::resolve_links\28\29 +2071:hb_serialize_context_t::reset\28\29 +2072:hb_lazy_loader_t\2c\20hb_face_t\2c\2016u\2c\20OT::cff1_accelerator_t>::do_destroy\28OT::cff1_accelerator_t*\29 +2073:hb_language_from_string +2074:hb_font_destroy +2075:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2076:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2077:get_sof +2078:ftell +2079:ft_var_readpackedpoints +2080:ft_mem_strdup +2081:ft_glyphslot_done +2082:float\20emscripten::internal::MemberAccess::getWire\28float\20StrokeOpts::*\20const&\2c\20StrokeOpts&\29 +2083:fill_window +2084:exp +2085:encodeImage\28GrDirectContext*\2c\20sk_sp\2c\20SkEncodedImageFormat\2c\20int\29 +2086:emscripten::val\20MakeTypedArray\28int\2c\20float\20const*\29 +2087:emscripten::internal::MethodInvoker::invoke\28float\20\28SkContourMeasure::*\20const&\29\28\29\20const\2c\20SkContourMeasure\20const*\29 +2088:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\29\2c\20unsigned\20long\2c\20unsigned\20long\29 +2089:dquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2090:do_clip_op\28SkReadBuffer*\2c\20SkCanvas*\2c\20SkRegion::Op\2c\20SkClipOp*\29 +2091:do_anti_hairline\28int\2c\20int\2c\20int\2c\20int\2c\20SkIRect\20const*\2c\20SkBlitter*\29 +2092:doWriteReverse\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +2093:doWriteForward\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +2094:dline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2095:dispose_chunk +2096:direct_blur_y\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2097:decltype\28fp\28\28SkRecords::NoOp\29\28\29\29\29\20SkRecord::Record::visit\28SkRecords::Draw&\29\20const +2098:dcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2099:dconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2100:crop_rect_edge\28SkRect\20const&\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float*\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +2101:char\20const*\20std::__2::__rewrap_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +2102:cff_slot_load +2103:cff_parse_real +2104:cff_index_get_sid_string +2105:cff_index_access_element +2106:cf2_doStems +2107:cf2_doFlex +2108:buffer_verify_error\28hb_buffer_t*\2c\20hb_font_t*\2c\20char\20const*\2c\20...\29 +2109:blur_y_rect\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2110:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29::$_0::operator\28\29\28unsigned\20char*\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29\20const +2111:auto\20std::__2::__unwrap_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +2112:af_sort_and_quantize_widths +2113:af_glyph_hints_align_weak_points +2114:af_glyph_hints_align_strong_points +2115:af_face_globals_new +2116:af_cjk_compute_stem_width +2117:add_huff_table +2118:addPoint\28UBiDi*\2c\20int\2c\20int\29 +2119:__uselocale +2120:__math_xflow +2121:__cxxabiv1::__base_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +2122:\28anonymous\20namespace\29::make_vertices_spec\28bool\2c\20bool\29 +2123:\28anonymous\20namespace\29::gather_lines_and_quads\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\29::$_1::operator\28\29\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20bool\29\20const +2124:\28anonymous\20namespace\29::draw_stencil_rect\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrHardClip\20const&\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +2125:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2126:\28anonymous\20namespace\29::PathSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +2127:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2128:\28anonymous\20namespace\29::CacheImpl::removeInternal\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +2129:WriteRingBuffer +2130:WebPRescalerExport +2131:WebPInitAlphaProcessing +2132:WebPFreeDecBuffer +2133:WebPDemuxDelete +2134:VP8SetError +2135:VP8LInverseTransform +2136:VP8LDelete +2137:VP8LColorCacheClear +2138:TT_Load_Context +2139:StringBuffer\20apply_format_string<1024>\28char\20const*\2c\20void*\2c\20char\20\28&\29\20\5b1024\5d\2c\20SkString*\29 +2140:SkYUVAPixmaps::operator=\28SkYUVAPixmaps\20const&\29 +2141:SkYUVAPixmapInfo::SupportedDataTypes::enableDataType\28SkYUVAPixmapInfo::DataType\2c\20int\29 +2142:SkWriter32::writeMatrix\28SkMatrix\20const&\29 +2143:SkWriter32::snapshotAsData\28\29\20const +2144:SkVertices::uniqueID\28\29\20const +2145:SkVertices::approximateSize\28\29\20const +2146:SkTypefaceCache::NewTypefaceID\28\29 +2147:SkTextBlobRunIterator::next\28\29 +2148:SkTextBlobRunIterator::SkTextBlobRunIterator\28SkTextBlob\20const*\29 +2149:SkTextBlobBuilder::make\28\29 +2150:SkTextBlobBuilder::SkTextBlobBuilder\28\29 +2151:SkTSpan::closestBoundedT\28SkDPoint\20const&\29\20const +2152:SkTSect::updateBounded\28SkTSpan*\2c\20SkTSpan*\2c\20SkTSpan*\29 +2153:SkTSect::trim\28SkTSpan*\2c\20SkTSect*\29 +2154:SkTDStorage::erase\28int\2c\20int\29 +2155:SkTDPQueue::percolateUpIfNecessary\28int\29 +2156:SkSurfaceProps::SkSurfaceProps\28unsigned\20int\2c\20SkPixelGeometry\2c\20float\2c\20float\29 +2157:SkStrokerPriv::JoinFactory\28SkPaint::Join\29 +2158:SkStrokeRec::setStrokeStyle\28float\2c\20bool\29 +2159:SkStrokeRec::setFillStyle\28\29 +2160:SkStrokeRec::applyToPath\28SkPath*\2c\20SkPath\20const&\29\20const +2161:SkString::set\28char\20const*\29 +2162:SkStrikeSpec::findOrCreateStrike\28\29\20const +2163:SkStrikeSpec::MakeWithNoDevice\28SkFont\20const&\2c\20SkPaint\20const*\29 +2164:SkStrike::glyph\28SkGlyphDigest\29 +2165:SkSharedMutex::SkSharedMutex\28\29 +2166:SkShadowTessellator::MakeSpot\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkPoint3\20const&\2c\20float\2c\20bool\2c\20bool\29 +2167:SkShaders::Empty\28\29 +2168:SkShaders::Color\28unsigned\20int\29 +2169:SkShaderBase::appendRootStages\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2170:SkScalerContext::~SkScalerContext\28\29_4003 +2171:SkSL::write_stringstream\28SkSL::StringStream\20const&\2c\20SkSL::OutputStream&\29 +2172:SkSL::evaluate_3_way_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +2173:SkSL::VarDeclaration::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\2c\20std::__2::unique_ptr>\29 +2174:SkSL::Type::priority\28\29\20const +2175:SkSL::Type::checkIfUsableInArray\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +2176:SkSL::SymbolTable::takeOwnershipOfString\28std::__2::basic_string\2c\20std::__2::allocator>\29 +2177:SkSL::SymbolTable::isBuiltinType\28std::__2::basic_string_view>\29\20const +2178:SkSL::SampleUsage::merge\28SkSL::SampleUsage\20const&\29 +2179:SkSL::RP::SlotManager::mapVariableToSlots\28SkSL::Variable\20const&\2c\20SkSL::RP::SlotRange\29 +2180:SkSL::RP::Program::appendStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkSL::RP::Callbacks*\2c\20SkSpan\29\20const +2181:SkSL::RP::Generator::pushVectorizedExpression\28SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +2182:SkSL::RP::DynamicIndexLValue::dynamicSlotRange\28\29 +2183:SkSL::RP::Builder::ternary_op\28SkSL::RP::BuilderOp\2c\20int\29 +2184:SkSL::RP::Builder::simplifyPopSlotsUnmasked\28SkSL::RP::SlotRange*\29 +2185:SkSL::RP::Builder::pop_slots_unmasked\28SkSL::RP::SlotRange\29 +2186:SkSL::RP::Builder::exchange_src\28\29 +2187:SkSL::ProgramUsage::remove\28SkSL::ProgramElement\20const&\29 +2188:SkSL::ProgramUsage::isDead\28SkSL::Variable\20const&\29\20const +2189:SkSL::Pool::~Pool\28\29 +2190:SkSL::PipelineStage::PipelineStageCodeGenerator::typedVariable\28SkSL::Type\20const&\2c\20std::__2::basic_string_view>\29 +2191:SkSL::PipelineStage::PipelineStageCodeGenerator::typeName\28SkSL::Type\20const&\29 +2192:SkSL::MethodReference::~MethodReference\28\29_6852 +2193:SkSL::MethodReference::~MethodReference\28\29 +2194:SkSL::LiteralType::priority\28\29\20const +2195:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sub\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +2196:SkSL::IndexExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +2197:SkSL::GLSLCodeGenerator::writeAnyConstructor\28SkSL::AnyConstructor\20const&\2c\20SkSL::OperatorPrecedence\29 +2198:SkSL::Compiler::errorText\28bool\29 +2199:SkSL::Block::Make\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2200:SkSL::Block::MakeBlock\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2201:SkSL::Analysis::DetectVarDeclarationWithoutScope\28SkSL::Statement\20const&\2c\20SkSL::ErrorReporter*\29 +2202:SkRuntimeEffectPriv::TransformUniforms\28SkSpan\2c\20sk_sp\2c\20SkColorSpace\20const*\29 +2203:SkRuntimeEffect::getRPProgram\28SkSL::DebugTracePriv*\29\20const +2204:SkRegion::getBoundaryPath\28SkPath*\29\20const +2205:SkRegion::Spanerator::next\28int*\2c\20int*\29 +2206:SkRegion::SkRegion\28SkRegion\20const&\29 +2207:SkReduceOrder::Quad\28SkPoint\20const*\2c\20SkPoint*\29 +2208:SkRectPriv::ClosestDisjointEdge\28SkIRect\20const&\2c\20SkIRect\20const&\29 +2209:SkReadBuffer::skipByteArray\28unsigned\20long*\29 +2210:SkReadBuffer::readSampling\28\29 +2211:SkReadBuffer::readRRect\28SkRRect*\29 +2212:SkReadBuffer::checkInt\28int\2c\20int\29 +2213:SkRasterPipeline::appendMatrix\28SkArenaAlloc*\2c\20SkMatrix\20const&\29 +2214:SkQuads::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +2215:SkQuadraticEdge::updateQuadratic\28\29 +2216:SkPngCodecBase::applyXformRow\28void*\2c\20unsigned\20char\20const*\29 +2217:SkPngCodec::processData\28\29 +2218:SkPixmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +2219:SkPictureRecord::~SkPictureRecord\28\29 +2220:SkPicture::~SkPicture\28\29_3431 +2221:SkPathStroker::quadStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2222:SkPathStroker::preJoinTo\28SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\2c\20bool\29 +2223:SkPathStroker::intersectRay\28SkQuadConstruct*\2c\20SkPathStroker::IntersectRayType\29\20const +2224:SkPathStroker::cubicStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2225:SkPathStroker::conicStroke\28SkConic\20const&\2c\20SkQuadConstruct*\29 +2226:SkPathMeasure::isClosed\28\29 +2227:SkPathEffectBase::getFlattenableType\28\29\20const +2228:SkPathBuilder::moveTo\28SkPoint\29 +2229:SkPathBuilder::incReserve\28int\2c\20int\29 +2230:SkPathBuilder::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2231:SkPath::isLastContourClosed\28\29\20const +2232:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2233:SkPaintToGrPaintReplaceShader\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::unique_ptr>\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +2234:SkPaint::setStrokeMiter\28float\29 +2235:SkPaint::setStrokeJoin\28SkPaint::Join\29 +2236:SkOpSpanBase::mergeMatches\28SkOpSpanBase*\29 +2237:SkOpSpanBase::addOpp\28SkOpSpanBase*\29 +2238:SkOpSegment::subDivide\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkDCurve*\29\20const +2239:SkOpSegment::release\28SkOpSpan\20const*\29 +2240:SkOpSegment::operand\28\29\20const +2241:SkOpSegment::moveNearby\28\29 +2242:SkOpSegment::markAndChaseDone\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpSpanBase**\29 +2243:SkOpSegment::isClose\28double\2c\20SkOpSegment\20const*\29\20const +2244:SkOpSegment::init\28SkPoint*\2c\20float\2c\20SkOpContour*\2c\20SkPath::Verb\29 +2245:SkOpSegment::addT\28double\2c\20SkPoint\20const&\29 +2246:SkOpCoincidence::fixUp\28SkOpPtT*\2c\20SkOpPtT\20const*\29 +2247:SkOpCoincidence::add\28SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\29 +2248:SkOpCoincidence::addMissing\28bool*\29 +2249:SkOpCoincidence::addIfMissing\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20double\2c\20double\2c\20SkOpSegment*\2c\20SkOpSegment*\2c\20bool*\29 +2250:SkOpCoincidence::addExpanded\28\29 +2251:SkOpAngle::set\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +2252:SkOpAngle::lineOnOneSide\28SkDPoint\20const&\2c\20SkDVector\20const&\2c\20SkOpAngle\20const*\2c\20bool\29\20const +2253:SkNoPixelsDevice::ClipState::op\28SkClipOp\2c\20SkM44\20const&\2c\20SkRect\20const&\2c\20bool\2c\20bool\29 +2254:SkNoDestructor>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>>::SkNoDestructor\28skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>&&\29 +2255:SkMatrix\20skif::Mapping::map\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +2256:SkMatrixPriv::DifferentialAreaScale\28SkMatrix\20const&\2c\20SkPoint\20const&\29 +2257:SkMatrix::writeToMemory\28void*\29\20const +2258:SkMatrix::preservesRightAngles\28float\29\20const +2259:SkM44::normalizePerspective\28\29 +2260:SkLatticeIter::~SkLatticeIter\28\29 +2261:SkLatticeIter::next\28SkIRect*\2c\20SkRect*\2c\20bool*\2c\20unsigned\20int*\29 +2262:SkJpegCodec::ReadHeader\28SkStream*\2c\20SkCodec**\2c\20JpegDecoderMgr**\2c\20std::__2::unique_ptr>\29 +2263:SkJSONWriter::endObject\28\29 +2264:SkJSONWriter::endArray\28\29 +2265:SkImages::RasterFromBitmap\28SkBitmap\20const&\29 +2266:SkImage_Lazy::Validator::Validator\28sk_sp\2c\20SkColorType\20const*\2c\20sk_sp\29 +2267:SkImageShader::MakeSubset\28sk_sp\2c\20SkRect\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +2268:SkImageFilters::MatrixTransform\28SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20sk_sp\29 +2269:SkImageFilters::Image\28sk_sp\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\29 +2270:SkImageFilters::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +2271:SkImage::readPixels\28GrDirectContext*\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +2272:SkImage::readPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +2273:SkHalfToFloat\28unsigned\20short\29 +2274:SkGradientShader::MakeSweep\28float\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +2275:SkGradientShader::MakeRadial\28SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +2276:SkGradientBaseShader::commonAsAGradient\28SkShaderBase::GradientInfo*\29\20const +2277:SkGradientBaseShader::ValidGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\29 +2278:SkGradientBaseShader::SkGradientBaseShader\28SkGradientBaseShader::Descriptor\20const&\2c\20SkMatrix\20const&\29 +2279:SkGradientBaseShader::MakeDegenerateGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20float\20const*\2c\20int\2c\20sk_sp\2c\20SkTileMode\29 +2280:SkGradientBaseShader::Descriptor::~Descriptor\28\29 +2281:SkGradientBaseShader::Descriptor::Descriptor\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\29 +2282:SkGlyph::setPath\28SkArenaAlloc*\2c\20SkPath\20const*\2c\20bool\2c\20bool\29 +2283:SkFontMgr::matchFamilyStyleCharacter\28char\20const*\2c\20SkFontStyle\20const&\2c\20char\20const**\2c\20int\2c\20int\29\20const +2284:SkFont::setSize\28float\29 +2285:SkEvalQuadAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +2286:SkEncodedInfo::~SkEncodedInfo\28\29 +2287:SkEmptyFontMgr::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +2288:SkDrawableList::~SkDrawableList\28\29 +2289:SkDrawable::draw\28SkCanvas*\2c\20SkMatrix\20const*\29 +2290:SkData::PrivateNewWithCopy\28void\20const*\2c\20unsigned\20long\29::$_0::operator\28\29\28\29\20const +2291:SkDashPathEffect::Make\28float\20const*\2c\20int\2c\20float\29 +2292:SkDQuad::monotonicInX\28\29\20const +2293:SkDCubic::dxdyAtT\28double\29\20const +2294:SkDCubic::RootsValidT\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +2295:SkCubicEdge::updateCubic\28\29 +2296:SkConicalGradient::~SkConicalGradient\28\29 +2297:SkColorSpace::MakeSRGBLinear\28\29 +2298:SkColorFilters::Blend\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\2c\20SkBlendMode\29 +2299:SkColorFilterPriv::MakeGaussian\28\29 +2300:SkColorConverter::SkColorConverter\28unsigned\20int\20const*\2c\20int\29 +2301:SkCodec::startScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const*\29 +2302:SkCodec::handleFrameIndex\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20std::__2::function\29 +2303:SkCodec::getScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +2304:SkChopQuadAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +2305:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\20const*\2c\20int\29 +2306:SkChopCubicAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +2307:SkCharToGlyphCache::SkCharToGlyphCache\28\29 +2308:SkCanvas::getTotalMatrix\28\29\20const +2309:SkCanvas::getLocalToDevice\28\29\20const +2310:SkCanvas::getLocalClipBounds\28\29\20const +2311:SkCanvas::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +2312:SkCanvas::drawAtlas\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +2313:SkCanvas::concat\28SkM44\20const&\29 +2314:SkCanvas::SkCanvas\28SkBitmap\20const&\29 +2315:SkCanvas::ImageSetEntry::ImageSetEntry\28SkCanvas::ImageSetEntry\20const&\29 +2316:SkBmpCodec::ReadHeader\28SkStream*\2c\20bool\2c\20std::__2::unique_ptr>*\29 +2317:SkBlurMaskFilterImpl::computeXformedSigma\28SkMatrix\20const&\29\20const +2318:SkBlitter::blitRectRegion\28SkIRect\20const&\2c\20SkRegion\20const&\29 +2319:SkBlendMode_ShouldPreScaleCoverage\28SkBlendMode\2c\20bool\29 +2320:SkBlendMode_AppendStages\28SkBlendMode\2c\20SkRasterPipeline*\29 +2321:SkBitmap::tryAllocPixels\28SkBitmap::Allocator*\29 +2322:SkBitmap::readPixels\28SkPixmap\20const&\2c\20int\2c\20int\29\20const +2323:SkBitmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +2324:SkBitmap::installPixels\28SkPixmap\20const&\29 +2325:SkBitmap::allocPixels\28SkImageInfo\20const&\29 +2326:SkBaseShadowTessellator::handleQuad\28SkPoint\20const*\29 +2327:SkAutoDescriptor::~SkAutoDescriptor\28\29 +2328:SkAnimatedImage::getFrameCount\28\29\20const +2329:SkAAClip::~SkAAClip\28\29 +2330:SkAAClip::setPath\28SkPath\20const&\2c\20SkIRect\20const&\2c\20bool\29 +2331:SkAAClip::op\28SkAAClip\20const&\2c\20SkClipOp\29 +2332:ReadHuffmanCode_15336 +2333:OT::vmtx_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2334:OT::hb_ot_layout_lookup_accelerator_t*\20OT::hb_ot_layout_lookup_accelerator_t::create\28OT::Layout::GSUB_impl::SubstLookup\20const&\29 +2335:OT::hb_ot_apply_context_t::replace_glyph\28unsigned\20int\29 +2336:OT::cff1_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2337:OT::apply_lookup\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20OT::LookupRecord\20const*\2c\20unsigned\20int\29 +2338:OT::Layout::GPOS_impl::ValueFormat::get_device\28OT::IntType\20const*\2c\20bool*\2c\20void\20const*\2c\20hb_sanitize_context_t&\29 +2339:OT::Layout::GPOS_impl::AnchorFormat3::get_anchor\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20float*\2c\20float*\29\20const +2340:OT::Layout::GPOS_impl::AnchorFormat2::get_anchor\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20float*\2c\20float*\29\20const +2341:OT::HVARVVAR::sanitize\28hb_sanitize_context_t*\29\20const +2342:OT::GPOS_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2343:OT::ClassDef::get_class\28unsigned\20int\29\20const +2344:JpegDecoderMgr::~JpegDecoderMgr\28\29 +2345:GrTriangulator::simplify\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +2346:GrTriangulator::setTop\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2347:GrTriangulator::mergeCoincidentVertices\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29\20const +2348:GrTriangulator::Vertex*\20SkArenaAlloc::make\28SkPoint&\2c\20int&&\29 +2349:GrThreadSafeCache::remove\28skgpu::UniqueKey\20const&\29 +2350:GrThreadSafeCache::internalFind\28skgpu::UniqueKey\20const&\29 +2351:GrThreadSafeCache::internalAdd\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2352:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29 +2353:GrTexture::markMipmapsClean\28\29 +2354:GrTessellationShader::MakePipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedClip&&\2c\20GrProcessorSet&&\29 +2355:GrSurfaceProxyView::concatSwizzle\28skgpu::Swizzle\29 +2356:GrSurfaceProxy::LazyCallbackResult::LazyCallbackResult\28sk_sp\29 +2357:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20GrSurfaceProxy::RectsMustMatch\2c\20sk_sp*\29 +2358:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +2359:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +2360:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrPipeline\20const*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrUserStencilSettings\20const*\29 +2361:GrShape::simplifyLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\29 +2362:GrShape::reset\28\29 +2363:GrShape::conservativeContains\28SkPoint\20const&\29\20const +2364:GrSWMaskHelper::init\28SkIRect\20const&\29 +2365:GrResourceProvider::createNonAAQuadIndexBuffer\28\29 +2366:GrResourceProvider::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\2c\20GrResourceProvider::ZeroInit\29 +2367:GrRenderTask::addTarget\28GrDrawingManager*\2c\20sk_sp\29 +2368:GrRenderTarget::~GrRenderTarget\28\29_9526 +2369:GrRecordingContextPriv::createDevice\28skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\2c\20skgpu::ganesh::Device::InitContents\29 +2370:GrQuadUtils::WillUseHairline\28GrQuad\20const&\2c\20GrAAType\2c\20GrQuadAAFlags\29 +2371:GrQuadUtils::CropToRect\28SkRect\20const&\2c\20GrAA\2c\20DrawQuad*\2c\20bool\29 +2372:GrProxyProvider::processInvalidUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\2c\20GrProxyProvider::InvalidateGPUResource\29 +2373:GrPorterDuffXPFactory::Get\28SkBlendMode\29 +2374:GrPixmap::operator=\28GrPixmap&&\29 +2375:GrPathUtils::scaleToleranceToSrc\28float\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +2376:GrPathUtils::quadraticPointCount\28SkPoint\20const*\2c\20float\29 +2377:GrPathUtils::cubicPointCount\28SkPoint\20const*\2c\20float\29 +2378:GrPaint::setPorterDuffXPFactory\28SkBlendMode\29 +2379:GrPaint::GrPaint\28GrPaint\20const&\29 +2380:GrOpsRenderPass::draw\28int\2c\20int\29 +2381:GrOpsRenderPass::drawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +2382:GrMeshDrawOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +2383:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29 +2384:GrGradientShader::MakeGradientFP\28SkGradientBaseShader\20const&\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\2c\20std::__2::unique_ptr>\2c\20SkMatrix\20const*\29 +2385:GrGpuResource::getContext\28\29 +2386:GrGpu::writePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +2387:GrGLTexture::onSetLabel\28\29 +2388:GrGLTexture::onRelease\28\29 +2389:GrGLTexture::onAbandon\28\29 +2390:GrGLTexture::backendFormat\28\29\20const +2391:GrGLSLShaderBuilder::appendFunctionDecl\28SkSLType\2c\20char\20const*\2c\20SkSpan\29 +2392:GrGLSLProgramBuilder::fragmentProcessorHasCoordsParam\28GrFragmentProcessor\20const*\29\20const +2393:GrGLRenderTarget::onRelease\28\29 +2394:GrGLRenderTarget::onAbandon\28\29 +2395:GrGLGpu::resolveRenderFBOs\28GrGLRenderTarget*\2c\20SkIRect\20const&\2c\20GrGLRenderTarget::ResolveDirection\2c\20bool\29 +2396:GrGLGpu::flushBlendAndColorWrite\28skgpu::BlendInfo\20const&\2c\20skgpu::Swizzle\20const&\29 +2397:GrGLGpu::deleteSync\28__GLsync*\29 +2398:GrGLGetVersionFromString\28char\20const*\29 +2399:GrGLFinishCallbacks::callAll\28bool\29 +2400:GrGLCheckLinkStatus\28GrGLGpu\20const*\2c\20unsigned\20int\2c\20bool\2c\20skgpu::ShaderErrorHandler*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const**\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +2401:GrGLCaps::maxRenderTargetSampleCount\28GrGLFormat\29\20const +2402:GrFragmentProcessors::Make\28SkBlenderBase\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20GrFPArgs\20const&\29 +2403:GrFragmentProcessor::isEqual\28GrFragmentProcessor\20const&\29\20const +2404:GrFragmentProcessor::asTextureEffect\28\29\20const +2405:GrFragmentProcessor::Rect\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRect\29 +2406:GrFragmentProcessor::ModulateRGBA\28std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +2407:GrDrawingManager::~GrDrawingManager\28\29 +2408:GrDrawingManager::removeRenderTasks\28\29 +2409:GrDrawingManager::getPathRenderer\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\2c\20bool\2c\20skgpu::ganesh::PathRendererChain::DrawType\2c\20skgpu::ganesh::PathRenderer::StencilSupport*\29 +2410:GrDrawOpAtlas::compact\28skgpu::AtlasToken\29 +2411:GrCpuBuffer::ref\28\29\20const +2412:GrContext_Base::~GrContext_Base\28\29 +2413:GrContext_Base::defaultBackendFormat\28SkColorType\2c\20skgpu::Renderable\29\20const +2414:GrColorSpaceXform::XformKey\28GrColorSpaceXform\20const*\29 +2415:GrColorSpaceXform::Make\28SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +2416:GrColorSpaceXform::Make\28GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +2417:GrColorInfo::operator=\28GrColorInfo\20const&\29 +2418:GrCaps::supportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +2419:GrCaps::getFallbackColorTypeAndFormat\28GrColorType\2c\20int\29\20const +2420:GrCaps::areColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +2421:GrBufferAllocPool::~GrBufferAllocPool\28\29 +2422:GrBlurUtils::DrawShapeWithMaskFilter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\29 +2423:GrBaseContextPriv::getShaderErrorHandler\28\29\20const +2424:GrBackendTexture::GrBackendTexture\28GrBackendTexture\20const&\29 +2425:GrBackendRenderTarget::getBackendFormat\28\29\20const +2426:GrBackendFormat::operator==\28GrBackendFormat\20const&\29\20const +2427:GrAAConvexTessellator::createOuterRing\28GrAAConvexTessellator::Ring\20const&\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring*\29 +2428:GrAAConvexTessellator::createInsetRings\28GrAAConvexTessellator::Ring&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring**\29 +2429:FindSortableTop\28SkOpContourHead*\29 +2430:FT_Stream_Close +2431:FT_Set_Charmap +2432:FT_Select_Metrics +2433:FT_Outline_Decompose +2434:FT_Open_Face +2435:FT_New_Size +2436:FT_Load_Sfnt_Table +2437:FT_GlyphLoader_Add +2438:FT_Get_Color_Glyph_Paint +2439:FT_Get_Color_Glyph_Layer +2440:FT_Done_Library +2441:FT_CMap_New +2442:DecodeImageData\28sk_sp\29 +2443:Current_Ratio +2444:Cr_z__tr_stored_block +2445:ClipParams_unpackRegionOp\28SkReadBuffer*\2c\20unsigned\20int\29 +2446:CircleOp::Circle&\20skia_private::TArray::emplace_back\28CircleOp::Circle&&\29 +2447:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +2448:AlmostEqualUlps_Pin\28float\2c\20float\29 +2449:2212 +2450:2213 +2451:2214 +2452:2215 +2453:2216 +2454:wuffs_lzw__decoder__workbuf_len +2455:wuffs_gif__decoder__decode_image_config +2456:wuffs_gif__decoder__decode_frame_config +2457:winding_mono_quad\28SkPoint\20const*\2c\20float\2c\20float\2c\20int*\29 +2458:winding_mono_conic\28SkConic\20const&\2c\20float\2c\20float\2c\20int*\29 +2459:week_num +2460:wcrtomb +2461:wchar_t\20const*\20std::__2::find\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const&\29 +2462:void\20std::__2::__sort4\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +2463:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +2464:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +2465:void\20std::__2::__inplace_merge\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +2466:void\20sort_r_simple\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\2c\20void*\29\2c\20void*\29 +2467:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29_14436 +2468:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29 +2469:void\20SkTIntroSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29>\28int\2c\20double*\2c\20int\2c\20void\20SkTQSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29\20const&\29 +2470:void\20SkTIntroSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29>\28int\2c\20SkEdge*\2c\20int\2c\20void\20SkTQSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29\20const&\29 +2471:vfprintf +2472:valid_args\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20unsigned\20long*\29 +2473:update_offset_to_base\28char\20const*\2c\20long\29 +2474:update_box +2475:u_charMirror_skia +2476:tt_size_reset +2477:tt_sbit_decoder_load_metrics +2478:tt_face_find_bdf_prop +2479:tolower +2480:toTextStyle\28SimpleTextStyle\20const&\29 +2481:t1_cmap_unicode_done +2482:subdivide_cubic_to\28SkPath*\2c\20SkPoint\20const*\2c\20int\29 +2483:subdivide\28SkConic\20const&\2c\20SkPoint*\2c\20int\29 +2484:strtox_15866 +2485:strtox +2486:strtoull_l +2487:strtod +2488:std::logic_error::~logic_error\28\29_17570 +2489:std::__2::vector>::__append\28unsigned\20long\29 +2490:std::__2::vector>::push_back\5babi:ne180100\5d\28float&&\29 +2491:std::__2::vector>::__append\28unsigned\20long\29 +2492:std::__2::vector<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20std::__2::allocator<\28anonymous\20namespace\29::CacheImpl::Value*>>::__throw_length_error\5babi:ne180100\5d\28\29\20const +2493:std::__2::vector>::reserve\28unsigned\20long\29 +2494:std::__2::vector\2c\20std::__2::allocator>>::push_back\5babi:ne180100\5d\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +2495:std::__2::unique_ptr<\28anonymous\20namespace\29::SoftwarePathData\2c\20std::__2::default_delete<\28anonymous\20namespace\29::SoftwarePathData>>::reset\5babi:ne180100\5d\28\28anonymous\20namespace\29::SoftwarePathData*\29 +2496:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2497:std::__2::time_put>>::~time_put\28\29_17106 +2498:std::__2::priority_queue>\2c\20GrAATriangulator::EventComparator>::push\28GrAATriangulator::Event*\20const&\29 +2499:std::__2::pair\2c\20std::__2::allocator>>>::~pair\28\29 +2500:std::__2::locale::operator=\28std::__2::locale\20const&\29 +2501:std::__2::locale::locale\28\29 +2502:std::__2::locale::__imp::acquire\28\29 +2503:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\29 +2504:std::__2::ios_base::~ios_base\28\29 +2505:std::__2::ios_base::init\28void*\29 +2506:std::__2::ios_base::clear\28unsigned\20int\29 +2507:std::__2::fpos<__mbstate_t>::fpos\5babi:nn180100\5d\28long\20long\29 +2508:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:ne180100\5d\28SkAnimatedImage::Frame&\2c\20SkAnimatedImage::Frame&\29 +2509:std::__2::default_delete::operator\28\29\5babi:ne180100\5d\28sktext::gpu::TextBlobRedrawCoordinator*\29\20const +2510:std::__2::char_traits::move\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +2511:std::__2::char_traits::assign\5babi:nn180100\5d\28char*\2c\20unsigned\20long\2c\20char\29 +2512:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_16157 +2513:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29 +2514:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +2515:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28wchar_t\29 +2516:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +2517:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::allocator\20const&\29 +2518:std::__2::basic_string\2c\20std::__2::allocator>::__make_iterator\5babi:nn180100\5d\28char*\29 +2519:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +2520:std::__2::basic_string\2c\20std::__2::allocator>::__init_copy_ctor_external\28char16_t\20const*\2c\20unsigned\20long\29 +2521:std::__2::basic_streambuf>::step\5babi:nn180100\5d\28char*\2c\20char*\29 +2522:std::__2::basic_streambuf>::basic_streambuf\28\29 +2523:std::__2::basic_ostream>::~basic_ostream\28\29_16056 +2524:std::__2::basic_istream>::~basic_istream\28\29_16015 +2525:std::__2::basic_istream>::sentry::sentry\28std::__2::basic_istream>&\2c\20bool\29 +2526:std::__2::basic_iostream>::~basic_iostream\28\29_16077 +2527:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +2528:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +2529:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +2530:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +2531:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +2532:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +2533:std::__2::__to_address_helper\2c\20void>::__call\5babi:nn180100\5d\28std::__2::__wrap_iter\20const&\29 +2534:std::__2::__throw_length_error\5babi:ne180100\5d\28char\20const*\29 +2535:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +2536:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20wchar_t*\2c\20wchar_t&\2c\20wchar_t&\29 +2537:std::__2::__num_get::__stage2_float_loop\28wchar_t\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20wchar_t*\29 +2538:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20char*\2c\20char&\2c\20char&\29 +2539:std::__2::__num_get::__stage2_float_loop\28char\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20char*\29 +2540:std::__2::__libcpp_wcrtomb_l\5babi:nn180100\5d\28char*\2c\20wchar_t\2c\20__mbstate_t*\2c\20__locale_struct*\29 +2541:std::__2::__itoa::__base_10_u32\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2542:std::__2::__itoa::__append6\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2543:std::__2::__itoa::__append4\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2544:sktext::gpu::VertexFiller::flatten\28SkWriteBuffer&\29\20const +2545:sktext::gpu::VertexFiller::Make\28skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20SkRect\2c\20SkSpan\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::FillerType\29 +2546:sktext::gpu::SubRunContainer::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20SkRefCnt\20const*\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +2547:sktext::gpu::SubRunAllocator::SubRunAllocator\28int\29 +2548:sktext::gpu::StrikeCache::internalPurge\28unsigned\20long\29 +2549:sktext::gpu::GlyphVector::flatten\28SkWriteBuffer&\29\20const +2550:sktext::gpu::GlyphVector::Make\28sktext::SkStrikePromise&&\2c\20SkSpan\2c\20sktext::gpu::SubRunAllocator*\29 +2551:sktext::gpu::BagOfBytes::MinimumSizeWithOverhead\28int\2c\20int\2c\20int\2c\20int\29::'lambda'\28\29::operator\28\29\28\29\20const +2552:sktext::SkStrikePromise::flatten\28SkWriteBuffer&\29\20const +2553:sktext::GlyphRunBuilder::makeGlyphRunList\28sktext::GlyphRun\20const&\2c\20SkPaint\20const&\2c\20SkPoint\29 +2554:sktext::GlyphRun::GlyphRun\28SkFont\20const&\2c\20SkSpan\2c\20SkSpan\2c\20SkSpan\2c\20SkSpan\2c\20SkSpan\29 +2555:skpaint_to_grpaint_impl\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::optional>>\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +2556:skip_literal_string +2557:skif::\28anonymous\20namespace\29::are_axes_nearly_integer_aligned\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29 +2558:skif::FilterResult::applyColorFilter\28skif::Context\20const&\2c\20sk_sp\29\20const +2559:skif::FilterResult::FilterResult\28\29 +2560:skif::FilterResult::Builder::outputBounds\28std::__2::optional>\29\20const +2561:skif::FilterResult::Builder::drawShader\28sk_sp\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +2562:skif::FilterResult::Builder::createInputShaders\28skif::LayerSpace\20const&\2c\20bool\29 +2563:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +2564:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +2565:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::set\28skia_private::THashMap>\2c\20SkGoodHash>::Pair\29 +2566:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +2567:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +2568:skia_private::THashTable::Traits>::resize\28int\29 +2569:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::resize\28int\29 +2570:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::find\28GrProgramDesc\20const&\29\20const +2571:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +2572:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrTextureProxy*&&\29 +2573:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +2574:skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::set\28SkSL::Variable\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +2575:skia_private::THashMap::set\28SkSL::SymbolTable::SymbolKey\2c\20SkSL::Symbol*\29 +2576:skia_private::THashMap::set\28SkSL::FunctionDeclaration\20const*\2c\20SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::FunctionState\29 +2577:skia_private::TArray::resize_back\28int\29 +2578:skia_private::TArray\2c\20false>::move\28void*\29 +2579:skia_private::TArray::operator=\28skia_private::TArray&&\29 +2580:skia_private::TArray::push_back\28SkRasterPipeline_MemoryCtxInfo&&\29 +2581:skia_private::TArray::push_back_raw\28int\29 +2582:skia_private::TArray::resize_back\28int\29 +2583:skia_png_write_chunk +2584:skia_png_set_sBIT +2585:skia_png_set_read_fn +2586:skia_png_set_packing +2587:skia_png_save_uint_32 +2588:skia_png_reciprocal2 +2589:skia_png_realloc_array +2590:skia_png_read_start_row +2591:skia_png_read_IDAT_data +2592:skia_png_handle_zTXt +2593:skia_png_handle_tRNS +2594:skia_png_handle_tIME +2595:skia_png_handle_tEXt +2596:skia_png_handle_sRGB +2597:skia_png_handle_sPLT +2598:skia_png_handle_sCAL +2599:skia_png_handle_sBIT +2600:skia_png_handle_pHYs +2601:skia_png_handle_pCAL +2602:skia_png_handle_oFFs +2603:skia_png_handle_iTXt +2604:skia_png_handle_iCCP +2605:skia_png_handle_hIST +2606:skia_png_handle_gAMA +2607:skia_png_handle_cHRM +2608:skia_png_handle_bKGD +2609:skia_png_handle_as_unknown +2610:skia_png_handle_PLTE +2611:skia_png_do_strip_channel +2612:skia_png_destroy_write_struct +2613:skia_png_destroy_info_struct +2614:skia_png_compress_IDAT +2615:skia_png_combine_row +2616:skia_png_colorspace_set_sRGB +2617:skia_png_check_fp_string +2618:skia_png_check_fp_number +2619:skia::textlayout::TypefaceFontStyleSet::createTypeface\28int\29 +2620:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::$_0::operator\28\29\28sk_sp\2c\20sk_sp\29\20const +2621:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const +2622:skia::textlayout::TextLine::getGlyphPositionAtCoordinate\28float\29 +2623:skia::textlayout::Run::isResolved\28\29\20const +2624:skia::textlayout::Run::copyTo\28SkTextBlobBuilder&\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +2625:skia::textlayout::ParagraphImpl::buildClusterTable\28\29 +2626:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29 +2627:skia::textlayout::OneLineShaper::~OneLineShaper\28\29 +2628:skia::textlayout::FontCollection::setDefaultFontManager\28sk_sp\29 +2629:skia::textlayout::FontCollection::FontCollection\28\29 +2630:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::flush\28GrMeshDrawTarget*\2c\20skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::FlushInfo*\29\20const +2631:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::~Impl\28\29 +2632:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::programInfo\28\29 +2633:skgpu::ganesh::SurfaceFillContext::discard\28\29 +2634:skgpu::ganesh::SurfaceDrawContext::internalStencilClear\28SkIRect\20const*\2c\20bool\29 +2635:skgpu::ganesh::SurfaceDrawContext::drawPath\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrStyle\20const&\29 +2636:skgpu::ganesh::SurfaceDrawContext::attemptQuadOptimization\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20DrawQuad*\2c\20GrPaint*\29 +2637:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +2638:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29::$_0::operator\28\29\28GrSurfaceProxyView\2c\20SkIRect\29\20const +2639:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +2640:skgpu::ganesh::QuadPerEdgeAA::MinColorType\28SkRGBA4f<\28SkAlphaType\292>\29 +2641:skgpu::ganesh::PathRendererChain::PathRendererChain\28GrRecordingContext*\2c\20skgpu::ganesh::PathRendererChain::Options\20const&\29 +2642:skgpu::ganesh::PathCurveTessellator::draw\28GrOpFlushState*\29\20const +2643:skgpu::ganesh::OpsTask::recordOp\28std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const*\2c\20GrCaps\20const&\29 +2644:skgpu::ganesh::FilterAndMipmapHaveNoEffect\28GrQuad\20const&\2c\20GrQuad\20const&\29 +2645:skgpu::ganesh::FillRectOp::MakeNonAARect\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +2646:skgpu::ganesh::FillRRectOp::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +2647:skgpu::ganesh::Device::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +2648:skgpu::ganesh::Device::drawImageQuadDirect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +2649:skgpu::ganesh::Device::Make\28std::__2::unique_ptr>\2c\20SkAlphaType\2c\20skgpu::ganesh::Device::InitContents\29 +2650:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::setup_dashed_rect\28SkRect\20const&\2c\20skgpu::VertexWriter&\2c\20SkMatrix\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashCap\29 +2651:skgpu::ganesh::ClipStack::SaveRecord::invalidateMasks\28GrProxyProvider*\2c\20SkTBlockList*\29 +2652:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::SaveRecord\20const&\29\20const +2653:skgpu::ganesh::AtlasTextOp::operator\20new\28unsigned\20long\29 +2654:skgpu::ganesh::AtlasTextOp::Geometry::Make\28sktext::gpu::AtlasSubRun\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\2c\20sk_sp&&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkArenaAlloc*\29 +2655:skgpu::ganesh::AtlasRenderTask::addAtlasDrawOp\28std::__2::unique_ptr>\2c\20GrCaps\20const&\29 +2656:skcms_TransferFunction_isPQish +2657:skcms_MaxRoundtripError +2658:sk_free_releaseproc\28void\20const*\2c\20void*\29 +2659:siprintf +2660:sift +2661:select_curve_ops\28skcms_Curve\20const*\2c\20int\2c\20OpAndArg*\29 +2662:rotate\28SkDCubic\20const&\2c\20int\2c\20int\2c\20SkDCubic&\29 +2663:read_metadata\28std::__2::vector>\20const&\2c\20unsigned\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +2664:read_header\28SkStream*\2c\20SkISize*\29 +2665:quad_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +2666:psh_globals_set_scale +2667:ps_parser_skip_PS_token +2668:ps_builder_done +2669:png_text_compress +2670:png_inflate_read +2671:png_inflate_claim +2672:png_image_size +2673:png_default_warning +2674:png_colorspace_endpoints_match +2675:png_build_16bit_table +2676:normalize +2677:next_marker +2678:morphpoints\28SkPoint*\2c\20SkPoint\20const*\2c\20int\2c\20SkPathMeasure&\2c\20float\29 +2679:make_unpremul_effect\28std::__2::unique_ptr>\29 +2680:long\20std::__2::__libcpp_atomic_refcount_decrement\5babi:nn180100\5d\28long&\29 +2681:long\20const&\20std::__2::min\5babi:nn180100\5d\28long\20const&\2c\20long\20const&\29 +2682:log1p +2683:load_truetype_glyph +2684:line_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +2685:lang_find_or_insert\28char\20const*\29 +2686:jpeg_calc_output_dimensions +2687:jpeg_CreateDecompress +2688:inner_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +2689:inflate_table +2690:increment_simple_rowgroup_ctr +2691:hb_vector_t::push\28\29 +2692:hb_tag_from_string +2693:hb_shape_plan_destroy +2694:hb_script_get_horizontal_direction +2695:hb_paint_extents_context_t::push_clip\28hb_extents_t\29 +2696:hb_ot_color_palette_get_colors +2697:hb_lazy_loader_t\2c\20hb_face_t\2c\203u\2c\20OT::cmap_accelerator_t>::do_destroy\28OT::cmap_accelerator_t*\29 +2698:hb_lazy_loader_t\2c\20hb_face_t\2c\2039u\2c\20OT::SVG_accelerator_t>::do_destroy\28OT::SVG_accelerator_t*\29 +2699:hb_hashmap_t::alloc\28unsigned\20int\29 +2700:hb_font_funcs_destroy +2701:hb_face_get_upem +2702:hb_face_destroy +2703:hb_draw_cubic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +2704:hb_buffer_set_segment_properties +2705:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2706:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2707:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2708:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2709:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +2710:hb_blob_create +2711:haircubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +2712:gray_render_line +2713:get_vendor\28char\20const*\29 +2714:get_renderer\28char\20const*\2c\20GrGLExtensions\20const&\29 +2715:get_layer_mapping_and_bounds\28SkSpan>\2c\20SkMatrix\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\2c\20float\29 +2716:get_joining_type\28unsigned\20int\2c\20hb_unicode_general_category_t\29 +2717:generate_distance_field_from_image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\29 +2718:ft_var_readpackeddeltas +2719:ft_var_get_item_delta +2720:ft_var_done_item_variation_store +2721:ft_glyphslot_alloc_bitmap +2722:freelocale +2723:free_pool +2724:fquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2725:fp_barrierf +2726:fline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2727:fixN0c\28BracketData*\2c\20int\2c\20int\2c\20unsigned\20char\29 +2728:fiprintf +2729:fcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2730:fconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +2731:fclose +2732:exp2 +2733:emscripten::internal::MethodInvoker::invoke\28void\20\28SkFont::*\20const&\29\28float\29\2c\20SkFont*\2c\20float\29 +2734:emscripten::internal::Invoker>\2c\20SimpleParagraphStyle\2c\20sk_sp>::invoke\28std::__2::unique_ptr>\20\28*\29\28SimpleParagraphStyle\2c\20sk_sp\29\2c\20SimpleParagraphStyle*\2c\20sk_sp*\29 +2735:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28SkFontMgr&\2c\20int\29\2c\20SkFontMgr*\2c\20int\29 +2736:do_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +2737:do_putc +2738:deserialize_image\28sk_sp\2c\20SkDeserialProcs\2c\20std::__2::optional\29 +2739:decompose\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\2c\20unsigned\20int\29 +2740:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0>\28skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0&&\29::'lambda'\28char*\29::__invoke\28char*\29 +2741:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool&\2c\20GrPipeline*&\2c\20GrUserStencilSettings\20const*&&\2c\20\28anonymous\20namespace\29::DrawAtlasPathShader*&\2c\20GrPrimitiveType&&\2c\20GrXferBarrierFlags&\2c\20GrLoadOp&\29::'lambda'\28void*\29>\28GrProgramInfo&&\29::'lambda'\28char*\29::__invoke\28char*\29 +2742:cubic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +2743:conic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +2744:compute_ULong_sum +2745:char\20const*\20std::__2::find\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const&\29 +2746:cff_index_get_pointers +2747:cff2_path_param_t::move_to\28CFF::point_t\20const&\29 +2748:cff1_path_param_t::move_to\28CFF::point_t\20const&\29 +2749:cf2_glyphpath_computeOffset +2750:build_tree +2751:bool\20std::__2::__is_pointer_in_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const*\29 +2752:bool\20OT::glyf_impl::Glyph::get_points\28hb_font_t*\2c\20OT::glyf_accelerator_t\20const&\2c\20contour_point_vector_t&\2c\20contour_point_vector_t*\2c\20head_maxp_info_t*\2c\20unsigned\20int*\2c\20bool\2c\20bool\2c\20bool\2c\20hb_array_t\2c\20hb_map_t*\2c\20unsigned\20int\2c\20unsigned\20int*\29\20const +2753:bool\20OT::glyf_accelerator_t::get_points\28hb_font_t*\2c\20unsigned\20int\2c\20OT::glyf_accelerator_t::points_aggregator_t\29\20const +2754:bool\20OT::GSUBGPOSVersion1_2::sanitize\28hb_sanitize_context_t*\29\20const +2755:bool\20OT::GSUBGPOSVersion1_2::sanitize\28hb_sanitize_context_t*\29\20const +2756:blit_aaa_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +2757:atan +2758:alloc_large +2759:af_glyph_hints_done +2760:add_quad\28SkPoint\20const*\2c\20skia_private::TArray*\29 +2761:acos +2762:aaa_fill_path\28SkPath\20const&\2c\20SkIRect\20const&\2c\20AdditiveBlitter*\2c\20int\2c\20int\2c\20bool\2c\20bool\2c\20bool\29 +2763:_get_path\28OT::cff1::accelerator_t\20const*\2c\20hb_font_t*\2c\20unsigned\20int\2c\20hb_draw_session_t&\2c\20bool\2c\20CFF::point_t*\29 +2764:_get_bounds\28OT::cff1::accelerator_t\20const*\2c\20unsigned\20int\2c\20bounds_t&\2c\20bool\29 +2765:_embind_register_bindings +2766:__trunctfdf2 +2767:__towrite +2768:__toread +2769:__subtf3 +2770:__strchrnul +2771:__rem_pio2f +2772:__rem_pio2 +2773:__math_uflowf +2774:__math_oflowf +2775:__fwritex +2776:__cxxabiv1::__class_type_info::process_static_type_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\29\20const +2777:__cxxabiv1::__class_type_info::process_static_type_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\29\20const +2778:__cxxabiv1::__class_type_info::process_found_base_class\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +2779:__cxxabiv1::__base_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +2780:\28anonymous\20namespace\29::shape_contains_rect\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const&\2c\20bool\29 +2781:\28anonymous\20namespace\29::generateFacePathCOLRv1\28FT_FaceRec_*\2c\20unsigned\20short\2c\20SkPath*\29 +2782:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads_with_constraint\28SkPoint\20const*\2c\20float\2c\20SkPathFirstDirection\2c\20skia_private::TArray*\2c\20int\29 +2783:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\2c\20int\2c\20bool\2c\20bool\29 +2784:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const +2785:\28anonymous\20namespace\29::bloat_quad\28SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkMatrix\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +2786:\28anonymous\20namespace\29::SkEmptyTypeface::onMakeClone\28SkFontArguments\20const&\29\20const +2787:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29_5810 +2788:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29 +2789:\28anonymous\20namespace\29::SkBlurImageFilter::mapSigma\28skif::Mapping\20const&\2c\20bool\29\20const +2790:\28anonymous\20namespace\29::DrawAtlasOpImpl::visitProxies\28std::__2::function\20const&\29\20const +2791:\28anonymous\20namespace\29::DrawAtlasOpImpl::programInfo\28\29 +2792:\28anonymous\20namespace\29::DrawAtlasOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +2793:\28anonymous\20namespace\29::DirectMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +2794:\28anonymous\20namespace\29::DirectMaskSubRun::glyphs\28\29\20const +2795:WebPRescaleNeededLines +2796:WebPInitDecBufferInternal +2797:WebPInitCustomIo +2798:WebPGetFeaturesInternal +2799:WebPDemuxGetFrame +2800:VP8LInitBitReader +2801:VP8LColorIndexInverseTransformAlpha +2802:VP8InitIoInternal +2803:VP8InitBitReader +2804:TT_Vary_Apply_Glyph_Deltas +2805:TT_Set_Var_Design +2806:SkWuffsCodec::decodeFrame\28\29 +2807:SkVertices::MakeCopy\28SkVertices::VertexMode\2c\20int\2c\20SkPoint\20const*\2c\20SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20short\20const*\29 +2808:SkVertices::Builder::texCoords\28\29 +2809:SkVertices::Builder::positions\28\29 +2810:SkVertices::Builder::init\28SkVertices::Desc\20const&\29 +2811:SkVertices::Builder::colors\28\29 +2812:SkVertices::Builder::Builder\28SkVertices::VertexMode\2c\20int\2c\20int\2c\20unsigned\20int\29 +2813:SkTypeface_FreeType::MakeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29 +2814:SkTypeface::getTableSize\28unsigned\20int\29\20const +2815:SkTiff::ImageFileDirectory::getEntryTag\28unsigned\20short\29\20const +2816:SkTiff::ImageFileDirectory::MakeFromOffset\28sk_sp\2c\20bool\2c\20unsigned\20int\2c\20bool\29 +2817:SkTextBlobRunIterator::positioning\28\29\20const +2818:SkTSpan::splitAt\28SkTSpan*\2c\20double\2c\20SkArenaAlloc*\29 +2819:SkTSect::computePerpendiculars\28SkTSect*\2c\20SkTSpan*\2c\20SkTSpan*\29 +2820:SkTDStorage::insert\28int\29 +2821:SkTDStorage::calculateSizeOrDie\28int\29::$_0::operator\28\29\28\29\20const +2822:SkTDPQueue::percolateDownIfNecessary\28int\29 +2823:SkTConic::hullIntersects\28SkDConic\20const&\2c\20bool*\29\20const +2824:SkSurface_Base::SkSurface_Base\28int\2c\20int\2c\20SkSurfaceProps\20const*\29 +2825:SkStrokerPriv::CapFactory\28SkPaint::Cap\29 +2826:SkStrokeRec::getInflationRadius\28\29\20const +2827:SkString::equals\28char\20const*\29\20const +2828:SkStrikeSpec::MakeTransformMask\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +2829:SkStrikeSpec::MakePath\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\29 +2830:SkShapers::HB::ShapeDontWrapOrReorder\28sk_sp\2c\20sk_sp\29 +2831:SkShaper::TrivialRunIterator::endOfCurrentRun\28\29\20const +2832:SkShaper::TrivialRunIterator::atEnd\28\29\20const +2833:SkShaper::MakeFontMgrRunIterator\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20sk_sp\29 +2834:SkShadowTessellator::MakeAmbient\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20bool\29 +2835:SkScan::HairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +2836:SkScan::FillTriangle\28SkPoint\20const*\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +2837:SkScan::FillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +2838:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +2839:SkScan::AntiHairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +2840:SkScan::AntiHairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +2841:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\2c\20bool\29 +2842:SkScalerContextRec::CachedMaskGamma\28unsigned\20char\2c\20unsigned\20char\29 +2843:SkScalerContextFTUtils::drawSVGGlyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +2844:SkScalarInterpFunc\28float\2c\20float\20const*\2c\20float\20const*\2c\20int\29 +2845:SkSLTypeString\28SkSLType\29 +2846:SkSL::simplify_negation\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\29 +2847:SkSL::simplify_matrix_multiplication\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +2848:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +2849:SkSL::build_argument_type_list\28SkSpan>\20const>\29 +2850:SkSL::\28anonymous\20namespace\29::SwitchCaseContainsExit::visitStatement\28SkSL::Statement\20const&\29 +2851:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::returnsInputAlpha\28SkSL::Expression\20const&\29 +2852:SkSL::\28anonymous\20namespace\29::ConstantExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +2853:SkSL::Variable::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\29 +2854:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29\20const +2855:SkSL::Type::MakeSamplerType\28char\20const*\2c\20SkSL::Type\20const&\29 +2856:SkSL::SymbolTable::moveSymbolTo\28SkSL::SymbolTable*\2c\20SkSL::Symbol*\2c\20SkSL::Context\20const&\29 +2857:SkSL::SymbolTable::isType\28std::__2::basic_string_view>\29\20const +2858:SkSL::Symbol::instantiate\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +2859:SkSL::StructType::slotCount\28\29\20const +2860:SkSL::ReturnStatement::~ReturnStatement\28\29_6428 +2861:SkSL::ReturnStatement::~ReturnStatement\28\29 +2862:SkSL::RP::UnownedLValueSlice::~UnownedLValueSlice\28\29 +2863:SkSL::RP::Generator::pushTernaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +2864:SkSL::RP::Generator::pushStructuredComparison\28SkSL::RP::LValue*\2c\20SkSL::Operator\2c\20SkSL::RP::LValue*\2c\20SkSL::Type\20const&\29 +2865:SkSL::RP::Generator::pushMatrixMultiply\28SkSL::RP::LValue*\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +2866:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29 +2867:SkSL::RP::Builder::push_uniform\28SkSL::RP::SlotRange\29 +2868:SkSL::RP::Builder::merge_condition_mask\28\29 +2869:SkSL::RP::Builder::jump\28int\29 +2870:SkSL::RP::Builder::branch_if_no_active_lanes_on_stack_top_equal\28int\2c\20int\29 +2871:SkSL::ProgramUsage::~ProgramUsage\28\29 +2872:SkSL::ProgramUsage::add\28SkSL::ProgramElement\20const&\29 +2873:SkSL::Pool::detachFromThread\28\29 +2874:SkSL::PipelineStage::ConvertProgram\28SkSL::Program\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20SkSL::PipelineStage::Callbacks*\29 +2875:SkSL::Parser::unaryExpression\28\29 +2876:SkSL::Parser::swizzle\28SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::basic_string_view>\2c\20SkSL::Position\29 +2877:SkSL::Parser::block\28bool\2c\20std::__2::unique_ptr>*\29 +2878:SkSL::Operator::getBinaryPrecedence\28\29\20const +2879:SkSL::ModuleLoader::loadVertexModule\28SkSL::Compiler*\29 +2880:SkSL::ModuleLoader::loadGPUModule\28SkSL::Compiler*\29 +2881:SkSL::ModuleLoader::loadFragmentModule\28SkSL::Compiler*\29 +2882:SkSL::ModifierFlags::checkPermittedFlags\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\29\20const +2883:SkSL::Mangler::uniqueName\28std::__2::basic_string_view>\2c\20SkSL::SymbolTable*\29 +2884:SkSL::LiteralType::slotType\28unsigned\20long\29\20const +2885:SkSL::Layout::operator==\28SkSL::Layout\20const&\29\20const +2886:SkSL::Layout::checkPermittedLayout\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkEnumBitMask\29\20const +2887:SkSL::Inliner::analyze\28std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\29 +2888:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29 +2889:SkSL::GLSLCodeGenerator::writeLiteral\28SkSL::Literal\20const&\29 +2890:SkSL::GLSLCodeGenerator::writeFunctionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +2891:SkSL::ForStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +2892:SkSL::FieldAccess::description\28SkSL::OperatorPrecedence\29\20const +2893:SkSL::Expression::isIncomplete\28SkSL::Context\20const&\29\20const +2894:SkSL::Expression::compareConstant\28SkSL::Expression\20const&\29\20const +2895:SkSL::DebugTracePriv::~DebugTracePriv\28\29 +2896:SkSL::Context::Context\28SkSL::BuiltinTypes\20const&\2c\20SkSL::ErrorReporter&\29 +2897:SkSL::ConstructorArrayCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +2898:SkSL::ConstructorArray::~ConstructorArray\28\29 +2899:SkSL::ConstructorArray::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +2900:SkSL::Analysis::GetReturnComplexity\28SkSL::FunctionDefinition\20const&\29 +2901:SkSL::Analysis::CallsColorTransformIntrinsics\28SkSL::Program\20const&\29 +2902:SkSL::AliasType::bitWidth\28\29\20const +2903:SkRuntimeEffectPriv::VarAsUniform\28SkSL::Variable\20const&\2c\20SkSL::Context\20const&\2c\20unsigned\20long*\29 +2904:SkRuntimeEffectPriv::UniformsAsSpan\28SkSpan\2c\20sk_sp\2c\20bool\2c\20SkColorSpace\20const*\2c\20SkArenaAlloc*\29 +2905:SkRuntimeEffect::source\28\29\20const +2906:SkRuntimeEffect::makeShader\28sk_sp\2c\20SkSpan\2c\20SkMatrix\20const*\29\20const +2907:SkRuntimeEffect::MakeForBlender\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +2908:SkResourceCache::checkMessages\28\29 +2909:SkResourceCache::NewCachedData\28unsigned\20long\29 +2910:SkRegion::translate\28int\2c\20int\2c\20SkRegion*\29\20const +2911:SkReduceOrder::Cubic\28SkPoint\20const*\2c\20SkPoint*\29 +2912:SkRectPriv::QuadContainsRectMask\28SkM44\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20float\29 +2913:SkRecords::PreCachedPath::PreCachedPath\28SkPath\20const&\29 +2914:SkRecords::FillBounds::pushSaveBlock\28SkPaint\20const*\2c\20bool\29 +2915:SkRecordDraw\28SkRecord\20const&\2c\20SkCanvas*\2c\20SkPicture\20const*\20const*\2c\20SkDrawable*\20const*\2c\20int\2c\20SkBBoxHierarchy\20const*\2c\20SkPicture::AbortCallback*\29 +2916:SkReadBuffer::readPoint\28SkPoint*\29 +2917:SkReadBuffer::readPath\28SkPath*\29 +2918:SkReadBuffer::readByteArrayAsData\28\29 +2919:SkRasterPipeline_<256ul>::SkRasterPipeline_\28\29 +2920:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29 +2921:SkRasterPipelineBlitter::blitRectWithTrace\28int\2c\20int\2c\20int\2c\20int\2c\20bool\29 +2922:SkRasterPipelineBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +2923:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29 +2924:SkRasterPipeline::appendLoad\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +2925:SkRasterClip::op\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkClipOp\2c\20bool\29 +2926:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29 +2927:SkRRect::scaleRadii\28\29 +2928:SkRRect::AreRectAndRadiiValid\28SkRect\20const&\2c\20SkPoint\20const*\29 +2929:SkRBuffer::skip\28unsigned\20long\29 +2930:SkPngEncoderImpl::~SkPngEncoderImpl\28\29 +2931:SkPngEncoder::Make\28SkWStream*\2c\20SkPixmap\20const&\2c\20SkPngEncoder::Options\20const&\29 +2932:SkPngDecoder::IsPng\28void\20const*\2c\20unsigned\20long\29 +2933:SkPixmap::setColorSpace\28sk_sp\29 +2934:SkPixelRef::~SkPixelRef\28\29 +2935:SkPixelRef::notifyPixelsChanged\28\29 +2936:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20sk_sp\29 +2937:SkPictureRecord::addPathToHeap\28SkPath\20const&\29 +2938:SkPictureData::getPath\28SkReadBuffer*\29\20const +2939:SkPicture::serialize\28SkWStream*\2c\20SkSerialProcs\20const*\2c\20SkRefCntSet*\2c\20bool\29\20const +2940:SkPathWriter::update\28SkOpPtT\20const*\29 +2941:SkPathStroker::strokeCloseEnough\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20SkQuadConstruct*\29\20const +2942:SkPathStroker::finishContour\28bool\2c\20bool\29 +2943:SkPathRef::reset\28\29 +2944:SkPathRef::isRRect\28SkRRect*\2c\20bool*\2c\20unsigned\20int*\29\20const +2945:SkPathRef::addGenIDChangeListener\28sk_sp\29 +2946:SkPathPriv::IsRectContour\28SkPath\20const&\2c\20bool\2c\20int*\2c\20SkPoint\20const**\2c\20bool*\2c\20SkPathDirection*\2c\20SkRect*\29 +2947:SkPathEffectBase::onAsPoints\28SkPathEffectBase::PointData*\2c\20SkPath\20const&\2c\20SkStrokeRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\29\20const +2948:SkPathEffect::filterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\29\20const +2949:SkPathBuilder::quadTo\28SkPoint\2c\20SkPoint\29 +2950:SkPathBuilder::cubicTo\28SkPoint\2c\20SkPoint\2c\20SkPoint\29 +2951:SkPath::writeToMemory\28void*\29\20const +2952:SkPath::reversePathTo\28SkPath\20const&\29 +2953:SkPath::rQuadTo\28float\2c\20float\2c\20float\2c\20float\29 +2954:SkPath::contains\28float\2c\20float\29\20const +2955:SkPath::arcTo\28float\2c\20float\2c\20float\2c\20SkPath::ArcSize\2c\20SkPathDirection\2c\20float\2c\20float\29 +2956:SkPath::approximateBytesUsed\28\29\20const +2957:SkPath::addCircle\28float\2c\20float\2c\20float\2c\20SkPathDirection\29 +2958:SkPath::Rect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2959:SkParse::FindScalar\28char\20const*\2c\20float*\29 +2960:SkPairPathEffect::flatten\28SkWriteBuffer&\29\20const +2961:SkPaintToGrPaintWithBlend\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +2962:SkPaint::refImageFilter\28\29\20const +2963:SkPaint::refBlender\28\29\20const +2964:SkPaint::getBlendMode_or\28SkBlendMode\29\20const +2965:SkPackARGB_as_RGBA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +2966:SkPackARGB_as_BGRA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +2967:SkOpSpan::setOppSum\28int\29 +2968:SkOpSegment::markAndChaseWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int\2c\20SkOpSpanBase**\29 +2969:SkOpSegment::markAllDone\28\29 +2970:SkOpSegment::activeWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +2971:SkOpPtT::contains\28SkOpSegment\20const*\29\20const +2972:SkOpEdgeBuilder::closeContour\28SkPoint\20const&\2c\20SkPoint\20const&\29 +2973:SkOpCoincidence::releaseDeleted\28\29 +2974:SkOpCoincidence::markCollapsed\28SkOpPtT*\29 +2975:SkOpCoincidence::findOverlaps\28SkOpCoincidence*\29\20const +2976:SkOpCoincidence::expand\28\29 +2977:SkOpCoincidence::apply\28\29 +2978:SkOpAngle::orderable\28SkOpAngle*\29 +2979:SkOpAngle::computeSector\28\29 +2980:SkNullBlitter::~SkNullBlitter\28\29 +2981:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\2c\20sk_sp\29 +2982:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\29 +2983:SkMessageBus::BufferFinishedMessage\2c\20GrDirectContext::DirectContextID\2c\20false>::Get\28\29 +2984:SkMemoryStream::SkMemoryStream\28sk_sp\29 +2985:SkMatrix::setRotate\28float\29 +2986:SkMatrix::setPolyToPoly\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20int\29 +2987:SkMatrix::postSkew\28float\2c\20float\29 +2988:SkMatrix::invert\28SkMatrix*\29\20const +2989:SkMatrix::getMinScale\28\29\20const +2990:SkMatrix::getMinMaxScales\28float*\29\20const +2991:SkMaskBuilder::PrepareDestination\28int\2c\20int\2c\20SkMask\20const&\29 +2992:SkMakeBitmapShaderForPaint\28SkPaint\20const&\2c\20SkBitmap\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20SkCopyPixelsMode\29 +2993:SkLineClipper::ClipLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\2c\20bool\29 +2994:SkLRUCache::~SkLRUCache\28\29 +2995:SkJSONWriter::separator\28bool\29 +2996:SkIntersections::intersectRay\28SkDQuad\20const&\2c\20SkDLine\20const&\29 +2997:SkIntersections::intersectRay\28SkDLine\20const&\2c\20SkDLine\20const&\29 +2998:SkIntersections::intersectRay\28SkDCubic\20const&\2c\20SkDLine\20const&\29 +2999:SkIntersections::intersectRay\28SkDConic\20const&\2c\20SkDLine\20const&\29 +3000:SkIntersections::cleanUpParallelLines\28bool\29 +3001:SkImage_Raster::SkImage_Raster\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20int\29 +3002:SkImage_Ganesh::~SkImage_Ganesh\28\29 +3003:SkImageShader::Make\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +3004:SkImageInfo::Make\28SkISize\2c\20SkColorType\2c\20SkAlphaType\29 +3005:SkImageInfo::MakeN32Premul\28SkISize\29 +3006:SkImageGenerator::getPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\29 +3007:SkImageGenerator::SkImageGenerator\28SkImageInfo\20const&\2c\20unsigned\20int\29 +3008:SkImageFilters::Blur\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +3009:SkImageFilter_Base::getInputBounds\28skif::Mapping\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\29\20const +3010:SkImageFilter_Base::filterImage\28skif::Context\20const&\29\20const +3011:SkImageFilter_Base::affectsTransparentBlack\28\29\20const +3012:SkImage::width\28\29\20const +3013:SkImage::hasMipmaps\28\29\20const +3014:SkIDChangeListener::List::add\28sk_sp\29 +3015:SkGradientShader::MakeTwoPointConical\28SkPoint\20const&\2c\20float\2c\20SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3016:SkGradientShader::MakeLinear\28SkPoint\20const*\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3017:SkGradientBaseShader::AppendInterpolatedToDstStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20bool\2c\20SkGradientShader::Interpolation\20const&\2c\20SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +3018:SkGlyph::setPath\28SkArenaAlloc*\2c\20SkScalerContext*\29 +3019:SkGlyph::mask\28\29\20const +3020:SkFontPriv::ApproximateTransformedTextSize\28SkFont\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\20const&\29 +3021:SkFontMgr::matchFamily\28char\20const*\29\20const +3022:SkFindCubicMaxCurvature\28SkPoint\20const*\2c\20float*\29 +3023:SkExif::parse_ifd\28SkExif::Metadata&\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20bool\2c\20bool\29 +3024:SkEncoder::encodeRows\28int\29 +3025:SkEncodedInfo::ICCProfile::Make\28sk_sp\29 +3026:SkEmptyFontMgr::onMatchFamilyStyleCharacter\28char\20const*\2c\20SkFontStyle\20const&\2c\20char\20const**\2c\20int\2c\20int\29\20const +3027:SkEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkIRect\20const*\2c\20int\29 +3028:SkDynamicMemoryWStream::padToAlign4\28\29 +3029:SkDrawable::SkDrawable\28\29 +3030:SkDrawBase::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29\20const +3031:SkDrawBase::drawDevicePoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\2c\20SkDevice*\29\20const +3032:SkDraw::drawBitmap\28SkBitmap\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29\20const +3033:SkDevice::simplifyGlyphRunRSXFormAndRedraw\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +3034:SkDevice::setDeviceCoordinateSystem\28SkM44\20const&\2c\20SkM44\20const&\2c\20SkM44\20const&\2c\20int\2c\20int\29 +3035:SkDevice::SkDevice\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +3036:SkDataTable::at\28int\2c\20unsigned\20long*\29\20const +3037:SkData::MakeFromStream\28SkStream*\2c\20unsigned\20long\29 +3038:SkDQuad::dxdyAtT\28double\29\20const +3039:SkDQuad::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +3040:SkDQuad::FindExtrema\28double\20const*\2c\20double*\29 +3041:SkDCubic::subDivide\28double\2c\20double\29\20const +3042:SkDCubic::searchRoots\28double*\2c\20int\2c\20double\2c\20SkDCubic::SearchAxis\2c\20double*\29\20const +3043:SkDCubic::Coefficients\28double\20const*\2c\20double*\2c\20double*\2c\20double*\2c\20double*\29 +3044:SkDConic::dxdyAtT\28double\29\20const +3045:SkDConic::FindExtrema\28double\20const*\2c\20float\2c\20double*\29 +3046:SkCopyStreamToData\28SkStream*\29 +3047:SkContourMeasure_segTo\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20float\2c\20SkPath*\29 +3048:SkContourMeasureIter::next\28\29 +3049:SkContourMeasureIter::Impl::compute_quad_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3050:SkContourMeasureIter::Impl::compute_cubic_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3051:SkContourMeasureIter::Impl::compute_conic_segs\28SkConic\20const&\2c\20float\2c\20int\2c\20SkPoint\20const&\2c\20int\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20int\29 +3052:SkContourMeasure::getPosTan\28float\2c\20SkPoint*\2c\20SkPoint*\29\20const +3053:SkConic::evalAt\28float\29\20const +3054:SkConic::TransformW\28SkPoint\20const*\2c\20float\2c\20SkMatrix\20const&\29 +3055:SkColorSpace::transferFn\28skcms_TransferFunction*\29\20const +3056:SkColorSpace::toXYZD50\28skcms_Matrix3x3*\29\20const +3057:SkColorSpace::serialize\28\29\20const +3058:SkColorPalette::SkColorPalette\28unsigned\20int\20const*\2c\20int\29 +3059:SkColor4fPrepForDst\28SkRGBA4f<\28SkAlphaType\293>\2c\20GrColorInfo\20const&\29 +3060:SkCodec::startIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const*\29 +3061:SkChopMonoCubicAtY\28SkPoint\20const*\2c\20float\2c\20SkPoint*\29 +3062:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\2c\20float\29 +3063:SkCanvas::setMatrix\28SkM44\20const&\29 +3064:SkCanvas::scale\28float\2c\20float\29 +3065:SkCanvas::private_draw_shadow_rec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +3066:SkCanvas::peekPixels\28SkPixmap*\29 +3067:SkCanvas::onResetClip\28\29 +3068:SkCanvas::onClipShader\28sk_sp\2c\20SkClipOp\29 +3069:SkCanvas::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +3070:SkCanvas::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3071:SkCanvas::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3072:SkCanvas::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3073:SkCanvas::internal_private_resetClip\28\29 +3074:SkCanvas::internalSaveLayer\28SkCanvas::SaveLayerRec\20const&\2c\20SkCanvas::SaveLayerStrategy\2c\20bool\29 +3075:SkCanvas::internalDrawDeviceWithFilter\28SkDevice*\2c\20SkDevice*\2c\20SkSpan>\2c\20SkPaint\20const&\2c\20SkCanvas::DeviceCompatibleWithFilter\2c\20SkColorInfo\20const&\2c\20float\2c\20SkTileMode\2c\20bool\29 +3076:SkCanvas::experimental_DrawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +3077:SkCanvas::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +3078:SkCanvas::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +3079:SkCanvas::drawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +3080:SkCanvas::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +3081:SkCanvas::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +3082:SkCanvas::drawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +3083:SkCanvas::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +3084:SkCanvas::attemptBlurredRRectDraw\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20SkEnumBitMask\29 +3085:SkCanvas::SkCanvas\28SkIRect\20const&\29 +3086:SkCachedData::~SkCachedData\28\29 +3087:SkCTMShader::~SkCTMShader\28\29_4797 +3088:SkBmpRLECodec::setPixel\28void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20char\29 +3089:SkBmpCodec::prepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +3090:SkBlockMemoryStream::getPosition\28\29\20const +3091:SkBlitterClipper::apply\28SkBlitter*\2c\20SkRegion\20const*\2c\20SkIRect\20const*\29 +3092:SkBlitter::blitRegion\28SkRegion\20const&\29 +3093:SkBitmapDevice::Create\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\2c\20SkRasterHandleAllocator*\29 +3094:SkBitmapDevice::BDDraw::~BDDraw\28\29 +3095:SkBitmapCacheDesc::Make\28SkImage\20const*\29 +3096:SkBitmap::writePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +3097:SkBitmap::setPixels\28void*\29 +3098:SkBitmap::pixelRefOrigin\28\29\20const +3099:SkBitmap::notifyPixelsChanged\28\29\20const +3100:SkBitmap::isImmutable\28\29\20const +3101:SkBitmap::allocPixels\28\29 +3102:SkBinaryWriteBuffer::writeScalarArray\28float\20const*\2c\20unsigned\20int\29 +3103:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29_5550 +3104:SkBaseShadowTessellator::handleCubic\28SkMatrix\20const&\2c\20SkPoint*\29 +3105:SkBaseShadowTessellator::handleConic\28SkMatrix\20const&\2c\20SkPoint*\2c\20float\29 +3106:SkAutoPathBoundsUpdate::SkAutoPathBoundsUpdate\28SkPath*\2c\20SkRect\20const&\29 +3107:SkAutoDescriptor::SkAutoDescriptor\28SkAutoDescriptor&&\29 +3108:SkArenaAllocWithReset::SkArenaAllocWithReset\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +3109:SkAnimatedImage::decodeNextFrame\28\29 +3110:SkAnimatedImage::Frame::copyTo\28SkAnimatedImage::Frame*\29\20const +3111:SkAnalyticQuadraticEdge::updateQuadratic\28\29 +3112:SkAnalyticCubicEdge::updateCubic\28bool\29 +3113:SkAlphaRuns::reset\28int\29 +3114:SkAAClip::setRect\28SkIRect\20const&\29 +3115:Simplify\28SkPath\20const&\2c\20SkPath*\29 +3116:ReconstructRow +3117:R_15649 +3118:OpAsWinding::nextEdge\28Contour&\2c\20OpAsWinding::Edge\29 +3119:OT::sbix::sanitize\28hb_sanitize_context_t*\29\20const +3120:OT::post::accelerator_t::cmp_gids\28void\20const*\2c\20void\20const*\2c\20void*\29 +3121:OT::gvar::sanitize_shallow\28hb_sanitize_context_t*\29\20const +3122:OT::fvar::sanitize\28hb_sanitize_context_t*\29\20const +3123:OT::cmap_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3124:OT::cmap::sanitize\28hb_sanitize_context_t*\29\20const +3125:OT::avar::sanitize\28hb_sanitize_context_t*\29\20const +3126:OT::VarRegionList::evaluate\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +3127:OT::VVAR::sanitize\28hb_sanitize_context_t*\29\20const +3128:OT::Rule::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +3129:OT::OpenTypeFontFile::sanitize\28hb_sanitize_context_t*\29\20const +3130:OT::MVAR::sanitize\28hb_sanitize_context_t*\29\20const +3131:OT::Layout::GSUB_impl::SubstLookup::serialize_ligature\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20hb_sorted_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\29 +3132:OT::Layout::GSUB::get_lookup\28unsigned\20int\29\20const +3133:OT::Layout::GPOS_impl::MarkArray::apply\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20OT::Layout::GPOS_impl::AnchorMatrix\20const&\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +3134:OT::GDEFVersion1_2::sanitize\28hb_sanitize_context_t*\29\20const +3135:OT::Device::get_y_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3136:OT::Device::get_x_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3137:OT::ClipList::get_extents\28unsigned\20int\2c\20hb_glyph_extents_t*\2c\20OT::VarStoreInstancer\20const&\29\20const +3138:OT::ChainRule::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +3139:OT::CPAL::sanitize\28hb_sanitize_context_t*\29\20const +3140:OT::COLR::sanitize\28hb_sanitize_context_t*\29\20const +3141:OT::COLR::paint_glyph\28hb_font_t*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29\20const +3142:MakeRasterCopyPriv\28SkPixmap\20const&\2c\20unsigned\20int\29 +3143:LineQuadraticIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineQuadraticIntersections::PinTPoint\29 +3144:LineQuadraticIntersections::checkCoincident\28\29 +3145:LineQuadraticIntersections::addLineNearEndPoints\28\29 +3146:LineCubicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineCubicIntersections::PinTPoint\29 +3147:LineCubicIntersections::checkCoincident\28\29 +3148:LineCubicIntersections::addLineNearEndPoints\28\29 +3149:LineConicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineConicIntersections::PinTPoint\29 +3150:LineConicIntersections::checkCoincident\28\29 +3151:LineConicIntersections::addLineNearEndPoints\28\29 +3152:Ins_UNKNOWN +3153:GrXferProcessor::GrXferProcessor\28GrProcessor::ClassID\29 +3154:GrVertexChunkBuilder::~GrVertexChunkBuilder\28\29 +3155:GrTriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +3156:GrTriangulator::splitEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +3157:GrTriangulator::pathToPolys\28float\2c\20SkRect\20const&\2c\20bool*\29 +3158:GrTriangulator::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20GrTriangulator::VertexList*\2c\20int\29\20const +3159:GrTriangulator::emitTriangle\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20skgpu::VertexWriter\29\20const +3160:GrTriangulator::checkForIntersection\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +3161:GrTriangulator::applyFillType\28int\29\20const +3162:GrTriangulator::EdgeList::insert\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +3163:GrTriangulator::Edge::intersect\28GrTriangulator::Edge\20const&\2c\20SkPoint*\2c\20unsigned\20char*\29\20const +3164:GrTriangulator::Edge::insertBelow\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +3165:GrTriangulator::Edge::insertAbove\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +3166:GrToGLStencilFunc\28GrStencilTest\29 +3167:GrThreadSafeCache::~GrThreadSafeCache\28\29 +3168:GrThreadSafeCache::dropAllRefs\28\29 +3169:GrTextureRenderTargetProxy::callbackDesc\28\29\20const +3170:GrTextureProxy::clearUniqueKey\28\29 +3171:GrTexture::GrTexture\28GrGpu*\2c\20SkISize\20const&\2c\20skgpu::Protected\2c\20GrTextureType\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +3172:GrTexture::ComputeScratchKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20skgpu::ScratchKey*\29 +3173:GrSurfaceProxyView::asTextureProxyRef\28\29\20const +3174:GrSurfaceProxy::GrSurfaceProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +3175:GrSurfaceProxy::GrSurfaceProxy\28sk_sp\2c\20SkBackingFit\2c\20GrSurfaceProxy::UseAllocator\29 +3176:GrSurface::setRelease\28sk_sp\29 +3177:GrStyledShape::styledBounds\28\29\20const +3178:GrStyledShape::asLine\28SkPoint*\2c\20bool*\29\20const +3179:GrStyledShape::addGenIDChangeListener\28sk_sp\29\20const +3180:GrSimpleMeshDrawOpHelper::fixedFunctionFlags\28\29\20const +3181:GrShape::setRRect\28SkRRect\20const&\29 +3182:GrShape::segmentMask\28\29\20const +3183:GrResourceProvider::assignUniqueKeyToResource\28skgpu::UniqueKey\20const&\2c\20GrGpuResource*\29 +3184:GrResourceCache::releaseAll\28\29 +3185:GrResourceCache::refAndMakeResourceMRU\28GrGpuResource*\29 +3186:GrResourceCache::getNextTimestamp\28\29 +3187:GrRenderTask::addDependency\28GrRenderTask*\29 +3188:GrRenderTargetProxy::canUseStencil\28GrCaps\20const&\29\20const +3189:GrRecordingContextPriv::addOnFlushCallbackObject\28GrOnFlushCallbackObject*\29 +3190:GrRecordingContext::~GrRecordingContext\28\29 +3191:GrRecordingContext::abandonContext\28\29 +3192:GrQuadUtils::TessellationHelper::Vertices::moveTo\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +3193:GrQuadUtils::TessellationHelper::EdgeEquations::reset\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\29 +3194:GrQuadUtils::ResolveAAType\28GrAAType\2c\20GrQuadAAFlags\2c\20GrQuad\20const&\2c\20GrAAType*\2c\20GrQuadAAFlags*\29 +3195:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::append\28GrQuad\20const&\2c\20\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA&&\2c\20GrQuad\20const*\29 +3196:GrPixmap::GrPixmap\28GrImageInfo\2c\20void*\2c\20unsigned\20long\29 +3197:GrPipeline::GrPipeline\28GrPipeline::InitArgs\20const&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29 +3198:GrPersistentCacheUtils::UnpackCachedShaders\28SkReadBuffer*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20int\2c\20GrPersistentCacheUtils::ShaderMetadata*\29 +3199:GrPathUtils::convertCubicToQuads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\29 +3200:GrPathTessellationShader::Make\28GrShaderCaps\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::tess::PatchAttribs\29 +3201:GrOp::chainConcat\28std::__2::unique_ptr>\29 +3202:GrMeshDrawOp::PatternHelper::PatternHelper\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +3203:GrMemoryPool::Make\28unsigned\20long\2c\20unsigned\20long\29 +3204:GrMakeKeyFromImageID\28skgpu::UniqueKey*\2c\20unsigned\20int\2c\20SkIRect\20const&\29 +3205:GrImageInfo::GrImageInfo\28GrColorInfo\20const&\2c\20SkISize\20const&\29 +3206:GrGpuResource::removeScratchKey\28\29 +3207:GrGpuResource::registerWithCacheWrapped\28GrWrapCacheable\29 +3208:GrGpuResource::dumpMemoryStatisticsPriv\28SkTraceMemoryDump*\2c\20SkString\20const&\2c\20char\20const*\2c\20unsigned\20long\29\20const +3209:GrGpuBuffer::onGpuMemorySize\28\29\20const +3210:GrGpu::resolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +3211:GrGpu::executeFlushInfo\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20std::__2::optional\2c\20skgpu::MutableTextureState\20const*\29 +3212:GrGeometryProcessor::TextureSampler::TextureSampler\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +3213:GrGeometryProcessor::ProgramImpl::ComputeMatrixKeys\28GrShaderCaps\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\29 +3214:GrGLUniformHandler::getUniformVariable\28GrResourceHandle\29\20const +3215:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_12295 +3216:GrGLSemaphore::GrGLSemaphore\28GrGLGpu*\2c\20bool\29 +3217:GrGLSLVaryingHandler::~GrGLSLVaryingHandler\28\29 +3218:GrGLSLUniformHandler::addInputSampler\28skgpu::Swizzle\20const&\2c\20char\20const*\29 +3219:GrGLSLShaderBuilder::emitFunction\28SkSLType\2c\20char\20const*\2c\20SkSpan\2c\20char\20const*\29 +3220:GrGLSLProgramDataManager::setSkMatrix\28GrResourceHandle\2c\20SkMatrix\20const&\29\20const +3221:GrGLSLProgramBuilder::writeFPFunction\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +3222:GrGLSLProgramBuilder::invokeFP\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +3223:GrGLSLProgramBuilder::addRTFlipUniform\28char\20const*\29 +3224:GrGLSLFragmentShaderBuilder::dstColor\28\29 +3225:GrGLSLBlend::BlendKey\28SkBlendMode\29 +3226:GrGLProgramBuilder::~GrGLProgramBuilder\28\29 +3227:GrGLProgramBuilder::computeCountsAndStrides\28unsigned\20int\2c\20GrGeometryProcessor\20const&\2c\20bool\29 +3228:GrGLGpu::flushScissor\28GrScissorState\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +3229:GrGLGpu::flushClearColor\28std::__2::array\29 +3230:GrGLGpu::createTexture\28SkISize\2c\20GrGLFormat\2c\20unsigned\20int\2c\20skgpu::Renderable\2c\20GrGLTextureParameters::SamplerOverriddenState*\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +3231:GrGLGpu::copySurfaceAsDraw\28GrSurface*\2c\20bool\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +3232:GrGLGpu::HWVertexArrayState::bindInternalVertexArray\28GrGLGpu*\2c\20GrBuffer\20const*\29 +3233:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +3234:GrGLBuffer::Make\28GrGLGpu*\2c\20unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +3235:GrGLAttribArrayState::enableVertexArrays\28GrGLGpu\20const*\2c\20int\2c\20GrPrimitiveRestart\29 +3236:GrFragmentProcessors::make_effect_fp\28sk_sp\2c\20char\20const*\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkSpan\2c\20GrFPArgs\20const&\29 +3237:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkMatrix\20const&\29 +3238:GrFragmentProcessors::MakeChildFP\28SkRuntimeEffect::ChildPtr\20const&\2c\20GrFPArgs\20const&\29 +3239:GrFragmentProcessors::IsSupported\28SkMaskFilter\20const*\29 +3240:GrFragmentProcessor::makeProgramImpl\28\29\20const +3241:GrFragmentProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +3242:GrFragmentProcessor::MulInputByChildAlpha\28std::__2::unique_ptr>\29 +3243:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +3244:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29 +3245:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3246:GrDynamicAtlas::makeNode\28GrDynamicAtlas::Node*\2c\20int\2c\20int\2c\20int\2c\20int\29 +3247:GrDynamicAtlas::instantiate\28GrOnFlushResourceProvider*\2c\20sk_sp\29 +3248:GrDrawingManager::setLastRenderTask\28GrSurfaceProxy\20const*\2c\20GrRenderTask*\29 +3249:GrDrawingManager::flushSurfaces\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +3250:GrDrawOpAtlas::updatePlot\28GrDeferredUploadTarget*\2c\20skgpu::AtlasLocator*\2c\20skgpu::Plot*\29 +3251:GrDirectContext::resetContext\28unsigned\20int\29 +3252:GrDirectContext::getResourceCacheLimit\28\29\20const +3253:GrDefaultGeoProcFactory::MakeForDeviceSpace\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +3254:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20sk_sp\29 +3255:GrColorSpaceXform::apply\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +3256:GrColorSpaceXform::Equals\28GrColorSpaceXform\20const*\2c\20GrColorSpaceXform\20const*\29 +3257:GrBufferAllocPool::unmap\28\29 +3258:GrBlurUtils::can_filter_mask\28SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect*\29 +3259:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29 +3260:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +3261:GrBackendTextures::MakeGL\28int\2c\20int\2c\20skgpu::Mipmapped\2c\20GrGLTextureInfo\20const&\2c\20sk_sp\2c\20std::__2::basic_string_view>\29 +3262:GrBackendFormatStencilBits\28GrBackendFormat\20const&\29 +3263:GrBackendFormat::asMockCompressionType\28\29\20const +3264:GrAATriangulator::~GrAATriangulator\28\29 +3265:GrAAConvexTessellator::fanRing\28GrAAConvexTessellator::Ring\20const&\29 +3266:GrAAConvexTessellator::computePtAlongBisector\28int\2c\20SkPoint\20const&\2c\20int\2c\20float\2c\20SkPoint*\29\20const +3267:GetVariationDesignPosition\28FT_FaceRec_*\2c\20SkFontArguments::VariationPosition::Coordinate*\2c\20int\29 +3268:GetAxes\28FT_FaceRec_*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\29 +3269:FT_Stream_ReadAt +3270:FT_Set_Char_Size +3271:FT_Request_Metrics +3272:FT_New_Library +3273:FT_Hypot +3274:FT_Get_Var_Design_Coordinates +3275:FT_Get_Paint +3276:FT_Get_MM_Var +3277:FT_Get_Advance +3278:FT_Add_Default_Modules +3279:DecodeImageData +3280:Cr_z_inflate_table +3281:Cr_z_inflateReset +3282:Cr_z_deflateEnd +3283:Cr_z_copy_with_crc +3284:Compute_Point_Displacement +3285:BuildHuffmanTable +3286:BrotliWarmupBitReader +3287:BrotliDecoderHuffmanTreeGroupInit +3288:AAT::track::sanitize\28hb_sanitize_context_t*\29\20const +3289:AAT::ltag::sanitize\28hb_sanitize_context_t*\29\20const +3290:AAT::StateTable::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +3291:AAT::Lookup>\2c\20OT::IntType\2c\20false>>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3292:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +3293:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +3294:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +3295:3058 +3296:3059 +3297:3060 +3298:3061 +3299:3062 +3300:3063 +3301:3064 +3302:3065 +3303:3066 +3304:3067 +3305:3068 +3306:3069 +3307:3070 +3308:3071 +3309:3072 +3310:3073 +3311:3074 +3312:3075 +3313:3076 +3314:3077 +3315:3078 +3316:3079 +3317:3080 +3318:3081 +3319:zeroinfnan +3320:xyz_almost_equal\28skcms_Matrix3x3\20const&\2c\20skcms_Matrix3x3\20const&\29 +3321:wuffs_lzw__decoder__transform_io +3322:wuffs_gif__decoder__set_quirk_enabled +3323:wuffs_gif__decoder__restart_frame +3324:wuffs_gif__decoder__num_animation_loops +3325:wuffs_gif__decoder__frame_dirty_rect +3326:wuffs_gif__decoder__decode_up_to_id_part1 +3327:wuffs_gif__decoder__decode_frame +3328:write_vertex_position\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrShaderVar\20const&\2c\20SkMatrix\20const&\2c\20char\20const*\2c\20GrShaderVar*\2c\20GrResourceHandle*\29 +3329:write_passthrough_vertex_position\28GrGLSLVertexBuilder*\2c\20GrShaderVar\20const&\2c\20GrShaderVar*\29 +3330:write_buf +3331:wctomb +3332:wchar_t*\20std::__2::copy\5babi:nn180100\5d\2c\20wchar_t*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20wchar_t*\29 +3333:wchar_t*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20std::__2::__element_count\29 +3334:walk_simple_edges\28SkEdge*\2c\20SkBlitter*\2c\20int\2c\20int\29 +3335:vsscanf +3336:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28unsigned\20long*\2c\20unsigned\20long*\2c\20long\29 +3337:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20long\29 +3338:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28SkString*\2c\20SkString*\2c\20long\29 +3339:void\20std::__2::vector>::__assign_with_size\5babi:ne180100\5d\28SkFontArguments::VariationPosition::Coordinate*\2c\20SkFontArguments::VariationPosition::Coordinate*\2c\20long\29 +3340:void\20std::__2::basic_string\2c\20std::__2::allocator>::__init\28wchar_t\20const*\2c\20wchar_t\20const*\29 +3341:void\20std::__2::basic_string\2c\20std::__2::allocator>::__init\28char*\2c\20char*\29 +3342:void\20std::__2::__tree_balance_after_insert\5babi:ne180100\5d*>\28std::__2::__tree_node_base*\2c\20std::__2::__tree_node_base*\29 +3343:void\20std::__2::__stable_sort_move\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\29 +3344:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +3345:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\29 +3346:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +3347:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +3348:void\20std::__2::__sift_up\5babi:ne180100\5d*>>\28std::__2::__wrap_iter*>\2c\20std::__2::__wrap_iter*>\2c\20GrGeometryProcessor::ProgramImpl::emitTransformCode\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\29::$_0&\2c\20std::__2::iterator_traits*>>::difference_type\29 +3349:void\20std::__2::__optional_storage_base::__assign_from\5babi:ne180100\5d\20const&>\28std::__2::__optional_copy_assign_base\20const&\29 +3350:void\20std::__2::__introsort\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +3351:void\20std::__2::__introsort\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\2c\20std::__2::iterator_traits<\28anonymous\20namespace\29::Entry*>::difference_type\2c\20bool\29 +3352:void\20std::__2::__introsort\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +3353:void\20std::__2::__introsort\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +3354:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20char*&\2c\20char*&\29 +3355:void\20std::__2::__call_once_proxy\5babi:nn180100\5d>\28void*\29 +3356:void\20sorted_merge<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +3357:void\20sorted_merge<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +3358:void\20sort_r_simple<>\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29_14114 +3359:void\20skgpu::ganesh::SurfaceFillContext::clear<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\20const&\29 +3360:void\20hair_path<\28SkPaint::Cap\292>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3361:void\20hair_path<\28SkPaint::Cap\291>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3362:void\20hair_path<\28SkPaint::Cap\290>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3363:void\20emscripten::internal::raw_destructor>\28sk_sp*\29 +3364:void\20emscripten::internal::MemberAccess>::setWire\28sk_sp\20SkRuntimeEffect::TracedShader::*\20const&\2c\20SkRuntimeEffect::TracedShader&\2c\20sk_sp*\29 +3365:void\20emscripten::internal::MemberAccess::setWire\28SimpleFontStyle\20SimpleStrutStyle::*\20const&\2c\20SimpleStrutStyle&\2c\20SimpleFontStyle*\29 +3366:void\20\28anonymous\20namespace\29::copyFT2LCD16\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\29 +3367:void\20SkTIntroSort\28int\2c\20int*\2c\20int\2c\20DistanceLessThan\20const&\29 +3368:void\20SkTIntroSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29>\28int\2c\20float*\2c\20int\2c\20void\20SkTQSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29\20const&\29 +3369:void\20SkTIntroSort\28int\2c\20SkString*\2c\20int\2c\20bool\20\20const\28&\29\28SkString\20const&\2c\20SkString\20const&\29\29 +3370:void\20SkTIntroSort\28int\2c\20SkOpRayHit**\2c\20int\2c\20bool\20\20const\28&\29\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29\29 +3371:void\20SkTIntroSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29>\28int\2c\20SkOpContour*\2c\20int\2c\20void\20SkTQSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29\20const&\29 +3372:void\20SkTIntroSort>\2c\20SkCodec::Result*\29::Entry\2c\20SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29::EntryLessThan>\28int\2c\20SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29::Entry*\2c\20int\2c\20SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29::EntryLessThan\20const&\29 +3373:void\20SkTIntroSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29>\28int\2c\20SkClosestRecord\20const*\2c\20int\2c\20void\20SkTQSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29\20const&\29 +3374:void\20SkTIntroSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29>\28int\2c\20SkAnalyticEdge*\2c\20int\2c\20void\20SkTQSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29\20const&\29 +3375:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\20const\28&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +3376:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\28*\20const&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +3377:void\20SkTIntroSort\28int\2c\20Edge*\2c\20int\2c\20EdgeLT\20const&\29 +3378:void\20AAT::StateTableDriver::drive::driver_context_t>\28AAT::LigatureSubtable::driver_context_t*\2c\20AAT::hb_aat_apply_context_t*\29::'lambda0'\28\29::operator\28\29\28\29\20const +3379:virtual\20thunk\20to\20GrGLTexture::onSetLabel\28\29 +3380:virtual\20thunk\20to\20GrGLTexture::backendFormat\28\29\20const +3381:vfiprintf +3382:validate_texel_levels\28SkISize\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20GrCaps\20const*\29 +3383:unsigned\20short\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3384:unsigned\20long\20long\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3385:unsigned\20long\20const&\20std::__2::min\5babi:nn180100\5d\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29 +3386:unsigned\20int\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3387:unsigned\20int\20const*\20std::__2::lower_bound\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20unsigned\20long\20const&\29 +3388:unsigned\20int\20const&\20std::__2::__identity::operator\28\29\5babi:nn180100\5d\28unsigned\20int\20const&\29\20const +3389:ubidi_close_skia +3390:u_terminateUChars_skia +3391:u_charType_skia +3392:tt_size_run_prep +3393:tt_size_done_bytecode +3394:tt_sbit_decoder_load_image +3395:tt_face_vary_cvt +3396:tt_face_palette_set +3397:tt_face_load_cvt +3398:tt_face_get_metrics +3399:tt_done_blend +3400:tt_delta_interpolate +3401:tt_cmap4_next +3402:tt_cmap4_char_map_linear +3403:tt_cmap4_char_map_binary +3404:tt_cmap14_get_def_chars +3405:tt_cmap13_next +3406:tt_cmap12_next +3407:tt_cmap12_init +3408:tt_cmap12_char_map_binary +3409:tt_apply_mvar +3410:toParagraphStyle\28SimpleParagraphStyle\20const&\29 +3411:toBytes\28sk_sp\29 +3412:t1_lookup_glyph_by_stdcharcode_ps +3413:t1_builder_close_contour +3414:t1_builder_check_points +3415:strtoull +3416:strtoll_l +3417:strspn +3418:strncpy +3419:stream_close +3420:store_int +3421:std::logic_error::~logic_error\28\29 +3422:std::logic_error::logic_error\28char\20const*\29 +3423:std::exception::exception\5babi:nn180100\5d\28\29 +3424:std::__2::vector>::max_size\28\29\20const +3425:std::__2::vector>::capacity\5babi:nn180100\5d\28\29\20const +3426:std::__2::vector>::__construct_at_end\28unsigned\20long\29 +3427:std::__2::vector>::__clear\5babi:nn180100\5d\28\29 +3428:std::__2::vector>::__base_destruct_at_end\5babi:nn180100\5d\28std::__2::locale::facet**\29 +3429:std::__2::vector>::insert\28std::__2::__wrap_iter\2c\20float&&\29 +3430:std::__2::vector>::__append\28unsigned\20long\29 +3431:std::__2::unique_ptr::operator=\5babi:nn180100\5d\28std::__2::unique_ptr&&\29 +3432:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3433:std::__2::unique_ptr>::operator=\5babi:ne180100\5d\28std::nullptr_t\29 +3434:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkCanvas::Layer*\29 +3435:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda0'\28\29::operator\28\29\28\29\20const +3436:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +3437:std::__2::to_string\28unsigned\20long\29 +3438:std::__2::to_chars_result\20std::__2::__to_chars_itoa\5babi:nn180100\5d\28char*\2c\20char*\2c\20unsigned\20int\2c\20std::__2::integral_constant\29 +3439:std::__2::time_put>>::~time_put\28\29 +3440:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3441:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3442:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3443:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3444:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3445:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +3446:std::__2::reverse_iterator::operator++\5babi:nn180100\5d\28\29 +3447:std::__2::reverse_iterator::operator*\5babi:nn180100\5d\28\29\20const +3448:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t*\29\20const +3449:std::__2::pair\2c\20void*>*>\2c\20bool>\20std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__emplace_unique_key_args\2c\20std::__2::tuple<>>\28GrFragmentProcessor\20const*\20const&\2c\20std::__2::piecewise_construct_t\20const&\2c\20std::__2::tuple&&\2c\20std::__2::tuple<>&&\29 +3450:std::__2::pair*>\2c\20bool>\20std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__emplace_unique_key_args\28int\20const&\2c\20int\20const&\29 +3451:std::__2::pair\2c\20std::__2::allocator>>>::pair\5babi:ne180100\5d\28std::__2::pair\2c\20std::__2::allocator>>>&&\29 +3452:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +3453:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28wchar_t\29 +3454:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28char\29 +3455:std::__2::optional&\20std::__2::optional::operator=\5babi:ne180100\5d\28SkPath\20const&\29 +3456:std::__2::numpunct::~numpunct\28\29 +3457:std::__2::numpunct::~numpunct\28\29 +3458:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +3459:std::__2::num_get>>\20const&\20std::__2::use_facet\5babi:nn180100\5d>>>\28std::__2::locale\20const&\29 +3460:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +3461:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3462:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3463:std::__2::moneypunct::do_negative_sign\28\29\20const +3464:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3465:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +3466:std::__2::moneypunct::do_negative_sign\28\29\20const +3467:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20wchar_t*&\2c\20wchar_t*\29 +3468:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20char*&\2c\20char*\29 +3469:std::__2::locale::facet**\20std::__2::__construct_at\5babi:nn180100\5d\28std::__2::locale::facet**\29 +3470:std::__2::locale::__imp::~__imp\28\29 +3471:std::__2::locale::__imp::release\28\29 +3472:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20std::__2::random_access_iterator_tag\29 +3473:std::__2::iterator_traits\2c\20std::__2::allocator>\20const*>::difference_type\20std::__2::distance\5babi:nn180100\5d\2c\20std::__2::allocator>\20const*>\28std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +3474:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28char*\2c\20char*\29 +3475:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::random_access_iterator_tag\29 +3476:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +3477:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +3478:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +3479:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +3480:std::__2::ios_base::width\5babi:nn180100\5d\28long\29 +3481:std::__2::ios_base::imbue\28std::__2::locale\20const&\29 +3482:std::__2::ios_base::__call_callbacks\28std::__2::ios_base::event\29 +3483:std::__2::hash::operator\28\29\28skia::textlayout::FontArguments\20const&\29\20const +3484:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d\28char&\2c\20char&\29 +3485:std::__2::deque>::__add_back_capacity\28\29 +3486:std::__2::default_delete::operator\28\29\5babi:ne180100\5d\28sktext::GlyphRunBuilder*\29\20const +3487:std::__2::default_delete\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot>::type\20std::__2::default_delete\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot>\28skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot*\29\20const +3488:std::__2::default_delete\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot>::type\20std::__2::default_delete\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot>\28skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot*\29\20const +3489:std::__2::ctype::~ctype\28\29 +3490:std::__2::codecvt::~codecvt\28\29 +3491:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +3492:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char32_t\20const*\2c\20char32_t\20const*\2c\20char32_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +3493:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +3494:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char32_t*\2c\20char32_t*\2c\20char32_t*&\29\20const +3495:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +3496:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +3497:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char16_t*\2c\20char16_t*\2c\20char16_t*&\29\20const +3498:std::__2::char_traits::not_eof\5babi:nn180100\5d\28int\29 +3499:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28\29\20const +3500:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29 +3501:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +3502:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20wchar_t\20const*\29 +3503:std::__2::basic_string\2c\20std::__2::allocator>::resize\28unsigned\20long\2c\20char\29 +3504:std::__2::basic_string\2c\20std::__2::allocator>::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +3505:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20char\29 +3506:std::__2::basic_string\2c\20std::__2::allocator>::basic_string>\2c\200>\28std::__2::basic_string_view>\20const&\29 +3507:std::__2::basic_string\2c\20std::__2::allocator>::__null_terminate_at\5babi:nn180100\5d\28char*\2c\20unsigned\20long\29 +3508:std::__2::basic_string\2c\20std::__2::allocator>&\20std::__2::basic_string\2c\20std::__2::allocator>::__assign_no_alias\28char\20const*\2c\20unsigned\20long\29 +3509:std::__2::basic_string\2c\20std::__2::allocator>&\20skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::emplace_back\28char\20const*&&\29 +3510:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +3511:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +3512:std::__2::basic_streambuf>::sputc\5babi:nn180100\5d\28char\29 +3513:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +3514:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +3515:std::__2::basic_ostream>::~basic_ostream\28\29_16058 +3516:std::__2::basic_ostream>::sentry::~sentry\28\29 +3517:std::__2::basic_ostream>::sentry::sentry\28std::__2::basic_ostream>&\29 +3518:std::__2::basic_ostream>::operator<<\28float\29 +3519:std::__2::basic_ostream>::flush\28\29 +3520:std::__2::basic_istream>::~basic_istream\28\29_16017 +3521:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::__sso_allocator&\2c\20std::__2::locale::facet**\2c\20unsigned\20long\29 +3522:std::__2::allocator::deallocate\5babi:nn180100\5d\28wchar_t*\2c\20unsigned\20long\29 +3523:std::__2::allocator::allocate\5babi:nn180100\5d\28unsigned\20long\29 +3524:std::__2::allocator::allocate\5babi:nn180100\5d\28unsigned\20long\29 +3525:std::__2::__wrap_iter\20std::__2::vector>::__insert_with_size\5babi:ne180100\5d>\2c\20std::__2::reverse_iterator>>\28std::__2::__wrap_iter\2c\20std::__2::reverse_iterator>\2c\20std::__2::reverse_iterator>\2c\20long\29 +3526:std::__2::__wrap_iter\20std::__2::vector>::__insert_with_size\5babi:ne180100\5d\2c\20std::__2::__wrap_iter>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20long\29 +3527:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +3528:std::__2::__time_put::__time_put\5babi:nn180100\5d\28\29 +3529:std::__2::__time_put::__do_put\28char*\2c\20char*&\2c\20tm\20const*\2c\20char\2c\20char\29\20const +3530:std::__2::__split_buffer>::push_back\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +3531:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3532:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +3533:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +3534:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +3535:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +3536:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20wchar_t&\2c\20wchar_t&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +3537:std::__2::__money_put::__format\28wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20unsigned\20int\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +3538:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20char&\2c\20char&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +3539:std::__2::__money_put::__format\28char*\2c\20char*&\2c\20char*&\2c\20unsigned\20int\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +3540:std::__2::__libcpp_sscanf_l\28char\20const*\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +3541:std::__2::__libcpp_mbrtowc_l\5babi:nn180100\5d\28wchar_t*\2c\20char\20const*\2c\20unsigned\20long\2c\20__mbstate_t*\2c\20__locale_struct*\29 +3542:std::__2::__libcpp_mb_cur_max_l\5babi:nn180100\5d\28__locale_struct*\29 +3543:std::__2::__libcpp_deallocate\5babi:nn180100\5d\28void*\2c\20unsigned\20long\2c\20unsigned\20long\29 +3544:std::__2::__libcpp_allocate\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\29 +3545:std::__2::__is_overaligned_for_new\5babi:nn180100\5d\28unsigned\20long\29 +3546:std::__2::__function::__value_func::swap\5babi:ne180100\5d\28std::__2::__function::__value_func&\29 +3547:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +3548:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +3549:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +3550:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::destroy\28\29 +3551:std::__2::__constexpr_wcslen\5babi:nn180100\5d\28wchar_t\20const*\29 +3552:std::__2::__compressed_pair_elem\2c\20std::__2::allocator>::__rep\2c\200\2c\20false>::__compressed_pair_elem\5babi:nn180100\5d\28std::__2::__value_init_tag\29 +3553:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::__sso_allocator&\2c\20unsigned\20long\29 +3554:start_input_pass +3555:sktext::gpu::can_use_direct\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +3556:sktext::gpu::build_distance_adjust_table\28float\29 +3557:sktext::gpu::VertexFiller::opMaskType\28\29\20const +3558:sktext::gpu::VertexFiller::isLCD\28\29\20const +3559:sktext::gpu::VertexFiller::fillVertexData\28int\2c\20int\2c\20SkSpan\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkIRect\2c\20void*\29\20const +3560:sktext::gpu::TextBlobRedrawCoordinator::internalRemove\28sktext::gpu::TextBlob*\29 +3561:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_2::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +3562:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_0::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +3563:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29 +3564:sktext::gpu::SubRunContainer::EstimateAllocSize\28sktext::GlyphRunList\20const&\29 +3565:sktext::gpu::SubRunAllocator::SubRunAllocator\28char*\2c\20int\2c\20int\29 +3566:sktext::gpu::StrikeCache::~StrikeCache\28\29 +3567:sktext::gpu::SlugImpl::Make\28SkMatrix\20const&\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\29 +3568:sktext::gpu::BagOfBytes::BagOfBytes\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29::$_1::operator\28\29\28\29\20const +3569:sktext::glyphrun_source_bounds\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkZip\2c\20SkSpan\29 +3570:sktext::SkStrikePromise::resetStrike\28\29 +3571:sktext::GlyphRunList::makeBlob\28\29\20const +3572:sktext::GlyphRunBuilder::blobToGlyphRunList\28SkTextBlob\20const&\2c\20SkPoint\29 +3573:sktext::GlyphRun*\20std::__2::vector>::__emplace_back_slow_path&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&>\28SkFont\20const&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\29 +3574:skstd::to_string\28float\29 +3575:skpathutils::FillPathWithPaint\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkPath*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29 +3576:skjpeg_err_exit\28jpeg_common_struct*\29 +3577:skip_string +3578:skip_procedure +3579:skif::\28anonymous\20namespace\29::decompose_transform\28SkMatrix\20const&\2c\20SkPoint\2c\20SkMatrix*\2c\20SkMatrix*\29 +3580:skif::Mapping::adjustLayerSpace\28SkMatrix\20const&\29 +3581:skif::FilterResult::imageAndOffset\28skif::Context\20const&\29\20const +3582:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20SkBlender\20const*\29\20const +3583:skif::FilterResult::MakeFromImage\28skif::Context\20const&\2c\20sk_sp\2c\20SkRect\2c\20skif::ParameterSpace\2c\20SkSamplingOptions\20const&\29 +3584:skif::FilterResult::FilterResult\28sk_sp\2c\20skif::LayerSpace\20const&\29 +3585:skif::Context::withNewSource\28skif::FilterResult\20const&\29\20const +3586:skia_private::THashTable::Traits>::set\28unsigned\20long\20long\29 +3587:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::set\28std::__2::basic_string_view>\29 +3588:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::resize\28int\29 +3589:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +3590:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::removeSlot\28int\29 +3591:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::resize\28int\29 +3592:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair&&\29 +3593:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair&&\29 +3594:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +3595:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\29 +3596:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::operator=\28skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>\20const&\29 +3597:skia_private::THashTable::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::resize\28int\29 +3598:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair&&\29 +3599:skia_private::THashTable::Pair\2c\20SkSL::Analysis::SpecializedCallKey\2c\20skia_private::THashMap::Pair>::set\28skia_private::THashMap::Pair\29 +3600:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +3601:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +3602:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::resize\28int\29 +3603:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28skgpu::ganesh::SmallPathShapeData*&&\29 +3604:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +3605:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::resize\28int\29 +3606:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::resize\28int\29 +3607:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::uncheckedSet\28\28anonymous\20namespace\29::CacheImpl::Value*&&\29 +3608:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::resize\28int\29 +3609:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +3610:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +3611:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +3612:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +3613:skia_private::THashTable::resize\28int\29 +3614:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::removeIfExists\28unsigned\20int\20const&\29 +3615:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +3616:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::uncheckedSet\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*&&\29 +3617:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +3618:skia_private::THashTable::AdaptedTraits>::set\28GrThreadSafeCache::Entry*\29 +3619:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +3620:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +3621:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +3622:skia_private::THashTable::Traits>::resize\28int\29 +3623:skia_private::THashSet::add\28FT_Opaque_Paint_\29 +3624:skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +3625:skia_private::THashMap>\2c\20SkGoodHash>::remove\28SkImageFilter\20const*\20const&\29 +3626:skia_private::TArray::push_back_raw\28int\29 +3627:skia_private::TArray::resize_back\28int\29 +3628:skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::checkRealloc\28int\2c\20double\29 +3629:skia_private::TArray::~TArray\28\29 +3630:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +3631:skia_private::TArray::operator=\28skia_private::TArray&&\29 +3632:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +3633:skia_private::TArray::BufferFinishedMessage\2c\20false>::operator=\28skia_private::TArray::BufferFinishedMessage\2c\20false>&&\29 +3634:skia_private::TArray::BufferFinishedMessage\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +3635:skia_private::TArray::operator=\28skia_private::TArray&&\29 +3636:skia_private::TArray\29::ReorderedArgument\2c\20false>::push_back\28SkSL::optimize_constructor_swizzle\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ConstructorCompound\20const&\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29::ReorderedArgument&&\29 +3637:skia_private::TArray::TArray\28skia_private::TArray&&\29 +3638:skia_private::TArray::swap\28skia_private::TArray&\29 +3639:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +3640:skia_private::TArray::push_back_raw\28int\29 +3641:skia_private::TArray::push_back_raw\28int\29 +3642:skia_private::TArray::push_back_raw\28int\29 +3643:skia_private::TArray::move_back_n\28int\2c\20GrTextureProxy**\29 +3644:skia_private::TArray::operator=\28skia_private::TArray&&\29 +3645:skia_private::TArray::push_back_n\28int\2c\20EllipticalRRectOp::RRect\20const*\29 +3646:skia_png_zfree +3647:skia_png_write_zTXt +3648:skia_png_write_tIME +3649:skia_png_write_tEXt +3650:skia_png_write_iTXt +3651:skia_png_set_write_fn +3652:skia_png_set_unknown_chunks +3653:skia_png_set_strip_16 +3654:skia_png_set_read_user_transform_fn +3655:skia_png_set_read_user_chunk_fn +3656:skia_png_set_option +3657:skia_png_set_mem_fn +3658:skia_png_set_expand_gray_1_2_4_to_8 +3659:skia_png_set_error_fn +3660:skia_png_set_compression_level +3661:skia_png_set_IHDR +3662:skia_png_read_filter_row +3663:skia_png_process_IDAT_data +3664:skia_png_icc_set_sRGB +3665:skia_png_icc_check_tag_table +3666:skia_png_icc_check_header +3667:skia_png_get_uint_31 +3668:skia_png_get_sBIT +3669:skia_png_get_rowbytes +3670:skia_png_get_error_ptr +3671:skia_png_get_IHDR +3672:skia_png_do_swap +3673:skia_png_do_read_transformations +3674:skia_png_do_read_interlace +3675:skia_png_do_packswap +3676:skia_png_do_invert +3677:skia_png_do_gray_to_rgb +3678:skia_png_do_expand +3679:skia_png_do_check_palette_indexes +3680:skia_png_do_bgr +3681:skia_png_destroy_png_struct +3682:skia_png_destroy_gamma_table +3683:skia_png_create_png_struct +3684:skia_png_create_info_struct +3685:skia_png_crc_read +3686:skia_png_colorspace_sync_info +3687:skia_png_check_IHDR +3688:skia::textlayout::TypefaceFontStyleSet::matchStyle\28SkFontStyle\20const&\29 +3689:skia::textlayout::TextStyle::matchOneAttribute\28skia::textlayout::StyleType\2c\20skia::textlayout::TextStyle\20const&\29\20const +3690:skia::textlayout::TextStyle::equals\28skia::textlayout::TextStyle\20const&\29\20const +3691:skia::textlayout::TextShadow::operator!=\28skia::textlayout::TextShadow\20const&\29\20const +3692:skia::textlayout::TextLine::paint\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\29 +3693:skia::textlayout::TextLine::iterateThroughClustersInGlyphsOrder\28bool\2c\20bool\2c\20std::__2::function\20const&\29\20const::$_0::operator\28\29\28unsigned\20long\20const&\29\20const +3694:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkRect\29::operator\28\29\28SkRect\29\20const +3695:skia::textlayout::TextLine::getMetrics\28\29\20const +3696:skia::textlayout::TextLine::ensureTextBlobCachePopulated\28\29 +3697:skia::textlayout::TextLine::buildTextBlob\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +3698:skia::textlayout::TextLine::TextLine\28skia::textlayout::ParagraphImpl*\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20skia::textlayout::InternalLineMetrics\29 +3699:skia::textlayout::TextLine&\20skia_private::TArray::emplace_back&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&>\28skia::textlayout::ParagraphImpl*&&\2c\20SkPoint&\2c\20SkPoint&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&\29 +3700:skia::textlayout::Run::shift\28skia::textlayout::Cluster\20const*\2c\20float\29 +3701:skia::textlayout::Run::newRunBuffer\28\29 +3702:skia::textlayout::Run::findLimitingGlyphClusters\28skia::textlayout::SkRange\29\20const +3703:skia::textlayout::Run::addSpacesAtTheEnd\28float\2c\20skia::textlayout::Cluster*\29 +3704:skia::textlayout::ParagraphStyle::effective_align\28\29\20const +3705:skia::textlayout::ParagraphStyle::ParagraphStyle\28\29 +3706:skia::textlayout::ParagraphPainter::DecorationStyle::DecorationStyle\28unsigned\20int\2c\20float\2c\20std::__2::optional\29 +3707:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29 +3708:skia::textlayout::ParagraphImpl::text\28skia::textlayout::SkRange\29 +3709:skia::textlayout::ParagraphImpl::resolveStrut\28\29 +3710:skia::textlayout::ParagraphImpl::getGlyphInfoAtUTF16Offset\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +3711:skia::textlayout::ParagraphImpl::getGlyphClusterAt\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +3712:skia::textlayout::ParagraphImpl::findPreviousGraphemeBoundary\28unsigned\20long\29\20const +3713:skia::textlayout::ParagraphImpl::computeEmptyMetrics\28\29 +3714:skia::textlayout::ParagraphImpl::clusters\28skia::textlayout::SkRange\29 +3715:skia::textlayout::ParagraphImpl::block\28unsigned\20long\29 +3716:skia::textlayout::ParagraphCacheValue::~ParagraphCacheValue\28\29 +3717:skia::textlayout::ParagraphCacheKey::ParagraphCacheKey\28skia::textlayout::ParagraphImpl\20const*\29 +3718:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29 +3719:skia::textlayout::ParagraphBuilderImpl::make\28skia::textlayout::ParagraphStyle\20const&\2c\20sk_sp\2c\20sk_sp\29 +3720:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\2c\20bool\29 +3721:skia::textlayout::ParagraphBuilderImpl::ParagraphBuilderImpl\28skia::textlayout::ParagraphStyle\20const&\2c\20sk_sp\2c\20sk_sp\29 +3722:skia::textlayout::Paragraph::~Paragraph\28\29 +3723:skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29 +3724:skia::textlayout::FontCollection::~FontCollection\28\29 +3725:skia::textlayout::FontCollection::matchTypeface\28SkString\20const&\2c\20SkFontStyle\29 +3726:skia::textlayout::FontCollection::defaultFallback\28int\2c\20SkFontStyle\2c\20SkString\20const&\29 +3727:skia::textlayout::FontCollection::FamilyKey::Hasher::operator\28\29\28skia::textlayout::FontCollection::FamilyKey\20const&\29\20const +3728:skgpu::tess::\28anonymous\20namespace\29::write_curve_index_buffer_base_index\28skgpu::VertexWriter\2c\20unsigned\20long\2c\20unsigned\20short\29 +3729:skgpu::tess::StrokeIterator::next\28\29 +3730:skgpu::tess::StrokeIterator::finishOpenContour\28\29 +3731:skgpu::tess::PreChopPathCurves\28float\2c\20SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +3732:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29 +3733:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::SmallPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20GrUserStencilSettings\20const*\29 +3734:skgpu::ganesh::\28anonymous\20namespace\29::ChopPathIfNecessary\28SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkStrokeRec\20const&\2c\20SkPath*\29 +3735:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::recordDraw\28GrMeshDrawTarget*\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20int\2c\20unsigned\20short*\29 +3736:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::AAFlatteningConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20float\2c\20SkStrokeRec::Style\2c\20SkPaint::Join\2c\20float\2c\20GrUserStencilSettings\20const*\29 +3737:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::AAConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrUserStencilSettings\20const*\29 +3738:skgpu::ganesh::TextureOp::Make\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20SkBlendMode\2c\20GrAAType\2c\20DrawQuad*\2c\20SkRect\20const*\29 +3739:skgpu::ganesh::TessellationPathRenderer::IsSupported\28GrCaps\20const&\29 +3740:skgpu::ganesh::SurfaceFillContext::fillRectToRectWithFP\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +3741:skgpu::ganesh::SurfaceFillContext::blitTexture\28GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\29 +3742:skgpu::ganesh::SurfaceFillContext::addOp\28std::__2::unique_ptr>\29 +3743:skgpu::ganesh::SurfaceFillContext::addDrawOp\28std::__2::unique_ptr>\29 +3744:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29_10038 +3745:skgpu::ganesh::SurfaceDrawContext::drawVertices\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20sk_sp\2c\20GrPrimitiveType*\2c\20bool\29 +3746:skgpu::ganesh::SurfaceDrawContext::drawTexturedQuad\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkBlendMode\2c\20DrawQuad*\2c\20SkRect\20const*\29 +3747:skgpu::ganesh::SurfaceDrawContext::drawTexture\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkBlendMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +3748:skgpu::ganesh::SurfaceDrawContext::drawStrokedLine\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPoint\20const*\2c\20SkStrokeRec\20const&\29 +3749:skgpu::ganesh::SurfaceDrawContext::drawRegion\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrStyle\20const&\2c\20GrUserStencilSettings\20const*\29 +3750:skgpu::ganesh::SurfaceDrawContext::drawOval\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\29 +3751:skgpu::ganesh::SurfaceDrawContext::SurfaceDrawContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +3752:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29 +3753:skgpu::ganesh::SurfaceContext::writePixels\28GrDirectContext*\2c\20GrCPixmap\2c\20SkIPoint\29 +3754:skgpu::ganesh::SurfaceContext::copy\28sk_sp\2c\20SkIRect\2c\20SkIPoint\29 +3755:skgpu::ganesh::SurfaceContext::copyScaled\28sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20SkFilterMode\29 +3756:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +3757:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::FinishContext::~FinishContext\28\29 +3758:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +3759:skgpu::ganesh::SurfaceContext::SurfaceContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +3760:skgpu::ganesh::StrokeTessellator::draw\28GrOpFlushState*\29\20const +3761:skgpu::ganesh::StrokeTessellateOp::prePrepareTessellator\28GrTessellationShader::ProgramArgs&&\2c\20GrAppliedClip&&\29 +3762:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::NonAAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrSimpleMeshDrawOpHelper::InputFlags\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\2c\20GrAAType\29 +3763:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::AAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::RectInfo\20const&\2c\20bool\29 +3764:skgpu::ganesh::StencilMaskHelper::drawShape\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20SkRegion::Op\2c\20GrAA\29 +3765:skgpu::ganesh::SoftwarePathRenderer::DrawAroundInvPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29 +3766:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11532 +3767:skgpu::ganesh::SmallPathAtlasMgr::findOrCreate\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +3768:skgpu::ganesh::SmallPathAtlasMgr::deleteCacheEntry\28skgpu::ganesh::SmallPathShapeData*\29 +3769:skgpu::ganesh::ShadowRRectOp::Make\28GrRecordingContext*\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20float\2c\20float\29 +3770:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::RegionOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +3771:skgpu::ganesh::RasterAsView\28GrRecordingContext*\2c\20SkImage_Raster\20const*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +3772:skgpu::ganesh::QuadPerEdgeAA::Tessellator::append\28GrQuad*\2c\20GrQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\29 +3773:skgpu::ganesh::QuadPerEdgeAA::Tessellator::Tessellator\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29 +3774:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::initializeAttrs\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29 +3775:skgpu::ganesh::QuadPerEdgeAA::IssueDraw\28GrCaps\20const&\2c\20GrOpsRenderPass*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3776:skgpu::ganesh::QuadPerEdgeAA::GetIndexBuffer\28GrMeshDrawTarget*\2c\20skgpu::ganesh::QuadPerEdgeAA::IndexBufferOption\29 +3777:skgpu::ganesh::PathTessellateOp::usesMSAA\28\29\20const +3778:skgpu::ganesh::PathTessellateOp::prepareTessellator\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +3779:skgpu::ganesh::PathTessellateOp::PathTessellateOp\28SkArenaAlloc*\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\2c\20SkRect\20const&\29 +3780:skgpu::ganesh::PathStencilCoverOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +3781:skgpu::ganesh::PathRenderer::getStencilSupport\28GrStyledShape\20const&\29\20const +3782:skgpu::ganesh::PathInnerTriangulateOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +3783:skgpu::ganesh::PathCurveTessellator::~PathCurveTessellator\28\29 +3784:skgpu::ganesh::PathCurveTessellator::prepareWithTriangles\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20GrTriangulator::BreadcrumbTriangleList*\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +3785:skgpu::ganesh::OpsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +3786:skgpu::ganesh::OpsTask::onExecute\28GrOpFlushState*\29 +3787:skgpu::ganesh::OpsTask::addOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +3788:skgpu::ganesh::OpsTask::addDrawOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +3789:skgpu::ganesh::OpsTask::OpsTask\28GrDrawingManager*\2c\20GrSurfaceProxyView\2c\20GrAuditTrail*\2c\20sk_sp\29 +3790:skgpu::ganesh::OpsTask::OpChain::tryConcat\28skgpu::ganesh::OpsTask::OpChain::List*\2c\20GrProcessorSet::Analysis\2c\20GrDstProxyView\20const&\2c\20GrAppliedClip\20const*\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrAuditTrail*\29 +3791:skgpu::ganesh::MakeFragmentProcessorFromView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +3792:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29 +3793:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29 +3794:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::NonAALatticeOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20std::__2::unique_ptr>\2c\20SkRect\20const&\29 +3795:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20GrAA\29 +3796:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::FillRRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29 +3797:skgpu::ganesh::DrawAtlasPathOp::prepareProgram\28GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +3798:skgpu::ganesh::Device::replaceBackingProxy\28SkSurface::ContentChangeMode\2c\20sk_sp\2c\20GrColorType\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +3799:skgpu::ganesh::Device::makeSpecial\28SkBitmap\20const&\29 +3800:skgpu::ganesh::Device::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +3801:skgpu::ganesh::Device::drawEdgeAAImage\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20SkTileMode\29 +3802:skgpu::ganesh::Device::discard\28\29 +3803:skgpu::ganesh::Device::android_utils_clipAsRgn\28SkRegion*\29\20const +3804:skgpu::ganesh::DefaultPathRenderer::internalDrawPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20bool\29 +3805:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +3806:skgpu::ganesh::CopyView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\2c\20std::__2::basic_string_view>\29 +3807:skgpu::ganesh::ClipStack::clipPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrAA\2c\20SkClipOp\29 +3808:skgpu::ganesh::ClipStack::SaveRecord::replaceWithElement\28skgpu::ganesh::ClipStack::RawElement&&\2c\20SkTBlockList*\29 +3809:skgpu::ganesh::ClipStack::SaveRecord::addElement\28skgpu::ganesh::ClipStack::RawElement&&\2c\20SkTBlockList*\29 +3810:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::Draw\20const&\29\20const +3811:skgpu::ganesh::AtlasTextOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +3812:skgpu::ganesh::AtlasTextOp::AtlasTextOp\28skgpu::ganesh::AtlasTextOp::MaskType\2c\20bool\2c\20int\2c\20SkRect\2c\20skgpu::ganesh::AtlasTextOp::Geometry*\2c\20GrColorInfo\20const&\2c\20GrPaint&&\29 +3813:skgpu::ganesh::AtlasRenderTask::stencilAtlasRect\28GrRecordingContext*\2c\20SkRect\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrUserStencilSettings\20const*\29 +3814:skgpu::ganesh::AtlasRenderTask::addPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIPoint\2c\20int\2c\20int\2c\20bool\2c\20SkIPoint16*\29 +3815:skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +3816:skgpu::ganesh::AtlasPathRenderer::addPathToAtlas\28GrRecordingContext*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRect\20const&\2c\20SkIRect*\2c\20SkIPoint16*\2c\20bool*\2c\20std::__2::function\20const&\29 +3817:skgpu::ganesh::AsFragmentProcessor\28GrRecordingContext*\2c\20SkImage\20const*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +3818:skgpu::TiledTextureUtils::OptimizeSampleArea\28SkISize\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkRect*\2c\20SkRect*\2c\20SkMatrix*\29 +3819:skgpu::TClientMappedBufferManager::process\28\29 +3820:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29 +3821:skgpu::RectanizerSkyline::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +3822:skgpu::Plot::Plot\28int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20SkColorType\2c\20unsigned\20long\29 +3823:skgpu::GetReducedBlendModeInfo\28SkBlendMode\29 +3824:skgpu::CreateIntegralTable\28int\29 +3825:skgpu::BlendFuncName\28SkBlendMode\29 +3826:skcms_private::baseline::exec_stages\28skcms_private::Op\20const*\2c\20void\20const**\2c\20char\20const*\2c\20char*\2c\20int\29 +3827:skcms_private::baseline::clut\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20float\20vector\5b4\5d*\2c\20float\20vector\5b4\5d*\2c\20float\20vector\5b4\5d*\2c\20float\20vector\5b4\5d*\29 +3828:skcms_ApproximatelyEqualProfiles +3829:sk_sp*\20std::__2::vector\2c\20std::__2::allocator>>::__emplace_back_slow_path>\28sk_sp&&\29 +3830:sk_sp\20sk_make_sp\2c\20SkSurfaceProps\20const*&>\28SkImageInfo\20const&\2c\20sk_sp&&\2c\20SkSurfaceProps\20const*&\29 +3831:sk_sp*\20emscripten::internal::MemberAccess>::getWire\28sk_sp\20SkRuntimeEffect::TracedShader::*\20const&\2c\20SkRuntimeEffect::TracedShader&\29 +3832:sk_fopen\28char\20const*\2c\20SkFILE_Flags\29 +3833:sk_fgetsize\28_IO_FILE*\29 +3834:sk_fclose\28_IO_FILE*\29 +3835:sk_error_fn\28png_struct_def*\2c\20char\20const*\29 +3836:setup_masks_arabic_plan\28arabic_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_script_t\29 +3837:set_khr_debug_label\28GrGLGpu*\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +3838:setThrew +3839:serialize_image\28SkImage\20const*\2c\20SkSerialProcs\29 +3840:send_tree +3841:sect_with_vertical\28SkPoint\20const*\2c\20float\29 +3842:sect_with_horizontal\28SkPoint\20const*\2c\20float\29 +3843:scanexp +3844:scalbnl +3845:rewind_if_necessary\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +3846:resolveImplicitLevels\28UBiDi*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +3847:reset_and_decode_image_config\28wuffs_gif__decoder__struct*\2c\20wuffs_base__image_config__struct*\2c\20wuffs_base__io_buffer__struct*\2c\20SkStream*\29 +3848:renderbuffer_storage_msaa\28GrGLGpu*\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +3849:recursive_edge_intersect\28GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20SkPoint*\2c\20double*\2c\20double*\29 +3850:reclassify_vertex\28TriangulationVertex*\2c\20SkPoint\20const*\2c\20int\2c\20ReflexHash*\2c\20SkTInternalLList*\29 +3851:quad_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +3852:quad_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +3853:quad_in_line\28SkPoint\20const*\29 +3854:psh_hint_table_init +3855:psh_hint_table_find_strong_points +3856:psh_hint_table_activate_mask +3857:psh_hint_align +3858:psh_glyph_interpolate_strong_points +3859:psh_glyph_interpolate_other_points +3860:psh_glyph_interpolate_normal_points +3861:psh_blues_set_zones +3862:ps_parser_load_field +3863:ps_dimension_end +3864:ps_dimension_done +3865:ps_builder_start_point +3866:printf_core +3867:position_cluster\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29 +3868:portable::uniform_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +3869:portable::set_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +3870:portable::memset64\28unsigned\20long\20long*\2c\20unsigned\20long\20long\2c\20int\29 +3871:portable::copy_from_indirect_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +3872:portable::copy_2_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +3873:portable::check_decal_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +3874:pop_arg +3875:pntz +3876:png_inflate +3877:png_deflate_claim +3878:png_decompress_chunk +3879:png_cache_unknown_chunk +3880:operator_new_impl\28unsigned\20long\29 +3881:operator==\28SkPaint\20const&\2c\20SkPaint\20const&\29 +3882:open_face +3883:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::vertexStride\28SkMatrix\20const&\29\20const +3884:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29_12534 +3885:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29 +3886:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +3887:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::glyphs\28\29\20const +3888:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::glyphCount\28\29\20const +3889:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2566 +3890:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +3891:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::size\28\29\20const +3892:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +3893:nearly_equal\28double\2c\20double\29 +3894:mbsrtowcs +3895:map_quad_general\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20SkMatrix\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +3896:make_tiled_gradient\28GrFPArgs\20const&\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20bool\2c\20bool\29 +3897:make_premul_effect\28std::__2::unique_ptr>\29 +3898:make_dual_interval_colorizer\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20float\29 +3899:make_clamped_gradient\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20bool\29 +3900:make_bmp_proxy\28GrProxyProvider*\2c\20SkBitmap\20const&\2c\20GrColorType\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +3901:longest_match +3902:long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3903:long\20long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +3904:long\20double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +3905:load_post_names +3906:line_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +3907:line_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +3908:legalfunc$_embind_register_bigint +3909:jpeg_open_backing_store +3910:jpeg_consume_input +3911:jpeg_alloc_huff_table +3912:jinit_upsampler +3913:is_leap +3914:init_error_limit +3915:init_block +3916:hb_vector_t\2c\20false>::alloc\28unsigned\20int\2c\20bool\29 +3917:hb_vector_t::push\28\29 +3918:hb_vector_t\2c\20false>::resize\28int\2c\20bool\2c\20bool\29 +3919:hb_utf8_t::next\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20int*\2c\20unsigned\20int\29 +3920:hb_unicode_script +3921:hb_unicode_mirroring_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +3922:hb_unicode_funcs_t::is_default_ignorable\28unsigned\20int\29 +3923:hb_shape_plan_key_t::init\28bool\2c\20hb_face_t*\2c\20hb_segment_properties_t\20const*\2c\20hb_feature_t\20const*\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20char\20const*\20const*\29 +3924:hb_shape_plan_create2 +3925:hb_serialize_context_t::fini\28\29 +3926:hb_sanitize_context_t::return_t\20AAT::ChainSubtable::dispatch\28hb_sanitize_context_t*\29\20const +3927:hb_sanitize_context_t::return_t\20AAT::ChainSubtable::dispatch\28hb_sanitize_context_t*\29\20const +3928:hb_paint_extents_paint_linear_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +3929:hb_paint_extents_get_funcs\28\29 +3930:hb_paint_extents_context_t::hb_paint_extents_context_t\28\29 +3931:hb_ot_map_t::fini\28\29 +3932:hb_ot_layout_table_select_script +3933:hb_ot_layout_table_get_lookup_count +3934:hb_ot_layout_table_find_feature_variations +3935:hb_ot_layout_table_find_feature\28hb_face_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +3936:hb_ot_layout_script_select_language +3937:hb_ot_layout_language_get_required_feature +3938:hb_ot_layout_language_find_feature +3939:hb_ot_layout_has_substitution +3940:hb_ot_layout_feature_with_variations_get_lookups +3941:hb_ot_layout_collect_features_map +3942:hb_ot_font_set_funcs +3943:hb_lazy_loader_t::do_destroy\28hb_draw_funcs_t*\29 +3944:hb_lazy_loader_t\2c\20hb_face_t\2c\2038u\2c\20OT::sbix_accelerator_t>::create\28hb_face_t*\29 +3945:hb_lazy_loader_t\2c\20hb_face_t\2c\207u\2c\20OT::post_accelerator_t>::do_destroy\28OT::post_accelerator_t*\29 +3946:hb_lazy_loader_t\2c\20hb_face_t\2c\2017u\2c\20OT::cff2_accelerator_t>::do_destroy\28OT::cff2_accelerator_t*\29 +3947:hb_lazy_loader_t\2c\20hb_face_t\2c\2037u\2c\20OT::CBDT_accelerator_t>::do_destroy\28OT::CBDT_accelerator_t*\29 +3948:hb_language_matches +3949:hb_indic_get_categories\28unsigned\20int\29 +3950:hb_hashmap_t::fetch_item\28hb_serialize_context_t::object_t\20const*\20const&\2c\20unsigned\20int\29\20const +3951:hb_hashmap_t::alloc\28unsigned\20int\29 +3952:hb_font_t::get_glyph_v_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +3953:hb_font_t::get_glyph_contour_point_for_origin\28unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20int*\2c\20int*\29 +3954:hb_font_set_variations +3955:hb_font_set_funcs +3956:hb_font_get_variation_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +3957:hb_font_get_glyph_h_advance +3958:hb_font_get_glyph_extents +3959:hb_font_get_font_h_extents_nil\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +3960:hb_font_funcs_set_variation_glyph_func +3961:hb_font_funcs_set_nominal_glyphs_func +3962:hb_font_funcs_set_nominal_glyph_func +3963:hb_font_funcs_set_glyph_h_advances_func +3964:hb_font_funcs_set_glyph_extents_func +3965:hb_font_funcs_create +3966:hb_draw_move_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +3967:hb_draw_funcs_set_quadratic_to_func +3968:hb_draw_funcs_set_move_to_func +3969:hb_draw_funcs_set_line_to_func +3970:hb_draw_funcs_set_cubic_to_func +3971:hb_draw_funcs_create +3972:hb_draw_extents_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +3973:hb_buffer_t::sort\28unsigned\20int\2c\20unsigned\20int\2c\20int\20\28*\29\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29\29 +3974:hb_buffer_t::output_info\28hb_glyph_info_t\20const&\29 +3975:hb_buffer_t::message_impl\28hb_font_t*\2c\20char\20const*\2c\20void*\29 +3976:hb_buffer_t::leave\28\29 +3977:hb_buffer_t::delete_glyphs_inplace\28bool\20\28*\29\28hb_glyph_info_t\20const*\29\29 +3978:hb_buffer_t::clear_positions\28\29 +3979:hb_buffer_set_length +3980:hb_buffer_get_glyph_positions +3981:hb_buffer_diff +3982:hb_buffer_create +3983:hb_buffer_clear_contents +3984:hb_buffer_add_utf8 +3985:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +3986:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +3987:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3988:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3989:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3990:hb_blob_t*\20hb_data_wrapper_t::call_create>\28\29\20const +3991:hb_aat_layout_remove_deleted_glyphs\28hb_buffer_t*\29 +3992:hair_cubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3993:getint +3994:get_win_string +3995:get_dst_swizzle_and_store\28GrColorType\2c\20SkRasterPipelineOp*\2c\20LumMode*\2c\20bool*\2c\20bool*\29 +3996:get_driver_and_version\28GrGLStandard\2c\20GrGLVendor\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +3997:gen_key\28skgpu::KeyBuilder*\2c\20GrProgramInfo\20const&\2c\20GrCaps\20const&\29 +3998:gen_fp_key\28GrFragmentProcessor\20const&\2c\20GrCaps\20const&\2c\20skgpu::KeyBuilder*\29 +3999:gather_uniforms_and_check_for_main\28SkSL::Program\20const&\2c\20std::__2::vector>*\2c\20std::__2::vector>*\2c\20SkRuntimeEffect::Uniform::Flags\2c\20unsigned\20long*\29 +4000:fwrite +4001:ft_var_to_normalized +4002:ft_var_load_item_variation_store +4003:ft_var_load_hvvar +4004:ft_var_load_avar +4005:ft_var_get_value_pointer +4006:ft_var_apply_tuple +4007:ft_validator_init +4008:ft_mem_strcpyn +4009:ft_hash_num_lookup +4010:ft_glyphslot_set_bitmap +4011:ft_glyphslot_preset_bitmap +4012:ft_corner_orientation +4013:ft_corner_is_flat +4014:frexp +4015:fread +4016:fp_force_eval +4017:fp_barrier_15688 +4018:fopen +4019:fold_opacity_layer_color_to_paint\28SkPaint\20const*\2c\20bool\2c\20SkPaint*\29 +4020:fmodl +4021:float\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +4022:fill_shadow_rec\28SkPath\20const&\2c\20SkPoint3\20const&\2c\20SkPoint3\20const&\2c\20float\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkDrawShadowRec*\29 +4023:fill_inverse_cmap +4024:fileno +4025:examine_app0 +4026:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29\2c\20SkCanvas*\2c\20SkPath*\2c\20SkClipOp\2c\20bool\29 +4027:emscripten::internal::MethodInvoker\20\28SkAnimatedImage::*\29\28\29\2c\20sk_sp\2c\20SkAnimatedImage*>::invoke\28sk_sp\20\28SkAnimatedImage::*\20const&\29\28\29\2c\20SkAnimatedImage*\29 +4028:emscripten::internal::Invoker\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20sk_sp\29\2c\20sk_sp*\2c\20sk_sp*\29 +4029:emscripten::internal::Invoker\2c\20SkBlendMode\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29\2c\20SkBlendMode\2c\20sk_sp*\2c\20sk_sp*\29 +4030:emscripten::internal::Invoker\2c\20SkBlendMode>::invoke\28sk_sp\20\28*\29\28SkBlendMode\29\2c\20SkBlendMode\29 +4031:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\29 +4032:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\29 +4033:emscripten::internal::FunctionInvoker\29\2c\20void\2c\20SkPaint&\2c\20unsigned\20long\2c\20sk_sp>::invoke\28void\20\28**\29\28SkPaint&\2c\20unsigned\20long\2c\20sk_sp\29\2c\20SkPaint*\2c\20unsigned\20long\2c\20sk_sp*\29 +4034:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29\2c\20SkCanvas*\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +4035:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +4036:emscripten::internal::FunctionInvoker\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +4037:emscripten::internal::FunctionInvoker\20\28*\29\28SkCanvas&\2c\20SimpleImageInfo\29\2c\20sk_sp\2c\20SkCanvas&\2c\20SimpleImageInfo>::invoke\28sk_sp\20\28**\29\28SkCanvas&\2c\20SimpleImageInfo\29\2c\20SkCanvas*\2c\20SimpleImageInfo*\29 +4038:emscripten::internal::FunctionInvoker::invoke\28int\20\28**\29\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SkFont*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +4039:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20SkPath\20const&\2c\20SkPathOp\29\2c\20SkPath*\2c\20SkPath*\2c\20SkPathOp\29 +4040:embind_init_builtin\28\29 +4041:embind_init_Skia\28\29 +4042:embind_init_Paragraph\28\29::$_0::__invoke\28SimpleParagraphStyle\2c\20sk_sp\29 +4043:embind_init_Paragraph\28\29 +4044:embind_init_ParagraphGen\28\29 +4045:edge_line_needs_recursion\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4046:draw_nine\28SkMask\20const&\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\2c\20bool\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +4047:dquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4048:dquad_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4049:double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +4050:dline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4051:dline_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4052:deflate_stored +4053:decompose_current_character\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\29 +4054:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::Make\28SkArenaAlloc*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4055:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&\2c\20skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathCurveTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4056:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4057:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker\2c\20int&>\28int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4058:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkShaderBase\20const&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTransformShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4059:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4060:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29>\28GrThreadSafeCache::Entry&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4061:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29::'lambda'\28void*\29>\28GrResourceAllocator::Register&&\29 +4062:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrRRectShadowGeoProc::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4063:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28GrQuadEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4064:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrPipeline::InitArgs&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29::'lambda'\28void*\29>\28GrPipeline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4065:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldA8TextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20float\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4066:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28DefaultGeoProc::Make\28SkArenaAlloc*\2c\20unsigned\20int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29 +4067:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28CircleGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +4068:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>>::__generic_construct\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__ctor\2c\20std::__2::unique_ptr>>>&\2c\20std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&>\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&\29 +4069:decltype\28_dispatch\28fp\2c\20\28hb_priority<16u>\29\28\29\29\29\20hb_sanitize_context_t::dispatch\28OT::DeltaSetIndexMap\20const&\29 +4070:dcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4071:dcubic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4072:dconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +4073:dconic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +4074:data_destroy_arabic\28void*\29 +4075:data_create_arabic\28hb_ot_shape_plan_t\20const*\29 +4076:cycle +4077:cubic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4078:cubic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4079:create_colorindex +4080:copysignl +4081:copy_bitmap_subset\28SkBitmap\20const&\2c\20SkIRect\20const&\29 +4082:conic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4083:conic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +4084:compute_pos_tan\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +4085:compute_intersection\28OffsetSegment\20const&\2c\20OffsetSegment\20const&\2c\20SkPoint*\2c\20float*\2c\20float*\29 +4086:compress_block +4087:compose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +4088:compare_offsets +4089:clipHandlesSprite\28SkRasterClip\20const&\2c\20int\2c\20int\2c\20SkPixmap\20const&\29 +4090:clamp\28SkPoint\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Comparator\20const&\29 +4091:checkint +4092:check_inverse_on_empty_return\28SkRegion*\2c\20SkPath\20const&\2c\20SkRegion\20const&\29 +4093:char*\20std::__2::copy_n\5babi:nn180100\5d\28char\20const*\2c\20unsigned\20long\2c\20char*\29 +4094:char*\20std::__2::copy\5babi:nn180100\5d\2c\20char*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20char*\29 +4095:char*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20std::__2::__element_count\29 +4096:cff_vstore_done +4097:cff_subfont_load +4098:cff_subfont_done +4099:cff_size_select +4100:cff_parser_run +4101:cff_make_private_dict +4102:cff_load_private_dict +4103:cff_index_get_name +4104:cff_get_kerning +4105:cff_blend_build_vector +4106:cf2_getSeacComponent +4107:cf2_computeDarkening +4108:cf2_arrstack_push +4109:cbrt +4110:build_ycc_rgb_table +4111:bracketProcessChar\28BracketData*\2c\20int\29 +4112:bool\20std::__2::operator==\5babi:nn180100\5d\28std::__2::unique_ptr\20const&\2c\20std::nullptr_t\29 +4113:bool\20std::__2::operator!=\5babi:ne180100\5d\28std::__2::variant\20const&\2c\20std::__2::variant\20const&\29 +4114:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +4115:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::Entry*\2c\20\28anonymous\20namespace\29::EntryComparator&\29 +4116:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +4117:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +4118:bool\20is_parallel\28SkDLine\20const&\2c\20SkTCurve\20const&\29 +4119:bool\20hb_hashmap_t::set_with_hash\28hb_serialize_context_t::object_t*&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool\29 +4120:bool\20apply_string\28OT::hb_ot_apply_context_t*\2c\20GSUBProxy::Lookup\20const&\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\29 +4121:bool\20OT::hb_accelerate_subtables_context_t::cache_func_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\2c\20bool\29 +4122:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4123:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4124:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4125:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4126:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4127:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4128:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4129:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4130:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4131:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4132:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4133:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4134:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4135:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4136:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4137:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4138:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4139:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +4140:bool\20OT::OffsetTo\2c\20true>::serialize_serialize\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&>\28hb_serialize_context_t*\2c\20hb_map_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&\29 +4141:bool\20GrTTopoSort_Visit\28GrRenderTask*\2c\20unsigned\20int*\29 +4142:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +4143:bits_to_runs\28SkBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\2c\20long\2c\20unsigned\20char\29 +4144:barycentric_coords\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +4145:auto\20std::__2::__unwrap_range\5babi:nn180100\5d\2c\20std::__2::__wrap_iter>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\29 +4146:atanf +4147:apply_forward\28OT::hb_ot_apply_context_t*\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\2c\20unsigned\20int\29 +4148:apply_alpha_and_colorfilter\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20SkPaint\20const&\29 +4149:append_multitexture_lookup\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20int\2c\20GrGLSLVarying\20const&\2c\20char\20const*\2c\20char\20const*\29 +4150:append_color_output\28PorterDuffXferProcessor\20const&\2c\20GrGLSLXPFragmentBuilder*\2c\20skgpu::BlendFormula::OutputType\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +4151:af_loader_compute_darkening +4152:af_latin_metrics_scale_dim +4153:af_latin_hints_detect_features +4154:af_latin_hint_edges +4155:af_hint_normal_stem +4156:af_cjk_metrics_scale_dim +4157:af_cjk_metrics_scale +4158:af_cjk_metrics_init_widths +4159:af_cjk_hints_init +4160:af_cjk_hints_detect_features +4161:af_cjk_hints_compute_blue_edges +4162:af_cjk_hints_apply +4163:af_cjk_hint_edges +4164:af_cjk_get_standard_widths +4165:af_axis_hints_new_edge +4166:adler32 +4167:a_ctz_32 +4168:_iup_worker_interpolate +4169:_hb_preprocess_text_vowel_constraints\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +4170:_hb_ot_shape +4171:_hb_options_init\28\29 +4172:_hb_font_create\28hb_face_t*\29 +4173:_hb_fallback_shape +4174:_glyf_get_advance_with_var_unscaled\28hb_font_t*\2c\20unsigned\20int\2c\20bool\29 +4175:__vfprintf_internal +4176:__trunctfsf2 +4177:__tan +4178:__strftime_l +4179:__rem_pio2_large +4180:__overflow +4181:__nl_langinfo_l +4182:__newlocale +4183:__math_xflowf +4184:__math_invalidf +4185:__loc_is_allocated +4186:__isxdigit_l +4187:__isdigit_l +4188:__getf2 +4189:__get_locale +4190:__ftello_unlocked +4191:__fseeko_unlocked +4192:__floatscan +4193:__expo2 +4194:__divtf3 +4195:__cxxabiv1::__base_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +4196:_ZZN19GrGeometryProcessor11ProgramImpl17collectTransformsEP19GrGLSLVertexBuilderP20GrGLSLVaryingHandlerP20GrGLSLUniformHandler12GrShaderTypeRK11GrShaderVarSA_RK10GrPipelineEN3$_0clISE_EEvRT_RK19GrFragmentProcessorbPSJ_iNS0_9BaseCoordE +4197:\28anonymous\20namespace\29::write_text_tag\28char\20const*\29 +4198:\28anonymous\20namespace\29::write_mAB_or_mBA_tag\28unsigned\20int\2c\20skcms_Curve\20const*\2c\20skcms_Curve\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20skcms_Curve\20const*\2c\20skcms_Matrix3x4\20const*\29 +4199:\28anonymous\20namespace\29::set_uv_quad\28SkPoint\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +4200:\28anonymous\20namespace\29::safe_to_ignore_subset_rect\28GrAAType\2c\20SkFilterMode\2c\20DrawQuad\20const&\2c\20SkRect\20const&\29 +4201:\28anonymous\20namespace\29::morphology_pass\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20\28anonymous\20namespace\29::MorphType\2c\20\28anonymous\20namespace\29::MorphDirection\2c\20int\29 +4202:\28anonymous\20namespace\29::make_non_convex_fill_op\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20skgpu::ganesh::FillPathFlags\2c\20GrAAType\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\29 +4203:\28anonymous\20namespace\29::is_newer_better\28SkData*\2c\20SkData*\29 +4204:\28anonymous\20namespace\29::get_glyph_run_intercepts\28sktext::GlyphRun\20const&\2c\20SkPaint\20const&\2c\20float\20const*\2c\20float*\2c\20int*\29 +4205:\28anonymous\20namespace\29::get_cicp_trfn\28skcms_TransferFunction\20const&\29 +4206:\28anonymous\20namespace\29::get_cicp_primaries\28skcms_Matrix3x3\20const&\29 +4207:\28anonymous\20namespace\29::draw_to_sw_mask\28GrSWMaskHelper*\2c\20skgpu::ganesh::ClipStack::Element\20const&\2c\20bool\29 +4208:\28anonymous\20namespace\29::draw_tiled_image\28SkCanvas*\2c\20std::__2::function\20\28SkIRect\29>\2c\20SkISize\2c\20int\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkSamplingOptions\29 +4209:\28anonymous\20namespace\29::determine_clipped_src_rect\28SkIRect\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkISize\20const&\2c\20SkRect\20const*\29 +4210:\28anonymous\20namespace\29::create_hb_face\28SkTypeface\20const&\29::$_0::__invoke\28void*\29 +4211:\28anonymous\20namespace\29::copyFTBitmap\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\29 +4212:\28anonymous\20namespace\29::colrv1_start_glyph\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20unsigned\20short\2c\20FT_Color_Root_Transform_\2c\20skia_private::THashSet*\29 +4213:\28anonymous\20namespace\29::colrv1_draw_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\29 +4214:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29 +4215:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29 +4216:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29 +4217:\28anonymous\20namespace\29::TriangulatingPathOp::TriangulatingPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +4218:\28anonymous\20namespace\29::TriangulatingPathOp::Triangulate\28GrEagerVertexAllocator*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool*\29 +4219:\28anonymous\20namespace\29::TriangulatingPathOp::CreateKey\28skgpu::UniqueKey*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\29 +4220:\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +4221:\28anonymous\20namespace\29::TextureOpImpl::propagateCoverageAAThroughoutChain\28\29 +4222:\28anonymous\20namespace\29::TextureOpImpl::characterize\28\28anonymous\20namespace\29::TextureOpImpl::Desc*\29\20const +4223:\28anonymous\20namespace\29::TextureOpImpl::appendQuad\28DrawQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\29 +4224:\28anonymous\20namespace\29::TextureOpImpl::Make\28GrRecordingContext*\2c\20GrTextureSetEntry*\2c\20int\2c\20int\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20GrAAType\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +4225:\28anonymous\20namespace\29::TextureOpImpl::FillInVertices\28GrCaps\20const&\2c\20\28anonymous\20namespace\29::TextureOpImpl*\2c\20\28anonymous\20namespace\29::TextureOpImpl::Desc*\2c\20char*\29 +4226:\28anonymous\20namespace\29::SpotVerticesFactory::makeVertices\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint*\29\20const +4227:\28anonymous\20namespace\29::SkImageImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +4228:\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +4229:\28anonymous\20namespace\29::RunIteratorQueue::advanceRuns\28\29 +4230:\28anonymous\20namespace\29::RPBlender::RPBlender\28SkColorType\2c\20SkColorType\2c\20SkAlphaType\2c\20bool\29 +4231:\28anonymous\20namespace\29::Pass::blur\28int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +4232:\28anonymous\20namespace\29::MipLevelHelper::allocAndInit\28SkArenaAlloc*\2c\20SkSamplingOptions\20const&\2c\20SkTileMode\2c\20SkTileMode\29 +4233:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29 +4234:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20sk_sp\2c\20GrPrimitiveType\20const*\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +4235:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMesh\20const&\2c\20skia_private::TArray>\2c\20true>\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +4236:\28anonymous\20namespace\29::MeshOp::Mesh::Mesh\28SkMesh\20const&\29 +4237:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29 +4238:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29 +4239:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineStruct\28char\20const*\29 +4240:\28anonymous\20namespace\29::FillRectOpImpl::tessellate\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29\20const +4241:\28anonymous\20namespace\29::FillRectOpImpl::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +4242:\28anonymous\20namespace\29::FillRectOpImpl::FillRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +4243:\28anonymous\20namespace\29::EllipticalRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRRect\20const&\29 +4244:\28anonymous\20namespace\29::DrawAtlasOpImpl::DrawAtlasOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrAAType\2c\20int\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\29 +4245:\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29_12515 +4246:\28anonymous\20namespace\29::DirectMaskSubRun::~DirectMaskSubRun\28\29 +4247:\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +4248:\28anonymous\20namespace\29::DirectMaskSubRun::glyphCount\28\29\20const +4249:\28anonymous\20namespace\29::DefaultPathOp::programInfo\28\29 +4250:\28anonymous\20namespace\29::DefaultPathOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +4251:\28anonymous\20namespace\29::DefaultPathOp::DefaultPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +4252:\28anonymous\20namespace\29::ClipGeometry\20\28anonymous\20namespace\29::get_clip_geometry\28skgpu::ganesh::ClipStack::SaveRecord\20const&\2c\20skgpu::ganesh::ClipStack::Draw\20const&\29 +4253:\28anonymous\20namespace\29::CircularRRectEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +4254:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29 +4255:\28anonymous\20namespace\29::CachedTessellations::CachedTessellations\28\29 +4256:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29 +4257:\28anonymous\20namespace\29::AAHairlineOp::AAHairlineOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIRect\2c\20float\2c\20GrUserStencilSettings\20const*\29 +4258:WebPResetDecParams +4259:WebPRescalerGetScaledDimensions +4260:WebPMultRows +4261:WebPMultARGBRows +4262:WebPIoInitFromOptions +4263:WebPInitUpsamplers +4264:WebPFlipBuffer +4265:WebPDemuxGetChunk +4266:WebPCopyDecBufferPixels +4267:WebPAllocateDecBuffer +4268:WebGLTextureImageGenerator::~WebGLTextureImageGenerator\28\29 +4269:VP8RemapBitReader +4270:VP8LHuffmanTablesAllocate +4271:VP8LDspInit +4272:VP8LConvertFromBGRA +4273:VP8LColorCacheInit +4274:VP8LColorCacheCopy +4275:VP8LBuildHuffmanTable +4276:VP8LBitReaderSetBuffer +4277:VP8InitScanline +4278:VP8GetInfo +4279:VP8BitReaderSetBuffer +4280:Update_Max +4281:TransformOne_C +4282:TT_Set_Named_Instance +4283:TT_Hint_Glyph +4284:StoreFrame +4285:SortContourList\28SkOpContourHead**\2c\20bool\2c\20bool\29 +4286:SkYUVAPixmapInfo::isSupported\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\29\20const +4287:SkWuffsCodec::seekFrame\28int\29 +4288:SkWuffsCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +4289:SkWuffsCodec::onIncrementalDecodeTwoPass\28\29 +4290:SkWuffsCodec::decodeFrameConfig\28\29 +4291:SkWriter32::writeString\28char\20const*\2c\20unsigned\20long\29 +4292:SkWriteICCProfile\28skcms_ICCProfile\20const*\2c\20char\20const*\29 +4293:SkWebpDecoder::IsWebp\28void\20const*\2c\20unsigned\20long\29 +4294:SkWebpCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29 +4295:SkWbmpDecoder::IsWbmp\28void\20const*\2c\20unsigned\20long\29 +4296:SkWbmpCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29 +4297:SkWStream::SizeOfPackedUInt\28unsigned\20long\29 +4298:SkWBuffer::padToAlign4\28\29 +4299:SkVertices::Builder::indices\28\29 +4300:SkUnicode::convertUtf16ToUtf8\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4301:SkUTF::UTF16ToUTF8\28char*\2c\20int\2c\20unsigned\20short\20const*\2c\20unsigned\20long\29 +4302:SkTypeface_FreeType::FaceRec::Make\28SkTypeface_FreeType\20const*\29 +4303:SkTypeface_Custom::onGetFamilyName\28SkString*\29\20const +4304:SkTypeface::textToGlyphs\28void\20const*\2c\20unsigned\20long\2c\20SkTextEncoding\2c\20unsigned\20short*\2c\20int\29\20const +4305:SkTypeface::serialize\28SkWStream*\2c\20SkTypeface::SerializeBehavior\29\20const +4306:SkTypeface::openStream\28int*\29\20const +4307:SkTypeface::onGetFixedPitch\28\29\20const +4308:SkTypeface::getVariationDesignPosition\28SkFontArguments::VariationPosition::Coordinate*\2c\20int\29\20const +4309:SkTypeface::getFamilyName\28SkString*\29\20const +4310:SkTransformShader::update\28SkMatrix\20const&\29 +4311:SkTransformShader::SkTransformShader\28SkShaderBase\20const&\2c\20bool\29 +4312:SkTiff::ImageFileDirectory::getEntryRawData\28unsigned\20short\2c\20unsigned\20short*\2c\20unsigned\20short*\2c\20unsigned\20int*\2c\20unsigned\20char\20const**\2c\20unsigned\20long*\29\20const +4313:SkTextBlobBuilder::allocRunPos\28SkFont\20const&\2c\20int\2c\20SkRect\20const*\29 +4314:SkTextBlob::getIntercepts\28float\20const*\2c\20float*\2c\20SkPaint\20const*\29\20const +4315:SkTextBlob::RunRecord::StorageSize\28unsigned\20int\2c\20unsigned\20int\2c\20SkTextBlob::GlyphPositioning\2c\20SkSafeMath*\29 +4316:SkTextBlob::MakeFromText\28void\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20SkTextEncoding\29 +4317:SkTextBlob::MakeFromRSXform\28void\20const*\2c\20unsigned\20long\2c\20SkRSXform\20const*\2c\20SkFont\20const&\2c\20SkTextEncoding\29 +4318:SkTextBlob::Iter::experimentalNext\28SkTextBlob::Iter::ExperimentalRun*\29 +4319:SkTextBlob::Iter::Iter\28SkTextBlob\20const&\29 +4320:SkTaskGroup::wait\28\29 +4321:SkTaskGroup::add\28std::__2::function\29 +4322:SkTSpan::onlyEndPointsInCommon\28SkTSpan\20const*\2c\20bool*\2c\20bool*\2c\20bool*\29 +4323:SkTSpan::linearIntersects\28SkTCurve\20const&\29\20const +4324:SkTSect::removeAllBut\28SkTSpan\20const*\2c\20SkTSpan*\2c\20SkTSect*\29 +4325:SkTSect::intersects\28SkTSpan*\2c\20SkTSect*\2c\20SkTSpan*\2c\20int*\29 +4326:SkTSect::deleteEmptySpans\28\29 +4327:SkTSect::addSplitAt\28SkTSpan*\2c\20double\29 +4328:SkTSect::addForPerp\28SkTSpan*\2c\20double\29 +4329:SkTSect::EndsEqual\28SkTSect\20const*\2c\20SkTSect\20const*\2c\20SkIntersections*\29 +4330:SkTMultiMap::~SkTMultiMap\28\29 +4331:SkTMaskGamma<3\2c\203\2c\203>::SkTMaskGamma\28float\2c\20float\29 +4332:SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::find\28SkImageFilterCacheKey\20const&\29\20const +4333:SkTDStorage::calculateSizeOrDie\28int\29::$_1::operator\28\29\28\29\20const +4334:SkTDStorage::SkTDStorage\28SkTDStorage&&\29 +4335:SkTCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +4336:SkTConic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +4337:SkTConic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +4338:SkTConic::controlsInside\28\29\20const +4339:SkTConic::collapsed\28\29\20const +4340:SkTBlockList::reset\28\29 +4341:SkTBlockList::reset\28\29 +4342:SkTBlockList::push_back\28GrGLProgramDataManager::GLUniformInfo\20const&\29 +4343:SkSwizzler::MakeSimple\28int\2c\20SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20SkIRect\20const*\29 +4344:SkSurfaces::WrapPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkSurfaceProps\20const*\29 +4345:SkSurface_Base::outstandingImageSnapshot\28\29\20const +4346:SkSurface_Base::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +4347:SkSurface_Base::onCapabilities\28\29 +4348:SkStrokeRec::setHairlineStyle\28\29 +4349:SkStrokeRec::SkStrokeRec\28SkPaint\20const&\2c\20SkPaint::Style\2c\20float\29 +4350:SkStrokeRec::GetInflationRadius\28SkPaint::Join\2c\20float\2c\20SkPaint::Cap\2c\20float\29 +4351:SkString::insertHex\28unsigned\20long\2c\20unsigned\20int\2c\20int\29 +4352:SkString::appendVAList\28char\20const*\2c\20void*\29 +4353:SkString::SkString\28std::__2::basic_string_view>\29 +4354:SkString*\20std::__2::vector>::__emplace_back_slow_path\28char\20const*&\29 +4355:SkStrikeSpec::SkStrikeSpec\28SkStrikeSpec\20const&\29 +4356:SkStrikeSpec::ShouldDrawAsPath\28SkPaint\20const&\2c\20SkFont\20const&\2c\20SkMatrix\20const&\29 +4357:SkStrike::~SkStrike\28\29 +4358:SkStream::readS8\28signed\20char*\29 +4359:SkStream::readS16\28short*\29 +4360:SkStrSplit\28char\20const*\2c\20char\20const*\2c\20SkStrSplitMode\2c\20skia_private::TArray*\29 +4361:SkStrAppendS32\28char*\2c\20int\29 +4362:SkSpriteBlitter_Memcpy::~SkSpriteBlitter_Memcpy\28\29 +4363:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +4364:SkSpecialImages::AsBitmap\28SkSpecialImage\20const*\2c\20SkBitmap*\29 +4365:SkSharedMutex::releaseShared\28\29 +4366:SkShapers::unicode::BidiRunIterator\28sk_sp\2c\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20char\29 +4367:SkShapers::HB::ScriptRunIterator\28char\20const*\2c\20unsigned\20long\29 +4368:SkShaper::MakeStdLanguageRunIterator\28char\20const*\2c\20unsigned\20long\29 +4369:SkShaders::MatrixRec::concat\28SkMatrix\20const&\29\20const +4370:SkShaders::Blend\28sk_sp\2c\20sk_sp\2c\20sk_sp\29 +4371:SkShaderUtils::VisitLineByLine\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::function\20const&\29 +4372:SkShaderUtils::PrettyPrint\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4373:SkShaderUtils::GLSLPrettyPrint::parseUntil\28char\20const*\29 +4374:SkShaderBlurAlgorithm::renderBlur\28SkRuntimeEffectBuilder*\2c\20SkFilterMode\2c\20SkISize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +4375:SkShaderBlurAlgorithm::evalBlur1D\28float\2c\20int\2c\20SkV2\2c\20sk_sp\2c\20SkIRect\2c\20SkTileMode\2c\20SkIRect\29\20const +4376:SkShaderBlurAlgorithm::Compute2DBlurOffsets\28SkISize\2c\20std::__2::array&\29 +4377:SkShaderBlurAlgorithm::Compute2DBlurKernel\28SkSize\2c\20SkISize\2c\20std::__2::array&\29 +4378:SkShaderBlurAlgorithm::Compute1DBlurLinearKernel\28float\2c\20int\2c\20std::__2::array&\29 +4379:SkShaderBase::getFlattenableType\28\29\20const +4380:SkShaderBase::asLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +4381:SkShader::makeWithColorFilter\28sk_sp\29\20const +4382:SkScan::PathRequiresTiling\28SkIRect\20const&\29 +4383:SkScan::HairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +4384:SkScan::AntiFrameRect\28SkRect\20const&\2c\20SkPoint\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +4385:SkScan::AntiFillXRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +4386:SkScan::AntiFillRect\28SkRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +4387:SkScan::AAAFillPath\28SkPath\20const&\2c\20SkBlitter*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +4388:SkScalerContext_FreeType::updateGlyphBoundsIfSubpixel\28SkGlyph\20const&\2c\20SkRect*\2c\20bool\29 +4389:SkScalerContext_FreeType::shouldSubpixelBitmap\28SkGlyph\20const&\2c\20SkMatrix\20const&\29 +4390:SkScalerContextRec::useStrokeForFakeBold\28\29 +4391:SkScalerContextRec::getSingleMatrix\28SkMatrix*\29\20const +4392:SkScalerContextFTUtils::drawCOLRv1Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +4393:SkScalerContextFTUtils::drawCOLRv0Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +4394:SkScalerContext::internalMakeGlyph\28SkPackedGlyphID\2c\20SkMask::Format\2c\20SkArenaAlloc*\29 +4395:SkScalerContext::internalGetPath\28SkGlyph&\2c\20SkArenaAlloc*\29 +4396:SkScalerContext::getFontMetrics\28SkFontMetrics*\29 +4397:SkScalerContext::SkScalerContext\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +4398:SkScalerContext::PreprocessRec\28SkTypeface\20const&\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const&\29 +4399:SkScalerContext::MakeRecAndEffects\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\2c\20SkScalerContextRec*\2c\20SkScalerContextEffects*\29 +4400:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +4401:SkScalerContext::GetMaskPreBlend\28SkScalerContextRec\20const&\29 +4402:SkScalerContext::AutoDescriptorGivenRecAndEffects\28SkScalerContextRec\20const&\2c\20SkScalerContextEffects\20const&\2c\20SkAutoDescriptor*\29 +4403:SkSampledCodec::sampledDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const&\29 +4404:SkSampledCodec::accountForNativeScaling\28int*\2c\20int*\29\20const +4405:SkSampledCodec::SkSampledCodec\28SkCodec*\29 +4406:SkSL::zero_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\29 +4407:SkSL::type_to_sksltype\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSLType*\29 +4408:SkSL::stoi\28std::__2::basic_string_view>\2c\20long\20long*\29 +4409:SkSL::splat_scalar\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +4410:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_2::operator\28\29\28int\29\20const +4411:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_1::operator\28\29\28int\29\20const +4412:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_0::operator\28\29\28int\29\20const +4413:SkSL::negate_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +4414:SkSL::make_reciprocal_expression\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29 +4415:SkSL::index_out_of_range\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20long\20long\2c\20SkSL::Expression\20const&\29 +4416:SkSL::get_struct_definitions_from_module\28SkSL::Program&\2c\20SkSL::Module\20const&\2c\20std::__2::vector>*\29 +4417:SkSL::find_existing_declaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20SkSL::IntrinsicKind\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray>\2c\20true>&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration**\29::$_0::operator\28\29\28\29\20const +4418:SkSL::extract_matrix\28SkSL::Expression\20const*\2c\20float*\29 +4419:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +4420:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_4::operator\28\29\28int\29\20const +4421:SkSL::\28anonymous\20namespace\29::check_valid_uniform_type\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Context\20const&\2c\20bool\29::$_0::operator\28\29\28\29\20const +4422:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +4423:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +4424:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +4425:SkSL::VariableReference::setRefKind\28SkSL::VariableRefKind\29 +4426:SkSL::Variable::setVarDeclaration\28SkSL::VarDeclaration*\29 +4427:SkSL::Variable::setGlobalVarDeclaration\28SkSL::GlobalVarDeclaration*\29 +4428:SkSL::Variable::globalVarDeclaration\28\29\20const +4429:SkSL::Variable::Make\28SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20std::__2::basic_string_view>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20bool\2c\20SkSL::VariableStorage\29 +4430:SkSL::Variable::MakeScratchVariable\28SkSL::Context\20const&\2c\20SkSL::Mangler&\2c\20std::__2::basic_string_view>\2c\20SkSL::Type\20const*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>\29 +4431:SkSL::VarDeclaration::Make\28SkSL::Context\20const&\2c\20SkSL::Variable*\2c\20SkSL::Type\20const*\2c\20int\2c\20std::__2::unique_ptr>\29 +4432:SkSL::VarDeclaration::ErrorCheck\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Type\20const*\2c\20SkSL::VariableStorage\29 +4433:SkSL::TypeReference::description\28SkSL::OperatorPrecedence\29\20const +4434:SkSL::TypeReference::VerifyType\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Position\29 +4435:SkSL::TypeReference::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\29 +4436:SkSL::Type::MakeStructType\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20bool\29 +4437:SkSL::Type::MakeLiteralType\28char\20const*\2c\20SkSL::Type\20const&\2c\20signed\20char\29 +4438:SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::addDeclaringElement\28SkSL::ProgramElement\20const*\29 +4439:SkSL::Transform::EliminateDeadFunctions\28SkSL::Program&\29 +4440:SkSL::ToGLSL\28SkSL::Program&\2c\20SkSL::ShaderCaps\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\29 +4441:SkSL::TernaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +4442:SkSL::SymbolTable::insertNewParent\28\29 +4443:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Symbol*\29 +4444:SkSL::Swizzle::MaskString\28skia_private::FixedArray<4\2c\20signed\20char>\20const&\29 +4445:SkSL::SwitchStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +4446:SkSL::SwitchCase::Make\28SkSL::Position\2c\20long\20long\2c\20std::__2::unique_ptr>\29 +4447:SkSL::SwitchCase::MakeDefault\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +4448:SkSL::StructType::StructType\28SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20int\2c\20bool\2c\20bool\29 +4449:SkSL::String::vappendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20void*\29 +4450:SkSL::SingleArgumentConstructor::argumentSpan\28\29 +4451:SkSL::RP::stack_usage\28SkSL::RP::Instruction\20const&\29 +4452:SkSL::RP::UnownedLValueSlice::isWritable\28\29\20const +4453:SkSL::RP::UnownedLValueSlice::dynamicSlotRange\28\29 +4454:SkSL::RP::Program::~Program\28\29 +4455:SkSL::RP::LValue::swizzle\28\29 +4456:SkSL::RP::Generator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\29 +4457:SkSL::RP::Generator::writeFunction\28SkSL::IRNode\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSpan>\20const>\29 +4458:SkSL::RP::Generator::storeImmutableValueToSlots\28skia_private::TArray\20const&\2c\20SkSL::RP::SlotRange\29 +4459:SkSL::RP::Generator::pushVariableReferencePartial\28SkSL::VariableReference\20const&\2c\20SkSL::RP::SlotRange\29 +4460:SkSL::RP::Generator::pushPrefixExpression\28SkSL::Operator\2c\20SkSL::Expression\20const&\29 +4461:SkSL::RP::Generator::pushIntrinsic\28SkSL::IntrinsicKind\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +4462:SkSL::RP::Generator::pushImmutableData\28SkSL::Expression\20const&\29 +4463:SkSL::RP::Generator::pushAbsFloatIntrinsic\28int\29 +4464:SkSL::RP::Generator::getImmutableValueForExpression\28SkSL::Expression\20const&\2c\20skia_private::TArray*\29 +4465:SkSL::RP::Generator::foldWithMultiOp\28SkSL::RP::BuilderOp\2c\20int\29 +4466:SkSL::RP::Generator::findPreexistingImmutableData\28skia_private::TArray\20const&\29 +4467:SkSL::RP::Builder::push_slots_or_immutable_indirect\28SkSL::RP::SlotRange\2c\20int\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::BuilderOp\29 +4468:SkSL::RP::Builder::push_condition_mask\28\29 +4469:SkSL::RP::Builder::pad_stack\28int\29 +4470:SkSL::RP::Builder::copy_stack_to_slots\28SkSL::RP::SlotRange\2c\20int\29 +4471:SkSL::RP::Builder::branch_if_any_lanes_active\28int\29 +4472:SkSL::ProgramVisitor::visit\28SkSL::Program\20const&\29 +4473:SkSL::ProgramUsage::remove\28SkSL::Expression\20const*\29 +4474:SkSL::ProgramUsage::add\28SkSL::Statement\20const*\29 +4475:SkSL::ProgramUsage::add\28SkSL::Expression\20const*\29 +4476:SkSL::Pool::attachToThread\28\29 +4477:SkSL::PipelineStage::PipelineStageCodeGenerator::functionName\28SkSL::FunctionDeclaration\20const&\2c\20int\29 +4478:SkSL::PipelineStage::PipelineStageCodeGenerator::functionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +4479:SkSL::PipelineStage::PipelineStageCodeGenerator::forEachSpecialization\28SkSL::FunctionDeclaration\20const&\2c\20std::__2::function\20const&\29 +4480:SkSL::Parser::~Parser\28\29 +4481:SkSL::Parser::varDeclarations\28\29 +4482:SkSL::Parser::varDeclarationsOrExpressionStatement\28\29 +4483:SkSL::Parser::switchCaseBody\28SkSL::ExpressionArray*\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>*\2c\20std::__2::unique_ptr>\29 +4484:SkSL::Parser::statementOrNop\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +4485:SkSL::Parser::shiftExpression\28\29 +4486:SkSL::Parser::relationalExpression\28\29 +4487:SkSL::Parser::parameter\28std::__2::unique_ptr>*\29 +4488:SkSL::Parser::multiplicativeExpression\28\29 +4489:SkSL::Parser::logicalXorExpression\28\29 +4490:SkSL::Parser::logicalAndExpression\28\29 +4491:SkSL::Parser::localVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +4492:SkSL::Parser::intLiteral\28long\20long*\29 +4493:SkSL::Parser::globalVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +4494:SkSL::Parser::equalityExpression\28\29 +4495:SkSL::Parser::directive\28bool\29 +4496:SkSL::Parser::declarations\28\29 +4497:SkSL::Parser::checkNext\28SkSL::Token::Kind\2c\20SkSL::Token*\29 +4498:SkSL::Parser::bitwiseXorExpression\28\29 +4499:SkSL::Parser::bitwiseOrExpression\28\29 +4500:SkSL::Parser::bitwiseAndExpression\28\29 +4501:SkSL::Parser::additiveExpression\28\29 +4502:SkSL::Parser::Parser\28SkSL::Compiler*\2c\20SkSL::ProgramSettings\20const&\2c\20SkSL::ProgramKind\2c\20std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20std::__2::default_delete\2c\20std::__2::allocator>>>\29 +4503:SkSL::MultiArgumentConstructor::argumentSpan\28\29 +4504:SkSL::ModuleTypeToString\28SkSL::ModuleType\29 +4505:SkSL::ModuleLoader::~ModuleLoader\28\29 +4506:SkSL::ModuleLoader::loadPublicModule\28SkSL::Compiler*\29 +4507:SkSL::ModuleLoader::Get\28\29 +4508:SkSL::MatrixType::bitWidth\28\29\20const +4509:SkSL::MakeRasterPipelineProgram\28SkSL::Program\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSL::DebugTracePriv*\2c\20bool\29 +4510:SkSL::Layout::description\28\29\20const +4511:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_length\28std::__2::array\20const&\29 +4512:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_add\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +4513:SkSL::InterfaceBlock::~InterfaceBlock\28\29 +4514:SkSL::Inliner::candidateCanBeInlined\28SkSL::InlineCandidate\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20skia_private::THashMap*\29 +4515:SkSL::IfStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +4516:SkSL::GLSLCodeGenerator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\2c\20bool\29 +4517:SkSL::GLSLCodeGenerator::writeProgramElement\28SkSL::ProgramElement\20const&\29 +4518:SkSL::GLSLCodeGenerator::writeMinAbsHack\28SkSL::Expression&\2c\20SkSL::Expression&\29 +4519:SkSL::GLSLCodeGenerator::generateCode\28\29 +4520:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::visitStatementPtr\28std::__2::unique_ptr>&\29 +4521:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::addLocalVariable\28SkSL::Variable\20const*\2c\20SkSL::Position\29 +4522:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29_6962 +4523:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29 +4524:SkSL::FunctionDeclaration::mangledName\28\29\20const +4525:SkSL::FunctionDeclaration::determineFinalTypes\28SkSL::ExpressionArray\20const&\2c\20skia_private::STArray<8\2c\20SkSL::Type\20const*\2c\20true>*\2c\20SkSL::Type\20const**\29\20const +4526:SkSL::FunctionDeclaration::FunctionDeclaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20SkSL::Type\20const*\2c\20SkSL::IntrinsicKind\29 +4527:SkSL::FunctionDebugInfo*\20std::__2::vector>::__push_back_slow_path\28SkSL::FunctionDebugInfo&&\29 +4528:SkSL::FunctionCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +4529:SkSL::FunctionCall::FindBestFunctionForCall\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const*\2c\20SkSL::ExpressionArray\20const&\29 +4530:SkSL::FunctionCall::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +4531:SkSL::ForStatement::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +4532:SkSL::FindIntrinsicKind\28std::__2::basic_string_view>\29 +4533:SkSL::FieldAccess::~FieldAccess\28\29_6849 +4534:SkSL::FieldAccess::~FieldAccess\28\29 +4535:SkSL::ExpressionStatement::Convert\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +4536:SkSL::DoStatement::~DoStatement\28\29_6832 +4537:SkSL::DoStatement::~DoStatement\28\29 +4538:SkSL::DebugTracePriv::setSource\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4539:SkSL::ConstructorScalarCast::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +4540:SkSL::ConstructorMatrixResize::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +4541:SkSL::Constructor::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +4542:SkSL::ConstantFolder::Simplify\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +4543:SkSL::Compiler::writeErrorCount\28\29 +4544:SkSL::Compiler::initializeContext\28SkSL::Module\20const*\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\2c\20std::__2::basic_string_view>\2c\20SkSL::ModuleType\29 +4545:SkSL::Compiler::cleanupContext\28\29 +4546:SkSL::ChildCall::~ChildCall\28\29_6767 +4547:SkSL::ChildCall::~ChildCall\28\29 +4548:SkSL::ChildCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Variable\20const&\2c\20SkSL::ExpressionArray\29 +4549:SkSL::BinaryExpression::isAssignmentIntoVariable\28\29 +4550:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\2c\20SkSL::Type\20const*\29 +4551:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29 +4552:SkSL::Analysis::IsConstantExpression\28SkSL::Expression\20const&\29 +4553:SkSL::Analysis::IsAssignable\28SkSL::Expression&\2c\20SkSL::Analysis::AssignmentInfo*\2c\20SkSL::ErrorReporter*\29 +4554:SkSL::Analysis::GetLoopUnrollInfo\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\20const&\2c\20SkSL::Statement\20const*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Expression\20const*\2c\20SkSL::Statement\20const*\2c\20SkSL::ErrorReporter*\29 +4555:SkSL::Analysis::GetLoopControlFlowInfo\28SkSL::Statement\20const&\29 +4556:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +4557:SkSL::AliasType::numberKind\28\29\20const +4558:SkSL::AliasType::isOrContainsBool\28\29\20const +4559:SkSL::AliasType::isOrContainsAtomic\28\29\20const +4560:SkSL::AliasType::isAllowedInES2\28\29\20const +4561:SkRuntimeShader::~SkRuntimeShader\28\29 +4562:SkRuntimeEffectPriv::WriteChildEffects\28SkWriteBuffer&\2c\20SkSpan\29 +4563:SkRuntimeEffectPriv::TransformUniforms\28SkSpan\2c\20sk_sp\2c\20SkColorSpaceXformSteps\20const&\29 +4564:SkRuntimeEffect::~SkRuntimeEffect\28\29 +4565:SkRuntimeEffect::makeShader\28sk_sp\2c\20sk_sp*\2c\20unsigned\20long\2c\20SkMatrix\20const*\29\20const +4566:SkRuntimeEffect::makeColorFilter\28sk_sp\2c\20SkSpan\29\20const +4567:SkRuntimeEffect::TracedShader*\20emscripten::internal::raw_constructor\28\29 +4568:SkRuntimeEffect::MakeInternal\28std::__2::unique_ptr>\2c\20SkRuntimeEffect::Options\20const&\2c\20SkSL::ProgramKind\29 +4569:SkRuntimeEffect::ChildPtr&\20skia_private::TArray::emplace_back&>\28sk_sp&\29 +4570:SkRuntimeBlender::flatten\28SkWriteBuffer&\29\20const +4571:SkRgnBuilder::~SkRgnBuilder\28\29 +4572:SkResourceCache::PostPurgeSharedID\28unsigned\20long\20long\29 +4573:SkResourceCache::GetDiscardableFactory\28\29 +4574:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +4575:SkRegion::Spanerator::Spanerator\28SkRegion\20const&\2c\20int\2c\20int\2c\20int\29 +4576:SkRegion::Oper\28SkRegion\20const&\2c\20SkRegion\20const&\2c\20SkRegion::Op\2c\20SkRegion*\29 +4577:SkRefCntSet::~SkRefCntSet\28\29 +4578:SkRefCntBase::internal_dispose\28\29\20const +4579:SkReduceOrder::reduce\28SkDQuad\20const&\29 +4580:SkReduceOrder::Conic\28SkConic\20const&\2c\20SkPoint*\29 +4581:SkRectClipBlitter::requestRowsPreserved\28\29\20const +4582:SkRectClipBlitter::allocBlitMemory\28unsigned\20long\29 +4583:SkRect::intersect\28SkRect\20const&\2c\20SkRect\20const&\29 +4584:SkRecords::TypedMatrix::TypedMatrix\28SkMatrix\20const&\29 +4585:SkRecordOptimize\28SkRecord*\29 +4586:SkRecordFillBounds\28SkRect\20const&\2c\20SkRecord\20const&\2c\20SkRect*\2c\20SkBBoxHierarchy::Metadata*\29 +4587:SkRecord::bytesUsed\28\29\20const +4588:SkReadPixelsRec::trim\28int\2c\20int\29 +4589:SkReadBuffer::setDeserialProcs\28SkDeserialProcs\20const&\29 +4590:SkReadBuffer::readString\28unsigned\20long*\29 +4591:SkReadBuffer::readRegion\28SkRegion*\29 +4592:SkReadBuffer::readRect\28\29 +4593:SkReadBuffer::readPoint3\28SkPoint3*\29 +4594:SkReadBuffer::readPad32\28void*\2c\20unsigned\20long\29 +4595:SkReadBuffer::readArray\28void*\2c\20unsigned\20long\2c\20unsigned\20long\29 +4596:SkRasterPipeline::tailPointer\28\29 +4597:SkRasterPipeline::appendSetRGB\28SkArenaAlloc*\2c\20float\20const*\29 +4598:SkRasterPipeline::addMemoryContext\28SkRasterPipeline_MemoryCtx*\2c\20int\2c\20bool\2c\20bool\29 +4599:SkRasterClipStack::SkRasterClipStack\28int\2c\20int\29 +4600:SkRTreeFactory::operator\28\29\28\29\20const +4601:SkRTree::search\28SkRTree::Node*\2c\20SkRect\20const&\2c\20std::__2::vector>*\29\20const +4602:SkRTree::bulkLoad\28std::__2::vector>*\2c\20int\29 +4603:SkRTree::allocateNodeAtLevel\28unsigned\20short\29 +4604:SkRSXform::toQuad\28float\2c\20float\2c\20SkPoint*\29\20const +4605:SkRRect::isValid\28\29\20const +4606:SkRRect::computeType\28\29 +4607:SkRGBA4f<\28SkAlphaType\292>\20skgpu::Swizzle::applyTo<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\29\20const +4608:SkRBuffer::skipToAlign4\28\29 +4609:SkQuads::EvalAt\28double\2c\20double\2c\20double\2c\20double\29 +4610:SkQuadraticEdge::setQuadraticWithoutUpdate\28SkPoint\20const*\2c\20int\29 +4611:SkPtrSet::reset\28\29 +4612:SkPtrSet::copyToArray\28void**\29\20const +4613:SkPtrSet::add\28void*\29 +4614:SkPoint::Normalize\28SkPoint*\29 +4615:SkPngEncoder::Encode\28GrDirectContext*\2c\20SkImage\20const*\2c\20SkPngEncoder::Options\20const&\29 +4616:SkPngDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +4617:SkPngCodecBase::initializeXformParams\28\29 +4618:SkPngCodecBase::initializeSwizzler\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20bool\2c\20int\29 +4619:SkPngCodecBase::SkPngCodecBase\28SkEncodedInfo&&\2c\20std::__2::unique_ptr>\29 +4620:SkPngCodec::initializeXforms\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +4621:SkPixmapUtils::Orient\28SkPixmap\20const&\2c\20SkPixmap\20const&\2c\20SkEncodedOrigin\29 +4622:SkPixmap::erase\28unsigned\20int\2c\20SkIRect\20const&\29\20const +4623:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const +4624:SkPixelRef::getGenerationID\28\29\20const +4625:SkPixelRef::addGenIDChangeListener\28sk_sp\29 +4626:SkPixelRef::SkPixelRef\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +4627:SkPictureShader::CachedImageInfo::makeImage\28sk_sp\2c\20SkPicture\20const*\29\20const +4628:SkPictureShader::CachedImageInfo::Make\28SkRect\20const&\2c\20SkMatrix\20const&\2c\20SkColorType\2c\20SkColorSpace*\2c\20int\2c\20SkSurfaceProps\20const&\29 +4629:SkPictureRecord::endRecording\28\29 +4630:SkPictureRecord::beginRecording\28\29 +4631:SkPicturePriv::Flatten\28sk_sp\2c\20SkWriteBuffer&\29 +4632:SkPicturePlayback::draw\28SkCanvas*\2c\20SkPicture::AbortCallback*\2c\20SkReadBuffer*\29 +4633:SkPictureData::parseBufferTag\28SkReadBuffer&\2c\20unsigned\20int\2c\20unsigned\20int\29 +4634:SkPictureData::getPicture\28SkReadBuffer*\29\20const +4635:SkPictureData::getDrawable\28SkReadBuffer*\29\20const +4636:SkPictureData::flatten\28SkWriteBuffer&\29\20const +4637:SkPictureData::flattenToBuffer\28SkWriteBuffer&\2c\20bool\29\20const +4638:SkPictureData::SkPictureData\28SkPictureRecord\20const&\2c\20SkPictInfo\20const&\29 +4639:SkPicture::backport\28\29\20const +4640:SkPicture::SkPicture\28\29 +4641:SkPicture::MakeFromStreamPriv\28SkStream*\2c\20SkDeserialProcs\20const*\2c\20SkTypefacePlayback*\2c\20int\29 +4642:SkPerlinNoiseShader::type\28\29\20const +4643:SkPerlinNoiseShader::getPaintingData\28\29\20const +4644:SkPathWriter::assemble\28\29 +4645:SkPathWriter::SkPathWriter\28SkPath&\29 +4646:SkPathRef::resetToSize\28int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +4647:SkPathRef::SkPathRef\28SkSpan\2c\20SkSpan\2c\20SkSpan\2c\20unsigned\20int\29 +4648:SkPathPriv::IsNestedFillRects\28SkPath\20const&\2c\20SkRect*\2c\20SkPathDirection*\29 +4649:SkPathPriv::CreateDrawArcPath\28SkPath*\2c\20SkArc\20const&\2c\20bool\29 +4650:SkPathEffectBase::PointData::~PointData\28\29 +4651:SkPathEffect::filterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +4652:SkPathBuilder::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +4653:SkPath::writeToMemoryAsRRect\28void*\29\20const +4654:SkPath::setLastPt\28float\2c\20float\29 +4655:SkPath::reverseAddPath\28SkPath\20const&\29 +4656:SkPath::readFromMemory\28void\20const*\2c\20unsigned\20long\29 +4657:SkPath::offset\28float\2c\20float\2c\20SkPath*\29\20const +4658:SkPath::isZeroLengthSincePoint\28int\29\20const +4659:SkPath::isRRect\28SkRRect*\29\20const +4660:SkPath::isOval\28SkRect*\29\20const +4661:SkPath::conservativelyContainsRect\28SkRect\20const&\29\20const +4662:SkPath::computeConvexity\28\29\20const +4663:SkPath::addPath\28SkPath\20const&\2c\20float\2c\20float\2c\20SkPath::AddPathMode\29 +4664:SkPath::Polygon\28SkPoint\20const*\2c\20int\2c\20bool\2c\20SkPathFillType\2c\20bool\29 +4665:SkPath2DPathEffect::Make\28SkMatrix\20const&\2c\20SkPath\20const&\29 +4666:SkParsePath::ToSVGString\28SkPath\20const&\2c\20SkParsePath::PathEncoding\29::$_0::operator\28\29\28char\2c\20SkPoint\20const*\2c\20unsigned\20long\29\20const +4667:SkParseEncodedOrigin\28void\20const*\2c\20unsigned\20long\2c\20SkEncodedOrigin*\29 +4668:SkPaintPriv::ShouldDither\28SkPaint\20const&\2c\20SkColorType\29 +4669:SkPaintPriv::Overwrites\28SkPaint\20const*\2c\20SkPaintPriv::ShaderOverrideOpacity\29 +4670:SkPaint::setStroke\28bool\29 +4671:SkPaint::reset\28\29 +4672:SkPaint::refColorFilter\28\29\20const +4673:SkOpSpanBase::merge\28SkOpSpan*\29 +4674:SkOpSpanBase::globalState\28\29\20const +4675:SkOpSpan::sortableTop\28SkOpContour*\29 +4676:SkOpSpan::release\28SkOpPtT\20const*\29 +4677:SkOpSpan::insertCoincidence\28SkOpSegment\20const*\2c\20bool\2c\20bool\29 +4678:SkOpSpan::init\28SkOpSegment*\2c\20SkOpSpan*\2c\20double\2c\20SkPoint\20const&\29 +4679:SkOpSegment::updateWindingReverse\28SkOpAngle\20const*\29 +4680:SkOpSegment::oppXor\28\29\20const +4681:SkOpSegment::moveMultiples\28\29 +4682:SkOpSegment::isXor\28\29\20const +4683:SkOpSegment::computeSum\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpAngle::IncludeType\29 +4684:SkOpSegment::collapsed\28double\2c\20double\29\20const +4685:SkOpSegment::addExpanded\28double\2c\20SkOpSpanBase\20const*\2c\20bool*\29 +4686:SkOpSegment::activeAngle\28SkOpSpanBase*\2c\20SkOpSpanBase**\2c\20SkOpSpanBase**\2c\20bool*\29 +4687:SkOpSegment::UseInnerWinding\28int\2c\20int\29 +4688:SkOpPtT::ptAlreadySeen\28SkOpPtT\20const*\29\20const +4689:SkOpPtT::contains\28SkOpSegment\20const*\2c\20double\29\20const +4690:SkOpGlobalState::SkOpGlobalState\28SkOpContourHead*\2c\20SkArenaAlloc*\29 +4691:SkOpEdgeBuilder::preFetch\28\29 +4692:SkOpEdgeBuilder::init\28\29 +4693:SkOpEdgeBuilder::finish\28\29 +4694:SkOpContourBuilder::addConic\28SkPoint*\2c\20float\29 +4695:SkOpContour::addQuad\28SkPoint*\29 +4696:SkOpContour::addCubic\28SkPoint*\29 +4697:SkOpContour::addConic\28SkPoint*\2c\20float\29 +4698:SkOpCoincidence::release\28SkOpSegment\20const*\29 +4699:SkOpCoincidence::mark\28\29 +4700:SkOpCoincidence::markCollapsed\28SkCoincidentSpans*\2c\20SkOpPtT*\29 +4701:SkOpCoincidence::fixUp\28SkCoincidentSpans*\2c\20SkOpPtT*\2c\20SkOpPtT\20const*\29 +4702:SkOpCoincidence::contains\28SkCoincidentSpans\20const*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\29\20const +4703:SkOpCoincidence::checkOverlap\28SkCoincidentSpans*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20SkTDArray*\29\20const +4704:SkOpCoincidence::addOrOverlap\28SkOpSegment*\2c\20SkOpSegment*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20bool*\29 +4705:SkOpAngle::tangentsDiverge\28SkOpAngle\20const*\2c\20double\29 +4706:SkOpAngle::setSpans\28\29 +4707:SkOpAngle::setSector\28\29 +4708:SkOpAngle::previous\28\29\20const +4709:SkOpAngle::midToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +4710:SkOpAngle::loopCount\28\29\20const +4711:SkOpAngle::loopContains\28SkOpAngle\20const*\29\20const +4712:SkOpAngle::lastMarked\28\29\20const +4713:SkOpAngle::endToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +4714:SkOpAngle::alignmentSameSide\28SkOpAngle\20const*\2c\20int*\29\20const +4715:SkOpAngle::after\28SkOpAngle*\29 +4716:SkOffsetSimplePolygon\28SkPoint\20const*\2c\20int\2c\20SkRect\20const&\2c\20float\2c\20SkTDArray*\2c\20SkTDArray*\29 +4717:SkNoDrawCanvas::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +4718:SkNoDrawCanvas::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +4719:SkMipmapBuilder::level\28int\29\20const +4720:SkMipmap::countLevels\28\29\20const +4721:SkMeshSpecification::Varying*\20std::__2::vector>::__push_back_slow_path\28SkMeshSpecification::Varying&&\29 +4722:SkMeshSpecification::Attribute*\20std::__2::vector>::__push_back_slow_path\28SkMeshSpecification::Attribute&&\29 +4723:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2560 +4724:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +4725:SkMeshPriv::CpuBuffer::size\28\29\20const +4726:SkMeshPriv::CpuBuffer::peek\28\29\20const +4727:SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +4728:SkMatrix::setRotate\28float\2c\20float\2c\20float\29 +4729:SkMatrix::mapRectScaleTranslate\28SkRect*\2c\20SkRect\20const&\29\20const +4730:SkMatrix::isFinite\28\29\20const +4731:SkMatrix::RotTrans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +4732:SkMaskSwizzler::swizzle\28void*\2c\20unsigned\20char\20const*\29 +4733:SkMaskFilterBase::NinePatch::~NinePatch\28\29 +4734:SkMask::computeTotalImageSize\28\29\20const +4735:SkMakeResourceCacheSharedIDForBitmap\28unsigned\20int\29 +4736:SkMD5::finish\28\29 +4737:SkMD5::SkMD5\28\29 +4738:SkMD5::Digest::toHexString\28\29\20const +4739:SkM44::preTranslate\28float\2c\20float\2c\20float\29 +4740:SkM44::postTranslate\28float\2c\20float\2c\20float\29 +4741:SkLinearColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +4742:SkLineParameters::cubicEndPoints\28SkDCubic\20const&\29 +4743:SkLatticeIter::SkLatticeIter\28SkCanvas::Lattice\20const&\2c\20SkRect\20const&\29 +4744:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::~SkLRUCache\28\29 +4745:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::reset\28\29 +4746:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::insert\28GrProgramDesc\20const&\2c\20std::__2::unique_ptr>\29 +4747:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_matrix_conv_effect\28SkKnownRuntimeEffects::\28anonymous\20namespace\29::MatrixConvolutionImpl\2c\20SkRuntimeEffect::Options\20const&\29::$_0::operator\28\29\28int\2c\20SkRuntimeEffect::Options\20const&\29\20const +4748:SkJpegMetadataDecoderImpl::SkJpegMetadataDecoderImpl\28std::__2::vector>\29 +4749:SkJpegDecoder::IsJpeg\28void\20const*\2c\20unsigned\20long\29 +4750:SkJpegCodec::readRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20SkCodec::Options\20const&\2c\20int*\29 +4751:SkJpegCodec::initializeSwizzler\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20bool\29 +4752:SkJSONWriter::appendString\28char\20const*\2c\20unsigned\20long\29 +4753:SkIsSimplePolygon\28SkPoint\20const*\2c\20int\29 +4754:SkInvert4x4Matrix\28float\20const*\2c\20float*\29 +4755:SkInvert3x3Matrix\28float\20const*\2c\20float*\29 +4756:SkInvert2x2Matrix\28float\20const*\2c\20float*\29 +4757:SkIntersections::vertical\28SkDQuad\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4758:SkIntersections::vertical\28SkDLine\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4759:SkIntersections::vertical\28SkDCubic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4760:SkIntersections::vertical\28SkDConic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4761:SkIntersections::mostOutside\28double\2c\20double\2c\20SkDPoint\20const&\29\20const +4762:SkIntersections::intersect\28SkDQuad\20const&\2c\20SkDLine\20const&\29 +4763:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDQuad\20const&\29 +4764:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDLine\20const&\29 +4765:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDConic\20const&\29 +4766:SkIntersections::intersect\28SkDConic\20const&\2c\20SkDQuad\20const&\29 +4767:SkIntersections::intersect\28SkDConic\20const&\2c\20SkDLine\20const&\29 +4768:SkIntersections::insertCoincident\28double\2c\20double\2c\20SkDPoint\20const&\29 +4769:SkIntersections::horizontal\28SkDQuad\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4770:SkIntersections::horizontal\28SkDLine\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4771:SkIntersections::horizontal\28SkDCubic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4772:SkIntersections::horizontal\28SkDConic\20const&\2c\20double\2c\20double\2c\20double\2c\20bool\29 +4773:SkImages::RasterFromPixmap\28SkPixmap\20const&\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +4774:SkImages::RasterFromData\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\29 +4775:SkImages::DeferredFromGenerator\28std::__2::unique_ptr>\29 +4776:SkImage_Raster::onPeekBitmap\28\29\20const +4777:SkImage_Lazy::~SkImage_Lazy\28\29_4624 +4778:SkImage_Lazy::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +4779:SkImage_GaneshBase::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +4780:SkImage_Base::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +4781:SkImage_Base::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +4782:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_1::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +4783:SkImageInfo::validRowBytes\28unsigned\20long\29\20const +4784:SkImageInfo::MakeN32Premul\28int\2c\20int\29 +4785:SkImageGenerator::~SkImageGenerator\28\29_901 +4786:SkImageFilters::ColorFilter\28sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +4787:SkImageFilter_Base::getCTMCapability\28\29\20const +4788:SkImageFilterCache::Get\28SkImageFilterCache::CreateIfNecessary\29 +4789:SkImageFilter::computeFastBounds\28SkRect\20const&\29\20const +4790:SkImage::withMipmaps\28sk_sp\29\20const +4791:SkImage::peekPixels\28SkPixmap*\29\20const +4792:SkImage::height\28\29\20const +4793:SkIcoDecoder::IsIco\28void\20const*\2c\20unsigned\20long\29 +4794:SkIcoCodec::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::Result*\29 +4795:SkGradientBaseShader::~SkGradientBaseShader\28\29 +4796:SkGradientBaseShader::AppendGradientFillStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const*\2c\20float\20const*\2c\20int\29 +4797:SkGlyphRunListPainterCPU::SkGlyphRunListPainterCPU\28SkSurfaceProps\20const&\2c\20SkColorType\2c\20SkColorSpace*\29 +4798:SkGlyph::setImage\28SkArenaAlloc*\2c\20SkScalerContext*\29 +4799:SkGlyph::setDrawable\28SkArenaAlloc*\2c\20SkScalerContext*\29 +4800:SkGlyph::pathIsHairline\28\29\20const +4801:SkGlyph::mask\28SkPoint\29\20const +4802:SkGifDecoder::MakeFromStream\28std::__2::unique_ptr>\2c\20SkCodec::SelectionPolicy\2c\20SkCodec::Result*\29 +4803:SkGifDecoder::IsGif\28void\20const*\2c\20unsigned\20long\29 +4804:SkGenerateDistanceFieldFromA8Image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20unsigned\20long\29 +4805:SkGaussFilter::SkGaussFilter\28double\29 +4806:SkFrameHolder::setAlphaAndRequiredFrame\28SkFrame*\29 +4807:SkFrame::fillIn\28SkCodec::FrameInfo*\2c\20bool\29\20const +4808:SkFontStyleSet_Custom::appendTypeface\28sk_sp\29 +4809:SkFontStyleSet_Custom::SkFontStyleSet_Custom\28SkString\29 +4810:SkFontScanner_FreeType::scanInstance\28SkStreamAsset*\2c\20int\2c\20int\2c\20SkString*\2c\20SkFontStyle*\2c\20bool*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\2c\20skia_private::STArray<4\2c\20SkFontArguments::VariationPosition::Coordinate\2c\20true>*\29\20const +4811:SkFontScanner_FreeType::computeAxisValues\28skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>\20const&\2c\20SkFontArguments::VariationPosition\2c\20SkFontArguments::VariationPosition\2c\20int*\2c\20SkString\20const&\2c\20SkFontStyle*\29 +4812:SkFontPriv::GetFontBounds\28SkFont\20const&\29 +4813:SkFontMgr_Custom::onMakeFromStreamArgs\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29\20const +4814:SkFontMgr::matchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +4815:SkFontMgr::makeFromStream\28std::__2::unique_ptr>\2c\20int\29\20const +4816:SkFontMgr::makeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29\20const +4817:SkFontMgr::legacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +4818:SkFontDescriptor::SkFontStyleWidthForWidthAxisValue\28float\29 +4819:SkFontDescriptor::SkFontDescriptor\28\29 +4820:SkFont::setupForAsPaths\28SkPaint*\29 +4821:SkFont::setSkewX\28float\29 +4822:SkFont::setLinearMetrics\28bool\29 +4823:SkFont::setEmbolden\28bool\29 +4824:SkFont::operator==\28SkFont\20const&\29\20const +4825:SkFont::getPaths\28unsigned\20short\20const*\2c\20int\2c\20void\20\28*\29\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29\2c\20void*\29\20const +4826:SkFlattenable::RegisterFlattenablesIfNeeded\28\29 +4827:SkFlattenable::PrivateInitializer::InitEffects\28\29 +4828:SkFlattenable::NameToFactory\28char\20const*\29 +4829:SkFlattenable::FactoryToName\28sk_sp\20\28*\29\28SkReadBuffer&\29\29 +4830:SkFindQuadExtrema\28float\2c\20float\2c\20float\2c\20float*\29 +4831:SkFindCubicExtrema\28float\2c\20float\2c\20float\2c\20float\2c\20float*\29 +4832:SkFactorySet::~SkFactorySet\28\29 +4833:SkEdgeClipper::clipQuad\28SkPoint\20const*\2c\20SkRect\20const&\29 +4834:SkEdgeClipper::ClipPath\28SkPath\20const&\2c\20SkRect\20const&\2c\20bool\2c\20void\20\28*\29\28SkEdgeClipper*\2c\20bool\2c\20void*\29\2c\20void*\29 +4835:SkEdgeBuilder::buildEdges\28SkPath\20const&\2c\20SkIRect\20const*\29 +4836:SkDynamicMemoryWStream::bytesWritten\28\29\20const +4837:SkDrawableList::newDrawableSnapshot\28\29 +4838:SkDrawTreatAAStrokeAsHairline\28float\2c\20SkMatrix\20const&\2c\20float*\29 +4839:SkDrawShadowMetrics::GetSpotShadowTransform\28SkPoint3\20const&\2c\20float\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkRect\20const&\2c\20bool\2c\20SkMatrix*\2c\20float*\29 +4840:SkDrawShadowMetrics::GetLocalBounds\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect*\29 +4841:SkDrawBase::drawPaint\28SkPaint\20const&\29\20const +4842:SkDrawBase::DrawToMask\28SkPath\20const&\2c\20SkIRect\20const&\2c\20SkMaskFilter\20const*\2c\20SkMatrix\20const*\2c\20SkMaskBuilder*\2c\20SkMaskBuilder::CreateMode\2c\20SkStrokeRec::InitStyle\29 +4843:SkDraw::drawSprite\28SkBitmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29\20const +4844:SkDiscretePathEffectImpl::flatten\28SkWriteBuffer&\29\20const +4845:SkDiscretePathEffect::Make\28float\2c\20float\2c\20unsigned\20int\29 +4846:SkDevice::getRelativeTransform\28SkDevice\20const&\29\20const +4847:SkDevice::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +4848:SkDevice::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +4849:SkDevice::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +4850:SkDevice::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +4851:SkDescriptor::addEntry\28unsigned\20int\2c\20unsigned\20long\2c\20void\20const*\29 +4852:SkDeque::Iter::next\28\29 +4853:SkDeque::Iter::Iter\28SkDeque\20const&\2c\20SkDeque::Iter::IterStart\29 +4854:SkData::MakeSubset\28SkData\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +4855:SkDashPath::InternalFilter\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20float\20const*\2c\20int\2c\20float\2c\20int\2c\20float\2c\20float\2c\20SkDashPath::StrokeRecApplication\29 +4856:SkDashPath::CalcDashParameters\28float\2c\20float\20const*\2c\20int\2c\20float*\2c\20int*\2c\20float*\2c\20float*\29 +4857:SkDRect::setBounds\28SkDQuad\20const&\2c\20SkDQuad\20const&\2c\20double\2c\20double\29 +4858:SkDRect::setBounds\28SkDCubic\20const&\2c\20SkDCubic\20const&\2c\20double\2c\20double\29 +4859:SkDRect::setBounds\28SkDConic\20const&\2c\20SkDConic\20const&\2c\20double\2c\20double\29 +4860:SkDQuad::subDivide\28double\2c\20double\29\20const +4861:SkDQuad::monotonicInY\28\29\20const +4862:SkDQuad::isLinear\28int\2c\20int\29\20const +4863:SkDQuad::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +4864:SkDPoint::approximatelyDEqual\28SkDPoint\20const&\29\20const +4865:SkDCurveSweep::setCurveHullSweep\28SkPath::Verb\29 +4866:SkDCurve::nearPoint\28SkPath::Verb\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29\20const +4867:SkDCubic::monotonicInX\28\29\20const +4868:SkDCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +4869:SkDCubic::hullIntersects\28SkDPoint\20const*\2c\20int\2c\20bool*\29\20const +4870:SkDConic::subDivide\28double\2c\20double\29\20const +4871:SkCubics::RootsReal\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +4872:SkCubicEdge::setCubicWithoutUpdate\28SkPoint\20const*\2c\20int\2c\20bool\29 +4873:SkCubicClipper::ChopMonoAtY\28SkPoint\20const*\2c\20float\2c\20float*\29 +4874:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20SkArenaAlloc*\2c\20sk_sp\29 +4875:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkArenaAlloc*\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +4876:SkContourMeasureIter::~SkContourMeasureIter\28\29 +4877:SkContourMeasureIter::SkContourMeasureIter\28SkPath\20const&\2c\20bool\2c\20float\29 +4878:SkContourMeasure::length\28\29\20const +4879:SkContourMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29\20const +4880:SkConic::BuildUnitArc\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkRotationDirection\2c\20SkMatrix\20const*\2c\20SkConic*\29 +4881:SkComputeRadialSteps\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float*\2c\20float*\2c\20int*\29 +4882:SkCompressedDataSize\28SkTextureCompressionType\2c\20SkISize\2c\20skia_private::TArray*\2c\20bool\29 +4883:SkColorTypeValidateAlphaType\28SkColorType\2c\20SkAlphaType\2c\20SkAlphaType*\29 +4884:SkColorToPMColor4f\28unsigned\20int\2c\20GrColorInfo\20const&\29 +4885:SkColorSpaceLuminance::Fetch\28float\29 +4886:SkColorSpace::toProfile\28skcms_ICCProfile*\29\20const +4887:SkColorSpace::makeLinearGamma\28\29\20const +4888:SkColorSpace::isSRGB\28\29\20const +4889:SkColorMatrix_RGB2YUV\28SkYUVColorSpace\2c\20float*\29 +4890:SkColorInfo::makeColorSpace\28sk_sp\29\20const +4891:SkColorFilterShader::Make\28sk_sp\2c\20float\2c\20sk_sp\29 +4892:SkColor4fXformer::SkColor4fXformer\28SkGradientBaseShader\20const*\2c\20SkColorSpace*\2c\20bool\29 +4893:SkCoincidentSpans::extend\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\29 +4894:SkCodecs::get_decoders_for_editing\28\29 +4895:SkCodec::outputScanline\28int\29\20const +4896:SkCodec::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +4897:SkCodec::initializeColorXform\28SkImageInfo\20const&\2c\20SkEncodedInfo::Alpha\2c\20bool\29 +4898:SkChopQuadAtMaxCurvature\28SkPoint\20const*\2c\20SkPoint*\29 +4899:SkChopQuadAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +4900:SkChopMonoCubicAtX\28SkPoint\20const*\2c\20float\2c\20SkPoint*\29 +4901:SkChopCubicAtInflections\28SkPoint\20const*\2c\20SkPoint*\29 +4902:SkCharToGlyphCache::findGlyphIndex\28int\29\20const +4903:SkCanvasPriv::WriteLattice\28void*\2c\20SkCanvas::Lattice\20const&\29 +4904:SkCanvasPriv::ReadLattice\28SkReadBuffer&\2c\20SkCanvas::Lattice*\29 +4905:SkCanvasPriv::GetDstClipAndMatrixCounts\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20int*\2c\20int*\29 +4906:SkCanvas::~SkCanvas\28\29 +4907:SkCanvas::skew\28float\2c\20float\29 +4908:SkCanvas::only_axis_aligned_saveBehind\28SkRect\20const*\29 +4909:SkCanvas::getDeviceClipBounds\28\29\20const +4910:SkCanvas::experimental_DrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +4911:SkCanvas::drawVertices\28sk_sp\20const&\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +4912:SkCanvas::drawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +4913:SkCanvas::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +4914:SkCanvas::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +4915:SkCanvas::drawImageNine\28SkImage\20const*\2c\20SkIRect\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +4916:SkCanvas::drawClippedToSaveBehind\28SkPaint\20const&\29 +4917:SkCanvas::drawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +4918:SkCanvas::didTranslate\28float\2c\20float\29 +4919:SkCanvas::clipShader\28sk_sp\2c\20SkClipOp\29 +4920:SkCanvas::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +4921:SkCanvas::SkCanvas\28sk_sp\29 +4922:SkCanvas::ImageSetEntry::ImageSetEntry\28\29 +4923:SkCachedData::SkCachedData\28void*\2c\20unsigned\20long\29 +4924:SkCachedData::SkCachedData\28unsigned\20long\2c\20SkDiscardableMemory*\29 +4925:SkCTMShader::isOpaque\28\29\20const +4926:SkBulkGlyphMetricsAndPaths::glyphs\28SkSpan\29 +4927:SkBmpStandardCodec::decodeIcoMask\28SkStream*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\29 +4928:SkBmpMaskCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +4929:SkBmpDecoder::IsBmp\28void\20const*\2c\20unsigned\20long\29 +4930:SkBmpCodec::SkBmpCodec\28SkEncodedInfo&&\2c\20std::__2::unique_ptr>\2c\20unsigned\20short\2c\20SkCodec::SkScanlineOrder\29 +4931:SkBmpBaseCodec::SkBmpBaseCodec\28SkEncodedInfo&&\2c\20std::__2::unique_ptr>\2c\20unsigned\20short\2c\20SkCodec::SkScanlineOrder\29 +4932:SkBlurMask::ConvertRadiusToSigma\28float\29 +4933:SkBlurMask::ComputeBlurredScanline\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20unsigned\20int\2c\20float\29 +4934:SkBlurMask::BlurRect\28float\2c\20SkMaskBuilder*\2c\20SkRect\20const&\2c\20SkBlurStyle\2c\20SkIPoint*\2c\20SkMaskBuilder::CreateMode\29 +4935:SkBlurEngine::GetRasterBlurEngine\28\29 +4936:SkBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +4937:SkBlitter::Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +4938:SkBlitter::ChooseSprite\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkArenaAlloc*\2c\20sk_sp\29 +4939:SkBlenderBase::asBlendMode\28\29\20const +4940:SkBlenderBase::affectsTransparentBlack\28\29\20const +4941:SkBlendShader::~SkBlendShader\28\29_4723 +4942:SkBlendShader::~SkBlendShader\28\29 +4943:SkBitmapImageGetPixelRef\28SkImage\20const*\29 +4944:SkBitmapDevice::SkBitmapDevice\28SkBitmap\20const&\2c\20SkSurfaceProps\20const&\2c\20void*\29 +4945:SkBitmapCache::Rec::install\28SkBitmap*\29 +4946:SkBitmapCache::Rec::diagnostic_only_getDiscardable\28\29\20const +4947:SkBitmapCache::Find\28SkBitmapCacheDesc\20const&\2c\20SkBitmap*\29 +4948:SkBitmapCache::Alloc\28SkBitmapCacheDesc\20const&\2c\20SkImageInfo\20const&\2c\20SkPixmap*\29 +4949:SkBitmapCache::Add\28std::__2::unique_ptr\2c\20SkBitmap*\29 +4950:SkBitmap::setPixelRef\28sk_sp\2c\20int\2c\20int\29 +4951:SkBitmap::setAlphaType\28SkAlphaType\29 +4952:SkBitmap::reset\28\29 +4953:SkBitmap::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\29\20const +4954:SkBitmap::getAddr\28int\2c\20int\29\20const +4955:SkBitmap::allocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29::$_0::operator\28\29\28\29\20const +4956:SkBitmap::HeapAllocator::allocPixelRef\28SkBitmap*\29 +4957:SkBinaryWriteBuffer::writeFlattenable\28SkFlattenable\20const*\29 +4958:SkBinaryWriteBuffer::writeColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +4959:SkBigPicture::SkBigPicture\28SkRect\20const&\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20sk_sp\2c\20unsigned\20long\29 +4960:SkBezierQuad::IntersectWithHorizontalLine\28SkSpan\2c\20float\2c\20float*\29 +4961:SkBezierCubic::IntersectWithHorizontalLine\28SkSpan\2c\20float\2c\20float*\29 +4962:SkBasicEdgeBuilder::~SkBasicEdgeBuilder\28\29 +4963:SkBaseShadowTessellator::finishPathPolygon\28\29 +4964:SkBaseShadowTessellator::computeConvexShadow\28float\2c\20float\2c\20bool\29 +4965:SkBaseShadowTessellator::computeConcaveShadow\28float\2c\20float\29 +4966:SkBaseShadowTessellator::clipUmbraPoint\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint*\29 +4967:SkBaseShadowTessellator::addInnerPoint\28SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20int*\29 +4968:SkBaseShadowTessellator::addEdge\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20bool\2c\20bool\29 +4969:SkBaseShadowTessellator::addArc\28SkPoint\20const&\2c\20float\2c\20bool\29 +4970:SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint\28\29 +4971:SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint\28SkCanvas*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\2c\20SkRect\20const&\29 +4972:SkAndroidCodecAdapter::~SkAndroidCodecAdapter\28\29 +4973:SkAndroidCodecAdapter::SkAndroidCodecAdapter\28SkCodec*\29 +4974:SkAndroidCodec::~SkAndroidCodec\28\29 +4975:SkAndroidCodec::getAndroidPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const*\29 +4976:SkAndroidCodec::SkAndroidCodec\28SkCodec*\29 +4977:SkAnalyticEdge::update\28int\2c\20bool\29 +4978:SkAnalyticEdge::updateLine\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +4979:SkAnalyticEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4980:SkAAClip::operator=\28SkAAClip\20const&\29 +4981:SkAAClip::op\28SkIRect\20const&\2c\20SkClipOp\29 +4982:SkAAClip::Builder::flushRow\28bool\29 +4983:SkAAClip::Builder::finish\28SkAAClip*\29 +4984:SkAAClip::Builder::Blitter::~Blitter\28\29 +4985:SkAAClip::Builder::Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +4986:Sk2DPathEffect::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +4987:SimpleImageInfo*\20emscripten::internal::raw_constructor\28\29 +4988:SimpleFontStyle*\20emscripten::internal::MemberAccess::getWire\28SimpleFontStyle\20SimpleStrutStyle::*\20const&\2c\20SimpleStrutStyle&\29 +4989:Shift +4990:SharedGenerator::isTextureGenerator\28\29 +4991:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29_4039 +4992:RgnOper::addSpan\28int\2c\20int\20const*\2c\20int\20const*\29 +4993:ReadBase128 +4994:PorterDuffXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +4995:PathSegment::init\28\29 +4996:PathAddVerbsPointsWeights\28SkPath&\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +4997:ParseSingleImage +4998:ParseHeadersInternal +4999:PS_Conv_ASCIIHexDecode +5000:Op\28SkPath\20const&\2c\20SkPath\20const&\2c\20SkPathOp\2c\20SkPath*\29 +5001:OpAsWinding::markReverse\28Contour*\2c\20Contour*\29 +5002:OpAsWinding::getDirection\28Contour&\29 +5003:OpAsWinding::checkContainerChildren\28Contour*\2c\20Contour*\29 +5004:OffsetEdge::computeCrossingDistance\28OffsetEdge\20const*\29 +5005:OT::sbix::accelerator_t::get_png_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +5006:OT::sbix::accelerator_t::choose_strike\28hb_font_t*\29\20const +5007:OT::post_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5008:OT::hmtxvmtx::accelerator_t::get_advance_with_var_unscaled\28unsigned\20int\2c\20hb_font_t*\2c\20float*\29\20const +5009:OT::hmtx_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5010:OT::hb_ot_layout_lookup_accelerator_t*\20OT::hb_ot_layout_lookup_accelerator_t::create\28OT::Layout::GPOS_impl::PosLookup\20const&\29 +5011:OT::hb_kern_machine_t::kern\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20bool\29\20const +5012:OT::hb_accelerate_subtables_context_t::return_t\20OT::Context::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +5013:OT::hb_accelerate_subtables_context_t::return_t\20OT::ChainContext::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +5014:OT::glyf_accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\29\20const +5015:OT::glyf_accelerator_t::get_advance_with_var_unscaled\28hb_font_t*\2c\20unsigned\20int\2c\20bool\29\20const +5016:OT::cmap::accelerator_t::get_variation_glyph\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_cache_t<21u\2c\2016u\2c\208u\2c\20true>*\29\20const +5017:OT::cff2_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5018:OT::cff2::accelerator_templ_t>::~accelerator_templ_t\28\29 +5019:OT::cff2::accelerator_templ_t>::_fini\28\29 +5020:OT::cff1::lookup_expert_subset_charset_for_sid\28unsigned\20int\29 +5021:OT::cff1::lookup_expert_charset_for_sid\28unsigned\20int\29 +5022:OT::cff1::accelerator_templ_t>::~accelerator_templ_t\28\29 +5023:OT::cff1::accelerator_templ_t>::_fini\28\29 +5024:OT::TupleVariationData::unpack_points\28OT::IntType\20const*&\2c\20hb_vector_t&\2c\20OT::IntType\20const*\29 +5025:OT::SBIXStrike::get_glyph_blob\28unsigned\20int\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20unsigned\20int\2c\20unsigned\20int*\29\20const +5026:OT::RuleSet::sanitize\28hb_sanitize_context_t*\29\20const +5027:OT::RuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +5028:OT::RecordListOf::sanitize\28hb_sanitize_context_t*\29\20const +5029:OT::RecordListOf::sanitize\28hb_sanitize_context_t*\29\20const +5030:OT::PaintTranslate::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5031:OT::PaintSolid::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5032:OT::PaintSkewAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5033:OT::PaintSkew::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5034:OT::PaintScaleUniformAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5035:OT::PaintScaleUniform::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5036:OT::PaintScaleAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5037:OT::PaintScale::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5038:OT::PaintRotateAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5039:OT::PaintLinearGradient::sanitize\28hb_sanitize_context_t*\29\20const +5040:OT::PaintLinearGradient::sanitize\28hb_sanitize_context_t*\29\20const +5041:OT::Lookup::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +5042:OT::Layout::propagate_attachment_offsets\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +5043:OT::Layout::GSUB_impl::MultipleSubstFormat1_2::sanitize\28hb_sanitize_context_t*\29\20const +5044:OT::Layout::GSUB_impl::Ligature::apply\28OT::hb_ot_apply_context_t*\29\20const +5045:OT::Layout::GPOS_impl::reverse_cursive_minor_offset\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +5046:OT::Layout::GPOS_impl::MarkBasePosFormat1_2::sanitize\28hb_sanitize_context_t*\29\20const +5047:OT::Layout::GPOS_impl::MarkArray::sanitize\28hb_sanitize_context_t*\29\20const +5048:OT::Layout::GPOS_impl::AnchorMatrix::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +5049:OT::IndexSubtableRecord::get_image_data\28unsigned\20int\2c\20void\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +5050:OT::FeatureVariationRecord::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5051:OT::FeatureParams::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +5052:OT::ContextFormat3::sanitize\28hb_sanitize_context_t*\29\20const +5053:OT::ContextFormat2_5::sanitize\28hb_sanitize_context_t*\29\20const +5054:OT::ContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +5055:OT::ContextFormat1_4::sanitize\28hb_sanitize_context_t*\29\20const +5056:OT::ColorStop::get_color_stop\28OT::hb_paint_context_t*\2c\20hb_color_stop_t*\2c\20unsigned\20int\2c\20OT::VarStoreInstancer\20const&\29\20const +5057:OT::ColorLine::static_get_extend\28hb_color_line_t*\2c\20void*\2c\20void*\29 +5058:OT::CmapSubtableFormat4::accelerator_t::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +5059:OT::ChainRuleSet::sanitize\28hb_sanitize_context_t*\29\20const +5060:OT::ChainRuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +5061:OT::ChainContextFormat3::sanitize\28hb_sanitize_context_t*\29\20const +5062:OT::ChainContextFormat2_5::sanitize\28hb_sanitize_context_t*\29\20const +5063:OT::ChainContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +5064:OT::ChainContextFormat1_4::sanitize\28hb_sanitize_context_t*\29\20const +5065:OT::CBDT_accelerator_t*\20hb_data_wrapper_t::call_create>\28\29\20const +5066:OT::CBDT::accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +5067:OT::Affine2x3::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +5068:MakeOnScreenGLSurface\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int\29 +5069:Load_SBit_Png +5070:LineCubicIntersections::intersectRay\28double*\29 +5071:LineCubicIntersections::VerticalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +5072:LineCubicIntersections::HorizontalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +5073:Launch +5074:JpegDecoderMgr::returnFalse\28char\20const*\29 +5075:JpegDecoderMgr::getEncodedColor\28SkEncodedInfo::Color*\29 +5076:JSObjectFromLineMetrics\28skia::textlayout::LineMetrics&\29 +5077:JSObjectFromGlyphInfo\28skia::textlayout::Paragraph::GlyphInfo&\29 +5078:Ins_DELTAP +5079:HandleCoincidence\28SkOpContourHead*\2c\20SkOpCoincidence*\29 +5080:GrWritePixelsTask::~GrWritePixelsTask\28\29 +5081:GrWaitRenderTask::~GrWaitRenderTask\28\29 +5082:GrVertexBufferAllocPool::makeSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +5083:GrVertexBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +5084:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20SkPathFillType\2c\20skgpu::VertexWriter\29\20const +5085:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20GrEagerVertexAllocator*\29\20const +5086:GrTriangulator::mergeEdgesBelow\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +5087:GrTriangulator::mergeEdgesAbove\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +5088:GrTriangulator::makeSortedVertex\28SkPoint\20const&\2c\20unsigned\20char\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29\20const +5089:GrTriangulator::makeEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\29 +5090:GrTriangulator::computeBisector\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\29\20const +5091:GrTriangulator::appendQuadraticToContour\28SkPoint\20const*\2c\20float\2c\20GrTriangulator::VertexList*\29\20const +5092:GrTriangulator::SortMesh\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +5093:GrTriangulator::FindEnclosingEdges\28GrTriangulator::Vertex\20const&\2c\20GrTriangulator::EdgeList\20const&\2c\20GrTriangulator::Edge**\2c\20GrTriangulator::Edge**\29 +5094:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29 +5095:GrThreadSafeCache::findVertsWithData\28skgpu::UniqueKey\20const&\29 +5096:GrThreadSafeCache::addVertsWithData\28skgpu::UniqueKey\20const&\2c\20sk_sp\2c\20bool\20\28*\29\28SkData*\2c\20SkData*\29\29 +5097:GrThreadSafeCache::Entry::set\28skgpu::UniqueKey\20const&\2c\20sk_sp\29 +5098:GrThreadSafeCache::CreateLazyView\28GrDirectContext*\2c\20GrColorType\2c\20SkISize\2c\20GrSurfaceOrigin\2c\20SkBackingFit\29 +5099:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29 +5100:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29 +5101:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28GrCaps\20const&\2c\20std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\2c\20std::__2::basic_string_view>\29 +5102:GrTextureProxyPriv::setDeferredUploader\28std::__2::unique_ptr>\29 +5103:GrTextureProxy::setUniqueKey\28GrProxyProvider*\2c\20skgpu::UniqueKey\20const&\29 +5104:GrTextureProxy::ProxiesAreCompatibleAsDynamicState\28GrSurfaceProxy\20const*\2c\20GrSurfaceProxy\20const*\29 +5105:GrTextureProxy::GrTextureProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29_9790 +5106:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::$_1::operator\28\29\28int\2c\20GrSamplerState::WrapMode\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20float\29\20const +5107:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_2::operator\28\29\28GrTextureEffect::ShaderMode\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +5108:GrTexture::markMipmapsDirty\28\29 +5109:GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +5110:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29 +5111:GrSurfaceProxyPriv::exactify\28\29 +5112:GrSurfaceProxy::GrSurfaceProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +5113:GrStyledShape::setInheritedKey\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +5114:GrStyledShape::asRRect\28SkRRect*\2c\20bool*\29\20const +5115:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20SkPaint\20const&\2c\20GrStyledShape::DoSimplify\29 +5116:GrStyle::~GrStyle\28\29 +5117:GrStyle::applyToPath\28SkPath*\2c\20SkStrokeRec::InitStyle*\2c\20SkPath\20const&\2c\20float\29\20const +5118:GrStyle::applyPathEffect\28SkPath*\2c\20SkStrokeRec*\2c\20SkPath\20const&\29\20const +5119:GrStencilSettings::SetClipBitSettings\28bool\29 +5120:GrStagingBufferManager::detachBuffers\28\29 +5121:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineStruct\28char\20const*\29 +5122:GrShape::simplify\28unsigned\20int\29 +5123:GrShape::setRect\28SkRect\20const&\29 +5124:GrShape::conservativeContains\28SkRect\20const&\29\20const +5125:GrShape::closed\28\29\20const +5126:GrSWMaskHelper::toTextureView\28GrRecordingContext*\2c\20SkBackingFit\29 +5127:GrSWMaskHelper::drawShape\28GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +5128:GrSWMaskHelper::drawShape\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +5129:GrResourceProvider::writePixels\28sk_sp\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\29\20const +5130:GrResourceProvider::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +5131:GrResourceProvider::prepareLevels\28GrBackendFormat\20const&\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\2c\20skia_private::AutoSTArray<14\2c\20GrMipLevel>*\2c\20skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>*\29\20const +5132:GrResourceProvider::getExactScratch\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5133:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5134:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20GrColorType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMipLevel\20const*\2c\20std::__2::basic_string_view>\29 +5135:GrResourceProvider::createApproxTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5136:GrResourceCache::~GrResourceCache\28\29 +5137:GrResourceCache::removeResource\28GrGpuResource*\29 +5138:GrResourceCache::processFreedGpuResources\28\29 +5139:GrResourceCache::insertResource\28GrGpuResource*\29 +5140:GrResourceCache::didChangeBudgetStatus\28GrGpuResource*\29 +5141:GrResourceAllocator::~GrResourceAllocator\28\29 +5142:GrResourceAllocator::planAssignment\28\29 +5143:GrResourceAllocator::expire\28unsigned\20int\29 +5144:GrRenderTask::makeSkippable\28\29 +5145:GrRenderTask::isInstantiated\28\29\20const +5146:GrRenderTarget::GrRenderTarget\28GrGpu*\2c\20SkISize\20const&\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20sk_sp\29 +5147:GrRecordingContext::init\28\29 +5148:GrRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRRect\20const&\2c\20GrShaderCaps\20const&\29 +5149:GrQuadUtils::TessellationHelper::reset\28GrQuad\20const&\2c\20GrQuad\20const*\29 +5150:GrQuadUtils::TessellationHelper::outset\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuad*\2c\20GrQuad*\29 +5151:GrQuadUtils::TessellationHelper::adjustDegenerateVertices\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuadUtils::TessellationHelper::Vertices*\29 +5152:GrQuadUtils::TessellationHelper::OutsetRequest::reset\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\2c\20GrQuad::Type\2c\20skvx::Vec<4\2c\20float>\20const&\29 +5153:GrQuadUtils::TessellationHelper::EdgeVectors::reset\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20GrQuad::Type\29 +5154:GrQuadUtils::ClipToW0\28DrawQuad*\2c\20DrawQuad*\29 +5155:GrQuad::bounds\28\29\20const +5156:GrProxyProvider::~GrProxyProvider\28\29 +5157:GrProxyProvider::wrapBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\2c\20GrIOType\2c\20sk_sp\29 +5158:GrProxyProvider::removeUniqueKeyFromProxy\28GrTextureProxy*\29 +5159:GrProxyProvider::createLazyProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20GrInternalSurfaceFlags\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +5160:GrProxyProvider::contextID\28\29\20const +5161:GrProxyProvider::adoptUniqueKeyFromSurface\28GrTextureProxy*\2c\20GrSurface\20const*\29 +5162:GrPixmapBase::clip\28SkISize\2c\20SkIPoint*\29 +5163:GrPixmap::GrPixmap\28GrImageInfo\2c\20sk_sp\2c\20unsigned\20long\29 +5164:GrPipeline::GrPipeline\28GrPipeline::InitArgs\20const&\2c\20sk_sp\2c\20GrAppliedHardClip\20const&\29 +5165:GrPersistentCacheUtils::GetType\28SkReadBuffer*\29 +5166:GrPathUtils::QuadUVMatrix::set\28SkPoint\20const*\29 +5167:GrPathTessellationShader::MakeStencilOnlyPipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedHardClip\20const&\2c\20GrPipeline::InputFlags\29 +5168:GrPaint::setCoverageSetOpXPFactory\28SkRegion::Op\2c\20bool\29 +5169:GrOvalOpFactory::MakeOvalOp\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\2c\20GrShaderCaps\20const*\29 +5170:GrOpsRenderPass::drawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +5171:GrOpsRenderPass::drawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +5172:GrOpsRenderPass::drawIndexPattern\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +5173:GrOpFlushState::reset\28\29 +5174:GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp\28GrOp\20const*\2c\20SkRect\20const&\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +5175:GrOpFlushState::addASAPUpload\28std::__2::function&\29>&&\29 +5176:GrOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +5177:GrOp::combineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +5178:GrOnFlushResourceProvider::instantiateProxy\28GrSurfaceProxy*\29 +5179:GrMeshDrawTarget::allocMesh\28\29 +5180:GrMeshDrawOp::PatternHelper::init\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +5181:GrMeshDrawOp::CombinedQuadCountWillOverflow\28GrAAType\2c\20bool\2c\20int\29 +5182:GrMemoryPool::allocate\28unsigned\20long\29 +5183:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::changed\28\29 +5184:GrIndexBufferAllocPool::makeSpace\28int\2c\20sk_sp*\2c\20int*\29 +5185:GrIndexBufferAllocPool::makeSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +5186:GrImageInfo::refColorSpace\28\29\20const +5187:GrImageInfo::minRowBytes\28\29\20const +5188:GrImageInfo::makeDimensions\28SkISize\29\20const +5189:GrImageInfo::bpp\28\29\20const +5190:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20int\2c\20int\29 +5191:GrImageContext::abandonContext\28\29 +5192:GrGpuResource::removeUniqueKey\28\29 +5193:GrGpuResource::makeBudgeted\28\29 +5194:GrGpuResource::getResourceName\28\29\20const +5195:GrGpuResource::abandon\28\29 +5196:GrGpuResource::CreateUniqueID\28\29 +5197:GrGpu::~GrGpu\28\29 +5198:GrGpu::regenerateMipMapLevels\28GrTexture*\29 +5199:GrGpu::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5200:GrGpu::createTextureCommon\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +5201:GrGeometryProcessor::AttributeSet::addToKey\28skgpu::KeyBuilder*\29\20const +5202:GrGLVertexArray::invalidateCachedState\28\29 +5203:GrGLTextureParameters::invalidate\28\29 +5204:GrGLTexture::MakeWrapped\28GrGLGpu*\2c\20GrMipmapStatus\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrWrapCacheable\2c\20GrIOType\2c\20std::__2::basic_string_view>\29 +5205:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20skgpu::Budgeted\2c\20GrGLTexture::Desc\20const&\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +5206:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +5207:GrGLSLVaryingHandler::getFragDecls\28SkString*\2c\20SkString*\29\20const +5208:GrGLSLVaryingHandler::addAttribute\28GrShaderVar\20const&\29 +5209:GrGLSLUniformHandler::liftUniformToVertexShader\28GrProcessor\20const&\2c\20SkString\29 +5210:GrGLSLShaderBuilder::finalize\28unsigned\20int\29 +5211:GrGLSLShaderBuilder::emitFunction\28char\20const*\2c\20char\20const*\29 +5212:GrGLSLShaderBuilder::emitFunctionPrototype\28char\20const*\29 +5213:GrGLSLShaderBuilder::appendTextureLookupAndBlend\28char\20const*\2c\20SkBlendMode\2c\20GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +5214:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29::$_0::operator\28\29\28char\20const*\2c\20GrResourceHandle\2c\20skcms_TFType\29\20const +5215:GrGLSLShaderBuilder::addLayoutQualifier\28char\20const*\2c\20GrGLSLShaderBuilder::InterfaceQualifier\29 +5216:GrGLSLShaderBuilder::GrGLSLShaderBuilder\28GrGLSLProgramBuilder*\29 +5217:GrGLSLProgramDataManager::setRuntimeEffectUniforms\28SkSpan\2c\20SkSpan\20const>\2c\20SkSpan\2c\20void\20const*\29\20const +5218:GrGLSLProgramBuilder::~GrGLSLProgramBuilder\28\29 +5219:GrGLSLBlend::SetBlendModeUniformData\28GrGLSLProgramDataManager\20const&\2c\20GrResourceHandle\2c\20SkBlendMode\29 +5220:GrGLSLBlend::BlendExpression\28GrProcessor\20const*\2c\20GrGLSLUniformHandler*\2c\20GrResourceHandle*\2c\20char\20const*\2c\20char\20const*\2c\20SkBlendMode\29 +5221:GrGLRenderTarget::GrGLRenderTarget\28GrGLGpu*\2c\20SkISize\20const&\2c\20GrGLFormat\2c\20int\2c\20GrGLRenderTarget::IDs\20const&\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +5222:GrGLProgramDataManager::set4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +5223:GrGLProgramDataManager::set2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +5224:GrGLProgramBuilder::uniformHandler\28\29 +5225:GrGLProgramBuilder::PrecompileProgram\28GrDirectContext*\2c\20GrGLPrecompiledProgram*\2c\20SkData\20const&\29::$_0::operator\28\29\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\29\20const +5226:GrGLProgramBuilder::CreateProgram\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrGLPrecompiledProgram\20const*\29 +5227:GrGLProgram::~GrGLProgram\28\29 +5228:GrGLMakeAssembledWebGLInterface\28void*\2c\20void\20\28*\20\28*\29\28void*\2c\20char\20const*\29\29\28\29\29 +5229:GrGLGpu::~GrGLGpu\28\29 +5230:GrGLGpu::uploadTexData\28SkISize\2c\20unsigned\20int\2c\20SkIRect\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20long\2c\20GrMipLevel\20const*\2c\20int\29 +5231:GrGLGpu::uploadCompressedTexData\28SkTextureCompressionType\2c\20GrGLFormat\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20unsigned\20int\2c\20void\20const*\2c\20unsigned\20long\29 +5232:GrGLGpu::uploadColorToTex\28GrGLFormat\2c\20SkISize\2c\20unsigned\20int\2c\20std::__2::array\2c\20unsigned\20int\29 +5233:GrGLGpu::readOrTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20int\29 +5234:GrGLGpu::getTimerQueryResult\28unsigned\20int\29 +5235:GrGLGpu::getCompatibleStencilIndex\28GrGLFormat\29 +5236:GrGLGpu::createRenderTargetObjects\28GrGLTexture::Desc\20const&\2c\20int\2c\20GrGLRenderTarget::IDs*\29 +5237:GrGLGpu::createCompressedTexture2D\28SkISize\2c\20SkTextureCompressionType\2c\20GrGLFormat\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrGLTextureParameters::SamplerOverriddenState*\29 +5238:GrGLGpu::bindFramebuffer\28unsigned\20int\2c\20unsigned\20int\29 +5239:GrGLGpu::ProgramCache::reset\28\29 +5240:GrGLGpu::ProgramCache::findOrCreateProgramImpl\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrThreadSafePipelineBuilder::Stats::ProgramCacheResult*\29 +5241:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29 +5242:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\29 +5243:GrGLFormatIsCompressed\28GrGLFormat\29 +5244:GrGLFinishCallbacks::check\28\29 +5245:GrGLContext::~GrGLContext\28\29_11996 +5246:GrGLContext::~GrGLContext\28\29 +5247:GrGLCaps::~GrGLCaps\28\29 +5248:GrGLCaps::getTexSubImageExternalFormatAndType\28GrGLFormat\2c\20GrColorType\2c\20GrColorType\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +5249:GrGLCaps::getTexSubImageDefaultFormatTypeAndColorType\28GrGLFormat\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20GrColorType*\29\20const +5250:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrGLFormat\29\20const +5251:GrGLCaps::formatSupportsTexStorage\28GrGLFormat\29\20const +5252:GrGLCaps::canCopyAsDraw\28GrGLFormat\2c\20bool\2c\20bool\29\20const +5253:GrGLCaps::canCopyAsBlit\28GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20SkRect\20const&\2c\20bool\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29\20const +5254:GrFragmentProcessor::~GrFragmentProcessor\28\29 +5255:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +5256:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +5257:GrFragmentProcessor::ProgramImpl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +5258:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::Make\28std::__2::unique_ptr>\29 +5259:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +5260:GrFragmentProcessor::ClampOutput\28std::__2::unique_ptr>\29 +5261:GrFixedClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +5262:GrFixedClip::getConservativeBounds\28\29\20const +5263:GrFixedClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +5264:GrExternalTextureGenerator::GrExternalTextureGenerator\28SkImageInfo\20const&\29 +5265:GrEagerDynamicVertexAllocator::unlock\28int\29 +5266:GrDynamicAtlas::readView\28GrCaps\20const&\29\20const +5267:GrDrawingManager::getLastRenderTask\28GrSurfaceProxy\20const*\29\20const +5268:GrDrawingManager::flush\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +5269:GrDrawOpAtlasConfig::atlasDimensions\28skgpu::MaskFormat\29\20const +5270:GrDrawOpAtlasConfig::GrDrawOpAtlasConfig\28int\2c\20unsigned\20long\29 +5271:GrDrawOpAtlas::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +5272:GrDrawOpAtlas::Make\28GrProxyProvider*\2c\20GrBackendFormat\20const&\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20int\2c\20int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20GrDrawOpAtlas::AllowMultitexturing\2c\20skgpu::PlotEvictionCallback*\2c\20std::__2::basic_string_view>\29 +5273:GrDistanceFieldA8TextGeoProc::onTextureSampler\28int\29\20const +5274:GrDistanceFieldA8TextGeoProc::addNewViews\28GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\29 +5275:GrDisableColorXPFactory::MakeXferProcessor\28\29 +5276:GrDirectContextPriv::validPMUPMConversionExists\28\29 +5277:GrDirectContext::~GrDirectContext\28\29 +5278:GrDirectContext::onGetSmallPathAtlasMgr\28\29 +5279:GrDirectContext::getResourceCacheLimits\28int*\2c\20unsigned\20long*\29\20const +5280:GrCopyRenderTask::~GrCopyRenderTask\28\29 +5281:GrCopyRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +5282:GrCopyBaseMipMapToView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Budgeted\29 +5283:GrContext_Base::threadSafeProxy\28\29 +5284:GrContext_Base::maxSurfaceSampleCountForColorType\28SkColorType\29\20const +5285:GrContext_Base::backend\28\29\20const +5286:GrColorInfo::makeColorType\28GrColorType\29\20const +5287:GrColorInfo::isLinearlyBlended\28\29\20const +5288:GrColorFragmentProcessorAnalysis::GrColorFragmentProcessorAnalysis\28GrProcessorAnalysisColor\20const&\2c\20std::__2::unique_ptr>\20const*\2c\20int\29 +5289:GrClip::IsPixelAligned\28SkRect\20const&\29 +5290:GrCaps::surfaceSupportsWritePixels\28GrSurface\20const*\29\20const +5291:GrCaps::getDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\2c\20bool\29\20const +5292:GrCPixmap::GrCPixmap\28GrPixmap\20const&\29 +5293:GrBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\2c\20unsigned\20long*\29 +5294:GrBufferAllocPool::createBlock\28unsigned\20long\29 +5295:GrBufferAllocPool::CpuBufferCache::makeBuffer\28unsigned\20long\2c\20bool\29 +5296:GrBlurUtils::draw_shape_with_mask_filter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\29 +5297:GrBlurUtils::draw_mask\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrPaint&&\2c\20GrSurfaceProxyView\29 +5298:GrBlurUtils::convolve_gaussian\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20SkIRect\2c\20SkIRect\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkBackingFit\29 +5299:GrBlurUtils::\28anonymous\20namespace\29::make_texture_effect\28GrCaps\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20GrSamplerState\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkISize\20const&\29 +5300:GrBitmapTextGeoProc::addNewViews\28GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\29 +5301:GrBitmapTextGeoProc::GrBitmapTextGeoProc\28GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29 +5302:GrBicubicEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +5303:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +5304:GrBackendTextures::MakeGL\28int\2c\20int\2c\20skgpu::Mipmapped\2c\20GrGLTextureInfo\20const&\2c\20std::__2::basic_string_view>\29 +5305:GrBackendTexture::operator=\28GrBackendTexture\20const&\29 +5306:GrBackendRenderTargets::MakeGL\28int\2c\20int\2c\20int\2c\20int\2c\20GrGLFramebufferInfo\20const&\29 +5307:GrBackendRenderTargets::GetGLFramebufferInfo\28GrBackendRenderTarget\20const&\2c\20GrGLFramebufferInfo*\29 +5308:GrBackendRenderTarget::~GrBackendRenderTarget\28\29 +5309:GrBackendRenderTarget::isProtected\28\29\20const +5310:GrBackendFormatBytesPerBlock\28GrBackendFormat\20const&\29 +5311:GrBackendFormat::makeTexture2D\28\29\20const +5312:GrBackendFormat::isMockStencilFormat\28\29\20const +5313:GrBackendFormat::MakeMock\28GrColorType\2c\20SkTextureCompressionType\2c\20bool\29 +5314:GrAuditTrail::opsCombined\28GrOp\20const*\2c\20GrOp\20const*\29 +5315:GrAttachment::ComputeSharedAttachmentUniqueKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\2c\20skgpu::UniqueKey*\29 +5316:GrAtlasManager::~GrAtlasManager\28\29 +5317:GrAtlasManager::getViews\28skgpu::MaskFormat\2c\20unsigned\20int*\29 +5318:GrAtlasManager::freeAll\28\29 +5319:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::EventList*\2c\20GrTriangulator::Comparator\20const&\29\20const +5320:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrAATriangulator::EventList*\29\20const +5321:GrAATriangulator::collapseOverlapRegions\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\2c\20GrAATriangulator::EventComparator\29 +5322:GrAAConvexTessellator::quadTo\28SkPoint\20const*\29 +5323:GetShapedLines\28skia::textlayout::Paragraph&\29 +5324:GetLargeValue +5325:FontMgrRunIterator::endOfCurrentRun\28\29\20const +5326:FontMgrRunIterator::atEnd\28\29\20const +5327:FinishRow +5328:FindUndone\28SkOpContourHead*\29 +5329:FT_Stream_Free +5330:FT_Sfnt_Table_Info +5331:FT_Select_Size +5332:FT_Render_Glyph_Internal +5333:FT_Remove_Module +5334:FT_Outline_Get_Orientation +5335:FT_Outline_EmboldenXY +5336:FT_New_GlyphSlot +5337:FT_Match_Size +5338:FT_List_Iterate +5339:FT_List_Find +5340:FT_List_Finalize +5341:FT_GlyphLoader_CheckSubGlyphs +5342:FT_Get_Postscript_Name +5343:FT_Get_Paint_Layers +5344:FT_Get_PS_Font_Info +5345:FT_Get_Glyph_Name +5346:FT_Get_FSType_Flags +5347:FT_Get_Colorline_Stops +5348:FT_Get_Color_Glyph_ClipBox +5349:FT_Bitmap_Convert +5350:EllipticalRRectOp::~EllipticalRRectOp\28\29_11229 +5351:EllipticalRRectOp::~EllipticalRRectOp\28\29 +5352:EllipticalRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +5353:EllipticalRRectOp::RRect&\20skia_private::TArray::emplace_back\28EllipticalRRectOp::RRect&&\29 +5354:EllipticalRRectOp::EllipticalRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20SkPoint\2c\20bool\29 +5355:EllipseOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\29 +5356:EllipseOp::EllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20EllipseOp::DeviceSpaceParams\20const&\2c\20SkStrokeRec\20const&\29 +5357:EllipseGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +5358:DecodeVarLenUint8 +5359:DecodeContextMap +5360:DIEllipseOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\29 +5361:DIEllipseOp::DIEllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20DIEllipseOp::DeviceSpaceParams\20const&\2c\20SkMatrix\20const&\29 +5362:CustomXP::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +5363:CustomXP::makeProgramImpl\28\29\20const::Impl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +5364:Cr_z_zcfree +5365:Cr_z_deflateReset +5366:Cr_z_deflate +5367:Cr_z_crc32_z +5368:CoverageSetOpXP::onIsEqual\28GrXferProcessor\20const&\29\20const +5369:Contour*\20std::__2::vector>::__emplace_back_slow_path\28SkRect&\2c\20int&\2c\20int&\29 +5370:CircularRRectOp::~CircularRRectOp\28\29_11206 +5371:CircularRRectOp::~CircularRRectOp\28\29 +5372:CircularRRectOp::CircularRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +5373:CircleOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +5374:CircleOp::CircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +5375:CircleGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +5376:CheckDecBuffer +5377:CFF::path_procs_t::vvcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5378:CFF::path_procs_t::vlineto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5379:CFF::path_procs_t::vhcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5380:CFF::path_procs_t::rrcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5381:CFF::path_procs_t::rlineto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5382:CFF::path_procs_t::rlinecurve\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5383:CFF::path_procs_t::rcurveline\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5384:CFF::path_procs_t::hvcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5385:CFF::path_procs_t::hlineto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5386:CFF::path_procs_t::hhcurveto\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5387:CFF::path_procs_t::hflex\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5388:CFF::path_procs_t::hflex1\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5389:CFF::path_procs_t::flex\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5390:CFF::path_procs_t::flex1\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +5391:CFF::dict_interpreter_t\2c\20CFF::interp_env_t>::interpret\28CFF::cff1_private_dict_values_base_t&\29 +5392:CFF::cff2_cs_opset_t::process_blend\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\29 +5393:CFF::FDSelect3_4\2c\20OT::IntType>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +5394:CFF::Charset::get_sid\28unsigned\20int\2c\20unsigned\20int\2c\20CFF::code_pair_t*\29\20const +5395:CFF::CFFIndex>::get_size\28\29\20const +5396:CFF::CFF2FDSelect::get_fd\28unsigned\20int\29\20const +5397:ButtCapDashedCircleOp::ButtCapDashedCircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5398:BrotliTransformDictionaryWord +5399:BrotliEnsureRingBuffer +5400:AutoLayerForImageFilter::addMaskFilterLayer\28SkRect\20const*\29 +5401:AsWinding\28SkPath\20const&\2c\20SkPath*\29 +5402:AngleWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\2c\20bool*\29 +5403:AddIntersectTs\28SkOpContour*\2c\20SkOpContour*\2c\20SkOpCoincidence*\29 +5404:ActiveEdgeList::replace\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +5405:ActiveEdgeList::remove\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +5406:ActiveEdgeList::insert\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +5407:AAT::hb_aat_apply_context_t::return_t\20AAT::ChainSubtable::dispatch\28AAT::hb_aat_apply_context_t*\29\20const +5408:AAT::hb_aat_apply_context_t::return_t\20AAT::ChainSubtable::dispatch\28AAT::hb_aat_apply_context_t*\29\20const +5409:AAT::ankr::get_anchor\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +5410:AAT::TrackData::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5411:AAT::TrackData::get_tracking\28void\20const*\2c\20float\29\20const +5412:AAT::StateTable::EntryData>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +5413:AAT::StateTable::EntryData>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +5414:AAT::StateTable::EntryData>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +5415:AAT::RearrangementSubtable::driver_context_t::transition\28AAT::StateTableDriver*\2c\20AAT::Entry\20const&\29 +5416:AAT::NoncontextualSubtable::apply\28AAT::hb_aat_apply_context_t*\29\20const +5417:AAT::Lookup>::sanitize\28hb_sanitize_context_t*\29\20const +5418:AAT::Lookup>::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +5419:AAT::InsertionSubtable::driver_context_t::transition\28AAT::StateTableDriver::EntryData>*\2c\20AAT::Entry::EntryData>\20const&\29 +5420:5183 +5421:5184 +5422:5185 +5423:5186 +5424:5187 +5425:5188 +5426:5189 +5427:5190 +5428:5191 +5429:5192 +5430:5193 +5431:5194 +5432:5195 +5433:5196 +5434:5197 +5435:5198 +5436:5199 +5437:5200 +5438:5201 +5439:5202 +5440:5203 +5441:5204 +5442:5205 +5443:5206 +5444:5207 +5445:5208 +5446:5209 +5447:5210 +5448:5211 +5449:5212 +5450:5213 +5451:5214 +5452:5215 +5453:5216 +5454:5217 +5455:5218 +5456:5219 +5457:5220 +5458:5221 +5459:5222 +5460:5223 +5461:5224 +5462:5225 +5463:5226 +5464:5227 +5465:5228 +5466:5229 +5467:5230 +5468:5231 +5469:5232 +5470:5233 +5471:5234 +5472:5235 +5473:5236 +5474:5237 +5475:5238 +5476:5239 +5477:5240 +5478:5241 +5479:5242 +5480:5243 +5481:5244 +5482:5245 +5483:5246 +5484:5247 +5485:5248 +5486:5249 +5487:5250 +5488:5251 +5489:5252 +5490:5253 +5491:5254 +5492:5255 +5493:5256 +5494:5257 +5495:5258 +5496:5259 +5497:5260 +5498:5261 +5499:5262 +5500:5263 +5501:5264 +5502:5265 +5503:5266 +5504:ycck_cmyk_convert +5505:ycc_rgb_convert +5506:ycc_rgb565_convert +5507:ycc_rgb565D_convert +5508:xyzd50_to_lab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +5509:xyzd50_to_hcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +5510:wuffs_gif__decoder__tell_me_more +5511:wuffs_gif__decoder__set_report_metadata +5512:wuffs_gif__decoder__num_decoded_frame_configs +5513:wuffs_base__pixel_swizzler__xxxxxxxx__index_binary_alpha__src_over +5514:wuffs_base__pixel_swizzler__xxxxxxxx__index__src +5515:wuffs_base__pixel_swizzler__xxxx__index_binary_alpha__src_over +5516:wuffs_base__pixel_swizzler__xxxx__index__src +5517:wuffs_base__pixel_swizzler__xxx__index_binary_alpha__src_over +5518:wuffs_base__pixel_swizzler__xxx__index__src +5519:wuffs_base__pixel_swizzler__transparent_black_src_over +5520:wuffs_base__pixel_swizzler__transparent_black_src +5521:wuffs_base__pixel_swizzler__copy_1_1 +5522:wuffs_base__pixel_swizzler__bgr_565__index_binary_alpha__src_over +5523:wuffs_base__pixel_swizzler__bgr_565__index__src +5524:webgl_get_gl_proc\28void*\2c\20char\20const*\29 +5525:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +5526:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +5527:void\20emscripten::internal::raw_destructor>\28sk_sp*\29 +5528:void\20emscripten::internal::raw_destructor\28SkVertices::Builder*\29 +5529:void\20emscripten::internal::raw_destructor\28SkRuntimeEffect::TracedShader*\29 +5530:void\20emscripten::internal::raw_destructor\28SkPictureRecorder*\29 +5531:void\20emscripten::internal::raw_destructor\28SkPath*\29 +5532:void\20emscripten::internal::raw_destructor\28SkPaint*\29 +5533:void\20emscripten::internal::raw_destructor\28SkContourMeasureIter*\29 +5534:void\20emscripten::internal::raw_destructor\28SimpleImageInfo*\29 +5535:void\20emscripten::internal::MemberAccess::setWire\28SimpleTextStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\2c\20SimpleTextStyle*\29 +5536:void\20emscripten::internal::MemberAccess::setWire\28SimpleStrutStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\2c\20SimpleStrutStyle*\29 +5537:void\20emscripten::internal::MemberAccess>::setWire\28sk_sp\20SimpleImageInfo::*\20const&\2c\20SimpleImageInfo&\2c\20sk_sp*\29 +5538:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::TypefaceFontProvider*\29 +5539:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::ParagraphBuilderImpl*\29 +5540:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::Paragraph*\29 +5541:void\20const*\20emscripten::internal::getActualType\28skia::textlayout::FontCollection*\29 +5542:void\20const*\20emscripten::internal::getActualType\28SkVertices*\29 +5543:void\20const*\20emscripten::internal::getActualType\28SkVertices::Builder*\29 +5544:void\20const*\20emscripten::internal::getActualType\28SkTypeface*\29 +5545:void\20const*\20emscripten::internal::getActualType\28SkTextBlob*\29 +5546:void\20const*\20emscripten::internal::getActualType\28SkSurface*\29 +5547:void\20const*\20emscripten::internal::getActualType\28SkShader*\29 +5548:void\20const*\20emscripten::internal::getActualType\28SkSL::DebugTrace*\29 +5549:void\20const*\20emscripten::internal::getActualType\28SkRuntimeEffect*\29 +5550:void\20const*\20emscripten::internal::getActualType\28SkPictureRecorder*\29 +5551:void\20const*\20emscripten::internal::getActualType\28SkPicture*\29 +5552:void\20const*\20emscripten::internal::getActualType\28SkPathEffect*\29 +5553:void\20const*\20emscripten::internal::getActualType\28SkPath*\29 +5554:void\20const*\20emscripten::internal::getActualType\28SkPaint*\29 +5555:void\20const*\20emscripten::internal::getActualType\28SkMaskFilter*\29 +5556:void\20const*\20emscripten::internal::getActualType\28SkImageFilter*\29 +5557:void\20const*\20emscripten::internal::getActualType\28SkImage*\29 +5558:void\20const*\20emscripten::internal::getActualType\28SkFontMgr*\29 +5559:void\20const*\20emscripten::internal::getActualType\28SkFont*\29 +5560:void\20const*\20emscripten::internal::getActualType\28SkContourMeasureIter*\29 +5561:void\20const*\20emscripten::internal::getActualType\28SkContourMeasure*\29 +5562:void\20const*\20emscripten::internal::getActualType\28SkColorSpace*\29 +5563:void\20const*\20emscripten::internal::getActualType\28SkColorFilter*\29 +5564:void\20const*\20emscripten::internal::getActualType\28SkCanvas*\29 +5565:void\20const*\20emscripten::internal::getActualType\28SkBlender*\29 +5566:void\20const*\20emscripten::internal::getActualType\28SkAnimatedImage*\29 +5567:void\20const*\20emscripten::internal::getActualType\28GrDirectContext*\29 +5568:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5569:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5570:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5571:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5572:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5573:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5574:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5575:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5576:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5577:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5578:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5579:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5580:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5581:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5582:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5583:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5584:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5585:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5586:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5587:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5588:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5589:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5590:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5591:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5592:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5593:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5594:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5595:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5596:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5597:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5598:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5599:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5600:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5601:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5602:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5603:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5604:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5605:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5606:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5607:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5608:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5609:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5610:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5611:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5612:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5613:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5614:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5615:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5616:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5617:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5618:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5619:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5620:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5621:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5622:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5623:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5624:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5625:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5626:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5627:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5628:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5629:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5630:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5631:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5632:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5633:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5634:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5635:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5636:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5637:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5638:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5639:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5640:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5641:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5642:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5643:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5644:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5645:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5646:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5647:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5648:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5649:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5650:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5651:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5652:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5653:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5654:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5655:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5656:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5657:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5658:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5659:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5660:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5661:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5662:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5663:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +5664:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5665:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5666:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&fast_swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5667:void\20SkSwizzler::SkipLeadingGrayAlphaZerosThen<&fast_swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5668:void\20SkSwizzler::SkipLeading8888ZerosThen<&swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5669:void\20SkSwizzler::SkipLeading8888ZerosThen<&swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5670:void\20SkSwizzler::SkipLeading8888ZerosThen<&swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5671:void\20SkSwizzler::SkipLeading8888ZerosThen<&sample4\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5672:void\20SkSwizzler::SkipLeading8888ZerosThen<&fast_swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5673:void\20SkSwizzler::SkipLeading8888ZerosThen<&fast_swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5674:void\20SkSwizzler::SkipLeading8888ZerosThen<&fast_swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5675:void\20SkSwizzler::SkipLeading8888ZerosThen<©\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29>\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5676:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_16161 +5677:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +5678:virtual\20thunk\20to\20std::__2::basic_ostream>::~basic_ostream\28\29_16059 +5679:virtual\20thunk\20to\20std::__2::basic_ostream>::~basic_ostream\28\29 +5680:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29_16018 +5681:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29 +5682:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_16079 +5683:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +5684:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9844 +5685:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +5686:virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +5687:virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +5688:virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +5689:virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +5690:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29_9795 +5691:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29 +5692:virtual\20thunk\20to\20GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +5693:virtual\20thunk\20to\20GrTextureProxy::instantiate\28GrResourceProvider*\29 +5694:virtual\20thunk\20to\20GrTextureProxy::getUniqueKey\28\29\20const +5695:virtual\20thunk\20to\20GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +5696:virtual\20thunk\20to\20GrTextureProxy::callbackDesc\28\29\20const +5697:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29\20const +5698:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29 +5699:virtual\20thunk\20to\20GrTexture::onGpuMemorySize\28\29\20const +5700:virtual\20thunk\20to\20GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +5701:virtual\20thunk\20to\20GrTexture::asTexture\28\29\20const +5702:virtual\20thunk\20to\20GrTexture::asTexture\28\29 +5703:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9563 +5704:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +5705:virtual\20thunk\20to\20GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +5706:virtual\20thunk\20to\20GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +5707:virtual\20thunk\20to\20GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +5708:virtual\20thunk\20to\20GrRenderTargetProxy::callbackDesc\28\29\20const +5709:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29\20const +5710:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29 +5711:virtual\20thunk\20to\20GrRenderTarget::onRelease\28\29 +5712:virtual\20thunk\20to\20GrRenderTarget::onAbandon\28\29 +5713:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29\20const +5714:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29 +5715:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_12305 +5716:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +5717:virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +5718:virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +5719:virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +5720:virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +5721:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29_12272 +5722:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29 +5723:virtual\20thunk\20to\20GrGLTexture::onRelease\28\29 +5724:virtual\20thunk\20to\20GrGLTexture::onAbandon\28\29 +5725:virtual\20thunk\20to\20GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +5726:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10589 +5727:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +5728:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::onFinalize\28\29 +5729:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29_12244 +5730:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29 +5731:virtual\20thunk\20to\20GrGLRenderTarget::onRelease\28\29 +5732:virtual\20thunk\20to\20GrGLRenderTarget::onGpuMemorySize\28\29\20const +5733:virtual\20thunk\20to\20GrGLRenderTarget::onAbandon\28\29 +5734:virtual\20thunk\20to\20GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +5735:virtual\20thunk\20to\20GrGLRenderTarget::backendFormat\28\29\20const +5736:tt_vadvance_adjust +5737:tt_slot_init +5738:tt_size_select +5739:tt_size_reset_iterator +5740:tt_size_request +5741:tt_size_init +5742:tt_size_done +5743:tt_sbit_decoder_load_png +5744:tt_sbit_decoder_load_compound +5745:tt_sbit_decoder_load_byte_aligned +5746:tt_sbit_decoder_load_bit_aligned +5747:tt_property_set +5748:tt_property_get +5749:tt_name_ascii_from_utf16 +5750:tt_name_ascii_from_other +5751:tt_hadvance_adjust +5752:tt_glyph_load +5753:tt_get_var_blend +5754:tt_get_interface +5755:tt_get_glyph_name +5756:tt_get_cmap_info +5757:tt_get_advances +5758:tt_face_set_sbit_strike +5759:tt_face_load_strike_metrics +5760:tt_face_load_sbit_image +5761:tt_face_load_sbit +5762:tt_face_load_post +5763:tt_face_load_pclt +5764:tt_face_load_os2 +5765:tt_face_load_name +5766:tt_face_load_maxp +5767:tt_face_load_kern +5768:tt_face_load_hmtx +5769:tt_face_load_hhea +5770:tt_face_load_head +5771:tt_face_load_gasp +5772:tt_face_load_font_dir +5773:tt_face_load_cpal +5774:tt_face_load_colr +5775:tt_face_load_cmap +5776:tt_face_load_bhed +5777:tt_face_load_any +5778:tt_face_init +5779:tt_face_goto_table +5780:tt_face_get_paint_layers +5781:tt_face_get_paint +5782:tt_face_get_kerning +5783:tt_face_get_colr_layer +5784:tt_face_get_colr_glyph_paint +5785:tt_face_get_colorline_stops +5786:tt_face_get_color_glyph_clipbox +5787:tt_face_free_sbit +5788:tt_face_free_ps_names +5789:tt_face_free_name +5790:tt_face_free_cpal +5791:tt_face_free_colr +5792:tt_face_done +5793:tt_face_colr_blend_layer +5794:tt_driver_init +5795:tt_cvt_ready_iterator +5796:tt_cmap_unicode_init +5797:tt_cmap_unicode_char_next +5798:tt_cmap_unicode_char_index +5799:tt_cmap_init +5800:tt_cmap8_validate +5801:tt_cmap8_get_info +5802:tt_cmap8_char_next +5803:tt_cmap8_char_index +5804:tt_cmap6_validate +5805:tt_cmap6_get_info +5806:tt_cmap6_char_next +5807:tt_cmap6_char_index +5808:tt_cmap4_validate +5809:tt_cmap4_init +5810:tt_cmap4_get_info +5811:tt_cmap4_char_next +5812:tt_cmap4_char_index +5813:tt_cmap2_validate +5814:tt_cmap2_get_info +5815:tt_cmap2_char_next +5816:tt_cmap2_char_index +5817:tt_cmap14_variants +5818:tt_cmap14_variant_chars +5819:tt_cmap14_validate +5820:tt_cmap14_init +5821:tt_cmap14_get_info +5822:tt_cmap14_done +5823:tt_cmap14_char_variants +5824:tt_cmap14_char_var_isdefault +5825:tt_cmap14_char_var_index +5826:tt_cmap14_char_next +5827:tt_cmap13_validate +5828:tt_cmap13_get_info +5829:tt_cmap13_char_next +5830:tt_cmap13_char_index +5831:tt_cmap12_validate +5832:tt_cmap12_get_info +5833:tt_cmap12_char_next +5834:tt_cmap12_char_index +5835:tt_cmap10_validate +5836:tt_cmap10_get_info +5837:tt_cmap10_char_next +5838:tt_cmap10_char_index +5839:tt_cmap0_validate +5840:tt_cmap0_get_info +5841:tt_cmap0_char_next +5842:tt_cmap0_char_index +5843:transform_scanline_rgbA\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5844:transform_scanline_memcpy\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5845:transform_scanline_bgra_1010102_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5846:transform_scanline_bgra_1010102\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5847:transform_scanline_bgra_10101010_xr_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5848:transform_scanline_bgra_10101010_xr\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5849:transform_scanline_bgr_101010x_xr\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5850:transform_scanline_bgr_101010x\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5851:transform_scanline_bgrA\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5852:transform_scanline_RGBX\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5853:transform_scanline_F32_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5854:transform_scanline_F32\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5855:transform_scanline_F16_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5856:transform_scanline_F16\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5857:transform_scanline_F16F16F16x\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5858:transform_scanline_BGRX\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5859:transform_scanline_BGRA\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5860:transform_scanline_A8_to_GrayAlpha\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5861:transform_scanline_565\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5862:transform_scanline_444\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5863:transform_scanline_4444\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5864:transform_scanline_101010x\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5865:transform_scanline_1010102_premul\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5866:transform_scanline_1010102\28char*\2c\20char\20const*\2c\20int\2c\20int\29 +5867:t2_hints_stems +5868:t2_hints_open +5869:t1_make_subfont +5870:t1_hints_stem +5871:t1_hints_open +5872:t1_decrypt +5873:t1_decoder_parse_metrics +5874:t1_decoder_init +5875:t1_decoder_done +5876:t1_cmap_unicode_init +5877:t1_cmap_unicode_char_next +5878:t1_cmap_unicode_char_index +5879:t1_cmap_std_done +5880:t1_cmap_std_char_next +5881:t1_cmap_std_char_index +5882:t1_cmap_standard_init +5883:t1_cmap_expert_init +5884:t1_cmap_custom_init +5885:t1_cmap_custom_done +5886:t1_cmap_custom_char_next +5887:t1_cmap_custom_char_index +5888:t1_builder_start_point +5889:t1_builder_init +5890:t1_builder_add_point1 +5891:t1_builder_add_point +5892:t1_builder_add_contour +5893:swizzle_small_index_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5894:swizzle_small_index_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5895:swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5896:swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5897:swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5898:swizzle_rgba16_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5899:swizzle_rgba16_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5900:swizzle_rgba16_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5901:swizzle_rgba16_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5902:swizzle_rgb_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5903:swizzle_rgb_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5904:swizzle_rgb_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5905:swizzle_rgb16_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5906:swizzle_rgb16_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5907:swizzle_rgb16_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5908:swizzle_mask32_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5909:swizzle_mask32_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5910:swizzle_mask32_to_rgba_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5911:swizzle_mask32_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5912:swizzle_mask32_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5913:swizzle_mask32_to_bgra_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5914:swizzle_mask32_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5915:swizzle_mask24_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5916:swizzle_mask24_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5917:swizzle_mask24_to_rgba_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5918:swizzle_mask24_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5919:swizzle_mask24_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5920:swizzle_mask24_to_bgra_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5921:swizzle_mask24_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5922:swizzle_mask16_to_rgba_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5923:swizzle_mask16_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5924:swizzle_mask16_to_rgba_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5925:swizzle_mask16_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5926:swizzle_mask16_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5927:swizzle_mask16_to_bgra_opaque\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5928:swizzle_mask16_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20SkMasks*\2c\20unsigned\20int\2c\20unsigned\20int\29 +5929:swizzle_index_to_n32_skipZ\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5930:swizzle_index_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5931:swizzle_index_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5932:swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5933:swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5934:swizzle_grayalpha_to_a8\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5935:swizzle_gray_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5936:swizzle_gray_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5937:swizzle_cmyk_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5938:swizzle_cmyk_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5939:swizzle_cmyk_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5940:swizzle_bit_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5941:swizzle_bit_to_grayscale\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5942:swizzle_bit_to_f16\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5943:swizzle_bit_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5944:swizzle_bgr_to_565\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +5945:string_read +5946:std::exception::what\28\29\20const +5947:std::bad_variant_access::what\28\29\20const +5948:std::bad_optional_access::what\28\29\20const +5949:std::bad_array_new_length::what\28\29\20const +5950:std::bad_alloc::what\28\29\20const +5951:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +5952:std::__2::unique_ptr>::operator=\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +5953:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20tm\20const*\2c\20char\2c\20char\29\20const +5954:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20tm\20const*\2c\20char\2c\20char\29\20const +5955:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5956:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5957:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5958:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5959:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5960:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +5961:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5962:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5963:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5964:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5965:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +5966:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +5967:std::__2::numpunct::~numpunct\28\29_17042 +5968:std::__2::numpunct::do_truename\28\29\20const +5969:std::__2::numpunct::do_grouping\28\29\20const +5970:std::__2::numpunct::do_falsename\28\29\20const +5971:std::__2::numpunct::~numpunct\28\29_17040 +5972:std::__2::numpunct::do_truename\28\29\20const +5973:std::__2::numpunct::do_thousands_sep\28\29\20const +5974:std::__2::numpunct::do_grouping\28\29\20const +5975:std::__2::numpunct::do_falsename\28\29\20const +5976:std::__2::numpunct::do_decimal_point\28\29\20const +5977:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20void\20const*\29\20const +5978:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\29\20const +5979:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\20long\29\20const +5980:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\29\20const +5981:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20long\29\20const +5982:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +5983:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20double\29\20const +5984:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20bool\29\20const +5985:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20void\20const*\29\20const +5986:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\29\20const +5987:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\20long\29\20const +5988:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\29\20const +5989:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20long\29\20const +5990:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +5991:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20double\29\20const +5992:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20bool\29\20const +5993:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +5994:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +5995:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +5996:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +5997:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +5998:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +5999:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +6000:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +6001:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +6002:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +6003:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +6004:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +6005:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +6006:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6007:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +6008:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +6009:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +6010:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +6011:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6012:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +6013:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6014:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +6015:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +6016:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6017:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +6018:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +6019:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6020:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +6021:std::__2::locale::__imp::~__imp\28\29_16920 +6022:std::__2::ios_base::~ios_base\28\29_16283 +6023:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +6024:std::__2::ctype::do_toupper\28wchar_t\29\20const +6025:std::__2::ctype::do_toupper\28wchar_t*\2c\20wchar_t\20const*\29\20const +6026:std::__2::ctype::do_tolower\28wchar_t\29\20const +6027:std::__2::ctype::do_tolower\28wchar_t*\2c\20wchar_t\20const*\29\20const +6028:std::__2::ctype::do_scan_not\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6029:std::__2::ctype::do_scan_is\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6030:std::__2::ctype::do_narrow\28wchar_t\2c\20char\29\20const +6031:std::__2::ctype::do_narrow\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20char\2c\20char*\29\20const +6032:std::__2::ctype::do_is\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20unsigned\20long*\29\20const +6033:std::__2::ctype::do_is\28unsigned\20long\2c\20wchar_t\29\20const +6034:std::__2::ctype::~ctype\28\29_16968 +6035:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +6036:std::__2::ctype::do_toupper\28char\29\20const +6037:std::__2::ctype::do_toupper\28char*\2c\20char\20const*\29\20const +6038:std::__2::ctype::do_tolower\28char\29\20const +6039:std::__2::ctype::do_tolower\28char*\2c\20char\20const*\29\20const +6040:std::__2::ctype::do_narrow\28char\2c\20char\29\20const +6041:std::__2::ctype::do_narrow\28char\20const*\2c\20char\20const*\2c\20char\2c\20char*\29\20const +6042:std::__2::collate::do_transform\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6043:std::__2::collate::do_hash\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6044:std::__2::collate::do_compare\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +6045:std::__2::collate::do_transform\28char\20const*\2c\20char\20const*\29\20const +6046:std::__2::collate::do_hash\28char\20const*\2c\20char\20const*\29\20const +6047:std::__2::collate::do_compare\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +6048:std::__2::codecvt::~codecvt\28\29_16986 +6049:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const +6050:std::__2::codecvt::do_out\28__mbstate_t&\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +6051:std::__2::codecvt::do_max_length\28\29\20const +6052:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +6053:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20wchar_t*\2c\20wchar_t*\2c\20wchar_t*&\29\20const +6054:std::__2::codecvt::do_encoding\28\29\20const +6055:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +6056:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29_16153 +6057:std::__2::basic_stringbuf\2c\20std::__2::allocator>::underflow\28\29 +6058:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +6059:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +6060:std::__2::basic_stringbuf\2c\20std::__2::allocator>::pbackfail\28int\29 +6061:std::__2::basic_stringbuf\2c\20std::__2::allocator>::overflow\28int\29 +6062:std::__2::basic_streambuf>::~basic_streambuf\28\29_15991 +6063:std::__2::basic_streambuf>::xsputn\28char\20const*\2c\20long\29 +6064:std::__2::basic_streambuf>::xsgetn\28char*\2c\20long\29 +6065:std::__2::basic_streambuf>::uflow\28\29 +6066:std::__2::basic_streambuf>::setbuf\28char*\2c\20long\29 +6067:std::__2::basic_streambuf>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +6068:std::__2::basic_streambuf>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +6069:std::__2::bad_function_call::what\28\29\20const +6070:std::__2::__time_get_c_storage::__x\28\29\20const +6071:std::__2::__time_get_c_storage::__weeks\28\29\20const +6072:std::__2::__time_get_c_storage::__r\28\29\20const +6073:std::__2::__time_get_c_storage::__months\28\29\20const +6074:std::__2::__time_get_c_storage::__c\28\29\20const +6075:std::__2::__time_get_c_storage::__am_pm\28\29\20const +6076:std::__2::__time_get_c_storage::__X\28\29\20const +6077:std::__2::__time_get_c_storage::__x\28\29\20const +6078:std::__2::__time_get_c_storage::__weeks\28\29\20const +6079:std::__2::__time_get_c_storage::__r\28\29\20const +6080:std::__2::__time_get_c_storage::__months\28\29\20const +6081:std::__2::__time_get_c_storage::__c\28\29\20const +6082:std::__2::__time_get_c_storage::__am_pm\28\29\20const +6083:std::__2::__time_get_c_storage::__X\28\29\20const +6084:std::__2::__shared_ptr_pointer<_IO_FILE*\2c\20void\20\28*\29\28_IO_FILE*\29\2c\20std::__2::allocator<_IO_FILE>>::__on_zero_shared\28\29 +6085:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7525 +6086:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6087:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +6088:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7820 +6089:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6090:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +6091:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_8064 +6092:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6093:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +6094:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_6238 +6095:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +6096:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6097:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6098:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6099:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6100:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6101:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6102:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6103:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6104:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6105:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6106:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6107:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6108:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6109:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6110:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6111:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6112:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6113:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6114:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +6115:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6116:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +6117:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +6118:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6119:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +6120:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6121:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6122:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6123:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6124:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6125:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6126:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6127:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6128:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6129:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6130:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6131:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6132:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6133:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6134:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6135:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6136:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6137:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6138:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6139:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6140:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6141:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6142:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6143:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6144:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6145:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6146:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6147:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6148:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6149:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6150:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6151:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6152:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6153:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +6154:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +6155:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +6156:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +6157:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +6158:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +6159:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20float&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20SkPoint&&\2c\20SkPoint&&\2c\20skia::textlayout::InternalLineMetrics&&\2c\20bool&&\29 +6160:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>*\29\20const +6161:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28\29\20const +6162:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::operator\28\29\28skia::textlayout::Cluster*&&\29 +6163:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28std::__2::__function::__base*\29\20const +6164:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28\29\20const +6165:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6166:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28\29\20const +6167:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20SkSpan&&\2c\20float&\2c\20unsigned\20long&&\2c\20unsigned\20char&&\29 +6168:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28std::__2::__function::__base\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>*\29\20const +6169:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28\29\20const +6170:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::operator\28\29\28skia::textlayout::Block&&\2c\20skia_private::TArray&&\29 +6171:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28std::__2::__function::__base\29>*\29\20const +6172:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28\29\20const +6173:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::operator\28\29\28sk_sp&&\29 +6174:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28std::__2::__function::__base\29>*\29\20const +6175:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28\29\20const +6176:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::operator\28\29\28skia::textlayout::SkRange&&\29 +6177:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28std::__2::__function::__base\29>*\29\20const +6178:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28\29\20const +6179:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +6180:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +6181:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +6182:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29_10026 +6183:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29 +6184:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::operator\28\29\28void*&&\2c\20void\20const*&&\29 +6185:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy_deallocate\28\29 +6186:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy\28\29 +6187:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6188:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28\29\20const +6189:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6190:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6191:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6192:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6193:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6194:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6195:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +6196:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6197:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6198:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +6199:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6200:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6201:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +6202:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6203:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6204:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +6205:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +6206:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +6207:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::operator\28\29\28sktext::gpu::GlyphVector*&&\2c\20int&&\2c\20int&&\2c\20skgpu::MaskFormat&&\2c\20int&&\29 +6208:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28std::__2::__function::__base\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>*\29\20const +6209:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28\29\20const +6210:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::operator\28\29\28GrSurfaceProxy\20const*&&\29 +6211:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6212:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28\29\20const +6213:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +6214:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +6215:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +6216:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +6217:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +6218:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +6219:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +6220:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6221:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +6222:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6223:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6224:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +6225:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +6226:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +6227:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6228:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6229:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::operator\28\29\28\29 +6230:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6231:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28\29\20const +6232:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6233:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6234:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6235:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6236:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6237:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6238:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6239:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6240:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6241:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6242:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6243:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6244:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6245:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6246:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6247:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6248:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6249:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6250:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6251:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29_4369 +6252:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29 +6253:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +6254:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy_deallocate\28\29 +6255:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy\28\29 +6256:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6257:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +6258:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +6259:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6260:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +6261:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6262:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6263:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6264:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6265:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6266:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6267:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::operator\28\29\28SkSL::Variable\20const&\29 +6268:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6269:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28\29\20const +6270:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::operator\28\29\28int&&\2c\20SkSL::Variable\20const*&&\2c\20SkSL::Expression\20const*&&\29 +6271:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6272:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28\29\20const +6273:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::operator\28\29\28unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\29 +6274:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +6275:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +6276:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +6277:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +6278:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::operator\28\29\28SkVertices\20const*&&\2c\20SkBlendMode&&\2c\20SkPaint\20const&\2c\20float&&\2c\20float&&\2c\20bool&&\29 +6279:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +6280:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28\29\20const +6281:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::operator\28\29\28SkIRect\20const&\29 +6282:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6283:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28\29\20const +6284:std::__2::__function::__func\2c\20SkCodec::Result\20\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int\29>::operator\28\29\28SkImageInfo\20const&\2c\20void*&&\2c\20unsigned\20long&&\2c\20SkCodec::Options\20const&\2c\20int&&\29 +6285:std::__2::__function::__func\2c\20SkCodec::Result\20\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int\29>::__clone\28std::__2::__function::__base*\29\20const +6286:std::__2::__function::__func\2c\20SkCodec::Result\20\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int\29>::__clone\28\29\20const +6287:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9888 +6288:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +6289:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6290:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +6291:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +6292:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6293:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6294:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9486 +6295:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +6296:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6297:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +6298:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +6299:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6300:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6301:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9493 +6302:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +6303:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6304:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +6305:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +6306:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6307:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6308:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::operator\28\29\28GrTextureProxy*&&\2c\20SkIRect&&\2c\20GrColorType&&\2c\20void\20const*&&\2c\20unsigned\20long&&\29 +6309:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +6310:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28\29\20const +6311:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::operator\28\29\28GrBackendTexture&&\29 +6312:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28std::__2::__function::__base*\29\20const +6313:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28\29\20const +6314:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6315:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6316:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6317:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +6318:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +6319:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +6320:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6321:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6322:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6323:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +6324:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +6325:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +6326:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +6327:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6328:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +6329:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +6330:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +6331:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +6332:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29_8990 +6333:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +6334:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +6335:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +6336:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29_8997 +6337:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +6338:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +6339:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +6340:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +6341:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +6342:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +6343:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::operator\28\29\28int&&\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*&&\29 +6344:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +6345:std::__2::__function::__func\2c\20void\20\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29>::__clone\28\29\20const +6346:start_pass_upsample +6347:start_pass_phuff_decoder +6348:start_pass_merged_upsample +6349:start_pass_main +6350:start_pass_huff_decoder +6351:start_pass_dpost +6352:start_pass_2_quant +6353:start_pass_1_quant +6354:start_pass +6355:start_output_pass +6356:start_input_pass_15423 +6357:srgb_to_hwb\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +6358:srgb_to_hsl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +6359:srcover_p\28unsigned\20char\2c\20unsigned\20char\29 +6360:sn_write +6361:sktext::gpu::post_purge_blob_message\28unsigned\20int\2c\20unsigned\20int\29 +6362:sktext::gpu::TextBlob::~TextBlob\28\29_12639 +6363:sktext::gpu::TextBlob::~TextBlob\28\29 +6364:sktext::gpu::SubRun::~SubRun\28\29 +6365:sktext::gpu::SlugImpl::~SlugImpl\28\29_12465 +6366:sktext::gpu::SlugImpl::~SlugImpl\28\29 +6367:sktext::gpu::SlugImpl::sourceBounds\28\29\20const +6368:sktext::gpu::SlugImpl::sourceBoundsWithOrigin\28\29\20const +6369:sktext::gpu::SlugImpl::doFlatten\28SkWriteBuffer&\29\20const +6370:sktext::gpu::SDFMaskFilterImpl::getTypeName\28\29\20const +6371:sktext::gpu::SDFMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +6372:sktext::gpu::SDFMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +6373:skip_variable +6374:skif::\28anonymous\20namespace\29::RasterBackend::~RasterBackend\28\29 +6375:skif::\28anonymous\20namespace\29::RasterBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +6376:skif::\28anonymous\20namespace\29::RasterBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +6377:skif::\28anonymous\20namespace\29::RasterBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +6378:skif::\28anonymous\20namespace\29::RasterBackend::getBlurEngine\28\29\20const +6379:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10684 +6380:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +6381:skif::\28anonymous\20namespace\29::GaneshBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +6382:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +6383:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +6384:skif::\28anonymous\20namespace\29::GaneshBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +6385:skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +6386:skia_png_zalloc +6387:skia_png_write_rows +6388:skia_png_write_info +6389:skia_png_write_end +6390:skia_png_user_version_check +6391:skia_png_set_text +6392:skia_png_set_sRGB +6393:skia_png_set_keep_unknown_chunks +6394:skia_png_set_iCCP +6395:skia_png_set_gray_to_rgb +6396:skia_png_set_filter +6397:skia_png_set_filler +6398:skia_png_read_update_info +6399:skia_png_read_info +6400:skia_png_read_image +6401:skia_png_read_end +6402:skia_png_push_fill_buffer +6403:skia_png_process_data +6404:skia_png_default_write_data +6405:skia_png_default_read_data +6406:skia_png_default_flush +6407:skia_png_create_read_struct +6408:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29_8005 +6409:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29 +6410:skia::textlayout::TypefaceFontStyleSet::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +6411:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29_7998 +6412:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29 +6413:skia::textlayout::TypefaceFontProvider::onMatchFamily\28char\20const*\29\20const +6414:skia::textlayout::TypefaceFontProvider::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +6415:skia::textlayout::TypefaceFontProvider::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +6416:skia::textlayout::TypefaceFontProvider::onGetFamilyName\28int\2c\20SkString*\29\20const +6417:skia::textlayout::TypefaceFontProvider::onCreateStyleSet\28int\29\20const +6418:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29_7848 +6419:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29 +6420:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +6421:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +6422:skia::textlayout::PositionWithAffinity*\20emscripten::internal::raw_constructor\28\29 +6423:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29_7662 +6424:skia::textlayout::ParagraphImpl::visit\28std::__2::function\20const&\29 +6425:skia::textlayout::ParagraphImpl::updateTextAlign\28skia::textlayout::TextAlign\29 +6426:skia::textlayout::ParagraphImpl::updateForegroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +6427:skia::textlayout::ParagraphImpl::updateFontSize\28unsigned\20long\2c\20unsigned\20long\2c\20float\29 +6428:skia::textlayout::ParagraphImpl::updateBackgroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +6429:skia::textlayout::ParagraphImpl::unresolvedGlyphs\28\29 +6430:skia::textlayout::ParagraphImpl::unresolvedCodepoints\28\29 +6431:skia::textlayout::ParagraphImpl::paint\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\29 +6432:skia::textlayout::ParagraphImpl::paint\28SkCanvas*\2c\20float\2c\20float\29 +6433:skia::textlayout::ParagraphImpl::markDirty\28\29 +6434:skia::textlayout::ParagraphImpl::lineNumber\28\29 +6435:skia::textlayout::ParagraphImpl::layout\28float\29 +6436:skia::textlayout::ParagraphImpl::getWordBoundary\28unsigned\20int\29 +6437:skia::textlayout::ParagraphImpl::getRectsForRange\28unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +6438:skia::textlayout::ParagraphImpl::getRectsForPlaceholders\28\29 +6439:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +6440:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29 +6441:skia::textlayout::ParagraphImpl::getLineNumberAt\28unsigned\20long\29\20const +6442:skia::textlayout::ParagraphImpl::getLineNumberAtUTF16Offset\28unsigned\20long\29 +6443:skia::textlayout::ParagraphImpl::getLineMetrics\28std::__2::vector>&\29 +6444:skia::textlayout::ParagraphImpl::getLineMetricsAt\28int\2c\20skia::textlayout::LineMetrics*\29\20const +6445:skia::textlayout::ParagraphImpl::getGlyphPositionAtCoordinate\28float\2c\20float\29 +6446:skia::textlayout::ParagraphImpl::getFonts\28\29\20const +6447:skia::textlayout::ParagraphImpl::getFontAt\28unsigned\20long\29\20const +6448:skia::textlayout::ParagraphImpl::getFontAtUTF16Offset\28unsigned\20long\29 +6449:skia::textlayout::ParagraphImpl::getClosestUTF16GlyphInfoAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +6450:skia::textlayout::ParagraphImpl::getClosestGlyphClusterAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +6451:skia::textlayout::ParagraphImpl::getActualTextRange\28int\2c\20bool\29\20const +6452:skia::textlayout::ParagraphImpl::extendedVisit\28std::__2::function\20const&\29 +6453:skia::textlayout::ParagraphImpl::containsEmoji\28SkTextBlob*\29 +6454:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29::$_0::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +6455:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29 +6456:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29_7592 +6457:skia::textlayout::ParagraphBuilderImpl::setWordsUtf8\28std::__2::vector>\29 +6458:skia::textlayout::ParagraphBuilderImpl::setWordsUtf16\28std::__2::vector>\29 +6459:skia::textlayout::ParagraphBuilderImpl::setLineBreaksUtf8\28std::__2::vector>\29 +6460:skia::textlayout::ParagraphBuilderImpl::setLineBreaksUtf16\28std::__2::vector>\29 +6461:skia::textlayout::ParagraphBuilderImpl::setGraphemeBreaksUtf8\28std::__2::vector>\29 +6462:skia::textlayout::ParagraphBuilderImpl::setGraphemeBreaksUtf16\28std::__2::vector>\29 +6463:skia::textlayout::ParagraphBuilderImpl::pushStyle\28skia::textlayout::TextStyle\20const&\29 +6464:skia::textlayout::ParagraphBuilderImpl::pop\28\29 +6465:skia::textlayout::ParagraphBuilderImpl::peekStyle\28\29 +6466:skia::textlayout::ParagraphBuilderImpl::getText\28\29 +6467:skia::textlayout::ParagraphBuilderImpl::getParagraphStyle\28\29\20const +6468:skia::textlayout::ParagraphBuilderImpl::getClientICUData\28\29\20const +6469:skia::textlayout::ParagraphBuilderImpl::addText\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +6470:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\2c\20unsigned\20long\29 +6471:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\29 +6472:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\29 +6473:skia::textlayout::ParagraphBuilderImpl::SetUnicode\28sk_sp\29 +6474:skia::textlayout::ParagraphBuilderImpl::Reset\28\29 +6475:skia::textlayout::ParagraphBuilderImpl::RequiresClientICU\28\29 +6476:skia::textlayout::ParagraphBuilderImpl::Build\28\29 +6477:skia::textlayout::Paragraph::getMinIntrinsicWidth\28\29 +6478:skia::textlayout::Paragraph::getMaxWidth\28\29 +6479:skia::textlayout::Paragraph::getMaxIntrinsicWidth\28\29 +6480:skia::textlayout::Paragraph::getLongestLine\28\29 +6481:skia::textlayout::Paragraph::getIdeographicBaseline\28\29 +6482:skia::textlayout::Paragraph::getHeight\28\29 +6483:skia::textlayout::Paragraph::getAlphabeticBaseline\28\29 +6484:skia::textlayout::Paragraph::didExceedMaxLines\28\29 +6485:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29_7750 +6486:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29 +6487:skia::textlayout::OneLineShaper::~OneLineShaper\28\29_7518 +6488:skia::textlayout::OneLineShaper::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +6489:skia::textlayout::OneLineShaper::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +6490:skia::textlayout::LangIterator::~LangIterator\28\29_7574 +6491:skia::textlayout::LangIterator::~LangIterator\28\29 +6492:skia::textlayout::LangIterator::endOfCurrentRun\28\29\20const +6493:skia::textlayout::LangIterator::currentLanguage\28\29\20const +6494:skia::textlayout::LangIterator::consume\28\29 +6495:skia::textlayout::LangIterator::atEnd\28\29\20const +6496:skia::textlayout::FontCollection::~FontCollection\28\29_7487 +6497:skia::textlayout::CanvasParagraphPainter::translate\28float\2c\20float\29 +6498:skia::textlayout::CanvasParagraphPainter::save\28\29 +6499:skia::textlayout::CanvasParagraphPainter::restore\28\29 +6500:skia::textlayout::CanvasParagraphPainter::drawTextShadow\28sk_sp\20const&\2c\20float\2c\20float\2c\20unsigned\20int\2c\20float\29 +6501:skia::textlayout::CanvasParagraphPainter::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20std::__2::variant\20const&\29 +6502:skia::textlayout::CanvasParagraphPainter::drawRect\28SkRect\20const&\2c\20std::__2::variant\20const&\29 +6503:skia::textlayout::CanvasParagraphPainter::drawPath\28SkPath\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +6504:skia::textlayout::CanvasParagraphPainter::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +6505:skia::textlayout::CanvasParagraphPainter::drawFilledRect\28SkRect\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +6506:skia::textlayout::CanvasParagraphPainter::clipRect\28SkRect\20const&\29 +6507:skgpu::tess::FixedCountWedges::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +6508:skgpu::tess::FixedCountWedges::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +6509:skgpu::tess::FixedCountStrokes::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +6510:skgpu::tess::FixedCountCurves::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +6511:skgpu::tess::FixedCountCurves::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +6512:skgpu::ganesh::texture_proxy_view_from_planes\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20skgpu::Budgeted\29::$_0::__invoke\28void*\2c\20void*\29 +6513:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29_11558 +6514:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::visitProxies\28std::__2::function\20const&\29\20const +6515:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6516:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6517:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6518:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::name\28\29\20const +6519:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::fixedFunctionFlags\28\29\20const +6520:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6521:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::name\28\29\20const +6522:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +6523:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6524:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6525:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +6526:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29_11434 +6527:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29 +6528:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::name\28\29\20const +6529:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6530:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6531:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29_10831 +6532:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29 +6533:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +6534:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6535:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6536:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6537:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6538:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::name\28\29\20const +6539:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::fixedFunctionFlags\28\29\20const +6540:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6541:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29_10774 +6542:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29 +6543:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +6544:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6545:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6546:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6547:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6548:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::name\28\29\20const +6549:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6550:skgpu::ganesh::TriangulatingPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6551:skgpu::ganesh::TriangulatingPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6552:skgpu::ganesh::TriangulatingPathRenderer::name\28\29\20const +6553:skgpu::ganesh::TessellationPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +6554:skgpu::ganesh::TessellationPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +6555:skgpu::ganesh::TessellationPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6556:skgpu::ganesh::TessellationPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6557:skgpu::ganesh::TessellationPathRenderer::name\28\29\20const +6558:skgpu::ganesh::SurfaceDrawContext::willReplaceOpsTask\28skgpu::ganesh::OpsTask*\2c\20skgpu::ganesh::OpsTask*\29 +6559:skgpu::ganesh::SurfaceDrawContext::canDiscardPreviousOpsOnFullClear\28\29\20const +6560:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29_8961 +6561:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +6562:skgpu::ganesh::SurfaceContext::asyncReadPixels\28GrDirectContext*\2c\20SkIRect\20const&\2c\20SkColorType\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +6563:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29_11629 +6564:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29 +6565:skgpu::ganesh::StrokeTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +6566:skgpu::ganesh::StrokeTessellateOp::usesStencil\28\29\20const +6567:skgpu::ganesh::StrokeTessellateOp::onPrepare\28GrOpFlushState*\29 +6568:skgpu::ganesh::StrokeTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6569:skgpu::ganesh::StrokeTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6570:skgpu::ganesh::StrokeTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6571:skgpu::ganesh::StrokeTessellateOp::name\28\29\20const +6572:skgpu::ganesh::StrokeTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6573:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29_11607 +6574:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29 +6575:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +6576:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::programInfo\28\29 +6577:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6578:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6579:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6580:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::name\28\29\20const +6581:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6582:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29_11596 +6583:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29 +6584:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +6585:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::programInfo\28\29 +6586:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6587:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6588:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6589:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6590:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::name\28\29\20const +6591:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6592:skgpu::ganesh::StencilClip::~StencilClip\28\29_9976 +6593:skgpu::ganesh::StencilClip::~StencilClip\28\29 +6594:skgpu::ganesh::StencilClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +6595:skgpu::ganesh::StencilClip::getConservativeBounds\28\29\20const +6596:skgpu::ganesh::StencilClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +6597:skgpu::ganesh::SoftwarePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6598:skgpu::ganesh::SoftwarePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6599:skgpu::ganesh::SoftwarePathRenderer::name\28\29\20const +6600:skgpu::ganesh::SmallPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6601:skgpu::ganesh::SmallPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6602:skgpu::ganesh::SmallPathRenderer::name\28\29\20const +6603:skgpu::ganesh::SmallPathAtlasMgr::preFlush\28GrOnFlushResourceProvider*\29 +6604:skgpu::ganesh::SmallPathAtlasMgr::postFlush\28skgpu::AtlasToken\29 +6605:skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +6606:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29_11505 +6607:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29 +6608:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::visitProxies\28std::__2::function\20const&\29\20const +6609:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::programInfo\28\29 +6610:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +6611:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6612:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6613:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6614:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::name\28\29\20const +6615:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6616:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_quad_generic\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6617:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6618:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6619:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6620:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6621:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6622:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6623:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +6624:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29_11494 +6625:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29 +6626:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::onTextureSampler\28int\29\20const +6627:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::name\28\29\20const +6628:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +6629:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6630:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6631:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +6632:skgpu::ganesh::PathWedgeTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +6633:skgpu::ganesh::PathTessellator::~PathTessellator\28\29 +6634:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29_11469 +6635:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29 +6636:skgpu::ganesh::PathTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +6637:skgpu::ganesh::PathTessellateOp::usesStencil\28\29\20const +6638:skgpu::ganesh::PathTessellateOp::onPrepare\28GrOpFlushState*\29 +6639:skgpu::ganesh::PathTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6640:skgpu::ganesh::PathTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6641:skgpu::ganesh::PathTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6642:skgpu::ganesh::PathTessellateOp::name\28\29\20const +6643:skgpu::ganesh::PathTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6644:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29_11452 +6645:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29 +6646:skgpu::ganesh::PathStencilCoverOp::visitProxies\28std::__2::function\20const&\29\20const +6647:skgpu::ganesh::PathStencilCoverOp::onPrepare\28GrOpFlushState*\29 +6648:skgpu::ganesh::PathStencilCoverOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6649:skgpu::ganesh::PathStencilCoverOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6650:skgpu::ganesh::PathStencilCoverOp::name\28\29\20const +6651:skgpu::ganesh::PathStencilCoverOp::fixedFunctionFlags\28\29\20const +6652:skgpu::ganesh::PathStencilCoverOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6653:skgpu::ganesh::PathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +6654:skgpu::ganesh::PathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +6655:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29_11428 +6656:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29 +6657:skgpu::ganesh::PathInnerTriangulateOp::visitProxies\28std::__2::function\20const&\29\20const +6658:skgpu::ganesh::PathInnerTriangulateOp::onPrepare\28GrOpFlushState*\29 +6659:skgpu::ganesh::PathInnerTriangulateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6660:skgpu::ganesh::PathInnerTriangulateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6661:skgpu::ganesh::PathInnerTriangulateOp::name\28\29\20const +6662:skgpu::ganesh::PathInnerTriangulateOp::fixedFunctionFlags\28\29\20const +6663:skgpu::ganesh::PathInnerTriangulateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6664:skgpu::ganesh::PathCurveTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +6665:skgpu::ganesh::OpsTask::~OpsTask\28\29_11367 +6666:skgpu::ganesh::OpsTask::onPrepare\28GrOpFlushState*\29 +6667:skgpu::ganesh::OpsTask::onPrePrepare\28GrRecordingContext*\29 +6668:skgpu::ganesh::OpsTask::onMakeSkippable\28\29 +6669:skgpu::ganesh::OpsTask::onIsUsed\28GrSurfaceProxy*\29\20const +6670:skgpu::ganesh::OpsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +6671:skgpu::ganesh::OpsTask::endFlush\28GrDrawingManager*\29 +6672:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29_11339 +6673:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::visitProxies\28std::__2::function\20const&\29\20const +6674:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6675:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6676:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6677:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6678:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::name\28\29\20const +6679:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6680:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29_11351 +6681:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29 +6682:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::onTextureSampler\28int\29\20const +6683:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::name\28\29\20const +6684:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +6685:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6686:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6687:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +6688:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29_11130 +6689:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29 +6690:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +6691:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::programInfo\28\29 +6692:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +6693:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6694:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6695:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6696:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::name\28\29\20const +6697:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6698:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::clipToShape\28skgpu::ganesh::SurfaceDrawContext*\2c\20SkClipOp\2c\20SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\29 +6699:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29_11147 +6700:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29 +6701:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::name\28\29\20const +6702:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6703:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +6704:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6705:skgpu::ganesh::DrawableOp::~DrawableOp\28\29_11120 +6706:skgpu::ganesh::DrawableOp::~DrawableOp\28\29 +6707:skgpu::ganesh::DrawableOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6708:skgpu::ganesh::DrawableOp::name\28\29\20const +6709:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29_11023 +6710:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29 +6711:skgpu::ganesh::DrawAtlasPathOp::visitProxies\28std::__2::function\20const&\29\20const +6712:skgpu::ganesh::DrawAtlasPathOp::onPrepare\28GrOpFlushState*\29 +6713:skgpu::ganesh::DrawAtlasPathOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6714:skgpu::ganesh::DrawAtlasPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6715:skgpu::ganesh::DrawAtlasPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6716:skgpu::ganesh::DrawAtlasPathOp::name\28\29\20const +6717:skgpu::ganesh::DrawAtlasPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6718:skgpu::ganesh::Device::~Device\28\29_8585 +6719:skgpu::ganesh::Device::~Device\28\29 +6720:skgpu::ganesh::Device::strikeDeviceInfo\28\29\20const +6721:skgpu::ganesh::Device::snapSpecial\28SkIRect\20const&\2c\20bool\29 +6722:skgpu::ganesh::Device::snapSpecialScaled\28SkIRect\20const&\2c\20SkISize\20const&\29 +6723:skgpu::ganesh::Device::replaceClip\28SkIRect\20const&\29 +6724:skgpu::ganesh::Device::recordingContext\28\29\20const +6725:skgpu::ganesh::Device::pushClipStack\28\29 +6726:skgpu::ganesh::Device::popClipStack\28\29 +6727:skgpu::ganesh::Device::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +6728:skgpu::ganesh::Device::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +6729:skgpu::ganesh::Device::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +6730:skgpu::ganesh::Device::onClipShader\28sk_sp\29 +6731:skgpu::ganesh::Device::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +6732:skgpu::ganesh::Device::makeSpecial\28SkImage\20const*\29 +6733:skgpu::ganesh::Device::isClipWideOpen\28\29\20const +6734:skgpu::ganesh::Device::isClipRect\28\29\20const +6735:skgpu::ganesh::Device::isClipEmpty\28\29\20const +6736:skgpu::ganesh::Device::isClipAntiAliased\28\29\20const +6737:skgpu::ganesh::Device::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +6738:skgpu::ganesh::Device::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +6739:skgpu::ganesh::Device::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +6740:skgpu::ganesh::Device::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +6741:skgpu::ganesh::Device::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +6742:skgpu::ganesh::Device::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +6743:skgpu::ganesh::Device::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +6744:skgpu::ganesh::Device::drawPaint\28SkPaint\20const&\29 +6745:skgpu::ganesh::Device::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +6746:skgpu::ganesh::Device::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +6747:skgpu::ganesh::Device::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +6748:skgpu::ganesh::Device::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +6749:skgpu::ganesh::Device::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +6750:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +6751:skgpu::ganesh::Device::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +6752:skgpu::ganesh::Device::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +6753:skgpu::ganesh::Device::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +6754:skgpu::ganesh::Device::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +6755:skgpu::ganesh::Device::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +6756:skgpu::ganesh::Device::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +6757:skgpu::ganesh::Device::devClipBounds\28\29\20const +6758:skgpu::ganesh::Device::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +6759:skgpu::ganesh::Device::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +6760:skgpu::ganesh::Device::convertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +6761:skgpu::ganesh::Device::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +6762:skgpu::ganesh::Device::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +6763:skgpu::ganesh::Device::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +6764:skgpu::ganesh::Device::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +6765:skgpu::ganesh::Device::android_utils_clipWithStencil\28\29 +6766:skgpu::ganesh::DefaultPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +6767:skgpu::ganesh::DefaultPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +6768:skgpu::ganesh::DefaultPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6769:skgpu::ganesh::DefaultPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6770:skgpu::ganesh::DefaultPathRenderer::name\28\29\20const +6771:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::name\28\29\20const +6772:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6773:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +6774:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6775:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::name\28\29\20const +6776:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +6777:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +6778:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +6779:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29_10946 +6780:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29 +6781:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::visitProxies\28std::__2::function\20const&\29\20const +6782:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::programInfo\28\29 +6783:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +6784:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6785:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +6786:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6787:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::name\28\29\20const +6788:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::fixedFunctionFlags\28\29\20const +6789:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6790:skgpu::ganesh::DashLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6791:skgpu::ganesh::DashLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6792:skgpu::ganesh::DashLinePathRenderer::name\28\29\20const +6793:skgpu::ganesh::ClipStack::~ClipStack\28\29_8547 +6794:skgpu::ganesh::ClipStack::preApply\28SkRect\20const&\2c\20GrAA\29\20const +6795:skgpu::ganesh::ClipStack::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +6796:skgpu::ganesh::ClearOp::~ClearOp\28\29 +6797:skgpu::ganesh::ClearOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6798:skgpu::ganesh::ClearOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6799:skgpu::ganesh::ClearOp::name\28\29\20const +6800:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29_10918 +6801:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29 +6802:skgpu::ganesh::AtlasTextOp::visitProxies\28std::__2::function\20const&\29\20const +6803:skgpu::ganesh::AtlasTextOp::onPrepareDraws\28GrMeshDrawTarget*\29 +6804:skgpu::ganesh::AtlasTextOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +6805:skgpu::ganesh::AtlasTextOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +6806:skgpu::ganesh::AtlasTextOp::name\28\29\20const +6807:skgpu::ganesh::AtlasTextOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +6808:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29_10897 +6809:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29 +6810:skgpu::ganesh::AtlasRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +6811:skgpu::ganesh::AtlasRenderTask::onExecute\28GrOpFlushState*\29 +6812:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10861 +6813:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +6814:skgpu::ganesh::AtlasPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6815:skgpu::ganesh::AtlasPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6816:skgpu::ganesh::AtlasPathRenderer::name\28\29\20const +6817:skgpu::ganesh::AALinearizingConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6818:skgpu::ganesh::AALinearizingConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6819:skgpu::ganesh::AALinearizingConvexPathRenderer::name\28\29\20const +6820:skgpu::ganesh::AAHairLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6821:skgpu::ganesh::AAHairLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6822:skgpu::ganesh::AAHairLinePathRenderer::name\28\29\20const +6823:skgpu::ganesh::AAConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +6824:skgpu::ganesh::AAConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +6825:skgpu::ganesh::AAConvexPathRenderer::name\28\29\20const +6826:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29_10020 +6827:skgpu::TAsyncReadResult::rowBytes\28int\29\20const +6828:skgpu::TAsyncReadResult::data\28int\29\20const +6829:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29_9453 +6830:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29 +6831:skgpu::StringKeyBuilder::appendComment\28char\20const*\29 +6832:skgpu::StringKeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +6833:skgpu::ShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\2c\20bool\29 +6834:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29_12391 +6835:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29 +6836:skgpu::RectanizerSkyline::reset\28\29 +6837:skgpu::RectanizerSkyline::percentFull\28\29\20const +6838:skgpu::RectanizerPow2::reset\28\29 +6839:skgpu::RectanizerPow2::percentFull\28\29\20const +6840:skgpu::RectanizerPow2::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +6841:skgpu::Plot::~Plot\28\29_12366 +6842:skgpu::Plot::~Plot\28\29 +6843:skgpu::KeyBuilder::~KeyBuilder\28\29 +6844:skgpu::KeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +6845:skgpu::DefaultShaderErrorHandler\28\29::DefaultShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\29 +6846:sk_write_fn\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20long\29 +6847:sk_sp*\20emscripten::internal::MemberAccess>::getWire\28sk_sp\20SimpleImageInfo::*\20const&\2c\20SimpleImageInfo&\29 +6848:sk_read_user_chunk\28png_struct_def*\2c\20png_unknown_chunk_t*\29 +6849:sk_mmap_releaseproc\28void\20const*\2c\20void*\29 +6850:sk_ft_stream_io\28FT_StreamRec_*\2c\20unsigned\20long\2c\20unsigned\20char*\2c\20unsigned\20long\29 +6851:sk_ft_realloc\28FT_MemoryRec_*\2c\20long\2c\20long\2c\20void*\29 +6852:sk_ft_free\28FT_MemoryRec_*\2c\20void*\29 +6853:sk_ft_alloc\28FT_MemoryRec_*\2c\20long\29 +6854:sk_dataref_releaseproc\28void\20const*\2c\20void*\29 +6855:sfnt_table_info +6856:sfnt_load_face +6857:sfnt_is_postscript +6858:sfnt_is_alphanumeric +6859:sfnt_init_face +6860:sfnt_get_ps_name +6861:sfnt_get_name_index +6862:sfnt_get_name_id +6863:sfnt_get_interface +6864:sfnt_get_glyph_name +6865:sfnt_get_charset_id +6866:sfnt_done_face +6867:setup_syllables_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6868:setup_syllables_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6869:setup_syllables_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6870:setup_syllables_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6871:setup_masks_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6872:setup_masks_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6873:setup_masks_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6874:setup_masks_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6875:setup_masks_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6876:setup_masks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6877:sep_upsample +6878:self_destruct +6879:save_marker +6880:sample8\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6881:sample6\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6882:sample4\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6883:sample2\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6884:sample1\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +6885:rgb_rgb_convert +6886:rgb_rgb565_convert +6887:rgb_rgb565D_convert +6888:rgb_gray_convert +6889:reverse_hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +6890:reverse_hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +6891:reset_marker_reader +6892:reset_input_controller +6893:reset_error_mgr +6894:request_virt_sarray +6895:request_virt_barray +6896:reorder_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6897:reorder_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6898:reorder_marks_hebrew\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6899:reorder_marks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +6900:reorder_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6901:release_data\28void*\2c\20void*\29 +6902:record_stch\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6903:record_rphf_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6904:record_pref_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +6905:realize_virt_arrays +6906:read_restart_marker +6907:read_markers +6908:read_data_from_FT_Stream +6909:quantize_ord_dither +6910:quantize_fs_dither +6911:quantize3_ord_dither +6912:psnames_get_service +6913:pshinter_get_t2_funcs +6914:pshinter_get_t1_funcs +6915:pshinter_get_globals_funcs +6916:psh_globals_new +6917:psh_globals_destroy +6918:psaux_get_glyph_name +6919:ps_table_release +6920:ps_table_new +6921:ps_table_done +6922:ps_table_add +6923:ps_property_set +6924:ps_property_get +6925:ps_parser_to_token_array +6926:ps_parser_to_int +6927:ps_parser_to_fixed_array +6928:ps_parser_to_fixed +6929:ps_parser_to_coord_array +6930:ps_parser_to_bytes +6931:ps_parser_skip_spaces +6932:ps_parser_load_field_table +6933:ps_parser_init +6934:ps_hints_t2mask +6935:ps_hints_t2counter +6936:ps_hints_t1stem3 +6937:ps_hints_t1reset +6938:ps_hints_close +6939:ps_hints_apply +6940:ps_hinter_init +6941:ps_hinter_done +6942:ps_get_standard_strings +6943:ps_get_macintosh_name +6944:ps_decoder_init +6945:ps_builder_init +6946:progress_monitor\28jpeg_common_struct*\29 +6947:process_data_simple_main +6948:process_data_crank_post +6949:process_data_context_main +6950:prescan_quantize +6951:preprocess_text_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6952:preprocess_text_thai\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6953:preprocess_text_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6954:preprocess_text_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6955:prepare_for_output_pass +6956:premultiply_data +6957:premul_rgb\28SkRGBA4f<\28SkAlphaType\292>\29 +6958:premul_polar\28SkRGBA4f<\28SkAlphaType\292>\29 +6959:postprocess_glyphs_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +6960:post_process_prepass +6961:post_process_2pass +6962:post_process_1pass +6963:portable::xy_to_unit_angle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6964:portable::xy_to_radius\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6965:portable::xy_to_2pt_conical_well_behaved\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6966:portable::xy_to_2pt_conical_strip\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6967:portable::xy_to_2pt_conical_smaller\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6968:portable::xy_to_2pt_conical_greater\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6969:portable::xy_to_2pt_conical_focal_on_circle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6970:portable::xor_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6971:portable::white_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6972:portable::unpremul_polar\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6973:portable::unpremul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6974:portable::uniform_color_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6975:portable::trace_var\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6976:portable::trace_scope\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6977:portable::trace_line\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6978:portable::trace_exit\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6979:portable::trace_enter\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6980:portable::tan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6981:portable::swizzle_copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6982:portable::swizzle_copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6983:portable::swizzle_copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6984:portable::swizzle_copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6985:portable::swizzle_copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6986:portable::swizzle_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6987:portable::swizzle_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6988:portable::swizzle_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6989:portable::swizzle_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6990:portable::swizzle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6991:portable::swap_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6992:portable::swap_rb_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6993:portable::swap_rb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6994:portable::sub_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6995:portable::sub_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6996:portable::sub_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6997:portable::sub_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6998:portable::sub_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +6999:portable::sub_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7000:portable::sub_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7001:portable::sub_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7002:portable::sub_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7003:portable::sub_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7004:portable::store_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7005:portable::store_src_a\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7006:portable::store_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7007:portable::store_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7008:portable::store_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7009:portable::store_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7010:portable::store_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7011:portable::store_r8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7012:portable::store_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7013:portable::store_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7014:portable::store_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7015:portable::store_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7016:portable::store_device_xy01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7017:portable::store_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7018:portable::store_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7019:portable::store_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7020:portable::store_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7021:portable::store_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7022:portable::store_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7023:portable::store_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7024:portable::store_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7025:portable::store_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7026:portable::store_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7027:portable::store_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7028:portable::store_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7029:portable::start_pipeline\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkRasterPipelineStage*\2c\20SkSpan\2c\20unsigned\20char*\29 +7030:portable::stack_rewind\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7031:portable::stack_checkpoint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7032:portable::srcover_rgba_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7033:portable::srcover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7034:portable::srcout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7035:portable::srcin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7036:portable::srcatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7037:portable::sqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7038:portable::splat_4_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7039:portable::splat_3_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7040:portable::splat_2_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7041:portable::softlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7042:portable::smoothstep_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7043:portable::sin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7044:portable::shuffle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7045:portable::set_base_pointer\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7046:portable::seed_shader\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7047:portable::screen\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7048:portable::scale_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7049:portable::scale_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7050:portable::scale_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7051:portable::scale_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7052:portable::saturation\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7053:portable::rgb_to_hsl\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7054:portable::repeat_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7055:portable::repeat_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7056:portable::repeat_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7057:portable::refract_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7058:portable::reenable_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7059:portable::rect_memset64\28unsigned\20long\20long*\2c\20unsigned\20long\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +7060:portable::rect_memset32\28unsigned\20int*\2c\20unsigned\20int\2c\20int\2c\20unsigned\20long\2c\20int\29 +7061:portable::rect_memset16\28unsigned\20short*\2c\20unsigned\20short\2c\20int\2c\20unsigned\20long\2c\20int\29 +7062:portable::premul_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7063:portable::premul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7064:portable::pow_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7065:portable::plus_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7066:portable::perlin_noise\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7067:portable::parametric\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7068:portable::overlay\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7069:portable::negate_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7070:portable::multiply\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7071:portable::mul_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7072:portable::mul_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7073:portable::mul_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7074:portable::mul_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7075:portable::mul_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7076:portable::mul_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7077:portable::mul_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7078:portable::mul_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7079:portable::mul_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7080:portable::mul_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7081:portable::mul_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7082:portable::mul_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7083:portable::move_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7084:portable::move_dst_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7085:portable::modulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7086:portable::mod_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7087:portable::mod_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7088:portable::mod_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7089:portable::mod_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7090:portable::mod_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7091:portable::mix_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7092:portable::mix_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7093:portable::mix_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7094:portable::mix_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7095:portable::mix_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7096:portable::mix_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7097:portable::mix_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7098:portable::mix_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7099:portable::mix_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7100:portable::mix_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7101:portable::mirror_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7102:portable::mirror_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7103:portable::mirror_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7104:portable::mipmap_linear_update\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7105:portable::mipmap_linear_init\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7106:portable::mipmap_linear_finish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7107:portable::min_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7108:portable::min_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7109:portable::min_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7110:portable::min_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7111:portable::min_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7112:portable::min_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7113:portable::min_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7114:portable::min_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7115:portable::min_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7116:portable::min_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7117:portable::min_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7118:portable::min_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7119:portable::min_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7120:portable::min_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7121:portable::min_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7122:portable::min_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7123:portable::merge_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7124:portable::merge_inv_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7125:portable::merge_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7126:portable::memset32\28unsigned\20int*\2c\20unsigned\20int\2c\20int\29 +7127:portable::memset16\28unsigned\20short*\2c\20unsigned\20short\2c\20int\29 +7128:portable::max_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7129:portable::max_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7130:portable::max_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7131:portable::max_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7132:portable::max_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7133:portable::max_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7134:portable::max_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7135:portable::max_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7136:portable::max_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7137:portable::max_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7138:portable::max_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7139:portable::max_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7140:portable::max_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7141:portable::max_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7142:portable::max_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7143:portable::max_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7144:portable::matrix_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7145:portable::matrix_scale_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7146:portable::matrix_perspective\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7147:portable::matrix_multiply_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7148:portable::matrix_multiply_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7149:portable::matrix_multiply_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7150:portable::matrix_4x5\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7151:portable::matrix_4x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7152:portable::matrix_3x4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7153:portable::matrix_3x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7154:portable::matrix_2x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7155:portable::mask_off_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7156:portable::mask_off_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7157:portable::mask_2pt_conical_nan\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7158:portable::mask_2pt_conical_degenerates\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7159:portable::luminosity\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7160:portable::log_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7161:portable::log2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7162:portable::load_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7163:portable::load_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7164:portable::load_rgf16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7165:portable::load_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7166:portable::load_rg88_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7167:portable::load_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7168:portable::load_rg1616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7169:portable::load_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7170:portable::load_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7171:portable::load_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7172:portable::load_f32_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7173:portable::load_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7174:portable::load_f16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7175:portable::load_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7176:portable::load_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7177:portable::load_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7178:portable::load_af16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7179:portable::load_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7180:portable::load_a8_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7181:portable::load_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7182:portable::load_a16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7183:portable::load_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7184:portable::load_8888_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7185:portable::load_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7186:portable::load_565_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7187:portable::load_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7188:portable::load_4444_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7189:portable::load_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7190:portable::load_16161616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7191:portable::load_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7192:portable::load_10x6_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7193:portable::load_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7194:portable::load_1010102_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7195:portable::load_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7196:portable::load_1010102_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7197:portable::load_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7198:portable::load_10101010_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7199:portable::load_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7200:portable::lighten\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7201:portable::lerp_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7202:portable::lerp_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7203:portable::lerp_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7204:portable::lerp_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7205:portable::just_return\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7206:portable::jump\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7207:portable::invsqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7208:portable::invsqrt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7209:portable::invsqrt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7210:portable::invsqrt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7211:portable::inverted_CMYK_to_RGB1\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7212:portable::inverted_CMYK_to_BGR1\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7213:portable::inverse_mat4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7214:portable::inverse_mat3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7215:portable::inverse_mat2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7216:portable::init_lane_masks\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7217:portable::hue\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7218:portable::hsl_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7219:portable::hardlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7220:portable::gray_to_RGB1\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7221:portable::grayA_to_rgbA\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7222:portable::grayA_to_RGBA\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7223:portable::gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7224:portable::gauss_a_to_rgba\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7225:portable::gather_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7226:portable::gather_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7227:portable::gather_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7228:portable::gather_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7229:portable::gather_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7230:portable::gather_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7231:portable::gather_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7232:portable::gather_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7233:portable::gather_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7234:portable::gather_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7235:portable::gather_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7236:portable::gather_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7237:portable::gather_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7238:portable::gather_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7239:portable::gather_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7240:portable::gather_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7241:portable::gamma_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7242:portable::force_opaque_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7243:portable::force_opaque\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7244:portable::floor_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7245:portable::floor_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7246:portable::floor_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7247:portable::floor_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7248:portable::exp_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7249:portable::exp2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7250:portable::exclusion\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7251:portable::exchange_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7252:portable::evenly_spaced_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7253:portable::evenly_spaced_2_stop_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7254:portable::emboss\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7255:portable::dstover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7256:portable::dstout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7257:portable::dstin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7258:portable::dstatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7259:portable::dot_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7260:portable::dot_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7261:portable::dot_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7262:portable::div_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7263:portable::div_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7264:portable::div_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7265:portable::div_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7266:portable::div_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7267:portable::div_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7268:portable::div_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7269:portable::div_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7270:portable::div_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7271:portable::div_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7272:portable::div_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7273:portable::div_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7274:portable::div_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7275:portable::div_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7276:portable::div_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7277:portable::dither\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7278:portable::difference\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7279:portable::decal_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7280:portable::decal_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7281:portable::decal_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7282:portable::darken\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7283:portable::css_oklab_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7284:portable::css_oklab_gamut_map_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7285:portable::css_lab_to_xyz\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7286:portable::css_hwb_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7287:portable::css_hsl_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7288:portable::css_hcl_to_lab\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7289:portable::cos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7290:portable::copy_uniform\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7291:portable::copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7292:portable::copy_slot_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7293:portable::copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7294:portable::copy_immutable_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7295:portable::copy_constant\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7296:portable::copy_4_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7297:portable::copy_4_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7298:portable::copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7299:portable::copy_4_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7300:portable::copy_3_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7301:portable::copy_3_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7302:portable::copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7303:portable::copy_3_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7304:portable::copy_2_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7305:portable::copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7306:portable::continue_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7307:portable::colordodge\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7308:portable::colorburn\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7309:portable::color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7310:portable::cmpne_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7311:portable::cmpne_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7312:portable::cmpne_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7313:portable::cmpne_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7314:portable::cmpne_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7315:portable::cmpne_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7316:portable::cmpne_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7317:portable::cmpne_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7318:portable::cmpne_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7319:portable::cmpne_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7320:portable::cmpne_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7321:portable::cmpne_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7322:portable::cmplt_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7323:portable::cmplt_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7324:portable::cmplt_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7325:portable::cmplt_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7326:portable::cmplt_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7327:portable::cmplt_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7328:portable::cmplt_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7329:portable::cmplt_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7330:portable::cmplt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7331:portable::cmplt_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7332:portable::cmplt_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7333:portable::cmplt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7334:portable::cmplt_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7335:portable::cmplt_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7336:portable::cmplt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7337:portable::cmplt_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7338:portable::cmplt_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7339:portable::cmplt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7340:portable::cmple_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7341:portable::cmple_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7342:portable::cmple_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7343:portable::cmple_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7344:portable::cmple_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7345:portable::cmple_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7346:portable::cmple_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7347:portable::cmple_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7348:portable::cmple_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7349:portable::cmple_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7350:portable::cmple_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7351:portable::cmple_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7352:portable::cmple_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7353:portable::cmple_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7354:portable::cmple_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7355:portable::cmple_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7356:portable::cmple_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7357:portable::cmple_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7358:portable::cmpeq_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7359:portable::cmpeq_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7360:portable::cmpeq_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7361:portable::cmpeq_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7362:portable::cmpeq_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7363:portable::cmpeq_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7364:portable::cmpeq_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7365:portable::cmpeq_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7366:portable::cmpeq_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7367:portable::cmpeq_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7368:portable::cmpeq_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7369:portable::cmpeq_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7370:portable::clear\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7371:portable::clamp_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7372:portable::clamp_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7373:portable::clamp_gamut\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7374:portable::clamp_a_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7375:portable::clamp_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7376:portable::ceil_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7377:portable::ceil_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7378:portable::ceil_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7379:portable::ceil_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7380:portable::cast_to_uint_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7381:portable::cast_to_uint_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7382:portable::cast_to_uint_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7383:portable::cast_to_uint_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7384:portable::cast_to_int_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7385:portable::cast_to_int_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7386:portable::cast_to_int_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7387:portable::cast_to_int_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7388:portable::cast_to_float_from_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7389:portable::cast_to_float_from_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7390:portable::cast_to_float_from_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7391:portable::cast_to_float_from_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7392:portable::cast_to_float_from_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7393:portable::cast_to_float_from_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7394:portable::cast_to_float_from_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7395:portable::cast_to_float_from_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7396:portable::case_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7397:portable::callback\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7398:portable::byte_tables\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7399:portable::bt709_luminance_or_luma_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7400:portable::bt709_luminance_or_luma_to_alpha\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7401:portable::branch_if_no_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7402:portable::branch_if_no_active_lanes_eq\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7403:portable::branch_if_any_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7404:portable::branch_if_all_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7405:portable::blit_row_s32a_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +7406:portable::black_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7407:portable::bitwise_xor_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7408:portable::bitwise_xor_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7409:portable::bitwise_xor_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7410:portable::bitwise_xor_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7411:portable::bitwise_xor_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7412:portable::bitwise_xor_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7413:portable::bitwise_or_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7414:portable::bitwise_or_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7415:portable::bitwise_or_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7416:portable::bitwise_or_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7417:portable::bitwise_or_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7418:portable::bitwise_and_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7419:portable::bitwise_and_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7420:portable::bitwise_and_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7421:portable::bitwise_and_imm_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7422:portable::bitwise_and_imm_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7423:portable::bitwise_and_imm_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7424:portable::bitwise_and_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7425:portable::bitwise_and_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7426:portable::bitwise_and_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7427:portable::bilinear_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7428:portable::bilinear_py\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7429:portable::bilinear_px\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7430:portable::bilinear_ny\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7431:portable::bilinear_nx\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7432:portable::bilerp_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7433:portable::bicubic_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7434:portable::bicubic_p3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7435:portable::bicubic_p3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7436:portable::bicubic_p1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7437:portable::bicubic_p1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7438:portable::bicubic_n3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7439:portable::bicubic_n3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7440:portable::bicubic_n1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7441:portable::bicubic_n1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7442:portable::bicubic_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7443:portable::atan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7444:portable::atan2_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7445:portable::asin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7446:portable::alter_2pt_conical_unswap\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7447:portable::alter_2pt_conical_compensate_focal\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7448:portable::alpha_to_red_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7449:portable::alpha_to_red\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7450:portable::alpha_to_gray_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7451:portable::alpha_to_gray\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7452:portable::add_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7453:portable::add_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7454:portable::add_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7455:portable::add_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7456:portable::add_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7457:portable::add_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7458:portable::add_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7459:portable::add_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7460:portable::add_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7461:portable::add_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7462:portable::add_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7463:portable::add_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7464:portable::acos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7465:portable::accumulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7466:portable::abs_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7467:portable::abs_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7468:portable::abs_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7469:portable::abs_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7470:portable::RGB_to_RGB1\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7471:portable::RGB_to_BGR1\28unsigned\20int*\2c\20unsigned\20char\20const*\2c\20int\29 +7472:portable::RGBA_to_rgbA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7473:portable::RGBA_to_bgrA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7474:portable::RGBA_to_BGRA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +7475:portable::PQish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7476:portable::HLGish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7477:portable::HLGinvish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +7478:pop_arg_long_double +7479:png_read_filter_row_up +7480:png_read_filter_row_sub +7481:png_read_filter_row_path_multibyte_pixel +7482:png_read_filter_row_path_1byte_pixel +7483:png_read_filter_row_avg +7484:pass2_no_dither +7485:pass2_fs_dither +7486:override_features_khmer\28hb_ot_shape_planner_t*\29 +7487:override_features_indic\28hb_ot_shape_planner_t*\29 +7488:override_features_hangul\28hb_ot_shape_planner_t*\29 +7489:output_message\28jpeg_common_struct*\29 +7490:output_message +7491:operator\20delete\28void*\2c\20unsigned\20long\29 +7492:null_convert +7493:noop_upsample +7494:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_16159 +7495:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +7496:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_16078 +7497:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +7498:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10697 +7499:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10696 +7500:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10694 +7501:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +7502:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +7503:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +7504:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11533 +7505:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +7506:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +7507:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10865 +7508:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +7509:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +7510:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +7511:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +7512:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +7513:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +7514:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +7515:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12566 +7516:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +7517:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +7518:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +7519:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::glyphCount\28\29\20const +7520:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +7521:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +7522:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +7523:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +7524:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +7525:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +7526:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9842 +7527:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +7528:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7529:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7530:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7531:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +7532:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29_9374 +7533:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29 +7534:non-virtual\20thunk\20to\20GrOpFlushState::writeView\28\29\20const +7535:non-virtual\20thunk\20to\20GrOpFlushState::usesMSAASurface\28\29\20const +7536:non-virtual\20thunk\20to\20GrOpFlushState::threadSafeCache\28\29\20const +7537:non-virtual\20thunk\20to\20GrOpFlushState::strikeCache\28\29\20const +7538:non-virtual\20thunk\20to\20GrOpFlushState::smallPathAtlasManager\28\29\20const +7539:non-virtual\20thunk\20to\20GrOpFlushState::sampledProxyArray\28\29 +7540:non-virtual\20thunk\20to\20GrOpFlushState::rtProxy\28\29\20const +7541:non-virtual\20thunk\20to\20GrOpFlushState::resourceProvider\28\29\20const +7542:non-virtual\20thunk\20to\20GrOpFlushState::renderPassBarriers\28\29\20const +7543:non-virtual\20thunk\20to\20GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +7544:non-virtual\20thunk\20to\20GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +7545:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndirectDraws\28int\29 +7546:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndices\28int\29 +7547:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +7548:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +7549:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +7550:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +7551:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +7552:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +7553:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +7554:non-virtual\20thunk\20to\20GrOpFlushState::dstProxyView\28\29\20const +7555:non-virtual\20thunk\20to\20GrOpFlushState::detachAppliedClip\28\29 +7556:non-virtual\20thunk\20to\20GrOpFlushState::deferredUploadTarget\28\29 +7557:non-virtual\20thunk\20to\20GrOpFlushState::colorLoadOp\28\29\20const +7558:non-virtual\20thunk\20to\20GrOpFlushState::caps\28\29\20const +7559:non-virtual\20thunk\20to\20GrOpFlushState::atlasManager\28\29\20const +7560:non-virtual\20thunk\20to\20GrOpFlushState::appliedClip\28\29\20const +7561:non-virtual\20thunk\20to\20GrGpuBuffer::~GrGpuBuffer\28\29 +7562:non-virtual\20thunk\20to\20GrGpuBuffer::unref\28\29\20const +7563:non-virtual\20thunk\20to\20GrGpuBuffer::ref\28\29\20const +7564:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_12300 +7565:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +7566:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onSetLabel\28\29 +7567:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +7568:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +7569:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +7570:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7571:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::backendFormat\28\29\20const +7572:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10587 +7573:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +7574:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +7575:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +7576:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::dstColor\28\29 +7577:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29_11942 +7578:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29 +7579:new_color_map_2_quant +7580:new_color_map_1_quant +7581:merged_2v_upsample +7582:merged_1v_upsample +7583:lin_srgb_to_oklab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +7584:lin_srgb_to_okhcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +7585:legalstub$dynCall_vijiii +7586:legalstub$dynCall_viji +7587:legalstub$dynCall_vij +7588:legalstub$dynCall_viijii +7589:legalstub$dynCall_viiiiij +7590:legalstub$dynCall_jiji +7591:legalstub$dynCall_jiiiiji +7592:legalstub$dynCall_jiiiiii +7593:legalstub$dynCall_jii +7594:legalstub$dynCall_ji +7595:legalstub$dynCall_iijj +7596:legalstub$dynCall_iiiiijj +7597:legalstub$dynCall_iiiiij +7598:legalstub$dynCall_iiiiiijj +7599:lcd_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +7600:jpeg_start_output +7601:jpeg_start_decompress +7602:jpeg_skip_scanlines +7603:jpeg_save_markers +7604:jpeg_resync_to_restart +7605:jpeg_read_scanlines +7606:jpeg_read_raw_data +7607:jpeg_read_header +7608:jpeg_input_complete +7609:jpeg_idct_islow +7610:jpeg_idct_ifast +7611:jpeg_idct_float +7612:jpeg_idct_9x9 +7613:jpeg_idct_7x7 +7614:jpeg_idct_6x6 +7615:jpeg_idct_5x5 +7616:jpeg_idct_4x4 +7617:jpeg_idct_3x3 +7618:jpeg_idct_2x2 +7619:jpeg_idct_1x1 +7620:jpeg_idct_16x16 +7621:jpeg_idct_15x15 +7622:jpeg_idct_14x14 +7623:jpeg_idct_13x13 +7624:jpeg_idct_12x12 +7625:jpeg_idct_11x11 +7626:jpeg_idct_10x10 +7627:jpeg_finish_output +7628:jpeg_destroy_decompress +7629:jpeg_crop_scanline +7630:is_deleted_glyph\28hb_glyph_info_t\20const*\29 +7631:internal_memalign +7632:int_upsample +7633:initial_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7634:hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +7635:hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +7636:hb_unicode_script_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +7637:hb_unicode_general_category_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +7638:hb_ucd_script\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +7639:hb_ucd_mirroring\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +7640:hb_ucd_general_category\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +7641:hb_ucd_decompose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20void*\29 +7642:hb_ucd_compose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +7643:hb_ucd_combining_class\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +7644:hb_syllabic_clear_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7645:hb_paint_sweep_gradient_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7646:hb_paint_push_transform_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7647:hb_paint_push_clip_rectangle_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7648:hb_paint_image_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +7649:hb_paint_extents_push_transform\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7650:hb_paint_extents_push_group\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +7651:hb_paint_extents_push_clip_rectangle\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7652:hb_paint_extents_push_clip_glyph\28hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_font_t*\2c\20void*\29 +7653:hb_paint_extents_pop_transform\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +7654:hb_paint_extents_pop_group\28hb_paint_funcs_t*\2c\20void*\2c\20hb_paint_composite_mode_t\2c\20void*\29 +7655:hb_paint_extents_pop_clip\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +7656:hb_paint_extents_paint_sweep_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7657:hb_paint_extents_paint_image\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +7658:hb_paint_extents_paint_color\28hb_paint_funcs_t*\2c\20void*\2c\20int\2c\20unsigned\20int\2c\20void*\29 +7659:hb_outline_recording_pen_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7660:hb_outline_recording_pen_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +7661:hb_outline_recording_pen_line_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +7662:hb_outline_recording_pen_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7663:hb_outline_recording_pen_close_path\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +7664:hb_ot_paint_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +7665:hb_ot_map_t::lookup_map_t::cmp\28void\20const*\2c\20void\20const*\29 +7666:hb_ot_map_t::feature_map_t::cmp\28void\20const*\2c\20void\20const*\29 +7667:hb_ot_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +7668:hb_ot_get_variation_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +7669:hb_ot_get_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +7670:hb_ot_get_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +7671:hb_ot_get_glyph_v_origin\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7672:hb_ot_get_glyph_v_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +7673:hb_ot_get_glyph_name\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +7674:hb_ot_get_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +7675:hb_ot_get_glyph_from_name\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +7676:hb_ot_get_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +7677:hb_ot_get_font_v_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +7678:hb_ot_get_font_h_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +7679:hb_ot_draw_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +7680:hb_font_paint_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +7681:hb_font_get_variation_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +7682:hb_font_get_nominal_glyphs_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +7683:hb_font_get_nominal_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +7684:hb_font_get_nominal_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +7685:hb_font_get_glyph_v_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7686:hb_font_get_glyph_v_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7687:hb_font_get_glyph_v_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +7688:hb_font_get_glyph_v_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +7689:hb_font_get_glyph_v_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +7690:hb_font_get_glyph_v_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +7691:hb_font_get_glyph_name_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +7692:hb_font_get_glyph_name_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +7693:hb_font_get_glyph_h_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7694:hb_font_get_glyph_h_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7695:hb_font_get_glyph_h_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +7696:hb_font_get_glyph_h_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +7697:hb_font_get_glyph_h_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +7698:hb_font_get_glyph_h_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +7699:hb_font_get_glyph_from_name_default\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +7700:hb_font_get_glyph_extents_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +7701:hb_font_get_glyph_extents_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +7702:hb_font_get_glyph_contour_point_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7703:hb_font_get_glyph_contour_point_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +7704:hb_font_get_font_v_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +7705:hb_font_get_font_h_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +7706:hb_font_draw_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +7707:hb_draw_quadratic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7708:hb_draw_quadratic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7709:hb_draw_move_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +7710:hb_draw_line_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +7711:hb_draw_extents_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7712:hb_draw_extents_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7713:hb_draw_cubic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +7714:hb_draw_close_path_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +7715:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +7716:hb_aat_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +7717:hb_aat_map_builder_t::feature_event_t::cmp\28void\20const*\2c\20void\20const*\29 +7718:h2v2_upsample +7719:h2v2_merged_upsample_565D +7720:h2v2_merged_upsample_565 +7721:h2v2_merged_upsample +7722:h2v2_fancy_upsample +7723:h2v1_upsample +7724:h2v1_merged_upsample_565D +7725:h2v1_merged_upsample_565 +7726:h2v1_merged_upsample +7727:h2v1_fancy_upsample +7728:grayscale_convert +7729:gray_rgb_convert +7730:gray_rgb565_convert +7731:gray_rgb565D_convert +7732:gray_raster_render +7733:gray_raster_new +7734:gray_raster_done +7735:gray_move_to +7736:gray_line_to +7737:gray_cubic_to +7738:gray_conic_to +7739:get_sk_marker_list\28jpeg_decompress_struct*\29 +7740:get_sfnt_table +7741:get_interesting_appn +7742:fullsize_upsample +7743:ft_smooth_transform +7744:ft_smooth_set_mode +7745:ft_smooth_render +7746:ft_smooth_overlap_spans +7747:ft_smooth_lcd_spans +7748:ft_smooth_init +7749:ft_smooth_get_cbox +7750:ft_gzip_free +7751:ft_gzip_alloc +7752:ft_ansi_stream_io +7753:ft_ansi_stream_close +7754:fquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +7755:format_message +7756:fmt_fp +7757:fline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +7758:first_axis_intersection\28double\20const*\2c\20bool\2c\20double\2c\20double*\29 +7759:finish_pass1 +7760:finish_output_pass +7761:finish_input_pass +7762:final_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +7763:fcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +7764:fconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +7765:fast_swizzle_rgba_to_rgba_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7766:fast_swizzle_rgba_to_bgra_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7767:fast_swizzle_rgba_to_bgra_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7768:fast_swizzle_rgb_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7769:fast_swizzle_rgb_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7770:fast_swizzle_grayalpha_to_n32_unpremul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7771:fast_swizzle_grayalpha_to_n32_premul\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7772:fast_swizzle_gray_to_n32\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7773:fast_swizzle_cmyk_to_rgba\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7774:fast_swizzle_cmyk_to_bgra\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +7775:error_exit +7776:error_callback +7777:emscripten_stack_get_current +7778:emscripten::internal::MethodInvoker\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20void\2c\20SkCanvas*\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&>::invoke\28void\20\28SkCanvas::*\20const&\29\28sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20SkPaint*\29 +7779:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint*\29 +7780:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\2c\20SkPaint*\29 +7781:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\2c\20float\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\29 +7782:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28float\2c\20float\29\2c\20SkCanvas*\2c\20float\2c\20float\29 +7783:emscripten::internal::MethodInvoker::invoke\28void\20\28SkCanvas::*\20const&\29\28SkPath\20const&\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20SkPath*\2c\20SkPaint*\29 +7784:emscripten::internal::MethodInvoker\20\28skia::textlayout::Paragraph::*\29\28unsigned\20int\29\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::Paragraph*\2c\20unsigned\20int>::invoke\28skia::textlayout::SkRange\20\28skia::textlayout::Paragraph::*\20const&\29\28unsigned\20int\29\2c\20skia::textlayout::Paragraph*\2c\20unsigned\20int\29 +7785:emscripten::internal::MethodInvoker::invoke\28skia::textlayout::PositionWithAffinity\20\28skia::textlayout::Paragraph::*\20const&\29\28float\2c\20float\29\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +7786:emscripten::internal::MethodInvoker\20\28SkVertices::Builder::*\29\28\29\2c\20sk_sp\2c\20SkVertices::Builder*>::invoke\28sk_sp\20\28SkVertices::Builder::*\20const&\29\28\29\2c\20SkVertices::Builder*\29 +7787:emscripten::internal::MethodInvoker::invoke\28int\20\28skia::textlayout::Paragraph::*\20const&\29\28unsigned\20long\29\20const\2c\20skia::textlayout::Paragraph\20const*\2c\20unsigned\20long\29 +7788:emscripten::internal::MethodInvoker::invoke\28bool\20\28SkPath::*\20const&\29\28float\2c\20float\29\20const\2c\20SkPath\20const*\2c\20float\2c\20float\29 +7789:emscripten::internal::MethodInvoker::invoke\28SkPath&\20\28SkPath::*\20const&\29\28bool\29\2c\20SkPath*\2c\20bool\29 +7790:emscripten::internal::Invoker::invoke\28SkVertices::Builder*\20\28*\29\28SkVertices::VertexMode&&\2c\20int&&\2c\20int&&\2c\20unsigned\20int&&\29\2c\20SkVertices::VertexMode\2c\20int\2c\20int\2c\20unsigned\20int\29 +7791:emscripten::internal::Invoker&&\2c\20float&&\2c\20float&&\2c\20float&&>::invoke\28SkFont*\20\28*\29\28sk_sp&&\2c\20float&&\2c\20float&&\2c\20float&&\29\2c\20sk_sp*\2c\20float\2c\20float\2c\20float\29 +7792:emscripten::internal::Invoker&&\2c\20float&&>::invoke\28SkFont*\20\28*\29\28sk_sp&&\2c\20float&&\29\2c\20sk_sp*\2c\20float\29 +7793:emscripten::internal::Invoker&&>::invoke\28SkFont*\20\28*\29\28sk_sp&&\29\2c\20sk_sp*\29 +7794:emscripten::internal::Invoker::invoke\28SkContourMeasureIter*\20\28*\29\28SkPath\20const&\2c\20bool&&\2c\20float&&\29\2c\20SkPath*\2c\20bool\2c\20float\29 +7795:emscripten::internal::Invoker::invoke\28SkCanvas*\20\28*\29\28float&&\2c\20float&&\29\2c\20float\2c\20float\29 +7796:emscripten::internal::Invoker::invoke\28void\20\28*\29\28unsigned\20long\2c\20unsigned\20long\29\2c\20unsigned\20long\2c\20unsigned\20long\29 +7797:emscripten::internal::Invoker::invoke\28void\20\28*\29\28emscripten::val\29\2c\20emscripten::_EM_VAL*\29 +7798:emscripten::internal::Invoker::invoke\28unsigned\20long\20\28*\29\28unsigned\20long\29\2c\20unsigned\20long\29 +7799:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont*\29 +7800:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont*\29 +7801:emscripten::internal::Invoker\2c\20sk_sp\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20int\2c\20int\2c\20sk_sp*\2c\20int\2c\20int\29 +7802:emscripten::internal::Invoker\2c\20sk_sp\2c\20int\2c\20int\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\29\2c\20sk_sp*\2c\20int\2c\20int\2c\20sk_sp*\29 +7803:emscripten::internal::Invoker\2c\20sk_sp\2c\20int\2c\20int>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20int\2c\20int\29 +7804:emscripten::internal::Invoker\2c\20sk_sp\2c\20SimpleImageInfo>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20SimpleImageInfo\29\2c\20sk_sp*\2c\20SimpleImageInfo*\29 +7805:emscripten::internal::Invoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\29 +7806:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +7807:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20sk_sp\29\2c\20unsigned\20long\2c\20sk_sp*\29 +7808:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +7809:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +7810:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29\2c\20float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29 +7811:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp*\29 +7812:emscripten::internal::Invoker\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val>::invoke\28sk_sp\20\28*\29\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\2c\20emscripten::_EM_VAL*\29 +7813:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20int\2c\20float>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20int\2c\20float\29\2c\20unsigned\20long\2c\20int\2c\20float\29 +7814:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20SkPath>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20SkPath\29\2c\20unsigned\20long\2c\20SkPath*\29 +7815:emscripten::internal::Invoker\2c\20float\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28float\2c\20unsigned\20long\29\2c\20float\2c\20unsigned\20long\29 +7816:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20unsigned\20int>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20unsigned\20int\29\2c\20float\2c\20float\2c\20unsigned\20int\29 +7817:emscripten::internal::Invoker\2c\20float>::invoke\28sk_sp\20\28*\29\28float\29\2c\20float\29 +7818:emscripten::internal::Invoker\2c\20SkPath\20const&\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style>::invoke\28sk_sp\20\28*\29\28SkPath\20const&\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style\29\2c\20SkPath*\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style\29 +7819:emscripten::internal::Invoker\2c\20SkBlurStyle\2c\20float\2c\20bool>::invoke\28sk_sp\20\28*\29\28SkBlurStyle\2c\20float\2c\20bool\29\2c\20SkBlurStyle\2c\20float\2c\20bool\29 +7820:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20float\2c\20float\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20float\2c\20float\2c\20sk_sp\29\2c\20unsigned\20long\2c\20float\2c\20float\2c\20sk_sp*\29 +7821:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp\29\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp*\29 +7822:emscripten::internal::Invoker\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\29\2c\20sk_sp*\29 +7823:emscripten::internal::Invoker\2c\20sk_sp\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\29 +7824:emscripten::internal::Invoker\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +7825:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20sk_sp\29\2c\20float\2c\20float\2c\20sk_sp*\29 +7826:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp\29\2c\20float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp*\29 +7827:emscripten::internal::Invoker\2c\20float\2c\20float\2c\20SkTileMode\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\29\2c\20float\2c\20float\2c\20SkTileMode\2c\20sk_sp*\29 +7828:emscripten::internal::Invoker\2c\20SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp\2c\20sk_sp\29\2c\20SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp*\2c\20sk_sp*\29 +7829:emscripten::internal::Invoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long>::invoke\28sk_sp\20\28*\29\28SimpleImageInfo\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\29\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\29 +7830:emscripten::internal::Invoker\2c\20SimpleImageInfo\2c\20emscripten::val>::invoke\28sk_sp\20\28*\29\28SimpleImageInfo\2c\20emscripten::val\29\2c\20SimpleImageInfo*\2c\20emscripten::_EM_VAL*\29 +7831:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20unsigned\20long\2c\20int\29\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\29 +7832:emscripten::internal::Invoker>::invoke\28sk_sp\20\28*\29\28\29\29 +7833:emscripten::internal::Invoker\2c\20unsigned\20long\2c\20SkBlendMode\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28unsigned\20long\2c\20SkBlendMode\2c\20sk_sp\29\2c\20unsigned\20long\2c\20SkBlendMode\2c\20sk_sp*\29 +7834:emscripten::internal::Invoker\2c\20sk_sp\20const&\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28sk_sp\20const&\2c\20sk_sp\29\2c\20sk_sp*\2c\20sk_sp*\29 +7835:emscripten::internal::Invoker\2c\20float\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28*\29\28float\2c\20sk_sp\2c\20sk_sp\29\2c\20float\2c\20sk_sp*\2c\20sk_sp*\29 +7836:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28unsigned\20long\2c\20int\29\2c\20unsigned\20long\2c\20int\29 +7837:emscripten::internal::Invoker\2c\20std::__2::allocator>>::invoke\28emscripten::val\20\28*\29\28std::__2::basic_string\2c\20std::__2::allocator>\29\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\29 +7838:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28emscripten::val\2c\20emscripten::val\2c\20float\29\2c\20emscripten::_EM_VAL*\2c\20emscripten::_EM_VAL*\2c\20float\29 +7839:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28SkPath\20const&\2c\20SkPath\20const&\2c\20float\29\2c\20SkPath*\2c\20SkPath*\2c\20float\29 +7840:emscripten::internal::Invoker::invoke\28emscripten::val\20\28*\29\28SkPath\20const&\2c\20SkPath\20const&\2c\20SkPathOp\29\2c\20SkPath*\2c\20SkPath*\2c\20SkPathOp\29 +7841:emscripten::internal::Invoker::invoke\28bool\20\28*\29\28unsigned\20long\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\29\2c\20unsigned\20long\2c\20SkPath*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\29 +7842:emscripten::internal::Invoker\2c\20sk_sp>::invoke\28bool\20\28*\29\28sk_sp\2c\20sk_sp\29\2c\20sk_sp*\2c\20sk_sp*\29 +7843:emscripten::internal::Invoker::invoke\28bool\20\28*\29\28SkPath\20const&\2c\20SkPath\20const&\29\2c\20SkPath*\2c\20SkPath*\29 +7844:emscripten::internal::Invoker\2c\20int\2c\20int>::invoke\28SkRuntimeEffect::TracedShader\20\28*\29\28sk_sp\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20int\2c\20int\29 +7845:emscripten::internal::Invoker::invoke\28SkPath\20\28*\29\28unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +7846:emscripten::internal::FunctionInvoker\2c\20unsigned\20long\29\2c\20void\2c\20skia::textlayout::TypefaceFontProvider&\2c\20sk_sp\2c\20unsigned\20long>::invoke\28void\20\28**\29\28skia::textlayout::TypefaceFontProvider&\2c\20sk_sp\2c\20unsigned\20long\29\2c\20skia::textlayout::TypefaceFontProvider*\2c\20sk_sp*\2c\20unsigned\20long\29 +7847:emscripten::internal::FunctionInvoker\2c\20std::__2::allocator>\29\2c\20void\2c\20skia::textlayout::ParagraphBuilderImpl&\2c\20std::__2::basic_string\2c\20std::__2::allocator>>::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\29 +7848:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20float\2c\20float\2c\20skia::textlayout::PlaceholderAlignment\2c\20skia::textlayout::TextBaseline\2c\20float\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20float\2c\20float\2c\20skia::textlayout::PlaceholderAlignment\2c\20skia::textlayout::TextBaseline\2c\20float\29 +7849:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\2c\20SkPaint\2c\20SkPaint\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20SimpleTextStyle*\2c\20SkPaint*\2c\20SkPaint*\29 +7850:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\29\2c\20skia::textlayout::ParagraphBuilderImpl*\2c\20SimpleTextStyle*\29 +7851:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +7852:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +7853:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +7854:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29 +7855:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +7856:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkPath&\2c\20SkPath\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29\2c\20SkPath*\2c\20SkPath*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +7857:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkContourMeasure&\2c\20float\2c\20unsigned\20long\29\2c\20SkContourMeasure*\2c\20float\2c\20unsigned\20long\29 +7858:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont*\2c\20SkPaint*\29 +7859:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\2c\20SkPaint*\29 +7860:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7861:emscripten::internal::FunctionInvoker\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7862:emscripten::internal::FunctionInvoker\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7863:emscripten::internal::FunctionInvoker\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20void\2c\20SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*>::invoke\28void\20\28**\29\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29\2c\20SkCanvas*\2c\20sk_sp*\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +7864:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont*\2c\20SkPaint*\29 +7865:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29\2c\20SkCanvas*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint*\29 +7866:emscripten::internal::FunctionInvoker::invoke\28void\20\28**\29\28SkCanvas&\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20int\29\2c\20SkCanvas*\2c\20SkPath*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20int\29 +7867:emscripten::internal::FunctionInvoker\2c\20std::__2::allocator>\20\28*\29\28SkSL::DebugTrace\20const*\29\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::DebugTrace\20const*>::invoke\28std::__2::basic_string\2c\20std::__2::allocator>\20\28**\29\28SkSL::DebugTrace\20const*\29\2c\20SkSL::DebugTrace\20const*\29 +7868:emscripten::internal::FunctionInvoker\20\28*\29\28SkFontMgr&\2c\20unsigned\20long\2c\20int\29\2c\20sk_sp\2c\20SkFontMgr&\2c\20unsigned\20long\2c\20int>::invoke\28sk_sp\20\28**\29\28SkFontMgr&\2c\20unsigned\20long\2c\20int\29\2c\20SkFontMgr*\2c\20unsigned\20long\2c\20int\29 +7869:emscripten::internal::FunctionInvoker\20\28*\29\28SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29\2c\20sk_sp\2c\20SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val>::invoke\28sk_sp\20\28**\29\28SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29\2c\20SkFontMgr*\2c\20emscripten::internal::BindingType\2c\20std::__2::allocator>\2c\20void>::'unnamed'*\2c\20emscripten::_EM_VAL*\29 +7870:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29\2c\20sk_sp\2c\20sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29 +7871:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29\2c\20sk_sp\2c\20sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29\2c\20sk_sp*\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29 +7872:emscripten::internal::FunctionInvoker\20\28*\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SkRuntimeEffect*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +7873:emscripten::internal::FunctionInvoker\20\28*\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29\2c\20SkRuntimeEffect*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29 +7874:emscripten::internal::FunctionInvoker\20\28*\29\28SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29\2c\20SkPicture*\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +7875:emscripten::internal::FunctionInvoker\20\28*\29\28SkPictureRecorder&\29\2c\20sk_sp\2c\20SkPictureRecorder&>::invoke\28sk_sp\20\28**\29\28SkPictureRecorder&\29\2c\20SkPictureRecorder*\29 +7876:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\29\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28**\29\28sk_sp\29\2c\20sk_sp*\29 +7877:emscripten::internal::FunctionInvoker\20\28*\29\28SkSurface&\2c\20unsigned\20long\29\2c\20sk_sp\2c\20SkSurface&\2c\20unsigned\20long>::invoke\28sk_sp\20\28**\29\28SkSurface&\2c\20unsigned\20long\29\2c\20SkSurface*\2c\20unsigned\20long\29 +7878:emscripten::internal::FunctionInvoker\20\28*\29\28SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo\29\2c\20sk_sp\2c\20SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo>::invoke\28sk_sp\20\28**\29\28SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo\29\2c\20SkSurface*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo*\29 +7879:emscripten::internal::FunctionInvoker\20\28*\29\28sk_sp\29\2c\20sk_sp\2c\20sk_sp>::invoke\28sk_sp\20\28**\29\28sk_sp\29\2c\20sk_sp*\29 +7880:emscripten::internal::FunctionInvoker\20\28*\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29\2c\20sk_sp\2c\20SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool>::invoke\28sk_sp\20\28**\29\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29\2c\20SkRuntimeEffect*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +7881:emscripten::internal::FunctionInvoker::invoke\28int\20\28**\29\28SkCanvas&\2c\20SkPaint\29\2c\20SkCanvas*\2c\20SkPaint*\29 +7882:emscripten::internal::FunctionInvoker::invoke\28int\20\28**\29\28SkCanvas&\2c\20SkPaint\20const*\2c\20unsigned\20long\2c\20SkImageFilter\20const*\2c\20unsigned\20int\2c\20SkTileMode\29\2c\20SkCanvas*\2c\20SkPaint\20const*\2c\20unsigned\20long\2c\20SkImageFilter\20const*\2c\20unsigned\20int\2c\20SkTileMode\29 +7883:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28skia::textlayout::Paragraph&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29\2c\20skia::textlayout::Paragraph*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +7884:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28skia::textlayout::Paragraph&\2c\20float\2c\20float\29\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +7885:emscripten::internal::FunctionInvoker\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29\2c\20emscripten::val\2c\20sk_sp\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*>::invoke\28emscripten::val\20\28**\29\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29\2c\20sk_sp*\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29 +7886:emscripten::internal::FunctionInvoker\2c\20SkEncodedImageFormat\2c\20int\29\2c\20emscripten::val\2c\20sk_sp\2c\20SkEncodedImageFormat\2c\20int>::invoke\28emscripten::val\20\28**\29\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\29\2c\20sk_sp*\2c\20SkEncodedImageFormat\2c\20int\29 +7887:emscripten::internal::FunctionInvoker\29\2c\20emscripten::val\2c\20sk_sp>::invoke\28emscripten::val\20\28**\29\28sk_sp\29\2c\20sk_sp*\29 +7888:emscripten::internal::FunctionInvoker::invoke\28emscripten::val\20\28**\29\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20float\2c\20float\29\2c\20SkFont*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20float\2c\20float\29 +7889:emscripten::internal::FunctionInvoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29\2c\20bool\2c\20sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*>::invoke\28bool\20\28**\29\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29\2c\20sk_sp*\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29 +7890:emscripten::internal::FunctionInvoker\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29\2c\20bool\2c\20sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int>::invoke\28bool\20\28**\29\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29\2c\20sk_sp*\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +7891:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20float\29\2c\20SkPath*\2c\20float\2c\20float\2c\20float\29 +7892:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20float\2c\20float\2c\20bool\29\2c\20SkPath*\2c\20float\2c\20float\2c\20bool\29 +7893:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkPath&\2c\20StrokeOpts\29\2c\20SkPath*\2c\20StrokeOpts*\29 +7894:emscripten::internal::FunctionInvoker::invoke\28bool\20\28**\29\28SkCanvas&\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29\2c\20SkCanvas*\2c\20SimpleImageInfo*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +7895:emscripten::internal::FunctionInvoker::invoke\28SkPath\20\28**\29\28SkPath\20const&\29\2c\20SkPath*\29 +7896:emscripten::internal::FunctionInvoker::invoke\28SkPath\20\28**\29\28SkContourMeasure&\2c\20float\2c\20float\2c\20bool\29\2c\20SkContourMeasure*\2c\20float\2c\20float\2c\20bool\29 +7897:emscripten::internal::FunctionInvoker::invoke\28SkPaint\20\28**\29\28SkPaint\20const&\29\2c\20SkPaint*\29 +7898:emscripten::internal::FunctionInvoker::invoke\28SimpleImageInfo\20\28**\29\28SkSurface&\29\2c\20SkSurface*\29 +7899:emscripten::internal::FunctionInvoker::invoke\28RuntimeEffectUniform\20\28**\29\28SkRuntimeEffect&\2c\20int\29\2c\20SkRuntimeEffect*\2c\20int\29 +7900:emit_message +7901:embind_init_Skia\28\29::$_9::__invoke\28SkAnimatedImage&\29 +7902:embind_init_Skia\28\29::$_99::__invoke\28SkPath&\2c\20unsigned\20long\2c\20int\2c\20bool\29 +7903:embind_init_Skia\28\29::$_98::__invoke\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\29 +7904:embind_init_Skia\28\29::$_97::__invoke\28SkPath&\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20int\29 +7905:embind_init_Skia\28\29::$_96::__invoke\28SkPath&\2c\20unsigned\20long\2c\20float\2c\20float\29 +7906:embind_init_Skia\28\29::$_95::__invoke\28unsigned\20long\2c\20SkPath\29 +7907:embind_init_Skia\28\29::$_94::__invoke\28float\2c\20unsigned\20long\29 +7908:embind_init_Skia\28\29::$_93::__invoke\28unsigned\20long\2c\20int\2c\20float\29 +7909:embind_init_Skia\28\29::$_92::__invoke\28\29 +7910:embind_init_Skia\28\29::$_91::__invoke\28\29 +7911:embind_init_Skia\28\29::$_90::__invoke\28sk_sp\2c\20sk_sp\29 +7912:embind_init_Skia\28\29::$_8::__invoke\28emscripten::val\29 +7913:embind_init_Skia\28\29::$_89::__invoke\28SkPaint&\2c\20unsigned\20int\2c\20sk_sp\29 +7914:embind_init_Skia\28\29::$_88::__invoke\28SkPaint&\2c\20unsigned\20int\29 +7915:embind_init_Skia\28\29::$_87::__invoke\28SkPaint&\2c\20unsigned\20long\2c\20sk_sp\29 +7916:embind_init_Skia\28\29::$_86::__invoke\28SkPaint&\2c\20unsigned\20long\29 +7917:embind_init_Skia\28\29::$_85::__invoke\28SkPaint\20const&\29 +7918:embind_init_Skia\28\29::$_84::__invoke\28SkBlurStyle\2c\20float\2c\20bool\29 +7919:embind_init_Skia\28\29::$_83::__invoke\28float\2c\20float\2c\20sk_sp\29 +7920:embind_init_Skia\28\29::$_82::__invoke\28unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20sk_sp\29 +7921:embind_init_Skia\28\29::$_81::__invoke\28unsigned\20long\2c\20float\2c\20float\2c\20sk_sp\29 +7922:embind_init_Skia\28\29::$_80::__invoke\28sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +7923:embind_init_Skia\28\29::$_7::__invoke\28GrDirectContext&\2c\20unsigned\20long\29 +7924:embind_init_Skia\28\29::$_79::__invoke\28sk_sp\2c\20float\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\29 +7925:embind_init_Skia\28\29::$_78::__invoke\28float\2c\20float\2c\20sk_sp\29 +7926:embind_init_Skia\28\29::$_77::__invoke\28float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp\29 +7927:embind_init_Skia\28\29::$_76::__invoke\28float\2c\20float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20sk_sp\29 +7928:embind_init_Skia\28\29::$_75::__invoke\28sk_sp\29 +7929:embind_init_Skia\28\29::$_74::__invoke\28SkColorChannel\2c\20SkColorChannel\2c\20float\2c\20sk_sp\2c\20sk_sp\29 +7930:embind_init_Skia\28\29::$_73::__invoke\28float\2c\20float\2c\20sk_sp\29 +7931:embind_init_Skia\28\29::$_72::__invoke\28sk_sp\2c\20sk_sp\29 +7932:embind_init_Skia\28\29::$_71::__invoke\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\29 +7933:embind_init_Skia\28\29::$_70::__invoke\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29 +7934:embind_init_Skia\28\29::$_6::__invoke\28GrDirectContext&\29 +7935:embind_init_Skia\28\29::$_69::__invoke\28SkImageFilter\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +7936:embind_init_Skia\28\29::$_68::__invoke\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +7937:embind_init_Skia\28\29::$_67::__invoke\28sk_sp\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\2c\20GrDirectContext*\29 +7938:embind_init_Skia\28\29::$_66::__invoke\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20unsigned\20long\29 +7939:embind_init_Skia\28\29::$_65::__invoke\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20long\29 +7940:embind_init_Skia\28\29::$_64::__invoke\28sk_sp\29 +7941:embind_init_Skia\28\29::$_63::__invoke\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\2c\20GrDirectContext*\29 +7942:embind_init_Skia\28\29::$_62::__invoke\28sk_sp\2c\20SkEncodedImageFormat\2c\20int\29 +7943:embind_init_Skia\28\29::$_61::__invoke\28sk_sp\29 +7944:embind_init_Skia\28\29::$_60::__invoke\28sk_sp\29 +7945:embind_init_Skia\28\29::$_5::__invoke\28GrDirectContext&\29 +7946:embind_init_Skia\28\29::$_59::__invoke\28SkFontMgr&\2c\20unsigned\20long\2c\20int\29 +7947:embind_init_Skia\28\29::$_58::__invoke\28SkFontMgr&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29 +7948:embind_init_Skia\28\29::$_57::__invoke\28SkFontMgr&\2c\20int\29 +7949:embind_init_Skia\28\29::$_56::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20int\29 +7950:embind_init_Skia\28\29::$_55::__invoke\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20float\2c\20float\29 +7951:embind_init_Skia\28\29::$_54::__invoke\28SkFont&\29 +7952:embind_init_Skia\28\29::$_53::__invoke\28SkFont&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +7953:embind_init_Skia\28\29::$_52::__invoke\28SkFont&\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPaint*\29 +7954:embind_init_Skia\28\29::$_51::__invoke\28SkContourMeasure&\2c\20float\2c\20float\2c\20bool\29 +7955:embind_init_Skia\28\29::$_50::__invoke\28SkContourMeasure&\2c\20float\2c\20unsigned\20long\29 +7956:embind_init_Skia\28\29::$_4::__invoke\28unsigned\20long\2c\20unsigned\20long\29 +7957:embind_init_Skia\28\29::$_49::__invoke\28unsigned\20long\29 +7958:embind_init_Skia\28\29::$_48::__invoke\28unsigned\20long\2c\20SkBlendMode\2c\20sk_sp\29 +7959:embind_init_Skia\28\29::$_47::__invoke\28SkCanvas&\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +7960:embind_init_Skia\28\29::$_46::__invoke\28SkCanvas&\2c\20SkPaint\29 +7961:embind_init_Skia\28\29::$_45::__invoke\28SkCanvas&\2c\20SkPaint\20const*\2c\20unsigned\20long\2c\20SkImageFilter\20const*\2c\20unsigned\20int\2c\20SkTileMode\29 +7962:embind_init_Skia\28\29::$_44::__invoke\28SkCanvas&\2c\20SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20int\29 +7963:embind_init_Skia\28\29::$_43::__invoke\28SkCanvas&\2c\20SimpleImageInfo\29 +7964:embind_init_Skia\28\29::$_42::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +7965:embind_init_Skia\28\29::$_41::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +7966:embind_init_Skia\28\29::$_40::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +7967:embind_init_Skia\28\29::$_3::__invoke\28unsigned\20long\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\29 +7968:embind_init_Skia\28\29::$_39::__invoke\28SkCanvas\20const&\2c\20unsigned\20long\29 +7969:embind_init_Skia\28\29::$_38::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29 +7970:embind_init_Skia\28\29::$_37::__invoke\28SkCanvas&\2c\20SkPath\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20int\29 +7971:embind_init_Skia\28\29::$_36::__invoke\28SkCanvas&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +7972:embind_init_Skia\28\29::$_35::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +7973:embind_init_Skia\28\29::$_34::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +7974:embind_init_Skia\28\29::$_33::__invoke\28SkCanvas&\2c\20SkCanvas::PointMode\2c\20unsigned\20long\2c\20int\2c\20SkPaint&\29 +7975:embind_init_Skia\28\29::$_32::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +7976:embind_init_Skia\28\29::$_31::__invoke\28SkCanvas&\2c\20skia::textlayout::Paragraph*\2c\20float\2c\20float\29 +7977:embind_init_Skia\28\29::$_30::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +7978:embind_init_Skia\28\29::$_2::__invoke\28SimpleImageInfo\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\29 +7979:embind_init_Skia\28\29::$_29::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +7980:embind_init_Skia\28\29::$_28::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7981:embind_init_Skia\28\29::$_27::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\20const*\2c\20bool\29 +7982:embind_init_Skia\28\29::$_26::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +7983:embind_init_Skia\28\29::$_25::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +7984:embind_init_Skia\28\29::$_24::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7985:embind_init_Skia\28\29::$_23::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7986:embind_init_Skia\28\29::$_22::__invoke\28SkCanvas&\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\2c\20SkFont\20const&\2c\20SkPaint\20const&\29 +7987:embind_init_Skia\28\29::$_21::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\20const&\29 +7988:embind_init_Skia\28\29::$_20::__invoke\28SkCanvas&\2c\20unsigned\20int\2c\20SkBlendMode\29 +7989:embind_init_Skia\28\29::$_1::__invoke\28unsigned\20long\2c\20unsigned\20long\29 +7990:embind_init_Skia\28\29::$_19::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkBlendMode\29 +7991:embind_init_Skia\28\29::$_18::__invoke\28SkCanvas&\2c\20unsigned\20long\29 +7992:embind_init_Skia\28\29::$_17::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20float\2c\20float\2c\20SkPaint\20const*\29 +7993:embind_init_Skia\28\29::$_16::__invoke\28SkCanvas&\2c\20sk_sp\20const&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\2c\20SkBlendMode\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkPaint\20const*\29 +7994:embind_init_Skia\28\29::$_15::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +7995:embind_init_Skia\28\29::$_14::__invoke\28SkCanvas&\2c\20unsigned\20long\29 +7996:embind_init_Skia\28\29::$_149::__invoke\28SkVertices::Builder&\29 +7997:embind_init_Skia\28\29::$_148::__invoke\28SkVertices::Builder&\29 +7998:embind_init_Skia\28\29::$_147::__invoke\28SkVertices::Builder&\29 +7999:embind_init_Skia\28\29::$_146::__invoke\28SkVertices::Builder&\29 +8000:embind_init_Skia\28\29::$_145::__invoke\28SkVertices&\2c\20unsigned\20long\29 +8001:embind_init_Skia\28\29::$_144::__invoke\28SkTypeface&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +8002:embind_init_Skia\28\29::$_143::__invoke\28unsigned\20long\2c\20int\29 +8003:embind_init_Skia\28\29::$_142::__invoke\28\29 +8004:embind_init_Skia\28\29::$_141::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +8005:embind_init_Skia\28\29::$_140::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +8006:embind_init_Skia\28\29::$_13::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29 +8007:embind_init_Skia\28\29::$_139::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +8008:embind_init_Skia\28\29::$_138::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkFont\20const&\29 +8009:embind_init_Skia\28\29::$_137::__invoke\28SkSurface&\29 +8010:embind_init_Skia\28\29::$_136::__invoke\28SkSurface&\29 +8011:embind_init_Skia\28\29::$_135::__invoke\28SkSurface&\29 +8012:embind_init_Skia\28\29::$_134::__invoke\28SkSurface&\2c\20SimpleImageInfo\29 +8013:embind_init_Skia\28\29::$_133::__invoke\28SkSurface&\2c\20unsigned\20long\29 +8014:embind_init_Skia\28\29::$_132::__invoke\28SkSurface&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SimpleImageInfo\29 +8015:embind_init_Skia\28\29::$_131::__invoke\28SkSurface&\29 +8016:embind_init_Skia\28\29::$_130::__invoke\28SkSurface&\29 +8017:embind_init_Skia\28\29::$_12::__invoke\28SkCanvas&\2c\20unsigned\20long\2c\20SkClipOp\2c\20bool\29 +8018:embind_init_Skia\28\29::$_129::__invoke\28SimpleImageInfo\2c\20unsigned\20long\2c\20unsigned\20long\29 +8019:embind_init_Skia\28\29::$_128::__invoke\28SkRuntimeEffect&\2c\20int\29 +8020:embind_init_Skia\28\29::$_127::__invoke\28SkRuntimeEffect&\2c\20int\29 +8021:embind_init_Skia\28\29::$_126::__invoke\28SkRuntimeEffect&\29 +8022:embind_init_Skia\28\29::$_125::__invoke\28SkRuntimeEffect&\29 +8023:embind_init_Skia\28\29::$_124::__invoke\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +8024:embind_init_Skia\28\29::$_123::__invoke\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +8025:embind_init_Skia\28\29::$_122::__invoke\28SkRuntimeEffect&\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\2c\20unsigned\20long\29 +8026:embind_init_Skia\28\29::$_121::__invoke\28sk_sp\2c\20int\2c\20int\29 +8027:embind_init_Skia\28\29::$_120::__invoke\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29 +8028:embind_init_Skia\28\29::$_11::__invoke\28SkCanvas&\2c\20unsigned\20long\29 +8029:embind_init_Skia\28\29::$_119::__invoke\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20emscripten::val\29 +8030:embind_init_Skia\28\29::$_118::__invoke\28SkSL::DebugTrace\20const*\29 +8031:embind_init_Skia\28\29::$_117::__invoke\28unsigned\20long\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +8032:embind_init_Skia\28\29::$_116::__invoke\28float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29 +8033:embind_init_Skia\28\29::$_115::__invoke\28float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +8034:embind_init_Skia\28\29::$_114::__invoke\28float\2c\20float\2c\20float\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +8035:embind_init_Skia\28\29::$_113::__invoke\28unsigned\20long\2c\20unsigned\20long\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20unsigned\20long\2c\20sk_sp\29 +8036:embind_init_Skia\28\29::$_112::__invoke\28float\2c\20float\2c\20int\2c\20float\2c\20int\2c\20int\29 +8037:embind_init_Skia\28\29::$_111::__invoke\28unsigned\20long\2c\20sk_sp\29 +8038:embind_init_Skia\28\29::$_110::operator\28\29\28SkPicture&\29\20const::'lambda'\28SkImage*\2c\20void*\29::__invoke\28SkImage*\2c\20void*\29 +8039:embind_init_Skia\28\29::$_110::__invoke\28SkPicture&\29 +8040:embind_init_Skia\28\29::$_10::__invoke\28SkAnimatedImage&\29 +8041:embind_init_Skia\28\29::$_109::__invoke\28SkPicture&\2c\20unsigned\20long\29 +8042:embind_init_Skia\28\29::$_108::__invoke\28SkPicture&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkFilterMode\2c\20unsigned\20long\2c\20unsigned\20long\29 +8043:embind_init_Skia\28\29::$_107::__invoke\28SkPictureRecorder&\29 +8044:embind_init_Skia\28\29::$_106::__invoke\28SkPictureRecorder&\2c\20unsigned\20long\2c\20bool\29 +8045:embind_init_Skia\28\29::$_105::__invoke\28SkPath&\2c\20unsigned\20long\29 +8046:embind_init_Skia\28\29::$_104::__invoke\28SkPath&\2c\20unsigned\20long\29 +8047:embind_init_Skia\28\29::$_103::__invoke\28SkPath&\2c\20int\2c\20unsigned\20long\29 +8048:embind_init_Skia\28\29::$_102::__invoke\28SkPath&\2c\20unsigned\20long\2c\20float\2c\20float\2c\20bool\29 +8049:embind_init_Skia\28\29::$_101::__invoke\28SkPath&\2c\20unsigned\20long\2c\20bool\29 +8050:embind_init_Skia\28\29::$_100::__invoke\28SkPath&\2c\20unsigned\20long\2c\20bool\29 +8051:embind_init_Skia\28\29::$_0::__invoke\28unsigned\20long\2c\20unsigned\20long\29 +8052:embind_init_Paragraph\28\29::$_9::__invoke\28skia::textlayout::ParagraphBuilderImpl&\29 +8053:embind_init_Paragraph\28\29::$_8::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20float\2c\20float\2c\20skia::textlayout::PlaceholderAlignment\2c\20skia::textlayout::TextBaseline\2c\20float\29 +8054:embind_init_Paragraph\28\29::$_7::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\2c\20SkPaint\2c\20SkPaint\29 +8055:embind_init_Paragraph\28\29::$_6::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20SimpleTextStyle\29 +8056:embind_init_Paragraph\28\29::$_5::__invoke\28skia::textlayout::ParagraphBuilderImpl&\29 +8057:embind_init_Paragraph\28\29::$_4::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +8058:embind_init_Paragraph\28\29::$_3::__invoke\28emscripten::val\2c\20emscripten::val\2c\20float\29 +8059:embind_init_Paragraph\28\29::$_2::__invoke\28SimpleParagraphStyle\2c\20sk_sp\29 +8060:embind_init_Paragraph\28\29::$_19::__invoke\28skia::textlayout::FontCollection&\2c\20sk_sp\20const&\29 +8061:embind_init_Paragraph\28\29::$_18::__invoke\28\29 +8062:embind_init_Paragraph\28\29::$_17::__invoke\28skia::textlayout::TypefaceFontProvider&\2c\20sk_sp\2c\20unsigned\20long\29 +8063:embind_init_Paragraph\28\29::$_16::__invoke\28\29 +8064:embind_init_Paragraph\28\29::$_15::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +8065:embind_init_Paragraph\28\29::$_14::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +8066:embind_init_Paragraph\28\29::$_13::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +8067:embind_init_Paragraph\28\29::$_12::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +8068:embind_init_Paragraph\28\29::$_11::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +8069:embind_init_Paragraph\28\29::$_10::__invoke\28skia::textlayout::ParagraphBuilderImpl&\2c\20unsigned\20long\2c\20unsigned\20long\29 +8070:dispose_external_texture\28void*\29 +8071:deleteJSTexture\28void*\29 +8072:deflate_slow +8073:deflate_fast +8074:decompress_smooth_data +8075:decompress_onepass +8076:decompress_data +8077:decompose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +8078:decompose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +8079:decompose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +8080:decode_mcu_DC_refine +8081:decode_mcu_DC_first +8082:decode_mcu_AC_refine +8083:decode_mcu_AC_first +8084:decode_mcu +8085:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::Make\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20bool\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8086:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\2c\20GrShaderCaps\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::\28anonymous\20namespace\29::HullShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8087:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8088:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8089:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&>\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathTessellator::PathDrawList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8090:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29>\28skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20sk_sp\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8091:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Make\28SkArenaAlloc*\2c\20GrAAType\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8092:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerSkyline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8093:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerPow2&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8094:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make*\20SkArenaAlloc::make>\28\29::'lambda'\28void*\29>\28sk_sp&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8095:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc>\28\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TextureOpImpl::Desc&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8096:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TentPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8097:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::SimpleTriangleShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8098:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8099:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader\2c\20bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*\2c\20GrShaderCaps\20const&>\28bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*&&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::DrawAtlasPathShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8100:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&>\28SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::BoundingBoxShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8101:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20unsigned\20char&&\29::'lambda'\28void*\29>\28Sprite_D32_S32&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8102:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTriColorShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8103:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTCubic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8104:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTConic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8105:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\29::'lambda'\28void*\29>\28SkSpriteBlitter_Memcpy&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8106:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&>\28SkPixmap\20const&\2c\20SkArenaAlloc*&\2c\20sk_sp&\29::'lambda'\28void*\29>\28SkRasterPipelineSpriteBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8107:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkArenaAlloc*&\29::'lambda'\28void*\29>\28SkRasterPipelineBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8108:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkNullBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8109:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkImage_Base\20const*&&\2c\20SkMatrix\20const&\2c\20SkMipmapMode&\29::'lambda'\28void*\29>\28SkMipmapAccessor&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8110:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::PathData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8111:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::DrawableData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8112:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\29>>::Node*\20SkArenaAlloc::make&\29>>::Node\2c\20std::__2::function&\29>>\28std::__2::function&\29>&&\29::'lambda'\28void*\29>\28SkArenaAllocList&\29>>::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8113:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node\2c\20std::__2::function&\29>\2c\20skgpu::AtlasToken>\28std::__2::function&\29>&&\2c\20skgpu::AtlasToken&&\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8114:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node>\28\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8115:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Coverage_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8116:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28GrSimpleMesh&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8117:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29::'lambda'\28void*\29>\28GrResourceAllocator::Register&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8118:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPath\20const&\2c\20SkArenaAlloc*\20const&\29::'lambda'\28void*\29>\28GrInnerFanTriangulator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8119:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldLCDTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20GrDistanceFieldLCDTextGeoProc::DistanceAdjust\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8120:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29>\28GrBitmapTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8121:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrAppliedClip&&\29::'lambda'\28void*\29>\28GrAppliedClip&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8122:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28EllipseGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8123:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28DefaultGeoProc::Make\28SkArenaAlloc*\2c\20unsigned\20int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +8124:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8125:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&\29 +8126:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8127:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8128:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8129:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +8130:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8131:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&\29 +8132:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8133:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8134:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +8135:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +8136:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +8137:deallocate_buffer_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8138:ddquad_xy_at_t\28SkDCurve\20const&\2c\20double\29 +8139:ddquad_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +8140:ddline_xy_at_t\28SkDCurve\20const&\2c\20double\29 +8141:ddline_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +8142:ddcubic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +8143:ddcubic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +8144:ddconic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +8145:ddconic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +8146:data_destroy_use\28void*\29 +8147:data_create_use\28hb_ot_shape_plan_t\20const*\29 +8148:data_create_khmer\28hb_ot_shape_plan_t\20const*\29 +8149:data_create_indic\28hb_ot_shape_plan_t\20const*\29 +8150:data_create_hangul\28hb_ot_shape_plan_t\20const*\29 +8151:copy\28void*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\29 +8152:convert_bytes_to_data +8153:consume_markers +8154:consume_data +8155:computeTonalColors\28unsigned\20long\2c\20unsigned\20long\29 +8156:compose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8157:compose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8158:compose_hebrew\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8159:compare_ppem +8160:compare_myanmar_order\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +8161:compare_combining_class\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +8162:color_quantize3 +8163:color_quantize +8164:collect_features_use\28hb_ot_shape_planner_t*\29 +8165:collect_features_myanmar\28hb_ot_shape_planner_t*\29 +8166:collect_features_khmer\28hb_ot_shape_planner_t*\29 +8167:collect_features_indic\28hb_ot_shape_planner_t*\29 +8168:collect_features_hangul\28hb_ot_shape_planner_t*\29 +8169:collect_features_arabic\28hb_ot_shape_planner_t*\29 +8170:clip\28SkPath\20const&\2c\20SkHalfPlane\20const&\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +8171:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitStatement\28SkSL::Statement\20const&\29 +8172:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +8173:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitExpression\28SkSL::Expression\20const&\29 +8174:cff_slot_init +8175:cff_slot_done +8176:cff_size_request +8177:cff_size_init +8178:cff_size_done +8179:cff_sid_to_glyph_name +8180:cff_set_var_design +8181:cff_set_mm_weightvector +8182:cff_set_mm_blend +8183:cff_set_instance +8184:cff_random +8185:cff_ps_has_glyph_names +8186:cff_ps_get_font_info +8187:cff_ps_get_font_extra +8188:cff_parse_vsindex +8189:cff_parse_private_dict +8190:cff_parse_multiple_master +8191:cff_parse_maxstack +8192:cff_parse_font_matrix +8193:cff_parse_font_bbox +8194:cff_parse_cid_ros +8195:cff_parse_blend +8196:cff_metrics_adjust +8197:cff_hadvance_adjust +8198:cff_glyph_load +8199:cff_get_var_design +8200:cff_get_var_blend +8201:cff_get_standard_encoding +8202:cff_get_ros +8203:cff_get_ps_name +8204:cff_get_name_index +8205:cff_get_mm_weightvector +8206:cff_get_mm_var +8207:cff_get_mm_blend +8208:cff_get_is_cid +8209:cff_get_interface +8210:cff_get_glyph_name +8211:cff_get_glyph_data +8212:cff_get_cmap_info +8213:cff_get_cid_from_glyph_index +8214:cff_get_advances +8215:cff_free_glyph_data +8216:cff_fd_select_get +8217:cff_face_init +8218:cff_face_done +8219:cff_driver_init +8220:cff_done_blend +8221:cff_decoder_prepare +8222:cff_decoder_init +8223:cff_cmap_unicode_init +8224:cff_cmap_unicode_char_next +8225:cff_cmap_unicode_char_index +8226:cff_cmap_encoding_init +8227:cff_cmap_encoding_done +8228:cff_cmap_encoding_char_next +8229:cff_cmap_encoding_char_index +8230:cff_builder_start_point +8231:cff_builder_init +8232:cff_builder_add_point1 +8233:cff_builder_add_point +8234:cff_builder_add_contour +8235:cff_blend_check_vector +8236:cf2_free_instance +8237:cf2_decoder_parse_charstrings +8238:cf2_builder_moveTo +8239:cf2_builder_lineTo +8240:cf2_builder_cubeTo +8241:bw_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +8242:bw_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8243:bw_pt_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8244:bw_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8245:bw_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8246:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::SpotVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +8247:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::AmbientVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +8248:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +8249:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +8250:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +8251:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +8252:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8253:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8254:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8255:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8256:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +8257:blur_y_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8258:blur_y_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8259:blur_y_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8260:blur_y_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8261:blur_x_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8262:blur_x_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8263:blur_x_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8264:blur_x_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +8265:blit_row_s32a_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +8266:blit_row_s32_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +8267:blit_row_s32_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +8268:argb32_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +8269:arabic_fallback_shape\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8270:alwaysSaveTypefaceBytes\28SkTypeface*\2c\20void*\29 +8271:alloc_sarray +8272:alloc_barray +8273:afm_parser_parse +8274:afm_parser_init +8275:afm_parser_done +8276:afm_compare_kern_pairs +8277:af_property_set +8278:af_property_get +8279:af_latin_metrics_scale +8280:af_latin_metrics_init +8281:af_latin_hints_init +8282:af_latin_hints_apply +8283:af_latin_get_standard_widths +8284:af_indic_metrics_init +8285:af_indic_hints_apply +8286:af_get_interface +8287:af_face_globals_free +8288:af_dummy_hints_init +8289:af_dummy_hints_apply +8290:af_cjk_metrics_init +8291:af_autofitter_load_glyph +8292:af_autofitter_init +8293:access_virt_sarray +8294:access_virt_barray +8295:aa_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8296:aa_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8297:aa_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +8298:_hb_ot_font_destroy\28void*\29 +8299:_hb_glyph_info_is_default_ignorable\28hb_glyph_info_t\20const*\29 +8300:_hb_face_for_data_reference_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +8301:_hb_face_for_data_closure_destroy\28void*\29 +8302:_hb_clear_substitution_flags\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8303:_emscripten_stack_restore +8304:__wasm_call_ctors +8305:__stdio_write +8306:__stdio_seek +8307:__stdio_read +8308:__stdio_close +8309:__getTypeName +8310:__cxxabiv1::__vmi_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +8311:__cxxabiv1::__vmi_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +8312:__cxxabiv1::__vmi_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +8313:__cxxabiv1::__si_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +8314:__cxxabiv1::__si_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +8315:__cxxabiv1::__si_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +8316:__cxxabiv1::__class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +8317:__cxxabiv1::__class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +8318:__cxxabiv1::__class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +8319:__cxxabiv1::__class_type_info::can_catch\28__cxxabiv1::__shim_type_info\20const*\2c\20void*&\29\20const +8320:__cxx_global_array_dtor_9958 +8321:__cxx_global_array_dtor_9569 +8322:__cxx_global_array_dtor_8554 +8323:__cxx_global_array_dtor_8165 +8324:__cxx_global_array_dtor_3977 +8325:__cxx_global_array_dtor_2243 +8326:__cxx_global_array_dtor_2115 +8327:__cxx_global_array_dtor_13377 +8328:__cxx_global_array_dtor_10664 +8329:__cxx_global_array_dtor.88 +8330:__cxx_global_array_dtor.73 +8331:__cxx_global_array_dtor.58 +8332:__cxx_global_array_dtor.45 +8333:__cxx_global_array_dtor.43 +8334:__cxx_global_array_dtor.41 +8335:__cxx_global_array_dtor.39 +8336:__cxx_global_array_dtor.37 +8337:__cxx_global_array_dtor.35 +8338:__cxx_global_array_dtor.34 +8339:__cxx_global_array_dtor.32 +8340:__cxx_global_array_dtor.139 +8341:__cxx_global_array_dtor.136 +8342:__cxx_global_array_dtor.112 +8343:__cxx_global_array_dtor.1 +8344:__cxx_global_array_dtor +8345:\28anonymous\20namespace\29::skhb_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +8346:\28anonymous\20namespace\29::skhb_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8347:\28anonymous\20namespace\29::skhb_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +8348:\28anonymous\20namespace\29::skhb_glyph_h_advance\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +8349:\28anonymous\20namespace\29::skhb_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +8350:\28anonymous\20namespace\29::skhb_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +8351:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29::$_0::__invoke\28void*\29 +8352:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +8353:\28anonymous\20namespace\29::make_morphology\28\28anonymous\20namespace\29::MorphType\2c\20SkSize\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +8354:\28anonymous\20namespace\29::make_drop_shadow_graph\28SkPoint\2c\20SkSize\2c\20SkRGBA4f<\28SkAlphaType\293>\2c\20sk_sp\2c\20bool\2c\20sk_sp\2c\20std::__2::optional\20const&\29 +8355:\28anonymous\20namespace\29::extension_compare\28SkString\20const&\2c\20SkString\20const&\29 +8356:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29_4554 +8357:\28anonymous\20namespace\29::YUVPlanesRec::getCategory\28\29\20const +8358:\28anonymous\20namespace\29::YUVPlanesRec::diagnostic_only_getDiscardable\28\29\20const +8359:\28anonymous\20namespace\29::YUVPlanesRec::bytesUsed\28\29\20const +8360:\28anonymous\20namespace\29::YUVPlanesRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +8361:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29_11694 +8362:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29 +8363:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29_11678 +8364:\28anonymous\20namespace\29::TriangulatingPathOp::visitProxies\28std::__2::function\20const&\29\20const +8365:\28anonymous\20namespace\29::TriangulatingPathOp::programInfo\28\29 +8366:\28anonymous\20namespace\29::TriangulatingPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8367:\28anonymous\20namespace\29::TriangulatingPathOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8368:\28anonymous\20namespace\29::TriangulatingPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8369:\28anonymous\20namespace\29::TriangulatingPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8370:\28anonymous\20namespace\29::TriangulatingPathOp::name\28\29\20const +8371:\28anonymous\20namespace\29::TriangulatingPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8372:\28anonymous\20namespace\29::TransformedMaskSubRun::unflattenSize\28\29\20const +8373:\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +8374:\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +8375:\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +8376:\28anonymous\20namespace\29::TransformedMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +8377:\28anonymous\20namespace\29::TransformedMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +8378:\28anonymous\20namespace\29::TransformedMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +8379:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29_11654 +8380:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29 +8381:\28anonymous\20namespace\29::TextureOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8382:\28anonymous\20namespace\29::TextureOpImpl::programInfo\28\29 +8383:\28anonymous\20namespace\29::TextureOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8384:\28anonymous\20namespace\29::TextureOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8385:\28anonymous\20namespace\29::TextureOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8386:\28anonymous\20namespace\29::TextureOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8387:\28anonymous\20namespace\29::TextureOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8388:\28anonymous\20namespace\29::TextureOpImpl::name\28\29\20const +8389:\28anonymous\20namespace\29::TextureOpImpl::fixedFunctionFlags\28\29\20const +8390:\28anonymous\20namespace\29::TextureOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8391:\28anonymous\20namespace\29::TentPass::startBlur\28\29 +8392:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +8393:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +8394:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +8395:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29_11699 +8396:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29 +8397:\28anonymous\20namespace\29::StaticVertexAllocator::unlock\28int\29 +8398:\28anonymous\20namespace\29::StaticVertexAllocator::lock\28unsigned\20long\2c\20int\29 +8399:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::currentScript\28\29\20const +8400:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::consume\28\29 +8401:\28anonymous\20namespace\29::SkShaderImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8402:\28anonymous\20namespace\29::SkShaderImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8403:\28anonymous\20namespace\29::SkShaderImageFilter::getTypeName\28\29\20const +8404:\28anonymous\20namespace\29::SkShaderImageFilter::flatten\28SkWriteBuffer&\29\20const +8405:\28anonymous\20namespace\29::SkShaderImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8406:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8407:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8408:\28anonymous\20namespace\29::SkMorphologyImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8409:\28anonymous\20namespace\29::SkMorphologyImageFilter::getTypeName\28\29\20const +8410:\28anonymous\20namespace\29::SkMorphologyImageFilter::flatten\28SkWriteBuffer&\29\20const +8411:\28anonymous\20namespace\29::SkMorphologyImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8412:\28anonymous\20namespace\29::SkMergeImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8413:\28anonymous\20namespace\29::SkMergeImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8414:\28anonymous\20namespace\29::SkMergeImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8415:\28anonymous\20namespace\29::SkMergeImageFilter::getTypeName\28\29\20const +8416:\28anonymous\20namespace\29::SkMergeImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8417:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8418:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8419:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8420:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::getTypeName\28\29\20const +8421:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::flatten\28SkWriteBuffer&\29\20const +8422:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8423:\28anonymous\20namespace\29::SkImageImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8424:\28anonymous\20namespace\29::SkImageImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8425:\28anonymous\20namespace\29::SkImageImageFilter::getTypeName\28\29\20const +8426:\28anonymous\20namespace\29::SkImageImageFilter::flatten\28SkWriteBuffer&\29\20const +8427:\28anonymous\20namespace\29::SkImageImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8428:\28anonymous\20namespace\29::SkFTGeometrySink::Quad\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +8429:\28anonymous\20namespace\29::SkFTGeometrySink::Move\28FT_Vector_\20const*\2c\20void*\29 +8430:\28anonymous\20namespace\29::SkFTGeometrySink::Line\28FT_Vector_\20const*\2c\20void*\29 +8431:\28anonymous\20namespace\29::SkFTGeometrySink::Cubic\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +8432:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +8433:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFamilyName\28SkString*\29\20const +8434:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +8435:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateFamilyNameIterator\28\29\20const +8436:\28anonymous\20namespace\29::SkEmptyTypeface::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +8437:\28anonymous\20namespace\29::SkEmptyTypeface::MakeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29 +8438:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8439:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8440:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8441:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::getTypeName\28\29\20const +8442:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::flatten\28SkWriteBuffer&\29\20const +8443:\28anonymous\20namespace\29::SkDisplacementMapImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8444:\28anonymous\20namespace\29::SkCropImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8445:\28anonymous\20namespace\29::SkCropImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8446:\28anonymous\20namespace\29::SkCropImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8447:\28anonymous\20namespace\29::SkCropImageFilter::onAffectsTransparentBlack\28\29\20const +8448:\28anonymous\20namespace\29::SkCropImageFilter::getTypeName\28\29\20const +8449:\28anonymous\20namespace\29::SkCropImageFilter::flatten\28SkWriteBuffer&\29\20const +8450:\28anonymous\20namespace\29::SkCropImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8451:\28anonymous\20namespace\29::SkComposeImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8452:\28anonymous\20namespace\29::SkComposeImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8453:\28anonymous\20namespace\29::SkComposeImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8454:\28anonymous\20namespace\29::SkComposeImageFilter::getTypeName\28\29\20const +8455:\28anonymous\20namespace\29::SkComposeImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8456:\28anonymous\20namespace\29::SkColorFilterImageFilter::onIsColorFilterNode\28SkColorFilter**\29\20const +8457:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8458:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8459:\28anonymous\20namespace\29::SkColorFilterImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8460:\28anonymous\20namespace\29::SkColorFilterImageFilter::onAffectsTransparentBlack\28\29\20const +8461:\28anonymous\20namespace\29::SkColorFilterImageFilter::getTypeName\28\29\20const +8462:\28anonymous\20namespace\29::SkColorFilterImageFilter::flatten\28SkWriteBuffer&\29\20const +8463:\28anonymous\20namespace\29::SkColorFilterImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8464:\28anonymous\20namespace\29::SkBlurImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8465:\28anonymous\20namespace\29::SkBlurImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8466:\28anonymous\20namespace\29::SkBlurImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8467:\28anonymous\20namespace\29::SkBlurImageFilter::getTypeName\28\29\20const +8468:\28anonymous\20namespace\29::SkBlurImageFilter::flatten\28SkWriteBuffer&\29\20const +8469:\28anonymous\20namespace\29::SkBlurImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8470:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29_5787 +8471:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29 +8472:\28anonymous\20namespace\29::SkBlendImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +8473:\28anonymous\20namespace\29::SkBlendImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +8474:\28anonymous\20namespace\29::SkBlendImageFilter::onFilterImage\28skif::Context\20const&\29\20const +8475:\28anonymous\20namespace\29::SkBlendImageFilter::onAffectsTransparentBlack\28\29\20const +8476:\28anonymous\20namespace\29::SkBlendImageFilter::getTypeName\28\29\20const +8477:\28anonymous\20namespace\29::SkBlendImageFilter::flatten\28SkWriteBuffer&\29\20const +8478:\28anonymous\20namespace\29::SkBlendImageFilter::computeFastBounds\28SkRect\20const&\29\20const +8479:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29_8025 +8480:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29 +8481:\28anonymous\20namespace\29::SkBidiIterator_icu::getLevelAt\28int\29 +8482:\28anonymous\20namespace\29::SkBidiIterator_icu::getLength\28\29 +8483:\28anonymous\20namespace\29::SimpleTriangleShader::name\28\29\20const +8484:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8485:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8486:\28anonymous\20namespace\29::ShaperHarfBuzz::~ShaperHarfBuzz\28\29_13407 +8487:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20float\2c\20SkShaper::RunHandler*\29\20const +8488:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +8489:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20bool\2c\20float\2c\20SkShaper::RunHandler*\29\20const +8490:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::~ShapeDontWrapOrReorder\28\29 +8491:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::wrap\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::BiDiRunIterator\20const&\2c\20SkShaper::LanguageRunIterator\20const&\2c\20SkShaper::ScriptRunIterator\20const&\2c\20SkShaper::FontRunIterator\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +8492:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29_5573 +8493:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29 +8494:\28anonymous\20namespace\29::ShadowInvalidator::changed\28\29 +8495:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29_11517 +8496:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29 +8497:\28anonymous\20namespace\29::ShadowCircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +8498:\28anonymous\20namespace\29::ShadowCircularRRectOp::programInfo\28\29 +8499:\28anonymous\20namespace\29::ShadowCircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8500:\28anonymous\20namespace\29::ShadowCircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8501:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8502:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8503:\28anonymous\20namespace\29::ShadowCircularRRectOp::name\28\29\20const +8504:\28anonymous\20namespace\29::ShadowCircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8505:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12547 +8506:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +8507:\28anonymous\20namespace\29::SDFTSubRun::vertexStride\28SkMatrix\20const&\29\20const +8508:\28anonymous\20namespace\29::SDFTSubRun::vertexFiller\28\29\20const +8509:\28anonymous\20namespace\29::SDFTSubRun::unflattenSize\28\29\20const +8510:\28anonymous\20namespace\29::SDFTSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +8511:\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +8512:\28anonymous\20namespace\29::SDFTSubRun::glyphs\28\29\20const +8513:\28anonymous\20namespace\29::SDFTSubRun::glyphCount\28\29\20const +8514:\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +8515:\28anonymous\20namespace\29::SDFTSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +8516:\28anonymous\20namespace\29::SDFTSubRun::doFlatten\28SkWriteBuffer&\29\20const +8517:\28anonymous\20namespace\29::SDFTSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +8518:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29_2427 +8519:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29 +8520:\28anonymous\20namespace\29::RectsBlurRec::getCategory\28\29\20const +8521:\28anonymous\20namespace\29::RectsBlurRec::diagnostic_only_getDiscardable\28\29\20const +8522:\28anonymous\20namespace\29::RectsBlurRec::bytesUsed\28\29\20const +8523:\28anonymous\20namespace\29::RectsBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +8524:\28anonymous\20namespace\29::RasterShaderBlurAlgorithm::makeDevice\28SkImageInfo\20const&\29\20const +8525:\28anonymous\20namespace\29::RasterBlurEngine::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +8526:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::maxSigma\28\29\20const +8527:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +8528:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29_2421 +8529:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29 +8530:\28anonymous\20namespace\29::RRectBlurRec::getCategory\28\29\20const +8531:\28anonymous\20namespace\29::RRectBlurRec::diagnostic_only_getDiscardable\28\29\20const +8532:\28anonymous\20namespace\29::RRectBlurRec::bytesUsed\28\29\20const +8533:\28anonymous\20namespace\29::RRectBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +8534:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29_12611 +8535:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29 +8536:\28anonymous\20namespace\29::PathSubRun::unflattenSize\28\29\20const +8537:\28anonymous\20namespace\29::PathSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +8538:\28anonymous\20namespace\29::PathSubRun::doFlatten\28SkWriteBuffer&\29\20const +8539:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29_1327 +8540:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29 +8541:\28anonymous\20namespace\29::MipMapRec::getCategory\28\29\20const +8542:\28anonymous\20namespace\29::MipMapRec::diagnostic_only_getDiscardable\28\29\20const +8543:\28anonymous\20namespace\29::MipMapRec::bytesUsed\28\29\20const +8544:\28anonymous\20namespace\29::MipMapRec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +8545:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29_11740 +8546:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29 +8547:\28anonymous\20namespace\29::MiddleOutShader::name\28\29\20const +8548:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8549:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8550:\28anonymous\20namespace\29::MiddleOutShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8551:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29_11043 +8552:\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const +8553:\28anonymous\20namespace\29::MeshOp::programInfo\28\29 +8554:\28anonymous\20namespace\29::MeshOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8555:\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8556:\28anonymous\20namespace\29::MeshOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8557:\28anonymous\20namespace\29::MeshOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8558:\28anonymous\20namespace\29::MeshOp::name\28\29\20const +8559:\28anonymous\20namespace\29::MeshOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8560:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29_11070 +8561:\28anonymous\20namespace\29::MeshGP::onTextureSampler\28int\29\20const +8562:\28anonymous\20namespace\29::MeshGP::name\28\29\20const +8563:\28anonymous\20namespace\29::MeshGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8564:\28anonymous\20namespace\29::MeshGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8565:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29_11083 +8566:\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8567:\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8568:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +8569:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +8570:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +8571:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +8572:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMangledName\28char\20const*\29 +8573:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMainName\28\29 +8574:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +8575:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +8576:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +8577:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareFunction\28char\20const*\29 +8578:\28anonymous\20namespace\29::ImageFromPictureRec::~ImageFromPictureRec\28\29_4830 +8579:\28anonymous\20namespace\29::ImageFromPictureRec::~ImageFromPictureRec\28\29 +8580:\28anonymous\20namespace\29::ImageFromPictureRec::getCategory\28\29\20const +8581:\28anonymous\20namespace\29::ImageFromPictureRec::bytesUsed\28\29\20const +8582:\28anonymous\20namespace\29::ImageFromPictureRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +8583:\28anonymous\20namespace\29::HQDownSampler::buildLevel\28SkPixmap\20const&\2c\20SkPixmap\20const&\29 +8584:\28anonymous\20namespace\29::GaussPass::startBlur\28\29 +8585:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +8586:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +8587:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +8588:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29_11160 +8589:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29 +8590:\28anonymous\20namespace\29::FillRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8591:\28anonymous\20namespace\29::FillRectOpImpl::programInfo\28\29 +8592:\28anonymous\20namespace\29::FillRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8593:\28anonymous\20namespace\29::FillRectOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8594:\28anonymous\20namespace\29::FillRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8595:\28anonymous\20namespace\29::FillRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8596:\28anonymous\20namespace\29::FillRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8597:\28anonymous\20namespace\29::FillRectOpImpl::name\28\29\20const +8598:\28anonymous\20namespace\29::FillRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8599:\28anonymous\20namespace\29::EllipticalRRectEffect::onMakeProgramImpl\28\29\20const +8600:\28anonymous\20namespace\29::EllipticalRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8601:\28anonymous\20namespace\29::EllipticalRRectEffect::name\28\29\20const +8602:\28anonymous\20namespace\29::EllipticalRRectEffect::clone\28\29\20const +8603:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +8604:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +8605:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29_12619 +8606:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29 +8607:\28anonymous\20namespace\29::DrawableSubRun::unflattenSize\28\29\20const +8608:\28anonymous\20namespace\29::DrawableSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +8609:\28anonymous\20namespace\29::DrawableSubRun::doFlatten\28SkWriteBuffer&\29\20const +8610:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29_11028 +8611:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29 +8612:\28anonymous\20namespace\29::DrawAtlasPathShader::onTextureSampler\28int\29\20const +8613:\28anonymous\20namespace\29::DrawAtlasPathShader::name\28\29\20const +8614:\28anonymous\20namespace\29::DrawAtlasPathShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8615:\28anonymous\20namespace\29::DrawAtlasPathShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8616:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8617:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8618:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29_11000 +8619:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29 +8620:\28anonymous\20namespace\29::DrawAtlasOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8621:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8622:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8623:\28anonymous\20namespace\29::DrawAtlasOpImpl::name\28\29\20const +8624:\28anonymous\20namespace\29::DrawAtlasOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8625:\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +8626:\28anonymous\20namespace\29::DirectMaskSubRun::unflattenSize\28\29\20const +8627:\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +8628:\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +8629:\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +8630:\28anonymous\20namespace\29::DirectMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +8631:\28anonymous\20namespace\29::DirectMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +8632:\28anonymous\20namespace\29::DirectMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +8633:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29_10985 +8634:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29 +8635:\28anonymous\20namespace\29::DefaultPathOp::visitProxies\28std::__2::function\20const&\29\20const +8636:\28anonymous\20namespace\29::DefaultPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8637:\28anonymous\20namespace\29::DefaultPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8638:\28anonymous\20namespace\29::DefaultPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8639:\28anonymous\20namespace\29::DefaultPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8640:\28anonymous\20namespace\29::DefaultPathOp::name\28\29\20const +8641:\28anonymous\20namespace\29::DefaultPathOp::fixedFunctionFlags\28\29\20const +8642:\28anonymous\20namespace\29::DefaultPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8643:\28anonymous\20namespace\29::CircularRRectEffect::onMakeProgramImpl\28\29\20const +8644:\28anonymous\20namespace\29::CircularRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8645:\28anonymous\20namespace\29::CircularRRectEffect::name\28\29\20const +8646:\28anonymous\20namespace\29::CircularRRectEffect::clone\28\29\20const +8647:\28anonymous\20namespace\29::CircularRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +8648:\28anonymous\20namespace\29::CircularRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +8649:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29_5567 +8650:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29 +8651:\28anonymous\20namespace\29::CachedTessellationsRec::getCategory\28\29\20const +8652:\28anonymous\20namespace\29::CachedTessellationsRec::bytesUsed\28\29\20const +8653:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29_5565 +8654:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29_2245 +8655:\28anonymous\20namespace\29::CacheImpl::set\28SkImageFilterCacheKey\20const&\2c\20SkImageFilter\20const*\2c\20skif::FilterResult\20const&\29 +8656:\28anonymous\20namespace\29::CacheImpl::purge\28\29 +8657:\28anonymous\20namespace\29::CacheImpl::purgeByImageFilter\28SkImageFilter\20const*\29 +8658:\28anonymous\20namespace\29::CacheImpl::get\28SkImageFilterCacheKey\20const&\2c\20skif::FilterResult*\29\20const +8659:\28anonymous\20namespace\29::BoundingBoxShader::name\28\29\20const +8660:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8661:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8662:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8663:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29_10807 +8664:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29 +8665:\28anonymous\20namespace\29::AAHairlineOp::visitProxies\28std::__2::function\20const&\29\20const +8666:\28anonymous\20namespace\29::AAHairlineOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8667:\28anonymous\20namespace\29::AAHairlineOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8668:\28anonymous\20namespace\29::AAHairlineOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8669:\28anonymous\20namespace\29::AAHairlineOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8670:\28anonymous\20namespace\29::AAHairlineOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8671:\28anonymous\20namespace\29::AAHairlineOp::name\28\29\20const +8672:\28anonymous\20namespace\29::AAHairlineOp::fixedFunctionFlags\28\29\20const +8673:\28anonymous\20namespace\29::AAHairlineOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8674:YuvToRgbaRow +8675:YuvToRgba4444Row +8676:YuvToRgbRow +8677:YuvToRgb565Row +8678:YuvToBgraRow +8679:YuvToBgrRow +8680:YuvToArgbRow +8681:Write_CVT_Stretched +8682:Write_CVT +8683:WebPYuv444ToRgba_C +8684:WebPYuv444ToRgba4444_C +8685:WebPYuv444ToRgb_C +8686:WebPYuv444ToRgb565_C +8687:WebPYuv444ToBgra_C +8688:WebPYuv444ToBgr_C +8689:WebPYuv444ToArgb_C +8690:WebPRescalerImportRowShrink_C +8691:WebPRescalerImportRowExpand_C +8692:WebPRescalerExportRowShrink_C +8693:WebPRescalerExportRowExpand_C +8694:WebPMultRow_C +8695:WebPMultARGBRow_C +8696:WebPConvertRGBA32ToUV_C +8697:WebPConvertARGBToUV_C +8698:WebGLTextureImageGenerator::~WebGLTextureImageGenerator\28\29_890 +8699:WebGLTextureImageGenerator::generateExternalTexture\28GrRecordingContext*\2c\20skgpu::Mipmapped\29 +8700:Vertish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +8701:Vertish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +8702:VerticalUnfilter_C +8703:VerticalFilter_C +8704:VertState::Triangles\28VertState*\29 +8705:VertState::TrianglesX\28VertState*\29 +8706:VertState::TriangleStrip\28VertState*\29 +8707:VertState::TriangleStripX\28VertState*\29 +8708:VertState::TriangleFan\28VertState*\29 +8709:VertState::TriangleFanX\28VertState*\29 +8710:VR4_C +8711:VP8LTransformColorInverse_C +8712:VP8LPredictor9_C +8713:VP8LPredictor8_C +8714:VP8LPredictor7_C +8715:VP8LPredictor6_C +8716:VP8LPredictor5_C +8717:VP8LPredictor4_C +8718:VP8LPredictor3_C +8719:VP8LPredictor2_C +8720:VP8LPredictor1_C +8721:VP8LPredictor13_C +8722:VP8LPredictor12_C +8723:VP8LPredictor11_C +8724:VP8LPredictor10_C +8725:VP8LPredictor0_C +8726:VP8LConvertBGRAToRGB_C +8727:VP8LConvertBGRAToRGBA_C +8728:VP8LConvertBGRAToRGBA4444_C +8729:VP8LConvertBGRAToRGB565_C +8730:VP8LConvertBGRAToBGR_C +8731:VP8LAddGreenToBlueAndRed_C +8732:VLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +8733:VLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +8734:VL4_C +8735:VFilter8i_C +8736:VFilter8_C +8737:VFilter16i_C +8738:VFilter16_C +8739:VE8uv_C +8740:VE4_C +8741:VE16_C +8742:UpsampleRgbaLinePair_C +8743:UpsampleRgba4444LinePair_C +8744:UpsampleRgbLinePair_C +8745:UpsampleRgb565LinePair_C +8746:UpsampleBgraLinePair_C +8747:UpsampleBgrLinePair_C +8748:UpsampleArgbLinePair_C +8749:UnresolvedCodepoints\28skia::textlayout::Paragraph&\29 +8750:TransformWHAT_C +8751:TransformUV_C +8752:TransformTwo_C +8753:TransformDC_C +8754:TransformDCUV_C +8755:TransformAC3_C +8756:ToSVGString\28SkPath\20const&\29 +8757:ToCmds\28SkPath\20const&\29 +8758:TT_Set_MM_Blend +8759:TT_RunIns +8760:TT_Load_Simple_Glyph +8761:TT_Load_Glyph_Header +8762:TT_Load_Composite_Glyph +8763:TT_Get_Var_Design +8764:TT_Get_MM_Blend +8765:TT_Forget_Glyph_Frame +8766:TT_Access_Glyph_Frame +8767:TM8uv_C +8768:TM4_C +8769:TM16_C +8770:Sync +8771:SquareCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +8772:Sprite_D32_S32::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +8773:SkWuffsFrameHolder::onGetFrame\28int\29\20const +8774:SkWuffsCodec::~SkWuffsCodec\28\29_13319 +8775:SkWuffsCodec::~SkWuffsCodec\28\29 +8776:SkWuffsCodec::onIncrementalDecode\28int*\29 +8777:SkWuffsCodec::onGetRepetitionCount\28\29 +8778:SkWuffsCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +8779:SkWuffsCodec::onGetFrameInfo\28int\2c\20SkCodec::FrameInfo*\29\20const +8780:SkWuffsCodec::onGetFrameCount\28\29 +8781:SkWuffsCodec::getFrameHolder\28\29\20const +8782:SkWuffsCodec::getEncodedData\28\29\20const +8783:SkWriteICCProfile\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +8784:SkWebpDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +8785:SkWebpCodec::~SkWebpCodec\28\29_12999 +8786:SkWebpCodec::~SkWebpCodec\28\29 +8787:SkWebpCodec::onGetValidSubset\28SkIRect*\29\20const +8788:SkWebpCodec::onGetRepetitionCount\28\29 +8789:SkWebpCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +8790:SkWebpCodec::onGetFrameInfo\28int\2c\20SkCodec::FrameInfo*\29\20const +8791:SkWebpCodec::onGetFrameCount\28\29 +8792:SkWebpCodec::getFrameHolder\28\29\20const +8793:SkWebpCodec::FrameHolder::~FrameHolder\28\29_12997 +8794:SkWebpCodec::FrameHolder::~FrameHolder\28\29 +8795:SkWebpCodec::FrameHolder::onGetFrame\28int\29\20const +8796:SkWeakRefCnt::internal_dispose\28\29\20const +8797:SkWbmpDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +8798:SkWbmpCodec::~SkWbmpCodec\28\29_6158 +8799:SkWbmpCodec::~SkWbmpCodec\28\29 +8800:SkWbmpCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +8801:SkWbmpCodec::onSkipScanlines\28int\29 +8802:SkWbmpCodec::onRewind\28\29 +8803:SkWbmpCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +8804:SkWbmpCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +8805:SkWbmpCodec::getSampler\28bool\29 +8806:SkWbmpCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +8807:SkVertices::Builder*\20emscripten::internal::operator_new\28SkVertices::VertexMode&&\2c\20int&&\2c\20int&&\2c\20unsigned\20int&&\29 +8808:SkUserTypeface::~SkUserTypeface\28\29_5454 +8809:SkUserTypeface::~SkUserTypeface\28\29 +8810:SkUserTypeface::onOpenStream\28int*\29\20const +8811:SkUserTypeface::onGetUPEM\28\29\20const +8812:SkUserTypeface::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +8813:SkUserTypeface::onGetFamilyName\28SkString*\29\20const +8814:SkUserTypeface::onFilterRec\28SkScalerContextRec*\29\20const +8815:SkUserTypeface::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +8816:SkUserTypeface::onCountGlyphs\28\29\20const +8817:SkUserTypeface::onComputeBounds\28SkRect*\29\20const +8818:SkUserTypeface::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +8819:SkUserTypeface::getGlyphToUnicodeMap\28int*\29\20const +8820:SkUserScalerContext::~SkUserScalerContext\28\29 +8821:SkUserScalerContext::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +8822:SkUserScalerContext::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +8823:SkUserScalerContext::generateImage\28SkGlyph\20const&\2c\20void*\29 +8824:SkUserScalerContext::generateFontMetrics\28SkFontMetrics*\29 +8825:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::~DrawableMatrixWrapper\28\29_5474 +8826:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::~DrawableMatrixWrapper\28\29 +8827:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::onGetBounds\28\29 +8828:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::onDraw\28SkCanvas*\29 +8829:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29::DrawableMatrixWrapper::onApproximateBytesUsed\28\29 +8830:SkUserScalerContext::generateDrawable\28SkGlyph\20const&\29 +8831:SkUnicode_client::~SkUnicode_client\28\29_8043 +8832:SkUnicode_client::~SkUnicode_client\28\29 +8833:SkUnicode_client::toUpper\28SkString\20const&\2c\20char\20const*\29 +8834:SkUnicode_client::toUpper\28SkString\20const&\29 +8835:SkUnicode_client::reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29 +8836:SkUnicode_client::makeBreakIterator\28char\20const*\2c\20SkUnicode::BreakType\29 +8837:SkUnicode_client::makeBreakIterator\28SkUnicode::BreakType\29 +8838:SkUnicode_client::makeBidiIterator\28unsigned\20short\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +8839:SkUnicode_client::makeBidiIterator\28char\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +8840:SkUnicode_client::getWords\28char\20const*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +8841:SkUnicode_client::getBidiRegions\28char\20const*\2c\20int\2c\20SkUnicode::TextDirection\2c\20std::__2::vector>*\29 +8842:SkUnicode_client::computeCodeUnitFlags\28char16_t*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +8843:SkUnicode_client::computeCodeUnitFlags\28char*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +8844:SkUnicodeHardCodedCharProperties::isWhitespace\28int\29 +8845:SkUnicodeHardCodedCharProperties::isTabulation\28int\29 +8846:SkUnicodeHardCodedCharProperties::isSpace\28int\29 +8847:SkUnicodeHardCodedCharProperties::isIdeographic\28int\29 +8848:SkUnicodeHardCodedCharProperties::isHardBreak\28int\29 +8849:SkUnicodeHardCodedCharProperties::isControl\28int\29 +8850:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29_13371 +8851:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29 +8852:SkUnicodeBidiRunIterator::endOfCurrentRun\28\29\20const +8853:SkUnicodeBidiRunIterator::currentLevel\28\29\20const +8854:SkUnicodeBidiRunIterator::consume\28\29 +8855:SkUnicodeBidiRunIterator::atEnd\28\29\20const +8856:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29_8156 +8857:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29 +8858:SkTypeface_FreeTypeStream::onOpenStream\28int*\29\20const +8859:SkTypeface_FreeTypeStream::onMakeFontData\28\29\20const +8860:SkTypeface_FreeTypeStream::onMakeClone\28SkFontArguments\20const&\29\20const +8861:SkTypeface_FreeTypeStream::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +8862:SkTypeface_FreeType::onGlyphMaskNeedsCurrentColor\28\29\20const +8863:SkTypeface_FreeType::onGetVariationDesignPosition\28SkFontArguments::VariationPosition::Coordinate*\2c\20int\29\20const +8864:SkTypeface_FreeType::onGetVariationDesignParameters\28SkFontParameters::Variation::Axis*\2c\20int\29\20const +8865:SkTypeface_FreeType::onGetUPEM\28\29\20const +8866:SkTypeface_FreeType::onGetTableTags\28unsigned\20int*\29\20const +8867:SkTypeface_FreeType::onGetTableData\28unsigned\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20void*\29\20const +8868:SkTypeface_FreeType::onGetPostScriptName\28SkString*\29\20const +8869:SkTypeface_FreeType::onGetKerningPairAdjustments\28unsigned\20short\20const*\2c\20int\2c\20int*\29\20const +8870:SkTypeface_FreeType::onGetAdvancedMetrics\28\29\20const +8871:SkTypeface_FreeType::onFilterRec\28SkScalerContextRec*\29\20const +8872:SkTypeface_FreeType::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +8873:SkTypeface_FreeType::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +8874:SkTypeface_FreeType::onCreateFamilyNameIterator\28\29\20const +8875:SkTypeface_FreeType::onCountGlyphs\28\29\20const +8876:SkTypeface_FreeType::onCopyTableData\28unsigned\20int\29\20const +8877:SkTypeface_FreeType::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +8878:SkTypeface_FreeType::getPostScriptGlyphNames\28SkString*\29\20const +8879:SkTypeface_FreeType::getGlyphToUnicodeMap\28int*\29\20const +8880:SkTypeface_Empty::~SkTypeface_Empty\28\29 +8881:SkTypeface_Custom::~SkTypeface_Custom\28\29_8099 +8882:SkTypeface_Custom::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +8883:SkTypeface::onOpenExistingStream\28int*\29\20const +8884:SkTypeface::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +8885:SkTypeface::onCopyTableData\28unsigned\20int\29\20const +8886:SkTypeface::onComputeBounds\28SkRect*\29\20const +8887:SkTrimPE::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +8888:SkTrimPE::getTypeName\28\29\20const +8889:SkTriColorShader::type\28\29\20const +8890:SkTriColorShader::isOpaque\28\29\20const +8891:SkTriColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +8892:SkTransformShader::type\28\29\20const +8893:SkTransformShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +8894:SkTQuad::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +8895:SkTQuad::setBounds\28SkDRect*\29\20const +8896:SkTQuad::ptAtT\28double\29\20const +8897:SkTQuad::make\28SkArenaAlloc&\29\20const +8898:SkTQuad::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +8899:SkTQuad::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +8900:SkTQuad::dxdyAtT\28double\29\20const +8901:SkTQuad::debugInit\28\29 +8902:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29_4002 +8903:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29 +8904:SkTCubic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +8905:SkTCubic::setBounds\28SkDRect*\29\20const +8906:SkTCubic::ptAtT\28double\29\20const +8907:SkTCubic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +8908:SkTCubic::make\28SkArenaAlloc&\29\20const +8909:SkTCubic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +8910:SkTCubic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +8911:SkTCubic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +8912:SkTCubic::dxdyAtT\28double\29\20const +8913:SkTCubic::debugInit\28\29 +8914:SkTCubic::controlsInside\28\29\20const +8915:SkTCubic::collapsed\28\29\20const +8916:SkTConic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +8917:SkTConic::setBounds\28SkDRect*\29\20const +8918:SkTConic::ptAtT\28double\29\20const +8919:SkTConic::make\28SkArenaAlloc&\29\20const +8920:SkTConic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +8921:SkTConic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +8922:SkTConic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +8923:SkTConic::dxdyAtT\28double\29\20const +8924:SkTConic::debugInit\28\29 +8925:SkSwizzler::onSetSampleX\28int\29 +8926:SkSwizzler::fillWidth\28\29\20const +8927:SkSweepGradient::getTypeName\28\29\20const +8928:SkSweepGradient::flatten\28SkWriteBuffer&\29\20const +8929:SkSweepGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +8930:SkSweepGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +8931:SkSurface_Raster::~SkSurface_Raster\28\29_4715 +8932:SkSurface_Raster::~SkSurface_Raster\28\29 +8933:SkSurface_Raster::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +8934:SkSurface_Raster::onRestoreBackingMutability\28\29 +8935:SkSurface_Raster::onNewSurface\28SkImageInfo\20const&\29 +8936:SkSurface_Raster::onNewImageSnapshot\28SkIRect\20const*\29 +8937:SkSurface_Raster::onNewCanvas\28\29 +8938:SkSurface_Raster::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +8939:SkSurface_Raster::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +8940:SkSurface_Raster::imageInfo\28\29\20const +8941:SkSurface_Ganesh::~SkSurface_Ganesh\28\29_11701 +8942:SkSurface_Ganesh::~SkSurface_Ganesh\28\29 +8943:SkSurface_Ganesh::replaceBackendTexture\28GrBackendTexture\20const&\2c\20GrSurfaceOrigin\2c\20SkSurface::ContentChangeMode\2c\20void\20\28*\29\28void*\29\2c\20void*\29 +8944:SkSurface_Ganesh::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +8945:SkSurface_Ganesh::onWait\28int\2c\20GrBackendSemaphore\20const*\2c\20bool\29 +8946:SkSurface_Ganesh::onNewSurface\28SkImageInfo\20const&\29 +8947:SkSurface_Ganesh::onNewImageSnapshot\28SkIRect\20const*\29 +8948:SkSurface_Ganesh::onNewCanvas\28\29 +8949:SkSurface_Ganesh::onIsCompatible\28GrSurfaceCharacterization\20const&\29\20const +8950:SkSurface_Ganesh::onGetRecordingContext\28\29\20const +8951:SkSurface_Ganesh::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +8952:SkSurface_Ganesh::onDiscard\28\29 +8953:SkSurface_Ganesh::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +8954:SkSurface_Ganesh::onCharacterize\28GrSurfaceCharacterization*\29\20const +8955:SkSurface_Ganesh::onCapabilities\28\29 +8956:SkSurface_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +8957:SkSurface_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +8958:SkSurface_Ganesh::imageInfo\28\29\20const +8959:SkSurface_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +8960:SkSurface::imageInfo\28\29\20const +8961:SkSurface::height\28\29\20const +8962:SkString*\20std::__2::vector>::__emplace_back_slow_path\28char\20const*&\2c\20int&&\29 +8963:SkStrikeCache::~SkStrikeCache\28\29_4246 +8964:SkStrikeCache::~SkStrikeCache\28\29 +8965:SkStrikeCache::findOrCreateScopedStrike\28SkStrikeSpec\20const&\29 +8966:SkStrike::~SkStrike\28\29_4233 +8967:SkStrike::strikePromise\28\29 +8968:SkStrike::roundingSpec\28\29\20const +8969:SkStrike::prepareForPath\28SkGlyph*\29 +8970:SkStrike::prepareForImage\28SkGlyph*\29 +8971:SkStrike::prepareForDrawable\28SkGlyph*\29 +8972:SkStrike::getDescriptor\28\29\20const +8973:SkSpriteBlitter_Memcpy::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +8974:SkSpriteBlitter::~SkSpriteBlitter\28\29_1503 +8975:SkSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +8976:SkSpriteBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +8977:SkSpriteBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +8978:SkSpriteBlitter::blitH\28int\2c\20int\2c\20int\29 +8979:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29_4125 +8980:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29 +8981:SkSpecialImage_Raster::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +8982:SkSpecialImage_Raster::getSize\28\29\20const +8983:SkSpecialImage_Raster::backingStoreDimensions\28\29\20const +8984:SkSpecialImage_Raster::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +8985:SkSpecialImage_Raster::asImage\28\29\20const +8986:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29_10750 +8987:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29 +8988:SkSpecialImage_Gpu::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +8989:SkSpecialImage_Gpu::getSize\28\29\20const +8990:SkSpecialImage_Gpu::backingStoreDimensions\28\29\20const +8991:SkSpecialImage_Gpu::asImage\28\29\20const +8992:SkSpecialImage::~SkSpecialImage\28\29 +8993:SkSpecialImage::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +8994:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29_13364 +8995:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29 +8996:SkShaper::TrivialLanguageRunIterator::currentLanguage\28\29\20const +8997:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29_7569 +8998:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29 +8999:SkShaper::TrivialBiDiRunIterator::currentLevel\28\29\20const +9000:SkShaderBlurAlgorithm::maxSigma\28\29\20const +9001:SkShaderBlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +9002:SkScan::HairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9003:SkScan::HairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9004:SkScan::HairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9005:SkScan::AntiHairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9006:SkScan::AntiHairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9007:SkScan::AntiHairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9008:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +9009:SkScalingCodec::onGetScaledDimensions\28float\29\20const +9010:SkScalingCodec::onDimensionsSupported\28SkISize\20const&\29 +9011:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29_8131 +9012:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29 +9013:SkScalerContext_FreeType::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +9014:SkScalerContext_FreeType::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +9015:SkScalerContext_FreeType::generateImage\28SkGlyph\20const&\2c\20void*\29 +9016:SkScalerContext_FreeType::generateFontMetrics\28SkFontMetrics*\29 +9017:SkScalerContext_FreeType::generateDrawable\28SkGlyph\20const&\29 +9018:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::~SkScalerContext_Empty\28\29 +9019:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +9020:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +9021:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateFontMetrics\28SkFontMetrics*\29 +9022:SkSampledCodec::onGetSampledDimensions\28int\29\20const +9023:SkSampledCodec::onGetAndroidPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const&\29 +9024:SkSRGBColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +9025:SkSRGBColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +9026:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_3::__invoke\28double\2c\20double\29 +9027:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_2::__invoke\28double\2c\20double\29 +9028:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_1::__invoke\28double\2c\20double\29 +9029:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_0::__invoke\28double\2c\20double\29 +9030:SkSL::remove_break_statements\28std::__2::unique_ptr>&\29::RemoveBreaksWriter::visitStatementPtr\28std::__2::unique_ptr>&\29 +9031:SkSL::hoist_vardecl_symbols_into_outer_scope\28SkSL::Context\20const&\2c\20SkSL::Block\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::SymbolTable*\29::SymbolHoister::visitStatement\28SkSL::Statement\20const&\29 +9032:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29_7365 +9033:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29 +9034:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29_7358 +9035:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29 +9036:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +9037:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitExpressionPtr\28std::__2::unique_ptr>&\29 +9038:SkSL::count_returns_at_end_of_control_flow\28SkSL::FunctionDefinition\20const&\29::CountReturnsAtEndOfControlFlow::visitStatement\28SkSL::Statement\20const&\29 +9039:SkSL::\28anonymous\20namespace\29::VariableWriteVisitor::visitExpression\28SkSL::Expression\20const&\29 +9040:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9041:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitExpression\28SkSL::Expression\20const&\29 +9042:SkSL::\28anonymous\20namespace\29::ReturnsNonOpaqueColorVisitor::visitStatement\28SkSL::Statement\20const&\29 +9043:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitStatement\28SkSL::Statement\20const&\29 +9044:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9045:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitStatement\28SkSL::Statement\20const&\29 +9046:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitStatement\28SkSL::Statement\20const&\29 +9047:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9048:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitExpression\28SkSL::Expression\20const&\29 +9049:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9050:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +9051:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29_6471 +9052:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29 +9053:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitExpression\28SkSL::Expression\20const&\29 +9054:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29_6496 +9055:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29 +9056:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitStatement\28SkSL::Statement\20const&\29 +9057:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitExpression\28SkSL::Expression\20const&\29 +9058:SkSL::VectorType::isOrContainsBool\28\29\20const +9059:SkSL::VectorType::isAllowedInUniform\28SkSL::Position*\29\20const +9060:SkSL::VectorType::isAllowedInES2\28\29\20const +9061:SkSL::VariableReference::clone\28SkSL::Position\29\20const +9062:SkSL::Variable::~Variable\28\29_7308 +9063:SkSL::Variable::~Variable\28\29 +9064:SkSL::Variable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +9065:SkSL::Variable::mangledName\28\29\20const +9066:SkSL::Variable::layout\28\29\20const +9067:SkSL::Variable::description\28\29\20const +9068:SkSL::VarDeclaration::~VarDeclaration\28\29_7306 +9069:SkSL::VarDeclaration::~VarDeclaration\28\29 +9070:SkSL::VarDeclaration::description\28\29\20const +9071:SkSL::TypeReference::clone\28SkSL::Position\29\20const +9072:SkSL::Type::minimumValue\28\29\20const +9073:SkSL::Type::maximumValue\28\29\20const +9074:SkSL::Type::matches\28SkSL::Type\20const&\29\20const +9075:SkSL::Type::isAllowedInUniform\28SkSL::Position*\29\20const +9076:SkSL::Type::fields\28\29\20const +9077:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29_7391 +9078:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29 +9079:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::visitStatementPtr\28std::__2::unique_ptr>&\29 +9080:SkSL::Tracer::var\28int\2c\20int\29 +9081:SkSL::Tracer::scope\28int\29 +9082:SkSL::Tracer::line\28int\29 +9083:SkSL::Tracer::exit\28int\29 +9084:SkSL::Tracer::enter\28int\29 +9085:SkSL::TextureType::textureAccess\28\29\20const +9086:SkSL::TextureType::isMultisampled\28\29\20const +9087:SkSL::TextureType::isDepth\28\29\20const +9088:SkSL::TernaryExpression::~TernaryExpression\28\29_7091 +9089:SkSL::TernaryExpression::~TernaryExpression\28\29 +9090:SkSL::TernaryExpression::description\28SkSL::OperatorPrecedence\29\20const +9091:SkSL::TernaryExpression::clone\28SkSL::Position\29\20const +9092:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression&\29 +9093:SkSL::Swizzle::description\28SkSL::OperatorPrecedence\29\20const +9094:SkSL::Swizzle::clone\28SkSL::Position\29\20const +9095:SkSL::SwitchStatement::description\28\29\20const +9096:SkSL::SwitchCase::description\28\29\20const +9097:SkSL::StructType::slotType\28unsigned\20long\29\20const +9098:SkSL::StructType::isOrContainsUnsizedArray\28\29\20const +9099:SkSL::StructType::isOrContainsBool\28\29\20const +9100:SkSL::StructType::isOrContainsAtomic\28\29\20const +9101:SkSL::StructType::isOrContainsArray\28\29\20const +9102:SkSL::StructType::isInterfaceBlock\28\29\20const +9103:SkSL::StructType::isBuiltin\28\29\20const +9104:SkSL::StructType::isAllowedInUniform\28SkSL::Position*\29\20const +9105:SkSL::StructType::isAllowedInES2\28\29\20const +9106:SkSL::StructType::fields\28\29\20const +9107:SkSL::StructDefinition::description\28\29\20const +9108:SkSL::StringStream::~StringStream\28\29_12717 +9109:SkSL::StringStream::~StringStream\28\29 +9110:SkSL::StringStream::write\28void\20const*\2c\20unsigned\20long\29 +9111:SkSL::StringStream::writeText\28char\20const*\29 +9112:SkSL::StringStream::write8\28unsigned\20char\29 +9113:SkSL::SingleArgumentConstructor::~SingleArgumentConstructor\28\29 +9114:SkSL::Setting::description\28SkSL::OperatorPrecedence\29\20const +9115:SkSL::Setting::clone\28SkSL::Position\29\20const +9116:SkSL::ScalarType::priority\28\29\20const +9117:SkSL::ScalarType::numberKind\28\29\20const +9118:SkSL::ScalarType::minimumValue\28\29\20const +9119:SkSL::ScalarType::maximumValue\28\29\20const +9120:SkSL::ScalarType::isOrContainsBool\28\29\20const +9121:SkSL::ScalarType::isAllowedInUniform\28SkSL::Position*\29\20const +9122:SkSL::ScalarType::isAllowedInES2\28\29\20const +9123:SkSL::ScalarType::bitWidth\28\29\20const +9124:SkSL::SamplerType::textureAccess\28\29\20const +9125:SkSL::SamplerType::isMultisampled\28\29\20const +9126:SkSL::SamplerType::isDepth\28\29\20const +9127:SkSL::SamplerType::isArrayedTexture\28\29\20const +9128:SkSL::SamplerType::dimensions\28\29\20const +9129:SkSL::ReturnStatement::description\28\29\20const +9130:SkSL::RP::VariableLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9131:SkSL::RP::VariableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9132:SkSL::RP::VariableLValue::isWritable\28\29\20const +9133:SkSL::RP::VariableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +9134:SkSL::RP::UnownedLValueSlice::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9135:SkSL::RP::UnownedLValueSlice::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9136:SkSL::RP::UnownedLValueSlice::fixedSlotRange\28SkSL::RP::Generator*\29 +9137:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29_6723 +9138:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29 +9139:SkSL::RP::SwizzleLValue::swizzle\28\29 +9140:SkSL::RP::SwizzleLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9141:SkSL::RP::SwizzleLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9142:SkSL::RP::SwizzleLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +9143:SkSL::RP::ScratchLValue::~ScratchLValue\28\29_6737 +9144:SkSL::RP::ScratchLValue::~ScratchLValue\28\29 +9145:SkSL::RP::ScratchLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9146:SkSL::RP::ScratchLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +9147:SkSL::RP::LValueSlice::~LValueSlice\28\29_6721 +9148:SkSL::RP::LValueSlice::~LValueSlice\28\29 +9149:SkSL::RP::LValue::~LValue\28\29_6713 +9150:SkSL::RP::ImmutableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9151:SkSL::RP::ImmutableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +9152:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29_6730 +9153:SkSL::RP::DynamicIndexLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9154:SkSL::RP::DynamicIndexLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +9155:SkSL::RP::DynamicIndexLValue::isWritable\28\29\20const +9156:SkSL::RP::DynamicIndexLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +9157:SkSL::ProgramVisitor::visitStatementPtr\28std::__2::unique_ptr>\20const&\29 +9158:SkSL::ProgramVisitor::visitExpressionPtr\28std::__2::unique_ptr>\20const&\29 +9159:SkSL::PrefixExpression::~PrefixExpression\28\29_7021 +9160:SkSL::PrefixExpression::~PrefixExpression\28\29 +9161:SkSL::PrefixExpression::description\28SkSL::OperatorPrecedence\29\20const +9162:SkSL::PrefixExpression::clone\28SkSL::Position\29\20const +9163:SkSL::PostfixExpression::description\28SkSL::OperatorPrecedence\29\20const +9164:SkSL::PostfixExpression::clone\28SkSL::Position\29\20const +9165:SkSL::Poison::description\28SkSL::OperatorPrecedence\29\20const +9166:SkSL::Poison::clone\28SkSL::Position\29\20const +9167:SkSL::PipelineStage::Callbacks::getMainName\28\29 +9168:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29_6424 +9169:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29 +9170:SkSL::Parser::Checkpoint::ForwardingErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +9171:SkSL::Nop::description\28\29\20const +9172:SkSL::MultiArgumentConstructor::~MultiArgumentConstructor\28\29 +9173:SkSL::ModifiersDeclaration::description\28\29\20const +9174:SkSL::MethodReference::description\28SkSL::OperatorPrecedence\29\20const +9175:SkSL::MethodReference::clone\28SkSL::Position\29\20const +9176:SkSL::MatrixType::slotCount\28\29\20const +9177:SkSL::MatrixType::rows\28\29\20const +9178:SkSL::MatrixType::isAllowedInES2\28\29\20const +9179:SkSL::LiteralType::minimumValue\28\29\20const +9180:SkSL::LiteralType::maximumValue\28\29\20const +9181:SkSL::LiteralType::isOrContainsBool\28\29\20const +9182:SkSL::Literal::getConstantValue\28int\29\20const +9183:SkSL::Literal::description\28SkSL::OperatorPrecedence\29\20const +9184:SkSL::Literal::compareConstant\28SkSL::Expression\20const&\29\20const +9185:SkSL::Literal::clone\28SkSL::Position\29\20const +9186:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_uintBitsToFloat\28double\2c\20double\2c\20double\29 +9187:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_trunc\28double\2c\20double\2c\20double\29 +9188:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tanh\28double\2c\20double\2c\20double\29 +9189:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tan\28double\2c\20double\2c\20double\29 +9190:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_step\28double\2c\20double\2c\20double\29 +9191:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sqrt\28double\2c\20double\2c\20double\29 +9192:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_smoothstep\28double\2c\20double\2c\20double\29 +9193:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sinh\28double\2c\20double\2c\20double\29 +9194:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sin\28double\2c\20double\2c\20double\29 +9195:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_saturate\28double\2c\20double\2c\20double\29 +9196:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_radians\28double\2c\20double\2c\20double\29 +9197:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_pow\28double\2c\20double\2c\20double\29 +9198:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mod\28double\2c\20double\2c\20double\29 +9199:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mix\28double\2c\20double\2c\20double\29 +9200:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_min\28double\2c\20double\2c\20double\29 +9201:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_max\28double\2c\20double\2c\20double\29 +9202:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_matrixCompMult\28double\2c\20double\2c\20double\29 +9203:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log\28double\2c\20double\2c\20double\29 +9204:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log2\28double\2c\20double\2c\20double\29 +9205:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_inversesqrt\28double\2c\20double\2c\20double\29 +9206:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_intBitsToFloat\28double\2c\20double\2c\20double\29 +9207:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fract\28double\2c\20double\2c\20double\29 +9208:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fma\28double\2c\20double\2c\20double\29 +9209:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floor\28double\2c\20double\2c\20double\29 +9210:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToUint\28double\2c\20double\2c\20double\29 +9211:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToInt\28double\2c\20double\2c\20double\29 +9212:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp\28double\2c\20double\2c\20double\29 +9213:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp2\28double\2c\20double\2c\20double\29 +9214:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_degrees\28double\2c\20double\2c\20double\29 +9215:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cosh\28double\2c\20double\2c\20double\29 +9216:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cos\28double\2c\20double\2c\20double\29 +9217:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_clamp\28double\2c\20double\2c\20double\29 +9218:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_ceil\28double\2c\20double\2c\20double\29 +9219:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atanh\28double\2c\20double\2c\20double\29 +9220:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan\28double\2c\20double\2c\20double\29 +9221:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan2\28double\2c\20double\2c\20double\29 +9222:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asinh\28double\2c\20double\2c\20double\29 +9223:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asin\28double\2c\20double\2c\20double\29 +9224:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acosh\28double\2c\20double\2c\20double\29 +9225:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acos\28double\2c\20double\2c\20double\29 +9226:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_abs\28double\2c\20double\2c\20double\29 +9227:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_notEqual\28double\2c\20double\29 +9228:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThan\28double\2c\20double\29 +9229:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThanEqual\28double\2c\20double\29 +9230:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThan\28double\2c\20double\29 +9231:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThanEqual\28double\2c\20double\29 +9232:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_equal\28double\2c\20double\29 +9233:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_dot\28double\2c\20double\2c\20double\29 +9234:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_any\28double\2c\20double\2c\20double\29 +9235:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_all\28double\2c\20double\2c\20double\29 +9236:SkSL::InterfaceBlock::~InterfaceBlock\28\29_6988 +9237:SkSL::InterfaceBlock::description\28\29\20const +9238:SkSL::IndexExpression::~IndexExpression\28\29_6985 +9239:SkSL::IndexExpression::~IndexExpression\28\29 +9240:SkSL::IndexExpression::description\28SkSL::OperatorPrecedence\29\20const +9241:SkSL::IndexExpression::clone\28SkSL::Position\29\20const +9242:SkSL::IfStatement::~IfStatement\28\29_6978 +9243:SkSL::IfStatement::~IfStatement\28\29 +9244:SkSL::IfStatement::description\28\29\20const +9245:SkSL::GlobalVarDeclaration::description\28\29\20const +9246:SkSL::GenericType::slotType\28unsigned\20long\29\20const +9247:SkSL::GenericType::coercibleTypes\28\29\20const +9248:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29_12792 +9249:SkSL::FunctionReference::description\28SkSL::OperatorPrecedence\29\20const +9250:SkSL::FunctionReference::clone\28SkSL::Position\29\20const +9251:SkSL::FunctionPrototype::description\28\29\20const +9252:SkSL::FunctionDefinition::description\28\29\20const +9253:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29_6969 +9254:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29 +9255:SkSL::FunctionCall::description\28SkSL::OperatorPrecedence\29\20const +9256:SkSL::FunctionCall::clone\28SkSL::Position\29\20const +9257:SkSL::ForStatement::~ForStatement\28\29_6860 +9258:SkSL::ForStatement::~ForStatement\28\29 +9259:SkSL::ForStatement::description\28\29\20const +9260:SkSL::FieldSymbol::description\28\29\20const +9261:SkSL::FieldAccess::clone\28SkSL::Position\29\20const +9262:SkSL::Extension::description\28\29\20const +9263:SkSL::ExtendedVariable::~ExtendedVariable\28\29_7310 +9264:SkSL::ExtendedVariable::~ExtendedVariable\28\29 +9265:SkSL::ExtendedVariable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +9266:SkSL::ExtendedVariable::mangledName\28\29\20const +9267:SkSL::ExtendedVariable::layout\28\29\20const +9268:SkSL::ExtendedVariable::interfaceBlock\28\29\20const +9269:SkSL::ExtendedVariable::detachDeadInterfaceBlock\28\29 +9270:SkSL::ExpressionStatement::description\28\29\20const +9271:SkSL::Expression::getConstantValue\28int\29\20const +9272:SkSL::EmptyExpression::description\28SkSL::OperatorPrecedence\29\20const +9273:SkSL::EmptyExpression::clone\28SkSL::Position\29\20const +9274:SkSL::DoStatement::description\28\29\20const +9275:SkSL::DiscardStatement::description\28\29\20const +9276:SkSL::DebugTracePriv::~DebugTracePriv\28\29_7341 +9277:SkSL::DebugTracePriv::dump\28SkWStream*\29\20const +9278:SkSL::CountReturnsWithLimit::visitStatement\28SkSL::Statement\20const&\29 +9279:SkSL::ContinueStatement::description\28\29\20const +9280:SkSL::ConstructorStruct::clone\28SkSL::Position\29\20const +9281:SkSL::ConstructorSplat::getConstantValue\28int\29\20const +9282:SkSL::ConstructorSplat::clone\28SkSL::Position\29\20const +9283:SkSL::ConstructorScalarCast::clone\28SkSL::Position\29\20const +9284:SkSL::ConstructorMatrixResize::getConstantValue\28int\29\20const +9285:SkSL::ConstructorMatrixResize::clone\28SkSL::Position\29\20const +9286:SkSL::ConstructorDiagonalMatrix::getConstantValue\28int\29\20const +9287:SkSL::ConstructorDiagonalMatrix::clone\28SkSL::Position\29\20const +9288:SkSL::ConstructorCompoundCast::clone\28SkSL::Position\29\20const +9289:SkSL::ConstructorCompound::clone\28SkSL::Position\29\20const +9290:SkSL::ConstructorArrayCast::clone\28SkSL::Position\29\20const +9291:SkSL::ConstructorArray::clone\28SkSL::Position\29\20const +9292:SkSL::Compiler::CompilerErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +9293:SkSL::CodeGenerator::~CodeGenerator\28\29 +9294:SkSL::ChildCall::description\28SkSL::OperatorPrecedence\29\20const +9295:SkSL::ChildCall::clone\28SkSL::Position\29\20const +9296:SkSL::BreakStatement::description\28\29\20const +9297:SkSL::Block::~Block\28\29_6762 +9298:SkSL::Block::~Block\28\29 +9299:SkSL::Block::isEmpty\28\29\20const +9300:SkSL::Block::description\28\29\20const +9301:SkSL::BinaryExpression::~BinaryExpression\28\29_6755 +9302:SkSL::BinaryExpression::~BinaryExpression\28\29 +9303:SkSL::BinaryExpression::description\28SkSL::OperatorPrecedence\29\20const +9304:SkSL::BinaryExpression::clone\28SkSL::Position\29\20const +9305:SkSL::ArrayType::slotType\28unsigned\20long\29\20const +9306:SkSL::ArrayType::slotCount\28\29\20const +9307:SkSL::ArrayType::matches\28SkSL::Type\20const&\29\20const +9308:SkSL::ArrayType::isUnsizedArray\28\29\20const +9309:SkSL::ArrayType::isOrContainsUnsizedArray\28\29\20const +9310:SkSL::ArrayType::isBuiltin\28\29\20const +9311:SkSL::ArrayType::isAllowedInUniform\28SkSL::Position*\29\20const +9312:SkSL::AnyConstructor::getConstantValue\28int\29\20const +9313:SkSL::AnyConstructor::description\28SkSL::OperatorPrecedence\29\20const +9314:SkSL::AnyConstructor::compareConstant\28SkSL::Expression\20const&\29\20const +9315:SkSL::Analysis::\28anonymous\20namespace\29::LoopControlFlowVisitor::visitStatement\28SkSL::Statement\20const&\29 +9316:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29::IsDynamicallyUniformExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +9317:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29::IsCompileTimeConstantVisitor::visitExpression\28SkSL::Expression\20const&\29 +9318:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29::HasSideEffectsVisitor::visitExpression\28SkSL::Expression\20const&\29 +9319:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29_6539 +9320:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29 +9321:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::visitExpression\28SkSL::Expression\20const&\29 +9322:SkSL::Analysis::ContainsVariable\28SkSL::Expression\20const&\2c\20SkSL::Variable\20const&\29::ContainsVariableVisitor::visitExpression\28SkSL::Expression\20const&\29 +9323:SkSL::Analysis::ContainsRTAdjust\28SkSL::Expression\20const&\29::ContainsRTAdjustVisitor::visitExpression\28SkSL::Expression\20const&\29 +9324:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29_6465 +9325:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29 +9326:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitExpression\28SkSL::Expression\20const&\29 +9327:SkSL::AliasType::textureAccess\28\29\20const +9328:SkSL::AliasType::slotType\28unsigned\20long\29\20const +9329:SkSL::AliasType::slotCount\28\29\20const +9330:SkSL::AliasType::rows\28\29\20const +9331:SkSL::AliasType::priority\28\29\20const +9332:SkSL::AliasType::isVector\28\29\20const +9333:SkSL::AliasType::isUnsizedArray\28\29\20const +9334:SkSL::AliasType::isStruct\28\29\20const +9335:SkSL::AliasType::isScalar\28\29\20const +9336:SkSL::AliasType::isMultisampled\28\29\20const +9337:SkSL::AliasType::isMatrix\28\29\20const +9338:SkSL::AliasType::isLiteral\28\29\20const +9339:SkSL::AliasType::isInterfaceBlock\28\29\20const +9340:SkSL::AliasType::isDepth\28\29\20const +9341:SkSL::AliasType::isArrayedTexture\28\29\20const +9342:SkSL::AliasType::isArray\28\29\20const +9343:SkSL::AliasType::dimensions\28\29\20const +9344:SkSL::AliasType::componentType\28\29\20const +9345:SkSL::AliasType::columns\28\29\20const +9346:SkSL::AliasType::coercibleTypes\28\29\20const +9347:SkRuntimeShader::~SkRuntimeShader\28\29_4841 +9348:SkRuntimeShader::type\28\29\20const +9349:SkRuntimeShader::isOpaque\28\29\20const +9350:SkRuntimeShader::getTypeName\28\29\20const +9351:SkRuntimeShader::flatten\28SkWriteBuffer&\29\20const +9352:SkRuntimeShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9353:SkRuntimeEffect::~SkRuntimeEffect\28\29_3952 +9354:SkRuntimeEffect::MakeFromSource\28SkString\2c\20SkRuntimeEffect::Options\20const&\2c\20SkSL::ProgramKind\29 +9355:SkRuntimeColorFilter::~SkRuntimeColorFilter\28\29_5779 +9356:SkRuntimeColorFilter::~SkRuntimeColorFilter\28\29 +9357:SkRuntimeColorFilter::onIsAlphaUnchanged\28\29\20const +9358:SkRuntimeColorFilter::getTypeName\28\29\20const +9359:SkRuntimeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +9360:SkRuntimeBlender::~SkRuntimeBlender\28\29_3919 +9361:SkRuntimeBlender::~SkRuntimeBlender\28\29 +9362:SkRuntimeBlender::onAppendStages\28SkStageRec\20const&\29\20const +9363:SkRuntimeBlender::getTypeName\28\29\20const +9364:SkRgnClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +9365:SkRgnClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +9366:SkRgnClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +9367:SkRgnClipBlitter::blitH\28int\2c\20int\2c\20int\29 +9368:SkRgnClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +9369:SkRgnClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +9370:SkRgnBuilder::~SkRgnBuilder\28\29_3884 +9371:SkRgnBuilder::blitH\28int\2c\20int\2c\20int\29 +9372:SkResourceCache::SetTotalByteLimit\28unsigned\20long\29 +9373:SkResourceCache::GetTotalBytesUsed\28\29 +9374:SkResourceCache::GetTotalByteLimit\28\29 +9375:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29_4663 +9376:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29 +9377:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::rowBytes\28int\29\20const +9378:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::data\28int\29\20const +9379:SkRefCntSet::~SkRefCntSet\28\29_2056 +9380:SkRefCntSet::incPtr\28void*\29 +9381:SkRefCntSet::decPtr\28void*\29 +9382:SkRectClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +9383:SkRectClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +9384:SkRectClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +9385:SkRectClipBlitter::blitH\28int\2c\20int\2c\20int\29 +9386:SkRectClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +9387:SkRectClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +9388:SkRecorder::~SkRecorder\28\29_3833 +9389:SkRecorder::~SkRecorder\28\29 +9390:SkRecorder::willSave\28\29 +9391:SkRecorder::onResetClip\28\29 +9392:SkRecorder::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9393:SkRecorder::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +9394:SkRecorder::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +9395:SkRecorder::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +9396:SkRecorder::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +9397:SkRecorder::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +9398:SkRecorder::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +9399:SkRecorder::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +9400:SkRecorder::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +9401:SkRecorder::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +9402:SkRecorder::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9403:SkRecorder::onDrawPaint\28SkPaint\20const&\29 +9404:SkRecorder::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +9405:SkRecorder::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +9406:SkRecorder::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +9407:SkRecorder::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +9408:SkRecorder::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +9409:SkRecorder::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +9410:SkRecorder::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +9411:SkRecorder::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +9412:SkRecorder::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +9413:SkRecorder::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +9414:SkRecorder::onDrawBehind\28SkPaint\20const&\29 +9415:SkRecorder::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +9416:SkRecorder::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +9417:SkRecorder::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +9418:SkRecorder::onDoSaveBehind\28SkRect\20const*\29 +9419:SkRecorder::onClipShader\28sk_sp\2c\20SkClipOp\29 +9420:SkRecorder::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +9421:SkRecorder::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +9422:SkRecorder::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +9423:SkRecorder::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +9424:SkRecorder::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +9425:SkRecorder::didTranslate\28float\2c\20float\29 +9426:SkRecorder::didSetM44\28SkM44\20const&\29 +9427:SkRecorder::didScale\28float\2c\20float\29 +9428:SkRecorder::didRestore\28\29 +9429:SkRecorder::didConcat44\28SkM44\20const&\29 +9430:SkRecordedDrawable::~SkRecordedDrawable\28\29_3780 +9431:SkRecordedDrawable::~SkRecordedDrawable\28\29 +9432:SkRecordedDrawable::onMakePictureSnapshot\28\29 +9433:SkRecordedDrawable::onGetBounds\28\29 +9434:SkRecordedDrawable::onDraw\28SkCanvas*\29 +9435:SkRecordedDrawable::onApproximateBytesUsed\28\29 +9436:SkRecordedDrawable::getTypeName\28\29\20const +9437:SkRecordedDrawable::flatten\28SkWriteBuffer&\29\20const +9438:SkRecord::~SkRecord\28\29_3734 +9439:SkRecord::~SkRecord\28\29 +9440:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29_1508 +9441:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29 +9442:SkRasterPipelineSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +9443:SkRasterPipelineSpriteBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +9444:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29_3688 +9445:SkRasterPipelineBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +9446:SkRasterPipelineBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +9447:SkRasterPipelineBlitter::blitH\28int\2c\20int\2c\20int\29 +9448:SkRasterPipelineBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +9449:SkRasterPipelineBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +9450:SkRasterPipelineBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +9451:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_3::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +9452:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_2::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +9453:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_1::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +9454:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_0::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +9455:SkRadialGradient::getTypeName\28\29\20const +9456:SkRadialGradient::flatten\28SkWriteBuffer&\29\20const +9457:SkRadialGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +9458:SkRadialGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +9459:SkRTree::~SkRTree\28\29_3623 +9460:SkRTree::~SkRTree\28\29 +9461:SkRTree::search\28SkRect\20const&\2c\20std::__2::vector>*\29\20const +9462:SkRTree::insert\28SkRect\20const*\2c\20int\29 +9463:SkRTree::bytesUsed\28\29\20const +9464:SkPtrSet::~SkPtrSet\28\29 +9465:SkPngNormalDecoder::~SkPngNormalDecoder\28\29 +9466:SkPngNormalDecoder::setRange\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +9467:SkPngNormalDecoder::decode\28int*\29 +9468:SkPngNormalDecoder::decodeAllRows\28void*\2c\20unsigned\20long\2c\20int*\29 +9469:SkPngNormalDecoder::RowCallback\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20int\2c\20int\29 +9470:SkPngNormalDecoder::AllRowsCallback\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20int\2c\20int\29 +9471:SkPngInterlacedDecoder::~SkPngInterlacedDecoder\28\29_12974 +9472:SkPngInterlacedDecoder::~SkPngInterlacedDecoder\28\29 +9473:SkPngInterlacedDecoder::setRange\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +9474:SkPngInterlacedDecoder::decode\28int*\29 +9475:SkPngInterlacedDecoder::decodeAllRows\28void*\2c\20unsigned\20long\2c\20int*\29 +9476:SkPngInterlacedDecoder::InterlacedRowCallback\28png_struct_def*\2c\20unsigned\20char*\2c\20unsigned\20int\2c\20int\29 +9477:SkPngEncoderImpl::~SkPngEncoderImpl\28\29_12839 +9478:SkPngEncoderImpl::onFinishEncoding\28\29 +9479:SkPngEncoderImpl::onEncodeRow\28SkSpan\29 +9480:SkPngEncoderBase::~SkPngEncoderBase\28\29 +9481:SkPngEncoderBase::onEncodeRows\28int\29 +9482:SkPngCompositeChunkReader::~SkPngCompositeChunkReader\28\29_12982 +9483:SkPngCompositeChunkReader::~SkPngCompositeChunkReader\28\29 +9484:SkPngCompositeChunkReader::readChunk\28char\20const*\2c\20void\20const*\2c\20unsigned\20long\29 +9485:SkPngCodecBase::initializeXforms\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\2c\20int\29 +9486:SkPngCodecBase::getSampler\28bool\29 +9487:SkPngCodec::~SkPngCodec\28\29_12966 +9488:SkPngCodec::onTryGetTrnsChunk\28\29 +9489:SkPngCodec::onTryGetPlteChunk\28\29 +9490:SkPngCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +9491:SkPngCodec::onRewind\28\29 +9492:SkPngCodec::onIncrementalDecode\28int*\29 +9493:SkPngCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9494:SkPngCodec::onGetGainmapInfo\28SkGainmapInfo*\29 +9495:SkPngCodec::onGetGainmapCodec\28SkGainmapInfo*\2c\20std::__2::unique_ptr>*\29 +9496:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_2::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +9497:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_1::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +9498:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_0::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +9499:SkPixelRef::~SkPixelRef\28\29_3554 +9500:SkPictureShader::~SkPictureShader\28\29_4825 +9501:SkPictureShader::~SkPictureShader\28\29 +9502:SkPictureShader::type\28\29\20const +9503:SkPictureShader::getTypeName\28\29\20const +9504:SkPictureShader::flatten\28SkWriteBuffer&\29\20const +9505:SkPictureShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9506:SkPictureRecorder*\20emscripten::internal::operator_new\28\29 +9507:SkPictureRecord::~SkPictureRecord\28\29_3538 +9508:SkPictureRecord::willSave\28\29 +9509:SkPictureRecord::willRestore\28\29 +9510:SkPictureRecord::onResetClip\28\29 +9511:SkPictureRecord::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9512:SkPictureRecord::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +9513:SkPictureRecord::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +9514:SkPictureRecord::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +9515:SkPictureRecord::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +9516:SkPictureRecord::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +9517:SkPictureRecord::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +9518:SkPictureRecord::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +9519:SkPictureRecord::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +9520:SkPictureRecord::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +9521:SkPictureRecord::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9522:SkPictureRecord::onDrawPaint\28SkPaint\20const&\29 +9523:SkPictureRecord::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +9524:SkPictureRecord::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +9525:SkPictureRecord::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +9526:SkPictureRecord::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +9527:SkPictureRecord::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +9528:SkPictureRecord::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +9529:SkPictureRecord::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +9530:SkPictureRecord::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +9531:SkPictureRecord::onDrawBehind\28SkPaint\20const&\29 +9532:SkPictureRecord::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +9533:SkPictureRecord::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +9534:SkPictureRecord::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +9535:SkPictureRecord::onDoSaveBehind\28SkRect\20const*\29 +9536:SkPictureRecord::onClipShader\28sk_sp\2c\20SkClipOp\29 +9537:SkPictureRecord::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +9538:SkPictureRecord::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +9539:SkPictureRecord::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +9540:SkPictureRecord::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +9541:SkPictureRecord::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +9542:SkPictureRecord::didTranslate\28float\2c\20float\29 +9543:SkPictureRecord::didSetM44\28SkM44\20const&\29 +9544:SkPictureRecord::didScale\28float\2c\20float\29 +9545:SkPictureRecord::didConcat44\28SkM44\20const&\29 +9546:SkPictureData::serialize\28SkWStream*\2c\20SkSerialProcs\20const&\2c\20SkRefCntSet*\2c\20bool\29\20const::DevNull::write\28void\20const*\2c\20unsigned\20long\29 +9547:SkPerlinNoiseShader::~SkPerlinNoiseShader\28\29_4809 +9548:SkPerlinNoiseShader::~SkPerlinNoiseShader\28\29 +9549:SkPerlinNoiseShader::getTypeName\28\29\20const +9550:SkPerlinNoiseShader::flatten\28SkWriteBuffer&\29\20const +9551:SkPerlinNoiseShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9552:SkPath::setIsVolatile\28bool\29 +9553:SkPath::setFillType\28SkPathFillType\29 +9554:SkPath::isVolatile\28\29\20const +9555:SkPath::getFillType\28\29\20const +9556:SkPath2DPathEffectImpl::~SkPath2DPathEffectImpl\28\29_5613 +9557:SkPath2DPathEffectImpl::~SkPath2DPathEffectImpl\28\29 +9558:SkPath2DPathEffectImpl::next\28SkPoint\20const&\2c\20int\2c\20int\2c\20SkPath*\29\20const +9559:SkPath2DPathEffectImpl::getTypeName\28\29\20const +9560:SkPath2DPathEffectImpl::getFactory\28\29\20const +9561:SkPath2DPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +9562:SkPath2DPathEffectImpl::CreateProc\28SkReadBuffer&\29 +9563:SkPath1DPathEffectImpl::~SkPath1DPathEffectImpl\28\29_5587 +9564:SkPath1DPathEffectImpl::~SkPath1DPathEffectImpl\28\29 +9565:SkPath1DPathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9566:SkPath1DPathEffectImpl::next\28SkPath*\2c\20float\2c\20SkPathMeasure&\29\20const +9567:SkPath1DPathEffectImpl::getTypeName\28\29\20const +9568:SkPath1DPathEffectImpl::getFactory\28\29\20const +9569:SkPath1DPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +9570:SkPath1DPathEffectImpl::begin\28float\29\20const +9571:SkPath1DPathEffectImpl::CreateProc\28SkReadBuffer&\29 +9572:SkPath1DPathEffect::Make\28SkPath\20const&\2c\20float\2c\20float\2c\20SkPath1DPathEffect::Style\29 +9573:SkPath*\20emscripten::internal::operator_new\28\29 +9574:SkPairPathEffect::~SkPairPathEffect\28\29_3375 +9575:SkPaint::setDither\28bool\29 +9576:SkPaint::setAntiAlias\28bool\29 +9577:SkPaint::getStrokeMiter\28\29\20const +9578:SkPaint::getStrokeJoin\28\29\20const +9579:SkPaint::getStrokeCap\28\29\20const +9580:SkPaint*\20emscripten::internal::operator_new\28\29 +9581:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29_8175 +9582:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29 +9583:SkOTUtils::LocalizedStrings_SingleName::next\28SkTypeface::LocalizedString*\29 +9584:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29_7451 +9585:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29 +9586:SkOTUtils::LocalizedStrings_NameTable::next\28SkTypeface::LocalizedString*\29 +9587:SkNoPixelsDevice::~SkNoPixelsDevice\28\29_1939 +9588:SkNoPixelsDevice::~SkNoPixelsDevice\28\29 +9589:SkNoPixelsDevice::replaceClip\28SkIRect\20const&\29 +9590:SkNoPixelsDevice::pushClipStack\28\29 +9591:SkNoPixelsDevice::popClipStack\28\29 +9592:SkNoPixelsDevice::onClipShader\28sk_sp\29 +9593:SkNoPixelsDevice::isClipWideOpen\28\29\20const +9594:SkNoPixelsDevice::isClipRect\28\29\20const +9595:SkNoPixelsDevice::isClipEmpty\28\29\20const +9596:SkNoPixelsDevice::isClipAntiAliased\28\29\20const +9597:SkNoPixelsDevice::devClipBounds\28\29\20const +9598:SkNoPixelsDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +9599:SkNoPixelsDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +9600:SkNoPixelsDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +9601:SkNoPixelsDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +9602:SkNoPixelsDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +9603:SkNoDrawCanvas::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +9604:SkNoDrawCanvas::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +9605:SkMipmap::~SkMipmap\28\29_2579 +9606:SkMipmap::~SkMipmap\28\29 +9607:SkMipmap::onDataChange\28void*\2c\20void*\29 +9608:SkMemoryStream::~SkMemoryStream\28\29_4194 +9609:SkMemoryStream::~SkMemoryStream\28\29 +9610:SkMemoryStream::setMemory\28void\20const*\2c\20unsigned\20long\2c\20bool\29 +9611:SkMemoryStream::seek\28unsigned\20long\29 +9612:SkMemoryStream::rewind\28\29 +9613:SkMemoryStream::read\28void*\2c\20unsigned\20long\29 +9614:SkMemoryStream::peek\28void*\2c\20unsigned\20long\29\20const +9615:SkMemoryStream::onFork\28\29\20const +9616:SkMemoryStream::onDuplicate\28\29\20const +9617:SkMemoryStream::move\28long\29 +9618:SkMemoryStream::isAtEnd\28\29\20const +9619:SkMemoryStream::getMemoryBase\28\29 +9620:SkMemoryStream::getLength\28\29\20const +9621:SkMemoryStream::getData\28\29\20const +9622:SkMatrixColorFilter::onIsAlphaUnchanged\28\29\20const +9623:SkMatrixColorFilter::onAsAColorMatrix\28float*\29\20const +9624:SkMatrixColorFilter::getTypeName\28\29\20const +9625:SkMatrixColorFilter::flatten\28SkWriteBuffer&\29\20const +9626:SkMatrixColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +9627:SkMatrix::Trans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +9628:SkMatrix::Trans_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +9629:SkMatrix::Scale_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +9630:SkMatrix::Scale_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +9631:SkMatrix::ScaleTrans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +9632:SkMatrix::Poly4Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +9633:SkMatrix::Poly3Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +9634:SkMatrix::Poly2Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +9635:SkMatrix::Persp_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +9636:SkMatrix::Persp_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +9637:SkMatrix::Identity_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +9638:SkMatrix::Identity_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +9639:SkMatrix::Affine_vpts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +9640:SkMaskSwizzler::onSetSampleX\28int\29 +9641:SkMaskFilterBase::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +9642:SkMaskFilterBase::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +9643:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29_2388 +9644:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29 +9645:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29_3564 +9646:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29 +9647:SkLumaColorFilter::Make\28\29 +9648:SkLocalMatrixShader::~SkLocalMatrixShader\28\29_4790 +9649:SkLocalMatrixShader::~SkLocalMatrixShader\28\29 +9650:SkLocalMatrixShader::type\28\29\20const +9651:SkLocalMatrixShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +9652:SkLocalMatrixShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +9653:SkLocalMatrixShader::makeAsALocalMatrixShader\28SkMatrix*\29\20const +9654:SkLocalMatrixShader::isOpaque\28\29\20const +9655:SkLocalMatrixShader::isConstant\28\29\20const +9656:SkLocalMatrixShader::getTypeName\28\29\20const +9657:SkLocalMatrixShader::flatten\28SkWriteBuffer&\29\20const +9658:SkLocalMatrixShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +9659:SkLocalMatrixShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9660:SkLinearGradient::getTypeName\28\29\20const +9661:SkLinearGradient::flatten\28SkWriteBuffer&\29\20const +9662:SkLinearGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +9663:SkLine2DPathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9664:SkLine2DPathEffectImpl::nextSpan\28int\2c\20int\2c\20int\2c\20SkPath*\29\20const +9665:SkLine2DPathEffectImpl::getTypeName\28\29\20const +9666:SkLine2DPathEffectImpl::getFactory\28\29\20const +9667:SkLine2DPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +9668:SkLine2DPathEffectImpl::CreateProc\28SkReadBuffer&\29 +9669:SkJpegMetadataDecoderImpl::~SkJpegMetadataDecoderImpl\28\29_12896 +9670:SkJpegMetadataDecoderImpl::~SkJpegMetadataDecoderImpl\28\29 +9671:SkJpegMetadataDecoderImpl::getISOGainmapMetadata\28bool\29\20const +9672:SkJpegMetadataDecoderImpl::getICCProfileData\28bool\29\20const +9673:SkJpegMetadataDecoderImpl::getExifMetadata\28bool\29\20const +9674:SkJpegMemorySourceMgr::skipInputBytes\28unsigned\20long\2c\20unsigned\20char\20const*&\2c\20unsigned\20long&\29 +9675:SkJpegMemorySourceMgr::initSource\28unsigned\20char\20const*&\2c\20unsigned\20long&\29 +9676:SkJpegDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +9677:SkJpegCodec::~SkJpegCodec\28\29_12852 +9678:SkJpegCodec::~SkJpegCodec\28\29 +9679:SkJpegCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +9680:SkJpegCodec::onSkipScanlines\28int\29 +9681:SkJpegCodec::onRewind\28\29 +9682:SkJpegCodec::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +9683:SkJpegCodec::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +9684:SkJpegCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +9685:SkJpegCodec::onGetScaledDimensions\28float\29\20const +9686:SkJpegCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9687:SkJpegCodec::onGetGainmapCodec\28SkGainmapInfo*\2c\20std::__2::unique_ptr>*\29 +9688:SkJpegCodec::onDimensionsSupported\28SkISize\20const&\29 +9689:SkJpegCodec::getSampler\28bool\29 +9690:SkJpegCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +9691:SkJpegBufferedSourceMgr::~SkJpegBufferedSourceMgr\28\29_12905 +9692:SkJpegBufferedSourceMgr::~SkJpegBufferedSourceMgr\28\29 +9693:SkJpegBufferedSourceMgr::skipInputBytes\28unsigned\20long\2c\20unsigned\20char\20const*&\2c\20unsigned\20long&\29 +9694:SkJpegBufferedSourceMgr::initSource\28unsigned\20char\20const*&\2c\20unsigned\20long&\29 +9695:SkJpegBufferedSourceMgr::fillInputBuffer\28unsigned\20char\20const*&\2c\20unsigned\20long&\29 +9696:SkImage_Raster::~SkImage_Raster\28\29_4633 +9697:SkImage_Raster::~SkImage_Raster\28\29 +9698:SkImage_Raster::onReinterpretColorSpace\28sk_sp\29\20const +9699:SkImage_Raster::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +9700:SkImage_Raster::onPeekPixels\28SkPixmap*\29\20const +9701:SkImage_Raster::onPeekMips\28\29\20const +9702:SkImage_Raster::onMakeWithMipmaps\28sk_sp\29\20const +9703:SkImage_Raster::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +9704:SkImage_Raster::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +9705:SkImage_Raster::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +9706:SkImage_Raster::onHasMipmaps\28\29\20const +9707:SkImage_Raster::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +9708:SkImage_Raster::notifyAddedToRasterCache\28\29\20const +9709:SkImage_Raster::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +9710:SkImage_LazyTexture::readPixelsProxy\28GrDirectContext*\2c\20SkPixmap\20const&\29\20const +9711:SkImage_LazyTexture::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +9712:SkImage_Lazy::~SkImage_Lazy\28\29 +9713:SkImage_Lazy::onReinterpretColorSpace\28sk_sp\29\20const +9714:SkImage_Lazy::onRefEncoded\28\29\20const +9715:SkImage_Lazy::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +9716:SkImage_Lazy::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +9717:SkImage_Lazy::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +9718:SkImage_Lazy::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +9719:SkImage_Lazy::onIsProtected\28\29\20const +9720:SkImage_Lazy::isValid\28GrRecordingContext*\29\20const +9721:SkImage_Lazy::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +9722:SkImage_GaneshBase::~SkImage_GaneshBase\28\29 +9723:SkImage_GaneshBase::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +9724:SkImage_GaneshBase::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +9725:SkImage_GaneshBase::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +9726:SkImage_GaneshBase::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +9727:SkImage_GaneshBase::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +9728:SkImage_GaneshBase::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +9729:SkImage_GaneshBase::isValid\28GrRecordingContext*\29\20const +9730:SkImage_GaneshBase::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +9731:SkImage_GaneshBase::directContext\28\29\20const +9732:SkImage_Ganesh::~SkImage_Ganesh\28\29_10708 +9733:SkImage_Ganesh::textureSize\28\29\20const +9734:SkImage_Ganesh::onReinterpretColorSpace\28sk_sp\29\20const +9735:SkImage_Ganesh::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +9736:SkImage_Ganesh::onIsProtected\28\29\20const +9737:SkImage_Ganesh::onHasMipmaps\28\29\20const +9738:SkImage_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +9739:SkImage_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +9740:SkImage_Ganesh::generatingSurfaceIsDeleted\28\29 +9741:SkImage_Ganesh::flush\28GrDirectContext*\2c\20GrFlushInfo\20const&\29\20const +9742:SkImage_Ganesh::asView\28GrRecordingContext*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29\20const +9743:SkImage_Ganesh::asFragmentProcessor\28GrRecordingContext*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29\20const +9744:SkImage_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +9745:SkImage_Base::notifyAddedToRasterCache\28\29\20const +9746:SkImage_Base::makeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +9747:SkImage_Base::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +9748:SkImage_Base::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +9749:SkImage_Base::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +9750:SkImage_Base::makeColorSpace\28skgpu::graphite::Recorder*\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +9751:SkImage_Base::makeColorSpace\28GrDirectContext*\2c\20sk_sp\29\20const +9752:SkImage_Base::isTextureBacked\28\29\20const +9753:SkImage_Base::isLazyGenerated\28\29\20const +9754:SkImageShader::~SkImageShader\28\29_4775 +9755:SkImageShader::~SkImageShader\28\29 +9756:SkImageShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +9757:SkImageShader::isOpaque\28\29\20const +9758:SkImageShader::getTypeName\28\29\20const +9759:SkImageShader::flatten\28SkWriteBuffer&\29\20const +9760:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9761:SkImageGenerator::~SkImageGenerator\28\29 +9762:SkImageFilters::Compose\28sk_sp\2c\20sk_sp\29 +9763:SkImage::~SkImage\28\29 +9764:SkIcoDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +9765:SkIcoCodec::~SkIcoCodec\28\29_12927 +9766:SkIcoCodec::~SkIcoCodec\28\29 +9767:SkIcoCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +9768:SkIcoCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +9769:SkIcoCodec::onSkipScanlines\28int\29 +9770:SkIcoCodec::onIncrementalDecode\28int*\29 +9771:SkIcoCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +9772:SkIcoCodec::onGetScanlineOrder\28\29\20const +9773:SkIcoCodec::onGetScaledDimensions\28float\29\20const +9774:SkIcoCodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9775:SkIcoCodec::onDimensionsSupported\28SkISize\20const&\29 +9776:SkIcoCodec::getSampler\28bool\29 +9777:SkIcoCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +9778:SkGradientBaseShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +9779:SkGradientBaseShader::isOpaque\28\29\20const +9780:SkGradientBaseShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9781:SkGifDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +9782:SkGaussianColorFilter::getTypeName\28\29\20const +9783:SkGaussianColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +9784:SkGammaColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +9785:SkGammaColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +9786:SkGainmapInfo::serialize\28\29\20const +9787:SkGainmapInfo::SerializeVersion\28\29 +9788:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29_8102 +9789:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29 +9790:SkFontStyleSet_Custom::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +9791:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29_8168 +9792:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29 +9793:SkFontScanner_FreeType::scanFile\28SkStreamAsset*\2c\20int*\29\20const +9794:SkFontScanner_FreeType::scanFace\28SkStreamAsset*\2c\20int\2c\20int*\29\20const +9795:SkFontScanner_FreeType::getFactoryId\28\29\20const +9796:SkFontMgr_Custom::~SkFontMgr_Custom\28\29_8104 +9797:SkFontMgr_Custom::~SkFontMgr_Custom\28\29 +9798:SkFontMgr_Custom::onMatchFamily\28char\20const*\29\20const +9799:SkFontMgr_Custom::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +9800:SkFontMgr_Custom::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +9801:SkFontMgr_Custom::onMakeFromFile\28char\20const*\2c\20int\29\20const +9802:SkFontMgr_Custom::onMakeFromData\28sk_sp\2c\20int\29\20const +9803:SkFontMgr_Custom::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +9804:SkFontMgr_Custom::onGetFamilyName\28int\2c\20SkString*\29\20const +9805:SkFont::setScaleX\28float\29 +9806:SkFont::setEmbeddedBitmaps\28bool\29 +9807:SkFont::isEmbolden\28\29\20const +9808:SkFont::getSkewX\28\29\20const +9809:SkFont::getSize\28\29\20const +9810:SkFont::getScaleX\28\29\20const +9811:SkFont*\20emscripten::internal::operator_new\2c\20float\2c\20float\2c\20float>\28sk_sp&&\2c\20float&&\2c\20float&&\2c\20float&&\29 +9812:SkFont*\20emscripten::internal::operator_new\2c\20float>\28sk_sp&&\2c\20float&&\29 +9813:SkFont*\20emscripten::internal::operator_new>\28sk_sp&&\29 +9814:SkFont*\20emscripten::internal::operator_new\28\29 +9815:SkFILEStream::~SkFILEStream\28\29_4148 +9816:SkFILEStream::~SkFILEStream\28\29 +9817:SkFILEStream::seek\28unsigned\20long\29 +9818:SkFILEStream::rewind\28\29 +9819:SkFILEStream::read\28void*\2c\20unsigned\20long\29 +9820:SkFILEStream::onFork\28\29\20const +9821:SkFILEStream::onDuplicate\28\29\20const +9822:SkFILEStream::move\28long\29 +9823:SkFILEStream::isAtEnd\28\29\20const +9824:SkFILEStream::getPosition\28\29\20const +9825:SkFILEStream::getLength\28\29\20const +9826:SkEncoder::~SkEncoder\28\29 +9827:SkEmptyShader::getTypeName\28\29\20const +9828:SkEmptyPicture::~SkEmptyPicture\28\29 +9829:SkEmptyPicture::cullRect\28\29\20const +9830:SkEmptyPicture::approximateBytesUsed\28\29\20const +9831:SkEmptyFontMgr::onMatchFamily\28char\20const*\29\20const +9832:SkEdgeBuilder::~SkEdgeBuilder\28\29 +9833:SkEdgeBuilder::build\28SkPath\20const&\2c\20SkIRect\20const*\2c\20bool\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +9834:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29_4178 +9835:SkDrawable::onMakePictureSnapshot\28\29 +9836:SkDrawBase::~SkDrawBase\28\29 +9837:SkDraw::paintMasks\28SkZip\2c\20SkPaint\20const&\29\20const +9838:SkDiscretePathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9839:SkDiscretePathEffectImpl::getTypeName\28\29\20const +9840:SkDiscretePathEffectImpl::getFactory\28\29\20const +9841:SkDiscretePathEffectImpl::computeFastBounds\28SkRect*\29\20const +9842:SkDiscretePathEffectImpl::CreateProc\28SkReadBuffer&\29 +9843:SkDevice::~SkDevice\28\29 +9844:SkDevice::strikeDeviceInfo\28\29\20const +9845:SkDevice::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +9846:SkDevice::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +9847:SkDevice::drawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20sk_sp\2c\20SkPaint\20const&\29 +9848:SkDevice::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +9849:SkDevice::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +9850:SkDevice::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +9851:SkDevice::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +9852:SkDevice::drawCoverageMask\28SkSpecialImage\20const*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +9853:SkDevice::drawBlurredRRect\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20float\29 +9854:SkDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +9855:SkDevice::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +9856:SkDevice::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +9857:SkDashImpl::~SkDashImpl\28\29_5628 +9858:SkDashImpl::~SkDashImpl\28\29 +9859:SkDashImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9860:SkDashImpl::onAsPoints\28SkPathEffectBase::PointData*\2c\20SkPath\20const&\2c\20SkStrokeRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\29\20const +9861:SkDashImpl::getTypeName\28\29\20const +9862:SkDashImpl::flatten\28SkWriteBuffer&\29\20const +9863:SkDashImpl::asADash\28SkPathEffectBase::DashInfo*\29\20const +9864:SkCustomTypefaceBuilder::MakeFromStream\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29 +9865:SkCornerPathEffectImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9866:SkCornerPathEffectImpl::getTypeName\28\29\20const +9867:SkCornerPathEffectImpl::getFactory\28\29\20const +9868:SkCornerPathEffectImpl::flatten\28SkWriteBuffer&\29\20const +9869:SkCornerPathEffectImpl::CreateProc\28SkReadBuffer&\29 +9870:SkCornerPathEffect::Make\28float\29 +9871:SkContourMeasureIter*\20emscripten::internal::operator_new\28SkPath\20const&\2c\20bool&&\2c\20float&&\29 +9872:SkContourMeasure::~SkContourMeasure\28\29_1862 +9873:SkContourMeasure::~SkContourMeasure\28\29 +9874:SkContourMeasure::isClosed\28\29\20const +9875:SkConicalGradient::getTypeName\28\29\20const +9876:SkConicalGradient::flatten\28SkWriteBuffer&\29\20const +9877:SkConicalGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +9878:SkConicalGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +9879:SkComposePathEffect::~SkComposePathEffect\28\29 +9880:SkComposePathEffect::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +9881:SkComposePathEffect::getTypeName\28\29\20const +9882:SkComposePathEffect::computeFastBounds\28SkRect*\29\20const +9883:SkComposeColorFilter::onIsAlphaUnchanged\28\29\20const +9884:SkComposeColorFilter::getTypeName\28\29\20const +9885:SkComposeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +9886:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29_5741 +9887:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29 +9888:SkColorSpaceXformColorFilter::getTypeName\28\29\20const +9889:SkColorSpaceXformColorFilter::flatten\28SkWriteBuffer&\29\20const +9890:SkColorSpaceXformColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +9891:SkColorShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +9892:SkColorShader::isOpaque\28\29\20const +9893:SkColorShader::getTypeName\28\29\20const +9894:SkColorShader::flatten\28SkWriteBuffer&\29\20const +9895:SkColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9896:SkColorPalette::~SkColorPalette\28\29_5972 +9897:SkColorPalette::~SkColorPalette\28\29 +9898:SkColorFilters::SRGBToLinearGamma\28\29 +9899:SkColorFilters::LinearToSRGBGamma\28\29 +9900:SkColorFilters::Lerp\28float\2c\20sk_sp\2c\20sk_sp\29 +9901:SkColorFilters::Compose\28sk_sp\20const&\2c\20sk_sp\29 +9902:SkColorFilterShader::~SkColorFilterShader\28\29_4739 +9903:SkColorFilterShader::~SkColorFilterShader\28\29 +9904:SkColorFilterShader::isOpaque\28\29\20const +9905:SkColorFilterShader::getTypeName\28\29\20const +9906:SkColorFilterShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9907:SkColorFilterBase::onFilterColor4f\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkColorSpace*\29\20const +9908:SkCodecPriv::PremultiplyARGBasRGBA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +9909:SkCodecPriv::PremultiplyARGBasBGRA\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +9910:SkCodecImageGenerator::~SkCodecImageGenerator\28\29_5969 +9911:SkCodecImageGenerator::~SkCodecImageGenerator\28\29 +9912:SkCodecImageGenerator::onRefEncodedData\28\29 +9913:SkCodecImageGenerator::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +9914:SkCodecImageGenerator::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +9915:SkCodecImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +9916:SkCodec::onStartScanlineDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +9917:SkCodec::onStartIncrementalDecode\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +9918:SkCodec::onOutputScanline\28int\29\20const +9919:SkCodec::onGetScaledDimensions\28float\29\20const +9920:SkCodec::getEncodedData\28\29\20const +9921:SkCodec::conversionSupported\28SkImageInfo\20const&\2c\20bool\2c\20bool\29 +9922:SkCanvas::rotate\28float\2c\20float\2c\20float\29 +9923:SkCanvas::recordingContext\28\29\20const +9924:SkCanvas::recorder\28\29\20const +9925:SkCanvas::onPeekPixels\28SkPixmap*\29 +9926:SkCanvas::onNewSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +9927:SkCanvas::onImageInfo\28\29\20const +9928:SkCanvas::onGetProps\28SkSurfaceProps*\2c\20bool\29\20const +9929:SkCanvas::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9930:SkCanvas::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +9931:SkCanvas::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +9932:SkCanvas::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +9933:SkCanvas::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +9934:SkCanvas::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +9935:SkCanvas::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +9936:SkCanvas::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +9937:SkCanvas::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +9938:SkCanvas::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +9939:SkCanvas::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +9940:SkCanvas::onDrawPaint\28SkPaint\20const&\29 +9941:SkCanvas::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +9942:SkCanvas::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +9943:SkCanvas::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +9944:SkCanvas::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +9945:SkCanvas::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +9946:SkCanvas::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +9947:SkCanvas::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +9948:SkCanvas::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +9949:SkCanvas::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +9950:SkCanvas::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +9951:SkCanvas::onDrawBehind\28SkPaint\20const&\29 +9952:SkCanvas::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +9953:SkCanvas::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +9954:SkCanvas::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +9955:SkCanvas::onDiscard\28\29 +9956:SkCanvas::onConvertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +9957:SkCanvas::onAccessTopLayerPixels\28SkPixmap*\29 +9958:SkCanvas::isClipRect\28\29\20const +9959:SkCanvas::isClipEmpty\28\29\20const +9960:SkCanvas::getSaveCount\28\29\20const +9961:SkCanvas::getBaseLayerSize\28\29\20const +9962:SkCanvas::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +9963:SkCanvas::drawPicture\28sk_sp\20const&\29 +9964:SkCanvas::drawCircle\28float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +9965:SkCanvas*\20emscripten::internal::operator_new\28float&&\2c\20float&&\29 +9966:SkCanvas*\20emscripten::internal::operator_new\28\29 +9967:SkCachedData::~SkCachedData\28\29_1598 +9968:SkCTMShader::~SkCTMShader\28\29 +9969:SkCTMShader::isConstant\28\29\20const +9970:SkCTMShader::getTypeName\28\29\20const +9971:SkCTMShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +9972:SkCTMShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +9973:SkBreakIterator_client::~SkBreakIterator_client\28\29_8055 +9974:SkBreakIterator_client::~SkBreakIterator_client\28\29 +9975:SkBreakIterator_client::status\28\29 +9976:SkBreakIterator_client::setText\28char\20const*\2c\20int\29 +9977:SkBreakIterator_client::setText\28char16_t\20const*\2c\20int\29 +9978:SkBreakIterator_client::next\28\29 +9979:SkBreakIterator_client::isDone\28\29 +9980:SkBreakIterator_client::first\28\29 +9981:SkBreakIterator_client::current\28\29 +9982:SkBmpStandardCodec::~SkBmpStandardCodec\28\29_6142 +9983:SkBmpStandardCodec::~SkBmpStandardCodec\28\29 +9984:SkBmpStandardCodec::onPrepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +9985:SkBmpStandardCodec::onInIco\28\29\20const +9986:SkBmpStandardCodec::getSampler\28bool\29 +9987:SkBmpStandardCodec::decodeRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +9988:SkBmpRLESampler::onSetSampleX\28int\29 +9989:SkBmpRLESampler::fillWidth\28\29\20const +9990:SkBmpRLECodec::~SkBmpRLECodec\28\29_6126 +9991:SkBmpRLECodec::~SkBmpRLECodec\28\29 +9992:SkBmpRLECodec::skipRows\28int\29 +9993:SkBmpRLECodec::onPrepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +9994:SkBmpRLECodec::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\2c\20int*\29 +9995:SkBmpRLECodec::getSampler\28bool\29 +9996:SkBmpRLECodec::decodeRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +9997:SkBmpMaskCodec::~SkBmpMaskCodec\28\29_6111 +9998:SkBmpMaskCodec::~SkBmpMaskCodec\28\29 +9999:SkBmpMaskCodec::onPrepareToDecode\28SkImageInfo\20const&\2c\20SkCodec::Options\20const&\29 +10000:SkBmpMaskCodec::getSampler\28bool\29 +10001:SkBmpMaskCodec::decodeRows\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkCodec::Options\20const&\29 +10002:SkBmpDecoder::Decode\28std::__2::unique_ptr>\2c\20SkCodec::Result*\2c\20void*\29 +10003:SkBmpCodec::~SkBmpCodec\28\29 +10004:SkBmpCodec::skipRows\28int\29 +10005:SkBmpCodec::onSkipScanlines\28int\29 +10006:SkBmpCodec::onRewind\28\29 +10007:SkBmpCodec::onGetScanlines\28void*\2c\20int\2c\20unsigned\20long\29 +10008:SkBmpCodec::onGetScanlineOrder\28\29\20const +10009:SkBlurMaskFilterImpl::getTypeName\28\29\20const +10010:SkBlurMaskFilterImpl::flatten\28SkWriteBuffer&\29\20const +10011:SkBlurMaskFilterImpl::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +10012:SkBlurMaskFilterImpl::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +10013:SkBlurMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +10014:SkBlurMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +10015:SkBlurMaskFilterImpl::asImageFilter\28SkMatrix\20const&\29\20const +10016:SkBlurMaskFilterImpl::asABlur\28SkMaskFilterBase::BlurRec*\29\20const +10017:SkBlockMemoryStream::~SkBlockMemoryStream\28\29_4203 +10018:SkBlockMemoryStream::~SkBlockMemoryStream\28\29 +10019:SkBlockMemoryStream::seek\28unsigned\20long\29 +10020:SkBlockMemoryStream::rewind\28\29 +10021:SkBlockMemoryStream::read\28void*\2c\20unsigned\20long\29 +10022:SkBlockMemoryStream::peek\28void*\2c\20unsigned\20long\29\20const +10023:SkBlockMemoryStream::onFork\28\29\20const +10024:SkBlockMemoryStream::onDuplicate\28\29\20const +10025:SkBlockMemoryStream::move\28long\29 +10026:SkBlockMemoryStream::isAtEnd\28\29\20const +10027:SkBlockMemoryStream::getMemoryBase\28\29 +10028:SkBlockMemoryRefCnt::~SkBlockMemoryRefCnt\28\29_4201 +10029:SkBlockMemoryRefCnt::~SkBlockMemoryRefCnt\28\29 +10030:SkBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10031:SkBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10032:SkBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10033:SkBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10034:SkBlitter::allocBlitMemory\28unsigned\20long\29 +10035:SkBlendShader::getTypeName\28\29\20const +10036:SkBlendShader::flatten\28SkWriteBuffer&\29\20const +10037:SkBlendShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10038:SkBlendModeColorFilter::onIsAlphaUnchanged\28\29\20const +10039:SkBlendModeColorFilter::onAsAColorMode\28unsigned\20int*\2c\20SkBlendMode*\29\20const +10040:SkBlendModeColorFilter::getTypeName\28\29\20const +10041:SkBlendModeColorFilter::flatten\28SkWriteBuffer&\29\20const +10042:SkBlendModeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10043:SkBlendModeBlender::onAppendStages\28SkStageRec\20const&\29\20const +10044:SkBlendModeBlender::getTypeName\28\29\20const +10045:SkBlendModeBlender::flatten\28SkWriteBuffer&\29\20const +10046:SkBlendModeBlender::asBlendMode\28\29\20const +10047:SkBitmapDevice::~SkBitmapDevice\28\29_1383 +10048:SkBitmapDevice::~SkBitmapDevice\28\29 +10049:SkBitmapDevice::snapSpecial\28SkIRect\20const&\2c\20bool\29 +10050:SkBitmapDevice::setImmutable\28\29 +10051:SkBitmapDevice::replaceClip\28SkIRect\20const&\29 +10052:SkBitmapDevice::pushClipStack\28\29 +10053:SkBitmapDevice::popClipStack\28\29 +10054:SkBitmapDevice::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +10055:SkBitmapDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +10056:SkBitmapDevice::onPeekPixels\28SkPixmap*\29 +10057:SkBitmapDevice::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +10058:SkBitmapDevice::onClipShader\28sk_sp\29 +10059:SkBitmapDevice::onAccessPixels\28SkPixmap*\29 +10060:SkBitmapDevice::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +10061:SkBitmapDevice::makeSpecial\28SkImage\20const*\29 +10062:SkBitmapDevice::makeSpecial\28SkBitmap\20const&\29 +10063:SkBitmapDevice::isClipWideOpen\28\29\20const +10064:SkBitmapDevice::isClipRect\28\29\20const +10065:SkBitmapDevice::isClipEmpty\28\29\20const +10066:SkBitmapDevice::isClipAntiAliased\28\29\20const +10067:SkBitmapDevice::getRasterHandle\28\29\20const +10068:SkBitmapDevice::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +10069:SkBitmapDevice::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +10070:SkBitmapDevice::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10071:SkBitmapDevice::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10072:SkBitmapDevice::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10073:SkBitmapDevice::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +10074:SkBitmapDevice::drawPaint\28SkPaint\20const&\29 +10075:SkBitmapDevice::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10076:SkBitmapDevice::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +10077:SkBitmapDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +10078:SkBitmapDevice::devClipBounds\28\29\20const +10079:SkBitmapDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +10080:SkBitmapDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10081:SkBitmapDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +10082:SkBitmapDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +10083:SkBitmapDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +10084:SkBitmapDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +10085:SkBitmapCache::Rec::~Rec\28\29_1316 +10086:SkBitmapCache::Rec::~Rec\28\29 +10087:SkBitmapCache::Rec::postAddInstall\28void*\29 +10088:SkBitmapCache::Rec::getCategory\28\29\20const +10089:SkBitmapCache::Rec::canBePurged\28\29 +10090:SkBitmapCache::Rec::bytesUsed\28\29\20const +10091:SkBitmapCache::Rec::ReleaseProc\28void*\2c\20void*\29 +10092:SkBitmapCache::Rec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +10093:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29_4490 +10094:SkBinaryWriteBuffer::write\28SkM44\20const&\29 +10095:SkBinaryWriteBuffer::writeTypeface\28SkTypeface*\29 +10096:SkBinaryWriteBuffer::writeString\28std::__2::basic_string_view>\29 +10097:SkBinaryWriteBuffer::writeStream\28SkStream*\2c\20unsigned\20long\29 +10098:SkBinaryWriteBuffer::writeScalar\28float\29 +10099:SkBinaryWriteBuffer::writeSampling\28SkSamplingOptions\20const&\29 +10100:SkBinaryWriteBuffer::writeRegion\28SkRegion\20const&\29 +10101:SkBinaryWriteBuffer::writeRect\28SkRect\20const&\29 +10102:SkBinaryWriteBuffer::writePoint\28SkPoint\20const&\29 +10103:SkBinaryWriteBuffer::writePointArray\28SkPoint\20const*\2c\20unsigned\20int\29 +10104:SkBinaryWriteBuffer::writePoint3\28SkPoint3\20const&\29 +10105:SkBinaryWriteBuffer::writePath\28SkPath\20const&\29 +10106:SkBinaryWriteBuffer::writePaint\28SkPaint\20const&\29 +10107:SkBinaryWriteBuffer::writePad32\28void\20const*\2c\20unsigned\20long\29 +10108:SkBinaryWriteBuffer::writeMatrix\28SkMatrix\20const&\29 +10109:SkBinaryWriteBuffer::writeImage\28SkImage\20const*\29 +10110:SkBinaryWriteBuffer::writeColor4fArray\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20unsigned\20int\29 +10111:SkBigPicture::~SkBigPicture\28\29_1260 +10112:SkBigPicture::~SkBigPicture\28\29 +10113:SkBigPicture::playback\28SkCanvas*\2c\20SkPicture::AbortCallback*\29\20const +10114:SkBigPicture::cullRect\28\29\20const +10115:SkBigPicture::approximateOpCount\28bool\29\20const +10116:SkBigPicture::approximateBytesUsed\28\29\20const +10117:SkBidiSubsetFactory::errorName\28UErrorCode\29\20const +10118:SkBidiSubsetFactory::bidi_setPara\28UBiDi*\2c\20char16_t\20const*\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20UErrorCode*\29\20const +10119:SkBidiSubsetFactory::bidi_reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29\20const +10120:SkBidiSubsetFactory::bidi_openSized\28int\2c\20int\2c\20UErrorCode*\29\20const +10121:SkBidiSubsetFactory::bidi_getLevelAt\28UBiDi\20const*\2c\20int\29\20const +10122:SkBidiSubsetFactory::bidi_getLength\28UBiDi\20const*\29\20const +10123:SkBidiSubsetFactory::bidi_getDirection\28UBiDi\20const*\29\20const +10124:SkBidiSubsetFactory::bidi_close_callback\28\29\20const +10125:SkBezierCubic::Subdivide\28double\20const*\2c\20double\2c\20double*\29 +10126:SkBasicEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +10127:SkBasicEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +10128:SkBasicEdgeBuilder::addQuad\28SkPoint\20const*\29 +10129:SkBasicEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +10130:SkBasicEdgeBuilder::addLine\28SkPoint\20const*\29 +10131:SkBasicEdgeBuilder::addCubic\28SkPoint\20const*\29 +10132:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29 +10133:SkBBoxHierarchy::insert\28SkRect\20const*\2c\20SkBBoxHierarchy::Metadata\20const*\2c\20int\29 +10134:SkArenaAlloc::SkipPod\28char*\29 +10135:SkArenaAlloc::NextBlock\28char*\29 +10136:SkAnimatedImage::~SkAnimatedImage\28\29_7409 +10137:SkAnimatedImage::~SkAnimatedImage\28\29 +10138:SkAnimatedImage::reset\28\29 +10139:SkAnimatedImage::onGetBounds\28\29 +10140:SkAnimatedImage::onDraw\28SkCanvas*\29 +10141:SkAnimatedImage::getRepetitionCount\28\29\20const +10142:SkAnimatedImage::getCurrentFrame\28\29 +10143:SkAnimatedImage::currentFrameDuration\28\29 +10144:SkAndroidCodecAdapter::onGetSupportedSubset\28SkIRect*\29\20const +10145:SkAndroidCodecAdapter::onGetSampledDimensions\28int\29\20const +10146:SkAndroidCodecAdapter::onGetAndroidPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkAndroidCodec::AndroidOptions\20const&\29 +10147:SkAnalyticEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +10148:SkAnalyticEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +10149:SkAnalyticEdgeBuilder::addQuad\28SkPoint\20const*\29 +10150:SkAnalyticEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +10151:SkAnalyticEdgeBuilder::addLine\28SkPoint\20const*\29 +10152:SkAnalyticEdgeBuilder::addCubic\28SkPoint\20const*\29 +10153:SkAAClipBlitter::~SkAAClipBlitter\28\29_1216 +10154:SkAAClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10155:SkAAClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10156:SkAAClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10157:SkAAClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10158:SkAAClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10159:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_1::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +10160:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_0::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +10161:SkAAClip::Builder::Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10162:SkAAClip::Builder::Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10163:SkAAClip::Builder::Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10164:SkAAClip::Builder::Blitter::blitH\28int\2c\20int\2c\20int\29 +10165:SkAAClip::Builder::Blitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10166:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29_1484 +10167:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29 +10168:SkA8_Coverage_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10169:SkA8_Coverage_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10170:SkA8_Coverage_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10171:SkA8_Coverage_Blitter::blitH\28int\2c\20int\2c\20int\29 +10172:SkA8_Coverage_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10173:SkA8_Blitter::~SkA8_Blitter\28\29_1486 +10174:SkA8_Blitter::~SkA8_Blitter\28\29 +10175:SkA8_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10176:SkA8_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10177:SkA8_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10178:SkA8_Blitter::blitH\28int\2c\20int\2c\20int\29 +10179:SkA8_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10180:SkA8Blitter_Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +10181:Sk2DPathEffect::nextSpan\28int\2c\20int\2c\20int\2c\20SkPath*\29\20const +10182:Sk2DPathEffect::flatten\28SkWriteBuffer&\29\20const +10183:SimpleVFilter16i_C +10184:SimpleVFilter16_C +10185:SimpleTextStyle*\20emscripten::internal::raw_constructor\28\29 +10186:SimpleTextStyle*\20emscripten::internal::MemberAccess::getWire\28SimpleTextStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\29 +10187:SimpleStrutStyle*\20emscripten::internal::raw_constructor\28\29 +10188:SimpleStrutStyle*\20emscripten::internal::MemberAccess::getWire\28SimpleStrutStyle\20SimpleParagraphStyle::*\20const&\2c\20SimpleParagraphStyle&\29 +10189:SimpleParagraphStyle*\20emscripten::internal::raw_constructor\28\29 +10190:SimpleHFilter16i_C +10191:SimpleHFilter16_C +10192:SimpleFontStyle*\20emscripten::internal::raw_constructor\28\29 +10193:ShaderPDXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10194:ShaderPDXferProcessor::name\28\29\20const +10195:ShaderPDXferProcessor::makeProgramImpl\28\29\20const +10196:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +10197:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +10198:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10199:RuntimeEffectUniform*\20emscripten::internal::raw_constructor\28\29 +10200:RuntimeEffectRPCallbacks::toLinearSrgb\28void\20const*\29 +10201:RuntimeEffectRPCallbacks::fromLinearSrgb\28void\20const*\29 +10202:RuntimeEffectRPCallbacks::appendShader\28int\29 +10203:RuntimeEffectRPCallbacks::appendColorFilter\28int\29 +10204:RuntimeEffectRPCallbacks::appendBlender\28int\29 +10205:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29 +10206:RunBasedAdditiveBlitter::getRealBlitter\28bool\29 +10207:RunBasedAdditiveBlitter::flush_if_y_changed\28int\2c\20int\29 +10208:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +10209:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +10210:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10211:Round_Up_To_Grid +10212:Round_To_Half_Grid +10213:Round_To_Grid +10214:Round_To_Double_Grid +10215:Round_Super_45 +10216:Round_Super +10217:Round_None +10218:Round_Down_To_Grid +10219:RoundJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +10220:RoundCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +10221:Reset +10222:Read_CVT_Stretched +10223:Read_CVT +10224:RD4_C +10225:Project_y +10226:Project +10227:ProcessRows +10228:PredictorAdd9_C +10229:PredictorAdd8_C +10230:PredictorAdd7_C +10231:PredictorAdd6_C +10232:PredictorAdd5_C +10233:PredictorAdd4_C +10234:PredictorAdd3_C +10235:PredictorAdd2_C +10236:PredictorAdd1_C +10237:PredictorAdd13_C +10238:PredictorAdd12_C +10239:PredictorAdd11_C +10240:PredictorAdd10_C +10241:PredictorAdd0_C +10242:PrePostInverseBlitterProc\28SkBlitter*\2c\20int\2c\20bool\29 +10243:PorterDuffXferProcessor::onHasSecondaryOutput\28\29\20const +10244:PorterDuffXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +10245:PorterDuffXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10246:PorterDuffXferProcessor::name\28\29\20const +10247:PorterDuffXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +10248:PorterDuffXferProcessor::makeProgramImpl\28\29\20const +10249:ParseVP8X +10250:PackRGB_C +10251:PDLCDXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +10252:PDLCDXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +10253:PDLCDXferProcessor::name\28\29\20const +10254:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +10255:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +10256:PDLCDXferProcessor::makeProgramImpl\28\29\20const +10257:OT::match_glyph\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +10258:OT::match_coverage\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +10259:OT::match_class_cached\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +10260:OT::match_class_cached2\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +10261:OT::match_class_cached1\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +10262:OT::match_class\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +10263:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GSUB_impl::SubstLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +10264:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GPOS_impl::PosLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +10265:OT::cff1::accelerator_t::gname_t::cmp\28void\20const*\2c\20void\20const*\29 +10266:OT::Layout::Common::RangeRecord::cmp_range\28void\20const*\2c\20void\20const*\29 +10267:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +10268:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +10269:OT::CmapSubtableFormat4::accelerator_t::get_glyph_func\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +10270:Move_CVT_Stretched +10271:Move_CVT +10272:MiterJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +10273:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29_4033 +10274:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29 +10275:MaskAdditiveBlitter::getWidth\28\29 +10276:MaskAdditiveBlitter::getRealBlitter\28bool\29 +10277:MaskAdditiveBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10278:MaskAdditiveBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10279:MaskAdditiveBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10280:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +10281:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +10282:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10283:MapAlpha_C +10284:MapARGB_C +10285:MakeRenderTarget\28sk_sp\2c\20int\2c\20int\29 +10286:MakeRenderTarget\28sk_sp\2c\20SimpleImageInfo\29 +10287:MakePathFromVerbsPointsWeights\28unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\2c\20unsigned\20long\2c\20int\29 +10288:MakePathFromSVGString\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10289:MakePathFromOp\28SkPath\20const&\2c\20SkPath\20const&\2c\20SkPathOp\29 +10290:MakePathFromInterpolation\28SkPath\20const&\2c\20SkPath\20const&\2c\20float\29 +10291:MakePathFromCmds\28unsigned\20long\2c\20int\29 +10292:MakeOnScreenGLSurface\28sk_sp\2c\20int\2c\20int\2c\20sk_sp\29 +10293:MakeImageFromGenerator\28SimpleImageInfo\2c\20emscripten::val\29 +10294:MakeGrContext\28\29 +10295:MakeAsWinding\28SkPath\20const&\29 +10296:LD4_C +10297:JpegDecoderMgr::returnFailure\28char\20const*\2c\20SkCodec::Result\29 +10298:JpegDecoderMgr::init\28\29 +10299:JpegDecoderMgr::SourceMgr::SkipInputData\28jpeg_decompress_struct*\2c\20long\29 +10300:JpegDecoderMgr::SourceMgr::InitSource\28jpeg_decompress_struct*\29 +10301:JpegDecoderMgr::SourceMgr::FillInputBuffer\28jpeg_decompress_struct*\29 +10302:JpegDecoderMgr::JpegDecoderMgr\28SkStream*\29 +10303:IsValidSimpleFormat +10304:IsValidExtendedFormat +10305:InverseBlitter::blitH\28int\2c\20int\2c\20int\29 +10306:Init +10307:HorizontalUnfilter_C +10308:HorizontalFilter_C +10309:Horish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +10310:Horish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +10311:HasAlpha8b_C +10312:HasAlpha32b_C +10313:HU4_C +10314:HLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +10315:HLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +10316:HFilter8i_C +10317:HFilter8_C +10318:HFilter16i_C +10319:HFilter16_C +10320:HE8uv_C +10321:HE4_C +10322:HE16_C +10323:HD4_C +10324:GradientUnfilter_C +10325:GradientFilter_C +10326:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10327:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10328:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const +10329:GrYUVtoRGBEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10330:GrYUVtoRGBEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10331:GrYUVtoRGBEffect::name\28\29\20const +10332:GrYUVtoRGBEffect::clone\28\29\20const +10333:GrXferProcessor::ProgramImpl::emitWriteSwizzle\28GrGLSLXPFragmentBuilder*\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20char\20const*\29\20const +10334:GrXferProcessor::ProgramImpl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +10335:GrXferProcessor::ProgramImpl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +10336:GrWritePixelsTask::~GrWritePixelsTask\28\29_9917 +10337:GrWritePixelsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +10338:GrWritePixelsTask::onExecute\28GrOpFlushState*\29 +10339:GrWritePixelsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +10340:GrWaitRenderTask::~GrWaitRenderTask\28\29_9907 +10341:GrWaitRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +10342:GrWaitRenderTask::onExecute\28GrOpFlushState*\29 +10343:GrWaitRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +10344:GrTriangulator::~GrTriangulator\28\29 +10345:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29_9897 +10346:GrTransferFromRenderTask::onExecute\28GrOpFlushState*\29 +10347:GrTransferFromRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +10348:GrThreadSafeCache::Trampoline::~Trampoline\28\29_9883 +10349:GrThreadSafeCache::Trampoline::~Trampoline\28\29 +10350:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29_9850 +10351:GrTextureResolveRenderTask::onExecute\28GrOpFlushState*\29 +10352:GrTextureResolveRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +10353:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9840 +10354:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +10355:GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +10356:GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +10357:GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +10358:GrTextureProxy::~GrTextureProxy\28\29_9794 +10359:GrTextureProxy::~GrTextureProxy\28\29_9792 +10360:GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +10361:GrTextureProxy::instantiate\28GrResourceProvider*\29 +10362:GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +10363:GrTextureProxy::callbackDesc\28\29\20const +10364:GrTextureEffect::~GrTextureEffect\28\29_10399 +10365:GrTextureEffect::~GrTextureEffect\28\29 +10366:GrTextureEffect::onMakeProgramImpl\28\29\20const +10367:GrTextureEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10368:GrTextureEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10369:GrTextureEffect::name\28\29\20const +10370:GrTextureEffect::clone\28\29\20const +10371:GrTextureEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10372:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10373:GrTexture::onGpuMemorySize\28\29\20const +10374:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29_8568 +10375:GrTDeferredProxyUploader>::freeData\28\29 +10376:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29_11583 +10377:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29 +10378:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::freeData\28\29 +10379:GrSurfaceProxy::getUniqueKey\28\29\20const +10380:GrSurface::~GrSurface\28\29 +10381:GrSurface::getResourceType\28\29\20const +10382:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29_11763 +10383:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29 +10384:GrStrokeTessellationShader::name\28\29\20const +10385:GrStrokeTessellationShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10386:GrStrokeTessellationShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10387:GrStrokeTessellationShader::Impl::~Impl\28\29_11766 +10388:GrStrokeTessellationShader::Impl::~Impl\28\29 +10389:GrStrokeTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10390:GrStrokeTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10391:GrSkSLFP::~GrSkSLFP\28\29_10355 +10392:GrSkSLFP::~GrSkSLFP\28\29 +10393:GrSkSLFP::onMakeProgramImpl\28\29\20const +10394:GrSkSLFP::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10395:GrSkSLFP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10396:GrSkSLFP::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +10397:GrSkSLFP::clone\28\29\20const +10398:GrSkSLFP::Impl::~Impl\28\29_10364 +10399:GrSkSLFP::Impl::~Impl\28\29 +10400:GrSkSLFP::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10401:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10402:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10403:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10404:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10405:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::getMangledName\28char\20const*\29 +10406:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10407:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +10408:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +10409:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareFunction\28char\20const*\29 +10410:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10411:GrSimpleMesh*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29::'lambda'\28char*\29::__invoke\28char*\29 +10412:GrRingBuffer::FinishSubmit\28void*\29 +10413:GrResourceCache::CompareTimestamp\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29 +10414:GrRenderTask::~GrRenderTask\28\29 +10415:GrRenderTask::disown\28GrDrawingManager*\29 +10416:GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9561 +10417:GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +10418:GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +10419:GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +10420:GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +10421:GrRenderTargetProxy::callbackDesc\28\29\20const +10422:GrRecordingContext::~GrRecordingContext\28\29_9503 +10423:GrRecordingContext::abandoned\28\29 +10424:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29_10338 +10425:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29 +10426:GrRRectShadowGeoProc::onTextureSampler\28int\29\20const +10427:GrRRectShadowGeoProc::name\28\29\20const +10428:GrRRectShadowGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10429:GrRRectShadowGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10430:GrQuadEffect::name\28\29\20const +10431:GrQuadEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10432:GrQuadEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10433:GrQuadEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10434:GrQuadEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10435:GrPorterDuffXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10436:GrPorterDuffXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10437:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29_10275 +10438:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29 +10439:GrPerlinNoise2Effect::onMakeProgramImpl\28\29\20const +10440:GrPerlinNoise2Effect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10441:GrPerlinNoise2Effect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10442:GrPerlinNoise2Effect::name\28\29\20const +10443:GrPerlinNoise2Effect::clone\28\29\20const +10444:GrPerlinNoise2Effect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10445:GrPerlinNoise2Effect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10446:GrPathTessellationShader::Impl::~Impl\28\29 +10447:GrPathTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10448:GrPathTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10449:GrOpsRenderPass::~GrOpsRenderPass\28\29 +10450:GrOpsRenderPass::onExecuteDrawable\28std::__2::unique_ptr>\29 +10451:GrOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +10452:GrOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +10453:GrOpFlushState::~GrOpFlushState\28\29_9360 +10454:GrOpFlushState::~GrOpFlushState\28\29 +10455:GrOpFlushState::writeView\28\29\20const +10456:GrOpFlushState::usesMSAASurface\28\29\20const +10457:GrOpFlushState::tokenTracker\28\29 +10458:GrOpFlushState::threadSafeCache\28\29\20const +10459:GrOpFlushState::strikeCache\28\29\20const +10460:GrOpFlushState::smallPathAtlasManager\28\29\20const +10461:GrOpFlushState::sampledProxyArray\28\29 +10462:GrOpFlushState::rtProxy\28\29\20const +10463:GrOpFlushState::resourceProvider\28\29\20const +10464:GrOpFlushState::renderPassBarriers\28\29\20const +10465:GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +10466:GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +10467:GrOpFlushState::putBackIndirectDraws\28int\29 +10468:GrOpFlushState::putBackIndices\28int\29 +10469:GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +10470:GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +10471:GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +10472:GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +10473:GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +10474:GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +10475:GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +10476:GrOpFlushState::dstProxyView\28\29\20const +10477:GrOpFlushState::colorLoadOp\28\29\20const +10478:GrOpFlushState::atlasManager\28\29\20const +10479:GrOpFlushState::appliedClip\28\29\20const +10480:GrOpFlushState::addInlineUpload\28std::__2::function&\29>&&\29 +10481:GrOp::~GrOp\28\29 +10482:GrOnFlushCallbackObject::postFlush\28skgpu::AtlasToken\29 +10483:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10484:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10485:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const +10486:GrModulateAtlasCoverageEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10487:GrModulateAtlasCoverageEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10488:GrModulateAtlasCoverageEffect::name\28\29\20const +10489:GrModulateAtlasCoverageEffect::clone\28\29\20const +10490:GrMeshDrawOp::onPrepare\28GrOpFlushState*\29 +10491:GrMeshDrawOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10492:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10493:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10494:GrMatrixEffect::onMakeProgramImpl\28\29\20const +10495:GrMatrixEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10496:GrMatrixEffect::name\28\29\20const +10497:GrMatrixEffect::clone\28\29\20const +10498:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29_9962 +10499:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29 +10500:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::$_0::__invoke\28void\20const*\2c\20void*\29 +10501:GrImageContext::~GrImageContext\28\29_9294 +10502:GrImageContext::~GrImageContext\28\29 +10503:GrHardClip::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +10504:GrGpuResource::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +10505:GrGpuBuffer::~GrGpuBuffer\28\29 +10506:GrGpuBuffer::unref\28\29\20const +10507:GrGpuBuffer::getResourceType\28\29\20const +10508:GrGpuBuffer::computeScratchKey\28skgpu::ScratchKey*\29\20const +10509:GrGpu::endTimerQuery\28GrTimerQuery\20const&\29 +10510:GrGeometryProcessor::onTextureSampler\28int\29\20const +10511:GrGeometryProcessor::ProgramImpl::~ProgramImpl\28\29 +10512:GrGLVaryingHandler::~GrGLVaryingHandler\28\29 +10513:GrGLUniformHandler::~GrGLUniformHandler\28\29_12321 +10514:GrGLUniformHandler::~GrGLUniformHandler\28\29 +10515:GrGLUniformHandler::samplerVariable\28GrResourceHandle\29\20const +10516:GrGLUniformHandler::samplerSwizzle\28GrResourceHandle\29\20const +10517:GrGLUniformHandler::internalAddUniformArray\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20bool\2c\20int\2c\20char\20const**\29 +10518:GrGLUniformHandler::getUniformCStr\28GrResourceHandle\29\20const +10519:GrGLUniformHandler::appendUniformDecls\28GrShaderFlags\2c\20SkString*\29\20const +10520:GrGLUniformHandler::addSampler\28GrBackendFormat\20const&\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20GrShaderCaps\20const*\29 +10521:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +10522:GrGLTextureRenderTarget::onSetLabel\28\29 +10523:GrGLTextureRenderTarget::onRelease\28\29 +10524:GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +10525:GrGLTextureRenderTarget::onAbandon\28\29 +10526:GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +10527:GrGLTextureRenderTarget::backendFormat\28\29\20const +10528:GrGLTexture::~GrGLTexture\28\29_12270 +10529:GrGLTexture::~GrGLTexture\28\29 +10530:GrGLTexture::textureParamsModified\28\29 +10531:GrGLTexture::onStealBackendTexture\28GrBackendTexture*\2c\20std::__2::function*\29 +10532:GrGLTexture::getBackendTexture\28\29\20const +10533:GrGLSemaphore::~GrGLSemaphore\28\29_12247 +10534:GrGLSemaphore::~GrGLSemaphore\28\29 +10535:GrGLSemaphore::setIsOwned\28\29 +10536:GrGLSemaphore::backendSemaphore\28\29\20const +10537:GrGLSLVertexBuilder::~GrGLSLVertexBuilder\28\29 +10538:GrGLSLVertexBuilder::onFinalize\28\29 +10539:GrGLSLUniformHandler::inputSamplerSwizzle\28GrResourceHandle\29\20const +10540:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10583 +10541:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +10542:GrGLSLFragmentShaderBuilder::primaryColorOutputIsInOut\28\29\20const +10543:GrGLSLFragmentShaderBuilder::onFinalize\28\29 +10544:GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +10545:GrGLSLFragmentShaderBuilder::forceHighPrecision\28\29 +10546:GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +10547:GrGLRenderTarget::~GrGLRenderTarget\28\29_12242 +10548:GrGLRenderTarget::~GrGLRenderTarget\28\29 +10549:GrGLRenderTarget::onGpuMemorySize\28\29\20const +10550:GrGLRenderTarget::getBackendRenderTarget\28\29\20const +10551:GrGLRenderTarget::completeStencilAttachment\28GrAttachment*\2c\20bool\29 +10552:GrGLRenderTarget::canAttemptStencilAttachment\28bool\29\20const +10553:GrGLRenderTarget::backendFormat\28\29\20const +10554:GrGLRenderTarget::alwaysClearStencil\28\29\20const +10555:GrGLProgramDataManager::~GrGLProgramDataManager\28\29_12218 +10556:GrGLProgramDataManager::~GrGLProgramDataManager\28\29 +10557:GrGLProgramDataManager::setMatrix4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +10558:GrGLProgramDataManager::setMatrix4f\28GrResourceHandle\2c\20float\20const*\29\20const +10559:GrGLProgramDataManager::setMatrix3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +10560:GrGLProgramDataManager::setMatrix3f\28GrResourceHandle\2c\20float\20const*\29\20const +10561:GrGLProgramDataManager::setMatrix2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +10562:GrGLProgramDataManager::setMatrix2f\28GrResourceHandle\2c\20float\20const*\29\20const +10563:GrGLProgramDataManager::set4iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +10564:GrGLProgramDataManager::set4i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\2c\20int\29\20const +10565:GrGLProgramDataManager::set4f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\2c\20float\29\20const +10566:GrGLProgramDataManager::set3iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +10567:GrGLProgramDataManager::set3i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\29\20const +10568:GrGLProgramDataManager::set3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +10569:GrGLProgramDataManager::set3f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\29\20const +10570:GrGLProgramDataManager::set2iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +10571:GrGLProgramDataManager::set2i\28GrResourceHandle\2c\20int\2c\20int\29\20const +10572:GrGLProgramDataManager::set2f\28GrResourceHandle\2c\20float\2c\20float\29\20const +10573:GrGLProgramDataManager::set1iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +10574:GrGLProgramDataManager::set1i\28GrResourceHandle\2c\20int\29\20const +10575:GrGLProgramDataManager::set1fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +10576:GrGLProgramDataManager::set1f\28GrResourceHandle\2c\20float\29\20const +10577:GrGLProgramBuilder::~GrGLProgramBuilder\28\29_12356 +10578:GrGLProgramBuilder::varyingHandler\28\29 +10579:GrGLProgramBuilder::caps\28\29\20const +10580:GrGLProgram::~GrGLProgram\28\29_12176 +10581:GrGLOpsRenderPass::~GrGLOpsRenderPass\28\29 +10582:GrGLOpsRenderPass::onSetScissorRect\28SkIRect\20const&\29 +10583:GrGLOpsRenderPass::onEnd\28\29 +10584:GrGLOpsRenderPass::onDraw\28int\2c\20int\29 +10585:GrGLOpsRenderPass::onDrawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +10586:GrGLOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +10587:GrGLOpsRenderPass::onDrawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +10588:GrGLOpsRenderPass::onDrawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +10589:GrGLOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +10590:GrGLOpsRenderPass::onClear\28GrScissorState\20const&\2c\20std::__2::array\29 +10591:GrGLOpsRenderPass::onClearStencilClip\28GrScissorState\20const&\2c\20bool\29 +10592:GrGLOpsRenderPass::onBindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +10593:GrGLOpsRenderPass::onBindPipeline\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +10594:GrGLOpsRenderPass::onBindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +10595:GrGLOpsRenderPass::onBegin\28\29 +10596:GrGLOpsRenderPass::inlineUpload\28GrOpFlushState*\2c\20std::__2::function&\29>&\29 +10597:GrGLInterface::~GrGLInterface\28\29_12153 +10598:GrGLInterface::~GrGLInterface\28\29 +10599:GrGLGpu::~GrGLGpu\28\29_12023 +10600:GrGLGpu::xferBarrier\28GrRenderTarget*\2c\20GrXferBarrierType\29 +10601:GrGLGpu::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +10602:GrGLGpu::willExecute\28\29 +10603:GrGLGpu::waitSemaphore\28GrSemaphore*\29 +10604:GrGLGpu::submit\28GrOpsRenderPass*\29 +10605:GrGLGpu::startTimerQuery\28\29 +10606:GrGLGpu::stagingBufferManager\28\29 +10607:GrGLGpu::refPipelineBuilder\28\29 +10608:GrGLGpu::prepareTextureForCrossContextUsage\28GrTexture*\29 +10609:GrGLGpu::precompileShader\28SkData\20const&\2c\20SkData\20const&\29 +10610:GrGLGpu::pipelineBuilder\28\29 +10611:GrGLGpu::onWritePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +10612:GrGLGpu::onWrapRenderableBackendTexture\28GrBackendTexture\20const&\2c\20int\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +10613:GrGLGpu::onWrapCompressedBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +10614:GrGLGpu::onWrapBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\2c\20GrIOType\29 +10615:GrGLGpu::onWrapBackendRenderTarget\28GrBackendRenderTarget\20const&\29 +10616:GrGLGpu::onUpdateCompressedBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20void\20const*\2c\20unsigned\20long\29 +10617:GrGLGpu::onTransferPixelsTo\28GrTexture*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +10618:GrGLGpu::onTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\29 +10619:GrGLGpu::onTransferFromBufferToBuffer\28sk_sp\2c\20unsigned\20long\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +10620:GrGLGpu::onSubmitToGpu\28GrSubmitInfo\20const&\29 +10621:GrGLGpu::onResolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +10622:GrGLGpu::onResetTextureBindings\28\29 +10623:GrGLGpu::onResetContext\28unsigned\20int\29 +10624:GrGLGpu::onRegenerateMipMapLevels\28GrTexture*\29 +10625:GrGLGpu::onReadPixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20unsigned\20long\29 +10626:GrGLGpu::onGetOpsRenderPass\28GrRenderTarget*\2c\20bool\2c\20GrAttachment*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const&\2c\20GrOpsRenderPass::LoadAndStoreInfo\20const&\2c\20GrOpsRenderPass::StencilLoadAndStoreInfo\20const&\2c\20skia_private::TArray\20const&\2c\20GrXferBarrierFlags\29 +10627:GrGLGpu::onDumpJSON\28SkJSONWriter*\29\20const +10628:GrGLGpu::onCreateTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +10629:GrGLGpu::onCreateCompressedTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20void\20const*\2c\20unsigned\20long\29 +10630:GrGLGpu::onCreateCompressedBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\29 +10631:GrGLGpu::onCreateBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +10632:GrGLGpu::onCreateBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +10633:GrGLGpu::onCopySurface\28GrSurface*\2c\20SkIRect\20const&\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +10634:GrGLGpu::onClearBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20std::__2::array\29 +10635:GrGLGpu::makeStencilAttachment\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\29 +10636:GrGLGpu::makeSemaphore\28bool\29 +10637:GrGLGpu::makeMSAAAttachment\28SkISize\2c\20GrBackendFormat\20const&\2c\20int\2c\20skgpu::Protected\2c\20GrMemoryless\29 +10638:GrGLGpu::insertSemaphore\28GrSemaphore*\29 +10639:GrGLGpu::getPreferredStencilFormat\28GrBackendFormat\20const&\29 +10640:GrGLGpu::finishOutstandingGpuWork\28\29 +10641:GrGLGpu::endTimerQuery\28GrTimerQuery\20const&\29 +10642:GrGLGpu::disconnect\28GrGpu::DisconnectType\29 +10643:GrGLGpu::deleteBackendTexture\28GrBackendTexture\20const&\29 +10644:GrGLGpu::compile\28GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\29 +10645:GrGLGpu::checkFinishedCallbacks\28\29 +10646:GrGLGpu::addFinishedCallback\28skgpu::AutoCallback\2c\20std::__2::optional\29 +10647:GrGLGpu::ProgramCache::~ProgramCache\28\29_12134 +10648:GrGLGpu::ProgramCache::~ProgramCache\28\29 +10649:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20unsigned\20int\2c\20float\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29 +10650:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29 +10651:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29 +10652:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\29\29::'lambda'\28void\20const*\2c\20float\29::__invoke\28void\20const*\2c\20float\29 +10653:GrGLFunction::GrGLFunction\28void\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +10654:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28__GLsync*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29 +10655:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +10656:GrGLCaps::~GrGLCaps\28\29_11990 +10657:GrGLCaps::surfaceSupportsReadPixels\28GrSurface\20const*\29\20const +10658:GrGLCaps::supportedWritePixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +10659:GrGLCaps::onSurfaceSupportsWritePixels\28GrSurface\20const*\29\20const +10660:GrGLCaps::onSupportsDynamicMSAA\28GrRenderTargetProxy\20const*\29\20const +10661:GrGLCaps::onSupportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +10662:GrGLCaps::onIsWindowRectanglesSupportedForRT\28GrBackendRenderTarget\20const&\29\20const +10663:GrGLCaps::onGetReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +10664:GrGLCaps::onGetDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\29\20const +10665:GrGLCaps::onGetDefaultBackendFormat\28GrColorType\29\20const +10666:GrGLCaps::onDumpJSON\28SkJSONWriter*\29\20const +10667:GrGLCaps::onCanCopySurface\28GrSurfaceProxy\20const*\2c\20SkIRect\20const&\2c\20GrSurfaceProxy\20const*\2c\20SkIRect\20const&\29\20const +10668:GrGLCaps::onAreColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +10669:GrGLCaps::onApplyOptionsOverrides\28GrContextOptions\20const&\29 +10670:GrGLCaps::maxRenderTargetSampleCount\28GrBackendFormat\20const&\29\20const +10671:GrGLCaps::makeDesc\28GrRenderTarget*\2c\20GrProgramInfo\20const&\2c\20GrCaps::ProgramDescOverrideFlags\29\20const +10672:GrGLCaps::isFormatTexturable\28GrBackendFormat\20const&\2c\20GrTextureType\29\20const +10673:GrGLCaps::isFormatSRGB\28GrBackendFormat\20const&\29\20const +10674:GrGLCaps::isFormatRenderable\28GrBackendFormat\20const&\2c\20int\29\20const +10675:GrGLCaps::isFormatCopyable\28GrBackendFormat\20const&\29\20const +10676:GrGLCaps::isFormatAsColorTypeRenderable\28GrColorType\2c\20GrBackendFormat\20const&\2c\20int\29\20const +10677:GrGLCaps::getWriteSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +10678:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrBackendFormat\20const&\29\20const +10679:GrGLCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +10680:GrGLCaps::getBackendFormatFromCompressionType\28SkTextureCompressionType\29\20const +10681:GrGLCaps::computeFormatKey\28GrBackendFormat\20const&\29\20const +10682:GrGLBuffer::~GrGLBuffer\28\29_11940 +10683:GrGLBuffer::~GrGLBuffer\28\29 +10684:GrGLBuffer::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +10685:GrGLBuffer::onUpdateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +10686:GrGLBuffer::onUnmap\28GrGpuBuffer::MapType\29 +10687:GrGLBuffer::onSetLabel\28\29 +10688:GrGLBuffer::onRelease\28\29 +10689:GrGLBuffer::onMap\28GrGpuBuffer::MapType\29 +10690:GrGLBuffer::onClearToZero\28\29 +10691:GrGLBuffer::onAbandon\28\29 +10692:GrGLBackendTextureData::~GrGLBackendTextureData\28\29_11914 +10693:GrGLBackendTextureData::~GrGLBackendTextureData\28\29 +10694:GrGLBackendTextureData::isSameTexture\28GrBackendTextureData\20const*\29\20const +10695:GrGLBackendTextureData::isProtected\28\29\20const +10696:GrGLBackendTextureData::getBackendFormat\28\29\20const +10697:GrGLBackendTextureData::equal\28GrBackendTextureData\20const*\29\20const +10698:GrGLBackendTextureData::copyTo\28SkAnySubclass&\29\20const +10699:GrGLBackendRenderTargetData::getBackendFormat\28\29\20const +10700:GrGLBackendRenderTargetData::equal\28GrBackendRenderTargetData\20const*\29\20const +10701:GrGLBackendRenderTargetData::copyTo\28SkAnySubclass&\29\20const +10702:GrGLBackendFormatData::toString\28\29\20const +10703:GrGLBackendFormatData::stencilBits\28\29\20const +10704:GrGLBackendFormatData::equal\28GrBackendFormatData\20const*\29\20const +10705:GrGLBackendFormatData::desc\28\29\20const +10706:GrGLBackendFormatData::copyTo\28SkAnySubclass&\29\20const +10707:GrGLBackendFormatData::compressionType\28\29\20const +10708:GrGLBackendFormatData::channelMask\28\29\20const +10709:GrGLBackendFormatData::bytesPerBlock\28\29\20const +10710:GrGLAttachment::~GrGLAttachment\28\29 +10711:GrGLAttachment::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +10712:GrGLAttachment::onSetLabel\28\29 +10713:GrGLAttachment::onRelease\28\29 +10714:GrGLAttachment::onAbandon\28\29 +10715:GrGLAttachment::backendFormat\28\29\20const +10716:GrFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +10717:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10718:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const +10719:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10720:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10721:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::name\28\29\20const +10722:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +10723:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::clone\28\29\20const +10724:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10725:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const +10726:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::name\28\29\20const +10727:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::clone\28\29\20const +10728:GrFragmentProcessor::ProgramImpl::~ProgramImpl\28\29 +10729:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10730:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const +10731:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::name\28\29\20const +10732:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::clone\28\29\20const +10733:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10734:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const +10735:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::name\28\29\20const +10736:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +10737:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::clone\28\29\20const +10738:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10739:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const +10740:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::name\28\29\20const +10741:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +10742:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::clone\28\29\20const +10743:GrFixedClip::~GrFixedClip\28\29_9069 +10744:GrFixedClip::~GrFixedClip\28\29 +10745:GrExternalTextureGenerator::onGenerateTexture\28GrRecordingContext*\2c\20SkImageInfo\20const&\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +10746:GrEagerDynamicVertexAllocator::lock\28unsigned\20long\2c\20int\29 +10747:GrDynamicAtlas::~GrDynamicAtlas\28\29_9040 +10748:GrDynamicAtlas::~GrDynamicAtlas\28\29 +10749:GrDrawOp::usesStencil\28\29\20const +10750:GrDrawOp::usesMSAA\28\29\20const +10751:GrDrawOp::fixedFunctionFlags\28\29\20const +10752:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29_10231 +10753:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29 +10754:GrDistanceFieldPathGeoProc::onTextureSampler\28int\29\20const +10755:GrDistanceFieldPathGeoProc::name\28\29\20const +10756:GrDistanceFieldPathGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10757:GrDistanceFieldPathGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10758:GrDistanceFieldPathGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10759:GrDistanceFieldPathGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10760:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29_10235 +10761:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29 +10762:GrDistanceFieldLCDTextGeoProc::name\28\29\20const +10763:GrDistanceFieldLCDTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10764:GrDistanceFieldLCDTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10765:GrDistanceFieldLCDTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10766:GrDistanceFieldLCDTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10767:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29_10227 +10768:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29 +10769:GrDistanceFieldA8TextGeoProc::name\28\29\20const +10770:GrDistanceFieldA8TextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10771:GrDistanceFieldA8TextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10772:GrDistanceFieldA8TextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10773:GrDistanceFieldA8TextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10774:GrDisableColorXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10775:GrDisableColorXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10776:GrDirectContext::~GrDirectContext\28\29_8941 +10777:GrDirectContext::releaseResourcesAndAbandonContext\28\29 +10778:GrDirectContext::init\28\29 +10779:GrDirectContext::abandoned\28\29 +10780:GrDirectContext::abandonContext\28\29 +10781:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29_8571 +10782:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29 +10783:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29_9064 +10784:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29 +10785:GrCpuVertexAllocator::unlock\28int\29 +10786:GrCpuVertexAllocator::lock\28unsigned\20long\2c\20int\29 +10787:GrCpuBuffer::unref\28\29\20const +10788:GrCoverageSetOpXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10789:GrCoverageSetOpXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10790:GrCopyRenderTask::~GrCopyRenderTask\28\29_8901 +10791:GrCopyRenderTask::onMakeSkippable\28\29 +10792:GrCopyRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +10793:GrCopyRenderTask::onExecute\28GrOpFlushState*\29 +10794:GrCopyRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +10795:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10796:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10797:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const +10798:GrConvexPolyEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10799:GrConvexPolyEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10800:GrConvexPolyEffect::name\28\29\20const +10801:GrConvexPolyEffect::clone\28\29\20const +10802:GrContext_Base::~GrContext_Base\28\29_8881 +10803:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29_8869 +10804:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29 +10805:GrContextThreadSafeProxy::isValidCharacterizationForVulkan\28sk_sp\2c\20bool\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20bool\2c\20bool\29 +10806:GrConicEffect::name\28\29\20const +10807:GrConicEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10808:GrConicEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10809:GrConicEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10810:GrConicEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10811:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29_8853 +10812:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29 +10813:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10814:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10815:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const +10816:GrColorSpaceXformEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10817:GrColorSpaceXformEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10818:GrColorSpaceXformEffect::name\28\29\20const +10819:GrColorSpaceXformEffect::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +10820:GrColorSpaceXformEffect::clone\28\29\20const +10821:GrCaps::~GrCaps\28\29 +10822:GrCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +10823:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29_10140 +10824:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29 +10825:GrBitmapTextGeoProc::onTextureSampler\28int\29\20const +10826:GrBitmapTextGeoProc::name\28\29\20const +10827:GrBitmapTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10828:GrBitmapTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10829:GrBitmapTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10830:GrBitmapTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10831:GrBicubicEffect::onMakeProgramImpl\28\29\20const +10832:GrBicubicEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +10833:GrBicubicEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10834:GrBicubicEffect::name\28\29\20const +10835:GrBicubicEffect::clone\28\29\20const +10836:GrBicubicEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10837:GrBicubicEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10838:GrAttachment::onGpuMemorySize\28\29\20const +10839:GrAttachment::getResourceType\28\29\20const +10840:GrAttachment::computeScratchKey\28skgpu::ScratchKey*\29\20const +10841:GrAtlasManager::~GrAtlasManager\28\29_11795 +10842:GrAtlasManager::preFlush\28GrOnFlushResourceProvider*\29 +10843:GrAtlasManager::postFlush\28skgpu::AtlasToken\29 +10844:GrAATriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +10845:GetRectsForRange\28skia::textlayout::Paragraph&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +10846:GetRectsForPlaceholders\28skia::textlayout::Paragraph&\29 +10847:GetLineMetrics\28skia::textlayout::Paragraph&\29 +10848:GetLineMetricsAt\28skia::textlayout::Paragraph&\2c\20unsigned\20long\29 +10849:GetGlyphInfoAt\28skia::textlayout::Paragraph&\2c\20unsigned\20long\29 +10850:GetCoeffsFast +10851:GetCoeffsAlt +10852:GetClosestGlyphInfoAtCoordinate\28skia::textlayout::Paragraph&\2c\20float\2c\20float\29 +10853:FontMgrRunIterator::~FontMgrRunIterator\28\29_13358 +10854:FontMgrRunIterator::~FontMgrRunIterator\28\29 +10855:FontMgrRunIterator::currentFont\28\29\20const +10856:FontMgrRunIterator::consume\28\29 +10857:ExtractGreen_C +10858:ExtractAlpha_C +10859:ExtractAlphaRows +10860:ExternalWebGLTexture::~ExternalWebGLTexture\28\29_904 +10861:ExternalWebGLTexture::~ExternalWebGLTexture\28\29 +10862:ExternalWebGLTexture::getBackendTexture\28\29 +10863:ExternalWebGLTexture::dispose\28\29 +10864:ExportAlphaRGBA4444 +10865:ExportAlpha +10866:Equals\28SkPath\20const&\2c\20SkPath\20const&\29 +10867:End +10868:EmitYUV +10869:EmitSampledRGB +10870:EmitRescaledYUV +10871:EmitRescaledRGB +10872:EmitRescaledAlphaYUV +10873:EmitRescaledAlphaRGB +10874:EmitFancyRGB +10875:EmitAlphaYUV +10876:EmitAlphaRGBA4444 +10877:EmitAlphaRGB +10878:EllipticalRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10879:EllipticalRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10880:EllipticalRRectOp::name\28\29\20const +10881:EllipticalRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10882:EllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10883:EllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10884:EllipseOp::name\28\29\20const +10885:EllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10886:EllipseGeometryProcessor::name\28\29\20const +10887:EllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10888:EllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10889:EllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10890:Dual_Project +10891:DitherCombine8x8_C +10892:DispatchAlpha_C +10893:DispatchAlphaToGreen_C +10894:DisableColorXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +10895:DisableColorXP::name\28\29\20const +10896:DisableColorXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +10897:DisableColorXP::makeProgramImpl\28\29\20const +10898:Direct_Move_Y +10899:Direct_Move_X +10900:Direct_Move_Orig_Y +10901:Direct_Move_Orig_X +10902:Direct_Move_Orig +10903:Direct_Move +10904:DefaultGeoProc::name\28\29\20const +10905:DefaultGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10906:DefaultGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10907:DefaultGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10908:DefaultGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10909:DataFontLoader::loadSystemFonts\28SkFontScanner\20const*\2c\20skia_private::TArray\2c\20true>*\29\20const +10910:DIEllipseOp::~DIEllipseOp\28\29_11298 +10911:DIEllipseOp::~DIEllipseOp\28\29 +10912:DIEllipseOp::visitProxies\28std::__2::function\20const&\29\20const +10913:DIEllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10914:DIEllipseOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10915:DIEllipseOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10916:DIEllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10917:DIEllipseOp::name\28\29\20const +10918:DIEllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10919:DIEllipseGeometryProcessor::name\28\29\20const +10920:DIEllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10921:DIEllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10922:DIEllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10923:DC8uv_C +10924:DC8uvNoTop_C +10925:DC8uvNoTopLeft_C +10926:DC8uvNoLeft_C +10927:DC4_C +10928:DC16_C +10929:DC16NoTop_C +10930:DC16NoTopLeft_C +10931:DC16NoLeft_C +10932:CustomXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10933:CustomXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +10934:CustomXP::xferBarrierType\28GrCaps\20const&\29\20const +10935:CustomXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +10936:CustomXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10937:CustomXP::name\28\29\20const +10938:CustomXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +10939:CustomXP::makeProgramImpl\28\29\20const +10940:CustomTeardown +10941:CustomSetup +10942:CustomPut +10943:Current_Ppem_Stretched +10944:Current_Ppem +10945:Cr_z_zcalloc +10946:CoverageSetOpXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +10947:CoverageSetOpXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10948:CoverageSetOpXP::name\28\29\20const +10949:CoverageSetOpXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +10950:CoverageSetOpXP::makeProgramImpl\28\29\20const +10951:CopyPath\28SkPath\20const&\29 +10952:ConvertRGB24ToY_C +10953:ConvertBGR24ToY_C +10954:ConvertARGBToY_C +10955:ColorTableEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10956:ColorTableEffect::onMakeProgramImpl\28\29\20const +10957:ColorTableEffect::name\28\29\20const +10958:ColorTableEffect::clone\28\29\20const +10959:CircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +10960:CircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10961:CircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10962:CircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10963:CircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10964:CircularRRectOp::name\28\29\20const +10965:CircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10966:CircleOp::~CircleOp\28\29_11272 +10967:CircleOp::~CircleOp\28\29 +10968:CircleOp::visitProxies\28std::__2::function\20const&\29\20const +10969:CircleOp::programInfo\28\29 +10970:CircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10971:CircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10972:CircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10973:CircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10974:CircleOp::name\28\29\20const +10975:CircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10976:CircleGeometryProcessor::name\28\29\20const +10977:CircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10978:CircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10979:CircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10980:CanInterpolate\28SkPath\20const&\2c\20SkPath\20const&\29 +10981:ButtCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +10982:ButtCapDashedCircleOp::visitProxies\28std::__2::function\20const&\29\20const +10983:ButtCapDashedCircleOp::programInfo\28\29 +10984:ButtCapDashedCircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10985:ButtCapDashedCircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10986:ButtCapDashedCircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10987:ButtCapDashedCircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10988:ButtCapDashedCircleOp::name\28\29\20const +10989:ButtCapDashedCircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10990:ButtCapDashedCircleGeometryProcessor::name\28\29\20const +10991:ButtCapDashedCircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10992:ButtCapDashedCircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10993:ButtCapDashedCircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10994:BrotliDefaultAllocFunc +10995:BluntJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +10996:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10997:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10998:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const +10999:BlendFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11000:BlendFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11001:BlendFragmentProcessor::name\28\29\20const +11002:BlendFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11003:BlendFragmentProcessor::clone\28\29\20const +11004:AutoCleanPng::infoCallback\28unsigned\20long\29 +11005:AutoCleanPng::decodeBounds\28\29 +11006:ApplyTrim\28SkPath&\2c\20float\2c\20float\2c\20bool\29 +11007:ApplyTransform\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +11008:ApplyStroke\28SkPath&\2c\20StrokeOpts\29 +11009:ApplySimplify\28SkPath&\29 +11010:ApplyRewind\28SkPath&\29 +11011:ApplyReset\28SkPath&\29 +11012:ApplyRQuadTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\29 +11013:ApplyRMoveTo\28SkPath&\2c\20float\2c\20float\29 +11014:ApplyRLineTo\28SkPath&\2c\20float\2c\20float\29 +11015:ApplyRCubicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +11016:ApplyRConicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +11017:ApplyRArcToArcSize\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29 +11018:ApplyQuadTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\29 +11019:ApplyPathOp\28SkPath&\2c\20SkPath\20const&\2c\20SkPathOp\29 +11020:ApplyMoveTo\28SkPath&\2c\20float\2c\20float\29 +11021:ApplyLineTo\28SkPath&\2c\20float\2c\20float\29 +11022:ApplyDash\28SkPath&\2c\20float\2c\20float\2c\20float\29 +11023:ApplyCubicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +11024:ApplyConicTo\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +11025:ApplyClose\28SkPath&\29 +11026:ApplyArcToTangent\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +11027:ApplyArcToArcSize\28SkPath&\2c\20float\2c\20float\2c\20float\2c\20bool\2c\20bool\2c\20float\2c\20float\29 +11028:ApplyAlphaMultiply_C +11029:ApplyAlphaMultiply_16b_C +11030:ApplyAddPath\28SkPath&\2c\20SkPath\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +11031:AlphaReplace_C +11032:$_3::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +11033:$_2::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 +11034:$_1::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +11035:$_0::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/chromium/canvaskit.wasm b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/chromium/canvaskit.wasm new file mode 100644 index 0000000000..914a40ccb5 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/chromium/canvaskit.wasm differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm.js new file mode 100644 index 0000000000..36392cf9da --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm.js @@ -0,0 +1,158 @@ + +var skwasm = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + + return ( +function(moduleArg = {}) { + var moduleRtn; + +function aa(){e.buffer!=h.buffer&&k();return h}function n(){e.buffer!=h.buffer&&k();return ba}function q(){e.buffer!=h.buffer&&k();return ca}function t(){e.buffer!=h.buffer&&k();return da}function u(){e.buffer!=h.buffer&&k();return ea}function fa(){e.buffer!=h.buffer&&k();return ha}var v=moduleArg,ia,ja,ka=new Promise((a,b)=>{ia=a;ja=b}),la="object"==typeof window,ma="function"==typeof importScripts,w=ma&&self.name?.startsWith("em-pthread"),na=Object.assign({},v),x="",oa,pa; +if(la||ma)ma?x=self.location.href:"undefined"!=typeof document&&document.currentScript&&(x=document.currentScript.src),_scriptName&&(x=_scriptName),x.startsWith("blob:")?x="":x=x.substr(0,x.replace(/[?#].*/,"").lastIndexOf("/")+1),ma&&(pa=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),oa=a=>fetch(a,{credentials:"same-origin"}).then(b=>b.ok?b.arrayBuffer():Promise.reject(Error(b.status+" : "+b.url))); +var qa=console.log.bind(console),y=console.error.bind(console);Object.assign(v,na);na=null;var e,ra,sa=!1,ta,h,ba,ua,va,ca,da,ea,ha;function k(){var a=e.buffer;h=new Int8Array(a);ua=new Int16Array(a);ba=new Uint8Array(a);va=new Uint16Array(a);ca=new Int32Array(a);da=new Uint32Array(a);ea=new Float32Array(a);ha=new Float64Array(a)} +if(w){var wa,xa=!1;y=function(...b){console.error(b.join(" "))};self.alert=function(...b){postMessage({g:"alert",text:b.join(" "),na:ya()})};v.instantiateWasm=(b,c)=>new Promise(d=>{wa=f=>{f=new WebAssembly.Instance(f,za());c(f);d()}});self.onunhandledrejection=b=>{throw b.reason||b;};function a(b){try{var c=b.data,d=c.g;if("load"===d){let f=[];self.onmessage=g=>f.push(g);self.startWorker=()=>{postMessage({g:"loaded"});for(let g of f)a(g);self.onmessage=a};for(const g of c.ca)if(!v[g]||v[g].proxy)v[g]= +(...l)=>{postMessage({g:"callHandler",ba:g,X:l})},"print"==g&&(qa=v[g]),"printErr"==g&&(y=v[g]);e=c.pa;k();wa(c.qa)}else if("run"===d){Aa(c.l);Ba(c.l,0,0,1,0,0);Ca(c);Da();Ea(c.l);xa||=!0;try{Fa(c.la,c.J)}catch(f){if("unwind"!=f)throw f;}}else"setimmediate"!==c.target&&("checkMailbox"===d?xa&&Ga():d&&(y(`worker: received unknown command ${d}`),y(c)))}catch(f){throw Ha(),f;}}self.onmessage=a}w||(e=new WebAssembly.Memory({initial:256,maximum:32768,shared:!0}),k()); +var Ia=[],Ja=[],Ka=[],z=0,La=null,Ma=null;function Na(){z--;if(0==z&&(null!==La&&(clearInterval(La),La=null),Ma)){var a=Ma;Ma=null;a()}}function Oa(a){a="Aborted("+a+")";y(a);sa=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ja(a);throw a;}var Pa=a=>a.startsWith("data:application/octet-stream;base64,"),Qa;function Ra(a){return oa(a).then(b=>new Uint8Array(b),()=>{if(pa)var b=pa(a);else throw"both async and sync fetching of the wasm failed";return b})} +function Sa(a,b,c){return Ra(a).then(d=>WebAssembly.instantiate(d,b)).then(c,d=>{y(`failed to asynchronously prepare wasm: ${d}`);Oa(d)})}function Ta(a,b){var c=Qa;return"function"!=typeof WebAssembly.instantiateStreaming||Pa(c)||"function"!=typeof fetch?Sa(c,a,b):fetch(c,{credentials:"same-origin"}).then(d=>WebAssembly.instantiateStreaming(d,a).then(b,function(f){y(`wasm streaming compile failed: ${f}`);y("falling back to ArrayBuffer instantiation");return Sa(c,a,b)}))} +function za(){Ua={__cxa_throw:Va,__pthread_create_js:Wa,__syscall_fcntl64:Xa,__syscall_fstat64:Ya,__syscall_ioctl:Za,__syscall_openat:$a,_abort_js:ab,_emscripten_get_now_is_monotonic:bb,_emscripten_init_main_thread_js:cb,_emscripten_notify_mailbox_postmessage:db,_emscripten_receive_on_main_thread_js:eb,_emscripten_runtime_keepalive_clear:fb,_emscripten_thread_cleanup:gb,_emscripten_thread_mailbox_await:Ea,_emscripten_thread_set_strongref:hb,_emscripten_throw_longjmp:ib,_mmap_js:jb,_munmap_js:kb,_setitimer_js:lb, +_tzset_js:mb,emscripten_check_blocking_allowed:nb,emscripten_exit_with_live_runtime:ob,emscripten_get_now:pb,emscripten_glActiveTexture:qb,emscripten_glAttachShader:rb,emscripten_glBeginQuery:sb,emscripten_glBeginQueryEXT:tb,emscripten_glBindAttribLocation:ub,emscripten_glBindBuffer:vb,emscripten_glBindFramebuffer:wb,emscripten_glBindRenderbuffer:xb,emscripten_glBindSampler:yb,emscripten_glBindTexture:zb,emscripten_glBindVertexArray:Ab,emscripten_glBindVertexArrayOES:Ab,emscripten_glBlendColor:Bb, +emscripten_glBlendEquation:Cb,emscripten_glBlendFunc:Db,emscripten_glBlitFramebuffer:Eb,emscripten_glBufferData:Fb,emscripten_glBufferSubData:Gb,emscripten_glCheckFramebufferStatus:Hb,emscripten_glClear:Ib,emscripten_glClearColor:Jb,emscripten_glClearStencil:Kb,emscripten_glClientWaitSync:Lb,emscripten_glColorMask:Mb,emscripten_glCompileShader:Nb,emscripten_glCompressedTexImage2D:Ob,emscripten_glCompressedTexSubImage2D:Pb,emscripten_glCopyBufferSubData:Qb,emscripten_glCopyTexSubImage2D:Rb,emscripten_glCreateProgram:Sb, +emscripten_glCreateShader:Tb,emscripten_glCullFace:Ub,emscripten_glDeleteBuffers:Vb,emscripten_glDeleteFramebuffers:Wb,emscripten_glDeleteProgram:Xb,emscripten_glDeleteQueries:Yb,emscripten_glDeleteQueriesEXT:Zb,emscripten_glDeleteRenderbuffers:$b,emscripten_glDeleteSamplers:ac,emscripten_glDeleteShader:bc,emscripten_glDeleteSync:cc,emscripten_glDeleteTextures:dc,emscripten_glDeleteVertexArrays:ec,emscripten_glDeleteVertexArraysOES:ec,emscripten_glDepthMask:fc,emscripten_glDisable:gc,emscripten_glDisableVertexAttribArray:hc, +emscripten_glDrawArrays:ic,emscripten_glDrawArraysInstanced:jc,emscripten_glDrawArraysInstancedBaseInstanceWEBGL:kc,emscripten_glDrawBuffers:lc,emscripten_glDrawElements:mc,emscripten_glDrawElementsInstanced:nc,emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL:oc,emscripten_glDrawRangeElements:pc,emscripten_glEnable:qc,emscripten_glEnableVertexAttribArray:rc,emscripten_glEndQuery:sc,emscripten_glEndQueryEXT:tc,emscripten_glFenceSync:uc,emscripten_glFinish:vc,emscripten_glFlush:wc,emscripten_glFramebufferRenderbuffer:xc, +emscripten_glFramebufferTexture2D:yc,emscripten_glFrontFace:zc,emscripten_glGenBuffers:Ac,emscripten_glGenFramebuffers:Bc,emscripten_glGenQueries:Cc,emscripten_glGenQueriesEXT:Dc,emscripten_glGenRenderbuffers:Ec,emscripten_glGenSamplers:Fc,emscripten_glGenTextures:Gc,emscripten_glGenVertexArrays:Hc,emscripten_glGenVertexArraysOES:Hc,emscripten_glGenerateMipmap:Ic,emscripten_glGetBufferParameteriv:Jc,emscripten_glGetError:Kc,emscripten_glGetFloatv:Lc,emscripten_glGetFramebufferAttachmentParameteriv:Mc, +emscripten_glGetIntegerv:Nc,emscripten_glGetProgramInfoLog:Oc,emscripten_glGetProgramiv:Pc,emscripten_glGetQueryObjecti64vEXT:Qc,emscripten_glGetQueryObjectui64vEXT:Qc,emscripten_glGetQueryObjectuiv:Rc,emscripten_glGetQueryObjectuivEXT:Sc,emscripten_glGetQueryiv:Tc,emscripten_glGetQueryivEXT:Uc,emscripten_glGetRenderbufferParameteriv:Vc,emscripten_glGetShaderInfoLog:Wc,emscripten_glGetShaderPrecisionFormat:Xc,emscripten_glGetShaderiv:Yc,emscripten_glGetString:Zc,emscripten_glGetStringi:$c,emscripten_glGetUniformLocation:ad, +emscripten_glInvalidateFramebuffer:bd,emscripten_glInvalidateSubFramebuffer:cd,emscripten_glIsSync:dd,emscripten_glIsTexture:ed,emscripten_glLineWidth:fd,emscripten_glLinkProgram:gd,emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL:hd,emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL:jd,emscripten_glPixelStorei:kd,emscripten_glQueryCounterEXT:ld,emscripten_glReadBuffer:md,emscripten_glReadPixels:and,emscripten_glRenderbufferStorage:od,emscripten_glRenderbufferStorageMultisample:pd, +emscripten_glSamplerParameterf:qd,emscripten_glSamplerParameteri:rd,emscripten_glSamplerParameteriv:sd,emscripten_glScissor:td,emscripten_glShaderSource:ud,emscripten_glStencilFunc:vd,emscripten_glStencilFuncSeparate:wd,emscripten_glStencilMask:xd,emscripten_glStencilMaskSeparate:yd,emscripten_glStencilOp:zd,emscripten_glStencilOpSeparate:Ad,emscripten_glTexImage2D:Bd,emscripten_glTexParameterf:Cd,emscripten_glTexParameterfv:Dd,emscripten_glTexParameteri:Ed,emscripten_glTexParameteriv:Fd,emscripten_glTexStorage2D:Gd, +emscripten_glTexSubImage2D:Hd,emscripten_glUniform1f:Id,emscripten_glUniform1fv:Jd,emscripten_glUniform1i:Kd,emscripten_glUniform1iv:Ld,emscripten_glUniform2f:Md,emscripten_glUniform2fv:And,emscripten_glUniform2i:Od,emscripten_glUniform2iv:Pd,emscripten_glUniform3f:Qd,emscripten_glUniform3fv:Rd,emscripten_glUniform3i:Sd,emscripten_glUniform3iv:Td,emscripten_glUniform4f:Ud,emscripten_glUniform4fv:Vd,emscripten_glUniform4i:Wd,emscripten_glUniform4iv:Xd,emscripten_glUniformMatrix2fv:Yd,emscripten_glUniformMatrix3fv:Zd, +emscripten_glUniformMatrix4fv:$d,emscripten_glUseProgram:ae,emscripten_glVertexAttrib1f:be,emscripten_glVertexAttrib2fv:ce,emscripten_glVertexAttrib3fv:de,emscripten_glVertexAttrib4fv:ee,emscripten_glVertexAttribDivisor:fe,emscripten_glVertexAttribIPointer:ge,emscripten_glVertexAttribPointer:he,emscripten_glViewport:ie,emscripten_glWaitSync:je,emscripten_resize_heap:ke,emscripten_webgl_enable_extension:le,emscripten_webgl_get_current_context:me,emscripten_webgl_make_context_current:ne,environ_get:oe, +environ_sizes_get:pe,exit:qe,fd_close:re,fd_pread:se,fd_read:te,fd_seek:ue,fd_write:ve,glDeleteTextures:dc,glGetIntegerv:Nc,glGetString:Zc,glGetStringi:$c,invoke_ii:we,invoke_iii:xe,invoke_iiii:ye,invoke_iiiii:ze,invoke_iiiiiii:Ae,invoke_vi:Be,invoke_vii:Ce,invoke_viii:De,invoke_viiii:Ee,invoke_viiiiiii:Fe,memory:e,proc_exit:Ge,skwasm_captureImageBitmap:He,skwasm_connectThread:Ie,skwasm_createGlTextureFromTextureSource:Je,skwasm_createOffscreenCanvas:Ke,skwasm_dispatchDisposeSurface:Le,skwasm_dispatchRasterizeImage:Me, +skwasm_dispatchRenderPictures:Ne,skwasm_disposeAssociatedObjectOnThread:Oe,skwasm_getAssociatedObject:Pe,skwasm_postRasterizeResult:Qe,skwasm_resizeCanvas:Re,skwasm_resolveAndPostImages:Se,skwasm_setAssociatedObjectOnThread:Te};return{env:Ua,wasi_snapshot_preview1:Ua}}function Ue(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a} +var Ve=a=>{a.terminate();a.onmessage=()=>{}},Ze=a=>{0==A.length&&(We(),Xe(A[0]));var b=A.pop();if(!b)return 6;Ye.push(b);B[a.l]=b;b.l=a.l;var c={g:"run",la:a.ka,J:a.J,l:a.l};c.B=a.B;c.L=a.L;b.postMessage(c,a.U);return 0},D=0,af=a=>$e(a);v.stackAlloc=af;var H=(a,b,...c)=>{for(var d=c.length,f=E(),g=$e(8*d),l=g>>3,m=0;m{if(!(a instanceof Ue||"unwind"==a))throw a;};function ef(a){if(w)return H(1,0,a);qe(a)}var qe=a=>{ta=a;if(w)throw ef(a),"unwind";Ge(a)},A=[],Ye=[],ff=[],B={};function gf(){for(var a=1;a--;)We();Ia.unshift(()=>{z++;hf(()=>Na())})}var kf=a=>{var b=a.l;delete B[b];A.push(a);Ye.splice(Ye.indexOf(a),1);a.l=0;jf(b)}; +function Ca(a){"undefined"!=typeof lf&&(Object.assign(mf,a.L),!v.canvas&&a.B&&mf[a.B]&&(v.canvas=mf[a.B].T,v.canvas.id=a.B))}function Da(){ff.forEach(a=>a())} +var Xe=a=>new Promise(b=>{a.onmessage=g=>{g=g.data;var l=g.g;if(g.I&&g.I!=ya()){var m=B[g.I];m?m.postMessage(g,g.U):y(`Internal error! Worker sent a message "${l}" to target pthread ${g.I}, but that thread no longer exists!`)}else if("checkMailbox"===l)Ga();else if("spawnThread"===l)Ze(g);else if("cleanupThread"===l)kf(B[g.ma]);else if("loaded"===l)a.loaded=!0,b(a);else if("alert"===l)alert(`Thread ${g.na}: ${g.text}`);else if("setimmediate"===g.target)a.postMessage(g);else if("callHandler"===l)v[g.ba](...g.X); +else l&&y(`worker sent an unknown command ${l}`)};a.onerror=g=>{y(`${"worker sent an error!"} ${g.filename}:${g.lineno}: ${g.message}`);throw g;};var c=[],d=[],f;for(f of d)v.propertyIsEnumerable(f)&&c.push(f);a.postMessage({g:"load",ca:c,pa:e,qa:ra})});function hf(a){w?a():Promise.all(A.map(Xe)).then(a)}function We(){var a=_scriptName;v.mainScriptUrlOrBlob&&(a=v.mainScriptUrlOrBlob,"string"!=typeof a&&(a=URL.createObjectURL(a)));a=new Worker(a,{type:"module",name:"em-pthread"});A.push(a)} +var nf=a=>{a.forEach(b=>b(v))},Aa=a=>{k();var b=t()[a+52>>2];a=t()[a+56>>2];of(b,b-a);G(b)},I,Fa=(a,b)=>{cf=D=0;a=I.get(a)(b);cf||0{var d=new qf(a);t()[d.A+16>>2]=0;t()[d.A+4>>2]=b;t()[d.A+8>>2]=c;rf=a;sf++;throw rf;};function tf(a,b,c,d){return w?H(2,1,a,b,c,d):Wa(a,b,c,d)} +var uf="undefined"!=typeof TextDecoder?new TextDecoder:void 0,vf=(a,b=0,c=NaN)=>{var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16f?d+=String.fromCharCode(f):(f-=65536,d+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else d+=String.fromCharCode(f)}return d},wf= +(a,b)=>a?vf(n(),a,b):"",Wa=(a,b,c,d)=>{if("undefined"==typeof SharedArrayBuffer)return 6;var f=[],g=0,l=b?t()[b+40>>2]:0;l=(l=4294967295==l?"#canvas":wf(l).trim())?l.split(","):[];var m={},p=v.canvas?.id||"";for(r of l){var r=r.trim();try{if("#canvas"==r){if(!v.canvas){y(`pthread_create: could not find canvas with ID "${r}" to transfer to thread!`);g=28;break}r=v.canvas.id}if(mf[r]){var F=mf[r];mf[r]=null;v.canvas instanceof OffscreenCanvas&&r===v.canvas.id&&(v.canvas=null)}else if(!w){var C=v.canvas&& +v.canvas.id===r?v.canvas:document.querySelector(r);if(!C){y(`pthread_create: could not find canvas with ID "${r}" to transfer to thread!`);g=28;break}if(C.Y){y(`pthread_create: cannot transfer canvas with ID "${r}" to thread, since the current thread does not have control over it!`);g=63;break}if(C.transferControlToOffscreen)C.u||(C.u=xf(12),q()[C.u>>2]=C.width,q()[C.u+4>>2]=C.height,t()[C.u+8>>2]=0),F={T:C.transferControlToOffscreen(),u:C.u,id:C.id},C.Y=!0;else return y(`pthread_create: cannot transfer control of canvas "${r}" to pthread, because current browser does not support OffscreenCanvas!`), +y("pthread_create: Build with -sOFFSCREEN_FRAMEBUFFER to enable fallback proxying of GL commands from pthread to main thread."),52}F&&(f.push(F.T),m[F.id]=F)}catch(rg){return y(`pthread_create: failed to transfer control of canvas "${r}" to OffscreenCanvas! Error: ${rg}`),28}}if(w&&(0===f.length||g))return tf(a,b,c,d);if(g)return g;for(C of Object.values(m))t()[C.u+8>>2]=a;a={ka:c,l:a,J:d,B:p,L:m,U:f};return w?(a.g="spawnThread",postMessage(a,f),0):Ze(a)}; +function Xa(a,b,c){return w?H(3,1,a,b,c):0}function Ya(a,b){if(w)return H(4,1,a,b)}function Za(a,b,c){return w?H(5,1,a,b,c):0}function $a(a,b,c,d){if(w)return H(6,1,a,b,c,d)} +var ab=()=>{Oa("")},bb=()=>1,cb=a=>{Ba(a,!ma,1,!la,65536,!1);Da()},yf=a=>{if(!sa)try{if(a(),!(cf||0{"function"===typeof Atomics.oa&&(Atomics.oa(q(),a>>2,a).value.then(Ga),a+=128,Atomics.store(q(),a>>2,1))},Ga=()=>{var a=ya();a&&(Ea(a),yf(zf))},db=(a,b)=>{a==b?setTimeout(Ga):w?postMessage({I:a,g:"checkMailbox"}):(a=B[a])&&a.postMessage({g:"checkMailbox"})},Af=[],eb=(a,b,c,d,f)=>{Af.length=d;b=f>>3;for(c=0;c{cf=!1;D=0},gb=a=>{w?postMessage({g:"cleanupThread",ma:a}):kf(B[a])},hb=()=>{},ib=()=>{throw Infinity;};function jb(a,b,c,d,f,g,l,m){return w?H(7,1,a,b,c,d,f,g,l,m):-52}function kb(a,b,c,d,f,g,l){if(w)return H(8,1,a,b,c,d,f,g,l)}var Cf={},pb=()=>performance.timeOrigin+performance.now(); +function lb(a,b){if(w)return H(9,1,a,b);Cf[a]&&(clearTimeout(Cf[a].id),delete Cf[a]);if(!b)return 0;var c=setTimeout(()=>{delete Cf[a];yf(()=>Df(a,performance.timeOrigin+performance.now()))},b);Cf[a]={id:c,ua:b};return 0} +var J=(a,b,c)=>{var d=n();if(0=l){var m=a.charCodeAt(++g);l=65536+((l&1023)<<10)|m&1023}if(127>=l){if(b>=c)break;d[b++]=l}else{if(2047>=l){if(b+1>=c)break;d[b++]=192|l>>6}else{if(65535>=l){if(b+2>=c)break;d[b++]=224|l>>12}else{if(b+3>=c)break;d[b++]=240|l>>18;d[b++]=128|l>>12&63}d[b++]=128|l>>6&63}d[b++]=128|l&63}}d[b]=0;a=b-f}else a=0;return a},mb=(a,b,c,d)=>{var f=(new Date).getFullYear(),g=(new Date(f,0,1)).getTimezoneOffset(); +f=(new Date(f,6,1)).getTimezoneOffset();var l=Math.max(g,f);t()[a>>2]=60*l;q()[b>>2]=Number(g!=f);b=m=>{var p=Math.abs(m);return`UTC${0<=m?"-":"+"}${String(Math.floor(p/60)).padStart(2,"0")}${String(p%60).padStart(2,"0")}`};a=b(g);b=b(f);f{},ob=()=>{D+=1;throw"unwind";},K,Ef=a=>{var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=(c,d)=>b.vertexAttribDivisorANGLE(c,d),a.drawArraysInstanced=(c,d,f,g)=>b.drawArraysInstancedANGLE(c, +d,f,g),a.drawElementsInstanced=(c,d,f,g,l)=>b.drawElementsInstancedANGLE(c,d,f,g,l))},Ff=a=>{var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray=()=>b.createVertexArrayOES(),a.deleteVertexArray=c=>b.deleteVertexArrayOES(c),a.bindVertexArray=c=>b.bindVertexArrayOES(c),a.isVertexArray=c=>b.isVertexArrayOES(c))},Gf=a=>{var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=(c,d)=>b.drawBuffersWEBGL(c,d))},Hf=a=>{a.O=a.getExtension("WEBGL_draw_instanced_base_vertex_base_instance")}, +If=a=>{a.S=a.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance")},Jf=a=>{var b="ANGLE_instanced_arrays EXT_blend_minmax EXT_disjoint_timer_query EXT_frag_depth EXT_shader_texture_load EXT_sRGB OES_element_index_uint OES_fbo_render_mipmap OES_standard_derivatives OES_texture_float OES_texture_half_float OES_texture_half_float_linear OES_vertex_array_object WEBGL_color_buffer_float WEBGL_depth_texture WEBGL_draw_buffers EXT_color_buffer_float EXT_conservative_depth EXT_disjoint_timer_query_webgl2 EXT_texture_norm16 NV_shader_noperspective_interpolation WEBGL_clip_cull_distance EXT_clip_control EXT_color_buffer_half_float EXT_depth_clamp EXT_float_blend EXT_polygon_offset_clamp EXT_texture_compression_bptc EXT_texture_compression_rgtc EXT_texture_filter_anisotropic KHR_parallel_shader_compile OES_texture_float_linear WEBGL_blend_func_extended WEBGL_compressed_texture_astc WEBGL_compressed_texture_etc WEBGL_compressed_texture_etc1 WEBGL_compressed_texture_s3tc WEBGL_compressed_texture_s3tc_srgb WEBGL_debug_renderer_info WEBGL_debug_shaders WEBGL_lose_context WEBGL_multi_draw WEBGL_polygon_mode".split(" "); +return(a.getSupportedExtensions()||[]).filter(c=>b.includes(c))},Kf=1,Lf=[],L=[],Mf=[],Nf=[],M=[],N=[],Of=[],Pf={},mf={},O=[],P=[],Q=[],Qf={},Rf={},Sf=4,Tf=0,Uf=a=>{for(var b=Kf++,c=a.length;c{for(var f=0;f>2]=l}},Wf=a=>{var b={R:2,alpha:!0,depth:!0,stencil:!0,antialias:!1,premultipliedAlpha:!0,preserveDrawingBuffer:!1,powerPreference:"default",failIfMajorPerformanceCaveat:!1,P:!0};a.A|| +(a.A=a.getContext,a.getContext=function(d,f){f=a.A(d,f);return"webgl"==d==f instanceof WebGLRenderingContext?f:null});var c=1{var c=xf(8);t()[c+4>>2]=ya();var d={handle:c,attributes:b,version:b.R,D:a};a.canvas&&(a.canvas.sa=d);Pf[c]=d;("undefined"==typeof b.P||b.P)&&Xf(d);return c},Xf=a=>{a||=T;if(!a.ea){a.ea=!0;var b=a.D;b.fa=b.getExtension("WEBGL_multi_draw");b.aa=b.getExtension("EXT_polygon_offset_clamp");b.$=b.getExtension("EXT_clip_control"); +b.ra=b.getExtension("WEBGL_polygon_mode");Ef(b);Ff(b);Gf(b);Hf(b);If(b);2<=a.version&&(b.h=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.h)b.h=b.getExtension("EXT_disjoint_timer_query");Jf(b).forEach(c=>{c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}},lf={},R,T,qb=a=>K.activeTexture(a),rb=(a,b)=>{K.attachShader(L[a],N[b])},sb=(a,b)=>{K.beginQuery(a,O[b])},tb=(a,b)=>{K.h.beginQueryEXT(a,O[b])},ub=(a,b,c)=>{K.bindAttribLocation(L[a],b,wf(c))},vb=(a,b)=> +{35051==a?K.K=b:35052==a&&(K.v=b);K.bindBuffer(a,Lf[b])},wb=(a,b)=>{K.bindFramebuffer(a,Mf[b])},xb=(a,b)=>{K.bindRenderbuffer(a,Nf[b])},yb=(a,b)=>{K.bindSampler(a,P[b])},zb=(a,b)=>{K.bindTexture(a,M[b])},Ab=a=>{K.bindVertexArray(Of[a])},Bb=(a,b,c,d)=>K.blendColor(a,b,c,d),Cb=a=>K.blendEquation(a),Db=(a,b)=>K.blendFunc(a,b),Eb=(a,b,c,d,f,g,l,m,p,r)=>K.blitFramebuffer(a,b,c,d,f,g,l,m,p,r),Fb=(a,b,c,d)=>{2<=T.version?c&&b?K.bufferData(a,n(),d,c,b):K.bufferData(a,b,d):K.bufferData(a,c?n().subarray(c, +c+b):b,d)},Gb=(a,b,c,d)=>{2<=T.version?c&&K.bufferSubData(a,b,n(),d,c):K.bufferSubData(a,b,n().subarray(d,d+c))},Hb=a=>K.checkFramebufferStatus(a),Ib=a=>K.clear(a),Jb=(a,b,c,d)=>K.clearColor(a,b,c,d),Kb=a=>K.clearStencil(a),Lb=(a,b,c,d)=>K.clientWaitSync(Q[a],b,(c>>>0)+4294967296*d),Mb=(a,b,c,d)=>{K.colorMask(!!a,!!b,!!c,!!d)},Nb=a=>{K.compileShader(N[a])},Ob=(a,b,c,d,f,g,l,m)=>{2<=T.version?K.v||!l?K.compressedTexImage2D(a,b,c,d,f,g,l,m):K.compressedTexImage2D(a,b,c,d,f,g,n(),m,l):K.compressedTexImage2D(a, +b,c,d,f,g,n().subarray(m,m+l))},Pb=(a,b,c,d,f,g,l,m,p)=>{2<=T.version?K.v||!m?K.compressedTexSubImage2D(a,b,c,d,f,g,l,m,p):K.compressedTexSubImage2D(a,b,c,d,f,g,l,n(),p,m):K.compressedTexSubImage2D(a,b,c,d,f,g,l,n().subarray(p,p+m))},Qb=(a,b,c,d,f)=>K.copyBufferSubData(a,b,c,d,f),Rb=(a,b,c,d,f,g,l,m)=>K.copyTexSubImage2D(a,b,c,d,f,g,l,m),Sb=()=>{var a=Uf(L),b=K.createProgram();b.name=a;b.H=b.F=b.G=0;b.N=1;L[a]=b;return a},Tb=a=>{var b=Uf(N);N[b]=K.createShader(a);return b},Ub=a=>K.cullFace(a),Vb= +(a,b)=>{for(var c=0;c>2],f=Lf[d];f&&(K.deleteBuffer(f),f.name=0,Lf[d]=null,d==K.K&&(K.K=0),d==K.v&&(K.v=0))}},Wb=(a,b)=>{for(var c=0;c>2],f=Mf[d];f&&(K.deleteFramebuffer(f),f.name=0,Mf[d]=null)}},Xb=a=>{if(a){var b=L[a];b?(K.deleteProgram(b),b.name=0,L[a]=null):R||=1281}},Yb=(a,b)=>{for(var c=0;c>2],f=O[d];f&&(K.deleteQuery(f),O[d]=null)}},Zb=(a,b)=>{for(var c=0;c>2],f=O[d];f&&(K.h.deleteQueryEXT(f),O[d]= +null)}},$b=(a,b)=>{for(var c=0;c>2],f=Nf[d];f&&(K.deleteRenderbuffer(f),f.name=0,Nf[d]=null)}},ac=(a,b)=>{for(var c=0;c>2],f=P[d];f&&(K.deleteSampler(f),f.name=0,P[d]=null)}},bc=a=>{if(a){var b=N[a];b?(K.deleteShader(b),N[a]=null):R||=1281}},cc=a=>{if(a){var b=Q[a];b?(K.deleteSync(b),b.name=0,Q[a]=null):R||=1281}},dc=(a,b)=>{for(var c=0;c>2],f=M[d];f&&(K.deleteTexture(f),f.name=0,M[d]=null)}},ec=(a,b)=>{for(var c=0;c>2];K.deleteVertexArray(Of[d]);Of[d]=null}},fc=a=>{K.depthMask(!!a)},gc=a=>K.disable(a),hc=a=>{K.disableVertexAttribArray(a)},ic=(a,b,c)=>{K.drawArrays(a,b,c)},jc=(a,b,c,d)=>{K.drawArraysInstanced(a,b,c,d)},kc=(a,b,c,d,f)=>{K.O.drawArraysInstancedBaseInstanceWEBGL(a,b,c,d,f)},Yf=[],lc=(a,b)=>{for(var c=Yf[a],d=0;d>2];K.drawBuffers(c)},mc=(a,b,c,d)=>{K.drawElements(a,b,c,d)},nc=(a,b,c,d,f)=>{K.drawElementsInstanced(a,b,c,d,f)},oc=(a,b,c,d,f,g,l)=>{K.O.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a, +b,c,d,f,g,l)},pc=(a,b,c,d,f,g)=>{K.drawElements(a,d,f,g)},qc=a=>K.enable(a),rc=a=>{K.enableVertexAttribArray(a)},sc=a=>K.endQuery(a),tc=a=>{K.h.endQueryEXT(a)},uc=(a,b)=>(a=K.fenceSync(a,b))?(b=Uf(Q),a.name=b,Q[b]=a,b):0,vc=()=>K.finish(),wc=()=>K.flush(),xc=(a,b,c,d)=>{K.framebufferRenderbuffer(a,b,c,Nf[d])},yc=(a,b,c,d,f)=>{K.framebufferTexture2D(a,b,c,M[d],f)},zc=a=>K.frontFace(a),Ac=(a,b)=>{S(a,b,"createBuffer",Lf)},Bc=(a,b)=>{S(a,b,"createFramebuffer",Mf)},Cc=(a,b)=>{S(a,b,"createQuery",O)}, +Dc=(a,b)=>{for(var c=0;c>2]=0;break}var f=Uf(O);d.name=f;O[f]=d;q()[b+4*c>>2]=f}},Ec=(a,b)=>{S(a,b,"createRenderbuffer",Nf)},Fc=(a,b)=>{S(a,b,"createSampler",P)},Gc=(a,b)=>{S(a,b,"createTexture",M)},Hc=(a,b)=>{S(a,b,"createVertexArray",Of)},Ic=a=>K.generateMipmap(a),Jc=(a,b,c)=>{c?q()[c>>2]=K.getBufferParameter(a,b):R||=1281},Kc=()=>{var a=K.getError()||R;R=0;return a},Zf=(a,b)=>{t()[a>>2]=b;var c=t()[a>>2];t()[a+4>>2]=(b-c)/ +4294967296};function $f(){var a=Jf(K);return a=a.concat(a.map(b=>"GL_"+b))} +var ag=(a,b,c)=>{if(b){var d=void 0;switch(a){case 36346:d=1;break;case 36344:0!=c&&1!=c&&(R||=1280);return;case 34814:case 36345:d=0;break;case 34466:var f=K.getParameter(34467);d=f?f.length:0;break;case 33309:if(2>T.version){R||=1282;return}d=$f().length;break;case 33307:case 33308:if(2>T.version){R||=1280;return}d=33307==a?3:0}if(void 0===d)switch(f=K.getParameter(a),typeof f){case "number":d=f;break;case "boolean":d=f?1:0;break;case "string":R||=1280;return;case "object":if(null===f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:d= +0;break;default:R||=1280;return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a>2]=f[a];break;case 2:u()[b+4*a>>2]=f[a];break;case 4:aa()[b+a]=f[a]?1:0}return}try{d=f.name|0}catch(g){R||=1280;y(`GL_INVALID_ENUM in glGet${c}v: Unknown object returned from WebGL getParameter(${a})! (error: ${g})`);return}}break;default:R||=1280;y(`GL_INVALID_ENUM in glGet${c}v: Native code calling glGet${c}v(${a}) and it returns ${f} of type ${typeof f}!`); +return}switch(c){case 1:Zf(b,d);break;case 0:q()[b>>2]=d;break;case 2:u()[b>>2]=d;break;case 4:aa()[b]=d?1:0}}else R||=1281},Lc=(a,b)=>ag(a,b,2),Mc=(a,b,c,d)=>{a=K.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer||a instanceof WebGLTexture)a=a.name|0;q()[d>>2]=a},Nc=(a,b)=>ag(a,b,0),Oc=(a,b,c,d)=>{a=K.getProgramInfoLog(L[a]);null===a&&(a="(unknown error)");b=0>2]=b)},Pc=(a,b,c)=>{if(c)if(a>=Kf)R||=1281;else if(a=L[a],35716==b)a=K.getProgramInfoLog(a), +null===a&&(a="(unknown error)"),q()[c>>2]=a.length+1;else if(35719==b){if(!a.H){var d=K.getProgramParameter(a,35718);for(b=0;b>2]=a.H}else if(35722==b){if(!a.F)for(d=K.getProgramParameter(a,35721),b=0;b>2]=a.F}else if(35381==b){if(!a.G)for(d=K.getProgramParameter(a,35382),b=0;b>2]=a.G}else q()[c>> +2]=K.getProgramParameter(a,b);else R||=1281},Qc=(a,b,c)=>{if(c){a=O[a];b=2>T.version?K.h.getQueryObjectEXT(a,b):K.getQueryParameter(a,b);var d;"boolean"==typeof b?d=b?1:0:d=b;Zf(c,d)}else R||=1281},Rc=(a,b,c)=>{if(c){a=K.getQueryParameter(O[a],b);var d;"boolean"==typeof a?d=a?1:0:d=a;q()[c>>2]=d}else R||=1281},Sc=(a,b,c)=>{if(c){a=K.h.getQueryObjectEXT(O[a],b);var d;"boolean"==typeof a?d=a?1:0:d=a;q()[c>>2]=d}else R||=1281},Tc=(a,b,c)=>{c?q()[c>>2]=K.getQuery(a,b):R||=1281},Uc=(a,b,c)=>{c?q()[c>> +2]=K.h.getQueryEXT(a,b):R||=1281},Vc=(a,b,c)=>{c?q()[c>>2]=K.getRenderbufferParameter(a,b):R||=1281},Wc=(a,b,c,d)=>{a=K.getShaderInfoLog(N[a]);null===a&&(a="(unknown error)");b=0>2]=b)},Xc=(a,b,c,d)=>{a=K.getShaderPrecisionFormat(a,b);q()[c>>2]=a.rangeMin;q()[c+4>>2]=a.rangeMax;q()[d>>2]=a.precision},Yc=(a,b,c)=>{c?35716==b?(a=K.getShaderInfoLog(N[a]),null===a&&(a="(unknown error)"),a=a?a.length+1:0,q()[c>>2]=a):35720==b?(a=(a=K.getShaderSource(N[a]))?a.length+1:0,q()[c>> +2]=a):q()[c>>2]=K.getShaderParameter(N[a],b):R||=1281},bg=a=>{for(var b=0,c=0;c=d?b++:2047>=d?b+=2:55296<=d&&57343>=d?(b+=4,++c):b+=3}b+=1;(c=xf(b))&&J(a,c,b);return c},Zc=a=>{var b=Qf[a];if(!b){switch(a){case 7939:b=bg($f().join(" "));break;case 7936:case 7937:case 37445:case 37446:(b=K.getParameter(a))||(R||=1280);b=b?bg(b):0;break;case 7938:b=K.getParameter(7938);var c=`OpenGL ES 2.0 (${b})`;2<=T.version&&(c=`OpenGL ES 3.0 (${b})`);b=bg(c);break;case 35724:b= +K.getParameter(35724);c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b=`OpenGL ES GLSL ES ${c[1]} (${b})`);b=bg(b);break;default:R||=1280}Qf[a]=b}return b},$c=(a,b)=>{if(2>T.version)return R||=1282,0;var c=Rf[a];if(c)return 0>b||b>=c.length?(R||=1281,0):c[b];switch(a){case 7939:return c=$f().map(bg),c=Rf[a]=c,0>b||b>=c.length?(R||=1281,0):c[b];default:return R||=1280,0}},cg=a=>"]"==a.slice(-1)&&a.lastIndexOf("["),ad=(a,b)=>{b=wf(b);if(a=L[a]){var c= +a,d=c.C,f=c.W,g;if(!d){c.C=d={};c.V={};var l=K.getProgramParameter(c,35718);for(g=0;g>>0,f=b.slice(0,g));if((f=a.W[f])&&d{for(var d=Yf[b],f=0;f>2];K.invalidateFramebuffer(a, +d)},cd=(a,b,c,d,f,g,l)=>{for(var m=Yf[b],p=0;p>2];K.invalidateSubFramebuffer(a,m,d,f,g,l)},dd=a=>K.isSync(Q[a]),ed=a=>(a=M[a])?K.isTexture(a):0,fd=a=>K.lineWidth(a),gd=a=>{a=L[a];K.linkProgram(a);a.C=0;a.W={}},hd=(a,b,c,d,f,g)=>{K.S.multiDrawArraysInstancedBaseInstanceWEBGL(a,q(),b>>2,q(),c>>2,q(),d>>2,t(),f>>2,g)},jd=(a,b,c,d,f,g,l,m)=>{K.S.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,q(),b>>2,c,q(),d>>2,q(),f>>2,q(),g>>2,t(),l>>2,m)},kd=(a,b)=>{3317==a?Sf=b:3314== +a&&(Tf=b);K.pixelStorei(a,b)},ld=(a,b)=>{K.h.queryCounterEXT(O[a],b)},md=a=>K.readBuffer(a),dg=a=>{a-=5120;0==a?a=aa():1==a?a=n():2==a?(e.buffer!=h.buffer&&k(),a=ua):4==a?a=q():6==a?a=u():5==a||28922==a||28520==a||30779==a||30782==a?a=t():(e.buffer!=h.buffer&&k(),a=va);return a},eg=(a,b,c,d,f)=>{a=dg(a);b=d*((Tf||c)*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*a.BYTES_PER_ELEMENT+Sf-1&-Sf);return a.subarray(f>>>31-Math.clz32(a.BYTES_PER_ELEMENT),f+b>>>31-Math.clz32(a.BYTES_PER_ELEMENT))}, +and=(a,b,c,d,f,g,l)=>{if(2<=T.version)if(K.K)K.readPixels(a,b,c,d,f,g,l);else{var m=dg(g);l>>>=31-Math.clz32(m.BYTES_PER_ELEMENT);K.readPixels(a,b,c,d,f,g,m,l)}else(m=eg(g,f,c,d,l))?K.readPixels(a,b,c,d,f,g,m):R||=1280},od=(a,b,c,d)=>K.renderbufferStorage(a,b,c,d),pd=(a,b,c,d,f)=>K.renderbufferStorageMultisample(a,b,c,d,f),qd=(a,b,c)=>{K.samplerParameterf(P[a],b,c)},rd=(a,b,c)=>{K.samplerParameteri(P[a],b,c)},sd=(a,b,c)=>{c=q()[c>>2];K.samplerParameteri(P[a],b,c)},td=(a,b,c,d)=>K.scissor(a,b,c,d), +ud=(a,b,c,d)=>{for(var f="",g=0;g>2]:void 0;f+=wf(t()[c+4*g>>2],l)}K.shaderSource(N[a],f)},vd=(a,b,c)=>K.stencilFunc(a,b,c),wd=(a,b,c,d)=>K.stencilFuncSeparate(a,b,c,d),xd=a=>K.stencilMask(a),yd=(a,b)=>K.stencilMaskSeparate(a,b),zd=(a,b,c)=>K.stencilOp(a,b,c),Ad=(a,b,c,d)=>K.stencilOpSeparate(a,b,c,d),Bd=(a,b,c,d,f,g,l,m,p)=>{if(2<=T.version){if(K.v){K.texImage2D(a,b,c,d,f,g,l,m,p);return}if(p){var r=dg(m);p>>>=31-Math.clz32(r.BYTES_PER_ELEMENT);K.texImage2D(a,b,c,d,f,g, +l,m,r,p);return}}r=p?eg(m,l,d,f,p):null;K.texImage2D(a,b,c,d,f,g,l,m,r)},Cd=(a,b,c)=>K.texParameterf(a,b,c),Dd=(a,b,c)=>{c=u()[c>>2];K.texParameterf(a,b,c)},Ed=(a,b,c)=>K.texParameteri(a,b,c),Fd=(a,b,c)=>{c=q()[c>>2];K.texParameteri(a,b,c)},Gd=(a,b,c,d,f)=>K.texStorage2D(a,b,c,d,f),Hd=(a,b,c,d,f,g,l,m,p)=>{if(2<=T.version){if(K.v){K.texSubImage2D(a,b,c,d,f,g,l,m,p);return}if(p){var r=dg(m);K.texSubImage2D(a,b,c,d,f,g,l,m,r,p>>>31-Math.clz32(r.BYTES_PER_ELEMENT));return}}p=p?eg(m,l,f,g,p):null;K.texSubImage2D(a, +b,c,d,f,g,l,m,p)},U=a=>{var b=K.Z;if(b){var c=b.C[a];"number"==typeof c&&(b.C[a]=c=K.getUniformLocation(b,b.V[a]+(0{K.uniform1f(U(a),b)},V=[],Jd=(a,b,c)=>{if(2<=T.version)b&&K.uniform1fv(U(a),u(),c>>2,b);else{if(288>=b)for(var d=V[b],f=0;f>2];else d=u().subarray(c>>2,c+4*b>>2);K.uniform1fv(U(a),d)}},Kd=(a,b)=>{K.uniform1i(U(a),b)},fg=[],Ld=(a,b,c)=>{if(2<=T.version)b&&K.uniform1iv(U(a),q(),c>>2,b);else{if(288>=b)for(var d=fg[b], +f=0;f>2];else d=q().subarray(c>>2,c+4*b>>2);K.uniform1iv(U(a),d)}},Md=(a,b,c)=>{K.uniform2f(U(a),b,c)},And=(a,b,c)=>{if(2<=T.version)b&&K.uniform2fv(U(a),u(),c>>2,2*b);else{if(144>=b){b*=2;for(var d=V[b],f=0;f>2],d[f+1]=u()[c+(4*f+4)>>2]}else d=u().subarray(c>>2,c+8*b>>2);K.uniform2fv(U(a),d)}},Od=(a,b,c)=>{K.uniform2i(U(a),b,c)},Pd=(a,b,c)=>{if(2<=T.version)b&&K.uniform2iv(U(a),q(),c>>2,2*b);else{if(144>=b){b*=2;for(var d=fg[b],f=0;f>2],d[f+1]=q()[c+(4*f+4)>>2]}else d=q().subarray(c>>2,c+8*b>>2);K.uniform2iv(U(a),d)}},Qd=(a,b,c,d)=>{K.uniform3f(U(a),b,c,d)},Rd=(a,b,c)=>{if(2<=T.version)b&&K.uniform3fv(U(a),u(),c>>2,3*b);else{if(96>=b){b*=3;for(var d=V[b],f=0;f>2],d[f+1]=u()[c+(4*f+4)>>2],d[f+2]=u()[c+(4*f+8)>>2]}else d=u().subarray(c>>2,c+12*b>>2);K.uniform3fv(U(a),d)}},Sd=(a,b,c,d)=>{K.uniform3i(U(a),b,c,d)},Td=(a,b,c)=>{if(2<=T.version)b&&K.uniform3iv(U(a),q(),c>>2,3*b);else{if(96>=b){b*=3;for(var d= +fg[b],f=0;f>2],d[f+1]=q()[c+(4*f+4)>>2],d[f+2]=q()[c+(4*f+8)>>2]}else d=q().subarray(c>>2,c+12*b>>2);K.uniform3iv(U(a),d)}},Ud=(a,b,c,d,f)=>{K.uniform4f(U(a),b,c,d,f)},Vd=(a,b,c)=>{if(2<=T.version)b&&K.uniform4fv(U(a),u(),c>>2,4*b);else{if(72>=b){var d=V[4*b],f=u();c>>=2;b*=4;for(var g=0;g>2,c+16*b>>2);K.uniform4fv(U(a),d)}},Wd=(a,b,c,d,f)=>{K.uniform4i(U(a),b,c,d,f)},Xd=(a,b,c)=>{if(2<= +T.version)b&&K.uniform4iv(U(a),q(),c>>2,4*b);else{if(72>=b){b*=4;for(var d=fg[b],f=0;f>2],d[f+1]=q()[c+(4*f+4)>>2],d[f+2]=q()[c+(4*f+8)>>2],d[f+3]=q()[c+(4*f+12)>>2]}else d=q().subarray(c>>2,c+16*b>>2);K.uniform4iv(U(a),d)}},Yd=(a,b,c,d)=>{if(2<=T.version)b&&K.uniformMatrix2fv(U(a),!!c,u(),d>>2,4*b);else{if(72>=b){b*=4;for(var f=V[b],g=0;g>2],f[g+1]=u()[d+(4*g+4)>>2],f[g+2]=u()[d+(4*g+8)>>2],f[g+3]=u()[d+(4*g+12)>>2]}else f=u().subarray(d>>2,d+16*b>>2); +K.uniformMatrix2fv(U(a),!!c,f)}},Zd=(a,b,c,d)=>{if(2<=T.version)b&&K.uniformMatrix3fv(U(a),!!c,u(),d>>2,9*b);else{if(32>=b){b*=9;for(var f=V[b],g=0;g>2],f[g+1]=u()[d+(4*g+4)>>2],f[g+2]=u()[d+(4*g+8)>>2],f[g+3]=u()[d+(4*g+12)>>2],f[g+4]=u()[d+(4*g+16)>>2],f[g+5]=u()[d+(4*g+20)>>2],f[g+6]=u()[d+(4*g+24)>>2],f[g+7]=u()[d+(4*g+28)>>2],f[g+8]=u()[d+(4*g+32)>>2]}else f=u().subarray(d>>2,d+36*b>>2);K.uniformMatrix3fv(U(a),!!c,f)}},$d=(a,b,c,d)=>{if(2<=T.version)b&&K.uniformMatrix4fv(U(a), +!!c,u(),d>>2,16*b);else{if(18>=b){var f=V[16*b],g=u();d>>=2;b*=16;for(var l=0;l>2,d+64*b>>2);K.uniformMatrix4fv(U(a),!!c,f)}},ae=a=>{a=L[a];K.useProgram(a);K.Z=a},be=(a,b)=>K.vertexAttrib1f(a,b),ce=(a,b)=>{K.vertexAttrib2f(a,u()[b>> +2],u()[b+4>>2])},de=(a,b)=>{K.vertexAttrib3f(a,u()[b>>2],u()[b+4>>2],u()[b+8>>2])},ee=(a,b)=>{K.vertexAttrib4f(a,u()[b>>2],u()[b+4>>2],u()[b+8>>2],u()[b+12>>2])},fe=(a,b)=>{K.vertexAttribDivisor(a,b)},ge=(a,b,c,d,f)=>{K.vertexAttribIPointer(a,b,c,d,f)},he=(a,b,c,d,f,g)=>{K.vertexAttribPointer(a,b,c,!!d,f,g)},ie=(a,b,c,d)=>K.viewport(a,b,c,d),je=(a,b,c,d)=>{K.waitSync(Q[a],b,(c>>>0)+4294967296*d)},ke=a=>{var b=n().length;a>>>=0;if(a<=b||2147483648=c;c*=2){var d=b*(1+.2/c); +d=Math.min(d,a+100663296);a:{d=(Math.min(2147483648,65536*Math.ceil(Math.max(a,d)/65536))-e.buffer.byteLength+65535)/65536|0;try{e.grow(d);k();var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1}; +function le(a,b){a=Pf[a];b=wf(b);b.startsWith("GL_")&&(b=b.substr(3));"ANGLE_instanced_arrays"==b&&Ef(K);"OES_vertex_array_object"==b&&Ff(K);"WEBGL_draw_buffers"==b&&Gf(K);"WEBGL_draw_instanced_base_vertex_base_instance"==b&&Hf(K);"WEBGL_multi_draw_instanced_base_vertex_base_instance"==b&&If(K);"WEBGL_multi_draw"==b&&(K.fa=K.getExtension("WEBGL_multi_draw"));"EXT_polygon_offset_clamp"==b&&(K.aa=K.getExtension("EXT_polygon_offset_clamp"));"EXT_clip_control"==b&&(K.$=K.getExtension("EXT_clip_control")); +"WEBGL_polygon_mode"==b&&(K.ra=K.getExtension("WEBGL_polygon_mode"));return!!a.D.getExtension(b)} +var me=()=>T?T.handle:0,ne=a=>{T=Pf[a];v.ta=K=T?.D;return!a||K?0:-5},gg={},ig=()=>{if(!hg){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:"./this.program"},b;for(b in gg)void 0===gg[b]?delete a[b]:a[b]=gg[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);hg=c}return hg},hg; +function oe(a,b){if(w)return H(10,1,a,b);var c=0;ig().forEach((d,f)=>{var g=b+c;f=t()[a+4*f>>2]=g;for(g=0;g>2]=c.length;var d=0;c.forEach(f=>d+=f.length+1);t()[b>>2]=d;return 0}function re(a){return w?H(12,1,a):52}function se(a,b,c,d,f,g){return w?H(13,1,a,b,c,d,f,g):52}function te(a,b,c,d){return w?H(14,1,a,b,c,d):52} +function ue(a,b,c,d,f){return w?H(15,1,a,b,c,d,f):70}var jg=[null,[],[]];function ve(a,b,c,d){if(w)return H(16,1,a,b,c,d);for(var f=0,g=0;g>2],m=t()[b+4>>2];b+=8;for(var p=0;p>2]=f;return 0}function kg(){}function lg(){}function W(){}function He(){}function Ie(){}function Je(){}function Ke(){}function Le(){}function Me(){}function Ne(){}function Oe(){}function Pe(){} +function Qe(){}function Re(){}function Se(){}function Te(){}var mg,ng=[];w||gf();for(var X=0;32>X;++X)Yf.push(Array(X));var og=new Float32Array(288);for(X=0;288>=X;++X)V[X]=og.subarray(0,X);var pg=new Int32Array(288);for(X=0;288>=X;++X)fg[X]=pg.subarray(0,X); +(function(){const a=new Map,b=new Map;Te=function(c,d,f){W({m:"setAssociatedObject",M:d,object:f},[f],c)};Pe=function(c){return b.get(c)};Ie=function(c){kg(c,function(d){var f=d.m;if(f)switch(f){case "renderPictures":qg(d.o,d.ha,d.ga,d.s,lg());break;case "onRenderComplete":sg(d.o,d.s,{imageBitmaps:d.da,rasterStartMilliseconds:d.ja,rasterEndMilliseconds:d.ia});break;case "setAssociatedObject":b.set(d.M,d.object);break;case "disposeAssociatedObject":d=d.M;f=b.get(d);f.close&&f.close();b.delete(d);break; +case "disposeSurface":tg(d.o);break;case "rasterizeImage":ug(d.o,d.image,d.format,d.s);break;case "onRasterizeComplete":vg(d.o,d.data,d.s);break;default:console.warn(`unrecognized skwasm message: ${f}`)}})};Ne=function(c,d,f,g,l){W({m:"renderPictures",o:d,ha:f,ga:g,s:l},[],c)};Ke=function(c,d){c=new OffscreenCanvas(c,d);d=Wf(c);a.set(d,c);return d};Re=function(c,d,f){c=a.get(c);c.width=d;c.height=f};He=function(c,d,f,g){g||=[];c=a.get(c);g.push(createImageBitmap(c,0,0,d,f));return g};Se=async function(c, +d,f,g){d=d?await Promise.all(d):[];W({m:"onRenderComplete",o:c,s:g,da:d,ja:f,ia:lg()},[...d])};Je=function(c,d,f){const g=T.D,l=g.createTexture();g.bindTexture(g.TEXTURE_2D,l);g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);g.texImage2D(g.TEXTURE_2D,0,g.RGBA,d,f,0,g.RGBA,g.UNSIGNED_BYTE,c);g.pixelStorei(g.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);g.bindTexture(g.TEXTURE_2D,null);c=Uf(M);M[c]=l;return c};Oe=function(c,d){W({m:"disposeAssociatedObject",M:d},[],c)};Le=function(c,d){W({m:"disposeSurface", +o:d},[],c)};Me=function(c,d,f,g,l){W({m:"rasterizeImage",o:d,image:f,format:g,s:l},[],c)};Qe=function(c,d,f){W({m:"onRasterizeComplete",o:c,data:d,s:f})}})(); +(function(){let a=0;kg=function(b,c){function d({data:f}){const g=f.m;g&&("syncTimeOrigin"==g?a=performance.timeOrigin-f.timeOrigin:c(f))}b?(B[b].addEventListener("message",d),B[b].postMessage({m:"syncTimeOrigin",timeOrigin:performance.timeOrigin})):addEventListener("message",d)};lg=function(){return performance.now()+a};W=function(b,c,d){d?B[d].postMessage(b,c):postMessage(b,c)}})(); +var Bf=[Ge,ef,tf,Xa,Ya,Za,$a,jb,kb,lb,oe,pe,re,se,te,ue,ve],Ua,Y=function(){function a(c,d){Y=c.exports;v.wasmExports=Y;ff.push(Y._emscripten_tls_init);I=Y.__indirect_function_table;Ja.unshift(Y.__wasm_call_ctors);ra=d;Na();return Y}var b=za();z++;if(v.instantiateWasm)try{return v.instantiateWasm(b,a)}catch(c){y(`Module.instantiateWasm callback failed with error: ${c}`),ja(c)}Qa??=Pa("skwasm.wasm")?"skwasm.wasm":x+"skwasm.wasm";Ta(b,function(c){a(c.instance,c.module)}).catch(ja);return{}}(); +v._canvas_saveLayer=(a,b,c,d,f)=>(v._canvas_saveLayer=Y.canvas_saveLayer)(a,b,c,d,f);v._canvas_save=a=>(v._canvas_save=Y.canvas_save)(a);v._canvas_restore=a=>(v._canvas_restore=Y.canvas_restore)(a);v._canvas_restoreToCount=(a,b)=>(v._canvas_restoreToCount=Y.canvas_restoreToCount)(a,b);v._canvas_getSaveCount=a=>(v._canvas_getSaveCount=Y.canvas_getSaveCount)(a);v._canvas_translate=(a,b,c)=>(v._canvas_translate=Y.canvas_translate)(a,b,c); +v._canvas_scale=(a,b,c)=>(v._canvas_scale=Y.canvas_scale)(a,b,c);v._canvas_rotate=(a,b)=>(v._canvas_rotate=Y.canvas_rotate)(a,b);v._canvas_skew=(a,b,c)=>(v._canvas_skew=Y.canvas_skew)(a,b,c);v._canvas_transform=(a,b)=>(v._canvas_transform=Y.canvas_transform)(a,b);v._canvas_clipRect=(a,b,c,d)=>(v._canvas_clipRect=Y.canvas_clipRect)(a,b,c,d);v._canvas_clipRRect=(a,b,c)=>(v._canvas_clipRRect=Y.canvas_clipRRect)(a,b,c);v._canvas_clipPath=(a,b,c)=>(v._canvas_clipPath=Y.canvas_clipPath)(a,b,c); +v._canvas_drawColor=(a,b,c)=>(v._canvas_drawColor=Y.canvas_drawColor)(a,b,c);v._canvas_drawLine=(a,b,c,d,f,g)=>(v._canvas_drawLine=Y.canvas_drawLine)(a,b,c,d,f,g);v._canvas_drawPaint=(a,b)=>(v._canvas_drawPaint=Y.canvas_drawPaint)(a,b);v._canvas_drawRect=(a,b,c)=>(v._canvas_drawRect=Y.canvas_drawRect)(a,b,c);v._canvas_drawRRect=(a,b,c)=>(v._canvas_drawRRect=Y.canvas_drawRRect)(a,b,c);v._canvas_drawDRRect=(a,b,c,d)=>(v._canvas_drawDRRect=Y.canvas_drawDRRect)(a,b,c,d); +v._canvas_drawOval=(a,b,c)=>(v._canvas_drawOval=Y.canvas_drawOval)(a,b,c);v._canvas_drawCircle=(a,b,c,d,f)=>(v._canvas_drawCircle=Y.canvas_drawCircle)(a,b,c,d,f);v._canvas_drawArc=(a,b,c,d,f,g)=>(v._canvas_drawArc=Y.canvas_drawArc)(a,b,c,d,f,g);v._canvas_drawPath=(a,b,c)=>(v._canvas_drawPath=Y.canvas_drawPath)(a,b,c);v._canvas_drawShadow=(a,b,c,d,f,g)=>(v._canvas_drawShadow=Y.canvas_drawShadow)(a,b,c,d,f,g); +v._canvas_drawParagraph=(a,b,c,d)=>(v._canvas_drawParagraph=Y.canvas_drawParagraph)(a,b,c,d);v._canvas_drawPicture=(a,b)=>(v._canvas_drawPicture=Y.canvas_drawPicture)(a,b);v._canvas_drawImage=(a,b,c,d,f,g)=>(v._canvas_drawImage=Y.canvas_drawImage)(a,b,c,d,f,g);v._canvas_drawImageRect=(a,b,c,d,f,g)=>(v._canvas_drawImageRect=Y.canvas_drawImageRect)(a,b,c,d,f,g);v._canvas_drawImageNine=(a,b,c,d,f,g)=>(v._canvas_drawImageNine=Y.canvas_drawImageNine)(a,b,c,d,f,g); +v._canvas_drawVertices=(a,b,c,d)=>(v._canvas_drawVertices=Y.canvas_drawVertices)(a,b,c,d);v._canvas_drawPoints=(a,b,c,d,f)=>(v._canvas_drawPoints=Y.canvas_drawPoints)(a,b,c,d,f);v._canvas_drawAtlas=(a,b,c,d,f,g,l,m,p)=>(v._canvas_drawAtlas=Y.canvas_drawAtlas)(a,b,c,d,f,g,l,m,p);v._canvas_getTransform=(a,b)=>(v._canvas_getTransform=Y.canvas_getTransform)(a,b);v._canvas_getLocalClipBounds=(a,b)=>(v._canvas_getLocalClipBounds=Y.canvas_getLocalClipBounds)(a,b); +v._canvas_getDeviceClipBounds=(a,b)=>(v._canvas_getDeviceClipBounds=Y.canvas_getDeviceClipBounds)(a,b);v._contourMeasureIter_create=(a,b,c)=>(v._contourMeasureIter_create=Y.contourMeasureIter_create)(a,b,c);v._contourMeasureIter_next=a=>(v._contourMeasureIter_next=Y.contourMeasureIter_next)(a);v._contourMeasureIter_dispose=a=>(v._contourMeasureIter_dispose=Y.contourMeasureIter_dispose)(a);v._contourMeasure_dispose=a=>(v._contourMeasure_dispose=Y.contourMeasure_dispose)(a); +v._contourMeasure_length=a=>(v._contourMeasure_length=Y.contourMeasure_length)(a);v._contourMeasure_isClosed=a=>(v._contourMeasure_isClosed=Y.contourMeasure_isClosed)(a);v._contourMeasure_getPosTan=(a,b,c,d)=>(v._contourMeasure_getPosTan=Y.contourMeasure_getPosTan)(a,b,c,d);v._contourMeasure_getSegment=(a,b,c,d)=>(v._contourMeasure_getSegment=Y.contourMeasure_getSegment)(a,b,c,d);v._skData_create=a=>(v._skData_create=Y.skData_create)(a);v._skData_getPointer=a=>(v._skData_getPointer=Y.skData_getPointer)(a); +v._skData_getConstPointer=a=>(v._skData_getConstPointer=Y.skData_getConstPointer)(a);v._skData_getSize=a=>(v._skData_getSize=Y.skData_getSize)(a);v._skData_dispose=a=>(v._skData_dispose=Y.skData_dispose)(a);v._imageFilter_createBlur=(a,b,c)=>(v._imageFilter_createBlur=Y.imageFilter_createBlur)(a,b,c);v._imageFilter_createDilate=(a,b)=>(v._imageFilter_createDilate=Y.imageFilter_createDilate)(a,b);v._imageFilter_createErode=(a,b)=>(v._imageFilter_createErode=Y.imageFilter_createErode)(a,b); +v._imageFilter_createMatrix=(a,b)=>(v._imageFilter_createMatrix=Y.imageFilter_createMatrix)(a,b);v._imageFilter_createFromColorFilter=a=>(v._imageFilter_createFromColorFilter=Y.imageFilter_createFromColorFilter)(a);v._imageFilter_compose=(a,b)=>(v._imageFilter_compose=Y.imageFilter_compose)(a,b);v._imageFilter_dispose=a=>(v._imageFilter_dispose=Y.imageFilter_dispose)(a);v._imageFilter_getFilterBounds=(a,b)=>(v._imageFilter_getFilterBounds=Y.imageFilter_getFilterBounds)(a,b); +v._colorFilter_createMode=(a,b)=>(v._colorFilter_createMode=Y.colorFilter_createMode)(a,b);v._colorFilter_createMatrix=a=>(v._colorFilter_createMatrix=Y.colorFilter_createMatrix)(a);v._colorFilter_createSRGBToLinearGamma=()=>(v._colorFilter_createSRGBToLinearGamma=Y.colorFilter_createSRGBToLinearGamma)();v._colorFilter_createLinearToSRGBGamma=()=>(v._colorFilter_createLinearToSRGBGamma=Y.colorFilter_createLinearToSRGBGamma)(); +v._colorFilter_compose=(a,b)=>(v._colorFilter_compose=Y.colorFilter_compose)(a,b);v._colorFilter_dispose=a=>(v._colorFilter_dispose=Y.colorFilter_dispose)(a);v._maskFilter_createBlur=(a,b)=>(v._maskFilter_createBlur=Y.maskFilter_createBlur)(a,b);v._maskFilter_dispose=a=>(v._maskFilter_dispose=Y.maskFilter_dispose)(a);v._fontCollection_create=()=>(v._fontCollection_create=Y.fontCollection_create)();v._fontCollection_dispose=a=>(v._fontCollection_dispose=Y.fontCollection_dispose)(a); +v._typeface_create=a=>(v._typeface_create=Y.typeface_create)(a);v._typeface_dispose=a=>(v._typeface_dispose=Y.typeface_dispose)(a);v._typefaces_filterCoveredCodePoints=(a,b,c,d)=>(v._typefaces_filterCoveredCodePoints=Y.typefaces_filterCoveredCodePoints)(a,b,c,d);v._fontCollection_registerTypeface=(a,b,c)=>(v._fontCollection_registerTypeface=Y.fontCollection_registerTypeface)(a,b,c);v._fontCollection_clearCaches=a=>(v._fontCollection_clearCaches=Y.fontCollection_clearCaches)(a); +v._image_createFromPicture=(a,b,c)=>(v._image_createFromPicture=Y.image_createFromPicture)(a,b,c);v._image_createFromPixels=(a,b,c,d,f)=>(v._image_createFromPixels=Y.image_createFromPixels)(a,b,c,d,f);v._image_createFromTextureSource=(a,b,c,d)=>(v._image_createFromTextureSource=Y.image_createFromTextureSource)(a,b,c,d);v._image_ref=a=>(v._image_ref=Y.image_ref)(a);v._image_dispose=a=>(v._image_dispose=Y.image_dispose)(a);v._image_getWidth=a=>(v._image_getWidth=Y.image_getWidth)(a); +v._image_getHeight=a=>(v._image_getHeight=Y.image_getHeight)(a);v._paint_create=(a,b,c,d,f,g,l,m)=>(v._paint_create=Y.paint_create)(a,b,c,d,f,g,l,m);v._paint_dispose=a=>(v._paint_dispose=Y.paint_dispose)(a);v._paint_setShader=(a,b)=>(v._paint_setShader=Y.paint_setShader)(a,b);v._paint_setImageFilter=(a,b)=>(v._paint_setImageFilter=Y.paint_setImageFilter)(a,b);v._paint_setColorFilter=(a,b)=>(v._paint_setColorFilter=Y.paint_setColorFilter)(a,b); +v._paint_setMaskFilter=(a,b)=>(v._paint_setMaskFilter=Y.paint_setMaskFilter)(a,b);v._path_create=()=>(v._path_create=Y.path_create)();v._path_dispose=a=>(v._path_dispose=Y.path_dispose)(a);v._path_copy=a=>(v._path_copy=Y.path_copy)(a);v._path_setFillType=(a,b)=>(v._path_setFillType=Y.path_setFillType)(a,b);v._path_getFillType=a=>(v._path_getFillType=Y.path_getFillType)(a);v._path_moveTo=(a,b,c)=>(v._path_moveTo=Y.path_moveTo)(a,b,c); +v._path_relativeMoveTo=(a,b,c)=>(v._path_relativeMoveTo=Y.path_relativeMoveTo)(a,b,c);v._path_lineTo=(a,b,c)=>(v._path_lineTo=Y.path_lineTo)(a,b,c);v._path_relativeLineTo=(a,b,c)=>(v._path_relativeLineTo=Y.path_relativeLineTo)(a,b,c);v._path_quadraticBezierTo=(a,b,c,d,f)=>(v._path_quadraticBezierTo=Y.path_quadraticBezierTo)(a,b,c,d,f);v._path_relativeQuadraticBezierTo=(a,b,c,d,f)=>(v._path_relativeQuadraticBezierTo=Y.path_relativeQuadraticBezierTo)(a,b,c,d,f); +v._path_cubicTo=(a,b,c,d,f,g,l)=>(v._path_cubicTo=Y.path_cubicTo)(a,b,c,d,f,g,l);v._path_relativeCubicTo=(a,b,c,d,f,g,l)=>(v._path_relativeCubicTo=Y.path_relativeCubicTo)(a,b,c,d,f,g,l);v._path_conicTo=(a,b,c,d,f,g)=>(v._path_conicTo=Y.path_conicTo)(a,b,c,d,f,g);v._path_relativeConicTo=(a,b,c,d,f,g)=>(v._path_relativeConicTo=Y.path_relativeConicTo)(a,b,c,d,f,g);v._path_arcToOval=(a,b,c,d,f)=>(v._path_arcToOval=Y.path_arcToOval)(a,b,c,d,f); +v._path_arcToRotated=(a,b,c,d,f,g,l,m)=>(v._path_arcToRotated=Y.path_arcToRotated)(a,b,c,d,f,g,l,m);v._path_relativeArcToRotated=(a,b,c,d,f,g,l,m)=>(v._path_relativeArcToRotated=Y.path_relativeArcToRotated)(a,b,c,d,f,g,l,m);v._path_addRect=(a,b)=>(v._path_addRect=Y.path_addRect)(a,b);v._path_addOval=(a,b)=>(v._path_addOval=Y.path_addOval)(a,b);v._path_addArc=(a,b,c,d)=>(v._path_addArc=Y.path_addArc)(a,b,c,d);v._path_addPolygon=(a,b,c,d)=>(v._path_addPolygon=Y.path_addPolygon)(a,b,c,d); +v._path_addRRect=(a,b)=>(v._path_addRRect=Y.path_addRRect)(a,b);v._path_addPath=(a,b,c,d)=>(v._path_addPath=Y.path_addPath)(a,b,c,d);v._path_close=a=>(v._path_close=Y.path_close)(a);v._path_reset=a=>(v._path_reset=Y.path_reset)(a);v._path_contains=(a,b,c)=>(v._path_contains=Y.path_contains)(a,b,c);v._path_transform=(a,b)=>(v._path_transform=Y.path_transform)(a,b);v._path_getBounds=(a,b)=>(v._path_getBounds=Y.path_getBounds)(a,b);v._path_combine=(a,b,c)=>(v._path_combine=Y.path_combine)(a,b,c); +v._path_getSvgString=a=>(v._path_getSvgString=Y.path_getSvgString)(a);v._pictureRecorder_create=()=>(v._pictureRecorder_create=Y.pictureRecorder_create)();v._pictureRecorder_dispose=a=>(v._pictureRecorder_dispose=Y.pictureRecorder_dispose)(a);v._pictureRecorder_beginRecording=(a,b)=>(v._pictureRecorder_beginRecording=Y.pictureRecorder_beginRecording)(a,b);v._pictureRecorder_endRecording=a=>(v._pictureRecorder_endRecording=Y.pictureRecorder_endRecording)(a); +v._picture_getCullRect=(a,b)=>(v._picture_getCullRect=Y.picture_getCullRect)(a,b);v._picture_dispose=a=>(v._picture_dispose=Y.picture_dispose)(a);v._picture_approximateBytesUsed=a=>(v._picture_approximateBytesUsed=Y.picture_approximateBytesUsed)(a);v._shader_createLinearGradient=(a,b,c,d,f,g)=>(v._shader_createLinearGradient=Y.shader_createLinearGradient)(a,b,c,d,f,g);v._shader_createRadialGradient=(a,b,c,d,f,g,l,m)=>(v._shader_createRadialGradient=Y.shader_createRadialGradient)(a,b,c,d,f,g,l,m); +v._shader_createConicalGradient=(a,b,c,d,f,g,l,m)=>(v._shader_createConicalGradient=Y.shader_createConicalGradient)(a,b,c,d,f,g,l,m);v._shader_createSweepGradient=(a,b,c,d,f,g,l,m,p)=>(v._shader_createSweepGradient=Y.shader_createSweepGradient)(a,b,c,d,f,g,l,m,p);v._shader_dispose=a=>(v._shader_dispose=Y.shader_dispose)(a);v._runtimeEffect_create=a=>(v._runtimeEffect_create=Y.runtimeEffect_create)(a);v._runtimeEffect_dispose=a=>(v._runtimeEffect_dispose=Y.runtimeEffect_dispose)(a); +v._runtimeEffect_getUniformSize=a=>(v._runtimeEffect_getUniformSize=Y.runtimeEffect_getUniformSize)(a);v._shader_createRuntimeEffectShader=(a,b,c,d)=>(v._shader_createRuntimeEffectShader=Y.shader_createRuntimeEffectShader)(a,b,c,d);v._shader_createFromImage=(a,b,c,d,f)=>(v._shader_createFromImage=Y.shader_createFromImage)(a,b,c,d,f);v._skString_allocate=a=>(v._skString_allocate=Y.skString_allocate)(a);v._skString_getData=a=>(v._skString_getData=Y.skString_getData)(a); +v._skString_getLength=a=>(v._skString_getLength=Y.skString_getLength)(a);v._skString_free=a=>(v._skString_free=Y.skString_free)(a);v._skString16_allocate=a=>(v._skString16_allocate=Y.skString16_allocate)(a);v._skString16_getData=a=>(v._skString16_getData=Y.skString16_getData)(a);v._skString16_free=a=>(v._skString16_free=Y.skString16_free)(a);v._surface_create=()=>(v._surface_create=Y.surface_create)();v._surface_getThreadId=a=>(v._surface_getThreadId=Y.surface_getThreadId)(a); +v._surface_setCallbackHandler=(a,b)=>(v._surface_setCallbackHandler=Y.surface_setCallbackHandler)(a,b);v._surface_destroy=a=>(v._surface_destroy=Y.surface_destroy)(a);var tg=v._surface_dispose=a=>(tg=v._surface_dispose=Y.surface_dispose)(a);v._surface_renderPictures=(a,b,c)=>(v._surface_renderPictures=Y.surface_renderPictures)(a,b,c);var qg=v._surface_renderPicturesOnWorker=(a,b,c,d,f)=>(qg=v._surface_renderPicturesOnWorker=Y.surface_renderPicturesOnWorker)(a,b,c,d,f); +v._surface_rasterizeImage=(a,b,c)=>(v._surface_rasterizeImage=Y.surface_rasterizeImage)(a,b,c);var ug=v._surface_rasterizeImageOnWorker=(a,b,c,d)=>(ug=v._surface_rasterizeImageOnWorker=Y.surface_rasterizeImageOnWorker)(a,b,c,d),sg=v._surface_onRenderComplete=(a,b,c)=>(sg=v._surface_onRenderComplete=Y.surface_onRenderComplete)(a,b,c),vg=v._surface_onRasterizeComplete=(a,b,c)=>(vg=v._surface_onRasterizeComplete=Y.surface_onRasterizeComplete)(a,b,c); +v._lineMetrics_create=(a,b,c,d,f,g,l,m,p)=>(v._lineMetrics_create=Y.lineMetrics_create)(a,b,c,d,f,g,l,m,p);v._lineMetrics_dispose=a=>(v._lineMetrics_dispose=Y.lineMetrics_dispose)(a);v._lineMetrics_getHardBreak=a=>(v._lineMetrics_getHardBreak=Y.lineMetrics_getHardBreak)(a);v._lineMetrics_getAscent=a=>(v._lineMetrics_getAscent=Y.lineMetrics_getAscent)(a);v._lineMetrics_getDescent=a=>(v._lineMetrics_getDescent=Y.lineMetrics_getDescent)(a); +v._lineMetrics_getUnscaledAscent=a=>(v._lineMetrics_getUnscaledAscent=Y.lineMetrics_getUnscaledAscent)(a);v._lineMetrics_getHeight=a=>(v._lineMetrics_getHeight=Y.lineMetrics_getHeight)(a);v._lineMetrics_getWidth=a=>(v._lineMetrics_getWidth=Y.lineMetrics_getWidth)(a);v._lineMetrics_getLeft=a=>(v._lineMetrics_getLeft=Y.lineMetrics_getLeft)(a);v._lineMetrics_getBaseline=a=>(v._lineMetrics_getBaseline=Y.lineMetrics_getBaseline)(a);v._lineMetrics_getLineNumber=a=>(v._lineMetrics_getLineNumber=Y.lineMetrics_getLineNumber)(a); +v._lineMetrics_getStartIndex=a=>(v._lineMetrics_getStartIndex=Y.lineMetrics_getStartIndex)(a);v._lineMetrics_getEndIndex=a=>(v._lineMetrics_getEndIndex=Y.lineMetrics_getEndIndex)(a);v._paragraph_dispose=a=>(v._paragraph_dispose=Y.paragraph_dispose)(a);v._paragraph_getWidth=a=>(v._paragraph_getWidth=Y.paragraph_getWidth)(a);v._paragraph_getHeight=a=>(v._paragraph_getHeight=Y.paragraph_getHeight)(a);v._paragraph_getLongestLine=a=>(v._paragraph_getLongestLine=Y.paragraph_getLongestLine)(a); +v._paragraph_getMinIntrinsicWidth=a=>(v._paragraph_getMinIntrinsicWidth=Y.paragraph_getMinIntrinsicWidth)(a);v._paragraph_getMaxIntrinsicWidth=a=>(v._paragraph_getMaxIntrinsicWidth=Y.paragraph_getMaxIntrinsicWidth)(a);v._paragraph_getAlphabeticBaseline=a=>(v._paragraph_getAlphabeticBaseline=Y.paragraph_getAlphabeticBaseline)(a);v._paragraph_getIdeographicBaseline=a=>(v._paragraph_getIdeographicBaseline=Y.paragraph_getIdeographicBaseline)(a); +v._paragraph_getDidExceedMaxLines=a=>(v._paragraph_getDidExceedMaxLines=Y.paragraph_getDidExceedMaxLines)(a);v._paragraph_layout=(a,b)=>(v._paragraph_layout=Y.paragraph_layout)(a,b);v._paragraph_getPositionForOffset=(a,b,c,d)=>(v._paragraph_getPositionForOffset=Y.paragraph_getPositionForOffset)(a,b,c,d);v._paragraph_getClosestGlyphInfoAtCoordinate=(a,b,c,d,f,g)=>(v._paragraph_getClosestGlyphInfoAtCoordinate=Y.paragraph_getClosestGlyphInfoAtCoordinate)(a,b,c,d,f,g); +v._paragraph_getGlyphInfoAt=(a,b,c,d,f)=>(v._paragraph_getGlyphInfoAt=Y.paragraph_getGlyphInfoAt)(a,b,c,d,f);v._paragraph_getWordBoundary=(a,b,c)=>(v._paragraph_getWordBoundary=Y.paragraph_getWordBoundary)(a,b,c);v._paragraph_getLineCount=a=>(v._paragraph_getLineCount=Y.paragraph_getLineCount)(a);v._paragraph_getLineNumberAt=(a,b)=>(v._paragraph_getLineNumberAt=Y.paragraph_getLineNumberAt)(a,b); +v._paragraph_getLineMetricsAtIndex=(a,b)=>(v._paragraph_getLineMetricsAtIndex=Y.paragraph_getLineMetricsAtIndex)(a,b);v._textBoxList_dispose=a=>(v._textBoxList_dispose=Y.textBoxList_dispose)(a);v._textBoxList_getLength=a=>(v._textBoxList_getLength=Y.textBoxList_getLength)(a);v._textBoxList_getBoxAtIndex=(a,b,c)=>(v._textBoxList_getBoxAtIndex=Y.textBoxList_getBoxAtIndex)(a,b,c);v._paragraph_getBoxesForRange=(a,b,c,d,f)=>(v._paragraph_getBoxesForRange=Y.paragraph_getBoxesForRange)(a,b,c,d,f); +v._paragraph_getBoxesForPlaceholders=a=>(v._paragraph_getBoxesForPlaceholders=Y.paragraph_getBoxesForPlaceholders)(a);v._paragraph_getUnresolvedCodePoints=(a,b,c)=>(v._paragraph_getUnresolvedCodePoints=Y.paragraph_getUnresolvedCodePoints)(a,b,c);v._paragraphBuilder_create=(a,b)=>(v._paragraphBuilder_create=Y.paragraphBuilder_create)(a,b);v._paragraphBuilder_dispose=a=>(v._paragraphBuilder_dispose=Y.paragraphBuilder_dispose)(a); +v._paragraphBuilder_addPlaceholder=(a,b,c,d,f,g)=>(v._paragraphBuilder_addPlaceholder=Y.paragraphBuilder_addPlaceholder)(a,b,c,d,f,g);v._paragraphBuilder_addText=(a,b)=>(v._paragraphBuilder_addText=Y.paragraphBuilder_addText)(a,b);v._paragraphBuilder_getUtf8Text=(a,b)=>(v._paragraphBuilder_getUtf8Text=Y.paragraphBuilder_getUtf8Text)(a,b);v._paragraphBuilder_pushStyle=(a,b)=>(v._paragraphBuilder_pushStyle=Y.paragraphBuilder_pushStyle)(a,b);v._paragraphBuilder_pop=a=>(v._paragraphBuilder_pop=Y.paragraphBuilder_pop)(a); +v._paragraphBuilder_build=a=>(v._paragraphBuilder_build=Y.paragraphBuilder_build)(a);v._unicodePositionBuffer_create=a=>(v._unicodePositionBuffer_create=Y.unicodePositionBuffer_create)(a);v._unicodePositionBuffer_getDataPointer=a=>(v._unicodePositionBuffer_getDataPointer=Y.unicodePositionBuffer_getDataPointer)(a);v._unicodePositionBuffer_free=a=>(v._unicodePositionBuffer_free=Y.unicodePositionBuffer_free)(a);v._lineBreakBuffer_create=a=>(v._lineBreakBuffer_create=Y.lineBreakBuffer_create)(a); +v._lineBreakBuffer_getDataPointer=a=>(v._lineBreakBuffer_getDataPointer=Y.lineBreakBuffer_getDataPointer)(a);v._lineBreakBuffer_free=a=>(v._lineBreakBuffer_free=Y.lineBreakBuffer_free)(a);v._paragraphBuilder_setGraphemeBreaksUtf16=(a,b)=>(v._paragraphBuilder_setGraphemeBreaksUtf16=Y.paragraphBuilder_setGraphemeBreaksUtf16)(a,b);v._paragraphBuilder_setWordBreaksUtf16=(a,b)=>(v._paragraphBuilder_setWordBreaksUtf16=Y.paragraphBuilder_setWordBreaksUtf16)(a,b); +v._paragraphBuilder_setLineBreaksUtf16=(a,b)=>(v._paragraphBuilder_setLineBreaksUtf16=Y.paragraphBuilder_setLineBreaksUtf16)(a,b);v._paragraphStyle_create=()=>(v._paragraphStyle_create=Y.paragraphStyle_create)();v._paragraphStyle_dispose=a=>(v._paragraphStyle_dispose=Y.paragraphStyle_dispose)(a);v._paragraphStyle_setTextAlign=(a,b)=>(v._paragraphStyle_setTextAlign=Y.paragraphStyle_setTextAlign)(a,b); +v._paragraphStyle_setTextDirection=(a,b)=>(v._paragraphStyle_setTextDirection=Y.paragraphStyle_setTextDirection)(a,b);v._paragraphStyle_setMaxLines=(a,b)=>(v._paragraphStyle_setMaxLines=Y.paragraphStyle_setMaxLines)(a,b);v._paragraphStyle_setHeight=(a,b)=>(v._paragraphStyle_setHeight=Y.paragraphStyle_setHeight)(a,b);v._paragraphStyle_setTextHeightBehavior=(a,b,c)=>(v._paragraphStyle_setTextHeightBehavior=Y.paragraphStyle_setTextHeightBehavior)(a,b,c); +v._paragraphStyle_setEllipsis=(a,b)=>(v._paragraphStyle_setEllipsis=Y.paragraphStyle_setEllipsis)(a,b);v._paragraphStyle_setStrutStyle=(a,b)=>(v._paragraphStyle_setStrutStyle=Y.paragraphStyle_setStrutStyle)(a,b);v._paragraphStyle_setTextStyle=(a,b)=>(v._paragraphStyle_setTextStyle=Y.paragraphStyle_setTextStyle)(a,b);v._paragraphStyle_setApplyRoundingHack=(a,b)=>(v._paragraphStyle_setApplyRoundingHack=Y.paragraphStyle_setApplyRoundingHack)(a,b);v._strutStyle_create=()=>(v._strutStyle_create=Y.strutStyle_create)(); +v._strutStyle_dispose=a=>(v._strutStyle_dispose=Y.strutStyle_dispose)(a);v._strutStyle_setFontFamilies=(a,b,c)=>(v._strutStyle_setFontFamilies=Y.strutStyle_setFontFamilies)(a,b,c);v._strutStyle_setFontSize=(a,b)=>(v._strutStyle_setFontSize=Y.strutStyle_setFontSize)(a,b);v._strutStyle_setHeight=(a,b)=>(v._strutStyle_setHeight=Y.strutStyle_setHeight)(a,b);v._strutStyle_setHalfLeading=(a,b)=>(v._strutStyle_setHalfLeading=Y.strutStyle_setHalfLeading)(a,b); +v._strutStyle_setLeading=(a,b)=>(v._strutStyle_setLeading=Y.strutStyle_setLeading)(a,b);v._strutStyle_setFontStyle=(a,b,c)=>(v._strutStyle_setFontStyle=Y.strutStyle_setFontStyle)(a,b,c);v._strutStyle_setForceStrutHeight=(a,b)=>(v._strutStyle_setForceStrutHeight=Y.strutStyle_setForceStrutHeight)(a,b);v._textStyle_create=()=>(v._textStyle_create=Y.textStyle_create)();v._textStyle_copy=a=>(v._textStyle_copy=Y.textStyle_copy)(a);v._textStyle_dispose=a=>(v._textStyle_dispose=Y.textStyle_dispose)(a); +v._textStyle_setColor=(a,b)=>(v._textStyle_setColor=Y.textStyle_setColor)(a,b);v._textStyle_setDecoration=(a,b)=>(v._textStyle_setDecoration=Y.textStyle_setDecoration)(a,b);v._textStyle_setDecorationColor=(a,b)=>(v._textStyle_setDecorationColor=Y.textStyle_setDecorationColor)(a,b);v._textStyle_setDecorationStyle=(a,b)=>(v._textStyle_setDecorationStyle=Y.textStyle_setDecorationStyle)(a,b); +v._textStyle_setDecorationThickness=(a,b)=>(v._textStyle_setDecorationThickness=Y.textStyle_setDecorationThickness)(a,b);v._textStyle_setFontStyle=(a,b,c)=>(v._textStyle_setFontStyle=Y.textStyle_setFontStyle)(a,b,c);v._textStyle_setTextBaseline=(a,b)=>(v._textStyle_setTextBaseline=Y.textStyle_setTextBaseline)(a,b);v._textStyle_clearFontFamilies=a=>(v._textStyle_clearFontFamilies=Y.textStyle_clearFontFamilies)(a); +v._textStyle_addFontFamilies=(a,b,c)=>(v._textStyle_addFontFamilies=Y.textStyle_addFontFamilies)(a,b,c);v._textStyle_setFontSize=(a,b)=>(v._textStyle_setFontSize=Y.textStyle_setFontSize)(a,b);v._textStyle_setLetterSpacing=(a,b)=>(v._textStyle_setLetterSpacing=Y.textStyle_setLetterSpacing)(a,b);v._textStyle_setWordSpacing=(a,b)=>(v._textStyle_setWordSpacing=Y.textStyle_setWordSpacing)(a,b);v._textStyle_setHeight=(a,b)=>(v._textStyle_setHeight=Y.textStyle_setHeight)(a,b); +v._textStyle_setHalfLeading=(a,b)=>(v._textStyle_setHalfLeading=Y.textStyle_setHalfLeading)(a,b);v._textStyle_setLocale=(a,b)=>(v._textStyle_setLocale=Y.textStyle_setLocale)(a,b);v._textStyle_setBackground=(a,b)=>(v._textStyle_setBackground=Y.textStyle_setBackground)(a,b);v._textStyle_setForeground=(a,b)=>(v._textStyle_setForeground=Y.textStyle_setForeground)(a,b);v._textStyle_addShadow=(a,b,c,d,f)=>(v._textStyle_addShadow=Y.textStyle_addShadow)(a,b,c,d,f); +v._textStyle_addFontFeature=(a,b,c)=>(v._textStyle_addFontFeature=Y.textStyle_addFontFeature)(a,b,c);v._textStyle_setFontVariations=(a,b,c,d)=>(v._textStyle_setFontVariations=Y.textStyle_setFontVariations)(a,b,c,d);v._vertices_create=(a,b,c,d,f,g,l)=>(v._vertices_create=Y.vertices_create)(a,b,c,d,f,g,l);v._vertices_dispose=a=>(v._vertices_dispose=Y.vertices_dispose)(a);v._skwasm_isMultiThreaded=()=>(v._skwasm_isMultiThreaded=Y.skwasm_isMultiThreaded)(); +var ya=()=>(ya=Y.pthread_self)(),xf=a=>(xf=Y.malloc)(a),Ba=(a,b,c,d,f,g)=>(Ba=Y._emscripten_thread_init)(a,b,c,d,f,g),Ha=()=>(Ha=Y._emscripten_thread_crashed)(),bf=(a,b,c,d,f)=>(bf=Y._emscripten_run_on_main_thread_js)(a,b,c,d,f),jf=a=>(jf=Y._emscripten_thread_free_data)(a),pf=a=>(pf=Y._emscripten_thread_exit)(a),Df=(a,b)=>(Df=Y._emscripten_timeout)(a,b),zf=()=>(zf=Y._emscripten_check_mailbox)(),Z=(a,b)=>(Z=Y.setThrew)(a,b),of=(a,b)=>(of=Y.emscripten_stack_set_limits)(a,b),G=a=>(G=Y._emscripten_stack_restore)(a), +$e=a=>($e=Y._emscripten_stack_alloc)(a),E=()=>(E=Y.emscripten_stack_get_current)();function xe(a,b,c){var d=E();try{return I.get(a)(b,c)}catch(f){G(d);if(f!==f+0)throw f;Z(1,0)}}function Ce(a,b,c){var d=E();try{I.get(a)(b,c)}catch(f){G(d);if(f!==f+0)throw f;Z(1,0)}}function we(a,b){var c=E();try{return I.get(a)(b)}catch(d){G(c);if(d!==d+0)throw d;Z(1,0)}}function De(a,b,c,d){var f=E();try{I.get(a)(b,c,d)}catch(g){G(f);if(g!==g+0)throw g;Z(1,0)}} +function ye(a,b,c,d){var f=E();try{return I.get(a)(b,c,d)}catch(g){G(f);if(g!==g+0)throw g;Z(1,0)}}function Ee(a,b,c,d,f){var g=E();try{I.get(a)(b,c,d,f)}catch(l){G(g);if(l!==l+0)throw l;Z(1,0)}}function Fe(a,b,c,d,f,g,l,m){var p=E();try{I.get(a)(b,c,d,f,g,l,m)}catch(r){G(p);if(r!==r+0)throw r;Z(1,0)}}function Be(a,b){var c=E();try{I.get(a)(b)}catch(d){G(c);if(d!==d+0)throw d;Z(1,0)}}function Ae(a,b,c,d,f,g,l){var m=E();try{return I.get(a)(b,c,d,f,g,l)}catch(p){G(m);if(p!==p+0)throw p;Z(1,0)}} +function ze(a,b,c,d,f){var g=E();try{return I.get(a)(b,c,d,f)}catch(l){G(g);if(l!==l+0)throw l;Z(1,0)}}v.wasmMemory=e;v.wasmExports=Y;v.stackAlloc=af; +v.addFunction=(a,b)=>{if(!mg){mg=new WeakMap;var c=I.length;if(mg)for(var d=0;d<0+c;d++){var f=I.get(d);f&&mg.set(f,d)}}if(c=mg.get(a)||0)return c;if(ng.length)c=ng.pop();else{try{I.grow(1)}catch(m){if(!(m instanceof RangeError))throw m;throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.";}c=I.length-1}try{I.set(c,a)}catch(m){if(!(m instanceof TypeError))throw m;if("function"==typeof WebAssembly.Function){d=WebAssembly.Function;f={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};for(var g= +{parameters:[],results:"v"==b[0]?[]:[f[b[0]]]},l=1;ll?d.push(l):d.push(l%128|128,l>>7);for(l=0;lf?b.push(f):b.push(f%128|128,f>>7);b.push(...d);b.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);b=new WebAssembly.Module(new Uint8Array(b));b=(new WebAssembly.Instance(b, +{e:{f:a}})).exports.f}I.set(c,b)}mg.set(a,c);return c};var wg,xg;Ma=function yg(){wg||zg();wg||(Ma=yg)};function zg(){if(!(0\2c\20std::__2::allocator>::~basic_string\28\29 +220:emscripten_builtin_free +221:sk_sp::~sk_sp\28\29 +222:operator\20new\28unsigned\20long\29 +223:GrGLSLShaderBuilder::codeAppendf\28char\20const*\2c\20...\29 +224:sk_sp::~sk_sp\28\29 +225:void\20SkSafeUnref\28GrSurfaceProxy*\29\20\28.4211\29 +226:void\20SkSafeUnref\28SkImageFilter*\29\20\28.2095\29 +227:operator\20delete\28void*\29 +228:SkRasterPipeline::uncheckedAppend\28SkRasterPipelineOp\2c\20void*\29 +229:void\20SkSafeUnref\28SkString::Rec*\29 +230:GrGLSLShaderBuilder::codeAppend\28char\20const*\29 +231:__cxa_guard_acquire +232:SkSL::GLSLCodeGenerator::write\28std::__2::basic_string_view>\29 +233:SkSL::ErrorReporter::error\28SkSL::Position\2c\20std::__2::basic_string_view>\29 +234:__cxa_guard_release +235:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>&&\2c\20char\20const*\29 +236:hb_blob_destroy +237:SkImageGenerator::onIsProtected\28\29\20const +238:SkDebugf\28char\20const*\2c\20...\29 +239:fmaxf +240:skia_private::TArray::~TArray\28\29 +241:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>&&\29 +242:std::__2::basic_string\2c\20std::__2::allocator>::size\5babi:nn180100\5d\28\29\20const +243:std::__2::__function::__value_func::~__value_func\5babi:ne180100\5d\28\29 +244:void\20SkSafeUnref\28SkPathRef*\29 +245:hb_sanitize_context_t::check_range\28void\20const*\2c\20unsigned\20int\29\20const +246:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::destroy\28\29 +247:GrShaderVar::~GrShaderVar\28\29 +248:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>&&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&&\29 +249:GrColorInfo::~GrColorInfo\28\29 +250:hb_buffer_t::message\28hb_font_t*\2c\20char\20const*\2c\20...\29 +251:__wasm_setjmp_test +252:SkArenaAlloc::allocObject\28unsigned\20int\2c\20unsigned\20int\29 +253:std::__2::basic_string\2c\20std::__2::allocator>::basic_string>\2c\200>\28std::__2::basic_string_view>\20const&\29 +254:fminf +255:SkPaint::~SkPaint\28\29 +256:FT_DivFix +257:strlen +258:std::exception::~exception\28\29 +259:SkMutex::release\28\29 +260:skvx::Vec<4\2c\20float>\20skvx::naive_if_then_else<4\2c\20float>\28skvx::Vec<4\2c\20skvx::Mask::type>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.5832\29 +261:SkPath::SkPath\28\29 +262:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:ne180100\5d<0>\28char\20const*\29 +263:skia_private::TArray>\2c\20true>::~TArray\28\29 +264:skia_png_crc_finish +265:skia_png_chunk_benign_error +266:ft_mem_realloc +267:hb_buffer_t::next_glyph\28\29 +268:SkSL::RP::Generator::pushExpression\28SkSL::Expression\20const&\2c\20bool\29 +269:sk_sp::reset\28SkFontStyleSet*\29 +270:SkSL::RP::Builder::appendInstruction\28SkSL::RP::BuilderOp\2c\20SkSL::RP::Builder::SlotList\2c\20int\2c\20int\2c\20int\2c\20int\29 +271:SkSL::Pool::AllocMemory\28unsigned\20long\29 +272:SkBitmap::~SkBitmap\28\29 +273:sk_report_container_overflow_and_die\28\29 +274:SkMatrix::hasPerspective\28\29\20const +275:SkSemaphore::wait\28\29 +276:skgpu::ganesh::VertexChunkPatchAllocator::append\28skgpu::tess::LinearTolerances\20const&\29 +277:SkWriter32::write32\28int\29 +278:SkString::appendf\28char\20const*\2c\20...\29 +279:skgpu::VertexWriter&\20skgpu::tess::operator<<<\28skgpu::tess::PatchAttribs\298\2c\20skgpu::VertexColor\2c\20false\2c\20true>\28skgpu::VertexWriter&\2c\20skgpu::tess::AttribValue<\28skgpu::tess::PatchAttribs\298\2c\20skgpu::VertexColor\2c\20false\2c\20true>\20const&\29 +280:SkContainerAllocator::allocate\28int\2c\20double\29 +281:FT_Stream_Seek +282:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +283:\28anonymous\20namespace\29::ColorTypeFilter_F16F16::Expand\28unsigned\20int\29 +284:FT_MulDiv +285:std::__2::basic_string\2c\20std::__2::allocator>::append\5babi:ne180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +286:SkString::append\28char\20const*\29 +287:SkArenaAlloc::allocObjectWithFooter\28unsigned\20int\2c\20unsigned\20int\29 +288:OT::VarStoreInstancer::operator\28\29\28unsigned\20int\2c\20unsigned\20short\29\20const +289:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +290:SkIRect::intersect\28SkIRect\20const&\29 +291:skia_png_free +292:lang_matches\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20int\29 +293:ft_mem_qrealloc +294:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +295:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\29 +296:emscripten_builtin_malloc +297:SkSL::Parser::expect\28SkSL::Token::Kind\2c\20char\20const*\2c\20SkSL::Token*\29 +298:SkIntersections::insert\28double\2c\20double\2c\20SkDPoint\20const&\29 +299:SkMatrix::invert\28SkMatrix*\29\20const +300:FT_Stream_ReadUShort +301:skia_private::TArray::push_back\28SkSL::RP::Program::Stage&&\29 +302:sk_sp::~sk_sp\28\29 +303:std::__2::basic_string\2c\20std::__2::allocator>::resize\5babi:nn180100\5d\28unsigned\20long\29 +304:sk_sp::~sk_sp\28\29 +305:cf2_stack_popFixed +306:GrTextureGenerator::isTextureGenerator\28\29\20const +307:strcmp +308:SkIRect::isEmpty\28\29\20const +309:SkBitmap::SkBitmap\28\29 +310:subtag_matches\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20int\29 +311:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +312:cf2_stack_getReal +313:SkSL::GLSLCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +314:SkSL::Type::displayName\28\29\20const +315:SkPathRef::getBounds\28\29\20const +316:SkImageGenerator::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +317:void\20SkSafeUnref\28SkColorSpace*\29\20\28.2052\29 +318:emscripten_builtin_calloc +319:GrAuditTrail::pushFrame\28char\20const*\29 +320:std::__2::locale::~locale\28\29 +321:std::__2::vector\2c\20std::__2::allocator>>::__throw_length_error\5babi:ne180100\5d\28\29\20const +322:skif::FilterResult::~FilterResult\28\29 +323:hb_vector_t::fini\28\29 +324:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrShaderCaps*\29 +325:SkPaint::SkPaint\28SkPaint\20const&\29 +326:SkString::SkString\28SkString&&\29 +327:GrGeometryProcessor::Attribute::asShaderVar\28\29\20const +328:sk_sp::reset\28SkImageFilter*\29 +329:SkBlitter::~SkBlitter\28\29_1533 +330:std::__2::to_string\28int\29 +331:SkTDStorage::~SkTDStorage\28\29 +332:SkSL::Parser::peek\28\29 +333:std::__2::ios_base::getloc\28\29\20const +334:hb_ot_map_builder_t::add_feature\28unsigned\20int\2c\20hb_ot_map_feature_flags_t\2c\20unsigned\20int\29 +335:SkWStream::writeText\28char\20const*\29 +336:void\20SkSafeUnref\28SkData\20const*\29\20\28.1178\29 +337:std::__2::__compressed_pair\2c\20std::__2::allocator>::__rep\2c\20std::__2::allocator>::__compressed_pair\5babi:nn180100\5d\28std::__2::__value_init_tag&&\2c\20std::__2::__default_init_tag&&\29 +338:GrProcessor::operator\20new\28unsigned\20long\29 +339:GrPixmapBase::~GrPixmapBase\28\29 +340:GrGLSLUniformHandler::addUniform\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20char\20const**\29 +341:GrGLContextInfo::hasExtension\28char\20const*\29\20const +342:skgpu::Swizzle::Swizzle\28char\20const*\29 +343:hb_face_t::get_num_glyphs\28\29\20const +344:SkString::~SkString\28\29 +345:GrSurfaceProxyView::operator=\28GrSurfaceProxyView&&\29 +346:GrPaint::~GrPaint\28\29 +347:std::__2::unique_ptr>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +348:std::__2::basic_string\2c\20std::__2::allocator>::__get_pointer\5babi:nn180100\5d\28\29 +349:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +350:SkIRect::contains\28SkIRect\20const&\29\20const +351:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +352:skvx::Vec<8\2c\20unsigned\20short>&\20skvx::operator+=<8\2c\20unsigned\20short>\28skvx::Vec<8\2c\20unsigned\20short>&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +353:memcmp +354:SkArenaAlloc::RunDtorsOnBlock\28char*\29 +355:std::__2::shared_ptr<_IO_FILE>::~shared_ptr\5babi:ne180100\5d\28\29 +356:skia_png_warning +357:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +358:SkString::SkString\28char\20const*\29 +359:hb_sanitize_context_t::start_processing\28\29 +360:__shgetc +361:SkMakeRuntimeEffect\28SkRuntimeEffect::Result\20\28*\29\28SkString\2c\20SkRuntimeEffect::Options\20const&\29\2c\20char\20const*\2c\20SkRuntimeEffect::Options\29 +362:FT_Stream_GetUShort +363:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28wchar_t\20const*\29 +364:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28char\20const*\29 +365:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +366:skia_private::TArray>\2c\20true>::push_back\28std::__2::unique_ptr>&&\29 +367:hb_sanitize_context_t::~hb_sanitize_context_t\28\29 +368:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +369:SkMatrix::mapRect\28SkRect*\2c\20SkRect\20const&\2c\20SkApplyPerspectiveClip\29\20const +370:skia_private::AutoSTMalloc<17ul\2c\20SkPoint\2c\20void>::~AutoSTMalloc\28\29 +371:hb_lazy_loader_t\2c\20hb_face_t\2c\2033u\2c\20hb_blob_t>::do_destroy\28hb_blob_t*\29 +372:SkDQuad::set\28SkPoint\20const*\29 +373:FT_Stream_ExitFrame +374:skia::textlayout::ParagraphImpl::getUTF16Index\28unsigned\20long\29\20const +375:SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29::operator\28\29\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29\20const +376:SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0::operator\28\29\28SkSL::FunctionDefinition\20const*\2c\20SkSL::FunctionDefinition\20const*\29\20const +377:SkSL::Expression::clone\28\29\20const +378:SkMatrix::SkMatrix\28\29 +379:skif::FilterResult::FilterResult\28\29 +380:std::__throw_bad_array_new_length\5babi:ne180100\5d\28\29 +381:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +382:std::__2::unique_ptr::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +383:skvx::Vec<4\2c\20int>\20skvx::operator&<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +384:skia_png_error +385:hb_face_reference_table +386:SkPixmap::SkPixmap\28\29 +387:SkPath::SkPath\28SkPath\20const&\29 +388:skgpu::ganesh::SurfaceDrawContext::addDrawOp\28GrClip\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::function\20const&\29 +389:sk_sp::~sk_sp\28\29 +390:hb_buffer_t::unsafe_to_break\28unsigned\20int\2c\20unsigned\20int\29 +391:\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16::Expand\28unsigned\20long\20long\29 +392:\28anonymous\20namespace\29::ColorTypeFilter_8888::Expand\28unsigned\20int\29 +393:\28anonymous\20namespace\29::ColorTypeFilter_16161616::Expand\28unsigned\20long\20long\29 +394:\28anonymous\20namespace\29::ColorTypeFilter_1010102::Expand\28unsigned\20long\20long\29 +395:SkStringPrintf\28char\20const*\2c\20...\29 +396:SkRecord::grow\28\29 +397:SkPictureRecord::addDraw\28DrawType\2c\20unsigned\20long*\29 +398:OT::Layout::Common::Coverage::get_coverage\28unsigned\20int\29\20const +399:strstr +400:std::__2::__cloc\28\29 +401:sscanf +402:skvx::Vec<4\2c\20int>\20skvx::operator!<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\29 +403:SkRect::intersect\28SkRect\20const&\29 +404:SkImageGenerator::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +405:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +406:skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>::STArray\28skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&&\29 +407:skia_png_chunk_error +408:hb_blob_get_data_writable +409:ft_mem_alloc +410:bool\20hb_sanitize_context_t::check_range>\28OT::IntType\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +411:__multf3 +412:SkSL::GLSLCodeGenerator::writeLine\28std::__2::basic_string_view>\29 +413:SkRect::outset\28float\2c\20float\29 +414:SkMatrix::mapPoints\28SkPoint*\2c\20int\29\20const +415:SkMatrix::getType\28\29\20const +416:FT_Stream_EnterFrame +417:std::__2::unique_ptr>\20SkSL::evaluate_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +418:std::__2::basic_string_view>::compare\28std::__2::basic_string_view>\29\20const +419:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20char\20const*\29 +420:skia_private::THashTable>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair\2c\20std::__2::unique_ptr>*\2c\20skia_private::THashMap>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair>::Hash\28std::__2::unique_ptr>*\20const&\29 +421:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +422:sk_malloc_throw\28unsigned\20long\2c\20unsigned\20long\29 +423:SkSL::String::printf\28char\20const*\2c\20...\29 +424:SkNullBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +425:SkIRect::Intersects\28SkIRect\20const&\2c\20SkIRect\20const&\29 +426:SkArenaAlloc::makeBytesAlignedTo\28unsigned\20long\2c\20unsigned\20long\29 +427:GrGLSLVaryingHandler::addVarying\28char\20const*\2c\20GrGLSLVarying*\2c\20GrGLSLVaryingHandler::Interpolation\29 +428:GrBackendFormats::AsGLFormat\28GrBackendFormat\20const&\29 +429:std::__2::locale::id::__get\28\29 +430:std::__2::locale::facet::facet\5babi:nn180100\5d\28unsigned\20long\29 +431:skgpu::UniqueKey::~UniqueKey\28\29 +432:SkString::operator=\28char\20const*\29 +433:SkRect::setBoundsCheck\28SkPoint\20const*\2c\20int\29 +434:SkDPoint::approximatelyEqual\28SkDPoint\20const&\29\20const +435:SkChecksum::Hash32\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20int\29 +436:GrProcessorSet::GrProcessorSet\28GrPaint&&\29 +437:GrOpFlushState::bindPipelineAndScissorClip\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +438:GrGLExtensions::has\28char\20const*\29\20const +439:strncmp +440:std::__2::locale::__imp::install\28std::__2::locale::facet*\2c\20long\29 +441:skia_png_muldiv +442:f_t_mutex\28\29 +443:SkTDStorage::reserve\28int\29 +444:SkSL::RP::Builder::discard_stack\28int\29 +445:SkSL::Pool::FreeMemory\28void*\29 +446:GrStyledShape::~GrStyledShape\28\29 +447:GrOp::~GrOp\28\29 +448:GrGeometryProcessor::AttributeSet::initImplicit\28GrGeometryProcessor::Attribute\20const*\2c\20int\29 +449:void\20SkSafeUnref\28GrSurface*\29 +450:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +451:sk_sp::~sk_sp\28\29 +452:hb_buffer_t::unsafe_to_concat\28unsigned\20int\2c\20unsigned\20int\29 +453:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +454:SkSL::PipelineStage::PipelineStageCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +455:SkRegion::freeRuns\28\29 +456:SkRect::roundOut\28\29\20const +457:SkRect::contains\28SkRect\20const&\29\20const +458:SkPoint::length\28\29\20const +459:SkPath::~SkPath\28\29 +460:SkPath::lineTo\28SkPoint\20const&\29 +461:SkMatrix::mapPoints\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +462:textStyle_setDecoration +463:std::__2::unique_ptr::~unique_ptr\5babi:nn180100\5d\28\29 +464:std::__2::enable_if::value\20&&\20sizeof\20\28unsigned\20int\29\20==\204\2c\20unsigned\20int>::type\20SkGoodHash::operator\28\29\28unsigned\20int\20const&\29\20const +465:skvx::Vec<8\2c\20unsigned\20short>\20skvx::mulhi<8>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +466:hb_ot_map_builder_t::add_gsub_pause\28bool\20\28*\29\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29\29 +467:cf2_stack_pushFixed +468:SkSL::RP::Builder::binary_op\28SkSL::RP::BuilderOp\2c\20int\29 +469:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20SkFilterMode\2c\20SkMipmapMode\29 +470:GrShaderVar::GrShaderVar\28char\20const*\2c\20SkSLType\2c\20int\29 +471:GrProcessor::operator\20new\28unsigned\20long\2c\20unsigned\20long\29 +472:GrOp::GenID\28std::__2::atomic*\29 +473:GrImageInfo::GrImageInfo\28GrImageInfo&&\29 +474:GrGLSLVaryingHandler::addPassThroughAttribute\28GrShaderVar\20const&\2c\20char\20const*\2c\20GrGLSLVaryingHandler::Interpolation\29 +475:GrFragmentProcessor::registerChild\28std::__2::unique_ptr>\2c\20SkSL::SampleUsage\29 +476:257 +477:std::__2::istreambuf_iterator>::operator*\5babi:nn180100\5d\28\29\20const +478:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +479:std::__2::__throw_system_error\28int\2c\20char\20const*\29 +480:std::__2::__split_buffer&>::~__split_buffer\28\29 +481:hb_buffer_t::merge_clusters\28unsigned\20int\2c\20unsigned\20int\29 +482:SkSL::SymbolTable::addWithoutOwnershipOrDie\28SkSL::Symbol*\29 +483:SkSL::Nop::~Nop\28\29 +484:SkRecords::FillBounds::updateSaveBounds\28SkRect\20const&\29 +485:SkPoint::normalize\28\29 +486:SkMatrix::mapRect\28SkRect\20const&\2c\20SkApplyPerspectiveClip\29\20const +487:SkMatrix::isIdentity\28\29\20const +488:SkJSONWriter::write\28char\20const*\2c\20unsigned\20long\29 +489:SkJSONWriter::appendBool\28char\20const*\2c\20bool\29 +490:GrSkSLFP::UniformPayloadSize\28SkRuntimeEffect\20const*\29 +491:GrSkSLFP::GrSkSLFP\28sk_sp\2c\20char\20const*\2c\20GrSkSLFP::OptFlags\29 +492:std::__2::unique_ptr::unique_ptr\5babi:nn180100\5d\28char*\2c\20std::__2::__dependent_type\2c\20true>::__good_rval_ref_type\29 +493:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +494:std::__2::__throw_bad_function_call\5babi:ne180100\5d\28\29 +495:skia_private::TArray::push_back_raw\28int\29 +496:skgpu::UniqueKey::UniqueKey\28\29 +497:sk_sp::reset\28GrSurface*\29 +498:sk_sp::~sk_sp\28\29 +499:pthread_mutex_unlock +500:dlrealloc +501:abort +502:a_cas +503:__multi3 +504:SkTDArray::push_back\28SkPoint\20const&\29 +505:SkStrokeRec::getStyle\28\29\20const +506:SkSL::fold_expression\28SkSL::Position\2c\20double\2c\20SkSL::Type\20const*\29 +507:SkSL::Type::MakeAliasType\28std::__2::basic_string_view>\2c\20SkSL::Type\20const&\29 +508:GrTriangulator::Comparator::sweep_lt\28SkPoint\20const&\2c\20SkPoint\20const&\29\20const +509:CFF::arg_stack_t::pop_uint\28\29 +510:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +511:skia_png_crc_read +512:pthread_mutex_lock +513:hb_draw_funcs_t::start_path\28void*\2c\20hb_draw_state_t&\29 +514:SkSpinlock::acquire\28\29 +515:SkSL::Parser::rangeFrom\28SkSL::Position\29 +516:SkSL::Parser::checkNext\28SkSL::Token::Kind\2c\20SkSL::Token*\29 +517:SkMatrix::postTranslate\28float\2c\20float\29 +518:SkMatrix::isScaleTranslate\28\29\20const +519:SkMatrix::Concat\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +520:GrOpFlushState::bindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +521:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28char\29 +522:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +523:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +524:sk_malloc_flags\28unsigned\20long\2c\20unsigned\20int\29 +525:hb_paint_funcs_t::pop_transform\28void*\29 +526:fma +527:SkTDStorage::append\28\29 +528:SkTDArray::append\28\29 +529:SkSL::RP::Builder::lastInstruction\28int\29 +530:SkPath::lineTo\28float\2c\20float\29 +531:SkMatrix::rectStaysRect\28\29\20const +532:SkMatrix::mapRect\28SkRect*\2c\20SkApplyPerspectiveClip\29\20const +533:OT::ArrayOf\2c\20OT::IntType>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +534:hb_draw_funcs_t::emit_line_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\29 +535:hb_buffer_t::reverse\28\29 +536:SkString::operator=\28SkString\20const&\29 +537:SkStrikeSpec::~SkStrikeSpec\28\29 +538:SkSL::Type::toCompound\28SkSL::Context\20const&\2c\20int\2c\20int\29\20const +539:SkSL::RP::Generator::binaryOp\28SkSL::Type\20const&\2c\20SkSL::RP::Generator::TypedOps\20const&\29 +540:SkRecords::FillBounds::adjustAndMap\28SkRect\2c\20SkPaint\20const*\29\20const +541:SkPath::operator=\28SkPath\20const&\29 +542:SkMatrix::preConcat\28SkMatrix\20const&\29 +543:SkMatrix::Translate\28float\2c\20float\29 +544:SkDCubic::set\28SkPoint\20const*\29 +545:SkColorSpaceXformSteps::SkColorSpaceXformSteps\28SkColorSpace\20const*\2c\20SkAlphaType\2c\20SkColorSpace\20const*\2c\20SkAlphaType\29 +546:GrStyle::isSimpleFill\28\29\20const +547:GrGLSLVaryingHandler::emitAttributes\28GrGeometryProcessor\20const&\29 +548:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::setIndices\28\29 +549:std::__2::unique_ptr::reset\5babi:nn180100\5d\28unsigned\20char*\29 +550:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +551:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +552:std::__2::__unique_if::__unique_array_unknown_bound\20std::__2::make_unique\5babi:ne180100\5d\28unsigned\20long\29 +553:skvx::Vec<8\2c\20unsigned\20short>\20skvx::operator+<8\2c\20unsigned\20short>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +554:skif::FilterResult::operator=\28skif::FilterResult&&\29 +555:skgpu::VertexColor::set\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\29 +556:skgpu::ResourceKey::Builder::finish\28\29 +557:sk_sp::~sk_sp\28\29 +558:ft_validator_error +559:SkSL::Parser::error\28SkSL::Token\2c\20std::__2::basic_string_view>\29 +560:SkSL::ConstantFolder::GetConstantValueForVariable\28SkSL::Expression\20const&\29 +561:SkPictureRecord::addPaintPtr\28SkPaint\20const*\29 +562:SkPath::reset\28\29 +563:SkPath::Iter::next\28SkPoint*\29 +564:SkGlyph::rowBytes\28\29\20const +565:GrSurfaceProxy::backingStoreDimensions\28\29\20const +566:GrProgramInfo::visitFPProxies\28std::__2::function\20const&\29\20const +567:GrMeshDrawOp::createProgramInfo\28GrMeshDrawTarget*\29 +568:GrGpu::handleDirtyContext\28\29 +569:FT_Stream_ReadFields +570:FT_Stream_ReadByte +571:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +572:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_size\5babi:nn180100\5d\28unsigned\20long\29 +573:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +574:skvx::Vec<4\2c\20float>\20\28anonymous\20namespace\29::add_121>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +575:skia_private::TArray::Allocate\28int\2c\20double\29 +576:skia_private::TArray\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +577:sk_srgb_singleton\28\29 +578:machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>::operator=\28machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\20const&\29 +579:SkWriter32::reserve\28unsigned\20long\29 +580:SkTSect::pointLast\28\29\20const +581:SkStrokeRec::isHairlineStyle\28\29\20const +582:SkSL::Type::MakeVectorType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\29 +583:SkRect::join\28SkRect\20const&\29 +584:SkMatrix::Scale\28float\2c\20float\29 +585:SkColorSpace::MakeSRGB\28\29 +586:FT_Stream_GetULong +587:target_from_texture_type\28GrTextureType\29 +588:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +589:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +590:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator+<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +591:skvx::Vec<4\2c\20unsigned\20int>\20skvx::operator+<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +592:skif::Context::~Context\28\29 +593:skia::textlayout::TextStyle::~TextStyle\28\29 +594:skia::textlayout::TextStyle::TextStyle\28skia::textlayout::TextStyle\20const&\29 +595:skia::textlayout::OneLineShaper::RunBlock::operator=\28skia::textlayout::OneLineShaper::RunBlock&&\29 +596:png_icc_profile_error +597:hb_font_t::get_nominal_glyph\28unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\29 +598:_hb_next_syllable\28hb_buffer_t*\2c\20unsigned\20int\29 +599:__memcpy +600:SkSL::TProgramVisitor::visitStatement\28SkSL::Statement\20const&\29 +601:SkSL::RP::Program::makeStages\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSpan\2c\20SkSL::RP::Program::SlotData\20const&\29\20const::$_2::operator\28\29\28\29\20const +602:SkSL::ConstructorCompound::MakeFromConstants\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20double\20const*\29 +603:SkRect::roundOut\28SkIRect*\29\20const +604:SkPathPriv::Iterate::Iterate\28SkPath\20const&\29 +605:SkPath::moveTo\28SkPoint\20const&\29 +606:SkPaint::setBlendMode\28SkBlendMode\29 +607:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_2::operator\28\29\28SkRasterPipelineOp\2c\20SkRasterPipelineOp\2c\20\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +608:SkDCubic::ptAtT\28double\29\20const +609:SkBitmap::SkBitmap\28SkBitmap\20const&\29 +610:OT::OffsetTo\2c\20OT::IntType\2c\20true>::operator\28\29\28void\20const*\29\20const +611:GrFragmentProcessor::ProgramImpl::invokeChild\28int\2c\20GrFragmentProcessor::ProgramImpl::EmitArgs&\2c\20std::__2::basic_string_view>\29 +612:GrCaps::getDefaultBackendFormat\28GrColorType\2c\20skgpu::Renderable\29\20const +613:FT_Stream_ReleaseFrame +614:DefaultGeoProc::Impl::~Impl\28\29 +615:396 +616:void\20std::__2::unique_ptr>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot*\2c\200>\28skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot*\29 +617:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:nn180100\5d\28\29\20const +618:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +619:out +620:cosf +621:cf2_stack_popInt +622:SkSL::Type::coerceExpression\28std::__2::unique_ptr>\2c\20SkSL::Context\20const&\29\20const +623:SkSL::Type::MakeGenericType\28char\20const*\2c\20SkSpan\2c\20SkSL::Type\20const*\29 +624:SkSL::RP::SlotManager::getVariableSlots\28SkSL::Variable\20const&\29 +625:SkRGBA4f<\28SkAlphaType\292>::operator!=\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +626:SkPathStroker::lineTo\28SkPoint\20const&\2c\20SkPath::Iter\20const*\29 +627:SkPath::conicTo\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\29 +628:SkPath::Iter::setPath\28SkPath\20const&\2c\20bool\29 +629:SkPaint::setColor\28unsigned\20int\29 +630:SkImageInfo::minRowBytes\28\29\20const +631:GrShaderVar::operator=\28GrShaderVar&&\29 +632:GrProcessor::operator\20delete\28void*\29 +633:GrImageInfo::GrImageInfo\28SkImageInfo\20const&\29 +634:GrColorInfo::GrColorInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\29 +635:FT_Outline_Translate +636:std::__2::char_traits::assign\5babi:nn180100\5d\28char&\2c\20char\20const&\29 +637:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +638:std::__2::__check_grouping\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int&\29 +639:skvx::Vec<4\2c\20int>\20skvx::operator|<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +640:skia_private::THashMap::find\28SkSL::FunctionDeclaration\20const*\20const&\29\20const +641:pad +642:ft_mem_qalloc +643:__ashlti3 +644:SkTCoincident::setPerp\28SkTCurve\20const&\2c\20double\2c\20SkDPoint\20const&\2c\20SkTCurve\20const&\29 +645:SkSL::Type::MakeMatrixType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\2c\20signed\20char\29 +646:SkSL::TProgramVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +647:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression\20const&\29 +648:SkSL::Parser::nextToken\28\29 +649:SkSL::Operator::tightOperatorName\28\29\20const +650:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29::$_0::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +651:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29 +652:SkMatrix::postConcat\28SkMatrix\20const&\29 +653:SkDrawBase::~SkDrawBase\28\29 +654:SkDVector::crossCheck\28SkDVector\20const&\29\20const +655:SkCanvas::internalQuickReject\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\29 +656:SkBlitter::~SkBlitter\28\29 +657:SkBitmapDevice::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +658:GrStyle::~GrStyle\28\29 +659:GrSimpleMeshDrawOpHelper::~GrSimpleMeshDrawOpHelper\28\29 +660:GrSimpleMeshDrawOpHelper::visitProxies\28std::__2::function\20const&\29\20const +661:GrShape::reset\28\29 +662:GrShape::bounds\28\29\20const +663:GrShaderVar::appendDecl\28GrShaderCaps\20const*\2c\20SkString*\29\20const +664:GrQuad::MakeFromRect\28SkRect\20const&\2c\20SkMatrix\20const&\29 +665:GrOpFlushState::drawMesh\28GrSimpleMesh\20const&\29 +666:GrAAConvexTessellator::Ring::index\28int\29\20const +667:DefaultGeoProc::~DefaultGeoProc\28\29 +668:449 +669:std::__2::vector\2c\20std::__2::allocator>>::~vector\5babi:ne180100\5d\28\29 +670:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock&\2c\20skia::textlayout::OneLineShaper::RunBlock&\29 +671:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +672:std::__2::basic_string\2c\20std::__2::allocator>::__set_short_size\5babi:nn180100\5d\28unsigned\20long\29 +673:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29\20\28.6973\29 +674:skia_png_chunk_report +675:skgpu::ResourceKey::operator==\28skgpu::ResourceKey\20const&\29\20const +676:sk_sp::~sk_sp\28\29 +677:hb_buffer_t::unsafe_to_break_from_outbuffer\28unsigned\20int\2c\20unsigned\20int\29 +678:cff2_path_procs_extents_t::curve\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +679:cff2_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +680:cff1_path_procs_extents_t::curve\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +681:cff1_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +682:_hb_glyph_info_get_modified_combining_class\28hb_glyph_info_t\20const*\29 +683:SkTDArray::push_back\28unsigned\20int\20const&\29 +684:SkString::data\28\29 +685:SkSemaphore::~SkSemaphore\28\29 +686:SkSL::FunctionDeclaration::description\28\29\20const +687:SkRasterPipeline::extend\28SkRasterPipeline\20const&\29 +688:SkPixmap::operator=\28SkPixmap\20const&\29 +689:SkPath::close\28\29 +690:SkPath::RangeIter::operator++\28\29 +691:SkOpPtT::contains\28SkOpPtT\20const*\29\20const +692:SkNullBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +693:SkMatrixPriv::CheapEqual\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +694:SkIRect::intersect\28SkIRect\20const&\2c\20SkIRect\20const&\29 +695:SkColorSpaceXformSteps::apply\28float*\29\20const +696:SkAAClipBlitterWrapper::~SkAAClipBlitterWrapper\28\29 +697:OT::hb_paint_context_t::recurse\28OT::Paint\20const&\29 +698:OT::hb_ot_apply_context_t::init_iters\28\29 +699:GrTextureProxy::mipmapped\28\29\20const +700:GrStyledShape::asPath\28SkPath*\29\20const +701:GrShaderVar::GrShaderVar\28char\20const*\2c\20SkSLType\2c\20GrShaderVar::TypeModifier\29 +702:GrMatrixEffect::Make\28SkMatrix\20const&\2c\20std::__2::unique_ptr>\29 +703:GrGLGpu::setTextureUnit\28int\29 +704:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::~Impl\28\29 +705:GrCPixmap::GrCPixmap\28GrImageInfo\2c\20void\20const*\2c\20unsigned\20long\29 +706:GrAppliedClip::~GrAppliedClip\28\29 +707:FT_Stream_ReadULong +708:FT_Load_Glyph +709:CFF::cff_stack_t::pop\28\29 +710:void\20SkOnce::operator\28\29*\29\2c\20SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*>\28void\20\28&\29\28SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*\29\2c\20SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*&&\29 +711:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +712:std::__2::numpunct::thousands_sep\5babi:nn180100\5d\28\29\20const +713:std::__2::numpunct::grouping\5babi:nn180100\5d\28\29\20const +714:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +715:std::__2::__throw_bad_optional_access\5babi:ne180100\5d\28\29 +716:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +717:skif::Context::Context\28skif::Context\20const&\29 +718:skia_private::TArray::push_back\28int&&\29 +719:skgpu::ResourceKey::Builder::Builder\28skgpu::ResourceKey*\2c\20unsigned\20int\2c\20int\29 +720:rewind\28GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +721:hb_sanitize_context_t::end_processing\28\29 +722:hb_buffer_t::move_to\28unsigned\20int\29 +723:_output_with_dotted_circle\28hb_buffer_t*\29 +724:SkTSpan::pointLast\28\29\20const +725:SkTDStorage::resize\28int\29 +726:SkSL::Parser::rangeFrom\28SkSL::Token\29 +727:SkSL::Parser::error\28SkSL::Position\2c\20std::__2::basic_string_view>\29 +728:SkPathRef::isFinite\28\29\20const +729:SkPathRef::Editor::Editor\28sk_sp*\2c\20int\2c\20int\2c\20int\29 +730:SkMatrix::mapXY\28float\2c\20float\2c\20SkPoint*\29\20const +731:SkImageInfo::MakeA8\28int\2c\20int\29 +732:SkImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +733:SkDrawable::getFlattenableType\28\29\20const +734:SkDPoint::ApproximatelyEqual\28SkPoint\20const&\2c\20SkPoint\20const&\29 +735:SkBlockAllocator::reset\28\29 +736:GrSimpleMeshDrawOpHelperWithStencil::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20bool*\29 +737:GrGeometryProcessor::ProgramImpl::SetTransform\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrResourceHandle\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix*\29 +738:GrGLSLVertexGeoBuilder::insertFunction\28char\20const*\29 +739:GrDrawingManager::flushIfNecessary\28\29 +740:FT_Stream_Skip +741:FT_Stream_ExtractFrame +742:Cr_z_crc32 +743:void\20std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrGLCaps::ColorTypeInfo*\29 +744:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +745:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +746:std::__2::basic_string\2c\20std::__2::allocator>::__move_assign\5babi:ne180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::integral_constant\29 +747:std::__2::__unique_if::__unique_array_unknown_bound\20std::__2::make_unique\5babi:ne180100\5d\28unsigned\20long\29 +748:std::__2::__compressed_pair_elem::__compressed_pair_elem\5babi:nn180100\5d\28void\20\28*&&\29\28void*\29\29 +749:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +750:skif::LayerSpace::outset\28skif::LayerSpace\20const&\29 +751:skia_private::TArray::checkRealloc\28int\2c\20double\29 +752:skgpu::tess::StrokeIterator::enqueue\28skgpu::tess::StrokeIterator::Verb\2c\20SkPoint\20const*\2c\20float\20const*\29 +753:skgpu::ganesh::SurfaceFillContext::getOpsTask\28\29 +754:skgpu::ganesh::AsView\28GrRecordingContext*\2c\20SkImage\20const*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +755:hb_buffer_t::unsafe_to_concat_from_outbuffer\28unsigned\20int\2c\20unsigned\20int\29 +756:fmodf +757:__addtf3 +758:SkSL::RP::Builder::push_constant_i\28int\2c\20int\29 +759:SkSL::RP::Builder::label\28int\29 +760:SkPath::isConvex\28\29\20const +761:SkPaintToGrPaint\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +762:SkImageInfo::operator=\28SkImageInfo\20const&\29 +763:SkImageGenerator::onIsValid\28GrRecordingContext*\29\20const +764:SkBitmap::tryAllocPixels\28SkImageInfo\20const&\29 +765:GrSkSLFP::addChild\28std::__2::unique_ptr>\2c\20bool\29 +766:GrProcessorSet::~GrProcessorSet\28\29 +767:GrGeometryProcessor::Attribute&\20skia_private::TArray::emplace_back\28char\20const\20\28&\29\20\5b10\5d\2c\20GrVertexAttribType&&\2c\20SkSLType&&\29 +768:GrGLGpu::clearErrorsAndCheckForOOM\28\29 +769:GrGLGpu::bindBuffer\28GrGpuBufferType\2c\20GrBuffer\20const*\29 +770:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +771:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20float\20const*\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20float\20const*\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20float\20const*\29 +772:GrFragmentProcessor::ProgramImpl::invokeChild\28int\2c\20char\20const*\2c\20char\20const*\2c\20GrFragmentProcessor::ProgramImpl::EmitArgs&\2c\20std::__2::basic_string_view>\29 +773:void\20SkSafeUnref\28SharedGenerator*\29 +774:ubidi_getParaLevelAtIndex_skia +775:std::__2::char_traits::copy\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +776:std::__2::basic_string\2c\20std::__2::allocator>::begin\5babi:nn180100\5d\28\29 +777:std::__2::basic_string\2c\20std::__2::allocator>::__is_long\5babi:nn180100\5d\28\29\20const +778:std::__2::__libcpp_snprintf_l\28char*\2c\20unsigned\20long\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +779:skia_private::THashTable>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair\2c\20std::__2::unique_ptr>*\2c\20skia_private::THashMap>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair&&\29 +780:skia::textlayout::Cluster::run\28\29\20const +781:skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::AddTrianglesWhenChopping\2c\20skgpu::tess::DiscardFlatCurves>::accountForCurve\28float\29 +782:skgpu::ganesh::SurfaceContext::PixelTransferResult::~PixelTransferResult\28\29 +783:is_equal\28std::type_info\20const*\2c\20std::type_info\20const*\2c\20bool\29 +784:hb_ot_map_t::get_1_mask\28unsigned\20int\29\20const +785:hb_font_get_glyph +786:hb_draw_funcs_t::emit_quadratic_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\2c\20float\2c\20float\29 +787:cff_index_get_sid_string +788:_hb_font_funcs_set_middle\28hb_font_funcs_t*\2c\20void*\2c\20void\20\28*\29\28void*\29\29 +789:__floatsitf +790:SkWriter32::writeScalar\28float\29 +791:SkTDArray<\28anonymous\20namespace\29::YOffset>::append\28\29 +792:SkSL::RP::Generator::pushVectorizedExpression\28SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +793:SkSL::RP::Builder::swizzle\28int\2c\20SkSpan\29 +794:SkRegion::setRect\28SkIRect\20const&\29 +795:SkPaint::setColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\29 +796:SkPaint::asBlendMode\28\29\20const +797:SkMatrix::preTranslate\28float\2c\20float\29 +798:SkMatrix::getMaxScale\28\29\20const +799:SkJSONWriter::appendHexU32\28char\20const*\2c\20unsigned\20int\29 +800:SkDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +801:SkCanvas::concat\28SkMatrix\20const&\29 +802:SkBlender::Mode\28SkBlendMode\29 +803:SkBitmap::setInfo\28SkImageInfo\20const&\2c\20unsigned\20long\29 +804:SkArenaAlloc::SkArenaAlloc\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +805:OT::hb_ot_apply_context_t::skipping_iterator_t::next\28unsigned\20int*\29 +806:OT::VarSizedBinSearchArrayOf>::get_length\28\29\20const +807:GrMeshDrawTarget::allocMesh\28\29 +808:GrGLGpu::bindTextureToScratchUnit\28unsigned\20int\2c\20int\29 +809:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::~SwizzleFragmentProcessor\28\29 +810:GrCaps::getReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +811:GrBackendFormat::GrBackendFormat\28GrBackendFormat\20const&\29 +812:CFF::cff1_cs_opset_t::check_width\28unsigned\20int\2c\20CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +813:AutoFTAccess::AutoFTAccess\28SkTypeface_FreeType\20const*\29 +814:strchr +815:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +816:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +817:std::__2::pair::type\2c\20std::__2::__unwrap_ref_decay::type>\20std::__2::make_pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +818:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20char\29\20const +819:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_cap\5babi:nn180100\5d\28unsigned\20long\29 +820:std::__2::__function::__value_func::__value_func\5babi:ne180100\5d\28std::__2::__function::__value_func&&\29 +821:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +822:skia_private::TArray>\2c\20true>::reserve_exact\28int\29 +823:skia_private::TArray::push_back\28bool&&\29 +824:skia_png_get_uint_32 +825:skia::textlayout::OneLineShaper::clusterIndex\28unsigned\20long\29 +826:skgpu::ganesh::SurfaceDrawContext::chooseAAType\28GrAA\29 +827:skgpu::UniqueKey::GenerateDomain\28\29 +828:path_quadraticBezierTo +829:hb_buffer_t::sync_so_far\28\29 +830:hb_buffer_t::sync\28\29 +831:compute_side\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +832:cff_parse_num +833:SkWriter32::writeRect\28SkRect\20const&\29 +834:SkSL::Type::clone\28SkSL::Context\20const&\2c\20SkSL::SymbolTable*\29\20const +835:SkSL::SymbolTable::find\28std::__2::basic_string_view>\29\20const +836:SkSL::RP::Generator::writeStatement\28SkSL::Statement\20const&\29 +837:SkSL::RP::Builder::unary_op\28SkSL::RP::BuilderOp\2c\20int\29 +838:SkSL::Parser::operatorRight\28SkSL::Parser::AutoDepth&\2c\20SkSL::OperatorKind\2c\20std::__2::unique_ptr>\20\28SkSL::Parser::*\29\28\29\2c\20std::__2::unique_ptr>&\29 +839:SkSL::Parser::expression\28\29 +840:SkSL::Nop::Make\28\29 +841:SkRecords::FillBounds::pushControl\28\29 +842:SkRasterClip::~SkRasterClip\28\29 +843:SkM44::asM33\28\29\20const +844:SkIRect::makeOutset\28int\2c\20int\29\20const +845:SkDQuad::ptAtT\28double\29\20const +846:SkDConic::ptAtT\28double\29\20const +847:SkAutoConicToQuads::computeQuads\28SkPoint\20const*\2c\20float\2c\20float\29 +848:SkArenaAlloc::~SkArenaAlloc\28\29 +849:SkAAClip::setEmpty\28\29 +850:OT::hb_ot_apply_context_t::skipping_iterator_t::reset\28unsigned\20int\29 +851:GrTriangulator::Line::intersect\28GrTriangulator::Line\20const&\2c\20SkPoint*\29\20const +852:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkISize\20const&\29 +853:GrGpuBuffer::unmap\28\29 +854:GrGeometryProcessor::ProgramImpl::WriteLocalCoord\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20GrShaderVar\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +855:GrGeometryProcessor::ProgramImpl::ComputeMatrixKey\28GrShaderCaps\20const&\2c\20SkMatrix\20const&\29 +856:GrFragmentProcessor::GrFragmentProcessor\28GrFragmentProcessor\20const&\29 +857:638 +858:void\20SkSafeUnref\28SkMipmap*\29 +859:ubidi_getMemory_skia +860:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +861:std::__2::vector>::erase\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\29 +862:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Module\20const*\29 +863:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +864:std::__2::numpunct::truename\5babi:nn180100\5d\28\29\20const +865:std::__2::numpunct::falsename\5babi:nn180100\5d\28\29\20const +866:std::__2::numpunct::decimal_point\5babi:nn180100\5d\28\29\20const +867:std::__2::moneypunct::do_grouping\28\29\20const +868:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29\20const +869:std::__2::basic_string\2c\20std::__2::allocator>::empty\5babi:nn180100\5d\28\29\20const +870:snprintf +871:skvx::Vec<4\2c\20float>\20skvx::operator-<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +872:skia_private::TArray::checkRealloc\28int\2c\20double\29 +873:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +874:skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>::STArray\28skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&&\29 +875:skia_png_reciprocal +876:skia_png_malloc_warn +877:skia::textlayout::\28anonymous\20namespace\29::relax\28float\29 +878:skgpu::ganesh::SurfaceFillContext::arenaAlloc\28\29 +879:skgpu::ganesh::SurfaceContext::readPixels\28GrDirectContext*\2c\20GrPixmap\2c\20SkIPoint\29 +880:skgpu::Swizzle::RGBA\28\29 +881:sk_sp::~sk_sp\28\29 +882:operator==\28SkIRect\20const&\2c\20SkIRect\20const&\29 +883:hb_draw_funcs_t::emit_close_path\28void*\2c\20hb_draw_state_t&\29 +884:em_task_queue_is_empty +885:crc32_z +886:__unlockfile +887:__lockfile +888:SkTSect::SkTSect\28SkTCurve\20const&\29 +889:SkSL::String::Separator\28\29 +890:SkSL::RP::Generator::pushIntrinsic\28SkSL::RP::BuilderOp\2c\20SkSL::Expression\20const&\29 +891:SkSL::ProgramConfig::strictES2Mode\28\29\20const +892:SkSL::Parser::layoutInt\28\29 +893:SkRegion::setEmpty\28\29 +894:SkRegion::Cliperator::next\28\29 +895:SkRegion::Cliperator::Cliperator\28SkRegion\20const&\2c\20SkIRect\20const&\29 +896:SkRGBA4f<\28SkAlphaType\293>::FromColor\28unsigned\20int\29 +897:SkPathRef::growForVerb\28int\2c\20float\29 +898:SkPath::transform\28SkMatrix\20const&\2c\20SkPath*\2c\20SkApplyPerspectiveClip\29\20const +899:SkMipmap::ComputeLevelCount\28int\2c\20int\29 +900:SkMatrix::MakeRectToRect\28SkRect\20const&\2c\20SkRect\20const&\2c\20SkMatrix::ScaleToFit\29 +901:SkMatrix::MakeAll\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +902:SkImageInfo::operator=\28SkImageInfo&&\29 +903:SkImageFilter_Base::getFlattenableType\28\29\20const +904:SkIRect::makeOffset\28int\2c\20int\29\20const +905:SkDLine::nearPoint\28SkDPoint\20const&\2c\20bool*\29\20const +906:SkChopQuadAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +907:SkCanvas::aboutToDraw\28SkPaint\20const&\2c\20SkRect\20const*\29 +908:SkBaseShadowTessellator::appendTriangle\28unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +909:SafeDecodeSymbol +910:OT::hb_ot_apply_context_t::~hb_ot_apply_context_t\28\29 +911:OT::hb_ot_apply_context_t::hb_ot_apply_context_t\28unsigned\20int\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20hb_blob_t*\29 +912:OT::ClassDef::get_class\28unsigned\20int\29\20const +913:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_4::operator\28\29\28char\20const*\29\20const +914:GrSimpleMeshDrawOpHelper::isCompatible\28GrSimpleMeshDrawOpHelper\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +915:GrShaderVar::GrShaderVar\28GrShaderVar\20const&\29 +916:GrQuad::writeVertex\28int\2c\20skgpu::VertexWriter&\29\20const +917:GrOpFlushState::bindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +918:GrGLSLShaderBuilder::appendTextureLookup\28GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +919:GrGLGpu::getErrorAndCheckForOOM\28\29 +920:GrColorInfo::GrColorInfo\28SkColorInfo\20const&\29 +921:GrAAConvexTessellator::addTri\28int\2c\20int\2c\20int\29 +922:FT_Get_Module +923:AlmostBequalUlps\28double\2c\20double\29 +924:tt_face_get_name +925:std::__2::unique_ptr::reset\5babi:ne180100\5d\28void*\29 +926:std::__2::locale::use_facet\28std::__2::locale::id&\29\20const +927:std::__2::basic_string\2c\20std::__2::allocator>::__init\28char\20const*\2c\20unsigned\20long\29 +928:std::__2::__variant_detail::__dtor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29 +929:std::__2::__variant_detail::__dtor\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29 +930:std::__2::__libcpp_locale_guard::~__libcpp_locale_guard\5babi:nn180100\5d\28\29 +931:std::__2::__libcpp_locale_guard::__libcpp_locale_guard\5babi:nn180100\5d\28__locale_struct*&\29 +932:skvx::Vec<4\2c\20float>&\20skvx::operator+=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.5849\29 +933:skvx::Vec<2\2c\20float>\20skvx::max<2\2c\20float>\28skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +934:skif::FilterResult::FilterResult\28skif::FilterResult\20const&\29 +935:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Hash\28SkImageFilter\20const*\20const&\29 +936:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +937:sk_sp&\20skia_private::TArray\2c\20true>::emplace_back>\28sk_sp&&\29 +938:sinf +939:qsort +940:path_cubicTo +941:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +942:hb_user_data_array_t::fini\28\29 +943:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\2c\20hb_pair_t>>::operator+\28unsigned\20int\29\20const +944:hb_indic_would_substitute_feature_t::would_substitute\28unsigned\20int\20const*\2c\20unsigned\20int\2c\20hb_face_t*\29\20const +945:hb_font_t::get_glyph_h_advance\28unsigned\20int\29 +946:ft_module_get_service +947:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\29\20const +948:__sindf +949:__shlim +950:__cosdf +951:SkWriter32::write\28void\20const*\2c\20unsigned\20long\29 +952:SkString::equals\28SkString\20const&\29\20const +953:SkSL::evaluate_pairwise_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +954:SkSL::compile_and_shrink\28SkSL::Compiler*\2c\20SkSL::ProgramKind\2c\20SkSL::ModuleType\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::Module\20const*\29 +955:SkSL::StringStream::str\28\29\20const +956:SkSL::RP::Generator::makeLValue\28SkSL::Expression\20const&\2c\20bool\29 +957:SkSL::Parser::expressionOrPoison\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +958:SkSL::GLSLCodeGenerator::writeIdentifier\28std::__2::basic_string_view>\29 +959:SkSL::GLSLCodeGenerator::getTypeName\28SkSL::Type\20const&\29 +960:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +961:SkRect::round\28\29\20const +962:SkPixmap::SkPixmap\28SkPixmap\20const&\29 +963:SkPaint::getAlpha\28\29\20const +964:SkMatrix::preScale\28float\2c\20float\29 +965:SkMatrix::isSimilarity\28float\29\20const +966:SkIRect::join\28SkIRect\20const&\29 +967:SkDrawBase::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20bool\29\20const +968:SkData::MakeUninitialized\28unsigned\20long\29 +969:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +970:SkCanvas::save\28\29 +971:SkCanvas::checkForDeferredSave\28\29 +972:SkBitmapCache::Rec::getKey\28\29\20const +973:SkAAClip::Builder::addRun\28int\2c\20int\2c\20unsigned\20int\2c\20int\29 +974:GrTriangulator::Line::Line\28SkPoint\20const&\2c\20SkPoint\20const&\29 +975:GrTriangulator::Edge::isRightOf\28GrTriangulator::Vertex\20const&\29\20const +976:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\29 +977:GrShape::setType\28GrShape::Type\29 +978:GrPixmapBase::GrPixmapBase\28GrPixmapBase\20const&\29 +979:GrMakeUncachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +980:GrIORef::unref\28\29\20const +981:GrGeometryProcessor::TextureSampler::reset\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +982:GrGLSLShaderBuilder::getMangledFunctionName\28char\20const*\29 +983:GrGLGpu::deleteFramebuffer\28unsigned\20int\29 +984:GrBackendFormats::MakeGL\28unsigned\20int\2c\20unsigned\20int\29 +985:766 +986:vsnprintf +987:top12 +988:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +989:std::__2::unique_ptr>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +990:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +991:std::__2::to_string\28long\20long\29 +992:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +993:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\2c\20std::__2::allocator>\28char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +994:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +995:std::__2::__num_put_base::__identify_padding\28char*\2c\20char*\2c\20std::__2::ios_base\20const&\29 +996:std::__2::__num_get_base::__get_base\28std::__2::ios_base&\29 +997:std::__2::__libcpp_asprintf_l\28char**\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +998:skvx::Vec<4\2c\20float>\20skvx::abs<4>\28skvx::Vec<4\2c\20float>\20const&\29 +999:skvx::Vec<2\2c\20float>\20skvx::min<2\2c\20float>\28skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +1000:sktext::gpu::BagOfBytes::allocateBytes\28int\2c\20int\29 +1001:skif::FilterResult::FilterResult\28sk_sp\2c\20skif::LayerSpace\20const&\29 +1002:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +1003:skia_private::TArray::~TArray\28\29 +1004:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1005:skia_png_malloc_base +1006:skia::textlayout::TextLine::iterateThroughVisualRuns\28bool\2c\20std::__2::function\2c\20float*\29>\20const&\29\20const +1007:skgpu::ganesh::SurfaceDrawContext::numSamples\28\29\20const +1008:skgpu::AutoCallback::~AutoCallback\28\29 +1009:sk_sp::reset\28SkData*\29 +1010:sk_sp::~sk_sp\28\29 +1011:skData_getConstPointer +1012:round +1013:operator==\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +1014:is_one_of\28hb_glyph_info_t\20const&\2c\20unsigned\20int\29 +1015:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1016:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1017:inflateStateCheck +1018:hb_lazy_loader_t\2c\20hb_face_t\2c\206u\2c\20hb_blob_t>::get\28\29\20const +1019:hb_font_t::has_glyph\28unsigned\20int\29 +1020:bool\20hb_sanitize_context_t::check_array\28OT::HBGlyphID16\20const*\2c\20unsigned\20int\29\20const +1021:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1022:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1023:bool\20OT::Layout::Common::Coverage::collect_coverage\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>>\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>*\29\20const +1024:addPoint\28UBiDi*\2c\20int\2c\20int\29 +1025:a_inc +1026:__unlock +1027:__extenddftf2 +1028:\28anonymous\20namespace\29::extension_compare\28SkString\20const&\2c\20SkString\20const&\29 +1029:\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1030:\28anonymous\20namespace\29::colrv1_transform\28FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\2c\20SkCanvas*\2c\20SkMatrix*\29 +1031:SkUTF::NextUTF8\28char\20const**\2c\20char\20const*\29 +1032:SkUTF::NextUTF8WithReplacement\28char\20const**\2c\20char\20const*\29 +1033:SkTInternalLList::addToHead\28sktext::gpu::TextBlob*\29 +1034:SkTDStorage::removeShuffle\28int\29 +1035:SkTCopyOnFirstWrite::writable\28\29 +1036:SkSurface_Base::getCachedCanvas\28\29 +1037:SkString::reset\28\29 +1038:SkStrike::unlock\28\29 +1039:SkStrike::lock\28\29 +1040:SkSafeMath::addInt\28int\2c\20int\29 +1041:SkSL::cast_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +1042:SkSL::StringStream::~StringStream\28\29 +1043:SkSL::RP::LValue::~LValue\28\29 +1044:SkSL::RP::Generator::pushIntrinsic\28SkSL::RP::Generator::TypedOps\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +1045:SkSL::InlineCandidateAnalyzer::visitExpression\28std::__2::unique_ptr>*\29 +1046:SkSL::GLSLCodeGenerator::writeType\28SkSL::Type\20const&\29 +1047:SkSL::Expression::isBoolLiteral\28\29\20const +1048:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29 +1049:SkRuntimeEffect::findUniform\28std::__2::basic_string_view>\29\20const +1050:SkRasterPipelineBlitter::appendLoadDst\28SkRasterPipeline*\29\20const +1051:SkPoint::Distance\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1052:SkPath::moveTo\28float\2c\20float\29 +1053:SkPath::isRect\28SkRect*\2c\20bool*\2c\20SkPathDirection*\29\20const +1054:SkPath::injectMoveToIfNeeded\28\29 +1055:SkMatrix::setScaleTranslate\28float\2c\20float\2c\20float\2c\20float\29 +1056:SkMatrix::postScale\28float\2c\20float\29 +1057:SkMatrix::mapVector\28float\2c\20float\29\20const +1058:SkIntersections::removeOne\28int\29 +1059:SkImages::RasterFromBitmap\28SkBitmap\20const&\29 +1060:SkImage_Ganesh::SkImage_Ganesh\28sk_sp\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20SkColorInfo\29 +1061:SkImageInfo::Make\28int\2c\20int\2c\20SkColorType\2c\20SkAlphaType\29 +1062:SkImageFilter_Base::getChildInputLayerBounds\28int\2c\20skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +1063:SkGlyph::iRect\28\29\20const +1064:SkFindUnitQuadRoots\28float\2c\20float\2c\20float\2c\20float*\29 +1065:SkDevice::makeSpecial\28SkBitmap\20const&\29 +1066:SkData::PrivateNewWithCopy\28void\20const*\2c\20unsigned\20long\29 +1067:SkColorSpaceXformSteps::Flags::mask\28\29\20const +1068:SkColorSpace::Equals\28SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +1069:SkBlurMaskFilterImpl::computeXformedSigma\28SkMatrix\20const&\29\20const +1070:SkBlockAllocator::BlockIter::Item::operator++\28\29 +1071:SkBitmap::peekPixels\28SkPixmap*\29\20const +1072:SkAAClip::freeRuns\28\29 +1073:OT::hb_ot_apply_context_t::set_lookup_mask\28unsigned\20int\2c\20bool\29 +1074:OT::cmap::find_subtable\28unsigned\20int\2c\20unsigned\20int\29\20const +1075:GrWindowRectangles::~GrWindowRectangles\28\29 +1076:GrTriangulator::EdgeList::remove\28GrTriangulator::Edge*\29 +1077:GrTriangulator::Edge::isLeftOf\28GrTriangulator::Vertex\20const&\29\20const +1078:GrStyle::SimpleFill\28\29 +1079:GrSimpleMeshDrawOpHelper::createProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1080:GrResourceAllocator::addInterval\28GrSurfaceProxy*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20GrResourceAllocator::ActualUse\2c\20GrResourceAllocator::AllowRecycling\29 +1081:GrRenderTask::makeClosed\28GrRecordingContext*\29 +1082:GrGLGpu::prepareToDraw\28GrPrimitiveType\29 +1083:GrBackendFormatToCompressionType\28GrBackendFormat\20const&\29 +1084:FT_Stream_Read +1085:FT_Outline_Get_CBox +1086:Cr_z_adler32 +1087:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::end\28\29\20const +1088:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::begin\28\29\20const +1089:AlmostDequalUlps\28double\2c\20double\29 +1090:871 +1091:872 +1092:write_tag_size\28SkWriteBuffer&\2c\20unsigned\20int\2c\20unsigned\20long\29 +1093:void\20std::__2::unique_ptr::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot*\2c\200>\28skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot*\29 +1094:void\20skgpu::VertexWriter::writeQuad\2c\20skgpu::VertexColor\2c\20skgpu::VertexWriter::Conditional>\28skgpu::VertexWriter::TriFan\20const&\2c\20skgpu::VertexColor\20const&\2c\20skgpu::VertexWriter::Conditional\20const&\29 +1095:uprv_free_skia +1096:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +1097:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +1098:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +1099:strcpy +1100:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1101:std::__2::unique_ptr>::operator=\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +1102:std::__2::unique_ptr>\20GrSkSLFP::Make<>\28SkRuntimeEffect\20const*\2c\20char\20const*\2c\20std::__2::unique_ptr>\2c\20GrSkSLFP::OptFlags\29 +1103:std::__2::unique_ptr>\20GrBlendFragmentProcessor::Make<\28SkBlendMode\2913>\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +1104:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +1105:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\20const*\2c\20char\20const*\29\20const +1106:std::__2::enable_if::type\20skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::AddTrianglesWhenChopping\2c\20skgpu::tess::DiscardFlatCurves>::writeTriangleStack\28skgpu::tess::MiddleOutPolygonTriangulator::PoppedTriangleStack&&\29 +1107:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +1108:std::__2::__tuple_impl\2c\20GrSurfaceProxyView\2c\20sk_sp>::~__tuple_impl\28\29 +1109:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator>=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29\20\28.5836\29 +1110:skia_private::TArray::push_back\28SkSL::SwitchCase\20const*\20const&\29 +1111:skia_private::TArray::push_back_n\28int\2c\20SkPoint\20const*\29 +1112:skia::textlayout::Run::placeholderStyle\28\29\20const +1113:skgpu::skgpu_init_static_unique_key_once\28SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*\29 +1114:skgpu::ganesh::\28anonymous\20namespace\29::update_degenerate_test\28skgpu::ganesh::\28anonymous\20namespace\29::DegenerateTestData*\2c\20SkPoint\20const&\29 +1115:skgpu::VertexWriter&\20skgpu::operator<<\28skgpu::VertexWriter&\2c\20skgpu::VertexColor\20const&\29 +1116:skgpu::ResourceKey::ResourceKey\28\29 +1117:sk_sp::~sk_sp\28\29 +1118:sk_sp::reset\28GrThreadSafeCache::VertexData*\29 +1119:scalbn +1120:rowcol3\28float\20const*\2c\20float\20const*\29 +1121:ps_parser_skip_spaces +1122:is_joiner\28hb_glyph_info_t\20const&\29 +1123:hb_paint_funcs_t::push_translate\28void*\2c\20float\2c\20float\29 +1124:hb_lazy_loader_t\2c\20hb_face_t\2c\2022u\2c\20hb_blob_t>::get\28\29\20const +1125:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\2c\20hb_pair_t>>::operator--\28int\29 +1126:hb_aat_map_t::range_flags_t*\20hb_vector_t::push\28hb_aat_map_t::range_flags_t&&\29 +1127:get_gsubgpos_table\28hb_face_t*\2c\20unsigned\20int\29 +1128:emscripten_longjmp +1129:contourMeasure_dispose +1130:cff2_path_procs_extents_t::line\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\2c\20CFF::point_t\20const&\29 +1131:cff2_path_param_t::line_to\28CFF::point_t\20const&\29 +1132:cff1_path_procs_extents_t::line\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\29 +1133:cff1_path_param_t::line_to\28CFF::point_t\20const&\29 +1134:cf2_stack_pushInt +1135:cf2_buf_readByte +1136:bool\20hb_bsearch_impl\28unsigned\20int*\2c\20unsigned\20int\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29 +1137:_hb_draw_funcs_set_preamble\28hb_draw_funcs_t*\2c\20bool\2c\20void**\2c\20void\20\28**\29\28void*\29\29 +1138:__wake +1139:__memset +1140:\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1141:SkWStream::writeDecAsText\28int\29 +1142:SkTDStorage::append\28void\20const*\2c\20int\29 +1143:SkStrikeSpec::SkStrikeSpec\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +1144:SkSL::RP::Builder::lastInstructionOnAnyStack\28int\29 +1145:SkSL::ProgramUsage::get\28SkSL::Variable\20const&\29\20const +1146:SkSL::Parser::expectIdentifier\28SkSL::Token*\29 +1147:SkSL::Parser::AutoDepth::increase\28\29 +1148:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29::$_3::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +1149:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29::$_2::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +1150:SkSL::GLSLCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1151:SkSL::GLSLCodeGenerator::finishLine\28\29 +1152:SkSL::ConstructorSplat::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1153:SkSL::ConstructorScalarCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1154:SkRuntimeEffect::Uniform::sizeInBytes\28\29\20const +1155:SkRegion::setRegion\28SkRegion\20const&\29 +1156:SkRegion::SkRegion\28SkIRect\20const&\29 +1157:SkRasterPipeline::run\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +1158:SkRasterPipeline::appendTransferFunction\28skcms_TransferFunction\20const&\29 +1159:SkRRect::checkCornerContainment\28float\2c\20float\29\20const +1160:SkRRect::MakeRect\28SkRect\20const&\29 +1161:SkRRect::MakeOval\28SkRect\20const&\29 +1162:SkPointPriv::DistanceToLineSegmentBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +1163:SkPoint::setLength\28float\29 +1164:SkPathPriv::AllPointsEq\28SkPoint\20const*\2c\20int\29 +1165:SkPathBuilder::~SkPathBuilder\28\29 +1166:SkPathBuilder::lineTo\28SkPoint\29 +1167:SkPathBuilder::detach\28\29 +1168:SkPathBuilder::SkPathBuilder\28\29 +1169:SkPath::transform\28SkMatrix\20const&\2c\20SkApplyPerspectiveClip\29 +1170:SkOpCoincidence::release\28SkCoincidentSpans*\2c\20SkCoincidentSpans*\29 +1171:SkJSONWriter::appendCString\28char\20const*\2c\20char\20const*\29 +1172:SkIntersections::hasT\28double\29\20const +1173:SkImageFilter_Base::getChildOutput\28int\2c\20skif::Context\20const&\29\20const +1174:SkIRect::offset\28int\2c\20int\29 +1175:SkDLine::ptAtT\28double\29\20const +1176:SkCanvas::translate\28float\2c\20float\29 +1177:SkCanvas::restoreToCount\28int\29 +1178:SkCanvas::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +1179:SkCachedData::unref\28\29\20const +1180:SkAutoSMalloc<1024ul>::~SkAutoSMalloc\28\29 +1181:SkAutoCanvasRestore::~SkAutoCanvasRestore\28\29 +1182:SkArenaAlloc::SkArenaAlloc\28unsigned\20long\29 +1183:SkAAClipBlitterWrapper::init\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1184:SkAAClipBlitterWrapper::SkAAClipBlitterWrapper\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1185:OT::Offset\2c\20true>::is_null\28\29\20const +1186:OT::MVAR::get_var\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29\20const +1187:MaskAdditiveBlitter::getRow\28int\29 +1188:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20GrCaps\20const&\2c\20float\20const*\29 +1189:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\29 +1190:GrTessellationShader::MakeProgram\28GrTessellationShader::ProgramArgs\20const&\2c\20GrTessellationShader\20const*\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +1191:GrScissorState::enabled\28\29\20const +1192:GrRecordingContextPriv::recordTimeAllocator\28\29 +1193:GrQuad::bounds\28\29\20const +1194:GrProxyProvider::createProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\29 +1195:GrPixmapBase::operator=\28GrPixmapBase&&\29 +1196:GrOpFlushState::detachAppliedClip\28\29 +1197:GrGLGpu::disableWindowRectangles\28\29 +1198:GrGLFormatFromGLEnum\28unsigned\20int\29 +1199:GrFragmentProcessor::~GrFragmentProcessor\28\29 +1200:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29 +1201:GrBackendTexture::getBackendFormat\28\29\20const +1202:CFF::interp_env_t::fetch_op\28\29 +1203:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::setIndices\28\29 +1204:AlmostEqualUlps\28double\2c\20double\29 +1205:AAT::StateTable::get_entry\28int\2c\20unsigned\20int\29\20const +1206:AAT::StateTable::EntryData>::get_entry\28int\2c\20unsigned\20int\29\20const +1207:void\20sktext::gpu::fill3D\28SkZip\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28float\2c\20float\29::operator\28\29\28float\2c\20float\29\20const +1208:tt_face_lookup_table +1209:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1210:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1211:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1212:std::__2::moneypunct::negative_sign\5babi:nn180100\5d\28\29\20const +1213:std::__2::moneypunct::neg_format\5babi:nn180100\5d\28\29\20const +1214:std::__2::moneypunct::frac_digits\5babi:nn180100\5d\28\29\20const +1215:std::__2::moneypunct::do_pos_format\28\29\20const +1216:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20std::__2::random_access_iterator_tag\29 +1217:std::__2::function::operator\28\29\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\20const +1218:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +1219:std::__2::char_traits::copy\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20unsigned\20long\29 +1220:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1221:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1222:std::__2::basic_string\2c\20std::__2::allocator>::__set_size\5babi:nn180100\5d\28unsigned\20long\29 +1223:std::__2::__split_buffer&>::~__split_buffer\28\29 +1224:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +1225:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +1226:std::__2::__itoa::__append2\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1227:std::__2::__exception_guard_exceptions>::__destroy_vector>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +1228:skvx::Vec<4\2c\20unsigned\20int>\20\28anonymous\20namespace\29::shift_right>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20int\29 +1229:skvx::Vec<4\2c\20float>\20skvx::naive_if_then_else<4\2c\20float>\28skvx::Vec<4\2c\20skvx::Mask::type>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1230:sktext::gpu::BagOfBytes::~BagOfBytes\28\29 +1231:skif::\28anonymous\20namespace\29::is_nearly_integer_translation\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29 +1232:skif::RoundOut\28SkRect\29 +1233:skif::FilterResult::resolve\28skif::Context\20const&\2c\20skif::LayerSpace\2c\20bool\29\20const +1234:skia_private::TArray\2c\20true>::destroyAll\28\29 +1235:skia_private::TArray::push_back\28float\20const&\29 +1236:skia_private::TArray::push_back\28SkSL::Variable*&&\29 +1237:skia_png_gamma_correct +1238:skia_png_gamma_8bit_correct +1239:skia::textlayout::TextStyle::operator=\28skia::textlayout::TextStyle\20const&\29 +1240:skia::textlayout::Run::positionX\28unsigned\20long\29\20const +1241:skia::textlayout::ParagraphImpl::codeUnitHasProperty\28unsigned\20long\2c\20SkUnicode::CodeUnitFlags\29\20const +1242:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20std::__2::basic_string_view>\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1243:skgpu::UniqueKey::UniqueKey\28skgpu::UniqueKey\20const&\29 +1244:sk_sp::operator=\28sk_sp\20const&\29 +1245:sk_sp::reset\28GrSurfaceProxy*\29 +1246:sk_sp::operator=\28sk_sp&&\29 +1247:sk_realloc_throw\28void*\2c\20unsigned\20long\29 +1248:powf_ +1249:png_read_buffer +1250:non-virtual\20thunk\20to\20GrOpFlushState::allocator\28\29 +1251:interp_cubic_coords\28double\20const*\2c\20double\29 +1252:int\20_hb_cmp_method>\28void\20const*\2c\20void\20const*\29 +1253:hb_paint_funcs_t::push_transform\28void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +1254:hb_font_t::parent_scale_y_distance\28int\29 +1255:hb_font_t::parent_scale_x_distance\28int\29 +1256:hb_face_t::get_upem\28\29\20const +1257:double_to_clamped_scalar\28double\29 +1258:conic_eval_numerator\28double\20const*\2c\20float\2c\20double\29 +1259:cff_index_init +1260:bool\20std::__2::operator!=\5babi:nn180100\5d\28std::__2::__wrap_iter\20const&\2c\20std::__2::__wrap_iter\20const&\29 +1261:bool\20hb_buffer_t::replace_glyphs\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\20const*\29 +1262:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1263:__wait +1264:__lock +1265:__isspace +1266:\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16::Compact\28skvx::Vec<4\2c\20float>\20const&\29 +1267:\28anonymous\20namespace\29::ColorTypeFilter_F16F16::Compact\28skvx::Vec<4\2c\20float>\20const&\29 +1268:\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16::Compact\28skvx::Vec<4\2c\20float>\20const&\29 +1269:\28anonymous\20namespace\29::ColorTypeFilter_8888::Compact\28skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +1270:\28anonymous\20namespace\29::ColorTypeFilter_16161616::Compact\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1271:\28anonymous\20namespace\29::ColorTypeFilter_1010102::Compact\28unsigned\20long\20long\29 +1272:TT_MulFix14 +1273:Skwasm::createMatrix\28float\20const*\29 +1274:SkWriter32::writeBool\28bool\29 +1275:SkTDStorage::append\28int\29 +1276:SkTDPQueue::setIndex\28int\29 +1277:SkTDArray::push_back\28void*\20const&\29 +1278:SkSurface_Base::refCachedImage\28\29 +1279:SkSpotShadowTessellator::addToClip\28SkPoint\20const&\29 +1280:SkShaderUtils::GLSLPrettyPrint::newline\28\29 +1281:SkShaderUtils::GLSLPrettyPrint::hasToken\28char\20const*\29 +1282:SkSL::Type::MakeTextureType\28char\20const*\2c\20SpvDim_\2c\20bool\2c\20bool\2c\20bool\2c\20SkSL::Type::TextureAccess\29 +1283:SkSL::Type::MakeSpecialType\28char\20const*\2c\20char\20const*\2c\20SkSL::Type::TypeKind\29 +1284:SkSL::Swizzle::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29 +1285:SkSL::RP::Builder::push_slots_or_immutable\28SkSL::RP::SlotRange\2c\20SkSL::RP::BuilderOp\29 +1286:SkSL::RP::Builder::push_duplicates\28int\29 +1287:SkSL::RP::Builder::push_constant_f\28float\29 +1288:SkSL::RP::Builder::push_clone\28int\2c\20int\29 +1289:SkSL::Parser::statementOrNop\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +1290:SkSL::Literal::Make\28SkSL::Position\2c\20double\2c\20SkSL::Type\20const*\29 +1291:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mul\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +1292:SkSL::InlineCandidateAnalyzer::visitStatement\28std::__2::unique_ptr>*\2c\20bool\29 +1293:SkSL::GLSLCodeGenerator::writeModifiers\28SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20bool\29 +1294:SkSL::Expression::isIntLiteral\28\29\20const +1295:SkSL::ConstructorCompound::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +1296:SkSL::ConstantFolder::IsConstantSplat\28SkSL::Expression\20const&\2c\20double\29 +1297:SkSL::Analysis::IsSameExpressionTree\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +1298:SkSL::AliasType::resolve\28\29\20const +1299:SkResourceCache::Find\28SkResourceCache::Key\20const&\2c\20bool\20\28*\29\28SkResourceCache::Rec\20const&\2c\20void*\29\2c\20void*\29 +1300:SkResourceCache::Add\28SkResourceCache::Rec*\2c\20void*\29 +1301:SkRectPriv::HalfWidth\28SkRect\20const&\29 +1302:SkRect::isFinite\28\29\20const +1303:SkRasterPipeline_<256ul>::SkRasterPipeline_\28\29 +1304:SkRasterPipeline::appendConstantColor\28SkArenaAlloc*\2c\20float\20const*\29 +1305:SkRasterClip::setRect\28SkIRect\20const&\29 +1306:SkRasterClip::quickContains\28SkIRect\20const&\29\20const +1307:SkRRect::setRect\28SkRect\20const&\29 +1308:SkPathWriter::isClosed\28\29\20const +1309:SkPathStroker::addDegenerateLine\28SkQuadConstruct\20const*\29 +1310:SkPathBuilder::moveTo\28SkPoint\29 +1311:SkPath::swap\28SkPath&\29 +1312:SkPath::getGenerationID\28\29\20const +1313:SkPath::addPoly\28SkPoint\20const*\2c\20int\2c\20bool\29 +1314:SkOpSegment::existing\28double\2c\20SkOpSegment\20const*\29\20const +1315:SkOpSegment::addT\28double\29 +1316:SkOpSegment::addCurveTo\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkPathWriter*\29\20const +1317:SkOpPtT::find\28SkOpSegment\20const*\29\20const +1318:SkOpContourBuilder::flush\28\29 +1319:SkNVRefCnt::unref\28\29\20const +1320:SkNVRefCnt::unref\28\29\20const +1321:SkMipmap::getLevel\28int\2c\20SkMipmap::Level*\29\20const +1322:SkMatrix::isFinite\28\29\20const +1323:SkM44::setConcat\28SkM44\20const&\2c\20SkM44\20const&\29 +1324:SkImage_Picture::type\28\29\20const +1325:SkImageInfoIsValid\28SkImageInfo\20const&\29 +1326:SkImageInfo::makeColorType\28SkColorType\29\20const +1327:SkImageInfo::computeByteSize\28unsigned\20long\29\20const +1328:SkImageInfo::SkImageInfo\28SkImageInfo\20const&\29 +1329:SkImageFilter_Base::SkImageFilter_Base\28sk_sp\20const*\2c\20int\2c\20std::__2::optional\29 +1330:SkGlyph::imageSize\28\29\20const +1331:SkColorSpaceXformSteps::apply\28SkRasterPipeline*\29\20const +1332:SkColorSpace::gammaIsLinear\28\29\20const +1333:SkColorFilterBase::affectsTransparentBlack\28\29\20const +1334:SkCanvas::~SkCanvas\28\29 +1335:SkCanvas::predrawNotify\28bool\29 +1336:SkCanvas::drawImage\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +1337:SkCanvas::aboutToDraw\28SkPaint\20const&\2c\20SkRect\20const*\2c\20SkEnumBitMask\29 +1338:SkBlockAllocator::SkBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\2c\20unsigned\20long\29 +1339:SkBlockAllocator::BlockIter::begin\28\29\20const +1340:SkBitmap::reset\28\29 +1341:SkBitmap::installPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29 +1342:ScalarToAlpha\28float\29 +1343:OT::Layout::GSUB_impl::SubstLookupSubTable*\20hb_serialize_context_t::push\28\29 +1344:OT::Layout::GPOS_impl::PosLookupSubTable\20const&\20OT::Lookup::get_subtable\28unsigned\20int\29\20const +1345:OT::ArrayOf\2c\20true>\2c\20OT::IntType>*\20hb_serialize_context_t::extend_size\2c\20true>\2c\20OT::IntType>>\28OT::ArrayOf\2c\20true>\2c\20OT::IntType>*\2c\20unsigned\20long\2c\20bool\29 +1346:GrTriangulator::makeConnectingEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\2c\20int\29 +1347:GrTriangulator::appendPointToContour\28SkPoint\20const&\2c\20GrTriangulator::VertexList*\29\20const +1348:GrSurface::ComputeSize\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20bool\29 +1349:GrStyledShape::writeUnstyledKey\28unsigned\20int*\29\20const +1350:GrStyledShape::unstyledKeySize\28\29\20const +1351:GrStyle::operator=\28GrStyle\20const&\29 +1352:GrStyle::GrStyle\28SkStrokeRec\20const&\2c\20sk_sp\29 +1353:GrStyle::GrStyle\28SkPaint\20const&\29 +1354:GrSimpleMesh::setIndexed\28sk_sp\2c\20int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20GrPrimitiveRestart\2c\20sk_sp\2c\20int\29 +1355:GrRecordingContextPriv::makeSFCWithFallback\28GrImageInfo\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1356:GrRecordingContextPriv::makeSC\28GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +1357:GrQuad::MakeFromSkQuad\28SkPoint\20const*\2c\20SkMatrix\20const&\29 +1358:GrProcessorSet::visitProxies\28std::__2::function\20const&\29\20const +1359:GrProcessorSet::finalize\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrCaps\20const&\2c\20GrClampType\2c\20SkRGBA4f<\28SkAlphaType\292>*\29 +1360:GrGpuResource::isPurgeable\28\29\20const +1361:GrGpuResource::gpuMemorySize\28\29\20const +1362:GrGpuBuffer::updateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +1363:GrGetColorTypeDesc\28GrColorType\29 +1364:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\29 +1365:GrGLSLShaderBuilder::~GrGLSLShaderBuilder\28\29 +1366:GrGLSLShaderBuilder::declAppend\28GrShaderVar\20const&\29 +1367:GrGLGpu::flushScissorTest\28GrScissorTest\29 +1368:GrGLGpu::didDrawTo\28GrRenderTarget*\29 +1369:GrGLGpu::bindFramebuffer\28unsigned\20int\2c\20unsigned\20int\29 +1370:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int*\29 +1371:GrGLCaps::maxRenderTargetSampleCount\28GrGLFormat\29\20const +1372:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\29 +1373:GrDefaultGeoProcFactory::Make\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +1374:GrCaps::validateSurfaceParams\28SkISize\20const&\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20GrTextureType\29\20const +1375:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29::$_0::operator\28\29\28SkIRect\2c\20SkIRect\29\20const +1376:GrBackendTexture::~GrBackendTexture\28\29 +1377:GrAppliedClip::GrAppliedClip\28GrAppliedClip&&\29 +1378:GrAAConvexTessellator::Ring::origEdgeID\28int\29\20const +1379:FT_GlyphLoader_CheckPoints +1380:FT_Get_Sfnt_Table +1381:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +1382:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::end\28\29\20const +1383:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::Item::operator++\28\29 +1384:AAT::Lookup>::get_class\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +1385:void\20std::__2::reverse\5babi:nn180100\5d\28char*\2c\20char*\29 +1386:void\20std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__rehash\28unsigned\20long\29 +1387:void\20SkTQSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29::operator\28\29\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29\20const +1388:void\20SkSafeUnref\28GrThreadSafeCache::VertexData*\29 +1389:unsigned\20int\20hb_buffer_t::group_end\28unsigned\20int\2c\20bool\20\20const\28&\29\28hb_glyph_info_t\20const&\2c\20hb_glyph_info_t\20const&\29\29\20const +1390:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +1391:std::__2::vector>\2c\20std::__2::allocator>>>::push_back\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +1392:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +1393:std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20std::__2::default_delete\2c\20std::__2::allocator>>>::~unique_ptr\5babi:ne180100\5d\28\29 +1394:std::__2::unique_ptr\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +1395:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::SymbolTable*\29 +1396:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1397:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1398:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ios_base&\2c\20wchar_t\29 +1399:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ios_base&\2c\20char\29 +1400:std::__2::hash::operator\28\29\5babi:ne180100\5d\28GrFragmentProcessor\20const*\29\20const +1401:std::__2::char_traits::to_int_type\5babi:nn180100\5d\28char\29 +1402:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +1403:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::allocator\20const&\29 +1404:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\2c\20unsigned\20long\29 +1405:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1406:std::__2::basic_string\2c\20std::__2::allocator>::__get_long_cap\5babi:nn180100\5d\28\29\20const +1407:std::__2::basic_ios>::setstate\5babi:nn180100\5d\28unsigned\20int\29 +1408:skvx::Vec<4\2c\20unsigned\20short>\20\28anonymous\20namespace\29::add_121>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +1409:skvx::Vec<4\2c\20unsigned\20int>\20\28anonymous\20namespace\29::add_121>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1410:skvx::Vec<4\2c\20float>\20unchecked_mix<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1411:skvx::Vec<4\2c\20float>\20skvx::operator/<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1412:skvx::Vec<4\2c\20float>\20skvx::min<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1413:skvx::Vec<4\2c\20float>&\20skvx::operator*=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1414:skvx::Vec<2\2c\20float>\20skvx::naive_if_then_else<2\2c\20float>\28skvx::Vec<2\2c\20skvx::Mask::type>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +1415:skip_spaces +1416:skia_private::THashMap::find\28SkSL::Variable\20const*\20const&\29\20const +1417:skia_private::TArray::push_back\28unsigned\20char&&\29 +1418:skia_private::TArray::TArray\28skia_private::TArray&&\29 +1419:skia_private::TArray::TArray\28skia_private::TArray&&\29 +1420:skia_private::TArray\2c\20true>::preallocateNewData\28int\2c\20double\29 +1421:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +1422:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1423:skia_private::FixedArray<4\2c\20signed\20char>::FixedArray\28std::initializer_list\29 +1424:skia_private::AutoSTMalloc<4ul\2c\20int\2c\20void>::AutoSTMalloc\28unsigned\20long\29 +1425:skia_png_safecat +1426:skia_png_malloc +1427:skia_png_colorspace_sync +1428:skia_png_chunk_warning +1429:skia::textlayout::TextWrapper::TextStretch::extend\28skia::textlayout::TextWrapper::TextStretch&\29 +1430:skia::textlayout::TextLine::iterateThroughSingleRunByStyles\28skia::textlayout::TextLine::TextAdjustment\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::StyleType\2c\20std::__2::function\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\20const&\29\20const +1431:skia::textlayout::ParagraphStyle::~ParagraphStyle\28\29 +1432:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29 +1433:skgpu::ganesh::SurfaceFillContext::fillWithFP\28std::__2::unique_ptr>\29 +1434:skgpu::ganesh::OpsTask::OpChain::List::popHead\28\29 +1435:skgpu::SkSLToGLSL\28SkSL::ShaderCaps\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20skgpu::ShaderErrorHandler*\29 +1436:skgpu::ResourceKey::reset\28\29 +1437:skcms_TransferFunction_getType +1438:skcms_TransferFunction_eval +1439:sk_sp::~sk_sp\28\29 +1440:sk_sp::reset\28SkString::Rec*\29 +1441:sk_sp::operator=\28sk_sp\20const&\29 +1442:sk_sp::operator=\28sk_sp&&\29 +1443:operator!=\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +1444:operator!=\28SkIRect\20const&\2c\20SkIRect\20const&\29 +1445:is_halant\28hb_glyph_info_t\20const&\29 +1446:hb_zip_iter_t\2c\20hb_array_t>::__next__\28\29 +1447:hb_serialize_context_t::pop_pack\28bool\29 +1448:hb_sanitize_context_t::init\28hb_blob_t*\29 +1449:hb_lazy_loader_t\2c\20hb_face_t\2c\2011u\2c\20hb_blob_t>::get\28\29\20const +1450:hb_lazy_loader_t\2c\20hb_face_t\2c\204u\2c\20hb_blob_t>::get\28\29\20const +1451:hb_lazy_loader_t\2c\20hb_face_t\2c\2025u\2c\20OT::GSUB_accelerator_t>::get_stored\28\29\20const +1452:hb_hashmap_t::alloc\28unsigned\20int\29 +1453:hb_font_t::scale_glyph_extents\28hb_glyph_extents_t*\29 +1454:hb_extents_t::add_point\28float\2c\20float\29 +1455:hb_draw_funcs_t::emit_cubic_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +1456:hb_buffer_t::reverse_range\28unsigned\20int\2c\20unsigned\20int\29 +1457:hb_buffer_t::replace_glyph\28unsigned\20int\29 +1458:hb_buffer_t::merge_out_clusters\28unsigned\20int\2c\20unsigned\20int\29 +1459:hb_buffer_destroy +1460:hb_buffer_append +1461:emscripten_futex_wake +1462:cos +1463:cleanup_program\28GrGLGpu*\2c\20unsigned\20int\2c\20SkTDArray\20const&\29 +1464:cff_index_done +1465:cf2_glyphpath_curveTo +1466:bool\20hb_array_t::sanitize\28hb_sanitize_context_t*\29\20const +1467:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1468:auto\20std::__2::__unwrap_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +1469:afm_parser_read_vals +1470:afm_parser_next_key +1471:__lshrti3 +1472:__letf2 +1473:\28anonymous\20namespace\29::skhb_position\28float\29 +1474:SkWriter32::reservePad\28unsigned\20long\29 +1475:SkTSpan::removeBounded\28SkTSpan\20const*\29 +1476:SkTSpan::initBounds\28SkTCurve\20const&\29 +1477:SkTSpan::addBounded\28SkTSpan*\2c\20SkArenaAlloc*\29 +1478:SkTSect::tail\28\29 +1479:SkTDStorage::reset\28\29 +1480:SkString::printf\28char\20const*\2c\20...\29 +1481:SkString::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +1482:SkShaders::Color\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\29 +1483:SkShader::makeWithLocalMatrix\28SkMatrix\20const&\29\20const +1484:SkSamplingOptions::operator==\28SkSamplingOptions\20const&\29\20const +1485:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_5::operator\28\29\28int\2c\20int\29\20const +1486:SkSL::is_constant_value\28SkSL::Expression\20const&\2c\20double\29 +1487:SkSL::\28anonymous\20namespace\29::ReturnsOnAllPathsVisitor::visitStatement\28SkSL::Statement\20const&\29 +1488:SkSL::Type::MakeScalarType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type::NumberKind\2c\20signed\20char\2c\20signed\20char\29 +1489:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Context\20const&\2c\20SkSL::Symbol*\29 +1490:SkSL::RP::Generator::push\28SkSL::RP::LValue&\29 +1491:SkSL::PipelineStage::PipelineStageCodeGenerator::writeLine\28std::__2::basic_string_view>\29 +1492:SkSL::Parser::statement\28bool\29 +1493:SkSL::ModifierFlags::description\28\29\20const +1494:SkSL::Layout::paddedDescription\28\29\20const +1495:SkSL::ConstructorCompoundCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1496:SkSL::Analysis::UpdateVariableRefKind\28SkSL::Expression*\2c\20SkSL::VariableRefKind\2c\20SkSL::ErrorReporter*\29 +1497:SkRegion::Iterator::next\28\29 +1498:SkRect::round\28SkIRect*\29\20const +1499:SkRect::makeSorted\28\29\20const +1500:SkRect::intersects\28SkRect\20const&\29\20const +1501:SkReadBuffer::readInt\28\29 +1502:SkReadBuffer::readBool\28\29 +1503:SkRasterPipeline_<256ul>::~SkRasterPipeline_\28\29 +1504:SkRasterClip::updateCacheAndReturnNonEmpty\28bool\29 +1505:SkRasterClip::quickReject\28SkIRect\20const&\29\20const +1506:SkPixmap::addr\28int\2c\20int\29\20const +1507:SkPath::incReserve\28int\2c\20int\2c\20int\29 +1508:SkPath::arcTo\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +1509:SkPath::addRect\28SkRect\20const&\2c\20SkPathDirection\29 +1510:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\29 +1511:SkPaint*\20SkRecorder::copy\28SkPaint\20const*\29 +1512:SkOpSegment::ptAtT\28double\29\20const +1513:SkOpSegment::dPtAtT\28double\29\20const +1514:SkNoPixelsDevice::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +1515:SkMemoryStream::getPosition\28\29\20const +1516:SkMatrix::setConcat\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +1517:SkMatrix::mapRadius\28float\29\20const +1518:SkMask::getAddr8\28int\2c\20int\29\20const +1519:SkIntersectionHelper::segmentType\28\29\20const +1520:SkImageFilter_Base::flatten\28SkWriteBuffer&\29\20const +1521:SkGoodHash::operator\28\29\28SkString\20const&\29\20const +1522:SkGlyph::rect\28\29\20const +1523:SkFont::SkFont\28sk_sp\2c\20float\29 +1524:SkDynamicMemoryWStream::write\28void\20const*\2c\20unsigned\20long\29 +1525:SkDrawBase::SkDrawBase\28\29 +1526:SkDescriptor::operator==\28SkDescriptor\20const&\29\20const +1527:SkDQuad::RootsValidT\28double\2c\20double\2c\20double\2c\20double*\29 +1528:SkConvertPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +1529:SkCanvas::restore\28\29 +1530:SkCanvas::drawImageRect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +1531:SkCanvas::AutoUpdateQRBounds::~AutoUpdateQRBounds\28\29 +1532:SkCachedData::ref\28\29\20const +1533:SkBulkGlyphMetrics::~SkBulkGlyphMetrics\28\29 +1534:SkBulkGlyphMetrics::SkBulkGlyphMetrics\28SkStrikeSpec\20const&\29 +1535:SkBitmap::setPixelRef\28sk_sp\2c\20int\2c\20int\29 +1536:SkBitmap::installPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\29 +1537:SkAutoPixmapStorage::~SkAutoPixmapStorage\28\29 +1538:SkAlphaRuns::Break\28short*\2c\20unsigned\20char*\2c\20int\2c\20int\29 +1539:OT::VariationStore::get_delta\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +1540:OT::GSUBGPOS::get_lookup\28unsigned\20int\29\20const +1541:OT::GDEF::get_glyph_props\28unsigned\20int\29\20const +1542:OT::CmapSubtable::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +1543:GrTriangulator::EdgeList::insert\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +1544:GrSurfaceProxyView::mipmapped\28\29\20const +1545:GrSurfaceProxy::backingStoreBoundsRect\28\29\20const +1546:GrStyledShape::knownToBeConvex\28\29\20const +1547:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +1548:GrSimpleMeshDrawOpHelperWithStencil::isCompatible\28GrSimpleMeshDrawOpHelperWithStencil\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +1549:GrShape::asPath\28SkPath*\2c\20bool\29\20const +1550:GrScissorState::set\28SkIRect\20const&\29 +1551:GrRenderTask::~GrRenderTask\28\29 +1552:GrPixmap::Allocate\28GrImageInfo\20const&\29 +1553:GrMakeCachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\29 +1554:GrImageInfo::makeColorType\28GrColorType\29\20const +1555:GrGpuResource::CacheAccess::release\28\29 +1556:GrGpuBuffer::map\28\29 +1557:GrGpu::didWriteToSurface\28GrSurface*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const*\2c\20unsigned\20int\29\20const +1558:GrGeometryProcessor::TextureSampler::TextureSampler\28\29 +1559:GrGeometryProcessor::AttributeSet::begin\28\29\20const +1560:GrGeometryProcessor::AttributeSet::Iter::operator++\28\29 +1561:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20int\2c\20int\2c\20int\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +1562:GrConvertPixels\28GrPixmap\20const&\2c\20GrCPixmap\20const&\2c\20bool\29 +1563:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +1564:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +1565:GrAtlasManager::getAtlas\28skgpu::MaskFormat\29\20const +1566:FT_Get_Char_Index +1567:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +1568:1349 +1569:write_buf +1570:wrapper_cmp +1571:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d\2c\20std::__2::tuple\2c\20GrFragmentProcessor\20const*\2c\20GrGeometryProcessor::ProgramImpl::TransformInfo\2c\200ul\2c\201ul>\28std::__2::tuple&\2c\20std::__2::tuple&&\2c\20std::__2::__tuple_types\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +1572:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20unsigned\20int*&\2c\20unsigned\20int*&\29 +1573:unsigned\20long\20const&\20std::__2::max\5babi:nn180100\5d\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29 +1574:toupper +1575:store\28unsigned\20char*\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20int\29 +1576:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +1577:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +1578:std::__2::unique_ptr::~unique_ptr\5babi:ne180100\5d\28\29 +1579:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skia::textlayout::Run*\29 +1580:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1581:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1582:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1583:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +1584:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1585:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1586:std::__2::istreambuf_iterator>::istreambuf_iterator\5babi:nn180100\5d\28\29 +1587:std::__2::enable_if::value\2c\20sk_sp>::type\20GrResourceProvider::findByUniqueKey\28skgpu::UniqueKey\20const&\29 +1588:std::__2::deque>::end\5babi:ne180100\5d\28\29 +1589:std::__2::ctype::narrow\5babi:nn180100\5d\28wchar_t\2c\20char\29\20const +1590:std::__2::ctype::narrow\5babi:nn180100\5d\28char\2c\20char\29\20const +1591:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1592:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>&&\2c\20char\29 +1593:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +1594:std::__2::basic_streambuf>::sputn\5babi:nn180100\5d\28char\20const*\2c\20long\29 +1595:std::__2::basic_streambuf>::setg\5babi:nn180100\5d\28char*\2c\20char*\2c\20char*\29 +1596:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +1597:std::__2::__tree\2c\20std::__2::__map_value_compare\2c\20std::__2::less\2c\20true>\2c\20std::__2::allocator>>::destroy\28std::__2::__tree_node\2c\20void*>*\29 +1598:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +1599:std::__2::__num_get::__stage2_int_loop\28wchar_t\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20wchar_t\20const*\29 +1600:std::__2::__num_get::__stage2_int_loop\28char\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20char\20const*\29 +1601:std::__2::__next_prime\28unsigned\20long\29 +1602:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1603:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1604:src_p\28unsigned\20char\2c\20unsigned\20char\29 +1605:sort_r_swap\28char*\2c\20char*\2c\20unsigned\20long\29 +1606:skvx::Vec<4\2c\20float>\20skvx::operator+<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +1607:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20int\2c\20void>\28int\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.7133\29 +1608:sktext::SkStrikePromise::SkStrikePromise\28sktext::SkStrikePromise&&\29 +1609:skif::\28anonymous\20namespace\29::downscale_step_count\28float\29 +1610:skif::LayerSpace::mapRect\28skif::LayerSpace\20const&\29\20const +1611:skif::LayerSpace::relevantSubset\28skif::LayerSpace\2c\20SkTileMode\29\20const +1612:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::resize\28int\29 +1613:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Hash\28std::__2::basic_string_view>\20const&\29 +1614:skia_private::THashTable::AdaptedTraits>::Hash\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +1615:skia_private::THashSet::contains\28SkSL::Variable\20const*\20const&\29\20const +1616:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1617:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +1618:skia_private::TArray\2c\20true>::~TArray\28\29 +1619:skia_private::TArray::copy\28float\20const*\29 +1620:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +1621:skia_private::TArray::resize_back\28int\29 +1622:skia_private::AutoTMalloc::AutoTMalloc\28unsigned\20long\29 +1623:skia_private::AutoSTArray<4\2c\20float>::reset\28int\29 +1624:skia_png_free_data +1625:skia::textlayout::TextStyle::TextStyle\28\29 +1626:skia::textlayout::Run::Run\28skia::textlayout::ParagraphImpl*\2c\20SkShaper::RunHandler::RunInfo\20const&\2c\20unsigned\20long\2c\20float\2c\20bool\2c\20float\2c\20unsigned\20long\2c\20float\29 +1627:skia::textlayout::InternalLineMetrics::delta\28\29\20const +1628:skia::textlayout::Cluster::Cluster\28skia::textlayout::ParagraphImpl*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkSpan\2c\20float\2c\20float\29 +1629:skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\294>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\298>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::ReplicateLineEndPoints\2c\20skgpu::tess::TrackJoinControlPoints>::chopAndWriteCubics\28skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20int\29 +1630:skgpu::ganesh::SurfaceDrawContext::fillRectToRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +1631:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::RawElement\20const&\29\20const +1632:skgpu::VertexWriter&\20skgpu::operator<<<4\2c\20SkPoint>\28skgpu::VertexWriter&\2c\20skgpu::VertexWriter::RepeatDesc<4\2c\20SkPoint>\20const&\29 +1633:skgpu::TAsyncReadResult::addCpuPlane\28sk_sp\2c\20unsigned\20long\29 +1634:skgpu::Swizzle::RGB1\28\29 +1635:sk_sp::reset\28SkPathRef*\29 +1636:sk_sp::reset\28SkMeshPriv::VB\20const*\29 +1637:sk_malloc_throw\28unsigned\20long\29 +1638:sk_doubles_nearly_equal_ulps\28double\2c\20double\2c\20unsigned\20char\29 +1639:sbrk +1640:quick_div\28int\2c\20int\29 +1641:processPropertySeq\28UBiDi*\2c\20LevState*\2c\20unsigned\20char\2c\20int\2c\20int\29 +1642:memchr +1643:left\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1644:inversion\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::Comparator\20const&\29 +1645:interp_quad_coords\28double\20const*\2c\20double\29 +1646:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +1647:hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>::may_have\28unsigned\20int\29\20const +1648:hb_serialize_context_t::object_t::fini\28\29 +1649:hb_ot_map_builder_t::add_feature\28hb_ot_map_feature_t\20const&\29 +1650:hb_lazy_loader_t\2c\20hb_face_t\2c\2015u\2c\20OT::glyf_accelerator_t>::get_stored\28\29\20const +1651:hb_hashmap_t::fini\28\29 +1652:hb_buffer_t::make_room_for\28unsigned\20int\2c\20unsigned\20int\29 +1653:hb_buffer_t::ensure\28unsigned\20int\29 +1654:hairquad\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +1655:fmt_u +1656:float*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29 +1657:duplicate_pt\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1658:compute_quad_level\28SkPoint\20const*\29 +1659:compute_ULong_sum +1660:cff2_extents_param_t::update_bounds\28CFF::point_t\20const&\29 +1661:cf2_glyphpath_hintPoint +1662:cf2_arrstack_getPointer +1663:cbrtf +1664:can_add_curve\28SkPath::Verb\2c\20SkPoint*\29 +1665:call_hline_blitter\28SkBlitter*\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\29 +1666:bounds_t::update\28CFF::point_t\20const&\29 +1667:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\29\20const +1668:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\29\20const +1669:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1670:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1671:atan2f +1672:af_shaper_get_cluster +1673:_hb_ot_metrics_get_position_common\28hb_font_t*\2c\20hb_ot_metrics_tag_t\2c\20int*\29 +1674:__tandf +1675:__pthread_setcancelstate +1676:__floatunsitf +1677:__cxa_allocate_exception +1678:_ZZNK6sktext3gpu12VertexFiller14fillVertexDataEii6SkSpanIPKNS0_5GlyphEEjRK8SkMatrix7SkIRectPvENK3$_0clIPA4_NS0_12Mask2DVertexEEEDaT_ +1679:\28anonymous\20namespace\29::subtract\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +1680:\28anonymous\20namespace\29::MeshOp::fixedFunctionFlags\28\29\20const +1681:\28anonymous\20namespace\29::DrawAtlasOpImpl::fixedFunctionFlags\28\29\20const +1682:Update_Max +1683:TT_Get_MM_Var +1684:SkWriteBuffer::writeDataAsByteArray\28SkData\20const*\29 +1685:SkUTF::UTF8ToUTF16\28unsigned\20short*\2c\20int\2c\20char\20const*\2c\20unsigned\20long\29 +1686:SkTextBlob::RunRecord::textSize\28\29\20const +1687:SkTSpan::resetBounds\28SkTCurve\20const&\29 +1688:SkTSect::removeSpan\28SkTSpan*\29 +1689:SkTSect::BinarySearch\28SkTSect*\2c\20SkTSect*\2c\20SkIntersections*\29 +1690:SkTInternalLList::remove\28skgpu::Plot*\29 +1691:SkTInternalLList>\2c\20SkGoodHash\2c\20SkNoOpPurge>::Entry>::remove\28SkLRUCache>\2c\20SkGoodHash\2c\20SkNoOpPurge>::Entry*\29 +1692:SkTDArray::append\28\29 +1693:SkTConic::operator\5b\5d\28int\29\20const +1694:SkTBlockList::~SkTBlockList\28\29 +1695:SkStrokeRec::needToApply\28\29\20const +1696:SkStrokeRec::SkStrokeRec\28SkPaint\20const&\2c\20float\29 +1697:SkString::set\28char\20const*\2c\20unsigned\20long\29 +1698:SkString::SkString\28char\20const*\2c\20unsigned\20long\29 +1699:SkStrikeSpec::findOrCreateStrike\28\29\20const +1700:SkStrike::digestFor\28skglyph::ActionType\2c\20SkPackedGlyphID\29 +1701:SkSpecialImages::MakeDeferredFromGpu\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1702:SkShaders::MatrixRec::applyForFragmentProcessor\28SkMatrix\20const&\29\20const +1703:SkScan::FillRect\28SkRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +1704:SkScalerContext_FreeType::setupSize\28\29 +1705:SkSL::type_is_valid_for_color\28SkSL::Type\20const&\29 +1706:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_4::operator\28\29\28int\29\20const +1707:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_3::operator\28\29\28int\29\20const +1708:SkSL::optimize_comparison\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20bool\20\28*\29\28double\2c\20double\29\29 +1709:SkSL::VariableReference::Make\28SkSL::Position\2c\20SkSL::Variable\20const*\2c\20SkSL::VariableRefKind\29 +1710:SkSL::Variable*\20SkSL::SymbolTable::add\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +1711:SkSL::Type::coercionCost\28SkSL::Type\20const&\29\20const +1712:SkSL::SymbolTable::addArrayDimension\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20int\29 +1713:SkSL::String::appendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20...\29 +1714:SkSL::RP::VariableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +1715:SkSL::RP::Program::appendCopySlotsUnmasked\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +1716:SkSL::RP::Generator::pushBinaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +1717:SkSL::RP::Generator::emitTraceLine\28SkSL::Position\29 +1718:SkSL::RP::AutoStack::enter\28\29 +1719:SkSL::PipelineStage::PipelineStageCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1720:SkSL::Operator::determineBinaryType\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\29\20const +1721:SkSL::GLSLCodeGenerator::getTypePrecision\28SkSL::Type\20const&\29 +1722:SkSL::ExpressionStatement::Make\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +1723:SkSL::ConstructorDiagonalMatrix::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1724:SkSL::ConstructorArrayCast::~ConstructorArrayCast\28\29 +1725:SkSL::ConstantFolder::MakeConstantValueForVariable\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +1726:SkSBlockAllocator<64ul>::SkSBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\29 +1727:SkRuntimeEffectBuilder::writableUniformData\28\29 +1728:SkRuntimeEffect::uniformSize\28\29\20const +1729:SkResourceCache::Key::init\28void*\2c\20unsigned\20long\20long\2c\20unsigned\20long\29 +1730:SkRegion::op\28SkRegion\20const&\2c\20SkRegion::Op\29 +1731:SkRasterPipelineBlitter::appendStore\28SkRasterPipeline*\29\20const +1732:SkRasterPipeline::compile\28\29\20const +1733:SkRasterPipeline::appendClampIfNormalized\28SkImageInfo\20const&\29 +1734:SkRasterClipStack::writable_rc\28\29 +1735:SkRRect::transform\28SkMatrix\20const&\2c\20SkRRect*\29\20const +1736:SkRGBA4f<\28SkAlphaType\293>::toSkColor\28\29\20const +1737:SkPointPriv::EqualsWithinTolerance\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1738:SkPoint::Length\28float\2c\20float\29 +1739:SkPixmap::operator=\28SkPixmap&&\29 +1740:SkPathWriter::matchedLast\28SkOpPtT\20const*\29\20const +1741:SkPathWriter::finishContour\28\29 +1742:SkPathRef::atVerb\28int\29\20const +1743:SkPathEdgeIter::next\28\29 +1744:SkPathBuilder::ensureMove\28\29 +1745:SkPathBuilder::close\28\29 +1746:SkPath::addPath\28SkPath\20const&\2c\20SkPath::AddPathMode\29 +1747:SkPaint::operator=\28SkPaint\20const&\29 +1748:SkPaint::isSrcOver\28\29\20const +1749:SkOpSpanBase::contains\28SkOpSegment\20const*\29\20const +1750:SkOpSegment::updateWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +1751:SkOpAngle::linesOnOriginalSide\28SkOpAngle\20const*\29 +1752:SkNoPixelsDevice::writableClip\28\29 +1753:SkNextID::ImageID\28\29 +1754:SkMatrixPriv::MapRect\28SkM44\20const&\2c\20SkRect\20const&\29 +1755:SkMatrix::mapVectors\28SkPoint*\2c\20int\29\20const +1756:SkMaskBuilder::AllocImage\28unsigned\20long\2c\20SkMaskBuilder::AllocType\29 +1757:SkMask::computeImageSize\28\29\20const +1758:SkMask::AlphaIter<\28SkMask::Format\294>::operator*\28\29\20const +1759:SkMakeImageFromRasterBitmap\28SkBitmap\20const&\2c\20SkCopyPixelsMode\29 +1760:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_2D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1761:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_1D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1762:SkKnownRuntimeEffects::GetKnownRuntimeEffect\28SkKnownRuntimeEffects::StableKey\29 +1763:SkJSONWriter::endObject\28\29 +1764:SkJSONWriter::beginObject\28char\20const*\2c\20bool\29 +1765:SkJSONWriter::appendName\28char\20const*\29 +1766:SkIntersections::flip\28\29 +1767:SkImageFilter::getInput\28int\29\20const +1768:SkIRect\20skif::Mapping::map\28SkIRect\20const&\2c\20SkMatrix\20const&\29 +1769:SkIRect::outset\28int\2c\20int\29 +1770:SkIDChangeListener::List::changed\28\29 +1771:SkFont::unicharToGlyph\28int\29\20const +1772:SkDrawTiler::~SkDrawTiler\28\29 +1773:SkDrawTiler::next\28\29 +1774:SkDrawTiler::SkDrawTiler\28SkBitmapDevice*\2c\20SkRect\20const*\29 +1775:SkDrawBase::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29\20const +1776:SkData::MakeEmpty\28\29 +1777:SkDRect::add\28SkDPoint\20const&\29 +1778:SkDCubic::FindExtrema\28double\20const*\2c\20double*\29 +1779:SkConic::chopAt\28float\2c\20SkConic*\29\20const +1780:SkColorFilters::Blend\28unsigned\20int\2c\20SkBlendMode\29 +1781:SkColorFilter::makeComposed\28sk_sp\29\20const +1782:SkCanvas::saveLayer\28SkRect\20const*\2c\20SkPaint\20const*\29 +1783:SkCanvas::getTotalMatrix\28\29\20const +1784:SkCanvas::computeDeviceClipBounds\28bool\29\20const +1785:SkBlurEngine::SigmaToRadius\28float\29 +1786:SkBlockAllocator::ByteRange\20SkBlockAllocator::allocate<4ul\2c\200ul>\28unsigned\20long\29 +1787:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29 +1788:SkAutoSMalloc<1024ul>::SkAutoSMalloc\28unsigned\20long\29 +1789:RunBasedAdditiveBlitter::checkY\28int\29 +1790:RoughlyEqualUlps\28double\2c\20double\29 +1791:Read255UShort +1792:PS_Conv_ToFixed +1793:OT::post::accelerator_t::cmp_gids\28void\20const*\2c\20void\20const*\2c\20void*\29 +1794:OT::hmtxvmtx::accelerator_t::get_advance_without_var_unscaled\28unsigned\20int\29\20const +1795:OT::Layout::GPOS_impl::ValueFormat::apply_value\28OT::hb_ot_apply_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\2c\20hb_glyph_position_t&\29\20const +1796:GrTriangulator::VertexList::remove\28GrTriangulator::Vertex*\29 +1797:GrTriangulator::Vertex*\20SkArenaAlloc::make\28SkPoint&\2c\20int&&\29 +1798:GrTriangulator::Poly::addEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Side\2c\20GrTriangulator*\29 +1799:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\2c\20bool\29 +1800:GrSurface::invokeReleaseProc\28\29 +1801:GrSurface::GrSurface\28GrGpu*\2c\20SkISize\20const&\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +1802:GrStyledShape::operator=\28GrStyledShape\20const&\29 +1803:GrSimpleMeshDrawOpHelperWithStencil::createProgramInfoWithStencil\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1804:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrProcessorSet&&\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrPipeline::InputFlags\2c\20GrUserStencilSettings\20const*\29 +1805:GrShape::setRRect\28SkRRect\20const&\29 +1806:GrShape::reset\28GrShape::Type\29 +1807:GrResourceProvider::findOrCreatePatternedIndexBuffer\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\2c\20skgpu::UniqueKey\20const&\29 +1808:GrResourceProvider::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\2c\20GrResourceProvider::ZeroInit\29 +1809:GrResourceProvider::assignUniqueKeyToResource\28skgpu::UniqueKey\20const&\2c\20GrGpuResource*\29 +1810:GrRenderTask::addDependency\28GrRenderTask*\29 +1811:GrRenderTask::GrRenderTask\28\29 +1812:GrRenderTarget::onRelease\28\29 +1813:GrQuadUtils::TessellationHelper::Vertices::asGrQuads\28GrQuad*\2c\20GrQuad::Type\2c\20GrQuad*\2c\20GrQuad::Type\29\20const +1814:GrProxyProvider::findOrCreateProxyByUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxy::UseAllocator\29 +1815:GrProxyProvider::assignUniqueKeyToProxy\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\29 +1816:GrPaint::setCoverageFragmentProcessor\28std::__2::unique_ptr>\29 +1817:GrOpFlushState::allocator\28\29 +1818:GrMeshDrawOp::QuadHelper::QuadHelper\28GrMeshDrawTarget*\2c\20unsigned\20long\2c\20int\29 +1819:GrIsStrokeHairlineOrEquivalent\28GrStyle\20const&\2c\20SkMatrix\20const&\2c\20float*\29 +1820:GrImageInfo::minRowBytes\28\29\20const +1821:GrGpuResource::CacheAccess::isUsableAsScratch\28\29\20const +1822:GrGeometryProcessor::ProgramImpl::setupUniformColor\28GrGLSLFPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20GrResourceHandle*\29 +1823:GrGLSLUniformHandler::addUniformArray\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20int\2c\20char\20const**\29 +1824:GrGLSLShaderBuilder::emitFunction\28SkSLType\2c\20char\20const*\2c\20SkSpan\2c\20char\20const*\29 +1825:GrGLSLShaderBuilder::code\28\29 +1826:GrGLOpsRenderPass::bindVertexBuffer\28GrBuffer\20const*\2c\20int\29 +1827:GrGLGpu::unbindSurfaceFBOForPixelOps\28GrSurface*\2c\20int\2c\20unsigned\20int\29 +1828:GrGLGpu::flushRenderTarget\28GrGLRenderTarget*\2c\20bool\29 +1829:GrGLGpu::bindSurfaceFBOForPixelOps\28GrSurface*\2c\20int\2c\20unsigned\20int\2c\20GrGLGpu::TempFBOTarget\29 +1830:GrGLCompileAndAttachShader\28GrGLContext\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20bool\2c\20GrThreadSafePipelineBuilder::Stats*\2c\20skgpu::ShaderErrorHandler*\29 +1831:GrFragmentProcessors::Make\28GrRecordingContext*\2c\20SkColorFilter\20const*\2c\20std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1832:GrFragmentProcessor::visitTextureEffects\28std::__2::function\20const&\29\20const +1833:GrFragmentProcessor::MakeColor\28SkRGBA4f<\28SkAlphaType\292>\29 +1834:GrDirectContextPriv::flushSurface\28GrSurfaceProxy*\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +1835:GrBlendFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkBlendMode\2c\20bool\29 +1836:GrBackendFormat::operator=\28GrBackendFormat\20const&\29 +1837:GrAAConvexTessellator::addPt\28SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20GrAAConvexTessellator::CurveState\29 +1838:FT_Outline_Transform +1839:CFF::parsed_values_t::add_op\28unsigned\20int\2c\20CFF::byte_str_ref_t\20const&\2c\20CFF::op_str_t\20const&\29 +1840:CFF::dict_opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +1841:CFF::cs_opset_t\2c\20cff2_extents_param_t\2c\20cff2_path_procs_extents_t>::process_post_move\28unsigned\20int\2c\20CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\29 +1842:CFF::cs_opset_t::process_post_move\28unsigned\20int\2c\20CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +1843:CFF::cs_interp_env_t>>::determine_hintmask_size\28\29 +1844:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::begin\28\29\20const +1845:AlmostBetweenUlps\28double\2c\20double\2c\20double\29 +1846:ActiveEdgeList::SingleRotation\28ActiveEdge*\2c\20int\29 +1847:AAT::StateTable::EntryData>::get_entry\28int\2c\20unsigned\20int\29\20const +1848:AAT::StateTable::EntryData>::get_entry\28int\2c\20unsigned\20int\29\20const +1849:AAT::ContextualSubtable::driver_context_t::is_actionable\28AAT::StateTableDriver::EntryData>*\2c\20AAT::Entry::EntryData>\20const&\29 +1850:1631 +1851:1632 +1852:1633 +1853:1634 +1854:void\20std::__2::__stable_sort\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +1855:void\20std::__2::__split_buffer&>::__construct_at_end\2c\200>\28std::__2::move_iterator\2c\20std::__2::move_iterator\29 +1856:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d>&>\2c\20std::__2::tuple>>\2c\20bool\2c\20std::__2::unique_ptr>\2c\200ul\2c\201ul>\28std::__2::tuple>&>&\2c\20std::__2::tuple>>&&\2c\20std::__2::__tuple_types>>\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +1857:void\20extend_pts<\28SkPaint::Cap\292>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1858:void\20extend_pts<\28SkPaint::Cap\291>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1859:void\20SkSafeUnref\28SkTextBlob*\29 +1860:void\20SkSafeUnref\28GrTextureProxy*\29 +1861:unsigned\20int*\20SkRecorder::copy\28unsigned\20int\20const*\2c\20unsigned\20long\29 +1862:tt_cmap14_ensure +1863:tanf +1864:std::__2::vector>\2c\20std::__2::allocator>>>::push_back\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +1865:std::__2::vector>\2c\20std::__2::allocator>>>::~vector\5babi:ne180100\5d\28\29 +1866:std::__2::vector>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +1867:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +1868:std::__2::unique_ptr>\20\5b\5d\2c\20std::__2::default_delete>\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +1869:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1870:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1871:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1872:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1873:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrDrawOpAtlas*\29 +1874:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +1875:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char8_t*\2c\20char8_t*\2c\20char8_t*&\29\20const +1876:std::__2::basic_string\2c\20std::__2::allocator>::clear\5babi:ne180100\5d\28\29 +1877:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28char\20const*\29 +1878:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20char\20const*\29 +1879:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +1880:std::__2::basic_string\2c\20std::__2::allocator>::__assign_external\28char\20const*\29 +1881:std::__2::array\2c\204ul>::~array\28\29 +1882:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +1883:std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>::__copy_constructor\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29 +1884:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +1885:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20wchar_t&\29 +1886:std::__2::__num_get::__do_widen\28std::__2::ios_base&\2c\20wchar_t*\29\20const +1887:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20char&\29 +1888:std::__2::__itoa::__append1\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1889:std::__2::__function::__value_func::operator=\5babi:ne180100\5d\28std::__2::__function::__value_func&&\29 +1890:std::__2::__function::__value_func::operator\28\29\5babi:ne180100\5d\28SkIRect\20const&\29\20const +1891:sqrtf +1892:skvx::Vec<4\2c\20unsigned\20int>&\20skvx::operator-=<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1893:skvx::Vec<4\2c\20unsigned\20int>&\20skvx::operator+=<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1894:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator><4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1895:skvx::Vec<4\2c\20float>\20skvx::operator+<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29\20\28.5847\29 +1896:skvx::Vec<4\2c\20float>\20skvx::operator+<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.674\29 +1897:skvx::Vec<4\2c\20float>\20skvx::max<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.7685\29 +1898:skvx::Vec<4\2c\20float>\20skvx::max<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1899:sktext::gpu::VertexFiller::vertexStride\28SkMatrix\20const&\29\20const +1900:sktext::gpu::SubRunList::append\28std::__2::unique_ptr\29 +1901:sktext::gpu::SubRun::~SubRun\28\29 +1902:sktext::gpu::GlyphVector::~GlyphVector\28\29 +1903:skif::\28anonymous\20namespace\29::draw_tiled_border\28SkCanvas*\2c\20SkTileMode\2c\20SkPaint\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::LayerSpace\2c\20skif::LayerSpace\29::$_0::operator\28\29\28SkRect\20const&\2c\20SkRect\20const&\29\20const +1904:skif::LayerSpace::inverseMapRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29\20const +1905:skif::FilterResult::analyzeBounds\28skif::LayerSpace\20const&\2c\20skif::FilterResult::BoundsScope\29\20const +1906:skif::FilterResult::AutoSurface::snap\28\29 +1907:skif::FilterResult::AutoSurface::AutoSurface\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult::PixelBoundary\2c\20bool\2c\20SkSurfaceProps\20const*\29 +1908:skia_private::THashTable::AdaptedTraits>::findOrNull\28skgpu::UniqueKey\20const&\29\20const +1909:skia_private::TArray::reset\28int\29 +1910:skia_private::TArray::push_back_raw\28int\29 +1911:skia_private::TArray::push_back\28\29 +1912:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1913:skia_private::AutoSTArray<8\2c\20unsigned\20int>::reset\28int\29 +1914:skia_private::AutoSTArray<24\2c\20unsigned\20int>::~AutoSTArray\28\29 +1915:skia_png_reciprocal2 +1916:skia_png_benign_error +1917:skia::textlayout::Run::~Run\28\29 +1918:skia::textlayout::Run::posX\28unsigned\20long\29\20const +1919:skia::textlayout::ParagraphStyle::ParagraphStyle\28skia::textlayout::ParagraphStyle\20const&\29 +1920:skia::textlayout::InternalLineMetrics::height\28\29\20const +1921:skia::textlayout::InternalLineMetrics::add\28skia::textlayout::Run*\29 +1922:skia::textlayout::FontCollection::findTypefaces\28std::__2::vector>\20const&\2c\20SkFontStyle\2c\20std::__2::optional\20const&\29 +1923:skgpu::ganesh::TextureOp::BatchSizeLimiter::createOp\28GrTextureSetEntry*\2c\20int\2c\20GrAAType\29 +1924:skgpu::ganesh::SurfaceFillContext::fillRectWithFP\28SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +1925:skgpu::ganesh::SurfaceFillContext::fillRectToRectWithFP\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +1926:skgpu::ganesh::SurfaceDrawContext::drawShapeUsingPathRenderer\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\2c\20bool\29 +1927:skgpu::ganesh::SurfaceDrawContext::drawRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const*\29 +1928:skgpu::ganesh::SurfaceDrawContext::drawRRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20GrStyle\20const&\29 +1929:skgpu::ganesh::SurfaceDrawContext::drawFilledQuad\28GrClip\20const*\2c\20GrPaint&&\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\29 +1930:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29::$_0::~$_0\28\29 +1931:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29 +1932:skgpu::ganesh::SurfaceContext::PixelTransferResult::PixelTransferResult\28skgpu::ganesh::SurfaceContext::PixelTransferResult&&\29 +1933:skgpu::ganesh::SoftwarePathRenderer::DrawNonAARect\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const&\29 +1934:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::vertexSize\28\29\20const +1935:skgpu::ganesh::OpsTask::OpChain::List::List\28skgpu::ganesh::OpsTask::OpChain::List&&\29 +1936:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29::$_0::operator\28\29\28GrSurfaceProxyView\20const&\29\20const +1937:skgpu::ganesh::Device::targetProxy\28\29 +1938:skgpu::ganesh::ClipStack::getConservativeBounds\28\29\20const +1939:skgpu::UniqueKeyInvalidatedMessage::UniqueKeyInvalidatedMessage\28skgpu::UniqueKeyInvalidatedMessage\20const&\29 +1940:skgpu::UniqueKey::operator=\28skgpu::UniqueKey\20const&\29 +1941:skgpu::TAsyncReadResult::addTransferResult\28skgpu::ganesh::SurfaceContext::PixelTransferResult\20const&\2c\20SkISize\2c\20unsigned\20long\2c\20skgpu::TClientMappedBufferManager*\29 +1942:skgpu::Swizzle::asString\28\29\20const +1943:skgpu::GetApproxSize\28SkISize\29 +1944:sk_srgb_linear_singleton\28\29 +1945:sk_sp::reset\28SkVertices*\29 +1946:sk_sp::operator=\28sk_sp&&\29 +1947:sk_sp::reset\28GrGpuBuffer*\29 +1948:sk_sp\20sk_make_sp\28\29 +1949:sfnt_get_name_id +1950:set_glyph\28hb_glyph_info_t&\2c\20hb_font_t*\29 +1951:resource_cache_mutex\28\29 +1952:remove_node\28OffsetEdge\20const*\2c\20OffsetEdge**\29 +1953:ps_parser_to_token +1954:precisely_between\28double\2c\20double\2c\20double\29 +1955:powf +1956:next_char\28hb_buffer_t*\2c\20unsigned\20int\29 +1957:log2f +1958:log +1959:less_or_equal_ulps\28float\2c\20float\2c\20int\29 +1960:is_consonant\28hb_glyph_info_t\20const&\29 +1961:int\20const*\20std::__2::find\5babi:ne180100\5d\28int\20const*\2c\20int\20const*\2c\20int\20const&\29 +1962:hb_vector_t::push\28\29 +1963:hb_vector_t::resize\28int\2c\20bool\2c\20bool\29 +1964:hb_unicode_funcs_destroy +1965:hb_serialize_context_t::pop_discard\28\29 +1966:hb_paint_funcs_t::push_root_transform\28void*\2c\20hb_font_t\20const*\29 +1967:hb_paint_funcs_t::pop_clip\28void*\29 +1968:hb_ot_map_t::feature_map_t\20const*\20hb_vector_t::bsearch\28unsigned\20int\20const&\2c\20hb_ot_map_t::feature_map_t\20const*\29\20const +1969:hb_lazy_loader_t\2c\20hb_face_t\2c\2024u\2c\20OT::GDEF_accelerator_t>::get_stored\28\29\20const +1970:hb_indic_would_substitute_feature_t::init\28hb_ot_map_t\20const*\2c\20unsigned\20int\2c\20bool\29 +1971:hb_hashmap_t::del\28unsigned\20int\20const&\29 +1972:hb_font_t::get_glyph_v_advance\28unsigned\20int\29 +1973:hb_font_t::get_glyph_extents\28unsigned\20int\2c\20hb_glyph_extents_t*\29 +1974:hb_buffer_t::_set_glyph_flags\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +1975:hb_buffer_create_similar +1976:gray_set_cell +1977:getenv +1978:ft_service_list_lookup +1979:fseek +1980:free_ctx +1981:find_table +1982:fillcheckrect\28int\2c\20int\2c\20int\2c\20int\2c\20SkBlitter*\29 +1983:fflush +1984:fclose +1985:expm1 +1986:expf +1987:emscripten_futex_wait +1988:crc_word +1989:classify\28skcms_TransferFunction\20const&\2c\20TF_PQish*\2c\20TF_HLGish*\29 +1990:choose_bmp_texture_colortype\28GrCaps\20const*\2c\20SkBitmap\20const&\29 +1991:char*\20sktext::gpu::BagOfBytes::allocateBytesFor\28int\29 +1992:cff_parse_fixed +1993:cf2_interpT2CharString +1994:cf2_hintmap_insertHint +1995:cf2_hintmap_build +1996:cf2_glyphpath_moveTo +1997:cf2_glyphpath_lineTo +1998:bool\20std::__2::operator==\5babi:ne180100\5d>\28std::__2::vector>\20const&\2c\20std::__2::vector>\20const&\29 +1999:bool\20std::__2::__less::operator\28\29\5babi:nn180100\5d\28unsigned\20int\20const&\2c\20unsigned\20long\20const&\29\20const +2000:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +2001:blit_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +2002:afm_tokenize +2003:af_glyph_hints_reload +2004:a_dec +2005:_hb_glyph_info_set_unicode_props\28hb_glyph_info_t*\2c\20hb_buffer_t*\29 +2006:_hb_draw_funcs_set_middle\28hb_draw_funcs_t*\2c\20void*\2c\20void\20\28*\29\28void*\29\29 +2007:__wasm_setjmp +2008:__wasi_syscall_ret +2009:__syscall_ret +2010:__sin +2011:__cos +2012:\28anonymous\20namespace\29::valid_unit_divide\28float\2c\20float\2c\20float*\29 +2013:\28anonymous\20namespace\29::draw_stencil_rect\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrHardClip\20const&\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +2014:\28anonymous\20namespace\29::can_reorder\28SkRect\20const&\2c\20SkRect\20const&\29 +2015:\28anonymous\20namespace\29::SkBlurImageFilter::~SkBlurImageFilter\28\29 +2016:\28anonymous\20namespace\29::FillRectOpImpl::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +2017:Skwasm::createRRect\28float\20const*\29 +2018:SkWriter32::writeSampling\28SkSamplingOptions\20const&\29 +2019:SkWriter32::writePad\28void\20const*\2c\20unsigned\20long\29 +2020:SkTextBlobRunIterator::next\28\29 +2021:SkTextBlobBuilder::make\28\29 +2022:SkTSect::addOne\28\29 +2023:SkTMultiMap::remove\28skgpu::ScratchKey\20const&\2c\20GrGpuResource\20const*\29 +2024:SkTLazy::set\28SkPath\20const&\29 +2025:SkTDArray::append\28\29 +2026:SkTDArray::append\28\29 +2027:SkSurfaces::RenderTarget\28GrRecordingContext*\2c\20skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20int\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const*\2c\20bool\2c\20bool\29 +2028:SkSurfaces::Raster\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20SkSurfaceProps\20const*\29 +2029:SkStrokeRec::isFillStyle\28\29\20const +2030:SkString::appendU32\28unsigned\20int\29 +2031:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +2032:SkShaders::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29 +2033:SkShaderUtils::GLSLPrettyPrint::appendChar\28char\29 +2034:SkScopeExit::~SkScopeExit\28\29 +2035:SkScan::FillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\29 +2036:SkSL::is_scalar_op_matrix\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +2037:SkSL::evaluate_n_way_intrinsic\28SkSL::Context\20const&\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +2038:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitType\28SkSL::Type\20const&\29 +2039:SkSL::Variable::initialValue\28\29\20const +2040:SkSL::Variable*\20SkSL::SymbolTable::takeOwnershipOfSymbol\28std::__2::unique_ptr>\29 +2041:SkSL::Type::canCoerceTo\28SkSL::Type\20const&\2c\20bool\29\20const +2042:SkSL::SymbolTable::takeOwnershipOfString\28std::__2::basic_string\2c\20std::__2::allocator>\29 +2043:SkSL::RP::pack_nybbles\28SkSpan\29 +2044:SkSL::RP::Generator::foldComparisonOp\28SkSL::Operator\2c\20int\29 +2045:SkSL::RP::Generator::emitTraceScope\28int\29 +2046:SkSL::RP::Generator::createStack\28\29 +2047:SkSL::RP::Builder::trace_var\28int\2c\20SkSL::RP::SlotRange\29 +2048:SkSL::RP::Builder::jump\28int\29 +2049:SkSL::RP::Builder::dot_floats\28int\29 +2050:SkSL::RP::Builder::branch_if_no_lanes_active\28int\29 +2051:SkSL::RP::AutoStack::~AutoStack\28\29 +2052:SkSL::RP::AutoStack::pushClone\28int\29 +2053:SkSL::Position::rangeThrough\28SkSL::Position\29\20const +2054:SkSL::PipelineStage::PipelineStageCodeGenerator::AutoOutputBuffer::~AutoOutputBuffer\28\29 +2055:SkSL::Parser::type\28SkSL::Modifiers*\29 +2056:SkSL::Parser::parseArrayDimensions\28SkSL::Position\2c\20SkSL::Type\20const**\29 +2057:SkSL::Parser::modifiers\28\29 +2058:SkSL::Parser::assignmentExpression\28\29 +2059:SkSL::Parser::arraySize\28long\20long*\29 +2060:SkSL::ModifierFlags::paddedDescription\28\29\20const +2061:SkSL::Literal::MakeBool\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20bool\29 +2062:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29::$_2::operator\28\29\28SkSL::ExpressionArray\20const&\29\20const +2063:SkSL::IRHelpers::Swizzle\28std::__2::unique_ptr>\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29\20const +2064:SkSL::GLSLCodeGenerator::writeTypePrecision\28SkSL::Type\20const&\29 +2065:SkSL::FunctionDeclaration::getMainCoordsParameter\28\29\20const +2066:SkSL::ExpressionArray::clone\28\29\20const +2067:SkSL::ConstantFolder::GetConstantValue\28SkSL::Expression\20const&\2c\20double*\29 +2068:SkSL::ConstantFolder::GetConstantInt\28SkSL::Expression\20const&\2c\20long\20long*\29 +2069:SkSL::Compiler::~Compiler\28\29 +2070:SkSL::Compiler::errorText\28bool\29 +2071:SkSL::Compiler::Compiler\28\29 +2072:SkSL::Analysis::IsTrivialExpression\28SkSL::Expression\20const&\29 +2073:SkRuntimeEffectPriv::TransformUniforms\28SkSpan\2c\20sk_sp\2c\20SkColorSpace\20const*\29 +2074:SkRuntimeEffectBuilder::~SkRuntimeEffectBuilder\28\29 +2075:SkRuntimeEffectBuilder::makeShader\28SkMatrix\20const*\29\20const +2076:SkRuntimeEffectBuilder::SkRuntimeEffectBuilder\28sk_sp\29 +2077:SkRuntimeEffectBuilder::BuilderChild&\20SkRuntimeEffectBuilder::BuilderChild::operator=\28sk_sp\29 +2078:SkRuntimeEffect::findChild\28std::__2::basic_string_view>\29\20const +2079:SkRegion::setPath\28SkPath\20const&\2c\20SkRegion\20const&\29 +2080:SkRegion::Iterator::Iterator\28SkRegion\20const&\29 +2081:SkReduceOrder::Quad\28SkPoint\20const*\2c\20SkPoint*\29 +2082:SkRect::sort\28\29 +2083:SkRect::joinPossiblyEmptyRect\28SkRect\20const&\29 +2084:SkRasterPipeline_BinaryOpCtx*\20SkArenaAlloc::make\28SkRasterPipeline_BinaryOpCtx\20const&\29 +2085:SkRasterPipelineBlitter::appendClipScale\28SkRasterPipeline*\29\20const +2086:SkRasterPipelineBlitter::appendClipLerp\28SkRasterPipeline*\29\20const +2087:SkRRect::setRectRadii\28SkRect\20const&\2c\20SkPoint\20const*\29 +2088:SkRGBA4f<\28SkAlphaType\292>::toBytes_RGBA\28\29\20const +2089:SkRGBA4f<\28SkAlphaType\292>::fitsInBytes\28\29\20const +2090:SkPointPriv::EqualsWithinTolerance\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\29 +2091:SkPoint*\20SkRecorder::copy\28SkPoint\20const*\2c\20unsigned\20long\29 +2092:SkPoint*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29 +2093:SkPixmap::reset\28\29 +2094:SkPixmap::computeByteSize\28\29\20const +2095:SkPictureRecord::addImage\28SkImage\20const*\29 +2096:SkPathRef::SkPathRef\28int\2c\20int\2c\20int\29 +2097:SkPathPriv::ComputeFirstDirection\28SkPath\20const&\29 +2098:SkPath::isLine\28SkPoint*\29\20const +2099:SkParsePath::ToSVGString\28SkPath\20const&\2c\20SkParsePath::PathEncoding\29::$_0::operator\28\29\28char\2c\20SkPoint\20const*\2c\20unsigned\20long\29\20const +2100:SkPaintPriv::ComputeLuminanceColor\28SkPaint\20const&\29 +2101:SkPaint::nothingToDraw\28\29\20const +2102:SkOpSpan::release\28SkOpPtT\20const*\29 +2103:SkOpContourBuilder::addCurve\28SkPath::Verb\2c\20SkPoint\20const*\2c\20float\29 +2104:SkMipmap::Build\28SkPixmap\20const&\2c\20SkDiscardableMemory*\20\28*\29\28unsigned\20long\29\2c\20bool\29 +2105:SkMeshSpecification::Varying::Varying\28SkMeshSpecification::Varying&&\29 +2106:SkMatrix::mapOrigin\28\29\20const +2107:SkMatrix::decomposeScale\28SkSize*\2c\20SkMatrix*\29\20const +2108:SkMaskFilterBase::getFlattenableType\28\29\20const +2109:SkMaskFilter::MakeBlur\28SkBlurStyle\2c\20float\2c\20bool\29 +2110:SkM44::SkM44\28SkMatrix\20const&\29 +2111:SkJSONWriter::endArray\28\29 +2112:SkJSONWriter::beginValue\28bool\29 +2113:SkJSONWriter::beginArray\28char\20const*\2c\20bool\29 +2114:SkIntersections::insertNear\28double\2c\20double\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29 +2115:SkImageShader::Make\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +2116:SkImageGenerator::onRefEncodedData\28\29 +2117:SkIRect::inset\28int\2c\20int\29 +2118:SkGradientBaseShader::flatten\28SkWriteBuffer&\29\20const +2119:SkFont::getMetrics\28SkFontMetrics*\29\20const +2120:SkFont::SkFont\28\29 +2121:SkFindQuadMaxCurvature\28SkPoint\20const*\29 +2122:SkFDot6Div\28int\2c\20int\29 +2123:SkEvalQuadAt\28SkPoint\20const*\2c\20float\29 +2124:SkEvalCubicAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29 +2125:SkEdgeClipper::appendVLine\28float\2c\20float\2c\20float\2c\20bool\29 +2126:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29 +2127:SkDrawShadowMetrics::GetSpotParams\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float*\2c\20float*\2c\20SkPoint*\29 +2128:SkDraw::SkDraw\28\29 +2129:SkDevice::setLocalToDevice\28SkM44\20const&\29 +2130:SkDevice::setGlobalCTM\28SkM44\20const&\29 +2131:SkDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +2132:SkDLine::exactPoint\28SkDPoint\20const&\29\20const +2133:SkColorSpace::MakeSRGBLinear\28\29 +2134:SkColorInfo::isOpaque\28\29\20const +2135:SkChopCubicAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +2136:SkCanvas::getLocalClipBounds\28\29\20const +2137:SkCanvas::drawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +2138:SkCanvas::drawIRect\28SkIRect\20const&\2c\20SkPaint\20const&\29 +2139:SkBulkGlyphMetrics::glyphs\28SkSpan\29 +2140:SkBlockAllocator::releaseBlock\28SkBlockAllocator::Block*\29 +2141:SkBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +2142:SkBlendMode_AppendStages\28SkBlendMode\2c\20SkRasterPipeline*\29 +2143:SkBitmap::tryAllocPixels\28SkBitmap::Allocator*\29 +2144:SkBitmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +2145:SkBitmap::operator=\28SkBitmap\20const&\29 +2146:SkBitmap::getGenerationID\28\29\20const +2147:SkAutoPixmapStorage::SkAutoPixmapStorage\28\29 +2148:SkAutoDeviceTransformRestore::~SkAutoDeviceTransformRestore\28\29 +2149:SkAutoDeviceTransformRestore::SkAutoDeviceTransformRestore\28SkDevice*\2c\20SkMatrix\20const&\29 +2150:SkAutoCanvasRestore::SkAutoCanvasRestore\28SkCanvas*\2c\20bool\29 +2151:SkAAClipBlitter::~SkAAClipBlitter\28\29 +2152:SkAAClip::setRegion\28SkRegion\20const&\29::$_0::operator\28\29\28unsigned\20char\2c\20int\29\20const +2153:SkAAClip::findX\28unsigned\20char\20const*\2c\20int\2c\20int*\29\20const +2154:SkAAClip::findRow\28int\2c\20int*\29\20const +2155:SkAAClip::Builder::Blitter::~Blitter\28\29 +2156:SaveErrorCode +2157:RoughlyEqualUlps\28float\2c\20float\29 +2158:R.10093 +2159:PS_Conv_ToInt +2160:OT::hmtxvmtx::accelerator_t::get_leading_bearing_without_var_unscaled\28unsigned\20int\2c\20int*\29\20const +2161:OT::hb_ot_apply_context_t::replace_glyph\28unsigned\20int\29 +2162:OT::fvar::get_axes\28\29\20const +2163:OT::Layout::GPOS_impl::ValueFormat::sanitize_values_stride_unsafe\28hb_sanitize_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +2164:OT::DeltaSetIndexMap::map\28unsigned\20int\29\20const +2165:Normalize +2166:Ins_Goto_CodeRange +2167:GrTriangulator::setBottom\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2168:GrTriangulator::VertexList::append\28GrTriangulator::VertexList\20const&\29 +2169:GrTriangulator::Line::normalize\28\29 +2170:GrTriangulator::Edge::disconnect\28\29 +2171:GrThreadSafeCache::find\28skgpu::UniqueKey\20const&\29 +2172:GrThreadSafeCache::add\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2173:GrTextureEffect::texture\28\29\20const +2174:GrSurfaceProxyView::Copy\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\29 +2175:GrSurfaceProxyPriv::doLazyInstantiation\28GrResourceProvider*\29 +2176:GrSurface::~GrSurface\28\29 +2177:GrStyledShape::simplify\28\29 +2178:GrStyle::applies\28\29\20const +2179:GrSimpleMeshDrawOpHelperWithStencil::fixedFunctionFlags\28\29\20const +2180:GrSimpleMeshDrawOpHelper::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20GrProcessorAnalysisColor*\29 +2181:GrSimpleMeshDrawOpHelper::detachProcessorSet\28\29 +2182:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrPipeline\20const*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrUserStencilSettings\20const*\29 +2183:GrSimpleMesh::setIndexedPatterned\28sk_sp\2c\20int\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int\29 +2184:GrShape::setRect\28SkRect\20const&\29 +2185:GrShape::GrShape\28GrShape\20const&\29 +2186:GrShaderVar::addModifier\28char\20const*\29 +2187:GrSWMaskHelper::~GrSWMaskHelper\28\29 +2188:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20void\20const*\2c\20skgpu::UniqueKey\20const&\29 +2189:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20skgpu::UniqueKey\20const&\2c\20void\20\28*\29\28skgpu::VertexWriter\2c\20unsigned\20long\29\29 +2190:GrResourceCache::purgeAsNeeded\28\29 +2191:GrRenderTask::addDependency\28GrDrawingManager*\2c\20GrSurfaceProxy*\2c\20skgpu::Mipmapped\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +2192:GrRecordingContextPriv::makeSFC\28GrImageInfo\2c\20std::__2::basic_string_view>\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2193:GrQuad::asRect\28SkRect*\29\20const +2194:GrProcessorSet::operator!=\28GrProcessorSet\20const&\29\20const +2195:GrPixmapBase::GrPixmapBase\28GrImageInfo\2c\20void\20const*\2c\20unsigned\20long\29 +2196:GrPipeline::getXferProcessor\28\29\20const +2197:GrNativeRect::asSkIRect\28\29\20const +2198:GrGeometryProcessor::ProgramImpl::~ProgramImpl\28\29 +2199:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +2200:GrGLSLShaderBuilder::defineConstant\28char\20const*\2c\20float\29 +2201:GrGLSLShaderBuilder::addFeature\28unsigned\20int\2c\20char\20const*\29 +2202:GrGLSLProgramBuilder::nameVariable\28char\2c\20char\20const*\2c\20bool\29 +2203:GrGLSLColorSpaceXformHelper::setData\28GrGLSLProgramDataManager\20const&\2c\20GrColorSpaceXform\20const*\29 +2204:GrGLSLColorSpaceXformHelper::emitCode\28GrGLSLUniformHandler*\2c\20GrColorSpaceXform\20const*\2c\20unsigned\20int\29 +2205:GrGLGpu::flushColorWrite\28bool\29 +2206:GrGLGpu::bindTexture\28int\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20GrGLTexture*\29 +2207:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkMatrix\20const&\29 +2208:GrFragmentProcessor::visitWithImpls\28std::__2::function\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\20const +2209:GrFragmentProcessor::visitProxies\28std::__2::function\20const&\29\20const +2210:GrFragmentProcessor::ColorMatrix\28std::__2::unique_ptr>\2c\20float\20const*\2c\20bool\2c\20bool\2c\20bool\29 +2211:GrDstProxyView::operator=\28GrDstProxyView\20const&\29 +2212:GrDrawingManager::closeActiveOpsTask\28\29 +2213:GrDrawingManager::appendTask\28sk_sp\29 +2214:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20sk_sp\29 +2215:GrColorSpaceXform::XformKey\28GrColorSpaceXform\20const*\29 +2216:GrColorSpaceXform::Make\28GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +2217:GrColorInfo::GrColorInfo\28GrColorInfo\20const&\29 +2218:GrCaps::isFormatCompressed\28GrBackendFormat\20const&\29\20const +2219:GrBufferAllocPool::~GrBufferAllocPool\28\29 +2220:GrBufferAllocPool::putBack\28unsigned\20long\29 +2221:GrBlurUtils::convolve_gaussian\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20SkIRect\2c\20SkIRect\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkBackingFit\29::$_1::operator\28\29\28SkIRect\29\20const +2222:GrAAConvexTessellator::lineTo\28SkPoint\20const&\2c\20GrAAConvexTessellator::CurveState\29 +2223:FwDCubicEvaluator::restart\28int\29 +2224:FT_Vector_Transform +2225:FT_Select_Charmap +2226:FT_Lookup_Renderer +2227:FT_Get_Module_Interface +2228:CFF::opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +2229:CFF::arg_stack_t::push_int\28int\29 +2230:CFF::CFFIndex>::offset_at\28unsigned\20int\29\20const +2231:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::operator++\28\29 +2232:ActiveEdge::intersect\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29\20const +2233:AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t\28\29 +2234:AAT::hb_aat_apply_context_t::hb_aat_apply_context_t\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20hb_blob_t*\29 +2235:2016 +2236:2017 +2237:2018 +2238:2019 +2239:2020 +2240:2021 +2241:2022 +2242:wmemchr +2243:void\20std::__2::unique_ptr>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot*\2c\200>\28skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot*\29 +2244:void\20std::__2::reverse\5babi:nn180100\5d\28unsigned\20int*\2c\20unsigned\20int*\29 +2245:void\20std::__2::__variant_detail::__assignment>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29 +2246:void\20hb_serialize_context_t::add_link\2c\20true>>\28OT::OffsetTo\2c\20true>&\2c\20unsigned\20int\2c\20hb_serialize_context_t::whence_t\2c\20unsigned\20int\29 +2247:void\20hb_sanitize_context_t::set_object\28AAT::KerxSubTable\20const*\29 +2248:void\20SkSafeUnref\28sktext::gpu::TextStrike*\29 +2249:void\20SkSafeUnref\28GrArenas*\29 +2250:void\20SkSL::RP::unpack_nybbles_to_offsets\28unsigned\20int\2c\20SkSpan\29 +2251:unlock +2252:ubidi_setPara_skia +2253:ubidi_getCustomizedClass_skia +2254:tt_set_mm_blend +2255:tt_face_get_ps_name +2256:trinkle +2257:t1_builder_check_points +2258:subdivide\28SkConic\20const&\2c\20SkPoint*\2c\20int\29 +2259:std::__2::vector>\2c\20std::__2::allocator>>>::__swap_out_circular_buffer\28std::__2::__split_buffer>\2c\20std::__2::allocator>>&>&\29 +2260:std::__2::vector>\2c\20std::__2::allocator>>>::__clear\5babi:ne180100\5d\28\29 +2261:std::__2::vector>\2c\20std::__2::allocator>>>::~vector\5babi:ne180100\5d\28\29 +2262:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +2263:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +2264:std::__2::vector\2c\20std::__2::allocator>>::push_back\5babi:ne180100\5d\28sk_sp\20const&\29 +2265:std::__2::vector>::push_back\5babi:ne180100\5d\28float&&\29 +2266:std::__2::vector>::push_back\5babi:ne180100\5d\28char\20const*&&\29 +2267:std::__2::vector>::__move_assign\28std::__2::vector>&\2c\20std::__2::integral_constant\29 +2268:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +2269:std::__2::unordered_map\2c\20std::__2::equal_to\2c\20std::__2::allocator>>::operator\5b\5d\28GrTriangulator::Vertex*\20const&\29 +2270:std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2271:std::__2::unique_ptr::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2272:std::__2::unique_ptr::Traits>::Slot\20\5b\5d\2c\20std::__2::default_delete::Traits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2273:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skgpu::ganesh::SurfaceDrawContext*\29 +2274:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2275:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skgpu::ganesh::PathRendererChain*\29 +2276:std::__2::unique_ptr\20\5b\5d\2c\20std::__2::default_delete\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2277:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28hb_face_t*\29 +2278:std::__2::unique_ptr::release\5babi:nn180100\5d\28\29 +2279:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2280:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2281:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2282:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2283:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2284:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2285:std::__2::mutex::unlock\28\29 +2286:std::__2::mutex::lock\28\29 +2287:std::__2::moneypunct::do_decimal_point\28\29\20const +2288:std::__2::moneypunct::pos_format\5babi:nn180100\5d\28\29\20const +2289:std::__2::moneypunct::do_decimal_point\28\29\20const +2290:std::__2::locale::locale\28std::__2::locale\20const&\29 +2291:std::__2::locale::classic\28\29 +2292:std::__2::istreambuf_iterator>::istreambuf_iterator\5babi:nn180100\5d\28std::__2::basic_istream>&\29 +2293:std::__2::function::operator\28\29\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +2294:std::__2::function::operator\28\29\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29\20const +2295:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d\28unsigned\20int&\2c\20unsigned\20int&\29 +2296:std::__2::deque>::pop_front\28\29 +2297:std::__2::deque>::begin\5babi:ne180100\5d\28\29 +2298:std::__2::ctype::toupper\5babi:nn180100\5d\28char\29\20const +2299:std::__2::chrono::duration>::duration\5babi:nn180100\5d\28long\20long\20const&\29 +2300:std::__2::basic_string_view>::find\5babi:ne180100\5d\28char\2c\20unsigned\20long\29\20const +2301:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +2302:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +2303:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +2304:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +2305:std::__2::basic_string\2c\20std::__2::allocator>::pop_back\5babi:ne180100\5d\28\29 +2306:std::__2::basic_string\2c\20std::__2::allocator>::operator=\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +2307:std::__2::basic_string\2c\20std::__2::allocator>::__get_short_size\5babi:nn180100\5d\28\29\20const +2308:std::__2::basic_string\2c\20std::__2::allocator>::__assign_external\28char\20const*\2c\20unsigned\20long\29 +2309:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:ne180100\5d\28\29\20const +2310:std::__2::basic_streambuf>::__pbump\5babi:nn180100\5d\28long\29 +2311:std::__2::basic_ostream>::sentry::operator\20bool\5babi:nn180100\5d\28\29\20const +2312:std::__2::basic_iostream>::~basic_iostream\28\29 +2313:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::OperatorKind&&\2c\20std::__2::unique_ptr>&&\29 +2314:std::__2::__tuple_impl\2c\20sk_sp\2c\20sk_sp>::~__tuple_impl\28\29 +2315:std::__2::__tuple_impl\2c\20GrFragmentProcessor\20const*\2c\20GrGeometryProcessor::ProgramImpl::TransformInfo>::__tuple_impl\28std::__2::__tuple_impl\2c\20GrFragmentProcessor\20const*\2c\20GrGeometryProcessor::ProgramImpl::TransformInfo>&&\29 +2316:std::__2::__tree\2c\20std::__2::__map_value_compare\2c\20std::__2::less\2c\20true>\2c\20std::__2::allocator>>::~__tree\28\29 +2317:std::__2::__throw_bad_variant_access\5babi:ne180100\5d\28\29 +2318:std::__2::__split_buffer>\2c\20std::__2::allocator>>&>::~__split_buffer\28\29 +2319:std::__2::__split_buffer>::push_front\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +2320:std::__2::__split_buffer>::push_back\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\20const&\29 +2321:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +2322:std::__2::__split_buffer\2c\20std::__2::allocator>&>::~__split_buffer\28\29 +2323:std::__2::__split_buffer\2c\20std::__2::allocator>&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator>&\29 +2324:std::__2::__shared_count::__release_shared\5babi:nn180100\5d\28\29 +2325:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +2326:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +2327:std::__2::__num_put_base::__format_int\28char*\2c\20char\20const*\2c\20bool\2c\20unsigned\20int\29 +2328:std::__2::__num_put_base::__format_float\28char*\2c\20char\20const*\2c\20unsigned\20int\29 +2329:std::__2::__itoa::__append8\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2330:std::__2::__function::__value_func::operator\28\29\5babi:ne180100\5d\28\29\20const +2331:std::__2::__function::__value_func::operator\28\29\5babi:ne180100\5d\28SkSL::Variable\20const&\29\20const +2332:skvx::Vec<8\2c\20unsigned\20short>\20skvx::operator+<8\2c\20unsigned\20short\2c\20unsigned\20short\2c\20void>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20short\29 +2333:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator&<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +2334:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator>=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +2335:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20double\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20double\29 +2336:sktext::gpu::VertexFiller::deviceRectAndCheckTransform\28SkMatrix\20const&\29\20const +2337:sktext::gpu::GlyphVector::packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29 +2338:sktext::SkStrikePromise::strike\28\29 +2339:skif::\28anonymous\20namespace\29::draw_tiled_border\28SkCanvas*\2c\20SkTileMode\2c\20SkPaint\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::LayerSpace\2c\20skif::LayerSpace\29::$_1::operator\28\29\28SkPoint\20const&\2c\20SkPoint\20const&\29\20const +2340:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +2341:skif::LayerSpace::postConcat\28skif::LayerSpace\20const&\29 +2342:skif::FilterResult::subset\28skif::LayerSpace\20const&\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +2343:skif::FilterResult::getAnalyzedShaderView\28skif::Context\20const&\2c\20SkSamplingOptions\20const&\2c\20SkEnumBitMask\29\20const +2344:skif::FilterResult::applyTransform\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkSamplingOptions\20const&\29\20const +2345:skif::FilterResult::applyCrop\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkTileMode\29\20const +2346:skif::FilterResult::analyzeBounds\28SkMatrix\20const&\2c\20SkIRect\20const&\2c\20skif::FilterResult::BoundsScope\29\20const +2347:skif::FilterResult::Builder::add\28skif::FilterResult\20const&\2c\20std::__2::optional>\2c\20SkEnumBitMask\2c\20SkSamplingOptions\20const&\29 +2348:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +2349:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +2350:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair&&\29 +2351:skia_private::THashTable::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +2352:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair&&\29 +2353:skia_private::THashTable::Pair\2c\20SkSL::Analysis::SpecializedCallKey\2c\20skia_private::THashMap::Pair>::Hash\28SkSL::Analysis::SpecializedCallKey\20const&\29 +2354:skia_private::THashTable::Traits>::uncheckedSet\28long\20long&&\29 +2355:skia_private::THashTable::Traits>::uncheckedSet\28int&&\29 +2356:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::resize\28int\29 +2357:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::find\28unsigned\20int\20const&\29\20const +2358:skia_private::THashMap::find\28unsigned\20int\20const&\29\20const +2359:skia_private::THashMap::operator\5b\5d\28SkSL::Variable\20const*\20const&\29 +2360:skia_private::TArray::push_back_raw\28int\29 +2361:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +2362:skia_private::TArray>\2c\20true>::destroyAll\28\29 +2363:skia_private::TArray>\2c\20true>::push_back\28std::__2::unique_ptr>&&\29 +2364:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2365:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +2366:skia_private::TArray::~TArray\28\29 +2367:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2368:skia_private::TArray::~TArray\28\29 +2369:skia_private::TArray\2c\20true>::~TArray\28\29 +2370:skia_private::TArray::push_back_n\28int\2c\20int\20const&\29 +2371:skia_private::TArray::reserve_exact\28int\29 +2372:skia_private::TArray<\28anonymous\20namespace\29::MeshOp::Mesh\2c\20true>::preallocateNewData\28int\2c\20double\29 +2373:skia_private::TArray<\28anonymous\20namespace\29::MeshOp::Mesh\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +2374:skia_private::TArray::clear\28\29 +2375:skia_private::TArray::operator=\28skia_private::TArray&&\29 +2376:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2377:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2378:skia_private::TArray::push_back\28GrRenderTask*&&\29 +2379:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +2380:skia_private::AutoSTMalloc<4ul\2c\20SkFontArguments::Palette::Override\2c\20void>::AutoSTMalloc\28unsigned\20long\29 +2381:skia_private::AutoSTArray<24\2c\20unsigned\20int>::reset\28int\29 +2382:skia_png_zstream_error +2383:skia_png_read_data +2384:skia_png_get_int_32 +2385:skia_png_chunk_unknown_handling +2386:skia_png_calloc +2387:skia::textlayout::TextWrapper::getClustersTrimmedWidth\28\29 +2388:skia::textlayout::TextWrapper::TextStretch::startFrom\28skia::textlayout::Cluster*\2c\20unsigned\20long\29 +2389:skia::textlayout::TextWrapper::TextStretch::extend\28skia::textlayout::Cluster*\29 +2390:skia::textlayout::TextLine::measureTextInsideOneRun\28skia::textlayout::SkRange\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20float\2c\20bool\2c\20skia::textlayout::TextLine::TextAdjustment\29\20const +2391:skia::textlayout::TextLine::isLastLine\28\29\20const +2392:skia::textlayout::Run::Run\28skia::textlayout::Run\20const&\29 +2393:skia::textlayout::ParagraphImpl::getLineNumberAt\28unsigned\20long\29\20const +2394:skia::textlayout::ParagraphImpl::findPreviousGraphemeBoundary\28unsigned\20long\29\20const +2395:skia::textlayout::ParagraphCacheKey::~ParagraphCacheKey\28\29 +2396:skia::textlayout::ParagraphBuilderImpl::startStyledBlock\28\29 +2397:skia::textlayout::OneLineShaper::RunBlock&\20std::__2::vector>::emplace_back\28skia::textlayout::OneLineShaper::RunBlock&\29 +2398:skia::textlayout::OneLineShaper::FontKey::FontKey\28skia::textlayout::OneLineShaper::FontKey&&\29 +2399:skia::textlayout::InternalLineMetrics::updateLineMetrics\28skia::textlayout::InternalLineMetrics&\29 +2400:skia::textlayout::InternalLineMetrics::runTop\28skia::textlayout::Run\20const*\2c\20skia::textlayout::LineMetricStyle\29\20const +2401:skia::textlayout::FontCollection::getFontManagerOrder\28\29\20const +2402:skia::textlayout::Decorations::calculateGaps\28skia::textlayout::TextLine::ClipContext\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\29 +2403:skia::textlayout::Cluster::runOrNull\28\29\20const +2404:skgpu::tess::PatchStride\28skgpu::tess::PatchAttribs\29 +2405:skgpu::tess::MiddleOutPolygonTriangulator::MiddleOutPolygonTriangulator\28int\2c\20SkPoint\29 +2406:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::fixedFunctionFlags\28\29\20const +2407:skgpu::ganesh::SurfaceFillContext::~SurfaceFillContext\28\29 +2408:skgpu::ganesh::SurfaceFillContext::replaceOpsTask\28\29 +2409:skgpu::ganesh::SurfaceDrawContext::fillPixelsWithLocalMatrix\28GrClip\20const*\2c\20GrPaint&&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\29 +2410:skgpu::ganesh::SurfaceDrawContext::drawShape\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\29 +2411:skgpu::ganesh::SurfaceDrawContext::drawPaint\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\29 +2412:skgpu::ganesh::SurfaceDrawContext::MakeWithFallback\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2413:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29 +2414:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29::$_0::$_0\28$_0&&\29 +2415:skgpu::ganesh::SurfaceContext::PixelTransferResult::operator=\28skgpu::ganesh::SurfaceContext::PixelTransferResult&&\29 +2416:skgpu::ganesh::SupportedTextureFormats\28GrImageContext\20const&\29::$_0::operator\28\29\28SkYUVAPixmapInfo::DataType\2c\20int\29\20const +2417:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +2418:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::coverageMode\28\29\20const +2419:skgpu::ganesh::PathInnerTriangulateOp::pushFanFillProgram\28GrTessellationShader::ProgramArgs\20const&\2c\20GrUserStencilSettings\20const*\29 +2420:skgpu::ganesh::OpsTask::deleteOps\28\29 +2421:skgpu::ganesh::OpsTask::OpChain::List::operator=\28skgpu::ganesh::OpsTask::OpChain::List&&\29 +2422:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29::$_0::operator\28\29\28int\29\20const +2423:skgpu::ganesh::ClipStack::clipRect\28SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrAA\2c\20SkClipOp\29 +2424:skgpu::TClientMappedBufferManager::BufferFinishedMessage::BufferFinishedMessage\28skgpu::TClientMappedBufferManager::BufferFinishedMessage&&\29 +2425:skgpu::Swizzle::Concat\28skgpu::Swizzle\20const&\2c\20skgpu::Swizzle\20const&\29 +2426:skgpu::Swizzle::CToI\28char\29 +2427:sk_sp::reset\28SkMipmap*\29 +2428:sk_sp::~sk_sp\28\29 +2429:sk_sp::reset\28SkColorSpace*\29 +2430:sk_sp::~sk_sp\28\29 +2431:sk_sp::~sk_sp\28\29 +2432:skData_getSize +2433:shr +2434:shl +2435:set_result_path\28SkPath*\2c\20SkPath\20const&\2c\20SkPathFillType\29 +2436:sect_with_horizontal\28SkPoint\20const*\2c\20float\29 +2437:roughly_between\28double\2c\20double\2c\20double\29 +2438:pthread_setspecific +2439:pt_to_line\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +2440:psh_calc_max_height +2441:ps_mask_set_bit +2442:ps_dimension_set_mask_bits +2443:ps_builder_check_points +2444:ps_builder_add_point +2445:png_colorspace_endpoints_match +2446:path_is_trivial\28SkPath\20const&\29::Trivializer::addTrivialContourPoint\28SkPoint\20const&\29 +2447:output_char\28hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +2448:operator!=\28SkRect\20const&\2c\20SkRect\20const&\29 +2449:nearly_equal\28double\2c\20double\29 +2450:mbrtowc +2451:mask_gamma_cache_mutex\28\29 +2452:map_rect_perspective\28SkRect\20const&\2c\20float\20const*\29::$_0::operator\28\29\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20const +2453:lock.9319 +2454:lineMetrics_getEndIndex +2455:is_smooth_enough\28SkAnalyticEdge*\2c\20SkAnalyticEdge*\2c\20int\29 +2456:is_ICC_signature_char +2457:interpolate_local\28float\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float*\2c\20float*\2c\20float*\29 +2458:int\20_hb_cmp_method>\28void\20const*\2c\20void\20const*\29 +2459:init_file_lock +2460:ilogbf +2461:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +2462:hb_vector_t\2c\20false>::fini\28\29 +2463:hb_unicode_funcs_t::compose\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +2464:hb_syllabic_insert_dotted_circles\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +2465:hb_shape_full +2466:hb_serialize_context_t::~hb_serialize_context_t\28\29 +2467:hb_serialize_context_t::hb_serialize_context_t\28void*\2c\20unsigned\20int\29 +2468:hb_serialize_context_t::end_serialize\28\29 +2469:hb_paint_funcs_t::push_scale\28void*\2c\20float\2c\20float\29 +2470:hb_paint_funcs_t::push_clip_rectangle\28void*\2c\20float\2c\20float\2c\20float\2c\20float\29 +2471:hb_paint_extents_context_t::paint\28\29 +2472:hb_ot_map_builder_t::disable_feature\28unsigned\20int\29 +2473:hb_map_iter_t\2c\20OT::IntType\2c\20true>\20const>\2c\20hb_partial_t<2u\2c\20$_9\20const*\2c\20OT::ChainRuleSet\20const*>\2c\20\28hb_function_sortedness_t\290\2c\20\28void*\290>::__item__\28\29\20const +2474:hb_lazy_loader_t\2c\20hb_face_t\2c\2012u\2c\20OT::vmtx_accelerator_t>::get_stored\28\29\20const +2475:hb_lazy_loader_t\2c\20hb_face_t\2c\2038u\2c\20OT::sbix_accelerator_t>::do_destroy\28OT::sbix_accelerator_t*\29 +2476:hb_lazy_loader_t\2c\20hb_face_t\2c\205u\2c\20OT::hmtx_accelerator_t>::do_destroy\28OT::hmtx_accelerator_t*\29 +2477:hb_lazy_loader_t\2c\20hb_face_t\2c\2016u\2c\20OT::cff1_accelerator_t>::get_stored\28\29\20const +2478:hb_lazy_loader_t\2c\20hb_face_t\2c\2025u\2c\20OT::GSUB_accelerator_t>::do_destroy\28OT::GSUB_accelerator_t*\29 +2479:hb_lazy_loader_t\2c\20hb_face_t\2c\2026u\2c\20OT::GPOS_accelerator_t>::get_stored\28\29\20const +2480:hb_lazy_loader_t\2c\20hb_face_t\2c\2034u\2c\20hb_blob_t>::get\28\29\20const +2481:hb_language_from_string +2482:hb_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>\2c\20OT::HBGlyphID16&>::operator*\28\29 +2483:hb_hashmap_t::add\28unsigned\20int\20const&\29 +2484:hb_hashmap_t::alloc\28unsigned\20int\29 +2485:hb_font_t::parent_scale_position\28int*\2c\20int*\29 +2486:hb_font_t::get_h_extents_with_fallback\28hb_font_extents_t*\29 +2487:hb_buffer_t::output_glyph\28unsigned\20int\29 +2488:hb_buffer_t::copy_glyph\28\29 +2489:hb_buffer_t::clear_positions\28\29 +2490:hb_bounds_t*\20hb_vector_t::push\28hb_bounds_t&&\29 +2491:hb_blob_create_sub_blob +2492:hb_blob_create +2493:get_cache\28\29 +2494:ftell +2495:ft_var_readpackedpoints +2496:ft_glyphslot_free_bitmap +2497:float\20const*\20std::__2::min_element\5babi:ne180100\5d>\28float\20const*\2c\20float\20const*\2c\20std::__2::__less\29 +2498:float\20const*\20std::__2::max_element\5babi:ne180100\5d>\28float\20const*\2c\20float\20const*\2c\20std::__2::__less\29 +2499:filter_to_gl_mag_filter\28SkFilterMode\29 +2500:extractMaskSubset\28SkMask\20const&\2c\20SkIRect\2c\20int\2c\20int\29 +2501:exp +2502:equal_ulps\28float\2c\20float\2c\20int\2c\20int\29 +2503:do_proxy +2504:direct_blur_y\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2505:derivative_at_t\28double\20const*\2c\20double\29 +2506:crop_rect_edge\28SkRect\20const&\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float*\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +2507:cleanup_program\28GrGLGpu*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +2508:clean_paint_for_drawVertices\28SkPaint\29 +2509:clean_paint_for_drawImage\28SkPaint\20const*\29 +2510:check_edge_against_rect\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkRect\20const&\2c\20SkPathFirstDirection\29 +2511:checkOnCurve\28float\2c\20float\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +2512:char*\20sktext::gpu::BagOfBytes::allocateBytesFor\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +2513:cff_strcpy +2514:cff_size_get_globals_funcs +2515:cff_index_forget_element +2516:cf2_stack_setReal +2517:cf2_hint_init +2518:cf2_doStems +2519:cf2_doFlex +2520:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_4::operator\28\29\28float\29\20const +2521:buffer_verify_error\28hb_buffer_t*\2c\20hb_font_t*\2c\20char\20const*\2c\20...\29 +2522:bool\20hb_hashmap_t::has\28unsigned\20int\20const&\2c\20unsigned\20int**\29\20const +2523:bool\20hb_buffer_t::replace_glyphs\28unsigned\20int\2c\20unsigned\20int\2c\20OT::HBGlyphID16\20const*\29 +2524:bool\20OT::would_match_input>\28OT::hb_would_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\29 +2525:bool\20OT::match_input>\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +2526:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +2527:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +2528:blur_y_rect\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2529:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29::$_0::operator\28\29\28unsigned\20char*\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29\20const +2530:blitClippedMask\28SkBlitter*\2c\20SkMask\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29 +2531:approx_arc_length\28SkPoint\20const*\2c\20int\29 +2532:antifillrect\28SkIRect\20const&\2c\20SkBlitter*\29 +2533:afm_parser_read_int +2534:af_sort_pos +2535:af_latin_hints_compute_segments +2536:acosf +2537:a_swap.9365 +2538:_hb_glyph_info_get_lig_num_comps\28hb_glyph_info_t\20const*\29 +2539:__wake.9313 +2540:__uselocale +2541:__pthread_rwlock_unlock +2542:__math_xflow +2543:__cxxabiv1::__base_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +2544:\28anonymous\20namespace\29::make_vertices_spec\28bool\2c\20bool\29 +2545:\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29 +2546:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28unsigned\20int\20const*\29::operator\28\29\28unsigned\20int\20const*\29\20const +2547:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2548:\28anonymous\20namespace\29::SkBlurImageFilter::kernelBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\2c\20bool\29\20const +2549:\28anonymous\20namespace\29::RunIteratorQueue::insert\28SkShaper::RunIterator*\2c\20int\29 +2550:\28anonymous\20namespace\29::RunIteratorQueue::CompareEntry\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29 +2551:\28anonymous\20namespace\29::PathGeoBuilder::ensureSpace\28int\2c\20int\2c\20SkPoint\20const*\29 +2552:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMangledName\28char\20const*\29 +2553:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2554:\28anonymous\20namespace\29::FillRectOpImpl::vertexSpec\28\29\20const +2555:\28anonymous\20namespace\29::CacheImpl::removeInternal\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +2556:WriteRingBuffer +2557:TT_Load_Context +2558:Skwasm::makeCurrent\28unsigned\20long\29 +2559:SkipCode +2560:SkYUVAPixmaps::~SkYUVAPixmaps\28\29 +2561:SkYUVAPixmaps::operator=\28SkYUVAPixmaps\20const&\29 +2562:SkYUVAPixmaps::SkYUVAPixmaps\28\29 +2563:SkWriter32::writeRRect\28SkRRect\20const&\29 +2564:SkWriter32::writeMatrix\28SkMatrix\20const&\29 +2565:SkWriter32::snapshotAsData\28\29\20const +2566:SkWBuffer::write\28void\20const*\2c\20unsigned\20long\29 +2567:SkVertices::approximateSize\28\29\20const +2568:SkTextBlobBuilder::~SkTextBlobBuilder\28\29 +2569:SkTextBlob::RunRecord::textBuffer\28\29\20const +2570:SkTextBlob::RunRecord::clusterBuffer\28\29\20const +2571:SkTextBlob::RunRecord::StorageSize\28unsigned\20int\2c\20unsigned\20int\2c\20SkTextBlob::GlyphPositioning\2c\20SkSafeMath*\29 +2572:SkTextBlob::RunRecord::Next\28SkTextBlob::RunRecord\20const*\29 +2573:SkTSpan::oppT\28double\29\20const +2574:SkTSpan::closestBoundedT\28SkDPoint\20const&\29\20const +2575:SkTSect::updateBounded\28SkTSpan*\2c\20SkTSpan*\2c\20SkTSpan*\29 +2576:SkTSect::trim\28SkTSpan*\2c\20SkTSect*\29 +2577:SkTSect::removeSpanRange\28SkTSpan*\2c\20SkTSpan*\29 +2578:SkTSect::removeCoincident\28SkTSpan*\2c\20bool\29 +2579:SkTSect::deleteEmptySpans\28\29 +2580:SkTInternalLList::Entry>::remove\28SkLRUCache::Entry*\29 +2581:SkTInternalLList>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry>::remove\28SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\29 +2582:SkTInternalLList>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry>::remove\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\29 +2583:SkTDStorage::insert\28int\2c\20int\2c\20void\20const*\29 +2584:SkTDStorage::insert\28int\29 +2585:SkTDStorage::erase\28int\2c\20int\29 +2586:SkTDArray::push_back\28int\20const&\29 +2587:SkTBlockList::pushItem\28\29 +2588:SkStrokeRec::applyToPath\28SkPath*\2c\20SkPath\20const&\29\20const +2589:SkString::set\28char\20const*\29 +2590:SkString::Rec::Make\28char\20const*\2c\20unsigned\20long\29 +2591:SkStrikeSpec::MakeCanonicalized\28SkFont\20const&\2c\20SkPaint\20const*\29 +2592:SkStrikeCache::GlobalStrikeCache\28\29 +2593:SkStrike::glyph\28SkPackedGlyphID\29 +2594:SkSpriteBlitter::~SkSpriteBlitter\28\29 +2595:SkShadowTessellator::MakeSpot\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkPoint3\20const&\2c\20float\2c\20bool\2c\20bool\29 +2596:SkShaders::MatrixRec::apply\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2597:SkShaderBlurAlgorithm::renderBlur\28SkRuntimeEffectBuilder*\2c\20SkFilterMode\2c\20SkISize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const::$_0::operator\28\29\28SkIRect\20const&\29\20const +2598:SkShaderBase::appendRootStages\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2599:SkSemaphore::signal\28int\29 +2600:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +2601:SkScalerContext_FreeType::emboldenIfNeeded\28FT_FaceRec_*\2c\20FT_GlyphSlotRec_*\2c\20unsigned\20short\29 +2602:SkScaleToSides::AdjustRadii\28double\2c\20double\2c\20float*\2c\20float*\29 +2603:SkSamplingOptions::operator!=\28SkSamplingOptions\20const&\29\20const +2604:SkSTArenaAlloc<3332ul>::SkSTArenaAlloc\28unsigned\20long\29 +2605:SkSTArenaAlloc<1024ul>::SkSTArenaAlloc\28unsigned\20long\29 +2606:SkSL::write_stringstream\28SkSL::StringStream\20const&\2c\20SkSL::OutputStream&\29 +2607:SkSL::evaluate_3_way_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +2608:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29 +2609:SkSL::calculate_count\28double\2c\20double\2c\20double\2c\20bool\2c\20bool\29 +2610:SkSL::append_rtadjust_fixup_to_vertex_main\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::Block&\29::AppendRTAdjustFixupHelper::Pos\28\29\20const +2611:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +2612:SkSL::VarDeclaration::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\2c\20std::__2::unique_ptr>\29 +2613:SkSL::Type::priority\28\29\20const +2614:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20double\2c\20SkSL::Position\29\20const +2615:SkSL::Transform::EliminateDeadFunctions\28SkSL::Program&\29::$_0::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +2616:SkSL::SymbolTable::lookup\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +2617:SkSL::SymbolTable::isType\28std::__2::basic_string_view>\29\20const +2618:SkSL::Swizzle::MaskString\28skia_private::FixedArray<4\2c\20signed\20char>\20const&\29 +2619:SkSL::RP::SlotManager::mapVariableToSlots\28SkSL::Variable\20const&\2c\20SkSL::RP::SlotRange\29 +2620:SkSL::RP::Program::appendStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkSL::RP::Callbacks*\2c\20SkSpan\29\20const::$_0::operator\28\29\28\29\20const +2621:SkSL::RP::Program::appendCopy\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20std::byte*\2c\20SkSL::RP::ProgramOp\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29\20const +2622:SkSL::RP::Generator::store\28SkSL::RP::LValue&\29 +2623:SkSL::RP::Generator::popToSlotRangeUnmasked\28SkSL::RP::SlotRange\29 +2624:SkSL::RP::DynamicIndexLValue::dynamicSlotRange\28\29 +2625:SkSL::RP::Builder::ternary_op\28SkSL::RP::BuilderOp\2c\20int\29 +2626:SkSL::RP::Builder::simplifyPopSlotsUnmasked\28SkSL::RP::SlotRange*\29 +2627:SkSL::RP::Builder::push_zeros\28int\29 +2628:SkSL::RP::Builder::push_loop_mask\28\29 +2629:SkSL::RP::Builder::pad_stack\28int\29 +2630:SkSL::RP::Builder::exchange_src\28\29 +2631:SkSL::ProgramVisitor::visit\28SkSL::Program\20const&\29 +2632:SkSL::ProgramUsage::remove\28SkSL::Statement\20const*\29 +2633:SkSL::PrefixExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +2634:SkSL::PipelineStage::PipelineStageCodeGenerator::typedVariable\28SkSL::Type\20const&\2c\20std::__2::basic_string_view>\29 +2635:SkSL::PipelineStage::PipelineStageCodeGenerator::typeName\28SkSL::Type\20const&\29 +2636:SkSL::Parser::parseInitializer\28SkSL::Position\2c\20std::__2::unique_ptr>*\29 +2637:SkSL::Parser::nextRawToken\28\29 +2638:SkSL::Parser::arrayType\28SkSL::Type\20const*\2c\20int\2c\20SkSL::Position\29 +2639:SkSL::Parser::AutoSymbolTable::AutoSymbolTable\28SkSL::Parser*\2c\20std::__2::unique_ptr>*\2c\20bool\29 +2640:SkSL::MethodReference::~MethodReference\28\29_6425 +2641:SkSL::MethodReference::~MethodReference\28\29 +2642:SkSL::LiteralType::priority\28\29\20const +2643:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sub\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +2644:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_dot\28std::__2::array\20const&\29 +2645:SkSL::InterfaceBlock::arraySize\28\29\20const +2646:SkSL::IndexExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +2647:SkSL::GLSLCodeGenerator::writeExtension\28std::__2::basic_string_view>\2c\20bool\29 +2648:SkSL::FieldAccess::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20int\2c\20SkSL::FieldAccessOwnerKind\29 +2649:SkSL::ConstructorArray::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +2650:SkSL::Compiler::convertProgram\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::ProgramSettings\20const&\29 +2651:SkSL::Block::isEmpty\28\29\20const +2652:SkSL::Block::Make\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2653:SkSL::Block::MakeBlock\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2654:SkSL::Analysis::DetectVarDeclarationWithoutScope\28SkSL::Statement\20const&\2c\20SkSL::ErrorReporter*\29 +2655:SkRuntimeEffect::Result::~Result\28\29 +2656:SkResourceCache::remove\28SkResourceCache::Rec*\29 +2657:SkRegion::writeToMemory\28void*\29\20const +2658:SkRegion::getBoundaryPath\28SkPath*\29\20const +2659:SkRegion::SkRegion\28SkRegion\20const&\29 +2660:SkRect\20skif::Mapping::map\28SkRect\20const&\2c\20SkMatrix\20const&\29 +2661:SkRect::set\28SkPoint\20const&\2c\20SkPoint\20const&\29 +2662:SkRect::offset\28SkPoint\20const&\29 +2663:SkRect::inset\28float\2c\20float\29 +2664:SkRect::center\28\29\20const +2665:SkRecords::Optional::~Optional\28\29 +2666:SkRecords::NoOp*\20SkRecord::replace\28int\29 +2667:SkReadBuffer::skip\28unsigned\20long\29 +2668:SkRasterPipeline::tailPointer\28\29 +2669:SkRasterPipeline::appendMatrix\28SkArenaAlloc*\2c\20SkMatrix\20const&\29 +2670:SkRasterPipeline::addMemoryContext\28SkRasterPipeline_MemoryCtx*\2c\20int\2c\20bool\2c\20bool\29 +2671:SkRasterClip::SkRasterClip\28SkIRect\20const&\29 +2672:SkRRect::setOval\28SkRect\20const&\29 +2673:SkRRect::initializeRect\28SkRect\20const&\29 +2674:SkRRect::MakeRectXY\28SkRect\20const&\2c\20float\2c\20float\29 +2675:SkRGBA4f<\28SkAlphaType\293>::operator==\28SkRGBA4f<\28SkAlphaType\293>\20const&\29\20const +2676:SkQuads::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +2677:SkPixelRef::~SkPixelRef\28\29 +2678:SkPixelRef::SkPixelRef\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +2679:SkPictureRecord::~SkPictureRecord\28\29 +2680:SkPictureRecord::recordRestoreOffsetPlaceholder\28\29 +2681:SkPathStroker::quadStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2682:SkPathStroker::preJoinTo\28SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\2c\20bool\29 +2683:SkPathStroker::intersectRay\28SkQuadConstruct*\2c\20SkPathStroker::IntersectRayType\29\20const +2684:SkPathStroker::cubicStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2685:SkPathStroker::cubicPerpRay\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +2686:SkPathStroker::conicStroke\28SkConic\20const&\2c\20SkQuadConstruct*\29 +2687:SkPathRef::computeBounds\28\29\20const +2688:SkPathEdgeIter::SkPathEdgeIter\28SkPath\20const&\29 +2689:SkPathBuilder::incReserve\28int\2c\20int\29 +2690:SkPathBuilder::conicTo\28SkPoint\2c\20SkPoint\2c\20float\29 +2691:SkPath::rewind\28\29 +2692:SkPath::quadTo\28float\2c\20float\2c\20float\2c\20float\29 +2693:SkPath::getPoint\28int\29\20const +2694:SkPath::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2695:SkPaint::operator=\28SkPaint&&\29 +2696:SkPaint::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +2697:SkPaint::canComputeFastBounds\28\29\20const +2698:SkPaint::SkPaint\28SkPaint&&\29 +2699:SkOpSpanBase::mergeMatches\28SkOpSpanBase*\29 +2700:SkOpSpanBase::addOpp\28SkOpSpanBase*\29 +2701:SkOpSegment::updateOppWinding\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\29\20const +2702:SkOpSegment::subDivide\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkDCurve*\29\20const +2703:SkOpSegment::setUpWindings\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\2c\20int*\2c\20int*\2c\20int*\2c\20int*\2c\20int*\29 +2704:SkOpSegment::nextChase\28SkOpSpanBase**\2c\20int*\2c\20SkOpSpan**\2c\20SkOpSpanBase**\29\20const +2705:SkOpSegment::markAndChaseDone\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpSpanBase**\29 +2706:SkOpSegment::isSimple\28SkOpSpanBase**\2c\20int*\29\20const +2707:SkOpSegment::init\28SkPoint*\2c\20float\2c\20SkOpContour*\2c\20SkPath::Verb\29 +2708:SkOpEdgeBuilder::complete\28\29 +2709:SkOpContour::appendSegment\28\29 +2710:SkOpCoincidence::overlap\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20double*\2c\20double*\29\20const +2711:SkOpCoincidence::add\28SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\29 +2712:SkOpCoincidence::addIfMissing\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20double\2c\20double\2c\20SkOpSegment*\2c\20SkOpSegment*\2c\20bool*\29 +2713:SkOpCoincidence::addExpanded\28\29 +2714:SkOpCoincidence::addEndMovedSpans\28SkOpPtT\20const*\29 +2715:SkOpCoincidence::TRange\28SkOpPtT\20const*\2c\20double\2c\20SkOpSegment\20const*\29 +2716:SkOpAngle::set\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +2717:SkOpAngle::loopCount\28\29\20const +2718:SkOpAngle::insert\28SkOpAngle*\29 +2719:SkOpAngle*\20SkArenaAlloc::make\28\29 +2720:SkNoPixelsDevice::ClipState::op\28SkClipOp\2c\20SkM44\20const&\2c\20SkRect\20const&\2c\20bool\2c\20bool\29 +2721:SkMipmap*\20SkSafeRef\28SkMipmap*\29 +2722:SkMeshSpecification::Varying::Varying\28SkMeshSpecification::Varying\20const&\29 +2723:SkMatrixPriv::DifferentialAreaScale\28SkMatrix\20const&\2c\20SkPoint\20const&\29 +2724:SkMatrix::setRotate\28float\29 +2725:SkMatrix::mapVectors\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +2726:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint\20const*\2c\20int\29\20const +2727:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29 +2728:SkM44::setConcat\28SkM44\20const&\2c\20SkM44\20const&\29::$_0::operator\28\29\28skvx::Vec<4\2c\20float>\29\20const +2729:SkM44::normalizePerspective\28\29 +2730:SkLineClipper::IntersectLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\29 +2731:SkImage_Ganesh::makeView\28GrRecordingContext*\29\20const +2732:SkImage_Base::~SkImage_Base\28\29 +2733:SkImage_Base::isGaneshBacked\28\29\20const +2734:SkImage_Base::SkImage_Base\28SkImageInfo\20const&\2c\20unsigned\20int\29 +2735:SkImageInfo::validRowBytes\28unsigned\20long\29\20const +2736:SkImageInfo::MakeUnknown\28int\2c\20int\29 +2737:SkImageGenerator::~SkImageGenerator\28\29 +2738:SkImageFilters::Crop\28SkRect\20const&\2c\20SkTileMode\2c\20sk_sp\29 +2739:SkImageFilter_Base::~SkImageFilter_Base\28\29 +2740:SkImage::makeRasterImage\28GrDirectContext*\2c\20SkImage::CachingHint\29\20const +2741:SkIRect::makeInset\28int\2c\20int\29\20const +2742:SkHalfToFloat\28unsigned\20short\29 +2743:SkGradientBaseShader::commonAsAGradient\28SkShaderBase::GradientInfo*\29\20const +2744:SkGradientBaseShader::ValidGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\29 +2745:SkGradientBaseShader::SkGradientBaseShader\28SkGradientBaseShader::Descriptor\20const&\2c\20SkMatrix\20const&\29 +2746:SkGradientBaseShader::MakeDegenerateGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20float\20const*\2c\20int\2c\20sk_sp\2c\20SkTileMode\29 +2747:SkGlyph::setPath\28SkArenaAlloc*\2c\20SkPath\20const*\2c\20bool\2c\20bool\29 +2748:SkGetPolygonWinding\28SkPoint\20const*\2c\20int\29 +2749:SkFontMgr::RefEmpty\28\29 +2750:SkFont::setTypeface\28sk_sp\29 +2751:SkEmptyFontMgr::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +2752:SkEdgeBuilder::~SkEdgeBuilder\28\29 +2753:SkDrawable::draw\28SkCanvas*\2c\20SkMatrix\20const*\29 +2754:SkDrawBase::drawPathCoverage\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkBlitter*\29\20const +2755:SkDevice::~SkDevice\28\29 +2756:SkDevice::scalerContextFlags\28\29\20const +2757:SkDevice::accessPixels\28SkPixmap*\29 +2758:SkData::MakeWithProc\28void\20const*\2c\20unsigned\20long\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +2759:SkDQuad::dxdyAtT\28double\29\20const +2760:SkDQuad::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +2761:SkDPoint::distance\28SkDPoint\20const&\29\20const +2762:SkDLine::NearPointV\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +2763:SkDLine::NearPointH\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +2764:SkDCubic::dxdyAtT\28double\29\20const +2765:SkDCubic::RootsValidT\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +2766:SkDConic::dxdyAtT\28double\29\20const +2767:SkConicalGradient::~SkConicalGradient\28\29 +2768:SkComputeRadialSteps\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float*\2c\20float*\2c\20int*\29 +2769:SkColorFilterPriv::MakeGaussian\28\29 +2770:SkColorFilter::filterColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\2c\20SkColorSpace*\29\20const +2771:SkColorConverter::SkColorConverter\28unsigned\20int\20const*\2c\20int\29 +2772:SkCoincidentSpans::correctOneEnd\28SkOpPtT\20const*\20\28SkCoincidentSpans::*\29\28\29\20const\2c\20void\20\28SkCoincidentSpans::*\29\28SkOpPtT\20const*\29\29 +2773:SkClosestRecord::findEnd\28SkTSpan\20const*\2c\20SkTSpan\20const*\2c\20int\2c\20int\29 +2774:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\20const*\2c\20int\29 +2775:SkChopCubicAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +2776:SkCanvas::init\28sk_sp\29 +2777:SkCanvas::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +2778:SkCanvas::concat\28SkM44\20const&\29 +2779:SkCanvas::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +2780:SkCachedData::detachFromCacheAndUnref\28\29\20const +2781:SkCachedData::attachToCacheAndRef\28\29\20const +2782:SkBitmap::pixelRefOrigin\28\29\20const +2783:SkBitmap::operator=\28SkBitmap&&\29 +2784:SkBitmap::notifyPixelsChanged\28\29\20const +2785:SkBitmap::extractSubset\28SkBitmap*\2c\20SkIRect\20const&\29\20const +2786:SkBinaryWriteBuffer::writeByteArray\28void\20const*\2c\20unsigned\20long\29 +2787:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29 +2788:SkAutoPixmapStorage::tryAlloc\28SkImageInfo\20const&\29 +2789:SkAutoBlitterChoose::SkAutoBlitterChoose\28SkDrawBase\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const&\2c\20bool\29 +2790:SkArenaAllocWithReset::SkArenaAllocWithReset\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +2791:SkAAClip::setPath\28SkPath\20const&\2c\20SkIRect\20const&\2c\20bool\29 +2792:SkAAClip::quickContains\28SkIRect\20const&\29\20const +2793:SkAAClip::op\28SkAAClip\20const&\2c\20SkClipOp\29 +2794:SkAAClip::Builder::flushRowH\28SkAAClip::Builder::Row*\29 +2795:SkAAClip::Builder::Blitter::checkForYGap\28int\29 +2796:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29 +2797:ReadHuffmanCode +2798:OT::post::accelerator_t::find_glyph_name\28unsigned\20int\29\20const +2799:OT::hb_ot_layout_lookup_accelerator_t::apply\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20bool\29\20const +2800:OT::hb_ot_apply_context_t::skipping_iterator_t::match\28hb_glyph_info_t&\29 +2801:OT::hb_ot_apply_context_t::_set_glyph_class\28unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +2802:OT::glyf_accelerator_t::glyph_for_gid\28unsigned\20int\2c\20bool\29\20const +2803:OT::cff1::accelerator_templ_t>::std_code_to_glyph\28unsigned\20int\29\20const +2804:OT::apply_lookup\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20OT::LookupRecord\20const*\2c\20unsigned\20int\29 +2805:OT::VariationStore::create_cache\28\29\20const +2806:OT::VarRegionList::evaluate\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +2807:OT::Lookup::get_props\28\29\20const +2808:OT::Layout::GSUB_impl::SubstLookup*\20hb_serialize_context_t::copy\28\29\20const +2809:OT::Layout::GPOS_impl::ValueFormat::get_device\28OT::IntType\20const*\2c\20bool*\2c\20void\20const*\2c\20hb_sanitize_context_t&\29 +2810:OT::Layout::GPOS_impl::Anchor::get_anchor\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20float*\2c\20float*\29\20const +2811:OT::IntType*\20hb_serialize_context_t::extend_min>\28OT::IntType*\29 +2812:OT::GSUBGPOS::get_script\28unsigned\20int\29\20const +2813:OT::GSUBGPOS::get_feature_tag\28unsigned\20int\29\20const +2814:OT::GSUBGPOS::find_script_index\28unsigned\20int\2c\20unsigned\20int*\29\20const +2815:OT::ArrayOf>*\20hb_serialize_context_t::extend_size>>\28OT::ArrayOf>*\2c\20unsigned\20long\2c\20bool\29 +2816:Move_Zp2_Point +2817:Modify_CVT_Check +2818:GrYUVATextureProxies::operator=\28GrYUVATextureProxies&&\29 +2819:GrYUVATextureProxies::GrYUVATextureProxies\28\29 +2820:GrXPFactory::FromBlendMode\28SkBlendMode\29 +2821:GrWindowRectangles::operator=\28GrWindowRectangles\20const&\29 +2822:GrTriangulator::~GrTriangulator\28\29 +2823:GrTriangulator::simplify\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +2824:GrTriangulator::setTop\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2825:GrTriangulator::mergeCollinearEdges\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2826:GrTriangulator::mergeCoincidentVertices\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29\20const +2827:GrTriangulator::emitTriangle\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20skgpu::VertexWriter\29\20const +2828:GrTriangulator::allocateEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20GrTriangulator::EdgeType\29 +2829:GrTriangulator::FindEnclosingEdges\28GrTriangulator::Vertex\20const&\2c\20GrTriangulator::EdgeList\20const&\2c\20GrTriangulator::Edge**\2c\20GrTriangulator::Edge**\29 +2830:GrTriangulator::Edge::dist\28SkPoint\20const&\29\20const +2831:GrTriangulator::Edge::Edge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20GrTriangulator::EdgeType\29 +2832:GrThreadSafeCache::remove\28skgpu::UniqueKey\20const&\29 +2833:GrThreadSafeCache::internalFind\28skgpu::UniqueKey\20const&\29 +2834:GrThreadSafeCache::internalAdd\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2835:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +2836:GrTextureEffect::GrTextureEffect\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20GrTextureEffect::Sampling\20const&\29 +2837:GrTessellationShader::MakePipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedClip&&\2c\20GrProcessorSet&&\29 +2838:GrSurfaceProxyView::operator!=\28GrSurfaceProxyView\20const&\29\20const +2839:GrSurfaceProxyView::concatSwizzle\28skgpu::Swizzle\29 +2840:GrSurfaceProxy::~GrSurfaceProxy\28\29 +2841:GrSurfaceProxy::isFunctionallyExact\28\29\20const +2842:GrSurfaceProxy::gpuMemorySize\28\29\20const +2843:GrSurfaceProxy::createSurfaceImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\29\20const +2844:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20GrSurfaceProxy::RectsMustMatch\2c\20sk_sp*\29 +2845:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20sk_sp*\29 +2846:GrStyledShape::hasUnstyledKey\28\29\20const +2847:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +2848:GrStyle::GrStyle\28GrStyle\20const&\29 +2849:GrSkSLFP::setInput\28std::__2::unique_ptr>\29 +2850:GrSimpleMeshDrawOpHelper::CreatePipeline\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20skgpu::Swizzle\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrProcessorSet&&\2c\20GrPipeline::InputFlags\29 +2851:GrSimpleMesh::set\28sk_sp\2c\20int\2c\20int\29 +2852:GrShape::simplifyRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20unsigned\20int\29 +2853:GrShape::simplifyRRect\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20unsigned\20int\29 +2854:GrShape::simplifyPoint\28SkPoint\20const&\2c\20unsigned\20int\29 +2855:GrShape::simplifyLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\29 +2856:GrShape::setInverted\28bool\29 +2857:GrSWMaskHelper::init\28SkIRect\20const&\29 +2858:GrSWMaskHelper::GrSWMaskHelper\28SkAutoPixmapStorage*\29 +2859:GrResourceProvider::refNonAAQuadIndexBuffer\28\29 +2860:GrRenderTask::addTarget\28GrDrawingManager*\2c\20sk_sp\29 +2861:GrRenderTarget::~GrRenderTarget\28\29 +2862:GrQuadUtils::WillUseHairline\28GrQuad\20const&\2c\20GrAAType\2c\20GrQuadAAFlags\29 +2863:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::unpackQuad\28GrQuad::Type\2c\20float\20const*\2c\20GrQuad*\29\20const +2864:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::MetadataIter::next\28\29 +2865:GrProxyProvider::processInvalidUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\2c\20GrProxyProvider::InvalidateGPUResource\29 +2866:GrProxyProvider::createMippedProxyFromBitmap\28SkBitmap\20const&\2c\20skgpu::Budgeted\29::$_0::~$_0\28\29 +2867:GrProgramInfo::GrProgramInfo\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrGeometryProcessor\20const*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +2868:GrPipeline::visitProxies\28std::__2::function\20const&\29\20const +2869:GrPathUtils::scaleToleranceToSrc\28float\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +2870:GrPathUtils::generateQuadraticPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +2871:GrPathUtils::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +2872:GrPathUtils::cubicPointCount\28SkPoint\20const*\2c\20float\29 +2873:GrPaint::GrPaint\28GrPaint\20const&\29 +2874:GrOpsRenderPass::prepareToDraw\28\29 +2875:GrOpFlushState::~GrOpFlushState\28\29 +2876:GrOpFlushState::drawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +2877:GrOpFlushState::bindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const&\2c\20GrPipeline\20const&\29 +2878:GrOp::uniqueID\28\29\20const +2879:GrNativeRect::MakeIRectRelativeTo\28GrSurfaceOrigin\2c\20int\2c\20SkIRect\29 +2880:GrMeshDrawOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +2881:GrMapRectPoints\28SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkPoint*\2c\20int\29 +2882:GrMakeKeyFromImageID\28skgpu::UniqueKey*\2c\20unsigned\20int\2c\20SkIRect\20const&\29 +2883:GrGradientShader::MakeGradientFP\28SkGradientBaseShader\20const&\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\2c\20std::__2::unique_ptr>\2c\20SkMatrix\20const*\29 +2884:GrGpuResource::setUniqueKey\28skgpu::UniqueKey\20const&\29 +2885:GrGpuResource::registerWithCache\28skgpu::Budgeted\29 +2886:GrGpu::writePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +2887:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +2888:GrGLTexture::onSetLabel\28\29 +2889:GrGLTexture::onAbandon\28\29 +2890:GrGLTexture::backendFormat\28\29\20const +2891:GrGLSLVaryingHandler::appendDecls\28SkTBlockList\20const&\2c\20SkString*\29\20const +2892:GrGLSLShaderBuilder::newTmpVarName\28char\20const*\29 +2893:GrGLSLShaderBuilder::definitionAppend\28char\20const*\29 +2894:GrGLSLProgramBuilder::invokeFP\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +2895:GrGLSLProgramBuilder::advanceStage\28\29 +2896:GrGLSLFragmentShaderBuilder::dstColor\28\29 +2897:GrGLRenderTarget::bindInternal\28unsigned\20int\2c\20bool\29 +2898:GrGLGpu::unbindXferBuffer\28GrGpuBufferType\29 +2899:GrGLGpu::resolveRenderFBOs\28GrGLRenderTarget*\2c\20SkIRect\20const&\2c\20GrGLRenderTarget::ResolveDirection\2c\20bool\29 +2900:GrGLGpu::flushBlendAndColorWrite\28skgpu::BlendInfo\20const&\2c\20skgpu::Swizzle\20const&\29 +2901:GrGLGpu::currentProgram\28\29 +2902:GrGLGpu::SamplerObjectCache::Sampler::~Sampler\28\29 +2903:GrGLGpu::HWVertexArrayState::setVertexArrayID\28GrGLGpu*\2c\20unsigned\20int\29 +2904:GrGLGetVersionFromString\28char\20const*\29 +2905:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\29 +2906:GrGLFunction::GrGLFunction\28unsigned\20char\20const*\20\28*\29\28unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\29 +2907:GrGLFinishCallbacks::callAll\28bool\29 +2908:GrGLCheckLinkStatus\28GrGLGpu\20const*\2c\20unsigned\20int\2c\20bool\2c\20skgpu::ShaderErrorHandler*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const**\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +2909:GrGLAttribArrayState::set\28GrGLGpu*\2c\20int\2c\20GrBuffer\20const*\2c\20GrVertexAttribType\2c\20SkSLType\2c\20int\2c\20unsigned\20long\2c\20int\29 +2910:GrFragmentProcessors::Make\28SkBlenderBase\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20GrFPArgs\20const&\29 +2911:GrFragmentProcessor::isEqual\28GrFragmentProcessor\20const&\29\20const +2912:GrFragmentProcessor::Rect\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRect\29 +2913:GrFragmentProcessor::ModulateRGBA\28std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +2914:GrDstProxyView::setProxyView\28GrSurfaceProxyView\29 +2915:GrDrawingManager::removeRenderTasks\28\29 +2916:GrDrawingManager::getPathRenderer\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\2c\20bool\2c\20skgpu::ganesh::PathRendererChain::DrawType\2c\20skgpu::ganesh::PathRenderer::StencilSupport*\29 +2917:GrDrawingManager::getLastRenderTask\28GrSurfaceProxy\20const*\29\20const +2918:GrDrawOpAtlas::updatePlot\28GrDeferredUploadTarget*\2c\20skgpu::AtlasLocator*\2c\20skgpu::Plot*\29::'lambda'\28std::__2::function&\29::\28'lambda'\28std::__2::function&\29\20const&\29 +2919:GrDrawOpAtlas::processEvictionAndResetRects\28skgpu::Plot*\29 +2920:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29 +2921:GrDeferredProxyUploader::wait\28\29 +2922:GrCpuBuffer::Make\28unsigned\20long\29 +2923:GrContext_Base::~GrContext_Base\28\29 +2924:GrColorSpaceXform::Make\28SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +2925:GrColorInfo::operator=\28GrColorInfo\20const&\29 +2926:GrClip::IsPixelAligned\28SkRect\20const&\29 +2927:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29::'lambda0'\28float\29::operator\28\29\28float\29\20const +2928:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29::'lambda'\28float\29::operator\28\29\28float\29\20const +2929:GrCaps::supportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +2930:GrCaps::getFallbackColorTypeAndFormat\28GrColorType\2c\20int\29\20const +2931:GrCaps::areColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +2932:GrBufferAllocPool::~GrBufferAllocPool\28\29_8477 +2933:GrBufferAllocPool::makeSpace\28unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\29 +2934:GrBufferAllocPool::GrBufferAllocPool\28GrGpu*\2c\20GrGpuBufferType\2c\20sk_sp\29 +2935:GrBlurUtils::DrawShapeWithMaskFilter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\29 +2936:GrBaseContextPriv::getShaderErrorHandler\28\29\20const +2937:GrBackendTexture::GrBackendTexture\28GrBackendTexture\20const&\29 +2938:GrBackendRenderTarget::getBackendFormat\28\29\20const +2939:GrAAConvexTessellator::createOuterRing\28GrAAConvexTessellator::Ring\20const&\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring*\29 +2940:GrAAConvexTessellator::createInsetRings\28GrAAConvexTessellator::Ring&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring**\29 +2941:GrAAConvexTessellator::Ring::init\28GrAAConvexTessellator\20const&\29 +2942:FwDCubicEvaluator::FwDCubicEvaluator\28SkPoint\20const*\29 +2943:FT_Stream_ReadAt +2944:FT_Stream_Free +2945:FT_Set_Charmap +2946:FT_New_Size +2947:FT_Load_Sfnt_Table +2948:FT_List_Find +2949:FT_GlyphLoader_Add +2950:FT_Get_Next_Char +2951:FT_Get_Color_Glyph_Layer +2952:FT_CMap_New +2953:Current_Ratio +2954:Compute_Funcs +2955:CircleOp::Circle&\20skia_private::TArray::emplace_back\28CircleOp::Circle&&\29 +2956:CFF::path_procs_t\2c\20cff2_path_param_t>::curve2\28CFF::cff2_cs_interp_env_t&\2c\20cff2_path_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2957:CFF::path_procs_t\2c\20cff2_extents_param_t>::curve2\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2958:CFF::path_procs_t::curve2\28CFF::cff1_cs_interp_env_t&\2c\20cff1_path_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2959:CFF::path_procs_t::curve2\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2960:CFF::parsed_values_t::operator=\28CFF::parsed_values_t&&\29 +2961:CFF::cs_interp_env_t>>::return_from_subr\28\29 +2962:CFF::cs_interp_env_t>>::call_subr\28CFF::biased_subrs_t>>\20const&\2c\20CFF::cs_type_t\29 +2963:CFF::cs_interp_env_t>>::call_subr\28CFF::biased_subrs_t>>\20const&\2c\20CFF::cs_type_t\29 +2964:CFF::byte_str_ref_t::operator\5b\5d\28int\29 +2965:CFF::arg_stack_t::push_fixed_from_substr\28CFF::byte_str_ref_t&\29 +2966:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +2967:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +2968:CFF::CFFIndex>::offset_at\28unsigned\20int\29\20const +2969:AlmostLessOrEqualUlps\28float\2c\20float\29 +2970:AlmostEqualUlps_Pin\28double\2c\20double\29 +2971:ActiveEdge::intersect\28ActiveEdge\20const*\29 +2972:AAT::Lookup::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +2973:AAT::ClassTable>::get_class\28unsigned\20int\2c\20unsigned\20int\29\20const +2974:2755 +2975:2756 +2976:2757 +2977:2758 +2978:2759 +2979:2760 +2980:week_num +2981:wcrtomb +2982:void\20std::__2::vector>::__construct_at_end\28skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20unsigned\20long\29 +2983:void\20std::__2::vector>::__construct_at_end\28SkString*\2c\20SkString*\2c\20unsigned\20long\29 +2984:void\20std::__2::__sort4\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +2985:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +2986:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +2987:void\20std::__2::__inplace_merge\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +2988:void\20skgpu::ganesh::SurfaceFillContext::clear<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\20const&\29 +2989:void\20skgpu::VertexWriter::writeQuad\28GrQuad\20const&\29 +2990:void\20merge_sort<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +2991:void\20merge_sort<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +2992:void\20hb_stable_sort\2c\20unsigned\20int>\28OT::HBGlyphID16*\2c\20unsigned\20int\2c\20int\20\28*\29\28OT::IntType\20const*\2c\20OT::IntType\20const*\29\2c\20unsigned\20int*\29 +2993:void\20SkSafeUnref\28SkMeshSpecification*\29 +2994:void\20SkSafeUnref\28SkMeshPriv::VB\20const*\29 +2995:void\20SkSafeUnref\28GrTexture*\29\20\28.4445\29 +2996:void\20SkSafeUnref\28GrCpuBuffer*\29 +2997:vfprintf +2998:valid_args\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20unsigned\20long*\29 +2999:uprv_malloc_skia +3000:update_offset_to_base\28char\20const*\2c\20long\29 +3001:unsigned\20long\20std::__2::__str_find\5babi:ne180100\5d\2c\204294967295ul>\28char\20const*\2c\20unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +3002:unsigned\20long\20const&\20std::__2::min\5babi:nn180100\5d\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29 +3003:ubidi_getRuns_skia +3004:u_charMirror_skia +3005:tt_size_reset +3006:tt_sbit_decoder_load_metrics +3007:tt_glyphzone_done +3008:tt_face_get_location +3009:tt_face_find_bdf_prop +3010:tt_delta_interpolate +3011:tt_cmap14_find_variant +3012:tt_cmap14_char_map_nondef_binary +3013:tt_cmap14_char_map_def_binary +3014:top12_14198 +3015:tolower +3016:t1_cmap_unicode_done +3017:subdivide_cubic_to\28SkPath*\2c\20SkPoint\20const*\2c\20int\29 +3018:strtox.9508 +3019:strtox +3020:strtoull_l +3021:std::logic_error::~logic_error\28\29_15741 +3022:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +3023:std::__2::vector>\2c\20std::__2::allocator>>>::erase\28std::__2::__wrap_iter>\20const*>\2c\20std::__2::__wrap_iter>\20const*>\29 +3024:std::__2::vector>::__alloc\5babi:nn180100\5d\28\29 +3025:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +3026:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +3027:std::__2::vector\2c\20std::__2::allocator>>::vector\5babi:ne180100\5d\28std::__2::vector\2c\20std::__2::allocator>>&&\29 +3028:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +3029:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +3030:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +3031:std::__2::vector>::push_back\5babi:ne180100\5d\28SkString\20const&\29 +3032:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +3033:std::__2::vector\2c\20std::__2::allocator>>::push_back\5babi:ne180100\5d\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +3034:std::__2::vector\2c\20std::__2::allocator>>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +3035:std::__2::vector>::push_back\5babi:ne180100\5d\28SkMeshSpecification::Attribute&&\29 +3036:std::__2::unique_ptr\2c\20void*>\2c\20std::__2::__hash_node_destructor\2c\20void*>>>>::~unique_ptr\5babi:ne180100\5d\28\29 +3037:std::__2::unique_ptr::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3038:std::__2::unique_ptr\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3039:std::__2::unique_ptr>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3040:std::__2::unique_ptr::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3041:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3042:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3043:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkTypeface_FreeType::FaceRec*\29 +3044:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkStrikeSpec*\29 +3045:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3046:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3047:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Pool*\29 +3048:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Block*\29 +3049:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkDrawableList*\29 +3050:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3051:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkContourMeasureIter::Impl*\29 +3052:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3053:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3054:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3055:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrGLGpu::SamplerObjectCache*\29 +3056:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28std::nullptr_t\29 +3057:std::__2::unique_ptr>\20GrBlendFragmentProcessor::Make<\28SkBlendMode\296>\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3058:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrDrawingManager*\29 +3059:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrClientMappedBufferManager*\29 +3060:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3061:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28FT_FaceRec_*\29 +3062:std::__2::tuple&\20std::__2::tuple::operator=\5babi:ne180100\5d\28std::__2::pair&&\29 +3063:std::__2::time_put>>::~time_put\28\29 +3064:std::__2::pair\20std::__2::minmax\5babi:ne180100\5d>\28std::initializer_list\2c\20std::__2::__less\29 +3065:std::__2::locale::locale\28\29 +3066:std::__2::locale::__imp::acquire\28\29 +3067:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\29 +3068:std::__2::ios_base::~ios_base\28\29 +3069:std::__2::ios_base::clear\28unsigned\20int\29 +3070:std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::operator\28\29\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29\20const +3071:std::__2::function\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const +3072:std::__2::fpos<__mbstate_t>::fpos\5babi:nn180100\5d\28long\20long\29 +3073:std::__2::enable_if::value\2c\20SkRuntimeEffectBuilder::BuilderUniform&>::type\20SkRuntimeEffectBuilder::BuilderUniform::operator=\28SkV2\20const&\29 +3074:std::__2::enable_if\28\29\20==\20std::declval\28\29\29\2c\20bool>\2c\20bool>::type\20std::__2::operator==\5babi:ne180100\5d\28std::__2::optional\20const&\2c\20std::__2::optional\20const&\29 +3075:std::__2::deque>::__back_spare\5babi:ne180100\5d\28\29\20const +3076:std::__2::default_delete::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::_EnableIfConvertible::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot>::type\20std::__2::default_delete::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot>\28skia_private::THashTable::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot*\29\20const +3077:std::__2::default_delete::Traits>::Slot\20\5b\5d>::_EnableIfConvertible::Traits>::Slot>::type\20std::__2::default_delete::Traits>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Traits>::Slot>\28skia_private::THashTable::Traits>::Slot*\29\20const +3078:std::__2::chrono::__libcpp_steady_clock_now\28\29 +3079:std::__2::char_traits::move\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +3080:std::__2::char_traits::assign\5babi:nn180100\5d\28char*\2c\20unsigned\20long\2c\20char\29 +3081:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_14675 +3082:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29 +3083:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28wchar_t\29 +3084:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +3085:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28wchar_t\20const*\29 +3086:std::__2::basic_string\2c\20std::__2::allocator>::__make_iterator\5babi:nn180100\5d\28char*\29 +3087:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +3088:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +3089:std::__2::basic_streambuf>::~basic_streambuf\28\29 +3090:std::__2::basic_streambuf>::step\5babi:nn180100\5d\28char*\2c\20char*\29 +3091:std::__2::basic_istream>::~basic_istream\28\29 +3092:std::__2::basic_istream>::sentry::sentry\28std::__2::basic_istream>&\2c\20bool\29 +3093:std::__2::basic_iostream>::~basic_iostream\28\29_14565 +3094:std::__2::basic_ios>::~basic_ios\28\29 +3095:std::__2::array\20skgpu::ganesh::SurfaceFillContext::adjustColorAlphaType<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\29\20const +3096:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +3097:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +3098:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +3099:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +3100:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +3101:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +3102:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28GrRecordingContext*&&\2c\20GrSurfaceProxyView&&\2c\20GrSurfaceProxyView&&\2c\20GrColorInfo\20const&\29 +3103:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28GrRecordingContext*&\2c\20skgpu::ganesh::PathRendererChain::Options&\29 +3104:std::__2::__unique_if>::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\2c\20GrDirectContext::DirectContextID>\28GrDirectContext::DirectContextID&&\29 +3105:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::SymbolTable*&\2c\20bool&\29 +3106:std::__2::__tuple_impl\2c\20GrSurfaceProxyView\2c\20sk_sp>::~__tuple_impl\28\29 +3107:std::__2::__split_buffer>::__destruct_at_end\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock**\2c\20std::__2::integral_constant\29 +3108:std::__2::__split_buffer&>::~__split_buffer\28\29 +3109:std::__2::__optional_destruct_base>\2c\20false>::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3110:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3111:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +3112:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3113:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +3114:std::__2::__optional_copy_base::__optional_copy_base\5babi:ne180100\5d\28std::__2::__optional_copy_base\20const&\29 +3115:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20wchar_t*\2c\20wchar_t&\2c\20wchar_t&\29 +3116:std::__2::__num_get::__stage2_float_loop\28wchar_t\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20wchar_t*\29 +3117:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20char*\2c\20char&\2c\20char&\29 +3118:std::__2::__num_get::__stage2_float_loop\28char\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20char*\29 +3119:std::__2::__murmur2_or_cityhash::operator\28\29\5babi:ne180100\5d\28void\20const*\2c\20unsigned\20long\29\20const +3120:std::__2::__libcpp_wcrtomb_l\5babi:nn180100\5d\28char*\2c\20wchar_t\2c\20__mbstate_t*\2c\20__locale_struct*\29 +3121:std::__2::__itoa::__base_10_u32\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +3122:std::__2::__itoa::__append6\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +3123:std::__2::__itoa::__append4\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +3124:std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::~__hash_table\28\29 +3125:std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::~__hash_table\28\29 +3126:std::__2::__function::__value_func\2c\20sktext::gpu::RendererData\29>::operator\28\29\5babi:ne180100\5d\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29\20const +3127:std::__2::__function::__value_func\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\5babi:ne180100\5d\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const +3128:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28std::__2::__function::__base*\29\20const +3129:skvx::Vec<4\2c\20unsigned\20short>\20skvx::to_half<4>\28skvx::Vec<4\2c\20float>\20const&\29 +3130:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator~<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +3131:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator|<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +3132:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +3133:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +3134:skvx::Vec<4\2c\20int>\20skvx::operator~<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\29 +3135:skvx::Vec<4\2c\20int>\20skvx::operator&<4\2c\20int\2c\20int\2c\20void>\28skvx::Vec<4\2c\20int>\20const&\2c\20int\29 +3136:skvx::Vec<4\2c\20float>&\20skvx::operator+=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +3137:sktext::gpu::VertexFiller::flatten\28SkWriteBuffer&\29\20const +3138:sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry::find\28sktext::gpu::TextBlob::Key\20const&\29\20const +3139:sktext::gpu::SubRunAllocator::SubRunAllocator\28char*\2c\20int\2c\20int\29 +3140:sktext::gpu::GlyphVector::flatten\28SkWriteBuffer&\29\20const +3141:sktext::gpu::GlyphVector::Make\28sktext::SkStrikePromise&&\2c\20SkSpan\2c\20sktext::gpu::SubRunAllocator*\29 +3142:sktext::gpu::GlyphVector::GlyphVector\28sktext::gpu::GlyphVector&&\29 +3143:sktext::gpu::BagOfBytes::PlatformMinimumSizeWithOverhead\28int\2c\20int\29 +3144:sktext::SkStrikePromise::flatten\28SkWriteBuffer&\29\20const +3145:sktext::GlyphRunList::sourceBoundsWithOrigin\28\29\20const +3146:skpaint_to_grpaint_impl\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::optional>>\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +3147:skip_literal_string +3148:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10241 +3149:skif::Mapping::Mapping\28\29 +3150:skif::LayerSpace::ceil\28\29\20const +3151:skif::LayerSpace::inverseMapRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29\20const +3152:skif::LayerSpace::inset\28skif::LayerSpace\20const&\29 +3153:skif::FilterResult::operator=\28skif::FilterResult\20const&\29 +3154:skif::FilterResult::insetByPixel\28\29\20const +3155:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20bool\2c\20SkBlender\20const*\29\20const +3156:skif::FilterResult::applyColorFilter\28skif::Context\20const&\2c\20sk_sp\29\20const +3157:skif::FilterResult::FilterResult\28sk_sp\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult::PixelBoundary\29 +3158:skif::FilterResult::Builder::~Builder\28\29 +3159:skif::Context::withNewSource\28skif::FilterResult\20const&\29\20const +3160:skif::Context::operator=\28skif::Context&&\29 +3161:skif::Backend::~Backend\28\29 +3162:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot::reset\28\29 +3163:skia_private::THashTable::Pair\2c\20SkSL::Symbol\20const*\2c\20skia_private::THashMap::Pair>::firstPopulatedSlot\28\29\20const +3164:skia_private::THashTable::Pair\2c\20SkSL::Symbol\20const*\2c\20skia_private::THashMap::Pair>::Iter>::operator++\28\29 +3165:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +3166:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot::reset\28\29 +3167:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot::reset\28\29 +3168:skia_private::THashTable::Traits>::Hash\28long\20long\20const&\29 +3169:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::Hash\28SkImageFilterCacheKey\20const&\29 +3170:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::findOrNull\28skgpu::ScratchKey\20const&\29\20const +3171:skia_private::THashTable::Traits>::set\28SkSL::Variable\20const*\29 +3172:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::uncheckedSet\28SkLRUCache::Entry*&&\29 +3173:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +3174:skia_private::THashTable::Traits>::Hash\28FT_Opaque_Paint_\20const&\29 +3175:skia_private::THashMap\2c\20SkGoodHash>::find\28SkString\20const&\29\20const +3176:skia_private::THashMap>\2c\20SkGoodHash>::set\28SkSL::Variable\20const*\2c\20std::__2::unique_ptr>\29 +3177:skia_private::THashMap::operator\5b\5d\28SkSL::SymbolTable::SymbolKey\20const&\29 +3178:skia_private::THashMap::find\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +3179:skia_private::THashMap::find\28SkSL::IRNode\20const*\20const&\29\20const +3180:skia_private::THashMap::set\28SkSL::FunctionDeclaration\20const*\2c\20SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::FunctionState\29 +3181:skia_private::THashMap>\2c\20SkGoodHash>::find\28SkImageFilter\20const*\20const&\29\20const +3182:skia_private::TArray::resize_back\28int\29 +3183:skia_private::TArray::push_back_raw\28int\29 +3184:skia_private::TArray::operator==\28skia_private::TArray\20const&\29\20const +3185:skia_private::TArray::reserve_exact\28int\29 +3186:skia_private::TArray\2c\20true>::push_back\28std::__2::array&&\29 +3187:skia_private::TArray\2c\20false>::~TArray\28\29 +3188:skia_private::TArray::clear\28\29 +3189:skia_private::TArray::clear\28\29 +3190:skia_private::TArray::TArray\28skia_private::TArray\20const&\29 +3191:skia_private::TArray::TArray\28skia_private::TArray\20const&\29 +3192:skia_private::TArray::~TArray\28\29 +3193:skia_private::TArray::move\28void*\29 +3194:skia_private::TArray::BufferFinishedMessage\2c\20false>::~TArray\28\29 +3195:skia_private::TArray::BufferFinishedMessage\2c\20false>::move\28void*\29 +3196:skia_private::TArray\2c\20true>::~TArray\28\29 +3197:skia_private::TArray\2c\20true>::push_back\28sk_sp&&\29 +3198:skia_private::TArray::reserve_exact\28int\29 +3199:skia_private::TArray\2c\20true>::Allocate\28int\2c\20double\29 +3200:skia_private::TArray::reserve_exact\28int\29 +3201:skia_private::TArray::Allocate\28int\2c\20double\29 +3202:skia_private::TArray::~TArray\28\29 +3203:skia_private::TArray::move\28void*\29 +3204:skia_private::AutoSTMalloc<8ul\2c\20unsigned\20int\2c\20void>::reset\28unsigned\20long\29 +3205:skia_private::AutoSTArray<6\2c\20SkResourceCache::Key>::reset\28int\29 +3206:skia_private::AutoSTArray<20\2c\20SkGlyph\20const*>::reset\28int\29 +3207:skia_private::AutoSTArray<16\2c\20SkRect>::reset\28int\29 +3208:skia_png_sig_cmp +3209:skia_png_set_text_2 +3210:skia_png_realloc_array +3211:skia_png_get_uint_31 +3212:skia_png_check_fp_string +3213:skia_png_check_fp_number +3214:skia_png_app_warning +3215:skia_png_app_error +3216:skia::textlayout::\28anonymous\20namespace\29::intersected\28skia::textlayout::SkRange\20const&\2c\20skia::textlayout::SkRange\20const&\29 +3217:skia::textlayout::\28anonymous\20namespace\29::draw_line_as_rect\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\2c\20float\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +3218:skia::textlayout::TypefaceFontStyleSet::createTypeface\28int\29 +3219:skia::textlayout::TextStyle::setForegroundColor\28SkPaint\29 +3220:skia::textlayout::TextStyle::setBackgroundColor\28SkPaint\29 +3221:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29 +3222:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::$_0::operator\28\29\28sk_sp\2c\20sk_sp\29\20const +3223:skia::textlayout::TextLine::iterateThroughSingleRunByStyles\28skia::textlayout::TextLine::TextAdjustment\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::StyleType\2c\20std::__2::function\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\20const&\29\20const::$_0::operator\28\29\28skia::textlayout::SkRange\2c\20float\29\20const +3224:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const +3225:skia::textlayout::TextBox&\20std::__2::vector>::emplace_back\28SkRect&\2c\20skia::textlayout::TextDirection&&\29 +3226:skia::textlayout::StrutStyle::StrutStyle\28skia::textlayout::StrutStyle\20const&\29 +3227:skia::textlayout::Run::isResolved\28\29\20const +3228:skia::textlayout::Run::copyTo\28SkTextBlobBuilder&\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +3229:skia::textlayout::Run::calculateWidth\28unsigned\20long\2c\20unsigned\20long\2c\20bool\29\20const +3230:skia::textlayout::Run::calculateHeight\28skia::textlayout::LineMetricStyle\2c\20skia::textlayout::LineMetricStyle\29\20const +3231:skia::textlayout::ParagraphStyle::ParagraphStyle\28skia::textlayout::ParagraphStyle&&\29 +3232:skia::textlayout::ParagraphImpl::getGlyphPositionAtCoordinate\28float\2c\20float\29 +3233:skia::textlayout::ParagraphImpl::findNextGraphemeBoundary\28unsigned\20long\29\20const +3234:skia::textlayout::ParagraphImpl::findAllBlocks\28skia::textlayout::SkRange\29 +3235:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +3236:skia::textlayout::ParagraphImpl::buildClusterTable\28\29 +3237:skia::textlayout::ParagraphCacheKey::operator==\28skia::textlayout::ParagraphCacheKey\20const&\29\20const +3238:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +3239:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29 +3240:skia::textlayout::ParagraphBuilderImpl::endRunIfNeeded\28\29 +3241:skia::textlayout::OneLineShaper::~OneLineShaper\28\29 +3242:skia::textlayout::LineMetrics::LineMetrics\28\29 +3243:skia::textlayout::FontCollection::FamilyKey::~FamilyKey\28\29 +3244:skia::textlayout::Cluster::isSoftBreak\28\29\20const +3245:skia::textlayout::Block::Block\28skia::textlayout::Block\20const&\29 +3246:skgpu::tess::AffineMatrix::AffineMatrix\28SkMatrix\20const&\29 +3247:skgpu::ganesh::\28anonymous\20namespace\29::add_quad_segment\28SkPoint\20const*\2c\20skia_private::TArray*\29 +3248:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::Entry::Entry\28skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::Entry&&\29 +3249:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::~Impl\28\29 +3250:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::programInfo\28\29 +3251:skgpu::ganesh::SurfaceFillContext::internalClear\28SkIRect\20const*\2c\20std::__2::array\2c\20bool\29 +3252:skgpu::ganesh::SurfaceFillContext::discard\28\29 +3253:skgpu::ganesh::SurfaceFillContext::addOp\28std::__2::unique_ptr>\29 +3254:skgpu::ganesh::SurfaceDrawContext::wrapsVkSecondaryCB\28\29\20const +3255:skgpu::ganesh::SurfaceDrawContext::stencilRect\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const*\29 +3256:skgpu::ganesh::SurfaceDrawContext::fillQuadWithEdgeAA\28GrClip\20const*\2c\20GrPaint&&\2c\20GrQuadAAFlags\2c\20SkMatrix\20const&\2c\20SkPoint\20const*\2c\20SkPoint\20const*\29 +3257:skgpu::ganesh::SurfaceDrawContext::drawPath\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrStyle\20const&\29 +3258:skgpu::ganesh::SurfaceDrawContext::attemptQuadOptimization\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20DrawQuad*\2c\20GrPaint*\29 +3259:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +3260:skgpu::ganesh::SurfaceContext::rescale\28GrImageInfo\20const&\2c\20GrSurfaceOrigin\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29 +3261:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29::$_0::operator\28\29\28GrSurfaceProxyView\2c\20SkIRect\29\20const +3262:skgpu::ganesh::SurfaceContext::SurfaceContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +3263:skgpu::ganesh::SmallPathShapeDataKey::operator==\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29\20const +3264:skgpu::ganesh::QuadPerEdgeAA::MinColorType\28SkRGBA4f<\28SkAlphaType\292>\29 +3265:skgpu::ganesh::PathTessellator::~PathTessellator\28\29 +3266:skgpu::ganesh::PathCurveTessellator::draw\28GrOpFlushState*\29\20const +3267:skgpu::ganesh::OpsTask::~OpsTask\28\29 +3268:skgpu::ganesh::OpsTask::recordOp\28std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const*\2c\20GrCaps\20const&\29 +3269:skgpu::ganesh::FilterAndMipmapHaveNoEffect\28GrQuad\20const&\2c\20GrQuad\20const&\29 +3270:skgpu::ganesh::FillRectOp::MakeNonAARect\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +3271:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::can_use_hw_derivatives_with_coverage\28skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +3272:skgpu::ganesh::FillRRectOp::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +3273:skgpu::ganesh::Device::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +3274:skgpu::ganesh::Device::drawImageQuadDirect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +3275:skgpu::ganesh::Device::Make\28std::__2::unique_ptr>\2c\20SkAlphaType\2c\20skgpu::ganesh::Device::InitContents\29 +3276:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::setup_dashed_rect\28SkRect\20const&\2c\20skgpu::VertexWriter&\2c\20SkMatrix\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashCap\29 +3277:skgpu::ganesh::ClipStack::~ClipStack\28\29 +3278:skgpu::ganesh::ClipStack::writableSaveRecord\28bool*\29 +3279:skgpu::ganesh::ClipStack::end\28\29\20const +3280:skgpu::ganesh::ClipStack::clip\28skgpu::ganesh::ClipStack::RawElement&&\29 +3281:skgpu::ganesh::ClipStack::clipState\28\29\20const +3282:skgpu::ganesh::ClipStack::SaveRecord::invalidateMasks\28GrProxyProvider*\2c\20SkTBlockList*\29 +3283:skgpu::ganesh::ClipStack::SaveRecord::genID\28\29\20const +3284:skgpu::ganesh::ClipStack::RawElement::operator=\28skgpu::ganesh::ClipStack::RawElement&&\29 +3285:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::SaveRecord\20const&\29\20const +3286:skgpu::ganesh::ClipStack::RawElement::RawElement\28SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\2c\20SkClipOp\29 +3287:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +3288:skgpu::Swizzle::apply\28SkRasterPipeline*\29\20const +3289:skgpu::Swizzle::applyTo\28std::__2::array\29\20const +3290:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29 +3291:skgpu::ScratchKey::GenerateResourceType\28\29 +3292:skgpu::RectanizerSkyline::reset\28\29 +3293:skgpu::Plot::addSubImage\28int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +3294:skgpu::AutoCallback::AutoCallback\28skgpu::AutoCallback&&\29 +3295:sk_sp::~sk_sp\28\29 +3296:sk_sp::operator=\28sk_sp&&\29 +3297:sk_sp::reset\28GrTextureProxy*\29 +3298:sk_sp::reset\28GrTexture*\29 +3299:sk_sp::operator=\28sk_sp&&\29 +3300:sk_sp::reset\28GrCpuBuffer*\29 +3301:sk_sp&\20sk_sp::operator=\28sk_sp&&\29 +3302:sk_sp&\20sk_sp::operator=\28sk_sp\20const&\29 +3303:sk_ft_free\28FT_MemoryRec_*\2c\20void*\29 +3304:sift +3305:set_initial_texture_params\28GrGLInterface\20const*\2c\20GrGLCaps\20const&\2c\20unsigned\20int\29 +3306:setLevelsOutsideIsolates\28UBiDi*\2c\20int\2c\20int\2c\20unsigned\20char\29 +3307:sect_with_vertical\28SkPoint\20const*\2c\20float\29 +3308:sampler_key\28GrTextureType\2c\20skgpu::Swizzle\20const&\2c\20GrCaps\20const&\29 +3309:round\28SkPoint*\29 +3310:read_color_line +3311:quick_inverse\28int\29 +3312:quad_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3313:pthread_mutex_destroy +3314:psh_globals_set_scale +3315:ps_tofixedarray +3316:ps_parser_skip_PS_token +3317:ps_mask_test_bit +3318:ps_mask_table_alloc +3319:ps_mask_ensure +3320:ps_dimension_reset_mask +3321:ps_builder_init +3322:ps_builder_done +3323:pow +3324:portable::parametric_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3325:portable::hsl_to_rgb_k\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3326:portable::gamma__k\28float\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3327:portable::PQish_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3328:portable::HLGish_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3329:portable::HLGinvish_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3330:points_are_collinear_and_b_is_middle\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float*\29 +3331:png_zlib_inflate +3332:png_inflate_read +3333:png_inflate_claim +3334:png_build_8bit_table +3335:png_build_16bit_table +3336:picture_approximateBytesUsed +3337:path_addOval +3338:paragraph_dispose +3339:operator==\28SkPath\20const&\2c\20SkPath\20const&\29 +3340:operator!=\28SkString\20const&\2c\20SkString\20const&\29 +3341:normalize +3342:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::glyphCount\28\29\20const +3343:non-virtual\20thunk\20to\20GrOpFlushState::deferredUploadTarget\28\29 +3344:nextafterf +3345:move_nearby\28SkOpContourHead*\29 +3346:make_unpremul_effect\28std::__2::unique_ptr>\29 +3347:machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>::operator==\28machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\20const&\29\20const +3348:long\20std::__2::__libcpp_atomic_refcount_decrement\5babi:nn180100\5d\28long&\29 +3349:long\20const&\20std::__2::min\5babi:nn180100\5d\28long\20const&\2c\20long\20const&\29 +3350:log1p +3351:load_truetype_glyph +3352:load\28unsigned\20char\20const*\2c\20int\2c\20void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\29 +3353:line_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3354:lineMetrics_getStartIndex +3355:just_solid_color\28SkPaint\20const&\29 +3356:is_reflex_vertex\28SkPoint\20const*\2c\20int\2c\20float\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +3357:inner_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +3358:inflate_table +3359:image_filter_color_type\28SkColorInfo\20const&\29 +3360:hb_vector_t::push\28\29 +3361:hb_vector_t\2c\20false>::shrink_vector\28unsigned\20int\29 +3362:hb_utf8_t::next\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20int*\2c\20unsigned\20int\29 +3363:hb_shape_plan_destroy +3364:hb_serialize_context_t::object_t::hash\28\29\20const +3365:hb_script_get_horizontal_direction +3366:hb_pool_t::alloc\28\29 +3367:hb_paint_funcs_t::push_clip_glyph\28void*\2c\20unsigned\20int\2c\20hb_font_t*\29 +3368:hb_paint_funcs_t::image\28void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\29 +3369:hb_paint_funcs_t::color\28void*\2c\20int\2c\20unsigned\20int\29 +3370:hb_paint_extents_context_t::~hb_paint_extents_context_t\28\29 +3371:hb_paint_extents_context_t::push_clip\28hb_extents_t\29 +3372:hb_ot_map_t::get_mask\28unsigned\20int\2c\20unsigned\20int*\29\20const +3373:hb_lazy_loader_t\2c\20hb_face_t\2c\202u\2c\20hb_blob_t>::get\28\29\20const +3374:hb_lazy_loader_t\2c\20hb_face_t\2c\2023u\2c\20hb_blob_t>::get\28\29\20const +3375:hb_lazy_loader_t\2c\20hb_face_t\2c\201u\2c\20hb_blob_t>::get\28\29\20const +3376:hb_lazy_loader_t\2c\20hb_face_t\2c\2018u\2c\20hb_blob_t>::get\28\29\20const +3377:hb_lazy_loader_t\2c\20hb_face_t\2c\203u\2c\20OT::cmap_accelerator_t>::get_stored\28\29\20const +3378:hb_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>\2c\20OT::HBGlyphID16&>::end\28\29\20const +3379:hb_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>\2c\20hb_pair_t>::operator++\28\29\20& +3380:hb_hashmap_t::item_t::operator==\28hb_serialize_context_t::object_t\20const*\20const&\29\20const +3381:hb_font_t::mults_changed\28\29 +3382:hb_font_t::has_glyph_h_origin_func\28\29 +3383:hb_font_t::has_func\28unsigned\20int\29 +3384:hb_font_t::get_nominal_glyphs\28unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\29 +3385:hb_font_t::get_glyph_v_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +3386:hb_font_t::get_glyph_v_advances\28unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\29 +3387:hb_font_t::get_glyph_h_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +3388:hb_font_t::get_glyph_h_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +3389:hb_font_t::get_glyph_h_advances\28unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\29 +3390:hb_font_t::get_glyph_contour_point_for_origin\28unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20int*\2c\20int*\29 +3391:hb_font_funcs_destroy +3392:hb_draw_cubic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +3393:hb_buffer_t::output_info\28hb_glyph_info_t\20const&\29 +3394:hb_buffer_t::digest\28\29\20const +3395:hb_buffer_t::_infos_set_glyph_flags\28hb_glyph_info_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +3396:hb_buffer_t::_infos_find_min_cluster\28hb_glyph_info_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +3397:hb_buffer_set_length +3398:hb_buffer_create +3399:hb_blob_ptr_t::destroy\28\29 +3400:haircubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3401:gray_render_line +3402:gl_target_to_gr_target\28unsigned\20int\29 +3403:gl_target_to_binding_index\28unsigned\20int\29 +3404:get_vendor\28char\20const*\29 +3405:get_renderer\28char\20const*\2c\20GrGLExtensions\20const&\29 +3406:get_layer_mapping_and_bounds\28SkSpan>\2c\20SkMatrix\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\2c\20float\29 +3407:get_joining_type\28unsigned\20int\2c\20hb_unicode_general_category_t\29 +3408:get_child_table_pointer +3409:generate_distance_field_from_image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\29 +3410:gaussianIntegral\28float\29 +3411:ft_var_readpackeddeltas +3412:ft_var_done_item_variation_store +3413:ft_glyphslot_alloc_bitmap +3414:ft_face_get_mm_service +3415:freelocale +3416:fputc +3417:fp_barrierf +3418:float*\20SkArenaAlloc::makeArray\28unsigned\20long\29 +3419:fixN0c\28BracketData*\2c\20int\2c\20int\2c\20unsigned\20char\29 +3420:filter_to_gl_min_filter\28SkFilterMode\2c\20SkMipmapMode\29 +3421:exp2 +3422:em_task_queue_execute +3423:dquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3424:do_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +3425:do_anti_hairline\28int\2c\20int\2c\20int\2c\20int\2c\20SkIRect\20const*\2c\20SkBlitter*\29 +3426:dline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3427:directionFromFlags\28UBiDi*\29 +3428:destroy_face +3429:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0>\28skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0&&\29::'lambda'\28char*\29::__invoke\28char*\29 +3430:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool&\2c\20GrPipeline*&\2c\20GrUserStencilSettings\20const*&&\2c\20\28anonymous\20namespace\29::DrawAtlasPathShader*&\2c\20GrPrimitiveType&&\2c\20GrXferBarrierFlags&\2c\20GrLoadOp&\29::'lambda'\28void*\29>\28GrProgramInfo&&\29::'lambda'\28char*\29::__invoke\28char*\29 +3431:dcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3432:dconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3433:cubic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3434:conic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3435:cleanup_shaders\28GrGLGpu*\2c\20SkTDArray\20const&\29 +3436:chop_mono_cubic_at_y\28SkPoint*\2c\20float\2c\20SkPoint*\29 +3437:check_inverse_on_empty_return\28SkRegion*\2c\20SkPath\20const&\2c\20SkRegion\20const&\29 +3438:check_intersection\28SkAnalyticEdge\20const*\2c\20int\2c\20int*\29 +3439:char\20const*\20std::__2::find\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const&\29 +3440:cff_parse_real +3441:cff_parse_integer +3442:cff_index_read_offset +3443:cff_index_get_pointers +3444:cff_index_access_element +3445:cff2_path_param_t::move_to\28CFF::point_t\20const&\29 +3446:cff1_path_param_t::move_to\28CFF::point_t\20const&\29 +3447:cf2_hintmap_map +3448:cf2_glyphpath_pushPrevElem +3449:cf2_glyphpath_computeOffset +3450:cf2_glyphpath_closeOpenPath +3451:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_1::operator\28\29\28int\29\20const +3452:calc_dot_cross_cubic\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +3453:bracketProcessBoundary\28BracketData*\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +3454:bracketAddOpening\28BracketData*\2c\20char16_t\2c\20int\29 +3455:bool\20std::__2::equal\5babi:ne180100\5d\28float\20const*\2c\20float\20const*\2c\20float\20const*\2c\20std::__2::__equal_to\29 +3456:bool\20std::__2::__is_pointer_in_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const*\29 +3457:bool\20SkIsFinite\28float\20const*\2c\20int\29\20\28.643\29 +3458:bool\20SkIsFinite\28float\20const*\2c\20int\29 +3459:bool\20OT::match_lookahead>\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +3460:bool\20OT::match_backtrack>\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\2c\20unsigned\20int*\29 +3461:bool\20OT::glyf_impl::Glyph::get_points\28hb_font_t*\2c\20OT::glyf_accelerator_t\20const&\2c\20contour_point_vector_t&\2c\20contour_point_vector_t*\2c\20head_maxp_info_t*\2c\20unsigned\20int*\2c\20bool\2c\20bool\2c\20bool\2c\20hb_array_t\2c\20hb_map_t*\2c\20unsigned\20int\2c\20unsigned\20int*\29\20const +3462:bool\20OT::glyf_accelerator_t::get_points\28hb_font_t*\2c\20unsigned\20int\2c\20OT::glyf_accelerator_t::points_aggregator_t\29\20const +3463:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3464:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3465:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3466:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3467:blitrect\28SkBlitter*\2c\20SkIRect\20const&\29 +3468:blit_single_alpha\28AdditiveBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +3469:blit_aaa_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +3470:atan +3471:append_index_uv_varyings\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20int\2c\20char\20const*\2c\20char\20const*\2c\20GrGLSLVarying*\2c\20GrGLSLVarying*\2c\20GrGLSLVarying*\29 +3472:antifillrect\28SkRect\20const&\2c\20SkBlitter*\29 +3473:af_property_get_face_globals +3474:af_latin_hints_link_segments +3475:af_latin_compute_stem_width +3476:af_latin_align_linked_edge +3477:af_iup_interp +3478:af_glyph_hints_save +3479:af_glyph_hints_done +3480:af_cjk_align_linked_edge +3481:add_quad\28SkPoint\20const*\2c\20skia_private::TArray*\29 +3482:acos +3483:aaa_fill_path\28SkPath\20const&\2c\20SkIRect\20const&\2c\20AdditiveBlitter*\2c\20int\2c\20int\2c\20bool\2c\20bool\2c\20bool\29 +3484:a_swap +3485:a_store +3486:_iup_worker_interpolate +3487:_hb_head_t\29&>\28fp\29\2c\20std::forward>\28fp0\29\2c\20\28hb_priority<16u>\29\28\29\29\29>::type\20$_14::operator\28\29\29&\2c\20hb_pair_t>\28find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29&\2c\20hb_pair_t&&\29\20const +3488:_hb_font_adopt_var_coords\28hb_font_t*\2c\20int*\2c\20float*\2c\20unsigned\20int\29 +3489:_get_path\28OT::cff1::accelerator_t\20const*\2c\20hb_font_t*\2c\20unsigned\20int\2c\20hb_draw_session_t&\2c\20bool\2c\20CFF::point_t*\29 +3490:_get_bounds\28OT::cff1::accelerator_t\20const*\2c\20unsigned\20int\2c\20bounds_t&\2c\20bool\29 +3491:__trunctfdf2 +3492:__towrite +3493:__toread +3494:__tl_unlock +3495:__tl_lock +3496:__timedwait_cp +3497:__timedwait +3498:__subtf3 +3499:__strchrnul +3500:__rem_pio2f +3501:__rem_pio2 +3502:__pthread_rwlock_timedrdlock +3503:__pthread_mutex_trylock +3504:__overflow +3505:__fwritex +3506:__cxxabiv1::__class_type_info::process_static_type_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\29\20const +3507:__cxxabiv1::__class_type_info::process_static_type_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\29\20const +3508:__cxxabiv1::__class_type_info::process_found_base_class\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +3509:__cxxabiv1::__base_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +3510:\28anonymous\20namespace\29::split_conic\28SkPoint\20const*\2c\20SkConic*\2c\20float\29 +3511:\28anonymous\20namespace\29::single_pass_shape\28GrStyledShape\20const&\29 +3512:\28anonymous\20namespace\29::shift_left\28skvx::Vec<4\2c\20float>\20const&\2c\20int\29 +3513:\28anonymous\20namespace\29::shape_contains_rect\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const&\2c\20bool\29 +3514:\28anonymous\20namespace\29::set_gl_stencil\28GrGLInterface\20const*\2c\20GrStencilSettings::Face\20const&\2c\20unsigned\20int\29 +3515:\28anonymous\20namespace\29::make_blend\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\2c\20std::__2::optional\2c\20bool\29::$_0::operator\28\29\28sk_sp\29\20const +3516:\28anonymous\20namespace\29::get_tile_count\28SkIRect\20const&\2c\20int\29 +3517:\28anonymous\20namespace\29::generateGlyphPathStatic\28FT_FaceRec_*\2c\20SkPath*\29 +3518:\28anonymous\20namespace\29::generateFacePathCOLRv1\28FT_FaceRec_*\2c\20unsigned\20short\2c\20SkPath*\29 +3519:\28anonymous\20namespace\29::gather_lines_and_quads\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\29::$_0::operator\28\29\28SkPoint\20const*\2c\20bool\29\20const +3520:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads_with_constraint\28SkPoint\20const*\2c\20float\2c\20SkPathFirstDirection\2c\20skia_private::TArray*\2c\20int\29 +3521:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\2c\20int\2c\20bool\2c\20bool\29 +3522:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const +3523:\28anonymous\20namespace\29::calculate_colors\28skgpu::ganesh::SurfaceDrawContext*\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20skgpu::MaskFormat\2c\20GrPaint*\29 +3524:\28anonymous\20namespace\29::bloat_quad\28SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkMatrix\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +3525:\28anonymous\20namespace\29::TriangulatingPathOp::CreateMesh\28GrMeshDrawTarget*\2c\20sk_sp\2c\20int\2c\20int\29 +3526:\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29_12077 +3527:\28anonymous\20namespace\29::TransformedMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +3528:\28anonymous\20namespace\29::TransformedMaskSubRun::glyphs\28\29\20const +3529:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29 +3530:\28anonymous\20namespace\29::SkMorphologyImageFilter::radii\28skif::Mapping\20const&\29\20const +3531:\28anonymous\20namespace\29::SkFTGeometrySink::goingTo\28FT_Vector_\20const*\29 +3532:\28anonymous\20namespace\29::SkCropImageFilter::cropRect\28skif::Mapping\20const&\29\20const +3533:\28anonymous\20namespace\29::ShapedRun::~ShapedRun\28\29 +3534:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +3535:\28anonymous\20namespace\29::PathSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +3536:\28anonymous\20namespace\29::MemoryPoolAccessor::pool\28\29\20const +3537:\28anonymous\20namespace\29::DrawAtlasOpImpl::visitProxies\28std::__2::function\20const&\29\20const +3538:\28anonymous\20namespace\29::DrawAtlasOpImpl::programInfo\28\29 +3539:\28anonymous\20namespace\29::DrawAtlasOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +3540:TT_Vary_Apply_Glyph_Deltas +3541:TT_Set_Var_Design +3542:TT_Get_VMetrics +3543:SkWriter32::writeRegion\28SkRegion\20const&\29 +3544:SkVertices::Sizes::Sizes\28SkVertices::Desc\20const&\29 +3545:SkVertices::MakeCopy\28SkVertices::VertexMode\2c\20int\2c\20SkPoint\20const*\2c\20SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20short\20const*\29 +3546:SkVertices::Builder::~Builder\28\29 +3547:SkVertices::Builder::detach\28\29 +3548:SkUnitScalarClampToByte\28float\29 +3549:SkUTF::ToUTF16\28int\2c\20unsigned\20short*\29 +3550:SkTypeface_FreeType::~SkTypeface_FreeType\28\29 +3551:SkTextBlobBuilder::allocInternal\28SkFont\20const&\2c\20SkTextBlob::GlyphPositioning\2c\20int\2c\20int\2c\20SkPoint\2c\20SkRect\20const*\29 +3552:SkTextBlob::RunRecord::textSizePtr\28\29\20const +3553:SkTSpan::markCoincident\28\29 +3554:SkTSect::markSpanGone\28SkTSpan*\29 +3555:SkTSect::computePerpendiculars\28SkTSect*\2c\20SkTSpan*\2c\20SkTSpan*\29 +3556:SkTMultiMap::insert\28skgpu::ScratchKey\20const&\2c\20GrGpuResource*\29 +3557:SkTLazy::getMaybeNull\28\29 +3558:SkTDStorage::moveTail\28int\2c\20int\2c\20int\29 +3559:SkTDStorage::calculateSizeOrDie\28int\29 +3560:SkTDArray::append\28int\29 +3561:SkTDArray::append\28\29 +3562:SkTConic::hullIntersects\28SkDConic\20const&\2c\20bool*\29\20const +3563:SkTBlockList::pop_back\28\29 +3564:SkSurface_Base::~SkSurface_Base\28\29 +3565:SkSurface_Base::aboutToDraw\28SkSurface::ContentChangeMode\29 +3566:SkStrokeRec::init\28SkPaint\20const&\2c\20SkPaint::Style\2c\20float\29 +3567:SkStrokeRec::getInflationRadius\28\29\20const +3568:SkString::printVAList\28char\20const*\2c\20void*\29 +3569:SkString::SkString\28unsigned\20long\29 +3570:SkStrikeSpec::SkStrikeSpec\28SkStrikeSpec&&\29 +3571:SkStrikeSpec::MakeWithNoDevice\28SkFont\20const&\2c\20SkPaint\20const*\29 +3572:SkStrikeSpec::MakePath\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\29 +3573:SkStrikeCache::findOrCreateStrike\28SkStrikeSpec\20const&\29 +3574:SkStrike::prepareForPath\28SkGlyph*\29 +3575:SkSpriteBlitter::SkSpriteBlitter\28SkPixmap\20const&\29 +3576:SkSpecialImage::~SkSpecialImage\28\29 +3577:SkSpecialImage::makeSubset\28SkIRect\20const&\29\20const +3578:SkSpecialImage::makePixelOutset\28\29\20const +3579:SkSize\20skif::Mapping::map\28SkSize\20const&\2c\20SkMatrix\20const&\29 +3580:SkShapers::HB::ScriptRunIterator\28char\20const*\2c\20unsigned\20long\29 +3581:SkShaper::TrivialRunIterator::endOfCurrentRun\28\29\20const +3582:SkShaper::TrivialRunIterator::consume\28\29 +3583:SkShaper::TrivialRunIterator::atEnd\28\29\20const +3584:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29 +3585:SkShaders::MatrixRec::MatrixRec\28SkMatrix\20const&\29 +3586:SkShaderUtils::GLSLPrettyPrint::tabString\28\29 +3587:SkScanClipper::~SkScanClipper\28\29 +3588:SkScanClipper::SkScanClipper\28SkBlitter*\2c\20SkRegion\20const*\2c\20SkIRect\20const&\2c\20bool\2c\20bool\29 +3589:SkScan::HairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3590:SkScan::FillTriangle\28SkPoint\20const*\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3591:SkScan::FillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3592:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3593:SkScan::AntiHairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3594:SkScan::AntiHairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3595:SkScan::AntiFillXRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3596:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\2c\20bool\29 +3597:SkScalerContext_FreeType::updateGlyphBoundsIfSubpixel\28SkGlyph\20const&\2c\20SkRect*\2c\20bool\29 +3598:SkScalerContextRec::CachedMaskGamma\28unsigned\20char\2c\20unsigned\20char\29 +3599:SkScalerContextFTUtils::drawSVGGlyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +3600:SkScalerContext::~SkScalerContext\28\29 +3601:SkSTArenaAlloc<2048ul>::SkSTArenaAlloc\28unsigned\20long\29 +3602:SkSL::type_is_valid_for_coords\28SkSL::Type\20const&\29 +3603:SkSL::simplify_negation\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\29 +3604:SkSL::simplify_matrix_multiplication\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3605:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +3606:SkSL::replace_empty_with_nop\28std::__2::unique_ptr>\2c\20bool\29 +3607:SkSL::find_generic_index\28SkSL::Type\20const&\2c\20SkSL::Type\20const&\2c\20bool\29 +3608:SkSL::evaluate_intrinsic_numeric\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +3609:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29 +3610:SkSL::coalesce_n_way_vector\28SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +3611:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_0::operator\28\29\28int\29\20const +3612:SkSL::build_argument_type_list\28SkSpan>\20const>\29 +3613:SkSL::\28anonymous\20namespace\29::SwitchCaseContainsExit::visitStatement\28SkSL::Statement\20const&\29 +3614:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::returnsInputAlpha\28SkSL::Expression\20const&\29 +3615:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29 +3616:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29 +3617:SkSL::\28anonymous\20namespace\29::ConstantExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +3618:SkSL::Variable::~Variable\28\29 +3619:SkSL::Variable::Make\28SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20std::__2::basic_string_view>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20bool\2c\20SkSL::VariableStorage\29 +3620:SkSL::Variable::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\29 +3621:SkSL::VarDeclaration::~VarDeclaration\28\29 +3622:SkSL::VarDeclaration::Make\28SkSL::Context\20const&\2c\20SkSL::Variable*\2c\20SkSL::Type\20const*\2c\20int\2c\20std::__2::unique_ptr>\29 +3623:SkSL::Type::isStorageTexture\28\29\20const +3624:SkSL::Type::convertArraySize\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20long\20long\29\20const +3625:SkSL::Type::MakeSamplerType\28char\20const*\2c\20SkSL::Type\20const&\29 +3626:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29 +3627:SkSL::Transform::EliminateDeadGlobalVariables\28SkSL::Program&\29::$_2::operator\28\29\28SkSL::ProgramElement\20const&\29\20const +3628:SkSL::TernaryExpression::~TernaryExpression\28\29 +3629:SkSL::SymbolTable::SymbolKey::operator==\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +3630:SkSL::SingleArgumentConstructor::~SingleArgumentConstructor\28\29 +3631:SkSL::RP::UnownedLValueSlice::~UnownedLValueSlice\28\29 +3632:SkSL::RP::SlotManager::createSlots\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20bool\29 +3633:SkSL::RP::SlotManager::addSlotDebugInfoForGroup\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20int*\2c\20bool\29 +3634:SkSL::RP::Program::makeStages\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSpan\2c\20SkSL::RP::Program::SlotData\20const&\29\20const::$_4::operator\28\29\28\29\20const +3635:SkSL::RP::Program::makeStages\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSpan\2c\20SkSL::RP::Program::SlotData\20const&\29\20const::$_1::operator\28\29\28int\29\20const +3636:SkSL::RP::Program::appendCopySlotsMasked\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +3637:SkSL::RP::LValueSlice::~LValueSlice\28\29 +3638:SkSL::RP::Generator::pushTraceScopeMask\28\29 +3639:SkSL::RP::Generator::pushTernaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +3640:SkSL::RP::Generator::pushStructuredComparison\28SkSL::RP::LValue*\2c\20SkSL::Operator\2c\20SkSL::RP::LValue*\2c\20SkSL::Type\20const&\29 +3641:SkSL::RP::Generator::pushPrefixExpression\28SkSL::Operator\2c\20SkSL::Expression\20const&\29 +3642:SkSL::RP::Generator::pushMatrixMultiply\28SkSL::RP::LValue*\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3643:SkSL::RP::Generator::pushAbsFloatIntrinsic\28int\29 +3644:SkSL::RP::Generator::needsReturnMask\28SkSL::FunctionDefinition\20const*\29 +3645:SkSL::RP::Generator::needsFunctionResultSlots\28SkSL::FunctionDefinition\20const*\29 +3646:SkSL::RP::Generator::foldWithMultiOp\28SkSL::RP::BuilderOp\2c\20int\29 +3647:SkSL::RP::Generator::GetTypedOp\28SkSL::Type\20const&\2c\20SkSL::RP::Generator::TypedOps\20const&\29 +3648:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29 +3649:SkSL::RP::Builder::select\28int\29 +3650:SkSL::RP::Builder::push_uniform\28SkSL::RP::SlotRange\29 +3651:SkSL::RP::Builder::pop_loop_mask\28\29 +3652:SkSL::RP::Builder::merge_condition_mask\28\29 +3653:SkSL::RP::Builder::branch_if_no_active_lanes_on_stack_top_equal\28int\2c\20int\29 +3654:SkSL::RP::AutoStack&\20std::__2::optional::emplace\5babi:ne180100\5d\28SkSL::RP::Generator*&\29 +3655:SkSL::ProgramUsage::add\28SkSL::ProgramElement\20const&\29 +3656:SkSL::PipelineStage::PipelineStageCodeGenerator::modifierString\28SkSL::ModifierFlags\29 +3657:SkSL::PipelineStage::ConvertProgram\28SkSL::Program\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20SkSL::PipelineStage::Callbacks*\29 +3658:SkSL::Parser::unsizedArrayType\28SkSL::Type\20const*\2c\20SkSL::Position\29 +3659:SkSL::Parser::unaryExpression\28\29 +3660:SkSL::Parser::swizzle\28SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::basic_string_view>\2c\20SkSL::Position\29 +3661:SkSL::Parser::poison\28SkSL::Position\29 +3662:SkSL::Parser::checkIdentifier\28SkSL::Token*\29 +3663:SkSL::Parser::block\28bool\2c\20std::__2::unique_ptr>*\29 +3664:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29 +3665:SkSL::Operator::getBinaryPrecedence\28\29\20const +3666:SkSL::MultiArgumentConstructor::~MultiArgumentConstructor\28\29 +3667:SkSL::ModuleLoader::loadVertexModule\28SkSL::Compiler*\29 +3668:SkSL::ModuleLoader::loadGPUModule\28SkSL::Compiler*\29 +3669:SkSL::ModuleLoader::loadFragmentModule\28SkSL::Compiler*\29 +3670:SkSL::ModifierFlags::checkPermittedFlags\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\29\20const +3671:SkSL::Mangler::uniqueName\28std::__2::basic_string_view>\2c\20SkSL::SymbolTable*\29 +3672:SkSL::LiteralType::slotType\28unsigned\20long\29\20const +3673:SkSL::Literal::MakeFloat\28SkSL::Position\2c\20float\2c\20SkSL::Type\20const*\29 +3674:SkSL::Literal::MakeBool\28SkSL::Position\2c\20bool\2c\20SkSL::Type\20const*\29 +3675:SkSL::Layout::checkPermittedLayout\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkEnumBitMask\29\20const +3676:SkSL::IfStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3677:SkSL::IRHelpers::Binary\28std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29\20const +3678:SkSL::GlobalVarDeclaration::~GlobalVarDeclaration\28\29_5900 +3679:SkSL::GlobalVarDeclaration::~GlobalVarDeclaration\28\29 +3680:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29 +3681:SkSL::GLSLCodeGenerator::writeLiteral\28SkSL::Literal\20const&\29 +3682:SkSL::GLSLCodeGenerator::writeFunctionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +3683:SkSL::GLSLCodeGenerator::shouldRewriteVoidTypedFunctions\28SkSL::FunctionDeclaration\20const*\29\20const +3684:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29 +3685:SkSL::ForStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3686:SkSL::Expression::isIncomplete\28SkSL::Context\20const&\29\20const +3687:SkSL::Expression::compareConstant\28SkSL::Expression\20const&\29\20const +3688:SkSL::DoStatement::~DoStatement\28\29 +3689:SkSL::DebugTracePriv::~DebugTracePriv\28\29 +3690:SkSL::ConstructorArrayCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +3691:SkSL::ConstructorArray::~ConstructorArray\28\29 +3692:SkSL::ConstantFolder::GetConstantValueOrNull\28SkSL::Expression\20const&\29 +3693:SkSL::Compiler::runInliner\28SkSL::Inliner*\2c\20std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\29 +3694:SkSL::Block::~Block\28\29 +3695:SkSL::BinaryExpression::~BinaryExpression\28\29 +3696:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\2c\20SkSL::Type\20const*\29 +3697:SkSL::Analysis::GetReturnComplexity\28SkSL::FunctionDefinition\20const&\29 +3698:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29 +3699:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29 +3700:SkSL::Analysis::CallsColorTransformIntrinsics\28SkSL::Program\20const&\29 +3701:SkSL::AliasType::bitWidth\28\29\20const +3702:SkRuntimeShader::uniformData\28SkColorSpace\20const*\29\20const +3703:SkRuntimeEffectPriv::VarAsUniform\28SkSL::Variable\20const&\2c\20SkSL::Context\20const&\2c\20unsigned\20long*\29 +3704:SkRuntimeEffect::makeShader\28sk_sp\2c\20SkSpan\2c\20SkMatrix\20const*\29\20const +3705:SkRuntimeEffect::MakeForShader\28SkString\29 +3706:SkRgnBuilder::~SkRgnBuilder\28\29 +3707:SkResourceCache::checkMessages\28\29 +3708:SkResourceCache::Key::operator==\28SkResourceCache::Key\20const&\29\20const +3709:SkRegion::translate\28int\2c\20int\2c\20SkRegion*\29\20const +3710:SkRegion::op\28SkRegion\20const&\2c\20SkIRect\20const&\2c\20SkRegion::Op\29 +3711:SkRegion::RunHead::findScanline\28int\29\20const +3712:SkRegion::RunHead::Alloc\28int\29 +3713:SkReduceOrder::Cubic\28SkPoint\20const*\2c\20SkPoint*\29 +3714:SkRect::offset\28float\2c\20float\29 +3715:SkRect*\20SkRecorder::copy\28SkRect\20const*\29 +3716:SkRecords::PreCachedPath::PreCachedPath\28SkPath\20const&\29 +3717:SkRecords::FillBounds::pushSaveBlock\28SkPaint\20const*\2c\20bool\29 +3718:SkRecorder::~SkRecorder\28\29 +3719:SkRecordDraw\28SkRecord\20const&\2c\20SkCanvas*\2c\20SkPicture\20const*\20const*\2c\20SkDrawable*\20const*\2c\20int\2c\20SkBBoxHierarchy\20const*\2c\20SkPicture::AbortCallback*\29 +3720:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29 +3721:SkRasterPipelineBlitter::blitRectWithTrace\28int\2c\20int\2c\20int\2c\20int\2c\20bool\29 +3722:SkRasterPipelineBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29::$_0::operator\28\29\28int\2c\20SkRasterPipeline_MemoryCtx*\29\20const +3723:SkRasterPipelineBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +3724:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29 +3725:SkRasterPipeline::appendStore\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +3726:SkRasterClip::op\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkClipOp\2c\20bool\29 +3727:SkRasterClip::convertToAA\28\29 +3728:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29::$_1::operator\28\29\28SkRect\20const&\2c\20SkRRect::Corner\29\20const +3729:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29 +3730:SkRRect::scaleRadii\28\29 +3731:SkRRect::AreRectAndRadiiValid\28SkRect\20const&\2c\20SkPoint\20const*\29 +3732:SkRGBA4f<\28SkAlphaType\292>*\20SkArenaAlloc::makeArray>\28unsigned\20long\29 +3733:SkQuadraticEdge::updateQuadratic\28\29 +3734:SkQuadConstruct::initWithStart\28SkQuadConstruct*\29 +3735:SkQuadConstruct::initWithEnd\28SkQuadConstruct*\29 +3736:SkPointPriv::DistanceToLineBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPointPriv::Side*\29 +3737:SkPoint::setNormalize\28float\2c\20float\29 +3738:SkPoint::setLength\28float\2c\20float\2c\20float\29 +3739:SkPixmap::setColorSpace\28sk_sp\29 +3740:SkPixmap::rowBytesAsPixels\28\29\20const +3741:SkPixelRef::getGenerationID\28\29\20const +3742:SkPictureRecorder::~SkPictureRecorder\28\29 +3743:SkPictureRecorder::SkPictureRecorder\28\29 +3744:SkPicture::~SkPicture\28\29 +3745:SkPerlinNoiseShader::PaintingData::random\28\29 +3746:SkPathWriter::~SkPathWriter\28\29 +3747:SkPathWriter::update\28SkOpPtT\20const*\29 +3748:SkPathWriter::lineTo\28\29 +3749:SkPathWriter::SkPathWriter\28SkPath&\29 +3750:SkPathStroker::strokeCloseEnough\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20SkQuadConstruct*\29\20const +3751:SkPathStroker::setRayPts\28SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +3752:SkPathStroker::quadPerpRay\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +3753:SkPathStroker::finishContour\28bool\2c\20bool\29 +3754:SkPathStroker::conicPerpRay\28SkConic\20const&\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +3755:SkPathPriv::IsRectContour\28SkPath\20const&\2c\20bool\2c\20int*\2c\20SkPoint\20const**\2c\20bool*\2c\20SkPathDirection*\2c\20SkRect*\29 +3756:SkPathPriv::AddGenIDChangeListener\28SkPath\20const&\2c\20sk_sp\29 +3757:SkPathEffect::filterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +3758:SkPathBuilder::quadTo\28SkPoint\2c\20SkPoint\29 +3759:SkPathBuilder::moveTo\28float\2c\20float\29 +3760:SkPathBuilder::cubicTo\28SkPoint\2c\20SkPoint\2c\20SkPoint\29 +3761:SkPathBuilder::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3762:SkPath::setLastPt\28float\2c\20float\29 +3763:SkPath::reversePathTo\28SkPath\20const&\29 +3764:SkPath::rQuadTo\28float\2c\20float\2c\20float\2c\20float\29 +3765:SkPath::isLastContourClosed\28\29\20const +3766:SkPath::cubicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +3767:SkPath::contains\28float\2c\20float\29\20const +3768:SkPath::conicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\29 +3769:SkPath::arcTo\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\29::$_0::operator\28\29\28SkPoint\20const&\29\20const +3770:SkPath::addPath\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPath::AddPathMode\29 +3771:SkPath::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3772:SkPath::Rect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3773:SkPath::Iter::autoClose\28SkPoint*\29 +3774:SkPath*\20SkTLazy::init<>\28\29 +3775:SkPaintToGrPaintReplaceShader\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::unique_ptr>\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +3776:SkPaint::getBlendMode_or\28SkBlendMode\29\20const +3777:SkPackedGlyphID::PackIDSkPoint\28unsigned\20short\2c\20SkPoint\2c\20SkIPoint\29 +3778:SkOpSpanBase::checkForCollapsedCoincidence\28\29 +3779:SkOpSpan::setWindSum\28int\29 +3780:SkOpSegment::updateWindingReverse\28SkOpAngle\20const*\29 +3781:SkOpSegment::match\28SkOpPtT\20const*\2c\20SkOpSegment\20const*\2c\20double\2c\20SkPoint\20const&\29\20const +3782:SkOpSegment::markWinding\28SkOpSpan*\2c\20int\2c\20int\29 +3783:SkOpSegment::markAngle\28int\2c\20int\2c\20int\2c\20int\2c\20SkOpAngle\20const*\2c\20SkOpSpanBase**\29 +3784:SkOpSegment::markAngle\28int\2c\20int\2c\20SkOpAngle\20const*\2c\20SkOpSpanBase**\29 +3785:SkOpSegment::markAndChaseWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int\2c\20int\2c\20SkOpSpanBase**\29 +3786:SkOpSegment::markAllDone\28\29 +3787:SkOpSegment::dSlopeAtT\28double\29\20const +3788:SkOpSegment::addT\28double\2c\20SkPoint\20const&\29 +3789:SkOpSegment::activeWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +3790:SkOpPtT::oppPrev\28SkOpPtT\20const*\29\20const +3791:SkOpPtT::contains\28SkOpSegment\20const*\29\20const +3792:SkOpPtT::Overlaps\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const**\2c\20SkOpPtT\20const**\29 +3793:SkOpEdgeBuilder::closeContour\28SkPoint\20const&\2c\20SkPoint\20const&\29 +3794:SkOpCoincidence::expand\28\29 +3795:SkOpCoincidence::Ordered\28SkOpSegment\20const*\2c\20SkOpSegment\20const*\29 +3796:SkOpCoincidence::Ordered\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\29 +3797:SkOpAngle::orderable\28SkOpAngle*\29 +3798:SkOpAngle::lineOnOneSide\28SkDPoint\20const&\2c\20SkDVector\20const&\2c\20SkOpAngle\20const*\2c\20bool\29\20const +3799:SkOpAngle::computeSector\28\29 +3800:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\2c\20sk_sp\29 +3801:SkMipmapAccessor::SkMipmapAccessor\28SkImage_Base\20const*\2c\20SkMatrix\20const&\2c\20SkMipmapMode\29::$_0::operator\28\29\28\29\20const +3802:SkMessageBus::Get\28\29 +3803:SkMessageBus::Get\28\29 +3804:SkMessageBus::BufferFinishedMessage\2c\20GrDirectContext::DirectContextID\2c\20false>::Get\28\29 +3805:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2707 +3806:SkMatrix\20skif::Mapping::map\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +3807:SkMatrixPriv::InverseMapRect\28SkMatrix\20const&\2c\20SkRect*\2c\20SkRect\20const&\29 +3808:SkMatrix::setPolyToPoly\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20int\29 +3809:SkMatrix::preservesRightAngles\28float\29\20const +3810:SkMatrix::mapRectToQuad\28SkPoint*\2c\20SkRect\20const&\29\20const +3811:SkMatrix::mapRectScaleTranslate\28SkRect*\2c\20SkRect\20const&\29\20const +3812:SkMatrix::getMinMaxScales\28float*\29\20const +3813:SkMatrix::getMapXYProc\28\29\20const +3814:SkMaskBuilder::PrepareDestination\28int\2c\20int\2c\20SkMask\20const&\29 +3815:SkLineParameters::cubicEndPoints\28SkDCubic\20const&\2c\20int\2c\20int\29 +3816:SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry::~Entry\28\29 +3817:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::reset\28\29 +3818:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry::~Entry\28\29 +3819:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_matrix_conv_effect\28SkKnownRuntimeEffects::\28anonymous\20namespace\29::MatrixConvolutionImpl\2c\20SkRuntimeEffect::Options\20const&\29 +3820:SkJSONWriter::separator\28bool\29 +3821:SkJSONWriter::appendString\28char\20const*\2c\20unsigned\20long\29 +3822:SkJSONWriter::appendS32\28char\20const*\2c\20int\29 +3823:SkIntersections::intersectRay\28SkDQuad\20const&\2c\20SkDLine\20const&\29 +3824:SkIntersections::intersectRay\28SkDLine\20const&\2c\20SkDLine\20const&\29 +3825:SkIntersections::intersectRay\28SkDCubic\20const&\2c\20SkDLine\20const&\29 +3826:SkIntersections::intersectRay\28SkDConic\20const&\2c\20SkDLine\20const&\29 +3827:SkIntersections::computePoints\28SkDLine\20const&\2c\20int\29 +3828:SkIntersections::cleanUpParallelLines\28bool\29 +3829:SkImage_Raster::SkImage_Raster\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20int\29 +3830:SkImage_Lazy::~SkImage_Lazy\28\29_4400 +3831:SkImage_Lazy::Validator::~Validator\28\29 +3832:SkImage_Lazy::Validator::Validator\28sk_sp\2c\20SkColorType\20const*\2c\20sk_sp\29 +3833:SkImage_Lazy::SkImage_Lazy\28SkImage_Lazy::Validator*\29 +3834:SkImage_Ganesh::~SkImage_Ganesh\28\29 +3835:SkImage_Ganesh::ProxyChooser::chooseProxy\28GrRecordingContext*\29 +3836:SkImage_Base::isYUVA\28\29\20const +3837:SkImageShader::MakeSubset\28sk_sp\2c\20SkRect\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +3838:SkImageShader::CubicResamplerMatrix\28float\2c\20float\29 +3839:SkImageInfo::minRowBytes64\28\29\20const +3840:SkImageInfo::makeAlphaType\28SkAlphaType\29\20const +3841:SkImageInfo::MakeN32Premul\28SkISize\29 +3842:SkImageGenerator::getPixels\28SkPixmap\20const&\29 +3843:SkImageFilters::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +3844:SkImageFilter_Base::filterImage\28skif::Context\20const&\29\20const +3845:SkImageFilter_Base::affectsTransparentBlack\28\29\20const +3846:SkImageFilterCacheKey::operator==\28SkImageFilterCacheKey\20const&\29\20const +3847:SkImage::readPixels\28GrDirectContext*\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +3848:SkImage::peekPixels\28SkPixmap*\29\20const +3849:SkImage::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\29\20const +3850:SkIRect::offset\28SkIPoint\20const&\29 +3851:SkIRect::containsNoEmptyCheck\28SkIRect\20const&\29\20const +3852:SkIRect::MakeXYWH\28int\2c\20int\2c\20int\2c\20int\29 +3853:SkIDChangeListener::List::~List\28\29 +3854:SkIDChangeListener::List::add\28sk_sp\29 +3855:SkGradientShader::MakeSweep\28float\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3856:SkGradientShader::MakeRadial\28SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3857:SkGradientBaseShader::AppendInterpolatedToDstStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20bool\2c\20SkGradientShader::Interpolation\20const&\2c\20SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +3858:SkGlyph::mask\28\29\20const +3859:SkFontScanner_FreeType::openFace\28SkStreamAsset*\2c\20int\2c\20FT_StreamRec_*\29\20const +3860:SkFontPriv::ApproximateTransformedTextSize\28SkFont\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\20const&\29 +3861:SkFontMgr::matchFamily\28char\20const*\29\20const +3862:SkFont::getWidthsBounds\28unsigned\20short\20const*\2c\20int\2c\20float*\2c\20SkRect*\2c\20SkPaint\20const*\29\20const +3863:SkFont::getBounds\28unsigned\20short\20const*\2c\20int\2c\20SkRect*\2c\20SkPaint\20const*\29\20const +3864:SkFindCubicMaxCurvature\28SkPoint\20const*\2c\20float*\29 +3865:SkFILEStream::SkFILEStream\28std::__2::shared_ptr<_IO_FILE>\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +3866:SkEmptyFontMgr::onMatchFamilyStyleCharacter\28char\20const*\2c\20SkFontStyle\20const&\2c\20char\20const**\2c\20int\2c\20int\29\20const +3867:SkEdgeClipper::appendQuad\28SkPoint\20const*\2c\20bool\29 +3868:SkEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkIRect\20const*\2c\20int\29 +3869:SkDrawTreatAAStrokeAsHairline\28float\2c\20SkMatrix\20const&\2c\20float*\29 +3870:SkDrawBase::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29\20const +3871:SkDrawBase::drawDevicePoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\2c\20SkDevice*\29\20const +3872:SkDevice::getRelativeTransform\28SkDevice\20const&\29\20const +3873:SkDevice::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +3874:SkDevice::drawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +3875:SkDevice::SkDevice\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +3876:SkData::MakeZeroInitialized\28unsigned\20long\29 +3877:SkData::MakeWithoutCopy\28void\20const*\2c\20unsigned\20long\29 +3878:SkDQuad::FindExtrema\28double\20const*\2c\20double*\29 +3879:SkDCubic::subDivide\28double\2c\20double\29\20const +3880:SkDCubic::searchRoots\28double*\2c\20int\2c\20double\2c\20SkDCubic::SearchAxis\2c\20double*\29\20const +3881:SkDCubic::monotonicInX\28\29\20const +3882:SkDCubic::findInflections\28double*\29\20const +3883:SkDConic::FindExtrema\28double\20const*\2c\20float\2c\20double*\29 +3884:SkCubicEdge::updateCubic\28\29 +3885:SkContourMeasure_segTo\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20float\2c\20SkPath*\29 +3886:SkContourMeasureIter::next\28\29 +3887:SkContourMeasureIter::Impl::compute_quad_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3888:SkContourMeasureIter::Impl::compute_cubic_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3889:SkContourMeasureIter::Impl::compute_conic_segs\28SkConic\20const&\2c\20float\2c\20int\2c\20SkPoint\20const&\2c\20int\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20int\29 +3890:SkContourMeasure::distanceToSegment\28float\2c\20float*\29\20const +3891:SkConic::evalAt\28float\2c\20SkPoint*\2c\20SkPoint*\29\20const +3892:SkConic::evalAt\28float\29\20const +3893:SkConic::TransformW\28SkPoint\20const*\2c\20float\2c\20SkMatrix\20const&\29 +3894:SkCompressedDataSize\28SkTextureCompressionType\2c\20SkISize\2c\20skia_private::TArray*\2c\20bool\29 +3895:SkColorSpace::serialize\28\29\20const +3896:SkColorSpace::MakeRGB\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +3897:SkColorInfo::operator=\28SkColorInfo&&\29 +3898:SkCoincidentSpans::extend\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\29 +3899:SkChopQuadAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +3900:SkCapabilities::RasterBackend\28\29 +3901:SkCanvas::scale\28float\2c\20float\29 +3902:SkCanvas::saveLayer\28SkCanvas::SaveLayerRec\20const&\29 +3903:SkCanvas::onResetClip\28\29 +3904:SkCanvas::onClipShader\28sk_sp\2c\20SkClipOp\29 +3905:SkCanvas::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +3906:SkCanvas::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3907:SkCanvas::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3908:SkCanvas::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3909:SkCanvas::internalSave\28\29 +3910:SkCanvas::internalRestore\28\29 +3911:SkCanvas::internalDrawDeviceWithFilter\28SkDevice*\2c\20SkDevice*\2c\20SkSpan>\2c\20SkPaint\20const&\2c\20SkCanvas::DeviceCompatibleWithFilter\2c\20SkColorInfo\20const&\2c\20float\2c\20SkTileMode\2c\20bool\29 +3912:SkCanvas::drawColor\28unsigned\20int\2c\20SkBlendMode\29 +3913:SkCanvas::clipRect\28SkRect\20const&\2c\20bool\29 +3914:SkCanvas::clipPath\28SkPath\20const&\2c\20bool\29 +3915:SkCanvas::clear\28unsigned\20int\29 +3916:SkCanvas::clear\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +3917:SkCanvas::attemptBlurredRRectDraw\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20SkEnumBitMask\29 +3918:SkCachedData::~SkCachedData\28\29 +3919:SkBlurEngine::BoxBlurWindow\28float\29 +3920:SkBlitterClipper::~SkBlitterClipper\28\29 +3921:SkBlitter::blitRegion\28SkRegion\20const&\29 +3922:SkBlendShader::~SkBlendShader\28\29 +3923:SkBitmapDevice::SkBitmapDevice\28SkBitmap\20const&\2c\20SkSurfaceProps\20const&\2c\20void*\29 +3924:SkBitmapDevice::Create\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\2c\20SkRasterHandleAllocator*\29 +3925:SkBitmapDevice::BDDraw::~BDDraw\28\29 +3926:SkBitmapDevice::BDDraw::BDDraw\28SkBitmapDevice*\29 +3927:SkBitmap::writePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +3928:SkBitmap::setPixels\28void*\29 +3929:SkBitmap::readPixels\28SkPixmap\20const&\2c\20int\2c\20int\29\20const +3930:SkBitmap::installPixels\28SkPixmap\20const&\29 +3931:SkBitmap::allocPixels\28\29 +3932:SkBitmap::SkBitmap\28SkBitmap&&\29 +3933:SkBinaryWriteBuffer::writeScalarArray\28float\20const*\2c\20unsigned\20int\29 +3934:SkBinaryWriteBuffer::writeInt\28int\29 +3935:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29_5157 +3936:SkBaseShadowTessellator::handleLine\28SkPoint\20const&\29 +3937:SkAutoPixmapStorage::freeStorage\28\29 +3938:SkAutoPathBoundsUpdate::~SkAutoPathBoundsUpdate\28\29 +3939:SkAutoPathBoundsUpdate::SkAutoPathBoundsUpdate\28SkPath*\2c\20SkRect\20const&\29 +3940:SkAutoMalloc::reset\28unsigned\20long\2c\20SkAutoMalloc::OnShrink\29 +3941:SkAutoDescriptor::free\28\29 +3942:SkArenaAllocWithReset::reset\28\29 +3943:SkAnalyticQuadraticEdge::updateQuadratic\28\29 +3944:SkAnalyticEdge::goY\28int\29 +3945:SkAnalyticCubicEdge::updateCubic\28bool\29 +3946:SkAAClipBlitter::ensureRunsAndAA\28\29 +3947:SkAAClip::setRegion\28SkRegion\20const&\29 +3948:SkAAClip::setRect\28SkIRect\20const&\29 +3949:SkAAClip::quickContains\28int\2c\20int\2c\20int\2c\20int\29\20const +3950:SkAAClip::RunHead::Alloc\28int\2c\20unsigned\20long\29 +3951:SkAAClip::Builder::AppendRun\28SkTDArray&\2c\20unsigned\20int\2c\20int\29 +3952:Sk4f_toL32\28skvx::Vec<4\2c\20float>\20const&\29 +3953:SSVertex*\20SkArenaAlloc::make\28GrTriangulator::Vertex*&\29 +3954:RunBasedAdditiveBlitter::flush\28\29 +3955:R.10100 +3956:OpAsWinding::nextEdge\28Contour&\2c\20OpAsWinding::Edge\29 +3957:OT::sbix::get_strike\28unsigned\20int\29\20const +3958:OT::hb_paint_context_t::get_color\28unsigned\20int\2c\20float\2c\20int*\29 +3959:OT::hb_ot_apply_context_t::skipping_iterator_t::prev\28unsigned\20int*\29 +3960:OT::hb_ot_apply_context_t::check_glyph_property\28hb_glyph_info_t\20const*\2c\20unsigned\20int\29\20const +3961:OT::glyf_impl::CompositeGlyphRecord::translate\28contour_point_t\20const&\2c\20hb_array_t\29 +3962:OT::VariationStore::sanitize\28hb_sanitize_context_t*\29\20const +3963:OT::VarSizedBinSearchArrayOf>\2c\20OT::IntType\2c\20false>>>::get_length\28\29\20const +3964:OT::Script::get_lang_sys\28unsigned\20int\29\20const +3965:OT::PaintSkew::sanitize\28hb_sanitize_context_t*\29\20const +3966:OT::OpenTypeOffsetTable::sanitize\28hb_sanitize_context_t*\29\20const +3967:OT::OS2::has_data\28\29\20const +3968:OT::Layout::GSUB_impl::SubstLookup::serialize_ligature\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20hb_sorted_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\29 +3969:OT::Layout::GPOS_impl::MarkArray::apply\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20OT::Layout::GPOS_impl::AnchorMatrix\20const&\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +3970:OT::HVARVVAR::sanitize\28hb_sanitize_context_t*\29\20const +3971:OT::GSUBGPOS::get_lookup_count\28\29\20const +3972:OT::GSUBGPOS::get_feature_list\28\29\20const +3973:OT::GSUBGPOS::accelerator_t::get_accel\28unsigned\20int\29\20const +3974:OT::Device::get_y_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3975:OT::Device::get_x_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3976:OT::ClipList::get_extents\28unsigned\20int\2c\20hb_glyph_extents_t*\2c\20OT::VarStoreInstancer\20const&\29\20const +3977:OT::COLR::paint_glyph\28hb_font_t*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29\20const +3978:OT::ArrayOf>::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20bool\29 +3979:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29 +3980:LineQuadraticIntersections::uniqueAnswer\28double\2c\20SkDPoint\20const&\29 +3981:LineQuadraticIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineQuadraticIntersections::PinTPoint\29 +3982:LineQuadraticIntersections::checkCoincident\28\29 +3983:LineQuadraticIntersections::addLineNearEndPoints\28\29 +3984:LineCubicIntersections::uniqueAnswer\28double\2c\20SkDPoint\20const&\29 +3985:LineCubicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineCubicIntersections::PinTPoint\29 +3986:LineCubicIntersections::checkCoincident\28\29 +3987:LineCubicIntersections::addLineNearEndPoints\28\29 +3988:LineConicIntersections::validT\28double*\2c\20double\2c\20double*\29 +3989:LineConicIntersections::uniqueAnswer\28double\2c\20SkDPoint\20const&\29 +3990:LineConicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineConicIntersections::PinTPoint\29 +3991:LineConicIntersections::checkCoincident\28\29 +3992:LineConicIntersections::addLineNearEndPoints\28\29 +3993:HandleInnerJoin\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +3994:GrVertexChunkBuilder::~GrVertexChunkBuilder\28\29 +3995:GrTriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +3996:GrTriangulator::splitEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +3997:GrTriangulator::pathToPolys\28float\2c\20SkRect\20const&\2c\20bool*\29 +3998:GrTriangulator::makePoly\28GrTriangulator::Poly**\2c\20GrTriangulator::Vertex*\2c\20int\29\20const +3999:GrTriangulator::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20GrTriangulator::VertexList*\2c\20int\29\20const +4000:GrTriangulator::checkForIntersection\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +4001:GrTriangulator::applyFillType\28int\29\20const +4002:GrTriangulator::SortMesh\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +4003:GrTriangulator::MonotonePoly::addEdge\28GrTriangulator::Edge*\29 +4004:GrTriangulator::GrTriangulator\28SkPath\20const&\2c\20SkArenaAlloc*\29 +4005:GrTriangulator::Edge::insertBelow\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +4006:GrTriangulator::Edge::insertAbove\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +4007:GrTriangulator::BreadcrumbTriangleList::append\28SkArenaAlloc*\2c\20SkPoint\2c\20SkPoint\2c\20SkPoint\2c\20int\29 +4008:GrThreadSafeCache::recycleEntry\28GrThreadSafeCache::Entry*\29 +4009:GrThreadSafeCache::dropAllRefs\28\29 +4010:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9474 +4011:GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +4012:GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +4013:GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +4014:GrTextureRenderTargetProxy::callbackDesc\28\29\20const +4015:GrTextureProxy::~GrTextureProxy\28\29 +4016:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::$_0::operator\28\29\28int\2c\20GrSamplerState::WrapMode\29\20const +4017:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29 +4018:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_3::operator\28\29\28bool\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +4019:GrTexture::GrTexture\28GrGpu*\2c\20SkISize\20const&\2c\20skgpu::Protected\2c\20GrTextureType\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +4020:GrTexture::ComputeScratchKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20skgpu::ScratchKey*\29 +4021:GrSurfaceProxyView::asTextureProxyRef\28\29\20const +4022:GrSurfaceProxy::instantiateImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::UniqueKey\20const*\29 +4023:GrSurfaceProxy::GrSurfaceProxy\28sk_sp\2c\20SkBackingFit\2c\20GrSurfaceProxy::UseAllocator\29 +4024:GrStyledShape::styledBounds\28\29\20const +4025:GrStyledShape::addGenIDChangeListener\28sk_sp\29\20const +4026:GrStyledShape::GrStyledShape\28SkRect\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +4027:GrStyle::isSimpleHairline\28\29\20const +4028:GrStyle::initPathEffect\28sk_sp\29 +4029:GrStencilSettings::Face::reset\28GrTStencilFaceSettings\20const&\2c\20bool\2c\20int\29 +4030:GrSimpleMeshDrawOpHelper::fixedFunctionFlags\28\29\20const +4031:GrShape::setPath\28SkPath\20const&\29 +4032:GrShape::segmentMask\28\29\20const +4033:GrShape::operator=\28GrShape\20const&\29 +4034:GrShape::convex\28bool\29\20const +4035:GrShaderVar::GrShaderVar\28SkString\2c\20SkSLType\2c\20int\29 +4036:GrResourceProvider::findResourceByUniqueKey\28skgpu::UniqueKey\20const&\29 +4037:GrResourceProvider::createPatternedIndexBuffer\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\2c\20skgpu::UniqueKey\20const*\29 +4038:GrResourceCache::removeUniqueKey\28GrGpuResource*\29 +4039:GrResourceCache::getNextTimestamp\28\29 +4040:GrResourceCache::findAndRefScratchResource\28skgpu::ScratchKey\20const&\29 +4041:GrRenderTask::dependsOn\28GrRenderTask\20const*\29\20const +4042:GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +4043:GrRenderTargetProxy::canUseStencil\28GrCaps\20const&\29\20const +4044:GrRecordingContextPriv::createDevice\28skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\2c\20skgpu::ganesh::Device::InitContents\29 +4045:GrRecordingContextPriv::addOnFlushCallbackObject\28GrOnFlushCallbackObject*\29 +4046:GrRecordingContext::~GrRecordingContext\28\29 +4047:GrQuadUtils::TessellationHelper::reset\28GrQuad\20const&\2c\20GrQuad\20const*\29 +4048:GrQuadUtils::TessellationHelper::getEdgeEquations\28\29 +4049:GrQuadUtils::TessellationHelper::Vertices::moveAlong\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4050:GrQuadUtils::ResolveAAType\28GrAAType\2c\20GrQuadAAFlags\2c\20GrQuad\20const&\2c\20GrAAType*\2c\20GrQuadAAFlags*\29 +4051:GrQuadUtils::CropToRect\28SkRect\20const&\2c\20GrAA\2c\20DrawQuad*\2c\20bool\29 +4052:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::append\28GrQuad\20const&\2c\20\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA&&\2c\20GrQuad\20const*\29 +4053:GrQuad::setQuadType\28GrQuad::Type\29 +4054:GrPorterDuffXPFactory::SimpleSrcOverXP\28\29 +4055:GrPipeline*\20SkArenaAlloc::make\28GrPipeline::InitArgs&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29 +4056:GrPersistentCacheUtils::UnpackCachedShaders\28SkReadBuffer*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20int\2c\20GrPersistentCacheUtils::ShaderMetadata*\29 +4057:GrPathUtils::quadraticPointCount\28SkPoint\20const*\2c\20float\29 +4058:GrPathUtils::convertCubicToQuads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\29 +4059:GrPathTessellationShader::Make\28GrShaderCaps\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::tess::PatchAttribs\29 +4060:GrPathTessellationShader::MakeSimpleTriangleShader\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +4061:GrOvalOpFactory::MakeOvalOp\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\2c\20GrShaderCaps\20const*\29 +4062:GrOpsRenderPass::drawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +4063:GrOpFlushState::draw\28int\2c\20int\29 +4064:GrOp::chainConcat\28std::__2::unique_ptr>\29 +4065:GrNonAtomicRef::unref\28\29\20const +4066:GrModulateAtlasCoverageEffect::GrModulateAtlasCoverageEffect\28GrModulateAtlasCoverageEffect\20const&\29 +4067:GrMipLevel::operator=\28GrMipLevel&&\29 +4068:GrMeshDrawOp::PatternHelper::PatternHelper\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +4069:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29 +4070:GrImageInfo::makeDimensions\28SkISize\29\20const +4071:GrGpuResource::~GrGpuResource\28\29 +4072:GrGpuResource::removeScratchKey\28\29 +4073:GrGpuResource::registerWithCacheWrapped\28GrWrapCacheable\29 +4074:GrGpuResource::getResourceName\28\29\20const +4075:GrGpuResource::dumpMemoryStatisticsPriv\28SkTraceMemoryDump*\2c\20SkString\20const&\2c\20char\20const*\2c\20unsigned\20long\29\20const +4076:GrGpuResource::CreateUniqueID\28\29 +4077:GrGpuBuffer::onGpuMemorySize\28\29\20const +4078:GrGpu::submitToGpu\28\29 +4079:GrGpu::resolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +4080:GrGpu::executeFlushInfo\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20std::__2::optional\2c\20skgpu::MutableTextureState\20const*\29 +4081:GrGeometryProcessor::TextureSampler::TextureSampler\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +4082:GrGeometryProcessor::TextureSampler::TextureSampler\28GrGeometryProcessor::TextureSampler&&\29 +4083:GrGeometryProcessor::ProgramImpl::TransformInfo::TransformInfo\28GrGeometryProcessor::ProgramImpl::TransformInfo\20const&\29 +4084:GrGeometryProcessor::ProgramImpl::AddMatrixKeys\28GrShaderCaps\20const&\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\29 +4085:GrGeometryProcessor::Attribute::size\28\29\20const +4086:GrGLUniformHandler::~GrGLUniformHandler\28\29 +4087:GrGLUniformHandler::getUniformVariable\28GrResourceHandle\29\20const +4088:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_11911 +4089:GrGLTextureRenderTarget::onRelease\28\29 +4090:GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +4091:GrGLTextureRenderTarget::onAbandon\28\29 +4092:GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +4093:GrGLTexture::~GrGLTexture\28\29 +4094:GrGLTexture::onRelease\28\29 +4095:GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +4096:GrGLTexture::TextureTypeFromTarget\28unsigned\20int\29 +4097:GrGLSemaphore::Make\28GrGLGpu*\2c\20bool\29 +4098:GrGLSLVaryingHandler::~GrGLSLVaryingHandler\28\29 +4099:GrGLSLUniformHandler::addInputSampler\28skgpu::Swizzle\20const&\2c\20char\20const*\29 +4100:GrGLSLUniformHandler::UniformInfo::~UniformInfo\28\29 +4101:GrGLSLShaderBuilder::appendTextureLookup\28SkString*\2c\20GrResourceHandle\2c\20char\20const*\29\20const +4102:GrGLSLShaderBuilder::appendColorGamutXform\28char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +4103:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +4104:GrGLSLProgramDataManager::setSkMatrix\28GrResourceHandle\2c\20SkMatrix\20const&\29\20const +4105:GrGLSLProgramBuilder::writeFPFunction\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +4106:GrGLSLProgramBuilder::nameExpression\28SkString*\2c\20char\20const*\29 +4107:GrGLSLProgramBuilder::fragmentProcessorHasCoordsParam\28GrFragmentProcessor\20const*\29\20const +4108:GrGLSLProgramBuilder::emitSampler\28GrBackendFormat\20const&\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\29 +4109:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10169 +4110:GrGLRenderTarget::~GrGLRenderTarget\28\29 +4111:GrGLRenderTarget::onRelease\28\29 +4112:GrGLRenderTarget::onAbandon\28\29 +4113:GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +4114:GrGLProgramDataManager::~GrGLProgramDataManager\28\29 +4115:GrGLProgramBuilder::~GrGLProgramBuilder\28\29 +4116:GrGLProgramBuilder::computeCountsAndStrides\28unsigned\20int\2c\20GrGeometryProcessor\20const&\2c\20bool\29 +4117:GrGLProgramBuilder::addInputVars\28SkSL::ProgramInterface\20const&\29 +4118:GrGLOpsRenderPass::dmsaaLoadStoreBounds\28\29\20const +4119:GrGLOpsRenderPass::bindInstanceBuffer\28GrBuffer\20const*\2c\20int\29 +4120:GrGLGpu::insertSemaphore\28GrSemaphore*\29 +4121:GrGLGpu::flushViewport\28SkIRect\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +4122:GrGLGpu::flushScissor\28GrScissorState\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +4123:GrGLGpu::flushClearColor\28std::__2::array\29 +4124:GrGLGpu::disableStencil\28\29 +4125:GrGLGpu::deleteSync\28__GLsync*\29 +4126:GrGLGpu::createTexture\28SkISize\2c\20GrGLFormat\2c\20unsigned\20int\2c\20skgpu::Renderable\2c\20GrGLTextureParameters::SamplerOverriddenState*\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +4127:GrGLGpu::copySurfaceAsDraw\28GrSurface*\2c\20bool\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +4128:GrGLGpu::HWVertexArrayState::bindInternalVertexArray\28GrGLGpu*\2c\20GrBuffer\20const*\29 +4129:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20char\2c\20int\2c\20void\20const*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20char\2c\20int\2c\20void\20const*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20char\2c\20int\2c\20void\20const*\29 +4130:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +4131:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +4132:GrGLFunction::GrGLFunction\28unsigned\20char\20const*\20\28*\29\28unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29 +4133:GrGLContextInfo::~GrGLContextInfo\28\29 +4134:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrGLFormat\29\20const +4135:GrGLCaps::canCopyAsDraw\28GrGLFormat\2c\20bool\2c\20bool\29\20const +4136:GrGLBuffer::~GrGLBuffer\28\29 +4137:GrGLBuffer::Make\28GrGLGpu*\2c\20unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +4138:GrGLBackendTextureData::GrGLBackendTextureData\28GrGLTextureInfo\20const&\2c\20sk_sp\29 +4139:GrGLAttribArrayState::invalidate\28\29 +4140:GrGLAttribArrayState::enableVertexArrays\28GrGLGpu\20const*\2c\20int\2c\20GrPrimitiveRestart\29 +4141:GrGLAttachment::GrGLAttachment\28GrGpu*\2c\20unsigned\20int\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20GrGLFormat\2c\20std::__2::basic_string_view>\29 +4142:GrFragmentProcessors::make_effect_fp\28sk_sp\2c\20char\20const*\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkSpan\2c\20GrFPArgs\20const&\29 +4143:GrFragmentProcessors::IsSupported\28SkMaskFilter\20const*\29 +4144:GrFragmentProcessor::makeProgramImpl\28\29\20const +4145:GrFragmentProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +4146:GrFragmentProcessor::ProgramImpl::~ProgramImpl\28\29 +4147:GrFragmentProcessor::MulInputByChildAlpha\28std::__2::unique_ptr>\29 +4148:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +4149:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29 +4150:GrEagerDynamicVertexAllocator::lock\28unsigned\20long\2c\20int\29 +4151:GrDynamicAtlas::makeNode\28GrDynamicAtlas::Node*\2c\20int\2c\20int\2c\20int\2c\20int\29 +4152:GrDstProxyView::GrDstProxyView\28GrDstProxyView\20const&\29 +4153:GrDrawingManager::setLastRenderTask\28GrSurfaceProxy\20const*\2c\20GrRenderTask*\29 +4154:GrDrawingManager::insertTaskBeforeLast\28sk_sp\29 +4155:GrDrawingManager::flushSurfaces\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +4156:GrDrawOpAtlas::makeMRU\28skgpu::Plot*\2c\20unsigned\20int\29 +4157:GrDefaultGeoProcFactory::MakeForDeviceSpace\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +4158:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29 +4159:GrColorTypeClampType\28GrColorType\29 +4160:GrColorSpaceXform::Equals\28GrColorSpaceXform\20const*\2c\20GrColorSpaceXform\20const*\29 +4161:GrBufferAllocPool::unmap\28\29 +4162:GrBufferAllocPool::reset\28\29 +4163:GrBlurUtils::extract_draw_rect_from_data\28SkData*\2c\20SkIRect\20const&\29 +4164:GrBlurUtils::can_filter_mask\28SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect*\29 +4165:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29 +4166:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +4167:GrBicubicEffect::GrBicubicEffect\28std::__2::unique_ptr>\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrBicubicEffect::Clamp\29 +4168:GrBackendTextures::MakeGL\28int\2c\20int\2c\20skgpu::Mipmapped\2c\20GrGLTextureInfo\20const&\2c\20sk_sp\2c\20std::__2::basic_string_view>\29 +4169:GrBackendFormatStencilBits\28GrBackendFormat\20const&\29 +4170:GrBackendFormat::operator==\28GrBackendFormat\20const&\29\20const +4171:GrAtlasManager::resolveMaskFormat\28skgpu::MaskFormat\29\20const +4172:GrAATriangulator::~GrAATriangulator\28\29 +4173:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrAATriangulator::EventList*\29\20const +4174:GrAATriangulator::connectSSEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +4175:GrAAConvexTessellator::terminate\28GrAAConvexTessellator::Ring\20const&\29 +4176:GrAAConvexTessellator::computePtAlongBisector\28int\2c\20SkPoint\20const&\2c\20int\2c\20float\2c\20SkPoint*\29\20const +4177:GrAAConvexTessellator::computeNormals\28\29::$_0::operator\28\29\28SkPoint\29\20const +4178:GrAAConvexTessellator::CandidateVerts::originatingIdx\28int\29\20const +4179:GrAAConvexTessellator::CandidateVerts::fuseWithPrior\28int\29 +4180:GrAAConvexTessellator::CandidateVerts::addNewPt\28SkPoint\20const&\2c\20int\2c\20int\2c\20bool\29 +4181:GetVariationDesignPosition\28FT_FaceRec_*\2c\20SkFontArguments::VariationPosition::Coordinate*\2c\20int\29 +4182:GetAxes\28FT_FaceRec_*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\29 +4183:FT_Set_Transform +4184:FT_Set_Char_Size +4185:FT_Select_Metrics +4186:FT_Request_Metrics +4187:FT_List_Remove +4188:FT_List_Finalize +4189:FT_Hypot +4190:FT_GlyphLoader_CreateExtra +4191:FT_GlyphLoader_Adjust_Points +4192:FT_Get_Paint +4193:FT_Get_MM_Var +4194:FT_Get_Color_Glyph_Paint +4195:FT_Done_GlyphSlot +4196:FT_Done_Face +4197:FT_Activate_Size +4198:EllipticalRRectOp::~EllipticalRRectOp\28\29 +4199:EdgeLT::operator\28\29\28Edge\20const&\2c\20Edge\20const&\29\20const +4200:DAffineMatrix::mapPoint\28\28anonymous\20namespace\29::DPoint\20const&\29\20const +4201:DAffineMatrix::mapPoint\28SkPoint\20const&\29\20const +4202:Cr_z_inflate_table +4203:CopyFromCompoundDictionary +4204:Compute_Point_Displacement +4205:CircularRRectOp::~CircularRRectOp\28\29 +4206:CFF::cff_stack_t::push\28\29 +4207:CFF::arg_stack_t::pop_int\28\29 +4208:CFF::CFFIndex>::get_size\28\29\20const +4209:BrotliWarmupBitReader +4210:Bounder::Bounder\28SkRect\20const&\2c\20SkPaint\20const&\29 +4211:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::operator++\28\29 +4212:ActiveEdgeList::DoubleRotation\28ActiveEdge*\2c\20int\29 +4213:AAT::kerxTupleKern\28int\2c\20unsigned\20int\2c\20void\20const*\2c\20AAT::hb_aat_apply_context_t*\29 +4214:AAT::feat::get_feature\28hb_aat_layout_feature_type_t\29\20const +4215:AAT::StateTable::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +4216:AAT::StateTable::get_class\28unsigned\20int\2c\20unsigned\20int\29\20const +4217:AAT::StateTable::get_entry\28int\2c\20unsigned\20int\29\20const +4218:AAT::Lookup::sanitize\28hb_sanitize_context_t*\29\20const +4219:AAT::ClassTable>::get_class\28unsigned\20int\2c\20unsigned\20int\29\20const +4220:4001 +4221:4002 +4222:4003 +4223:4004 +4224:4005 +4225:4006 +4226:4007 +4227:4008 +4228:4009 +4229:4010 +4230:4011 +4231:4012 +4232:4013 +4233:4014 +4234:4015 +4235:4016 +4236:4017 +4237:4018 +4238:4019 +4239:4020 +4240:4021 +4241:4022 +4242:4023 +4243:4024 +4244:4025 +4245:4026 +4246:4027 +4247:4028 +4248:4029 +4249:4030 +4250:4031 +4251:4032 +4252:4033 +4253:4034 +4254:4035 +4255:4036 +4256:4037 +4257:4038 +4258:4039 +4259:4040 +4260:4041 +4261:4042 +4262:4043 +4263:4044 +4264:4045 +4265:4046 +4266:4047 +4267:4048 +4268:4049 +4269:4050 +4270:zeroinfnan +4271:zero_mark_widths_by_gdef\28hb_buffer_t*\2c\20bool\29 +4272:xyzd50_to_lab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +4273:xyz_almost_equal\28skcms_Matrix3x3\20const&\2c\20skcms_Matrix3x3\20const&\29 +4274:write_vertex_position\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrShaderVar\20const&\2c\20SkMatrix\20const&\2c\20char\20const*\2c\20GrShaderVar*\2c\20GrResourceHandle*\29 +4275:write_passthrough_vertex_position\28GrGLSLVertexBuilder*\2c\20GrShaderVar\20const&\2c\20GrShaderVar*\29 +4276:winding_mono_quad\28SkPoint\20const*\2c\20float\2c\20float\2c\20int*\29 +4277:winding_mono_conic\28SkConic\20const&\2c\20float\2c\20float\2c\20int*\29 +4278:wctomb +4279:wchar_t*\20std::__2::copy\5babi:nn180100\5d\2c\20wchar_t*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20wchar_t*\29 +4280:wchar_t*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20std::__2::__element_count\29 +4281:walk_simple_edges\28SkEdge*\2c\20SkBlitter*\2c\20int\2c\20int\29 +4282:vsscanf +4283:void\20std::__2::unique_ptr::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot*\2c\200>\28skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot*\29 +4284:void\20std::__2::unique_ptr\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot*\2c\200>\28skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot*\29 +4285:void\20std::__2::unique_ptr>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot*\2c\200>\28skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot*\29 +4286:void\20std::__2::unique_ptr::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot*\2c\200>\28skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot*\29 +4287:void\20std::__2::allocator::construct\5babi:ne180100\5d&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&>\28sktext::GlyphRun*\2c\20SkFont\20const&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\29 +4288:void\20std::__2::allocator::construct\5babi:ne180100\5d\28skia::textlayout::FontFeature*\2c\20SkString\20const&\2c\20int&\29 +4289:void\20std::__2::allocator::construct\5babi:ne180100\5d\28Contour*\2c\20SkRect&\2c\20int&\2c\20int&\29 +4290:void\20std::__2::__variant_detail::__impl\2c\20std::__2::unique_ptr>>::__assign\5babi:ne180100\5d<0ul\2c\20sk_sp>\28sk_sp&&\29 +4291:void\20std::__2::__variant_detail::__impl::__assign\5babi:ne180100\5d<0ul\2c\20SkPaint>\28SkPaint&&\29 +4292:void\20std::__2::__variant_detail::__assignment>::__assign_alt\5babi:ne180100\5d<0ul\2c\20SkPaint\2c\20SkPaint>\28std::__2::__variant_detail::__alt<0ul\2c\20SkPaint>&\2c\20SkPaint&&\29 +4293:void\20std::__2::__tree_right_rotate\5babi:ne180100\5d*>\28std::__2::__tree_node_base*\29 +4294:void\20std::__2::__tree_left_rotate\5babi:ne180100\5d*>\28std::__2::__tree_node_base*\29 +4295:void\20std::__2::__stable_sort_move\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\29 +4296:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +4297:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +4298:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +4299:void\20std::__2::__sift_up\5babi:ne180100\5d*>>\28std::__2::__wrap_iter*>\2c\20std::__2::__wrap_iter*>\2c\20GrGeometryProcessor::ProgramImpl::emitTransformCode\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\29::$_0&\2c\20std::__2::iterator_traits*>>::difference_type\29 +4300:void\20std::__2::__sift_up\5babi:ne180100\5d>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20GrAATriangulator::EventComparator&\2c\20std::__2::iterator_traits>::difference_type\29 +4301:void\20std::__2::__optional_storage_base::__construct\5babi:ne180100\5d\28skia::textlayout::FontArguments\20const&\29 +4302:void\20std::__2::__optional_storage_base::__assign_from\5babi:ne180100\5d\20const&>\28std::__2::__optional_copy_assign_base\20const&\29 +4303:void\20std::__2::__optional_storage_base::__construct\5babi:ne180100\5d\28SkPath\20const&\29 +4304:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d&\2c\20int&>\2c\20std::__2::tuple\2c\20unsigned\20long>\2c\20sk_sp\2c\20unsigned\20long\2c\200ul\2c\201ul>\28std::__2::tuple&\2c\20int&>&\2c\20std::__2::tuple\2c\20unsigned\20long>&&\2c\20std::__2::__tuple_types\2c\20unsigned\20long>\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +4305:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d&>\2c\20std::__2::tuple>\2c\20GrSurfaceProxyView\2c\20sk_sp\2c\200ul\2c\201ul>\28std::__2::tuple&>&\2c\20std::__2::tuple>&&\2c\20std::__2::__tuple_types>\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +4306:void\20std::__2::__list_imp>::__delete_node\5babi:ne180100\5d<>\28std::__2::__list_node*\29 +4307:void\20std::__2::__introsort\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +4308:void\20std::__2::__introsort\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +4309:void\20std::__2::__introsort\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +4310:void\20std::__2::__forward_list_base\2c\20std::__2::allocator>>::__delete_node\5babi:ne180100\5d<>\28std::__2::__forward_list_node\2c\20void*>*\29 +4311:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20char*&\2c\20char*&\29 +4312:void\20sorted_merge<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +4313:void\20sorted_merge<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +4314:void\20sort_r_simple\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\2c\20void*\29\2c\20void*\29 +4315:void\20sktext::gpu::fillDirectClipped\28SkZip\2c\20unsigned\20int\2c\20SkPoint\2c\20SkIRect*\29 +4316:void\20skgpu::ganesh::SurfaceFillContext::clearAtLeast<\28SkAlphaType\292>\28SkIRect\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +4317:void\20portable::memsetT\28unsigned\20short*\2c\20unsigned\20short\2c\20int\29 +4318:void\20portable::memsetT\28unsigned\20int*\2c\20unsigned\20int\2c\20int\29 +4319:void\20hb_sanitize_context_t::set_object>\28OT::KernSubTable\20const*\29 +4320:void\20hb_sanitize_context_t::set_object>\28AAT::ChainSubtable\20const*\29 +4321:void\20hb_sanitize_context_t::set_object>\28AAT::ChainSubtable\20const*\29 +4322:void\20hair_path<\28SkPaint::Cap\292>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4323:void\20hair_path<\28SkPaint::Cap\291>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4324:void\20hair_path<\28SkPaint::Cap\290>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4325:void\20\28anonymous\20namespace\29::copyFT2LCD16\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\29 +4326:void\20SkTQSort\28double*\2c\20double*\29 +4327:void\20SkTIntroSort\28int\2c\20int*\2c\20int\2c\20DistanceLessThan\20const&\29 +4328:void\20SkTIntroSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29>\28int\2c\20float*\2c\20int\2c\20void\20SkTQSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29\20const&\29 +4329:void\20SkTIntroSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29>\28int\2c\20double*\2c\20int\2c\20void\20SkTQSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29\20const&\29 +4330:void\20SkTIntroSort\28int\2c\20SkString*\2c\20int\2c\20bool\20\20const\28&\29\28SkString\20const&\2c\20SkString\20const&\29\29 +4331:void\20SkTIntroSort\28int\2c\20SkOpRayHit**\2c\20int\2c\20bool\20\20const\28&\29\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29\29 +4332:void\20SkTIntroSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29>\28int\2c\20SkOpContour*\2c\20int\2c\20void\20SkTQSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29\20const&\29 +4333:void\20SkTIntroSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29>\28int\2c\20SkEdge*\2c\20int\2c\20void\20SkTQSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29\20const&\29 +4334:void\20SkTIntroSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29>\28int\2c\20SkClosestRecord\20const*\2c\20int\2c\20void\20SkTQSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29\20const&\29 +4335:void\20SkTIntroSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29>\28int\2c\20SkAnalyticEdge*\2c\20int\2c\20void\20SkTQSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29\20const&\29 +4336:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\20const\28&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +4337:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\28*\20const&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +4338:void\20SkTIntroSort\28int\2c\20Edge*\2c\20int\2c\20EdgeLT\20const&\29 +4339:void\20SkSafeUnref\28GrWindowRectangles::Rec\20const*\29 +4340:void\20SkSafeUnref\28GrSurface::RefCntedReleaseProc*\29 +4341:void\20SkSafeUnref\28GrBufferAllocPool::CpuBufferCache*\29 +4342:void\20SkRecords::FillBounds::trackBounds\28SkRecords::NoOp\20const&\29 +4343:void\20GrGLProgramDataManager::setMatrices<4>\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +4344:void\20GrGLProgramDataManager::setMatrices<3>\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +4345:void\20GrGLProgramDataManager::setMatrices<2>\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +4346:void\20A8_row_aa\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\20\28*\29\28unsigned\20char\2c\20unsigned\20char\29\2c\20bool\29 +4347:virtual\20thunk\20to\20GrGLTexture::onSetLabel\28\29 +4348:virtual\20thunk\20to\20GrGLTexture::backendFormat\28\29\20const +4349:vfiprintf +4350:validate_texel_levels\28SkISize\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20GrCaps\20const*\29 +4351:valid_divs\28int\20const*\2c\20int\2c\20int\2c\20int\29 +4352:utf8_byte_type\28unsigned\20char\29 +4353:use_tiled_rendering\28GrGLCaps\20const&\2c\20GrOpsRenderPass::StencilLoadAndStoreInfo\20const&\29 +4354:uprv_realloc_skia +4355:update_edge\28SkEdge*\2c\20int\29 +4356:unsigned\20short\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4357:unsigned\20short\20sk_saturate_cast\28float\29 +4358:unsigned\20long\20long\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4359:unsigned\20long&\20std::__2::vector>::emplace_back\28unsigned\20long&\29 +4360:unsigned\20int\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4361:unsigned\20int\20const*\20std::__2::lower_bound\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20unsigned\20long\20const&\29 +4362:unsigned\20int*\20hb_vector_t::push\28unsigned\20int&\29 +4363:unsigned\20char\20pack_distance_field_val<4>\28float\29 +4364:ubidi_getVisualRun_skia +4365:ubidi_countRuns_skia +4366:ubidi_close_skia +4367:u_charType_skia +4368:u8_lerp\28unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char\29 +4369:tt_size_select +4370:tt_size_run_prep +4371:tt_size_done_bytecode +4372:tt_sbit_decoder_load_image +4373:tt_prepare_zone +4374:tt_loader_set_pp +4375:tt_loader_init +4376:tt_loader_done +4377:tt_hvadvance_adjust +4378:tt_face_vary_cvt +4379:tt_face_palette_set +4380:tt_face_load_generic_header +4381:tt_face_load_cvt +4382:tt_face_goto_table +4383:tt_face_get_metrics +4384:tt_done_blend +4385:tt_cmap4_set_range +4386:tt_cmap4_next +4387:tt_cmap4_char_map_linear +4388:tt_cmap4_char_map_binary +4389:tt_cmap2_get_subheader +4390:tt_cmap14_get_nondef_chars +4391:tt_cmap14_get_def_chars +4392:tt_cmap14_def_char_count +4393:tt_cmap13_next +4394:tt_cmap13_init +4395:tt_cmap13_char_map_binary +4396:tt_cmap12_next +4397:tt_cmap12_char_map_binary +4398:tt_apply_mvar +4399:top_collinear\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +4400:to_stablekey\28int\2c\20unsigned\20int\29 +4401:throw_on_failure\28unsigned\20long\2c\20void*\29 +4402:thai_pua_shape\28unsigned\20int\2c\20thai_action_t\2c\20hb_font_t*\29 +4403:t1_lookup_glyph_by_stdcharcode_ps +4404:t1_cmap_std_init +4405:t1_cmap_std_char_index +4406:t1_builder_init +4407:t1_builder_close_contour +4408:t1_builder_add_point1 +4409:t1_builder_add_point +4410:t1_builder_add_contour +4411:sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4412:sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4413:surface_setCallbackHandler +4414:surface_getThreadId +4415:strutStyle_setFontSize +4416:strtoull +4417:strtoll_l +4418:strspn +4419:strncpy +4420:strcspn +4421:store_int +4422:std::logic_error::~logic_error\28\29 +4423:std::logic_error::logic_error\28char\20const*\29 +4424:std::exception::exception\5babi:nn180100\5d\28\29 +4425:std::__2::vector>::operator=\5babi:ne180100\5d\28std::__2::vector>\20const&\29 +4426:std::__2::vector>::__vdeallocate\28\29 +4427:std::__2::vector>::__move_assign\28std::__2::vector>&\2c\20std::__2::integral_constant\29 +4428:std::__2::vector>\2c\20std::__2::allocator>>>::__base_destruct_at_end\5babi:ne180100\5d\28std::__2::unique_ptr>*\29 +4429:std::__2::vector\2c\20std::__2::allocator>>::__base_destruct_at_end\5babi:ne180100\5d\28std::__2::tuple*\29 +4430:std::__2::vector>::max_size\28\29\20const +4431:std::__2::vector>::capacity\5babi:nn180100\5d\28\29\20const +4432:std::__2::vector>::__construct_at_end\28unsigned\20long\29 +4433:std::__2::vector>::__clear\5babi:nn180100\5d\28\29 +4434:std::__2::vector\2c\20std::__2::allocator>\2c\20std::__2::allocator\2c\20std::__2::allocator>>>::__clear\5babi:ne180100\5d\28\29 +4435:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4436:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +4437:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4438:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +4439:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4440:std::__2::vector>::operator=\5babi:ne180100\5d\28std::__2::vector>\20const&\29 +4441:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4442:std::__2::vector>::__base_destruct_at_end\5babi:ne180100\5d\28skia::textlayout::FontFeature*\29 +4443:std::__2::vector\2c\20std::__2::allocator>>::vector\28std::__2::vector\2c\20std::__2::allocator>>\20const&\29 +4444:std::__2::vector>::insert\28std::__2::__wrap_iter\2c\20float&&\29 +4445:std::__2::vector>::__construct_at_end\28unsigned\20long\29 +4446:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4447:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4448:std::__2::vector>::vector\5babi:ne180100\5d\28std::initializer_list\29 +4449:std::__2::vector>::reserve\28unsigned\20long\29 +4450:std::__2::vector>::operator=\5babi:ne180100\5d\28std::__2::vector>\20const&\29 +4451:std::__2::vector>::__vdeallocate\28\29 +4452:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4453:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4454:std::__2::vector>::__base_destruct_at_end\5babi:ne180100\5d\28SkString*\29 +4455:std::__2::vector>::push_back\5babi:ne180100\5d\28SkSL::TraceInfo&&\29 +4456:std::__2::vector>::push_back\5babi:ne180100\5d\28SkSL::SymbolTable*\20const&\29 +4457:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +4458:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4459:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\2c\20SkSL::ProgramElement\20const**\29 +4460:std::__2::vector>::__move_range\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\29 +4461:std::__2::vector>::push_back\5babi:ne180100\5d\28SkRuntimeEffect::Uniform&&\29 +4462:std::__2::vector>::push_back\5babi:ne180100\5d\28SkRuntimeEffect::Child&&\29 +4463:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +4464:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4465:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4466:std::__2::vector>::reserve\28unsigned\20long\29 +4467:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4468:std::__2::vector\2c\20std::__2::allocator>>::__swap_out_circular_buffer\28std::__2::__split_buffer\2c\20std::__2::allocator>&>&\29 +4469:std::__2::vector>::push_back\5babi:ne180100\5d\28SkMeshSpecification::Varying&&\29 +4470:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4471:std::__2::vector>::reserve\28unsigned\20long\29 +4472:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4473:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4474:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4475:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4476:std::__2::unique_ptr::unique_ptr\5babi:nn180100\5d\28unsigned\20char*\2c\20std::__2::__dependent_type\2c\20true>::__good_rval_ref_type\29 +4477:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4478:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::gpu::TextBlobRedrawCoordinator*\29 +4479:std::__2::unique_ptr::~unique_ptr\5babi:ne180100\5d\28\29 +4480:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4481:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::gpu::SubRunAllocator*\29 +4482:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4483:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::gpu::StrikeCache*\29 +4484:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4485:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::GlyphRunBuilder*\29 +4486:std::__2::unique_ptr\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4487:std::__2::unique_ptr\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4488:std::__2::unique_ptr\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4489:std::__2::unique_ptr>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4490:std::__2::unique_ptr\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4491:std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4492:std::__2::unique_ptr::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4493:std::__2::unique_ptr>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4494:std::__2::unique_ptr\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4495:std::__2::unique_ptr\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4496:std::__2::unique_ptr::AdaptedTraits>::Slot\20\5b\5d\2c\20std::__2::default_delete::AdaptedTraits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4497:std::__2::unique_ptr::Slot\20\5b\5d\2c\20std::__2::default_delete::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4498:std::__2::unique_ptr\2c\20std::__2::default_delete>>::reset\5babi:ne180100\5d\28skia_private::TArray*\29 +4499:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4500:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4501:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skgpu::ganesh::SmallPathAtlasMgr*\29 +4502:std::__2::unique_ptr\20\5b\5d\2c\20std::__2::default_delete\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4503:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28hb_font_t*\29 +4504:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4505:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28hb_blob_t*\29 +4506:std::__2::unique_ptr::operator=\5babi:nn180100\5d\28std::__2::unique_ptr&&\29 +4507:std::__2::unique_ptr<\28anonymous\20namespace\29::SoftwarePathData\2c\20std::__2::default_delete<\28anonymous\20namespace\29::SoftwarePathData>>::reset\5babi:ne180100\5d\28\28anonymous\20namespace\29::SoftwarePathData*\29 +4508:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4509:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkTaskGroup*\29 +4510:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4511:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4512:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::RP::Program*\29 +4513:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4514:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Program*\29 +4515:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::ProgramUsage*\29 +4516:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4517:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4518:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::MemoryPool*\29 +4519:std::__2::unique_ptr>\20SkSL::coalesce_vector\28std::__2::array\20const&\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +4520:std::__2::unique_ptr>\20SkSL::coalesce_pairwise_vectors\28std::__2::array\20const&\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +4521:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4522:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4523:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkRecorder*\29 +4524:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkLatticeIter*\29 +4525:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkCanvas::Layer*\29 +4526:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4527:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkCanvas::BackImage*\29 +4528:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4529:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkArenaAlloc*\29 +4530:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4531:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrThreadSafeCache*\29 +4532:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4533:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrResourceProvider*\29 +4534:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4535:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrResourceCache*\29 +4536:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4537:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrProxyProvider*\29 +4538:std::__2::unique_ptr>\20GrOp::Make\28GrRecordingContext*\2c\20skgpu::ganesh::AtlasTextOp::MaskType&&\2c\20bool&&\2c\20int&&\2c\20SkRect&\2c\20skgpu::ganesh::AtlasTextOp::Geometry*&\2c\20GrColorInfo\20const&\2c\20GrPaint&&\29 +4539:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4540:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4541:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4542:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4543:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrAuditTrail::OpNode*\29 +4544:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28FT_SizeRec_*\29 +4545:std::__2::tuple::tuple\5babi:nn180100\5d\28std::__2::locale::id::__get\28\29::$_0&&\29 +4546:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda0'\28\29::operator\28\29\28\29\20const +4547:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +4548:std::__2::tuple&\20std::__2::tuple::operator=\5babi:ne180100\5d\28std::__2::pair&&\29 +4549:std::__2::to_string\28unsigned\20long\29 +4550:std::__2::to_chars_result\20std::__2::__to_chars_itoa\5babi:nn180100\5d\28char*\2c\20char*\2c\20unsigned\20int\2c\20std::__2::integral_constant\29 +4551:std::__2::time_put>>::~time_put\28\29_15437 +4552:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4553:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4554:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4555:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4556:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4557:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4558:std::__2::shared_ptr::operator=\5babi:ne180100\5d\28std::__2::shared_ptr&&\29 +4559:std::__2::reverse_iterator::operator++\5babi:nn180100\5d\28\29 +4560:std::__2::priority_queue>\2c\20GrAATriangulator::EventComparator>::push\28GrAATriangulator::Event*\20const&\29 +4561:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t*\29\20const +4562:std::__2::pair::pair\5babi:ne180100\5d\28std::__2::pair&&\29 +4563:std::__2::pair>::~pair\28\29 +4564:std::__2::pair\20std::__2::__unwrap_and_dispatch\5babi:ne180100\5d\2c\20std::__2::__copy_trivial>\2c\20skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\200>\28skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\29 +4565:std::__2::pair\2c\20std::__2::allocator>>>::~pair\28\29 +4566:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +4567:std::__2::pair::pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +4568:std::__2::pair>::~pair\28\29 +4569:std::__2::pair\20std::__2::__unwrap_and_dispatch\5babi:ne180100\5d\2c\20std::__2::__copy_trivial>\2c\20SkString*\2c\20SkString*\2c\20SkString*\2c\200>\28SkString*\2c\20SkString*\2c\20SkString*\29 +4570:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28wchar_t\29 +4571:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28char\29 +4572:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +4573:std::__2::optional&\20std::__2::optional::operator=\5babi:ne180100\5d\28SkPath\20const&\29 +4574:std::__2::optional&\20std::__2::optional::operator=\5babi:ne180100\5d\28SkPaint\20const&\29 +4575:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +4576:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +4577:std::__2::numpunct::~numpunct\28\29 +4578:std::__2::numpunct::~numpunct\28\29 +4579:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +4580:std::__2::num_get>>\20const&\20std::__2::use_facet\5babi:nn180100\5d>>>\28std::__2::locale\20const&\29 +4581:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +4582:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4583:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4584:std::__2::moneypunct::do_negative_sign\28\29\20const +4585:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4586:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4587:std::__2::moneypunct::do_negative_sign\28\29\20const +4588:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20wchar_t*&\2c\20wchar_t*\29 +4589:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20char*&\2c\20char*\29 +4590:std::__2::locale::operator=\28std::__2::locale\20const&\29 +4591:std::__2::locale::facet**\20std::__2::__construct_at\5babi:nn180100\5d\28std::__2::locale::facet**\29 +4592:std::__2::locale::__imp::~__imp\28\29 +4593:std::__2::locale::__imp::release\28\29 +4594:std::__2::list>::pop_front\28\29 +4595:std::__2::iterator_traits\2c\20std::__2::allocator>\20const*>::difference_type\20std::__2::distance\5babi:nn180100\5d\2c\20std::__2::allocator>\20const*>\28std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +4596:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28char*\2c\20char*\29 +4597:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::random_access_iterator_tag\29 +4598:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +4599:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +4600:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +4601:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +4602:std::__2::ios_base::width\5babi:nn180100\5d\28long\29 +4603:std::__2::ios_base::__call_callbacks\28std::__2::ios_base::event\29 +4604:std::__2::hash>::operator\28\29\5babi:ne180100\5d\28std::__2::optional\20const&\29\20const +4605:std::__2::function::operator\28\29\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29\20const +4606:std::__2::function::operator\28\29\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29\20const +4607:std::__2::function::operator\28\29\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29\20const +4608:std::__2::enable_if::type\20skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\294>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\298>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::ReplicateLineEndPoints\2c\20skgpu::tess::TrackJoinControlPoints>::writeDeferredStrokePatch\28\29 +4609:std::__2::enable_if>::value\2c\20SkRuntimeEffectBuilder::BuilderUniform&>::type\20SkRuntimeEffectBuilder::BuilderUniform::operator=>\28std::__2::array\20const&\29 +4610:std::__2::enable_if::value\2c\20SkRuntimeEffectBuilder::BuilderUniform&>::type\20SkRuntimeEffectBuilder::BuilderUniform::operator=\28float\20const&\29 +4611:std::__2::enable_if>::value\20&&\20sizeof\20\28skia::textlayout::SkRange\29\20!=\204\2c\20unsigned\20int>::type\20SkGoodHash::operator\28\29>\28skia::textlayout::SkRange\20const&\29\20const +4612:std::__2::enable_if::value\20&&\20sizeof\20\28bool\29\20!=\204\2c\20unsigned\20int>::type\20SkGoodHash::operator\28\29\28bool\20const&\29\20const +4613:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d\28char&\2c\20char&\29 +4614:std::__2::deque>::back\28\29 +4615:std::__2::deque>::__add_back_capacity\28\29 +4616:std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::_EnableIfConvertible::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot>::type\20std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot>\28skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot*\29\20const +4617:std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot>::type\20std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot>\28skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot*\29\20const +4618:std::__2::default_delete\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot>::type\20std::__2::default_delete\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot>\28skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot*\29\20const +4619:std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot>::type\20std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot>\28skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot*\29\20const +4620:std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot>::type\20std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot>\28skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot*\29\20const +4621:std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::_EnableIfConvertible::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot>::type\20std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot>\28skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot*\29\20const +4622:std::__2::default_delete\20\5b\5d>::_EnableIfConvertible>::type\20std::__2::default_delete\20\5b\5d>::operator\28\29\5babi:ne180100\5d>\28sk_sp*\29\20const +4623:std::__2::default_delete::_EnableIfConvertible::type\20std::__2::default_delete::operator\28\29\5babi:ne180100\5d\28GrGLCaps::ColorTypeInfo*\29\20const +4624:std::__2::ctype::~ctype\28\29 +4625:std::__2::codecvt::~codecvt\28\29 +4626:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +4627:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char32_t\20const*\2c\20char32_t\20const*\2c\20char32_t\20const*&\2c\20char8_t*\2c\20char8_t*\2c\20char8_t*&\29\20const +4628:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20unsigned\20long\29\20const +4629:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20char8_t\20const*&\2c\20char32_t*\2c\20char32_t*\2c\20char32_t*&\29\20const +4630:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*&\2c\20char8_t*\2c\20char8_t*\2c\20char8_t*&\29\20const +4631:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20unsigned\20long\29\20const +4632:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20char8_t\20const*&\2c\20char16_t*\2c\20char16_t*\2c\20char16_t*&\29\20const +4633:std::__2::char_traits::eq_int_type\5babi:nn180100\5d\28int\2c\20int\29 +4634:std::__2::char_traits::not_eof\5babi:nn180100\5d\28int\29 +4635:std::__2::char_traits::find\5babi:ne180100\5d\28char\20const*\2c\20unsigned\20long\2c\20char\20const&\29 +4636:std::__2::basic_stringstream\2c\20std::__2::allocator>::basic_stringstream\5babi:ne180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\29 +4637:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4638:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28\29\20const +4639:std::__2::basic_string_view>::substr\5babi:ne180100\5d\28unsigned\20long\2c\20unsigned\20long\29\20const +4640:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29 +4641:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\29 +4642:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +4643:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20wchar_t\20const*\29 +4644:std::__2::basic_string\2c\20std::__2::allocator>::resize\28unsigned\20long\2c\20char\29 +4645:std::__2::basic_string\2c\20std::__2::allocator>::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +4646:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20char\29 +4647:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:ne180100\5d\28std::__2::__uninitialized_size_tag\2c\20unsigned\20long\2c\20std::__2::allocator\20const&\29 +4648:std::__2::basic_string\2c\20std::__2::allocator>::__null_terminate_at\5babi:nn180100\5d\28char*\2c\20unsigned\20long\29 +4649:std::__2::basic_string\2c\20std::__2::allocator>&\20std::__2::basic_string\2c\20std::__2::allocator>::operator+=>\2c\200>\28std::__2::basic_string_view>\20const&\29 +4650:std::__2::basic_string\2c\20std::__2::allocator>&\20skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::emplace_back\28char\20const*&&\29 +4651:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +4652:std::__2::basic_streambuf>::sputc\5babi:nn180100\5d\28char\29 +4653:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +4654:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +4655:std::__2::basic_streambuf>::basic_streambuf\28\29 +4656:std::__2::basic_ostream>::sentry::~sentry\28\29 +4657:std::__2::basic_ostream>::sentry::sentry\28std::__2::basic_ostream>&\29 +4658:std::__2::basic_ostream>::operator<<\28float\29 +4659:std::__2::basic_ostream>::flush\28\29 +4660:std::__2::basic_istream>::~basic_istream\28\29_14523 +4661:std::__2::basic_iostream>::basic_iostream\5babi:ne180100\5d\28std::__2::basic_streambuf>*\29 +4662:std::__2::basic_ios>::imbue\5babi:ne180100\5d\28std::__2::locale\20const&\29 +4663:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::__sso_allocator&\2c\20std::__2::locale::facet**\2c\20unsigned\20long\29 +4664:std::__2::allocator::allocate\5babi:nn180100\5d\28unsigned\20long\29 +4665:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +4666:std::__2::__wrap_iter\20std::__2::vector>::insert\2c\200>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\29 +4667:std::__2::__unwrap_iter_impl::__rewrap\5babi:nn180100\5d\28char*\2c\20char*\29 +4668:std::__2::__unique_if\2c\20std::__2::allocator>>::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>>\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +4669:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>>\28SkSL::Position&\2c\20std::__2::unique_ptr>&&\2c\20std::__2::unique_ptr>&&\2c\20std::__2::unique_ptr>&&\29 +4670:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28\29 +4671:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28\29 +4672:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +4673:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4674:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4675:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4676:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4677:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4678:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +4679:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4680:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +4681:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>\2c\20true>\2c\20SkSL::Block::Kind&\2c\20std::__2::unique_ptr>>\28SkSL::Position&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&&\2c\20SkSL::Block::Kind&\2c\20std::__2::unique_ptr>&&\29 +4682:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>\28sk_sp&&\29 +4683:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d&>\28std::__2::shared_ptr&\29 +4684:std::__2::__tuple_impl\2c\20std::__2::locale::id::__get\28\29::$_0&&>::__tuple_impl\5babi:nn180100\5d<0ul\2c\20std::__2::locale::id::__get\28\29::$_0&&\2c\20std::__2::locale::id::__get\28\29::$_0>\28std::__2::__tuple_indices<0ul>\2c\20std::__2::__tuple_types\2c\20std::__2::__tuple_indices<...>\2c\20std::__2::__tuple_types<>\2c\20std::__2::locale::id::__get\28\29::$_0&&\29 +4685:std::__2::__time_put::__time_put\5babi:nn180100\5d\28\29 +4686:std::__2::__time_put::__do_put\28char*\2c\20char*&\2c\20tm\20const*\2c\20char\2c\20char\29\20const +4687:std::__2::__throw_length_error\5babi:ne180100\5d\28char\20const*\29 +4688:std::__2::__split_buffer&>::~__split_buffer\28\29 +4689:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +4690:std::__2::__split_buffer>::pop_back\5babi:ne180100\5d\28\29 +4691:std::__2::__split_buffer&>::push_back\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +4692:std::__2::__split_buffer&>::~__split_buffer\28\29 +4693:std::__2::__split_buffer&>::~__split_buffer\28\29 +4694:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +4695:std::__2::__split_buffer&>::~__split_buffer\28\29 +4696:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +4697:std::__2::__split_buffer&>::~__split_buffer\28\29 +4698:std::__2::__shared_weak_count::__release_shared\5babi:ne180100\5d\28\29 +4699:std::__2::__shared_count::__add_shared\5babi:nn180100\5d\28\29 +4700:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +4701:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +4702:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +4703:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +4704:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +4705:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +4706:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +4707:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +4708:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20wchar_t&\2c\20wchar_t&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +4709:std::__2::__money_put::__format\28wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20unsigned\20int\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +4710:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20char&\2c\20char&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +4711:std::__2::__money_put::__format\28char*\2c\20char*&\2c\20char*&\2c\20unsigned\20int\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +4712:std::__2::__libcpp_sscanf_l\28char\20const*\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +4713:std::__2::__libcpp_mbrtowc_l\5babi:nn180100\5d\28wchar_t*\2c\20char\20const*\2c\20unsigned\20long\2c\20__mbstate_t*\2c\20__locale_struct*\29 +4714:std::__2::__libcpp_mb_cur_max_l\5babi:nn180100\5d\28__locale_struct*\29 +4715:std::__2::__libcpp_condvar_wait\5babi:nn180100\5d\28pthread_cond_t*\2c\20pthread_mutex_t*\29 +4716:std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__deallocate_node\28std::__2::__hash_node_base\2c\20void*>*>*\29 +4717:std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__deallocate_node\28std::__2::__hash_node_base\2c\20void*>*>*\29 +4718:std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__deallocate_node\28std::__2::__hash_node_base*>*\29 +4719:std::__2::__function::__value_func\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::operator\28\29\5babi:ne180100\5d\28skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20float&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20SkPoint&&\2c\20SkPoint&&\2c\20skia::textlayout::InternalLineMetrics&&\2c\20bool&&\29\20const +4720:std::__2::__function::__value_func\29>::operator\28\29\5babi:ne180100\5d\28skia::textlayout::Block&&\2c\20skia_private::TArray&&\29\20const +4721:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29 +4722:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +4723:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +4724:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29 +4725:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +4726:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +4727:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +4728:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +4729:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +4730:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::destroy_deallocate\28\29 +4731:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::destroy\28\29 +4732:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +4733:std::__2::__forward_list_base\2c\20std::__2::allocator>>::clear\28\29 +4734:std::__2::__exception_guard_exceptions>::__destroy_vector>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +4735:std::__2::__exception_guard_exceptions>::__destroy_vector>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +4736:std::__2::__exception_guard_exceptions\2c\20SkString*>>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +4737:std::__2::__constexpr_wcslen\5babi:nn180100\5d\28wchar_t\20const*\29 +4738:std::__2::__compressed_pair_elem\29::$_0\2c\200\2c\20false>::__compressed_pair_elem\5babi:ne180100\5d\29::$_0\20const&\2c\200ul>\28std::__2::piecewise_construct_t\2c\20std::__2::tuple\29::$_0\20const&>\2c\20std::__2::__tuple_indices<0ul>\29 +4739:std::__2::__compressed_pair_elem::__compressed_pair_elem\5babi:ne180100\5d\28std::__2::piecewise_construct_t\2c\20std::__2::tuple\2c\20std::__2::__tuple_indices<0ul>\29 +4740:std::__2::__compressed_pair::__compressed_pair\5babi:nn180100\5d\28unsigned\20char*&\2c\20void\20\28*&&\29\28void*\29\29 +4741:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::__sso_allocator&\2c\20unsigned\20long\29 +4742:srgb_to_hsl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +4743:sort_r_swap_blocks\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +4744:sort_increasing_Y\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +4745:sort_edges\28SkEdge**\2c\20int\2c\20SkEdge**\29 +4746:sort_as_rect\28skvx::Vec<4\2c\20float>\20const&\29 +4747:small_blur\28double\2c\20double\2c\20SkMask\20const&\2c\20SkMaskBuilder*\29::$_0::operator\28\29\28SkGaussFilter\20const&\2c\20unsigned\20short*\29\20const +4748:skvx::Vec<8\2c\20unsigned\20short>\20skvx::operator&<8\2c\20unsigned\20short>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +4749:skvx::Vec<8\2c\20unsigned\20int>\20skvx::cast\28skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +4750:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator>><4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20int\29 +4751:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator<<<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20int\29 +4752:skvx::Vec<4\2c\20unsigned\20int>\20skvx::operator>><4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20int\29 +4753:skvx::Vec<4\2c\20unsigned\20int>\20skvx::operator*<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +4754:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator!=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +4755:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator!=<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4756:skvx::Vec<4\2c\20int>\20skvx::operator^<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +4757:skvx::Vec<4\2c\20int>\20skvx::operator>><4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20int\29 +4758:skvx::Vec<4\2c\20int>\20skvx::operator<<<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20int\29 +4759:skvx::Vec<4\2c\20float>\20skvx::sqrt<4>\28skvx::Vec<4\2c\20float>\20const&\29 +4760:skvx::Vec<4\2c\20float>\20skvx::operator/<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +4761:skvx::Vec<4\2c\20float>\20skvx::operator/<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4762:skvx::Vec<4\2c\20float>\20skvx::operator-<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +4763:skvx::Vec<4\2c\20float>\20skvx::operator-<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4764:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20int\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20int\29 +4765:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20int\2c\20void>\28int\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4766:skvx::Vec<4\2c\20float>\20skvx::min<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4767:skvx::Vec<4\2c\20float>\20skvx::min<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.5846\29 +4768:skvx::Vec<4\2c\20float>\20skvx::max<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4769:skvx::Vec<4\2c\20float>\20skvx::from_half<4>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +4770:skvx::Vec<4\2c\20float>&\20skvx::operator*=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.6752\29 +4771:skvx::Vec<2\2c\20unsigned\20char>\20skvx::cast\28skvx::Vec<2\2c\20float>\20const&\29 +4772:skvx::ScaledDividerU32::divide\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +4773:skvx::ScaledDividerU32::ScaledDividerU32\28unsigned\20int\29 +4774:sktext::gpu::can_use_direct\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +4775:sktext::gpu::build_distance_adjust_table\28float\29 +4776:sktext::gpu::VertexFiller::fillVertexData\28int\2c\20int\2c\20SkSpan\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkIRect\2c\20void*\29\20const +4777:sktext::gpu::TextBlobRedrawCoordinator::internalRemove\28sktext::gpu::TextBlob*\29 +4778:sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry::findBlobIndex\28sktext::gpu::TextBlob::Key\20const&\29\20const +4779:sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry::BlobIDCacheEntry\28sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry&&\29 +4780:sktext::gpu::TextBlob::~TextBlob\28\29 +4781:sktext::gpu::SubRunControl::isSDFT\28float\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +4782:sktext::gpu::SubRunContainer::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20SkRefCnt\20const*\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +4783:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_2::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +4784:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_0::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +4785:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29 +4786:sktext::gpu::SubRunContainer::EstimateAllocSize\28sktext::GlyphRunList\20const&\29 +4787:sktext::gpu::SubRunAllocator::SubRunAllocator\28int\29 +4788:sktext::gpu::StrikeCache::internalPurge\28unsigned\20long\29 +4789:sktext::gpu::StrikeCache::freeAll\28\29 +4790:sktext::gpu::SlugImpl::~SlugImpl\28\29 +4791:sktext::SkStrikePromise::resetStrike\28\29 +4792:sktext::GlyphRunList::maxGlyphRunSize\28\29\20const +4793:sktext::GlyphRunBuilder::~GlyphRunBuilder\28\29 +4794:sktext::GlyphRunBuilder::makeGlyphRunList\28sktext::GlyphRun\20const&\2c\20SkPaint\20const&\2c\20SkPoint\29 +4795:sktext::GlyphRunBuilder::blobToGlyphRunList\28SkTextBlob\20const&\2c\20SkPoint\29 +4796:skstd::to_string\28float\29 +4797:skip_string +4798:skip_procedure +4799:skip_comment +4800:skif::compatible_sampling\28SkSamplingOptions\20const&\2c\20bool\2c\20SkSamplingOptions*\2c\20bool\29 +4801:skif::\28anonymous\20namespace\29::decompose_transform\28SkMatrix\20const&\2c\20SkPoint\2c\20SkMatrix*\2c\20SkMatrix*\29 +4802:skif::\28anonymous\20namespace\29::are_axes_nearly_integer_aligned\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29 +4803:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +4804:skif::RoundIn\28SkRect\29 +4805:skif::Mapping::adjustLayerSpace\28SkMatrix\20const&\29 +4806:skif::LayerSpace::inset\28skif::LayerSpace\20const&\29 +4807:skif::LayerSpace::RectToRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace\20const&\29 +4808:skif::FilterResult::imageAndOffset\28skif::Context\20const&\29\20const +4809:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20SkBlender\20const*\29\20const +4810:skif::FilterResult::Builder::drawShader\28sk_sp\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +4811:skif::FilterResult::Builder::createInputShaders\28skif::LayerSpace\20const&\2c\20bool\29 +4812:skif::Context::Context\28sk_sp\2c\20skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult\20const&\2c\20SkColorSpace\20const*\2c\20skif::Stats*\29 +4813:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::uncheckedSet\28std::__2::basic_string_view>&&\29 +4814:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::set\28std::__2::basic_string_view>\29 +4815:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::resize\28int\29 +4816:skia_private::THashTable::uncheckedSet\28sktext::gpu::Glyph*&&\29 +4817:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4818:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4819:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::removeIfExists\28unsigned\20int\20const&\29 +4820:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot::emplace\28skia_private::THashMap::Pair&&\2c\20unsigned\20int\29 +4821:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4822:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::reset\28\29 +4823:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4824:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair&&\29 +4825:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot::reset\28\29 +4826:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair&&\2c\20unsigned\20int\29 +4827:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Hash\28skia::textlayout::OneLineShaper::FontKey\20const&\29 +4828:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair&&\29 +4829:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot::reset\28\29 +4830:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair&&\2c\20unsigned\20int\29 +4831:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Hash\28skia::textlayout::FontCollection::FamilyKey\20const&\29 +4832:skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::uncheckedSet\28skia_private::THashMap>::Pair&&\29 +4833:skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::reset\28\29 +4834:skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Hash\28skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\20const&\29 +4835:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4836:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot::reset\28\29 +4837:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot::emplace\28skia_private::THashMap::Pair&&\2c\20unsigned\20int\29 +4838:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\29 +4839:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4840:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4841:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\29 +4842:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4843:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4844:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Hash\28SkString\20const&\29 +4845:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4846:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4847:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4848:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4849:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4850:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4851:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4852:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::firstPopulatedSlot\28\29\20const +4853:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Iter>::operator++\28\29 +4854:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::THashTable\28skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>\20const&\29 +4855:skia_private::THashTable::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4856:skia_private::THashTable::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4857:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4858:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::set\28skia_private::THashMap::Pair\29 +4859:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4860:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair&&\29 +4861:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4862:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4863:skia_private::THashTable::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4864:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair&&\29 +4865:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot::reset\28\29 +4866:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair&&\2c\20unsigned\20int\29 +4867:skia_private::THashTable::Pair\2c\20SkSL::Analysis::SpecializedCallKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4868:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4869:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot::reset\28\29 +4870:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot::emplace\28skia_private::THashMap::Pair&&\2c\20unsigned\20int\29 +4871:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4872:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::resize\28int\29 +4873:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4874:skia_private::THashTable::Pair\2c\20GrSurfaceProxy*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4875:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28skgpu::ganesh::SmallPathShapeData*&&\29 +4876:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4877:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +4878:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::uncheckedSet\28sk_sp&&\29 +4879:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::resize\28int\29 +4880:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot::emplace\28sk_sp&&\2c\20unsigned\20int\29 +4881:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::uncheckedSet\28sk_sp&&\29 +4882:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::resize\28int\29 +4883:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot::emplace\28sk_sp&&\2c\20unsigned\20int\29 +4884:skia_private::THashTable::Traits>::set\28int\29 +4885:skia_private::THashTable::Traits>::THashTable\28skia_private::THashTable::Traits>&&\29 +4886:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::uncheckedSet\28\28anonymous\20namespace\29::CacheImpl::Value*&&\29 +4887:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::resize\28int\29 +4888:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +4889:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +4890:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::findOrNull\28skgpu::ScratchKey\20const&\29\20const +4891:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +4892:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +4893:skia_private::THashTable::Traits>::uncheckedSet\28SkSL::Variable\20const*&&\29 +4894:skia_private::THashTable::Traits>::resize\28int\29 +4895:skia_private::THashTable::Traits>::uncheckedSet\28SkSL::FunctionDeclaration\20const*&&\29 +4896:skia_private::THashTable::uncheckedSet\28SkResourceCache::Rec*&&\29 +4897:skia_private::THashTable::resize\28int\29 +4898:skia_private::THashTable::find\28SkResourceCache::Key\20const&\29\20const +4899:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::uncheckedSet\28SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*&&\29 +4900:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +4901:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::find\28skia::textlayout::ParagraphCacheKey\20const&\29\20const +4902:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::uncheckedSet\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*&&\29 +4903:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +4904:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::find\28GrProgramDesc\20const&\29\20const +4905:skia_private::THashTable::uncheckedSet\28SkGlyphDigest&&\29 +4906:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrThreadSafeCache::Entry*&&\29 +4907:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4908:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +4909:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrTextureProxy*&&\29 +4910:skia_private::THashTable::AdaptedTraits>::set\28GrTextureProxy*\29 +4911:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4912:skia_private::THashTable::AdaptedTraits>::findOrNull\28skgpu::UniqueKey\20const&\29\20const +4913:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrGpuResource*&&\29 +4914:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4915:skia_private::THashTable::AdaptedTraits>::findOrNull\28skgpu::UniqueKey\20const&\29\20const +4916:skia_private::THashTable::Traits>::uncheckedSet\28FT_Opaque_Paint_&&\29 +4917:skia_private::THashTable::Traits>::resize\28int\29 +4918:skia_private::THashSet::contains\28int\20const&\29\20const +4919:skia_private::THashSet::contains\28FT_Opaque_Paint_\20const&\29\20const +4920:skia_private::THashSet::add\28FT_Opaque_Paint_\29 +4921:skia_private::THashMap::find\28unsigned\20int\20const&\29\20const +4922:skia_private::THashMap\2c\20SkGoodHash>::find\28int\20const&\29\20const +4923:skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::set\28SkSL::Variable\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +4924:skia_private::THashMap::operator\5b\5d\28SkSL::Variable\20const*\20const&\29 +4925:skia_private::THashMap::operator\5b\5d\28SkSL::Symbol\20const*\20const&\29 +4926:skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +4927:skia_private::THashMap::set\28SkSL::FunctionDeclaration\20const*\2c\20int\29 +4928:skia_private::THashMap::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +4929:skia_private::THashMap::operator\5b\5d\28SkSL::Analysis::SpecializedCallKey\20const&\29 +4930:skia_private::THashMap::find\28SkSL::Analysis::SpecializedCallKey\20const&\29\20const +4931:skia_private::THashMap>\2c\20SkGoodHash>::remove\28SkImageFilter\20const*\20const&\29 +4932:skia_private::THashMap>\2c\20SkGoodHash>::Pair::Pair\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4933:skia_private::THashMap::find\28GrSurfaceProxy*\20const&\29\20const +4934:skia_private::TArray::push_back_raw\28int\29 +4935:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4936:skia_private::TArray::push_back\28unsigned\20int\20const&\29 +4937:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +4938:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4939:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +4940:skia_private::TArray::initData\28int\29 +4941:skia_private::TArray::Allocate\28int\2c\20double\29 +4942:skia_private::TArray>\2c\20true>::~TArray\28\29 +4943:skia_private::TArray>\2c\20true>::clear\28\29 +4944:skia_private::TArray>\2c\20true>::operator=\28skia_private::TArray>\2c\20true>&&\29 +4945:skia_private::TArray>\2c\20true>::~TArray\28\29 +4946:skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +4947:skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::checkRealloc\28int\2c\20double\29 +4948:skia_private::TArray\2c\20true>::preallocateNewData\28int\2c\20double\29 +4949:skia_private::TArray\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +4950:skia_private::TArray\2c\20false>::move\28void*\29 +4951:skia_private::TArray\2c\20false>::TArray\28skia_private::TArray\2c\20false>&&\29 +4952:skia_private::TArray\2c\20false>::Allocate\28int\2c\20double\29 +4953:skia_private::TArray::destroyAll\28\29 +4954:skia_private::TArray::destroyAll\28\29 +4955:skia_private::TArray\2c\20false>::~TArray\28\29 +4956:skia_private::TArray::~TArray\28\29 +4957:skia_private::TArray::destroyAll\28\29 +4958:skia_private::TArray::copy\28skia::textlayout::Run\20const*\29 +4959:skia_private::TArray::Allocate\28int\2c\20double\29 +4960:skia_private::TArray::destroyAll\28\29 +4961:skia_private::TArray::initData\28int\29 +4962:skia_private::TArray::destroyAll\28\29 +4963:skia_private::TArray::TArray\28skia_private::TArray&&\29 +4964:skia_private::TArray::Allocate\28int\2c\20double\29 +4965:skia_private::TArray::copy\28skia::textlayout::Cluster\20const*\29 +4966:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4967:skia_private::TArray::Allocate\28int\2c\20double\29 +4968:skia_private::TArray::initData\28int\29 +4969:skia_private::TArray::destroyAll\28\29 +4970:skia_private::TArray::TArray\28skia_private::TArray&&\29 +4971:skia_private::TArray::Allocate\28int\2c\20double\29 +4972:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4973:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4974:skia_private::TArray::push_back\28\29 +4975:skia_private::TArray::push_back\28\29 +4976:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4977:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4978:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4979:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4980:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4981:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4982:skia_private::TArray::destroyAll\28\29 +4983:skia_private::TArray::clear\28\29 +4984:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4985:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4986:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4987:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4988:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4989:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4990:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4991:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4992:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4993:skia_private::TArray::destroyAll\28\29 +4994:skia_private::TArray::clear\28\29 +4995:skia_private::TArray::Allocate\28int\2c\20double\29 +4996:skia_private::TArray::BufferFinishedMessage\2c\20false>::operator=\28skia_private::TArray::BufferFinishedMessage\2c\20false>&&\29 +4997:skia_private::TArray::BufferFinishedMessage\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +4998:skia_private::TArray::BufferFinishedMessage\2c\20false>::destroyAll\28\29 +4999:skia_private::TArray::BufferFinishedMessage\2c\20false>::clear\28\29 +5000:skia_private::TArray::Plane\2c\20false>::preallocateNewData\28int\2c\20double\29 +5001:skia_private::TArray::Plane\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +5002:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +5003:skia_private::TArray\2c\20true>::~TArray\28\29 +5004:skia_private::TArray\2c\20true>::~TArray\28\29 +5005:skia_private::TArray\2c\20true>::preallocateNewData\28int\2c\20double\29 +5006:skia_private::TArray\2c\20true>::clear\28\29 +5007:skia_private::TArray::push_back_raw\28int\29 +5008:skia_private::TArray::push_back\28hb_feature_t&&\29 +5009:skia_private::TArray::resize_back\28int\29 +5010:skia_private::TArray::reset\28int\29 +5011:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +5012:skia_private::TArray::operator=\28skia_private::TArray&&\29 +5013:skia_private::TArray::initData\28int\29 +5014:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5015:skia_private::TArray<\28anonymous\20namespace\29::DrawAtlasOpImpl::Geometry\2c\20true>::checkRealloc\28int\2c\20double\29 +5016:skia_private::TArray<\28anonymous\20namespace\29::DefaultPathOp::PathData\2c\20true>::preallocateNewData\28int\2c\20double\29 +5017:skia_private::TArray<\28anonymous\20namespace\29::AAHairlineOp::PathData\2c\20true>::preallocateNewData\28int\2c\20double\29 +5018:skia_private::TArray<\28anonymous\20namespace\29::AAHairlineOp::PathData\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +5019:skia_private::TArray::push_back_n\28int\2c\20SkUnicode::CodeUnitFlags\20const&\29 +5020:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5021:skia_private::TArray::operator=\28skia_private::TArray&&\29 +5022:skia_private::TArray::destroyAll\28\29 +5023:skia_private::TArray::initData\28int\29 +5024:skia_private::TArray::TArray\28skia_private::TArray\20const&\29 +5025:skia_private::TArray\29::ReorderedArgument\2c\20false>::push_back\28SkSL::optimize_constructor_swizzle\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ConstructorCompound\20const&\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29::ReorderedArgument&&\29 +5026:skia_private::TArray::reserve_exact\28int\29 +5027:skia_private::TArray::fromBack\28int\29 +5028:skia_private::TArray::TArray\28skia_private::TArray&&\29 +5029:skia_private::TArray::Allocate\28int\2c\20double\29 +5030:skia_private::TArray::push_back\28SkSL::Field&&\29 +5031:skia_private::TArray::initData\28int\29 +5032:skia_private::TArray::Allocate\28int\2c\20double\29 +5033:skia_private::TArray::~TArray\28\29 +5034:skia_private::TArray::destroyAll\28\29 +5035:skia_private::TArray\2c\20true>::push_back\28SkRGBA4f<\28SkAlphaType\292>&&\29 +5036:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +5037:skia_private::TArray\2c\20true>::checkRealloc\28int\2c\20double\29 +5038:skia_private::TArray::push_back\28SkPoint\20const&\29 +5039:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +5040:skia_private::TArray::copy\28SkPoint\20const*\29 +5041:skia_private::TArray::~TArray\28\29 +5042:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5043:skia_private::TArray::destroyAll\28\29 +5044:skia_private::TArray::~TArray\28\29 +5045:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5046:skia_private::TArray::destroyAll\28\29 +5047:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5048:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5049:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5050:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5051:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5052:skia_private::TArray::push_back\28\29 +5053:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5054:skia_private::TArray::push_back\28\29 +5055:skia_private::TArray::push_back_raw\28int\29 +5056:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5057:skia_private::TArray::~TArray\28\29 +5058:skia_private::TArray::operator=\28skia_private::TArray&&\29 +5059:skia_private::TArray::destroyAll\28\29 +5060:skia_private::TArray::clear\28\29 +5061:skia_private::TArray::Allocate\28int\2c\20double\29 +5062:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5063:skia_private::TArray::push_back\28\29 +5064:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5065:skia_private::TArray::pop_back\28\29 +5066:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5067:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5068:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5069:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5070:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5071:skia_private::STArray<8\2c\20int\2c\20true>::STArray\28int\29 +5072:skia_private::AutoTMalloc::realloc\28unsigned\20long\29 +5073:skia_private::AutoTMalloc::reset\28unsigned\20long\29 +5074:skia_private::AutoTArray::AutoTArray\28unsigned\20long\29 +5075:skia_private::AutoTArray::AutoTArray\28unsigned\20long\29 +5076:skia_private::AutoTArray::AutoTArray\28unsigned\20long\29 +5077:skia_private::AutoSTMalloc<256ul\2c\20unsigned\20short\2c\20void>::AutoSTMalloc\28unsigned\20long\29 +5078:skia_private::AutoSTArray<6\2c\20SkResourceCache::Key>::~AutoSTArray\28\29 +5079:skia_private::AutoSTArray<64\2c\20TriangulationVertex>::reset\28int\29 +5080:skia_private::AutoSTArray<64\2c\20SkGlyph\20const*>::reset\28int\29 +5081:skia_private::AutoSTArray<4\2c\20unsigned\20char>::reset\28int\29 +5082:skia_private::AutoSTArray<4\2c\20GrResourceHandle>::reset\28int\29 +5083:skia_private::AutoSTArray<3\2c\20std::__2::unique_ptr>>::reset\28int\29 +5084:skia_private::AutoSTArray<32\2c\20unsigned\20short>::~AutoSTArray\28\29 +5085:skia_private::AutoSTArray<32\2c\20unsigned\20short>::reset\28int\29 +5086:skia_private::AutoSTArray<32\2c\20SkRect>::reset\28int\29 +5087:skia_private::AutoSTArray<2\2c\20sk_sp>::reset\28int\29 +5088:skia_private::AutoSTArray<16\2c\20SkRect>::~AutoSTArray\28\29 +5089:skia_private::AutoSTArray<16\2c\20GrMipLevel>::reset\28int\29 +5090:skia_private::AutoSTArray<15\2c\20GrMipLevel>::reset\28int\29 +5091:skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>::~AutoSTArray\28\29 +5092:skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>::reset\28int\29 +5093:skia_private::AutoSTArray<14\2c\20GrMipLevel>::~AutoSTArray\28\29 +5094:skia_private::AutoSTArray<14\2c\20GrMipLevel>::reset\28int\29 +5095:skia_png_set_longjmp_fn +5096:skia_png_read_finish_IDAT +5097:skia_png_read_chunk_header +5098:skia_png_read_IDAT_data +5099:skia_png_gamma_16bit_correct +5100:skia_png_do_strip_channel +5101:skia_png_do_gray_to_rgb +5102:skia_png_do_expand +5103:skia_png_destroy_gamma_table +5104:skia_png_colorspace_set_sRGB +5105:skia_png_check_IHDR +5106:skia_png_calculate_crc +5107:skia::textlayout::operator==\28skia::textlayout::FontArguments\20const&\2c\20skia::textlayout::FontArguments\20const&\29 +5108:skia::textlayout::\28anonymous\20namespace\29::littleRound\28float\29 +5109:skia::textlayout::\28anonymous\20namespace\29::LineBreakerWithLittleRounding::breakLine\28float\29\20const +5110:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29 +5111:skia::textlayout::TypefaceFontStyleSet::matchStyle\28SkFontStyle\20const&\29 +5112:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29 +5113:skia::textlayout::TypefaceFontProvider::registerTypeface\28sk_sp\2c\20SkString\20const&\29 +5114:skia::textlayout::TextWrapper::TextStretch::TextStretch\28skia::textlayout::Cluster*\2c\20skia::textlayout::Cluster*\2c\20bool\29 +5115:skia::textlayout::TextStyle::matchOneAttribute\28skia::textlayout::StyleType\2c\20skia::textlayout::TextStyle\20const&\29\20const +5116:skia::textlayout::TextStyle::equals\28skia::textlayout::TextStyle\20const&\29\20const +5117:skia::textlayout::TextShadow::operator!=\28skia::textlayout::TextShadow\20const&\29\20const +5118:skia::textlayout::TextLine::~TextLine\28\29 +5119:skia::textlayout::TextLine::spacesWidth\28\29\20const +5120:skia::textlayout::TextLine::shiftCluster\28skia::textlayout::Cluster\20const*\2c\20float\2c\20float\29 +5121:skia::textlayout::TextLine::iterateThroughClustersInGlyphsOrder\28bool\2c\20bool\2c\20std::__2::function\20const&\29\20const::$_0::operator\28\29\28unsigned\20long\20const&\29\20const::'lambda'\28skia::textlayout::Cluster&\29::operator\28\29\28skia::textlayout::Cluster&\29\20const +5122:skia::textlayout::TextLine::iterateThroughClustersInGlyphsOrder\28bool\2c\20bool\2c\20std::__2::function\20const&\29\20const +5123:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkRect\29::operator\28\29\28SkRect\29\20const +5124:skia::textlayout::TextLine::getMetrics\28\29\20const +5125:skia::textlayout::TextLine::extendHeight\28skia::textlayout::TextLine::ClipContext\20const&\29\20const +5126:skia::textlayout::TextLine::ensureTextBlobCachePopulated\28\29 +5127:skia::textlayout::TextLine::endsWithHardLineBreak\28\29\20const +5128:skia::textlayout::TextLine::buildTextBlob\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +5129:skia::textlayout::TextLine::TextLine\28skia::textlayout::ParagraphImpl*\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20skia::textlayout::InternalLineMetrics\29 +5130:skia::textlayout::TextLine::TextBlobRecord::~TextBlobRecord\28\29 +5131:skia::textlayout::TextLine::TextBlobRecord::TextBlobRecord\28\29 +5132:skia::textlayout::TextLine&\20skia_private::TArray::emplace_back&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&>\28skia::textlayout::ParagraphImpl*&&\2c\20SkPoint&\2c\20SkPoint&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&\29 +5133:skia::textlayout::StrutStyle::StrutStyle\28\29 +5134:skia::textlayout::Run::shift\28skia::textlayout::Cluster\20const*\2c\20float\29 +5135:skia::textlayout::Run::newRunBuffer\28\29 +5136:skia::textlayout::Run::clusterIndex\28unsigned\20long\29\20const +5137:skia::textlayout::Run::calculateMetrics\28\29 +5138:skia::textlayout::ParagraphStyle::ellipsized\28\29\20const +5139:skia::textlayout::ParagraphPainter::DecorationStyle::DecorationStyle\28unsigned\20int\2c\20float\2c\20std::__2::optional\29 +5140:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29 +5141:skia::textlayout::ParagraphImpl::resolveStrut\28\29 +5142:skia::textlayout::ParagraphImpl::paint\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\29 +5143:skia::textlayout::ParagraphImpl::getGlyphInfoAtUTF16Offset\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +5144:skia::textlayout::ParagraphImpl::getGlyphClusterAt\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +5145:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda0'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +5146:skia::textlayout::ParagraphImpl::computeEmptyMetrics\28\29 +5147:skia::textlayout::ParagraphImpl::buildClusterTable\28\29::$_0::operator\28\29\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\29\20const +5148:skia::textlayout::ParagraphCacheKey::ParagraphCacheKey\28skia::textlayout::ParagraphImpl\20const*\29 +5149:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29 +5150:skia::textlayout::ParagraphBuilderImpl::finalize\28\29 +5151:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda0'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +5152:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\2c\20bool\29 +5153:skia::textlayout::Paragraph::~Paragraph\28\29 +5154:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29 +5155:skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29::$_0::operator\28\29\28unsigned\20long\2c\20skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29::Dir\29\20const +5156:skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29 +5157:skia::textlayout::OneLineShaper::FontKey::operator==\28skia::textlayout::OneLineShaper::FontKey\20const&\29\20const +5158:skia::textlayout::InternalLineMetrics::add\28skia::textlayout::InternalLineMetrics\29 +5159:skia::textlayout::FontFeature::operator==\28skia::textlayout::FontFeature\20const&\29\20const +5160:skia::textlayout::FontFeature::FontFeature\28skia::textlayout::FontFeature\20const&\29 +5161:skia::textlayout::FontCollection::~FontCollection\28\29 +5162:skia::textlayout::FontCollection::matchTypeface\28SkString\20const&\2c\20SkFontStyle\29 +5163:skia::textlayout::FontCollection::defaultFallback\28int\2c\20SkFontStyle\2c\20SkString\20const&\29 +5164:skia::textlayout::FontCollection::FamilyKey::operator==\28skia::textlayout::FontCollection::FamilyKey\20const&\29\20const +5165:skia::textlayout::FontCollection::FamilyKey::FamilyKey\28skia::textlayout::FontCollection::FamilyKey&&\29 +5166:skia::textlayout::FontArguments::~FontArguments\28\29 +5167:skia::textlayout::Decoration::operator==\28skia::textlayout::Decoration\20const&\29\20const +5168:skia::textlayout::Cluster::trimmedWidth\28unsigned\20long\29\20const +5169:skgpu::tess::\28anonymous\20namespace\29::write_curve_index_buffer_base_index\28skgpu::VertexWriter\2c\20unsigned\20long\2c\20unsigned\20short\29 +5170:skgpu::tess::StrokeParams::set\28SkStrokeRec\20const&\29 +5171:skgpu::tess::StrokeIterator::finishOpenContour\28\29 +5172:skgpu::tess::PreChopPathCurves\28float\2c\20SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +5173:skgpu::tess::LinearTolerances::setStroke\28skgpu::tess::StrokeParams\20const&\2c\20float\29 +5174:skgpu::tess::LinearTolerances::requiredResolveLevel\28\29\20const +5175:skgpu::tess::GetJoinType\28SkStrokeRec\20const&\29 +5176:skgpu::tess::FixedCountCurves::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +5177:skgpu::tess::CullTest::areVisible3\28SkPoint\20const*\29\20const +5178:skgpu::tess::ConicHasCusp\28SkPoint\20const*\29 +5179:skgpu::make_unnormalized_half_kernel\28float*\2c\20int\2c\20float\29 +5180:skgpu::ganesh::\28anonymous\20namespace\29::add_line_to_segment\28SkPoint\20const&\2c\20skia_private::TArray*\29 +5181:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29 +5182:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::flush\28GrMeshDrawTarget*\2c\20skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::FlushInfo*\29\20const +5183:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::addToAtlasWithRetry\28GrMeshDrawTarget*\2c\20skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::FlushInfo*\2c\20skgpu::ganesh::SmallPathAtlasMgr*\2c\20int\2c\20int\2c\20void\20const*\2c\20SkRect\20const&\2c\20int\2c\20skgpu::ganesh::SmallPathShapeData*\29\20const +5184:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::SmallPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20GrUserStencilSettings\20const*\29 +5185:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29 +5186:skgpu::ganesh::\28anonymous\20namespace\29::ChopPathIfNecessary\28SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkStrokeRec\20const&\2c\20SkPath*\29 +5187:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29 +5188:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::recordDraw\28GrMeshDrawTarget*\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20int\2c\20unsigned\20short*\29 +5189:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::PathData::PathData\28skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::PathData&&\29 +5190:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::AAFlatteningConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20float\2c\20SkStrokeRec::Style\2c\20SkPaint::Join\2c\20float\2c\20GrUserStencilSettings\20const*\29 +5191:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29 +5192:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::PathData::PathData\28skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::PathData&&\29 +5193:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::AAConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrUserStencilSettings\20const*\29 +5194:skgpu::ganesh::TextureOp::Make\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20SkBlendMode\2c\20GrAAType\2c\20DrawQuad*\2c\20SkRect\20const*\29 +5195:skgpu::ganesh::TessellationPathRenderer::IsSupported\28GrCaps\20const&\29 +5196:skgpu::ganesh::SurfaceFillContext::fillRectToRectWithFP\28SkRect\20const&\2c\20SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +5197:skgpu::ganesh::SurfaceFillContext::blitTexture\28GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\29 +5198:skgpu::ganesh::SurfaceFillContext::arenas\28\29 +5199:skgpu::ganesh::SurfaceFillContext::addDrawOp\28std::__2::unique_ptr>\29 +5200:skgpu::ganesh::SurfaceFillContext::SurfaceFillContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +5201:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29_9625 +5202:skgpu::ganesh::SurfaceDrawContext::setNeedsStencil\28\29 +5203:skgpu::ganesh::SurfaceDrawContext::internalStencilClear\28SkIRect\20const*\2c\20bool\29 +5204:skgpu::ganesh::SurfaceDrawContext::fillRectWithEdgeAA\28GrClip\20const*\2c\20GrPaint&&\2c\20GrQuadAAFlags\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const*\29 +5205:skgpu::ganesh::SurfaceDrawContext::drawVertices\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20sk_sp\2c\20GrPrimitiveType*\2c\20bool\29 +5206:skgpu::ganesh::SurfaceDrawContext::drawTexturedQuad\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkBlendMode\2c\20DrawQuad*\2c\20SkRect\20const*\29 +5207:skgpu::ganesh::SurfaceDrawContext::drawTexture\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkBlendMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +5208:skgpu::ganesh::SurfaceDrawContext::drawStrokedLine\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPoint\20const*\2c\20SkStrokeRec\20const&\29 +5209:skgpu::ganesh::SurfaceDrawContext::drawRegion\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrStyle\20const&\2c\20GrUserStencilSettings\20const*\29 +5210:skgpu::ganesh::SurfaceDrawContext::drawOval\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\29 +5211:skgpu::ganesh::SurfaceDrawContext::attemptQuadOptimization\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20DrawQuad*\2c\20GrPaint*\29::$_0::operator\28\29\28\29\20const +5212:skgpu::ganesh::SurfaceDrawContext::SurfaceDrawContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +5213:skgpu::ganesh::SurfaceContext::writePixels\28GrDirectContext*\2c\20GrCPixmap\2c\20SkIPoint\29 +5214:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29 +5215:skgpu::ganesh::SurfaceContext::copy\28sk_sp\2c\20SkIRect\2c\20SkIPoint\29 +5216:skgpu::ganesh::SurfaceContext::copyScaled\28sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20SkFilterMode\29 +5217:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +5218:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::FinishContext::~FinishContext\28\29 +5219:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +5220:skgpu::ganesh::StrokeTessellator::draw\28GrOpFlushState*\29\20const +5221:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29 +5222:skgpu::ganesh::StrokeTessellateOp::prePrepareTessellator\28GrTessellationShader::ProgramArgs&&\2c\20GrAppliedClip&&\29 +5223:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::allowed_stroke\28GrCaps\20const*\2c\20SkStrokeRec\20const&\2c\20GrAA\2c\20bool*\29 +5224:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29 +5225:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::NonAAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrSimpleMeshDrawOpHelper::InputFlags\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\2c\20GrAAType\29 +5226:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29 +5227:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::ClassID\28\29 +5228:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::AAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::RectInfo\20const&\2c\20bool\29 +5229:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::AAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const&\29 +5230:skgpu::ganesh::SoftwarePathRenderer::DrawAroundInvPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29 +5231:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11142 +5232:skgpu::ganesh::SmallPathAtlasMgr::reset\28\29 +5233:skgpu::ganesh::SmallPathAtlasMgr::findOrCreate\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +5234:skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +5235:skgpu::ganesh::SmallPathAtlasMgr::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +5236:skgpu::ganesh::ShadowRRectOp::Make\28GrRecordingContext*\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20float\2c\20float\29 +5237:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29 +5238:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::RegionOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +5239:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::primitiveType\28\29\20const +5240:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::VertexSpec\28GrQuad::Type\2c\20skgpu::ganesh::QuadPerEdgeAA::ColorType\2c\20GrQuad::Type\2c\20bool\2c\20skgpu::ganesh::QuadPerEdgeAA::Subset\2c\20GrAAType\2c\20bool\2c\20skgpu::ganesh::QuadPerEdgeAA::IndexBufferOption\29 +5241:skgpu::ganesh::QuadPerEdgeAA::Tessellator::append\28GrQuad*\2c\20GrQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\29 +5242:skgpu::ganesh::QuadPerEdgeAA::Tessellator::Tessellator\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29 +5243:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29 +5244:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::initializeAttrs\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29 +5245:skgpu::ganesh::QuadPerEdgeAA::IssueDraw\28GrCaps\20const&\2c\20GrOpsRenderPass*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +5246:skgpu::ganesh::QuadPerEdgeAA::GetIndexBuffer\28GrMeshDrawTarget*\2c\20skgpu::ganesh::QuadPerEdgeAA::IndexBufferOption\29 +5247:skgpu::ganesh::PathWedgeTessellator::Make\28SkArenaAlloc*\2c\20bool\2c\20skgpu::tess::PatchAttribs\29 +5248:skgpu::ganesh::PathTessellator::PathTessellator\28bool\2c\20skgpu::tess::PatchAttribs\29 +5249:skgpu::ganesh::PathTessellator::PathDrawList*\20SkArenaAlloc::make\20const&>\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +5250:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29 +5251:skgpu::ganesh::PathTessellateOp::usesMSAA\28\29\20const +5252:skgpu::ganesh::PathTessellateOp::prepareTessellator\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +5253:skgpu::ganesh::PathTessellateOp::PathTessellateOp\28SkArenaAlloc*\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\2c\20SkRect\20const&\29 +5254:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29 +5255:skgpu::ganesh::PathStencilCoverOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +5256:skgpu::ganesh::PathStencilCoverOp::ClassID\28\29 +5257:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29 +5258:skgpu::ganesh::PathInnerTriangulateOp::pushFanStencilProgram\28GrTessellationShader::ProgramArgs\20const&\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +5259:skgpu::ganesh::PathInnerTriangulateOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +5260:skgpu::ganesh::PathCurveTessellator::~PathCurveTessellator\28\29 +5261:skgpu::ganesh::PathCurveTessellator::prepareWithTriangles\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20GrTriangulator::BreadcrumbTriangleList*\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +5262:skgpu::ganesh::PathCurveTessellator::Make\28SkArenaAlloc*\2c\20bool\2c\20skgpu::tess::PatchAttribs\29 +5263:skgpu::ganesh::OpsTask::setColorLoadOp\28GrLoadOp\2c\20std::__2::array\29 +5264:skgpu::ganesh::OpsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +5265:skgpu::ganesh::OpsTask::onExecute\28GrOpFlushState*\29 +5266:skgpu::ganesh::OpsTask::addSampledTexture\28GrSurfaceProxy*\29 +5267:skgpu::ganesh::OpsTask::addDrawOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0::operator\28\29\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\20const +5268:skgpu::ganesh::OpsTask::addDrawOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +5269:skgpu::ganesh::OpsTask::OpsTask\28GrDrawingManager*\2c\20GrSurfaceProxyView\2c\20GrAuditTrail*\2c\20sk_sp\29 +5270:skgpu::ganesh::OpsTask::OpChain::tryConcat\28skgpu::ganesh::OpsTask::OpChain::List*\2c\20GrProcessorSet::Analysis\2c\20GrDstProxyView\20const&\2c\20GrAppliedClip\20const*\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrAuditTrail*\29 +5271:skgpu::ganesh::OpsTask::OpChain::OpChain\28std::__2::unique_ptr>\2c\20GrProcessorSet::Analysis\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const*\29 +5272:skgpu::ganesh::MakeFragmentProcessorFromView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +5273:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29 +5274:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29 +5275:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::NonAALatticeOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20std::__2::unique_ptr>\2c\20SkRect\20const&\29 +5276:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29 +5277:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::can_use_hw_derivatives_with_coverage\28skvx::Vec<2\2c\20float>\20const&\2c\20SkPoint\20const&\29 +5278:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29 +5279:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20GrAA\29 +5280:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::FillRRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29 +5281:skgpu::ganesh::DrawableOp::~DrawableOp\28\29 +5282:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29 +5283:skgpu::ganesh::DrawAtlasPathOp::prepareProgram\28GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +5284:skgpu::ganesh::Device::~Device\28\29 +5285:skgpu::ganesh::Device::replaceBackingProxy\28SkSurface::ContentChangeMode\2c\20sk_sp\2c\20GrColorType\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +5286:skgpu::ganesh::Device::makeSpecial\28SkBitmap\20const&\29 +5287:skgpu::ganesh::Device::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +5288:skgpu::ganesh::Device::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +5289:skgpu::ganesh::Device::drawEdgeAAImage\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20SkTileMode\29 +5290:skgpu::ganesh::Device::convertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +5291:skgpu::ganesh::Device::android_utils_clipAsRgn\28SkRegion*\29\20const +5292:skgpu::ganesh::DefaultPathRenderer::internalDrawPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20bool\29 +5293:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +5294:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29 +5295:skgpu::ganesh::CopyView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\2c\20std::__2::basic_string_view>\29 +5296:skgpu::ganesh::ClipStack::clipPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrAA\2c\20SkClipOp\29 +5297:skgpu::ganesh::ClipStack::begin\28\29\20const +5298:skgpu::ganesh::ClipStack::SaveRecord::removeElements\28SkTBlockList*\29 +5299:skgpu::ganesh::ClipStack::RawElement::clipType\28\29\20const +5300:skgpu::ganesh::ClipStack::Mask::invalidate\28GrProxyProvider*\29 +5301:skgpu::ganesh::ClipStack::ElementIter::operator++\28\29 +5302:skgpu::ganesh::ClipStack::Element::Element\28skgpu::ganesh::ClipStack::Element\20const&\29 +5303:skgpu::ganesh::ClipStack::Draw::Draw\28SkRect\20const&\2c\20GrAA\29 +5304:skgpu::ganesh::ClearOp::ClearOp\28skgpu::ganesh::ClearOp::Buffer\2c\20GrScissorState\20const&\2c\20std::__2::array\2c\20bool\29 +5305:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29 +5306:skgpu::ganesh::AtlasTextOp::operator\20new\28unsigned\20long\29 +5307:skgpu::ganesh::AtlasTextOp::onPrepareDraws\28GrMeshDrawTarget*\29::$_0::operator\28\29\28\29\20const +5308:skgpu::ganesh::AtlasTextOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +5309:skgpu::ganesh::AtlasTextOp::ClassID\28\29 +5310:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29 +5311:skgpu::ganesh::AtlasRenderTask::stencilAtlasRect\28GrRecordingContext*\2c\20SkRect\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrUserStencilSettings\20const*\29 +5312:skgpu::ganesh::AtlasRenderTask::readView\28GrCaps\20const&\29\20const +5313:skgpu::ganesh::AtlasRenderTask::instantiate\28GrOnFlushResourceProvider*\2c\20sk_sp\29 +5314:skgpu::ganesh::AtlasRenderTask::addPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIPoint\2c\20int\2c\20int\2c\20bool\2c\20SkIPoint16*\29 +5315:skgpu::ganesh::AtlasRenderTask::addAtlasDrawOp\28std::__2::unique_ptr>\2c\20GrCaps\20const&\29 +5316:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10438 +5317:skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +5318:skgpu::ganesh::AtlasPathRenderer::pathFitsInAtlas\28SkRect\20const&\2c\20GrAAType\29\20const +5319:skgpu::ganesh::AtlasPathRenderer::addPathToAtlas\28GrRecordingContext*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRect\20const&\2c\20SkIRect*\2c\20SkIPoint16*\2c\20bool*\2c\20std::__2::function\20const&\29 +5320:skgpu::ganesh::AtlasPathRenderer::AtlasPathKey::operator==\28skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\20const&\29\20const +5321:skgpu::ganesh::AsFragmentProcessor\28GrRecordingContext*\2c\20SkImage\20const*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +5322:skgpu::TiledTextureUtils::OptimizeSampleArea\28SkISize\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkRect*\2c\20SkRect*\2c\20SkMatrix*\29 +5323:skgpu::TiledTextureUtils::CanDisableMipmap\28SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\29 +5324:skgpu::TClientMappedBufferManager::process\28\29 +5325:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29 +5326:skgpu::TAsyncReadResult::count\28\29\20const +5327:skgpu::TAsyncReadResult::Plane::~Plane\28\29 +5328:skgpu::Swizzle::BGRA\28\29 +5329:skgpu::ScratchKey::ScratchKey\28skgpu::ScratchKey\20const&\29 +5330:skgpu::ResourceKey::operator=\28skgpu::ResourceKey\20const&\29 +5331:skgpu::RectanizerSkyline::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +5332:skgpu::RectanizerSkyline::RectanizerSkyline\28int\2c\20int\29 +5333:skgpu::Plot::~Plot\28\29 +5334:skgpu::Plot::resetRects\28\29 +5335:skgpu::Plot::Plot\28int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20SkColorType\2c\20unsigned\20long\29 +5336:skgpu::KeyBuilder::flush\28\29 +5337:skgpu::KeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +5338:skgpu::GetReducedBlendModeInfo\28SkBlendMode\29 +5339:skgpu::GetApproxSize\28SkISize\29::$_0::operator\28\29\28int\29\20const +5340:skgpu::CreateIntegralTable\28int\29 +5341:skgpu::ComputeIntegralTableWidth\28float\29 +5342:skgpu::AtlasLocator::updatePlotLocator\28skgpu::PlotLocator\29 +5343:skgpu::AtlasLocator::insetSrc\28int\29 +5344:skcms_Matrix3x3_invert +5345:sk_sp::~sk_sp\28\29 +5346:sk_sp::reset\28sktext::gpu::TextStrike*\29 +5347:sk_sp\20skgpu::RefCntedCallback::MakeImpl\28void\20\28*\29\28void*\29\2c\20void*\29 +5348:sk_sp<\28anonymous\20namespace\29::UniqueKeyInvalidator>\20sk_make_sp<\28anonymous\20namespace\29::UniqueKeyInvalidator\2c\20skgpu::UniqueKey&\2c\20unsigned\20int>\28skgpu::UniqueKey&\2c\20unsigned\20int&&\29 +5349:sk_sp<\28anonymous\20namespace\29::ShadowInvalidator>\20sk_make_sp<\28anonymous\20namespace\29::ShadowInvalidator\2c\20SkResourceCache::Key&>\28SkResourceCache::Key&\29 +5350:sk_sp::operator=\28sk_sp\20const&\29 +5351:sk_sp&\20std::__2::vector\2c\20std::__2::allocator>>::emplace_back>\28sk_sp&&\29 +5352:sk_sp\20sk_make_sp>\28sk_sp&&\29 +5353:sk_sp::~sk_sp\28\29 +5354:sk_sp::sk_sp\28sk_sp\20const&\29 +5355:sk_sp::operator=\28sk_sp&&\29 +5356:sk_sp::reset\28SkMeshSpecification*\29 +5357:sk_sp::reset\28SkData\20const*\29 +5358:sk_sp::operator=\28sk_sp\20const&\29 +5359:sk_sp::operator=\28sk_sp\20const&\29 +5360:sk_sp::operator=\28sk_sp&&\29 +5361:sk_sp::~sk_sp\28\29 +5362:sk_sp::sk_sp\28sk_sp\20const&\29 +5363:sk_sp&\20sk_sp::operator=\28sk_sp&&\29 +5364:sk_sp::reset\28GrSurface::RefCntedReleaseProc*\29 +5365:sk_sp::operator=\28sk_sp&&\29 +5366:sk_sp::~sk_sp\28\29 +5367:sk_sp::operator=\28sk_sp&&\29 +5368:sk_sp::~sk_sp\28\29 +5369:sk_sp\20sk_make_sp\28\29 +5370:sk_sp::reset\28GrArenas*\29 +5371:sk_ft_alloc\28FT_MemoryRec_*\2c\20long\29 +5372:sk_fopen\28char\20const*\2c\20SkFILE_Flags\29 +5373:sk_fgetsize\28_IO_FILE*\29 +5374:sk_determinant\28float\20const*\2c\20int\29 +5375:sk_blit_below\28SkBlitter*\2c\20SkIRect\20const&\2c\20SkRegion\20const&\29 +5376:sk_blit_above\28SkBlitter*\2c\20SkIRect\20const&\2c\20SkRegion\20const&\29 +5377:sid_to_gid_t\20const*\20hb_sorted_array_t::bsearch\28unsigned\20int\20const&\2c\20sid_to_gid_t\20const*\29 +5378:short\20sk_saturate_cast\28float\29 +5379:sharp_angle\28SkPoint\20const*\29 +5380:sfnt_stream_close +5381:setup_masks_arabic_plan\28arabic_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_script_t\29 +5382:set_points\28float*\2c\20int*\2c\20int\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float\2c\20float\2c\20bool\29 +5383:set_normal_unitnormal\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +5384:set_khr_debug_label\28GrGLGpu*\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +5385:setThrew +5386:serialize_image\28SkImage\20const*\2c\20SkSerialProcs\29 +5387:sem_trywait +5388:sem_init +5389:sect_clamp_with_vertical\28SkPoint\20const*\2c\20float\29 +5390:scanexp +5391:scalbnl +5392:safe_picture_bounds\28SkRect\20const&\29 +5393:safe_int_addition +5394:rt_has_msaa_render_buffer\28GrGLRenderTarget\20const*\2c\20GrGLCaps\20const&\29 +5395:rrect_type_to_vert_count\28RRectType\29 +5396:row_is_all_zeros\28unsigned\20char\20const*\2c\20int\29 +5397:round_up_to_int\28float\29 +5398:round_down_to_int\28float\29 +5399:rotate\28SkDCubic\20const&\2c\20int\2c\20int\2c\20SkDCubic&\29 +5400:rewind_if_necessary\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +5401:resolveImplicitLevels\28UBiDi*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +5402:renderbuffer_storage_msaa\28GrGLGpu*\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +5403:remove_edge_below\28GrTriangulator::Edge*\29 +5404:remove_edge_above\28GrTriangulator::Edge*\29 +5405:remove_active_ctx +5406:reductionLineCount\28SkDQuad\20const&\29 +5407:recursive_edge_intersect\28GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20SkPoint*\2c\20double*\2c\20double*\29 +5408:rect_exceeds\28SkRect\20const&\2c\20float\29 +5409:reclassify_vertex\28TriangulationVertex*\2c\20SkPoint\20const*\2c\20int\2c\20ReflexHash*\2c\20SkTInternalLList*\29 +5410:radii_are_nine_patch\28SkPoint\20const*\29 +5411:quad_type_for_transformed_rect\28SkMatrix\20const&\29 +5412:quad_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5413:quad_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5414:quad_in_line\28SkPoint\20const*\29 +5415:pthread_cond_wait +5416:pthread_cond_signal +5417:pthread_cond_broadcast +5418:pt_to_tangent_line\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +5419:psh_hint_table_record +5420:psh_hint_table_init +5421:psh_hint_table_find_strong_points +5422:psh_hint_table_done +5423:psh_hint_table_activate_mask +5424:psh_hint_align +5425:psh_glyph_load_points +5426:psh_globals_scale_widths +5427:psh_compute_dir +5428:psh_blues_set_zones_0 +5429:psh_blues_set_zones +5430:ps_table_realloc +5431:ps_parser_to_token_array +5432:ps_parser_load_field +5433:ps_mask_table_last +5434:ps_mask_table_done +5435:ps_hints_stem +5436:ps_dimension_end +5437:ps_dimension_done +5438:ps_dimension_add_t1stem +5439:ps_builder_start_point +5440:ps_builder_close_contour +5441:ps_builder_add_point1 +5442:printf_core +5443:prepare_to_draw_into_mask\28SkRect\20const&\2c\20SkMaskBuilder*\29 +5444:position_cluster\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29 +5445:portable::uniform_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5446:portable::set_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5447:portable::copy_from_indirect_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5448:portable::copy_2_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5449:portable::check_decal_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5450:pop_arg +5451:pointInTriangle\28SkDPoint\20const*\2c\20SkDPoint\20const&\29 +5452:pntz +5453:png_rtran_ok +5454:png_malloc_array_checked +5455:png_inflate +5456:png_format_buffer +5457:png_decompress_chunk +5458:png_colorspace_check_gamma +5459:png_cache_unknown_chunk +5460:pin_offset_s32\28int\2c\20int\2c\20int\29 +5461:path_key_from_data_size\28SkPath\20const&\29 +5462:parse_private_use_subtag\28char\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20char\20const*\2c\20unsigned\20char\20\28*\29\28unsigned\20char\29\29 +5463:paint_color_to_dst\28SkPaint\20const&\2c\20SkPixmap\20const&\29 +5464:pad4 +5465:operator_new_impl\28unsigned\20long\29 +5466:operator==\28SkRect\20const&\2c\20SkRect\20const&\29 +5467:operator==\28SkRRect\20const&\2c\20SkRRect\20const&\29 +5468:operator==\28SkPaint\20const&\2c\20SkPaint\20const&\29 +5469:operator!=\28SkRRect\20const&\2c\20SkRRect\20const&\29 +5470:open_face +5471:on_same_side\28SkPoint\20const*\2c\20int\2c\20int\29 +5472:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29_12104 +5473:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29 +5474:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +5475:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::glyphs\28\29\20const +5476:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2713 +5477:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +5478:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::size\28\29\20const +5479:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +5480:move_multiples\28SkOpContourHead*\29 +5481:mono_cubic_closestT\28float\20const*\2c\20float\29 +5482:mbsrtowcs +5483:matchesEnd\28SkDPoint\20const*\2c\20SkDPoint\20const&\29 +5484:map_rect_perspective\28SkRect\20const&\2c\20float\20const*\29::$_0::operator\28\29\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20const::'lambda'\28skvx::Vec<4\2c\20float>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20float>\20const&\29\20const +5485:map_quad_to_rect\28SkRSXform\20const&\2c\20SkRect\20const&\29 +5486:map_quad_general\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20SkMatrix\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +5487:make_xrect\28SkRect\20const&\29 +5488:make_tiled_gradient\28GrFPArgs\20const&\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20bool\2c\20bool\29 +5489:make_premul_effect\28std::__2::unique_ptr>\29 +5490:make_paint_with_image\28SkPaint\20const&\2c\20SkBitmap\20const&\2c\20SkSamplingOptions\20const&\2c\20SkMatrix*\29 +5491:make_dual_interval_colorizer\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20float\29 +5492:make_clamped_gradient\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20bool\29 +5493:make_bmp_proxy\28GrProxyProvider*\2c\20SkBitmap\20const&\2c\20GrColorType\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +5494:long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +5495:long\20long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +5496:long\20double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +5497:log2f_\28float\29 +5498:load_post_names +5499:line_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5500:line_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5501:lineMetrics_getLineNumber +5502:lineMetrics_getHardBreak +5503:lineBreakBuffer_free +5504:lin_srgb_to_oklab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +5505:lang_find_or_insert\28char\20const*\29 +5506:isxdigit +5507:isdigit +5508:is_zero_width_char\28hb_font_t*\2c\20unsigned\20int\29 +5509:is_simple_rect\28GrQuad\20const&\29 +5510:is_plane_config_compatible_with_subsampling\28SkYUVAInfo::PlaneConfig\2c\20SkYUVAInfo::Subsampling\29 +5511:is_overlap_edge\28GrTriangulator::Edge*\29 +5512:is_leap +5513:is_int\28float\29 +5514:is_halant_use\28hb_glyph_info_t\20const&\29 +5515:is_float_fp32\28GrGLContextInfo\20const&\2c\20GrGLInterface\20const*\2c\20unsigned\20int\29 +5516:iprintf +5517:invalidate_buffer\28GrGLGpu*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20long\29 +5518:interp_cubic_coords\28double\20const*\2c\20double*\2c\20double\29 +5519:int\20SkRecords::Pattern>::matchFirst>\28SkRecords::Is*\2c\20SkRecord*\2c\20int\29 +5520:inside_triangle\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +5521:init_mparams +5522:init_active_ctxs +5523:inflateEnd +5524:image_ref +5525:image_getWidth +5526:hb_vector_t::resize\28int\2c\20bool\2c\20bool\29 +5527:hb_vector_t\2c\20false>::shrink_vector\28unsigned\20int\29 +5528:hb_vector_t\2c\20false>::resize\28int\2c\20bool\2c\20bool\29 +5529:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +5530:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +5531:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +5532:hb_vector_t::pop\28\29 +5533:hb_vector_t\2c\20false>::shrink_vector\28unsigned\20int\29 +5534:hb_vector_t\2c\20false>::fini\28\29 +5535:hb_vector_t::shrink_vector\28unsigned\20int\29 +5536:hb_vector_t::fini\28\29 +5537:hb_unicode_mirroring_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +5538:hb_unicode_funcs_t::is_default_ignorable\28unsigned\20int\29 +5539:hb_unicode_funcs_get_default +5540:hb_tag_from_string +5541:hb_shape_plan_key_t::init\28bool\2c\20hb_face_t*\2c\20hb_segment_properties_t\20const*\2c\20hb_feature_t\20const*\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20char\20const*\20const*\29 +5542:hb_shape_plan_key_t::fini\28\29 +5543:hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>::may_have\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>\20const&\29\20const +5544:hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>::add\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>\20const&\29 +5545:hb_serialize_context_t::fini\28\29 +5546:hb_sanitize_context_t::return_t\20OT::Context::dispatch\28hb_sanitize_context_t*\29\20const +5547:hb_sanitize_context_t::return_t\20OT::ChainContext::dispatch\28hb_sanitize_context_t*\29\20const +5548:hb_paint_funcs_t::sweep_gradient\28void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5549:hb_paint_funcs_t::radial_gradient\28void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5550:hb_paint_funcs_t::push_skew\28void*\2c\20float\2c\20float\29 +5551:hb_paint_funcs_t::push_rotate\28void*\2c\20float\29 +5552:hb_paint_funcs_t::push_inverse_root_transform\28void*\2c\20hb_font_t*\29 +5553:hb_paint_funcs_t::push_group\28void*\29 +5554:hb_paint_funcs_t::pop_group\28void*\2c\20hb_paint_composite_mode_t\29 +5555:hb_paint_funcs_t::linear_gradient\28void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5556:hb_paint_extents_paint_linear_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +5557:hb_paint_extents_get_funcs\28\29 +5558:hb_paint_extents_context_t::pop_clip\28\29 +5559:hb_paint_extents_context_t::hb_paint_extents_context_t\28\29 +5560:hb_ot_map_t::fini\28\29 +5561:hb_ot_map_builder_t::add_pause\28unsigned\20int\2c\20bool\20\28*\29\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29\29 +5562:hb_ot_map_builder_t::add_lookups\28hb_ot_map_t&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20unsigned\20int\29 +5563:hb_ot_layout_has_substitution +5564:hb_ot_font_set_funcs +5565:hb_memcmp\28void\20const*\2c\20void\20const*\2c\20unsigned\20int\29 +5566:hb_lazy_loader_t\2c\20hb_face_t\2c\2038u\2c\20OT::sbix_accelerator_t>::get_stored\28\29\20const +5567:hb_lazy_loader_t\2c\20hb_face_t\2c\207u\2c\20OT::post_accelerator_t>::get_stored\28\29\20const +5568:hb_lazy_loader_t\2c\20hb_face_t\2c\207u\2c\20OT::post_accelerator_t>::do_destroy\28OT::post_accelerator_t*\29 +5569:hb_lazy_loader_t\2c\20hb_face_t\2c\2023u\2c\20hb_blob_t>::get_stored\28\29\20const +5570:hb_lazy_loader_t\2c\20hb_face_t\2c\205u\2c\20OT::hmtx_accelerator_t>::get_stored\28\29\20const +5571:hb_lazy_loader_t\2c\20hb_face_t\2c\2021u\2c\20OT::gvar_accelerator_t>::do_destroy\28OT::gvar_accelerator_t*\29 +5572:hb_lazy_loader_t\2c\20hb_face_t\2c\2015u\2c\20OT::glyf_accelerator_t>::do_destroy\28OT::glyf_accelerator_t*\29 +5573:hb_lazy_loader_t\2c\20hb_face_t\2c\203u\2c\20OT::cmap_accelerator_t>::do_destroy\28OT::cmap_accelerator_t*\29 +5574:hb_lazy_loader_t\2c\20hb_face_t\2c\2017u\2c\20OT::cff2_accelerator_t>::get_stored\28\29\20const +5575:hb_lazy_loader_t\2c\20hb_face_t\2c\2017u\2c\20OT::cff2_accelerator_t>::do_destroy\28OT::cff2_accelerator_t*\29 +5576:hb_lazy_loader_t\2c\20hb_face_t\2c\2016u\2c\20OT::cff1_accelerator_t>::do_destroy\28OT::cff1_accelerator_t*\29 +5577:hb_lazy_loader_t\2c\20hb_face_t\2c\2019u\2c\20hb_blob_t>::get\28\29\20const +5578:hb_lazy_loader_t\2c\20hb_face_t\2c\2024u\2c\20OT::GDEF_accelerator_t>::do_destroy\28OT::GDEF_accelerator_t*\29 +5579:hb_lazy_loader_t\2c\20hb_face_t\2c\2035u\2c\20hb_blob_t>::get\28\29\20const +5580:hb_lazy_loader_t\2c\20hb_face_t\2c\2037u\2c\20OT::CBDT_accelerator_t>::get_stored\28\29\20const +5581:hb_lazy_loader_t\2c\20hb_face_t\2c\2037u\2c\20OT::CBDT_accelerator_t>::do_destroy\28OT::CBDT_accelerator_t*\29 +5582:hb_lazy_loader_t\2c\20hb_face_t\2c\2032u\2c\20hb_blob_t>::get\28\29\20const +5583:hb_lazy_loader_t\2c\20hb_face_t\2c\2028u\2c\20hb_blob_t>::get_stored\28\29\20const +5584:hb_lazy_loader_t\2c\20hb_face_t\2c\2028u\2c\20hb_blob_t>::get\28\29\20const +5585:hb_lazy_loader_t\2c\20hb_face_t\2c\2029u\2c\20hb_blob_t>::get_stored\28\29\20const +5586:hb_lazy_loader_t\2c\20hb_face_t\2c\2029u\2c\20hb_blob_t>::get\28\29\20const +5587:hb_lazy_loader_t\2c\20hb_face_t\2c\2033u\2c\20hb_blob_t>::get\28\29\20const +5588:hb_lazy_loader_t\2c\20hb_face_t\2c\2030u\2c\20hb_blob_t>::get_stored\28\29\20const +5589:hb_language_matches +5590:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>\2c\20hb_pair_t>>::operator-=\28unsigned\20int\29\20& +5591:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>\2c\20hb_pair_t>>::operator+=\28unsigned\20int\29\20& +5592:hb_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20hb_pair_t>::operator++\28\29\20& +5593:hb_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>\2c\20hb_pair_t>::operator--\28\29\20& +5594:hb_indic_get_categories\28unsigned\20int\29 +5595:hb_hashmap_t::fetch_item\28unsigned\20int\20const&\2c\20unsigned\20int\29\20const +5596:hb_hashmap_t::fetch_item\28hb_serialize_context_t::object_t\20const*\20const&\2c\20unsigned\20int\29\20const +5597:hb_font_t::subtract_glyph_origin_for_direction\28unsigned\20int\2c\20hb_direction_t\2c\20int*\2c\20int*\29 +5598:hb_font_t::subtract_glyph_h_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +5599:hb_font_t::guess_v_origin_minus_h_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +5600:hb_font_t::get_variation_glyph\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\29 +5601:hb_font_t::get_glyph_v_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +5602:hb_font_t::get_glyph_v_kerning\28unsigned\20int\2c\20unsigned\20int\29 +5603:hb_font_t::get_glyph_h_kerning\28unsigned\20int\2c\20unsigned\20int\29 +5604:hb_font_t::get_glyph_contour_point\28unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\29 +5605:hb_font_t::get_font_h_extents\28hb_font_extents_t*\29 +5606:hb_font_t::draw_glyph\28unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\29 +5607:hb_font_set_variations +5608:hb_font_set_funcs +5609:hb_font_get_variation_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +5610:hb_font_get_font_h_extents_nil\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +5611:hb_font_funcs_set_variation_glyph_func +5612:hb_font_funcs_set_nominal_glyphs_func +5613:hb_font_funcs_set_nominal_glyph_func +5614:hb_font_funcs_set_glyph_h_advances_func +5615:hb_font_funcs_set_glyph_extents_func +5616:hb_font_funcs_create +5617:hb_font_destroy +5618:hb_face_destroy +5619:hb_face_create_for_tables +5620:hb_draw_move_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +5621:hb_draw_funcs_t::emit_move_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\29 +5622:hb_draw_funcs_set_quadratic_to_func +5623:hb_draw_funcs_set_move_to_func +5624:hb_draw_funcs_set_line_to_func +5625:hb_draw_funcs_set_cubic_to_func +5626:hb_draw_funcs_destroy +5627:hb_draw_funcs_create +5628:hb_draw_extents_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +5629:hb_cache_t<24u\2c\2016u\2c\208u\2c\20true>::clear\28\29 +5630:hb_buffer_t::sort\28unsigned\20int\2c\20unsigned\20int\2c\20int\20\28*\29\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29\29 +5631:hb_buffer_t::safe_to_insert_tatweel\28unsigned\20int\2c\20unsigned\20int\29 +5632:hb_buffer_t::next_glyphs\28unsigned\20int\29 +5633:hb_buffer_t::message_impl\28hb_font_t*\2c\20char\20const*\2c\20void*\29 +5634:hb_buffer_t::delete_glyphs_inplace\28bool\20\28*\29\28hb_glyph_info_t\20const*\29\29 +5635:hb_buffer_t::clear\28\29 +5636:hb_buffer_t::add\28unsigned\20int\2c\20unsigned\20int\29 +5637:hb_buffer_get_glyph_positions +5638:hb_buffer_diff +5639:hb_buffer_clear_contents +5640:hb_buffer_add_utf8 +5641:hb_bounds_t::union_\28hb_bounds_t\20const&\29 +5642:hb_blob_t::destroy_user_data\28\29 +5643:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +5644:hb_array_t::hash\28\29\20const +5645:hb_array_t::cmp\28hb_array_t\20const&\29\20const +5646:hb_array_t>::qsort\28int\20\28*\29\28void\20const*\2c\20void\20const*\29\29 +5647:hb_array_t::__next__\28\29 +5648:hb_aat_map_builder_t::feature_info_t\20const*\20hb_vector_t::bsearch\28hb_aat_map_builder_t::feature_info_t\20const&\2c\20hb_aat_map_builder_t::feature_info_t\20const*\29\20const +5649:hb_aat_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +5650:hb_aat_map_builder_t::feature_info_t::cmp\28hb_aat_map_builder_t::feature_info_t\20const&\29\20const +5651:hb_aat_layout_remove_deleted_glyphs\28hb_buffer_t*\29 +5652:has_msaa_render_buffer\28GrSurfaceProxy\20const*\2c\20GrGLCaps\20const&\29 +5653:hair_cubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +5654:getint +5655:get_win_string +5656:get_tasks_for_thread +5657:get_paint\28GrAA\2c\20unsigned\20char\29 +5658:get_layer_mapping_and_bounds\28SkSpan>\2c\20SkMatrix\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\2c\20float\29::$_0::operator\28\29\28int\29\20const +5659:get_dst_swizzle_and_store\28GrColorType\2c\20SkRasterPipelineOp*\2c\20LumMode*\2c\20bool*\2c\20bool*\29 +5660:get_driver_and_version\28GrGLStandard\2c\20GrGLVendor\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +5661:get_apple_string +5662:getSingleRun\28UBiDi*\2c\20unsigned\20char\29 +5663:getRunFromLogicalIndex\28UBiDi*\2c\20int\29 +5664:getMirror\28int\2c\20unsigned\20short\29\20\28.8960\29 +5665:geometric_overlap\28SkRect\20const&\2c\20SkRect\20const&\29 +5666:geometric_contains\28SkRect\20const&\2c\20SkRect\20const&\29 +5667:gen_key\28skgpu::KeyBuilder*\2c\20GrProgramInfo\20const&\2c\20GrCaps\20const&\29 +5668:gen_fp_key\28GrFragmentProcessor\20const&\2c\20GrCaps\20const&\2c\20skgpu::KeyBuilder*\29 +5669:gather_uniforms_and_check_for_main\28SkSL::Program\20const&\2c\20std::__2::vector>*\2c\20std::__2::vector>*\2c\20SkRuntimeEffect::Uniform::Flags\2c\20unsigned\20long*\29 +5670:fwrite +5671:ft_var_to_normalized +5672:ft_var_load_item_variation_store +5673:ft_var_load_hvvar +5674:ft_var_load_avar +5675:ft_var_get_value_pointer +5676:ft_var_get_item_delta +5677:ft_var_apply_tuple +5678:ft_set_current_renderer +5679:ft_recompute_scaled_metrics +5680:ft_mem_strcpyn +5681:ft_mem_dup +5682:ft_hash_num_lookup +5683:ft_gzip_alloc +5684:ft_glyphslot_preset_bitmap +5685:ft_glyphslot_done +5686:ft_corner_orientation +5687:ft_corner_is_flat +5688:ft_cmap_done_internal +5689:frexp +5690:fread +5691:fquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5692:fp_force_eval +5693:fp_barrier +5694:formulate_F1DotF2\28float\20const*\2c\20float*\29 +5695:formulate_F1DotF2\28double\20const*\2c\20double*\29 +5696:format_alignment\28SkMask::Format\29 +5697:format1_names\28unsigned\20int\29 +5698:fopen +5699:fold_opacity_layer_color_to_paint\28SkPaint\20const*\2c\20bool\2c\20SkPaint*\29 +5700:fmodl +5701:float\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +5702:fline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5703:first_axis_intersection\28double\20const*\2c\20bool\2c\20double\2c\20double*\29 +5704:fiprintf +5705:find_unicode_charmap +5706:find_diff_pt\28SkPoint\20const*\2c\20int\2c\20int\2c\20int\29 +5707:fillable\28SkRect\20const&\29 +5708:fileno +5709:fcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5710:fconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5711:exp2f_\28float\29 +5712:eval_cubic_pts\28float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5713:eval_cubic_derivative\28SkPoint\20const*\2c\20float\29 +5714:emptyOnNull\28sk_sp&&\29 +5715:em_task_queue_free +5716:em_task_queue_enqueue +5717:em_task_queue_dequeue +5718:em_task_queue_create +5719:em_task_queue_cancel +5720:em_proxying_ctx_deinit +5721:elliptical_effect_uses_scale\28GrShaderCaps\20const&\2c\20SkRRect\20const&\29 +5722:edges_too_close\28SkAnalyticEdge*\2c\20SkAnalyticEdge*\2c\20int\29 +5723:edge_line_needs_recursion\28SkPoint\20const&\2c\20SkPoint\20const&\29 +5724:eat_space_sep_strings\28skia_private::TArray*\2c\20char\20const*\29 +5725:draw_rect_as_path\28SkDrawBase\20const&\2c\20SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\29 +5726:draw_nine\28SkMask\20const&\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\2c\20bool\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +5727:dquad_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5728:double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +5729:do_fixed +5730:doWriteReverse\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +5731:doWriteForward\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +5732:dline_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5733:distance_to_sentinel\28int\20const*\29 +5734:dispose_chunk +5735:diff_to_shift\28int\2c\20int\2c\20int\29 +5736:destroy_size +5737:destroy_charmaps +5738:decompose_current_character\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\29 +5739:decompose\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\2c\20unsigned\20int\29 +5740:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::Make\28SkArenaAlloc*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5741:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&\2c\20skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathCurveTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5742:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5743:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker\2c\20int&>\28int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5744:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkShaderBase&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTransformShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5745:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5746:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29>\28GrThreadSafeCache::Entry&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5747:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrRRectShadowGeoProc::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5748:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28GrQuadEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5749:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrPipeline::InitArgs&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29::'lambda'\28void*\29>\28GrPipeline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5750:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldA8TextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20float\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5751:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28CircleGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5752:decltype\28fp0\28\28SkRecords::NoOp\29\28\29\29\29\20SkRecord::visit\28int\2c\20SkRecords::Draw&\29\20const +5753:decltype\28fp0\28\28SkRecords::NoOp*\29\28nullptr\29\29\29\20SkRecord::mutate\28int\2c\20SkRecord::Destroyer&\29 +5754:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +5755:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>>::__generic_construct\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__ctor\2c\20std::__2::unique_ptr>>>&\2c\20std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&>\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&\29 +5756:dcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5757:dcubic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5758:dconic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5759:data_destroy_arabic\28void*\29 +5760:data_create_arabic\28hb_ot_shape_plan_t\20const*\29 +5761:cycle +5762:cubic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5763:cubic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5764:cubic_delta_from_line\28int\2c\20int\2c\20int\2c\20int\29 +5765:crop_simple_rect\28SkRect\20const&\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +5766:crop_rect\28SkRect\20const&\2c\20float*\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +5767:count_scalable_pixels\28int\20const*\2c\20int\2c\20bool\2c\20int\2c\20int\29 +5768:copysignl +5769:copy_mask_to_cacheddata\28SkMaskBuilder*\29 +5770:copy_bitmap_subset\28SkBitmap\20const&\2c\20SkIRect\20const&\29 +5771:contour_point_vector_t::extend\28hb_array_t\20const&\29 +5772:conservative_round_to_int\28SkRect\20const&\29 +5773:conic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5774:conic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5775:conic_eval_tan\28double\20const*\2c\20float\2c\20double\29 +5776:conic_deriv_coeff\28double\20const*\2c\20float\2c\20double*\29 +5777:compute_stroke_size\28SkPaint\20const&\2c\20SkMatrix\20const&\29 +5778:compute_pos_tan\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +5779:compute_normal\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint*\29 +5780:compute_intersection\28OffsetSegment\20const&\2c\20OffsetSegment\20const&\2c\20SkPoint*\2c\20float*\2c\20float*\29 +5781:compute_anti_width\28short\20const*\29 +5782:compose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +5783:compare_offsets +5784:clip_to_limit\28SkRegion\20const&\2c\20SkRegion*\29 +5785:clip_line\28SkPoint*\2c\20SkRect\20const&\2c\20float\2c\20float\29 +5786:clipHandlesSprite\28SkRasterClip\20const&\2c\20int\2c\20int\2c\20SkPixmap\20const&\29 +5787:clean_sampling_for_constraint\28SkSamplingOptions\20const&\2c\20SkCanvas::SrcRectConstraint\29 +5788:clamp_to_zero\28SkPoint*\29 +5789:clamp\28SkPoint\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Comparator\20const&\29 +5790:chop_mono_cubic_at_x\28SkPoint*\2c\20float\2c\20SkPoint*\29 +5791:chopMonoQuadAt\28float\2c\20float\2c\20float\2c\20float\2c\20float*\29 +5792:chopMonoQuadAtY\28SkPoint*\2c\20float\2c\20float*\29 +5793:chopMonoQuadAtX\28SkPoint*\2c\20float\2c\20float*\29 +5794:checkint +5795:check_write_and_transfer_input\28GrGLTexture*\29 +5796:check_name\28SkString\20const&\29 +5797:check_backend_texture\28GrBackendTexture\20const&\2c\20GrGLCaps\20const&\2c\20GrGLTexture::Desc*\2c\20bool\29 +5798:char*\20std::__2::copy\5babi:nn180100\5d\2c\20char*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20char*\29 +5799:char*\20std::__2::copy\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29 +5800:char*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20std::__2::__element_count\29 +5801:char*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29 +5802:cff_vstore_done +5803:cff_subfont_load +5804:cff_subfont_done +5805:cff_size_select +5806:cff_parser_run +5807:cff_parser_init +5808:cff_make_private_dict +5809:cff_load_private_dict +5810:cff_index_get_name +5811:cff_glyph_load +5812:cff_get_kerning +5813:cff_get_glyph_data +5814:cff_fd_select_get +5815:cff_charset_compute_cids +5816:cff_builder_init +5817:cff_builder_add_point1 +5818:cff_builder_add_point +5819:cff_builder_add_contour +5820:cff_blend_check_vector +5821:cff_blend_build_vector +5822:cff1_path_param_t::end_path\28\29 +5823:cf2_stack_pop +5824:cf2_hintmask_setCounts +5825:cf2_hintmask_read +5826:cf2_glyphpath_pushMove +5827:cf2_getSeacComponent +5828:cf2_freeSeacComponent +5829:cf2_computeDarkening +5830:cf2_arrstack_setNumElements +5831:cf2_arrstack_push +5832:cbrt +5833:cancel_ctx +5834:can_use_hw_blend_equation\28skgpu::BlendEquation\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\29 +5835:can_proxy_use_scratch\28GrCaps\20const&\2c\20GrSurfaceProxy*\29 +5836:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_3::operator\28\29\28float\29\20const +5837:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_2::operator\28\29\28float\29\20const +5838:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_0::operator\28\29\28float\29\20const +5839:build_key\28skgpu::ResourceKey::Builder*\2c\20GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\29 +5840:build_intervals\28int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const*\2c\20float\20const*\2c\20int\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20float*\29 +5841:bracketProcessChar\28BracketData*\2c\20int\29 +5842:bracketInit\28UBiDi*\2c\20BracketData*\29 +5843:bounds_t::merge\28bounds_t\20const&\29 +5844:bottom_collinear\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +5845:bool\20std::__2::operator==\5babi:ne180100\5d>\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +5846:bool\20std::__2::operator==\5babi:ne180100\5d\28std::__2::variant\20const&\2c\20std::__2::variant\20const&\29 +5847:bool\20std::__2::operator!=\5babi:ne180100\5d\28std::__2::variant\20const&\2c\20std::__2::variant\20const&\29 +5848:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +5849:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +5850:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +5851:bool\20set_point_length\28SkPoint*\2c\20float\2c\20float\2c\20float\2c\20float*\29 +5852:bool\20is_parallel\28SkDLine\20const&\2c\20SkTCurve\20const&\29 +5853:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +5854:bool\20hb_sanitize_context_t::check_array\28OT::Index\20const*\2c\20unsigned\20int\29\20const +5855:bool\20hb_sanitize_context_t::check_array\28AAT::Feature\20const*\2c\20unsigned\20int\29\20const +5856:bool\20hb_sanitize_context_t::check_array>\28AAT::Entry\20const*\2c\20unsigned\20int\29\20const +5857:bool\20apply_string\28OT::hb_ot_apply_context_t*\2c\20GSUBProxy::Lookup\20const&\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\29 +5858:bool\20OT::hb_accelerate_subtables_context_t::cache_func_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\2c\20bool\29 +5859:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5860:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5861:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5862:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5863:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5864:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5865:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5866:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5867:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5868:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5869:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5870:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5871:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5872:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5873:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5874:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5875:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5876:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5877:bool\20OT::Paint::sanitize<>\28hb_sanitize_context_t*\29\20const +5878:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5879:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5880:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5881:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5882:bool\20OT::OffsetTo\2c\20true>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\2c\20unsigned\20int&&\29\20const +5883:bool\20OT::OffsetTo\2c\20true>::serialize_serialize\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&>\28hb_serialize_context_t*\2c\20hb_map_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&\29 +5884:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5885:bool\20OT::OffsetTo\2c\20true>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\2c\20unsigned\20int&&\29\20const +5886:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5887:bool\20OT::OffsetTo\2c\20true>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\2c\20AAT::track\20const*&&\29\20const +5888:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5889:bool\20OT::GSUBGPOS::sanitize\28hb_sanitize_context_t*\29\20const +5890:bool\20OT::GSUBGPOS::sanitize\28hb_sanitize_context_t*\29\20const +5891:bool\20GrTTopoSort_Visit\28GrRenderTask*\2c\20unsigned\20int*\29 +5892:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +5893:blit_two_alphas\28AdditiveBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +5894:blit_full_alpha\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +5895:blender_requires_shader\28SkBlender\20const*\29 +5896:bits_to_runs\28SkBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\2c\20long\2c\20unsigned\20char\29 +5897:between_closed\28double\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5898:barycentric_coords\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +5899:auto&&\20std::__2::__generic_get\5babi:ne180100\5d<0ul\2c\20std::__2::variant\20const&>\28std::__2::variant\20const&\29 +5900:atanf +5901:are_radius_check_predicates_valid\28float\2c\20float\2c\20float\29 +5902:arabic_fallback_plan_destroy\28arabic_fallback_plan_t*\29 +5903:apply_forward\28OT::hb_ot_apply_context_t*\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\2c\20unsigned\20int\29 +5904:apply_fill_type\28SkPathFillType\2c\20int\29 +5905:apply_fill_type\28SkPathFillType\2c\20GrTriangulator::Poly*\29 +5906:apply_alpha_and_colorfilter\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20SkPaint\20const&\29 +5907:append_texture_swizzle\28SkString*\2c\20skgpu::Swizzle\29 +5908:append_multitexture_lookup\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20int\2c\20GrGLSLVarying\20const&\2c\20char\20const*\2c\20char\20const*\29 +5909:append_color_output\28PorterDuffXferProcessor\20const&\2c\20GrGLSLXPFragmentBuilder*\2c\20skgpu::BlendFormula::OutputType\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +5910:antifilldot8\28int\2c\20int\2c\20int\2c\20int\2c\20SkBlitter*\2c\20bool\29 +5911:analysis_properties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\2c\20SkBlendMode\29 +5912:afm_stream_skip_spaces +5913:afm_stream_read_string +5914:afm_stream_read_one +5915:af_sort_and_quantize_widths +5916:af_shaper_get_elem +5917:af_loader_compute_darkening +5918:af_latin_metrics_scale_dim +5919:af_latin_hints_detect_features +5920:af_hint_normal_stem +5921:af_glyph_hints_align_weak_points +5922:af_glyph_hints_align_strong_points +5923:af_face_globals_new +5924:af_cjk_metrics_scale_dim +5925:af_cjk_metrics_scale +5926:af_cjk_metrics_init_widths +5927:af_cjk_metrics_check_digits +5928:af_cjk_hints_init +5929:af_cjk_hints_detect_features +5930:af_cjk_hints_compute_blue_edges +5931:af_cjk_hints_apply +5932:af_cjk_get_standard_widths +5933:af_cjk_compute_stem_width +5934:af_axis_hints_new_edge +5935:adjust_mipmapped\28skgpu::Mipmapped\2c\20SkBitmap\20const&\2c\20GrCaps\20const*\29 +5936:add_line\28SkPoint\20const*\2c\20skia_private::TArray*\29 +5937:add_const_color\28SkRasterPipeline_GradientCtx*\2c\20unsigned\20long\2c\20SkRGBA4f<\28SkAlphaType\292>\29 +5938:a_fetch_add.9320 +5939:a_fetch_add +5940:a_ctz_32 +5941:a_cas_p +5942:_pthread_cleanup_push +5943:_pthread_cleanup_pop +5944:_pow10\28unsigned\20int\29 +5945:_hb_preprocess_text_vowel_constraints\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +5946:_hb_ot_shape +5947:_hb_options_init\28\29 +5948:_hb_grapheme_group_func\28hb_glyph_info_t\20const&\2c\20hb_glyph_info_t\20const&\29 +5949:_hb_font_create\28hb_face_t*\29 +5950:_hb_fallback_shape +5951:_glyf_get_advance_with_var_unscaled\28hb_font_t*\2c\20unsigned\20int\2c\20bool\29 +5952:_emscripten_yield +5953:_emscripten_timeout +5954:_emscripten_thread_mailbox_init +5955:__wasm_init_tls +5956:__vm_wait +5957:__vfprintf_internal +5958:__trunctfsf2 +5959:__tan +5960:__strftime_l +5961:__set_thread_state +5962:__rem_pio2_large +5963:__pthread_rwlock_trywrlock +5964:__pthread_rwlock_tryrdlock +5965:__pthread_getspecific +5966:__private_cond_signal +5967:__nl_langinfo_l +5968:__newlocale +5969:__math_xflowf +5970:__math_uflowf +5971:__math_oflowf +5972:__math_invalidf +5973:__loc_is_allocated +5974:__getf2 +5975:__get_locale +5976:__ftello_unlocked +5977:__fseeko_unlocked +5978:__floatscan +5979:__expo2 +5980:__divtf3 +5981:__cxxabiv1::__base_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +5982:__cxxabiv1::\28anonymous\20namespace\29::InitByteGlobalMutex<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex\2c\20__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex>::instance\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar>::instance\2c\20\28unsigned\20int\20\28*\29\28\29\290>::LockGuard::~LockGuard\28\29 +5983:__cxxabiv1::\28anonymous\20namespace\29::InitByteGlobalMutex<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex\2c\20__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex>::instance\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar>::instance\2c\20\28unsigned\20int\20\28*\29\28\29\290>::LockGuard::LockGuard\28char\20const*\29 +5984:__cxxabiv1::\28anonymous\20namespace\29::GuardObject<__cxxabiv1::\28anonymous\20namespace\29::InitByteGlobalMutex<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex\2c\20__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex>::instance\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar>::instance\2c\20\28unsigned\20int\20\28*\29\28\29\290>>::GuardObject\28unsigned\20int*\29 +5985:_ZZN19GrGeometryProcessor11ProgramImpl17collectTransformsEP19GrGLSLVertexBuilderP20GrGLSLVaryingHandlerP20GrGLSLUniformHandler12GrShaderTypeRK11GrShaderVarSA_RK10GrPipelineEN3$_0clISE_EEvRT_RK19GrFragmentProcessorbPSJ_iNS0_9BaseCoordE +5986:_ZZN18GrGLProgramBuilder23computeCountsAndStridesEjRK19GrGeometryProcessorbENK3$_0clINS0_9AttributeEEEDaiRKT_ +5987:\28anonymous\20namespace\29::texture_color\28SkRGBA4f<\28SkAlphaType\293>\2c\20float\2c\20GrColorType\2c\20GrColorInfo\20const&\29 +5988:\28anonymous\20namespace\29::supported_aa\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrAA\29 +5989:\28anonymous\20namespace\29::set_uv_quad\28SkPoint\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +5990:\28anonymous\20namespace\29::safe_to_ignore_subset_rect\28GrAAType\2c\20SkFilterMode\2c\20DrawQuad\20const&\2c\20SkRect\20const&\29 +5991:\28anonymous\20namespace\29::rrect_type_to_vert_count\28\28anonymous\20namespace\29::RRectType\29 +5992:\28anonymous\20namespace\29::proxy_normalization_params\28GrSurfaceProxy\20const*\2c\20GrSurfaceOrigin\29 +5993:\28anonymous\20namespace\29::normalize_src_quad\28\28anonymous\20namespace\29::NormalizationParams\20const&\2c\20GrQuad*\29 +5994:\28anonymous\20namespace\29::normalize_and_inset_subset\28SkFilterMode\2c\20\28anonymous\20namespace\29::NormalizationParams\20const&\2c\20SkRect\20const*\29 +5995:\28anonymous\20namespace\29::next_gen_id\28\29 +5996:\28anonymous\20namespace\29::morphology_pass\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20\28anonymous\20namespace\29::MorphType\2c\20\28anonymous\20namespace\29::MorphDirection\2c\20int\29 +5997:\28anonymous\20namespace\29::make_non_convex_fill_op\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20skgpu::ganesh::FillPathFlags\2c\20GrAAType\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\29 +5998:\28anonymous\20namespace\29::is_visible\28SkRect\20const&\2c\20SkIRect\20const&\29 +5999:\28anonymous\20namespace\29::is_degen_quad_or_conic\28SkPoint\20const*\2c\20float*\29 +6000:\28anonymous\20namespace\29::init_vertices_paint\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkBlender*\2c\20bool\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +6001:\28anonymous\20namespace\29::get_hbFace_cache\28\29 +6002:\28anonymous\20namespace\29::gather_lines_and_quads\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\29::$_1::operator\28\29\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20bool\29\20const +6003:\28anonymous\20namespace\29::draw_to_sw_mask\28GrSWMaskHelper*\2c\20skgpu::ganesh::ClipStack::Element\20const&\2c\20bool\29 +6004:\28anonymous\20namespace\29::draw_tiled_image\28SkCanvas*\2c\20std::__2::function\20\28SkIRect\29>\2c\20SkISize\2c\20int\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkSamplingOptions\29 +6005:\28anonymous\20namespace\29::draw_path\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20skgpu::ganesh::PathRenderer*\2c\20GrHardClip\20const&\2c\20SkIRect\20const&\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20GrAA\29 +6006:\28anonymous\20namespace\29::determine_clipped_src_rect\28SkIRect\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkISize\20const&\2c\20SkRect\20const*\29 +6007:\28anonymous\20namespace\29::create_data\28int\2c\20bool\2c\20float\29 +6008:\28anonymous\20namespace\29::copyFTBitmap\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\29 +6009:\28anonymous\20namespace\29::contains_scissor\28GrScissorState\20const&\2c\20GrScissorState\20const&\29 +6010:\28anonymous\20namespace\29::colrv1_start_glyph_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20unsigned\20short\2c\20FT_Color_Root_Transform_\2c\20skia_private::THashSet*\29 +6011:\28anonymous\20namespace\29::colrv1_start_glyph\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20unsigned\20short\2c\20FT_Color_Root_Transform_\2c\20skia_private::THashSet*\29 +6012:\28anonymous\20namespace\29::colrv1_draw_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\29 +6013:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29 +6014:\28anonymous\20namespace\29::can_use_draw_texture\28SkPaint\20const&\2c\20SkSamplingOptions\20const&\29 +6015:\28anonymous\20namespace\29::axis_aligned_quad_size\28GrQuad\20const&\29 +6016:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29 +6017:\28anonymous\20namespace\29::YUVPlanesKey::YUVPlanesKey\28unsigned\20int\29 +6018:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29 +6019:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29 +6020:\28anonymous\20namespace\29::TriangulatingPathOp::TriangulatingPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +6021:\28anonymous\20namespace\29::TriangulatingPathOp::Triangulate\28GrEagerVertexAllocator*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool*\29 +6022:\28anonymous\20namespace\29::TriangulatingPathOp::CreateKey\28skgpu::UniqueKey*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\29 +6023:\28anonymous\20namespace\29::TransformedMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +6024:\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +6025:\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +6026:\28anonymous\20namespace\29::TransformedMaskSubRun::glyphCount\28\29\20const +6027:\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +6028:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29 +6029:\28anonymous\20namespace\29::TextureOpImpl::propagateCoverageAAThroughoutChain\28\29 +6030:\28anonymous\20namespace\29::TextureOpImpl::numChainedQuads\28\29\20const +6031:\28anonymous\20namespace\29::TextureOpImpl::characterize\28\28anonymous\20namespace\29::TextureOpImpl::Desc*\29\20const +6032:\28anonymous\20namespace\29::TextureOpImpl::appendQuad\28DrawQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\29 +6033:\28anonymous\20namespace\29::TextureOpImpl::Make\28GrRecordingContext*\2c\20GrTextureSetEntry*\2c\20int\2c\20int\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20GrAAType\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +6034:\28anonymous\20namespace\29::TextureOpImpl::FillInVertices\28GrCaps\20const&\2c\20\28anonymous\20namespace\29::TextureOpImpl*\2c\20\28anonymous\20namespace\29::TextureOpImpl::Desc*\2c\20char*\29 +6035:\28anonymous\20namespace\29::TextureOpImpl::Desc::totalSizeInBytes\28\29\20const +6036:\28anonymous\20namespace\29::TextureOpImpl::Desc*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc>\28\29 +6037:\28anonymous\20namespace\29::TextureOpImpl::ClassID\28\29 +6038:\28anonymous\20namespace\29::SpotVerticesFactory::makeVertices\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint*\29\20const +6039:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::hb_script_for_unichar\28int\29 +6040:\28anonymous\20namespace\29::SkQuadCoeff::SkQuadCoeff\28SkPoint\20const*\29 +6041:\28anonymous\20namespace\29::SkMorphologyImageFilter::requiredInput\28skif::Mapping\20const&\2c\20skif::LayerSpace\29\20const +6042:\28anonymous\20namespace\29::SkMorphologyImageFilter::kernelOutputBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\29\20const +6043:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::requiredInput\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\29\20const +6044:\28anonymous\20namespace\29::SkEmptyTypeface::onMakeClone\28SkFontArguments\20const&\29\20const +6045:\28anonymous\20namespace\29::SkCropImageFilter::requiredInput\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\29\20const +6046:\28anonymous\20namespace\29::SkConicCoeff::SkConicCoeff\28SkConic\20const&\29 +6047:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29 +6048:\28anonymous\20namespace\29::SkBlurImageFilter::mapSigma\28skif::Mapping\20const&\2c\20bool\29\20const +6049:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29 +6050:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29 +6051:\28anonymous\20namespace\29::ShaperHarfBuzz::~ShaperHarfBuzz\28\29 +6052:\28anonymous\20namespace\29::ShadowedPath::keyBytes\28\29\20const +6053:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29 +6054:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29 +6055:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12165 +6056:\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +6057:\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +6058:\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +6059:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29 +6060:\28anonymous\20namespace\29::RectsBlurKey::RectsBlurKey\28float\2c\20SkBlurStyle\2c\20SkRect\20const*\2c\20int\29 +6061:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const::'lambda'\28float\29::operator\28\29\28float\29\20const +6062:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29 +6063:\28anonymous\20namespace\29::RRectBlurKey::RRectBlurKey\28float\2c\20SkRRect\20const&\2c\20SkBlurStyle\29 +6064:\28anonymous\20namespace\29::PlanGauss::PlanGauss\28double\29 +6065:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29 +6066:\28anonymous\20namespace\29::PathOpSubmitter::~PathOpSubmitter\28\29 +6067:\28anonymous\20namespace\29::PathGeoBuilder::createMeshAndPutBackReserve\28\29 +6068:\28anonymous\20namespace\29::PathGeoBuilder::allocNewBuffers\28\29 +6069:\28anonymous\20namespace\29::PathGeoBuilder::addQuad\28SkPoint\20const*\2c\20float\2c\20float\29 +6070:\28anonymous\20namespace\29::Pass::blur\28int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +6071:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29 +6072:\28anonymous\20namespace\29::MipMapKey::MipMapKey\28SkBitmapCacheDesc\20const&\29 +6073:\28anonymous\20namespace\29::MipLevelHelper::allocAndInit\28SkArenaAlloc*\2c\20SkSamplingOptions\20const&\2c\20SkTileMode\2c\20SkTileMode\29 +6074:\28anonymous\20namespace\29::MipLevelHelper::MipLevelHelper\28\29 +6075:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29 +6076:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29 +6077:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20sk_sp\2c\20GrPrimitiveType\20const*\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +6078:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMesh\20const&\2c\20skia_private::TArray>\2c\20true>\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +6079:\28anonymous\20namespace\29::MeshOp::Mesh::indices\28\29\20const +6080:\28anonymous\20namespace\29::MeshOp::Mesh::Mesh\28SkMesh\20const&\29 +6081:\28anonymous\20namespace\29::MeshOp::ClassID\28\29 +6082:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29 +6083:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29 +6084:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineStruct\28char\20const*\29 +6085:\28anonymous\20namespace\29::Iter::next\28\29 +6086:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29 +6087:\28anonymous\20namespace\29::FillRectOpImpl::tessellate\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29\20const +6088:\28anonymous\20namespace\29::FillRectOpImpl::FillRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +6089:\28anonymous\20namespace\29::ExternalWebGLTexture::~ExternalWebGLTexture\28\29 +6090:\28anonymous\20namespace\29::EllipticalRRectEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +6091:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29 +6092:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29 +6093:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29 +6094:\28anonymous\20namespace\29::DrawAtlasOpImpl::DrawAtlasOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrAAType\2c\20int\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\29 +6095:\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +6096:\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +6097:\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +6098:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29 +6099:\28anonymous\20namespace\29::DefaultPathOp::programInfo\28\29 +6100:\28anonymous\20namespace\29::DefaultPathOp::primType\28\29\20const +6101:\28anonymous\20namespace\29::DefaultPathOp::PathData::PathData\28\28anonymous\20namespace\29::DefaultPathOp::PathData&&\29 +6102:\28anonymous\20namespace\29::DefaultPathOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +6103:\28anonymous\20namespace\29::DefaultPathOp::DefaultPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +6104:\28anonymous\20namespace\29::ClipGeometry\20\28anonymous\20namespace\29::get_clip_geometry\28skgpu::ganesh::ClipStack::SaveRecord\20const&\2c\20skgpu::ganesh::ClipStack::Draw\20const&\29 +6105:\28anonymous\20namespace\29::CircularRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20unsigned\20int\2c\20SkRRect\20const&\29 +6106:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29 +6107:\28anonymous\20namespace\29::CachedTessellationsRec::CachedTessellationsRec\28SkResourceCache::Key\20const&\2c\20sk_sp<\28anonymous\20namespace\29::CachedTessellations>\29 +6108:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29 +6109:\28anonymous\20namespace\29::CachedTessellations::CachedTessellations\28\29 +6110:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29 +6111:\28anonymous\20namespace\29::BitmapKey::BitmapKey\28SkBitmapCacheDesc\20const&\29 +6112:\28anonymous\20namespace\29::AmbientVerticesFactory::makeVertices\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint*\29\20const +6113:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29 +6114:\28anonymous\20namespace\29::AAHairlineOp::PathData::PathData\28\28anonymous\20namespace\29::AAHairlineOp::PathData&&\29 +6115:\28anonymous\20namespace\29::AAHairlineOp::AAHairlineOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIRect\2c\20float\2c\20GrUserStencilSettings\20const*\29 +6116:ToUpperCase +6117:TextureSourceImageGenerator::~TextureSourceImageGenerator\28\29 +6118:TT_Set_Named_Instance +6119:TT_Save_Context +6120:TT_Hint_Glyph +6121:TT_DotFix14 +6122:TT_Done_Context +6123:StringBuffer\20apply_format_string<1024>\28char\20const*\2c\20void*\2c\20char\20\28&\29\20\5b1024\5d\2c\20SkString*\29 +6124:SortContourList\28SkOpContourHead**\2c\20bool\2c\20bool\29 +6125:Skwasm::Surface::_resizeCanvasToFit\28int\2c\20int\29 +6126:SkWriter32::writeString\28char\20const*\2c\20unsigned\20long\29 +6127:SkWriter32::writePoint3\28SkPoint3\20const&\29 +6128:SkWStream::writeScalarAsText\28float\29 +6129:SkWBuffer::padToAlign4\28\29 +6130:SkVertices::getSizes\28\29\20const +6131:SkVertices::Builder::init\28SkVertices::Desc\20const&\29 +6132:SkVertices::Builder::Builder\28SkVertices::VertexMode\2c\20int\2c\20int\2c\20unsigned\20int\29 +6133:SkUnicode_client::~SkUnicode_client\28\29 +6134:SkUnicode::convertUtf16ToUtf8\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +6135:SkUnicode::BidiRegion&\20std::__2::vector>::emplace_back\28unsigned\20long&\2c\20unsigned\20long&\2c\20unsigned\20char&\29 +6136:SkUTF::UTF16ToUTF8\28char*\2c\20int\2c\20unsigned\20short\20const*\2c\20unsigned\20long\29 +6137:SkUTF::ToUTF8\28int\2c\20char*\29 +6138:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29 +6139:SkTypeface_FreeTypeStream::SkTypeface_FreeTypeStream\28std::__2::unique_ptr>\2c\20SkString\2c\20SkFontStyle\20const&\2c\20bool\29 +6140:SkTypeface_FreeType::getFaceRec\28\29\20const +6141:SkTypeface_FreeType::SkTypeface_FreeType\28SkFontStyle\20const&\2c\20bool\29 +6142:SkTypeface_FreeType::GetUnitsPerEm\28FT_FaceRec_*\29 +6143:SkTypeface_Custom::~SkTypeface_Custom\28\29 +6144:SkTypeface_Custom::onGetFamilyName\28SkString*\29\20const +6145:SkTypeface::unicharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +6146:SkTypeface::onGetFixedPitch\28\29\20const +6147:SkTypeface::MakeEmpty\28\29 +6148:SkTransformShader::update\28SkMatrix\20const&\29 +6149:SkTextBlobBuilder::updateDeferredBounds\28\29 +6150:SkTextBlobBuilder::reserve\28unsigned\20long\29 +6151:SkTextBlobBuilder::allocRunPos\28SkFont\20const&\2c\20int\2c\20SkRect\20const*\29 +6152:SkTextBlobBuilder::TightRunBounds\28SkTextBlob::RunRecord\20const&\29 +6153:SkTextBlob::getIntercepts\28float\20const*\2c\20float*\2c\20SkPaint\20const*\29\20const +6154:SkTaskGroup::add\28std::__2::function\29 +6155:SkTSpan::split\28SkTSpan*\2c\20SkArenaAlloc*\29 +6156:SkTSpan::splitAt\28SkTSpan*\2c\20double\2c\20SkArenaAlloc*\29 +6157:SkTSpan::linearIntersects\28SkTCurve\20const&\29\20const +6158:SkTSpan::hullCheck\28SkTSpan\20const*\2c\20bool*\2c\20bool*\29 +6159:SkTSpan::contains\28double\29\20const +6160:SkTSect::unlinkSpan\28SkTSpan*\29 +6161:SkTSect::removeAllBut\28SkTSpan\20const*\2c\20SkTSpan*\2c\20SkTSect*\29 +6162:SkTSect::recoverCollapsed\28\29 +6163:SkTSect::intersects\28SkTSpan*\2c\20SkTSect*\2c\20SkTSpan*\2c\20int*\29 +6164:SkTSect::coincidentHasT\28double\29 +6165:SkTSect::boundsMax\28\29 +6166:SkTSect::addSplitAt\28SkTSpan*\2c\20double\29 +6167:SkTSect::addForPerp\28SkTSpan*\2c\20double\29 +6168:SkTSect::EndsEqual\28SkTSect\20const*\2c\20SkTSect\20const*\2c\20SkIntersections*\29 +6169:SkTMultiMap::reset\28\29 +6170:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29 +6171:SkTMaskGamma<3\2c\203\2c\203>::SkTMaskGamma\28float\2c\20float\29 +6172:SkTMaskGamma<3\2c\203\2c\203>::CanonicalColor\28unsigned\20int\29 +6173:SkTInternalLList::remove\28skgpu::ganesh::SmallPathShapeData*\29 +6174:SkTInternalLList<\28anonymous\20namespace\29::CacheImpl::Value>::remove\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +6175:SkTInternalLList<\28anonymous\20namespace\29::CacheImpl::Value>::addToHead\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +6176:SkTInternalLList::remove\28TriangulationVertex*\29 +6177:SkTInternalLList::addToTail\28TriangulationVertex*\29 +6178:SkTInternalLList::Entry>::addToHead\28SkLRUCache::Entry*\29 +6179:SkTInternalLList>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry>::addToHead\28SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\29 +6180:SkTInternalLList>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry>::addToHead\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\29 +6181:SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::find\28SkImageFilterCacheKey\20const&\29\20const +6182:SkTDStorage::SkTDStorage\28SkTDStorage&&\29 +6183:SkTDPQueue<\28anonymous\20namespace\29::RunIteratorQueue::Entry\2c\20&\28anonymous\20namespace\29::RunIteratorQueue::CompareEntry\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\2c\20\28int*\20\28*\29\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\290>::insert\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\29 +6184:SkTDPQueue::remove\28GrGpuResource*\29 +6185:SkTDPQueue::percolateUpIfNecessary\28int\29 +6186:SkTDPQueue::percolateDownIfNecessary\28int\29 +6187:SkTDPQueue::insert\28GrGpuResource*\29 +6188:SkTDArray::append\28int\29 +6189:SkTDArray::append\28int\29 +6190:SkTDArray::push_back\28SkRecords::FillBounds::SaveBounds\20const&\29 +6191:SkTDArray::push_back\28SkOpPtT\20const*\20const&\29 +6192:SkTCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +6193:SkTCopyOnFirstWrite::writable\28\29 +6194:SkTCopyOnFirstWrite::writable\28\29 +6195:SkTConic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +6196:SkTConic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +6197:SkTConic::controlsInside\28\29\20const +6198:SkTConic::collapsed\28\29\20const +6199:SkTBlockList::pushItem\28\29 +6200:SkTBlockList::pop_back\28\29 +6201:SkTBlockList::push_back\28skgpu::ganesh::ClipStack::RawElement&&\29 +6202:SkTBlockList::pushItem\28\29 +6203:SkTBlockList::~SkTBlockList\28\29 +6204:SkTBlockList::push_back\28GrGLProgramDataManager::GLUniformInfo\20const&\29 +6205:SkTBlockList::item\28int\29 +6206:SkSurface_Raster::~SkSurface_Raster\28\29 +6207:SkSurface_Ganesh::~SkSurface_Ganesh\28\29 +6208:SkSurface_Ganesh::onDiscard\28\29 +6209:SkSurface_Base::replaceBackendTexture\28GrBackendTexture\20const&\2c\20GrSurfaceOrigin\2c\20SkSurface::ContentChangeMode\2c\20void\20\28*\29\28void*\29\2c\20void*\29 +6210:SkSurface_Base::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +6211:SkSurface_Base::onCapabilities\28\29 +6212:SkSurfaceValidateRasterInfo\28SkImageInfo\20const&\2c\20unsigned\20long\29 +6213:SkStrokeRec::GetInflationRadius\28SkPaint::Join\2c\20float\2c\20SkPaint::Cap\2c\20float\29 +6214:SkString_from_UTF16BE\28unsigned\20char\20const*\2c\20unsigned\20long\2c\20SkString&\29 +6215:SkString::equals\28char\20const*\2c\20unsigned\20long\29\20const +6216:SkString::equals\28char\20const*\29\20const +6217:SkString::appendVAList\28char\20const*\2c\20void*\29 +6218:SkString::appendUnichar\28int\29 +6219:SkString::appendHex\28unsigned\20int\2c\20int\29 +6220:SkStrikeSpec::SkStrikeSpec\28SkStrikeSpec\20const&\29 +6221:SkStrikeSpec::ShouldDrawAsPath\28SkPaint\20const&\2c\20SkFont\20const&\2c\20SkMatrix\20const&\29::$_0::operator\28\29\28int\2c\20int\29\20const +6222:SkStrikeSpec::ShouldDrawAsPath\28SkPaint\20const&\2c\20SkFont\20const&\2c\20SkMatrix\20const&\29 +6223:SkStrikeSpec::MakeTransformMask\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +6224:SkStrikeCache::~SkStrikeCache\28\29 +6225:SkStrike::~SkStrike\28\29 +6226:SkStrike::prepareForImage\28SkGlyph*\29 +6227:SkStrike::prepareForDrawable\28SkGlyph*\29 +6228:SkStrike::internalPrepare\28SkSpan\2c\20SkStrike::PathDetail\2c\20SkGlyph\20const**\29 +6229:SkStrSplit\28char\20const*\2c\20char\20const*\2c\20SkStrSplitMode\2c\20skia_private::TArray*\29 +6230:SkStrAppendU32\28char*\2c\20unsigned\20int\29 +6231:SkStrAppendS32\28char*\2c\20int\29 +6232:SkSpriteBlitter_Memcpy::~SkSpriteBlitter_Memcpy\28\29 +6233:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +6234:SkSpecialImages::AsBitmap\28SkSpecialImage\20const*\2c\20SkBitmap*\29 +6235:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29 +6236:SkSpecialImage_Raster::getROPixels\28SkBitmap*\29\20const +6237:SkSpecialImage_Raster::SkSpecialImage_Raster\28SkIRect\20const&\2c\20SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +6238:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29 +6239:SkSpecialImage::SkSpecialImage\28SkIRect\20const&\2c\20unsigned\20int\2c\20SkColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +6240:SkShapers::unicode::BidiRunIterator\28sk_sp\2c\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20char\29 +6241:SkShapers::HB::ShapeDontWrapOrReorder\28sk_sp\2c\20sk_sp\29 +6242:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29 +6243:SkShaper::MakeStdLanguageRunIterator\28char\20const*\2c\20unsigned\20long\29 +6244:SkShaper::MakeFontMgrRunIterator\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20sk_sp\29 +6245:SkShadowTessellator::MakeAmbient\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20bool\29 +6246:SkShaders::MatrixRec::totalMatrix\28\29\20const +6247:SkShaders::MatrixRec::concat\28SkMatrix\20const&\29\20const +6248:SkShaders::Empty\28\29 +6249:SkShaders::Color\28unsigned\20int\29 +6250:SkShaders::Blend\28sk_sp\2c\20sk_sp\2c\20sk_sp\29 +6251:SkShaderUtils::VisitLineByLine\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::function\20const&\29 +6252:SkShaderUtils::GLSLPrettyPrint::undoNewlineAfter\28char\29 +6253:SkShaderUtils::GLSLPrettyPrint::parseUntil\28char\20const*\29 +6254:SkShaderUtils::GLSLPrettyPrint::parseUntilNewline\28\29 +6255:SkShaderBlurAlgorithm::renderBlur\28SkRuntimeEffectBuilder*\2c\20SkFilterMode\2c\20SkISize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +6256:SkShaderBlurAlgorithm::evalBlur1D\28float\2c\20int\2c\20SkV2\2c\20sk_sp\2c\20SkIRect\2c\20SkTileMode\2c\20SkIRect\29\20const +6257:SkShaderBlurAlgorithm::GetLinearBlur1DEffect\28int\29 +6258:SkShaderBlurAlgorithm::GetBlur2DEffect\28SkISize\20const&\29 +6259:SkShaderBlurAlgorithm::Compute2DBlurOffsets\28SkISize\2c\20std::__2::array&\29 +6260:SkShaderBlurAlgorithm::Compute2DBlurKernel\28SkSize\2c\20SkISize\2c\20std::__2::array&\29 +6261:SkShaderBlurAlgorithm::Compute2DBlurKernel\28SkSize\2c\20SkISize\2c\20SkSpan\29 +6262:SkShaderBlurAlgorithm::Compute1DBlurLinearKernel\28float\2c\20int\2c\20std::__2::array&\29 +6263:SkShaderBlurAlgorithm::Compute1DBlurKernel\28float\2c\20int\2c\20SkSpan\29 +6264:SkShaderBase::getFlattenableType\28\29\20const +6265:SkShader::makeWithColorFilter\28sk_sp\29\20const +6266:SkScan::PathRequiresTiling\28SkIRect\20const&\29 +6267:SkScan::HairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +6268:SkScan::FillXRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6269:SkScan::FillRect\28SkRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6270:SkScan::AntiFrameRect\28SkRect\20const&\2c\20SkPoint\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6271:SkScan::AntiFillRect\28SkRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6272:SkScan::AAAFillPath\28SkPath\20const&\2c\20SkBlitter*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +6273:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29 +6274:SkScalerContext_FreeType::shouldSubpixelBitmap\28SkGlyph\20const&\2c\20SkMatrix\20const&\29 +6275:SkScalerContext_FreeType::getCBoxForLetter\28char\2c\20FT_BBox_*\29 +6276:SkScalerContext_FreeType::getBoundsOfCurrentOutlineGlyph\28FT_GlyphSlotRec_*\2c\20SkRect*\29 +6277:SkScalerContextRec::setLuminanceColor\28unsigned\20int\29 +6278:SkScalerContextFTUtils::drawCOLRv1Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +6279:SkScalerContextFTUtils::drawCOLRv0Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +6280:SkScalerContext::makeGlyph\28SkPackedGlyphID\2c\20SkArenaAlloc*\29 +6281:SkScalerContext::internalGetPath\28SkGlyph&\2c\20SkArenaAlloc*\29 +6282:SkScalerContext::SkScalerContext\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +6283:SkScalerContext::SaturateGlyphBounds\28SkGlyph*\2c\20SkRect&&\29 +6284:SkScalerContext::MakeRecAndEffects\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\2c\20SkScalerContextRec*\2c\20SkScalerContextEffects*\29 +6285:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +6286:SkScalerContext::AutoDescriptorGivenRecAndEffects\28SkScalerContextRec\20const&\2c\20SkScalerContextEffects\20const&\2c\20SkAutoDescriptor*\29 +6287:SkScalarInterpFunc\28float\2c\20float\20const*\2c\20float\20const*\2c\20int\29 +6288:SkSTArenaAlloc<4096ul>::SkSTArenaAlloc\28unsigned\20long\29 +6289:SkSTArenaAlloc<256ul>::SkSTArenaAlloc\28unsigned\20long\29 +6290:SkSLCombinedSamplerTypeForTextureType\28GrTextureType\29 +6291:SkSL::type_to_sksltype\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSLType*\29 +6292:SkSL::stoi\28std::__2::basic_string_view>\2c\20long\20long*\29 +6293:SkSL::splat_scalar\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +6294:SkSL::simplify_constant_equality\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +6295:SkSL::short_circuit_boolean\28SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +6296:SkSL::remove_break_statements\28std::__2::unique_ptr>&\29::RemoveBreaksWriter::visitStatementPtr\28std::__2::unique_ptr>&\29 +6297:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_2::operator\28\29\28int\29\20const +6298:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_1::operator\28\29\28int\29\20const +6299:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_0::operator\28\29\28int\29\20const +6300:SkSL::negate_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +6301:SkSL::make_reciprocal_expression\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29 +6302:SkSL::index_out_of_range\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20long\20long\2c\20SkSL::Expression\20const&\29 +6303:SkSL::hoist_vardecl_symbols_into_outer_scope\28SkSL::Context\20const&\2c\20SkSL::Block\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::SymbolTable*\29::SymbolHoister::visitStatement\28SkSL::Statement\20const&\29 +6304:SkSL::get_struct_definitions_from_module\28SkSL::Program&\2c\20SkSL::Module\20const&\2c\20std::__2::vector>*\29 +6305:SkSL::find_existing_declaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20SkSL::IntrinsicKind\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray>\2c\20true>&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration**\29::$_0::operator\28\29\28\29\20const +6306:SkSL::extract_matrix\28SkSL::Expression\20const*\2c\20float*\29 +6307:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +6308:SkSL::eliminate_no_op_boolean\28SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +6309:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_4::operator\28\29\28int\29\20const +6310:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_2::operator\28\29\28SkSL::Type\20const&\29\20const +6311:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_1::operator\28\29\28int\29\20const +6312:SkSL::argument_needs_scratch_variable\28SkSL::Expression\20const*\2c\20SkSL::Variable\20const*\2c\20SkSL::ProgramUsage\20const&\29 +6313:SkSL::argument_and_parameter_flags_match\28SkSL::Expression\20const&\2c\20SkSL::Variable\20const&\29 +6314:SkSL::apply_to_elements\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20double\20\28*\29\28double\29\29 +6315:SkSL::append_rtadjust_fixup_to_vertex_main\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::Block&\29::AppendRTAdjustFixupHelper::Adjust\28\29\20const +6316:SkSL::\28anonymous\20namespace\29::clone_with_ref_kind\28SkSL::Expression\20const&\2c\20SkSL::VariableRefKind\2c\20SkSL::Position\29 +6317:SkSL::\28anonymous\20namespace\29::check_valid_uniform_type\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Context\20const&\2c\20bool\29::$_0::operator\28\29\28\29\20const +6318:SkSL::\28anonymous\20namespace\29::caps_lookup_table\28\29 +6319:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +6320:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitStructFields\28SkSL::Type\20const&\29 +6321:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitStatement\28SkSL::Statement\20const&\29 +6322:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +6323:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitStatement\28SkSL::Statement\20const&\29 +6324:SkSL::\28anonymous\20namespace\29::IsAssignableVisitor::visitExpression\28SkSL::Expression&\2c\20SkSL::FieldAccess\20const*\29::'lambda'\28\29::operator\28\29\28\29\20const +6325:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +6326:SkSL::Variable::MakeScratchVariable\28SkSL::Context\20const&\2c\20SkSL::Mangler&\2c\20std::__2::basic_string_view>\2c\20SkSL::Type\20const*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>\29 +6327:SkSL::VarDeclaration::ErrorCheck\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Type\20const*\2c\20SkSL::VariableStorage\29 +6328:SkSL::TypeReference::description\28SkSL::OperatorPrecedence\29\20const +6329:SkSL::TypeReference::VerifyType\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Position\29 +6330:SkSL::TypeReference::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\29 +6331:SkSL::Type::checkIfUsableInArray\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +6332:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29\20const +6333:SkSL::Type::MakeStructType\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20bool\29 +6334:SkSL::Type::MakeLiteralType\28char\20const*\2c\20SkSL::Type\20const&\2c\20signed\20char\29 +6335:SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::addDeclaringElement\28SkSL::Symbol\20const*\29 +6336:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::visitStatementPtr\28std::__2::unique_ptr>&\29 +6337:SkSL::Transform::EliminateDeadGlobalVariables\28SkSL::Program&\29::$_0::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +6338:SkSL::Transform::EliminateDeadFunctions\28SkSL::Program&\29 +6339:SkSL::TernaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6340:SkSL::SymbolTable::moveSymbolTo\28SkSL::SymbolTable*\2c\20SkSL::Symbol*\2c\20SkSL::Context\20const&\29 +6341:SkSL::SymbolTable::isBuiltinType\28std::__2::basic_string_view>\29\20const +6342:SkSL::SymbolTable::insertNewParent\28\29 +6343:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Symbol*\29 +6344:SkSL::Symbol::instantiate\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +6345:SkSL::SwitchStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6346:SkSL::SwitchCase::Make\28SkSL::Position\2c\20long\20long\2c\20std::__2::unique_ptr>\29 +6347:SkSL::SwitchCase::MakeDefault\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +6348:SkSL::StructType::structNestingDepth\28\29\20const +6349:SkSL::StructType::slotCount\28\29\20const +6350:SkSL::StructType::StructType\28SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20int\2c\20bool\2c\20bool\29 +6351:SkSL::String::vappendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20void*\29 +6352:SkSL::SingleArgumentConstructor::argumentSpan\28\29 +6353:SkSL::Setting::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20bool\20const\20SkSL::ShaderCaps::*\29 +6354:SkSL::RP::stack_usage\28SkSL::RP::Instruction\20const&\29 +6355:SkSL::RP::is_sliceable_swizzle\28SkSpan\29 +6356:SkSL::RP::is_immediate_op\28SkSL::RP::BuilderOp\29 +6357:SkSL::RP::UnownedLValueSlice::isWritable\28\29\20const +6358:SkSL::RP::UnownedLValueSlice::dynamicSlotRange\28\29 +6359:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29 +6360:SkSL::RP::ScratchLValue::~ScratchLValue\28\29 +6361:SkSL::RP::Program::appendStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkSL::RP::Callbacks*\2c\20SkSpan\29\20const +6362:SkSL::RP::Program::appendStackRewind\28skia_private::TArray*\29\20const +6363:SkSL::RP::Program::appendCopyImmutableUnmasked\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20std::byte*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +6364:SkSL::RP::Program::appendAdjacentNWayTernaryOp\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSL::RP::ProgramOp\2c\20std::byte*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +6365:SkSL::RP::Program::appendAdjacentNWayBinaryOp\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSL::RP::ProgramOp\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +6366:SkSL::RP::LValue::swizzle\28\29 +6367:SkSL::RP::ImmutableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +6368:SkSL::RP::Generator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\29 +6369:SkSL::RP::Generator::writeFunction\28SkSL::IRNode\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSpan>\20const>\29 +6370:SkSL::RP::Generator::storeImmutableValueToSlots\28skia_private::TArray\20const&\2c\20SkSL::RP::SlotRange\29 +6371:SkSL::RP::Generator::returnComplexity\28SkSL::FunctionDefinition\20const*\29 +6372:SkSL::RP::Generator::pushVariableReferencePartial\28SkSL::VariableReference\20const&\2c\20SkSL::RP::SlotRange\29 +6373:SkSL::RP::Generator::pushLengthIntrinsic\28int\29 +6374:SkSL::RP::Generator::pushLValueOrExpression\28SkSL::RP::LValue*\2c\20SkSL::Expression\20const&\29 +6375:SkSL::RP::Generator::pushIntrinsic\28SkSL::RP::BuilderOp\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +6376:SkSL::RP::Generator::pushIntrinsic\28SkSL::IntrinsicKind\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +6377:SkSL::RP::Generator::pushImmutableData\28SkSL::Expression\20const&\29 +6378:SkSL::RP::Generator::getImmutableValueForExpression\28SkSL::Expression\20const&\2c\20skia_private::TArray*\29 +6379:SkSL::RP::Generator::getImmutableBitsForSlot\28SkSL::Expression\20const&\2c\20unsigned\20long\29 +6380:SkSL::RP::Generator::findPreexistingImmutableData\28skia_private::TArray\20const&\29 +6381:SkSL::RP::Generator::discardTraceScopeMask\28\29 +6382:SkSL::RP::Builder::push_condition_mask\28\29 +6383:SkSL::RP::Builder::pop_slots_unmasked\28SkSL::RP::SlotRange\29 +6384:SkSL::RP::Builder::pop_condition_mask\28\29 +6385:SkSL::RP::Builder::pop_and_reenable_loop_mask\28\29 +6386:SkSL::RP::Builder::merge_loop_mask\28\29 +6387:SkSL::RP::Builder::merge_inv_condition_mask\28\29 +6388:SkSL::RP::Builder::mask_off_loop_mask\28\29 +6389:SkSL::RP::Builder::discard_stack\28int\2c\20int\29 +6390:SkSL::RP::Builder::copy_stack_to_slots_unmasked\28SkSL::RP::SlotRange\2c\20int\29 +6391:SkSL::RP::Builder::copy_stack_to_slots_unmasked\28SkSL::RP::SlotRange\29 +6392:SkSL::RP::Builder::copy_stack_to_slots\28SkSL::RP::SlotRange\29 +6393:SkSL::RP::Builder::branch_if_any_lanes_active\28int\29 +6394:SkSL::RP::AutoStack::pushClone\28SkSL::RP::SlotRange\2c\20int\29 +6395:SkSL::RP::AutoContinueMask::~AutoContinueMask\28\29 +6396:SkSL::RP::AutoContinueMask::exitLoopBody\28\29 +6397:SkSL::RP::AutoContinueMask::enterLoopBody\28\29 +6398:SkSL::RP::AutoContinueMask::enable\28\29 +6399:SkSL::ProgramUsage::remove\28SkSL::Expression\20const*\29 +6400:SkSL::ProgramUsage::get\28SkSL::FunctionDeclaration\20const&\29\20const +6401:SkSL::ProgramUsage::add\28SkSL::Statement\20const*\29 +6402:SkSL::ProgramUsage::add\28SkSL::Expression\20const*\29 +6403:SkSL::ProgramConfig::ProgramConfig\28\29 +6404:SkSL::Program::~Program\28\29 +6405:SkSL::PostfixExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\29 +6406:SkSL::PipelineStage::PipelineStageCodeGenerator::functionName\28SkSL::FunctionDeclaration\20const&\2c\20int\29 +6407:SkSL::PipelineStage::PipelineStageCodeGenerator::functionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +6408:SkSL::PipelineStage::PipelineStageCodeGenerator::forEachSpecialization\28SkSL::FunctionDeclaration\20const&\2c\20std::__2::function\20const&\29 +6409:SkSL::Parser::~Parser\28\29 +6410:SkSL::Parser::varDeclarations\28\29 +6411:SkSL::Parser::varDeclarationsPrefix\28SkSL::Parser::VarDeclarationsPrefix*\29 +6412:SkSL::Parser::varDeclarationsOrExpressionStatement\28\29 +6413:SkSL::Parser::switchCaseBody\28SkSL::ExpressionArray*\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>*\2c\20std::__2::unique_ptr>\29 +6414:SkSL::Parser::shiftExpression\28\29 +6415:SkSL::Parser::relationalExpression\28\29 +6416:SkSL::Parser::multiplicativeExpression\28\29 +6417:SkSL::Parser::logicalXorExpression\28\29 +6418:SkSL::Parser::logicalAndExpression\28\29 +6419:SkSL::Parser::localVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +6420:SkSL::Parser::intLiteral\28long\20long*\29 +6421:SkSL::Parser::identifier\28std::__2::basic_string_view>*\29 +6422:SkSL::Parser::globalVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +6423:SkSL::Parser::expressionStatement\28\29 +6424:SkSL::Parser::expectNewline\28\29 +6425:SkSL::Parser::equalityExpression\28\29 +6426:SkSL::Parser::directive\28bool\29 +6427:SkSL::Parser::declarations\28\29 +6428:SkSL::Parser::bitwiseXorExpression\28\29 +6429:SkSL::Parser::bitwiseOrExpression\28\29 +6430:SkSL::Parser::bitwiseAndExpression\28\29 +6431:SkSL::Parser::additiveExpression\28\29 +6432:SkSL::Parser::addGlobalVarDeclaration\28std::__2::unique_ptr>\29 +6433:SkSL::Parser::Parser\28SkSL::Compiler*\2c\20SkSL::ProgramSettings\20const&\2c\20SkSL::ProgramKind\2c\20std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20std::__2::default_delete\2c\20std::__2::allocator>>>\29 +6434:SkSL::MultiArgumentConstructor::argumentSpan\28\29 +6435:SkSL::ModuleLoader::loadSharedModule\28SkSL::Compiler*\29 +6436:SkSL::ModuleLoader::loadPublicModule\28SkSL::Compiler*\29 +6437:SkSL::ModuleLoader::Get\28\29 +6438:SkSL::Module::~Module\28\29 +6439:SkSL::MatrixType::bitWidth\28\29\20const +6440:SkSL::MakeRasterPipelineProgram\28SkSL::Program\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSL::DebugTracePriv*\2c\20bool\29 +6441:SkSL::Layout::operator!=\28SkSL::Layout\20const&\29\20const +6442:SkSL::Layout::description\28\29\20const +6443:SkSL::Intrinsics::\28anonymous\20namespace\29::finalize_distance\28double\29 +6444:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_matrixCompMult\28double\2c\20double\2c\20double\29 +6445:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_length\28std::__2::array\20const&\29 +6446:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_add\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +6447:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29 +6448:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29 +6449:SkSL::Inliner::buildCandidateList\28std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\2c\20SkSL::InlineCandidateList*\29::$_1::operator\28\29\28SkSL::InlineCandidate\20const&\29\20const +6450:SkSL::Inliner::buildCandidateList\28std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\2c\20SkSL::InlineCandidateList*\29::$_0::operator\28\29\28SkSL::InlineCandidate\20const&\29\20const +6451:SkSL::Inliner::InlinedCall::~InlinedCall\28\29 +6452:SkSL::IndexExpression::~IndexExpression\28\29 +6453:SkSL::IfStatement::~IfStatement\28\29 +6454:SkSL::IRHelpers::Ref\28SkSL::Variable\20const*\29\20const +6455:SkSL::IRHelpers::Mul\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29\20const +6456:SkSL::IRHelpers::Assign\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29\20const +6457:SkSL::GLSLCodeGenerator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\2c\20bool\29 +6458:SkSL::GLSLCodeGenerator::writeProgramElement\28SkSL::ProgramElement\20const&\29 +6459:SkSL::GLSLCodeGenerator::writeMinAbsHack\28SkSL::Expression&\2c\20SkSL::Expression&\29 +6460:SkSL::GLSLCodeGenerator::generateCode\28\29 +6461:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::visitStatementPtr\28std::__2::unique_ptr>&\29 +6462:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::addLocalVariable\28SkSL::Variable\20const*\2c\20SkSL::Position\29 +6463:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29_6544 +6464:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29 +6465:SkSL::FunctionDeclaration::mangledName\28\29\20const +6466:SkSL::FunctionDeclaration::getMainInputColorParameter\28\29\20const +6467:SkSL::FunctionDeclaration::getMainDestColorParameter\28\29\20const +6468:SkSL::FunctionDeclaration::determineFinalTypes\28SkSL::ExpressionArray\20const&\2c\20skia_private::STArray<8\2c\20SkSL::Type\20const*\2c\20true>*\2c\20SkSL::Type\20const**\29\20const +6469:SkSL::FunctionDeclaration::FunctionDeclaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20SkSL::Type\20const*\2c\20SkSL::IntrinsicKind\29 +6470:SkSL::FunctionCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +6471:SkSL::FunctionCall::FunctionCall\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration\20const*\2c\20SkSL::ExpressionArray\2c\20SkSL::FunctionCall\20const*\29 +6472:SkSL::FunctionCall::FindBestFunctionForCall\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const*\2c\20SkSL::ExpressionArray\20const&\29 +6473:SkSL::FunctionCall::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +6474:SkSL::ForStatement::~ForStatement\28\29 +6475:SkSL::ForStatement::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6476:SkSL::FindIntrinsicKind\28std::__2::basic_string_view>\29 +6477:SkSL::FieldAccess::~FieldAccess\28\29_6421 +6478:SkSL::FieldAccess::~FieldAccess\28\29 +6479:SkSL::FieldAccess::description\28SkSL::OperatorPrecedence\29\20const +6480:SkSL::FieldAccess::FieldAccess\28SkSL::Position\2c\20std::__2::unique_ptr>\2c\20int\2c\20SkSL::FieldAccessOwnerKind\29 +6481:SkSL::ExtendedVariable::~ExtendedVariable\28\29 +6482:SkSL::Expression::isFloatLiteral\28\29\20const +6483:SkSL::Expression::coercionCost\28SkSL::Type\20const&\29\20const +6484:SkSL::DoStatement::~DoStatement\28\29_6410 +6485:SkSL::DoStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6486:SkSL::DiscardStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\29 +6487:SkSL::ContinueStatement::Make\28SkSL::Position\29 +6488:SkSL::ConstructorStruct::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +6489:SkSL::ConstructorScalarCast::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +6490:SkSL::ConstructorMatrixResize::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +6491:SkSL::Constructor::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +6492:SkSL::Compiler::resetErrors\28\29 +6493:SkSL::Compiler::initializeContext\28SkSL::Module\20const*\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\2c\20std::__2::basic_string_view>\2c\20SkSL::ModuleType\29 +6494:SkSL::Compiler::cleanupContext\28\29 +6495:SkSL::CoercionCost::operator<\28SkSL::CoercionCost\29\20const +6496:SkSL::ChildCall::~ChildCall\28\29_6349 +6497:SkSL::ChildCall::~ChildCall\28\29 +6498:SkSL::ChildCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Variable\20const&\2c\20SkSL::ExpressionArray\29 +6499:SkSL::ChildCall::ChildCall\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Variable\20const*\2c\20SkSL::ExpressionArray\29 +6500:SkSL::BreakStatement::Make\28SkSL::Position\29 +6501:SkSL::Block::Block\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +6502:SkSL::BinaryExpression::isAssignmentIntoVariable\28\29 +6503:SkSL::ArrayType::columns\28\29\20const +6504:SkSL::Analysis::\28anonymous\20namespace\29::LoopControlFlowVisitor::visitStatement\28SkSL::Statement\20const&\29 +6505:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29::IsDynamicallyUniformExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +6506:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29 +6507:SkSL::Analysis::IsConstantExpression\28SkSL::Expression\20const&\29 +6508:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29::IsCompileTimeConstantVisitor::visitExpression\28SkSL::Expression\20const&\29 +6509:SkSL::Analysis::IsAssignable\28SkSL::Expression&\2c\20SkSL::Analysis::AssignmentInfo*\2c\20SkSL::ErrorReporter*\29 +6510:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29::HasSideEffectsVisitor::visitExpression\28SkSL::Expression\20const&\29 +6511:SkSL::Analysis::GetLoopUnrollInfo\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\20const&\2c\20SkSL::Statement\20const*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Expression\20const*\2c\20SkSL::Statement\20const*\2c\20SkSL::ErrorReporter*\29 +6512:SkSL::Analysis::GetLoopControlFlowInfo\28SkSL::Statement\20const&\29 +6513:SkSL::Analysis::ContainsVariable\28SkSL::Expression\20const&\2c\20SkSL::Variable\20const&\29::ContainsVariableVisitor::visitExpression\28SkSL::Expression\20const&\29 +6514:SkSL::Analysis::ContainsRTAdjust\28SkSL::Expression\20const&\29::ContainsRTAdjustVisitor::visitExpression\28SkSL::Expression\20const&\29 +6515:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +6516:SkSL::AliasType::numberKind\28\29\20const +6517:SkSL::AliasType::isOrContainsBool\28\29\20const +6518:SkSL::AliasType::isOrContainsAtomic\28\29\20const +6519:SkSL::AliasType::isAllowedInES2\28\29\20const +6520:SkSBlockAllocator<80ul>::SkSBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\29 +6521:SkRuntimeShader::~SkRuntimeShader\28\29 +6522:SkRuntimeEffectPriv::VarAsChild\28SkSL::Variable\20const&\2c\20int\29 +6523:SkRuntimeEffect::~SkRuntimeEffect\28\29 +6524:SkRuntimeEffect::getRPProgram\28SkSL::DebugTracePriv*\29\20const +6525:SkRuntimeEffect::MakeForShader\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +6526:SkRuntimeEffect::ChildPtr::type\28\29\20const +6527:SkRuntimeEffect::ChildPtr::shader\28\29\20const +6528:SkRuntimeEffect::ChildPtr::colorFilter\28\29\20const +6529:SkRuntimeEffect::ChildPtr::blender\28\29\20const +6530:SkRgnBuilder::collapseWithPrev\28\29 +6531:SkResourceCache::release\28SkResourceCache::Rec*\29 +6532:SkResourceCache::PostPurgeSharedID\28unsigned\20long\20long\29 +6533:SkResourceCache::NewCachedData\28unsigned\20long\29 +6534:SkResourceCache::GetDiscardableFactory\28\29 +6535:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29 +6536:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +6537:SkRegion::quickReject\28SkIRect\20const&\29\20const +6538:SkRegion::quickContains\28SkIRect\20const&\29\20const +6539:SkRegion::op\28SkIRect\20const&\2c\20SkRegion::Op\29 +6540:SkRegion::getRuns\28int*\2c\20int*\29\20const +6541:SkRegion::Spanerator::Spanerator\28SkRegion\20const&\2c\20int\2c\20int\2c\20int\29 +6542:SkRegion::RunHead::ensureWritable\28\29 +6543:SkRegion::RunHead::computeRunBounds\28SkIRect*\29 +6544:SkRegion::RunHead::Alloc\28int\2c\20int\2c\20int\29 +6545:SkRegion::Oper\28SkRegion\20const&\2c\20SkRegion\20const&\2c\20SkRegion::Op\2c\20SkRegion*\29 +6546:SkRefCntBase::internal_dispose\28\29\20const +6547:SkReduceOrder::Conic\28SkConic\20const&\2c\20SkPoint*\29 +6548:SkRectPriv::Subtract\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkIRect*\29 +6549:SkRectPriv::QuadContainsRect\28SkM44\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20float\29 +6550:SkRectPriv::QuadContainsRectMask\28SkM44\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20float\29 +6551:SkRectPriv::FitsInFixed\28SkRect\20const&\29 +6552:SkRectClipBlitter::requestRowsPreserved\28\29\20const +6553:SkRectClipBlitter::allocBlitMemory\28unsigned\20long\29 +6554:SkRect::roundOut\28SkRect*\29\20const +6555:SkRect::roundIn\28\29\20const +6556:SkRect::roundIn\28SkIRect*\29\20const +6557:SkRect::makeOffset\28float\2c\20float\29\20const +6558:SkRect::joinNonEmptyArg\28SkRect\20const&\29 +6559:SkRect::intersect\28SkRect\20const&\2c\20SkRect\20const&\29 +6560:SkRect::contains\28float\2c\20float\29\20const +6561:SkRect::contains\28SkIRect\20const&\29\20const +6562:SkRect*\20SkRecord::alloc\28unsigned\20long\29 +6563:SkRecords::FillBounds::popSaveBlock\28\29 +6564:SkRecords::FillBounds::popControl\28SkRect\20const&\29 +6565:SkRecords::FillBounds::AdjustForPaint\28SkPaint\20const*\2c\20SkRect*\29 +6566:SkRecorder::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6567:SkRecordedDrawable::~SkRecordedDrawable\28\29 +6568:SkRecordOptimize\28SkRecord*\29 +6569:SkRecordFillBounds\28SkRect\20const&\2c\20SkRecord\20const&\2c\20SkRect*\2c\20SkBBoxHierarchy::Metadata*\29 +6570:SkRecord::~SkRecord\28\29 +6571:SkReadBuffer::skipByteArray\28unsigned\20long*\29 +6572:SkReadBuffer::readPad32\28void*\2c\20unsigned\20long\29 +6573:SkReadBuffer::SkReadBuffer\28void\20const*\2c\20unsigned\20long\29 +6574:SkRasterPipeline_UniformColorCtx*\20SkArenaAlloc::make\28\29 +6575:SkRasterPipeline_TileCtx*\20SkArenaAlloc::make\28\29 +6576:SkRasterPipeline_RewindCtx*\20SkArenaAlloc::make\28\29 +6577:SkRasterPipeline_DecalTileCtx*\20SkArenaAlloc::make\28\29 +6578:SkRasterPipeline_CopyIndirectCtx*\20SkArenaAlloc::make\28\29 +6579:SkRasterPipeline_2PtConicalCtx*\20SkArenaAlloc::make\28\29 +6580:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29 +6581:SkRasterPipeline::buildPipeline\28SkRasterPipelineStage*\29\20const +6582:SkRasterPipeline::appendSetRGB\28SkArenaAlloc*\2c\20float\20const*\29 +6583:SkRasterPipeline::appendLoad\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +6584:SkRasterClipStack::Rec::Rec\28SkRasterClip\20const&\29 +6585:SkRasterClip::setEmpty\28\29 +6586:SkRasterClip::computeIsRect\28\29\20const +6587:SkRandom::nextULessThan\28unsigned\20int\29 +6588:SkRTreeFactory::operator\28\29\28\29\20const +6589:SkRTree::~SkRTree\28\29 +6590:SkRTree::search\28SkRTree::Node*\2c\20SkRect\20const&\2c\20std::__2::vector>*\29\20const +6591:SkRTree::bulkLoad\28std::__2::vector>*\2c\20int\29 +6592:SkRTree::allocateNodeAtLevel\28unsigned\20short\29 +6593:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29::$_2::operator\28\29\28SkRRect::Corner\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29\20const +6594:SkRRect::setRectXY\28SkRect\20const&\2c\20float\2c\20float\29 +6595:SkRRect::isValid\28\29\20const +6596:SkRRect::computeType\28\29 +6597:SkRGBA4f<\28SkAlphaType\292>\20skgpu::Swizzle::applyTo<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\29\20const +6598:SkRGBA4f<\28SkAlphaType\292>::unpremul\28\29\20const +6599:SkQuads::Roots\28double\2c\20double\2c\20double\29 +6600:SkQuadraticEdge::setQuadraticWithoutUpdate\28SkPoint\20const*\2c\20int\29 +6601:SkQuadConstruct::init\28float\2c\20float\29 +6602:SkPtrSet::add\28void*\29 +6603:SkPoint::Normalize\28SkPoint*\29 +6604:SkPixmap::readPixels\28SkPixmap\20const&\29\20const +6605:SkPixmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +6606:SkPixmap::erase\28unsigned\20int\29\20const +6607:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const +6608:SkPixelRef::callGenIDChangeListeners\28\29 +6609:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20sk_sp\29 +6610:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20SkBBHFactory*\29 +6611:SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel\28unsigned\20int\29 +6612:SkPictureRecord::endRecording\28\29 +6613:SkPictureRecord::beginRecording\28\29 +6614:SkPictureRecord::addPath\28SkPath\20const&\29 +6615:SkPictureRecord::addPathToHeap\28SkPath\20const&\29 +6616:SkPictureRecord::SkPictureRecord\28SkIRect\20const&\2c\20unsigned\20int\29 +6617:SkPictureImageGenerator::~SkPictureImageGenerator\28\29 +6618:SkPictureData::~SkPictureData\28\29 +6619:SkPictureData::flatten\28SkWriteBuffer&\29\20const +6620:SkPictureData::SkPictureData\28SkPictureRecord\20const&\2c\20SkPictInfo\20const&\29 +6621:SkPicture::SkPicture\28\29 +6622:SkPathWriter::moveTo\28\29 +6623:SkPathWriter::init\28\29 +6624:SkPathWriter::assemble\28\29 +6625:SkPathStroker::setQuadEndNormal\28SkPoint\20const*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\29 +6626:SkPathStroker::cubicQuadEnds\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +6627:SkPathRef::resetToSize\28int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +6628:SkPathRef::isRRect\28SkRRect*\2c\20bool*\2c\20unsigned\20int*\29\20const +6629:SkPathRef::isOval\28SkRect*\2c\20bool*\2c\20unsigned\20int*\29\20const +6630:SkPathRef::commonReset\28\29 +6631:SkPathRef::Iter::next\28SkPoint*\29 +6632:SkPathRef::CreateEmpty\28\29 +6633:SkPathPriv::LeadingMoveToCount\28SkPath\20const&\29 +6634:SkPathPriv::IsRRect\28SkPath\20const&\2c\20SkRRect*\2c\20SkPathDirection*\2c\20unsigned\20int*\29 +6635:SkPathPriv::IsOval\28SkPath\20const&\2c\20SkRect*\2c\20SkPathDirection*\2c\20unsigned\20int*\29 +6636:SkPathPriv::IsNestedFillRects\28SkPath\20const&\2c\20SkRect*\2c\20SkPathDirection*\29 +6637:SkPathPriv::CreateDrawArcPath\28SkPath*\2c\20SkArc\20const&\2c\20bool\29 +6638:SkPathOpsBounds::Intersects\28SkPathOpsBounds\20const&\2c\20SkPathOpsBounds\20const&\29 +6639:SkPathMeasure::~SkPathMeasure\28\29 +6640:SkPathMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29 +6641:SkPathMeasure::SkPathMeasure\28SkPath\20const&\2c\20bool\2c\20float\29 +6642:SkPathEffectBase::getFlattenableType\28\29\20const +6643:SkPathEffectBase::PointData::~PointData\28\29 +6644:SkPathEdgeIter::next\28\29::'lambda'\28\29::operator\28\29\28\29\20const +6645:SkPathBuilder::reset\28\29 +6646:SkPathBuilder::lineTo\28float\2c\20float\29 +6647:SkPathBuilder::addRect\28SkRect\20const&\2c\20SkPathDirection\29 +6648:SkPathBuilder::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +6649:SkPath::writeToMemory\28void*\29\20const +6650:SkPath::reverseAddPath\28SkPath\20const&\29 +6651:SkPath::offset\28float\2c\20float\29 +6652:SkPath::makeTransform\28SkMatrix\20const&\2c\20SkApplyPerspectiveClip\29\20const +6653:SkPath::isZeroLengthSincePoint\28int\29\20const +6654:SkPath::isRRect\28SkRRect*\29\20const +6655:SkPath::isOval\28SkRect*\29\20const +6656:SkPath::copyFields\28SkPath\20const&\29 +6657:SkPath::conservativelyContainsRect\28SkRect\20const&\29\20const +6658:SkPath::arcTo\28float\2c\20float\2c\20float\2c\20SkPath::ArcSize\2c\20SkPathDirection\2c\20float\2c\20float\29 +6659:SkPath::addRect\28float\2c\20float\2c\20float\2c\20float\2c\20SkPathDirection\29 +6660:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +6661:SkPath::addCircle\28float\2c\20float\2c\20float\2c\20SkPathDirection\29 +6662:SkPath::Polygon\28std::initializer_list\20const&\2c\20bool\2c\20SkPathFillType\2c\20bool\29 +6663:SkPaintToGrPaintWithBlend\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +6664:SkPaintPriv::ShouldDither\28SkPaint\20const&\2c\20SkColorType\29 +6665:SkOpSpanBase::merge\28SkOpSpan*\29 +6666:SkOpSpanBase::initBase\28SkOpSegment*\2c\20SkOpSpan*\2c\20double\2c\20SkPoint\20const&\29 +6667:SkOpSpan::sortableTop\28SkOpContour*\29 +6668:SkOpSpan::setOppSum\28int\29 +6669:SkOpSpan::insertCoincidence\28SkOpSpan*\29 +6670:SkOpSpan::insertCoincidence\28SkOpSegment\20const*\2c\20bool\2c\20bool\29 +6671:SkOpSpan::init\28SkOpSegment*\2c\20SkOpSpan*\2c\20double\2c\20SkPoint\20const&\29 +6672:SkOpSpan::containsCoincidence\28SkOpSegment\20const*\29\20const +6673:SkOpSpan::computeWindSum\28\29 +6674:SkOpSegment::updateOppWindingReverse\28SkOpAngle\20const*\29\20const +6675:SkOpSegment::ptsDisjoint\28double\2c\20SkPoint\20const&\2c\20double\2c\20SkPoint\20const&\29\20const +6676:SkOpSegment::markWinding\28SkOpSpan*\2c\20int\29 +6677:SkOpSegment::isClose\28double\2c\20SkOpSegment\20const*\29\20const +6678:SkOpSegment::computeSum\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpAngle::IncludeType\29 +6679:SkOpSegment::collapsed\28double\2c\20double\29\20const +6680:SkOpSegment::addExpanded\28double\2c\20SkOpSpanBase\20const*\2c\20bool*\29 +6681:SkOpSegment::activeWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\29 +6682:SkOpSegment::activeOp\28int\2c\20int\2c\20SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkPathOp\2c\20int*\2c\20int*\29 +6683:SkOpSegment::activeAngle\28SkOpSpanBase*\2c\20SkOpSpanBase**\2c\20SkOpSpanBase**\2c\20bool*\29 +6684:SkOpSegment::activeAngleInner\28SkOpSpanBase*\2c\20SkOpSpanBase**\2c\20SkOpSpanBase**\2c\20bool*\29 +6685:SkOpPtT::ptAlreadySeen\28SkOpPtT\20const*\29\20const +6686:SkOpEdgeBuilder::~SkOpEdgeBuilder\28\29 +6687:SkOpEdgeBuilder::preFetch\28\29 +6688:SkOpEdgeBuilder::finish\28\29 +6689:SkOpEdgeBuilder::SkOpEdgeBuilder\28SkPath\20const&\2c\20SkOpContourHead*\2c\20SkOpGlobalState*\29 +6690:SkOpContourBuilder::addQuad\28SkPoint*\29 +6691:SkOpContourBuilder::addLine\28SkPoint\20const*\29 +6692:SkOpContourBuilder::addCubic\28SkPoint*\29 +6693:SkOpContourBuilder::addConic\28SkPoint*\2c\20float\29 +6694:SkOpCoincidence::restoreHead\28\29 +6695:SkOpCoincidence::releaseDeleted\28SkCoincidentSpans*\29 +6696:SkOpCoincidence::mark\28\29 +6697:SkOpCoincidence::markCollapsed\28SkCoincidentSpans*\2c\20SkOpPtT*\29 +6698:SkOpCoincidence::fixUp\28SkCoincidentSpans*\2c\20SkOpPtT*\2c\20SkOpPtT\20const*\29 +6699:SkOpCoincidence::contains\28SkCoincidentSpans\20const*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\29\20const +6700:SkOpCoincidence::checkOverlap\28SkCoincidentSpans*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20SkTDArray*\29\20const +6701:SkOpCoincidence::addOrOverlap\28SkOpSegment*\2c\20SkOpSegment*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20bool*\29 +6702:SkOpCoincidence::addMissing\28bool*\29 +6703:SkOpCoincidence::addEndMovedSpans\28SkOpSpan\20const*\2c\20SkOpSpanBase\20const*\29 +6704:SkOpAngle::tangentsDiverge\28SkOpAngle\20const*\2c\20double\29 +6705:SkOpAngle::setSpans\28\29 +6706:SkOpAngle::setSector\28\29 +6707:SkOpAngle::previous\28\29\20const +6708:SkOpAngle::midToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +6709:SkOpAngle::merge\28SkOpAngle*\29 +6710:SkOpAngle::loopContains\28SkOpAngle\20const*\29\20const +6711:SkOpAngle::lineOnOneSide\28SkOpAngle\20const*\2c\20bool\29 +6712:SkOpAngle::findSector\28SkPath::Verb\2c\20double\2c\20double\29\20const +6713:SkOpAngle::endToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +6714:SkOpAngle::checkCrossesZero\28\29\20const +6715:SkOpAngle::alignmentSameSide\28SkOpAngle\20const*\2c\20int*\29\20const +6716:SkOpAngle::after\28SkOpAngle*\29 +6717:SkOffsetSimplePolygon\28SkPoint\20const*\2c\20int\2c\20SkRect\20const&\2c\20float\2c\20SkTDArray*\2c\20SkTDArray*\29 +6718:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29 +6719:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29 +6720:SkNullBlitter*\20SkArenaAlloc::make\28\29 +6721:SkNotifyBitmapGenIDIsStale\28unsigned\20int\29 +6722:SkNoPixelsDevice::~SkNoPixelsDevice\28\29 +6723:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\29 +6724:SkNoDestructor::SkNoDestructor\2c\20sk_sp>\28sk_sp&&\2c\20sk_sp&&\29 +6725:SkNVRefCnt::unref\28\29\20const +6726:SkNVRefCnt::unref\28\29\20const +6727:SkNVRefCnt::unref\28\29\20const +6728:SkNVRefCnt::unref\28\29\20const +6729:SkNVRefCnt::unref\28\29\20const +6730:SkMipmapAccessor::SkMipmapAccessor\28SkImage_Base\20const*\2c\20SkMatrix\20const&\2c\20SkMipmapMode\29::$_1::operator\28\29\28SkPixmap\20const&\29\20const +6731:SkMipmap::~SkMipmap\28\29 +6732:SkMessageBus::Get\28\29 +6733:SkMessageBus::Get\28\29 +6734:SkMeshSpecification::Attribute::Attribute\28SkMeshSpecification::Attribute\20const&\29 +6735:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +6736:SkMeshPriv::CpuBuffer::size\28\29\20const +6737:SkMeshPriv::CpuBuffer::peek\28\29\20const +6738:SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +6739:SkMemoryStream::~SkMemoryStream\28\29 +6740:SkMemoryStream::SkMemoryStream\28sk_sp\29 +6741:SkMatrixPriv::MapPointsWithStride\28SkMatrix\20const&\2c\20SkPoint*\2c\20unsigned\20long\2c\20int\29 +6742:SkMatrix::updateTranslateMask\28\29 +6743:SkMatrix::setTranslate\28float\2c\20float\29 +6744:SkMatrix::setScale\28float\2c\20float\29 +6745:SkMatrix::postSkew\28float\2c\20float\29 +6746:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint3\20const*\2c\20int\29\20const +6747:SkMatrix::getMinScale\28\29\20const +6748:SkMatrix::computeTypeMask\28\29\20const +6749:SkMatrix::Rot_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +6750:SkMatrix*\20SkRecord::alloc\28unsigned\20long\29 +6751:SkMaskFilterBase::NinePatch::~NinePatch\28\29 +6752:SkMask*\20SkTLazy::init\28unsigned\20char\20const*&&\2c\20SkIRect\20const&\2c\20unsigned\20int\20const&\2c\20SkMask::Format\20const&\29 +6753:SkMask*\20SkTLazy::init\28SkMaskBuilder&\29 +6754:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29 +6755:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29 +6756:SkMakeBitmapShaderForPaint\28SkPaint\20const&\2c\20SkBitmap\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20SkCopyPixelsMode\29 +6757:SkM44::preTranslate\28float\2c\20float\2c\20float\29 +6758:SkM44::postTranslate\28float\2c\20float\2c\20float\29 +6759:SkLinearColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +6760:SkLineParameters::normalize\28\29 +6761:SkLineParameters::cubicEndPoints\28SkDCubic\20const&\29 +6762:SkLineClipper::ClipLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\2c\20bool\29 +6763:SkLatticeIter::~SkLatticeIter\28\29 +6764:SkLatticeIter::next\28SkIRect*\2c\20SkRect*\2c\20bool*\2c\20unsigned\20int*\29 +6765:SkLatticeIter::SkLatticeIter\28SkCanvas::Lattice\20const&\2c\20SkRect\20const&\29 +6766:SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::find\28skia::textlayout::ParagraphCacheKey\20const&\29 +6767:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::insert\28GrProgramDesc\20const&\2c\20std::__2::unique_ptr>\29 +6768:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::find\28GrProgramDesc\20const&\29 +6769:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_matrix_conv_effect\28SkKnownRuntimeEffects::\28anonymous\20namespace\29::MatrixConvolutionImpl\2c\20SkRuntimeEffect::Options\20const&\29::$_0::operator\28\29\28int\2c\20SkRuntimeEffect::Options\20const&\29\20const +6770:SkIsSimplePolygon\28SkPoint\20const*\2c\20int\29 +6771:SkIsConvexPolygon\28SkPoint\20const*\2c\20int\29 +6772:SkInvert4x4Matrix\28float\20const*\2c\20float*\29 +6773:SkInvert3x3Matrix\28float\20const*\2c\20float*\29 +6774:SkIntersections::quadVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6775:SkIntersections::quadLine\28SkPoint\20const*\2c\20SkPoint\20const*\29 +6776:SkIntersections::quadHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6777:SkIntersections::mostOutside\28double\2c\20double\2c\20SkDPoint\20const&\29\20const +6778:SkIntersections::lineVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6779:SkIntersections::lineHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6780:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDQuad\20const&\29 +6781:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDConic\20const&\29 +6782:SkIntersections::intersect\28SkDConic\20const&\2c\20SkDQuad\20const&\29 +6783:SkIntersections::insertCoincident\28double\2c\20double\2c\20SkDPoint\20const&\29 +6784:SkIntersections::cubicVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6785:SkIntersections::cubicLine\28SkPoint\20const*\2c\20SkPoint\20const*\29 +6786:SkIntersections::cubicHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6787:SkIntersections::conicVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6788:SkIntersections::conicLine\28SkPoint\20const*\2c\20float\2c\20SkPoint\20const*\29 +6789:SkIntersections::conicHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6790:SkImages::RasterFromPixmap\28SkPixmap\20const&\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +6791:SkImages::RasterFromData\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\29 +6792:SkImage_Raster::~SkImage_Raster\28\29 +6793:SkImage_Raster::onPeekBitmap\28\29\20const +6794:SkImage_Raster::SkImage_Raster\28SkBitmap\20const&\2c\20bool\29 +6795:SkImage_Picture::Make\28sk_sp\2c\20SkISize\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\2c\20SkImages::BitDepth\2c\20sk_sp\2c\20SkSurfaceProps\29 +6796:SkImage_Lazy::~SkImage_Lazy\28\29 +6797:SkImage_Lazy::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +6798:SkImage_GaneshBase::~SkImage_GaneshBase\28\29 +6799:SkImage_GaneshBase::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +6800:SkImage_GaneshBase::SkImage_GaneshBase\28sk_sp\2c\20SkImageInfo\2c\20unsigned\20int\29 +6801:SkImage_Base::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +6802:SkImage_Base::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +6803:SkImageShader::~SkImageShader\28\29 +6804:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_3::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +6805:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_1::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +6806:SkImageInfoValidConversion\28SkImageInfo\20const&\2c\20SkImageInfo\20const&\29 +6807:SkImageGenerator::SkImageGenerator\28SkImageInfo\20const&\2c\20unsigned\20int\29 +6808:SkImageFilters::Crop\28SkRect\20const&\2c\20sk_sp\29 +6809:SkImageFilters::Blur\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +6810:SkImageFilter_Base::getInputBounds\28skif::Mapping\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\29\20const +6811:SkImageFilter_Base::getCTMCapability\28\29\20const +6812:SkImageFilterCache::Get\28SkImageFilterCache::CreateIfNecessary\29 +6813:SkImageFilterCache::Create\28unsigned\20long\29 +6814:SkImage::~SkImage\28\29 +6815:SkGradientShader::MakeTwoPointConical\28SkPoint\20const&\2c\20float\2c\20SkPoint\20const&\2c\20float\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6816:SkGradientShader::MakeTwoPointConical\28SkPoint\20const&\2c\20float\2c\20SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +6817:SkGradientShader::MakeSweep\28float\2c\20float\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6818:SkGradientShader::MakeRadial\28SkPoint\20const&\2c\20float\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6819:SkGradientShader::MakeLinear\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6820:SkGradientShader::MakeLinear\28SkPoint\20const*\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +6821:SkGradientBaseShader::~SkGradientBaseShader\28\29 +6822:SkGradientBaseShader::getPos\28int\29\20const +6823:SkGradientBaseShader::AppendGradientFillStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const*\2c\20float\20const*\2c\20int\29 +6824:SkGlyph::mask\28SkPoint\29\20const +6825:SkGlyph::ensureIntercepts\28float\20const*\2c\20float\2c\20float\2c\20float*\2c\20int*\2c\20SkArenaAlloc*\29::$_1::operator\28\29\28SkGlyph::Intercept\20const*\2c\20float*\2c\20int*\29\20const +6826:SkGenerateDistanceFieldFromA8Image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20unsigned\20long\29 +6827:SkGaussFilter::SkGaussFilter\28double\29 +6828:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29 +6829:SkFontStyleSet::CreateEmpty\28\29 +6830:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29 +6831:SkFontScanner_FreeType::scanInstance\28SkStreamAsset*\2c\20int\2c\20int\2c\20SkString*\2c\20SkFontStyle*\2c\20bool*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\2c\20skia_private::STArray<4\2c\20SkFontArguments::VariationPosition::Coordinate\2c\20true>*\29\20const +6832:SkFontScanner_FreeType::computeAxisValues\28skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>\20const&\2c\20SkFontArguments::VariationPosition\2c\20SkFontArguments::VariationPosition\2c\20int*\2c\20SkString\20const&\2c\20SkFontStyle*\29 +6833:SkFontScanner_FreeType::SkFontScanner_FreeType\28\29 +6834:SkFontPriv::MakeTextMatrix\28float\2c\20float\2c\20float\29 +6835:SkFontPriv::GetFontBounds\28SkFont\20const&\29 +6836:SkFontMgr_Custom::~SkFontMgr_Custom\28\29 +6837:SkFontMgr_Custom::onMakeFromStreamArgs\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29\20const +6838:SkFontDescriptor::SkFontStyleWidthForWidthAxisValue\28float\29 +6839:SkFontData::~SkFontData\28\29 +6840:SkFontData::SkFontData\28std::__2::unique_ptr>\2c\20int\2c\20int\2c\20int\20const*\2c\20int\2c\20SkFontArguments::Palette::Override\20const*\2c\20int\29 +6841:SkFont::operator==\28SkFont\20const&\29\20const +6842:SkFont::getWidths\28unsigned\20short\20const*\2c\20int\2c\20float*\29\20const +6843:SkFont::getPaths\28unsigned\20short\20const*\2c\20int\2c\20void\20\28*\29\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29\2c\20void*\29\20const +6844:SkFindCubicInflections\28SkPoint\20const*\2c\20float*\29 +6845:SkFindCubicExtrema\28float\2c\20float\2c\20float\2c\20float\2c\20float*\29 +6846:SkFindBisector\28SkPoint\2c\20SkPoint\29 +6847:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda0'\28\29::operator\28\29\28\29\20const +6848:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda'\28\29::operator\28\29\28\29\20const +6849:SkFILEStream::~SkFILEStream\28\29 +6850:SkEvalQuadTangentAt\28SkPoint\20const*\2c\20float\29 +6851:SkEvalQuadAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +6852:SkEdgeClipper::next\28SkPoint*\29 +6853:SkEdgeClipper::clipQuad\28SkPoint\20const*\2c\20SkRect\20const&\29 +6854:SkEdgeClipper::clipLine\28SkPoint\2c\20SkPoint\2c\20SkRect\20const&\29 +6855:SkEdgeClipper::appendCubic\28SkPoint\20const*\2c\20bool\29 +6856:SkEdgeClipper::ClipPath\28SkPath\20const&\2c\20SkRect\20const&\2c\20bool\2c\20void\20\28*\29\28SkEdgeClipper*\2c\20bool\2c\20void*\29\2c\20void*\29 +6857:SkEdgeBuilder::build\28SkPath\20const&\2c\20SkIRect\20const*\2c\20bool\29::$_1::operator\28\29\28SkPoint\20const*\29\20const +6858:SkEdgeBuilder::buildEdges\28SkPath\20const&\2c\20SkIRect\20const*\29 +6859:SkEdgeBuilder::SkEdgeBuilder\28\29 +6860:SkEdge::updateLine\28int\2c\20int\2c\20int\2c\20int\29 +6861:SkEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20int\29 +6862:SkDynamicMemoryWStream::reset\28\29 +6863:SkDynamicMemoryWStream::Block::append\28void\20const*\2c\20unsigned\20long\29 +6864:SkDrawableList::newDrawableSnapshot\28\29 +6865:SkDrawTreatAsHairline\28SkPaint\20const&\2c\20SkMatrix\20const&\2c\20float*\29 +6866:SkDrawShadowMetrics::GetSpotShadowTransform\28SkPoint3\20const&\2c\20float\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkRect\20const&\2c\20bool\2c\20SkMatrix*\2c\20float*\29 +6867:SkDrawBase::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20SkRect\20const*\29\20const +6868:SkDrawBase::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20bool\2c\20bool\2c\20SkBlitter*\29\20const +6869:SkDrawBase::drawPaint\28SkPaint\20const&\29\20const +6870:SkDrawBase::SkDrawBase\28SkDrawBase\20const&\29 +6871:SkDrawBase::DrawToMask\28SkPath\20const&\2c\20SkIRect\20const&\2c\20SkMaskFilter\20const*\2c\20SkMatrix\20const*\2c\20SkMaskBuilder*\2c\20SkMaskBuilder::CreateMode\2c\20SkStrokeRec::InitStyle\29 +6872:SkDraw::drawSprite\28SkBitmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29\20const +6873:SkDraw::drawBitmap\28SkBitmap\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29\20const +6874:SkDraw::SkDraw\28SkDraw\20const&\29 +6875:SkDevice::setOrigin\28SkM44\20const&\2c\20int\2c\20int\29 +6876:SkDevice::setDeviceCoordinateSystem\28SkM44\20const&\2c\20SkM44\20const&\2c\20SkM44\20const&\2c\20int\2c\20int\29 +6877:SkDevice::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +6878:SkDevice::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +6879:SkDevice::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +6880:SkDescriptor::addEntry\28unsigned\20int\2c\20unsigned\20long\2c\20void\20const*\29 +6881:SkDeque::push_back\28\29 +6882:SkDeque::allocateBlock\28int\29 +6883:SkDeque::Iter::Iter\28SkDeque\20const&\2c\20SkDeque::Iter::IterStart\29 +6884:SkDashPathEffect::Make\28float\20const*\2c\20int\2c\20float\29 +6885:SkDashPath::InternalFilter\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20float\20const*\2c\20int\2c\20float\2c\20int\2c\20float\2c\20float\2c\20SkDashPath::StrokeRecApplication\29 +6886:SkDashPath::CalcDashParameters\28float\2c\20float\20const*\2c\20int\2c\20float*\2c\20int*\2c\20float*\2c\20float*\29 +6887:SkDashImpl::~SkDashImpl\28\29 +6888:SkDRect::setBounds\28SkDQuad\20const&\2c\20SkDQuad\20const&\2c\20double\2c\20double\29 +6889:SkDRect::setBounds\28SkDCubic\20const&\2c\20SkDCubic\20const&\2c\20double\2c\20double\29 +6890:SkDRect::setBounds\28SkDConic\20const&\2c\20SkDConic\20const&\2c\20double\2c\20double\29 +6891:SkDQuad::subDivide\28double\2c\20double\29\20const +6892:SkDQuad::otherPts\28int\2c\20SkDPoint\20const**\29\20const +6893:SkDQuad::isLinear\28int\2c\20int\29\20const +6894:SkDQuad::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +6895:SkDQuad::AddValidTs\28double*\2c\20int\2c\20double*\29 +6896:SkDPoint::roughlyEqual\28SkDPoint\20const&\29\20const +6897:SkDPoint::approximatelyDEqual\28SkDPoint\20const&\29\20const +6898:SkDCurveSweep::setCurveHullSweep\28SkPath::Verb\29 +6899:SkDCubic::monotonicInY\28\29\20const +6900:SkDCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +6901:SkDCubic::hullIntersects\28SkDPoint\20const*\2c\20int\2c\20bool*\29\20const +6902:SkDCubic::Coefficients\28double\20const*\2c\20double*\2c\20double*\2c\20double*\2c\20double*\29 +6903:SkDConic::subDivide\28double\2c\20double\29\20const +6904:SkCubics::RootsReal\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +6905:SkCubicEdge::setCubicWithoutUpdate\28SkPoint\20const*\2c\20int\2c\20bool\29 +6906:SkCubicClipper::ChopMonoAtY\28SkPoint\20const*\2c\20float\2c\20float*\29 +6907:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20SkArenaAlloc*\2c\20sk_sp\29 +6908:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkArenaAlloc*\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +6909:SkContourMeasureIter::SkContourMeasureIter\28SkPath\20const&\2c\20bool\2c\20float\29 +6910:SkContourMeasureIter::Impl::compute_line_seg\28SkPoint\2c\20SkPoint\2c\20float\2c\20unsigned\20int\29 +6911:SkContourMeasure::~SkContourMeasure\28\29 +6912:SkContourMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29\20const +6913:SkConicalGradient::getCenterX1\28\29\20const +6914:SkConic::evalTangentAt\28float\29\20const +6915:SkConic::chop\28SkConic*\29\20const +6916:SkConic::chopIntoQuadsPOW2\28SkPoint*\2c\20int\29\20const +6917:SkConic::BuildUnitArc\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkRotationDirection\2c\20SkMatrix\20const*\2c\20SkConic*\29 +6918:SkColorToPMColor4f\28unsigned\20int\2c\20GrColorInfo\20const&\29 +6919:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29 +6920:SkColorSpaceSingletonFactory::Make\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +6921:SkColorSpaceLuminance::Fetch\28float\29 +6922:SkColorSpace::makeLinearGamma\28\29\20const +6923:SkColorSpace::computeLazyDstFields\28\29\20const +6924:SkColorSpace::SkColorSpace\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +6925:SkColorFilters::Compose\28sk_sp\20const&\2c\20sk_sp\29 +6926:SkColorFilters::Blend\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\2c\20SkBlendMode\29 +6927:SkColorFilterShader::~SkColorFilterShader\28\29 +6928:SkColorFilterShader::flatten\28SkWriteBuffer&\29\20const +6929:SkColorFilterShader::Make\28sk_sp\2c\20float\2c\20sk_sp\29 +6930:SkColor4fXformer::~SkColor4fXformer\28\29 +6931:SkColor4fXformer::SkColor4fXformer\28SkGradientBaseShader\20const*\2c\20SkColorSpace*\2c\20bool\29 +6932:SkCoincidentSpans::contains\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\29\20const +6933:SkChopQuadAtMaxCurvature\28SkPoint\20const*\2c\20SkPoint*\29 +6934:SkChopQuadAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +6935:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\2c\20float\29 +6936:SkChopCubicAtInflections\28SkPoint\20const*\2c\20SkPoint*\29 +6937:SkCharToGlyphCache::reset\28\29 +6938:SkCharToGlyphCache::findGlyphIndex\28int\29\20const +6939:SkCanvasVirtualEnforcer::SkCanvasVirtualEnforcer\28SkIRect\20const&\29 +6940:SkCanvasPriv::WriteLattice\28void*\2c\20SkCanvas::Lattice\20const&\29 +6941:SkCanvasPriv::GetDstClipAndMatrixCounts\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20int*\2c\20int*\29 +6942:SkCanvas::setMatrix\28SkM44\20const&\29 +6943:SkCanvas::internalSaveLayer\28SkCanvas::SaveLayerRec\20const&\2c\20SkCanvas::SaveLayerStrategy\2c\20bool\29 +6944:SkCanvas::internalDrawPaint\28SkPaint\20const&\29 +6945:SkCanvas::getDeviceClipBounds\28\29\20const +6946:SkCanvas::experimental_DrawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +6947:SkCanvas::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6948:SkCanvas::drawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6949:SkCanvas::drawPicture\28sk_sp\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +6950:SkCanvas::drawPicture\28SkPicture\20const*\29 +6951:SkCanvas::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6952:SkCanvas::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +6953:SkCanvas::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +6954:SkCanvas::drawColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +6955:SkCanvas::drawAtlas\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +6956:SkCanvas::drawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +6957:SkCanvas::didTranslate\28float\2c\20float\29 +6958:SkCanvas::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +6959:SkCanvas::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +6960:SkCanvas::clipIRect\28SkIRect\20const&\2c\20SkClipOp\29 +6961:SkCanvas::SkCanvas\28sk_sp\29 +6962:SkCanvas::SkCanvas\28SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +6963:SkCanvas::SkCanvas\28SkBitmap\20const&\29 +6964:SkCachedData::setData\28void*\29 +6965:SkCachedData::internalUnref\28bool\29\20const +6966:SkCachedData::internalRef\28bool\29\20const +6967:SkCachedData::SkCachedData\28void*\2c\20unsigned\20long\29 +6968:SkCachedData::SkCachedData\28unsigned\20long\2c\20SkDiscardableMemory*\29 +6969:SkCTMShader::isOpaque\28\29\20const +6970:SkBulkGlyphMetricsAndPaths::glyphs\28SkSpan\29 +6971:SkBreakIterator_client::~SkBreakIterator_client\28\29 +6972:SkBlurMaskFilterImpl::filterRectMask\28SkMaskBuilder*\2c\20SkRect\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\2c\20SkMaskBuilder::CreateMode\29\20const +6973:SkBlurMask::ComputeBlurredScanline\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20unsigned\20int\2c\20float\29 +6974:SkBlurEngine::GetRasterBlurEngine\28\29 +6975:SkBlockAllocator::addBlock\28int\2c\20int\29 +6976:SkBlockAllocator::BlockIter::Item::advance\28SkBlockAllocator::Block*\29 +6977:SkBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +6978:SkBlitter::blitRectRegion\28SkIRect\20const&\2c\20SkRegion\20const&\29 +6979:SkBlitter::Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +6980:SkBlitter::ChooseSprite\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkArenaAlloc*\2c\20sk_sp\29 +6981:SkBlenderBase::affectsTransparentBlack\28\29\20const +6982:SkBlendShader::~SkBlendShader\28\29_4499 +6983:SkBitmapDevice::~SkBitmapDevice\28\29 +6984:SkBitmapCache::Rec::~Rec\28\29 +6985:SkBitmapCache::Rec::install\28SkBitmap*\29 +6986:SkBitmapCache::Rec::diagnostic_only_getDiscardable\28\29\20const +6987:SkBitmapCache::Find\28SkBitmapCacheDesc\20const&\2c\20SkBitmap*\29 +6988:SkBitmapCache::Alloc\28SkBitmapCacheDesc\20const&\2c\20SkImageInfo\20const&\2c\20SkPixmap*\29 +6989:SkBitmap::tryAllocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29 +6990:SkBitmap::readPixels\28SkPixmap\20const&\29\20const +6991:SkBitmap::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\29\20const +6992:SkBitmap::getAddr\28int\2c\20int\29\20const +6993:SkBitmap::allocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29 +6994:SkBitmap::allocPixels\28SkImageInfo\20const&\29 +6995:SkBinaryWriteBuffer::writeFlattenable\28SkFlattenable\20const*\29 +6996:SkBinaryWriteBuffer::writeColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +6997:SkBigPicture::~SkBigPicture\28\29 +6998:SkBigPicture::cullRect\28\29\20const +6999:SkBigPicture::SnapshotArray::~SnapshotArray\28\29 +7000:SkBigPicture::SkBigPicture\28SkRect\20const&\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20sk_sp\2c\20unsigned\20long\29 +7001:SkBidiFactory::MakeIterator\28unsigned\20short\20const*\2c\20int\2c\20SkBidiIterator::Direction\29\20const +7002:SkBezierCubic::Subdivide\28double\20const*\2c\20double\2c\20double*\29 +7003:SkBasicEdgeBuilder::~SkBasicEdgeBuilder\28\29 +7004:SkBasicEdgeBuilder::combineVertical\28SkEdge\20const*\2c\20SkEdge*\29 +7005:SkBaseShadowTessellator::releaseVertices\28\29 +7006:SkBaseShadowTessellator::handleQuad\28SkPoint\20const*\29 +7007:SkBaseShadowTessellator::handleQuad\28SkMatrix\20const&\2c\20SkPoint*\29 +7008:SkBaseShadowTessellator::handleLine\28SkMatrix\20const&\2c\20SkPoint*\29 +7009:SkBaseShadowTessellator::handleCubic\28SkMatrix\20const&\2c\20SkPoint*\29 +7010:SkBaseShadowTessellator::handleConic\28SkMatrix\20const&\2c\20SkPoint*\2c\20float\29 +7011:SkBaseShadowTessellator::finishPathPolygon\28\29 +7012:SkBaseShadowTessellator::computeConvexShadow\28float\2c\20float\2c\20bool\29 +7013:SkBaseShadowTessellator::computeConcaveShadow\28float\2c\20float\29 +7014:SkBaseShadowTessellator::clipUmbraPoint\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint*\29 +7015:SkBaseShadowTessellator::checkConvexity\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +7016:SkBaseShadowTessellator::appendQuad\28unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +7017:SkBaseShadowTessellator::addInnerPoint\28SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20int*\29 +7018:SkBaseShadowTessellator::addEdge\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20bool\2c\20bool\29 +7019:SkBaseShadowTessellator::addArc\28SkPoint\20const&\2c\20float\2c\20bool\29 +7020:SkBaseShadowTessellator::accumulateCentroid\28SkPoint\20const&\2c\20SkPoint\20const&\29 +7021:SkAutoSMalloc<1024ul>::reset\28unsigned\20long\2c\20SkAutoMalloc::OnShrink\2c\20bool*\29 +7022:SkAutoPixmapStorage::reset\28SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +7023:SkAutoMalloc::SkAutoMalloc\28unsigned\20long\29 +7024:SkAutoDescriptor::reset\28unsigned\20long\29 +7025:SkAutoDescriptor::reset\28SkDescriptor\20const&\29 +7026:SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint\28\29 +7027:SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint\28SkCanvas*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\2c\20SkRect\20const&\29 +7028:SkAutoBlitterChoose::choose\28SkDrawBase\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const&\2c\20bool\29 +7029:SkArenaAlloc::ensureSpace\28unsigned\20int\2c\20unsigned\20int\29 +7030:SkAnalyticEdgeBuilder::combineVertical\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge*\29 +7031:SkAnalyticEdge::update\28int\2c\20bool\29 +7032:SkAnalyticEdge::updateLine\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +7033:SkAnalyticEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\29 +7034:SkAlphaRuns::BreakAt\28short*\2c\20unsigned\20char*\2c\20int\29 +7035:SkAAClip::operator=\28SkAAClip\20const&\29 +7036:SkAAClip::op\28SkIRect\20const&\2c\20SkClipOp\29 +7037:SkAAClip::isRect\28\29\20const +7038:SkAAClip::RunHead::Iterate\28SkAAClip\20const&\29 +7039:SkAAClip::Builder::~Builder\28\29 +7040:SkAAClip::Builder::flushRow\28bool\29 +7041:SkAAClip::Builder::finish\28SkAAClip*\29 +7042:SkAAClip::Builder::Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +7043:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29 +7044:SkA8_Coverage_Blitter*\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29 +7045:SkA8_Blitter::~SkA8_Blitter\28\29 +7046:Simplify\28SkPath\20const&\2c\20SkPath*\29 +7047:Shift +7048:SharedGenerator::Make\28std::__2::unique_ptr>\29 +7049:SetSuperRound +7050:RuntimeEffectRPCallbacks::applyColorSpaceXform\28SkColorSpaceXformSteps\20const&\2c\20void\20const*\29 +7051:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29_3984 +7052:RunBasedAdditiveBlitter::advanceRuns\28\29 +7053:RunBasedAdditiveBlitter::RunBasedAdditiveBlitter\28SkBlitter*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +7054:RgnOper::addSpan\28int\2c\20int\20const*\2c\20int\20const*\29 +7055:ReflexHash::hash\28TriangulationVertex*\29\20const +7056:ReadBase128 +7057:PorterDuffXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +7058:PathSegment::init\28\29 +7059:PS_Conv_Strtol +7060:PS_Conv_ASCIIHexDecode +7061:PDLCDXferProcessor::Make\28SkBlendMode\2c\20GrProcessorAnalysisColor\20const&\29 +7062:OpAsWinding::markReverse\28Contour*\2c\20Contour*\29 +7063:OpAsWinding::getDirection\28Contour&\29 +7064:OpAsWinding::checkContainerChildren\28Contour*\2c\20Contour*\29 +7065:OffsetEdge::computeCrossingDistance\28OffsetEdge\20const*\29 +7066:OT::sbix::sanitize\28hb_sanitize_context_t*\29\20const +7067:OT::sbix::accelerator_t::reference_png\28hb_font_t*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20unsigned\20int*\29\20const +7068:OT::sbix::accelerator_t::has_data\28\29\20const +7069:OT::sbix::accelerator_t::get_png_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +7070:OT::post::sanitize\28hb_sanitize_context_t*\29\20const +7071:OT::maxp::sanitize\28hb_sanitize_context_t*\29\20const +7072:OT::kern::sanitize\28hb_sanitize_context_t*\29\20const +7073:OT::hmtxvmtx::accelerator_t::get_advance_with_var_unscaled\28unsigned\20int\2c\20hb_font_t*\2c\20float*\29\20const +7074:OT::head::sanitize\28hb_sanitize_context_t*\29\20const +7075:OT::hb_ot_layout_lookup_accelerator_t*\20OT::hb_ot_layout_lookup_accelerator_t::create\28OT::Layout::GSUB_impl::SubstLookup\20const&\29 +7076:OT::hb_ot_apply_context_t::skipping_iterator_t::may_skip\28hb_glyph_info_t\20const&\29\20const +7077:OT::hb_ot_apply_context_t::skipping_iterator_t::init\28OT::hb_ot_apply_context_t*\2c\20bool\29 +7078:OT::hb_ot_apply_context_t::matcher_t::may_skip\28OT::hb_ot_apply_context_t\20const*\2c\20hb_glyph_info_t\20const&\29\20const +7079:OT::hb_kern_machine_t::kern\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20bool\29\20const +7080:OT::hb_accelerate_subtables_context_t::return_t\20OT::Context::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +7081:OT::hb_accelerate_subtables_context_t::return_t\20OT::ChainContext::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +7082:OT::gvar::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7083:OT::gvar::get_offset\28unsigned\20int\2c\20unsigned\20int\29\20const +7084:OT::gvar::accelerator_t::infer_delta\28hb_array_t\2c\20hb_array_t\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\20contour_point_t::*\29 +7085:OT::glyf_impl::composite_iter_tmpl::set_current\28OT::glyf_impl::CompositeGlyphRecord\20const*\29 +7086:OT::glyf_impl::composite_iter_tmpl::__next__\28\29 +7087:OT::glyf_impl::SimpleGlyph::read_points\28OT::IntType\20const*&\2c\20hb_array_t\2c\20OT::IntType\20const*\2c\20float\20contour_point_t::*\2c\20OT::glyf_impl::SimpleGlyph::simple_glyph_flag_t\2c\20OT::glyf_impl::SimpleGlyph::simple_glyph_flag_t\29 +7088:OT::glyf_impl::Glyph::get_composite_iterator\28\29\20const +7089:OT::glyf_impl::CompositeGlyphRecord::transform\28float\20const\20\28&\29\20\5b4\5d\2c\20hb_array_t\29 +7090:OT::glyf_impl::CompositeGlyphRecord::get_transformation\28float\20\28&\29\20\5b4\5d\2c\20contour_point_t&\29\20const +7091:OT::glyf_accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\29\20const +7092:OT::fvar::sanitize\28hb_sanitize_context_t*\29\20const +7093:OT::cmap::sanitize\28hb_sanitize_context_t*\29\20const +7094:OT::cmap::accelerator_t::get_nominal_glyph\28unsigned\20int\2c\20unsigned\20int*\2c\20hb_cache_t<21u\2c\2016u\2c\208u\2c\20true>*\29\20const +7095:OT::cmap::accelerator_t::_cached_get\28unsigned\20int\2c\20unsigned\20int*\2c\20hb_cache_t<21u\2c\2016u\2c\208u\2c\20true>*\29\20const +7096:OT::cff2::sanitize\28hb_sanitize_context_t*\29\20const +7097:OT::cff2::accelerator_templ_t>::_fini\28\29 +7098:OT::cff1::sanitize\28hb_sanitize_context_t*\29\20const +7099:OT::cff1::accelerator_templ_t>::glyph_to_sid\28unsigned\20int\2c\20CFF::code_pair_t*\29\20const +7100:OT::cff1::accelerator_templ_t>::_fini\28\29 +7101:OT::cff1::accelerator_t::gname_t::cmp\28void\20const*\2c\20void\20const*\29 +7102:OT::avar::sanitize\28hb_sanitize_context_t*\29\20const +7103:OT::VariationDevice::get_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +7104:OT::VarData::get_row_size\28\29\20const +7105:OT::VVAR::sanitize\28hb_sanitize_context_t*\29\20const +7106:OT::VORG::sanitize\28hb_sanitize_context_t*\29\20const +7107:OT::UnsizedArrayOf\2c\2014u>>\20const&\20OT::operator+\2c\20\28void*\290>\28hb_blob_ptr_t\20const&\2c\20OT::OffsetTo\2c\2014u>>\2c\20OT::IntType\2c\20false>\20const&\29 +7108:OT::TupleVariationHeader::get_size\28unsigned\20int\29\20const +7109:OT::TupleVariationData::unpack_points\28OT::IntType\20const*&\2c\20hb_vector_t&\2c\20OT::IntType\20const*\29 +7110:OT::TupleVariationData::unpack_deltas\28OT::IntType\20const*&\2c\20hb_vector_t&\2c\20OT::IntType\20const*\29 +7111:OT::TupleVariationData::tuple_iterator_t::is_valid\28\29\20const +7112:OT::SortedArrayOf\2c\20OT::IntType>::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\29 +7113:OT::SVG::sanitize\28hb_sanitize_context_t*\29\20const +7114:OT::RuleSet::would_apply\28OT::hb_would_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +7115:OT::RuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +7116:OT::ResourceMap::get_type_record\28unsigned\20int\29\20const +7117:OT::ResourceMap::get_type_count\28\29\20const +7118:OT::RecordArrayOf::find_index\28unsigned\20int\2c\20unsigned\20int*\29\20const +7119:OT::PaintTranslate::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7120:OT::PaintSolid::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7121:OT::PaintSkewAroundCenter::sanitize\28hb_sanitize_context_t*\29\20const +7122:OT::PaintSkewAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7123:OT::PaintSkew::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7124:OT::PaintScaleUniformAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7125:OT::PaintScaleUniform::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7126:OT::PaintScaleAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7127:OT::PaintScale::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7128:OT::PaintRotateAroundCenter::sanitize\28hb_sanitize_context_t*\29\20const +7129:OT::PaintRotateAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7130:OT::PaintRotate::sanitize\28hb_sanitize_context_t*\29\20const +7131:OT::PaintRotate::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7132:OT::OpenTypeFontFile::sanitize\28hb_sanitize_context_t*\29\20const +7133:OT::OS2::sanitize\28hb_sanitize_context_t*\29\20const +7134:OT::MVAR::sanitize\28hb_sanitize_context_t*\29\20const +7135:OT::Lookup::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +7136:OT::Lookup*\20hb_serialize_context_t::extend_size\28OT::Lookup*\2c\20unsigned\20long\2c\20bool\29 +7137:OT::Layout::propagate_attachment_offsets\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +7138:OT::Layout::GPOS_impl::reverse_cursive_minor_offset\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +7139:OT::Layout::GPOS_impl::ValueFormat::sanitize_value_devices\28hb_sanitize_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\29\20const +7140:OT::Layout::Common::RangeRecord\20const&\20OT::SortedArrayOf\2c\20OT::IntType>::bsearch\28unsigned\20int\20const&\2c\20OT::Layout::Common::RangeRecord\20const&\29\20const +7141:OT::Layout::Common::CoverageFormat2_4*\20hb_serialize_context_t::extend_min>\28OT::Layout::Common::CoverageFormat2_4*\29 +7142:OT::Layout::Common::Coverage::sanitize\28hb_sanitize_context_t*\29\20const +7143:OT::Layout::Common::Coverage::get_population\28\29\20const +7144:OT::LangSys::sanitize\28hb_sanitize_context_t*\2c\20OT::Record_sanitize_closure_t\20const*\29\20const +7145:OT::IndexSubtableRecord::get_image_data\28unsigned\20int\2c\20void\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7146:OT::IndexArray::get_indexes\28unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7147:OT::HintingDevice::get_delta\28unsigned\20int\2c\20int\29\20const +7148:OT::HVARVVAR::get_advance_delta_unscaled\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +7149:OT::GSUBGPOS::get_script_list\28\29\20const +7150:OT::GSUBGPOS::get_feature_variations\28\29\20const +7151:OT::GSUBGPOS::accelerator_t::get_accel\28unsigned\20int\29\20const +7152:OT::GDEF::sanitize\28hb_sanitize_context_t*\29\20const +7153:OT::GDEF::get_mark_glyph_sets\28\29\20const +7154:OT::GDEF::accelerator_t::get_glyph_props\28unsigned\20int\29\20const +7155:OT::Feature::sanitize\28hb_sanitize_context_t*\2c\20OT::Record_sanitize_closure_t\20const*\29\20const +7156:OT::ContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +7157:OT::ColorStop::get_color_stop\28OT::hb_paint_context_t*\2c\20hb_color_stop_t*\2c\20unsigned\20int\2c\20OT::VarStoreInstancer\20const&\29\20const +7158:OT::ColorLine::static_get_extend\28hb_color_line_t*\2c\20void*\2c\20void*\29 +7159:OT::CmapSubtableLongSegmented::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +7160:OT::CmapSubtableLongGroup\20const&\20OT::SortedArrayOf>::bsearch\28unsigned\20int\20const&\2c\20OT::CmapSubtableLongGroup\20const&\29\20const +7161:OT::CmapSubtableFormat4::accelerator_t::init\28OT::CmapSubtableFormat4\20const*\29 +7162:OT::CmapSubtableFormat4::accelerator_t::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +7163:OT::ClipBoxFormat1::get_clip_box\28OT::ClipBoxData&\2c\20OT::VarStoreInstancer\20const&\29\20const +7164:OT::ClassDef::cost\28\29\20const +7165:OT::ChainRuleSet::would_apply\28OT::hb_would_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +7166:OT::ChainRuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +7167:OT::ChainContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +7168:OT::CPAL::sanitize\28hb_sanitize_context_t*\29\20const +7169:OT::COLR::sanitize\28hb_sanitize_context_t*\29\20const +7170:OT::COLR::get_base_glyph_paint\28unsigned\20int\29\20const +7171:OT::CBLC::sanitize\28hb_sanitize_context_t*\29\20const +7172:OT::CBLC::choose_strike\28hb_font_t*\29\20const +7173:OT::CBDT::sanitize\28hb_sanitize_context_t*\29\20const +7174:OT::CBDT::accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +7175:OT::BitmapSizeTable::find_table\28unsigned\20int\2c\20void\20const*\2c\20void\20const**\29\20const +7176:OT::ArrayOf>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7177:OT::ArrayOf\2c\20OT::IntType>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7178:OT::ArrayOf>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7179:OT::ArrayOf>>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7180:OT::Affine2x3::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7181:MaskValue*\20SkTLazy::init\28MaskValue\20const&\29 +7182:MakeRasterCopyPriv\28SkPixmap\20const&\2c\20unsigned\20int\29 +7183:Load_SBit_Png +7184:LineQuadraticIntersections::verticalIntersect\28double\2c\20double*\29 +7185:LineQuadraticIntersections::intersectRay\28double*\29 +7186:LineQuadraticIntersections::horizontalIntersect\28double\2c\20double*\29 +7187:LineCubicIntersections::intersectRay\28double*\29 +7188:LineCubicIntersections::VerticalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +7189:LineCubicIntersections::HorizontalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +7190:LineConicIntersections::verticalIntersect\28double\2c\20double*\29 +7191:LineConicIntersections::intersectRay\28double*\29 +7192:LineConicIntersections::horizontalIntersect\28double\2c\20double*\29 +7193:Ins_UNKNOWN +7194:Ins_SxVTL +7195:InitializeCompoundDictionaryCopy +7196:HandleCoincidence\28SkOpContourHead*\2c\20SkOpCoincidence*\29 +7197:GrWritePixelsTask::~GrWritePixelsTask\28\29 +7198:GrWindowRectsState::operator=\28GrWindowRectsState\20const&\29 +7199:GrWindowRectsState::operator==\28GrWindowRectsState\20const&\29\20const +7200:GrWindowRectangles::GrWindowRectangles\28GrWindowRectangles\20const&\29 +7201:GrWaitRenderTask::~GrWaitRenderTask\28\29 +7202:GrVertexBufferAllocPool::makeSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +7203:GrVertexBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +7204:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20SkPathFillType\2c\20skgpu::VertexWriter\29\20const +7205:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20GrEagerVertexAllocator*\29\20const +7206:GrTriangulator::mergeEdgesBelow\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +7207:GrTriangulator::mergeEdgesAbove\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +7208:GrTriangulator::makeSortedVertex\28SkPoint\20const&\2c\20unsigned\20char\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29\20const +7209:GrTriangulator::makeEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\29 +7210:GrTriangulator::computeBisector\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\29\20const +7211:GrTriangulator::appendQuadraticToContour\28SkPoint\20const*\2c\20float\2c\20GrTriangulator::VertexList*\29\20const +7212:GrTriangulator::allocateMonotonePoly\28GrTriangulator::Edge*\2c\20GrTriangulator::Side\2c\20int\29 +7213:GrTriangulator::Edge::recompute\28\29 +7214:GrTriangulator::Edge::intersect\28GrTriangulator::Edge\20const&\2c\20SkPoint*\2c\20unsigned\20char*\29\20const +7215:GrTriangulator::CountPoints\28GrTriangulator::Poly*\2c\20SkPathFillType\29 +7216:GrTriangulator::BreadcrumbTriangleList::concat\28GrTriangulator::BreadcrumbTriangleList&&\29 +7217:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29 +7218:GrThreadSafeCache::makeNewEntryMRU\28GrThreadSafeCache::Entry*\29 +7219:GrThreadSafeCache::makeExistingEntryMRU\28GrThreadSafeCache::Entry*\29 +7220:GrThreadSafeCache::findVertsWithData\28skgpu::UniqueKey\20const&\29 +7221:GrThreadSafeCache::addVertsWithData\28skgpu::UniqueKey\20const&\2c\20sk_sp\2c\20bool\20\28*\29\28SkData*\2c\20SkData*\29\29 +7222:GrThreadSafeCache::Trampoline::~Trampoline\28\29 +7223:GrThreadSafeCache::Entry::set\28skgpu::UniqueKey\20const&\2c\20sk_sp\29 +7224:GrThreadSafeCache::Entry::makeEmpty\28\29 +7225:GrThreadSafeCache::CreateLazyView\28GrDirectContext*\2c\20GrColorType\2c\20SkISize\2c\20GrSurfaceOrigin\2c\20SkBackingFit\29 +7226:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29 +7227:GrTextureRenderTargetProxy::initSurfaceFlags\28GrCaps\20const&\29 +7228:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29 +7229:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28GrCaps\20const&\2c\20std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\2c\20std::__2::basic_string_view>\29 +7230:GrTextureProxy::~GrTextureProxy\28\29_9449 +7231:GrTextureProxy::~GrTextureProxy\28\29_9448 +7232:GrTextureProxy::setUniqueKey\28GrProxyProvider*\2c\20skgpu::UniqueKey\20const&\29 +7233:GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +7234:GrTextureProxy::instantiate\28GrResourceProvider*\29 +7235:GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +7236:GrTextureProxy::callbackDesc\28\29\20const +7237:GrTextureProxy::ProxiesAreCompatibleAsDynamicState\28GrSurfaceProxy\20const*\2c\20GrSurfaceProxy\20const*\29 +7238:GrTextureProxy::GrTextureProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29 +7239:GrTextureEffect::~GrTextureEffect\28\29 +7240:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::$_1::operator\28\29\28int\2c\20GrSamplerState::WrapMode\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20float\29\20const +7241:GrTextureEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29::$_0::operator\28\29\28float*\2c\20GrResourceHandle\29\20const +7242:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_2::operator\28\29\28GrTextureEffect::ShaderMode\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +7243:GrTexture::onGpuMemorySize\28\29\20const +7244:GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +7245:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29 +7246:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29 +7247:GrSurfaceProxyView::operator=\28GrSurfaceProxyView\20const&\29 +7248:GrSurfaceProxyView::operator==\28GrSurfaceProxyView\20const&\29\20const +7249:GrSurfaceProxyPriv::exactify\28\29 +7250:GrSurfaceProxyPriv::assign\28sk_sp\29 +7251:GrSurfaceProxy::GrSurfaceProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +7252:GrSurfaceProxy::GrSurfaceProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +7253:GrSurface::setRelease\28sk_sp\29 +7254:GrSurface::onRelease\28\29 +7255:GrStyledShape::setInheritedKey\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +7256:GrStyledShape::asRRect\28SkRRect*\2c\20bool*\29\20const +7257:GrStyledShape::asLine\28SkPoint*\2c\20bool*\29\20const +7258:GrStyledShape::GrStyledShape\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20bool\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +7259:GrStyledShape::GrStyledShape\28SkRRect\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +7260:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20SkPaint\20const&\2c\20GrStyledShape::DoSimplify\29 +7261:GrStyle::resetToInitStyle\28SkStrokeRec::InitStyle\29 +7262:GrStyle::applyToPath\28SkPath*\2c\20SkStrokeRec::InitStyle*\2c\20SkPath\20const&\2c\20float\29\20const +7263:GrStyle::applyPathEffect\28SkPath*\2c\20SkStrokeRec*\2c\20SkPath\20const&\29\20const +7264:GrStyle::MatrixToScaleFactor\28SkMatrix\20const&\29 +7265:GrStyle::DashInfo::operator=\28GrStyle::DashInfo\20const&\29 +7266:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29 +7267:GrStrokeTessellationShader::Impl::~Impl\28\29 +7268:GrStagingBufferManager::detachBuffers\28\29 +7269:GrSkSLFP::~GrSkSLFP\28\29 +7270:GrSkSLFP::Impl::~Impl\28\29 +7271:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineStruct\28char\20const*\29 +7272:GrSimpleMesh::~GrSimpleMesh\28\29 +7273:GrShape::simplify\28unsigned\20int\29 +7274:GrShape::setArc\28SkArc\20const&\29 +7275:GrShape::conservativeContains\28SkRect\20const&\29\20const +7276:GrShape::closed\28\29\20const +7277:GrShape::GrShape\28SkRect\20const&\29 +7278:GrShape::GrShape\28SkRRect\20const&\29 +7279:GrShape::GrShape\28SkPath\20const&\29 +7280:GrShaderVar::GrShaderVar\28SkString\2c\20SkSLType\2c\20GrShaderVar::TypeModifier\2c\20int\2c\20SkString\2c\20SkString\29 +7281:GrScissorState::operator==\28GrScissorState\20const&\29\20const +7282:GrScissorState::intersect\28SkIRect\20const&\29 +7283:GrSWMaskHelper::toTextureView\28GrRecordingContext*\2c\20SkBackingFit\29 +7284:GrSWMaskHelper::drawShape\28GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +7285:GrSWMaskHelper::drawShape\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +7286:GrResourceProvider::writePixels\28sk_sp\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\29\20const +7287:GrResourceProvider::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +7288:GrResourceProvider::prepareLevels\28GrBackendFormat\20const&\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\2c\20skia_private::AutoSTArray<14\2c\20GrMipLevel>*\2c\20skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>*\29\20const +7289:GrResourceProvider::getExactScratch\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7290:GrResourceProvider::findAndRefScratchTexture\28skgpu::ScratchKey\20const&\2c\20std::__2::basic_string_view>\29 +7291:GrResourceProvider::findAndRefScratchTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7292:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7293:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20GrColorType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMipLevel\20const*\2c\20std::__2::basic_string_view>\29 +7294:GrResourceProvider::createBuffer\28void\20const*\2c\20unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +7295:GrResourceProvider::createApproxTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7296:GrResourceCache::removeResource\28GrGpuResource*\29 +7297:GrResourceCache::removeFromNonpurgeableArray\28GrGpuResource*\29 +7298:GrResourceCache::releaseAll\28\29 +7299:GrResourceCache::refAndMakeResourceMRU\28GrGpuResource*\29 +7300:GrResourceCache::processFreedGpuResources\28\29 +7301:GrResourceCache::insertResource\28GrGpuResource*\29 +7302:GrResourceCache::findAndRefUniqueResource\28skgpu::UniqueKey\20const&\29 +7303:GrResourceCache::didChangeBudgetStatus\28GrGpuResource*\29 +7304:GrResourceCache::addToNonpurgeableArray\28GrGpuResource*\29 +7305:GrResourceAllocator::~GrResourceAllocator\28\29 +7306:GrResourceAllocator::planAssignment\28\29 +7307:GrResourceAllocator::expire\28unsigned\20int\29 +7308:GrResourceAllocator::Register*\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29 +7309:GrResourceAllocator::IntervalList::popHead\28\29 +7310:GrResourceAllocator::IntervalList::insertByIncreasingStart\28GrResourceAllocator::Interval*\29 +7311:GrRenderTask::makeSkippable\28\29 +7312:GrRenderTask::isUsed\28GrSurfaceProxy*\29\20const +7313:GrRenderTask::isInstantiated\28\29\20const +7314:GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9296 +7315:GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9294 +7316:GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7317:GrRenderTargetProxy::isMSAADirty\28\29\20const +7318:GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7319:GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7320:GrRenderTargetProxy::callbackDesc\28\29\20const +7321:GrRenderTarget::GrRenderTarget\28GrGpu*\2c\20SkISize\20const&\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20sk_sp\29 +7322:GrRecordingContext::init\28\29 +7323:GrRecordingContext::destroyDrawingManager\28\29 +7324:GrRecordingContext::colorTypeSupportedAsSurface\28SkColorType\29\20const +7325:GrRecordingContext::abandoned\28\29 +7326:GrRecordingContext::abandonContext\28\29 +7327:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29 +7328:GrRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRRect\20const&\2c\20GrShaderCaps\20const&\29 +7329:GrQuadUtils::TessellationHelper::outset\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuad*\2c\20GrQuad*\29 +7330:GrQuadUtils::TessellationHelper::getOutsetRequest\28skvx::Vec<4\2c\20float>\20const&\29 +7331:GrQuadUtils::TessellationHelper::adjustVertices\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuadUtils::TessellationHelper::Vertices*\29 +7332:GrQuadUtils::TessellationHelper::adjustDegenerateVertices\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuadUtils::TessellationHelper::Vertices*\29 +7333:GrQuadUtils::TessellationHelper::Vertices::moveTo\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +7334:GrQuadUtils::ClipToW0\28DrawQuad*\2c\20DrawQuad*\29 +7335:GrQuadBuffer<\28anonymous\20namespace\29::TextureOpImpl::ColorSubsetAndAA>::append\28GrQuad\20const&\2c\20\28anonymous\20namespace\29::TextureOpImpl::ColorSubsetAndAA&&\2c\20GrQuad\20const*\29 +7336:GrQuadBuffer<\28anonymous\20namespace\29::TextureOpImpl::ColorSubsetAndAA>::GrQuadBuffer\28int\2c\20bool\29 +7337:GrQuad::point\28int\29\20const +7338:GrQuad::bounds\28\29\20const::'lambda0'\28float\20const*\29::operator\28\29\28float\20const*\29\20const +7339:GrQuad::bounds\28\29\20const::'lambda'\28float\20const*\29::operator\28\29\28float\20const*\29\20const +7340:GrProxyProvider::removeUniqueKeyFromProxy\28GrTextureProxy*\29 +7341:GrProxyProvider::processInvalidUniqueKeyImpl\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\2c\20GrProxyProvider::InvalidateGPUResource\2c\20GrProxyProvider::RemoveTableEntry\29 +7342:GrProxyProvider::createLazyProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20GrInternalSurfaceFlags\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +7343:GrProxyProvider::adoptUniqueKeyFromSurface\28GrTextureProxy*\2c\20GrSurface\20const*\29 +7344:GrProcessorSet::operator==\28GrProcessorSet\20const&\29\20const +7345:GrPorterDuffXPFactory::Get\28SkBlendMode\29 +7346:GrPixmap::GrPixmap\28SkPixmap\20const&\29 +7347:GrPipeline::peekDstTexture\28\29\20const +7348:GrPipeline::GrPipeline\28GrPipeline::InitArgs\20const&\2c\20sk_sp\2c\20GrAppliedHardClip\20const&\29 +7349:GrPersistentCacheUtils::ShaderMetadata::~ShaderMetadata\28\29 +7350:GrPersistentCacheUtils::GetType\28SkReadBuffer*\29 +7351:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29 +7352:GrPathUtils::QuadUVMatrix::set\28SkPoint\20const*\29 +7353:GrPathUtils::QuadUVMatrix::apply\28void*\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +7354:GrPathTessellationShader::MakeStencilOnlyPipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedHardClip\20const&\2c\20GrPipeline::InputFlags\29 +7355:GrPathTessellationShader::Impl::~Impl\28\29 +7356:GrOpsRenderPass::~GrOpsRenderPass\28\29 +7357:GrOpsRenderPass::resetActiveBuffers\28\29 +7358:GrOpsRenderPass::draw\28int\2c\20int\29 +7359:GrOpsRenderPass::drawIndexPattern\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +7360:GrOpFlushState::~GrOpFlushState\28\29_9083 +7361:GrOpFlushState::smallPathAtlasManager\28\29\20const +7362:GrOpFlushState::reset\28\29 +7363:GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +7364:GrOpFlushState::putBackIndices\28int\29 +7365:GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp\28GrOp\20const*\2c\20SkRect\20const&\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +7366:GrOpFlushState::drawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +7367:GrOpFlushState::doUpload\28std::__2::function&\29>&\2c\20bool\29 +7368:GrOpFlushState::addASAPUpload\28std::__2::function&\29>&&\29 +7369:GrOpFlushState::OpArgs::OpArgs\28GrOp*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7370:GrOp::setTransformedBounds\28SkRect\20const&\2c\20SkMatrix\20const&\2c\20GrOp::HasAABloat\2c\20GrOp::IsHairline\29 +7371:GrOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7372:GrOp::combineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7373:GrNonAtomicRef::unref\28\29\20const +7374:GrNonAtomicRef::unref\28\29\20const +7375:GrNonAtomicRef::unref\28\29\20const +7376:GrNativeRect::operator!=\28GrNativeRect\20const&\29\20const +7377:GrMeshDrawTarget::allocPrimProcProxyPtrs\28int\29 +7378:GrMeshDrawOp::PatternHelper::init\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +7379:GrMemoryPool::allocate\28unsigned\20long\29 +7380:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29 +7381:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::changed\28\29 +7382:GrMakeCachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\29::$_0::operator\28\29\28GrTextureProxy*\29\20const +7383:GrIndexBufferAllocPool::makeSpace\28int\2c\20sk_sp*\2c\20int*\29 +7384:GrIndexBufferAllocPool::makeSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +7385:GrImageInfo::operator=\28GrImageInfo&&\29 +7386:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20int\2c\20int\29 +7387:GrImageContext::abandonContext\28\29 +7388:GrHashMapWithCache::find\28unsigned\20int\20const&\29\20const +7389:GrGradientBitmapCache::release\28GrGradientBitmapCache::Entry*\29\20const +7390:GrGpuResource::setLabel\28std::__2::basic_string_view>\29 +7391:GrGpuResource::makeBudgeted\28\29 +7392:GrGpuResource::GrGpuResource\28GrGpu*\2c\20std::__2::basic_string_view>\29 +7393:GrGpuResource::CacheAccess::abandon\28\29 +7394:GrGpuBuffer::ComputeScratchKeyForDynamicBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20skgpu::ScratchKey*\29 +7395:GrGpu::~GrGpu\28\29 +7396:GrGpu::submitToGpu\28GrSubmitInfo\20const&\29 +7397:GrGpu::regenerateMipMapLevels\28GrTexture*\29 +7398:GrGpu::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7399:GrGpu::createTextureCommon\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +7400:GrGpu::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +7401:GrGpu::callSubmittedProcs\28bool\29 +7402:GrGeometryProcessor::AttributeSet::addToKey\28skgpu::KeyBuilder*\29\20const +7403:GrGeometryProcessor::AttributeSet::Iter::skipUninitialized\28\29 +7404:GrGeometryProcessor::Attribute&\20skia_private::TArray::emplace_back\28char\20const\20\28&\29\20\5b26\5d\2c\20GrVertexAttribType&&\2c\20SkSLType&&\29 +7405:GrGLTextureParameters::invalidate\28\29 +7406:GrGLTextureParameters::SamplerOverriddenState::SamplerOverriddenState\28\29 +7407:GrGLTexture::~GrGLTexture\28\29_11891 +7408:GrGLTexture::~GrGLTexture\28\29_11890 +7409:GrGLTexture::MakeWrapped\28GrGLGpu*\2c\20GrMipmapStatus\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrWrapCacheable\2c\20GrIOType\2c\20std::__2::basic_string_view>\29 +7410:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20skgpu::Budgeted\2c\20GrGLTexture::Desc\20const&\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +7411:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +7412:GrGLSemaphore::~GrGLSemaphore\28\29 +7413:GrGLSLVaryingHandler::addAttribute\28GrShaderVar\20const&\29 +7414:GrGLSLVarying::vsOutVar\28\29\20const +7415:GrGLSLVarying::fsInVar\28\29\20const +7416:GrGLSLUniformHandler::liftUniformToVertexShader\28GrProcessor\20const&\2c\20SkString\29 +7417:GrGLSLShaderBuilder::nextStage\28\29 +7418:GrGLSLShaderBuilder::finalize\28unsigned\20int\29 +7419:GrGLSLShaderBuilder::emitFunction\28char\20const*\2c\20char\20const*\29 +7420:GrGLSLShaderBuilder::emitFunctionPrototype\28char\20const*\29 +7421:GrGLSLShaderBuilder::appendTextureLookupAndBlend\28char\20const*\2c\20SkBlendMode\2c\20GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +7422:GrGLSLShaderBuilder::appendDecls\28SkTBlockList\20const&\2c\20SkString*\29\20const +7423:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29::$_0::operator\28\29\28char\20const*\2c\20GrResourceHandle\2c\20skcms_TFType\29\20const +7424:GrGLSLShaderBuilder::GrGLSLShaderBuilder\28GrGLSLProgramBuilder*\29 +7425:GrGLSLProgramDataManager::setRuntimeEffectUniforms\28SkSpan\2c\20SkSpan\20const>\2c\20SkSpan\2c\20void\20const*\29\20const +7426:GrGLSLProgramBuilder::~GrGLSLProgramBuilder\28\29 +7427:GrGLSLFragmentShaderBuilder::onFinalize\28\29 +7428:GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +7429:GrGLSLColorSpaceXformHelper::isNoop\28\29\20const +7430:GrGLSLBlend::SetBlendModeUniformData\28GrGLSLProgramDataManager\20const&\2c\20GrResourceHandle\2c\20SkBlendMode\29 +7431:GrGLSLBlend::BlendExpression\28GrProcessor\20const*\2c\20GrGLSLUniformHandler*\2c\20GrResourceHandle*\2c\20char\20const*\2c\20char\20const*\2c\20SkBlendMode\29 +7432:GrGLRenderTarget::~GrGLRenderTarget\28\29_11861 +7433:GrGLRenderTarget::~GrGLRenderTarget\28\29_11860 +7434:GrGLRenderTarget::setFlags\28GrGLCaps\20const&\2c\20GrGLRenderTarget::IDs\20const&\29 +7435:GrGLRenderTarget::onGpuMemorySize\28\29\20const +7436:GrGLRenderTarget::bind\28bool\29 +7437:GrGLRenderTarget::backendFormat\28\29\20const +7438:GrGLRenderTarget::GrGLRenderTarget\28GrGLGpu*\2c\20SkISize\20const&\2c\20GrGLFormat\2c\20int\2c\20GrGLRenderTarget::IDs\20const&\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7439:GrGLProgramDataManager::set4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +7440:GrGLProgramDataManager::set2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +7441:GrGLProgramBuilder::uniformHandler\28\29 +7442:GrGLProgramBuilder::compileAndAttachShaders\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SkTDArray*\2c\20bool\2c\20skgpu::ShaderErrorHandler*\29 +7443:GrGLProgramBuilder::PrecompileProgram\28GrDirectContext*\2c\20GrGLPrecompiledProgram*\2c\20SkData\20const&\29::$_0::operator\28\29\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\29\20const +7444:GrGLProgramBuilder::CreateProgram\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrGLPrecompiledProgram\20const*\29 +7445:GrGLProgram::~GrGLProgram\28\29 +7446:GrGLInterfaces::MakeWebGL\28\29 +7447:GrGLInterface::~GrGLInterface\28\29 +7448:GrGLGpu::~GrGLGpu\28\29 +7449:GrGLGpu::waitSemaphore\28GrSemaphore*\29 +7450:GrGLGpu::uploadTexData\28SkISize\2c\20unsigned\20int\2c\20SkIRect\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20long\2c\20GrMipLevel\20const*\2c\20int\29 +7451:GrGLGpu::uploadCompressedTexData\28SkTextureCompressionType\2c\20GrGLFormat\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20unsigned\20int\2c\20void\20const*\2c\20unsigned\20long\29 +7452:GrGLGpu::uploadColorToTex\28GrGLFormat\2c\20SkISize\2c\20unsigned\20int\2c\20std::__2::array\2c\20unsigned\20int\29 +7453:GrGLGpu::readOrTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20int\29 +7454:GrGLGpu::onFBOChanged\28\29 +7455:GrGLGpu::getTimerQueryResult\28unsigned\20int\29 +7456:GrGLGpu::getCompatibleStencilIndex\28GrGLFormat\29 +7457:GrGLGpu::flushWireframeState\28bool\29 +7458:GrGLGpu::flushScissorRect\28SkIRect\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +7459:GrGLGpu::flushProgram\28unsigned\20int\29 +7460:GrGLGpu::flushProgram\28sk_sp\29 +7461:GrGLGpu::flushFramebufferSRGB\28bool\29 +7462:GrGLGpu::flushConservativeRasterState\28bool\29 +7463:GrGLGpu::createRenderTargetObjects\28GrGLTexture::Desc\20const&\2c\20int\2c\20GrGLRenderTarget::IDs*\29 +7464:GrGLGpu::createCompressedTexture2D\28SkISize\2c\20SkTextureCompressionType\2c\20GrGLFormat\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrGLTextureParameters::SamplerOverriddenState*\29 +7465:GrGLGpu::bindVertexArray\28unsigned\20int\29 +7466:GrGLGpu::TextureUnitBindings::setBoundID\28unsigned\20int\2c\20GrGpuResource::UniqueID\29 +7467:GrGLGpu::TextureUnitBindings::invalidateAllTargets\28bool\29 +7468:GrGLGpu::TextureToCopyProgramIdx\28GrTexture*\29 +7469:GrGLGpu::ProgramCache::~ProgramCache\28\29 +7470:GrGLGpu::ProgramCache::findOrCreateProgramImpl\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrThreadSafePipelineBuilder::Stats::ProgramCacheResult*\29 +7471:GrGLGpu::HWVertexArrayState::invalidate\28\29 +7472:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29 +7473:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\29 +7474:GrGLFinishCallbacks::check\28\29 +7475:GrGLContext::~GrGLContext\28\29_11601 +7476:GrGLCaps::~GrGLCaps\28\29 +7477:GrGLCaps::getTexSubImageExternalFormatAndType\28GrGLFormat\2c\20GrColorType\2c\20GrColorType\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7478:GrGLCaps::getExternalFormat\28GrGLFormat\2c\20GrColorType\2c\20GrColorType\2c\20GrGLCaps::ExternalFormatUsage\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7479:GrGLCaps::canCopyTexSubImage\28GrGLFormat\2c\20bool\2c\20GrTextureType\20const*\2c\20GrGLFormat\2c\20bool\2c\20GrTextureType\20const*\29\20const +7480:GrGLCaps::canCopyAsBlit\28GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20SkRect\20const&\2c\20bool\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29\20const +7481:GrGLBuffer::~GrGLBuffer\28\29_11540 +7482:GrGLAttribArrayState::resize\28int\29 +7483:GrGLAttribArrayState::GrGLAttribArrayState\28int\29 +7484:GrFragmentProcessors::MakeChildFP\28SkRuntimeEffect::ChildPtr\20const&\2c\20GrFPArgs\20const&\29 +7485:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +7486:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +7487:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::Make\28\29 +7488:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::Make\28std::__2::unique_ptr>\29 +7489:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::DeviceSpace\28std::__2::unique_ptr>\29 +7490:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +7491:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +7492:GrFragmentProcessor::ClampOutput\28std::__2::unique_ptr>\29 +7493:GrFixedClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +7494:GrFixedClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +7495:GrEagerDynamicVertexAllocator::unlock\28int\29 +7496:GrDynamicAtlas::~GrDynamicAtlas\28\29 +7497:GrDynamicAtlas::Node::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +7498:GrDrawingManager::flush\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +7499:GrDrawingManager::closeAllTasks\28\29 +7500:GrDrawOpAtlas::uploadToPage\28unsigned\20int\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +7501:GrDrawOpAtlas::updatePlot\28GrDeferredUploadTarget*\2c\20skgpu::AtlasLocator*\2c\20skgpu::Plot*\29 +7502:GrDrawOpAtlas::setLastUseToken\28skgpu::AtlasLocator\20const&\2c\20skgpu::AtlasToken\29 +7503:GrDrawOpAtlas::processEviction\28skgpu::PlotLocator\29 +7504:GrDrawOpAtlas::hasID\28skgpu::PlotLocator\20const&\29 +7505:GrDrawOpAtlas::compact\28skgpu::AtlasToken\29 +7506:GrDrawOpAtlas::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +7507:GrDrawOpAtlas::Make\28GrProxyProvider*\2c\20GrBackendFormat\20const&\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20int\2c\20int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20GrDrawOpAtlas::AllowMultitexturing\2c\20skgpu::PlotEvictionCallback*\2c\20std::__2::basic_string_view>\29 +7508:GrDrawIndirectBufferAllocPool::putBack\28int\29 +7509:GrDrawIndirectBufferAllocPool::putBackIndexed\28int\29 +7510:GrDrawIndirectBufferAllocPool::makeSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +7511:GrDrawIndirectBufferAllocPool::makeIndexedSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +7512:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29 +7513:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29 +7514:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29 +7515:GrDistanceFieldA8TextGeoProc::onTextureSampler\28int\29\20const +7516:GrDisableColorXPFactory::MakeXferProcessor\28\29 +7517:GrDirectContextPriv::validPMUPMConversionExists\28\29 +7518:GrDirectContext::~GrDirectContext\28\29 +7519:GrDirectContext::syncAllOutstandingGpuWork\28bool\29 +7520:GrDirectContext::submit\28GrSyncCpu\29 +7521:GrDirectContext::flush\28SkSurface*\29 +7522:GrDirectContext::abandoned\28\29 +7523:GrDeferredProxyUploader::signalAndFreeData\28\29 +7524:GrDeferredProxyUploader::GrDeferredProxyUploader\28\29 +7525:GrCopyRenderTask::~GrCopyRenderTask\28\29 +7526:GrCopyRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +7527:GrCopyBaseMipMapToView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Budgeted\29 +7528:GrCopyBaseMipMapToTextureProxy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20std::__2::basic_string_view>\2c\20skgpu::Budgeted\29 +7529:GrContext_Base::~GrContext_Base\28\29_8592 +7530:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29 +7531:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29 +7532:GrColorInfo::makeColorType\28GrColorType\29\20const +7533:GrColorInfo::isLinearlyBlended\28\29\20const +7534:GrColorFragmentProcessorAnalysis::GrColorFragmentProcessorAnalysis\28GrProcessorAnalysisColor\20const&\2c\20std::__2::unique_ptr>\20const*\2c\20int\29 +7535:GrCaps::~GrCaps\28\29 +7536:GrCaps::surfaceSupportsWritePixels\28GrSurface\20const*\29\20const +7537:GrCaps::getDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\2c\20bool\29\20const +7538:GrCPixmap::GrCPixmap\28GrPixmap\20const&\29 +7539:GrBufferAllocPool::resetCpuData\28unsigned\20long\29 +7540:GrBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\2c\20unsigned\20long*\29 +7541:GrBufferAllocPool::flushCpuData\28GrBufferAllocPool::BufferBlock\20const&\2c\20unsigned\20long\29 +7542:GrBufferAllocPool::destroyBlock\28\29 +7543:GrBufferAllocPool::deleteBlocks\28\29 +7544:GrBufferAllocPool::createBlock\28unsigned\20long\29 +7545:GrBufferAllocPool::CpuBufferCache::makeBuffer\28unsigned\20long\2c\20bool\29 +7546:GrBlurUtils::mask_release_proc\28void*\2c\20void*\29 +7547:GrBlurUtils::draw_shape_with_mask_filter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\29 +7548:GrBlurUtils::draw_mask\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrPaint&&\2c\20GrSurfaceProxyView\29 +7549:GrBlurUtils::create_data\28SkIRect\20const&\2c\20SkIRect\20const&\29 +7550:GrBlurUtils::convolve_gaussian_1d\28skgpu::ganesh::SurfaceFillContext*\2c\20GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\2c\20SkIRect\20const&\2c\20SkAlphaType\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\29 +7551:GrBlurUtils::convolve_gaussian\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20SkIRect\2c\20SkIRect\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkBackingFit\29 +7552:GrBlurUtils::clip_bounds_quick_reject\28SkIRect\20const&\2c\20SkIRect\20const&\29 +7553:GrBlurUtils::\28anonymous\20namespace\29::make_texture_effect\28GrCaps\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20GrSamplerState\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkISize\20const&\29 +7554:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29 +7555:GrBitmapTextGeoProc::addNewViews\28GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\29 +7556:GrBitmapTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29 +7557:GrBicubicEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +7558:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +7559:GrBackendTexture::operator=\28GrBackendTexture\20const&\29 +7560:GrBackendTexture::GrBackendTexture\28int\2c\20int\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\2c\20GrBackendApi\2c\20GrTextureType\2c\20GrGLBackendTextureData\20const&\29 +7561:GrBackendRenderTarget::isProtected\28\29\20const +7562:GrBackendFormatBytesPerBlock\28GrBackendFormat\20const&\29 +7563:GrBackendFormat::operator!=\28GrBackendFormat\20const&\29\20const +7564:GrBackendFormat::makeTexture2D\28\29\20const +7565:GrAuditTrail::opsCombined\28GrOp\20const*\2c\20GrOp\20const*\29 +7566:GrAttachment::ComputeSharedAttachmentUniqueKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\2c\20skgpu::UniqueKey*\29 +7567:GrAttachment::ComputeScratchKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\2c\20skgpu::ScratchKey*\29 +7568:GrAtlasManager::~GrAtlasManager\28\29 +7569:GrAtlasManager::getViews\28skgpu::MaskFormat\2c\20unsigned\20int*\29 +7570:GrAtlasManager::atlasGeneration\28skgpu::MaskFormat\29\20const +7571:GrAppliedClip::visitProxies\28std::__2::function\20const&\29\20const +7572:GrAppliedClip::addCoverageFP\28std::__2::unique_ptr>\29 +7573:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::EventList*\2c\20GrTriangulator::Comparator\20const&\29\20const +7574:GrAATriangulator::connectPartners\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +7575:GrAATriangulator::collapseOverlapRegions\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\2c\20GrAATriangulator::EventComparator\29 +7576:GrAATriangulator::Event*\20SkArenaAlloc::make\28GrAATriangulator::SSEdge*&\2c\20SkPoint&\2c\20unsigned\20char&\29 +7577:GrAAConvexTessellator::~GrAAConvexTessellator\28\29 +7578:GrAAConvexTessellator::quadTo\28SkPoint\20const*\29 +7579:GrAAConvexTessellator::fanRing\28GrAAConvexTessellator::Ring\20const&\29 +7580:GetShortIns +7581:FontMgrRunIterator::~FontMgrRunIterator\28\29 +7582:FontMgrRunIterator::endOfCurrentRun\28\29\20const +7583:FontMgrRunIterator::atEnd\28\29\20const +7584:FindSortableTop\28SkOpContourHead*\29 +7585:FT_Vector_NormLen +7586:FT_Sfnt_Table_Info +7587:FT_Select_Size +7588:FT_Render_Glyph +7589:FT_Remove_Module +7590:FT_Outline_Get_Orientation +7591:FT_Outline_EmboldenXY +7592:FT_Outline_Decompose +7593:FT_Open_Face +7594:FT_New_Library +7595:FT_New_GlyphSlot +7596:FT_Match_Size +7597:FT_GlyphLoader_Reset +7598:FT_GlyphLoader_Prepare +7599:FT_GlyphLoader_CheckSubGlyphs +7600:FT_Get_Var_Design_Coordinates +7601:FT_Get_Postscript_Name +7602:FT_Get_Paint_Layers +7603:FT_Get_PS_Font_Info +7604:FT_Get_Glyph_Name +7605:FT_Get_FSType_Flags +7606:FT_Get_Color_Glyph_ClipBox +7607:FT_Done_Size +7608:FT_Done_Library +7609:FT_Bitmap_Done +7610:FT_Bitmap_Convert +7611:FT_Add_Default_Modules +7612:EllipticalRRectOp::~EllipticalRRectOp\28\29_10849 +7613:EllipticalRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7614:EllipticalRRectOp::EllipticalRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20SkPoint\2c\20bool\29 +7615:EllipseOp::EllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20EllipseOp::DeviceSpaceParams\20const&\2c\20SkStrokeRec\20const&\29 +7616:EllipseGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7617:Dot2AngleType\28float\29 +7618:DecodeVarLenUint8 +7619:DecodeContextMap +7620:DIEllipseOp::~DIEllipseOp\28\29 +7621:DIEllipseOp::DIEllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20DIEllipseOp::DeviceSpaceParams\20const&\2c\20SkMatrix\20const&\29 +7622:CustomXP::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +7623:CustomXP::makeProgramImpl\28\29\20const::Impl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +7624:Cr_z_inflateReset2 +7625:Cr_z_inflateReset +7626:CoverageSetOpXP::onIsEqual\28GrXferProcessor\20const&\29\20const +7627:Convexicator::close\28\29 +7628:Convexicator::addVec\28SkPoint\20const&\29 +7629:Convexicator::addPt\28SkPoint\20const&\29 +7630:ContourIter::next\28\29 +7631:Contour&\20std::__2::vector>::emplace_back\28SkRect&\2c\20int&\2c\20int&\29 +7632:CircularRRectOp::~CircularRRectOp\28\29_10826 +7633:CircularRRectOp::CircularRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +7634:CircleOp::~CircleOp\28\29 +7635:CircleOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +7636:CircleOp::CircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +7637:CircleGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29 +7638:CircleGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7639:CFF::dict_interpreter_t\2c\20CFF::interp_env_t>::interpret\28CFF::cff1_private_dict_values_base_t&\29 +7640:CFF::cs_opset_t\2c\20cff2_path_param_t\2c\20cff2_path_procs_path_t>::process_op\28unsigned\20int\2c\20CFF::cff2_cs_interp_env_t&\2c\20cff2_path_param_t&\29 +7641:CFF::cs_opset_t\2c\20cff2_extents_param_t\2c\20cff2_path_procs_extents_t>::process_op\28unsigned\20int\2c\20CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\29 +7642:CFF::cff_stack_t::cff_stack_t\28\29 +7643:CFF::cff2_cs_interp_env_t::process_vsindex\28\29 +7644:CFF::cff2_cs_interp_env_t::process_blend\28\29 +7645:CFF::cff2_cs_interp_env_t::fetch_op\28\29 +7646:CFF::cff2_cs_interp_env_t::cff2_cs_interp_env_t\28hb_array_t\20const&\2c\20OT::cff2::accelerator_t\20const&\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29 +7647:CFF::cff2_cs_interp_env_t::blend_deltas\28hb_array_t\29\20const +7648:CFF::cff1_top_dict_values_t::init\28\29 +7649:CFF::cff1_cs_interp_env_t::cff1_cs_interp_env_t\28hb_array_t\20const&\2c\20OT::cff1::accelerator_t\20const&\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29 +7650:CFF::biased_subrs_t>>::init\28CFF::Subrs>\20const*\29 +7651:CFF::biased_subrs_t>>::init\28CFF::Subrs>\20const*\29 +7652:CFF::FDSelect::get_fd\28unsigned\20int\29\20const +7653:CFF::FDSelect3_4\2c\20OT::IntType>::sentinel\28\29\20const +7654:CFF::FDSelect3_4\2c\20OT::IntType>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +7655:CFF::FDSelect3_4\2c\20OT::IntType>::get_fd\28unsigned\20int\29\20const +7656:CFF::FDSelect0::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +7657:CFF::Charset::get_glyph\28unsigned\20int\2c\20unsigned\20int\29\20const +7658:CFF::CFF2FDSelect::get_fd\28unsigned\20int\29\20const +7659:ButtCapDashedCircleOp::ButtCapDashedCircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +7660:BrotliTransformDictionaryWord +7661:BrotliEnsureRingBuffer +7662:BrotliDecoderStateCleanupAfterMetablock +7663:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::begin\28\29\20const +7664:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::Item::operator++\28\29 +7665:AutoRestoreInverseness::~AutoRestoreInverseness\28\29 +7666:AutoRestoreInverseness::AutoRestoreInverseness\28GrShape*\2c\20GrStyle\20const&\29 +7667:AutoLayerForImageFilter::addMaskFilterLayer\28SkRect\20const*\29 +7668:AutoLayerForImageFilter::addLayer\28SkPaint\20const&\2c\20SkRect\20const*\2c\20bool\29 +7669:AngleWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\2c\20bool*\29 +7670:AddIntersectTs\28SkOpContour*\2c\20SkOpContour*\2c\20SkOpCoincidence*\29 +7671:ActiveEdgeList::replace\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +7672:ActiveEdgeList::remove\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +7673:ActiveEdgeList::insert\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +7674:ActiveEdgeList::allocate\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +7675:AAT::track::sanitize\28hb_sanitize_context_t*\29\20const +7676:AAT::mortmorx::sanitize\28hb_sanitize_context_t*\29\20const +7677:AAT::mortmorx::sanitize\28hb_sanitize_context_t*\29\20const +7678:AAT::ltag::sanitize\28hb_sanitize_context_t*\29\20const +7679:AAT::ltag::get_language\28unsigned\20int\29\20const +7680:AAT::feat::sanitize\28hb_sanitize_context_t*\29\20const +7681:AAT::ankr::sanitize\28hb_sanitize_context_t*\29\20const +7682:AAT::ankr::get_anchor\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +7683:AAT::TrackData::get_tracking\28void\20const*\2c\20float\29\20const +7684:AAT::Lookup>::get_value_or_null\28unsigned\20int\2c\20unsigned\20int\29\20const +7685:AAT::Lookup>::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +7686:AAT::Lookup>::get_value_or_null\28unsigned\20int\2c\20unsigned\20int\29\20const +7687:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +7688:AAT::KernPair\20const*\20hb_sorted_array_t::bsearch\28AAT::hb_glyph_pair_t\20const&\2c\20AAT::KernPair\20const*\29 +7689:AAT::KernPair\20const&\20OT::SortedArrayOf>>::bsearch\28AAT::hb_glyph_pair_t\20const&\2c\20AAT::KernPair\20const&\29\20const +7690:AAT::ChainSubtable::apply\28AAT::hb_aat_apply_context_t*\29\20const +7691:AAT::ChainSubtable::apply\28AAT::hb_aat_apply_context_t*\29\20const +7692:7473 +7693:7474 +7694:7475 +7695:7476 +7696:7477 +7697:7478 +7698:7479 +7699:7480 +7700:7481 +7701:7482 +7702:7483 +7703:7484 +7704:7485 +7705:7486 +7706:7487 +7707:7488 +7708:7489 +7709:7490 +7710:7491 +7711:7492 +7712:7493 +7713:7494 +7714:7495 +7715:7496 +7716:7497 +7717:7498 +7718:7499 +7719:7500 +7720:7501 +7721:7502 +7722:7503 +7723:7504 +7724:7505 +7725:7506 +7726:7507 +7727:7508 +7728:7509 +7729:7510 +7730:7511 +7731:7512 +7732:7513 +7733:7514 +7734:7515 +7735:7516 +7736:7517 +7737:7518 +7738:7519 +7739:7520 +7740:7521 +7741:7522 +7742:7523 +7743:7524 +7744:7525 +7745:7526 +7746:7527 +7747:7528 +7748:7529 +7749:7530 +7750:7531 +7751:7532 +7752:7533 +7753:7534 +7754:7535 +7755:7536 +7756:7537 +7757:7538 +7758:7539 +7759:7540 +7760:7541 +7761:7542 +7762:7543 +7763:7544 +7764:7545 +7765:7546 +7766:7547 +7767:7548 +7768:7549 +7769:7550 +7770:7551 +7771:7552 +7772:7553 +7773:7554 +7774:7555 +7775:7556 +7776:7557 +7777:7558 +7778:7559 +7779:7560 +7780:7561 +7781:7562 +7782:7563 +7783:7564 +7784:7565 +7785:xyzd50_to_hcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +7786:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +7787:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +7788:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7789:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7790:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7791:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7792:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7793:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7794:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7795:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7796:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7797:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7798:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7799:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7800:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7801:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7802:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7803:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7804:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7805:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7806:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7807:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7808:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7809:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7810:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7811:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7812:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7813:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7814:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7815:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7816:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7817:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7818:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7819:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7820:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7821:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7822:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7823:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7824:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7825:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7826:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7827:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7828:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7829:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7830:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7831:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7832:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7833:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7834:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7835:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7836:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7837:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7838:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7839:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7840:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7841:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7842:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7843:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7844:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7845:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7846:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7847:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7848:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7849:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7850:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7851:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7852:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7853:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7854:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7855:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7856:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7857:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7858:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7859:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7860:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7861:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7862:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7863:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7864:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7865:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7866:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7867:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7868:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7869:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7870:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7871:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7872:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7873:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7874:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7875:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7876:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7877:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7878:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7879:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7880:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7881:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7882:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7883:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7884:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_14679 +7885:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +7886:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29_14525 +7887:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29 +7888:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_14569 +7889:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +7890:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9482 +7891:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +7892:virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7893:virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7894:virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7895:virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +7896:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29_9454 +7897:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29 +7898:virtual\20thunk\20to\20GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +7899:virtual\20thunk\20to\20GrTextureProxy::instantiate\28GrResourceProvider*\29 +7900:virtual\20thunk\20to\20GrTextureProxy::getUniqueKey\28\29\20const +7901:virtual\20thunk\20to\20GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +7902:virtual\20thunk\20to\20GrTextureProxy::callbackDesc\28\29\20const +7903:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29\20const +7904:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29 +7905:virtual\20thunk\20to\20GrTexture::onGpuMemorySize\28\29\20const +7906:virtual\20thunk\20to\20GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +7907:virtual\20thunk\20to\20GrTexture::asTexture\28\29\20const +7908:virtual\20thunk\20to\20GrTexture::asTexture\28\29 +7909:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9298 +7910:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +7911:virtual\20thunk\20to\20GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7912:virtual\20thunk\20to\20GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7913:virtual\20thunk\20to\20GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7914:virtual\20thunk\20to\20GrRenderTargetProxy::callbackDesc\28\29\20const +7915:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29\20const +7916:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29 +7917:virtual\20thunk\20to\20GrRenderTarget::onRelease\28\29 +7918:virtual\20thunk\20to\20GrRenderTarget::onAbandon\28\29 +7919:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29\20const +7920:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29 +7921:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_11929 +7922:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +7923:virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +7924:virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +7925:virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +7926:virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7927:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29_11898 +7928:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29 +7929:virtual\20thunk\20to\20GrGLTexture::onRelease\28\29 +7930:virtual\20thunk\20to\20GrGLTexture::onAbandon\28\29 +7931:virtual\20thunk\20to\20GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7932:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10180 +7933:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +7934:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::onFinalize\28\29 +7935:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29_11871 +7936:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29 +7937:virtual\20thunk\20to\20GrGLRenderTarget::onRelease\28\29 +7938:virtual\20thunk\20to\20GrGLRenderTarget::onGpuMemorySize\28\29\20const +7939:virtual\20thunk\20to\20GrGLRenderTarget::onAbandon\28\29 +7940:virtual\20thunk\20to\20GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7941:virtual\20thunk\20to\20GrGLRenderTarget::backendFormat\28\29\20const +7942:vertices_dispose +7943:vertices_create +7944:unicodePositionBuffer_create +7945:undo +7946:typefaces_filterCoveredCodePoints +7947:typeface_create +7948:tt_vadvance_adjust +7949:tt_slot_init +7950:tt_size_request +7951:tt_size_init +7952:tt_size_done +7953:tt_sbit_decoder_load_png +7954:tt_sbit_decoder_load_compound +7955:tt_sbit_decoder_load_byte_aligned +7956:tt_sbit_decoder_load_bit_aligned +7957:tt_property_set +7958:tt_property_get +7959:tt_name_ascii_from_utf16 +7960:tt_name_ascii_from_other +7961:tt_hadvance_adjust +7962:tt_glyph_load +7963:tt_get_var_blend +7964:tt_get_interface +7965:tt_get_glyph_name +7966:tt_get_cmap_info +7967:tt_get_advances +7968:tt_face_set_sbit_strike +7969:tt_face_load_strike_metrics +7970:tt_face_load_sbit_image +7971:tt_face_load_sbit +7972:tt_face_load_post +7973:tt_face_load_pclt +7974:tt_face_load_os2 +7975:tt_face_load_name +7976:tt_face_load_maxp +7977:tt_face_load_kern +7978:tt_face_load_hmtx +7979:tt_face_load_hhea +7980:tt_face_load_head +7981:tt_face_load_gasp +7982:tt_face_load_font_dir +7983:tt_face_load_cpal +7984:tt_face_load_colr +7985:tt_face_load_cmap +7986:tt_face_load_bhed +7987:tt_face_load_any +7988:tt_face_init +7989:tt_face_get_paint_layers +7990:tt_face_get_paint +7991:tt_face_get_kerning +7992:tt_face_get_colr_layer +7993:tt_face_get_colr_glyph_paint +7994:tt_face_get_colorline_stops +7995:tt_face_get_color_glyph_clipbox +7996:tt_face_free_sbit +7997:tt_face_free_ps_names +7998:tt_face_free_name +7999:tt_face_free_cpal +8000:tt_face_free_colr +8001:tt_face_done +8002:tt_face_colr_blend_layer +8003:tt_driver_init +8004:tt_cmap_unicode_init +8005:tt_cmap_unicode_char_next +8006:tt_cmap_unicode_char_index +8007:tt_cmap_init +8008:tt_cmap8_validate +8009:tt_cmap8_get_info +8010:tt_cmap8_char_next +8011:tt_cmap8_char_index +8012:tt_cmap6_validate +8013:tt_cmap6_get_info +8014:tt_cmap6_char_next +8015:tt_cmap6_char_index +8016:tt_cmap4_validate +8017:tt_cmap4_init +8018:tt_cmap4_get_info +8019:tt_cmap4_char_next +8020:tt_cmap4_char_index +8021:tt_cmap2_validate +8022:tt_cmap2_get_info +8023:tt_cmap2_char_next +8024:tt_cmap2_char_index +8025:tt_cmap14_variants +8026:tt_cmap14_variant_chars +8027:tt_cmap14_validate +8028:tt_cmap14_init +8029:tt_cmap14_get_info +8030:tt_cmap14_done +8031:tt_cmap14_char_variants +8032:tt_cmap14_char_var_isdefault +8033:tt_cmap14_char_var_index +8034:tt_cmap14_char_next +8035:tt_cmap13_validate +8036:tt_cmap13_get_info +8037:tt_cmap13_char_next +8038:tt_cmap13_char_index +8039:tt_cmap12_validate +8040:tt_cmap12_get_info +8041:tt_cmap12_char_next +8042:tt_cmap12_char_index +8043:tt_cmap10_validate +8044:tt_cmap10_get_info +8045:tt_cmap10_char_next +8046:tt_cmap10_char_index +8047:tt_cmap0_validate +8048:tt_cmap0_get_info +8049:tt_cmap0_char_next +8050:tt_cmap0_char_index +8051:textStyle_setWordSpacing +8052:textStyle_setTextBaseline +8053:textStyle_setLocale +8054:textStyle_setLetterSpacing +8055:textStyle_setHeight +8056:textStyle_setHalfLeading +8057:textStyle_setForeground +8058:textStyle_setFontVariations +8059:textStyle_setFontStyle +8060:textStyle_setFontSize +8061:textStyle_setDecorationColor +8062:textStyle_setColor +8063:textStyle_setBackground +8064:textStyle_dispose +8065:textStyle_create +8066:textStyle_copy +8067:textStyle_clearFontFamilies +8068:textStyle_addShadow +8069:textStyle_addFontFeature +8070:textStyle_addFontFamilies +8071:textBoxList_getLength +8072:textBoxList_getBoxAtIndex +8073:textBoxList_dispose +8074:t2_hints_stems +8075:t2_hints_open +8076:t1_make_subfont +8077:t1_hints_stem +8078:t1_hints_open +8079:t1_decrypt +8080:t1_decoder_parse_metrics +8081:t1_decoder_init +8082:t1_decoder_done +8083:t1_cmap_unicode_init +8084:t1_cmap_unicode_char_next +8085:t1_cmap_unicode_char_index +8086:t1_cmap_std_done +8087:t1_cmap_std_char_next +8088:t1_cmap_standard_init +8089:t1_cmap_expert_init +8090:t1_cmap_custom_init +8091:t1_cmap_custom_done +8092:t1_cmap_custom_char_next +8093:t1_cmap_custom_char_index +8094:t1_builder_start_point +8095:swizzle_or_premul\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20SkColorSpaceXformSteps\20const&\29 +8096:surface_renderPicturesOnWorker +8097:surface_renderPictures +8098:surface_rasterizeImageOnWorker +8099:surface_rasterizeImage +8100:surface_onRenderComplete +8101:surface_onRasterizeComplete +8102:surface_dispose +8103:surface_destroy +8104:surface_create +8105:strutStyle_setLeading +8106:strutStyle_setHeight +8107:strutStyle_setHalfLeading +8108:strutStyle_setForceStrutHeight +8109:strutStyle_setFontStyle +8110:strutStyle_setFontFamilies +8111:strutStyle_dispose +8112:strutStyle_create +8113:string_read +8114:std::exception::what\28\29\20const +8115:std::bad_variant_access::what\28\29\20const +8116:std::bad_optional_access::what\28\29\20const +8117:std::bad_array_new_length::what\28\29\20const +8118:std::bad_alloc::what\28\29\20const +8119:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20tm\20const*\2c\20char\2c\20char\29\20const +8120:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20tm\20const*\2c\20char\2c\20char\29\20const +8121:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8122:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8123:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8124:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8125:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8126:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +8127:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8128:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8129:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8130:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8131:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8132:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +8133:std::__2::numpunct::~numpunct\28\29_15488 +8134:std::__2::numpunct::do_truename\28\29\20const +8135:std::__2::numpunct::do_grouping\28\29\20const +8136:std::__2::numpunct::do_falsename\28\29\20const +8137:std::__2::numpunct::~numpunct\28\29_15495 +8138:std::__2::numpunct::do_truename\28\29\20const +8139:std::__2::numpunct::do_thousands_sep\28\29\20const +8140:std::__2::numpunct::do_grouping\28\29\20const +8141:std::__2::numpunct::do_falsename\28\29\20const +8142:std::__2::numpunct::do_decimal_point\28\29\20const +8143:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20void\20const*\29\20const +8144:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\29\20const +8145:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\20long\29\20const +8146:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\29\20const +8147:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20long\29\20const +8148:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +8149:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20double\29\20const +8150:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20bool\29\20const +8151:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20void\20const*\29\20const +8152:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\29\20const +8153:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\20long\29\20const +8154:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\29\20const +8155:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20long\29\20const +8156:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +8157:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20double\29\20const +8158:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20bool\29\20const +8159:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +8160:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +8161:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +8162:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +8163:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8164:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +8165:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +8166:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +8167:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +8168:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +8169:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +8170:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +8171:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +8172:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8173:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +8174:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +8175:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +8176:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +8177:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8178:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +8179:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8180:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +8181:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +8182:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8183:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +8184:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8185:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8186:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8187:std::__2::locale::__imp::~__imp\28\29_15593 +8188:std::__2::ios_base::~ios_base\28\29_14688 +8189:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +8190:std::__2::ctype::do_toupper\28wchar_t\29\20const +8191:std::__2::ctype::do_toupper\28wchar_t*\2c\20wchar_t\20const*\29\20const +8192:std::__2::ctype::do_tolower\28wchar_t\29\20const +8193:std::__2::ctype::do_tolower\28wchar_t*\2c\20wchar_t\20const*\29\20const +8194:std::__2::ctype::do_scan_not\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8195:std::__2::ctype::do_scan_is\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8196:std::__2::ctype::do_narrow\28wchar_t\2c\20char\29\20const +8197:std::__2::ctype::do_narrow\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20char\2c\20char*\29\20const +8198:std::__2::ctype::do_is\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20unsigned\20long*\29\20const +8199:std::__2::ctype::do_is\28unsigned\20long\2c\20wchar_t\29\20const +8200:std::__2::ctype::~ctype\28\29_15580 +8201:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +8202:std::__2::ctype::do_toupper\28char\29\20const +8203:std::__2::ctype::do_toupper\28char*\2c\20char\20const*\29\20const +8204:std::__2::ctype::do_tolower\28char\29\20const +8205:std::__2::ctype::do_tolower\28char*\2c\20char\20const*\29\20const +8206:std::__2::ctype::do_narrow\28char\2c\20char\29\20const +8207:std::__2::ctype::do_narrow\28char\20const*\2c\20char\20const*\2c\20char\2c\20char*\29\20const +8208:std::__2::collate::do_transform\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8209:std::__2::collate::do_hash\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8210:std::__2::collate::do_compare\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8211:std::__2::collate::do_transform\28char\20const*\2c\20char\20const*\29\20const +8212:std::__2::collate::do_hash\28char\20const*\2c\20char\20const*\29\20const +8213:std::__2::collate::do_compare\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +8214:std::__2::codecvt::~codecvt\28\29_15540 +8215:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const +8216:std::__2::codecvt::do_out\28__mbstate_t&\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +8217:std::__2::codecvt::do_max_length\28\29\20const +8218:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +8219:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20wchar_t*\2c\20wchar_t*\2c\20wchar_t*&\29\20const +8220:std::__2::codecvt::do_encoding\28\29\20const +8221:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +8222:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29_14673 +8223:std::__2::basic_stringbuf\2c\20std::__2::allocator>::underflow\28\29 +8224:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +8225:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +8226:std::__2::basic_stringbuf\2c\20std::__2::allocator>::pbackfail\28int\29 +8227:std::__2::basic_stringbuf\2c\20std::__2::allocator>::overflow\28int\29 +8228:std::__2::basic_streambuf>::~basic_streambuf\28\29_14480 +8229:std::__2::basic_streambuf>::xsputn\28char\20const*\2c\20long\29 +8230:std::__2::basic_streambuf>::xsgetn\28char*\2c\20long\29 +8231:std::__2::basic_streambuf>::uflow\28\29 +8232:std::__2::basic_streambuf>::setbuf\28char*\2c\20long\29 +8233:std::__2::basic_streambuf>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +8234:std::__2::basic_streambuf>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +8235:std::__2::bad_function_call::what\28\29\20const +8236:std::__2::__time_get_c_storage::__x\28\29\20const +8237:std::__2::__time_get_c_storage::__weeks\28\29\20const +8238:std::__2::__time_get_c_storage::__r\28\29\20const +8239:std::__2::__time_get_c_storage::__months\28\29\20const +8240:std::__2::__time_get_c_storage::__c\28\29\20const +8241:std::__2::__time_get_c_storage::__am_pm\28\29\20const +8242:std::__2::__time_get_c_storage::__X\28\29\20const +8243:std::__2::__time_get_c_storage::__x\28\29\20const +8244:std::__2::__time_get_c_storage::__weeks\28\29\20const +8245:std::__2::__time_get_c_storage::__r\28\29\20const +8246:std::__2::__time_get_c_storage::__months\28\29\20const +8247:std::__2::__time_get_c_storage::__c\28\29\20const +8248:std::__2::__time_get_c_storage::__am_pm\28\29\20const +8249:std::__2::__time_get_c_storage::__X\28\29\20const +8250:std::__2::__shared_ptr_pointer<_IO_FILE*\2c\20void\20\28*\29\28_IO_FILE*\29\2c\20std::__2::allocator<_IO_FILE>>::__on_zero_shared\28\29 +8251:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7049 +8252:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8253:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +8254:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7322 +8255:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8256:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +8257:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7562 +8258:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8259:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +8260:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_5515 +8261:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8262:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8263:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8264:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8265:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8266:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8267:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8268:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8269:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8270:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8271:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8272:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8273:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8274:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8275:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8276:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8277:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8278:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8279:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8280:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +8281:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8282:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +8283:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +8284:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8285:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +8286:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8287:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8288:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8289:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8290:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8291:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8292:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8293:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8294:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8295:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8296:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8297:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8298:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8299:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8300:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8301:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8302:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8303:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8304:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8305:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8306:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8307:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8308:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8309:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8310:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8311:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8312:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8313:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8314:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8315:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8316:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8317:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8318:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8319:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8320:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8321:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8322:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8323:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8324:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8325:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20float&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20SkPoint&&\2c\20SkPoint&&\2c\20skia::textlayout::InternalLineMetrics&&\2c\20bool&&\29 +8326:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>*\29\20const +8327:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28\29\20const +8328:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::operator\28\29\28skia::textlayout::Cluster*&&\29 +8329:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28std::__2::__function::__base*\29\20const +8330:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28\29\20const +8331:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8332:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28\29\20const +8333:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20SkSpan&&\2c\20float&\2c\20unsigned\20long&&\2c\20unsigned\20char&&\29 +8334:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28std::__2::__function::__base\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>*\29\20const +8335:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28\29\20const +8336:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::operator\28\29\28skia::textlayout::Block&&\2c\20skia_private::TArray&&\29 +8337:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28std::__2::__function::__base\29>*\29\20const +8338:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28\29\20const +8339:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::operator\28\29\28sk_sp&&\29 +8340:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28std::__2::__function::__base\29>*\29\20const +8341:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28\29\20const +8342:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::operator\28\29\28skia::textlayout::SkRange&&\29 +8343:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28std::__2::__function::__base\29>*\29\20const +8344:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28\29\20const +8345:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +8346:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +8347:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +8348:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29_9608 +8349:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::operator\28\29\28void*&&\2c\20void\20const*&&\29 +8350:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy_deallocate\28\29 +8351:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy\28\29 +8352:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8353:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28\29\20const +8354:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8355:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8356:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8357:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8358:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8359:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8360:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +8361:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8362:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8363:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +8364:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8365:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8366:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +8367:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8368:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8369:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +8370:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +8371:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +8372:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::operator\28\29\28sktext::gpu::GlyphVector*&&\2c\20int&&\2c\20int&&\2c\20skgpu::MaskFormat&&\2c\20int&&\29 +8373:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28std::__2::__function::__base\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>*\29\20const +8374:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28\29\20const +8375:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::operator\28\29\28GrSurfaceProxy\20const*&&\29 +8376:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8377:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28\29\20const +8378:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +8379:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +8380:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +8381:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +8382:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +8383:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +8384:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +8385:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8386:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +8387:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8388:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8389:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8390:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8391:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +8392:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8393:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8394:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::operator\28\29\28\29 +8395:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8396:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28\29\20const +8397:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8398:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8399:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8400:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8401:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8402:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8403:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8404:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8405:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8406:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8407:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8408:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8409:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8410:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8411:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8412:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8413:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8414:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8415:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8416:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29_4242 +8417:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +8418:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy_deallocate\28\29 +8419:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy\28\29 +8420:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8421:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8422:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +8423:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8424:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +8425:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8426:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8427:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8428:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8429:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8430:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8431:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::operator\28\29\28SkSL::Variable\20const&\29 +8432:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8433:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28\29\20const +8434:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::operator\28\29\28int&&\2c\20SkSL::Variable\20const*&&\2c\20SkSL::Expression\20const*&&\29 +8435:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8436:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28\29\20const +8437:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::operator\28\29\28unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\29 +8438:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +8439:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +8440:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +8441:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +8442:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::operator\28\29\28SkVertices\20const*&&\2c\20SkBlendMode&&\2c\20SkPaint\20const&\2c\20float&&\2c\20float&&\2c\20bool&&\29 +8443:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8444:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28\29\20const +8445:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::operator\28\29\28SkIRect\20const&\29 +8446:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8447:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28\29\20const +8448:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9512 +8449:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8450:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +8451:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +8452:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8453:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8454:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9242 +8455:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8456:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +8457:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +8458:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8459:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8460:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9233 +8461:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8462:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +8463:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +8464:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8465:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8466:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::operator\28\29\28GrTextureProxy*&&\2c\20SkIRect&&\2c\20GrColorType&&\2c\20void\20const*&&\2c\20unsigned\20long&&\29 +8467:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +8468:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28\29\20const +8469:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::operator\28\29\28GrBackendTexture&&\29 +8470:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28\29\20const +8471:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8472:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8473:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8474:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8475:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8476:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8477:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8478:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8479:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8480:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8481:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8482:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8483:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8484:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8485:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8486:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8487:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8488:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8489:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29_8757 +8490:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +8491:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +8492:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29_8769 +8493:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +8494:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +8495:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +8496:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +8497:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +8498:srgb_to_hwb\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +8499:srcover_p\28unsigned\20char\2c\20unsigned\20char\29 +8500:sn_write +8501:skwasm_isMultiThreaded +8502:sktext::gpu::post_purge_blob_message\28unsigned\20int\2c\20unsigned\20int\29 +8503:sktext::gpu::TextBlob::~TextBlob\28\29_12197 +8504:sktext::gpu::SlugImpl::~SlugImpl\28\29_12048 +8505:sktext::gpu::SlugImpl::sourceBounds\28\29\20const +8506:sktext::gpu::SlugImpl::sourceBoundsWithOrigin\28\29\20const +8507:sktext::gpu::SlugImpl::doFlatten\28SkWriteBuffer&\29\20const +8508:sktext::gpu::SDFMaskFilterImpl::getTypeName\28\29\20const +8509:sktext::gpu::SDFMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +8510:sktext::gpu::SDFMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +8511:skif::\28anonymous\20namespace\29::RasterBackend::~RasterBackend\28\29 +8512:skif::\28anonymous\20namespace\29::RasterBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +8513:skif::\28anonymous\20namespace\29::RasterBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +8514:skif::\28anonymous\20namespace\29::RasterBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +8515:skif::\28anonymous\20namespace\29::RasterBackend::getBlurEngine\28\29\20const +8516:skif::\28anonymous\20namespace\29::GaneshBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +8517:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +8518:skif::\28anonymous\20namespace\29::GaneshBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +8519:skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +8520:skia_png_zfree +8521:skia_png_zalloc +8522:skia_png_set_read_fn +8523:skia_png_set_expand_gray_1_2_4_to_8 +8524:skia_png_read_start_row +8525:skia_png_read_finish_row +8526:skia_png_handle_zTXt +8527:skia_png_handle_unknown +8528:skia_png_handle_tRNS +8529:skia_png_handle_tIME +8530:skia_png_handle_tEXt +8531:skia_png_handle_sRGB +8532:skia_png_handle_sPLT +8533:skia_png_handle_sCAL +8534:skia_png_handle_sBIT +8535:skia_png_handle_pHYs +8536:skia_png_handle_pCAL +8537:skia_png_handle_oFFs +8538:skia_png_handle_iTXt +8539:skia_png_handle_iCCP +8540:skia_png_handle_hIST +8541:skia_png_handle_gAMA +8542:skia_png_handle_cHRM +8543:skia_png_handle_bKGD +8544:skia_png_handle_PLTE +8545:skia_png_handle_IHDR +8546:skia_png_handle_IEND +8547:skia_png_get_IHDR +8548:skia_png_do_read_transformations +8549:skia_png_destroy_read_struct +8550:skia_png_default_read_data +8551:skia_png_create_png_struct +8552:skia_png_combine_row +8553:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29_7495 +8554:skia::textlayout::TypefaceFontStyleSet::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +8555:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29_7502 +8556:skia::textlayout::TypefaceFontProvider::onMatchFamily\28char\20const*\29\20const +8557:skia::textlayout::TypefaceFontProvider::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +8558:skia::textlayout::TypefaceFontProvider::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +8559:skia::textlayout::TypefaceFontProvider::onGetFamilyName\28int\2c\20SkString*\29\20const +8560:skia::textlayout::TypefaceFontProvider::onCreateStyleSet\28int\29\20const +8561:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29_7415 +8562:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8563:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8564:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29_7160 +8565:skia::textlayout::ParagraphImpl::visit\28std::__2::function\20const&\29 +8566:skia::textlayout::ParagraphImpl::updateTextAlign\28skia::textlayout::TextAlign\29 +8567:skia::textlayout::ParagraphImpl::updateForegroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +8568:skia::textlayout::ParagraphImpl::updateFontSize\28unsigned\20long\2c\20unsigned\20long\2c\20float\29 +8569:skia::textlayout::ParagraphImpl::updateBackgroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +8570:skia::textlayout::ParagraphImpl::unresolvedGlyphs\28\29 +8571:skia::textlayout::ParagraphImpl::unresolvedCodepoints\28\29 +8572:skia::textlayout::ParagraphImpl::paint\28SkCanvas*\2c\20float\2c\20float\29 +8573:skia::textlayout::ParagraphImpl::markDirty\28\29 +8574:skia::textlayout::ParagraphImpl::lineNumber\28\29 +8575:skia::textlayout::ParagraphImpl::layout\28float\29 +8576:skia::textlayout::ParagraphImpl::getWordBoundary\28unsigned\20int\29 +8577:skia::textlayout::ParagraphImpl::getRectsForRange\28unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +8578:skia::textlayout::ParagraphImpl::getRectsForPlaceholders\28\29 +8579:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +8580:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29 +8581:skia::textlayout::ParagraphImpl::getLineNumberAtUTF16Offset\28unsigned\20long\29 +8582:skia::textlayout::ParagraphImpl::getLineMetrics\28std::__2::vector>&\29 +8583:skia::textlayout::ParagraphImpl::getLineMetricsAt\28int\2c\20skia::textlayout::LineMetrics*\29\20const +8584:skia::textlayout::ParagraphImpl::getFonts\28\29\20const +8585:skia::textlayout::ParagraphImpl::getFontAt\28unsigned\20long\29\20const +8586:skia::textlayout::ParagraphImpl::getFontAtUTF16Offset\28unsigned\20long\29 +8587:skia::textlayout::ParagraphImpl::getClosestUTF16GlyphInfoAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +8588:skia::textlayout::ParagraphImpl::getClosestGlyphClusterAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +8589:skia::textlayout::ParagraphImpl::getActualTextRange\28int\2c\20bool\29\20const +8590:skia::textlayout::ParagraphImpl::extendedVisit\28std::__2::function\20const&\29 +8591:skia::textlayout::ParagraphImpl::containsEmoji\28SkTextBlob*\29 +8592:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29::$_0::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +8593:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29 +8594:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29_7061 +8595:skia::textlayout::ParagraphBuilderImpl::setWordsUtf8\28std::__2::vector>\29 +8596:skia::textlayout::ParagraphBuilderImpl::setWordsUtf16\28std::__2::vector>\29 +8597:skia::textlayout::ParagraphBuilderImpl::setLineBreaksUtf8\28std::__2::vector>\29 +8598:skia::textlayout::ParagraphBuilderImpl::setLineBreaksUtf16\28std::__2::vector>\29 +8599:skia::textlayout::ParagraphBuilderImpl::setGraphemeBreaksUtf8\28std::__2::vector>\29 +8600:skia::textlayout::ParagraphBuilderImpl::setGraphemeBreaksUtf16\28std::__2::vector>\29 +8601:skia::textlayout::ParagraphBuilderImpl::pushStyle\28skia::textlayout::TextStyle\20const&\29 +8602:skia::textlayout::ParagraphBuilderImpl::pop\28\29 +8603:skia::textlayout::ParagraphBuilderImpl::peekStyle\28\29 +8604:skia::textlayout::ParagraphBuilderImpl::getText\28\29 +8605:skia::textlayout::ParagraphBuilderImpl::getParagraphStyle\28\29\20const +8606:skia::textlayout::ParagraphBuilderImpl::getClientICUData\28\29\20const +8607:skia::textlayout::ParagraphBuilderImpl::addText\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +8608:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\2c\20unsigned\20long\29 +8609:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\29 +8610:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\29 +8611:skia::textlayout::ParagraphBuilderImpl::SetUnicode\28sk_sp\29 +8612:skia::textlayout::ParagraphBuilderImpl::Reset\28\29 +8613:skia::textlayout::ParagraphBuilderImpl::Build\28\29 +8614:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29_7243 +8615:skia::textlayout::OneLineShaper::~OneLineShaper\28\29_7041 +8616:skia::textlayout::OneLineShaper::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8617:skia::textlayout::OneLineShaper::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8618:skia::textlayout::LangIterator::~LangIterator\28\29_7029 +8619:skia::textlayout::LangIterator::~LangIterator\28\29 +8620:skia::textlayout::LangIterator::endOfCurrentRun\28\29\20const +8621:skia::textlayout::LangIterator::currentLanguage\28\29\20const +8622:skia::textlayout::LangIterator::consume\28\29 +8623:skia::textlayout::LangIterator::atEnd\28\29\20const +8624:skia::textlayout::FontCollection::~FontCollection\28\29_6892 +8625:skia::textlayout::CanvasParagraphPainter::translate\28float\2c\20float\29 +8626:skia::textlayout::CanvasParagraphPainter::save\28\29 +8627:skia::textlayout::CanvasParagraphPainter::restore\28\29 +8628:skia::textlayout::CanvasParagraphPainter::drawTextShadow\28sk_sp\20const&\2c\20float\2c\20float\2c\20unsigned\20int\2c\20float\29 +8629:skia::textlayout::CanvasParagraphPainter::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20std::__2::variant\20const&\29 +8630:skia::textlayout::CanvasParagraphPainter::drawRect\28SkRect\20const&\2c\20std::__2::variant\20const&\29 +8631:skia::textlayout::CanvasParagraphPainter::drawPath\28SkPath\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +8632:skia::textlayout::CanvasParagraphPainter::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +8633:skia::textlayout::CanvasParagraphPainter::drawFilledRect\28SkRect\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +8634:skia::textlayout::CanvasParagraphPainter::clipRect\28SkRect\20const&\29 +8635:skgpu::tess::FixedCountWedges::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8636:skgpu::tess::FixedCountWedges::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8637:skgpu::tess::FixedCountStrokes::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8638:skgpu::tess::FixedCountCurves::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8639:skgpu::ganesh::texture_proxy_view_from_planes\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20skgpu::Budgeted\29::$_0::__invoke\28void*\2c\20void*\29 +8640:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29_11170 +8641:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::visitProxies\28std::__2::function\20const&\29\20const +8642:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8643:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8644:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8645:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::name\28\29\20const +8646:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::fixedFunctionFlags\28\29\20const +8647:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8648:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::name\28\29\20const +8649:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8650:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8651:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8652:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8653:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29_11035 +8654:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::name\28\29\20const +8655:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8656:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8657:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29_10415 +8658:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +8659:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8660:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8661:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8662:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8663:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::name\28\29\20const +8664:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::fixedFunctionFlags\28\29\20const +8665:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8666:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29_10322 +8667:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +8668:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8669:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8670:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8671:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8672:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::name\28\29\20const +8673:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8674:skgpu::ganesh::TriangulatingPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8675:skgpu::ganesh::TriangulatingPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8676:skgpu::ganesh::TriangulatingPathRenderer::name\28\29\20const +8677:skgpu::ganesh::TessellationPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +8678:skgpu::ganesh::TessellationPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +8679:skgpu::ganesh::TessellationPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8680:skgpu::ganesh::TessellationPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8681:skgpu::ganesh::TessellationPathRenderer::name\28\29\20const +8682:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29 +8683:skgpu::ganesh::SurfaceDrawContext::willReplaceOpsTask\28skgpu::ganesh::OpsTask*\2c\20skgpu::ganesh::OpsTask*\29 +8684:skgpu::ganesh::SurfaceDrawContext::canDiscardPreviousOpsOnFullClear\28\29\20const +8685:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29_8717 +8686:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +8687:skgpu::ganesh::SurfaceContext::asyncReadPixels\28GrDirectContext*\2c\20SkIRect\20const&\2c\20SkColorType\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +8688:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29_11230 +8689:skgpu::ganesh::StrokeTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +8690:skgpu::ganesh::StrokeTessellateOp::usesStencil\28\29\20const +8691:skgpu::ganesh::StrokeTessellateOp::onPrepare\28GrOpFlushState*\29 +8692:skgpu::ganesh::StrokeTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8693:skgpu::ganesh::StrokeTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8694:skgpu::ganesh::StrokeTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8695:skgpu::ganesh::StrokeTessellateOp::name\28\29\20const +8696:skgpu::ganesh::StrokeTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8697:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29_11207 +8698:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +8699:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::programInfo\28\29 +8700:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8701:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8702:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8703:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::name\28\29\20const +8704:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8705:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29_11217 +8706:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +8707:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::programInfo\28\29 +8708:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8709:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8710:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8711:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8712:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::name\28\29\20const +8713:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8714:skgpu::ganesh::StencilClip::~StencilClip\28\29_9575 +8715:skgpu::ganesh::StencilClip::~StencilClip\28\29 +8716:skgpu::ganesh::StencilClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +8717:skgpu::ganesh::StencilClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +8718:skgpu::ganesh::SoftwarePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8719:skgpu::ganesh::SoftwarePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8720:skgpu::ganesh::SoftwarePathRenderer::name\28\29\20const +8721:skgpu::ganesh::SmallPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8722:skgpu::ganesh::SmallPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8723:skgpu::ganesh::SmallPathRenderer::name\28\29\20const +8724:skgpu::ganesh::SmallPathAtlasMgr::postFlush\28skgpu::AtlasToken\29 +8725:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29_11117 +8726:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8727:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::programInfo\28\29 +8728:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8729:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8730:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8731:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8732:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::name\28\29\20const +8733:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8734:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_quad_generic\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8735:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8736:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8737:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8738:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8739:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8740:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8741:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8742:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29_11106 +8743:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::onTextureSampler\28int\29\20const +8744:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::name\28\29\20const +8745:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8746:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8747:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8748:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8749:skgpu::ganesh::PathWedgeTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +8750:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29_11090 +8751:skgpu::ganesh::PathTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +8752:skgpu::ganesh::PathTessellateOp::usesStencil\28\29\20const +8753:skgpu::ganesh::PathTessellateOp::onPrepare\28GrOpFlushState*\29 +8754:skgpu::ganesh::PathTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8755:skgpu::ganesh::PathTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8756:skgpu::ganesh::PathTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8757:skgpu::ganesh::PathTessellateOp::name\28\29\20const +8758:skgpu::ganesh::PathTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8759:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29_11080 +8760:skgpu::ganesh::PathStencilCoverOp::visitProxies\28std::__2::function\20const&\29\20const +8761:skgpu::ganesh::PathStencilCoverOp::onPrepare\28GrOpFlushState*\29 +8762:skgpu::ganesh::PathStencilCoverOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8763:skgpu::ganesh::PathStencilCoverOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8764:skgpu::ganesh::PathStencilCoverOp::name\28\29\20const +8765:skgpu::ganesh::PathStencilCoverOp::fixedFunctionFlags\28\29\20const +8766:skgpu::ganesh::PathStencilCoverOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8767:skgpu::ganesh::PathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +8768:skgpu::ganesh::PathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +8769:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29_11056 +8770:skgpu::ganesh::PathInnerTriangulateOp::visitProxies\28std::__2::function\20const&\29\20const +8771:skgpu::ganesh::PathInnerTriangulateOp::onPrepare\28GrOpFlushState*\29 +8772:skgpu::ganesh::PathInnerTriangulateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8773:skgpu::ganesh::PathInnerTriangulateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8774:skgpu::ganesh::PathInnerTriangulateOp::name\28\29\20const +8775:skgpu::ganesh::PathInnerTriangulateOp::fixedFunctionFlags\28\29\20const +8776:skgpu::ganesh::PathInnerTriangulateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8777:skgpu::ganesh::PathCurveTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +8778:skgpu::ganesh::OpsTask::~OpsTask\28\29_10976 +8779:skgpu::ganesh::OpsTask::onPrepare\28GrOpFlushState*\29 +8780:skgpu::ganesh::OpsTask::onPrePrepare\28GrRecordingContext*\29 +8781:skgpu::ganesh::OpsTask::onMakeSkippable\28\29 +8782:skgpu::ganesh::OpsTask::onIsUsed\28GrSurfaceProxy*\29\20const +8783:skgpu::ganesh::OpsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +8784:skgpu::ganesh::OpsTask::endFlush\28GrDrawingManager*\29 +8785:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29_10945 +8786:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::visitProxies\28std::__2::function\20const&\29\20const +8787:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8788:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8789:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8790:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8791:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::name\28\29\20const +8792:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8793:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29_10958 +8794:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::onTextureSampler\28int\29\20const +8795:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::name\28\29\20const +8796:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8797:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8798:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8799:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8800:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29_10762 +8801:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8802:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::programInfo\28\29 +8803:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8804:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8805:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8806:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8807:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::name\28\29\20const +8808:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8809:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::clipToShape\28skgpu::ganesh::SurfaceDrawContext*\2c\20SkClipOp\2c\20SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\29 +8810:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29_10780 +8811:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29 +8812:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::name\28\29\20const +8813:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8814:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8815:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8816:skgpu::ganesh::DrawableOp::~DrawableOp\28\29_10751 +8817:skgpu::ganesh::DrawableOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8818:skgpu::ganesh::DrawableOp::name\28\29\20const +8819:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29_10658 +8820:skgpu::ganesh::DrawAtlasPathOp::visitProxies\28std::__2::function\20const&\29\20const +8821:skgpu::ganesh::DrawAtlasPathOp::onPrepare\28GrOpFlushState*\29 +8822:skgpu::ganesh::DrawAtlasPathOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8823:skgpu::ganesh::DrawAtlasPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8824:skgpu::ganesh::DrawAtlasPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8825:skgpu::ganesh::DrawAtlasPathOp::name\28\29\20const +8826:skgpu::ganesh::DrawAtlasPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8827:skgpu::ganesh::Device::~Device\28\29_8075 +8828:skgpu::ganesh::Device::strikeDeviceInfo\28\29\20const +8829:skgpu::ganesh::Device::snapSpecial\28SkIRect\20const&\2c\20bool\29 +8830:skgpu::ganesh::Device::snapSpecialScaled\28SkIRect\20const&\2c\20SkISize\20const&\29 +8831:skgpu::ganesh::Device::replaceClip\28SkIRect\20const&\29 +8832:skgpu::ganesh::Device::recordingContext\28\29\20const +8833:skgpu::ganesh::Device::pushClipStack\28\29 +8834:skgpu::ganesh::Device::popClipStack\28\29 +8835:skgpu::ganesh::Device::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +8836:skgpu::ganesh::Device::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +8837:skgpu::ganesh::Device::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +8838:skgpu::ganesh::Device::onClipShader\28sk_sp\29 +8839:skgpu::ganesh::Device::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +8840:skgpu::ganesh::Device::makeSpecial\28SkImage\20const*\29 +8841:skgpu::ganesh::Device::isClipWideOpen\28\29\20const +8842:skgpu::ganesh::Device::isClipRect\28\29\20const +8843:skgpu::ganesh::Device::isClipEmpty\28\29\20const +8844:skgpu::ganesh::Device::isClipAntiAliased\28\29\20const +8845:skgpu::ganesh::Device::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +8846:skgpu::ganesh::Device::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8847:skgpu::ganesh::Device::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +8848:skgpu::ganesh::Device::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +8849:skgpu::ganesh::Device::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +8850:skgpu::ganesh::Device::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +8851:skgpu::ganesh::Device::drawPaint\28SkPaint\20const&\29 +8852:skgpu::ganesh::Device::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +8853:skgpu::ganesh::Device::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +8854:skgpu::ganesh::Device::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8855:skgpu::ganesh::Device::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +8856:skgpu::ganesh::Device::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +8857:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8858:skgpu::ganesh::Device::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +8859:skgpu::ganesh::Device::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +8860:skgpu::ganesh::Device::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +8861:skgpu::ganesh::Device::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +8862:skgpu::ganesh::Device::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8863:skgpu::ganesh::Device::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +8864:skgpu::ganesh::Device::devClipBounds\28\29\20const +8865:skgpu::ganesh::Device::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +8866:skgpu::ganesh::Device::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +8867:skgpu::ganesh::Device::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +8868:skgpu::ganesh::Device::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +8869:skgpu::ganesh::Device::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +8870:skgpu::ganesh::Device::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +8871:skgpu::ganesh::Device::android_utils_clipWithStencil\28\29 +8872:skgpu::ganesh::DefaultPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +8873:skgpu::ganesh::DefaultPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +8874:skgpu::ganesh::DefaultPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8875:skgpu::ganesh::DefaultPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8876:skgpu::ganesh::DefaultPathRenderer::name\28\29\20const +8877:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::name\28\29\20const +8878:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8879:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8880:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8881:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::name\28\29\20const +8882:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8883:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8884:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8885:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29_10556 +8886:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8887:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::programInfo\28\29 +8888:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8889:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8890:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8891:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8892:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::name\28\29\20const +8893:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::fixedFunctionFlags\28\29\20const +8894:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8895:skgpu::ganesh::DashLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8896:skgpu::ganesh::DashLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8897:skgpu::ganesh::DashLinePathRenderer::name\28\29\20const +8898:skgpu::ganesh::ClipStack::~ClipStack\28\29_7967 +8899:skgpu::ganesh::ClipStack::preApply\28SkRect\20const&\2c\20GrAA\29\20const +8900:skgpu::ganesh::ClipStack::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +8901:skgpu::ganesh::ClearOp::~ClearOp\28\29 +8902:skgpu::ganesh::ClearOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8903:skgpu::ganesh::ClearOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8904:skgpu::ganesh::ClearOp::name\28\29\20const +8905:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29_10497 +8906:skgpu::ganesh::AtlasTextOp::visitProxies\28std::__2::function\20const&\29\20const +8907:skgpu::ganesh::AtlasTextOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8908:skgpu::ganesh::AtlasTextOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8909:skgpu::ganesh::AtlasTextOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8910:skgpu::ganesh::AtlasTextOp::name\28\29\20const +8911:skgpu::ganesh::AtlasTextOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8912:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29_10483 +8913:skgpu::ganesh::AtlasRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +8914:skgpu::ganesh::AtlasRenderTask::onExecute\28GrOpFlushState*\29 +8915:skgpu::ganesh::AtlasPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8916:skgpu::ganesh::AtlasPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8917:skgpu::ganesh::AtlasPathRenderer::name\28\29\20const +8918:skgpu::ganesh::AALinearizingConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8919:skgpu::ganesh::AALinearizingConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8920:skgpu::ganesh::AALinearizingConvexPathRenderer::name\28\29\20const +8921:skgpu::ganesh::AAHairLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8922:skgpu::ganesh::AAHairLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8923:skgpu::ganesh::AAHairLinePathRenderer::name\28\29\20const +8924:skgpu::ganesh::AAConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8925:skgpu::ganesh::AAConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8926:skgpu::ganesh::AAConvexPathRenderer::name\28\29\20const +8927:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29_9603 +8928:skgpu::TAsyncReadResult::rowBytes\28int\29\20const +8929:skgpu::TAsyncReadResult::data\28int\29\20const +8930:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29_9207 +8931:skgpu::StringKeyBuilder::appendComment\28char\20const*\29 +8932:skgpu::StringKeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +8933:skgpu::ShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\2c\20bool\29 +8934:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29_11982 +8935:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29 +8936:skgpu::RectanizerSkyline::percentFull\28\29\20const +8937:skgpu::RectanizerPow2::reset\28\29 +8938:skgpu::RectanizerPow2::percentFull\28\29\20const +8939:skgpu::RectanizerPow2::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +8940:skgpu::Plot::~Plot\28\29_11973 +8941:skgpu::KeyBuilder::~KeyBuilder\28\29 +8942:skgpu::DefaultShaderErrorHandler\28\29::DefaultShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\29 +8943:sk_mmap_releaseproc\28void\20const*\2c\20void*\29 +8944:sk_ft_stream_io\28FT_StreamRec_*\2c\20unsigned\20long\2c\20unsigned\20char*\2c\20unsigned\20long\29 +8945:sk_ft_realloc\28FT_MemoryRec_*\2c\20long\2c\20long\2c\20void*\29 +8946:sk_fclose\28_IO_FILE*\29 +8947:skString_getLength +8948:skString_getData +8949:skString_free +8950:skString_allocate +8951:skString16_getData +8952:skString16_free +8953:skString16_allocate +8954:skData_dispose +8955:skData_create +8956:shader_createSweepGradient +8957:shader_createRuntimeEffectShader +8958:shader_createRadialGradient +8959:shader_createLinearGradient +8960:shader_createFromImage +8961:shader_createConicalGradient +8962:sfnt_table_info +8963:sfnt_load_face +8964:sfnt_is_postscript +8965:sfnt_is_alphanumeric +8966:sfnt_init_face +8967:sfnt_get_ps_name +8968:sfnt_get_name_index +8969:sfnt_get_interface +8970:sfnt_get_glyph_name +8971:sfnt_get_charset_id +8972:sfnt_done_face +8973:setup_syllables_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8974:setup_syllables_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8975:setup_syllables_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8976:setup_syllables_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8977:setup_masks_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8978:setup_masks_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8979:setup_masks_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8980:setup_masks_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8981:setup_masks_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8982:setup_masks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8983:runtimeEffect_getUniformSize +8984:runtimeEffect_create +8985:run_js_func +8986:reverse_hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +8987:reverse_hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +8988:reorder_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8989:reorder_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8990:reorder_marks_hebrew\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +8991:reorder_marks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +8992:reorder_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8993:release_data\28void*\2c\20void*\29 +8994:rect_memcpy\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20SkColorSpaceXformSteps\20const&\29 +8995:record_stch\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8996:record_rphf_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8997:record_pref_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8998:receive_notification +8999:read_data_from_FT_Stream +9000:pthread_self +9001:psnames_get_service +9002:pshinter_get_t2_funcs +9003:pshinter_get_t1_funcs +9004:pshinter_get_globals_funcs +9005:psh_globals_new +9006:psh_globals_destroy +9007:psaux_get_glyph_name +9008:ps_table_release +9009:ps_table_new +9010:ps_table_done +9011:ps_table_add +9012:ps_property_set +9013:ps_property_get +9014:ps_parser_to_int +9015:ps_parser_to_fixed_array +9016:ps_parser_to_fixed +9017:ps_parser_to_coord_array +9018:ps_parser_to_bytes +9019:ps_parser_load_field_table +9020:ps_parser_init +9021:ps_hints_t2mask +9022:ps_hints_t2counter +9023:ps_hints_t1stem3 +9024:ps_hints_t1reset +9025:ps_hints_close +9026:ps_hints_apply +9027:ps_hinter_init +9028:ps_hinter_done +9029:ps_get_standard_strings +9030:ps_get_macintosh_name +9031:ps_decoder_init +9032:preprocess_text_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +9033:preprocess_text_thai\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +9034:preprocess_text_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +9035:preprocess_text_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +9036:premultiply_data +9037:premul_rgb\28SkRGBA4f<\28SkAlphaType\292>\29 +9038:premul_polar\28SkRGBA4f<\28SkAlphaType\292>\29 +9039:postprocess_glyphs_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +9040:portable::xy_to_unit_angle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9041:portable::xy_to_radius\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9042:portable::xy_to_2pt_conical_well_behaved\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9043:portable::xy_to_2pt_conical_strip\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9044:portable::xy_to_2pt_conical_smaller\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9045:portable::xy_to_2pt_conical_greater\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9046:portable::xy_to_2pt_conical_focal_on_circle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9047:portable::xor_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9048:portable::white_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9049:portable::unpremul_polar\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9050:portable::unpremul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9051:portable::uniform_color_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9052:portable::trace_var\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9053:portable::trace_scope\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9054:portable::trace_line\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9055:portable::trace_exit\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9056:portable::trace_enter\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9057:portable::tan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9058:portable::swizzle_copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9059:portable::swizzle_copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9060:portable::swizzle_copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9061:portable::swizzle_copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9062:portable::swizzle_copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9063:portable::swizzle_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9064:portable::swizzle_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9065:portable::swizzle_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9066:portable::swizzle_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9067:portable::swizzle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9068:portable::swap_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9069:portable::swap_rb_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9070:portable::swap_rb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9071:portable::sub_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9072:portable::sub_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9073:portable::sub_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9074:portable::sub_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9075:portable::sub_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9076:portable::sub_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9077:portable::sub_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9078:portable::sub_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9079:portable::sub_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9080:portable::sub_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9081:portable::store_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9082:portable::store_src_a\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9083:portable::store_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9084:portable::store_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9085:portable::store_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9086:portable::store_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9087:portable::store_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9088:portable::store_r8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9089:portable::store_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9090:portable::store_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9091:portable::store_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9092:portable::store_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9093:portable::store_device_xy01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9094:portable::store_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9095:portable::store_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9096:portable::store_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9097:portable::store_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9098:portable::store_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9099:portable::store_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9100:portable::store_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9101:portable::store_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9102:portable::store_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9103:portable::store_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9104:portable::store_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9105:portable::store_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9106:portable::start_pipeline\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkRasterPipelineStage*\2c\20SkSpan\2c\20unsigned\20char*\29 +9107:portable::stack_rewind\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9108:portable::stack_checkpoint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9109:portable::srcover_rgba_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9110:portable::srcover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9111:portable::srcout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9112:portable::srcin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9113:portable::srcatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9114:portable::sqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9115:portable::splat_4_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9116:portable::splat_3_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9117:portable::splat_2_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9118:portable::softlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9119:portable::smoothstep_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9120:portable::sin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9121:portable::shuffle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9122:portable::set_base_pointer\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9123:portable::seed_shader\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9124:portable::screen\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9125:portable::scale_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9126:portable::scale_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9127:portable::scale_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9128:portable::scale_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9129:portable::saturation\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9130:portable::rgb_to_hsl\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9131:portable::repeat_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9132:portable::repeat_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9133:portable::repeat_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9134:portable::refract_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9135:portable::reenable_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9136:portable::premul_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9137:portable::premul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9138:portable::pow_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9139:portable::plus_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9140:portable::perlin_noise\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9141:portable::parametric\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9142:portable::overlay\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9143:portable::negate_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9144:portable::multiply\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9145:portable::mul_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9146:portable::mul_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9147:portable::mul_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9148:portable::mul_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9149:portable::mul_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9150:portable::mul_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9151:portable::mul_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9152:portable::mul_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9153:portable::mul_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9154:portable::mul_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9155:portable::mul_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9156:portable::mul_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9157:portable::move_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9158:portable::move_dst_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9159:portable::modulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9160:portable::mod_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9161:portable::mod_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9162:portable::mod_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9163:portable::mod_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9164:portable::mod_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9165:portable::mix_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9166:portable::mix_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9167:portable::mix_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9168:portable::mix_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9169:portable::mix_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9170:portable::mix_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9171:portable::mix_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9172:portable::mix_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9173:portable::mix_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9174:portable::mix_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9175:portable::mirror_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9176:portable::mirror_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9177:portable::mirror_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9178:portable::mipmap_linear_update\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9179:portable::mipmap_linear_init\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9180:portable::mipmap_linear_finish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9181:portable::min_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9182:portable::min_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9183:portable::min_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9184:portable::min_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9185:portable::min_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9186:portable::min_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9187:portable::min_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9188:portable::min_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9189:portable::min_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9190:portable::min_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9191:portable::min_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9192:portable::min_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9193:portable::min_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9194:portable::min_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9195:portable::min_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9196:portable::min_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9197:portable::merge_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9198:portable::merge_inv_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9199:portable::merge_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9200:portable::max_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9201:portable::max_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9202:portable::max_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9203:portable::max_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9204:portable::max_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9205:portable::max_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9206:portable::max_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9207:portable::max_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9208:portable::max_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9209:portable::max_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9210:portable::max_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9211:portable::max_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9212:portable::max_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9213:portable::max_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9214:portable::max_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9215:portable::max_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9216:portable::matrix_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9217:portable::matrix_scale_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9218:portable::matrix_perspective\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9219:portable::matrix_multiply_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9220:portable::matrix_multiply_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9221:portable::matrix_multiply_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9222:portable::matrix_4x5\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9223:portable::matrix_4x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9224:portable::matrix_3x4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9225:portable::matrix_3x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9226:portable::matrix_2x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9227:portable::mask_off_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9228:portable::mask_off_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9229:portable::mask_2pt_conical_nan\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9230:portable::mask_2pt_conical_degenerates\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9231:portable::luminosity\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9232:portable::log_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9233:portable::log2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9234:portable::load_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9235:portable::load_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9236:portable::load_rgf16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9237:portable::load_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9238:portable::load_rg88_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9239:portable::load_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9240:portable::load_rg1616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9241:portable::load_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9242:portable::load_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9243:portable::load_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9244:portable::load_f32_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9245:portable::load_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9246:portable::load_f16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9247:portable::load_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9248:portable::load_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9249:portable::load_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9250:portable::load_af16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9251:portable::load_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9252:portable::load_a8_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9253:portable::load_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9254:portable::load_a16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9255:portable::load_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9256:portable::load_8888_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9257:portable::load_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9258:portable::load_565_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9259:portable::load_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9260:portable::load_4444_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9261:portable::load_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9262:portable::load_16161616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9263:portable::load_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9264:portable::load_10x6_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9265:portable::load_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9266:portable::load_1010102_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9267:portable::load_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9268:portable::load_1010102_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9269:portable::load_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9270:portable::load_10101010_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9271:portable::load_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9272:portable::lighten\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9273:portable::lerp_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9274:portable::lerp_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9275:portable::lerp_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9276:portable::lerp_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9277:portable::just_return\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9278:portable::jump\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9279:portable::invsqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9280:portable::invsqrt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9281:portable::invsqrt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9282:portable::invsqrt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9283:portable::inverse_mat4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9284:portable::inverse_mat3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9285:portable::inverse_mat2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9286:portable::init_lane_masks\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9287:portable::hue\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9288:portable::hsl_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9289:portable::hardlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9290:portable::gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9291:portable::gauss_a_to_rgba\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9292:portable::gather_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9293:portable::gather_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9294:portable::gather_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9295:portable::gather_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9296:portable::gather_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9297:portable::gather_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9298:portable::gather_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9299:portable::gather_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9300:portable::gather_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9301:portable::gather_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9302:portable::gather_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9303:portable::gather_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9304:portable::gather_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9305:portable::gather_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9306:portable::gather_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9307:portable::gather_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9308:portable::gamma_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9309:portable::force_opaque_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9310:portable::force_opaque\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9311:portable::floor_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9312:portable::floor_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9313:portable::floor_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9314:portable::floor_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9315:portable::exp_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9316:portable::exp2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9317:portable::exclusion\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9318:portable::exchange_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9319:portable::evenly_spaced_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9320:portable::evenly_spaced_2_stop_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9321:portable::emboss\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9322:portable::dstover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9323:portable::dstout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9324:portable::dstin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9325:portable::dstatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9326:portable::dot_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9327:portable::dot_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9328:portable::dot_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9329:portable::div_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9330:portable::div_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9331:portable::div_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9332:portable::div_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9333:portable::div_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9334:portable::div_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9335:portable::div_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9336:portable::div_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9337:portable::div_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9338:portable::div_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9339:portable::div_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9340:portable::div_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9341:portable::div_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9342:portable::div_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9343:portable::div_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9344:portable::dither\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9345:portable::difference\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9346:portable::decal_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9347:portable::decal_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9348:portable::decal_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9349:portable::darken\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9350:portable::css_oklab_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9351:portable::css_oklab_gamut_map_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9352:portable::css_lab_to_xyz\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9353:portable::css_hwb_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9354:portable::css_hsl_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9355:portable::css_hcl_to_lab\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9356:portable::cos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9357:portable::copy_uniform\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9358:portable::copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9359:portable::copy_slot_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9360:portable::copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9361:portable::copy_immutable_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9362:portable::copy_constant\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9363:portable::copy_4_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9364:portable::copy_4_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9365:portable::copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9366:portable::copy_4_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9367:portable::copy_3_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9368:portable::copy_3_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9369:portable::copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9370:portable::copy_3_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9371:portable::copy_2_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9372:portable::copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9373:portable::continue_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9374:portable::colordodge\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9375:portable::colorburn\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9376:portable::color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9377:portable::cmpne_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9378:portable::cmpne_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9379:portable::cmpne_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9380:portable::cmpne_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9381:portable::cmpne_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9382:portable::cmpne_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9383:portable::cmpne_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9384:portable::cmpne_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9385:portable::cmpne_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9386:portable::cmpne_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9387:portable::cmpne_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9388:portable::cmpne_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9389:portable::cmplt_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9390:portable::cmplt_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9391:portable::cmplt_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9392:portable::cmplt_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9393:portable::cmplt_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9394:portable::cmplt_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9395:portable::cmplt_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9396:portable::cmplt_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9397:portable::cmplt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9398:portable::cmplt_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9399:portable::cmplt_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9400:portable::cmplt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9401:portable::cmplt_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9402:portable::cmplt_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9403:portable::cmplt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9404:portable::cmplt_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9405:portable::cmplt_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9406:portable::cmplt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9407:portable::cmple_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9408:portable::cmple_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9409:portable::cmple_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9410:portable::cmple_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9411:portable::cmple_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9412:portable::cmple_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9413:portable::cmple_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9414:portable::cmple_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9415:portable::cmple_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9416:portable::cmple_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9417:portable::cmple_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9418:portable::cmple_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9419:portable::cmple_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9420:portable::cmple_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9421:portable::cmple_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9422:portable::cmple_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9423:portable::cmple_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9424:portable::cmple_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9425:portable::cmpeq_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9426:portable::cmpeq_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9427:portable::cmpeq_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9428:portable::cmpeq_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9429:portable::cmpeq_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9430:portable::cmpeq_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9431:portable::cmpeq_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9432:portable::cmpeq_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9433:portable::cmpeq_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9434:portable::cmpeq_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9435:portable::cmpeq_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9436:portable::cmpeq_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9437:portable::clear\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9438:portable::clamp_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9439:portable::clamp_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9440:portable::clamp_gamut\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9441:portable::clamp_a_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9442:portable::clamp_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9443:portable::ceil_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9444:portable::ceil_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9445:portable::ceil_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9446:portable::ceil_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9447:portable::cast_to_uint_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9448:portable::cast_to_uint_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9449:portable::cast_to_uint_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9450:portable::cast_to_uint_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9451:portable::cast_to_int_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9452:portable::cast_to_int_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9453:portable::cast_to_int_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9454:portable::cast_to_int_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9455:portable::cast_to_float_from_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9456:portable::cast_to_float_from_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9457:portable::cast_to_float_from_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9458:portable::cast_to_float_from_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9459:portable::cast_to_float_from_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9460:portable::cast_to_float_from_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9461:portable::cast_to_float_from_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9462:portable::cast_to_float_from_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9463:portable::case_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9464:portable::callback\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9465:portable::byte_tables\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9466:portable::bt709_luminance_or_luma_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9467:portable::bt709_luminance_or_luma_to_alpha\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9468:portable::branch_if_no_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9469:portable::branch_if_no_active_lanes_eq\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9470:portable::branch_if_any_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9471:portable::branch_if_all_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9472:portable::blit_row_s32a_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9473:portable::black_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9474:portable::bitwise_xor_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9475:portable::bitwise_xor_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9476:portable::bitwise_xor_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9477:portable::bitwise_xor_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9478:portable::bitwise_xor_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9479:portable::bitwise_xor_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9480:portable::bitwise_or_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9481:portable::bitwise_or_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9482:portable::bitwise_or_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9483:portable::bitwise_or_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9484:portable::bitwise_or_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9485:portable::bitwise_and_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9486:portable::bitwise_and_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9487:portable::bitwise_and_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9488:portable::bitwise_and_imm_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9489:portable::bitwise_and_imm_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9490:portable::bitwise_and_imm_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9491:portable::bitwise_and_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9492:portable::bitwise_and_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9493:portable::bitwise_and_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9494:portable::bilinear_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9495:portable::bilinear_py\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9496:portable::bilinear_px\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9497:portable::bilinear_ny\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9498:portable::bilinear_nx\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9499:portable::bilerp_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9500:portable::bicubic_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9501:portable::bicubic_p3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9502:portable::bicubic_p3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9503:portable::bicubic_p1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9504:portable::bicubic_p1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9505:portable::bicubic_n3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9506:portable::bicubic_n3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9507:portable::bicubic_n1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9508:portable::bicubic_n1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9509:portable::bicubic_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9510:portable::atan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9511:portable::atan2_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9512:portable::asin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9513:portable::alter_2pt_conical_unswap\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9514:portable::alter_2pt_conical_compensate_focal\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9515:portable::alpha_to_red_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9516:portable::alpha_to_red\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9517:portable::alpha_to_gray_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9518:portable::alpha_to_gray\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9519:portable::add_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9520:portable::add_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9521:portable::add_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9522:portable::add_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9523:portable::add_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9524:portable::add_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9525:portable::add_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9526:portable::add_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9527:portable::add_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9528:portable::add_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9529:portable::add_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9530:portable::add_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9531:portable::acos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9532:portable::accumulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9533:portable::abs_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9534:portable::abs_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9535:portable::abs_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9536:portable::abs_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9537:portable::RGBA_to_rgbA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +9538:portable::RGBA_to_bgrA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +9539:portable::RGBA_to_BGRA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +9540:portable::PQish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9541:portable::HLGish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9542:portable::HLGinvish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9543:pop_arg_long_double +9544:png_read_filter_row_up +9545:png_read_filter_row_sub +9546:png_read_filter_row_path_multibyte_pixel +9547:png_read_filter_row_path_1byte_pixel +9548:png_read_filter_row_avg +9549:picture_getCullRect +9550:pictureRecorder_endRecording +9551:pictureRecorder_dispose +9552:pictureRecorder_create +9553:pictureRecorder_beginRecording +9554:path_transform +9555:path_setFillType +9556:path_reset +9557:path_relativeQuadraticBezierTo +9558:path_relativeMoveTo +9559:path_relativeLineTo +9560:path_relativeCubicTo +9561:path_relativeConicTo +9562:path_relativeArcToRotated +9563:path_moveTo +9564:path_lineTo +9565:path_getSvgString +9566:path_getFillType +9567:path_getBounds +9568:path_dispose +9569:path_create +9570:path_copy +9571:path_contains +9572:path_conicTo +9573:path_combine +9574:path_close +9575:path_arcToRotated +9576:path_arcToOval +9577:path_addRect +9578:path_addRRect +9579:path_addPolygon +9580:path_addPath +9581:path_addArc +9582:paragraph_layout +9583:paragraph_getWordBoundary +9584:paragraph_getWidth +9585:paragraph_getUnresolvedCodePoints +9586:paragraph_getPositionForOffset +9587:paragraph_getMinIntrinsicWidth +9588:paragraph_getMaxIntrinsicWidth +9589:paragraph_getLongestLine +9590:paragraph_getLineNumberAt +9591:paragraph_getLineMetricsAtIndex +9592:paragraph_getLineCount +9593:paragraph_getIdeographicBaseline +9594:paragraph_getHeight +9595:paragraph_getGlyphInfoAt +9596:paragraph_getDidExceedMaxLines +9597:paragraph_getClosestGlyphInfoAtCoordinate +9598:paragraph_getBoxesForRange +9599:paragraph_getBoxesForPlaceholders +9600:paragraph_getAlphabeticBaseline +9601:paragraphStyle_setTextStyle +9602:paragraphStyle_setTextHeightBehavior +9603:paragraphStyle_setTextDirection +9604:paragraphStyle_setTextAlign +9605:paragraphStyle_setStrutStyle +9606:paragraphStyle_setMaxLines +9607:paragraphStyle_setHeight +9608:paragraphStyle_setEllipsis +9609:paragraphStyle_setApplyRoundingHack +9610:paragraphStyle_dispose +9611:paragraphStyle_create +9612:paragraphBuilder_setWordBreaksUtf16 +9613:paragraphBuilder_setLineBreaksUtf16 +9614:paragraphBuilder_setGraphemeBreaksUtf16 +9615:paragraphBuilder_pushStyle +9616:paragraphBuilder_pop +9617:paragraphBuilder_getUtf8Text +9618:paragraphBuilder_create +9619:paragraphBuilder_build +9620:paragraphBuilder_addText +9621:paragraphBuilder_addPlaceholder +9622:paint_setShader +9623:paint_setMaskFilter +9624:paint_setImageFilter +9625:paint_setColorFilter +9626:paint_dispose +9627:paint_create +9628:override_features_khmer\28hb_ot_shape_planner_t*\29 +9629:override_features_indic\28hb_ot_shape_planner_t*\29 +9630:override_features_hangul\28hb_ot_shape_planner_t*\29 +9631:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_14677 +9632:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +9633:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_14567 +9634:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +9635:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10254 +9636:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10253 +9637:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10251 +9638:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +9639:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +9640:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +9641:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11151 +9642:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +9643:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +9644:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10447 +9645:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +9646:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +9647:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +9648:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9649:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +9650:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +9651:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9652:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12184 +9653:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +9654:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9655:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +9656:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::glyphCount\28\29\20const +9657:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9658:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +9659:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9660:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +9661:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +9662:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9663:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9477 +9664:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +9665:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +9666:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +9667:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +9668:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +9669:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29_9125 +9670:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29 +9671:non-virtual\20thunk\20to\20GrOpFlushState::writeView\28\29\20const +9672:non-virtual\20thunk\20to\20GrOpFlushState::usesMSAASurface\28\29\20const +9673:non-virtual\20thunk\20to\20GrOpFlushState::threadSafeCache\28\29\20const +9674:non-virtual\20thunk\20to\20GrOpFlushState::strikeCache\28\29\20const +9675:non-virtual\20thunk\20to\20GrOpFlushState::smallPathAtlasManager\28\29\20const +9676:non-virtual\20thunk\20to\20GrOpFlushState::sampledProxyArray\28\29 +9677:non-virtual\20thunk\20to\20GrOpFlushState::rtProxy\28\29\20const +9678:non-virtual\20thunk\20to\20GrOpFlushState::resourceProvider\28\29\20const +9679:non-virtual\20thunk\20to\20GrOpFlushState::renderPassBarriers\28\29\20const +9680:non-virtual\20thunk\20to\20GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +9681:non-virtual\20thunk\20to\20GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +9682:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndirectDraws\28int\29 +9683:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndices\28int\29 +9684:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +9685:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +9686:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +9687:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +9688:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +9689:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +9690:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +9691:non-virtual\20thunk\20to\20GrOpFlushState::dstProxyView\28\29\20const +9692:non-virtual\20thunk\20to\20GrOpFlushState::detachAppliedClip\28\29 +9693:non-virtual\20thunk\20to\20GrOpFlushState::colorLoadOp\28\29\20const +9694:non-virtual\20thunk\20to\20GrOpFlushState::caps\28\29\20const +9695:non-virtual\20thunk\20to\20GrOpFlushState::atlasManager\28\29\20const +9696:non-virtual\20thunk\20to\20GrOpFlushState::appliedClip\28\29\20const +9697:non-virtual\20thunk\20to\20GrGpuBuffer::unref\28\29\20const +9698:non-virtual\20thunk\20to\20GrGpuBuffer::ref\28\29\20const +9699:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_11920 +9700:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +9701:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onSetLabel\28\29 +9702:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +9703:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +9704:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +9705:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +9706:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::backendFormat\28\29\20const +9707:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10178 +9708:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +9709:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +9710:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +9711:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::dstColor\28\29 +9712:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29_11551 +9713:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29 +9714:maskFilter_createBlur +9715:lineMetrics_getWidth +9716:lineMetrics_getUnscaledAscent +9717:lineMetrics_getLeft +9718:lineMetrics_getHeight +9719:lineMetrics_getDescent +9720:lineMetrics_getBaseline +9721:lineMetrics_getAscent +9722:lineMetrics_dispose +9723:lineMetrics_create +9724:lineBreakBuffer_create +9725:lin_srgb_to_okhcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +9726:lcd_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +9727:is_deleted_glyph\28hb_glyph_info_t\20const*\29 +9728:initial_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9729:image_getHeight +9730:image_createFromTextureSource +9731:image_createFromPixels +9732:image_createFromPicture +9733:imageFilter_getFilterBounds +9734:imageFilter_createMatrix +9735:imageFilter_createFromColorFilter +9736:imageFilter_createErode +9737:imageFilter_createDilate +9738:imageFilter_createBlur +9739:imageFilter_compose +9740:hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +9741:hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +9742:hb_unicode_script_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9743:hb_unicode_general_category_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9744:hb_ucd_script\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9745:hb_ucd_mirroring\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9746:hb_ucd_general_category\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9747:hb_ucd_decompose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20void*\29 +9748:hb_ucd_compose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9749:hb_ucd_combining_class\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9750:hb_syllabic_clear_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9751:hb_paint_sweep_gradient_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9752:hb_paint_push_transform_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9753:hb_paint_push_clip_rectangle_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9754:hb_paint_image_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +9755:hb_paint_extents_push_transform\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9756:hb_paint_extents_push_group\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +9757:hb_paint_extents_push_clip_rectangle\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9758:hb_paint_extents_push_clip_glyph\28hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_font_t*\2c\20void*\29 +9759:hb_paint_extents_pop_transform\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +9760:hb_paint_extents_pop_group\28hb_paint_funcs_t*\2c\20void*\2c\20hb_paint_composite_mode_t\2c\20void*\29 +9761:hb_paint_extents_pop_clip\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +9762:hb_paint_extents_paint_sweep_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9763:hb_paint_extents_paint_image\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +9764:hb_paint_extents_paint_color\28hb_paint_funcs_t*\2c\20void*\2c\20int\2c\20unsigned\20int\2c\20void*\29 +9765:hb_outline_recording_pen_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9766:hb_outline_recording_pen_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9767:hb_outline_recording_pen_line_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9768:hb_outline_recording_pen_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9769:hb_outline_recording_pen_close_path\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +9770:hb_ot_paint_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9771:hb_ot_map_t::lookup_map_t::cmp\28void\20const*\2c\20void\20const*\29 +9772:hb_ot_map_t::feature_map_t::cmp\28void\20const*\2c\20void\20const*\29 +9773:hb_ot_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +9774:hb_ot_get_variation_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9775:hb_ot_get_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +9776:hb_ot_get_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9777:hb_ot_get_glyph_v_origin\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9778:hb_ot_get_glyph_v_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9779:hb_ot_get_glyph_name\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +9780:hb_ot_get_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9781:hb_ot_get_glyph_from_name\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +9782:hb_ot_get_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9783:hb_ot_get_font_v_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9784:hb_ot_get_font_h_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9785:hb_ot_draw_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +9786:hb_font_paint_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9787:hb_font_paint_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9788:hb_font_get_variation_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9789:hb_font_get_nominal_glyphs_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +9790:hb_font_get_nominal_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9791:hb_font_get_nominal_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9792:hb_font_get_glyph_v_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9793:hb_font_get_glyph_v_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9794:hb_font_get_glyph_v_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9795:hb_font_get_glyph_v_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9796:hb_font_get_glyph_v_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9797:hb_font_get_glyph_v_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9798:hb_font_get_glyph_name_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +9799:hb_font_get_glyph_name_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +9800:hb_font_get_glyph_h_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9801:hb_font_get_glyph_h_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9802:hb_font_get_glyph_h_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9803:hb_font_get_glyph_h_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9804:hb_font_get_glyph_h_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9805:hb_font_get_glyph_h_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9806:hb_font_get_glyph_from_name_default\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +9807:hb_font_get_glyph_extents_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9808:hb_font_get_glyph_extents_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9809:hb_font_get_glyph_contour_point_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9810:hb_font_get_glyph_contour_point_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9811:hb_font_get_font_v_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9812:hb_font_get_font_h_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9813:hb_font_draw_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +9814:hb_draw_quadratic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9815:hb_draw_quadratic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9816:hb_draw_move_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9817:hb_draw_line_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9818:hb_draw_extents_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9819:hb_draw_extents_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9820:hb_draw_cubic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9821:hb_draw_close_path_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +9822:hb_buffer_t::_cluster_group_func\28hb_glyph_info_t\20const&\2c\20hb_glyph_info_t\20const&\29 +9823:hb_aat_map_builder_t::feature_event_t::cmp\28void\20const*\2c\20void\20const*\29 +9824:gray_raster_render +9825:gray_raster_new +9826:gray_raster_done +9827:gray_move_to +9828:gray_line_to +9829:gray_cubic_to +9830:gray_conic_to +9831:get_sfnt_table +9832:ft_smooth_transform +9833:ft_smooth_set_mode +9834:ft_smooth_render +9835:ft_smooth_overlap_spans +9836:ft_smooth_lcd_spans +9837:ft_smooth_init +9838:ft_smooth_get_cbox +9839:ft_gzip_free +9840:ft_ansi_stream_io +9841:ft_ansi_stream_close +9842:fquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9843:fontCollection_registerTypeface +9844:fontCollection_dispose +9845:fontCollection_create +9846:fontCollection_clearCaches +9847:fmt_fp +9848:fline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9849:final_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9850:fcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9851:fconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9852:error_callback +9853:emscripten_stack_set_limits +9854:emscripten_stack_get_current +9855:emscripten_current_thread_process_queued_calls +9856:dquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9857:dline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9858:dispose_external_texture\28void*\29 +9859:decompose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9860:decompose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9861:decompose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9862:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::Make\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20bool\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9863:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\2c\20GrShaderCaps\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::\28anonymous\20namespace\29::HullShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9864:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9865:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9866:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&>\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathTessellator::PathDrawList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9867:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29>\28skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20sk_sp\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9868:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Make\28SkArenaAlloc*\2c\20GrAAType\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9869:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerSkyline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9870:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerPow2&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9871:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc>\28\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TextureOpImpl::Desc&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9872:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TentPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9873:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::SimpleTriangleShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9874:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9875:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader\2c\20bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*\2c\20GrShaderCaps\20const&>\28bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*&&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::DrawAtlasPathShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9876:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&>\28SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::BoundingBoxShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9877:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20unsigned\20char&&\29::'lambda'\28void*\29>\28Sprite_D32_S32&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9878:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTriColorShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9879:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTCubic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9880:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTConic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9881:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\29::'lambda'\28void*\29>\28SkSpriteBlitter_Memcpy&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9882:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&>\28SkPixmap\20const&\2c\20SkArenaAlloc*&\2c\20sk_sp&\29::'lambda'\28void*\29>\28SkRasterPipelineSpriteBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9883:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkArenaAlloc*&\29::'lambda'\28void*\29>\28SkRasterPipelineBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9884:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkNullBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9885:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkImage_Base\20const*&&\2c\20SkMatrix\20const&\2c\20SkMipmapMode&\29::'lambda'\28void*\29>\28SkMipmapAccessor&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9886:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::PathData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9887:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::DrawableData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9888:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\29>>::Node*\20SkArenaAlloc::make&\29>>::Node\2c\20std::__2::function&\29>>\28std::__2::function&\29>&&\29::'lambda'\28void*\29>\28SkArenaAllocList&\29>>::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9889:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node\2c\20std::__2::function&\29>\2c\20skgpu::AtlasToken>\28std::__2::function&\29>&&\2c\20skgpu::AtlasToken&&\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9890:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node>\28\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9891:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Coverage_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9892:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28GrSimpleMesh&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9893:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29::'lambda'\28void*\29>\28GrResourceAllocator::Register&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9894:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPath\20const&\2c\20SkArenaAlloc*\20const&\29::'lambda'\28void*\29>\28GrInnerFanTriangulator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9895:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldLCDTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20GrDistanceFieldLCDTextGeoProc::DistanceAdjust\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9896:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29>\28GrBitmapTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9897:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrAppliedClip&&\29::'lambda'\28void*\29>\28GrAppliedClip&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9898:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28EllipseGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9899:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28DefaultGeoProc::Make\28SkArenaAlloc*\2c\20unsigned\20int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9900:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9901:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9902:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9903:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +9904:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9905:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&\29 +9906:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9907:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9908:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9909:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +9910:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +9911:deallocate_buffer_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9912:ddquad_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9913:ddquad_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9914:ddline_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9915:ddline_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9916:ddcubic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9917:ddcubic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9918:ddconic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9919:ddconic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9920:dconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9921:data_destroy_use\28void*\29 +9922:data_create_use\28hb_ot_shape_plan_t\20const*\29 +9923:data_create_khmer\28hb_ot_shape_plan_t\20const*\29 +9924:data_create_indic\28hb_ot_shape_plan_t\20const*\29 +9925:data_create_hangul\28hb_ot_shape_plan_t\20const*\29 +9926:convert_to_alpha8\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20SkColorSpaceXformSteps\20const&\29 +9927:convert_bytes_to_data +9928:contourMeasure_length +9929:contourMeasure_isClosed +9930:contourMeasure_getSegment +9931:contourMeasure_getPosTan +9932:contourMeasureIter_next +9933:contourMeasureIter_dispose +9934:contourMeasureIter_create +9935:compose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9936:compose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9937:compose_hebrew\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9938:compare_ppem +9939:compare_myanmar_order\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +9940:compare_combining_class\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +9941:colorFilter_createSRGBToLinearGamma +9942:colorFilter_createMode +9943:colorFilter_createMatrix +9944:colorFilter_createLinearToSRGBGamma +9945:colorFilter_compose +9946:collect_features_use\28hb_ot_shape_planner_t*\29 +9947:collect_features_myanmar\28hb_ot_shape_planner_t*\29 +9948:collect_features_khmer\28hb_ot_shape_planner_t*\29 +9949:collect_features_indic\28hb_ot_shape_planner_t*\29 +9950:collect_features_hangul\28hb_ot_shape_planner_t*\29 +9951:collect_features_arabic\28hb_ot_shape_planner_t*\29 +9952:clip\28SkPath\20const&\2c\20SkHalfPlane\20const&\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +9953:cleanup +9954:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitStatement\28SkSL::Statement\20const&\29 +9955:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9956:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitExpression\28SkSL::Expression\20const&\29 +9957:cff_slot_init +9958:cff_slot_done +9959:cff_size_request +9960:cff_size_init +9961:cff_size_done +9962:cff_sid_to_glyph_name +9963:cff_set_var_design +9964:cff_set_mm_weightvector +9965:cff_set_mm_blend +9966:cff_set_instance +9967:cff_random +9968:cff_ps_has_glyph_names +9969:cff_ps_get_font_info +9970:cff_ps_get_font_extra +9971:cff_parse_vsindex +9972:cff_parse_private_dict +9973:cff_parse_multiple_master +9974:cff_parse_maxstack +9975:cff_parse_font_matrix +9976:cff_parse_font_bbox +9977:cff_parse_cid_ros +9978:cff_parse_blend +9979:cff_metrics_adjust +9980:cff_hadvance_adjust +9981:cff_get_var_design +9982:cff_get_var_blend +9983:cff_get_standard_encoding +9984:cff_get_ros +9985:cff_get_ps_name +9986:cff_get_name_index +9987:cff_get_mm_weightvector +9988:cff_get_mm_var +9989:cff_get_mm_blend +9990:cff_get_is_cid +9991:cff_get_interface +9992:cff_get_glyph_name +9993:cff_get_cmap_info +9994:cff_get_cid_from_glyph_index +9995:cff_get_advances +9996:cff_free_glyph_data +9997:cff_face_init +9998:cff_face_done +9999:cff_driver_init +10000:cff_done_blend +10001:cff_decoder_prepare +10002:cff_decoder_init +10003:cff_cmap_unicode_init +10004:cff_cmap_unicode_char_next +10005:cff_cmap_unicode_char_index +10006:cff_cmap_encoding_init +10007:cff_cmap_encoding_done +10008:cff_cmap_encoding_char_next +10009:cff_cmap_encoding_char_index +10010:cff_builder_start_point +10011:cf2_free_instance +10012:cf2_decoder_parse_charstrings +10013:cf2_builder_moveTo +10014:cf2_builder_lineTo +10015:cf2_builder_cubeTo +10016:canvas_translate +10017:canvas_transform +10018:canvas_skew +10019:canvas_scale +10020:canvas_saveLayer +10021:canvas_save +10022:canvas_rotate +10023:canvas_restoreToCount +10024:canvas_restore +10025:canvas_getTransform +10026:canvas_getSaveCount +10027:canvas_getLocalClipBounds +10028:canvas_getDeviceClipBounds +10029:canvas_drawVertices +10030:canvas_drawShadow +10031:canvas_drawRect +10032:canvas_drawRRect +10033:canvas_drawPoints +10034:canvas_drawPicture +10035:canvas_drawPath +10036:canvas_drawParagraph +10037:canvas_drawPaint +10038:canvas_drawOval +10039:canvas_drawLine +10040:canvas_drawImageRect +10041:canvas_drawImageNine +10042:canvas_drawImage +10043:canvas_drawDRRect +10044:canvas_drawColor +10045:canvas_drawCircle +10046:canvas_drawAtlas +10047:canvas_drawArc +10048:canvas_clipRect +10049:canvas_clipRRect +10050:canvas_clipPath +10051:cancel_notification +10052:cancel_active_ctxs +10053:call_with_ctx +10054:call_then_finish_task +10055:call_cancel_then_free_ctx +10056:call_callback_then_free_ctx +10057:bw_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +10058:bw_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10059:bw_pt_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10060:bw_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10061:bw_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10062:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::SpotVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +10063:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::AmbientVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +10064:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +10065:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +10066:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +10067:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +10068:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +10069:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +10070:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +10071:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +10072:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +10073:blur_y_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10074:blur_y_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10075:blur_y_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10076:blur_y_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10077:blur_x_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10078:blur_x_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10079:blur_x_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10080:blur_x_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +10081:blit_row_s32a_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +10082:blit_row_s32_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +10083:blit_row_s32_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +10084:argb32_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +10085:arabic_fallback_shape\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +10086:afm_parser_parse +10087:afm_parser_init +10088:afm_parser_done +10089:afm_compare_kern_pairs +10090:af_property_set +10091:af_property_get +10092:af_latin_metrics_scale +10093:af_latin_metrics_init +10094:af_latin_hints_init +10095:af_latin_hints_apply +10096:af_latin_get_standard_widths +10097:af_indic_metrics_scale +10098:af_indic_metrics_init +10099:af_indic_hints_init +10100:af_indic_hints_apply +10101:af_get_interface +10102:af_face_globals_free +10103:af_dummy_hints_init +10104:af_dummy_hints_apply +10105:af_cjk_metrics_init +10106:af_autofitter_load_glyph +10107:af_autofitter_init +10108:action_terminate +10109:action_abort +10110:aa_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10111:aa_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10112:aa_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10113:_hb_ot_font_destroy\28void*\29 +10114:_hb_glyph_info_is_default_ignorable\28hb_glyph_info_t\20const*\29 +10115:_hb_face_for_data_reference_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +10116:_hb_face_for_data_closure_destroy\28void*\29 +10117:_hb_clear_substitution_flags\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +10118:_hb_blob_destroy\28void*\29 +10119:_emscripten_tls_init +10120:_emscripten_thread_init +10121:_emscripten_thread_free_data +10122:_emscripten_thread_exit +10123:_emscripten_thread_crashed +10124:_emscripten_stack_restore +10125:_emscripten_stack_alloc +10126:_emscripten_run_on_main_thread_js +10127:_emscripten_check_mailbox +10128:__wasm_init_memory +10129:__wasm_call_ctors +10130:__stdio_write +10131:__stdio_seek +10132:__stdio_read +10133:__stdio_close +10134:__emscripten_stdout_seek +10135:__cxxabiv1::__vmi_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10136:__cxxabiv1::__vmi_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10137:__cxxabiv1::__vmi_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +10138:__cxxabiv1::__si_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10139:__cxxabiv1::__si_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10140:__cxxabiv1::__si_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +10141:__cxxabiv1::__class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10142:__cxxabiv1::__class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10143:__cxxabiv1::__class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +10144:__cxxabiv1::__class_type_info::can_catch\28__cxxabiv1::__shim_type_info\20const*\2c\20void*&\29\20const +10145:\28anonymous\20namespace\29::skhb_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +10146:\28anonymous\20namespace\29::skhb_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +10147:\28anonymous\20namespace\29::skhb_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +10148:\28anonymous\20namespace\29::skhb_glyph_h_advance\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +10149:\28anonymous\20namespace\29::skhb_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +10150:\28anonymous\20namespace\29::skhb_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +10151:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29::$_0::__invoke\28void*\29 +10152:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +10153:\28anonymous\20namespace\29::make_morphology\28\28anonymous\20namespace\29::MorphType\2c\20SkSize\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +10154:\28anonymous\20namespace\29::create_sub_hb_font\28SkFont\20const&\2c\20std::__2::unique_ptr>\20const&\29::$_0::__invoke\28void*\29 +10155:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29_4361 +10156:\28anonymous\20namespace\29::YUVPlanesRec::getCategory\28\29\20const +10157:\28anonymous\20namespace\29::YUVPlanesRec::diagnostic_only_getDiscardable\28\29\20const +10158:\28anonymous\20namespace\29::YUVPlanesRec::bytesUsed\28\29\20const +10159:\28anonymous\20namespace\29::YUVPlanesRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +10160:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29_11318 +10161:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29_11296 +10162:\28anonymous\20namespace\29::TriangulatingPathOp::visitProxies\28std::__2::function\20const&\29\20const +10163:\28anonymous\20namespace\29::TriangulatingPathOp::programInfo\28\29 +10164:\28anonymous\20namespace\29::TriangulatingPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10165:\28anonymous\20namespace\29::TriangulatingPathOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10166:\28anonymous\20namespace\29::TriangulatingPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10167:\28anonymous\20namespace\29::TriangulatingPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10168:\28anonymous\20namespace\29::TriangulatingPathOp::name\28\29\20const +10169:\28anonymous\20namespace\29::TriangulatingPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10170:\28anonymous\20namespace\29::TransformedMaskSubRun::unflattenSize\28\29\20const +10171:\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +10172:\28anonymous\20namespace\29::TransformedMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10173:\28anonymous\20namespace\29::TransformedMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +10174:\28anonymous\20namespace\29::TransformedMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +10175:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29_11270 +10176:\28anonymous\20namespace\29::TextureOpImpl::visitProxies\28std::__2::function\20const&\29\20const +10177:\28anonymous\20namespace\29::TextureOpImpl::programInfo\28\29 +10178:\28anonymous\20namespace\29::TextureOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +10179:\28anonymous\20namespace\29::TextureOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10180:\28anonymous\20namespace\29::TextureOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10181:\28anonymous\20namespace\29::TextureOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10182:\28anonymous\20namespace\29::TextureOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10183:\28anonymous\20namespace\29::TextureOpImpl::name\28\29\20const +10184:\28anonymous\20namespace\29::TextureOpImpl::fixedFunctionFlags\28\29\20const +10185:\28anonymous\20namespace\29::TextureOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10186:\28anonymous\20namespace\29::TentPass::startBlur\28\29 +10187:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +10188:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +10189:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +10190:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29_11322 +10191:\28anonymous\20namespace\29::StaticVertexAllocator::unlock\28int\29 +10192:\28anonymous\20namespace\29::StaticVertexAllocator::lock\28unsigned\20long\2c\20int\29 +10193:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::currentScript\28\29\20const +10194:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::consume\28\29 +10195:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10196:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10197:\28anonymous\20namespace\29::SkMorphologyImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10198:\28anonymous\20namespace\29::SkMorphologyImageFilter::getTypeName\28\29\20const +10199:\28anonymous\20namespace\29::SkMorphologyImageFilter::flatten\28SkWriteBuffer&\29\20const +10200:\28anonymous\20namespace\29::SkMorphologyImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10201:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10202:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10203:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10204:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::getTypeName\28\29\20const +10205:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::flatten\28SkWriteBuffer&\29\20const +10206:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10207:\28anonymous\20namespace\29::SkFTGeometrySink::Quad\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +10208:\28anonymous\20namespace\29::SkFTGeometrySink::Move\28FT_Vector_\20const*\2c\20void*\29 +10209:\28anonymous\20namespace\29::SkFTGeometrySink::Line\28FT_Vector_\20const*\2c\20void*\29 +10210:\28anonymous\20namespace\29::SkFTGeometrySink::Cubic\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +10211:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +10212:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFamilyName\28SkString*\29\20const +10213:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +10214:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateFamilyNameIterator\28\29\20const +10215:\28anonymous\20namespace\29::SkEmptyTypeface::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +10216:\28anonymous\20namespace\29::SkCropImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10217:\28anonymous\20namespace\29::SkCropImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10218:\28anonymous\20namespace\29::SkCropImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10219:\28anonymous\20namespace\29::SkCropImageFilter::onAffectsTransparentBlack\28\29\20const +10220:\28anonymous\20namespace\29::SkCropImageFilter::getTypeName\28\29\20const +10221:\28anonymous\20namespace\29::SkCropImageFilter::flatten\28SkWriteBuffer&\29\20const +10222:\28anonymous\20namespace\29::SkCropImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10223:\28anonymous\20namespace\29::SkComposeImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10224:\28anonymous\20namespace\29::SkComposeImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10225:\28anonymous\20namespace\29::SkComposeImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10226:\28anonymous\20namespace\29::SkComposeImageFilter::getTypeName\28\29\20const +10227:\28anonymous\20namespace\29::SkComposeImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10228:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29_5412 +10229:\28anonymous\20namespace\29::SkColorFilterImageFilter::onIsColorFilterNode\28SkColorFilter**\29\20const +10230:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10231:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10232:\28anonymous\20namespace\29::SkColorFilterImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10233:\28anonymous\20namespace\29::SkColorFilterImageFilter::onAffectsTransparentBlack\28\29\20const +10234:\28anonymous\20namespace\29::SkColorFilterImageFilter::getTypeName\28\29\20const +10235:\28anonymous\20namespace\29::SkColorFilterImageFilter::flatten\28SkWriteBuffer&\29\20const +10236:\28anonymous\20namespace\29::SkColorFilterImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10237:\28anonymous\20namespace\29::SkBlurImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10238:\28anonymous\20namespace\29::SkBlurImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10239:\28anonymous\20namespace\29::SkBlurImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10240:\28anonymous\20namespace\29::SkBlurImageFilter::getTypeName\28\29\20const +10241:\28anonymous\20namespace\29::SkBlurImageFilter::flatten\28SkWriteBuffer&\29\20const +10242:\28anonymous\20namespace\29::SkBlurImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10243:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29_5384 +10244:\28anonymous\20namespace\29::SkBlendImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10245:\28anonymous\20namespace\29::SkBlendImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10246:\28anonymous\20namespace\29::SkBlendImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10247:\28anonymous\20namespace\29::SkBlendImageFilter::onAffectsTransparentBlack\28\29\20const +10248:\28anonymous\20namespace\29::SkBlendImageFilter::getTypeName\28\29\20const +10249:\28anonymous\20namespace\29::SkBlendImageFilter::flatten\28SkWriteBuffer&\29\20const +10250:\28anonymous\20namespace\29::SkBlendImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10251:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29_7526 +10252:\28anonymous\20namespace\29::SkBidiIterator_icu::getLevelAt\28int\29 +10253:\28anonymous\20namespace\29::SkBidiIterator_icu::getLength\28\29 +10254:\28anonymous\20namespace\29::SimpleTriangleShader::name\28\29\20const +10255:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10256:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10257:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10258:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10259:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20bool\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10260:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::~ShapeDontWrapOrReorder\28\29 +10261:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::wrap\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::BiDiRunIterator\20const&\2c\20SkShaper::LanguageRunIterator\20const&\2c\20SkShaper::ScriptRunIterator\20const&\2c\20SkShaper::FontRunIterator\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10262:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29_5227 +10263:\28anonymous\20namespace\29::ShadowInvalidator::changed\28\29 +10264:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29_11130 +10265:\28anonymous\20namespace\29::ShadowCircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +10266:\28anonymous\20namespace\29::ShadowCircularRRectOp::programInfo\28\29 +10267:\28anonymous\20namespace\29::ShadowCircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10268:\28anonymous\20namespace\29::ShadowCircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10269:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10270:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10271:\28anonymous\20namespace\29::ShadowCircularRRectOp::name\28\29\20const +10272:\28anonymous\20namespace\29::ShadowCircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10273:\28anonymous\20namespace\29::SDFTSubRun::vertexStride\28SkMatrix\20const&\29\20const +10274:\28anonymous\20namespace\29::SDFTSubRun::vertexFiller\28\29\20const +10275:\28anonymous\20namespace\29::SDFTSubRun::unflattenSize\28\29\20const +10276:\28anonymous\20namespace\29::SDFTSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +10277:\28anonymous\20namespace\29::SDFTSubRun::glyphs\28\29\20const +10278:\28anonymous\20namespace\29::SDFTSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10279:\28anonymous\20namespace\29::SDFTSubRun::doFlatten\28SkWriteBuffer&\29\20const +10280:\28anonymous\20namespace\29::SDFTSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +10281:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29_2603 +10282:\28anonymous\20namespace\29::RectsBlurRec::getCategory\28\29\20const +10283:\28anonymous\20namespace\29::RectsBlurRec::diagnostic_only_getDiscardable\28\29\20const +10284:\28anonymous\20namespace\29::RectsBlurRec::bytesUsed\28\29\20const +10285:\28anonymous\20namespace\29::RectsBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +10286:\28anonymous\20namespace\29::RasterShaderBlurAlgorithm::makeDevice\28SkImageInfo\20const&\29\20const +10287:\28anonymous\20namespace\29::RasterBlurEngine::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +10288:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::maxSigma\28\29\20const +10289:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +10290:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29_2597 +10291:\28anonymous\20namespace\29::RRectBlurRec::getCategory\28\29\20const +10292:\28anonymous\20namespace\29::RRectBlurRec::diagnostic_only_getDiscardable\28\29\20const +10293:\28anonymous\20namespace\29::RRectBlurRec::bytesUsed\28\29\20const +10294:\28anonymous\20namespace\29::RRectBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +10295:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29_12117 +10296:\28anonymous\20namespace\29::PathSubRun::unflattenSize\28\29\20const +10297:\28anonymous\20namespace\29::PathSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10298:\28anonymous\20namespace\29::PathSubRun::doFlatten\28SkWriteBuffer&\29\20const +10299:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29_1287 +10300:\28anonymous\20namespace\29::MipMapRec::getCategory\28\29\20const +10301:\28anonymous\20namespace\29::MipMapRec::diagnostic_only_getDiscardable\28\29\20const +10302:\28anonymous\20namespace\29::MipMapRec::bytesUsed\28\29\20const +10303:\28anonymous\20namespace\29::MipMapRec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +10304:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29_11346 +10305:\28anonymous\20namespace\29::MiddleOutShader::name\28\29\20const +10306:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10307:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10308:\28anonymous\20namespace\29::MiddleOutShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10309:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29_10671 +10310:\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const +10311:\28anonymous\20namespace\29::MeshOp::programInfo\28\29 +10312:\28anonymous\20namespace\29::MeshOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10313:\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10314:\28anonymous\20namespace\29::MeshOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10315:\28anonymous\20namespace\29::MeshOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10316:\28anonymous\20namespace\29::MeshOp::name\28\29\20const +10317:\28anonymous\20namespace\29::MeshOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10318:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29_10695 +10319:\28anonymous\20namespace\29::MeshGP::onTextureSampler\28int\29\20const +10320:\28anonymous\20namespace\29::MeshGP::name\28\29\20const +10321:\28anonymous\20namespace\29::MeshGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10322:\28anonymous\20namespace\29::MeshGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10323:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29_10701 +10324:\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10325:\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10326:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10327:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10328:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10329:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10330:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMainName\28\29 +10331:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10332:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +10333:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +10334:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareFunction\28char\20const*\29 +10335:\28anonymous\20namespace\29::HQDownSampler::buildLevel\28SkPixmap\20const&\2c\20SkPixmap\20const&\29 +10336:\28anonymous\20namespace\29::GaussPass::startBlur\28\29 +10337:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +10338:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +10339:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +10340:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29_10791 +10341:\28anonymous\20namespace\29::FillRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +10342:\28anonymous\20namespace\29::FillRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +10343:\28anonymous\20namespace\29::FillRectOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10344:\28anonymous\20namespace\29::FillRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10345:\28anonymous\20namespace\29::FillRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10346:\28anonymous\20namespace\29::FillRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10347:\28anonymous\20namespace\29::FillRectOpImpl::name\28\29\20const +10348:\28anonymous\20namespace\29::FillRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10349:\28anonymous\20namespace\29::ExternalWebGLTexture::~ExternalWebGLTexture\28\29_546 +10350:\28anonymous\20namespace\29::ExternalWebGLTexture::getBackendTexture\28\29 +10351:\28anonymous\20namespace\29::ExternalWebGLTexture::dispose\28\29 +10352:\28anonymous\20namespace\29::EllipticalRRectEffect::onMakeProgramImpl\28\29\20const +10353:\28anonymous\20namespace\29::EllipticalRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10354:\28anonymous\20namespace\29::EllipticalRRectEffect::name\28\29\20const +10355:\28anonymous\20namespace\29::EllipticalRRectEffect::clone\28\29\20const +10356:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10357:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10358:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29_12125 +10359:\28anonymous\20namespace\29::DrawableSubRun::unflattenSize\28\29\20const +10360:\28anonymous\20namespace\29::DrawableSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10361:\28anonymous\20namespace\29::DrawableSubRun::doFlatten\28SkWriteBuffer&\29\20const +10362:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29_10642 +10363:\28anonymous\20namespace\29::DrawAtlasPathShader::onTextureSampler\28int\29\20const +10364:\28anonymous\20namespace\29::DrawAtlasPathShader::name\28\29\20const +10365:\28anonymous\20namespace\29::DrawAtlasPathShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10366:\28anonymous\20namespace\29::DrawAtlasPathShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10367:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10368:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10369:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29_10619 +10370:\28anonymous\20namespace\29::DrawAtlasOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +10371:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10372:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10373:\28anonymous\20namespace\29::DrawAtlasOpImpl::name\28\29\20const +10374:\28anonymous\20namespace\29::DrawAtlasOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10375:\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +10376:\28anonymous\20namespace\29::DirectMaskSubRun::unflattenSize\28\29\20const +10377:\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +10378:\28anonymous\20namespace\29::DirectMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10379:\28anonymous\20namespace\29::DirectMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +10380:\28anonymous\20namespace\29::DirectMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +10381:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29_10595 +10382:\28anonymous\20namespace\29::DefaultPathOp::visitProxies\28std::__2::function\20const&\29\20const +10383:\28anonymous\20namespace\29::DefaultPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10384:\28anonymous\20namespace\29::DefaultPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10385:\28anonymous\20namespace\29::DefaultPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10386:\28anonymous\20namespace\29::DefaultPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10387:\28anonymous\20namespace\29::DefaultPathOp::name\28\29\20const +10388:\28anonymous\20namespace\29::DefaultPathOp::fixedFunctionFlags\28\29\20const +10389:\28anonymous\20namespace\29::DefaultPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10390:\28anonymous\20namespace\29::CircularRRectEffect::onMakeProgramImpl\28\29\20const +10391:\28anonymous\20namespace\29::CircularRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10392:\28anonymous\20namespace\29::CircularRRectEffect::name\28\29\20const +10393:\28anonymous\20namespace\29::CircularRRectEffect::clone\28\29\20const +10394:\28anonymous\20namespace\29::CircularRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10395:\28anonymous\20namespace\29::CircularRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10396:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29_5231 +10397:\28anonymous\20namespace\29::CachedTessellationsRec::getCategory\28\29\20const +10398:\28anonymous\20namespace\29::CachedTessellationsRec::bytesUsed\28\29\20const +10399:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29_5237 +10400:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29_2461 +10401:\28anonymous\20namespace\29::CacheImpl::set\28SkImageFilterCacheKey\20const&\2c\20SkImageFilter\20const*\2c\20skif::FilterResult\20const&\29 +10402:\28anonymous\20namespace\29::CacheImpl::purge\28\29 +10403:\28anonymous\20namespace\29::CacheImpl::purgeByImageFilter\28SkImageFilter\20const*\29 +10404:\28anonymous\20namespace\29::CacheImpl::get\28SkImageFilterCacheKey\20const&\2c\20skif::FilterResult*\29\20const +10405:\28anonymous\20namespace\29::BoundingBoxShader::name\28\29\20const +10406:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10407:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10408:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10409:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29_10375 +10410:\28anonymous\20namespace\29::AAHairlineOp::visitProxies\28std::__2::function\20const&\29\20const +10411:\28anonymous\20namespace\29::AAHairlineOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10412:\28anonymous\20namespace\29::AAHairlineOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10413:\28anonymous\20namespace\29::AAHairlineOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10414:\28anonymous\20namespace\29::AAHairlineOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10415:\28anonymous\20namespace\29::AAHairlineOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10416:\28anonymous\20namespace\29::AAHairlineOp::name\28\29\20const +10417:\28anonymous\20namespace\29::AAHairlineOp::fixedFunctionFlags\28\29\20const +10418:\28anonymous\20namespace\29::AAHairlineOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10419:Write_CVT_Stretched +10420:Write_CVT +10421:Vertish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +10422:Vertish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +10423:VertState::Triangles\28VertState*\29 +10424:VertState::TrianglesX\28VertState*\29 +10425:VertState::TriangleStrip\28VertState*\29 +10426:VertState::TriangleStripX\28VertState*\29 +10427:VertState::TriangleFan\28VertState*\29 +10428:VertState::TriangleFanX\28VertState*\29 +10429:VLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +10430:VLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +10431:TextureSourceImageGenerator::~TextureSourceImageGenerator\28\29_527 +10432:TextureSourceImageGenerator::generateExternalTexture\28GrRecordingContext*\2c\20skgpu::Mipmapped\29 +10433:TT_Set_MM_Blend +10434:TT_RunIns +10435:TT_Load_Simple_Glyph +10436:TT_Load_Glyph_Header +10437:TT_Load_Composite_Glyph +10438:TT_Get_Var_Design +10439:TT_Get_MM_Blend +10440:TT_Forget_Glyph_Frame +10441:TT_Access_Glyph_Frame +10442:TOUPPER\28unsigned\20char\29 +10443:TOLOWER\28unsigned\20char\29 +10444:SquareCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +10445:Sprite_D32_S32::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10446:Skwasm::Surface::Surface\28\29::$_0::__invoke\28void*\29 +10447:SkWeakRefCnt::internal_dispose\28\29\20const +10448:SkUnicode_client::~SkUnicode_client\28\29_7566 +10449:SkUnicode_client::toUpper\28SkString\20const&\2c\20char\20const*\29 +10450:SkUnicode_client::toUpper\28SkString\20const&\29 +10451:SkUnicode_client::reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29 +10452:SkUnicode_client::makeBreakIterator\28char\20const*\2c\20SkUnicode::BreakType\29 +10453:SkUnicode_client::makeBreakIterator\28SkUnicode::BreakType\29 +10454:SkUnicode_client::makeBidiIterator\28unsigned\20short\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +10455:SkUnicode_client::makeBidiIterator\28char\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +10456:SkUnicode_client::getWords\28char\20const*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +10457:SkUnicode_client::getBidiRegions\28char\20const*\2c\20int\2c\20SkUnicode::TextDirection\2c\20std::__2::vector>*\29 +10458:SkUnicode_client::computeCodeUnitFlags\28char16_t*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +10459:SkUnicode_client::computeCodeUnitFlags\28char*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +10460:SkUnicodeHardCodedCharProperties::isWhitespace\28int\29 +10461:SkUnicodeHardCodedCharProperties::isTabulation\28int\29 +10462:SkUnicodeHardCodedCharProperties::isSpace\28int\29 +10463:SkUnicodeHardCodedCharProperties::isIdeographic\28int\29 +10464:SkUnicodeHardCodedCharProperties::isHardBreak\28int\29 +10465:SkUnicodeHardCodedCharProperties::isControl\28int\29 +10466:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29_12312 +10467:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29 +10468:SkUnicodeBidiRunIterator::endOfCurrentRun\28\29\20const +10469:SkUnicodeBidiRunIterator::currentLevel\28\29\20const +10470:SkUnicodeBidiRunIterator::consume\28\29 +10471:SkUnicodeBidiRunIterator::atEnd\28\29\20const +10472:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29_7723 +10473:SkTypeface_FreeTypeStream::onOpenStream\28int*\29\20const +10474:SkTypeface_FreeTypeStream::onMakeFontData\28\29\20const +10475:SkTypeface_FreeTypeStream::onMakeClone\28SkFontArguments\20const&\29\20const +10476:SkTypeface_FreeTypeStream::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +10477:SkTypeface_FreeType::onGlyphMaskNeedsCurrentColor\28\29\20const +10478:SkTypeface_FreeType::onGetVariationDesignPosition\28SkFontArguments::VariationPosition::Coordinate*\2c\20int\29\20const +10479:SkTypeface_FreeType::onGetVariationDesignParameters\28SkFontParameters::Variation::Axis*\2c\20int\29\20const +10480:SkTypeface_FreeType::onGetUPEM\28\29\20const +10481:SkTypeface_FreeType::onGetTableTags\28unsigned\20int*\29\20const +10482:SkTypeface_FreeType::onGetTableData\28unsigned\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20void*\29\20const +10483:SkTypeface_FreeType::onGetPostScriptName\28SkString*\29\20const +10484:SkTypeface_FreeType::onGetKerningPairAdjustments\28unsigned\20short\20const*\2c\20int\2c\20int*\29\20const +10485:SkTypeface_FreeType::onGetAdvancedMetrics\28\29\20const +10486:SkTypeface_FreeType::onFilterRec\28SkScalerContextRec*\29\20const +10487:SkTypeface_FreeType::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +10488:SkTypeface_FreeType::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +10489:SkTypeface_FreeType::onCreateFamilyNameIterator\28\29\20const +10490:SkTypeface_FreeType::onCountGlyphs\28\29\20const +10491:SkTypeface_FreeType::onCopyTableData\28unsigned\20int\29\20const +10492:SkTypeface_FreeType::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +10493:SkTypeface_FreeType::getPostScriptGlyphNames\28SkString*\29\20const +10494:SkTypeface_FreeType::getGlyphToUnicodeMap\28int*\29\20const +10495:SkTypeface_Empty::~SkTypeface_Empty\28\29 +10496:SkTypeface_Custom::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +10497:SkTypeface::onOpenExistingStream\28int*\29\20const +10498:SkTypeface::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +10499:SkTypeface::onCopyTableData\28unsigned\20int\29\20const +10500:SkTypeface::onComputeBounds\28SkRect*\29\20const +10501:SkTriColorShader::type\28\29\20const +10502:SkTriColorShader::isOpaque\28\29\20const +10503:SkTriColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10504:SkTransformShader::type\28\29\20const +10505:SkTransformShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10506:SkTQuad::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +10507:SkTQuad::setBounds\28SkDRect*\29\20const +10508:SkTQuad::ptAtT\28double\29\20const +10509:SkTQuad::make\28SkArenaAlloc&\29\20const +10510:SkTQuad::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +10511:SkTQuad::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +10512:SkTQuad::dxdyAtT\28double\29\20const +10513:SkTQuad::debugInit\28\29 +10514:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29_3938 +10515:SkTCubic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +10516:SkTCubic::setBounds\28SkDRect*\29\20const +10517:SkTCubic::ptAtT\28double\29\20const +10518:SkTCubic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +10519:SkTCubic::maxIntersections\28\29\20const +10520:SkTCubic::make\28SkArenaAlloc&\29\20const +10521:SkTCubic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +10522:SkTCubic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +10523:SkTCubic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +10524:SkTCubic::dxdyAtT\28double\29\20const +10525:SkTCubic::debugInit\28\29 +10526:SkTCubic::controlsInside\28\29\20const +10527:SkTCubic::collapsed\28\29\20const +10528:SkTConic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +10529:SkTConic::setBounds\28SkDRect*\29\20const +10530:SkTConic::ptAtT\28double\29\20const +10531:SkTConic::make\28SkArenaAlloc&\29\20const +10532:SkTConic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +10533:SkTConic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +10534:SkTConic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +10535:SkTConic::dxdyAtT\28double\29\20const +10536:SkTConic::debugInit\28\29 +10537:SkSweepGradient::getTypeName\28\29\20const +10538:SkSweepGradient::flatten\28SkWriteBuffer&\29\20const +10539:SkSweepGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10540:SkSweepGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +10541:SkSurface_Raster::~SkSurface_Raster\28\29_4485 +10542:SkSurface_Raster::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +10543:SkSurface_Raster::onRestoreBackingMutability\28\29 +10544:SkSurface_Raster::onNewSurface\28SkImageInfo\20const&\29 +10545:SkSurface_Raster::onNewImageSnapshot\28SkIRect\20const*\29 +10546:SkSurface_Raster::onNewCanvas\28\29 +10547:SkSurface_Raster::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10548:SkSurface_Raster::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +10549:SkSurface_Raster::imageInfo\28\29\20const +10550:SkSurface_Ganesh::~SkSurface_Ganesh\28\29_11324 +10551:SkSurface_Ganesh::replaceBackendTexture\28GrBackendTexture\20const&\2c\20GrSurfaceOrigin\2c\20SkSurface::ContentChangeMode\2c\20void\20\28*\29\28void*\29\2c\20void*\29 +10552:SkSurface_Ganesh::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +10553:SkSurface_Ganesh::onWait\28int\2c\20GrBackendSemaphore\20const*\2c\20bool\29 +10554:SkSurface_Ganesh::onNewSurface\28SkImageInfo\20const&\29 +10555:SkSurface_Ganesh::onNewImageSnapshot\28SkIRect\20const*\29 +10556:SkSurface_Ganesh::onNewCanvas\28\29 +10557:SkSurface_Ganesh::onIsCompatible\28GrSurfaceCharacterization\20const&\29\20const +10558:SkSurface_Ganesh::onGetRecordingContext\28\29\20const +10559:SkSurface_Ganesh::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10560:SkSurface_Ganesh::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +10561:SkSurface_Ganesh::onCharacterize\28GrSurfaceCharacterization*\29\20const +10562:SkSurface_Ganesh::onCapabilities\28\29 +10563:SkSurface_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10564:SkSurface_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10565:SkSurface_Ganesh::imageInfo\28\29\20const +10566:SkSurface_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10567:SkSurface::imageInfo\28\29\20const +10568:SkStrikeCache::~SkStrikeCache\28\29_4159 +10569:SkStrikeCache::findOrCreateScopedStrike\28SkStrikeSpec\20const&\29 +10570:SkStrike::~SkStrike\28\29_4144 +10571:SkStrike::strikePromise\28\29 +10572:SkStrike::roundingSpec\28\29\20const +10573:SkStrike::getDescriptor\28\29\20const +10574:SkSpriteBlitter_Memcpy::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10575:SkSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +10576:SkSpriteBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10577:SkSpriteBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10578:SkSpriteBlitter::blitH\28int\2c\20int\2c\20int\29 +10579:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29_4079 +10580:SkSpecialImage_Raster::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +10581:SkSpecialImage_Raster::getSize\28\29\20const +10582:SkSpecialImage_Raster::backingStoreDimensions\28\29\20const +10583:SkSpecialImage_Raster::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +10584:SkSpecialImage_Raster::asImage\28\29\20const +10585:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29_10297 +10586:SkSpecialImage_Gpu::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +10587:SkSpecialImage_Gpu::getSize\28\29\20const +10588:SkSpecialImage_Gpu::backingStoreDimensions\28\29\20const +10589:SkSpecialImage_Gpu::asImage\28\29\20const +10590:SkSpecialImage::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +10591:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29_12305 +10592:SkShaper::TrivialLanguageRunIterator::currentLanguage\28\29\20const +10593:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29_7035 +10594:SkShaper::TrivialBiDiRunIterator::currentLevel\28\29\20const +10595:SkShaderBlurAlgorithm::maxSigma\28\29\20const +10596:SkShaderBlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +10597:SkScan::HairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10598:SkScan::HairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10599:SkScan::HairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10600:SkScan::AntiHairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10601:SkScan::AntiHairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10602:SkScan::AntiHairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10603:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10604:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29_7659 +10605:SkScalerContext_FreeType::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +10606:SkScalerContext_FreeType::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +10607:SkScalerContext_FreeType::generateImage\28SkGlyph\20const&\2c\20void*\29 +10608:SkScalerContext_FreeType::generateFontMetrics\28SkFontMetrics*\29 +10609:SkScalerContext_FreeType::generateDrawable\28SkGlyph\20const&\29 +10610:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::~SkScalerContext_Empty\28\29 +10611:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +10612:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +10613:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateFontMetrics\28SkFontMetrics*\29 +10614:SkSRGBColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +10615:SkSRGBColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +10616:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_3::__invoke\28double\2c\20double\29 +10617:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_2::__invoke\28double\2c\20double\29 +10618:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_1::__invoke\28double\2c\20double\29 +10619:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_0::__invoke\28double\2c\20double\29 +10620:SkSL::negate_value\28double\29 +10621:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29_6853 +10622:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29_6850 +10623:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +10624:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitExpressionPtr\28std::__2::unique_ptr>&\29 +10625:SkSL::count_returns_at_end_of_control_flow\28SkSL::FunctionDefinition\20const&\29::CountReturnsAtEndOfControlFlow::visitStatement\28SkSL::Statement\20const&\29 +10626:SkSL::bitwise_not_value\28double\29 +10627:SkSL::\28anonymous\20namespace\29::VariableWriteVisitor::visitExpression\28SkSL::Expression\20const&\29 +10628:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10629:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitExpression\28SkSL::Expression\20const&\29 +10630:SkSL::\28anonymous\20namespace\29::ReturnsNonOpaqueColorVisitor::visitStatement\28SkSL::Statement\20const&\29 +10631:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitStatement\28SkSL::Statement\20const&\29 +10632:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10633:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitExpression\28SkSL::Expression\20const&\29 +10634:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10635:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +10636:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29_6015 +10637:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitExpression\28SkSL::Expression\20const&\29 +10638:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29_6038 +10639:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitStatement\28SkSL::Statement\20const&\29 +10640:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitExpression\28SkSL::Expression\20const&\29 +10641:SkSL::VectorType::isOrContainsBool\28\29\20const +10642:SkSL::VectorType::isAllowedInUniform\28SkSL::Position*\29\20const +10643:SkSL::VectorType::isAllowedInES2\28\29\20const +10644:SkSL::VariableReference::clone\28SkSL::Position\29\20const +10645:SkSL::Variable::~Variable\28\29_6818 +10646:SkSL::Variable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +10647:SkSL::Variable::mangledName\28\29\20const +10648:SkSL::Variable::layout\28\29\20const +10649:SkSL::Variable::description\28\29\20const +10650:SkSL::VarDeclaration::~VarDeclaration\28\29_6816 +10651:SkSL::VarDeclaration::description\28\29\20const +10652:SkSL::TypeReference::clone\28SkSL::Position\29\20const +10653:SkSL::Type::minimumValue\28\29\20const +10654:SkSL::Type::maximumValue\28\29\20const +10655:SkSL::Type::matches\28SkSL::Type\20const&\29\20const +10656:SkSL::Type::isAllowedInUniform\28SkSL::Position*\29\20const +10657:SkSL::Type::fields\28\29\20const +10658:SkSL::Type::description\28\29\20const +10659:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29_6867 +10660:SkSL::Tracer::var\28int\2c\20int\29 +10661:SkSL::Tracer::scope\28int\29 +10662:SkSL::Tracer::line\28int\29 +10663:SkSL::Tracer::exit\28int\29 +10664:SkSL::Tracer::enter\28int\29 +10665:SkSL::TextureType::textureAccess\28\29\20const +10666:SkSL::TextureType::isMultisampled\28\29\20const +10667:SkSL::TextureType::isDepth\28\29\20const +10668:SkSL::TernaryExpression::~TernaryExpression\28\29_6631 +10669:SkSL::TernaryExpression::description\28SkSL::OperatorPrecedence\29\20const +10670:SkSL::TernaryExpression::clone\28SkSL::Position\29\20const +10671:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression&\29 +10672:SkSL::Swizzle::description\28SkSL::OperatorPrecedence\29\20const +10673:SkSL::Swizzle::clone\28SkSL::Position\29\20const +10674:SkSL::SwitchStatement::description\28\29\20const +10675:SkSL::SwitchCase::description\28\29\20const +10676:SkSL::StructType::slotType\28unsigned\20long\29\20const +10677:SkSL::StructType::isOrContainsUnsizedArray\28\29\20const +10678:SkSL::StructType::isOrContainsBool\28\29\20const +10679:SkSL::StructType::isOrContainsAtomic\28\29\20const +10680:SkSL::StructType::isOrContainsArray\28\29\20const +10681:SkSL::StructType::isInterfaceBlock\28\29\20const +10682:SkSL::StructType::isBuiltin\28\29\20const +10683:SkSL::StructType::isAllowedInUniform\28SkSL::Position*\29\20const +10684:SkSL::StructType::isAllowedInES2\28\29\20const +10685:SkSL::StructType::fields\28\29\20const +10686:SkSL::StructDefinition::description\28\29\20const +10687:SkSL::StringStream::~StringStream\28\29_12237 +10688:SkSL::StringStream::write\28void\20const*\2c\20unsigned\20long\29 +10689:SkSL::StringStream::writeText\28char\20const*\29 +10690:SkSL::StringStream::write8\28unsigned\20char\29 +10691:SkSL::Setting::description\28SkSL::OperatorPrecedence\29\20const +10692:SkSL::Setting::clone\28SkSL::Position\29\20const +10693:SkSL::ScalarType::priority\28\29\20const +10694:SkSL::ScalarType::numberKind\28\29\20const +10695:SkSL::ScalarType::minimumValue\28\29\20const +10696:SkSL::ScalarType::maximumValue\28\29\20const +10697:SkSL::ScalarType::isOrContainsBool\28\29\20const +10698:SkSL::ScalarType::isAllowedInUniform\28SkSL::Position*\29\20const +10699:SkSL::ScalarType::isAllowedInES2\28\29\20const +10700:SkSL::ScalarType::bitWidth\28\29\20const +10701:SkSL::SamplerType::textureAccess\28\29\20const +10702:SkSL::SamplerType::isMultisampled\28\29\20const +10703:SkSL::SamplerType::isDepth\28\29\20const +10704:SkSL::SamplerType::isArrayedTexture\28\29\20const +10705:SkSL::SamplerType::dimensions\28\29\20const +10706:SkSL::ReturnStatement::description\28\29\20const +10707:SkSL::RP::VariableLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10708:SkSL::RP::VariableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10709:SkSL::RP::VariableLValue::isWritable\28\29\20const +10710:SkSL::RP::UnownedLValueSlice::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10711:SkSL::RP::UnownedLValueSlice::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10712:SkSL::RP::UnownedLValueSlice::fixedSlotRange\28SkSL::RP::Generator*\29 +10713:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29_6309 +10714:SkSL::RP::SwizzleLValue::swizzle\28\29 +10715:SkSL::RP::SwizzleLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10716:SkSL::RP::SwizzleLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10717:SkSL::RP::SwizzleLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10718:SkSL::RP::ScratchLValue::~ScratchLValue\28\29_6203 +10719:SkSL::RP::ScratchLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10720:SkSL::RP::ScratchLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10721:SkSL::RP::LValueSlice::~LValueSlice\28\29_6307 +10722:SkSL::RP::ImmutableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10723:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29_6301 +10724:SkSL::RP::DynamicIndexLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10725:SkSL::RP::DynamicIndexLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10726:SkSL::RP::DynamicIndexLValue::isWritable\28\29\20const +10727:SkSL::RP::DynamicIndexLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10728:SkSL::ProgramVisitor::visitStatementPtr\28std::__2::unique_ptr>\20const&\29 +10729:SkSL::ProgramVisitor::visitExpressionPtr\28std::__2::unique_ptr>\20const&\29 +10730:SkSL::PrefixExpression::~PrefixExpression\28\29_6591 +10731:SkSL::PrefixExpression::~PrefixExpression\28\29 +10732:SkSL::PrefixExpression::description\28SkSL::OperatorPrecedence\29\20const +10733:SkSL::PrefixExpression::clone\28SkSL::Position\29\20const +10734:SkSL::PostfixExpression::description\28SkSL::OperatorPrecedence\29\20const +10735:SkSL::PostfixExpression::clone\28SkSL::Position\29\20const +10736:SkSL::Poison::description\28SkSL::OperatorPrecedence\29\20const +10737:SkSL::Poison::clone\28SkSL::Position\29\20const +10738:SkSL::PipelineStage::Callbacks::getMainName\28\29 +10739:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29_5966 +10740:SkSL::Parser::Checkpoint::ForwardingErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +10741:SkSL::Nop::description\28\29\20const +10742:SkSL::ModifiersDeclaration::description\28\29\20const +10743:SkSL::MethodReference::description\28SkSL::OperatorPrecedence\29\20const +10744:SkSL::MethodReference::clone\28SkSL::Position\29\20const +10745:SkSL::MatrixType::slotCount\28\29\20const +10746:SkSL::MatrixType::rows\28\29\20const +10747:SkSL::MatrixType::isAllowedInES2\28\29\20const +10748:SkSL::LiteralType::minimumValue\28\29\20const +10749:SkSL::LiteralType::maximumValue\28\29\20const +10750:SkSL::LiteralType::isOrContainsBool\28\29\20const +10751:SkSL::Literal::getConstantValue\28int\29\20const +10752:SkSL::Literal::description\28SkSL::OperatorPrecedence\29\20const +10753:SkSL::Literal::compareConstant\28SkSL::Expression\20const&\29\20const +10754:SkSL::Literal::clone\28SkSL::Position\29\20const +10755:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_uintBitsToFloat\28double\2c\20double\2c\20double\29 +10756:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_trunc\28double\2c\20double\2c\20double\29 +10757:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tanh\28double\2c\20double\2c\20double\29 +10758:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tan\28double\2c\20double\2c\20double\29 +10759:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sub\28double\2c\20double\2c\20double\29 +10760:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_step\28double\2c\20double\2c\20double\29 +10761:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sqrt\28double\2c\20double\2c\20double\29 +10762:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_smoothstep\28double\2c\20double\2c\20double\29 +10763:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sinh\28double\2c\20double\2c\20double\29 +10764:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sin\28double\2c\20double\2c\20double\29 +10765:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sign\28double\2c\20double\2c\20double\29 +10766:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_saturate\28double\2c\20double\2c\20double\29 +10767:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_round\28double\2c\20double\2c\20double\29 +10768:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_radians\28double\2c\20double\2c\20double\29 +10769:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_pow\28double\2c\20double\2c\20double\29 +10770:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_opposite_sign\28double\2c\20double\2c\20double\29 +10771:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_not\28double\2c\20double\2c\20double\29 +10772:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mod\28double\2c\20double\2c\20double\29 +10773:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mix\28double\2c\20double\2c\20double\29 +10774:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_min\28double\2c\20double\2c\20double\29 +10775:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_max\28double\2c\20double\2c\20double\29 +10776:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log\28double\2c\20double\2c\20double\29 +10777:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log2\28double\2c\20double\2c\20double\29 +10778:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_inversesqrt\28double\2c\20double\2c\20double\29 +10779:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_intBitsToFloat\28double\2c\20double\2c\20double\29 +10780:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fract\28double\2c\20double\2c\20double\29 +10781:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fma\28double\2c\20double\2c\20double\29 +10782:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floor\28double\2c\20double\2c\20double\29 +10783:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToUint\28double\2c\20double\2c\20double\29 +10784:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToInt\28double\2c\20double\2c\20double\29 +10785:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp\28double\2c\20double\2c\20double\29 +10786:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp2\28double\2c\20double\2c\20double\29 +10787:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_div\28double\2c\20double\2c\20double\29 +10788:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_degrees\28double\2c\20double\2c\20double\29 +10789:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cosh\28double\2c\20double\2c\20double\29 +10790:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cos\28double\2c\20double\2c\20double\29 +10791:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_clamp\28double\2c\20double\2c\20double\29 +10792:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_ceil\28double\2c\20double\2c\20double\29 +10793:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atanh\28double\2c\20double\2c\20double\29 +10794:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan\28double\2c\20double\2c\20double\29 +10795:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan2\28double\2c\20double\2c\20double\29 +10796:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asinh\28double\2c\20double\2c\20double\29 +10797:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asin\28double\2c\20double\2c\20double\29 +10798:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_add\28double\2c\20double\2c\20double\29 +10799:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acosh\28double\2c\20double\2c\20double\29 +10800:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acos\28double\2c\20double\2c\20double\29 +10801:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_abs\28double\2c\20double\2c\20double\29 +10802:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_notEqual\28double\2c\20double\29 +10803:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThan\28double\2c\20double\29 +10804:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThanEqual\28double\2c\20double\29 +10805:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThan\28double\2c\20double\29 +10806:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThanEqual\28double\2c\20double\29 +10807:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_equal\28double\2c\20double\29 +10808:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_length\28double\2c\20double\2c\20double\29 +10809:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_dot\28double\2c\20double\2c\20double\29 +10810:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_distance\28double\2c\20double\2c\20double\29 +10811:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_any\28double\2c\20double\2c\20double\29 +10812:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_all\28double\2c\20double\2c\20double\29 +10813:SkSL::InterfaceBlock::~InterfaceBlock\28\29_6565 +10814:SkSL::InterfaceBlock::~InterfaceBlock\28\29 +10815:SkSL::InterfaceBlock::description\28\29\20const +10816:SkSL::IndexExpression::~IndexExpression\28\29_6561 +10817:SkSL::IndexExpression::description\28SkSL::OperatorPrecedence\29\20const +10818:SkSL::IndexExpression::clone\28SkSL::Position\29\20const +10819:SkSL::IfStatement::~IfStatement\28\29_6559 +10820:SkSL::IfStatement::description\28\29\20const +10821:SkSL::GlobalVarDeclaration::description\28\29\20const +10822:SkSL::GenericType::slotType\28unsigned\20long\29\20const +10823:SkSL::GenericType::coercibleTypes\28\29\20const +10824:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29_12294 +10825:SkSL::FunctionReference::description\28SkSL::OperatorPrecedence\29\20const +10826:SkSL::FunctionReference::clone\28SkSL::Position\29\20const +10827:SkSL::FunctionPrototype::description\28\29\20const +10828:SkSL::FunctionDefinition::description\28\29\20const +10829:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29_6554 +10830:SkSL::FunctionCall::description\28SkSL::OperatorPrecedence\29\20const +10831:SkSL::FunctionCall::clone\28SkSL::Position\29\20const +10832:SkSL::ForStatement::~ForStatement\28\29_6431 +10833:SkSL::ForStatement::description\28\29\20const +10834:SkSL::FieldSymbol::description\28\29\20const +10835:SkSL::FieldAccess::clone\28SkSL::Position\29\20const +10836:SkSL::Extension::description\28\29\20const +10837:SkSL::ExtendedVariable::~ExtendedVariable\28\29_6826 +10838:SkSL::ExtendedVariable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +10839:SkSL::ExtendedVariable::mangledName\28\29\20const +10840:SkSL::ExtendedVariable::layout\28\29\20const +10841:SkSL::ExtendedVariable::interfaceBlock\28\29\20const +10842:SkSL::ExtendedVariable::detachDeadInterfaceBlock\28\29 +10843:SkSL::ExpressionStatement::description\28\29\20const +10844:SkSL::Expression::getConstantValue\28int\29\20const +10845:SkSL::Expression::description\28\29\20const +10846:SkSL::EmptyExpression::description\28SkSL::OperatorPrecedence\29\20const +10847:SkSL::EmptyExpression::clone\28SkSL::Position\29\20const +10848:SkSL::DoStatement::description\28\29\20const +10849:SkSL::DiscardStatement::description\28\29\20const +10850:SkSL::DebugTracePriv::~DebugTracePriv\28\29_6837 +10851:SkSL::DebugTracePriv::dump\28SkWStream*\29\20const +10852:SkSL::CountReturnsWithLimit::visitStatement\28SkSL::Statement\20const&\29 +10853:SkSL::ContinueStatement::description\28\29\20const +10854:SkSL::ConstructorStruct::clone\28SkSL::Position\29\20const +10855:SkSL::ConstructorSplat::getConstantValue\28int\29\20const +10856:SkSL::ConstructorSplat::clone\28SkSL::Position\29\20const +10857:SkSL::ConstructorScalarCast::clone\28SkSL::Position\29\20const +10858:SkSL::ConstructorMatrixResize::getConstantValue\28int\29\20const +10859:SkSL::ConstructorMatrixResize::clone\28SkSL::Position\29\20const +10860:SkSL::ConstructorDiagonalMatrix::getConstantValue\28int\29\20const +10861:SkSL::ConstructorDiagonalMatrix::clone\28SkSL::Position\29\20const +10862:SkSL::ConstructorCompoundCast::clone\28SkSL::Position\29\20const +10863:SkSL::ConstructorCompound::clone\28SkSL::Position\29\20const +10864:SkSL::ConstructorArrayCast::clone\28SkSL::Position\29\20const +10865:SkSL::ConstructorArray::clone\28SkSL::Position\29\20const +10866:SkSL::Compiler::CompilerErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +10867:SkSL::CodeGenerator::~CodeGenerator\28\29 +10868:SkSL::ChildCall::description\28SkSL::OperatorPrecedence\29\20const +10869:SkSL::ChildCall::clone\28SkSL::Position\29\20const +10870:SkSL::BreakStatement::description\28\29\20const +10871:SkSL::Block::~Block\28\29_6341 +10872:SkSL::Block::description\28\29\20const +10873:SkSL::BinaryExpression::~BinaryExpression\28\29_6335 +10874:SkSL::BinaryExpression::description\28SkSL::OperatorPrecedence\29\20const +10875:SkSL::BinaryExpression::clone\28SkSL::Position\29\20const +10876:SkSL::ArrayType::slotType\28unsigned\20long\29\20const +10877:SkSL::ArrayType::slotCount\28\29\20const +10878:SkSL::ArrayType::matches\28SkSL::Type\20const&\29\20const +10879:SkSL::ArrayType::isUnsizedArray\28\29\20const +10880:SkSL::ArrayType::isOrContainsUnsizedArray\28\29\20const +10881:SkSL::ArrayType::isBuiltin\28\29\20const +10882:SkSL::ArrayType::isAllowedInUniform\28SkSL::Position*\29\20const +10883:SkSL::AnyConstructor::getConstantValue\28int\29\20const +10884:SkSL::AnyConstructor::description\28SkSL::OperatorPrecedence\29\20const +10885:SkSL::AnyConstructor::compareConstant\28SkSL::Expression\20const&\29\20const +10886:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29_6086 +10887:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::visitExpression\28SkSL::Expression\20const&\29 +10888:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29_6009 +10889:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitExpression\28SkSL::Expression\20const&\29 +10890:SkSL::AliasType::textureAccess\28\29\20const +10891:SkSL::AliasType::slotType\28unsigned\20long\29\20const +10892:SkSL::AliasType::slotCount\28\29\20const +10893:SkSL::AliasType::rows\28\29\20const +10894:SkSL::AliasType::priority\28\29\20const +10895:SkSL::AliasType::isVector\28\29\20const +10896:SkSL::AliasType::isUnsizedArray\28\29\20const +10897:SkSL::AliasType::isStruct\28\29\20const +10898:SkSL::AliasType::isScalar\28\29\20const +10899:SkSL::AliasType::isMultisampled\28\29\20const +10900:SkSL::AliasType::isMatrix\28\29\20const +10901:SkSL::AliasType::isLiteral\28\29\20const +10902:SkSL::AliasType::isInterfaceBlock\28\29\20const +10903:SkSL::AliasType::isDepth\28\29\20const +10904:SkSL::AliasType::isArrayedTexture\28\29\20const +10905:SkSL::AliasType::isArray\28\29\20const +10906:SkSL::AliasType::dimensions\28\29\20const +10907:SkSL::AliasType::componentType\28\29\20const +10908:SkSL::AliasType::columns\28\29\20const +10909:SkSL::AliasType::coercibleTypes\28\29\20const +10910:SkRuntimeShader::~SkRuntimeShader\28\29_4587 +10911:SkRuntimeShader::type\28\29\20const +10912:SkRuntimeShader::isOpaque\28\29\20const +10913:SkRuntimeShader::getTypeName\28\29\20const +10914:SkRuntimeShader::flatten\28SkWriteBuffer&\29\20const +10915:SkRuntimeShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10916:SkRuntimeEffect::~SkRuntimeEffect\28\29_3921 +10917:SkRuntimeEffect::MakeFromSource\28SkString\2c\20SkRuntimeEffect::Options\20const&\2c\20SkSL::ProgramKind\29 +10918:SkRuntimeEffect::MakeForColorFilter\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +10919:SkRuntimeEffect::MakeForBlender\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +10920:SkRgnClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10921:SkRgnClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10922:SkRgnClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10923:SkRgnClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10924:SkRgnClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10925:SkRgnClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10926:SkRgnBuilder::~SkRgnBuilder\28\29_3858 +10927:SkRgnBuilder::blitH\28int\2c\20int\2c\20int\29 +10928:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29_4461 +10929:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::rowBytes\28int\29\20const +10930:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::data\28int\29\20const +10931:SkRectClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10932:SkRectClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10933:SkRectClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10934:SkRectClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10935:SkRectClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10936:SkRectClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10937:SkRecorder::~SkRecorder\28\29_3780 +10938:SkRecorder::willSave\28\29 +10939:SkRecorder::onResetClip\28\29 +10940:SkRecorder::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10941:SkRecorder::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10942:SkRecorder::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +10943:SkRecorder::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10944:SkRecorder::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10945:SkRecorder::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10946:SkRecorder::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10947:SkRecorder::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +10948:SkRecorder::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +10949:SkRecorder::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10950:SkRecorder::onDrawPaint\28SkPaint\20const&\29 +10951:SkRecorder::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10952:SkRecorder::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +10953:SkRecorder::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10954:SkRecorder::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +10955:SkRecorder::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10956:SkRecorder::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +10957:SkRecorder::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10958:SkRecorder::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10959:SkRecorder::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +10960:SkRecorder::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10961:SkRecorder::onDrawBehind\28SkPaint\20const&\29 +10962:SkRecorder::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +10963:SkRecorder::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +10964:SkRecorder::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +10965:SkRecorder::onDoSaveBehind\28SkRect\20const*\29 +10966:SkRecorder::onClipShader\28sk_sp\2c\20SkClipOp\29 +10967:SkRecorder::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10968:SkRecorder::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10969:SkRecorder::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10970:SkRecorder::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10971:SkRecorder::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +10972:SkRecorder::didTranslate\28float\2c\20float\29 +10973:SkRecorder::didSetM44\28SkM44\20const&\29 +10974:SkRecorder::didScale\28float\2c\20float\29 +10975:SkRecorder::didRestore\28\29 +10976:SkRecorder::didConcat44\28SkM44\20const&\29 +10977:SkRecordedDrawable::~SkRecordedDrawable\28\29_3776 +10978:SkRecordedDrawable::onMakePictureSnapshot\28\29 +10979:SkRecordedDrawable::onGetBounds\28\29 +10980:SkRecordedDrawable::onDraw\28SkCanvas*\29 +10981:SkRecordedDrawable::onApproximateBytesUsed\28\29 +10982:SkRecordedDrawable::getTypeName\28\29\20const +10983:SkRecordedDrawable::flatten\28SkWriteBuffer&\29\20const +10984:SkRecord::~SkRecord\28\29_3755 +10985:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29_1638 +10986:SkRasterPipelineSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +10987:SkRasterPipelineSpriteBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10988:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29_3727 +10989:SkRasterPipelineBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10990:SkRasterPipelineBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10991:SkRasterPipelineBlitter::blitH\28int\2c\20int\2c\20int\29 +10992:SkRasterPipelineBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10993:SkRasterPipelineBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10994:SkRasterPipelineBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10995:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_3::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10996:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_2::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10997:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_1::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10998:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_0::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10999:SkRadialGradient::getTypeName\28\29\20const +11000:SkRadialGradient::flatten\28SkWriteBuffer&\29\20const +11001:SkRadialGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11002:SkRadialGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +11003:SkRTree::~SkRTree\28\29_3661 +11004:SkRTree::search\28SkRect\20const&\2c\20std::__2::vector>*\29\20const +11005:SkRTree::insert\28SkRect\20const*\2c\20int\29 +11006:SkRTree::bytesUsed\28\29\20const +11007:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_3::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +11008:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_2::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +11009:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_1::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +11010:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_0::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +11011:SkPixelRef::~SkPixelRef\28\29_3629 +11012:SkPictureRecord::~SkPictureRecord\28\29_3541 +11013:SkPictureRecord::willSave\28\29 +11014:SkPictureRecord::willRestore\28\29 +11015:SkPictureRecord::onResetClip\28\29 +11016:SkPictureRecord::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +11017:SkPictureRecord::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +11018:SkPictureRecord::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +11019:SkPictureRecord::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +11020:SkPictureRecord::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +11021:SkPictureRecord::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +11022:SkPictureRecord::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +11023:SkPictureRecord::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +11024:SkPictureRecord::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +11025:SkPictureRecord::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +11026:SkPictureRecord::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +11027:SkPictureRecord::onDrawPaint\28SkPaint\20const&\29 +11028:SkPictureRecord::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +11029:SkPictureRecord::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +11030:SkPictureRecord::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +11031:SkPictureRecord::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +11032:SkPictureRecord::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +11033:SkPictureRecord::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +11034:SkPictureRecord::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +11035:SkPictureRecord::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +11036:SkPictureRecord::onDrawBehind\28SkPaint\20const&\29 +11037:SkPictureRecord::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +11038:SkPictureRecord::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +11039:SkPictureRecord::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +11040:SkPictureRecord::onDoSaveBehind\28SkRect\20const*\29 +11041:SkPictureRecord::onClipShader\28sk_sp\2c\20SkClipOp\29 +11042:SkPictureRecord::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +11043:SkPictureRecord::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +11044:SkPictureRecord::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +11045:SkPictureRecord::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +11046:SkPictureRecord::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +11047:SkPictureRecord::didTranslate\28float\2c\20float\29 +11048:SkPictureRecord::didSetM44\28SkM44\20const&\29 +11049:SkPictureRecord::didScale\28float\2c\20float\29 +11050:SkPictureRecord::didConcat44\28SkM44\20const&\29 +11051:SkPictureImageGenerator::~SkPictureImageGenerator\28\29_4452 +11052:SkPictureImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +11053:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29_7719 +11054:SkOTUtils::LocalizedStrings_SingleName::next\28SkTypeface::LocalizedString*\29 +11055:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29_6879 +11056:SkOTUtils::LocalizedStrings_NameTable::next\28SkTypeface::LocalizedString*\29 +11057:SkNoPixelsDevice::~SkNoPixelsDevice\28\29_2167 +11058:SkNoPixelsDevice::replaceClip\28SkIRect\20const&\29 +11059:SkNoPixelsDevice::pushClipStack\28\29 +11060:SkNoPixelsDevice::popClipStack\28\29 +11061:SkNoPixelsDevice::onClipShader\28sk_sp\29 +11062:SkNoPixelsDevice::isClipWideOpen\28\29\20const +11063:SkNoPixelsDevice::isClipRect\28\29\20const +11064:SkNoPixelsDevice::isClipEmpty\28\29\20const +11065:SkNoPixelsDevice::isClipAntiAliased\28\29\20const +11066:SkNoPixelsDevice::devClipBounds\28\29\20const +11067:SkNoPixelsDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +11068:SkNoPixelsDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +11069:SkNoPixelsDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +11070:SkNoPixelsDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +11071:SkNoPixelsDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +11072:SkMipmap::~SkMipmap\28\29_2730 +11073:SkMipmap::onDataChange\28void*\2c\20void*\29 +11074:SkMemoryStream::~SkMemoryStream\28\29_4122 +11075:SkMemoryStream::setMemory\28void\20const*\2c\20unsigned\20long\2c\20bool\29 +11076:SkMemoryStream::seek\28unsigned\20long\29 +11077:SkMemoryStream::rewind\28\29 +11078:SkMemoryStream::read\28void*\2c\20unsigned\20long\29 +11079:SkMemoryStream::peek\28void*\2c\20unsigned\20long\29\20const +11080:SkMemoryStream::onFork\28\29\20const +11081:SkMemoryStream::onDuplicate\28\29\20const +11082:SkMemoryStream::move\28long\29 +11083:SkMemoryStream::isAtEnd\28\29\20const +11084:SkMemoryStream::getMemoryBase\28\29 +11085:SkMemoryStream::getLength\28\29\20const +11086:SkMemoryStream::getData\28\29\20const +11087:SkMatrixColorFilter::onIsAlphaUnchanged\28\29\20const +11088:SkMatrixColorFilter::onAsAColorMatrix\28float*\29\20const +11089:SkMatrixColorFilter::getTypeName\28\29\20const +11090:SkMatrixColorFilter::flatten\28SkWriteBuffer&\29\20const +11091:SkMatrixColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11092:SkMatrix::Trans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11093:SkMatrix::Trans_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11094:SkMatrix::Scale_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11095:SkMatrix::Scale_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11096:SkMatrix::ScaleTrans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11097:SkMatrix::Poly4Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +11098:SkMatrix::Poly3Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +11099:SkMatrix::Poly2Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +11100:SkMatrix::Persp_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11101:SkMatrix::Persp_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11102:SkMatrix::Identity_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11103:SkMatrix::Identity_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11104:SkMatrix::Affine_vpts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11105:SkMaskFilterBase::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11106:SkMaskFilterBase::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11107:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29_2572 +11108:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29_3631 +11109:SkLocalMatrixShader::~SkLocalMatrixShader\28\29_4576 +11110:SkLocalMatrixShader::~SkLocalMatrixShader\28\29 +11111:SkLocalMatrixShader::type\28\29\20const +11112:SkLocalMatrixShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +11113:SkLocalMatrixShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +11114:SkLocalMatrixShader::makeAsALocalMatrixShader\28SkMatrix*\29\20const +11115:SkLocalMatrixShader::isOpaque\28\29\20const +11116:SkLocalMatrixShader::isConstant\28\29\20const +11117:SkLocalMatrixShader::getTypeName\28\29\20const +11118:SkLocalMatrixShader::flatten\28SkWriteBuffer&\29\20const +11119:SkLocalMatrixShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11120:SkLocalMatrixShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11121:SkLinearGradient::getTypeName\28\29\20const +11122:SkLinearGradient::flatten\28SkWriteBuffer&\29\20const +11123:SkLinearGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11124:SkJSONWriter::popScope\28\29 +11125:SkJSONWriter::appendf\28char\20const*\2c\20...\29 +11126:SkIntersections::hasOppT\28double\29\20const +11127:SkImage_Raster::~SkImage_Raster\28\29_4426 +11128:SkImage_Raster::onReinterpretColorSpace\28sk_sp\29\20const +11129:SkImage_Raster::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +11130:SkImage_Raster::onPeekPixels\28SkPixmap*\29\20const +11131:SkImage_Raster::onPeekMips\28\29\20const +11132:SkImage_Raster::onMakeWithMipmaps\28sk_sp\29\20const +11133:SkImage_Raster::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11134:SkImage_Raster::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11135:SkImage_Raster::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +11136:SkImage_Raster::onHasMipmaps\28\29\20const +11137:SkImage_Raster::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +11138:SkImage_Raster::notifyAddedToRasterCache\28\29\20const +11139:SkImage_Raster::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +11140:SkImage_Picture::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11141:SkImage_Picture::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11142:SkImage_LazyTexture::readPixelsProxy\28GrDirectContext*\2c\20SkPixmap\20const&\29\20const +11143:SkImage_LazyTexture::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11144:SkImage_Lazy::onReinterpretColorSpace\28sk_sp\29\20const +11145:SkImage_Lazy::onRefEncoded\28\29\20const +11146:SkImage_Lazy::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +11147:SkImage_Lazy::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11148:SkImage_Lazy::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11149:SkImage_Lazy::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +11150:SkImage_Lazy::onIsProtected\28\29\20const +11151:SkImage_Lazy::isValid\28GrRecordingContext*\29\20const +11152:SkImage_Lazy::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +11153:SkImage_GaneshBase::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +11154:SkImage_GaneshBase::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +11155:SkImage_GaneshBase::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11156:SkImage_GaneshBase::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11157:SkImage_GaneshBase::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +11158:SkImage_GaneshBase::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +11159:SkImage_GaneshBase::isValid\28GrRecordingContext*\29\20const +11160:SkImage_GaneshBase::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +11161:SkImage_GaneshBase::directContext\28\29\20const +11162:SkImage_Ganesh::~SkImage_Ganesh\28\29_10261 +11163:SkImage_Ganesh::textureSize\28\29\20const +11164:SkImage_Ganesh::onReinterpretColorSpace\28sk_sp\29\20const +11165:SkImage_Ganesh::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +11166:SkImage_Ganesh::onIsProtected\28\29\20const +11167:SkImage_Ganesh::onHasMipmaps\28\29\20const +11168:SkImage_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +11169:SkImage_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +11170:SkImage_Ganesh::generatingSurfaceIsDeleted\28\29 +11171:SkImage_Ganesh::flush\28GrDirectContext*\2c\20GrFlushInfo\20const&\29\20const +11172:SkImage_Ganesh::asView\28GrRecordingContext*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29\20const +11173:SkImage_Ganesh::asFragmentProcessor\28GrRecordingContext*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29\20const +11174:SkImage_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +11175:SkImage_Base::notifyAddedToRasterCache\28\29\20const +11176:SkImage_Base::makeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11177:SkImage_Base::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11178:SkImage_Base::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +11179:SkImage_Base::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +11180:SkImage_Base::makeColorSpace\28skgpu::graphite::Recorder*\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +11181:SkImage_Base::makeColorSpace\28GrDirectContext*\2c\20sk_sp\29\20const +11182:SkImage_Base::isTextureBacked\28\29\20const +11183:SkImage_Base::isLazyGenerated\28\29\20const +11184:SkImageShader::~SkImageShader\28\29_4540 +11185:SkImageShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +11186:SkImageShader::isOpaque\28\29\20const +11187:SkImageShader::getTypeName\28\29\20const +11188:SkImageShader::flatten\28SkWriteBuffer&\29\20const +11189:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11190:SkImageGenerator::~SkImageGenerator\28\29_550 +11191:SkImageFilter::computeFastBounds\28SkRect\20const&\29\20const +11192:SkGradientBaseShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +11193:SkGradientBaseShader::isOpaque\28\29\20const +11194:SkGradientBaseShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11195:SkGaussianColorFilter::getTypeName\28\29\20const +11196:SkGaussianColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11197:SkGammaColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +11198:SkGammaColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +11199:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29_7595 +11200:SkFontStyleSet_Custom::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +11201:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29_7733 +11202:SkFontScanner_FreeType::scanFile\28SkStreamAsset*\2c\20int*\29\20const +11203:SkFontScanner_FreeType::scanFace\28SkStreamAsset*\2c\20int\2c\20int*\29\20const +11204:SkFontScanner_FreeType::getFactoryId\28\29\20const +11205:SkFontMgr_Custom::~SkFontMgr_Custom\28\29_7601 +11206:SkFontMgr_Custom::onMatchFamily\28char\20const*\29\20const +11207:SkFontMgr_Custom::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +11208:SkFontMgr_Custom::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +11209:SkFontMgr_Custom::onMakeFromFile\28char\20const*\2c\20int\29\20const +11210:SkFontMgr_Custom::onMakeFromData\28sk_sp\2c\20int\29\20const +11211:SkFontMgr_Custom::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +11212:SkFontMgr_Custom::onGetFamilyName\28int\2c\20SkString*\29\20const +11213:SkFILEStream::~SkFILEStream\28\29_4099 +11214:SkFILEStream::seek\28unsigned\20long\29 +11215:SkFILEStream::rewind\28\29 +11216:SkFILEStream::read\28void*\2c\20unsigned\20long\29 +11217:SkFILEStream::onFork\28\29\20const +11218:SkFILEStream::onDuplicate\28\29\20const +11219:SkFILEStream::move\28long\29 +11220:SkFILEStream::isAtEnd\28\29\20const +11221:SkFILEStream::getPosition\28\29\20const +11222:SkFILEStream::getLength\28\29\20const +11223:SkEmptyShader::getTypeName\28\29\20const +11224:SkEmptyPicture::~SkEmptyPicture\28\29 +11225:SkEmptyPicture::cullRect\28\29\20const +11226:SkEmptyPicture::approximateBytesUsed\28\29\20const +11227:SkEmptyFontMgr::onMatchFamily\28char\20const*\29\20const +11228:SkEdgeBuilder::build\28SkPath\20const&\2c\20SkIRect\20const*\2c\20bool\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +11229:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29_4139 +11230:SkDynamicMemoryWStream::bytesWritten\28\29\20const +11231:SkDraw::paintMasks\28SkZip\2c\20SkPaint\20const&\29\20const +11232:SkDevice::strikeDeviceInfo\28\29\20const +11233:SkDevice::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +11234:SkDevice::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +11235:SkDevice::drawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20sk_sp\2c\20SkPaint\20const&\29 +11236:SkDevice::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +11237:SkDevice::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +11238:SkDevice::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11239:SkDevice::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +11240:SkDevice::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +11241:SkDevice::drawCoverageMask\28SkSpecialImage\20const*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +11242:SkDevice::drawBlurredRRect\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20float\29 +11243:SkDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +11244:SkDevice::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11245:SkDevice::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +11246:SkDashImpl::~SkDashImpl\28\29_5248 +11247:SkDashImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +11248:SkDashImpl::onAsPoints\28SkPathEffectBase::PointData*\2c\20SkPath\20const&\2c\20SkStrokeRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\29\20const +11249:SkDashImpl::getTypeName\28\29\20const +11250:SkDashImpl::flatten\28SkWriteBuffer&\29\20const +11251:SkDashImpl::asADash\28SkPathEffectBase::DashInfo*\29\20const +11252:SkDCurve::nearPoint\28SkPath::Verb\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29\20const +11253:SkContourMeasure::~SkContourMeasure\28\29_2089 +11254:SkConicalGradient::getTypeName\28\29\20const +11255:SkConicalGradient::flatten\28SkWriteBuffer&\29\20const +11256:SkConicalGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11257:SkConicalGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +11258:SkComposeColorFilter::onIsAlphaUnchanged\28\29\20const +11259:SkComposeColorFilter::getTypeName\28\29\20const +11260:SkComposeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11261:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29_5349 +11262:SkColorSpaceXformColorFilter::getTypeName\28\29\20const +11263:SkColorSpaceXformColorFilter::flatten\28SkWriteBuffer&\29\20const +11264:SkColorSpaceXformColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11265:SkColorShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +11266:SkColorShader::isOpaque\28\29\20const +11267:SkColorShader::getTypeName\28\29\20const +11268:SkColorShader::flatten\28SkWriteBuffer&\29\20const +11269:SkColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11270:SkColorFilterShader::~SkColorFilterShader\28\29_4513 +11271:SkColorFilterShader::isOpaque\28\29\20const +11272:SkColorFilterShader::getTypeName\28\29\20const +11273:SkColorFilterShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11274:SkColorFilterBase::onFilterColor4f\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkColorSpace*\29\20const +11275:SkCoincidentSpans::setOppPtTStart\28SkOpPtT\20const*\29 +11276:SkCoincidentSpans::setOppPtTEnd\28SkOpPtT\20const*\29 +11277:SkCoincidentSpans::setCoinPtTStart\28SkOpPtT\20const*\29 +11278:SkCoincidentSpans::setCoinPtTEnd\28SkOpPtT\20const*\29 +11279:SkCanvas::~SkCanvas\28\29_1881 +11280:SkCanvas::recordingContext\28\29\20const +11281:SkCanvas::recorder\28\29\20const +11282:SkCanvas::onPeekPixels\28SkPixmap*\29 +11283:SkCanvas::onNewSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +11284:SkCanvas::onImageInfo\28\29\20const +11285:SkCanvas::onGetProps\28SkSurfaceProps*\2c\20bool\29\20const +11286:SkCanvas::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +11287:SkCanvas::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +11288:SkCanvas::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +11289:SkCanvas::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +11290:SkCanvas::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +11291:SkCanvas::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +11292:SkCanvas::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +11293:SkCanvas::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +11294:SkCanvas::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +11295:SkCanvas::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +11296:SkCanvas::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +11297:SkCanvas::onDrawPaint\28SkPaint\20const&\29 +11298:SkCanvas::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +11299:SkCanvas::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +11300:SkCanvas::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +11301:SkCanvas::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +11302:SkCanvas::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +11303:SkCanvas::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11304:SkCanvas::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +11305:SkCanvas::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +11306:SkCanvas::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +11307:SkCanvas::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +11308:SkCanvas::onDrawBehind\28SkPaint\20const&\29 +11309:SkCanvas::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +11310:SkCanvas::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +11311:SkCanvas::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +11312:SkCanvas::onDiscard\28\29 +11313:SkCanvas::onConvertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11314:SkCanvas::onAccessTopLayerPixels\28SkPixmap*\29 +11315:SkCanvas::isClipRect\28\29\20const +11316:SkCanvas::isClipEmpty\28\29\20const +11317:SkCanvas::getBaseLayerSize\28\29\20const +11318:SkCachedData::~SkCachedData\28\29_1797 +11319:SkCTMShader::~SkCTMShader\28\29_4566 +11320:SkCTMShader::~SkCTMShader\28\29 +11321:SkCTMShader::isConstant\28\29\20const +11322:SkCTMShader::getTypeName\28\29\20const +11323:SkCTMShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11324:SkCTMShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11325:SkBreakIterator_client::~SkBreakIterator_client\28\29_7552 +11326:SkBreakIterator_client::status\28\29 +11327:SkBreakIterator_client::setText\28char\20const*\2c\20int\29 +11328:SkBreakIterator_client::setText\28char16_t\20const*\2c\20int\29 +11329:SkBreakIterator_client::next\28\29 +11330:SkBreakIterator_client::isDone\28\29 +11331:SkBreakIterator_client::first\28\29 +11332:SkBreakIterator_client::current\28\29 +11333:SkBlurMaskFilterImpl::getTypeName\28\29\20const +11334:SkBlurMaskFilterImpl::flatten\28SkWriteBuffer&\29\20const +11335:SkBlurMaskFilterImpl::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11336:SkBlurMaskFilterImpl::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11337:SkBlurMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +11338:SkBlurMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +11339:SkBlurMaskFilterImpl::asImageFilter\28SkMatrix\20const&\29\20const +11340:SkBlurMaskFilterImpl::asABlur\28SkMaskFilterBase::BlurRec*\29\20const +11341:SkBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11342:SkBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11343:SkBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11344:SkBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11345:SkBlitter::allocBlitMemory\28unsigned\20long\29 +11346:SkBlendShader::getTypeName\28\29\20const +11347:SkBlendShader::flatten\28SkWriteBuffer&\29\20const +11348:SkBlendShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11349:SkBlendModeColorFilter::onIsAlphaUnchanged\28\29\20const +11350:SkBlendModeColorFilter::onAsAColorMode\28unsigned\20int*\2c\20SkBlendMode*\29\20const +11351:SkBlendModeColorFilter::getTypeName\28\29\20const +11352:SkBlendModeColorFilter::flatten\28SkWriteBuffer&\29\20const +11353:SkBlendModeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11354:SkBlendModeBlender::onAppendStages\28SkStageRec\20const&\29\20const +11355:SkBlendModeBlender::getTypeName\28\29\20const +11356:SkBlendModeBlender::flatten\28SkWriteBuffer&\29\20const +11357:SkBlendModeBlender::asBlendMode\28\29\20const +11358:SkBitmapDevice::~SkBitmapDevice\28\29_1307 +11359:SkBitmapDevice::snapSpecial\28SkIRect\20const&\2c\20bool\29 +11360:SkBitmapDevice::setImmutable\28\29 +11361:SkBitmapDevice::replaceClip\28SkIRect\20const&\29 +11362:SkBitmapDevice::pushClipStack\28\29 +11363:SkBitmapDevice::popClipStack\28\29 +11364:SkBitmapDevice::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +11365:SkBitmapDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +11366:SkBitmapDevice::onPeekPixels\28SkPixmap*\29 +11367:SkBitmapDevice::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11368:SkBitmapDevice::onClipShader\28sk_sp\29 +11369:SkBitmapDevice::onAccessPixels\28SkPixmap*\29 +11370:SkBitmapDevice::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +11371:SkBitmapDevice::makeSpecial\28SkImage\20const*\29 +11372:SkBitmapDevice::makeSpecial\28SkBitmap\20const&\29 +11373:SkBitmapDevice::isClipWideOpen\28\29\20const +11374:SkBitmapDevice::isClipRect\28\29\20const +11375:SkBitmapDevice::isClipEmpty\28\29\20const +11376:SkBitmapDevice::isClipAntiAliased\28\29\20const +11377:SkBitmapDevice::getRasterHandle\28\29\20const +11378:SkBitmapDevice::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +11379:SkBitmapDevice::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11380:SkBitmapDevice::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +11381:SkBitmapDevice::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +11382:SkBitmapDevice::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +11383:SkBitmapDevice::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +11384:SkBitmapDevice::drawPaint\28SkPaint\20const&\29 +11385:SkBitmapDevice::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +11386:SkBitmapDevice::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11387:SkBitmapDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +11388:SkBitmapDevice::devClipBounds\28\29\20const +11389:SkBitmapDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +11390:SkBitmapDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +11391:SkBitmapDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +11392:SkBitmapDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +11393:SkBitmapDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +11394:SkBitmapDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +11395:SkBitmapCache::Rec::~Rec\28\29_1270 +11396:SkBitmapCache::Rec::postAddInstall\28void*\29 +11397:SkBitmapCache::Rec::getCategory\28\29\20const +11398:SkBitmapCache::Rec::canBePurged\28\29 +11399:SkBitmapCache::Rec::bytesUsed\28\29\20const +11400:SkBitmapCache::Rec::ReleaseProc\28void*\2c\20void*\29 +11401:SkBitmapCache::Rec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +11402:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29_4320 +11403:SkBinaryWriteBuffer::write\28SkM44\20const&\29 +11404:SkBinaryWriteBuffer::writeTypeface\28SkTypeface*\29 +11405:SkBinaryWriteBuffer::writeString\28std::__2::basic_string_view>\29 +11406:SkBinaryWriteBuffer::writeStream\28SkStream*\2c\20unsigned\20long\29 +11407:SkBinaryWriteBuffer::writeScalar\28float\29 +11408:SkBinaryWriteBuffer::writeSampling\28SkSamplingOptions\20const&\29 +11409:SkBinaryWriteBuffer::writeRegion\28SkRegion\20const&\29 +11410:SkBinaryWriteBuffer::writeRect\28SkRect\20const&\29 +11411:SkBinaryWriteBuffer::writePoint\28SkPoint\20const&\29 +11412:SkBinaryWriteBuffer::writePointArray\28SkPoint\20const*\2c\20unsigned\20int\29 +11413:SkBinaryWriteBuffer::writePoint3\28SkPoint3\20const&\29 +11414:SkBinaryWriteBuffer::writePath\28SkPath\20const&\29 +11415:SkBinaryWriteBuffer::writePaint\28SkPaint\20const&\29 +11416:SkBinaryWriteBuffer::writePad32\28void\20const*\2c\20unsigned\20long\29 +11417:SkBinaryWriteBuffer::writeMatrix\28SkMatrix\20const&\29 +11418:SkBinaryWriteBuffer::writeImage\28SkImage\20const*\29 +11419:SkBinaryWriteBuffer::writeColor4fArray\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20unsigned\20int\29 +11420:SkBinaryWriteBuffer::writeBool\28bool\29 +11421:SkBigPicture::~SkBigPicture\28\29_1185 +11422:SkBigPicture::playback\28SkCanvas*\2c\20SkPicture::AbortCallback*\29\20const +11423:SkBigPicture::approximateOpCount\28bool\29\20const +11424:SkBigPicture::approximateBytesUsed\28\29\20const +11425:SkBidiSubsetFactory::errorName\28UErrorCode\29\20const +11426:SkBidiSubsetFactory::bidi_setPara\28UBiDi*\2c\20char16_t\20const*\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20UErrorCode*\29\20const +11427:SkBidiSubsetFactory::bidi_reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29\20const +11428:SkBidiSubsetFactory::bidi_openSized\28int\2c\20int\2c\20UErrorCode*\29\20const +11429:SkBidiSubsetFactory::bidi_getLevelAt\28UBiDi\20const*\2c\20int\29\20const +11430:SkBidiSubsetFactory::bidi_getLength\28UBiDi\20const*\29\20const +11431:SkBidiSubsetFactory::bidi_getDirection\28UBiDi\20const*\29\20const +11432:SkBidiSubsetFactory::bidi_close_callback\28\29\20const +11433:SkBasicEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +11434:SkBasicEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +11435:SkBasicEdgeBuilder::addQuad\28SkPoint\20const*\29 +11436:SkBasicEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +11437:SkBasicEdgeBuilder::addLine\28SkPoint\20const*\29 +11438:SkBasicEdgeBuilder::addCubic\28SkPoint\20const*\29 +11439:SkBBoxHierarchy::insert\28SkRect\20const*\2c\20SkBBoxHierarchy::Metadata\20const*\2c\20int\29 +11440:SkArenaAlloc::SkipPod\28char*\29 +11441:SkArenaAlloc::NextBlock\28char*\29 +11442:SkAnalyticEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +11443:SkAnalyticEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +11444:SkAnalyticEdgeBuilder::addQuad\28SkPoint\20const*\29 +11445:SkAnalyticEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +11446:SkAnalyticEdgeBuilder::addLine\28SkPoint\20const*\29 +11447:SkAnalyticEdgeBuilder::addCubic\28SkPoint\20const*\29 +11448:SkAAClipBlitter::~SkAAClipBlitter\28\29_1143 +11449:SkAAClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11450:SkAAClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11451:SkAAClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11452:SkAAClipBlitter::blitH\28int\2c\20int\2c\20int\29 +11453:SkAAClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11454:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_1::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +11455:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_0::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +11456:SkAAClip::Builder::Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11457:SkAAClip::Builder::Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11458:SkAAClip::Builder::Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11459:SkAAClip::Builder::Blitter::blitH\28int\2c\20int\2c\20int\29 +11460:SkAAClip::Builder::Blitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11461:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29_1601 +11462:SkA8_Coverage_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11463:SkA8_Coverage_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11464:SkA8_Coverage_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11465:SkA8_Coverage_Blitter::blitH\28int\2c\20int\2c\20int\29 +11466:SkA8_Coverage_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11467:SkA8_Blitter::~SkA8_Blitter\28\29_1616 +11468:SkA8_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11469:SkA8_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11470:SkA8_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11471:SkA8_Blitter::blitH\28int\2c\20int\2c\20int\29 +11472:SkA8_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11473:SkA8Blitter_Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +11474:ShaderPDXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11475:ShaderPDXferProcessor::name\28\29\20const +11476:ShaderPDXferProcessor::makeProgramImpl\28\29\20const +11477:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11478:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11479:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11480:RuntimeEffectRPCallbacks::toLinearSrgb\28void\20const*\29 +11481:RuntimeEffectRPCallbacks::fromLinearSrgb\28void\20const*\29 +11482:RuntimeEffectRPCallbacks::appendShader\28int\29 +11483:RuntimeEffectRPCallbacks::appendColorFilter\28int\29 +11484:RuntimeEffectRPCallbacks::appendBlender\28int\29 +11485:RunBasedAdditiveBlitter::getRealBlitter\28bool\29 +11486:RunBasedAdditiveBlitter::flush_if_y_changed\28int\2c\20int\29 +11487:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11488:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11489:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11490:Round_Up_To_Grid +11491:Round_To_Half_Grid +11492:Round_To_Grid +11493:Round_To_Double_Grid +11494:Round_Super_45 +11495:Round_Super +11496:Round_None +11497:Round_Down_To_Grid +11498:RoundJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11499:RoundCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +11500:Read_CVT_Stretched +11501:Read_CVT +11502:Project_y +11503:Project +11504:PrePostInverseBlitterProc\28SkBlitter*\2c\20int\2c\20bool\29 +11505:PorterDuffXferProcessor::onHasSecondaryOutput\28\29\20const +11506:PorterDuffXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11507:PorterDuffXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11508:PorterDuffXferProcessor::name\28\29\20const +11509:PorterDuffXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11510:PorterDuffXferProcessor::makeProgramImpl\28\29\20const +11511:PDLCDXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +11512:PDLCDXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11513:PDLCDXferProcessor::name\28\29\20const +11514:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +11515:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11516:PDLCDXferProcessor::makeProgramImpl\28\29\20const +11517:OT::match_glyph\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11518:OT::match_coverage\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11519:OT::match_class_cached\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11520:OT::match_class_cached2\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11521:OT::match_class_cached1\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11522:OT::match_class\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11523:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GSUB_impl::SubstLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +11524:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GPOS_impl::PosLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +11525:OT::Layout::Common::RangeRecord::cmp_range\28void\20const*\2c\20void\20const*\29 +11526:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +11527:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +11528:OT::CmapSubtableFormat4::accelerator_t::get_glyph_func\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +11529:Move_CVT_Stretched +11530:Move_CVT +11531:MiterJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11532:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29_3967 +11533:MaskAdditiveBlitter::getWidth\28\29 +11534:MaskAdditiveBlitter::getRealBlitter\28bool\29 +11535:MaskAdditiveBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11536:MaskAdditiveBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11537:MaskAdditiveBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11538:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11539:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11540:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11541:InverseBlitter::blitH\28int\2c\20int\2c\20int\29 +11542:Horish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +11543:Horish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +11544:HLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +11545:HLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +11546:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11547:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11548:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const +11549:GrYUVtoRGBEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11550:GrYUVtoRGBEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11551:GrYUVtoRGBEffect::name\28\29\20const +11552:GrYUVtoRGBEffect::clone\28\29\20const +11553:GrXferProcessor::ProgramImpl::emitWriteSwizzle\28GrGLSLXPFragmentBuilder*\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20char\20const*\29\20const +11554:GrXferProcessor::ProgramImpl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11555:GrXferProcessor::ProgramImpl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +11556:GrWritePixelsTask::~GrWritePixelsTask\28\29_9535 +11557:GrWritePixelsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +11558:GrWritePixelsTask::onExecute\28GrOpFlushState*\29 +11559:GrWritePixelsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11560:GrWaitRenderTask::~GrWaitRenderTask\28\29_9530 +11561:GrWaitRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +11562:GrWaitRenderTask::onExecute\28GrOpFlushState*\29 +11563:GrWaitRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11564:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29_9523 +11565:GrTransferFromRenderTask::onExecute\28GrOpFlushState*\29 +11566:GrTransferFromRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11567:GrThreadSafeCache::Trampoline::~Trampoline\28\29_9519 +11568:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29_9491 +11569:GrTextureResolveRenderTask::onExecute\28GrOpFlushState*\29 +11570:GrTextureResolveRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11571:GrTextureEffect::~GrTextureEffect\28\29_9966 +11572:GrTextureEffect::onMakeProgramImpl\28\29\20const +11573:GrTextureEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11574:GrTextureEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11575:GrTextureEffect::name\28\29\20const +11576:GrTextureEffect::clone\28\29\20const +11577:GrTextureEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11578:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11579:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29_8054 +11580:GrTDeferredProxyUploader>::freeData\28\29 +11581:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29_11200 +11582:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::freeData\28\29 +11583:GrSurfaceProxy::getUniqueKey\28\29\20const +11584:GrSurface::getResourceType\28\29\20const +11585:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29_11365 +11586:GrStrokeTessellationShader::name\28\29\20const +11587:GrStrokeTessellationShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11588:GrStrokeTessellationShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11589:GrStrokeTessellationShader::Impl::~Impl\28\29_11370 +11590:GrStrokeTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11591:GrStrokeTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11592:GrSkSLFP::~GrSkSLFP\28\29_9923 +11593:GrSkSLFP::onMakeProgramImpl\28\29\20const +11594:GrSkSLFP::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11595:GrSkSLFP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11596:GrSkSLFP::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11597:GrSkSLFP::clone\28\29\20const +11598:GrSkSLFP::Impl::~Impl\28\29_9931 +11599:GrSkSLFP::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11600:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11601:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11602:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11603:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11604:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::getMangledName\28char\20const*\29 +11605:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11606:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +11607:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +11608:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareFunction\28char\20const*\29 +11609:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11610:GrSimpleMesh*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29::'lambda'\28char*\29::__invoke\28char*\29 +11611:GrRingBuffer::FinishSubmit\28void*\29 +11612:GrResourceCache::CompareTimestamp\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29 +11613:GrRenderTask::disown\28GrDrawingManager*\29 +11614:GrRecordingContext::~GrRecordingContext\28\29_9255 +11615:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29_9914 +11616:GrRRectShadowGeoProc::onTextureSampler\28int\29\20const +11617:GrRRectShadowGeoProc::name\28\29\20const +11618:GrRRectShadowGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11619:GrRRectShadowGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11620:GrQuadEffect::name\28\29\20const +11621:GrQuadEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11622:GrQuadEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11623:GrQuadEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11624:GrQuadEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11625:GrPorterDuffXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11626:GrPorterDuffXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11627:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29_9856 +11628:GrPerlinNoise2Effect::onMakeProgramImpl\28\29\20const +11629:GrPerlinNoise2Effect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11630:GrPerlinNoise2Effect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11631:GrPerlinNoise2Effect::name\28\29\20const +11632:GrPerlinNoise2Effect::clone\28\29\20const +11633:GrPerlinNoise2Effect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11634:GrPerlinNoise2Effect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11635:GrPathTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11636:GrPathTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11637:GrOpsRenderPass::onExecuteDrawable\28std::__2::unique_ptr>\29 +11638:GrOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11639:GrOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11640:GrOpFlushState::writeView\28\29\20const +11641:GrOpFlushState::usesMSAASurface\28\29\20const +11642:GrOpFlushState::tokenTracker\28\29 +11643:GrOpFlushState::threadSafeCache\28\29\20const +11644:GrOpFlushState::strikeCache\28\29\20const +11645:GrOpFlushState::sampledProxyArray\28\29 +11646:GrOpFlushState::rtProxy\28\29\20const +11647:GrOpFlushState::resourceProvider\28\29\20const +11648:GrOpFlushState::renderPassBarriers\28\29\20const +11649:GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +11650:GrOpFlushState::putBackIndirectDraws\28int\29 +11651:GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +11652:GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +11653:GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +11654:GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +11655:GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +11656:GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +11657:GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +11658:GrOpFlushState::dstProxyView\28\29\20const +11659:GrOpFlushState::colorLoadOp\28\29\20const +11660:GrOpFlushState::caps\28\29\20const +11661:GrOpFlushState::atlasManager\28\29\20const +11662:GrOpFlushState::appliedClip\28\29\20const +11663:GrOpFlushState::addInlineUpload\28std::__2::function&\29>&&\29 +11664:GrOnFlushCallbackObject::postFlush\28skgpu::AtlasToken\29 +11665:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11666:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11667:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const +11668:GrModulateAtlasCoverageEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11669:GrModulateAtlasCoverageEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11670:GrModulateAtlasCoverageEffect::name\28\29\20const +11671:GrModulateAtlasCoverageEffect::clone\28\29\20const +11672:GrMeshDrawOp::onPrepare\28GrOpFlushState*\29 +11673:GrMeshDrawOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11674:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11675:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11676:GrMatrixEffect::onMakeProgramImpl\28\29\20const +11677:GrMatrixEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11678:GrMatrixEffect::name\28\29\20const +11679:GrMatrixEffect::clone\28\29\20const +11680:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29_9560 +11681:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::$_0::__invoke\28void\20const*\2c\20void*\29 +11682:GrImageContext::~GrImageContext\28\29 +11683:GrHardClip::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +11684:GrGpuResource::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +11685:GrGpuBuffer::unref\28\29\20const +11686:GrGpuBuffer::getResourceType\28\29\20const +11687:GrGpuBuffer::computeScratchKey\28skgpu::ScratchKey*\29\20const +11688:GrGpu::startTimerQuery\28\29 +11689:GrGpu::endTimerQuery\28GrTimerQuery\20const&\29 +11690:GrGeometryProcessor::onTextureSampler\28int\29\20const +11691:GrGLVaryingHandler::~GrGLVaryingHandler\28\29 +11692:GrGLUniformHandler::~GrGLUniformHandler\28\29_11946 +11693:GrGLUniformHandler::samplerVariable\28GrResourceHandle\29\20const +11694:GrGLUniformHandler::samplerSwizzle\28GrResourceHandle\29\20const +11695:GrGLUniformHandler::internalAddUniformArray\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20bool\2c\20int\2c\20char\20const**\29 +11696:GrGLUniformHandler::getUniformCStr\28GrResourceHandle\29\20const +11697:GrGLUniformHandler::appendUniformDecls\28GrShaderFlags\2c\20SkString*\29\20const +11698:GrGLUniformHandler::addSampler\28GrBackendFormat\20const&\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20GrShaderCaps\20const*\29 +11699:GrGLTextureRenderTarget::onSetLabel\28\29 +11700:GrGLTextureRenderTarget::backendFormat\28\29\20const +11701:GrGLTexture::textureParamsModified\28\29 +11702:GrGLTexture::onStealBackendTexture\28GrBackendTexture*\2c\20std::__2::function*\29 +11703:GrGLTexture::getBackendTexture\28\29\20const +11704:GrGLSemaphore::~GrGLSemaphore\28\29_11878 +11705:GrGLSemaphore::setIsOwned\28\29 +11706:GrGLSemaphore::backendSemaphore\28\29\20const +11707:GrGLSLVertexBuilder::~GrGLSLVertexBuilder\28\29 +11708:GrGLSLVertexBuilder::onFinalize\28\29 +11709:GrGLSLUniformHandler::inputSamplerSwizzle\28GrResourceHandle\29\20const +11710:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +11711:GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +11712:GrGLSLFragmentShaderBuilder::forceHighPrecision\28\29 +11713:GrGLRenderTarget::getBackendRenderTarget\28\29\20const +11714:GrGLRenderTarget::completeStencilAttachment\28GrAttachment*\2c\20bool\29 +11715:GrGLRenderTarget::canAttemptStencilAttachment\28bool\29\20const +11716:GrGLRenderTarget::alwaysClearStencil\28\29\20const +11717:GrGLProgramDataManager::~GrGLProgramDataManager\28\29_11832 +11718:GrGLProgramDataManager::setMatrix4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11719:GrGLProgramDataManager::setMatrix4f\28GrResourceHandle\2c\20float\20const*\29\20const +11720:GrGLProgramDataManager::setMatrix3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11721:GrGLProgramDataManager::setMatrix3f\28GrResourceHandle\2c\20float\20const*\29\20const +11722:GrGLProgramDataManager::setMatrix2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11723:GrGLProgramDataManager::setMatrix2f\28GrResourceHandle\2c\20float\20const*\29\20const +11724:GrGLProgramDataManager::set4iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11725:GrGLProgramDataManager::set4i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\2c\20int\29\20const +11726:GrGLProgramDataManager::set4f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\2c\20float\29\20const +11727:GrGLProgramDataManager::set3iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11728:GrGLProgramDataManager::set3i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\29\20const +11729:GrGLProgramDataManager::set3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11730:GrGLProgramDataManager::set3f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\29\20const +11731:GrGLProgramDataManager::set2iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11732:GrGLProgramDataManager::set2i\28GrResourceHandle\2c\20int\2c\20int\29\20const +11733:GrGLProgramDataManager::set2f\28GrResourceHandle\2c\20float\2c\20float\29\20const +11734:GrGLProgramDataManager::set1iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11735:GrGLProgramDataManager::set1i\28GrResourceHandle\2c\20int\29\20const +11736:GrGLProgramDataManager::set1fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11737:GrGLProgramDataManager::set1f\28GrResourceHandle\2c\20float\29\20const +11738:GrGLProgramBuilder::~GrGLProgramBuilder\28\29_11964 +11739:GrGLProgramBuilder::varyingHandler\28\29 +11740:GrGLProgramBuilder::caps\28\29\20const +11741:GrGLProgram::~GrGLProgram\28\29_11815 +11742:GrGLOpsRenderPass::~GrGLOpsRenderPass\28\29 +11743:GrGLOpsRenderPass::onSetScissorRect\28SkIRect\20const&\29 +11744:GrGLOpsRenderPass::onEnd\28\29 +11745:GrGLOpsRenderPass::onDraw\28int\2c\20int\29 +11746:GrGLOpsRenderPass::onDrawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +11747:GrGLOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11748:GrGLOpsRenderPass::onDrawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +11749:GrGLOpsRenderPass::onDrawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +11750:GrGLOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11751:GrGLOpsRenderPass::onClear\28GrScissorState\20const&\2c\20std::__2::array\29 +11752:GrGLOpsRenderPass::onClearStencilClip\28GrScissorState\20const&\2c\20bool\29 +11753:GrGLOpsRenderPass::onBindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +11754:GrGLOpsRenderPass::onBindPipeline\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +11755:GrGLOpsRenderPass::onBindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +11756:GrGLOpsRenderPass::onBegin\28\29 +11757:GrGLOpsRenderPass::inlineUpload\28GrOpFlushState*\2c\20std::__2::function&\29>&\29 +11758:GrGLInterface::~GrGLInterface\28\29_11788 +11759:GrGLGpu::~GrGLGpu\28\29_11629 +11760:GrGLGpu::xferBarrier\28GrRenderTarget*\2c\20GrXferBarrierType\29 +11761:GrGLGpu::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +11762:GrGLGpu::willExecute\28\29 +11763:GrGLGpu::submit\28GrOpsRenderPass*\29 +11764:GrGLGpu::startTimerQuery\28\29 +11765:GrGLGpu::stagingBufferManager\28\29 +11766:GrGLGpu::refPipelineBuilder\28\29 +11767:GrGLGpu::prepareTextureForCrossContextUsage\28GrTexture*\29 +11768:GrGLGpu::precompileShader\28SkData\20const&\2c\20SkData\20const&\29 +11769:GrGLGpu::pipelineBuilder\28\29 +11770:GrGLGpu::onWritePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +11771:GrGLGpu::onWrapRenderableBackendTexture\28GrBackendTexture\20const&\2c\20int\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +11772:GrGLGpu::onWrapCompressedBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +11773:GrGLGpu::onWrapBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\2c\20GrIOType\29 +11774:GrGLGpu::onWrapBackendRenderTarget\28GrBackendRenderTarget\20const&\29 +11775:GrGLGpu::onUpdateCompressedBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20void\20const*\2c\20unsigned\20long\29 +11776:GrGLGpu::onTransferPixelsTo\28GrTexture*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +11777:GrGLGpu::onTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\29 +11778:GrGLGpu::onTransferFromBufferToBuffer\28sk_sp\2c\20unsigned\20long\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +11779:GrGLGpu::onSubmitToGpu\28GrSubmitInfo\20const&\29 +11780:GrGLGpu::onResolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +11781:GrGLGpu::onResetTextureBindings\28\29 +11782:GrGLGpu::onResetContext\28unsigned\20int\29 +11783:GrGLGpu::onRegenerateMipMapLevels\28GrTexture*\29 +11784:GrGLGpu::onReadPixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20unsigned\20long\29 +11785:GrGLGpu::onGetOpsRenderPass\28GrRenderTarget*\2c\20bool\2c\20GrAttachment*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const&\2c\20GrOpsRenderPass::LoadAndStoreInfo\20const&\2c\20GrOpsRenderPass::StencilLoadAndStoreInfo\20const&\2c\20skia_private::TArray\20const&\2c\20GrXferBarrierFlags\29 +11786:GrGLGpu::onDumpJSON\28SkJSONWriter*\29\20const +11787:GrGLGpu::onCreateTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +11788:GrGLGpu::onCreateCompressedTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20void\20const*\2c\20unsigned\20long\29 +11789:GrGLGpu::onCreateCompressedBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\29 +11790:GrGLGpu::onCreateBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +11791:GrGLGpu::onCreateBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +11792:GrGLGpu::onCopySurface\28GrSurface*\2c\20SkIRect\20const&\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +11793:GrGLGpu::onClearBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20std::__2::array\29 +11794:GrGLGpu::makeStencilAttachment\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\29 +11795:GrGLGpu::makeSemaphore\28bool\29 +11796:GrGLGpu::makeMSAAAttachment\28SkISize\2c\20GrBackendFormat\20const&\2c\20int\2c\20skgpu::Protected\2c\20GrMemoryless\29 +11797:GrGLGpu::getPreferredStencilFormat\28GrBackendFormat\20const&\29 +11798:GrGLGpu::finishOutstandingGpuWork\28\29 +11799:GrGLGpu::endTimerQuery\28GrTimerQuery\20const&\29 +11800:GrGLGpu::disconnect\28GrGpu::DisconnectType\29 +11801:GrGLGpu::deleteBackendTexture\28GrBackendTexture\20const&\29 +11802:GrGLGpu::compile\28GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\29 +11803:GrGLGpu::checkFinishedCallbacks\28\29 +11804:GrGLGpu::addFinishedCallback\28skgpu::AutoCallback\2c\20std::__2::optional\29 +11805:GrGLGpu::ProgramCache::~ProgramCache\28\29_11777 +11806:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20unsigned\20int\2c\20float\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29 +11807:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11808:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\2c\20float\29 +11809:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29 +11810:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\29 +11811:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29 +11812:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\29\29::'lambda'\28void\20const*\2c\20float\29::__invoke\28void\20const*\2c\20float\29 +11813:GrGLFunction::GrGLFunction\28void\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +11814:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28__GLsync*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29 +11815:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +11816:GrGLContext::~GrGLContext\28\29 +11817:GrGLCaps::~GrGLCaps\28\29_11564 +11818:GrGLCaps::surfaceSupportsReadPixels\28GrSurface\20const*\29\20const +11819:GrGLCaps::supportedWritePixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +11820:GrGLCaps::onSurfaceSupportsWritePixels\28GrSurface\20const*\29\20const +11821:GrGLCaps::onSupportsDynamicMSAA\28GrRenderTargetProxy\20const*\29\20const +11822:GrGLCaps::onSupportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +11823:GrGLCaps::onIsWindowRectanglesSupportedForRT\28GrBackendRenderTarget\20const&\29\20const +11824:GrGLCaps::onGetReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +11825:GrGLCaps::onGetDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\29\20const +11826:GrGLCaps::onGetDefaultBackendFormat\28GrColorType\29\20const +11827:GrGLCaps::onDumpJSON\28SkJSONWriter*\29\20const +11828:GrGLCaps::onCanCopySurface\28GrSurfaceProxy\20const*\2c\20SkIRect\20const&\2c\20GrSurfaceProxy\20const*\2c\20SkIRect\20const&\29\20const +11829:GrGLCaps::onAreColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +11830:GrGLCaps::onApplyOptionsOverrides\28GrContextOptions\20const&\29 +11831:GrGLCaps::maxRenderTargetSampleCount\28GrBackendFormat\20const&\29\20const +11832:GrGLCaps::makeDesc\28GrRenderTarget*\2c\20GrProgramInfo\20const&\2c\20GrCaps::ProgramDescOverrideFlags\29\20const +11833:GrGLCaps::isFormatTexturable\28GrBackendFormat\20const&\2c\20GrTextureType\29\20const +11834:GrGLCaps::isFormatSRGB\28GrBackendFormat\20const&\29\20const +11835:GrGLCaps::isFormatRenderable\28GrBackendFormat\20const&\2c\20int\29\20const +11836:GrGLCaps::isFormatCopyable\28GrBackendFormat\20const&\29\20const +11837:GrGLCaps::isFormatAsColorTypeRenderable\28GrColorType\2c\20GrBackendFormat\20const&\2c\20int\29\20const +11838:GrGLCaps::getWriteSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +11839:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrBackendFormat\20const&\29\20const +11840:GrGLCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +11841:GrGLCaps::getBackendFormatFromCompressionType\28SkTextureCompressionType\29\20const +11842:GrGLCaps::computeFormatKey\28GrBackendFormat\20const&\29\20const +11843:GrGLBuffer::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +11844:GrGLBuffer::onUpdateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +11845:GrGLBuffer::onUnmap\28GrGpuBuffer::MapType\29 +11846:GrGLBuffer::onSetLabel\28\29 +11847:GrGLBuffer::onRelease\28\29 +11848:GrGLBuffer::onMap\28GrGpuBuffer::MapType\29 +11849:GrGLBuffer::onClearToZero\28\29 +11850:GrGLBuffer::onAbandon\28\29 +11851:GrGLBackendTextureData::~GrGLBackendTextureData\28\29_11523 +11852:GrGLBackendTextureData::~GrGLBackendTextureData\28\29 +11853:GrGLBackendTextureData::isSameTexture\28GrBackendTextureData\20const*\29\20const +11854:GrGLBackendTextureData::getBackendFormat\28\29\20const +11855:GrGLBackendTextureData::equal\28GrBackendTextureData\20const*\29\20const +11856:GrGLBackendTextureData::copyTo\28SkAnySubclass&\29\20const +11857:GrGLBackendRenderTargetData::isProtected\28\29\20const +11858:GrGLBackendRenderTargetData::getBackendFormat\28\29\20const +11859:GrGLBackendRenderTargetData::equal\28GrBackendRenderTargetData\20const*\29\20const +11860:GrGLBackendRenderTargetData::copyTo\28SkAnySubclass&\29\20const +11861:GrGLBackendFormatData::toString\28\29\20const +11862:GrGLBackendFormatData::stencilBits\28\29\20const +11863:GrGLBackendFormatData::equal\28GrBackendFormatData\20const*\29\20const +11864:GrGLBackendFormatData::desc\28\29\20const +11865:GrGLBackendFormatData::copyTo\28SkAnySubclass&\29\20const +11866:GrGLBackendFormatData::compressionType\28\29\20const +11867:GrGLBackendFormatData::channelMask\28\29\20const +11868:GrGLBackendFormatData::bytesPerBlock\28\29\20const +11869:GrGLAttachment::~GrGLAttachment\28\29 +11870:GrGLAttachment::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +11871:GrGLAttachment::onSetLabel\28\29 +11872:GrGLAttachment::onRelease\28\29 +11873:GrGLAttachment::onAbandon\28\29 +11874:GrGLAttachment::backendFormat\28\29\20const +11875:GrFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11876:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11877:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const +11878:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11879:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11880:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::name\28\29\20const +11881:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11882:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::clone\28\29\20const +11883:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11884:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const +11885:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::name\28\29\20const +11886:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::clone\28\29\20const +11887:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11888:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const +11889:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::name\28\29\20const +11890:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::clone\28\29\20const +11891:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11892:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const +11893:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::name\28\29\20const +11894:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11895:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::clone\28\29\20const +11896:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11897:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const +11898:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::name\28\29\20const +11899:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11900:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::clone\28\29\20const +11901:GrFixedClip::~GrFixedClip\28\29_8889 +11902:GrFixedClip::~GrFixedClip\28\29 +11903:GrFixedClip::getConservativeBounds\28\29\20const +11904:GrExternalTextureGenerator::onGenerateTexture\28GrRecordingContext*\2c\20SkImageInfo\20const&\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +11905:GrDynamicAtlas::~GrDynamicAtlas\28\29_8863 +11906:GrDrawOp::usesStencil\28\29\20const +11907:GrDrawOp::usesMSAA\28\29\20const +11908:GrDrawOp::fixedFunctionFlags\28\29\20const +11909:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29_9812 +11910:GrDistanceFieldPathGeoProc::onTextureSampler\28int\29\20const +11911:GrDistanceFieldPathGeoProc::name\28\29\20const +11912:GrDistanceFieldPathGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11913:GrDistanceFieldPathGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11914:GrDistanceFieldPathGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11915:GrDistanceFieldPathGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11916:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29_9821 +11917:GrDistanceFieldLCDTextGeoProc::name\28\29\20const +11918:GrDistanceFieldLCDTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11919:GrDistanceFieldLCDTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11920:GrDistanceFieldLCDTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11921:GrDistanceFieldLCDTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11922:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29_9801 +11923:GrDistanceFieldA8TextGeoProc::name\28\29\20const +11924:GrDistanceFieldA8TextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11925:GrDistanceFieldA8TextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11926:GrDistanceFieldA8TextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11927:GrDistanceFieldA8TextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11928:GrDisableColorXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11929:GrDisableColorXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11930:GrDirectContext::~GrDirectContext\28\29_8671 +11931:GrDirectContext::init\28\29 +11932:GrDirectContext::abandonContext\28\29 +11933:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29_8056 +11934:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29_8882 +11935:GrCpuVertexAllocator::unlock\28int\29 +11936:GrCpuVertexAllocator::lock\28unsigned\20long\2c\20int\29 +11937:GrCpuBuffer::unref\28\29\20const +11938:GrCpuBuffer::ref\28\29\20const +11939:GrCoverageSetOpXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11940:GrCoverageSetOpXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11941:GrCopyRenderTask::~GrCopyRenderTask\28\29_8600 +11942:GrCopyRenderTask::onMakeSkippable\28\29 +11943:GrCopyRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +11944:GrCopyRenderTask::onExecute\28GrOpFlushState*\29 +11945:GrCopyRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11946:GrConvexPolyEffect::~GrConvexPolyEffect\28\29 +11947:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11948:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11949:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const +11950:GrConvexPolyEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11951:GrConvexPolyEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11952:GrConvexPolyEffect::name\28\29\20const +11953:GrConvexPolyEffect::clone\28\29\20const +11954:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29_8576 +11955:GrContextThreadSafeProxy::isValidCharacterizationForVulkan\28sk_sp\2c\20bool\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20bool\2c\20bool\29 +11956:GrConicEffect::name\28\29\20const +11957:GrConicEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11958:GrConicEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11959:GrConicEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11960:GrConicEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11961:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29_8540 +11962:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11963:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11964:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const +11965:GrColorSpaceXformEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11966:GrColorSpaceXformEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11967:GrColorSpaceXformEffect::name\28\29\20const +11968:GrColorSpaceXformEffect::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11969:GrColorSpaceXformEffect::clone\28\29\20const +11970:GrCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +11971:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29_9724 +11972:GrBitmapTextGeoProc::onTextureSampler\28int\29\20const +11973:GrBitmapTextGeoProc::name\28\29\20const +11974:GrBitmapTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11975:GrBitmapTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11976:GrBitmapTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11977:GrBitmapTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11978:GrBicubicEffect::onMakeProgramImpl\28\29\20const +11979:GrBicubicEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11980:GrBicubicEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11981:GrBicubicEffect::name\28\29\20const +11982:GrBicubicEffect::clone\28\29\20const +11983:GrBicubicEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11984:GrBicubicEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11985:GrAttachment::onGpuMemorySize\28\29\20const +11986:GrAttachment::getResourceType\28\29\20const +11987:GrAttachment::computeScratchKey\28skgpu::ScratchKey*\29\20const +11988:GrAtlasManager::~GrAtlasManager\28\29_11414 +11989:GrAtlasManager::postFlush\28skgpu::AtlasToken\29 +11990:GrAATriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +11991:FontMgrRunIterator::~FontMgrRunIterator\28\29_12296 +11992:FontMgrRunIterator::consume\28\29 +11993:EllipticalRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11994:EllipticalRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11995:EllipticalRRectOp::name\28\29\20const +11996:EllipticalRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11997:EllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11998:EllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11999:EllipseOp::name\28\29\20const +12000:EllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12001:EllipseGeometryProcessor::name\28\29\20const +12002:EllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12003:EllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12004:EllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12005:Dual_Project +12006:DisableColorXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +12007:DisableColorXP::name\28\29\20const +12008:DisableColorXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +12009:DisableColorXP::makeProgramImpl\28\29\20const +12010:Direct_Move_Y +12011:Direct_Move_X +12012:Direct_Move_Orig_Y +12013:Direct_Move_Orig_X +12014:Direct_Move_Orig +12015:Direct_Move +12016:DefaultGeoProc::name\28\29\20const +12017:DefaultGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12018:DefaultGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12019:DefaultGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +12020:DefaultGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12021:DIEllipseOp::~DIEllipseOp\28\29_10874 +12022:DIEllipseOp::visitProxies\28std::__2::function\20const&\29\20const +12023:DIEllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12024:DIEllipseOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12025:DIEllipseOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12026:DIEllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12027:DIEllipseOp::name\28\29\20const +12028:DIEllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12029:DIEllipseGeometryProcessor::name\28\29\20const +12030:DIEllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12031:DIEllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12032:DIEllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12033:CustomXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +12034:CustomXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +12035:CustomXP::xferBarrierType\28GrCaps\20const&\29\20const +12036:CustomXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +12037:CustomXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12038:CustomXP::name\28\29\20const +12039:CustomXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +12040:CustomXP::makeProgramImpl\28\29\20const +12041:Current_Ppem_Stretched +12042:Current_Ppem +12043:Cr_z_zcalloc +12044:CoverageSetOpXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +12045:CoverageSetOpXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12046:CoverageSetOpXP::name\28\29\20const +12047:CoverageSetOpXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +12048:CoverageSetOpXP::makeProgramImpl\28\29\20const +12049:ColorTableEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +12050:ColorTableEffect::onMakeProgramImpl\28\29\20const +12051:ColorTableEffect::name\28\29\20const +12052:ColorTableEffect::clone\28\29\20const +12053:CircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +12054:CircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12055:CircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12056:CircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12057:CircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12058:CircularRRectOp::name\28\29\20const +12059:CircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12060:CircleOp::~CircleOp\28\29_10910 +12061:CircleOp::visitProxies\28std::__2::function\20const&\29\20const +12062:CircleOp::programInfo\28\29 +12063:CircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12064:CircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12065:CircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12066:CircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12067:CircleOp::name\28\29\20const +12068:CircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12069:CircleGeometryProcessor::name\28\29\20const +12070:CircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12071:CircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12072:CircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12073:ButtCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +12074:ButtCapDashedCircleOp::visitProxies\28std::__2::function\20const&\29\20const +12075:ButtCapDashedCircleOp::programInfo\28\29 +12076:ButtCapDashedCircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +12077:ButtCapDashedCircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +12078:ButtCapDashedCircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +12079:ButtCapDashedCircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +12080:ButtCapDashedCircleOp::name\28\29\20const +12081:ButtCapDashedCircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +12082:ButtCapDashedCircleGeometryProcessor::name\28\29\20const +12083:ButtCapDashedCircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +12084:ButtCapDashedCircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12085:ButtCapDashedCircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +12086:BluntJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +12087:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +12088:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +12089:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const +12090:BlendFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +12091:BlendFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +12092:BlendFragmentProcessor::name\28\29\20const +12093:BlendFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +12094:BlendFragmentProcessor::clone\28\29\20const +12095:$_3::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +12096:$_2::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 +12097:$_1::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +12098:$_0::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm.wasm b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm.wasm new file mode 100644 index 0000000000..d93952e90f Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm.wasm differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm_st.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm_st.js new file mode 100644 index 0000000000..7d353c2518 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm_st.js @@ -0,0 +1,134 @@ + +var skwasm_st = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + + return ( +function(moduleArg = {}) { + var moduleRtn; + +function d(){g.buffer!=k.buffer&&n();return k}function q(){g.buffer!=k.buffer&&n();return aa}function r(){g.buffer!=k.buffer&&n();return ba}function t(){g.buffer!=k.buffer&&n();return ca}function u(){g.buffer!=k.buffer&&n();return da}var w=moduleArg,ea,fa,ha=new Promise((a,b)=>{ea=a;fa=b}),ia="object"==typeof window,ja="function"==typeof importScripts,ka=Object.assign({},w),x="",la,ma; +if(ia||ja)ja?x=self.location.href:"undefined"!=typeof document&&document.currentScript&&(x=document.currentScript.src),_scriptName&&(x=_scriptName),x.startsWith("blob:")?x="":x=x.substr(0,x.replace(/[?#].*/,"").lastIndexOf("/")+1),ja&&(ma=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),la=a=>fetch(a,{credentials:"same-origin"}).then(b=>b.ok?b.arrayBuffer():Promise.reject(Error(b.status+" : "+b.url))); +var na=console.log.bind(console),y=console.error.bind(console);Object.assign(w,ka);ka=null;var g,oa=!1,pa,k,aa,qa,ra,ba,ca,da;function n(){var a=g.buffer;k=new Int8Array(a);qa=new Int16Array(a);aa=new Uint8Array(a);ra=new Uint16Array(a);ba=new Int32Array(a);ca=new Uint32Array(a);da=new Float32Array(a);new Float64Array(a)}var sa=[],ta=[],ua=[],z=0,va=null,A=null; +function wa(a){a="Aborted("+a+")";y(a);oa=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");fa(a);throw a;}var xa=a=>a.startsWith("data:application/octet-stream;base64,"),ya;function za(a){return la(a).then(b=>new Uint8Array(b),()=>{if(ma)var b=ma(a);else throw"both async and sync fetching of the wasm failed";return b})}function Aa(a,b,c){return za(a).then(e=>WebAssembly.instantiate(e,b)).then(c,e=>{y(`failed to asynchronously prepare wasm: ${e}`);wa(e)})} +function Ba(a,b){var c=ya;return"function"!=typeof WebAssembly.instantiateStreaming||xa(c)||"function"!=typeof fetch?Aa(c,a,b):fetch(c,{credentials:"same-origin"}).then(e=>WebAssembly.instantiateStreaming(e,a).then(b,function(f){y(`wasm streaming compile failed: ${f}`);y("falling back to ArrayBuffer instantiation");return Aa(c,a,b)}))}function Ca(a){this.name="ExitStatus";this.message=`Program terminated with exit(${a})`;this.status=a}var Da=a=>{a.forEach(b=>b(w))},Ea=w.noExitRuntime||!0; +class Fa{constructor(a){this.s=a-24}} +var Ga=0,Ha=0,Ia="undefined"!=typeof TextDecoder?new TextDecoder:void 0,Ja=(a,b=0,c=NaN)=>{var e=b+c;for(c=b;a[c]&&!(c>=e);)++c;if(16f?e+=String.fromCharCode(f):(f-=65536,e+=String.fromCharCode(55296|f>>10,56320|f&1023))}}else e+=String.fromCharCode(f)}return e}, +Ka=(a,b)=>a?Ja(q(),a,b):"",B={},La=a=>{if(!(a instanceof Ca||"unwind"==a))throw a;},Ma=0,Na=a=>{pa=a;Ea||0{if(!oa)try{if(a(),!(Ea||0{var e=q();if(0=l){var m=a.charCodeAt(++h);l=65536+((l&1023)<<10)|m&1023}if(127>=l){if(b>=c)break;e[b++]=l}else{if(2047>=l){if(b+1>=c)break;e[b++]=192|l>>6}else{if(65535>=l){if(b+ +2>=c)break;e[b++]=224|l>>12}else{if(b+3>=c)break;e[b++]=240|l>>18;e[b++]=128|l>>12&63}e[b++]=128|l>>6&63}e[b++]=128|l&63}}e[b]=0;a=b-f}else a=0;return a},D,Pa=a=>{var b=a.getExtension("ANGLE_instanced_arrays");b&&(a.vertexAttribDivisor=(c,e)=>b.vertexAttribDivisorANGLE(c,e),a.drawArraysInstanced=(c,e,f,h)=>b.drawArraysInstancedANGLE(c,e,f,h),a.drawElementsInstanced=(c,e,f,h,l)=>b.drawElementsInstancedANGLE(c,e,f,h,l))},Qa=a=>{var b=a.getExtension("OES_vertex_array_object");b&&(a.createVertexArray= +()=>b.createVertexArrayOES(),a.deleteVertexArray=c=>b.deleteVertexArrayOES(c),a.bindVertexArray=c=>b.bindVertexArrayOES(c),a.isVertexArray=c=>b.isVertexArrayOES(c))},Ra=a=>{var b=a.getExtension("WEBGL_draw_buffers");b&&(a.drawBuffers=(c,e)=>b.drawBuffersWEBGL(c,e))},Sa=a=>{a.H=a.getExtension("WEBGL_draw_instanced_base_vertex_base_instance")},Ta=a=>{a.K=a.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance")},Ua=a=>{var b="ANGLE_instanced_arrays EXT_blend_minmax EXT_disjoint_timer_query EXT_frag_depth EXT_shader_texture_load EXT_sRGB OES_element_index_uint OES_fbo_render_mipmap OES_standard_derivatives OES_texture_float OES_texture_half_float OES_texture_half_float_linear OES_vertex_array_object WEBGL_color_buffer_float WEBGL_depth_texture WEBGL_draw_buffers EXT_color_buffer_float EXT_conservative_depth EXT_disjoint_timer_query_webgl2 EXT_texture_norm16 NV_shader_noperspective_interpolation WEBGL_clip_cull_distance EXT_clip_control EXT_color_buffer_half_float EXT_depth_clamp EXT_float_blend EXT_polygon_offset_clamp EXT_texture_compression_bptc EXT_texture_compression_rgtc EXT_texture_filter_anisotropic KHR_parallel_shader_compile OES_texture_float_linear WEBGL_blend_func_extended WEBGL_compressed_texture_astc WEBGL_compressed_texture_etc WEBGL_compressed_texture_etc1 WEBGL_compressed_texture_s3tc WEBGL_compressed_texture_s3tc_srgb WEBGL_debug_renderer_info WEBGL_debug_shaders WEBGL_lose_context WEBGL_multi_draw WEBGL_polygon_mode".split(" "); +return(a.getSupportedExtensions()||[]).filter(c=>b.includes(c))},Va=1,Wa=[],E=[],Xa=[],F=[],G=[],H=[],Ya=[],Za=[],I=[],J=[],K=[],$a={},ab={},bb=4,cb=0,L=a=>{for(var b=Va++,c=a.length;c{for(var f=0;f>2]=l}},eb=a=>{var b={J:2,alpha:!0,depth:!0,stencil:!0,antialias:!1,premultipliedAlpha:!0,preserveDrawingBuffer:!1,powerPreference:"default",failIfMajorPerformanceCaveat:!1,I:!0};a.s||(a.s=a.getContext, +a.getContext=function(e,f){f=a.s(e,f);return"webgl"==e==f instanceof WebGLRenderingContext?f:null});var c=1{var c=L(Za),e={handle:c,attributes:b,version:b.J,v:a};a.canvas&&(a.canvas.Z=e);Za[c]=e;("undefined"==typeof b.I||b.I)&&fb(e);return c},fb=a=>{a||=O;if(!a.S){a.S=!0;var b=a.v;b.T=b.getExtension("WEBGL_multi_draw");b.P=b.getExtension("EXT_polygon_offset_clamp");b.O=b.getExtension("EXT_clip_control");b.Y=b.getExtension("WEBGL_polygon_mode"); +Pa(b);Qa(b);Ra(b);Sa(b);Ta(b);2<=a.version&&(b.g=b.getExtension("EXT_disjoint_timer_query_webgl2"));if(2>a.version||!b.g)b.g=b.getExtension("EXT_disjoint_timer_query");Ua(b).forEach(c=>{c.includes("lose_context")||c.includes("debug")||b.getExtension(c)})}},M,O,gb=a=>{D.bindVertexArray(Ya[a])},hb=(a,b)=>{for(var c=0;c>2],f=G[e];f&&(D.deleteTexture(f),f.name=0,G[e]=null)}},ib=(a,b)=>{for(var c=0;c>2];D.deleteVertexArray(Ya[e]);Ya[e]=null}},jb=[],kb=(a, +b)=>{N(a,b,"createVertexArray",Ya)},lb=(a,b)=>{t()[a>>2]=b;var c=t()[a>>2];t()[a+4>>2]=(b-c)/4294967296};function mb(){var a=Ua(D);return a=a.concat(a.map(b=>"GL_"+b))} +var nb=(a,b,c)=>{if(b){var e=void 0;switch(a){case 36346:e=1;break;case 36344:0!=c&&1!=c&&(M||=1280);return;case 34814:case 36345:e=0;break;case 34466:var f=D.getParameter(34467);e=f?f.length:0;break;case 33309:if(2>O.version){M||=1282;return}e=mb().length;break;case 33307:case 33308:if(2>O.version){M||=1280;return}e=33307==a?3:0}if(void 0===e)switch(f=D.getParameter(a),typeof f){case "number":e=f;break;case "boolean":e=f?1:0;break;case "string":M||=1280;return;case "object":if(null===f)switch(a){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:e= +0;break;default:M||=1280;return}else{if(f instanceof Float32Array||f instanceof Uint32Array||f instanceof Int32Array||f instanceof Array){for(a=0;a>2]=f[a];break;case 2:u()[b+4*a>>2]=f[a];break;case 4:d()[b+a]=f[a]?1:0}return}try{e=f.name|0}catch(h){M||=1280;y(`GL_INVALID_ENUM in glGet${c}v: Unknown object returned from WebGL getParameter(${a})! (error: ${h})`);return}}break;default:M||=1280;y(`GL_INVALID_ENUM in glGet${c}v: Native code calling glGet${c}v(${a}) and it returns ${f} of type ${typeof f}!`); +return}switch(c){case 1:lb(b,e);break;case 0:r()[b>>2]=e;break;case 2:u()[b>>2]=e;break;case 4:d()[b]=e?1:0}}else M||=1281},ob=(a,b)=>nb(a,b,0),pb=(a,b,c)=>{if(c){a=I[a];b=2>O.version?D.g.getQueryObjectEXT(a,b):D.getQueryParameter(a,b);var e;"boolean"==typeof b?e=b?1:0:e=b;lb(c,e)}else M||=1281},rb=a=>{for(var b=0,c=0;c=e?b++:2047>=e?b+=2:55296<=e&&57343>=e?(b+=4,++c):b+=3}b+=1;(c=qb(b))&&C(a,c,b);return c},sb=a=>{var b=$a[a];if(!b){switch(a){case 7939:b=rb(mb().join(" ")); +break;case 7936:case 7937:case 37445:case 37446:(b=D.getParameter(a))||(M||=1280);b=b?rb(b):0;break;case 7938:b=D.getParameter(7938);var c=`OpenGL ES 2.0 (${b})`;2<=O.version&&(c=`OpenGL ES 3.0 (${b})`);b=rb(c);break;case 35724:b=D.getParameter(35724);c=b.match(/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/);null!==c&&(3==c[1].length&&(c[1]+="0"),b=`OpenGL ES GLSL ES ${c[1]} (${b})`);b=rb(b);break;default:M||=1280}$a[a]=b}return b},tb=(a,b)=>{if(2>O.version)return M||=1282,0;var c=ab[a];if(c)return 0> +b||b>=c.length?(M||=1281,0):c[b];switch(a){case 7939:return c=mb().map(rb),c=ab[a]=c,0>b||b>=c.length?(M||=1281,0):c[b];default:return M||=1280,0}},ub=a=>"]"==a.slice(-1)&&a.lastIndexOf("["),vb=a=>{a-=5120;0==a?a=d():1==a?a=q():2==a?(g.buffer!=k.buffer&&n(),a=qa):4==a?a=r():6==a?a=u():5==a||28922==a||28520==a||30779==a||30782==a?a=t():(g.buffer!=k.buffer&&n(),a=ra);return a},wb=(a,b,c,e,f)=>{a=vb(a);b=e*((cb||c)*({5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4}[b-6402]||1)*a.BYTES_PER_ELEMENT+ +bb-1&-bb);return a.subarray(f>>>31-Math.clz32(a.BYTES_PER_ELEMENT),f+b>>>31-Math.clz32(a.BYTES_PER_ELEMENT))},P=a=>{var b=D.N;if(b){var c=b.u[a];"number"==typeof c&&(b.u[a]=c=D.getUniformLocation(b,b.L[a]+(0{if(!zb){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:"./this.program"},b;for(b in yb)void 0=== +yb[b]?delete a[b]:a[b]=yb[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);zb=c}return zb},zb,Bb=[null,[],[]];function Cb(){}function Db(){}function R(){}function Eb(){}function Fb(){}function Gb(){}function Hb(){}function Ib(){}function Jb(){}function Kb(){}function Lb(){}function Mb(){}function Nb(){}function Ob(){}function Pb(){}function Qb(){}var S,U,Rb=[],Tb=a=>Sb(a);w.stackAlloc=Tb;for(var V=0;32>V;++V)jb.push(Array(V));var Ub=new Float32Array(288);for(V=0;288>=V;++V)Q[V]=Ub.subarray(0,V); +var Vb=new Int32Array(288);for(V=0;288>=V;++V)xb[V]=Vb.subarray(0,V); +(function(){const a=new Map,b=new Map;Qb=function(c,e,f){R({m:"setAssociatedObject",F:e,object:f})};Mb=function(c){return b.get(c)};Fb=function(){Cb(function(c){var e=c.m;if(e)switch(e){case "renderPictures":Wb(c.h,c.V,c.U,c.l,Db());break;case "onRenderComplete":Xb(c.h,c.l,{imageBitmaps:c.R,rasterStartMilliseconds:c.X,rasterEndMilliseconds:c.W});break;case "setAssociatedObject":b.set(c.F,c.object);break;case "disposeAssociatedObject":c=c.F;e=b.get(c);e.close&&e.close();b.delete(c);break;case "disposeSurface":Yb(c.h); +break;case "rasterizeImage":Zb(c.h,c.image,c.format,c.l);break;case "onRasterizeComplete":$b(c.h,c.data,c.l);break;default:console.warn(`unrecognized skwasm message: ${e}`)}})};Kb=function(c,e,f,h,l){R({m:"renderPictures",h:e,V:f,U:h,l})};Hb=function(c,e){c=new OffscreenCanvas(c,e);e=eb(c);a.set(e,c);return e};Ob=function(c,e,f){c=a.get(c);c.width=e;c.height=f};Eb=function(c,e,f,h){h||=[];c=a.get(c);h.push(createImageBitmap(c,0,0,e,f));return h};Pb=async function(c,e,f,h){e=e?await Promise.all(e): +[];R({m:"onRenderComplete",h:c,l:h,R:e,X:f,W:Db()},[...e])};Gb=function(c,e,f){const h=O.v,l=h.createTexture();h.bindTexture(h.TEXTURE_2D,l);h.pixelStorei(h.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0);h.texImage2D(h.TEXTURE_2D,0,h.RGBA,e,f,0,h.RGBA,h.UNSIGNED_BYTE,c);h.pixelStorei(h.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1);h.bindTexture(h.TEXTURE_2D,null);c=L(G);G[c]=l;return c};Lb=function(c,e){R({m:"disposeAssociatedObject",F:e})};Ib=function(c,e){R({m:"disposeSurface",h:e})};Jb=function(c,e,f,h,l){R({m:"rasterizeImage", +h:e,image:f,format:h,l})};Nb=function(c,e,f){R({m:"onRasterizeComplete",h:c,data:e,l:f})}})();(function(){let a;Cb=function(b){a=b};Db=function(){return performance.now()};R=function(b){queueMicrotask(()=>{a(b)})}})(); +var lc={__cxa_throw:(a,b,c)=>{var e=new Fa(a);t()[e.s+16>>2]=0;t()[e.s+4>>2]=b;t()[e.s+8>>2]=c;Ga=a;Ha++;throw Ga;},__syscall_fcntl64:function(){return 0},__syscall_fstat64:()=>{},__syscall_ioctl:function(){return 0},__syscall_openat:function(){},_abort_js:()=>{wa("")},_emscripten_get_now_is_monotonic:()=>1,_emscripten_runtime_keepalive_clear:()=>{Ea=!1;Ma=0},_emscripten_throw_longjmp:()=>{throw Infinity;},_mmap_js:function(){return-52},_munmap_js:function(){},_setitimer_js:(a,b)=>{B[a]&&(clearTimeout(B[a].id), +delete B[a]);if(!b)return 0;var c=setTimeout(()=>{delete B[a];Oa(()=>ac(a,performance.now()))},b);B[a]={id:c,aa:b};return 0},_tzset_js:(a,b,c,e)=>{var f=(new Date).getFullYear(),h=(new Date(f,0,1)).getTimezoneOffset();f=(new Date(f,6,1)).getTimezoneOffset();var l=Math.max(h,f);t()[a>>2]=60*l;r()[b>>2]=Number(h!=f);b=m=>{var p=Math.abs(m);return`UTC${0<=m?"-":"+"}${String(Math.floor(p/60)).padStart(2,"0")}${String(p%60).padStart(2,"0")}`};a=b(h);b=b(f);fperformance.now(),emscripten_glActiveTexture:a=>D.activeTexture(a),emscripten_glAttachShader:(a,b)=>{D.attachShader(E[a],H[b])},emscripten_glBeginQuery:(a,b)=>{D.beginQuery(a,I[b])},emscripten_glBeginQueryEXT:(a,b)=>{D.g.beginQueryEXT(a,I[b])},emscripten_glBindAttribLocation:(a,b,c)=>{D.bindAttribLocation(E[a],b,Ka(c))},emscripten_glBindBuffer:(a,b)=>{35051==a?D.D=b:35052==a&&(D.o=b);D.bindBuffer(a,Wa[b])},emscripten_glBindFramebuffer:(a,b)=>{D.bindFramebuffer(a,Xa[b])},emscripten_glBindRenderbuffer:(a, +b)=>{D.bindRenderbuffer(a,F[b])},emscripten_glBindSampler:(a,b)=>{D.bindSampler(a,J[b])},emscripten_glBindTexture:(a,b)=>{D.bindTexture(a,G[b])},emscripten_glBindVertexArray:gb,emscripten_glBindVertexArrayOES:gb,emscripten_glBlendColor:(a,b,c,e)=>D.blendColor(a,b,c,e),emscripten_glBlendEquation:a=>D.blendEquation(a),emscripten_glBlendFunc:(a,b)=>D.blendFunc(a,b),emscripten_glBlitFramebuffer:(a,b,c,e,f,h,l,m,p,v)=>D.blitFramebuffer(a,b,c,e,f,h,l,m,p,v),emscripten_glBufferData:(a,b,c,e)=>{2<=O.version? +c&&b?D.bufferData(a,q(),e,c,b):D.bufferData(a,b,e):D.bufferData(a,c?q().subarray(c,c+b):b,e)},emscripten_glBufferSubData:(a,b,c,e)=>{2<=O.version?c&&D.bufferSubData(a,b,q(),e,c):D.bufferSubData(a,b,q().subarray(e,e+c))},emscripten_glCheckFramebufferStatus:a=>D.checkFramebufferStatus(a),emscripten_glClear:a=>D.clear(a),emscripten_glClearColor:(a,b,c,e)=>D.clearColor(a,b,c,e),emscripten_glClearStencil:a=>D.clearStencil(a),emscripten_glClientWaitSync:(a,b,c,e)=>D.clientWaitSync(K[a],b,(c>>>0)+4294967296* +e),emscripten_glColorMask:(a,b,c,e)=>{D.colorMask(!!a,!!b,!!c,!!e)},emscripten_glCompileShader:a=>{D.compileShader(H[a])},emscripten_glCompressedTexImage2D:(a,b,c,e,f,h,l,m)=>{2<=O.version?D.o||!l?D.compressedTexImage2D(a,b,c,e,f,h,l,m):D.compressedTexImage2D(a,b,c,e,f,h,q(),m,l):D.compressedTexImage2D(a,b,c,e,f,h,q().subarray(m,m+l))},emscripten_glCompressedTexSubImage2D:(a,b,c,e,f,h,l,m,p)=>{2<=O.version?D.o||!m?D.compressedTexSubImage2D(a,b,c,e,f,h,l,m,p):D.compressedTexSubImage2D(a,b,c,e,f,h, +l,q(),p,m):D.compressedTexSubImage2D(a,b,c,e,f,h,l,q().subarray(p,p+m))},emscripten_glCopyBufferSubData:(a,b,c,e,f)=>D.copyBufferSubData(a,b,c,e,f),emscripten_glCopyTexSubImage2D:(a,b,c,e,f,h,l,m)=>D.copyTexSubImage2D(a,b,c,e,f,h,l,m),emscripten_glCreateProgram:()=>{var a=L(E),b=D.createProgram();b.name=a;b.C=b.A=b.B=0;b.G=1;E[a]=b;return a},emscripten_glCreateShader:a=>{var b=L(H);H[b]=D.createShader(a);return b},emscripten_glCullFace:a=>D.cullFace(a),emscripten_glDeleteBuffers:(a,b)=>{for(var c= +0;c>2],f=Wa[e];f&&(D.deleteBuffer(f),f.name=0,Wa[e]=null,e==D.D&&(D.D=0),e==D.o&&(D.o=0))}},emscripten_glDeleteFramebuffers:(a,b)=>{for(var c=0;c>2],f=Xa[e];f&&(D.deleteFramebuffer(f),f.name=0,Xa[e]=null)}},emscripten_glDeleteProgram:a=>{if(a){var b=E[a];b?(D.deleteProgram(b),b.name=0,E[a]=null):M||=1281}},emscripten_glDeleteQueries:(a,b)=>{for(var c=0;c>2],f=I[e];f&&(D.deleteQuery(f),I[e]=null)}},emscripten_glDeleteQueriesEXT:(a, +b)=>{for(var c=0;c>2],f=I[e];f&&(D.g.deleteQueryEXT(f),I[e]=null)}},emscripten_glDeleteRenderbuffers:(a,b)=>{for(var c=0;c>2],f=F[e];f&&(D.deleteRenderbuffer(f),f.name=0,F[e]=null)}},emscripten_glDeleteSamplers:(a,b)=>{for(var c=0;c>2],f=J[e];f&&(D.deleteSampler(f),f.name=0,J[e]=null)}},emscripten_glDeleteShader:a=>{if(a){var b=H[a];b?(D.deleteShader(b),H[a]=null):M||=1281}},emscripten_glDeleteSync:a=>{if(a){var b=K[a];b?(D.deleteSync(b), +b.name=0,K[a]=null):M||=1281}},emscripten_glDeleteTextures:hb,emscripten_glDeleteVertexArrays:ib,emscripten_glDeleteVertexArraysOES:ib,emscripten_glDepthMask:a=>{D.depthMask(!!a)},emscripten_glDisable:a=>D.disable(a),emscripten_glDisableVertexAttribArray:a=>{D.disableVertexAttribArray(a)},emscripten_glDrawArrays:(a,b,c)=>{D.drawArrays(a,b,c)},emscripten_glDrawArraysInstanced:(a,b,c,e)=>{D.drawArraysInstanced(a,b,c,e)},emscripten_glDrawArraysInstancedBaseInstanceWEBGL:(a,b,c,e,f)=>{D.H.drawArraysInstancedBaseInstanceWEBGL(a, +b,c,e,f)},emscripten_glDrawBuffers:(a,b)=>{for(var c=jb[a],e=0;e>2];D.drawBuffers(c)},emscripten_glDrawElements:(a,b,c,e)=>{D.drawElements(a,b,c,e)},emscripten_glDrawElementsInstanced:(a,b,c,e,f)=>{D.drawElementsInstanced(a,b,c,e,f)},emscripten_glDrawElementsInstancedBaseVertexBaseInstanceWEBGL:(a,b,c,e,f,h,l)=>{D.H.drawElementsInstancedBaseVertexBaseInstanceWEBGL(a,b,c,e,f,h,l)},emscripten_glDrawRangeElements:(a,b,c,e,f,h)=>{D.drawElements(a,e,f,h)},emscripten_glEnable:a=>D.enable(a), +emscripten_glEnableVertexAttribArray:a=>{D.enableVertexAttribArray(a)},emscripten_glEndQuery:a=>D.endQuery(a),emscripten_glEndQueryEXT:a=>{D.g.endQueryEXT(a)},emscripten_glFenceSync:(a,b)=>(a=D.fenceSync(a,b))?(b=L(K),a.name=b,K[b]=a,b):0,emscripten_glFinish:()=>D.finish(),emscripten_glFlush:()=>D.flush(),emscripten_glFramebufferRenderbuffer:(a,b,c,e)=>{D.framebufferRenderbuffer(a,b,c,F[e])},emscripten_glFramebufferTexture2D:(a,b,c,e,f)=>{D.framebufferTexture2D(a,b,c,G[e],f)},emscripten_glFrontFace:a=> +D.frontFace(a),emscripten_glGenBuffers:(a,b)=>{N(a,b,"createBuffer",Wa)},emscripten_glGenFramebuffers:(a,b)=>{N(a,b,"createFramebuffer",Xa)},emscripten_glGenQueries:(a,b)=>{N(a,b,"createQuery",I)},emscripten_glGenQueriesEXT:(a,b)=>{for(var c=0;c>2]=0;break}var f=L(I);e.name=f;I[f]=e;r()[b+4*c>>2]=f}},emscripten_glGenRenderbuffers:(a,b)=>{N(a,b,"createRenderbuffer",F)},emscripten_glGenSamplers:(a,b)=>{N(a,b,"createSampler",J)}, +emscripten_glGenTextures:(a,b)=>{N(a,b,"createTexture",G)},emscripten_glGenVertexArrays:kb,emscripten_glGenVertexArraysOES:kb,emscripten_glGenerateMipmap:a=>D.generateMipmap(a),emscripten_glGetBufferParameteriv:(a,b,c)=>{c?r()[c>>2]=D.getBufferParameter(a,b):M||=1281},emscripten_glGetError:()=>{var a=D.getError()||M;M=0;return a},emscripten_glGetFloatv:(a,b)=>nb(a,b,2),emscripten_glGetFramebufferAttachmentParameteriv:(a,b,c,e)=>{a=D.getFramebufferAttachmentParameter(a,b,c);if(a instanceof WebGLRenderbuffer|| +a instanceof WebGLTexture)a=a.name|0;r()[e>>2]=a},emscripten_glGetIntegerv:ob,emscripten_glGetProgramInfoLog:(a,b,c,e)=>{a=D.getProgramInfoLog(E[a]);null===a&&(a="(unknown error)");b=0>2]=b)},emscripten_glGetProgramiv:(a,b,c)=>{if(c)if(a>=Va)M||=1281;else if(a=E[a],35716==b)a=D.getProgramInfoLog(a),null===a&&(a="(unknown error)"),r()[c>>2]=a.length+1;else if(35719==b){if(!a.C){var e=D.getProgramParameter(a,35718);for(b=0;b>2]=a.C}else if(35722==b){if(!a.A)for(e=D.getProgramParameter(a,35721),b=0;b>2]=a.A}else if(35381==b){if(!a.B)for(e=D.getProgramParameter(a,35382),b=0;b>2]=a.B}else r()[c>>2]=D.getProgramParameter(a,b);else M||=1281},emscripten_glGetQueryObjecti64vEXT:pb,emscripten_glGetQueryObjectui64vEXT:pb,emscripten_glGetQueryObjectuiv:(a,b,c)=>{if(c){a=D.getQueryParameter(I[a], +b);var e;"boolean"==typeof a?e=a?1:0:e=a;r()[c>>2]=e}else M||=1281},emscripten_glGetQueryObjectuivEXT:(a,b,c)=>{if(c){a=D.g.getQueryObjectEXT(I[a],b);var e;"boolean"==typeof a?e=a?1:0:e=a;r()[c>>2]=e}else M||=1281},emscripten_glGetQueryiv:(a,b,c)=>{c?r()[c>>2]=D.getQuery(a,b):M||=1281},emscripten_glGetQueryivEXT:(a,b,c)=>{c?r()[c>>2]=D.g.getQueryEXT(a,b):M||=1281},emscripten_glGetRenderbufferParameteriv:(a,b,c)=>{c?r()[c>>2]=D.getRenderbufferParameter(a,b):M||=1281},emscripten_glGetShaderInfoLog:(a, +b,c,e)=>{a=D.getShaderInfoLog(H[a]);null===a&&(a="(unknown error)");b=0>2]=b)},emscripten_glGetShaderPrecisionFormat:(a,b,c,e)=>{a=D.getShaderPrecisionFormat(a,b);r()[c>>2]=a.rangeMin;r()[c+4>>2]=a.rangeMax;r()[e>>2]=a.precision},emscripten_glGetShaderiv:(a,b,c)=>{c?35716==b?(a=D.getShaderInfoLog(H[a]),null===a&&(a="(unknown error)"),a=a?a.length+1:0,r()[c>>2]=a):35720==b?(a=(a=D.getShaderSource(H[a]))?a.length+1:0,r()[c>>2]=a):r()[c>>2]=D.getShaderParameter(H[a],b):M||= +1281},emscripten_glGetString:sb,emscripten_glGetStringi:tb,emscripten_glGetUniformLocation:(a,b)=>{b=Ka(b);if(a=E[a]){var c=a,e=c.u,f=c.M,h;if(!e){c.u=e={};c.L={};var l=D.getProgramParameter(c,35718);for(h=0;h>>0,f=b.slice(0,h));if((f=a.M[f])&&e{for(var e=jb[b],f=0;f>2];D.invalidateFramebuffer(a,e)},emscripten_glInvalidateSubFramebuffer:(a,b,c,e,f,h,l)=>{for(var m=jb[b],p=0;p>2];D.invalidateSubFramebuffer(a,m,e,f,h,l)},emscripten_glIsSync:a=>D.isSync(K[a]),emscripten_glIsTexture:a=>(a=G[a])?D.isTexture(a):0,emscripten_glLineWidth:a=>D.lineWidth(a),emscripten_glLinkProgram:a=>{a=E[a];D.linkProgram(a);a.u=0;a.M={}}, +emscripten_glMultiDrawArraysInstancedBaseInstanceWEBGL:(a,b,c,e,f,h)=>{D.K.multiDrawArraysInstancedBaseInstanceWEBGL(a,r(),b>>2,r(),c>>2,r(),e>>2,t(),f>>2,h)},emscripten_glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL:(a,b,c,e,f,h,l,m)=>{D.K.multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL(a,r(),b>>2,c,r(),e>>2,r(),f>>2,r(),h>>2,t(),l>>2,m)},emscripten_glPixelStorei:(a,b)=>{3317==a?bb=b:3314==a&&(cb=b);D.pixelStorei(a,b)},emscripten_glQueryCounterEXT:(a,b)=>{D.g.queryCounterEXT(I[a], +b)},emscripten_glReadBuffer:a=>D.readBuffer(a),emscripten_glReadPixels:(a,b,c,e,f,h,l)=>{if(2<=O.version)if(D.D)D.readPixels(a,b,c,e,f,h,l);else{var m=vb(h);l>>>=31-Math.clz32(m.BYTES_PER_ELEMENT);D.readPixels(a,b,c,e,f,h,m,l)}else(m=wb(h,f,c,e,l))?D.readPixels(a,b,c,e,f,h,m):M||=1280},emscripten_glRenderbufferStorage:(a,b,c,e)=>D.renderbufferStorage(a,b,c,e),emscripten_glRenderbufferStorageMultisample:(a,b,c,e,f)=>D.renderbufferStorageMultisample(a,b,c,e,f),emscripten_glSamplerParameterf:(a,b,c)=> +{D.samplerParameterf(J[a],b,c)},emscripten_glSamplerParameteri:(a,b,c)=>{D.samplerParameteri(J[a],b,c)},emscripten_glSamplerParameteriv:(a,b,c)=>{c=r()[c>>2];D.samplerParameteri(J[a],b,c)},emscripten_glScissor:(a,b,c,e)=>D.scissor(a,b,c,e),emscripten_glShaderSource:(a,b,c,e)=>{for(var f="",h=0;h>2]:void 0;f+=Ka(t()[c+4*h>>2],l)}D.shaderSource(H[a],f)},emscripten_glStencilFunc:(a,b,c)=>D.stencilFunc(a,b,c),emscripten_glStencilFuncSeparate:(a,b,c,e)=>D.stencilFuncSeparate(a, +b,c,e),emscripten_glStencilMask:a=>D.stencilMask(a),emscripten_glStencilMaskSeparate:(a,b)=>D.stencilMaskSeparate(a,b),emscripten_glStencilOp:(a,b,c)=>D.stencilOp(a,b,c),emscripten_glStencilOpSeparate:(a,b,c,e)=>D.stencilOpSeparate(a,b,c,e),emscripten_glTexImage2D:(a,b,c,e,f,h,l,m,p)=>{if(2<=O.version){if(D.o){D.texImage2D(a,b,c,e,f,h,l,m,p);return}if(p){var v=vb(m);p>>>=31-Math.clz32(v.BYTES_PER_ELEMENT);D.texImage2D(a,b,c,e,f,h,l,m,v,p);return}}v=p?wb(m,l,e,f,p):null;D.texImage2D(a,b,c,e,f,h,l, +m,v)},emscripten_glTexParameterf:(a,b,c)=>D.texParameterf(a,b,c),emscripten_glTexParameterfv:(a,b,c)=>{c=u()[c>>2];D.texParameterf(a,b,c)},emscripten_glTexParameteri:(a,b,c)=>D.texParameteri(a,b,c),emscripten_glTexParameteriv:(a,b,c)=>{c=r()[c>>2];D.texParameteri(a,b,c)},emscripten_glTexStorage2D:(a,b,c,e,f)=>D.texStorage2D(a,b,c,e,f),emscripten_glTexSubImage2D:(a,b,c,e,f,h,l,m,p)=>{if(2<=O.version){if(D.o){D.texSubImage2D(a,b,c,e,f,h,l,m,p);return}if(p){var v=vb(m);D.texSubImage2D(a,b,c,e,f,h,l, +m,v,p>>>31-Math.clz32(v.BYTES_PER_ELEMENT));return}}p=p?wb(m,l,f,h,p):null;D.texSubImage2D(a,b,c,e,f,h,l,m,p)},emscripten_glUniform1f:(a,b)=>{D.uniform1f(P(a),b)},emscripten_glUniform1fv:(a,b,c)=>{if(2<=O.version)b&&D.uniform1fv(P(a),u(),c>>2,b);else{if(288>=b)for(var e=Q[b],f=0;f>2];else e=u().subarray(c>>2,c+4*b>>2);D.uniform1fv(P(a),e)}},emscripten_glUniform1i:(a,b)=>{D.uniform1i(P(a),b)},emscripten_glUniform1iv:(a,b,c)=>{if(2<=O.version)b&&D.uniform1iv(P(a),r(),c>>2,b);else{if(288>= +b)for(var e=xb[b],f=0;f>2];else e=r().subarray(c>>2,c+4*b>>2);D.uniform1iv(P(a),e)}},emscripten_glUniform2f:(a,b,c)=>{D.uniform2f(P(a),b,c)},emscripten_glUniform2fv:(a,b,c)=>{if(2<=O.version)b&&D.uniform2fv(P(a),u(),c>>2,2*b);else{if(144>=b){b*=2;for(var e=Q[b],f=0;f>2],e[f+1]=u()[c+(4*f+4)>>2]}else e=u().subarray(c>>2,c+8*b>>2);D.uniform2fv(P(a),e)}},emscripten_glUniform2i:(a,b,c)=>{D.uniform2i(P(a),b,c)},emscripten_glUniform2iv:(a,b,c)=>{if(2<=O.version)b&& +D.uniform2iv(P(a),r(),c>>2,2*b);else{if(144>=b){b*=2;for(var e=xb[b],f=0;f>2],e[f+1]=r()[c+(4*f+4)>>2]}else e=r().subarray(c>>2,c+8*b>>2);D.uniform2iv(P(a),e)}},emscripten_glUniform3f:(a,b,c,e)=>{D.uniform3f(P(a),b,c,e)},emscripten_glUniform3fv:(a,b,c)=>{if(2<=O.version)b&&D.uniform3fv(P(a),u(),c>>2,3*b);else{if(96>=b){b*=3;for(var e=Q[b],f=0;f>2],e[f+1]=u()[c+(4*f+4)>>2],e[f+2]=u()[c+(4*f+8)>>2]}else e=u().subarray(c>>2,c+12*b>>2);D.uniform3fv(P(a),e)}}, +emscripten_glUniform3i:(a,b,c,e)=>{D.uniform3i(P(a),b,c,e)},emscripten_glUniform3iv:(a,b,c)=>{if(2<=O.version)b&&D.uniform3iv(P(a),r(),c>>2,3*b);else{if(96>=b){b*=3;for(var e=xb[b],f=0;f>2],e[f+1]=r()[c+(4*f+4)>>2],e[f+2]=r()[c+(4*f+8)>>2]}else e=r().subarray(c>>2,c+12*b>>2);D.uniform3iv(P(a),e)}},emscripten_glUniform4f:(a,b,c,e,f)=>{D.uniform4f(P(a),b,c,e,f)},emscripten_glUniform4fv:(a,b,c)=>{if(2<=O.version)b&&D.uniform4fv(P(a),u(),c>>2,4*b);else{if(72>=b){var e=Q[4*b],f= +u();c>>=2;b*=4;for(var h=0;h>2,c+16*b>>2);D.uniform4fv(P(a),e)}},emscripten_glUniform4i:(a,b,c,e,f)=>{D.uniform4i(P(a),b,c,e,f)},emscripten_glUniform4iv:(a,b,c)=>{if(2<=O.version)b&&D.uniform4iv(P(a),r(),c>>2,4*b);else{if(72>=b){b*=4;for(var e=xb[b],f=0;f>2],e[f+1]=r()[c+(4*f+4)>>2],e[f+2]=r()[c+(4*f+8)>>2],e[f+3]=r()[c+(4*f+12)>>2]}else e=r().subarray(c>>2,c+16*b>>2);D.uniform4iv(P(a), +e)}},emscripten_glUniformMatrix2fv:(a,b,c,e)=>{if(2<=O.version)b&&D.uniformMatrix2fv(P(a),!!c,u(),e>>2,4*b);else{if(72>=b){b*=4;for(var f=Q[b],h=0;h>2],f[h+1]=u()[e+(4*h+4)>>2],f[h+2]=u()[e+(4*h+8)>>2],f[h+3]=u()[e+(4*h+12)>>2]}else f=u().subarray(e>>2,e+16*b>>2);D.uniformMatrix2fv(P(a),!!c,f)}},emscripten_glUniformMatrix3fv:(a,b,c,e)=>{if(2<=O.version)b&&D.uniformMatrix3fv(P(a),!!c,u(),e>>2,9*b);else{if(32>=b){b*=9;for(var f=Q[b],h=0;h>2],f[h+1]=u()[e+ +(4*h+4)>>2],f[h+2]=u()[e+(4*h+8)>>2],f[h+3]=u()[e+(4*h+12)>>2],f[h+4]=u()[e+(4*h+16)>>2],f[h+5]=u()[e+(4*h+20)>>2],f[h+6]=u()[e+(4*h+24)>>2],f[h+7]=u()[e+(4*h+28)>>2],f[h+8]=u()[e+(4*h+32)>>2]}else f=u().subarray(e>>2,e+36*b>>2);D.uniformMatrix3fv(P(a),!!c,f)}},emscripten_glUniformMatrix4fv:(a,b,c,e)=>{if(2<=O.version)b&&D.uniformMatrix4fv(P(a),!!c,u(),e>>2,16*b);else{if(18>=b){var f=Q[16*b],h=u();e>>=2;b*=16;for(var l=0;l>2,e+64*b>>2);D.uniformMatrix4fv(P(a),!!c,f)}},emscripten_glUseProgram:a=>{a=E[a];D.useProgram(a);D.N=a},emscripten_glVertexAttrib1f:(a,b)=>D.vertexAttrib1f(a,b),emscripten_glVertexAttrib2fv:(a,b)=>{D.vertexAttrib2f(a,u()[b>>2],u()[b+4>>2])},emscripten_glVertexAttrib3fv:(a,b)=>{D.vertexAttrib3f(a,u()[b>> +2],u()[b+4>>2],u()[b+8>>2])},emscripten_glVertexAttrib4fv:(a,b)=>{D.vertexAttrib4f(a,u()[b>>2],u()[b+4>>2],u()[b+8>>2],u()[b+12>>2])},emscripten_glVertexAttribDivisor:(a,b)=>{D.vertexAttribDivisor(a,b)},emscripten_glVertexAttribIPointer:(a,b,c,e,f)=>{D.vertexAttribIPointer(a,b,c,e,f)},emscripten_glVertexAttribPointer:(a,b,c,e,f,h)=>{D.vertexAttribPointer(a,b,c,!!e,f,h)},emscripten_glViewport:(a,b,c,e)=>D.viewport(a,b,c,e),emscripten_glWaitSync:(a,b,c,e)=>{D.waitSync(K[a],b,(c>>>0)+4294967296*e)}, +emscripten_resize_heap:a=>{var b=q().length;a>>>=0;if(a<=b||2147483648=c;c*=2){var e=b*(1+.2/c);e=Math.min(e,a+100663296);a:{e=(Math.min(2147483648,65536*Math.ceil(Math.max(a,e)/65536))-g.buffer.byteLength+65535)/65536|0;try{g.grow(e);n();var f=1;break a}catch(h){}f=void 0}if(f)return!0}return!1},emscripten_webgl_enable_extension:function(a,b){a=Za[a];b=Ka(b);b.startsWith("GL_")&&(b=b.substr(3));"ANGLE_instanced_arrays"==b&&Pa(D);"OES_vertex_array_object"==b&&Qa(D);"WEBGL_draw_buffers"== +b&&Ra(D);"WEBGL_draw_instanced_base_vertex_base_instance"==b&&Sa(D);"WEBGL_multi_draw_instanced_base_vertex_base_instance"==b&&Ta(D);"WEBGL_multi_draw"==b&&(D.T=D.getExtension("WEBGL_multi_draw"));"EXT_polygon_offset_clamp"==b&&(D.P=D.getExtension("EXT_polygon_offset_clamp"));"EXT_clip_control"==b&&(D.O=D.getExtension("EXT_clip_control"));"WEBGL_polygon_mode"==b&&(D.Y=D.getExtension("WEBGL_polygon_mode"));return!!a.v.getExtension(b)},emscripten_webgl_get_current_context:()=>O?O.handle:0,emscripten_webgl_make_context_current:a=> +{O=Za[a];w.$=D=O?.v;return!a||D?0:-5},environ_get:(a,b)=>{var c=0;Ab().forEach((e,f)=>{var h=b+c;f=t()[a+4*f>>2]=h;for(h=0;h{var c=Ab();t()[a>>2]=c.length;var e=0;c.forEach(f=>e+=f.length+1);t()[b>>2]=e;return 0},fd_close:()=>52,fd_pread:function(){return 52},fd_read:()=>52,fd_seek:function(){return 70},fd_write:(a,b,c,e)=>{for(var f=0,h=0;h>2],m=t()[b+4>>2];b+=8;for(var p=0;p>2]=f;return 0},glDeleteTextures:hb,glGetIntegerv:ob,glGetString:sb,glGetStringi:tb,invoke_ii:bc,invoke_iii:cc,invoke_iiii:dc,invoke_iiiii:ec,invoke_iiiiiii:fc,invoke_vi:gc,invoke_vii:hc,invoke_viii:ic,invoke_viiii:jc,invoke_viiiiiii:kc,proc_exit:Na,skwasm_captureImageBitmap:Eb,skwasm_connectThread:Fb,skwasm_createGlTextureFromTextureSource:Gb,skwasm_createOffscreenCanvas:Hb,skwasm_dispatchDisposeSurface:Ib,skwasm_dispatchRasterizeImage:Jb, +skwasm_dispatchRenderPictures:Kb,skwasm_disposeAssociatedObjectOnThread:Lb,skwasm_getAssociatedObject:Mb,skwasm_postRasterizeResult:Nb,skwasm_resizeCanvas:Ob,skwasm_resolveAndPostImages:Pb,skwasm_setAssociatedObjectOnThread:Qb},W=function(){function a(c){W=c.exports;w.wasmExports=W;g=W.memory;w.wasmMemory=g;n();S=W.__indirect_function_table;ta.unshift(W.__wasm_call_ctors);z--;0==z&&(null!==va&&(clearInterval(va),va=null),A&&(c=A,A=null,c()));return W}var b={env:lc,wasi_snapshot_preview1:lc};z++;if(w.instantiateWasm)try{return w.instantiateWasm(b, +a)}catch(c){y(`Module.instantiateWasm callback failed with error: ${c}`),fa(c)}ya??=xa("skwasm_st.wasm")?"skwasm_st.wasm":x+"skwasm_st.wasm";Ba(b,function(c){a(c.instance,c.module)}).catch(fa);return{}}();w._canvas_saveLayer=(a,b,c,e,f)=>(w._canvas_saveLayer=W.canvas_saveLayer)(a,b,c,e,f);w._canvas_save=a=>(w._canvas_save=W.canvas_save)(a);w._canvas_restore=a=>(w._canvas_restore=W.canvas_restore)(a);w._canvas_restoreToCount=(a,b)=>(w._canvas_restoreToCount=W.canvas_restoreToCount)(a,b); +w._canvas_getSaveCount=a=>(w._canvas_getSaveCount=W.canvas_getSaveCount)(a);w._canvas_translate=(a,b,c)=>(w._canvas_translate=W.canvas_translate)(a,b,c);w._canvas_scale=(a,b,c)=>(w._canvas_scale=W.canvas_scale)(a,b,c);w._canvas_rotate=(a,b)=>(w._canvas_rotate=W.canvas_rotate)(a,b);w._canvas_skew=(a,b,c)=>(w._canvas_skew=W.canvas_skew)(a,b,c);w._canvas_transform=(a,b)=>(w._canvas_transform=W.canvas_transform)(a,b);w._canvas_clipRect=(a,b,c,e)=>(w._canvas_clipRect=W.canvas_clipRect)(a,b,c,e); +w._canvas_clipRRect=(a,b,c)=>(w._canvas_clipRRect=W.canvas_clipRRect)(a,b,c);w._canvas_clipPath=(a,b,c)=>(w._canvas_clipPath=W.canvas_clipPath)(a,b,c);w._canvas_drawColor=(a,b,c)=>(w._canvas_drawColor=W.canvas_drawColor)(a,b,c);w._canvas_drawLine=(a,b,c,e,f,h)=>(w._canvas_drawLine=W.canvas_drawLine)(a,b,c,e,f,h);w._canvas_drawPaint=(a,b)=>(w._canvas_drawPaint=W.canvas_drawPaint)(a,b);w._canvas_drawRect=(a,b,c)=>(w._canvas_drawRect=W.canvas_drawRect)(a,b,c); +w._canvas_drawRRect=(a,b,c)=>(w._canvas_drawRRect=W.canvas_drawRRect)(a,b,c);w._canvas_drawDRRect=(a,b,c,e)=>(w._canvas_drawDRRect=W.canvas_drawDRRect)(a,b,c,e);w._canvas_drawOval=(a,b,c)=>(w._canvas_drawOval=W.canvas_drawOval)(a,b,c);w._canvas_drawCircle=(a,b,c,e,f)=>(w._canvas_drawCircle=W.canvas_drawCircle)(a,b,c,e,f);w._canvas_drawArc=(a,b,c,e,f,h)=>(w._canvas_drawArc=W.canvas_drawArc)(a,b,c,e,f,h);w._canvas_drawPath=(a,b,c)=>(w._canvas_drawPath=W.canvas_drawPath)(a,b,c); +w._canvas_drawShadow=(a,b,c,e,f,h)=>(w._canvas_drawShadow=W.canvas_drawShadow)(a,b,c,e,f,h);w._canvas_drawParagraph=(a,b,c,e)=>(w._canvas_drawParagraph=W.canvas_drawParagraph)(a,b,c,e);w._canvas_drawPicture=(a,b)=>(w._canvas_drawPicture=W.canvas_drawPicture)(a,b);w._canvas_drawImage=(a,b,c,e,f,h)=>(w._canvas_drawImage=W.canvas_drawImage)(a,b,c,e,f,h);w._canvas_drawImageRect=(a,b,c,e,f,h)=>(w._canvas_drawImageRect=W.canvas_drawImageRect)(a,b,c,e,f,h); +w._canvas_drawImageNine=(a,b,c,e,f,h)=>(w._canvas_drawImageNine=W.canvas_drawImageNine)(a,b,c,e,f,h);w._canvas_drawVertices=(a,b,c,e)=>(w._canvas_drawVertices=W.canvas_drawVertices)(a,b,c,e);w._canvas_drawPoints=(a,b,c,e,f)=>(w._canvas_drawPoints=W.canvas_drawPoints)(a,b,c,e,f);w._canvas_drawAtlas=(a,b,c,e,f,h,l,m,p)=>(w._canvas_drawAtlas=W.canvas_drawAtlas)(a,b,c,e,f,h,l,m,p);w._canvas_getTransform=(a,b)=>(w._canvas_getTransform=W.canvas_getTransform)(a,b); +w._canvas_getLocalClipBounds=(a,b)=>(w._canvas_getLocalClipBounds=W.canvas_getLocalClipBounds)(a,b);w._canvas_getDeviceClipBounds=(a,b)=>(w._canvas_getDeviceClipBounds=W.canvas_getDeviceClipBounds)(a,b);w._contourMeasureIter_create=(a,b,c)=>(w._contourMeasureIter_create=W.contourMeasureIter_create)(a,b,c);w._contourMeasureIter_next=a=>(w._contourMeasureIter_next=W.contourMeasureIter_next)(a);w._contourMeasureIter_dispose=a=>(w._contourMeasureIter_dispose=W.contourMeasureIter_dispose)(a); +w._contourMeasure_dispose=a=>(w._contourMeasure_dispose=W.contourMeasure_dispose)(a);w._contourMeasure_length=a=>(w._contourMeasure_length=W.contourMeasure_length)(a);w._contourMeasure_isClosed=a=>(w._contourMeasure_isClosed=W.contourMeasure_isClosed)(a);w._contourMeasure_getPosTan=(a,b,c,e)=>(w._contourMeasure_getPosTan=W.contourMeasure_getPosTan)(a,b,c,e);w._contourMeasure_getSegment=(a,b,c,e)=>(w._contourMeasure_getSegment=W.contourMeasure_getSegment)(a,b,c,e); +w._skData_create=a=>(w._skData_create=W.skData_create)(a);w._skData_getPointer=a=>(w._skData_getPointer=W.skData_getPointer)(a);w._skData_getConstPointer=a=>(w._skData_getConstPointer=W.skData_getConstPointer)(a);w._skData_getSize=a=>(w._skData_getSize=W.skData_getSize)(a);w._skData_dispose=a=>(w._skData_dispose=W.skData_dispose)(a);w._imageFilter_createBlur=(a,b,c)=>(w._imageFilter_createBlur=W.imageFilter_createBlur)(a,b,c); +w._imageFilter_createDilate=(a,b)=>(w._imageFilter_createDilate=W.imageFilter_createDilate)(a,b);w._imageFilter_createErode=(a,b)=>(w._imageFilter_createErode=W.imageFilter_createErode)(a,b);w._imageFilter_createMatrix=(a,b)=>(w._imageFilter_createMatrix=W.imageFilter_createMatrix)(a,b);w._imageFilter_createFromColorFilter=a=>(w._imageFilter_createFromColorFilter=W.imageFilter_createFromColorFilter)(a);w._imageFilter_compose=(a,b)=>(w._imageFilter_compose=W.imageFilter_compose)(a,b); +w._imageFilter_dispose=a=>(w._imageFilter_dispose=W.imageFilter_dispose)(a);w._imageFilter_getFilterBounds=(a,b)=>(w._imageFilter_getFilterBounds=W.imageFilter_getFilterBounds)(a,b);w._colorFilter_createMode=(a,b)=>(w._colorFilter_createMode=W.colorFilter_createMode)(a,b);w._colorFilter_createMatrix=a=>(w._colorFilter_createMatrix=W.colorFilter_createMatrix)(a);w._colorFilter_createSRGBToLinearGamma=()=>(w._colorFilter_createSRGBToLinearGamma=W.colorFilter_createSRGBToLinearGamma)(); +w._colorFilter_createLinearToSRGBGamma=()=>(w._colorFilter_createLinearToSRGBGamma=W.colorFilter_createLinearToSRGBGamma)();w._colorFilter_compose=(a,b)=>(w._colorFilter_compose=W.colorFilter_compose)(a,b);w._colorFilter_dispose=a=>(w._colorFilter_dispose=W.colorFilter_dispose)(a);w._maskFilter_createBlur=(a,b)=>(w._maskFilter_createBlur=W.maskFilter_createBlur)(a,b);w._maskFilter_dispose=a=>(w._maskFilter_dispose=W.maskFilter_dispose)(a);w._fontCollection_create=()=>(w._fontCollection_create=W.fontCollection_create)(); +w._fontCollection_dispose=a=>(w._fontCollection_dispose=W.fontCollection_dispose)(a);w._typeface_create=a=>(w._typeface_create=W.typeface_create)(a);w._typeface_dispose=a=>(w._typeface_dispose=W.typeface_dispose)(a);w._typefaces_filterCoveredCodePoints=(a,b,c,e)=>(w._typefaces_filterCoveredCodePoints=W.typefaces_filterCoveredCodePoints)(a,b,c,e);w._fontCollection_registerTypeface=(a,b,c)=>(w._fontCollection_registerTypeface=W.fontCollection_registerTypeface)(a,b,c); +w._fontCollection_clearCaches=a=>(w._fontCollection_clearCaches=W.fontCollection_clearCaches)(a);w._image_createFromPicture=(a,b,c)=>(w._image_createFromPicture=W.image_createFromPicture)(a,b,c);w._image_createFromPixels=(a,b,c,e,f)=>(w._image_createFromPixels=W.image_createFromPixels)(a,b,c,e,f);w._image_createFromTextureSource=(a,b,c,e)=>(w._image_createFromTextureSource=W.image_createFromTextureSource)(a,b,c,e);w._image_ref=a=>(w._image_ref=W.image_ref)(a); +w._image_dispose=a=>(w._image_dispose=W.image_dispose)(a);w._image_getWidth=a=>(w._image_getWidth=W.image_getWidth)(a);w._image_getHeight=a=>(w._image_getHeight=W.image_getHeight)(a);w._paint_create=(a,b,c,e,f,h,l,m)=>(w._paint_create=W.paint_create)(a,b,c,e,f,h,l,m);w._paint_dispose=a=>(w._paint_dispose=W.paint_dispose)(a);w._paint_setShader=(a,b)=>(w._paint_setShader=W.paint_setShader)(a,b);w._paint_setImageFilter=(a,b)=>(w._paint_setImageFilter=W.paint_setImageFilter)(a,b); +w._paint_setColorFilter=(a,b)=>(w._paint_setColorFilter=W.paint_setColorFilter)(a,b);w._paint_setMaskFilter=(a,b)=>(w._paint_setMaskFilter=W.paint_setMaskFilter)(a,b);w._path_create=()=>(w._path_create=W.path_create)();w._path_dispose=a=>(w._path_dispose=W.path_dispose)(a);w._path_copy=a=>(w._path_copy=W.path_copy)(a);w._path_setFillType=(a,b)=>(w._path_setFillType=W.path_setFillType)(a,b);w._path_getFillType=a=>(w._path_getFillType=W.path_getFillType)(a); +w._path_moveTo=(a,b,c)=>(w._path_moveTo=W.path_moveTo)(a,b,c);w._path_relativeMoveTo=(a,b,c)=>(w._path_relativeMoveTo=W.path_relativeMoveTo)(a,b,c);w._path_lineTo=(a,b,c)=>(w._path_lineTo=W.path_lineTo)(a,b,c);w._path_relativeLineTo=(a,b,c)=>(w._path_relativeLineTo=W.path_relativeLineTo)(a,b,c);w._path_quadraticBezierTo=(a,b,c,e,f)=>(w._path_quadraticBezierTo=W.path_quadraticBezierTo)(a,b,c,e,f); +w._path_relativeQuadraticBezierTo=(a,b,c,e,f)=>(w._path_relativeQuadraticBezierTo=W.path_relativeQuadraticBezierTo)(a,b,c,e,f);w._path_cubicTo=(a,b,c,e,f,h,l)=>(w._path_cubicTo=W.path_cubicTo)(a,b,c,e,f,h,l);w._path_relativeCubicTo=(a,b,c,e,f,h,l)=>(w._path_relativeCubicTo=W.path_relativeCubicTo)(a,b,c,e,f,h,l);w._path_conicTo=(a,b,c,e,f,h)=>(w._path_conicTo=W.path_conicTo)(a,b,c,e,f,h);w._path_relativeConicTo=(a,b,c,e,f,h)=>(w._path_relativeConicTo=W.path_relativeConicTo)(a,b,c,e,f,h); +w._path_arcToOval=(a,b,c,e,f)=>(w._path_arcToOval=W.path_arcToOval)(a,b,c,e,f);w._path_arcToRotated=(a,b,c,e,f,h,l,m)=>(w._path_arcToRotated=W.path_arcToRotated)(a,b,c,e,f,h,l,m);w._path_relativeArcToRotated=(a,b,c,e,f,h,l,m)=>(w._path_relativeArcToRotated=W.path_relativeArcToRotated)(a,b,c,e,f,h,l,m);w._path_addRect=(a,b)=>(w._path_addRect=W.path_addRect)(a,b);w._path_addOval=(a,b)=>(w._path_addOval=W.path_addOval)(a,b);w._path_addArc=(a,b,c,e)=>(w._path_addArc=W.path_addArc)(a,b,c,e); +w._path_addPolygon=(a,b,c,e)=>(w._path_addPolygon=W.path_addPolygon)(a,b,c,e);w._path_addRRect=(a,b)=>(w._path_addRRect=W.path_addRRect)(a,b);w._path_addPath=(a,b,c,e)=>(w._path_addPath=W.path_addPath)(a,b,c,e);w._path_close=a=>(w._path_close=W.path_close)(a);w._path_reset=a=>(w._path_reset=W.path_reset)(a);w._path_contains=(a,b,c)=>(w._path_contains=W.path_contains)(a,b,c);w._path_transform=(a,b)=>(w._path_transform=W.path_transform)(a,b); +w._path_getBounds=(a,b)=>(w._path_getBounds=W.path_getBounds)(a,b);w._path_combine=(a,b,c)=>(w._path_combine=W.path_combine)(a,b,c);w._path_getSvgString=a=>(w._path_getSvgString=W.path_getSvgString)(a);w._pictureRecorder_create=()=>(w._pictureRecorder_create=W.pictureRecorder_create)();w._pictureRecorder_dispose=a=>(w._pictureRecorder_dispose=W.pictureRecorder_dispose)(a);w._pictureRecorder_beginRecording=(a,b)=>(w._pictureRecorder_beginRecording=W.pictureRecorder_beginRecording)(a,b); +w._pictureRecorder_endRecording=a=>(w._pictureRecorder_endRecording=W.pictureRecorder_endRecording)(a);w._picture_getCullRect=(a,b)=>(w._picture_getCullRect=W.picture_getCullRect)(a,b);w._picture_dispose=a=>(w._picture_dispose=W.picture_dispose)(a);w._picture_approximateBytesUsed=a=>(w._picture_approximateBytesUsed=W.picture_approximateBytesUsed)(a);w._shader_createLinearGradient=(a,b,c,e,f,h)=>(w._shader_createLinearGradient=W.shader_createLinearGradient)(a,b,c,e,f,h); +w._shader_createRadialGradient=(a,b,c,e,f,h,l,m)=>(w._shader_createRadialGradient=W.shader_createRadialGradient)(a,b,c,e,f,h,l,m);w._shader_createConicalGradient=(a,b,c,e,f,h,l,m)=>(w._shader_createConicalGradient=W.shader_createConicalGradient)(a,b,c,e,f,h,l,m);w._shader_createSweepGradient=(a,b,c,e,f,h,l,m,p)=>(w._shader_createSweepGradient=W.shader_createSweepGradient)(a,b,c,e,f,h,l,m,p);w._shader_dispose=a=>(w._shader_dispose=W.shader_dispose)(a); +w._runtimeEffect_create=a=>(w._runtimeEffect_create=W.runtimeEffect_create)(a);w._runtimeEffect_dispose=a=>(w._runtimeEffect_dispose=W.runtimeEffect_dispose)(a);w._runtimeEffect_getUniformSize=a=>(w._runtimeEffect_getUniformSize=W.runtimeEffect_getUniformSize)(a);w._shader_createRuntimeEffectShader=(a,b,c,e)=>(w._shader_createRuntimeEffectShader=W.shader_createRuntimeEffectShader)(a,b,c,e);w._shader_createFromImage=(a,b,c,e,f)=>(w._shader_createFromImage=W.shader_createFromImage)(a,b,c,e,f); +w._skString_allocate=a=>(w._skString_allocate=W.skString_allocate)(a);w._skString_getData=a=>(w._skString_getData=W.skString_getData)(a);w._skString_getLength=a=>(w._skString_getLength=W.skString_getLength)(a);w._skString_free=a=>(w._skString_free=W.skString_free)(a);w._skString16_allocate=a=>(w._skString16_allocate=W.skString16_allocate)(a);w._skString16_getData=a=>(w._skString16_getData=W.skString16_getData)(a);w._skString16_free=a=>(w._skString16_free=W.skString16_free)(a); +w._surface_create=()=>(w._surface_create=W.surface_create)();w._surface_getThreadId=a=>(w._surface_getThreadId=W.surface_getThreadId)(a);w._surface_setCallbackHandler=(a,b)=>(w._surface_setCallbackHandler=W.surface_setCallbackHandler)(a,b);w._surface_destroy=a=>(w._surface_destroy=W.surface_destroy)(a);var Yb=w._surface_dispose=a=>(Yb=w._surface_dispose=W.surface_dispose)(a);w._surface_renderPictures=(a,b,c)=>(w._surface_renderPictures=W.surface_renderPictures)(a,b,c); +var Wb=w._surface_renderPicturesOnWorker=(a,b,c,e,f)=>(Wb=w._surface_renderPicturesOnWorker=W.surface_renderPicturesOnWorker)(a,b,c,e,f);w._surface_rasterizeImage=(a,b,c)=>(w._surface_rasterizeImage=W.surface_rasterizeImage)(a,b,c); +var Zb=w._surface_rasterizeImageOnWorker=(a,b,c,e)=>(Zb=w._surface_rasterizeImageOnWorker=W.surface_rasterizeImageOnWorker)(a,b,c,e),Xb=w._surface_onRenderComplete=(a,b,c)=>(Xb=w._surface_onRenderComplete=W.surface_onRenderComplete)(a,b,c),$b=w._surface_onRasterizeComplete=(a,b,c)=>($b=w._surface_onRasterizeComplete=W.surface_onRasterizeComplete)(a,b,c);w._lineMetrics_create=(a,b,c,e,f,h,l,m,p)=>(w._lineMetrics_create=W.lineMetrics_create)(a,b,c,e,f,h,l,m,p); +w._lineMetrics_dispose=a=>(w._lineMetrics_dispose=W.lineMetrics_dispose)(a);w._lineMetrics_getHardBreak=a=>(w._lineMetrics_getHardBreak=W.lineMetrics_getHardBreak)(a);w._lineMetrics_getAscent=a=>(w._lineMetrics_getAscent=W.lineMetrics_getAscent)(a);w._lineMetrics_getDescent=a=>(w._lineMetrics_getDescent=W.lineMetrics_getDescent)(a);w._lineMetrics_getUnscaledAscent=a=>(w._lineMetrics_getUnscaledAscent=W.lineMetrics_getUnscaledAscent)(a);w._lineMetrics_getHeight=a=>(w._lineMetrics_getHeight=W.lineMetrics_getHeight)(a); +w._lineMetrics_getWidth=a=>(w._lineMetrics_getWidth=W.lineMetrics_getWidth)(a);w._lineMetrics_getLeft=a=>(w._lineMetrics_getLeft=W.lineMetrics_getLeft)(a);w._lineMetrics_getBaseline=a=>(w._lineMetrics_getBaseline=W.lineMetrics_getBaseline)(a);w._lineMetrics_getLineNumber=a=>(w._lineMetrics_getLineNumber=W.lineMetrics_getLineNumber)(a);w._lineMetrics_getStartIndex=a=>(w._lineMetrics_getStartIndex=W.lineMetrics_getStartIndex)(a);w._lineMetrics_getEndIndex=a=>(w._lineMetrics_getEndIndex=W.lineMetrics_getEndIndex)(a); +w._paragraph_dispose=a=>(w._paragraph_dispose=W.paragraph_dispose)(a);w._paragraph_getWidth=a=>(w._paragraph_getWidth=W.paragraph_getWidth)(a);w._paragraph_getHeight=a=>(w._paragraph_getHeight=W.paragraph_getHeight)(a);w._paragraph_getLongestLine=a=>(w._paragraph_getLongestLine=W.paragraph_getLongestLine)(a);w._paragraph_getMinIntrinsicWidth=a=>(w._paragraph_getMinIntrinsicWidth=W.paragraph_getMinIntrinsicWidth)(a);w._paragraph_getMaxIntrinsicWidth=a=>(w._paragraph_getMaxIntrinsicWidth=W.paragraph_getMaxIntrinsicWidth)(a); +w._paragraph_getAlphabeticBaseline=a=>(w._paragraph_getAlphabeticBaseline=W.paragraph_getAlphabeticBaseline)(a);w._paragraph_getIdeographicBaseline=a=>(w._paragraph_getIdeographicBaseline=W.paragraph_getIdeographicBaseline)(a);w._paragraph_getDidExceedMaxLines=a=>(w._paragraph_getDidExceedMaxLines=W.paragraph_getDidExceedMaxLines)(a);w._paragraph_layout=(a,b)=>(w._paragraph_layout=W.paragraph_layout)(a,b); +w._paragraph_getPositionForOffset=(a,b,c,e)=>(w._paragraph_getPositionForOffset=W.paragraph_getPositionForOffset)(a,b,c,e);w._paragraph_getClosestGlyphInfoAtCoordinate=(a,b,c,e,f,h)=>(w._paragraph_getClosestGlyphInfoAtCoordinate=W.paragraph_getClosestGlyphInfoAtCoordinate)(a,b,c,e,f,h);w._paragraph_getGlyphInfoAt=(a,b,c,e,f)=>(w._paragraph_getGlyphInfoAt=W.paragraph_getGlyphInfoAt)(a,b,c,e,f);w._paragraph_getWordBoundary=(a,b,c)=>(w._paragraph_getWordBoundary=W.paragraph_getWordBoundary)(a,b,c); +w._paragraph_getLineCount=a=>(w._paragraph_getLineCount=W.paragraph_getLineCount)(a);w._paragraph_getLineNumberAt=(a,b)=>(w._paragraph_getLineNumberAt=W.paragraph_getLineNumberAt)(a,b);w._paragraph_getLineMetricsAtIndex=(a,b)=>(w._paragraph_getLineMetricsAtIndex=W.paragraph_getLineMetricsAtIndex)(a,b);w._textBoxList_dispose=a=>(w._textBoxList_dispose=W.textBoxList_dispose)(a);w._textBoxList_getLength=a=>(w._textBoxList_getLength=W.textBoxList_getLength)(a); +w._textBoxList_getBoxAtIndex=(a,b,c)=>(w._textBoxList_getBoxAtIndex=W.textBoxList_getBoxAtIndex)(a,b,c);w._paragraph_getBoxesForRange=(a,b,c,e,f)=>(w._paragraph_getBoxesForRange=W.paragraph_getBoxesForRange)(a,b,c,e,f);w._paragraph_getBoxesForPlaceholders=a=>(w._paragraph_getBoxesForPlaceholders=W.paragraph_getBoxesForPlaceholders)(a);w._paragraph_getUnresolvedCodePoints=(a,b,c)=>(w._paragraph_getUnresolvedCodePoints=W.paragraph_getUnresolvedCodePoints)(a,b,c); +w._paragraphBuilder_create=(a,b)=>(w._paragraphBuilder_create=W.paragraphBuilder_create)(a,b);w._paragraphBuilder_dispose=a=>(w._paragraphBuilder_dispose=W.paragraphBuilder_dispose)(a);w._paragraphBuilder_addPlaceholder=(a,b,c,e,f,h)=>(w._paragraphBuilder_addPlaceholder=W.paragraphBuilder_addPlaceholder)(a,b,c,e,f,h);w._paragraphBuilder_addText=(a,b)=>(w._paragraphBuilder_addText=W.paragraphBuilder_addText)(a,b); +w._paragraphBuilder_getUtf8Text=(a,b)=>(w._paragraphBuilder_getUtf8Text=W.paragraphBuilder_getUtf8Text)(a,b);w._paragraphBuilder_pushStyle=(a,b)=>(w._paragraphBuilder_pushStyle=W.paragraphBuilder_pushStyle)(a,b);w._paragraphBuilder_pop=a=>(w._paragraphBuilder_pop=W.paragraphBuilder_pop)(a);w._paragraphBuilder_build=a=>(w._paragraphBuilder_build=W.paragraphBuilder_build)(a);w._unicodePositionBuffer_create=a=>(w._unicodePositionBuffer_create=W.unicodePositionBuffer_create)(a); +w._unicodePositionBuffer_getDataPointer=a=>(w._unicodePositionBuffer_getDataPointer=W.unicodePositionBuffer_getDataPointer)(a);w._unicodePositionBuffer_free=a=>(w._unicodePositionBuffer_free=W.unicodePositionBuffer_free)(a);w._lineBreakBuffer_create=a=>(w._lineBreakBuffer_create=W.lineBreakBuffer_create)(a);w._lineBreakBuffer_getDataPointer=a=>(w._lineBreakBuffer_getDataPointer=W.lineBreakBuffer_getDataPointer)(a);w._lineBreakBuffer_free=a=>(w._lineBreakBuffer_free=W.lineBreakBuffer_free)(a); +w._paragraphBuilder_setGraphemeBreaksUtf16=(a,b)=>(w._paragraphBuilder_setGraphemeBreaksUtf16=W.paragraphBuilder_setGraphemeBreaksUtf16)(a,b);w._paragraphBuilder_setWordBreaksUtf16=(a,b)=>(w._paragraphBuilder_setWordBreaksUtf16=W.paragraphBuilder_setWordBreaksUtf16)(a,b);w._paragraphBuilder_setLineBreaksUtf16=(a,b)=>(w._paragraphBuilder_setLineBreaksUtf16=W.paragraphBuilder_setLineBreaksUtf16)(a,b);w._paragraphStyle_create=()=>(w._paragraphStyle_create=W.paragraphStyle_create)(); +w._paragraphStyle_dispose=a=>(w._paragraphStyle_dispose=W.paragraphStyle_dispose)(a);w._paragraphStyle_setTextAlign=(a,b)=>(w._paragraphStyle_setTextAlign=W.paragraphStyle_setTextAlign)(a,b);w._paragraphStyle_setTextDirection=(a,b)=>(w._paragraphStyle_setTextDirection=W.paragraphStyle_setTextDirection)(a,b);w._paragraphStyle_setMaxLines=(a,b)=>(w._paragraphStyle_setMaxLines=W.paragraphStyle_setMaxLines)(a,b); +w._paragraphStyle_setHeight=(a,b)=>(w._paragraphStyle_setHeight=W.paragraphStyle_setHeight)(a,b);w._paragraphStyle_setTextHeightBehavior=(a,b,c)=>(w._paragraphStyle_setTextHeightBehavior=W.paragraphStyle_setTextHeightBehavior)(a,b,c);w._paragraphStyle_setEllipsis=(a,b)=>(w._paragraphStyle_setEllipsis=W.paragraphStyle_setEllipsis)(a,b);w._paragraphStyle_setStrutStyle=(a,b)=>(w._paragraphStyle_setStrutStyle=W.paragraphStyle_setStrutStyle)(a,b); +w._paragraphStyle_setTextStyle=(a,b)=>(w._paragraphStyle_setTextStyle=W.paragraphStyle_setTextStyle)(a,b);w._paragraphStyle_setApplyRoundingHack=(a,b)=>(w._paragraphStyle_setApplyRoundingHack=W.paragraphStyle_setApplyRoundingHack)(a,b);w._strutStyle_create=()=>(w._strutStyle_create=W.strutStyle_create)();w._strutStyle_dispose=a=>(w._strutStyle_dispose=W.strutStyle_dispose)(a);w._strutStyle_setFontFamilies=(a,b,c)=>(w._strutStyle_setFontFamilies=W.strutStyle_setFontFamilies)(a,b,c); +w._strutStyle_setFontSize=(a,b)=>(w._strutStyle_setFontSize=W.strutStyle_setFontSize)(a,b);w._strutStyle_setHeight=(a,b)=>(w._strutStyle_setHeight=W.strutStyle_setHeight)(a,b);w._strutStyle_setHalfLeading=(a,b)=>(w._strutStyle_setHalfLeading=W.strutStyle_setHalfLeading)(a,b);w._strutStyle_setLeading=(a,b)=>(w._strutStyle_setLeading=W.strutStyle_setLeading)(a,b);w._strutStyle_setFontStyle=(a,b,c)=>(w._strutStyle_setFontStyle=W.strutStyle_setFontStyle)(a,b,c); +w._strutStyle_setForceStrutHeight=(a,b)=>(w._strutStyle_setForceStrutHeight=W.strutStyle_setForceStrutHeight)(a,b);w._textStyle_create=()=>(w._textStyle_create=W.textStyle_create)();w._textStyle_copy=a=>(w._textStyle_copy=W.textStyle_copy)(a);w._textStyle_dispose=a=>(w._textStyle_dispose=W.textStyle_dispose)(a);w._textStyle_setColor=(a,b)=>(w._textStyle_setColor=W.textStyle_setColor)(a,b);w._textStyle_setDecoration=(a,b)=>(w._textStyle_setDecoration=W.textStyle_setDecoration)(a,b); +w._textStyle_setDecorationColor=(a,b)=>(w._textStyle_setDecorationColor=W.textStyle_setDecorationColor)(a,b);w._textStyle_setDecorationStyle=(a,b)=>(w._textStyle_setDecorationStyle=W.textStyle_setDecorationStyle)(a,b);w._textStyle_setDecorationThickness=(a,b)=>(w._textStyle_setDecorationThickness=W.textStyle_setDecorationThickness)(a,b);w._textStyle_setFontStyle=(a,b,c)=>(w._textStyle_setFontStyle=W.textStyle_setFontStyle)(a,b,c); +w._textStyle_setTextBaseline=(a,b)=>(w._textStyle_setTextBaseline=W.textStyle_setTextBaseline)(a,b);w._textStyle_clearFontFamilies=a=>(w._textStyle_clearFontFamilies=W.textStyle_clearFontFamilies)(a);w._textStyle_addFontFamilies=(a,b,c)=>(w._textStyle_addFontFamilies=W.textStyle_addFontFamilies)(a,b,c);w._textStyle_setFontSize=(a,b)=>(w._textStyle_setFontSize=W.textStyle_setFontSize)(a,b);w._textStyle_setLetterSpacing=(a,b)=>(w._textStyle_setLetterSpacing=W.textStyle_setLetterSpacing)(a,b); +w._textStyle_setWordSpacing=(a,b)=>(w._textStyle_setWordSpacing=W.textStyle_setWordSpacing)(a,b);w._textStyle_setHeight=(a,b)=>(w._textStyle_setHeight=W.textStyle_setHeight)(a,b);w._textStyle_setHalfLeading=(a,b)=>(w._textStyle_setHalfLeading=W.textStyle_setHalfLeading)(a,b);w._textStyle_setLocale=(a,b)=>(w._textStyle_setLocale=W.textStyle_setLocale)(a,b);w._textStyle_setBackground=(a,b)=>(w._textStyle_setBackground=W.textStyle_setBackground)(a,b); +w._textStyle_setForeground=(a,b)=>(w._textStyle_setForeground=W.textStyle_setForeground)(a,b);w._textStyle_addShadow=(a,b,c,e,f)=>(w._textStyle_addShadow=W.textStyle_addShadow)(a,b,c,e,f);w._textStyle_addFontFeature=(a,b,c)=>(w._textStyle_addFontFeature=W.textStyle_addFontFeature)(a,b,c);w._textStyle_setFontVariations=(a,b,c,e)=>(w._textStyle_setFontVariations=W.textStyle_setFontVariations)(a,b,c,e);w._vertices_create=(a,b,c,e,f,h,l)=>(w._vertices_create=W.vertices_create)(a,b,c,e,f,h,l); +w._vertices_dispose=a=>(w._vertices_dispose=W.vertices_dispose)(a);w._skwasm_isMultiThreaded=()=>(w._skwasm_isMultiThreaded=W.skwasm_isMultiThreaded)();var qb=a=>(qb=W.malloc)(a),ac=(a,b)=>(ac=W._emscripten_timeout)(a,b),X=(a,b)=>(X=W.setThrew)(a,b),Y=a=>(Y=W._emscripten_stack_restore)(a),Sb=a=>(Sb=W._emscripten_stack_alloc)(a),Z=()=>(Z=W.emscripten_stack_get_current)();function cc(a,b,c){var e=Z();try{return S.get(a)(b,c)}catch(f){Y(e);if(f!==f+0)throw f;X(1,0)}} +function hc(a,b,c){var e=Z();try{S.get(a)(b,c)}catch(f){Y(e);if(f!==f+0)throw f;X(1,0)}}function bc(a,b){var c=Z();try{return S.get(a)(b)}catch(e){Y(c);if(e!==e+0)throw e;X(1,0)}}function ic(a,b,c,e){var f=Z();try{S.get(a)(b,c,e)}catch(h){Y(f);if(h!==h+0)throw h;X(1,0)}}function dc(a,b,c,e){var f=Z();try{return S.get(a)(b,c,e)}catch(h){Y(f);if(h!==h+0)throw h;X(1,0)}}function jc(a,b,c,e,f){var h=Z();try{S.get(a)(b,c,e,f)}catch(l){Y(h);if(l!==l+0)throw l;X(1,0)}} +function kc(a,b,c,e,f,h,l,m){var p=Z();try{S.get(a)(b,c,e,f,h,l,m)}catch(v){Y(p);if(v!==v+0)throw v;X(1,0)}}function gc(a,b){var c=Z();try{S.get(a)(b)}catch(e){Y(c);if(e!==e+0)throw e;X(1,0)}}function fc(a,b,c,e,f,h,l){var m=Z();try{return S.get(a)(b,c,e,f,h,l)}catch(p){Y(m);if(p!==p+0)throw p;X(1,0)}}function ec(a,b,c,e,f){var h=Z();try{return S.get(a)(b,c,e,f)}catch(l){Y(h);if(l!==l+0)throw l;X(1,0)}}w.wasmMemory=g;w.wasmExports=W;w.stackAlloc=Tb; +w.addFunction=(a,b)=>{if(!U){U=new WeakMap;var c=S.length;if(U)for(var e=0;e<0+c;e++){var f=S.get(e);f&&U.set(f,e)}}if(c=U.get(a)||0)return c;if(Rb.length)c=Rb.pop();else{try{S.grow(1)}catch(m){if(!(m instanceof RangeError))throw m;throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH.";}c=S.length-1}try{S.set(c,a)}catch(m){if(!(m instanceof TypeError))throw m;if("function"==typeof WebAssembly.Function){e=WebAssembly.Function;f={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",p:"i32"};for(var h={parameters:[], +results:"v"==b[0]?[]:[f[b[0]]]},l=1;ll?e.push(l):e.push(l%128|128,l>>7);for(l=0;lf?b.push(f):b.push(f%128|128,f>>7);b.push(...e);b.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);b=new WebAssembly.Module(new Uint8Array(b));b=(new WebAssembly.Instance(b, +{e:{f:a}})).exports.f}S.set(c,b)}U.set(a,c);return c};var mc,nc;A=function oc(){mc||pc();mc||(A=oc)};function pc(){if(!(0\2c\20std::__2::allocator>::~basic_string\28\29 +210:emscripten_builtin_free +211:sk_sp::~sk_sp\28\29 +212:operator\20new\28unsigned\20long\29 +213:GrGLSLShaderBuilder::codeAppendf\28char\20const*\2c\20...\29 +214:sk_sp::~sk_sp\28\29 +215:void\20SkSafeUnref\28GrContextThreadSafeProxy*\29 +216:void\20SkSafeUnref\28SkImageFilter*\29\20\28.2095\29 +217:operator\20delete\28void*\29 +218:SkRasterPipeline::uncheckedAppend\28SkRasterPipelineOp\2c\20void*\29 +219:void\20SkSafeUnref\28SkString::Rec*\29 +220:GrGLSLShaderBuilder::codeAppend\28char\20const*\29 +221:SkSL::GLSLCodeGenerator::write\28std::__2::basic_string_view>\29 +222:SkSL::ErrorReporter::error\28SkSL::Position\2c\20std::__2::basic_string_view>\29 +223:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>&&\2c\20char\20const*\29 +224:hb_blob_destroy +225:SkImageGenerator::onIsProtected\28\29\20const +226:SkDebugf\28char\20const*\2c\20...\29 +227:fmaxf +228:skia_private::TArray::~TArray\28\29 +229:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>&&\29 +230:std::__2::basic_string\2c\20std::__2::allocator>::size\5babi:nn180100\5d\28\29\20const +231:std::__2::__function::__value_func::~__value_func\5babi:ne180100\5d\28\29 +232:void\20SkSafeUnref\28SkPathRef*\29 +233:hb_sanitize_context_t::check_range\28void\20const*\2c\20unsigned\20int\29\20const +234:GrShaderVar::~GrShaderVar\28\29 +235:__unlockfile +236:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>&&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&&\29 +237:GrColorInfo::~GrColorInfo\28\29 +238:hb_buffer_t::message\28hb_font_t*\2c\20char\20const*\2c\20...\29 +239:__wasm_setjmp_test +240:SkArenaAlloc::allocObject\28unsigned\20int\2c\20unsigned\20int\29 +241:std::__2::basic_string\2c\20std::__2::allocator>::basic_string>\2c\200>\28std::__2::basic_string_view>\20const&\29 +242:fminf +243:SkPaint::~SkPaint\28\29 +244:FT_DivFix +245:std::exception::~exception\28\29 +246:strlen +247:SkMutex::release\28\29 +248:skvx::Vec<4\2c\20float>\20skvx::naive_if_then_else<4\2c\20float>\28skvx::Vec<4\2c\20skvx::Mask::type>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.5831\29 +249:SkPath::SkPath\28\29 +250:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:ne180100\5d<0>\28char\20const*\29 +251:skia_private::TArray>\2c\20true>::~TArray\28\29 +252:skia_png_crc_finish +253:skia_png_chunk_benign_error +254:ft_mem_realloc +255:hb_buffer_t::next_glyph\28\29 +256:SkSL::RP::Generator::pushExpression\28SkSL::Expression\20const&\2c\20bool\29 +257:sk_sp::reset\28SkFontStyleSet*\29 +258:SkSL::RP::Builder::appendInstruction\28SkSL::RP::BuilderOp\2c\20SkSL::RP::Builder::SlotList\2c\20int\2c\20int\2c\20int\2c\20int\29 +259:SkSL::Pool::AllocMemory\28unsigned\20long\29 +260:SkBitmap::~SkBitmap\28\29 +261:sk_report_container_overflow_and_die\28\29 +262:SkMatrix::hasPerspective\28\29\20const +263:SkSemaphore::wait\28\29 +264:skgpu::ganesh::VertexChunkPatchAllocator::append\28skgpu::tess::LinearTolerances\20const&\29 +265:SkWriter32::write32\28int\29 +266:SkString::appendf\28char\20const*\2c\20...\29 +267:skgpu::VertexWriter&\20skgpu::tess::operator<<<\28skgpu::tess::PatchAttribs\298\2c\20skgpu::VertexColor\2c\20false\2c\20true>\28skgpu::VertexWriter&\2c\20skgpu::tess::AttribValue<\28skgpu::tess::PatchAttribs\298\2c\20skgpu::VertexColor\2c\20false\2c\20true>\20const&\29 +268:SkContainerAllocator::allocate\28int\2c\20double\29 +269:FT_Stream_Seek +270:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +271:\28anonymous\20namespace\29::ColorTypeFilter_F16F16::Expand\28unsigned\20int\29 +272:FT_MulDiv +273:std::__2::basic_string\2c\20std::__2::allocator>::append\5babi:ne180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +274:SkString::append\28char\20const*\29 +275:SkArenaAlloc::allocObjectWithFooter\28unsigned\20int\2c\20unsigned\20int\29 +276:OT::VarStoreInstancer::operator\28\29\28unsigned\20int\2c\20unsigned\20short\29\20const +277:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +278:SkIRect::intersect\28SkIRect\20const&\29 +279:skia_png_free +280:lang_matches\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20int\29 +281:ft_mem_qrealloc +282:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +283:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\29 +284:SkSL::Parser::expect\28SkSL::Token::Kind\2c\20char\20const*\2c\20SkSL::Token*\29 +285:SkIntersections::insert\28double\2c\20double\2c\20SkDPoint\20const&\29 +286:SkMatrix::invert\28SkMatrix*\29\20const +287:FT_Stream_ReadUShort +288:skia_private::TArray::push_back\28SkSL::RP::Program::Stage&&\29 +289:sk_sp::~sk_sp\28\29 +290:std::__2::basic_string\2c\20std::__2::allocator>::resize\5babi:nn180100\5d\28unsigned\20long\29 +291:sk_sp::~sk_sp\28\29 +292:cf2_stack_popFixed +293:__lockfile +294:strcmp +295:SkIRect::isEmpty\28\29\20const +296:SkBitmap::SkBitmap\28\29 +297:subtag_matches\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20int\29 +298:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +299:cf2_stack_getReal +300:SkSL::GLSLCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +301:emscripten_builtin_malloc +302:SkSL::Type::displayName\28\29\20const +303:SkPathRef::getBounds\28\29\20const +304:SkImageGenerator::onGetYUVAPlanes\28SkYUVAPixmaps\20const&\29 +305:void\20SkSafeUnref\28SkColorSpace*\29\20\28.2052\29 +306:emscripten_builtin_calloc +307:GrAuditTrail::pushFrame\28char\20const*\29 +308:std::__2::locale::~locale\28\29 +309:std::__2::vector\2c\20std::__2::allocator>>::__throw_length_error\5babi:ne180100\5d\28\29\20const +310:skif::FilterResult::~FilterResult\28\29 +311:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrShaderCaps*\29 +312:hb_vector_t::fini\28\29 +313:SkPaint::SkPaint\28SkPaint\20const&\29 +314:SkString::SkString\28SkString&&\29 +315:GrGeometryProcessor::Attribute::asShaderVar\28\29\20const +316:sk_sp::reset\28SkImageFilter*\29 +317:SkBlitter::~SkBlitter\28\29_1495 +318:std::__2::to_string\28int\29 +319:SkTDStorage::~SkTDStorage\28\29 +320:SkSL::Parser::peek\28\29 +321:std::__2::ios_base::getloc\28\29\20const +322:hb_ot_map_builder_t::add_feature\28unsigned\20int\2c\20hb_ot_map_feature_flags_t\2c\20unsigned\20int\29 +323:SkWStream::writeText\28char\20const*\29 +324:void\20SkSafeUnref\28SkData\20const*\29\20\28.1178\29 +325:std::__2::__compressed_pair\2c\20std::__2::allocator>::__rep\2c\20std::__2::allocator>::__compressed_pair\5babi:nn180100\5d\28std::__2::__value_init_tag&&\2c\20std::__2::__default_init_tag&&\29 +326:GrProcessor::operator\20new\28unsigned\20long\29 +327:GrPixmapBase::~GrPixmapBase\28\29 +328:GrGLSLUniformHandler::addUniform\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20char\20const**\29 +329:GrGLContextInfo::hasExtension\28char\20const*\29\20const +330:skgpu::Swizzle::Swizzle\28char\20const*\29 +331:hb_face_t::get_num_glyphs\28\29\20const +332:SkString::~SkString\28\29 +333:GrSurfaceProxyView::operator=\28GrSurfaceProxyView&&\29 +334:GrPaint::~GrPaint\28\29 +335:std::__2::unique_ptr>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +336:std::__2::basic_string\2c\20std::__2::allocator>::__get_pointer\5babi:nn180100\5d\28\29 +337:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +338:SkIRect::contains\28SkIRect\20const&\29\20const +339:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +340:skvx::Vec<8\2c\20unsigned\20short>&\20skvx::operator+=<8\2c\20unsigned\20short>\28skvx::Vec<8\2c\20unsigned\20short>&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +341:memcmp +342:SkArenaAlloc::RunDtorsOnBlock\28char*\29 +343:std::__2::shared_ptr<_IO_FILE>::~shared_ptr\5babi:ne180100\5d\28\29 +344:skia_png_warning +345:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +346:SkString::SkString\28char\20const*\29 +347:hb_sanitize_context_t::start_processing\28\29 +348:__shgetc +349:SkMakeRuntimeEffect\28SkRuntimeEffect::Result\20\28*\29\28SkString\2c\20SkRuntimeEffect::Options\20const&\29\2c\20char\20const*\2c\20SkRuntimeEffect::Options\29 +350:FT_Stream_GetUShort +351:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28wchar_t\20const*\29 +352:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28char\20const*\29 +353:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +354:skia_private::TArray>\2c\20true>::push_back\28std::__2::unique_ptr>&&\29 +355:hb_sanitize_context_t::~hb_sanitize_context_t\28\29 +356:bool\20std::__2::operator==\5babi:nn180100\5d>\28std::__2::istreambuf_iterator>\20const&\2c\20std::__2::istreambuf_iterator>\20const&\29 +357:SkMatrix::mapRect\28SkRect*\2c\20SkRect\20const&\2c\20SkApplyPerspectiveClip\29\20const +358:skia_private::AutoSTMalloc<17ul\2c\20SkPoint\2c\20void>::~AutoSTMalloc\28\29 +359:hb_lazy_loader_t\2c\20hb_face_t\2c\2033u\2c\20hb_blob_t>::do_destroy\28hb_blob_t*\29 +360:SkDQuad::set\28SkPoint\20const*\29 +361:FT_Stream_ExitFrame +362:skia::textlayout::ParagraphImpl::getUTF16Index\28unsigned\20long\29\20const +363:SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29::operator\28\29\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29\20const +364:SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0::operator\28\29\28SkSL::FunctionDefinition\20const*\2c\20SkSL::FunctionDefinition\20const*\29\20const +365:SkSL::Expression::clone\28\29\20const +366:SkMatrix::SkMatrix\28\29 +367:skif::FilterResult::FilterResult\28\29 +368:std::__throw_bad_array_new_length\5babi:ne180100\5d\28\29 +369:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +370:std::__2::unique_ptr::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +371:skvx::Vec<4\2c\20int>\20skvx::operator&<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +372:skia_png_error +373:hb_face_reference_table +374:SkPixmap::SkPixmap\28\29 +375:SkPath::SkPath\28SkPath\20const&\29 +376:skgpu::ganesh::SurfaceDrawContext::addDrawOp\28GrClip\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::function\20const&\29 +377:sk_sp::~sk_sp\28\29 +378:hb_buffer_t::unsafe_to_break\28unsigned\20int\2c\20unsigned\20int\29 +379:\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16::Expand\28unsigned\20long\20long\29 +380:\28anonymous\20namespace\29::ColorTypeFilter_8888::Expand\28unsigned\20int\29 +381:\28anonymous\20namespace\29::ColorTypeFilter_16161616::Expand\28unsigned\20long\20long\29 +382:\28anonymous\20namespace\29::ColorTypeFilter_1010102::Expand\28unsigned\20long\20long\29 +383:SkStringPrintf\28char\20const*\2c\20...\29 +384:SkRecord::grow\28\29 +385:SkPictureRecord::addDraw\28DrawType\2c\20unsigned\20long*\29 +386:OT::Layout::Common::Coverage::get_coverage\28unsigned\20int\29\20const +387:strstr +388:std::__2::__cloc\28\29 +389:sscanf +390:skvx::Vec<4\2c\20int>\20skvx::operator!<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\29 +391:SkRect::intersect\28SkRect\20const&\29 +392:SkImageGenerator::onQueryYUVAInfo\28SkYUVAPixmapInfo::SupportedDataTypes\20const&\2c\20SkYUVAPixmapInfo*\29\20const +393:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +394:skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>::STArray\28skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&&\29 +395:skia_png_chunk_error +396:hb_blob_get_data_writable +397:ft_mem_alloc +398:bool\20hb_sanitize_context_t::check_range>\28OT::IntType\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +399:__multf3 +400:SkSL::GLSLCodeGenerator::writeLine\28std::__2::basic_string_view>\29 +401:SkRect::outset\28float\2c\20float\29 +402:SkMatrix::mapPoints\28SkPoint*\2c\20int\29\20const +403:SkMatrix::getType\28\29\20const +404:FT_Stream_EnterFrame +405:std::__2::unique_ptr>\20SkSL::evaluate_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +406:std::__2::basic_string_view>::compare\28std::__2::basic_string_view>\29\20const +407:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20char\20const*\29 +408:skia_private::THashTable>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair\2c\20std::__2::unique_ptr>*\2c\20skia_private::THashMap>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair>::Hash\28std::__2::unique_ptr>*\20const&\29 +409:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +410:sk_malloc_throw\28unsigned\20long\2c\20unsigned\20long\29 +411:SkSL::String::printf\28char\20const*\2c\20...\29 +412:SkNullBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +413:SkIRect::Intersects\28SkIRect\20const&\2c\20SkIRect\20const&\29 +414:SkArenaAlloc::makeBytesAlignedTo\28unsigned\20long\2c\20unsigned\20long\29 +415:GrGLSLVaryingHandler::addVarying\28char\20const*\2c\20GrGLSLVarying*\2c\20GrGLSLVaryingHandler::Interpolation\29 +416:GrBackendFormats::AsGLFormat\28GrBackendFormat\20const&\29 +417:std::__2::locale::id::__get\28\29 +418:std::__2::locale::facet::facet\5babi:nn180100\5d\28unsigned\20long\29 +419:skgpu::UniqueKey::~UniqueKey\28\29 +420:SkString::operator=\28char\20const*\29 +421:SkRect::setBoundsCheck\28SkPoint\20const*\2c\20int\29 +422:SkDPoint::approximatelyEqual\28SkDPoint\20const&\29\20const +423:SkChecksum::Hash32\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20int\29 +424:GrProcessorSet::GrProcessorSet\28GrPaint&&\29 +425:GrOpFlushState::bindPipelineAndScissorClip\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +426:GrGLExtensions::has\28char\20const*\29\20const +427:strncmp +428:std::__2::locale::__imp::install\28std::__2::locale::facet*\2c\20long\29 +429:skia_png_muldiv +430:f_t_mutex\28\29 +431:SkTDStorage::reserve\28int\29 +432:SkSL::RP::Builder::discard_stack\28int\29 +433:SkSL::Pool::FreeMemory\28void*\29 +434:GrStyledShape::~GrStyledShape\28\29 +435:GrOp::~GrOp\28\29 +436:GrGeometryProcessor::AttributeSet::initImplicit\28GrGeometryProcessor::Attribute\20const*\2c\20int\29 +437:void\20SkSafeUnref\28GrSurface*\29 +438:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +439:sk_sp::~sk_sp\28\29 +440:hb_buffer_t::unsafe_to_concat\28unsigned\20int\2c\20unsigned\20int\29 +441:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +442:SkSL::PipelineStage::PipelineStageCodeGenerator::writeExpression\28SkSL::Expression\20const&\2c\20SkSL::OperatorPrecedence\29 +443:SkRegion::freeRuns\28\29 +444:SkRect::roundOut\28\29\20const +445:SkRect::contains\28SkRect\20const&\29\20const +446:SkPoint::length\28\29\20const +447:SkPath::~SkPath\28\29 +448:SkPath::lineTo\28SkPoint\20const&\29 +449:SkMatrix::mapPoints\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +450:GrOp::GenID\28std::__2::atomic*\29 +451:textStyle_setDecoration +452:std::__2::unique_ptr::~unique_ptr\5babi:nn180100\5d\28\29 +453:std::__2::enable_if::value\20&&\20sizeof\20\28unsigned\20int\29\20==\204\2c\20unsigned\20int>::type\20SkGoodHash::operator\28\29\28unsigned\20int\20const&\29\20const +454:skvx::Vec<8\2c\20unsigned\20short>\20skvx::mulhi<8>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +455:hb_ot_map_builder_t::add_gsub_pause\28bool\20\28*\29\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29\29 +456:cf2_stack_pushFixed +457:SkSL::RP::Builder::binary_op\28SkSL::RP::BuilderOp\2c\20int\29 +458:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20SkFilterMode\2c\20SkMipmapMode\29 +459:GrShaderVar::GrShaderVar\28char\20const*\2c\20SkSLType\2c\20int\29 +460:GrProcessor::operator\20new\28unsigned\20long\2c\20unsigned\20long\29 +461:GrImageInfo::GrImageInfo\28GrImageInfo&&\29 +462:GrGLSLVaryingHandler::addPassThroughAttribute\28GrShaderVar\20const&\2c\20char\20const*\2c\20GrGLSLVaryingHandler::Interpolation\29 +463:GrFragmentProcessor::registerChild\28std::__2::unique_ptr>\2c\20SkSL::SampleUsage\29 +464:255 +465:std::__2::istreambuf_iterator>::operator*\5babi:nn180100\5d\28\29\20const +466:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +467:std::__2::__split_buffer&>::~__split_buffer\28\29 +468:hb_buffer_t::merge_clusters\28unsigned\20int\2c\20unsigned\20int\29 +469:SkSL::SymbolTable::addWithoutOwnershipOrDie\28SkSL::Symbol*\29 +470:SkSL::Nop::~Nop\28\29 +471:SkRecords::FillBounds::updateSaveBounds\28SkRect\20const&\29 +472:SkPoint::normalize\28\29 +473:SkMatrix::mapRect\28SkRect\20const&\2c\20SkApplyPerspectiveClip\29\20const +474:SkMatrix::isIdentity\28\29\20const +475:SkJSONWriter::write\28char\20const*\2c\20unsigned\20long\29 +476:SkJSONWriter::appendBool\28char\20const*\2c\20bool\29 +477:GrSkSLFP::UniformPayloadSize\28SkRuntimeEffect\20const*\29 +478:GrSkSLFP::GrSkSLFP\28sk_sp\2c\20char\20const*\2c\20GrSkSLFP::OptFlags\29 +479:std::__2::unique_ptr::unique_ptr\5babi:nn180100\5d\28char*\2c\20std::__2::__dependent_type\2c\20true>::__good_rval_ref_type\29 +480:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +481:std::__2::__throw_bad_function_call\5babi:ne180100\5d\28\29 +482:skia_private::TArray::push_back_raw\28int\29 +483:skgpu::UniqueKey::UniqueKey\28\29 +484:sk_sp::reset\28GrSurface*\29 +485:sk_sp::~sk_sp\28\29 +486:abort +487:__multi3 +488:SkTDArray::push_back\28SkPoint\20const&\29 +489:SkStrokeRec::getStyle\28\29\20const +490:SkSL::fold_expression\28SkSL::Position\2c\20double\2c\20SkSL::Type\20const*\29 +491:SkSL::Type::MakeAliasType\28std::__2::basic_string_view>\2c\20SkSL::Type\20const&\29 +492:GrTriangulator::Comparator::sweep_lt\28SkPoint\20const&\2c\20SkPoint\20const&\29\20const +493:CFF::arg_stack_t::pop_uint\28\29 +494:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +495:skia_png_crc_read +496:hb_draw_funcs_t::start_path\28void*\2c\20hb_draw_state_t&\29 +497:dlrealloc +498:SkSpinlock::acquire\28\29 +499:SkSL::Parser::rangeFrom\28SkSL::Position\29 +500:SkSL::Parser::checkNext\28SkSL::Token::Kind\2c\20SkSL::Token*\29 +501:SkMatrix::postTranslate\28float\2c\20float\29 +502:SkMatrix::isScaleTranslate\28\29\20const +503:SkMatrix::Concat\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +504:GrOpFlushState::bindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +505:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28char\29 +506:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +507:std::__2::__throw_system_error\28int\2c\20char\20const*\29 +508:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +509:sk_malloc_flags\28unsigned\20long\2c\20unsigned\20int\29 +510:hb_paint_funcs_t::pop_transform\28void*\29 +511:fma +512:SkTDStorage::append\28\29 +513:SkTDArray::append\28\29 +514:SkSL::RP::Builder::lastInstruction\28int\29 +515:SkPath::lineTo\28float\2c\20float\29 +516:SkMatrix::rectStaysRect\28\29\20const +517:SkMatrix::mapRect\28SkRect*\2c\20SkApplyPerspectiveClip\29\20const +518:OT::ArrayOf\2c\20OT::IntType>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +519:hb_draw_funcs_t::emit_line_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\29 +520:hb_buffer_t::reverse\28\29 +521:SkString::operator=\28SkString\20const&\29 +522:SkStrikeSpec::~SkStrikeSpec\28\29 +523:SkSL::Type::toCompound\28SkSL::Context\20const&\2c\20int\2c\20int\29\20const +524:SkSL::RP::Generator::binaryOp\28SkSL::Type\20const&\2c\20SkSL::RP::Generator::TypedOps\20const&\29 +525:SkRecords::FillBounds::adjustAndMap\28SkRect\2c\20SkPaint\20const*\29\20const +526:SkPath::operator=\28SkPath\20const&\29 +527:SkMatrix::preConcat\28SkMatrix\20const&\29 +528:SkMatrix::Translate\28float\2c\20float\29 +529:SkDCubic::set\28SkPoint\20const*\29 +530:SkColorSpaceXformSteps::SkColorSpaceXformSteps\28SkColorSpace\20const*\2c\20SkAlphaType\2c\20SkColorSpace\20const*\2c\20SkAlphaType\29 +531:GrStyle::isSimpleFill\28\29\20const +532:GrGLSLVaryingHandler::emitAttributes\28GrGeometryProcessor\20const&\29 +533:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::setIndices\28\29 +534:std::__2::unique_ptr::reset\5babi:nn180100\5d\28unsigned\20char*\29 +535:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +536:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +537:std::__2::__unique_if::__unique_array_unknown_bound\20std::__2::make_unique\5babi:ne180100\5d\28unsigned\20long\29 +538:skvx::Vec<8\2c\20unsigned\20short>\20skvx::operator+<8\2c\20unsigned\20short>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +539:skif::FilterResult::operator=\28skif::FilterResult&&\29 +540:skgpu::VertexColor::set\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\29 +541:skgpu::ResourceKey::Builder::finish\28\29 +542:sk_sp::~sk_sp\28\29 +543:ft_validator_error +544:SkSL::Parser::error\28SkSL::Token\2c\20std::__2::basic_string_view>\29 +545:SkSL::ConstantFolder::GetConstantValueForVariable\28SkSL::Expression\20const&\29 +546:SkPictureRecord::addPaintPtr\28SkPaint\20const*\29 +547:SkPath::reset\28\29 +548:SkPath::Iter::next\28SkPoint*\29 +549:SkGlyph::rowBytes\28\29\20const +550:GrSurfaceProxy::backingStoreDimensions\28\29\20const +551:GrProgramInfo::visitFPProxies\28std::__2::function\20const&\29\20const +552:GrMeshDrawOp::createProgramInfo\28GrMeshDrawTarget*\29 +553:GrGpu::handleDirtyContext\28\29 +554:FT_Stream_ReadFields +555:FT_Stream_ReadByte +556:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28\29 +557:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_size\5babi:nn180100\5d\28unsigned\20long\29 +558:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +559:skvx::Vec<4\2c\20float>\20\28anonymous\20namespace\29::add_121>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +560:skia_private::TArray::Allocate\28int\2c\20double\29 +561:skia_private::TArray\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +562:sk_srgb_singleton\28\29 +563:machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>::operator=\28machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\20const&\29 +564:SkWriter32::reserve\28unsigned\20long\29 +565:SkTSect::pointLast\28\29\20const +566:SkStrokeRec::isHairlineStyle\28\29\20const +567:SkSL::Type::MakeVectorType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\29 +568:SkRect::join\28SkRect\20const&\29 +569:SkMatrix::Scale\28float\2c\20float\29 +570:SkColorSpace::MakeSRGB\28\29 +571:FT_Stream_GetULong +572:target_from_texture_type\28GrTextureType\29 +573:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +574:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +575:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator+<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +576:skvx::Vec<4\2c\20unsigned\20int>\20skvx::operator+<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +577:skif::Context::~Context\28\29 +578:skia::textlayout::TextStyle::~TextStyle\28\29 +579:skia::textlayout::TextStyle::TextStyle\28skia::textlayout::TextStyle\20const&\29 +580:skia::textlayout::OneLineShaper::RunBlock::operator=\28skia::textlayout::OneLineShaper::RunBlock&&\29 +581:png_icc_profile_error +582:hb_font_t::get_nominal_glyph\28unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\29 +583:_hb_next_syllable\28hb_buffer_t*\2c\20unsigned\20int\29 +584:__cxa_guard_release +585:__cxa_guard_acquire +586:SkSL::TProgramVisitor::visitStatement\28SkSL::Statement\20const&\29 +587:SkSL::RP::Program::makeStages\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSpan\2c\20SkSL::RP::Program::SlotData\20const&\29\20const::$_2::operator\28\29\28\29\20const +588:SkSL::ConstructorCompound::MakeFromConstants\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20double\20const*\29 +589:SkRect::roundOut\28SkIRect*\29\20const +590:SkPathPriv::Iterate::Iterate\28SkPath\20const&\29 +591:SkPath::moveTo\28SkPoint\20const&\29 +592:SkPaint::setBlendMode\28SkBlendMode\29 +593:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_2::operator\28\29\28SkRasterPipelineOp\2c\20SkRasterPipelineOp\2c\20\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +594:SkDCubic::ptAtT\28double\29\20const +595:SkBitmap::SkBitmap\28SkBitmap\20const&\29 +596:OT::OffsetTo\2c\20OT::IntType\2c\20true>::operator\28\29\28void\20const*\29\20const +597:GrFragmentProcessor::ProgramImpl::invokeChild\28int\2c\20GrFragmentProcessor::ProgramImpl::EmitArgs&\2c\20std::__2::basic_string_view>\29 +598:GrCaps::getDefaultBackendFormat\28GrColorType\2c\20skgpu::Renderable\29\20const +599:FT_Stream_ReleaseFrame +600:DefaultGeoProc::Impl::~Impl\28\29 +601:392 +602:void\20std::__2::unique_ptr>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot*\2c\200>\28skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::Slot*\29 +603:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:nn180100\5d\28\29\20const +604:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +605:out +606:cosf +607:cf2_stack_popInt +608:SkSL::Type::coerceExpression\28std::__2::unique_ptr>\2c\20SkSL::Context\20const&\29\20const +609:SkSL::Type::MakeGenericType\28char\20const*\2c\20SkSpan\2c\20SkSL::Type\20const*\29 +610:SkSL::RP::SlotManager::getVariableSlots\28SkSL::Variable\20const&\29 +611:SkRGBA4f<\28SkAlphaType\292>::operator!=\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +612:SkPathStroker::lineTo\28SkPoint\20const&\2c\20SkPath::Iter\20const*\29 +613:SkPath::conicTo\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\29 +614:SkPath::Iter::setPath\28SkPath\20const&\2c\20bool\29 +615:SkPaint::setColor\28unsigned\20int\29 +616:SkImageInfo::minRowBytes\28\29\20const +617:GrShaderVar::operator=\28GrShaderVar&&\29 +618:GrProcessor::operator\20delete\28void*\29 +619:GrImageInfo::GrImageInfo\28SkImageInfo\20const&\29 +620:GrColorInfo::GrColorInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\29 +621:FT_Outline_Translate +622:std::__2::char_traits::assign\5babi:nn180100\5d\28char&\2c\20char\20const&\29 +623:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +624:std::__2::__check_grouping\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int&\29 +625:skvx::Vec<4\2c\20int>\20skvx::operator|<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +626:skia_private::THashMap::find\28SkSL::FunctionDeclaration\20const*\20const&\29\20const +627:pad +628:ft_mem_qalloc +629:__ashlti3 +630:SkTCoincident::setPerp\28SkTCurve\20const&\2c\20double\2c\20SkDPoint\20const&\2c\20SkTCurve\20const&\29 +631:SkSL::Type::MakeMatrixType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type\20const&\2c\20int\2c\20signed\20char\29 +632:SkSL::TProgramVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +633:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression\20const&\29 +634:SkSL::Parser::nextToken\28\29 +635:SkSL::Operator::tightOperatorName\28\29\20const +636:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29::$_0::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +637:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29 +638:SkMatrix::postConcat\28SkMatrix\20const&\29 +639:SkDrawBase::~SkDrawBase\28\29 +640:SkDVector::crossCheck\28SkDVector\20const&\29\20const +641:SkCanvas::internalQuickReject\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\29 +642:SkBlitter::~SkBlitter\28\29 +643:SkBitmapDevice::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +644:GrStyle::~GrStyle\28\29 +645:GrSimpleMeshDrawOpHelper::~GrSimpleMeshDrawOpHelper\28\29 +646:GrSimpleMeshDrawOpHelper::visitProxies\28std::__2::function\20const&\29\20const +647:GrShape::reset\28\29 +648:GrShape::bounds\28\29\20const +649:GrShaderVar::appendDecl\28GrShaderCaps\20const*\2c\20SkString*\29\20const +650:GrQuad::MakeFromRect\28SkRect\20const&\2c\20SkMatrix\20const&\29 +651:GrOpFlushState::drawMesh\28GrSimpleMesh\20const&\29 +652:GrAAConvexTessellator::Ring::index\28int\29\20const +653:DefaultGeoProc::~DefaultGeoProc\28\29 +654:445 +655:std::__2::vector\2c\20std::__2::allocator>>::~vector\5babi:ne180100\5d\28\29 +656:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock&\2c\20skia::textlayout::OneLineShaper::RunBlock&\29 +657:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +658:std::__2::basic_string\2c\20std::__2::allocator>::__set_short_size\5babi:nn180100\5d\28unsigned\20long\29 +659:std::__2::__compressed_pair_elem::__compressed_pair_elem\5babi:nn180100\5d\28void\20\28*&&\29\28void*\29\29 +660:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29\20\28.6972\29 +661:skia_png_chunk_report +662:skgpu::ResourceKey::operator==\28skgpu::ResourceKey\20const&\29\20const +663:sk_sp::~sk_sp\28\29 +664:hb_buffer_t::unsafe_to_break_from_outbuffer\28unsigned\20int\2c\20unsigned\20int\29 +665:cff2_path_procs_extents_t::curve\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +666:cff2_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +667:cff1_path_procs_extents_t::curve\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +668:cff1_path_param_t::cubic_to\28CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +669:_hb_glyph_info_get_modified_combining_class\28hb_glyph_info_t\20const*\29 +670:SkTDArray::push_back\28unsigned\20int\20const&\29 +671:SkString::data\28\29 +672:SkSemaphore::~SkSemaphore\28\29 +673:SkSL::FunctionDeclaration::description\28\29\20const +674:SkRasterPipeline::extend\28SkRasterPipeline\20const&\29 +675:SkPixmap::operator=\28SkPixmap\20const&\29 +676:SkPath::close\28\29 +677:SkPath::RangeIter::operator++\28\29 +678:SkOpPtT::contains\28SkOpPtT\20const*\29\20const +679:SkNullBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +680:SkMatrixPriv::CheapEqual\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +681:SkIRect::intersect\28SkIRect\20const&\2c\20SkIRect\20const&\29 +682:SkColorSpaceXformSteps::apply\28float*\29\20const +683:SkAAClipBlitterWrapper::~SkAAClipBlitterWrapper\28\29 +684:OT::hb_paint_context_t::recurse\28OT::Paint\20const&\29 +685:OT::hb_ot_apply_context_t::init_iters\28\29 +686:GrTextureProxy::mipmapped\28\29\20const +687:GrStyledShape::asPath\28SkPath*\29\20const +688:GrShaderVar::GrShaderVar\28char\20const*\2c\20SkSLType\2c\20GrShaderVar::TypeModifier\29 +689:GrMatrixEffect::Make\28SkMatrix\20const&\2c\20std::__2::unique_ptr>\29 +690:GrGLGpu::setTextureUnit\28int\29 +691:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::~Impl\28\29 +692:GrCPixmap::GrCPixmap\28GrImageInfo\2c\20void\20const*\2c\20unsigned\20long\29 +693:GrAppliedClip::~GrAppliedClip\28\29 +694:FT_Stream_ReadULong +695:FT_Load_Glyph +696:CFF::cff_stack_t::pop\28\29 +697:void\20SkOnce::operator\28\29*\29\2c\20SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*>\28void\20\28&\29\28SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*\29\2c\20SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*&&\29 +698:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +699:std::__2::numpunct::thousands_sep\5babi:nn180100\5d\28\29\20const +700:std::__2::numpunct::grouping\5babi:nn180100\5d\28\29\20const +701:std::__2::ctype\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +702:std::__2::__throw_bad_optional_access\5babi:ne180100\5d\28\29 +703:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +704:skif::Context::Context\28skif::Context\20const&\29 +705:skia_private::TArray::push_back\28int&&\29 +706:skgpu::ResourceKey::Builder::Builder\28skgpu::ResourceKey*\2c\20unsigned\20int\2c\20int\29 +707:rewind\28GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +708:hb_sanitize_context_t::end_processing\28\29 +709:hb_buffer_t::move_to\28unsigned\20int\29 +710:_output_with_dotted_circle\28hb_buffer_t*\29 +711:__memcpy +712:SkTSpan::pointLast\28\29\20const +713:SkTDStorage::resize\28int\29 +714:SkSL::Parser::rangeFrom\28SkSL::Token\29 +715:SkSL::Parser::error\28SkSL::Position\2c\20std::__2::basic_string_view>\29 +716:SkPathRef::isFinite\28\29\20const +717:SkPathRef::Editor::Editor\28sk_sp*\2c\20int\2c\20int\2c\20int\29 +718:SkMatrix::mapXY\28float\2c\20float\2c\20SkPoint*\29\20const +719:SkImageInfo::MakeA8\28int\2c\20int\29 +720:SkImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +721:SkDrawable::getFlattenableType\28\29\20const +722:SkDPoint::ApproximatelyEqual\28SkPoint\20const&\2c\20SkPoint\20const&\29 +723:SkBlockAllocator::reset\28\29 +724:GrSimpleMeshDrawOpHelperWithStencil::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20bool*\29 +725:GrGeometryProcessor::ProgramImpl::SetTransform\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrResourceHandle\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix*\29 +726:GrGLSLVertexGeoBuilder::insertFunction\28char\20const*\29 +727:GrDrawingManager::flushIfNecessary\28\29 +728:FT_Stream_Skip +729:FT_Stream_ExtractFrame +730:Cr_z_crc32 +731:void\20std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrGLCaps::ColorTypeInfo*\29 +732:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +733:std::__2::ctype::widen\5babi:nn180100\5d\28char\29\20const +734:std::__2::basic_string\2c\20std::__2::allocator>::__move_assign\5babi:ne180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::integral_constant\29 +735:std::__2::__unique_if::__unique_array_unknown_bound\20std::__2::make_unique\5babi:ne180100\5d\28unsigned\20long\29 +736:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +737:skif::LayerSpace::outset\28skif::LayerSpace\20const&\29 +738:skia_private::TArray::checkRealloc\28int\2c\20double\29 +739:skgpu::tess::StrokeIterator::enqueue\28skgpu::tess::StrokeIterator::Verb\2c\20SkPoint\20const*\2c\20float\20const*\29 +740:skgpu::ganesh::SurfaceFillContext::getOpsTask\28\29 +741:skgpu::ganesh::AsView\28GrRecordingContext*\2c\20SkImage\20const*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +742:hb_buffer_t::unsafe_to_concat_from_outbuffer\28unsigned\20int\2c\20unsigned\20int\29 +743:fmodf +744:__addtf3 +745:SkSL::RP::Builder::push_constant_i\28int\2c\20int\29 +746:SkSL::RP::Builder::label\28int\29 +747:SkPath::isConvex\28\29\20const +748:SkPaintToGrPaint\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +749:SkImageInfo::operator=\28SkImageInfo\20const&\29 +750:SkImageGenerator::onIsValid\28GrRecordingContext*\29\20const +751:SkBitmap::tryAllocPixels\28SkImageInfo\20const&\29 +752:GrSkSLFP::addChild\28std::__2::unique_ptr>\2c\20bool\29 +753:GrProcessorSet::~GrProcessorSet\28\29 +754:GrGeometryProcessor::Attribute&\20skia_private::TArray::emplace_back\28char\20const\20\28&\29\20\5b10\5d\2c\20GrVertexAttribType&&\2c\20SkSLType&&\29 +755:GrGLGpu::clearErrorsAndCheckForOOM\28\29 +756:GrGLGpu::bindBuffer\28GrGpuBufferType\2c\20GrBuffer\20const*\29 +757:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +758:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20float\20const*\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20float\20const*\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20float\20const*\29 +759:GrFragmentProcessor::ProgramImpl::invokeChild\28int\2c\20char\20const*\2c\20char\20const*\2c\20GrFragmentProcessor::ProgramImpl::EmitArgs&\2c\20std::__2::basic_string_view>\29 +760:void\20SkSafeUnref\28SharedGenerator*\29 +761:ubidi_getParaLevelAtIndex_skia +762:std::__2::char_traits::copy\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +763:std::__2::basic_string\2c\20std::__2::allocator>::begin\5babi:nn180100\5d\28\29 +764:std::__2::basic_string\2c\20std::__2::allocator>::__is_long\5babi:nn180100\5d\28\29\20const +765:std::__2::__libcpp_snprintf_l\28char*\2c\20unsigned\20long\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +766:skia_private::THashTable>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair\2c\20std::__2::unique_ptr>*\2c\20skia_private::THashMap>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>*\2c\20std::__2::unique_ptr>*\2c\20SkGoodHash>::Pair&&\29 +767:skia::textlayout::Cluster::run\28\29\20const +768:skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::AddTrianglesWhenChopping\2c\20skgpu::tess::DiscardFlatCurves>::accountForCurve\28float\29 +769:skgpu::ganesh::SurfaceContext::PixelTransferResult::~PixelTransferResult\28\29 +770:is_equal\28std::type_info\20const*\2c\20std::type_info\20const*\2c\20bool\29 +771:hb_ot_map_t::get_1_mask\28unsigned\20int\29\20const +772:hb_font_get_glyph +773:hb_draw_funcs_t::emit_quadratic_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\2c\20float\2c\20float\29 +774:cff_index_get_sid_string +775:_hb_font_funcs_set_middle\28hb_font_funcs_t*\2c\20void*\2c\20void\20\28*\29\28void*\29\29 +776:__floatsitf +777:SkWriter32::writeScalar\28float\29 +778:SkTDArray<\28anonymous\20namespace\29::YOffset>::append\28\29 +779:SkSL::RP::Generator::pushVectorizedExpression\28SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +780:SkSL::RP::Builder::swizzle\28int\2c\20SkSpan\29 +781:SkRegion::setRect\28SkIRect\20const&\29 +782:SkPaint::setColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\29 +783:SkPaint::asBlendMode\28\29\20const +784:SkMatrix::preTranslate\28float\2c\20float\29 +785:SkMatrix::getMaxScale\28\29\20const +786:SkJSONWriter::appendHexU32\28char\20const*\2c\20unsigned\20int\29 +787:SkDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +788:SkCanvas::concat\28SkMatrix\20const&\29 +789:SkBlender::Mode\28SkBlendMode\29 +790:SkBitmap::setInfo\28SkImageInfo\20const&\2c\20unsigned\20long\29 +791:SkArenaAlloc::SkArenaAlloc\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +792:OT::hb_ot_apply_context_t::skipping_iterator_t::next\28unsigned\20int*\29 +793:OT::VarSizedBinSearchArrayOf>::get_length\28\29\20const +794:GrMeshDrawTarget::allocMesh\28\29 +795:GrGLGpu::bindTextureToScratchUnit\28unsigned\20int\2c\20int\29 +796:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::~SwizzleFragmentProcessor\28\29 +797:GrCaps::getReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +798:GrBackendFormat::GrBackendFormat\28GrBackendFormat\20const&\29 +799:CFF::cff1_cs_opset_t::check_width\28unsigned\20int\2c\20CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +800:AutoFTAccess::AutoFTAccess\28SkTypeface_FreeType\20const*\29 +801:strchr +802:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +803:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +804:std::__2::pair::type\2c\20std::__2::__unwrap_ref_decay::type>\20std::__2::make_pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +805:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20char\29\20const +806:std::__2::basic_string\2c\20std::__2::allocator>::__set_long_cap\5babi:nn180100\5d\28unsigned\20long\29 +807:std::__2::__function::__value_func::__value_func\5babi:ne180100\5d\28std::__2::__function::__value_func&&\29 +808:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +809:skia_private::TArray>\2c\20true>::reserve_exact\28int\29 +810:skia_private::TArray::push_back\28bool&&\29 +811:skia_png_get_uint_32 +812:skia::textlayout::OneLineShaper::clusterIndex\28unsigned\20long\29 +813:skgpu::ganesh::SurfaceDrawContext::chooseAAType\28GrAA\29 +814:skgpu::UniqueKey::GenerateDomain\28\29 +815:path_quadraticBezierTo +816:hb_buffer_t::sync_so_far\28\29 +817:hb_buffer_t::sync\28\29 +818:compute_side\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +819:cff_parse_num +820:SkWriter32::writeRect\28SkRect\20const&\29 +821:SkSL::Type::clone\28SkSL::Context\20const&\2c\20SkSL::SymbolTable*\29\20const +822:SkSL::SymbolTable::find\28std::__2::basic_string_view>\29\20const +823:SkSL::RP::Generator::writeStatement\28SkSL::Statement\20const&\29 +824:SkSL::RP::Builder::unary_op\28SkSL::RP::BuilderOp\2c\20int\29 +825:SkSL::Parser::operatorRight\28SkSL::Parser::AutoDepth&\2c\20SkSL::OperatorKind\2c\20std::__2::unique_ptr>\20\28SkSL::Parser::*\29\28\29\2c\20std::__2::unique_ptr>&\29 +826:SkSL::Parser::expression\28\29 +827:SkSL::Nop::Make\28\29 +828:SkRecords::FillBounds::pushControl\28\29 +829:SkRasterClip::~SkRasterClip\28\29 +830:SkM44::asM33\28\29\20const +831:SkIRect::makeOutset\28int\2c\20int\29\20const +832:SkDQuad::ptAtT\28double\29\20const +833:SkDConic::ptAtT\28double\29\20const +834:SkAutoConicToQuads::computeQuads\28SkPoint\20const*\2c\20float\2c\20float\29 +835:SkArenaAlloc::~SkArenaAlloc\28\29 +836:SkAAClip::setEmpty\28\29 +837:OT::hb_ot_apply_context_t::skipping_iterator_t::reset\28unsigned\20int\29 +838:GrTriangulator::Line::intersect\28GrTriangulator::Line\20const&\2c\20SkPoint*\29\20const +839:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkISize\20const&\29 +840:GrGpuBuffer::unmap\28\29 +841:GrGeometryProcessor::ProgramImpl::WriteLocalCoord\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20GrShaderVar\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +842:GrGeometryProcessor::ProgramImpl::ComputeMatrixKey\28GrShaderCaps\20const&\2c\20SkMatrix\20const&\29 +843:GrFragmentProcessor::GrFragmentProcessor\28GrFragmentProcessor\20const&\29 +844:635 +845:void\20SkSafeUnref\28SkMipmap*\29 +846:ubidi_getMemory_skia +847:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +848:std::__2::vector>::erase\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\29 +849:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Module\20const*\29 +850:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +851:std::__2::numpunct::truename\5babi:nn180100\5d\28\29\20const +852:std::__2::numpunct::falsename\5babi:nn180100\5d\28\29\20const +853:std::__2::numpunct::decimal_point\5babi:nn180100\5d\28\29\20const +854:std::__2::moneypunct::do_grouping\28\29\20const +855:std::__2::ctype::is\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29\20const +856:std::__2::basic_string\2c\20std::__2::allocator>::empty\5babi:nn180100\5d\28\29\20const +857:snprintf +858:skvx::Vec<4\2c\20float>\20skvx::operator-<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +859:skia_private::TArray::checkRealloc\28int\2c\20double\29 +860:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +861:skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>::STArray\28skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&&\29 +862:skia_png_reciprocal +863:skia_png_malloc_warn +864:skia::textlayout::\28anonymous\20namespace\29::relax\28float\29 +865:skgpu::ganesh::SurfaceFillContext::arenaAlloc\28\29 +866:skgpu::ganesh::SurfaceContext::readPixels\28GrDirectContext*\2c\20GrPixmap\2c\20SkIPoint\29 +867:skgpu::Swizzle::RGBA\28\29 +868:sk_sp::~sk_sp\28\29 +869:operator==\28SkIRect\20const&\2c\20SkIRect\20const&\29 +870:hb_draw_funcs_t::emit_close_path\28void*\2c\20hb_draw_state_t&\29 +871:crc32_z +872:SkTSect::SkTSect\28SkTCurve\20const&\29 +873:SkSL::String::Separator\28\29 +874:SkSL::RP::Generator::pushIntrinsic\28SkSL::RP::BuilderOp\2c\20SkSL::Expression\20const&\29 +875:SkSL::ProgramConfig::strictES2Mode\28\29\20const +876:SkSL::Parser::layoutInt\28\29 +877:SkRegion::setEmpty\28\29 +878:SkRegion::Cliperator::next\28\29 +879:SkRegion::Cliperator::Cliperator\28SkRegion\20const&\2c\20SkIRect\20const&\29 +880:SkRGBA4f<\28SkAlphaType\293>::FromColor\28unsigned\20int\29 +881:SkPathRef::growForVerb\28int\2c\20float\29 +882:SkPath::transform\28SkMatrix\20const&\2c\20SkPath*\2c\20SkApplyPerspectiveClip\29\20const +883:SkMipmap::ComputeLevelCount\28int\2c\20int\29 +884:SkMatrix::MakeRectToRect\28SkRect\20const&\2c\20SkRect\20const&\2c\20SkMatrix::ScaleToFit\29 +885:SkMatrix::MakeAll\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +886:SkImageInfo::operator=\28SkImageInfo&&\29 +887:SkImageFilter_Base::getFlattenableType\28\29\20const +888:SkIRect::makeOffset\28int\2c\20int\29\20const +889:SkDLine::nearPoint\28SkDPoint\20const&\2c\20bool*\29\20const +890:SkChopQuadAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +891:SkCanvas::aboutToDraw\28SkPaint\20const&\2c\20SkRect\20const*\29 +892:SkBaseShadowTessellator::appendTriangle\28unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +893:SafeDecodeSymbol +894:OT::hb_ot_apply_context_t::~hb_ot_apply_context_t\28\29 +895:OT::hb_ot_apply_context_t::hb_ot_apply_context_t\28unsigned\20int\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20hb_blob_t*\29 +896:OT::ClassDef::get_class\28unsigned\20int\29\20const +897:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_4::operator\28\29\28char\20const*\29\20const +898:GrSimpleMeshDrawOpHelper::isCompatible\28GrSimpleMeshDrawOpHelper\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +899:GrShaderVar::GrShaderVar\28GrShaderVar\20const&\29 +900:GrQuad::writeVertex\28int\2c\20skgpu::VertexWriter&\29\20const +901:GrOpFlushState::bindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +902:GrGLSLShaderBuilder::appendTextureLookup\28GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +903:GrGLGpu::getErrorAndCheckForOOM\28\29 +904:GrColorInfo::GrColorInfo\28SkColorInfo\20const&\29 +905:GrAAConvexTessellator::addTri\28int\2c\20int\2c\20int\29 +906:FT_Get_Module +907:AlmostBequalUlps\28double\2c\20double\29 +908:tt_face_get_name +909:std::__2::unique_ptr::reset\5babi:ne180100\5d\28void*\29 +910:std::__2::locale::use_facet\28std::__2::locale::id&\29\20const +911:std::__2::basic_string\2c\20std::__2::allocator>::__init\28char\20const*\2c\20unsigned\20long\29 +912:std::__2::__variant_detail::__dtor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29 +913:std::__2::__variant_detail::__dtor\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29 +914:std::__2::__libcpp_locale_guard::~__libcpp_locale_guard\5babi:nn180100\5d\28\29 +915:std::__2::__libcpp_locale_guard::__libcpp_locale_guard\5babi:nn180100\5d\28__locale_struct*&\29 +916:skvx::Vec<4\2c\20float>&\20skvx::operator+=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.5848\29 +917:skvx::Vec<2\2c\20float>\20skvx::max<2\2c\20float>\28skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +918:skif::FilterResult::FilterResult\28skif::FilterResult\20const&\29 +919:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Hash\28SkImageFilter\20const*\20const&\29 +920:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +921:sk_sp&\20skia_private::TArray\2c\20true>::emplace_back>\28sk_sp&&\29 +922:sinf +923:qsort +924:path_cubicTo +925:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +926:hb_user_data_array_t::fini\28\29 +927:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\2c\20hb_pair_t>>::operator+\28unsigned\20int\29\20const +928:hb_indic_would_substitute_feature_t::would_substitute\28unsigned\20int\20const*\2c\20unsigned\20int\2c\20hb_face_t*\29\20const +929:hb_font_t::get_glyph_h_advance\28unsigned\20int\29 +930:ft_module_get_service +931:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\29\20const +932:__sindf +933:__shlim +934:__cosdf +935:SkWriter32::write\28void\20const*\2c\20unsigned\20long\29 +936:SkString::equals\28SkString\20const&\29\20const +937:SkSL::evaluate_pairwise_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +938:SkSL::compile_and_shrink\28SkSL::Compiler*\2c\20SkSL::ProgramKind\2c\20SkSL::ModuleType\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::Module\20const*\29 +939:SkSL::StringStream::str\28\29\20const +940:SkSL::RP::Generator::makeLValue\28SkSL::Expression\20const&\2c\20bool\29 +941:SkSL::Parser::expressionOrPoison\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +942:SkSL::GLSLCodeGenerator::writeIdentifier\28std::__2::basic_string_view>\29 +943:SkSL::GLSLCodeGenerator::getTypeName\28SkSL::Type\20const&\29 +944:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +945:SkRect::round\28\29\20const +946:SkPixmap::SkPixmap\28SkPixmap\20const&\29 +947:SkPaint::getAlpha\28\29\20const +948:SkMatrix::preScale\28float\2c\20float\29 +949:SkMatrix::isSimilarity\28float\29\20const +950:SkIRect::join\28SkIRect\20const&\29 +951:SkDrawBase::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20bool\29\20const +952:SkData::MakeUninitialized\28unsigned\20long\29 +953:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\29 +954:SkCanvas::save\28\29 +955:SkCanvas::checkForDeferredSave\28\29 +956:SkBitmapCache::Rec::getKey\28\29\20const +957:SkAAClip::Builder::addRun\28int\2c\20int\2c\20unsigned\20int\2c\20int\29 +958:GrTriangulator::Line::Line\28SkPoint\20const&\2c\20SkPoint\20const&\29 +959:GrTriangulator::Edge::isRightOf\28GrTriangulator::Vertex\20const&\29\20const +960:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\29 +961:GrShape::setType\28GrShape::Type\29 +962:GrPixmapBase::GrPixmapBase\28GrPixmapBase\20const&\29 +963:GrMakeUncachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +964:GrIORef::unref\28\29\20const +965:GrGeometryProcessor::TextureSampler::reset\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +966:GrGLSLShaderBuilder::getMangledFunctionName\28char\20const*\29 +967:GrGLGpu::deleteFramebuffer\28unsigned\20int\29 +968:GrBackendFormats::MakeGL\28unsigned\20int\2c\20unsigned\20int\29 +969:760 +970:vsnprintf +971:top12 +972:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +973:std::__2::unique_ptr>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +974:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +975:std::__2::to_string\28long\20long\29 +976:std::__2::basic_string\2c\20std::__2::allocator>::operator=\5babi:nn180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +977:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\2c\20std::__2::allocator>\28char\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +978:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +979:std::__2::__num_put_base::__identify_padding\28char*\2c\20char*\2c\20std::__2::ios_base\20const&\29 +980:std::__2::__num_get_base::__get_base\28std::__2::ios_base&\29 +981:std::__2::__libcpp_asprintf_l\28char**\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +982:skvx::Vec<4\2c\20float>\20skvx::abs<4>\28skvx::Vec<4\2c\20float>\20const&\29 +983:skvx::Vec<2\2c\20float>\20skvx::min<2\2c\20float>\28skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +984:sktext::gpu::BagOfBytes::allocateBytes\28int\2c\20int\29 +985:skif::FilterResult::FilterResult\28sk_sp\2c\20skif::LayerSpace\20const&\29 +986:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +987:skia_private::TArray::~TArray\28\29 +988:skia_private::TArray::checkRealloc\28int\2c\20double\29 +989:skia_png_malloc_base +990:skia::textlayout::TextLine::iterateThroughVisualRuns\28bool\2c\20std::__2::function\2c\20float*\29>\20const&\29\20const +991:skgpu::ganesh::SurfaceDrawContext::numSamples\28\29\20const +992:skgpu::AutoCallback::~AutoCallback\28\29 +993:sk_sp::reset\28SkData*\29 +994:sk_sp::~sk_sp\28\29 +995:skData_getConstPointer +996:round +997:operator==\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +998:is_one_of\28hb_glyph_info_t\20const&\2c\20unsigned\20int\29 +999:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1000:int\20std::__2::__get_up_to_n_digits\5babi:nn180100\5d>>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\2c\20int\29 +1001:inflateStateCheck +1002:hb_lazy_loader_t\2c\20hb_face_t\2c\206u\2c\20hb_blob_t>::get\28\29\20const +1003:hb_font_t::has_glyph\28unsigned\20int\29 +1004:bool\20hb_sanitize_context_t::check_array\28OT::HBGlyphID16\20const*\2c\20unsigned\20int\29\20const +1005:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1006:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1007:bool\20OT::Layout::Common::Coverage::collect_coverage\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>>\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>*\29\20const +1008:addPoint\28UBiDi*\2c\20int\2c\20int\29 +1009:__extenddftf2 +1010:\28anonymous\20namespace\29::extension_compare\28SkString\20const&\2c\20SkString\20const&\29 +1011:\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1012:\28anonymous\20namespace\29::colrv1_transform\28FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\2c\20SkCanvas*\2c\20SkMatrix*\29 +1013:SkUTF::NextUTF8\28char\20const**\2c\20char\20const*\29 +1014:SkUTF::NextUTF8WithReplacement\28char\20const**\2c\20char\20const*\29 +1015:SkTInternalLList::addToHead\28sktext::gpu::TextBlob*\29 +1016:SkTDStorage::removeShuffle\28int\29 +1017:SkTCopyOnFirstWrite::writable\28\29 +1018:SkSurface_Base::getCachedCanvas\28\29 +1019:SkString::reset\28\29 +1020:SkStrike::unlock\28\29 +1021:SkStrike::lock\28\29 +1022:SkSafeMath::addInt\28int\2c\20int\29 +1023:SkSL::cast_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +1024:SkSL::StringStream::~StringStream\28\29 +1025:SkSL::RP::LValue::~LValue\28\29 +1026:SkSL::RP::Generator::pushIntrinsic\28SkSL::RP::Generator::TypedOps\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +1027:SkSL::InlineCandidateAnalyzer::visitExpression\28std::__2::unique_ptr>*\29 +1028:SkSL::GLSLCodeGenerator::writeType\28SkSL::Type\20const&\29 +1029:SkSL::Expression::isBoolLiteral\28\29\20const +1030:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29 +1031:SkRuntimeEffect::findUniform\28std::__2::basic_string_view>\29\20const +1032:SkRasterPipelineBlitter::appendLoadDst\28SkRasterPipeline*\29\20const +1033:SkPoint::Distance\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1034:SkPath::moveTo\28float\2c\20float\29 +1035:SkPath::isRect\28SkRect*\2c\20bool*\2c\20SkPathDirection*\29\20const +1036:SkPath::injectMoveToIfNeeded\28\29 +1037:SkMatrix::setScaleTranslate\28float\2c\20float\2c\20float\2c\20float\29 +1038:SkMatrix::postScale\28float\2c\20float\29 +1039:SkMatrix::mapVector\28float\2c\20float\29\20const +1040:SkIntersections::removeOne\28int\29 +1041:SkImages::RasterFromBitmap\28SkBitmap\20const&\29 +1042:SkImage_Ganesh::SkImage_Ganesh\28sk_sp\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20SkColorInfo\29 +1043:SkImageInfo::Make\28int\2c\20int\2c\20SkColorType\2c\20SkAlphaType\29 +1044:SkImageFilter_Base::getChildInputLayerBounds\28int\2c\20skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +1045:SkGlyph::iRect\28\29\20const +1046:SkFindUnitQuadRoots\28float\2c\20float\2c\20float\2c\20float*\29 +1047:SkDevice::makeSpecial\28SkBitmap\20const&\29 +1048:SkData::PrivateNewWithCopy\28void\20const*\2c\20unsigned\20long\29 +1049:SkColorSpaceXformSteps::Flags::mask\28\29\20const +1050:SkColorSpace::Equals\28SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +1051:SkBlurMaskFilterImpl::computeXformedSigma\28SkMatrix\20const&\29\20const +1052:SkBlockAllocator::BlockIter::Item::operator++\28\29 +1053:SkBitmap::peekPixels\28SkPixmap*\29\20const +1054:SkAAClip::freeRuns\28\29 +1055:OT::hb_ot_apply_context_t::set_lookup_mask\28unsigned\20int\2c\20bool\29 +1056:OT::cmap::find_subtable\28unsigned\20int\2c\20unsigned\20int\29\20const +1057:GrWindowRectangles::~GrWindowRectangles\28\29 +1058:GrTriangulator::EdgeList::remove\28GrTriangulator::Edge*\29 +1059:GrTriangulator::Edge::isLeftOf\28GrTriangulator::Vertex\20const&\29\20const +1060:GrStyle::SimpleFill\28\29 +1061:GrSimpleMeshDrawOpHelper::createProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1062:GrResourceAllocator::addInterval\28GrSurfaceProxy*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20GrResourceAllocator::ActualUse\2c\20GrResourceAllocator::AllowRecycling\29 +1063:GrRenderTask::makeClosed\28GrRecordingContext*\29 +1064:GrGLGpu::prepareToDraw\28GrPrimitiveType\29 +1065:GrBackendFormatToCompressionType\28GrBackendFormat\20const&\29 +1066:FT_Stream_Read +1067:FT_Outline_Get_CBox +1068:Cr_z_adler32 +1069:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::end\28\29\20const +1070:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::begin\28\29\20const +1071:AlmostDequalUlps\28double\2c\20double\29 +1072:863 +1073:864 +1074:write_tag_size\28SkWriteBuffer&\2c\20unsigned\20int\2c\20unsigned\20long\29 +1075:void\20std::__2::unique_ptr::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot*\2c\200>\28skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Slot*\29 +1076:void\20skgpu::VertexWriter::writeQuad\2c\20skgpu::VertexColor\2c\20skgpu::VertexWriter::Conditional>\28skgpu::VertexWriter::TriFan\20const&\2c\20skgpu::VertexColor\20const&\2c\20skgpu::VertexWriter::Conditional\20const&\29 +1077:uprv_free_skia +1078:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +1079:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +1080:unsigned\20int\20std::__2::__sort3\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +1081:strcpy +1082:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1083:std::__2::unique_ptr>::operator=\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +1084:std::__2::unique_ptr>\20GrSkSLFP::Make<>\28SkRuntimeEffect\20const*\2c\20char\20const*\2c\20std::__2::unique_ptr>\2c\20GrSkSLFP::OptFlags\29 +1085:std::__2::unique_ptr>\20GrBlendFragmentProcessor::Make<\28SkBlendMode\2913>\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +1086:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +1087:std::__2::time_get>>::get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\20const*\2c\20char\20const*\29\20const +1088:std::__2::enable_if::type\20skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::AddTrianglesWhenChopping\2c\20skgpu::tess::DiscardFlatCurves>::writeTriangleStack\28skgpu::tess::MiddleOutPolygonTriangulator::PoppedTriangleStack&&\29 +1089:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +1090:std::__2::__tuple_impl\2c\20GrSurfaceProxyView\2c\20sk_sp>::~__tuple_impl\28\29 +1091:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator>=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29\20\28.5835\29 +1092:skia_private::TArray::push_back\28SkSL::SwitchCase\20const*\20const&\29 +1093:skia_private::TArray::push_back_n\28int\2c\20SkPoint\20const*\29 +1094:skia::textlayout::Run::placeholderStyle\28\29\20const +1095:skgpu::skgpu_init_static_unique_key_once\28SkAlignedSTStorage<1\2c\20skgpu::UniqueKey>*\29 +1096:skgpu::ganesh::\28anonymous\20namespace\29::update_degenerate_test\28skgpu::ganesh::\28anonymous\20namespace\29::DegenerateTestData*\2c\20SkPoint\20const&\29 +1097:skgpu::VertexWriter&\20skgpu::operator<<\28skgpu::VertexWriter&\2c\20skgpu::VertexColor\20const&\29 +1098:skgpu::ResourceKey::ResourceKey\28\29 +1099:sk_sp::~sk_sp\28\29 +1100:sk_sp::reset\28GrThreadSafeCache::VertexData*\29 +1101:scalbn +1102:rowcol3\28float\20const*\2c\20float\20const*\29 +1103:ps_parser_skip_spaces +1104:is_joiner\28hb_glyph_info_t\20const&\29 +1105:hb_paint_funcs_t::push_translate\28void*\2c\20float\2c\20float\29 +1106:hb_lazy_loader_t\2c\20hb_face_t\2c\2022u\2c\20hb_blob_t>::get\28\29\20const +1107:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\2c\20hb_pair_t>>::operator--\28int\29 +1108:hb_aat_map_t::range_flags_t*\20hb_vector_t::push\28hb_aat_map_t::range_flags_t&&\29 +1109:get_gsubgpos_table\28hb_face_t*\2c\20unsigned\20int\29 +1110:emscripten_longjmp +1111:contourMeasure_dispose +1112:cff2_path_procs_extents_t::line\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\2c\20CFF::point_t\20const&\29 +1113:cff2_path_param_t::line_to\28CFF::point_t\20const&\29 +1114:cff1_path_procs_extents_t::line\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\29 +1115:cff1_path_param_t::line_to\28CFF::point_t\20const&\29 +1116:cf2_stack_pushInt +1117:cf2_buf_readByte +1118:bool\20hb_bsearch_impl\28unsigned\20int*\2c\20unsigned\20int\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\29\29 +1119:_hb_draw_funcs_set_preamble\28hb_draw_funcs_t*\2c\20bool\2c\20void**\2c\20void\20\28**\29\28void*\29\29 +1120:\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29 +1121:SkWStream::writeDecAsText\28int\29 +1122:SkTDStorage::append\28void\20const*\2c\20int\29 +1123:SkStrikeSpec::SkStrikeSpec\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +1124:SkSL::RP::Builder::lastInstructionOnAnyStack\28int\29 +1125:SkSL::ProgramUsage::get\28SkSL::Variable\20const&\29\20const +1126:SkSL::Parser::expectIdentifier\28SkSL::Token*\29 +1127:SkSL::Parser::AutoDepth::increase\28\29 +1128:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29::$_3::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +1129:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29::$_2::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +1130:SkSL::GLSLCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1131:SkSL::GLSLCodeGenerator::finishLine\28\29 +1132:SkSL::ConstructorSplat::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1133:SkSL::ConstructorScalarCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1134:SkRuntimeEffect::Uniform::sizeInBytes\28\29\20const +1135:SkRegion::setRegion\28SkRegion\20const&\29 +1136:SkRegion::SkRegion\28SkIRect\20const&\29 +1137:SkRasterPipeline::run\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +1138:SkRasterPipeline::appendTransferFunction\28skcms_TransferFunction\20const&\29 +1139:SkRRect::checkCornerContainment\28float\2c\20float\29\20const +1140:SkRRect::MakeRect\28SkRect\20const&\29 +1141:SkRRect::MakeOval\28SkRect\20const&\29 +1142:SkPointPriv::DistanceToLineSegmentBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +1143:SkPoint::setLength\28float\29 +1144:SkPathPriv::AllPointsEq\28SkPoint\20const*\2c\20int\29 +1145:SkPathBuilder::~SkPathBuilder\28\29 +1146:SkPathBuilder::lineTo\28SkPoint\29 +1147:SkPathBuilder::detach\28\29 +1148:SkPathBuilder::SkPathBuilder\28\29 +1149:SkPath::transform\28SkMatrix\20const&\2c\20SkApplyPerspectiveClip\29 +1150:SkOpCoincidence::release\28SkCoincidentSpans*\2c\20SkCoincidentSpans*\29 +1151:SkJSONWriter::appendCString\28char\20const*\2c\20char\20const*\29 +1152:SkIntersections::hasT\28double\29\20const +1153:SkImageFilter_Base::getChildOutput\28int\2c\20skif::Context\20const&\29\20const +1154:SkIRect::offset\28int\2c\20int\29 +1155:SkDLine::ptAtT\28double\29\20const +1156:SkCanvas::translate\28float\2c\20float\29 +1157:SkCanvas::restoreToCount\28int\29 +1158:SkCanvas::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +1159:SkCachedData::unref\28\29\20const +1160:SkAutoSMalloc<1024ul>::~SkAutoSMalloc\28\29 +1161:SkAutoCanvasRestore::~SkAutoCanvasRestore\28\29 +1162:SkArenaAlloc::SkArenaAlloc\28unsigned\20long\29 +1163:SkAAClipBlitterWrapper::init\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1164:SkAAClipBlitterWrapper::SkAAClipBlitterWrapper\28SkRasterClip\20const&\2c\20SkBlitter*\29 +1165:OT::Offset\2c\20true>::is_null\28\29\20const +1166:OT::MVAR::get_var\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29\20const +1167:MaskAdditiveBlitter::getRow\28int\29 +1168:GrTextureEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20GrCaps\20const&\2c\20float\20const*\29 +1169:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\29 +1170:GrTessellationShader::MakeProgram\28GrTessellationShader::ProgramArgs\20const&\2c\20GrTessellationShader\20const*\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +1171:GrScissorState::enabled\28\29\20const +1172:GrRecordingContextPriv::recordTimeAllocator\28\29 +1173:GrQuad::bounds\28\29\20const +1174:GrProxyProvider::createProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\29 +1175:GrPixmapBase::operator=\28GrPixmapBase&&\29 +1176:GrOpFlushState::detachAppliedClip\28\29 +1177:GrGLGpu::disableWindowRectangles\28\29 +1178:GrGLFormatFromGLEnum\28unsigned\20int\29 +1179:GrFragmentProcessor::~GrFragmentProcessor\28\29 +1180:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29 +1181:GrBackendTexture::getBackendFormat\28\29\20const +1182:CFF::interp_env_t::fetch_op\28\29 +1183:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::setIndices\28\29 +1184:AlmostEqualUlps\28double\2c\20double\29 +1185:AAT::StateTable::get_entry\28int\2c\20unsigned\20int\29\20const +1186:AAT::StateTable::EntryData>::get_entry\28int\2c\20unsigned\20int\29\20const +1187:void\20sktext::gpu::fill3D\28SkZip\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28float\2c\20float\29::operator\28\29\28float\2c\20float\29\20const +1188:tt_face_lookup_table +1189:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1190:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1191:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1192:std::__2::moneypunct::negative_sign\5babi:nn180100\5d\28\29\20const +1193:std::__2::moneypunct::neg_format\5babi:nn180100\5d\28\29\20const +1194:std::__2::moneypunct::frac_digits\5babi:nn180100\5d\28\29\20const +1195:std::__2::moneypunct::do_pos_format\28\29\20const +1196:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20std::__2::random_access_iterator_tag\29 +1197:std::__2::function::operator\28\29\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\20const +1198:std::__2::ctype::widen\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +1199:std::__2::char_traits::copy\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20unsigned\20long\29 +1200:std::__2::char_traits::eq_int_type\5babi:nn180100\5d\28int\2c\20int\29 +1201:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1202:std::__2::basic_string\2c\20std::__2::allocator>::end\5babi:nn180100\5d\28\29 +1203:std::__2::basic_string\2c\20std::__2::allocator>::__set_size\5babi:nn180100\5d\28unsigned\20long\29 +1204:std::__2::__split_buffer&>::~__split_buffer\28\29 +1205:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +1206:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +1207:std::__2::__itoa::__append2\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1208:std::__2::__exception_guard_exceptions>::__destroy_vector>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +1209:skvx::Vec<4\2c\20unsigned\20int>\20\28anonymous\20namespace\29::shift_right>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20int\29 +1210:skvx::Vec<4\2c\20float>\20skvx::naive_if_then_else<4\2c\20float>\28skvx::Vec<4\2c\20skvx::Mask::type>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1211:sktext::gpu::BagOfBytes::~BagOfBytes\28\29 +1212:skif::\28anonymous\20namespace\29::is_nearly_integer_translation\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29 +1213:skif::RoundOut\28SkRect\29 +1214:skif::FilterResult::resolve\28skif::Context\20const&\2c\20skif::LayerSpace\2c\20bool\29\20const +1215:skia_private::TArray\2c\20true>::destroyAll\28\29 +1216:skia_private::TArray::push_back\28float\20const&\29 +1217:skia_private::TArray::push_back\28SkSL::Variable*&&\29 +1218:skia_png_gamma_correct +1219:skia_png_gamma_8bit_correct +1220:skia::textlayout::TextStyle::operator=\28skia::textlayout::TextStyle\20const&\29 +1221:skia::textlayout::Run::positionX\28unsigned\20long\29\20const +1222:skia::textlayout::ParagraphImpl::codeUnitHasProperty\28unsigned\20long\2c\20SkUnicode::CodeUnitFlags\29\20const +1223:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20std::__2::basic_string_view>\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1224:skgpu::UniqueKey::UniqueKey\28skgpu::UniqueKey\20const&\29 +1225:sk_sp::operator=\28sk_sp\20const&\29 +1226:sk_sp::reset\28GrSurfaceProxy*\29 +1227:sk_sp::operator=\28sk_sp&&\29 +1228:sk_realloc_throw\28void*\2c\20unsigned\20long\29 +1229:powf_ +1230:png_read_buffer +1231:non-virtual\20thunk\20to\20GrOpFlushState::allocator\28\29 +1232:interp_cubic_coords\28double\20const*\2c\20double\29 +1233:int\20_hb_cmp_method>\28void\20const*\2c\20void\20const*\29 +1234:hb_paint_funcs_t::push_transform\28void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +1235:hb_font_t::parent_scale_y_distance\28int\29 +1236:hb_font_t::parent_scale_x_distance\28int\29 +1237:hb_face_t::get_upem\28\29\20const +1238:double_to_clamped_scalar\28double\29 +1239:conic_eval_numerator\28double\20const*\2c\20float\2c\20double\29 +1240:cff_index_init +1241:bool\20std::__2::operator!=\5babi:nn180100\5d\28std::__2::__wrap_iter\20const&\2c\20std::__2::__wrap_iter\20const&\29 +1242:bool\20hb_buffer_t::replace_glyphs\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\20const*\29 +1243:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1244:__isspace +1245:\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16::Compact\28skvx::Vec<4\2c\20float>\20const&\29 +1246:\28anonymous\20namespace\29::ColorTypeFilter_F16F16::Compact\28skvx::Vec<4\2c\20float>\20const&\29 +1247:\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16::Compact\28skvx::Vec<4\2c\20float>\20const&\29 +1248:\28anonymous\20namespace\29::ColorTypeFilter_8888::Compact\28skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +1249:\28anonymous\20namespace\29::ColorTypeFilter_16161616::Compact\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1250:\28anonymous\20namespace\29::ColorTypeFilter_1010102::Compact\28unsigned\20long\20long\29 +1251:TT_MulFix14 +1252:Skwasm::createMatrix\28float\20const*\29 +1253:SkWriter32::writeBool\28bool\29 +1254:SkTDStorage::append\28int\29 +1255:SkTDPQueue::setIndex\28int\29 +1256:SkTDArray::push_back\28void*\20const&\29 +1257:SkSurface_Base::refCachedImage\28\29 +1258:SkSpotShadowTessellator::addToClip\28SkPoint\20const&\29 +1259:SkShaderUtils::GLSLPrettyPrint::newline\28\29 +1260:SkShaderUtils::GLSLPrettyPrint::hasToken\28char\20const*\29 +1261:SkSL::Type::MakeTextureType\28char\20const*\2c\20SpvDim_\2c\20bool\2c\20bool\2c\20bool\2c\20SkSL::Type::TextureAccess\29 +1262:SkSL::Type::MakeSpecialType\28char\20const*\2c\20char\20const*\2c\20SkSL::Type::TypeKind\29 +1263:SkSL::Swizzle::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29 +1264:SkSL::RP::Builder::push_slots_or_immutable\28SkSL::RP::SlotRange\2c\20SkSL::RP::BuilderOp\29 +1265:SkSL::RP::Builder::push_duplicates\28int\29 +1266:SkSL::RP::Builder::push_constant_f\28float\29 +1267:SkSL::RP::Builder::push_clone\28int\2c\20int\29 +1268:SkSL::Parser::statementOrNop\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +1269:SkSL::Literal::Make\28SkSL::Position\2c\20double\2c\20SkSL::Type\20const*\29 +1270:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mul\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +1271:SkSL::InlineCandidateAnalyzer::visitStatement\28std::__2::unique_ptr>*\2c\20bool\29 +1272:SkSL::GLSLCodeGenerator::writeModifiers\28SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20bool\29 +1273:SkSL::Expression::isIntLiteral\28\29\20const +1274:SkSL::ConstructorCompound::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +1275:SkSL::ConstantFolder::IsConstantSplat\28SkSL::Expression\20const&\2c\20double\29 +1276:SkSL::Analysis::IsSameExpressionTree\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +1277:SkSL::AliasType::resolve\28\29\20const +1278:SkResourceCache::Find\28SkResourceCache::Key\20const&\2c\20bool\20\28*\29\28SkResourceCache::Rec\20const&\2c\20void*\29\2c\20void*\29 +1279:SkResourceCache::Add\28SkResourceCache::Rec*\2c\20void*\29 +1280:SkRectPriv::HalfWidth\28SkRect\20const&\29 +1281:SkRect::isFinite\28\29\20const +1282:SkRasterPipeline_<256ul>::SkRasterPipeline_\28\29 +1283:SkRasterPipeline::appendConstantColor\28SkArenaAlloc*\2c\20float\20const*\29 +1284:SkRasterClip::setRect\28SkIRect\20const&\29 +1285:SkRasterClip::quickContains\28SkIRect\20const&\29\20const +1286:SkRRect::setRect\28SkRect\20const&\29 +1287:SkPathWriter::isClosed\28\29\20const +1288:SkPathStroker::addDegenerateLine\28SkQuadConstruct\20const*\29 +1289:SkPathBuilder::moveTo\28SkPoint\29 +1290:SkPath::swap\28SkPath&\29 +1291:SkPath::getGenerationID\28\29\20const +1292:SkPath::addPoly\28SkPoint\20const*\2c\20int\2c\20bool\29 +1293:SkOpSegment::existing\28double\2c\20SkOpSegment\20const*\29\20const +1294:SkOpSegment::addT\28double\29 +1295:SkOpSegment::addCurveTo\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkPathWriter*\29\20const +1296:SkOpPtT::find\28SkOpSegment\20const*\29\20const +1297:SkOpContourBuilder::flush\28\29 +1298:SkNVRefCnt::unref\28\29\20const +1299:SkNVRefCnt::unref\28\29\20const +1300:SkMipmap::getLevel\28int\2c\20SkMipmap::Level*\29\20const +1301:SkMatrix::isFinite\28\29\20const +1302:SkM44::setConcat\28SkM44\20const&\2c\20SkM44\20const&\29 +1303:SkImage_Picture::type\28\29\20const +1304:SkImageInfoIsValid\28SkImageInfo\20const&\29 +1305:SkImageInfo::makeColorType\28SkColorType\29\20const +1306:SkImageInfo::computeByteSize\28unsigned\20long\29\20const +1307:SkImageInfo::SkImageInfo\28SkImageInfo\20const&\29 +1308:SkImageFilter_Base::SkImageFilter_Base\28sk_sp\20const*\2c\20int\2c\20std::__2::optional\29 +1309:SkGlyph::imageSize\28\29\20const +1310:SkColorSpaceXformSteps::apply\28SkRasterPipeline*\29\20const +1311:SkColorSpace::gammaIsLinear\28\29\20const +1312:SkColorFilterBase::affectsTransparentBlack\28\29\20const +1313:SkCanvas::~SkCanvas\28\29 +1314:SkCanvas::predrawNotify\28bool\29 +1315:SkCanvas::drawImage\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +1316:SkCanvas::aboutToDraw\28SkPaint\20const&\2c\20SkRect\20const*\2c\20SkEnumBitMask\29 +1317:SkBlockAllocator::SkBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\2c\20unsigned\20long\29 +1318:SkBlockAllocator::BlockIter::begin\28\29\20const +1319:SkBitmap::reset\28\29 +1320:SkBitmap::installPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29 +1321:ScalarToAlpha\28float\29 +1322:OT::Layout::GSUB_impl::SubstLookupSubTable*\20hb_serialize_context_t::push\28\29 +1323:OT::Layout::GPOS_impl::PosLookupSubTable\20const&\20OT::Lookup::get_subtable\28unsigned\20int\29\20const +1324:OT::ArrayOf\2c\20true>\2c\20OT::IntType>*\20hb_serialize_context_t::extend_size\2c\20true>\2c\20OT::IntType>>\28OT::ArrayOf\2c\20true>\2c\20OT::IntType>*\2c\20unsigned\20long\2c\20bool\29 +1325:GrTriangulator::makeConnectingEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\2c\20int\29 +1326:GrTriangulator::appendPointToContour\28SkPoint\20const&\2c\20GrTriangulator::VertexList*\29\20const +1327:GrSurface::ComputeSize\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20bool\29 +1328:GrStyledShape::writeUnstyledKey\28unsigned\20int*\29\20const +1329:GrStyledShape::unstyledKeySize\28\29\20const +1330:GrStyle::operator=\28GrStyle\20const&\29 +1331:GrStyle::GrStyle\28SkStrokeRec\20const&\2c\20sk_sp\29 +1332:GrStyle::GrStyle\28SkPaint\20const&\29 +1333:GrSimpleMesh::setIndexed\28sk_sp\2c\20int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20GrPrimitiveRestart\2c\20sk_sp\2c\20int\29 +1334:GrRecordingContextPriv::makeSFCWithFallback\28GrImageInfo\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +1335:GrRecordingContextPriv::makeSC\28GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +1336:GrQuad::MakeFromSkQuad\28SkPoint\20const*\2c\20SkMatrix\20const&\29 +1337:GrProcessorSet::visitProxies\28std::__2::function\20const&\29\20const +1338:GrProcessorSet::finalize\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrCaps\20const&\2c\20GrClampType\2c\20SkRGBA4f<\28SkAlphaType\292>*\29 +1339:GrGpuResource::isPurgeable\28\29\20const +1340:GrGpuResource::gpuMemorySize\28\29\20const +1341:GrGpuBuffer::updateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +1342:GrGetColorTypeDesc\28GrColorType\29 +1343:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\29 +1344:GrGLSLShaderBuilder::~GrGLSLShaderBuilder\28\29 +1345:GrGLSLShaderBuilder::declAppend\28GrShaderVar\20const&\29 +1346:GrGLGpu::flushScissorTest\28GrScissorTest\29 +1347:GrGLGpu::didDrawTo\28GrRenderTarget*\29 +1348:GrGLGpu::bindFramebuffer\28unsigned\20int\2c\20unsigned\20int\29 +1349:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int*\29 +1350:GrGLCaps::maxRenderTargetSampleCount\28GrGLFormat\29\20const +1351:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\29 +1352:GrDefaultGeoProcFactory::Make\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +1353:GrCaps::validateSurfaceParams\28SkISize\20const&\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20GrTextureType\29\20const +1354:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29::$_0::operator\28\29\28SkIRect\2c\20SkIRect\29\20const +1355:GrBackendTexture::~GrBackendTexture\28\29 +1356:GrAppliedClip::GrAppliedClip\28GrAppliedClip&&\29 +1357:GrAAConvexTessellator::Ring::origEdgeID\28int\29\20const +1358:FT_GlyphLoader_CheckPoints +1359:FT_Get_Sfnt_Table +1360:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +1361:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::end\28\29\20const +1362:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::Item::operator++\28\29 +1363:AAT::Lookup>::get_class\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +1364:void\20std::__2::reverse\5babi:nn180100\5d\28char*\2c\20char*\29 +1365:void\20std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__rehash\28unsigned\20long\29 +1366:void\20SkTQSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29::operator\28\29\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29\20const +1367:void\20SkSafeUnref\28GrThreadSafeCache::VertexData*\29 +1368:unsigned\20int\20hb_buffer_t::group_end\28unsigned\20int\2c\20bool\20\20const\28&\29\28hb_glyph_info_t\20const&\2c\20hb_glyph_info_t\20const&\29\29\20const +1369:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +1370:std::__2::vector>\2c\20std::__2::allocator>>>::push_back\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +1371:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +1372:std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20std::__2::default_delete\2c\20std::__2::allocator>>>::~unique_ptr\5babi:ne180100\5d\28\29 +1373:std::__2::unique_ptr\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap\20\28*\29\28SkReadBuffer&\29\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +1374:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::SymbolTable*\29 +1375:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1376:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1377:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ios_base&\2c\20wchar_t\29 +1378:std::__2::ostreambuf_iterator>\20std::__2::__pad_and_output\5babi:nn180100\5d>\28std::__2::ostreambuf_iterator>\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ios_base&\2c\20char\29 +1379:std::__2::hash::operator\28\29\5babi:ne180100\5d\28GrFragmentProcessor\20const*\29\20const +1380:std::__2::char_traits::to_int_type\5babi:nn180100\5d\28char\29 +1381:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +1382:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::allocator\20const&\29 +1383:std::__2::basic_string\2c\20std::__2::allocator>::append\28char\20const*\2c\20unsigned\20long\29 +1384:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1385:std::__2::basic_string\2c\20std::__2::allocator>::__get_long_cap\5babi:nn180100\5d\28\29\20const +1386:std::__2::basic_ios>::setstate\5babi:nn180100\5d\28unsigned\20int\29 +1387:skvx::Vec<4\2c\20unsigned\20short>\20\28anonymous\20namespace\29::add_121>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +1388:skvx::Vec<4\2c\20unsigned\20int>\20\28anonymous\20namespace\29::add_121>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1389:skvx::Vec<4\2c\20float>\20unchecked_mix<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1390:skvx::Vec<4\2c\20float>\20skvx::operator/<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1391:skvx::Vec<4\2c\20float>\20skvx::min<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1392:skvx::Vec<4\2c\20float>&\20skvx::operator*=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1393:skvx::Vec<2\2c\20float>\20skvx::naive_if_then_else<2\2c\20float>\28skvx::Vec<2\2c\20skvx::Mask::type>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +1394:skip_spaces +1395:skia_private::THashMap::find\28SkSL::Variable\20const*\20const&\29\20const +1396:skia_private::TArray::push_back\28unsigned\20char&&\29 +1397:skia_private::TArray::TArray\28skia_private::TArray&&\29 +1398:skia_private::TArray::TArray\28skia_private::TArray&&\29 +1399:skia_private::TArray\2c\20true>::preallocateNewData\28int\2c\20double\29 +1400:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +1401:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1402:skia_private::FixedArray<4\2c\20signed\20char>::FixedArray\28std::initializer_list\29 +1403:skia_private::AutoSTMalloc<4ul\2c\20int\2c\20void>::AutoSTMalloc\28unsigned\20long\29 +1404:skia_png_safecat +1405:skia_png_malloc +1406:skia_png_colorspace_sync +1407:skia_png_chunk_warning +1408:skia::textlayout::TextWrapper::TextStretch::extend\28skia::textlayout::TextWrapper::TextStretch&\29 +1409:skia::textlayout::TextLine::iterateThroughSingleRunByStyles\28skia::textlayout::TextLine::TextAdjustment\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::StyleType\2c\20std::__2::function\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\20const&\29\20const +1410:skia::textlayout::ParagraphStyle::~ParagraphStyle\28\29 +1411:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29 +1412:skgpu::ganesh::SurfaceFillContext::fillWithFP\28std::__2::unique_ptr>\29 +1413:skgpu::ganesh::OpsTask::OpChain::List::popHead\28\29 +1414:skgpu::SkSLToGLSL\28SkSL::ShaderCaps\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20skgpu::ShaderErrorHandler*\29 +1415:skgpu::ResourceKey::reset\28\29 +1416:skcms_TransferFunction_getType +1417:skcms_TransferFunction_eval +1418:sk_sp::~sk_sp\28\29 +1419:sk_sp::reset\28SkString::Rec*\29 +1420:sk_sp::operator=\28sk_sp\20const&\29 +1421:sk_sp::operator=\28sk_sp&&\29 +1422:operator!=\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +1423:operator!=\28SkIRect\20const&\2c\20SkIRect\20const&\29 +1424:is_halant\28hb_glyph_info_t\20const&\29 +1425:hb_zip_iter_t\2c\20hb_array_t>::__next__\28\29 +1426:hb_serialize_context_t::pop_pack\28bool\29 +1427:hb_sanitize_context_t::init\28hb_blob_t*\29 +1428:hb_lazy_loader_t\2c\20hb_face_t\2c\2011u\2c\20hb_blob_t>::get\28\29\20const +1429:hb_lazy_loader_t\2c\20hb_face_t\2c\204u\2c\20hb_blob_t>::get\28\29\20const +1430:hb_lazy_loader_t\2c\20hb_face_t\2c\2025u\2c\20OT::GSUB_accelerator_t>::get_stored\28\29\20const +1431:hb_hashmap_t::alloc\28unsigned\20int\29 +1432:hb_font_t::scale_glyph_extents\28hb_glyph_extents_t*\29 +1433:hb_extents_t::add_point\28float\2c\20float\29 +1434:hb_draw_funcs_t::emit_cubic_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +1435:hb_buffer_t::reverse_range\28unsigned\20int\2c\20unsigned\20int\29 +1436:hb_buffer_t::replace_glyph\28unsigned\20int\29 +1437:hb_buffer_t::merge_out_clusters\28unsigned\20int\2c\20unsigned\20int\29 +1438:hb_buffer_destroy +1439:hb_buffer_append +1440:cos +1441:cleanup_program\28GrGLGpu*\2c\20unsigned\20int\2c\20SkTDArray\20const&\29 +1442:cff_index_done +1443:cf2_glyphpath_curveTo +1444:bool\20hb_array_t::sanitize\28hb_sanitize_context_t*\29\20const +1445:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1446:auto\20std::__2::__unwrap_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\29 +1447:afm_parser_read_vals +1448:afm_parser_next_key +1449:_emscripten_yield +1450:__memset +1451:__lshrti3 +1452:__letf2 +1453:\28anonymous\20namespace\29::skhb_position\28float\29 +1454:SkWriter32::reservePad\28unsigned\20long\29 +1455:SkTSpan::removeBounded\28SkTSpan\20const*\29 +1456:SkTSpan::initBounds\28SkTCurve\20const&\29 +1457:SkTSpan::addBounded\28SkTSpan*\2c\20SkArenaAlloc*\29 +1458:SkTSect::tail\28\29 +1459:SkTDStorage::reset\28\29 +1460:SkString::printf\28char\20const*\2c\20...\29 +1461:SkString::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +1462:SkShaders::Color\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\29 +1463:SkShader::makeWithLocalMatrix\28SkMatrix\20const&\29\20const +1464:SkSamplingOptions::operator==\28SkSamplingOptions\20const&\29\20const +1465:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_5::operator\28\29\28int\2c\20int\29\20const +1466:SkSL::is_constant_value\28SkSL::Expression\20const&\2c\20double\29 +1467:SkSL::\28anonymous\20namespace\29::ReturnsOnAllPathsVisitor::visitStatement\28SkSL::Statement\20const&\29 +1468:SkSL::Type::MakeScalarType\28std::__2::basic_string_view>\2c\20char\20const*\2c\20SkSL::Type::NumberKind\2c\20signed\20char\2c\20signed\20char\29 +1469:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Context\20const&\2c\20SkSL::Symbol*\29 +1470:SkSL::RP::Generator::push\28SkSL::RP::LValue&\29 +1471:SkSL::PipelineStage::PipelineStageCodeGenerator::writeLine\28std::__2::basic_string_view>\29 +1472:SkSL::Parser::statement\28bool\29 +1473:SkSL::ModifierFlags::description\28\29\20const +1474:SkSL::Layout::paddedDescription\28\29\20const +1475:SkSL::ConstructorCompoundCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1476:SkSL::Analysis::UpdateVariableRefKind\28SkSL::Expression*\2c\20SkSL::VariableRefKind\2c\20SkSL::ErrorReporter*\29 +1477:SkRegion::Iterator::next\28\29 +1478:SkRect::round\28SkIRect*\29\20const +1479:SkRect::makeSorted\28\29\20const +1480:SkRect::intersects\28SkRect\20const&\29\20const +1481:SkReadBuffer::readInt\28\29 +1482:SkReadBuffer::readBool\28\29 +1483:SkRasterPipeline_<256ul>::~SkRasterPipeline_\28\29 +1484:SkRasterClip::updateCacheAndReturnNonEmpty\28bool\29 +1485:SkRasterClip::quickReject\28SkIRect\20const&\29\20const +1486:SkPixmap::addr\28int\2c\20int\29\20const +1487:SkPath::incReserve\28int\2c\20int\2c\20int\29 +1488:SkPath::arcTo\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +1489:SkPath::addRect\28SkRect\20const&\2c\20SkPathDirection\29 +1490:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\29 +1491:SkPaint*\20SkRecorder::copy\28SkPaint\20const*\29 +1492:SkOpSegment::ptAtT\28double\29\20const +1493:SkOpSegment::dPtAtT\28double\29\20const +1494:SkNoPixelsDevice::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +1495:SkMemoryStream::getPosition\28\29\20const +1496:SkMatrix::setConcat\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +1497:SkMatrix::mapRadius\28float\29\20const +1498:SkMask::getAddr8\28int\2c\20int\29\20const +1499:SkIntersectionHelper::segmentType\28\29\20const +1500:SkImageFilter_Base::flatten\28SkWriteBuffer&\29\20const +1501:SkGoodHash::operator\28\29\28SkString\20const&\29\20const +1502:SkGlyph::rect\28\29\20const +1503:SkFont::SkFont\28sk_sp\2c\20float\29 +1504:SkDynamicMemoryWStream::write\28void\20const*\2c\20unsigned\20long\29 +1505:SkDrawBase::SkDrawBase\28\29 +1506:SkDescriptor::operator==\28SkDescriptor\20const&\29\20const +1507:SkDQuad::RootsValidT\28double\2c\20double\2c\20double\2c\20double*\29 +1508:SkConvertPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +1509:SkCanvas::restore\28\29 +1510:SkCanvas::drawImageRect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +1511:SkCanvas::AutoUpdateQRBounds::~AutoUpdateQRBounds\28\29 +1512:SkCachedData::ref\28\29\20const +1513:SkBulkGlyphMetrics::~SkBulkGlyphMetrics\28\29 +1514:SkBulkGlyphMetrics::SkBulkGlyphMetrics\28SkStrikeSpec\20const&\29 +1515:SkBitmap::setPixelRef\28sk_sp\2c\20int\2c\20int\29 +1516:SkBitmap::installPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\29 +1517:SkAutoPixmapStorage::~SkAutoPixmapStorage\28\29 +1518:SkAlphaRuns::Break\28short*\2c\20unsigned\20char*\2c\20int\2c\20int\29 +1519:OT::VariationStore::get_delta\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +1520:OT::GSUBGPOS::get_lookup\28unsigned\20int\29\20const +1521:OT::GDEF::get_glyph_props\28unsigned\20int\29\20const +1522:OT::CmapSubtable::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +1523:GrTriangulator::EdgeList::insert\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +1524:GrSurfaceProxyView::mipmapped\28\29\20const +1525:GrSurfaceProxy::backingStoreBoundsRect\28\29\20const +1526:GrStyledShape::knownToBeConvex\28\29\20const +1527:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +1528:GrSimpleMeshDrawOpHelperWithStencil::isCompatible\28GrSimpleMeshDrawOpHelperWithStencil\20const&\2c\20GrCaps\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20bool\29\20const +1529:GrShape::asPath\28SkPath*\2c\20bool\29\20const +1530:GrScissorState::set\28SkIRect\20const&\29 +1531:GrRenderTask::~GrRenderTask\28\29 +1532:GrPixmap::Allocate\28GrImageInfo\20const&\29 +1533:GrMakeCachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\29 +1534:GrImageInfo::makeColorType\28GrColorType\29\20const +1535:GrGpuResource::CacheAccess::release\28\29 +1536:GrGpuBuffer::map\28\29 +1537:GrGpu::didWriteToSurface\28GrSurface*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const*\2c\20unsigned\20int\29\20const +1538:GrGeometryProcessor::TextureSampler::TextureSampler\28\29 +1539:GrGeometryProcessor::AttributeSet::begin\28\29\20const +1540:GrGeometryProcessor::AttributeSet::Iter::operator++\28\29 +1541:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20int\2c\20int\2c\20int\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +1542:GrConvertPixels\28GrPixmap\20const&\2c\20GrCPixmap\20const&\2c\20bool\29 +1543:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +1544:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +1545:GrAtlasManager::getAtlas\28skgpu::MaskFormat\29\20const +1546:FT_Get_Char_Index +1547:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +1548:1339 +1549:write_buf +1550:wrapper_cmp +1551:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d\2c\20std::__2::tuple\2c\20GrFragmentProcessor\20const*\2c\20GrGeometryProcessor::ProgramImpl::TransformInfo\2c\200ul\2c\201ul>\28std::__2::tuple&\2c\20std::__2::tuple&&\2c\20std::__2::__tuple_types\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +1552:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20unsigned\20int*&\2c\20unsigned\20int*&\29 +1553:unsigned\20long\20const&\20std::__2::max\5babi:nn180100\5d\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29 +1554:toupper +1555:store\28unsigned\20char*\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20int\29 +1556:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +1557:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +1558:std::__2::unique_ptr::~unique_ptr\5babi:ne180100\5d\28\29 +1559:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skia::textlayout::Run*\29 +1560:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1561:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1562:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1563:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +1564:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1565:std::__2::numpunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +1566:std::__2::istreambuf_iterator>::istreambuf_iterator\5babi:nn180100\5d\28\29 +1567:std::__2::enable_if::value\2c\20sk_sp>::type\20GrResourceProvider::findByUniqueKey\28skgpu::UniqueKey\20const&\29 +1568:std::__2::deque>::end\5babi:ne180100\5d\28\29 +1569:std::__2::ctype::narrow\5babi:nn180100\5d\28wchar_t\2c\20char\29\20const +1570:std::__2::ctype::narrow\5babi:nn180100\5d\28char\2c\20char\29\20const +1571:std::__2::basic_string\2c\20std::__2::allocator>::__recommend\5babi:nn180100\5d\28unsigned\20long\29 +1572:std::__2::basic_string\2c\20std::__2::allocator>\20std::__2::operator+\5babi:ne180100\5d\2c\20std::__2::allocator>\28std::__2::basic_string\2c\20std::__2::allocator>&&\2c\20char\29 +1573:std::__2::basic_string\2c\20std::__2::allocator>::~basic_string\28\29 +1574:std::__2::basic_streambuf>::sputn\5babi:nn180100\5d\28char\20const*\2c\20long\29 +1575:std::__2::basic_streambuf>::setg\5babi:nn180100\5d\28char*\2c\20char*\2c\20char*\29 +1576:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +1577:std::__2::__tree\2c\20std::__2::__map_value_compare\2c\20std::__2::less\2c\20true>\2c\20std::__2::allocator>>::destroy\28std::__2::__tree_node\2c\20void*>*\29 +1578:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +1579:std::__2::__num_get::__stage2_int_loop\28wchar_t\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20wchar_t\20const*\29 +1580:std::__2::__num_get::__stage2_int_loop\28char\2c\20int\2c\20char*\2c\20char*&\2c\20unsigned\20int&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20char\20const*\29 +1581:std::__2::__next_prime\28unsigned\20long\29 +1582:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1583:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::allocator&\2c\20unsigned\20long\29 +1584:src_p\28unsigned\20char\2c\20unsigned\20char\29 +1585:sort_r_swap\28char*\2c\20char*\2c\20unsigned\20long\29 +1586:skvx::Vec<4\2c\20float>\20skvx::operator+<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +1587:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20int\2c\20void>\28int\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.7132\29 +1588:sktext::SkStrikePromise::SkStrikePromise\28sktext::SkStrikePromise&&\29 +1589:skif::\28anonymous\20namespace\29::downscale_step_count\28float\29 +1590:skif::LayerSpace::mapRect\28skif::LayerSpace\20const&\29\20const +1591:skif::LayerSpace::relevantSubset\28skif::LayerSpace\2c\20SkTileMode\29\20const +1592:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::resize\28int\29 +1593:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Hash\28std::__2::basic_string_view>\20const&\29 +1594:skia_private::THashTable::AdaptedTraits>::Hash\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +1595:skia_private::THashSet::contains\28SkSL::Variable\20const*\20const&\29\20const +1596:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1597:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +1598:skia_private::TArray\2c\20true>::~TArray\28\29 +1599:skia_private::TArray::copy\28float\20const*\29 +1600:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +1601:skia_private::TArray::resize_back\28int\29 +1602:skia_private::AutoTMalloc::AutoTMalloc\28unsigned\20long\29 +1603:skia_private::AutoSTArray<4\2c\20float>::reset\28int\29 +1604:skia_png_free_data +1605:skia::textlayout::TextStyle::TextStyle\28\29 +1606:skia::textlayout::Run::Run\28skia::textlayout::ParagraphImpl*\2c\20SkShaper::RunHandler::RunInfo\20const&\2c\20unsigned\20long\2c\20float\2c\20bool\2c\20float\2c\20unsigned\20long\2c\20float\29 +1607:skia::textlayout::InternalLineMetrics::delta\28\29\20const +1608:skia::textlayout::Cluster::Cluster\28skia::textlayout::ParagraphImpl*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkSpan\2c\20float\2c\20float\29 +1609:skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\294>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\298>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::ReplicateLineEndPoints\2c\20skgpu::tess::TrackJoinControlPoints>::chopAndWriteCubics\28skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20skvx::Vec<2\2c\20float>\2c\20int\29 +1610:skgpu::ganesh::SurfaceDrawContext::fillRectToRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +1611:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::RawElement\20const&\29\20const +1612:skgpu::VertexWriter&\20skgpu::operator<<<4\2c\20SkPoint>\28skgpu::VertexWriter&\2c\20skgpu::VertexWriter::RepeatDesc<4\2c\20SkPoint>\20const&\29 +1613:skgpu::TAsyncReadResult::addCpuPlane\28sk_sp\2c\20unsigned\20long\29 +1614:skgpu::Swizzle::RGB1\28\29 +1615:sk_sp::reset\28SkPathRef*\29 +1616:sk_sp::reset\28SkMeshPriv::VB\20const*\29 +1617:sk_malloc_throw\28unsigned\20long\29 +1618:sk_doubles_nearly_equal_ulps\28double\2c\20double\2c\20unsigned\20char\29 +1619:sbrk +1620:quick_div\28int\2c\20int\29 +1621:processPropertySeq\28UBiDi*\2c\20LevState*\2c\20unsigned\20char\2c\20int\2c\20int\29 +1622:memchr +1623:left\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1624:inversion\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::Comparator\20const&\29 +1625:interp_quad_coords\28double\20const*\2c\20double\29 +1626:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +1627:hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>::may_have\28unsigned\20int\29\20const +1628:hb_serialize_context_t::object_t::fini\28\29 +1629:hb_ot_map_builder_t::add_feature\28hb_ot_map_feature_t\20const&\29 +1630:hb_lazy_loader_t\2c\20hb_face_t\2c\2015u\2c\20OT::glyf_accelerator_t>::get_stored\28\29\20const +1631:hb_hashmap_t::fini\28\29 +1632:hb_buffer_t::make_room_for\28unsigned\20int\2c\20unsigned\20int\29 +1633:hb_buffer_t::ensure\28unsigned\20int\29 +1634:hairquad\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +1635:fmt_u +1636:float*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29 +1637:duplicate_pt\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1638:compute_quad_level\28SkPoint\20const*\29 +1639:compute_ULong_sum +1640:cff2_extents_param_t::update_bounds\28CFF::point_t\20const&\29 +1641:cf2_glyphpath_hintPoint +1642:cf2_arrstack_getPointer +1643:cbrtf +1644:can_add_curve\28SkPath::Verb\2c\20SkPoint*\29 +1645:call_hline_blitter\28SkBlitter*\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\29 +1646:bounds_t::update\28CFF::point_t\20const&\29 +1647:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\29\20const +1648:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\29\20const +1649:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1650:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1651:atan2f +1652:af_shaper_get_cluster +1653:_hb_ot_metrics_get_position_common\28hb_font_t*\2c\20hb_ot_metrics_tag_t\2c\20int*\29 +1654:__tandf +1655:__floatunsitf +1656:__cxa_allocate_exception +1657:_ZZNK6sktext3gpu12VertexFiller14fillVertexDataEii6SkSpanIPKNS0_5GlyphEEjRK8SkMatrix7SkIRectPvENK3$_0clIPA4_NS0_12Mask2DVertexEEEDaT_ +1658:\28anonymous\20namespace\29::subtract\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +1659:\28anonymous\20namespace\29::MeshOp::fixedFunctionFlags\28\29\20const +1660:\28anonymous\20namespace\29::DrawAtlasOpImpl::fixedFunctionFlags\28\29\20const +1661:Update_Max +1662:TT_Get_MM_Var +1663:SkWriteBuffer::writeDataAsByteArray\28SkData\20const*\29 +1664:SkUTF::UTF8ToUTF16\28unsigned\20short*\2c\20int\2c\20char\20const*\2c\20unsigned\20long\29 +1665:SkTextBlob::RunRecord::textSize\28\29\20const +1666:SkTSpan::resetBounds\28SkTCurve\20const&\29 +1667:SkTSect::removeSpan\28SkTSpan*\29 +1668:SkTSect::BinarySearch\28SkTSect*\2c\20SkTSect*\2c\20SkIntersections*\29 +1669:SkTInternalLList::remove\28skgpu::Plot*\29 +1670:SkTInternalLList>\2c\20SkGoodHash\2c\20SkNoOpPurge>::Entry>::remove\28SkLRUCache>\2c\20SkGoodHash\2c\20SkNoOpPurge>::Entry*\29 +1671:SkTDArray::append\28\29 +1672:SkTConic::operator\5b\5d\28int\29\20const +1673:SkTBlockList::~SkTBlockList\28\29 +1674:SkStrokeRec::needToApply\28\29\20const +1675:SkStrokeRec::SkStrokeRec\28SkPaint\20const&\2c\20float\29 +1676:SkString::set\28char\20const*\2c\20unsigned\20long\29 +1677:SkString::SkString\28char\20const*\2c\20unsigned\20long\29 +1678:SkStrikeSpec::findOrCreateStrike\28\29\20const +1679:SkStrike::digestFor\28skglyph::ActionType\2c\20SkPackedGlyphID\29 +1680:SkSpecialImages::MakeDeferredFromGpu\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20unsigned\20int\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1681:SkShaders::MatrixRec::applyForFragmentProcessor\28SkMatrix\20const&\29\20const +1682:SkScan::FillRect\28SkRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +1683:SkScalerContext_FreeType::setupSize\28\29 +1684:SkSL::type_is_valid_for_color\28SkSL::Type\20const&\29 +1685:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_4::operator\28\29\28int\29\20const +1686:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_3::operator\28\29\28int\29\20const +1687:SkSL::optimize_comparison\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20bool\20\28*\29\28double\2c\20double\29\29 +1688:SkSL::VariableReference::Make\28SkSL::Position\2c\20SkSL::Variable\20const*\2c\20SkSL::VariableRefKind\29 +1689:SkSL::Variable*\20SkSL::SymbolTable::add\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +1690:SkSL::Type::coercionCost\28SkSL::Type\20const&\29\20const +1691:SkSL::SymbolTable::addArrayDimension\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20int\29 +1692:SkSL::String::appendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20...\29 +1693:SkSL::RP::VariableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +1694:SkSL::RP::Program::appendCopySlotsUnmasked\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +1695:SkSL::RP::Generator::pushBinaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +1696:SkSL::RP::Generator::emitTraceLine\28SkSL::Position\29 +1697:SkSL::RP::AutoStack::enter\28\29 +1698:SkSL::PipelineStage::PipelineStageCodeGenerator::writeStatement\28SkSL::Statement\20const&\29 +1699:SkSL::Operator::determineBinaryType\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\2c\20SkSL::Type\20const**\29\20const +1700:SkSL::GLSLCodeGenerator::getTypePrecision\28SkSL::Type\20const&\29 +1701:SkSL::ExpressionStatement::Make\28SkSL::Context\20const&\2c\20std::__2::unique_ptr>\29 +1702:SkSL::ConstructorDiagonalMatrix::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +1703:SkSL::ConstructorArrayCast::~ConstructorArrayCast\28\29 +1704:SkSL::ConstantFolder::MakeConstantValueForVariable\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +1705:SkSBlockAllocator<64ul>::SkSBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\29 +1706:SkRuntimeEffectBuilder::writableUniformData\28\29 +1707:SkRuntimeEffect::uniformSize\28\29\20const +1708:SkResourceCache::Key::init\28void*\2c\20unsigned\20long\20long\2c\20unsigned\20long\29 +1709:SkRegion::op\28SkRegion\20const&\2c\20SkRegion::Op\29 +1710:SkRasterPipelineBlitter::appendStore\28SkRasterPipeline*\29\20const +1711:SkRasterPipeline::compile\28\29\20const +1712:SkRasterPipeline::appendClampIfNormalized\28SkImageInfo\20const&\29 +1713:SkRasterClipStack::writable_rc\28\29 +1714:SkRRect::transform\28SkMatrix\20const&\2c\20SkRRect*\29\20const +1715:SkRGBA4f<\28SkAlphaType\293>::toSkColor\28\29\20const +1716:SkPointPriv::EqualsWithinTolerance\28SkPoint\20const&\2c\20SkPoint\20const&\29 +1717:SkPoint::Length\28float\2c\20float\29 +1718:SkPixmap::operator=\28SkPixmap&&\29 +1719:SkPathWriter::matchedLast\28SkOpPtT\20const*\29\20const +1720:SkPathWriter::finishContour\28\29 +1721:SkPathRef::atVerb\28int\29\20const +1722:SkPathEdgeIter::next\28\29 +1723:SkPathBuilder::ensureMove\28\29 +1724:SkPathBuilder::close\28\29 +1725:SkPath::addPath\28SkPath\20const&\2c\20SkPath::AddPathMode\29 +1726:SkPaint::operator=\28SkPaint\20const&\29 +1727:SkPaint::isSrcOver\28\29\20const +1728:SkOpSpanBase::contains\28SkOpSegment\20const*\29\20const +1729:SkOpSegment::updateWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +1730:SkOpAngle::linesOnOriginalSide\28SkOpAngle\20const*\29 +1731:SkNoPixelsDevice::writableClip\28\29 +1732:SkNextID::ImageID\28\29 +1733:SkMatrixPriv::MapRect\28SkM44\20const&\2c\20SkRect\20const&\29 +1734:SkMatrix::mapVectors\28SkPoint*\2c\20int\29\20const +1735:SkMaskBuilder::AllocImage\28unsigned\20long\2c\20SkMaskBuilder::AllocType\29 +1736:SkMask::computeImageSize\28\29\20const +1737:SkMask::AlphaIter<\28SkMask::Format\294>::operator*\28\29\20const +1738:SkMakeImageFromRasterBitmap\28SkBitmap\20const&\2c\20SkCopyPixelsMode\29 +1739:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_2D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1740:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_blur_1D_effect\28int\2c\20SkRuntimeEffect::Options\20const&\29 +1741:SkKnownRuntimeEffects::GetKnownRuntimeEffect\28SkKnownRuntimeEffects::StableKey\29 +1742:SkJSONWriter::endObject\28\29 +1743:SkJSONWriter::beginObject\28char\20const*\2c\20bool\29 +1744:SkJSONWriter::appendName\28char\20const*\29 +1745:SkIntersections::flip\28\29 +1746:SkImageFilter::getInput\28int\29\20const +1747:SkIRect\20skif::Mapping::map\28SkIRect\20const&\2c\20SkMatrix\20const&\29 +1748:SkIRect::outset\28int\2c\20int\29 +1749:SkIDChangeListener::List::changed\28\29 +1750:SkFont::unicharToGlyph\28int\29\20const +1751:SkDrawTiler::~SkDrawTiler\28\29 +1752:SkDrawTiler::next\28\29 +1753:SkDrawTiler::SkDrawTiler\28SkBitmapDevice*\2c\20SkRect\20const*\29 +1754:SkDrawBase::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29\20const +1755:SkData::MakeEmpty\28\29 +1756:SkDRect::add\28SkDPoint\20const&\29 +1757:SkDCubic::FindExtrema\28double\20const*\2c\20double*\29 +1758:SkConic::chopAt\28float\2c\20SkConic*\29\20const +1759:SkColorFilters::Blend\28unsigned\20int\2c\20SkBlendMode\29 +1760:SkColorFilter::makeComposed\28sk_sp\29\20const +1761:SkCanvas::saveLayer\28SkRect\20const*\2c\20SkPaint\20const*\29 +1762:SkCanvas::getTotalMatrix\28\29\20const +1763:SkCanvas::computeDeviceClipBounds\28bool\29\20const +1764:SkBlurEngine::SigmaToRadius\28float\29 +1765:SkBlockAllocator::ByteRange\20SkBlockAllocator::allocate<4ul\2c\200ul>\28unsigned\20long\29 +1766:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29 +1767:SkAutoSMalloc<1024ul>::SkAutoSMalloc\28unsigned\20long\29 +1768:RunBasedAdditiveBlitter::checkY\28int\29 +1769:RoughlyEqualUlps\28double\2c\20double\29 +1770:Read255UShort +1771:PS_Conv_ToFixed +1772:OT::post::accelerator_t::cmp_gids\28void\20const*\2c\20void\20const*\2c\20void*\29 +1773:OT::hmtxvmtx::accelerator_t::get_advance_without_var_unscaled\28unsigned\20int\29\20const +1774:OT::Layout::GPOS_impl::ValueFormat::apply_value\28OT::hb_ot_apply_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\2c\20hb_glyph_position_t&\29\20const +1775:GrTriangulator::VertexList::remove\28GrTriangulator::Vertex*\29 +1776:GrTriangulator::Vertex*\20SkArenaAlloc::make\28SkPoint&\2c\20int&&\29 +1777:GrTriangulator::Poly::addEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Side\2c\20GrTriangulator*\29 +1778:GrTextureEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20float\20const*\2c\20bool\29 +1779:GrSurface::invokeReleaseProc\28\29 +1780:GrSurface::GrSurface\28GrGpu*\2c\20SkISize\20const&\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +1781:GrStyledShape::operator=\28GrStyledShape\20const&\29 +1782:GrSimpleMeshDrawOpHelperWithStencil::createProgramInfoWithStencil\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +1783:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrGeometryProcessor*\2c\20GrProcessorSet&&\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrPipeline::InputFlags\2c\20GrUserStencilSettings\20const*\29 +1784:GrShape::setRRect\28SkRRect\20const&\29 +1785:GrShape::reset\28GrShape::Type\29 +1786:GrResourceProvider::findOrCreatePatternedIndexBuffer\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\2c\20skgpu::UniqueKey\20const&\29 +1787:GrResourceProvider::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\2c\20GrResourceProvider::ZeroInit\29 +1788:GrResourceProvider::assignUniqueKeyToResource\28skgpu::UniqueKey\20const&\2c\20GrGpuResource*\29 +1789:GrRenderTask::addDependency\28GrRenderTask*\29 +1790:GrRenderTask::GrRenderTask\28\29 +1791:GrRenderTarget::onRelease\28\29 +1792:GrQuadUtils::TessellationHelper::Vertices::asGrQuads\28GrQuad*\2c\20GrQuad::Type\2c\20GrQuad*\2c\20GrQuad::Type\29\20const +1793:GrProxyProvider::findOrCreateProxyByUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxy::UseAllocator\29 +1794:GrProxyProvider::assignUniqueKeyToProxy\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\29 +1795:GrPaint::setCoverageFragmentProcessor\28std::__2::unique_ptr>\29 +1796:GrOpFlushState::allocator\28\29 +1797:GrMeshDrawOp::QuadHelper::QuadHelper\28GrMeshDrawTarget*\2c\20unsigned\20long\2c\20int\29 +1798:GrIsStrokeHairlineOrEquivalent\28GrStyle\20const&\2c\20SkMatrix\20const&\2c\20float*\29 +1799:GrImageInfo::minRowBytes\28\29\20const +1800:GrGpuResource::CacheAccess::isUsableAsScratch\28\29\20const +1801:GrGeometryProcessor::ProgramImpl::setupUniformColor\28GrGLSLFPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20GrResourceHandle*\29 +1802:GrGLSLUniformHandler::addUniformArray\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20int\2c\20char\20const**\29 +1803:GrGLSLShaderBuilder::emitFunction\28SkSLType\2c\20char\20const*\2c\20SkSpan\2c\20char\20const*\29 +1804:GrGLSLShaderBuilder::code\28\29 +1805:GrGLOpsRenderPass::bindVertexBuffer\28GrBuffer\20const*\2c\20int\29 +1806:GrGLGpu::unbindSurfaceFBOForPixelOps\28GrSurface*\2c\20int\2c\20unsigned\20int\29 +1807:GrGLGpu::flushRenderTarget\28GrGLRenderTarget*\2c\20bool\29 +1808:GrGLGpu::bindSurfaceFBOForPixelOps\28GrSurface*\2c\20int\2c\20unsigned\20int\2c\20GrGLGpu::TempFBOTarget\29 +1809:GrGLCompileAndAttachShader\28GrGLContext\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20bool\2c\20GrThreadSafePipelineBuilder::Stats*\2c\20skgpu::ShaderErrorHandler*\29 +1810:GrFragmentProcessors::Make\28GrRecordingContext*\2c\20SkColorFilter\20const*\2c\20std::__2::unique_ptr>\2c\20GrColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +1811:GrFragmentProcessor::visitTextureEffects\28std::__2::function\20const&\29\20const +1812:GrFragmentProcessor::MakeColor\28SkRGBA4f<\28SkAlphaType\292>\29 +1813:GrDirectContextPriv::flushSurface\28GrSurfaceProxy*\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +1814:GrBlendFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkBlendMode\2c\20bool\29 +1815:GrBackendFormat::operator=\28GrBackendFormat\20const&\29 +1816:GrAAConvexTessellator::addPt\28SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20GrAAConvexTessellator::CurveState\29 +1817:FT_Outline_Transform +1818:CFF::parsed_values_t::add_op\28unsigned\20int\2c\20CFF::byte_str_ref_t\20const&\2c\20CFF::op_str_t\20const&\29 +1819:CFF::dict_opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +1820:CFF::cs_opset_t\2c\20cff2_extents_param_t\2c\20cff2_path_procs_extents_t>::process_post_move\28unsigned\20int\2c\20CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\29 +1821:CFF::cs_opset_t::process_post_move\28unsigned\20int\2c\20CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\29 +1822:CFF::cs_interp_env_t>>::determine_hintmask_size\28\29 +1823:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::begin\28\29\20const +1824:AlmostBetweenUlps\28double\2c\20double\2c\20double\29 +1825:ActiveEdgeList::SingleRotation\28ActiveEdge*\2c\20int\29 +1826:AAT::StateTable::EntryData>::get_entry\28int\2c\20unsigned\20int\29\20const +1827:AAT::StateTable::EntryData>::get_entry\28int\2c\20unsigned\20int\29\20const +1828:AAT::ContextualSubtable::driver_context_t::is_actionable\28AAT::StateTableDriver::EntryData>*\2c\20AAT::Entry::EntryData>\20const&\29 +1829:1620 +1830:1621 +1831:1622 +1832:1623 +1833:void\20std::__2::__stable_sort\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +1834:void\20std::__2::__split_buffer&>::__construct_at_end\2c\200>\28std::__2::move_iterator\2c\20std::__2::move_iterator\29 +1835:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d>&>\2c\20std::__2::tuple>>\2c\20bool\2c\20std::__2::unique_ptr>\2c\200ul\2c\201ul>\28std::__2::tuple>&>&\2c\20std::__2::tuple>>&&\2c\20std::__2::__tuple_types>>\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +1836:void\20extend_pts<\28SkPaint::Cap\292>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1837:void\20extend_pts<\28SkPaint::Cap\291>\28SkPath::Verb\2c\20SkPath::Verb\2c\20SkPoint*\2c\20int\29 +1838:void\20SkSafeUnref\28SkTextBlob*\29 +1839:void\20SkSafeUnref\28GrTextureProxy*\29 +1840:unsigned\20int*\20SkRecorder::copy\28unsigned\20int\20const*\2c\20unsigned\20long\29 +1841:tt_cmap14_ensure +1842:tanf +1843:std::__2::vector>\2c\20std::__2::allocator>>>::push_back\5babi:ne180100\5d\28std::__2::unique_ptr>&&\29 +1844:std::__2::vector>\2c\20std::__2::allocator>>>::~vector\5babi:ne180100\5d\28\29 +1845:std::__2::vector>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +1846:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +1847:std::__2::unique_ptr>\20\5b\5d\2c\20std::__2::default_delete>\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +1848:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1849:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1850:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1851:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +1852:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrDrawOpAtlas*\29 +1853:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +1854:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char8_t*\2c\20char8_t*\2c\20char8_t*&\29\20const +1855:std::__2::basic_string\2c\20std::__2::allocator>::clear\5babi:ne180100\5d\28\29 +1856:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28char\20const*\29 +1857:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20char\20const*\29 +1858:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +1859:std::__2::basic_string\2c\20std::__2::allocator>::__assign_external\28char\20const*\29 +1860:std::__2::array\2c\204ul>::~array\28\29 +1861:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +1862:std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>::__copy_constructor\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29 +1863:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +1864:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20wchar_t&\29 +1865:std::__2::__num_get::__do_widen\28std::__2::ios_base&\2c\20wchar_t*\29\20const +1866:std::__2::__num_get::__stage2_int_prep\28std::__2::ios_base&\2c\20char&\29 +1867:std::__2::__itoa::__append1\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +1868:std::__2::__function::__value_func::operator=\5babi:ne180100\5d\28std::__2::__function::__value_func&&\29 +1869:std::__2::__function::__value_func::operator\28\29\5babi:ne180100\5d\28SkIRect\20const&\29\20const +1870:sqrtf +1871:skvx::Vec<4\2c\20unsigned\20int>&\20skvx::operator-=<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1872:skvx::Vec<4\2c\20unsigned\20int>&\20skvx::operator+=<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +1873:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator><4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1874:skvx::Vec<4\2c\20float>\20skvx::operator+<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29\20\28.5846\29 +1875:skvx::Vec<4\2c\20float>\20skvx::operator+<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.674\29 +1876:skvx::Vec<4\2c\20float>\20skvx::max<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.7684\29 +1877:skvx::Vec<4\2c\20float>\20skvx::max<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +1878:sktext::gpu::VertexFiller::vertexStride\28SkMatrix\20const&\29\20const +1879:sktext::gpu::SubRunList::append\28std::__2::unique_ptr\29 +1880:sktext::gpu::SubRun::~SubRun\28\29 +1881:sktext::gpu::GlyphVector::~GlyphVector\28\29 +1882:skif::\28anonymous\20namespace\29::draw_tiled_border\28SkCanvas*\2c\20SkTileMode\2c\20SkPaint\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::LayerSpace\2c\20skif::LayerSpace\29::$_0::operator\28\29\28SkRect\20const&\2c\20SkRect\20const&\29\20const +1883:skif::LayerSpace::inverseMapRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29\20const +1884:skif::FilterResult::analyzeBounds\28skif::LayerSpace\20const&\2c\20skif::FilterResult::BoundsScope\29\20const +1885:skif::FilterResult::AutoSurface::snap\28\29 +1886:skif::FilterResult::AutoSurface::AutoSurface\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult::PixelBoundary\2c\20bool\2c\20SkSurfaceProps\20const*\29 +1887:skia_private::THashTable::AdaptedTraits>::findOrNull\28skgpu::UniqueKey\20const&\29\20const +1888:skia_private::TArray::reset\28int\29 +1889:skia_private::TArray::push_back_raw\28int\29 +1890:skia_private::TArray::push_back\28\29 +1891:skia_private::TArray::checkRealloc\28int\2c\20double\29 +1892:skia_private::AutoSTArray<8\2c\20unsigned\20int>::reset\28int\29 +1893:skia_private::AutoSTArray<24\2c\20unsigned\20int>::~AutoSTArray\28\29 +1894:skia_png_reciprocal2 +1895:skia_png_benign_error +1896:skia::textlayout::Run::~Run\28\29 +1897:skia::textlayout::Run::posX\28unsigned\20long\29\20const +1898:skia::textlayout::ParagraphStyle::ParagraphStyle\28skia::textlayout::ParagraphStyle\20const&\29 +1899:skia::textlayout::InternalLineMetrics::height\28\29\20const +1900:skia::textlayout::InternalLineMetrics::add\28skia::textlayout::Run*\29 +1901:skia::textlayout::FontCollection::findTypefaces\28std::__2::vector>\20const&\2c\20SkFontStyle\2c\20std::__2::optional\20const&\29 +1902:skgpu::ganesh::TextureOp::BatchSizeLimiter::createOp\28GrTextureSetEntry*\2c\20int\2c\20GrAAType\29 +1903:skgpu::ganesh::SurfaceFillContext::fillRectWithFP\28SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +1904:skgpu::ganesh::SurfaceFillContext::fillRectToRectWithFP\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +1905:skgpu::ganesh::SurfaceDrawContext::drawShapeUsingPathRenderer\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\2c\20bool\29 +1906:skgpu::ganesh::SurfaceDrawContext::drawRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const*\29 +1907:skgpu::ganesh::SurfaceDrawContext::drawRRect\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20GrStyle\20const&\29 +1908:skgpu::ganesh::SurfaceDrawContext::drawFilledQuad\28GrClip\20const*\2c\20GrPaint&&\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\29 +1909:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29::$_0::~$_0\28\29 +1910:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29 +1911:skgpu::ganesh::SurfaceContext::PixelTransferResult::PixelTransferResult\28skgpu::ganesh::SurfaceContext::PixelTransferResult&&\29 +1912:skgpu::ganesh::SoftwarePathRenderer::DrawNonAARect\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const&\29 +1913:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::vertexSize\28\29\20const +1914:skgpu::ganesh::OpsTask::OpChain::List::List\28skgpu::ganesh::OpsTask::OpChain::List&&\29 +1915:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29::$_0::operator\28\29\28GrSurfaceProxyView\20const&\29\20const +1916:skgpu::ganesh::Device::targetProxy\28\29 +1917:skgpu::ganesh::ClipStack::getConservativeBounds\28\29\20const +1918:skgpu::UniqueKeyInvalidatedMessage::UniqueKeyInvalidatedMessage\28skgpu::UniqueKeyInvalidatedMessage\20const&\29 +1919:skgpu::UniqueKey::operator=\28skgpu::UniqueKey\20const&\29 +1920:skgpu::TAsyncReadResult::addTransferResult\28skgpu::ganesh::SurfaceContext::PixelTransferResult\20const&\2c\20SkISize\2c\20unsigned\20long\2c\20skgpu::TClientMappedBufferManager*\29 +1921:skgpu::Swizzle::asString\28\29\20const +1922:skgpu::GetApproxSize\28SkISize\29 +1923:sk_srgb_linear_singleton\28\29 +1924:sk_sp::reset\28SkVertices*\29 +1925:sk_sp::operator=\28sk_sp&&\29 +1926:sk_sp::reset\28GrGpuBuffer*\29 +1927:sk_sp\20sk_make_sp\28\29 +1928:sfnt_get_name_id +1929:set_glyph\28hb_glyph_info_t&\2c\20hb_font_t*\29 +1930:resource_cache_mutex\28\29 +1931:remove_node\28OffsetEdge\20const*\2c\20OffsetEdge**\29 +1932:ps_parser_to_token +1933:precisely_between\28double\2c\20double\2c\20double\29 +1934:powf +1935:next_char\28hb_buffer_t*\2c\20unsigned\20int\29 +1936:log2f +1937:log +1938:less_or_equal_ulps\28float\2c\20float\2c\20int\29 +1939:is_consonant\28hb_glyph_info_t\20const&\29 +1940:int\20const*\20std::__2::find\5babi:ne180100\5d\28int\20const*\2c\20int\20const*\2c\20int\20const&\29 +1941:hb_vector_t::push\28\29 +1942:hb_vector_t::resize\28int\2c\20bool\2c\20bool\29 +1943:hb_unicode_funcs_destroy +1944:hb_serialize_context_t::pop_discard\28\29 +1945:hb_paint_funcs_t::push_root_transform\28void*\2c\20hb_font_t\20const*\29 +1946:hb_paint_funcs_t::pop_clip\28void*\29 +1947:hb_ot_map_t::feature_map_t\20const*\20hb_vector_t::bsearch\28unsigned\20int\20const&\2c\20hb_ot_map_t::feature_map_t\20const*\29\20const +1948:hb_lazy_loader_t\2c\20hb_face_t\2c\2024u\2c\20OT::GDEF_accelerator_t>::get_stored\28\29\20const +1949:hb_indic_would_substitute_feature_t::init\28hb_ot_map_t\20const*\2c\20unsigned\20int\2c\20bool\29 +1950:hb_hashmap_t::del\28unsigned\20int\20const&\29 +1951:hb_font_t::get_glyph_v_advance\28unsigned\20int\29 +1952:hb_font_t::get_glyph_extents\28unsigned\20int\2c\20hb_glyph_extents_t*\29 +1953:hb_buffer_t::_set_glyph_flags\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +1954:hb_buffer_create_similar +1955:gray_set_cell +1956:getenv +1957:ft_service_list_lookup +1958:fseek +1959:find_table +1960:fillcheckrect\28int\2c\20int\2c\20int\2c\20int\2c\20SkBlitter*\29 +1961:fclose +1962:expm1 +1963:expf +1964:crc_word +1965:classify\28skcms_TransferFunction\20const&\2c\20TF_PQish*\2c\20TF_HLGish*\29 +1966:choose_bmp_texture_colortype\28GrCaps\20const*\2c\20SkBitmap\20const&\29 +1967:char*\20sktext::gpu::BagOfBytes::allocateBytesFor\28int\29 +1968:cff_parse_fixed +1969:cf2_interpT2CharString +1970:cf2_hintmap_insertHint +1971:cf2_hintmap_build +1972:cf2_glyphpath_moveTo +1973:cf2_glyphpath_lineTo +1974:bool\20std::__2::operator==\5babi:ne180100\5d>\28std::__2::vector>\20const&\2c\20std::__2::vector>\20const&\29 +1975:bool\20std::__2::__less::operator\28\29\5babi:nn180100\5d\28unsigned\20int\20const&\2c\20unsigned\20long\20const&\29\20const +1976:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +1977:blit_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +1978:afm_tokenize +1979:af_glyph_hints_reload +1980:_hb_glyph_info_set_unicode_props\28hb_glyph_info_t*\2c\20hb_buffer_t*\29 +1981:_hb_draw_funcs_set_middle\28hb_draw_funcs_t*\2c\20void*\2c\20void\20\28*\29\28void*\29\29 +1982:__wasm_setjmp +1983:__wasi_syscall_ret +1984:__syscall_ret +1985:__sin +1986:__cos +1987:\28anonymous\20namespace\29::valid_unit_divide\28float\2c\20float\2c\20float*\29 +1988:\28anonymous\20namespace\29::draw_stencil_rect\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrHardClip\20const&\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +1989:\28anonymous\20namespace\29::can_reorder\28SkRect\20const&\2c\20SkRect\20const&\29 +1990:\28anonymous\20namespace\29::SkBlurImageFilter::~SkBlurImageFilter\28\29 +1991:\28anonymous\20namespace\29::FillRectOpImpl::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +1992:Skwasm::createRRect\28float\20const*\29 +1993:SkWriter32::writeSampling\28SkSamplingOptions\20const&\29 +1994:SkWriter32::writePad\28void\20const*\2c\20unsigned\20long\29 +1995:SkTextBlobRunIterator::next\28\29 +1996:SkTextBlobBuilder::make\28\29 +1997:SkTSect::addOne\28\29 +1998:SkTMultiMap::remove\28skgpu::ScratchKey\20const&\2c\20GrGpuResource\20const*\29 +1999:SkTLazy::set\28SkPath\20const&\29 +2000:SkTDArray::append\28\29 +2001:SkTDArray::append\28\29 +2002:SkSurfaces::RenderTarget\28GrRecordingContext*\2c\20skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20int\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const*\2c\20bool\2c\20bool\29 +2003:SkSurfaces::Raster\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20SkSurfaceProps\20const*\29 +2004:SkStrokeRec::isFillStyle\28\29\20const +2005:SkString::appendU32\28unsigned\20int\29 +2006:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +2007:SkShaders::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\29 +2008:SkShaderUtils::GLSLPrettyPrint::appendChar\28char\29 +2009:SkScopeExit::~SkScopeExit\28\29 +2010:SkScan::FillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\29 +2011:SkSL::is_scalar_op_matrix\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +2012:SkSL::evaluate_n_way_intrinsic\28SkSL::Context\20const&\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +2013:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitType\28SkSL::Type\20const&\29 +2014:SkSL::Variable::initialValue\28\29\20const +2015:SkSL::Variable*\20SkSL::SymbolTable::takeOwnershipOfSymbol\28std::__2::unique_ptr>\29 +2016:SkSL::Type::canCoerceTo\28SkSL::Type\20const&\2c\20bool\29\20const +2017:SkSL::SymbolTable::takeOwnershipOfString\28std::__2::basic_string\2c\20std::__2::allocator>\29 +2018:SkSL::RP::pack_nybbles\28SkSpan\29 +2019:SkSL::RP::Generator::foldComparisonOp\28SkSL::Operator\2c\20int\29 +2020:SkSL::RP::Generator::emitTraceScope\28int\29 +2021:SkSL::RP::Generator::createStack\28\29 +2022:SkSL::RP::Builder::trace_var\28int\2c\20SkSL::RP::SlotRange\29 +2023:SkSL::RP::Builder::jump\28int\29 +2024:SkSL::RP::Builder::dot_floats\28int\29 +2025:SkSL::RP::Builder::branch_if_no_lanes_active\28int\29 +2026:SkSL::RP::AutoStack::~AutoStack\28\29 +2027:SkSL::RP::AutoStack::pushClone\28int\29 +2028:SkSL::Position::rangeThrough\28SkSL::Position\29\20const +2029:SkSL::PipelineStage::PipelineStageCodeGenerator::AutoOutputBuffer::~AutoOutputBuffer\28\29 +2030:SkSL::Parser::type\28SkSL::Modifiers*\29 +2031:SkSL::Parser::parseArrayDimensions\28SkSL::Position\2c\20SkSL::Type\20const**\29 +2032:SkSL::Parser::modifiers\28\29 +2033:SkSL::Parser::assignmentExpression\28\29 +2034:SkSL::Parser::arraySize\28long\20long*\29 +2035:SkSL::ModifierFlags::paddedDescription\28\29\20const +2036:SkSL::Literal::MakeBool\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20bool\29 +2037:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29::$_2::operator\28\29\28SkSL::ExpressionArray\20const&\29\20const +2038:SkSL::IRHelpers::Swizzle\28std::__2::unique_ptr>\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29\20const +2039:SkSL::GLSLCodeGenerator::writeTypePrecision\28SkSL::Type\20const&\29 +2040:SkSL::FunctionDeclaration::getMainCoordsParameter\28\29\20const +2041:SkSL::ExpressionArray::clone\28\29\20const +2042:SkSL::ConstantFolder::GetConstantValue\28SkSL::Expression\20const&\2c\20double*\29 +2043:SkSL::ConstantFolder::GetConstantInt\28SkSL::Expression\20const&\2c\20long\20long*\29 +2044:SkSL::Compiler::~Compiler\28\29 +2045:SkSL::Compiler::errorText\28bool\29 +2046:SkSL::Compiler::Compiler\28\29 +2047:SkSL::Analysis::IsTrivialExpression\28SkSL::Expression\20const&\29 +2048:SkRuntimeEffectPriv::TransformUniforms\28SkSpan\2c\20sk_sp\2c\20SkColorSpace\20const*\29 +2049:SkRuntimeEffectBuilder::~SkRuntimeEffectBuilder\28\29 +2050:SkRuntimeEffectBuilder::makeShader\28SkMatrix\20const*\29\20const +2051:SkRuntimeEffectBuilder::SkRuntimeEffectBuilder\28sk_sp\29 +2052:SkRuntimeEffectBuilder::BuilderChild&\20SkRuntimeEffectBuilder::BuilderChild::operator=\28sk_sp\29 +2053:SkRuntimeEffect::findChild\28std::__2::basic_string_view>\29\20const +2054:SkRegion::setPath\28SkPath\20const&\2c\20SkRegion\20const&\29 +2055:SkRegion::Iterator::Iterator\28SkRegion\20const&\29 +2056:SkReduceOrder::Quad\28SkPoint\20const*\2c\20SkPoint*\29 +2057:SkRect::sort\28\29 +2058:SkRect::joinPossiblyEmptyRect\28SkRect\20const&\29 +2059:SkRasterPipeline_BinaryOpCtx*\20SkArenaAlloc::make\28SkRasterPipeline_BinaryOpCtx\20const&\29 +2060:SkRasterPipelineBlitter::appendClipScale\28SkRasterPipeline*\29\20const +2061:SkRasterPipelineBlitter::appendClipLerp\28SkRasterPipeline*\29\20const +2062:SkRRect::setRectRadii\28SkRect\20const&\2c\20SkPoint\20const*\29 +2063:SkRGBA4f<\28SkAlphaType\292>::toBytes_RGBA\28\29\20const +2064:SkRGBA4f<\28SkAlphaType\292>::fitsInBytes\28\29\20const +2065:SkPointPriv::EqualsWithinTolerance\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\29 +2066:SkPoint*\20SkRecorder::copy\28SkPoint\20const*\2c\20unsigned\20long\29 +2067:SkPoint*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29 +2068:SkPixmap::reset\28\29 +2069:SkPixmap::computeByteSize\28\29\20const +2070:SkPictureRecord::addImage\28SkImage\20const*\29 +2071:SkPathRef::SkPathRef\28int\2c\20int\2c\20int\29 +2072:SkPathPriv::ComputeFirstDirection\28SkPath\20const&\29 +2073:SkPath::isLine\28SkPoint*\29\20const +2074:SkParsePath::ToSVGString\28SkPath\20const&\2c\20SkParsePath::PathEncoding\29::$_0::operator\28\29\28char\2c\20SkPoint\20const*\2c\20unsigned\20long\29\20const +2075:SkPaintPriv::ComputeLuminanceColor\28SkPaint\20const&\29 +2076:SkPaint::nothingToDraw\28\29\20const +2077:SkOpSpan::release\28SkOpPtT\20const*\29 +2078:SkOpContourBuilder::addCurve\28SkPath::Verb\2c\20SkPoint\20const*\2c\20float\29 +2079:SkMipmap::Build\28SkPixmap\20const&\2c\20SkDiscardableMemory*\20\28*\29\28unsigned\20long\29\2c\20bool\29 +2080:SkMeshSpecification::Varying::Varying\28SkMeshSpecification::Varying&&\29 +2081:SkMatrix::mapOrigin\28\29\20const +2082:SkMatrix::decomposeScale\28SkSize*\2c\20SkMatrix*\29\20const +2083:SkMaskFilterBase::getFlattenableType\28\29\20const +2084:SkMaskFilter::MakeBlur\28SkBlurStyle\2c\20float\2c\20bool\29 +2085:SkM44::SkM44\28SkMatrix\20const&\29 +2086:SkJSONWriter::endArray\28\29 +2087:SkJSONWriter::beginValue\28bool\29 +2088:SkJSONWriter::beginArray\28char\20const*\2c\20bool\29 +2089:SkIntersections::insertNear\28double\2c\20double\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29 +2090:SkImageShader::Make\28sk_sp\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +2091:SkImageGenerator::onRefEncodedData\28\29 +2092:SkIRect::inset\28int\2c\20int\29 +2093:SkGradientBaseShader::flatten\28SkWriteBuffer&\29\20const +2094:SkFont::getMetrics\28SkFontMetrics*\29\20const +2095:SkFont::SkFont\28\29 +2096:SkFindQuadMaxCurvature\28SkPoint\20const*\29 +2097:SkFDot6Div\28int\2c\20int\29 +2098:SkEvalQuadAt\28SkPoint\20const*\2c\20float\29 +2099:SkEvalCubicAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29 +2100:SkEdgeClipper::appendVLine\28float\2c\20float\2c\20float\2c\20bool\29 +2101:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29 +2102:SkDrawShadowMetrics::GetSpotParams\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float*\2c\20float*\2c\20SkPoint*\29 +2103:SkDraw::SkDraw\28\29 +2104:SkDevice::setLocalToDevice\28SkM44\20const&\29 +2105:SkDevice::setGlobalCTM\28SkM44\20const&\29 +2106:SkDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +2107:SkDLine::exactPoint\28SkDPoint\20const&\29\20const +2108:SkColorSpace::MakeSRGBLinear\28\29 +2109:SkColorInfo::isOpaque\28\29\20const +2110:SkChopCubicAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +2111:SkCanvas::getLocalClipBounds\28\29\20const +2112:SkCanvas::drawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +2113:SkCanvas::drawIRect\28SkIRect\20const&\2c\20SkPaint\20const&\29 +2114:SkBulkGlyphMetrics::glyphs\28SkSpan\29 +2115:SkBlockAllocator::releaseBlock\28SkBlockAllocator::Block*\29 +2116:SkBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +2117:SkBlendMode_AppendStages\28SkBlendMode\2c\20SkRasterPipeline*\29 +2118:SkBitmap::tryAllocPixels\28SkBitmap::Allocator*\29 +2119:SkBitmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +2120:SkBitmap::operator=\28SkBitmap\20const&\29 +2121:SkBitmap::getGenerationID\28\29\20const +2122:SkAutoPixmapStorage::SkAutoPixmapStorage\28\29 +2123:SkAutoDeviceTransformRestore::~SkAutoDeviceTransformRestore\28\29 +2124:SkAutoDeviceTransformRestore::SkAutoDeviceTransformRestore\28SkDevice*\2c\20SkMatrix\20const&\29 +2125:SkAutoCanvasRestore::SkAutoCanvasRestore\28SkCanvas*\2c\20bool\29 +2126:SkAAClipBlitter::~SkAAClipBlitter\28\29 +2127:SkAAClip::setRegion\28SkRegion\20const&\29::$_0::operator\28\29\28unsigned\20char\2c\20int\29\20const +2128:SkAAClip::findX\28unsigned\20char\20const*\2c\20int\2c\20int*\29\20const +2129:SkAAClip::findRow\28int\2c\20int*\29\20const +2130:SkAAClip::Builder::Blitter::~Blitter\28\29 +2131:SaveErrorCode +2132:RoughlyEqualUlps\28float\2c\20float\29 +2133:R.9921 +2134:PS_Conv_ToInt +2135:OT::hmtxvmtx::accelerator_t::get_leading_bearing_without_var_unscaled\28unsigned\20int\2c\20int*\29\20const +2136:OT::hb_ot_apply_context_t::replace_glyph\28unsigned\20int\29 +2137:OT::fvar::get_axes\28\29\20const +2138:OT::Layout::GPOS_impl::ValueFormat::sanitize_values_stride_unsafe\28hb_sanitize_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +2139:OT::DeltaSetIndexMap::map\28unsigned\20int\29\20const +2140:Normalize +2141:Ins_Goto_CodeRange +2142:GrTriangulator::setBottom\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2143:GrTriangulator::VertexList::append\28GrTriangulator::VertexList\20const&\29 +2144:GrTriangulator::Line::normalize\28\29 +2145:GrTriangulator::Edge::disconnect\28\29 +2146:GrThreadSafeCache::find\28skgpu::UniqueKey\20const&\29 +2147:GrThreadSafeCache::add\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2148:GrTextureEffect::texture\28\29\20const +2149:GrSurfaceProxyView::Copy\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\29 +2150:GrSurfaceProxyPriv::doLazyInstantiation\28GrResourceProvider*\29 +2151:GrSurface::~GrSurface\28\29 +2152:GrStyledShape::simplify\28\29 +2153:GrStyle::applies\28\29\20const +2154:GrSimpleMeshDrawOpHelperWithStencil::fixedFunctionFlags\28\29\20const +2155:GrSimpleMeshDrawOpHelper::finalizeProcessors\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrClampType\2c\20GrProcessorAnalysisCoverage\2c\20GrProcessorAnalysisColor*\29 +2156:GrSimpleMeshDrawOpHelper::detachProcessorSet\28\29 +2157:GrSimpleMeshDrawOpHelper::CreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrPipeline\20const*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrGeometryProcessor*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\2c\20GrUserStencilSettings\20const*\29 +2158:GrSimpleMesh::setIndexedPatterned\28sk_sp\2c\20int\2c\20int\2c\20int\2c\20sk_sp\2c\20int\2c\20int\29 +2159:GrShape::setRect\28SkRect\20const&\29 +2160:GrShape::GrShape\28GrShape\20const&\29 +2161:GrShaderVar::addModifier\28char\20const*\29 +2162:GrSWMaskHelper::~GrSWMaskHelper\28\29 +2163:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20void\20const*\2c\20skgpu::UniqueKey\20const&\29 +2164:GrResourceProvider::findOrMakeStaticBuffer\28GrGpuBufferType\2c\20unsigned\20long\2c\20skgpu::UniqueKey\20const&\2c\20void\20\28*\29\28skgpu::VertexWriter\2c\20unsigned\20long\29\29 +2165:GrResourceCache::purgeAsNeeded\28\29 +2166:GrRenderTask::addDependency\28GrDrawingManager*\2c\20GrSurfaceProxy*\2c\20skgpu::Mipmapped\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +2167:GrRecordingContextPriv::makeSFC\28GrImageInfo\2c\20std::__2::basic_string_view>\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2168:GrQuad::asRect\28SkRect*\29\20const +2169:GrProcessorSet::operator!=\28GrProcessorSet\20const&\29\20const +2170:GrPixmapBase::GrPixmapBase\28GrImageInfo\2c\20void\20const*\2c\20unsigned\20long\29 +2171:GrPipeline::getXferProcessor\28\29\20const +2172:GrNativeRect::asSkIRect\28\29\20const +2173:GrGeometryProcessor::ProgramImpl::~ProgramImpl\28\29 +2174:GrGeometryProcessor::ProgramImpl::WriteOutputPosition\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\2c\20char\20const*\2c\20SkMatrix\20const&\2c\20GrResourceHandle*\29 +2175:GrGLSLShaderBuilder::defineConstant\28char\20const*\2c\20float\29 +2176:GrGLSLShaderBuilder::addFeature\28unsigned\20int\2c\20char\20const*\29 +2177:GrGLSLProgramBuilder::nameVariable\28char\2c\20char\20const*\2c\20bool\29 +2178:GrGLSLColorSpaceXformHelper::setData\28GrGLSLProgramDataManager\20const&\2c\20GrColorSpaceXform\20const*\29 +2179:GrGLSLColorSpaceXformHelper::emitCode\28GrGLSLUniformHandler*\2c\20GrColorSpaceXform\20const*\2c\20unsigned\20int\29 +2180:GrGLGpu::flushColorWrite\28bool\29 +2181:GrGLGpu::bindTexture\28int\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20GrGLTexture*\29 +2182:GrFragmentProcessors::Make\28SkShader\20const*\2c\20GrFPArgs\20const&\2c\20SkMatrix\20const&\29 +2183:GrFragmentProcessor::visitWithImpls\28std::__2::function\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\20const +2184:GrFragmentProcessor::visitProxies\28std::__2::function\20const&\29\20const +2185:GrFragmentProcessor::ColorMatrix\28std::__2::unique_ptr>\2c\20float\20const*\2c\20bool\2c\20bool\2c\20bool\29 +2186:GrDstProxyView::operator=\28GrDstProxyView\20const&\29 +2187:GrDrawingManager::closeActiveOpsTask\28\29 +2188:GrDrawingManager::appendTask\28sk_sp\29 +2189:GrColorSpaceXformEffect::Make\28std::__2::unique_ptr>\2c\20sk_sp\29 +2190:GrColorSpaceXform::XformKey\28GrColorSpaceXform\20const*\29 +2191:GrColorSpaceXform::Make\28GrColorInfo\20const&\2c\20GrColorInfo\20const&\29 +2192:GrColorInfo::GrColorInfo\28GrColorInfo\20const&\29 +2193:GrCaps::isFormatCompressed\28GrBackendFormat\20const&\29\20const +2194:GrBufferAllocPool::~GrBufferAllocPool\28\29 +2195:GrBufferAllocPool::putBack\28unsigned\20long\29 +2196:GrBlurUtils::convolve_gaussian\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20SkIRect\2c\20SkIRect\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkBackingFit\29::$_1::operator\28\29\28SkIRect\29\20const +2197:GrAAConvexTessellator::lineTo\28SkPoint\20const&\2c\20GrAAConvexTessellator::CurveState\29 +2198:FwDCubicEvaluator::restart\28int\29 +2199:FT_Vector_Transform +2200:FT_Select_Charmap +2201:FT_Lookup_Renderer +2202:FT_Get_Module_Interface +2203:CFF::opset_t::process_op\28unsigned\20int\2c\20CFF::interp_env_t&\29 +2204:CFF::arg_stack_t::push_int\28int\29 +2205:CFF::CFFIndex>::offset_at\28unsigned\20int\29\20const +2206:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::operator++\28\29 +2207:ActiveEdge::intersect\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29\20const +2208:AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t\28\29 +2209:AAT::hb_aat_apply_context_t::hb_aat_apply_context_t\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20hb_blob_t*\29 +2210:2001 +2211:2002 +2212:2003 +2213:2004 +2214:2005 +2215:2006 +2216:wmemchr +2217:void\20std::__2::unique_ptr>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot*\2c\200>\28skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot*\29 +2218:void\20std::__2::reverse\5babi:nn180100\5d\28unsigned\20int*\2c\20unsigned\20int*\29 +2219:void\20std::__2::__variant_detail::__assignment>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29 +2220:void\20hb_serialize_context_t::add_link\2c\20true>>\28OT::OffsetTo\2c\20true>&\2c\20unsigned\20int\2c\20hb_serialize_context_t::whence_t\2c\20unsigned\20int\29 +2221:void\20hb_sanitize_context_t::set_object\28AAT::KerxSubTable\20const*\29 +2222:void\20SkSafeUnref\28sktext::gpu::TextStrike*\29 +2223:void\20SkSafeUnref\28GrArenas*\29 +2224:void\20SkSL::RP::unpack_nybbles_to_offsets\28unsigned\20int\2c\20SkSpan\29 +2225:ubidi_setPara_skia +2226:ubidi_getCustomizedClass_skia +2227:tt_set_mm_blend +2228:tt_face_get_ps_name +2229:trinkle +2230:t1_builder_check_points +2231:subdivide\28SkConic\20const&\2c\20SkPoint*\2c\20int\29 +2232:std::__2::vector>\2c\20std::__2::allocator>>>::__swap_out_circular_buffer\28std::__2::__split_buffer>\2c\20std::__2::allocator>>&>&\29 +2233:std::__2::vector>\2c\20std::__2::allocator>>>::__clear\5babi:ne180100\5d\28\29 +2234:std::__2::vector>\2c\20std::__2::allocator>>>::~vector\5babi:ne180100\5d\28\29 +2235:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +2236:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +2237:std::__2::vector\2c\20std::__2::allocator>>::push_back\5babi:ne180100\5d\28sk_sp\20const&\29 +2238:std::__2::vector>::push_back\5babi:ne180100\5d\28float&&\29 +2239:std::__2::vector>::push_back\5babi:ne180100\5d\28char\20const*&&\29 +2240:std::__2::vector>::__move_assign\28std::__2::vector>&\2c\20std::__2::integral_constant\29 +2241:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +2242:std::__2::unordered_map\2c\20std::__2::equal_to\2c\20std::__2::allocator>>::operator\5b\5d\28GrTriangulator::Vertex*\20const&\29 +2243:std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2244:std::__2::unique_ptr::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2245:std::__2::unique_ptr::Traits>::Slot\20\5b\5d\2c\20std::__2::default_delete::Traits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2246:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skgpu::ganesh::SurfaceDrawContext*\29 +2247:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2248:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skgpu::ganesh::PathRendererChain*\29 +2249:std::__2::unique_ptr\20\5b\5d\2c\20std::__2::default_delete\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +2250:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28hb_face_t*\29 +2251:std::__2::unique_ptr::release\5babi:nn180100\5d\28\29 +2252:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2253:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2254:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2255:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2256:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2257:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +2258:std::__2::moneypunct::do_decimal_point\28\29\20const +2259:std::__2::moneypunct::pos_format\5babi:nn180100\5d\28\29\20const +2260:std::__2::moneypunct::do_decimal_point\28\29\20const +2261:std::__2::locale::locale\28std::__2::locale\20const&\29 +2262:std::__2::locale::classic\28\29 +2263:std::__2::istreambuf_iterator>::istreambuf_iterator\5babi:nn180100\5d\28std::__2::basic_istream>&\29 +2264:std::__2::function::operator\28\29\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +2265:std::__2::function::operator\28\29\28int\2c\20skia::textlayout::Paragraph::VisitorInfo\20const*\29\20const +2266:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d\28unsigned\20int&\2c\20unsigned\20int&\29 +2267:std::__2::deque>::pop_front\28\29 +2268:std::__2::deque>::begin\5babi:ne180100\5d\28\29 +2269:std::__2::ctype::toupper\5babi:nn180100\5d\28char\29\20const +2270:std::__2::chrono::duration>::duration\5babi:nn180100\5d\28long\20long\20const&\29 +2271:std::__2::basic_string_view>::find\5babi:ne180100\5d\28char\2c\20unsigned\20long\29\20const +2272:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +2273:std::__2::basic_string\2c\20std::__2::allocator>::operator\5b\5d\5babi:nn180100\5d\28unsigned\20long\29\20const +2274:std::__2::basic_string\2c\20std::__2::allocator>::__fits_in_sso\5babi:nn180100\5d\28unsigned\20long\29 +2275:std::__2::basic_string\2c\20std::__2::allocator>\20const*\20std::__2::__scan_keyword\5babi:nn180100\5d>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype>\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::ctype\20const&\2c\20unsigned\20int&\2c\20bool\29 +2276:std::__2::basic_string\2c\20std::__2::allocator>::pop_back\5babi:ne180100\5d\28\29 +2277:std::__2::basic_string\2c\20std::__2::allocator>::operator=\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +2278:std::__2::basic_string\2c\20std::__2::allocator>::__get_short_size\5babi:nn180100\5d\28\29\20const +2279:std::__2::basic_string\2c\20std::__2::allocator>::__assign_external\28char\20const*\2c\20unsigned\20long\29 +2280:std::__2::basic_string\2c\20std::__2::allocator>::__throw_length_error\5babi:ne180100\5d\28\29\20const +2281:std::__2::basic_streambuf>::__pbump\5babi:nn180100\5d\28long\29 +2282:std::__2::basic_ostream>::sentry::operator\20bool\5babi:nn180100\5d\28\29\20const +2283:std::__2::basic_iostream>::~basic_iostream\28\29 +2284:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::OperatorKind&&\2c\20std::__2::unique_ptr>&&\29 +2285:std::__2::__tuple_impl\2c\20sk_sp\2c\20sk_sp>::~__tuple_impl\28\29 +2286:std::__2::__tuple_impl\2c\20GrFragmentProcessor\20const*\2c\20GrGeometryProcessor::ProgramImpl::TransformInfo>::__tuple_impl\28std::__2::__tuple_impl\2c\20GrFragmentProcessor\20const*\2c\20GrGeometryProcessor::ProgramImpl::TransformInfo>&&\29 +2287:std::__2::__tree\2c\20std::__2::__map_value_compare\2c\20std::__2::less\2c\20true>\2c\20std::__2::allocator>>::~__tree\28\29 +2288:std::__2::__throw_bad_variant_access\5babi:ne180100\5d\28\29 +2289:std::__2::__split_buffer>\2c\20std::__2::allocator>>&>::~__split_buffer\28\29 +2290:std::__2::__split_buffer>::push_front\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +2291:std::__2::__split_buffer>::push_back\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\20const&\29 +2292:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +2293:std::__2::__split_buffer\2c\20std::__2::allocator>&>::~__split_buffer\28\29 +2294:std::__2::__split_buffer\2c\20std::__2::allocator>&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator>&\29 +2295:std::__2::__shared_count::__release_shared\5babi:nn180100\5d\28\29 +2296:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +2297:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +2298:std::__2::__num_put_base::__format_int\28char*\2c\20char\20const*\2c\20bool\2c\20unsigned\20int\29 +2299:std::__2::__num_put_base::__format_float\28char*\2c\20char\20const*\2c\20unsigned\20int\29 +2300:std::__2::__itoa::__append8\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +2301:std::__2::__function::__value_func::operator\28\29\5babi:ne180100\5d\28\29\20const +2302:std::__2::__function::__value_func::operator\28\29\5babi:ne180100\5d\28SkSL::Variable\20const&\29\20const +2303:skvx::Vec<8\2c\20unsigned\20short>\20skvx::operator+<8\2c\20unsigned\20short\2c\20unsigned\20short\2c\20void>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20short\29 +2304:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator&<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +2305:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator>=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +2306:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20double\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20double\29 +2307:sktext::gpu::VertexFiller::deviceRectAndCheckTransform\28SkMatrix\20const&\29\20const +2308:sktext::gpu::GlyphVector::packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29 +2309:sktext::SkStrikePromise::strike\28\29 +2310:skif::\28anonymous\20namespace\29::draw_tiled_border\28SkCanvas*\2c\20SkTileMode\2c\20SkPaint\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::LayerSpace\2c\20skif::LayerSpace\29::$_1::operator\28\29\28SkPoint\20const&\2c\20SkPoint\20const&\29\20const +2311:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +2312:skif::LayerSpace::postConcat\28skif::LayerSpace\20const&\29 +2313:skif::FilterResult::subset\28skif::LayerSpace\20const&\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +2314:skif::FilterResult::getAnalyzedShaderView\28skif::Context\20const&\2c\20SkSamplingOptions\20const&\2c\20SkEnumBitMask\29\20const +2315:skif::FilterResult::applyTransform\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkSamplingOptions\20const&\29\20const +2316:skif::FilterResult::applyCrop\28skif::Context\20const&\2c\20skif::LayerSpace\20const&\2c\20SkTileMode\29\20const +2317:skif::FilterResult::analyzeBounds\28SkMatrix\20const&\2c\20SkIRect\20const&\2c\20skif::FilterResult::BoundsScope\29\20const +2318:skif::FilterResult::Builder::add\28skif::FilterResult\20const&\2c\20std::__2::optional>\2c\20SkEnumBitMask\2c\20SkSamplingOptions\20const&\29 +2319:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +2320:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +2321:skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair&&\29 +2322:skia_private::THashTable::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +2323:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair&&\29 +2324:skia_private::THashTable::Pair\2c\20SkSL::Analysis::SpecializedCallKey\2c\20skia_private::THashMap::Pair>::Hash\28SkSL::Analysis::SpecializedCallKey\20const&\29 +2325:skia_private::THashTable::Traits>::uncheckedSet\28long\20long&&\29 +2326:skia_private::THashTable::Traits>::uncheckedSet\28int&&\29 +2327:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::resize\28int\29 +2328:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::find\28unsigned\20int\20const&\29\20const +2329:skia_private::THashMap::find\28unsigned\20int\20const&\29\20const +2330:skia_private::THashMap::operator\5b\5d\28SkSL::Variable\20const*\20const&\29 +2331:skia_private::TArray::push_back_raw\28int\29 +2332:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +2333:skia_private::TArray>\2c\20true>::destroyAll\28\29 +2334:skia_private::TArray>\2c\20true>::push_back\28std::__2::unique_ptr>&&\29 +2335:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2336:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +2337:skia_private::TArray::~TArray\28\29 +2338:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2339:skia_private::TArray::~TArray\28\29 +2340:skia_private::TArray\2c\20true>::~TArray\28\29 +2341:skia_private::TArray::push_back_n\28int\2c\20int\20const&\29 +2342:skia_private::TArray::reserve_exact\28int\29 +2343:skia_private::TArray<\28anonymous\20namespace\29::MeshOp::Mesh\2c\20true>::preallocateNewData\28int\2c\20double\29 +2344:skia_private::TArray<\28anonymous\20namespace\29::MeshOp::Mesh\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +2345:skia_private::TArray::clear\28\29 +2346:skia_private::TArray::operator=\28skia_private::TArray&&\29 +2347:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2348:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +2349:skia_private::TArray::push_back\28GrRenderTask*&&\29 +2350:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +2351:skia_private::AutoSTMalloc<4ul\2c\20SkFontArguments::Palette::Override\2c\20void>::AutoSTMalloc\28unsigned\20long\29 +2352:skia_private::AutoSTArray<24\2c\20unsigned\20int>::reset\28int\29 +2353:skia_png_zstream_error +2354:skia_png_read_data +2355:skia_png_get_int_32 +2356:skia_png_chunk_unknown_handling +2357:skia_png_calloc +2358:skia::textlayout::TextWrapper::getClustersTrimmedWidth\28\29 +2359:skia::textlayout::TextWrapper::TextStretch::startFrom\28skia::textlayout::Cluster*\2c\20unsigned\20long\29 +2360:skia::textlayout::TextWrapper::TextStretch::extend\28skia::textlayout::Cluster*\29 +2361:skia::textlayout::TextLine::measureTextInsideOneRun\28skia::textlayout::SkRange\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20float\2c\20bool\2c\20skia::textlayout::TextLine::TextAdjustment\29\20const +2362:skia::textlayout::TextLine::isLastLine\28\29\20const +2363:skia::textlayout::Run::Run\28skia::textlayout::Run\20const&\29 +2364:skia::textlayout::ParagraphImpl::getLineNumberAt\28unsigned\20long\29\20const +2365:skia::textlayout::ParagraphImpl::findPreviousGraphemeBoundary\28unsigned\20long\29\20const +2366:skia::textlayout::ParagraphCacheKey::~ParagraphCacheKey\28\29 +2367:skia::textlayout::ParagraphBuilderImpl::startStyledBlock\28\29 +2368:skia::textlayout::OneLineShaper::RunBlock&\20std::__2::vector>::emplace_back\28skia::textlayout::OneLineShaper::RunBlock&\29 +2369:skia::textlayout::OneLineShaper::FontKey::FontKey\28skia::textlayout::OneLineShaper::FontKey&&\29 +2370:skia::textlayout::InternalLineMetrics::updateLineMetrics\28skia::textlayout::InternalLineMetrics&\29 +2371:skia::textlayout::InternalLineMetrics::runTop\28skia::textlayout::Run\20const*\2c\20skia::textlayout::LineMetricStyle\29\20const +2372:skia::textlayout::FontCollection::getFontManagerOrder\28\29\20const +2373:skia::textlayout::Decorations::calculateGaps\28skia::textlayout::TextLine::ClipContext\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\29 +2374:skia::textlayout::Cluster::runOrNull\28\29\20const +2375:skgpu::tess::PatchStride\28skgpu::tess::PatchAttribs\29 +2376:skgpu::tess::MiddleOutPolygonTriangulator::MiddleOutPolygonTriangulator\28int\2c\20SkPoint\29 +2377:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::fixedFunctionFlags\28\29\20const +2378:skgpu::ganesh::SurfaceFillContext::~SurfaceFillContext\28\29 +2379:skgpu::ganesh::SurfaceFillContext::replaceOpsTask\28\29 +2380:skgpu::ganesh::SurfaceDrawContext::fillPixelsWithLocalMatrix\28GrClip\20const*\2c\20GrPaint&&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\29 +2381:skgpu::ganesh::SurfaceDrawContext::drawShape\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20GrStyledShape&&\29 +2382:skgpu::ganesh::SurfaceDrawContext::drawPaint\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\29 +2383:skgpu::ganesh::SurfaceDrawContext::MakeWithFallback\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20SkBackingFit\2c\20SkISize\2c\20SkSurfaceProps\20const&\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20skgpu::Budgeted\29 +2384:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29 +2385:skgpu::ganesh::SurfaceContext::transferPixels\28GrColorType\2c\20SkIRect\20const&\29::$_0::$_0\28$_0&&\29 +2386:skgpu::ganesh::SurfaceContext::PixelTransferResult::operator=\28skgpu::ganesh::SurfaceContext::PixelTransferResult&&\29 +2387:skgpu::ganesh::SupportedTextureFormats\28GrImageContext\20const&\29::$_0::operator\28\29\28SkYUVAPixmapInfo::DataType\2c\20int\29\20const +2388:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +2389:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::coverageMode\28\29\20const +2390:skgpu::ganesh::PathInnerTriangulateOp::pushFanFillProgram\28GrTessellationShader::ProgramArgs\20const&\2c\20GrUserStencilSettings\20const*\29 +2391:skgpu::ganesh::OpsTask::deleteOps\28\29 +2392:skgpu::ganesh::OpsTask::OpChain::List::operator=\28skgpu::ganesh::OpsTask::OpChain::List&&\29 +2393:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29::$_0::operator\28\29\28int\29\20const +2394:skgpu::ganesh::ClipStack::clipRect\28SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrAA\2c\20SkClipOp\29 +2395:skgpu::TClientMappedBufferManager::BufferFinishedMessage::BufferFinishedMessage\28skgpu::TClientMappedBufferManager::BufferFinishedMessage&&\29 +2396:skgpu::Swizzle::Concat\28skgpu::Swizzle\20const&\2c\20skgpu::Swizzle\20const&\29 +2397:skgpu::Swizzle::CToI\28char\29 +2398:sk_sp::reset\28SkMipmap*\29 +2399:sk_sp::~sk_sp\28\29 +2400:sk_sp::reset\28SkColorSpace*\29 +2401:sk_sp::~sk_sp\28\29 +2402:sk_sp::~sk_sp\28\29 +2403:skData_getSize +2404:shr +2405:shl +2406:set_result_path\28SkPath*\2c\20SkPath\20const&\2c\20SkPathFillType\29 +2407:sect_with_horizontal\28SkPoint\20const*\2c\20float\29 +2408:roughly_between\28double\2c\20double\2c\20double\29 +2409:pt_to_line\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +2410:psh_calc_max_height +2411:ps_mask_set_bit +2412:ps_dimension_set_mask_bits +2413:ps_builder_check_points +2414:ps_builder_add_point +2415:png_colorspace_endpoints_match +2416:path_is_trivial\28SkPath\20const&\29::Trivializer::addTrivialContourPoint\28SkPoint\20const&\29 +2417:output_char\28hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +2418:operator!=\28SkRect\20const&\2c\20SkRect\20const&\29 +2419:nearly_equal\28double\2c\20double\29 +2420:mbrtowc +2421:mask_gamma_cache_mutex\28\29 +2422:map_rect_perspective\28SkRect\20const&\2c\20float\20const*\29::$_0::operator\28\29\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20const +2423:lineMetrics_getEndIndex +2424:is_smooth_enough\28SkAnalyticEdge*\2c\20SkAnalyticEdge*\2c\20int\29 +2425:is_ICC_signature_char +2426:interpolate_local\28float\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float*\2c\20float*\2c\20float*\29 +2427:int\20_hb_cmp_method>\28void\20const*\2c\20void\20const*\29 +2428:ilogbf +2429:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +2430:hb_vector_t\2c\20false>::fini\28\29 +2431:hb_unicode_funcs_t::compose\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +2432:hb_syllabic_insert_dotted_circles\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +2433:hb_shape_full +2434:hb_serialize_context_t::~hb_serialize_context_t\28\29 +2435:hb_serialize_context_t::hb_serialize_context_t\28void*\2c\20unsigned\20int\29 +2436:hb_serialize_context_t::end_serialize\28\29 +2437:hb_paint_funcs_t::push_scale\28void*\2c\20float\2c\20float\29 +2438:hb_paint_funcs_t::push_clip_rectangle\28void*\2c\20float\2c\20float\2c\20float\2c\20float\29 +2439:hb_paint_extents_context_t::paint\28\29 +2440:hb_ot_map_builder_t::disable_feature\28unsigned\20int\29 +2441:hb_map_iter_t\2c\20OT::IntType\2c\20true>\20const>\2c\20hb_partial_t<2u\2c\20$_9\20const*\2c\20OT::ChainRuleSet\20const*>\2c\20\28hb_function_sortedness_t\290\2c\20\28void*\290>::__item__\28\29\20const +2442:hb_lazy_loader_t\2c\20hb_face_t\2c\2012u\2c\20OT::vmtx_accelerator_t>::get_stored\28\29\20const +2443:hb_lazy_loader_t\2c\20hb_face_t\2c\2038u\2c\20OT::sbix_accelerator_t>::do_destroy\28OT::sbix_accelerator_t*\29 +2444:hb_lazy_loader_t\2c\20hb_face_t\2c\205u\2c\20OT::hmtx_accelerator_t>::do_destroy\28OT::hmtx_accelerator_t*\29 +2445:hb_lazy_loader_t\2c\20hb_face_t\2c\2016u\2c\20OT::cff1_accelerator_t>::get_stored\28\29\20const +2446:hb_lazy_loader_t\2c\20hb_face_t\2c\2025u\2c\20OT::GSUB_accelerator_t>::do_destroy\28OT::GSUB_accelerator_t*\29 +2447:hb_lazy_loader_t\2c\20hb_face_t\2c\2026u\2c\20OT::GPOS_accelerator_t>::get_stored\28\29\20const +2448:hb_lazy_loader_t\2c\20hb_face_t\2c\2034u\2c\20hb_blob_t>::get\28\29\20const +2449:hb_language_from_string +2450:hb_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>\2c\20OT::HBGlyphID16&>::operator*\28\29 +2451:hb_hashmap_t::add\28unsigned\20int\20const&\29 +2452:hb_hashmap_t::alloc\28unsigned\20int\29 +2453:hb_font_t::parent_scale_position\28int*\2c\20int*\29 +2454:hb_font_t::get_h_extents_with_fallback\28hb_font_extents_t*\29 +2455:hb_buffer_t::output_glyph\28unsigned\20int\29 +2456:hb_buffer_t::copy_glyph\28\29 +2457:hb_buffer_t::clear_positions\28\29 +2458:hb_bounds_t*\20hb_vector_t::push\28hb_bounds_t&&\29 +2459:hb_blob_create_sub_blob +2460:hb_blob_create +2461:get_cache\28\29 +2462:ftell +2463:ft_var_readpackedpoints +2464:ft_glyphslot_free_bitmap +2465:float\20const*\20std::__2::min_element\5babi:ne180100\5d>\28float\20const*\2c\20float\20const*\2c\20std::__2::__less\29 +2466:float\20const*\20std::__2::max_element\5babi:ne180100\5d>\28float\20const*\2c\20float\20const*\2c\20std::__2::__less\29 +2467:filter_to_gl_mag_filter\28SkFilterMode\29 +2468:fflush +2469:extractMaskSubset\28SkMask\20const&\2c\20SkIRect\2c\20int\2c\20int\29 +2470:exp +2471:equal_ulps\28float\2c\20float\2c\20int\2c\20int\29 +2472:direct_blur_y\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2473:derivative_at_t\28double\20const*\2c\20double\29 +2474:crop_rect_edge\28SkRect\20const&\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float*\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +2475:cleanup_program\28GrGLGpu*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +2476:clean_paint_for_drawVertices\28SkPaint\29 +2477:clean_paint_for_drawImage\28SkPaint\20const*\29 +2478:check_edge_against_rect\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkRect\20const&\2c\20SkPathFirstDirection\29 +2479:checkOnCurve\28float\2c\20float\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +2480:char*\20sktext::gpu::BagOfBytes::allocateBytesFor\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +2481:cff_strcpy +2482:cff_size_get_globals_funcs +2483:cff_index_forget_element +2484:cf2_stack_setReal +2485:cf2_hint_init +2486:cf2_doStems +2487:cf2_doFlex +2488:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_4::operator\28\29\28float\29\20const +2489:buffer_verify_error\28hb_buffer_t*\2c\20hb_font_t*\2c\20char\20const*\2c\20...\29 +2490:bool\20hb_hashmap_t::has\28unsigned\20int\20const&\2c\20unsigned\20int**\29\20const +2491:bool\20hb_buffer_t::replace_glyphs\28unsigned\20int\2c\20unsigned\20int\2c\20OT::HBGlyphID16\20const*\29 +2492:bool\20OT::would_match_input>\28OT::hb_would_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\29 +2493:bool\20OT::match_input>\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +2494:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +2495:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +2496:blur_y_rect\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20unsigned\20short*\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +2497:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29::$_0::operator\28\29\28unsigned\20char*\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29\20const +2498:blitClippedMask\28SkBlitter*\2c\20SkMask\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29 +2499:approx_arc_length\28SkPoint\20const*\2c\20int\29 +2500:antifillrect\28SkIRect\20const&\2c\20SkBlitter*\29 +2501:afm_parser_read_int +2502:af_sort_pos +2503:af_latin_hints_compute_segments +2504:acosf +2505:_hb_glyph_info_get_lig_num_comps\28hb_glyph_info_t\20const*\29 +2506:__uselocale +2507:__math_xflow +2508:__cxxabiv1::__base_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +2509:\28anonymous\20namespace\29::make_vertices_spec\28bool\2c\20bool\29 +2510:\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29 +2511:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28unsigned\20int\20const*\29::operator\28\29\28unsigned\20int\20const*\29\20const +2512:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2513:\28anonymous\20namespace\29::SkBlurImageFilter::kernelBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\2c\20bool\29\20const +2514:\28anonymous\20namespace\29::RunIteratorQueue::insert\28SkShaper::RunIterator*\2c\20int\29 +2515:\28anonymous\20namespace\29::RunIteratorQueue::CompareEntry\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29 +2516:\28anonymous\20namespace\29::PathGeoBuilder::ensureSpace\28int\2c\20int\2c\20SkPoint\20const*\29 +2517:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMangledName\28char\20const*\29 +2518:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29::'lambda'\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +2519:\28anonymous\20namespace\29::FillRectOpImpl::vertexSpec\28\29\20const +2520:\28anonymous\20namespace\29::CacheImpl::removeInternal\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +2521:WriteRingBuffer +2522:TT_Load_Context +2523:Skwasm::makeCurrent\28unsigned\20long\29 +2524:SkipCode +2525:SkYUVAPixmaps::~SkYUVAPixmaps\28\29 +2526:SkYUVAPixmaps::operator=\28SkYUVAPixmaps\20const&\29 +2527:SkYUVAPixmaps::SkYUVAPixmaps\28\29 +2528:SkWriter32::writeRRect\28SkRRect\20const&\29 +2529:SkWriter32::writeMatrix\28SkMatrix\20const&\29 +2530:SkWriter32::snapshotAsData\28\29\20const +2531:SkWBuffer::write\28void\20const*\2c\20unsigned\20long\29 +2532:SkVertices::approximateSize\28\29\20const +2533:SkTextBlobBuilder::~SkTextBlobBuilder\28\29 +2534:SkTextBlob::RunRecord::textBuffer\28\29\20const +2535:SkTextBlob::RunRecord::clusterBuffer\28\29\20const +2536:SkTextBlob::RunRecord::StorageSize\28unsigned\20int\2c\20unsigned\20int\2c\20SkTextBlob::GlyphPositioning\2c\20SkSafeMath*\29 +2537:SkTextBlob::RunRecord::Next\28SkTextBlob::RunRecord\20const*\29 +2538:SkTSpan::oppT\28double\29\20const +2539:SkTSpan::closestBoundedT\28SkDPoint\20const&\29\20const +2540:SkTSect::updateBounded\28SkTSpan*\2c\20SkTSpan*\2c\20SkTSpan*\29 +2541:SkTSect::trim\28SkTSpan*\2c\20SkTSect*\29 +2542:SkTSect::removeSpanRange\28SkTSpan*\2c\20SkTSpan*\29 +2543:SkTSect::removeCoincident\28SkTSpan*\2c\20bool\29 +2544:SkTSect::deleteEmptySpans\28\29 +2545:SkTInternalLList::Entry>::remove\28SkLRUCache::Entry*\29 +2546:SkTInternalLList>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry>::remove\28SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\29 +2547:SkTInternalLList>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry>::remove\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\29 +2548:SkTDStorage::insert\28int\2c\20int\2c\20void\20const*\29 +2549:SkTDStorage::insert\28int\29 +2550:SkTDStorage::erase\28int\2c\20int\29 +2551:SkTDArray::push_back\28int\20const&\29 +2552:SkTBlockList::pushItem\28\29 +2553:SkStrokeRec::applyToPath\28SkPath*\2c\20SkPath\20const&\29\20const +2554:SkString::set\28char\20const*\29 +2555:SkString::Rec::Make\28char\20const*\2c\20unsigned\20long\29 +2556:SkStrikeSpec::MakeCanonicalized\28SkFont\20const&\2c\20SkPaint\20const*\29 +2557:SkStrikeCache::GlobalStrikeCache\28\29 +2558:SkStrike::glyph\28SkPackedGlyphID\29 +2559:SkSpriteBlitter::~SkSpriteBlitter\28\29 +2560:SkShadowTessellator::MakeSpot\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkPoint3\20const&\2c\20float\2c\20bool\2c\20bool\29 +2561:SkShaders::MatrixRec::apply\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2562:SkShaderBlurAlgorithm::renderBlur\28SkRuntimeEffectBuilder*\2c\20SkFilterMode\2c\20SkISize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const::$_0::operator\28\29\28SkIRect\20const&\29\20const +2563:SkShaderBase::appendRootStages\28SkStageRec\20const&\2c\20SkMatrix\20const&\29\20const +2564:SkSemaphore::signal\28int\29 +2565:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +2566:SkScalerContext_FreeType::emboldenIfNeeded\28FT_FaceRec_*\2c\20FT_GlyphSlotRec_*\2c\20unsigned\20short\29 +2567:SkScaleToSides::AdjustRadii\28double\2c\20double\2c\20float*\2c\20float*\29 +2568:SkSamplingOptions::operator!=\28SkSamplingOptions\20const&\29\20const +2569:SkSTArenaAlloc<3332ul>::SkSTArenaAlloc\28unsigned\20long\29 +2570:SkSTArenaAlloc<1024ul>::SkSTArenaAlloc\28unsigned\20long\29 +2571:SkSL::write_stringstream\28SkSL::StringStream\20const&\2c\20SkSL::OutputStream&\29 +2572:SkSL::evaluate_3_way_intrinsic\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +2573:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29 +2574:SkSL::calculate_count\28double\2c\20double\2c\20double\2c\20bool\2c\20bool\29 +2575:SkSL::append_rtadjust_fixup_to_vertex_main\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::Block&\29::AppendRTAdjustFixupHelper::Pos\28\29\20const +2576:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +2577:SkSL::VarDeclaration::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\2c\20std::__2::unique_ptr>\29 +2578:SkSL::Type::priority\28\29\20const +2579:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20double\2c\20SkSL::Position\29\20const +2580:SkSL::Transform::EliminateDeadFunctions\28SkSL::Program&\29::$_0::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +2581:SkSL::SymbolTable::lookup\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +2582:SkSL::SymbolTable::isType\28std::__2::basic_string_view>\29\20const +2583:SkSL::Swizzle::MaskString\28skia_private::FixedArray<4\2c\20signed\20char>\20const&\29 +2584:SkSL::RP::SlotManager::mapVariableToSlots\28SkSL::Variable\20const&\2c\20SkSL::RP::SlotRange\29 +2585:SkSL::RP::Program::appendStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkSL::RP::Callbacks*\2c\20SkSpan\29\20const::$_0::operator\28\29\28\29\20const +2586:SkSL::RP::Program::appendCopy\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20std::byte*\2c\20SkSL::RP::ProgramOp\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29\20const +2587:SkSL::RP::Generator::store\28SkSL::RP::LValue&\29 +2588:SkSL::RP::Generator::popToSlotRangeUnmasked\28SkSL::RP::SlotRange\29 +2589:SkSL::RP::DynamicIndexLValue::dynamicSlotRange\28\29 +2590:SkSL::RP::Builder::ternary_op\28SkSL::RP::BuilderOp\2c\20int\29 +2591:SkSL::RP::Builder::simplifyPopSlotsUnmasked\28SkSL::RP::SlotRange*\29 +2592:SkSL::RP::Builder::push_zeros\28int\29 +2593:SkSL::RP::Builder::push_loop_mask\28\29 +2594:SkSL::RP::Builder::pad_stack\28int\29 +2595:SkSL::RP::Builder::exchange_src\28\29 +2596:SkSL::ProgramVisitor::visit\28SkSL::Program\20const&\29 +2597:SkSL::ProgramUsage::remove\28SkSL::Statement\20const*\29 +2598:SkSL::PrefixExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29 +2599:SkSL::PipelineStage::PipelineStageCodeGenerator::typedVariable\28SkSL::Type\20const&\2c\20std::__2::basic_string_view>\29 +2600:SkSL::PipelineStage::PipelineStageCodeGenerator::typeName\28SkSL::Type\20const&\29 +2601:SkSL::Parser::parseInitializer\28SkSL::Position\2c\20std::__2::unique_ptr>*\29 +2602:SkSL::Parser::nextRawToken\28\29 +2603:SkSL::Parser::arrayType\28SkSL::Type\20const*\2c\20int\2c\20SkSL::Position\29 +2604:SkSL::Parser::AutoSymbolTable::AutoSymbolTable\28SkSL::Parser*\2c\20std::__2::unique_ptr>*\2c\20bool\29 +2605:SkSL::MethodReference::~MethodReference\28\29_6386 +2606:SkSL::MethodReference::~MethodReference\28\29 +2607:SkSL::LiteralType::priority\28\29\20const +2608:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sub\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +2609:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_dot\28std::__2::array\20const&\29 +2610:SkSL::InterfaceBlock::arraySize\28\29\20const +2611:SkSL::IndexExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +2612:SkSL::GLSLCodeGenerator::writeExtension\28std::__2::basic_string_view>\2c\20bool\29 +2613:SkSL::FieldAccess::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20int\2c\20SkSL::FieldAccessOwnerKind\29 +2614:SkSL::ConstructorArray::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +2615:SkSL::Compiler::convertProgram\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::ProgramSettings\20const&\29 +2616:SkSL::Block::isEmpty\28\29\20const +2617:SkSL::Block::Make\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2618:SkSL::Block::MakeBlock\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +2619:SkSL::Analysis::DetectVarDeclarationWithoutScope\28SkSL::Statement\20const&\2c\20SkSL::ErrorReporter*\29 +2620:SkRuntimeEffect::Result::~Result\28\29 +2621:SkResourceCache::remove\28SkResourceCache::Rec*\29 +2622:SkRegion::writeToMemory\28void*\29\20const +2623:SkRegion::getBoundaryPath\28SkPath*\29\20const +2624:SkRegion::SkRegion\28SkRegion\20const&\29 +2625:SkRect\20skif::Mapping::map\28SkRect\20const&\2c\20SkMatrix\20const&\29 +2626:SkRect::set\28SkPoint\20const&\2c\20SkPoint\20const&\29 +2627:SkRect::offset\28SkPoint\20const&\29 +2628:SkRect::inset\28float\2c\20float\29 +2629:SkRect::center\28\29\20const +2630:SkRecords::Optional::~Optional\28\29 +2631:SkRecords::NoOp*\20SkRecord::replace\28int\29 +2632:SkReadBuffer::skip\28unsigned\20long\29 +2633:SkRasterPipeline::tailPointer\28\29 +2634:SkRasterPipeline::appendMatrix\28SkArenaAlloc*\2c\20SkMatrix\20const&\29 +2635:SkRasterPipeline::addMemoryContext\28SkRasterPipeline_MemoryCtx*\2c\20int\2c\20bool\2c\20bool\29 +2636:SkRasterClip::SkRasterClip\28SkIRect\20const&\29 +2637:SkRRect::setOval\28SkRect\20const&\29 +2638:SkRRect::initializeRect\28SkRect\20const&\29 +2639:SkRRect::MakeRectXY\28SkRect\20const&\2c\20float\2c\20float\29 +2640:SkRGBA4f<\28SkAlphaType\293>::operator==\28SkRGBA4f<\28SkAlphaType\293>\20const&\29\20const +2641:SkQuads::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +2642:SkPixelRef::~SkPixelRef\28\29 +2643:SkPixelRef::SkPixelRef\28int\2c\20int\2c\20void*\2c\20unsigned\20long\29 +2644:SkPictureRecord::~SkPictureRecord\28\29 +2645:SkPictureRecord::recordRestoreOffsetPlaceholder\28\29 +2646:SkPathStroker::quadStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2647:SkPathStroker::preJoinTo\28SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\2c\20bool\29 +2648:SkPathStroker::intersectRay\28SkQuadConstruct*\2c\20SkPathStroker::IntersectRayType\29\20const +2649:SkPathStroker::cubicStroke\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +2650:SkPathStroker::cubicPerpRay\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +2651:SkPathStroker::conicStroke\28SkConic\20const&\2c\20SkQuadConstruct*\29 +2652:SkPathRef::computeBounds\28\29\20const +2653:SkPathEdgeIter::SkPathEdgeIter\28SkPath\20const&\29 +2654:SkPathBuilder::incReserve\28int\2c\20int\29 +2655:SkPathBuilder::conicTo\28SkPoint\2c\20SkPoint\2c\20float\29 +2656:SkPath::rewind\28\29 +2657:SkPath::quadTo\28float\2c\20float\2c\20float\2c\20float\29 +2658:SkPath::getPoint\28int\29\20const +2659:SkPath::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +2660:SkPaint::operator=\28SkPaint&&\29 +2661:SkPaint::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +2662:SkPaint::canComputeFastBounds\28\29\20const +2663:SkPaint::SkPaint\28SkPaint&&\29 +2664:SkOpSpanBase::mergeMatches\28SkOpSpanBase*\29 +2665:SkOpSpanBase::addOpp\28SkOpSpanBase*\29 +2666:SkOpSegment::updateOppWinding\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\29\20const +2667:SkOpSegment::subDivide\28SkOpSpanBase\20const*\2c\20SkOpSpanBase\20const*\2c\20SkDCurve*\29\20const +2668:SkOpSegment::setUpWindings\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\2c\20int*\2c\20int*\2c\20int*\2c\20int*\2c\20int*\29 +2669:SkOpSegment::nextChase\28SkOpSpanBase**\2c\20int*\2c\20SkOpSpan**\2c\20SkOpSpanBase**\29\20const +2670:SkOpSegment::markAndChaseDone\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpSpanBase**\29 +2671:SkOpSegment::isSimple\28SkOpSpanBase**\2c\20int*\29\20const +2672:SkOpSegment::init\28SkPoint*\2c\20float\2c\20SkOpContour*\2c\20SkPath::Verb\29 +2673:SkOpEdgeBuilder::complete\28\29 +2674:SkOpContour::appendSegment\28\29 +2675:SkOpCoincidence::overlap\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20double*\2c\20double*\29\20const +2676:SkOpCoincidence::add\28SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\2c\20SkOpPtT*\29 +2677:SkOpCoincidence::addIfMissing\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20double\2c\20double\2c\20SkOpSegment*\2c\20SkOpSegment*\2c\20bool*\29 +2678:SkOpCoincidence::addExpanded\28\29 +2679:SkOpCoincidence::addEndMovedSpans\28SkOpPtT\20const*\29 +2680:SkOpCoincidence::TRange\28SkOpPtT\20const*\2c\20double\2c\20SkOpSegment\20const*\29 +2681:SkOpAngle::set\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +2682:SkOpAngle::loopCount\28\29\20const +2683:SkOpAngle::insert\28SkOpAngle*\29 +2684:SkOpAngle*\20SkArenaAlloc::make\28\29 +2685:SkNoPixelsDevice::ClipState::op\28SkClipOp\2c\20SkM44\20const&\2c\20SkRect\20const&\2c\20bool\2c\20bool\29 +2686:SkMipmap*\20SkSafeRef\28SkMipmap*\29 +2687:SkMeshSpecification::Varying::Varying\28SkMeshSpecification::Varying\20const&\29 +2688:SkMatrixPriv::DifferentialAreaScale\28SkMatrix\20const&\2c\20SkPoint\20const&\29 +2689:SkMatrix::setRotate\28float\29 +2690:SkMatrix::mapVectors\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29\20const +2691:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint\20const*\2c\20int\29\20const +2692:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29 +2693:SkM44::setConcat\28SkM44\20const&\2c\20SkM44\20const&\29::$_0::operator\28\29\28skvx::Vec<4\2c\20float>\29\20const +2694:SkM44::normalizePerspective\28\29 +2695:SkLineClipper::IntersectLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\29 +2696:SkImage_Ganesh::makeView\28GrRecordingContext*\29\20const +2697:SkImage_Base::~SkImage_Base\28\29 +2698:SkImage_Base::isGaneshBacked\28\29\20const +2699:SkImage_Base::SkImage_Base\28SkImageInfo\20const&\2c\20unsigned\20int\29 +2700:SkImageInfo::validRowBytes\28unsigned\20long\29\20const +2701:SkImageInfo::MakeUnknown\28int\2c\20int\29 +2702:SkImageGenerator::~SkImageGenerator\28\29 +2703:SkImageFilters::Crop\28SkRect\20const&\2c\20SkTileMode\2c\20sk_sp\29 +2704:SkImageFilter_Base::~SkImageFilter_Base\28\29 +2705:SkImage::makeRasterImage\28GrDirectContext*\2c\20SkImage::CachingHint\29\20const +2706:SkIRect::makeInset\28int\2c\20int\29\20const +2707:SkHalfToFloat\28unsigned\20short\29 +2708:SkGradientBaseShader::commonAsAGradient\28SkShaderBase::GradientInfo*\29\20const +2709:SkGradientBaseShader::ValidGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\29 +2710:SkGradientBaseShader::SkGradientBaseShader\28SkGradientBaseShader::Descriptor\20const&\2c\20SkMatrix\20const&\29 +2711:SkGradientBaseShader::MakeDegenerateGradient\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20float\20const*\2c\20int\2c\20sk_sp\2c\20SkTileMode\29 +2712:SkGlyph::setPath\28SkArenaAlloc*\2c\20SkPath\20const*\2c\20bool\2c\20bool\29 +2713:SkGetPolygonWinding\28SkPoint\20const*\2c\20int\29 +2714:SkFontMgr::RefEmpty\28\29 +2715:SkFont::setTypeface\28sk_sp\29 +2716:SkEmptyFontMgr::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +2717:SkEdgeBuilder::~SkEdgeBuilder\28\29 +2718:SkDrawable::draw\28SkCanvas*\2c\20SkMatrix\20const*\29 +2719:SkDrawBase::drawPathCoverage\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkBlitter*\29\20const +2720:SkDevice::~SkDevice\28\29 +2721:SkDevice::scalerContextFlags\28\29\20const +2722:SkDevice::accessPixels\28SkPixmap*\29 +2723:SkData::MakeWithProc\28void\20const*\2c\20unsigned\20long\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +2724:SkDQuad::dxdyAtT\28double\29\20const +2725:SkDQuad::RootsReal\28double\2c\20double\2c\20double\2c\20double*\29 +2726:SkDPoint::distance\28SkDPoint\20const&\29\20const +2727:SkDLine::NearPointV\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +2728:SkDLine::NearPointH\28SkDPoint\20const&\2c\20double\2c\20double\2c\20double\29 +2729:SkDCubic::dxdyAtT\28double\29\20const +2730:SkDCubic::RootsValidT\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +2731:SkDConic::dxdyAtT\28double\29\20const +2732:SkConicalGradient::~SkConicalGradient\28\29 +2733:SkComputeRadialSteps\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float*\2c\20float*\2c\20int*\29 +2734:SkColorFilterPriv::MakeGaussian\28\29 +2735:SkColorFilter::filterColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkColorSpace*\2c\20SkColorSpace*\29\20const +2736:SkColorConverter::SkColorConverter\28unsigned\20int\20const*\2c\20int\29 +2737:SkCoincidentSpans::correctOneEnd\28SkOpPtT\20const*\20\28SkCoincidentSpans::*\29\28\29\20const\2c\20void\20\28SkCoincidentSpans::*\29\28SkOpPtT\20const*\29\29 +2738:SkClosestRecord::findEnd\28SkTSpan\20const*\2c\20SkTSpan\20const*\2c\20int\2c\20int\29 +2739:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\20const*\2c\20int\29 +2740:SkChopCubicAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +2741:SkCanvas::init\28sk_sp\29 +2742:SkCanvas::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +2743:SkCanvas::concat\28SkM44\20const&\29 +2744:SkCanvas::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +2745:SkCachedData::detachFromCacheAndUnref\28\29\20const +2746:SkCachedData::attachToCacheAndRef\28\29\20const +2747:SkBitmap::pixelRefOrigin\28\29\20const +2748:SkBitmap::operator=\28SkBitmap&&\29 +2749:SkBitmap::notifyPixelsChanged\28\29\20const +2750:SkBitmap::extractSubset\28SkBitmap*\2c\20SkIRect\20const&\29\20const +2751:SkBinaryWriteBuffer::writeByteArray\28void\20const*\2c\20unsigned\20long\29 +2752:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29 +2753:SkAutoPixmapStorage::tryAlloc\28SkImageInfo\20const&\29 +2754:SkAutoBlitterChoose::SkAutoBlitterChoose\28SkDrawBase\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const&\2c\20bool\29 +2755:SkArenaAllocWithReset::SkArenaAllocWithReset\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +2756:SkAAClip::setPath\28SkPath\20const&\2c\20SkIRect\20const&\2c\20bool\29 +2757:SkAAClip::quickContains\28SkIRect\20const&\29\20const +2758:SkAAClip::op\28SkAAClip\20const&\2c\20SkClipOp\29 +2759:SkAAClip::Builder::flushRowH\28SkAAClip::Builder::Row*\29 +2760:SkAAClip::Builder::Blitter::checkForYGap\28int\29 +2761:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29 +2762:ReadHuffmanCode +2763:OT::post::accelerator_t::find_glyph_name\28unsigned\20int\29\20const +2764:OT::hb_ot_layout_lookup_accelerator_t::apply\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20bool\29\20const +2765:OT::hb_ot_apply_context_t::skipping_iterator_t::match\28hb_glyph_info_t&\29 +2766:OT::hb_ot_apply_context_t::_set_glyph_class\28unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\29 +2767:OT::glyf_accelerator_t::glyph_for_gid\28unsigned\20int\2c\20bool\29\20const +2768:OT::cff1::accelerator_templ_t>::std_code_to_glyph\28unsigned\20int\29\20const +2769:OT::apply_lookup\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20OT::LookupRecord\20const*\2c\20unsigned\20int\29 +2770:OT::VariationStore::create_cache\28\29\20const +2771:OT::VarRegionList::evaluate\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +2772:OT::Lookup::get_props\28\29\20const +2773:OT::Layout::GSUB_impl::SubstLookup*\20hb_serialize_context_t::copy\28\29\20const +2774:OT::Layout::GPOS_impl::ValueFormat::get_device\28OT::IntType\20const*\2c\20bool*\2c\20void\20const*\2c\20hb_sanitize_context_t&\29 +2775:OT::Layout::GPOS_impl::Anchor::get_anchor\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20float*\2c\20float*\29\20const +2776:OT::IntType*\20hb_serialize_context_t::extend_min>\28OT::IntType*\29 +2777:OT::GSUBGPOS::get_script\28unsigned\20int\29\20const +2778:OT::GSUBGPOS::get_feature_tag\28unsigned\20int\29\20const +2779:OT::GSUBGPOS::find_script_index\28unsigned\20int\2c\20unsigned\20int*\29\20const +2780:OT::ArrayOf>*\20hb_serialize_context_t::extend_size>>\28OT::ArrayOf>*\2c\20unsigned\20long\2c\20bool\29 +2781:Move_Zp2_Point +2782:Modify_CVT_Check +2783:GrYUVATextureProxies::operator=\28GrYUVATextureProxies&&\29 +2784:GrYUVATextureProxies::GrYUVATextureProxies\28\29 +2785:GrXPFactory::FromBlendMode\28SkBlendMode\29 +2786:GrWindowRectangles::operator=\28GrWindowRectangles\20const&\29 +2787:GrTriangulator::~GrTriangulator\28\29 +2788:GrTriangulator::simplify\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +2789:GrTriangulator::setTop\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2790:GrTriangulator::mergeCollinearEdges\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +2791:GrTriangulator::mergeCoincidentVertices\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29\20const +2792:GrTriangulator::emitTriangle\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20skgpu::VertexWriter\29\20const +2793:GrTriangulator::allocateEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20GrTriangulator::EdgeType\29 +2794:GrTriangulator::FindEnclosingEdges\28GrTriangulator::Vertex\20const&\2c\20GrTriangulator::EdgeList\20const&\2c\20GrTriangulator::Edge**\2c\20GrTriangulator::Edge**\29 +2795:GrTriangulator::Edge::dist\28SkPoint\20const&\29\20const +2796:GrTriangulator::Edge::Edge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20int\2c\20GrTriangulator::EdgeType\29 +2797:GrThreadSafeCache::remove\28skgpu::UniqueKey\20const&\29 +2798:GrThreadSafeCache::internalFind\28skgpu::UniqueKey\20const&\29 +2799:GrThreadSafeCache::internalAdd\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29 +2800:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +2801:GrTextureEffect::GrTextureEffect\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20GrTextureEffect::Sampling\20const&\29 +2802:GrTessellationShader::MakePipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedClip&&\2c\20GrProcessorSet&&\29 +2803:GrSurfaceProxyView::operator!=\28GrSurfaceProxyView\20const&\29\20const +2804:GrSurfaceProxyView::concatSwizzle\28skgpu::Swizzle\29 +2805:GrSurfaceProxy::~GrSurfaceProxy\28\29 +2806:GrSurfaceProxy::isFunctionallyExact\28\29\20const +2807:GrSurfaceProxy::gpuMemorySize\28\29\20const +2808:GrSurfaceProxy::createSurfaceImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\29\20const +2809:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkIRect\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20GrSurfaceProxy::RectsMustMatch\2c\20sk_sp*\29 +2810:GrSurfaceProxy::Copy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20std::__2::basic_string_view>\2c\20sk_sp*\29 +2811:GrStyledShape::hasUnstyledKey\28\29\20const +2812:GrStyledShape::GrStyledShape\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +2813:GrStyle::GrStyle\28GrStyle\20const&\29 +2814:GrSkSLFP::setInput\28std::__2::unique_ptr>\29 +2815:GrSimpleMeshDrawOpHelper::CreatePipeline\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20skgpu::Swizzle\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrProcessorSet&&\2c\20GrPipeline::InputFlags\29 +2816:GrSimpleMesh::set\28sk_sp\2c\20int\2c\20int\29 +2817:GrShape::simplifyRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20unsigned\20int\29 +2818:GrShape::simplifyRRect\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20unsigned\20int\29 +2819:GrShape::simplifyPoint\28SkPoint\20const&\2c\20unsigned\20int\29 +2820:GrShape::simplifyLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\29 +2821:GrShape::setInverted\28bool\29 +2822:GrSWMaskHelper::init\28SkIRect\20const&\29 +2823:GrSWMaskHelper::GrSWMaskHelper\28SkAutoPixmapStorage*\29 +2824:GrResourceProvider::refNonAAQuadIndexBuffer\28\29 +2825:GrRenderTask::addTarget\28GrDrawingManager*\2c\20sk_sp\29 +2826:GrRenderTarget::~GrRenderTarget\28\29 +2827:GrQuadUtils::WillUseHairline\28GrQuad\20const&\2c\20GrAAType\2c\20GrQuadAAFlags\29 +2828:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::unpackQuad\28GrQuad::Type\2c\20float\20const*\2c\20GrQuad*\29\20const +2829:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::MetadataIter::next\28\29 +2830:GrProxyProvider::processInvalidUniqueKey\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\2c\20GrProxyProvider::InvalidateGPUResource\29 +2831:GrProxyProvider::createMippedProxyFromBitmap\28SkBitmap\20const&\2c\20skgpu::Budgeted\29::$_0::~$_0\28\29 +2832:GrProgramInfo::GrProgramInfo\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrGeometryProcessor\20const*\2c\20GrPrimitiveType\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +2833:GrPipeline::visitProxies\28std::__2::function\20const&\29\20const +2834:GrPathUtils::scaleToleranceToSrc\28float\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +2835:GrPathUtils::generateQuadraticPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +2836:GrPathUtils::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint**\2c\20unsigned\20int\29 +2837:GrPathUtils::cubicPointCount\28SkPoint\20const*\2c\20float\29 +2838:GrPaint::GrPaint\28GrPaint\20const&\29 +2839:GrOpsRenderPass::prepareToDraw\28\29 +2840:GrOpFlushState::~GrOpFlushState\28\29 +2841:GrOpFlushState::drawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +2842:GrOpFlushState::bindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const&\2c\20GrPipeline\20const&\29 +2843:GrOp::uniqueID\28\29\20const +2844:GrNativeRect::MakeIRectRelativeTo\28GrSurfaceOrigin\2c\20int\2c\20SkIRect\29 +2845:GrMeshDrawOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +2846:GrMapRectPoints\28SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkPoint*\2c\20int\29 +2847:GrMakeKeyFromImageID\28skgpu::UniqueKey*\2c\20unsigned\20int\2c\20SkIRect\20const&\29 +2848:GrGradientShader::MakeGradientFP\28SkGradientBaseShader\20const&\2c\20GrFPArgs\20const&\2c\20SkShaders::MatrixRec\20const&\2c\20std::__2::unique_ptr>\2c\20SkMatrix\20const*\29 +2849:GrGpuResource::setUniqueKey\28skgpu::UniqueKey\20const&\29 +2850:GrGpuResource::registerWithCache\28skgpu::Budgeted\29 +2851:GrGpu::writePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +2852:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +2853:GrGLTexture::onSetLabel\28\29 +2854:GrGLTexture::onAbandon\28\29 +2855:GrGLTexture::backendFormat\28\29\20const +2856:GrGLSLVaryingHandler::appendDecls\28SkTBlockList\20const&\2c\20SkString*\29\20const +2857:GrGLSLShaderBuilder::newTmpVarName\28char\20const*\29 +2858:GrGLSLShaderBuilder::definitionAppend\28char\20const*\29 +2859:GrGLSLProgramBuilder::invokeFP\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +2860:GrGLSLProgramBuilder::advanceStage\28\29 +2861:GrGLSLFragmentShaderBuilder::dstColor\28\29 +2862:GrGLRenderTarget::bindInternal\28unsigned\20int\2c\20bool\29 +2863:GrGLGpu::unbindXferBuffer\28GrGpuBufferType\29 +2864:GrGLGpu::resolveRenderFBOs\28GrGLRenderTarget*\2c\20SkIRect\20const&\2c\20GrGLRenderTarget::ResolveDirection\2c\20bool\29 +2865:GrGLGpu::flushBlendAndColorWrite\28skgpu::BlendInfo\20const&\2c\20skgpu::Swizzle\20const&\29 +2866:GrGLGpu::currentProgram\28\29 +2867:GrGLGpu::SamplerObjectCache::Sampler::~Sampler\28\29 +2868:GrGLGpu::HWVertexArrayState::setVertexArrayID\28GrGLGpu*\2c\20unsigned\20int\29 +2869:GrGLGetVersionFromString\28char\20const*\29 +2870:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\29 +2871:GrGLFunction::GrGLFunction\28unsigned\20char\20const*\20\28*\29\28unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\29 +2872:GrGLFinishCallbacks::callAll\28bool\29 +2873:GrGLCheckLinkStatus\28GrGLGpu\20const*\2c\20unsigned\20int\2c\20bool\2c\20skgpu::ShaderErrorHandler*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const**\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +2874:GrGLAttribArrayState::set\28GrGLGpu*\2c\20int\2c\20GrBuffer\20const*\2c\20GrVertexAttribType\2c\20SkSLType\2c\20int\2c\20unsigned\20long\2c\20int\29 +2875:GrFragmentProcessors::Make\28SkBlenderBase\20const*\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20GrFPArgs\20const&\29 +2876:GrFragmentProcessor::isEqual\28GrFragmentProcessor\20const&\29\20const +2877:GrFragmentProcessor::Rect\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRect\29 +2878:GrFragmentProcessor::ModulateRGBA\28std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +2879:GrDstProxyView::setProxyView\28GrSurfaceProxyView\29 +2880:GrDrawingManager::removeRenderTasks\28\29 +2881:GrDrawingManager::getPathRenderer\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\2c\20bool\2c\20skgpu::ganesh::PathRendererChain::DrawType\2c\20skgpu::ganesh::PathRenderer::StencilSupport*\29 +2882:GrDrawingManager::getLastRenderTask\28GrSurfaceProxy\20const*\29\20const +2883:GrDrawOpAtlas::updatePlot\28GrDeferredUploadTarget*\2c\20skgpu::AtlasLocator*\2c\20skgpu::Plot*\29::'lambda'\28std::__2::function&\29::\28'lambda'\28std::__2::function&\29\20const&\29 +2884:GrDrawOpAtlas::processEvictionAndResetRects\28skgpu::Plot*\29 +2885:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29 +2886:GrDeferredProxyUploader::wait\28\29 +2887:GrCpuBuffer::Make\28unsigned\20long\29 +2888:GrContext_Base::~GrContext_Base\28\29 +2889:GrColorSpaceXform::Make\28SkColorSpace*\2c\20SkAlphaType\2c\20SkColorSpace*\2c\20SkAlphaType\29 +2890:GrColorInfo::operator=\28GrColorInfo\20const&\29 +2891:GrClip::IsPixelAligned\28SkRect\20const&\29 +2892:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29::'lambda0'\28float\29::operator\28\29\28float\29\20const +2893:GrClip::GetPixelIBounds\28SkRect\20const&\2c\20GrAA\2c\20GrClip::BoundsType\29::'lambda'\28float\29::operator\28\29\28float\29\20const +2894:GrCaps::supportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +2895:GrCaps::getFallbackColorTypeAndFormat\28GrColorType\2c\20int\29\20const +2896:GrCaps::areColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +2897:GrBufferAllocPool::~GrBufferAllocPool\28\29_8440 +2898:GrBufferAllocPool::makeSpace\28unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\29 +2899:GrBufferAllocPool::GrBufferAllocPool\28GrGpu*\2c\20GrGpuBufferType\2c\20sk_sp\29 +2900:GrBlurUtils::DrawShapeWithMaskFilter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\29 +2901:GrBackendTexture::GrBackendTexture\28GrBackendTexture\20const&\29 +2902:GrBackendRenderTarget::getBackendFormat\28\29\20const +2903:GrAAConvexTessellator::createOuterRing\28GrAAConvexTessellator::Ring\20const&\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring*\29 +2904:GrAAConvexTessellator::createInsetRings\28GrAAConvexTessellator::Ring&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20GrAAConvexTessellator::Ring**\29 +2905:GrAAConvexTessellator::Ring::init\28GrAAConvexTessellator\20const&\29 +2906:FwDCubicEvaluator::FwDCubicEvaluator\28SkPoint\20const*\29 +2907:FT_Stream_ReadAt +2908:FT_Stream_Free +2909:FT_Set_Charmap +2910:FT_New_Size +2911:FT_Load_Sfnt_Table +2912:FT_List_Find +2913:FT_GlyphLoader_Add +2914:FT_Get_Next_Char +2915:FT_Get_Color_Glyph_Layer +2916:FT_CMap_New +2917:Current_Ratio +2918:Compute_Funcs +2919:CircleOp::Circle&\20skia_private::TArray::emplace_back\28CircleOp::Circle&&\29 +2920:CFF::path_procs_t\2c\20cff2_path_param_t>::curve2\28CFF::cff2_cs_interp_env_t&\2c\20cff2_path_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2921:CFF::path_procs_t\2c\20cff2_extents_param_t>::curve2\28CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2922:CFF::path_procs_t::curve2\28CFF::cff1_cs_interp_env_t&\2c\20cff1_path_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2923:CFF::path_procs_t::curve2\28CFF::cff1_cs_interp_env_t&\2c\20cff1_extents_param_t&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\2c\20CFF::point_t\20const&\29 +2924:CFF::parsed_values_t::operator=\28CFF::parsed_values_t&&\29 +2925:CFF::cs_interp_env_t>>::return_from_subr\28\29 +2926:CFF::cs_interp_env_t>>::call_subr\28CFF::biased_subrs_t>>\20const&\2c\20CFF::cs_type_t\29 +2927:CFF::cs_interp_env_t>>::call_subr\28CFF::biased_subrs_t>>\20const&\2c\20CFF::cs_type_t\29 +2928:CFF::byte_str_ref_t::operator\5b\5d\28int\29 +2929:CFF::arg_stack_t::push_fixed_from_substr\28CFF::byte_str_ref_t&\29 +2930:CFF::CFFIndex>::sanitize\28hb_sanitize_context_t*\29\20const +2931:CFF::CFFIndex>::operator\5b\5d\28unsigned\20int\29\20const +2932:CFF::CFFIndex>::offset_at\28unsigned\20int\29\20const +2933:AlmostLessOrEqualUlps\28float\2c\20float\29 +2934:AlmostEqualUlps_Pin\28double\2c\20double\29 +2935:ActiveEdge::intersect\28ActiveEdge\20const*\29 +2936:AAT::Lookup::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +2937:AAT::ClassTable>::get_class\28unsigned\20int\2c\20unsigned\20int\29\20const +2938:2729 +2939:2730 +2940:2731 +2941:2732 +2942:2733 +2943:2734 +2944:week_num +2945:wcrtomb +2946:void\20std::__2::vector>::__construct_at_end\28skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20unsigned\20long\29 +2947:void\20std::__2::vector>::__construct_at_end\28SkString*\2c\20SkString*\2c\20unsigned\20long\29 +2948:void\20std::__2::__sort4\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +2949:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +2950:void\20std::__2::__sort4\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +2951:void\20std::__2::__inplace_merge\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\2c\20long\29 +2952:void\20skgpu::ganesh::SurfaceFillContext::clear<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\20const&\29 +2953:void\20skgpu::VertexWriter::writeQuad\28GrQuad\20const&\29 +2954:void\20merge_sort<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +2955:void\20merge_sort<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\29 +2956:void\20hb_stable_sort\2c\20unsigned\20int>\28OT::HBGlyphID16*\2c\20unsigned\20int\2c\20int\20\28*\29\28OT::IntType\20const*\2c\20OT::IntType\20const*\29\2c\20unsigned\20int*\29 +2957:void\20SkSafeUnref\28SkMeshSpecification*\29 +2958:void\20SkSafeUnref\28SkMeshPriv::VB\20const*\29 +2959:void\20SkSafeUnref\28GrTexture*\29\20\28.4445\29 +2960:void\20SkSafeUnref\28GrCpuBuffer*\29 +2961:vfprintf +2962:valid_args\28SkImageInfo\20const&\2c\20unsigned\20long\2c\20unsigned\20long*\29 +2963:uprv_malloc_skia +2964:update_offset_to_base\28char\20const*\2c\20long\29 +2965:unsigned\20long\20std::__2::__str_find\5babi:ne180100\5d\2c\204294967295ul>\28char\20const*\2c\20unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +2966:unsigned\20long\20const&\20std::__2::min\5babi:nn180100\5d\28unsigned\20long\20const&\2c\20unsigned\20long\20const&\29 +2967:ubidi_getRuns_skia +2968:u_charMirror_skia +2969:tt_size_reset +2970:tt_sbit_decoder_load_metrics +2971:tt_glyphzone_done +2972:tt_face_get_location +2973:tt_face_find_bdf_prop +2974:tt_delta_interpolate +2975:tt_cmap14_find_variant +2976:tt_cmap14_char_map_nondef_binary +2977:tt_cmap14_char_map_def_binary +2978:top12_14140 +2979:tolower +2980:t1_cmap_unicode_done +2981:subdivide_cubic_to\28SkPath*\2c\20SkPoint\20const*\2c\20int\29 +2982:strtox.9350 +2983:strtox +2984:strtoull_l +2985:std::logic_error::~logic_error\28\29_15539 +2986:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +2987:std::__2::vector>\2c\20std::__2::allocator>>>::erase\28std::__2::__wrap_iter>\20const*>\2c\20std::__2::__wrap_iter>\20const*>\29 +2988:std::__2::vector>::__alloc\5babi:nn180100\5d\28\29 +2989:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +2990:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +2991:std::__2::vector\2c\20std::__2::allocator>>::vector\5babi:ne180100\5d\28std::__2::vector\2c\20std::__2::allocator>>&&\29 +2992:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +2993:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +2994:std::__2::vector>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +2995:std::__2::vector>::push_back\5babi:ne180100\5d\28SkString\20const&\29 +2996:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +2997:std::__2::vector\2c\20std::__2::allocator>>::push_back\5babi:ne180100\5d\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +2998:std::__2::vector\2c\20std::__2::allocator>>::__recommend\5babi:ne180100\5d\28unsigned\20long\29\20const +2999:std::__2::vector>::push_back\5babi:ne180100\5d\28SkMeshSpecification::Attribute&&\29 +3000:std::__2::unique_ptr\2c\20void*>\2c\20std::__2::__hash_node_destructor\2c\20void*>>>>::~unique_ptr\5babi:ne180100\5d\28\29 +3001:std::__2::unique_ptr::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3002:std::__2::unique_ptr\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3003:std::__2::unique_ptr>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3004:std::__2::unique_ptr::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +3005:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3006:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3007:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkTypeface_FreeType::FaceRec*\29 +3008:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkStrikeSpec*\29 +3009:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3010:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3011:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Pool*\29 +3012:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Block*\29 +3013:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkDrawableList*\29 +3014:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3015:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkContourMeasureIter::Impl*\29 +3016:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3017:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3018:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3019:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrGLGpu::SamplerObjectCache*\29 +3020:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28std::nullptr_t\29 +3021:std::__2::unique_ptr>\20GrBlendFragmentProcessor::Make<\28SkBlendMode\296>\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3022:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrDrawingManager*\29 +3023:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrClientMappedBufferManager*\29 +3024:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +3025:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28FT_FaceRec_*\29 +3026:std::__2::tuple&\20std::__2::tuple::operator=\5babi:ne180100\5d\28std::__2::pair&&\29 +3027:std::__2::time_put>>::~time_put\28\29 +3028:std::__2::pair\20std::__2::minmax\5babi:ne180100\5d>\28std::initializer_list\2c\20std::__2::__less\29 +3029:std::__2::locale::locale\28\29 +3030:std::__2::locale::__imp::acquire\28\29 +3031:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\29 +3032:std::__2::ios_base::~ios_base\28\29 +3033:std::__2::ios_base::clear\28unsigned\20int\29 +3034:std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::operator\28\29\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29\20const +3035:std::__2::function\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const +3036:std::__2::fpos<__mbstate_t>::fpos\5babi:nn180100\5d\28long\20long\29 +3037:std::__2::enable_if::value\2c\20SkRuntimeEffectBuilder::BuilderUniform&>::type\20SkRuntimeEffectBuilder::BuilderUniform::operator=\28SkV2\20const&\29 +3038:std::__2::enable_if\28\29\20==\20std::declval\28\29\29\2c\20bool>\2c\20bool>::type\20std::__2::operator==\5babi:ne180100\5d\28std::__2::optional\20const&\2c\20std::__2::optional\20const&\29 +3039:std::__2::deque>::__back_spare\5babi:ne180100\5d\28\29\20const +3040:std::__2::default_delete::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::_EnableIfConvertible::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot>::type\20std::__2::default_delete::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot>\28skia_private::THashTable::Pair\2c\20char\20const*\2c\20skia_private::THashMap::Pair>::Slot*\29\20const +3041:std::__2::default_delete::Traits>::Slot\20\5b\5d>::_EnableIfConvertible::Traits>::Slot>::type\20std::__2::default_delete::Traits>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Traits>::Slot>\28skia_private::THashTable::Traits>::Slot*\29\20const +3042:std::__2::chrono::__libcpp_steady_clock_now\28\29 +3043:std::__2::char_traits::move\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20unsigned\20long\29 +3044:std::__2::char_traits::assign\5babi:nn180100\5d\28char*\2c\20unsigned\20long\2c\20char\29 +3045:std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_14474 +3046:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29 +3047:std::__2::basic_string\2c\20std::__2::allocator>::push_back\28wchar_t\29 +3048:std::__2::basic_string\2c\20std::__2::allocator>::capacity\5babi:nn180100\5d\28\29\20const +3049:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d<0>\28wchar_t\20const*\29 +3050:std::__2::basic_string\2c\20std::__2::allocator>::__make_iterator\5babi:nn180100\5d\28char*\29 +3051:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +3052:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +3053:std::__2::basic_streambuf>::~basic_streambuf\28\29 +3054:std::__2::basic_streambuf>::step\5babi:nn180100\5d\28char*\2c\20char*\29 +3055:std::__2::basic_istream>::~basic_istream\28\29 +3056:std::__2::basic_istream>::sentry::sentry\28std::__2::basic_istream>&\2c\20bool\29 +3057:std::__2::basic_iostream>::~basic_iostream\28\29_14364 +3058:std::__2::basic_ios>::~basic_ios\28\29 +3059:std::__2::array\20skgpu::ganesh::SurfaceFillContext::adjustColorAlphaType<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\29\20const +3060:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +3061:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +3062:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +3063:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +3064:std::__2::__wrap_iter::operator+\5babi:nn180100\5d\28long\29\20const +3065:std::__2::__wrap_iter::operator++\5babi:nn180100\5d\28\29 +3066:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28GrRecordingContext*&&\2c\20GrSurfaceProxyView&&\2c\20GrSurfaceProxyView&&\2c\20GrColorInfo\20const&\29 +3067:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28GrRecordingContext*&\2c\20skgpu::ganesh::PathRendererChain::Options&\29 +3068:std::__2::__unique_if>::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\2c\20GrDirectContext::DirectContextID>\28GrDirectContext::DirectContextID&&\29 +3069:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::SymbolTable*&\2c\20bool&\29 +3070:std::__2::__tuple_impl\2c\20GrSurfaceProxyView\2c\20sk_sp>::~__tuple_impl\28\29 +3071:std::__2::__split_buffer>::__destruct_at_end\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock**\2c\20std::__2::integral_constant\29 +3072:std::__2::__split_buffer&>::~__split_buffer\28\29 +3073:std::__2::__optional_destruct_base>\2c\20false>::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3074:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3075:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +3076:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +3077:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +3078:std::__2::__optional_copy_base::__optional_copy_base\5babi:ne180100\5d\28std::__2::__optional_copy_base\20const&\29 +3079:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20wchar_t*\2c\20wchar_t&\2c\20wchar_t&\29 +3080:std::__2::__num_get::__stage2_float_loop\28wchar_t\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20wchar_t*\29 +3081:std::__2::__num_get::__stage2_float_prep\28std::__2::ios_base&\2c\20char*\2c\20char&\2c\20char&\29 +3082:std::__2::__num_get::__stage2_float_loop\28char\2c\20bool&\2c\20char&\2c\20char*\2c\20char*&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int*\2c\20unsigned\20int*&\2c\20unsigned\20int&\2c\20char*\29 +3083:std::__2::__murmur2_or_cityhash::operator\28\29\5babi:ne180100\5d\28void\20const*\2c\20unsigned\20long\29\20const +3084:std::__2::__libcpp_wcrtomb_l\5babi:nn180100\5d\28char*\2c\20wchar_t\2c\20__mbstate_t*\2c\20__locale_struct*\29 +3085:std::__2::__itoa::__base_10_u32\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +3086:std::__2::__itoa::__append6\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +3087:std::__2::__itoa::__append4\5babi:nn180100\5d\28char*\2c\20unsigned\20int\29 +3088:std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::~__hash_table\28\29 +3089:std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::~__hash_table\28\29 +3090:std::__2::__function::__value_func\2c\20sktext::gpu::RendererData\29>::operator\28\29\5babi:ne180100\5d\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29\20const +3091:std::__2::__function::__value_func\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\5babi:ne180100\5d\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const +3092:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28std::__2::__function::__base*\29\20const +3093:skvx::Vec<4\2c\20unsigned\20short>\20skvx::to_half<4>\28skvx::Vec<4\2c\20float>\20const&\29 +3094:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator~<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +3095:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator|<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +3096:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +3097:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator<=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +3098:skvx::Vec<4\2c\20int>\20skvx::operator~<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\29 +3099:skvx::Vec<4\2c\20int>\20skvx::operator&<4\2c\20int\2c\20int\2c\20void>\28skvx::Vec<4\2c\20int>\20const&\2c\20int\29 +3100:skvx::Vec<4\2c\20float>&\20skvx::operator+=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +3101:sktext::gpu::VertexFiller::flatten\28SkWriteBuffer&\29\20const +3102:sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry::find\28sktext::gpu::TextBlob::Key\20const&\29\20const +3103:sktext::gpu::SubRunAllocator::SubRunAllocator\28char*\2c\20int\2c\20int\29 +3104:sktext::gpu::GlyphVector::flatten\28SkWriteBuffer&\29\20const +3105:sktext::gpu::GlyphVector::Make\28sktext::SkStrikePromise&&\2c\20SkSpan\2c\20sktext::gpu::SubRunAllocator*\29 +3106:sktext::gpu::GlyphVector::GlyphVector\28sktext::gpu::GlyphVector&&\29 +3107:sktext::gpu::BagOfBytes::PlatformMinimumSizeWithOverhead\28int\2c\20int\29 +3108:sktext::SkStrikePromise::flatten\28SkWriteBuffer&\29\20const +3109:sktext::GlyphRunList::sourceBoundsWithOrigin\28\29\20const +3110:skpaint_to_grpaint_impl\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::optional>>\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +3111:skip_literal_string +3112:skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10203 +3113:skif::Mapping::Mapping\28\29 +3114:skif::LayerSpace::ceil\28\29\20const +3115:skif::LayerSpace::inverseMapRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29\20const +3116:skif::LayerSpace::inset\28skif::LayerSpace\20const&\29 +3117:skif::FilterResult::operator=\28skif::FilterResult\20const&\29 +3118:skif::FilterResult::insetByPixel\28\29\20const +3119:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20bool\2c\20SkBlender\20const*\29\20const +3120:skif::FilterResult::applyColorFilter\28skif::Context\20const&\2c\20sk_sp\29\20const +3121:skif::FilterResult::FilterResult\28sk_sp\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult::PixelBoundary\29 +3122:skif::FilterResult::Builder::~Builder\28\29 +3123:skif::Context::withNewSource\28skif::FilterResult\20const&\29\20const +3124:skif::Context::operator=\28skif::Context&&\29 +3125:skif::Backend::~Backend\28\29 +3126:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot::reset\28\29 +3127:skia_private::THashTable::Pair\2c\20SkSL::Symbol\20const*\2c\20skia_private::THashMap::Pair>::firstPopulatedSlot\28\29\20const +3128:skia_private::THashTable::Pair\2c\20SkSL::Symbol\20const*\2c\20skia_private::THashMap::Pair>::Iter>::operator++\28\29 +3129:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +3130:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot::reset\28\29 +3131:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot::reset\28\29 +3132:skia_private::THashTable::Traits>::Hash\28long\20long\20const&\29 +3133:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::Hash\28SkImageFilterCacheKey\20const&\29 +3134:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::findOrNull\28skgpu::ScratchKey\20const&\29\20const +3135:skia_private::THashTable::Traits>::set\28SkSL::Variable\20const*\29 +3136:skia_private::THashTable::Entry*\2c\20unsigned\20int\2c\20SkLRUCache::Traits>::uncheckedSet\28SkLRUCache::Entry*&&\29 +3137:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +3138:skia_private::THashTable::Traits>::Hash\28FT_Opaque_Paint_\20const&\29 +3139:skia_private::THashMap\2c\20SkGoodHash>::find\28SkString\20const&\29\20const +3140:skia_private::THashMap>\2c\20SkGoodHash>::set\28SkSL::Variable\20const*\2c\20std::__2::unique_ptr>\29 +3141:skia_private::THashMap::operator\5b\5d\28SkSL::SymbolTable::SymbolKey\20const&\29 +3142:skia_private::THashMap::find\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +3143:skia_private::THashMap::find\28SkSL::IRNode\20const*\20const&\29\20const +3144:skia_private::THashMap::set\28SkSL::FunctionDeclaration\20const*\2c\20SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::FunctionState\29 +3145:skia_private::THashMap>\2c\20SkGoodHash>::find\28SkImageFilter\20const*\20const&\29\20const +3146:skia_private::TArray::resize_back\28int\29 +3147:skia_private::TArray::push_back_raw\28int\29 +3148:skia_private::TArray::operator==\28skia_private::TArray\20const&\29\20const +3149:skia_private::TArray::reserve_exact\28int\29 +3150:skia_private::TArray\2c\20true>::push_back\28std::__2::array&&\29 +3151:skia_private::TArray\2c\20false>::~TArray\28\29 +3152:skia_private::TArray::clear\28\29 +3153:skia_private::TArray::clear\28\29 +3154:skia_private::TArray::TArray\28skia_private::TArray\20const&\29 +3155:skia_private::TArray::TArray\28skia_private::TArray\20const&\29 +3156:skia_private::TArray::~TArray\28\29 +3157:skia_private::TArray::move\28void*\29 +3158:skia_private::TArray::BufferFinishedMessage\2c\20false>::~TArray\28\29 +3159:skia_private::TArray::BufferFinishedMessage\2c\20false>::move\28void*\29 +3160:skia_private::TArray\2c\20true>::~TArray\28\29 +3161:skia_private::TArray\2c\20true>::push_back\28sk_sp&&\29 +3162:skia_private::TArray::reserve_exact\28int\29 +3163:skia_private::TArray\2c\20true>::Allocate\28int\2c\20double\29 +3164:skia_private::TArray::reserve_exact\28int\29 +3165:skia_private::TArray::Allocate\28int\2c\20double\29 +3166:skia_private::TArray::~TArray\28\29 +3167:skia_private::TArray::move\28void*\29 +3168:skia_private::AutoSTMalloc<8ul\2c\20unsigned\20int\2c\20void>::reset\28unsigned\20long\29 +3169:skia_private::AutoSTArray<6\2c\20SkResourceCache::Key>::reset\28int\29 +3170:skia_private::AutoSTArray<20\2c\20SkGlyph\20const*>::reset\28int\29 +3171:skia_private::AutoSTArray<16\2c\20SkRect>::reset\28int\29 +3172:skia_png_sig_cmp +3173:skia_png_set_text_2 +3174:skia_png_realloc_array +3175:skia_png_get_uint_31 +3176:skia_png_check_fp_string +3177:skia_png_check_fp_number +3178:skia_png_app_warning +3179:skia_png_app_error +3180:skia::textlayout::\28anonymous\20namespace\29::intersected\28skia::textlayout::SkRange\20const&\2c\20skia::textlayout::SkRange\20const&\29 +3181:skia::textlayout::\28anonymous\20namespace\29::draw_line_as_rect\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\2c\20float\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +3182:skia::textlayout::TypefaceFontStyleSet::createTypeface\28int\29 +3183:skia::textlayout::TextStyle::setForegroundColor\28SkPaint\29 +3184:skia::textlayout::TextStyle::setBackgroundColor\28SkPaint\29 +3185:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29 +3186:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::$_0::operator\28\29\28sk_sp\2c\20sk_sp\29\20const +3187:skia::textlayout::TextLine::iterateThroughSingleRunByStyles\28skia::textlayout::TextLine::TextAdjustment\2c\20skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::StyleType\2c\20std::__2::function\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\20const&\29\20const::$_0::operator\28\29\28skia::textlayout::SkRange\2c\20float\29\20const +3188:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const +3189:skia::textlayout::TextBox&\20std::__2::vector>::emplace_back\28SkRect&\2c\20skia::textlayout::TextDirection&&\29 +3190:skia::textlayout::StrutStyle::StrutStyle\28skia::textlayout::StrutStyle\20const&\29 +3191:skia::textlayout::Run::isResolved\28\29\20const +3192:skia::textlayout::Run::copyTo\28SkTextBlobBuilder&\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +3193:skia::textlayout::Run::calculateWidth\28unsigned\20long\2c\20unsigned\20long\2c\20bool\29\20const +3194:skia::textlayout::Run::calculateHeight\28skia::textlayout::LineMetricStyle\2c\20skia::textlayout::LineMetricStyle\29\20const +3195:skia::textlayout::ParagraphStyle::ParagraphStyle\28skia::textlayout::ParagraphStyle&&\29 +3196:skia::textlayout::ParagraphImpl::getGlyphPositionAtCoordinate\28float\2c\20float\29 +3197:skia::textlayout::ParagraphImpl::findNextGraphemeBoundary\28unsigned\20long\29\20const +3198:skia::textlayout::ParagraphImpl::findAllBlocks\28skia::textlayout::SkRange\29 +3199:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +3200:skia::textlayout::ParagraphImpl::buildClusterTable\28\29 +3201:skia::textlayout::ParagraphCacheKey::operator==\28skia::textlayout::ParagraphCacheKey\20const&\29\20const +3202:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +3203:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29 +3204:skia::textlayout::ParagraphBuilderImpl::endRunIfNeeded\28\29 +3205:skia::textlayout::OneLineShaper::~OneLineShaper\28\29 +3206:skia::textlayout::LineMetrics::LineMetrics\28\29 +3207:skia::textlayout::FontCollection::FamilyKey::~FamilyKey\28\29 +3208:skia::textlayout::Cluster::isSoftBreak\28\29\20const +3209:skia::textlayout::Block::Block\28skia::textlayout::Block\20const&\29 +3210:skgpu::tess::AffineMatrix::AffineMatrix\28SkMatrix\20const&\29 +3211:skgpu::ganesh::\28anonymous\20namespace\29::add_quad_segment\28SkPoint\20const*\2c\20skia_private::TArray*\29 +3212:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::Entry::Entry\28skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::Entry&&\29 +3213:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::~Impl\28\29 +3214:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::programInfo\28\29 +3215:skgpu::ganesh::SurfaceFillContext::internalClear\28SkIRect\20const*\2c\20std::__2::array\2c\20bool\29 +3216:skgpu::ganesh::SurfaceFillContext::discard\28\29 +3217:skgpu::ganesh::SurfaceFillContext::addOp\28std::__2::unique_ptr>\29 +3218:skgpu::ganesh::SurfaceDrawContext::wrapsVkSecondaryCB\28\29\20const +3219:skgpu::ganesh::SurfaceDrawContext::stencilRect\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const*\29 +3220:skgpu::ganesh::SurfaceDrawContext::fillQuadWithEdgeAA\28GrClip\20const*\2c\20GrPaint&&\2c\20GrQuadAAFlags\2c\20SkMatrix\20const&\2c\20SkPoint\20const*\2c\20SkPoint\20const*\29 +3221:skgpu::ganesh::SurfaceDrawContext::drawPath\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrStyle\20const&\29 +3222:skgpu::ganesh::SurfaceDrawContext::attemptQuadOptimization\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20DrawQuad*\2c\20GrPaint*\29 +3223:skgpu::ganesh::SurfaceDrawContext::Make\28GrRecordingContext*\2c\20GrColorType\2c\20sk_sp\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +3224:skgpu::ganesh::SurfaceContext::rescale\28GrImageInfo\20const&\2c\20GrSurfaceOrigin\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29 +3225:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29::$_0::operator\28\29\28GrSurfaceProxyView\2c\20SkIRect\29\20const +3226:skgpu::ganesh::SurfaceContext::SurfaceContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +3227:skgpu::ganesh::SmallPathShapeDataKey::operator==\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29\20const +3228:skgpu::ganesh::QuadPerEdgeAA::MinColorType\28SkRGBA4f<\28SkAlphaType\292>\29 +3229:skgpu::ganesh::PathTessellator::~PathTessellator\28\29 +3230:skgpu::ganesh::PathCurveTessellator::draw\28GrOpFlushState*\29\20const +3231:skgpu::ganesh::OpsTask::~OpsTask\28\29 +3232:skgpu::ganesh::OpsTask::recordOp\28std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const*\2c\20GrCaps\20const&\29 +3233:skgpu::ganesh::FilterAndMipmapHaveNoEffect\28GrQuad\20const&\2c\20GrQuad\20const&\29 +3234:skgpu::ganesh::FillRectOp::MakeNonAARect\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +3235:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::can_use_hw_derivatives_with_coverage\28skvx::Vec<2\2c\20float>\20const&\2c\20skvx::Vec<2\2c\20float>\20const&\29 +3236:skgpu::ganesh::FillRRectOp::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20SkRect\20const&\2c\20GrAA\29 +3237:skgpu::ganesh::Device::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +3238:skgpu::ganesh::Device::drawImageQuadDirect\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +3239:skgpu::ganesh::Device::Make\28std::__2::unique_ptr>\2c\20SkAlphaType\2c\20skgpu::ganesh::Device::InitContents\29 +3240:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::setup_dashed_rect\28SkRect\20const&\2c\20skgpu::VertexWriter&\2c\20SkMatrix\20const&\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashCap\29 +3241:skgpu::ganesh::ClipStack::~ClipStack\28\29 +3242:skgpu::ganesh::ClipStack::writableSaveRecord\28bool*\29 +3243:skgpu::ganesh::ClipStack::end\28\29\20const +3244:skgpu::ganesh::ClipStack::clip\28skgpu::ganesh::ClipStack::RawElement&&\29 +3245:skgpu::ganesh::ClipStack::clipState\28\29\20const +3246:skgpu::ganesh::ClipStack::SaveRecord::invalidateMasks\28GrProxyProvider*\2c\20SkTBlockList*\29 +3247:skgpu::ganesh::ClipStack::SaveRecord::genID\28\29\20const +3248:skgpu::ganesh::ClipStack::RawElement::operator=\28skgpu::ganesh::ClipStack::RawElement&&\29 +3249:skgpu::ganesh::ClipStack::RawElement::contains\28skgpu::ganesh::ClipStack::SaveRecord\20const&\29\20const +3250:skgpu::ganesh::ClipStack::RawElement::RawElement\28SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\2c\20SkClipOp\29 +3251:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +3252:skgpu::Swizzle::apply\28SkRasterPipeline*\29\20const +3253:skgpu::Swizzle::applyTo\28std::__2::array\29\20const +3254:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29 +3255:skgpu::ScratchKey::GenerateResourceType\28\29 +3256:skgpu::RectanizerSkyline::reset\28\29 +3257:skgpu::Plot::addSubImage\28int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +3258:skgpu::AutoCallback::AutoCallback\28skgpu::AutoCallback&&\29 +3259:sk_sp::~sk_sp\28\29 +3260:sk_sp::operator=\28sk_sp&&\29 +3261:sk_sp::reset\28GrTextureProxy*\29 +3262:sk_sp::reset\28GrTexture*\29 +3263:sk_sp::operator=\28sk_sp&&\29 +3264:sk_sp::reset\28GrCpuBuffer*\29 +3265:sk_sp&\20sk_sp::operator=\28sk_sp&&\29 +3266:sk_sp&\20sk_sp::operator=\28sk_sp\20const&\29 +3267:sk_ft_free\28FT_MemoryRec_*\2c\20void*\29 +3268:sift +3269:set_initial_texture_params\28GrGLInterface\20const*\2c\20GrGLCaps\20const&\2c\20unsigned\20int\29 +3270:setLevelsOutsideIsolates\28UBiDi*\2c\20int\2c\20int\2c\20unsigned\20char\29 +3271:sect_with_vertical\28SkPoint\20const*\2c\20float\29 +3272:sampler_key\28GrTextureType\2c\20skgpu::Swizzle\20const&\2c\20GrCaps\20const&\29 +3273:round\28SkPoint*\29 +3274:read_color_line +3275:quick_inverse\28int\29 +3276:quad_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3277:psh_globals_set_scale +3278:ps_tofixedarray +3279:ps_parser_skip_PS_token +3280:ps_mask_test_bit +3281:ps_mask_table_alloc +3282:ps_mask_ensure +3283:ps_dimension_reset_mask +3284:ps_builder_init +3285:ps_builder_done +3286:pow +3287:portable::parametric_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3288:portable::hsl_to_rgb_k\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3289:portable::gamma__k\28float\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3290:portable::PQish_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3291:portable::HLGish_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3292:portable::HLGinvish_k\28skcms_TransferFunction\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20std::byte*&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\2c\20float&\29::'lambda'\28float\29::operator\28\29\28float\29\20const +3293:points_are_collinear_and_b_is_middle\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float*\29 +3294:png_zlib_inflate +3295:png_inflate_read +3296:png_inflate_claim +3297:png_build_8bit_table +3298:png_build_16bit_table +3299:picture_approximateBytesUsed +3300:path_addOval +3301:paragraph_dispose +3302:operator==\28SkPath\20const&\2c\20SkPath\20const&\29 +3303:operator!=\28SkString\20const&\2c\20SkString\20const&\29 +3304:normalize +3305:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::glyphCount\28\29\20const +3306:non-virtual\20thunk\20to\20GrOpFlushState::deferredUploadTarget\28\29 +3307:nextafterf +3308:move_nearby\28SkOpContourHead*\29 +3309:make_unpremul_effect\28std::__2::unique_ptr>\29 +3310:machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>::operator==\28machine_index_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>>\20const&\29\20const +3311:long\20std::__2::__libcpp_atomic_refcount_decrement\5babi:nn180100\5d\28long&\29 +3312:long\20const&\20std::__2::min\5babi:nn180100\5d\28long\20const&\2c\20long\20const&\29 +3313:log1p +3314:load_truetype_glyph +3315:load\28unsigned\20char\20const*\2c\20int\2c\20void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\29 +3316:line_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3317:lineMetrics_getStartIndex +3318:just_solid_color\28SkPaint\20const&\29 +3319:is_reflex_vertex\28SkPoint\20const*\2c\20int\2c\20float\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +3320:inner_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +3321:inflate_table +3322:image_filter_color_type\28SkColorInfo\20const&\29 +3323:hb_vector_t::push\28\29 +3324:hb_vector_t\2c\20false>::shrink_vector\28unsigned\20int\29 +3325:hb_utf8_t::next\28unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20int*\2c\20unsigned\20int\29 +3326:hb_shape_plan_destroy +3327:hb_serialize_context_t::object_t::hash\28\29\20const +3328:hb_script_get_horizontal_direction +3329:hb_pool_t::alloc\28\29 +3330:hb_paint_funcs_t::push_clip_glyph\28void*\2c\20unsigned\20int\2c\20hb_font_t*\29 +3331:hb_paint_funcs_t::image\28void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\29 +3332:hb_paint_funcs_t::color\28void*\2c\20int\2c\20unsigned\20int\29 +3333:hb_paint_extents_context_t::~hb_paint_extents_context_t\28\29 +3334:hb_paint_extents_context_t::push_clip\28hb_extents_t\29 +3335:hb_ot_map_t::get_mask\28unsigned\20int\2c\20unsigned\20int*\29\20const +3336:hb_lazy_loader_t\2c\20hb_face_t\2c\202u\2c\20hb_blob_t>::get\28\29\20const +3337:hb_lazy_loader_t\2c\20hb_face_t\2c\2023u\2c\20hb_blob_t>::get\28\29\20const +3338:hb_lazy_loader_t\2c\20hb_face_t\2c\201u\2c\20hb_blob_t>::get\28\29\20const +3339:hb_lazy_loader_t\2c\20hb_face_t\2c\2018u\2c\20hb_blob_t>::get\28\29\20const +3340:hb_lazy_loader_t\2c\20hb_face_t\2c\203u\2c\20OT::cmap_accelerator_t>::get_stored\28\29\20const +3341:hb_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>\2c\20OT::HBGlyphID16&>::end\28\29\20const +3342:hb_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>\2c\20hb_pair_t>::operator++\28\29\20& +3343:hb_hashmap_t::item_t::operator==\28hb_serialize_context_t::object_t\20const*\20const&\29\20const +3344:hb_font_t::mults_changed\28\29 +3345:hb_font_t::has_glyph_h_origin_func\28\29 +3346:hb_font_t::has_func\28unsigned\20int\29 +3347:hb_font_t::get_nominal_glyphs\28unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\29 +3348:hb_font_t::get_glyph_v_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +3349:hb_font_t::get_glyph_v_advances\28unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\29 +3350:hb_font_t::get_glyph_h_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +3351:hb_font_t::get_glyph_h_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +3352:hb_font_t::get_glyph_h_advances\28unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\29 +3353:hb_font_t::get_glyph_contour_point_for_origin\28unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20int*\2c\20int*\29 +3354:hb_font_funcs_destroy +3355:hb_draw_cubic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +3356:hb_buffer_t::output_info\28hb_glyph_info_t\20const&\29 +3357:hb_buffer_t::digest\28\29\20const +3358:hb_buffer_t::_infos_set_glyph_flags\28hb_glyph_info_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +3359:hb_buffer_t::_infos_find_min_cluster\28hb_glyph_info_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +3360:hb_buffer_set_length +3361:hb_buffer_create +3362:hb_blob_ptr_t::destroy\28\29 +3363:haircubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkRect\20const*\2c\20SkRect\20const*\2c\20SkBlitter*\2c\20int\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +3364:gray_render_line +3365:gl_target_to_gr_target\28unsigned\20int\29 +3366:gl_target_to_binding_index\28unsigned\20int\29 +3367:get_vendor\28char\20const*\29 +3368:get_renderer\28char\20const*\2c\20GrGLExtensions\20const&\29 +3369:get_layer_mapping_and_bounds\28SkSpan>\2c\20SkMatrix\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\2c\20float\29 +3370:get_joining_type\28unsigned\20int\2c\20hb_unicode_general_category_t\29 +3371:get_child_table_pointer +3372:generate_distance_field_from_image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\29 +3373:gaussianIntegral\28float\29 +3374:ft_var_readpackeddeltas +3375:ft_var_done_item_variation_store +3376:ft_glyphslot_alloc_bitmap +3377:ft_face_get_mm_service +3378:freelocale +3379:fputc +3380:fp_barrierf +3381:float*\20SkArenaAlloc::makeArray\28unsigned\20long\29 +3382:fixN0c\28BracketData*\2c\20int\2c\20int\2c\20unsigned\20char\29 +3383:filter_to_gl_min_filter\28SkFilterMode\2c\20SkMipmapMode\29 +3384:exp2 +3385:dquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3386:do_scanline\28int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkBlitter*\29 +3387:do_anti_hairline\28int\2c\20int\2c\20int\2c\20int\2c\20SkIRect\20const*\2c\20SkBlitter*\29 +3388:dline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3389:directionFromFlags\28UBiDi*\29 +3390:destroy_face +3391:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0>\28skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::DashOp::AAMode\2c\20SkMatrix\20const&\2c\20bool\29::$_0&&\29::'lambda'\28char*\29::__invoke\28char*\29 +3392:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrCaps\20const&\2c\20GrSurfaceProxyView\20const&\2c\20bool&\2c\20GrPipeline*&\2c\20GrUserStencilSettings\20const*&&\2c\20\28anonymous\20namespace\29::DrawAtlasPathShader*&\2c\20GrPrimitiveType&&\2c\20GrXferBarrierFlags&\2c\20GrLoadOp&\29::'lambda'\28void*\29>\28GrProgramInfo&&\29::'lambda'\28char*\29::__invoke\28char*\29 +3393:dcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3394:dconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +3395:cubic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3396:conic_intersect_ray\28SkPoint\20const*\2c\20float\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +3397:cleanup_shaders\28GrGLGpu*\2c\20SkTDArray\20const&\29 +3398:chop_mono_cubic_at_y\28SkPoint*\2c\20float\2c\20SkPoint*\29 +3399:check_inverse_on_empty_return\28SkRegion*\2c\20SkPath\20const&\2c\20SkRegion\20const&\29 +3400:check_intersection\28SkAnalyticEdge\20const*\2c\20int\2c\20int*\29 +3401:char\20const*\20std::__2::find\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const&\29 +3402:cff_parse_real +3403:cff_parse_integer +3404:cff_index_read_offset +3405:cff_index_get_pointers +3406:cff_index_access_element +3407:cff2_path_param_t::move_to\28CFF::point_t\20const&\29 +3408:cff1_path_param_t::move_to\28CFF::point_t\20const&\29 +3409:cf2_hintmap_map +3410:cf2_glyphpath_pushPrevElem +3411:cf2_glyphpath_computeOffset +3412:cf2_glyphpath_closeOpenPath +3413:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_1::operator\28\29\28int\29\20const +3414:calc_dot_cross_cubic\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +3415:bracketProcessBoundary\28BracketData*\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +3416:bracketAddOpening\28BracketData*\2c\20char16_t\2c\20int\29 +3417:bool\20std::__2::equal\5babi:ne180100\5d\28float\20const*\2c\20float\20const*\2c\20float\20const*\2c\20std::__2::__equal_to\29 +3418:bool\20std::__2::__is_pointer_in_range\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char\20const*\29 +3419:bool\20SkIsFinite\28float\20const*\2c\20int\29\20\28.643\29 +3420:bool\20SkIsFinite\28float\20const*\2c\20int\29 +3421:bool\20OT::match_lookahead>\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +3422:bool\20OT::match_backtrack>\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20OT::IntType\20const*\2c\20bool\20\28*\29\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29\2c\20void\20const*\2c\20unsigned\20int*\29 +3423:bool\20OT::glyf_impl::Glyph::get_points\28hb_font_t*\2c\20OT::glyf_accelerator_t\20const&\2c\20contour_point_vector_t&\2c\20contour_point_vector_t*\2c\20head_maxp_info_t*\2c\20unsigned\20int*\2c\20bool\2c\20bool\2c\20bool\2c\20hb_array_t\2c\20hb_map_t*\2c\20unsigned\20int\2c\20unsigned\20int*\29\20const +3424:bool\20OT::glyf_accelerator_t::get_points\28hb_font_t*\2c\20unsigned\20int\2c\20OT::glyf_accelerator_t::points_aggregator_t\29\20const +3425:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3426:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3427:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3428:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +3429:blitrect\28SkBlitter*\2c\20SkIRect\20const&\29 +3430:blit_single_alpha\28AdditiveBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +3431:blit_aaa_trapezoid_row\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +3432:atan +3433:append_index_uv_varyings\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20int\2c\20char\20const*\2c\20char\20const*\2c\20GrGLSLVarying*\2c\20GrGLSLVarying*\2c\20GrGLSLVarying*\29 +3434:antifillrect\28SkRect\20const&\2c\20SkBlitter*\29 +3435:af_property_get_face_globals +3436:af_latin_hints_link_segments +3437:af_latin_compute_stem_width +3438:af_latin_align_linked_edge +3439:af_iup_interp +3440:af_glyph_hints_save +3441:af_glyph_hints_done +3442:af_cjk_align_linked_edge +3443:add_quad\28SkPoint\20const*\2c\20skia_private::TArray*\29 +3444:acos +3445:aaa_fill_path\28SkPath\20const&\2c\20SkIRect\20const&\2c\20AdditiveBlitter*\2c\20int\2c\20int\2c\20bool\2c\20bool\2c\20bool\29 +3446:_iup_worker_interpolate +3447:_hb_head_t\29&>\28fp\29\2c\20std::forward>\28fp0\29\2c\20\28hb_priority<16u>\29\28\29\29\29>::type\20$_14::operator\28\29\29&\2c\20hb_pair_t>\28find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29&\2c\20hb_pair_t&&\29\20const +3448:_hb_font_adopt_var_coords\28hb_font_t*\2c\20int*\2c\20float*\2c\20unsigned\20int\29 +3449:_get_path\28OT::cff1::accelerator_t\20const*\2c\20hb_font_t*\2c\20unsigned\20int\2c\20hb_draw_session_t&\2c\20bool\2c\20CFF::point_t*\29 +3450:_get_bounds\28OT::cff1::accelerator_t\20const*\2c\20unsigned\20int\2c\20bounds_t&\2c\20bool\29 +3451:__trunctfdf2 +3452:__towrite +3453:__toread +3454:__subtf3 +3455:__strchrnul +3456:__rem_pio2f +3457:__rem_pio2 +3458:__overflow +3459:__fwritex +3460:__cxxabiv1::__class_type_info::process_static_type_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\29\20const +3461:__cxxabiv1::__class_type_info::process_static_type_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\29\20const +3462:__cxxabiv1::__class_type_info::process_found_base_class\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +3463:__cxxabiv1::__base_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +3464:\28anonymous\20namespace\29::split_conic\28SkPoint\20const*\2c\20SkConic*\2c\20float\29 +3465:\28anonymous\20namespace\29::single_pass_shape\28GrStyledShape\20const&\29 +3466:\28anonymous\20namespace\29::shift_left\28skvx::Vec<4\2c\20float>\20const&\2c\20int\29 +3467:\28anonymous\20namespace\29::shape_contains_rect\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkMatrix\20const&\2c\20bool\29 +3468:\28anonymous\20namespace\29::set_gl_stencil\28GrGLInterface\20const*\2c\20GrStencilSettings::Face\20const&\2c\20unsigned\20int\29 +3469:\28anonymous\20namespace\29::make_blend\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\2c\20std::__2::optional\2c\20bool\29::$_0::operator\28\29\28sk_sp\29\20const +3470:\28anonymous\20namespace\29::get_tile_count\28SkIRect\20const&\2c\20int\29 +3471:\28anonymous\20namespace\29::generateGlyphPathStatic\28FT_FaceRec_*\2c\20SkPath*\29 +3472:\28anonymous\20namespace\29::generateFacePathCOLRv1\28FT_FaceRec_*\2c\20unsigned\20short\2c\20SkPath*\29 +3473:\28anonymous\20namespace\29::gather_lines_and_quads\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\29::$_0::operator\28\29\28SkPoint\20const*\2c\20bool\29\20const +3474:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads_with_constraint\28SkPoint\20const*\2c\20float\2c\20SkPathFirstDirection\2c\20skia_private::TArray*\2c\20int\29 +3475:\28anonymous\20namespace\29::convert_noninflect_cubic_to_quads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\2c\20int\2c\20bool\2c\20bool\29 +3476:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const +3477:\28anonymous\20namespace\29::calculate_colors\28skgpu::ganesh::SurfaceDrawContext*\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20skgpu::MaskFormat\2c\20GrPaint*\29 +3478:\28anonymous\20namespace\29::bloat_quad\28SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkMatrix\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +3479:\28anonymous\20namespace\29::TriangulatingPathOp::CreateMesh\28GrMeshDrawTarget*\2c\20sk_sp\2c\20int\2c\20int\29 +3480:\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29_12039 +3481:\28anonymous\20namespace\29::TransformedMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +3482:\28anonymous\20namespace\29::TransformedMaskSubRun::glyphs\28\29\20const +3483:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29 +3484:\28anonymous\20namespace\29::SkMorphologyImageFilter::radii\28skif::Mapping\20const&\29\20const +3485:\28anonymous\20namespace\29::SkFTGeometrySink::goingTo\28FT_Vector_\20const*\29 +3486:\28anonymous\20namespace\29::SkCropImageFilter::cropRect\28skif::Mapping\20const&\29\20const +3487:\28anonymous\20namespace\29::ShapedRun::~ShapedRun\28\29 +3488:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +3489:\28anonymous\20namespace\29::PathSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +3490:\28anonymous\20namespace\29::MemoryPoolAccessor::pool\28\29\20const +3491:\28anonymous\20namespace\29::DrawAtlasOpImpl::visitProxies\28std::__2::function\20const&\29\20const +3492:\28anonymous\20namespace\29::DrawAtlasOpImpl::programInfo\28\29 +3493:\28anonymous\20namespace\29::DrawAtlasOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +3494:TT_Vary_Apply_Glyph_Deltas +3495:TT_Set_Var_Design +3496:TT_Get_VMetrics +3497:SkWriter32::writeRegion\28SkRegion\20const&\29 +3498:SkVertices::Sizes::Sizes\28SkVertices::Desc\20const&\29 +3499:SkVertices::MakeCopy\28SkVertices::VertexMode\2c\20int\2c\20SkPoint\20const*\2c\20SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20short\20const*\29 +3500:SkVertices::Builder::~Builder\28\29 +3501:SkVertices::Builder::detach\28\29 +3502:SkUnitScalarClampToByte\28float\29 +3503:SkUTF::ToUTF16\28int\2c\20unsigned\20short*\29 +3504:SkTypeface_FreeType::~SkTypeface_FreeType\28\29 +3505:SkTextBlobBuilder::allocInternal\28SkFont\20const&\2c\20SkTextBlob::GlyphPositioning\2c\20int\2c\20int\2c\20SkPoint\2c\20SkRect\20const*\29 +3506:SkTextBlob::RunRecord::textSizePtr\28\29\20const +3507:SkTSpan::markCoincident\28\29 +3508:SkTSect::markSpanGone\28SkTSpan*\29 +3509:SkTSect::computePerpendiculars\28SkTSect*\2c\20SkTSpan*\2c\20SkTSpan*\29 +3510:SkTMultiMap::insert\28skgpu::ScratchKey\20const&\2c\20GrGpuResource*\29 +3511:SkTLazy::getMaybeNull\28\29 +3512:SkTDStorage::moveTail\28int\2c\20int\2c\20int\29 +3513:SkTDStorage::calculateSizeOrDie\28int\29 +3514:SkTDArray::append\28int\29 +3515:SkTDArray::append\28\29 +3516:SkTConic::hullIntersects\28SkDConic\20const&\2c\20bool*\29\20const +3517:SkTBlockList::pop_back\28\29 +3518:SkSurface_Base::~SkSurface_Base\28\29 +3519:SkSurface_Base::aboutToDraw\28SkSurface::ContentChangeMode\29 +3520:SkStrokeRec::init\28SkPaint\20const&\2c\20SkPaint::Style\2c\20float\29 +3521:SkStrokeRec::getInflationRadius\28\29\20const +3522:SkString::printVAList\28char\20const*\2c\20void*\29 +3523:SkString::SkString\28unsigned\20long\29 +3524:SkStrikeSpec::SkStrikeSpec\28SkStrikeSpec&&\29 +3525:SkStrikeSpec::MakeWithNoDevice\28SkFont\20const&\2c\20SkPaint\20const*\29 +3526:SkStrikeSpec::MakePath\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\29 +3527:SkStrikeCache::findOrCreateStrike\28SkStrikeSpec\20const&\29 +3528:SkStrike::prepareForPath\28SkGlyph*\29 +3529:SkSpriteBlitter::SkSpriteBlitter\28SkPixmap\20const&\29 +3530:SkSpecialImage::~SkSpecialImage\28\29 +3531:SkSpecialImage::makeSubset\28SkIRect\20const&\29\20const +3532:SkSpecialImage::makePixelOutset\28\29\20const +3533:SkSize\20skif::Mapping::map\28SkSize\20const&\2c\20SkMatrix\20const&\29 +3534:SkShapers::HB::ScriptRunIterator\28char\20const*\2c\20unsigned\20long\29 +3535:SkShaper::TrivialRunIterator::endOfCurrentRun\28\29\20const +3536:SkShaper::TrivialRunIterator::consume\28\29 +3537:SkShaper::TrivialRunIterator::atEnd\28\29\20const +3538:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29 +3539:SkShaders::MatrixRec::MatrixRec\28SkMatrix\20const&\29 +3540:SkShaderUtils::GLSLPrettyPrint::tabString\28\29 +3541:SkScanClipper::~SkScanClipper\28\29 +3542:SkScanClipper::SkScanClipper\28SkBlitter*\2c\20SkRegion\20const*\2c\20SkIRect\20const&\2c\20bool\2c\20bool\29 +3543:SkScan::HairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3544:SkScan::FillTriangle\28SkPoint\20const*\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3545:SkScan::FillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3546:SkScan::FillIRect\28SkIRect\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3547:SkScan::AntiHairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +3548:SkScan::AntiHairLineRgn\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3549:SkScan::AntiFillXRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +3550:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRegion\20const&\2c\20SkBlitter*\2c\20bool\29 +3551:SkScalerContext_FreeType::updateGlyphBoundsIfSubpixel\28SkGlyph\20const&\2c\20SkRect*\2c\20bool\29 +3552:SkScalerContextRec::CachedMaskGamma\28unsigned\20char\2c\20unsigned\20char\29 +3553:SkScalerContextFTUtils::drawSVGGlyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +3554:SkScalerContext::~SkScalerContext\28\29 +3555:SkSTArenaAlloc<2048ul>::SkSTArenaAlloc\28unsigned\20long\29 +3556:SkSL::type_is_valid_for_coords\28SkSL::Type\20const&\29 +3557:SkSL::simplify_negation\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\29 +3558:SkSL::simplify_matrix_multiplication\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3559:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +3560:SkSL::replace_empty_with_nop\28std::__2::unique_ptr>\2c\20bool\29 +3561:SkSL::find_generic_index\28SkSL::Type\20const&\2c\20SkSL::Type\20const&\2c\20bool\29 +3562:SkSL::evaluate_intrinsic_numeric\28SkSL::Context\20const&\2c\20std::__2::array\20const&\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\29 +3563:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29 +3564:SkSL::coalesce_n_way_vector\28SkSL::Expression\20const*\2c\20SkSL::Expression\20const*\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +3565:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_0::operator\28\29\28int\29\20const +3566:SkSL::build_argument_type_list\28SkSpan>\20const>\29 +3567:SkSL::\28anonymous\20namespace\29::SwitchCaseContainsExit::visitStatement\28SkSL::Statement\20const&\29 +3568:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::returnsInputAlpha\28SkSL::Expression\20const&\29 +3569:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29 +3570:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29 +3571:SkSL::\28anonymous\20namespace\29::ConstantExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +3572:SkSL::Variable::~Variable\28\29 +3573:SkSL::Variable::Make\28SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20std::__2::basic_string_view>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20bool\2c\20SkSL::VariableStorage\29 +3574:SkSL::Variable::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20SkSL::VariableStorage\29 +3575:SkSL::VarDeclaration::~VarDeclaration\28\29 +3576:SkSL::VarDeclaration::Make\28SkSL::Context\20const&\2c\20SkSL::Variable*\2c\20SkSL::Type\20const*\2c\20int\2c\20std::__2::unique_ptr>\29 +3577:SkSL::Type::isStorageTexture\28\29\20const +3578:SkSL::Type::convertArraySize\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20long\20long\29\20const +3579:SkSL::Type::MakeSamplerType\28char\20const*\2c\20SkSL::Type\20const&\29 +3580:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29 +3581:SkSL::Transform::EliminateDeadGlobalVariables\28SkSL::Program&\29::$_2::operator\28\29\28SkSL::ProgramElement\20const&\29\20const +3582:SkSL::TernaryExpression::~TernaryExpression\28\29 +3583:SkSL::SymbolTable::SymbolKey::operator==\28SkSL::SymbolTable::SymbolKey\20const&\29\20const +3584:SkSL::SingleArgumentConstructor::~SingleArgumentConstructor\28\29 +3585:SkSL::RP::UnownedLValueSlice::~UnownedLValueSlice\28\29 +3586:SkSL::RP::SlotManager::createSlots\28std::__2::basic_string\2c\20std::__2::allocator>\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20bool\29 +3587:SkSL::RP::SlotManager::addSlotDebugInfoForGroup\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20SkSL::Type\20const&\2c\20SkSL::Position\2c\20int*\2c\20bool\29 +3588:SkSL::RP::Program::makeStages\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSpan\2c\20SkSL::RP::Program::SlotData\20const&\29\20const::$_4::operator\28\29\28\29\20const +3589:SkSL::RP::Program::makeStages\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSpan\2c\20SkSL::RP::Program::SlotData\20const&\29\20const::$_1::operator\28\29\28int\29\20const +3590:SkSL::RP::Program::appendCopySlotsMasked\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +3591:SkSL::RP::LValueSlice::~LValueSlice\28\29 +3592:SkSL::RP::Generator::pushTraceScopeMask\28\29 +3593:SkSL::RP::Generator::pushTernaryExpression\28SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +3594:SkSL::RP::Generator::pushStructuredComparison\28SkSL::RP::LValue*\2c\20SkSL::Operator\2c\20SkSL::RP::LValue*\2c\20SkSL::Type\20const&\29 +3595:SkSL::RP::Generator::pushPrefixExpression\28SkSL::Operator\2c\20SkSL::Expression\20const&\29 +3596:SkSL::RP::Generator::pushMatrixMultiply\28SkSL::RP::LValue*\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +3597:SkSL::RP::Generator::pushAbsFloatIntrinsic\28int\29 +3598:SkSL::RP::Generator::needsReturnMask\28SkSL::FunctionDefinition\20const*\29 +3599:SkSL::RP::Generator::needsFunctionResultSlots\28SkSL::FunctionDefinition\20const*\29 +3600:SkSL::RP::Generator::foldWithMultiOp\28SkSL::RP::BuilderOp\2c\20int\29 +3601:SkSL::RP::Generator::GetTypedOp\28SkSL::Type\20const&\2c\20SkSL::RP::Generator::TypedOps\20const&\29 +3602:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29 +3603:SkSL::RP::Builder::select\28int\29 +3604:SkSL::RP::Builder::push_uniform\28SkSL::RP::SlotRange\29 +3605:SkSL::RP::Builder::pop_loop_mask\28\29 +3606:SkSL::RP::Builder::merge_condition_mask\28\29 +3607:SkSL::RP::Builder::branch_if_no_active_lanes_on_stack_top_equal\28int\2c\20int\29 +3608:SkSL::RP::AutoStack&\20std::__2::optional::emplace\5babi:ne180100\5d\28SkSL::RP::Generator*&\29 +3609:SkSL::ProgramUsage::add\28SkSL::ProgramElement\20const&\29 +3610:SkSL::PipelineStage::PipelineStageCodeGenerator::modifierString\28SkSL::ModifierFlags\29 +3611:SkSL::PipelineStage::ConvertProgram\28SkSL::Program\20const&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20SkSL::PipelineStage::Callbacks*\29 +3612:SkSL::Parser::unsizedArrayType\28SkSL::Type\20const*\2c\20SkSL::Position\29 +3613:SkSL::Parser::unaryExpression\28\29 +3614:SkSL::Parser::swizzle\28SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::basic_string_view>\2c\20SkSL::Position\29 +3615:SkSL::Parser::poison\28SkSL::Position\29 +3616:SkSL::Parser::checkIdentifier\28SkSL::Token*\29 +3617:SkSL::Parser::block\28bool\2c\20std::__2::unique_ptr>*\29 +3618:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29 +3619:SkSL::Operator::getBinaryPrecedence\28\29\20const +3620:SkSL::MultiArgumentConstructor::~MultiArgumentConstructor\28\29 +3621:SkSL::ModuleLoader::loadVertexModule\28SkSL::Compiler*\29 +3622:SkSL::ModuleLoader::loadGPUModule\28SkSL::Compiler*\29 +3623:SkSL::ModuleLoader::loadFragmentModule\28SkSL::Compiler*\29 +3624:SkSL::ModifierFlags::checkPermittedFlags\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\29\20const +3625:SkSL::Mangler::uniqueName\28std::__2::basic_string_view>\2c\20SkSL::SymbolTable*\29 +3626:SkSL::LiteralType::slotType\28unsigned\20long\29\20const +3627:SkSL::Literal::MakeFloat\28SkSL::Position\2c\20float\2c\20SkSL::Type\20const*\29 +3628:SkSL::Literal::MakeBool\28SkSL::Position\2c\20bool\2c\20SkSL::Type\20const*\29 +3629:SkSL::Layout::checkPermittedLayout\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkEnumBitMask\29\20const +3630:SkSL::IfStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3631:SkSL::IRHelpers::Binary\28std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\29\20const +3632:SkSL::GlobalVarDeclaration::~GlobalVarDeclaration\28\29_5861 +3633:SkSL::GlobalVarDeclaration::~GlobalVarDeclaration\28\29 +3634:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29 +3635:SkSL::GLSLCodeGenerator::writeLiteral\28SkSL::Literal\20const&\29 +3636:SkSL::GLSLCodeGenerator::writeFunctionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +3637:SkSL::GLSLCodeGenerator::shouldRewriteVoidTypedFunctions\28SkSL::FunctionDeclaration\20const*\29\20const +3638:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29 +3639:SkSL::ForStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +3640:SkSL::Expression::isIncomplete\28SkSL::Context\20const&\29\20const +3641:SkSL::Expression::compareConstant\28SkSL::Expression\20const&\29\20const +3642:SkSL::DoStatement::~DoStatement\28\29 +3643:SkSL::DebugTracePriv::~DebugTracePriv\28\29 +3644:SkSL::ConstructorArrayCast::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +3645:SkSL::ConstructorArray::~ConstructorArray\28\29 +3646:SkSL::ConstantFolder::GetConstantValueOrNull\28SkSL::Expression\20const&\29 +3647:SkSL::Compiler::runInliner\28SkSL::Inliner*\2c\20std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\29 +3648:SkSL::Block::~Block\28\29 +3649:SkSL::BinaryExpression::~BinaryExpression\28\29 +3650:SkSL::BinaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\2c\20std::__2::unique_ptr>\2c\20SkSL::Type\20const*\29 +3651:SkSL::Analysis::GetReturnComplexity\28SkSL::FunctionDefinition\20const&\29 +3652:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29 +3653:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29 +3654:SkSL::Analysis::CallsColorTransformIntrinsics\28SkSL::Program\20const&\29 +3655:SkSL::AliasType::bitWidth\28\29\20const +3656:SkRuntimeShader::uniformData\28SkColorSpace\20const*\29\20const +3657:SkRuntimeEffectPriv::VarAsUniform\28SkSL::Variable\20const&\2c\20SkSL::Context\20const&\2c\20unsigned\20long*\29 +3658:SkRuntimeEffect::makeShader\28sk_sp\2c\20SkSpan\2c\20SkMatrix\20const*\29\20const +3659:SkRuntimeEffect::MakeForShader\28SkString\29 +3660:SkRgnBuilder::~SkRgnBuilder\28\29 +3661:SkResourceCache::checkMessages\28\29 +3662:SkResourceCache::Key::operator==\28SkResourceCache::Key\20const&\29\20const +3663:SkRegion::translate\28int\2c\20int\2c\20SkRegion*\29\20const +3664:SkRegion::op\28SkRegion\20const&\2c\20SkIRect\20const&\2c\20SkRegion::Op\29 +3665:SkRegion::RunHead::findScanline\28int\29\20const +3666:SkRegion::RunHead::Alloc\28int\29 +3667:SkReduceOrder::Cubic\28SkPoint\20const*\2c\20SkPoint*\29 +3668:SkRect::offset\28float\2c\20float\29 +3669:SkRect*\20SkRecorder::copy\28SkRect\20const*\29 +3670:SkRecords::PreCachedPath::PreCachedPath\28SkPath\20const&\29 +3671:SkRecords::FillBounds::pushSaveBlock\28SkPaint\20const*\2c\20bool\29 +3672:SkRecorder::~SkRecorder\28\29 +3673:SkRecordDraw\28SkRecord\20const&\2c\20SkCanvas*\2c\20SkPicture\20const*\20const*\2c\20SkDrawable*\20const*\2c\20int\2c\20SkBBoxHierarchy\20const*\2c\20SkPicture::AbortCallback*\29 +3674:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29 +3675:SkRasterPipelineBlitter::blitRectWithTrace\28int\2c\20int\2c\20int\2c\20int\2c\20bool\29 +3676:SkRasterPipelineBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29::$_0::operator\28\29\28int\2c\20SkRasterPipeline_MemoryCtx*\29\20const +3677:SkRasterPipelineBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +3678:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29 +3679:SkRasterPipeline::appendStore\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +3680:SkRasterClip::op\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkClipOp\2c\20bool\29 +3681:SkRasterClip::convertToAA\28\29 +3682:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29::$_1::operator\28\29\28SkRect\20const&\2c\20SkRRect::Corner\29\20const +3683:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29 +3684:SkRRect::scaleRadii\28\29 +3685:SkRRect::AreRectAndRadiiValid\28SkRect\20const&\2c\20SkPoint\20const*\29 +3686:SkRGBA4f<\28SkAlphaType\292>*\20SkArenaAlloc::makeArray>\28unsigned\20long\29 +3687:SkQuadraticEdge::updateQuadratic\28\29 +3688:SkQuadConstruct::initWithStart\28SkQuadConstruct*\29 +3689:SkQuadConstruct::initWithEnd\28SkQuadConstruct*\29 +3690:SkPointPriv::DistanceToLineBetweenSqd\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPointPriv::Side*\29 +3691:SkPoint::setNormalize\28float\2c\20float\29 +3692:SkPoint::setLength\28float\2c\20float\2c\20float\29 +3693:SkPixmap::setColorSpace\28sk_sp\29 +3694:SkPixmap::rowBytesAsPixels\28\29\20const +3695:SkPixelRef::getGenerationID\28\29\20const +3696:SkPictureRecorder::~SkPictureRecorder\28\29 +3697:SkPictureRecorder::SkPictureRecorder\28\29 +3698:SkPicture::~SkPicture\28\29 +3699:SkPerlinNoiseShader::PaintingData::random\28\29 +3700:SkPathWriter::~SkPathWriter\28\29 +3701:SkPathWriter::update\28SkOpPtT\20const*\29 +3702:SkPathWriter::lineTo\28\29 +3703:SkPathWriter::SkPathWriter\28SkPath&\29 +3704:SkPathStroker::strokeCloseEnough\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20SkQuadConstruct*\29\20const +3705:SkPathStroker::setRayPts\28SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +3706:SkPathStroker::quadPerpRay\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +3707:SkPathStroker::finishContour\28bool\2c\20bool\29 +3708:SkPathStroker::conicPerpRay\28SkConic\20const&\2c\20float\2c\20SkPoint*\2c\20SkPoint*\2c\20SkPoint*\29\20const +3709:SkPathPriv::IsRectContour\28SkPath\20const&\2c\20bool\2c\20int*\2c\20SkPoint\20const**\2c\20bool*\2c\20SkPathDirection*\2c\20SkRect*\29 +3710:SkPathPriv::AddGenIDChangeListener\28SkPath\20const&\2c\20sk_sp\29 +3711:SkPathEffect::filterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +3712:SkPathBuilder::quadTo\28SkPoint\2c\20SkPoint\29 +3713:SkPathBuilder::moveTo\28float\2c\20float\29 +3714:SkPathBuilder::cubicTo\28SkPoint\2c\20SkPoint\2c\20SkPoint\29 +3715:SkPathBuilder::addRect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3716:SkPath::setLastPt\28float\2c\20float\29 +3717:SkPath::reversePathTo\28SkPath\20const&\29 +3718:SkPath::rQuadTo\28float\2c\20float\2c\20float\2c\20float\29 +3719:SkPath::isLastContourClosed\28\29\20const +3720:SkPath::cubicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +3721:SkPath::contains\28float\2c\20float\29\20const +3722:SkPath::conicTo\28float\2c\20float\2c\20float\2c\20float\2c\20float\29 +3723:SkPath::arcTo\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\29::$_0::operator\28\29\28SkPoint\20const&\29\20const +3724:SkPath::addPath\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPath::AddPathMode\29 +3725:SkPath::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3726:SkPath::Rect\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +3727:SkPath::Iter::autoClose\28SkPoint*\29 +3728:SkPath*\20SkTLazy::init<>\28\29 +3729:SkPaintToGrPaintReplaceShader\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20std::__2::unique_ptr>\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +3730:SkPaint::getBlendMode_or\28SkBlendMode\29\20const +3731:SkPackedGlyphID::PackIDSkPoint\28unsigned\20short\2c\20SkPoint\2c\20SkIPoint\29 +3732:SkOpSpanBase::checkForCollapsedCoincidence\28\29 +3733:SkOpSpan::setWindSum\28int\29 +3734:SkOpSegment::updateWindingReverse\28SkOpAngle\20const*\29 +3735:SkOpSegment::match\28SkOpPtT\20const*\2c\20SkOpSegment\20const*\2c\20double\2c\20SkPoint\20const&\29\20const +3736:SkOpSegment::markWinding\28SkOpSpan*\2c\20int\2c\20int\29 +3737:SkOpSegment::markAngle\28int\2c\20int\2c\20int\2c\20int\2c\20SkOpAngle\20const*\2c\20SkOpSpanBase**\29 +3738:SkOpSegment::markAngle\28int\2c\20int\2c\20SkOpAngle\20const*\2c\20SkOpSpanBase**\29 +3739:SkOpSegment::markAndChaseWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int\2c\20int\2c\20SkOpSpanBase**\29 +3740:SkOpSegment::markAllDone\28\29 +3741:SkOpSegment::dSlopeAtT\28double\29\20const +3742:SkOpSegment::addT\28double\2c\20SkPoint\20const&\29 +3743:SkOpSegment::activeWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\29 +3744:SkOpPtT::oppPrev\28SkOpPtT\20const*\29\20const +3745:SkOpPtT::contains\28SkOpSegment\20const*\29\20const +3746:SkOpPtT::Overlaps\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const**\2c\20SkOpPtT\20const**\29 +3747:SkOpEdgeBuilder::closeContour\28SkPoint\20const&\2c\20SkPoint\20const&\29 +3748:SkOpCoincidence::expand\28\29 +3749:SkOpCoincidence::Ordered\28SkOpSegment\20const*\2c\20SkOpSegment\20const*\29 +3750:SkOpCoincidence::Ordered\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\29 +3751:SkOpAngle::orderable\28SkOpAngle*\29 +3752:SkOpAngle::lineOnOneSide\28SkDPoint\20const&\2c\20SkDVector\20const&\2c\20SkOpAngle\20const*\2c\20bool\29\20const +3753:SkOpAngle::computeSector\28\29 +3754:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\2c\20sk_sp\29 +3755:SkMipmapAccessor::SkMipmapAccessor\28SkImage_Base\20const*\2c\20SkMatrix\20const&\2c\20SkMipmapMode\29::$_0::operator\28\29\28\29\20const +3756:SkMessageBus::Get\28\29 +3757:SkMessageBus::Get\28\29 +3758:SkMessageBus::BufferFinishedMessage\2c\20GrDirectContext::DirectContextID\2c\20false>::Get\28\29 +3759:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2668 +3760:SkMatrix\20skif::Mapping::map\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +3761:SkMatrixPriv::InverseMapRect\28SkMatrix\20const&\2c\20SkRect*\2c\20SkRect\20const&\29 +3762:SkMatrix::setPolyToPoly\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20int\29 +3763:SkMatrix::preservesRightAngles\28float\29\20const +3764:SkMatrix::mapRectToQuad\28SkPoint*\2c\20SkRect\20const&\29\20const +3765:SkMatrix::mapRectScaleTranslate\28SkRect*\2c\20SkRect\20const&\29\20const +3766:SkMatrix::getMinMaxScales\28float*\29\20const +3767:SkMatrix::getMapXYProc\28\29\20const +3768:SkMaskBuilder::PrepareDestination\28int\2c\20int\2c\20SkMask\20const&\29 +3769:SkLineParameters::cubicEndPoints\28SkDCubic\20const&\2c\20int\2c\20int\29 +3770:SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry::~Entry\28\29 +3771:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::reset\28\29 +3772:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry::~Entry\28\29 +3773:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_matrix_conv_effect\28SkKnownRuntimeEffects::\28anonymous\20namespace\29::MatrixConvolutionImpl\2c\20SkRuntimeEffect::Options\20const&\29 +3774:SkJSONWriter::separator\28bool\29 +3775:SkJSONWriter::appendString\28char\20const*\2c\20unsigned\20long\29 +3776:SkJSONWriter::appendS32\28char\20const*\2c\20int\29 +3777:SkIntersections::intersectRay\28SkDQuad\20const&\2c\20SkDLine\20const&\29 +3778:SkIntersections::intersectRay\28SkDLine\20const&\2c\20SkDLine\20const&\29 +3779:SkIntersections::intersectRay\28SkDCubic\20const&\2c\20SkDLine\20const&\29 +3780:SkIntersections::intersectRay\28SkDConic\20const&\2c\20SkDLine\20const&\29 +3781:SkIntersections::computePoints\28SkDLine\20const&\2c\20int\29 +3782:SkIntersections::cleanUpParallelLines\28bool\29 +3783:SkImage_Raster::SkImage_Raster\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20int\29 +3784:SkImage_Lazy::~SkImage_Lazy\28\29_4361 +3785:SkImage_Lazy::Validator::~Validator\28\29 +3786:SkImage_Lazy::Validator::Validator\28sk_sp\2c\20SkColorType\20const*\2c\20sk_sp\29 +3787:SkImage_Lazy::SkImage_Lazy\28SkImage_Lazy::Validator*\29 +3788:SkImage_Ganesh::~SkImage_Ganesh\28\29 +3789:SkImage_Ganesh::ProxyChooser::chooseProxy\28GrRecordingContext*\29 +3790:SkImage_Base::isYUVA\28\29\20const +3791:SkImageShader::MakeSubset\28sk_sp\2c\20SkRect\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20bool\29 +3792:SkImageShader::CubicResamplerMatrix\28float\2c\20float\29 +3793:SkImageInfo::minRowBytes64\28\29\20const +3794:SkImageInfo::makeAlphaType\28SkAlphaType\29\20const +3795:SkImageInfo::MakeN32Premul\28SkISize\29 +3796:SkImageGenerator::getPixels\28SkPixmap\20const&\29 +3797:SkImageFilters::Blend\28SkBlendMode\2c\20sk_sp\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +3798:SkImageFilter_Base::filterImage\28skif::Context\20const&\29\20const +3799:SkImageFilter_Base::affectsTransparentBlack\28\29\20const +3800:SkImageFilterCacheKey::operator==\28SkImageFilterCacheKey\20const&\29\20const +3801:SkImage::readPixels\28GrDirectContext*\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +3802:SkImage::peekPixels\28SkPixmap*\29\20const +3803:SkImage::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\29\20const +3804:SkIRect::offset\28SkIPoint\20const&\29 +3805:SkIRect::containsNoEmptyCheck\28SkIRect\20const&\29\20const +3806:SkIRect::MakeXYWH\28int\2c\20int\2c\20int\2c\20int\29 +3807:SkIDChangeListener::List::~List\28\29 +3808:SkIDChangeListener::List::add\28sk_sp\29 +3809:SkGradientShader::MakeSweep\28float\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3810:SkGradientShader::MakeRadial\28SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +3811:SkGradientBaseShader::AppendInterpolatedToDstStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20bool\2c\20SkGradientShader::Interpolation\20const&\2c\20SkColorSpace\20const*\2c\20SkColorSpace\20const*\29 +3812:SkGlyph::mask\28\29\20const +3813:SkFontScanner_FreeType::openFace\28SkStreamAsset*\2c\20int\2c\20FT_StreamRec_*\29\20const +3814:SkFontPriv::ApproximateTransformedTextSize\28SkFont\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\20const&\29 +3815:SkFontMgr::matchFamily\28char\20const*\29\20const +3816:SkFont::getWidthsBounds\28unsigned\20short\20const*\2c\20int\2c\20float*\2c\20SkRect*\2c\20SkPaint\20const*\29\20const +3817:SkFont::getBounds\28unsigned\20short\20const*\2c\20int\2c\20SkRect*\2c\20SkPaint\20const*\29\20const +3818:SkFindCubicMaxCurvature\28SkPoint\20const*\2c\20float*\29 +3819:SkFILEStream::SkFILEStream\28std::__2::shared_ptr<_IO_FILE>\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +3820:SkEmptyFontMgr::onMatchFamilyStyleCharacter\28char\20const*\2c\20SkFontStyle\20const&\2c\20char\20const**\2c\20int\2c\20int\29\20const +3821:SkEdgeClipper::appendQuad\28SkPoint\20const*\2c\20bool\29 +3822:SkEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkIRect\20const*\2c\20int\29 +3823:SkDrawTreatAAStrokeAsHairline\28float\2c\20SkMatrix\20const&\2c\20float*\29 +3824:SkDrawBase::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29\20const +3825:SkDrawBase::drawDevicePoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\2c\20SkDevice*\29\20const +3826:SkDevice::getRelativeTransform\28SkDevice\20const&\29\20const +3827:SkDevice::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +3828:SkDevice::drawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +3829:SkDevice::SkDevice\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +3830:SkData::MakeZeroInitialized\28unsigned\20long\29 +3831:SkData::MakeWithoutCopy\28void\20const*\2c\20unsigned\20long\29 +3832:SkDQuad::FindExtrema\28double\20const*\2c\20double*\29 +3833:SkDCubic::subDivide\28double\2c\20double\29\20const +3834:SkDCubic::searchRoots\28double*\2c\20int\2c\20double\2c\20SkDCubic::SearchAxis\2c\20double*\29\20const +3835:SkDCubic::monotonicInX\28\29\20const +3836:SkDCubic::findInflections\28double*\29\20const +3837:SkDConic::FindExtrema\28double\20const*\2c\20float\2c\20double*\29 +3838:SkCubicEdge::updateCubic\28\29 +3839:SkContourMeasure_segTo\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20float\2c\20SkPath*\29 +3840:SkContourMeasureIter::next\28\29 +3841:SkContourMeasureIter::Impl::compute_quad_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3842:SkContourMeasureIter::Impl::compute_cubic_segs\28SkPoint\20const*\2c\20float\2c\20int\2c\20int\2c\20unsigned\20int\2c\20int\29 +3843:SkContourMeasureIter::Impl::compute_conic_segs\28SkConic\20const&\2c\20float\2c\20int\2c\20SkPoint\20const&\2c\20int\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20int\29 +3844:SkContourMeasure::distanceToSegment\28float\2c\20float*\29\20const +3845:SkConic::evalAt\28float\2c\20SkPoint*\2c\20SkPoint*\29\20const +3846:SkConic::evalAt\28float\29\20const +3847:SkConic::TransformW\28SkPoint\20const*\2c\20float\2c\20SkMatrix\20const&\29 +3848:SkCompressedDataSize\28SkTextureCompressionType\2c\20SkISize\2c\20skia_private::TArray*\2c\20bool\29 +3849:SkColorSpace::serialize\28\29\20const +3850:SkColorSpace::MakeRGB\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +3851:SkColorInfo::operator=\28SkColorInfo&&\29 +3852:SkCoincidentSpans::extend\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\2c\20SkOpPtT\20const*\29 +3853:SkChopQuadAtYExtrema\28SkPoint\20const*\2c\20SkPoint*\29 +3854:SkCapabilities::RasterBackend\28\29 +3855:SkCanvas::scale\28float\2c\20float\29 +3856:SkCanvas::saveLayer\28SkCanvas::SaveLayerRec\20const&\29 +3857:SkCanvas::onResetClip\28\29 +3858:SkCanvas::onClipShader\28sk_sp\2c\20SkClipOp\29 +3859:SkCanvas::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +3860:SkCanvas::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3861:SkCanvas::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3862:SkCanvas::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +3863:SkCanvas::internalSave\28\29 +3864:SkCanvas::internalRestore\28\29 +3865:SkCanvas::internalDrawDeviceWithFilter\28SkDevice*\2c\20SkDevice*\2c\20SkSpan>\2c\20SkPaint\20const&\2c\20SkCanvas::DeviceCompatibleWithFilter\2c\20SkColorInfo\20const&\2c\20float\2c\20SkTileMode\2c\20bool\29 +3866:SkCanvas::drawColor\28unsigned\20int\2c\20SkBlendMode\29 +3867:SkCanvas::clipRect\28SkRect\20const&\2c\20bool\29 +3868:SkCanvas::clipPath\28SkPath\20const&\2c\20bool\29 +3869:SkCanvas::clear\28unsigned\20int\29 +3870:SkCanvas::clear\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +3871:SkCanvas::attemptBlurredRRectDraw\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20SkEnumBitMask\29 +3872:SkCachedData::~SkCachedData\28\29 +3873:SkBlurEngine::BoxBlurWindow\28float\29 +3874:SkBlitterClipper::~SkBlitterClipper\28\29 +3875:SkBlitter::blitRegion\28SkRegion\20const&\29 +3876:SkBlendShader::~SkBlendShader\28\29 +3877:SkBitmapDevice::SkBitmapDevice\28SkBitmap\20const&\2c\20SkSurfaceProps\20const&\2c\20void*\29 +3878:SkBitmapDevice::Create\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\2c\20SkRasterHandleAllocator*\29 +3879:SkBitmapDevice::BDDraw::~BDDraw\28\29 +3880:SkBitmapDevice::BDDraw::BDDraw\28SkBitmapDevice*\29 +3881:SkBitmap::writePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +3882:SkBitmap::setPixels\28void*\29 +3883:SkBitmap::readPixels\28SkPixmap\20const&\2c\20int\2c\20int\29\20const +3884:SkBitmap::installPixels\28SkPixmap\20const&\29 +3885:SkBitmap::allocPixels\28\29 +3886:SkBitmap::SkBitmap\28SkBitmap&&\29 +3887:SkBinaryWriteBuffer::writeScalarArray\28float\20const*\2c\20unsigned\20int\29 +3888:SkBinaryWriteBuffer::writeInt\28int\29 +3889:SkBaseShadowTessellator::~SkBaseShadowTessellator\28\29_5118 +3890:SkBaseShadowTessellator::handleLine\28SkPoint\20const&\29 +3891:SkAutoPixmapStorage::freeStorage\28\29 +3892:SkAutoPathBoundsUpdate::~SkAutoPathBoundsUpdate\28\29 +3893:SkAutoPathBoundsUpdate::SkAutoPathBoundsUpdate\28SkPath*\2c\20SkRect\20const&\29 +3894:SkAutoMalloc::reset\28unsigned\20long\2c\20SkAutoMalloc::OnShrink\29 +3895:SkAutoDescriptor::free\28\29 +3896:SkArenaAllocWithReset::reset\28\29 +3897:SkAnalyticQuadraticEdge::updateQuadratic\28\29 +3898:SkAnalyticEdge::goY\28int\29 +3899:SkAnalyticCubicEdge::updateCubic\28bool\29 +3900:SkAAClipBlitter::ensureRunsAndAA\28\29 +3901:SkAAClip::setRegion\28SkRegion\20const&\29 +3902:SkAAClip::setRect\28SkIRect\20const&\29 +3903:SkAAClip::quickContains\28int\2c\20int\2c\20int\2c\20int\29\20const +3904:SkAAClip::RunHead::Alloc\28int\2c\20unsigned\20long\29 +3905:SkAAClip::Builder::AppendRun\28SkTDArray&\2c\20unsigned\20int\2c\20int\29 +3906:Sk4f_toL32\28skvx::Vec<4\2c\20float>\20const&\29 +3907:SSVertex*\20SkArenaAlloc::make\28GrTriangulator::Vertex*&\29 +3908:RunBasedAdditiveBlitter::flush\28\29 +3909:R.9928 +3910:OpAsWinding::nextEdge\28Contour&\2c\20OpAsWinding::Edge\29 +3911:OT::sbix::get_strike\28unsigned\20int\29\20const +3912:OT::hb_paint_context_t::get_color\28unsigned\20int\2c\20float\2c\20int*\29 +3913:OT::hb_ot_apply_context_t::skipping_iterator_t::prev\28unsigned\20int*\29 +3914:OT::hb_ot_apply_context_t::check_glyph_property\28hb_glyph_info_t\20const*\2c\20unsigned\20int\29\20const +3915:OT::glyf_impl::CompositeGlyphRecord::translate\28contour_point_t\20const&\2c\20hb_array_t\29 +3916:OT::VariationStore::sanitize\28hb_sanitize_context_t*\29\20const +3917:OT::VarSizedBinSearchArrayOf>\2c\20OT::IntType\2c\20false>>>::get_length\28\29\20const +3918:OT::Script::get_lang_sys\28unsigned\20int\29\20const +3919:OT::PaintSkew::sanitize\28hb_sanitize_context_t*\29\20const +3920:OT::OpenTypeOffsetTable::sanitize\28hb_sanitize_context_t*\29\20const +3921:OT::OS2::has_data\28\29\20const +3922:OT::Layout::GSUB_impl::SubstLookup::serialize_ligature\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20hb_sorted_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\2c\20hb_array_t\29 +3923:OT::Layout::GPOS_impl::MarkArray::apply\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20OT::Layout::GPOS_impl::AnchorMatrix\20const&\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +3924:OT::HVARVVAR::sanitize\28hb_sanitize_context_t*\29\20const +3925:OT::GSUBGPOS::get_lookup_count\28\29\20const +3926:OT::GSUBGPOS::get_feature_list\28\29\20const +3927:OT::GSUBGPOS::accelerator_t::get_accel\28unsigned\20int\29\20const +3928:OT::Device::get_y_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3929:OT::Device::get_x_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +3930:OT::ClipList::get_extents\28unsigned\20int\2c\20hb_glyph_extents_t*\2c\20OT::VarStoreInstancer\20const&\29\20const +3931:OT::COLR::paint_glyph\28hb_font_t*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29\20const +3932:OT::ArrayOf>::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20bool\29 +3933:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29 +3934:LineQuadraticIntersections::uniqueAnswer\28double\2c\20SkDPoint\20const&\29 +3935:LineQuadraticIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineQuadraticIntersections::PinTPoint\29 +3936:LineQuadraticIntersections::checkCoincident\28\29 +3937:LineQuadraticIntersections::addLineNearEndPoints\28\29 +3938:LineCubicIntersections::uniqueAnswer\28double\2c\20SkDPoint\20const&\29 +3939:LineCubicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineCubicIntersections::PinTPoint\29 +3940:LineCubicIntersections::checkCoincident\28\29 +3941:LineCubicIntersections::addLineNearEndPoints\28\29 +3942:LineConicIntersections::validT\28double*\2c\20double\2c\20double*\29 +3943:LineConicIntersections::uniqueAnswer\28double\2c\20SkDPoint\20const&\29 +3944:LineConicIntersections::pinTs\28double*\2c\20double*\2c\20SkDPoint*\2c\20LineConicIntersections::PinTPoint\29 +3945:LineConicIntersections::checkCoincident\28\29 +3946:LineConicIntersections::addLineNearEndPoints\28\29 +3947:HandleInnerJoin\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +3948:GrVertexChunkBuilder::~GrVertexChunkBuilder\28\29 +3949:GrTriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +3950:GrTriangulator::splitEdge\28GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +3951:GrTriangulator::pathToPolys\28float\2c\20SkRect\20const&\2c\20bool*\29 +3952:GrTriangulator::makePoly\28GrTriangulator::Poly**\2c\20GrTriangulator::Vertex*\2c\20int\29\20const +3953:GrTriangulator::generateCubicPoints\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20GrTriangulator::VertexList*\2c\20int\29\20const +3954:GrTriangulator::checkForIntersection\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +3955:GrTriangulator::applyFillType\28int\29\20const +3956:GrTriangulator::SortMesh\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +3957:GrTriangulator::MonotonePoly::addEdge\28GrTriangulator::Edge*\29 +3958:GrTriangulator::GrTriangulator\28SkPath\20const&\2c\20SkArenaAlloc*\29 +3959:GrTriangulator::Edge::insertBelow\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +3960:GrTriangulator::Edge::insertAbove\28GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +3961:GrTriangulator::BreadcrumbTriangleList::append\28SkArenaAlloc*\2c\20SkPoint\2c\20SkPoint\2c\20SkPoint\2c\20int\29 +3962:GrThreadSafeCache::recycleEntry\28GrThreadSafeCache::Entry*\29 +3963:GrThreadSafeCache::dropAllRefs\28\29 +3964:GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9436 +3965:GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +3966:GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +3967:GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +3968:GrTextureRenderTargetProxy::callbackDesc\28\29\20const +3969:GrTextureProxy::~GrTextureProxy\28\29 +3970:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::$_0::operator\28\29\28int\2c\20GrSamplerState::WrapMode\29\20const +3971:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29 +3972:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_3::operator\28\29\28bool\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +3973:GrTexture::GrTexture\28GrGpu*\2c\20SkISize\20const&\2c\20skgpu::Protected\2c\20GrTextureType\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +3974:GrTexture::ComputeScratchKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20skgpu::ScratchKey*\29 +3975:GrSurfaceProxyView::asTextureProxyRef\28\29\20const +3976:GrSurfaceProxy::instantiateImpl\28GrResourceProvider*\2c\20int\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::UniqueKey\20const*\29 +3977:GrSurfaceProxy::GrSurfaceProxy\28sk_sp\2c\20SkBackingFit\2c\20GrSurfaceProxy::UseAllocator\29 +3978:GrStyledShape::styledBounds\28\29\20const +3979:GrStyledShape::addGenIDChangeListener\28sk_sp\29\20const +3980:GrStyledShape::GrStyledShape\28SkRect\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +3981:GrStyle::isSimpleHairline\28\29\20const +3982:GrStyle::initPathEffect\28sk_sp\29 +3983:GrStencilSettings::Face::reset\28GrTStencilFaceSettings\20const&\2c\20bool\2c\20int\29 +3984:GrSimpleMeshDrawOpHelper::fixedFunctionFlags\28\29\20const +3985:GrShape::setPath\28SkPath\20const&\29 +3986:GrShape::segmentMask\28\29\20const +3987:GrShape::operator=\28GrShape\20const&\29 +3988:GrShape::convex\28bool\29\20const +3989:GrShaderVar::GrShaderVar\28SkString\2c\20SkSLType\2c\20int\29 +3990:GrResourceProvider::findResourceByUniqueKey\28skgpu::UniqueKey\20const&\29 +3991:GrResourceProvider::createPatternedIndexBuffer\28unsigned\20short\20const*\2c\20int\2c\20int\2c\20int\2c\20skgpu::UniqueKey\20const*\29 +3992:GrResourceCache::removeUniqueKey\28GrGpuResource*\29 +3993:GrResourceCache::getNextTimestamp\28\29 +3994:GrResourceCache::findAndRefScratchResource\28skgpu::ScratchKey\20const&\29 +3995:GrRenderTask::dependsOn\28GrRenderTask\20const*\29\20const +3996:GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +3997:GrRenderTargetProxy::canUseStencil\28GrCaps\20const&\29\20const +3998:GrRecordingContextPriv::createDevice\28skgpu::Budgeted\2c\20SkImageInfo\20const&\2c\20SkBackingFit\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\2c\20skgpu::ganesh::Device::InitContents\29 +3999:GrRecordingContextPriv::addOnFlushCallbackObject\28GrOnFlushCallbackObject*\29 +4000:GrRecordingContext::~GrRecordingContext\28\29 +4001:GrQuadUtils::TessellationHelper::reset\28GrQuad\20const&\2c\20GrQuad\20const*\29 +4002:GrQuadUtils::TessellationHelper::getEdgeEquations\28\29 +4003:GrQuadUtils::TessellationHelper::Vertices::moveAlong\28GrQuadUtils::TessellationHelper::EdgeVectors\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4004:GrQuadUtils::ResolveAAType\28GrAAType\2c\20GrQuadAAFlags\2c\20GrQuad\20const&\2c\20GrAAType*\2c\20GrQuadAAFlags*\29 +4005:GrQuadUtils::CropToRect\28SkRect\20const&\2c\20GrAA\2c\20DrawQuad*\2c\20bool\29 +4006:GrQuadBuffer<\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA>::append\28GrQuad\20const&\2c\20\28anonymous\20namespace\29::FillRectOpImpl::ColorAndAA&&\2c\20GrQuad\20const*\29 +4007:GrQuad::setQuadType\28GrQuad::Type\29 +4008:GrPorterDuffXPFactory::SimpleSrcOverXP\28\29 +4009:GrPipeline*\20SkArenaAlloc::make\28GrPipeline::InitArgs&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29 +4010:GrPersistentCacheUtils::UnpackCachedShaders\28SkReadBuffer*\2c\20std::__2::basic_string\2c\20std::__2::allocator>*\2c\20SkSL::ProgramInterface*\2c\20int\2c\20GrPersistentCacheUtils::ShaderMetadata*\29 +4011:GrPathUtils::quadraticPointCount\28SkPoint\20const*\2c\20float\29 +4012:GrPathUtils::convertCubicToQuads\28SkPoint\20const*\2c\20float\2c\20skia_private::TArray*\29 +4013:GrPathTessellationShader::Make\28GrShaderCaps\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::tess::PatchAttribs\29 +4014:GrPathTessellationShader::MakeSimpleTriangleShader\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +4015:GrOvalOpFactory::MakeOvalOp\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\2c\20GrShaderCaps\20const*\29 +4016:GrOpsRenderPass::drawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +4017:GrOpFlushState::draw\28int\2c\20int\29 +4018:GrOp::chainConcat\28std::__2::unique_ptr>\29 +4019:GrNonAtomicRef::unref\28\29\20const +4020:GrModulateAtlasCoverageEffect::GrModulateAtlasCoverageEffect\28GrModulateAtlasCoverageEffect\20const&\29 +4021:GrMipLevel::operator=\28GrMipLevel&&\29 +4022:GrMeshDrawOp::PatternHelper::PatternHelper\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +4023:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29 +4024:GrImageInfo::makeDimensions\28SkISize\29\20const +4025:GrGpuResource::~GrGpuResource\28\29 +4026:GrGpuResource::removeScratchKey\28\29 +4027:GrGpuResource::registerWithCacheWrapped\28GrWrapCacheable\29 +4028:GrGpuResource::getResourceName\28\29\20const +4029:GrGpuResource::dumpMemoryStatisticsPriv\28SkTraceMemoryDump*\2c\20SkString\20const&\2c\20char\20const*\2c\20unsigned\20long\29\20const +4030:GrGpuResource::CreateUniqueID\28\29 +4031:GrGpuBuffer::onGpuMemorySize\28\29\20const +4032:GrGpu::submitToGpu\28\29 +4033:GrGpu::resolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +4034:GrGpu::executeFlushInfo\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20std::__2::optional\2c\20skgpu::MutableTextureState\20const*\29 +4035:GrGeometryProcessor::TextureSampler::TextureSampler\28GrSamplerState\2c\20GrBackendFormat\20const&\2c\20skgpu::Swizzle\20const&\29 +4036:GrGeometryProcessor::TextureSampler::TextureSampler\28GrGeometryProcessor::TextureSampler&&\29 +4037:GrGeometryProcessor::ProgramImpl::TransformInfo::TransformInfo\28GrGeometryProcessor::ProgramImpl::TransformInfo\20const&\29 +4038:GrGeometryProcessor::ProgramImpl::AddMatrixKeys\28GrShaderCaps\20const&\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\29 +4039:GrGeometryProcessor::Attribute::size\28\29\20const +4040:GrGLUniformHandler::~GrGLUniformHandler\28\29 +4041:GrGLUniformHandler::getUniformVariable\28GrResourceHandle\29\20const +4042:GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_11873 +4043:GrGLTextureRenderTarget::onRelease\28\29 +4044:GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +4045:GrGLTextureRenderTarget::onAbandon\28\29 +4046:GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +4047:GrGLTexture::~GrGLTexture\28\29 +4048:GrGLTexture::onRelease\28\29 +4049:GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +4050:GrGLTexture::TextureTypeFromTarget\28unsigned\20int\29 +4051:GrGLSemaphore::Make\28GrGLGpu*\2c\20bool\29 +4052:GrGLSLVaryingHandler::~GrGLSLVaryingHandler\28\29 +4053:GrGLSLUniformHandler::addInputSampler\28skgpu::Swizzle\20const&\2c\20char\20const*\29 +4054:GrGLSLUniformHandler::UniformInfo::~UniformInfo\28\29 +4055:GrGLSLShaderBuilder::appendTextureLookup\28SkString*\2c\20GrResourceHandle\2c\20char\20const*\29\20const +4056:GrGLSLShaderBuilder::appendColorGamutXform\28char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +4057:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +4058:GrGLSLProgramDataManager::setSkMatrix\28GrResourceHandle\2c\20SkMatrix\20const&\29\20const +4059:GrGLSLProgramBuilder::writeFPFunction\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +4060:GrGLSLProgramBuilder::nameExpression\28SkString*\2c\20char\20const*\29 +4061:GrGLSLProgramBuilder::fragmentProcessorHasCoordsParam\28GrFragmentProcessor\20const*\29\20const +4062:GrGLSLProgramBuilder::emitSampler\28GrBackendFormat\20const&\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\29 +4063:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10131 +4064:GrGLRenderTarget::~GrGLRenderTarget\28\29 +4065:GrGLRenderTarget::onRelease\28\29 +4066:GrGLRenderTarget::onAbandon\28\29 +4067:GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +4068:GrGLProgramDataManager::~GrGLProgramDataManager\28\29 +4069:GrGLProgramBuilder::~GrGLProgramBuilder\28\29 +4070:GrGLProgramBuilder::computeCountsAndStrides\28unsigned\20int\2c\20GrGeometryProcessor\20const&\2c\20bool\29 +4071:GrGLProgramBuilder::addInputVars\28SkSL::ProgramInterface\20const&\29 +4072:GrGLOpsRenderPass::dmsaaLoadStoreBounds\28\29\20const +4073:GrGLOpsRenderPass::bindInstanceBuffer\28GrBuffer\20const*\2c\20int\29 +4074:GrGLGpu::insertSemaphore\28GrSemaphore*\29 +4075:GrGLGpu::flushViewport\28SkIRect\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +4076:GrGLGpu::flushScissor\28GrScissorState\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +4077:GrGLGpu::flushClearColor\28std::__2::array\29 +4078:GrGLGpu::disableStencil\28\29 +4079:GrGLGpu::deleteSync\28__GLsync*\29 +4080:GrGLGpu::createTexture\28SkISize\2c\20GrGLFormat\2c\20unsigned\20int\2c\20skgpu::Renderable\2c\20GrGLTextureParameters::SamplerOverriddenState*\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +4081:GrGLGpu::copySurfaceAsDraw\28GrSurface*\2c\20bool\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +4082:GrGLGpu::HWVertexArrayState::bindInternalVertexArray\28GrGLGpu*\2c\20GrBuffer\20const*\29 +4083:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20char\2c\20int\2c\20void\20const*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20char\2c\20int\2c\20void\20const*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20char\2c\20int\2c\20void\20const*\29 +4084:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +4085:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +4086:GrGLFunction::GrGLFunction\28unsigned\20char\20const*\20\28*\29\28unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29 +4087:GrGLContextInfo::~GrGLContextInfo\28\29 +4088:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrGLFormat\29\20const +4089:GrGLCaps::canCopyAsDraw\28GrGLFormat\2c\20bool\2c\20bool\29\20const +4090:GrGLBuffer::~GrGLBuffer\28\29 +4091:GrGLBuffer::Make\28GrGLGpu*\2c\20unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +4092:GrGLBackendTextureData::GrGLBackendTextureData\28GrGLTextureInfo\20const&\2c\20sk_sp\29 +4093:GrGLAttribArrayState::invalidate\28\29 +4094:GrGLAttribArrayState::enableVertexArrays\28GrGLGpu\20const*\2c\20int\2c\20GrPrimitiveRestart\29 +4095:GrGLAttachment::GrGLAttachment\28GrGpu*\2c\20unsigned\20int\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20GrGLFormat\2c\20std::__2::basic_string_view>\29 +4096:GrFragmentProcessors::make_effect_fp\28sk_sp\2c\20char\20const*\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkSpan\2c\20GrFPArgs\20const&\29 +4097:GrFragmentProcessors::IsSupported\28SkMaskFilter\20const*\29 +4098:GrFragmentProcessor::makeProgramImpl\28\29\20const +4099:GrFragmentProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +4100:GrFragmentProcessor::ProgramImpl::~ProgramImpl\28\29 +4101:GrFragmentProcessor::MulInputByChildAlpha\28std::__2::unique_ptr>\29 +4102:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +4103:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29 +4104:GrEagerDynamicVertexAllocator::lock\28unsigned\20long\2c\20int\29 +4105:GrDynamicAtlas::makeNode\28GrDynamicAtlas::Node*\2c\20int\2c\20int\2c\20int\2c\20int\29 +4106:GrDstProxyView::GrDstProxyView\28GrDstProxyView\20const&\29 +4107:GrDrawingManager::setLastRenderTask\28GrSurfaceProxy\20const*\2c\20GrRenderTask*\29 +4108:GrDrawingManager::insertTaskBeforeLast\28sk_sp\29 +4109:GrDrawingManager::flushSurfaces\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +4110:GrDrawOpAtlas::makeMRU\28skgpu::Plot*\2c\20unsigned\20int\29 +4111:GrDefaultGeoProcFactory::MakeForDeviceSpace\28SkArenaAlloc*\2c\20GrDefaultGeoProcFactory::Color\20const&\2c\20GrDefaultGeoProcFactory::Coverage\20const&\2c\20GrDefaultGeoProcFactory::LocalCoords\20const&\2c\20SkMatrix\20const&\29 +4112:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29 +4113:GrColorTypeClampType\28GrColorType\29 +4114:GrColorSpaceXform::Equals\28GrColorSpaceXform\20const*\2c\20GrColorSpaceXform\20const*\29 +4115:GrBufferAllocPool::unmap\28\29 +4116:GrBufferAllocPool::reset\28\29 +4117:GrBlurUtils::extract_draw_rect_from_data\28SkData*\2c\20SkIRect\20const&\29 +4118:GrBlurUtils::can_filter_mask\28SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect*\29 +4119:GrBlurUtils::GaussianBlur\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20float\2c\20float\2c\20SkTileMode\2c\20SkBackingFit\29 +4120:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +4121:GrBicubicEffect::GrBicubicEffect\28std::__2::unique_ptr>\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrBicubicEffect::Clamp\29 +4122:GrBackendTextures::MakeGL\28int\2c\20int\2c\20skgpu::Mipmapped\2c\20GrGLTextureInfo\20const&\2c\20sk_sp\2c\20std::__2::basic_string_view>\29 +4123:GrBackendFormatStencilBits\28GrBackendFormat\20const&\29 +4124:GrBackendFormat::operator==\28GrBackendFormat\20const&\29\20const +4125:GrAtlasManager::resolveMaskFormat\28skgpu::MaskFormat\29\20const +4126:GrAATriangulator::~GrAATriangulator\28\29 +4127:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrAATriangulator::EventList*\29\20const +4128:GrAATriangulator::connectSSEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29 +4129:GrAAConvexTessellator::terminate\28GrAAConvexTessellator::Ring\20const&\29 +4130:GrAAConvexTessellator::computePtAlongBisector\28int\2c\20SkPoint\20const&\2c\20int\2c\20float\2c\20SkPoint*\29\20const +4131:GrAAConvexTessellator::computeNormals\28\29::$_0::operator\28\29\28SkPoint\29\20const +4132:GrAAConvexTessellator::CandidateVerts::originatingIdx\28int\29\20const +4133:GrAAConvexTessellator::CandidateVerts::fuseWithPrior\28int\29 +4134:GrAAConvexTessellator::CandidateVerts::addNewPt\28SkPoint\20const&\2c\20int\2c\20int\2c\20bool\29 +4135:GetVariationDesignPosition\28FT_FaceRec_*\2c\20SkFontArguments::VariationPosition::Coordinate*\2c\20int\29 +4136:GetAxes\28FT_FaceRec_*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\29 +4137:FT_Set_Transform +4138:FT_Set_Char_Size +4139:FT_Select_Metrics +4140:FT_Request_Metrics +4141:FT_List_Remove +4142:FT_List_Finalize +4143:FT_Hypot +4144:FT_GlyphLoader_CreateExtra +4145:FT_GlyphLoader_Adjust_Points +4146:FT_Get_Paint +4147:FT_Get_MM_Var +4148:FT_Get_Color_Glyph_Paint +4149:FT_Done_GlyphSlot +4150:FT_Done_Face +4151:FT_Activate_Size +4152:EllipticalRRectOp::~EllipticalRRectOp\28\29 +4153:EdgeLT::operator\28\29\28Edge\20const&\2c\20Edge\20const&\29\20const +4154:DAffineMatrix::mapPoint\28\28anonymous\20namespace\29::DPoint\20const&\29\20const +4155:DAffineMatrix::mapPoint\28SkPoint\20const&\29\20const +4156:Cr_z_inflate_table +4157:CopyFromCompoundDictionary +4158:Compute_Point_Displacement +4159:CircularRRectOp::~CircularRRectOp\28\29 +4160:CFF::cff_stack_t::push\28\29 +4161:CFF::arg_stack_t::pop_int\28\29 +4162:CFF::CFFIndex>::get_size\28\29\20const +4163:BrotliWarmupBitReader +4164:Bounder::Bounder\28SkRect\20const&\2c\20SkPaint\20const&\29 +4165:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block*\2c\20int\29>::Item::operator++\28\29 +4166:ActiveEdgeList::DoubleRotation\28ActiveEdge*\2c\20int\29 +4167:AAT::kerxTupleKern\28int\2c\20unsigned\20int\2c\20void\20const*\2c\20AAT::hb_aat_apply_context_t*\29 +4168:AAT::feat::get_feature\28hb_aat_layout_feature_type_t\29\20const +4169:AAT::StateTable::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int*\29\20const +4170:AAT::StateTable::get_class\28unsigned\20int\2c\20unsigned\20int\29\20const +4171:AAT::StateTable::get_entry\28int\2c\20unsigned\20int\29\20const +4172:AAT::Lookup::sanitize\28hb_sanitize_context_t*\29\20const +4173:AAT::ClassTable>::get_class\28unsigned\20int\2c\20unsigned\20int\29\20const +4174:3965 +4175:3966 +4176:3967 +4177:3968 +4178:3969 +4179:3970 +4180:3971 +4181:3972 +4182:3973 +4183:3974 +4184:3975 +4185:3976 +4186:3977 +4187:3978 +4188:3979 +4189:3980 +4190:3981 +4191:3982 +4192:3983 +4193:3984 +4194:3985 +4195:3986 +4196:3987 +4197:3988 +4198:3989 +4199:3990 +4200:3991 +4201:3992 +4202:3993 +4203:3994 +4204:3995 +4205:3996 +4206:3997 +4207:3998 +4208:3999 +4209:4000 +4210:4001 +4211:4002 +4212:4003 +4213:4004 +4214:4005 +4215:4006 +4216:4007 +4217:4008 +4218:4009 +4219:4010 +4220:4011 +4221:4012 +4222:4013 +4223:4014 +4224:4015 +4225:zeroinfnan +4226:zero_mark_widths_by_gdef\28hb_buffer_t*\2c\20bool\29 +4227:xyzd50_to_lab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +4228:xyz_almost_equal\28skcms_Matrix3x3\20const&\2c\20skcms_Matrix3x3\20const&\29 +4229:write_vertex_position\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\2c\20GrShaderCaps\20const&\2c\20GrShaderVar\20const&\2c\20SkMatrix\20const&\2c\20char\20const*\2c\20GrShaderVar*\2c\20GrResourceHandle*\29 +4230:write_passthrough_vertex_position\28GrGLSLVertexBuilder*\2c\20GrShaderVar\20const&\2c\20GrShaderVar*\29 +4231:winding_mono_quad\28SkPoint\20const*\2c\20float\2c\20float\2c\20int*\29 +4232:winding_mono_conic\28SkConic\20const&\2c\20float\2c\20float\2c\20int*\29 +4233:wctomb +4234:wchar_t*\20std::__2::copy\5babi:nn180100\5d\2c\20wchar_t*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20wchar_t*\29 +4235:wchar_t*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28wchar_t*\2c\20wchar_t\20const*\2c\20std::__2::__element_count\29 +4236:walk_simple_edges\28SkEdge*\2c\20SkBlitter*\2c\20int\2c\20int\29 +4237:vsscanf +4238:void\20std::__2::unique_ptr::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot*\2c\200>\28skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot*\29 +4239:void\20std::__2::unique_ptr\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot*\2c\200>\28skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot*\29 +4240:void\20std::__2::unique_ptr>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot*\2c\200>\28skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot*\29 +4241:void\20std::__2::unique_ptr::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::reset\5babi:ne180100\5d::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot*\2c\200>\28skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot*\29 +4242:void\20std::__2::allocator::construct\5babi:ne180100\5d&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&>\28sktext::GlyphRun*\2c\20SkFont\20const&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\2c\20SkSpan&\29 +4243:void\20std::__2::allocator::construct\5babi:ne180100\5d\28skia::textlayout::FontFeature*\2c\20SkString\20const&\2c\20int&\29 +4244:void\20std::__2::allocator::construct\5babi:ne180100\5d\28Contour*\2c\20SkRect&\2c\20int&\2c\20int&\29 +4245:void\20std::__2::__variant_detail::__impl\2c\20std::__2::unique_ptr>>::__assign\5babi:ne180100\5d<0ul\2c\20sk_sp>\28sk_sp&&\29 +4246:void\20std::__2::__variant_detail::__impl::__assign\5babi:ne180100\5d<0ul\2c\20SkPaint>\28SkPaint&&\29 +4247:void\20std::__2::__variant_detail::__assignment>::__assign_alt\5babi:ne180100\5d<0ul\2c\20SkPaint\2c\20SkPaint>\28std::__2::__variant_detail::__alt<0ul\2c\20SkPaint>&\2c\20SkPaint&&\29 +4248:void\20std::__2::__tree_right_rotate\5babi:ne180100\5d*>\28std::__2::__tree_node_base*\29 +4249:void\20std::__2::__tree_left_rotate\5babi:ne180100\5d*>\28std::__2::__tree_node_base*\29 +4250:void\20std::__2::__stable_sort_move\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>\28std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20std::__2::__wrap_iter<\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::'lambda'\28\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\2c\20\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop\20const&\29&\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::difference_type\2c\20std::__2::iterator_traits\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29::$_0::operator\28\29\28FT_ColorStopIterator_\20const&\2c\20std::__2::vector>&\2c\20std::__2::vector\2c\20std::__2::allocator>>&\29\20const::ColorStop*>>::value_type*\29 +4251:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +4252:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +4253:void\20std::__2::__sort5_maybe_branchless\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +4254:void\20std::__2::__sift_up\5babi:ne180100\5d*>>\28std::__2::__wrap_iter*>\2c\20std::__2::__wrap_iter*>\2c\20GrGeometryProcessor::ProgramImpl::emitTransformCode\28GrGLSLVertexBuilder*\2c\20GrGLSLUniformHandler*\29::$_0&\2c\20std::__2::iterator_traits*>>::difference_type\29 +4255:void\20std::__2::__sift_up\5babi:ne180100\5d>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20GrAATriangulator::EventComparator&\2c\20std::__2::iterator_traits>::difference_type\29 +4256:void\20std::__2::__optional_storage_base::__construct\5babi:ne180100\5d\28skia::textlayout::FontArguments\20const&\29 +4257:void\20std::__2::__optional_storage_base::__assign_from\5babi:ne180100\5d\20const&>\28std::__2::__optional_copy_assign_base\20const&\29 +4258:void\20std::__2::__optional_storage_base::__construct\5babi:ne180100\5d\28SkPath\20const&\29 +4259:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d&\2c\20int&>\2c\20std::__2::tuple\2c\20unsigned\20long>\2c\20sk_sp\2c\20unsigned\20long\2c\200ul\2c\201ul>\28std::__2::tuple&\2c\20int&>&\2c\20std::__2::tuple\2c\20unsigned\20long>&&\2c\20std::__2::__tuple_types\2c\20unsigned\20long>\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +4260:void\20std::__2::__memberwise_forward_assign\5babi:ne180100\5d&>\2c\20std::__2::tuple>\2c\20GrSurfaceProxyView\2c\20sk_sp\2c\200ul\2c\201ul>\28std::__2::tuple&>&\2c\20std::__2::tuple>&&\2c\20std::__2::__tuple_types>\2c\20std::__2::__tuple_indices<0ul\2c\201ul>\29 +4261:void\20std::__2::__list_imp>::__delete_node\5babi:ne180100\5d<>\28std::__2::__list_node*\29 +4262:void\20std::__2::__introsort\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +4263:void\20std::__2::__introsort\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +4264:void\20std::__2::__introsort\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\2c\20std::__2::iterator_traits::difference_type\2c\20bool\29 +4265:void\20std::__2::__forward_list_base\2c\20std::__2::allocator>>::__delete_node\5babi:ne180100\5d<>\28std::__2::__forward_list_node\2c\20void*>*\29 +4266:void\20std::__2::__double_or_nothing\5babi:nn180100\5d\28std::__2::unique_ptr&\2c\20char*&\2c\20char*&\29 +4267:void\20sorted_merge<&sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +4268:void\20sorted_merge<&sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29>\28GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::VertexList*\29 +4269:void\20sort_r_simple\28void*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20int\20\28*\29\28void\20const*\2c\20void\20const*\2c\20void*\29\2c\20void*\29 +4270:void\20sktext::gpu::fillDirectClipped\28SkZip\2c\20unsigned\20int\2c\20SkPoint\2c\20SkIRect*\29 +4271:void\20skgpu::ganesh::SurfaceFillContext::clearAtLeast<\28SkAlphaType\292>\28SkIRect\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +4272:void\20portable::memsetT\28unsigned\20short*\2c\20unsigned\20short\2c\20int\29 +4273:void\20portable::memsetT\28unsigned\20int*\2c\20unsigned\20int\2c\20int\29 +4274:void\20hb_sanitize_context_t::set_object>\28OT::KernSubTable\20const*\29 +4275:void\20hb_sanitize_context_t::set_object>\28AAT::ChainSubtable\20const*\29 +4276:void\20hb_sanitize_context_t::set_object>\28AAT::ChainSubtable\20const*\29 +4277:void\20hair_path<\28SkPaint::Cap\292>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4278:void\20hair_path<\28SkPaint::Cap\291>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4279:void\20hair_path<\28SkPaint::Cap\290>\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +4280:void\20\28anonymous\20namespace\29::copyFT2LCD16\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\2c\20unsigned\20char\20const*\29 +4281:void\20SkTQSort\28double*\2c\20double*\29 +4282:void\20SkTIntroSort\28int\2c\20int*\2c\20int\2c\20DistanceLessThan\20const&\29 +4283:void\20SkTIntroSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29>\28int\2c\20float*\2c\20int\2c\20void\20SkTQSort\28float*\2c\20float*\29::'lambda'\28float\20const&\2c\20float\20const&\29\20const&\29 +4284:void\20SkTIntroSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29>\28int\2c\20double*\2c\20int\2c\20void\20SkTQSort\28double*\2c\20double*\29::'lambda'\28double\20const&\2c\20double\20const&\29\20const&\29 +4285:void\20SkTIntroSort\28int\2c\20SkString*\2c\20int\2c\20bool\20\20const\28&\29\28SkString\20const&\2c\20SkString\20const&\29\29 +4286:void\20SkTIntroSort\28int\2c\20SkOpRayHit**\2c\20int\2c\20bool\20\20const\28&\29\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29\29 +4287:void\20SkTIntroSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29>\28int\2c\20SkOpContour*\2c\20int\2c\20void\20SkTQSort\28SkOpContour**\2c\20SkOpContour**\29::'lambda'\28SkOpContour\20const*\2c\20SkOpContour\20const*\29\20const&\29 +4288:void\20SkTIntroSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29>\28int\2c\20SkEdge*\2c\20int\2c\20void\20SkTQSort\28SkEdge**\2c\20SkEdge**\29::'lambda'\28SkEdge\20const*\2c\20SkEdge\20const*\29\20const&\29 +4289:void\20SkTIntroSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29>\28int\2c\20SkClosestRecord\20const*\2c\20int\2c\20void\20SkTQSort\28SkClosestRecord\20const**\2c\20SkClosestRecord\20const**\29::'lambda'\28SkClosestRecord\20const*\2c\20SkClosestRecord\20const*\29\20const&\29 +4290:void\20SkTIntroSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29>\28int\2c\20SkAnalyticEdge*\2c\20int\2c\20void\20SkTQSort\28SkAnalyticEdge**\2c\20SkAnalyticEdge**\29::'lambda'\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge\20const*\29\20const&\29 +4291:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\20const\28&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +4292:void\20SkTIntroSort\28int\2c\20GrGpuResource**\2c\20int\2c\20bool\20\28*\20const&\29\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29\29 +4293:void\20SkTIntroSort\28int\2c\20Edge*\2c\20int\2c\20EdgeLT\20const&\29 +4294:void\20SkSafeUnref\28GrWindowRectangles::Rec\20const*\29 +4295:void\20SkSafeUnref\28GrSurface::RefCntedReleaseProc*\29 +4296:void\20SkSafeUnref\28GrBufferAllocPool::CpuBufferCache*\29 +4297:void\20SkRecords::FillBounds::trackBounds\28SkRecords::NoOp\20const&\29 +4298:void\20GrGLProgramDataManager::setMatrices<4>\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +4299:void\20GrGLProgramDataManager::setMatrices<3>\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +4300:void\20GrGLProgramDataManager::setMatrices<2>\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +4301:void\20A8_row_aa\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\20\28*\29\28unsigned\20char\2c\20unsigned\20char\29\2c\20bool\29 +4302:virtual\20thunk\20to\20GrGLTexture::onSetLabel\28\29 +4303:virtual\20thunk\20to\20GrGLTexture::backendFormat\28\29\20const +4304:vfiprintf +4305:validate_texel_levels\28SkISize\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20GrCaps\20const*\29 +4306:valid_divs\28int\20const*\2c\20int\2c\20int\2c\20int\29 +4307:utf8_byte_type\28unsigned\20char\29 +4308:use_tiled_rendering\28GrGLCaps\20const&\2c\20GrOpsRenderPass::StencilLoadAndStoreInfo\20const&\29 +4309:uprv_realloc_skia +4310:update_edge\28SkEdge*\2c\20int\29 +4311:unsigned\20short\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4312:unsigned\20short\20sk_saturate_cast\28float\29 +4313:unsigned\20long\20long\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4314:unsigned\20long&\20std::__2::vector>::emplace_back\28unsigned\20long&\29 +4315:unsigned\20int\20std::__2::__num_get_unsigned_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +4316:unsigned\20int\20const*\20std::__2::lower_bound\5babi:nn180100\5d\28unsigned\20int\20const*\2c\20unsigned\20int\20const*\2c\20unsigned\20long\20const&\29 +4317:unsigned\20int*\20hb_vector_t::push\28unsigned\20int&\29 +4318:unsigned\20char\20pack_distance_field_val<4>\28float\29 +4319:ubidi_getVisualRun_skia +4320:ubidi_countRuns_skia +4321:ubidi_close_skia +4322:u_charType_skia +4323:u8_lerp\28unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char\29 +4324:tt_size_select +4325:tt_size_run_prep +4326:tt_size_done_bytecode +4327:tt_sbit_decoder_load_image +4328:tt_prepare_zone +4329:tt_loader_set_pp +4330:tt_loader_init +4331:tt_loader_done +4332:tt_hvadvance_adjust +4333:tt_face_vary_cvt +4334:tt_face_palette_set +4335:tt_face_load_generic_header +4336:tt_face_load_cvt +4337:tt_face_goto_table +4338:tt_face_get_metrics +4339:tt_done_blend +4340:tt_cmap4_set_range +4341:tt_cmap4_next +4342:tt_cmap4_char_map_linear +4343:tt_cmap4_char_map_binary +4344:tt_cmap2_get_subheader +4345:tt_cmap14_get_nondef_chars +4346:tt_cmap14_get_def_chars +4347:tt_cmap14_def_char_count +4348:tt_cmap13_next +4349:tt_cmap13_init +4350:tt_cmap13_char_map_binary +4351:tt_cmap12_next +4352:tt_cmap12_char_map_binary +4353:tt_apply_mvar +4354:top_collinear\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +4355:to_stablekey\28int\2c\20unsigned\20int\29 +4356:throw_on_failure\28unsigned\20long\2c\20void*\29 +4357:thai_pua_shape\28unsigned\20int\2c\20thai_action_t\2c\20hb_font_t*\29 +4358:t1_lookup_glyph_by_stdcharcode_ps +4359:t1_cmap_std_init +4360:t1_cmap_std_char_index +4361:t1_builder_init +4362:t1_builder_close_contour +4363:t1_builder_add_point1 +4364:t1_builder_add_point +4365:t1_builder_add_contour +4366:sweep_lt_vert\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4367:sweep_lt_horiz\28SkPoint\20const&\2c\20SkPoint\20const&\29 +4368:surface_setCallbackHandler +4369:surface_getThreadId +4370:strutStyle_setFontSize +4371:strtoull +4372:strtoll_l +4373:strspn +4374:strncpy +4375:strcspn +4376:store_int +4377:std::logic_error::~logic_error\28\29 +4378:std::logic_error::logic_error\28char\20const*\29 +4379:std::exception::exception\5babi:nn180100\5d\28\29 +4380:std::__2::vector>::operator=\5babi:ne180100\5d\28std::__2::vector>\20const&\29 +4381:std::__2::vector>::__vdeallocate\28\29 +4382:std::__2::vector>::__move_assign\28std::__2::vector>&\2c\20std::__2::integral_constant\29 +4383:std::__2::vector>\2c\20std::__2::allocator>>>::__base_destruct_at_end\5babi:ne180100\5d\28std::__2::unique_ptr>*\29 +4384:std::__2::vector\2c\20std::__2::allocator>>::__base_destruct_at_end\5babi:ne180100\5d\28std::__2::tuple*\29 +4385:std::__2::vector>::max_size\28\29\20const +4386:std::__2::vector>::capacity\5babi:nn180100\5d\28\29\20const +4387:std::__2::vector>::__construct_at_end\28unsigned\20long\29 +4388:std::__2::vector>::__clear\5babi:nn180100\5d\28\29 +4389:std::__2::vector\2c\20std::__2::allocator>\2c\20std::__2::allocator\2c\20std::__2::allocator>>>::__clear\5babi:ne180100\5d\28\29 +4390:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4391:std::__2::vector>::vector\28std::__2::vector>\20const&\29 +4392:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4393:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +4394:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4395:std::__2::vector>::operator=\5babi:ne180100\5d\28std::__2::vector>\20const&\29 +4396:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4397:std::__2::vector>::__base_destruct_at_end\5babi:ne180100\5d\28skia::textlayout::FontFeature*\29 +4398:std::__2::vector\2c\20std::__2::allocator>>::vector\28std::__2::vector\2c\20std::__2::allocator>>\20const&\29 +4399:std::__2::vector>::insert\28std::__2::__wrap_iter\2c\20float&&\29 +4400:std::__2::vector>::__construct_at_end\28unsigned\20long\29 +4401:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4402:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4403:std::__2::vector>::vector\5babi:ne180100\5d\28std::initializer_list\29 +4404:std::__2::vector>::reserve\28unsigned\20long\29 +4405:std::__2::vector>::operator=\5babi:ne180100\5d\28std::__2::vector>\20const&\29 +4406:std::__2::vector>::__vdeallocate\28\29 +4407:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4408:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4409:std::__2::vector>::__base_destruct_at_end\5babi:ne180100\5d\28SkString*\29 +4410:std::__2::vector>::push_back\5babi:ne180100\5d\28SkSL::TraceInfo&&\29 +4411:std::__2::vector>::push_back\5babi:ne180100\5d\28SkSL::SymbolTable*\20const&\29 +4412:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +4413:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4414:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\2c\20SkSL::ProgramElement\20const**\29 +4415:std::__2::vector>::__move_range\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\29 +4416:std::__2::vector>::push_back\5babi:ne180100\5d\28SkRuntimeEffect::Uniform&&\29 +4417:std::__2::vector>::push_back\5babi:ne180100\5d\28SkRuntimeEffect::Child&&\29 +4418:std::__2::vector>::~vector\5babi:ne180100\5d\28\29 +4419:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4420:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4421:std::__2::vector>::reserve\28unsigned\20long\29 +4422:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4423:std::__2::vector\2c\20std::__2::allocator>>::__swap_out_circular_buffer\28std::__2::__split_buffer\2c\20std::__2::allocator>&>&\29 +4424:std::__2::vector>::push_back\5babi:ne180100\5d\28SkMeshSpecification::Varying&&\29 +4425:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4426:std::__2::vector>::reserve\28unsigned\20long\29 +4427:std::__2::vector>::__swap_out_circular_buffer\28std::__2::__split_buffer&>&\29 +4428:std::__2::vector>::__destroy_vector::operator\28\29\5babi:ne180100\5d\28\29 +4429:std::__2::vector>::__vallocate\5babi:ne180100\5d\28unsigned\20long\29 +4430:std::__2::vector>::__clear\5babi:ne180100\5d\28\29 +4431:std::__2::unique_ptr::unique_ptr\5babi:nn180100\5d\28unsigned\20char*\2c\20std::__2::__dependent_type\2c\20true>::__good_rval_ref_type\29 +4432:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4433:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::gpu::TextBlobRedrawCoordinator*\29 +4434:std::__2::unique_ptr::~unique_ptr\5babi:ne180100\5d\28\29 +4435:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4436:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::gpu::SubRunAllocator*\29 +4437:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4438:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::gpu::StrikeCache*\29 +4439:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4440:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28sktext::GlyphRunBuilder*\29 +4441:std::__2::unique_ptr\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4442:std::__2::unique_ptr\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4443:std::__2::unique_ptr\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4444:std::__2::unique_ptr>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4445:std::__2::unique_ptr\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4446:std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4447:std::__2::unique_ptr::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4448:std::__2::unique_ptr>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d\2c\20std::__2::default_delete>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4449:std::__2::unique_ptr\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4450:std::__2::unique_ptr\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot\20\5b\5d\2c\20std::__2::default_delete\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4451:std::__2::unique_ptr::AdaptedTraits>::Slot\20\5b\5d\2c\20std::__2::default_delete::AdaptedTraits>::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4452:std::__2::unique_ptr::Slot\20\5b\5d\2c\20std::__2::default_delete::Slot\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4453:std::__2::unique_ptr\2c\20std::__2::default_delete>>::reset\5babi:ne180100\5d\28skia_private::TArray*\29 +4454:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4455:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4456:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28skgpu::ganesh::SmallPathAtlasMgr*\29 +4457:std::__2::unique_ptr\20\5b\5d\2c\20std::__2::default_delete\20\5b\5d>>::~unique_ptr\5babi:ne180100\5d\28\29 +4458:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28hb_font_t*\29 +4459:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4460:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28hb_blob_t*\29 +4461:std::__2::unique_ptr::operator=\5babi:nn180100\5d\28std::__2::unique_ptr&&\29 +4462:std::__2::unique_ptr<\28anonymous\20namespace\29::SoftwarePathData\2c\20std::__2::default_delete<\28anonymous\20namespace\29::SoftwarePathData>>::reset\5babi:ne180100\5d\28\28anonymous\20namespace\29::SoftwarePathData*\29 +4463:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4464:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkTaskGroup*\29 +4465:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4466:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4467:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::RP::Program*\29 +4468:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4469:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::Program*\29 +4470:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::ProgramUsage*\29 +4471:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4472:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4473:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkSL::MemoryPool*\29 +4474:std::__2::unique_ptr>\20SkSL::coalesce_vector\28std::__2::array\20const&\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +4475:std::__2::unique_ptr>\20SkSL::coalesce_pairwise_vectors\28std::__2::array\20const&\2c\20double\2c\20SkSL::Type\20const&\2c\20double\20\28*\29\28double\2c\20double\2c\20double\29\2c\20double\20\28*\29\28double\29\29 +4476:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4477:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4478:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkRecorder*\29 +4479:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkLatticeIter*\29 +4480:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkCanvas::Layer*\29 +4481:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4482:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkCanvas::BackImage*\29 +4483:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4484:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28SkArenaAlloc*\29 +4485:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4486:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrThreadSafeCache*\29 +4487:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4488:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrResourceProvider*\29 +4489:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4490:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrResourceCache*\29 +4491:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4492:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrProxyProvider*\29 +4493:std::__2::unique_ptr>\20GrOp::Make\28GrRecordingContext*\2c\20skgpu::ganesh::AtlasTextOp::MaskType&&\2c\20bool&&\2c\20int&&\2c\20SkRect&\2c\20skgpu::ganesh::AtlasTextOp::Geometry*&\2c\20GrColorInfo\20const&\2c\20GrPaint&&\29 +4494:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4495:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4496:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4497:std::__2::unique_ptr>::~unique_ptr\5babi:ne180100\5d\28\29 +4498:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28GrAuditTrail::OpNode*\29 +4499:std::__2::unique_ptr>::reset\5babi:ne180100\5d\28FT_SizeRec_*\29 +4500:std::__2::tuple::tuple\5babi:nn180100\5d\28std::__2::locale::id::__get\28\29::$_0&&\29 +4501:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda0'\28\29::operator\28\29\28\29\20const +4502:std::__2::tuple\2c\20int\2c\20sktext::gpu::SubRunAllocator>\20sktext::gpu::SubRunAllocator::AllocateClassMemoryAndArena\28int\29::'lambda'\28\29::operator\28\29\28\29\20const +4503:std::__2::tuple&\20std::__2::tuple::operator=\5babi:ne180100\5d\28std::__2::pair&&\29 +4504:std::__2::to_string\28unsigned\20long\29 +4505:std::__2::to_chars_result\20std::__2::__to_chars_itoa\5babi:nn180100\5d\28char*\2c\20char*\2c\20unsigned\20int\2c\20std::__2::integral_constant\29 +4506:std::__2::time_put>>::~time_put\28\29_15238 +4507:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4508:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4509:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4510:std::__2::time_get>>::__get_year\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4511:std::__2::time_get>>::__get_weekdayname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4512:std::__2::time_get>>::__get_monthname\28int&\2c\20std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20unsigned\20int&\2c\20std::__2::ctype\20const&\29\20const +4513:std::__2::shared_ptr::operator=\5babi:ne180100\5d\28std::__2::shared_ptr&&\29 +4514:std::__2::reverse_iterator::operator++\5babi:nn180100\5d\28\29 +4515:std::__2::priority_queue>\2c\20GrAATriangulator::EventComparator>::push\28GrAATriangulator::Event*\20const&\29 +4516:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t*\29\20const +4517:std::__2::pair::pair\5babi:ne180100\5d\28std::__2::pair&&\29 +4518:std::__2::pair>::~pair\28\29 +4519:std::__2::pair\20std::__2::__unwrap_and_dispatch\5babi:ne180100\5d\2c\20std::__2::__copy_trivial>\2c\20skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\200>\28skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\2c\20skia::textlayout::FontFeature*\29 +4520:std::__2::pair\2c\20std::__2::allocator>>>::~pair\28\29 +4521:std::__2::pair\20std::__2::__copy_trivial::operator\28\29\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +4522:std::__2::pair::pair\5babi:nn180100\5d\28char\20const*&&\2c\20char*&&\29 +4523:std::__2::pair>::~pair\28\29 +4524:std::__2::pair\20std::__2::__unwrap_and_dispatch\5babi:ne180100\5d\2c\20std::__2::__copy_trivial>\2c\20SkString*\2c\20SkString*\2c\20SkString*\2c\200>\28SkString*\2c\20SkString*\2c\20SkString*\29 +4525:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28wchar_t\29 +4526:std::__2::ostreambuf_iterator>::operator=\5babi:nn180100\5d\28char\29 +4527:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +4528:std::__2::optional&\20std::__2::optional::operator=\5babi:ne180100\5d\28SkPath\20const&\29 +4529:std::__2::optional&\20std::__2::optional::operator=\5babi:ne180100\5d\28SkPaint\20const&\29 +4530:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +4531:std::__2::optional::value\5babi:ne180100\5d\28\29\20& +4532:std::__2::numpunct::~numpunct\28\29 +4533:std::__2::numpunct::~numpunct\28\29 +4534:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +4535:std::__2::num_get>>\20const&\20std::__2::use_facet\5babi:nn180100\5d>>>\28std::__2::locale\20const&\29 +4536:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20int&\29\20const +4537:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4538:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4539:std::__2::moneypunct::do_negative_sign\28\29\20const +4540:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4541:std::__2::moneypunct\20const&\20std::__2::use_facet\5babi:nn180100\5d>\28std::__2::locale\20const&\29 +4542:std::__2::moneypunct::do_negative_sign\28\29\20const +4543:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20wchar_t*&\2c\20wchar_t*\29 +4544:std::__2::money_get>>::__do_get\28std::__2::istreambuf_iterator>&\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::locale\20const&\2c\20unsigned\20int\2c\20unsigned\20int&\2c\20bool&\2c\20std::__2::ctype\20const&\2c\20std::__2::unique_ptr&\2c\20char*&\2c\20char*\29 +4545:std::__2::locale::operator=\28std::__2::locale\20const&\29 +4546:std::__2::locale::facet**\20std::__2::__construct_at\5babi:nn180100\5d\28std::__2::locale::facet**\29 +4547:std::__2::locale::__imp::~__imp\28\29 +4548:std::__2::locale::__imp::release\28\29 +4549:std::__2::list>::pop_front\28\29 +4550:std::__2::iterator_traits\2c\20std::__2::allocator>\20const*>::difference_type\20std::__2::distance\5babi:nn180100\5d\2c\20std::__2::allocator>\20const*>\28std::__2::basic_string\2c\20std::__2::allocator>\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const*\29 +4551:std::__2::iterator_traits::difference_type\20std::__2::distance\5babi:nn180100\5d\28char*\2c\20char*\29 +4552:std::__2::iterator_traits::difference_type\20std::__2::__distance\5babi:nn180100\5d\28char*\2c\20char*\2c\20std::__2::random_access_iterator_tag\29 +4553:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +4554:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +4555:std::__2::istreambuf_iterator>::operator++\5babi:nn180100\5d\28int\29 +4556:std::__2::istreambuf_iterator>::__test_for_eof\5babi:nn180100\5d\28\29\20const +4557:std::__2::ios_base::width\5babi:nn180100\5d\28long\29 +4558:std::__2::ios_base::__call_callbacks\28std::__2::ios_base::event\29 +4559:std::__2::hash>::operator\28\29\5babi:ne180100\5d\28std::__2::optional\20const&\29\20const +4560:std::__2::function::operator\28\29\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29\20const +4561:std::__2::function::operator\28\29\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29\20const +4562:std::__2::function::operator\28\29\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29\20const +4563:std::__2::enable_if::type\20skgpu::tess::PatchWriter\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\294>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\298>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2964>\2c\20skgpu::tess::Optional<\28skgpu::tess::PatchAttribs\2932>\2c\20skgpu::tess::ReplicateLineEndPoints\2c\20skgpu::tess::TrackJoinControlPoints>::writeDeferredStrokePatch\28\29 +4564:std::__2::enable_if>::value\2c\20SkRuntimeEffectBuilder::BuilderUniform&>::type\20SkRuntimeEffectBuilder::BuilderUniform::operator=>\28std::__2::array\20const&\29 +4565:std::__2::enable_if::value\2c\20SkRuntimeEffectBuilder::BuilderUniform&>::type\20SkRuntimeEffectBuilder::BuilderUniform::operator=\28float\20const&\29 +4566:std::__2::enable_if>::value\20&&\20sizeof\20\28skia::textlayout::SkRange\29\20!=\204\2c\20unsigned\20int>::type\20SkGoodHash::operator\28\29>\28skia::textlayout::SkRange\20const&\29\20const +4567:std::__2::enable_if::value\20&&\20sizeof\20\28bool\29\20!=\204\2c\20unsigned\20int>::type\20SkGoodHash::operator\28\29\28bool\20const&\29\20const +4568:std::__2::enable_if::value\20&&\20is_move_assignable::value\2c\20void>::type\20std::__2::swap\5babi:nn180100\5d\28char&\2c\20char&\29 +4569:std::__2::deque>::back\28\29 +4570:std::__2::deque>::__add_back_capacity\28\29 +4571:std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::_EnableIfConvertible::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot>::type\20std::__2::default_delete::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot>\28skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot*\29\20const +4572:std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot>::type\20std::__2::default_delete>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot>\28skia_private::THashTable>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair\2c\20std::__2::basic_string_view>\2c\20skia_private::THashMap>\2c\20SkSL::IntrinsicKind\2c\20SkGoodHash>::Pair>::Slot*\29\20const +4573:std::__2::default_delete\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot>::type\20std::__2::default_delete\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot>\28skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot*\29\20const +4574:std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot>::type\20std::__2::default_delete\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot>\28skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot*\29\20const +4575:std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>::_EnableIfConvertible>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot>::type\20std::__2::default_delete>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot>\28skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Slot*\29\20const +4576:std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::_EnableIfConvertible::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot>::type\20std::__2::default_delete::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot\20\5b\5d>::operator\28\29\5babi:ne180100\5d::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot>\28skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot*\29\20const +4577:std::__2::default_delete\20\5b\5d>::_EnableIfConvertible>::type\20std::__2::default_delete\20\5b\5d>::operator\28\29\5babi:ne180100\5d>\28sk_sp*\29\20const +4578:std::__2::default_delete::_EnableIfConvertible::type\20std::__2::default_delete::operator\28\29\5babi:ne180100\5d\28GrGLCaps::ColorTypeInfo*\29\20const +4579:std::__2::ctype::~ctype\28\29 +4580:std::__2::codecvt::~codecvt\28\29 +4581:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +4582:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char32_t\20const*\2c\20char32_t\20const*\2c\20char32_t\20const*&\2c\20char8_t*\2c\20char8_t*\2c\20char8_t*&\29\20const +4583:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20unsigned\20long\29\20const +4584:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20char8_t\20const*&\2c\20char32_t*\2c\20char32_t*\2c\20char32_t*&\29\20const +4585:std::__2::codecvt::do_out\28__mbstate_t&\2c\20char16_t\20const*\2c\20char16_t\20const*\2c\20char16_t\20const*&\2c\20char8_t*\2c\20char8_t*\2c\20char8_t*&\29\20const +4586:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20unsigned\20long\29\20const +4587:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char8_t\20const*\2c\20char8_t\20const*\2c\20char8_t\20const*&\2c\20char16_t*\2c\20char16_t*\2c\20char16_t*&\29\20const +4588:std::__2::char_traits::eq_int_type\5babi:nn180100\5d\28int\2c\20int\29 +4589:std::__2::char_traits::not_eof\5babi:nn180100\5d\28int\29 +4590:std::__2::char_traits::find\5babi:ne180100\5d\28char\20const*\2c\20unsigned\20long\2c\20char\20const&\29 +4591:std::__2::basic_stringstream\2c\20std::__2::allocator>::basic_stringstream\5babi:ne180100\5d\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\29 +4592:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +4593:std::__2::basic_stringbuf\2c\20std::__2::allocator>::str\28\29\20const +4594:std::__2::basic_string_view>::substr\5babi:ne180100\5d\28unsigned\20long\2c\20unsigned\20long\29\20const +4595:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20wchar_t\29 +4596:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28wchar_t\20const*\2c\20wchar_t\20const*\29 +4597:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_without_replace\5babi:nn180100\5d\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29 +4598:std::__2::basic_string\2c\20std::__2::allocator>::__grow_by_and_replace\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20wchar_t\20const*\29 +4599:std::__2::basic_string\2c\20std::__2::allocator>::resize\28unsigned\20long\2c\20char\29 +4600:std::__2::basic_string\2c\20std::__2::allocator>::insert\28unsigned\20long\2c\20char\20const*\2c\20unsigned\20long\29 +4601:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:nn180100\5d\28unsigned\20long\2c\20char\29 +4602:std::__2::basic_string\2c\20std::__2::allocator>::basic_string\5babi:ne180100\5d\28std::__2::__uninitialized_size_tag\2c\20unsigned\20long\2c\20std::__2::allocator\20const&\29 +4603:std::__2::basic_string\2c\20std::__2::allocator>::__null_terminate_at\5babi:nn180100\5d\28char*\2c\20unsigned\20long\29 +4604:std::__2::basic_string\2c\20std::__2::allocator>&\20std::__2::basic_string\2c\20std::__2::allocator>::operator+=>\2c\200>\28std::__2::basic_string_view>\20const&\29 +4605:std::__2::basic_string\2c\20std::__2::allocator>&\20skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::emplace_back\28char\20const*&&\29 +4606:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +4607:std::__2::basic_streambuf>::sputc\5babi:nn180100\5d\28char\29 +4608:std::__2::basic_streambuf>::sgetc\5babi:nn180100\5d\28\29 +4609:std::__2::basic_streambuf>::sbumpc\5babi:nn180100\5d\28\29 +4610:std::__2::basic_streambuf>::basic_streambuf\28\29 +4611:std::__2::basic_ostream>::sentry::~sentry\28\29 +4612:std::__2::basic_ostream>::sentry::sentry\28std::__2::basic_ostream>&\29 +4613:std::__2::basic_ostream>::operator<<\28float\29 +4614:std::__2::basic_ostream>::flush\28\29 +4615:std::__2::basic_istream>::~basic_istream\28\29_14322 +4616:std::__2::basic_iostream>::basic_iostream\5babi:ne180100\5d\28std::__2::basic_streambuf>*\29 +4617:std::__2::basic_ios>::imbue\5babi:ne180100\5d\28std::__2::locale\20const&\29 +4618:std::__2::allocator_traits>::deallocate\5babi:nn180100\5d\28std::__2::__sso_allocator&\2c\20std::__2::locale::facet**\2c\20unsigned\20long\29 +4619:std::__2::allocator::allocate\5babi:nn180100\5d\28unsigned\20long\29 +4620:std::__2::allocator::allocate\5babi:ne180100\5d\28unsigned\20long\29 +4621:std::__2::__wrap_iter\20std::__2::vector>::insert\2c\200>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\29 +4622:std::__2::__unwrap_iter_impl::__rewrap\5babi:nn180100\5d\28char*\2c\20char*\29 +4623:std::__2::__unique_if\2c\20std::__2::allocator>>::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>>\28std::__2::basic_string\2c\20std::__2::allocator>&&\29 +4624:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>>\28SkSL::Position&\2c\20std::__2::unique_ptr>&&\2c\20std::__2::unique_ptr>&&\2c\20std::__2::unique_ptr>&&\29 +4625:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28\29 +4626:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28\29 +4627:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +4628:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4629:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4630:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4631:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4632:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4633:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +4634:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>>\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>&&\29 +4635:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d\28SkSL::Position&\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray&&\29 +4636:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>\2c\20true>\2c\20SkSL::Block::Kind&\2c\20std::__2::unique_ptr>>\28SkSL::Position&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&&\2c\20SkSL::Block::Kind&\2c\20std::__2::unique_ptr>&&\29 +4637:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d>\28sk_sp&&\29 +4638:std::__2::__unique_if::__unique_single\20std::__2::make_unique\5babi:ne180100\5d&>\28std::__2::shared_ptr&\29 +4639:std::__2::__tuple_impl\2c\20std::__2::locale::id::__get\28\29::$_0&&>::__tuple_impl\5babi:nn180100\5d<0ul\2c\20std::__2::locale::id::__get\28\29::$_0&&\2c\20std::__2::locale::id::__get\28\29::$_0>\28std::__2::__tuple_indices<0ul>\2c\20std::__2::__tuple_types\2c\20std::__2::__tuple_indices<...>\2c\20std::__2::__tuple_types<>\2c\20std::__2::locale::id::__get\28\29::$_0&&\29 +4640:std::__2::__time_put::__time_put\5babi:nn180100\5d\28\29 +4641:std::__2::__time_put::__do_put\28char*\2c\20char*&\2c\20tm\20const*\2c\20char\2c\20char\29\20const +4642:std::__2::__throw_length_error\5babi:ne180100\5d\28char\20const*\29 +4643:std::__2::__split_buffer&>::~__split_buffer\28\29 +4644:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +4645:std::__2::__split_buffer>::pop_back\5babi:ne180100\5d\28\29 +4646:std::__2::__split_buffer&>::push_back\28skia::textlayout::OneLineShaper::RunBlock*&&\29 +4647:std::__2::__split_buffer&>::~__split_buffer\28\29 +4648:std::__2::__split_buffer&>::~__split_buffer\28\29 +4649:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +4650:std::__2::__split_buffer&>::~__split_buffer\28\29 +4651:std::__2::__split_buffer&>::__split_buffer\28unsigned\20long\2c\20unsigned\20long\2c\20std::__2::allocator&\29 +4652:std::__2::__split_buffer&>::~__split_buffer\28\29 +4653:std::__2::__shared_weak_count::__release_shared\5babi:ne180100\5d\28\29 +4654:std::__2::__shared_count::__add_shared\5babi:nn180100\5d\28\29 +4655:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +4656:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +4657:std::__2::__optional_destruct_base::reset\5babi:ne180100\5d\28\29 +4658:std::__2::__optional_destruct_base::~__optional_destruct_base\5babi:ne180100\5d\28\29 +4659:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +4660:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20std::__2::locale\20const&\29 +4661:std::__2::__num_put::__widen_and_group_int\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +4662:std::__2::__num_put::__widen_and_group_float\28char*\2c\20char*\2c\20char*\2c\20char*\2c\20char*&\2c\20char*&\2c\20std::__2::locale\20const&\29 +4663:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20wchar_t&\2c\20wchar_t&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +4664:std::__2::__money_put::__format\28wchar_t*\2c\20wchar_t*&\2c\20wchar_t*&\2c\20unsigned\20int\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20wchar_t\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +4665:std::__2::__money_put::__gather_info\28bool\2c\20bool\2c\20std::__2::locale\20const&\2c\20std::__2::money_base::pattern&\2c\20char&\2c\20char&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\2c\20int&\29 +4666:std::__2::__money_put::__format\28char*\2c\20char*&\2c\20char*&\2c\20unsigned\20int\2c\20char\20const*\2c\20char\20const*\2c\20std::__2::ctype\20const&\2c\20bool\2c\20std::__2::money_base::pattern\20const&\2c\20char\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20int\29 +4667:std::__2::__libcpp_sscanf_l\28char\20const*\2c\20__locale_struct*\2c\20char\20const*\2c\20...\29 +4668:std::__2::__libcpp_mbrtowc_l\5babi:nn180100\5d\28wchar_t*\2c\20char\20const*\2c\20unsigned\20long\2c\20__mbstate_t*\2c\20__locale_struct*\29 +4669:std::__2::__libcpp_mb_cur_max_l\5babi:nn180100\5d\28__locale_struct*\29 +4670:std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__deallocate_node\28std::__2::__hash_node_base\2c\20void*>*>*\29 +4671:std::__2::__hash_table\2c\20std::__2::__unordered_map_hasher\2c\20std::__2::hash\2c\20std::__2::equal_to\2c\20true>\2c\20std::__2::__unordered_map_equal\2c\20std::__2::equal_to\2c\20std::__2::hash\2c\20true>\2c\20std::__2::allocator>>::__deallocate_node\28std::__2::__hash_node_base\2c\20void*>*>*\29 +4672:std::__2::__hash_table\2c\20std::__2::equal_to\2c\20std::__2::allocator>::__deallocate_node\28std::__2::__hash_node_base*>*\29 +4673:std::__2::__function::__value_func\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::operator\28\29\5babi:ne180100\5d\28skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20float&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20SkPoint&&\2c\20SkPoint&&\2c\20skia::textlayout::InternalLineMetrics&&\2c\20bool&&\29\20const +4674:std::__2::__function::__value_func\29>::operator\28\29\5babi:ne180100\5d\28skia::textlayout::Block&&\2c\20skia_private::TArray&&\29\20const +4675:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29 +4676:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +4677:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +4678:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29 +4679:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +4680:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +4681:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29 +4682:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +4683:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +4684:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::destroy_deallocate\28\29 +4685:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::destroy\28\29 +4686:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29 +4687:std::__2::__forward_list_base\2c\20std::__2::allocator>>::clear\28\29 +4688:std::__2::__exception_guard_exceptions>::__destroy_vector>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +4689:std::__2::__exception_guard_exceptions>::__destroy_vector>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +4690:std::__2::__exception_guard_exceptions\2c\20SkString*>>::~__exception_guard_exceptions\5babi:ne180100\5d\28\29 +4691:std::__2::__constexpr_wcslen\5babi:nn180100\5d\28wchar_t\20const*\29 +4692:std::__2::__compressed_pair_elem\29::$_0\2c\200\2c\20false>::__compressed_pair_elem\5babi:ne180100\5d\29::$_0\20const&\2c\200ul>\28std::__2::piecewise_construct_t\2c\20std::__2::tuple\29::$_0\20const&>\2c\20std::__2::__tuple_indices<0ul>\29 +4693:std::__2::__compressed_pair_elem::__compressed_pair_elem\5babi:ne180100\5d\28std::__2::piecewise_construct_t\2c\20std::__2::tuple\2c\20std::__2::__tuple_indices<0ul>\29 +4694:std::__2::__compressed_pair::__compressed_pair\5babi:nn180100\5d\28unsigned\20char*&\2c\20void\20\28*&&\29\28void*\29\29 +4695:std::__2::__allocation_result>::pointer>\20std::__2::__allocate_at_least\5babi:nn180100\5d>\28std::__2::__sso_allocator&\2c\20unsigned\20long\29 +4696:srgb_to_hsl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +4697:sort_r_swap_blocks\28char*\2c\20unsigned\20long\2c\20unsigned\20long\29 +4698:sort_increasing_Y\28SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +4699:sort_edges\28SkEdge**\2c\20int\2c\20SkEdge**\29 +4700:sort_as_rect\28skvx::Vec<4\2c\20float>\20const&\29 +4701:small_blur\28double\2c\20double\2c\20SkMask\20const&\2c\20SkMaskBuilder*\29::$_0::operator\28\29\28SkGaussFilter\20const&\2c\20unsigned\20short*\29\20const +4702:skvx::Vec<8\2c\20unsigned\20short>\20skvx::operator&<8\2c\20unsigned\20short>\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +4703:skvx::Vec<8\2c\20unsigned\20int>\20skvx::cast\28skvx::Vec<8\2c\20unsigned\20short>\20const&\29 +4704:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator>><4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20int\29 +4705:skvx::Vec<4\2c\20unsigned\20short>\20skvx::operator<<<4\2c\20unsigned\20short>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\2c\20int\29 +4706:skvx::Vec<4\2c\20unsigned\20int>\20skvx::operator>><4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20int\29 +4707:skvx::Vec<4\2c\20unsigned\20int>\20skvx::operator*<4\2c\20unsigned\20int>\28skvx::Vec<4\2c\20unsigned\20int>\20const&\2c\20skvx::Vec<4\2c\20unsigned\20int>\20const&\29 +4708:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator!=<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +4709:skvx::Vec<4\2c\20skvx::Mask::type>\20skvx::operator!=<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4710:skvx::Vec<4\2c\20int>\20skvx::operator^<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +4711:skvx::Vec<4\2c\20int>\20skvx::operator>><4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20int\29 +4712:skvx::Vec<4\2c\20int>\20skvx::operator<<<4\2c\20int>\28skvx::Vec<4\2c\20int>\20const&\2c\20int\29 +4713:skvx::Vec<4\2c\20float>\20skvx::sqrt<4>\28skvx::Vec<4\2c\20float>\20const&\29 +4714:skvx::Vec<4\2c\20float>\20skvx::operator/<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +4715:skvx::Vec<4\2c\20float>\20skvx::operator/<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4716:skvx::Vec<4\2c\20float>\20skvx::operator-<4\2c\20float\2c\20float\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20float\29 +4717:skvx::Vec<4\2c\20float>\20skvx::operator-<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4718:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20int\2c\20void>\28skvx::Vec<4\2c\20float>\20const&\2c\20int\29 +4719:skvx::Vec<4\2c\20float>\20skvx::operator*<4\2c\20float\2c\20int\2c\20void>\28int\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4720:skvx::Vec<4\2c\20float>\20skvx::min<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4721:skvx::Vec<4\2c\20float>\20skvx::min<4\2c\20float>\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.5845\29 +4722:skvx::Vec<4\2c\20float>\20skvx::max<4\2c\20float\2c\20float\2c\20void>\28float\2c\20skvx::Vec<4\2c\20float>\20const&\29 +4723:skvx::Vec<4\2c\20float>\20skvx::from_half<4>\28skvx::Vec<4\2c\20unsigned\20short>\20const&\29 +4724:skvx::Vec<4\2c\20float>&\20skvx::operator*=<4\2c\20float>\28skvx::Vec<4\2c\20float>&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20\28.6751\29 +4725:skvx::Vec<2\2c\20unsigned\20char>\20skvx::cast\28skvx::Vec<2\2c\20float>\20const&\29 +4726:skvx::ScaledDividerU32::divide\28skvx::Vec<4\2c\20unsigned\20int>\20const&\29\20const +4727:skvx::ScaledDividerU32::ScaledDividerU32\28unsigned\20int\29 +4728:sktext::gpu::can_use_direct\28SkMatrix\20const&\2c\20SkMatrix\20const&\29 +4729:sktext::gpu::build_distance_adjust_table\28float\29 +4730:sktext::gpu::VertexFiller::fillVertexData\28int\2c\20int\2c\20SkSpan\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkIRect\2c\20void*\29\20const +4731:sktext::gpu::TextBlobRedrawCoordinator::internalRemove\28sktext::gpu::TextBlob*\29 +4732:sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry::findBlobIndex\28sktext::gpu::TextBlob::Key\20const&\29\20const +4733:sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry::BlobIDCacheEntry\28sktext::gpu::TextBlobRedrawCoordinator::BlobIDCacheEntry&&\29 +4734:sktext::gpu::TextBlob::~TextBlob\28\29 +4735:sktext::gpu::SubRunControl::isSDFT\28float\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +4736:sktext::gpu::SubRunContainer::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20SkRefCnt\20const*\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +4737:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_2::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +4738:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29::$_0::operator\28\29\28SkZip\2c\20skgpu::MaskFormat\29\20const +4739:sktext::gpu::SubRunContainer::MakeInAlloc\28sktext::GlyphRunList\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkStrikeDeviceInfo\2c\20sktext::StrikeForGPUCacheInterface*\2c\20sktext::gpu::SubRunAllocator*\2c\20sktext::gpu::SubRunContainer::SubRunCreationBehavior\2c\20char\20const*\29 +4740:sktext::gpu::SubRunContainer::EstimateAllocSize\28sktext::GlyphRunList\20const&\29 +4741:sktext::gpu::SubRunAllocator::SubRunAllocator\28int\29 +4742:sktext::gpu::StrikeCache::internalPurge\28unsigned\20long\29 +4743:sktext::gpu::StrikeCache::freeAll\28\29 +4744:sktext::gpu::SlugImpl::~SlugImpl\28\29 +4745:sktext::SkStrikePromise::resetStrike\28\29 +4746:sktext::GlyphRunList::maxGlyphRunSize\28\29\20const +4747:sktext::GlyphRunBuilder::~GlyphRunBuilder\28\29 +4748:sktext::GlyphRunBuilder::makeGlyphRunList\28sktext::GlyphRun\20const&\2c\20SkPaint\20const&\2c\20SkPoint\29 +4749:sktext::GlyphRunBuilder::blobToGlyphRunList\28SkTextBlob\20const&\2c\20SkPoint\29 +4750:skstd::to_string\28float\29 +4751:skip_string +4752:skip_procedure +4753:skip_comment +4754:skif::compatible_sampling\28SkSamplingOptions\20const&\2c\20bool\2c\20SkSamplingOptions*\2c\20bool\29 +4755:skif::\28anonymous\20namespace\29::decompose_transform\28SkMatrix\20const&\2c\20SkPoint\2c\20SkMatrix*\2c\20SkMatrix*\29 +4756:skif::\28anonymous\20namespace\29::are_axes_nearly_integer_aligned\28skif::LayerSpace\20const&\2c\20skif::LayerSpace*\29 +4757:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +4758:skif::RoundIn\28SkRect\29 +4759:skif::Mapping::adjustLayerSpace\28SkMatrix\20const&\29 +4760:skif::LayerSpace::inset\28skif::LayerSpace\20const&\29 +4761:skif::LayerSpace::RectToRect\28skif::LayerSpace\20const&\2c\20skif::LayerSpace\20const&\29 +4762:skif::FilterResult::imageAndOffset\28skif::Context\20const&\29\20const +4763:skif::FilterResult::draw\28skif::Context\20const&\2c\20SkDevice*\2c\20SkBlender\20const*\29\20const +4764:skif::FilterResult::Builder::drawShader\28sk_sp\2c\20skif::LayerSpace\20const&\2c\20bool\29\20const +4765:skif::FilterResult::Builder::createInputShaders\28skif::LayerSpace\20const&\2c\20bool\29 +4766:skif::Context::Context\28sk_sp\2c\20skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20skif::FilterResult\20const&\2c\20SkColorSpace\20const*\2c\20skif::Stats*\29 +4767:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::uncheckedSet\28std::__2::basic_string_view>&&\29 +4768:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::set\28std::__2::basic_string_view>\29 +4769:skia_private::THashTable>\2c\20std::__2::basic_string_view>\2c\20skia_private::THashSet>\2c\20SkGoodHash>::Traits>::resize\28int\29 +4770:skia_private::THashTable::uncheckedSet\28sktext::gpu::Glyph*&&\29 +4771:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4772:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4773:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::removeIfExists\28unsigned\20int\20const&\29 +4774:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::Slot::emplace\28skia_private::THashMap::Pair&&\2c\20unsigned\20int\29 +4775:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4776:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::reset\28\29 +4777:skia_private::THashTable::Pair\2c\20unsigned\20int\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4778:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair&&\29 +4779:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot::reset\28\29 +4780:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair&&\2c\20unsigned\20int\29 +4781:skia_private::THashTable\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair\2c\20skia::textlayout::OneLineShaper::FontKey\2c\20skia_private::THashMap\2c\20skia::textlayout::OneLineShaper::FontKey::Hasher>::Pair>::Hash\28skia::textlayout::OneLineShaper::FontKey\20const&\29 +4782:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair&&\29 +4783:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot::reset\28\29 +4784:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair&&\2c\20unsigned\20int\29 +4785:skia_private::THashTable\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair\2c\20skia::textlayout::FontCollection::FamilyKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>>\2c\20skia::textlayout::FontCollection::FamilyKey::Hasher>::Pair>::Hash\28skia::textlayout::FontCollection::FamilyKey\20const&\29 +4786:skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::uncheckedSet\28skia_private::THashMap>::Pair&&\29 +4787:skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::reset\28\29 +4788:skia_private::THashTable>::Pair\2c\20skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\2c\20skia_private::THashMap>::Pair>::Hash\28skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\20const&\29 +4789:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4790:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot::reset\28\29 +4791:skia_private::THashTable::Pair\2c\20skgpu::UniqueKey\2c\20skia_private::THashMap::Pair>::Slot::emplace\28skia_private::THashMap::Pair&&\2c\20unsigned\20int\29 +4792:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\29 +4793:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4794:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20int\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4795:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\29 +4796:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4797:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4798:skia_private::THashTable\2c\20SkGoodHash>::Pair\2c\20SkString\2c\20skia_private::THashMap\2c\20SkGoodHash>::Pair>::Hash\28SkString\20const&\29 +4799:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4800:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4801:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4802:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4803:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4804:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4805:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4806:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::firstPopulatedSlot\28\29\20const +4807:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::Iter>::operator++\28\29 +4808:skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>::THashTable\28skia_private::THashTable::Pair\2c\20SkSL::Variable\20const*\2c\20skia_private::THashMap::Pair>\20const&\29 +4809:skia_private::THashTable::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4810:skia_private::THashTable::Pair\2c\20SkSL::SymbolTable::SymbolKey\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4811:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4812:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::set\28skia_private::THashMap::Pair\29 +4813:skia_private::THashTable::Pair\2c\20SkSL::IRNode\20const*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4814:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair&&\29 +4815:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot::reset\28\29 +4816:skia_private::THashTable\2c\20false>\2c\20SkGoodHash>::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4817:skia_private::THashTable::Pair\2c\20SkSL::FunctionDeclaration\20const*\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4818:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::uncheckedSet\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair&&\29 +4819:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot::reset\28\29 +4820:skia_private::THashTable\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair\2c\20SkSL::Analysis::SpecializedFunctionKey\2c\20skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair>::Slot::emplace\28skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkSL::Analysis::SpecializedFunctionKey::Hash>::Pair&&\2c\20unsigned\20int\29 +4821:skia_private::THashTable::Pair\2c\20SkSL::Analysis::SpecializedCallKey\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4822:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::uncheckedSet\28skia_private::THashMap::Pair&&\29 +4823:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot::reset\28\29 +4824:skia_private::THashTable::Pair\2c\20SkPath\2c\20skia_private::THashMap::Pair>::Slot::emplace\28skia_private::THashMap::Pair&&\2c\20unsigned\20int\29 +4825:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::uncheckedSet\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4826:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::resize\28int\29 +4827:skia_private::THashTable>\2c\20SkGoodHash>::Pair\2c\20SkImageFilter\20const*\2c\20skia_private::THashMap>\2c\20SkGoodHash>::Pair>::Slot::emplace\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\2c\20unsigned\20int\29 +4828:skia_private::THashTable::Pair\2c\20GrSurfaceProxy*\2c\20skia_private::THashMap::Pair>::resize\28int\29 +4829:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28skgpu::ganesh::SmallPathShapeData*&&\29 +4830:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4831:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +4832:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::uncheckedSet\28sk_sp&&\29 +4833:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::resize\28int\29 +4834:skia_private::THashTable\2c\20SkDescriptor\20const&\2c\20sktext::gpu::StrikeCache::HashTraits>::Slot::emplace\28sk_sp&&\2c\20unsigned\20int\29 +4835:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::uncheckedSet\28sk_sp&&\29 +4836:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::resize\28int\29 +4837:skia_private::THashTable\2c\20SkDescriptor\2c\20SkStrikeCache::StrikeTraits>::Slot::emplace\28sk_sp&&\2c\20unsigned\20int\29 +4838:skia_private::THashTable::Traits>::set\28int\29 +4839:skia_private::THashTable::Traits>::THashTable\28skia_private::THashTable::Traits>&&\29 +4840:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::uncheckedSet\28\28anonymous\20namespace\29::CacheImpl::Value*&&\29 +4841:skia_private::THashTable<\28anonymous\20namespace\29::CacheImpl::Value*\2c\20SkImageFilterCacheKey\2c\20SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::AdaptedTraits>::resize\28int\29 +4842:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +4843:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +4844:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::findOrNull\28skgpu::ScratchKey\20const&\29\20const +4845:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::uncheckedSet\28SkTMultiMap::ValueList*&&\29 +4846:skia_private::THashTable::ValueList*\2c\20skgpu::ScratchKey\2c\20SkTDynamicHash::ValueList\2c\20skgpu::ScratchKey\2c\20SkTMultiMap::ValueList>::AdaptedTraits>::resize\28int\29 +4847:skia_private::THashTable::Traits>::uncheckedSet\28SkSL::Variable\20const*&&\29 +4848:skia_private::THashTable::Traits>::resize\28int\29 +4849:skia_private::THashTable::Traits>::uncheckedSet\28SkSL::FunctionDeclaration\20const*&&\29 +4850:skia_private::THashTable::uncheckedSet\28SkResourceCache::Rec*&&\29 +4851:skia_private::THashTable::resize\28int\29 +4852:skia_private::THashTable::find\28SkResourceCache::Key\20const&\29\20const +4853:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::uncheckedSet\28SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*&&\29 +4854:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +4855:skia_private::THashTable>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\2c\20skia::textlayout::ParagraphCacheKey\2c\20SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Traits>::find\28skia::textlayout::ParagraphCacheKey\20const&\29\20const +4856:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::uncheckedSet\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*&&\29 +4857:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::resize\28int\29 +4858:skia_private::THashTable>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\2c\20GrProgramDesc\2c\20SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Traits>::find\28GrProgramDesc\20const&\29\20const +4859:skia_private::THashTable::uncheckedSet\28SkGlyphDigest&&\29 +4860:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrThreadSafeCache::Entry*&&\29 +4861:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4862:skia_private::THashTable::AdaptedTraits>::removeIfExists\28skgpu::UniqueKey\20const&\29 +4863:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrTextureProxy*&&\29 +4864:skia_private::THashTable::AdaptedTraits>::set\28GrTextureProxy*\29 +4865:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4866:skia_private::THashTable::AdaptedTraits>::findOrNull\28skgpu::UniqueKey\20const&\29\20const +4867:skia_private::THashTable::AdaptedTraits>::uncheckedSet\28GrGpuResource*&&\29 +4868:skia_private::THashTable::AdaptedTraits>::resize\28int\29 +4869:skia_private::THashTable::AdaptedTraits>::findOrNull\28skgpu::UniqueKey\20const&\29\20const +4870:skia_private::THashTable::Traits>::uncheckedSet\28FT_Opaque_Paint_&&\29 +4871:skia_private::THashTable::Traits>::resize\28int\29 +4872:skia_private::THashSet::contains\28int\20const&\29\20const +4873:skia_private::THashSet::contains\28FT_Opaque_Paint_\20const&\29\20const +4874:skia_private::THashSet::add\28FT_Opaque_Paint_\29 +4875:skia_private::THashMap::find\28unsigned\20int\20const&\29\20const +4876:skia_private::THashMap\2c\20SkGoodHash>::find\28int\20const&\29\20const +4877:skia_private::THashMap\2c\20std::__2::allocator>\2c\20SkGoodHash>::set\28SkSL::Variable\20const*\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +4878:skia_private::THashMap::operator\5b\5d\28SkSL::Variable\20const*\20const&\29 +4879:skia_private::THashMap::operator\5b\5d\28SkSL::Symbol\20const*\20const&\29 +4880:skia_private::THashMap\2c\20false>\2c\20SkGoodHash>::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +4881:skia_private::THashMap::set\28SkSL::FunctionDeclaration\20const*\2c\20int\29 +4882:skia_private::THashMap::operator\5b\5d\28SkSL::FunctionDeclaration\20const*\20const&\29 +4883:skia_private::THashMap::operator\5b\5d\28SkSL::Analysis::SpecializedCallKey\20const&\29 +4884:skia_private::THashMap::find\28SkSL::Analysis::SpecializedCallKey\20const&\29\20const +4885:skia_private::THashMap>\2c\20SkGoodHash>::remove\28SkImageFilter\20const*\20const&\29 +4886:skia_private::THashMap>\2c\20SkGoodHash>::Pair::Pair\28skia_private::THashMap>\2c\20SkGoodHash>::Pair&&\29 +4887:skia_private::THashMap::find\28GrSurfaceProxy*\20const&\29\20const +4888:skia_private::TArray::push_back_raw\28int\29 +4889:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4890:skia_private::TArray::push_back\28unsigned\20int\20const&\29 +4891:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +4892:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4893:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +4894:skia_private::TArray::initData\28int\29 +4895:skia_private::TArray::Allocate\28int\2c\20double\29 +4896:skia_private::TArray>\2c\20true>::~TArray\28\29 +4897:skia_private::TArray>\2c\20true>::clear\28\29 +4898:skia_private::TArray>\2c\20true>::operator=\28skia_private::TArray>\2c\20true>&&\29 +4899:skia_private::TArray>\2c\20true>::~TArray\28\29 +4900:skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +4901:skia_private::TArray\2c\20std::__2::allocator>\2c\20false>::checkRealloc\28int\2c\20double\29 +4902:skia_private::TArray\2c\20true>::preallocateNewData\28int\2c\20double\29 +4903:skia_private::TArray\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +4904:skia_private::TArray\2c\20false>::move\28void*\29 +4905:skia_private::TArray\2c\20false>::TArray\28skia_private::TArray\2c\20false>&&\29 +4906:skia_private::TArray\2c\20false>::Allocate\28int\2c\20double\29 +4907:skia_private::TArray::destroyAll\28\29 +4908:skia_private::TArray::destroyAll\28\29 +4909:skia_private::TArray\2c\20false>::~TArray\28\29 +4910:skia_private::TArray::~TArray\28\29 +4911:skia_private::TArray::destroyAll\28\29 +4912:skia_private::TArray::copy\28skia::textlayout::Run\20const*\29 +4913:skia_private::TArray::Allocate\28int\2c\20double\29 +4914:skia_private::TArray::destroyAll\28\29 +4915:skia_private::TArray::initData\28int\29 +4916:skia_private::TArray::destroyAll\28\29 +4917:skia_private::TArray::TArray\28skia_private::TArray&&\29 +4918:skia_private::TArray::Allocate\28int\2c\20double\29 +4919:skia_private::TArray::copy\28skia::textlayout::Cluster\20const*\29 +4920:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4921:skia_private::TArray::Allocate\28int\2c\20double\29 +4922:skia_private::TArray::initData\28int\29 +4923:skia_private::TArray::destroyAll\28\29 +4924:skia_private::TArray::TArray\28skia_private::TArray&&\29 +4925:skia_private::TArray::Allocate\28int\2c\20double\29 +4926:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4927:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4928:skia_private::TArray::push_back\28\29 +4929:skia_private::TArray::push_back\28\29 +4930:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4931:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4932:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4933:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4934:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4935:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4936:skia_private::TArray::destroyAll\28\29 +4937:skia_private::TArray::clear\28\29 +4938:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4939:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4940:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4941:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4942:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4943:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4944:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4945:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4946:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4947:skia_private::TArray::destroyAll\28\29 +4948:skia_private::TArray::clear\28\29 +4949:skia_private::TArray::Allocate\28int\2c\20double\29 +4950:skia_private::TArray::BufferFinishedMessage\2c\20false>::operator=\28skia_private::TArray::BufferFinishedMessage\2c\20false>&&\29 +4951:skia_private::TArray::BufferFinishedMessage\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +4952:skia_private::TArray::BufferFinishedMessage\2c\20false>::destroyAll\28\29 +4953:skia_private::TArray::BufferFinishedMessage\2c\20false>::clear\28\29 +4954:skia_private::TArray::Plane\2c\20false>::preallocateNewData\28int\2c\20double\29 +4955:skia_private::TArray::Plane\2c\20false>::installDataAndUpdateCapacity\28SkSpan\29 +4956:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +4957:skia_private::TArray\2c\20true>::~TArray\28\29 +4958:skia_private::TArray\2c\20true>::~TArray\28\29 +4959:skia_private::TArray\2c\20true>::preallocateNewData\28int\2c\20double\29 +4960:skia_private::TArray\2c\20true>::clear\28\29 +4961:skia_private::TArray::push_back_raw\28int\29 +4962:skia_private::TArray::push_back\28hb_feature_t&&\29 +4963:skia_private::TArray::resize_back\28int\29 +4964:skia_private::TArray::reset\28int\29 +4965:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +4966:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4967:skia_private::TArray::initData\28int\29 +4968:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +4969:skia_private::TArray<\28anonymous\20namespace\29::DrawAtlasOpImpl::Geometry\2c\20true>::checkRealloc\28int\2c\20double\29 +4970:skia_private::TArray<\28anonymous\20namespace\29::DefaultPathOp::PathData\2c\20true>::preallocateNewData\28int\2c\20double\29 +4971:skia_private::TArray<\28anonymous\20namespace\29::AAHairlineOp::PathData\2c\20true>::preallocateNewData\28int\2c\20double\29 +4972:skia_private::TArray<\28anonymous\20namespace\29::AAHairlineOp::PathData\2c\20true>::installDataAndUpdateCapacity\28SkSpan\29 +4973:skia_private::TArray::push_back_n\28int\2c\20SkUnicode::CodeUnitFlags\20const&\29 +4974:skia_private::TArray::checkRealloc\28int\2c\20double\29 +4975:skia_private::TArray::operator=\28skia_private::TArray&&\29 +4976:skia_private::TArray::destroyAll\28\29 +4977:skia_private::TArray::initData\28int\29 +4978:skia_private::TArray::TArray\28skia_private::TArray\20const&\29 +4979:skia_private::TArray\29::ReorderedArgument\2c\20false>::push_back\28SkSL::optimize_constructor_swizzle\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ConstructorCompound\20const&\2c\20skia_private::FixedArray<4\2c\20signed\20char>\29::ReorderedArgument&&\29 +4980:skia_private::TArray::reserve_exact\28int\29 +4981:skia_private::TArray::fromBack\28int\29 +4982:skia_private::TArray::TArray\28skia_private::TArray&&\29 +4983:skia_private::TArray::Allocate\28int\2c\20double\29 +4984:skia_private::TArray::push_back\28SkSL::Field&&\29 +4985:skia_private::TArray::initData\28int\29 +4986:skia_private::TArray::Allocate\28int\2c\20double\29 +4987:skia_private::TArray::~TArray\28\29 +4988:skia_private::TArray::destroyAll\28\29 +4989:skia_private::TArray\2c\20true>::push_back\28SkRGBA4f<\28SkAlphaType\292>&&\29 +4990:skia_private::TArray\2c\20true>::operator=\28skia_private::TArray\2c\20true>&&\29 +4991:skia_private::TArray\2c\20true>::checkRealloc\28int\2c\20double\29 +4992:skia_private::TArray::push_back\28SkPoint\20const&\29 +4993:skia_private::TArray::operator=\28skia_private::TArray\20const&\29 +4994:skia_private::TArray::copy\28SkPoint\20const*\29 +4995:skia_private::TArray::~TArray\28\29 +4996:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +4997:skia_private::TArray::destroyAll\28\29 +4998:skia_private::TArray::~TArray\28\29 +4999:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5000:skia_private::TArray::destroyAll\28\29 +5001:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5002:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5003:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5004:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5005:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5006:skia_private::TArray::push_back\28\29 +5007:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5008:skia_private::TArray::push_back\28\29 +5009:skia_private::TArray::push_back_raw\28int\29 +5010:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5011:skia_private::TArray::~TArray\28\29 +5012:skia_private::TArray::operator=\28skia_private::TArray&&\29 +5013:skia_private::TArray::destroyAll\28\29 +5014:skia_private::TArray::clear\28\29 +5015:skia_private::TArray::Allocate\28int\2c\20double\29 +5016:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5017:skia_private::TArray::push_back\28\29 +5018:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5019:skia_private::TArray::pop_back\28\29 +5020:skia_private::TArray::checkRealloc\28int\2c\20double\29 +5021:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5022:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5023:skia_private::TArray::installDataAndUpdateCapacity\28SkSpan\29 +5024:skia_private::TArray::preallocateNewData\28int\2c\20double\29 +5025:skia_private::STArray<8\2c\20int\2c\20true>::STArray\28int\29 +5026:skia_private::AutoTMalloc::realloc\28unsigned\20long\29 +5027:skia_private::AutoTMalloc::reset\28unsigned\20long\29 +5028:skia_private::AutoTArray::AutoTArray\28unsigned\20long\29 +5029:skia_private::AutoTArray::AutoTArray\28unsigned\20long\29 +5030:skia_private::AutoTArray::AutoTArray\28unsigned\20long\29 +5031:skia_private::AutoSTMalloc<256ul\2c\20unsigned\20short\2c\20void>::AutoSTMalloc\28unsigned\20long\29 +5032:skia_private::AutoSTArray<6\2c\20SkResourceCache::Key>::~AutoSTArray\28\29 +5033:skia_private::AutoSTArray<64\2c\20TriangulationVertex>::reset\28int\29 +5034:skia_private::AutoSTArray<64\2c\20SkGlyph\20const*>::reset\28int\29 +5035:skia_private::AutoSTArray<4\2c\20unsigned\20char>::reset\28int\29 +5036:skia_private::AutoSTArray<4\2c\20GrResourceHandle>::reset\28int\29 +5037:skia_private::AutoSTArray<3\2c\20std::__2::unique_ptr>>::reset\28int\29 +5038:skia_private::AutoSTArray<32\2c\20unsigned\20short>::~AutoSTArray\28\29 +5039:skia_private::AutoSTArray<32\2c\20unsigned\20short>::reset\28int\29 +5040:skia_private::AutoSTArray<32\2c\20SkRect>::reset\28int\29 +5041:skia_private::AutoSTArray<2\2c\20sk_sp>::reset\28int\29 +5042:skia_private::AutoSTArray<16\2c\20SkRect>::~AutoSTArray\28\29 +5043:skia_private::AutoSTArray<16\2c\20GrMipLevel>::reset\28int\29 +5044:skia_private::AutoSTArray<15\2c\20GrMipLevel>::reset\28int\29 +5045:skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>::~AutoSTArray\28\29 +5046:skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>::reset\28int\29 +5047:skia_private::AutoSTArray<14\2c\20GrMipLevel>::~AutoSTArray\28\29 +5048:skia_private::AutoSTArray<14\2c\20GrMipLevel>::reset\28int\29 +5049:skia_png_set_longjmp_fn +5050:skia_png_read_finish_IDAT +5051:skia_png_read_chunk_header +5052:skia_png_read_IDAT_data +5053:skia_png_gamma_16bit_correct +5054:skia_png_do_strip_channel +5055:skia_png_do_gray_to_rgb +5056:skia_png_do_expand +5057:skia_png_destroy_gamma_table +5058:skia_png_colorspace_set_sRGB +5059:skia_png_check_IHDR +5060:skia_png_calculate_crc +5061:skia::textlayout::operator==\28skia::textlayout::FontArguments\20const&\2c\20skia::textlayout::FontArguments\20const&\29 +5062:skia::textlayout::\28anonymous\20namespace\29::littleRound\28float\29 +5063:skia::textlayout::\28anonymous\20namespace\29::LineBreakerWithLittleRounding::breakLine\28float\29\20const +5064:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29 +5065:skia::textlayout::TypefaceFontStyleSet::matchStyle\28SkFontStyle\20const&\29 +5066:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29 +5067:skia::textlayout::TypefaceFontProvider::registerTypeface\28sk_sp\2c\20SkString\20const&\29 +5068:skia::textlayout::TextWrapper::TextStretch::TextStretch\28skia::textlayout::Cluster*\2c\20skia::textlayout::Cluster*\2c\20bool\29 +5069:skia::textlayout::TextStyle::matchOneAttribute\28skia::textlayout::StyleType\2c\20skia::textlayout::TextStyle\20const&\29\20const +5070:skia::textlayout::TextStyle::equals\28skia::textlayout::TextStyle\20const&\29\20const +5071:skia::textlayout::TextShadow::operator!=\28skia::textlayout::TextShadow\20const&\29\20const +5072:skia::textlayout::TextLine::~TextLine\28\29 +5073:skia::textlayout::TextLine::spacesWidth\28\29\20const +5074:skia::textlayout::TextLine::shiftCluster\28skia::textlayout::Cluster\20const*\2c\20float\2c\20float\29 +5075:skia::textlayout::TextLine::iterateThroughClustersInGlyphsOrder\28bool\2c\20bool\2c\20std::__2::function\20const&\29\20const::$_0::operator\28\29\28unsigned\20long\20const&\29\20const::'lambda'\28skia::textlayout::Cluster&\29::operator\28\29\28skia::textlayout::Cluster&\29\20const +5076:skia::textlayout::TextLine::iterateThroughClustersInGlyphsOrder\28bool\2c\20bool\2c\20std::__2::function\20const&\29\20const +5077:skia::textlayout::TextLine::getRectsForRange\28skia::textlayout::SkRange\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkRect\29::operator\28\29\28SkRect\29\20const +5078:skia::textlayout::TextLine::getMetrics\28\29\20const +5079:skia::textlayout::TextLine::extendHeight\28skia::textlayout::TextLine::ClipContext\20const&\29\20const +5080:skia::textlayout::TextLine::ensureTextBlobCachePopulated\28\29 +5081:skia::textlayout::TextLine::endsWithHardLineBreak\28\29\20const +5082:skia::textlayout::TextLine::buildTextBlob\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +5083:skia::textlayout::TextLine::TextLine\28skia::textlayout::ParagraphImpl*\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20skia::textlayout::InternalLineMetrics\29 +5084:skia::textlayout::TextLine::TextBlobRecord::~TextBlobRecord\28\29 +5085:skia::textlayout::TextLine::TextBlobRecord::TextBlobRecord\28\29 +5086:skia::textlayout::TextLine&\20skia_private::TArray::emplace_back&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&>\28skia::textlayout::ParagraphImpl*&&\2c\20SkPoint&\2c\20SkPoint&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20skia::textlayout::SkRange&\2c\20float&\2c\20skia::textlayout::InternalLineMetrics&\29 +5087:skia::textlayout::StrutStyle::StrutStyle\28\29 +5088:skia::textlayout::Run::shift\28skia::textlayout::Cluster\20const*\2c\20float\29 +5089:skia::textlayout::Run::newRunBuffer\28\29 +5090:skia::textlayout::Run::clusterIndex\28unsigned\20long\29\20const +5091:skia::textlayout::Run::calculateMetrics\28\29 +5092:skia::textlayout::ParagraphStyle::ellipsized\28\29\20const +5093:skia::textlayout::ParagraphPainter::DecorationStyle::DecorationStyle\28unsigned\20int\2c\20float\2c\20std::__2::optional\29 +5094:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29 +5095:skia::textlayout::ParagraphImpl::resolveStrut\28\29 +5096:skia::textlayout::ParagraphImpl::paint\28skia::textlayout::ParagraphPainter*\2c\20float\2c\20float\29 +5097:skia::textlayout::ParagraphImpl::getGlyphInfoAtUTF16Offset\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +5098:skia::textlayout::ParagraphImpl::getGlyphClusterAt\28unsigned\20long\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +5099:skia::textlayout::ParagraphImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda0'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +5100:skia::textlayout::ParagraphImpl::computeEmptyMetrics\28\29 +5101:skia::textlayout::ParagraphImpl::buildClusterTable\28\29::$_0::operator\28\29\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20float\2c\20float\29\20const +5102:skia::textlayout::ParagraphCacheKey::ParagraphCacheKey\28skia::textlayout::ParagraphImpl\20const*\29 +5103:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29 +5104:skia::textlayout::ParagraphBuilderImpl::finalize\28\29 +5105:skia::textlayout::ParagraphBuilderImpl::ensureUTF16Mapping\28\29::$_0::operator\28\29\28\29\20const::'lambda0'\28unsigned\20long\29::operator\28\29\28unsigned\20long\29\20const +5106:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\2c\20bool\29 +5107:skia::textlayout::Paragraph::~Paragraph\28\29 +5108:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29 +5109:skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29::$_0::operator\28\29\28unsigned\20long\2c\20skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29::Dir\29\20const +5110:skia::textlayout::OneLineShaper::clusteredText\28skia::textlayout::SkRange&\29 +5111:skia::textlayout::OneLineShaper::FontKey::operator==\28skia::textlayout::OneLineShaper::FontKey\20const&\29\20const +5112:skia::textlayout::InternalLineMetrics::add\28skia::textlayout::InternalLineMetrics\29 +5113:skia::textlayout::FontFeature::operator==\28skia::textlayout::FontFeature\20const&\29\20const +5114:skia::textlayout::FontFeature::FontFeature\28skia::textlayout::FontFeature\20const&\29 +5115:skia::textlayout::FontCollection::~FontCollection\28\29 +5116:skia::textlayout::FontCollection::matchTypeface\28SkString\20const&\2c\20SkFontStyle\29 +5117:skia::textlayout::FontCollection::defaultFallback\28int\2c\20SkFontStyle\2c\20SkString\20const&\29 +5118:skia::textlayout::FontCollection::FamilyKey::operator==\28skia::textlayout::FontCollection::FamilyKey\20const&\29\20const +5119:skia::textlayout::FontCollection::FamilyKey::FamilyKey\28skia::textlayout::FontCollection::FamilyKey&&\29 +5120:skia::textlayout::FontArguments::~FontArguments\28\29 +5121:skia::textlayout::Decoration::operator==\28skia::textlayout::Decoration\20const&\29\20const +5122:skia::textlayout::Cluster::trimmedWidth\28unsigned\20long\29\20const +5123:skgpu::tess::\28anonymous\20namespace\29::write_curve_index_buffer_base_index\28skgpu::VertexWriter\2c\20unsigned\20long\2c\20unsigned\20short\29 +5124:skgpu::tess::StrokeParams::set\28SkStrokeRec\20const&\29 +5125:skgpu::tess::StrokeIterator::finishOpenContour\28\29 +5126:skgpu::tess::PreChopPathCurves\28float\2c\20SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\29 +5127:skgpu::tess::LinearTolerances::setStroke\28skgpu::tess::StrokeParams\20const&\2c\20float\29 +5128:skgpu::tess::LinearTolerances::requiredResolveLevel\28\29\20const +5129:skgpu::tess::GetJoinType\28SkStrokeRec\20const&\29 +5130:skgpu::tess::FixedCountCurves::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +5131:skgpu::tess::CullTest::areVisible3\28SkPoint\20const*\29\20const +5132:skgpu::tess::ConicHasCusp\28SkPoint\20const*\29 +5133:skgpu::make_unnormalized_half_kernel\28float*\2c\20int\2c\20float\29 +5134:skgpu::ganesh::\28anonymous\20namespace\29::add_line_to_segment\28SkPoint\20const&\2c\20skia_private::TArray*\29 +5135:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29 +5136:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::flush\28GrMeshDrawTarget*\2c\20skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::FlushInfo*\29\20const +5137:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::addToAtlasWithRetry\28GrMeshDrawTarget*\2c\20skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::FlushInfo*\2c\20skgpu::ganesh::SmallPathAtlasMgr*\2c\20int\2c\20int\2c\20void\20const*\2c\20SkRect\20const&\2c\20int\2c\20skgpu::ganesh::SmallPathShapeData*\29\20const +5138:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::SmallPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20GrUserStencilSettings\20const*\29 +5139:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29 +5140:skgpu::ganesh::\28anonymous\20namespace\29::ChopPathIfNecessary\28SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20SkStrokeRec\20const&\2c\20SkPath*\29 +5141:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29 +5142:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::recordDraw\28GrMeshDrawTarget*\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20int\2c\20unsigned\20short*\29 +5143:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::PathData::PathData\28skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::PathData&&\29 +5144:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::AAFlatteningConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20float\2c\20SkStrokeRec::Style\2c\20SkPaint::Join\2c\20float\2c\20GrUserStencilSettings\20const*\29 +5145:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29 +5146:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::PathData::PathData\28skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::PathData&&\29 +5147:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::AAConvexPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrUserStencilSettings\20const*\29 +5148:skgpu::ganesh::TextureOp::Make\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20SkBlendMode\2c\20GrAAType\2c\20DrawQuad*\2c\20SkRect\20const*\29 +5149:skgpu::ganesh::TessellationPathRenderer::IsSupported\28GrCaps\20const&\29 +5150:skgpu::ganesh::SurfaceFillContext::fillRectToRectWithFP\28SkRect\20const&\2c\20SkIRect\20const&\2c\20std::__2::unique_ptr>\29 +5151:skgpu::ganesh::SurfaceFillContext::blitTexture\28GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\29 +5152:skgpu::ganesh::SurfaceFillContext::arenas\28\29 +5153:skgpu::ganesh::SurfaceFillContext::addDrawOp\28std::__2::unique_ptr>\29 +5154:skgpu::ganesh::SurfaceFillContext::SurfaceFillContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorInfo\20const&\29 +5155:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29_9587 +5156:skgpu::ganesh::SurfaceDrawContext::setNeedsStencil\28\29 +5157:skgpu::ganesh::SurfaceDrawContext::internalStencilClear\28SkIRect\20const*\2c\20bool\29 +5158:skgpu::ganesh::SurfaceDrawContext::fillRectWithEdgeAA\28GrClip\20const*\2c\20GrPaint&&\2c\20GrQuadAAFlags\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const*\29 +5159:skgpu::ganesh::SurfaceDrawContext::drawVertices\28GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20sk_sp\2c\20GrPrimitiveType*\2c\20bool\29 +5160:skgpu::ganesh::SurfaceDrawContext::drawTexturedQuad\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkBlendMode\2c\20DrawQuad*\2c\20SkRect\20const*\29 +5161:skgpu::ganesh::SurfaceDrawContext::drawTexture\28GrClip\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20SkBlendMode\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +5162:skgpu::ganesh::SurfaceDrawContext::drawStrokedLine\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkPoint\20const*\2c\20SkStrokeRec\20const&\29 +5163:skgpu::ganesh::SurfaceDrawContext::drawRegion\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrStyle\20const&\2c\20GrUserStencilSettings\20const*\29 +5164:skgpu::ganesh::SurfaceDrawContext::drawOval\28GrClip\20const*\2c\20GrPaint&&\2c\20GrAA\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20GrStyle\20const&\29 +5165:skgpu::ganesh::SurfaceDrawContext::attemptQuadOptimization\28GrClip\20const*\2c\20GrUserStencilSettings\20const*\2c\20DrawQuad*\2c\20GrPaint*\29::$_0::operator\28\29\28\29\20const +5166:skgpu::ganesh::SurfaceDrawContext::SurfaceDrawContext\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +5167:skgpu::ganesh::SurfaceContext::writePixels\28GrDirectContext*\2c\20GrCPixmap\2c\20SkIPoint\29 +5168:skgpu::ganesh::SurfaceContext::rescaleInto\28skgpu::ganesh::SurfaceFillContext*\2c\20SkIRect\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\29 +5169:skgpu::ganesh::SurfaceContext::copy\28sk_sp\2c\20SkIRect\2c\20SkIPoint\29 +5170:skgpu::ganesh::SurfaceContext::copyScaled\28sk_sp\2c\20SkIRect\2c\20SkIRect\2c\20SkFilterMode\29 +5171:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +5172:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::FinishContext::~FinishContext\28\29 +5173:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +5174:skgpu::ganesh::StrokeTessellator::draw\28GrOpFlushState*\29\20const +5175:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29 +5176:skgpu::ganesh::StrokeTessellateOp::prePrepareTessellator\28GrTessellationShader::ProgramArgs&&\2c\20GrAppliedClip&&\29 +5177:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::allowed_stroke\28GrCaps\20const*\2c\20SkStrokeRec\20const&\2c\20GrAA\2c\20bool*\29 +5178:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29 +5179:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::NonAAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrSimpleMeshDrawOpHelper::InputFlags\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkStrokeRec\20const&\2c\20GrAAType\29 +5180:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29 +5181:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::ClassID\28\29 +5182:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::AAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::RectInfo\20const&\2c\20bool\29 +5183:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::AAStrokeRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const&\29 +5184:skgpu::ganesh::SoftwarePathRenderer::DrawAroundInvPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29 +5185:skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11104 +5186:skgpu::ganesh::SmallPathAtlasMgr::reset\28\29 +5187:skgpu::ganesh::SmallPathAtlasMgr::findOrCreate\28skgpu::ganesh::SmallPathShapeDataKey\20const&\29 +5188:skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +5189:skgpu::ganesh::SmallPathAtlasMgr::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +5190:skgpu::ganesh::ShadowRRectOp::Make\28GrRecordingContext*\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20float\2c\20float\29 +5191:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29 +5192:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::RegionOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRegion\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +5193:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::primitiveType\28\29\20const +5194:skgpu::ganesh::QuadPerEdgeAA::VertexSpec::VertexSpec\28GrQuad::Type\2c\20skgpu::ganesh::QuadPerEdgeAA::ColorType\2c\20GrQuad::Type\2c\20bool\2c\20skgpu::ganesh::QuadPerEdgeAA::Subset\2c\20GrAAType\2c\20bool\2c\20skgpu::ganesh::QuadPerEdgeAA::IndexBufferOption\29 +5195:skgpu::ganesh::QuadPerEdgeAA::Tessellator::append\28GrQuad*\2c\20GrQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20GrQuadAAFlags\29 +5196:skgpu::ganesh::QuadPerEdgeAA::Tessellator::Tessellator\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29 +5197:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29 +5198:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::initializeAttrs\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29 +5199:skgpu::ganesh::QuadPerEdgeAA::IssueDraw\28GrCaps\20const&\2c\20GrOpsRenderPass*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20int\2c\20int\2c\20int\2c\20int\29 +5200:skgpu::ganesh::QuadPerEdgeAA::GetIndexBuffer\28GrMeshDrawTarget*\2c\20skgpu::ganesh::QuadPerEdgeAA::IndexBufferOption\29 +5201:skgpu::ganesh::PathWedgeTessellator::Make\28SkArenaAlloc*\2c\20bool\2c\20skgpu::tess::PatchAttribs\29 +5202:skgpu::ganesh::PathTessellator::PathTessellator\28bool\2c\20skgpu::tess::PatchAttribs\29 +5203:skgpu::ganesh::PathTessellator::PathDrawList*\20SkArenaAlloc::make\20const&>\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29 +5204:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29 +5205:skgpu::ganesh::PathTessellateOp::usesMSAA\28\29\20const +5206:skgpu::ganesh::PathTessellateOp::prepareTessellator\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +5207:skgpu::ganesh::PathTessellateOp::PathTessellateOp\28SkArenaAlloc*\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\2c\20SkRect\20const&\29 +5208:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29 +5209:skgpu::ganesh::PathStencilCoverOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +5210:skgpu::ganesh::PathStencilCoverOp::ClassID\28\29 +5211:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29 +5212:skgpu::ganesh::PathInnerTriangulateOp::pushFanStencilProgram\28GrTessellationShader::ProgramArgs\20const&\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +5213:skgpu::ganesh::PathInnerTriangulateOp::prePreparePrograms\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAppliedClip&&\29 +5214:skgpu::ganesh::PathCurveTessellator::~PathCurveTessellator\28\29 +5215:skgpu::ganesh::PathCurveTessellator::prepareWithTriangles\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20GrTriangulator::BreadcrumbTriangleList*\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +5216:skgpu::ganesh::PathCurveTessellator::Make\28SkArenaAlloc*\2c\20bool\2c\20skgpu::tess::PatchAttribs\29 +5217:skgpu::ganesh::OpsTask::setColorLoadOp\28GrLoadOp\2c\20std::__2::array\29 +5218:skgpu::ganesh::OpsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +5219:skgpu::ganesh::OpsTask::onExecute\28GrOpFlushState*\29 +5220:skgpu::ganesh::OpsTask::addSampledTexture\28GrSurfaceProxy*\29 +5221:skgpu::ganesh::OpsTask::addDrawOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0::operator\28\29\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\20const +5222:skgpu::ganesh::OpsTask::addDrawOp\28GrDrawingManager*\2c\20std::__2::unique_ptr>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29 +5223:skgpu::ganesh::OpsTask::OpsTask\28GrDrawingManager*\2c\20GrSurfaceProxyView\2c\20GrAuditTrail*\2c\20sk_sp\29 +5224:skgpu::ganesh::OpsTask::OpChain::tryConcat\28skgpu::ganesh::OpsTask::OpChain::List*\2c\20GrProcessorSet::Analysis\2c\20GrDstProxyView\20const&\2c\20GrAppliedClip\20const*\2c\20SkRect\20const&\2c\20GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrAuditTrail*\29 +5225:skgpu::ganesh::OpsTask::OpChain::OpChain\28std::__2::unique_ptr>\2c\20GrProcessorSet::Analysis\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const*\29 +5226:skgpu::ganesh::MakeFragmentProcessorFromView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +5227:skgpu::ganesh::LockTextureProxyView\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20GrImageTexGenPolicy\2c\20skgpu::Mipmapped\29 +5228:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29 +5229:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::NonAALatticeOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20sk_sp\2c\20SkFilterMode\2c\20std::__2::unique_ptr>\2c\20SkRect\20const&\29 +5230:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29 +5231:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::can_use_hw_derivatives_with_coverage\28skvx::Vec<2\2c\20float>\20const&\2c\20SkPoint\20const&\29 +5232:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29 +5233:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Make\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20GrAA\29 +5234:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::FillRRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20SkRRect\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::LocalCoords\20const&\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29 +5235:skgpu::ganesh::DrawableOp::~DrawableOp\28\29 +5236:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29 +5237:skgpu::ganesh::DrawAtlasPathOp::prepareProgram\28GrCaps\20const&\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +5238:skgpu::ganesh::Device::~Device\28\29 +5239:skgpu::ganesh::Device::replaceBackingProxy\28SkSurface::ContentChangeMode\2c\20sk_sp\2c\20GrColorType\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20SkSurfaceProps\20const&\29 +5240:skgpu::ganesh::Device::makeSpecial\28SkBitmap\20const&\29 +5241:skgpu::ganesh::Device::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +5242:skgpu::ganesh::Device::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +5243:skgpu::ganesh::Device::drawEdgeAAImage\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20SkTileMode\29 +5244:skgpu::ganesh::Device::convertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +5245:skgpu::ganesh::Device::android_utils_clipAsRgn\28SkRegion*\29\20const +5246:skgpu::ganesh::DefaultPathRenderer::internalDrawPath\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrPaint&&\2c\20GrAAType\2c\20GrUserStencilSettings\20const&\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20bool\29 +5247:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +5248:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29 +5249:skgpu::ganesh::CopyView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\2c\20std::__2::basic_string_view>\29 +5250:skgpu::ganesh::ClipStack::clipPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrAA\2c\20SkClipOp\29 +5251:skgpu::ganesh::ClipStack::begin\28\29\20const +5252:skgpu::ganesh::ClipStack::SaveRecord::removeElements\28SkTBlockList*\29 +5253:skgpu::ganesh::ClipStack::RawElement::clipType\28\29\20const +5254:skgpu::ganesh::ClipStack::Mask::invalidate\28GrProxyProvider*\29 +5255:skgpu::ganesh::ClipStack::ElementIter::operator++\28\29 +5256:skgpu::ganesh::ClipStack::Element::Element\28skgpu::ganesh::ClipStack::Element\20const&\29 +5257:skgpu::ganesh::ClipStack::Draw::Draw\28SkRect\20const&\2c\20GrAA\29 +5258:skgpu::ganesh::ClearOp::ClearOp\28skgpu::ganesh::ClearOp::Buffer\2c\20GrScissorState\20const&\2c\20std::__2::array\2c\20bool\29 +5259:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29 +5260:skgpu::ganesh::AtlasTextOp::operator\20new\28unsigned\20long\29 +5261:skgpu::ganesh::AtlasTextOp::onPrepareDraws\28GrMeshDrawTarget*\29::$_0::operator\28\29\28\29\20const +5262:skgpu::ganesh::AtlasTextOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +5263:skgpu::ganesh::AtlasTextOp::ClassID\28\29 +5264:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29 +5265:skgpu::ganesh::AtlasRenderTask::stencilAtlasRect\28GrRecordingContext*\2c\20SkRect\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrUserStencilSettings\20const*\29 +5266:skgpu::ganesh::AtlasRenderTask::readView\28GrCaps\20const&\29\20const +5267:skgpu::ganesh::AtlasRenderTask::instantiate\28GrOnFlushResourceProvider*\2c\20sk_sp\29 +5268:skgpu::ganesh::AtlasRenderTask::addPath\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIPoint\2c\20int\2c\20int\2c\20bool\2c\20SkIPoint16*\29 +5269:skgpu::ganesh::AtlasRenderTask::addAtlasDrawOp\28std::__2::unique_ptr>\2c\20GrCaps\20const&\29 +5270:skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10400 +5271:skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +5272:skgpu::ganesh::AtlasPathRenderer::pathFitsInAtlas\28SkRect\20const&\2c\20GrAAType\29\20const +5273:skgpu::ganesh::AtlasPathRenderer::addPathToAtlas\28GrRecordingContext*\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRect\20const&\2c\20SkIRect*\2c\20SkIPoint16*\2c\20bool*\2c\20std::__2::function\20const&\29 +5274:skgpu::ganesh::AtlasPathRenderer::AtlasPathKey::operator==\28skgpu::ganesh::AtlasPathRenderer::AtlasPathKey\20const&\29\20const +5275:skgpu::ganesh::AsFragmentProcessor\28GrRecordingContext*\2c\20SkImage\20const*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29 +5276:skgpu::TiledTextureUtils::OptimizeSampleArea\28SkISize\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkPoint\20const*\2c\20SkRect*\2c\20SkRect*\2c\20SkMatrix*\29 +5277:skgpu::TiledTextureUtils::CanDisableMipmap\28SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\29 +5278:skgpu::TClientMappedBufferManager::process\28\29 +5279:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29 +5280:skgpu::TAsyncReadResult::count\28\29\20const +5281:skgpu::TAsyncReadResult::Plane::~Plane\28\29 +5282:skgpu::Swizzle::BGRA\28\29 +5283:skgpu::ScratchKey::ScratchKey\28skgpu::ScratchKey\20const&\29 +5284:skgpu::ResourceKey::operator=\28skgpu::ResourceKey\20const&\29 +5285:skgpu::RectanizerSkyline::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +5286:skgpu::RectanizerSkyline::RectanizerSkyline\28int\2c\20int\29 +5287:skgpu::Plot::~Plot\28\29 +5288:skgpu::Plot::resetRects\28\29 +5289:skgpu::Plot::Plot\28int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20SkColorType\2c\20unsigned\20long\29 +5290:skgpu::KeyBuilder::flush\28\29 +5291:skgpu::KeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +5292:skgpu::GetReducedBlendModeInfo\28SkBlendMode\29 +5293:skgpu::GetApproxSize\28SkISize\29::$_0::operator\28\29\28int\29\20const +5294:skgpu::CreateIntegralTable\28int\29 +5295:skgpu::ComputeIntegralTableWidth\28float\29 +5296:skgpu::AtlasLocator::updatePlotLocator\28skgpu::PlotLocator\29 +5297:skgpu::AtlasLocator::insetSrc\28int\29 +5298:skcms_Matrix3x3_invert +5299:sk_sp::~sk_sp\28\29 +5300:sk_sp::reset\28sktext::gpu::TextStrike*\29 +5301:sk_sp\20skgpu::RefCntedCallback::MakeImpl\28void\20\28*\29\28void*\29\2c\20void*\29 +5302:sk_sp<\28anonymous\20namespace\29::UniqueKeyInvalidator>\20sk_make_sp<\28anonymous\20namespace\29::UniqueKeyInvalidator\2c\20skgpu::UniqueKey&\2c\20unsigned\20int>\28skgpu::UniqueKey&\2c\20unsigned\20int&&\29 +5303:sk_sp<\28anonymous\20namespace\29::ShadowInvalidator>\20sk_make_sp<\28anonymous\20namespace\29::ShadowInvalidator\2c\20SkResourceCache::Key&>\28SkResourceCache::Key&\29 +5304:sk_sp::operator=\28sk_sp\20const&\29 +5305:sk_sp&\20std::__2::vector\2c\20std::__2::allocator>>::emplace_back>\28sk_sp&&\29 +5306:sk_sp\20sk_make_sp>\28sk_sp&&\29 +5307:sk_sp::~sk_sp\28\29 +5308:sk_sp::sk_sp\28sk_sp\20const&\29 +5309:sk_sp::operator=\28sk_sp&&\29 +5310:sk_sp::reset\28SkMeshSpecification*\29 +5311:sk_sp::reset\28SkData\20const*\29 +5312:sk_sp::operator=\28sk_sp\20const&\29 +5313:sk_sp::operator=\28sk_sp\20const&\29 +5314:sk_sp::operator=\28sk_sp&&\29 +5315:sk_sp::~sk_sp\28\29 +5316:sk_sp::sk_sp\28sk_sp\20const&\29 +5317:sk_sp&\20sk_sp::operator=\28sk_sp&&\29 +5318:sk_sp::reset\28GrSurface::RefCntedReleaseProc*\29 +5319:sk_sp::operator=\28sk_sp&&\29 +5320:sk_sp::~sk_sp\28\29 +5321:sk_sp::operator=\28sk_sp&&\29 +5322:sk_sp::~sk_sp\28\29 +5323:sk_sp\20sk_make_sp\28\29 +5324:sk_sp::reset\28GrArenas*\29 +5325:sk_ft_alloc\28FT_MemoryRec_*\2c\20long\29 +5326:sk_fopen\28char\20const*\2c\20SkFILE_Flags\29 +5327:sk_fgetsize\28_IO_FILE*\29 +5328:sk_determinant\28float\20const*\2c\20int\29 +5329:sk_blit_below\28SkBlitter*\2c\20SkIRect\20const&\2c\20SkRegion\20const&\29 +5330:sk_blit_above\28SkBlitter*\2c\20SkIRect\20const&\2c\20SkRegion\20const&\29 +5331:sid_to_gid_t\20const*\20hb_sorted_array_t::bsearch\28unsigned\20int\20const&\2c\20sid_to_gid_t\20const*\29 +5332:short\20sk_saturate_cast\28float\29 +5333:sharp_angle\28SkPoint\20const*\29 +5334:sfnt_stream_close +5335:setup_masks_arabic_plan\28arabic_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_script_t\29 +5336:set_points\28float*\2c\20int*\2c\20int\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20float\2c\20float\2c\20bool\29 +5337:set_normal_unitnormal\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +5338:set_khr_debug_label\28GrGLGpu*\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +5339:setThrew +5340:serialize_image\28SkImage\20const*\2c\20SkSerialProcs\29 +5341:sect_clamp_with_vertical\28SkPoint\20const*\2c\20float\29 +5342:scanexp +5343:scalbnl +5344:safe_picture_bounds\28SkRect\20const&\29 +5345:safe_int_addition +5346:rt_has_msaa_render_buffer\28GrGLRenderTarget\20const*\2c\20GrGLCaps\20const&\29 +5347:rrect_type_to_vert_count\28RRectType\29 +5348:row_is_all_zeros\28unsigned\20char\20const*\2c\20int\29 +5349:round_up_to_int\28float\29 +5350:round_down_to_int\28float\29 +5351:rotate\28SkDCubic\20const&\2c\20int\2c\20int\2c\20SkDCubic&\29 +5352:rewind_if_necessary\28GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29 +5353:resolveImplicitLevels\28UBiDi*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +5354:renderbuffer_storage_msaa\28GrGLGpu*\2c\20int\2c\20unsigned\20int\2c\20int\2c\20int\29 +5355:remove_edge_below\28GrTriangulator::Edge*\29 +5356:remove_edge_above\28GrTriangulator::Edge*\29 +5357:reductionLineCount\28SkDQuad\20const&\29 +5358:recursive_edge_intersect\28GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Line\20const&\2c\20SkPoint\2c\20SkPoint\2c\20SkPoint*\2c\20double*\2c\20double*\29 +5359:rect_exceeds\28SkRect\20const&\2c\20float\29 +5360:reclassify_vertex\28TriangulationVertex*\2c\20SkPoint\20const*\2c\20int\2c\20ReflexHash*\2c\20SkTInternalLList*\29 +5361:radii_are_nine_patch\28SkPoint\20const*\29 +5362:quad_type_for_transformed_rect\28SkMatrix\20const&\29 +5363:quad_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5364:quad_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5365:quad_in_line\28SkPoint\20const*\29 +5366:pt_to_tangent_line\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +5367:psh_hint_table_record +5368:psh_hint_table_init +5369:psh_hint_table_find_strong_points +5370:psh_hint_table_done +5371:psh_hint_table_activate_mask +5372:psh_hint_align +5373:psh_glyph_load_points +5374:psh_globals_scale_widths +5375:psh_compute_dir +5376:psh_blues_set_zones_0 +5377:psh_blues_set_zones +5378:ps_table_realloc +5379:ps_parser_to_token_array +5380:ps_parser_load_field +5381:ps_mask_table_last +5382:ps_mask_table_done +5383:ps_hints_stem +5384:ps_dimension_end +5385:ps_dimension_done +5386:ps_dimension_add_t1stem +5387:ps_builder_start_point +5388:ps_builder_close_contour +5389:ps_builder_add_point1 +5390:printf_core +5391:prepare_to_draw_into_mask\28SkRect\20const&\2c\20SkMaskBuilder*\29 +5392:position_cluster\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\29 +5393:portable::uniform_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5394:portable::set_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5395:portable::copy_from_indirect_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5396:portable::copy_2_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5397:portable::check_decal_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5398:pop_arg +5399:pointInTriangle\28SkDPoint\20const*\2c\20SkDPoint\20const&\29 +5400:pntz +5401:png_rtran_ok +5402:png_malloc_array_checked +5403:png_inflate +5404:png_format_buffer +5405:png_decompress_chunk +5406:png_colorspace_check_gamma +5407:png_cache_unknown_chunk +5408:pin_offset_s32\28int\2c\20int\2c\20int\29 +5409:path_key_from_data_size\28SkPath\20const&\29 +5410:parse_private_use_subtag\28char\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20char\20const*\2c\20unsigned\20char\20\28*\29\28unsigned\20char\29\29 +5411:paint_color_to_dst\28SkPaint\20const&\2c\20SkPixmap\20const&\29 +5412:pad4 +5413:operator_new_impl\28unsigned\20long\29 +5414:operator==\28SkRect\20const&\2c\20SkRect\20const&\29 +5415:operator==\28SkRRect\20const&\2c\20SkRRect\20const&\29 +5416:operator==\28SkPaint\20const&\2c\20SkPaint\20const&\29 +5417:operator!=\28SkRRect\20const&\2c\20SkRRect\20const&\29 +5418:open_face +5419:on_same_side\28SkPoint\20const*\2c\20int\2c\20int\29 +5420:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29_12066 +5421:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::~TransformedMaskSubRun\28\29 +5422:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +5423:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::glyphs\28\29\20const +5424:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29_2674 +5425:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +5426:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::size\28\29\20const +5427:non-virtual\20thunk\20to\20SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +5428:move_multiples\28SkOpContourHead*\29 +5429:mono_cubic_closestT\28float\20const*\2c\20float\29 +5430:mbsrtowcs +5431:matchesEnd\28SkDPoint\20const*\2c\20SkDPoint\20const&\29 +5432:map_rect_perspective\28SkRect\20const&\2c\20float\20const*\29::$_0::operator\28\29\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29\20const::'lambda'\28skvx::Vec<4\2c\20float>\20const&\29::operator\28\29\28skvx::Vec<4\2c\20float>\20const&\29\20const +5433:map_quad_to_rect\28SkRSXform\20const&\2c\20SkRect\20const&\29 +5434:map_quad_general\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20SkMatrix\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +5435:make_xrect\28SkRect\20const&\29 +5436:make_tiled_gradient\28GrFPArgs\20const&\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20bool\2c\20bool\29 +5437:make_premul_effect\28std::__2::unique_ptr>\29 +5438:make_paint_with_image\28SkPaint\20const&\2c\20SkBitmap\20const&\2c\20SkSamplingOptions\20const&\2c\20SkMatrix*\29 +5439:make_dual_interval_colorizer\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20float\29 +5440:make_clamped_gradient\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20bool\29 +5441:make_bmp_proxy\28GrProxyProvider*\2c\20SkBitmap\20const&\2c\20GrColorType\2c\20skgpu::Mipmapped\2c\20SkBackingFit\2c\20skgpu::Budgeted\29 +5442:long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +5443:long\20long\20std::__2::__num_get_signed_integral\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\2c\20int\29 +5444:long\20double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +5445:log2f_\28float\29 +5446:load_post_names +5447:line_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5448:line_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5449:lineMetrics_getLineNumber +5450:lineMetrics_getHardBreak +5451:lineBreakBuffer_free +5452:lin_srgb_to_oklab\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +5453:lang_find_or_insert\28char\20const*\29 +5454:isxdigit +5455:isdigit +5456:is_zero_width_char\28hb_font_t*\2c\20unsigned\20int\29 +5457:is_simple_rect\28GrQuad\20const&\29 +5458:is_plane_config_compatible_with_subsampling\28SkYUVAInfo::PlaneConfig\2c\20SkYUVAInfo::Subsampling\29 +5459:is_overlap_edge\28GrTriangulator::Edge*\29 +5460:is_leap +5461:is_int\28float\29 +5462:is_halant_use\28hb_glyph_info_t\20const&\29 +5463:is_float_fp32\28GrGLContextInfo\20const&\2c\20GrGLInterface\20const*\2c\20unsigned\20int\29 +5464:iprintf +5465:invalidate_buffer\28GrGLGpu*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20long\29 +5466:interp_cubic_coords\28double\20const*\2c\20double*\2c\20double\29 +5467:int\20SkRecords::Pattern>::matchFirst>\28SkRecords::Is*\2c\20SkRecord*\2c\20int\29 +5468:inside_triangle\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\29 +5469:inflateEnd +5470:image_ref +5471:image_getWidth +5472:hb_vector_t::resize\28int\2c\20bool\2c\20bool\29 +5473:hb_vector_t\2c\20false>::shrink_vector\28unsigned\20int\29 +5474:hb_vector_t\2c\20false>::resize\28int\2c\20bool\2c\20bool\29 +5475:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +5476:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +5477:hb_vector_t::alloc\28unsigned\20int\2c\20bool\29 +5478:hb_vector_t::pop\28\29 +5479:hb_vector_t\2c\20false>::shrink_vector\28unsigned\20int\29 +5480:hb_vector_t\2c\20false>::fini\28\29 +5481:hb_vector_t::shrink_vector\28unsigned\20int\29 +5482:hb_vector_t::fini\28\29 +5483:hb_unicode_mirroring_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +5484:hb_unicode_funcs_t::is_default_ignorable\28unsigned\20int\29 +5485:hb_unicode_funcs_get_default +5486:hb_tag_from_string +5487:hb_shape_plan_key_t::init\28bool\2c\20hb_face_t*\2c\20hb_segment_properties_t\20const*\2c\20hb_feature_t\20const*\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20char\20const*\20const*\29 +5488:hb_shape_plan_key_t::fini\28\29 +5489:hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>::may_have\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>\20const&\29\20const +5490:hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>::add\28hb_set_digest_combiner_t\2c\20hb_set_digest_combiner_t\2c\20hb_set_digest_bits_pattern_t>>\20const&\29 +5491:hb_serialize_context_t::fini\28\29 +5492:hb_sanitize_context_t::return_t\20OT::Context::dispatch\28hb_sanitize_context_t*\29\20const +5493:hb_sanitize_context_t::return_t\20OT::ChainContext::dispatch\28hb_sanitize_context_t*\29\20const +5494:hb_paint_funcs_t::sweep_gradient\28void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\29 +5495:hb_paint_funcs_t::radial_gradient\28void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5496:hb_paint_funcs_t::push_skew\28void*\2c\20float\2c\20float\29 +5497:hb_paint_funcs_t::push_rotate\28void*\2c\20float\29 +5498:hb_paint_funcs_t::push_inverse_root_transform\28void*\2c\20hb_font_t*\29 +5499:hb_paint_funcs_t::push_group\28void*\29 +5500:hb_paint_funcs_t::pop_group\28void*\2c\20hb_paint_composite_mode_t\29 +5501:hb_paint_funcs_t::linear_gradient\28void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5502:hb_paint_extents_paint_linear_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +5503:hb_paint_extents_get_funcs\28\29 +5504:hb_paint_extents_context_t::pop_clip\28\29 +5505:hb_paint_extents_context_t::hb_paint_extents_context_t\28\29 +5506:hb_ot_map_t::fini\28\29 +5507:hb_ot_map_builder_t::add_pause\28unsigned\20int\2c\20bool\20\28*\29\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29\29 +5508:hb_ot_map_builder_t::add_lookups\28hb_ot_map_t&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20unsigned\20int\29 +5509:hb_ot_layout_has_substitution +5510:hb_ot_font_set_funcs +5511:hb_memcmp\28void\20const*\2c\20void\20const*\2c\20unsigned\20int\29 +5512:hb_lazy_loader_t\2c\20hb_face_t\2c\2038u\2c\20OT::sbix_accelerator_t>::get_stored\28\29\20const +5513:hb_lazy_loader_t\2c\20hb_face_t\2c\207u\2c\20OT::post_accelerator_t>::get_stored\28\29\20const +5514:hb_lazy_loader_t\2c\20hb_face_t\2c\207u\2c\20OT::post_accelerator_t>::do_destroy\28OT::post_accelerator_t*\29 +5515:hb_lazy_loader_t\2c\20hb_face_t\2c\2023u\2c\20hb_blob_t>::get_stored\28\29\20const +5516:hb_lazy_loader_t\2c\20hb_face_t\2c\205u\2c\20OT::hmtx_accelerator_t>::get_stored\28\29\20const +5517:hb_lazy_loader_t\2c\20hb_face_t\2c\2021u\2c\20OT::gvar_accelerator_t>::do_destroy\28OT::gvar_accelerator_t*\29 +5518:hb_lazy_loader_t\2c\20hb_face_t\2c\2015u\2c\20OT::glyf_accelerator_t>::do_destroy\28OT::glyf_accelerator_t*\29 +5519:hb_lazy_loader_t\2c\20hb_face_t\2c\203u\2c\20OT::cmap_accelerator_t>::do_destroy\28OT::cmap_accelerator_t*\29 +5520:hb_lazy_loader_t\2c\20hb_face_t\2c\2017u\2c\20OT::cff2_accelerator_t>::get_stored\28\29\20const +5521:hb_lazy_loader_t\2c\20hb_face_t\2c\2017u\2c\20OT::cff2_accelerator_t>::do_destroy\28OT::cff2_accelerator_t*\29 +5522:hb_lazy_loader_t\2c\20hb_face_t\2c\2016u\2c\20OT::cff1_accelerator_t>::do_destroy\28OT::cff1_accelerator_t*\29 +5523:hb_lazy_loader_t\2c\20hb_face_t\2c\2019u\2c\20hb_blob_t>::get\28\29\20const +5524:hb_lazy_loader_t\2c\20hb_face_t\2c\2024u\2c\20OT::GDEF_accelerator_t>::do_destroy\28OT::GDEF_accelerator_t*\29 +5525:hb_lazy_loader_t\2c\20hb_face_t\2c\2035u\2c\20hb_blob_t>::get\28\29\20const +5526:hb_lazy_loader_t\2c\20hb_face_t\2c\2037u\2c\20OT::CBDT_accelerator_t>::get_stored\28\29\20const +5527:hb_lazy_loader_t\2c\20hb_face_t\2c\2037u\2c\20OT::CBDT_accelerator_t>::do_destroy\28OT::CBDT_accelerator_t*\29 +5528:hb_lazy_loader_t\2c\20hb_face_t\2c\2032u\2c\20hb_blob_t>::get\28\29\20const +5529:hb_lazy_loader_t\2c\20hb_face_t\2c\2028u\2c\20hb_blob_t>::get_stored\28\29\20const +5530:hb_lazy_loader_t\2c\20hb_face_t\2c\2028u\2c\20hb_blob_t>::get\28\29\20const +5531:hb_lazy_loader_t\2c\20hb_face_t\2c\2029u\2c\20hb_blob_t>::get_stored\28\29\20const +5532:hb_lazy_loader_t\2c\20hb_face_t\2c\2029u\2c\20hb_blob_t>::get\28\29\20const +5533:hb_lazy_loader_t\2c\20hb_face_t\2c\2033u\2c\20hb_blob_t>::get\28\29\20const +5534:hb_lazy_loader_t\2c\20hb_face_t\2c\2030u\2c\20hb_blob_t>::get_stored\28\29\20const +5535:hb_language_matches +5536:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>\2c\20hb_pair_t>>::operator-=\28unsigned\20int\29\20& +5537:hb_iter_t\2c\20hb_filter_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>>\2c\20hb_pair_t>>::operator+=\28unsigned\20int\29\20& +5538:hb_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20hb_pair_t>::operator++\28\29\20& +5539:hb_iter_t\2c\20hb_array_t>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_glyph_info_t\20const&\29\2c\20$_6\20const&\2c\20\28void*\290>\2c\20find_syllables_use\28hb_buffer_t*\29::'lambda'\28hb_pair_t\29\2c\20$_5\20const&\2c\20\28void*\290>\2c\20hb_pair_t>::operator--\28\29\20& +5540:hb_indic_get_categories\28unsigned\20int\29 +5541:hb_hashmap_t::fetch_item\28unsigned\20int\20const&\2c\20unsigned\20int\29\20const +5542:hb_hashmap_t::fetch_item\28hb_serialize_context_t::object_t\20const*\20const&\2c\20unsigned\20int\29\20const +5543:hb_font_t::subtract_glyph_origin_for_direction\28unsigned\20int\2c\20hb_direction_t\2c\20int*\2c\20int*\29 +5544:hb_font_t::subtract_glyph_h_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +5545:hb_font_t::guess_v_origin_minus_h_origin\28unsigned\20int\2c\20int*\2c\20int*\29 +5546:hb_font_t::get_variation_glyph\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\29 +5547:hb_font_t::get_glyph_v_origin_with_fallback\28unsigned\20int\2c\20int*\2c\20int*\29 +5548:hb_font_t::get_glyph_v_kerning\28unsigned\20int\2c\20unsigned\20int\29 +5549:hb_font_t::get_glyph_h_kerning\28unsigned\20int\2c\20unsigned\20int\29 +5550:hb_font_t::get_glyph_contour_point\28unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\29 +5551:hb_font_t::get_font_h_extents\28hb_font_extents_t*\29 +5552:hb_font_t::draw_glyph\28unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\29 +5553:hb_font_set_variations +5554:hb_font_set_funcs +5555:hb_font_get_variation_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +5556:hb_font_get_font_h_extents_nil\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +5557:hb_font_funcs_set_variation_glyph_func +5558:hb_font_funcs_set_nominal_glyphs_func +5559:hb_font_funcs_set_nominal_glyph_func +5560:hb_font_funcs_set_glyph_h_advances_func +5561:hb_font_funcs_set_glyph_extents_func +5562:hb_font_funcs_create +5563:hb_font_destroy +5564:hb_face_destroy +5565:hb_face_create_for_tables +5566:hb_draw_move_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +5567:hb_draw_funcs_t::emit_move_to\28void*\2c\20hb_draw_state_t&\2c\20float\2c\20float\29 +5568:hb_draw_funcs_set_quadratic_to_func +5569:hb_draw_funcs_set_move_to_func +5570:hb_draw_funcs_set_line_to_func +5571:hb_draw_funcs_set_cubic_to_func +5572:hb_draw_funcs_destroy +5573:hb_draw_funcs_create +5574:hb_draw_extents_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +5575:hb_cache_t<24u\2c\2016u\2c\208u\2c\20true>::clear\28\29 +5576:hb_buffer_t::sort\28unsigned\20int\2c\20unsigned\20int\2c\20int\20\28*\29\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29\29 +5577:hb_buffer_t::safe_to_insert_tatweel\28unsigned\20int\2c\20unsigned\20int\29 +5578:hb_buffer_t::next_glyphs\28unsigned\20int\29 +5579:hb_buffer_t::message_impl\28hb_font_t*\2c\20char\20const*\2c\20void*\29 +5580:hb_buffer_t::delete_glyphs_inplace\28bool\20\28*\29\28hb_glyph_info_t\20const*\29\29 +5581:hb_buffer_t::clear\28\29 +5582:hb_buffer_t::add\28unsigned\20int\2c\20unsigned\20int\29 +5583:hb_buffer_get_glyph_positions +5584:hb_buffer_diff +5585:hb_buffer_clear_contents +5586:hb_buffer_add_utf8 +5587:hb_bounds_t::union_\28hb_bounds_t\20const&\29 +5588:hb_blob_t::destroy_user_data\28\29 +5589:hb_blob_t*\20hb_sanitize_context_t::sanitize_blob\28hb_blob_t*\29 +5590:hb_array_t::hash\28\29\20const +5591:hb_array_t::cmp\28hb_array_t\20const&\29\20const +5592:hb_array_t>::qsort\28int\20\28*\29\28void\20const*\2c\20void\20const*\29\29 +5593:hb_array_t::__next__\28\29 +5594:hb_aat_map_builder_t::feature_info_t\20const*\20hb_vector_t::bsearch\28hb_aat_map_builder_t::feature_info_t\20const&\2c\20hb_aat_map_builder_t::feature_info_t\20const*\29\20const +5595:hb_aat_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +5596:hb_aat_map_builder_t::feature_info_t::cmp\28hb_aat_map_builder_t::feature_info_t\20const&\29\20const +5597:hb_aat_layout_remove_deleted_glyphs\28hb_buffer_t*\29 +5598:has_msaa_render_buffer\28GrSurfaceProxy\20const*\2c\20GrGLCaps\20const&\29 +5599:hair_cubic\28SkPoint\20const*\2c\20SkRegion\20const*\2c\20SkBlitter*\2c\20void\20\28*\29\28SkPoint\20const*\2c\20int\2c\20SkRegion\20const*\2c\20SkBlitter*\29\29 +5600:getint +5601:get_win_string +5602:get_paint\28GrAA\2c\20unsigned\20char\29 +5603:get_layer_mapping_and_bounds\28SkSpan>\2c\20SkMatrix\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\2c\20float\29::$_0::operator\28\29\28int\29\20const +5604:get_dst_swizzle_and_store\28GrColorType\2c\20SkRasterPipelineOp*\2c\20LumMode*\2c\20bool*\2c\20bool*\29 +5605:get_driver_and_version\28GrGLStandard\2c\20GrGLVendor\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +5606:get_apple_string +5607:getSingleRun\28UBiDi*\2c\20unsigned\20char\29 +5608:getRunFromLogicalIndex\28UBiDi*\2c\20int\29 +5609:getMirror\28int\2c\20unsigned\20short\29\20\28.8959\29 +5610:geometric_overlap\28SkRect\20const&\2c\20SkRect\20const&\29 +5611:geometric_contains\28SkRect\20const&\2c\20SkRect\20const&\29 +5612:gen_key\28skgpu::KeyBuilder*\2c\20GrProgramInfo\20const&\2c\20GrCaps\20const&\29 +5613:gen_fp_key\28GrFragmentProcessor\20const&\2c\20GrCaps\20const&\2c\20skgpu::KeyBuilder*\29 +5614:gather_uniforms_and_check_for_main\28SkSL::Program\20const&\2c\20std::__2::vector>*\2c\20std::__2::vector>*\2c\20SkRuntimeEffect::Uniform::Flags\2c\20unsigned\20long*\29 +5615:fwrite +5616:ft_var_to_normalized +5617:ft_var_load_item_variation_store +5618:ft_var_load_hvvar +5619:ft_var_load_avar +5620:ft_var_get_value_pointer +5621:ft_var_get_item_delta +5622:ft_var_apply_tuple +5623:ft_set_current_renderer +5624:ft_recompute_scaled_metrics +5625:ft_mem_strcpyn +5626:ft_mem_dup +5627:ft_hash_num_lookup +5628:ft_gzip_alloc +5629:ft_glyphslot_preset_bitmap +5630:ft_glyphslot_done +5631:ft_corner_orientation +5632:ft_corner_is_flat +5633:ft_cmap_done_internal +5634:frexp +5635:fread +5636:fquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5637:fp_force_eval +5638:fp_barrier +5639:formulate_F1DotF2\28float\20const*\2c\20float*\29 +5640:formulate_F1DotF2\28double\20const*\2c\20double*\29 +5641:format_alignment\28SkMask::Format\29 +5642:format1_names\28unsigned\20int\29 +5643:fopen +5644:fold_opacity_layer_color_to_paint\28SkPaint\20const*\2c\20bool\2c\20SkPaint*\29 +5645:fmodl +5646:float\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +5647:fline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5648:first_axis_intersection\28double\20const*\2c\20bool\2c\20double\2c\20double*\29 +5649:fiprintf +5650:find_unicode_charmap +5651:find_diff_pt\28SkPoint\20const*\2c\20int\2c\20int\2c\20int\29 +5652:fillable\28SkRect\20const&\29 +5653:fileno +5654:fcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5655:fconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5656:exp2f_\28float\29 +5657:eval_cubic_pts\28float\2c\20float\2c\20float\2c\20float\2c\20float\29 +5658:eval_cubic_derivative\28SkPoint\20const*\2c\20float\29 +5659:emptyOnNull\28sk_sp&&\29 +5660:elliptical_effect_uses_scale\28GrShaderCaps\20const&\2c\20SkRRect\20const&\29 +5661:edges_too_close\28SkAnalyticEdge*\2c\20SkAnalyticEdge*\2c\20int\29 +5662:edge_line_needs_recursion\28SkPoint\20const&\2c\20SkPoint\20const&\29 +5663:eat_space_sep_strings\28skia_private::TArray*\2c\20char\20const*\29 +5664:draw_rect_as_path\28SkDrawBase\20const&\2c\20SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\29 +5665:draw_nine\28SkMask\20const&\2c\20SkIRect\20const&\2c\20SkIPoint\20const&\2c\20bool\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +5666:dquad_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5667:double\20std::__2::__num_get_float\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20unsigned\20int&\29 +5668:do_newlocale +5669:do_fixed +5670:doWriteReverse\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +5671:doWriteForward\28char16_t\20const*\2c\20int\2c\20char16_t*\2c\20int\2c\20unsigned\20short\2c\20UErrorCode*\29 +5672:dline_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5673:distance_to_sentinel\28int\20const*\29 +5674:dispose_chunk +5675:diff_to_shift\28int\2c\20int\2c\20int\29 +5676:destroy_size +5677:destroy_charmaps +5678:decompose_current_character\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\29 +5679:decompose\28hb_ot_shape_normalize_context_t\20const*\2c\20bool\2c\20unsigned\20int\29 +5680:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::Make\28SkArenaAlloc*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5681:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&\2c\20skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathCurveTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5682:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::MeshGP::Make\28SkArenaAlloc*\2c\20sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5683:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker\2c\20int&>\28int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5684:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkShaderBase&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTransformShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5685:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5686:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::UniqueKey\20const&\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29>\28GrThreadSafeCache::Entry&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5687:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrRRectShadowGeoProc::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5688:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28GrQuadEffect::Make\28SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrCaps\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5689:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrPipeline::InitArgs&\2c\20GrProcessorSet&&\2c\20GrAppliedClip&&\29::'lambda'\28void*\29>\28GrPipeline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5690:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldA8TextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20float\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5691:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28CircleGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +5692:decltype\28fp0\28\28SkRecords::NoOp\29\28\29\29\29\20SkRecord::visit\28int\2c\20SkRecords::Draw&\29\20const +5693:decltype\28fp0\28\28SkRecords::NoOp*\29\28nullptr\29\29\29\20SkRecord::mutate\28int\2c\20SkRecord::Destroyer&\29 +5694:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +5695:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>>::__generic_construct\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__ctor\2c\20std::__2::unique_ptr>>>&\2c\20std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&>\28std::__2::__variant_detail::__move_constructor\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&&\29 +5696:dcubic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +5697:dcubic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5698:dconic_intersect_ray\28SkDCurve\20const&\2c\20SkDLine\20const&\2c\20SkIntersections*\29 +5699:data_destroy_arabic\28void*\29 +5700:data_create_arabic\28hb_ot_shape_plan_t\20const*\29 +5701:cycle +5702:cubic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5703:cubic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5704:cubic_delta_from_line\28int\2c\20int\2c\20int\2c\20int\29 +5705:crop_simple_rect\28SkRect\20const&\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +5706:crop_rect\28SkRect\20const&\2c\20float*\2c\20float*\2c\20float*\2c\20float*\2c\20float*\29 +5707:count_scalable_pixels\28int\20const*\2c\20int\2c\20bool\2c\20int\2c\20int\29 +5708:copysignl +5709:copy_mask_to_cacheddata\28SkMaskBuilder*\29 +5710:copy_bitmap_subset\28SkBitmap\20const&\2c\20SkIRect\20const&\29 +5711:contour_point_vector_t::extend\28hb_array_t\20const&\29 +5712:conservative_round_to_int\28SkRect\20const&\29 +5713:conic_intercept_v\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5714:conic_intercept_h\28SkPoint\20const*\2c\20float\2c\20float\2c\20double*\29 +5715:conic_eval_tan\28double\20const*\2c\20float\2c\20double\29 +5716:conic_deriv_coeff\28double\20const*\2c\20float\2c\20double*\29 +5717:compute_stroke_size\28SkPaint\20const&\2c\20SkMatrix\20const&\29 +5718:compute_pos_tan\28SkPoint\20const*\2c\20unsigned\20int\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +5719:compute_normal\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20SkPoint*\29 +5720:compute_intersection\28OffsetSegment\20const&\2c\20OffsetSegment\20const&\2c\20SkPoint*\2c\20float*\2c\20float*\29 +5721:compute_anti_width\28short\20const*\29 +5722:compose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +5723:compare_offsets +5724:clip_to_limit\28SkRegion\20const&\2c\20SkRegion*\29 +5725:clip_line\28SkPoint*\2c\20SkRect\20const&\2c\20float\2c\20float\29 +5726:clipHandlesSprite\28SkRasterClip\20const&\2c\20int\2c\20int\2c\20SkPixmap\20const&\29 +5727:clean_sampling_for_constraint\28SkSamplingOptions\20const&\2c\20SkCanvas::SrcRectConstraint\29 +5728:clamp_to_zero\28SkPoint*\29 +5729:clamp\28SkPoint\2c\20SkPoint\2c\20SkPoint\2c\20GrTriangulator::Comparator\20const&\29 +5730:chop_mono_cubic_at_x\28SkPoint*\2c\20float\2c\20SkPoint*\29 +5731:chopMonoQuadAt\28float\2c\20float\2c\20float\2c\20float\2c\20float*\29 +5732:chopMonoQuadAtY\28SkPoint*\2c\20float\2c\20float*\29 +5733:chopMonoQuadAtX\28SkPoint*\2c\20float\2c\20float*\29 +5734:checkint +5735:check_write_and_transfer_input\28GrGLTexture*\29 +5736:check_name\28SkString\20const&\29 +5737:check_backend_texture\28GrBackendTexture\20const&\2c\20GrGLCaps\20const&\2c\20GrGLTexture::Desc*\2c\20bool\29 +5738:char*\20std::__2::copy\5babi:nn180100\5d\2c\20char*>\28std::__2::__wrap_iter\2c\20std::__2::__wrap_iter\2c\20char*\29 +5739:char*\20std::__2::copy\5babi:nn180100\5d\28char\20const*\2c\20char\20const*\2c\20char*\29 +5740:char*\20std::__2::__constexpr_memmove\5babi:nn180100\5d\28char*\2c\20char\20const*\2c\20std::__2::__element_count\29 +5741:char*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29 +5742:cff_vstore_done +5743:cff_subfont_load +5744:cff_subfont_done +5745:cff_size_select +5746:cff_parser_run +5747:cff_parser_init +5748:cff_make_private_dict +5749:cff_load_private_dict +5750:cff_index_get_name +5751:cff_glyph_load +5752:cff_get_kerning +5753:cff_get_glyph_data +5754:cff_fd_select_get +5755:cff_charset_compute_cids +5756:cff_builder_init +5757:cff_builder_add_point1 +5758:cff_builder_add_point +5759:cff_builder_add_contour +5760:cff_blend_check_vector +5761:cff_blend_build_vector +5762:cff1_path_param_t::end_path\28\29 +5763:cf2_stack_pop +5764:cf2_hintmask_setCounts +5765:cf2_hintmask_read +5766:cf2_glyphpath_pushMove +5767:cf2_getSeacComponent +5768:cf2_freeSeacComponent +5769:cf2_computeDarkening +5770:cf2_arrstack_setNumElements +5771:cf2_arrstack_push +5772:cbrt +5773:can_use_hw_blend_equation\28skgpu::BlendEquation\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\29 +5774:can_proxy_use_scratch\28GrCaps\20const&\2c\20GrSurfaceProxy*\29 +5775:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_3::operator\28\29\28float\29\20const +5776:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_2::operator\28\29\28float\29\20const +5777:calculate_path_gap\28float\2c\20float\2c\20SkPath\20const&\29::$_0::operator\28\29\28float\29\20const +5778:build_key\28skgpu::ResourceKey::Builder*\2c\20GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\29 +5779:build_intervals\28int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const*\2c\20float\20const*\2c\20int\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20SkRGBA4f<\28SkAlphaType\292>*\2c\20float*\29 +5780:bracketProcessChar\28BracketData*\2c\20int\29 +5781:bracketInit\28UBiDi*\2c\20BracketData*\29 +5782:bounds_t::merge\28bounds_t\20const&\29 +5783:bottom_collinear\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\29 +5784:bool\20std::__2::operator==\5babi:ne180100\5d>\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +5785:bool\20std::__2::operator==\5babi:ne180100\5d\28std::__2::variant\20const&\2c\20std::__2::variant\20const&\29 +5786:bool\20std::__2::operator!=\5babi:ne180100\5d\28std::__2::variant\20const&\2c\20std::__2::variant\20const&\29 +5787:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::RunBlock*\2c\20skia::textlayout::OneLineShaper::finish\28skia::textlayout::Block\20const&\2c\20float\2c\20float&\29::$_0&\29 +5788:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::ProgramElement\20const**\2c\20SkSL::ProgramElement\20const**\2c\20SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::sortNewElements\28\29::'lambda'\28SkSL::ProgramElement\20const*\2c\20SkSL::ProgramElement\20const*\29&\29 +5789:bool\20std::__2::__insertion_sort_incomplete\5babi:ne180100\5d\28SkSL::FunctionDefinition\20const**\2c\20SkSL::FunctionDefinition\20const**\2c\20SkSL::Transform::FindAndDeclareBuiltinFunctions\28SkSL::Program&\29::$_0&\29 +5790:bool\20set_point_length\28SkPoint*\2c\20float\2c\20float\2c\20float\2c\20float*\29 +5791:bool\20is_parallel\28SkDLine\20const&\2c\20SkTCurve\20const&\29 +5792:bool\20hb_sanitize_context_t::check_array>\28OT::IntType\20const*\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +5793:bool\20hb_sanitize_context_t::check_array\28OT::Index\20const*\2c\20unsigned\20int\29\20const +5794:bool\20hb_sanitize_context_t::check_array\28AAT::Feature\20const*\2c\20unsigned\20int\29\20const +5795:bool\20hb_sanitize_context_t::check_array>\28AAT::Entry\20const*\2c\20unsigned\20int\29\20const +5796:bool\20apply_string\28OT::hb_ot_apply_context_t*\2c\20GSUBProxy::Lookup\20const&\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\29 +5797:bool\20OT::hb_accelerate_subtables_context_t::cache_func_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\2c\20bool\29 +5798:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5799:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5800:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5801:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5802:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5803:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5804:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5805:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5806:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5807:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5808:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5809:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5810:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5811:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5812:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5813:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5814:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5815:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +5816:bool\20OT::Paint::sanitize<>\28hb_sanitize_context_t*\29\20const +5817:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5818:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5819:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5820:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5821:bool\20OT::OffsetTo\2c\20true>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\2c\20unsigned\20int&&\29\20const +5822:bool\20OT::OffsetTo\2c\20true>::serialize_serialize\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&>\28hb_serialize_context_t*\2c\20hb_map_iter_t\2c\20hb_array_t>\2c\20$_7\20const&\2c\20\28hb_function_sortedness_t\291\2c\20\28void*\290>&\29 +5823:bool\20OT::OffsetTo\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5824:bool\20OT::OffsetTo\2c\20true>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\2c\20unsigned\20int&&\29\20const +5825:bool\20OT::OffsetTo\2c\20OT::IntType\2c\20true>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5826:bool\20OT::OffsetTo\2c\20true>::sanitize\28hb_sanitize_context_t*\2c\20void\20const*\2c\20AAT::track\20const*&&\29\20const +5827:bool\20OT::OffsetTo>\2c\20OT::IntType\2c\20false>::sanitize<>\28hb_sanitize_context_t*\2c\20void\20const*\29\20const +5828:bool\20OT::GSUBGPOS::sanitize\28hb_sanitize_context_t*\29\20const +5829:bool\20OT::GSUBGPOS::sanitize\28hb_sanitize_context_t*\29\20const +5830:bool\20GrTTopoSort_Visit\28GrRenderTask*\2c\20unsigned\20int*\29 +5831:blur_column\28void\20\28*\29\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29\2c\20skvx::Vec<8\2c\20unsigned\20short>\20\28*\29\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29\2c\20int\2c\20int\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20unsigned\20char\20const*\2c\20unsigned\20long\2c\20int\2c\20unsigned\20char*\2c\20unsigned\20long\29 +5832:blit_two_alphas\28AdditiveBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +5833:blit_full_alpha\28AdditiveBlitter*\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20bool\29 +5834:blender_requires_shader\28SkBlender\20const*\29 +5835:bits_to_runs\28SkBlitter*\2c\20int\2c\20int\2c\20unsigned\20char\20const*\2c\20unsigned\20char\2c\20long\2c\20unsigned\20char\29 +5836:between_closed\28double\2c\20double\2c\20double\2c\20double\2c\20bool\29 +5837:barycentric_coords\28float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\2c\20skvx::Vec<4\2c\20float>*\29 +5838:auto&&\20std::__2::__generic_get\5babi:ne180100\5d<0ul\2c\20std::__2::variant\20const&>\28std::__2::variant\20const&\29 +5839:atanf +5840:are_radius_check_predicates_valid\28float\2c\20float\2c\20float\29 +5841:arabic_fallback_plan_destroy\28arabic_fallback_plan_t*\29 +5842:apply_forward\28OT::hb_ot_apply_context_t*\2c\20OT::hb_ot_layout_lookup_accelerator_t\20const&\2c\20unsigned\20int\29 +5843:apply_fill_type\28SkPathFillType\2c\20int\29 +5844:apply_fill_type\28SkPathFillType\2c\20GrTriangulator::Poly*\29 +5845:apply_alpha_and_colorfilter\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20SkPaint\20const&\29 +5846:append_texture_swizzle\28SkString*\2c\20skgpu::Swizzle\29 +5847:append_multitexture_lookup\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20int\2c\20GrGLSLVarying\20const&\2c\20char\20const*\2c\20char\20const*\29 +5848:append_color_output\28PorterDuffXferProcessor\20const&\2c\20GrGLSLXPFragmentBuilder*\2c\20skgpu::BlendFormula::OutputType\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29 +5849:antifilldot8\28int\2c\20int\2c\20int\2c\20int\2c\20SkBlitter*\2c\20bool\29 +5850:analysis_properties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\2c\20SkBlendMode\29 +5851:afm_stream_skip_spaces +5852:afm_stream_read_string +5853:afm_stream_read_one +5854:af_sort_and_quantize_widths +5855:af_shaper_get_elem +5856:af_loader_compute_darkening +5857:af_latin_metrics_scale_dim +5858:af_latin_hints_detect_features +5859:af_hint_normal_stem +5860:af_glyph_hints_align_weak_points +5861:af_glyph_hints_align_strong_points +5862:af_face_globals_new +5863:af_cjk_metrics_scale_dim +5864:af_cjk_metrics_scale +5865:af_cjk_metrics_init_widths +5866:af_cjk_metrics_check_digits +5867:af_cjk_hints_init +5868:af_cjk_hints_detect_features +5869:af_cjk_hints_compute_blue_edges +5870:af_cjk_hints_apply +5871:af_cjk_get_standard_widths +5872:af_cjk_compute_stem_width +5873:af_axis_hints_new_edge +5874:adjust_mipmapped\28skgpu::Mipmapped\2c\20SkBitmap\20const&\2c\20GrCaps\20const*\29 +5875:add_line\28SkPoint\20const*\2c\20skia_private::TArray*\29 +5876:add_const_color\28SkRasterPipeline_GradientCtx*\2c\20unsigned\20long\2c\20SkRGBA4f<\28SkAlphaType\292>\29 +5877:a_ctz_32 +5878:_pow10\28unsigned\20int\29 +5879:_hb_preprocess_text_vowel_constraints\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +5880:_hb_ot_shape +5881:_hb_options_init\28\29 +5882:_hb_grapheme_group_func\28hb_glyph_info_t\20const&\2c\20hb_glyph_info_t\20const&\29 +5883:_hb_font_create\28hb_face_t*\29 +5884:_hb_fallback_shape +5885:_glyf_get_advance_with_var_unscaled\28hb_font_t*\2c\20unsigned\20int\2c\20bool\29 +5886:_emscripten_timeout +5887:__vfprintf_internal +5888:__trunctfsf2 +5889:__tan +5890:__strftime_l +5891:__rem_pio2_large +5892:__nl_langinfo_l +5893:__math_xflowf +5894:__math_uflowf +5895:__math_oflowf +5896:__math_invalidf +5897:__loc_is_allocated +5898:__getf2 +5899:__get_locale +5900:__ftello_unlocked +5901:__floatscan +5902:__expo2 +5903:__divtf3 +5904:__cxxabiv1::__base_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +5905:__cxxabiv1::\28anonymous\20namespace\29::GuardObject<__cxxabiv1::\28anonymous\20namespace\29::InitByteGlobalMutex<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex\2c\20__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppMutex>::instance\2c\20__cxxabiv1::\28anonymous\20namespace\29::GlobalStatic<__cxxabiv1::\28anonymous\20namespace\29::LibcppCondVar>::instance\2c\20\28unsigned\20int\20\28*\29\28\29\290>>::GuardObject\28unsigned\20int*\29 +5906:_ZZN19GrGeometryProcessor11ProgramImpl17collectTransformsEP19GrGLSLVertexBuilderP20GrGLSLVaryingHandlerP20GrGLSLUniformHandler12GrShaderTypeRK11GrShaderVarSA_RK10GrPipelineEN3$_0clISE_EEvRT_RK19GrFragmentProcessorbPSJ_iNS0_9BaseCoordE +5907:_ZZN18GrGLProgramBuilder23computeCountsAndStridesEjRK19GrGeometryProcessorbENK3$_0clINS0_9AttributeEEEDaiRKT_ +5908:\28anonymous\20namespace\29::texture_color\28SkRGBA4f<\28SkAlphaType\293>\2c\20float\2c\20GrColorType\2c\20GrColorInfo\20const&\29 +5909:\28anonymous\20namespace\29::supported_aa\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrAA\29 +5910:\28anonymous\20namespace\29::set_uv_quad\28SkPoint\20const*\2c\20\28anonymous\20namespace\29::BezierVertex*\29 +5911:\28anonymous\20namespace\29::safe_to_ignore_subset_rect\28GrAAType\2c\20SkFilterMode\2c\20DrawQuad\20const&\2c\20SkRect\20const&\29 +5912:\28anonymous\20namespace\29::rrect_type_to_vert_count\28\28anonymous\20namespace\29::RRectType\29 +5913:\28anonymous\20namespace\29::proxy_normalization_params\28GrSurfaceProxy\20const*\2c\20GrSurfaceOrigin\29 +5914:\28anonymous\20namespace\29::normalize_src_quad\28\28anonymous\20namespace\29::NormalizationParams\20const&\2c\20GrQuad*\29 +5915:\28anonymous\20namespace\29::normalize_and_inset_subset\28SkFilterMode\2c\20\28anonymous\20namespace\29::NormalizationParams\20const&\2c\20SkRect\20const*\29 +5916:\28anonymous\20namespace\29::next_gen_id\28\29 +5917:\28anonymous\20namespace\29::morphology_pass\28skif::Context\20const&\2c\20skif::FilterResult\20const&\2c\20\28anonymous\20namespace\29::MorphType\2c\20\28anonymous\20namespace\29::MorphDirection\2c\20int\29 +5918:\28anonymous\20namespace\29::make_non_convex_fill_op\28GrRecordingContext*\2c\20SkArenaAlloc*\2c\20skgpu::ganesh::FillPathFlags\2c\20GrAAType\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20GrPaint&&\29 +5919:\28anonymous\20namespace\29::is_visible\28SkRect\20const&\2c\20SkIRect\20const&\29 +5920:\28anonymous\20namespace\29::is_degen_quad_or_conic\28SkPoint\20const*\2c\20float*\29 +5921:\28anonymous\20namespace\29::init_vertices_paint\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkBlender*\2c\20bool\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +5922:\28anonymous\20namespace\29::get_hbFace_cache\28\29 +5923:\28anonymous\20namespace\29::gather_lines_and_quads\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\2c\20skia_private::TArray*\29::$_1::operator\28\29\28SkPoint\20const*\2c\20SkPoint\20const*\2c\20bool\29\20const +5924:\28anonymous\20namespace\29::draw_to_sw_mask\28GrSWMaskHelper*\2c\20skgpu::ganesh::ClipStack::Element\20const&\2c\20bool\29 +5925:\28anonymous\20namespace\29::draw_tiled_image\28SkCanvas*\2c\20std::__2::function\20\28SkIRect\29>\2c\20SkISize\2c\20int\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20SkIRect\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkCanvas::SrcRectConstraint\2c\20SkSamplingOptions\29 +5926:\28anonymous\20namespace\29::draw_path\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20skgpu::ganesh::PathRenderer*\2c\20GrHardClip\20const&\2c\20SkIRect\20const&\2c\20GrUserStencilSettings\20const*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20GrAA\29 +5927:\28anonymous\20namespace\29::determine_clipped_src_rect\28SkIRect\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20SkISize\20const&\2c\20SkRect\20const*\29 +5928:\28anonymous\20namespace\29::create_data\28int\2c\20bool\2c\20float\29 +5929:\28anonymous\20namespace\29::copyFTBitmap\28FT_Bitmap_\20const&\2c\20SkMaskBuilder*\29 +5930:\28anonymous\20namespace\29::contains_scissor\28GrScissorState\20const&\2c\20GrScissorState\20const&\29 +5931:\28anonymous\20namespace\29::colrv1_start_glyph_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20unsigned\20short\2c\20FT_Color_Root_Transform_\2c\20skia_private::THashSet*\29 +5932:\28anonymous\20namespace\29::colrv1_start_glyph\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20unsigned\20short\2c\20FT_Color_Root_Transform_\2c\20skia_private::THashSet*\29 +5933:\28anonymous\20namespace\29::colrv1_draw_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_COLR_Paint_\20const&\29 +5934:\28anonymous\20namespace\29::colrv1_configure_skpaint\28FT_FaceRec_*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_COLR_Paint_\20const&\2c\20SkPaint*\29 +5935:\28anonymous\20namespace\29::can_use_draw_texture\28SkPaint\20const&\2c\20SkSamplingOptions\20const&\29 +5936:\28anonymous\20namespace\29::axis_aligned_quad_size\28GrQuad\20const&\29 +5937:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29 +5938:\28anonymous\20namespace\29::YUVPlanesKey::YUVPlanesKey\28unsigned\20int\29 +5939:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29 +5940:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29 +5941:\28anonymous\20namespace\29::TriangulatingPathOp::TriangulatingPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrAAType\2c\20GrUserStencilSettings\20const*\29 +5942:\28anonymous\20namespace\29::TriangulatingPathOp::Triangulate\28GrEagerVertexAllocator*\2c\20SkMatrix\20const&\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\2c\20float\2c\20bool*\29 +5943:\28anonymous\20namespace\29::TriangulatingPathOp::CreateKey\28skgpu::UniqueKey*\2c\20GrStyledShape\20const&\2c\20SkIRect\20const&\29 +5944:\28anonymous\20namespace\29::TransformedMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +5945:\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +5946:\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +5947:\28anonymous\20namespace\29::TransformedMaskSubRun::glyphCount\28\29\20const +5948:\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +5949:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29 +5950:\28anonymous\20namespace\29::TextureOpImpl::propagateCoverageAAThroughoutChain\28\29 +5951:\28anonymous\20namespace\29::TextureOpImpl::numChainedQuads\28\29\20const +5952:\28anonymous\20namespace\29::TextureOpImpl::characterize\28\28anonymous\20namespace\29::TextureOpImpl::Desc*\29\20const +5953:\28anonymous\20namespace\29::TextureOpImpl::appendQuad\28DrawQuad*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\29 +5954:\28anonymous\20namespace\29::TextureOpImpl::Make\28GrRecordingContext*\2c\20GrTextureSetEntry*\2c\20int\2c\20int\2c\20SkFilterMode\2c\20SkMipmapMode\2c\20skgpu::ganesh::TextureOp::Saturate\2c\20GrAAType\2c\20SkCanvas::SrcRectConstraint\2c\20SkMatrix\20const&\2c\20sk_sp\29 +5955:\28anonymous\20namespace\29::TextureOpImpl::FillInVertices\28GrCaps\20const&\2c\20\28anonymous\20namespace\29::TextureOpImpl*\2c\20\28anonymous\20namespace\29::TextureOpImpl::Desc*\2c\20char*\29 +5956:\28anonymous\20namespace\29::TextureOpImpl::Desc::totalSizeInBytes\28\29\20const +5957:\28anonymous\20namespace\29::TextureOpImpl::Desc*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc>\28\29 +5958:\28anonymous\20namespace\29::TextureOpImpl::ClassID\28\29 +5959:\28anonymous\20namespace\29::SpotVerticesFactory::makeVertices\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint*\29\20const +5960:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::hb_script_for_unichar\28int\29 +5961:\28anonymous\20namespace\29::SkQuadCoeff::SkQuadCoeff\28SkPoint\20const*\29 +5962:\28anonymous\20namespace\29::SkMorphologyImageFilter::requiredInput\28skif::Mapping\20const&\2c\20skif::LayerSpace\29\20const +5963:\28anonymous\20namespace\29::SkMorphologyImageFilter::kernelOutputBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\29\20const +5964:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::requiredInput\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\29\20const +5965:\28anonymous\20namespace\29::SkEmptyTypeface::onMakeClone\28SkFontArguments\20const&\29\20const +5966:\28anonymous\20namespace\29::SkCropImageFilter::requiredInput\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\29\20const +5967:\28anonymous\20namespace\29::SkConicCoeff::SkConicCoeff\28SkConic\20const&\29 +5968:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29 +5969:\28anonymous\20namespace\29::SkBlurImageFilter::mapSigma\28skif::Mapping\20const&\2c\20bool\29\20const +5970:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29 +5971:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29 +5972:\28anonymous\20namespace\29::ShaperHarfBuzz::~ShaperHarfBuzz\28\29 +5973:\28anonymous\20namespace\29::ShadowedPath::keyBytes\28\29\20const +5974:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29 +5975:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29 +5976:\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12127 +5977:\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +5978:\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +5979:\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +5980:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29 +5981:\28anonymous\20namespace\29::RectsBlurKey::RectsBlurKey\28float\2c\20SkBlurStyle\2c\20SkRect\20const*\2c\20int\29 +5982:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const::'lambda'\28float\29::operator\28\29\28float\29\20const +5983:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29 +5984:\28anonymous\20namespace\29::RRectBlurKey::RRectBlurKey\28float\2c\20SkRRect\20const&\2c\20SkBlurStyle\29 +5985:\28anonymous\20namespace\29::PlanGauss::PlanGauss\28double\29 +5986:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29 +5987:\28anonymous\20namespace\29::PathOpSubmitter::~PathOpSubmitter\28\29 +5988:\28anonymous\20namespace\29::PathGeoBuilder::createMeshAndPutBackReserve\28\29 +5989:\28anonymous\20namespace\29::PathGeoBuilder::allocNewBuffers\28\29 +5990:\28anonymous\20namespace\29::PathGeoBuilder::addQuad\28SkPoint\20const*\2c\20float\2c\20float\29 +5991:\28anonymous\20namespace\29::Pass::blur\28int\2c\20int\2c\20int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +5992:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29 +5993:\28anonymous\20namespace\29::MipMapKey::MipMapKey\28SkBitmapCacheDesc\20const&\29 +5994:\28anonymous\20namespace\29::MipLevelHelper::allocAndInit\28SkArenaAlloc*\2c\20SkSamplingOptions\20const&\2c\20SkTileMode\2c\20SkTileMode\29 +5995:\28anonymous\20namespace\29::MipLevelHelper::MipLevelHelper\28\29 +5996:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29 +5997:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29 +5998:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20sk_sp\2c\20GrPrimitiveType\20const*\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +5999:\28anonymous\20namespace\29::MeshOp::MeshOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMesh\20const&\2c\20skia_private::TArray>\2c\20true>\2c\20GrAAType\2c\20sk_sp\2c\20SkMatrix\20const&\29 +6000:\28anonymous\20namespace\29::MeshOp::Mesh::indices\28\29\20const +6001:\28anonymous\20namespace\29::MeshOp::Mesh::Mesh\28SkMesh\20const&\29 +6002:\28anonymous\20namespace\29::MeshOp::ClassID\28\29 +6003:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29 +6004:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29 +6005:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineStruct\28char\20const*\29 +6006:\28anonymous\20namespace\29::Iter::next\28\29 +6007:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29 +6008:\28anonymous\20namespace\29::FillRectOpImpl::tessellate\28skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20char*\29\20const +6009:\28anonymous\20namespace\29::FillRectOpImpl::FillRectOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\2c\20GrAAType\2c\20DrawQuad*\2c\20GrUserStencilSettings\20const*\2c\20GrSimpleMeshDrawOpHelper::InputFlags\29 +6010:\28anonymous\20namespace\29::ExternalWebGLTexture::~ExternalWebGLTexture\28\29 +6011:\28anonymous\20namespace\29::EllipticalRRectEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +6012:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29 +6013:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29 +6014:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29 +6015:\28anonymous\20namespace\29::DrawAtlasOpImpl::DrawAtlasOpImpl\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20GrAAType\2c\20int\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\29 +6016:\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +6017:\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +6018:\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +6019:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29 +6020:\28anonymous\20namespace\29::DefaultPathOp::programInfo\28\29 +6021:\28anonymous\20namespace\29::DefaultPathOp::primType\28\29\20const +6022:\28anonymous\20namespace\29::DefaultPathOp::PathData::PathData\28\28anonymous\20namespace\29::DefaultPathOp::PathData&&\29 +6023:\28anonymous\20namespace\29::DefaultPathOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +6024:\28anonymous\20namespace\29::DefaultPathOp::DefaultPathOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkPath\20const&\2c\20float\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20bool\2c\20GrAAType\2c\20SkRect\20const&\2c\20GrUserStencilSettings\20const*\29 +6025:\28anonymous\20namespace\29::ClipGeometry\20\28anonymous\20namespace\29::get_clip_geometry\28skgpu::ganesh::ClipStack::SaveRecord\20const&\2c\20skgpu::ganesh::ClipStack::Draw\20const&\29 +6026:\28anonymous\20namespace\29::CircularRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20unsigned\20int\2c\20SkRRect\20const&\29 +6027:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29 +6028:\28anonymous\20namespace\29::CachedTessellationsRec::CachedTessellationsRec\28SkResourceCache::Key\20const&\2c\20sk_sp<\28anonymous\20namespace\29::CachedTessellations>\29 +6029:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29 +6030:\28anonymous\20namespace\29::CachedTessellations::CachedTessellations\28\29 +6031:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29 +6032:\28anonymous\20namespace\29::BitmapKey::BitmapKey\28SkBitmapCacheDesc\20const&\29 +6033:\28anonymous\20namespace\29::AmbientVerticesFactory::makeVertices\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint*\29\20const +6034:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29 +6035:\28anonymous\20namespace\29::AAHairlineOp::PathData::PathData\28\28anonymous\20namespace\29::AAHairlineOp::PathData&&\29 +6036:\28anonymous\20namespace\29::AAHairlineOp::AAHairlineOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20unsigned\20char\2c\20SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkIRect\2c\20float\2c\20GrUserStencilSettings\20const*\29 +6037:ToUpperCase +6038:TextureSourceImageGenerator::~TextureSourceImageGenerator\28\29 +6039:TT_Set_Named_Instance +6040:TT_Save_Context +6041:TT_Hint_Glyph +6042:TT_DotFix14 +6043:TT_Done_Context +6044:StringBuffer\20apply_format_string<1024>\28char\20const*\2c\20void*\2c\20char\20\28&\29\20\5b1024\5d\2c\20SkString*\29 +6045:SortContourList\28SkOpContourHead**\2c\20bool\2c\20bool\29 +6046:Skwasm::Surface::_resizeCanvasToFit\28int\2c\20int\29 +6047:SkWriter32::writeString\28char\20const*\2c\20unsigned\20long\29 +6048:SkWriter32::writePoint3\28SkPoint3\20const&\29 +6049:SkWStream::writeScalarAsText\28float\29 +6050:SkWBuffer::padToAlign4\28\29 +6051:SkVertices::getSizes\28\29\20const +6052:SkVertices::Builder::init\28SkVertices::Desc\20const&\29 +6053:SkVertices::Builder::Builder\28SkVertices::VertexMode\2c\20int\2c\20int\2c\20unsigned\20int\29 +6054:SkUnicode_client::~SkUnicode_client\28\29 +6055:SkUnicode::convertUtf16ToUtf8\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +6056:SkUnicode::BidiRegion&\20std::__2::vector>::emplace_back\28unsigned\20long&\2c\20unsigned\20long&\2c\20unsigned\20char&\29 +6057:SkUTF::UTF16ToUTF8\28char*\2c\20int\2c\20unsigned\20short\20const*\2c\20unsigned\20long\29 +6058:SkUTF::ToUTF8\28int\2c\20char*\29 +6059:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29 +6060:SkTypeface_FreeTypeStream::SkTypeface_FreeTypeStream\28std::__2::unique_ptr>\2c\20SkString\2c\20SkFontStyle\20const&\2c\20bool\29 +6061:SkTypeface_FreeType::getFaceRec\28\29\20const +6062:SkTypeface_FreeType::SkTypeface_FreeType\28SkFontStyle\20const&\2c\20bool\29 +6063:SkTypeface_FreeType::GetUnitsPerEm\28FT_FaceRec_*\29 +6064:SkTypeface_Custom::~SkTypeface_Custom\28\29 +6065:SkTypeface_Custom::onGetFamilyName\28SkString*\29\20const +6066:SkTypeface::unicharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +6067:SkTypeface::onGetFixedPitch\28\29\20const +6068:SkTypeface::MakeEmpty\28\29 +6069:SkTransformShader::update\28SkMatrix\20const&\29 +6070:SkTextBlobBuilder::updateDeferredBounds\28\29 +6071:SkTextBlobBuilder::reserve\28unsigned\20long\29 +6072:SkTextBlobBuilder::allocRunPos\28SkFont\20const&\2c\20int\2c\20SkRect\20const*\29 +6073:SkTextBlobBuilder::TightRunBounds\28SkTextBlob::RunRecord\20const&\29 +6074:SkTextBlob::getIntercepts\28float\20const*\2c\20float*\2c\20SkPaint\20const*\29\20const +6075:SkTaskGroup::add\28std::__2::function\29 +6076:SkTSpan::split\28SkTSpan*\2c\20SkArenaAlloc*\29 +6077:SkTSpan::splitAt\28SkTSpan*\2c\20double\2c\20SkArenaAlloc*\29 +6078:SkTSpan::linearIntersects\28SkTCurve\20const&\29\20const +6079:SkTSpan::hullCheck\28SkTSpan\20const*\2c\20bool*\2c\20bool*\29 +6080:SkTSpan::contains\28double\29\20const +6081:SkTSect::unlinkSpan\28SkTSpan*\29 +6082:SkTSect::removeAllBut\28SkTSpan\20const*\2c\20SkTSpan*\2c\20SkTSect*\29 +6083:SkTSect::recoverCollapsed\28\29 +6084:SkTSect::intersects\28SkTSpan*\2c\20SkTSect*\2c\20SkTSpan*\2c\20int*\29 +6085:SkTSect::coincidentHasT\28double\29 +6086:SkTSect::boundsMax\28\29 +6087:SkTSect::addSplitAt\28SkTSpan*\2c\20double\29 +6088:SkTSect::addForPerp\28SkTSpan*\2c\20double\29 +6089:SkTSect::EndsEqual\28SkTSect\20const*\2c\20SkTSect\20const*\2c\20SkIntersections*\29 +6090:SkTMultiMap::reset\28\29 +6091:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29 +6092:SkTMaskGamma<3\2c\203\2c\203>::SkTMaskGamma\28float\2c\20float\29 +6093:SkTMaskGamma<3\2c\203\2c\203>::CanonicalColor\28unsigned\20int\29 +6094:SkTInternalLList::remove\28skgpu::ganesh::SmallPathShapeData*\29 +6095:SkTInternalLList<\28anonymous\20namespace\29::CacheImpl::Value>::remove\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +6096:SkTInternalLList<\28anonymous\20namespace\29::CacheImpl::Value>::addToHead\28\28anonymous\20namespace\29::CacheImpl::Value*\29 +6097:SkTInternalLList::remove\28TriangulationVertex*\29 +6098:SkTInternalLList::addToTail\28TriangulationVertex*\29 +6099:SkTInternalLList::Entry>::addToHead\28SkLRUCache::Entry*\29 +6100:SkTInternalLList>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry>::addToHead\28SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::Entry*\29 +6101:SkTInternalLList>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry>::addToHead\28SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::Entry*\29 +6102:SkTDynamicHash<\28anonymous\20namespace\29::CacheImpl::Value\2c\20SkImageFilterCacheKey\2c\20\28anonymous\20namespace\29::CacheImpl::Value>::find\28SkImageFilterCacheKey\20const&\29\20const +6103:SkTDStorage::SkTDStorage\28SkTDStorage&&\29 +6104:SkTDPQueue<\28anonymous\20namespace\29::RunIteratorQueue::Entry\2c\20&\28anonymous\20namespace\29::RunIteratorQueue::CompareEntry\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\2c\20\28int*\20\28*\29\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\20const&\29\290>::insert\28\28anonymous\20namespace\29::RunIteratorQueue::Entry\29 +6105:SkTDPQueue::remove\28GrGpuResource*\29 +6106:SkTDPQueue::percolateUpIfNecessary\28int\29 +6107:SkTDPQueue::percolateDownIfNecessary\28int\29 +6108:SkTDPQueue::insert\28GrGpuResource*\29 +6109:SkTDArray::append\28int\29 +6110:SkTDArray::append\28int\29 +6111:SkTDArray::push_back\28SkRecords::FillBounds::SaveBounds\20const&\29 +6112:SkTDArray::push_back\28SkOpPtT\20const*\20const&\29 +6113:SkTCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +6114:SkTCopyOnFirstWrite::writable\28\29 +6115:SkTCopyOnFirstWrite::writable\28\29 +6116:SkTConic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +6117:SkTConic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +6118:SkTConic::controlsInside\28\29\20const +6119:SkTConic::collapsed\28\29\20const +6120:SkTBlockList::pushItem\28\29 +6121:SkTBlockList::pop_back\28\29 +6122:SkTBlockList::push_back\28skgpu::ganesh::ClipStack::RawElement&&\29 +6123:SkTBlockList::pushItem\28\29 +6124:SkTBlockList::~SkTBlockList\28\29 +6125:SkTBlockList::push_back\28GrGLProgramDataManager::GLUniformInfo\20const&\29 +6126:SkTBlockList::item\28int\29 +6127:SkSurface_Raster::~SkSurface_Raster\28\29 +6128:SkSurface_Ganesh::~SkSurface_Ganesh\28\29 +6129:SkSurface_Ganesh::onDiscard\28\29 +6130:SkSurface_Base::replaceBackendTexture\28GrBackendTexture\20const&\2c\20GrSurfaceOrigin\2c\20SkSurface::ContentChangeMode\2c\20void\20\28*\29\28void*\29\2c\20void*\29 +6131:SkSurface_Base::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +6132:SkSurface_Base::onCapabilities\28\29 +6133:SkSurfaceValidateRasterInfo\28SkImageInfo\20const&\2c\20unsigned\20long\29 +6134:SkStrokeRec::GetInflationRadius\28SkPaint::Join\2c\20float\2c\20SkPaint::Cap\2c\20float\29 +6135:SkString_from_UTF16BE\28unsigned\20char\20const*\2c\20unsigned\20long\2c\20SkString&\29 +6136:SkString::equals\28char\20const*\2c\20unsigned\20long\29\20const +6137:SkString::equals\28char\20const*\29\20const +6138:SkString::appendVAList\28char\20const*\2c\20void*\29 +6139:SkString::appendUnichar\28int\29 +6140:SkString::appendHex\28unsigned\20int\2c\20int\29 +6141:SkStrikeSpec::SkStrikeSpec\28SkStrikeSpec\20const&\29 +6142:SkStrikeSpec::ShouldDrawAsPath\28SkPaint\20const&\2c\20SkFont\20const&\2c\20SkMatrix\20const&\29::$_0::operator\28\29\28int\2c\20int\29\20const +6143:SkStrikeSpec::ShouldDrawAsPath\28SkPaint\20const&\2c\20SkFont\20const&\2c\20SkMatrix\20const&\29 +6144:SkStrikeSpec::MakeTransformMask\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\29 +6145:SkStrikeCache::~SkStrikeCache\28\29 +6146:SkStrike::~SkStrike\28\29 +6147:SkStrike::prepareForImage\28SkGlyph*\29 +6148:SkStrike::prepareForDrawable\28SkGlyph*\29 +6149:SkStrike::internalPrepare\28SkSpan\2c\20SkStrike::PathDetail\2c\20SkGlyph\20const**\29 +6150:SkStrSplit\28char\20const*\2c\20char\20const*\2c\20SkStrSplitMode\2c\20skia_private::TArray*\29 +6151:SkStrAppendU32\28char*\2c\20unsigned\20int\29 +6152:SkStrAppendS32\28char*\2c\20int\29 +6153:SkSpriteBlitter_Memcpy::~SkSpriteBlitter_Memcpy\28\29 +6154:SkSpecialImages::MakeFromRaster\28SkIRect\20const&\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +6155:SkSpecialImages::AsBitmap\28SkSpecialImage\20const*\2c\20SkBitmap*\29 +6156:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29 +6157:SkSpecialImage_Raster::getROPixels\28SkBitmap*\29\20const +6158:SkSpecialImage_Raster::SkSpecialImage_Raster\28SkIRect\20const&\2c\20SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +6159:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29 +6160:SkSpecialImage::SkSpecialImage\28SkIRect\20const&\2c\20unsigned\20int\2c\20SkColorInfo\20const&\2c\20SkSurfaceProps\20const&\29 +6161:SkShapers::unicode::BidiRunIterator\28sk_sp\2c\20char\20const*\2c\20unsigned\20long\2c\20unsigned\20char\29 +6162:SkShapers::HB::ShapeDontWrapOrReorder\28sk_sp\2c\20sk_sp\29 +6163:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29 +6164:SkShaper::MakeStdLanguageRunIterator\28char\20const*\2c\20unsigned\20long\29 +6165:SkShaper::MakeFontMgrRunIterator\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20sk_sp\29 +6166:SkShadowTessellator::MakeAmbient\28SkPath\20const&\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20bool\29 +6167:SkShaders::MatrixRec::totalMatrix\28\29\20const +6168:SkShaders::MatrixRec::concat\28SkMatrix\20const&\29\20const +6169:SkShaders::Empty\28\29 +6170:SkShaders::Color\28unsigned\20int\29 +6171:SkShaders::Blend\28sk_sp\2c\20sk_sp\2c\20sk_sp\29 +6172:SkShaderUtils::VisitLineByLine\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20std::__2::function\20const&\29 +6173:SkShaderUtils::GLSLPrettyPrint::undoNewlineAfter\28char\29 +6174:SkShaderUtils::GLSLPrettyPrint::parseUntil\28char\20const*\29 +6175:SkShaderUtils::GLSLPrettyPrint::parseUntilNewline\28\29 +6176:SkShaderBlurAlgorithm::renderBlur\28SkRuntimeEffectBuilder*\2c\20SkFilterMode\2c\20SkISize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +6177:SkShaderBlurAlgorithm::evalBlur1D\28float\2c\20int\2c\20SkV2\2c\20sk_sp\2c\20SkIRect\2c\20SkTileMode\2c\20SkIRect\29\20const +6178:SkShaderBlurAlgorithm::GetLinearBlur1DEffect\28int\29 +6179:SkShaderBlurAlgorithm::GetBlur2DEffect\28SkISize\20const&\29 +6180:SkShaderBlurAlgorithm::Compute2DBlurOffsets\28SkISize\2c\20std::__2::array&\29 +6181:SkShaderBlurAlgorithm::Compute2DBlurKernel\28SkSize\2c\20SkISize\2c\20std::__2::array&\29 +6182:SkShaderBlurAlgorithm::Compute2DBlurKernel\28SkSize\2c\20SkISize\2c\20SkSpan\29 +6183:SkShaderBlurAlgorithm::Compute1DBlurLinearKernel\28float\2c\20int\2c\20std::__2::array&\29 +6184:SkShaderBlurAlgorithm::Compute1DBlurKernel\28float\2c\20int\2c\20SkSpan\29 +6185:SkShaderBase::getFlattenableType\28\29\20const +6186:SkShader::makeWithColorFilter\28sk_sp\29\20const +6187:SkScan::PathRequiresTiling\28SkIRect\20const&\29 +6188:SkScan::HairLine\28SkPoint\20const*\2c\20int\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +6189:SkScan::FillXRect\28SkIRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6190:SkScan::FillRect\28SkRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6191:SkScan::AntiFrameRect\28SkRect\20const&\2c\20SkPoint\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6192:SkScan::AntiFillRect\28SkRect\20const&\2c\20SkRegion\20const*\2c\20SkBlitter*\29 +6193:SkScan::AAAFillPath\28SkPath\20const&\2c\20SkBlitter*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +6194:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29 +6195:SkScalerContext_FreeType::shouldSubpixelBitmap\28SkGlyph\20const&\2c\20SkMatrix\20const&\29 +6196:SkScalerContext_FreeType::getCBoxForLetter\28char\2c\20FT_BBox_*\29 +6197:SkScalerContext_FreeType::getBoundsOfCurrentOutlineGlyph\28FT_GlyphSlotRec_*\2c\20SkRect*\29 +6198:SkScalerContextRec::setLuminanceColor\28unsigned\20int\29 +6199:SkScalerContextFTUtils::drawCOLRv1Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +6200:SkScalerContextFTUtils::drawCOLRv0Glyph\28FT_FaceRec_*\2c\20SkGlyph\20const&\2c\20unsigned\20int\2c\20SkSpan\2c\20SkCanvas*\29\20const +6201:SkScalerContext::makeGlyph\28SkPackedGlyphID\2c\20SkArenaAlloc*\29 +6202:SkScalerContext::internalGetPath\28SkGlyph&\2c\20SkArenaAlloc*\29 +6203:SkScalerContext::SkScalerContext\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +6204:SkScalerContext::SaturateGlyphBounds\28SkGlyph*\2c\20SkRect&&\29 +6205:SkScalerContext::MakeRecAndEffects\28SkFont\20const&\2c\20SkPaint\20const&\2c\20SkSurfaceProps\20const&\2c\20SkScalerContextFlags\2c\20SkMatrix\20const&\2c\20SkScalerContextRec*\2c\20SkScalerContextEffects*\29 +6206:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29 +6207:SkScalerContext::AutoDescriptorGivenRecAndEffects\28SkScalerContextRec\20const&\2c\20SkScalerContextEffects\20const&\2c\20SkAutoDescriptor*\29 +6208:SkScalarInterpFunc\28float\2c\20float\20const*\2c\20float\20const*\2c\20int\29 +6209:SkSTArenaAlloc<4096ul>::SkSTArenaAlloc\28unsigned\20long\29 +6210:SkSTArenaAlloc<256ul>::SkSTArenaAlloc\28unsigned\20long\29 +6211:SkSLCombinedSamplerTypeForTextureType\28GrTextureType\29 +6212:SkSL::type_to_sksltype\28SkSL::Context\20const&\2c\20SkSL::Type\20const&\2c\20SkSLType*\29 +6213:SkSL::stoi\28std::__2::basic_string_view>\2c\20long\20long*\29 +6214:SkSL::splat_scalar\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +6215:SkSL::simplify_constant_equality\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +6216:SkSL::short_circuit_boolean\28SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +6217:SkSL::remove_break_statements\28std::__2::unique_ptr>&\29::RemoveBreaksWriter::visitStatementPtr\28std::__2::unique_ptr>&\29 +6218:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_2::operator\28\29\28int\29\20const +6219:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_1::operator\28\29\28int\29\20const +6220:SkSL::optimize_intrinsic_call\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::IntrinsicKind\2c\20SkSL::ExpressionArray\20const&\2c\20SkSL::Type\20const&\29::$_0::operator\28\29\28int\29\20const +6221:SkSL::negate_expression\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Type\20const&\29 +6222:SkSL::make_reciprocal_expression\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29 +6223:SkSL::index_out_of_range\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20long\20long\2c\20SkSL::Expression\20const&\29 +6224:SkSL::hoist_vardecl_symbols_into_outer_scope\28SkSL::Context\20const&\2c\20SkSL::Block\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::SymbolTable*\29::SymbolHoister::visitStatement\28SkSL::Statement\20const&\29 +6225:SkSL::get_struct_definitions_from_module\28SkSL::Program&\2c\20SkSL::Module\20const&\2c\20std::__2::vector>*\29 +6226:SkSL::find_existing_declaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20SkSL::IntrinsicKind\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray>\2c\20true>&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration**\29::$_0::operator\28\29\28\29\20const +6227:SkSL::extract_matrix\28SkSL::Expression\20const*\2c\20float*\29 +6228:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +6229:SkSL::eliminate_no_op_boolean\28SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29 +6230:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_4::operator\28\29\28int\29\20const +6231:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_2::operator\28\29\28SkSL::Type\20const&\29\20const +6232:SkSL::check_main_signature\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20skia_private::TArray>\2c\20true>&\29::$_1::operator\28\29\28int\29\20const +6233:SkSL::argument_needs_scratch_variable\28SkSL::Expression\20const*\2c\20SkSL::Variable\20const*\2c\20SkSL::ProgramUsage\20const&\29 +6234:SkSL::argument_and_parameter_flags_match\28SkSL::Expression\20const&\2c\20SkSL::Variable\20const&\29 +6235:SkSL::apply_to_elements\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20double\20\28*\29\28double\29\29 +6236:SkSL::append_rtadjust_fixup_to_vertex_main\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::Block&\29::AppendRTAdjustFixupHelper::Adjust\28\29\20const +6237:SkSL::\28anonymous\20namespace\29::clone_with_ref_kind\28SkSL::Expression\20const&\2c\20SkSL::VariableRefKind\2c\20SkSL::Position\29 +6238:SkSL::\28anonymous\20namespace\29::check_valid_uniform_type\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Context\20const&\2c\20bool\29::$_0::operator\28\29\28\29\20const +6239:SkSL::\28anonymous\20namespace\29::caps_lookup_table\28\29 +6240:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +6241:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitStructFields\28SkSL::Type\20const&\29 +6242:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitStatement\28SkSL::Statement\20const&\29 +6243:SkSL::\28anonymous\20namespace\29::ProgramUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +6244:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitStatement\28SkSL::Statement\20const&\29 +6245:SkSL::\28anonymous\20namespace\29::IsAssignableVisitor::visitExpression\28SkSL::Expression&\2c\20SkSL::FieldAccess\20const*\29::'lambda'\28\29::operator\28\29\28\29\20const +6246:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +6247:SkSL::Variable::MakeScratchVariable\28SkSL::Context\20const&\2c\20SkSL::Mangler&\2c\20std::__2::basic_string_view>\2c\20SkSL::Type\20const*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>\29 +6248:SkSL::VarDeclaration::ErrorCheck\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Position\2c\20SkSL::Layout\20const&\2c\20SkSL::ModifierFlags\2c\20SkSL::Type\20const*\2c\20SkSL::Type\20const*\2c\20SkSL::VariableStorage\29 +6249:SkSL::TypeReference::description\28SkSL::OperatorPrecedence\29\20const +6250:SkSL::TypeReference::VerifyType\28SkSL::Context\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Position\29 +6251:SkSL::TypeReference::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\29 +6252:SkSL::Type::checkIfUsableInArray\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +6253:SkSL::Type::checkForOutOfRangeLiteral\28SkSL::Context\20const&\2c\20SkSL::Expression\20const&\29\20const +6254:SkSL::Type::MakeStructType\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20bool\29 +6255:SkSL::Type::MakeLiteralType\28char\20const*\2c\20SkSL::Type\20const&\2c\20signed\20char\29 +6256:SkSL::Transform::\28anonymous\20namespace\29::BuiltinVariableScanner::addDeclaringElement\28SkSL::Symbol\20const*\29 +6257:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::visitStatementPtr\28std::__2::unique_ptr>&\29 +6258:SkSL::Transform::EliminateDeadGlobalVariables\28SkSL::Program&\29::$_0::operator\28\29\28std::__2::unique_ptr>\20const&\29\20const +6259:SkSL::Transform::EliminateDeadFunctions\28SkSL::Program&\29 +6260:SkSL::TernaryExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6261:SkSL::SymbolTable::moveSymbolTo\28SkSL::SymbolTable*\2c\20SkSL::Symbol*\2c\20SkSL::Context\20const&\29 +6262:SkSL::SymbolTable::isBuiltinType\28std::__2::basic_string_view>\29\20const +6263:SkSL::SymbolTable::insertNewParent\28\29 +6264:SkSL::SymbolTable::addWithoutOwnership\28SkSL::Symbol*\29 +6265:SkSL::Symbol::instantiate\28SkSL::Context\20const&\2c\20SkSL::Position\29\20const +6266:SkSL::SwitchStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6267:SkSL::SwitchCase::Make\28SkSL::Position\2c\20long\20long\2c\20std::__2::unique_ptr>\29 +6268:SkSL::SwitchCase::MakeDefault\28SkSL::Position\2c\20std::__2::unique_ptr>\29 +6269:SkSL::StructType::structNestingDepth\28\29\20const +6270:SkSL::StructType::slotCount\28\29\20const +6271:SkSL::StructType::StructType\28SkSL::Position\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20int\2c\20bool\2c\20bool\29 +6272:SkSL::String::vappendf\28std::__2::basic_string\2c\20std::__2::allocator>*\2c\20char\20const*\2c\20void*\29 +6273:SkSL::SingleArgumentConstructor::argumentSpan\28\29 +6274:SkSL::Setting::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20bool\20const\20SkSL::ShaderCaps::*\29 +6275:SkSL::RP::stack_usage\28SkSL::RP::Instruction\20const&\29 +6276:SkSL::RP::is_sliceable_swizzle\28SkSpan\29 +6277:SkSL::RP::is_immediate_op\28SkSL::RP::BuilderOp\29 +6278:SkSL::RP::UnownedLValueSlice::isWritable\28\29\20const +6279:SkSL::RP::UnownedLValueSlice::dynamicSlotRange\28\29 +6280:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29 +6281:SkSL::RP::ScratchLValue::~ScratchLValue\28\29 +6282:SkSL::RP::Program::appendStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkSL::RP::Callbacks*\2c\20SkSpan\29\20const +6283:SkSL::RP::Program::appendStackRewind\28skia_private::TArray*\29\20const +6284:SkSL::RP::Program::appendCopyImmutableUnmasked\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20std::byte*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +6285:SkSL::RP::Program::appendAdjacentNWayTernaryOp\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSL::RP::ProgramOp\2c\20std::byte*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +6286:SkSL::RP::Program::appendAdjacentNWayBinaryOp\28skia_private::TArray*\2c\20SkArenaAlloc*\2c\20SkSL::RP::ProgramOp\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int\29\20const +6287:SkSL::RP::LValue::swizzle\28\29 +6288:SkSL::RP::ImmutableLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +6289:SkSL::RP::Generator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\29 +6290:SkSL::RP::Generator::writeFunction\28SkSL::IRNode\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSpan>\20const>\29 +6291:SkSL::RP::Generator::storeImmutableValueToSlots\28skia_private::TArray\20const&\2c\20SkSL::RP::SlotRange\29 +6292:SkSL::RP::Generator::returnComplexity\28SkSL::FunctionDefinition\20const*\29 +6293:SkSL::RP::Generator::pushVariableReferencePartial\28SkSL::VariableReference\20const&\2c\20SkSL::RP::SlotRange\29 +6294:SkSL::RP::Generator::pushLengthIntrinsic\28int\29 +6295:SkSL::RP::Generator::pushLValueOrExpression\28SkSL::RP::LValue*\2c\20SkSL::Expression\20const&\29 +6296:SkSL::RP::Generator::pushIntrinsic\28SkSL::RP::BuilderOp\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +6297:SkSL::RP::Generator::pushIntrinsic\28SkSL::IntrinsicKind\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\2c\20SkSL::Expression\20const&\29 +6298:SkSL::RP::Generator::pushImmutableData\28SkSL::Expression\20const&\29 +6299:SkSL::RP::Generator::getImmutableValueForExpression\28SkSL::Expression\20const&\2c\20skia_private::TArray*\29 +6300:SkSL::RP::Generator::getImmutableBitsForSlot\28SkSL::Expression\20const&\2c\20unsigned\20long\29 +6301:SkSL::RP::Generator::findPreexistingImmutableData\28skia_private::TArray\20const&\29 +6302:SkSL::RP::Generator::discardTraceScopeMask\28\29 +6303:SkSL::RP::Builder::push_condition_mask\28\29 +6304:SkSL::RP::Builder::pop_slots_unmasked\28SkSL::RP::SlotRange\29 +6305:SkSL::RP::Builder::pop_condition_mask\28\29 +6306:SkSL::RP::Builder::pop_and_reenable_loop_mask\28\29 +6307:SkSL::RP::Builder::merge_loop_mask\28\29 +6308:SkSL::RP::Builder::merge_inv_condition_mask\28\29 +6309:SkSL::RP::Builder::mask_off_loop_mask\28\29 +6310:SkSL::RP::Builder::discard_stack\28int\2c\20int\29 +6311:SkSL::RP::Builder::copy_stack_to_slots_unmasked\28SkSL::RP::SlotRange\2c\20int\29 +6312:SkSL::RP::Builder::copy_stack_to_slots_unmasked\28SkSL::RP::SlotRange\29 +6313:SkSL::RP::Builder::copy_stack_to_slots\28SkSL::RP::SlotRange\29 +6314:SkSL::RP::Builder::branch_if_any_lanes_active\28int\29 +6315:SkSL::RP::AutoStack::pushClone\28SkSL::RP::SlotRange\2c\20int\29 +6316:SkSL::RP::AutoContinueMask::~AutoContinueMask\28\29 +6317:SkSL::RP::AutoContinueMask::exitLoopBody\28\29 +6318:SkSL::RP::AutoContinueMask::enterLoopBody\28\29 +6319:SkSL::RP::AutoContinueMask::enable\28\29 +6320:SkSL::ProgramUsage::remove\28SkSL::Expression\20const*\29 +6321:SkSL::ProgramUsage::get\28SkSL::FunctionDeclaration\20const&\29\20const +6322:SkSL::ProgramUsage::add\28SkSL::Statement\20const*\29 +6323:SkSL::ProgramUsage::add\28SkSL::Expression\20const*\29 +6324:SkSL::ProgramConfig::ProgramConfig\28\29 +6325:SkSL::Program::~Program\28\29 +6326:SkSL::PostfixExpression::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20SkSL::Operator\29 +6327:SkSL::PipelineStage::PipelineStageCodeGenerator::functionName\28SkSL::FunctionDeclaration\20const&\2c\20int\29 +6328:SkSL::PipelineStage::PipelineStageCodeGenerator::functionDeclaration\28SkSL::FunctionDeclaration\20const&\29 +6329:SkSL::PipelineStage::PipelineStageCodeGenerator::forEachSpecialization\28SkSL::FunctionDeclaration\20const&\2c\20std::__2::function\20const&\29 +6330:SkSL::Parser::~Parser\28\29 +6331:SkSL::Parser::varDeclarations\28\29 +6332:SkSL::Parser::varDeclarationsPrefix\28SkSL::Parser::VarDeclarationsPrefix*\29 +6333:SkSL::Parser::varDeclarationsOrExpressionStatement\28\29 +6334:SkSL::Parser::switchCaseBody\28SkSL::ExpressionArray*\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>*\2c\20std::__2::unique_ptr>\29 +6335:SkSL::Parser::shiftExpression\28\29 +6336:SkSL::Parser::relationalExpression\28\29 +6337:SkSL::Parser::multiplicativeExpression\28\29 +6338:SkSL::Parser::logicalXorExpression\28\29 +6339:SkSL::Parser::logicalAndExpression\28\29 +6340:SkSL::Parser::localVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +6341:SkSL::Parser::intLiteral\28long\20long*\29 +6342:SkSL::Parser::identifier\28std::__2::basic_string_view>*\29 +6343:SkSL::Parser::globalVarDeclarationEnd\28SkSL::Position\2c\20SkSL::Modifiers\20const&\2c\20SkSL::Type\20const*\2c\20SkSL::Token\29 +6344:SkSL::Parser::expressionStatement\28\29 +6345:SkSL::Parser::expectNewline\28\29 +6346:SkSL::Parser::equalityExpression\28\29 +6347:SkSL::Parser::directive\28bool\29 +6348:SkSL::Parser::declarations\28\29 +6349:SkSL::Parser::bitwiseXorExpression\28\29 +6350:SkSL::Parser::bitwiseOrExpression\28\29 +6351:SkSL::Parser::bitwiseAndExpression\28\29 +6352:SkSL::Parser::additiveExpression\28\29 +6353:SkSL::Parser::addGlobalVarDeclaration\28std::__2::unique_ptr>\29 +6354:SkSL::Parser::Parser\28SkSL::Compiler*\2c\20SkSL::ProgramSettings\20const&\2c\20SkSL::ProgramKind\2c\20std::__2::unique_ptr\2c\20std::__2::allocator>\2c\20std::__2::default_delete\2c\20std::__2::allocator>>>\29 +6355:SkSL::MultiArgumentConstructor::argumentSpan\28\29 +6356:SkSL::ModuleLoader::loadSharedModule\28SkSL::Compiler*\29 +6357:SkSL::ModuleLoader::loadPublicModule\28SkSL::Compiler*\29 +6358:SkSL::ModuleLoader::Get\28\29 +6359:SkSL::Module::~Module\28\29 +6360:SkSL::MatrixType::bitWidth\28\29\20const +6361:SkSL::MakeRasterPipelineProgram\28SkSL::Program\20const&\2c\20SkSL::FunctionDefinition\20const&\2c\20SkSL::DebugTracePriv*\2c\20bool\29 +6362:SkSL::Layout::operator!=\28SkSL::Layout\20const&\29\20const +6363:SkSL::Layout::description\28\29\20const +6364:SkSL::Intrinsics::\28anonymous\20namespace\29::finalize_distance\28double\29 +6365:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_matrixCompMult\28double\2c\20double\2c\20double\29 +6366:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_length\28std::__2::array\20const&\29 +6367:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_add\28SkSL::Context\20const&\2c\20std::__2::array\20const&\29 +6368:SkSL::Inliner::inlineStatement\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Analysis::ReturnComplexity\2c\20SkSL::Statement\20const&\2c\20SkSL::ProgramUsage\20const&\2c\20bool\29 +6369:SkSL::Inliner::inlineExpression\28SkSL::Position\2c\20skia_private::THashMap>\2c\20SkGoodHash>*\2c\20SkSL::SymbolTable*\2c\20SkSL::Expression\20const&\29 +6370:SkSL::Inliner::buildCandidateList\28std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\2c\20SkSL::InlineCandidateList*\29::$_1::operator\28\29\28SkSL::InlineCandidate\20const&\29\20const +6371:SkSL::Inliner::buildCandidateList\28std::__2::vector>\2c\20std::__2::allocator>>>\20const&\2c\20SkSL::SymbolTable*\2c\20SkSL::ProgramUsage*\2c\20SkSL::InlineCandidateList*\29::$_0::operator\28\29\28SkSL::InlineCandidate\20const&\29\20const +6372:SkSL::Inliner::InlinedCall::~InlinedCall\28\29 +6373:SkSL::IndexExpression::~IndexExpression\28\29 +6374:SkSL::IfStatement::~IfStatement\28\29 +6375:SkSL::IRHelpers::Ref\28SkSL::Variable\20const*\29\20const +6376:SkSL::IRHelpers::Mul\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29\20const +6377:SkSL::IRHelpers::Assign\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29\20const +6378:SkSL::GLSLCodeGenerator::writeVarDeclaration\28SkSL::VarDeclaration\20const&\2c\20bool\29 +6379:SkSL::GLSLCodeGenerator::writeProgramElement\28SkSL::ProgramElement\20const&\29 +6380:SkSL::GLSLCodeGenerator::writeMinAbsHack\28SkSL::Expression&\2c\20SkSL::Expression&\29 +6381:SkSL::GLSLCodeGenerator::generateCode\28\29 +6382:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::visitStatementPtr\28std::__2::unique_ptr>&\29 +6383:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::addLocalVariable\28SkSL::Variable\20const*\2c\20SkSL::Position\29 +6384:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29_6505 +6385:SkSL::FunctionDeclaration::~FunctionDeclaration\28\29 +6386:SkSL::FunctionDeclaration::mangledName\28\29\20const +6387:SkSL::FunctionDeclaration::getMainInputColorParameter\28\29\20const +6388:SkSL::FunctionDeclaration::getMainDestColorParameter\28\29\20const +6389:SkSL::FunctionDeclaration::determineFinalTypes\28SkSL::ExpressionArray\20const&\2c\20skia_private::STArray<8\2c\20SkSL::Type\20const*\2c\20true>*\2c\20SkSL::Type\20const**\29\20const +6390:SkSL::FunctionDeclaration::FunctionDeclaration\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ModifierFlags\2c\20std::__2::basic_string_view>\2c\20skia_private::TArray\2c\20SkSL::Type\20const*\2c\20SkSL::IntrinsicKind\29 +6391:SkSL::FunctionCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +6392:SkSL::FunctionCall::FunctionCall\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::FunctionDeclaration\20const*\2c\20SkSL::ExpressionArray\2c\20SkSL::FunctionCall\20const*\29 +6393:SkSL::FunctionCall::FindBestFunctionForCall\28SkSL::Context\20const&\2c\20SkSL::FunctionDeclaration\20const*\2c\20SkSL::ExpressionArray\20const&\29 +6394:SkSL::FunctionCall::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20SkSL::ExpressionArray\29 +6395:SkSL::ForStatement::~ForStatement\28\29 +6396:SkSL::ForStatement::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6397:SkSL::FindIntrinsicKind\28std::__2::basic_string_view>\29 +6398:SkSL::FieldAccess::~FieldAccess\28\29_6382 +6399:SkSL::FieldAccess::~FieldAccess\28\29 +6400:SkSL::FieldAccess::description\28SkSL::OperatorPrecedence\29\20const +6401:SkSL::FieldAccess::FieldAccess\28SkSL::Position\2c\20std::__2::unique_ptr>\2c\20int\2c\20SkSL::FieldAccessOwnerKind\29 +6402:SkSL::ExtendedVariable::~ExtendedVariable\28\29 +6403:SkSL::Expression::isFloatLiteral\28\29\20const +6404:SkSL::Expression::coercionCost\28SkSL::Type\20const&\29\20const +6405:SkSL::DoStatement::~DoStatement\28\29_6371 +6406:SkSL::DoStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +6407:SkSL::DiscardStatement::Make\28SkSL::Context\20const&\2c\20SkSL::Position\29 +6408:SkSL::ContinueStatement::Make\28SkSL::Position\29 +6409:SkSL::ConstructorStruct::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +6410:SkSL::ConstructorScalarCast::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +6411:SkSL::ConstructorMatrixResize::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20std::__2::unique_ptr>\29 +6412:SkSL::Constructor::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const&\2c\20SkSL::ExpressionArray\29 +6413:SkSL::Compiler::resetErrors\28\29 +6414:SkSL::Compiler::initializeContext\28SkSL::Module\20const*\2c\20SkSL::ProgramKind\2c\20SkSL::ProgramSettings\2c\20std::__2::basic_string_view>\2c\20SkSL::ModuleType\29 +6415:SkSL::Compiler::cleanupContext\28\29 +6416:SkSL::CoercionCost::operator<\28SkSL::CoercionCost\29\20const +6417:SkSL::ChildCall::~ChildCall\28\29_6310 +6418:SkSL::ChildCall::~ChildCall\28\29 +6419:SkSL::ChildCall::Make\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Variable\20const&\2c\20SkSL::ExpressionArray\29 +6420:SkSL::ChildCall::ChildCall\28SkSL::Position\2c\20SkSL::Type\20const*\2c\20SkSL::Variable\20const*\2c\20SkSL::ExpressionArray\29 +6421:SkSL::BreakStatement::Make\28SkSL::Position\29 +6422:SkSL::Block::Block\28SkSL::Position\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>\2c\20SkSL::Block::Kind\2c\20std::__2::unique_ptr>\29 +6423:SkSL::BinaryExpression::isAssignmentIntoVariable\28\29 +6424:SkSL::ArrayType::columns\28\29\20const +6425:SkSL::Analysis::\28anonymous\20namespace\29::LoopControlFlowVisitor::visitStatement\28SkSL::Statement\20const&\29 +6426:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29::IsDynamicallyUniformExpressionVisitor::visitExpression\28SkSL::Expression\20const&\29 +6427:SkSL::Analysis::IsDynamicallyUniformExpression\28SkSL::Expression\20const&\29 +6428:SkSL::Analysis::IsConstantExpression\28SkSL::Expression\20const&\29 +6429:SkSL::Analysis::IsCompileTimeConstant\28SkSL::Expression\20const&\29::IsCompileTimeConstantVisitor::visitExpression\28SkSL::Expression\20const&\29 +6430:SkSL::Analysis::IsAssignable\28SkSL::Expression&\2c\20SkSL::Analysis::AssignmentInfo*\2c\20SkSL::ErrorReporter*\29 +6431:SkSL::Analysis::HasSideEffects\28SkSL::Expression\20const&\29::HasSideEffectsVisitor::visitExpression\28SkSL::Expression\20const&\29 +6432:SkSL::Analysis::GetLoopUnrollInfo\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::ForLoopPositions\20const&\2c\20SkSL::Statement\20const*\2c\20std::__2::unique_ptr>*\2c\20SkSL::Expression\20const*\2c\20SkSL::Statement\20const*\2c\20SkSL::ErrorReporter*\29 +6433:SkSL::Analysis::GetLoopControlFlowInfo\28SkSL::Statement\20const&\29 +6434:SkSL::Analysis::ContainsVariable\28SkSL::Expression\20const&\2c\20SkSL::Variable\20const&\29::ContainsVariableVisitor::visitExpression\28SkSL::Expression\20const&\29 +6435:SkSL::Analysis::ContainsRTAdjust\28SkSL::Expression\20const&\29::ContainsRTAdjustVisitor::visitExpression\28SkSL::Expression\20const&\29 +6436:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +6437:SkSL::AliasType::numberKind\28\29\20const +6438:SkSL::AliasType::isOrContainsBool\28\29\20const +6439:SkSL::AliasType::isOrContainsAtomic\28\29\20const +6440:SkSL::AliasType::isAllowedInES2\28\29\20const +6441:SkSBlockAllocator<80ul>::SkSBlockAllocator\28SkBlockAllocator::GrowthPolicy\2c\20unsigned\20long\29 +6442:SkRuntimeShader::~SkRuntimeShader\28\29 +6443:SkRuntimeEffectPriv::VarAsChild\28SkSL::Variable\20const&\2c\20int\29 +6444:SkRuntimeEffect::~SkRuntimeEffect\28\29 +6445:SkRuntimeEffect::getRPProgram\28SkSL::DebugTracePriv*\29\20const +6446:SkRuntimeEffect::MakeForShader\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +6447:SkRuntimeEffect::ChildPtr::type\28\29\20const +6448:SkRuntimeEffect::ChildPtr::shader\28\29\20const +6449:SkRuntimeEffect::ChildPtr::colorFilter\28\29\20const +6450:SkRuntimeEffect::ChildPtr::blender\28\29\20const +6451:SkRgnBuilder::collapseWithPrev\28\29 +6452:SkResourceCache::release\28SkResourceCache::Rec*\29 +6453:SkResourceCache::PostPurgeSharedID\28unsigned\20long\20long\29 +6454:SkResourceCache::NewCachedData\28unsigned\20long\29 +6455:SkResourceCache::GetDiscardableFactory\28\29 +6456:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29 +6457:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +6458:SkRegion::quickReject\28SkIRect\20const&\29\20const +6459:SkRegion::quickContains\28SkIRect\20const&\29\20const +6460:SkRegion::op\28SkIRect\20const&\2c\20SkRegion::Op\29 +6461:SkRegion::getRuns\28int*\2c\20int*\29\20const +6462:SkRegion::Spanerator::Spanerator\28SkRegion\20const&\2c\20int\2c\20int\2c\20int\29 +6463:SkRegion::RunHead::ensureWritable\28\29 +6464:SkRegion::RunHead::computeRunBounds\28SkIRect*\29 +6465:SkRegion::RunHead::Alloc\28int\2c\20int\2c\20int\29 +6466:SkRegion::Oper\28SkRegion\20const&\2c\20SkRegion\20const&\2c\20SkRegion::Op\2c\20SkRegion*\29 +6467:SkRefCntBase::internal_dispose\28\29\20const +6468:SkReduceOrder::Conic\28SkConic\20const&\2c\20SkPoint*\29 +6469:SkRectPriv::Subtract\28SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkIRect*\29 +6470:SkRectPriv::QuadContainsRect\28SkM44\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20float\29 +6471:SkRectPriv::QuadContainsRectMask\28SkM44\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20float\29 +6472:SkRectPriv::FitsInFixed\28SkRect\20const&\29 +6473:SkRectClipBlitter::requestRowsPreserved\28\29\20const +6474:SkRectClipBlitter::allocBlitMemory\28unsigned\20long\29 +6475:SkRect::roundOut\28SkRect*\29\20const +6476:SkRect::roundIn\28\29\20const +6477:SkRect::roundIn\28SkIRect*\29\20const +6478:SkRect::makeOffset\28float\2c\20float\29\20const +6479:SkRect::joinNonEmptyArg\28SkRect\20const&\29 +6480:SkRect::intersect\28SkRect\20const&\2c\20SkRect\20const&\29 +6481:SkRect::contains\28float\2c\20float\29\20const +6482:SkRect::contains\28SkIRect\20const&\29\20const +6483:SkRect*\20SkRecord::alloc\28unsigned\20long\29 +6484:SkRecords::FillBounds::popSaveBlock\28\29 +6485:SkRecords::FillBounds::popControl\28SkRect\20const&\29 +6486:SkRecords::FillBounds::AdjustForPaint\28SkPaint\20const*\2c\20SkRect*\29 +6487:SkRecorder::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6488:SkRecordedDrawable::~SkRecordedDrawable\28\29 +6489:SkRecordOptimize\28SkRecord*\29 +6490:SkRecordFillBounds\28SkRect\20const&\2c\20SkRecord\20const&\2c\20SkRect*\2c\20SkBBoxHierarchy::Metadata*\29 +6491:SkRecord::~SkRecord\28\29 +6492:SkReadBuffer::skipByteArray\28unsigned\20long*\29 +6493:SkReadBuffer::readPad32\28void*\2c\20unsigned\20long\29 +6494:SkReadBuffer::SkReadBuffer\28void\20const*\2c\20unsigned\20long\29 +6495:SkRasterPipeline_UniformColorCtx*\20SkArenaAlloc::make\28\29 +6496:SkRasterPipeline_TileCtx*\20SkArenaAlloc::make\28\29 +6497:SkRasterPipeline_RewindCtx*\20SkArenaAlloc::make\28\29 +6498:SkRasterPipeline_DecalTileCtx*\20SkArenaAlloc::make\28\29 +6499:SkRasterPipeline_CopyIndirectCtx*\20SkArenaAlloc::make\28\29 +6500:SkRasterPipeline_2PtConicalCtx*\20SkArenaAlloc::make\28\29 +6501:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29 +6502:SkRasterPipeline::buildPipeline\28SkRasterPipelineStage*\29\20const +6503:SkRasterPipeline::appendSetRGB\28SkArenaAlloc*\2c\20float\20const*\29 +6504:SkRasterPipeline::appendLoad\28SkColorType\2c\20SkRasterPipeline_MemoryCtx\20const*\29 +6505:SkRasterClipStack::Rec::Rec\28SkRasterClip\20const&\29 +6506:SkRasterClip::setEmpty\28\29 +6507:SkRasterClip::computeIsRect\28\29\20const +6508:SkRandom::nextULessThan\28unsigned\20int\29 +6509:SkRTreeFactory::operator\28\29\28\29\20const +6510:SkRTree::~SkRTree\28\29 +6511:SkRTree::search\28SkRTree::Node*\2c\20SkRect\20const&\2c\20std::__2::vector>*\29\20const +6512:SkRTree::bulkLoad\28std::__2::vector>*\2c\20int\29 +6513:SkRTree::allocateNodeAtLevel\28unsigned\20short\29 +6514:SkRRectPriv::ConservativeIntersect\28SkRRect\20const&\2c\20SkRRect\20const&\29::$_2::operator\28\29\28SkRRect::Corner\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29\20const +6515:SkRRect::setRectXY\28SkRect\20const&\2c\20float\2c\20float\29 +6516:SkRRect::isValid\28\29\20const +6517:SkRRect::computeType\28\29 +6518:SkRGBA4f<\28SkAlphaType\292>\20skgpu::Swizzle::applyTo<\28SkAlphaType\292>\28SkRGBA4f<\28SkAlphaType\292>\29\20const +6519:SkRGBA4f<\28SkAlphaType\292>::unpremul\28\29\20const +6520:SkQuads::Roots\28double\2c\20double\2c\20double\29 +6521:SkQuadraticEdge::setQuadraticWithoutUpdate\28SkPoint\20const*\2c\20int\29 +6522:SkQuadConstruct::init\28float\2c\20float\29 +6523:SkPtrSet::add\28void*\29 +6524:SkPoint::Normalize\28SkPoint*\29 +6525:SkPixmap::readPixels\28SkPixmap\20const&\29\20const +6526:SkPixmap::readPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\29\20const +6527:SkPixmap::erase\28unsigned\20int\29\20const +6528:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const +6529:SkPixelRef::callGenIDChangeListeners\28\29 +6530:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20sk_sp\29 +6531:SkPictureRecorder::beginRecording\28SkRect\20const&\2c\20SkBBHFactory*\29 +6532:SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel\28unsigned\20int\29 +6533:SkPictureRecord::endRecording\28\29 +6534:SkPictureRecord::beginRecording\28\29 +6535:SkPictureRecord::addPath\28SkPath\20const&\29 +6536:SkPictureRecord::addPathToHeap\28SkPath\20const&\29 +6537:SkPictureRecord::SkPictureRecord\28SkIRect\20const&\2c\20unsigned\20int\29 +6538:SkPictureImageGenerator::~SkPictureImageGenerator\28\29 +6539:SkPictureData::~SkPictureData\28\29 +6540:SkPictureData::flatten\28SkWriteBuffer&\29\20const +6541:SkPictureData::SkPictureData\28SkPictureRecord\20const&\2c\20SkPictInfo\20const&\29 +6542:SkPicture::SkPicture\28\29 +6543:SkPathWriter::moveTo\28\29 +6544:SkPathWriter::init\28\29 +6545:SkPathWriter::assemble\28\29 +6546:SkPathStroker::setQuadEndNormal\28SkPoint\20const*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint*\2c\20SkPoint*\29 +6547:SkPathStroker::cubicQuadEnds\28SkPoint\20const*\2c\20SkQuadConstruct*\29 +6548:SkPathRef::resetToSize\28int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\29 +6549:SkPathRef::isRRect\28SkRRect*\2c\20bool*\2c\20unsigned\20int*\29\20const +6550:SkPathRef::isOval\28SkRect*\2c\20bool*\2c\20unsigned\20int*\29\20const +6551:SkPathRef::commonReset\28\29 +6552:SkPathRef::Iter::next\28SkPoint*\29 +6553:SkPathRef::CreateEmpty\28\29 +6554:SkPathPriv::LeadingMoveToCount\28SkPath\20const&\29 +6555:SkPathPriv::IsRRect\28SkPath\20const&\2c\20SkRRect*\2c\20SkPathDirection*\2c\20unsigned\20int*\29 +6556:SkPathPriv::IsOval\28SkPath\20const&\2c\20SkRect*\2c\20SkPathDirection*\2c\20unsigned\20int*\29 +6557:SkPathPriv::IsNestedFillRects\28SkPath\20const&\2c\20SkRect*\2c\20SkPathDirection*\29 +6558:SkPathPriv::CreateDrawArcPath\28SkPath*\2c\20SkArc\20const&\2c\20bool\29 +6559:SkPathOpsBounds::Intersects\28SkPathOpsBounds\20const&\2c\20SkPathOpsBounds\20const&\29 +6560:SkPathMeasure::~SkPathMeasure\28\29 +6561:SkPathMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29 +6562:SkPathMeasure::SkPathMeasure\28SkPath\20const&\2c\20bool\2c\20float\29 +6563:SkPathEffectBase::getFlattenableType\28\29\20const +6564:SkPathEffectBase::PointData::~PointData\28\29 +6565:SkPathEdgeIter::next\28\29::'lambda'\28\29::operator\28\29\28\29\20const +6566:SkPathBuilder::reset\28\29 +6567:SkPathBuilder::lineTo\28float\2c\20float\29 +6568:SkPathBuilder::addRect\28SkRect\20const&\2c\20SkPathDirection\29 +6569:SkPathBuilder::addOval\28SkRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +6570:SkPath::writeToMemory\28void*\29\20const +6571:SkPath::reverseAddPath\28SkPath\20const&\29 +6572:SkPath::offset\28float\2c\20float\29 +6573:SkPath::makeTransform\28SkMatrix\20const&\2c\20SkApplyPerspectiveClip\29\20const +6574:SkPath::isZeroLengthSincePoint\28int\29\20const +6575:SkPath::isRRect\28SkRRect*\29\20const +6576:SkPath::isOval\28SkRect*\29\20const +6577:SkPath::copyFields\28SkPath\20const&\29 +6578:SkPath::conservativelyContainsRect\28SkRect\20const&\29\20const +6579:SkPath::arcTo\28float\2c\20float\2c\20float\2c\20SkPath::ArcSize\2c\20SkPathDirection\2c\20float\2c\20float\29 +6580:SkPath::addRect\28float\2c\20float\2c\20float\2c\20float\2c\20SkPathDirection\29 +6581:SkPath::addRRect\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\29 +6582:SkPath::addCircle\28float\2c\20float\2c\20float\2c\20SkPathDirection\29 +6583:SkPath::Polygon\28std::initializer_list\20const&\2c\20bool\2c\20SkPathFillType\2c\20bool\29 +6584:SkPaintToGrPaintWithBlend\28GrRecordingContext*\2c\20GrColorInfo\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkBlender*\2c\20SkSurfaceProps\20const&\2c\20GrPaint*\29 +6585:SkPaintPriv::ShouldDither\28SkPaint\20const&\2c\20SkColorType\29 +6586:SkOpSpanBase::merge\28SkOpSpan*\29 +6587:SkOpSpanBase::initBase\28SkOpSegment*\2c\20SkOpSpan*\2c\20double\2c\20SkPoint\20const&\29 +6588:SkOpSpan::sortableTop\28SkOpContour*\29 +6589:SkOpSpan::setOppSum\28int\29 +6590:SkOpSpan::insertCoincidence\28SkOpSpan*\29 +6591:SkOpSpan::insertCoincidence\28SkOpSegment\20const*\2c\20bool\2c\20bool\29 +6592:SkOpSpan::init\28SkOpSegment*\2c\20SkOpSpan*\2c\20double\2c\20SkPoint\20const&\29 +6593:SkOpSpan::containsCoincidence\28SkOpSegment\20const*\29\20const +6594:SkOpSpan::computeWindSum\28\29 +6595:SkOpSegment::updateOppWindingReverse\28SkOpAngle\20const*\29\20const +6596:SkOpSegment::ptsDisjoint\28double\2c\20SkPoint\20const&\2c\20double\2c\20SkPoint\20const&\29\20const +6597:SkOpSegment::markWinding\28SkOpSpan*\2c\20int\29 +6598:SkOpSegment::isClose\28double\2c\20SkOpSegment\20const*\29\20const +6599:SkOpSegment::computeSum\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkOpAngle::IncludeType\29 +6600:SkOpSegment::collapsed\28double\2c\20double\29\20const +6601:SkOpSegment::addExpanded\28double\2c\20SkOpSpanBase\20const*\2c\20bool*\29 +6602:SkOpSegment::activeWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\29 +6603:SkOpSegment::activeOp\28int\2c\20int\2c\20SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20SkPathOp\2c\20int*\2c\20int*\29 +6604:SkOpSegment::activeAngle\28SkOpSpanBase*\2c\20SkOpSpanBase**\2c\20SkOpSpanBase**\2c\20bool*\29 +6605:SkOpSegment::activeAngleInner\28SkOpSpanBase*\2c\20SkOpSpanBase**\2c\20SkOpSpanBase**\2c\20bool*\29 +6606:SkOpPtT::ptAlreadySeen\28SkOpPtT\20const*\29\20const +6607:SkOpEdgeBuilder::~SkOpEdgeBuilder\28\29 +6608:SkOpEdgeBuilder::preFetch\28\29 +6609:SkOpEdgeBuilder::finish\28\29 +6610:SkOpEdgeBuilder::SkOpEdgeBuilder\28SkPath\20const&\2c\20SkOpContourHead*\2c\20SkOpGlobalState*\29 +6611:SkOpContourBuilder::addQuad\28SkPoint*\29 +6612:SkOpContourBuilder::addLine\28SkPoint\20const*\29 +6613:SkOpContourBuilder::addCubic\28SkPoint*\29 +6614:SkOpContourBuilder::addConic\28SkPoint*\2c\20float\29 +6615:SkOpCoincidence::restoreHead\28\29 +6616:SkOpCoincidence::releaseDeleted\28SkCoincidentSpans*\29 +6617:SkOpCoincidence::mark\28\29 +6618:SkOpCoincidence::markCollapsed\28SkCoincidentSpans*\2c\20SkOpPtT*\29 +6619:SkOpCoincidence::fixUp\28SkCoincidentSpans*\2c\20SkOpPtT*\2c\20SkOpPtT\20const*\29 +6620:SkOpCoincidence::contains\28SkCoincidentSpans\20const*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\29\20const +6621:SkOpCoincidence::checkOverlap\28SkCoincidentSpans*\2c\20SkOpSegment\20const*\2c\20SkOpSegment\20const*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20SkTDArray*\29\20const +6622:SkOpCoincidence::addOrOverlap\28SkOpSegment*\2c\20SkOpSegment*\2c\20double\2c\20double\2c\20double\2c\20double\2c\20bool*\29 +6623:SkOpCoincidence::addMissing\28bool*\29 +6624:SkOpCoincidence::addEndMovedSpans\28SkOpSpan\20const*\2c\20SkOpSpanBase\20const*\29 +6625:SkOpAngle::tangentsDiverge\28SkOpAngle\20const*\2c\20double\29 +6626:SkOpAngle::setSpans\28\29 +6627:SkOpAngle::setSector\28\29 +6628:SkOpAngle::previous\28\29\20const +6629:SkOpAngle::midToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +6630:SkOpAngle::merge\28SkOpAngle*\29 +6631:SkOpAngle::loopContains\28SkOpAngle\20const*\29\20const +6632:SkOpAngle::lineOnOneSide\28SkOpAngle\20const*\2c\20bool\29 +6633:SkOpAngle::findSector\28SkPath::Verb\2c\20double\2c\20double\29\20const +6634:SkOpAngle::endToSide\28SkOpAngle\20const*\2c\20bool*\29\20const +6635:SkOpAngle::checkCrossesZero\28\29\20const +6636:SkOpAngle::alignmentSameSide\28SkOpAngle\20const*\2c\20int*\29\20const +6637:SkOpAngle::after\28SkOpAngle*\29 +6638:SkOffsetSimplePolygon\28SkPoint\20const*\2c\20int\2c\20SkRect\20const&\2c\20float\2c\20SkTDArray*\2c\20SkTDArray*\29 +6639:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29 +6640:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29 +6641:SkNullBlitter*\20SkArenaAlloc::make\28\29 +6642:SkNotifyBitmapGenIDIsStale\28unsigned\20int\29 +6643:SkNoPixelsDevice::~SkNoPixelsDevice\28\29 +6644:SkNoPixelsDevice::SkNoPixelsDevice\28SkIRect\20const&\2c\20SkSurfaceProps\20const&\29 +6645:SkNoDestructor::SkNoDestructor\2c\20sk_sp>\28sk_sp&&\2c\20sk_sp&&\29 +6646:SkNVRefCnt::unref\28\29\20const +6647:SkNVRefCnt::unref\28\29\20const +6648:SkNVRefCnt::unref\28\29\20const +6649:SkNVRefCnt::unref\28\29\20const +6650:SkNVRefCnt::unref\28\29\20const +6651:SkMipmapAccessor::SkMipmapAccessor\28SkImage_Base\20const*\2c\20SkMatrix\20const&\2c\20SkMipmapMode\29::$_1::operator\28\29\28SkPixmap\20const&\29\20const +6652:SkMipmap::~SkMipmap\28\29 +6653:SkMessageBus::Get\28\29 +6654:SkMessageBus::Get\28\29 +6655:SkMeshSpecification::Attribute::Attribute\28SkMeshSpecification::Attribute\20const&\29 +6656:SkMeshPriv::CpuBuffer::~CpuBuffer\28\29 +6657:SkMeshPriv::CpuBuffer::size\28\29\20const +6658:SkMeshPriv::CpuBuffer::peek\28\29\20const +6659:SkMeshPriv::CpuBuffer::onUpdate\28GrDirectContext*\2c\20void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\29 +6660:SkMemoryStream::~SkMemoryStream\28\29 +6661:SkMemoryStream::SkMemoryStream\28sk_sp\29 +6662:SkMatrixPriv::MapPointsWithStride\28SkMatrix\20const&\2c\20SkPoint*\2c\20unsigned\20long\2c\20int\29 +6663:SkMatrix::updateTranslateMask\28\29 +6664:SkMatrix::setTranslate\28float\2c\20float\29 +6665:SkMatrix::setScale\28float\2c\20float\29 +6666:SkMatrix::postSkew\28float\2c\20float\29 +6667:SkMatrix::mapHomogeneousPoints\28SkPoint3*\2c\20SkPoint3\20const*\2c\20int\29\20const +6668:SkMatrix::getMinScale\28\29\20const +6669:SkMatrix::computeTypeMask\28\29\20const +6670:SkMatrix::Rot_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +6671:SkMatrix*\20SkRecord::alloc\28unsigned\20long\29 +6672:SkMaskFilterBase::NinePatch::~NinePatch\28\29 +6673:SkMask*\20SkTLazy::init\28unsigned\20char\20const*&&\2c\20SkIRect\20const&\2c\20unsigned\20int\20const&\2c\20SkMask::Format\20const&\29 +6674:SkMask*\20SkTLazy::init\28SkMaskBuilder&\29 +6675:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29 +6676:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29 +6677:SkMakeBitmapShaderForPaint\28SkPaint\20const&\2c\20SkBitmap\20const&\2c\20SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const*\2c\20SkCopyPixelsMode\29 +6678:SkM44::preTranslate\28float\2c\20float\2c\20float\29 +6679:SkM44::postTranslate\28float\2c\20float\2c\20float\29 +6680:SkLinearColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +6681:SkLineParameters::normalize\28\29 +6682:SkLineParameters::cubicEndPoints\28SkDCubic\20const&\29 +6683:SkLineClipper::ClipLine\28SkPoint\20const*\2c\20SkRect\20const&\2c\20SkPoint*\2c\20bool\29 +6684:SkLatticeIter::~SkLatticeIter\28\29 +6685:SkLatticeIter::next\28SkIRect*\2c\20SkRect*\2c\20bool*\2c\20unsigned\20int*\29 +6686:SkLatticeIter::SkLatticeIter\28SkCanvas::Lattice\20const&\2c\20SkRect\20const&\29 +6687:SkLRUCache>\2c\20skia::textlayout::ParagraphCache::KeyHash\2c\20SkNoOpPurge>::find\28skia::textlayout::ParagraphCacheKey\20const&\29 +6688:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::insert\28GrProgramDesc\20const&\2c\20std::__2::unique_ptr>\29 +6689:SkLRUCache>\2c\20GrGLGpu::ProgramCache::DescHash\2c\20SkNoOpPurge>::find\28GrProgramDesc\20const&\29 +6690:SkKnownRuntimeEffects::\28anonymous\20namespace\29::make_matrix_conv_effect\28SkKnownRuntimeEffects::\28anonymous\20namespace\29::MatrixConvolutionImpl\2c\20SkRuntimeEffect::Options\20const&\29::$_0::operator\28\29\28int\2c\20SkRuntimeEffect::Options\20const&\29\20const +6691:SkIsSimplePolygon\28SkPoint\20const*\2c\20int\29 +6692:SkIsConvexPolygon\28SkPoint\20const*\2c\20int\29 +6693:SkInvert4x4Matrix\28float\20const*\2c\20float*\29 +6694:SkInvert3x3Matrix\28float\20const*\2c\20float*\29 +6695:SkIntersections::quadVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6696:SkIntersections::quadLine\28SkPoint\20const*\2c\20SkPoint\20const*\29 +6697:SkIntersections::quadHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6698:SkIntersections::mostOutside\28double\2c\20double\2c\20SkDPoint\20const&\29\20const +6699:SkIntersections::lineVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6700:SkIntersections::lineHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6701:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDQuad\20const&\29 +6702:SkIntersections::intersect\28SkDCubic\20const&\2c\20SkDConic\20const&\29 +6703:SkIntersections::intersect\28SkDConic\20const&\2c\20SkDQuad\20const&\29 +6704:SkIntersections::insertCoincident\28double\2c\20double\2c\20SkDPoint\20const&\29 +6705:SkIntersections::cubicVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6706:SkIntersections::cubicLine\28SkPoint\20const*\2c\20SkPoint\20const*\29 +6707:SkIntersections::cubicHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6708:SkIntersections::conicVertical\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6709:SkIntersections::conicLine\28SkPoint\20const*\2c\20float\2c\20SkPoint\20const*\29 +6710:SkIntersections::conicHorizontal\28SkPoint\20const*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20bool\29 +6711:SkImages::RasterFromPixmap\28SkPixmap\20const&\2c\20void\20\28*\29\28void\20const*\2c\20void*\29\2c\20void*\29 +6712:SkImages::RasterFromData\28SkImageInfo\20const&\2c\20sk_sp\2c\20unsigned\20long\29 +6713:SkImage_Raster::~SkImage_Raster\28\29 +6714:SkImage_Raster::onPeekBitmap\28\29\20const +6715:SkImage_Raster::SkImage_Raster\28SkBitmap\20const&\2c\20bool\29 +6716:SkImage_Picture::Make\28sk_sp\2c\20SkISize\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\2c\20SkImages::BitDepth\2c\20sk_sp\2c\20SkSurfaceProps\29 +6717:SkImage_Lazy::~SkImage_Lazy\28\29 +6718:SkImage_Lazy::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +6719:SkImage_GaneshBase::~SkImage_GaneshBase\28\29 +6720:SkImage_GaneshBase::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +6721:SkImage_GaneshBase::SkImage_GaneshBase\28sk_sp\2c\20SkImageInfo\2c\20unsigned\20int\29 +6722:SkImage_Base::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +6723:SkImage_Base::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +6724:SkImageShader::~SkImageShader\28\29 +6725:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_3::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +6726:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const::$_1::operator\28\29\28\28anonymous\20namespace\29::MipLevelHelper\20const*\29\20const +6727:SkImageInfoValidConversion\28SkImageInfo\20const&\2c\20SkImageInfo\20const&\29 +6728:SkImageGenerator::SkImageGenerator\28SkImageInfo\20const&\2c\20unsigned\20int\29 +6729:SkImageFilters::Crop\28SkRect\20const&\2c\20sk_sp\29 +6730:SkImageFilters::Blur\28float\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +6731:SkImageFilter_Base::getInputBounds\28skif::Mapping\20const&\2c\20skif::DeviceSpace\20const&\2c\20std::__2::optional>\29\20const +6732:SkImageFilter_Base::getCTMCapability\28\29\20const +6733:SkImageFilterCache::Get\28SkImageFilterCache::CreateIfNecessary\29 +6734:SkImageFilterCache::Create\28unsigned\20long\29 +6735:SkImage::~SkImage\28\29 +6736:SkGradientShader::MakeTwoPointConical\28SkPoint\20const&\2c\20float\2c\20SkPoint\20const&\2c\20float\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6737:SkGradientShader::MakeTwoPointConical\28SkPoint\20const&\2c\20float\2c\20SkPoint\20const&\2c\20float\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +6738:SkGradientShader::MakeSweep\28float\2c\20float\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20float\2c\20float\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6739:SkGradientShader::MakeRadial\28SkPoint\20const&\2c\20float\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6740:SkGradientShader::MakeLinear\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20unsigned\20int\2c\20SkMatrix\20const*\29 +6741:SkGradientShader::MakeLinear\28SkPoint\20const*\2c\20SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20sk_sp\2c\20float\20const*\2c\20int\2c\20SkTileMode\2c\20SkGradientShader::Interpolation\20const&\2c\20SkMatrix\20const*\29 +6742:SkGradientBaseShader::~SkGradientBaseShader\28\29 +6743:SkGradientBaseShader::getPos\28int\29\20const +6744:SkGradientBaseShader::AppendGradientFillStages\28SkRasterPipeline*\2c\20SkArenaAlloc*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const*\2c\20float\20const*\2c\20int\29 +6745:SkGlyph::mask\28SkPoint\29\20const +6746:SkGlyph::ensureIntercepts\28float\20const*\2c\20float\2c\20float\2c\20float*\2c\20int*\2c\20SkArenaAlloc*\29::$_1::operator\28\29\28SkGlyph::Intercept\20const*\2c\20float*\2c\20int*\29\20const +6747:SkGenerateDistanceFieldFromA8Image\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\2c\20int\2c\20unsigned\20long\29 +6748:SkGaussFilter::SkGaussFilter\28double\29 +6749:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29 +6750:SkFontStyleSet::CreateEmpty\28\29 +6751:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29 +6752:SkFontScanner_FreeType::scanInstance\28SkStreamAsset*\2c\20int\2c\20int\2c\20SkString*\2c\20SkFontStyle*\2c\20bool*\2c\20skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>*\2c\20skia_private::STArray<4\2c\20SkFontArguments::VariationPosition::Coordinate\2c\20true>*\29\20const +6753:SkFontScanner_FreeType::computeAxisValues\28skia_private::STArray<4\2c\20SkFontParameters::Variation::Axis\2c\20true>\20const&\2c\20SkFontArguments::VariationPosition\2c\20SkFontArguments::VariationPosition\2c\20int*\2c\20SkString\20const&\2c\20SkFontStyle*\29 +6754:SkFontScanner_FreeType::SkFontScanner_FreeType\28\29 +6755:SkFontPriv::MakeTextMatrix\28float\2c\20float\2c\20float\29 +6756:SkFontPriv::GetFontBounds\28SkFont\20const&\29 +6757:SkFontMgr_Custom::~SkFontMgr_Custom\28\29 +6758:SkFontMgr_Custom::onMakeFromStreamArgs\28std::__2::unique_ptr>\2c\20SkFontArguments\20const&\29\20const +6759:SkFontDescriptor::SkFontStyleWidthForWidthAxisValue\28float\29 +6760:SkFontData::~SkFontData\28\29 +6761:SkFontData::SkFontData\28std::__2::unique_ptr>\2c\20int\2c\20int\2c\20int\20const*\2c\20int\2c\20SkFontArguments::Palette::Override\20const*\2c\20int\29 +6762:SkFont::operator==\28SkFont\20const&\29\20const +6763:SkFont::getWidths\28unsigned\20short\20const*\2c\20int\2c\20float*\29\20const +6764:SkFont::getPaths\28unsigned\20short\20const*\2c\20int\2c\20void\20\28*\29\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29\2c\20void*\29\20const +6765:SkFindCubicInflections\28SkPoint\20const*\2c\20float*\29 +6766:SkFindCubicExtrema\28float\2c\20float\2c\20float\2c\20float\2c\20float*\29 +6767:SkFindBisector\28SkPoint\2c\20SkPoint\29 +6768:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda0'\28\29::operator\28\29\28\29\20const +6769:SkFibBlockSizes<4294967295u>::SkFibBlockSizes\28unsigned\20int\2c\20unsigned\20int\29::'lambda'\28\29::operator\28\29\28\29\20const +6770:SkFILEStream::~SkFILEStream\28\29 +6771:SkEvalQuadTangentAt\28SkPoint\20const*\2c\20float\29 +6772:SkEvalQuadAt\28SkPoint\20const*\2c\20float\2c\20SkPoint*\2c\20SkPoint*\29 +6773:SkEdgeClipper::next\28SkPoint*\29 +6774:SkEdgeClipper::clipQuad\28SkPoint\20const*\2c\20SkRect\20const&\29 +6775:SkEdgeClipper::clipLine\28SkPoint\2c\20SkPoint\2c\20SkRect\20const&\29 +6776:SkEdgeClipper::appendCubic\28SkPoint\20const*\2c\20bool\29 +6777:SkEdgeClipper::ClipPath\28SkPath\20const&\2c\20SkRect\20const&\2c\20bool\2c\20void\20\28*\29\28SkEdgeClipper*\2c\20bool\2c\20void*\29\2c\20void*\29 +6778:SkEdgeBuilder::build\28SkPath\20const&\2c\20SkIRect\20const*\2c\20bool\29::$_1::operator\28\29\28SkPoint\20const*\29\20const +6779:SkEdgeBuilder::buildEdges\28SkPath\20const&\2c\20SkIRect\20const*\29 +6780:SkEdgeBuilder::SkEdgeBuilder\28\29 +6781:SkEdge::updateLine\28int\2c\20int\2c\20int\2c\20int\29 +6782:SkEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20int\29 +6783:SkDynamicMemoryWStream::reset\28\29 +6784:SkDynamicMemoryWStream::Block::append\28void\20const*\2c\20unsigned\20long\29 +6785:SkDrawableList::newDrawableSnapshot\28\29 +6786:SkDrawTreatAsHairline\28SkPaint\20const&\2c\20SkMatrix\20const&\2c\20float*\29 +6787:SkDrawShadowMetrics::GetSpotShadowTransform\28SkPoint3\20const&\2c\20float\2c\20SkMatrix\20const&\2c\20SkPoint3\20const&\2c\20SkRect\20const&\2c\20bool\2c\20SkMatrix*\2c\20float*\29 +6788:SkDrawBase::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20SkRect\20const*\29\20const +6789:SkDrawBase::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const*\2c\20bool\2c\20bool\2c\20SkBlitter*\29\20const +6790:SkDrawBase::drawPaint\28SkPaint\20const&\29\20const +6791:SkDrawBase::SkDrawBase\28SkDrawBase\20const&\29 +6792:SkDrawBase::DrawToMask\28SkPath\20const&\2c\20SkIRect\20const&\2c\20SkMaskFilter\20const*\2c\20SkMatrix\20const*\2c\20SkMaskBuilder*\2c\20SkMaskBuilder::CreateMode\2c\20SkStrokeRec::InitStyle\29 +6793:SkDraw::drawSprite\28SkBitmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29\20const +6794:SkDraw::drawBitmap\28SkBitmap\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29\20const +6795:SkDraw::SkDraw\28SkDraw\20const&\29 +6796:SkDevice::setOrigin\28SkM44\20const&\2c\20int\2c\20int\29 +6797:SkDevice::setDeviceCoordinateSystem\28SkM44\20const&\2c\20SkM44\20const&\2c\20SkM44\20const&\2c\20int\2c\20int\29 +6798:SkDevice::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +6799:SkDevice::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +6800:SkDevice::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +6801:SkDescriptor::addEntry\28unsigned\20int\2c\20unsigned\20long\2c\20void\20const*\29 +6802:SkDeque::push_back\28\29 +6803:SkDeque::allocateBlock\28int\29 +6804:SkDeque::Iter::Iter\28SkDeque\20const&\2c\20SkDeque::Iter::IterStart\29 +6805:SkDashPathEffect::Make\28float\20const*\2c\20int\2c\20float\29 +6806:SkDashPath::InternalFilter\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20float\20const*\2c\20int\2c\20float\2c\20int\2c\20float\2c\20float\2c\20SkDashPath::StrokeRecApplication\29 +6807:SkDashPath::CalcDashParameters\28float\2c\20float\20const*\2c\20int\2c\20float*\2c\20int*\2c\20float*\2c\20float*\29 +6808:SkDashImpl::~SkDashImpl\28\29 +6809:SkDRect::setBounds\28SkDQuad\20const&\2c\20SkDQuad\20const&\2c\20double\2c\20double\29 +6810:SkDRect::setBounds\28SkDCubic\20const&\2c\20SkDCubic\20const&\2c\20double\2c\20double\29 +6811:SkDRect::setBounds\28SkDConic\20const&\2c\20SkDConic\20const&\2c\20double\2c\20double\29 +6812:SkDQuad::subDivide\28double\2c\20double\29\20const +6813:SkDQuad::otherPts\28int\2c\20SkDPoint\20const**\29\20const +6814:SkDQuad::isLinear\28int\2c\20int\29\20const +6815:SkDQuad::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +6816:SkDQuad::AddValidTs\28double*\2c\20int\2c\20double*\29 +6817:SkDPoint::roughlyEqual\28SkDPoint\20const&\29\20const +6818:SkDPoint::approximatelyDEqual\28SkDPoint\20const&\29\20const +6819:SkDCurveSweep::setCurveHullSweep\28SkPath::Verb\29 +6820:SkDCubic::monotonicInY\28\29\20const +6821:SkDCubic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +6822:SkDCubic::hullIntersects\28SkDPoint\20const*\2c\20int\2c\20bool*\29\20const +6823:SkDCubic::Coefficients\28double\20const*\2c\20double*\2c\20double*\2c\20double*\2c\20double*\29 +6824:SkDConic::subDivide\28double\2c\20double\29\20const +6825:SkCubics::RootsReal\28double\2c\20double\2c\20double\2c\20double\2c\20double*\29 +6826:SkCubicEdge::setCubicWithoutUpdate\28SkPoint\20const*\2c\20int\2c\20bool\29 +6827:SkCubicClipper::ChopMonoAtY\28SkPoint\20const*\2c\20float\2c\20float*\29 +6828:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20SkArenaAlloc*\2c\20sk_sp\29 +6829:SkCreateRasterPipelineBlitter\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkMatrix\20const&\2c\20SkArenaAlloc*\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +6830:SkContourMeasureIter::SkContourMeasureIter\28SkPath\20const&\2c\20bool\2c\20float\29 +6831:SkContourMeasureIter::Impl::compute_line_seg\28SkPoint\2c\20SkPoint\2c\20float\2c\20unsigned\20int\29 +6832:SkContourMeasure::~SkContourMeasure\28\29 +6833:SkContourMeasure::getSegment\28float\2c\20float\2c\20SkPath*\2c\20bool\29\20const +6834:SkConicalGradient::getCenterX1\28\29\20const +6835:SkConic::evalTangentAt\28float\29\20const +6836:SkConic::chop\28SkConic*\29\20const +6837:SkConic::chopIntoQuadsPOW2\28SkPoint*\2c\20int\29\20const +6838:SkConic::BuildUnitArc\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkRotationDirection\2c\20SkMatrix\20const*\2c\20SkConic*\29 +6839:SkColorToPMColor4f\28unsigned\20int\2c\20GrColorInfo\20const&\29 +6840:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29 +6841:SkColorSpaceSingletonFactory::Make\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +6842:SkColorSpaceLuminance::Fetch\28float\29 +6843:SkColorSpace::makeLinearGamma\28\29\20const +6844:SkColorSpace::computeLazyDstFields\28\29\20const +6845:SkColorSpace::SkColorSpace\28skcms_TransferFunction\20const&\2c\20skcms_Matrix3x3\20const&\29 +6846:SkColorFilters::Compose\28sk_sp\20const&\2c\20sk_sp\29 +6847:SkColorFilters::Blend\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20sk_sp\2c\20SkBlendMode\29 +6848:SkColorFilterShader::~SkColorFilterShader\28\29 +6849:SkColorFilterShader::flatten\28SkWriteBuffer&\29\20const +6850:SkColorFilterShader::Make\28sk_sp\2c\20float\2c\20sk_sp\29 +6851:SkColor4fXformer::~SkColor4fXformer\28\29 +6852:SkColor4fXformer::SkColor4fXformer\28SkGradientBaseShader\20const*\2c\20SkColorSpace*\2c\20bool\29 +6853:SkCoincidentSpans::contains\28SkOpPtT\20const*\2c\20SkOpPtT\20const*\29\20const +6854:SkChopQuadAtMaxCurvature\28SkPoint\20const*\2c\20SkPoint*\29 +6855:SkChopQuadAtHalf\28SkPoint\20const*\2c\20SkPoint*\29 +6856:SkChopCubicAt\28SkPoint\20const*\2c\20SkPoint*\2c\20float\2c\20float\29 +6857:SkChopCubicAtInflections\28SkPoint\20const*\2c\20SkPoint*\29 +6858:SkCharToGlyphCache::reset\28\29 +6859:SkCharToGlyphCache::findGlyphIndex\28int\29\20const +6860:SkCanvasVirtualEnforcer::SkCanvasVirtualEnforcer\28SkIRect\20const&\29 +6861:SkCanvasPriv::WriteLattice\28void*\2c\20SkCanvas::Lattice\20const&\29 +6862:SkCanvasPriv::GetDstClipAndMatrixCounts\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20int*\2c\20int*\29 +6863:SkCanvas::setMatrix\28SkM44\20const&\29 +6864:SkCanvas::internalSaveLayer\28SkCanvas::SaveLayerRec\20const&\2c\20SkCanvas::SaveLayerStrategy\2c\20bool\29 +6865:SkCanvas::internalDrawPaint\28SkPaint\20const&\29 +6866:SkCanvas::getDeviceClipBounds\28\29\20const +6867:SkCanvas::experimental_DrawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +6868:SkCanvas::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6869:SkCanvas::drawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6870:SkCanvas::drawPicture\28sk_sp\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +6871:SkCanvas::drawPicture\28SkPicture\20const*\29 +6872:SkCanvas::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +6873:SkCanvas::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +6874:SkCanvas::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +6875:SkCanvas::drawColor\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +6876:SkCanvas::drawAtlas\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +6877:SkCanvas::drawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +6878:SkCanvas::didTranslate\28float\2c\20float\29 +6879:SkCanvas::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +6880:SkCanvas::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +6881:SkCanvas::clipIRect\28SkIRect\20const&\2c\20SkClipOp\29 +6882:SkCanvas::SkCanvas\28sk_sp\29 +6883:SkCanvas::SkCanvas\28SkBitmap\20const&\2c\20SkSurfaceProps\20const&\29 +6884:SkCanvas::SkCanvas\28SkBitmap\20const&\29 +6885:SkCachedData::setData\28void*\29 +6886:SkCachedData::internalUnref\28bool\29\20const +6887:SkCachedData::internalRef\28bool\29\20const +6888:SkCachedData::SkCachedData\28void*\2c\20unsigned\20long\29 +6889:SkCachedData::SkCachedData\28unsigned\20long\2c\20SkDiscardableMemory*\29 +6890:SkCTMShader::isOpaque\28\29\20const +6891:SkBulkGlyphMetricsAndPaths::glyphs\28SkSpan\29 +6892:SkBreakIterator_client::~SkBreakIterator_client\28\29 +6893:SkBlurMaskFilterImpl::filterRectMask\28SkMaskBuilder*\2c\20SkRect\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\2c\20SkMaskBuilder::CreateMode\29\20const +6894:SkBlurMask::ComputeBlurredScanline\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20unsigned\20int\2c\20float\29 +6895:SkBlockAllocator::addBlock\28int\2c\20int\29 +6896:SkBlockAllocator::BlockIter::Item::advance\28SkBlockAllocator::Block*\29 +6897:SkBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +6898:SkBlitter::blitRectRegion\28SkIRect\20const&\2c\20SkRegion\20const&\29 +6899:SkBlitter::Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +6900:SkBlitter::ChooseSprite\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkPixmap\20const&\2c\20int\2c\20int\2c\20SkArenaAlloc*\2c\20sk_sp\29 +6901:SkBlenderBase::affectsTransparentBlack\28\29\20const +6902:SkBlendShader::~SkBlendShader\28\29_4460 +6903:SkBitmapDevice::~SkBitmapDevice\28\29 +6904:SkBitmapCache::Rec::~Rec\28\29 +6905:SkBitmapCache::Rec::install\28SkBitmap*\29 +6906:SkBitmapCache::Rec::diagnostic_only_getDiscardable\28\29\20const +6907:SkBitmapCache::Find\28SkBitmapCacheDesc\20const&\2c\20SkBitmap*\29 +6908:SkBitmapCache::Alloc\28SkBitmapCacheDesc\20const&\2c\20SkImageInfo\20const&\2c\20SkPixmap*\29 +6909:SkBitmap::tryAllocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29 +6910:SkBitmap::readPixels\28SkPixmap\20const&\29\20const +6911:SkBitmap::makeShader\28SkTileMode\2c\20SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\29\20const +6912:SkBitmap::getAddr\28int\2c\20int\29\20const +6913:SkBitmap::allocPixels\28SkImageInfo\20const&\2c\20unsigned\20long\29 +6914:SkBitmap::allocPixels\28SkImageInfo\20const&\29 +6915:SkBinaryWriteBuffer::writeFlattenable\28SkFlattenable\20const*\29 +6916:SkBinaryWriteBuffer::writeColor4f\28SkRGBA4f<\28SkAlphaType\293>\20const&\29 +6917:SkBigPicture::~SkBigPicture\28\29 +6918:SkBigPicture::cullRect\28\29\20const +6919:SkBigPicture::SnapshotArray::~SnapshotArray\28\29 +6920:SkBigPicture::SkBigPicture\28SkRect\20const&\2c\20sk_sp\2c\20std::__2::unique_ptr>\2c\20sk_sp\2c\20unsigned\20long\29 +6921:SkBidiFactory::MakeIterator\28unsigned\20short\20const*\2c\20int\2c\20SkBidiIterator::Direction\29\20const +6922:SkBezierCubic::Subdivide\28double\20const*\2c\20double\2c\20double*\29 +6923:SkBasicEdgeBuilder::~SkBasicEdgeBuilder\28\29 +6924:SkBasicEdgeBuilder::combineVertical\28SkEdge\20const*\2c\20SkEdge*\29 +6925:SkBaseShadowTessellator::releaseVertices\28\29 +6926:SkBaseShadowTessellator::handleQuad\28SkPoint\20const*\29 +6927:SkBaseShadowTessellator::handleQuad\28SkMatrix\20const&\2c\20SkPoint*\29 +6928:SkBaseShadowTessellator::handleLine\28SkMatrix\20const&\2c\20SkPoint*\29 +6929:SkBaseShadowTessellator::handleCubic\28SkMatrix\20const&\2c\20SkPoint*\29 +6930:SkBaseShadowTessellator::handleConic\28SkMatrix\20const&\2c\20SkPoint*\2c\20float\29 +6931:SkBaseShadowTessellator::finishPathPolygon\28\29 +6932:SkBaseShadowTessellator::computeConvexShadow\28float\2c\20float\2c\20bool\29 +6933:SkBaseShadowTessellator::computeConcaveShadow\28float\2c\20float\29 +6934:SkBaseShadowTessellator::clipUmbraPoint\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint*\29 +6935:SkBaseShadowTessellator::checkConvexity\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\29 +6936:SkBaseShadowTessellator::appendQuad\28unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +6937:SkBaseShadowTessellator::addInnerPoint\28SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20int*\29 +6938:SkBaseShadowTessellator::addEdge\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20int\2c\20SkTDArray\20const&\2c\20bool\2c\20bool\29 +6939:SkBaseShadowTessellator::addArc\28SkPoint\20const&\2c\20float\2c\20bool\29 +6940:SkBaseShadowTessellator::accumulateCentroid\28SkPoint\20const&\2c\20SkPoint\20const&\29 +6941:SkAutoSMalloc<1024ul>::reset\28unsigned\20long\2c\20SkAutoMalloc::OnShrink\2c\20bool*\29 +6942:SkAutoPixmapStorage::reset\28SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\29 +6943:SkAutoMalloc::SkAutoMalloc\28unsigned\20long\29 +6944:SkAutoDescriptor::reset\28unsigned\20long\29 +6945:SkAutoDescriptor::reset\28SkDescriptor\20const&\29 +6946:SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint\28\29 +6947:SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint\28SkCanvas*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\2c\20SkRect\20const&\29 +6948:SkAutoBlitterChoose::choose\28SkDrawBase\20const&\2c\20SkMatrix\20const*\2c\20SkPaint\20const&\2c\20bool\29 +6949:SkArenaAlloc::ensureSpace\28unsigned\20int\2c\20unsigned\20int\29 +6950:SkAnalyticEdgeBuilder::combineVertical\28SkAnalyticEdge\20const*\2c\20SkAnalyticEdge*\29 +6951:SkAnalyticEdge::update\28int\2c\20bool\29 +6952:SkAnalyticEdge::updateLine\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +6953:SkAnalyticEdge::setLine\28SkPoint\20const&\2c\20SkPoint\20const&\29 +6954:SkAlphaRuns::BreakAt\28short*\2c\20unsigned\20char*\2c\20int\29 +6955:SkAAClip::operator=\28SkAAClip\20const&\29 +6956:SkAAClip::op\28SkIRect\20const&\2c\20SkClipOp\29 +6957:SkAAClip::isRect\28\29\20const +6958:SkAAClip::RunHead::Iterate\28SkAAClip\20const&\29 +6959:SkAAClip::Builder::~Builder\28\29 +6960:SkAAClip::Builder::flushRow\28bool\29 +6961:SkAAClip::Builder::finish\28SkAAClip*\29 +6962:SkAAClip::Builder::Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +6963:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29 +6964:SkA8_Coverage_Blitter*\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29 +6965:SkA8_Blitter::~SkA8_Blitter\28\29 +6966:Simplify\28SkPath\20const&\2c\20SkPath*\29 +6967:Shift +6968:SharedGenerator::Make\28std::__2::unique_ptr>\29 +6969:SetSuperRound +6970:RuntimeEffectRPCallbacks::applyColorSpaceXform\28SkColorSpaceXformSteps\20const&\2c\20void\20const*\29 +6971:RunBasedAdditiveBlitter::~RunBasedAdditiveBlitter\28\29_3945 +6972:RunBasedAdditiveBlitter::advanceRuns\28\29 +6973:RunBasedAdditiveBlitter::RunBasedAdditiveBlitter\28SkBlitter*\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20bool\29 +6974:RgnOper::addSpan\28int\2c\20int\20const*\2c\20int\20const*\29 +6975:ReflexHash::hash\28TriangulationVertex*\29\20const +6976:ReadBase128 +6977:PorterDuffXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +6978:PathSegment::init\28\29 +6979:PS_Conv_Strtol +6980:PS_Conv_ASCIIHexDecode +6981:PDLCDXferProcessor::Make\28SkBlendMode\2c\20GrProcessorAnalysisColor\20const&\29 +6982:OpAsWinding::markReverse\28Contour*\2c\20Contour*\29 +6983:OpAsWinding::getDirection\28Contour&\29 +6984:OpAsWinding::checkContainerChildren\28Contour*\2c\20Contour*\29 +6985:OffsetEdge::computeCrossingDistance\28OffsetEdge\20const*\29 +6986:OT::sbix::sanitize\28hb_sanitize_context_t*\29\20const +6987:OT::sbix::accelerator_t::reference_png\28hb_font_t*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20unsigned\20int*\29\20const +6988:OT::sbix::accelerator_t::has_data\28\29\20const +6989:OT::sbix::accelerator_t::get_png_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +6990:OT::post::sanitize\28hb_sanitize_context_t*\29\20const +6991:OT::maxp::sanitize\28hb_sanitize_context_t*\29\20const +6992:OT::kern::sanitize\28hb_sanitize_context_t*\29\20const +6993:OT::hmtxvmtx::accelerator_t::get_advance_with_var_unscaled\28unsigned\20int\2c\20hb_font_t*\2c\20float*\29\20const +6994:OT::head::sanitize\28hb_sanitize_context_t*\29\20const +6995:OT::hb_ot_layout_lookup_accelerator_t*\20OT::hb_ot_layout_lookup_accelerator_t::create\28OT::Layout::GSUB_impl::SubstLookup\20const&\29 +6996:OT::hb_ot_apply_context_t::skipping_iterator_t::may_skip\28hb_glyph_info_t\20const&\29\20const +6997:OT::hb_ot_apply_context_t::skipping_iterator_t::init\28OT::hb_ot_apply_context_t*\2c\20bool\29 +6998:OT::hb_ot_apply_context_t::matcher_t::may_skip\28OT::hb_ot_apply_context_t\20const*\2c\20hb_glyph_info_t\20const&\29\20const +6999:OT::hb_kern_machine_t::kern\28hb_font_t*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20bool\29\20const +7000:OT::hb_accelerate_subtables_context_t::return_t\20OT::Context::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +7001:OT::hb_accelerate_subtables_context_t::return_t\20OT::ChainContext::dispatch\28OT::hb_accelerate_subtables_context_t*\29\20const +7002:OT::gvar::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7003:OT::gvar::get_offset\28unsigned\20int\2c\20unsigned\20int\29\20const +7004:OT::gvar::accelerator_t::infer_delta\28hb_array_t\2c\20hb_array_t\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\20contour_point_t::*\29 +7005:OT::glyf_impl::composite_iter_tmpl::set_current\28OT::glyf_impl::CompositeGlyphRecord\20const*\29 +7006:OT::glyf_impl::composite_iter_tmpl::__next__\28\29 +7007:OT::glyf_impl::SimpleGlyph::read_points\28OT::IntType\20const*&\2c\20hb_array_t\2c\20OT::IntType\20const*\2c\20float\20contour_point_t::*\2c\20OT::glyf_impl::SimpleGlyph::simple_glyph_flag_t\2c\20OT::glyf_impl::SimpleGlyph::simple_glyph_flag_t\29 +7008:OT::glyf_impl::Glyph::get_composite_iterator\28\29\20const +7009:OT::glyf_impl::CompositeGlyphRecord::transform\28float\20const\20\28&\29\20\5b4\5d\2c\20hb_array_t\29 +7010:OT::glyf_impl::CompositeGlyphRecord::get_transformation\28float\20\28&\29\20\5b4\5d\2c\20contour_point_t&\29\20const +7011:OT::glyf_accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\29\20const +7012:OT::fvar::sanitize\28hb_sanitize_context_t*\29\20const +7013:OT::cmap::sanitize\28hb_sanitize_context_t*\29\20const +7014:OT::cmap::accelerator_t::get_nominal_glyph\28unsigned\20int\2c\20unsigned\20int*\2c\20hb_cache_t<21u\2c\2016u\2c\208u\2c\20true>*\29\20const +7015:OT::cmap::accelerator_t::_cached_get\28unsigned\20int\2c\20unsigned\20int*\2c\20hb_cache_t<21u\2c\2016u\2c\208u\2c\20true>*\29\20const +7016:OT::cff2::sanitize\28hb_sanitize_context_t*\29\20const +7017:OT::cff2::accelerator_templ_t>::_fini\28\29 +7018:OT::cff1::sanitize\28hb_sanitize_context_t*\29\20const +7019:OT::cff1::accelerator_templ_t>::glyph_to_sid\28unsigned\20int\2c\20CFF::code_pair_t*\29\20const +7020:OT::cff1::accelerator_templ_t>::_fini\28\29 +7021:OT::cff1::accelerator_t::gname_t::cmp\28void\20const*\2c\20void\20const*\29 +7022:OT::avar::sanitize\28hb_sanitize_context_t*\29\20const +7023:OT::VariationDevice::get_delta\28hb_font_t*\2c\20OT::VariationStore\20const&\2c\20float*\29\20const +7024:OT::VarData::get_row_size\28\29\20const +7025:OT::VVAR::sanitize\28hb_sanitize_context_t*\29\20const +7026:OT::VORG::sanitize\28hb_sanitize_context_t*\29\20const +7027:OT::UnsizedArrayOf\2c\2014u>>\20const&\20OT::operator+\2c\20\28void*\290>\28hb_blob_ptr_t\20const&\2c\20OT::OffsetTo\2c\2014u>>\2c\20OT::IntType\2c\20false>\20const&\29 +7028:OT::TupleVariationHeader::get_size\28unsigned\20int\29\20const +7029:OT::TupleVariationData::unpack_points\28OT::IntType\20const*&\2c\20hb_vector_t&\2c\20OT::IntType\20const*\29 +7030:OT::TupleVariationData::unpack_deltas\28OT::IntType\20const*&\2c\20hb_vector_t&\2c\20OT::IntType\20const*\29 +7031:OT::TupleVariationData::tuple_iterator_t::is_valid\28\29\20const +7032:OT::SortedArrayOf\2c\20OT::IntType>::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\29 +7033:OT::SVG::sanitize\28hb_sanitize_context_t*\29\20const +7034:OT::RuleSet::would_apply\28OT::hb_would_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +7035:OT::RuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ContextApplyLookupContext\20const&\29\20const +7036:OT::ResourceMap::get_type_record\28unsigned\20int\29\20const +7037:OT::ResourceMap::get_type_count\28\29\20const +7038:OT::RecordArrayOf::find_index\28unsigned\20int\2c\20unsigned\20int*\29\20const +7039:OT::PaintTranslate::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7040:OT::PaintSolid::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7041:OT::PaintSkewAroundCenter::sanitize\28hb_sanitize_context_t*\29\20const +7042:OT::PaintSkewAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7043:OT::PaintSkew::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7044:OT::PaintScaleUniformAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7045:OT::PaintScaleUniform::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7046:OT::PaintScaleAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7047:OT::PaintScale::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7048:OT::PaintRotateAroundCenter::sanitize\28hb_sanitize_context_t*\29\20const +7049:OT::PaintRotateAroundCenter::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7050:OT::PaintRotate::sanitize\28hb_sanitize_context_t*\29\20const +7051:OT::PaintRotate::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7052:OT::OpenTypeFontFile::sanitize\28hb_sanitize_context_t*\29\20const +7053:OT::OS2::sanitize\28hb_sanitize_context_t*\29\20const +7054:OT::MVAR::sanitize\28hb_sanitize_context_t*\29\20const +7055:OT::Lookup::serialize\28hb_serialize_context_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +7056:OT::Lookup*\20hb_serialize_context_t::extend_size\28OT::Lookup*\2c\20unsigned\20long\2c\20bool\29 +7057:OT::Layout::propagate_attachment_offsets\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +7058:OT::Layout::GPOS_impl::reverse_cursive_minor_offset\28hb_glyph_position_t*\2c\20unsigned\20int\2c\20hb_direction_t\2c\20unsigned\20int\29 +7059:OT::Layout::GPOS_impl::ValueFormat::sanitize_value_devices\28hb_sanitize_context_t*\2c\20void\20const*\2c\20OT::IntType\20const*\29\20const +7060:OT::Layout::Common::RangeRecord\20const&\20OT::SortedArrayOf\2c\20OT::IntType>::bsearch\28unsigned\20int\20const&\2c\20OT::Layout::Common::RangeRecord\20const&\29\20const +7061:OT::Layout::Common::CoverageFormat2_4*\20hb_serialize_context_t::extend_min>\28OT::Layout::Common::CoverageFormat2_4*\29 +7062:OT::Layout::Common::Coverage::sanitize\28hb_sanitize_context_t*\29\20const +7063:OT::Layout::Common::Coverage::get_population\28\29\20const +7064:OT::LangSys::sanitize\28hb_sanitize_context_t*\2c\20OT::Record_sanitize_closure_t\20const*\29\20const +7065:OT::IndexSubtableRecord::get_image_data\28unsigned\20int\2c\20void\20const*\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7066:OT::IndexArray::get_indexes\28unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7067:OT::HintingDevice::get_delta\28unsigned\20int\2c\20int\29\20const +7068:OT::HVARVVAR::get_advance_delta_unscaled\28unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\2c\20float*\29\20const +7069:OT::GSUBGPOS::get_script_list\28\29\20const +7070:OT::GSUBGPOS::get_feature_variations\28\29\20const +7071:OT::GSUBGPOS::accelerator_t::get_accel\28unsigned\20int\29\20const +7072:OT::GDEF::sanitize\28hb_sanitize_context_t*\29\20const +7073:OT::GDEF::get_mark_glyph_sets\28\29\20const +7074:OT::GDEF::accelerator_t::get_glyph_props\28unsigned\20int\29\20const +7075:OT::Feature::sanitize\28hb_sanitize_context_t*\2c\20OT::Record_sanitize_closure_t\20const*\29\20const +7076:OT::ContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +7077:OT::ColorStop::get_color_stop\28OT::hb_paint_context_t*\2c\20hb_color_stop_t*\2c\20unsigned\20int\2c\20OT::VarStoreInstancer\20const&\29\20const +7078:OT::ColorLine::static_get_extend\28hb_color_line_t*\2c\20void*\2c\20void*\29 +7079:OT::CmapSubtableLongSegmented::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +7080:OT::CmapSubtableLongGroup\20const&\20OT::SortedArrayOf>::bsearch\28unsigned\20int\20const&\2c\20OT::CmapSubtableLongGroup\20const&\29\20const +7081:OT::CmapSubtableFormat4::accelerator_t::init\28OT::CmapSubtableFormat4\20const*\29 +7082:OT::CmapSubtableFormat4::accelerator_t::get_glyph\28unsigned\20int\2c\20unsigned\20int*\29\20const +7083:OT::ClipBoxFormat1::get_clip_box\28OT::ClipBoxData&\2c\20OT::VarStoreInstancer\20const&\29\20const +7084:OT::ClassDef::cost\28\29\20const +7085:OT::ChainRuleSet::would_apply\28OT::hb_would_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +7086:OT::ChainRuleSet::apply\28OT::hb_ot_apply_context_t*\2c\20OT::ChainContextApplyLookupContext\20const&\29\20const +7087:OT::ChainContextFormat2_5::_apply\28OT::hb_ot_apply_context_t*\2c\20bool\29\20const +7088:OT::CPAL::sanitize\28hb_sanitize_context_t*\29\20const +7089:OT::COLR::sanitize\28hb_sanitize_context_t*\29\20const +7090:OT::COLR::get_base_glyph_paint\28unsigned\20int\29\20const +7091:OT::CBLC::sanitize\28hb_sanitize_context_t*\29\20const +7092:OT::CBLC::choose_strike\28hb_font_t*\29\20const +7093:OT::CBDT::sanitize\28hb_sanitize_context_t*\29\20const +7094:OT::CBDT::accelerator_t::get_extents\28hb_font_t*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20bool\29\20const +7095:OT::BitmapSizeTable::find_table\28unsigned\20int\2c\20void\20const*\2c\20void\20const**\29\20const +7096:OT::ArrayOf>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7097:OT::ArrayOf\2c\20OT::IntType>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7098:OT::ArrayOf>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7099:OT::ArrayOf>>::sanitize_shallow\28hb_sanitize_context_t*\29\20const +7100:OT::Affine2x3::paint_glyph\28OT::hb_paint_context_t*\2c\20unsigned\20int\29\20const +7101:MaskValue*\20SkTLazy::init\28MaskValue\20const&\29 +7102:MakeRasterCopyPriv\28SkPixmap\20const&\2c\20unsigned\20int\29 +7103:Load_SBit_Png +7104:LineQuadraticIntersections::verticalIntersect\28double\2c\20double*\29 +7105:LineQuadraticIntersections::intersectRay\28double*\29 +7106:LineQuadraticIntersections::horizontalIntersect\28double\2c\20double*\29 +7107:LineCubicIntersections::intersectRay\28double*\29 +7108:LineCubicIntersections::VerticalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +7109:LineCubicIntersections::HorizontalIntersect\28SkDCubic\20const&\2c\20double\2c\20double*\29 +7110:LineConicIntersections::verticalIntersect\28double\2c\20double*\29 +7111:LineConicIntersections::intersectRay\28double*\29 +7112:LineConicIntersections::horizontalIntersect\28double\2c\20double*\29 +7113:Ins_UNKNOWN +7114:Ins_SxVTL +7115:InitializeCompoundDictionaryCopy +7116:HandleCoincidence\28SkOpContourHead*\2c\20SkOpCoincidence*\29 +7117:GrWritePixelsTask::~GrWritePixelsTask\28\29 +7118:GrWindowRectsState::operator=\28GrWindowRectsState\20const&\29 +7119:GrWindowRectsState::operator==\28GrWindowRectsState\20const&\29\20const +7120:GrWindowRectangles::GrWindowRectangles\28GrWindowRectangles\20const&\29 +7121:GrWaitRenderTask::~GrWaitRenderTask\28\29 +7122:GrVertexBufferAllocPool::makeSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +7123:GrVertexBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +7124:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20SkPathFillType\2c\20skgpu::VertexWriter\29\20const +7125:GrTriangulator::polysToTriangles\28GrTriangulator::Poly*\2c\20GrEagerVertexAllocator*\29\20const +7126:GrTriangulator::mergeEdgesBelow\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +7127:GrTriangulator::mergeEdgesAbove\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::EdgeList*\2c\20GrTriangulator::Vertex**\2c\20GrTriangulator::Comparator\20const&\29\20const +7128:GrTriangulator::makeSortedVertex\28SkPoint\20const&\2c\20unsigned\20char\2c\20GrTriangulator::VertexList*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::Comparator\20const&\29\20const +7129:GrTriangulator::makeEdge\28GrTriangulator::Vertex*\2c\20GrTriangulator::Vertex*\2c\20GrTriangulator::EdgeType\2c\20GrTriangulator::Comparator\20const&\29 +7130:GrTriangulator::computeBisector\28GrTriangulator::Edge*\2c\20GrTriangulator::Edge*\2c\20GrTriangulator::Vertex*\29\20const +7131:GrTriangulator::appendQuadraticToContour\28SkPoint\20const*\2c\20float\2c\20GrTriangulator::VertexList*\29\20const +7132:GrTriangulator::allocateMonotonePoly\28GrTriangulator::Edge*\2c\20GrTriangulator::Side\2c\20int\29 +7133:GrTriangulator::Edge::recompute\28\29 +7134:GrTriangulator::Edge::intersect\28GrTriangulator::Edge\20const&\2c\20SkPoint*\2c\20unsigned\20char*\29\20const +7135:GrTriangulator::CountPoints\28GrTriangulator::Poly*\2c\20SkPathFillType\29 +7136:GrTriangulator::BreadcrumbTriangleList::concat\28GrTriangulator::BreadcrumbTriangleList&&\29 +7137:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29 +7138:GrThreadSafeCache::makeNewEntryMRU\28GrThreadSafeCache::Entry*\29 +7139:GrThreadSafeCache::makeExistingEntryMRU\28GrThreadSafeCache::Entry*\29 +7140:GrThreadSafeCache::findVertsWithData\28skgpu::UniqueKey\20const&\29 +7141:GrThreadSafeCache::addVertsWithData\28skgpu::UniqueKey\20const&\2c\20sk_sp\2c\20bool\20\28*\29\28SkData*\2c\20SkData*\29\29 +7142:GrThreadSafeCache::Trampoline::~Trampoline\28\29 +7143:GrThreadSafeCache::Entry::set\28skgpu::UniqueKey\20const&\2c\20sk_sp\29 +7144:GrThreadSafeCache::Entry::makeEmpty\28\29 +7145:GrThreadSafeCache::CreateLazyView\28GrDirectContext*\2c\20GrColorType\2c\20SkISize\2c\20GrSurfaceOrigin\2c\20SkBackingFit\29 +7146:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29 +7147:GrTextureRenderTargetProxy::initSurfaceFlags\28GrCaps\20const&\29 +7148:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29 +7149:GrTextureRenderTargetProxy::GrTextureRenderTargetProxy\28GrCaps\20const&\2c\20std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20int\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\2c\20std::__2::basic_string_view>\29 +7150:GrTextureProxy::~GrTextureProxy\28\29_9411 +7151:GrTextureProxy::~GrTextureProxy\28\29_9410 +7152:GrTextureProxy::setUniqueKey\28GrProxyProvider*\2c\20skgpu::UniqueKey\20const&\29 +7153:GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +7154:GrTextureProxy::instantiate\28GrResourceProvider*\29 +7155:GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +7156:GrTextureProxy::callbackDesc\28\29\20const +7157:GrTextureProxy::ProxiesAreCompatibleAsDynamicState\28GrSurfaceProxy\20const*\2c\20GrSurfaceProxy\20const*\29 +7158:GrTextureProxy::GrTextureProxy\28sk_sp\2c\20GrSurfaceProxy::UseAllocator\2c\20GrDDLProvider\29 +7159:GrTextureEffect::~GrTextureEffect\28\29 +7160:GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::$_1::operator\28\29\28int\2c\20GrSamplerState::WrapMode\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20GrTextureEffect::Sampling::Sampling\28GrSurfaceProxy\20const&\2c\20GrSamplerState\2c\20SkRect\20const&\2c\20SkRect\20const*\2c\20float\20const*\2c\20bool\2c\20GrCaps\20const&\2c\20SkPoint\29::Span\2c\20float\29\20const +7161:GrTextureEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29::$_0::operator\28\29\28float*\2c\20GrResourceHandle\29\20const +7162:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::$_2::operator\28\29\28GrTextureEffect::ShaderMode\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +7163:GrTexture::onGpuMemorySize\28\29\20const +7164:GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +7165:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29 +7166:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29 +7167:GrSurfaceProxyView::operator=\28GrSurfaceProxyView\20const&\29 +7168:GrSurfaceProxyView::operator==\28GrSurfaceProxyView\20const&\29\20const +7169:GrSurfaceProxyPriv::exactify\28\29 +7170:GrSurfaceProxyPriv::assign\28sk_sp\29 +7171:GrSurfaceProxy::GrSurfaceProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +7172:GrSurfaceProxy::GrSurfaceProxy\28GrBackendFormat\20const&\2c\20SkISize\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrInternalSurfaceFlags\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +7173:GrSurface::setRelease\28sk_sp\29 +7174:GrSurface::onRelease\28\29 +7175:GrStyledShape::setInheritedKey\28GrStyledShape\20const&\2c\20GrStyle::Apply\2c\20float\29 +7176:GrStyledShape::asRRect\28SkRRect*\2c\20bool*\29\20const +7177:GrStyledShape::asLine\28SkPoint*\2c\20bool*\29\20const +7178:GrStyledShape::GrStyledShape\28SkRRect\20const&\2c\20SkPathDirection\2c\20unsigned\20int\2c\20bool\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +7179:GrStyledShape::GrStyledShape\28SkRRect\20const&\2c\20GrStyle\20const&\2c\20GrStyledShape::DoSimplify\29 +7180:GrStyledShape::GrStyledShape\28SkPath\20const&\2c\20SkPaint\20const&\2c\20GrStyledShape::DoSimplify\29 +7181:GrStyle::resetToInitStyle\28SkStrokeRec::InitStyle\29 +7182:GrStyle::applyToPath\28SkPath*\2c\20SkStrokeRec::InitStyle*\2c\20SkPath\20const&\2c\20float\29\20const +7183:GrStyle::applyPathEffect\28SkPath*\2c\20SkStrokeRec*\2c\20SkPath\20const&\29\20const +7184:GrStyle::MatrixToScaleFactor\28SkMatrix\20const&\29 +7185:GrStyle::DashInfo::operator=\28GrStyle::DashInfo\20const&\29 +7186:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29 +7187:GrStrokeTessellationShader::Impl::~Impl\28\29 +7188:GrStagingBufferManager::detachBuffers\28\29 +7189:GrSkSLFP::~GrSkSLFP\28\29 +7190:GrSkSLFP::Impl::~Impl\28\29 +7191:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineStruct\28char\20const*\29 +7192:GrSimpleMesh::~GrSimpleMesh\28\29 +7193:GrShape::simplify\28unsigned\20int\29 +7194:GrShape::setArc\28SkArc\20const&\29 +7195:GrShape::conservativeContains\28SkRect\20const&\29\20const +7196:GrShape::closed\28\29\20const +7197:GrShape::GrShape\28SkRect\20const&\29 +7198:GrShape::GrShape\28SkRRect\20const&\29 +7199:GrShape::GrShape\28SkPath\20const&\29 +7200:GrShaderVar::GrShaderVar\28SkString\2c\20SkSLType\2c\20GrShaderVar::TypeModifier\2c\20int\2c\20SkString\2c\20SkString\29 +7201:GrScissorState::operator==\28GrScissorState\20const&\29\20const +7202:GrScissorState::intersect\28SkIRect\20const&\29 +7203:GrSWMaskHelper::toTextureView\28GrRecordingContext*\2c\20SkBackingFit\29 +7204:GrSWMaskHelper::drawShape\28GrStyledShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +7205:GrSWMaskHelper::drawShape\28GrShape\20const&\2c\20SkMatrix\20const&\2c\20GrAA\2c\20unsigned\20char\29 +7206:GrResourceProvider::writePixels\28sk_sp\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\29\20const +7207:GrResourceProvider::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +7208:GrResourceProvider::prepareLevels\28GrBackendFormat\20const&\2c\20GrColorType\2c\20SkISize\2c\20GrMipLevel\20const*\2c\20int\2c\20skia_private::AutoSTArray<14\2c\20GrMipLevel>*\2c\20skia_private::AutoSTArray<14\2c\20std::__2::unique_ptr>>*\29\20const +7209:GrResourceProvider::getExactScratch\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7210:GrResourceProvider::findAndRefScratchTexture\28skgpu::ScratchKey\20const&\2c\20std::__2::basic_string_view>\29 +7211:GrResourceProvider::findAndRefScratchTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7212:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7213:GrResourceProvider::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20GrColorType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMipLevel\20const*\2c\20std::__2::basic_string_view>\29 +7214:GrResourceProvider::createBuffer\28void\20const*\2c\20unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +7215:GrResourceProvider::createApproxTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7216:GrResourceCache::removeResource\28GrGpuResource*\29 +7217:GrResourceCache::removeFromNonpurgeableArray\28GrGpuResource*\29 +7218:GrResourceCache::releaseAll\28\29 +7219:GrResourceCache::refAndMakeResourceMRU\28GrGpuResource*\29 +7220:GrResourceCache::processFreedGpuResources\28\29 +7221:GrResourceCache::insertResource\28GrGpuResource*\29 +7222:GrResourceCache::findAndRefUniqueResource\28skgpu::UniqueKey\20const&\29 +7223:GrResourceCache::didChangeBudgetStatus\28GrGpuResource*\29 +7224:GrResourceCache::addToNonpurgeableArray\28GrGpuResource*\29 +7225:GrResourceAllocator::~GrResourceAllocator\28\29 +7226:GrResourceAllocator::planAssignment\28\29 +7227:GrResourceAllocator::expire\28unsigned\20int\29 +7228:GrResourceAllocator::Register*\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29 +7229:GrResourceAllocator::IntervalList::popHead\28\29 +7230:GrResourceAllocator::IntervalList::insertByIncreasingStart\28GrResourceAllocator::Interval*\29 +7231:GrRenderTask::makeSkippable\28\29 +7232:GrRenderTask::isUsed\28GrSurfaceProxy*\29\20const +7233:GrRenderTask::isInstantiated\28\29\20const +7234:GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9258 +7235:GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9256 +7236:GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7237:GrRenderTargetProxy::isMSAADirty\28\29\20const +7238:GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7239:GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7240:GrRenderTargetProxy::callbackDesc\28\29\20const +7241:GrRenderTarget::GrRenderTarget\28GrGpu*\2c\20SkISize\20const&\2c\20int\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\2c\20sk_sp\29 +7242:GrRecordingContext::init\28\29 +7243:GrRecordingContext::destroyDrawingManager\28\29 +7244:GrRecordingContext::colorTypeSupportedAsSurface\28SkColorType\29\20const +7245:GrRecordingContext::abandoned\28\29 +7246:GrRecordingContext::abandonContext\28\29 +7247:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29 +7248:GrRRectEffect::Make\28std::__2::unique_ptr>\2c\20GrClipEdgeType\2c\20SkRRect\20const&\2c\20GrShaderCaps\20const&\29 +7249:GrQuadUtils::TessellationHelper::outset\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuad*\2c\20GrQuad*\29 +7250:GrQuadUtils::TessellationHelper::getOutsetRequest\28skvx::Vec<4\2c\20float>\20const&\29 +7251:GrQuadUtils::TessellationHelper::adjustVertices\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuadUtils::TessellationHelper::Vertices*\29 +7252:GrQuadUtils::TessellationHelper::adjustDegenerateVertices\28skvx::Vec<4\2c\20float>\20const&\2c\20GrQuadUtils::TessellationHelper::Vertices*\29 +7253:GrQuadUtils::TessellationHelper::Vertices::moveTo\28skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20float>\20const&\2c\20skvx::Vec<4\2c\20int>\20const&\29 +7254:GrQuadUtils::ClipToW0\28DrawQuad*\2c\20DrawQuad*\29 +7255:GrQuadBuffer<\28anonymous\20namespace\29::TextureOpImpl::ColorSubsetAndAA>::append\28GrQuad\20const&\2c\20\28anonymous\20namespace\29::TextureOpImpl::ColorSubsetAndAA&&\2c\20GrQuad\20const*\29 +7256:GrQuadBuffer<\28anonymous\20namespace\29::TextureOpImpl::ColorSubsetAndAA>::GrQuadBuffer\28int\2c\20bool\29 +7257:GrQuad::point\28int\29\20const +7258:GrQuad::bounds\28\29\20const::'lambda0'\28float\20const*\29::operator\28\29\28float\20const*\29\20const +7259:GrQuad::bounds\28\29\20const::'lambda'\28float\20const*\29::operator\28\29\28float\20const*\29\20const +7260:GrProxyProvider::removeUniqueKeyFromProxy\28GrTextureProxy*\29 +7261:GrProxyProvider::processInvalidUniqueKeyImpl\28skgpu::UniqueKey\20const&\2c\20GrTextureProxy*\2c\20GrProxyProvider::InvalidateGPUResource\2c\20GrProxyProvider::RemoveTableEntry\29 +7262:GrProxyProvider::createLazyProxy\28std::__2::function&&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20GrMipmapStatus\2c\20GrInternalSurfaceFlags\2c\20SkBackingFit\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20GrSurfaceProxy::UseAllocator\2c\20std::__2::basic_string_view>\29 +7263:GrProxyProvider::adoptUniqueKeyFromSurface\28GrTextureProxy*\2c\20GrSurface\20const*\29 +7264:GrProcessorSet::operator==\28GrProcessorSet\20const&\29\20const +7265:GrPorterDuffXPFactory::Get\28SkBlendMode\29 +7266:GrPixmap::GrPixmap\28SkPixmap\20const&\29 +7267:GrPipeline::peekDstTexture\28\29\20const +7268:GrPipeline::GrPipeline\28GrPipeline::InitArgs\20const&\2c\20sk_sp\2c\20GrAppliedHardClip\20const&\29 +7269:GrPersistentCacheUtils::ShaderMetadata::~ShaderMetadata\28\29 +7270:GrPersistentCacheUtils::GetType\28SkReadBuffer*\29 +7271:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29 +7272:GrPathUtils::QuadUVMatrix::set\28SkPoint\20const*\29 +7273:GrPathUtils::QuadUVMatrix::apply\28void*\2c\20int\2c\20unsigned\20long\2c\20unsigned\20long\29\20const +7274:GrPathTessellationShader::MakeStencilOnlyPipeline\28GrTessellationShader::ProgramArgs\20const&\2c\20GrAAType\2c\20GrAppliedHardClip\20const&\2c\20GrPipeline::InputFlags\29 +7275:GrPathTessellationShader::Impl::~Impl\28\29 +7276:GrOpsRenderPass::~GrOpsRenderPass\28\29 +7277:GrOpsRenderPass::resetActiveBuffers\28\29 +7278:GrOpsRenderPass::draw\28int\2c\20int\29 +7279:GrOpsRenderPass::drawIndexPattern\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +7280:GrOpFlushState::~GrOpFlushState\28\29_9045 +7281:GrOpFlushState::smallPathAtlasManager\28\29\20const +7282:GrOpFlushState::reset\28\29 +7283:GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +7284:GrOpFlushState::putBackIndices\28int\29 +7285:GrOpFlushState::executeDrawsAndUploadsForMeshDrawOp\28GrOp\20const*\2c\20SkRect\20const&\2c\20GrPipeline\20const*\2c\20GrUserStencilSettings\20const*\29 +7286:GrOpFlushState::drawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +7287:GrOpFlushState::doUpload\28std::__2::function&\29>&\2c\20bool\29 +7288:GrOpFlushState::addASAPUpload\28std::__2::function&\29>&&\29 +7289:GrOpFlushState::OpArgs::OpArgs\28GrOp*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7290:GrOp::setTransformedBounds\28SkRect\20const&\2c\20SkMatrix\20const&\2c\20GrOp::HasAABloat\2c\20GrOp::IsHairline\29 +7291:GrOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7292:GrOp::combineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +7293:GrNonAtomicRef::unref\28\29\20const +7294:GrNonAtomicRef::unref\28\29\20const +7295:GrNonAtomicRef::unref\28\29\20const +7296:GrNativeRect::operator!=\28GrNativeRect\20const&\29\20const +7297:GrMeshDrawTarget::allocPrimProcProxyPtrs\28int\29 +7298:GrMeshDrawOp::PatternHelper::init\28GrMeshDrawTarget*\2c\20GrPrimitiveType\2c\20unsigned\20long\2c\20sk_sp\2c\20int\2c\20int\2c\20int\2c\20int\29 +7299:GrMemoryPool::allocate\28unsigned\20long\29 +7300:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29 +7301:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::changed\28\29 +7302:GrMakeCachedBitmapProxyView\28GrRecordingContext*\2c\20SkBitmap\20const&\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\29::$_0::operator\28\29\28GrTextureProxy*\29\20const +7303:GrIndexBufferAllocPool::makeSpace\28int\2c\20sk_sp*\2c\20int*\29 +7304:GrIndexBufferAllocPool::makeSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +7305:GrImageInfo::operator=\28GrImageInfo&&\29 +7306:GrImageInfo::GrImageInfo\28GrColorType\2c\20SkAlphaType\2c\20sk_sp\2c\20int\2c\20int\29 +7307:GrImageContext::abandonContext\28\29 +7308:GrHashMapWithCache::find\28unsigned\20int\20const&\29\20const +7309:GrGradientBitmapCache::release\28GrGradientBitmapCache::Entry*\29\20const +7310:GrGpuResource::setLabel\28std::__2::basic_string_view>\29 +7311:GrGpuResource::makeBudgeted\28\29 +7312:GrGpuResource::GrGpuResource\28GrGpu*\2c\20std::__2::basic_string_view>\29 +7313:GrGpuResource::CacheAccess::abandon\28\29 +7314:GrGpuBuffer::ComputeScratchKeyForDynamicBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20skgpu::ScratchKey*\29 +7315:GrGpu::~GrGpu\28\29 +7316:GrGpu::submitToGpu\28GrSubmitInfo\20const&\29 +7317:GrGpu::regenerateMipMapLevels\28GrTexture*\29 +7318:GrGpu::createTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7319:GrGpu::createTextureCommon\28SkISize\2c\20GrBackendFormat\20const&\2c\20GrTextureType\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +7320:GrGpu::createBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +7321:GrGpu::callSubmittedProcs\28bool\29 +7322:GrGeometryProcessor::AttributeSet::addToKey\28skgpu::KeyBuilder*\29\20const +7323:GrGeometryProcessor::AttributeSet::Iter::skipUninitialized\28\29 +7324:GrGeometryProcessor::Attribute&\20skia_private::TArray::emplace_back\28char\20const\20\28&\29\20\5b26\5d\2c\20GrVertexAttribType&&\2c\20SkSLType&&\29 +7325:GrGLTextureParameters::invalidate\28\29 +7326:GrGLTextureParameters::SamplerOverriddenState::SamplerOverriddenState\28\29 +7327:GrGLTexture::~GrGLTexture\28\29_11853 +7328:GrGLTexture::~GrGLTexture\28\29_11852 +7329:GrGLTexture::MakeWrapped\28GrGLGpu*\2c\20GrMipmapStatus\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrWrapCacheable\2c\20GrIOType\2c\20std::__2::basic_string_view>\29 +7330:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20skgpu::Budgeted\2c\20GrGLTexture::Desc\20const&\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +7331:GrGLTexture::GrGLTexture\28GrGLGpu*\2c\20GrGLTexture::Desc\20const&\2c\20sk_sp\2c\20GrMipmapStatus\2c\20std::__2::basic_string_view>\29 +7332:GrGLSemaphore::~GrGLSemaphore\28\29 +7333:GrGLSLVaryingHandler::addAttribute\28GrShaderVar\20const&\29 +7334:GrGLSLVarying::vsOutVar\28\29\20const +7335:GrGLSLVarying::fsInVar\28\29\20const +7336:GrGLSLUniformHandler::liftUniformToVertexShader\28GrProcessor\20const&\2c\20SkString\29 +7337:GrGLSLShaderBuilder::nextStage\28\29 +7338:GrGLSLShaderBuilder::finalize\28unsigned\20int\29 +7339:GrGLSLShaderBuilder::emitFunction\28char\20const*\2c\20char\20const*\29 +7340:GrGLSLShaderBuilder::emitFunctionPrototype\28char\20const*\29 +7341:GrGLSLShaderBuilder::appendTextureLookupAndBlend\28char\20const*\2c\20SkBlendMode\2c\20GrResourceHandle\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29 +7342:GrGLSLShaderBuilder::appendDecls\28SkTBlockList\20const&\2c\20SkString*\29\20const +7343:GrGLSLShaderBuilder::appendColorGamutXform\28SkString*\2c\20char\20const*\2c\20GrGLSLColorSpaceXformHelper*\29::$_0::operator\28\29\28char\20const*\2c\20GrResourceHandle\2c\20skcms_TFType\29\20const +7344:GrGLSLShaderBuilder::GrGLSLShaderBuilder\28GrGLSLProgramBuilder*\29 +7345:GrGLSLProgramDataManager::setRuntimeEffectUniforms\28SkSpan\2c\20SkSpan\20const>\2c\20SkSpan\2c\20void\20const*\29\20const +7346:GrGLSLProgramBuilder::~GrGLSLProgramBuilder\28\29 +7347:GrGLSLFragmentShaderBuilder::onFinalize\28\29 +7348:GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +7349:GrGLSLColorSpaceXformHelper::isNoop\28\29\20const +7350:GrGLSLBlend::SetBlendModeUniformData\28GrGLSLProgramDataManager\20const&\2c\20GrResourceHandle\2c\20SkBlendMode\29 +7351:GrGLSLBlend::BlendExpression\28GrProcessor\20const*\2c\20GrGLSLUniformHandler*\2c\20GrResourceHandle*\2c\20char\20const*\2c\20char\20const*\2c\20SkBlendMode\29 +7352:GrGLRenderTarget::~GrGLRenderTarget\28\29_11823 +7353:GrGLRenderTarget::~GrGLRenderTarget\28\29_11822 +7354:GrGLRenderTarget::setFlags\28GrGLCaps\20const&\2c\20GrGLRenderTarget::IDs\20const&\29 +7355:GrGLRenderTarget::onGpuMemorySize\28\29\20const +7356:GrGLRenderTarget::bind\28bool\29 +7357:GrGLRenderTarget::backendFormat\28\29\20const +7358:GrGLRenderTarget::GrGLRenderTarget\28GrGLGpu*\2c\20SkISize\20const&\2c\20GrGLFormat\2c\20int\2c\20GrGLRenderTarget::IDs\20const&\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +7359:GrGLProgramDataManager::set4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +7360:GrGLProgramDataManager::set2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +7361:GrGLProgramBuilder::uniformHandler\28\29 +7362:GrGLProgramBuilder::compileAndAttachShaders\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\2c\20unsigned\20int\2c\20SkTDArray*\2c\20bool\2c\20skgpu::ShaderErrorHandler*\29 +7363:GrGLProgramBuilder::PrecompileProgram\28GrDirectContext*\2c\20GrGLPrecompiledProgram*\2c\20SkData\20const&\29::$_0::operator\28\29\28SkSL::ProgramKind\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\2c\20unsigned\20int\29\20const +7364:GrGLProgramBuilder::CreateProgram\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrGLPrecompiledProgram\20const*\29 +7365:GrGLProgram::~GrGLProgram\28\29 +7366:GrGLInterfaces::MakeWebGL\28\29 +7367:GrGLInterface::~GrGLInterface\28\29 +7368:GrGLGpu::~GrGLGpu\28\29 +7369:GrGLGpu::waitSemaphore\28GrSemaphore*\29 +7370:GrGLGpu::uploadTexData\28SkISize\2c\20unsigned\20int\2c\20SkIRect\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20long\2c\20GrMipLevel\20const*\2c\20int\29 +7371:GrGLGpu::uploadCompressedTexData\28SkTextureCompressionType\2c\20GrGLFormat\2c\20SkISize\2c\20skgpu::Mipmapped\2c\20unsigned\20int\2c\20void\20const*\2c\20unsigned\20long\29 +7372:GrGLGpu::uploadColorToTex\28GrGLFormat\2c\20SkISize\2c\20unsigned\20int\2c\20std::__2::array\2c\20unsigned\20int\29 +7373:GrGLGpu::readOrTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20int\29 +7374:GrGLGpu::onFBOChanged\28\29 +7375:GrGLGpu::getTimerQueryResult\28unsigned\20int\29 +7376:GrGLGpu::getCompatibleStencilIndex\28GrGLFormat\29 +7377:GrGLGpu::flushWireframeState\28bool\29 +7378:GrGLGpu::flushScissorRect\28SkIRect\20const&\2c\20int\2c\20GrSurfaceOrigin\29 +7379:GrGLGpu::flushProgram\28unsigned\20int\29 +7380:GrGLGpu::flushProgram\28sk_sp\29 +7381:GrGLGpu::flushFramebufferSRGB\28bool\29 +7382:GrGLGpu::flushConservativeRasterState\28bool\29 +7383:GrGLGpu::createRenderTargetObjects\28GrGLTexture::Desc\20const&\2c\20int\2c\20GrGLRenderTarget::IDs*\29 +7384:GrGLGpu::createCompressedTexture2D\28SkISize\2c\20SkTextureCompressionType\2c\20GrGLFormat\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrGLTextureParameters::SamplerOverriddenState*\29 +7385:GrGLGpu::bindVertexArray\28unsigned\20int\29 +7386:GrGLGpu::TextureUnitBindings::setBoundID\28unsigned\20int\2c\20GrGpuResource::UniqueID\29 +7387:GrGLGpu::TextureUnitBindings::invalidateAllTargets\28bool\29 +7388:GrGLGpu::TextureToCopyProgramIdx\28GrTexture*\29 +7389:GrGLGpu::ProgramCache::~ProgramCache\28\29 +7390:GrGLGpu::ProgramCache::findOrCreateProgramImpl\28GrDirectContext*\2c\20GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\2c\20GrThreadSafePipelineBuilder::Stats::ProgramCacheResult*\29 +7391:GrGLGpu::HWVertexArrayState::invalidate\28\29 +7392:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void\20const*\29 +7393:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\29 +7394:GrGLFinishCallbacks::check\28\29 +7395:GrGLContext::~GrGLContext\28\29_11563 +7396:GrGLCaps::~GrGLCaps\28\29 +7397:GrGLCaps::getTexSubImageExternalFormatAndType\28GrGLFormat\2c\20GrColorType\2c\20GrColorType\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7398:GrGLCaps::getExternalFormat\28GrGLFormat\2c\20GrColorType\2c\20GrColorType\2c\20GrGLCaps::ExternalFormatUsage\2c\20unsigned\20int*\2c\20unsigned\20int*\29\20const +7399:GrGLCaps::canCopyTexSubImage\28GrGLFormat\2c\20bool\2c\20GrTextureType\20const*\2c\20GrGLFormat\2c\20bool\2c\20GrTextureType\20const*\29\20const +7400:GrGLCaps::canCopyAsBlit\28GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20GrGLFormat\2c\20int\2c\20GrTextureType\20const*\2c\20SkRect\20const&\2c\20bool\2c\20SkIRect\20const&\2c\20SkIRect\20const&\29\20const +7401:GrGLBuffer::~GrGLBuffer\28\29_11502 +7402:GrGLAttribArrayState::resize\28int\29 +7403:GrGLAttribArrayState::GrGLAttribArrayState\28int\29 +7404:GrFragmentProcessors::MakeChildFP\28SkRuntimeEffect::ChildPtr\20const&\2c\20GrFPArgs\20const&\29 +7405:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::Make\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +7406:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29 +7407:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::Make\28\29 +7408:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::Make\28std::__2::unique_ptr>\29 +7409:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::DeviceSpace\28std::__2::unique_ptr>\29 +7410:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::Make\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +7411:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29 +7412:GrFragmentProcessor::ClampOutput\28std::__2::unique_ptr>\29 +7413:GrFixedClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +7414:GrFixedClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +7415:GrEagerDynamicVertexAllocator::unlock\28int\29 +7416:GrDynamicAtlas::~GrDynamicAtlas\28\29 +7417:GrDynamicAtlas::Node::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +7418:GrDrawingManager::flush\28SkSpan\2c\20SkSurfaces::BackendSurfaceAccess\2c\20GrFlushInfo\20const&\2c\20skgpu::MutableTextureState\20const*\29 +7419:GrDrawingManager::closeAllTasks\28\29 +7420:GrDrawOpAtlas::uploadToPage\28unsigned\20int\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +7421:GrDrawOpAtlas::updatePlot\28GrDeferredUploadTarget*\2c\20skgpu::AtlasLocator*\2c\20skgpu::Plot*\29 +7422:GrDrawOpAtlas::setLastUseToken\28skgpu::AtlasLocator\20const&\2c\20skgpu::AtlasToken\29 +7423:GrDrawOpAtlas::processEviction\28skgpu::PlotLocator\29 +7424:GrDrawOpAtlas::hasID\28skgpu::PlotLocator\20const&\29 +7425:GrDrawOpAtlas::compact\28skgpu::AtlasToken\29 +7426:GrDrawOpAtlas::addToAtlas\28GrResourceProvider*\2c\20GrDeferredUploadTarget*\2c\20int\2c\20int\2c\20void\20const*\2c\20skgpu::AtlasLocator*\29 +7427:GrDrawOpAtlas::Make\28GrProxyProvider*\2c\20GrBackendFormat\20const&\2c\20SkColorType\2c\20unsigned\20long\2c\20int\2c\20int\2c\20int\2c\20int\2c\20skgpu::AtlasGenerationCounter*\2c\20GrDrawOpAtlas::AllowMultitexturing\2c\20skgpu::PlotEvictionCallback*\2c\20std::__2::basic_string_view>\29 +7428:GrDrawIndirectBufferAllocPool::putBack\28int\29 +7429:GrDrawIndirectBufferAllocPool::putBackIndexed\28int\29 +7430:GrDrawIndirectBufferAllocPool::makeSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +7431:GrDrawIndirectBufferAllocPool::makeIndexedSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +7432:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29 +7433:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29 +7434:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29 +7435:GrDistanceFieldA8TextGeoProc::onTextureSampler\28int\29\20const +7436:GrDisableColorXPFactory::MakeXferProcessor\28\29 +7437:GrDirectContextPriv::validPMUPMConversionExists\28\29 +7438:GrDirectContext::~GrDirectContext\28\29 +7439:GrDirectContext::syncAllOutstandingGpuWork\28bool\29 +7440:GrDirectContext::submit\28GrSyncCpu\29 +7441:GrDirectContext::flush\28SkSurface*\29 +7442:GrDirectContext::abandoned\28\29 +7443:GrDeferredProxyUploader::signalAndFreeData\28\29 +7444:GrDeferredProxyUploader::GrDeferredProxyUploader\28\29 +7445:GrCopyRenderTask::~GrCopyRenderTask\28\29 +7446:GrCopyRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +7447:GrCopyBaseMipMapToView\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20skgpu::Budgeted\29 +7448:GrCopyBaseMipMapToTextureProxy\28GrRecordingContext*\2c\20sk_sp\2c\20GrSurfaceOrigin\2c\20std::__2::basic_string_view>\2c\20skgpu::Budgeted\29 +7449:GrContext_Base::~GrContext_Base\28\29_8555 +7450:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29 +7451:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29 +7452:GrColorInfo::makeColorType\28GrColorType\29\20const +7453:GrColorInfo::isLinearlyBlended\28\29\20const +7454:GrColorFragmentProcessorAnalysis::GrColorFragmentProcessorAnalysis\28GrProcessorAnalysisColor\20const&\2c\20std::__2::unique_ptr>\20const*\2c\20int\29 +7455:GrCaps::~GrCaps\28\29 +7456:GrCaps::surfaceSupportsWritePixels\28GrSurface\20const*\29\20const +7457:GrCaps::getDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\2c\20bool\29\20const +7458:GrCPixmap::GrCPixmap\28GrPixmap\20const&\29 +7459:GrBufferAllocPool::resetCpuData\28unsigned\20long\29 +7460:GrBufferAllocPool::makeSpaceAtLeast\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20sk_sp*\2c\20unsigned\20long*\2c\20unsigned\20long*\29 +7461:GrBufferAllocPool::flushCpuData\28GrBufferAllocPool::BufferBlock\20const&\2c\20unsigned\20long\29 +7462:GrBufferAllocPool::destroyBlock\28\29 +7463:GrBufferAllocPool::deleteBlocks\28\29 +7464:GrBufferAllocPool::createBlock\28unsigned\20long\29 +7465:GrBufferAllocPool::CpuBufferCache::makeBuffer\28unsigned\20long\2c\20bool\29 +7466:GrBlurUtils::mask_release_proc\28void*\2c\20void*\29 +7467:GrBlurUtils::draw_shape_with_mask_filter\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkMaskFilterBase\20const*\2c\20GrStyledShape\20const&\29 +7468:GrBlurUtils::draw_mask\28skgpu::ganesh::SurfaceDrawContext*\2c\20GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20GrPaint&&\2c\20GrSurfaceProxyView\29 +7469:GrBlurUtils::create_data\28SkIRect\20const&\2c\20SkIRect\20const&\29 +7470:GrBlurUtils::convolve_gaussian_1d\28skgpu::ganesh::SurfaceFillContext*\2c\20GrSurfaceProxyView\2c\20SkIRect\20const&\2c\20SkIPoint\2c\20SkIRect\20const&\2c\20SkAlphaType\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\29 +7471:GrBlurUtils::convolve_gaussian\28GrRecordingContext*\2c\20GrSurfaceProxyView\2c\20GrColorType\2c\20SkAlphaType\2c\20SkIRect\2c\20SkIRect\2c\20GrBlurUtils::\28anonymous\20namespace\29::Direction\2c\20int\2c\20float\2c\20SkTileMode\2c\20sk_sp\2c\20SkBackingFit\29 +7472:GrBlurUtils::clip_bounds_quick_reject\28SkIRect\20const&\2c\20SkIRect\20const&\29 +7473:GrBlurUtils::\28anonymous\20namespace\29::make_texture_effect\28GrCaps\20const*\2c\20GrSurfaceProxyView\2c\20SkAlphaType\2c\20GrSamplerState\20const&\2c\20SkIRect\20const&\2c\20SkIRect\20const&\2c\20SkISize\20const&\29 +7474:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29 +7475:GrBitmapTextGeoProc::addNewViews\28GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\29 +7476:GrBitmapTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29 +7477:GrBicubicEffect::Make\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +7478:GrBicubicEffect::MakeSubset\28GrSurfaceProxyView\2c\20SkAlphaType\2c\20SkMatrix\20const&\2c\20GrSamplerState::WrapMode\2c\20GrSamplerState::WrapMode\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkCubicResampler\2c\20GrBicubicEffect::Direction\2c\20GrCaps\20const&\29 +7479:GrBackendTexture::operator=\28GrBackendTexture\20const&\29 +7480:GrBackendTexture::GrBackendTexture\28int\2c\20int\2c\20std::__2::basic_string_view>\2c\20skgpu::Mipmapped\2c\20GrBackendApi\2c\20GrTextureType\2c\20GrGLBackendTextureData\20const&\29 +7481:GrBackendRenderTarget::isProtected\28\29\20const +7482:GrBackendFormatBytesPerBlock\28GrBackendFormat\20const&\29 +7483:GrBackendFormat::operator!=\28GrBackendFormat\20const&\29\20const +7484:GrBackendFormat::makeTexture2D\28\29\20const +7485:GrAuditTrail::opsCombined\28GrOp\20const*\2c\20GrOp\20const*\29 +7486:GrAttachment::ComputeSharedAttachmentUniqueKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\2c\20skgpu::UniqueKey*\29 +7487:GrAttachment::ComputeScratchKey\28GrCaps\20const&\2c\20GrBackendFormat\20const&\2c\20SkISize\2c\20GrAttachment::UsageFlags\2c\20int\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20GrMemoryless\2c\20skgpu::ScratchKey*\29 +7488:GrAtlasManager::~GrAtlasManager\28\29 +7489:GrAtlasManager::getViews\28skgpu::MaskFormat\2c\20unsigned\20int*\29 +7490:GrAtlasManager::atlasGeneration\28skgpu::MaskFormat\29\20const +7491:GrAppliedClip::visitProxies\28std::__2::function\20const&\29\20const +7492:GrAppliedClip::addCoverageFP\28std::__2::unique_ptr>\29 +7493:GrAATriangulator::makeEvent\28GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::SSEdge*\2c\20GrTriangulator::Vertex*\2c\20GrAATriangulator::EventList*\2c\20GrTriangulator::Comparator\20const&\29\20const +7494:GrAATriangulator::connectPartners\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\29 +7495:GrAATriangulator::collapseOverlapRegions\28GrTriangulator::VertexList*\2c\20GrTriangulator::Comparator\20const&\2c\20GrAATriangulator::EventComparator\29 +7496:GrAATriangulator::Event*\20SkArenaAlloc::make\28GrAATriangulator::SSEdge*&\2c\20SkPoint&\2c\20unsigned\20char&\29 +7497:GrAAConvexTessellator::~GrAAConvexTessellator\28\29 +7498:GrAAConvexTessellator::quadTo\28SkPoint\20const*\29 +7499:GrAAConvexTessellator::fanRing\28GrAAConvexTessellator::Ring\20const&\29 +7500:GetShortIns +7501:FontMgrRunIterator::~FontMgrRunIterator\28\29 +7502:FontMgrRunIterator::endOfCurrentRun\28\29\20const +7503:FontMgrRunIterator::atEnd\28\29\20const +7504:FindSortableTop\28SkOpContourHead*\29 +7505:FT_Vector_NormLen +7506:FT_Sfnt_Table_Info +7507:FT_Select_Size +7508:FT_Render_Glyph +7509:FT_Remove_Module +7510:FT_Outline_Get_Orientation +7511:FT_Outline_EmboldenXY +7512:FT_Outline_Decompose +7513:FT_Open_Face +7514:FT_New_Library +7515:FT_New_GlyphSlot +7516:FT_Match_Size +7517:FT_GlyphLoader_Reset +7518:FT_GlyphLoader_Prepare +7519:FT_GlyphLoader_CheckSubGlyphs +7520:FT_Get_Var_Design_Coordinates +7521:FT_Get_Postscript_Name +7522:FT_Get_Paint_Layers +7523:FT_Get_PS_Font_Info +7524:FT_Get_Glyph_Name +7525:FT_Get_FSType_Flags +7526:FT_Get_Color_Glyph_ClipBox +7527:FT_Done_Size +7528:FT_Done_Library +7529:FT_Bitmap_Done +7530:FT_Bitmap_Convert +7531:FT_Add_Default_Modules +7532:EmptyFontLoader::loadSystemFonts\28SkFontScanner\20const*\2c\20skia_private::TArray\2c\20true>*\29\20const +7533:EllipticalRRectOp::~EllipticalRRectOp\28\29_10811 +7534:EllipticalRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +7535:EllipticalRRectOp::EllipticalRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20SkPoint\2c\20bool\29 +7536:EllipseOp::EllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20EllipseOp::DeviceSpaceParams\20const&\2c\20SkStrokeRec\20const&\29 +7537:EllipseGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7538:Dot2AngleType\28float\29 +7539:DecodeVarLenUint8 +7540:DecodeContextMap +7541:DIEllipseOp::~DIEllipseOp\28\29 +7542:DIEllipseOp::DIEllipseOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20DIEllipseOp::DeviceSpaceParams\20const&\2c\20SkMatrix\20const&\29 +7543:CustomXP::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +7544:CustomXP::makeProgramImpl\28\29\20const::Impl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +7545:Cr_z_inflateReset2 +7546:Cr_z_inflateReset +7547:CoverageSetOpXP::onIsEqual\28GrXferProcessor\20const&\29\20const +7548:Convexicator::close\28\29 +7549:Convexicator::addVec\28SkPoint\20const&\29 +7550:Convexicator::addPt\28SkPoint\20const&\29 +7551:ContourIter::next\28\29 +7552:Contour&\20std::__2::vector>::emplace_back\28SkRect&\2c\20int&\2c\20int&\29 +7553:CircularRRectOp::~CircularRRectOp\28\29_10788 +7554:CircularRRectOp::CircularRRectOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const&\2c\20float\2c\20float\2c\20bool\29 +7555:CircleOp::~CircleOp\28\29 +7556:CircleOp::Make\28GrRecordingContext*\2c\20GrPaint&&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +7557:CircleOp::CircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20GrStyle\20const&\2c\20CircleOp::ArcParams\20const*\29 +7558:CircleGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29 +7559:CircleGeometryProcessor::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +7560:CFF::dict_interpreter_t\2c\20CFF::interp_env_t>::interpret\28CFF::cff1_private_dict_values_base_t&\29 +7561:CFF::cs_opset_t\2c\20cff2_path_param_t\2c\20cff2_path_procs_path_t>::process_op\28unsigned\20int\2c\20CFF::cff2_cs_interp_env_t&\2c\20cff2_path_param_t&\29 +7562:CFF::cs_opset_t\2c\20cff2_extents_param_t\2c\20cff2_path_procs_extents_t>::process_op\28unsigned\20int\2c\20CFF::cff2_cs_interp_env_t&\2c\20cff2_extents_param_t&\29 +7563:CFF::cff_stack_t::cff_stack_t\28\29 +7564:CFF::cff2_cs_interp_env_t::process_vsindex\28\29 +7565:CFF::cff2_cs_interp_env_t::process_blend\28\29 +7566:CFF::cff2_cs_interp_env_t::fetch_op\28\29 +7567:CFF::cff2_cs_interp_env_t::cff2_cs_interp_env_t\28hb_array_t\20const&\2c\20OT::cff2::accelerator_t\20const&\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29 +7568:CFF::cff2_cs_interp_env_t::blend_deltas\28hb_array_t\29\20const +7569:CFF::cff1_top_dict_values_t::init\28\29 +7570:CFF::cff1_cs_interp_env_t::cff1_cs_interp_env_t\28hb_array_t\20const&\2c\20OT::cff1::accelerator_t\20const&\2c\20unsigned\20int\2c\20int\20const*\2c\20unsigned\20int\29 +7571:CFF::biased_subrs_t>>::init\28CFF::Subrs>\20const*\29 +7572:CFF::biased_subrs_t>>::init\28CFF::Subrs>\20const*\29 +7573:CFF::FDSelect::get_fd\28unsigned\20int\29\20const +7574:CFF::FDSelect3_4\2c\20OT::IntType>::sentinel\28\29\20const +7575:CFF::FDSelect3_4\2c\20OT::IntType>::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +7576:CFF::FDSelect3_4\2c\20OT::IntType>::get_fd\28unsigned\20int\29\20const +7577:CFF::FDSelect0::sanitize\28hb_sanitize_context_t*\2c\20unsigned\20int\29\20const +7578:CFF::Charset::get_glyph\28unsigned\20int\2c\20unsigned\20int\29\20const +7579:CFF::CFF2FDSelect::get_fd\28unsigned\20int\29\20const +7580:ButtCapDashedCircleOp::ButtCapDashedCircleOp\28GrProcessorSet*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\29 +7581:BrotliTransformDictionaryWord +7582:BrotliEnsureRingBuffer +7583:BrotliDecoderStateCleanupAfterMetablock +7584:BlockIndexIterator::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Decrement\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::begin\28\29\20const +7585:BlockIndexIterator::First\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Last\28SkBlockAllocator::Block\20const*\29\2c\20&SkTBlockList::Increment\28SkBlockAllocator::Block\20const*\2c\20int\29\2c\20&SkTBlockList::GetItem\28SkBlockAllocator::Block\20const*\2c\20int\29>::Item::operator++\28\29 +7586:AutoRestoreInverseness::~AutoRestoreInverseness\28\29 +7587:AutoRestoreInverseness::AutoRestoreInverseness\28GrShape*\2c\20GrStyle\20const&\29 +7588:AutoLayerForImageFilter::addMaskFilterLayer\28SkRect\20const*\29 +7589:AutoLayerForImageFilter::addLayer\28SkPaint\20const&\2c\20SkRect\20const*\2c\20bool\29 +7590:AngleWinding\28SkOpSpanBase*\2c\20SkOpSpanBase*\2c\20int*\2c\20bool*\29 +7591:AddIntersectTs\28SkOpContour*\2c\20SkOpContour*\2c\20SkOpCoincidence*\29 +7592:ActiveEdgeList::replace\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\2c\20unsigned\20short\29 +7593:ActiveEdgeList::remove\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +7594:ActiveEdgeList::insert\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +7595:ActiveEdgeList::allocate\28SkPoint\20const&\2c\20SkPoint\20const&\2c\20unsigned\20short\2c\20unsigned\20short\29 +7596:AAT::track::sanitize\28hb_sanitize_context_t*\29\20const +7597:AAT::mortmorx::sanitize\28hb_sanitize_context_t*\29\20const +7598:AAT::mortmorx::sanitize\28hb_sanitize_context_t*\29\20const +7599:AAT::ltag::sanitize\28hb_sanitize_context_t*\29\20const +7600:AAT::ltag::get_language\28unsigned\20int\29\20const +7601:AAT::feat::sanitize\28hb_sanitize_context_t*\29\20const +7602:AAT::ankr::sanitize\28hb_sanitize_context_t*\29\20const +7603:AAT::ankr::get_anchor\28unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\20const +7604:AAT::TrackData::get_tracking\28void\20const*\2c\20float\29\20const +7605:AAT::Lookup>::get_value_or_null\28unsigned\20int\2c\20unsigned\20int\29\20const +7606:AAT::Lookup>::get_value\28unsigned\20int\2c\20unsigned\20int\29\20const +7607:AAT::Lookup>::get_value_or_null\28unsigned\20int\2c\20unsigned\20int\29\20const +7608:AAT::KerxTable::sanitize\28hb_sanitize_context_t*\29\20const +7609:AAT::KernPair\20const*\20hb_sorted_array_t::bsearch\28AAT::hb_glyph_pair_t\20const&\2c\20AAT::KernPair\20const*\29 +7610:AAT::KernPair\20const&\20OT::SortedArrayOf>>::bsearch\28AAT::hb_glyph_pair_t\20const&\2c\20AAT::KernPair\20const&\29\20const +7611:AAT::ChainSubtable::apply\28AAT::hb_aat_apply_context_t*\29\20const +7612:AAT::ChainSubtable::apply\28AAT::hb_aat_apply_context_t*\29\20const +7613:7404 +7614:7405 +7615:7406 +7616:7407 +7617:7408 +7618:7409 +7619:7410 +7620:7411 +7621:7412 +7622:7413 +7623:7414 +7624:7415 +7625:7416 +7626:7417 +7627:7418 +7628:7419 +7629:7420 +7630:7421 +7631:7422 +7632:7423 +7633:7424 +7634:7425 +7635:7426 +7636:7427 +7637:7428 +7638:7429 +7639:7430 +7640:7431 +7641:7432 +7642:7433 +7643:7434 +7644:7435 +7645:7436 +7646:7437 +7647:7438 +7648:7439 +7649:7440 +7650:7441 +7651:7442 +7652:7443 +7653:7444 +7654:7445 +7655:7446 +7656:7447 +7657:7448 +7658:7449 +7659:7450 +7660:7451 +7661:7452 +7662:7453 +7663:7454 +7664:7455 +7665:7456 +7666:7457 +7667:7458 +7668:7459 +7669:7460 +7670:7461 +7671:7462 +7672:7463 +7673:7464 +7674:7465 +7675:7466 +7676:7467 +7677:7468 +7678:7469 +7679:7470 +7680:7471 +7681:7472 +7682:7473 +7683:7474 +7684:7475 +7685:7476 +7686:7477 +7687:7478 +7688:7479 +7689:7480 +7690:7481 +7691:7482 +7692:7483 +7693:7484 +7694:7485 +7695:7486 +7696:7487 +7697:7488 +7698:7489 +7699:7490 +7700:7491 +7701:7492 +7702:7493 +7703:7494 +7704:7495 +7705:7496 +7706:7497 +7707:xyzd50_to_hcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +7708:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +7709:void\20mergeT\28void\20const*\2c\20int\2c\20unsigned\20char\20const*\2c\20int\2c\20void*\29 +7710:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7711:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7712:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7713:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7714:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7715:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7716:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7717:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7718:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7719:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7720:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7721:void\20\28anonymous\20namespace\29::downsample_3_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7722:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7723:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7724:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7725:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7726:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7727:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7728:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7729:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7730:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7731:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7732:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7733:void\20\28anonymous\20namespace\29::downsample_3_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7734:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7735:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7736:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7737:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7738:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7739:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7740:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7741:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7742:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7743:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7744:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7745:void\20\28anonymous\20namespace\29::downsample_3_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7746:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7747:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7748:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7749:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7750:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7751:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7752:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7753:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7754:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7755:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7756:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7757:void\20\28anonymous\20namespace\29::downsample_2_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7758:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7759:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7760:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7761:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7762:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7763:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7764:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7765:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7766:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7767:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7768:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7769:void\20\28anonymous\20namespace\29::downsample_2_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7770:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7771:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7772:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7773:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7774:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7775:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7776:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7777:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7778:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7779:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7780:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7781:void\20\28anonymous\20namespace\29::downsample_2_1<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7782:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7783:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7784:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7785:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7786:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7787:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7788:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7789:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7790:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7791:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7792:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7793:void\20\28anonymous\20namespace\29::downsample_1_3<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7794:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_RGBA_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7795:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_F16F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7796:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_Alpha_F16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7797:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7798:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_88>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7799:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_8888>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7800:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_565>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7801:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_4444>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7802:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7803:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7804:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_16161616>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7805:void\20\28anonymous\20namespace\29::downsample_1_2<\28anonymous\20namespace\29::ColorTypeFilter_1010102>\28void*\2c\20void\20const*\2c\20unsigned\20long\2c\20int\29 +7806:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_14478 +7807:virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +7808:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29_14324 +7809:virtual\20thunk\20to\20std::__2::basic_istream>::~basic_istream\28\29 +7810:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_14368 +7811:virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +7812:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9444 +7813:virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +7814:virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7815:virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7816:virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7817:virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +7818:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29_9416 +7819:virtual\20thunk\20to\20GrTextureProxy::~GrTextureProxy\28\29 +7820:virtual\20thunk\20to\20GrTextureProxy::onUninstantiatedGpuMemorySize\28\29\20const +7821:virtual\20thunk\20to\20GrTextureProxy::instantiate\28GrResourceProvider*\29 +7822:virtual\20thunk\20to\20GrTextureProxy::getUniqueKey\28\29\20const +7823:virtual\20thunk\20to\20GrTextureProxy::createSurface\28GrResourceProvider*\29\20const +7824:virtual\20thunk\20to\20GrTextureProxy::callbackDesc\28\29\20const +7825:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29\20const +7826:virtual\20thunk\20to\20GrTextureProxy::asTextureProxy\28\29 +7827:virtual\20thunk\20to\20GrTexture::onGpuMemorySize\28\29\20const +7828:virtual\20thunk\20to\20GrTexture::computeScratchKey\28skgpu::ScratchKey*\29\20const +7829:virtual\20thunk\20to\20GrTexture::asTexture\28\29\20const +7830:virtual\20thunk\20to\20GrTexture::asTexture\28\29 +7831:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29_9260 +7832:virtual\20thunk\20to\20GrRenderTargetProxy::~GrRenderTargetProxy\28\29 +7833:virtual\20thunk\20to\20GrRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +7834:virtual\20thunk\20to\20GrRenderTargetProxy::instantiate\28GrResourceProvider*\29 +7835:virtual\20thunk\20to\20GrRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +7836:virtual\20thunk\20to\20GrRenderTargetProxy::callbackDesc\28\29\20const +7837:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29\20const +7838:virtual\20thunk\20to\20GrRenderTargetProxy::asRenderTargetProxy\28\29 +7839:virtual\20thunk\20to\20GrRenderTarget::onRelease\28\29 +7840:virtual\20thunk\20to\20GrRenderTarget::onAbandon\28\29 +7841:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29\20const +7842:virtual\20thunk\20to\20GrRenderTarget::asRenderTarget\28\29 +7843:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_11891 +7844:virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +7845:virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +7846:virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +7847:virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +7848:virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7849:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29_11860 +7850:virtual\20thunk\20to\20GrGLTexture::~GrGLTexture\28\29 +7851:virtual\20thunk\20to\20GrGLTexture::onRelease\28\29 +7852:virtual\20thunk\20to\20GrGLTexture::onAbandon\28\29 +7853:virtual\20thunk\20to\20GrGLTexture::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7854:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10142 +7855:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +7856:virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::onFinalize\28\29 +7857:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29_11833 +7858:virtual\20thunk\20to\20GrGLRenderTarget::~GrGLRenderTarget\28\29 +7859:virtual\20thunk\20to\20GrGLRenderTarget::onRelease\28\29 +7860:virtual\20thunk\20to\20GrGLRenderTarget::onGpuMemorySize\28\29\20const +7861:virtual\20thunk\20to\20GrGLRenderTarget::onAbandon\28\29 +7862:virtual\20thunk\20to\20GrGLRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +7863:virtual\20thunk\20to\20GrGLRenderTarget::backendFormat\28\29\20const +7864:vertices_dispose +7865:vertices_create +7866:unicodePositionBuffer_create +7867:typefaces_filterCoveredCodePoints +7868:typeface_create +7869:tt_vadvance_adjust +7870:tt_slot_init +7871:tt_size_request +7872:tt_size_init +7873:tt_size_done +7874:tt_sbit_decoder_load_png +7875:tt_sbit_decoder_load_compound +7876:tt_sbit_decoder_load_byte_aligned +7877:tt_sbit_decoder_load_bit_aligned +7878:tt_property_set +7879:tt_property_get +7880:tt_name_ascii_from_utf16 +7881:tt_name_ascii_from_other +7882:tt_hadvance_adjust +7883:tt_glyph_load +7884:tt_get_var_blend +7885:tt_get_interface +7886:tt_get_glyph_name +7887:tt_get_cmap_info +7888:tt_get_advances +7889:tt_face_set_sbit_strike +7890:tt_face_load_strike_metrics +7891:tt_face_load_sbit_image +7892:tt_face_load_sbit +7893:tt_face_load_post +7894:tt_face_load_pclt +7895:tt_face_load_os2 +7896:tt_face_load_name +7897:tt_face_load_maxp +7898:tt_face_load_kern +7899:tt_face_load_hmtx +7900:tt_face_load_hhea +7901:tt_face_load_head +7902:tt_face_load_gasp +7903:tt_face_load_font_dir +7904:tt_face_load_cpal +7905:tt_face_load_colr +7906:tt_face_load_cmap +7907:tt_face_load_bhed +7908:tt_face_load_any +7909:tt_face_init +7910:tt_face_get_paint_layers +7911:tt_face_get_paint +7912:tt_face_get_kerning +7913:tt_face_get_colr_layer +7914:tt_face_get_colr_glyph_paint +7915:tt_face_get_colorline_stops +7916:tt_face_get_color_glyph_clipbox +7917:tt_face_free_sbit +7918:tt_face_free_ps_names +7919:tt_face_free_name +7920:tt_face_free_cpal +7921:tt_face_free_colr +7922:tt_face_done +7923:tt_face_colr_blend_layer +7924:tt_driver_init +7925:tt_cmap_unicode_init +7926:tt_cmap_unicode_char_next +7927:tt_cmap_unicode_char_index +7928:tt_cmap_init +7929:tt_cmap8_validate +7930:tt_cmap8_get_info +7931:tt_cmap8_char_next +7932:tt_cmap8_char_index +7933:tt_cmap6_validate +7934:tt_cmap6_get_info +7935:tt_cmap6_char_next +7936:tt_cmap6_char_index +7937:tt_cmap4_validate +7938:tt_cmap4_init +7939:tt_cmap4_get_info +7940:tt_cmap4_char_next +7941:tt_cmap4_char_index +7942:tt_cmap2_validate +7943:tt_cmap2_get_info +7944:tt_cmap2_char_next +7945:tt_cmap2_char_index +7946:tt_cmap14_variants +7947:tt_cmap14_variant_chars +7948:tt_cmap14_validate +7949:tt_cmap14_init +7950:tt_cmap14_get_info +7951:tt_cmap14_done +7952:tt_cmap14_char_variants +7953:tt_cmap14_char_var_isdefault +7954:tt_cmap14_char_var_index +7955:tt_cmap14_char_next +7956:tt_cmap13_validate +7957:tt_cmap13_get_info +7958:tt_cmap13_char_next +7959:tt_cmap13_char_index +7960:tt_cmap12_validate +7961:tt_cmap12_get_info +7962:tt_cmap12_char_next +7963:tt_cmap12_char_index +7964:tt_cmap10_validate +7965:tt_cmap10_get_info +7966:tt_cmap10_char_next +7967:tt_cmap10_char_index +7968:tt_cmap0_validate +7969:tt_cmap0_get_info +7970:tt_cmap0_char_next +7971:tt_cmap0_char_index +7972:textStyle_setWordSpacing +7973:textStyle_setTextBaseline +7974:textStyle_setLocale +7975:textStyle_setLetterSpacing +7976:textStyle_setHeight +7977:textStyle_setHalfLeading +7978:textStyle_setForeground +7979:textStyle_setFontVariations +7980:textStyle_setFontStyle +7981:textStyle_setFontSize +7982:textStyle_setDecorationColor +7983:textStyle_setColor +7984:textStyle_setBackground +7985:textStyle_dispose +7986:textStyle_create +7987:textStyle_copy +7988:textStyle_clearFontFamilies +7989:textStyle_addShadow +7990:textStyle_addFontFeature +7991:textStyle_addFontFamilies +7992:textBoxList_getLength +7993:textBoxList_getBoxAtIndex +7994:textBoxList_dispose +7995:t2_hints_stems +7996:t2_hints_open +7997:t1_make_subfont +7998:t1_hints_stem +7999:t1_hints_open +8000:t1_decrypt +8001:t1_decoder_parse_metrics +8002:t1_decoder_init +8003:t1_decoder_done +8004:t1_cmap_unicode_init +8005:t1_cmap_unicode_char_next +8006:t1_cmap_unicode_char_index +8007:t1_cmap_std_done +8008:t1_cmap_std_char_next +8009:t1_cmap_standard_init +8010:t1_cmap_expert_init +8011:t1_cmap_custom_init +8012:t1_cmap_custom_done +8013:t1_cmap_custom_char_next +8014:t1_cmap_custom_char_index +8015:t1_builder_start_point +8016:swizzle_or_premul\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20SkColorSpaceXformSteps\20const&\29 +8017:surface_renderPicturesOnWorker +8018:surface_renderPictures +8019:surface_rasterizeImageOnWorker +8020:surface_rasterizeImage +8021:surface_onRenderComplete +8022:surface_onRasterizeComplete +8023:surface_dispose +8024:surface_destroy +8025:surface_create +8026:strutStyle_setLeading +8027:strutStyle_setHeight +8028:strutStyle_setHalfLeading +8029:strutStyle_setForceStrutHeight +8030:strutStyle_setFontStyle +8031:strutStyle_setFontFamilies +8032:strutStyle_dispose +8033:strutStyle_create +8034:string_read +8035:std::exception::what\28\29\20const +8036:std::bad_variant_access::what\28\29\20const +8037:std::bad_optional_access::what\28\29\20const +8038:std::bad_array_new_length::what\28\29\20const +8039:std::bad_alloc::what\28\29\20const +8040:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20tm\20const*\2c\20char\2c\20char\29\20const +8041:std::__2::time_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20tm\20const*\2c\20char\2c\20char\29\20const +8042:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8043:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8044:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8045:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8046:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8047:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +8048:std::__2::time_get>>::do_get_year\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8049:std::__2::time_get>>::do_get_weekday\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8050:std::__2::time_get>>::do_get_time\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8051:std::__2::time_get>>::do_get_monthname\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8052:std::__2::time_get>>::do_get_date\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\29\20const +8053:std::__2::time_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20tm*\2c\20char\2c\20char\29\20const +8054:std::__2::numpunct::~numpunct\28\29_15289 +8055:std::__2::numpunct::do_truename\28\29\20const +8056:std::__2::numpunct::do_grouping\28\29\20const +8057:std::__2::numpunct::do_falsename\28\29\20const +8058:std::__2::numpunct::~numpunct\28\29_15296 +8059:std::__2::numpunct::do_truename\28\29\20const +8060:std::__2::numpunct::do_thousands_sep\28\29\20const +8061:std::__2::numpunct::do_grouping\28\29\20const +8062:std::__2::numpunct::do_falsename\28\29\20const +8063:std::__2::numpunct::do_decimal_point\28\29\20const +8064:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20void\20const*\29\20const +8065:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\29\20const +8066:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20unsigned\20long\20long\29\20const +8067:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\29\20const +8068:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20long\29\20const +8069:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +8070:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20double\29\20const +8071:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20bool\29\20const +8072:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20void\20const*\29\20const +8073:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\29\20const +8074:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20unsigned\20long\20long\29\20const +8075:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\29\20const +8076:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20long\29\20const +8077:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +8078:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20double\29\20const +8079:std::__2::num_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20std::__2::ios_base&\2c\20char\2c\20bool\29\20const +8080:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +8081:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +8082:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +8083:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +8084:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8085:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +8086:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +8087:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +8088:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +8089:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20void*&\29\20const +8090:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20short&\29\20const +8091:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20unsigned\20long\20long&\29\20const +8092:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20long&\29\20const +8093:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8094:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long&\29\20const +8095:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20float&\29\20const +8096:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20double&\29\20const +8097:std::__2::num_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20bool&\29\20const +8098:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8099:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20wchar_t\2c\20long\20double\29\20const +8100:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8101:std::__2::money_put>>::do_put\28std::__2::ostreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20char\2c\20long\20double\29\20const +8102:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +8103:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8104:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20std::__2::basic_string\2c\20std::__2::allocator>&\29\20const +8105:std::__2::money_get>>::do_get\28std::__2::istreambuf_iterator>\2c\20std::__2::istreambuf_iterator>\2c\20bool\2c\20std::__2::ios_base&\2c\20unsigned\20int&\2c\20long\20double&\29\20const +8106:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8107:std::__2::messages::do_get\28long\2c\20int\2c\20int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\20const&\29\20const +8108:std::__2::locale::__imp::~__imp\28\29_15394 +8109:std::__2::ios_base::~ios_base\28\29_14487 +8110:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20wchar_t*\29\20const +8111:std::__2::ctype::do_toupper\28wchar_t\29\20const +8112:std::__2::ctype::do_toupper\28wchar_t*\2c\20wchar_t\20const*\29\20const +8113:std::__2::ctype::do_tolower\28wchar_t\29\20const +8114:std::__2::ctype::do_tolower\28wchar_t*\2c\20wchar_t\20const*\29\20const +8115:std::__2::ctype::do_scan_not\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8116:std::__2::ctype::do_scan_is\28unsigned\20long\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8117:std::__2::ctype::do_narrow\28wchar_t\2c\20char\29\20const +8118:std::__2::ctype::do_narrow\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20char\2c\20char*\29\20const +8119:std::__2::ctype::do_is\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20unsigned\20long*\29\20const +8120:std::__2::ctype::do_is\28unsigned\20long\2c\20wchar_t\29\20const +8121:std::__2::ctype::~ctype\28\29_15381 +8122:std::__2::ctype::do_widen\28char\20const*\2c\20char\20const*\2c\20char*\29\20const +8123:std::__2::ctype::do_toupper\28char\29\20const +8124:std::__2::ctype::do_toupper\28char*\2c\20char\20const*\29\20const +8125:std::__2::ctype::do_tolower\28char\29\20const +8126:std::__2::ctype::do_tolower\28char*\2c\20char\20const*\29\20const +8127:std::__2::ctype::do_narrow\28char\2c\20char\29\20const +8128:std::__2::ctype::do_narrow\28char\20const*\2c\20char\20const*\2c\20char\2c\20char*\29\20const +8129:std::__2::collate::do_transform\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8130:std::__2::collate::do_hash\28wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8131:std::__2::collate::do_compare\28wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*\29\20const +8132:std::__2::collate::do_transform\28char\20const*\2c\20char\20const*\29\20const +8133:std::__2::collate::do_hash\28char\20const*\2c\20char\20const*\29\20const +8134:std::__2::collate::do_compare\28char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\29\20const +8135:std::__2::codecvt::~codecvt\28\29_15341 +8136:std::__2::codecvt::do_unshift\28__mbstate_t&\2c\20char*\2c\20char*\2c\20char*&\29\20const +8137:std::__2::codecvt::do_out\28__mbstate_t&\2c\20wchar_t\20const*\2c\20wchar_t\20const*\2c\20wchar_t\20const*&\2c\20char*\2c\20char*\2c\20char*&\29\20const +8138:std::__2::codecvt::do_max_length\28\29\20const +8139:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +8140:std::__2::codecvt::do_in\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*&\2c\20wchar_t*\2c\20wchar_t*\2c\20wchar_t*&\29\20const +8141:std::__2::codecvt::do_encoding\28\29\20const +8142:std::__2::codecvt::do_length\28__mbstate_t&\2c\20char\20const*\2c\20char\20const*\2c\20unsigned\20long\29\20const +8143:std::__2::basic_stringbuf\2c\20std::__2::allocator>::~basic_stringbuf\28\29_14472 +8144:std::__2::basic_stringbuf\2c\20std::__2::allocator>::underflow\28\29 +8145:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +8146:std::__2::basic_stringbuf\2c\20std::__2::allocator>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +8147:std::__2::basic_stringbuf\2c\20std::__2::allocator>::pbackfail\28int\29 +8148:std::__2::basic_stringbuf\2c\20std::__2::allocator>::overflow\28int\29 +8149:std::__2::basic_streambuf>::~basic_streambuf\28\29_14279 +8150:std::__2::basic_streambuf>::xsputn\28char\20const*\2c\20long\29 +8151:std::__2::basic_streambuf>::xsgetn\28char*\2c\20long\29 +8152:std::__2::basic_streambuf>::uflow\28\29 +8153:std::__2::basic_streambuf>::setbuf\28char*\2c\20long\29 +8154:std::__2::basic_streambuf>::seekpos\28std::__2::fpos<__mbstate_t>\2c\20unsigned\20int\29 +8155:std::__2::basic_streambuf>::seekoff\28long\20long\2c\20std::__2::ios_base::seekdir\2c\20unsigned\20int\29 +8156:std::__2::bad_function_call::what\28\29\20const +8157:std::__2::__time_get_c_storage::__x\28\29\20const +8158:std::__2::__time_get_c_storage::__weeks\28\29\20const +8159:std::__2::__time_get_c_storage::__r\28\29\20const +8160:std::__2::__time_get_c_storage::__months\28\29\20const +8161:std::__2::__time_get_c_storage::__c\28\29\20const +8162:std::__2::__time_get_c_storage::__am_pm\28\29\20const +8163:std::__2::__time_get_c_storage::__X\28\29\20const +8164:std::__2::__time_get_c_storage::__x\28\29\20const +8165:std::__2::__time_get_c_storage::__weeks\28\29\20const +8166:std::__2::__time_get_c_storage::__r\28\29\20const +8167:std::__2::__time_get_c_storage::__months\28\29\20const +8168:std::__2::__time_get_c_storage::__c\28\29\20const +8169:std::__2::__time_get_c_storage::__am_pm\28\29\20const +8170:std::__2::__time_get_c_storage::__X\28\29\20const +8171:std::__2::__shared_ptr_pointer<_IO_FILE*\2c\20void\20\28*\29\28_IO_FILE*\29\2c\20std::__2::allocator<_IO_FILE>>::__on_zero_shared\28\29 +8172:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7010 +8173:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8174:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +8175:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7283 +8176:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8177:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +8178:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_7523 +8179:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8180:std::__2::__shared_ptr_emplace>::__on_zero_shared\28\29 +8181:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29_5476 +8182:std::__2::__shared_ptr_emplace>::~__shared_ptr_emplace\28\29 +8183:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8184:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8185:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8186:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8187:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8188:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8189:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8190:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8191:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8192:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8193:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8194:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8195:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8196:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8197:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8198:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8199:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8200:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8201:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +8202:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8203:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +8204:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::operator\28\29\28skia::textlayout::Cluster\20const*&&\2c\20unsigned\20long&&\2c\20bool&&\29 +8205:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8206:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Cluster\20const*\2c\20unsigned\20long\2c\20bool\29>::__clone\28\29\20const +8207:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8208:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8209:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8210:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8211:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8212:std::__2::__function::__func\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\2c\20std::__2::vector>&\29\20const::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8213:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8214:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8215:std::__2::__function::__func>&\29::$_0\2c\20std::__2::allocator>&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8216:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8217:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8218:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8219:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8220:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8221:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8222:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8223:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8224:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8225:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8226:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8227:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8228:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8229:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8230:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8231:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8232:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8233:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8234:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8235:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8236:std::__2::__function::__func\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8237:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8238:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8239:std::__2::__function::__func\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8240:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::operator\28\29\28skia::textlayout::Run\20const*&&\2c\20float&&\2c\20skia::textlayout::SkRange&&\2c\20float*&&\29 +8241:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28std::__2::__function::__base\2c\20float*\29>*\29\20const +8242:std::__2::__function::__func\20const&\29::$_0\2c\20std::__2::allocator\20const&\29::$_0>\2c\20bool\20\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29>::__clone\28\29\20const +8243:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29 +8244:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>*\29\20const +8245:std::__2::__function::__func\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\2c\20std::__2::allocator\20const&\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29>::__clone\28\29\20const +8246:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20skia::textlayout::SkRange&&\2c\20float&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20SkPoint&&\2c\20SkPoint&&\2c\20skia::textlayout::InternalLineMetrics&&\2c\20bool&&\29 +8247:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28std::__2::__function::__base\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>*\29\20const +8248:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20skia::textlayout::SkRange\2c\20float\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkPoint\2c\20SkPoint\2c\20skia::textlayout::InternalLineMetrics\2c\20bool\29>::__clone\28\29\20const +8249:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::operator\28\29\28skia::textlayout::Cluster*&&\29 +8250:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28std::__2::__function::__base*\29\20const +8251:std::__2::__function::__func\2c\20void\20\28skia::textlayout::Cluster*\29>::__clone\28\29\20const +8252:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8253:std::__2::__function::__func\2c\20void\20\28skia::textlayout::ParagraphImpl*\2c\20char\20const*\2c\20bool\29>::__clone\28\29\20const +8254:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::operator\28\29\28skia::textlayout::SkRange&&\2c\20SkSpan&&\2c\20float&\2c\20unsigned\20long&&\2c\20unsigned\20char&&\29 +8255:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28std::__2::__function::__base\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>*\29\20const +8256:std::__2::__function::__func\2c\20float\20\28skia::textlayout::SkRange\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29>::__clone\28\29\20const +8257:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::operator\28\29\28skia::textlayout::Block&&\2c\20skia_private::TArray&&\29 +8258:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28std::__2::__function::__base\29>*\29\20const +8259:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29>\2c\20void\20\28skia::textlayout::Block\2c\20skia_private::TArray\29>::__clone\28\29\20const +8260:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::operator\28\29\28sk_sp&&\29 +8261:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28std::__2::__function::__base\29>*\29\20const +8262:std::__2::__function::__func\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29\2c\20std::__2::allocator\2c\20SkSpan\2c\20float&\2c\20unsigned\20long\2c\20unsigned\20char\29\20const::'lambda'\28skia::textlayout::Block\2c\20skia_private::TArray\29::operator\28\29\28skia::textlayout::Block\2c\20skia_private::TArray\29\20const::'lambda'\28sk_sp\29>\2c\20skia::textlayout::OneLineShaper::Resolved\20\28sk_sp\29>::__clone\28\29\20const +8263:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::operator\28\29\28skia::textlayout::SkRange&&\29 +8264:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28std::__2::__function::__base\29>*\29\20const +8265:std::__2::__function::__func\2c\20void\20\28skia::textlayout::SkRange\29>::__clone\28\29\20const +8266:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +8267:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +8268:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +8269:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::~__func\28\29_9570 +8270:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::operator\28\29\28void*&&\2c\20void\20const*&&\29 +8271:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy_deallocate\28\29 +8272:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::destroy\28\29 +8273:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8274:std::__2::__function::__func\2c\20void\20\28void*\2c\20void\20const*\29>::__clone\28\29\20const +8275:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8276:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8277:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8278:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8279:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8280:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8281:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +8282:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8283:std::__2::__function::__func\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8284:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +8285:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8286:std::__2::__function::__func>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8287:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::operator\28\29\28GrSurfaceProxy*&&\2c\20skgpu::Mipmapped&&\29 +8288:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8289:std::__2::__function::__func>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0\2c\20std::__2::allocator>\2c\20bool\2c\20GrProcessorSet::Analysis\20const&\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrTextureResolveManager\2c\20GrCaps\20const&\29::$_0>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8290:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::operator\28\29\28sktext::gpu::AtlasSubRun\20const*&&\2c\20SkPoint&&\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20sktext::gpu::RendererData&&\29 +8291:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28std::__2::__function::__base\2c\20sktext::gpu::RendererData\29>*\29\20const +8292:std::__2::__function::__func\2c\20void\20\28sktext::gpu::AtlasSubRun\20const*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20sktext::gpu::RendererData\29>::__clone\28\29\20const +8293:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::operator\28\29\28sktext::gpu::GlyphVector*&&\2c\20int&&\2c\20int&&\2c\20skgpu::MaskFormat&&\2c\20int&&\29 +8294:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28std::__2::__function::__base\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>*\29\20const +8295:std::__2::__function::__func\2c\20std::__2::tuple\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>::__clone\28\29\20const +8296:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::operator\28\29\28GrSurfaceProxy\20const*&&\29 +8297:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8298:std::__2::__function::__func>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0\2c\20std::__2::allocator>\2c\20SkIRect\20const&\2c\20SkMatrix\20const&\2c\20SkPath\20const&\29::$_0>\2c\20bool\20\28GrSurfaceProxy\20const*\29>::__clone\28\29\20const +8299:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +8300:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +8301:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +8302:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::operator\28\29\28SkIRect&&\29 +8303:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28std::__2::__function::__base\20\28SkIRect\29>*\29\20const +8304:std::__2::__function::__func\2c\20sk_sp\20\28SkIRect\29>::__clone\28\29\20const +8305:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +8306:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8307:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +8308:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8309:std::__2::__function::__func\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrOp\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8310:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28std::__2::__function::__base*\29\20const +8311:std::__2::__function::__func\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29\2c\20std::__2::allocator\28GrFragmentProcessor\20const*\2c\20GrSurfaceProxy\20const*\29::'lambda'\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>\2c\20void\20\28GrSurfaceProxy*\2c\20skgpu::Mipmapped\29>::__clone\28\29\20const +8312:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +8313:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8314:std::__2::__function::__func<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::render_sw_mask\28GrRecordingContext*\2c\20SkIRect\20const&\2c\20skgpu::ganesh::ClipStack::Element\20const**\2c\20int\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8315:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::operator\28\29\28\29 +8316:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8317:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_1>\2c\20void\20\28\29>::__clone\28\29\20const +8318:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8319:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint_bounds\28SkMatrix*\2c\20SkRect*\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8320:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8321:std::__2::__function::__func<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::colrv1_traverse_paint\28SkCanvas*\2c\20SkSpan\20const&\2c\20unsigned\20int\2c\20FT_FaceRec_*\2c\20FT_Opaque_Paint_\2c\20skia_private::THashSet*\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8322:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8323:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8324:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8325:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8326:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8327:std::__2::__function::__func<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8328:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8329:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8330:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::MeshGP\28sk_sp\2c\20sk_sp\2c\20SkMatrix\20const&\2c\20std::__2::optional>\20const&\2c\20bool\2c\20sk_sp\2c\20SkSpan>>\29::'lambda'\28GrTextureEffect\20const&\29>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8331:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8332:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8333:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8334:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8335:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8336:std::__2::__function::__func<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29\2c\20std::__2::allocator<\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29::'lambda'\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8337:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::~__func\28\29_4203 +8338:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::operator\28\29\28\29 +8339:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy_deallocate\28\29 +8340:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::destroy\28\29 +8341:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8342:std::__2::__function::__func\29::$_0\2c\20std::__2::allocator\29::$_0>\2c\20void\20\28\29>::__clone\28\29\20const +8343:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::operator\28\29\28int&&\2c\20char\20const*&&\29 +8344:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8345:std::__2::__function::__func\2c\20void\20\28int\2c\20char\20const*\29>::__clone\28\29\20const +8346:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8347:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8348:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8349:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8350:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8351:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8352:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::operator\28\29\28SkSL::Variable\20const&\29 +8353:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8354:std::__2::__function::__func\2c\20bool\20\28SkSL::Variable\20const&\29>::__clone\28\29\20const +8355:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::operator\28\29\28int&&\2c\20SkSL::Variable\20const*&&\2c\20SkSL::Expression\20const*&&\29 +8356:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28std::__2::__function::__base*\29\20const +8357:std::__2::__function::__func\2c\20void\20\28int\2c\20SkSL::Variable\20const*\2c\20SkSL::Expression\20const*\29>::__clone\28\29\20const +8358:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::operator\28\29\28unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\2c\20unsigned\20long&&\29 +8359:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +8360:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +8361:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +8362:std::__2::__function::__func\2c\20void\20\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\29>::__clone\28\29\20const +8363:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::operator\28\29\28SkVertices\20const*&&\2c\20SkBlendMode&&\2c\20SkPaint\20const&\2c\20float&&\2c\20float&&\2c\20bool&&\29 +8364:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28std::__2::__function::__base*\29\20const +8365:std::__2::__function::__func\2c\20void\20\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\2c\20float\2c\20float\2c\20bool\29>::__clone\28\29\20const +8366:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::operator\28\29\28SkIRect\20const&\29 +8367:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8368:std::__2::__function::__func\2c\20void\20\28SkIRect\20const&\29>::__clone\28\29\20const +8369:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9474 +8370:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8371:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +8372:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +8373:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8374:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8375:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9204 +8376:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8377:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +8378:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +8379:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8380:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8381:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::~__func\28\29_9195 +8382:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8383:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy_deallocate\28\29 +8384:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::destroy\28\29 +8385:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8386:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8387:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::operator\28\29\28GrTextureProxy*&&\2c\20SkIRect&&\2c\20GrColorType&&\2c\20void\20const*&&\2c\20unsigned\20long&&\29 +8388:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28std::__2::__function::__base*\29\20const +8389:std::__2::__function::__func&\29>&\2c\20bool\29::$_0\2c\20std::__2::allocator&\29>&\2c\20bool\29::$_0>\2c\20bool\20\28GrTextureProxy*\2c\20SkIRect\2c\20GrColorType\2c\20void\20const*\2c\20unsigned\20long\29>::__clone\28\29\20const +8390:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::operator\28\29\28GrBackendTexture&&\29 +8391:std::__2::__function::__func*\29::$_0\2c\20std::__2::allocator*\29::$_0>\2c\20void\20\28GrBackendTexture\29>::__clone\28\29\20const +8392:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8393:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8394:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8395:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::operator\28\29\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29 +8396:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28std::__2::__function::__base*\29\20const +8397:std::__2::__function::__func\2c\20void\20\28GrFragmentProcessor\20const&\2c\20GrFragmentProcessor::ProgramImpl&\29>::__clone\28\29\20const +8398:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8399:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8400:std::__2::__function::__func\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8401:std::__2::__function::__func\2c\20void\20\28\29>::operator\28\29\28\29 +8402:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28std::__2::__function::__base*\29\20const +8403:std::__2::__function::__func\2c\20void\20\28\29>::__clone\28\29\20const +8404:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::operator\28\29\28GrTextureEffect\20const&\29 +8405:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8406:std::__2::__function::__func\20const&\29\20const::$_0\2c\20std::__2::allocator\20const&\29\20const::$_0>\2c\20void\20\28GrTextureEffect\20const&\29>::__clone\28\29\20const +8407:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::operator\28\29\28GrResourceProvider*&&\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29 +8408:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28std::__2::__function::__base*\29\20const +8409:std::__2::__function::__func\2c\20GrSurfaceProxy::LazyCallbackResult\20\28GrResourceProvider*\2c\20GrSurfaceProxy::LazySurfaceDesc\20const&\29>::__clone\28\29\20const +8410:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::~__func\28\29_8719 +8411:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +8412:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +8413:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::~__func\28\29_8731 +8414:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +8415:std::__2::__function::__func\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +8416:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::operator\28\29\28std::__2::function&\29 +8417:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28std::__2::__function::__base&\29>*\29\20const +8418:std::__2::__function::__func&\29\2c\20std::__2::allocator&\29>\2c\20void\20\28std::__2::function&\29>::__clone\28\29\20const +8419:srgb_to_hwb\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +8420:srcover_p\28unsigned\20char\2c\20unsigned\20char\29 +8421:sn_write +8422:sktext::gpu::post_purge_blob_message\28unsigned\20int\2c\20unsigned\20int\29 +8423:sktext::gpu::TextBlob::~TextBlob\28\29_12159 +8424:sktext::gpu::SlugImpl::~SlugImpl\28\29_12010 +8425:sktext::gpu::SlugImpl::sourceBounds\28\29\20const +8426:sktext::gpu::SlugImpl::sourceBoundsWithOrigin\28\29\20const +8427:sktext::gpu::SlugImpl::doFlatten\28SkWriteBuffer&\29\20const +8428:sktext::gpu::SDFMaskFilterImpl::getTypeName\28\29\20const +8429:sktext::gpu::SDFMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +8430:sktext::gpu::SDFMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +8431:skif::\28anonymous\20namespace\29::RasterBackend::~RasterBackend\28\29 +8432:skif::\28anonymous\20namespace\29::RasterBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +8433:skif::\28anonymous\20namespace\29::RasterBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +8434:skif::\28anonymous\20namespace\29::RasterBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +8435:skif::\28anonymous\20namespace\29::RasterBackend::getBlurEngine\28\29\20const +8436:skif::\28anonymous\20namespace\29::GaneshBackend::makeImage\28SkIRect\20const&\2c\20sk_sp\29\20const +8437:skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkISize\2c\20sk_sp\2c\20SkSurfaceProps\20const*\29\20const +8438:skif::\28anonymous\20namespace\29::GaneshBackend::getCachedBitmap\28SkBitmap\20const&\29\20const +8439:skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +8440:skia_png_zfree +8441:skia_png_zalloc +8442:skia_png_set_read_fn +8443:skia_png_set_expand_gray_1_2_4_to_8 +8444:skia_png_read_start_row +8445:skia_png_read_finish_row +8446:skia_png_handle_zTXt +8447:skia_png_handle_unknown +8448:skia_png_handle_tRNS +8449:skia_png_handle_tIME +8450:skia_png_handle_tEXt +8451:skia_png_handle_sRGB +8452:skia_png_handle_sPLT +8453:skia_png_handle_sCAL +8454:skia_png_handle_sBIT +8455:skia_png_handle_pHYs +8456:skia_png_handle_pCAL +8457:skia_png_handle_oFFs +8458:skia_png_handle_iTXt +8459:skia_png_handle_iCCP +8460:skia_png_handle_hIST +8461:skia_png_handle_gAMA +8462:skia_png_handle_cHRM +8463:skia_png_handle_bKGD +8464:skia_png_handle_PLTE +8465:skia_png_handle_IHDR +8466:skia_png_handle_IEND +8467:skia_png_get_IHDR +8468:skia_png_do_read_transformations +8469:skia_png_destroy_read_struct +8470:skia_png_default_read_data +8471:skia_png_create_png_struct +8472:skia_png_combine_row +8473:skia::textlayout::TypefaceFontStyleSet::~TypefaceFontStyleSet\28\29_7456 +8474:skia::textlayout::TypefaceFontStyleSet::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +8475:skia::textlayout::TypefaceFontProvider::~TypefaceFontProvider\28\29_7463 +8476:skia::textlayout::TypefaceFontProvider::onMatchFamily\28char\20const*\29\20const +8477:skia::textlayout::TypefaceFontProvider::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +8478:skia::textlayout::TypefaceFontProvider::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +8479:skia::textlayout::TypefaceFontProvider::onGetFamilyName\28int\2c\20SkString*\29\20const +8480:skia::textlayout::TypefaceFontProvider::onCreateStyleSet\28int\29\20const +8481:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::~ShapeHandler\28\29_7376 +8482:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8483:skia::textlayout::TextLine::shapeEllipsis\28SkString\20const&\2c\20skia::textlayout::Cluster\20const*\29::ShapeHandler::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8484:skia::textlayout::ParagraphImpl::~ParagraphImpl\28\29_7121 +8485:skia::textlayout::ParagraphImpl::visit\28std::__2::function\20const&\29 +8486:skia::textlayout::ParagraphImpl::updateTextAlign\28skia::textlayout::TextAlign\29 +8487:skia::textlayout::ParagraphImpl::updateForegroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +8488:skia::textlayout::ParagraphImpl::updateFontSize\28unsigned\20long\2c\20unsigned\20long\2c\20float\29 +8489:skia::textlayout::ParagraphImpl::updateBackgroundPaint\28unsigned\20long\2c\20unsigned\20long\2c\20SkPaint\29 +8490:skia::textlayout::ParagraphImpl::unresolvedGlyphs\28\29 +8491:skia::textlayout::ParagraphImpl::unresolvedCodepoints\28\29 +8492:skia::textlayout::ParagraphImpl::paint\28SkCanvas*\2c\20float\2c\20float\29 +8493:skia::textlayout::ParagraphImpl::markDirty\28\29 +8494:skia::textlayout::ParagraphImpl::lineNumber\28\29 +8495:skia::textlayout::ParagraphImpl::layout\28float\29 +8496:skia::textlayout::ParagraphImpl::getWordBoundary\28unsigned\20int\29 +8497:skia::textlayout::ParagraphImpl::getRectsForRange\28unsigned\20int\2c\20unsigned\20int\2c\20skia::textlayout::RectHeightStyle\2c\20skia::textlayout::RectWidthStyle\29 +8498:skia::textlayout::ParagraphImpl::getRectsForPlaceholders\28\29 +8499:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29::$_0::operator\28\29\28skia::textlayout::Run\20const*\2c\20float\2c\20skia::textlayout::SkRange\2c\20float*\29\20const::'lambda'\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29::operator\28\29\28skia::textlayout::SkRange\2c\20skia::textlayout::TextStyle\20const&\2c\20skia::textlayout::TextLine::ClipContext\20const&\29\20const::'lambda'\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +8500:skia::textlayout::ParagraphImpl::getPath\28int\2c\20SkPath*\29 +8501:skia::textlayout::ParagraphImpl::getLineNumberAtUTF16Offset\28unsigned\20long\29 +8502:skia::textlayout::ParagraphImpl::getLineMetrics\28std::__2::vector>&\29 +8503:skia::textlayout::ParagraphImpl::getLineMetricsAt\28int\2c\20skia::textlayout::LineMetrics*\29\20const +8504:skia::textlayout::ParagraphImpl::getFonts\28\29\20const +8505:skia::textlayout::ParagraphImpl::getFontAt\28unsigned\20long\29\20const +8506:skia::textlayout::ParagraphImpl::getFontAtUTF16Offset\28unsigned\20long\29 +8507:skia::textlayout::ParagraphImpl::getClosestUTF16GlyphInfoAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphInfo*\29 +8508:skia::textlayout::ParagraphImpl::getClosestGlyphClusterAt\28float\2c\20float\2c\20skia::textlayout::Paragraph::GlyphClusterInfo*\29 +8509:skia::textlayout::ParagraphImpl::getActualTextRange\28int\2c\20bool\29\20const +8510:skia::textlayout::ParagraphImpl::extendedVisit\28std::__2::function\20const&\29 +8511:skia::textlayout::ParagraphImpl::containsEmoji\28SkTextBlob*\29 +8512:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29::$_0::__invoke\28SkPath\20const*\2c\20SkMatrix\20const&\2c\20void*\29 +8513:skia::textlayout::ParagraphImpl::containsColorFontOrBitmap\28SkTextBlob*\29 +8514:skia::textlayout::ParagraphBuilderImpl::~ParagraphBuilderImpl\28\29_7022 +8515:skia::textlayout::ParagraphBuilderImpl::setWordsUtf8\28std::__2::vector>\29 +8516:skia::textlayout::ParagraphBuilderImpl::setWordsUtf16\28std::__2::vector>\29 +8517:skia::textlayout::ParagraphBuilderImpl::setLineBreaksUtf8\28std::__2::vector>\29 +8518:skia::textlayout::ParagraphBuilderImpl::setLineBreaksUtf16\28std::__2::vector>\29 +8519:skia::textlayout::ParagraphBuilderImpl::setGraphemeBreaksUtf8\28std::__2::vector>\29 +8520:skia::textlayout::ParagraphBuilderImpl::setGraphemeBreaksUtf16\28std::__2::vector>\29 +8521:skia::textlayout::ParagraphBuilderImpl::pushStyle\28skia::textlayout::TextStyle\20const&\29 +8522:skia::textlayout::ParagraphBuilderImpl::pop\28\29 +8523:skia::textlayout::ParagraphBuilderImpl::peekStyle\28\29 +8524:skia::textlayout::ParagraphBuilderImpl::getText\28\29 +8525:skia::textlayout::ParagraphBuilderImpl::getParagraphStyle\28\29\20const +8526:skia::textlayout::ParagraphBuilderImpl::getClientICUData\28\29\20const +8527:skia::textlayout::ParagraphBuilderImpl::addText\28std::__2::basic_string\2c\20std::__2::allocator>\20const&\29 +8528:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\2c\20unsigned\20long\29 +8529:skia::textlayout::ParagraphBuilderImpl::addText\28char\20const*\29 +8530:skia::textlayout::ParagraphBuilderImpl::addPlaceholder\28skia::textlayout::PlaceholderStyle\20const&\29 +8531:skia::textlayout::ParagraphBuilderImpl::SetUnicode\28sk_sp\29 +8532:skia::textlayout::ParagraphBuilderImpl::Reset\28\29 +8533:skia::textlayout::ParagraphBuilderImpl::Build\28\29 +8534:skia::textlayout::Paragraph::FontInfo::~FontInfo\28\29_7204 +8535:skia::textlayout::OneLineShaper::~OneLineShaper\28\29_7002 +8536:skia::textlayout::OneLineShaper::runBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8537:skia::textlayout::OneLineShaper::commitRunBuffer\28SkShaper::RunHandler::RunInfo\20const&\29 +8538:skia::textlayout::LangIterator::~LangIterator\28\29_6990 +8539:skia::textlayout::LangIterator::~LangIterator\28\29 +8540:skia::textlayout::LangIterator::endOfCurrentRun\28\29\20const +8541:skia::textlayout::LangIterator::currentLanguage\28\29\20const +8542:skia::textlayout::LangIterator::consume\28\29 +8543:skia::textlayout::LangIterator::atEnd\28\29\20const +8544:skia::textlayout::FontCollection::~FontCollection\28\29_6853 +8545:skia::textlayout::CanvasParagraphPainter::translate\28float\2c\20float\29 +8546:skia::textlayout::CanvasParagraphPainter::save\28\29 +8547:skia::textlayout::CanvasParagraphPainter::restore\28\29 +8548:skia::textlayout::CanvasParagraphPainter::drawTextShadow\28sk_sp\20const&\2c\20float\2c\20float\2c\20unsigned\20int\2c\20float\29 +8549:skia::textlayout::CanvasParagraphPainter::drawTextBlob\28sk_sp\20const&\2c\20float\2c\20float\2c\20std::__2::variant\20const&\29 +8550:skia::textlayout::CanvasParagraphPainter::drawRect\28SkRect\20const&\2c\20std::__2::variant\20const&\29 +8551:skia::textlayout::CanvasParagraphPainter::drawPath\28SkPath\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +8552:skia::textlayout::CanvasParagraphPainter::drawLine\28float\2c\20float\2c\20float\2c\20float\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +8553:skia::textlayout::CanvasParagraphPainter::drawFilledRect\28SkRect\20const&\2c\20skia::textlayout::ParagraphPainter::DecorationStyle\20const&\29 +8554:skia::textlayout::CanvasParagraphPainter::clipRect\28SkRect\20const&\29 +8555:skgpu::tess::FixedCountWedges::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8556:skgpu::tess::FixedCountWedges::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8557:skgpu::tess::FixedCountStrokes::WriteVertexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8558:skgpu::tess::FixedCountCurves::WriteIndexBuffer\28skgpu::VertexWriter\2c\20unsigned\20long\29 +8559:skgpu::ganesh::texture_proxy_view_from_planes\28GrRecordingContext*\2c\20SkImage_Lazy\20const*\2c\20skgpu::Budgeted\29::$_0::__invoke\28void*\2c\20void*\29 +8560:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::~SmallPathOp\28\29_11132 +8561:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::visitProxies\28std::__2::function\20const&\29\20const +8562:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8563:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8564:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8565:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::name\28\29\20const +8566:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::fixedFunctionFlags\28\29\20const +8567:skgpu::ganesh::\28anonymous\20namespace\29::SmallPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8568:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::name\28\29\20const +8569:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8570:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8571:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8572:skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8573:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::~HullShader\28\29_10997 +8574:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::name\28\29\20const +8575:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8576:skgpu::ganesh::\28anonymous\20namespace\29::HullShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8577:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::~AAFlatteningConvexPathOp\28\29_10377 +8578:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +8579:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8580:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8581:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8582:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8583:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::name\28\29\20const +8584:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::fixedFunctionFlags\28\29\20const +8585:skgpu::ganesh::\28anonymous\20namespace\29::AAFlatteningConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8586:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::~AAConvexPathOp\28\29_10284 +8587:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::visitProxies\28std::__2::function\20const&\29\20const +8588:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8589:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8590:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8591:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8592:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::name\28\29\20const +8593:skgpu::ganesh::\28anonymous\20namespace\29::AAConvexPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8594:skgpu::ganesh::TriangulatingPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8595:skgpu::ganesh::TriangulatingPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8596:skgpu::ganesh::TriangulatingPathRenderer::name\28\29\20const +8597:skgpu::ganesh::TessellationPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +8598:skgpu::ganesh::TessellationPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +8599:skgpu::ganesh::TessellationPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8600:skgpu::ganesh::TessellationPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8601:skgpu::ganesh::TessellationPathRenderer::name\28\29\20const +8602:skgpu::ganesh::SurfaceDrawContext::~SurfaceDrawContext\28\29 +8603:skgpu::ganesh::SurfaceDrawContext::willReplaceOpsTask\28skgpu::ganesh::OpsTask*\2c\20skgpu::ganesh::OpsTask*\29 +8604:skgpu::ganesh::SurfaceDrawContext::canDiscardPreviousOpsOnFullClear\28\29\20const +8605:skgpu::ganesh::SurfaceContext::~SurfaceContext\28\29_8679 +8606:skgpu::ganesh::SurfaceContext::asyncRescaleAndReadPixelsYUV420\28GrDirectContext*\2c\20SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +8607:skgpu::ganesh::SurfaceContext::asyncReadPixels\28GrDirectContext*\2c\20SkIRect\20const&\2c\20SkColorType\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::$_0::__invoke\28void*\29 +8608:skgpu::ganesh::StrokeTessellateOp::~StrokeTessellateOp\28\29_11192 +8609:skgpu::ganesh::StrokeTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +8610:skgpu::ganesh::StrokeTessellateOp::usesStencil\28\29\20const +8611:skgpu::ganesh::StrokeTessellateOp::onPrepare\28GrOpFlushState*\29 +8612:skgpu::ganesh::StrokeTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8613:skgpu::ganesh::StrokeTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8614:skgpu::ganesh::StrokeTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8615:skgpu::ganesh::StrokeTessellateOp::name\28\29\20const +8616:skgpu::ganesh::StrokeTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8617:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::~NonAAStrokeRectOp\28\29_11169 +8618:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +8619:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::programInfo\28\29 +8620:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8621:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8622:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8623:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::name\28\29\20const +8624:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::NonAAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8625:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::~AAStrokeRectOp\28\29_11179 +8626:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::visitProxies\28std::__2::function\20const&\29\20const +8627:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::programInfo\28\29 +8628:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8629:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8630:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8631:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8632:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::name\28\29\20const +8633:skgpu::ganesh::StrokeRectOp::\28anonymous\20namespace\29::AAStrokeRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8634:skgpu::ganesh::StencilClip::~StencilClip\28\29_9537 +8635:skgpu::ganesh::StencilClip::~StencilClip\28\29 +8636:skgpu::ganesh::StencilClip::preApply\28SkRect\20const&\2c\20GrAA\29\20const +8637:skgpu::ganesh::StencilClip::apply\28GrAppliedHardClip*\2c\20SkIRect*\29\20const +8638:skgpu::ganesh::SoftwarePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8639:skgpu::ganesh::SoftwarePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8640:skgpu::ganesh::SoftwarePathRenderer::name\28\29\20const +8641:skgpu::ganesh::SmallPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8642:skgpu::ganesh::SmallPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8643:skgpu::ganesh::SmallPathRenderer::name\28\29\20const +8644:skgpu::ganesh::SmallPathAtlasMgr::postFlush\28skgpu::AtlasToken\29 +8645:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::~RegionOpImpl\28\29_11079 +8646:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8647:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::programInfo\28\29 +8648:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8649:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8650:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8651:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8652:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::name\28\29\20const +8653:skgpu::ganesh::RegionOp::\28anonymous\20namespace\29::RegionOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8654:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_quad_generic\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8655:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8656:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8657:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8658:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_cov_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8659:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv_strict\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8660:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color_uv\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8661:skgpu::ganesh::QuadPerEdgeAA::\28anonymous\20namespace\29::write_2d_color\28skgpu::VertexWriter*\2c\20skgpu::ganesh::QuadPerEdgeAA::VertexSpec\20const&\2c\20GrQuad\20const*\2c\20GrQuad\20const*\2c\20float\20const*\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkRect\20const&\2c\20SkRect\20const&\29 +8662:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::~QuadPerEdgeAAGeometryProcessor\28\29_11068 +8663:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::onTextureSampler\28int\29\20const +8664:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::name\28\29\20const +8665:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8666:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8667:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8668:skgpu::ganesh::QuadPerEdgeAA::QuadPerEdgeAAGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8669:skgpu::ganesh::PathWedgeTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +8670:skgpu::ganesh::PathTessellateOp::~PathTessellateOp\28\29_11052 +8671:skgpu::ganesh::PathTessellateOp::visitProxies\28std::__2::function\20const&\29\20const +8672:skgpu::ganesh::PathTessellateOp::usesStencil\28\29\20const +8673:skgpu::ganesh::PathTessellateOp::onPrepare\28GrOpFlushState*\29 +8674:skgpu::ganesh::PathTessellateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8675:skgpu::ganesh::PathTessellateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8676:skgpu::ganesh::PathTessellateOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8677:skgpu::ganesh::PathTessellateOp::name\28\29\20const +8678:skgpu::ganesh::PathTessellateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8679:skgpu::ganesh::PathStencilCoverOp::~PathStencilCoverOp\28\29_11042 +8680:skgpu::ganesh::PathStencilCoverOp::visitProxies\28std::__2::function\20const&\29\20const +8681:skgpu::ganesh::PathStencilCoverOp::onPrepare\28GrOpFlushState*\29 +8682:skgpu::ganesh::PathStencilCoverOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8683:skgpu::ganesh::PathStencilCoverOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8684:skgpu::ganesh::PathStencilCoverOp::name\28\29\20const +8685:skgpu::ganesh::PathStencilCoverOp::fixedFunctionFlags\28\29\20const +8686:skgpu::ganesh::PathStencilCoverOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8687:skgpu::ganesh::PathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +8688:skgpu::ganesh::PathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +8689:skgpu::ganesh::PathInnerTriangulateOp::~PathInnerTriangulateOp\28\29_11018 +8690:skgpu::ganesh::PathInnerTriangulateOp::visitProxies\28std::__2::function\20const&\29\20const +8691:skgpu::ganesh::PathInnerTriangulateOp::onPrepare\28GrOpFlushState*\29 +8692:skgpu::ganesh::PathInnerTriangulateOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8693:skgpu::ganesh::PathInnerTriangulateOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8694:skgpu::ganesh::PathInnerTriangulateOp::name\28\29\20const +8695:skgpu::ganesh::PathInnerTriangulateOp::fixedFunctionFlags\28\29\20const +8696:skgpu::ganesh::PathInnerTriangulateOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8697:skgpu::ganesh::PathCurveTessellator::prepare\28GrMeshDrawTarget*\2c\20SkMatrix\20const&\2c\20skgpu::ganesh::PathTessellator::PathDrawList\20const&\2c\20int\29 +8698:skgpu::ganesh::OpsTask::~OpsTask\28\29_10938 +8699:skgpu::ganesh::OpsTask::onPrepare\28GrOpFlushState*\29 +8700:skgpu::ganesh::OpsTask::onPrePrepare\28GrRecordingContext*\29 +8701:skgpu::ganesh::OpsTask::onMakeSkippable\28\29 +8702:skgpu::ganesh::OpsTask::onIsUsed\28GrSurfaceProxy*\29\20const +8703:skgpu::ganesh::OpsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +8704:skgpu::ganesh::OpsTask::endFlush\28GrDrawingManager*\29 +8705:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::~NonAALatticeOp\28\29_10907 +8706:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::visitProxies\28std::__2::function\20const&\29\20const +8707:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8708:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8709:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8710:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8711:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::name\28\29\20const +8712:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::NonAALatticeOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8713:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::~LatticeGP\28\29_10920 +8714:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::onTextureSampler\28int\29\20const +8715:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::name\28\29\20const +8716:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8717:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8718:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8719:skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8720:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::~FillRRectOpImpl\28\29_10724 +8721:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8722:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::programInfo\28\29 +8723:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8724:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8725:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8726:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8727:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::name\28\29\20const +8728:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8729:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::clipToShape\28skgpu::ganesh::SurfaceDrawContext*\2c\20SkClipOp\2c\20SkMatrix\20const&\2c\20GrShape\20const&\2c\20GrAA\29 +8730:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29_10742 +8731:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::~Processor\28\29 +8732:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::name\28\29\20const +8733:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8734:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +8735:skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8736:skgpu::ganesh::DrawableOp::~DrawableOp\28\29_10713 +8737:skgpu::ganesh::DrawableOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8738:skgpu::ganesh::DrawableOp::name\28\29\20const +8739:skgpu::ganesh::DrawAtlasPathOp::~DrawAtlasPathOp\28\29_10620 +8740:skgpu::ganesh::DrawAtlasPathOp::visitProxies\28std::__2::function\20const&\29\20const +8741:skgpu::ganesh::DrawAtlasPathOp::onPrepare\28GrOpFlushState*\29 +8742:skgpu::ganesh::DrawAtlasPathOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8743:skgpu::ganesh::DrawAtlasPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8744:skgpu::ganesh::DrawAtlasPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8745:skgpu::ganesh::DrawAtlasPathOp::name\28\29\20const +8746:skgpu::ganesh::DrawAtlasPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8747:skgpu::ganesh::Device::~Device\28\29_8038 +8748:skgpu::ganesh::Device::strikeDeviceInfo\28\29\20const +8749:skgpu::ganesh::Device::snapSpecial\28SkIRect\20const&\2c\20bool\29 +8750:skgpu::ganesh::Device::snapSpecialScaled\28SkIRect\20const&\2c\20SkISize\20const&\29 +8751:skgpu::ganesh::Device::replaceClip\28SkIRect\20const&\29 +8752:skgpu::ganesh::Device::recordingContext\28\29\20const +8753:skgpu::ganesh::Device::pushClipStack\28\29 +8754:skgpu::ganesh::Device::popClipStack\28\29 +8755:skgpu::ganesh::Device::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +8756:skgpu::ganesh::Device::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +8757:skgpu::ganesh::Device::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +8758:skgpu::ganesh::Device::onClipShader\28sk_sp\29 +8759:skgpu::ganesh::Device::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +8760:skgpu::ganesh::Device::makeSpecial\28SkImage\20const*\29 +8761:skgpu::ganesh::Device::isClipWideOpen\28\29\20const +8762:skgpu::ganesh::Device::isClipRect\28\29\20const +8763:skgpu::ganesh::Device::isClipEmpty\28\29\20const +8764:skgpu::ganesh::Device::isClipAntiAliased\28\29\20const +8765:skgpu::ganesh::Device::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +8766:skgpu::ganesh::Device::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8767:skgpu::ganesh::Device::drawShadow\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +8768:skgpu::ganesh::Device::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +8769:skgpu::ganesh::Device::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +8770:skgpu::ganesh::Device::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +8771:skgpu::ganesh::Device::drawPaint\28SkPaint\20const&\29 +8772:skgpu::ganesh::Device::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +8773:skgpu::ganesh::Device::drawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +8774:skgpu::ganesh::Device::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8775:skgpu::ganesh::Device::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +8776:skgpu::ganesh::Device::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +8777:skgpu::ganesh::Device::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8778:skgpu::ganesh::Device::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +8779:skgpu::ganesh::Device::drawDevice\28SkDevice*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +8780:skgpu::ganesh::Device::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +8781:skgpu::ganesh::Device::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +8782:skgpu::ganesh::Device::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +8783:skgpu::ganesh::Device::drawArc\28SkArc\20const&\2c\20SkPaint\20const&\29 +8784:skgpu::ganesh::Device::devClipBounds\28\29\20const +8785:skgpu::ganesh::Device::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +8786:skgpu::ganesh::Device::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +8787:skgpu::ganesh::Device::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +8788:skgpu::ganesh::Device::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +8789:skgpu::ganesh::Device::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +8790:skgpu::ganesh::Device::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +8791:skgpu::ganesh::Device::android_utils_clipWithStencil\28\29 +8792:skgpu::ganesh::DefaultPathRenderer::onStencilPath\28skgpu::ganesh::PathRenderer::StencilPathArgs\20const&\29 +8793:skgpu::ganesh::DefaultPathRenderer::onGetStencilSupport\28GrStyledShape\20const&\29\20const +8794:skgpu::ganesh::DefaultPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8795:skgpu::ganesh::DefaultPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8796:skgpu::ganesh::DefaultPathRenderer::name\28\29\20const +8797:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::name\28\29\20const +8798:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8799:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8800:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingLineEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8801:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::name\28\29\20const +8802:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +8803:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +8804:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashingCircleEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +8805:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::~DashOpImpl\28\29_10518 +8806:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::visitProxies\28std::__2::function\20const&\29\20const +8807:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::programInfo\28\29 +8808:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +8809:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8810:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +8811:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8812:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::name\28\29\20const +8813:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::fixedFunctionFlags\28\29\20const +8814:skgpu::ganesh::DashOp::\28anonymous\20namespace\29::DashOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8815:skgpu::ganesh::DashLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8816:skgpu::ganesh::DashLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8817:skgpu::ganesh::DashLinePathRenderer::name\28\29\20const +8818:skgpu::ganesh::ClipStack::~ClipStack\28\29_7930 +8819:skgpu::ganesh::ClipStack::preApply\28SkRect\20const&\2c\20GrAA\29\20const +8820:skgpu::ganesh::ClipStack::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +8821:skgpu::ganesh::ClearOp::~ClearOp\28\29 +8822:skgpu::ganesh::ClearOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8823:skgpu::ganesh::ClearOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8824:skgpu::ganesh::ClearOp::name\28\29\20const +8825:skgpu::ganesh::AtlasTextOp::~AtlasTextOp\28\29_10459 +8826:skgpu::ganesh::AtlasTextOp::visitProxies\28std::__2::function\20const&\29\20const +8827:skgpu::ganesh::AtlasTextOp::onPrepareDraws\28GrMeshDrawTarget*\29 +8828:skgpu::ganesh::AtlasTextOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +8829:skgpu::ganesh::AtlasTextOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +8830:skgpu::ganesh::AtlasTextOp::name\28\29\20const +8831:skgpu::ganesh::AtlasTextOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +8832:skgpu::ganesh::AtlasRenderTask::~AtlasRenderTask\28\29_10445 +8833:skgpu::ganesh::AtlasRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +8834:skgpu::ganesh::AtlasRenderTask::onExecute\28GrOpFlushState*\29 +8835:skgpu::ganesh::AtlasPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8836:skgpu::ganesh::AtlasPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8837:skgpu::ganesh::AtlasPathRenderer::name\28\29\20const +8838:skgpu::ganesh::AALinearizingConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8839:skgpu::ganesh::AALinearizingConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8840:skgpu::ganesh::AALinearizingConvexPathRenderer::name\28\29\20const +8841:skgpu::ganesh::AAHairLinePathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8842:skgpu::ganesh::AAHairLinePathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8843:skgpu::ganesh::AAHairLinePathRenderer::name\28\29\20const +8844:skgpu::ganesh::AAConvexPathRenderer::onDrawPath\28skgpu::ganesh::PathRenderer::DrawPathArgs\20const&\29 +8845:skgpu::ganesh::AAConvexPathRenderer::onCanDrawPath\28skgpu::ganesh::PathRenderer::CanDrawPathArgs\20const&\29\20const +8846:skgpu::ganesh::AAConvexPathRenderer::name\28\29\20const +8847:skgpu::TAsyncReadResult::~TAsyncReadResult\28\29_9565 +8848:skgpu::TAsyncReadResult::rowBytes\28int\29\20const +8849:skgpu::TAsyncReadResult::data\28int\29\20const +8850:skgpu::StringKeyBuilder::~StringKeyBuilder\28\29_9169 +8851:skgpu::StringKeyBuilder::appendComment\28char\20const*\29 +8852:skgpu::StringKeyBuilder::addBits\28unsigned\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +8853:skgpu::ShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\2c\20bool\29 +8854:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29_11944 +8855:skgpu::RectanizerSkyline::~RectanizerSkyline\28\29 +8856:skgpu::RectanizerSkyline::percentFull\28\29\20const +8857:skgpu::RectanizerPow2::reset\28\29 +8858:skgpu::RectanizerPow2::percentFull\28\29\20const +8859:skgpu::RectanizerPow2::addRect\28int\2c\20int\2c\20SkIPoint16*\29 +8860:skgpu::Plot::~Plot\28\29_11935 +8861:skgpu::KeyBuilder::~KeyBuilder\28\29 +8862:skgpu::DefaultShaderErrorHandler\28\29::DefaultShaderErrorHandler::compileError\28char\20const*\2c\20char\20const*\29 +8863:sk_mmap_releaseproc\28void\20const*\2c\20void*\29 +8864:sk_ft_stream_io\28FT_StreamRec_*\2c\20unsigned\20long\2c\20unsigned\20char*\2c\20unsigned\20long\29 +8865:sk_ft_realloc\28FT_MemoryRec_*\2c\20long\2c\20long\2c\20void*\29 +8866:sk_fclose\28_IO_FILE*\29 +8867:skString_getLength +8868:skString_getData +8869:skString_free +8870:skString_allocate +8871:skString16_getData +8872:skString16_free +8873:skString16_allocate +8874:skData_dispose +8875:skData_create +8876:shader_createSweepGradient +8877:shader_createRuntimeEffectShader +8878:shader_createRadialGradient +8879:shader_createLinearGradient +8880:shader_createFromImage +8881:shader_createConicalGradient +8882:sfnt_table_info +8883:sfnt_load_face +8884:sfnt_is_postscript +8885:sfnt_is_alphanumeric +8886:sfnt_init_face +8887:sfnt_get_ps_name +8888:sfnt_get_name_index +8889:sfnt_get_interface +8890:sfnt_get_glyph_name +8891:sfnt_get_charset_id +8892:sfnt_done_face +8893:setup_syllables_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8894:setup_syllables_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8895:setup_syllables_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8896:setup_syllables_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8897:setup_masks_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8898:setup_masks_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8899:setup_masks_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8900:setup_masks_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8901:setup_masks_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8902:setup_masks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8903:runtimeEffect_getUniformSize +8904:runtimeEffect_create +8905:reverse_hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +8906:reverse_hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +8907:reorder_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8908:reorder_myanmar\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8909:reorder_marks_hebrew\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +8910:reorder_marks_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20unsigned\20int\2c\20unsigned\20int\29 +8911:reorder_khmer\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8912:release_data\28void*\2c\20void*\29 +8913:rect_memcpy\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20SkColorSpaceXformSteps\20const&\29 +8914:record_stch\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8915:record_rphf_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8916:record_pref_use\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +8917:read_data_from_FT_Stream +8918:psnames_get_service +8919:pshinter_get_t2_funcs +8920:pshinter_get_t1_funcs +8921:pshinter_get_globals_funcs +8922:psh_globals_new +8923:psh_globals_destroy +8924:psaux_get_glyph_name +8925:ps_table_release +8926:ps_table_new +8927:ps_table_done +8928:ps_table_add +8929:ps_property_set +8930:ps_property_get +8931:ps_parser_to_int +8932:ps_parser_to_fixed_array +8933:ps_parser_to_fixed +8934:ps_parser_to_coord_array +8935:ps_parser_to_bytes +8936:ps_parser_load_field_table +8937:ps_parser_init +8938:ps_hints_t2mask +8939:ps_hints_t2counter +8940:ps_hints_t1stem3 +8941:ps_hints_t1reset +8942:ps_hints_close +8943:ps_hints_apply +8944:ps_hinter_init +8945:ps_hinter_done +8946:ps_get_standard_strings +8947:ps_get_macintosh_name +8948:ps_decoder_init +8949:preprocess_text_use\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8950:preprocess_text_thai\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8951:preprocess_text_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8952:preprocess_text_hangul\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8953:premultiply_data +8954:premul_rgb\28SkRGBA4f<\28SkAlphaType\292>\29 +8955:premul_polar\28SkRGBA4f<\28SkAlphaType\292>\29 +8956:postprocess_glyphs_arabic\28hb_ot_shape_plan_t\20const*\2c\20hb_buffer_t*\2c\20hb_font_t*\29 +8957:portable::xy_to_unit_angle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8958:portable::xy_to_radius\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8959:portable::xy_to_2pt_conical_well_behaved\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8960:portable::xy_to_2pt_conical_strip\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8961:portable::xy_to_2pt_conical_smaller\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8962:portable::xy_to_2pt_conical_greater\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8963:portable::xy_to_2pt_conical_focal_on_circle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8964:portable::xor_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8965:portable::white_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8966:portable::unpremul_polar\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8967:portable::unpremul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8968:portable::uniform_color_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8969:portable::trace_var\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8970:portable::trace_scope\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8971:portable::trace_line\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8972:portable::trace_exit\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8973:portable::trace_enter\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8974:portable::tan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8975:portable::swizzle_copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8976:portable::swizzle_copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8977:portable::swizzle_copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8978:portable::swizzle_copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8979:portable::swizzle_copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8980:portable::swizzle_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8981:portable::swizzle_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8982:portable::swizzle_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8983:portable::swizzle_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8984:portable::swizzle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8985:portable::swap_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8986:portable::swap_rb_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8987:portable::swap_rb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8988:portable::sub_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8989:portable::sub_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8990:portable::sub_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8991:portable::sub_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8992:portable::sub_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8993:portable::sub_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8994:portable::sub_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8995:portable::sub_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8996:portable::sub_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8997:portable::sub_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8998:portable::store_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +8999:portable::store_src_a\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9000:portable::store_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9001:portable::store_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9002:portable::store_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9003:portable::store_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9004:portable::store_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9005:portable::store_r8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9006:portable::store_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9007:portable::store_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9008:portable::store_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9009:portable::store_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9010:portable::store_device_xy01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9011:portable::store_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9012:portable::store_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9013:portable::store_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9014:portable::store_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9015:portable::store_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9016:portable::store_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9017:portable::store_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9018:portable::store_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9019:portable::store_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9020:portable::store_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9021:portable::store_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9022:portable::store_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9023:portable::start_pipeline\28unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20unsigned\20long\2c\20SkRasterPipelineStage*\2c\20SkSpan\2c\20unsigned\20char*\29 +9024:portable::stack_rewind\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9025:portable::stack_checkpoint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9026:portable::srcover_rgba_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9027:portable::srcover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9028:portable::srcout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9029:portable::srcin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9030:portable::srcatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9031:portable::sqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9032:portable::splat_4_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9033:portable::splat_3_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9034:portable::splat_2_constants\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9035:portable::softlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9036:portable::smoothstep_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9037:portable::sin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9038:portable::shuffle\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9039:portable::set_base_pointer\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9040:portable::seed_shader\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9041:portable::screen\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9042:portable::scale_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9043:portable::scale_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9044:portable::scale_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9045:portable::scale_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9046:portable::saturation\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9047:portable::rgb_to_hsl\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9048:portable::repeat_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9049:portable::repeat_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9050:portable::repeat_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9051:portable::refract_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9052:portable::reenable_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9053:portable::premul_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9054:portable::premul\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9055:portable::pow_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9056:portable::plus_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9057:portable::perlin_noise\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9058:portable::parametric\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9059:portable::overlay\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9060:portable::negate_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9061:portable::multiply\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9062:portable::mul_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9063:portable::mul_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9064:portable::mul_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9065:portable::mul_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9066:portable::mul_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9067:portable::mul_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9068:portable::mul_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9069:portable::mul_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9070:portable::mul_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9071:portable::mul_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9072:portable::mul_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9073:portable::mul_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9074:portable::move_src_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9075:portable::move_dst_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9076:portable::modulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9077:portable::mod_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9078:portable::mod_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9079:portable::mod_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9080:portable::mod_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9081:portable::mod_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9082:portable::mix_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9083:portable::mix_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9084:portable::mix_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9085:portable::mix_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9086:portable::mix_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9087:portable::mix_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9088:portable::mix_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9089:portable::mix_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9090:portable::mix_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9091:portable::mix_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9092:portable::mirror_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9093:portable::mirror_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9094:portable::mirror_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9095:portable::mipmap_linear_update\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9096:portable::mipmap_linear_init\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9097:portable::mipmap_linear_finish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9098:portable::min_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9099:portable::min_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9100:portable::min_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9101:portable::min_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9102:portable::min_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9103:portable::min_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9104:portable::min_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9105:portable::min_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9106:portable::min_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9107:portable::min_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9108:portable::min_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9109:portable::min_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9110:portable::min_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9111:portable::min_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9112:portable::min_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9113:portable::min_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9114:portable::merge_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9115:portable::merge_inv_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9116:portable::merge_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9117:portable::max_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9118:portable::max_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9119:portable::max_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9120:portable::max_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9121:portable::max_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9122:portable::max_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9123:portable::max_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9124:portable::max_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9125:portable::max_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9126:portable::max_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9127:portable::max_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9128:portable::max_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9129:portable::max_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9130:portable::max_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9131:portable::max_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9132:portable::max_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9133:portable::matrix_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9134:portable::matrix_scale_translate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9135:portable::matrix_perspective\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9136:portable::matrix_multiply_4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9137:portable::matrix_multiply_3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9138:portable::matrix_multiply_2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9139:portable::matrix_4x5\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9140:portable::matrix_4x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9141:portable::matrix_3x4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9142:portable::matrix_3x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9143:portable::matrix_2x3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9144:portable::mask_off_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9145:portable::mask_off_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9146:portable::mask_2pt_conical_nan\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9147:portable::mask_2pt_conical_degenerates\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9148:portable::luminosity\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9149:portable::log_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9150:portable::log2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9151:portable::load_src_rg\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9152:portable::load_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9153:portable::load_rgf16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9154:portable::load_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9155:portable::load_rg88_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9156:portable::load_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9157:portable::load_rg1616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9158:portable::load_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9159:portable::load_return_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9160:portable::load_loop_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9161:portable::load_f32_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9162:portable::load_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9163:portable::load_f16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9164:portable::load_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9165:portable::load_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9166:portable::load_condition_mask\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9167:portable::load_af16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9168:portable::load_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9169:portable::load_a8_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9170:portable::load_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9171:portable::load_a16_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9172:portable::load_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9173:portable::load_8888_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9174:portable::load_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9175:portable::load_565_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9176:portable::load_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9177:portable::load_4444_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9178:portable::load_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9179:portable::load_16161616_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9180:portable::load_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9181:portable::load_10x6_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9182:portable::load_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9183:portable::load_1010102_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9184:portable::load_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9185:portable::load_1010102_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9186:portable::load_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9187:portable::load_10101010_xr_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9188:portable::load_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9189:portable::lighten\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9190:portable::lerp_u8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9191:portable::lerp_native\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9192:portable::lerp_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9193:portable::lerp_1_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9194:portable::just_return\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9195:portable::jump\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9196:portable::invsqrt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9197:portable::invsqrt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9198:portable::invsqrt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9199:portable::invsqrt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9200:portable::inverse_mat4\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9201:portable::inverse_mat3\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9202:portable::inverse_mat2\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9203:portable::init_lane_masks\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9204:portable::hue\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9205:portable::hsl_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9206:portable::hardlight\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9207:portable::gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9208:portable::gauss_a_to_rgba\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9209:portable::gather_rgf16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9210:portable::gather_rg88\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9211:portable::gather_rg1616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9212:portable::gather_f32\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9213:portable::gather_f16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9214:portable::gather_af16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9215:portable::gather_a8\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9216:portable::gather_a16\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9217:portable::gather_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9218:portable::gather_565\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9219:portable::gather_4444\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9220:portable::gather_16161616\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9221:portable::gather_10x6\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9222:portable::gather_1010102_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9223:portable::gather_1010102\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9224:portable::gather_10101010_xr\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9225:portable::gamma_\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9226:portable::force_opaque_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9227:portable::force_opaque\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9228:portable::floor_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9229:portable::floor_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9230:portable::floor_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9231:portable::floor_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9232:portable::exp_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9233:portable::exp2_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9234:portable::exclusion\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9235:portable::exchange_src\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9236:portable::evenly_spaced_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9237:portable::evenly_spaced_2_stop_gradient\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9238:portable::emboss\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9239:portable::dstover\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9240:portable::dstout\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9241:portable::dstin\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9242:portable::dstatop\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9243:portable::dot_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9244:portable::dot_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9245:portable::dot_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9246:portable::div_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9247:portable::div_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9248:portable::div_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9249:portable::div_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9250:portable::div_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9251:portable::div_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9252:portable::div_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9253:portable::div_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9254:portable::div_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9255:portable::div_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9256:portable::div_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9257:portable::div_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9258:portable::div_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9259:portable::div_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9260:portable::div_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9261:portable::dither\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9262:portable::difference\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9263:portable::decal_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9264:portable::decal_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9265:portable::decal_x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9266:portable::darken\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9267:portable::css_oklab_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9268:portable::css_oklab_gamut_map_to_linear_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9269:portable::css_lab_to_xyz\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9270:portable::css_hwb_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9271:portable::css_hsl_to_srgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9272:portable::css_hcl_to_lab\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9273:portable::cos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9274:portable::copy_uniform\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9275:portable::copy_to_indirect_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9276:portable::copy_slot_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9277:portable::copy_slot_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9278:portable::copy_immutable_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9279:portable::copy_constant\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9280:portable::copy_4_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9281:portable::copy_4_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9282:portable::copy_4_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9283:portable::copy_4_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9284:portable::copy_3_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9285:portable::copy_3_slots_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9286:portable::copy_3_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9287:portable::copy_3_immutables_unmasked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9288:portable::copy_2_uniforms\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9289:portable::copy_2_slots_masked\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9290:portable::continue_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9291:portable::colordodge\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9292:portable::colorburn\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9293:portable::color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9294:portable::cmpne_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9295:portable::cmpne_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9296:portable::cmpne_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9297:portable::cmpne_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9298:portable::cmpne_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9299:portable::cmpne_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9300:portable::cmpne_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9301:portable::cmpne_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9302:portable::cmpne_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9303:portable::cmpne_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9304:portable::cmpne_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9305:portable::cmpne_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9306:portable::cmplt_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9307:portable::cmplt_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9308:portable::cmplt_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9309:portable::cmplt_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9310:portable::cmplt_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9311:portable::cmplt_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9312:portable::cmplt_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9313:portable::cmplt_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9314:portable::cmplt_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9315:portable::cmplt_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9316:portable::cmplt_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9317:portable::cmplt_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9318:portable::cmplt_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9319:portable::cmplt_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9320:portable::cmplt_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9321:portable::cmplt_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9322:portable::cmplt_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9323:portable::cmplt_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9324:portable::cmple_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9325:portable::cmple_n_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9326:portable::cmple_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9327:portable::cmple_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9328:portable::cmple_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9329:portable::cmple_imm_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9330:portable::cmple_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9331:portable::cmple_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9332:portable::cmple_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9333:portable::cmple_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9334:portable::cmple_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9335:portable::cmple_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9336:portable::cmple_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9337:portable::cmple_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9338:portable::cmple_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9339:portable::cmple_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9340:portable::cmple_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9341:portable::cmple_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9342:portable::cmpeq_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9343:portable::cmpeq_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9344:portable::cmpeq_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9345:portable::cmpeq_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9346:portable::cmpeq_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9347:portable::cmpeq_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9348:portable::cmpeq_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9349:portable::cmpeq_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9350:portable::cmpeq_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9351:portable::cmpeq_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9352:portable::cmpeq_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9353:portable::cmpeq_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9354:portable::clear\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9355:portable::clamp_x_and_y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9356:portable::clamp_x_1\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9357:portable::clamp_gamut\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9358:portable::clamp_a_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9359:portable::clamp_01\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9360:portable::ceil_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9361:portable::ceil_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9362:portable::ceil_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9363:portable::ceil_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9364:portable::cast_to_uint_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9365:portable::cast_to_uint_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9366:portable::cast_to_uint_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9367:portable::cast_to_uint_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9368:portable::cast_to_int_from_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9369:portable::cast_to_int_from_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9370:portable::cast_to_int_from_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9371:portable::cast_to_int_from_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9372:portable::cast_to_float_from_uint\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9373:portable::cast_to_float_from_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9374:portable::cast_to_float_from_4_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9375:portable::cast_to_float_from_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9376:portable::cast_to_float_from_3_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9377:portable::cast_to_float_from_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9378:portable::cast_to_float_from_2_uints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9379:portable::cast_to_float_from_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9380:portable::case_op\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9381:portable::callback\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9382:portable::byte_tables\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9383:portable::bt709_luminance_or_luma_to_rgb\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9384:portable::bt709_luminance_or_luma_to_alpha\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9385:portable::branch_if_no_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9386:portable::branch_if_no_active_lanes_eq\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9387:portable::branch_if_any_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9388:portable::branch_if_all_lanes_active\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9389:portable::blit_row_s32a_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9390:portable::black_color\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9391:portable::bitwise_xor_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9392:portable::bitwise_xor_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9393:portable::bitwise_xor_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9394:portable::bitwise_xor_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9395:portable::bitwise_xor_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9396:portable::bitwise_xor_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9397:portable::bitwise_or_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9398:portable::bitwise_or_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9399:portable::bitwise_or_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9400:portable::bitwise_or_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9401:portable::bitwise_or_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9402:portable::bitwise_and_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9403:portable::bitwise_and_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9404:portable::bitwise_and_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9405:portable::bitwise_and_imm_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9406:portable::bitwise_and_imm_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9407:portable::bitwise_and_imm_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9408:portable::bitwise_and_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9409:portable::bitwise_and_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9410:portable::bitwise_and_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9411:portable::bilinear_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9412:portable::bilinear_py\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9413:portable::bilinear_px\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9414:portable::bilinear_ny\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9415:portable::bilinear_nx\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9416:portable::bilerp_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9417:portable::bicubic_setup\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9418:portable::bicubic_p3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9419:portable::bicubic_p3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9420:portable::bicubic_p1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9421:portable::bicubic_p1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9422:portable::bicubic_n3y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9423:portable::bicubic_n3x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9424:portable::bicubic_n1y\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9425:portable::bicubic_n1x\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9426:portable::bicubic_clamp_8888\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9427:portable::atan_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9428:portable::atan2_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9429:portable::asin_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9430:portable::alter_2pt_conical_unswap\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9431:portable::alter_2pt_conical_compensate_focal\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9432:portable::alpha_to_red_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9433:portable::alpha_to_red\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9434:portable::alpha_to_gray_dst\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9435:portable::alpha_to_gray\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9436:portable::add_n_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9437:portable::add_n_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9438:portable::add_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9439:portable::add_imm_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9440:portable::add_imm_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9441:portable::add_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9442:portable::add_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9443:portable::add_4_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9444:portable::add_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9445:portable::add_3_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9446:portable::add_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9447:portable::add_2_floats\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9448:portable::acos_float\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9449:portable::accumulate\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9450:portable::abs_int\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9451:portable::abs_4_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9452:portable::abs_3_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9453:portable::abs_2_ints\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9454:portable::RGBA_to_rgbA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +9455:portable::RGBA_to_bgrA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +9456:portable::RGBA_to_BGRA\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\29 +9457:portable::PQish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9458:portable::HLGish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9459:portable::HLGinvish\28portable::Params*\2c\20SkRasterPipelineStage*\2c\20float\2c\20float\2c\20float\2c\20float\29 +9460:pop_arg_long_double +9461:png_read_filter_row_up +9462:png_read_filter_row_sub +9463:png_read_filter_row_path_multibyte_pixel +9464:png_read_filter_row_path_1byte_pixel +9465:png_read_filter_row_avg +9466:picture_getCullRect +9467:pictureRecorder_endRecording +9468:pictureRecorder_dispose +9469:pictureRecorder_create +9470:pictureRecorder_beginRecording +9471:path_transform +9472:path_setFillType +9473:path_reset +9474:path_relativeQuadraticBezierTo +9475:path_relativeMoveTo +9476:path_relativeLineTo +9477:path_relativeCubicTo +9478:path_relativeConicTo +9479:path_relativeArcToRotated +9480:path_moveTo +9481:path_lineTo +9482:path_getSvgString +9483:path_getFillType +9484:path_getBounds +9485:path_dispose +9486:path_create +9487:path_copy +9488:path_contains +9489:path_conicTo +9490:path_combine +9491:path_close +9492:path_arcToRotated +9493:path_arcToOval +9494:path_addRect +9495:path_addRRect +9496:path_addPolygon +9497:path_addPath +9498:path_addArc +9499:paragraph_layout +9500:paragraph_getWordBoundary +9501:paragraph_getWidth +9502:paragraph_getUnresolvedCodePoints +9503:paragraph_getPositionForOffset +9504:paragraph_getMinIntrinsicWidth +9505:paragraph_getMaxIntrinsicWidth +9506:paragraph_getLongestLine +9507:paragraph_getLineNumberAt +9508:paragraph_getLineMetricsAtIndex +9509:paragraph_getLineCount +9510:paragraph_getIdeographicBaseline +9511:paragraph_getHeight +9512:paragraph_getGlyphInfoAt +9513:paragraph_getDidExceedMaxLines +9514:paragraph_getClosestGlyphInfoAtCoordinate +9515:paragraph_getBoxesForRange +9516:paragraph_getBoxesForPlaceholders +9517:paragraph_getAlphabeticBaseline +9518:paragraphStyle_setTextStyle +9519:paragraphStyle_setTextHeightBehavior +9520:paragraphStyle_setTextDirection +9521:paragraphStyle_setTextAlign +9522:paragraphStyle_setStrutStyle +9523:paragraphStyle_setMaxLines +9524:paragraphStyle_setHeight +9525:paragraphStyle_setEllipsis +9526:paragraphStyle_setApplyRoundingHack +9527:paragraphStyle_dispose +9528:paragraphStyle_create +9529:paragraphBuilder_setWordBreaksUtf16 +9530:paragraphBuilder_setLineBreaksUtf16 +9531:paragraphBuilder_setGraphemeBreaksUtf16 +9532:paragraphBuilder_pushStyle +9533:paragraphBuilder_pop +9534:paragraphBuilder_getUtf8Text +9535:paragraphBuilder_create +9536:paragraphBuilder_build +9537:paragraphBuilder_addText +9538:paragraphBuilder_addPlaceholder +9539:paint_setShader +9540:paint_setMaskFilter +9541:paint_setImageFilter +9542:paint_setColorFilter +9543:paint_dispose +9544:paint_create +9545:override_features_khmer\28hb_ot_shape_planner_t*\29 +9546:override_features_indic\28hb_ot_shape_planner_t*\29 +9547:override_features_hangul\28hb_ot_shape_planner_t*\29 +9548:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29_14476 +9549:non-virtual\20thunk\20to\20std::__2::basic_stringstream\2c\20std::__2::allocator>::~basic_stringstream\28\29 +9550:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29_14366 +9551:non-virtual\20thunk\20to\20std::__2::basic_iostream>::~basic_iostream\28\29 +9552:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10216 +9553:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10215 +9554:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29_10213 +9555:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::~GaneshBackend\28\29 +9556:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::makeDevice\28SkImageInfo\20const&\29\20const +9557:non-virtual\20thunk\20to\20skif::\28anonymous\20namespace\29::GaneshBackend::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +9558:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29_11113 +9559:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::~SmallPathAtlasMgr\28\29 +9560:non-virtual\20thunk\20to\20skgpu::ganesh::SmallPathAtlasMgr::evict\28skgpu::PlotLocator\29 +9561:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29_10409 +9562:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::~AtlasPathRenderer\28\29 +9563:non-virtual\20thunk\20to\20skgpu::ganesh::AtlasPathRenderer::preFlush\28GrOnFlushResourceProvider*\29 +9564:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +9565:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9566:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +9567:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +9568:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::TransformedMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9569:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29_12146 +9570:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::~SDFTSubRun\28\29 +9571:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9572:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +9573:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::glyphCount\28\29\20const +9574:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::SDFTSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9575:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +9576:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::regenerateAtlas\28int\2c\20int\2c\20std::__2::function\20\28sktext::gpu::GlyphVector*\2c\20int\2c\20int\2c\20skgpu::MaskFormat\2c\20int\29>\29\20const +9577:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::makeAtlasTextOp\28GrClip\20const*\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp&&\2c\20skgpu::ganesh::SurfaceDrawContext*\29\20const +9578:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +9579:non-virtual\20thunk\20to\20\28anonymous\20namespace\29::DirectMaskSubRun::fillVertexData\28void*\2c\20int\2c\20int\2c\20unsigned\20int\2c\20SkMatrix\20const&\2c\20SkPoint\2c\20SkIRect\29\20const +9580:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29_9439 +9581:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::~GrTextureRenderTargetProxy\28\29 +9582:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize\28\29\20const +9583:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::instantiate\28GrResourceProvider*\29 +9584:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::createSurface\28GrResourceProvider*\29\20const +9585:non-virtual\20thunk\20to\20GrTextureRenderTargetProxy::callbackDesc\28\29\20const +9586:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29_9087 +9587:non-virtual\20thunk\20to\20GrOpFlushState::~GrOpFlushState\28\29 +9588:non-virtual\20thunk\20to\20GrOpFlushState::writeView\28\29\20const +9589:non-virtual\20thunk\20to\20GrOpFlushState::usesMSAASurface\28\29\20const +9590:non-virtual\20thunk\20to\20GrOpFlushState::threadSafeCache\28\29\20const +9591:non-virtual\20thunk\20to\20GrOpFlushState::strikeCache\28\29\20const +9592:non-virtual\20thunk\20to\20GrOpFlushState::smallPathAtlasManager\28\29\20const +9593:non-virtual\20thunk\20to\20GrOpFlushState::sampledProxyArray\28\29 +9594:non-virtual\20thunk\20to\20GrOpFlushState::rtProxy\28\29\20const +9595:non-virtual\20thunk\20to\20GrOpFlushState::resourceProvider\28\29\20const +9596:non-virtual\20thunk\20to\20GrOpFlushState::renderPassBarriers\28\29\20const +9597:non-virtual\20thunk\20to\20GrOpFlushState::recordDraw\28GrGeometryProcessor\20const*\2c\20GrSimpleMesh\20const*\2c\20int\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPrimitiveType\29 +9598:non-virtual\20thunk\20to\20GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +9599:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndirectDraws\28int\29 +9600:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndices\28int\29 +9601:non-virtual\20thunk\20to\20GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +9602:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +9603:non-virtual\20thunk\20to\20GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +9604:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +9605:non-virtual\20thunk\20to\20GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +9606:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +9607:non-virtual\20thunk\20to\20GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +9608:non-virtual\20thunk\20to\20GrOpFlushState::dstProxyView\28\29\20const +9609:non-virtual\20thunk\20to\20GrOpFlushState::detachAppliedClip\28\29 +9610:non-virtual\20thunk\20to\20GrOpFlushState::colorLoadOp\28\29\20const +9611:non-virtual\20thunk\20to\20GrOpFlushState::caps\28\29\20const +9612:non-virtual\20thunk\20to\20GrOpFlushState::atlasManager\28\29\20const +9613:non-virtual\20thunk\20to\20GrOpFlushState::appliedClip\28\29\20const +9614:non-virtual\20thunk\20to\20GrGpuBuffer::unref\28\29\20const +9615:non-virtual\20thunk\20to\20GrGpuBuffer::ref\28\29\20const +9616:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29_11882 +9617:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::~GrGLTextureRenderTarget\28\29 +9618:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onSetLabel\28\29 +9619:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onRelease\28\29 +9620:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onGpuMemorySize\28\29\20const +9621:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::onAbandon\28\29 +9622:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +9623:non-virtual\20thunk\20to\20GrGLTextureRenderTarget::backendFormat\28\29\20const +9624:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29_10140 +9625:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +9626:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +9627:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded\28skgpu::BlendEquation\29 +9628:non-virtual\20thunk\20to\20GrGLSLFragmentShaderBuilder::dstColor\28\29 +9629:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29_11513 +9630:non-virtual\20thunk\20to\20GrGLBuffer::~GrGLBuffer\28\29 +9631:maskFilter_createBlur +9632:lineMetrics_getWidth +9633:lineMetrics_getUnscaledAscent +9634:lineMetrics_getLeft +9635:lineMetrics_getHeight +9636:lineMetrics_getDescent +9637:lineMetrics_getBaseline +9638:lineMetrics_getAscent +9639:lineMetrics_dispose +9640:lineMetrics_create +9641:lineBreakBuffer_create +9642:lin_srgb_to_okhcl\28SkRGBA4f<\28SkAlphaType\292>\2c\20bool*\29 +9643:lcd_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +9644:is_deleted_glyph\28hb_glyph_info_t\20const*\29 +9645:initial_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9646:image_getHeight +9647:image_createFromTextureSource +9648:image_createFromPixels +9649:image_createFromPicture +9650:imageFilter_getFilterBounds +9651:imageFilter_createMatrix +9652:imageFilter_createFromColorFilter +9653:imageFilter_createErode +9654:imageFilter_createDilate +9655:imageFilter_createBlur +9656:imageFilter_compose +9657:hit_compare_y\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +9658:hit_compare_x\28SkOpRayHit\20const*\2c\20SkOpRayHit\20const*\29 +9659:hb_unicode_script_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9660:hb_unicode_general_category_nil\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9661:hb_ucd_script\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9662:hb_ucd_mirroring\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9663:hb_ucd_general_category\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9664:hb_ucd_decompose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\2c\20void*\29 +9665:hb_ucd_compose\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9666:hb_ucd_combining_class\28hb_unicode_funcs_t*\2c\20unsigned\20int\2c\20void*\29 +9667:hb_syllabic_clear_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9668:hb_paint_sweep_gradient_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9669:hb_paint_push_transform_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9670:hb_paint_push_clip_rectangle_nil\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9671:hb_paint_image_nil\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +9672:hb_paint_extents_push_transform\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9673:hb_paint_extents_push_group\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +9674:hb_paint_extents_push_clip_rectangle\28hb_paint_funcs_t*\2c\20void*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9675:hb_paint_extents_push_clip_glyph\28hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_font_t*\2c\20void*\29 +9676:hb_paint_extents_pop_transform\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +9677:hb_paint_extents_pop_group\28hb_paint_funcs_t*\2c\20void*\2c\20hb_paint_composite_mode_t\2c\20void*\29 +9678:hb_paint_extents_pop_clip\28hb_paint_funcs_t*\2c\20void*\2c\20void*\29 +9679:hb_paint_extents_paint_sweep_gradient\28hb_paint_funcs_t*\2c\20void*\2c\20hb_color_line_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9680:hb_paint_extents_paint_image\28hb_paint_funcs_t*\2c\20void*\2c\20hb_blob_t*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\2c\20hb_glyph_extents_t*\2c\20void*\29 +9681:hb_paint_extents_paint_color\28hb_paint_funcs_t*\2c\20void*\2c\20int\2c\20unsigned\20int\2c\20void*\29 +9682:hb_outline_recording_pen_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9683:hb_outline_recording_pen_move_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9684:hb_outline_recording_pen_line_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9685:hb_outline_recording_pen_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9686:hb_outline_recording_pen_close_path\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +9687:hb_ot_paint_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9688:hb_ot_map_t::lookup_map_t::cmp\28void\20const*\2c\20void\20const*\29 +9689:hb_ot_map_t::feature_map_t::cmp\28void\20const*\2c\20void\20const*\29 +9690:hb_ot_map_builder_t::feature_info_t::cmp\28void\20const*\2c\20void\20const*\29 +9691:hb_ot_get_variation_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9692:hb_ot_get_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +9693:hb_ot_get_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9694:hb_ot_get_glyph_v_origin\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9695:hb_ot_get_glyph_v_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9696:hb_ot_get_glyph_name\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +9697:hb_ot_get_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9698:hb_ot_get_glyph_from_name\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +9699:hb_ot_get_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9700:hb_ot_get_font_v_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9701:hb_ot_get_font_h_extents\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9702:hb_ot_draw_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +9703:hb_font_paint_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9704:hb_font_paint_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_paint_funcs_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9705:hb_font_get_variation_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9706:hb_font_get_nominal_glyphs_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +9707:hb_font_get_nominal_glyph_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9708:hb_font_get_nominal_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +9709:hb_font_get_glyph_v_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9710:hb_font_get_glyph_v_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9711:hb_font_get_glyph_v_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9712:hb_font_get_glyph_v_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9713:hb_font_get_glyph_v_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9714:hb_font_get_glyph_v_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9715:hb_font_get_glyph_name_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +9716:hb_font_get_glyph_name_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20char*\2c\20unsigned\20int\2c\20void*\29 +9717:hb_font_get_glyph_h_origin_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9718:hb_font_get_glyph_h_origin_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9719:hb_font_get_glyph_h_kerning_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20void*\29 +9720:hb_font_get_glyph_h_advances_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +9721:hb_font_get_glyph_h_advance_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9722:hb_font_get_glyph_h_advance_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +9723:hb_font_get_glyph_from_name_default\28hb_font_t*\2c\20void*\2c\20char\20const*\2c\20int\2c\20unsigned\20int*\2c\20void*\29 +9724:hb_font_get_glyph_extents_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9725:hb_font_get_glyph_extents_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +9726:hb_font_get_glyph_contour_point_nil\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9727:hb_font_get_glyph_contour_point_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20int*\2c\20int*\2c\20void*\29 +9728:hb_font_get_font_v_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9729:hb_font_get_font_h_extents_default\28hb_font_t*\2c\20void*\2c\20hb_font_extents_t*\2c\20void*\29 +9730:hb_font_draw_glyph_default\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_draw_funcs_t*\2c\20void*\2c\20void*\29 +9731:hb_draw_quadratic_to_nil\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9732:hb_draw_quadratic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9733:hb_draw_move_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9734:hb_draw_line_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20void*\29 +9735:hb_draw_extents_quadratic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9736:hb_draw_extents_cubic_to\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9737:hb_draw_cubic_to_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20float\2c\20void*\29 +9738:hb_draw_close_path_default\28hb_draw_funcs_t*\2c\20void*\2c\20hb_draw_state_t*\2c\20void*\29 +9739:hb_buffer_t::_cluster_group_func\28hb_glyph_info_t\20const&\2c\20hb_glyph_info_t\20const&\29 +9740:hb_aat_map_builder_t::feature_event_t::cmp\28void\20const*\2c\20void\20const*\29 +9741:gray_raster_render +9742:gray_raster_new +9743:gray_raster_done +9744:gray_move_to +9745:gray_line_to +9746:gray_cubic_to +9747:gray_conic_to +9748:get_sfnt_table +9749:ft_smooth_transform +9750:ft_smooth_set_mode +9751:ft_smooth_render +9752:ft_smooth_overlap_spans +9753:ft_smooth_lcd_spans +9754:ft_smooth_init +9755:ft_smooth_get_cbox +9756:ft_gzip_free +9757:ft_ansi_stream_io +9758:ft_ansi_stream_close +9759:fquad_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9760:fontCollection_registerTypeface +9761:fontCollection_dispose +9762:fontCollection_create +9763:fontCollection_clearCaches +9764:fmt_fp +9765:fline_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9766:final_reordering_indic\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9767:fcubic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9768:fconic_dxdy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9769:error_callback +9770:emscripten_stack_get_current +9771:dquad_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9772:dline_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9773:dispose_external_texture\28void*\29 +9774:decompose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9775:decompose_khmer\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9776:decompose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int*\29 +9777:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::\28anonymous\20namespace\29::QuadEdgeEffect::Make\28SkArenaAlloc*\2c\20SkMatrix\20const&\2c\20bool\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9778:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\2c\20GrShaderCaps\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::\28anonymous\20namespace\29::HullShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9779:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator::PathStrokeList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9780:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::tess::PatchAttribs&\29::'lambda'\28void*\29>\28skgpu::ganesh::StrokeTessellator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9781:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&>\28SkMatrix\20const&\2c\20SkPath\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28skgpu::ganesh::PathTessellator::PathDrawList&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9782:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29>\28skgpu::ganesh::LatticeOp::\28anonymous\20namespace\29::LatticeGP::Make\28SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20sk_sp\2c\20SkFilterMode\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9783:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::Processor::Make\28SkArenaAlloc*\2c\20GrAAType\2c\20skgpu::ganesh::FillRRectOp::\28anonymous\20namespace\29::FillRRectOpImpl::ProcessorFlags\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9784:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerSkyline&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9785:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28int&\2c\20int&\29::'lambda'\28void*\29>\28skgpu::RectanizerPow2&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9786:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TextureOpImpl::Desc>\28\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TextureOpImpl::Desc&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9787:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::TentPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::TentPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9788:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::SimpleTriangleShader\2c\20SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&>\28SkMatrix\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::SimpleTriangleShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9789:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass*\20SkArenaAlloc::make<\28anonymous\20namespace\29::GaussPass\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&>\28skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20skvx::Vec<4\2c\20unsigned\20int>*&\2c\20int&\2c\20int&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::GaussPass&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9790:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::DrawAtlasPathShader\2c\20bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*\2c\20GrShaderCaps\20const&>\28bool&\2c\20skgpu::ganesh::AtlasInstancedHelper*&&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::DrawAtlasPathShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9791:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader*\20SkArenaAlloc::make<\28anonymous\20namespace\29::BoundingBoxShader\2c\20SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&>\28SkRGBA4f<\28SkAlphaType\292>&\2c\20GrShaderCaps\20const&\29::'lambda'\28void*\29>\28\28anonymous\20namespace\29::BoundingBoxShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9792:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20unsigned\20char&&\29::'lambda'\28void*\29>\28Sprite_D32_S32&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9793:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28bool&&\2c\20bool\20const&\29::'lambda'\28void*\29>\28SkTriColorShader&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9794:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTCubic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9795:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkTConic&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9796:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\29::'lambda'\28void*\29>\28SkSpriteBlitter_Memcpy&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9797:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&>\28SkPixmap\20const&\2c\20SkArenaAlloc*&\2c\20sk_sp&\29::'lambda'\28void*\29>\28SkRasterPipelineSpriteBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9798:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkArenaAlloc*&\29::'lambda'\28void*\29>\28SkRasterPipelineBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9799:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkNullBlitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9800:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkImage_Base\20const*&&\2c\20SkMatrix\20const&\2c\20SkMipmapMode&\29::'lambda'\28void*\29>\28SkMipmapAccessor&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9801:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::PathData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9802:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28SkGlyph::DrawableData&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9803:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make&\29>>::Node*\20SkArenaAlloc::make&\29>>::Node\2c\20std::__2::function&\29>>\28std::__2::function&\29>&&\29::'lambda'\28void*\29>\28SkArenaAllocList&\29>>::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9804:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node\2c\20std::__2::function&\29>\2c\20skgpu::AtlasToken>\28std::__2::function&\29>&&\2c\20skgpu::AtlasToken&&\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9805:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make::Node*\20SkArenaAlloc::make::Node>\28\29::'lambda'\28void*\29>\28SkArenaAllocList::Node&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9806:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPixmap\20const&\2c\20SkPaint\20const&\29::'lambda'\28void*\29>\28SkA8_Coverage_Blitter&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9807:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28\29::'lambda'\28void*\29>\28GrSimpleMesh&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9808:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrSurfaceProxy*&\2c\20skgpu::ScratchKey&&\2c\20GrResourceProvider*&\29::'lambda'\28void*\29>\28GrResourceAllocator::Register&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9809:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28SkPath\20const&\2c\20SkArenaAlloc*\20const&\29::'lambda'\28void*\29>\28GrInnerFanTriangulator&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9810:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrDistanceFieldLCDTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20GrDistanceFieldLCDTextGeoProc::DistanceAdjust\2c\20unsigned\20int\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9811:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29>\28GrBitmapTextGeoProc::Make\28SkArenaAlloc*\2c\20GrShaderCaps\20const&\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20bool\2c\20sk_sp\2c\20GrSurfaceProxyView\20const*\2c\20int\2c\20GrSamplerState\2c\20skgpu::MaskFormat\2c\20SkMatrix\20const&\2c\20bool\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9812:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28GrAppliedClip&&\29::'lambda'\28void*\29>\28GrAppliedClip&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9813:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\28EllipseGeometryProcessor::Make\28SkArenaAlloc*\2c\20bool\2c\20bool\2c\20bool\2c\20SkMatrix\20const&\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9814:decltype\28fp\28nullptr\29\29\20SkArenaAlloc::make\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29>\28DefaultGeoProc::Make\28SkArenaAlloc*\2c\20unsigned\20int\2c\20SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkMatrix\20const&\2c\20SkMatrix\20const&\2c\20bool\2c\20unsigned\20char\29::'lambda'\28void*\29&&\29::'lambda'\28char*\29::__invoke\28char*\29 +9815:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9816:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9817:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul\2c\201ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9818:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +9819:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_construct\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__ctor>&\2c\20std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_constructor\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9820:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&&\29::'lambda'\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&>\28std::__2::__variant_detail::__move_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&&\29 +9821:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>::__generic_assign\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\29::'lambda'\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20auto&&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__copy_assignment\2c\20\28std::__2::__variant_detail::_Trait\291>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9822:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9823:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul\2c\200ul>::__dispatch\5babi:ne180100\5d>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&>\28std::__2::__variant_detail::__visitation::__variant::__value_visitor>>&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>\20const&\29 +9824:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20std::__2::unique_ptr>>\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20sk_sp\2c\20std::__2::unique_ptr>>&\29 +9825:decltype\28auto\29\20std::__2::__variant_detail::__visitation::__base::__dispatcher<0ul>::__dispatch\5babi:ne180100\5d\2c\20\28std::__2::__variant_detail::_Trait\291>::__destroy\5babi:ne180100\5d\28\29::'lambda'\28auto&\29&&\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&>\28auto\2c\20std::__2::__variant_detail::__base<\28std::__2::__variant_detail::_Trait\291\2c\20SkPaint\2c\20int>&\29 +9826:deallocate_buffer_var\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9827:ddquad_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9828:ddquad_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9829:ddline_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9830:ddline_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9831:ddcubic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9832:ddcubic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9833:ddconic_xy_at_t\28SkDCurve\20const&\2c\20double\29 +9834:ddconic_dxdy_at_t\28SkDCurve\20const&\2c\20double\29 +9835:dconic_xy_at_t\28SkPoint\20const*\2c\20float\2c\20double\29 +9836:data_destroy_use\28void*\29 +9837:data_create_use\28hb_ot_shape_plan_t\20const*\29 +9838:data_create_khmer\28hb_ot_shape_plan_t\20const*\29 +9839:data_create_indic\28hb_ot_shape_plan_t\20const*\29 +9840:data_create_hangul\28hb_ot_shape_plan_t\20const*\29 +9841:convert_to_alpha8\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageInfo\20const&\2c\20void\20const*\2c\20unsigned\20long\2c\20SkColorSpaceXformSteps\20const&\29 +9842:convert_bytes_to_data +9843:contourMeasure_length +9844:contourMeasure_isClosed +9845:contourMeasure_getSegment +9846:contourMeasure_getPosTan +9847:contourMeasureIter_next +9848:contourMeasureIter_dispose +9849:contourMeasureIter_create +9850:compose_unicode\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9851:compose_indic\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9852:compose_hebrew\28hb_ot_shape_normalize_context_t\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9853:compare_ppem +9854:compare_myanmar_order\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +9855:compare_combining_class\28hb_glyph_info_t\20const*\2c\20hb_glyph_info_t\20const*\29 +9856:colorFilter_createSRGBToLinearGamma +9857:colorFilter_createMode +9858:colorFilter_createMatrix +9859:colorFilter_createLinearToSRGBGamma +9860:colorFilter_compose +9861:collect_features_use\28hb_ot_shape_planner_t*\29 +9862:collect_features_myanmar\28hb_ot_shape_planner_t*\29 +9863:collect_features_khmer\28hb_ot_shape_planner_t*\29 +9864:collect_features_indic\28hb_ot_shape_planner_t*\29 +9865:collect_features_hangul\28hb_ot_shape_planner_t*\29 +9866:collect_features_arabic\28hb_ot_shape_planner_t*\29 +9867:clip\28SkPath\20const&\2c\20SkHalfPlane\20const&\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +9868:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitStatement\28SkSL::Statement\20const&\29 +9869:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +9870:check_for_passthrough_local_coords_and_dead_varyings\28SkSL::Program\20const&\2c\20unsigned\20int*\29::Visitor::visitExpression\28SkSL::Expression\20const&\29 +9871:cff_slot_init +9872:cff_slot_done +9873:cff_size_request +9874:cff_size_init +9875:cff_size_done +9876:cff_sid_to_glyph_name +9877:cff_set_var_design +9878:cff_set_mm_weightvector +9879:cff_set_mm_blend +9880:cff_set_instance +9881:cff_random +9882:cff_ps_has_glyph_names +9883:cff_ps_get_font_info +9884:cff_ps_get_font_extra +9885:cff_parse_vsindex +9886:cff_parse_private_dict +9887:cff_parse_multiple_master +9888:cff_parse_maxstack +9889:cff_parse_font_matrix +9890:cff_parse_font_bbox +9891:cff_parse_cid_ros +9892:cff_parse_blend +9893:cff_metrics_adjust +9894:cff_hadvance_adjust +9895:cff_get_var_design +9896:cff_get_var_blend +9897:cff_get_standard_encoding +9898:cff_get_ros +9899:cff_get_ps_name +9900:cff_get_name_index +9901:cff_get_mm_weightvector +9902:cff_get_mm_var +9903:cff_get_mm_blend +9904:cff_get_is_cid +9905:cff_get_interface +9906:cff_get_glyph_name +9907:cff_get_cmap_info +9908:cff_get_cid_from_glyph_index +9909:cff_get_advances +9910:cff_free_glyph_data +9911:cff_face_init +9912:cff_face_done +9913:cff_driver_init +9914:cff_done_blend +9915:cff_decoder_prepare +9916:cff_decoder_init +9917:cff_cmap_unicode_init +9918:cff_cmap_unicode_char_next +9919:cff_cmap_unicode_char_index +9920:cff_cmap_encoding_init +9921:cff_cmap_encoding_done +9922:cff_cmap_encoding_char_next +9923:cff_cmap_encoding_char_index +9924:cff_builder_start_point +9925:cf2_free_instance +9926:cf2_decoder_parse_charstrings +9927:cf2_builder_moveTo +9928:cf2_builder_lineTo +9929:cf2_builder_cubeTo +9930:canvas_translate +9931:canvas_transform +9932:canvas_skew +9933:canvas_scale +9934:canvas_saveLayer +9935:canvas_save +9936:canvas_rotate +9937:canvas_restoreToCount +9938:canvas_restore +9939:canvas_getTransform +9940:canvas_getSaveCount +9941:canvas_getLocalClipBounds +9942:canvas_getDeviceClipBounds +9943:canvas_drawVertices +9944:canvas_drawShadow +9945:canvas_drawRect +9946:canvas_drawRRect +9947:canvas_drawPoints +9948:canvas_drawPicture +9949:canvas_drawPath +9950:canvas_drawParagraph +9951:canvas_drawPaint +9952:canvas_drawOval +9953:canvas_drawLine +9954:canvas_drawImageRect +9955:canvas_drawImageNine +9956:canvas_drawImage +9957:canvas_drawDRRect +9958:canvas_drawColor +9959:canvas_drawCircle +9960:canvas_drawAtlas +9961:canvas_drawArc +9962:canvas_clipRect +9963:canvas_clipRRect +9964:canvas_clipPath +9965:bw_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +9966:bw_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9967:bw_pt_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9968:bw_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9969:bw_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +9970:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::SpotVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +9971:bool\20\28anonymous\20namespace\29::FindVisitor<\28anonymous\20namespace\29::AmbientVerticesFactory>\28SkResourceCache::Rec\20const&\2c\20void*\29 +9972:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9973:bool\20OT::hb_accelerate_subtables_context_t::apply_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9974:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9975:bool\20OT::hb_accelerate_subtables_context_t::apply_cached_to>\28void\20const*\2c\20OT::hb_ot_apply_context_t*\29 +9976:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9977:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9978:bool\20OT::cmap::accelerator_t::get_glyph_from_symbol\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9979:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9980:bool\20OT::cmap::accelerator_t::get_glyph_from\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +9981:blur_y_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9982:blur_y_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9983:blur_y_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9984:blur_y_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9985:blur_x_radius_4\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9986:blur_x_radius_3\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9987:blur_x_radius_2\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9988:blur_x_radius_1\28skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>\20const&\2c\20skvx::Vec<8\2c\20unsigned\20short>*\2c\20skvx::Vec<8\2c\20unsigned\20short>*\29 +9989:blit_row_s32a_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9990:blit_row_s32_opaque\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9991:blit_row_s32_blend\28unsigned\20int*\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int\29 +9992:argb32_to_a8\28unsigned\20char*\2c\20unsigned\20char\20const*\2c\20int\29 +9993:arabic_fallback_shape\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +9994:afm_parser_parse +9995:afm_parser_init +9996:afm_parser_done +9997:afm_compare_kern_pairs +9998:af_property_set +9999:af_property_get +10000:af_latin_metrics_scale +10001:af_latin_metrics_init +10002:af_latin_hints_init +10003:af_latin_hints_apply +10004:af_latin_get_standard_widths +10005:af_indic_metrics_scale +10006:af_indic_metrics_init +10007:af_indic_hints_init +10008:af_indic_hints_apply +10009:af_get_interface +10010:af_face_globals_free +10011:af_dummy_hints_init +10012:af_dummy_hints_apply +10013:af_cjk_metrics_init +10014:af_autofitter_load_glyph +10015:af_autofitter_init +10016:action_terminate +10017:action_abort +10018:aa_square_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10019:aa_poly_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10020:aa_line_hair_proc\28PtProcRec\20const&\2c\20SkPoint\20const*\2c\20int\2c\20SkBlitter*\29 +10021:_hb_ot_font_destroy\28void*\29 +10022:_hb_glyph_info_is_default_ignorable\28hb_glyph_info_t\20const*\29 +10023:_hb_face_for_data_reference_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +10024:_hb_face_for_data_closure_destroy\28void*\29 +10025:_hb_clear_substitution_flags\28hb_ot_shape_plan_t\20const*\2c\20hb_font_t*\2c\20hb_buffer_t*\29 +10026:_hb_blob_destroy\28void*\29 +10027:_emscripten_stack_restore +10028:_emscripten_stack_alloc +10029:__wasm_init_memory +10030:__wasm_call_ctors +10031:__stdio_write +10032:__stdio_seek +10033:__stdio_read +10034:__stdio_close +10035:__fe_getround +10036:__emscripten_stdout_seek +10037:__cxxabiv1::__vmi_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10038:__cxxabiv1::__vmi_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10039:__cxxabiv1::__vmi_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +10040:__cxxabiv1::__si_class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10041:__cxxabiv1::__si_class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10042:__cxxabiv1::__si_class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +10043:__cxxabiv1::__class_type_info::search_below_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10044:__cxxabiv1::__class_type_info::search_above_dst\28__cxxabiv1::__dynamic_cast_info*\2c\20void\20const*\2c\20void\20const*\2c\20int\2c\20bool\29\20const +10045:__cxxabiv1::__class_type_info::has_unambiguous_public_base\28__cxxabiv1::__dynamic_cast_info*\2c\20void*\2c\20int\29\20const +10046:__cxxabiv1::__class_type_info::can_catch\28__cxxabiv1::__shim_type_info\20const*\2c\20void*&\29\20const +10047:\28anonymous\20namespace\29::skhb_nominal_glyphs\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20unsigned\20int\2c\20void*\29 +10048:\28anonymous\20namespace\29::skhb_nominal_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +10049:\28anonymous\20namespace\29::skhb_glyph_h_advances\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\20const*\2c\20unsigned\20int\2c\20int*\2c\20unsigned\20int\2c\20void*\29 +10050:\28anonymous\20namespace\29::skhb_glyph_h_advance\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20void*\29 +10051:\28anonymous\20namespace\29::skhb_glyph_extents\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20hb_glyph_extents_t*\2c\20void*\29 +10052:\28anonymous\20namespace\29::skhb_glyph\28hb_font_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20void*\29 +10053:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29::$_0::__invoke\28void*\29 +10054:\28anonymous\20namespace\29::skhb_get_table\28hb_face_t*\2c\20unsigned\20int\2c\20void*\29 +10055:\28anonymous\20namespace\29::make_morphology\28\28anonymous\20namespace\29::MorphType\2c\20SkSize\2c\20sk_sp\2c\20SkImageFilters::CropRect\20const&\29 +10056:\28anonymous\20namespace\29::create_sub_hb_font\28SkFont\20const&\2c\20std::__2::unique_ptr>\20const&\29::$_0::__invoke\28void*\29 +10057:\28anonymous\20namespace\29::YUVPlanesRec::~YUVPlanesRec\28\29_4322 +10058:\28anonymous\20namespace\29::YUVPlanesRec::getCategory\28\29\20const +10059:\28anonymous\20namespace\29::YUVPlanesRec::diagnostic_only_getDiscardable\28\29\20const +10060:\28anonymous\20namespace\29::YUVPlanesRec::bytesUsed\28\29\20const +10061:\28anonymous\20namespace\29::YUVPlanesRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +10062:\28anonymous\20namespace\29::UniqueKeyInvalidator::~UniqueKeyInvalidator\28\29_11280 +10063:\28anonymous\20namespace\29::TriangulatingPathOp::~TriangulatingPathOp\28\29_11258 +10064:\28anonymous\20namespace\29::TriangulatingPathOp::visitProxies\28std::__2::function\20const&\29\20const +10065:\28anonymous\20namespace\29::TriangulatingPathOp::programInfo\28\29 +10066:\28anonymous\20namespace\29::TriangulatingPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10067:\28anonymous\20namespace\29::TriangulatingPathOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10068:\28anonymous\20namespace\29::TriangulatingPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10069:\28anonymous\20namespace\29::TriangulatingPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10070:\28anonymous\20namespace\29::TriangulatingPathOp::name\28\29\20const +10071:\28anonymous\20namespace\29::TriangulatingPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10072:\28anonymous\20namespace\29::TransformedMaskSubRun::unflattenSize\28\29\20const +10073:\28anonymous\20namespace\29::TransformedMaskSubRun::instanceFlags\28\29\20const +10074:\28anonymous\20namespace\29::TransformedMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10075:\28anonymous\20namespace\29::TransformedMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +10076:\28anonymous\20namespace\29::TransformedMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +10077:\28anonymous\20namespace\29::TextureOpImpl::~TextureOpImpl\28\29_11232 +10078:\28anonymous\20namespace\29::TextureOpImpl::visitProxies\28std::__2::function\20const&\29\20const +10079:\28anonymous\20namespace\29::TextureOpImpl::programInfo\28\29 +10080:\28anonymous\20namespace\29::TextureOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +10081:\28anonymous\20namespace\29::TextureOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10082:\28anonymous\20namespace\29::TextureOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10083:\28anonymous\20namespace\29::TextureOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10084:\28anonymous\20namespace\29::TextureOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10085:\28anonymous\20namespace\29::TextureOpImpl::name\28\29\20const +10086:\28anonymous\20namespace\29::TextureOpImpl::fixedFunctionFlags\28\29\20const +10087:\28anonymous\20namespace\29::TextureOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10088:\28anonymous\20namespace\29::TentPass::startBlur\28\29 +10089:\28anonymous\20namespace\29::TentPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +10090:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +10091:\28anonymous\20namespace\29::TentPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +10092:\28anonymous\20namespace\29::StaticVertexAllocator::~StaticVertexAllocator\28\29_11284 +10093:\28anonymous\20namespace\29::StaticVertexAllocator::unlock\28int\29 +10094:\28anonymous\20namespace\29::StaticVertexAllocator::lock\28unsigned\20long\2c\20int\29 +10095:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::currentScript\28\29\20const +10096:\28anonymous\20namespace\29::SkUnicodeHbScriptRunIterator::consume\28\29 +10097:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10098:\28anonymous\20namespace\29::SkMorphologyImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10099:\28anonymous\20namespace\29::SkMorphologyImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10100:\28anonymous\20namespace\29::SkMorphologyImageFilter::getTypeName\28\29\20const +10101:\28anonymous\20namespace\29::SkMorphologyImageFilter::flatten\28SkWriteBuffer&\29\20const +10102:\28anonymous\20namespace\29::SkMorphologyImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10103:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10104:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10105:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10106:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::getTypeName\28\29\20const +10107:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::flatten\28SkWriteBuffer&\29\20const +10108:\28anonymous\20namespace\29::SkMatrixTransformImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10109:\28anonymous\20namespace\29::SkFTGeometrySink::Quad\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +10110:\28anonymous\20namespace\29::SkFTGeometrySink::Move\28FT_Vector_\20const*\2c\20void*\29 +10111:\28anonymous\20namespace\29::SkFTGeometrySink::Line\28FT_Vector_\20const*\2c\20void*\29 +10112:\28anonymous\20namespace\29::SkFTGeometrySink::Cubic\28FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20FT_Vector_\20const*\2c\20void*\29 +10113:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +10114:\28anonymous\20namespace\29::SkEmptyTypeface::onGetFamilyName\28SkString*\29\20const +10115:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +10116:\28anonymous\20namespace\29::SkEmptyTypeface::onCreateFamilyNameIterator\28\29\20const +10117:\28anonymous\20namespace\29::SkEmptyTypeface::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +10118:\28anonymous\20namespace\29::SkCropImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10119:\28anonymous\20namespace\29::SkCropImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10120:\28anonymous\20namespace\29::SkCropImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10121:\28anonymous\20namespace\29::SkCropImageFilter::onAffectsTransparentBlack\28\29\20const +10122:\28anonymous\20namespace\29::SkCropImageFilter::getTypeName\28\29\20const +10123:\28anonymous\20namespace\29::SkCropImageFilter::flatten\28SkWriteBuffer&\29\20const +10124:\28anonymous\20namespace\29::SkCropImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10125:\28anonymous\20namespace\29::SkComposeImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10126:\28anonymous\20namespace\29::SkComposeImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10127:\28anonymous\20namespace\29::SkComposeImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10128:\28anonymous\20namespace\29::SkComposeImageFilter::getTypeName\28\29\20const +10129:\28anonymous\20namespace\29::SkComposeImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10130:\28anonymous\20namespace\29::SkColorFilterImageFilter::~SkColorFilterImageFilter\28\29_5373 +10131:\28anonymous\20namespace\29::SkColorFilterImageFilter::onIsColorFilterNode\28SkColorFilter**\29\20const +10132:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10133:\28anonymous\20namespace\29::SkColorFilterImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10134:\28anonymous\20namespace\29::SkColorFilterImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10135:\28anonymous\20namespace\29::SkColorFilterImageFilter::onAffectsTransparentBlack\28\29\20const +10136:\28anonymous\20namespace\29::SkColorFilterImageFilter::getTypeName\28\29\20const +10137:\28anonymous\20namespace\29::SkColorFilterImageFilter::flatten\28SkWriteBuffer&\29\20const +10138:\28anonymous\20namespace\29::SkColorFilterImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10139:\28anonymous\20namespace\29::SkBlurImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10140:\28anonymous\20namespace\29::SkBlurImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10141:\28anonymous\20namespace\29::SkBlurImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10142:\28anonymous\20namespace\29::SkBlurImageFilter::getTypeName\28\29\20const +10143:\28anonymous\20namespace\29::SkBlurImageFilter::flatten\28SkWriteBuffer&\29\20const +10144:\28anonymous\20namespace\29::SkBlurImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10145:\28anonymous\20namespace\29::SkBlendImageFilter::~SkBlendImageFilter\28\29_5345 +10146:\28anonymous\20namespace\29::SkBlendImageFilter::onGetOutputLayerBounds\28skif::Mapping\20const&\2c\20std::__2::optional>\29\20const +10147:\28anonymous\20namespace\29::SkBlendImageFilter::onGetInputLayerBounds\28skif::Mapping\20const&\2c\20skif::LayerSpace\20const&\2c\20std::__2::optional>\29\20const +10148:\28anonymous\20namespace\29::SkBlendImageFilter::onFilterImage\28skif::Context\20const&\29\20const +10149:\28anonymous\20namespace\29::SkBlendImageFilter::onAffectsTransparentBlack\28\29\20const +10150:\28anonymous\20namespace\29::SkBlendImageFilter::getTypeName\28\29\20const +10151:\28anonymous\20namespace\29::SkBlendImageFilter::flatten\28SkWriteBuffer&\29\20const +10152:\28anonymous\20namespace\29::SkBlendImageFilter::computeFastBounds\28SkRect\20const&\29\20const +10153:\28anonymous\20namespace\29::SkBidiIterator_icu::~SkBidiIterator_icu\28\29_7487 +10154:\28anonymous\20namespace\29::SkBidiIterator_icu::getLevelAt\28int\29 +10155:\28anonymous\20namespace\29::SkBidiIterator_icu::getLength\28\29 +10156:\28anonymous\20namespace\29::SimpleTriangleShader::name\28\29\20const +10157:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10158:\28anonymous\20namespace\29::SimpleTriangleShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10159:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10160:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::FontRunIterator&\2c\20SkShaper::BiDiRunIterator&\2c\20SkShaper::ScriptRunIterator&\2c\20SkShaper::LanguageRunIterator&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10161:\28anonymous\20namespace\29::ShaperHarfBuzz::shape\28char\20const*\2c\20unsigned\20long\2c\20SkFont\20const&\2c\20bool\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10162:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::~ShapeDontWrapOrReorder\28\29 +10163:\28anonymous\20namespace\29::ShapeDontWrapOrReorder::wrap\28char\20const*\2c\20unsigned\20long\2c\20SkShaper::BiDiRunIterator\20const&\2c\20SkShaper::LanguageRunIterator\20const&\2c\20SkShaper::ScriptRunIterator\20const&\2c\20SkShaper::FontRunIterator\20const&\2c\20\28anonymous\20namespace\29::RunIteratorQueue&\2c\20SkShaper::Feature\20const*\2c\20unsigned\20long\2c\20float\2c\20SkShaper::RunHandler*\29\20const +10164:\28anonymous\20namespace\29::ShadowInvalidator::~ShadowInvalidator\28\29_5188 +10165:\28anonymous\20namespace\29::ShadowInvalidator::changed\28\29 +10166:\28anonymous\20namespace\29::ShadowCircularRRectOp::~ShadowCircularRRectOp\28\29_11092 +10167:\28anonymous\20namespace\29::ShadowCircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +10168:\28anonymous\20namespace\29::ShadowCircularRRectOp::programInfo\28\29 +10169:\28anonymous\20namespace\29::ShadowCircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10170:\28anonymous\20namespace\29::ShadowCircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10171:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10172:\28anonymous\20namespace\29::ShadowCircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10173:\28anonymous\20namespace\29::ShadowCircularRRectOp::name\28\29\20const +10174:\28anonymous\20namespace\29::ShadowCircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10175:\28anonymous\20namespace\29::SDFTSubRun::vertexStride\28SkMatrix\20const&\29\20const +10176:\28anonymous\20namespace\29::SDFTSubRun::vertexFiller\28\29\20const +10177:\28anonymous\20namespace\29::SDFTSubRun::unflattenSize\28\29\20const +10178:\28anonymous\20namespace\29::SDFTSubRun::testingOnly_packedGlyphIDToGlyph\28sktext::gpu::StrikeCache*\29\20const +10179:\28anonymous\20namespace\29::SDFTSubRun::glyphs\28\29\20const +10180:\28anonymous\20namespace\29::SDFTSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10181:\28anonymous\20namespace\29::SDFTSubRun::doFlatten\28SkWriteBuffer&\29\20const +10182:\28anonymous\20namespace\29::SDFTSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +10183:\28anonymous\20namespace\29::RectsBlurRec::~RectsBlurRec\28\29_2564 +10184:\28anonymous\20namespace\29::RectsBlurRec::getCategory\28\29\20const +10185:\28anonymous\20namespace\29::RectsBlurRec::diagnostic_only_getDiscardable\28\29\20const +10186:\28anonymous\20namespace\29::RectsBlurRec::bytesUsed\28\29\20const +10187:\28anonymous\20namespace\29::RectsBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +10188:\28anonymous\20namespace\29::RasterShaderBlurAlgorithm::makeDevice\28SkImageInfo\20const&\29\20const +10189:\28anonymous\20namespace\29::RasterBlurEngine::findAlgorithm\28SkSize\2c\20SkColorType\29\20const +10190:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::maxSigma\28\29\20const +10191:\28anonymous\20namespace\29::Raster8888BlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +10192:\28anonymous\20namespace\29::RRectBlurRec::~RRectBlurRec\28\29_2558 +10193:\28anonymous\20namespace\29::RRectBlurRec::getCategory\28\29\20const +10194:\28anonymous\20namespace\29::RRectBlurRec::diagnostic_only_getDiscardable\28\29\20const +10195:\28anonymous\20namespace\29::RRectBlurRec::bytesUsed\28\29\20const +10196:\28anonymous\20namespace\29::RRectBlurRec::Visitor\28SkResourceCache::Rec\20const&\2c\20void*\29 +10197:\28anonymous\20namespace\29::PathSubRun::~PathSubRun\28\29_12079 +10198:\28anonymous\20namespace\29::PathSubRun::unflattenSize\28\29\20const +10199:\28anonymous\20namespace\29::PathSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10200:\28anonymous\20namespace\29::PathSubRun::doFlatten\28SkWriteBuffer&\29\20const +10201:\28anonymous\20namespace\29::MipMapRec::~MipMapRec\28\29_1249 +10202:\28anonymous\20namespace\29::MipMapRec::getCategory\28\29\20const +10203:\28anonymous\20namespace\29::MipMapRec::diagnostic_only_getDiscardable\28\29\20const +10204:\28anonymous\20namespace\29::MipMapRec::bytesUsed\28\29\20const +10205:\28anonymous\20namespace\29::MipMapRec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +10206:\28anonymous\20namespace\29::MiddleOutShader::~MiddleOutShader\28\29_11308 +10207:\28anonymous\20namespace\29::MiddleOutShader::name\28\29\20const +10208:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::emitVertexCode\28GrShaderCaps\20const&\2c\20GrPathTessellationShader\20const&\2c\20GrGLSLVertexBuilder*\2c\20GrGLSLVaryingHandler*\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10209:\28anonymous\20namespace\29::MiddleOutShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10210:\28anonymous\20namespace\29::MiddleOutShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10211:\28anonymous\20namespace\29::MeshOp::~MeshOp\28\29_10633 +10212:\28anonymous\20namespace\29::MeshOp::visitProxies\28std::__2::function\20const&\29\20const +10213:\28anonymous\20namespace\29::MeshOp::programInfo\28\29 +10214:\28anonymous\20namespace\29::MeshOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10215:\28anonymous\20namespace\29::MeshOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10216:\28anonymous\20namespace\29::MeshOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10217:\28anonymous\20namespace\29::MeshOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10218:\28anonymous\20namespace\29::MeshOp::name\28\29\20const +10219:\28anonymous\20namespace\29::MeshOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10220:\28anonymous\20namespace\29::MeshGP::~MeshGP\28\29_10657 +10221:\28anonymous\20namespace\29::MeshGP::onTextureSampler\28int\29\20const +10222:\28anonymous\20namespace\29::MeshGP::name\28\29\20const +10223:\28anonymous\20namespace\29::MeshGP::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10224:\28anonymous\20namespace\29::MeshGP::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10225:\28anonymous\20namespace\29::MeshGP::Impl::~Impl\28\29_10663 +10226:\28anonymous\20namespace\29::MeshGP::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10227:\28anonymous\20namespace\29::MeshGP::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10228:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10229:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10230:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10231:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +10232:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::getMainName\28\29 +10233:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +10234:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +10235:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +10236:\28anonymous\20namespace\29::MeshGP::Impl::MeshCallbacks::declareFunction\28char\20const*\29 +10237:\28anonymous\20namespace\29::HQDownSampler::buildLevel\28SkPixmap\20const&\2c\20SkPixmap\20const&\29 +10238:\28anonymous\20namespace\29::GaussPass::startBlur\28\29 +10239:\28anonymous\20namespace\29::GaussPass::blurSegment\28int\2c\20unsigned\20int\20const*\2c\20int\2c\20unsigned\20int*\2c\20int\29 +10240:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::makePass\28void*\2c\20SkArenaAlloc*\29\20const +10241:\28anonymous\20namespace\29::GaussPass::MakeMaker\28float\2c\20SkArenaAlloc*\29::Maker::bufferSizeBytes\28\29\20const +10242:\28anonymous\20namespace\29::FillRectOpImpl::~FillRectOpImpl\28\29_10753 +10243:\28anonymous\20namespace\29::FillRectOpImpl::visitProxies\28std::__2::function\20const&\29\20const +10244:\28anonymous\20namespace\29::FillRectOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +10245:\28anonymous\20namespace\29::FillRectOpImpl::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10246:\28anonymous\20namespace\29::FillRectOpImpl::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10247:\28anonymous\20namespace\29::FillRectOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10248:\28anonymous\20namespace\29::FillRectOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10249:\28anonymous\20namespace\29::FillRectOpImpl::name\28\29\20const +10250:\28anonymous\20namespace\29::FillRectOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10251:\28anonymous\20namespace\29::ExternalWebGLTexture::~ExternalWebGLTexture\28\29_517 +10252:\28anonymous\20namespace\29::ExternalWebGLTexture::getBackendTexture\28\29 +10253:\28anonymous\20namespace\29::ExternalWebGLTexture::dispose\28\29 +10254:\28anonymous\20namespace\29::EllipticalRRectEffect::onMakeProgramImpl\28\29\20const +10255:\28anonymous\20namespace\29::EllipticalRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10256:\28anonymous\20namespace\29::EllipticalRRectEffect::name\28\29\20const +10257:\28anonymous\20namespace\29::EllipticalRRectEffect::clone\28\29\20const +10258:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10259:\28anonymous\20namespace\29::EllipticalRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10260:\28anonymous\20namespace\29::DrawableSubRun::~DrawableSubRun\28\29_12087 +10261:\28anonymous\20namespace\29::DrawableSubRun::unflattenSize\28\29\20const +10262:\28anonymous\20namespace\29::DrawableSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10263:\28anonymous\20namespace\29::DrawableSubRun::doFlatten\28SkWriteBuffer&\29\20const +10264:\28anonymous\20namespace\29::DrawAtlasPathShader::~DrawAtlasPathShader\28\29_10604 +10265:\28anonymous\20namespace\29::DrawAtlasPathShader::onTextureSampler\28int\29\20const +10266:\28anonymous\20namespace\29::DrawAtlasPathShader::name\28\29\20const +10267:\28anonymous\20namespace\29::DrawAtlasPathShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10268:\28anonymous\20namespace\29::DrawAtlasPathShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10269:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10270:\28anonymous\20namespace\29::DrawAtlasPathShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10271:\28anonymous\20namespace\29::DrawAtlasOpImpl::~DrawAtlasOpImpl\28\29_10581 +10272:\28anonymous\20namespace\29::DrawAtlasOpImpl::onPrepareDraws\28GrMeshDrawTarget*\29 +10273:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10274:\28anonymous\20namespace\29::DrawAtlasOpImpl::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10275:\28anonymous\20namespace\29::DrawAtlasOpImpl::name\28\29\20const +10276:\28anonymous\20namespace\29::DrawAtlasOpImpl::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10277:\28anonymous\20namespace\29::DirectMaskSubRun::vertexStride\28SkMatrix\20const&\29\20const +10278:\28anonymous\20namespace\29::DirectMaskSubRun::unflattenSize\28\29\20const +10279:\28anonymous\20namespace\29::DirectMaskSubRun::instanceFlags\28\29\20const +10280:\28anonymous\20namespace\29::DirectMaskSubRun::draw\28SkCanvas*\2c\20SkPoint\2c\20SkPaint\20const&\2c\20sk_sp\2c\20std::__2::function\2c\20sktext::gpu::RendererData\29>\20const&\29\20const +10281:\28anonymous\20namespace\29::DirectMaskSubRun::doFlatten\28SkWriteBuffer&\29\20const +10282:\28anonymous\20namespace\29::DirectMaskSubRun::canReuse\28SkPaint\20const&\2c\20SkMatrix\20const&\29\20const +10283:\28anonymous\20namespace\29::DefaultPathOp::~DefaultPathOp\28\29_10557 +10284:\28anonymous\20namespace\29::DefaultPathOp::visitProxies\28std::__2::function\20const&\29\20const +10285:\28anonymous\20namespace\29::DefaultPathOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10286:\28anonymous\20namespace\29::DefaultPathOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10287:\28anonymous\20namespace\29::DefaultPathOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10288:\28anonymous\20namespace\29::DefaultPathOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10289:\28anonymous\20namespace\29::DefaultPathOp::name\28\29\20const +10290:\28anonymous\20namespace\29::DefaultPathOp::fixedFunctionFlags\28\29\20const +10291:\28anonymous\20namespace\29::DefaultPathOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10292:\28anonymous\20namespace\29::CircularRRectEffect::onMakeProgramImpl\28\29\20const +10293:\28anonymous\20namespace\29::CircularRRectEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +10294:\28anonymous\20namespace\29::CircularRRectEffect::name\28\29\20const +10295:\28anonymous\20namespace\29::CircularRRectEffect::clone\28\29\20const +10296:\28anonymous\20namespace\29::CircularRRectEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +10297:\28anonymous\20namespace\29::CircularRRectEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +10298:\28anonymous\20namespace\29::CachedTessellationsRec::~CachedTessellationsRec\28\29_5192 +10299:\28anonymous\20namespace\29::CachedTessellationsRec::getCategory\28\29\20const +10300:\28anonymous\20namespace\29::CachedTessellationsRec::bytesUsed\28\29\20const +10301:\28anonymous\20namespace\29::CachedTessellations::~CachedTessellations\28\29_5198 +10302:\28anonymous\20namespace\29::CacheImpl::~CacheImpl\28\29_2422 +10303:\28anonymous\20namespace\29::CacheImpl::set\28SkImageFilterCacheKey\20const&\2c\20SkImageFilter\20const*\2c\20skif::FilterResult\20const&\29 +10304:\28anonymous\20namespace\29::CacheImpl::purge\28\29 +10305:\28anonymous\20namespace\29::CacheImpl::purgeByImageFilter\28SkImageFilter\20const*\29 +10306:\28anonymous\20namespace\29::CacheImpl::get\28SkImageFilterCacheKey\20const&\2c\20skif::FilterResult*\29\20const +10307:\28anonymous\20namespace\29::BoundingBoxShader::name\28\29\20const +10308:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +10309:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +10310:\28anonymous\20namespace\29::BoundingBoxShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +10311:\28anonymous\20namespace\29::AAHairlineOp::~AAHairlineOp\28\29_10337 +10312:\28anonymous\20namespace\29::AAHairlineOp::visitProxies\28std::__2::function\20const&\29\20const +10313:\28anonymous\20namespace\29::AAHairlineOp::onPrepareDraws\28GrMeshDrawTarget*\29 +10314:\28anonymous\20namespace\29::AAHairlineOp::onPrePrepareDraws\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10315:\28anonymous\20namespace\29::AAHairlineOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +10316:\28anonymous\20namespace\29::AAHairlineOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +10317:\28anonymous\20namespace\29::AAHairlineOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +10318:\28anonymous\20namespace\29::AAHairlineOp::name\28\29\20const +10319:\28anonymous\20namespace\29::AAHairlineOp::fixedFunctionFlags\28\29\20const +10320:\28anonymous\20namespace\29::AAHairlineOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +10321:Write_CVT_Stretched +10322:Write_CVT +10323:Vertish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +10324:Vertish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +10325:VertState::Triangles\28VertState*\29 +10326:VertState::TrianglesX\28VertState*\29 +10327:VertState::TriangleStrip\28VertState*\29 +10328:VertState::TriangleStripX\28VertState*\29 +10329:VertState::TriangleFan\28VertState*\29 +10330:VertState::TriangleFanX\28VertState*\29 +10331:VLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +10332:VLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +10333:TextureSourceImageGenerator::~TextureSourceImageGenerator\28\29_498 +10334:TextureSourceImageGenerator::generateExternalTexture\28GrRecordingContext*\2c\20skgpu::Mipmapped\29 +10335:TT_Set_MM_Blend +10336:TT_RunIns +10337:TT_Load_Simple_Glyph +10338:TT_Load_Glyph_Header +10339:TT_Load_Composite_Glyph +10340:TT_Get_Var_Design +10341:TT_Get_MM_Blend +10342:TT_Forget_Glyph_Frame +10343:TT_Access_Glyph_Frame +10344:TOUPPER\28unsigned\20char\29 +10345:TOLOWER\28unsigned\20char\29 +10346:SquareCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +10347:Sprite_D32_S32::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10348:SkWeakRefCnt::internal_dispose\28\29\20const +10349:SkUnicode_client::~SkUnicode_client\28\29_7527 +10350:SkUnicode_client::toUpper\28SkString\20const&\2c\20char\20const*\29 +10351:SkUnicode_client::toUpper\28SkString\20const&\29 +10352:SkUnicode_client::reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29 +10353:SkUnicode_client::makeBreakIterator\28char\20const*\2c\20SkUnicode::BreakType\29 +10354:SkUnicode_client::makeBreakIterator\28SkUnicode::BreakType\29 +10355:SkUnicode_client::makeBidiIterator\28unsigned\20short\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +10356:SkUnicode_client::makeBidiIterator\28char\20const*\2c\20int\2c\20SkBidiIterator::Direction\29 +10357:SkUnicode_client::getWords\28char\20const*\2c\20int\2c\20char\20const*\2c\20std::__2::vector>*\29 +10358:SkUnicode_client::getBidiRegions\28char\20const*\2c\20int\2c\20SkUnicode::TextDirection\2c\20std::__2::vector>*\29 +10359:SkUnicode_client::computeCodeUnitFlags\28char16_t*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +10360:SkUnicode_client::computeCodeUnitFlags\28char*\2c\20int\2c\20bool\2c\20skia_private::TArray*\29 +10361:SkUnicodeHardCodedCharProperties::isWhitespace\28int\29 +10362:SkUnicodeHardCodedCharProperties::isTabulation\28int\29 +10363:SkUnicodeHardCodedCharProperties::isSpace\28int\29 +10364:SkUnicodeHardCodedCharProperties::isIdeographic\28int\29 +10365:SkUnicodeHardCodedCharProperties::isHardBreak\28int\29 +10366:SkUnicodeHardCodedCharProperties::isControl\28int\29 +10367:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29_12274 +10368:SkUnicodeBidiRunIterator::~SkUnicodeBidiRunIterator\28\29 +10369:SkUnicodeBidiRunIterator::endOfCurrentRun\28\29\20const +10370:SkUnicodeBidiRunIterator::currentLevel\28\29\20const +10371:SkUnicodeBidiRunIterator::consume\28\29 +10372:SkUnicodeBidiRunIterator::atEnd\28\29\20const +10373:SkTypeface_FreeTypeStream::~SkTypeface_FreeTypeStream\28\29_7685 +10374:SkTypeface_FreeTypeStream::onOpenStream\28int*\29\20const +10375:SkTypeface_FreeTypeStream::onMakeFontData\28\29\20const +10376:SkTypeface_FreeTypeStream::onMakeClone\28SkFontArguments\20const&\29\20const +10377:SkTypeface_FreeTypeStream::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +10378:SkTypeface_FreeType::onGlyphMaskNeedsCurrentColor\28\29\20const +10379:SkTypeface_FreeType::onGetVariationDesignPosition\28SkFontArguments::VariationPosition::Coordinate*\2c\20int\29\20const +10380:SkTypeface_FreeType::onGetVariationDesignParameters\28SkFontParameters::Variation::Axis*\2c\20int\29\20const +10381:SkTypeface_FreeType::onGetUPEM\28\29\20const +10382:SkTypeface_FreeType::onGetTableTags\28unsigned\20int*\29\20const +10383:SkTypeface_FreeType::onGetTableData\28unsigned\20int\2c\20unsigned\20long\2c\20unsigned\20long\2c\20void*\29\20const +10384:SkTypeface_FreeType::onGetPostScriptName\28SkString*\29\20const +10385:SkTypeface_FreeType::onGetKerningPairAdjustments\28unsigned\20short\20const*\2c\20int\2c\20int*\29\20const +10386:SkTypeface_FreeType::onGetAdvancedMetrics\28\29\20const +10387:SkTypeface_FreeType::onFilterRec\28SkScalerContextRec*\29\20const +10388:SkTypeface_FreeType::onCreateScalerContext\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29\20const +10389:SkTypeface_FreeType::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +10390:SkTypeface_FreeType::onCreateFamilyNameIterator\28\29\20const +10391:SkTypeface_FreeType::onCountGlyphs\28\29\20const +10392:SkTypeface_FreeType::onCopyTableData\28unsigned\20int\29\20const +10393:SkTypeface_FreeType::onCharsToGlyphs\28int\20const*\2c\20int\2c\20unsigned\20short*\29\20const +10394:SkTypeface_FreeType::getPostScriptGlyphNames\28SkString*\29\20const +10395:SkTypeface_FreeType::getGlyphToUnicodeMap\28int*\29\20const +10396:SkTypeface_Empty::~SkTypeface_Empty\28\29 +10397:SkTypeface_Custom::onGetFontDescriptor\28SkFontDescriptor*\2c\20bool*\29\20const +10398:SkTypeface::onOpenExistingStream\28int*\29\20const +10399:SkTypeface::onCreateScalerContextAsProxyTypeface\28SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\2c\20sk_sp\29\20const +10400:SkTypeface::onCopyTableData\28unsigned\20int\29\20const +10401:SkTypeface::onComputeBounds\28SkRect*\29\20const +10402:SkTriColorShader::type\28\29\20const +10403:SkTriColorShader::isOpaque\28\29\20const +10404:SkTriColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10405:SkTransformShader::type\28\29\20const +10406:SkTransformShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10407:SkTQuad::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +10408:SkTQuad::setBounds\28SkDRect*\29\20const +10409:SkTQuad::ptAtT\28double\29\20const +10410:SkTQuad::make\28SkArenaAlloc&\29\20const +10411:SkTQuad::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +10412:SkTQuad::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +10413:SkTQuad::dxdyAtT\28double\29\20const +10414:SkTQuad::debugInit\28\29 +10415:SkTMaskGamma<3\2c\203\2c\203>::~SkTMaskGamma\28\29_3899 +10416:SkTCubic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +10417:SkTCubic::setBounds\28SkDRect*\29\20const +10418:SkTCubic::ptAtT\28double\29\20const +10419:SkTCubic::otherPts\28int\2c\20SkDPoint\20const**\29\20const +10420:SkTCubic::maxIntersections\28\29\20const +10421:SkTCubic::make\28SkArenaAlloc&\29\20const +10422:SkTCubic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +10423:SkTCubic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +10424:SkTCubic::hullIntersects\28SkDCubic\20const&\2c\20bool*\29\20const +10425:SkTCubic::dxdyAtT\28double\29\20const +10426:SkTCubic::debugInit\28\29 +10427:SkTCubic::controlsInside\28\29\20const +10428:SkTCubic::collapsed\28\29\20const +10429:SkTConic::subDivide\28double\2c\20double\2c\20SkTCurve*\29\20const +10430:SkTConic::setBounds\28SkDRect*\29\20const +10431:SkTConic::ptAtT\28double\29\20const +10432:SkTConic::make\28SkArenaAlloc&\29\20const +10433:SkTConic::intersectRay\28SkIntersections*\2c\20SkDLine\20const&\29\20const +10434:SkTConic::hullIntersects\28SkTCurve\20const&\2c\20bool*\29\20const +10435:SkTConic::hullIntersects\28SkDQuad\20const&\2c\20bool*\29\20const +10436:SkTConic::dxdyAtT\28double\29\20const +10437:SkTConic::debugInit\28\29 +10438:SkSweepGradient::getTypeName\28\29\20const +10439:SkSweepGradient::flatten\28SkWriteBuffer&\29\20const +10440:SkSweepGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10441:SkSweepGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +10442:SkSurface_Raster::~SkSurface_Raster\28\29_4446 +10443:SkSurface_Raster::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +10444:SkSurface_Raster::onRestoreBackingMutability\28\29 +10445:SkSurface_Raster::onNewSurface\28SkImageInfo\20const&\29 +10446:SkSurface_Raster::onNewImageSnapshot\28SkIRect\20const*\29 +10447:SkSurface_Raster::onNewCanvas\28\29 +10448:SkSurface_Raster::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10449:SkSurface_Raster::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +10450:SkSurface_Raster::imageInfo\28\29\20const +10451:SkSurface_Ganesh::~SkSurface_Ganesh\28\29_11286 +10452:SkSurface_Ganesh::replaceBackendTexture\28GrBackendTexture\20const&\2c\20GrSurfaceOrigin\2c\20SkSurface::ContentChangeMode\2c\20void\20\28*\29\28void*\29\2c\20void*\29 +10453:SkSurface_Ganesh::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +10454:SkSurface_Ganesh::onWait\28int\2c\20GrBackendSemaphore\20const*\2c\20bool\29 +10455:SkSurface_Ganesh::onNewSurface\28SkImageInfo\20const&\29 +10456:SkSurface_Ganesh::onNewImageSnapshot\28SkIRect\20const*\29 +10457:SkSurface_Ganesh::onNewCanvas\28\29 +10458:SkSurface_Ganesh::onIsCompatible\28GrSurfaceCharacterization\20const&\29\20const +10459:SkSurface_Ganesh::onGetRecordingContext\28\29\20const +10460:SkSurface_Ganesh::onDraw\28SkCanvas*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10461:SkSurface_Ganesh::onCopyOnWrite\28SkSurface::ContentChangeMode\29 +10462:SkSurface_Ganesh::onCharacterize\28GrSurfaceCharacterization*\29\20const +10463:SkSurface_Ganesh::onCapabilities\28\29 +10464:SkSurface_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10465:SkSurface_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10466:SkSurface_Ganesh::imageInfo\28\29\20const +10467:SkSurface_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29 +10468:SkSurface::imageInfo\28\29\20const +10469:SkStrikeCache::~SkStrikeCache\28\29_4120 +10470:SkStrikeCache::findOrCreateScopedStrike\28SkStrikeSpec\20const&\29 +10471:SkStrike::~SkStrike\28\29_4105 +10472:SkStrike::strikePromise\28\29 +10473:SkStrike::roundingSpec\28\29\20const +10474:SkStrike::getDescriptor\28\29\20const +10475:SkSpriteBlitter_Memcpy::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10476:SkSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +10477:SkSpriteBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10478:SkSpriteBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10479:SkSpriteBlitter::blitH\28int\2c\20int\2c\20int\29 +10480:SkSpecialImage_Raster::~SkSpecialImage_Raster\28\29_4040 +10481:SkSpecialImage_Raster::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +10482:SkSpecialImage_Raster::getSize\28\29\20const +10483:SkSpecialImage_Raster::backingStoreDimensions\28\29\20const +10484:SkSpecialImage_Raster::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +10485:SkSpecialImage_Raster::asImage\28\29\20const +10486:SkSpecialImage_Gpu::~SkSpecialImage_Gpu\28\29_10259 +10487:SkSpecialImage_Gpu::onMakeBackingStoreSubset\28SkIRect\20const&\29\20const +10488:SkSpecialImage_Gpu::getSize\28\29\20const +10489:SkSpecialImage_Gpu::backingStoreDimensions\28\29\20const +10490:SkSpecialImage_Gpu::asImage\28\29\20const +10491:SkSpecialImage::asShader\28SkTileMode\2c\20SkSamplingOptions\20const&\2c\20SkMatrix\20const&\2c\20bool\29\20const +10492:SkShaper::TrivialLanguageRunIterator::~TrivialLanguageRunIterator\28\29_12267 +10493:SkShaper::TrivialLanguageRunIterator::currentLanguage\28\29\20const +10494:SkShaper::TrivialFontRunIterator::~TrivialFontRunIterator\28\29_6996 +10495:SkShaper::TrivialBiDiRunIterator::currentLevel\28\29\20const +10496:SkShaderBlurAlgorithm::maxSigma\28\29\20const +10497:SkShaderBlurAlgorithm::blur\28SkSize\2c\20sk_sp\2c\20SkIRect\20const&\2c\20SkTileMode\2c\20SkIRect\20const&\29\20const +10498:SkScan::HairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10499:SkScan::HairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10500:SkScan::HairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10501:SkScan::AntiHairSquarePath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10502:SkScan::AntiHairRoundPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10503:SkScan::AntiHairPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10504:SkScan::AntiFillPath\28SkPath\20const&\2c\20SkRasterClip\20const&\2c\20SkBlitter*\29 +10505:SkScalerContext_FreeType::~SkScalerContext_FreeType\28\29_7621 +10506:SkScalerContext_FreeType::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +10507:SkScalerContext_FreeType::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +10508:SkScalerContext_FreeType::generateImage\28SkGlyph\20const&\2c\20void*\29 +10509:SkScalerContext_FreeType::generateFontMetrics\28SkFontMetrics*\29 +10510:SkScalerContext_FreeType::generateDrawable\28SkGlyph\20const&\29 +10511:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::~SkScalerContext_Empty\28\29 +10512:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generatePath\28SkGlyph\20const&\2c\20SkPath*\2c\20bool*\29 +10513:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateMetrics\28SkGlyph\20const&\2c\20SkArenaAlloc*\29 +10514:SkScalerContext::MakeEmpty\28sk_sp\2c\20SkScalerContextEffects\20const&\2c\20SkDescriptor\20const*\29::SkScalerContext_Empty::generateFontMetrics\28SkFontMetrics*\29 +10515:SkSRGBColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +10516:SkSRGBColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +10517:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_3::__invoke\28double\2c\20double\29 +10518:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_2::__invoke\28double\2c\20double\29 +10519:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_1::__invoke\28double\2c\20double\29 +10520:SkSL::simplify_componentwise\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::Expression\20const&\2c\20SkSL::Operator\2c\20SkSL::Expression\20const&\29::$_0::__invoke\28double\2c\20double\29 +10521:SkSL::negate_value\28double\29 +10522:SkSL::eliminate_unreachable_code\28SkSpan>>\2c\20SkSL::ProgramUsage*\29::UnreachableCodeEliminator::~UnreachableCodeEliminator\28\29_6814 +10523:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::~DeadLocalVariableEliminator\28\29_6811 +10524:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitStatementPtr\28std::__2::unique_ptr>&\29 +10525:SkSL::eliminate_dead_local_variables\28SkSL::Context\20const&\2c\20SkSpan>>\2c\20SkSL::ProgramUsage*\29::DeadLocalVariableEliminator::visitExpressionPtr\28std::__2::unique_ptr>&\29 +10526:SkSL::count_returns_at_end_of_control_flow\28SkSL::FunctionDefinition\20const&\29::CountReturnsAtEndOfControlFlow::visitStatement\28SkSL::Statement\20const&\29 +10527:SkSL::bitwise_not_value\28double\29 +10528:SkSL::\28anonymous\20namespace\29::VariableWriteVisitor::visitExpression\28SkSL::Expression\20const&\29 +10529:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10530:SkSL::\28anonymous\20namespace\29::SampleOutsideMainVisitor::visitExpression\28SkSL::Expression\20const&\29 +10531:SkSL::\28anonymous\20namespace\29::ReturnsNonOpaqueColorVisitor::visitStatement\28SkSL::Statement\20const&\29 +10532:SkSL::\28anonymous\20namespace\29::ReturnsInputAlphaVisitor::visitStatement\28SkSL::Statement\20const&\29 +10533:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10534:SkSL::\28anonymous\20namespace\29::NodeCountVisitor::visitExpression\28SkSL::Expression\20const&\29 +10535:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitProgramElement\28SkSL::ProgramElement\20const&\29 +10536:SkSL::\28anonymous\20namespace\29::MergeSampleUsageVisitor::visitExpression\28SkSL::Expression\20const&\29 +10537:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::~FinalizationVisitor\28\29_5976 +10538:SkSL::\28anonymous\20namespace\29::FinalizationVisitor::visitExpression\28SkSL::Expression\20const&\29 +10539:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::~ES2IndexingVisitor\28\29_5999 +10540:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitStatement\28SkSL::Statement\20const&\29 +10541:SkSL::\28anonymous\20namespace\29::ES2IndexingVisitor::visitExpression\28SkSL::Expression\20const&\29 +10542:SkSL::VectorType::isOrContainsBool\28\29\20const +10543:SkSL::VectorType::isAllowedInUniform\28SkSL::Position*\29\20const +10544:SkSL::VectorType::isAllowedInES2\28\29\20const +10545:SkSL::VariableReference::clone\28SkSL::Position\29\20const +10546:SkSL::Variable::~Variable\28\29_6779 +10547:SkSL::Variable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +10548:SkSL::Variable::mangledName\28\29\20const +10549:SkSL::Variable::layout\28\29\20const +10550:SkSL::Variable::description\28\29\20const +10551:SkSL::VarDeclaration::~VarDeclaration\28\29_6777 +10552:SkSL::VarDeclaration::description\28\29\20const +10553:SkSL::TypeReference::clone\28SkSL::Position\29\20const +10554:SkSL::Type::minimumValue\28\29\20const +10555:SkSL::Type::maximumValue\28\29\20const +10556:SkSL::Type::matches\28SkSL::Type\20const&\29\20const +10557:SkSL::Type::isAllowedInUniform\28SkSL::Position*\29\20const +10558:SkSL::Type::fields\28\29\20const +10559:SkSL::Type::description\28\29\20const +10560:SkSL::Transform::HoistSwitchVarDeclarationsAtTopLevel\28SkSL::Context\20const&\2c\20skia_private::STArray<2\2c\20std::__2::unique_ptr>\2c\20true>&\2c\20SkSL::SymbolTable&\2c\20SkSL::Position\29::HoistSwitchVarDeclsVisitor::~HoistSwitchVarDeclsVisitor\28\29_6828 +10561:SkSL::Tracer::var\28int\2c\20int\29 +10562:SkSL::Tracer::scope\28int\29 +10563:SkSL::Tracer::line\28int\29 +10564:SkSL::Tracer::exit\28int\29 +10565:SkSL::Tracer::enter\28int\29 +10566:SkSL::TextureType::textureAccess\28\29\20const +10567:SkSL::TextureType::isMultisampled\28\29\20const +10568:SkSL::TextureType::isDepth\28\29\20const +10569:SkSL::TernaryExpression::~TernaryExpression\28\29_6592 +10570:SkSL::TernaryExpression::description\28SkSL::OperatorPrecedence\29\20const +10571:SkSL::TernaryExpression::clone\28SkSL::Position\29\20const +10572:SkSL::TProgramVisitor::visitExpression\28SkSL::Expression&\29 +10573:SkSL::Swizzle::description\28SkSL::OperatorPrecedence\29\20const +10574:SkSL::Swizzle::clone\28SkSL::Position\29\20const +10575:SkSL::SwitchStatement::description\28\29\20const +10576:SkSL::SwitchCase::description\28\29\20const +10577:SkSL::StructType::slotType\28unsigned\20long\29\20const +10578:SkSL::StructType::isOrContainsUnsizedArray\28\29\20const +10579:SkSL::StructType::isOrContainsBool\28\29\20const +10580:SkSL::StructType::isOrContainsAtomic\28\29\20const +10581:SkSL::StructType::isOrContainsArray\28\29\20const +10582:SkSL::StructType::isInterfaceBlock\28\29\20const +10583:SkSL::StructType::isBuiltin\28\29\20const +10584:SkSL::StructType::isAllowedInUniform\28SkSL::Position*\29\20const +10585:SkSL::StructType::isAllowedInES2\28\29\20const +10586:SkSL::StructType::fields\28\29\20const +10587:SkSL::StructDefinition::description\28\29\20const +10588:SkSL::StringStream::~StringStream\28\29_12199 +10589:SkSL::StringStream::write\28void\20const*\2c\20unsigned\20long\29 +10590:SkSL::StringStream::writeText\28char\20const*\29 +10591:SkSL::StringStream::write8\28unsigned\20char\29 +10592:SkSL::Setting::description\28SkSL::OperatorPrecedence\29\20const +10593:SkSL::Setting::clone\28SkSL::Position\29\20const +10594:SkSL::ScalarType::priority\28\29\20const +10595:SkSL::ScalarType::numberKind\28\29\20const +10596:SkSL::ScalarType::minimumValue\28\29\20const +10597:SkSL::ScalarType::maximumValue\28\29\20const +10598:SkSL::ScalarType::isOrContainsBool\28\29\20const +10599:SkSL::ScalarType::isAllowedInUniform\28SkSL::Position*\29\20const +10600:SkSL::ScalarType::isAllowedInES2\28\29\20const +10601:SkSL::ScalarType::bitWidth\28\29\20const +10602:SkSL::SamplerType::textureAccess\28\29\20const +10603:SkSL::SamplerType::isMultisampled\28\29\20const +10604:SkSL::SamplerType::isDepth\28\29\20const +10605:SkSL::SamplerType::isArrayedTexture\28\29\20const +10606:SkSL::SamplerType::dimensions\28\29\20const +10607:SkSL::ReturnStatement::description\28\29\20const +10608:SkSL::RP::VariableLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10609:SkSL::RP::VariableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10610:SkSL::RP::VariableLValue::isWritable\28\29\20const +10611:SkSL::RP::UnownedLValueSlice::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10612:SkSL::RP::UnownedLValueSlice::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10613:SkSL::RP::UnownedLValueSlice::fixedSlotRange\28SkSL::RP::Generator*\29 +10614:SkSL::RP::SwizzleLValue::~SwizzleLValue\28\29_6270 +10615:SkSL::RP::SwizzleLValue::swizzle\28\29 +10616:SkSL::RP::SwizzleLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10617:SkSL::RP::SwizzleLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10618:SkSL::RP::SwizzleLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10619:SkSL::RP::ScratchLValue::~ScratchLValue\28\29_6164 +10620:SkSL::RP::ScratchLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10621:SkSL::RP::ScratchLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10622:SkSL::RP::LValueSlice::~LValueSlice\28\29_6268 +10623:SkSL::RP::ImmutableLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10624:SkSL::RP::DynamicIndexLValue::~DynamicIndexLValue\28\29_6262 +10625:SkSL::RP::DynamicIndexLValue::store\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10626:SkSL::RP::DynamicIndexLValue::push\28SkSL::RP::Generator*\2c\20SkSL::RP::SlotRange\2c\20SkSL::RP::AutoStack*\2c\20SkSpan\29 +10627:SkSL::RP::DynamicIndexLValue::isWritable\28\29\20const +10628:SkSL::RP::DynamicIndexLValue::fixedSlotRange\28SkSL::RP::Generator*\29 +10629:SkSL::ProgramVisitor::visitStatementPtr\28std::__2::unique_ptr>\20const&\29 +10630:SkSL::ProgramVisitor::visitExpressionPtr\28std::__2::unique_ptr>\20const&\29 +10631:SkSL::PrefixExpression::~PrefixExpression\28\29_6552 +10632:SkSL::PrefixExpression::~PrefixExpression\28\29 +10633:SkSL::PrefixExpression::description\28SkSL::OperatorPrecedence\29\20const +10634:SkSL::PrefixExpression::clone\28SkSL::Position\29\20const +10635:SkSL::PostfixExpression::description\28SkSL::OperatorPrecedence\29\20const +10636:SkSL::PostfixExpression::clone\28SkSL::Position\29\20const +10637:SkSL::Poison::description\28SkSL::OperatorPrecedence\29\20const +10638:SkSL::Poison::clone\28SkSL::Position\29\20const +10639:SkSL::PipelineStage::Callbacks::getMainName\28\29 +10640:SkSL::Parser::Checkpoint::ForwardingErrorReporter::~ForwardingErrorReporter\28\29_5927 +10641:SkSL::Parser::Checkpoint::ForwardingErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +10642:SkSL::Nop::description\28\29\20const +10643:SkSL::ModifiersDeclaration::description\28\29\20const +10644:SkSL::MethodReference::description\28SkSL::OperatorPrecedence\29\20const +10645:SkSL::MethodReference::clone\28SkSL::Position\29\20const +10646:SkSL::MatrixType::slotCount\28\29\20const +10647:SkSL::MatrixType::rows\28\29\20const +10648:SkSL::MatrixType::isAllowedInES2\28\29\20const +10649:SkSL::LiteralType::minimumValue\28\29\20const +10650:SkSL::LiteralType::maximumValue\28\29\20const +10651:SkSL::LiteralType::isOrContainsBool\28\29\20const +10652:SkSL::Literal::getConstantValue\28int\29\20const +10653:SkSL::Literal::description\28SkSL::OperatorPrecedence\29\20const +10654:SkSL::Literal::compareConstant\28SkSL::Expression\20const&\29\20const +10655:SkSL::Literal::clone\28SkSL::Position\29\20const +10656:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_uintBitsToFloat\28double\2c\20double\2c\20double\29 +10657:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_trunc\28double\2c\20double\2c\20double\29 +10658:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tanh\28double\2c\20double\2c\20double\29 +10659:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_tan\28double\2c\20double\2c\20double\29 +10660:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sub\28double\2c\20double\2c\20double\29 +10661:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_step\28double\2c\20double\2c\20double\29 +10662:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sqrt\28double\2c\20double\2c\20double\29 +10663:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_smoothstep\28double\2c\20double\2c\20double\29 +10664:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sinh\28double\2c\20double\2c\20double\29 +10665:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sin\28double\2c\20double\2c\20double\29 +10666:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_sign\28double\2c\20double\2c\20double\29 +10667:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_saturate\28double\2c\20double\2c\20double\29 +10668:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_round\28double\2c\20double\2c\20double\29 +10669:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_radians\28double\2c\20double\2c\20double\29 +10670:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_pow\28double\2c\20double\2c\20double\29 +10671:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_opposite_sign\28double\2c\20double\2c\20double\29 +10672:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_not\28double\2c\20double\2c\20double\29 +10673:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mod\28double\2c\20double\2c\20double\29 +10674:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_mix\28double\2c\20double\2c\20double\29 +10675:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_min\28double\2c\20double\2c\20double\29 +10676:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_max\28double\2c\20double\2c\20double\29 +10677:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log\28double\2c\20double\2c\20double\29 +10678:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_log2\28double\2c\20double\2c\20double\29 +10679:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_inversesqrt\28double\2c\20double\2c\20double\29 +10680:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_intBitsToFloat\28double\2c\20double\2c\20double\29 +10681:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fract\28double\2c\20double\2c\20double\29 +10682:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_fma\28double\2c\20double\2c\20double\29 +10683:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floor\28double\2c\20double\2c\20double\29 +10684:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToUint\28double\2c\20double\2c\20double\29 +10685:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_floatBitsToInt\28double\2c\20double\2c\20double\29 +10686:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp\28double\2c\20double\2c\20double\29 +10687:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_exp2\28double\2c\20double\2c\20double\29 +10688:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_div\28double\2c\20double\2c\20double\29 +10689:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_degrees\28double\2c\20double\2c\20double\29 +10690:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cosh\28double\2c\20double\2c\20double\29 +10691:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_cos\28double\2c\20double\2c\20double\29 +10692:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_clamp\28double\2c\20double\2c\20double\29 +10693:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_ceil\28double\2c\20double\2c\20double\29 +10694:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atanh\28double\2c\20double\2c\20double\29 +10695:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan\28double\2c\20double\2c\20double\29 +10696:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_atan2\28double\2c\20double\2c\20double\29 +10697:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asinh\28double\2c\20double\2c\20double\29 +10698:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_asin\28double\2c\20double\2c\20double\29 +10699:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_add\28double\2c\20double\2c\20double\29 +10700:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acosh\28double\2c\20double\2c\20double\29 +10701:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_acos\28double\2c\20double\2c\20double\29 +10702:SkSL::Intrinsics::\28anonymous\20namespace\29::evaluate_abs\28double\2c\20double\2c\20double\29 +10703:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_notEqual\28double\2c\20double\29 +10704:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThan\28double\2c\20double\29 +10705:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_lessThanEqual\28double\2c\20double\29 +10706:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThan\28double\2c\20double\29 +10707:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_greaterThanEqual\28double\2c\20double\29 +10708:SkSL::Intrinsics::\28anonymous\20namespace\29::compare_equal\28double\2c\20double\29 +10709:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_length\28double\2c\20double\2c\20double\29 +10710:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_dot\28double\2c\20double\2c\20double\29 +10711:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_distance\28double\2c\20double\2c\20double\29 +10712:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_any\28double\2c\20double\2c\20double\29 +10713:SkSL::Intrinsics::\28anonymous\20namespace\29::coalesce_all\28double\2c\20double\2c\20double\29 +10714:SkSL::InterfaceBlock::~InterfaceBlock\28\29_6526 +10715:SkSL::InterfaceBlock::~InterfaceBlock\28\29 +10716:SkSL::InterfaceBlock::description\28\29\20const +10717:SkSL::IndexExpression::~IndexExpression\28\29_6522 +10718:SkSL::IndexExpression::description\28SkSL::OperatorPrecedence\29\20const +10719:SkSL::IndexExpression::clone\28SkSL::Position\29\20const +10720:SkSL::IfStatement::~IfStatement\28\29_6520 +10721:SkSL::IfStatement::description\28\29\20const +10722:SkSL::GlobalVarDeclaration::description\28\29\20const +10723:SkSL::GenericType::slotType\28unsigned\20long\29\20const +10724:SkSL::GenericType::coercibleTypes\28\29\20const +10725:SkSL::GLSLCodeGenerator::~GLSLCodeGenerator\28\29_12256 +10726:SkSL::FunctionReference::description\28SkSL::OperatorPrecedence\29\20const +10727:SkSL::FunctionReference::clone\28SkSL::Position\29\20const +10728:SkSL::FunctionPrototype::description\28\29\20const +10729:SkSL::FunctionDefinition::description\28\29\20const +10730:SkSL::FunctionDefinition::Convert\28SkSL::Context\20const&\2c\20SkSL::Position\2c\20SkSL::FunctionDeclaration\20const&\2c\20std::__2::unique_ptr>\29::Finalizer::~Finalizer\28\29_6515 +10731:SkSL::FunctionCall::description\28SkSL::OperatorPrecedence\29\20const +10732:SkSL::FunctionCall::clone\28SkSL::Position\29\20const +10733:SkSL::ForStatement::~ForStatement\28\29_6392 +10734:SkSL::ForStatement::description\28\29\20const +10735:SkSL::FieldSymbol::description\28\29\20const +10736:SkSL::FieldAccess::clone\28SkSL::Position\29\20const +10737:SkSL::Extension::description\28\29\20const +10738:SkSL::ExtendedVariable::~ExtendedVariable\28\29_6787 +10739:SkSL::ExtendedVariable::setInterfaceBlock\28SkSL::InterfaceBlock*\29 +10740:SkSL::ExtendedVariable::mangledName\28\29\20const +10741:SkSL::ExtendedVariable::layout\28\29\20const +10742:SkSL::ExtendedVariable::interfaceBlock\28\29\20const +10743:SkSL::ExtendedVariable::detachDeadInterfaceBlock\28\29 +10744:SkSL::ExpressionStatement::description\28\29\20const +10745:SkSL::Expression::getConstantValue\28int\29\20const +10746:SkSL::Expression::description\28\29\20const +10747:SkSL::EmptyExpression::description\28SkSL::OperatorPrecedence\29\20const +10748:SkSL::EmptyExpression::clone\28SkSL::Position\29\20const +10749:SkSL::DoStatement::description\28\29\20const +10750:SkSL::DiscardStatement::description\28\29\20const +10751:SkSL::DebugTracePriv::~DebugTracePriv\28\29_6798 +10752:SkSL::DebugTracePriv::dump\28SkWStream*\29\20const +10753:SkSL::CountReturnsWithLimit::visitStatement\28SkSL::Statement\20const&\29 +10754:SkSL::ContinueStatement::description\28\29\20const +10755:SkSL::ConstructorStruct::clone\28SkSL::Position\29\20const +10756:SkSL::ConstructorSplat::getConstantValue\28int\29\20const +10757:SkSL::ConstructorSplat::clone\28SkSL::Position\29\20const +10758:SkSL::ConstructorScalarCast::clone\28SkSL::Position\29\20const +10759:SkSL::ConstructorMatrixResize::getConstantValue\28int\29\20const +10760:SkSL::ConstructorMatrixResize::clone\28SkSL::Position\29\20const +10761:SkSL::ConstructorDiagonalMatrix::getConstantValue\28int\29\20const +10762:SkSL::ConstructorDiagonalMatrix::clone\28SkSL::Position\29\20const +10763:SkSL::ConstructorCompoundCast::clone\28SkSL::Position\29\20const +10764:SkSL::ConstructorCompound::clone\28SkSL::Position\29\20const +10765:SkSL::ConstructorArrayCast::clone\28SkSL::Position\29\20const +10766:SkSL::ConstructorArray::clone\28SkSL::Position\29\20const +10767:SkSL::Compiler::CompilerErrorReporter::handleError\28std::__2::basic_string_view>\2c\20SkSL::Position\29 +10768:SkSL::CodeGenerator::~CodeGenerator\28\29 +10769:SkSL::ChildCall::description\28SkSL::OperatorPrecedence\29\20const +10770:SkSL::ChildCall::clone\28SkSL::Position\29\20const +10771:SkSL::BreakStatement::description\28\29\20const +10772:SkSL::Block::~Block\28\29_6302 +10773:SkSL::Block::description\28\29\20const +10774:SkSL::BinaryExpression::~BinaryExpression\28\29_6296 +10775:SkSL::BinaryExpression::description\28SkSL::OperatorPrecedence\29\20const +10776:SkSL::BinaryExpression::clone\28SkSL::Position\29\20const +10777:SkSL::ArrayType::slotType\28unsigned\20long\29\20const +10778:SkSL::ArrayType::slotCount\28\29\20const +10779:SkSL::ArrayType::matches\28SkSL::Type\20const&\29\20const +10780:SkSL::ArrayType::isUnsizedArray\28\29\20const +10781:SkSL::ArrayType::isOrContainsUnsizedArray\28\29\20const +10782:SkSL::ArrayType::isBuiltin\28\29\20const +10783:SkSL::ArrayType::isAllowedInUniform\28SkSL::Position*\29\20const +10784:SkSL::AnyConstructor::getConstantValue\28int\29\20const +10785:SkSL::AnyConstructor::description\28SkSL::OperatorPrecedence\29\20const +10786:SkSL::AnyConstructor::compareConstant\28SkSL::Expression\20const&\29\20const +10787:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::~Searcher\28\29_6047 +10788:SkSL::Analysis::FindFunctionsToSpecialize\28SkSL::Program\20const&\2c\20SkSL::Analysis::SpecializationInfo*\2c\20std::__2::function\20const&\29::Searcher::visitExpression\28SkSL::Expression\20const&\29 +10789:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::~ProgramStructureVisitor\28\29_5970 +10790:SkSL::Analysis::CheckProgramStructure\28SkSL::Program\20const&\29::ProgramStructureVisitor::visitExpression\28SkSL::Expression\20const&\29 +10791:SkSL::AliasType::textureAccess\28\29\20const +10792:SkSL::AliasType::slotType\28unsigned\20long\29\20const +10793:SkSL::AliasType::slotCount\28\29\20const +10794:SkSL::AliasType::rows\28\29\20const +10795:SkSL::AliasType::priority\28\29\20const +10796:SkSL::AliasType::isVector\28\29\20const +10797:SkSL::AliasType::isUnsizedArray\28\29\20const +10798:SkSL::AliasType::isStruct\28\29\20const +10799:SkSL::AliasType::isScalar\28\29\20const +10800:SkSL::AliasType::isMultisampled\28\29\20const +10801:SkSL::AliasType::isMatrix\28\29\20const +10802:SkSL::AliasType::isLiteral\28\29\20const +10803:SkSL::AliasType::isInterfaceBlock\28\29\20const +10804:SkSL::AliasType::isDepth\28\29\20const +10805:SkSL::AliasType::isArrayedTexture\28\29\20const +10806:SkSL::AliasType::isArray\28\29\20const +10807:SkSL::AliasType::dimensions\28\29\20const +10808:SkSL::AliasType::componentType\28\29\20const +10809:SkSL::AliasType::columns\28\29\20const +10810:SkSL::AliasType::coercibleTypes\28\29\20const +10811:SkRuntimeShader::~SkRuntimeShader\28\29_4548 +10812:SkRuntimeShader::type\28\29\20const +10813:SkRuntimeShader::isOpaque\28\29\20const +10814:SkRuntimeShader::getTypeName\28\29\20const +10815:SkRuntimeShader::flatten\28SkWriteBuffer&\29\20const +10816:SkRuntimeShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +10817:SkRuntimeEffect::~SkRuntimeEffect\28\29_3882 +10818:SkRuntimeEffect::MakeFromSource\28SkString\2c\20SkRuntimeEffect::Options\20const&\2c\20SkSL::ProgramKind\29 +10819:SkRuntimeEffect::MakeForColorFilter\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +10820:SkRuntimeEffect::MakeForBlender\28SkString\2c\20SkRuntimeEffect::Options\20const&\29 +10821:SkRgnClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10822:SkRgnClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10823:SkRgnClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10824:SkRgnClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10825:SkRgnClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10826:SkRgnClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10827:SkRgnBuilder::~SkRgnBuilder\28\29_3819 +10828:SkRgnBuilder::blitH\28int\2c\20int\2c\20int\29 +10829:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::~Result\28\29_4422 +10830:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::rowBytes\28int\29\20const +10831:SkRescaleAndReadPixels\28SkBitmap\2c\20SkImageInfo\20const&\2c\20SkIRect\20const&\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29::Result::data\28int\29\20const +10832:SkRectClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10833:SkRectClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10834:SkRectClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +10835:SkRectClipBlitter::blitH\28int\2c\20int\2c\20int\29 +10836:SkRectClipBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +10837:SkRectClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10838:SkRecorder::~SkRecorder\28\29_3741 +10839:SkRecorder::willSave\28\29 +10840:SkRecorder::onResetClip\28\29 +10841:SkRecorder::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10842:SkRecorder::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10843:SkRecorder::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +10844:SkRecorder::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10845:SkRecorder::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10846:SkRecorder::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10847:SkRecorder::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10848:SkRecorder::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +10849:SkRecorder::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +10850:SkRecorder::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10851:SkRecorder::onDrawPaint\28SkPaint\20const&\29 +10852:SkRecorder::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10853:SkRecorder::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +10854:SkRecorder::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10855:SkRecorder::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +10856:SkRecorder::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10857:SkRecorder::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +10858:SkRecorder::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10859:SkRecorder::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10860:SkRecorder::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +10861:SkRecorder::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10862:SkRecorder::onDrawBehind\28SkPaint\20const&\29 +10863:SkRecorder::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +10864:SkRecorder::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +10865:SkRecorder::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +10866:SkRecorder::onDoSaveBehind\28SkRect\20const*\29 +10867:SkRecorder::onClipShader\28sk_sp\2c\20SkClipOp\29 +10868:SkRecorder::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10869:SkRecorder::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10870:SkRecorder::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10871:SkRecorder::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10872:SkRecorder::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +10873:SkRecorder::didTranslate\28float\2c\20float\29 +10874:SkRecorder::didSetM44\28SkM44\20const&\29 +10875:SkRecorder::didScale\28float\2c\20float\29 +10876:SkRecorder::didRestore\28\29 +10877:SkRecorder::didConcat44\28SkM44\20const&\29 +10878:SkRecordedDrawable::~SkRecordedDrawable\28\29_3737 +10879:SkRecordedDrawable::onMakePictureSnapshot\28\29 +10880:SkRecordedDrawable::onGetBounds\28\29 +10881:SkRecordedDrawable::onDraw\28SkCanvas*\29 +10882:SkRecordedDrawable::onApproximateBytesUsed\28\29 +10883:SkRecordedDrawable::getTypeName\28\29\20const +10884:SkRecordedDrawable::flatten\28SkWriteBuffer&\29\20const +10885:SkRecord::~SkRecord\28\29_3716 +10886:SkRasterPipelineSpriteBlitter::~SkRasterPipelineSpriteBlitter\28\29_1600 +10887:SkRasterPipelineSpriteBlitter::setup\28SkPixmap\20const&\2c\20int\2c\20int\2c\20SkPaint\20const&\29 +10888:SkRasterPipelineSpriteBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10889:SkRasterPipelineBlitter::~SkRasterPipelineBlitter\28\29_3688 +10890:SkRasterPipelineBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +10891:SkRasterPipelineBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +10892:SkRasterPipelineBlitter::blitH\28int\2c\20int\2c\20int\29 +10893:SkRasterPipelineBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10894:SkRasterPipelineBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +10895:SkRasterPipelineBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +10896:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_3::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10897:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_2::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10898:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_1::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10899:SkRasterPipelineBlitter::Create\28SkPixmap\20const&\2c\20SkPaint\20const&\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkArenaAlloc*\2c\20SkRasterPipeline\20const&\2c\20bool\2c\20bool\2c\20SkShader\20const*\29::$_0::__invoke\28SkPixmap*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20long\20long\29 +10900:SkRadialGradient::getTypeName\28\29\20const +10901:SkRadialGradient::flatten\28SkWriteBuffer&\29\20const +10902:SkRadialGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +10903:SkRadialGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +10904:SkRTree::~SkRTree\28\29_3622 +10905:SkRTree::search\28SkRect\20const&\2c\20std::__2::vector>*\29\20const +10906:SkRTree::insert\28SkRect\20const*\2c\20int\29 +10907:SkRTree::bytesUsed\28\29\20const +10908:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_3::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10909:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_2::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10910:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_1::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10911:SkPixmap::erase\28SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkIRect\20const*\29\20const::$_0::__invoke\28void*\2c\20unsigned\20long\20long\2c\20int\29 +10912:SkPixelRef::~SkPixelRef\28\29_3590 +10913:SkPictureRecord::~SkPictureRecord\28\29_3502 +10914:SkPictureRecord::willSave\28\29 +10915:SkPictureRecord::willRestore\28\29 +10916:SkPictureRecord::onResetClip\28\29 +10917:SkPictureRecord::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10918:SkPictureRecord::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +10919:SkPictureRecord::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +10920:SkPictureRecord::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +10921:SkPictureRecord::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +10922:SkPictureRecord::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +10923:SkPictureRecord::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +10924:SkPictureRecord::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +10925:SkPictureRecord::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +10926:SkPictureRecord::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +10927:SkPictureRecord::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +10928:SkPictureRecord::onDrawPaint\28SkPaint\20const&\29 +10929:SkPictureRecord::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +10930:SkPictureRecord::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10931:SkPictureRecord::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +10932:SkPictureRecord::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +10933:SkPictureRecord::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +10934:SkPictureRecord::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +10935:SkPictureRecord::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +10936:SkPictureRecord::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +10937:SkPictureRecord::onDrawBehind\28SkPaint\20const&\29 +10938:SkPictureRecord::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +10939:SkPictureRecord::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +10940:SkPictureRecord::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +10941:SkPictureRecord::onDoSaveBehind\28SkRect\20const*\29 +10942:SkPictureRecord::onClipShader\28sk_sp\2c\20SkClipOp\29 +10943:SkPictureRecord::onClipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10944:SkPictureRecord::onClipRect\28SkRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10945:SkPictureRecord::onClipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10946:SkPictureRecord::onClipPath\28SkPath\20const&\2c\20SkClipOp\2c\20SkCanvas::ClipEdgeStyle\29 +10947:SkPictureRecord::getSaveLayerStrategy\28SkCanvas::SaveLayerRec\20const&\29 +10948:SkPictureRecord::didTranslate\28float\2c\20float\29 +10949:SkPictureRecord::didSetM44\28SkM44\20const&\29 +10950:SkPictureRecord::didScale\28float\2c\20float\29 +10951:SkPictureRecord::didConcat44\28SkM44\20const&\29 +10952:SkPictureImageGenerator::~SkPictureImageGenerator\28\29_4413 +10953:SkPictureImageGenerator::onGetPixels\28SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20SkImageGenerator::Options\20const&\29 +10954:SkOTUtils::LocalizedStrings_SingleName::~LocalizedStrings_SingleName\28\29_7681 +10955:SkOTUtils::LocalizedStrings_SingleName::next\28SkTypeface::LocalizedString*\29 +10956:SkOTUtils::LocalizedStrings_NameTable::~LocalizedStrings_NameTable\28\29_6840 +10957:SkOTUtils::LocalizedStrings_NameTable::next\28SkTypeface::LocalizedString*\29 +10958:SkNoPixelsDevice::~SkNoPixelsDevice\28\29_2128 +10959:SkNoPixelsDevice::replaceClip\28SkIRect\20const&\29 +10960:SkNoPixelsDevice::pushClipStack\28\29 +10961:SkNoPixelsDevice::popClipStack\28\29 +10962:SkNoPixelsDevice::onClipShader\28sk_sp\29 +10963:SkNoPixelsDevice::isClipWideOpen\28\29\20const +10964:SkNoPixelsDevice::isClipRect\28\29\20const +10965:SkNoPixelsDevice::isClipEmpty\28\29\20const +10966:SkNoPixelsDevice::isClipAntiAliased\28\29\20const +10967:SkNoPixelsDevice::devClipBounds\28\29\20const +10968:SkNoPixelsDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +10969:SkNoPixelsDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +10970:SkNoPixelsDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +10971:SkNoPixelsDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +10972:SkNoPixelsDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +10973:SkMipmap::~SkMipmap\28\29_2691 +10974:SkMipmap::onDataChange\28void*\2c\20void*\29 +10975:SkMemoryStream::~SkMemoryStream\28\29_4083 +10976:SkMemoryStream::setMemory\28void\20const*\2c\20unsigned\20long\2c\20bool\29 +10977:SkMemoryStream::seek\28unsigned\20long\29 +10978:SkMemoryStream::rewind\28\29 +10979:SkMemoryStream::read\28void*\2c\20unsigned\20long\29 +10980:SkMemoryStream::peek\28void*\2c\20unsigned\20long\29\20const +10981:SkMemoryStream::onFork\28\29\20const +10982:SkMemoryStream::onDuplicate\28\29\20const +10983:SkMemoryStream::move\28long\29 +10984:SkMemoryStream::isAtEnd\28\29\20const +10985:SkMemoryStream::getMemoryBase\28\29 +10986:SkMemoryStream::getLength\28\29\20const +10987:SkMemoryStream::getData\28\29\20const +10988:SkMatrixColorFilter::onIsAlphaUnchanged\28\29\20const +10989:SkMatrixColorFilter::onAsAColorMatrix\28float*\29\20const +10990:SkMatrixColorFilter::getTypeName\28\29\20const +10991:SkMatrixColorFilter::flatten\28SkWriteBuffer&\29\20const +10992:SkMatrixColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +10993:SkMatrix::Trans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10994:SkMatrix::Trans_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10995:SkMatrix::Scale_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10996:SkMatrix::Scale_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +10997:SkMatrix::ScaleTrans_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +10998:SkMatrix::Poly4Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +10999:SkMatrix::Poly3Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +11000:SkMatrix::Poly2Proc\28SkPoint\20const*\2c\20SkMatrix*\29 +11001:SkMatrix::Persp_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11002:SkMatrix::Persp_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11003:SkMatrix::Identity_xy\28SkMatrix\20const&\2c\20float\2c\20float\2c\20SkPoint*\29 +11004:SkMatrix::Identity_pts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11005:SkMatrix::Affine_vpts\28SkMatrix\20const&\2c\20SkPoint*\2c\20SkPoint\20const*\2c\20int\29 +11006:SkMaskFilterBase::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11007:SkMaskFilterBase::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11008:SkMallocPixelRef::MakeAllocate\28SkImageInfo\20const&\2c\20unsigned\20long\29::PixelRef::~PixelRef\28\29_2533 +11009:SkMakePixelRefWithProc\28int\2c\20int\2c\20unsigned\20long\2c\20void*\2c\20void\20\28*\29\28void*\2c\20void*\29\2c\20void*\29::PixelRef::~PixelRef\28\29_3592 +11010:SkLocalMatrixShader::~SkLocalMatrixShader\28\29_4537 +11011:SkLocalMatrixShader::~SkLocalMatrixShader\28\29 +11012:SkLocalMatrixShader::type\28\29\20const +11013:SkLocalMatrixShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +11014:SkLocalMatrixShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +11015:SkLocalMatrixShader::makeAsALocalMatrixShader\28SkMatrix*\29\20const +11016:SkLocalMatrixShader::isOpaque\28\29\20const +11017:SkLocalMatrixShader::isConstant\28\29\20const +11018:SkLocalMatrixShader::getTypeName\28\29\20const +11019:SkLocalMatrixShader::flatten\28SkWriteBuffer&\29\20const +11020:SkLocalMatrixShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11021:SkLocalMatrixShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11022:SkLinearGradient::getTypeName\28\29\20const +11023:SkLinearGradient::flatten\28SkWriteBuffer&\29\20const +11024:SkLinearGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11025:SkJSONWriter::popScope\28\29 +11026:SkJSONWriter::appendf\28char\20const*\2c\20...\29 +11027:SkIntersections::hasOppT\28double\29\20const +11028:SkImage_Raster::~SkImage_Raster\28\29_4387 +11029:SkImage_Raster::onReinterpretColorSpace\28sk_sp\29\20const +11030:SkImage_Raster::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +11031:SkImage_Raster::onPeekPixels\28SkPixmap*\29\20const +11032:SkImage_Raster::onPeekMips\28\29\20const +11033:SkImage_Raster::onMakeWithMipmaps\28sk_sp\29\20const +11034:SkImage_Raster::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11035:SkImage_Raster::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11036:SkImage_Raster::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +11037:SkImage_Raster::onHasMipmaps\28\29\20const +11038:SkImage_Raster::onAsLegacyBitmap\28GrDirectContext*\2c\20SkBitmap*\29\20const +11039:SkImage_Raster::notifyAddedToRasterCache\28\29\20const +11040:SkImage_Raster::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +11041:SkImage_Picture::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11042:SkImage_Picture::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11043:SkImage_LazyTexture::readPixelsProxy\28GrDirectContext*\2c\20SkPixmap\20const&\29\20const +11044:SkImage_LazyTexture::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11045:SkImage_Lazy::onReinterpretColorSpace\28sk_sp\29\20const +11046:SkImage_Lazy::onRefEncoded\28\29\20const +11047:SkImage_Lazy::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +11048:SkImage_Lazy::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11049:SkImage_Lazy::onMakeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11050:SkImage_Lazy::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +11051:SkImage_Lazy::onIsProtected\28\29\20const +11052:SkImage_Lazy::isValid\28GrRecordingContext*\29\20const +11053:SkImage_Lazy::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +11054:SkImage_GaneshBase::onReadPixels\28GrDirectContext*\2c\20SkImageInfo\20const&\2c\20void*\2c\20unsigned\20long\2c\20int\2c\20int\2c\20SkImage::CachingHint\29\20const +11055:SkImage_GaneshBase::onMakeSurface\28skgpu::graphite::Recorder*\2c\20SkImageInfo\20const&\29\20const +11056:SkImage_GaneshBase::onMakeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11057:SkImage_GaneshBase::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11058:SkImage_GaneshBase::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +11059:SkImage_GaneshBase::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +11060:SkImage_GaneshBase::isValid\28GrRecordingContext*\29\20const +11061:SkImage_GaneshBase::getROPixels\28GrDirectContext*\2c\20SkBitmap*\2c\20SkImage::CachingHint\29\20const +11062:SkImage_GaneshBase::directContext\28\29\20const +11063:SkImage_Ganesh::~SkImage_Ganesh\28\29_10223 +11064:SkImage_Ganesh::textureSize\28\29\20const +11065:SkImage_Ganesh::onReinterpretColorSpace\28sk_sp\29\20const +11066:SkImage_Ganesh::onMakeColorTypeAndColorSpace\28SkColorType\2c\20sk_sp\2c\20GrDirectContext*\29\20const +11067:SkImage_Ganesh::onIsProtected\28\29\20const +11068:SkImage_Ganesh::onHasMipmaps\28\29\20const +11069:SkImage_Ganesh::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +11070:SkImage_Ganesh::onAsyncRescaleAndReadPixelsYUV420\28SkYUVColorSpace\2c\20bool\2c\20sk_sp\2c\20SkIRect\2c\20SkISize\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +11071:SkImage_Ganesh::generatingSurfaceIsDeleted\28\29 +11072:SkImage_Ganesh::flush\28GrDirectContext*\2c\20GrFlushInfo\20const&\29\20const +11073:SkImage_Ganesh::asView\28GrRecordingContext*\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29\20const +11074:SkImage_Ganesh::asFragmentProcessor\28GrRecordingContext*\2c\20SkSamplingOptions\2c\20SkTileMode\20const*\2c\20SkMatrix\20const&\2c\20SkRect\20const*\2c\20SkRect\20const*\29\20const +11075:SkImage_Base::onAsyncRescaleAndReadPixels\28SkImageInfo\20const&\2c\20SkIRect\2c\20SkImage::RescaleGamma\2c\20SkImage::RescaleMode\2c\20void\20\28*\29\28void*\2c\20std::__2::unique_ptr>\29\2c\20void*\29\20const +11076:SkImage_Base::notifyAddedToRasterCache\28\29\20const +11077:SkImage_Base::makeSubset\28skgpu::graphite::Recorder*\2c\20SkIRect\20const&\2c\20SkImage::RequiredProperties\29\20const +11078:SkImage_Base::makeSubset\28GrDirectContext*\2c\20SkIRect\20const&\29\20const +11079:SkImage_Base::makeColorTypeAndColorSpace\28skgpu::graphite::Recorder*\2c\20SkColorType\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +11080:SkImage_Base::makeColorTypeAndColorSpace\28GrDirectContext*\2c\20SkColorType\2c\20sk_sp\29\20const +11081:SkImage_Base::makeColorSpace\28skgpu::graphite::Recorder*\2c\20sk_sp\2c\20SkImage::RequiredProperties\29\20const +11082:SkImage_Base::makeColorSpace\28GrDirectContext*\2c\20sk_sp\29\20const +11083:SkImage_Base::isTextureBacked\28\29\20const +11084:SkImage_Base::isLazyGenerated\28\29\20const +11085:SkImageShader::~SkImageShader\28\29_4501 +11086:SkImageShader::onIsAImage\28SkMatrix*\2c\20SkTileMode*\29\20const +11087:SkImageShader::isOpaque\28\29\20const +11088:SkImageShader::getTypeName\28\29\20const +11089:SkImageShader::flatten\28SkWriteBuffer&\29\20const +11090:SkImageShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11091:SkImageGenerator::~SkImageGenerator\28\29_521 +11092:SkImageFilter::computeFastBounds\28SkRect\20const&\29\20const +11093:SkGradientBaseShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +11094:SkGradientBaseShader::isOpaque\28\29\20const +11095:SkGradientBaseShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11096:SkGaussianColorFilter::getTypeName\28\29\20const +11097:SkGaussianColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11098:SkGammaColorSpaceLuminance::toLuma\28float\2c\20float\29\20const +11099:SkGammaColorSpaceLuminance::fromLuma\28float\2c\20float\29\20const +11100:SkFontStyleSet_Custom::~SkFontStyleSet_Custom\28\29_7557 +11101:SkFontStyleSet_Custom::getStyle\28int\2c\20SkFontStyle*\2c\20SkString*\29 +11102:SkFontScanner_FreeType::~SkFontScanner_FreeType\28\29_7695 +11103:SkFontScanner_FreeType::scanFile\28SkStreamAsset*\2c\20int*\29\20const +11104:SkFontScanner_FreeType::scanFace\28SkStreamAsset*\2c\20int\2c\20int*\29\20const +11105:SkFontScanner_FreeType::getFactoryId\28\29\20const +11106:SkFontMgr_Custom::~SkFontMgr_Custom\28\29_7563 +11107:SkFontMgr_Custom::onMatchFamily\28char\20const*\29\20const +11108:SkFontMgr_Custom::onMatchFamilyStyle\28char\20const*\2c\20SkFontStyle\20const&\29\20const +11109:SkFontMgr_Custom::onMakeFromStreamIndex\28std::__2::unique_ptr>\2c\20int\29\20const +11110:SkFontMgr_Custom::onMakeFromFile\28char\20const*\2c\20int\29\20const +11111:SkFontMgr_Custom::onMakeFromData\28sk_sp\2c\20int\29\20const +11112:SkFontMgr_Custom::onLegacyMakeTypeface\28char\20const*\2c\20SkFontStyle\29\20const +11113:SkFontMgr_Custom::onGetFamilyName\28int\2c\20SkString*\29\20const +11114:SkFILEStream::~SkFILEStream\28\29_4060 +11115:SkFILEStream::seek\28unsigned\20long\29 +11116:SkFILEStream::rewind\28\29 +11117:SkFILEStream::read\28void*\2c\20unsigned\20long\29 +11118:SkFILEStream::onFork\28\29\20const +11119:SkFILEStream::onDuplicate\28\29\20const +11120:SkFILEStream::move\28long\29 +11121:SkFILEStream::isAtEnd\28\29\20const +11122:SkFILEStream::getPosition\28\29\20const +11123:SkFILEStream::getLength\28\29\20const +11124:SkEmptyShader::getTypeName\28\29\20const +11125:SkEmptyPicture::~SkEmptyPicture\28\29 +11126:SkEmptyPicture::cullRect\28\29\20const +11127:SkEmptyPicture::approximateBytesUsed\28\29\20const +11128:SkEmptyFontMgr::onMatchFamily\28char\20const*\29\20const +11129:SkEdgeBuilder::build\28SkPath\20const&\2c\20SkIRect\20const*\2c\20bool\29::$_0::__invoke\28SkEdgeClipper*\2c\20bool\2c\20void*\29 +11130:SkDynamicMemoryWStream::~SkDynamicMemoryWStream\28\29_4100 +11131:SkDynamicMemoryWStream::bytesWritten\28\29\20const +11132:SkDraw::paintMasks\28SkZip\2c\20SkPaint\20const&\29\20const +11133:SkDevice::strikeDeviceInfo\28\29\20const +11134:SkDevice::drawSlug\28SkCanvas*\2c\20sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +11135:SkDevice::drawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +11136:SkDevice::drawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20sk_sp\2c\20SkPaint\20const&\29 +11137:SkDevice::drawImageLattice\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const&\29 +11138:SkDevice::drawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +11139:SkDevice::drawEdgeAAImageSet\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11140:SkDevice::drawDrawable\28SkCanvas*\2c\20SkDrawable*\2c\20SkMatrix\20const*\29 +11141:SkDevice::drawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +11142:SkDevice::drawCoverageMask\28SkSpecialImage\20const*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\29 +11143:SkDevice::drawBlurredRRect\28SkRRect\20const&\2c\20SkPaint\20const&\2c\20float\29 +11144:SkDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +11145:SkDevice::drawAsTiledImageRect\28SkCanvas*\2c\20SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11146:SkDevice::createImageFilteringBackend\28SkSurfaceProps\20const&\2c\20SkColorType\29\20const +11147:SkDashImpl::~SkDashImpl\28\29_5209 +11148:SkDashImpl::onFilterPath\28SkPath*\2c\20SkPath\20const&\2c\20SkStrokeRec*\2c\20SkRect\20const*\2c\20SkMatrix\20const&\29\20const +11149:SkDashImpl::onAsPoints\28SkPathEffectBase::PointData*\2c\20SkPath\20const&\2c\20SkStrokeRec\20const&\2c\20SkMatrix\20const&\2c\20SkRect\20const*\29\20const +11150:SkDashImpl::getTypeName\28\29\20const +11151:SkDashImpl::flatten\28SkWriteBuffer&\29\20const +11152:SkDashImpl::asADash\28SkPathEffectBase::DashInfo*\29\20const +11153:SkDCurve::nearPoint\28SkPath::Verb\2c\20SkDPoint\20const&\2c\20SkDPoint\20const&\29\20const +11154:SkContourMeasure::~SkContourMeasure\28\29_2050 +11155:SkConicalGradient::getTypeName\28\29\20const +11156:SkConicalGradient::flatten\28SkWriteBuffer&\29\20const +11157:SkConicalGradient::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11158:SkConicalGradient::appendGradientStages\28SkArenaAlloc*\2c\20SkRasterPipeline*\2c\20SkRasterPipeline*\29\20const +11159:SkComposeColorFilter::onIsAlphaUnchanged\28\29\20const +11160:SkComposeColorFilter::getTypeName\28\29\20const +11161:SkComposeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11162:SkColorSpaceXformColorFilter::~SkColorSpaceXformColorFilter\28\29_5310 +11163:SkColorSpaceXformColorFilter::getTypeName\28\29\20const +11164:SkColorSpaceXformColorFilter::flatten\28SkWriteBuffer&\29\20const +11165:SkColorSpaceXformColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11166:SkColorShader::onAsLuminanceColor\28SkRGBA4f<\28SkAlphaType\293>*\29\20const +11167:SkColorShader::isOpaque\28\29\20const +11168:SkColorShader::getTypeName\28\29\20const +11169:SkColorShader::flatten\28SkWriteBuffer&\29\20const +11170:SkColorShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11171:SkColorFilterShader::~SkColorFilterShader\28\29_4474 +11172:SkColorFilterShader::isOpaque\28\29\20const +11173:SkColorFilterShader::getTypeName\28\29\20const +11174:SkColorFilterShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11175:SkColorFilterBase::onFilterColor4f\28SkRGBA4f<\28SkAlphaType\292>\20const&\2c\20SkColorSpace*\29\20const +11176:SkCoincidentSpans::setOppPtTStart\28SkOpPtT\20const*\29 +11177:SkCoincidentSpans::setOppPtTEnd\28SkOpPtT\20const*\29 +11178:SkCoincidentSpans::setCoinPtTStart\28SkOpPtT\20const*\29 +11179:SkCoincidentSpans::setCoinPtTEnd\28SkOpPtT\20const*\29 +11180:SkCanvas::~SkCanvas\28\29_1842 +11181:SkCanvas::recordingContext\28\29\20const +11182:SkCanvas::recorder\28\29\20const +11183:SkCanvas::onPeekPixels\28SkPixmap*\29 +11184:SkCanvas::onNewSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +11185:SkCanvas::onImageInfo\28\29\20const +11186:SkCanvas::onGetProps\28SkSurfaceProps*\2c\20bool\29\20const +11187:SkCanvas::onDrawVerticesObject\28SkVertices\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +11188:SkCanvas::onDrawTextBlob\28SkTextBlob\20const*\2c\20float\2c\20float\2c\20SkPaint\20const&\29 +11189:SkCanvas::onDrawSlug\28sktext::gpu::Slug\20const*\2c\20SkPaint\20const&\29 +11190:SkCanvas::onDrawShadowRec\28SkPath\20const&\2c\20SkDrawShadowRec\20const&\29 +11191:SkCanvas::onDrawRegion\28SkRegion\20const&\2c\20SkPaint\20const&\29 +11192:SkCanvas::onDrawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +11193:SkCanvas::onDrawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +11194:SkCanvas::onDrawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +11195:SkCanvas::onDrawPicture\28SkPicture\20const*\2c\20SkMatrix\20const*\2c\20SkPaint\20const*\29 +11196:SkCanvas::onDrawPath\28SkPath\20const&\2c\20SkPaint\20const&\29 +11197:SkCanvas::onDrawPatch\28SkPoint\20const*\2c\20unsigned\20int\20const*\2c\20SkPoint\20const*\2c\20SkBlendMode\2c\20SkPaint\20const&\29 +11198:SkCanvas::onDrawPaint\28SkPaint\20const&\29 +11199:SkCanvas::onDrawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +11200:SkCanvas::onDrawMesh\28SkMesh\20const&\2c\20sk_sp\2c\20SkPaint\20const&\29 +11201:SkCanvas::onDrawImageRect2\28SkImage\20const*\2c\20SkRect\20const&\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +11202:SkCanvas::onDrawImageLattice2\28SkImage\20const*\2c\20SkCanvas::Lattice\20const&\2c\20SkRect\20const&\2c\20SkFilterMode\2c\20SkPaint\20const*\29 +11203:SkCanvas::onDrawImage2\28SkImage\20const*\2c\20float\2c\20float\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\29 +11204:SkCanvas::onDrawGlyphRunList\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11205:SkCanvas::onDrawEdgeAAQuad\28SkRect\20const&\2c\20SkPoint\20const*\2c\20SkCanvas::QuadAAFlags\2c\20SkRGBA4f<\28SkAlphaType\293>\20const&\2c\20SkBlendMode\29 +11206:SkCanvas::onDrawEdgeAAImageSet2\28SkCanvas::ImageSetEntry\20const*\2c\20int\2c\20SkPoint\20const*\2c\20SkMatrix\20const*\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const*\2c\20SkCanvas::SrcRectConstraint\29 +11207:SkCanvas::onDrawDrawable\28SkDrawable*\2c\20SkMatrix\20const*\29 +11208:SkCanvas::onDrawDRRect\28SkRRect\20const&\2c\20SkRRect\20const&\2c\20SkPaint\20const&\29 +11209:SkCanvas::onDrawBehind\28SkPaint\20const&\29 +11210:SkCanvas::onDrawAtlas2\28SkImage\20const*\2c\20SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20SkBlendMode\2c\20SkSamplingOptions\20const&\2c\20SkRect\20const*\2c\20SkPaint\20const*\29 +11211:SkCanvas::onDrawArc\28SkRect\20const&\2c\20float\2c\20float\2c\20bool\2c\20SkPaint\20const&\29 +11212:SkCanvas::onDrawAnnotation\28SkRect\20const&\2c\20char\20const*\2c\20SkData*\29 +11213:SkCanvas::onDiscard\28\29 +11214:SkCanvas::onConvertGlyphRunListToSlug\28sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11215:SkCanvas::onAccessTopLayerPixels\28SkPixmap*\29 +11216:SkCanvas::isClipRect\28\29\20const +11217:SkCanvas::isClipEmpty\28\29\20const +11218:SkCanvas::getBaseLayerSize\28\29\20const +11219:SkCachedData::~SkCachedData\28\29_1758 +11220:SkCTMShader::~SkCTMShader\28\29_4527 +11221:SkCTMShader::~SkCTMShader\28\29 +11222:SkCTMShader::isConstant\28\29\20const +11223:SkCTMShader::getTypeName\28\29\20const +11224:SkCTMShader::asGradient\28SkShaderBase::GradientInfo*\2c\20SkMatrix*\29\20const +11225:SkCTMShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11226:SkBreakIterator_client::~SkBreakIterator_client\28\29_7513 +11227:SkBreakIterator_client::status\28\29 +11228:SkBreakIterator_client::setText\28char\20const*\2c\20int\29 +11229:SkBreakIterator_client::setText\28char16_t\20const*\2c\20int\29 +11230:SkBreakIterator_client::next\28\29 +11231:SkBreakIterator_client::isDone\28\29 +11232:SkBreakIterator_client::first\28\29 +11233:SkBreakIterator_client::current\28\29 +11234:SkBlurMaskFilterImpl::getTypeName\28\29\20const +11235:SkBlurMaskFilterImpl::flatten\28SkWriteBuffer&\29\20const +11236:SkBlurMaskFilterImpl::filterRectsToNine\28SkRect\20const*\2c\20int\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11237:SkBlurMaskFilterImpl::filterRRectToNine\28SkRRect\20const&\2c\20SkMatrix\20const&\2c\20SkIRect\20const&\2c\20SkTLazy*\29\20const +11238:SkBlurMaskFilterImpl::filterMask\28SkMaskBuilder*\2c\20SkMask\20const&\2c\20SkMatrix\20const&\2c\20SkIPoint*\29\20const +11239:SkBlurMaskFilterImpl::computeFastBounds\28SkRect\20const&\2c\20SkRect*\29\20const +11240:SkBlurMaskFilterImpl::asImageFilter\28SkMatrix\20const&\29\20const +11241:SkBlurMaskFilterImpl::asABlur\28SkMaskFilterBase::BlurRec*\29\20const +11242:SkBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11243:SkBlitter::blitAntiV2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11244:SkBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11245:SkBlitter::blitAntiH2\28int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11246:SkBlitter::allocBlitMemory\28unsigned\20long\29 +11247:SkBlendShader::getTypeName\28\29\20const +11248:SkBlendShader::flatten\28SkWriteBuffer&\29\20const +11249:SkBlendShader::appendStages\28SkStageRec\20const&\2c\20SkShaders::MatrixRec\20const&\29\20const +11250:SkBlendModeColorFilter::onIsAlphaUnchanged\28\29\20const +11251:SkBlendModeColorFilter::onAsAColorMode\28unsigned\20int*\2c\20SkBlendMode*\29\20const +11252:SkBlendModeColorFilter::getTypeName\28\29\20const +11253:SkBlendModeColorFilter::flatten\28SkWriteBuffer&\29\20const +11254:SkBlendModeColorFilter::appendStages\28SkStageRec\20const&\2c\20bool\29\20const +11255:SkBlendModeBlender::onAppendStages\28SkStageRec\20const&\29\20const +11256:SkBlendModeBlender::getTypeName\28\29\20const +11257:SkBlendModeBlender::flatten\28SkWriteBuffer&\29\20const +11258:SkBlendModeBlender::asBlendMode\28\29\20const +11259:SkBitmapDevice::~SkBitmapDevice\28\29_1269 +11260:SkBitmapDevice::snapSpecial\28SkIRect\20const&\2c\20bool\29 +11261:SkBitmapDevice::setImmutable\28\29 +11262:SkBitmapDevice::replaceClip\28SkIRect\20const&\29 +11263:SkBitmapDevice::pushClipStack\28\29 +11264:SkBitmapDevice::popClipStack\28\29 +11265:SkBitmapDevice::onWritePixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +11266:SkBitmapDevice::onReadPixels\28SkPixmap\20const&\2c\20int\2c\20int\29 +11267:SkBitmapDevice::onPeekPixels\28SkPixmap*\29 +11268:SkBitmapDevice::onDrawGlyphRunList\28SkCanvas*\2c\20sktext::GlyphRunList\20const&\2c\20SkPaint\20const&\29 +11269:SkBitmapDevice::onClipShader\28sk_sp\29 +11270:SkBitmapDevice::onAccessPixels\28SkPixmap*\29 +11271:SkBitmapDevice::makeSurface\28SkImageInfo\20const&\2c\20SkSurfaceProps\20const&\29 +11272:SkBitmapDevice::makeSpecial\28SkImage\20const*\29 +11273:SkBitmapDevice::makeSpecial\28SkBitmap\20const&\29 +11274:SkBitmapDevice::isClipWideOpen\28\29\20const +11275:SkBitmapDevice::isClipRect\28\29\20const +11276:SkBitmapDevice::isClipEmpty\28\29\20const +11277:SkBitmapDevice::isClipAntiAliased\28\29\20const +11278:SkBitmapDevice::getRasterHandle\28\29\20const +11279:SkBitmapDevice::drawVertices\28SkVertices\20const*\2c\20sk_sp\2c\20SkPaint\20const&\2c\20bool\29 +11280:SkBitmapDevice::drawSpecial\28SkSpecialImage*\2c\20SkMatrix\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11281:SkBitmapDevice::drawRect\28SkRect\20const&\2c\20SkPaint\20const&\29 +11282:SkBitmapDevice::drawRRect\28SkRRect\20const&\2c\20SkPaint\20const&\29 +11283:SkBitmapDevice::drawPoints\28SkCanvas::PointMode\2c\20unsigned\20long\2c\20SkPoint\20const*\2c\20SkPaint\20const&\29 +11284:SkBitmapDevice::drawPath\28SkPath\20const&\2c\20SkPaint\20const&\2c\20bool\29 +11285:SkBitmapDevice::drawPaint\28SkPaint\20const&\29 +11286:SkBitmapDevice::drawOval\28SkRect\20const&\2c\20SkPaint\20const&\29 +11287:SkBitmapDevice::drawImageRect\28SkImage\20const*\2c\20SkRect\20const*\2c\20SkRect\20const&\2c\20SkSamplingOptions\20const&\2c\20SkPaint\20const&\2c\20SkCanvas::SrcRectConstraint\29 +11288:SkBitmapDevice::drawAtlas\28SkRSXform\20const*\2c\20SkRect\20const*\2c\20unsigned\20int\20const*\2c\20int\2c\20sk_sp\2c\20SkPaint\20const&\29 +11289:SkBitmapDevice::devClipBounds\28\29\20const +11290:SkBitmapDevice::createDevice\28SkDevice::CreateInfo\20const&\2c\20SkPaint\20const*\29 +11291:SkBitmapDevice::clipRegion\28SkRegion\20const&\2c\20SkClipOp\29 +11292:SkBitmapDevice::clipRect\28SkRect\20const&\2c\20SkClipOp\2c\20bool\29 +11293:SkBitmapDevice::clipRRect\28SkRRect\20const&\2c\20SkClipOp\2c\20bool\29 +11294:SkBitmapDevice::clipPath\28SkPath\20const&\2c\20SkClipOp\2c\20bool\29 +11295:SkBitmapDevice::android_utils_clipAsRgn\28SkRegion*\29\20const +11296:SkBitmapCache::Rec::~Rec\28\29_1232 +11297:SkBitmapCache::Rec::postAddInstall\28void*\29 +11298:SkBitmapCache::Rec::getCategory\28\29\20const +11299:SkBitmapCache::Rec::canBePurged\28\29 +11300:SkBitmapCache::Rec::bytesUsed\28\29\20const +11301:SkBitmapCache::Rec::ReleaseProc\28void*\2c\20void*\29 +11302:SkBitmapCache::Rec::Finder\28SkResourceCache::Rec\20const&\2c\20void*\29 +11303:SkBinaryWriteBuffer::~SkBinaryWriteBuffer\28\29_4281 +11304:SkBinaryWriteBuffer::write\28SkM44\20const&\29 +11305:SkBinaryWriteBuffer::writeTypeface\28SkTypeface*\29 +11306:SkBinaryWriteBuffer::writeString\28std::__2::basic_string_view>\29 +11307:SkBinaryWriteBuffer::writeStream\28SkStream*\2c\20unsigned\20long\29 +11308:SkBinaryWriteBuffer::writeScalar\28float\29 +11309:SkBinaryWriteBuffer::writeSampling\28SkSamplingOptions\20const&\29 +11310:SkBinaryWriteBuffer::writeRegion\28SkRegion\20const&\29 +11311:SkBinaryWriteBuffer::writeRect\28SkRect\20const&\29 +11312:SkBinaryWriteBuffer::writePoint\28SkPoint\20const&\29 +11313:SkBinaryWriteBuffer::writePointArray\28SkPoint\20const*\2c\20unsigned\20int\29 +11314:SkBinaryWriteBuffer::writePoint3\28SkPoint3\20const&\29 +11315:SkBinaryWriteBuffer::writePath\28SkPath\20const&\29 +11316:SkBinaryWriteBuffer::writePaint\28SkPaint\20const&\29 +11317:SkBinaryWriteBuffer::writePad32\28void\20const*\2c\20unsigned\20long\29 +11318:SkBinaryWriteBuffer::writeMatrix\28SkMatrix\20const&\29 +11319:SkBinaryWriteBuffer::writeImage\28SkImage\20const*\29 +11320:SkBinaryWriteBuffer::writeColor4fArray\28SkRGBA4f<\28SkAlphaType\293>\20const*\2c\20unsigned\20int\29 +11321:SkBinaryWriteBuffer::writeBool\28bool\29 +11322:SkBigPicture::~SkBigPicture\28\29_1147 +11323:SkBigPicture::playback\28SkCanvas*\2c\20SkPicture::AbortCallback*\29\20const +11324:SkBigPicture::approximateOpCount\28bool\29\20const +11325:SkBigPicture::approximateBytesUsed\28\29\20const +11326:SkBidiSubsetFactory::errorName\28UErrorCode\29\20const +11327:SkBidiSubsetFactory::bidi_setPara\28UBiDi*\2c\20char16_t\20const*\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char*\2c\20UErrorCode*\29\20const +11328:SkBidiSubsetFactory::bidi_reorderVisual\28unsigned\20char\20const*\2c\20int\2c\20int*\29\20const +11329:SkBidiSubsetFactory::bidi_openSized\28int\2c\20int\2c\20UErrorCode*\29\20const +11330:SkBidiSubsetFactory::bidi_getLevelAt\28UBiDi\20const*\2c\20int\29\20const +11331:SkBidiSubsetFactory::bidi_getLength\28UBiDi\20const*\29\20const +11332:SkBidiSubsetFactory::bidi_getDirection\28UBiDi\20const*\29\20const +11333:SkBidiSubsetFactory::bidi_close_callback\28\29\20const +11334:SkBasicEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +11335:SkBasicEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +11336:SkBasicEdgeBuilder::addQuad\28SkPoint\20const*\29 +11337:SkBasicEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +11338:SkBasicEdgeBuilder::addLine\28SkPoint\20const*\29 +11339:SkBasicEdgeBuilder::addCubic\28SkPoint\20const*\29 +11340:SkBBoxHierarchy::insert\28SkRect\20const*\2c\20SkBBoxHierarchy::Metadata\20const*\2c\20int\29 +11341:SkArenaAlloc::SkipPod\28char*\29 +11342:SkArenaAlloc::NextBlock\28char*\29 +11343:SkAnalyticEdgeBuilder::recoverClip\28SkIRect\20const&\29\20const +11344:SkAnalyticEdgeBuilder::allocEdges\28unsigned\20long\2c\20unsigned\20long*\29 +11345:SkAnalyticEdgeBuilder::addQuad\28SkPoint\20const*\29 +11346:SkAnalyticEdgeBuilder::addPolyLine\28SkPoint\20const*\2c\20char*\2c\20char**\29 +11347:SkAnalyticEdgeBuilder::addLine\28SkPoint\20const*\29 +11348:SkAnalyticEdgeBuilder::addCubic\28SkPoint\20const*\29 +11349:SkAAClipBlitter::~SkAAClipBlitter\28\29_1105 +11350:SkAAClipBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11351:SkAAClipBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11352:SkAAClipBlitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11353:SkAAClipBlitter::blitH\28int\2c\20int\2c\20int\29 +11354:SkAAClipBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11355:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_1::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +11356:SkAAClip::Builder::operateY\28SkAAClip\20const&\2c\20SkAAClip\20const&\2c\20SkClipOp\29::$_0::__invoke\28unsigned\20int\2c\20unsigned\20int\29 +11357:SkAAClip::Builder::Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11358:SkAAClip::Builder::Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11359:SkAAClip::Builder::Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11360:SkAAClip::Builder::Blitter::blitH\28int\2c\20int\2c\20int\29 +11361:SkAAClip::Builder::Blitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11362:SkA8_Coverage_Blitter::~SkA8_Coverage_Blitter\28\29_1563 +11363:SkA8_Coverage_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11364:SkA8_Coverage_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11365:SkA8_Coverage_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11366:SkA8_Coverage_Blitter::blitH\28int\2c\20int\2c\20int\29 +11367:SkA8_Coverage_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11368:SkA8_Blitter::~SkA8_Blitter\28\29_1578 +11369:SkA8_Blitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11370:SkA8_Blitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11371:SkA8_Blitter::blitMask\28SkMask\20const&\2c\20SkIRect\20const&\29 +11372:SkA8_Blitter::blitH\28int\2c\20int\2c\20int\29 +11373:SkA8_Blitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20short\20const*\29 +11374:SkA8Blitter_Choose\28SkPixmap\20const&\2c\20SkMatrix\20const&\2c\20SkPaint\20const&\2c\20SkArenaAlloc*\2c\20bool\2c\20sk_sp\2c\20SkSurfaceProps\20const&\29 +11375:ShaderPDXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11376:ShaderPDXferProcessor::name\28\29\20const +11377:ShaderPDXferProcessor::makeProgramImpl\28\29\20const +11378:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11379:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11380:SafeRLEAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11381:RuntimeEffectRPCallbacks::toLinearSrgb\28void\20const*\29 +11382:RuntimeEffectRPCallbacks::fromLinearSrgb\28void\20const*\29 +11383:RuntimeEffectRPCallbacks::appendShader\28int\29 +11384:RuntimeEffectRPCallbacks::appendColorFilter\28int\29 +11385:RuntimeEffectRPCallbacks::appendBlender\28int\29 +11386:RunBasedAdditiveBlitter::getRealBlitter\28bool\29 +11387:RunBasedAdditiveBlitter::flush_if_y_changed\28int\2c\20int\29 +11388:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11389:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11390:RunBasedAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11391:Round_Up_To_Grid +11392:Round_To_Half_Grid +11393:Round_To_Grid +11394:Round_To_Double_Grid +11395:Round_Super_45 +11396:Round_Super +11397:Round_None +11398:Round_Down_To_Grid +11399:RoundJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11400:RoundCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +11401:Read_CVT_Stretched +11402:Read_CVT +11403:Project_y +11404:Project +11405:PrePostInverseBlitterProc\28SkBlitter*\2c\20int\2c\20bool\29 +11406:PorterDuffXferProcessor::onHasSecondaryOutput\28\29\20const +11407:PorterDuffXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11408:PorterDuffXferProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11409:PorterDuffXferProcessor::name\28\29\20const +11410:PorterDuffXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11411:PorterDuffXferProcessor::makeProgramImpl\28\29\20const +11412:PDLCDXferProcessor::onIsEqual\28GrXferProcessor\20const&\29\20const +11413:PDLCDXferProcessor::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11414:PDLCDXferProcessor::name\28\29\20const +11415:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrXferProcessor\20const&\29 +11416:PDLCDXferProcessor::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11417:PDLCDXferProcessor::makeProgramImpl\28\29\20const +11418:OT::match_glyph\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11419:OT::match_coverage\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11420:OT::match_class_cached\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11421:OT::match_class_cached2\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11422:OT::match_class_cached1\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11423:OT::match_class\28hb_glyph_info_t&\2c\20unsigned\20int\2c\20void\20const*\29 +11424:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GSUB_impl::SubstLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +11425:OT::hb_ot_apply_context_t::return_t\20OT::Layout::GPOS_impl::PosLookup::dispatch_recurse_func\28OT::hb_ot_apply_context_t*\2c\20unsigned\20int\29 +11426:OT::Layout::Common::RangeRecord::cmp_range\28void\20const*\2c\20void\20const*\29 +11427:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +11428:OT::ColorLine::static_get_color_stops\28hb_color_line_t*\2c\20void*\2c\20unsigned\20int\2c\20unsigned\20int*\2c\20hb_color_stop_t*\2c\20void*\29 +11429:OT::CmapSubtableFormat4::accelerator_t::get_glyph_func\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int*\29 +11430:Move_CVT_Stretched +11431:Move_CVT +11432:MiterJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11433:MaskAdditiveBlitter::~MaskAdditiveBlitter\28\29_3928 +11434:MaskAdditiveBlitter::getWidth\28\29 +11435:MaskAdditiveBlitter::getRealBlitter\28bool\29 +11436:MaskAdditiveBlitter::blitV\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11437:MaskAdditiveBlitter::blitRect\28int\2c\20int\2c\20int\2c\20int\29 +11438:MaskAdditiveBlitter::blitAntiRect\28int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20char\2c\20unsigned\20char\29 +11439:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\29 +11440:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20unsigned\20char\20const*\2c\20int\29 +11441:MaskAdditiveBlitter::blitAntiH\28int\2c\20int\2c\20int\2c\20unsigned\20char\29 +11442:InverseBlitter::blitH\28int\2c\20int\2c\20int\29 +11443:Horish_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +11444:Horish_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +11445:HLine_SkAntiHairBlitter::drawLine\28int\2c\20int\2c\20int\2c\20int\29 +11446:HLine_SkAntiHairBlitter::drawCap\28int\2c\20int\2c\20int\2c\20int\29 +11447:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11448:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11449:GrYUVtoRGBEffect::onMakeProgramImpl\28\29\20const +11450:GrYUVtoRGBEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11451:GrYUVtoRGBEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11452:GrYUVtoRGBEffect::name\28\29\20const +11453:GrYUVtoRGBEffect::clone\28\29\20const +11454:GrXferProcessor::ProgramImpl::emitWriteSwizzle\28GrGLSLXPFragmentBuilder*\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20char\20const*\29\20const +11455:GrXferProcessor::ProgramImpl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11456:GrXferProcessor::ProgramImpl::emitBlendCodeForDstRead\28GrGLSLXPFragmentBuilder*\2c\20GrGLSLUniformHandler*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20char\20const*\2c\20GrXferProcessor\20const&\29 +11457:GrWritePixelsTask::~GrWritePixelsTask\28\29_9497 +11458:GrWritePixelsTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +11459:GrWritePixelsTask::onExecute\28GrOpFlushState*\29 +11460:GrWritePixelsTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11461:GrWaitRenderTask::~GrWaitRenderTask\28\29_9492 +11462:GrWaitRenderTask::onIsUsed\28GrSurfaceProxy*\29\20const +11463:GrWaitRenderTask::onExecute\28GrOpFlushState*\29 +11464:GrWaitRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11465:GrTransferFromRenderTask::~GrTransferFromRenderTask\28\29_9485 +11466:GrTransferFromRenderTask::onExecute\28GrOpFlushState*\29 +11467:GrTransferFromRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11468:GrThreadSafeCache::Trampoline::~Trampoline\28\29_9481 +11469:GrTextureResolveRenderTask::~GrTextureResolveRenderTask\28\29_9453 +11470:GrTextureResolveRenderTask::onExecute\28GrOpFlushState*\29 +11471:GrTextureResolveRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11472:GrTextureEffect::~GrTextureEffect\28\29_9928 +11473:GrTextureEffect::onMakeProgramImpl\28\29\20const +11474:GrTextureEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11475:GrTextureEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11476:GrTextureEffect::name\28\29\20const +11477:GrTextureEffect::clone\28\29\20const +11478:GrTextureEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11479:GrTextureEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11480:GrTDeferredProxyUploader>::~GrTDeferredProxyUploader\28\29_8017 +11481:GrTDeferredProxyUploader>::freeData\28\29 +11482:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::~GrTDeferredProxyUploader\28\29_11162 +11483:GrTDeferredProxyUploader<\28anonymous\20namespace\29::SoftwarePathData>::freeData\28\29 +11484:GrSurfaceProxy::getUniqueKey\28\29\20const +11485:GrSurface::getResourceType\28\29\20const +11486:GrStrokeTessellationShader::~GrStrokeTessellationShader\28\29_11327 +11487:GrStrokeTessellationShader::name\28\29\20const +11488:GrStrokeTessellationShader::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11489:GrStrokeTessellationShader::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11490:GrStrokeTessellationShader::Impl::~Impl\28\29_11332 +11491:GrStrokeTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11492:GrStrokeTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11493:GrSkSLFP::~GrSkSLFP\28\29_9885 +11494:GrSkSLFP::onMakeProgramImpl\28\29\20const +11495:GrSkSLFP::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11496:GrSkSLFP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11497:GrSkSLFP::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11498:GrSkSLFP::clone\28\29\20const +11499:GrSkSLFP::Impl::~Impl\28\29_9893 +11500:GrSkSLFP::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11501:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::toLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11502:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleShader\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11503:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleColorFilter\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11504:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::sampleBlender\28int\2c\20std::__2::basic_string\2c\20std::__2::allocator>\2c\20std::__2::basic_string\2c\20std::__2::allocator>\29 +11505:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::getMangledName\28char\20const*\29 +11506:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::fromLinearSrgb\28std::__2::basic_string\2c\20std::__2::allocator>\29 +11507:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::defineFunction\28char\20const*\2c\20char\20const*\2c\20bool\29 +11508:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareUniform\28SkSL::VarDeclaration\20const*\29 +11509:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29::FPCallbacks::declareFunction\28char\20const*\29 +11510:GrSkSLFP::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11511:GrSimpleMesh*\20SkArenaAlloc::allocUninitializedArray\28unsigned\20long\29::'lambda'\28char*\29::__invoke\28char*\29 +11512:GrRingBuffer::FinishSubmit\28void*\29 +11513:GrResourceCache::CompareTimestamp\28GrGpuResource*\20const&\2c\20GrGpuResource*\20const&\29 +11514:GrRenderTask::disown\28GrDrawingManager*\29 +11515:GrRecordingContext::~GrRecordingContext\28\29_9217 +11516:GrRRectShadowGeoProc::~GrRRectShadowGeoProc\28\29_9876 +11517:GrRRectShadowGeoProc::onTextureSampler\28int\29\20const +11518:GrRRectShadowGeoProc::name\28\29\20const +11519:GrRRectShadowGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11520:GrRRectShadowGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11521:GrQuadEffect::name\28\29\20const +11522:GrQuadEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11523:GrQuadEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11524:GrQuadEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11525:GrQuadEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11526:GrPorterDuffXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11527:GrPorterDuffXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11528:GrPerlinNoise2Effect::~GrPerlinNoise2Effect\28\29_9818 +11529:GrPerlinNoise2Effect::onMakeProgramImpl\28\29\20const +11530:GrPerlinNoise2Effect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11531:GrPerlinNoise2Effect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11532:GrPerlinNoise2Effect::name\28\29\20const +11533:GrPerlinNoise2Effect::clone\28\29\20const +11534:GrPerlinNoise2Effect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11535:GrPerlinNoise2Effect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11536:GrPathTessellationShader::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11537:GrPathTessellationShader::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11538:GrOpsRenderPass::onExecuteDrawable\28std::__2::unique_ptr>\29 +11539:GrOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11540:GrOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11541:GrOpFlushState::writeView\28\29\20const +11542:GrOpFlushState::usesMSAASurface\28\29\20const +11543:GrOpFlushState::tokenTracker\28\29 +11544:GrOpFlushState::threadSafeCache\28\29\20const +11545:GrOpFlushState::strikeCache\28\29\20const +11546:GrOpFlushState::sampledProxyArray\28\29 +11547:GrOpFlushState::rtProxy\28\29\20const +11548:GrOpFlushState::resourceProvider\28\29\20const +11549:GrOpFlushState::renderPassBarriers\28\29\20const +11550:GrOpFlushState::putBackVertices\28int\2c\20unsigned\20long\29 +11551:GrOpFlushState::putBackIndirectDraws\28int\29 +11552:GrOpFlushState::putBackIndexedIndirectDraws\28int\29 +11553:GrOpFlushState::makeVertexSpace\28unsigned\20long\2c\20int\2c\20sk_sp*\2c\20int*\29 +11554:GrOpFlushState::makeVertexSpaceAtLeast\28unsigned\20long\2c\20int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +11555:GrOpFlushState::makeIndexSpace\28int\2c\20sk_sp*\2c\20int*\29 +11556:GrOpFlushState::makeIndexSpaceAtLeast\28int\2c\20int\2c\20sk_sp*\2c\20int*\2c\20int*\29 +11557:GrOpFlushState::makeDrawIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +11558:GrOpFlushState::makeDrawIndexedIndirectSpace\28int\2c\20sk_sp*\2c\20unsigned\20long*\29 +11559:GrOpFlushState::dstProxyView\28\29\20const +11560:GrOpFlushState::colorLoadOp\28\29\20const +11561:GrOpFlushState::caps\28\29\20const +11562:GrOpFlushState::atlasManager\28\29\20const +11563:GrOpFlushState::appliedClip\28\29\20const +11564:GrOpFlushState::addInlineUpload\28std::__2::function&\29>&&\29 +11565:GrOnFlushCallbackObject::postFlush\28skgpu::AtlasToken\29 +11566:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11567:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11568:GrModulateAtlasCoverageEffect::onMakeProgramImpl\28\29\20const +11569:GrModulateAtlasCoverageEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11570:GrModulateAtlasCoverageEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11571:GrModulateAtlasCoverageEffect::name\28\29\20const +11572:GrModulateAtlasCoverageEffect::clone\28\29\20const +11573:GrMeshDrawOp::onPrepare\28GrOpFlushState*\29 +11574:GrMeshDrawOp::onPrePrepare\28GrRecordingContext*\2c\20GrSurfaceProxyView\20const&\2c\20GrAppliedClip*\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11575:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11576:GrMatrixEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11577:GrMatrixEffect::onMakeProgramImpl\28\29\20const +11578:GrMatrixEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11579:GrMatrixEffect::name\28\29\20const +11580:GrMatrixEffect::clone\28\29\20const +11581:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::Listener::~Listener\28\29_9522 +11582:GrMakeUniqueKeyInvalidationListener\28skgpu::UniqueKey*\2c\20unsigned\20int\29::$_0::__invoke\28void\20const*\2c\20void*\29 +11583:GrImageContext::~GrImageContext\28\29 +11584:GrHardClip::apply\28GrRecordingContext*\2c\20skgpu::ganesh::SurfaceDrawContext*\2c\20GrDrawOp*\2c\20GrAAType\2c\20GrAppliedClip*\2c\20SkRect*\29\20const +11585:GrGpuResource::dumpMemoryStatistics\28SkTraceMemoryDump*\29\20const +11586:GrGpuBuffer::unref\28\29\20const +11587:GrGpuBuffer::getResourceType\28\29\20const +11588:GrGpuBuffer::computeScratchKey\28skgpu::ScratchKey*\29\20const +11589:GrGpu::startTimerQuery\28\29 +11590:GrGpu::endTimerQuery\28GrTimerQuery\20const&\29 +11591:GrGeometryProcessor::onTextureSampler\28int\29\20const +11592:GrGLVaryingHandler::~GrGLVaryingHandler\28\29 +11593:GrGLUniformHandler::~GrGLUniformHandler\28\29_11908 +11594:GrGLUniformHandler::samplerVariable\28GrResourceHandle\29\20const +11595:GrGLUniformHandler::samplerSwizzle\28GrResourceHandle\29\20const +11596:GrGLUniformHandler::internalAddUniformArray\28GrProcessor\20const*\2c\20unsigned\20int\2c\20SkSLType\2c\20char\20const*\2c\20bool\2c\20int\2c\20char\20const**\29 +11597:GrGLUniformHandler::getUniformCStr\28GrResourceHandle\29\20const +11598:GrGLUniformHandler::appendUniformDecls\28GrShaderFlags\2c\20SkString*\29\20const +11599:GrGLUniformHandler::addSampler\28GrBackendFormat\20const&\2c\20GrSamplerState\2c\20skgpu::Swizzle\20const&\2c\20char\20const*\2c\20GrShaderCaps\20const*\29 +11600:GrGLTextureRenderTarget::onSetLabel\28\29 +11601:GrGLTextureRenderTarget::backendFormat\28\29\20const +11602:GrGLTexture::textureParamsModified\28\29 +11603:GrGLTexture::onStealBackendTexture\28GrBackendTexture*\2c\20std::__2::function*\29 +11604:GrGLTexture::getBackendTexture\28\29\20const +11605:GrGLSemaphore::~GrGLSemaphore\28\29_11840 +11606:GrGLSemaphore::setIsOwned\28\29 +11607:GrGLSemaphore::backendSemaphore\28\29\20const +11608:GrGLSLVertexBuilder::~GrGLSLVertexBuilder\28\29 +11609:GrGLSLVertexBuilder::onFinalize\28\29 +11610:GrGLSLUniformHandler::inputSamplerSwizzle\28GrResourceHandle\29\20const +11611:GrGLSLFragmentShaderBuilder::~GrGLSLFragmentShaderBuilder\28\29 +11612:GrGLSLFragmentShaderBuilder::hasSecondaryOutput\28\29\20const +11613:GrGLSLFragmentShaderBuilder::forceHighPrecision\28\29 +11614:GrGLRenderTarget::getBackendRenderTarget\28\29\20const +11615:GrGLRenderTarget::completeStencilAttachment\28GrAttachment*\2c\20bool\29 +11616:GrGLRenderTarget::canAttemptStencilAttachment\28bool\29\20const +11617:GrGLRenderTarget::alwaysClearStencil\28\29\20const +11618:GrGLProgramDataManager::~GrGLProgramDataManager\28\29_11794 +11619:GrGLProgramDataManager::setMatrix4fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11620:GrGLProgramDataManager::setMatrix4f\28GrResourceHandle\2c\20float\20const*\29\20const +11621:GrGLProgramDataManager::setMatrix3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11622:GrGLProgramDataManager::setMatrix3f\28GrResourceHandle\2c\20float\20const*\29\20const +11623:GrGLProgramDataManager::setMatrix2fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11624:GrGLProgramDataManager::setMatrix2f\28GrResourceHandle\2c\20float\20const*\29\20const +11625:GrGLProgramDataManager::set4iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11626:GrGLProgramDataManager::set4i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\2c\20int\29\20const +11627:GrGLProgramDataManager::set4f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\2c\20float\29\20const +11628:GrGLProgramDataManager::set3iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11629:GrGLProgramDataManager::set3i\28GrResourceHandle\2c\20int\2c\20int\2c\20int\29\20const +11630:GrGLProgramDataManager::set3fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11631:GrGLProgramDataManager::set3f\28GrResourceHandle\2c\20float\2c\20float\2c\20float\29\20const +11632:GrGLProgramDataManager::set2iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11633:GrGLProgramDataManager::set2i\28GrResourceHandle\2c\20int\2c\20int\29\20const +11634:GrGLProgramDataManager::set2f\28GrResourceHandle\2c\20float\2c\20float\29\20const +11635:GrGLProgramDataManager::set1iv\28GrResourceHandle\2c\20int\2c\20int\20const*\29\20const +11636:GrGLProgramDataManager::set1i\28GrResourceHandle\2c\20int\29\20const +11637:GrGLProgramDataManager::set1fv\28GrResourceHandle\2c\20int\2c\20float\20const*\29\20const +11638:GrGLProgramDataManager::set1f\28GrResourceHandle\2c\20float\29\20const +11639:GrGLProgramBuilder::~GrGLProgramBuilder\28\29_11926 +11640:GrGLProgramBuilder::varyingHandler\28\29 +11641:GrGLProgramBuilder::caps\28\29\20const +11642:GrGLProgram::~GrGLProgram\28\29_11777 +11643:GrGLOpsRenderPass::~GrGLOpsRenderPass\28\29 +11644:GrGLOpsRenderPass::onSetScissorRect\28SkIRect\20const&\29 +11645:GrGLOpsRenderPass::onEnd\28\29 +11646:GrGLOpsRenderPass::onDraw\28int\2c\20int\29 +11647:GrGLOpsRenderPass::onDrawInstanced\28int\2c\20int\2c\20int\2c\20int\29 +11648:GrGLOpsRenderPass::onDrawIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11649:GrGLOpsRenderPass::onDrawIndexed\28int\2c\20int\2c\20unsigned\20short\2c\20unsigned\20short\2c\20int\29 +11650:GrGLOpsRenderPass::onDrawIndexedInstanced\28int\2c\20int\2c\20int\2c\20int\2c\20int\29 +11651:GrGLOpsRenderPass::onDrawIndexedIndirect\28GrBuffer\20const*\2c\20unsigned\20long\2c\20int\29 +11652:GrGLOpsRenderPass::onClear\28GrScissorState\20const&\2c\20std::__2::array\29 +11653:GrGLOpsRenderPass::onClearStencilClip\28GrScissorState\20const&\2c\20bool\29 +11654:GrGLOpsRenderPass::onBindTextures\28GrGeometryProcessor\20const&\2c\20GrSurfaceProxy\20const*\20const*\2c\20GrPipeline\20const&\29 +11655:GrGLOpsRenderPass::onBindPipeline\28GrProgramInfo\20const&\2c\20SkRect\20const&\29 +11656:GrGLOpsRenderPass::onBindBuffers\28sk_sp\2c\20sk_sp\2c\20sk_sp\2c\20GrPrimitiveRestart\29 +11657:GrGLOpsRenderPass::onBegin\28\29 +11658:GrGLOpsRenderPass::inlineUpload\28GrOpFlushState*\2c\20std::__2::function&\29>&\29 +11659:GrGLInterface::~GrGLInterface\28\29_11750 +11660:GrGLGpu::~GrGLGpu\28\29_11591 +11661:GrGLGpu::xferBarrier\28GrRenderTarget*\2c\20GrXferBarrierType\29 +11662:GrGLGpu::wrapBackendSemaphore\28GrBackendSemaphore\20const&\2c\20GrSemaphoreWrapType\2c\20GrWrapOwnership\29 +11663:GrGLGpu::willExecute\28\29 +11664:GrGLGpu::submit\28GrOpsRenderPass*\29 +11665:GrGLGpu::startTimerQuery\28\29 +11666:GrGLGpu::stagingBufferManager\28\29 +11667:GrGLGpu::refPipelineBuilder\28\29 +11668:GrGLGpu::prepareTextureForCrossContextUsage\28GrTexture*\29 +11669:GrGLGpu::precompileShader\28SkData\20const&\2c\20SkData\20const&\29 +11670:GrGLGpu::pipelineBuilder\28\29 +11671:GrGLGpu::onWritePixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20GrMipLevel\20const*\2c\20int\2c\20bool\29 +11672:GrGLGpu::onWrapRenderableBackendTexture\28GrBackendTexture\20const&\2c\20int\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +11673:GrGLGpu::onWrapCompressedBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\29 +11674:GrGLGpu::onWrapBackendTexture\28GrBackendTexture\20const&\2c\20GrWrapOwnership\2c\20GrWrapCacheable\2c\20GrIOType\29 +11675:GrGLGpu::onWrapBackendRenderTarget\28GrBackendRenderTarget\20const&\29 +11676:GrGLGpu::onUpdateCompressedBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20void\20const*\2c\20unsigned\20long\29 +11677:GrGLGpu::onTransferPixelsTo\28GrTexture*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +11678:GrGLGpu::onTransferPixelsFrom\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20sk_sp\2c\20unsigned\20long\29 +11679:GrGLGpu::onTransferFromBufferToBuffer\28sk_sp\2c\20unsigned\20long\2c\20sk_sp\2c\20unsigned\20long\2c\20unsigned\20long\29 +11680:GrGLGpu::onSubmitToGpu\28GrSubmitInfo\20const&\29 +11681:GrGLGpu::onResolveRenderTarget\28GrRenderTarget*\2c\20SkIRect\20const&\29 +11682:GrGLGpu::onResetTextureBindings\28\29 +11683:GrGLGpu::onResetContext\28unsigned\20int\29 +11684:GrGLGpu::onRegenerateMipMapLevels\28GrTexture*\29 +11685:GrGLGpu::onReadPixels\28GrSurface*\2c\20SkIRect\2c\20GrColorType\2c\20GrColorType\2c\20void*\2c\20unsigned\20long\29 +11686:GrGLGpu::onGetOpsRenderPass\28GrRenderTarget*\2c\20bool\2c\20GrAttachment*\2c\20GrSurfaceOrigin\2c\20SkIRect\20const&\2c\20GrOpsRenderPass::LoadAndStoreInfo\20const&\2c\20GrOpsRenderPass::StencilLoadAndStoreInfo\20const&\2c\20skia_private::TArray\20const&\2c\20GrXferBarrierFlags\29 +11687:GrGLGpu::onDumpJSON\28SkJSONWriter*\29\20const +11688:GrGLGpu::onCreateTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20int\2c\20skgpu::Budgeted\2c\20skgpu::Protected\2c\20int\2c\20unsigned\20int\2c\20std::__2::basic_string_view>\29 +11689:GrGLGpu::onCreateCompressedTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Budgeted\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20void\20const*\2c\20unsigned\20long\29 +11690:GrGLGpu::onCreateCompressedBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\29 +11691:GrGLGpu::onCreateBuffer\28unsigned\20long\2c\20GrGpuBufferType\2c\20GrAccessPattern\29 +11692:GrGLGpu::onCreateBackendTexture\28SkISize\2c\20GrBackendFormat\20const&\2c\20skgpu::Renderable\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20std::__2::basic_string_view>\29 +11693:GrGLGpu::onCopySurface\28GrSurface*\2c\20SkIRect\20const&\2c\20GrSurface*\2c\20SkIRect\20const&\2c\20SkFilterMode\29 +11694:GrGLGpu::onClearBackendTexture\28GrBackendTexture\20const&\2c\20sk_sp\2c\20std::__2::array\29 +11695:GrGLGpu::makeStencilAttachment\28GrBackendFormat\20const&\2c\20SkISize\2c\20int\29 +11696:GrGLGpu::makeSemaphore\28bool\29 +11697:GrGLGpu::makeMSAAAttachment\28SkISize\2c\20GrBackendFormat\20const&\2c\20int\2c\20skgpu::Protected\2c\20GrMemoryless\29 +11698:GrGLGpu::getPreferredStencilFormat\28GrBackendFormat\20const&\29 +11699:GrGLGpu::finishOutstandingGpuWork\28\29 +11700:GrGLGpu::endTimerQuery\28GrTimerQuery\20const&\29 +11701:GrGLGpu::disconnect\28GrGpu::DisconnectType\29 +11702:GrGLGpu::deleteBackendTexture\28GrBackendTexture\20const&\29 +11703:GrGLGpu::compile\28GrProgramDesc\20const&\2c\20GrProgramInfo\20const&\29 +11704:GrGLGpu::checkFinishedCallbacks\28\29 +11705:GrGLGpu::addFinishedCallback\28skgpu::AutoCallback\2c\20std::__2::optional\29 +11706:GrGLGpu::ProgramCache::~ProgramCache\28\29_11739 +11707:GrGLFunction::GrGLFunction\28void\20\28*\29\28unsigned\20int\2c\20unsigned\20int\2c\20float\29\29::'lambda'\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29::__invoke\28void\20const*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20float\29 +11708:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29::__invoke\28void\20const*\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20int\2c\20unsigned\20int\2c\20unsigned\20int\29 +11709:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\2c\20float\29 +11710:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\2c\20float\29 +11711:GrGLFunction::GrGLFunction\28void\20\28*\29\28int\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20int\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20int\2c\20float\2c\20float\29 +11712:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\2c\20float\2c\20float\2c\20float\29\29::'lambda'\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29::__invoke\28void\20const*\2c\20float\2c\20float\2c\20float\2c\20float\29 +11713:GrGLFunction::GrGLFunction\28void\20\28*\29\28float\29\29::'lambda'\28void\20const*\2c\20float\29::__invoke\28void\20const*\2c\20float\29 +11714:GrGLFunction::GrGLFunction\28void\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +11715:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28__GLsync*\2c\20unsigned\20int\2c\20unsigned\20int\2c\20unsigned\20int\29\29::'lambda'\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29::__invoke\28void\20const*\2c\20__GLsync*\2c\20unsigned\20int\2c\20int\2c\20int\29 +11716:GrGLFunction::GrGLFunction\28unsigned\20int\20\28*\29\28\29\29::'lambda'\28void\20const*\29::__invoke\28void\20const*\29 +11717:GrGLContext::~GrGLContext\28\29 +11718:GrGLCaps::~GrGLCaps\28\29_11526 +11719:GrGLCaps::surfaceSupportsReadPixels\28GrSurface\20const*\29\20const +11720:GrGLCaps::supportedWritePixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +11721:GrGLCaps::onSurfaceSupportsWritePixels\28GrSurface\20const*\29\20const +11722:GrGLCaps::onSupportsDynamicMSAA\28GrRenderTargetProxy\20const*\29\20const +11723:GrGLCaps::onSupportedReadPixelsColorType\28GrColorType\2c\20GrBackendFormat\20const&\2c\20GrColorType\29\20const +11724:GrGLCaps::onIsWindowRectanglesSupportedForRT\28GrBackendRenderTarget\20const&\29\20const +11725:GrGLCaps::onGetReadSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +11726:GrGLCaps::onGetDstSampleFlagsForProxy\28GrRenderTargetProxy\20const*\29\20const +11727:GrGLCaps::onGetDefaultBackendFormat\28GrColorType\29\20const +11728:GrGLCaps::onDumpJSON\28SkJSONWriter*\29\20const +11729:GrGLCaps::onCanCopySurface\28GrSurfaceProxy\20const*\2c\20SkIRect\20const&\2c\20GrSurfaceProxy\20const*\2c\20SkIRect\20const&\29\20const +11730:GrGLCaps::onAreColorTypeAndFormatCompatible\28GrColorType\2c\20GrBackendFormat\20const&\29\20const +11731:GrGLCaps::onApplyOptionsOverrides\28GrContextOptions\20const&\29 +11732:GrGLCaps::maxRenderTargetSampleCount\28GrBackendFormat\20const&\29\20const +11733:GrGLCaps::makeDesc\28GrRenderTarget*\2c\20GrProgramInfo\20const&\2c\20GrCaps::ProgramDescOverrideFlags\29\20const +11734:GrGLCaps::isFormatTexturable\28GrBackendFormat\20const&\2c\20GrTextureType\29\20const +11735:GrGLCaps::isFormatSRGB\28GrBackendFormat\20const&\29\20const +11736:GrGLCaps::isFormatRenderable\28GrBackendFormat\20const&\2c\20int\29\20const +11737:GrGLCaps::isFormatCopyable\28GrBackendFormat\20const&\29\20const +11738:GrGLCaps::isFormatAsColorTypeRenderable\28GrColorType\2c\20GrBackendFormat\20const&\2c\20int\29\20const +11739:GrGLCaps::getWriteSwizzle\28GrBackendFormat\20const&\2c\20GrColorType\29\20const +11740:GrGLCaps::getRenderTargetSampleCount\28int\2c\20GrBackendFormat\20const&\29\20const +11741:GrGLCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +11742:GrGLCaps::getBackendFormatFromCompressionType\28SkTextureCompressionType\29\20const +11743:GrGLCaps::computeFormatKey\28GrBackendFormat\20const&\29\20const +11744:GrGLBuffer::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +11745:GrGLBuffer::onUpdateData\28void\20const*\2c\20unsigned\20long\2c\20unsigned\20long\2c\20bool\29 +11746:GrGLBuffer::onUnmap\28GrGpuBuffer::MapType\29 +11747:GrGLBuffer::onSetLabel\28\29 +11748:GrGLBuffer::onRelease\28\29 +11749:GrGLBuffer::onMap\28GrGpuBuffer::MapType\29 +11750:GrGLBuffer::onClearToZero\28\29 +11751:GrGLBuffer::onAbandon\28\29 +11752:GrGLBackendTextureData::~GrGLBackendTextureData\28\29_11485 +11753:GrGLBackendTextureData::~GrGLBackendTextureData\28\29 +11754:GrGLBackendTextureData::isSameTexture\28GrBackendTextureData\20const*\29\20const +11755:GrGLBackendTextureData::getBackendFormat\28\29\20const +11756:GrGLBackendTextureData::equal\28GrBackendTextureData\20const*\29\20const +11757:GrGLBackendTextureData::copyTo\28SkAnySubclass&\29\20const +11758:GrGLBackendRenderTargetData::isProtected\28\29\20const +11759:GrGLBackendRenderTargetData::getBackendFormat\28\29\20const +11760:GrGLBackendRenderTargetData::equal\28GrBackendRenderTargetData\20const*\29\20const +11761:GrGLBackendRenderTargetData::copyTo\28SkAnySubclass&\29\20const +11762:GrGLBackendFormatData::toString\28\29\20const +11763:GrGLBackendFormatData::stencilBits\28\29\20const +11764:GrGLBackendFormatData::equal\28GrBackendFormatData\20const*\29\20const +11765:GrGLBackendFormatData::desc\28\29\20const +11766:GrGLBackendFormatData::copyTo\28SkAnySubclass&\29\20const +11767:GrGLBackendFormatData::compressionType\28\29\20const +11768:GrGLBackendFormatData::channelMask\28\29\20const +11769:GrGLBackendFormatData::bytesPerBlock\28\29\20const +11770:GrGLAttachment::~GrGLAttachment\28\29 +11771:GrGLAttachment::setMemoryBacking\28SkTraceMemoryDump*\2c\20SkString\20const&\29\20const +11772:GrGLAttachment::onSetLabel\28\29 +11773:GrGLAttachment::onRelease\28\29 +11774:GrGLAttachment::onAbandon\28\29 +11775:GrGLAttachment::backendFormat\28\29\20const +11776:GrFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11777:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11778:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onMakeProgramImpl\28\29\20const +11779:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11780:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11781:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::name\28\29\20const +11782:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11783:GrFragmentProcessor::SwizzleOutput\28std::__2::unique_ptr>\2c\20skgpu::Swizzle\20const&\29::SwizzleFragmentProcessor::clone\28\29\20const +11784:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11785:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::onMakeProgramImpl\28\29\20const +11786:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::name\28\29\20const +11787:GrFragmentProcessor::SurfaceColor\28\29::SurfaceColorProcessor::clone\28\29\20const +11788:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11789:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::onMakeProgramImpl\28\29\20const +11790:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::name\28\29\20const +11791:GrFragmentProcessor::HighPrecision\28std::__2::unique_ptr>\29::HighPrecisionFragmentProcessor::clone\28\29\20const +11792:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11793:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::onMakeProgramImpl\28\29\20const +11794:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::name\28\29\20const +11795:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11796:GrFragmentProcessor::DeviceSpace\28std::__2::unique_ptr>\29::DeviceSpace::clone\28\29\20const +11797:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11798:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::onMakeProgramImpl\28\29\20const +11799:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::name\28\29\20const +11800:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11801:GrFragmentProcessor::Compose\28std::__2::unique_ptr>\2c\20std::__2::unique_ptr>\29::ComposeProcessor::clone\28\29\20const +11802:GrFixedClip::~GrFixedClip\28\29_8851 +11803:GrFixedClip::~GrFixedClip\28\29 +11804:GrFixedClip::getConservativeBounds\28\29\20const +11805:GrExternalTextureGenerator::onGenerateTexture\28GrRecordingContext*\2c\20SkImageInfo\20const&\2c\20skgpu::Mipmapped\2c\20GrImageTexGenPolicy\29 +11806:GrDynamicAtlas::~GrDynamicAtlas\28\29_8825 +11807:GrDrawOp::usesStencil\28\29\20const +11808:GrDrawOp::usesMSAA\28\29\20const +11809:GrDrawOp::fixedFunctionFlags\28\29\20const +11810:GrDistanceFieldPathGeoProc::~GrDistanceFieldPathGeoProc\28\29_9774 +11811:GrDistanceFieldPathGeoProc::onTextureSampler\28int\29\20const +11812:GrDistanceFieldPathGeoProc::name\28\29\20const +11813:GrDistanceFieldPathGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11814:GrDistanceFieldPathGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11815:GrDistanceFieldPathGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11816:GrDistanceFieldPathGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11817:GrDistanceFieldLCDTextGeoProc::~GrDistanceFieldLCDTextGeoProc\28\29_9783 +11818:GrDistanceFieldLCDTextGeoProc::name\28\29\20const +11819:GrDistanceFieldLCDTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11820:GrDistanceFieldLCDTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11821:GrDistanceFieldLCDTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11822:GrDistanceFieldLCDTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11823:GrDistanceFieldA8TextGeoProc::~GrDistanceFieldA8TextGeoProc\28\29_9763 +11824:GrDistanceFieldA8TextGeoProc::name\28\29\20const +11825:GrDistanceFieldA8TextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11826:GrDistanceFieldA8TextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11827:GrDistanceFieldA8TextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11828:GrDistanceFieldA8TextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11829:GrDisableColorXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11830:GrDisableColorXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11831:GrDirectContext::~GrDirectContext\28\29_8633 +11832:GrDirectContext::init\28\29 +11833:GrDirectContext::abandonContext\28\29 +11834:GrDeferredProxyUploader::~GrDeferredProxyUploader\28\29_8019 +11835:GrCpuVertexAllocator::~GrCpuVertexAllocator\28\29_8844 +11836:GrCpuVertexAllocator::unlock\28int\29 +11837:GrCpuVertexAllocator::lock\28unsigned\20long\2c\20int\29 +11838:GrCpuBuffer::unref\28\29\20const +11839:GrCpuBuffer::ref\28\29\20const +11840:GrCoverageSetOpXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11841:GrCoverageSetOpXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11842:GrCopyRenderTask::~GrCopyRenderTask\28\29_8562 +11843:GrCopyRenderTask::onMakeSkippable\28\29 +11844:GrCopyRenderTask::onMakeClosed\28GrRecordingContext*\2c\20SkIRect*\29 +11845:GrCopyRenderTask::onExecute\28GrOpFlushState*\29 +11846:GrCopyRenderTask::gatherProxyIntervals\28GrResourceAllocator*\29\20const +11847:GrConvexPolyEffect::~GrConvexPolyEffect\28\29 +11848:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11849:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11850:GrConvexPolyEffect::onMakeProgramImpl\28\29\20const +11851:GrConvexPolyEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11852:GrConvexPolyEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11853:GrConvexPolyEffect::name\28\29\20const +11854:GrConvexPolyEffect::clone\28\29\20const +11855:GrContextThreadSafeProxy::~GrContextThreadSafeProxy\28\29_8539 +11856:GrContextThreadSafeProxy::isValidCharacterizationForVulkan\28sk_sp\2c\20bool\2c\20skgpu::Mipmapped\2c\20skgpu::Protected\2c\20bool\2c\20bool\29 +11857:GrConicEffect::name\28\29\20const +11858:GrConicEffect::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11859:GrConicEffect::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11860:GrConicEffect::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11861:GrConicEffect::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11862:GrColorSpaceXformEffect::~GrColorSpaceXformEffect\28\29_8503 +11863:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11864:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11865:GrColorSpaceXformEffect::onMakeProgramImpl\28\29\20const +11866:GrColorSpaceXformEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11867:GrColorSpaceXformEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11868:GrColorSpaceXformEffect::name\28\29\20const +11869:GrColorSpaceXformEffect::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11870:GrColorSpaceXformEffect::clone\28\29\20const +11871:GrCaps::getDstCopyRestrictions\28GrRenderTargetProxy\20const*\2c\20GrColorType\29\20const +11872:GrBitmapTextGeoProc::~GrBitmapTextGeoProc\28\29_9686 +11873:GrBitmapTextGeoProc::onTextureSampler\28int\29\20const +11874:GrBitmapTextGeoProc::name\28\29\20const +11875:GrBitmapTextGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11876:GrBitmapTextGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11877:GrBitmapTextGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11878:GrBitmapTextGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11879:GrBicubicEffect::onMakeProgramImpl\28\29\20const +11880:GrBicubicEffect::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11881:GrBicubicEffect::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11882:GrBicubicEffect::name\28\29\20const +11883:GrBicubicEffect::clone\28\29\20const +11884:GrBicubicEffect::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11885:GrBicubicEffect::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11886:GrAttachment::onGpuMemorySize\28\29\20const +11887:GrAttachment::getResourceType\28\29\20const +11888:GrAttachment::computeScratchKey\28skgpu::ScratchKey*\29\20const +11889:GrAtlasManager::~GrAtlasManager\28\29_11376 +11890:GrAtlasManager::postFlush\28skgpu::AtlasToken\29 +11891:GrAATriangulator::tessellate\28GrTriangulator::VertexList\20const&\2c\20GrTriangulator::Comparator\20const&\29 +11892:FontMgrRunIterator::~FontMgrRunIterator\28\29_12258 +11893:FontMgrRunIterator::consume\28\29 +11894:EllipticalRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11895:EllipticalRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11896:EllipticalRRectOp::name\28\29\20const +11897:EllipticalRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11898:EllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11899:EllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11900:EllipseOp::name\28\29\20const +11901:EllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11902:EllipseGeometryProcessor::name\28\29\20const +11903:EllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11904:EllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11905:EllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11906:Dual_Project +11907:DisableColorXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11908:DisableColorXP::name\28\29\20const +11909:DisableColorXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11910:DisableColorXP::makeProgramImpl\28\29\20const +11911:Direct_Move_Y +11912:Direct_Move_X +11913:Direct_Move_Orig_Y +11914:Direct_Move_Orig_X +11915:Direct_Move_Orig +11916:Direct_Move +11917:DefaultGeoProc::name\28\29\20const +11918:DefaultGeoProc::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11919:DefaultGeoProc::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11920:DefaultGeoProc::Impl::setData\28GrGLSLProgramDataManager\20const&\2c\20GrShaderCaps\20const&\2c\20GrGeometryProcessor\20const&\29 +11921:DefaultGeoProc::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11922:DIEllipseOp::~DIEllipseOp\28\29_10836 +11923:DIEllipseOp::visitProxies\28std::__2::function\20const&\29\20const +11924:DIEllipseOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11925:DIEllipseOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +11926:DIEllipseOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11927:DIEllipseOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11928:DIEllipseOp::name\28\29\20const +11929:DIEllipseOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11930:DIEllipseGeometryProcessor::name\28\29\20const +11931:DIEllipseGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11932:DIEllipseGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11933:DIEllipseGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11934:CustomXPFactory::makeXferProcessor\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11935:CustomXPFactory::analysisProperties\28GrProcessorAnalysisColor\20const&\2c\20GrProcessorAnalysisCoverage\20const&\2c\20GrCaps\20const&\2c\20GrClampType\29\20const +11936:CustomXP::xferBarrierType\28GrCaps\20const&\29\20const +11937:CustomXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11938:CustomXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11939:CustomXP::name\28\29\20const +11940:CustomXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11941:CustomXP::makeProgramImpl\28\29\20const +11942:Current_Ppem_Stretched +11943:Current_Ppem +11944:Cr_z_zcalloc +11945:CoverageSetOpXP::onGetBlendInfo\28skgpu::BlendInfo*\29\20const +11946:CoverageSetOpXP::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11947:CoverageSetOpXP::name\28\29\20const +11948:CoverageSetOpXP::makeProgramImpl\28\29\20const::Impl::emitOutputsForBlendState\28GrXferProcessor::ProgramImpl::EmitArgs\20const&\29 +11949:CoverageSetOpXP::makeProgramImpl\28\29\20const +11950:ColorTableEffect::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11951:ColorTableEffect::onMakeProgramImpl\28\29\20const +11952:ColorTableEffect::name\28\29\20const +11953:ColorTableEffect::clone\28\29\20const +11954:CircularRRectOp::visitProxies\28std::__2::function\20const&\29\20const +11955:CircularRRectOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11956:CircularRRectOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +11957:CircularRRectOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11958:CircularRRectOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11959:CircularRRectOp::name\28\29\20const +11960:CircularRRectOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11961:CircleOp::~CircleOp\28\29_10872 +11962:CircleOp::visitProxies\28std::__2::function\20const&\29\20const +11963:CircleOp::programInfo\28\29 +11964:CircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11965:CircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +11966:CircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11967:CircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11968:CircleOp::name\28\29\20const +11969:CircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11970:CircleGeometryProcessor::name\28\29\20const +11971:CircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11972:CircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11973:CircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11974:ButtCapper\28SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPath*\29 +11975:ButtCapDashedCircleOp::visitProxies\28std::__2::function\20const&\29\20const +11976:ButtCapDashedCircleOp::programInfo\28\29 +11977:ButtCapDashedCircleOp::onPrepareDraws\28GrMeshDrawTarget*\29 +11978:ButtCapDashedCircleOp::onExecute\28GrOpFlushState*\2c\20SkRect\20const&\29 +11979:ButtCapDashedCircleOp::onCreateProgramInfo\28GrCaps\20const*\2c\20SkArenaAlloc*\2c\20GrSurfaceProxyView\20const&\2c\20bool\2c\20GrAppliedClip&&\2c\20GrDstProxyView\20const&\2c\20GrXferBarrierFlags\2c\20GrLoadOp\29 +11980:ButtCapDashedCircleOp::onCombineIfPossible\28GrOp*\2c\20SkArenaAlloc*\2c\20GrCaps\20const&\29 +11981:ButtCapDashedCircleOp::name\28\29\20const +11982:ButtCapDashedCircleOp::finalize\28GrCaps\20const&\2c\20GrAppliedClip\20const*\2c\20GrClampType\29 +11983:ButtCapDashedCircleGeometryProcessor::name\28\29\20const +11984:ButtCapDashedCircleGeometryProcessor::makeProgramImpl\28GrShaderCaps\20const&\29\20const +11985:ButtCapDashedCircleGeometryProcessor::addToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11986:ButtCapDashedCircleGeometryProcessor::Impl::onEmitCode\28GrGeometryProcessor::ProgramImpl::EmitArgs&\2c\20GrGeometryProcessor::ProgramImpl::GrGPArgs*\29 +11987:BluntJoiner\28SkPath*\2c\20SkPath*\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20SkPoint\20const&\2c\20float\2c\20float\2c\20bool\2c\20bool\29 +11988:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::onSetData\28GrGLSLProgramDataManager\20const&\2c\20GrFragmentProcessor\20const&\29 +11989:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const::Impl::emitCode\28GrFragmentProcessor::ProgramImpl::EmitArgs&\29 +11990:BlendFragmentProcessor::onMakeProgramImpl\28\29\20const +11991:BlendFragmentProcessor::onIsEqual\28GrFragmentProcessor\20const&\29\20const +11992:BlendFragmentProcessor::onAddToKey\28GrShaderCaps\20const&\2c\20skgpu::KeyBuilder*\29\20const +11993:BlendFragmentProcessor::name\28\29\20const +11994:BlendFragmentProcessor::constantOutputForConstantInput\28SkRGBA4f<\28SkAlphaType\292>\20const&\29\20const +11995:BlendFragmentProcessor::clone\28\29\20const +11996:$_3::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +11997:$_2::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 +11998:$_1::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\2c\20unsigned\20char\29 +11999:$_0::__invoke\28unsigned\20char*\2c\20unsigned\20char\2c\20int\29 diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm_st.wasm b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm_st.wasm new file mode 100644 index 0000000000..5fbf1f5ee4 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/canvaskit/skwasm_st.wasm differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/favicon.png b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/favicon.png new file mode 100644 index 0000000000..b3a4cac781 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/favicon.png differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/flutter.js.map b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/flutter.js.map new file mode 100644 index 0000000000..fbd22bc4b4 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/flutter.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["src/browser_environment.js", "src/utils.js", "src/entrypoint_loader.js", "src/service_worker_loader.js", "src/trusted_types.js", "src/instantiate_wasm.js", "src/canvaskit_loader.js", "src/skwasm_loader.js", "src/loader.js", "src/flutter.js"], + "sourcesContent": ["// Copyright 2013 The Flutter Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nconst isBlink = () => {\n return (navigator.vendor === 'Google Inc.') ||\n (navigator.agent === 'Edg/');\n}\n\nconst hasImageCodecs = () => {\n if (typeof ImageDecoder === 'undefined') {\n return false;\n }\n // TODO(yjbanov): https://github.com/flutter/flutter/issues/122761\n // Frequently, when a browser launches an API that other browsers already\n // support, there are subtle incompatibilities that may cause apps to crash if,\n // we blindly adopt the new implementation. This check prevents us from picking\n // up potentially incompatible implementations of ImagdeDecoder API. Instead,\n // when a new browser engine launches the API, we'll evaluate it and enable it\n // explicitly.\n return isBlink();\n}\n\nconst hasChromiumBreakIterators = () => {\n return (typeof Intl.v8BreakIterator !== \"undefined\") &&\n (typeof Intl.Segmenter !== \"undefined\");\n}\n\nconst supportsWasmGC = () => {\n // This attempts to instantiate a wasm module that only will validate if the\n // final WasmGC spec is implemented in the browser.\n //\n // Copied from https://github.com/GoogleChromeLabs/wasm-feature-detect/blob/main/src/detectors/gc/index.js\n const bytes = [0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 95, 1, 120, 0];\n return WebAssembly.validate(new Uint8Array(bytes));\n}\n\n/**\n * @returns {import(\"./types\").BrowserEnvironment}\n */\nexport const browserEnvironment = {\n hasImageCodecs: hasImageCodecs(),\n hasChromiumBreakIterators: hasChromiumBreakIterators(),\n supportsWasmGC: supportsWasmGC(),\n crossOriginIsolated: window.crossOriginIsolated,\n};\n", "// Copyright 2013 The Flutter Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport function resolveUrlWithSegments(...segments) {\n return new URL(joinPathSegments(...segments), document.baseURI).toString()\n}\n\nfunction joinPathSegments(...segments) {\n return segments.filter((segment) => !!segment).map((segment, i) => {\n if (i === 0) {\n return stripRightSlashes(segment);\n } else {\n return stripLeftSlashes(stripRightSlashes(segment));\n }\n }).filter(x => x.length).join(\"/\")\n}\n\nfunction stripLeftSlashes(s) {\n let i = 0;\n while (i < s.length) {\n if (s.charAt(i) !== \"/\") {\n break;\n }\n i++;\n }\n return s.substring(i);\n}\n\nfunction stripRightSlashes(s) {\n let i = s.length;\n while (i > 0) {\n if (s.charAt(i - 1) !== \"/\") {\n break;\n }\n i--;\n }\n return s.substring(0, i);\n}\n\n/**\n * Calculates the proper base URL for CanvasKit/Skwasm assets.\n * \n * @param {import(\"./types\").FlutterConfiguration} config\n * @param {import(\"./types\").BuildConfig} buildConfig\n */\nexport function getCanvaskitBaseUrl(config, buildConfig) {\n if (config.canvasKitBaseUrl) {\n return config.canvasKitBaseUrl;\n }\n if (buildConfig.engineRevision && !buildConfig.useLocalCanvasKit) {\n return joinPathSegments(\"https://www.gstatic.com/flutter-canvaskit\", buildConfig.engineRevision);\n }\n return \"canvaskit\";\n}\n", "// Copyright 2013 The Flutter Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport { resolveUrlWithSegments } from \"./utils.js\";\n\n/**\n * Handles injecting the main Flutter web entrypoint (main.dart.js), and notifying\n * the user when Flutter is ready, through `didCreateEngineInitializer`.\n *\n * @see https://docs.flutter.dev/development/platform-integration/web/initialization\n */\nexport class FlutterEntrypointLoader {\n /**\n * Creates a FlutterEntrypointLoader.\n */\n constructor() {\n // Watchdog to prevent injecting the main entrypoint multiple times.\n this._scriptLoaded = false;\n }\n /**\n * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).\n * @param {TrustedTypesPolicy | undefined} policy\n */\n setTrustedTypesPolicy(policy) {\n this._ttPolicy = policy;\n }\n /**\n * @deprecated\n * Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a\n * user-specified `onEntrypointLoaded` callback with an EngineInitializer\n * object when it's done.\n *\n * @param {*} options\n * @returns {Promise | undefined} that will eventually resolve with an\n * EngineInitializer, or will be rejected with the error caused by the loader.\n * Returns undefined when an `onEntrypointLoaded` callback is supplied in `options`.\n */\n async loadEntrypoint(options) {\n const { entrypointUrl = resolveUrlWithSegments(\"main.dart.js\"), onEntrypointLoaded, nonce } =\n options || {};\n return this._loadJSEntrypoint(entrypointUrl, onEntrypointLoaded, nonce);\n }\n\n /**\n * Loads the entry point for a flutter application.\n * @param {import(\"./types\").ApplicationBuild} build\n * Information about the specific build that is to be loaded\n * @param {*} deps\n * External dependencies that may be needed to load the app.\n * @param {import(\"./types\").FlutterConfiguration} config\n * The application configuration. If no callback is specified, this will be\n * passed along to engine when initializing it.\n * @param {string} nonce\n * A nonce to apply to the main application script tag, if necessary.\n * @param {import(\"./types\").OnEntrypointLoadedCallback?} onEntrypointLoaded\n * An optional callback to invoke when the entrypoint is loaded. If no\n * callback is supplied, the engine initializer and app runner will be\n * automatically invoked on load, passing along the supplied flutter\n * configuration.\n */\n async load(build, deps, config, nonce, onEntrypointLoaded) {\n onEntrypointLoaded ??= (engineInitializer) => {\n engineInitializer.initializeEngine(config).then((appRunner) => appRunner.runApp())\n };\n const { entryPointBaseUrl } = config;\n if (build.compileTarget === \"dart2wasm\") {\n return this._loadWasmEntrypoint(build, deps, entryPointBaseUrl, onEntrypointLoaded);\n } else {\n const mainPath = build.mainJsPath ?? \"main.dart.js\";\n const entrypointUrl = resolveUrlWithSegments(entryPointBaseUrl, mainPath);\n return this._loadJSEntrypoint(entrypointUrl, onEntrypointLoaded, nonce);\n }\n }\n\n /**\n * Resolves the promise created by loadEntrypoint, and calls the `onEntrypointLoaded`\n * function supplied by the user (if needed).\n *\n * Called by Flutter through `_flutter.loader.didCreateEngineInitializer` method,\n * which is bound to the correct instance of the FlutterEntrypointLoader by\n * the FlutterLoader object.\n *\n * @param {Function} engineInitializer @see https://github.com/flutter/engine/blob/main/lib/web_ui/lib/src/engine/js_interop/js_loader.dart#L42\n */\n didCreateEngineInitializer(engineInitializer) {\n if (typeof this._didCreateEngineInitializerResolve === \"function\") {\n this._didCreateEngineInitializerResolve(engineInitializer);\n // Remove the resolver after the first time, so Flutter Web can hot restart.\n this._didCreateEngineInitializerResolve = null;\n // Make the engine revert to \"auto\" initialization on hot restart.\n delete _flutter.loader.didCreateEngineInitializer;\n }\n if (typeof this._onEntrypointLoaded === \"function\") {\n this._onEntrypointLoaded(engineInitializer);\n }\n }\n /**\n * Injects a script tag into the DOM, and configures this loader to be able to\n * handle the \"entrypoint loaded\" notifications received from Flutter web.\n *\n * @param {string} entrypointUrl the URL of the script that will initialize\n * Flutter.\n * @param {Function} onEntrypointLoaded a callback that will be called when\n * Flutter web notifies this object that the entrypoint is\n * loaded.\n * @returns {Promise | undefined} a Promise that resolves when the entrypoint\n * is loaded, or undefined if `onEntrypointLoaded`\n * is a function.\n */\n _loadJSEntrypoint(entrypointUrl, onEntrypointLoaded, nonce) {\n const useCallback = typeof onEntrypointLoaded === \"function\";\n if (!this._scriptLoaded) {\n this._scriptLoaded = true;\n const scriptTag = this._createScriptTag(entrypointUrl, nonce);\n if (useCallback) {\n // Just inject the script tag, and return nothing; Flutter will call\n // `didCreateEngineInitializer` when it's done.\n console.debug(\"Injecting + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/manifest.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/manifest.json new file mode 100644 index 0000000000..51a961196a --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "{{ cookiecutter.product_name }}", + "short_name": "{{ cookiecutter.project_name }}", + "start_url": ".", + "display": "standalone", + "background_color": "{{ cookiecutter.pwa_background_color }}", + "theme_color": "{{ cookiecutter.pwa_theme_color }}", + "description": "{{ cookiecutter.project_description }}", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/ffi.d.ts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/ffi.d.ts new file mode 100644 index 0000000000..a388e87d38 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/ffi.d.ts @@ -0,0 +1,1118 @@ +// Generated by dts-bundle-generator v8.1.2 + +export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; +interface PyProxy { + [x: string]: any; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` is an object that allows idiomatic use of a Python object from + * JavaScript. See :ref:`type-translations-pyproxy`. + */ +declare class PyProxy { + /** @private */ + $$flags: number; + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; + /** + * @hideconstructor + */ + constructor(); + /** @hidden */ + get [Symbol.toStringTag](): string; + /** + * The name of the type of the object. + * + * Usually the value is ``"module.name"`` but for builtins or + * interpreter-defined types it is just ``"name"``. As pseudocode this is: + * + * .. code-block:: python + * + * ty = type(x) + * if ty.__module__ == 'builtins' or ty.__module__ == "__main__": + * return ty.__name__ + * else: + * ty.__module__ + "." + ty.__name__ + * + */ + get type(): string; + /** + * Returns `str(o)` (unless `pyproxyToStringRepr: true` was passed to + * :js:func:`~globalThis.loadPyodide` in which case it will return `repr(o)`) + */ + toString(): string; + /** + * Destroy the :js:class:`~pyodide.ffi.PyProxy`. This will release the memory. Any further attempt + * to use the object will raise an error. + * + * In a browser supporting :js:data:`FinalizationRegistry`, Pyodide will + * automatically destroy the :js:class:`~pyodide.ffi.PyProxy` when it is garbage collected, however + * there is no guarantee that the finalizer will be run in a timely manner so + * it is better to destroy the proxy explicitly. + * + * @param options + * @param options.message The error message to print if use is attempted after + * destroying. Defaults to "Object has already been destroyed". + * + */ + destroy(options?: { + message?: string; + destroyRoundtrip?: boolean; + }): void; + /** + * Make a new :js:class:`~pyodide.ffi.PyProxy` pointing to the same Python object. + * Useful if the :js:class:`~pyodide.ffi.PyProxy` is destroyed somewhere else. + */ + copy(): PyProxy; + /** + * Converts the :js:class:`~pyodide.ffi.PyProxy` into a JavaScript object as best as possible. By + * default does a deep conversion, if a shallow conversion is desired, you can + * use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy + * ` for more info. + * @param options + * @return The JavaScript object resulting from the conversion. + */ + toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, }?: { + /** How many layers deep to perform the conversion. Defaults to infinite */ + depth?: number; + /** + * If provided, :js:meth:`toJs` will store all PyProxies created in this + * list. This allows you to easily destroy all the PyProxies by iterating + * the list without having to recurse over the generated structure. The most + * common use case is to create a new empty list, pass the list as + * ``pyproxies``, and then later iterate over ``pyproxies`` to destroy all of + * created proxies. + */ + pyproxies?: PyProxy[]; + /** + * If false, :js:meth:`toJs` will throw a + * :py:exc:`~pyodide.ffi.ConversionError` rather than producing a + * :js:class:`~pyodide.ffi.PyProxy`. + */ + create_pyproxies?: boolean; + /** + * A function to be called on an iterable of pairs ``[key, value]``. Convert + * this iterable of pairs to the desired output. For instance, + * :js:func:`Object.fromEntries` would convert the dict to an object, + * :js:func:`Array.from` converts it to an :js:class:`Array` of pairs, and + * ``(it) => new Map(it)`` converts it to a :js:class:`Map` (which is the + * default behavior). + */ + dict_converter?: (array: Iterable<[ + key: string, + value: any + ]>) => any; + /** + * Optional argument to convert objects with no default conversion. See the + * documentation of :meth:`~pyodide.ffi.to_js`. + */ + default_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any; + }): any; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a :meth:`~object.__len__` + * method. + */ +declare class PyProxyWithLength extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyProxyWithLength extends PyLengthMethods { +} +declare class PyLengthMethods { + /** + * The length of the object. + */ + get length(): number; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a + * :meth:`~object.__getitem__` method. + */ +declare class PyProxyWithGet extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyProxyWithGet extends PyGetItemMethods { +} +declare class PyGetItemMethods { + /** + * This translates to the Python code ``obj[key]``. + * + * @param key The key to look up. + * @returns The corresponding value. + */ + get(key: any): any; + /** + * Returns the object treated as a json adaptor. + * + * With a JsonAdaptor: + * 1. property access / modification / deletion is implemented with + * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and + * :meth:`~object.__delitem__` respectively. + * 2. If an attribute is accessed and the result implements + * :meth:`~object.__getitem__` then the result will also be a json + * adaptor. + * + * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an + * inverse to Python's :py:func:`json.loads`. + */ + asJsJson(): PyProxy & {}; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a + * :meth:`~object.__setitem__` or :meth:`~object.__delitem__` method. + */ +declare class PyProxyWithSet extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyProxyWithSet extends PySetItemMethods { +} +declare class PySetItemMethods { + /** + * This translates to the Python code ``obj[key] = value``. + * + * @param key The key to set. + * @param value The value to set it to. + */ + set(key: any, value: any): void; + /** + * This translates to the Python code ``del obj[key]``. + * + * @param key The key to delete. + */ + delete(key: any): void; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object has a + * :meth:`~object.__contains__` method. + */ +declare class PyProxyWithHas extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyProxyWithHas extends PyContainsMethods { +} +declare class PyContainsMethods { + /** + * This translates to the Python code ``key in obj``. + * + * @param key The key to check for. + * @returns Is ``key`` present? + */ + has(key: any): boolean; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is :std:term:`iterable` + * (i.e., it has an :meth:`~object.__iter__` method). + */ +declare class PyIterable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyIterable extends PyIterableMethods { +} +declare class PyIterableMethods { + /** + * This translates to the Python code ``iter(obj)``. Return an iterator + * associated to the proxy. See the documentation for + * :js:data:`Symbol.iterator`. + * + * This will be used implicitly by ``for(let x of proxy){}``. + */ + [Symbol.iterator](): Iterator; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is :std:term:`asynchronous + * iterable` (i.e., has an :meth:`~object.__aiter__` method). + */ +declare class PyAsyncIterable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyAsyncIterable extends PyAsyncIterableMethods { +} +declare class PyAsyncIterableMethods { + /** + * This translates to the Python code ``aiter(obj)``. Return an async iterator + * associated to the proxy. See the documentation for :js:data:`Symbol.asyncIterator`. + * + * This will be used implicitly by ``for(await let x of proxy){}``. + */ + [Symbol.asyncIterator](): AsyncIterator; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an :term:`iterator` + * (i.e., has a :meth:`~generator.send` or :meth:`~iterator.__next__` method). + */ +declare class PyIterator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyIterator extends PyIteratorMethods { +} +declare class PyIteratorMethods { + /** @private */ + [Symbol.iterator](): this; + /** + * This translates to the Python code ``next(obj)``. Returns the next value of + * the generator. See the documentation for :js:meth:`Generator.next` The + * argument will be sent to the Python generator. + * + * This will be used implicitly by ``for(let x of proxy){}``. + * + * @param arg The value to send to the generator. The value will be assigned + * as a result of a yield expression. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``next`` returns ``{done : false, value : + * some_value}``. When the generator raises a :py:exc:`StopIteration` + * exception, ``next`` returns ``{done : true, value : result_value}``. + */ + next(arg?: any): IteratorResult; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is a :std:term:`generator` + * (i.e., it is an instance of :py:class:`~collections.abc.Generator`). + */ +declare class PyGenerator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyGenerator extends PyGeneratorMethods { +} +declare class PyGeneratorMethods { + /** + * Throws an exception into the Generator. + * + * See the documentation for :js:meth:`Generator.throw`. + * + * @param exc Error The error to throw into the generator. Must be an + * instanceof ``Error``. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a + * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : + * true, value : result_value}``. + */ + throw(exc: any): IteratorResult; + /** + * Throws a :py:exc:`GeneratorExit` into the generator and if the + * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: + * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and + * returns or yields another value the next value of the generator this is + * returned in the normal way. If it throws some error other than + * :py:exc:`GeneratorExit` or :py:exc:`StopIteration`, that error is propagated. See + * the documentation for :js:meth:`Generator.return`. + * + * @param v The value to return from the generator. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a + * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : + * true, value : result_value}``. + */ + return(v: any): IteratorResult; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an + * :std:term:`asynchronous iterator` + */ +declare class PyAsyncIterator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyAsyncIterator extends PyAsyncIteratorMethods { +} +declare class PyAsyncIteratorMethods { + /** @private */ + [Symbol.asyncIterator](): this; + /** + * This translates to the Python code ``anext(obj)``. Returns the next value + * of the asynchronous iterator. The argument will be sent to the Python + * iterator (if it's a generator for instance). + * + * This will be used implicitly by ``for(let x of proxy){}``. + * + * @param arg The value to send to a generator. The value will be assigned as + * a result of a yield expression. + * @returns An Object with two properties: ``done`` and ``value``. When the + * iterator yields ``some_value``, ``next`` returns ``{done : false, value : + * some_value}``. When the giterator is done, ``next`` returns + * ``{done : true }``. + */ + next(arg?: any): Promise>; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an + * :std:term:`asynchronous generator` (i.e., it is an instance of + * :py:class:`~collections.abc.AsyncGenerator`) + */ +declare class PyAsyncGenerator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyAsyncGenerator extends PyAsyncGeneratorMethods { +} +declare class PyAsyncGeneratorMethods { + /** + * Throws an exception into the Generator. + * + * See the documentation for :js:meth:`AsyncGenerator.throw`. + * + * @param exc Error The error to throw into the generator. Must be an + * instanceof ``Error``. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a + * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : + * true, value : result_value}``. + */ + throw(exc: any): Promise>; + /** + * Throws a :py:exc:`GeneratorExit` into the generator and if the + * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: + * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and + * returns or yields another value the next value of the generator this is + * returned in the normal way. If it throws some error other than + * :py:exc:`GeneratorExit` or :py:exc:`StopAsyncIteration`, that error is + * propagated. See the documentation for :js:meth:`AsyncGenerator.throw` + * + * @param v The value to return from the generator. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a :py:exc:`StopAsyncIteration` + * exception, ``return`` returns ``{done : true, value : result_value}``. + */ + return(v: any): Promise>; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an + * :py:class:`~collections.abc.Sequence` (i.e., a :py:class:`list`) + */ +declare class PySequence extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PySequence extends PySequenceMethods { +} +declare class PySequenceMethods { + /** @hidden */ + get [Symbol.isConcatSpreadable](): boolean; + /** + * See :js:meth:`Array.join`. The :js:meth:`Array.join` method creates and + * returns a new string by concatenating all of the elements in the + * :py:class:`~collections.abc.Sequence`. + * + * @param separator A string to separate each pair of adjacent elements of the + * Sequence. + * + * @returns A string with all Sequence elements joined. + */ + join(separator?: string): string; + /** + * See :js:meth:`Array.slice`. The :js:meth:`Array.slice` method returns a + * shallow copy of a portion of a :py:class:`~collections.abc.Sequence` into a + * new array object selected from ``start`` to ``stop`` (`stop` not included) + * @param start Zero-based index at which to start extraction. Negative index + * counts back from the end of the Sequence. + * @param stop Zero-based index at which to end extraction. Negative index + * counts back from the end of the Sequence. + * @returns A new array containing the extracted elements. + */ + slice(start?: number, stop?: number): any; + /** + * See :js:meth:`Array.lastIndexOf`. Returns the last index at which a given + * element can be found in the Sequence, or -1 if it is not present. + * @param elt Element to locate in the Sequence. + * @param fromIndex Zero-based index at which to start searching backwards, + * converted to an integer. Negative index counts back from the end of the + * Sequence. + * @returns The last index of the element in the Sequence; -1 if not found. + */ + lastIndexOf(elt: any, fromIndex?: number): number; + /** + * See :js:meth:`Array.indexOf`. Returns the first index at which a given + * element can be found in the Sequence, or -1 if it is not present. + * @param elt Element to locate in the Sequence. + * @param fromIndex Zero-based index at which to start searching, converted to + * an integer. Negative index counts back from the end of the Sequence. + * @returns The first index of the element in the Sequence; -1 if not found. + */ + indexOf(elt: any, fromIndex?: number): number; + /** + * See :js:meth:`Array.forEach`. Executes a provided function once for each + * ``Sequence`` element. + * @param callbackfn A function to execute for each element in the ``Sequence``. Its + * return value is discarded. + * @param thisArg A value to use as ``this`` when executing ``callbackFn``. + */ + forEach(callbackfn: (elt: any) => void, thisArg?: any): void; + /** + * See :js:meth:`Array.map`. Creates a new array populated with the results of + * calling a provided function on every element in the calling ``Sequence``. + * @param callbackfn A function to execute for each element in the ``Sequence``. Its + * return value is added as a single element in the new array. + * @param thisArg A value to use as ``this`` when executing ``callbackFn``. + */ + map(callbackfn: (elt: any, index: number, array: any) => U, thisArg?: any): U[]; + /** + * See :js:meth:`Array.filter`. Creates a shallow copy of a portion of a given + * ``Sequence``, filtered down to just the elements from the given array that pass + * the test implemented by the provided function. + * @param predicate A function to execute for each element in the array. It + * should return a truthy value to keep the element in the resulting array, + * and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + */ + filter(predicate: (elt: any, index: number, array: any) => boolean, thisArg?: any): any[]; + /** + * See :js:meth:`Array.some`. Tests whether at least one element in the + * ``Sequence`` passes the test implemented by the provided function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate the element + * passes the test, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + */ + some(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; + /** + * See :js:meth:`Array.every`. Tests whether every element in the ``Sequence`` + * passes the test implemented by the provided function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate the element + * passes the test, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + */ + every(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; + /** + * See :js:meth:`Array.reduce`. Executes a user-supplied "reducer" callback + * function on each element of the Sequence, in order, passing in the return + * value from the calculation on the preceding element. The final result of + * running the reducer across all elements of the Sequence is a single value. + * @param callbackfn A function to execute for each element in the ``Sequence``. Its + * return value is discarded. + */ + reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue?: any): any; + /** + * See :js:meth:`Array.reduceRight`. Applies a function against an accumulator + * and each value of the Sequence (from right to left) to reduce it to a + * single value. + * @param callbackfn A function to execute for each element in the Sequence. + * Its return value is discarded. + */ + reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue: any): any; + /** + * See :js:meth:`Array.at`. Takes an integer value and returns the item at + * that index. + * @param index Zero-based index of the Sequence element to be returned, + * converted to an integer. Negative index counts back from the end of the + * Sequence. + * @returns The element in the Sequence matching the given index. + */ + at(index: number): any; + /** + * The :js:meth:`Array.concat` method is used to merge two or more arrays. + * This method does not change the existing arrays, but instead returns a new + * array. + * @param rest Arrays and/or values to concatenate into a new array. + * @returns A new Array instance. + */ + concat(...rest: ConcatArray[]): any[]; + /** + * The :js:meth:`Array.includes` method determines whether a Sequence + * includes a certain value among its entries, returning true or false as + * appropriate. + * @param elt + * @returns + */ + includes(elt: any): any; + /** + * The :js:meth:`Array.entries` method returns a new iterator object that + * contains the key/value pairs for each index in the ``Sequence``. + * @returns A new iterator object. + */ + entries(): IterableIterator<[ + number, + any + ]>; + /** + * The :js:meth:`Array.keys` method returns a new iterator object that + * contains the keys for each index in the ``Sequence``. + * @returns A new iterator object. + */ + keys(): IterableIterator; + /** + * The :js:meth:`Array.values` method returns a new iterator object that + * contains the values for each index in the ``Sequence``. + * @returns A new iterator object. + */ + values(): IterableIterator; + /** + * The :js:meth:`Array.find` method returns the first element in the provided + * array that satisfies the provided testing function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate a matching + * element has been found, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + * @returns The first element in the ``Sequence`` that satisfies the provided + * testing function. + */ + find(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): any; + /** + * The :js:meth:`Array.findIndex` method returns the index of the first + * element in the provided array that satisfies the provided testing function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate a matching + * element has been found, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + * @returns The index of the first element in the ``Sequence`` that satisfies + * the provided testing function. + */ + findIndex(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): number; + toJSON(this: any): unknown[]; + /** + * Returns the object treated as a json adaptor. + * + * With a JsonAdaptor: + * 1. property access / modification / deletion is implemented with + * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and + * :meth:`~object.__delitem__` respectively. + * 2. If an attribute is accessed and the result implements + * :meth:`~object.__getitem__` then the result will also be a json + * adaptor. + * + * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an + * inverse to Python's :py:func:`json.loads`. + */ + asJsJson(): PyProxy & {}; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is an + * :py:class:`~collections.abc.MutableSequence` (i.e., a :py:class:`list`) + */ +declare class PyMutableSequence extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyMutableSequence extends PyMutableSequenceMethods { +} +declare class PyMutableSequenceMethods { + /** + * The :js:meth:`Array.reverse` method reverses a :js:class:`PyMutableSequence` in + * place. + * @returns A reference to the same :js:class:`PyMutableSequence` + */ + reverse(): PyMutableSequence; + /** + * The :js:meth:`Array.sort` method sorts the elements of a + * :js:class:`PyMutableSequence` in place. + * @param compareFn A function that defines the sort order. + * @returns A reference to the same :js:class:`PyMutableSequence` + */ + sort(compareFn?: (a: any, b: any) => number): PyMutableSequence; + /** + * The :js:meth:`Array.splice` method changes the contents of a + * :js:class:`PyMutableSequence` by removing or replacing existing elements and/or + * adding new elements in place. + * @param start Zero-based index at which to start changing the + * :js:class:`PyMutableSequence`. + * @param deleteCount An integer indicating the number of elements in the + * :js:class:`PyMutableSequence` to remove from ``start``. + * @param items The elements to add to the :js:class:`PyMutableSequence`, beginning from + * ``start``. + * @returns An array containing the deleted elements. + */ + splice(start: number, deleteCount?: number, ...items: any[]): any[]; + /** + * The :js:meth:`Array.push` method adds the specified elements to the end of + * a :js:class:`PyMutableSequence`. + * @param elts The element(s) to add to the end of the :js:class:`PyMutableSequence`. + * @returns The new length property of the object upon which the method was + * called. + */ + push(...elts: any[]): any; + /** + * The :js:meth:`Array.pop` method removes the last element from a + * :js:class:`PyMutableSequence`. + * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the + * :js:class:`PyMutableSequence` is empty. + */ + pop(): any; + /** + * The :js:meth:`Array.shift` method removes the first element from a + * :js:class:`PyMutableSequence`. + * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the + * :js:class:`PyMutableSequence` is empty. + */ + shift(): any; + /** + * The :js:meth:`Array.unshift` method adds the specified elements to the + * beginning of a :js:class:`PyMutableSequence`. + * @param elts The elements to add to the front of the :js:class:`PyMutableSequence`. + * @returns The new length of the :js:class:`PyMutableSequence`. + */ + unshift(...elts: any[]): any; + /** + * The :js:meth:`Array.copyWithin` method shallow copies part of a + * :js:class:`PyMutableSequence` to another location in the same :js:class:`PyMutableSequence` + * without modifying its length. + * @param target Zero-based index at which to copy the sequence to. + * @param start Zero-based index at which to start copying elements from. + * @param end Zero-based index at which to end copying elements from. + * @returns The modified :js:class:`PyMutableSequence`. + */ + copyWithin(target: number, start?: number, end?: number): any; + /** + * The :js:meth:`Array.fill` method changes all elements in an array to a + * static value, from a start index to an end index. + * @param value Value to fill the array with. + * @param start Zero-based index at which to start filling. Default 0. + * @param end Zero-based index at which to end filling. Default + * ``list.length``. + * @returns + */ + fill(value: any, start?: number, end?: number): any; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is :ref:`awaitable + * ` (i.e., has an :meth:`~object.__await__` method). + */ +declare class PyAwaitable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyAwaitable extends Promise { +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is + * :std:term:`callable` (i.e., has an :py:meth:`~object.__call__` method). + */ +declare class PyCallable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyCallable; +} +interface PyCallable extends PyCallableMethods { + (...args: any[]): any; +} +declare class PyCallableMethods { + /** + * The ``apply()`` method calls the specified function with a given this + * value, and arguments provided as an array (or an array-like object). Like + * :js:meth:`Function.apply`. + * + * @param thisArg The ``this`` argument. Has no effect unless the + * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If + * :js:meth:`captureThis` is set, it will be passed as the first argument to + * the Python function. + * @param jsargs The array of arguments + * @returns The result from the function call. + */ + apply(thisArg: any, jsargs: any): any; + /** + * Calls the function with a given this value and arguments provided + * individually. See :js:meth:`Function.call`. + * + * @param thisArg The ``this`` argument. Has no effect unless the + * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If + * :js:meth:`captureThis` is set, it will be passed as the first argument to + * the Python function. + * @param jsargs The arguments + * @returns The result from the function call. + */ + call(thisArg: any, ...jsargs: any): any; + /** + * Call the Python function. The first parameter controls various parameters + * that change the way the call is performed. + * + * @param options + * @param options.kwargs If true, the last argument is treated as a collection + * of keyword arguments. + * @param options.promising If true, the call is made with stack switching + * enabled. Not needed if the callee is an async + * Python function. + * @param options.relaxed If true, extra arguments are ignored instead of + * raising a :py:exc:`TypeError`. + * @param jsargs Arguments to the Python function. + * @returns + */ + callWithOptions({ relaxed, kwargs, promising, }: { + relaxed?: boolean; + kwargs?: boolean; + promising?: boolean; + }, ...jsargs: any): any; + /** + * Call the function with keyword arguments. The last argument must be an + * object with the keyword arguments. + */ + callKwargs(...jsargs: any): any; + /** + * Call the function in a "relaxed" manner. Any extra arguments will be + * ignored. This matches the behavior of JavaScript functions more accurately. + * + * Any extra arguments will be ignored. This matches the behavior of + * JavaScript functions more accurately. Missing arguments are **NOT** filled + * with `None`. If too few arguments are passed, this will still raise a + * TypeError. + * + * This uses :py:func:`pyodide.code.relaxed_call`. + */ + callRelaxed(...jsargs: any): any; + /** + * Call the function with keyword arguments in a "relaxed" manner. The last + * argument must be an object with the keyword arguments. Any extra arguments + * will be ignored. This matches the behavior of JavaScript functions more + * accurately. + * + * Missing arguments are **NOT** filled with ``None``. If too few arguments are + * passed, this will still raise a :py:exc:`TypeError`. Also, if the same argument is + * passed as both a keyword argument and a positional argument, it will raise + * an error. + * + * This uses :py:func:`pyodide.code.relaxed_call`. + */ + callKwargsRelaxed(...jsargs: any): any; + /** + * Call the function with stack switching enabled. The last argument must be + * an object with the keyword arguments. Functions called this way can use + * :py:meth:`~pyodide.ffi.run_sync` to block until an + * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes + * with JS Promise integration. + * + * .. admonition:: Experimental + * :class: warning + * + * This feature is not yet stable. + * + * @experimental + */ + callPromising(...jsargs: any): Promise; + /** + * Call the function with stack switching enabled. The last argument must be + * an object with the keyword arguments. Functions called this way can use + * :py:meth:`~pyodide.ffi.run_sync` to block until an + * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes + * with JS Promise integration. + * + * .. admonition:: Experimental + * :class: warning + * + * This feature is not yet stable. + * + * @experimental + */ + callPromisingKwargs(...jsargs: any): Promise; + /** + * The ``bind()`` method creates a new function that, when called, has its + * ``this`` keyword set to the provided value, with a given sequence of + * arguments preceding any provided when the new function is called. See + * :js:meth:`Function.bind`. + * + * If the :js:class:`~pyodide.ffi.PyCallable` does not have + * :js:meth:`captureThis` set, the ``this`` parameter will be discarded. If it + * does have :js:meth:`captureThis` set, ``thisArg`` will be set to the first + * argument of the Python function. The returned proxy and the original proxy + * have the same lifetime so destroying either destroys both. + * + * @param thisArg The value to be passed as the ``this`` parameter to the + * target function ``func`` when the bound function is called. + * @param jsargs Extra arguments to prepend to arguments provided to the bound + * function when invoking ``func``. + * @returns + */ + bind(thisArg: any, ...jsargs: any): PyProxy; + /** + * Returns a :js:class:`~pyodide.ffi.PyProxy` that passes ``this`` as the first argument to the + * Python function. The returned :js:class:`~pyodide.ffi.PyProxy` has the internal ``captureThis`` + * property set. + * + * It can then be used as a method on a JavaScript object. The returned proxy + * and the original proxy have the same lifetime so destroying either destroys + * both. + * + * For example: + * + * .. code-block:: pyodide + * + * let obj = { a : 7 }; + * pyodide.runPython(` + * def f(self): + * return self.a + * `); + * // Without captureThis, it doesn't work to use f as a method for obj: + * obj.f = pyodide.globals.get("f"); + * obj.f(); // raises "TypeError: f() missing 1 required positional argument: 'self'" + * // With captureThis, it works fine: + * obj.f = pyodide.globals.get("f").captureThis(); + * obj.f(); // returns 7 + * + * @returns The resulting :js:class:`~pyodide.ffi.PyProxy`. It has the same lifetime as the + * original :js:class:`~pyodide.ffi.PyProxy` but passes ``this`` to the wrapped function. + * + */ + captureThis(): PyProxy; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object supports the + * Python :external:doc:`c-api/buffer`. + * + * Examples of buffers include {py:class}`bytes` objects and numpy + * {external+numpy:ref}`arrays`. + */ +declare class PyBuffer extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyBuffer; +} +interface PyBuffer extends PyBufferMethods { +} +declare class PyBufferMethods { + /** + * Get a view of the buffer data which is usable from JavaScript. No copy is + * ever performed. + * + * We do not support suboffsets, if the buffer requires suboffsets we will + * throw an error. JavaScript and array libraries can't handle suboffsets + * anyways. In this case, you should use the :js:meth:`~PyProxy.toJs` api or + * copy the buffer to one that doesn't use suboffsets (using e.g., + * :py:func:`numpy.ascontiguousarray`). + * + * If the buffer stores big endian data or half floats, this function will + * fail without an explicit type argument. For big endian data you can use + * :js:meth:`~PyProxy.toJs`. :js:class:`DataView` has support for big endian + * data, so you might want to pass ``'dataview'`` as the type argument in that + * case. + * + * @param type The type of the :js:attr:`~pyodide.ffi.PyBufferView.data` field + * in the output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, + * ``"i16"``, ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, + * ``"i64"``, ``"u64"``, ``"f32"``, ``"f64"``, or ``"dataview"``. This argument + * is optional, if absent :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will try + * to determine the appropriate output type based on the buffer format string + * (see :std:ref:`struct-format-strings`). + */ + getBuffer(type?: string): PyBufferView; +} +/** + * A :js:class:`~pyodide.ffi.PyProxy` whose proxied Python object is a :py:class:`dict`. + */ +declare class PyDict extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +interface PyDict extends PyProxyWithGet, PyProxyWithSet, PyProxyWithHas, PyProxyWithLength, PyIterable { +} +/** + * A class to allow access to Python data buffers from JavaScript. These are + * produced by :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` and cannot be constructed directly. + * When you are done, release it with the :js:func:`~PyBufferView.release` method. + * See the Python :external:doc:`c-api/buffer` documentation for more + * information. + * + * To find the element ``x[a_1, ..., a_n]``, you could use the following code: + * + * .. code-block:: js + * + * function multiIndexToIndex(pybuff, multiIndex) { + * if (multindex.length !== pybuff.ndim) { + * throw new Error("Wrong length index"); + * } + * let idx = pybuff.offset; + * for (let i = 0; i < pybuff.ndim; i++) { + * if (multiIndex[i] < 0) { + * multiIndex[i] = pybuff.shape[i] - multiIndex[i]; + * } + * if (multiIndex[i] < 0 || multiIndex[i] >= pybuff.shape[i]) { + * throw new Error("Index out of range"); + * } + * idx += multiIndex[i] * pybuff.stride[i]; + * } + * return idx; + * } + * console.log("entry is", pybuff.data[multiIndexToIndex(pybuff, [2, 0, -1])]); + * + * .. admonition:: Converting between TypedArray types + * :class: warning + * + * The following naive code to change the type of a typed array does not + * work: + * + * .. code-block:: js + * + * // Incorrectly convert a TypedArray. + * // Produces a Uint16Array that points to the entire WASM memory! + * let myarray = new Uint16Array(buffer.data.buffer); + * + * Instead, if you want to convert the output TypedArray, you need to say: + * + * .. code-block:: js + * + * // Correctly convert a TypedArray. + * let myarray = new Uint16Array( + * buffer.data.buffer, + * buffer.data.byteOffset, + * buffer.data.byteLength + * ); + */ +declare class PyBufferView { + /** + * The offset of the first entry of the array. For instance if our array + * is 3d, then you will find ``array[0,0,0]`` at + * ``pybuf.data[pybuf.offset]`` + */ + offset: number; + /** + * If the data is read only, you should not modify it. There is no way for us + * to enforce this, but it may cause very weird behavior. See + * :py:attr:`memoryview.readonly`. + */ + readonly: boolean; + /** + * The format string for the buffer. See :ref:`struct-format-strings` + * and :py:attr:`memoryview.format`. + */ + format: string; + /** + * How large is each entry in bytes? See :py:attr:`memoryview.itemsize`. + */ + itemsize: number; + /** + * The number of dimensions of the buffer. If ``ndim`` is 0, the buffer + * represents a single scalar or struct. Otherwise, it represents an + * array. See :py:attr:`memoryview.ndim`. + */ + ndim: number; + /** + * The total number of bytes the buffer takes up. This is equal to + * :js:attr:`buff.data.byteLength `. See + * :py:attr:`memoryview.nbytes`. + */ + nbytes: number; + /** + * The shape of the buffer, that is how long it is in each dimension. + * The length will be equal to ``ndim``. For instance, a 2x3x4 array + * would have shape ``[2, 3, 4]``. See :py:attr:`memoryview.shape`. + */ + shape: number[]; + /** + * An array of of length ``ndim`` giving the number of elements to skip + * to get to a new element in each dimension. See the example definition + * of a ``multiIndexToIndex`` function above. See :py:attr:`memoryview.strides`. + */ + strides: number[]; + /** + * The actual data. A typed array of an appropriate size backed by a segment + * of the WASM memory. + * + * The ``type`` argument of :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` determines + * which sort of :js:class:`TypedArray` or :js:class:`DataView` to return. By + * default :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will look at the format string + * to determine the most appropriate option. Most often the result is a + * :js:class:`Uint8Array`. + * + * .. admonition:: Contiguity + * :class: warning + * + * If the buffer is not contiguous, the :js:attr:`~PyBufferView.readonly` + * TypedArray will contain data that is not part of the buffer. Modifying + * this data leads to undefined behavior. + * + * .. admonition:: Read only buffers + * :class: warning + * + * If :js:attr:`buffer.readonly ` is ``true``, you + * should not modify the buffer. Modifying a read only buffer leads to + * undefined behavior. + * + */ + data: TypedArray; + /** + * Is it C contiguous? See :py:attr:`memoryview.c_contiguous`. + */ + c_contiguous: boolean; + /** + * Is it Fortran contiguous? See :py:attr:`memoryview.f_contiguous`. + */ + f_contiguous: boolean; + /** + * @private + */ + _released: boolean; + /** + * @private + */ + _view_ptr: number; + /** @private */ + constructor(); + /** + * Release the buffer. This allows the memory to be reclaimed. + */ + release(): void; +} +/** + * A JavaScript error caused by a Python exception. + * + * In order to reduce the risk of large memory leaks, the :js:class:`PythonError` + * contains no reference to the Python exception that caused it. You can find + * the actual Python exception that caused this error as + * :py:data:`sys.last_exc`. + * + * See :ref:`type translations of errors ` for more + * information. + * + * .. admonition:: Avoid leaking stack Frames + * :class: warning + * + * If you make a :js:class:`~pyodide.ffi.PyProxy` of + * :py:data:`sys.last_exc`, you should be especially careful to + * :js:meth:`~pyodide.ffi.PyProxy.destroy` it when you are done. You may leak a large + * amount of memory including the local variables of all the stack frames in + * the traceback if you don't. The easiest way is to only handle the + * exception in Python. + * + * @hideconstructor + */ +declare class PythonError extends Error { + /** + * The address of the error we are wrapping. We may later compare this + * against sys.last_exc. + * WARNING: we don't own a reference to this pointer, dereferencing it + * may be a use-after-free error! + * @private + */ + __error_address: number; + /** + * The name of the Python error class, e.g, :py:exc:`RuntimeError` or + * :py:exc:`KeyError`. + */ + type: string; + constructor(type: string, message: string, error_address: number); +} +/** + * Foreign function interface classes. Can be used for typescript type + * annotations or at runtime for `instanceof` checks. + * @summaryLink :ref:`ffi ` + * @hidetype + * @omitFromAutoModule + */ +declare const ffi: { + PyProxy: typeof PyProxy; + PyProxyWithLength: typeof PyProxyWithLength; + PyProxyWithGet: typeof PyProxyWithGet; + PyProxyWithSet: typeof PyProxyWithSet; + PyProxyWithHas: typeof PyProxyWithHas; + PyDict: typeof PyDict; + PyIterable: typeof PyIterable; + PyAsyncIterable: typeof PyAsyncIterable; + PyIterator: typeof PyIterator; + PyAsyncIterator: typeof PyAsyncIterator; + PyGenerator: typeof PyGenerator; + PyAsyncGenerator: typeof PyAsyncGenerator; + PyAwaitable: typeof PyAwaitable; + PyCallable: typeof PyCallable; + PyBuffer: typeof PyBuffer; + PyBufferView: typeof PyBufferView; + PythonError: typeof PythonError; + PySequence: typeof PySequence; + PyMutableSequence: typeof PyMutableSequence; +}; + +export type {}; +export type {PyAsyncGenerator, PyAsyncIterable, PyAsyncIterator, PyAwaitable, PyBuffer, PyBufferView, PyCallable, PyDict, PyGenerator, PyIterable, PyIterator, PyMutableSequence, PyProxy, PyProxyWithGet, PyProxyWithHas, PyProxyWithLength, PyProxyWithSet, PySequence, PythonError}; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/micropip-0.8.0-py3-none-any.whl b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/micropip-0.8.0-py3-none-any.whl new file mode 100644 index 0000000000..49a7cf3919 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/micropip-0.8.0-py3-none-any.whl differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/package.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/package.json new file mode 100644 index 0000000000..906a8c1ec8 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/package.json @@ -0,0 +1,137 @@ +{ + "name": "pyodide", + "version": "0.27.5", + "description": "The Pyodide JavaScript package", + "keywords": [ + "python", + "webassembly" + ], + "homepage": "https://github.com/pyodide/pyodide", + "repository": { + "type": "git", + "url": "https://github.com/pyodide/pyodide" + }, + "bugs": { + "url": "https://github.com/pyodide/pyodide/issues" + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/assert": "^1.5.6", + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.0", + "@types/node": "^20.8.4", + "@types/ws": "^8.5.3", + "chai": "^4.3.6", + "chai-as-promised": "^7.1.1", + "cross-env": "^7.0.3", + "dts-bundle-generator": "^8.1.1", + "esbuild": "^0.17.12", + "express": "^4.17.3", + "mocha": "^9.0.2", + "npm-run-all": "^4.1.5", + "nyc": "^15.1.0", + "prettier": "^2.2.1", + "sinon": "^18.0.0", + "ts-mocha": "^9.0.2", + "tsd": "^0.24.1", + "typedoc": "^0.27.6", + "typescript": "5.7", + "wabt": "^1.0.32" + }, + "main": "pyodide.js", + "exports": { + ".": { + "types": "./pyodide.d.ts", + "require": "./pyodide.js", + "import": "./pyodide.mjs" + }, + "./ffi": { + "types": "./ffi.d.ts" + }, + "./pyodide.asm.wasm": "./pyodide.asm.wasm", + "./pyodide.asm.js": "./pyodide.asm.js", + "./python_stdlib.zip": "./python_stdlib.zip", + "./pyodide.mjs": "./pyodide.mjs", + "./pyodide.js": "./pyodide.js", + "./package.json": "./package.json", + "./pyodide-lock.json": "./pyodide-lock.json" + }, + "files": [ + "pyodide.asm.js", + "pyodide.asm.wasm", + "python_stdlib.zip", + "pyodide.mjs", + "pyodide.js.map", + "pyodide.mjs.map", + "pyodide.d.ts", + "ffi.d.ts", + "pyodide-lock.json", + "console.html" + ], + "browser": { + "child_process": false, + "crypto": false, + "fs": false, + "fs/promises": false, + "path": false, + "url": false, + "vm": false, + "ws": false + }, + "scripts": { + "build-inner": "node esbuild.config.inner.mjs", + "build": "tsc --noEmit && node esbuild.config.outer.mjs", + "test": "npm-run-all test:*", + "test:unit": "cross-env TEST_NODE=1 ts-mocha --node-option=experimental-loader=./test/loader.mjs --node-option=experimental-wasm-stack-switching -p tsconfig.test.json \"test/unit/**\"", + "test:node": "cross-env TEST_NODE=1 mocha test/integration/**/*.test.js", + "test:browser": "mocha test/integration/**/*.test.js", + "tsc": "tsc --noEmit", + "coverage": "cross-env TEST_NODE=1 npm-run-all coverage:*", + "coverage:build": "nyc npm run test:node" + }, + "mocha": { + "bail": false, + "timeout": 30000, + "full-trace": true, + "inline-diffs": true, + "check-leaks": false, + "global": [ + "pyodide", + "page", + "chai" + ] + }, + "nyc": { + "reporter": [ + "html", + "text-summary" + ], + "include": [ + "*.ts" + ], + "all": true, + "clean": true, + "cache": false, + "instrument": false, + "checkCoverage": true, + "statements": 95, + "functions": 95, + "branches": 80, + "lines": 95 + }, + "tsd": { + "compilerOptions": { + "lib": [ + "ES2017", + "DOM" + ] + } + }, + "dependencies": { + "ws": "^8.5.0" + }, + "types": "./pyodide.d.ts", + "engines": { + "node": ">=18.0.0" + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/packaging-24.2-py3-none-any.whl b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/packaging-24.2-py3-none-any.whl new file mode 100644 index 0000000000..ff72069a11 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/packaging-24.2-py3-none-any.whl differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide-lock.json b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide-lock.json new file mode 100644 index 0000000000..1190ca7f0c --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide-lock.json @@ -0,0 +1 @@ +{"info": {"abi_version": "2024_0", "arch": "wasm32", "platform": "emscripten_3_1_58", "python": "3.12.7", "version": "0.27.5"}, "packages": {"affine": {"depends": [], "file_name": "affine-2.4.0-py3-none-any.whl", "imports": ["affine"], "install_dir": "site", "name": "affine", "package_type": "package", "sha256": "8664b50346c876731c19b3a653654aff16f7401124b47c541f6c90113c5409a2", "unvendored_tests": true, "version": "2.4.0"}, "affine-tests": {"depends": ["affine"], "file_name": "affine-tests.tar", "imports": [], "install_dir": "site", "name": "affine-tests", "package_type": "package", "sha256": "873f12fdb2b589cf64615b4e618b79a4cc515c7d457bd13279a8733f0e0cb452", "unvendored_tests": false, "version": "2.4.0"}, "aiohttp": {"depends": ["aiosignal", "async-timeout", "attrs", "charset-normalizer", "frozenlist", "multidict", "yarl"], "file_name": "aiohttp-3.9.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["aiohttp"], "install_dir": "site", "name": "aiohttp", "package_type": "package", "sha256": "525acb77c54a1fa13b61910fa92ac99b642ea3703667aad6ece9a64a48fb7fa2", "unvendored_tests": true, "version": "3.9.5"}, "aiohttp-tests": {"depends": ["aiohttp"], "file_name": "aiohttp-tests.tar", "imports": [], "install_dir": "site", "name": "aiohttp-tests", "package_type": "package", "sha256": "7af84003adb3fe8ffbaddebdd5e483d050a203afd21f2f518b608eea1855c0a9", "unvendored_tests": false, "version": "3.9.5"}, "aiosignal": {"depends": ["frozenlist"], "file_name": "aiosignal-1.3.1-py3-none-any.whl", "imports": ["aiosignal"], "install_dir": "site", "name": "aiosignal", "package_type": "package", "sha256": "5d8a73d0605b5edb2365ef24b43e4afcd3269e1b770e40cc06a1cf04bf2553bc", "unvendored_tests": false, "version": "1.3.1"}, "altair": {"depends": ["typing-extensions", "jinja2", "jsonschema", "packaging", "narwhals"], "file_name": "altair-5.4.1-py3-none-any.whl", "imports": ["altair"], "install_dir": "site", "name": "altair", "package_type": "package", "sha256": "9b02dba3e478b65fd2218167a1f2b900cec14552cf9061d5ee3ed406100df5e8", "unvendored_tests": false, "version": "5.4.1"}, "annotated-types": {"depends": [], "file_name": "annotated_types-0.6.0-py3-none-any.whl", "imports": ["annotated_types"], "install_dir": "site", "name": "annotated-types", "package_type": "package", "sha256": "811e9db4c6797c002a47c152310f17f4a737a89c484a1a12a4771c0ca80cf676", "unvendored_tests": true, "version": "0.6.0"}, "annotated-types-tests": {"depends": ["annotated-types"], "file_name": "annotated-types-tests.tar", "imports": [], "install_dir": "site", "name": "annotated-types-tests", "package_type": "package", "sha256": "954d31773ac7f2c9d762f4d759e9c4f69ac17365ec5515116bb31b10586ae845", "unvendored_tests": false, "version": "0.6.0"}, "anyio": {"depends": ["ssl", "sniffio", "typing-extensions"], "file_name": "anyio-4.9.0-py3-none-any.whl", "imports": ["anyio"], "install_dir": "site", "name": "anyio", "package_type": "package", "sha256": "6d613e50e4e7f92c83ae41042232824c82d87e594ebc41a28a5a9fc490cf81c9", "unvendored_tests": false, "version": "4.9.0"}, "apsw": {"depends": [], "file_name": "apsw-3.47.2.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["apsw"], "install_dir": "site", "name": "apsw", "package_type": "package", "sha256": "65feeaa90d231946953b87f17ad5a2ddb37e456826ad0d68aef7c41e4c431cd1", "unvendored_tests": false, "version": "3.47.2.0"}, "argon2-cffi": {"depends": ["argon2-cffi-bindings"], "file_name": "argon2_cffi-23.1.0-py3-none-any.whl", "imports": ["argon2"], "install_dir": "site", "name": "argon2-cffi", "package_type": "package", "sha256": "cd2c6077e876673af831c66a3b4e870a6c9f560104f7b22e724473d49cd15933", "unvendored_tests": false, "version": "23.1.0"}, "argon2-cffi-bindings": {"depends": ["cffi"], "file_name": "argon2_cffi_bindings-21.2.0-cp312-abi3-pyodide_2024_0_wasm32.whl", "imports": ["_argon2_cffi_bindings"], "install_dir": "site", "name": "argon2-cffi-bindings", "package_type": "package", "sha256": "79d4022c67ceab5b569b6fd184db3cde4e410cc497440c25e672471dbe7b0078", "unvendored_tests": false, "version": "21.2.0"}, "arrow3-compute": {"depends": ["arrow3-core"], "file_name": "arrow3_compute-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["arrow3.compute"], "install_dir": "site", "name": "arrow3-compute", "package_type": "package", "sha256": "b851a0c77fc090e435ce03d34a15013adc4b1c41795b5ae10ab88b61730603b5", "unvendored_tests": false, "version": "0.4.1"}, "arrow3-core": {"depends": [], "file_name": "arrow3_core-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["arrow3.core"], "install_dir": "site", "name": "arrow3-core", "package_type": "package", "sha256": "a51d3bf71f8369e8026c17d3b412952a17d0006bfac162de6e644ab73a72e42c", "unvendored_tests": false, "version": "0.4.1"}, "arrow3-io": {"depends": ["arrow3-core"], "file_name": "arrow3_io-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["arrow3.io"], "install_dir": "site", "name": "arrow3-io", "package_type": "package", "sha256": "4e5353d748ef3ce8a46b7f3c0bb42e30dd66d7efcf22c5da2d0d1a27f548f86d", "unvendored_tests": false, "version": "0.4.1"}, "asciitree": {"depends": [], "file_name": "asciitree-0.3.3-py3-none-any.whl", "imports": ["asciitree"], "install_dir": "site", "name": "asciitree", "package_type": "package", "sha256": "bb9d09a3a2f8a9e5910e38643ba977b27c9b3d8551ecbf6712d0b0882eaeaa9f", "unvendored_tests": false, "version": "0.3.3"}, "astropy": {"depends": ["packaging", "numpy", "pyerfa", "pyyaml", "astropy_iers_data"], "file_name": "astropy-7.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["astropy"], "install_dir": "site", "name": "astropy", "package_type": "package", "sha256": "682ea08184550b45d01163b930de73ca6adc85972359b28c9e3723b1731e1ad6", "unvendored_tests": false, "version": "7.0.0"}, "astropy-iers-data": {"depends": [], "file_name": "astropy_iers_data-0.2024.4.22.0.29.50-py3-none-any.whl", "imports": ["astropy_iers_data"], "install_dir": "site", "name": "astropy_iers_data", "package_type": "package", "sha256": "a60d0d63ac7fd7567e9fe4fb39766eaf51028c359d09ce89aa404ab29a4173ef", "unvendored_tests": true, "version": "0.2024.4.22.0.29.50"}, "astropy-iers-data-tests": {"depends": ["astropy_iers_data"], "file_name": "astropy-iers-data-tests.tar", "imports": [], "install_dir": "site", "name": "astropy_iers_data-tests", "package_type": "package", "sha256": "e3c96bf55b465d5638d2c8dbb501cb84f118173f0ee40e055c0dfdd62f856e6e", "unvendored_tests": false, "version": "0.2024.4.22.0.29.50"}, "asttokens": {"depends": ["six"], "file_name": "asttokens-2.4.1-py2.py3-none-any.whl", "imports": ["asttokens"], "install_dir": "site", "name": "asttokens", "package_type": "package", "sha256": "f84fe88eb7d9fad1e04ed388ee09375b8b0ad4c57df56e8de866dcc544eca32e", "unvendored_tests": false, "version": "2.4.1"}, "async-timeout": {"depends": [], "file_name": "async_timeout-4.0.3-py3-none-any.whl", "imports": ["async_timeout"], "install_dir": "site", "name": "async-timeout", "package_type": "package", "sha256": "bd2d99debcceae37ee98542b06eec79460dff524f6b4e97ecdadfc9bd621381e", "unvendored_tests": false, "version": "4.0.3"}, "atomicwrites": {"depends": [], "file_name": "atomicwrites-1.4.1-py2.py3-none-any.whl", "imports": ["atomicwrites"], "install_dir": "site", "name": "atomicwrites", "package_type": "package", "sha256": "2420cf72ee45bc38cdc653530c1f98c5c9914cf3fe6cdff81d83fc30a9385d50", "unvendored_tests": false, "version": "1.4.1"}, "attrs": {"depends": ["six"], "file_name": "attrs-23.2.0-py3-none-any.whl", "imports": ["attr", "attrs"], "install_dir": "site", "name": "attrs", "package_type": "package", "sha256": "cc48953205b2bf4e65d01bbe4c13717b0bf4d504dea9c4666a7a99997e952f3e", "unvendored_tests": false, "version": "23.2.0"}, "autograd": {"depends": ["numpy", "future"], "file_name": "autograd-1.7.0-py3-none-any.whl", "imports": ["autograd"], "install_dir": "site", "name": "autograd", "package_type": "package", "sha256": "b7e73219111580195e174d014d0aa0873c6c1501011764db65f8741544faabdb", "unvendored_tests": true, "version": "1.7.0"}, "autograd-tests": {"depends": ["autograd"], "file_name": "autograd-tests.tar", "imports": [], "install_dir": "site", "name": "autograd-tests", "package_type": "package", "sha256": "6cb9c01180d47303fc87f335de4056b95ccb9cad987c7f257bd8e150eac1c967", "unvendored_tests": false, "version": "1.7.0"}, "awkward-cpp": {"depends": ["numpy"], "file_name": "awkward_cpp-44-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["awkward_cpp"], "install_dir": "site", "name": "awkward-cpp", "package_type": "package", "sha256": "6c09227fa07de34303fc24f32ba781f9f9df0ace163f85b9cae6717dd06c2fcd", "unvendored_tests": false, "version": "44"}, "b2d": {"depends": ["numpy", "pydantic", "setuptools", "annotated-types"], "file_name": "b2d-0.7.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["b2d"], "install_dir": "site", "name": "b2d", "package_type": "package", "sha256": "5f94377c9f7c56c28d04d4ffa806e3c334479b11d2a4a48842b359a62fdbe1e3", "unvendored_tests": false, "version": "0.7.4"}, "bcrypt": {"depends": [], "file_name": "bcrypt-4.1.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["bcrypt"], "install_dir": "site", "name": "bcrypt", "package_type": "package", "sha256": "77841a73cac8764f91608b5632c6687332c7ffaf937c9b3933022b57d6ee2fe7", "unvendored_tests": false, "version": "4.1.2"}, "beautifulsoup4": {"depends": ["soupsieve"], "file_name": "beautifulsoup4-4.12.3-py3-none-any.whl", "imports": ["bs4"], "install_dir": "site", "name": "beautifulsoup4", "package_type": "package", "sha256": "833d93af8a8b878ab9a853b243692c992c0fa74d9c4af66bb6245b43da5041a9", "unvendored_tests": true, "version": "4.12.3"}, "beautifulsoup4-tests": {"depends": ["beautifulsoup4"], "file_name": "beautifulsoup4-tests.tar", "imports": [], "install_dir": "site", "name": "beautifulsoup4-tests", "package_type": "package", "sha256": "a688d7c95428719476e776daf15b6645de61bdf2936cd7cdc44542b18cc9cb60", "unvendored_tests": false, "version": "4.12.3"}, "biopython": {"depends": ["numpy"], "file_name": "biopython-1.84-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["Bio", "BioSQL"], "install_dir": "site", "name": "biopython", "package_type": "package", "sha256": "2765e3ae36d32f47522218e61a8192c34a02aecf530bcb8d2bab090946422c3b", "unvendored_tests": false, "version": "1.84"}, "bitarray": {"depends": [], "file_name": "bitarray-2.9.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["bitarray"], "install_dir": "site", "name": "bitarray", "package_type": "package", "sha256": "f3140c49b6ab7a7486c803c00dfaea227e21c4035fa037341decadb5897fd57f", "unvendored_tests": true, "version": "2.9.2"}, "bitarray-tests": {"depends": ["bitarray"], "file_name": "bitarray-tests.tar", "imports": [], "install_dir": "site", "name": "bitarray-tests", "package_type": "package", "sha256": "504d9e3ecf394a18aabb6458bf4e16736cd12ade28c166043e90961a6afd2de1", "unvendored_tests": false, "version": "2.9.2"}, "bitstring": {"depends": ["bitarray"], "file_name": "bitstring-4.1.4-py3-none-any.whl", "imports": ["bitstring"], "install_dir": "site", "name": "bitstring", "package_type": "package", "sha256": "fa1e4377b88991ea78fd52dac0a20fffe9a28b81fbb98a98d1fb63b2309ab0e2", "unvendored_tests": false, "version": "4.1.4"}, "bleach": {"depends": ["webencodings", "packaging", "six"], "file_name": "bleach-6.1.0-py3-none-any.whl", "imports": ["bleach"], "install_dir": "site", "name": "bleach", "package_type": "package", "sha256": "4fd87e4ab3ade4db5f18bbbb62e1ee75f1a3d52f2baad5cc90b9eac29d5e4c56", "unvendored_tests": false, "version": "6.1.0"}, "bokeh": {"depends": ["contourpy", "numpy", "jinja2", "pandas", "pillow", "python-dateutil", "six", "typing-extensions", "pyyaml", "xyzservices"], "file_name": "bokeh-3.6.0-py3-none-any.whl", "imports": ["bokeh"], "install_dir": "site", "name": "bokeh", "package_type": "package", "sha256": "783240ea3bbdc12668e9615793cf69fe13e492c4a9b6ef2ea673ebdf12eafaff", "unvendored_tests": false, "version": "3.6.0"}, "boost-histogram": {"depends": ["numpy"], "file_name": "boost_histogram-1.5.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["boost_histogram"], "install_dir": "site", "name": "boost-histogram", "package_type": "package", "sha256": "5ecfa92eafc508344929b87a347e769ce42ef0971990765711b019c6c516b54d", "unvendored_tests": false, "version": "1.5.0"}, "brotli": {"depends": [], "file_name": "brotli-1.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["brotli"], "install_dir": "site", "name": "brotli", "package_type": "package", "sha256": "2dd23510bd7854896c20cc64808113b12184c40dfc76b7754e21bce937b6a9f2", "unvendored_tests": false, "version": "1.1.0"}, "buffer-test": {"depends": [], "file_name": "buffer_test-0.1.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["buffer_test"], "install_dir": "site", "name": "buffer-test", "package_type": "package", "sha256": "5c19c1ced70b59966bbd67356487d45ee5d19cd5b348db39dc482678b4e29334", "unvendored_tests": false, "version": "0.1.1"}, "cachetools": {"depends": [], "file_name": "cachetools-5.3.3-py3-none-any.whl", "imports": ["cachetools"], "install_dir": "site", "name": "cachetools", "package_type": "package", "sha256": "43008ed4fdec28d325a0061bb027e248326213cd298c51fe31994de5ac115e48", "unvendored_tests": false, "version": "5.3.3"}, "cartopy": {"depends": ["shapely", "pyshp", "pyproj", "geos", "matplotlib", "scipy"], "file_name": "cartopy-0.24.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cartopy"], "install_dir": "site", "name": "Cartopy", "package_type": "package", "sha256": "a60d719d0dcf30e21d224807f91eafbc120f1dde8445b0cef2b87ae8e716b223", "unvendored_tests": true, "version": "0.24.1"}, "cartopy-tests": {"depends": ["Cartopy"], "file_name": "cartopy-tests.tar", "imports": [], "install_dir": "site", "name": "Cartopy-tests", "package_type": "package", "sha256": "909e73dc61061f76a6b4e1ab8030c9ccb2c02b9f4bfcc09ae811a516b3171297", "unvendored_tests": false, "version": "0.24.1"}, "casadi": {"depends": ["numpy"], "file_name": "casadi-3.6.7-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["casadi"], "install_dir": "site", "name": "casadi", "package_type": "package", "sha256": "2dffc33ea7061706e5c120db3e1bc46a67048515698d2d8a484a0ce8f38b6310", "unvendored_tests": false, "version": "3.6.7"}, "cbor-diag": {"depends": [], "file_name": "cbor_diag-1.0.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cbor_diag"], "install_dir": "site", "name": "cbor-diag", "package_type": "package", "sha256": "5c40982470d04f536be36f5ae69072ae7635f4c1d12f8ca5c127cac1d8741502", "unvendored_tests": false, "version": "1.0.1"}, "certifi": {"depends": [], "file_name": "certifi-2024.12.14-py3-none-any.whl", "imports": ["certifi"], "install_dir": "site", "name": "certifi", "package_type": "package", "sha256": "8d8cdc7cb6076c96663158adc25e0313cda14692c4d0e8ebdb7571bd8835c381", "unvendored_tests": false, "version": "2024.12.14"}, "cffi": {"depends": ["pycparser"], "file_name": "cffi-1.17.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cffi"], "install_dir": "site", "name": "cffi", "package_type": "package", "sha256": "e63b1be17f345759089c983584abc1fde327c0eed326d00323fc8d7d4285c847", "unvendored_tests": false, "version": "1.17.1"}, "cffi-example": {"depends": ["cffi"], "file_name": "cffi_example-0.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cffi_example"], "install_dir": "site", "name": "cffi_example", "package_type": "package", "sha256": "7f608ef6af0f81747788e537029e4765596b641024fd047947107d072194de34", "unvendored_tests": false, "version": "0.1"}, "cftime": {"depends": ["numpy"], "file_name": "cftime-1.6.4.post1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cftime"], "install_dir": "site", "name": "cftime", "package_type": "package", "sha256": "df3171ba26918bab999d2c8ccf1b0db9f1bd6172348a33afd10ff72a1907e88b", "unvendored_tests": false, "version": "1.6.4.post1"}, "charset-normalizer": {"depends": [], "file_name": "charset_normalizer-3.3.2-py3-none-any.whl", "imports": ["charset_normalizer"], "install_dir": "site", "name": "charset-normalizer", "package_type": "package", "sha256": "3511099b514ade7fee4d7b866fd3d7739109e52d92126042312d7b3b38bb6eb3", "unvendored_tests": false, "version": "3.3.2"}, "clarabel": {"depends": ["numpy", "scipy"], "file_name": "clarabel-0.9.0-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["clarabel"], "install_dir": "site", "name": "clarabel", "package_type": "package", "sha256": "58da94dfa24e945d6a6e1a1bc70ddfe585029d086c0deaf186dd9ac1a1957959", "unvendored_tests": false, "version": "0.9.0"}, "click": {"depends": [], "file_name": "click-8.1.7-py3-none-any.whl", "imports": ["click"], "install_dir": "site", "name": "click", "package_type": "package", "sha256": "4221f083126ac0557d5c826d5ac72595a16b7f24fe8d0be8fae6673a0b0225d1", "unvendored_tests": false, "version": "8.1.7"}, "cligj": {"depends": ["click"], "file_name": "cligj-0.7.2-py3-none-any.whl", "imports": ["cligj"], "install_dir": "site", "name": "cligj", "package_type": "package", "sha256": "870a33f01ca6d041c640c9dadb3e38c1bf6f8bc32c53f20195553c56cd4516e2", "unvendored_tests": false, "version": "0.7.2"}, "clingo": {"depends": ["cffi"], "file_name": "clingo-5.7.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["clingo"], "install_dir": "site", "name": "clingo", "package_type": "package", "sha256": "7c8a380ff8464684f1a143d28954c7a5fdae3aeee92d2b1ffafbaeed1f304502", "unvendored_tests": false, "version": "5.7.1"}, "cloudpickle": {"depends": [], "file_name": "cloudpickle-3.0.0-py3-none-any.whl", "imports": ["cloudpickle"], "install_dir": "site", "name": "cloudpickle", "package_type": "package", "sha256": "546d4499bdb1e99c240079b748a64169bae6cc2845ecc83be5ba42cacc707f5c", "unvendored_tests": false, "version": "3.0.0"}, "cmyt": {"depends": ["colorspacious", "matplotlib", "more-itertools", "numpy"], "file_name": "cmyt-2.0.0-py3-none-any.whl", "imports": ["cmyt"], "install_dir": "site", "name": "cmyt", "package_type": "package", "sha256": "b9cce3f1b05194440ca7da55ea7ee34c5de81141741b56c70c1c68d5578cefc6", "unvendored_tests": true, "version": "2.0.0"}, "cmyt-tests": {"depends": ["cmyt"], "file_name": "cmyt-tests.tar", "imports": [], "install_dir": "site", "name": "cmyt-tests", "package_type": "package", "sha256": "edda18a701bf1b399828b1087a8467663d1a7606e9fc9be37091185f3590b2a9", "unvendored_tests": false, "version": "2.0.0"}, "colorspacious": {"depends": ["numpy"], "file_name": "colorspacious-1.1.2-py2.py3-none-any.whl", "imports": ["colorspacious"], "install_dir": "site", "name": "colorspacious", "package_type": "package", "sha256": "42a5115324956c99721e05a28aec9f9091f35501c69ecaa318a263e1b28c8fc2", "unvendored_tests": false, "version": "1.1.2"}, "contourpy": {"depends": ["numpy"], "file_name": "contourpy-1.3.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["contourpy"], "install_dir": "site", "name": "contourpy", "package_type": "package", "sha256": "d640f7cba60c14cf381c04a7a781e1454ca55f0ae5e015facfb2291d8c869875", "unvendored_tests": false, "version": "1.3.0"}, "coolprop": {"depends": ["numpy", "matplotlib"], "file_name": "coolprop-6.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["CoolProp"], "install_dir": "site", "name": "coolprop", "package_type": "package", "sha256": "77fb9f0834728a14589428db7b030f4109a0dc45600cdaf686c1a8ea9b253d01", "unvendored_tests": true, "version": "6.6.0"}, "coolprop-tests": {"depends": ["coolprop"], "file_name": "coolprop-tests.tar", "imports": [], "install_dir": "site", "name": "coolprop-tests", "package_type": "package", "sha256": "3aa7f95cd22f0fc78ded93b41328043547e9193ad7f836fe4f68cc150f131b75", "unvendored_tests": false, "version": "6.6.0"}, "coverage": {"depends": ["sqlite3"], "file_name": "coverage-7.4.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["coverage"], "install_dir": "site", "name": "coverage", "package_type": "package", "sha256": "4ad66017cfa2e26a76646e0e0f92b6747c693e7fdb399972d4ee229235aa2f74", "unvendored_tests": false, "version": "7.4.4"}, "cpp-exceptions-test": {"depends": [], "file_name": "cpp-exceptions-test-0.1.zip", "imports": [], "install_dir": "dynlib", "name": "cpp-exceptions-test", "package_type": "shared_library", "sha256": "b10c69648a0e346ff8e00e702b1cdda12bd4951ccfd5b18986121e50d333623e", "unvendored_tests": false, "version": "0.1"}, "cpp-exceptions-test2": {"depends": [], "file_name": "cpp_exceptions_test2-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cpp-exceptions-test2"], "install_dir": "site", "name": "cpp-exceptions-test2", "package_type": "package", "sha256": "32ea714635a32fd5c4f61ccf0d3431bd43dd61574ac65ca364147d0a853d36e5", "unvendored_tests": false, "version": "1.0"}, "cramjam": {"depends": [], "file_name": "cramjam-2.8.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cramjam"], "install_dir": "site", "name": "cramjam", "package_type": "package", "sha256": "23cf4a1d67f3626dbda54d02abc8a74f9fb8ff65fa68c5178f1878e68fee18be", "unvendored_tests": false, "version": "2.8.3"}, "crc32c": {"depends": [], "file_name": "crc32c-2.7.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["crc32c"], "install_dir": "site", "name": "crc32c", "package_type": "package", "sha256": "6809cf3fc3119b24f3eb52ca9121aa277b5ec9447972a9ca9476a8f22e1732ac", "unvendored_tests": false, "version": "2.7.1"}, "cryptography": {"depends": ["openssl", "six", "cffi"], "file_name": "cryptography-42.0.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cryptography"], "install_dir": "site", "name": "cryptography", "package_type": "package", "sha256": "e7ea7fbbb4313a9ba2af9eae543e88e014c9893704226cfe95a762df799bb5e2", "unvendored_tests": false, "version": "42.0.5"}, "css-inline": {"depends": [], "file_name": "css_inline-0.14.6-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["css_inline"], "install_dir": "site", "name": "css-inline", "package_type": "package", "sha256": "d5c0ab3c3556df597597cf94933601262f0de6c0d55405830242af85c6fa4790", "unvendored_tests": false, "version": "0.14.6"}, "cssselect": {"depends": [], "file_name": "cssselect-1.2.0-py2.py3-none-any.whl", "imports": ["cssselect"], "install_dir": "site", "name": "cssselect", "package_type": "package", "sha256": "2b94a837c83b33a16652b748fa2461952fb5734488bb775d026688e7e5f6f89e", "unvendored_tests": false, "version": "1.2.0"}, "cvxpy-base": {"depends": ["numpy", "scipy", "clarabel"], "file_name": "cvxpy_base-1.5.1-py3-none-any.whl", "imports": ["cvxpy"], "install_dir": "site", "name": "cvxpy-base", "package_type": "package", "sha256": "5a775b0a589b42d68a6a3f1a1bb95c90b82522b46d2682caecae861b62fdb3dd", "unvendored_tests": true, "version": "1.5.1"}, "cvxpy-base-tests": {"depends": ["cvxpy-base"], "file_name": "cvxpy-base-tests.tar", "imports": [], "install_dir": "site", "name": "cvxpy-base-tests", "package_type": "package", "sha256": "148982c88724bbcf1d63f0a26869dce5a690a66334a906a714b359eb4f0dbabc", "unvendored_tests": false, "version": "1.5.1"}, "cycler": {"depends": ["six"], "file_name": "cycler-0.12.1-py3-none-any.whl", "imports": ["cycler"], "install_dir": "site", "name": "cycler", "package_type": "package", "sha256": "d9b2fa15e8dfa23230d5e4e182ab4b160a00a84b714cad1a258e5bf6ac36b930", "unvendored_tests": false, "version": "0.12.1"}, "cysignals": {"depends": [], "file_name": "cysignals-1.12.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cysignals"], "install_dir": "site", "name": "cysignals", "package_type": "package", "sha256": "2314f96016d6e7dceb665e8bfcf15f7d2746646a70ceb60617860e0dbf2aea91", "unvendored_tests": false, "version": "1.12.2"}, "cytoolz": {"depends": ["toolz"], "file_name": "cytoolz-0.12.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cytoolz"], "install_dir": "site", "name": "cytoolz", "package_type": "package", "sha256": "b5f8f6a713cad9fe458d8b406fac2ce141c94388266005434ceefdda244ed1b2", "unvendored_tests": true, "version": "0.12.3"}, "cytoolz-tests": {"depends": ["cytoolz"], "file_name": "cytoolz-tests.tar", "imports": [], "install_dir": "site", "name": "cytoolz-tests", "package_type": "package", "sha256": "9c360f292c520cde61a0a614df7380519b452371565f4b6120217226885c2f3e", "unvendored_tests": false, "version": "0.12.3"}, "decorator": {"depends": [], "file_name": "decorator-5.1.1-py3-none-any.whl", "imports": ["decorator"], "install_dir": "site", "name": "decorator", "package_type": "package", "sha256": "92573e0de88a33627dc99bd79ea6ee257e5719d885cf7211e446aae53bce2097", "unvendored_tests": false, "version": "5.1.1"}, "demes": {"depends": ["attrs", "ruamel.yaml"], "file_name": "demes-0.2.3-py3-none-any.whl", "imports": ["demes"], "install_dir": "site", "name": "demes", "package_type": "package", "sha256": "551cc5c98a3a95845cc630363fcc3216f66c1234b55c17394a7ba63d6ad29089", "unvendored_tests": false, "version": "0.2.3"}, "deprecation": {"depends": ["packaging"], "file_name": "deprecation-2.1.0-py2.py3-none-any.whl", "imports": ["deprecation"], "install_dir": "site", "name": "deprecation", "package_type": "package", "sha256": "dc7ba383da30f44361be9d6965ede2cdc7c34ed47c610a3df00cb583527d644c", "unvendored_tests": false, "version": "2.1.0"}, "distlib": {"depends": [], "file_name": "distlib-0.3.8-py2.py3-none-any.whl", "imports": ["distlib"], "install_dir": "site", "name": "distlib", "package_type": "package", "sha256": "f0fe2bdc8fae883d4cbc98e48ea3bbdb42ead639730acafc281d5c5d1c7eca6d", "unvendored_tests": false, "version": "0.3.8"}, "distro": {"depends": [], "file_name": "distro-1.9.0-py3-none-any.whl", "imports": ["distro"], "install_dir": "site", "name": "distro", "package_type": "package", "sha256": "b7c1206d175417dc8ea7e70fbdeda5d34b531d2f6e09b5a0dd74d9800f13f5e9", "unvendored_tests": false, "version": "1.9.0"}, "docutils": {"depends": [], "file_name": "docutils-0.21.1-py3-none-any.whl", "imports": ["docutils"], "install_dir": "site", "name": "docutils", "package_type": "package", "sha256": "0c5efa76ae008b941d449d2f58ac9729883f8847c310a7a3f090dfd40a421452", "unvendored_tests": false, "version": "0.21.1"}, "duckdb": {"depends": [], "file_name": "duckdb-1.1.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["duckdb"], "install_dir": "site", "name": "duckdb", "package_type": "package", "sha256": "3039edc5d67a2fdf91a318c26f4f1d3711272d3175e67a758183815b2cc6682d", "unvendored_tests": false, "version": "1.1.2"}, "ewah-bool-utils": {"depends": [], "file_name": "ewah_bool_utils-1.2.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["ewah_bool_utils"], "install_dir": "site", "name": "ewah_bool_utils", "package_type": "package", "sha256": "2bd26d50615368c72d5c2a745a7d0dde688711e8513b0816cdcd02a4965aefb8", "unvendored_tests": true, "version": "1.2.2"}, "ewah-bool-utils-tests": {"depends": ["ewah_bool_utils"], "file_name": "ewah-bool-utils-tests.tar", "imports": [], "install_dir": "site", "name": "ewah_bool_utils-tests", "package_type": "package", "sha256": "f6f3cbfe973a869ffead7a802e15a6f7e203da542492719ff3ce3062551a9fae", "unvendored_tests": false, "version": "1.2.2"}, "exceptiongroup": {"depends": [], "file_name": "exceptiongroup-1.2.1-py3-none-any.whl", "imports": ["exceptiongroup"], "install_dir": "site", "name": "exceptiongroup", "package_type": "package", "sha256": "bbe9b83febeaf15976b12de48b48e6ff23380e37e06891ca4965ca09074cc23c", "unvendored_tests": false, "version": "1.2.1"}, "executing": {"depends": [], "file_name": "executing-2.0.1-py2.py3-none-any.whl", "imports": ["executing"], "install_dir": "site", "name": "executing", "package_type": "package", "sha256": "d327f698f0eebe50fa3eddcf9834d9471127faf9f4e74c3931d17a697c2d6726", "unvendored_tests": false, "version": "2.0.1"}, "fastparquet": {"depends": ["cramjam", "numpy", "pandas", "fsspec", "packaging"], "file_name": "fastparquet-2024.5.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["fastparquet"], "install_dir": "site", "name": "fastparquet", "package_type": "package", "sha256": "3095b72076ee7e8d4be754847de186b01b506155968a706427f2bffc948cb29f", "unvendored_tests": false, "version": "2024.5.0"}, "fiona": {"depends": ["attrs", "certifi", "setuptools", "six", "click", "cligj"], "file_name": "fiona-1.9.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["fiona"], "install_dir": "site", "name": "fiona", "package_type": "package", "sha256": "bc823a4a57aa082bec3e4a184ac5df48707adb77cc06d58da7f7e4987443d8c8", "unvendored_tests": false, "version": "1.9.5"}, "fonttools": {"depends": [], "file_name": "fonttools-4.51.0-py3-none-any.whl", "imports": ["fontTools"], "install_dir": "site", "name": "fonttools", "package_type": "package", "sha256": "34cbc5d0d263cab22e6a917d6adb018a3d0512b19b96ef1cd35e2cfd03d0bd24", "unvendored_tests": false, "version": "4.51.0"}, "fpcast-test": {"depends": [], "file_name": "fpcast_test-0.1.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["fpcast_test"], "install_dir": "site", "name": "fpcast-test", "package_type": "package", "sha256": "3ba25e161f211c0773c0c2a367b5eee6d85f3d9b967905dd796791df59bf29a3", "unvendored_tests": false, "version": "0.1.1"}, "freesasa": {"depends": [], "file_name": "freesasa-2.2.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["freesasa"], "install_dir": "site", "name": "freesasa", "package_type": "package", "sha256": "4ea48ec30a8dcd9060f450ac146746cda007e6765f7cba7685b60d091dfb5f4b", "unvendored_tests": false, "version": "2.2.1"}, "frozenlist": {"depends": [], "file_name": "frozenlist-1.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["frozenlist"], "install_dir": "site", "name": "frozenlist", "package_type": "package", "sha256": "b4e5861b93e8f1a3a6b30b60461c7e4100a84f8794c6b81c7d732152f657e6f3", "unvendored_tests": false, "version": "1.4.1"}, "fsspec": {"depends": [], "file_name": "fsspec-2024.3.1-py3-none-any.whl", "imports": ["fsspec"], "install_dir": "site", "name": "fsspec", "package_type": "package", "sha256": "8f3f6445574a26fd5e6e5e7abbcdf81b51d641fb630c61904726942be14e50ad", "unvendored_tests": true, "version": "2024.3.1"}, "fsspec-tests": {"depends": ["fsspec"], "file_name": "fsspec-tests.tar", "imports": [], "install_dir": "site", "name": "fsspec-tests", "package_type": "package", "sha256": "c405fb3bc59ff66c41e88633a2ece57df2ab495e034c8a991b07730a41da72f4", "unvendored_tests": false, "version": "2024.3.1"}, "future": {"depends": [], "file_name": "future-1.0.0-py3-none-any.whl", "imports": ["future"], "install_dir": "site", "name": "future", "package_type": "package", "sha256": "d952e549e31bfe43b9f05b7b03a7d3033909425422691fce346757c5ce101ce4", "unvendored_tests": true, "version": "1.0.0"}, "future-tests": {"depends": ["future"], "file_name": "future-tests.tar", "imports": [], "install_dir": "site", "name": "future-tests", "package_type": "package", "sha256": "16c499e9a56d13216285274a85ed84c4c2a831372db5bab5fa9d987520239254", "unvendored_tests": false, "version": "1.0.0"}, "galpy": {"depends": ["numpy", "scipy", "matplotlib", "astropy", "future", "setuptools"], "file_name": "galpy-1.10.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["galpy"], "install_dir": "site", "name": "galpy", "package_type": "package", "sha256": "fe1fa6b43f4aaa05dca0bf95934f4a1ee3ce51c5c796fbc9c98f5161022aab55", "unvendored_tests": false, "version": "1.10.1"}, "gdal": {"depends": ["geos"], "file_name": "gdal-3.8.3.zip", "imports": [], "install_dir": "dynlib", "name": "gdal", "package_type": "shared_library", "sha256": "003c7cb0166189152b2d2c2cb66e0313c25ba4ad2d8158509c7c04a867c0cb1e", "unvendored_tests": false, "version": "3.8.3"}, "gensim": {"depends": ["numpy", "scipy", "six", "smart-open", "wrapt"], "file_name": "gensim-4.3.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["gensim"], "install_dir": "site", "name": "gensim", "package_type": "package", "sha256": "b6b5bffa2b79b785a4249fd4907377b40900715023f01de9ddaf1abecf210ed8", "unvendored_tests": true, "version": "4.3.3"}, "gensim-tests": {"depends": ["gensim"], "file_name": "gensim-tests.tar", "imports": [], "install_dir": "site", "name": "gensim-tests", "package_type": "package", "sha256": "07c36e56c2dd4cfc8bac5e155c73577e075a6e31ba96ab5616cccfe26b716d10", "unvendored_tests": false, "version": "4.3.3"}, "geopandas": {"depends": ["shapely", "fiona", "pyproj", "packaging", "pandas"], "file_name": "geopandas-1.0.1-py3-none-any.whl", "imports": ["geopandas"], "install_dir": "site", "name": "geopandas", "package_type": "package", "sha256": "910726fb3341783eb46d460b3846fd927de714d05d9deef79595fdfc05c6614b", "unvendored_tests": true, "version": "1.0.1"}, "geopandas-tests": {"depends": ["geopandas"], "file_name": "geopandas-tests.tar", "imports": [], "install_dir": "site", "name": "geopandas-tests", "package_type": "package", "sha256": "c45975091cf9fefb6035d9b345121562965593e2a0394820d53b34496f45c0e5", "unvendored_tests": false, "version": "1.0.1"}, "geos": {"depends": [], "file_name": "geos-3.12.1.zip", "imports": [], "install_dir": "dynlib", "name": "geos", "package_type": "shared_library", "sha256": "89ab18bfc1a2ea81ffbb0c5869d866907e53ccff5419a6a35e83d35726cca09a", "unvendored_tests": false, "version": "3.12.1"}, "gmpy2": {"depends": [], "file_name": "gmpy2-2.1.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["gmpy2"], "install_dir": "site", "name": "gmpy2", "package_type": "package", "sha256": "2b1b0f014bde64f51037a02f35a58d6c0c75d0458eef2430f55391c5915dec68", "unvendored_tests": false, "version": "2.1.5"}, "gsw": {"depends": ["numpy"], "file_name": "gsw-3.6.19-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["gsw"], "install_dir": "site", "name": "gsw", "package_type": "package", "sha256": "1ee6e22cb51da5e61d4aaa5f6d37b3ddcfd94431e89ab3662c3fb3e89432e538", "unvendored_tests": true, "version": "3.6.19"}, "gsw-tests": {"depends": ["gsw"], "file_name": "gsw-tests.tar", "imports": [], "install_dir": "site", "name": "gsw-tests", "package_type": "package", "sha256": "b837fbacd416923a0ec0c5e8d2fee1344e646a772b2963b9ce2902ad055a8d31", "unvendored_tests": false, "version": "3.6.19"}, "h11": {"depends": [], "file_name": "h11-0.14.0-py3-none-any.whl", "imports": ["h11"], "install_dir": "site", "name": "h11", "package_type": "package", "sha256": "1e322ea9efae60080675a7c6ce3ff91ff1167a738cb818a5c9a9e5c2127d77af", "unvendored_tests": true, "version": "0.14.0"}, "h11-tests": {"depends": ["h11"], "file_name": "h11-tests.tar", "imports": [], "install_dir": "site", "name": "h11-tests", "package_type": "package", "sha256": "722483c803f56200ba4190abfc50de7f9be1abfe485fe9ac6c8373c36b17ffc1", "unvendored_tests": false, "version": "0.14.0"}, "h3": {"depends": [], "file_name": "h3-4.2.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["h3"], "install_dir": "site", "name": "h3", "package_type": "package", "sha256": "260fef4a4b3c463238f739560cfff861af09a438e1c6c5592ec9f9a171e29ea2", "unvendored_tests": false, "version": "4.2.1"}, "h5py": {"depends": ["numpy", "pkgconfig"], "file_name": "h5py-3.12.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["h5py"], "install_dir": "site", "name": "h5py", "package_type": "package", "sha256": "281e55873b2bc61504ccfeff227e27bdba3ff8c532f9e2207ea00eef217c48de", "unvendored_tests": true, "version": "3.12.1"}, "h5py-tests": {"depends": ["h5py"], "file_name": "h5py-tests.tar", "imports": [], "install_dir": "site", "name": "h5py-tests", "package_type": "package", "sha256": "f6cf8be2f492a1f3bcba09a10283eca82a3ef4ab178920dd8f8168f17780f712", "unvendored_tests": false, "version": "3.12.1"}, "hashlib": {"depends": ["openssl"], "file_name": "hashlib-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_hashlib"], "install_dir": "site", "name": "hashlib", "package_type": "cpython_module", "sha256": "2f4a4544f3829eb8222fd0998935ebaae374faace00e930e469ce8f52051e579", "unvendored_tests": false, "version": "1.0.0"}, "html5lib": {"depends": ["webencodings", "six"], "file_name": "html5lib-1.1-py2.py3-none-any.whl", "imports": ["html5lib"], "install_dir": "site", "name": "html5lib", "package_type": "package", "sha256": "b9bfe21cb41b7a803e73202efe606939fa45e514b78a6a7ed9fe1fd85751eb15", "unvendored_tests": false, "version": "1.1"}, "httpcore": {"depends": ["certifi", "h11", "ssl"], "file_name": "httpcore-1.0.7-py3-none-any.whl", "imports": ["httpcore"], "install_dir": "site", "name": "httpcore", "package_type": "package", "sha256": "de2bb35c01126339c49f6f13a56a5b3347331bdd8309a486d2ee10bf43819709", "unvendored_tests": false, "version": "1.0.7"}, "httpx": {"depends": [], "file_name": "httpx-0.28.1-py3-none-any.whl", "imports": ["httpx"], "install_dir": "site", "name": "httpx", "package_type": "package", "sha256": "1842d8aca8cf781f49af06e70716e5dc338b273f0e7517e653961d8d62eecf81", "unvendored_tests": false, "version": "0.28.1"}, "idna": {"depends": [], "file_name": "idna-3.7-py3-none-any.whl", "imports": ["idna"], "install_dir": "site", "name": "idna", "package_type": "package", "sha256": "b24ecab34fbb7ed3a1cbcc31c6adb73b23f5f7b8998b084256460aa48916c970", "unvendored_tests": false, "version": "3.7"}, "igraph": {"depends": ["texttable"], "file_name": "igraph-0.11.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["igraph"], "install_dir": "site", "name": "igraph", "package_type": "package", "sha256": "6c7cf9fe1f3eb57f6f50e423544a64b13f8f6dde9e5204fb2cedb834b25be799", "unvendored_tests": false, "version": "0.11.4"}, "imageio": {"depends": ["numpy", "pillow"], "file_name": "imageio-2.36.0-py3-none-any.whl", "imports": ["imageio"], "install_dir": "site", "name": "imageio", "package_type": "package", "sha256": "dddc4066dc64e862cd1230081b54b7c4cb94433481160999737bea9ca84c5eb2", "unvendored_tests": false, "version": "2.36.0"}, "iminuit": {"depends": ["numpy"], "file_name": "iminuit-2.30.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["iminuit"], "install_dir": "site", "name": "iminuit", "package_type": "package", "sha256": "1536fe48e523a820df347b6f923a553af35040cebf298e9ec9ad4a3dc2f4ce54", "unvendored_tests": false, "version": "2.30.1"}, "iniconfig": {"depends": [], "file_name": "iniconfig-2.0.0-py3-none-any.whl", "imports": ["iniconfig"], "install_dir": "site", "name": "iniconfig", "package_type": "package", "sha256": "1221421a5309a002ca873bb5a5936b6cc0322052aa9e46b8f25676e2b4051ee9", "unvendored_tests": false, "version": "2.0.0"}, "ipython": {"depends": ["asttokens", "decorator", "executing", "matplotlib-inline", "prompt_toolkit", "pure-eval", "pygments", "six", "stack-data", "traitlets", "sqlite3", "wcwidth"], "file_name": "ipython-8.23.0-py3-none-any.whl", "imports": ["IPython"], "install_dir": "site", "name": "ipython", "package_type": "package", "sha256": "287e72a87350b6ff963156377c83d959b6cc9df6cd3e0890475837d2e4b5376a", "unvendored_tests": true, "version": "8.23.0"}, "ipython-tests": {"depends": ["ipython"], "file_name": "ipython-tests.tar", "imports": [], "install_dir": "site", "name": "ipython-tests", "package_type": "package", "sha256": "0cc51dda711fd35f1ea0591f2457aa84132730be8554b8f280461bc5e9793b90", "unvendored_tests": false, "version": "8.23.0"}, "jedi": {"depends": ["parso"], "file_name": "jedi-0.19.1-py2.py3-none-any.whl", "imports": ["jedi"], "install_dir": "site", "name": "jedi", "package_type": "package", "sha256": "e129d07588a92865b1d68dfe2ffec3ffeeb7b06f36a2e5d987eae519d841a297", "unvendored_tests": true, "version": "0.19.1"}, "jedi-tests": {"depends": ["jedi"], "file_name": "jedi-tests.tar", "imports": [], "install_dir": "site", "name": "jedi-tests", "package_type": "package", "sha256": "05f604214ba66314f039acc53029471cd014fc0d76556f69598ec27fedacf21e", "unvendored_tests": false, "version": "0.19.1"}, "jinja2": {"depends": ["markupsafe"], "file_name": "Jinja2-3.1.3-py3-none-any.whl", "imports": ["jinja2"], "install_dir": "site", "name": "Jinja2", "package_type": "package", "sha256": "6ee99404ad3d9f5ec9a8449547d363dee84f8c61e0200f11766ca2d70dff17af", "unvendored_tests": false, "version": "3.1.3"}, "jiter": {"depends": [], "file_name": "jiter-0.8.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["jiter"], "install_dir": "site", "name": "jiter", "package_type": "package", "sha256": "ce51a38e785f3b5cc6241736cfa955309b07210d4af5ab4e06479e59cf14dee2", "unvendored_tests": false, "version": "0.8.2"}, "joblib": {"depends": [], "file_name": "joblib-1.4.0-py3-none-any.whl", "imports": ["joblib"], "install_dir": "site", "name": "joblib", "package_type": "package", "sha256": "82e19599bfbdd728364132c5596227ba6e0e9b7cdd13eea9621f5e4cd29450d3", "unvendored_tests": true, "version": "1.4.0"}, "joblib-tests": {"depends": ["joblib"], "file_name": "joblib-tests.tar", "imports": [], "install_dir": "site", "name": "joblib-tests", "package_type": "package", "sha256": "0faa0db47d971e95a145a06f5bea770aebb08a845d642dbe82be5559ab2aa344", "unvendored_tests": false, "version": "1.4.0"}, "jsonschema": {"depends": ["attrs", "pyrsistent", "referencing", "jsonschema_specifications"], "file_name": "jsonschema-4.21.1-py3-none-any.whl", "imports": ["jsonschema"], "install_dir": "site", "name": "jsonschema", "package_type": "package", "sha256": "e7a197e1667d0fb83ce7811d2f6c02718ab6d46df0e6a24d85bf88c05e89c1af", "unvendored_tests": true, "version": "4.21.1"}, "jsonschema-specifications": {"depends": [], "file_name": "jsonschema_specifications-2023.12.1-py3-none-any.whl", "imports": ["jsonschema_specifications"], "install_dir": "site", "name": "jsonschema_specifications", "package_type": "package", "sha256": "02e321dae0c2a327d9fd05e6bb4a2397408c73eb0858c3b6ef52896c0cd3b992", "unvendored_tests": true, "version": "2023.12.1"}, "jsonschema-specifications-tests": {"depends": ["jsonschema_specifications"], "file_name": "jsonschema-specifications-tests.tar", "imports": [], "install_dir": "site", "name": "jsonschema_specifications-tests", "package_type": "package", "sha256": "e13ed1a413ccfe06015c390fc3bf0eec83cd9f5c69b93c71680083ad8583c795", "unvendored_tests": false, "version": "2023.12.1"}, "jsonschema-tests": {"depends": ["jsonschema"], "file_name": "jsonschema-tests.tar", "imports": [], "install_dir": "site", "name": "jsonschema-tests", "package_type": "package", "sha256": "45c31daf6314e969be3986e4bd5e56b4b1e9ed21f52b532cf50c750855171371", "unvendored_tests": false, "version": "4.21.1"}, "kiwisolver": {"depends": [], "file_name": "kiwisolver-1.4.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["kiwisolver"], "install_dir": "site", "name": "kiwisolver", "package_type": "package", "sha256": "f006a1adb6d567f292eb5facec3d5f0b4e4e055ee506c7dfbcd10e6b05e3d46d", "unvendored_tests": false, "version": "1.4.5"}, "lakers-python": {"depends": [], "file_name": "lakers_python-0.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lakers"], "install_dir": "site", "name": "lakers-python", "package_type": "package", "sha256": "741426866cf3071c8cb4258a54e115c4c95d13586f49ecf7ae6a600780ce3b2a", "unvendored_tests": false, "version": "0.4.1"}, "lazy-loader": {"depends": [], "file_name": "lazy_loader-0.4-py3-none-any.whl", "imports": ["lazy_loader"], "install_dir": "site", "name": "lazy_loader", "package_type": "package", "sha256": "153d8ff5e918ba9a8bc0df280d02ade1c3f3930950792d42968f37babd41e12f", "unvendored_tests": true, "version": "0.4"}, "lazy-loader-tests": {"depends": ["lazy_loader"], "file_name": "lazy-loader-tests.tar", "imports": [], "install_dir": "site", "name": "lazy_loader-tests", "package_type": "package", "sha256": "fbfa6d63aead157f63b90c8a6ebb42a7f5d30d62367527fe39a67fb0d5a7dfa3", "unvendored_tests": false, "version": "0.4"}, "lazy-object-proxy": {"depends": [], "file_name": "lazy_object_proxy-1.10.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lazy_object_proxy"], "install_dir": "site", "name": "lazy-object-proxy", "package_type": "package", "sha256": "776639ccd52e0f160c6fb2360fd93410f0abbd6aef3cf15000a5ab36d4743133", "unvendored_tests": false, "version": "1.10.0"}, "libcst": {"depends": ["pyyaml"], "file_name": "libcst-1.4.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["libcst"], "install_dir": "site", "name": "libcst", "package_type": "package", "sha256": "79c2daf035d61c21faa8718cd08f3382a68098ddfd3368f076b9ef1bfe44eaf7", "unvendored_tests": true, "version": "1.4.0"}, "libcst-tests": {"depends": ["libcst"], "file_name": "libcst-tests.tar", "imports": [], "install_dir": "site", "name": "libcst-tests", "package_type": "package", "sha256": "405f16bea1126f7d332f93021dc4a780d5506379019b67b361c633120ca7bcbf", "unvendored_tests": false, "version": "1.4.0"}, "libhdf5": {"depends": [], "file_name": "libhdf5-1.12.1.zip", "imports": [], "install_dir": "dynlib", "name": "libhdf5", "package_type": "shared_library", "sha256": "85764401d68456b7145fe90b34347f06aff2ec70721b40fcd5868a936bb6efe1", "unvendored_tests": false, "version": "1.12.1"}, "libheif": {"depends": [], "file_name": "libheif-1.12.0.zip", "imports": [], "install_dir": "dynlib", "name": "libheif", "package_type": "shared_library", "sha256": "b69ed6649f0192f9f264dcba82f0a00c3d994e98285feba0be31475ee459de06", "unvendored_tests": false, "version": "1.12.0"}, "libmagic": {"depends": [], "file_name": "libmagic-5.42.zip", "imports": [], "install_dir": "dynlib", "name": "libmagic", "package_type": "shared_library", "sha256": "f0c178e17e2386bb42b9fade9314ba880c61a03bc59d81fc4cb4fd6415e95515", "unvendored_tests": false, "version": "5.42"}, "lightgbm": {"depends": ["numpy", "scipy", "scikit-learn"], "file_name": "lightgbm-4.5.0-py3-none-pyodide_2024_0_wasm32.whl", "imports": ["lightgbm"], "install_dir": "site", "name": "lightgbm", "package_type": "package", "sha256": "208f804db8a78b17b9095aa0fd4010b9a082f24ae143ecbecedee2df3a708263", "unvendored_tests": false, "version": "4.5.0"}, "logbook": {"depends": ["ssl"], "file_name": "logbook-1.7.0.post0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["logbook"], "install_dir": "site", "name": "logbook", "package_type": "package", "sha256": "7023b1fadf2e0369e56cbc54d87dcb89009f5677d8977860089832931f90205f", "unvendored_tests": false, "version": "1.7.0.post0"}, "lxml": {"depends": [], "file_name": "lxml-5.2.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lxml"], "install_dir": "site", "name": "lxml", "package_type": "package", "sha256": "c3b9dbcdd49b440c8c8d4eeea8e1c299ba687fe159fb6f9ff505834ab004fcc1", "unvendored_tests": false, "version": "5.2.1"}, "lzma": {"depends": [], "file_name": "lzma-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["lzma", "_lzma"], "install_dir": "site", "name": "lzma", "package_type": "cpython_module", "sha256": "53f3dc8770df047052220fa10c37461e50ef8cd6845fcf8b604c2c0fbd751637", "unvendored_tests": false, "version": "1.0.0"}, "markupsafe": {"depends": [], "file_name": "markupsafe-2.1.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["markupsafe"], "install_dir": "site", "name": "MarkupSafe", "package_type": "package", "sha256": "ece48b98519a7bc228ba914fc1783ec08a2df99594258ca62d108bb1810dd3d7", "unvendored_tests": false, "version": "2.1.5"}, "matplotlib": {"depends": ["contourpy", "cycler", "fonttools", "kiwisolver", "numpy", "packaging", "pillow", "pyparsing", "python-dateutil", "pytz", "matplotlib-pyodide"], "file_name": "matplotlib-3.8.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pylab", "mpl_toolkits", "matplotlib"], "install_dir": "site", "name": "matplotlib", "package_type": "package", "sha256": "726a069e0407cf14ba9d921747c9c4c81687621a4cdf0a27ad4af2b403025f4d", "unvendored_tests": true, "version": "3.8.4"}, "matplotlib-inline": {"depends": ["traitlets"], "file_name": "matplotlib_inline-0.1.7-py3-none-any.whl", "imports": ["matplotlib-inline"], "install_dir": "site", "name": "matplotlib-inline", "package_type": "package", "sha256": "98b748fc366158ea4d947dbf2532913dd05befb632f03f117f139d361228cfcc", "unvendored_tests": false, "version": "0.1.7"}, "matplotlib-pyodide": {"depends": [], "file_name": "matplotlib_pyodide-0.2.3-py3-none-any.whl", "imports": ["matplotlib_pyodide"], "install_dir": "site", "name": "matplotlib-pyodide", "package_type": "package", "sha256": "fdecad0b458cd658bffa8cd014bed38d008f1f441aaa10ee6081fcf3e74318ff", "unvendored_tests": false, "version": "0.2.3"}, "matplotlib-tests": {"depends": ["matplotlib"], "file_name": "matplotlib-tests.tar", "imports": [], "install_dir": "site", "name": "matplotlib-tests", "package_type": "package", "sha256": "9c6cfe36881f7a682cb1a73bf3a9ad53a1fe88edcf73759180d4664d71557ba2", "unvendored_tests": false, "version": "3.8.4"}, "memory-allocator": {"depends": [], "file_name": "memory_allocator-0.1.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["memory_allocator"], "install_dir": "site", "name": "memory-allocator", "package_type": "package", "sha256": "c0fd9e73411ca1bfed22f8e50094f93a653185d294e013c2eef260f34b00967b", "unvendored_tests": false, "version": "0.1.4"}, "micropip": {"depends": ["packaging"], "file_name": "micropip-0.8.0-py3-none-any.whl", "imports": ["micropip"], "install_dir": "site", "name": "micropip", "package_type": "package", "sha256": "b496f99fdcc46fcce8c41f3f5ecba5b368f582ce01b3501cd3f8670cb0039398", "unvendored_tests": false, "version": "0.8.0"}, "mmh3": {"depends": [], "file_name": "mmh3-4.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["mmh3"], "install_dir": "site", "name": "mmh3", "package_type": "package", "sha256": "ee07ebd2c988a0ebb85d0ab62b8851a282183229feef265b76d1e0cef27850ac", "unvendored_tests": false, "version": "4.1.0"}, "mne": {"depends": ["numpy", "scipy", "setuptools", "decorator", "lazy_loader", "packaging"], "file_name": "mne-1.8.0-py3-none-any.whl", "imports": ["mne"], "install_dir": "site", "name": "mne", "package_type": "package", "sha256": "2d00616cc40514e72556ef14ac18aa6d32f803528bb3edc531a74e921007312f", "unvendored_tests": true, "version": "1.8.0"}, "mne-tests": {"depends": ["mne"], "file_name": "mne-tests.tar", "imports": [], "install_dir": "site", "name": "mne-tests", "package_type": "package", "sha256": "1f23cef11518897f90d8ed970e78d1c1bcaec6d8c1ac28c4c12a37586d531239", "unvendored_tests": false, "version": "1.8.0"}, "more-itertools": {"depends": [], "file_name": "more_itertools-10.2.0-py3-none-any.whl", "imports": ["more_itertools"], "install_dir": "site", "name": "more-itertools", "package_type": "package", "sha256": "da7f19d04fb7913d23cc038ef9c9be2dd15ac5380af796eedb8d88a40382038b", "unvendored_tests": false, "version": "10.2.0"}, "mpmath": {"depends": [], "file_name": "mpmath-1.3.0-py3-none-any.whl", "imports": ["mpmath"], "install_dir": "site", "name": "mpmath", "package_type": "package", "sha256": "fbab8b194a7bd0be0b4b45985c06b92834d956c7f6d110314075810e182c224d", "unvendored_tests": true, "version": "1.3.0"}, "mpmath-tests": {"depends": ["mpmath"], "file_name": "mpmath-tests.tar", "imports": [], "install_dir": "site", "name": "mpmath-tests", "package_type": "package", "sha256": "9658f2b68ffd16f667e8fc1856576f450b509702141caf1824dfe4dede6e2498", "unvendored_tests": false, "version": "1.3.0"}, "msgpack": {"depends": [], "file_name": "msgpack-1.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["msgpack"], "install_dir": "site", "name": "msgpack", "package_type": "package", "sha256": "441de64d86df5e2f4e58970d58e67f857e442d09dd836bea5c9991fbf7d3aebb", "unvendored_tests": false, "version": "1.1.0"}, "msgspec": {"depends": [], "file_name": "msgspec-0.18.6-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["msgspec"], "install_dir": "site", "name": "msgspec", "package_type": "package", "sha256": "cbdf3b5b7a01c9e1a9fbeddcefa4a2d616daef28dcdadde86af164dba8e9fe29", "unvendored_tests": false, "version": "0.18.6"}, "msprime": {"depends": ["numpy", "newick", "tskit", "demes", "rpds-py"], "file_name": "msprime-1.3.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["msprime"], "install_dir": "site", "name": "msprime", "package_type": "package", "sha256": "709c2bf26067412cccea3236e0ae551e54f7480e5a6b8916c522f6c23ba0c23a", "unvendored_tests": false, "version": "1.3.3"}, "multidict": {"depends": [], "file_name": "multidict-6.0.5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["multidict"], "install_dir": "site", "name": "multidict", "package_type": "package", "sha256": "1d02f3f120cfc9798a427c93e1f5f489c91807cdb79aec5214d1d7e7ea8e6478", "unvendored_tests": false, "version": "6.0.5"}, "munch": {"depends": ["setuptools", "six"], "file_name": "munch-4.0.0-py2.py3-none-any.whl", "imports": ["munch"], "install_dir": "site", "name": "munch", "package_type": "package", "sha256": "9433a2f237274903cb17d4001c6b80745ac5d1d38e9e51a13bfed7d8209de8b2", "unvendored_tests": false, "version": "4.0.0"}, "mypy": {"depends": [], "file_name": "mypy-1.9.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["mypyc", "mypy"], "install_dir": "site", "name": "mypy", "package_type": "package", "sha256": "24d0a4b1e890c921b8b83e02b154c114b7f644974b9d9dc1e0440212bf3d0e34", "unvendored_tests": true, "version": "1.9.0"}, "mypy-tests": {"depends": ["mypy"], "file_name": "mypy-tests.tar", "imports": [], "install_dir": "site", "name": "mypy-tests", "package_type": "package", "sha256": "1c7f8f7316836d1cf26d30d792d85621f314d3e7946567381de775d22496c3da", "unvendored_tests": false, "version": "1.9.0"}, "narwhals": {"depends": [], "file_name": "narwhals-1.24.1-py3-none-any.whl", "imports": ["narwhals"], "install_dir": "site", "name": "narwhals", "package_type": "package", "sha256": "b2cd5d6379e6356fe7d13781634a6828bd82349d65eab5d563af8f33d16be46e", "unvendored_tests": false, "version": "1.24.1"}, "netcdf4": {"depends": ["numpy", "packaging", "h5py", "cftime", "certifi"], "file_name": "netcdf4-1.7.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["netCDF4"], "install_dir": "site", "name": "netcdf4", "package_type": "package", "sha256": "34cbbb724a4423810c508205fde6ba69fd496fc5287c90f5be57316644952f01", "unvendored_tests": false, "version": "1.7.2"}, "networkx": {"depends": ["decorator", "setuptools", "matplotlib", "numpy"], "file_name": "networkx-3.4.2-py3-none-any.whl", "imports": ["networkx"], "install_dir": "site", "name": "networkx", "package_type": "package", "sha256": "669155bea3e65d3c9c06eecb0b34629ee942a0bae458fdd76709dc05937744e9", "unvendored_tests": true, "version": "3.4.2"}, "networkx-tests": {"depends": ["networkx"], "file_name": "networkx-tests.tar", "imports": [], "install_dir": "site", "name": "networkx-tests", "package_type": "package", "sha256": "48b6cde4fea56a15e8a8a315672878c47f6dcc248265df46b4945637d873aeff", "unvendored_tests": false, "version": "3.4.2"}, "newick": {"depends": [], "file_name": "newick-1.9.0-py2.py3-none-any.whl", "imports": ["newick"], "install_dir": "site", "name": "newick", "package_type": "package", "sha256": "147939847e56082a3d9515aef6735bc1b100b92f758cfed128685bcecfff404c", "unvendored_tests": false, "version": "1.9.0"}, "nh3": {"depends": [], "file_name": "nh3-0.2.17-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["nh3"], "install_dir": "site", "name": "nh3", "package_type": "package", "sha256": "2e0bf68035cd5598184e2ec9b9d4b558c8ec12d28d73508ec8cc57c5759e7787", "unvendored_tests": false, "version": "0.2.17"}, "nlopt": {"depends": ["numpy"], "file_name": "nlopt-2.9.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["nlopt"], "install_dir": "site", "name": "nlopt", "package_type": "package", "sha256": "8a376f44d6410d7d2c30c9f6b3846043f644f70ca05595cb1be2ebcb24ceb898", "unvendored_tests": false, "version": "2.9.1"}, "nltk": {"depends": ["regex", "sqlite3"], "file_name": "nltk-3.8.1-py3-none-any.whl", "imports": ["nltk"], "install_dir": "site", "name": "nltk", "package_type": "package", "sha256": "79cf38ba481fa82e876e8cc10bf846e465e1a4f8b4057e72c2fb35b8c0753225", "unvendored_tests": true, "version": "3.8.1"}, "nltk-tests": {"depends": ["nltk"], "file_name": "nltk-tests.tar", "imports": [], "install_dir": "site", "name": "nltk-tests", "package_type": "package", "sha256": "32893b1427552c2fe4bf40a719217acdf56f885908368701c18d43dda3bdaaba", "unvendored_tests": false, "version": "3.8.1"}, "numcodecs": {"depends": ["numpy", "msgpack"], "file_name": "numcodecs-0.13.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["numcodecs"], "install_dir": "site", "name": "numcodecs", "package_type": "package", "sha256": "d91d647ef0dcb1626aaeb2648b0ec78f9c5b562c829a0e0f84b8d229293d1ca8", "unvendored_tests": true, "version": "0.13.1"}, "numcodecs-tests": {"depends": ["numcodecs"], "file_name": "numcodecs-tests.tar", "imports": [], "install_dir": "site", "name": "numcodecs-tests", "package_type": "package", "sha256": "047a6a8ccd92792d558d7de263ab94f8863baecad929027f05ce5409dda82af2", "unvendored_tests": false, "version": "0.13.1"}, "numpy": {"depends": [], "file_name": "numpy-2.0.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["numpy"], "install_dir": "site", "name": "numpy", "package_type": "package", "sha256": "d9cc75a959bbfb14efe05e26ca04cb2c85acbdad8b0a07a1c0140c4b820b4eec", "unvendored_tests": true, "version": "2.0.2"}, "numpy-tests": {"depends": ["numpy"], "file_name": "numpy-tests.tar", "imports": [], "install_dir": "site", "name": "numpy-tests", "package_type": "package", "sha256": "73a014499d803ecdabc9607ceef269b114211a98317bd071c08cbdbebe2697f6", "unvendored_tests": false, "version": "2.0.2"}, "openai": {"depends": ["httpx", "pydantic", "typing-extensions", "distro", "anyio", "jiter"], "file_name": "openai-1.68.2-py3-none-any.whl", "imports": ["openai"], "install_dir": "site", "name": "openai", "package_type": "package", "sha256": "5a935d84e20be1bb4e13a5848d8cee5e4453abddebdaf6758853847848dca5f6", "unvendored_tests": false, "version": "1.68.2"}, "openblas": {"depends": [], "file_name": "openblas-0.3.26.zip", "imports": [], "install_dir": "dynlib", "name": "openblas", "package_type": "shared_library", "sha256": "779255bf4fe1fc8fb529b663acfa3b8dbe4e2e922f0b6e531b84af78a44526e7", "unvendored_tests": false, "version": "0.3.26"}, "opencv-python": {"depends": ["numpy"], "file_name": "opencv_python-4.10.0.84-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["cv2"], "install_dir": "site", "name": "opencv-python", "package_type": "package", "sha256": "4275f3b874af7fa72c75a6ec3d6a071851514b21404f817fd00082385be27096", "unvendored_tests": false, "version": "4.10.0.84"}, "openssl": {"depends": [], "file_name": "openssl-1.1.1w.zip", "imports": [], "install_dir": "dynlib", "name": "openssl", "package_type": "shared_library", "sha256": "f41e9ac321494b4b4eb1b4a41921dee7c69440ac324800ac39d0dba3df96b7f6", "unvendored_tests": false, "version": "1.1.1w"}, "optlang": {"depends": ["sympy", "six", "swiglpk"], "file_name": "optlang-1.8.1-py2.py3-none-any.whl", "imports": ["optlang"], "install_dir": "site", "name": "optlang", "package_type": "package", "sha256": "09ca5ff2616d4c95b476d73b9a5a267124308de6d4bb5d94ed2221933063c3d4", "unvendored_tests": true, "version": "1.8.1"}, "optlang-tests": {"depends": ["optlang"], "file_name": "optlang-tests.tar", "imports": [], "install_dir": "site", "name": "optlang-tests", "package_type": "package", "sha256": "cda10eabec8caa857c73936fd80930d4b010dbc9299011e27e359ec0efafe132", "unvendored_tests": false, "version": "1.8.1"}, "orjson": {"depends": [], "file_name": "orjson-3.10.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["orjson"], "install_dir": "site", "name": "orjson", "package_type": "package", "sha256": "0a670d159d0f1acdf3e3e8442d2f9771185a0abec0d88ca62f39b80dfff64719", "unvendored_tests": false, "version": "3.10.1"}, "osqp": {"depends": ["jinja2", "numpy", "scipy"], "file_name": "osqp-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["osqp"], "install_dir": "site", "name": "osqp", "package_type": "package", "sha256": "522f0f000d175a415aa45dfebea430cbc1ae39beeff2ae768b13189ff3575d95", "unvendored_tests": true, "version": "1.0.0"}, "osqp-tests": {"depends": ["osqp"], "file_name": "osqp-tests.tar", "imports": [], "install_dir": "site", "name": "osqp-tests", "package_type": "package", "sha256": "c329c19fecb52a3dd38bb441896e88bb2618821471da0597c576369e06fb951c", "unvendored_tests": false, "version": "1.0.0"}, "packaging": {"depends": [], "file_name": "packaging-24.2-py3-none-any.whl", "imports": ["packaging"], "install_dir": "site", "name": "packaging", "package_type": "package", "sha256": "8702ed5471ec290c11d7b7792d70159ecb47b0dc476a5606acd891609a9ff7d0", "unvendored_tests": false, "version": "24.2"}, "pandas": {"depends": ["numpy", "python-dateutil", "pytz"], "file_name": "pandas-2.2.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pandas"], "install_dir": "site", "name": "pandas", "package_type": "package", "sha256": "c5de410f0624d310276ad28ed8f98ff58dc1ba18ffda93688c846195af939f7c", "unvendored_tests": true, "version": "2.2.3"}, "pandas-tests": {"depends": ["pandas"], "file_name": "pandas-tests.tar", "imports": [], "install_dir": "site", "name": "pandas-tests", "package_type": "package", "sha256": "6a9bec1f2a2376520ef4fbcf195fd0a159e08b0438f73217389c6b3bac420d59", "unvendored_tests": false, "version": "2.2.3"}, "parso": {"depends": [], "file_name": "parso-0.8.4-py2.py3-none-any.whl", "imports": ["parso"], "install_dir": "site", "name": "parso", "package_type": "package", "sha256": "182626b0e2dea7235120c3fab406e6fcfe606b05aa6498a8ed34d316fc1af45d", "unvendored_tests": false, "version": "0.8.4"}, "patsy": {"depends": ["numpy", "six"], "file_name": "patsy-0.5.6-py2.py3-none-any.whl", "imports": ["patsy"], "install_dir": "site", "name": "patsy", "package_type": "package", "sha256": "d50c9cae4fa185aadeffd03c421f38551d5bdcc7b0a374803753991d9f96c9d8", "unvendored_tests": true, "version": "0.5.6"}, "patsy-tests": {"depends": ["patsy"], "file_name": "patsy-tests.tar", "imports": [], "install_dir": "site", "name": "patsy-tests", "package_type": "package", "sha256": "f7af3b54d1130196058cabdc8a55624d5c774986449a454759f1cb02ea5eb813", "unvendored_tests": false, "version": "0.5.6"}, "pcodec": {"depends": ["numpy"], "file_name": "pcodec-0.3.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pcodec"], "install_dir": "site", "name": "pcodec", "package_type": "package", "sha256": "319c5e7c0254c1dc530035e08bf04724fe260c2e991b0e5bc5c3c7fa0846cff0", "unvendored_tests": false, "version": "0.3.3"}, "peewee": {"depends": ["sqlite3", "cffi"], "file_name": "peewee-3.17.3-py3-none-any.whl", "imports": ["peewee"], "install_dir": "site", "name": "peewee", "package_type": "package", "sha256": "b5b3f6a311d7e653802f41a8b7192500fb8be7b66a6738cffdb83046086055a7", "unvendored_tests": true, "version": "3.17.3"}, "peewee-tests": {"depends": ["peewee"], "file_name": "peewee-tests.tar", "imports": [], "install_dir": "site", "name": "peewee-tests", "package_type": "package", "sha256": "6ab29bde28e76216a44732f326d68297827ccde45dd36ea9634a05a5b6cb8292", "unvendored_tests": false, "version": "3.17.3"}, "pi-heif": {"depends": ["cffi", "pillow", "libheif"], "file_name": "pi_heif-0.21.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pi_heif"], "install_dir": "site", "name": "pi-heif", "package_type": "package", "sha256": "6d9273b0e516ab725b267824faf19facee0b4724eb717583fcf5c39a9e2a6ffd", "unvendored_tests": false, "version": "0.21.0"}, "pillow": {"depends": [], "file_name": "pillow-10.2.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["PIL"], "install_dir": "site", "name": "Pillow", "package_type": "package", "sha256": "cf56845b516fe5410e62df531ca3efac7d865e52d43ff0763238db3ad454d2f7", "unvendored_tests": false, "version": "10.2.0"}, "pillow-heif": {"depends": ["cffi", "pillow", "libheif"], "file_name": "pillow_heif-0.20.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pillow_heif"], "install_dir": "site", "name": "pillow-heif", "package_type": "package", "sha256": "0b0837dd407ed85d6b84c5c3e4ad30e1703aa7ef407886d04407f8866d997fcf", "unvendored_tests": false, "version": "0.20.0"}, "pkgconfig": {"depends": [], "file_name": "pkgconfig-1.5.5-py3-none-any.whl", "imports": ["pkgconfig"], "install_dir": "site", "name": "pkgconfig", "package_type": "package", "sha256": "e26e04f26177cd2aaa4175b590616b869c896dd67da3606222df7e5a16ad7930", "unvendored_tests": false, "version": "1.5.5"}, "pluggy": {"depends": [], "file_name": "pluggy-1.5.0-py3-none-any.whl", "imports": ["pluggy"], "install_dir": "site", "name": "pluggy", "package_type": "package", "sha256": "6b80e7cab3a322a277973efe16043409c0ba3417f33a1b0af0a91fdb305c574e", "unvendored_tests": false, "version": "1.5.0"}, "polars": {"depends": [], "file_name": "polars-1.18.0-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["polars"], "install_dir": "site", "name": "polars", "package_type": "package", "sha256": "9402b7ee34f2004c485dceeff03c28bd7ab8ab92a98895e43cbc2c0e0af6cea5", "unvendored_tests": false, "version": "1.18.0"}, "pplpy": {"depends": ["gmpy2", "cysignals"], "file_name": "pplpy-0.8.10-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["ppl"], "install_dir": "site", "name": "pplpy", "package_type": "package", "sha256": "9257148efcf21e2bc262d9bb6dca86cb1290094e9b70ef59ff1b79b8c44c4be5", "unvendored_tests": false, "version": "0.8.10"}, "primecountpy": {"depends": ["cysignals"], "file_name": "primecountpy-0.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["primecountpy"], "install_dir": "site", "name": "primecountpy", "package_type": "package", "sha256": "c7679113d862a7c64a8f25ab458aa55c8afea7e854aea7ef540ef5ebe5bbc552", "unvendored_tests": false, "version": "0.1.0"}, "prompt-toolkit": {"depends": [], "file_name": "prompt_toolkit-3.0.43-py3-none-any.whl", "imports": ["prompt_toolkit"], "install_dir": "site", "name": "prompt_toolkit", "package_type": "package", "sha256": "45080cd14a060d3228d33afcc3e057ae3f1ba64e15e00dc03a2e7f37a1bb5c44", "unvendored_tests": false, "version": "3.0.43"}, "protobuf": {"depends": [], "file_name": "protobuf-5.29.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["google"], "install_dir": "site", "name": "protobuf", "package_type": "package", "sha256": "1ecd45c1ec68711e8316d8ca05a8bac70842d7b29ccc5cd627f75d2345fa4e72", "unvendored_tests": false, "version": "5.29.2"}, "pure-eval": {"depends": [], "file_name": "pure_eval-0.2.3-py3-none-any.whl", "imports": ["pure_eval"], "install_dir": "site", "name": "pure-eval", "package_type": "package", "sha256": "975eda8d7e66aa8c2443330908002baae28608b2867c7e30719ccd7b8335001e", "unvendored_tests": false, "version": "0.2.3"}, "py": {"depends": [], "file_name": "py-1.11.0-py2.py3-none-any.whl", "imports": ["py"], "install_dir": "site", "name": "py", "package_type": "package", "sha256": "a3971587e319b811fc7ac78fd64a171acc82409d664049f15f01374846762d28", "unvendored_tests": false, "version": "1.11.0"}, "pyarrow": {"depends": ["numpy", "pandas", "pyodide-unix-timezones"], "file_name": "pyarrow-18.1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyarrow"], "install_dir": "site", "name": "pyarrow", "package_type": "package", "sha256": "24b6b46ce290ed1febf44f2f25422e34a5932ae55406b45e407c151fdd074d98", "unvendored_tests": false, "version": "18.1.0"}, "pyclipper": {"depends": [], "file_name": "pyclipper-1.3.0.post5-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyclipper"], "install_dir": "site", "name": "pyclipper", "package_type": "package", "sha256": "68b3e5635b423178f487dc00f16425a64ba15d4221adb4f75a050b5f0d803f9b", "unvendored_tests": false, "version": "1.3.0.post5"}, "pycparser": {"depends": [], "file_name": "pycparser-2.22-py3-none-any.whl", "imports": ["pycparser"], "install_dir": "site", "name": "pycparser", "package_type": "package", "sha256": "70457c82283bd1d0f2691587c938b4299a294008a4d2dc4076e05f38e1d30039", "unvendored_tests": false, "version": "2.22"}, "pycryptodome": {"depends": [], "file_name": "pycryptodome-3.20.0-cp35-abi3-pyodide_2024_0_wasm32.whl", "imports": ["Crypto"], "install_dir": "site", "name": "pycryptodome", "package_type": "package", "sha256": "82bbe0cdffb1f2bd4285e197e0066c9cdd565948e8d302a55f8b4e7773940a46", "unvendored_tests": true, "version": "3.20.0"}, "pycryptodome-tests": {"depends": ["pycryptodome"], "file_name": "pycryptodome-tests.tar", "imports": [], "install_dir": "site", "name": "pycryptodome-tests", "package_type": "package", "sha256": "5dc5dfe1f81da57ca36aafad5d14890b3922076f702f1009c4850e7ca66004f7", "unvendored_tests": false, "version": "3.20.0"}, "pydantic": {"depends": ["typing-extensions", "pydantic_core", "annotated-types"], "file_name": "pydantic-2.10.5-py3-none-any.whl", "imports": ["pydantic"], "install_dir": "site", "name": "pydantic", "package_type": "package", "sha256": "3acac436fe05b4f12b65fc0d676750d1464dc23940e430964c075d8131b5180f", "unvendored_tests": false, "version": "2.10.5"}, "pydantic-core": {"depends": [], "file_name": "pydantic_core-2.27.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pydantic_core"], "install_dir": "site", "name": "pydantic_core", "package_type": "package", "sha256": "9820b2285c6b4e150791aad0fa3ffcb9ac357046f794c1e27eca6a8c56070e05", "unvendored_tests": false, "version": "2.27.2"}, "pydecimal": {"depends": [], "file_name": "pydecimal-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_pydecimal"], "install_dir": "site", "name": "pydecimal", "package_type": "cpython_module", "sha256": "9847cb165d02795cfcc3f6f1833f8add7a75cd4dddc0ee6b38a61552bf8e97bd", "unvendored_tests": false, "version": "1.0.0"}, "pydoc-data": {"depends": [], "file_name": "pydoc_data-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pydoc_data"], "install_dir": "site", "name": "pydoc_data", "package_type": "cpython_module", "sha256": "603a0cb32a812c680fb922ae37040aa49d07649e57a1c2a30257738dc8790df7", "unvendored_tests": false, "version": "1.0.0"}, "pyerfa": {"depends": ["numpy"], "file_name": "pyerfa-2.0.1.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["erfa"], "install_dir": "site", "name": "pyerfa", "package_type": "package", "sha256": "13e825453f19ac12daa400fff038d15ea1c5b2a8e5cac837edf8a86b72a2b56a", "unvendored_tests": true, "version": "2.0.1.4"}, "pyerfa-tests": {"depends": ["pyerfa"], "file_name": "pyerfa-tests.tar", "imports": [], "install_dir": "site", "name": "pyerfa-tests", "package_type": "package", "sha256": "13ad71f873cf0f1614585f48356b906f5160c90c85691e2f55ae1c728b7e4ac8", "unvendored_tests": false, "version": "2.0.1.4"}, "pygame-ce": {"depends": [], "file_name": "pygame_ce-2.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pygame"], "install_dir": "site", "name": "pygame-ce", "package_type": "package", "sha256": "c41a4bfb623b80d75d2772e083a4c081d386f97432044f516fa8601ab20d3c8a", "unvendored_tests": true, "version": "2.4.1"}, "pygame-ce-tests": {"depends": ["pygame-ce"], "file_name": "pygame-ce-tests.tar", "imports": [], "install_dir": "site", "name": "pygame-ce-tests", "package_type": "package", "sha256": "a79cd7b856b9807c0cff5adf86d8ada41149d821719d607306bb3b566c31e1fa", "unvendored_tests": false, "version": "2.4.1"}, "pygments": {"depends": [], "file_name": "pygments-2.17.2-py3-none-any.whl", "imports": ["pygments"], "install_dir": "site", "name": "Pygments", "package_type": "package", "sha256": "1873ce1b862d54a9bdf63e6612007832e0ac7abe5a22eefd7f260759b1a83d4c", "unvendored_tests": false, "version": "2.17.2"}, "pyheif": {"depends": ["cffi"], "file_name": "pyheif-0.8.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyheif"], "install_dir": "site", "name": "pyheif", "package_type": "package", "sha256": "2cc3d2c0091aaf73f26476d81fb353830129a619c881d42bb4ee4e310ac25738", "unvendored_tests": false, "version": "0.8.0"}, "pyiceberg": {"depends": ["click", "fsspec", "mmh3", "pydantic", "pyparsing", "requests", "rich", "sortedcontainers", "sqlalchemy", "strictyaml"], "file_name": "pyiceberg-0.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyiceberg"], "install_dir": "site", "name": "pyiceberg", "package_type": "package", "sha256": "ffb45b6e1e89159336607022c15e61906c111c4af816541bbb655ca964793fbe", "unvendored_tests": false, "version": "0.6.0"}, "pyinstrument": {"depends": [], "file_name": "pyinstrument-4.4.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyinstrument"], "install_dir": "site", "name": "pyinstrument", "package_type": "package", "sha256": "3e6ed8e2023741274c627601d926c487b4331318b26a7798a2d538bcaa1b5f31", "unvendored_tests": false, "version": "4.4.0"}, "pynacl": {"depends": ["cffi"], "file_name": "pynacl-1.5.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["nacl"], "install_dir": "site", "name": "pynacl", "package_type": "package", "sha256": "34a05719b22ac0ba51ba7b75e7e8dd4c7f27eabe82e6ef5876c1860e27c66bbd", "unvendored_tests": false, "version": "1.5.0"}, "pyodide-http": {"depends": [], "file_name": "pyodide_http-0.2.1-py3-none-any.whl", "imports": ["pyodide_http"], "install_dir": "site", "name": "pyodide-http", "package_type": "package", "sha256": "90b7303746c4aa808b23dd7328d10ff07300573a0e05ad3d5243f0ccebca6cf4", "unvendored_tests": false, "version": "0.2.1"}, "pyodide-unix-timezones": {"depends": [], "file_name": "pyodide_unix_timezones-1.0.0-py3-none-any.whl", "imports": ["unix_timezones"], "install_dir": "site", "name": "pyodide-unix-timezones", "package_type": "package", "sha256": "827ca2a7344d34bb02fda20226637b28c2724e4c35e701ba399d260a9b410f0e", "unvendored_tests": false, "version": "1.0.0"}, "pyparsing": {"depends": [], "file_name": "pyparsing-3.1.2-py3-none-any.whl", "imports": ["pyparsing"], "install_dir": "site", "name": "pyparsing", "package_type": "package", "sha256": "891387669ff1255b12e7ca1a35ff2691a4e635b016ea9dc32f48b306e2e79c0c", "unvendored_tests": false, "version": "3.1.2"}, "pyproj": {"depends": ["certifi", "sqlite3"], "file_name": "pyproj-3.6.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyproj"], "install_dir": "site", "name": "pyproj", "package_type": "package", "sha256": "9faf4dcde6b70571056f48214ca2283f306673d81a198e9c58c82297fe20d758", "unvendored_tests": false, "version": "3.6.1"}, "pyrsistent": {"depends": [], "file_name": "pyrsistent-0.20.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_pyrsistent_version", "pyrsistent"], "install_dir": "site", "name": "pyrsistent", "package_type": "package", "sha256": "dd92b50845cf849cf9ad3d0d180e492c6117176db556f7e7a29b7444e08a824e", "unvendored_tests": false, "version": "0.20.0"}, "pysam": {"depends": [], "file_name": "pysam-0.22.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pysam"], "install_dir": "site", "name": "pysam", "package_type": "package", "sha256": "93ad0a00f9dbe5eccf7d79d9b2aba7c3b0b677ca9a2235449ff46b9568bb04f7", "unvendored_tests": false, "version": "0.22.0"}, "pyshp": {"depends": [], "file_name": "pyshp-2.3.1-py2.py3-none-any.whl", "imports": ["shapefile"], "install_dir": "site", "name": "pyshp", "package_type": "package", "sha256": "20f5238d19c8513a10365c111acaa492a9d8deb5664a86adb8ba37353a7bd90e", "unvendored_tests": false, "version": "2.3.1"}, "pytest": {"depends": ["atomicwrites", "attrs", "more-itertools", "pluggy", "py", "setuptools", "six", "iniconfig", "exceptiongroup"], "file_name": "pytest-8.1.1-py3-none-any.whl", "imports": ["_pytest", "pytest"], "install_dir": "site", "name": "pytest", "package_type": "package", "sha256": "7c6b1a93a7f7370021edbc7d8e44b30728276699dbc5d23ebc5215a844067720", "unvendored_tests": false, "version": "8.1.1"}, "pytest-asyncio": {"depends": ["pytest"], "file_name": "pytest_asyncio-0.23.7-py3-none-any.whl", "imports": ["pytest_asyncio"], "install_dir": "site", "name": "pytest-asyncio", "package_type": "package", "sha256": "636c56adfb684d7f7b568cb079fd9ea7318831fcdc7abfe0968da09b2471796d", "unvendored_tests": false, "version": "0.23.7"}, "pytest-benchmark": {"depends": [], "file_name": "pytest_benchmark-4.0.0-py3-none-any.whl", "imports": ["pytest_benchmark"], "install_dir": "site", "name": "pytest-benchmark", "package_type": "package", "sha256": "52c6f9db48d069cbb463101a022880d30168fce3617ab4a052a9ca0e519df917", "unvendored_tests": false, "version": "4.0.0"}, "pytest-httpx": {"depends": ["httpx", "pytest", "httpcore"], "file_name": "pytest_httpx-0.30.0-py3-none-any.whl", "imports": ["pytest_httpx"], "install_dir": "site", "name": "pytest_httpx", "package_type": "package", "sha256": "d7ba19b760fd56f8c6f42d4e278ee2f36e4334d861ae8394a2c8e1e4eb41886b", "unvendored_tests": false, "version": "0.30.0"}, "python-dateutil": {"depends": ["six"], "file_name": "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", "imports": ["dateutil"], "install_dir": "site", "name": "python-dateutil", "package_type": "package", "sha256": "ae746faed61551f3cc0d663f52f732551c3e3f8c6c61c6b36862440819acd470", "unvendored_tests": false, "version": "2.9.0.post0"}, "python-flint": {"depends": [], "file_name": "python_flint-0.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["flint"], "install_dir": "site", "name": "python-flint", "package_type": "package", "sha256": "e2850dc68fd5a3842f4745ff878e6af572248e2c6ff804fc2346c498ae8b75eb", "unvendored_tests": false, "version": "0.6.0"}, "python-magic": {"depends": ["libmagic"], "file_name": "python_magic-0.4.27-py2.py3-none-any.whl", "imports": ["magic"], "install_dir": "site", "name": "python-magic", "package_type": "package", "sha256": "89217fc159715cec8055e84184883f882b1d468974ce76c25def46b606c9d7e4", "unvendored_tests": false, "version": "0.4.27"}, "python-sat": {"depends": ["six"], "file_name": "python_sat-1.8.dev13-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pysat"], "install_dir": "site", "name": "python-sat", "package_type": "package", "sha256": "041e88de4db9e981796dd8cb8e924b40f8723915c831d9bcba802a557cc28ba0", "unvendored_tests": false, "version": "1.8.dev13"}, "python-solvespace": {"depends": [], "file_name": "python_solvespace-3.0.8-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["python_solvespace"], "install_dir": "site", "name": "python-solvespace", "package_type": "package", "sha256": "e7ec8d1a549578c1405c25c38fe5034ad5c95bbf090d414ef8610e775d738cd1", "unvendored_tests": false, "version": "3.0.8"}, "pytz": {"depends": [], "file_name": "pytz-2024.1-py2.py3-none-any.whl", "imports": ["pytz"], "install_dir": "site", "name": "pytz", "package_type": "package", "sha256": "dc3559afd49896fa97d16d17cc802d2ee8e5247d26a15cb4338656b5b079dc00", "unvendored_tests": false, "version": "2024.1"}, "pywavelets": {"depends": ["numpy"], "file_name": "pywavelets-1.8.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pywt"], "install_dir": "site", "name": "pywavelets", "package_type": "package", "sha256": "8b9eba80802ed5d4626a51825ff14bb7777df205e0b376fc72b7270d50959167", "unvendored_tests": true, "version": "1.8.0"}, "pywavelets-tests": {"depends": ["pywavelets"], "file_name": "pywavelets-tests.tar", "imports": [], "install_dir": "site", "name": "pywavelets-tests", "package_type": "package", "sha256": "26c5bcba2fc0b4d8a84982123cf6f598b1c5e480fd3ee999063173191372af09", "unvendored_tests": false, "version": "1.8.0"}, "pyxel": {"depends": [], "file_name": "pyxel-1.9.10-cp37-abi3-pyodide_2024_0_wasm32.whl", "imports": ["pyxel"], "install_dir": "site", "name": "pyxel", "package_type": "package", "sha256": "5fed5de64a1a61a9f17a9a35db3744c2f540ad5e494f799cc47991a27dcc638c", "unvendored_tests": false, "version": "1.9.10"}, "pyxirr": {"depends": [], "file_name": "pyxirr-0.10.6-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["pyxirr"], "install_dir": "site", "name": "pyxirr", "package_type": "package", "sha256": "11687e94f153eccd179aaa1538da4cec2bc425892bf77eb13935e605cacc1d6c", "unvendored_tests": false, "version": "0.10.6"}, "pyyaml": {"depends": [], "file_name": "pyyaml-6.0.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["_yaml", "yaml"], "install_dir": "site", "name": "pyyaml", "package_type": "package", "sha256": "58acd6abad0ee4a419dd3c1c895d143a7f430d95213f01d8fe379e72a8ab4a03", "unvendored_tests": false, "version": "6.0.2"}, "rasterio": {"depends": ["numpy", "affine", "gdal", "attrs", "certifi", "click", "cligj"], "file_name": "rasterio-1.4.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rasterio"], "install_dir": "site", "name": "rasterio", "package_type": "package", "sha256": "fa4a8c6c1f5565c3cbb2b9e4f80ae4d42b21189f9f583a137cb635418c838c60", "unvendored_tests": false, "version": "1.4.2"}, "rateslib": {"depends": ["numpy", "pandas", "matplotlib"], "file_name": "rateslib-1.6.0-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["rateslib"], "install_dir": "site", "name": "rateslib", "package_type": "package", "sha256": "cb2687fa523b6fa8ff4799380cbdfb60e21ea0573109245db232d5291d66a788", "unvendored_tests": false, "version": "1.6.0"}, "rebound": {"depends": ["numpy"], "file_name": "rebound-4.4.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rebound"], "install_dir": "site", "name": "rebound", "package_type": "package", "sha256": "ac471b8f8f09a33506744491307b69445e496525c86b116062d523d211e59082", "unvendored_tests": false, "version": "4.4.3"}, "reboundx": {"depends": ["rebound", "numpy"], "file_name": "reboundx-4.3.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["reboundx"], "install_dir": "site", "name": "reboundx", "package_type": "package", "sha256": "1924a624a297d9ee10c562935c5badb4fdbf4dc3e08eeb16b4f48a992a911e16", "unvendored_tests": false, "version": "4.3.0"}, "referencing": {"depends": ["attrs", "rpds-py"], "file_name": "referencing-0.34.0-py3-none-any.whl", "imports": ["referencing"], "install_dir": "site", "name": "referencing", "package_type": "package", "sha256": "f96d58b2f8e15d11230b3e91004b93a27da2d3f5c25287f4590933f14bf6d759", "unvendored_tests": true, "version": "0.34.0"}, "referencing-tests": {"depends": ["referencing"], "file_name": "referencing-tests.tar", "imports": [], "install_dir": "site", "name": "referencing-tests", "package_type": "package", "sha256": "994e834e76aa41be940f446682791a526d688ec00583864b57e2ba9f4f293417", "unvendored_tests": false, "version": "0.34.0"}, "regex": {"depends": [], "file_name": "regex-2024.9.11-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["regex"], "install_dir": "site", "name": "regex", "package_type": "package", "sha256": "03be0e532aad2f53a4037ce910323cd8f9cc413f88c19fcdf37dde4851e0383b", "unvendored_tests": true, "version": "2024.9.11"}, "regex-tests": {"depends": ["regex"], "file_name": "regex-tests.tar", "imports": [], "install_dir": "site", "name": "regex-tests", "package_type": "package", "sha256": "275d78a9f21fdccd24ca9ddce624dcaba6801fd30b9c5aa10d8e7301f2196582", "unvendored_tests": false, "version": "2024.9.11"}, "requests": {"depends": ["charset-normalizer", "idna", "urllib3", "certifi"], "file_name": "requests-2.31.0-py3-none-any.whl", "imports": ["requests"], "install_dir": "site", "name": "requests", "package_type": "package", "sha256": "276634b754dc1cec8c56f5a007b6105cdb5a5e4bcf185866e9aad284234ee31c", "unvendored_tests": false, "version": "2.31.0"}, "retrying": {"depends": ["six"], "file_name": "retrying-1.3.4-py3-none-any.whl", "imports": ["retrying"], "install_dir": "site", "name": "retrying", "package_type": "package", "sha256": "7398762af3d140bf4e2e1f04bc38818384ba4c3ad9b19dbd167896b91e88435e", "unvendored_tests": false, "version": "1.3.4"}, "rich": {"depends": [], "file_name": "rich-13.7.1-py3-none-any.whl", "imports": ["rich"], "install_dir": "site", "name": "rich", "package_type": "package", "sha256": "b2d44df384df95eda76798b41f3fbe9bd0d0f711fb39dbd0ddb6651a5b541809", "unvendored_tests": false, "version": "13.7.1"}, "river": {"depends": ["numpy", "pandas", "scipy"], "file_name": "river-0.22.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["river"], "install_dir": "site", "name": "river", "package_type": "package", "sha256": "624c62ffd7157159f6dc2f903ef3081cd33a2900afc74b526027d01536efb361", "unvendored_tests": true, "version": "0.22.0"}, "river-tests": {"depends": ["river"], "file_name": "river-tests.tar", "imports": [], "install_dir": "site", "name": "river-tests", "package_type": "package", "sha256": "f4cfb6e0ff124654976a06af51124e1e1dce087cbb6b98a8e07942e04396f9cd", "unvendored_tests": false, "version": "0.22.0"}, "robotraconteur": {"depends": ["numpy"], "file_name": "robotraconteur-1.2.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["RobotRaconteur"], "install_dir": "site", "name": "RobotRaconteur", "package_type": "package", "sha256": "13ebb279ca35f3cde2aa74e7ceb1f9af5564c2b8d7ff7d65cf61636d63593c90", "unvendored_tests": false, "version": "1.2.2"}, "rpds-py": {"depends": [], "file_name": "rpds_py-0.18.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rpds"], "install_dir": "site", "name": "rpds-py", "package_type": "package", "sha256": "31d6ed4039e2ce268b95c29851cea53a96d8910a096f3f739ba85f81aa8badb3", "unvendored_tests": false, "version": "0.18.0"}, "ruamel-yaml": {"depends": [], "file_name": "ruamel.yaml-0.18.6-py3-none-any.whl", "imports": ["ruamel"], "install_dir": "site", "name": "ruamel.yaml", "package_type": "package", "sha256": "ed95f4c022ae2091f2eccce618bcbf256fd7da3e9ddabb2f7bb7e68105876bf7", "unvendored_tests": false, "version": "0.18.6"}, "rust-abi-test": {"depends": [], "file_name": "rust_abi_test-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rust-abi-test"], "install_dir": "site", "name": "rust-abi-test", "package_type": "package", "sha256": "660fe1cc35c05c1d6135d951d5f73ebd592c7920afb20b20ef4afaf89d761cb3", "unvendored_tests": false, "version": "1.0"}, "rust-panic-test": {"depends": [], "file_name": "rust_panic_test-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["rust-panic-test"], "install_dir": "site", "name": "rust-panic-test", "package_type": "package", "sha256": "e55108de5dde410f2f5a1ffe1bc7da71feb6b943d9827eb7171bd5c337aab5ea", "unvendored_tests": false, "version": "1.0"}, "scikit-image": {"depends": ["packaging", "numpy", "scipy", "networkx", "pillow", "imageio", "pywavelets", "lazy_loader"], "file_name": "scikit_image-0.25.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["skimage"], "install_dir": "site", "name": "scikit-image", "package_type": "package", "sha256": "0a29586de31c1adc93bef2789f58651a23e0f34a6b0eb905cd31447a3b06acf3", "unvendored_tests": true, "version": "0.25.0"}, "scikit-image-tests": {"depends": ["scikit-image"], "file_name": "scikit-image-tests.tar", "imports": [], "install_dir": "site", "name": "scikit-image-tests", "package_type": "package", "sha256": "3d331996093686dde4207622763a285671106939153f9b2ab3932e5b6002ca02", "unvendored_tests": false, "version": "0.25.0"}, "scikit-learn": {"depends": ["scipy", "joblib", "threadpoolctl"], "file_name": "scikit_learn-1.6.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sklearn"], "install_dir": "site", "name": "scikit-learn", "package_type": "package", "sha256": "0cc13c8e59dfa7c02e062d94a27324dae64bf55926ba2bfd101fdc26bcb8729b", "unvendored_tests": true, "version": "1.6.1"}, "scikit-learn-tests": {"depends": ["scikit-learn"], "file_name": "scikit-learn-tests.tar", "imports": [], "install_dir": "site", "name": "scikit-learn-tests", "package_type": "package", "sha256": "c1379d0d9468bc6d4a604c27bc5da240c01fdf1f80d9ccd0f678b21f4159dd43", "unvendored_tests": false, "version": "1.6.1"}, "scipy": {"depends": ["numpy", "openblas"], "file_name": "scipy-1.14.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["scipy"], "install_dir": "site", "name": "scipy", "package_type": "package", "sha256": "4f1a0684ce8c2f91a985fbd4ecfefc186b4ff8494c0a28556c210ea00899b233", "unvendored_tests": true, "version": "1.14.1"}, "scipy-tests": {"depends": ["scipy"], "file_name": "scipy-tests.tar", "imports": [], "install_dir": "site", "name": "scipy-tests", "package_type": "package", "sha256": "cbf695618fc73dc9646983782ad55d0dbe0b5fdedb1a84d82d7efd6d06d672be", "unvendored_tests": false, "version": "1.14.1"}, "screed": {"depends": [], "file_name": "screed-1.1.3-py2.py3-none-any.whl", "imports": ["bigtests", "screed"], "install_dir": "site", "name": "screed", "package_type": "package", "sha256": "4dc98aa71bb13a55a7c14d6b3450660661c838b5dd3ca8812a1e7153dc3a9808", "unvendored_tests": true, "version": "1.1.3"}, "screed-tests": {"depends": ["screed"], "file_name": "screed-tests.tar", "imports": [], "install_dir": "site", "name": "screed-tests", "package_type": "package", "sha256": "064f1b2e89ad6e3be0cef4ed9f7a80483988fbe8383cf3400728629bed82fc4e", "unvendored_tests": false, "version": "1.1.3"}, "setuptools": {"depends": ["pyparsing"], "file_name": "setuptools-69.5.1-py3-none-any.whl", "imports": ["_distutils_hack", "pkg_resources", "setuptools"], "install_dir": "site", "name": "setuptools", "package_type": "package", "sha256": "ca49b2e2f1d6bf77a513462beffe3951a31f0f10e8fe0ee4b333f8b83aa73ca1", "unvendored_tests": false, "version": "69.5.1"}, "shapely": {"depends": ["numpy"], "file_name": "shapely-2.0.6-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["shapely"], "install_dir": "site", "name": "shapely", "package_type": "package", "sha256": "49d34e4a8d139a2ba46cf2cc9aab9f4f0f0e4d56dc30966ec266e9d2eae94253", "unvendored_tests": true, "version": "2.0.6"}, "shapely-tests": {"depends": ["shapely"], "file_name": "shapely-tests.tar", "imports": [], "install_dir": "site", "name": "shapely-tests", "package_type": "package", "sha256": "4c6aa1b8ef642c017bad9f062a0caf5753bd22bfe64910de3a944a0c1bf857ca", "unvendored_tests": false, "version": "2.0.6"}, "sharedlib-test": {"depends": [], "file_name": "sharedlib-test-1.0.zip", "imports": [], "install_dir": "dynlib", "name": "sharedlib-test", "package_type": "shared_library", "sha256": "b9d77b594114f514de225232b0ffddd4e0d39559a399886812e4eb7aee7be7c5", "unvendored_tests": false, "version": "1.0"}, "sharedlib-test-py": {"depends": ["sharedlib-test"], "file_name": "sharedlib_test_py-1.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sharedlib_test"], "install_dir": "site", "name": "sharedlib-test-py", "package_type": "package", "sha256": "813ef309eb591b2b61ace3a3b9073e85c1e603e68302e71d480ca95dfc7ef5b6", "unvendored_tests": false, "version": "1.0"}, "simplejson": {"depends": [], "file_name": "simplejson-3.19.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["simplejson"], "install_dir": "site", "name": "simplejson", "package_type": "package", "sha256": "c4e6d7551386be3ee21f5d42075efe4bfe361760e5cbf96a6b6ff3c6e9b92f08", "unvendored_tests": true, "version": "3.19.2"}, "simplejson-tests": {"depends": ["simplejson"], "file_name": "simplejson-tests.tar", "imports": [], "install_dir": "site", "name": "simplejson-tests", "package_type": "package", "sha256": "3928aa102ce9df50576a0fcf40a93d16977f44fadcbfcd10b3714169689bca3b", "unvendored_tests": false, "version": "3.19.2"}, "sisl": {"depends": ["pyparsing", "numpy", "scipy", "tqdm", "xarray", "pandas", "matplotlib"], "file_name": "sisl-0.15.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sisl_toolbox", "sisl"], "install_dir": "site", "name": "sisl", "package_type": "package", "sha256": "8ec753646c2209213cd914752c2eb99ebd8dd51e75a9597e042b5bc6aa111208", "unvendored_tests": true, "version": "0.15.1"}, "sisl-tests": {"depends": ["sisl"], "file_name": "sisl-tests.tar", "imports": [], "install_dir": "site", "name": "sisl-tests", "package_type": "package", "sha256": "2465d1a1df18c81eb11f9232b4c7bd0af0a2628fca68d3b7a4844265fbfbf350", "unvendored_tests": false, "version": "0.15.1"}, "six": {"depends": [], "file_name": "six-1.16.0-py2.py3-none-any.whl", "imports": ["six"], "install_dir": "site", "name": "six", "package_type": "package", "sha256": "894f203bc82a942d3a405dbd15ac331a6bd3f63fedadfbb5a557a8ed7f13a9b3", "unvendored_tests": false, "version": "1.16.0"}, "smart-open": {"depends": ["wrapt"], "file_name": "smart_open-7.0.4-py3-none-any.whl", "imports": ["smart_open"], "install_dir": "site", "name": "smart-open", "package_type": "package", "sha256": "5f671959bfe064e4fcace74aca923c5965edb6e5b83dd97d366951587cce4d71", "unvendored_tests": false, "version": "7.0.4"}, "sniffio": {"depends": [], "file_name": "sniffio-1.3.1-py3-none-any.whl", "imports": ["sniffio"], "install_dir": "site", "name": "sniffio", "package_type": "package", "sha256": "abd0199c829c9852b7520199b1e3de1baeafd71ea5b9948f6c4103f3c1498159", "unvendored_tests": true, "version": "1.3.1"}, "sniffio-tests": {"depends": ["sniffio"], "file_name": "sniffio-tests.tar", "imports": [], "install_dir": "site", "name": "sniffio-tests", "package_type": "package", "sha256": "402fec0d65a2932ab77de9d6d3b5c53ce21b6f738a9827468cfb73cbf0a8134f", "unvendored_tests": false, "version": "1.3.1"}, "sortedcontainers": {"depends": [], "file_name": "sortedcontainers-2.4.0-py2.py3-none-any.whl", "imports": ["sortedcontainers"], "install_dir": "site", "name": "sortedcontainers", "package_type": "package", "sha256": "d4778097924f0882545cad8893dbf12482e6c19af0674480dd8caa295589a855", "unvendored_tests": false, "version": "2.4.0"}, "soupsieve": {"depends": [], "file_name": "soupsieve-2.5-py3-none-any.whl", "imports": ["soupsieve"], "install_dir": "site", "name": "soupsieve", "package_type": "package", "sha256": "ffa2ba33193667822322597c6840b7a51ad7e852e4223ea90f87e37d5659fc1a", "unvendored_tests": false, "version": "2.5"}, "sourmash": {"depends": ["screed", "cffi", "deprecation", "cachetools", "numpy", "matplotlib", "scipy", "sqlite3", "bitstring"], "file_name": "sourmash-4.8.11-py3-none-pyodide_2024_0_wasm32.whl", "imports": ["sourmash"], "install_dir": "site", "name": "sourmash", "package_type": "package", "sha256": "e58546944be9dc19f9e06ddc8016b3ff371d4bfbc8986aef9cf57800e651356b", "unvendored_tests": false, "version": "4.8.11"}, "soxr": {"depends": ["numpy"], "file_name": "soxr-0.5.0.post1-cp312-abi3-pyodide_2024_0_wasm32.whl", "imports": ["soxr"], "install_dir": "site", "name": "soxr", "package_type": "package", "sha256": "a4763a2932daffc419260192f591109dc7b33aff57fd9d8502b28f575698cfbb", "unvendored_tests": false, "version": "0.5.0.post1"}, "sparseqr": {"depends": ["pycparser", "cffi", "numpy", "scipy", "suitesparse"], "file_name": "sparseqr-1.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sparseqr"], "install_dir": "site", "name": "sparseqr", "package_type": "package", "sha256": "e21eed75fa71b72bd19562b6ddb5d98669ade84f047089548a6065d72e47e324", "unvendored_tests": false, "version": "1.2"}, "sqlalchemy": {"depends": ["sqlite3", "typing-extensions"], "file_name": "sqlalchemy-2.0.29-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sqlalchemy"], "install_dir": "site", "name": "sqlalchemy", "package_type": "package", "sha256": "78d085b308f648b836bf362dfd133f9b3cd2a3f1f836532b277e26b9df60158b", "unvendored_tests": true, "version": "2.0.29"}, "sqlalchemy-tests": {"depends": ["sqlalchemy"], "file_name": "sqlalchemy-tests.tar", "imports": [], "install_dir": "site", "name": "sqlalchemy-tests", "package_type": "package", "sha256": "fee0fd0a369e6c7c5348f7c78a6e63a2bfed3a46d1f1a02c6e8abacc4e8b86d4", "unvendored_tests": false, "version": "2.0.29"}, "sqlite3": {"depends": [], "file_name": "sqlite3-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["sqlite3", "_sqlite3"], "install_dir": "site", "name": "sqlite3", "package_type": "cpython_module", "sha256": "e636899fc57ab8bc4861e36468bd0926194359d8c55e997b40971b19ece7345c", "unvendored_tests": false, "version": "1.0.0"}, "ssl": {"depends": ["openssl"], "file_name": "ssl-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["ssl", "_ssl"], "install_dir": "site", "name": "ssl", "package_type": "cpython_module", "sha256": "3fe64c940c16393ddf91b37d3f4328cee09a774e58ce2bef5ea774c40f6da01a", "unvendored_tests": false, "version": "1.0.0"}, "stack-data": {"depends": ["executing", "asttokens", "pure-eval"], "file_name": "stack_data-0.6.3-py3-none-any.whl", "imports": ["stack_data"], "install_dir": "site", "name": "stack-data", "package_type": "package", "sha256": "3c62ca4126609a6130fc44b048be8c3e736f5b0773a22767696b8e772e8bff74", "unvendored_tests": false, "version": "0.6.3"}, "statsmodels": {"depends": ["numpy", "scipy", "pandas", "patsy", "packaging"], "file_name": "statsmodels-0.14.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["statsmodels"], "install_dir": "site", "name": "statsmodels", "package_type": "package", "sha256": "85183af20425f787398929a6169e6acd194e561a8acc287de2bc75fe4f091723", "unvendored_tests": false, "version": "0.14.4"}, "strictyaml": {"depends": ["python-dateutil"], "file_name": "strictyaml-1.7.3-py3-none-any.whl", "imports": ["strictyaml"], "install_dir": "site", "name": "strictyaml", "package_type": "package", "sha256": "3ce62e91c18e41116003d19e40d87a51718e89daba8d9cb6bcd2247c1721b53b", "unvendored_tests": false, "version": "1.7.3"}, "suitesparse": {"depends": ["openblas"], "file_name": "suitesparse-5.11.0.zip", "imports": [], "install_dir": "dynlib", "name": "suitesparse", "package_type": "shared_library", "sha256": "a9fdad02424af094f485dbd8e2973f271ce4dad4525e8e57bee0bf674ab1b42d", "unvendored_tests": false, "version": "5.11.0"}, "svgwrite": {"depends": [], "file_name": "svgwrite-1.4.3-py3-none-any.whl", "imports": ["svgwrite"], "install_dir": "site", "name": "svgwrite", "package_type": "package", "sha256": "d79a7901cb3d7a1262e33b576115daaa5458f90b007febedd273fc079fa961d3", "unvendored_tests": false, "version": "1.4.3"}, "swiglpk": {"depends": [], "file_name": "swiglpk-5.0.10-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["swiglpk"], "install_dir": "site", "name": "swiglpk", "package_type": "package", "sha256": "3c310af347afcbe68da00b287f3901b624319c622f755ed8119d8d0058794c26", "unvendored_tests": false, "version": "5.0.10"}, "sympy": {"depends": ["mpmath"], "file_name": "sympy-1.13.3-py3-none-any.whl", "imports": ["isympy", "sympy"], "install_dir": "site", "name": "sympy", "package_type": "package", "sha256": "9573c186118a90b78f0772742beb7683b132f20b88e560928dac1279d5638d08", "unvendored_tests": true, "version": "1.13.3"}, "sympy-tests": {"depends": ["sympy"], "file_name": "sympy-tests.tar", "imports": [], "install_dir": "site", "name": "sympy-tests", "package_type": "package", "sha256": "c192b4c2bab13a2e50eaa6dfe8bca3158fd931d22d562c2bf0ecc3a0aab0fb31", "unvendored_tests": false, "version": "1.13.3"}, "tblib": {"depends": [], "file_name": "tblib-3.0.0-py3-none-any.whl", "imports": ["tblib"], "install_dir": "site", "name": "tblib", "package_type": "package", "sha256": "15163ab202bc5f6ac2f4f1cfe6e02fdb1aa4bfa829cf6610df2768d3dea56ad0", "unvendored_tests": false, "version": "3.0.0"}, "termcolor": {"depends": [], "file_name": "termcolor-2.4.0-py3-none-any.whl", "imports": ["termcolor"], "install_dir": "site", "name": "termcolor", "package_type": "package", "sha256": "df87573f28dc7c0ebe2b0deb64a4f51ac199f445ede41f863e2189b032db7b24", "unvendored_tests": false, "version": "2.4.0"}, "test": {"depends": [], "file_name": "test-1.0.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["test"], "install_dir": "site", "name": "test", "package_type": "cpython_module", "sha256": "404f292ff7629068eff727c46d2116f3a6354c6161c30d59582d80bb045493b3", "unvendored_tests": false, "version": "1.0.0"}, "texttable": {"depends": [], "file_name": "texttable-1.7.0-py2.py3-none-any.whl", "imports": ["texttable"], "install_dir": "site", "name": "texttable", "package_type": "package", "sha256": "20bf4534688e8e0f4ea09b793cdba58885181fab5e3bdfc9a25712284b1cf0cd", "unvendored_tests": false, "version": "1.7.0"}, "threadpoolctl": {"depends": [], "file_name": "threadpoolctl-3.5.0-py3-none-any.whl", "imports": ["threadpoolctl"], "install_dir": "site", "name": "threadpoolctl", "package_type": "package", "sha256": "511082e407d392ddd56579c8f63a80f62a16a1534c908dc0c1f1aab3e12cf53b", "unvendored_tests": false, "version": "3.5.0"}, "tiktoken": {"depends": ["regex", "requests"], "file_name": "tiktoken-0.8.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["tiktoken", "tiktoken_ext"], "install_dir": "site", "name": "tiktoken", "package_type": "package", "sha256": "751bc1f7eda588a7991e44893fae11121b368f31e1e4a163fd98e27217786b40", "unvendored_tests": false, "version": "0.8.0"}, "tomli": {"depends": [], "file_name": "tomli-2.0.1-py3-none-any.whl", "imports": ["tomli"], "install_dir": "site", "name": "tomli", "package_type": "package", "sha256": "57e063ddbc2c438e123ef11038f6a14c1b12f2104dd90ed504f1c7a3d1b6a4ee", "unvendored_tests": false, "version": "2.0.1"}, "tomli-w": {"depends": [], "file_name": "tomli_w-1.0.0-py3-none-any.whl", "imports": ["tomli_w"], "install_dir": "site", "name": "tomli-w", "package_type": "package", "sha256": "7e85d74811bb9e5e5b8a0385ada9c10196060d987eb100b2fa75e37b725b4082", "unvendored_tests": false, "version": "1.0.0"}, "toolz": {"depends": [], "file_name": "toolz-0.12.1-py3-none-any.whl", "imports": ["tlz", "toolz"], "install_dir": "site", "name": "toolz", "package_type": "package", "sha256": "f37aa33421f36ac2bb510cf75de14bd8f65d1920ee5d2c64a7763a0f7e19790a", "unvendored_tests": true, "version": "0.12.1"}, "toolz-tests": {"depends": ["toolz"], "file_name": "toolz-tests.tar", "imports": [], "install_dir": "site", "name": "toolz-tests", "package_type": "package", "sha256": "91feca5cdec5320378e6b3407429521827a6d2075c8f005b2033488fd232cf20", "unvendored_tests": false, "version": "0.12.1"}, "tqdm": {"depends": [], "file_name": "tqdm-4.66.2-py3-none-any.whl", "imports": ["tqdm"], "install_dir": "site", "name": "tqdm", "package_type": "package", "sha256": "c9e5d957fea777b71aff50fc4ca29694139e07657504230aa86ca9f435f6b3b4", "unvendored_tests": false, "version": "4.66.2"}, "traitlets": {"depends": [], "file_name": "traitlets-5.14.3-py3-none-any.whl", "imports": ["traitlets"], "install_dir": "site", "name": "traitlets", "package_type": "package", "sha256": "d2a6705ef61df8d249283580a6b58fa8a79732e605d7962f9646d1e38d311211", "unvendored_tests": true, "version": "5.14.3"}, "traitlets-tests": {"depends": ["traitlets"], "file_name": "traitlets-tests.tar", "imports": [], "install_dir": "site", "name": "traitlets-tests", "package_type": "package", "sha256": "2e4133b69e59c927f0244cdc62225cd448dc0c9b2f9513015d9dbbd2bfef50a3", "unvendored_tests": false, "version": "5.14.3"}, "traits": {"depends": [], "file_name": "traits-6.4.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["traits"], "install_dir": "site", "name": "traits", "package_type": "package", "sha256": "44876e5c5b407016a5f102e90877330a1f7082cc1a3285dd9326eae520ba3aa7", "unvendored_tests": true, "version": "6.4.3"}, "traits-tests": {"depends": ["traits"], "file_name": "traits-tests.tar", "imports": [], "install_dir": "site", "name": "traits-tests", "package_type": "package", "sha256": "b5accca3f46624a57a78bb11622fbd67f99d2e4b5794d90da35759ef9e8a8610", "unvendored_tests": false, "version": "6.4.3"}, "tree-sitter": {"depends": [], "file_name": "tree_sitter-0.23.2-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter"], "install_dir": "site", "name": "tree-sitter", "package_type": "package", "sha256": "5856dd4e0dd3f3d8dabc2ebe779c39ee705cf2c47f1c2fd98ab44351c7af8bbc", "unvendored_tests": false, "version": "0.23.2"}, "tree-sitter-go": {"depends": ["tree-sitter"], "file_name": "tree_sitter_go-0.23.3-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter_go"], "install_dir": "site", "name": "tree-sitter-go", "package_type": "package", "sha256": "451d9f20877fa214d12a287ccbd74fff47ed8b44aade43504170fa15f526a062", "unvendored_tests": false, "version": "0.23.3"}, "tree-sitter-java": {"depends": ["tree-sitter"], "file_name": "tree_sitter_java-0.23.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter_java"], "install_dir": "site", "name": "tree-sitter-java", "package_type": "package", "sha256": "cd09cb0924fd528d6bc61d3be576f63c38f382287243f0e3adc70e5f48cc808d", "unvendored_tests": false, "version": "0.23.4"}, "tree-sitter-python": {"depends": ["tree-sitter"], "file_name": "tree_sitter_python-0.23.4-cp39-abi3-pyodide_2024_0_wasm32.whl", "imports": ["tree_sitter_python"], "install_dir": "site", "name": "tree-sitter-python", "package_type": "package", "sha256": "fa9efec77f729570b272995edf857dc7371e0ca3b74f3319cc793e9bc051d0d7", "unvendored_tests": false, "version": "0.23.4"}, "tskit": {"depends": ["numpy", "svgwrite", "jsonschema", "rpds-py"], "file_name": "tskit-0.6.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["tskit"], "install_dir": "site", "name": "tskit", "package_type": "package", "sha256": "5e831ac0d0f856e9f053e398a1db2e55f42d6c52404fb65524a9e21b1e3206cd", "unvendored_tests": false, "version": "0.6.0"}, "typing-extensions": {"depends": [], "file_name": "typing_extensions-4.11.0-py3-none-any.whl", "imports": ["typing_extensions"], "install_dir": "site", "name": "typing-extensions", "package_type": "package", "sha256": "c5d83049b5bffe93555e107f59206beea237ecaa96c239a541ac3a1ae112a8be", "unvendored_tests": false, "version": "4.11.0"}, "tzdata": {"depends": [], "file_name": "tzdata-2024.1-py2.py3-none-any.whl", "imports": ["tzdata"], "install_dir": "site", "name": "tzdata", "package_type": "package", "sha256": "a5dc514d6359be6ca42c353f0ae900a59a1674bff2b77904cae0aac4056f4a37", "unvendored_tests": false, "version": "2024.1"}, "uncertainties": {"depends": ["future"], "file_name": "uncertainties-3.1.7-py2.py3-none-any.whl", "imports": ["uncertainties"], "install_dir": "site", "name": "uncertainties", "package_type": "package", "sha256": "77d8ac45e59dc469c33ef08fd6154aaa0a3a5286b411d011fa591b7db8b9fed9", "unvendored_tests": true, "version": "3.1.7"}, "uncertainties-tests": {"depends": ["uncertainties"], "file_name": "uncertainties-tests.tar", "imports": [], "install_dir": "site", "name": "uncertainties-tests", "package_type": "package", "sha256": "5f87266c5dd7fcccc7ddec1568465991f78f0095e99778e0b84cdd01bbc9bf51", "unvendored_tests": false, "version": "3.1.7"}, "unyt": {"depends": ["numpy", "packaging", "sympy"], "file_name": "unyt-3.0.3-py3-none-any.whl", "imports": ["unyt"], "install_dir": "site", "name": "unyt", "package_type": "package", "sha256": "d84be2febc2d98fb380b1e85d37493768bbe4989d3cb79d6fbbb555bed79e70b", "unvendored_tests": true, "version": "3.0.3"}, "unyt-tests": {"depends": ["unyt"], "file_name": "unyt-tests.tar", "imports": [], "install_dir": "site", "name": "unyt-tests", "package_type": "package", "sha256": "182bd14a80049a4e6f0f7b7f66d4797abdf82d385c103c5cf1a2eb28fc209c8e", "unvendored_tests": false, "version": "3.0.3"}, "urllib3": {"depends": [], "file_name": "urllib3-2.2.3-py3-none-any.whl", "imports": ["urllib3"], "install_dir": "site", "name": "urllib3", "package_type": "package", "sha256": "8b4e298e3922b4f300dac60a56a2297f5f45618078859876d279ee01f4cd8336", "unvendored_tests": false, "version": "2.2.3"}, "vega-datasets": {"depends": ["pandas"], "file_name": "vega_datasets-0.9.0-py3-none-any.whl", "imports": ["vega_datasets"], "install_dir": "site", "name": "vega-datasets", "package_type": "package", "sha256": "3fd304baa3e4418bd04c5f792f4e0ce47adeec0d5df302501c47dcf9518562dc", "unvendored_tests": true, "version": "0.9.0"}, "vega-datasets-tests": {"depends": ["vega-datasets"], "file_name": "vega-datasets-tests.tar", "imports": [], "install_dir": "site", "name": "vega-datasets-tests", "package_type": "package", "sha256": "dd2323e9016863143b0209e13647e0e8a938803b213f171f5aebada347165c0e", "unvendored_tests": false, "version": "0.9.0"}, "wcwidth": {"depends": [], "file_name": "wcwidth-0.2.13-py2.py3-none-any.whl", "imports": ["wcwidth"], "install_dir": "site", "name": "wcwidth", "package_type": "package", "sha256": "3450b26dc882024b4c6b9e4d06f6ecf06617b02204797937144e91be4e5d8550", "unvendored_tests": false, "version": "0.2.13"}, "webencodings": {"depends": [], "file_name": "webencodings-0.5.1-py2.py3-none-any.whl", "imports": ["webencodings"], "install_dir": "site", "name": "webencodings", "package_type": "package", "sha256": "757ae337e56e3cc2c130856aed4458ca8d2aaad8ef7c95f4afba464d3001717b", "unvendored_tests": false, "version": "0.5.1"}, "wordcloud": {"depends": ["matplotlib"], "file_name": "wordcloud-1.9.3-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["wordcloud"], "install_dir": "site", "name": "wordcloud", "package_type": "package", "sha256": "43397c51f157e0217ce05eba8c3124b70068103aceafe6e833dfdab7f71989a8", "unvendored_tests": false, "version": "1.9.3"}, "wrapt": {"depends": [], "file_name": "wrapt-1.16.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["wrapt"], "install_dir": "site", "name": "wrapt", "package_type": "package", "sha256": "67ff5bba92fa0df4d0877bccc5416bbbc22b7984319c519b8da35f4f8e7ad749", "unvendored_tests": false, "version": "1.16.0"}, "xarray": {"depends": ["numpy", "packaging", "pandas"], "file_name": "xarray-2024.11.0-py3-none-any.whl", "imports": ["xarray"], "install_dir": "site", "name": "xarray", "package_type": "package", "sha256": "e66982e156be82a5e98685ea5588b128f241578f1765c5d3e904d023a8075b97", "unvendored_tests": true, "version": "2024.11.0"}, "xarray-tests": {"depends": ["xarray"], "file_name": "xarray-tests.tar", "imports": [], "install_dir": "site", "name": "xarray-tests", "package_type": "package", "sha256": "6079c8e7bd67fe3080b7cd40b26ca465421eacfd86c5a42ec35fa80dd7194d29", "unvendored_tests": false, "version": "2024.11.0"}, "xgboost": {"depends": ["numpy", "scipy", "setuptools"], "file_name": "xgboost-2.1.2-py3-none-pyodide_2024_0_wasm32.whl", "imports": ["xgboost"], "install_dir": "site", "name": "xgboost", "package_type": "package", "sha256": "5cb188b4a6ec13f196c9068e8eff09d582c5f865b49b66293253327f0992278d", "unvendored_tests": false, "version": "2.1.2"}, "xlrd": {"depends": [], "file_name": "xlrd-2.0.1-py2.py3-none-any.whl", "imports": ["xlrd"], "install_dir": "site", "name": "xlrd", "package_type": "package", "sha256": "72ea12240afdda83bec992ab1dd118bd9cfb5285ffc5236ad6184a52e56cce9e", "unvendored_tests": false, "version": "2.0.1"}, "xxhash": {"depends": [], "file_name": "xxhash-3.4.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["xxhash"], "install_dir": "site", "name": "xxhash", "package_type": "package", "sha256": "a6dd829b60e0c24774b14819830b9faf66d554cb1aec9235bd75f28b1167af0f", "unvendored_tests": false, "version": "3.4.1"}, "xyzservices": {"depends": [], "file_name": "xyzservices-2024.4.0-py3-none-any.whl", "imports": ["xyzservices"], "install_dir": "site", "name": "xyzservices", "package_type": "package", "sha256": "d85571cb8c63136be77913be4ba5066571fc4b570bc6292e8dd716480c7a4432", "unvendored_tests": true, "version": "2024.4.0"}, "xyzservices-tests": {"depends": ["xyzservices"], "file_name": "xyzservices-tests.tar", "imports": [], "install_dir": "site", "name": "xyzservices-tests", "package_type": "package", "sha256": "04095591cf97cc7db7ef1b6b815902a67eda9e2a1a19d11e9a9dbf61497aad65", "unvendored_tests": false, "version": "2024.4.0"}, "yarl": {"depends": ["multidict", "idna"], "file_name": "yarl-1.9.4-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["yarl"], "install_dir": "site", "name": "yarl", "package_type": "package", "sha256": "ad00a3f6a1b674805041db36f57010b2aa53fc5993a043a169b538280483ee99", "unvendored_tests": false, "version": "1.9.4"}, "yt": {"depends": ["ewah_bool_utils", "numpy", "matplotlib", "sympy", "setuptools", "packaging", "unyt", "cmyt", "colorspacious", "tqdm", "tomli", "tomli-w"], "file_name": "yt-4.3.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["yt"], "install_dir": "site", "name": "yt", "package_type": "package", "sha256": "6017d71bfeff723db959bcf5a9b4f380932717388227cfb12eccedd0ca9b1c17", "unvendored_tests": false, "version": "4.3.1"}, "zarr": {"depends": ["numpy", "asciitree", "numcodecs"], "file_name": "zarr-2.18.3-py3-none-any.whl", "imports": ["zarr"], "install_dir": "site", "name": "zarr", "package_type": "package", "sha256": "d117324c79785dd78ed10fa42b9d7247acb07ca2a6ae0bcdbb3d8d8bc71fa2ad", "unvendored_tests": true, "version": "2.18.3"}, "zarr-tests": {"depends": ["zarr"], "file_name": "zarr-tests.tar", "imports": [], "install_dir": "site", "name": "zarr-tests", "package_type": "package", "sha256": "ad9b25b92274431d73cbcf947b058aad26616eb226fe5136fb121dc92ea70702", "unvendored_tests": false, "version": "2.18.3"}, "zengl": {"depends": [], "file_name": "zengl-2.7.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["zengl", "_zengl"], "install_dir": "site", "name": "zengl", "package_type": "package", "sha256": "60da3d7e40f1c594e208b48d8b51891e568aa50ecc9ce58955280412aa8f0aed", "unvendored_tests": false, "version": "2.7.1"}, "zfpy": {"depends": ["numpy"], "file_name": "zfpy-1.0.1-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["zfpy"], "install_dir": "site", "name": "zfpy", "package_type": "package", "sha256": "f1b400d00de7c89674d593ac7582e173499269fa18dc493f7e8a138e2d087f17", "unvendored_tests": false, "version": "1.0.1"}, "zstandard": {"depends": ["cffi"], "file_name": "zstandard-0.22.0-cp312-cp312-pyodide_2024_0_wasm32.whl", "imports": ["zstandard"], "install_dir": "site", "name": "zstandard", "package_type": "package", "sha256": "05f0474feb828917524671bfd96da83f2a4af54439676140dd6740dff567dfcf", "unvendored_tests": false, "version": "0.22.0"}}} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.js new file mode 100644 index 0000000000..832acdedb3 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.js @@ -0,0 +1,17 @@ +"use strict"; + +var _createPyodideModule = (() => { + var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; + if (typeof __filename != 'undefined') _scriptName ||= __filename; + return ( +function(moduleArg = {}) { + var moduleRtn; + +var Module=Object.assign({},moduleArg);var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){}var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];if(!Module.wrapException){Module.wrapException=e=>e}var dynamicLibraries=Module["dynamicLibraries"]||[];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];function intArrayFromBase64(s){if(typeof ENVIRONMENT_IS_NODE!="undefined"&&ENVIRONMENT_IS_NODE){var buf=Buffer.from(s,"base64");return new Uint8Array(buf.buffer,buf.byteOffset,buf.length)}var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;ifilename.startsWith(dataURIPrefix);var isFileURI=filename=>filename.startsWith("file://");var wasmBinaryFile;wasmBinaryFile="pyodide.asm.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"&&!isFileURI(binaryFile)){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{if(!response["ok"]){throw`failed to load wasm binary file at '${binaryFile}'`}return response["arrayBuffer"]()}).catch(()=>getBinarySync(binaryFile))}else if(readAsync){return new Promise((resolve,reject)=>{readAsync(binaryFile,response=>resolve(new Uint8Array(response)),reject)})}}return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&!isFileURI(binaryFile)&&!ENVIRONMENT_IS_NODE&&typeof fetch=="function"){return fetch(binaryFile,{credentials:"same-origin"}).then(response=>{var result=WebAssembly.instantiateStreaming(response,imports);return result.then(callback,function(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(binaryFile,imports,callback)})})}return instantiateArrayBuffer(binaryFile,imports,callback)}function getWasmImports(){return{"env":wasmImports,"wasi_snapshot_preview1":wasmImports,"GOT.mem":new Proxy(wasmImports,GOTHandler),"GOT.func":new Proxy(wasmImports,GOTHandler)}}function createWasm(){var info=getWasmImports();if(Module.adjustWasmImports){Module.adjustWasmImports(info)}function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=relocateExports(wasmExports,1024);var metadata=getDylinkMetadata(module);if(metadata.neededDynlibs){dynamicLibraries=metadata.neededDynlibs.concat(dynamicLibraries)}mergeLibSymbols(wasmExports,"main");LDSO.init();loadDylibs();wasmExports=applySignatureConversions(wasmExports);addOnInit(wasmExports["__wasm_call_ctors"]);__RELOC_FUNCS__.push(wasmExports["__wasm_apply_data_relocs"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"],result["module"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var ASM_CONSTS={4580244:()=>{throw new Error("intentionally triggered fatal error!")},4580301:()=>{wasmImports["open64"]=wasmImports["open"]},4580350:()=>jspiSupported};function console_error(msg){let jsmsg=UTF8ToString(msg);console.error(jsmsg)}function console_error_obj(obj){console.error(obj)}function new_error(type,msg,err){return new API.PythonError(UTF8ToString(type),msg,err)}new_error.sig="eiei";function fail_test(){API.fail_test=true}fail_test.sig="v";function capture_stderr(){API.capture_stderr()}capture_stderr.sig="v";function restore_stderr(){return API.restore_stderr()}restore_stderr.sig="e";function raw_call_js(func){func()}raw_call_js.sig="ve";function hiwire_invalid_ref(type,ref){API.fail_test=!!1;if(type===1&&!ref){if(_PyErr_Occurred()){const e=_wrap_exception();console.error("Pyodide internal error: Argument to hiwire_get is falsy. This was "+"probably because the Python error indicator was set when get_value was "+"called. The Python error that caused this was:",e);throw e}else{const msg="Pyodide internal error: Argument to hiwire_get is falsy (but error "+"indicator is not set).";console.error(msg);throw new Error(msg)}}const typestr={[1]:"get",[2]:"incref",[3]:"decref"}[type];const msg=`hiwire_${typestr} on invalid reference ${ref}. This is most likely due `+"to use after free. It may also be due to memory corruption.";console.error(msg);throw new Error(msg)}hiwire_invalid_ref.sig="vii";function set_pyodide_module(mod){API._pyodide=mod}set_pyodide_module.sig="ve";function js2python_immutable_js(value){try{let result=Module.js2python_convertImmutable(value);if(result!==undefined){return result}return 0}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_immutable_js.sig="ie";function js2python_js(value){try{let result=Module.js2python_convertImmutable(value);if(result!==undefined){return result}return _JsProxy_create(value)}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_js.sig="ie";function js2python_convert(v,depth,defaultConverter){try{return Module.js2python_convert(v,{depth:depth,defaultConverter:defaultConverter})}catch(e){Module.handle_js_error(e);return 0}errNoRet()}js2python_convert.sig="ieie";function isReservedWord(word){if(!Module.pythonReservedWords){Module.pythonReservedWords=new Set(["False","await","else","import","pass","None","break","except","in","raise","True","class","finally","is","return","and","continue","for","lambda","try","as","def","from","nonlocal","while","assert","del","global","not","with","async","elif","if","or","yield"])}return Module.pythonReservedWords.has(word)}function normalizeReservedWords(word){const noTrailing_=word.replace(/_*$/,"");if(!isReservedWord(noTrailing_)){return word}if(noTrailing_!==word){return word.slice(0,-1)}return word}function JsProxy_GetAttr_js(jsobj,ptrkey){try{const jskey=normalizeReservedWords(UTF8ToString(ptrkey));const result=jsobj[jskey];if(result===undefined&&!(jskey in jsobj)){return null}return nullToUndefined(result)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_GetAttr_js.sig="eei";function JsProxy_SetAttr_js(jsobj,ptrkey,jsval){try{let jskey=normalizeReservedWords(UTF8ToString(ptrkey));jsobj[jskey]=jsval}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_SetAttr_js.sig="ieie";function JsProxy_DelAttr_js(jsobj,ptrkey){try{let jskey=normalizeReservedWords(UTF8ToString(ptrkey));delete jsobj[jskey]}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_DelAttr_js.sig="iei";function JsProxy_GetIter_js(obj){try{return obj[Symbol.iterator]()}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_GetIter_js.sig="ee";function handle_next_result_js(res,done,msg){try{let errmsg;if(typeof res!=="object"){errmsg=`Result should have type "object" not "${typeof res}"`}else if(typeof res.done==="undefined"){if(typeof res.then==="function"){errmsg=`Result was a promise, use anext() / ascend() / athrow() instead.`}else{errmsg=`Result has no "done" field.`}}if(errmsg){HEAPU32[(msg>>2)+0>>>0]=stringToNewUTF8(errmsg);HEAPU32[(done>>2)+0>>>0]=-1}HEAPU32[(done>>2)+0>>>0]=res.done;return res.value}catch(e){Module.handle_js_error(e);return-1}return 0}handle_next_result_js.sig="eeii";function JsException_new_helper(name_ptr,message_ptr,stack_ptr){try{let name=UTF8ToString(name_ptr);let message=UTF8ToString(message_ptr);let stack=UTF8ToString(stack_ptr);return API.deserializeError(name,message,stack)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsException_new_helper.sig="eiii";function JsProxy_GetAsyncIter_js(obj){try{return obj[Symbol.asyncIterator]()}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_GetAsyncIter_js.sig="ee";function _agen_handle_result_js(p,msg,set_result,set_exception,closing){try{let errmsg;if(typeof p!=="object"){errmsg=`Result of anext() should be object not ${typeof p}`}else if(typeof p.then!=="function"){if(typeof p.done==="boolean"){errmsg=`Result of anext() was not a promise, use next() instead.`}else{errmsg=`Result of anext() was not a promise.`}}if(errmsg){HEAPU32[(msg>>2)+0>>>0]=stringToNewUTF8(errmsg);return-1}_Py_IncRef(set_result);_Py_IncRef(set_exception);p.then(({done:done,value:value})=>{__agen_handle_result_js_c(set_result,set_exception,done,value,closing)},err=>{__agen_handle_result_js_c(set_result,set_exception,-1,err,closing)}).finally(()=>{_Py_DecRef(set_result);_Py_DecRef(set_exception)});return 0}catch(e){Module.handle_js_error(e);return-1}return 0}_agen_handle_result_js.sig="ieiiii";function get_length_helper(val){try{let result;if(typeof val.size==="number"){result=val.size}else if(typeof val.length==="number"){result=val.length}else{return-2}if(result<0){return-3}if(result>2147483647){return-4}return result}catch(e){Module.handle_js_error(e);return-1}return 0}get_length_helper.sig="ie";function get_length_string(val){try{let result;if(typeof val.size==="number"){result=val.size}else if(typeof val.length==="number"){result=val.length}return stringToNewUTF8(" "+result.toString())}catch(e){Module.handle_js_error(e);return 0}errNoRet()}get_length_string.sig="ie";function destroy_jsarray_entries(array){for(let v of array){try{if(typeof v.destroy==="function"){v.destroy()}}catch(e){console.warn("Weird error:",e)}}}destroy_jsarray_entries.sig="ve";function JsArray_repeat_js(o,count){try{return Array.from({length:count},()=>o).flat()}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsArray_repeat_js.sig="eei";function JsArray_inplace_repeat_js(o,count){try{o.splice(0,o.length,...Array.from({length:count},()=>o).flat())}catch(e){Module.handle_js_error(e);return-1}return 0}JsArray_inplace_repeat_js.sig="iei";function JsArray_reversed_iterator(array){return new ReversedIterator(array)}class ReversedIterator{constructor(array){this._array=array;this._i=array.length-1}__length_hint__(){return this._array.length}[Symbol.toStringTag](){return"ReverseIterator"}next(){const i=this._i;const a=this._array;const done=i<0;const value=done?undefined:a[i];this._i--;return{done:done,value:value}}}JsArray_reversed_iterator.sig="ee";function JsArray_index_js(o,v,start,stop){try{for(let i=start;i{let c=s.charCodeAt(0);return c<48||c>57}).map(word=>isReservedWord(word.replace(/_*$/,""))?word+"_":word))}while(jsobj=Object.getPrototypeOf(jsobj));return result}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsProxy_Dir_js.sig="ee";function JsProxy_Bool_js(val){try{if(!val){return!!0}if(val.size===0){if(/HTML[A-Za-z]*Element/.test(getTypeTag(val))){return!!1}return!!0}if(val.length===0&&JsvArray_Check(val)){return!!0}if(val.byteLength===0){return!!0}return!!1}catch(e){return!!0}}JsProxy_Bool_js.sig="ie";function JsObjMap_GetIter_js(obj){try{return Module.iterObject(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsObjMap_GetIter_js.sig="ee";function JsObjMap_length_js(obj){try{let length=0;for(let _ of Module.iterObject(obj)){length++}return length}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_length_js.sig="ie";function JsObjMap_subscript_js(obj,key){try{if(!Object.prototype.hasOwnProperty.call(obj,key)){return null}return obj[key]}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsObjMap_subscript_js.sig="eee";function JsObjMap_ass_subscript_js(obj,key,value){try{if(value===null){if(!Object.prototype.hasOwnProperty.call(obj,key)){return-1}delete obj[key]}else{obj[key]=value}return 0}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_ass_subscript_js.sig="ieee";function JsObjMap_contains_js(obj,key){try{return Object.prototype.hasOwnProperty.call(obj,key)}catch(e){Module.handle_js_error(e);return-1}return 0}JsObjMap_contains_js.sig="iee";function JsModule_GetAll_js(o){try{return Object.getOwnPropertyNames(o)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsModule_GetAll_js.sig="ee";function JsBuffer_DecodeString_js(buffer,encoding){try{let encoding_js;if(encoding){encoding_js=UTF8ToString(encoding)}const decoder=new TextDecoder(encoding_js,{fatal:!!1,ignoreBOM:!!1});let res;try{res=decoder.decode(buffer)}catch(e){if(e instanceof TypeError){return null}throw e}return res}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsBuffer_DecodeString_js.sig="eei";function JsBuffer_get_info(jsobj,byteLength_ptr,format_ptr,size_ptr,checked_ptr){const[format_utf8,size,checked]=Module.get_buffer_datatype(jsobj);HEAPU32[(byteLength_ptr>>2)+0>>>0]=jsobj.byteLength;HEAPU32[(format_ptr>>2)+0>>>0]=format_utf8;HEAPU32[(size_ptr>>2)+0>>>0]=size;HEAPU8[checked_ptr+0>>>0]=checked}JsBuffer_get_info.sig="veiiii";function JsDoubleProxy_unwrap_helper(id){try{return Module.PyProxy_getPtr(id)}catch(e){Module.handle_js_error(e);return 0}errNoRet()}JsDoubleProxy_unwrap_helper.sig="ie";function JsProxy_compute_typeflags(obj,is_py_json){try{let type_flags=0;if(API.isPyProxy(obj)&&!pyproxyIsAlive(obj)){return 0}const typeTag=getTypeTag(obj);function safeBool(cb){try{return cb()}catch(e){return!!0}}const isBufferView=safeBool(()=>ArrayBuffer.isView(obj));const isArray=safeBool(()=>Array.isArray(obj));const constructorName=safeBool(()=>obj.constructor.name)||"";if(typeof obj==="function"){type_flags|=1<<9}if(hasMethod(obj,"then")){type_flags|=1<<7}if(hasMethod(obj,Symbol.iterator)){type_flags|=1<<0}if(hasMethod(obj,Symbol.asyncIterator)){type_flags|=1<<15}if(hasMethod(obj,"next")&&(hasMethod(obj,Symbol.iterator)||!hasMethod(obj,Symbol.asyncIterator))){type_flags|=1<<1}if(hasMethod(obj,"next")&&(!hasMethod(obj,Symbol.iterator)||hasMethod(obj,Symbol.asyncIterator))){type_flags|=1<<18}if(hasProperty(obj,"size")||hasProperty(obj,"length")&&typeof obj!=="function"){type_flags|=1<<2}if(hasMethod(obj,"get")){type_flags|=1<<3}if(hasMethod(obj,"set")){type_flags|=1<<4}if(hasMethod(obj,"has")){type_flags|=1<<5}if(hasMethod(obj,"includes")){type_flags|=1<<6}if((isBufferView||typeTag==="[object ArrayBuffer]")&&!(type_flags&1<<9)){type_flags|=1<<8}if(API.isPyProxy(obj)){type_flags|=1<<13}if(isArray){type_flags|=1<<10}if(typeTag==="[object HTMLCollection]"||typeTag==="[object NodeList]"){type_flags|=1<<11}if(isBufferView&&typeTag!=="[object DataView]"){type_flags|=1<<12}if(typeTag==="[object Generator]"){type_flags|=1<<16}if(typeTag==="[object AsyncGenerator]"){type_flags|=1<<17}if(hasProperty(obj,"name")&&hasProperty(obj,"message")&&(hasProperty(obj,"stack")||constructorName==="DOMException")&&!(type_flags&(1<<9|1<<8))){type_flags|=1<<19}if(is_py_json&&type_flags&(1<<10|1<<11|1<<1)){type_flags|=1<<21}if(is_py_json&&!(type_flags&(1<<10|1<<12|1<<11|1<<8|1<<13|1<<1|1<<9|1<<19))){type_flags|=1<<20}return type_flags}catch(e){Module.handle_js_error(e);return-1}return 0}JsProxy_compute_typeflags.sig="iei";function is_comlink_proxy(obj){try{return!!(API.Comlink&&value[API.Comlink.createEndpoint])}catch(e){return!!0}}is_comlink_proxy.sig="ie";function can_run_sync_js(){return!!validSuspender.value}can_run_sync_js.sig="i";function my_dict_converter(){return Object.fromEntries}my_dict_converter.sig="e";function get_async_js_call_done_callback(proxies){try{return function(result){let msg="This borrowed proxy was automatically destroyed "+"at the end of an asynchronous function call. Try "+"using create_proxy or create_once_callable.";for(let px of proxies){Module.pyproxy_destroy(px,msg,!!0)}if(API.isPyProxy(result)){Module.pyproxy_destroy(result,msg,!!0)}}}catch(e){Module.handle_js_error(e);return null}errNoRet()}get_async_js_call_done_callback.sig="ee";function wrap_generator(gen,proxies){try{proxies=new Set(proxies);const msg="This borrowed proxy was automatically destroyed "+"when a generator completed execution. Try "+"using create_proxy or create_once_callable.";function cleanup(){proxies.forEach(px=>Module.pyproxy_destroy(px,msg))}function wrap(funcname){return function(val){if(API.isPyProxy(val)){val=val.copy();proxies.add(val)}let res;try{res=gen[funcname](val)}catch(e){cleanup();throw e}if(res.done){proxies.delete(res.value);cleanup()}return res}}return{get[Symbol.toStringTag](){return"Generator"},[Symbol.iterator](){return this},next:wrap("next"),throw:wrap("throw"),return:wrap("return")}}catch(e){Module.handle_js_error(e);return null}errNoRet()}wrap_generator.sig="eee";function wrap_async_generator(gen,proxies){try{proxies=new Set(proxies);const msg="This borrowed proxy was automatically destroyed "+"when an asynchronous generator completed execution. Try "+"using create_proxy or create_once_callable.";function cleanup(){proxies.forEach(px=>Module.pyproxy_destroy(px,msg))}function wrap(funcname){return async function(val){if(API.isPyProxy(val)){val=val.copy();proxies.add(val)}let res;try{res=await gen[funcname](val)}catch(e){cleanup();throw e}if(res.done){proxies.delete(res.value);cleanup()}return res}}return{get[Symbol.toStringTag](){return"AsyncGenerator"},[Symbol.asyncIterator](){return this},next:wrap("next"),throw:wrap("throw"),return:wrap("return")}}catch(e){Module.handle_js_error(e);return null}errNoRet()}wrap_async_generator.sig="eee";function throw_no_gil(){throw new API.NoGilError("Attempted to use PyProxy when Python GIL not held")}throw_no_gil.sig="v";function pyproxy_Check(val){return API.isPyProxy(val)}pyproxy_Check.sig="ie";function pyproxy_AsPyObject(val){if(!API.isPyProxy(val)||!pyproxyIsAlive(val)){return 0}return Module.PyProxy_getPtr(val)}pyproxy_AsPyObject.sig="ie";function destroy_proxies(proxies,msg_ptr){let msg=undefined;if(msg_ptr){msg=_JsvString_FromId(msg_ptr)}for(let px of proxies){Module.pyproxy_destroy(px,msg,false)}}destroy_proxies.sig="vei";function gc_register_proxies(proxies){for(let px of proxies){Module.gc_register_proxy(Module.PyProxy_getAttrs(px).shared)}}gc_register_proxies.sig="ve";function destroy_proxy(px,msg_ptr){const{shared:shared,props:props}=Module.PyProxy_getAttrsQuiet(px);if(!shared.ptr){return}if(props.roundtrip){return}let msg=undefined;if(msg_ptr){msg=_JsvString_FromId(msg_ptr)}Module.pyproxy_destroy(px,msg,false)}destroy_proxy.sig="vei";function proxy_cache_get(proxyCache,descr){const proxy=proxyCache.get(descr);if(!proxy){return null}if(pyproxyIsAlive(proxy)){return proxy}else{proxyCache.delete(descr);return null}}proxy_cache_get.sig="eei";function proxy_cache_set(proxyCache,descr,proxy){proxyCache.set(descr,proxy)}proxy_cache_set.sig="veie";function _pyproxyGen_make_result(done,value){return{done:!!done,value:value}}_pyproxyGen_make_result.sig="eie";function array_to_js(array,len){return Array.from(HEAP32.subarray(array/4>>>0,array/4+len>>>0))}array_to_js.sig="eii";function _pyproxy_get_buffer_result(start_ptr,smallest_ptr,largest_ptr,readonly,format,itemsize,shape,strides,view,c_contiguous,f_contiguous,sentinel){format=UTF8ToString(format);return{start_ptr:start_ptr,smallest_ptr:smallest_ptr,largest_ptr:largest_ptr,readonly:readonly,format:format,itemsize:itemsize,shape:shape,strides:strides,view:view,c_contiguous:c_contiguous,f_contiguous:f_contiguous}}_pyproxy_get_buffer_result.sig="eiiiiiieeiiii";function pyproxy_new_ex(ptrobj,capture_this,roundtrip,gcRegister,jsonAdaptor){try{return Module.pyproxy_new(ptrobj,{props:{captureThis:!!capture_this,roundtrip:!!roundtrip},gcRegister:gcRegister,jsonAdaptor:jsonAdaptor})}catch(e){Module.handle_js_error(e);return null}errNoRet()}pyproxy_new_ex.sig="eiiiii";function pyproxy_new(ptrobj){try{return Module.pyproxy_new(ptrobj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}pyproxy_new.sig="ei";function create_once_callable(obj,may_syncify){try{_Py_IncRef(obj);let alreadyCalled=!!0;function wrapper(...args){if(alreadyCalled){throw new Error("OnceProxy can only be called once")}try{if(may_syncify){return Module.callPyObjectMaybePromising(obj,args)}else{return Module.callPyObject(obj,args)}}finally{wrapper.destroy()}}wrapper.destroy=function(){if(alreadyCalled){throw new Error("OnceProxy has already been destroyed")}alreadyCalled=!!1;Module.finalizationRegistry.unregister(wrapper);_Py_DecRef(obj)};Module.finalizationRegistry.register(wrapper,[obj,undefined],wrapper);return wrapper}catch(e){Module.handle_js_error(e);return null}errNoRet()}create_once_callable.sig="eii";function create_promise_handles(handle_result,handle_exception,done_callback,js2py_converter){try{if(handle_result){_Py_IncRef(handle_result)}if(handle_exception){_Py_IncRef(handle_exception)}if(js2py_converter){_Py_IncRef(js2py_converter)}if(!done_callback){done_callback=x=>{}}let used=!!0;function checkUsed(){if(used){throw new Error("One of the promise handles has already been called.")}}function destroy(){checkUsed();used=!!1;if(handle_result){_Py_DecRef(handle_result)}if(handle_exception){_Py_DecRef(handle_exception)}if(js2py_converter){_Py_DecRef(js2py_converter)}}function onFulfilled(res){checkUsed();try{if(handle_result){return _create_promise_handles_result_helper(handle_result,js2py_converter,res)}}finally{done_callback(res);destroy()}}function onRejected(err){checkUsed();try{if(handle_exception){return Module.callPyObjectMaybePromising(handle_exception,[err])}}finally{done_callback(undefined);destroy()}}onFulfilled.destroy=destroy;onRejected.destroy=destroy;return[onFulfilled,onRejected]}catch(e){Module.handle_js_error(e);return null}errNoRet()}create_promise_handles.sig="eiiei";function _python2js_buffer_inner(buf,itemsize,ndim,format,shape,strides,suboffsets){try{let converter=Module.get_converter(format,itemsize);return Module._python2js_buffer_recursive(buf,0,{ndim:ndim,format:format,itemsize:itemsize,shape:shape,strides:strides,suboffsets:suboffsets,converter:converter})}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_buffer_inner.sig="eiiiiiii";function jslib_init_js(){try{HEAP32[_Jsr_undefined/4>>>0]=_hiwire_intern(undefined);HEAP32[_Jsr_true/4>>>0]=_hiwire_intern(true);HEAP32[_Jsr_false/4>>>0]=_hiwire_intern(false);HEAP32[_Jsr_novalue/4>>>0]=_hiwire_intern({noValueMarker:1});Module.novalue=_hiwire_get(HEAP32[_Jsr_novalue/4>>>0]);Hiwire.num_keys=_hiwire_num_refs;return 0}catch(e){Module.handle_js_error(e);return-1}return 0}jslib_init_js.sig="i";function JsvNoValue_Check(v){return v===Module.novalue}JsvNoValue_Check.sig="ie";function JsvNum_fromInt(x){return x}JsvNum_fromInt.sig="ei";function JsvNum_fromDouble(val){return val}JsvNum_fromDouble.sig="ed";function JsvNum_fromDigits(digits,ndigits){let result=BigInt(0);for(let i=0;i>2)+i>>>0])<>2)+ndigits-1>>>0]&2147483648)<=arr.length){return null}return arr.splice(idx,1)[0]}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvArray_Delete.sig="eei";function JsvArray_Push(arr,obj){return arr.push(obj)}JsvArray_Push.sig="iee";function JsvArray_Extend(arr,vals){arr.push(...vals)}JsvArray_Extend.sig="vee";function JsvArray_Insert(arr,idx,value){try{arr.splice(idx,0,value)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_Insert.sig="ieie";function JsvArray_ShallowCopy(arr){try{return"slice"in arr?arr.slice():Array.from(arr)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_ShallowCopy.sig="ee";function JsvArray_slice(obj,length,start,stop,step){try{let result;if(step===1){result=obj.slice(start,stop)}else{result=Array.from({length:length},(_,i)=>obj[start+i*step])}return result}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvArray_slice.sig="eeiiii";function JsvArray_slice_assign(obj,slicelength,start,stop,step,values_length,values){try{let jsvalues=[];for(let i=0;i>2)+i>>>0]);if(ref===null){return-1}jsvalues.push(ref)}if(step===1){obj.splice(start,slicelength,...jsvalues)}else{if(values!==0){for(let i=0;i=0;i--){obj.splice(start+i*step,1)}}}}catch(e){Module.handle_js_error(e);return-1}return 0}JsvArray_slice_assign.sig="ieiiiiii";function JsvObject_New(){return{}}JsvObject_New.sig="e";function JsvObject_SetAttr(obj,attr,value){try{obj[attr]=value}catch(e){Module.handle_js_error(e);return-1}return 0}JsvObject_SetAttr.sig="ieee";function JsvObject_Entries(obj){try{return Object.entries(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_Entries.sig="ee";function JsvObject_Keys(obj){try{return Object.keys(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_Keys.sig="ee";function JsvObject_Values(obj){try{return Object.values(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_Values.sig="ee";function JsvObject_toString(obj){try{if(hasMethod(obj,"toString")){return obj.toString()}return Object.prototype.toString.call(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_toString.sig="ee";function JsvObject_CallMethod(obj,meth,args){try{return nullToUndefined(obj[meth](...args))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod.sig="eeee";function JsvObject_CallMethod_NoArgs(obj,meth){try{return nullToUndefined(obj[meth]())}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod_NoArgs.sig="eee";function JsvObject_CallMethod_OneArg(obj,meth,arg){try{return nullToUndefined(obj[meth](arg))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod_OneArg.sig="eeee";function JsvObject_CallMethod_TwoArgs(obj,meth,arg1,arg2){try{return nullToUndefined(obj[meth](arg1,arg2))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvObject_CallMethod_TwoArgs.sig="eeeee";function JsvFunction_Check(obj){try{return typeof obj==="function"}catch(e){return false}}JsvFunction_Check.sig="ie";function JsvFunction_CallBound(func,this_,args){try{return nullToUndefined(Function.prototype.apply.apply(func,[this_,args]))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvFunction_CallBound.sig="eeee";function JsvFunction_Call_OneArg(func,arg){try{return nullToUndefined(func(arg))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvFunction_Call_OneArg.sig="eee";function JsvFunction_Construct(func,args){try{return nullToUndefined(Reflect.construct(func,args))}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvFunction_Construct.sig="eee";function JsvPromise_Check(obj){try{return isPromise(obj)}catch(e){return false}}JsvPromise_Check.sig="ie";function JsvPromise_Resolve(obj){try{return Promise.resolve(obj)}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvPromise_Resolve.sig="ee";function jslib_init_buffers_js(){try{const dtypes_str=Array.from("bBhHiIqQfd").join(String.fromCharCode(0));const dtypes_ptr=stringToNewUTF8(dtypes_str);const dtypes_map=Object.fromEntries(Object.entries(dtypes_str).map(([idx,val])=>[val,dtypes_ptr+ +idx]));const buffer_datatype_map=new Map([["Int8Array",[dtypes_map["b"],1,true]],["Uint8Array",[dtypes_map["B"],1,true]],["Uint8ClampedArray",[dtypes_map["B"],1,true]],["Int16Array",[dtypes_map["h"],2,true]],["Uint16Array",[dtypes_map["H"],2,true]],["Int32Array",[dtypes_map["i"],4,true]],["Uint32Array",[dtypes_map["I"],4,true]],["Float32Array",[dtypes_map["f"],4,true]],["Float64Array",[dtypes_map["d"],8,true]],["BigInt64Array",[dtypes_map["q"],8,true]],["BigUint64Array",[dtypes_map["Q"],8,true]],["DataView",[dtypes_map["B"],1,false]],["ArrayBuffer",[dtypes_map["B"],1,false]]]);Module.get_buffer_datatype=function(jsobj){return buffer_datatype_map.get(jsobj.constructor.name)||[0,0,false]}}catch(e){Module.handle_js_error(e);return-1}return 0}jslib_init_buffers_js.sig="i";function JsvBuffer_assignToPtr(buf,ptr){try{Module.HEAPU8.set(bufferAsUint8Array(buf),ptr)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_assignToPtr.sig="iei";function JsvBuffer_assignFromPtr(buf,ptr){try{bufferAsUint8Array(buf).set(Module.HEAPU8.subarray(ptr,ptr+buf.byteLength))}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_assignFromPtr.sig="iei";function JsvBuffer_readFromFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.read(stream,uint8_buf,0,uint8_buf.byteLength)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_readFromFile.sig="iei";function JsvBuffer_writeToFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.write(stream,uint8_buf,0,uint8_buf.byteLength)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_writeToFile.sig="iei";function JsvBuffer_intoFile(buf,fd){try{let uint8_buf=bufferAsUint8Array(buf);let stream=Module.FS.streams[fd];Module.FS.write(stream,uint8_buf,0,uint8_buf.byteLength,undefined,true)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvBuffer_intoFile.sig="iei";function JsvGenerator_Check(obj){try{return getTypeTag(obj)==="[object Generator]"}catch(e){return false}}JsvGenerator_Check.sig="ie";function JsvAsyncGenerator_Check(obj){try{return getTypeTag(obj)==="[object AsyncGenerator]"}catch(e){return false}}JsvAsyncGenerator_Check.sig="ie";function JsvError_Throw(e){throw e}JsvError_Throw.sig="ve";function Jsv_less_than(a,b){try{return!!(ab)}catch(e){return false}}Jsv_greater_than.sig="iee";function Jsv_greater_than_equal(a,b){try{return!!(a>=b)}catch(e){return false}}Jsv_greater_than_equal.sig="iee";function JsvMap_New(){try{return new Map}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvMap_New.sig="e";function JsvLiteralMap_New(){try{return new API.LiteralMap}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvLiteralMap_New.sig="e";function JsvMap_Set(map,key,val){try{map.set(key,val)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvMap_Set.sig="ieee";function JsvSet_New(){try{return new Set}catch(e){Module.handle_js_error(e);return null}errNoRet()}JsvSet_New.sig="e";function JsvSet_Add(set,val){try{set.add(val)}catch(e){Module.handle_js_error(e);return-1}return 0}JsvSet_Add.sig="iee";function _python2js_addto_postprocess_list(list,parent,key,value){list.push([parent,key,value])}_python2js_addto_postprocess_list.sig="veeei";function _python2js_handle_postprocess_list(list,cache){for(const[parent,key,ptr]of list){let val=cache.get(ptr);if(parent.constructor.name==="LiteralMap"){parent.set(key,val)}else{parent[key]=val}}}_python2js_handle_postprocess_list.sig="vee";function _python2js_ucs1(ptr,len){try{let jsstr="";for(let i=0;i>>0])}return jsstr}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_ucs1.sig="eii";function _python2js_ucs2(ptr,len){try{let jsstr="";for(let i=0;i>1)+i>>>0])}return jsstr}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_ucs2.sig="eii";function _python2js_ucs4(ptr,len){try{let jsstr="";for(let i=0;i>2)+i>>>0])}return jsstr}catch(e){Module.handle_js_error(e);return null}errNoRet()}_python2js_ucs4.sig="eii";function _python2js_add_to_cache(cache,pyparent,jsparent){try{cache.set(pyparent,jsparent)}catch(e){Module.handle_js_error(e);return-1}return 0}_python2js_add_to_cache.sig="ieie";function _python2js_cache_lookup(cache,pyparent){return cache.get(pyparent)||null}_python2js_cache_lookup.sig="eei";function _JsArray_PushEntry_helper(array,key,value){try{array.push([key,value])}catch(e){Module.handle_js_error(e);return-1}return 0}_JsArray_PushEntry_helper.sig="ieee";function _JsArray_PostProcess_helper(jscontext,array){try{return jscontext.dict_converter(array)}catch(e){Module.handle_js_error(e);return null}errNoRet()}_JsArray_PostProcess_helper.sig="eee";function python2js__default_converter_js(jscontext,object){try{let proxy=Module.pyproxy_new(object);let result=jscontext.default_converter(proxy,jscontext.converter,jscontext.cacheConversion);proxy.destroy();return result}catch(e){Module.handle_js_error(e);return null}errNoRet()}python2js__default_converter_js.sig="eei";function python2js_custom__create_jscontext(context,cache,dict_converter,default_converter){try{let jscontext={};if(dict_converter){jscontext.dict_converter=dict_converter}if(default_converter){jscontext.default_converter=default_converter;jscontext.cacheConversion=function(input,output){if(!API.isPyProxy(input)){throw new TypeError("The first argument to cacheConversion must be a PyProxy.")}let input_ptr=Module.PyProxy_getPtr(input);cache.set(input_ptr,output)};jscontext.converter=function(x){if(!API.isPyProxy(x)){return x}let ptr=Module.PyProxy_getPtr(x);return __python2js(context,ptr)}}return jscontext}catch(e){Module.handle_js_error(e);return null}errNoRet()}python2js_custom__create_jscontext.sig="eieee";function destroy_proxies_js(proxies_id){try{for(const proxy of proxies_id){proxy.destroy()}}catch(e){Module.handle_js_error(e);return-1}return 0}destroy_proxies_js.sig="ie";function pyodide_js_init(){"use strict";(()=>{var Vr=Object.create;var mt=Object.defineProperty;var qr=Object.getOwnPropertyDescriptor;var Yr=Object.getOwnPropertyNames;var Qr=Object.getPrototypeOf,Xr=Object.prototype.hasOwnProperty;var i=(t,e)=>mt(t,"name",{value:e,configurable:!0}),x=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var Zr=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Yr(e))!Xr.call(t,o)&&o!==r&&mt(t,o,{get:()=>e[o],enumerable:!(n=qr(e,o))||n.enumerable});return t};var N=(t,e,r)=>(r=t!=null?Vr(Qr(t)):{},Zr(e||!t||!t.__esModule?mt(r,"default",{value:t,enumerable:!0}):r,t));var Bt=(t,e,r)=>{if(!e.has(t))throw TypeError("Cannot "+r)};var y=(t,e,r)=>(Bt(t,e,"read from private field"),r?r.call(t):e.get(t)),O=(t,e,r)=>{if(e.has(t))throw TypeError("Cannot add the same private member more than once");e instanceof WeakSet?e.add(t):e.set(t,r)},D=(t,e,r,n)=>(Bt(t,e,"write to private field"),n?n.call(t,r):e.set(t,r),r);function en(t){return!isNaN(parseFloat(t))&&isFinite(t)}i(en,"_isNumber");function j(t){return t.charAt(0).toUpperCase()+t.substring(1)}i(j,"_capitalize");function _t(t){return function(){return this[t]}}i(_t,"_getter");var z=["isConstructor","isEval","isNative","isToplevel"],W=["columnNumber","lineNumber"],G=["fileName","functionName","source"],tn=["args"],rn=["evalOrigin"],Re=z.concat(W,G,tn,rn);function S(t){if(t)for(var e=0;e-1&&(a=a.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var s=a.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),l=s.match(/ (\(.+\)$)/);s=l?s.replace(l[0],""):s;var c=this.extractLocation(l?l[1]:s),u=l&&s||void 0,d=["eval",""].indexOf(c[0])>-1?void 0:c[0];return new Le({functionName:u,fileName:d,lineNumber:c[1],columnNumber:c[2],source:a})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:i(function(n){var o=n.stack.split(`\n`).filter(function(a){return!a.match(e)},this);return o.map(function(a){if(a.indexOf(" > eval")>-1&&(a=a.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),a.indexOf("@")===-1&&a.indexOf(":")===-1)return new Le({functionName:a});var s=/((.*".+"[^@]*)?[^@]*)(?:@)/,l=a.match(s),c=l&&l[1]?l[1]:void 0,u=this.extractLocation(a.replace(s,""));return new Le({functionName:c,fileName:u[0],lineNumber:u[1],columnNumber:u[2],source:a})},this)},"ErrorStackParser$$parseFFOrSafari")}}i(nn,"ErrorStackParser");var on=new nn;var ht=on;function Wt(t){if(typeof t=="string")t=new Error(t);else if(t&&typeof t=="object"&&t.name==="ExitStatus"){let e=t.status;t=new K(t.message),t.status=e}else if(typeof t!="object"||t===null||typeof t.stack!="string"||typeof t.message!="string"){let e=API.getTypeTag(t),r=`A value of type ${typeof t} with tag ${e} was thrown as an error!`;try{r+=`\nString interpolation of the thrown value gives """${t}""".`}catch{r+=`\nString interpolation of the thrown value fails.`}try{r+=`\nThe thrown value's toString method returns """${t.toString()}""".`}catch{r+=`\nThe thrown value's toString method fails.`}t=new Error(r)}return t}i(Wt,"ensureCaughtObjectIsError");var te=class extends Error{constructor(r,n,o){n||(n=`The exception is an object of type ${r} at address ${o} which does not inherit from std::exception`);super(n);this.ty=r}};i(te,"CppException");Object.defineProperty(te.prototype,"name",{get(){return`${this.constructor.name} ${this.ty}`}});var an=WebAssembly.Exception||function(){},Gt=i(t=>t instanceof an,"isWasmException");function Kt(t){if(Gt(t))if(t.is(Module.jsWrapperTag))t=t.getArg(Module.jsWrapperTag,0);else return t;let[e,r]=Module.getExceptionMessage(t);return new te(e,r,t)}i(Kt,"convertCppException");Tests.convertCppException=Kt;var Ht=!1;API.fatal_error=function(t){if(t&&t.pyodide_fatal_error)return;if(Ht){console.error("Recursive call to fatal_error. Inner error was:"),console.error(t);return}if(t instanceof J)throw t;typeof t=="number"||Gt(t)?t=Kt(t):t=Wt(t),t.pyodide_fatal_error=!0,Ht=!0;let e=t instanceof K;e||(console.error("Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers."),console.error("The cause of the fatal error was:"),API.inTestHoist?(console.error(t.toString()),console.error(t.stack)):console.error(t));try{e||_dump_traceback();let n=`Pyodide already ${e?"exited":"fatally failed"} and can no longer be used.`;for(let o of Reflect.ownKeys(API.public_api))typeof o=="string"&&o.startsWith("_")||o==="version"||Object.defineProperty(API.public_api,o,{enumerable:!0,configurable:!0,get:()=>{throw new Error(n)}});API.on_fatal&&API.on_fatal(t)}catch(r){console.error("Another error occurred while handling the fatal error:"),console.error(r)}throw t};API.maybe_fatal_error=function(t){API._skip_unwind_fatal_error&&t==="unwind"||API.fatal_error(t)};var bt=[];API.capture_stderr=function(){bt=[],FS.createDevice("/dev","capture_stderr",null,t=>bt.push(t)),FS.closeStream(2),FS.open("/dev/capture_stderr",1)};API.restore_stderr=function(){return FS.closeStream(2),FS.unlink("/dev/capture_stderr"),FS.open("/dev/stderr",1),(new TextDecoder).decode(new Uint8Array(bt))};API.fatal_loading_error=function(...t){let e=t.join(" ");if(_PyErr_Occurred()){API.capture_stderr(),_PyErr_Print();let r=API.restore_stderr();e+=`\n`+r}throw new re(e)};function Pt(t){if(!t)return!1;let e=t.fileName||"";if(e.includes("wasm-function"))return!0;if(!e.includes("pyodide.asm.js"))return!1;let r=t.functionName||"";return r.startsWith("Object.")&&(r=r.slice(7)),API.public_api&&r in API.public_api&&r!=="PythonError"?(t.functionName=r,!1):!0}i(Pt,"isPyodideFrame");function zt(t){return Pt(t)&&t.functionName==="new_error"}i(zt,"isErrorStart");Module.handle_js_error=function(t){if(t&&t.pyodide_fatal_error)throw t;if(t instanceof I)return;let e=!1;t instanceof T&&(e=_restore_sys_last_exception(t.__error_address));let r,n;try{r=ht.parse(t)}catch{n=!0}if(n&&(t=Wt(t)),!e){let o=_JsProxy_create(t);_set_error(o),_Py_DecRef(o)}if(!n){if(zt(r[0])||zt(r[1]))for(;Pt(r[0]);)r.shift();for(let o of r){if(Pt(o))break;let a=stringToNewUTF8(o.functionName||"???"),s=stringToNewUTF8(o.fileName||"???.js");__PyTraceback_Add(a,s,o.lineNumber),_free(a),_free(s)}}};var T=class extends Error{constructor(r,n,o){let a=Error.stackTraceLimit;Error.stackTraceLimit=1/0;super(n);Error.stackTraceLimit=a,this.type=r,this.__error_address=o}};i(T,"PythonError");API.PythonError=T;var I=class extends Error{constructor(){super("If you are seeing this message, an internal Pyodide error has occurred. Please report it to the Pyodide maintainers.")}};i(I,"_PropagatePythonError");function sn(t){Object.defineProperty(t.prototype,"name",{value:t.name})}i(sn,"setName");var re=class extends Error{};i(re,"FatalPyodideError");var K=class extends Error{};i(K,"Exit");var J=class extends Error{};i(J,"NoGilError");[I,re,K,T,J].forEach(sn);API.NoGilError=J;API.errorConstructors=new Map([EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError,globalThis.DOMException,globalThis.AssertionError,globalThis.SystemError].filter(t=>t).map(t=>[t.constructor.name,t]));API.deserializeError=function(t,e,r){let n=API.errorConstructors.get(t)||Error,o=new n(e);return API.errorConstructors.has(t)||(o.name=t),o.message=e,o.stack=r,o};function ln(t){let e=0,r=0;for(let a of t){r++;let s=a.codePointAt(0);e=s>e?s:e}let n=_PyUnicode_New(r,e);if(n===0)throw new I;let o=_PyUnicode_Data(n);if(e>65535)for(let a of t)HEAPU32[o/4>>>0]=a.codePointAt(0),o+=4;else if(e>255)for(let a of t)HEAPU16[o/2>>>0]=a.codePointAt(0),o+=2;else for(let a of t)HEAPU8[o>>>0]=a.codePointAt(0),o+=1;return n}i(ln,"js2python_string");function cn(t){let e=t,r=0;for(t<0&&(t=-t),t<<=BigInt(1);t;)r++,t>>=BigInt(32);let n=stackSave(),o=stackAlloc(r*4);t=e;for(let s=0;s>2)+s>>>0]=Number(t&BigInt(4294967295)),t>>=BigInt(32);let a=__PyLong_FromByteArray(o,r*4,!0,!0);return stackRestore(n),a}i(cn,"js2python_bigint");function ne(t){let e=un(t);if(e===0)throw new I;return e}i(ne,"js2python_convertImmutable");Module.js2python_convertImmutable=ne;function un(t){let e=typeof t;if(e==="string")return ln(t);if(e==="number")return Number.isSafeInteger(t)?_PyLong_FromDouble(t):_PyFloat_FromDouble(t);if(e==="bigint")return cn(t);if(t==null)return __js2python_none();if(t===!0)return __js2python_true();if(t===!1)return __js2python_false();if(API.isPyProxy(t)){let{props:r,shared:n}=Module.PyProxy_getAttrs(t);return r.roundtrip?_JsProxy_create(t):__js2python_pyproxy(n.ptr)}}i(un,"js2python_convertImmutableInner");function dn(t,e){let r=_PyList_New(t.length);if(r===0)return 0;let n=0;try{e.cache.set(t,r);for(let o=0;oModule.pyproxy_new($e(o,n)),cacheConversion(o,a){if(API.isPyProxy(a))n.cache.set(o,Module.PyProxy_getPtr(a));else throw new Error("Second argument should be a PyProxy!")}};return $e(t,n)}i(fn,"js2python_convert");Module.js2python_convert=fn;Module.processBufferFormatString=function(t,e=""){if(t.length>2)throw new Error(`Expected format string to have length <= 2, got '${t}'.`+e);let r=t.slice(-1),n=t.slice(0,-1),o;switch(n){case"!":case">":o=!0;break;case"<":case"@":case"=":case"":o=!1;break;default:throw new Error(`Unrecognized alignment character ${n}.`+e)}let a;switch(r){case"b":a=Int8Array;break;case"s":case"p":case"c":case"B":case"?":a=Uint8Array;break;case"h":a=Int16Array;break;case"H":a=Uint16Array;break;case"i":case"l":case"n":a=Int32Array;break;case"I":case"L":case"N":case"P":a=Uint32Array;break;case"q":if(globalThis.BigInt64Array===void 0)throw new Error("BigInt64Array is not supported on this browser."+e);a=BigInt64Array;break;case"Q":if(globalThis.BigUint64Array===void 0)throw new Error("BigUint64Array is not supported on this browser."+e);a=BigUint64Array;break;case"f":a=Float32Array;break;case"d":a=Float64Array;break;case"e":throw new Error("Javascript has no Float16 support.");default:throw new Error(`Unrecognized format character '${r}'.`+e)}return[a,o]};Module.python2js_buffer_1d_contiguous=function(t,e,r){let n=e*r;return HEAP8.slice(t,t+n).buffer};Module.python2js_buffer_1d_noncontiguous=function(t,e,r,n,o){let a=o*n,s=new Uint8Array(a);for(let l=0;l=0&&(c=HEAPU32[(c>>2)+0>>>0]+r),s.set(HEAP8.subarray(c>>>0,c+o>>>0),l*o)}return s.buffer};Module._python2js_buffer_recursive=function(t,e,r){let{shape:n,strides:o,ndim:a,converter:s,itemsize:l,suboffsets:c}=r,u=HEAPU32[(n>>2)+e>>>0],d=HEAP32[(o>>2)+e>>>0],p=-1;if(a===0)return s(Module.python2js_buffer_1d_contiguous(t,l,1));if(c!==0&&(p=HEAP32[(c>>2)+e>>>0]),e===a-1){let m;return d===l&&p<0?m=Module.python2js_buffer_1d_contiguous(t,d,u):m=Module.python2js_buffer_1d_noncontiguous(t,d,p,u,l),s(m)}let _=[];for(let m=0;m=0&&(curptr=HEAPU32[(curptr>>2)+0>>>0]+p),_.push(Module._python2js_buffer_recursive(E,e+1,r))}return _};Module.get_converter=function(t,e){let r=UTF8ToString(t),[n,o]=Module.processBufferFormatString(r);switch(r.slice(-1)){case"s":let u=new TextDecoder("utf8",{ignoreBOM:!0});return d=>u.decode(d);case"?":return d=>Array.from(new Uint8Array(d),p=>!!p)}if(!o)return u=>new n(u);let s,l;switch(e){case 2:s="getUint16",l="setUint16";break;case 4:s="getUint32",l="setUint32";break;case 8:s="getFloat64",l="setFloat64";break;default:throw new Error(`Unexpected size ${e}`)}function c(u){let d=new DataView(u),p=d[s].bind(d),_=d[l].bind(d);for(let m=0;mnew n(c(u))};function gn(t){try{return t instanceof g}catch{return!1}}i(gn,"isPyProxy");API.isPyProxy=gn;globalThis.FinalizationRegistry?Module.finalizationRegistry=new FinalizationRegistry(({ptr:t,cache:e})=>{e&&(e.leaked=!0,rr(e));try{_check_gil();let r=validSuspender.value;validSuspender.value=!1,_Py_DecRef(t),validSuspender.value=r}catch(r){API.fatal_error(r)}}):Module.finalizationRegistry={register(){},unregister(){}};var vt=new Map;Module.pyproxy_alloc_map=vt;var wt,St;Module.enable_pyproxy_allocation_tracing=function(){wt=i(function(t){vt.set(t,Error().stack)},"trace_pyproxy_alloc"),St=i(function(t){vt.delete(t)},"trace_pyproxy_dealloc")};Module.disable_pyproxy_allocation_tracing=function(){wt=i(function(t){},"trace_pyproxy_alloc"),St=i(function(t){},"trace_pyproxy_dealloc")};Module.disable_pyproxy_allocation_tracing();var Zt=Symbol("pyproxy.attrs");function mn(t,e){_check_gil();let r=validSuspender.value;validSuspender.value=!1;try{return _pyproxy_getflags(t,e)}finally{validSuspender.value=r}}i(mn,"pyproxy_getflags");function xe(t,{flags:e,cache:r,props:n,shared:o,gcRegister:a,jsonAdaptor:s}={}){a===void 0&&(a=!0);let l=e!==void 0?e:mn(t,!!s);l===-1&&_pythonexc2js();let c=l&8192,u=l&32768,d=Module.getPyProxyClass(l),p;l&256?(p=i(function(){},"target"),Object.setPrototypeOf(p,d.prototype),delete p.length,delete p.name,p.prototype=void 0):p=Object.create(d.prototype);let _=!!o;o||(r||(r={map:new Map,json_adaptor_map:new Map,refcnt:0}),r.refcnt++,o={ptr:t,cache:r,flags:l,promise:void 0,destroyed_msg:void 0,gcRegistered:!1},_Py_IncRef(t)),n=Object.assign({isBound:!1,captureThis:!1,boundArgs:[],roundtrip:!1},n);let m;u?m=xt:c?m=In:m=B;let E=new Proxy(p,m);!_&&a&&er(o),_||wt(E);let M={shared:o,props:n};return p[Zt]=M,E}i(xe,"pyproxy_new");Module.pyproxy_new=xe;function er(t){let e=Object.assign({},t);t.gcRegistered=!0,Module.finalizationRegistry.register(t,e,t)}i(er,"gc_register_proxy");Module.gc_register_proxy=er;function Ze(t){return t[Zt]}i(Ze,"_getAttrsQuiet");Module.PyProxy_getAttrsQuiet=Ze;function k(t){let e=Ze(t);if(!e.shared.ptr)throw new Error(e.shared.destroyed_msg);return e}i(k,"_getAttrs");Module.PyProxy_getAttrs=k;function f(t){return k(t).shared.ptr}i(f,"_getPtr");function P(t){return Object.getPrototypeOf(t).$$flags}i(P,"_getFlags");function tr(t){return!!(P(t)&98304)}i(tr,"isJsonAdaptor");function qt(t,e,r){let{captureThis:n,boundArgs:o,boundThis:a,isBound:s}=k(t).props;return n?s?[a].concat(o,r):[e].concat(r):s?o.concat(r):r}i(qt,"_adjustArgs");var Yt=new Map;Module.getPyProxyClass=function(t){let e=[[1,je],[2,H],[4,R],[8,V],[16,He],[32,We],[2048,Ge],[512,ze],[1024,Ke],[4096,Je],[64,Ye],[128,Qe],[256,be],[8192,Ve],[16384,qe]],r=Yt.get(t);if(r)return r;let n={};for(let[l,c]of e)t&l&&Object.assign(n,Object.getOwnPropertyDescriptors(c.prototype));(t&8192||t&2)&&Object.assign(n,Object.getOwnPropertyDescriptors(Be.prototype)),n.constructor=Object.getOwnPropertyDescriptor(g.prototype,"constructor"),Object.assign(n,Object.getOwnPropertyDescriptors({$$flags:t}));let o=t&256?or:nr,a=Object.create(o,n);function s(){}return i(s,"NewPyProxyClass"),s.prototype=a,Yt.set(t,s),s};Module.PyProxy_getPtr=f;var Qt="This borrowed attribute proxy was automatically destroyed in the process of destroying the proxy it was borrowed from. Try using the 'copy' method.";function rr(t){if(t&&(t.refcnt--,!t.leaked&&t.refcnt===0)){for(let e of t.map.values())Module.pyproxy_destroy(e,Qt,!0);for(let e of t.json_adaptor_map.values())Module.pyproxy_destroy(e,Qt,!0)}}i(rr,"pyproxy_decref_cache");function _n(t,e){if(e=e||"Object has already been destroyed",API.debug_ffi){let r=t.type,n;try{n=t.toString()}catch(o){if(o.pyodide_fatal_error)throw o}e+=`\nThe object was of type "${r}" and `,n?e+=`had repr "${n}"`:e+="an error was raised when trying to generate its repr"}else e+="\nFor more information about the cause of this error, use `pyodide.setDebug(true)`";return e}i(_n,"generateDestroyedMessage");Module.pyproxy_destroy=function(t,e,r){let{shared:n,props:o}=Ze(t);if(!n.ptr||!r&&o.roundtrip)return;n.destroyed_msg=_n(t,e);let a=n.ptr;n.ptr=0,n.gcRegistered&&Module.finalizationRegistry.unregister(n),rr(n.cache);try{_check_gil();let s=validSuspender.value;validSuspender.value=!1,_Py_DecRef(a),St(t),validSuspender.value=s}catch(s){API.fatal_error(s)}};function Xe(t,e,r){let n=e.length,o=Object.keys(r),a=Object.values(r),s=o.length;e.push(...a);let l;try{_check_gil();let c=validSuspender.value;validSuspender.value=!1,l=__pyproxy_apply(t,e,n,o,s),validSuspender.value=c}catch(c){API.maybe_fatal_error(c);return}if(l===null&&_pythonexc2js(),l&&l.type==="coroutine"&&l._ensure_future){_check_gil();let c=validSuspender.value;validSuspender.value=!1;let u=__iscoroutinefunction(t);validSuspender.value=c,u&&l._ensure_future()}return l}i(Xe,"callPyObjectKwargs");async function Ue(t,e,r){if(!Module.jspiSupported)throw new Error("WebAssembly stack switching not supported in this JavaScript runtime");let n=e.length,o=Object.keys(r),a=Object.values(r),s=o.length;e.push(...a);let l=stackSave(),c=stackAlloc(4),u;try{_check_gil();let d=validSuspender.value;validSuspender.value=!1,u=await Module.promisingApply(t,e,n,o,s,c),validSuspender.value=d}catch(d){API.fatal_error(d)}if(u===null){_PyErr_SetRaisedException(HEAPU32[c/4>>>0]);try{_pythonexc2js()}finally{stackRestore(l)}}if(u&&u.type==="coroutine"&&u._ensure_future){_check_gil();let d=validSuspender.value;validSuspender.value=!1;let p=__iscoroutinefunction(t);validSuspender.value=d,p&&u._ensure_future()}return u}i(Ue,"callPyObjectKwargsPromising");Module.callPyObjectMaybePromising=async function(t,e){return Module.jspiSupported?await Ue(t,e,{}):Xe(t,e,{})};Module.callPyObject=function(t,e){return Xe(t,e,{})};var g=class{static[Symbol.hasInstance](e){return[g,ar].some(r=>Function.prototype[Symbol.hasInstance].call(r,e))}constructor(){throw new TypeError("PyProxy is not a constructor")}get[Symbol.toStringTag](){return"PyProxy"}get type(){let e=f(this);return __pyproxy_type(e)}toString(){let e=f(this),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxy_repr(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r}destroy(e={}){e=Object.assign({message:"",destroyRoundtrip:!0},e);let{message:r,destroyRoundtrip:n}=e;Module.pyproxy_destroy(this,r,n)}copy(){let e=k(this);return xe(e.shared.ptr,{flags:P(this),cache:e.shared.cache,props:e.props})}toJs({depth:e=-1,pyproxies:r=void 0,create_pyproxies:n=!0,dict_converter:o=void 0,default_converter:a=void 0}={}){let s=f(this),l,c;n?r?c=r:c=[]:c=null;try{_check_gil();let u=validSuspender.value;validSuspender.value=!1,l=_python2js_custom(s,e,c,o||null,a||null),validSuspender.value=u}catch(u){API.fatal_error(u)}return l===null&&_pythonexc2js(),l}};i(g,"PyProxy");var nr=g.prototype;Tests.Function=Function;var or=Object.create(Function.prototype,Object.getOwnPropertyDescriptors(nr));function ar(){}i(ar,"PyProxyFunction");ar.prototype=or;var oe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&1)}};i(oe,"PyProxyWithLength");var je=class{get length(){let e=f(this),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=_PyObject_Size(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===-1&&_pythonexc2js(),r}};i(je,"PyLengthMethods");var ae=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&2)}};i(ae,"PyProxyWithGet");var Be=class{asJsJson(){let{shared:e,props:r}=k(this),n=P(this);return n&8192?n|=65536:n|=32768,xe(e.ptr,{shared:e,flags:n,props:r})}};i(Be,"PyAsJsonAdaptorMethods");var H=class{get(e){let{shared:r}=k(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_getitem(r.ptr,e,r.cache.json_adaptor_map,tr(this)),validSuspender.value=o}catch(o){API.fatal_error(o)}if(n===null)if(_PyErr_Occurred())_pythonexc2js();else return;return n}asJsJson(){throw new Error("Should not happen")}};i(H,"PyGetItemMethods");var ie=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&4)}};i(ie,"PyProxyWithSet");var R=class{set(e,r){let n=f(this),o;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,o=__pyproxy_setitem(n,e,r),validSuspender.value=a}catch(a){API.fatal_error(a)}o===-1&&_pythonexc2js()}delete(e){let r=f(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_delitem(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}n===-1&&_pythonexc2js()}};i(R,"PySetItemMethods");var se=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&8)}};i(se,"PyProxyWithHas");var V=class{has(e){let r=f(this),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_contains(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===-1&&_pythonexc2js(),n===1}};i(V,"PyContainsMethods");function*hn(t,e,r,n){let o=[];try{for(;;){_check_gil();let a=validSuspender.value;validSuspender.value=!1;let s=__pyproxy_iter_next(t,r,n);if(validSuspender.value=a,s===null)break;yield s,!n&&API.isPyProxy(s)&&o.push(s)}}catch(a){API.fatal_error(a)}finally{Module.finalizationRegistry.unregister(e),_Py_DecRef(t)}try{o.forEach(a=>Module.pyproxy_destroy(a,"This borrowed proxy was automatically destroyed when an iterator was exhausted."))}catch{}_PyErr_Occurred()&&_pythonexc2js()}i(hn,"iter_helper");var le=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&48)}};i(le,"PyIterable");var He=class{[Symbol.iterator](){let{shared:e}=k(this),r={},n;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,n=_PyObject_GetIter(e.ptr),validSuspender.value=a}catch(a){API.fatal_error(a)}n===0&&_pythonexc2js();let o=hn(n,r,e.cache.json_adaptor_map,tr(this));return Module.finalizationRegistry.register(o,[n,void 0],r),o}};i(He,"PyIterableMethods");async function*bn(t,e){try{for(;;){let r;try{_check_gil();let n=validSuspender.value;if(validSuspender.value=!1,r=__pyproxy_aiter_next(t),validSuspender.value=n,r===null)break}catch(n){API.fatal_error(n)}try{yield await r}catch(n){if(n&&typeof n=="object"&&n.type==="StopAsyncIteration")return;throw n}finally{r.destroy()}}}finally{Module.finalizationRegistry.unregister(e),_Py_DecRef(t)}_PyErr_Occurred()&&_pythonexc2js()}i(bn,"aiter_helper");var ce=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&1536)}};i(ce,"PyAsyncIterable");var ze=class{[Symbol.asyncIterator](){let e=f(this),r={},n;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,n=_PyObject_GetAIter(e),validSuspender.value=a}catch(a){API.fatal_error(a)}n===0&&_pythonexc2js();let o=bn(n,r);return Module.finalizationRegistry.register(o,[n,void 0],r),o}};i(ze,"PyAsyncIterableMethods");var ue=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&32)}};i(ue,"PyIterator");var We=class{[Symbol.iterator](){return this}next(e=void 0){let r,n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_Send(f(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}return r===null&&_pythonexc2js(),r}};i(We,"PyIteratorMethods");var de=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&2048)}};i(de,"PyGenerator");var Ge=class{throw(e){let r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_throw(f(this),e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r}return(e){let r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_return(f(this),e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r}};i(Ge,"PyGeneratorMethods");var ye=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&1024)}};i(ye,"PyAsyncIterator");var Ke=class{[Symbol.asyncIterator](){return this}async next(e=void 0){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_ascend(f(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}r===null&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"&&o.type==="StopAsyncIteration")return{done:!0,value:n};throw o}finally{r.destroy()}return{done:!1,value:n}}};i(Ke,"PyAsyncIteratorMethods");var pe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&4096)}};i(pe,"PyAsyncGenerator");var Je=class{async throw(e){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_athrow(f(this),e),validSuspender.value=o}catch(o){API.fatal_error(o)}r===null&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"){if(o.type==="StopAsyncIteration")return{done:!0,value:n};if(o.type==="GeneratorExit")return{done:!0,value:n}}throw o}finally{r.destroy()}return{done:!1,value:n}}async return(e){let r;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,r=__pyproxyGen_areturn(f(this)),validSuspender.value=o}catch(o){API.fatal_error(o)}r===null&&_pythonexc2js();let n;try{n=await r}catch(o){if(o&&typeof o=="object"){if(o.type==="StopAsyncIteration")return{done:!0,value:n};if(o.type==="GeneratorExit")return{done:!0,value:e}}throw o}finally{r.destroy()}return{done:!1,value:n}}};i(Je,"PyAsyncGeneratorMethods");var fe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&8192)}};i(fe,"PySequence");function On(t,e){let r=t.toString(),n=e.toString();return r===n?0:r{this.insert(n,r)}),this.length}copyWithin(...e){return Array.prototype.copyWithin.apply(this,e),this}fill(...e){return Array.prototype.fill.apply(this,e),this}};i(qe,"PyMutableSequenceMethods");function vn(t,e){let r=f(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_hasattr(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===-1&&_pythonexc2js(),n!==0}i(vn,"python_hasattr");function xn(t,e){let{shared:r}=k(t),n=r.cache.map,o;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,o=__pyproxy_getattr(r.ptr,e,n),validSuspender.value=a}catch(a){API.fatal_error(a)}if(o===null){_PyErr_Occurred()&&_pythonexc2js();return}return o}i(xn,"python_getattr");function wn(t,e,r){let n=f(t),o;try{_check_gil();let a=validSuspender.value;validSuspender.value=!1,o=__pyproxy_setattr(n,e,r),validSuspender.value=a}catch(a){API.fatal_error(a)}o===-1&&_pythonexc2js()}i(wn,"python_setattr");function Sn(t,e){let r=f(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_delattr(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}n===-1&&_pythonexc2js()}i(Sn,"python_delattr");function An(t,e,r,n){let o=f(t),a;try{_check_gil();let s=validSuspender.value;validSuspender.value=!1,a=__pyproxy_slice_assign(o,e,r,n),validSuspender.value=s}catch(s){API.fatal_error(s)}return a===null&&_pythonexc2js(),a}i(An,"python_slice_assign");function Xt(t,e){let r=f(t),n;try{_check_gil();let o=validSuspender.value;validSuspender.value=!1,n=__pyproxy_pop(r,e),validSuspender.value=o}catch(o){API.fatal_error(o)}return n===null&&_pythonexc2js(),n}i(Xt,"python_pop");function Ce(t,e,r){return t instanceof Function?e in t&&!["name","length","caller","arguments",r?"prototype":void 0].includes(e):e in t}i(Ce,"filteredHasKey");var B={isExtensible(){return!0},has(t,e){return Ce(t,e,!1)?!0:typeof e=="symbol"?!1:(e.startsWith("$")&&(e=e.slice(1)),vn(t,e))},get(t,e){return typeof e=="symbol"||Ce(t,e,!0)?Reflect.get(t,e):(e.startsWith("$")&&(e=e.slice(1)),xn(t,e))},set(t,e,r){let n=Object.getOwnPropertyDescriptor(t,e);return n&&!n.writable&&!n.set?!1:typeof e=="symbol"||Ce(t,e,!0)?Reflect.set(t,e,r):(e.startsWith("$")&&(e=e.slice(1)),wn(t,e,r),!0)},deleteProperty(t,e){let r=Object.getOwnPropertyDescriptor(t,e);return r&&!r.configurable?!1:typeof e=="symbol"||Ce(t,e,!0)?Reflect.deleteProperty(t,e):(e.startsWith("$")&&(e=e.slice(1)),Sn(t,e),!0)},ownKeys(t){let e=f(t),r;try{_check_gil();let n=validSuspender.value;validSuspender.value=!1,r=__pyproxy_ownKeys(e),validSuspender.value=n}catch(n){API.fatal_error(n)}return r===null&&_pythonexc2js(),r.push(...Reflect.ownKeys(t)),r},apply(t,e,r){return t.apply(e,r)}};function me(t){return t&&typeof t=="object"&&t.constructor&&t.constructor.name==="PythonError"}i(me,"isPythonError");var In={isExtensible(){return!0},has(t,e){return typeof e=="string"&&/^[0-9]+$/.test(e)?Number(e)n.toString())),e.push("length"),e}},xt={isExtensible(){return!0},has(t,e){return!!(V.prototype.has.call(t,e)||(typeof e=="string"&&/^[0-9]+$/.test(e)&&(e=Number(e)),V.prototype.has.call(t,e)))},get(t,e){let r;return["copy","constructor","$$flags","toString","destroy"].includes(e)||typeof e=="symbol"?Reflect.get(...arguments):(typeof e=="string"&&(r=H.prototype.get.call(t,e)),r||(typeof e=="string"&&/^[0-9]+$/.test(e)&&(e=Number(e),r=H.prototype.get.call(t,e)),r)?r:Reflect.get(...arguments))},set(t,e,r){if(typeof e=="string"){/^[0-9]+$/.test(e)&&(e=Number(e));try{return R.prototype.set.call(t,e,r),!0}catch(n){if(me(n))return!1;throw n}}return!1},deleteProperty(t,e){if(typeof e=="string"&&/^[0-9]+$/.test(e))try{return R.prototype.delete.call(t,Number(e)),!0}catch(r){if(me(r))return!1;throw r}return!1},getOwnPropertyDescriptor(t,e){return xt.has(t,e)?{configurable:!0,enumerable:!0,value:xt.get(t,e),writable:!0}:void 0},ownKeys(t){let e;e=B.get(t,"keys")();let r=Array.from(e);return e.destroy(),r}},_e=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&64)}};i(_e,"PyAwaitable");var Ye=class{_ensure_future(){let{shared:e}=Ze(this);if(e.promise)return e.promise;let r=e.ptr;r||k(this);let n,o,a=new Promise((l,c)=>{n=l,o=c}),s;try{_check_gil();let l=validSuspender.value;validSuspender.value=!1,s=__pyproxy_ensure_future(r,n,o),validSuspender.value=l}catch(l){API.fatal_error(l)}return s===-1&&_pythonexc2js(),e.promise=a,this.destroy(),a}then(e,r){return this._ensure_future().then(e,r)}catch(e){return this._ensure_future().catch(e)}finally(e){return this._ensure_future().finally(e)}};i(Ye,"PyAwaitableMethods");var he=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&256)}};i(he,"PyCallable");var be=class{apply(e,r){return r=function(...n){return n}.apply(void 0,r),r=qt(this,e,r),Module.callPyObject(f(this),r)}call(e,...r){return r=qt(this,e,r),Module.callPyObject(f(this),r)}callWithOptions({relaxed:e,kwargs:r,promising:n},...o){let a={};if(r){if(o.length===0)throw new TypeError("callWithOptions with 'kwargs: true' requires at least one argument (the key word argument object)");if(a=o.pop(),a.constructor!==void 0&&a.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object")}let s=e?API.pyodide_code.relaxed_call:this;return e&&o.unshift(this),(n?Ue:Xe)(f(s),o,a)}callKwargs(...e){if(e.length===0)throw new TypeError("callKwargs requires at least one argument (the key word argument object)");let r=e.pop();if(r.constructor!==void 0&&r.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object");return Xe(f(this),e,r)}callRelaxed(...e){return API.pyodide_code.relaxed_call(this,...e)}callKwargsRelaxed(...e){return API.pyodide_code.relaxed_call.callKwargs(this,...e)}callPromising(...e){return Ue(f(this),e,{})}callPromisingKwargs(...e){if(e.length===0)throw new TypeError("callKwargs requires at least one argument (the key word argument object)");let r=e.pop();if(r.constructor!==void 0&&r.constructor.name!=="Object")throw new TypeError("kwargs argument is not an object");return Ue(f(this),e,r)}bind(e,...r){let{shared:n,props:o}=k(this),{boundArgs:a,boundThis:s,isBound:l}=o,c=e;l&&(c=s);let u=a.concat(r);return o=Object.assign({},o,{boundArgs:u,isBound:!0,boundThis:c}),xe(n.ptr,{shared:n,flags:P(this),props:o})}captureThis(){let{props:e,shared:r}=k(this);return e=Object.assign({},e,{captureThis:!0}),xe(r.ptr,{shared:r,flags:P(this),props:e})}};i(be,"PyCallableMethods");be.prototype.prototype=Function.prototype;var kn=new Map([["i8",Int8Array],["u8",Uint8Array],["u8clamped",Uint8ClampedArray],["i16",Int16Array],["u16",Uint16Array],["i32",Int32Array],["u32",Uint32Array],["i32",Int32Array],["u32",Uint32Array],["i64",globalThis.BigInt64Array],["u64",globalThis.BigUint64Array],["f32",Float32Array],["f64",Float64Array],["dataview",DataView]]),Pe=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&!!(P(e)&128)}};i(Pe,"PyBuffer");var Qe=class{getBuffer(e){let r;if(e&&(r=kn.get(e),r===void 0))throw new Error(`Unknown type ${e}`);let n=f(this),o;try{_check_gil();let F=validSuspender.value;validSuspender.value=!1,o=__pyproxy_get_buffer(n),validSuspender.value=F}catch(F){API.fatal_error(F)}o===null&&_pythonexc2js();let{start_ptr:a,smallest_ptr:s,largest_ptr:l,readonly:c,format:u,itemsize:d,shape:p,strides:_,view:m,c_contiguous:E,f_contiguous:M}=o,jt=!1;try{let F=!1;r===void 0&&([r,F]=Module.processBufferFormatString(u," In this case, you can pass an explicit type argument."));let L=parseInt(r.name.replace(/[^0-9]/g,""))/8||1;if(F&&L>1)throw new Error("JavaScript has no native support for big endian buffers. In this case, you can pass an explicit type argument. For instance, `getBuffer('dataview')` will return a `DataView`which has native support for reading big endian data. Alternatively, toJs will automatically convert the buffer to little endian.");let Te=l-s;if(Te!==0&&(a%L!==0||s%L!==0||l%L!==0))throw new Error(`Buffer does not have valid alignment for a ${r.name}`);let Gr=Te/L,Kr=(a-s)/L,gt;Te===0?gt=new r:gt=new r(HEAPU32.buffer,s,Gr);for(let Jr of _.keys())_[Jr]/=L;return jt=!0,Object.create(q.prototype,Object.getOwnPropertyDescriptors({offset:Kr,readonly:c,format:u,itemsize:d,ndim:p.length,nbytes:Te,shape:p,strides:_,data:gt,c_contiguous:E,f_contiguous:M,_view_ptr:m,_released:!1}))}finally{if(!jt)try{_check_gil();let F=validSuspender.value;validSuspender.value=!1,_PyBuffer_Release(m),_PyMem_Free(m),validSuspender.value=F}catch(F){API.fatal_error(F)}}}};i(Qe,"PyBufferMethods");var ve=class extends g{static[Symbol.hasInstance](e){return API.isPyProxy(e)&&e.type==="dict"}};i(ve,"PyDict");var q=class{constructor(){throw new TypeError("PyBufferView is not a constructor")}release(){if(!this._released){try{_check_gil();let e=validSuspender.value;validSuspender.value=!1,_PyBuffer_Release(this._view_ptr),_PyMem_Free(this._view_ptr),validSuspender.value=e}catch(e){API.fatal_error(e)}this._released=!0,this.data=null}}};i(q,"PyBufferView");var ir={PyProxy:g,PyProxyWithLength:oe,PyProxyWithGet:ae,PyProxyWithSet:ie,PyProxyWithHas:se,PyDict:ve,PyIterable:le,PyAsyncIterable:ce,PyIterator:ue,PyAsyncIterator:ye,PyGenerator:de,PyAsyncGenerator:pe,PyAwaitable:_e,PyCallable:he,PyBuffer:Pe,PyBufferView:q,PythonError:T,PySequence:fe,PyMutableSequence:ge};function sr(t){t.id!=="canvas"&&console.warn("If you are using canvas element for SDL library, it should have id 'canvas' to work properly."),Module.canvas=t}i(sr,"setCanvas2D");function lr(){return Module.canvas}i(lr,"getCanvas2D");function En(t){sr(t)}i(En,"setCanvas3D");function Fn(){return lr()}i(Fn,"getCanvas3D");var cr={setCanvas2D:sr,getCanvas2D:lr,setCanvas3D:En,getCanvas3D:Fn};var h=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,At=h&&typeof module<"u"&&typeof module.exports<"u"&&typeof x<"u"&&typeof __dirname<"u",ur=h&&!At,On=typeof globalThis.Bun<"u",dr=typeof Deno<"u",It=!h&&!dr,Y=It&&typeof window=="object"&&typeof document=="object"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof importScripts!="function",we=It&&typeof importScripts=="function"&&typeof self=="object",kt=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")==-1&&navigator.userAgent.indexOf("Safari")>-1;function yr(){return{IN_NODE:h,IN_NODE_COMMONJS:At,IN_NODE_ESM:ur,IN_BUN:On,IN_DENO:dr,IN_BROWSER:It,IN_BROWSER_MAIN_THREAD:Y,IN_BROWSER_WEB_WORKER:we,IN_SAFARI:kt}}i(yr,"detectEnvironment");function Et(){let t=i(()=>{},"_resolve"),e=i(()=>{},"_reject"),r=new Promise((n,o)=>{t=n,e=o});return r.resolve=t,r.reject=e,r}i(Et,"createResolvable");function et(){let t=Promise.resolve();async function e(){let r=t,n;return t=new Promise(o=>n=o),await r,n}return i(e,"acquireLock"),e}i(et,"createLock");var Dn=/[-_.]+/g;function pr(t){return t.replace(Dn,"-").toLowerCase()}i(pr,"canonicalizePackageName");var Mn=/^.*?([^\/]*)\.whl$/;function fr(t){let e=Mn.exec(t);if(e){let r=e[1].toLowerCase().split("-");return{name:r[0],version:r[1],fileName:r.join("-")+".whl"}}}i(fr,"uriToPackageData");function gr(t){return btoa(t.match(/\w{2}/g).map(function(e){return String.fromCharCode(parseInt(e,16))}).join(""))}i(gr,"base16ToBase64");var mr,Ot,_r,tt,Q;async function hr(){if(!h||(mr=(await import("node:url")).default,tt=await import("node:fs"),Q=await import("node:fs/promises"),_r=(await import("node:vm")).default,Ot=await import("node:path"),br=Ot.sep,typeof x<"u"))return;let t=tt,e=await import("node:crypto"),r=await import("ws"),n=await import("node:child_process"),o={fs:t,crypto:e,ws:r,child_process:n};globalThis.require=function(a){return o[a]}}i(hr,"initNodeModules");function Nn(t,e){return Ot.resolve(e||".",t)}i(Nn,"node_resolvePath");function Tn(t,e){return e===void 0&&(e=location),new URL(t,e).toString()}i(Tn,"browser_resolvePath");var rt;h?rt=Nn:rt=Tn;var br;h||(br="/");function Rn(t,e){return t.startsWith("file://")&&(t=t.slice(7)),t.includes("://")?{response:fetch(t)}:{binary:Q.readFile(t).then(r=>new Uint8Array(r.buffer,r.byteOffset,r.byteLength))}}i(Rn,"node_getBinaryResponse");function Ln(t,e){let r=new URL(t,location);return{response:fetch(r,e?{integrity:e}:{})}}i(Ln,"browser_getBinaryResponse");var Dt;h?Dt=Rn:Dt=Ln;async function Se(t,e){let{response:r,binary:n}=Dt(t,e);if(n)return n;let o=await r;if(!o.ok)throw new Error(`Failed to load '${t}': request failed.`);return new Uint8Array(await o.arrayBuffer())}i(Se,"loadBinaryFile");var Ft;if(Y)Ft=i(async t=>await import(t),"loadScript");else if(we)Ft=i(async t=>{try{globalThis.importScripts(t)}catch(e){if(e instanceof TypeError)await import(t);else throw e}},"loadScript");else if(h)Ft=$n;else throw new Error("Cannot determine runtime environment");async function $n(t){t.startsWith("file://")&&(t=t.slice(7)),t.includes("://")?_r.runInThisContext(await(await fetch(t)).text()):await import(mr.pathToFileURL(t).href)}i($n,"nodeLoadScript");async function Pr(t){if(h)try{await Q.stat(t)}catch{await Q.mkdir(t,{recursive:!0})}}i(Pr,"ensureDirNode");var Z,b,X=class{constructor(e,r){O(this,Z,void 0);O(this,b,void 0);this._lock=et();D(this,Z,e),D(this,b,r)}*getSubDirs(e){let r=y(this,b).FS.readdir(e);for(let n of r){if(n==="."||n==="..")continue;let o=y(this,b).PATH.join2(e,n),a=y(this,b).FS.lookupPath(o);if(a.node===null)continue;let s=a.node.mode;y(this,b).FS.isDir(s)&&(yield o,yield*this.getSubDirs(o))}}createDynlibFS(e,r){let n=e.substring(0,e.lastIndexOf("/")),o=r||[];o=o.concat(y(this,Z).defaultLdLibraryPath,[n]);let a=i(c=>{if(y(this,b).PATH.isAbs(c))return c;for(let u of o){let d=y(this,b).PATH.join2(u,c);if(y(this,b).FS.findObject(d)!==null)return d}for(let u of this.getSubDirs(n)){let d=y(this,b).PATH.join2(u,c);if(y(this,b).FS.findObject(d)!==null)return d}return c},"resolvePath");return{findObject:(c,u)=>y(this,b).FS.findObject(a(c),u),readFile:i(c=>y(this,b).FS.readFile(a(c)),"readFile")}}async loadDynlib(e,r,n){let o=await this._lock(),a=this.createDynlibFS(e,n),s=r?null:{};try{if(await y(this,b).loadDynamicLibrary(e,{loadAsync:!0,nodelete:!0,allowUndefined:!0,global:r,fs:a},s),y(this,b).PATH.isAbs(e)){let l=y(this,b).PATH.basename(e);y(this,b).LDSO.loadedLibsByName[l]||(y(this,b).LDSO.loadedLibsByName[l]=y(this,b).LDSO.loadedLibsByName[e])}}catch(l){if(l&&l.message&&l.message.includes("need to see wasm magic number")){console.warn(`Failed to load dynlib ${e}. We probably just tried to load a linux .so file or something.`);return}throw l}finally{o()}}async loadDynlibsFromPackage(e,r){let n=`${y(this,Z).sitepackages}/${e.file_name.split("-")[0]}.libs`;for(let o of r)await this.loadDynlib(o,!1,[n])}};i(X,"DynlibLoader"),Z=new WeakMap,b=new WeakMap;if(typeof API<"u"&&typeof Module<"u"){let t=new X(API,Module);API.loadDynlib=t.loadDynlib.bind(t),API.loadDynlibsFromPackage=t.loadDynlibsFromPackage.bind(t)}var Ae,Ie,ee=class{constructor(e,r){O(this,Ae,void 0);O(this,Ie,void 0);D(this,Ae,e),D(this,Ie,new X(e,r))}async install(e,r,n,o,a){let s=y(this,Ae).package_loader.unpack_buffer.callKwargs({buffer:e,filename:r,extract_dir:n,installer:o,source:a,calculate_dynlibs:!0});await y(this,Ie).loadDynlibsFromPackage({file_name:r},s)}};i(ee,"Installer"),Ae=new WeakMap,Ie=new WeakMap;var vr;if(typeof API<"u"&&typeof Module<"u"){let t=new ee(API,Module);vr=t.install.bind(t),API.install=vr}async function Cn(t){await hr();let e=await t;if(!e.packages)throw new Error("Loaded pyodide lock file does not contain the expected key 'packages'.");if(e.info.version!==API.version)throw new Error(`Lock file version doesn't match Pyodide version.\n lockfile version: ${e.info.version}\n pyodide version: ${API.version}`);API.lockfile_info=e.info,API.lockfile_packages=e.packages,API.lockfile_unvendored_stdlibs_and_test=[],API.repodata_info=e.info,API.repodata_packages=e.packages,API._import_name_to_package_name=new Map;for(let o of Object.keys(API.lockfile_packages)){let a=API.lockfile_packages[o];for(let s of a.imports)API._import_name_to_package_name.set(s,o);a.package_type==="cpython_module"&&API.lockfile_unvendored_stdlibs_and_test.push(o)}API.lockfile_unvendored_stdlibs=API.lockfile_unvendored_stdlibs_and_test.filter(o=>o!=="test");let r=API.config.packages;API.config.fullStdLib&&(r=[...r,...API.lockfile_unvendored_stdlibs]),await Oe(r,{messageCallback(){}}),await API.bootstrapFinalizedPromise,API._pyodide._importhook.register_module_not_found_hook(API._import_name_to_package_name,API.lockfile_unvendored_stdlibs_and_test),API.package_loader.init_loaded_packages()}i(Cn,"initializePackageIndex");var Un="default channel",jn="pyodide.loadPackage",w,Ee,Fe,nt=class{constructor(e,r){O(this,w,void 0);O(this,Ee,void 0);O(this,Fe,void 0);this.cdnURL="";this.loadedPackages={};this._lock=et();this.stdout=console.log;this.stderr=console.error;this.defaultChannel=Un;D(this,w,e),D(this,Ee,r),D(this,Fe,new ee(e,r))}async loadPackage(e,r={checkIntegrity:!0}){let n=new Set,{messageCallback:o,errorCallback:a}=r,s=Hn(e),l=this.recursiveDependencies(s,a);for(let[p,{name:_,normalizedName:m,channel:E}]of l){let M=this.getLoadedPackageChannel(_);M&&(l.delete(m),M===E||E===this.defaultChannel?this.logStdout(`${_} already loaded from ${M}`,o):this.logStderr(`URI mismatch, attempting to load package ${_} from ${E} while it is already loaded from ${M}. To override a dependency, load the custom package first.`,a))}if(l.size===0)return this.logStdout("No new packages to load",o),[];let c=Array.from(l.values(),({name:p})=>p).sort().join(", "),u=new Map,d=await this._lock();try{this.logStdout(`Loading ${c}`,o);for(let[p,_]of l){if(this.getLoadedPackageChannel(_.name)){l.delete(_.normalizedName);continue}_.installPromise=this.downloadAndInstall(_,l,n,u,r.checkIntegrity)}if(await Promise.all(Array.from(l.values()).map(({installPromise:p})=>p)),y(this,Ee).reportUndefinedSymbols(),n.size>0){let p=Array.from(n,_=>_.name).sort().join(", ");this.logStdout(`Loaded ${p}`,o)}if(u.size>0){let p=Array.from(u.keys()).sort().join(", ");this.logStdout(`Failed to load ${p}`,o);for(let[_,m]of u)this.logStderr(`The following error occurred while loading ${_}:`,a),this.logStderr(m.message,a)}return y(this,w).importlib.invalidate_caches(),Array.from(n,Bn)}finally{d()}}addPackageToLoad(e,r){let n=pr(e);if(r.has(n))return;let o=y(this,w).lockfile_packages[n];if(!o)throw new Error(`No known package with name '${e}'`);if(r.set(n,{name:o.name,normalizedName:n,channel:this.defaultChannel,depends:o.depends,installPromise:void 0,done:Et(),packageData:o}),!this.getLoadedPackageChannel(o.name))for(let a of o.depends)this.addPackageToLoad(a,r)}recursiveDependencies(e,r){let n=new Map;for(let o of e){let a=fr(o);if(a===void 0){this.addPackageToLoad(o,n);continue}let{name:s,version:l,fileName:c}=a,u=o;if(n.has(s)&&n.get(s).channel!==u){this.logStderr(`Loading same package ${s} from ${u} and ${n.get(s).channel}`,r);continue}n.set(s,{name:s,normalizedName:s,channel:u,depends:[],installPromise:void 0,done:Et(),packageData:{name:s,version:l,file_name:c,install_dir:"site",sha256:"",package_type:"package",imports:[],depends:[]}})}return n}async downloadPackage(e,r=!0){let n=h?y(this,w).config.packageCacheDir:y(this,w).config.indexURL;await Pr(n);let o,a,s;if(e.channel===this.defaultChannel){if(!(e.normalizedName in y(this,w).lockfile_packages))throw new Error(`Internal error: no entry for package named ${name}`);let c=y(this,w).lockfile_packages[e.normalizedName];o=c.file_name,a=rt(o,n),s="sha256-"+gr(c.sha256)}else a=e.channel,s=void 0;r||(s=void 0);try{return await Se(a,s)}catch(c){if(!h||e.channel!==this.defaultChannel)throw c}this.logStdout(`Didn't find package ${o} locally, attempting to load from ${this.cdnURL}`);let l=await Se(this.cdnURL+o);return this.logStdout(`Package ${o} loaded from ${this.cdnURL}, caching the wheel in node_modules for future use.`),await Q.writeFile(a,l),l}async installPackage(e,r){let n=y(this,w).lockfile_packages[e.normalizedName];n||(n=e.packageData);let o=n.file_name,a=y(this,w).package_loader.get_install_dir(n.install_dir);await y(this,Fe).install(r,o,a,jn,e.channel===this.defaultChannel?"pyodide":e.channel)}async downloadAndInstall(e,r,n,o,a=!0){if(ke[e.name]===void 0)try{let s=await this.downloadPackage(e,a),l=e.depends.map(c=>r.has(c)?r.get(c).done:Promise.resolve());await y(this,w).bootstrapFinalizedPromise,await Promise.all(l),await this.installPackage(e,s),n.add(e.packageData),ke[e.name]=e.channel}catch(s){o.set(e.name,s)}finally{e.done.resolve()}}setCdnUrl(e){this.cdnURL=e}getLoadedPackageChannel(e){let r=this.loadedPackages[e];return r===void 0?null:r}logStdout(e,r){r?r(e):this.stdout(e)}logStderr(e,r){r?r(e):this.stderr(e)}};i(nt,"PackageManager"),w=new WeakMap,Ee=new WeakMap,Fe=new WeakMap;function Bn({name:t,version:e,file_name:r,package_type:n}){return{name:t,version:e,fileName:r,packageType:n}}i(Bn,"filterPackageData");function Hn(t){return typeof t.toJs=="function"&&(t=t.toJs()),Array.isArray(t)||(t=[t]),t}i(Hn,"toStringArray");var Oe,ke;if(typeof API<"u"&&typeof Module<"u"){let t=new nt(API,Module);Oe=t.loadPackage.bind(t),ke=t.loadedPackages,API.recursiveDependencies=t.recursiveDependencies.bind(t),API.setCdnUrl=t.setCdnUrl.bind(t),API.lockFilePromise&&(API.packageIndexReady=Cn(API.lockFilePromise))}var xr="0.27.5";var Tt=h?x("node:fs"):void 0,Ir=h?x("node:tty"):void 0;function kr(t){try{Tt.fsyncSync(t)}catch(e){if(e?.code==="EINVAL"||e?.code==="ENOTSUP"&&(t===1||t===2))return;throw e}}i(kr,"nodeFsync");var Er=!1,ct={},A={};function Nt(t){ct[A.stdin]=t}i(Nt,"_setStdinOps");function zn(t){ct[A.stdout]=t}i(zn,"_setStdoutOps");function Wn(t){ct[A.stderr]=t}i(Wn,"_setStderrOps");function Gn(t){return t&&typeof t=="object"&&"errno"in t}i(Gn,"isErrnoError");var Kn=new Int32Array(new WebAssembly.Memory({shared:!0,initial:1,maximum:1}).buffer);function Jn(t){try{return Atomics.wait(Kn,0,0,t),!0}catch{return!1}}i(Jn,"syncSleep");function Vn(t){for(;;)try{return t()}catch(e){if(e&&e.code==="EAGAIN"&&Jn(100))continue;throw e}}i(Vn,"handleEAGAIN");function wr(t,e,r){let n;try{n=Vn(e)}catch(o){throw o&&o.code&&Module.ERRNO_CODES[o.code]?new FS.ErrnoError(Module.ERRNO_CODES[o.code]):Gn(o)?o:(console.error("Error thrown in read:"),console.error(o),new FS.ErrnoError(29))}if(n===void 0)throw console.warn(`${r} returned undefined; a correct implementation must return a number`),new FS.ErrnoError(29);return n!==0&&(t.node.timestamp=Date.now()),n}i(wr,"readWriteHelper");var Sr=i((t,e,r)=>API.typedArrayAsUint8Array(t).subarray(e,e+r),"prepareBuffer"),Mt={open:function(t){let e=ct[t.node.rdev];if(!e)throw new FS.ErrnoError(43);t.devops=e,t.tty=t.devops.isatty,t.seekable=!1},close:function(t){t.stream_ops.fsync(t)},fsync:function(t){let e=t.devops;e.fsync&&e.fsync()},read:function(t,e,r,n,o){return e=Sr(e,r,n),wr(t,()=>t.devops.read(e),"read")},write:function(t,e,r,n,o){return e=Sr(e,r,n),wr(t,()=>t.devops.write(e),"write")}};function ut(){Er&&(FS.closeStream(0),FS.closeStream(1),FS.closeStream(2),FS.open("/dev/stdin",0),FS.open("/dev/stdout",1),FS.open("/dev/stderr",1))}i(ut,"refreshStreams");API.initializeStreams=function(t,e,r){let n=FS.createDevice.major++;A.stdin=FS.makedev(n,0),A.stdout=FS.makedev(n,1),A.stderr=FS.makedev(n,2),FS.registerDevice(A.stdin,Mt),FS.registerDevice(A.stdout,Mt),FS.registerDevice(A.stderr,Mt),FS.unlink("/dev/stdin"),FS.unlink("/dev/stdout"),FS.unlink("/dev/stderr"),FS.mkdev("/dev/stdin",A.stdin),FS.mkdev("/dev/stdout",A.stdout),FS.mkdev("/dev/stderr",A.stderr),Me({stdin:t}),Rt({batched:e}),Lt({batched:r}),Er=!0,ut()};function qn(){Me(h?new at(process.stdin.fd):{stdin:()=>prompt()})}i(qn,"setDefaultStdin");function Yn(){Nt(new ot),ut()}i(Yn,"setStdinError");function Me(t={}){let{stdin:e,error:r,isatty:n,autoEOF:o,read:a}=t,s=+!!e+ +!!r+ +!!a;if(s>1)throw new TypeError("At most one of stdin, read, and error must be provided.");if(!e&&o!==void 0)throw new TypeError("The 'autoEOF' option can only be used with the 'stdin' option");if(s===0){qn();return}r&&Yn(),e&&(o=o===void 0?!0:o,Nt(new it(e.bind(t),!!n,o))),a&&Nt(t),ut()}i(Me,"setStdin");function Fr(t,e,r){let{raw:n,isatty:o,batched:a,write:s}=t,l=+!!n+ +!!a+ +!!s;if(l===0&&(t=r(),({raw:n,isatty:o,batched:a,write:s}=t)),l>1)throw new TypeError("At most one of 'raw', 'batched', and 'write' must be passed");if(!n&&!s&&o)throw new TypeError("Cannot set 'isatty' to true unless 'raw' or 'write' is provided");n&&e(new st(n.bind(t),!!o)),a&&e(new lt(a.bind(t))),s&&e(t),ut()}i(Fr,"_setStdwrite");function Qn(){return h?new De(process.stdout.fd):{batched:t=>console.log(t)}}i(Qn,"_getStdoutDefaults");function Xn(){return h?new De(process.stderr.fd):{batched:t=>console.warn(t)}}i(Xn,"_getStderrDefaults");function Rt(t={}){Fr(t,zn,Qn)}i(Rt,"setStdout");function Lt(t={}){Fr(t,Wn,Xn)}i(Lt,"setStderr");var Zn=new TextEncoder,Ar=new TextDecoder,ot=class{read(e){throw new FS.ErrnoError(29)}};i(ot,"ErrorReader");var at=class{constructor(e){this.fd=e,this.isatty=Ir.isatty(e)}read(e){try{return Tt.readSync(this.fd,e)}catch(r){if(r.toString().includes("EOF"))return 0;throw r}}fsync(){kr(this.fd)}};i(at,"NodeReader");var it=class{constructor(e,r,n){this.infunc=e,this.isatty=r,this.autoEOF=n,this.index=0,this.saved=void 0,this.insertEOF=!1}_getInput(){if(this.saved)return this.saved;let e=this.infunc();if(typeof e=="number")return e;if(e!=null){if(ArrayBuffer.isView(e)){if(e.BYTES_PER_ELEMENT!==1)throw console.warn(`Expected BYTES_PER_ELEMENT to be 1, infunc gave ${e.constructor}`),new FS.ErrnoError(29);return e}if(typeof e=="string")return e.endsWith(`\n`)||(e+=`\n`),e;if(Object.prototype.toString.call(e)==="[object ArrayBuffer]")return new Uint8Array(e);throw console.warn("Expected result to be undefined, null, string, array buffer, or array buffer view"),new FS.ErrnoError(29)}}read(e){if(this.insertEOF)return this.insertEOF=!1,0;let r=0;for(;;){let n=this._getInput();if(typeof n=="number"){e[0]=n,e=e.subarray(1),r++;continue}let o;if(n&&n.length>0)if(typeof n=="string"){let{read:a,written:s}=Zn.encodeInto(n,e);this.saved=n.slice(a),r+=s,o=e[s-1],e=e.subarray(s)}else{let a;n.length>e.length?(e.set(n.subarray(0,e.length)),this.saved=n.subarray(e.length),a=e.length):(e.set(n),this.saved=void 0,a=n.length),r+=a,o=e[a-1],e=e.subarray(a)}if(!(n&&n.length>0)||this.autoEOF||e.length===0)return this.insertEOF=r>0&&this.autoEOF&&o!==10,r}}fsync(){}};i(it,"LegacyReader");var st=class{constructor(e,r){this.out=e,this.isatty=r}write(e){for(let r of e)this.out(r);return e.length}};i(st,"CharacterCodeWriter");var lt=class{constructor(e){this.isatty=!1;this.out=e,this.output=[]}write(e){for(let r of e)r===10?(this.out(Ar.decode(new Uint8Array(this.output))),this.output=[]):r!==0&&this.output.push(r);return e.length}fsync(){this.output&&this.output.length>0&&(this.out(Ar.decode(new Uint8Array(this.output))),this.output=[])}};i(lt,"StringWriter");var De=class{constructor(e){this.fd=e,this.isatty=Ir.isatty(e)}write(e){return Tt.writeSync(this.fd,e)}fsync(){kr(this.fd)}};i(De,"NodeWriter");var Ct="sched$"+Math.random().toString(36).slice(2)+"$",Ut={},$t=0;function eo(){if(!Y)return;let t=i(e=>{if(typeof e.data=="string"&&e.data.indexOf(Ct)===0){let r=+e.data.slice(Ct.length),n=Ut[r];if(!n)return;try{n()}finally{delete Ut[r]}}},"onGlobalMessage");globalThis.addEventListener("message",t,!1)}i(eo,"installPostMessageHandler");eo();function to(t){if(h)setImmediate(t);else if(Y&&typeof globalThis.postMessage=="function")Ut[$t]=t,globalThis.postMessage(Ct+$t,"*"),$t++;else if(we&&!kt&&typeof MessageChannel=="function"){let e=new MessageChannel;e.port1.onmessage=()=>t(),e.port2.postMessage("")}else setTimeout(t,0)}i(to,"scheduleCallbackImmediate");function dt(t,e=0){e<=2?to(t):setTimeout(t,e)}i(dt,"scheduleCallback");var{get:ro,getOwnPropertyDescriptor:no,ownKeys:oo}=Reflect,ao=i(t=>({value:t,enumerable:!0,writable:!0,configurable:!0}),"getPropertyDescriptor"),Dr=Symbol(),Or="prototype",io={deleteProperty:(t,e)=>t.has(e)?t.delete(e):delete t[e],get(t,e,r){if(e===Dr)return t;let n=t[e];return typeof n=="function"&&e!=="constructor"&&(n=n.bind(t)),n||(n=t.get(e)),n},getOwnPropertyDescriptor(t,e){if(t.has(e))return ao(t.get(e));if(e in t)return no(t,e)},has:(t,e)=>t.has(e)||e in t,ownKeys:t=>[...t.keys(),...oo(t)].filter(e=>["string","symbol"].includes(typeof e)),set:(t,e,r)=>(t.set(e,r),!0)},so=new Proxy(i(class extends Map{constructor(...e){return new Proxy(super(...e),io)}},"LiteralMap"),{get(t,e,...r){return e!==Or&&e in t[Or]?(n,...o)=>{let a=n[Dr],s=a[e];return typeof s=="function"&&(s=s.apply(a,o)),s===a?n:s}:ro(t,e,...r)}}),Mr=so;var yt=new FinalizationRegistry(t=>void t());function lo(t){let e=new AbortController;for(let l of t)if(l.aborted)return e.abort(l.reason),e.signal;let r=new WeakRef(e),n=[],o=t.length;t.forEach(l=>{let c=new WeakRef(l);function u(){r.deref()?.abort(c.deref()?.reason)}i(u,"abort"),l.addEventListener("abort",u),n.push([c,u]),yt.register(l,()=>!--o&&a(),l)});function a(){n.forEach(([l,c])=>{let u=l.deref();u&&(u.removeEventListener("abort",c),yt.unregister(u));let d=r.deref();d&&(yt.unregister(d.signal),delete d.signal.__controller)})}i(a,"clear");let{signal:s}=e;return yt.register(s,a,s),s.addEventListener("abort",a),s.__controller=e,s}i(lo,"abortSignalAny");var Nr=lo;API.getExpectedKeys=function(){return[null,API.config.jsglobals,API.public_api,API,dt,API,{}]};var Lr=Symbol("getAccessorList");function pt(t,e=[]){return new Proxy(t,{get(r,n,o){if(n===Lr)return e;let a=Reflect.get(...arguments),s=Reflect.getOwnPropertyDescriptor(r,n);return s&&s.writable===!1&&!s.configurable||s&&s.set&&!s.get||!["object","function"].includes(typeof a)?a:pt(a,[...e,n])},getPrototypeOf(){return pt(Reflect.getPrototypeOf(...arguments),[...e,"[getProtoTypeOf]"])}})}i(pt,"makeGlobalsProxy");var $r=1886286592,ft=4+4+4+4+32;function co(t,e){if(e.length!==8)throw new Error("Expected 256 bit buffer");for(let r=0;r<32;r++)e[r]=parseInt(t.slice(r*8,(r+1)*8),16)}i(co,"encodeBuildId");function uo(t){if(t.length!==8)throw new Error("Expected 256 bit buffer");return Array.from(t,e=>e.toString(16).padStart(8,"0")).join("")}i(uo,"decodeBuildId");var Ne=5;function Tr(t,e,r){if(e===r)return;if(typeof r=="function"&&typeof e!="function")throw console.warn(r,e),new Error(`Expected function at index ${t}`);let n=!1;try{n=JSON.stringify(e)===JSON.stringify(r)}catch(o){console.warn(o)}if(!n)throw console.warn(r,e),new Error(`Unexpected hiwire entry at index ${t}`)}i(Tr,"checkEntry");API.serializeHiwireState=function(t,e){e||(e=Tr);let r=[],n=API.getExpectedKeys();for(let s=0;sRr(a,o)),e.hiwireKeys.forEach((o,a)=>{let s;if(!o)s=o;else if("path"in o)s=o.path.reduce((l,c)=>l[c],t)||null;else{if(!r)throw new Error("You must pass an appropriate deserializer as _snapshotDeserializer");s=r(o.serialized)}Rr(n.length+a,s)}),e.immortalKeys.forEach(o=>Module.__hiwire_immortal_add(o))}i(Ur,"syncUpSnapshotLoad2");async function jr(t,e){return new Promise((r,n)=>{t.FS.syncfs(e,o=>{o?n(o):r()})})}i(jr,"syncfs");async function Br(t){return await jr(t,!1)}i(Br,"syncLocalToRemote");async function Hr(t){return await jr(t,!0)}i(Hr,"syncRemoteToLocal");API.loadBinaryFile=Se;API.rawRun=i(function(e){let r=Module.stringToNewUTF8(e);Module.API.capture_stderr();let n=_PyRun_SimpleString(r);_free(r);let o=Module.API.restore_stderr().trim();return[n,o]},"rawRun");API.runPythonInternal=function(t){return API._pyodide._base.eval_code(t,API.runPythonInternal_dict)};API.setPyProxyToStringMethod=function(t){Module.HEAP8[Module._compat_to_string_repr]=+t};API.saveState=()=>API.pyodide_py._state.save_state();API.restoreState=t=>API.pyodide_py._state.restore_state(t);API.scheduleCallback=dt;API.detectEnvironment=yr;AbortSignal.any?API.abortSignalAny=AbortSignal.any:API.abortSignalAny=Nr;API.LiteralMap=Mr;function zr(t){Module.FS.mkdirTree(t);let{node:e}=Module.FS.lookupPath(t,{follow_mount:!1});if(FS.isMountpoint(e))throw new Error(`path '${t}' is already a file system mount point`);if(!FS.isDir(e.mode))throw new Error(`path '${t}' points to a file not a directory`);for(let r in e.contents)throw new Error(`directory '${t}' is not empty`)}i(zr,"ensureMountPathExists");var v=class{static async loadPackagesFromImports(e,r={checkIntegrity:!0}){let n=API.pyodide_code.find_imports(e),o;try{o=n.toJs()}finally{n.destroy()}if(o.length===0)return[];let a=API._import_name_to_package_name,s=new Set;for(let l of o)a.has(l)&&s.add(a.get(l));return s.size?await Oe(Array.from(s),r):[]}static runPython(e,r={}){return r.globals||(r.globals=API.globals),API.pyodide_code.eval_code.callKwargs(e,r)}static async runPythonAsync(e,r={}){return r.globals||(r.globals=API.globals),await API.pyodide_code.eval_code_async.callKwargs(e,r)}static registerJsModule(e,r){API.pyodide_ffi.register_js_module(e,r)}static unregisterJsModule(e){API.pyodide_ffi.unregister_js_module(e)}static toPy(e,{depth:r,defaultConverter:n}={depth:-1}){switch(typeof e){case"string":case"number":case"boolean":case"bigint":case"undefined":return e}if(!e||API.isPyProxy(e))return e;let o=0,a=0;try{o=Module.js2python_convert(e,{depth:r,defaultConverter:n})}catch(s){throw s instanceof Module._PropagatePythonError&&_pythonexc2js(),s}try{if(_JsProxy_Check(o))return e;a=_python2js(o),a===null&&_pythonexc2js()}finally{_Py_DecRef(o)}return a}static pyimport(e){return API.pyodide_base.pyimport_impl(e)}static unpackArchive(e,r,n={}){if(!ArrayBuffer.isView(e)&&API.getTypeTag(e)!=="[object ArrayBuffer]")throw new TypeError("Expected argument 'buffer' to be an ArrayBuffer or an ArrayBuffer view");API.typedArrayAsUint8Array(e);let o=n.extractDir;API.package_loader.unpack_buffer.callKwargs({buffer:e,format:r,extract_dir:o,installer:"pyodide.unpackArchive"})}static async mountNativeFS(e,r){if(r.constructor.name!=="FileSystemDirectoryHandle")throw new TypeError("Expected argument 'fileSystemHandle' to be a FileSystemDirectoryHandle");return zr(e),Module.FS.mount(Module.FS.filesystems.NATIVEFS_ASYNC,{fileSystemHandle:r},e),await Hr(Module),{syncfs:async()=>await Br(Module)}}static mountNodeFS(e,r){if(!h)throw new Error("mountNodeFS only works in Node");zr(e);let n;try{n=tt.lstatSync(r)}catch{throw new Error(`hostPath '${r}' does not exist`)}if(!n.isDirectory())throw new Error(`hostPath '${r}' is not a directory`);Module.FS.mount(Module.FS.filesystems.NODEFS,{root:r},e)}static registerComlink(e){API._Comlink=e}static setInterruptBuffer(e){Module.HEAP8[Module._Py_EMSCRIPTEN_SIGNAL_HANDLING]=+!!e,Module.Py_EmscriptenSignalBuffer=e}static checkInterrupt(){if(_PyGILState_Check()){__PyErr_CheckSignals()&&_pythonexc2js();return}else{let e=Module.Py_EmscriptenSignalBuffer;if(e&&e[0]===2)throw new Module.FS.ErrnoError(27)}}static setDebug(e){let r=!!API.debug_ffi;return API.debug_ffi=e,r}static makeMemorySnapshot({serializer:e}={}){if(!API.config._makeSnapshot)throw new Error("Can only use pyodide.makeMemorySnapshot if the _makeSnapshot option is passed to loadPyodide");return API.makeSnapshot(e)}};i(v,"PyodideAPI"),v.version=xr,v.loadPackage=Oe,v.loadedPackages=ke,v.ffi=ir,v.setStdin=Me,v.setStdout=Rt,v.setStderr=Lt,v.globals={},v.FS={},v.PATH={},v.canvas=cr,v.ERRNO_CODES={},v.pyodide_py={};function yo(){let t=Object.getOwnPropertyDescriptors(v);delete t.prototype;let e=Object.create({},t);return API.public_api=e,e.FS=Module.FS,e.PATH=Module.PATH,e.ERRNO_CODES=Module.ERRNO_CODES,e._module=Module,e._api=API,e}i(yo,"makePublicAPI");function po(t,e){return new Proxy(t,{get(r,n){return n==="get"?o=>{let a=r.get(o);return a===void 0&&(a=e.get(o)),a}:n==="has"?o=>r.has(o)||e.has(o):Reflect.get(r,n)}})}i(po,"wrapPythonGlobals");var Wr;API.bootstrapFinalizedPromise=new Promise(t=>Wr=t);API.finalizeBootstrap=function(t,e){t&&Cr();let[r,n]=API.rawRun("import _pyodide_core");r&&API.fatal_loading_error(`Failed to import _pyodide_core\n`,n),API.runPythonInternal_dict=API._pyodide._base.eval_code("{}"),API.importlib=API.runPythonInternal("import importlib; importlib");let o=API.importlib.import_module;API.sys=o("sys"),API.os=o("os");let a=API.runPythonInternal("import __main__; __main__.__dict__"),s=API.runPythonInternal("import builtins; builtins.__dict__");API.globals=po(a,s);let l=API._pyodide._importhook,c=yo();API.config._makeSnapshot&&(API.config.jsglobals=pt(API.config.jsglobals));let u=API.config.jsglobals;return t?Ur(u,t,e):(l.register_js_finder(),l.register_js_module("js",u),l.register_js_module("pyodide_js",c)),API.pyodide_py=o("pyodide"),API.pyodide_code=o("pyodide.code"),API.pyodide_ffi=o("pyodide.ffi"),API.package_loader=o("pyodide._package_loader"),API.pyodide_base=o("_pyodide._base"),API.sitepackages=API.package_loader.SITE_PACKAGES.__str__(),API.dsodir=API.package_loader.DSO_DIR.__str__(),API.defaultLdLibraryPath=[API.dsodir,API.sitepackages],API.os.environ.__setitem__("LD_LIBRARY_PATH",API.defaultLdLibraryPath.join(":")),c.pyodide_py=API.pyodide_py,c.globals=API.globals,Wr(),c}})()}var StackSwitching=(()=>{var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var stack_switching_exports={};__export(stack_switching_exports,{StackState:()=>StackState,createPromising:()=>createPromising,jsWrapperTag:()=>jsWrapperTag,jspiSupported:()=>jspiSupported,newJspiSupported:()=>newJspiSupported,oldJspiSupported:()=>oldJspiSupported,promisingApply:()=>promisingApply,suspenderGlobal:()=>suspenderGlobal,validSuspender:()=>validSuspender});var WASM_PRELUDE=[0,97,115,109,1,0,0,0];function insertSectionPrefix(sectionCode,sectionBody){var section=[sectionCode];uleb128Encode(sectionBody.length,section);section.push(...sectionBody);return section}var typeCodes={i32:127,i64:126,f32:125,f64:124,externref:111,void:64};var constCodes={i32:65,i64:66,f32:67,f64:68};function emscriptenSigToWasm(sig){const lookup={i:"i32",j:"i64",f:"f32",d:"f64",e:"externref",v:""};const parameters=sig.split("").map(x=>lookup[x]);const result=parameters.shift();const results=result?[result]:[];return{parameters:parameters,results:results}}var TypeSection=class{constructor(){this._numTypes=0;this._section=[0]}addEmscripten(sig){return this.addWasm(emscriptenSigToWasm(sig))}addWasm({parameters:parameters,results:results}){this._section.push(96);uleb128Encode(parameters.length,this._section);for(let p of parameters){this._section.push(typeCodes[p])}uleb128Encode(results.length,this._section);for(let p of results){this._section.push(typeCodes[p])}return this._numTypes++}generate(){this._section[0]=this._numTypes;return insertSectionPrefix(1,this._section)}};function encodeStr(s){const buf=(new TextEncoder).encode(s);return[buf.length,...buf]}var ImportSection=class{constructor(){this._numImports=0;this.numGlobals=0;this.numFuncs=0;this._section=[0]}_addName(name){this._section.push(...ImportSection._module);this._section.push(...encodeStr(name))}addFunction(name,sig){this._addName(name);this._section.push(ImportSection.descr.func,sig);this._numImports++;return this.numFuncs++}addTable(name){this._addName(name);this._section.push(ImportSection.descr.table,112,0,0);this._numImports++}addGlobal(name,type){this._addName(name);this._section.push(ImportSection.descr.global,typeCodes[type],1);this._numImports++;return this.numGlobals++}addTag(name,sig){this._addName(name);this._section.push(ImportSection.descr.tag,0,sig);this._numImports++}generate(){this._section[0]=this._numImports;return insertSectionPrefix(2,this._section)}};ImportSection._module=encodeStr("e");ImportSection.descr={func:0,table:1,mem:2,global:3,tag:4};var CodeSection=class{constructor(...locals){this._section=[];this.add(locals.length);for(let l of locals){this.add(1,typeCodes[l])}}add(...args){this._section.push(...args)}local_get(idx){this.add(32,idx)}local_set(idx){this.add(33,idx)}local_tee(idx){this.add(34,idx)}global_get(idx){this.add(35,idx)}global_set(idx){this.add(36,idx)}call(func){this.add(16,func)}call_indirect(func){this.add(17,func,0)}const(type,...val){this.add(constCodes[type],...val)}end(){this.add(11)}generate(){this.end();return insertSectionPrefix(10,insertSectionPrefix(1,this._section))}};var WasmModule=class{constructor(){this._sections=[WASM_PRELUDE]}addSection(section){this._sections.push(section.generate())}addSectionBody(sectionCode,sectionBody){this._sections.push(insertSectionPrefix(sectionCode,sectionBody))}addImportSection(imports){this.addSection(imports);this._numImportFuncs=imports.numFuncs}setExportType(type){const functionSection=[1,type];this.addSectionBody(3,functionSection);const exportSection=[1,...encodeStr("o"),0,this._numImportFuncs];this.addSectionBody(7,exportSection)}generate(){const bytes=new Uint8Array(this._sections.flat());return new WebAssembly.Module(bytes)}};function createInvokeModule(sig){const mod=new WasmModule;const types=new TypeSection;const invoke_sig=emscriptenSigToWasm(sig);const export_sig=structuredClone(invoke_sig);export_sig.parameters.unshift("i32");const invoke_tidx=types.addWasm(invoke_sig);const export_tidx=types.addWasm(export_sig);const try_tidx=typeCodes[invoke_sig.results[0]||"void"];const tag_tidx=types.addEmscripten("ve");const save_tidx=types.addEmscripten("i");const restore_tidx=types.addEmscripten("vi");const setThrew_tidx=types.addEmscripten("vii");mod.addSection(types);const imports=new ImportSection;imports.addTable("t");imports.addTag("tag",tag_tidx);const save_stack_func=imports.addFunction("s",save_tidx);const restore_stack_func=imports.addFunction("r",restore_tidx);const set_threw_func=imports.addFunction("q",setThrew_tidx);mod.addImportSection(imports);mod.setExportType(export_tidx);const code=new CodeSection(["i32"]);const stackLocal=export_sig.parameters.length;code.call(save_stack_func);code.local_set(stackLocal);code.add(6,try_tidx);for(let i=1;inew WebAssembly.Exception(jsWrapperTag,[e]);function createInvoke(sig){if(!jsWrapperTag){return createInvokeFunction(sig)}const module=createInvokeModule(sig);const instance=new WebAssembly.Instance(module,{e:{t:wasmTable,s:()=>stackSave(),r:x=>stackRestore(x),q:(x,y)=>_setThrew(x,y),tag:jsWrapperTag}});return instance.exports["o"]}function adjustWasmImports(wasmImports){const i="invoke_";for(let name of Object.keys(wasmImports.env)){if(!name.startsWith(i)){continue}wasmImports.env[name]=createInvoke(name.slice(i.length))}}var suspenderGlobal={value:null};var validSuspender={value:false};var promisingApplyHandler;function promisingApply(...args){validSuspender.value=true;Module.stackStop=stackSave();Module.origCframe=_get_cframe();return promisingApplyHandler(...args)}function createPromising(wasm_func){if(Module.newJspiSupported){const promisingFunc=WebAssembly.promising(wasm_func);async function wrapper(...args){const orig=validSuspender.value;validSuspender.value=true;try{return await promisingFunc(null,...args)}finally{validSuspender.value=orig}}return wrapper}const{parameters:parameters}=wasmFunctionType(wasm_func);parameters.shift();return new WebAssembly.Function({parameters:parameters,results:["externref"]},wasm_func,{promising:"first"})}function initSuspenders(){promisingApplyHandler=createPromising(wasmExports._pyproxy_apply_promising)}var stackStates=[];var StackState=class{constructor(){this.start=stackSave();this.stop=Module.stackStop;this._copy=new Uint8Array(0);if(this.start!==this.stop){stackStates.push(this)}}restore(){let total=0;while(stackStates.length>0&&stackStates[stackStates.length-1].stop>>0,this.start+sz2>>>0);const c=new Uint8Array(sz2);c.set(this._copy);c.set(new_segment,sz1);this._copy=c;return sz2}_save(){return this._save_up_to(this.stop)}};var canConstructWasm=true;try{new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0]))}catch(e){canConstructWasm=false}var newJspiSupported=canConstructWasm&&"Suspending"in WebAssembly;var oldJspiSupported=canConstructWasm&&"Suspender"in WebAssembly;var jspiSupported=newJspiSupported||oldJspiSupported;Module.newJspiSupported=newJspiSupported;Module.oldJspiSupported=oldJspiSupported;Module.jspiSupported=jspiSupported;if(jspiSupported){Module.preRun.push(initSuspenders);Module.adjustWasmImports=adjustWasmImports;Module.wrapException=wrapException;Module.createInvoke=createInvoke}return __toCommonJS(stack_switching_exports)})();const{StackState:StackState,createPromising:createPromising,jsWrapperTag:jsWrapperTag,jspiSupported:jspiSupported,newJspiSupported:newJspiSupported,oldJspiSupported:oldJspiSupported,promisingApply:promisingApply,suspenderGlobal:suspenderGlobal,validSuspender:validSuspender}=StackSwitching;Object.assign(Module,StackSwitching);const API=Module.API;const Hiwire={};const Tests={};API.tests=Tests;API.version="0.27.5";Module.hiwire=Hiwire;function getTypeTag(x){try{return Object.prototype.toString.call(x)}catch(e){return""}}API.getTypeTag=getTypeTag;function hasProperty(obj,prop){try{while(obj){if(Object.getOwnPropertyDescriptor(obj,prop)){return true}obj=Object.getPrototypeOf(obj)}}catch(e){}return false}function hasMethod(obj,prop){try{return typeof obj[prop]==="function"}catch(e){return false}}const pyproxyIsAlive=px=>!!Module.PyProxy_getAttrsQuiet(px).shared.ptr;API.pyproxyIsAlive=pyproxyIsAlive;const errNoRet=()=>{throw new Error("Assertion error: control reached end of function without return")};Module.reportUndefinedSymbols=()=>{};const nullToUndefined=x=>x===null?undefined:x;function isPromise(obj){try{return!!obj&&typeof obj.then==="function"}catch(e){return false}}API.isPromise=isPromise;function bufferAsUint8Array(arg){if(ArrayBuffer.isView(arg)){return new Uint8Array(arg.buffer,arg.byteOffset,arg.byteLength)}else{return new Uint8Array(arg)}}API.typedArrayAsUint8Array=bufferAsUint8Array;Module.iterObject=function*(object){for(let k in object){if(Object.prototype.hasOwnProperty.call(object,k)){yield k}}};function wasmFunctionType(wasm_func){if(!WebAssembly.Function){throw new Error("No type reflection")}if(WebAssembly.Function.type){return WebAssembly.Function.type(wasm_func)}return wasm_func.type()}pyodide_js_init();pyodide_js_init.sig="v";function set_suspender(suspender){suspenderGlobal.value=suspender}set_suspender.sig="ve";function get_suspender(){return suspenderGlobal.value}get_suspender.sig="e";function syncifyHandler(x,y){return null}async function inner(x,y){try{return nullToUndefined(await(x??y))}catch(e){if(e&&e.pyodide_fatal_error){throw e}Module.syncify_error=e;return null}}if(newJspiSupported){syncifyHandler=new WebAssembly.Suspending(inner)}else if(oldJspiSupported){syncifyHandler=new WebAssembly.Function({parameters:["externref","externref"],results:["externref"]},inner,{suspending:"first"})}syncifyHandler.sig="eee";function JsvPromise_Syncify_handleError(){if(!Module.syncify_error){return}Module.handle_js_error(Module.syncify_error);delete Module.syncify_error}JsvPromise_Syncify_handleError.sig="v";function saveState(){if(!validSuspender.value){return null}const stackState=new StackState;const threadState=_captureThreadState();const origCframe=Module.origCframe;_restore_cframe(origCframe);return{threadState:threadState,stackState:stackState,suspender:suspenderGlobal.value,origCframe:origCframe}}saveState.sig="e";function restoreState(state){state.stackState.restore();Module.origCframe=state.origCframe;_restoreThreadState(state.threadState);suspenderGlobal.value=state.suspender;validSuspender.value=true}restoreState.sig="ve";function _PyImport_InitFunc_TrampolineCall(func){return wasmTable.get(func)()}_PyImport_InitFunc_TrampolineCall.sig="ii";function _Py_emscripten_runtime(){var info;if(typeof navigator=="object"){info=navigator.userAgent}else if(typeof process=="object"){info="Node.js ".concat(process.version)}else{info="UNKNOWN"}var len=lengthBytesUTF8(info)+1;var res=_malloc(len);if(res)stringToUTF8(info,res,len);return res}_Py_emscripten_runtime.sig="i";function _Py_CheckEmscriptenSignals_Helper(){if(!Module.Py_EmscriptenSignalBuffer){return 0}try{let result=Module.Py_EmscriptenSignalBuffer[0];Module.Py_EmscriptenSignalBuffer[0]=0;return result}catch(e){return 0}}_Py_CheckEmscriptenSignals_Helper.sig="i";function _PyEM_GetCountArgsPtr(){return Module._PyEM_CountArgsPtr}function getPyEMCountArgsPtr(){let isIOS=globalThis.navigator&&/iPad|iPhone|iPod/.test(navigator.platform);if(isIOS){return 0}const code=new Uint8Array([0,97,115,109,1,0,0,0,1,27,5,96,0,1,127,96,1,127,1,127,96,2,127,127,1,127,96,3,127,127,127,1,127,96,1,127,0,2,9,1,1,101,1,116,1,112,0,0,3,2,1,1,7,5,1,1,102,0,0,10,68,1,66,1,1,112,32,0,37,0,34,1,251,20,3,2,4,69,13,0,65,3,15,11,32,1,251,20,2,2,4,69,13,0,65,2,15,11,32,1,251,20,1,2,4,69,13,0,65,1,15,11,32,1,251,20,0,2,4,69,13,0,65,0,15,11,65,127,11]);try{const mod=new WebAssembly.Module(code);const inst=new WebAssembly.Instance(mod,{e:{t:wasmTable}});return addFunction(inst.exports.f)}catch(e){return 0}}addOnPreRun(()=>{const ptr=getPyEMCountArgsPtr();Module._PyEM_CountArgsPtr=ptr;const offset=HEAP32[__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET/4>>>0];HEAP32[(__PyRuntime+offset)/4>>>0]=ptr});_PyEM_GetCountArgsPtr.sig="i";function _PyEM_TrampolineCall_JS(func,arg1,arg2,arg3){return wasmTable.get(func)(arg1,arg2,arg3)}_PyEM_TrampolineCall_JS.sig="iiiii";function unbox_small_structs(type_ptr){var type_id=HEAPU16[(type_ptr+6>>1)+0>>>0];while(type_id===13){var elements=HEAPU32[(type_ptr+8>>2)+0>>>0];var first_element=HEAPU32[(elements>>2)+0>>>0];if(first_element===0){type_id=0;break}else if(HEAPU32[(elements>>2)+1>>>0]===0){type_ptr=first_element;type_id=HEAPU16[(first_element+6>>1)+0>>>0]}else{break}}return[type_ptr,type_id]}function ffi_call_js(cif,fn,rvalue,avalue){var abi=HEAPU32[(cif>>2)+0>>>0];var nargs=HEAPU32[(cif>>2)+1>>>0];var nfixedargs=HEAPU32[(cif>>2)+6>>>0];var arg_types_ptr=HEAPU32[(cif>>2)+2>>>0];var rtype_unboxed=unbox_small_structs(HEAPU32[(cif>>2)+3>>>0]);var rtype_ptr=rtype_unboxed[0];var rtype_id=rtype_unboxed[1];var orig_stack_ptr=stackSave();var cur_stack_ptr=orig_stack_ptr;var args=[];var ret_by_arg=false;if(rtype_id===15){throw new Error("complex ret marshalling nyi")}if(rtype_id<0||rtype_id>15){throw new Error("Unexpected rtype "+rtype_id)}if(rtype_id===4||rtype_id===13){args.push(rvalue);ret_by_arg=true}for(var i=0;i>2)+i>>>0];var arg_unboxed=unbox_small_structs(HEAPU32[(arg_types_ptr>>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];switch(arg_type_id){case 1:case 10:case 9:case 14:args.push(HEAPU32[(arg_ptr>>2)+0>>>0]);break;case 2:args.push(HEAPF32[(arg_ptr>>2)+0>>>0]);break;case 3:args.push(HEAPF64[(arg_ptr>>3)+0>>>0]);break;case 5:args.push(HEAPU8[arg_ptr+0>>>0]);break;case 6:args.push(HEAP8[arg_ptr+0>>>0]);break;case 7:args.push(HEAPU16[(arg_ptr>>1)+0>>>0]);break;case 8:args.push(HEAP16[(arg_ptr>>1)+0>>>0]);break;case 11:case 12:args.push(HEAPU64[(arg_ptr>>3)+0]);break;case 4:args.push(HEAPU64[(arg_ptr>>3)+0]);args.push(HEAPU64[(arg_ptr>>3)+1]);break;case 13:var size=HEAPU32[(arg_type_ptr>>2)+0>>>0];var align=HEAPU16[(arg_type_ptr+4>>1)+0>>>0];cur_stack_ptr-=size,cur_stack_ptr&=~(align-1);HEAP8.subarray(cur_stack_ptr>>>0,cur_stack_ptr+size>>>0).set(HEAP8.subarray(arg_ptr>>>0,arg_ptr+size>>>0));args.push(cur_stack_ptr);break;case 15:throw new Error("complex marshalling nyi");default:throw new Error("Unexpected type "+arg_type_id)}}if(nfixedargs!=nargs){var struct_arg_info=[];for(var i=nargs-1;i>=nfixedargs;i--){var arg_ptr=HEAPU32[(avalue>>2)+i>>>0];var arg_unboxed=unbox_small_structs(HEAPU32[(arg_types_ptr>>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];switch(arg_type_id){case 5:case 6:cur_stack_ptr-=1,cur_stack_ptr&=~(1-1);HEAPU8[cur_stack_ptr+0>>>0]=HEAPU8[arg_ptr+0>>>0];break;case 7:case 8:cur_stack_ptr-=2,cur_stack_ptr&=~(2-1);HEAPU16[(cur_stack_ptr>>1)+0>>>0]=HEAPU16[(arg_ptr>>1)+0>>>0];break;case 1:case 9:case 10:case 14:case 2:cur_stack_ptr-=4,cur_stack_ptr&=~(4-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];break;case 3:case 11:case 12:cur_stack_ptr-=8,cur_stack_ptr&=~(8-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];HEAPU32[(cur_stack_ptr>>2)+1>>>0]=HEAPU32[(arg_ptr>>2)+1>>>0];break;case 4:cur_stack_ptr-=16,cur_stack_ptr&=~(8-1);HEAPU32[(cur_stack_ptr>>2)+0>>>0]=HEAPU32[(arg_ptr>>2)+0>>>0];HEAPU32[(cur_stack_ptr>>2)+1>>>0]=HEAPU32[(arg_ptr>>2)+1>>>0];HEAPU32[(cur_stack_ptr>>2)+2>>>0]=HEAPU32[(arg_ptr>>2)+2>>>0];HEAPU32[(cur_stack_ptr>>2)+3>>>0]=HEAPU32[(arg_ptr>>2)+3>>>0];break;case 13:cur_stack_ptr-=4,cur_stack_ptr&=~(4-1);struct_arg_info.push([cur_stack_ptr,arg_ptr,HEAPU32[(arg_type_ptr>>2)+0>>>0],HEAPU16[(arg_type_ptr+4>>1)+0>>>0]]);break;case 15:throw new Error("complex arg marshalling nyi");default:throw new Error("Unexpected argtype "+arg_type_id)}}args.push(cur_stack_ptr);for(var i=0;i>>0,cur_stack_ptr+size>>>0).set(HEAP8.subarray(arg_ptr>>>0,arg_ptr+size>>>0));HEAPU32[(arg_target>>2)+0>>>0]=cur_stack_ptr}}stackRestore(cur_stack_ptr);stackAlloc(0);var result=(0,getWasmTableEntry(fn).apply(null,args));stackRestore(orig_stack_ptr);if(ret_by_arg){return}switch(rtype_id){case 0:break;case 1:case 9:case 10:case 14:HEAPU32[(rvalue>>2)+0>>>0]=result;break;case 2:HEAPF32[(rvalue>>2)+0>>>0]=result;break;case 3:HEAPF64[(rvalue>>3)+0>>>0]=result;break;case 5:case 6:HEAPU8[rvalue+0>>>0]=result;break;case 7:case 8:HEAPU16[(rvalue>>1)+0>>>0]=result;break;case 11:case 12:HEAPU64[(rvalue>>3)+0]=result;break;case 15:throw new Error("complex ret marshalling nyi");default:throw new Error("Unexpected rtype "+rtype_id)}}ffi_call_js.sig="viiii";function ffi_closure_alloc_js(size,code){var closure=_malloc(size);var index=getEmptyTableSlot();HEAPU32[(code>>2)+0>>>0]=index;HEAPU32[(closure>>2)+0>>>0]=index;return closure}ffi_closure_alloc_js.sig="iii";function ffi_closure_free_js(closure){var index=HEAPU32[(closure>>2)+0>>>0];freeTableIndexes.push(index);_free(closure)}ffi_closure_free_js.sig="vi";function ffi_prep_closure_loc_js(closure,cif,fun,user_data,codeloc){var abi=HEAPU32[(cif>>2)+0>>>0];var nargs=HEAPU32[(cif>>2)+1>>>0];var nfixedargs=HEAPU32[(cif>>2)+6>>>0];var arg_types_ptr=HEAPU32[(cif>>2)+2>>>0];var rtype_unboxed=unbox_small_structs(HEAPU32[(cif>>2)+3>>>0]);var rtype_ptr=rtype_unboxed[0];var rtype_id=rtype_unboxed[1];var sig;var ret_by_arg=false;switch(rtype_id){case 0:sig="v";break;case 13:case 4:sig="vi";ret_by_arg=true;break;case 1:case 5:case 6:case 7:case 8:case 9:case 10:case 14:sig="i";break;case 2:sig="f";break;case 3:sig="d";break;case 11:case 12:sig="j";break;case 15:throw new Error("complex ret marshalling nyi");default:throw new Error("Unexpected rtype "+rtype_id)}var unboxed_arg_type_id_list=[];var unboxed_arg_type_info_list=[];for(var i=0;i>2)+i>>>0]);var arg_type_ptr=arg_unboxed[0];var arg_type_id=arg_unboxed[1];unboxed_arg_type_id_list.push(arg_type_id);unboxed_arg_type_info_list.push([HEAPU32[(arg_type_ptr>>2)+0>>>0],HEAPU16[(arg_type_ptr+4>>1)+0>>>0]])}for(var i=0;i>2)+carg_idx>>>0]=cur_ptr;HEAPU8[cur_ptr+0>>>0]=cur_arg;break;case 7:case 8:cur_ptr-=2,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU16[(cur_ptr>>1)+0>>>0]=cur_arg;break;case 1:case 9:case 10:case 14:cur_ptr-=4,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU32[(cur_ptr>>2)+0>>>0]=cur_arg;break;case 13:cur_ptr-=arg_size,cur_ptr&=~(arg_align-1);HEAP8.subarray(cur_ptr>>>0,cur_ptr+arg_size>>>0).set(HEAP8.subarray(cur_arg>>>0,cur_arg+arg_size>>>0));HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;break;case 2:cur_ptr-=4,cur_ptr&=~(4-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPF32[(cur_ptr>>2)+0>>>0]=cur_arg;break;case 3:cur_ptr-=8,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPF64[(cur_ptr>>3)+0>>>0]=cur_arg;break;case 11:case 12:cur_ptr-=8,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU64[(cur_ptr>>3)+0]=cur_arg;break;case 4:cur_ptr-=16,cur_ptr&=~(8-1);HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr;HEAPU64[(cur_ptr>>3)+0]=cur_arg;cur_arg=args[jsarg_idx++];HEAPU64[(cur_ptr>>3)+1]=cur_arg;break}}var varargs=args[args.length-1];for(;carg_idx>2)+0>>>0];cur_ptr-=arg_size,cur_ptr&=~(arg_align-1);HEAP8.subarray(cur_ptr>>>0,cur_ptr+arg_size>>>0).set(HEAP8.subarray(struct_ptr>>>0,struct_ptr+arg_size>>>0));HEAPU32[(args_ptr>>2)+carg_idx>>>0]=cur_ptr}else{HEAPU32[(args_ptr>>2)+carg_idx>>>0]=varargs}varargs+=4}stackRestore(cur_ptr);stackAlloc(0);0;getWasmTableEntry(HEAPU32[(closure>>2)+2>>>0])(HEAPU32[(closure>>2)+1>>>0],ret_ptr,args_ptr,HEAPU32[(closure>>2)+3>>>0]);stackRestore(orig_stack_ptr);if(!ret_by_arg){switch(sig[0]){case"i":return HEAPU32[(ret_ptr>>2)+0>>>0];case"j":return HEAPU64[(ret_ptr>>3)+0];case"d":return HEAPF64[(ret_ptr>>3)+0>>>0];case"f":return HEAPF32[(ret_ptr>>2)+0>>>0]}}}try{var wasm_trampoline=convertJsFunctionToWasm(trampoline,sig)}catch(e){return 1}setWasmTableEntry(codeloc,wasm_trampoline);HEAPU32[(closure>>2)+1>>>0]=cif;HEAPU32[(closure>>2)+2>>>0]=fun;HEAPU32[(closure>>2)+3>>>0]=user_data;return 0}ffi_prep_closure_loc_js.sig="iiiiii";function __hiwire_deduplicate_new(){return new Map}__hiwire_deduplicate_new.sig="e";function __hiwire_deduplicate_get(map,value){return map.get(value)}__hiwire_deduplicate_get.sig="iee";function __hiwire_deduplicate_set(map,value,ref){map.set(value,ref)}__hiwire_deduplicate_set.sig="veei";function __hiwire_deduplicate_delete(map,value){map.delete(value)}__hiwire_deduplicate_delete.sig="vee";function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}Module["ExitStatus"]=ExitStatus;var GOT={};Module["GOT"]=GOT;var currentModuleWeakSymbols=new Set([]);Module["currentModuleWeakSymbols"]=currentModuleWeakSymbols;var GOTHandler={get(obj,symName){var rtn=GOT[symName];if(!rtn){rtn=GOT[symName]=new WebAssembly.Global({"value":"i32","mutable":true})}if(!currentModuleWeakSymbols.has(symName)){rtn.required=true}return rtn}};Module["GOTHandler"]=GOTHandler;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};Module["callRuntimeCallbacks"]=callRuntimeCallbacks;var decrementExceptionRefcount=ptr=>___cxa_decrement_exception_refcount(ptr);Module["decrementExceptionRefcount"]=decrementExceptionRefcount;var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;Module["UTF8Decoder"]=UTF8Decoder;var UTF8ArrayToString=(heapOrArray,idx,maxBytesToRead)=>{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};Module["UTF8ArrayToString"]=UTF8ArrayToString;var getDylinkMetadata=binary=>{var offset=0;var end=0;function getU8(){return binary[offset++]}function getLEB(){var ret=0;var mul=1;while(1){var byte=binary[offset++];ret+=(byte&127)*mul;mul*=128;if(!(byte&128))break}return ret}function getString(){var len=getLEB();offset+=len;return UTF8ArrayToString(binary,offset-len,len)}function failIf(condition,message){if(condition)throw new Error(message)}var name="dylink.0";if(binary instanceof WebAssembly.Module){var dylinkSection=WebAssembly.Module.customSections(binary,name);if(dylinkSection.length===0){name="dylink";dylinkSection=WebAssembly.Module.customSections(binary,name)}failIf(dylinkSection.length===0,"need dylink section");binary=new Uint8Array(dylinkSection[0]);end=binary.length}else{var int32View=new Uint32Array(new Uint8Array(binary.subarray(0,24)).buffer);var magicNumberFound=int32View[0]==1836278016;failIf(!magicNumberFound,"need to see wasm magic number");failIf(binary[8]!==0,"need the dylink section to be first");offset=9;var section_size=getLEB();end=offset+section_size;name=getString()}var customSection={neededDynlibs:[],tlsExports:new Set,weakImports:new Set};if(name=="dylink"){customSection.memorySize=getLEB();customSection.memoryAlign=getLEB();customSection.tableSize=getLEB();customSection.tableAlign=getLEB();var neededDynlibsCount=getLEB();for(var i=0;i_emscripten_stack_get_current();Module["stackSave"]=stackSave;var stackRestore=val=>__emscripten_stack_restore(val);Module["stackRestore"]=stackRestore;var stackAlloc=sz=>__emscripten_stack_alloc(sz);Module["stackAlloc"]=stackAlloc;var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};Module["UTF8ToString"]=UTF8ToString;var getExceptionMessageCommon=ptr=>{var sp=stackSave();var type_addr_addr=stackAlloc(4);var message_addr_addr=stackAlloc(4);___get_exception_message(ptr,type_addr_addr,message_addr_addr);var type_addr=HEAPU32[type_addr_addr>>>2>>>0];var message_addr=HEAPU32[message_addr_addr>>>2>>>0];var type=UTF8ToString(type_addr);_free(type_addr);var message;if(message_addr){message=UTF8ToString(message_addr);_free(message_addr)}stackRestore(sp);return[type,message]};Module["getExceptionMessageCommon"]=getExceptionMessageCommon;var getExceptionMessage=ptr=>getExceptionMessageCommon(ptr);Module["getExceptionMessage"]=getExceptionMessage;function getValue(ptr,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":return HEAP8[ptr>>>0];case"i8":return HEAP8[ptr>>>0];case"i16":return HEAP16[ptr>>>1>>>0];case"i32":return HEAP32[ptr>>>2>>>0];case"i64":return HEAP64[ptr>>>3];case"float":return HEAPF32[ptr>>>2>>>0];case"double":return HEAPF64[ptr>>>3>>>0];case"*":return HEAPU32[ptr>>>2>>>0];default:abort(`invalid type for getValue: ${type}`)}}Module["getValue"]=getValue;var incrementExceptionRefcount=ptr=>___cxa_increment_exception_refcount(ptr);Module["incrementExceptionRefcount"]=incrementExceptionRefcount;var newDSO=(name,handle,syms)=>{var dso={refcount:Infinity,name:name,exports:syms,global:true};LDSO.loadedLibsByName[name]=dso;if(handle!=undefined){LDSO.loadedLibsByHandle[handle]=dso}return dso};Module["newDSO"]=newDSO;var LDSO={loadedLibsByName:{},loadedLibsByHandle:{},init(){newDSO("__main__",0,wasmImports)}};Module["LDSO"]=LDSO;var ___heap_base=9882224;Module["___heap_base"]=___heap_base;var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size);return address};Module["zeroMemory"]=zeroMemory;var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;Module["alignMemory"]=alignMemory;var getMemory=size=>{if(runtimeInitialized){return zeroMemory(_malloc(size),size)}var ret=___heap_base;var end=ret+alignMemory(size,16);___heap_base=end;GOT["__heap_base"].value=end;return ret};Module["getMemory"]=getMemory;var isInternalSym=symName=>["__cpp_exception","__c_longjmp","__wasm_apply_data_relocs","__dso_handle","__tls_size","__tls_align","__set_stack_limits","_emscripten_tls_init","__wasm_init_tls","__wasm_call_ctors","__start_em_asm","__stop_em_asm","__start_em_js","__stop_em_js"].includes(symName)||symName.startsWith("__em_js__");Module["isInternalSym"]=isInternalSym;var uleb128Encode=(n,target)=>{if(n<128){target.push(n)}else{target.push(n%128|128,n>>7)}};Module["uleb128Encode"]=uleb128Encode;var sigToWasmTypes=sig=>{var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64","e":"externref","p":"i32"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i{var sigRet=sig.slice(0,1);var sigParam=sig.slice(1);var typeCodes={"i":127,"p":127,"j":126,"f":125,"d":124,"e":111};target.push(96);uleb128Encode(sigParam.length,target);for(var i=0;i{if(typeof WebAssembly.Function=="function"){return new WebAssembly.Function(sigToWasmTypes(sig),func)}var typeSectionBody=[1];generateFuncType(sig,typeSectionBody);var bytes=[0,97,115,109,1,0,0,0,1];uleb128Encode(typeSectionBody.length,bytes);bytes.push(...typeSectionBody);bytes.push(2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0);var module=new WebAssembly.Module(new Uint8Array(bytes));var instance=new WebAssembly.Instance(module,{"e":{"f":func}});var wrappedFunc=instance.exports["f"];return wrappedFunc};Module["convertJsFunctionToWasm"]=convertJsFunctionToWasm;var wasmTableMirror=[];Module["wasmTableMirror"]=wasmTableMirror;var wasmTable=new WebAssembly.Table({"initial":6648,"element":"anyfunc"});Module["wasmTable"]=wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};Module["getWasmTableEntry"]=getWasmTableEntry;var updateTableMap=(offset,count)=>{if(functionsInTableMap){for(var i=offset;i{if(!functionsInTableMap){functionsInTableMap=new WeakMap;updateTableMap(0,wasmTable.length)}return functionsInTableMap.get(func)||0};Module["getFunctionAddress"]=getFunctionAddress;var freeTableIndexes=[];Module["freeTableIndexes"]=freeTableIndexes;var getEmptyTableSlot=()=>{if(freeTableIndexes.length){return freeTableIndexes.pop()}try{wasmTable.grow(1)}catch(err){if(!(err instanceof RangeError)){throw err}throw"Unable to grow wasm table. Set ALLOW_TABLE_GROWTH."}return wasmTable.length-1};Module["getEmptyTableSlot"]=getEmptyTableSlot;var setWasmTableEntry=(idx,func)=>{wasmTable.set(idx,func);wasmTableMirror[idx]=wasmTable.get(idx)};Module["setWasmTableEntry"]=setWasmTableEntry;var addFunction=(func,sig)=>{var rtn=getFunctionAddress(func);if(rtn){return rtn}var ret=getEmptyTableSlot();try{setWasmTableEntry(ret,func)}catch(err){if(!(err instanceof TypeError)){throw err}var wrapped=convertJsFunctionToWasm(func,sig);setWasmTableEntry(ret,wrapped)}functionsInTableMap.set(func,ret);return ret};Module["addFunction"]=addFunction;var updateGOT=(exports,replace)=>{for(var symName in exports){if(isInternalSym(symName)){continue}var value=exports[symName];GOT[symName]||=new WebAssembly.Global({"value":"i32","mutable":true});if(replace||GOT[symName].value==0){if(typeof value=="function"){GOT[symName].value=addFunction(value)}else if(typeof value=="number"){GOT[symName].value=value}else{err(`unhandled export type for '${symName}': ${typeof value}`)}}}};Module["updateGOT"]=updateGOT;var relocateExports=(exports,memoryBase,replace)=>{var relocated={};for(var e in exports){var value=exports[e];if(typeof value=="object"){value=value.value}if(typeof value=="number"){value+=memoryBase}relocated[e]=value}updateGOT(relocated,replace);return relocated};Module["relocateExports"]=relocateExports;var isSymbolDefined=symName=>{var existing=wasmImports[symName];if(!existing||existing.stub){return false}return true};Module["isSymbolDefined"]=isSymbolDefined;var dynCall=(sig,ptr,args=[])=>{var rtn=getWasmTableEntry(ptr)(...args);return sig[0]=="p"?rtn>>>0:rtn};Module["dynCall"]=dynCall;var createInvokeFunction=sig=>function(){var sp=stackSave();try{return dynCall(sig,arguments[0],Array.prototype.slice.call(arguments,1))}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);if(sig[0]=="j")return 0n}};Module["createInvokeFunction"]=createInvokeFunction;var resolveGlobalSymbol=(symName,direct=false)=>{var sym;if(isSymbolDefined(symName)){sym=wasmImports[symName]}else if(symName.startsWith("invoke_")){sym=wasmImports[symName]=Module.createInvoke(symName.split("_")[1])}else if(symName.startsWith("__cxa_find_matching_catch_")){sym=wasmImports[symName]=function(){var args=Array.from(arguments);var rtn=findMatchingCatch(args);return rtn}}return{sym:sym,name:symName}};Module["resolveGlobalSymbol"]=resolveGlobalSymbol;var loadWebAssemblyModule=(binary,flags,libName,localScope,handle)=>{var metadata=getDylinkMetadata(binary);currentModuleWeakSymbols=metadata.weakImports;function loadModule(){var firstLoad=!handle||!HEAP8[handle+8>>>0];if(firstLoad){var memAlign=Math.pow(2,metadata.memoryAlign);var memoryBase=metadata.memorySize?alignMemory(getMemory(metadata.memorySize+memAlign),memAlign):0;var tableBase=metadata.tableSize?wasmTable.length:0;if(handle){HEAP8[handle+8>>>0]=1;HEAPU32[handle+12>>>2>>>0]=memoryBase;HEAP32[handle+16>>>2>>>0]=metadata.memorySize;HEAPU32[handle+20>>>2>>>0]=tableBase;HEAP32[handle+24>>>2>>>0]=metadata.tableSize}}else{memoryBase=HEAPU32[handle+12>>>2>>>0];tableBase=HEAPU32[handle+20>>>2>>>0]}var tableGrowthNeeded=tableBase+metadata.tableSize-wasmTable.length;if(tableGrowthNeeded>0){wasmTable.grow(tableGrowthNeeded)}var moduleExports;function resolveSymbol(sym){var resolved=resolveGlobalSymbol(sym).sym;if(!resolved&&localScope){resolved=localScope[sym]}if(!resolved){resolved=moduleExports[sym]}return resolved}var proxyHandler={get(stubs,prop){switch(prop){case"__memory_base":return memoryBase;case"__table_base":return tableBase}if(prop in wasmImports&&!wasmImports[prop].stub){return wasmImports[prop]}if(!(prop in stubs)){var resolved;stubs[prop]=(...args)=>{resolved||=resolveSymbol(prop);if(!resolved){throw new Error(`Dynamic linking error: cannot resolve symbol ${prop}`)}return resolved(...args)}}return stubs[prop]}};var proxy=new Proxy({},proxyHandler);var info={"GOT.mem":new Proxy({},GOTHandler),"GOT.func":new Proxy({},GOTHandler),"env":proxy,"wasi_snapshot_preview1":proxy};function postInstantiation(module,instance){updateTableMap(tableBase,metadata.tableSize);moduleExports=relocateExports(instance.exports,memoryBase);if(!flags.allowUndefined){reportUndefinedSymbols()}function addEmAsm(addr,body){var args=[];var arity=0;for(;arity<16;arity++){if(body.indexOf("$"+arity)!=-1){args.push("$"+arity)}else{break}}args=args.join(",");var func=`(${args}) => { ${body} };`;ASM_CONSTS[start]=eval(func)}if("__start_em_asm"in moduleExports){var start=moduleExports["__start_em_asm"];var stop=moduleExports["__stop_em_asm"];while(start ${body};`;moduleExports[name]=eval(func)}for(var name in moduleExports){if(name.startsWith("__em_js__")){var start=moduleExports[name];var jsString=UTF8ToString(start);var parts=jsString.split("<::>");addEmJs(name.replace("__em_js__",""),parts[0],parts[1]);delete moduleExports[name]}}var applyRelocs=moduleExports["__wasm_apply_data_relocs"];if(applyRelocs){if(runtimeInitialized){applyRelocs()}else{__RELOC_FUNCS__.push(applyRelocs)}}var init=moduleExports["__wasm_call_ctors"];if(init){if(runtimeInitialized){init()}else{__ATINIT__.push(init)}}return moduleExports}if(flags.loadAsync){if(binary instanceof WebAssembly.Module){var instance=new WebAssembly.Instance(binary,info);return Promise.resolve(postInstantiation(binary,instance))}return WebAssembly.instantiate(binary,info).then(result=>postInstantiation(result.module,result.instance))}var module=binary instanceof WebAssembly.Module?binary:new WebAssembly.Module(binary);var instance=new WebAssembly.Instance(module,info);return postInstantiation(module,instance)}if(flags.loadAsync){return metadata.neededDynlibs.reduce((chain,dynNeeded)=>chain.then(()=>loadDynamicLibrary(dynNeeded,flags,localScope)),Promise.resolve()).then(loadModule)}metadata.neededDynlibs.forEach(needed=>loadDynamicLibrary(needed,flags,localScope));return loadModule()};Module["loadWebAssemblyModule"]=loadWebAssemblyModule;var mergeLibSymbols=(exports,libName)=>{for(var[sym,exp]of Object.entries(exports)){const setImport=target=>{if(!isSymbolDefined(target)){wasmImports[target]=exp}};setImport(sym);const main_alias="__main_argc_argv";if(sym=="main"){setImport(main_alias)}if(sym==main_alias){setImport("main")}if(sym.startsWith("dynCall_")&&!Module.hasOwnProperty(sym)){Module[sym]=exp}}};Module["mergeLibSymbols"]=mergeLibSymbols;var asyncLoad=(url,onload,onerror,noRunDep)=>{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};Module["asyncLoad"]=asyncLoad;var preloadPlugins=Module["preloadPlugins"]||[];Module["preloadPlugins"]=preloadPlugins;var registerWasmPlugin=()=>{var wasmPlugin={"promiseChainEnd":Promise.resolve(),"canHandle":name=>!Module.noWasmDecoding&&name.endsWith(".so"),"handle":(byteArray,name,onload,onerror)=>{wasmPlugin["promiseChainEnd"]=wasmPlugin["promiseChainEnd"].then(()=>loadWebAssemblyModule(byteArray,{loadAsync:true,nodelete:true},name,{})).then(exports=>{preloadedWasm[name]=exports;onload(byteArray)},error=>{err(`failed to instantiate wasm: ${name}: ${error}`);onerror()})}};preloadPlugins.push(wasmPlugin)};Module["registerWasmPlugin"]=registerWasmPlugin;var preloadedWasm={};Module["preloadedWasm"]=preloadedWasm;function loadDynamicLibrary(libName,flags={global:true,nodelete:true},localScope,handle){var dso=LDSO.loadedLibsByName[libName];if(dso){if(!flags.global){if(localScope){Object.assign(localScope,dso.exports)}}else if(!dso.global){dso.global=true;mergeLibSymbols(dso.exports,libName)}if(flags.nodelete&&dso.refcount!==Infinity){dso.refcount=Infinity}dso.refcount++;if(handle){LDSO.loadedLibsByHandle[handle]=dso}return flags.loadAsync?Promise.resolve(true):true}dso=newDSO(libName,handle,"loading");dso.refcount=flags.nodelete?Infinity:1;dso.global=flags.global;function loadLibData(){var libData;if(handle){var data=HEAPU32[handle+28>>>2>>>0];var dataSize=HEAPU32[handle+32>>>2>>>0];if(data&&dataSize){libData=HEAP8.slice(data,data+dataSize)}}if(!libData&&flags.fs&&flags.fs.findObject(libName)){libData=flags.fs.readFile(libName,{encoding:"binary"});if(!(libData instanceof Uint8Array)){libData=new Uint8Array(libData)}}if(libData){return flags.loadAsync?Promise.resolve(libData):libData}var libFile=locateFile(libName);if(flags.loadAsync){return new Promise(function(resolve,reject){asyncLoad(libFile,resolve,reject)})}if(!readBinary){throw new Error(`${libFile}: file not found, and synchronous loading of external files is not available`)}return readBinary(libFile)}function getExports(){var preloaded=preloadedWasm[libName];if(preloaded){return flags.loadAsync?Promise.resolve(preloaded):preloaded}if(flags.loadAsync){return loadLibData().then(libData=>loadWebAssemblyModule(libData,flags,libName,localScope,handle))}return loadWebAssemblyModule(loadLibData(),flags,libName,localScope,handle)}function moduleLoaded(exports){if(dso.global){mergeLibSymbols(exports,libName)}else if(localScope){Object.assign(localScope,exports)}dso.exports=exports}if(flags.loadAsync){return getExports().then(exports=>{moduleLoaded(exports);return true})}moduleLoaded(getExports());return true}Module["loadDynamicLibrary"]=loadDynamicLibrary;var reportUndefinedSymbols=()=>{for(var[symName,entry]of Object.entries(GOT)){if(entry.value==0){var value=resolveGlobalSymbol(symName,true).sym;if(!value&&!entry.required){continue}if(typeof value=="function"){entry.value=addFunction(value,value.sig)}else if(typeof value=="number"){entry.value=value}else{throw new Error(`bad export type for '${symName}': ${typeof value}`)}}}};Module["reportUndefinedSymbols"]=reportUndefinedSymbols;var loadDylibs=()=>{if(!dynamicLibraries.length){reportUndefinedSymbols();return}addRunDependency("loadDylibs");dynamicLibraries.reduce((chain,lib)=>chain.then(()=>loadDynamicLibrary(lib,{loadAsync:true,global:true,nodelete:true,allowUndefined:true})),Promise.resolve()).then(()=>{reportUndefinedSymbols();removeRunDependency("loadDylibs")})};Module["loadDylibs"]=loadDylibs;var noExitRuntime=Module["noExitRuntime"]||true;Module["noExitRuntime"]=noExitRuntime;function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="*";switch(type){case"i1":HEAP8[ptr>>>0]=value;break;case"i8":HEAP8[ptr>>>0]=value;break;case"i16":HEAP16[ptr>>>1>>>0]=value;break;case"i32":HEAP32[ptr>>>2>>>0]=value;break;case"i64":HEAP64[ptr>>>3]=BigInt(value);break;case"float":HEAPF32[ptr>>>2>>>0]=value;break;case"double":HEAPF64[ptr>>>3>>>0]=value;break;case"*":HEAPU32[ptr>>>2>>>0]=value;break;default:abort(`invalid type for setValue: ${type}`)}}Module["setValue"]=setValue;var MAX_INT53=9007199254740992;Module["MAX_INT53"]=MAX_INT53;var MIN_INT53=-9007199254740992;Module["MIN_INT53"]=MIN_INT53;var bigintToI53Checked=num=>numMAX_INT53?NaN:Number(num);Module["bigintToI53Checked"]=bigintToI53Checked;function ___assert_fail(condition,filename,line,func){condition>>>=0;filename>>>=0;func>>>=0;abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}Module["___assert_fail"]=___assert_fail;___assert_fail.sig="vppip";function ___call_sighandler(fp,sig){fp>>>=0;return getWasmTableEntry(fp)(sig)}Module["___call_sighandler"]=___call_sighandler;___call_sighandler.sig="vpi";var exceptionCaught=[];Module["exceptionCaught"]=exceptionCaught;var uncaughtExceptionCount=0;Module["uncaughtExceptionCount"]=uncaughtExceptionCount;function ___cxa_begin_catch(ptr){ptr>>>=0;var info=new ExceptionInfo(ptr);if(!info.get_caught()){info.set_caught(true);uncaughtExceptionCount--}info.set_rethrown(false);exceptionCaught.push(info);___cxa_increment_exception_refcount(info.excPtr);return info.get_exception_ptr()}Module["___cxa_begin_catch"]=___cxa_begin_catch;___cxa_begin_catch.sig="pp";function ___cxa_current_primary_exception(){if(!exceptionCaught.length){return 0}var info=exceptionCaught[exceptionCaught.length-1];___cxa_increment_exception_refcount(info.excPtr);return info.excPtr}Module["___cxa_current_primary_exception"]=___cxa_current_primary_exception;___cxa_current_primary_exception.sig="p";var exceptionLast=0;Module["exceptionLast"]=exceptionLast;var ___cxa_end_catch=()=>{_setThrew(0,0);var info=exceptionCaught.pop();___cxa_decrement_exception_refcount(info.excPtr);exceptionLast=0};Module["___cxa_end_catch"]=___cxa_end_catch;___cxa_end_catch.sig="v";class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>>2>>>0]=type}get_type(){return HEAPU32[this.ptr+4>>>2>>>0]}set_destructor(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>>2>>>0]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0]=caught}get_caught(){return HEAP8[this.ptr+12>>>0]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0]=rethrown}get_rethrown(){return HEAP8[this.ptr+13>>>0]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>>2>>>0]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>>2>>>0]}get_exception_ptr(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return HEAPU32[this.excPtr>>>2>>>0]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}Module["ExceptionInfo"]=ExceptionInfo;function ___resumeException(ptr){ptr>>>=0;if(!exceptionLast){exceptionLast=ptr}throw Module.wrapException(exceptionLast)}Module["___resumeException"]=___resumeException;___resumeException.sig="vp";var setTempRet0=val=>__emscripten_tempret_set(val);Module["setTempRet0"]=setTempRet0;var findMatchingCatch=args=>{var thrown=exceptionLast;if(!thrown){setTempRet0(0);return 0}var info=new ExceptionInfo(thrown);info.set_adjusted_ptr(thrown);var thrownType=info.get_type();if(!thrownType){setTempRet0(0);return thrown}for(var arg in args){var caughtType=args[arg];if(caughtType===0||caughtType===thrownType){break}var adjusted_ptr_addr=info.ptr+16;if(___cxa_can_catch(caughtType,thrownType,adjusted_ptr_addr)){setTempRet0(caughtType);return thrown}}setTempRet0(thrownType);return thrown};Module["findMatchingCatch"]=findMatchingCatch;function ___cxa_find_matching_catch_2(){return findMatchingCatch([])}Module["___cxa_find_matching_catch_2"]=___cxa_find_matching_catch_2;___cxa_find_matching_catch_2.sig="p";function ___cxa_find_matching_catch_3(arg0){arg0>>>=0;return findMatchingCatch([arg0])}Module["___cxa_find_matching_catch_3"]=___cxa_find_matching_catch_3;___cxa_find_matching_catch_3.sig="pp";var ___cxa_rethrow=()=>{var info=exceptionCaught.pop();if(!info){abort("no exception to throw")}var ptr=info.excPtr;if(!info.get_rethrown()){exceptionCaught.push(info);info.set_rethrown(true);info.set_caught(false);uncaughtExceptionCount++}exceptionLast=ptr;throw Module.wrapException(exceptionLast)};Module["___cxa_rethrow"]=___cxa_rethrow;___cxa_rethrow.sig="v";function ___cxa_rethrow_primary_exception(ptr){ptr>>>=0;if(!ptr)return;var info=new ExceptionInfo(ptr);exceptionCaught.push(info);info.set_rethrown(true);___cxa_rethrow()}Module["___cxa_rethrow_primary_exception"]=___cxa_rethrow_primary_exception;___cxa_rethrow_primary_exception.sig="vp";function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw Module.wrapException(exceptionLast)}Module["___cxa_throw"]=___cxa_throw;___cxa_throw.sig="vppp";var ___cxa_uncaught_exceptions=()=>uncaughtExceptionCount;Module["___cxa_uncaught_exceptions"]=___cxa_uncaught_exceptions;___cxa_uncaught_exceptions.sig="i";var ___memory_base=new WebAssembly.Global({"value":"i32","mutable":false},1024);Module["___memory_base"]=___memory_base;var ___stack_high=9882224;Module["___stack_high"]=___stack_high;var ___stack_low=4639344;Module["___stack_low"]=___stack_low;var ___stack_pointer=new WebAssembly.Global({"value":"i32","mutable":true},9882224);Module["___stack_pointer"]=___stack_pointer;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};Module["PATH"]=PATH;var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};Module["initRandomFill"]=initRandomFill;var randomFill=view=>(randomFill=initRandomFill())(view);Module["randomFill"]=randomFill;var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};Module["lengthBytesUTF8"]=lengthBytesUTF8;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};Module["stringToUTF8Array"]=stringToUTF8Array;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};Module["FS_stdin_getChar"]=FS_stdin_getChar;var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};Module["TTY"]=TTY;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(!ptr)return 0;return zeroMemory(ptr,size)};Module["mmapAlloc"]=mmapAlloc;var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key of Object.keys(node.contents)){entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}return{ptr:ptr,allocated:allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};Module["MEMFS"]=MEMFS;var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};Module["FS_createDataFile"]=FS_createDataFile;var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};Module["FS_handledByPreloadPlugin"]=FS_handledByPreloadPlugin;var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,processData,onerror)}else{processData(url)}};Module["FS_createPreloadedFile"]=FS_createPreloadedFile;var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};Module["FS_modeStringToFlags"]=FS_modeStringToFlags;var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};Module["FS_getMode"]=FS_getMode;var IDBFS={dbs:{},indexedDB:()=>{if(typeof indexedDB!="undefined")return indexedDB;var ret=null;if(typeof window=="object")ret=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;return ret},DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:(...args)=>MEMFS.mount(...args),syncfs:(mount,populate,callback)=>{IDBFS.getLocalSet(mount,(err,local)=>{if(err)return callback(err);IDBFS.getRemoteSet(mount,(err,remote)=>{if(err)return callback(err);var src=populate?remote:local;var dst=populate?local:remote;IDBFS.reconcile(src,dst,callback)})})},quit:()=>{Object.values(IDBFS.dbs).forEach(value=>value.close());IDBFS.dbs={}},getDB:(name,callback)=>{var db=IDBFS.dbs[name];if(db){return callback(null,db)}var req;try{req=IDBFS.indexedDB().open(name,IDBFS.DB_VERSION)}catch(e){return callback(e)}if(!req){return callback("Unable to connect to IndexedDB")}req.onupgradeneeded=e=>{var db=e.target.result;var transaction=e.target.transaction;var fileStore;if(db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)){fileStore=transaction.objectStore(IDBFS.DB_STORE_NAME)}else{fileStore=db.createObjectStore(IDBFS.DB_STORE_NAME)}if(!fileStore.indexNames.contains("timestamp")){fileStore.createIndex("timestamp","timestamp",{unique:false})}};req.onsuccess=()=>{db=req.result;IDBFS.dbs[name]=db;callback(null,db)};req.onerror=e=>{callback(e.target.error);e.preventDefault()}},getLocalSet:(mount,callback)=>{var entries={};function isRealDir(p){return p!=="."&&p!==".."}function toAbsolute(root){return p=>PATH.join2(root,p)}var check=FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));while(check.length){var path=check.pop();var stat;try{stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){check.push(...FS.readdir(path).filter(isRealDir).map(toAbsolute(path)))}entries[path]={"timestamp":stat.mtime}}return callback(null,{type:"local",entries:entries})},getRemoteSet:(mount,callback)=>{var entries={};IDBFS.getDB(mount.mountpoint,(err,db)=>{if(err)return callback(err);try{var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readonly");transaction.onerror=e=>{callback(e.target.error);e.preventDefault()};var store=transaction.objectStore(IDBFS.DB_STORE_NAME);var index=store.index("timestamp");index.openKeyCursor().onsuccess=event=>{var cursor=event.target.result;if(!cursor){return callback(null,{type:"remote",db:db,entries:entries})}entries[cursor.primaryKey]={"timestamp":cursor.key};cursor.continue()}}catch(e){return callback(e)}})},loadLocalEntry:(path,callback)=>{var stat,node;try{var lookup=FS.lookupPath(path);node=lookup.node;stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){return callback(null,{"timestamp":stat.mtime,"mode":stat.mode})}else if(FS.isFile(stat.mode)){node.contents=MEMFS.getFileDataAsTypedArray(node);return callback(null,{"timestamp":stat.mtime,"mode":stat.mode,"contents":node.contents})}else{return callback(new Error("node type not supported"))}},storeLocalEntry:(path,entry,callback)=>{try{if(FS.isDir(entry["mode"])){FS.mkdirTree(path,entry["mode"])}else if(FS.isFile(entry["mode"])){FS.writeFile(path,entry["contents"],{canOwn:true})}else{return callback(new Error("node type not supported"))}FS.chmod(path,entry["mode"]);FS.utime(path,entry["timestamp"],entry["timestamp"])}catch(e){return callback(e)}callback(null)},removeLocalEntry:(path,callback)=>{try{var stat=FS.stat(path);if(FS.isDir(stat.mode)){FS.rmdir(path)}else if(FS.isFile(stat.mode)){FS.unlink(path)}}catch(e){return callback(e)}callback(null)},loadRemoteEntry:(store,path,callback)=>{var req=store.get(path);req.onsuccess=event=>callback(null,event.target.result);req.onerror=e=>{callback(e.target.error);e.preventDefault()}},storeRemoteEntry:(store,path,entry,callback)=>{try{var req=store.put(entry,path)}catch(e){callback(e);return}req.onsuccess=event=>callback();req.onerror=e=>{callback(e.target.error);e.preventDefault()}},removeRemoteEntry:(store,path,callback)=>{var req=store.delete(path);req.onsuccess=event=>callback();req.onerror=e=>{callback(e.target.error);e.preventDefault()}},reconcile:(src,dst,callback)=>{var total=0;var create=[];Object.keys(src.entries).forEach(function(key){var e=src.entries[key];var e2=dst.entries[key];if(!e2||e["timestamp"].getTime()!=e2["timestamp"].getTime()){create.push(key);total++}});var remove=[];Object.keys(dst.entries).forEach(function(key){if(!src.entries[key]){remove.push(key);total++}});if(!total){return callback(null)}var errored=false;var db=src.type==="remote"?src.db:dst.db;var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readwrite");var store=transaction.objectStore(IDBFS.DB_STORE_NAME);function done(err){if(err&&!errored){errored=true;return callback(err)}}transaction.onerror=transaction.onabort=e=>{done(e.target.error);e.preventDefault()};transaction.oncomplete=e=>{if(!errored){callback(null)}};create.sort().forEach(path=>{if(dst.type==="local"){IDBFS.loadRemoteEntry(store,path,(err,entry)=>{if(err)return done(err);IDBFS.storeLocalEntry(path,entry,done)})}else{IDBFS.loadLocalEntry(path,(err,entry)=>{if(err)return done(err);IDBFS.storeRemoteEntry(store,path,entry,done)})}});remove.sort().reverse().forEach(path=>{if(dst.type==="local"){IDBFS.removeLocalEntry(path,done)}else{IDBFS.removeRemoteEntry(store,path,done)}})}};Module["IDBFS"]=IDBFS;var ERRNO_CODES={"EPERM":63,"ENOENT":44,"ESRCH":71,"EINTR":27,"EIO":29,"ENXIO":60,"E2BIG":1,"ENOEXEC":45,"EBADF":8,"ECHILD":12,"EAGAIN":6,"EWOULDBLOCK":6,"ENOMEM":48,"EACCES":2,"EFAULT":21,"ENOTBLK":105,"EBUSY":10,"EEXIST":20,"EXDEV":75,"ENODEV":43,"ENOTDIR":54,"EISDIR":31,"EINVAL":28,"ENFILE":41,"EMFILE":33,"ENOTTY":59,"ETXTBSY":74,"EFBIG":22,"ENOSPC":51,"ESPIPE":70,"EROFS":69,"EMLINK":34,"EPIPE":64,"EDOM":18,"ERANGE":68,"ENOMSG":49,"EIDRM":24,"ECHRNG":106,"EL2NSYNC":156,"EL3HLT":107,"EL3RST":108,"ELNRNG":109,"EUNATCH":110,"ENOCSI":111,"EL2HLT":112,"EDEADLK":16,"ENOLCK":46,"EBADE":113,"EBADR":114,"EXFULL":115,"ENOANO":104,"EBADRQC":103,"EBADSLT":102,"EDEADLOCK":16,"EBFONT":101,"ENOSTR":100,"ENODATA":116,"ETIME":117,"ENOSR":118,"ENONET":119,"ENOPKG":120,"EREMOTE":121,"ENOLINK":47,"EADV":122,"ESRMNT":123,"ECOMM":124,"EPROTO":65,"EMULTIHOP":36,"EDOTDOT":125,"EBADMSG":9,"ENOTUNIQ":126,"EBADFD":127,"EREMCHG":128,"ELIBACC":129,"ELIBBAD":130,"ELIBSCN":131,"ELIBMAX":132,"ELIBEXEC":133,"ENOSYS":52,"ENOTEMPTY":55,"ENAMETOOLONG":37,"ELOOP":32,"EOPNOTSUPP":138,"EPFNOSUPPORT":139,"ECONNRESET":15,"ENOBUFS":42,"EAFNOSUPPORT":5,"EPROTOTYPE":67,"ENOTSOCK":57,"ENOPROTOOPT":50,"ESHUTDOWN":140,"ECONNREFUSED":14,"EADDRINUSE":3,"ECONNABORTED":13,"ENETUNREACH":40,"ENETDOWN":38,"ETIMEDOUT":73,"EHOSTDOWN":142,"EHOSTUNREACH":23,"EINPROGRESS":26,"EALREADY":7,"EDESTADDRREQ":17,"EMSGSIZE":35,"EPROTONOSUPPORT":66,"ESOCKTNOSUPPORT":137,"EADDRNOTAVAIL":4,"ENETRESET":39,"EISCONN":30,"ENOTCONN":53,"ETOOMANYREFS":141,"EUSERS":136,"EDQUOT":19,"ESTALE":72,"ENOTSUP":138,"ENOMEDIUM":148,"EILSEQ":25,"EOVERFLOW":61,"ECANCELED":11,"ENOTRECOVERABLE":56,"EOWNERDEAD":62,"ESTRPIPE":135};Module["ERRNO_CODES"]=ERRNO_CODES;var NODEFS={isWindows:false,staticInit(){NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process.binding("constants");if(flags["fs"]){flags=flags["fs"]}NODEFS.flagsForNodeMap={1024:flags["O_APPEND"],64:flags["O_CREAT"],128:flags["O_EXCL"],256:flags["O_NOCTTY"],0:flags["O_RDONLY"],2:flags["O_RDWR"],4096:flags["O_SYNC"],512:flags["O_TRUNC"],1:flags["O_WRONLY"],131072:flags["O_NOFOLLOW"]}},convertNodeCode(e){var code=e.code;return ERRNO_CODES[code]},mount(mount){return NODEFS.createNode(null,"/",NODEFS.getMode(mount.opts.root),0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(28)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode(path){var stat;try{stat=fs.lstatSync(path);if(NODEFS.isWindows){stat.mode=stat.mode|(stat.mode&292)>>2}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}return stat.mode},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},flagsForNode(flags){flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;flags&=~65536;var newFlags=0;for(var k in NODEFS.flagsForNodeMap){if(flags&k){newFlags|=NODEFS.flagsForNodeMap[k];flags^=k}}if(flags){throw new FS.ErrnoError(28)}return newFlags},node_ops:{getattr(node){var path=NODEFS.realPath(node);var stat;try{stat=fs.lstatSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}if(NODEFS.isWindows&&!stat.blksize){stat.blksize=4096}if(NODEFS.isWindows&&!stat.blocks){stat.blocks=(stat.size+stat.blksize-1)/stat.blksize|0}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=NODEFS.realPath(node);try{if(attr.mode!==undefined){fs.chmodSync(path,attr.mode);node.mode=attr.mode}if(attr.timestamp!==undefined){var date=new Date(attr.timestamp);fs.utimesSync(path,date,date)}if(attr.size!==undefined){fs.truncateSync(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},lookup(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod(parent,name,mode,dev){var node=NODEFS.createNode(parent,name,mode,dev);var path=NODEFS.realPath(node);try{if(FS.isDir(node.mode)){fs.mkdirSync(path,node.mode)}else{fs.writeFileSync(path,"",{mode:node.mode})}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}return node},rename(oldNode,newDir,newName){var oldPath=NODEFS.realPath(oldNode);var newPath=PATH.join2(NODEFS.realPath(newDir),newName);try{fs.renameSync(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}oldNode.name=newName},unlink(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);try{fs.unlinkSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},rmdir(parent,name){var path=PATH.join2(NODEFS.realPath(parent),name);try{fs.rmdirSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},readdir(node){var path=NODEFS.realPath(node);try{return fs.readdirSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},symlink(parent,newName,oldPath){var newPath=PATH.join2(NODEFS.realPath(parent),newName);try{fs.symlinkSync(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},readlink(node){var path=NODEFS.realPath(node);try{path=fs.readlinkSync(path);path=nodePath.relative(nodePath.resolve(node.mount.opts.root),path);return path}catch(e){if(!e.code)throw e;if(e.code==="UNKNOWN")throw new FS.ErrnoError(28);throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}},stream_ops:{open(stream){var path=NODEFS.realPath(stream.node);try{if(FS.isFile(stream.node.mode)){stream.shared.refcount=1;stream.nfd=fs.openSync(path,NODEFS.flagsForNode(stream.flags))}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},close(stream){try{if(FS.isFile(stream.node.mode)&&stream.nfd&&--stream.shared.refcount===0){fs.closeSync(stream.nfd)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},dup(stream){stream.shared.refcount++},read(stream,buffer,offset,length,position){if(length===0)return 0;try{return fs.readSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),{position:position})}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},write(stream,buffer,offset,length,position){try{return fs.writeSync(stream.nfd,new Int8Array(buffer.buffer,offset,length),{position:position})}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=fs.fstatSync(stream.nfd);position+=stat.size}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr=mmapAlloc(length);NODEFS.stream_ops.read(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}},msync(stream,buffer,offset,length,mmapFlags){NODEFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};Module["NODEFS"]=NODEFS;var WORKERFS={DIR_MODE:16895,FILE_MODE:33279,reader:null,mount(mount){assert(ENVIRONMENT_IS_WORKER);if(!WORKERFS.reader)WORKERFS.reader=new FileReaderSync;var root=WORKERFS.createNode(null,"/",WORKERFS.DIR_MODE,0);var createdParents={};function ensureParent(path){var parts=path.split("/");var parent=root;for(var i=0;i=stream.node.size)return 0;var chunk=stream.node.contents.slice(position,position+length);var ab=WORKERFS.reader.readAsArrayBuffer(chunk);buffer.set(new Uint8Array(ab),offset);return chunk.size},write(stream,buffer,offset,length,position){throw new FS.ErrnoError(29)},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.size}}if(position<0){throw new FS.ErrnoError(28)}return position}}};Module["WORKERFS"]=WORKERFS;var PROXYFS={mount(mount){return PROXYFS.createNode(null,"/",mount.opts.fs.lstat(mount.opts.root).mode,0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}var node=FS.createNode(parent,name,mode);node.node_ops=PROXYFS.node_ops;node.stream_ops=PROXYFS.stream_ops;return node},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},node_ops:{getattr(node){var path=PROXYFS.realPath(node);var stat;try{stat=node.mount.opts.fs.lstat(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=PROXYFS.realPath(node);try{if(attr.mode!==undefined){node.mount.opts.fs.chmod(path,attr.mode);node.mode=attr.mode}if(attr.timestamp!==undefined){var date=new Date(attr.timestamp);node.mount.opts.fs.utime(path,date,date)}if(attr.size!==undefined){node.mount.opts.fs.truncate(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},lookup(parent,name){try{var path=PATH.join2(PROXYFS.realPath(parent),name);var mode=parent.mount.opts.fs.lstat(path).mode;var node=PROXYFS.createNode(parent,name,mode);return node}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},mknod(parent,name,mode,dev){var node=PROXYFS.createNode(parent,name,mode,dev);var path=PROXYFS.realPath(node);try{if(FS.isDir(node.mode)){node.mount.opts.fs.mkdir(path,node.mode)}else{node.mount.opts.fs.writeFile(path,"",{mode:node.mode})}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return node},rename(oldNode,newDir,newName){var oldPath=PROXYFS.realPath(oldNode);var newPath=PATH.join2(PROXYFS.realPath(newDir),newName);try{oldNode.mount.opts.fs.rename(oldPath,newPath);oldNode.name=newName;oldNode.parent=newDir}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},unlink(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.unlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},rmdir(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.rmdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readdir(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},symlink(parent,newName,oldPath){var newPath=PATH.join2(PROXYFS.realPath(parent),newName);try{parent.mount.opts.fs.symlink(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readlink(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}}},stream_ops:{open(stream){var path=PROXYFS.realPath(stream.node);try{stream.nfd=stream.node.mount.opts.fs.open(path,stream.flags)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},close(stream){try{stream.node.mount.opts.fs.close(stream.nfd)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},read(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.read(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},write(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.write(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=stream.node.node_ops.getattr(stream.node);position+=stat.size}catch(e){throw new FS.ErrnoError(ERRNO_CODES[e.code])}}}if(position<0){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}return position}}};Module["PROXYFS"]=PROXYFS;var LZ4={DIR_MODE:16895,FILE_MODE:33279,CHUNK_SIZE:-1,codec:null,init(){if(LZ4.codec)return;LZ4.codec=function(){var MiniLZ4=function(){var exports={};exports.uncompress=function(input,output,sIdx,eIdx){sIdx=sIdx||0;eIdx=eIdx||input.length-sIdx;for(var i=sIdx,n=eIdx,j=0;i>4;if(literals_length>0){var l=literals_length+240;while(l===255){l=input[i++];literals_length+=l}var end=i+literals_length;while(ij)return-(i-2);var match_length=token&15;var l=match_length+240;while(l===255){l=input[i++];match_length+=l}var pos=j-offset;var end=j+match_length+4;while(jmaxInputSize?0:isize+isize/255+16|0};exports.compress=function(src,dst,sIdx,eIdx){hashTable.set(empty);return compressBlock(src,dst,0,sIdx||0,eIdx||dst.length)};function compressBlock(src,dst,pos,sIdx,eIdx){var dpos=sIdx;var dlen=eIdx-sIdx;var anchor=0;if(src.length>=maxInputSize)throw new Error("input too large");if(src.length>mfLimit){var n=exports.compressBound(src.length);if(dlen>>hashShift;var ref=hashTable[hash]-1;hashTable[hash]=pos+1;if(ref<0||pos-ref>>>16>0||((src[ref+3]<<8|src[ref+2])!=sequenceHighBits||(src[ref+1]<<8|src[ref])!=sequenceLowBits)){step=findMatchAttempts++>>skipStrength;pos+=step;continue}findMatchAttempts=(1<=runMask){dst[dpos++]=(runMask<254;len-=255){dst[dpos++]=255}dst[dpos++]=len}else{dst[dpos++]=(literals_length<>8;if(match_length>=mlMask){match_length-=mlMask;while(match_length>=255){match_length-=255;dst[dpos++]=255}dst[dpos++]=match_length}anchor=pos}}if(anchor==0)return 0;literals_length=src.length-anchor;if(literals_length>=runMask){dst[dpos++]=runMask<254;ln-=255){dst[dpos++]=255}dst[dpos++]=ln}else{dst[dpos++]=literals_length<0){assert(compressedSize<=bound);compressed=compressed.subarray(0,compressedSize);compressedChunks.push(compressed);total+=compressedSize;successes.push(1);if(verify){var back=exports.uncompress(compressed,temp);assert(back===chunk.length,[back,chunk.length]);for(var i=0;i{var dir=PATH.dirname(file.filename);var name=PATH.basename(file.filename);FS.createPath("",dir,true,true);var parent=FS.analyzePath(dir).object;LZ4.createNode(parent,name,LZ4.FILE_MODE,0,{compressedData:compressedData,start:file.start,end:file.end})});if(preloadPlugin){Browser.init();pack["metadata"].files.forEach(file=>{var handled=false;var fullname=file.filename;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){var dep=getUniqueRunDependency("fp "+fullname);addRunDependency(dep);var finish=()=>removeRunDependency(dep);var byteArray=FS.readFile(fullname);plugin["handle"](byteArray,fullname,finish,finish);handled=true}})})}},createNode(parent,name,mode,dev,contents,mtime){var node=FS.createNode(parent,name,mode);node.mode=mode;node.node_ops=LZ4.node_ops;node.stream_ops=LZ4.stream_ops;node.timestamp=(mtime||new Date).getTime();assert(LZ4.FILE_MODE!==LZ4.DIR_MODE);if(mode===LZ4.FILE_MODE){node.size=contents.end-contents.start;node.contents=contents}else{node.size=4096;node.contents={}}if(parent){parent.contents[name]=node}return node},node_ops:{getattr(node){return{dev:1,ino:node.id,mode:node.mode,nlink:1,uid:0,gid:0,rdev:0,size:node.size,atime:new Date(node.timestamp),mtime:new Date(node.timestamp),ctime:new Date(node.timestamp),blksize:4096,blocks:Math.ceil(node.size/4096)}},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}},lookup(parent,name){throw new FS.ErrnoError(44)},mknod(parent,name,mode,dev){throw new FS.ErrnoError(63)},rename(oldNode,newDir,newName){throw new FS.ErrnoError(63)},unlink(parent,name){throw new FS.ErrnoError(63)},rmdir(parent,name){throw new FS.ErrnoError(63)},readdir(node){throw new FS.ErrnoError(63)},symlink(parent,newName,oldPath){throw new FS.ErrnoError(63)}},stream_ops:{read(stream,buffer,offset,length,position){length=Math.min(length,stream.node.size-position);if(length<=0)return 0;var contents=stream.node.contents;var compressedData=contents.compressedData;var written=0;while(written=0){currChunk=compressedData["cachedChunks"][found]}else{compressedData["cachedIndexes"].pop();compressedData["cachedIndexes"].unshift(chunkIndex);currChunk=compressedData["cachedChunks"].pop();compressedData["cachedChunks"].unshift(currChunk);if(compressedData["debug"]){out("decompressing chunk "+chunkIndex);Module["decompressedChunks"]=(Module["decompressedChunks"]||0)+1}var compressed=compressedData["data"].subarray(compressedStart,compressedStart+compressedSize);var originalSize=LZ4.codec.uncompress(compressed,currChunk);if(chunkIndex8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;if(FS.trackingDelegate["onMakeDirectory"]){FS.trackingDelegate["onMakeDirectory"](path,mode)}return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""});FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS,"IDBFS":IDBFS,"NODEFS":NODEFS,"WORKERFS":WORKERFS,"PROXYFS":PROXYFS}},init(input,output,error){FS.init.initialized=true;Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;_fflush(0);for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};Module["FS"]=FS;var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;HEAP64[buf+24>>>3]=BigInt(stat.size);HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3;HEAP64[buf+56>>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3;HEAP64[buf+72>>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3;HEAP64[buf+88>>>3]=BigInt(stat.ino);return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};Module["SYSCALLS"]=SYSCALLS;function ___syscall__newselect(nfds,readfds,writefds,exceptfds,timeout){readfds>>>=0;writefds>>>=0;exceptfds>>>=0;timeout>>>=0;try{var total=0;var srcReadLow=readfds?HEAP32[readfds>>>2>>>0]:0,srcReadHigh=readfds?HEAP32[readfds+4>>>2>>>0]:0;var srcWriteLow=writefds?HEAP32[writefds>>>2>>>0]:0,srcWriteHigh=writefds?HEAP32[writefds+4>>>2>>>0]:0;var srcExceptLow=exceptfds?HEAP32[exceptfds>>>2>>>0]:0,srcExceptHigh=exceptfds?HEAP32[exceptfds+4>>>2>>>0]:0;var dstReadLow=0,dstReadHigh=0;var dstWriteLow=0,dstWriteHigh=0;var dstExceptLow=0,dstExceptHigh=0;var allLow=(readfds?HEAP32[readfds>>>2>>>0]:0)|(writefds?HEAP32[writefds>>>2>>>0]:0)|(exceptfds?HEAP32[exceptfds>>>2>>>0]:0);var allHigh=(readfds?HEAP32[readfds+4>>>2>>>0]:0)|(writefds?HEAP32[writefds+4>>>2>>>0]:0)|(exceptfds?HEAP32[exceptfds+4>>>2>>>0]:0);var check=function(fd,low,high,val){return fd<32?low&val:high&val};for(var fd=0;fd>>2>>>0]:0,tv_usec=readfds?HEAP32[timeout+4>>>2>>>0]:0;timeoutInMillis=(tv_sec+tv_usec/1e6)*1e3}flags=stream.stream_ops.poll(stream,timeoutInMillis)}if(flags&1&&check(fd,srcReadLow,srcReadHigh,mask)){fd<32?dstReadLow=dstReadLow|mask:dstReadHigh=dstReadHigh|mask;total++}if(flags&4&&check(fd,srcWriteLow,srcWriteHigh,mask)){fd<32?dstWriteLow=dstWriteLow|mask:dstWriteHigh=dstWriteHigh|mask;total++}if(flags&2&&check(fd,srcExceptLow,srcExceptHigh,mask)){fd<32?dstExceptLow=dstExceptLow|mask:dstExceptHigh=dstExceptHigh|mask;total++}}if(readfds){HEAP32[readfds>>>2>>>0]=dstReadLow;HEAP32[readfds+4>>>2>>>0]=dstReadHigh}if(writefds){HEAP32[writefds>>>2>>>0]=dstWriteLow;HEAP32[writefds+4>>>2>>>0]=dstWriteHigh}if(exceptfds){HEAP32[exceptfds>>>2>>>0]=dstExceptLow;HEAP32[exceptfds+4>>>2>>>0]=dstExceptHigh}return total}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall__newselect"]=___syscall__newselect;___syscall__newselect.sig="iipppp";var SOCKFS={mount(mount){Module["websocket"]=Module["websocket"]&&"object"===typeof Module["websocket"]?Module["websocket"]:{};Module["websocket"]._callbacks={};Module["websocket"]["on"]=function(event,callback){if("function"===typeof callback){this._callbacks[event]=callback}return this};Module["websocket"].emit=function(event,param){if("function"===typeof this._callbacks[event]){this._callbacks[event].call(this,param)}};return FS.createNode(null,"/",16384|511,0)},createSocket(family,type,protocol){type&=~526336;var streaming=type==1;if(streaming&&protocol&&protocol!=6){throw new FS.ErrnoError(66)}var sock={family:family,type:type,protocol:protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node:node,flags:2,seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer(sock,addr,port){var ws;if(typeof addr=="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var runtimeConfig=Module["websocket"]&&"object"===typeof Module["websocket"];var url="ws:#".replace("#","//");if(runtimeConfig){if("string"===typeof Module["websocket"]["url"]){url=Module["websocket"]["url"]}}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}var subProtocols="binary";if(runtimeConfig){if("string"===typeof Module["websocket"]["subprotocol"]){subProtocols=Module["websocket"]["subprotocol"]}}var opts=undefined;if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(23)}}var peer={addr:addr,port:port,socket:ws,dgram_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!="undefined"){peer.dgram_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer(sock,addr,port){return sock.peers[addr+":"+port]},addPeer(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.dgram_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.dgram_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data=="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}data=new Uint8Array(data)}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data:data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,isBinary){if(!isBinary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){Module["websocket"].emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){Module["websocket"].emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=16}return mask},ioctl(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>>2>>>0]=bytes;return 0;default:return 28}},close(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i{var socket=SOCKFS.getSocket(fd);if(!socket)throw new FS.ErrnoError(8);return socket};Module["getSocketFromFD"]=getSocketFromFD;var Sockets={BUFFER_SIZE:10240,MAX_BUFFER_SIZE:10485760,nextFd:1,fds:{},nextport:1,maxport:65535,peer:null,connections:{},portmap:{},localAddr:4261412874,addrPool:[33554442,50331658,67108874,83886090,100663306,117440522,134217738,150994954,167772170,184549386,201326602,218103818,234881034]};Module["Sockets"]=Sockets;var inetPton4=str=>{var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0};Module["inetPton4"]=inetPton4;var jstoi_q=str=>parseInt(str);Module["jstoi_q"]=jstoi_q;var inetPton6=str=>{var words;var w,offset,z,i;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w{switch(family){case 2:addr=inetPton4(addr);zeroMemory(sa,16);if(addrlen){HEAP32[addrlen>>>2>>>0]=16}HEAP16[sa>>>1>>>0]=family;HEAP32[sa+4>>>2>>>0]=addr;HEAP16[sa+2>>>1>>>0]=_htons(port);break;case 10:addr=inetPton6(addr);zeroMemory(sa,28);if(addrlen){HEAP32[addrlen>>>2>>>0]=28}HEAP32[sa>>>2>>>0]=family;HEAP32[sa+8>>>2>>>0]=addr[0];HEAP32[sa+12>>>2>>>0]=addr[1];HEAP32[sa+16>>>2>>>0]=addr[2];HEAP32[sa+20>>>2>>>0]=addr[3];HEAP16[sa+2>>>1>>>0]=_htons(port);break;default:return 5}return 0};Module["writeSockaddr"]=writeSockaddr;var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name(name){var res=inetPton4(name);if(res!==null){return name}res=inetPton6(name);if(res!==null){return name}var addr;if(DNS.address_map.addrs[name]){addr=DNS.address_map.addrs[name]}else{var id=DNS.address_map.id++;assert(id<65535,"exceeded max address mappings of 65535");addr="172.29."+(id&255)+"."+(id&65280);DNS.address_map.names[addr]=name;DNS.address_map.addrs[name]=addr}return addr},lookup_addr(addr){if(DNS.address_map.names[addr]){return DNS.address_map.names[addr]}return null}};Module["DNS"]=DNS;function ___syscall_accept4(fd,addr,addrlen,flags,d1,d2){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var newsock=sock.sock_ops.accept(sock);if(addr){var errno=writeSockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport,addrlen)}return newsock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_accept4"]=___syscall_accept4;___syscall_accept4.sig="iippiii";var inetNtop4=addr=>(addr&255)+"."+(addr>>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255);Module["inetNtop4"]=inetNtop4;var inetNtop6=ints=>{var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=inetNtop4(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word{var family=HEAP16[sa>>>1>>>0];var port=_ntohs(HEAPU16[sa+2>>>1>>>0]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>>2>>>0];addr=inetNtop4(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>>2>>>0],HEAP32[sa+12>>>2>>>0],HEAP32[sa+16>>>2>>>0],HEAP32[sa+20>>>2>>>0]];addr=inetNtop6(addr);break;default:return{errno:5}}return{family:family,addr:addr,port:port}};Module["readSockaddr"]=readSockaddr;var getSocketAddress=(addrp,addrlen,allowNull)=>{if(allowNull&&addrp===0)return null;var info=readSockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};Module["getSocketAddress"]=getSocketAddress;function ___syscall_bind(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.bind(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_bind"]=___syscall_bind;___syscall_bind.sig="iippiii";function ___syscall_chdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_chdir"]=___syscall_chdir;___syscall_chdir.sig="ip";function ___syscall_chmod(path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_chmod"]=___syscall_chmod;___syscall_chmod.sig="ipi";function ___syscall_connect(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.connect(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_connect"]=___syscall_connect;___syscall_connect.sig="iippiii";function ___syscall_dup(fd){try{var old=SYSCALLS.getStreamFromFD(fd);return FS.dupStream(old).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_dup"]=___syscall_dup;___syscall_dup.sig="ii";function ___syscall_dup3(fd,newfd,flags){try{var old=SYSCALLS.getStreamFromFD(fd);if(old.fd===newfd)return-28;var existing=FS.getStream(newfd);if(existing)FS.close(existing);return FS.dupStream(old,newfd).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_dup3"]=___syscall_dup3;___syscall_dup3.sig="iiii";function ___syscall_faccessat(dirfd,path,amode,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_faccessat"]=___syscall_faccessat;___syscall_faccessat.sig="iipii";var ___syscall_fadvise64=(fd,offset,len,advice)=>0;Module["___syscall_fadvise64"]=___syscall_fadvise64;___syscall_fadvise64.sig="iijji";function ___syscall_fallocate(fd,mode,offset,len){offset=bigintToI53Checked(offset);len=bigintToI53Checked(len);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.allocate(stream,offset,len);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fallocate"]=___syscall_fallocate;___syscall_fallocate.sig="iiijj";function ___syscall_fchdir(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.chdir(stream.path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchdir"]=___syscall_fchdir;___syscall_fchdir.sig="ii";function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchmod"]=___syscall_fchmod;___syscall_fchmod.sig="iii";function ___syscall_fchmodat2(dirfd,path,mode,flags){path>>>=0;try{var nofollow=flags&256;path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);FS.chmod(path,mode,nofollow);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchmodat2"]=___syscall_fchmodat2;___syscall_fchmodat2.sig="iipii";function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchown32"]=___syscall_fchown32;___syscall_fchown32.sig="iiii";function ___syscall_fchownat(dirfd,path,owner,group,flags){path>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;flags=flags&~256;path=SYSCALLS.calculateAt(dirfd,path);(nofollow?FS.lchown:FS.chown)(path,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fchownat"]=___syscall_fchownat;___syscall_fchownat.sig="iipiii";function syscallGetVarargI(){var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret}Module["syscallGetVarargI"]=syscallGetVarargI;var syscallGetVarargP=syscallGetVarargI;Module["syscallGetVarargP"]=syscallGetVarargP;function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fcntl64"]=___syscall_fcntl64;___syscall_fcntl64.sig="iiip";function ___syscall_fdatasync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fdatasync"]=___syscall_fdatasync;___syscall_fdatasync.sig="ii";function ___syscall_fstat64(fd,buf){buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fstat64"]=___syscall_fstat64;___syscall_fstat64.sig="iip";function ___syscall_statfs64(path,size,buf){path>>>=0;size>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);HEAP32[buf+4>>>2>>>0]=4096;HEAP32[buf+40>>>2>>>0]=4096;HEAP32[buf+8>>>2>>>0]=1e6;HEAP32[buf+12>>>2>>>0]=5e5;HEAP32[buf+16>>>2>>>0]=5e5;HEAP32[buf+20>>>2>>>0]=FS.nextInode;HEAP32[buf+24>>>2>>>0]=1e6;HEAP32[buf+28>>>2>>>0]=42;HEAP32[buf+44>>>2>>>0]=2;HEAP32[buf+36>>>2>>>0]=255;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_statfs64"]=___syscall_statfs64;___syscall_statfs64.sig="ippp";function ___syscall_fstatfs64(fd,size,buf){size>>>=0;buf>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);return ___syscall_statfs64(0,size,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_fstatfs64"]=___syscall_fstatfs64;___syscall_fstatfs64.sig="iipp";function ___syscall_ftruncate64(fd,length){length=bigintToI53Checked(length);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_ftruncate64"]=___syscall_ftruncate64;___syscall_ftruncate64.sig="iij";var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);Module["stringToUTF8"]=stringToUTF8;function ___syscall_getcwd(buf,size){buf>>>=0;size>>>=0;try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size>>=0;count>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);stream.getdents||=FS.readdir(stream.path);var struct_size=280;var pos=0;var off=FS.llseek(stream,0,1);var idx=Math.floor(off/struct_size);while(idx>>3]=BigInt(id);HEAP64[dirp+pos+8>>>3]=BigInt((idx+1)*struct_size);HEAP16[dirp+pos+16>>>1>>>0]=280;HEAP8[dirp+pos+18>>>0]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size;idx+=1}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getdents64"]=___syscall_getdents64;___syscall_getdents64.sig="iipp";function ___syscall_getpeername(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);if(!sock.daddr){return-53}var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getpeername"]=___syscall_getpeername;___syscall_getpeername.sig="iippiii";function ___syscall_getsockname(fd,addr,addrlen,d1,d2,d3){addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getsockname"]=___syscall_getsockname;___syscall_getsockname.sig="iippiii";function ___syscall_getsockopt(fd,level,optname,optval,optlen,d1){optval>>>=0;optlen>>>=0;try{var sock=getSocketFromFD(fd);if(level===1){if(optname===4){HEAP32[optval>>>2>>>0]=sock.error;HEAP32[optlen>>>2>>>0]=4;sock.error=null;return 0}}return-50}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_getsockopt"]=___syscall_getsockopt;___syscall_getsockopt.sig="iiiippi";function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_ioctl"]=___syscall_ioctl;___syscall_ioctl.sig="iiip";function ___syscall_listen(fd,backlog){try{var sock=getSocketFromFD(fd);sock.sock_ops.listen(sock,backlog);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_listen"]=___syscall_listen;___syscall_listen.sig="iiiiiii";function ___syscall_lstat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_lstat64"]=___syscall_lstat64;___syscall_lstat64.sig="ipp";function ___syscall_mkdirat(dirfd,path,mode){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_mkdirat"]=___syscall_mkdirat;___syscall_mkdirat.sig="iipi";function ___syscall_mknodat(dirfd,path,mode,dev){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_mknodat"]=___syscall_mknodat;___syscall_mknodat.sig="iipii";function ___syscall_newfstatat(dirfd,path,buf,flags){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_newfstatat"]=___syscall_newfstatat;___syscall_newfstatat.sig="iippi";function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_openat"]=___syscall_openat;___syscall_openat.sig="iipip";var PIPEFS={BUCKET_BUFFER_SIZE:8192,mount(mount){return FS.createNode(null,"/",16384|511,0)},createPipe(){var pipe={buckets:[],refcnt:2};pipe.buckets.push({buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:0,roffset:0});var rName=PIPEFS.nextname();var wName=PIPEFS.nextname();var rNode=FS.createNode(PIPEFS.root,rName,4096,0);var wNode=FS.createNode(PIPEFS.root,wName,4096,0);rNode.pipe=pipe;wNode.pipe=pipe;var readableStream=FS.createStream({path:rName,node:rNode,flags:0,seekable:false,stream_ops:PIPEFS.stream_ops});rNode.stream=readableStream;var writableStream=FS.createStream({path:wName,node:wNode,flags:1,seekable:false,stream_ops:PIPEFS.stream_ops});wNode.stream=writableStream;return{readable_fd:readableStream.fd,writable_fd:writableStream.fd}},stream_ops:{poll(stream){var pipe=stream.node.pipe;if((stream.flags&2097155)===1){return 256|4}if(pipe.buckets.length>0){for(var i=0;i0){return 64|1}}}return 0},ioctl(stream,request,varargs){return 28},fsync(stream){return 28},read(stream,buffer,offset,length,position){var pipe=stream.node.pipe;var currentLength=0;for(var i=0;i=dataLen){currBucket.buffer.set(data,currBucket.offset);currBucket.offset+=dataLen;return dataLen}else if(freeBytesInCurrBuffer>0){currBucket.buffer.set(data.subarray(0,freeBytesInCurrBuffer),currBucket.offset);currBucket.offset+=freeBytesInCurrBuffer;data=data.subarray(freeBytesInCurrBuffer,data.byteLength)}var numBuckets=data.byteLength/PIPEFS.BUCKET_BUFFER_SIZE|0;var remElements=data.byteLength%PIPEFS.BUCKET_BUFFER_SIZE;for(var i=0;i0){var newBucket={buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:data.byteLength,roffset:0};pipe.buckets.push(newBucket);newBucket.buffer.set(data)}return dataLen},close(stream){var pipe=stream.node.pipe;pipe.refcnt--;if(pipe.refcnt===0){pipe.buckets=null}}},nextname(){if(!PIPEFS.nextname.current){PIPEFS.nextname.current=0}return"pipe["+PIPEFS.nextname.current+++"]"}};Module["PIPEFS"]=PIPEFS;function ___syscall_pipe(fdPtr){fdPtr>>>=0;try{if(fdPtr==0){throw new FS.ErrnoError(21)}var res=PIPEFS.createPipe();HEAP32[fdPtr>>>2>>>0]=res.readable_fd;HEAP32[fdPtr+4>>>2>>>0]=res.writable_fd;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_pipe"]=___syscall_pipe;___syscall_pipe.sig="ip";function ___syscall_poll(fds,nfds,timeout){fds>>>=0;try{var nonzero=0;for(var i=0;i>>2>>>0];var events=HEAP16[pollfd+4>>>1>>>0];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream,-1)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>>1>>>0]=mask}return nonzero}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_poll"]=___syscall_poll;___syscall_poll.sig="ipii";function ___syscall_readlinkat(dirfd,path,buf,bufsize){path>>>=0;buf>>>=0;bufsize>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len>>>0];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len>>>0]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_readlinkat"]=___syscall_readlinkat;___syscall_readlinkat.sig="iippp";function ___syscall_recvfrom(fd,buf,len,flags,addr,addrlen){buf>>>=0;len>>>=0;addr>>>=0;addrlen>>>=0;try{var sock=getSocketFromFD(fd);var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port,addrlen)}HEAPU8.set(msg.buffer,buf>>>0);return msg.buffer.byteLength}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_recvfrom"]=___syscall_recvfrom;___syscall_recvfrom.sig="iippipp";function ___syscall_recvmsg(fd,message,flags,d1,d2,d3){message>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var total=0;for(var i=0;i>>2>>>0]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAPU32[message>>>2>>>0];if(name){var errno=writeSockaddr(name,sock.family,DNS.lookup_name(msg.addr),msg.port)}var bytesRead=0;var bytesRemaining=msg.buffer.byteLength;for(var i=0;bytesRemaining>0&&i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead>>>0);bytesRead+=length;bytesRemaining-=length}return bytesRead}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_recvmsg"]=___syscall_recvmsg;___syscall_recvmsg.sig="iipiiii";function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){oldpath>>>=0;newpath>>>=0;try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_renameat"]=___syscall_renameat;___syscall_renameat.sig="iipip";function ___syscall_rmdir(path){path>>>=0;try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_rmdir"]=___syscall_rmdir;___syscall_rmdir.sig="ip";function ___syscall_sendmsg(fd,message,flags,d1,d2,d3){message>>>=0;d1>>>=0;d2>>>=0;try{var sock=getSocketFromFD(fd);var iov=HEAPU32[message+8>>>2>>>0];var num=HEAP32[message+12>>>2>>>0];var addr,port;var name=HEAPU32[message>>>2>>>0];var namelen=HEAP32[message+4>>>2>>>0];if(name){var info=readSockaddr(name,namelen);if(info.errno)return-info.errno;port=info.port;addr=DNS.lookup_addr(info.addr)||info.addr}var total=0;for(var i=0;i>>2>>>0]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>>2>>>0];var iovlen=HEAP32[iov+(8*i+4)>>>2>>>0];for(var j=0;j>>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_sendmsg"]=___syscall_sendmsg;___syscall_sendmsg.sig="iipippi";function ___syscall_sendto(fd,message,length,flags,addr,addr_len){message>>>=0;length>>>=0;addr>>>=0;addr_len>>>=0;try{var sock=getSocketFromFD(fd);var dest=getSocketAddress(addr,addr_len,true);if(!dest){return FS.write(sock.stream,HEAP8,message,length)}return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_sendto"]=___syscall_sendto;___syscall_sendto.sig="iippipp";function ___syscall_socket(domain,type,protocol){try{var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_socket"]=___syscall_socket;___syscall_socket.sig="iiiiiii";function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_stat64"]=___syscall_stat64;___syscall_stat64.sig="ipp";function ___syscall_symlink(target,linkpath){target>>>=0;linkpath>>>=0;try{target=SYSCALLS.getStr(target);linkpath=SYSCALLS.getStr(linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_symlink"]=___syscall_symlink;___syscall_symlink.sig="ipp";function ___syscall_symlinkat(target,newdirfd,linkpath){target>>>=0;linkpath>>>=0;try{linkpath=SYSCALLS.calculateAt(newdirfd,linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_symlinkat"]=___syscall_symlinkat;___syscall_symlinkat.sig="ipip";function ___syscall_truncate64(path,length){path>>>=0;length=bigintToI53Checked(length);try{if(isNaN(length))return 61;path=SYSCALLS.getStr(path);FS.truncate(path,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_truncate64"]=___syscall_truncate64;___syscall_truncate64.sig="ipj";function ___syscall_unlinkat(dirfd,path,flags){path>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(flags===0){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{abort("Invalid flags passed to unlinkat")}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_unlinkat"]=___syscall_unlinkat;___syscall_unlinkat.sig="iipi";var readI53FromI64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAP32[ptr+4>>>2>>>0]*4294967296;Module["readI53FromI64"]=readI53FromI64;function ___syscall_utimensat(dirfd,path,times,flags){path>>>=0;times>>>=0;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);if(!times){var atime=Date.now();var mtime=atime}else{var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>>2>>>0];atime=seconds*1e3+nanoseconds/(1e3*1e3);times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>>2>>>0];mtime=seconds*1e3+nanoseconds/(1e3*1e3)}FS.utime(path,atime,mtime);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["___syscall_utimensat"]=___syscall_utimensat;___syscall_utimensat.sig="iippi";var ___table_base=new WebAssembly.Global({"value":"i32","mutable":false},1);Module["___table_base"]=___table_base;var ENV={};Module["ENV"]=ENV;var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};Module["stringToUTF8OnStack"]=stringToUTF8OnStack;var dlSetError=msg=>{var sp=stackSave();var cmsg=stringToUTF8OnStack(msg);___dl_seterr(cmsg,0);stackRestore(sp)};Module["dlSetError"]=dlSetError;var dlopenInternal=(handle,jsflags)=>{var filename=UTF8ToString(handle+36);var flags=HEAP32[handle+4>>>2>>>0];filename=PATH.normalize(filename);var searchpaths=[];var global=Boolean(flags&256);var localScope=global?null:{};var combinedFlags={global:global,nodelete:Boolean(flags&4096),loadAsync:jsflags.loadAsync};if(jsflags.loadAsync){return loadDynamicLibrary(filename,combinedFlags,localScope,handle)}try{return loadDynamicLibrary(filename,combinedFlags,localScope,handle)}catch(e){dlSetError(`Could not load dynamic lib: ${filename}\n${e}`);return 0}};Module["dlopenInternal"]=dlopenInternal;function __dlopen_js(handle){handle>>>=0;return dlopenInternal(handle,{loadAsync:false})}Module["__dlopen_js"]=__dlopen_js;__dlopen_js.sig="pp";function __dlsym_js(handle,symbol,symbolIndex){handle>>>=0;symbol>>>=0;symbolIndex>>>=0;symbol=UTF8ToString(symbol);var result;var newSymIndex;var lib=LDSO.loadedLibsByHandle[handle];if(!lib.exports.hasOwnProperty(symbol)||lib.exports[symbol].stub){dlSetError(`Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}`);return 0}newSymIndex=Object.keys(lib.exports).indexOf(symbol);result=lib.exports[symbol];if(typeof result=="function"){var addr=getFunctionAddress(result);if(addr){result=addr}else{result=addFunction(result,result.sig);HEAPU32[symbolIndex>>>2>>>0]=newSymIndex}}return result}Module["__dlsym_js"]=__dlsym_js;__dlsym_js.sig="pppp";var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};Module["handleException"]=handleException;var runtimeKeepaliveCounter=0;Module["runtimeKeepaliveCounter"]=runtimeKeepaliveCounter;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;Module["keepRuntimeAlive"]=keepRuntimeAlive;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};Module["_proc_exit"]=_proc_exit;_proc_exit.sig="vi";var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};Module["exitJS"]=exitJS;var _exit=exitJS;Module["_exit"]=_exit;_exit.sig="vi";var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};Module["maybeExit"]=maybeExit;var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};Module["callUserCallback"]=callUserCallback;function __emscripten_dlopen_js(handle,onsuccess,onerror,user_data){handle>>>=0;onsuccess>>>=0;onerror>>>=0;user_data>>>=0;function errorCallback(e){var filename=UTF8ToString(handle+36);dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`);callUserCallback(()=>getWasmTableEntry(onerror)(handle,user_data))}function successCallback(){callUserCallback(()=>getWasmTableEntry(onsuccess)(handle,user_data))}var promise=dlopenInternal(handle,{loadAsync:true});if(promise){promise.then(successCallback,errorCallback)}else{errorCallback()}}Module["__emscripten_dlopen_js"]=__emscripten_dlopen_js;__emscripten_dlopen_js.sig="vpppp";var nowIsMonotonic=1;Module["nowIsMonotonic"]=nowIsMonotonic;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;Module["__emscripten_get_now_is_monotonic"]=__emscripten_get_now_is_monotonic;__emscripten_get_now_is_monotonic.sig="i";function __emscripten_get_progname(str,len){str>>>=0;stringToUTF8(thisProgram,str,len)}Module["__emscripten_get_progname"]=__emscripten_get_progname;__emscripten_get_progname.sig="vpi";function __emscripten_lookup_name(name){name>>>=0;var nameString=UTF8ToString(name);return inetPton4(DNS.lookup_name(nameString))}Module["__emscripten_lookup_name"]=__emscripten_lookup_name;__emscripten_lookup_name.sig="ip";var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};Module["__emscripten_runtime_keepalive_clear"]=__emscripten_runtime_keepalive_clear;__emscripten_runtime_keepalive_clear.sig="v";function __emscripten_system(command){command>>>=0;if(ENVIRONMENT_IS_NODE){if(!command)return 1;var cmdstr=UTF8ToString(command);if(!cmdstr.length)return 0;var cp=require("child_process");var ret=cp.spawnSync(cmdstr,[],{shell:true,stdio:"inherit"});var _W_EXITCODE=(ret,sig)=>ret<<8|sig;if(ret.status===null){var signalToNumber=sig=>{switch(sig){case"SIGHUP":return 1;case"SIGINT":return 2;case"SIGQUIT":return 3;case"SIGFPE":return 8;case"SIGKILL":return 9;case"SIGALRM":return 14;case"SIGTERM":return 15}return 2};return _W_EXITCODE(0,signalToNumber(ret.signal))}return _W_EXITCODE(ret.status,0)}if(!command)return 0;return-52}Module["__emscripten_system"]=__emscripten_system;__emscripten_system.sig="ip";var __emscripten_throw_longjmp=()=>{throw Module.wrapException(Infinity)};Module["__emscripten_throw_longjmp"]=__emscripten_throw_longjmp;__emscripten_throw_longjmp.sig="v";function __gmtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getUTCSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getUTCMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getUTCHours();HEAP32[tmPtr+12>>>2>>>0]=date.getUTCDate();HEAP32[tmPtr+16>>>2>>>0]=date.getUTCMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday}Module["__gmtime_js"]=__gmtime_js;__gmtime_js.sig="vjp";var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);Module["isLeapYear"]=isLeapYear;var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];Module["MONTH_DAYS_LEAP_CUMULATIVE"]=MONTH_DAYS_LEAP_CUMULATIVE;var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];Module["MONTH_DAYS_REGULAR_CUMULATIVE"]=MONTH_DAYS_REGULAR_CUMULATIVE;var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};Module["ydayFromDate"]=ydayFromDate;function __localtime_js(time,tmPtr){time=bigintToI53Checked(time);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}Module["__localtime_js"]=__localtime_js;__localtime_js.sig="vjp";var __mktime_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var date=new Date(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var dst=HEAP32[tmPtr+32>>>2>>>0];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>>2>>>0]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getYear();var timeMs=date.getTime();if(isNaN(timeMs)){return-1}return timeMs/1e3})();return BigInt(ret)};Module["__mktime_js"]=__mktime_js;__mktime_js.sig="jp";function __mmap_js(len,prot,flags,fd,offset,allocated,addr){len>>>=0;offset=bigintToI53Checked(offset);allocated>>>=0;addr>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>>2>>>0]=res.allocated;HEAPU32[addr>>>2>>>0]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__mmap_js"]=__mmap_js;__mmap_js.sig="ipiiijpp";function __msync_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 61;SYSCALLS.doMsync(addr,SYSCALLS.getStreamFromFD(fd),len,flags,offset);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__msync_js"]=__msync_js;__msync_js.sig="ippiiij";function __munmap_js(addr,len,prot,flags,fd,offset){addr>>>=0;len>>>=0;offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}Module["__munmap_js"]=__munmap_js;__munmap_js.sig="ippiiij";var timers={};Module["timers"]=timers;var _emscripten_get_now;_emscripten_get_now=()=>performance.now();Module["_emscripten_get_now"]=_emscripten_get_now;_emscripten_get_now.sig="d";var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id:id,timeout_ms:timeout_ms};return 0};Module["__setitimer_js"]=__setitimer_js;__setitimer_js.sig="iid";var __timegm_js=function(tmPtr){tmPtr>>>=0;var ret=(()=>{var time=Date.UTC(HEAP32[tmPtr+20>>>2>>>0]+1900,HEAP32[tmPtr+16>>>2>>>0],HEAP32[tmPtr+12>>>2>>>0],HEAP32[tmPtr+8>>>2>>>0],HEAP32[tmPtr+4>>>2>>>0],HEAP32[tmPtr>>>2>>>0],0);var date=new Date(time);HEAP32[tmPtr+24>>>2>>>0]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;return date.getTime()/1e3})();return BigInt(ret)};Module["__timegm_js"]=__timegm_js;__timegm_js.sig="jp";var __tzset_js=function(timezone,daylight,std_name,dst_name){timezone>>>=0;daylight>>>=0;std_name>>>=0;dst_name>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);var extractZone=date=>date.toLocaleTimeString(undefined,{hour12:false,timeZoneName:"short"}).split(" ")[1];var winterName=extractZone(winter);var summerName=extractZone(summer);if(summerOffset{abort("")};Module["_abort"]=_abort;_abort.sig="v";var readEmAsmArgsArray=[];Module["readEmAsmArgsArray"]=readEmAsmArgsArray;var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++>>>0]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>>2>>>0]:ch==106?HEAP64[buf>>>3]:ch==105?HEAP32[buf>>>2>>>0]:HEAPF64[buf>>>3>>>0]);buf+=wide?8:4}return readEmAsmArgsArray};Module["readEmAsmArgs"]=readEmAsmArgs;var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};Module["runEmAsmFunction"]=runEmAsmFunction;function _emscripten_asm_const_int(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}Module["_emscripten_asm_const_int"]=_emscripten_asm_const_int;_emscripten_asm_const_int.sig="ippp";function _emscripten_console_error(str){str>>>=0;console.error(UTF8ToString(str))}Module["_emscripten_console_error"]=_emscripten_console_error;_emscripten_console_error.sig="vp";function _emscripten_console_log(str){str>>>=0;console.log(UTF8ToString(str))}Module["_emscripten_console_log"]=_emscripten_console_log;_emscripten_console_log.sig="vp";function _emscripten_console_warn(str){str>>>=0;console.warn(UTF8ToString(str))}Module["_emscripten_console_warn"]=_emscripten_console_warn;_emscripten_console_warn.sig="vp";var _emscripten_date_now=()=>Date.now();Module["_emscripten_date_now"]=_emscripten_date_now;_emscripten_date_now.sig="d";function _emscripten_err(str){str>>>=0;return err(UTF8ToString(str))}Module["_emscripten_err"]=_emscripten_err;_emscripten_err.sig="vp";var _emscripten_exit_with_live_runtime=()=>{throw"unwind"};Module["_emscripten_exit_with_live_runtime"]=_emscripten_exit_with_live_runtime;_emscripten_exit_with_live_runtime.sig="v";var getHeapMax=()=>4294901760;Module["getHeapMax"]=getHeapMax;function _emscripten_get_heap_max(){return getHeapMax()}Module["_emscripten_get_heap_max"]=_emscripten_get_heap_max;_emscripten_get_heap_max.sig="p";var _emscripten_get_now_res=()=>{if(ENVIRONMENT_IS_NODE){return 1}return 1e3};Module["_emscripten_get_now_res"]=_emscripten_get_now_res;_emscripten_get_now_res.sig="d";var webgl_enable_ANGLE_instanced_arrays=ctx=>{var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=(index,divisor)=>ext["vertexAttribDivisorANGLE"](index,divisor);ctx["drawArraysInstanced"]=(mode,first,count,primcount)=>ext["drawArraysInstancedANGLE"](mode,first,count,primcount);ctx["drawElementsInstanced"]=(mode,count,type,indices,primcount)=>ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount);return 1}};Module["webgl_enable_ANGLE_instanced_arrays"]=webgl_enable_ANGLE_instanced_arrays;var webgl_enable_OES_vertex_array_object=ctx=>{var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=()=>ext["createVertexArrayOES"]();ctx["deleteVertexArray"]=vao=>ext["deleteVertexArrayOES"](vao);ctx["bindVertexArray"]=vao=>ext["bindVertexArrayOES"](vao);ctx["isVertexArray"]=vao=>ext["isVertexArrayOES"](vao);return 1}};Module["webgl_enable_OES_vertex_array_object"]=webgl_enable_OES_vertex_array_object;var webgl_enable_WEBGL_draw_buffers=ctx=>{var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=(n,bufs)=>ext["drawBuffersWEBGL"](n,bufs);return 1}};Module["webgl_enable_WEBGL_draw_buffers"]=webgl_enable_WEBGL_draw_buffers;var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));Module["webgl_enable_WEBGL_multi_draw"]=webgl_enable_WEBGL_multi_draw;var getEmscriptenSupportedExtensions=ctx=>{var supportedExtensions=["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_disjoint_timer_query","EXT_frag_depth","EXT_shader_texture_load","EXT_sRGB","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_depth_texture","WEBGL_draw_buffers","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_float_blend","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_blend_func_extended","WEBGL_compressed_texture_astc","WEBGL_compressed_texture_etc","WEBGL_compressed_texture_etc1","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw"];return(ctx.getSupportedExtensions()||[]).filter(ext=>supportedExtensions.includes(ext))};Module["getEmscriptenSupportedExtensions"]=getEmscriptenSupportedExtensions;var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],stringCache:{},unpackAlignment:4,recordError:errorCode=>{if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{for(var i=0;i>>2>>>0]=id}},getSource:(shader,count,string,length)=>{var source="";for(var i=0;i>>2>>>0]:undefined;source+=UTF8ToString(HEAPU32[string+i*4>>>2>>>0],len)}return source},createContext:(canvas,webGLContextAttributes)=>{var ctx=canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module.ctx=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_ANGLE_instanced_arrays(GLctx);webgl_enable_OES_vertex_array_object(GLctx);webgl_enable_WEBGL_draw_buffers(GLctx);{GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}webgl_enable_WEBGL_multi_draw(GLctx);getEmscriptenSupportedExtensions(GLctx).forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};Module["GL"]=GL;var _glActiveTexture=x0=>GLctx.activeTexture(x0);Module["_glActiveTexture"]=_glActiveTexture;_glActiveTexture.sig="vi";var _emscripten_glActiveTexture=_glActiveTexture;Module["_emscripten_glActiveTexture"]=_emscripten_glActiveTexture;_emscripten_glActiveTexture.sig="vi";var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};Module["_glAttachShader"]=_glAttachShader;_glAttachShader.sig="vii";var _emscripten_glAttachShader=_glAttachShader;Module["_emscripten_glAttachShader"]=_emscripten_glAttachShader;_emscripten_glAttachShader.sig="vii";var _glBeginQueryEXT=(target,id)=>{GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.queries[id])};Module["_glBeginQueryEXT"]=_glBeginQueryEXT;_glBeginQueryEXT.sig="vii";var _emscripten_glBeginQueryEXT=_glBeginQueryEXT;Module["_emscripten_glBeginQueryEXT"]=_emscripten_glBeginQueryEXT;function _glBindAttribLocation(program,index,name){name>>>=0;GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}Module["_glBindAttribLocation"]=_glBindAttribLocation;_glBindAttribLocation.sig="viip";var _emscripten_glBindAttribLocation=_glBindAttribLocation;Module["_emscripten_glBindAttribLocation"]=_emscripten_glBindAttribLocation;_emscripten_glBindAttribLocation.sig="viip";var _glBindBuffer=(target,buffer)=>{GLctx.bindBuffer(target,GL.buffers[buffer])};Module["_glBindBuffer"]=_glBindBuffer;_glBindBuffer.sig="vii";var _emscripten_glBindBuffer=_glBindBuffer;Module["_emscripten_glBindBuffer"]=_emscripten_glBindBuffer;_emscripten_glBindBuffer.sig="vii";var _glBindFramebuffer=(target,framebuffer)=>{GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])};Module["_glBindFramebuffer"]=_glBindFramebuffer;_glBindFramebuffer.sig="vii";var _emscripten_glBindFramebuffer=_glBindFramebuffer;Module["_emscripten_glBindFramebuffer"]=_emscripten_glBindFramebuffer;_emscripten_glBindFramebuffer.sig="vii";var _glBindRenderbuffer=(target,renderbuffer)=>{GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])};Module["_glBindRenderbuffer"]=_glBindRenderbuffer;_glBindRenderbuffer.sig="vii";var _emscripten_glBindRenderbuffer=_glBindRenderbuffer;Module["_emscripten_glBindRenderbuffer"]=_emscripten_glBindRenderbuffer;_emscripten_glBindRenderbuffer.sig="vii";var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};Module["_glBindTexture"]=_glBindTexture;_glBindTexture.sig="vii";var _emscripten_glBindTexture=_glBindTexture;Module["_emscripten_glBindTexture"]=_emscripten_glBindTexture;_emscripten_glBindTexture.sig="vii";var _glBindVertexArray=vao=>{GLctx.bindVertexArray(GL.vaos[vao])};Module["_glBindVertexArray"]=_glBindVertexArray;_glBindVertexArray.sig="vi";var _glBindVertexArrayOES=_glBindVertexArray;Module["_glBindVertexArrayOES"]=_glBindVertexArrayOES;_glBindVertexArrayOES.sig="vi";var _emscripten_glBindVertexArrayOES=_glBindVertexArrayOES;Module["_emscripten_glBindVertexArrayOES"]=_emscripten_glBindVertexArrayOES;_emscripten_glBindVertexArrayOES.sig="vi";var _glBlendColor=(x0,x1,x2,x3)=>GLctx.blendColor(x0,x1,x2,x3);Module["_glBlendColor"]=_glBlendColor;_glBlendColor.sig="vffff";var _emscripten_glBlendColor=_glBlendColor;Module["_emscripten_glBlendColor"]=_emscripten_glBlendColor;_emscripten_glBlendColor.sig="vffff";var _glBlendEquation=x0=>GLctx.blendEquation(x0);Module["_glBlendEquation"]=_glBlendEquation;_glBlendEquation.sig="vi";var _emscripten_glBlendEquation=_glBlendEquation;Module["_emscripten_glBlendEquation"]=_emscripten_glBlendEquation;_emscripten_glBlendEquation.sig="vi";var _glBlendEquationSeparate=(x0,x1)=>GLctx.blendEquationSeparate(x0,x1);Module["_glBlendEquationSeparate"]=_glBlendEquationSeparate;_glBlendEquationSeparate.sig="vii";var _emscripten_glBlendEquationSeparate=_glBlendEquationSeparate;Module["_emscripten_glBlendEquationSeparate"]=_emscripten_glBlendEquationSeparate;_emscripten_glBlendEquationSeparate.sig="vii";var _glBlendFunc=(x0,x1)=>GLctx.blendFunc(x0,x1);Module["_glBlendFunc"]=_glBlendFunc;_glBlendFunc.sig="vii";var _emscripten_glBlendFunc=_glBlendFunc;Module["_emscripten_glBlendFunc"]=_emscripten_glBlendFunc;_emscripten_glBlendFunc.sig="vii";var _glBlendFuncSeparate=(x0,x1,x2,x3)=>GLctx.blendFuncSeparate(x0,x1,x2,x3);Module["_glBlendFuncSeparate"]=_glBlendFuncSeparate;_glBlendFuncSeparate.sig="viiii";var _emscripten_glBlendFuncSeparate=_glBlendFuncSeparate;Module["_emscripten_glBlendFuncSeparate"]=_emscripten_glBlendFuncSeparate;_emscripten_glBlendFuncSeparate.sig="viiii";function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}Module["_glBufferData"]=_glBufferData;_glBufferData.sig="vippi";var _emscripten_glBufferData=_glBufferData;Module["_emscripten_glBufferData"]=_emscripten_glBufferData;_emscripten_glBufferData.sig="vippi";function _glBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;GLctx.bufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}Module["_glBufferSubData"]=_glBufferSubData;_glBufferSubData.sig="vippp";var _emscripten_glBufferSubData=_glBufferSubData;Module["_emscripten_glBufferSubData"]=_emscripten_glBufferSubData;_emscripten_glBufferSubData.sig="vippp";var _glCheckFramebufferStatus=x0=>GLctx.checkFramebufferStatus(x0);Module["_glCheckFramebufferStatus"]=_glCheckFramebufferStatus;_glCheckFramebufferStatus.sig="ii";var _emscripten_glCheckFramebufferStatus=_glCheckFramebufferStatus;Module["_emscripten_glCheckFramebufferStatus"]=_emscripten_glCheckFramebufferStatus;_emscripten_glCheckFramebufferStatus.sig="ii";var _glClear=x0=>GLctx.clear(x0);Module["_glClear"]=_glClear;_glClear.sig="vi";var _emscripten_glClear=_glClear;Module["_emscripten_glClear"]=_emscripten_glClear;_emscripten_glClear.sig="vi";var _glClearColor=(x0,x1,x2,x3)=>GLctx.clearColor(x0,x1,x2,x3);Module["_glClearColor"]=_glClearColor;_glClearColor.sig="vffff";var _emscripten_glClearColor=_glClearColor;Module["_emscripten_glClearColor"]=_emscripten_glClearColor;_emscripten_glClearColor.sig="vffff";var _glClearDepthf=x0=>GLctx.clearDepth(x0);Module["_glClearDepthf"]=_glClearDepthf;_glClearDepthf.sig="vf";var _emscripten_glClearDepthf=_glClearDepthf;Module["_emscripten_glClearDepthf"]=_emscripten_glClearDepthf;_emscripten_glClearDepthf.sig="vf";var _glClearStencil=x0=>GLctx.clearStencil(x0);Module["_glClearStencil"]=_glClearStencil;_glClearStencil.sig="vi";var _emscripten_glClearStencil=_glClearStencil;Module["_emscripten_glClearStencil"]=_emscripten_glClearStencil;_emscripten_glClearStencil.sig="vi";var _glColorMask=(red,green,blue,alpha)=>{GLctx.colorMask(!!red,!!green,!!blue,!!alpha)};Module["_glColorMask"]=_glColorMask;_glColorMask.sig="viiii";var _emscripten_glColorMask=_glColorMask;Module["_emscripten_glColorMask"]=_emscripten_glColorMask;_emscripten_glColorMask.sig="viiii";var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};Module["_glCompileShader"]=_glCompileShader;_glCompileShader.sig="vi";var _emscripten_glCompileShader=_glCompileShader;Module["_emscripten_glCompileShader"]=_emscripten_glCompileShader;_emscripten_glCompileShader.sig="vi";function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){data>>>=0;GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data>>>0,data+imageSize>>>0):null)}Module["_glCompressedTexImage2D"]=_glCompressedTexImage2D;_glCompressedTexImage2D.sig="viiiiiiip";var _emscripten_glCompressedTexImage2D=_glCompressedTexImage2D;Module["_emscripten_glCompressedTexImage2D"]=_emscripten_glCompressedTexImage2D;_emscripten_glCompressedTexImage2D.sig="viiiiiiip";function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){data>>>=0;GLctx.compressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data>>>0,data+imageSize>>>0):null)}Module["_glCompressedTexSubImage2D"]=_glCompressedTexSubImage2D;_glCompressedTexSubImage2D.sig="viiiiiiiip";var _emscripten_glCompressedTexSubImage2D=_glCompressedTexSubImage2D;Module["_emscripten_glCompressedTexSubImage2D"]=_emscripten_glCompressedTexSubImage2D;_emscripten_glCompressedTexSubImage2D.sig="viiiiiiiip";var _glCopyTexImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7);Module["_glCopyTexImage2D"]=_glCopyTexImage2D;_glCopyTexImage2D.sig="viiiiiiii";var _emscripten_glCopyTexImage2D=_glCopyTexImage2D;Module["_emscripten_glCopyTexImage2D"]=_emscripten_glCopyTexImage2D;_emscripten_glCopyTexImage2D.sig="viiiiiiii";var _glCopyTexSubImage2D=(x0,x1,x2,x3,x4,x5,x6,x7)=>GLctx.copyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7);Module["_glCopyTexSubImage2D"]=_glCopyTexSubImage2D;_glCopyTexSubImage2D.sig="viiiiiiii";var _emscripten_glCopyTexSubImage2D=_glCopyTexSubImage2D;Module["_emscripten_glCopyTexSubImage2D"]=_emscripten_glCopyTexSubImage2D;_emscripten_glCopyTexSubImage2D.sig="viiiiiiii";var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};Module["_glCreateProgram"]=_glCreateProgram;_glCreateProgram.sig="i";var _emscripten_glCreateProgram=_glCreateProgram;Module["_emscripten_glCreateProgram"]=_emscripten_glCreateProgram;_emscripten_glCreateProgram.sig="i";var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};Module["_glCreateShader"]=_glCreateShader;_glCreateShader.sig="ii";var _emscripten_glCreateShader=_glCreateShader;Module["_emscripten_glCreateShader"]=_emscripten_glCreateShader;_emscripten_glCreateShader.sig="ii";var _glCullFace=x0=>GLctx.cullFace(x0);Module["_glCullFace"]=_glCullFace;_glCullFace.sig="vi";var _emscripten_glCullFace=_glCullFace;Module["_emscripten_glCullFace"]=_emscripten_glCullFace;_emscripten_glCullFace.sig="vi";function _glDeleteBuffers(n,buffers){buffers>>>=0;for(var i=0;i>>2>>>0];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null}}Module["_glDeleteBuffers"]=_glDeleteBuffers;_glDeleteBuffers.sig="vip";var _emscripten_glDeleteBuffers=_glDeleteBuffers;Module["_emscripten_glDeleteBuffers"]=_emscripten_glDeleteBuffers;_emscripten_glDeleteBuffers.sig="vip";function _glDeleteFramebuffers(n,framebuffers){framebuffers>>>=0;for(var i=0;i>>2>>>0];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}Module["_glDeleteFramebuffers"]=_glDeleteFramebuffers;_glDeleteFramebuffers.sig="vip";var _emscripten_glDeleteFramebuffers=_glDeleteFramebuffers;Module["_emscripten_glDeleteFramebuffers"]=_emscripten_glDeleteFramebuffers;_emscripten_glDeleteFramebuffers.sig="vip";var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};Module["_glDeleteProgram"]=_glDeleteProgram;_glDeleteProgram.sig="vi";var _emscripten_glDeleteProgram=_glDeleteProgram;Module["_emscripten_glDeleteProgram"]=_emscripten_glDeleteProgram;_emscripten_glDeleteProgram.sig="vi";function _glDeleteQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0];var query=GL.queries[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.queries[id]=null}}Module["_glDeleteQueriesEXT"]=_glDeleteQueriesEXT;_glDeleteQueriesEXT.sig="vip";var _emscripten_glDeleteQueriesEXT=_glDeleteQueriesEXT;Module["_emscripten_glDeleteQueriesEXT"]=_emscripten_glDeleteQueriesEXT;function _glDeleteRenderbuffers(n,renderbuffers){renderbuffers>>>=0;for(var i=0;i>>2>>>0];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}Module["_glDeleteRenderbuffers"]=_glDeleteRenderbuffers;_glDeleteRenderbuffers.sig="vip";var _emscripten_glDeleteRenderbuffers=_glDeleteRenderbuffers;Module["_emscripten_glDeleteRenderbuffers"]=_emscripten_glDeleteRenderbuffers;_emscripten_glDeleteRenderbuffers.sig="vip";var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};Module["_glDeleteShader"]=_glDeleteShader;_glDeleteShader.sig="vi";var _emscripten_glDeleteShader=_glDeleteShader;Module["_emscripten_glDeleteShader"]=_emscripten_glDeleteShader;_emscripten_glDeleteShader.sig="vi";function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}Module["_glDeleteTextures"]=_glDeleteTextures;_glDeleteTextures.sig="vip";var _emscripten_glDeleteTextures=_glDeleteTextures;Module["_emscripten_glDeleteTextures"]=_emscripten_glDeleteTextures;_emscripten_glDeleteTextures.sig="vip";function _glDeleteVertexArrays(n,vaos){vaos>>>=0;for(var i=0;i>>2>>>0];GLctx.deleteVertexArray(GL.vaos[id]);GL.vaos[id]=null}}Module["_glDeleteVertexArrays"]=_glDeleteVertexArrays;_glDeleteVertexArrays.sig="vip";var _glDeleteVertexArraysOES=_glDeleteVertexArrays;Module["_glDeleteVertexArraysOES"]=_glDeleteVertexArraysOES;_glDeleteVertexArraysOES.sig="vip";var _emscripten_glDeleteVertexArraysOES=_glDeleteVertexArraysOES;Module["_emscripten_glDeleteVertexArraysOES"]=_emscripten_glDeleteVertexArraysOES;_emscripten_glDeleteVertexArraysOES.sig="vip";var _glDepthFunc=x0=>GLctx.depthFunc(x0);Module["_glDepthFunc"]=_glDepthFunc;_glDepthFunc.sig="vi";var _emscripten_glDepthFunc=_glDepthFunc;Module["_emscripten_glDepthFunc"]=_emscripten_glDepthFunc;_emscripten_glDepthFunc.sig="vi";var _glDepthMask=flag=>{GLctx.depthMask(!!flag)};Module["_glDepthMask"]=_glDepthMask;_glDepthMask.sig="vi";var _emscripten_glDepthMask=_glDepthMask;Module["_emscripten_glDepthMask"]=_emscripten_glDepthMask;_emscripten_glDepthMask.sig="vi";var _glDepthRangef=(x0,x1)=>GLctx.depthRange(x0,x1);Module["_glDepthRangef"]=_glDepthRangef;_glDepthRangef.sig="vff";var _emscripten_glDepthRangef=_glDepthRangef;Module["_emscripten_glDepthRangef"]=_emscripten_glDepthRangef;_emscripten_glDepthRangef.sig="vff";var _glDetachShader=(program,shader)=>{GLctx.detachShader(GL.programs[program],GL.shaders[shader])};Module["_glDetachShader"]=_glDetachShader;_glDetachShader.sig="vii";var _emscripten_glDetachShader=_glDetachShader;Module["_emscripten_glDetachShader"]=_emscripten_glDetachShader;_emscripten_glDetachShader.sig="vii";var _glDisable=x0=>GLctx.disable(x0);Module["_glDisable"]=_glDisable;_glDisable.sig="vi";var _emscripten_glDisable=_glDisable;Module["_emscripten_glDisable"]=_emscripten_glDisable;_emscripten_glDisable.sig="vi";var _glDisableVertexAttribArray=index=>{GLctx.disableVertexAttribArray(index)};Module["_glDisableVertexAttribArray"]=_glDisableVertexAttribArray;_glDisableVertexAttribArray.sig="vi";var _emscripten_glDisableVertexAttribArray=_glDisableVertexAttribArray;Module["_emscripten_glDisableVertexAttribArray"]=_emscripten_glDisableVertexAttribArray;_emscripten_glDisableVertexAttribArray.sig="vi";var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};Module["_glDrawArrays"]=_glDrawArrays;_glDrawArrays.sig="viii";var _emscripten_glDrawArrays=_glDrawArrays;Module["_emscripten_glDrawArrays"]=_emscripten_glDrawArrays;_emscripten_glDrawArrays.sig="viii";var _glDrawArraysInstanced=(mode,first,count,primcount)=>{GLctx.drawArraysInstanced(mode,first,count,primcount)};Module["_glDrawArraysInstanced"]=_glDrawArraysInstanced;_glDrawArraysInstanced.sig="viiii";var _glDrawArraysInstancedANGLE=_glDrawArraysInstanced;Module["_glDrawArraysInstancedANGLE"]=_glDrawArraysInstancedANGLE;var _emscripten_glDrawArraysInstancedANGLE=_glDrawArraysInstancedANGLE;Module["_emscripten_glDrawArraysInstancedANGLE"]=_emscripten_glDrawArraysInstancedANGLE;var tempFixedLengthArray=[];Module["tempFixedLengthArray"]=tempFixedLengthArray;function _glDrawBuffers(n,bufs){bufs>>>=0;var bufArray=tempFixedLengthArray[n];for(var i=0;i>>2>>>0]}GLctx.drawBuffers(bufArray)}Module["_glDrawBuffers"]=_glDrawBuffers;_glDrawBuffers.sig="vip";var _glDrawBuffersWEBGL=_glDrawBuffers;Module["_glDrawBuffersWEBGL"]=_glDrawBuffersWEBGL;var _emscripten_glDrawBuffersWEBGL=_glDrawBuffersWEBGL;Module["_emscripten_glDrawBuffersWEBGL"]=_emscripten_glDrawBuffersWEBGL;function _glDrawElements(mode,count,type,indices){indices>>>=0;GLctx.drawElements(mode,count,type,indices)}Module["_glDrawElements"]=_glDrawElements;_glDrawElements.sig="viiip";var _emscripten_glDrawElements=_glDrawElements;Module["_emscripten_glDrawElements"]=_emscripten_glDrawElements;_emscripten_glDrawElements.sig="viiip";function _glDrawElementsInstanced(mode,count,type,indices,primcount){indices>>>=0;GLctx.drawElementsInstanced(mode,count,type,indices,primcount)}Module["_glDrawElementsInstanced"]=_glDrawElementsInstanced;_glDrawElementsInstanced.sig="viiipi";var _glDrawElementsInstancedANGLE=_glDrawElementsInstanced;Module["_glDrawElementsInstancedANGLE"]=_glDrawElementsInstancedANGLE;var _emscripten_glDrawElementsInstancedANGLE=_glDrawElementsInstancedANGLE;Module["_emscripten_glDrawElementsInstancedANGLE"]=_emscripten_glDrawElementsInstancedANGLE;var _glEnable=x0=>GLctx.enable(x0);Module["_glEnable"]=_glEnable;_glEnable.sig="vi";var _emscripten_glEnable=_glEnable;Module["_emscripten_glEnable"]=_emscripten_glEnable;_emscripten_glEnable.sig="vi";var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};Module["_glEnableVertexAttribArray"]=_glEnableVertexAttribArray;_glEnableVertexAttribArray.sig="vi";var _emscripten_glEnableVertexAttribArray=_glEnableVertexAttribArray;Module["_emscripten_glEnableVertexAttribArray"]=_emscripten_glEnableVertexAttribArray;_emscripten_glEnableVertexAttribArray.sig="vi";var _glEndQueryEXT=target=>{GLctx.disjointTimerQueryExt["endQueryEXT"](target)};Module["_glEndQueryEXT"]=_glEndQueryEXT;_glEndQueryEXT.sig="vi";var _emscripten_glEndQueryEXT=_glEndQueryEXT;Module["_emscripten_glEndQueryEXT"]=_emscripten_glEndQueryEXT;var _glFinish=()=>GLctx.finish();Module["_glFinish"]=_glFinish;_glFinish.sig="v";var _emscripten_glFinish=_glFinish;Module["_emscripten_glFinish"]=_emscripten_glFinish;_emscripten_glFinish.sig="v";var _glFlush=()=>GLctx.flush();Module["_glFlush"]=_glFlush;_glFlush.sig="v";var _emscripten_glFlush=_glFlush;Module["_emscripten_glFlush"]=_emscripten_glFlush;_emscripten_glFlush.sig="v";var _glFramebufferRenderbuffer=(target,attachment,renderbuffertarget,renderbuffer)=>{GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])};Module["_glFramebufferRenderbuffer"]=_glFramebufferRenderbuffer;_glFramebufferRenderbuffer.sig="viiii";var _emscripten_glFramebufferRenderbuffer=_glFramebufferRenderbuffer;Module["_emscripten_glFramebufferRenderbuffer"]=_emscripten_glFramebufferRenderbuffer;_emscripten_glFramebufferRenderbuffer.sig="viiii";var _glFramebufferTexture2D=(target,attachment,textarget,texture,level)=>{GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)};Module["_glFramebufferTexture2D"]=_glFramebufferTexture2D;_glFramebufferTexture2D.sig="viiiii";var _emscripten_glFramebufferTexture2D=_glFramebufferTexture2D;Module["_emscripten_glFramebufferTexture2D"]=_emscripten_glFramebufferTexture2D;_emscripten_glFramebufferTexture2D.sig="viiiii";var _glFrontFace=x0=>GLctx.frontFace(x0);Module["_glFrontFace"]=_glFrontFace;_glFrontFace.sig="vi";var _emscripten_glFrontFace=_glFrontFace;Module["_emscripten_glFrontFace"]=_emscripten_glFrontFace;_emscripten_glFrontFace.sig="vi";function _glGenBuffers(n,buffers){buffers>>>=0;GL.genObject(n,buffers,"createBuffer",GL.buffers)}Module["_glGenBuffers"]=_glGenBuffers;_glGenBuffers.sig="vip";var _emscripten_glGenBuffers=_glGenBuffers;Module["_emscripten_glGenBuffers"]=_emscripten_glGenBuffers;_emscripten_glGenBuffers.sig="vip";function _glGenFramebuffers(n,ids){ids>>>=0;GL.genObject(n,ids,"createFramebuffer",GL.framebuffers)}Module["_glGenFramebuffers"]=_glGenFramebuffers;_glGenFramebuffers.sig="vip";var _emscripten_glGenFramebuffers=_glGenFramebuffers;Module["_emscripten_glGenFramebuffers"]=_emscripten_glGenFramebuffers;_emscripten_glGenFramebuffers.sig="vip";function _glGenQueriesEXT(n,ids){ids>>>=0;for(var i=0;i>>2>>>0]=0;return}var id=GL.getNewId(GL.queries);query.name=id;GL.queries[id]=query;HEAP32[ids+i*4>>>2>>>0]=id}}Module["_glGenQueriesEXT"]=_glGenQueriesEXT;_glGenQueriesEXT.sig="vip";var _emscripten_glGenQueriesEXT=_glGenQueriesEXT;Module["_emscripten_glGenQueriesEXT"]=_emscripten_glGenQueriesEXT;function _glGenRenderbuffers(n,renderbuffers){renderbuffers>>>=0;GL.genObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}Module["_glGenRenderbuffers"]=_glGenRenderbuffers;_glGenRenderbuffers.sig="vip";var _emscripten_glGenRenderbuffers=_glGenRenderbuffers;Module["_emscripten_glGenRenderbuffers"]=_emscripten_glGenRenderbuffers;_emscripten_glGenRenderbuffers.sig="vip";function _glGenTextures(n,textures){textures>>>=0;GL.genObject(n,textures,"createTexture",GL.textures)}Module["_glGenTextures"]=_glGenTextures;_glGenTextures.sig="vip";var _emscripten_glGenTextures=_glGenTextures;Module["_emscripten_glGenTextures"]=_emscripten_glGenTextures;_emscripten_glGenTextures.sig="vip";function _glGenVertexArrays(n,arrays){arrays>>>=0;GL.genObject(n,arrays,"createVertexArray",GL.vaos)}Module["_glGenVertexArrays"]=_glGenVertexArrays;_glGenVertexArrays.sig="vip";var _glGenVertexArraysOES=_glGenVertexArrays;Module["_glGenVertexArraysOES"]=_glGenVertexArraysOES;_glGenVertexArraysOES.sig="vip";var _emscripten_glGenVertexArraysOES=_glGenVertexArraysOES;Module["_emscripten_glGenVertexArraysOES"]=_emscripten_glGenVertexArraysOES;_emscripten_glGenVertexArraysOES.sig="vip";var _glGenerateMipmap=x0=>GLctx.generateMipmap(x0);Module["_glGenerateMipmap"]=_glGenerateMipmap;_glGenerateMipmap.sig="vi";var _emscripten_glGenerateMipmap=_glGenerateMipmap;Module["_emscripten_glGenerateMipmap"]=_emscripten_glGenerateMipmap;_emscripten_glGenerateMipmap.sig="vi";var __glGetActiveAttribOrUniform=(funcName,program,index,bufSize,length,size,type,name)=>{program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull;if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}};Module["__glGetActiveAttribOrUniform"]=__glGetActiveAttribOrUniform;function _glGetActiveAttrib(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;__glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}Module["_glGetActiveAttrib"]=_glGetActiveAttrib;_glGetActiveAttrib.sig="viiipppp";var _emscripten_glGetActiveAttrib=_glGetActiveAttrib;Module["_emscripten_glGetActiveAttrib"]=_emscripten_glGetActiveAttrib;_emscripten_glGetActiveAttrib.sig="viiipppp";function _glGetActiveUniform(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}Module["_glGetActiveUniform"]=_glGetActiveUniform;_glGetActiveUniform.sig="viiipppp";var _emscripten_glGetActiveUniform=_glGetActiveUniform;Module["_emscripten_glGetActiveUniform"]=_emscripten_glGetActiveUniform;_emscripten_glGetActiveUniform.sig="viiipppp";function _glGetAttachedShaders(program,maxCount,count,shaders){count>>>=0;shaders>>>=0;var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>>2>>>0]=len;for(var i=0;i>>2>>>0]=id}}Module["_glGetAttachedShaders"]=_glGetAttachedShaders;_glGetAttachedShaders.sig="viipp";var _emscripten_glGetAttachedShaders=_glGetAttachedShaders;Module["_emscripten_glGetAttachedShaders"]=_emscripten_glGetAttachedShaders;_emscripten_glGetAttachedShaders.sig="viipp";function _glGetAttribLocation(program,name){name>>>=0;return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}Module["_glGetAttribLocation"]=_glGetAttribLocation;_glGetAttribLocation.sig="iip";var _emscripten_glGetAttribLocation=_glGetAttribLocation;Module["_emscripten_glGetAttribLocation"]=_emscripten_glGetAttribLocation;_emscripten_glGetAttribLocation.sig="iip";var writeI53ToI64=(ptr,num)=>{HEAPU32[ptr>>>2>>>0]=num;var lower=HEAPU32[ptr>>>2>>>0];HEAPU32[ptr+4>>>2>>>0]=(num-lower)/4294967296};Module["writeI53ToI64"]=writeI53ToI64;var emscriptenWebGLGet=(name_,p,type)=>{if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>>2>>>0]=result[i];break;case 2:HEAPF32[p+i*4>>>2>>>0]=result[i];break;case 4:HEAP8[p+i>>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`);return}}break;default:GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!`);return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>>2>>>0]=ret;break;case 2:HEAPF32[p>>>2>>>0]=ret;break;case 4:HEAP8[p>>>0]=ret?1:0;break}};Module["emscriptenWebGLGet"]=emscriptenWebGLGet;function _glGetBooleanv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,4)}Module["_glGetBooleanv"]=_glGetBooleanv;_glGetBooleanv.sig="vip";var _emscripten_glGetBooleanv=_glGetBooleanv;Module["_emscripten_glGetBooleanv"]=_emscripten_glGetBooleanv;_emscripten_glGetBooleanv.sig="vip";function _glGetBufferParameteriv(target,value,data){data>>>=0;if(!data){GL.recordError(1281);return}HEAP32[data>>>2>>>0]=GLctx.getBufferParameter(target,value)}Module["_glGetBufferParameteriv"]=_glGetBufferParameteriv;_glGetBufferParameteriv.sig="viip";var _emscripten_glGetBufferParameteriv=_glGetBufferParameteriv;Module["_emscripten_glGetBufferParameteriv"]=_emscripten_glGetBufferParameteriv;_emscripten_glGetBufferParameteriv.sig="viip";var _glGetError=()=>{var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error};Module["_glGetError"]=_glGetError;_glGetError.sig="i";var _emscripten_glGetError=_glGetError;Module["_emscripten_glGetError"]=_emscripten_glGetError;_emscripten_glGetError.sig="i";function _glGetFloatv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,2)}Module["_glGetFloatv"]=_glGetFloatv;_glGetFloatv.sig="vip";var _emscripten_glGetFloatv=_glGetFloatv;Module["_emscripten_glGetFloatv"]=_emscripten_glGetFloatv;_emscripten_glGetFloatv.sig="vip";function _glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){params>>>=0;var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>>2>>>0]=result}Module["_glGetFramebufferAttachmentParameteriv"]=_glGetFramebufferAttachmentParameteriv;_glGetFramebufferAttachmentParameteriv.sig="viiip";var _emscripten_glGetFramebufferAttachmentParameteriv=_glGetFramebufferAttachmentParameteriv;Module["_emscripten_glGetFramebufferAttachmentParameteriv"]=_emscripten_glGetFramebufferAttachmentParameteriv;_emscripten_glGetFramebufferAttachmentParameteriv.sig="viiip";function _glGetIntegerv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,0)}Module["_glGetIntegerv"]=_glGetIntegerv;_glGetIntegerv.sig="vip";var _emscripten_glGetIntegerv=_glGetIntegerv;Module["_emscripten_glGetIntegerv"]=_emscripten_glGetIntegerv;_emscripten_glGetIntegerv.sig="vip";function _glGetProgramInfoLog(program,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}Module["_glGetProgramInfoLog"]=_glGetProgramInfoLog;_glGetProgramInfoLog.sig="viipp";var _emscripten_glGetProgramInfoLog=_glGetProgramInfoLog;Module["_emscripten_glGetProgramInfoLog"]=_emscripten_glGetProgramInfoLog;_emscripten_glGetProgramInfoLog.sig="viipp";function _glGetProgramiv(program,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>>2>>>0]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i>>2>>>0]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i>>2>>>0]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i>>2>>>0]=program.maxUniformBlockNameLength}else{HEAP32[p>>>2>>>0]=GLctx.getProgramParameter(program,pname)}}Module["_glGetProgramiv"]=_glGetProgramiv;_glGetProgramiv.sig="viip";var _emscripten_glGetProgramiv=_glGetProgramiv;Module["_emscripten_glGetProgramiv"]=_emscripten_glGetProgramiv;_emscripten_glGetProgramiv.sig="viip";function _glGetQueryObjecti64vEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;{param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}Module["_glGetQueryObjecti64vEXT"]=_glGetQueryObjecti64vEXT;_glGetQueryObjecti64vEXT.sig="viip";var _emscripten_glGetQueryObjecti64vEXT=_glGetQueryObjecti64vEXT;Module["_emscripten_glGetQueryObjecti64vEXT"]=_emscripten_glGetQueryObjecti64vEXT;function _glGetQueryObjectivEXT(id,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>>2>>>0]=ret}Module["_glGetQueryObjectivEXT"]=_glGetQueryObjectivEXT;_glGetQueryObjectivEXT.sig="viip";var _emscripten_glGetQueryObjectivEXT=_glGetQueryObjectivEXT;Module["_emscripten_glGetQueryObjectivEXT"]=_emscripten_glGetQueryObjectivEXT;var _glGetQueryObjectui64vEXT=_glGetQueryObjecti64vEXT;Module["_glGetQueryObjectui64vEXT"]=_glGetQueryObjectui64vEXT;var _emscripten_glGetQueryObjectui64vEXT=_glGetQueryObjectui64vEXT;Module["_emscripten_glGetQueryObjectui64vEXT"]=_emscripten_glGetQueryObjectui64vEXT;var _glGetQueryObjectuivEXT=_glGetQueryObjectivEXT;Module["_glGetQueryObjectuivEXT"]=_glGetQueryObjectuivEXT;var _emscripten_glGetQueryObjectuivEXT=_glGetQueryObjectuivEXT;Module["_emscripten_glGetQueryObjectuivEXT"]=_emscripten_glGetQueryObjectuivEXT;function _glGetQueryivEXT(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}Module["_glGetQueryivEXT"]=_glGetQueryivEXT;_glGetQueryivEXT.sig="viip";var _emscripten_glGetQueryivEXT=_glGetQueryivEXT;Module["_emscripten_glGetQueryivEXT"]=_emscripten_glGetQueryivEXT;function _glGetRenderbufferParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getRenderbufferParameter(target,pname)}Module["_glGetRenderbufferParameteriv"]=_glGetRenderbufferParameteriv;_glGetRenderbufferParameteriv.sig="viip";var _emscripten_glGetRenderbufferParameteriv=_glGetRenderbufferParameteriv;Module["_emscripten_glGetRenderbufferParameteriv"]=_emscripten_glGetRenderbufferParameteriv;_emscripten_glGetRenderbufferParameteriv.sig="viip";function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}Module["_glGetShaderInfoLog"]=_glGetShaderInfoLog;_glGetShaderInfoLog.sig="viipp";var _emscripten_glGetShaderInfoLog=_glGetShaderInfoLog;Module["_emscripten_glGetShaderInfoLog"]=_emscripten_glGetShaderInfoLog;_emscripten_glGetShaderInfoLog.sig="viipp";function _glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){range>>>=0;precision>>>=0;var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>>2>>>0]=result.rangeMin;HEAP32[range+4>>>2>>>0]=result.rangeMax;HEAP32[precision>>>2>>>0]=result.precision}Module["_glGetShaderPrecisionFormat"]=_glGetShaderPrecisionFormat;_glGetShaderPrecisionFormat.sig="viipp";var _emscripten_glGetShaderPrecisionFormat=_glGetShaderPrecisionFormat;Module["_emscripten_glGetShaderPrecisionFormat"]=_emscripten_glGetShaderPrecisionFormat;_emscripten_glGetShaderPrecisionFormat.sig="viipp";function _glGetShaderSource(shader,bufSize,length,source){length>>>=0;source>>>=0;var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}Module["_glGetShaderSource"]=_glGetShaderSource;_glGetShaderSource.sig="viipp";var _emscripten_glGetShaderSource=_glGetShaderSource;Module["_emscripten_glGetShaderSource"]=_emscripten_glGetShaderSource;_emscripten_glGetShaderSource.sig="viipp";function _glGetShaderiv(shader,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>>2>>>0]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>>2>>>0]=sourceLength}else{HEAP32[p>>>2>>>0]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}Module["_glGetShaderiv"]=_glGetShaderiv;_glGetShaderiv.sig="viip";var _emscripten_glGetShaderiv=_glGetShaderiv;Module["_emscripten_glGetShaderiv"]=_emscripten_glGetShaderiv;_emscripten_glGetShaderiv.sig="viip";var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};Module["stringToNewUTF8"]=stringToNewUTF8;var webglGetExtensions=function $webglGetExtensions(){var exts=getEmscriptenSupportedExtensions(GLctx);exts=exts.concat(exts.map(e=>"GL_"+e));return exts};Module["webglGetExtensions"]=webglGetExtensions;function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:ret=stringToNewUTF8(webglGetExtensions().join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s?stringToNewUTF8(s):0;break;case 7938:var glVersion=GLctx.getParameter(7938);{glVersion=`OpenGL ES 2.0 (${glVersion})`}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion=`OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}Module["_glGetString"]=_glGetString;_glGetString.sig="pi";var _emscripten_glGetString=_glGetString;Module["_emscripten_glGetString"]=_emscripten_glGetString;_emscripten_glGetString.sig="pi";function _glGetTexParameterfv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAPF32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}Module["_glGetTexParameterfv"]=_glGetTexParameterfv;_glGetTexParameterfv.sig="viip";var _emscripten_glGetTexParameterfv=_glGetTexParameterfv;Module["_emscripten_glGetTexParameterfv"]=_emscripten_glGetTexParameterfv;_emscripten_glGetTexParameterfv.sig="viip";function _glGetTexParameteriv(target,pname,params){params>>>=0;if(!params){GL.recordError(1281);return}HEAP32[params>>>2>>>0]=GLctx.getTexParameter(target,pname)}Module["_glGetTexParameteriv"]=_glGetTexParameteriv;_glGetTexParameteriv.sig="viip";var _emscripten_glGetTexParameteriv=_glGetTexParameteriv;Module["_emscripten_glGetTexParameteriv"]=_emscripten_glGetTexParameteriv;_emscripten_glGetTexParameteriv.sig="viip";var webglGetLeftBracePos=name=>name.slice(-1)=="]"&&name.lastIndexOf("[");Module["webglGetLeftBracePos"]=webglGetLeftBracePos;var webglPrepareUniformLocationsBeforeFirstUse=program=>{var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j>>=0;name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex{var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?`[${webglLoc}]`:""))}return webglLoc}else{GL.recordError(1282)}};Module["webglGetUniformLocation"]=webglGetUniformLocation;var emscriptenWebGLGetUniform=(program,location,params,type)=>{if(!params){GL.recordError(1281);return}program=GL.programs[program];webglPrepareUniformLocationsBeforeFirstUse(program);var data=GLctx.getUniform(program,webglGetUniformLocation(location));if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break}}}};Module["emscriptenWebGLGetUniform"]=emscriptenWebGLGetUniform;function _glGetUniformfv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,2)}Module["_glGetUniformfv"]=_glGetUniformfv;_glGetUniformfv.sig="viip";var _emscripten_glGetUniformfv=_glGetUniformfv;Module["_emscripten_glGetUniformfv"]=_emscripten_glGetUniformfv;_emscripten_glGetUniformfv.sig="viip";function _glGetUniformiv(program,location,params){params>>>=0;emscriptenWebGLGetUniform(program,location,params,0)}Module["_glGetUniformiv"]=_glGetUniformiv;_glGetUniformiv.sig="viip";var _emscripten_glGetUniformiv=_glGetUniformiv;Module["_emscripten_glGetUniformiv"]=_emscripten_glGetUniformiv;_emscripten_glGetUniformiv.sig="viip";function _glGetVertexAttribPointerv(index,pname,pointer){pointer>>>=0;if(!pointer){GL.recordError(1281);return}HEAP32[pointer>>>2>>>0]=GLctx.getVertexAttribOffset(index,pname)}Module["_glGetVertexAttribPointerv"]=_glGetVertexAttribPointerv;_glGetVertexAttribPointerv.sig="viip";var _emscripten_glGetVertexAttribPointerv=_glGetVertexAttribPointerv;Module["_emscripten_glGetVertexAttribPointerv"]=_emscripten_glGetVertexAttribPointerv;_emscripten_glGetVertexAttribPointerv.sig="viip";var emscriptenWebGLGetVertexAttrib=(index,pname,params,type)=>{if(!params){GL.recordError(1281);return}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>>2>>>0]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>>2>>>0]=data;break;case 2:HEAPF32[params>>>2>>>0]=data;break;case 5:HEAP32[params>>>2>>>0]=Math.fround(data);break}}else{for(var i=0;i>>2>>>0]=data[i];break;case 2:HEAPF32[params+i*4>>>2>>>0]=data[i];break;case 5:HEAP32[params+i*4>>>2>>>0]=Math.fround(data[i]);break}}}};Module["emscriptenWebGLGetVertexAttrib"]=emscriptenWebGLGetVertexAttrib;function _glGetVertexAttribfv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,2)}Module["_glGetVertexAttribfv"]=_glGetVertexAttribfv;_glGetVertexAttribfv.sig="viip";var _emscripten_glGetVertexAttribfv=_glGetVertexAttribfv;Module["_emscripten_glGetVertexAttribfv"]=_emscripten_glGetVertexAttribfv;_emscripten_glGetVertexAttribfv.sig="viip";function _glGetVertexAttribiv(index,pname,params){params>>>=0;emscriptenWebGLGetVertexAttrib(index,pname,params,5)}Module["_glGetVertexAttribiv"]=_glGetVertexAttribiv;_glGetVertexAttribiv.sig="viip";var _emscripten_glGetVertexAttribiv=_glGetVertexAttribiv;Module["_emscripten_glGetVertexAttribiv"]=_emscripten_glGetVertexAttribiv;_emscripten_glGetVertexAttribiv.sig="viip";var _glHint=(x0,x1)=>GLctx.hint(x0,x1);Module["_glHint"]=_glHint;_glHint.sig="vii";var _emscripten_glHint=_glHint;Module["_emscripten_glHint"]=_emscripten_glHint;_emscripten_glHint.sig="vii";var _glIsBuffer=buffer=>{var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)};Module["_glIsBuffer"]=_glIsBuffer;_glIsBuffer.sig="ii";var _emscripten_glIsBuffer=_glIsBuffer;Module["_emscripten_glIsBuffer"]=_emscripten_glIsBuffer;_emscripten_glIsBuffer.sig="ii";var _glIsEnabled=x0=>GLctx.isEnabled(x0);Module["_glIsEnabled"]=_glIsEnabled;_glIsEnabled.sig="ii";var _emscripten_glIsEnabled=_glIsEnabled;Module["_emscripten_glIsEnabled"]=_emscripten_glIsEnabled;_emscripten_glIsEnabled.sig="ii";var _glIsFramebuffer=framebuffer=>{var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)};Module["_glIsFramebuffer"]=_glIsFramebuffer;_glIsFramebuffer.sig="ii";var _emscripten_glIsFramebuffer=_glIsFramebuffer;Module["_emscripten_glIsFramebuffer"]=_emscripten_glIsFramebuffer;_emscripten_glIsFramebuffer.sig="ii";var _glIsProgram=program=>{program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)};Module["_glIsProgram"]=_glIsProgram;_glIsProgram.sig="ii";var _emscripten_glIsProgram=_glIsProgram;Module["_emscripten_glIsProgram"]=_emscripten_glIsProgram;_emscripten_glIsProgram.sig="ii";var _glIsQueryEXT=id=>{var query=GL.queries[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)};Module["_glIsQueryEXT"]=_glIsQueryEXT;_glIsQueryEXT.sig="ii";var _emscripten_glIsQueryEXT=_glIsQueryEXT;Module["_emscripten_glIsQueryEXT"]=_emscripten_glIsQueryEXT;var _glIsRenderbuffer=renderbuffer=>{var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)};Module["_glIsRenderbuffer"]=_glIsRenderbuffer;_glIsRenderbuffer.sig="ii";var _emscripten_glIsRenderbuffer=_glIsRenderbuffer;Module["_emscripten_glIsRenderbuffer"]=_emscripten_glIsRenderbuffer;_emscripten_glIsRenderbuffer.sig="ii";var _glIsShader=shader=>{var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)};Module["_glIsShader"]=_glIsShader;_glIsShader.sig="ii";var _emscripten_glIsShader=_glIsShader;Module["_emscripten_glIsShader"]=_emscripten_glIsShader;_emscripten_glIsShader.sig="ii";var _glIsTexture=id=>{var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)};Module["_glIsTexture"]=_glIsTexture;_glIsTexture.sig="ii";var _emscripten_glIsTexture=_glIsTexture;Module["_emscripten_glIsTexture"]=_emscripten_glIsTexture;_emscripten_glIsTexture.sig="ii";var _glIsVertexArray=array=>{var vao=GL.vaos[array];if(!vao)return 0;return GLctx.isVertexArray(vao)};Module["_glIsVertexArray"]=_glIsVertexArray;_glIsVertexArray.sig="ii";var _glIsVertexArrayOES=_glIsVertexArray;Module["_glIsVertexArrayOES"]=_glIsVertexArrayOES;_glIsVertexArrayOES.sig="ii";var _emscripten_glIsVertexArrayOES=_glIsVertexArrayOES;Module["_emscripten_glIsVertexArrayOES"]=_emscripten_glIsVertexArrayOES;_emscripten_glIsVertexArrayOES.sig="ii";var _glLineWidth=x0=>GLctx.lineWidth(x0);Module["_glLineWidth"]=_glLineWidth;_glLineWidth.sig="vf";var _emscripten_glLineWidth=_glLineWidth;Module["_emscripten_glLineWidth"]=_emscripten_glLineWidth;_emscripten_glLineWidth.sig="vf";var _glLinkProgram=program=>{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};Module["_glLinkProgram"]=_glLinkProgram;_glLinkProgram.sig="vi";var _emscripten_glLinkProgram=_glLinkProgram;Module["_emscripten_glLinkProgram"]=_emscripten_glLinkProgram;_emscripten_glLinkProgram.sig="vi";var _glPixelStorei=(pname,param)=>{if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)};Module["_glPixelStorei"]=_glPixelStorei;_glPixelStorei.sig="vii";var _emscripten_glPixelStorei=_glPixelStorei;Module["_emscripten_glPixelStorei"]=_emscripten_glPixelStorei;_emscripten_glPixelStorei.sig="vii";var _glPolygonOffset=(x0,x1)=>GLctx.polygonOffset(x0,x1);Module["_glPolygonOffset"]=_glPolygonOffset;_glPolygonOffset.sig="vff";var _emscripten_glPolygonOffset=_glPolygonOffset;Module["_emscripten_glPolygonOffset"]=_emscripten_glPolygonOffset;_emscripten_glPolygonOffset.sig="vff";var _glQueryCounterEXT=(id,target)=>{GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.queries[id],target)};Module["_glQueryCounterEXT"]=_glQueryCounterEXT;_glQueryCounterEXT.sig="vii";var _emscripten_glQueryCounterEXT=_glQueryCounterEXT;Module["_emscripten_glQueryCounterEXT"]=_emscripten_glQueryCounterEXT;var computeUnpackAlignedImageSize=(width,height,sizePerPixel,alignment)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize};Module["computeUnpackAlignedImageSize"]=computeUnpackAlignedImageSize;var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4};return colorChannels[format-6402]||1};Module["colorChannelsInGlTextureFormat"]=colorChannelsInGlTextureFormat;var heapObjectForWebGLType=type=>{type-=5120;if(type==1)return HEAPU8;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922)return HEAPU32;return HEAPU16};Module["heapObjectForWebGLType"]=heapObjectForWebGLType;var toTypedArrayIndex=(pointer,heap)=>pointer>>>31-Math.clz32(heap.BYTES_PER_ELEMENT);Module["toTypedArrayIndex"]=toTypedArrayIndex;var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var sizePerPixel=colorChannelsInGlTextureFormat(format)*heap.BYTES_PER_ELEMENT;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel,GL.unpackAlignment);return heap.subarray(toTypedArrayIndex(pixels,heap)>>>0,toTypedArrayIndex(pixels+bytes,heap)>>>0)};Module["emscriptenWebGLGetTexPixelData"]=emscriptenWebGLGetTexPixelData;function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}Module["_glReadPixels"]=_glReadPixels;_glReadPixels.sig="viiiiiip";var _emscripten_glReadPixels=_glReadPixels;Module["_emscripten_glReadPixels"]=_emscripten_glReadPixels;_emscripten_glReadPixels.sig="viiiiiip";var _glReleaseShaderCompiler=()=>{};Module["_glReleaseShaderCompiler"]=_glReleaseShaderCompiler;_glReleaseShaderCompiler.sig="v";var _emscripten_glReleaseShaderCompiler=_glReleaseShaderCompiler;Module["_emscripten_glReleaseShaderCompiler"]=_emscripten_glReleaseShaderCompiler;_emscripten_glReleaseShaderCompiler.sig="v";var _glRenderbufferStorage=(x0,x1,x2,x3)=>GLctx.renderbufferStorage(x0,x1,x2,x3);Module["_glRenderbufferStorage"]=_glRenderbufferStorage;_glRenderbufferStorage.sig="viiii";var _emscripten_glRenderbufferStorage=_glRenderbufferStorage;Module["_emscripten_glRenderbufferStorage"]=_emscripten_glRenderbufferStorage;_emscripten_glRenderbufferStorage.sig="viiii";var _glSampleCoverage=(value,invert)=>{GLctx.sampleCoverage(value,!!invert)};Module["_glSampleCoverage"]=_glSampleCoverage;_glSampleCoverage.sig="vfi";var _emscripten_glSampleCoverage=_glSampleCoverage;Module["_emscripten_glSampleCoverage"]=_emscripten_glSampleCoverage;_emscripten_glSampleCoverage.sig="vfi";var _glScissor=(x0,x1,x2,x3)=>GLctx.scissor(x0,x1,x2,x3);Module["_glScissor"]=_glScissor;_glScissor.sig="viiii";var _emscripten_glScissor=_glScissor;Module["_emscripten_glScissor"]=_emscripten_glScissor;_emscripten_glScissor.sig="viiii";function _glShaderBinary(count,shaders,binaryformat,binary,length){shaders>>>=0;binary>>>=0;GL.recordError(1280)}Module["_glShaderBinary"]=_glShaderBinary;_glShaderBinary.sig="vipipi";var _emscripten_glShaderBinary=_glShaderBinary;Module["_emscripten_glShaderBinary"]=_emscripten_glShaderBinary;_emscripten_glShaderBinary.sig="vipipi";function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}Module["_glShaderSource"]=_glShaderSource;_glShaderSource.sig="viipp";var _emscripten_glShaderSource=_glShaderSource;Module["_emscripten_glShaderSource"]=_emscripten_glShaderSource;_emscripten_glShaderSource.sig="viipp";var _glStencilFunc=(x0,x1,x2)=>GLctx.stencilFunc(x0,x1,x2);Module["_glStencilFunc"]=_glStencilFunc;_glStencilFunc.sig="viii";var _emscripten_glStencilFunc=_glStencilFunc;Module["_emscripten_glStencilFunc"]=_emscripten_glStencilFunc;_emscripten_glStencilFunc.sig="viii";var _glStencilFuncSeparate=(x0,x1,x2,x3)=>GLctx.stencilFuncSeparate(x0,x1,x2,x3);Module["_glStencilFuncSeparate"]=_glStencilFuncSeparate;_glStencilFuncSeparate.sig="viiii";var _emscripten_glStencilFuncSeparate=_glStencilFuncSeparate;Module["_emscripten_glStencilFuncSeparate"]=_emscripten_glStencilFuncSeparate;_emscripten_glStencilFuncSeparate.sig="viiii";var _glStencilMask=x0=>GLctx.stencilMask(x0);Module["_glStencilMask"]=_glStencilMask;_glStencilMask.sig="vi";var _emscripten_glStencilMask=_glStencilMask;Module["_emscripten_glStencilMask"]=_emscripten_glStencilMask;_emscripten_glStencilMask.sig="vi";var _glStencilMaskSeparate=(x0,x1)=>GLctx.stencilMaskSeparate(x0,x1);Module["_glStencilMaskSeparate"]=_glStencilMaskSeparate;_glStencilMaskSeparate.sig="vii";var _emscripten_glStencilMaskSeparate=_glStencilMaskSeparate;Module["_emscripten_glStencilMaskSeparate"]=_emscripten_glStencilMaskSeparate;_emscripten_glStencilMaskSeparate.sig="vii";var _glStencilOp=(x0,x1,x2)=>GLctx.stencilOp(x0,x1,x2);Module["_glStencilOp"]=_glStencilOp;_glStencilOp.sig="viii";var _emscripten_glStencilOp=_glStencilOp;Module["_emscripten_glStencilOp"]=_emscripten_glStencilOp;_emscripten_glStencilOp.sig="viii";var _glStencilOpSeparate=(x0,x1,x2,x3)=>GLctx.stencilOpSeparate(x0,x1,x2,x3);Module["_glStencilOpSeparate"]=_glStencilOpSeparate;_glStencilOpSeparate.sig="viiii";var _emscripten_glStencilOpSeparate=_glStencilOpSeparate;Module["_emscripten_glStencilOpSeparate"]=_emscripten_glStencilOpSeparate;_emscripten_glStencilOpSeparate.sig="viiii";function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null;GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixelData)}Module["_glTexImage2D"]=_glTexImage2D;_glTexImage2D.sig="viiiiiiiip";var _emscripten_glTexImage2D=_glTexImage2D;Module["_emscripten_glTexImage2D"]=_emscripten_glTexImage2D;_emscripten_glTexImage2D.sig="viiiiiiiip";var _glTexParameterf=(x0,x1,x2)=>GLctx.texParameterf(x0,x1,x2);Module["_glTexParameterf"]=_glTexParameterf;_glTexParameterf.sig="viif";var _emscripten_glTexParameterf=_glTexParameterf;Module["_emscripten_glTexParameterf"]=_emscripten_glTexParameterf;_emscripten_glTexParameterf.sig="viif";function _glTexParameterfv(target,pname,params){params>>>=0;var param=HEAPF32[params>>>2>>>0];GLctx.texParameterf(target,pname,param)}Module["_glTexParameterfv"]=_glTexParameterfv;_glTexParameterfv.sig="viip";var _emscripten_glTexParameterfv=_glTexParameterfv;Module["_emscripten_glTexParameterfv"]=_emscripten_glTexParameterfv;_emscripten_glTexParameterfv.sig="viip";var _glTexParameteri=(x0,x1,x2)=>GLctx.texParameteri(x0,x1,x2);Module["_glTexParameteri"]=_glTexParameteri;_glTexParameteri.sig="viii";var _emscripten_glTexParameteri=_glTexParameteri;Module["_emscripten_glTexParameteri"]=_emscripten_glTexParameteri;_emscripten_glTexParameteri.sig="viii";function _glTexParameteriv(target,pname,params){params>>>=0;var param=HEAP32[params>>>2>>>0];GLctx.texParameteri(target,pname,param)}Module["_glTexParameteriv"]=_glTexParameteriv;_glTexParameteriv.sig="viip";var _emscripten_glTexParameteriv=_glTexParameteriv;Module["_emscripten_glTexParameteriv"]=_emscripten_glTexParameteriv;_emscripten_glTexParameteriv.sig="viip";function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){pixels>>>=0;var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0):null;GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}Module["_glTexSubImage2D"]=_glTexSubImage2D;_glTexSubImage2D.sig="viiiiiiiip";var _emscripten_glTexSubImage2D=_glTexSubImage2D;Module["_emscripten_glTexSubImage2D"]=_emscripten_glTexSubImage2D;_emscripten_glTexSubImage2D.sig="viiiiiiiip";var _glUniform1f=(location,v0)=>{GLctx.uniform1f(webglGetUniformLocation(location),v0)};Module["_glUniform1f"]=_glUniform1f;_glUniform1f.sig="vif";var _emscripten_glUniform1f=_glUniform1f;Module["_emscripten_glUniform1f"]=_emscripten_glUniform1f;_emscripten_glUniform1f.sig="vif";var miniTempWebGLFloatBuffers=[];Module["miniTempWebGLFloatBuffers"]=miniTempWebGLFloatBuffers;function _glUniform1fv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLFloatBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}Module["_glUniform1fv"]=_glUniform1fv;_glUniform1fv.sig="viip";var _emscripten_glUniform1fv=_glUniform1fv;Module["_emscripten_glUniform1fv"]=_emscripten_glUniform1fv;_emscripten_glUniform1fv.sig="viip";var _glUniform1i=(location,v0)=>{GLctx.uniform1i(webglGetUniformLocation(location),v0)};Module["_glUniform1i"]=_glUniform1i;_glUniform1i.sig="vii";var _emscripten_glUniform1i=_glUniform1i;Module["_emscripten_glUniform1i"]=_emscripten_glUniform1i;_emscripten_glUniform1i.sig="vii";var miniTempWebGLIntBuffers=[];Module["miniTempWebGLIntBuffers"]=miniTempWebGLIntBuffers;function _glUniform1iv(location,count,value){value>>>=0;if(count<=288){var view=miniTempWebGLIntBuffers[count];for(var i=0;i>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*4>>>2>>>0)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}Module["_glUniform1iv"]=_glUniform1iv;_glUniform1iv.sig="viip";var _emscripten_glUniform1iv=_glUniform1iv;Module["_emscripten_glUniform1iv"]=_emscripten_glUniform1iv;_emscripten_glUniform1iv.sig="viip";var _glUniform2f=(location,v0,v1)=>{GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)};Module["_glUniform2f"]=_glUniform2f;_glUniform2f.sig="viff";var _emscripten_glUniform2f=_glUniform2f;Module["_emscripten_glUniform2f"]=_emscripten_glUniform2f;_emscripten_glUniform2f.sig="viff";function _glUniform2fv(location,count,value){value>>>=0;if(count<=144){var view=miniTempWebGLFloatBuffers[2*count];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}Module["_glUniform2fv"]=_glUniform2fv;_glUniform2fv.sig="viip";var _emscripten_glUniform2fv=_glUniform2fv;Module["_emscripten_glUniform2fv"]=_emscripten_glUniform2fv;_emscripten_glUniform2fv.sig="viip";var _glUniform2i=(location,v0,v1)=>{GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)};Module["_glUniform2i"]=_glUniform2i;_glUniform2i.sig="viii";var _emscripten_glUniform2i=_glUniform2i;Module["_emscripten_glUniform2i"]=_emscripten_glUniform2i;_emscripten_glUniform2i.sig="viii";function _glUniform2iv(location,count,value){value>>>=0;if(count<=144){var view=miniTempWebGLIntBuffers[2*count];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*8>>>2>>>0)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}Module["_glUniform2iv"]=_glUniform2iv;_glUniform2iv.sig="viip";var _emscripten_glUniform2iv=_glUniform2iv;Module["_emscripten_glUniform2iv"]=_emscripten_glUniform2iv;_emscripten_glUniform2iv.sig="viip";var _glUniform3f=(location,v0,v1,v2)=>{GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)};Module["_glUniform3f"]=_glUniform3f;_glUniform3f.sig="vifff";var _emscripten_glUniform3f=_glUniform3f;Module["_emscripten_glUniform3f"]=_emscripten_glUniform3f;_emscripten_glUniform3f.sig="vifff";function _glUniform3fv(location,count,value){value>>>=0;if(count<=96){var view=miniTempWebGLFloatBuffers[3*count];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}Module["_glUniform3fv"]=_glUniform3fv;_glUniform3fv.sig="viip";var _emscripten_glUniform3fv=_glUniform3fv;Module["_emscripten_glUniform3fv"]=_emscripten_glUniform3fv;_emscripten_glUniform3fv.sig="viip";var _glUniform3i=(location,v0,v1,v2)=>{GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)};Module["_glUniform3i"]=_glUniform3i;_glUniform3i.sig="viiii";var _emscripten_glUniform3i=_glUniform3i;Module["_emscripten_glUniform3i"]=_emscripten_glUniform3i;_emscripten_glUniform3i.sig="viiii";function _glUniform3iv(location,count,value){value>>>=0;if(count<=96){var view=miniTempWebGLIntBuffers[3*count];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*12>>>2>>>0)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}Module["_glUniform3iv"]=_glUniform3iv;_glUniform3iv.sig="viip";var _emscripten_glUniform3iv=_glUniform3iv;Module["_emscripten_glUniform3iv"]=_emscripten_glUniform3iv;_emscripten_glUniform3iv.sig="viip";var _glUniform4f=(location,v0,v1,v2,v3)=>{GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)};Module["_glUniform4f"]=_glUniform4f;_glUniform4f.sig="viffff";var _emscripten_glUniform4f=_glUniform4f;Module["_emscripten_glUniform4f"]=_emscripten_glUniform4f;_emscripten_glUniform4f.sig="viffff";function _glUniform4fv(location,count,value){value>>>=0;if(count<=72){var view=miniTempWebGLFloatBuffers[4*count];var heap=HEAPF32;value=value>>>2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst>>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}Module["_glUniform4fv"]=_glUniform4fv;_glUniform4fv.sig="viip";var _emscripten_glUniform4fv=_glUniform4fv;Module["_emscripten_glUniform4fv"]=_emscripten_glUniform4fv;_emscripten_glUniform4fv.sig="viip";var _glUniform4i=(location,v0,v1,v2,v3)=>{GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)};Module["_glUniform4i"]=_glUniform4i;_glUniform4i.sig="viiiii";var _emscripten_glUniform4i=_glUniform4i;Module["_emscripten_glUniform4i"]=_emscripten_glUniform4i;_emscripten_glUniform4i.sig="viiiii";function _glUniform4iv(location,count,value){value>>>=0;if(count<=72){var view=miniTempWebGLIntBuffers[4*count];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>>2>>>0];view[i+1]=HEAP32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAP32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAP32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAP32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}Module["_glUniform4iv"]=_glUniform4iv;_glUniform4iv.sig="viip";var _emscripten_glUniform4iv=_glUniform4iv;Module["_emscripten_glUniform4iv"]=_emscripten_glUniform4iv;_emscripten_glUniform4iv.sig="viip";function _glUniformMatrix2fv(location,count,transpose,value){value>>>=0;if(count<=72){var view=miniTempWebGLFloatBuffers[4*count];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*16>>>2>>>0)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}Module["_glUniformMatrix2fv"]=_glUniformMatrix2fv;_glUniformMatrix2fv.sig="viiip";var _emscripten_glUniformMatrix2fv=_glUniformMatrix2fv;Module["_emscripten_glUniformMatrix2fv"]=_emscripten_glUniformMatrix2fv;_emscripten_glUniformMatrix2fv.sig="viiip";function _glUniformMatrix3fv(location,count,transpose,value){value>>>=0;if(count<=32){var view=miniTempWebGLFloatBuffers[9*count];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>>2>>>0];view[i+1]=HEAPF32[value+(4*i+4)>>>2>>>0];view[i+2]=HEAPF32[value+(4*i+8)>>>2>>>0];view[i+3]=HEAPF32[value+(4*i+12)>>>2>>>0];view[i+4]=HEAPF32[value+(4*i+16)>>>2>>>0];view[i+5]=HEAPF32[value+(4*i+20)>>>2>>>0];view[i+6]=HEAPF32[value+(4*i+24)>>>2>>>0];view[i+7]=HEAPF32[value+(4*i+28)>>>2>>>0];view[i+8]=HEAPF32[value+(4*i+32)>>>2>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*36>>>2>>>0)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}Module["_glUniformMatrix3fv"]=_glUniformMatrix3fv;_glUniformMatrix3fv.sig="viiip";var _emscripten_glUniformMatrix3fv=_glUniformMatrix3fv;Module["_emscripten_glUniformMatrix3fv"]=_emscripten_glUniformMatrix3fv;_emscripten_glUniformMatrix3fv.sig="viiip";function _glUniformMatrix4fv(location,count,transpose,value){value>>>=0;if(count<=18){var view=miniTempWebGLFloatBuffers[16*count];var heap=HEAPF32;value=value>>>2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst>>>0];view[i+1]=heap[dst+1>>>0];view[i+2]=heap[dst+2>>>0];view[i+3]=heap[dst+3>>>0];view[i+4]=heap[dst+4>>>0];view[i+5]=heap[dst+5>>>0];view[i+6]=heap[dst+6>>>0];view[i+7]=heap[dst+7>>>0];view[i+8]=heap[dst+8>>>0];view[i+9]=heap[dst+9>>>0];view[i+10]=heap[dst+10>>>0];view[i+11]=heap[dst+11>>>0];view[i+12]=heap[dst+12>>>0];view[i+13]=heap[dst+13>>>0];view[i+14]=heap[dst+14>>>0];view[i+15]=heap[dst+15>>>0]}}else{var view=HEAPF32.subarray(value>>>2>>>0,value+count*64>>>2>>>0)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}Module["_glUniformMatrix4fv"]=_glUniformMatrix4fv;_glUniformMatrix4fv.sig="viiip";var _emscripten_glUniformMatrix4fv=_glUniformMatrix4fv;Module["_emscripten_glUniformMatrix4fv"]=_emscripten_glUniformMatrix4fv;_emscripten_glUniformMatrix4fv.sig="viiip";var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};Module["_glUseProgram"]=_glUseProgram;_glUseProgram.sig="vi";var _emscripten_glUseProgram=_glUseProgram;Module["_emscripten_glUseProgram"]=_emscripten_glUseProgram;_emscripten_glUseProgram.sig="vi";var _glValidateProgram=program=>{GLctx.validateProgram(GL.programs[program])};Module["_glValidateProgram"]=_glValidateProgram;_glValidateProgram.sig="vi";var _emscripten_glValidateProgram=_glValidateProgram;Module["_emscripten_glValidateProgram"]=_emscripten_glValidateProgram;_emscripten_glValidateProgram.sig="vi";var _glVertexAttrib1f=(x0,x1)=>GLctx.vertexAttrib1f(x0,x1);Module["_glVertexAttrib1f"]=_glVertexAttrib1f;_glVertexAttrib1f.sig="vif";var _emscripten_glVertexAttrib1f=_glVertexAttrib1f;Module["_emscripten_glVertexAttrib1f"]=_emscripten_glVertexAttrib1f;_emscripten_glVertexAttrib1f.sig="vif";function _glVertexAttrib1fv(index,v){v>>>=0;GLctx.vertexAttrib1f(index,HEAPF32[v>>>2])}Module["_glVertexAttrib1fv"]=_glVertexAttrib1fv;_glVertexAttrib1fv.sig="vip";var _emscripten_glVertexAttrib1fv=_glVertexAttrib1fv;Module["_emscripten_glVertexAttrib1fv"]=_emscripten_glVertexAttrib1fv;_emscripten_glVertexAttrib1fv.sig="vip";var _glVertexAttrib2f=(x0,x1,x2)=>GLctx.vertexAttrib2f(x0,x1,x2);Module["_glVertexAttrib2f"]=_glVertexAttrib2f;_glVertexAttrib2f.sig="viff";var _emscripten_glVertexAttrib2f=_glVertexAttrib2f;Module["_emscripten_glVertexAttrib2f"]=_emscripten_glVertexAttrib2f;_emscripten_glVertexAttrib2f.sig="viff";function _glVertexAttrib2fv(index,v){v>>>=0;GLctx.vertexAttrib2f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2])}Module["_glVertexAttrib2fv"]=_glVertexAttrib2fv;_glVertexAttrib2fv.sig="vip";var _emscripten_glVertexAttrib2fv=_glVertexAttrib2fv;Module["_emscripten_glVertexAttrib2fv"]=_emscripten_glVertexAttrib2fv;_emscripten_glVertexAttrib2fv.sig="vip";var _glVertexAttrib3f=(x0,x1,x2,x3)=>GLctx.vertexAttrib3f(x0,x1,x2,x3);Module["_glVertexAttrib3f"]=_glVertexAttrib3f;_glVertexAttrib3f.sig="vifff";var _emscripten_glVertexAttrib3f=_glVertexAttrib3f;Module["_emscripten_glVertexAttrib3f"]=_emscripten_glVertexAttrib3f;_emscripten_glVertexAttrib3f.sig="vifff";function _glVertexAttrib3fv(index,v){v>>>=0;GLctx.vertexAttrib3f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2])}Module["_glVertexAttrib3fv"]=_glVertexAttrib3fv;_glVertexAttrib3fv.sig="vip";var _emscripten_glVertexAttrib3fv=_glVertexAttrib3fv;Module["_emscripten_glVertexAttrib3fv"]=_emscripten_glVertexAttrib3fv;_emscripten_glVertexAttrib3fv.sig="vip";var _glVertexAttrib4f=(x0,x1,x2,x3,x4)=>GLctx.vertexAttrib4f(x0,x1,x2,x3,x4);Module["_glVertexAttrib4f"]=_glVertexAttrib4f;_glVertexAttrib4f.sig="viffff";var _emscripten_glVertexAttrib4f=_glVertexAttrib4f;Module["_emscripten_glVertexAttrib4f"]=_emscripten_glVertexAttrib4f;_emscripten_glVertexAttrib4f.sig="viffff";function _glVertexAttrib4fv(index,v){v>>>=0;GLctx.vertexAttrib4f(index,HEAPF32[v>>>2],HEAPF32[v+4>>>2],HEAPF32[v+8>>>2],HEAPF32[v+12>>>2])}Module["_glVertexAttrib4fv"]=_glVertexAttrib4fv;_glVertexAttrib4fv.sig="vip";var _emscripten_glVertexAttrib4fv=_glVertexAttrib4fv;Module["_emscripten_glVertexAttrib4fv"]=_emscripten_glVertexAttrib4fv;_emscripten_glVertexAttrib4fv.sig="vip";var _glVertexAttribDivisor=(index,divisor)=>{GLctx.vertexAttribDivisor(index,divisor)};Module["_glVertexAttribDivisor"]=_glVertexAttribDivisor;_glVertexAttribDivisor.sig="vii";var _glVertexAttribDivisorANGLE=_glVertexAttribDivisor;Module["_glVertexAttribDivisorANGLE"]=_glVertexAttribDivisorANGLE;var _emscripten_glVertexAttribDivisorANGLE=_glVertexAttribDivisorANGLE;Module["_emscripten_glVertexAttribDivisorANGLE"]=_emscripten_glVertexAttribDivisorANGLE;function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}Module["_glVertexAttribPointer"]=_glVertexAttribPointer;_glVertexAttribPointer.sig="viiiiip";var _emscripten_glVertexAttribPointer=_glVertexAttribPointer;Module["_emscripten_glVertexAttribPointer"]=_emscripten_glVertexAttribPointer;_emscripten_glVertexAttribPointer.sig="viiiiip";var _glViewport=(x0,x1,x2,x3)=>GLctx.viewport(x0,x1,x2,x3);Module["_glViewport"]=_glViewport;_glViewport.sig="viiii";var _emscripten_glViewport=_glViewport;Module["_emscripten_glViewport"]=_emscripten_glViewport;_emscripten_glViewport.sig="viiii";function _emscripten_out(str){str>>>=0;return out(UTF8ToString(str))}Module["_emscripten_out"]=_emscripten_out;_emscripten_out.sig="vp";class HandleAllocator{constructor(){this.allocated=[undefined];this.freelist=[]}get(id){return this.allocated[id]}has(id){return this.allocated[id]!==undefined}allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id}free(id){this.allocated[id]=undefined;this.freelist.push(id)}}Module["HandleAllocator"]=HandleAllocator;var promiseMap=new HandleAllocator;Module["promiseMap"]=promiseMap;var makePromise=()=>{var promiseInfo={};promiseInfo.promise=new Promise((resolve,reject)=>{promiseInfo.reject=reject;promiseInfo.resolve=resolve});promiseInfo.id=promiseMap.allocate(promiseInfo);return promiseInfo};Module["makePromise"]=makePromise;function _emscripten_promise_create(){return makePromise().id}Module["_emscripten_promise_create"]=_emscripten_promise_create;_emscripten_promise_create.sig="p";function _emscripten_promise_destroy(id){id>>>=0;promiseMap.free(id)}Module["_emscripten_promise_destroy"]=_emscripten_promise_destroy;_emscripten_promise_destroy.sig="vp";var getPromise=id=>promiseMap.get(id).promise;Module["getPromise"]=getPromise;function _emscripten_promise_resolve(id,result,value){id>>>=0;value>>>=0;var info=promiseMap.get(id);switch(result){case 0:info.resolve(value);return;case 1:info.resolve(getPromise(value));return;case 2:info.resolve(getPromise(value));_emscripten_promise_destroy(value);return;case 3:info.reject(value);return}}Module["_emscripten_promise_resolve"]=_emscripten_promise_resolve;_emscripten_promise_resolve.sig="vpip";var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};Module["growMemory"]=growMemory;function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}Module["_emscripten_resize_heap"]=_emscripten_resize_heap;_emscripten_resize_heap.sig="ip";var getExecutableName=()=>thisProgram||"./this.program";Module["getExecutableName"]=getExecutableName;var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};Module["getEnvStrings"]=getEnvStrings;var stringToAscii=(str,buffer)=>{for(var i=0;i>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0]=0};Module["stringToAscii"]=stringToAscii;var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};Module["_environ_get"]=_environ_get;_environ_get.sig="ipp";var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};Module["_environ_sizes_get"]=_environ_sizes_get;_environ_sizes_get.sig="ipp";function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_close"]=_fd_close;_fd_close.sig="ii";function _fd_fdstat_get(fd,pbuf){pbuf>>>=0;try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf>>>0]=type;HEAP16[pbuf+2>>>1>>>0]=flags;HEAP64[pbuf+8>>>3]=BigInt(rightsBase);HEAP64[pbuf+16>>>3]=BigInt(rightsInheriting);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_fdstat_get"]=_fd_fdstat_get;_fd_fdstat_get.sig="iip";var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;offset=bigintToI53Checked(offset);pnum>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt,offset);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_pread"]=_fd_pread;_fd_pread.sig="iippjp";var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!="undefined"){offset+=curr}}return ret};Module["doWritev"]=doWritev;function _fd_pwrite(fd,iov,iovcnt,offset,pnum){iov>>>=0;iovcnt>>>=0;offset=bigintToI53Checked(offset);pnum>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt,offset);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_pwrite"]=_fd_pwrite;_fd_pwrite.sig="iippjp";function _fd_read(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_read"]=_fd_read;_fd_read.sig="iippp";function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_seek"]=_fd_seek;_fd_seek.sig="iijip";function _fd_sync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);if(stream.stream_ops?.fsync){return stream.stream_ops.fsync(stream)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_sync"]=_fd_sync;_fd_sync.sig="ii";function _fd_write(fd,iov,iovcnt,pnum){iov>>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_fd_write"]=_fd_write;_fd_write.sig="iippp";function _getaddrinfo(node,service,hint,out){node>>>=0;service>>>=0;hint>>>=0;out>>>=0;var addrs=[];var canon=null;var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai,last;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var errno;salen=family===10?28:16;addr=family===10?inetNtop6(addr):inetNtop4(addr);sa=_malloc(salen);errno=writeSockaddr(sa,family,addr,port);assert(!errno);ai=_malloc(32);HEAP32[ai+4>>>2>>>0]=family;HEAP32[ai+8>>>2>>>0]=type;HEAP32[ai+12>>>2>>>0]=proto;HEAPU32[ai+24>>>2>>>0]=canon;HEAPU32[ai+20>>>2>>>0]=sa;if(family===10){HEAP32[ai+16>>>2>>>0]=28}else{HEAP32[ai+16>>>2>>>0]=16}HEAP32[ai+28>>>2>>>0]=0;return ai}if(hint){flags=HEAP32[hint>>>2>>>0];family=HEAP32[hint+4>>>2>>>0];type=HEAP32[hint+8>>>2>>>0];proto=HEAP32[hint+12>>>2>>>0]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>>2>>>0]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,1]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}node=UTF8ToString(node);addr=inetPton4(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=inetPton6(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=inetPton4(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>>2>>>0]=ai;return 0}Module["_getaddrinfo"]=_getaddrinfo;_getaddrinfo.sig="ipppp";function _getentropy(buffer,size){buffer>>>=0;size>>>=0;randomFill(HEAPU8.subarray(buffer>>>0,buffer+size>>>0));return 0}Module["_getentropy"]=_getentropy;_getentropy.sig="ipp";function _getnameinfo(sa,salen,node,nodelen,serv,servlen,flags){sa>>>=0;node>>>=0;serv>>>=0;var info=readSockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0}Module["_getnameinfo"]=_getnameinfo;_getnameinfo.sig="ipipipii";var Protocols={list:[],map:{}};Module["Protocols"]=Protocols;var _setprotoent=stayopen=>{function allocprotoent(name,proto,aliases){var nameBuf=_malloc(name.length+1);stringToAscii(name,nameBuf);var j=0;var length=aliases.length;var aliasListBuf=_malloc((length+1)*4);for(var i=0;i>>2>>>0]=aliasBuf}HEAPU32[aliasListBuf+j>>>2>>>0]=0;var pe=_malloc(12);HEAPU32[pe>>>2>>>0]=nameBuf;HEAPU32[pe+4>>>2>>>0]=aliasListBuf;HEAP32[pe+8>>>2>>>0]=proto;return pe}var list=Protocols.list;var map=Protocols.map;if(list.length===0){var entry=allocprotoent("tcp",6,["TCP"]);list.push(entry);map["tcp"]=map["6"]=entry;entry=allocprotoent("udp",17,["UDP"]);list.push(entry);map["udp"]=map["17"]=entry}_setprotoent.index=0};Module["_setprotoent"]=_setprotoent;_setprotoent.sig="vi";function _getprotobyname(name){name>>>=0;name=UTF8ToString(name);_setprotoent(true);var result=Protocols.map[name];return result}Module["_getprotobyname"]=_getprotobyname;_getprotobyname.sig="pp";var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};Module["arraySum"]=arraySum;var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];Module["MONTH_DAYS_LEAP"]=MONTH_DAYS_LEAP;var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];Module["MONTH_DAYS_REGULAR"]=MONTH_DAYS_REGULAR;var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};Module["addDays"]=addDays;var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};Module["writeArrayToMemory"]=writeArrayToMemory;function _strftime(s,maxsize,format,tm){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;var tm_zone=HEAPU32[tm+40>>>2>>>0];var date={tm_sec:HEAP32[tm>>>2>>>0],tm_min:HEAP32[tm+4>>>2>>>0],tm_hour:HEAP32[tm+8>>>2>>>0],tm_mday:HEAP32[tm+12>>>2>>>0],tm_mon:HEAP32[tm+16>>>2>>>0],tm_year:HEAP32[tm+20>>>2>>>0],tm_wday:HEAP32[tm+24>>>2>>>0],tm_yday:HEAP32[tm+28>>>2>>>0],tm_isdst:HEAP32[tm+32>>>2>>>0],tm_gmtoff:HEAP32[tm+36>>>2>>>0],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":date=>WEEKDAYS[date.tm_wday].substring(0,3),"%A":date=>WEEKDAYS[date.tm_wday],"%b":date=>MONTHS[date.tm_mon].substring(0,3),"%B":date=>MONTHS[date.tm_mon],"%C":date=>{var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":date=>leadingNulls(date.tm_mday,2),"%e":date=>leadingSomething(date.tm_mday,2," "),"%g":date=>getWeekBasedYear(date).toString().substring(2),"%G":getWeekBasedYear,"%H":date=>leadingNulls(date.tm_hour,2),"%I":date=>{var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":date=>leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3),"%m":date=>leadingNulls(date.tm_mon+1,2),"%M":date=>leadingNulls(date.tm_min,2),"%n":()=>"\n","%p":date=>{if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":date=>leadingNulls(date.tm_sec,2),"%t":()=>"\t","%u":date=>date.tm_wday||7,"%U":date=>{var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":date=>{var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":date=>date.tm_wday,"%W":date=>{var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":date=>(date.tm_year+1900).toString().substring(2),"%Y":date=>date.tm_year+1900,"%z":date=>{var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":date=>date.tm_zone,"%%":()=>"%"};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}Module["_strftime"]=_strftime;_strftime.sig="ppppp";function _strftime_l(s,maxsize,format,tm,loc){s>>>=0;maxsize>>>=0;format>>>=0;tm>>>=0;loc>>>=0;return _strftime(s,maxsize,format,tm)}Module["_strftime_l"]=_strftime_l;_strftime_l.sig="pppppp";var _stackAlloc=stackAlloc;Module["_stackAlloc"]=_stackAlloc;var _stackRestore=stackSave;Module["_stackRestore"]=_stackRestore;var _stackSave=stackSave;Module["_stackSave"]=_stackSave;var FS_unlink=path=>FS.unlink(path);Module["FS_unlink"]=FS_unlink;var writeI53ToI64Clamped=(ptr,num)=>{if(num>0x8000000000000000){HEAPU32[ptr>>>2>>>0]=4294967295;HEAPU32[ptr+4>>>2>>>0]=2147483647}else if(num<-0x8000000000000000){HEAPU32[ptr>>>2>>>0]=0;HEAPU32[ptr+4>>>2>>>0]=2147483648}else{writeI53ToI64(ptr,num)}};Module["writeI53ToI64Clamped"]=writeI53ToI64Clamped;var writeI53ToI64Signaling=(ptr,num)=>{if(num>0x8000000000000000||num<-0x8000000000000000){throw`RangeError: ${num}`}writeI53ToI64(ptr,num)};Module["writeI53ToI64Signaling"]=writeI53ToI64Signaling;var writeI53ToU64Clamped=(ptr,num)=>{if(num>0x10000000000000000){HEAPU32[ptr>>>2>>>0]=4294967295;HEAPU32[ptr+4>>>2>>>0]=4294967295}else if(num<0){HEAPU32[ptr>>>2>>>0]=0;HEAPU32[ptr+4>>>2>>>0]=0}else{writeI53ToI64(ptr,num)}};Module["writeI53ToU64Clamped"]=writeI53ToU64Clamped;var writeI53ToU64Signaling=(ptr,num)=>{if(num<0||num>0x10000000000000000){throw`RangeError: ${num}`}writeI53ToI64(ptr,num)};Module["writeI53ToU64Signaling"]=writeI53ToU64Signaling;var readI53FromU64=ptr=>HEAPU32[ptr>>>2>>>0]+HEAPU32[ptr+4>>>2>>>0]*4294967296;Module["readI53FromU64"]=readI53FromU64;var convertI32PairToI53=(lo,hi)=>(lo>>>0)+hi*4294967296;Module["convertI32PairToI53"]=convertI32PairToI53;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;Module["convertI32PairToI53Checked"]=convertI32PairToI53Checked;var convertU32PairToI53=(lo,hi)=>(lo>>>0)+(hi>>>0)*4294967296;Module["convertU32PairToI53"]=convertU32PairToI53;var getTempRet0=val=>__emscripten_tempret_get();Module["getTempRet0"]=getTempRet0;var ptrToString=ptr=>"0x"+ptr.toString(16).padStart(8,"0");Module["ptrToString"]=ptrToString;function _emscripten_notify_memory_growth(memoryIndex){memoryIndex>>>=0;updateMemoryViews()}Module["_emscripten_notify_memory_growth"]=_emscripten_notify_memory_growth;_emscripten_notify_memory_growth.sig="vp";function ___asctime_r(tmPtr,buf){tmPtr>>>=0;buf>>>=0;var date={tm_sec:HEAP32[tmPtr>>>2>>>0],tm_min:HEAP32[tmPtr+4>>>2>>>0],tm_hour:HEAP32[tmPtr+8>>>2>>>0],tm_mday:HEAP32[tmPtr+12>>>2>>>0],tm_mon:HEAP32[tmPtr+16>>>2>>>0],tm_year:HEAP32[tmPtr+20>>>2>>>0],tm_wday:HEAP32[tmPtr+24>>>2>>>0]};var days=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var s=days[date.tm_wday]+" "+months[date.tm_mon]+(date.tm_mday<10?" ":" ")+date.tm_mday+(date.tm_hour<10?" 0":" ")+date.tm_hour+(date.tm_min<10?":0":":")+date.tm_min+(date.tm_sec<10?":0":":")+date.tm_sec+" "+(1900+date.tm_year)+"\n";stringToUTF8(s,buf,26);return buf}Module["___asctime_r"]=___asctime_r;___asctime_r.sig="ppp";var withStackSave=f=>{var stack=stackSave();var ret=f();stackRestore(stack);return ret};Module["withStackSave"]=withStackSave;function _strptime(buf,format,tm){buf>>>=0;format>>>=0;tm>>>=0;var pattern=UTF8ToString(format);var SPECIAL_CHARS="\\!@#$^&*()+=-[]/{}|:<>?,.";for(var i=0,ii=SPECIAL_CHARS.length;iEQUIVALENT_MATCHERS[c]||m).replace(/%(.)/g,(_,c)=>{let pat=DATE_PATTERNS[c];if(pat){capture.push(c);return`(${pat})`}else{return c}}).replace(/\s+/g,"\\s*");var matches=new RegExp("^"+pattern_out,"i").exec(UTF8ToString(buf));function initDate(){function fixup(value,min,max){return typeof value!="number"||isNaN(value)?min:value>=min?value<=max?value:max:min}return{year:fixup(HEAP32[tm+20>>>2>>>0]+1900,1970,9999),month:fixup(HEAP32[tm+16>>>2>>>0],0,11),day:fixup(HEAP32[tm+12>>>2>>>0],1,31),hour:fixup(HEAP32[tm+8>>>2>>>0],0,23),min:fixup(HEAP32[tm+4>>>2>>>0],0,59),sec:fixup(HEAP32[tm>>>2>>>0],0,59),gmtoff:0}}if(matches){var date=initDate();var value;var getMatch=symbol=>{var pos=capture.indexOf(symbol);if(pos>=0){return matches[pos+1]}return};if(value=getMatch("S")){date.sec=jstoi_q(value)}if(value=getMatch("M")){date.min=jstoi_q(value)}if(value=getMatch("H")){date.hour=jstoi_q(value)}else if(value=getMatch("I")){var hour=jstoi_q(value);if(value=getMatch("p")){hour+=value.toUpperCase()[0]==="P"?12:0}date.hour=hour}if(value=getMatch("Y")){date.year=jstoi_q(value)}else if(value=getMatch("y")){var year=jstoi_q(value);if(value=getMatch("C")){year+=jstoi_q(value)*100}else{year+=year<69?2e3:1900}date.year=year}if(value=getMatch("m")){date.month=jstoi_q(value)-1}else if(value=getMatch("b")){date.month=MONTH_NUMBERS[value.substring(0,3).toUpperCase()]||0}if(value=getMatch("d")){date.day=jstoi_q(value)}else if(value=getMatch("j")){var day=jstoi_q(value);var leapYear=isLeapYear(date.year);for(var month=0;month<12;++month){var daysUntilMonth=arraySum(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,month-1);if(day<=daysUntilMonth+(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[month]){date.day=day-daysUntilMonth}}}else if(value=getMatch("a")){var weekDay=value.substring(0,3).toUpperCase();if(value=getMatch("U")){var weekDayNumber=DAY_NUMBERS_SUN_FIRST[weekDay];var weekNumber=jstoi_q(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===0){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}else if(value=getMatch("W")){var weekDayNumber=DAY_NUMBERS_MON_FIRST[weekDay];var weekNumber=jstoi_q(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===1){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}}if(value=getMatch("z")){if(value.toLowerCase()==="z"){date.gmtoff=0}else{var match=value.match(/^((?:\-|\+)\d\d):?(\d\d)?/);date.gmtoff=match[1]*3600;if(match[2]){date.gmtoff+=date.gmtoff>0?match[2]*60:-match[2]*60}}}var fullDate=new Date(date.year,date.month,date.day,date.hour,date.min,date.sec,0);HEAP32[tm>>>2>>>0]=fullDate.getSeconds();HEAP32[tm+4>>>2>>>0]=fullDate.getMinutes();HEAP32[tm+8>>>2>>>0]=fullDate.getHours();HEAP32[tm+12>>>2>>>0]=fullDate.getDate();HEAP32[tm+16>>>2>>>0]=fullDate.getMonth();HEAP32[tm+20>>>2>>>0]=fullDate.getFullYear()-1900;HEAP32[tm+24>>>2>>>0]=fullDate.getDay();HEAP32[tm+28>>>2>>>0]=arraySum(isLeapYear(fullDate.getFullYear())?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,fullDate.getMonth()-1)+fullDate.getDate()-1;HEAP32[tm+32>>>2>>>0]=0;HEAP32[tm+36>>>2>>>0]=date.gmtoff;return buf+intArrayFromString(matches[0]).length-1}return 0}Module["_strptime"]=_strptime;_strptime.sig="pppp";function _strptime_l(buf,format,tm,locale){buf>>>=0;format>>>=0;tm>>>=0;locale>>>=0;return _strptime(buf,format,tm)}Module["_strptime_l"]=_strptime_l;_strptime_l.sig="ppppp";var ERRNO_MESSAGES={0:"Success",1:"Arg list too long",2:"Permission denied",3:"Address already in use",4:"Address not available",5:"Address family not supported by protocol family",6:"No more processes",7:"Socket already connected",8:"Bad file number",9:"Trying to read unreadable message",10:"Mount device busy",11:"Operation canceled",12:"No children",13:"Connection aborted",14:"Connection refused",15:"Connection reset by peer",16:"File locking deadlock error",17:"Destination address required",18:"Math arg out of domain of func",19:"Quota exceeded",20:"File exists",21:"Bad address",22:"File too large",23:"Host is unreachable",24:"Identifier removed",25:"Illegal byte sequence",26:"Connection already in progress",27:"Interrupted system call",28:"Invalid argument",29:"I/O error",30:"Socket is already connected",31:"Is a directory",32:"Too many symbolic links",33:"Too many open files",34:"Too many links",35:"Message too long",36:"Multihop attempted",37:"File or path name too long",38:"Network interface is not configured",39:"Connection reset by network",40:"Network is unreachable",41:"Too many open files in system",42:"No buffer space available",43:"No such device",44:"No such file or directory",45:"Exec format error",46:"No record locks available",47:"The link has been severed",48:"Not enough core",49:"No message of desired type",50:"Protocol not available",51:"No space left on device",52:"Function not implemented",53:"Socket is not connected",54:"Not a directory",55:"Directory not empty",56:"State not recoverable",57:"Socket operation on non-socket",59:"Not a typewriter",60:"No such device or address",61:"Value too large for defined data type",62:"Previous owner died",63:"Not super-user",64:"Broken pipe",65:"Protocol error",66:"Unknown protocol",67:"Protocol wrong type for socket",68:"Math result not representable",69:"Read only file system",70:"Illegal seek",71:"No such process",72:"Stale file handle",73:"Connection timed out",74:"Text file busy",75:"Cross-device link",100:"Device not a stream",101:"Bad font file fmt",102:"Invalid slot",103:"Invalid request code",104:"No anode",105:"Block device required",106:"Channel number out of range",107:"Level 3 halted",108:"Level 3 reset",109:"Link number out of range",110:"Protocol driver not attached",111:"No CSI structure available",112:"Level 2 halted",113:"Invalid exchange",114:"Invalid request descriptor",115:"Exchange full",116:"No data (for no delay io)",117:"Timer expired",118:"Out of streams resources",119:"Machine is not on the network",120:"Package not installed",121:"The object is remote",122:"Advertise error",123:"Srmount error",124:"Communication error on send",125:"Cross mount point (not really error)",126:"Given log. name not unique",127:"f.d. invalid for this operation",128:"Remote address changed",129:"Can access a needed shared lib",130:"Accessing a corrupted shared lib",131:".lib section in a.out corrupted",132:"Attempting to link in too many libs",133:"Attempting to exec a shared library",135:"Streams pipe error",136:"Too many users",137:"Socket type not supported",138:"Not supported",139:"Protocol family not supported",140:"Can't send after socket shutdown",141:"Too many references",142:"Host is down",148:"No medium (in tape drive)",156:"Level 2 not synchronized"};Module["ERRNO_MESSAGES"]=ERRNO_MESSAGES;var _endprotoent=()=>{};Module["_endprotoent"]=_endprotoent;_endprotoent.sig="v";function _getprotoent(number){if(_setprotoent.index===Protocols.list.length){return 0}var result=Protocols.list[_setprotoent.index++];return result}Module["_getprotoent"]=_getprotoent;_getprotoent.sig="p";function _getprotobynumber(number){_setprotoent(true);var result=Protocols.map[number];return result}Module["_getprotobynumber"]=_getprotobynumber;_getprotobynumber.sig="pi";function _emscripten_run_script(ptr){ptr>>>=0;eval(UTF8ToString(ptr))}Module["_emscripten_run_script"]=_emscripten_run_script;_emscripten_run_script.sig="vp";function _emscripten_run_script_int(ptr){ptr>>>=0;return eval(UTF8ToString(ptr))|0}Module["_emscripten_run_script_int"]=_emscripten_run_script_int;_emscripten_run_script_int.sig="ip";function _emscripten_run_script_string(ptr){ptr>>>=0;var s=eval(UTF8ToString(ptr));if(s==null){return 0}s+="";var me=_emscripten_run_script_string;var len=lengthBytesUTF8(s);if(!me.bufferSize||me.bufferSizeMath.random();Module["_emscripten_random"]=_emscripten_random;_emscripten_random.sig="f";var warnOnce=text=>{warnOnce.shown||={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};Module["warnOnce"]=warnOnce;function jsStackTrace(){return(new Error).stack.toString()}Module["jsStackTrace"]=jsStackTrace;function getCallstack(flags){var callstack=jsStackTrace();var iThisFunc=callstack.lastIndexOf("_emscripten_log");var iThisFunc2=callstack.lastIndexOf("_emscripten_get_callstack");var iNextLine=callstack.indexOf("\n",Math.max(iThisFunc,iThisFunc2))+1;callstack=callstack.slice(iNextLine);if(flags&8&&typeof emscripten_source_map=="undefined"){warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.');flags^=8;flags|=16}var lines=callstack.split("\n");callstack="";var newFirefoxRe=new RegExp("\\s*(.*?)@(.*?):([0-9]+):([0-9]+)");var firefoxRe=new RegExp("\\s*(.*?)@(.*):(.*)(:(.*))?");var chromeRe=new RegExp("\\s*at (.*?) \\((.*):(.*):(.*)\\)");for(var l in lines){var line=lines[l];var symbolName="";var file="";var lineno=0;var column=0;var parts=chromeRe.exec(line);if(parts&&parts.length==5){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]}else{parts=newFirefoxRe.exec(line);if(!parts)parts=firefoxRe.exec(line);if(parts&&parts.length>=4){symbolName=parts[1];file=parts[2];lineno=parts[3];column=parts[4]|0}else{callstack+=line+"\n";continue}}var haveSourceMap=false;if(flags&8){var orig=emscripten_source_map.originalPositionFor({line:lineno,column:column});haveSourceMap=orig?.source;if(haveSourceMap){if(flags&64){orig.source=orig.source.substring(orig.source.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=` at ${symbolName} (${orig.source}:${orig.line}:${orig.column})\n`}}if(flags&16||!haveSourceMap){if(flags&64){file=file.substring(file.replace(/\\/g,"/").lastIndexOf("/")+1)}callstack+=(haveSourceMap?` = ${symbolName}`:` at ${symbolName}`)+` (${file}:${lineno}:${column})\n`}}callstack=callstack.replace(/\s+$/,"");return callstack}Module["getCallstack"]=getCallstack;var emscriptenLog=(flags,str)=>{if(flags&24){str=str.replace(/\s+$/,"");str+=(str.length>0?"\n":"")+getCallstack(flags)}if(flags&1){if(flags&4){console.error(str)}else if(flags&2){console.warn(str)}else if(flags&512){console.info(str)}else if(flags&256){console.debug(str)}else{console.log(str)}}else if(flags&6){err(str)}else{out(str)}};Module["emscriptenLog"]=emscriptenLog;var reallyNegative=x=>x<0||x===0&&1/x===-Infinity;Module["reallyNegative"]=reallyNegative;var reSign=(value,bits)=>{if(value<=0){return value}var half=bits<=32?Math.abs(1<=half&&(bits<=32||value>half)){value=-2*half+value}return value};Module["reSign"]=reSign;var unSign=(value,bits)=>{if(value>=0){return value}return bits<=32?2*Math.abs(1<{var end=ptr;while(HEAPU8[end>>>0])++end;return end-ptr};Module["strLen"]=strLen;var formatString=(format,varargs)=>{var textIndex=format;var argIndex=varargs;function prepVararg(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){ptr+=4}}else{}return ptr}function getNextArg(type){var ret;argIndex=prepVararg(argIndex,type);if(type==="double"){ret=HEAPF64[argIndex>>>3>>>0];argIndex+=8}else if(type=="i64"){ret=[HEAP32[argIndex>>>2>>>0],HEAP32[argIndex+4>>>2>>>0]];argIndex+=8}else{type="i32";ret=HEAP32[argIndex>>>2>>>0];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>>0];if(curr===0)break;next=HEAP8[textIndex+1>>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break}case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;currArg=getNextArg("i"+argSize*8);var argText;if(argSize==8){currArg=next==117?convertU32PairToI53(currArg[0],currArg[1]):convertI32PairToI53(currArg[0],currArg[1])}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){argText=reSign(currArg,8*argSize).toString(10)}else if(next==117){argText=unSign(currArg,8*argSize).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.lengthexponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].includes(".")&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.length>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break}case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>>2>>>0]=ret.length;break}case"%":{ret.push(curr);break}default:{for(var i=startTextIndex;i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret};Module["formatString"]=formatString;function _emscripten_log(flags,format,varargs){format>>>=0;varargs>>>=0;var result=formatString(format,varargs);var str=UTF8ArrayToString(result,0);emscriptenLog(flags,str)}Module["_emscripten_log"]=_emscripten_log;_emscripten_log.sig="vipp";function _emscripten_get_compiler_setting(name){name>>>=0;throw"You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work"}Module["_emscripten_get_compiler_setting"]=_emscripten_get_compiler_setting;_emscripten_get_compiler_setting.sig="pp";var _emscripten_has_asyncify=()=>0;Module["_emscripten_has_asyncify"]=_emscripten_has_asyncify;_emscripten_has_asyncify.sig="i";function _emscripten_debugger(){debugger}Module["_emscripten_debugger"]=_emscripten_debugger;_emscripten_debugger.sig="v";function _emscripten_print_double(x,to,max){to>>>=0;var str=x+"";if(to)return stringToUTF8(str,to,max);else return lengthBytesUTF8(str)}Module["_emscripten_print_double"]=_emscripten_print_double;_emscripten_print_double.sig="idpi";function _emscripten_get_module_name(buf,length){buf>>>=0;length>>>=0;return stringToUTF8(wasmBinaryFile,buf,length)}Module["_emscripten_get_module_name"]=_emscripten_get_module_name;_emscripten_get_module_name.sig="ppp";function _emscripten_asm_const_double(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}Module["_emscripten_asm_const_double"]=_emscripten_asm_const_double;_emscripten_asm_const_double.sig="dppp";function _emscripten_asm_const_ptr(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}Module["_emscripten_asm_const_ptr"]=_emscripten_asm_const_ptr;_emscripten_asm_const_ptr.sig="pppp";var runMainThreadEmAsm=(emAsmAddr,sigPtr,argbuf,sync)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[emAsmAddr](...args)};Module["runMainThreadEmAsm"]=runMainThreadEmAsm;function _emscripten_asm_const_int_sync_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,1)}Module["_emscripten_asm_const_int_sync_on_main_thread"]=_emscripten_asm_const_int_sync_on_main_thread;_emscripten_asm_const_int_sync_on_main_thread.sig="ippp";function _emscripten_asm_const_ptr_sync_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,1)}Module["_emscripten_asm_const_ptr_sync_on_main_thread"]=_emscripten_asm_const_ptr_sync_on_main_thread;_emscripten_asm_const_ptr_sync_on_main_thread.sig="pppp";var _emscripten_asm_const_double_sync_on_main_thread=_emscripten_asm_const_int_sync_on_main_thread;Module["_emscripten_asm_const_double_sync_on_main_thread"]=_emscripten_asm_const_double_sync_on_main_thread;_emscripten_asm_const_double_sync_on_main_thread.sig="dppp";function _emscripten_asm_const_async_on_main_thread(emAsmAddr,sigPtr,argbuf){emAsmAddr>>>=0;sigPtr>>>=0;argbuf>>>=0;return runMainThreadEmAsm(emAsmAddr,sigPtr,argbuf,0)}Module["_emscripten_asm_const_async_on_main_thread"]=_emscripten_asm_const_async_on_main_thread;_emscripten_asm_const_async_on_main_thread.sig="vppp";var jstoi_s=Number;Module["jstoi_s"]=jstoi_s;function __Unwind_Backtrace(func,arg){func>>>=0;arg>>>=0;var trace=getCallstack();var parts=trace.split("\n");for(var i=0;i>>=0;ipBefore>>>=0;return abort("Unwind_GetIPInfo")}Module["__Unwind_GetIPInfo"]=__Unwind_GetIPInfo;__Unwind_GetIPInfo.sig="ppp";function __Unwind_FindEnclosingFunction(ip){ip>>>=0;return 0}Module["__Unwind_FindEnclosingFunction"]=__Unwind_FindEnclosingFunction;__Unwind_FindEnclosingFunction.sig="pp";function __Unwind_RaiseException(ex){ex>>>=0;err("Warning: _Unwind_RaiseException is not correctly implemented");return ___cxa_throw(ex,0,0)}Module["__Unwind_RaiseException"]=__Unwind_RaiseException;__Unwind_RaiseException.sig="ip";function __Unwind_DeleteException(ex){ex>>>=0;err("TODO: Unwind_DeleteException")}Module["__Unwind_DeleteException"]=__Unwind_DeleteException;__Unwind_DeleteException.sig="vp";var listenOnce=(object,event,func)=>{object.addEventListener(event,func,{"once":true})};Module["listenOnce"]=listenOnce;var autoResumeAudioContext=(ctx,elements)=>{if(!elements){elements=[document,document.getElementById("canvas")]}["keydown","mousedown","touchstart"].forEach(event=>{elements.forEach(element=>{if(element){listenOnce(element,event,()=>{if(ctx.state==="suspended")ctx.resume()})}})})};Module["autoResumeAudioContext"]=autoResumeAudioContext;var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);Module["getDynCaller"]=getDynCaller;var _emscripten_force_exit=status=>{__emscripten_runtime_keepalive_clear();_exit(status)};Module["_emscripten_force_exit"]=_emscripten_force_exit;_emscripten_force_exit.sig="vi";function _emscripten_outn(str,len){str>>>=0;len>>>=0;return out(UTF8ToString(str,len))}Module["_emscripten_outn"]=_emscripten_outn;_emscripten_outn.sig="vpp";function _emscripten_errn(str,len){str>>>=0;len>>>=0;return err(UTF8ToString(str,len))}Module["_emscripten_errn"]=_emscripten_errn;_emscripten_errn.sig="vpp";var _emscripten_throw_number=number=>{throw number};Module["_emscripten_throw_number"]=_emscripten_throw_number;_emscripten_throw_number.sig="vd";function _emscripten_throw_string(str){str>>>=0;throw UTF8ToString(str)}Module["_emscripten_throw_string"]=_emscripten_throw_string;_emscripten_throw_string.sig="vp";var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};Module["runtimeKeepalivePush"]=runtimeKeepalivePush;runtimeKeepalivePush.sig="v";var runtimeKeepalivePop=()=>{runtimeKeepaliveCounter-=1};Module["runtimeKeepalivePop"]=runtimeKeepalivePop;runtimeKeepalivePop.sig="v";var _emscripten_runtime_keepalive_push=runtimeKeepalivePush;Module["_emscripten_runtime_keepalive_push"]=_emscripten_runtime_keepalive_push;_emscripten_runtime_keepalive_push.sig="v";var _emscripten_runtime_keepalive_pop=runtimeKeepalivePop;Module["_emscripten_runtime_keepalive_pop"]=_emscripten_runtime_keepalive_pop;_emscripten_runtime_keepalive_pop.sig="v";var _emscripten_runtime_keepalive_check=keepRuntimeAlive;Module["_emscripten_runtime_keepalive_check"]=_emscripten_runtime_keepalive_check;_emscripten_runtime_keepalive_check.sig="i";var asmjsMangle=x=>{if(x=="__main_argc_argv"){x="main"}return x.startsWith("dynCall_")?x:"_"+x};Module["asmjsMangle"]=asmjsMangle;var ___global_base=1024;Module["___global_base"]=___global_base;function __emscripten_fs_load_embedded_files(ptr){ptr>>>=0;do{var name_addr=HEAPU32[ptr>>>2>>>0];ptr+=4;var len=HEAPU32[ptr>>>2>>>0];ptr+=4;var content=HEAPU32[ptr>>>2>>>0];ptr+=4;var name=UTF8ToString(name_addr);FS.createPath("/",PATH.dirname(name),true,true);FS.createDataFile(name,null,HEAP8.subarray(content>>>0,content+len>>>0),true,true,true)}while(HEAPU32[ptr>>>2>>>0])}Module["__emscripten_fs_load_embedded_files"]=__emscripten_fs_load_embedded_files;__emscripten_fs_load_embedded_files.sig="vp";var POINTER_SIZE=4;Module["POINTER_SIZE"]=POINTER_SIZE;function getNativeTypeSize(type){switch(type){case"i1":case"i8":case"u8":return 1;case"i16":case"u16":return 2;case"i32":case"u32":return 4;case"i64":case"u64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return POINTER_SIZE}if(type[0]==="i"){const bits=Number(type.substr(1));assert(bits%8===0,`getNativeTypeSize invalid bits ${bits}, ${type} type`);return bits/8}return 0}}}Module["getNativeTypeSize"]=getNativeTypeSize;var STACK_SIZE=5242880;Module["STACK_SIZE"]=STACK_SIZE;var STACK_ALIGN=16;Module["STACK_ALIGN"]=STACK_ALIGN;var ASSERTIONS=0;Module["ASSERTIONS"]=ASSERTIONS;var getCFunc=ident=>{var func=Module["_"+ident];return func};Module["getCFunc"]=getCFunc;var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={"string":str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},"array":arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};Module["cwrap"]=cwrap;var removeFunction=index=>{functionsInTableMap.delete(getWasmTableEntry(index));setWasmTableEntry(index,null);freeTableIndexes.push(index)};Module["removeFunction"]=removeFunction;var _emscripten_math_cbrt=Math.cbrt;Module["_emscripten_math_cbrt"]=_emscripten_math_cbrt;_emscripten_math_cbrt.sig="dd";var _emscripten_math_pow=Math.pow;Module["_emscripten_math_pow"]=_emscripten_math_pow;_emscripten_math_pow.sig="ddd";var _emscripten_math_random=Math.random;Module["_emscripten_math_random"]=_emscripten_math_random;_emscripten_math_random.sig="d";var _emscripten_math_sign=Math.sign;Module["_emscripten_math_sign"]=_emscripten_math_sign;_emscripten_math_sign.sig="dd";var _emscripten_math_sqrt=Math.sqrt;Module["_emscripten_math_sqrt"]=_emscripten_math_sqrt;_emscripten_math_sqrt.sig="dd";var _emscripten_math_exp=Math.exp;Module["_emscripten_math_exp"]=_emscripten_math_exp;_emscripten_math_exp.sig="dd";var _emscripten_math_expm1=Math.expm1;Module["_emscripten_math_expm1"]=_emscripten_math_expm1;_emscripten_math_expm1.sig="dd";var _emscripten_math_fmod=(x,y)=>x%y;Module["_emscripten_math_fmod"]=_emscripten_math_fmod;_emscripten_math_fmod.sig="ddd";var _emscripten_math_log=Math.log;Module["_emscripten_math_log"]=_emscripten_math_log;_emscripten_math_log.sig="dd";var _emscripten_math_log1p=Math.log1p;Module["_emscripten_math_log1p"]=_emscripten_math_log1p;_emscripten_math_log1p.sig="dd";var _emscripten_math_log10=Math.log10;Module["_emscripten_math_log10"]=_emscripten_math_log10;_emscripten_math_log10.sig="dd";var _emscripten_math_log2=Math.log2;Module["_emscripten_math_log2"]=_emscripten_math_log2;_emscripten_math_log2.sig="dd";var _emscripten_math_round=Math.round;Module["_emscripten_math_round"]=_emscripten_math_round;_emscripten_math_round.sig="dd";var _emscripten_math_acos=Math.acos;Module["_emscripten_math_acos"]=_emscripten_math_acos;_emscripten_math_acos.sig="dd";var _emscripten_math_acosh=Math.acosh;Module["_emscripten_math_acosh"]=_emscripten_math_acosh;_emscripten_math_acosh.sig="dd";var _emscripten_math_asin=Math.asin;Module["_emscripten_math_asin"]=_emscripten_math_asin;_emscripten_math_asin.sig="dd";var _emscripten_math_asinh=Math.asinh;Module["_emscripten_math_asinh"]=_emscripten_math_asinh;_emscripten_math_asinh.sig="dd";var _emscripten_math_atan=Math.atan;Module["_emscripten_math_atan"]=_emscripten_math_atan;_emscripten_math_atan.sig="dd";var _emscripten_math_atanh=Math.atanh;Module["_emscripten_math_atanh"]=_emscripten_math_atanh;_emscripten_math_atanh.sig="dd";var _emscripten_math_atan2=Math.atan2;Module["_emscripten_math_atan2"]=_emscripten_math_atan2;_emscripten_math_atan2.sig="ddd";var _emscripten_math_cos=Math.cos;Module["_emscripten_math_cos"]=_emscripten_math_cos;_emscripten_math_cos.sig="dd";var _emscripten_math_cosh=Math.cosh;Module["_emscripten_math_cosh"]=_emscripten_math_cosh;_emscripten_math_cosh.sig="dd";function _emscripten_math_hypot(count,varargs){varargs>>>=0;var args=[];for(var i=0;i>>3>>>0])}return Math.hypot(...args)}Module["_emscripten_math_hypot"]=_emscripten_math_hypot;_emscripten_math_hypot.sig="dip";var _emscripten_math_sin=Math.sin;Module["_emscripten_math_sin"]=_emscripten_math_sin;_emscripten_math_sin.sig="dd";var _emscripten_math_sinh=Math.sinh;Module["_emscripten_math_sinh"]=_emscripten_math_sinh;_emscripten_math_sinh.sig="dd";var _emscripten_math_tan=Math.tan;Module["_emscripten_math_tan"]=_emscripten_math_tan;_emscripten_math_tan.sig="dd";var _emscripten_math_tanh=Math.tanh;Module["_emscripten_math_tanh"]=_emscripten_math_tanh;_emscripten_math_tanh.sig="dd";function intArrayToString(array){var ret=[];for(var i=0;i255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}Module["intArrayToString"]=intArrayToString;var AsciiToString=ptr=>{ptr>>>=0;var str="";while(1){var ch=HEAPU8[ptr++>>>0];if(!ch)return str;str+=String.fromCharCode(ch)}};Module["AsciiToString"]=AsciiToString;var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;Module["UTF16Decoder"]=UTF16Decoder;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx>>>0])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr>>>0,endPtr>>>0));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>>1>>>0];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};Module["UTF16ToString"]=UTF16ToString;var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>>1>>>0]=codeUnit;outPtr+=2}HEAP16[outPtr>>>1>>>0]=0;return outPtr-startPtr};Module["stringToUTF16"]=stringToUTF16;var lengthBytesUTF16=str=>str.length*2;Module["lengthBytesUTF16"]=lengthBytesUTF16;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>>2>>>0];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};Module["UTF32ToString"]=UTF32ToString;var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{outPtr>>>=0;maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>>2>>>0]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>>2>>>0]=0;return outPtr-startPtr};Module["stringToUTF32"]=stringToUTF32;var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};Module["lengthBytesUTF32"]=lengthBytesUTF32;var JSEvents={removeAllEventListeners(){while(JSEvents.eventHandlers.length){JSEvents._removeHandler(JSEvents.eventHandlers.length-1)}JSEvents.deferredCalls=[]},inEventHandler:0,deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedence{for(var i=0;icString>2?UTF8ToString(cString):cString;Module["maybeCStringToJsString"]=maybeCStringToJsString;var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];Module["specialHTMLTargets"]=specialHTMLTargets;var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):undefined);return domElement};Module["findEventTarget"]=findEventTarget;var registerKeyEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.keyEvent)JSEvents.keyEvent=_malloc(176);var keyEventHandlerFunc=e=>{var keyEventData=JSEvents.keyEvent;HEAPF64[keyEventData>>>3>>>0]=e.timeStamp;var idx=keyEventData>>>2;HEAP32[idx+2>>>0]=e.location;HEAP32[idx+3>>>0]=e.ctrlKey;HEAP32[idx+4>>>0]=e.shiftKey;HEAP32[idx+5>>>0]=e.altKey;HEAP32[idx+6>>>0]=e.metaKey;HEAP32[idx+7>>>0]=e.repeat;HEAP32[idx+8>>>0]=e.charCode;HEAP32[idx+9>>>0]=e.keyCode;HEAP32[idx+10>>>0]=e.which;stringToUTF8(e.key||"",keyEventData+44,32);stringToUTF8(e.code||"",keyEventData+76,32);stringToUTF8(e.char||"",keyEventData+108,32);stringToUTF8(e.locale||"",keyEventData+140,32);if(getWasmTableEntry(callbackfunc)(eventTypeId,keyEventData,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:keyEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerKeyEventCallback"]=registerKeyEventCallback;var findCanvasEventTarget=findEventTarget;Module["findCanvasEventTarget"]=findCanvasEventTarget;function _emscripten_set_keypress_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,1,"keypress",targetThread)}Module["_emscripten_set_keypress_callback_on_thread"]=_emscripten_set_keypress_callback_on_thread;_emscripten_set_keypress_callback_on_thread.sig="ippipp";function _emscripten_set_keydown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,2,"keydown",targetThread)}Module["_emscripten_set_keydown_callback_on_thread"]=_emscripten_set_keydown_callback_on_thread;_emscripten_set_keydown_callback_on_thread.sig="ippipp";function _emscripten_set_keyup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerKeyEventCallback(target,userData,useCapture,callbackfunc,3,"keyup",targetThread)}Module["_emscripten_set_keyup_callback_on_thread"]=_emscripten_set_keyup_callback_on_thread;_emscripten_set_keyup_callback_on_thread.sig="ippipp";var getBoundingClientRect=e=>specialHTMLTargets.indexOf(e)<0?e.getBoundingClientRect():{"left":0,"top":0};Module["getBoundingClientRect"]=getBoundingClientRect;var fillMouseEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.timeStamp;var idx=eventStruct>>>2;HEAP32[idx+2>>>0]=e.screenX;HEAP32[idx+3>>>0]=e.screenY;HEAP32[idx+4>>>0]=e.clientX;HEAP32[idx+5>>>0]=e.clientY;HEAP32[idx+6>>>0]=e.ctrlKey;HEAP32[idx+7>>>0]=e.shiftKey;HEAP32[idx+8>>>0]=e.altKey;HEAP32[idx+9>>>0]=e.metaKey;HEAP16[idx*2+20>>>0]=e.button;HEAP16[idx*2+21>>>0]=e.buttons;HEAP32[idx+11>>>0]=e["movementX"];HEAP32[idx+12>>>0]=e["movementY"];var rect=getBoundingClientRect(target);HEAP32[idx+13>>>0]=e.clientX-(rect.left|0);HEAP32[idx+14>>>0]=e.clientY-(rect.top|0)};Module["fillMouseEventData"]=fillMouseEventData;var registerMouseEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.mouseEvent)JSEvents.mouseEvent=_malloc(72);target=findEventTarget(target);var mouseEventHandlerFunc=(e=event)=>{fillMouseEventData(JSEvents.mouseEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.mouseEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString!="mousemove"&&eventTypeString!="mouseenter"&&eventTypeString!="mouseleave",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:mouseEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerMouseEventCallback"]=registerMouseEventCallback;function _emscripten_set_click_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,4,"click",targetThread)}Module["_emscripten_set_click_callback_on_thread"]=_emscripten_set_click_callback_on_thread;_emscripten_set_click_callback_on_thread.sig="ippipp";function _emscripten_set_mousedown_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,5,"mousedown",targetThread)}Module["_emscripten_set_mousedown_callback_on_thread"]=_emscripten_set_mousedown_callback_on_thread;_emscripten_set_mousedown_callback_on_thread.sig="ippipp";function _emscripten_set_mouseup_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,6,"mouseup",targetThread)}Module["_emscripten_set_mouseup_callback_on_thread"]=_emscripten_set_mouseup_callback_on_thread;_emscripten_set_mouseup_callback_on_thread.sig="ippipp";function _emscripten_set_dblclick_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,7,"dblclick",targetThread)}Module["_emscripten_set_dblclick_callback_on_thread"]=_emscripten_set_dblclick_callback_on_thread;_emscripten_set_dblclick_callback_on_thread.sig="ippipp";function _emscripten_set_mousemove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,8,"mousemove",targetThread)}Module["_emscripten_set_mousemove_callback_on_thread"]=_emscripten_set_mousemove_callback_on_thread;_emscripten_set_mousemove_callback_on_thread.sig="ippipp";function _emscripten_set_mouseenter_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,33,"mouseenter",targetThread)}Module["_emscripten_set_mouseenter_callback_on_thread"]=_emscripten_set_mouseenter_callback_on_thread;_emscripten_set_mouseenter_callback_on_thread.sig="ippipp";function _emscripten_set_mouseleave_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,34,"mouseleave",targetThread)}Module["_emscripten_set_mouseleave_callback_on_thread"]=_emscripten_set_mouseleave_callback_on_thread;_emscripten_set_mouseleave_callback_on_thread.sig="ippipp";function _emscripten_set_mouseover_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,35,"mouseover",targetThread)}Module["_emscripten_set_mouseover_callback_on_thread"]=_emscripten_set_mouseover_callback_on_thread;_emscripten_set_mouseover_callback_on_thread.sig="ippipp";function _emscripten_set_mouseout_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerMouseEventCallback(target,userData,useCapture,callbackfunc,36,"mouseout",targetThread)}Module["_emscripten_set_mouseout_callback_on_thread"]=_emscripten_set_mouseout_callback_on_thread;_emscripten_set_mouseout_callback_on_thread.sig="ippipp";function _emscripten_get_mouse_status(mouseState){mouseState>>>=0;if(!JSEvents.mouseEvent)return-7;HEAP8.set(HEAP8.subarray(JSEvents.mouseEvent>>>0,JSEvents.mouseEvent+72>>>0),mouseState>>>0);return 0}Module["_emscripten_get_mouse_status"]=_emscripten_get_mouse_status;_emscripten_get_mouse_status.sig="ip";var registerWheelEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.wheelEvent)JSEvents.wheelEvent=_malloc(104);var wheelHandlerFunc=(e=event)=>{var wheelEvent=JSEvents.wheelEvent;fillMouseEventData(wheelEvent,e,target);HEAPF64[wheelEvent+72>>>3>>>0]=e["deltaX"];HEAPF64[wheelEvent+80>>>3>>>0]=e["deltaY"];HEAPF64[wheelEvent+88>>>3>>>0]=e["deltaZ"];HEAP32[wheelEvent+96>>>2>>>0]=e["deltaMode"];if(getWasmTableEntry(callbackfunc)(eventTypeId,wheelEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:wheelHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerWheelEventCallback"]=registerWheelEventCallback;function _emscripten_set_wheel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;target=findEventTarget(target);if(!target)return-4;if(typeof target.onwheel!="undefined"){return registerWheelEventCallback(target,userData,useCapture,callbackfunc,9,"wheel",targetThread)}else{return-1}}Module["_emscripten_set_wheel_callback_on_thread"]=_emscripten_set_wheel_callback_on_thread;_emscripten_set_wheel_callback_on_thread.sig="ippipp";var registerUiEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.uiEvent)JSEvents.uiEvent=_malloc(36);target=findEventTarget(target);var uiEventHandlerFunc=(e=event)=>{if(e.target!=target){return}var b=document.body;if(!b){return}var uiEvent=JSEvents.uiEvent;HEAP32[uiEvent>>>2>>>0]=0;HEAP32[uiEvent+4>>>2>>>0]=b.clientWidth;HEAP32[uiEvent+8>>>2>>>0]=b.clientHeight;HEAP32[uiEvent+12>>>2>>>0]=innerWidth;HEAP32[uiEvent+16>>>2>>>0]=innerHeight;HEAP32[uiEvent+20>>>2>>>0]=outerWidth;HEAP32[uiEvent+24>>>2>>>0]=outerHeight;HEAP32[uiEvent+28>>>2>>>0]=pageXOffset|0;HEAP32[uiEvent+32>>>2>>>0]=pageYOffset|0;if(getWasmTableEntry(callbackfunc)(eventTypeId,uiEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:uiEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerUiEventCallback"]=registerUiEventCallback;function _emscripten_set_resize_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,10,"resize",targetThread)}Module["_emscripten_set_resize_callback_on_thread"]=_emscripten_set_resize_callback_on_thread;_emscripten_set_resize_callback_on_thread.sig="ippipp";function _emscripten_set_scroll_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerUiEventCallback(target,userData,useCapture,callbackfunc,11,"scroll",targetThread)}Module["_emscripten_set_scroll_callback_on_thread"]=_emscripten_set_scroll_callback_on_thread;_emscripten_set_scroll_callback_on_thread.sig="ippipp";var registerFocusEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.focusEvent)JSEvents.focusEvent=_malloc(256);var focusEventHandlerFunc=(e=event)=>{var nodeName=JSEvents.getNodeNameForTarget(e.target);var id=e.target.id?e.target.id:"";var focusEvent=JSEvents.focusEvent;stringToUTF8(nodeName,focusEvent+0,128);stringToUTF8(id,focusEvent+128,128);if(getWasmTableEntry(callbackfunc)(eventTypeId,focusEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:focusEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerFocusEventCallback"]=registerFocusEventCallback;function _emscripten_set_blur_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,12,"blur",targetThread)}Module["_emscripten_set_blur_callback_on_thread"]=_emscripten_set_blur_callback_on_thread;_emscripten_set_blur_callback_on_thread.sig="ippipp";function _emscripten_set_focus_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,13,"focus",targetThread)}Module["_emscripten_set_focus_callback_on_thread"]=_emscripten_set_focus_callback_on_thread;_emscripten_set_focus_callback_on_thread.sig="ippipp";function _emscripten_set_focusin_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,14,"focusin",targetThread)}Module["_emscripten_set_focusin_callback_on_thread"]=_emscripten_set_focusin_callback_on_thread;_emscripten_set_focusin_callback_on_thread.sig="ippipp";function _emscripten_set_focusout_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerFocusEventCallback(target,userData,useCapture,callbackfunc,15,"focusout",targetThread)}Module["_emscripten_set_focusout_callback_on_thread"]=_emscripten_set_focusout_callback_on_thread;_emscripten_set_focusout_callback_on_thread.sig="ippipp";var fillDeviceOrientationEventData=(eventStruct,e,target)=>{HEAPF64[eventStruct>>>3>>>0]=e.alpha;HEAPF64[eventStruct+8>>>3>>>0]=e.beta;HEAPF64[eventStruct+16>>>3>>>0]=e.gamma;HEAP32[eventStruct+24>>>2>>>0]=e.absolute};Module["fillDeviceOrientationEventData"]=fillDeviceOrientationEventData;var registerDeviceOrientationEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.deviceOrientationEvent)JSEvents.deviceOrientationEvent=_malloc(32);var deviceOrientationEventHandlerFunc=(e=event)=>{fillDeviceOrientationEventData(JSEvents.deviceOrientationEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.deviceOrientationEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:deviceOrientationEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerDeviceOrientationEventCallback"]=registerDeviceOrientationEventCallback;function _emscripten_set_deviceorientation_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerDeviceOrientationEventCallback(2,userData,useCapture,callbackfunc,16,"deviceorientation",targetThread)}Module["_emscripten_set_deviceorientation_callback_on_thread"]=_emscripten_set_deviceorientation_callback_on_thread;_emscripten_set_deviceorientation_callback_on_thread.sig="ipipp";function _emscripten_get_deviceorientation_status(orientationState){orientationState>>>=0;if(!JSEvents.deviceOrientationEvent)return-7;HEAP32.set(HEAP32.subarray(JSEvents.deviceOrientationEvent>>>0,32>>>0),orientationState>>>0);return 0}Module["_emscripten_get_deviceorientation_status"]=_emscripten_get_deviceorientation_status;_emscripten_get_deviceorientation_status.sig="ip";var fillDeviceMotionEventData=(eventStruct,e,target)=>{var supportedFields=0;var a=e["acceleration"];supportedFields|=a&&1;var ag=e["accelerationIncludingGravity"];supportedFields|=ag&&2;var rr=e["rotationRate"];supportedFields|=rr&&4;a=a||{};ag=ag||{};rr=rr||{};HEAPF64[eventStruct>>>3>>>0]=a["x"];HEAPF64[eventStruct+8>>>3>>>0]=a["y"];HEAPF64[eventStruct+16>>>3>>>0]=a["z"];HEAPF64[eventStruct+24>>>3>>>0]=ag["x"];HEAPF64[eventStruct+32>>>3>>>0]=ag["y"];HEAPF64[eventStruct+40>>>3>>>0]=ag["z"];HEAPF64[eventStruct+48>>>3>>>0]=rr["alpha"];HEAPF64[eventStruct+56>>>3>>>0]=rr["beta"];HEAPF64[eventStruct+64>>>3>>>0]=rr["gamma"]};Module["fillDeviceMotionEventData"]=fillDeviceMotionEventData;var registerDeviceMotionEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.deviceMotionEvent)JSEvents.deviceMotionEvent=_malloc(80);var deviceMotionEventHandlerFunc=(e=event)=>{fillDeviceMotionEventData(JSEvents.deviceMotionEvent,e,target);if(getWasmTableEntry(callbackfunc)(eventTypeId,JSEvents.deviceMotionEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:deviceMotionEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerDeviceMotionEventCallback"]=registerDeviceMotionEventCallback;function _emscripten_set_devicemotion_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerDeviceMotionEventCallback(2,userData,useCapture,callbackfunc,17,"devicemotion",targetThread)}Module["_emscripten_set_devicemotion_callback_on_thread"]=_emscripten_set_devicemotion_callback_on_thread;_emscripten_set_devicemotion_callback_on_thread.sig="ipipp";function _emscripten_get_devicemotion_status(motionState){motionState>>>=0;if(!JSEvents.deviceMotionEvent)return-7;HEAP32.set(HEAP32.subarray(JSEvents.deviceMotionEvent>>>0,80>>>0),motionState>>>0);return 0}Module["_emscripten_get_devicemotion_status"]=_emscripten_get_devicemotion_status;_emscripten_get_devicemotion_status.sig="ip";var screenOrientation=()=>{if(!window.screen)return undefined;return screen.orientation||screen["mozOrientation"]||screen["webkitOrientation"]};Module["screenOrientation"]=screenOrientation;var fillOrientationChangeEventData=eventStruct=>{var orientationsType1=["portrait-primary","portrait-secondary","landscape-primary","landscape-secondary"];var orientationsType2=["portrait","portrait","landscape","landscape"];var orientationIndex=0;var orientationAngle=0;var screenOrientObj=screenOrientation();if(typeof screenOrientObj==="object"){orientationIndex=orientationsType1.indexOf(screenOrientObj.type);if(orientationIndex<0){orientationIndex=orientationsType2.indexOf(screenOrientObj.type)}if(orientationIndex>=0){orientationIndex=1<>>2>>>0]=orientationIndex;HEAP32[eventStruct+4>>>2>>>0]=orientationAngle};Module["fillOrientationChangeEventData"]=fillOrientationChangeEventData;var registerOrientationChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.orientationChangeEvent)JSEvents.orientationChangeEvent=_malloc(8);var orientationChangeEventHandlerFunc=(e=event)=>{var orientationChangeEvent=JSEvents.orientationChangeEvent;fillOrientationChangeEventData(orientationChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,orientationChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:orientationChangeEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerOrientationChangeEventCallback"]=registerOrientationChangeEventCallback;function _emscripten_set_orientationchange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!window.screen||!screen.orientation)return-1;return registerOrientationChangeEventCallback(screen.orientation,userData,useCapture,callbackfunc,18,"change",targetThread)}Module["_emscripten_set_orientationchange_callback_on_thread"]=_emscripten_set_orientationchange_callback_on_thread;_emscripten_set_orientationchange_callback_on_thread.sig="ipipp";function _emscripten_get_orientation_status(orientationChangeEvent){orientationChangeEvent>>>=0;if(!screenOrientation()&&typeof orientation=="undefined")return-1;fillOrientationChangeEventData(orientationChangeEvent);return 0}Module["_emscripten_get_orientation_status"]=_emscripten_get_orientation_status;_emscripten_get_orientation_status.sig="ip";var _emscripten_lock_orientation=allowedOrientations=>{var orientations=[];if(allowedOrientations&1)orientations.push("portrait-primary");if(allowedOrientations&2)orientations.push("portrait-secondary");if(allowedOrientations&4)orientations.push("landscape-primary");if(allowedOrientations&8)orientations.push("landscape-secondary");var succeeded;if(screen.lockOrientation){succeeded=screen.lockOrientation(orientations)}else if(screen.mozLockOrientation){succeeded=screen.mozLockOrientation(orientations)}else if(screen.webkitLockOrientation){succeeded=screen.webkitLockOrientation(orientations)}else{return-1}if(succeeded){return 0}return-6};Module["_emscripten_lock_orientation"]=_emscripten_lock_orientation;_emscripten_lock_orientation.sig="ii";var _emscripten_unlock_orientation=()=>{if(screen.unlockOrientation){screen.unlockOrientation()}else if(screen.mozUnlockOrientation){screen.mozUnlockOrientation()}else if(screen.webkitUnlockOrientation){screen.webkitUnlockOrientation()}else{return-1}return 0};Module["_emscripten_unlock_orientation"]=_emscripten_unlock_orientation;_emscripten_unlock_orientation.sig="i";var fillFullscreenChangeEventData=eventStruct=>{var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;var isFullscreen=!!fullscreenElement;HEAP32[eventStruct>>>2>>>0]=isFullscreen;HEAP32[eventStruct+4>>>2>>>0]=JSEvents.fullscreenEnabled();var reportedElement=isFullscreen?fullscreenElement:JSEvents.previousFullscreenElement;var nodeName=JSEvents.getNodeNameForTarget(reportedElement);var id=reportedElement?.id||"";stringToUTF8(nodeName,eventStruct+8,128);stringToUTF8(id,eventStruct+136,128);HEAP32[eventStruct+264>>>2>>>0]=reportedElement?reportedElement.clientWidth:0;HEAP32[eventStruct+268>>>2>>>0]=reportedElement?reportedElement.clientHeight:0;HEAP32[eventStruct+272>>>2>>>0]=screen.width;HEAP32[eventStruct+276>>>2>>>0]=screen.height;if(isFullscreen){JSEvents.previousFullscreenElement=fullscreenElement}};Module["fillFullscreenChangeEventData"]=fillFullscreenChangeEventData;var registerFullscreenChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.fullscreenChangeEvent)JSEvents.fullscreenChangeEvent=_malloc(280);var fullscreenChangeEventhandlerFunc=(e=event)=>{var fullscreenChangeEvent=JSEvents.fullscreenChangeEvent;fillFullscreenChangeEventData(fullscreenChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,fullscreenChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:fullscreenChangeEventhandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerFullscreenChangeEventCallback"]=registerFullscreenChangeEventCallback;function _emscripten_set_fullscreenchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"webkitfullscreenchange",targetThread);return registerFullscreenChangeEventCallback(target,userData,useCapture,callbackfunc,19,"fullscreenchange",targetThread)}Module["_emscripten_set_fullscreenchange_callback_on_thread"]=_emscripten_set_fullscreenchange_callback_on_thread;_emscripten_set_fullscreenchange_callback_on_thread.sig="ippipp";function _emscripten_get_fullscreen_status(fullscreenStatus){fullscreenStatus>>>=0;if(!JSEvents.fullscreenEnabled())return-1;fillFullscreenChangeEventData(fullscreenStatus);return 0}Module["_emscripten_get_fullscreen_status"]=_emscripten_get_fullscreen_status;_emscripten_get_fullscreen_status.sig="ip";function _emscripten_get_canvas_element_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;HEAP32[width>>>2>>>0]=canvas.width;HEAP32[height>>>2>>>0]=canvas.height}Module["_emscripten_get_canvas_element_size"]=_emscripten_get_canvas_element_size;_emscripten_get_canvas_element_size.sig="ippp";var getCanvasElementSize=target=>{var sp=stackSave();var w=stackAlloc(8);var h=w+4;var targetInt=stringToUTF8OnStack(target.id);var ret=_emscripten_get_canvas_element_size(targetInt,w,h);var size=[HEAP32[w>>>2>>>0],HEAP32[h>>>2>>>0]];stackRestore(sp);return size};Module["getCanvasElementSize"]=getCanvasElementSize;function _emscripten_set_canvas_element_size(target,width,height){target>>>=0;var canvas=findCanvasEventTarget(target);if(!canvas)return-4;canvas.width=width;canvas.height=height;return 0}Module["_emscripten_set_canvas_element_size"]=_emscripten_set_canvas_element_size;_emscripten_set_canvas_element_size.sig="ipii";var setCanvasElementSize=(target,width,height)=>{if(!target.controlTransferredOffscreen){target.width=width;target.height=height}else{var sp=stackSave();var targetInt=stringToUTF8OnStack(target.id);_emscripten_set_canvas_element_size(targetInt,width,height);stackRestore(sp)}};Module["setCanvasElementSize"]=setCanvasElementSize;var registerRestoreOldStyle=canvas=>{var canvasSize=getCanvasElementSize(canvas);var oldWidth=canvasSize[0];var oldHeight=canvasSize[1];var oldCssWidth=canvas.style.width;var oldCssHeight=canvas.style.height;var oldBackgroundColor=canvas.style.backgroundColor;var oldDocumentBackgroundColor=document.body.style.backgroundColor;var oldPaddingLeft=canvas.style.paddingLeft;var oldPaddingRight=canvas.style.paddingRight;var oldPaddingTop=canvas.style.paddingTop;var oldPaddingBottom=canvas.style.paddingBottom;var oldMarginLeft=canvas.style.marginLeft;var oldMarginRight=canvas.style.marginRight;var oldMarginTop=canvas.style.marginTop;var oldMarginBottom=canvas.style.marginBottom;var oldDocumentBodyMargin=document.body.style.margin;var oldDocumentOverflow=document.documentElement.style.overflow;var oldDocumentScroll=document.body.scroll;var oldImageRendering=canvas.style.imageRendering;function restoreOldStyle(){var fullscreenElement=document.fullscreenElement||document.webkitFullscreenElement;if(!fullscreenElement){document.removeEventListener("fullscreenchange",restoreOldStyle);document.removeEventListener("webkitfullscreenchange",restoreOldStyle);setCanvasElementSize(canvas,oldWidth,oldHeight);canvas.style.width=oldCssWidth;canvas.style.height=oldCssHeight;canvas.style.backgroundColor=oldBackgroundColor;if(!oldDocumentBackgroundColor)document.body.style.backgroundColor="white";document.body.style.backgroundColor=oldDocumentBackgroundColor;canvas.style.paddingLeft=oldPaddingLeft;canvas.style.paddingRight=oldPaddingRight;canvas.style.paddingTop=oldPaddingTop;canvas.style.paddingBottom=oldPaddingBottom;canvas.style.marginLeft=oldMarginLeft;canvas.style.marginRight=oldMarginRight;canvas.style.marginTop=oldMarginTop;canvas.style.marginBottom=oldMarginBottom;document.body.style.margin=oldDocumentBodyMargin;document.documentElement.style.overflow=oldDocumentOverflow;document.body.scroll=oldDocumentScroll;canvas.style.imageRendering=oldImageRendering;if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,oldWidth,oldHeight);if(currentFullscreenStrategy.canvasResizedCallback){getWasmTableEntry(currentFullscreenStrategy.canvasResizedCallback)(37,0,currentFullscreenStrategy.canvasResizedCallbackUserData)}}}document.addEventListener("fullscreenchange",restoreOldStyle);document.addEventListener("webkitfullscreenchange",restoreOldStyle);return restoreOldStyle};Module["registerRestoreOldStyle"]=registerRestoreOldStyle;var setLetterbox=(element,topBottom,leftRight)=>{element.style.paddingLeft=element.style.paddingRight=leftRight+"px";element.style.paddingTop=element.style.paddingBottom=topBottom+"px"};Module["setLetterbox"]=setLetterbox;var JSEvents_resizeCanvasForFullscreen=(target,strategy)=>{var restoreOldStyle=registerRestoreOldStyle(target);var cssWidth=strategy.softFullscreen?innerWidth:screen.width;var cssHeight=strategy.softFullscreen?innerHeight:screen.height;var rect=getBoundingClientRect(target);var windowedCssWidth=rect.width;var windowedCssHeight=rect.height;var canvasSize=getCanvasElementSize(target);var windowedRttWidth=canvasSize[0];var windowedRttHeight=canvasSize[1];if(strategy.scaleMode==3){setLetterbox(target,(cssHeight-windowedCssHeight)/2,(cssWidth-windowedCssWidth)/2);cssWidth=windowedCssWidth;cssHeight=windowedCssHeight}else if(strategy.scaleMode==2){if(cssWidth*windowedRttHeight{if(strategy.scaleMode!=0||strategy.canvasResolutionScaleMode!=0){JSEvents_resizeCanvasForFullscreen(target,strategy)}if(target.requestFullscreen){target.requestFullscreen()}else if(target.webkitRequestFullscreen){target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else{return JSEvents.fullscreenEnabled()?-3:-1}currentFullscreenStrategy=strategy;if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}return 0};Module["JSEvents_requestFullscreen"]=JSEvents_requestFullscreen;var hideEverythingExceptGivenElement=onlyVisibleElement=>{var child=onlyVisibleElement;var parent=child.parentNode;var hiddenElements=[];while(child!=document.body){var children=parent.children;for(var i=0;i{for(var i=0;i{var dpr=devicePixelRatio;var inHiDPIFullscreenMode=currentFullscreenStrategy.canvasResolutionScaleMode==2;var inAspectRatioFixedFullscreenMode=currentFullscreenStrategy.scaleMode==2;var inPixelPerfectFullscreenMode=currentFullscreenStrategy.canvasResolutionScaleMode!=0;var inCenteredWithoutScalingFullscreenMode=currentFullscreenStrategy.scaleMode==3;var screenWidth=inHiDPIFullscreenMode?Math.round(innerWidth*dpr):innerWidth;var screenHeight=inHiDPIFullscreenMode?Math.round(innerHeight*dpr):innerHeight;var w=screenWidth;var h=screenHeight;var canvas=currentFullscreenStrategy.target;var canvasSize=getCanvasElementSize(canvas);var x=canvasSize[0];var y=canvasSize[1];var topMargin;if(inAspectRatioFixedFullscreenMode){if(w*yx*h)w=h*x/y|0;topMargin=(screenHeight-h)/2|0}if(inPixelPerfectFullscreenMode){setCanvasElementSize(canvas,w,h);if(canvas.GLctxObject)canvas.GLctxObject.GLctx.viewport(0,0,w,h)}if(inHiDPIFullscreenMode){topMargin/=dpr;w/=dpr;h/=dpr;w=Math.round(w*1e4)/1e4;h=Math.round(h*1e4)/1e4;topMargin=Math.round(topMargin*1e4)/1e4}if(inCenteredWithoutScalingFullscreenMode){var t=(innerHeight-jstoi_q(canvas.style.height))/2;var b=(innerWidth-jstoi_q(canvas.style.width))/2;setLetterbox(canvas,t,b)}else{canvas.style.width=w+"px";canvas.style.height=h+"px";var b=(innerWidth-w)/2;setLetterbox(canvas,topMargin,b)}if(!inCenteredWithoutScalingFullscreenMode&¤tFullscreenStrategy.canvasResizedCallback){getWasmTableEntry(currentFullscreenStrategy.canvasResizedCallback)(37,0,currentFullscreenStrategy.canvasResizedCallbackUserData)}};Module["softFullscreenResizeWebGLRenderTarget"]=softFullscreenResizeWebGLRenderTarget;var doRequestFullscreen=(target,strategy)=>{if(!JSEvents.fullscreenEnabled())return-1;target=findEventTarget(target);if(!target)return-4;if(!target.requestFullscreen&&!target.webkitRequestFullscreen){return-3}var canPerformRequests=JSEvents.canPerformEventHandlerRequests();if(!canPerformRequests){if(strategy.deferUntilInEventHandler){JSEvents.deferCall(JSEvents_requestFullscreen,1,[target,strategy]);return 1}return-2}return JSEvents_requestFullscreen(target,strategy)};Module["doRequestFullscreen"]=doRequestFullscreen;function _emscripten_request_fullscreen(target,deferUntilInEventHandler){target>>>=0;var strategy={scaleMode:0,canvasResolutionScaleMode:0,filteringMode:0,deferUntilInEventHandler:deferUntilInEventHandler,canvasResizedCallbackTargetThread:2};return doRequestFullscreen(target,strategy)}Module["_emscripten_request_fullscreen"]=_emscripten_request_fullscreen;_emscripten_request_fullscreen.sig="ipi";function _emscripten_request_fullscreen_strategy(target,deferUntilInEventHandler,fullscreenStrategy){target>>>=0;fullscreenStrategy>>>=0;var strategy={scaleMode:HEAP32[fullscreenStrategy>>>2>>>0],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>>2>>>0],filteringMode:HEAP32[fullscreenStrategy+8>>>2>>>0],deferUntilInEventHandler:deferUntilInEventHandler,canvasResizedCallback:HEAP32[fullscreenStrategy+12>>>2>>>0],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>>2>>>0]};return doRequestFullscreen(target,strategy)}Module["_emscripten_request_fullscreen_strategy"]=_emscripten_request_fullscreen_strategy;_emscripten_request_fullscreen_strategy.sig="ipip";function _emscripten_enter_soft_fullscreen(target,fullscreenStrategy){target>>>=0;fullscreenStrategy>>>=0;target=findEventTarget(target);if(!target)return-4;var strategy={scaleMode:HEAP32[fullscreenStrategy>>>2>>>0],canvasResolutionScaleMode:HEAP32[fullscreenStrategy+4>>>2>>>0],filteringMode:HEAP32[fullscreenStrategy+8>>>2>>>0],canvasResizedCallback:HEAP32[fullscreenStrategy+12>>>2>>>0],canvasResizedCallbackUserData:HEAP32[fullscreenStrategy+16>>>2>>>0],target:target,softFullscreen:true};var restoreOldStyle=JSEvents_resizeCanvasForFullscreen(target,strategy);document.documentElement.style.overflow="hidden";document.body.scroll="no";document.body.style.margin="0px";var hiddenElements=hideEverythingExceptGivenElement(target);function restoreWindowedState(){restoreOldStyle();restoreHiddenElements(hiddenElements);removeEventListener("resize",softFullscreenResizeWebGLRenderTarget);if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}currentFullscreenStrategy=0}restoreOldWindowedStyle=restoreWindowedState;currentFullscreenStrategy=strategy;addEventListener("resize",softFullscreenResizeWebGLRenderTarget);if(strategy.canvasResizedCallback){getWasmTableEntry(strategy.canvasResizedCallback)(37,0,strategy.canvasResizedCallbackUserData)}return 0}Module["_emscripten_enter_soft_fullscreen"]=_emscripten_enter_soft_fullscreen;_emscripten_enter_soft_fullscreen.sig="ipp";var _emscripten_exit_soft_fullscreen=()=>{restoreOldWindowedStyle?.();restoreOldWindowedStyle=null;return 0};Module["_emscripten_exit_soft_fullscreen"]=_emscripten_exit_soft_fullscreen;_emscripten_exit_soft_fullscreen.sig="i";var _emscripten_exit_fullscreen=()=>{if(!JSEvents.fullscreenEnabled())return-1;JSEvents.removeDeferredCalls(JSEvents_requestFullscreen);var d=specialHTMLTargets[1];if(d.exitFullscreen){d.fullscreenElement&&d.exitFullscreen()}else if(d.webkitExitFullscreen){d.webkitFullscreenElement&&d.webkitExitFullscreen()}else{return-1}return 0};Module["_emscripten_exit_fullscreen"]=_emscripten_exit_fullscreen;_emscripten_exit_fullscreen.sig="i";var fillPointerlockChangeEventData=eventStruct=>{var pointerLockElement=document.pointerLockElement||document.mozPointerLockElement||document.webkitPointerLockElement||document.msPointerLockElement;var isPointerlocked=!!pointerLockElement;HEAP32[eventStruct>>>2>>>0]=isPointerlocked;var nodeName=JSEvents.getNodeNameForTarget(pointerLockElement);var id=pointerLockElement?.id||"";stringToUTF8(nodeName,eventStruct+4,128);stringToUTF8(id,eventStruct+132,128)};Module["fillPointerlockChangeEventData"]=fillPointerlockChangeEventData;var registerPointerlockChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.pointerlockChangeEvent)JSEvents.pointerlockChangeEvent=_malloc(260);var pointerlockChangeEventHandlerFunc=(e=event)=>{var pointerlockChangeEvent=JSEvents.pointerlockChangeEvent;fillPointerlockChangeEventData(pointerlockChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,pointerlockChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:pointerlockChangeEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerPointerlockChangeEventCallback"]=registerPointerlockChangeEventCallback;function _emscripten_set_pointerlockchange_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!document||!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mozpointerlockchange",targetThread);registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"webkitpointerlockchange",targetThread);registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"mspointerlockchange",targetThread);return registerPointerlockChangeEventCallback(target,userData,useCapture,callbackfunc,20,"pointerlockchange",targetThread)}Module["_emscripten_set_pointerlockchange_callback_on_thread"]=_emscripten_set_pointerlockchange_callback_on_thread;_emscripten_set_pointerlockchange_callback_on_thread.sig="ippipp";var registerPointerlockErrorEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{var pointerlockErrorEventHandlerFunc=(e=event)=>{if(getWasmTableEntry(callbackfunc)(eventTypeId,0,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:pointerlockErrorEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerPointerlockErrorEventCallback"]=registerPointerlockErrorEventCallback;function _emscripten_set_pointerlockerror_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!document||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}target=findEventTarget(target);if(!target)return-4;registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"mozpointerlockerror",targetThread);registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"webkitpointerlockerror",targetThread);registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"mspointerlockerror",targetThread);return registerPointerlockErrorEventCallback(target,userData,useCapture,callbackfunc,38,"pointerlockerror",targetThread)}Module["_emscripten_set_pointerlockerror_callback_on_thread"]=_emscripten_set_pointerlockerror_callback_on_thread;_emscripten_set_pointerlockerror_callback_on_thread.sig="ippipp";function _emscripten_get_pointerlock_status(pointerlockStatus){pointerlockStatus>>>=0;if(pointerlockStatus)fillPointerlockChangeEventData(pointerlockStatus);if(!document.body||!document.body.requestPointerLock&&!document.body.mozRequestPointerLock&&!document.body.webkitRequestPointerLock&&!document.body.msRequestPointerLock){return-1}return 0}Module["_emscripten_get_pointerlock_status"]=_emscripten_get_pointerlock_status;_emscripten_get_pointerlock_status.sig="ip";var requestPointerLock=target=>{if(target.requestPointerLock){target.requestPointerLock()}else{if(document.body.requestPointerLock){return-3}return-1}return 0};Module["requestPointerLock"]=requestPointerLock;function _emscripten_request_pointerlock(target,deferUntilInEventHandler){target>>>=0;target=findEventTarget(target);if(!target)return-4;if(!target.requestPointerLock){return-1}var canPerformRequests=JSEvents.canPerformEventHandlerRequests();if(!canPerformRequests){if(deferUntilInEventHandler){JSEvents.deferCall(requestPointerLock,2,[target]);return 1}return-2}return requestPointerLock(target)}Module["_emscripten_request_pointerlock"]=_emscripten_request_pointerlock;_emscripten_request_pointerlock.sig="ipi";var _emscripten_exit_pointerlock=()=>{JSEvents.removeDeferredCalls(requestPointerLock);if(document.exitPointerLock){document.exitPointerLock()}else{return-1}return 0};Module["_emscripten_exit_pointerlock"]=_emscripten_exit_pointerlock;_emscripten_exit_pointerlock.sig="i";var _emscripten_vibrate=msecs=>{if(!navigator.vibrate)return-1;navigator.vibrate(msecs);return 0};Module["_emscripten_vibrate"]=_emscripten_vibrate;_emscripten_vibrate.sig="ii";function _emscripten_vibrate_pattern(msecsArray,numEntries){msecsArray>>>=0;if(!navigator.vibrate)return-1;var vibrateList=[];for(var i=0;i>>2>>>0];vibrateList.push(msecs)}navigator.vibrate(vibrateList);return 0}Module["_emscripten_vibrate_pattern"]=_emscripten_vibrate_pattern;_emscripten_vibrate_pattern.sig="ipi";var fillVisibilityChangeEventData=eventStruct=>{var visibilityStates=["hidden","visible","prerender","unloaded"];var visibilityState=visibilityStates.indexOf(document.visibilityState);HEAP32[eventStruct>>>2>>>0]=document.hidden;HEAP32[eventStruct+4>>>2>>>0]=visibilityState};Module["fillVisibilityChangeEventData"]=fillVisibilityChangeEventData;var registerVisibilityChangeEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.visibilityChangeEvent)JSEvents.visibilityChangeEvent=_malloc(8);var visibilityChangeEventHandlerFunc=(e=event)=>{var visibilityChangeEvent=JSEvents.visibilityChangeEvent;fillVisibilityChangeEventData(visibilityChangeEvent);if(getWasmTableEntry(callbackfunc)(eventTypeId,visibilityChangeEvent,userData))e.preventDefault()};var eventHandler={target:target,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:visibilityChangeEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerVisibilityChangeEventCallback"]=registerVisibilityChangeEventCallback;function _emscripten_set_visibilitychange_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!specialHTMLTargets[1]){return-4}return registerVisibilityChangeEventCallback(specialHTMLTargets[1],userData,useCapture,callbackfunc,21,"visibilitychange",targetThread)}Module["_emscripten_set_visibilitychange_callback_on_thread"]=_emscripten_set_visibilitychange_callback_on_thread;_emscripten_set_visibilitychange_callback_on_thread.sig="ipipp";function _emscripten_get_visibility_status(visibilityStatus){visibilityStatus>>>=0;if(typeof document.visibilityState=="undefined"&&typeof document.hidden=="undefined"){return-1}fillVisibilityChangeEventData(visibilityStatus);return 0}Module["_emscripten_get_visibility_status"]=_emscripten_get_visibility_status;_emscripten_get_visibility_status.sig="ip";var registerTouchEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.touchEvent)JSEvents.touchEvent=_malloc(1696);target=findEventTarget(target);var touchEventHandlerFunc=e=>{var t,touches={},et=e.touches;for(var i=0;i>>3>>>0]=e.timeStamp;var idx=touchEvent>>>2;HEAP32[idx+3>>>0]=e.ctrlKey;HEAP32[idx+4>>>0]=e.shiftKey;HEAP32[idx+5>>>0]=e.altKey;HEAP32[idx+6>>>0]=e.metaKey;idx+=7;var targetRect=getBoundingClientRect(target);var numTouches=0;for(var i in touches){t=touches[i];HEAP32[idx+0>>>0]=t.identifier;HEAP32[idx+1>>>0]=t.screenX;HEAP32[idx+2>>>0]=t.screenY;HEAP32[idx+3>>>0]=t.clientX;HEAP32[idx+4>>>0]=t.clientY;HEAP32[idx+5>>>0]=t.pageX;HEAP32[idx+6>>>0]=t.pageY;HEAP32[idx+7>>>0]=t.isChanged;HEAP32[idx+8>>>0]=t.onTarget;HEAP32[idx+9>>>0]=t.clientX-(targetRect.left|0);HEAP32[idx+10>>>0]=t.clientY-(targetRect.top|0);idx+=13;if(++numTouches>31){break}}HEAP32[touchEvent+8>>>2>>>0]=numTouches;if(getWasmTableEntry(callbackfunc)(eventTypeId,touchEvent,userData))e.preventDefault()};var eventHandler={target:target,allowsDeferredCalls:eventTypeString=="touchstart"||eventTypeString=="touchend",eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:touchEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerTouchEventCallback"]=registerTouchEventCallback;function _emscripten_set_touchstart_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,22,"touchstart",targetThread)}Module["_emscripten_set_touchstart_callback_on_thread"]=_emscripten_set_touchstart_callback_on_thread;_emscripten_set_touchstart_callback_on_thread.sig="ippipp";function _emscripten_set_touchend_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,23,"touchend",targetThread)}Module["_emscripten_set_touchend_callback_on_thread"]=_emscripten_set_touchend_callback_on_thread;_emscripten_set_touchend_callback_on_thread.sig="ippipp";function _emscripten_set_touchmove_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,24,"touchmove",targetThread)}Module["_emscripten_set_touchmove_callback_on_thread"]=_emscripten_set_touchmove_callback_on_thread;_emscripten_set_touchmove_callback_on_thread.sig="ippipp";function _emscripten_set_touchcancel_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;return registerTouchEventCallback(target,userData,useCapture,callbackfunc,25,"touchcancel",targetThread)}Module["_emscripten_set_touchcancel_callback_on_thread"]=_emscripten_set_touchcancel_callback_on_thread;_emscripten_set_touchcancel_callback_on_thread.sig="ippipp";var fillGamepadEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.timestamp;for(var i=0;i>>3>>>0]=e.axes[i]}for(var i=0;i>>3>>>0]=e.buttons[i].value}else{HEAPF64[eventStruct+i*8+528>>>3>>>0]=e.buttons[i]}}for(var i=0;i>>2>>>0]=e.buttons[i].pressed}else{HEAP32[eventStruct+i*4+1040>>>2>>>0]=e.buttons[i]==1}}HEAP32[eventStruct+1296>>>2>>>0]=e.connected;HEAP32[eventStruct+1300>>>2>>>0]=e.index;HEAP32[eventStruct+8>>>2>>>0]=e.axes.length;HEAP32[eventStruct+12>>>2>>>0]=e.buttons.length;stringToUTF8(e.id,eventStruct+1304,64);stringToUTF8(e.mapping,eventStruct+1368,64)};Module["fillGamepadEventData"]=fillGamepadEventData;var registerGamepadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.gamepadEvent)JSEvents.gamepadEvent=_malloc(1432);var gamepadEventHandlerFunc=(e=event)=>{var gamepadEvent=JSEvents.gamepadEvent;fillGamepadEventData(gamepadEvent,e["gamepad"]);if(getWasmTableEntry(callbackfunc)(eventTypeId,gamepadEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),allowsDeferredCalls:true,eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:gamepadEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerGamepadEventCallback"]=registerGamepadEventCallback;var _emscripten_sample_gamepad_data=()=>{try{if(navigator.getGamepads)return(JSEvents.lastGamepadState=navigator.getGamepads())?0:-1}catch(e){navigator.getGamepads=null}return-1};Module["_emscripten_sample_gamepad_data"]=_emscripten_sample_gamepad_data;_emscripten_sample_gamepad_data.sig="i";function _emscripten_set_gamepadconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(_emscripten_sample_gamepad_data())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,26,"gamepadconnected",targetThread)}Module["_emscripten_set_gamepadconnected_callback_on_thread"]=_emscripten_set_gamepadconnected_callback_on_thread;_emscripten_set_gamepadconnected_callback_on_thread.sig="ipipp";function _emscripten_set_gamepaddisconnected_callback_on_thread(userData,useCapture,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(_emscripten_sample_gamepad_data())return-1;return registerGamepadEventCallback(2,userData,useCapture,callbackfunc,27,"gamepaddisconnected",targetThread)}Module["_emscripten_set_gamepaddisconnected_callback_on_thread"]=_emscripten_set_gamepaddisconnected_callback_on_thread;_emscripten_set_gamepaddisconnected_callback_on_thread.sig="ipipp";var _emscripten_get_num_gamepads=()=>JSEvents.lastGamepadState.length;Module["_emscripten_get_num_gamepads"]=_emscripten_get_num_gamepads;_emscripten_get_num_gamepads.sig="i";function _emscripten_get_gamepad_status(index,gamepadState){gamepadState>>>=0;if(index<0||index>=JSEvents.lastGamepadState.length)return-5;if(!JSEvents.lastGamepadState[index])return-7;fillGamepadEventData(gamepadState,JSEvents.lastGamepadState[index]);return 0}Module["_emscripten_get_gamepad_status"]=_emscripten_get_gamepad_status;_emscripten_get_gamepad_status.sig="iip";var registerBeforeUnloadEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString)=>{var beforeUnloadEventHandlerFunc=(e=event)=>{var confirmationMessage=getWasmTableEntry(callbackfunc)(eventTypeId,0,userData);if(confirmationMessage){confirmationMessage=UTF8ToString(confirmationMessage)}if(confirmationMessage){e.preventDefault();e.returnValue=confirmationMessage;return confirmationMessage}};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:beforeUnloadEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerBeforeUnloadEventCallback"]=registerBeforeUnloadEventCallback;function _emscripten_set_beforeunload_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(typeof onbeforeunload=="undefined")return-1;if(targetThread!==1)return-5;return registerBeforeUnloadEventCallback(2,userData,true,callbackfunc,28,"beforeunload")}Module["_emscripten_set_beforeunload_callback_on_thread"]=_emscripten_set_beforeunload_callback_on_thread;_emscripten_set_beforeunload_callback_on_thread.sig="ippp";var fillBatteryEventData=(eventStruct,e)=>{HEAPF64[eventStruct>>>3>>>0]=e.chargingTime;HEAPF64[eventStruct+8>>>3>>>0]=e.dischargingTime;HEAPF64[eventStruct+16>>>3>>>0]=e.level;HEAP32[eventStruct+24>>>2>>>0]=e.charging};Module["fillBatteryEventData"]=fillBatteryEventData;var battery=()=>navigator.battery||navigator.mozBattery||navigator.webkitBattery;Module["battery"]=battery;var registerBatteryEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{if(!JSEvents.batteryEvent)JSEvents.batteryEvent=_malloc(32);var batteryEventHandlerFunc=(e=event)=>{var batteryEvent=JSEvents.batteryEvent;fillBatteryEventData(batteryEvent,battery());if(getWasmTableEntry(callbackfunc)(eventTypeId,batteryEvent,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:batteryEventHandlerFunc,useCapture:useCapture};return JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerBatteryEventCallback"]=registerBatteryEventCallback;function _emscripten_set_batterychargingchange_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!battery())return-1;return registerBatteryEventCallback(battery(),userData,true,callbackfunc,29,"chargingchange",targetThread)}Module["_emscripten_set_batterychargingchange_callback_on_thread"]=_emscripten_set_batterychargingchange_callback_on_thread;_emscripten_set_batterychargingchange_callback_on_thread.sig="ippp";function _emscripten_set_batterylevelchange_callback_on_thread(userData,callbackfunc,targetThread){userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;if(!battery())return-1;return registerBatteryEventCallback(battery(),userData,true,callbackfunc,30,"levelchange",targetThread)}Module["_emscripten_set_batterylevelchange_callback_on_thread"]=_emscripten_set_batterylevelchange_callback_on_thread;_emscripten_set_batterylevelchange_callback_on_thread.sig="ippp";function _emscripten_get_battery_status(batteryState){batteryState>>>=0;if(!battery())return-1;fillBatteryEventData(batteryState,battery());return 0}Module["_emscripten_get_battery_status"]=_emscripten_get_battery_status;_emscripten_get_battery_status.sig="ip";function __emscripten_set_offscreencanvas_size(target,width,height){target>>>=0;return-1}Module["__emscripten_set_offscreencanvas_size"]=__emscripten_set_offscreencanvas_size;__emscripten_set_offscreencanvas_size.sig="ipii";function _emscripten_set_element_css_size(target,width,height){target>>>=0;target=findEventTarget(target);if(!target)return-4;target.style.width=width+"px";target.style.height=height+"px";return 0}Module["_emscripten_set_element_css_size"]=_emscripten_set_element_css_size;_emscripten_set_element_css_size.sig="ipdd";function _emscripten_get_element_css_size(target,width,height){target>>>=0;width>>>=0;height>>>=0;target=findEventTarget(target);if(!target)return-4;var rect=getBoundingClientRect(target);HEAPF64[width>>>3>>>0]=rect.width;HEAPF64[height>>>3>>>0]=rect.height;return 0}Module["_emscripten_get_element_css_size"]=_emscripten_get_element_css_size;_emscripten_get_element_css_size.sig="ippp";var _emscripten_html5_remove_all_event_listeners=()=>JSEvents.removeAllEventListeners();Module["_emscripten_html5_remove_all_event_listeners"]=_emscripten_html5_remove_all_event_listeners;_emscripten_html5_remove_all_event_listeners.sig="v";var _emscripten_request_animation_frame=function(cb,userData){cb>>>=0;userData>>>=0;return requestAnimationFrame(timeStamp=>getWasmTableEntry(cb)(timeStamp,userData))};Module["_emscripten_request_animation_frame"]=_emscripten_request_animation_frame;_emscripten_request_animation_frame.sig="ipp";var _emscripten_cancel_animation_frame=id=>cancelAnimationFrame(id);Module["_emscripten_cancel_animation_frame"]=_emscripten_cancel_animation_frame;_emscripten_cancel_animation_frame.sig="vi";function _emscripten_request_animation_frame_loop(cb,userData){cb>>>=0;userData>>>=0;function tick(timeStamp){if(getWasmTableEntry(cb)(timeStamp,userData)){requestAnimationFrame(tick)}}return requestAnimationFrame(tick)}Module["_emscripten_request_animation_frame_loop"]=_emscripten_request_animation_frame_loop;_emscripten_request_animation_frame_loop.sig="vpp";var _emscripten_performance_now=()=>performance.now();Module["_emscripten_performance_now"]=_emscripten_performance_now;_emscripten_performance_now.sig="d";var _emscripten_get_device_pixel_ratio=()=>typeof devicePixelRatio=="number"&&devicePixelRatio||1;Module["_emscripten_get_device_pixel_ratio"]=_emscripten_get_device_pixel_ratio;_emscripten_get_device_pixel_ratio.sig="d";function _emscripten_get_callstack(flags,str,maxbytes){str>>>=0;var callstack=getCallstack(flags);if(!str||maxbytes<=0){return lengthBytesUTF8(callstack)+1}var bytesWrittenExcludingNull=stringToUTF8(callstack,str,maxbytes);return bytesWrittenExcludingNull+1}Module["_emscripten_get_callstack"]=_emscripten_get_callstack;_emscripten_get_callstack.sig="iipi";var convertFrameToPC=frame=>{abort("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0};Module["convertFrameToPC"]=convertFrameToPC;function _emscripten_return_address(level){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}var caller=callstack[level+3];return convertFrameToPC(caller)}Module["_emscripten_return_address"]=_emscripten_return_address;_emscripten_return_address.sig="pi";var UNWIND_CACHE={};Module["UNWIND_CACHE"]=UNWIND_CACHE;var saveInUnwindCache=callstack=>{callstack.forEach(frame=>{var pc=convertFrameToPC(frame);if(pc){UNWIND_CACHE[pc]=frame}})};Module["saveInUnwindCache"]=saveInUnwindCache;function _emscripten_stack_snapshot(){var callstack=jsStackTrace().split("\n");if(callstack[0]=="Error"){callstack.shift()}saveInUnwindCache(callstack);UNWIND_CACHE.last_addr=convertFrameToPC(callstack[3]);UNWIND_CACHE.last_stack=callstack;return UNWIND_CACHE.last_addr}Module["_emscripten_stack_snapshot"]=_emscripten_stack_snapshot;_emscripten_stack_snapshot.sig="p";function _emscripten_stack_unwind_buffer(addr,buffer,count){addr>>>=0;buffer>>>=0;var stack;if(UNWIND_CACHE.last_addr==addr){stack=UNWIND_CACHE.last_stack}else{stack=jsStackTrace().split("\n");if(stack[0]=="Error"){stack.shift()}saveInUnwindCache(stack)}var offset=3;while(stack[offset]&&convertFrameToPC(stack[offset])!=addr){++offset}for(var i=0;i>>2>>>0]=convertFrameToPC(stack[i+offset])}return i}Module["_emscripten_stack_unwind_buffer"]=_emscripten_stack_unwind_buffer;_emscripten_stack_unwind_buffer.sig="ippi";function _emscripten_pc_get_function(pc){pc>>>=0;abort("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER");return 0}Module["_emscripten_pc_get_function"]=_emscripten_pc_get_function;_emscripten_pc_get_function.sig="pp";var convertPCtoSourceLocation=pc=>{if(UNWIND_CACHE.last_get_source_pc==pc)return UNWIND_CACHE.last_source;var match;var source;if(!source){var frame=UNWIND_CACHE[pc];if(!frame)return null;if(match=/\((.*):(\d+):(\d+)\)$/.exec(frame)){source={file:match[1],line:match[2],column:match[3]}}else if(match=/@(.*):(\d+):(\d+)/.exec(frame)){source={file:match[1],line:match[2],column:match[3]}}}UNWIND_CACHE.last_get_source_pc=pc;UNWIND_CACHE.last_source=source;return source};Module["convertPCtoSourceLocation"]=convertPCtoSourceLocation;function _emscripten_pc_get_file(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);if(!result)return 0;if(_emscripten_pc_get_file.ret)_free(_emscripten_pc_get_file.ret);_emscripten_pc_get_file.ret=stringToNewUTF8(result.file);return _emscripten_pc_get_file.ret}Module["_emscripten_pc_get_file"]=_emscripten_pc_get_file;_emscripten_pc_get_file.sig="pp";function _emscripten_pc_get_line(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);return result?result.line:0}Module["_emscripten_pc_get_line"]=_emscripten_pc_get_line;_emscripten_pc_get_line.sig="ip";function _emscripten_pc_get_column(pc){pc>>>=0;var result=convertPCtoSourceLocation(pc);return result?result.column||0:0}Module["_emscripten_pc_get_column"]=_emscripten_pc_get_column;_emscripten_pc_get_column.sig="ip";function _random_get(buf,buf_len){buf>>>=0;buf_len>>>=0;try{_getentropy(buf,buf_len);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}Module["_random_get"]=_random_get;_random_get.sig="ipp";var checkWasiClock=clock_id=>clock_id==0||clock_id==1||clock_id==2||clock_id==3;Module["checkWasiClock"]=checkWasiClock;function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);ptime>>>=0;if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=Date.now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP32[ptime>>>2>>>0]=nsec>>>0;HEAP32[ptime+4>>>2>>>0]=nsec/Math.pow(2,32)>>>0;return 0}Module["_clock_time_get"]=_clock_time_get;_clock_time_get.sig="iijp";function _clock_res_get(clk_id,pres){pres>>>=0;if(!checkWasiClock(clk_id)){return 28}var nsec;if(clk_id===0){nsec=1e3*1e3}else if(nowIsMonotonic){nsec=_emscripten_get_now_res()}else{return 52}HEAP32[pres>>>2>>>0]=nsec>>>0;HEAP32[pres+4>>>2>>>0]=nsec/Math.pow(2,32)>>>0;return 0}Module["_clock_res_get"]=_clock_res_get;_clock_res_get.sig="iip";var wasiRightsToMuslOFlags=rights=>{if(rights&2&&rights&64){return 2}if(rights&2){return 0}if(rights&64){return 1}throw new FS.ErrnoError(28)};Module["wasiRightsToMuslOFlags"]=wasiRightsToMuslOFlags;var wasiOFlagsToMuslOFlags=oflags=>{var musl_oflags=0;if(oflags&1){musl_oflags|=64}if(oflags&8){musl_oflags|=512}if(oflags&2){musl_oflags|=65536}if(oflags&4){musl_oflags|=128}return musl_oflags};Module["wasiOFlagsToMuslOFlags"]=wasiOFlagsToMuslOFlags;var createDyncallWrapper=sig=>{var sections=[];var prelude=[0,97,115,109,1,0,0,0];sections.push(prelude);var wrappersig=[sig[0].replace("j","i"),"i",sig.slice(1).replace(/j/g,"ii")].join("");var typeSectionBody=[3];generateFuncType(wrappersig,typeSectionBody);generateFuncType(sig,typeSectionBody);generateFuncType("vi",typeSectionBody);var typeSection=[1];uleb128Encode(typeSectionBody.length,typeSection);typeSection.push(...typeSectionBody);sections.push(typeSection);var importSection=[2,15,2,1,101,1,116,1,112,0,0,1,101,1,114,0,2];sections.push(importSection);var functionSection=[3,2,1,0];sections.push(functionSection);var exportSection=[7,5,1,1,102,0,1];sections.push(exportSection);var convert_code=[];if(sig[0]==="j"){convert_code=[1,1,126]}else{convert_code.push(0)}function localGet(j){convert_code.push(32);uleb128Encode(j,convert_code)}var j=1;for(var i=1;i{throw"unwind"};Module["_emscripten_unwind_to_js_event_loop"]=_emscripten_unwind_to_js_event_loop;_emscripten_unwind_to_js_event_loop.sig="v";var safeSetTimeout=(func,timeout)=>setTimeout(()=>{callUserCallback(func)},timeout);Module["safeSetTimeout"]=safeSetTimeout;var setImmediateWrapped=func=>{setImmediateWrapped.mapping||=[];var id=setImmediateWrapped.mapping.length;setImmediateWrapped.mapping[id]=setImmediate(()=>{setImmediateWrapped.mapping[id]=undefined;func()});return id};Module["setImmediateWrapped"]=setImmediateWrapped;var clearImmediateWrapped=id=>{clearImmediate(setImmediateWrapped.mapping[id]);setImmediateWrapped.mapping[id]=undefined};Module["clearImmediateWrapped"]=clearImmediateWrapped;var polyfillSetImmediate=()=>{};Module["polyfillSetImmediate"]=polyfillSetImmediate;var _emscripten_set_immediate=function(cb,userData){cb>>>=0;userData>>>=0;return emSetImmediate(()=>{callUserCallback(()=>getWasmTableEntry(cb)(userData))})};Module["_emscripten_set_immediate"]=_emscripten_set_immediate;_emscripten_set_immediate.sig="ipp";var _emscripten_clear_immediate=id=>{emClearImmediate(id)};Module["_emscripten_clear_immediate"]=_emscripten_clear_immediate;_emscripten_clear_immediate.sig="vi";var _emscripten_set_immediate_loop=function(cb,userData){cb>>>=0;userData>>>=0;function tick(){callUserCallback(()=>{if(getWasmTableEntry(cb)(userData)){emSetImmediate(tick)}else{}})}emSetImmediate(tick)};Module["_emscripten_set_immediate_loop"]=_emscripten_set_immediate_loop;_emscripten_set_immediate_loop.sig="vpp";var _emscripten_set_timeout=function(cb,msecs,userData){cb>>>=0;userData>>>=0;return safeSetTimeout(()=>getWasmTableEntry(cb)(userData),msecs)};Module["_emscripten_set_timeout"]=_emscripten_set_timeout;_emscripten_set_timeout.sig="ipdp";var _emscripten_clear_timeout=clearTimeout;Module["_emscripten_clear_timeout"]=_emscripten_clear_timeout;_emscripten_clear_timeout.sig="vi";var _emscripten_set_timeout_loop=function(cb,msecs,userData){cb>>>=0;userData>>>=0;function tick(){var t=_emscripten_get_now();var n=t+msecs;callUserCallback(()=>{if(getWasmTableEntry(cb)(t,userData)){setTimeout(tick,n-_emscripten_get_now())}})}return setTimeout(tick,0)};Module["_emscripten_set_timeout_loop"]=_emscripten_set_timeout_loop;_emscripten_set_timeout_loop.sig="vpdp";var _emscripten_set_interval=function(cb,msecs,userData){cb>>>=0;userData>>>=0;return setInterval(()=>{callUserCallback(()=>getWasmTableEntry(cb)(userData))},msecs)};Module["_emscripten_set_interval"]=_emscripten_set_interval;_emscripten_set_interval.sig="ipdp";var _emscripten_clear_interval=id=>{clearInterval(id)};Module["_emscripten_clear_interval"]=_emscripten_clear_interval;_emscripten_clear_interval.sig="vi";var idsToPromises=(idBuf,size)=>{var promises=[];for(var i=0;i>>2>>>0];promises[i]=getPromise(id)}return promises};Module["idsToPromises"]=idsToPromises;var makePromiseCallback=(callback,userData)=>value=>{var stack=stackSave();var resultPtr=stackAlloc(POINTER_SIZE);HEAPU32[resultPtr>>>2>>>0]=0;try{var result=getWasmTableEntry(callback)(resultPtr,userData,value);var resultVal=HEAPU32[resultPtr>>>2>>>0]}catch(e){if(typeof e!="number"){throw 0}throw e}finally{stackRestore(stack)}switch(result){case 0:return resultVal;case 1:return getPromise(resultVal);case 2:var ret=getPromise(resultVal);_emscripten_promise_destroy(resultVal);return ret;case 3:throw resultVal}};Module["makePromiseCallback"]=makePromiseCallback;function _emscripten_promise_then(id,onFulfilled,onRejected,userData){id>>>=0;onFulfilled>>>=0;onRejected>>>=0;userData>>>=0;var promise=getPromise(id);var newId=promiseMap.allocate({promise:promise.then(makePromiseCallback(onFulfilled,userData),makePromiseCallback(onRejected,userData))});return newId}Module["_emscripten_promise_then"]=_emscripten_promise_then;_emscripten_promise_then.sig="ppppp";var _emscripten_promise_all=function(idBuf,resultBuf,size){idBuf>>>=0;resultBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.all(promises).then(results=>{if(resultBuf){for(var i=0;i>>2>>>0]=result}}return resultBuf})});return id};Module["_emscripten_promise_all"]=_emscripten_promise_all;_emscripten_promise_all.sig="pppp";var setPromiseResult=(ptr,fulfill,value)=>{var result=fulfill?0:3;HEAP32[ptr>>>2>>>0]=result;HEAPU32[ptr+4>>>2>>>0]=value};Module["setPromiseResult"]=setPromiseResult;var _emscripten_promise_all_settled=function(idBuf,resultBuf,size){idBuf>>>=0;resultBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.allSettled(promises).then(results=>{if(resultBuf){var offset=resultBuf;for(var i=0;i>>=0;errorBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.any(promises).catch(err=>{if(errorBuf){for(var i=0;i>>2>>>0]=err.errors[i]}}throw errorBuf})});return id};Module["_emscripten_promise_any"]=_emscripten_promise_any;_emscripten_promise_any.sig="pppp";function _emscripten_promise_race(idBuf,size){idBuf>>>=0;size>>>=0;var promises=idsToPromises(idBuf,size);var id=promiseMap.allocate({promise:Promise.race(promises)});return id}Module["_emscripten_promise_race"]=_emscripten_promise_race;_emscripten_promise_race.sig="ppp";function _emscripten_promise_await(returnValuePtr,id){returnValuePtr>>>=0;id>>>=0;abort("emscripten_promise_await is only available with ASYNCIFY")}Module["_emscripten_promise_await"]=_emscripten_promise_await;_emscripten_promise_await.sig="vpp";function ___cxa_find_matching_catch_4(arg0,arg1){arg0>>>=0;arg1>>>=0;return findMatchingCatch([arg0,arg1])}Module["___cxa_find_matching_catch_4"]=___cxa_find_matching_catch_4;___cxa_find_matching_catch_4.sig="ppp";function _llvm_eh_typeid_for(type){type>>>=0;return type}Module["_llvm_eh_typeid_for"]=_llvm_eh_typeid_for;_llvm_eh_typeid_for.sig="vp";function ___cxa_get_exception_ptr(ptr){ptr>>>=0;var rtn=new ExceptionInfo(ptr).get_exception_ptr();return rtn}Module["___cxa_get_exception_ptr"]=___cxa_get_exception_ptr;___cxa_get_exception_ptr.sig="pp";function ___cxa_call_unexpected(exception){exception>>>=0;return abort("Unexpected exception thrown, this is not properly supported - aborting")}Module["___cxa_call_unexpected"]=___cxa_call_unexpected;___cxa_call_unexpected.sig="vp";var _emscripten_set_main_loop_timing=(mode,value)=>{Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(!Browser.mainLoop.running){Browser.mainLoop.running=true}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof Browser.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);Browser.setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{Browser.setImmediate=setImmediate}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){Browser.setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0};Module["_emscripten_set_main_loop_timing"]=_emscripten_set_main_loop_timing;_emscripten_set_main_loop_timing.sig="iii";var setMainLoop=(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object")SDL.audio?.queueNewAudioData?.();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};Module["setMainLoop"]=setMainLoop;var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining{var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;URL.revokeObjectURL(url);onload?.(byteArray)};img.onerror=event=>{err(`Image ${url} could not be decoded`);onerror?.()};img.src=url};preloadPlugins.push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;onload?.(byteArray)}function fail(){if(done)return;done=true;preloadedAudios[name]=new Audio;onerror?.()}var b=new Blob([byteArray],{type:Browser.getMimetype(name)});var url=URL.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",()=>finish(audio),false);audio.onerror=function audio_onerror(event){if(done)return;err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`);function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(()=>{finish(audio)},1e4)};preloadPlugins.push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||(()=>{});canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||(()=>{});canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",ev=>{if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(callback=>callback());Browser.init()}return ctx},destroyContext(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}Module["onFullScreen"]?.(Browser.isFullscreen);Module["onFullscreen"]?.(Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?()=>canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"]):null)||(canvasContainer["webkitRequestFullScreen"]?()=>canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"]):null);canvasContainer.requestFullscreen()},exitFullscreen(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||(()=>{});CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout(func,timeout){return safeSetTimeout(func,timeout)},safeRequestAnimationFrame(func){return Browser.requestAnimationFrame(()=>{callUserCallback(func)})},getMimetype(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia(func){window.getUserMedia||=navigator["getUserMedia"]||navigator["mozGetUserMedia"];window.getUserMedia(func)},getMovementX(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseCoords(pageX,pageY){var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;var adjustedX=pageX-(scrollX+rect.left);var adjustedY=pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);return{x:adjustedX,y:adjustedY}},setMouseCoords(pageX,pageY){const{x:x,y:y}=Browser.calculateMouseCoords(pageX,pageY);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y},calculateMouseEvent(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}else{if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var coords=Browser.calculateMouseCoords(touch.pageX,touch.pageY);if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];last||=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}Browser.setMouseCoords(event.pageX,event.pageY)}},resizeListeners:[],updateResizeListeners(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(listener=>listener(canvas.width,canvas.height))},setCanvasSize(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags|8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>>2>>>0];flags=flags&~8388608;HEAP32[SDL.screen>>>2>>>0]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h>>=0;onload>>>=0;onerror>>>=0;var _file=UTF8ToString(file);var data=FS.analyzePath(_file);if(!data.exists)return-1;FS.createPreloadedFile(PATH.dirname(_file),PATH.basename(_file),new Uint8Array(data.object.contents),true,true,()=>{if(onload)getWasmTableEntry(onload)(file)},()=>{if(onerror)getWasmTableEntry(onerror)(file)},true);return 0};Module["_emscripten_run_preload_plugins"]=_emscripten_run_preload_plugins;_emscripten_run_preload_plugins.sig="ippp";var Browser_asyncPrepareDataCounter=0;Module["Browser_asyncPrepareDataCounter"]=Browser_asyncPrepareDataCounter;var _emscripten_run_preload_plugins_data=function(data,size,suffix,arg,onload,onerror){data>>>=0;suffix>>>=0;arg>>>=0;onload>>>=0;onerror>>>=0;var _suffix=UTF8ToString(suffix);var name="prepare_data_"+Browser_asyncPrepareDataCounter+++"."+_suffix;var cname=stringToNewUTF8(name);FS.createPreloadedFile("/",name,HEAPU8.subarray(data>>>0,data+size>>>0),true,true,()=>{if(onload)getWasmTableEntry(onload)(arg,cname)},()=>{if(onerror)getWasmTableEntry(onerror)(arg)},true)};Module["_emscripten_run_preload_plugins_data"]=_emscripten_run_preload_plugins_data;_emscripten_run_preload_plugins_data.sig="vpipppp";var _emscripten_async_run_script=function(script,millis){script>>>=0;safeSetTimeout(()=>_emscripten_run_script(script),millis)};Module["_emscripten_async_run_script"]=_emscripten_async_run_script;_emscripten_async_run_script.sig="vpi";var _emscripten_async_load_script=function(url,onload,onerror){url>>>=0;onload>>>=0;onerror>>>=0;url=UTF8ToString(url);onload=getWasmTableEntry(onload);onerror=getWasmTableEntry(onerror);var loadDone=()=>{if(onload){if(runDependencies>0){dependenciesFulfilled=onload}else{onload()}}};var loadError=()=>{onerror?.()};if(ENVIRONMENT_IS_NODE){readAsync(url,data=>{eval(data);loadDone()},loadError,false);return}var script=document.createElement("script");script.onload=loadDone;script.onerror=loadError;script.src=url;document.body.appendChild(script)};Module["_emscripten_async_load_script"]=_emscripten_async_load_script;_emscripten_async_load_script.sig="vppp";function _emscripten_get_main_loop_timing(mode,value){mode>>>=0;value>>>=0;if(mode)HEAP32[mode>>>2>>>0]=Browser.mainLoop.timingMode;if(value)HEAP32[value>>>2>>>0]=Browser.mainLoop.timingValue}Module["_emscripten_get_main_loop_timing"]=_emscripten_get_main_loop_timing;_emscripten_get_main_loop_timing.sig="vpp";function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var browserIterationFunc=getWasmTableEntry(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)}Module["_emscripten_set_main_loop"]=_emscripten_set_main_loop;_emscripten_set_main_loop.sig="vpii";var _emscripten_set_main_loop_arg=function(func,arg,fps,simulateInfiniteLoop){func>>>=0;arg>>>=0;var browserIterationFunc=()=>getWasmTableEntry(func)(arg);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg)};Module["_emscripten_set_main_loop_arg"]=_emscripten_set_main_loop_arg;_emscripten_set_main_loop_arg.sig="vppii";var _emscripten_cancel_main_loop=()=>{Browser.mainLoop.pause();Browser.mainLoop.func=null};Module["_emscripten_cancel_main_loop"]=_emscripten_cancel_main_loop;_emscripten_cancel_main_loop.sig="v";var _emscripten_pause_main_loop=()=>{Browser.mainLoop.pause()};Module["_emscripten_pause_main_loop"]=_emscripten_pause_main_loop;_emscripten_pause_main_loop.sig="v";var _emscripten_resume_main_loop=()=>{Browser.mainLoop.resume()};Module["_emscripten_resume_main_loop"]=_emscripten_resume_main_loop;_emscripten_resume_main_loop.sig="v";var __emscripten_push_main_loop_blocker=function(func,arg,name){func>>>=0;arg>>>=0;name>>>=0;Browser.mainLoop.queue.push({func:()=>{getWasmTableEntry(func)(arg)},name:UTF8ToString(name),counted:true});Browser.mainLoop.updateStatus()};Module["__emscripten_push_main_loop_blocker"]=__emscripten_push_main_loop_blocker;__emscripten_push_main_loop_blocker.sig="vppp";var __emscripten_push_uncounted_main_loop_blocker=function(func,arg,name){func>>>=0;arg>>>=0;name>>>=0;Browser.mainLoop.queue.push({func:()=>{getWasmTableEntry(func)(arg)},name:UTF8ToString(name),counted:false});Browser.mainLoop.updateStatus()};Module["__emscripten_push_uncounted_main_loop_blocker"]=__emscripten_push_uncounted_main_loop_blocker;__emscripten_push_uncounted_main_loop_blocker.sig="vppp";var _emscripten_set_main_loop_expected_blockers=num=>{Browser.mainLoop.expectedBlockers=num;Browser.mainLoop.remainingBlockers=num;Browser.mainLoop.updateStatus()};Module["_emscripten_set_main_loop_expected_blockers"]=_emscripten_set_main_loop_expected_blockers;_emscripten_set_main_loop_expected_blockers.sig="vi";function _emscripten_async_call(func,arg,millis){func>>>=0;arg>>>=0;function wrapper(){getWasmTableEntry(func)(arg)}if(millis>=0||ENVIRONMENT_IS_NODE){safeSetTimeout(wrapper,millis)}else{Browser.safeRequestAnimationFrame(wrapper)}}Module["_emscripten_async_call"]=_emscripten_async_call;_emscripten_async_call.sig="vppi";function _emscripten_get_window_title(){var buflen=256;if(!_emscripten_get_window_title.buffer){_emscripten_get_window_title.buffer=_malloc(buflen)}stringToUTF8(document.title,_emscripten_get_window_title.buffer,buflen);return _emscripten_get_window_title.buffer}Module["_emscripten_get_window_title"]=_emscripten_get_window_title;_emscripten_get_window_title.sig="p";function _emscripten_set_window_title(title){title>>>=0;return document.title=UTF8ToString(title)}Module["_emscripten_set_window_title"]=_emscripten_set_window_title;_emscripten_set_window_title.sig="vp";function _emscripten_get_screen_size(width,height){width>>>=0;height>>>=0;HEAP32[width>>>2>>>0]=screen.width;HEAP32[height>>>2>>>0]=screen.height}Module["_emscripten_get_screen_size"]=_emscripten_get_screen_size;_emscripten_get_screen_size.sig="vpp";var _emscripten_hide_mouse=()=>{var styleSheet=document.styleSheets[0];var rules=styleSheet.cssRules;for(var i=0;i{Browser.setCanvasSize(width,height)};Module["_emscripten_set_canvas_size"]=_emscripten_set_canvas_size;_emscripten_set_canvas_size.sig="vii";function _emscripten_get_canvas_size(width,height,isFullscreen){width>>>=0;height>>>=0;isFullscreen>>>=0;var canvas=Module["canvas"];HEAP32[width>>>2>>>0]=canvas.width;HEAP32[height>>>2>>>0]=canvas.height;HEAP32[isFullscreen>>>2>>>0]=Browser.isFullscreen?1:0}Module["_emscripten_get_canvas_size"]=_emscripten_get_canvas_size;_emscripten_get_canvas_size.sig="vppp";function _emscripten_create_worker(url){url>>>=0;url=UTF8ToString(url);var id=Browser.workers.length;var info={worker:new Worker(url),callbacks:[],awaited:0,buffer:0,bufferSize:0};info.worker.onmessage=function info_worker_onmessage(msg){if(ABORT)return;var info=Browser.workers[id];if(!info)return;var callbackId=msg.data["callbackId"];var callbackInfo=info.callbacks[callbackId];if(!callbackInfo)return;if(msg.data["finalResponse"]){info.awaited--;info.callbacks[callbackId]=null}var data=msg.data["data"];if(data){if(!data.byteLength)data=new Uint8Array(data);if(!info.buffer||info.bufferSize>>0);callbackInfo.func(info.buffer,data.length,callbackInfo.arg)}else{callbackInfo.func(0,0,callbackInfo.arg)}};Browser.workers.push(info);return id}Module["_emscripten_create_worker"]=_emscripten_create_worker;_emscripten_create_worker.sig="ip";var _emscripten_destroy_worker=id=>{var info=Browser.workers[id];info.worker.terminate();if(info.buffer)_free(info.buffer);Browser.workers[id]=null};Module["_emscripten_destroy_worker"]=_emscripten_destroy_worker;_emscripten_destroy_worker.sig="vi";function _emscripten_call_worker(id,funcName,data,size,callback,arg){funcName>>>=0;data>>>=0;callback>>>=0;arg>>>=0;funcName=UTF8ToString(funcName);var info=Browser.workers[id];var callbackId=-1;if(callback){callbackId=info.callbacks.length;info.callbacks.push({func:getWasmTableEntry(callback),arg:arg});info.awaited++}var transferObject={"funcName":funcName,"callbackId":callbackId,"data":data?new Uint8Array(HEAPU8.subarray(data>>>0,data+size>>>0)):0};if(data){info.worker.postMessage(transferObject,[transferObject.data.buffer])}else{info.worker.postMessage(transferObject)}}Module["_emscripten_call_worker"]=_emscripten_call_worker;_emscripten_call_worker.sig="vippipp";var _emscripten_get_worker_queue_size=id=>{var info=Browser.workers[id];if(!info)return-1;return info.awaited};Module["_emscripten_get_worker_queue_size"]=_emscripten_get_worker_queue_size;_emscripten_get_worker_queue_size.sig="ii";var getPreloadedImageData=(path,w,h)=>{path=PATH_FS.resolve(path);var canvas=preloadedImages[path];if(!canvas)return 0;var ctx=canvas.getContext("2d");var image=ctx.getImageData(0,0,canvas.width,canvas.height);var buf=_malloc(canvas.width*canvas.height*4);HEAPU8.set(image.data,buf>>>0);HEAP32[w>>>2>>>0]=canvas.width;HEAP32[h>>>2>>>0]=canvas.height;return buf};Module["getPreloadedImageData"]=getPreloadedImageData;function _emscripten_get_preloaded_image_data(path,w,h){path>>>=0;w>>>=0;h>>>=0;return getPreloadedImageData(UTF8ToString(path),w,h)}Module["_emscripten_get_preloaded_image_data"]=_emscripten_get_preloaded_image_data;_emscripten_get_preloaded_image_data.sig="pppp";var getPreloadedImageData__data=["$PATH_FS","malloc"];Module["getPreloadedImageData__data"]=getPreloadedImageData__data;function _emscripten_get_preloaded_image_data_from_FILE(file,w,h){file>>>=0;w>>>=0;h>>>=0;var fd=_fileno(file);var stream=FS.getStream(fd);if(stream){return getPreloadedImageData(stream.path,w,h)}return 0}Module["_emscripten_get_preloaded_image_data_from_FILE"]=_emscripten_get_preloaded_image_data_from_FILE;_emscripten_get_preloaded_image_data_from_FILE.sig="pppp";var wget={wgetRequests:{},nextWgetRequestHandle:0,getNextWgetRequestHandle(){var handle=wget.nextWgetRequestHandle;wget.nextWgetRequestHandle++;return handle}};Module["wget"]=wget;var FS_mkdirTree=(path,mode)=>FS.mkdirTree(path,mode);Module["FS_mkdirTree"]=FS_mkdirTree;var _emscripten_async_wget=function(url,file,onload,onerror){url>>>=0;file>>>=0;onload>>>=0;onerror>>>=0;var _url=UTF8ToString(url);var _file=UTF8ToString(file);_file=PATH_FS.resolve(_file);function doCallback(callback){if(callback){callUserCallback(()=>{var sp=stackSave();getWasmTableEntry(callback)(stringToUTF8OnStack(_file));stackRestore(sp)})}}var destinationDirectory=PATH.dirname(_file);FS_createPreloadedFile(destinationDirectory,PATH.basename(_file),_url,true,true,()=>doCallback(onload),()=>doCallback(onerror),false,false,()=>{try{FS_unlink(_file)}catch(e){}FS_mkdirTree(destinationDirectory)})};Module["_emscripten_async_wget"]=_emscripten_async_wget;_emscripten_async_wget.sig="vpppp";var _emscripten_async_wget_data=function(url,userdata,onload,onerror){url>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;asyncLoad(UTF8ToString(url),byteArray=>{callUserCallback(()=>{var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer>>>0);getWasmTableEntry(onload)(userdata,buffer,byteArray.length);_free(buffer)})},()=>{if(onerror){callUserCallback(()=>{getWasmTableEntry(onerror)(userdata)})}},true)};Module["_emscripten_async_wget_data"]=_emscripten_async_wget_data;_emscripten_async_wget_data.sig="vpppp";var _emscripten_async_wget2=function(url,file,request,param,userdata,onload,onerror,onprogress){url>>>=0;file>>>=0;request>>>=0;param>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;onprogress>>>=0;var _url=UTF8ToString(url);var _file=UTF8ToString(file);_file=PATH_FS.resolve(_file);var _request=UTF8ToString(request);var _param=UTF8ToString(param);var index=_file.lastIndexOf("/");var http=new XMLHttpRequest;http.open(_request,_url,true);http.responseType="arraybuffer";var handle=wget.getNextWgetRequestHandle();var destinationDirectory=PATH.dirname(_file);http.onload=e=>{if(http.status>=200&&http.status<300){try{FS.unlink(_file)}catch(e){}FS.mkdirTree(destinationDirectory);FS.createDataFile(_file.substr(0,index),_file.substr(index+1),new Uint8Array(http.response),true,true,false);if(onload){var sp=stackSave();getWasmTableEntry(onload)(handle,userdata,stringToUTF8OnStack(_file));stackRestore(sp)}}else{if(onerror)getWasmTableEntry(onerror)(handle,userdata,http.status)}delete wget.wgetRequests[handle]};http.onerror=e=>{if(onerror)getWasmTableEntry(onerror)(handle,userdata,http.status);delete wget.wgetRequests[handle]};http.onprogress=e=>{if(e.lengthComputable||e.lengthComputable===undefined&&e.total!=0){var percentComplete=e.loaded/e.total*100;if(onprogress)getWasmTableEntry(onprogress)(handle,userdata,percentComplete)}};http.onabort=e=>{delete wget.wgetRequests[handle]};if(_request=="POST"){http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send(_param)}else{http.send(null)}wget.wgetRequests[handle]=http;return handle};Module["_emscripten_async_wget2"]=_emscripten_async_wget2;_emscripten_async_wget2.sig="ipppppppp";function _emscripten_async_wget2_data(url,request,param,userdata,free,onload,onerror,onprogress){url>>>=0;request>>>=0;param>>>=0;userdata>>>=0;onload>>>=0;onerror>>>=0;onprogress>>>=0;var _url=UTF8ToString(url);var _request=UTF8ToString(request);var _param=UTF8ToString(param);var http=new XMLHttpRequest;http.open(_request,_url,true);http.responseType="arraybuffer";var handle=wget.getNextWgetRequestHandle();function onerrorjs(){if(onerror){var sp=stackSave();var statusText=0;if(http.statusText){statusText=stringToUTF8OnStack(http.statusText)}getWasmTableEntry(onerror)(handle,userdata,http.status,statusText);stackRestore(sp)}}http.onload=e=>{if(http.status>=200&&http.status<300||http.status===0&&_url.substr(0,4).toLowerCase()!="http"){var byteArray=new Uint8Array(http.response);var buffer=_malloc(byteArray.length);HEAPU8.set(byteArray,buffer>>>0);if(onload)getWasmTableEntry(onload)(handle,userdata,buffer,byteArray.length);if(free)_free(buffer)}else{onerrorjs()}delete wget.wgetRequests[handle]};http.onerror=e=>{onerrorjs();delete wget.wgetRequests[handle]};http.onprogress=e=>{if(onprogress)getWasmTableEntry(onprogress)(handle,userdata,e.loaded,e.lengthComputable||e.lengthComputable===undefined?e.total:0)};http.onabort=e=>{delete wget.wgetRequests[handle]};if(_request=="POST"){http.setRequestHeader("Content-type","application/x-www-form-urlencoded");http.send(_param)}else{http.send(null)}wget.wgetRequests[handle]=http;return handle}Module["_emscripten_async_wget2_data"]=_emscripten_async_wget2_data;_emscripten_async_wget2_data.sig="ippppippp";var _emscripten_async_wget2_abort=handle=>{var http=wget.wgetRequests[handle];http?.abort()};Module["_emscripten_async_wget2_abort"]=_emscripten_async_wget2_abort;_emscripten_async_wget2_abort.sig="vi";function __dlsym_catchup_js(handle,symbolIndex){handle>>>=0;var lib=LDSO.loadedLibsByHandle[handle];var symDict=lib.exports;var symName=Object.keys(symDict)[symbolIndex];var sym=symDict[symName];var result=addFunction(sym,sym.sig);return result}Module["__dlsym_catchup_js"]=__dlsym_catchup_js;__dlsym_catchup_js.sig="ppi";var _setNetworkCallback=(event,userData,callback)=>{function _callback(data){try{if(event==="error"){var sp=stackSave();var msg=stringToUTF8OnStack(data[2]);getWasmTableEntry(callback)(data[0],data[1],msg,userData);stackRestore(sp)}else{getWasmTableEntry(callback)(data,userData)}}catch(e){if(!(e instanceof ExitStatus)){if(e&&typeof e=="object"&&e.stack)err("exception thrown: "+[e,e.stack]);throw e}}}Module["websocket"]["on"](event,callback?_callback:null)};Module["_setNetworkCallback"]=_setNetworkCallback;function _emscripten_set_socket_error_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("error",userData,callback)}Module["_emscripten_set_socket_error_callback"]=_emscripten_set_socket_error_callback;_emscripten_set_socket_error_callback.sig="vpp";function _emscripten_set_socket_open_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("open",userData,callback)}Module["_emscripten_set_socket_open_callback"]=_emscripten_set_socket_open_callback;_emscripten_set_socket_open_callback.sig="vpp";function _emscripten_set_socket_listen_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("listen",userData,callback)}Module["_emscripten_set_socket_listen_callback"]=_emscripten_set_socket_listen_callback;_emscripten_set_socket_listen_callback.sig="vpp";function _emscripten_set_socket_connection_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("connection",userData,callback)}Module["_emscripten_set_socket_connection_callback"]=_emscripten_set_socket_connection_callback;_emscripten_set_socket_connection_callback.sig="vpp";function _emscripten_set_socket_message_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("message",userData,callback)}Module["_emscripten_set_socket_message_callback"]=_emscripten_set_socket_message_callback;_emscripten_set_socket_message_callback.sig="vpp";function _emscripten_set_socket_close_callback(userData,callback){userData>>>=0;callback>>>=0;_setNetworkCallback("close",userData,callback)}Module["_emscripten_set_socket_close_callback"]=_emscripten_set_socket_close_callback;_emscripten_set_socket_close_callback.sig="vpp";var ALLOC_NORMAL=0;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;var ALLOC_STACK=1;Module["ALLOC_STACK"]=ALLOC_STACK;var allocate=(slab,allocator)=>{var ret;if(allocator==ALLOC_STACK){ret=stackAlloc(slab.length)}else{ret=_malloc(slab.length)}if(!slab.subarray&&!slab.slice){slab=new Uint8Array(slab)}HEAPU8.set(slab,ret>>>0);return ret};Module["allocate"]=allocate;var writeStringToMemory=(string,buffer,dontAddNull)=>{warnOnce("writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!");var lastChar,end;if(dontAddNull){end=buffer+lengthBytesUTF8(string);lastChar=HEAP8[end>>>0]}stringToUTF8(string,buffer,Infinity);if(dontAddNull)HEAP8[end>>>0]=lastChar};Module["writeStringToMemory"]=writeStringToMemory;var writeAsciiToMemory=(str,buffer,dontAddNull)=>{for(var i=0;i>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>>0]=0};Module["writeAsciiToMemory"]=writeAsciiToMemory;var allocateUTF8=stringToNewUTF8;Module["allocateUTF8"]=allocateUTF8;var allocateUTF8OnStack=stringToUTF8OnStack;Module["allocateUTF8OnStack"]=allocateUTF8OnStack;var setErrNo=value=>{HEAP32[___errno_location()>>>2>>>0]=value;return value};Module["setErrNo"]=setErrNo;var demangle=func=>{demangle.recursionGuard=(demangle.recursionGuard|0)+1;if(demangle.recursionGuard>1)return func;return withStackSave(()=>{try{var s=func;if(s.startsWith("__Z"))s=s.substr(1);var buf=stringToUTF8OnStack(s);var status=stackAlloc(4);var ret=___cxa_demangle(buf,0,0,status);if(HEAP32[status>>>2>>>0]===0&&ret){return UTF8ToString(ret)}}catch(e){}finally{_free(ret);if(demangle.recursionGuard<2)--demangle.recursionGuard}return func})};Module["demangle"]=demangle;function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return js}Module["stackTrace"]=stackTrace;var _emscripten_is_main_browser_thread=()=>!ENVIRONMENT_IS_WORKER;Module["_emscripten_is_main_browser_thread"]=_emscripten_is_main_browser_thread;var webSockets=new HandleAllocator;Module["webSockets"]=webSockets;var WS={socketEvent:null,getSocket(socketId){if(!webSockets.has(socketId)){return 0}return webSockets.get(socketId)},getSocketEvent(socketId){this.socketEvent||=_malloc(524);HEAPU32[this.socketEvent>>>2>>>0]=socketId;return this.socketEvent}};Module["WS"]=WS;function _emscripten_websocket_get_ready_state(socketId,readyState){readyState>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAP16[readyState>>>1>>>0]=socket.readyState;return 0}Module["_emscripten_websocket_get_ready_state"]=_emscripten_websocket_get_ready_state;_emscripten_websocket_get_ready_state.sig="iip";function _emscripten_websocket_get_buffered_amount(socketId,bufferedAmount){bufferedAmount>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}HEAPU32[bufferedAmount>>>2>>>0]=socket.bufferedAmount;return 0}Module["_emscripten_websocket_get_buffered_amount"]=_emscripten_websocket_get_buffered_amount;_emscripten_websocket_get_buffered_amount.sig="iip";function _emscripten_websocket_get_extensions(socketId,extensions,extensionsLength){extensions>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!extensions)return-5;stringToUTF8(socket.extensions,extensions,extensionsLength);return 0}Module["_emscripten_websocket_get_extensions"]=_emscripten_websocket_get_extensions;_emscripten_websocket_get_extensions.sig="iipi";function _emscripten_websocket_get_extensions_length(socketId,extensionsLength){extensionsLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!extensionsLength)return-5;HEAP32[extensionsLength>>>2>>>0]=lengthBytesUTF8(socket.extensions)+1;return 0}Module["_emscripten_websocket_get_extensions_length"]=_emscripten_websocket_get_extensions_length;_emscripten_websocket_get_extensions_length.sig="iip";function _emscripten_websocket_get_protocol(socketId,protocol,protocolLength){protocol>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!protocol)return-5;stringToUTF8(socket.protocol,protocol,protocolLength);return 0}Module["_emscripten_websocket_get_protocol"]=_emscripten_websocket_get_protocol;_emscripten_websocket_get_protocol.sig="iipi";function _emscripten_websocket_get_protocol_length(socketId,protocolLength){protocolLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!protocolLength)return-5;HEAP32[protocolLength>>>2>>>0]=lengthBytesUTF8(socket.protocol)+1;return 0}Module["_emscripten_websocket_get_protocol_length"]=_emscripten_websocket_get_protocol_length;_emscripten_websocket_get_protocol_length.sig="iip";function _emscripten_websocket_get_url(socketId,url,urlLength){url>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!url)return-5;stringToUTF8(socket.url,url,urlLength);return 0}Module["_emscripten_websocket_get_url"]=_emscripten_websocket_get_url;_emscripten_websocket_get_url.sig="iipi";function _emscripten_websocket_get_url_length(socketId,urlLength){urlLength>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}if(!urlLength)return-5;HEAP32[urlLength>>>2>>>0]=lengthBytesUTF8(socket.url)+1;return 0}Module["_emscripten_websocket_get_url_length"]=_emscripten_websocket_get_url_length;_emscripten_websocket_get_url_length.sig="iip";function _emscripten_websocket_set_onopen_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=function(e){getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}Module["_emscripten_websocket_set_onopen_callback_on_thread"]=_emscripten_websocket_set_onopen_callback_on_thread;_emscripten_websocket_set_onopen_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onerror_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onerror=function(e){getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}Module["_emscripten_websocket_set_onerror_callback_on_thread"]=_emscripten_websocket_set_onerror_callback_on_thread;_emscripten_websocket_set_onerror_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onclose_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onclose=function(e){HEAP32[eventPtr+4>>>2>>>0]=e.wasClean,HEAP16[eventPtr+4>>>1>>>0]=e.code,stringToUTF8(e.reason,eventPtr+10,512);getWasmTableEntry(callbackFunc)(0,eventPtr,userData)};return 0}Module["_emscripten_websocket_set_onclose_callback_on_thread"]=_emscripten_websocket_set_onclose_callback_on_thread;_emscripten_websocket_set_onclose_callback_on_thread.sig="iippp";function _emscripten_websocket_set_onmessage_callback_on_thread(socketId,userData,callbackFunc,thread){userData>>>=0;callbackFunc>>>=0;thread>>>=0;var eventPtr=WS.getSocketEvent(socketId);var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onmessage=function(e){var isText=typeof e.data=="string";if(isText){var buf=stringToNewUTF8(e.data);var len=lengthBytesUTF8(e.data)+1}else{var len=e.data.byteLength;var buf=_malloc(len);HEAP8.set(new Uint8Array(e.data),buf>>>0)}HEAPU32[eventPtr+4>>>2>>>0]=buf,HEAP32[eventPtr+8>>>2>>>0]=len,HEAP32[eventPtr+12>>>2>>>0]=isText,getWasmTableEntry(callbackFunc)(0,eventPtr,userData);_free(buf)};return 0}Module["_emscripten_websocket_set_onmessage_callback_on_thread"]=_emscripten_websocket_set_onmessage_callback_on_thread;_emscripten_websocket_set_onmessage_callback_on_thread.sig="iippp";function _emscripten_websocket_new(createAttributes){createAttributes>>>=0;if(typeof WebSocket=="undefined"){return-1}if(!createAttributes){return-5}var url=UTF8ToString(HEAPU32[createAttributes>>>2>>>0]);var protocols=HEAPU32[createAttributes+4>>>2>>>0];var socket=protocols?new WebSocket(url,UTF8ToString(protocols).split(",")):new WebSocket(url);socket.binaryType="arraybuffer";var socketId=webSockets.allocate(socket);return socketId}Module["_emscripten_websocket_new"]=_emscripten_websocket_new;_emscripten_websocket_new.sig="ip";function _emscripten_websocket_send_utf8_text(socketId,textData){textData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var str=UTF8ToString(textData);socket.send(str);return 0}Module["_emscripten_websocket_send_utf8_text"]=_emscripten_websocket_send_utf8_text;_emscripten_websocket_send_utf8_text.sig="iip";function _emscripten_websocket_send_binary(socketId,binaryData,dataLength){binaryData>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}socket.send(HEAPU8.subarray(binaryData>>>0,binaryData+dataLength>>>0));return 0}Module["_emscripten_websocket_send_binary"]=_emscripten_websocket_send_binary;_emscripten_websocket_send_binary.sig="iipi";function _emscripten_websocket_close(socketId,code,reason){reason>>>=0;var socket=WS.getSocket(socketId);if(!socket){return-3}var reasonStr=reason?UTF8ToString(reason):undefined;if(reason)socket.close(code||undefined,UTF8ToString(reason));else if(code)socket.close(code);else socket.close();return 0}Module["_emscripten_websocket_close"]=_emscripten_websocket_close;_emscripten_websocket_close.sig="iiip";var _emscripten_websocket_delete=socketId=>{var socket=WS.getSocket(socketId);if(!socket){return-3}socket.onopen=socket.onerror=socket.onclose=socket.onmessage=null;webSockets.free(socketId);return 0};Module["_emscripten_websocket_delete"]=_emscripten_websocket_delete;_emscripten_websocket_delete.sig="ii";var _emscripten_websocket_is_supported=()=>typeof WebSocket!="undefined";Module["_emscripten_websocket_is_supported"]=_emscripten_websocket_is_supported;_emscripten_websocket_is_supported.sig="i";var _emscripten_websocket_deinitialize=()=>{for(var i in WS.sockets){var socket=WS.sockets[i];if(socket){socket.close();_emscripten_websocket_delete(i)}}WS.sockets=[]};Module["_emscripten_websocket_deinitialize"]=_emscripten_websocket_deinitialize;_emscripten_websocket_deinitialize.sig="v";function _emscripten_webgl_enable_ANGLE_instanced_arrays(ctx){ctx>>>=0;return webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_ANGLE_instanced_arrays"]=_emscripten_webgl_enable_ANGLE_instanced_arrays;_emscripten_webgl_enable_ANGLE_instanced_arrays.sig="ip";function _emscripten_webgl_enable_OES_vertex_array_object(ctx){ctx>>>=0;return webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_OES_vertex_array_object"]=_emscripten_webgl_enable_OES_vertex_array_object;_emscripten_webgl_enable_OES_vertex_array_object.sig="ip";function _emscripten_webgl_enable_WEBGL_draw_buffers(ctx){ctx>>>=0;return webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_WEBGL_draw_buffers"]=_emscripten_webgl_enable_WEBGL_draw_buffers;_emscripten_webgl_enable_WEBGL_draw_buffers.sig="ip";function _emscripten_webgl_enable_WEBGL_multi_draw(ctx){ctx>>>=0;return webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx)}Module["_emscripten_webgl_enable_WEBGL_multi_draw"]=_emscripten_webgl_enable_WEBGL_multi_draw;_emscripten_webgl_enable_WEBGL_multi_draw.sig="ip";function _glVertexPointer(size,type,stride,ptr){ptr>>>=0;throw"Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."}Module["_glVertexPointer"]=_glVertexPointer;_glVertexPointer.sig="viiip";var _glMatrixMode=()=>{throw"Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};Module["_glMatrixMode"]=_glMatrixMode;_glMatrixMode.sig="vi";var _glBegin=()=>{throw"Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};Module["_glBegin"]=_glBegin;_glBegin.sig="vi";var _glLoadIdentity=()=>{throw"Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation."};Module["_glLoadIdentity"]=_glLoadIdentity;_glLoadIdentity.sig="v";var _glVertexAttribDivisorNV=_glVertexAttribDivisor;Module["_glVertexAttribDivisorNV"]=_glVertexAttribDivisorNV;var _glDrawArraysInstancedNV=_glDrawArraysInstanced;Module["_glDrawArraysInstancedNV"]=_glDrawArraysInstancedNV;var _glDrawElementsInstancedNV=_glDrawElementsInstanced;Module["_glDrawElementsInstancedNV"]=_glDrawElementsInstancedNV;var _glVertexAttribDivisorEXT=_glVertexAttribDivisor;Module["_glVertexAttribDivisorEXT"]=_glVertexAttribDivisorEXT;var _glDrawArraysInstancedEXT=_glDrawArraysInstanced;Module["_glDrawArraysInstancedEXT"]=_glDrawArraysInstancedEXT;var _glDrawElementsInstancedEXT=_glDrawElementsInstanced;Module["_glDrawElementsInstancedEXT"]=_glDrawElementsInstancedEXT;var _glVertexAttribDivisorARB=_glVertexAttribDivisor;Module["_glVertexAttribDivisorARB"]=_glVertexAttribDivisorARB;var _glDrawArraysInstancedARB=_glDrawArraysInstanced;Module["_glDrawArraysInstancedARB"]=_glDrawArraysInstancedARB;var _glDrawElementsInstancedARB=_glDrawElementsInstanced;Module["_glDrawElementsInstancedARB"]=_glDrawElementsInstancedARB;var _glDrawBuffersEXT=_glDrawBuffers;Module["_glDrawBuffersEXT"]=_glDrawBuffersEXT;function _glMultiDrawArraysWEBGL(mode,firsts,counts,drawcount){firsts>>>=0;counts>>>=0;GLctx.multiDrawWebgl["multiDrawArraysWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,drawcount)}Module["_glMultiDrawArraysWEBGL"]=_glMultiDrawArraysWEBGL;_glMultiDrawArraysWEBGL.sig="vippi";var _glMultiDrawArrays=_glMultiDrawArraysWEBGL;Module["_glMultiDrawArrays"]=_glMultiDrawArrays;_glMultiDrawArrays.sig="vippi";var _glMultiDrawArraysANGLE=_glMultiDrawArraysWEBGL;Module["_glMultiDrawArraysANGLE"]=_glMultiDrawArraysANGLE;function _glMultiDrawArraysInstancedWEBGL(mode,firsts,counts,instanceCounts,drawcount){firsts>>>=0;counts>>>=0;instanceCounts>>>=0;GLctx.multiDrawWebgl["multiDrawArraysInstancedWEBGL"](mode,HEAP32,firsts>>>2,HEAP32,counts>>>2,HEAP32,instanceCounts>>>2,drawcount)}Module["_glMultiDrawArraysInstancedWEBGL"]=_glMultiDrawArraysInstancedWEBGL;_glMultiDrawArraysInstancedWEBGL.sig="vipppi";var _glMultiDrawArraysInstancedANGLE=_glMultiDrawArraysInstancedWEBGL;Module["_glMultiDrawArraysInstancedANGLE"]=_glMultiDrawArraysInstancedANGLE;function _glMultiDrawElementsWEBGL(mode,counts,type,offsets,drawcount){counts>>>=0;offsets>>>=0;GLctx.multiDrawWebgl["multiDrawElementsWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,drawcount)}Module["_glMultiDrawElementsWEBGL"]=_glMultiDrawElementsWEBGL;_glMultiDrawElementsWEBGL.sig="vipipi";var _glMultiDrawElements=_glMultiDrawElementsWEBGL;Module["_glMultiDrawElements"]=_glMultiDrawElements;_glMultiDrawElements.sig="vipipi";var _glMultiDrawElementsANGLE=_glMultiDrawElementsWEBGL;Module["_glMultiDrawElementsANGLE"]=_glMultiDrawElementsANGLE;function _glMultiDrawElementsInstancedWEBGL(mode,counts,type,offsets,instanceCounts,drawcount){counts>>>=0;offsets>>>=0;instanceCounts>>>=0;GLctx.multiDrawWebgl["multiDrawElementsInstancedWEBGL"](mode,HEAP32,counts>>>2,type,HEAP32,offsets>>>2,HEAP32,instanceCounts>>>2,drawcount)}Module["_glMultiDrawElementsInstancedWEBGL"]=_glMultiDrawElementsInstancedWEBGL;_glMultiDrawElementsInstancedWEBGL.sig="vipippi";var _glMultiDrawElementsInstancedANGLE=_glMultiDrawElementsInstancedWEBGL;Module["_glMultiDrawElementsInstancedANGLE"]=_glMultiDrawElementsInstancedANGLE;var _glClearDepth=x0=>GLctx.clearDepth(x0);Module["_glClearDepth"]=_glClearDepth;_glClearDepth.sig="vd";var _glDepthRange=(x0,x1)=>GLctx.depthRange(x0,x1);Module["_glDepthRange"]=_glDepthRange;_glDepthRange.sig="vdd";var _emscripten_glGenVertexArrays=_glGenVertexArrays;Module["_emscripten_glGenVertexArrays"]=_emscripten_glGenVertexArrays;_emscripten_glGenVertexArrays.sig="vip";var _emscripten_glDeleteVertexArrays=_glDeleteVertexArrays;Module["_emscripten_glDeleteVertexArrays"]=_emscripten_glDeleteVertexArrays;_emscripten_glDeleteVertexArrays.sig="vip";var _emscripten_glBindVertexArray=_glBindVertexArray;Module["_emscripten_glBindVertexArray"]=_emscripten_glBindVertexArray;_emscripten_glBindVertexArray.sig="vi";var _emscripten_glIsVertexArray=_glIsVertexArray;Module["_emscripten_glIsVertexArray"]=_emscripten_glIsVertexArray;_emscripten_glIsVertexArray.sig="ii";var _emscripten_glVertexPointer=_glVertexPointer;Module["_emscripten_glVertexPointer"]=_emscripten_glVertexPointer;_emscripten_glVertexPointer.sig="viiip";var _emscripten_glMatrixMode=_glMatrixMode;Module["_emscripten_glMatrixMode"]=_emscripten_glMatrixMode;_emscripten_glMatrixMode.sig="vi";var _emscripten_glBegin=_glBegin;Module["_emscripten_glBegin"]=_emscripten_glBegin;_emscripten_glBegin.sig="vi";var _emscripten_glLoadIdentity=_glLoadIdentity;Module["_emscripten_glLoadIdentity"]=_emscripten_glLoadIdentity;_emscripten_glLoadIdentity.sig="v";var _emscripten_glVertexAttribDivisor=_glVertexAttribDivisor;Module["_emscripten_glVertexAttribDivisor"]=_emscripten_glVertexAttribDivisor;_emscripten_glVertexAttribDivisor.sig="vii";var _emscripten_glDrawArraysInstanced=_glDrawArraysInstanced;Module["_emscripten_glDrawArraysInstanced"]=_emscripten_glDrawArraysInstanced;_emscripten_glDrawArraysInstanced.sig="viiii";var _emscripten_glDrawElementsInstanced=_glDrawElementsInstanced;Module["_emscripten_glDrawElementsInstanced"]=_emscripten_glDrawElementsInstanced;_emscripten_glDrawElementsInstanced.sig="viiipi";var _emscripten_glVertexAttribDivisorNV=_glVertexAttribDivisorNV;Module["_emscripten_glVertexAttribDivisorNV"]=_emscripten_glVertexAttribDivisorNV;var _emscripten_glDrawArraysInstancedNV=_glDrawArraysInstancedNV;Module["_emscripten_glDrawArraysInstancedNV"]=_emscripten_glDrawArraysInstancedNV;var _emscripten_glDrawElementsInstancedNV=_glDrawElementsInstancedNV;Module["_emscripten_glDrawElementsInstancedNV"]=_emscripten_glDrawElementsInstancedNV;var _emscripten_glVertexAttribDivisorEXT=_glVertexAttribDivisorEXT;Module["_emscripten_glVertexAttribDivisorEXT"]=_emscripten_glVertexAttribDivisorEXT;var _emscripten_glDrawArraysInstancedEXT=_glDrawArraysInstancedEXT;Module["_emscripten_glDrawArraysInstancedEXT"]=_emscripten_glDrawArraysInstancedEXT;var _emscripten_glDrawElementsInstancedEXT=_glDrawElementsInstancedEXT;Module["_emscripten_glDrawElementsInstancedEXT"]=_emscripten_glDrawElementsInstancedEXT;var _emscripten_glVertexAttribDivisorARB=_glVertexAttribDivisorARB;Module["_emscripten_glVertexAttribDivisorARB"]=_emscripten_glVertexAttribDivisorARB;var _emscripten_glDrawArraysInstancedARB=_glDrawArraysInstancedARB;Module["_emscripten_glDrawArraysInstancedARB"]=_emscripten_glDrawArraysInstancedARB;var _emscripten_glDrawElementsInstancedARB=_glDrawElementsInstancedARB;Module["_emscripten_glDrawElementsInstancedARB"]=_emscripten_glDrawElementsInstancedARB;var _emscripten_glDrawBuffers=_glDrawBuffers;Module["_emscripten_glDrawBuffers"]=_emscripten_glDrawBuffers;_emscripten_glDrawBuffers.sig="vip";var _emscripten_glDrawBuffersEXT=_glDrawBuffersEXT;Module["_emscripten_glDrawBuffersEXT"]=_emscripten_glDrawBuffersEXT;var _emscripten_glMultiDrawArrays=_glMultiDrawArrays;Module["_emscripten_glMultiDrawArrays"]=_emscripten_glMultiDrawArrays;_emscripten_glMultiDrawArrays.sig="vippi";var _emscripten_glMultiDrawArraysANGLE=_glMultiDrawArraysANGLE;Module["_emscripten_glMultiDrawArraysANGLE"]=_emscripten_glMultiDrawArraysANGLE;var _emscripten_glMultiDrawArraysWEBGL=_glMultiDrawArraysWEBGL;Module["_emscripten_glMultiDrawArraysWEBGL"]=_emscripten_glMultiDrawArraysWEBGL;var _emscripten_glMultiDrawArraysInstancedANGLE=_glMultiDrawArraysInstancedANGLE;Module["_emscripten_glMultiDrawArraysInstancedANGLE"]=_emscripten_glMultiDrawArraysInstancedANGLE;var _emscripten_glMultiDrawArraysInstancedWEBGL=_glMultiDrawArraysInstancedWEBGL;Module["_emscripten_glMultiDrawArraysInstancedWEBGL"]=_emscripten_glMultiDrawArraysInstancedWEBGL;var _emscripten_glMultiDrawElements=_glMultiDrawElements;Module["_emscripten_glMultiDrawElements"]=_emscripten_glMultiDrawElements;_emscripten_glMultiDrawElements.sig="vipipi";var _emscripten_glMultiDrawElementsANGLE=_glMultiDrawElementsANGLE;Module["_emscripten_glMultiDrawElementsANGLE"]=_emscripten_glMultiDrawElementsANGLE;var _emscripten_glMultiDrawElementsWEBGL=_glMultiDrawElementsWEBGL;Module["_emscripten_glMultiDrawElementsWEBGL"]=_emscripten_glMultiDrawElementsWEBGL;var _emscripten_glMultiDrawElementsInstancedANGLE=_glMultiDrawElementsInstancedANGLE;Module["_emscripten_glMultiDrawElementsInstancedANGLE"]=_emscripten_glMultiDrawElementsInstancedANGLE;var _emscripten_glMultiDrawElementsInstancedWEBGL=_glMultiDrawElementsInstancedWEBGL;Module["_emscripten_glMultiDrawElementsInstancedWEBGL"]=_emscripten_glMultiDrawElementsInstancedWEBGL;var _emscripten_glClearDepth=_glClearDepth;Module["_emscripten_glClearDepth"]=_emscripten_glClearDepth;_emscripten_glClearDepth.sig="vd";var _emscripten_glDepthRange=_glDepthRange;Module["_emscripten_glDepthRange"]=_emscripten_glDepthRange;_emscripten_glDepthRange.sig="vdd";var writeGLArray=(arr,dst,dstLength,heapType)=>{var len=arr.length;var writeLength=dstLength>>2;for(var i=0;i>>0]=arr[i]}return len};Module["writeGLArray"]=writeGLArray;var webglPowerPreferences=["default","low-power","high-performance"];Module["webglPowerPreferences"]=webglPowerPreferences;function _emscripten_webgl_do_create_context(target,attributes){target>>>=0;attributes>>>=0;var a=attributes>>>2;var powerPreference=HEAP32[a+(24>>2)>>>0];var contextAttributes={"alpha":!!HEAP32[a+(0>>2)>>>0],"depth":!!HEAP32[a+(4>>2)>>>0],"stencil":!!HEAP32[a+(8>>2)>>>0],"antialias":!!HEAP32[a+(12>>2)>>>0],"premultipliedAlpha":!!HEAP32[a+(16>>2)>>>0],"preserveDrawingBuffer":!!HEAP32[a+(20>>2)>>>0],"powerPreference":webglPowerPreferences[powerPreference],"failIfMajorPerformanceCaveat":!!HEAP32[a+(28>>2)>>>0],majorVersion:HEAP32[a+(32>>2)>>>0],minorVersion:HEAP32[a+(36>>2)>>>0],enableExtensionsByDefault:HEAP32[a+(40>>2)>>>0],explicitSwapControl:HEAP32[a+(44>>2)>>>0],proxyContextToMainThread:HEAP32[a+(48>>2)>>>0],renderViaOffscreenBackBuffer:HEAP32[a+(52>>2)>>>0]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}Module["_emscripten_webgl_do_create_context"]=_emscripten_webgl_do_create_context;_emscripten_webgl_do_create_context.sig="ppp";var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;Module["_emscripten_webgl_create_context"]=_emscripten_webgl_create_context;_emscripten_webgl_create_context.sig="ppp";function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}Module["_emscripten_webgl_do_get_current_context"]=_emscripten_webgl_do_get_current_context;_emscripten_webgl_do_get_current_context.sig="p";var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;Module["_emscripten_webgl_get_current_context"]=_emscripten_webgl_get_current_context;_emscripten_webgl_get_current_context.sig="p";var _emscripten_webgl_do_commit_frame=()=>{if(!GL.currentContext||!GL.currentContext.GLctx){return-3}if(!GL.currentContext.attributes.explicitSwapControl){return-3}return 0};Module["_emscripten_webgl_do_commit_frame"]=_emscripten_webgl_do_commit_frame;_emscripten_webgl_do_commit_frame.sig="i";var _emscripten_webgl_commit_frame=_emscripten_webgl_do_commit_frame;Module["_emscripten_webgl_commit_frame"]=_emscripten_webgl_commit_frame;_emscripten_webgl_commit_frame.sig="i";function _emscripten_webgl_make_context_current(contextHandle){contextHandle>>>=0;var success=GL.makeContextCurrent(contextHandle);return success?0:-5}Module["_emscripten_webgl_make_context_current"]=_emscripten_webgl_make_context_current;_emscripten_webgl_make_context_current.sig="ip";function _emscripten_webgl_get_drawing_buffer_size(contextHandle,width,height){contextHandle>>>=0;width>>>=0;height>>>=0;var GLContext=GL.getContext(contextHandle);if(!GLContext||!GLContext.GLctx||!width||!height){return-5}HEAP32[width>>>2>>>0]=GLContext.GLctx.drawingBufferWidth;HEAP32[height>>>2>>>0]=GLContext.GLctx.drawingBufferHeight;return 0}Module["_emscripten_webgl_get_drawing_buffer_size"]=_emscripten_webgl_get_drawing_buffer_size;_emscripten_webgl_get_drawing_buffer_size.sig="ippp";function _emscripten_webgl_get_context_attributes(c,a){c>>>=0;a>>>=0;if(!a)return-5;c=GL.contexts[c];if(!c)return-3;var t=c.GLctx;if(!t)return-3;t=t.getContextAttributes();HEAP32[a>>>2>>>0]=t.alpha;HEAP32[a+4>>>2>>>0]=t.depth;HEAP32[a+8>>>2>>>0]=t.stencil;HEAP32[a+12>>>2>>>0]=t.antialias;HEAP32[a+16>>>2>>>0]=t.premultipliedAlpha;HEAP32[a+20>>>2>>>0]=t.preserveDrawingBuffer;var power=t["powerPreference"]&&webglPowerPreferences.indexOf(t["powerPreference"]);HEAP32[a+24>>>2>>>0]=power;HEAP32[a+28>>>2>>>0]=t.failIfMajorPerformanceCaveat;HEAP32[a+32>>>2>>>0]=c.version;HEAP32[a+36>>>2>>>0]=0;HEAP32[a+40>>>2>>>0]=c.attributes.enableExtensionsByDefault;return 0}Module["_emscripten_webgl_get_context_attributes"]=_emscripten_webgl_get_context_attributes;_emscripten_webgl_get_context_attributes.sig="ipp";function _emscripten_webgl_destroy_context(contextHandle){contextHandle>>>=0;if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}Module["_emscripten_webgl_destroy_context"]=_emscripten_webgl_destroy_context;_emscripten_webgl_destroy_context.sig="ip";function _emscripten_webgl_enable_extension(contextHandle,extension){contextHandle>>>=0;extension>>>=0;var context=GL.getContext(contextHandle);var extString=UTF8ToString(extension);if(extString.startsWith("GL_"))extString=extString.substr(3);if(extString=="ANGLE_instanced_arrays")webgl_enable_ANGLE_instanced_arrays(GLctx);if(extString=="OES_vertex_array_object")webgl_enable_OES_vertex_array_object(GLctx);if(extString=="WEBGL_draw_buffers")webgl_enable_WEBGL_draw_buffers(GLctx);if(extString=="WEBGL_multi_draw")webgl_enable_WEBGL_multi_draw(GLctx);var ext=context.GLctx.getExtension(extString);return!!ext}Module["_emscripten_webgl_enable_extension"]=_emscripten_webgl_enable_extension;_emscripten_webgl_enable_extension.sig="ipp";var _emscripten_supports_offscreencanvas=()=>0;Module["_emscripten_supports_offscreencanvas"]=_emscripten_supports_offscreencanvas;_emscripten_supports_offscreencanvas.sig="i";var registerWebGlEventCallback=(target,userData,useCapture,callbackfunc,eventTypeId,eventTypeString,targetThread)=>{var webGlEventHandlerFunc=(e=event)=>{if(getWasmTableEntry(callbackfunc)(eventTypeId,0,userData))e.preventDefault()};var eventHandler={target:findEventTarget(target),eventTypeString:eventTypeString,callbackfunc:callbackfunc,handlerFunc:webGlEventHandlerFunc,useCapture:useCapture};JSEvents.registerOrRemoveHandler(eventHandler)};Module["registerWebGlEventCallback"]=registerWebGlEventCallback;function _emscripten_set_webglcontextlost_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;registerWebGlEventCallback(target,userData,useCapture,callbackfunc,31,"webglcontextlost",targetThread);return 0}Module["_emscripten_set_webglcontextlost_callback_on_thread"]=_emscripten_set_webglcontextlost_callback_on_thread;_emscripten_set_webglcontextlost_callback_on_thread.sig="ippipp";function _emscripten_set_webglcontextrestored_callback_on_thread(target,userData,useCapture,callbackfunc,targetThread){target>>>=0;userData>>>=0;callbackfunc>>>=0;targetThread>>>=0;registerWebGlEventCallback(target,userData,useCapture,callbackfunc,32,"webglcontextrestored",targetThread);return 0}Module["_emscripten_set_webglcontextrestored_callback_on_thread"]=_emscripten_set_webglcontextrestored_callback_on_thread;_emscripten_set_webglcontextrestored_callback_on_thread.sig="ippipp";function _emscripten_is_webgl_context_lost(contextHandle){contextHandle>>>=0;return!GL.contexts[contextHandle]||GL.contexts[contextHandle].GLctx.isContextLost()}Module["_emscripten_is_webgl_context_lost"]=_emscripten_is_webgl_context_lost;_emscripten_is_webgl_context_lost.sig="ip";function _emscripten_webgl_get_supported_extensions(){return stringToNewUTF8(GLctx.getSupportedExtensions().join(" "))}Module["_emscripten_webgl_get_supported_extensions"]=_emscripten_webgl_get_supported_extensions;_emscripten_webgl_get_supported_extensions.sig="p";var _emscripten_webgl_get_program_parameter_d=(program,param)=>GLctx.getProgramParameter(GL.programs[program],param);Module["_emscripten_webgl_get_program_parameter_d"]=_emscripten_webgl_get_program_parameter_d;_emscripten_webgl_get_program_parameter_d.sig="dii";function _emscripten_webgl_get_program_info_log_utf8(program){return stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program]))}Module["_emscripten_webgl_get_program_info_log_utf8"]=_emscripten_webgl_get_program_info_log_utf8;_emscripten_webgl_get_program_info_log_utf8.sig="pi";var _emscripten_webgl_get_shader_parameter_d=(shader,param)=>GLctx.getShaderParameter(GL.shaders[shader],param);Module["_emscripten_webgl_get_shader_parameter_d"]=_emscripten_webgl_get_shader_parameter_d;_emscripten_webgl_get_shader_parameter_d.sig="dii";function _emscripten_webgl_get_shader_info_log_utf8(shader){return stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader]))}Module["_emscripten_webgl_get_shader_info_log_utf8"]=_emscripten_webgl_get_shader_info_log_utf8;_emscripten_webgl_get_shader_info_log_utf8.sig="pi";function _emscripten_webgl_get_shader_source_utf8(shader){return stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader]))}Module["_emscripten_webgl_get_shader_source_utf8"]=_emscripten_webgl_get_shader_source_utf8;_emscripten_webgl_get_shader_source_utf8.sig="pi";var _emscripten_webgl_get_vertex_attrib_d=(index,param)=>GLctx.getVertexAttrib(index,param);Module["_emscripten_webgl_get_vertex_attrib_d"]=_emscripten_webgl_get_vertex_attrib_d;_emscripten_webgl_get_vertex_attrib_d.sig="dii";var _emscripten_webgl_get_vertex_attrib_o=(index,param)=>{var obj=GLctx.getVertexAttrib(index,param);return obj?.name};Module["_emscripten_webgl_get_vertex_attrib_o"]=_emscripten_webgl_get_vertex_attrib_o;_emscripten_webgl_get_vertex_attrib_o.sig="iii";function _emscripten_webgl_get_vertex_attrib_v(index,param,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getVertexAttrib(index,param),dst,dstLength,dstType)}Module["_emscripten_webgl_get_vertex_attrib_v"]=_emscripten_webgl_get_vertex_attrib_v;_emscripten_webgl_get_vertex_attrib_v.sig="iiipii";var _emscripten_webgl_get_uniform_d=(program,location)=>GLctx.getUniform(GL.programs[program],webglGetUniformLocation(location));Module["_emscripten_webgl_get_uniform_d"]=_emscripten_webgl_get_uniform_d;_emscripten_webgl_get_uniform_d.sig="dii";function _emscripten_webgl_get_uniform_v(program,location,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getUniform(GL.programs[program],webglGetUniformLocation(location)),dst,dstLength,dstType)}Module["_emscripten_webgl_get_uniform_v"]=_emscripten_webgl_get_uniform_v;_emscripten_webgl_get_uniform_v.sig="iiipii";function _emscripten_webgl_get_parameter_v(param,dst,dstLength,dstType){dst>>>=0;return writeGLArray(GLctx.getParameter(param),dst,dstLength,dstType)}Module["_emscripten_webgl_get_parameter_v"]=_emscripten_webgl_get_parameter_v;_emscripten_webgl_get_parameter_v.sig="iipii";var _emscripten_webgl_get_parameter_d=param=>GLctx.getParameter(param);Module["_emscripten_webgl_get_parameter_d"]=_emscripten_webgl_get_parameter_d;_emscripten_webgl_get_parameter_d.sig="di";var _emscripten_webgl_get_parameter_o=param=>{var obj=GLctx.getParameter(param);return obj?.name};Module["_emscripten_webgl_get_parameter_o"]=_emscripten_webgl_get_parameter_o;_emscripten_webgl_get_parameter_o.sig="ii";function _emscripten_webgl_get_parameter_utf8(param){return stringToNewUTF8(GLctx.getParameter(param))}Module["_emscripten_webgl_get_parameter_utf8"]=_emscripten_webgl_get_parameter_utf8;_emscripten_webgl_get_parameter_utf8.sig="pi";function _emscripten_webgl_get_parameter_i64v(param,dst){dst>>>=0;return writeI53ToI64(dst,GLctx.getParameter(param))}Module["_emscripten_webgl_get_parameter_i64v"]=_emscripten_webgl_get_parameter_i64v;_emscripten_webgl_get_parameter_i64v.sig="vip";var EGL={errorCode:12288,defaultDisplayInitialized:false,currentContext:0,currentReadSurface:0,currentDrawSurface:0,contextAttributes:{alpha:false,depth:false,stencil:false,antialias:false},stringCache:{},setErrorCode(code){EGL.errorCode=code},chooseConfig(display,attribList,config,config_size,numConfigs){if(display!=62e3){EGL.setErrorCode(12296);return 0}if(attribList){for(;;){var param=HEAP32[attribList>>>2>>>0];if(param==12321){var alphaSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.alpha=alphaSize>0}else if(param==12325){var depthSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.depth=depthSize>0}else if(param==12326){var stencilSize=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.stencil=stencilSize>0}else if(param==12337){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples>0}else if(param==12338){var samples=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.antialias=samples==1}else if(param==12544){var requestedPriority=HEAP32[attribList+4>>>2>>>0];EGL.contextAttributes.lowLatency=requestedPriority!=12547}else if(param==12344){break}attribList+=8}}if((!config||!config_size)&&!numConfigs){EGL.setErrorCode(12300);return 0}if(numConfigs){HEAP32[numConfigs>>>2>>>0]=1}if(config&&config_size>0){HEAPU32[config>>>2>>>0]=62002}EGL.setErrorCode(12288);return 1}};Module["EGL"]=EGL;function _eglGetDisplay(nativeDisplayType){nativeDisplayType>>>=0;EGL.setErrorCode(12288);if(nativeDisplayType!=0&&nativeDisplayType!=1){return 0}return 62e3}Module["_eglGetDisplay"]=_eglGetDisplay;_eglGetDisplay.sig="pp";function _eglInitialize(display,majorVersion,minorVersion){display>>>=0;majorVersion>>>=0;minorVersion>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(majorVersion){HEAP32[majorVersion>>>2>>>0]=1}if(minorVersion){HEAP32[minorVersion>>>2>>>0]=4}EGL.defaultDisplayInitialized=true;EGL.setErrorCode(12288);return 1}Module["_eglInitialize"]=_eglInitialize;_eglInitialize.sig="ippp";function _eglTerminate(display){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.defaultDisplayInitialized=false;EGL.setErrorCode(12288);return 1}Module["_eglTerminate"]=_eglTerminate;_eglTerminate.sig="ip";function _eglGetConfigs(display,configs,config_size,numConfigs){display>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,0,configs,config_size,numConfigs)}Module["_eglGetConfigs"]=_eglGetConfigs;_eglGetConfigs.sig="ippip";function _eglChooseConfig(display,attrib_list,configs,config_size,numConfigs){display>>>=0;attrib_list>>>=0;configs>>>=0;numConfigs>>>=0;return EGL.chooseConfig(display,attrib_list,configs,config_size,numConfigs)}Module["_eglChooseConfig"]=_eglChooseConfig;_eglChooseConfig.sig="ipppip";function _eglGetConfigAttrib(display,config,attribute,value){display>>>=0;config>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12320:HEAP32[value>>>2>>>0]=EGL.contextAttributes.alpha?32:24;return 1;case 12321:HEAP32[value>>>2>>>0]=EGL.contextAttributes.alpha?8:0;return 1;case 12322:HEAP32[value>>>2>>>0]=8;return 1;case 12323:HEAP32[value>>>2>>>0]=8;return 1;case 12324:HEAP32[value>>>2>>>0]=8;return 1;case 12325:HEAP32[value>>>2>>>0]=EGL.contextAttributes.depth?24:0;return 1;case 12326:HEAP32[value>>>2>>>0]=EGL.contextAttributes.stencil?8:0;return 1;case 12327:HEAP32[value>>>2>>>0]=12344;return 1;case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12329:HEAP32[value>>>2>>>0]=0;return 1;case 12330:HEAP32[value>>>2>>>0]=4096;return 1;case 12331:HEAP32[value>>>2>>>0]=16777216;return 1;case 12332:HEAP32[value>>>2>>>0]=4096;return 1;case 12333:HEAP32[value>>>2>>>0]=0;return 1;case 12334:HEAP32[value>>>2>>>0]=0;return 1;case 12335:HEAP32[value>>>2>>>0]=12344;return 1;case 12337:HEAP32[value>>>2>>>0]=EGL.contextAttributes.antialias?4:0;return 1;case 12338:HEAP32[value>>>2>>>0]=EGL.contextAttributes.antialias?1:0;return 1;case 12339:HEAP32[value>>>2>>>0]=4;return 1;case 12340:HEAP32[value>>>2>>>0]=12344;return 1;case 12341:case 12342:case 12343:HEAP32[value>>>2>>>0]=-1;return 1;case 12345:case 12346:HEAP32[value>>>2>>>0]=0;return 1;case 12347:HEAP32[value>>>2>>>0]=0;return 1;case 12348:HEAP32[value>>>2>>>0]=1;return 1;case 12349:case 12350:HEAP32[value>>>2>>>0]=0;return 1;case 12351:HEAP32[value>>>2>>>0]=12430;return 1;case 12352:HEAP32[value>>>2>>>0]=4;return 1;case 12354:HEAP32[value>>>2>>>0]=0;return 1;default:EGL.setErrorCode(12292);return 0}}Module["_eglGetConfigAttrib"]=_eglGetConfigAttrib;_eglGetConfigAttrib.sig="ippip";function _eglCreateWindowSurface(display,config,win,attrib_list){display>>>=0;config>>>=0;attrib_list>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(config!=62002){EGL.setErrorCode(12293);return 0}EGL.setErrorCode(12288);return 62006}Module["_eglCreateWindowSurface"]=_eglCreateWindowSurface;_eglCreateWindowSurface.sig="pppip";function _eglDestroySurface(display,surface){display>>>=0;surface>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 1}if(EGL.currentReadSurface==surface){EGL.currentReadSurface=0}if(EGL.currentDrawSurface==surface){EGL.currentDrawSurface=0}EGL.setErrorCode(12288);return 1}Module["_eglDestroySurface"]=_eglDestroySurface;_eglDestroySurface.sig="ipp";function _eglCreateContext(display,config,hmm,contextAttribs){display>>>=0;config>>>=0;hmm>>>=0;contextAttribs>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}var glesContextVersion=1;for(;;){var param=HEAP32[contextAttribs>>>2>>>0];if(param==12440){glesContextVersion=HEAP32[contextAttribs+4>>>2>>>0]}else if(param==12344){break}else{EGL.setErrorCode(12292);return 0}contextAttribs+=8}if(glesContextVersion!=2){EGL.setErrorCode(12293);return 0}EGL.contextAttributes.majorVersion=glesContextVersion-1;EGL.contextAttributes.minorVersion=0;EGL.context=GL.createContext(Module["canvas"],EGL.contextAttributes);if(EGL.context!=0){EGL.setErrorCode(12288);GL.makeContextCurrent(EGL.context);Module.useWebGL=true;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});GL.makeContextCurrent(null);return 62004}else{EGL.setErrorCode(12297);return 0}}Module["_eglCreateContext"]=_eglCreateContext;_eglCreateContext.sig="ppppp";function _eglDestroyContext(display,context){display>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}GL.deleteContext(EGL.context);EGL.setErrorCode(12288);if(EGL.currentContext==context){EGL.currentContext=0}return 1}Module["_eglDestroyContext"]=_eglDestroyContext;_eglDestroyContext.sig="ipp";function _eglQuerySurface(display,surface,attribute,value){display>>>=0;surface>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(surface!=62006){EGL.setErrorCode(12301);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12376:return 1;case 12375:HEAP32[value>>>2>>>0]=Module["canvas"].width;return 1;case 12374:HEAP32[value>>>2>>>0]=Module["canvas"].height;return 1;case 12432:HEAP32[value>>>2>>>0]=-1;return 1;case 12433:HEAP32[value>>>2>>>0]=-1;return 1;case 12434:HEAP32[value>>>2>>>0]=-1;return 1;case 12422:HEAP32[value>>>2>>>0]=12420;return 1;case 12441:HEAP32[value>>>2>>>0]=12442;return 1;case 12435:HEAP32[value>>>2>>>0]=12437;return 1;case 12416:case 12417:case 12418:case 12419:return 1;default:EGL.setErrorCode(12292);return 0}}Module["_eglQuerySurface"]=_eglQuerySurface;_eglQuerySurface.sig="ippip";function _eglQueryContext(display,context,attribute,value){display>>>=0;context>>>=0;value>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=62004){EGL.setErrorCode(12294);return 0}if(!value){EGL.setErrorCode(12300);return 0}EGL.setErrorCode(12288);switch(attribute){case 12328:HEAP32[value>>>2>>>0]=62002;return 1;case 12439:HEAP32[value>>>2>>>0]=12448;return 1;case 12440:HEAP32[value>>>2>>>0]=EGL.contextAttributes.majorVersion+1;return 1;case 12422:HEAP32[value>>>2>>>0]=12420;return 1;default:EGL.setErrorCode(12292);return 0}}Module["_eglQueryContext"]=_eglQueryContext;_eglQueryContext.sig="ippip";var _eglGetError=()=>EGL.errorCode;Module["_eglGetError"]=_eglGetError;_eglGetError.sig="i";function _eglQueryString(display,name){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}EGL.setErrorCode(12288);if(EGL.stringCache[name])return EGL.stringCache[name];var ret;switch(name){case 12371:ret=stringToNewUTF8("Emscripten");break;case 12372:ret=stringToNewUTF8("1.4 Emscripten EGL");break;case 12373:ret=stringToNewUTF8("");break;case 12429:ret=stringToNewUTF8("OpenGL_ES");break;default:EGL.setErrorCode(12300);return 0}EGL.stringCache[name]=ret;return ret}Module["_eglQueryString"]=_eglQueryString;_eglQueryString.sig="ppi";var _eglBindAPI=api=>{if(api==12448){EGL.setErrorCode(12288);return 1}EGL.setErrorCode(12300);return 0};Module["_eglBindAPI"]=_eglBindAPI;_eglBindAPI.sig="ii";var _eglQueryAPI=()=>{EGL.setErrorCode(12288);return 12448};Module["_eglQueryAPI"]=_eglQueryAPI;_eglQueryAPI.sig="i";var _eglWaitClient=()=>{EGL.setErrorCode(12288);return 1};Module["_eglWaitClient"]=_eglWaitClient;_eglWaitClient.sig="i";var _eglWaitNative=nativeEngineId=>{EGL.setErrorCode(12288);return 1};Module["_eglWaitNative"]=_eglWaitNative;_eglWaitNative.sig="ii";var _eglWaitGL=_eglWaitClient;Module["_eglWaitGL"]=_eglWaitGL;_eglWaitGL.sig="i";function _eglSwapInterval(display,interval){display>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(interval==0)_emscripten_set_main_loop_timing(0,0);else _emscripten_set_main_loop_timing(1,interval);EGL.setErrorCode(12288);return 1}Module["_eglSwapInterval"]=_eglSwapInterval;_eglSwapInterval.sig="ipi";function _eglMakeCurrent(display,draw,read,context){display>>>=0;draw>>>=0;read>>>=0;context>>>=0;if(display!=62e3){EGL.setErrorCode(12296);return 0}if(context!=0&&context!=62004){EGL.setErrorCode(12294);return 0}if(read!=0&&read!=62006||draw!=0&&draw!=62006){EGL.setErrorCode(12301);return 0}GL.makeContextCurrent(context?EGL.context:null);EGL.currentContext=context;EGL.currentDrawSurface=draw;EGL.currentReadSurface=read;EGL.setErrorCode(12288);return 1}Module["_eglMakeCurrent"]=_eglMakeCurrent;_eglMakeCurrent.sig="ipppp";function _eglGetCurrentContext(){return EGL.currentContext}Module["_eglGetCurrentContext"]=_eglGetCurrentContext;_eglGetCurrentContext.sig="p";function _eglGetCurrentSurface(readdraw){if(readdraw==12378){return EGL.currentReadSurface}else if(readdraw==12377){return EGL.currentDrawSurface}else{EGL.setErrorCode(12300);return 0}}Module["_eglGetCurrentSurface"]=_eglGetCurrentSurface;_eglGetCurrentSurface.sig="pi";function _eglGetCurrentDisplay(){return EGL.currentContext?62e3:0}Module["_eglGetCurrentDisplay"]=_eglGetCurrentDisplay;_eglGetCurrentDisplay.sig="p";function _eglSwapBuffers(dpy,surface){dpy>>>=0;surface>>>=0;if(!EGL.defaultDisplayInitialized){EGL.setErrorCode(12289)}else if(!Module.ctx){EGL.setErrorCode(12290)}else if(Module.ctx.isContextLost()){EGL.setErrorCode(12302)}else{EGL.setErrorCode(12288);return 1}return 0}Module["_eglSwapBuffers"]=_eglSwapBuffers;_eglSwapBuffers.sig="ipp";var _eglReleaseThread=()=>{EGL.currentContext=0;EGL.currentReadSurface=0;EGL.currentDrawSurface=0;EGL.setErrorCode(12288);return 1};Module["_eglReleaseThread"]=_eglReleaseThread;_eglReleaseThread.sig="i";var _SDL_GetTicks=()=>Date.now()-SDL.startTime|0;Module["_SDL_GetTicks"]=_SDL_GetTicks;_SDL_GetTicks.sig="i";function _SDL_LockSurface(surf){surf>>>=0;var surfData=SDL.surfaces[surf];surfData.locked++;if(surfData.locked>1)return 0;if(!surfData.buffer){surfData.buffer=_malloc(surfData.width*surfData.height*4);HEAPU32[surf+20>>>2>>>0]=surfData.buffer}HEAPU32[surf+20>>>2>>>0]=surfData.buffer;if(surf==SDL.screen&&Module.screenIsReadOnly&&surfData.image)return 0;if(SDL.defaults.discardOnLock){if(!surfData.image){surfData.image=surfData.ctx.createImageData(surfData.width,surfData.height)}if(!SDL.defaults.opaqueFrontBuffer)return}else{surfData.image=surfData.ctx.getImageData(0,0,surfData.width,surfData.height)}if(surf==SDL.screen&&SDL.defaults.opaqueFrontBuffer){var data=surfData.image.data;var num=data.length;for(var i=0;i>>0)}}return 0}Module["_SDL_LockSurface"]=_SDL_LockSurface;_SDL_LockSurface.sig="ip";var SDL={defaults:{width:320,height:200,copyOnLock:true,discardOnLock:false,opaqueFrontBuffer:true},version:null,surfaces:{},canvasPool:[],events:[],fonts:[null],audios:[null],rwops:[null],music:{audio:null,volume:1},mixerFrequency:22050,mixerFormat:32784,mixerNumChannels:2,mixerChunkSize:1024,channelMinimumNumber:0,GL:false,glAttributes:{0:3,1:3,2:2,3:0,4:0,5:1,6:16,7:0,8:0,9:0,10:0,11:0,12:0,13:0,14:0,15:1,16:0,17:0,18:0},keyboardState:null,keyboardMap:{},canRequestFullscreen:false,isRequestingFullscreen:false,textInput:false,unicode:false,ttfContext:null,audio:null,startTime:null,initFlags:0,buttonState:0,modState:0,DOMButtons:[0,0,0],DOMEventToSDLEvent:{},TOUCH_DEFAULT_ID:0,eventHandler:null,eventHandlerContext:null,eventHandlerTemp:0,keyCodes:{16:1249,17:1248,18:1250,20:1081,33:1099,34:1102,35:1101,36:1098,37:1104,38:1106,39:1103,40:1105,44:316,45:1097,46:127,91:1251,93:1125,96:1122,97:1113,98:1114,99:1115,100:1116,101:1117,102:1118,103:1119,104:1120,105:1121,106:1109,107:1111,109:1110,110:1123,111:1108,112:1082,113:1083,114:1084,115:1085,116:1086,117:1087,118:1088,119:1089,120:1090,121:1091,122:1092,123:1093,124:1128,125:1129,126:1130,127:1131,128:1132,129:1133,130:1134,131:1135,132:1136,133:1137,134:1138,135:1139,144:1107,160:94,161:33,162:34,163:35,164:36,165:37,166:38,167:95,168:40,169:41,170:42,171:43,172:124,173:45,174:123,175:125,176:126,181:127,182:129,183:128,188:44,190:46,191:47,192:96,219:91,220:92,221:93,222:39,224:1251},scanCodes:{8:42,9:43,13:40,27:41,32:44,35:204,39:53,44:54,46:55,47:56,48:39,49:30,50:31,51:32,52:33,53:34,54:35,55:36,56:37,57:38,58:203,59:51,61:46,91:47,92:49,93:48,96:52,97:4,98:5,99:6,100:7,101:8,102:9,103:10,104:11,105:12,106:13,107:14,108:15,109:16,110:17,111:18,112:19,113:20,114:21,115:22,116:23,117:24,118:25,119:26,120:27,121:28,122:29,127:76,305:224,308:226,316:70},loadRect(rect){return{x:HEAP32[rect+0>>>2>>>0],y:HEAP32[rect+4>>>2>>>0],w:HEAP32[rect+8>>>2>>>0],h:HEAP32[rect+12>>>2>>>0]}},updateRect(rect,r){HEAP32[rect>>>2>>>0]=r.x;HEAP32[rect+4>>>2>>>0]=r.y;HEAP32[rect+8>>>2>>>0]=r.w;HEAP32[rect+12>>>2>>>0]=r.h},intersectionOfRects(first,second){var leftX=Math.max(first.x,second.x);var leftY=Math.max(first.y,second.y);var rightX=Math.min(first.x+first.w,second.x+second.w);var rightY=Math.min(first.y+first.h,second.y+second.h);return{x:leftX,y:leftY,w:Math.max(leftX,rightX)-leftX,h:Math.max(leftY,rightY)-leftY}},checkPixelFormat(fmt){},loadColorToCSSRGB(color){var rgba=HEAP32[color>>>2>>>0];return"rgb("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+")"},loadColorToCSSRGBA(color){var rgba=HEAP32[color>>>2>>>0];return"rgba("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+","+(rgba>>24&255)/255+")"},translateColorToCSSRGBA:rgba=>"rgba("+(rgba&255)+","+(rgba>>8&255)+","+(rgba>>16&255)+","+(rgba>>>24)/255+")",translateRGBAToCSSRGBA:(r,g,b,a)=>"rgba("+(r&255)+","+(g&255)+","+(b&255)+","+(a&255)/255+")",translateRGBAToColor:(r,g,b,a)=>r|g<<8|b<<16|a<<24,makeSurface(width,height,flags,usePageCanvas,source,rmask,gmask,bmask,amask){var is_SDL_HWSURFACE=flags&1;var is_SDL_HWPALETTE=flags&2097152;var is_SDL_OPENGL=flags&67108864;var surf=_malloc(60);var pixelFormat=_malloc(44);var bpp=is_SDL_HWPALETTE?1:4;var buffer=0;if(!is_SDL_HWSURFACE&&!is_SDL_OPENGL){buffer=_malloc(width*height*4)}HEAP32[surf>>>2>>>0]=flags;HEAPU32[surf+4>>>2>>>0]=pixelFormat;HEAP32[surf+8>>>2>>>0]=width;HEAP32[surf+12>>>2>>>0]=height;HEAP32[surf+16>>>2>>>0]=width*bpp;HEAPU32[surf+20>>>2>>>0]=buffer;HEAP32[surf+36>>>2>>>0]=0;HEAP32[surf+40>>>2>>>0]=0;HEAP32[surf+44>>>2>>>0]=Module["canvas"].width;HEAP32[surf+48>>>2>>>0]=Module["canvas"].height;HEAP32[surf+56>>>2>>>0]=1;HEAP32[pixelFormat>>>2>>>0]=-2042224636;HEAP32[pixelFormat+4>>>2>>>0]=0;HEAP8[pixelFormat+8>>>0]=bpp*8;HEAP8[pixelFormat+9>>>0]=bpp;HEAP32[pixelFormat+12>>>2>>>0]=rmask||255;HEAP32[pixelFormat+16>>>2>>>0]=gmask||65280;HEAP32[pixelFormat+20>>>2>>>0]=bmask||16711680;HEAP32[pixelFormat+24>>>2>>>0]=amask||4278190080;SDL.GL=SDL.GL||is_SDL_OPENGL;var canvas;if(!usePageCanvas){if(SDL.canvasPool.length>0){canvas=SDL.canvasPool.pop()}else{canvas=document.createElement("canvas")}canvas.width=width;canvas.height=height}else{canvas=Module["canvas"]}var webGLContextAttributes={antialias:SDL.glAttributes[13]!=0&&SDL.glAttributes[14]>1,depth:SDL.glAttributes[6]>0,stencil:SDL.glAttributes[7]>0,alpha:SDL.glAttributes[3]>0};var ctx=Browser.createContext(canvas,is_SDL_OPENGL,usePageCanvas,webGLContextAttributes);SDL.surfaces[surf]={width:width,height:height,canvas:canvas,ctx:ctx,surf:surf,buffer:buffer,pixelFormat:pixelFormat,alpha:255,flags:flags,locked:0,usePageCanvas:usePageCanvas,source:source,isFlagSet:flag=>flags&flag};return surf},copyIndexedColorData(surfData,rX,rY,rW,rH){if(!surfData.colors){return}var fullWidth=Module["canvas"].width;var fullHeight=Module["canvas"].height;var startX=rX||0;var startY=rY||0;var endX=(rW||fullWidth-startX)+startX;var endY=(rH||fullHeight-startY)+startY;var buffer=surfData.buffer;if(!surfData.image.data32){surfData.image.data32=new Uint32Array(surfData.image.data.buffer)}var data32=surfData.image.data32;var colors32=surfData.colors32;for(var y=startY;y>>0]]}}},freeSurface(surf){var refcountPointer=surf+56;var refcount=HEAP32[refcountPointer>>>2>>>0];if(refcount>1){HEAP32[refcountPointer>>>2>>>0]=refcount-1;return}var info=SDL.surfaces[surf];if(!info.usePageCanvas&&info.canvas)SDL.canvasPool.push(info.canvas);if(info.buffer)_free(info.buffer);_free(info.pixelFormat);_free(surf);SDL.surfaces[surf]=null;if(surf===SDL.screen){SDL.screen=null}},blitSurface(src,srcrect,dst,dstrect,scale){var srcData=SDL.surfaces[src];var dstData=SDL.surfaces[dst];var sr,dr;if(srcrect){sr=SDL.loadRect(srcrect)}else{sr={x:0,y:0,w:srcData.width,h:srcData.height}}if(dstrect){dr=SDL.loadRect(dstrect)}else{dr={x:0,y:0,w:srcData.width,h:srcData.height}}if(dstData.clipRect){var widthScale=!scale||sr.w===0?1:sr.w/dr.w;var heightScale=!scale||sr.h===0?1:sr.h/dr.h;dr=SDL.intersectionOfRects(dstData.clipRect,dr);sr.w=dr.w*widthScale;sr.h=dr.h*heightScale;if(dstrect){SDL.updateRect(dstrect,dr)}}var blitw,blith;if(scale){blitw=dr.w;blith=dr.h}else{blitw=sr.w;blith=sr.h}if(sr.w===0||sr.h===0||blitw===0||blith===0){return 0}var oldAlpha=dstData.ctx.globalAlpha;dstData.ctx.globalAlpha=srcData.alpha/255;dstData.ctx.drawImage(srcData.canvas,sr.x,sr.y,sr.w,sr.h,dr.x,dr.y,blitw,blith);dstData.ctx.globalAlpha=oldAlpha;if(dst!=SDL.screen){warnOnce("WARNING: copying canvas data to memory for compatibility");_SDL_LockSurface(dst);dstData.locked--}return 0},downFingers:{},savedKeydown:null,receiveEvent(event){function unpressAllPressedKeys(){for(var code in SDL.keyboardMap){SDL.events.push({type:"keyup",keyCode:SDL.keyboardMap[code]})}}switch(event.type){case"touchstart":case"touchmove":{event.preventDefault();var touches=[];if(event.type==="touchstart"){for(var i=0;i0?Math.max(delta,1):Math.min(delta,-1);var button=delta>0?3:4;SDL.events.push({type:"mousedown",button:button,pageX:event.pageX,pageY:event.pageY});SDL.events.push({type:"mouseup",button:button,pageX:event.pageX,pageY:event.pageY});SDL.events.push({type:"wheel",deltaX:0,deltaY:delta});event.preventDefault();break;case"mousemove":if(SDL.DOMButtons[0]===1){SDL.events.push({type:"touchmove",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}})}if(Browser.pointerLock){if("mozMovementX"in event){event["movementX"]=event["mozMovementX"];event["movementY"]=event["mozMovementY"]}if(event["movementX"]==0&&event["movementY"]==0){event.preventDefault();return}}case"keydown":case"keyup":case"keypress":case"mousedown":case"mouseup":if(event.type!=="keydown"||!SDL.unicode&&!SDL.textInput||(event.keyCode===8||event.keyCode===9)){event.preventDefault()}if(event.type=="mousedown"){SDL.DOMButtons[event.button]=1;SDL.events.push({type:"touchstart",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}})}else if(event.type=="mouseup"){if(!SDL.DOMButtons[event.button]){return}SDL.events.push({type:"touchend",touch:{identifier:0,deviceID:-1,pageX:event.pageX,pageY:event.pageY}});SDL.DOMButtons[event.button]=0}if(event.type==="keydown"||event.type==="mousedown"){SDL.canRequestFullscreen=true}else if(event.type==="keyup"||event.type==="mouseup"){if(SDL.isRequestingFullscreen){Module["requestFullscreen"](true,true);SDL.isRequestingFullscreen=false}SDL.canRequestFullscreen=false}if(event.type==="keypress"&&SDL.savedKeydown){SDL.savedKeydown.keypressCharCode=event.charCode;SDL.savedKeydown=null}else if(event.type==="keydown"){SDL.savedKeydown=event}if(event.type!=="keypress"||SDL.textInput){SDL.events.push(event)}break;case"mouseout":for(var i=0;i<3;i++){if(SDL.DOMButtons[i]){SDL.events.push({type:"mouseup",button:i,pageX:event.pageX,pageY:event.pageY});SDL.DOMButtons[i]=0}}event.preventDefault();break;case"focus":SDL.events.push(event);event.preventDefault();break;case"blur":SDL.events.push(event);unpressAllPressedKeys();event.preventDefault();break;case"visibilitychange":SDL.events.push({type:"visibilitychange",visible:!document.hidden});unpressAllPressedKeys();event.preventDefault();break;case"unload":if(Browser.mainLoop.runner){SDL.events.push(event);Browser.mainLoop.runner()}return;case"resize":SDL.events.push(event);if(event.preventDefault){event.preventDefault()}break}if(SDL.events.length>=1e4){err("SDL event queue full, dropping events");SDL.events=SDL.events.slice(0,1e4)}SDL.flushEventsToHandler();return},lookupKeyCodeForEvent(event){var code=event.keyCode;if(code>=65&&code<=90){code+=32}else{code=SDL.keyCodes[event.keyCode]||event.keyCode;if(event.location===2&&code>=(224|1<<10)&&code<=(227|1<<10)){code+=4}}return code},handleEvent(event){if(event.handled)return;event.handled=true;switch(event.type){case"touchstart":case"touchend":case"touchmove":{Browser.calculateMouseEvent(event);break}case"keydown":case"keyup":{var down=event.type==="keydown";var code=SDL.lookupKeyCodeForEvent(event);HEAP8[SDL.keyboardState+code>>>0]=down;SDL.modState=(HEAP8[SDL.keyboardState+1248>>>0]?64:0)|(HEAP8[SDL.keyboardState+1249>>>0]?1:0)|(HEAP8[SDL.keyboardState+1250>>>0]?256:0)|(HEAP8[SDL.keyboardState+1252>>>0]?128:0)|(HEAP8[SDL.keyboardState+1253>>>0]?2:0)|(HEAP8[SDL.keyboardState+1254>>>0]?512:0);if(down){SDL.keyboardMap[code]=event.keyCode}else{delete SDL.keyboardMap[code]}break}case"mousedown":case"mouseup":if(event.type=="mousedown"){SDL.buttonState|=1<0){if(SDL.makeCEvent(SDL.events.shift(),ptr)!==false)return 1}return 0}return SDL.events.length>0},makeCEvent(event,ptr){if(typeof event=="number"){_memcpy(ptr,event,28);_free(event);return}SDL.handleEvent(event);switch(event.type){case"keydown":case"keyup":{var down=event.type==="keydown";var key=SDL.lookupKeyCodeForEvent(event);var scan;if(key>=1024){scan=key-1024}else{scan=SDL.scanCodes[key]||key}HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+8>>>0]=down?1:0;HEAP8[ptr+9>>>0]=0;HEAP32[ptr+12>>>2>>>0]=scan;HEAP32[ptr+16>>>2>>>0]=key;HEAP16[ptr+20>>>1>>>0]=SDL.modState;HEAP32[ptr+24>>>2>>>0]=event.keypressCharCode||key;break}case"keypress":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];var cStr=intArrayFromString(String.fromCharCode(event.charCode));for(var i=0;i>>0]=cStr[i]}break}case"mousedown":case"mouseup":case"mousemove":{if(event.type!="mousemove"){var down=event.type==="mousedown";HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP32[ptr+8>>>2>>>0]=0;HEAP32[ptr+12>>>2>>>0]=0;HEAP8[ptr+16>>>0]=event.button+1;HEAP8[ptr+17>>>0]=down?1:0;HEAP32[ptr+20>>>2>>>0]=Browser.mouseX;HEAP32[ptr+24>>>2>>>0]=Browser.mouseY}else{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP32[ptr+8>>>2>>>0]=0;HEAP32[ptr+12>>>2>>>0]=0;HEAP32[ptr+16>>>2>>>0]=SDL.buttonState;HEAP32[ptr+20>>>2>>>0]=Browser.mouseX;HEAP32[ptr+24>>>2>>>0]=Browser.mouseY;HEAP32[ptr+28>>>2>>>0]=Browser.mouseMovementX;HEAP32[ptr+32>>>2>>>0]=Browser.mouseMovementY}break}case"wheel":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+16>>>2>>>0]=event.deltaX;HEAP32[ptr+20>>>2>>>0]=event.deltaY;break}case"touchstart":case"touchend":case"touchmove":{var touch=event.touch;if(!Browser.touches[touch.identifier])break;var w=Module["canvas"].width;var h=Module["canvas"].height;var x=Browser.touches[touch.identifier].x/w;var y=Browser.touches[touch.identifier].y/h;var lx=Browser.lastTouches[touch.identifier].x/w;var ly=Browser.lastTouches[touch.identifier].y/h;var dx=x-lx;var dy=y-ly;if(touch["deviceID"]===undefined)touch.deviceID=SDL.TOUCH_DEFAULT_ID;if(dx===0&&dy===0&&event.type==="touchmove")return false;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=_SDL_GetTicks();HEAP64[ptr+8>>>3]=BigInt(touch.deviceID);HEAP64[ptr+16>>>3]=BigInt(touch.identifier);HEAPF32[ptr+24>>>2>>>0]=x;HEAPF32[ptr+28>>>2>>>0]=y;HEAPF32[ptr+32>>>2>>>0]=dx;HEAPF32[ptr+36>>>2>>>0]=dy;if(touch.force!==undefined){HEAPF32[ptr+40>>>2>>>0]=touch.force}else{HEAPF32[ptr+40>>>2>>>0]=event.type=="touchend"?0:1}break}case"unload":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];break}case"resize":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=event.w;HEAP32[ptr+8>>>2>>>0]=event.h;break}case"joystick_button_up":case"joystick_button_down":{var state=event.type==="joystick_button_up"?0:1;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+4>>>0]=event.index;HEAP8[ptr+5>>>0]=event.button;HEAP8[ptr+6>>>0]=state;break}case"joystick_axis_motion":{HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP8[ptr+4>>>0]=event.index;HEAP8[ptr+5>>>0]=event.axis;HEAP32[ptr+8>>>2>>>0]=SDL.joystickAxisValueConversion(event.value);break}case"focus":{var SDL_WINDOWEVENT_FOCUS_GAINED=12;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=SDL_WINDOWEVENT_FOCUS_GAINED;break}case"blur":{var SDL_WINDOWEVENT_FOCUS_LOST=13;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=SDL_WINDOWEVENT_FOCUS_LOST;break}case"visibilitychange":{var SDL_WINDOWEVENT_SHOWN=1;var SDL_WINDOWEVENT_HIDDEN=2;var visibilityEventID=event.visible?SDL_WINDOWEVENT_SHOWN:SDL_WINDOWEVENT_HIDDEN;HEAP32[ptr>>>2>>>0]=SDL.DOMEventToSDLEvent[event.type];HEAP32[ptr+4>>>2>>>0]=0;HEAP8[ptr+8>>>0]=visibilityEventID;break}default:throw"Unhandled SDL event: "+event.type}},makeFontString(height,fontName){if(fontName.charAt(0)!="'"&&fontName.charAt(0)!='"'){fontName='"'+fontName+'"'}return height+"px "+fontName+", serif"},estimateTextWidth(fontData,text){var h=fontData.size;var fontString=SDL.makeFontString(h,fontData.name);var tempCtx=SDL.ttfContext;tempCtx.font=fontString;var ret=tempCtx.measureText(text).width|0;return ret},allocateChannels(num){if(SDL.numChannels&&SDL.numChannels>=num&&num!=0)return;SDL.numChannels=num;SDL.channels=[];for(var i=0;i{if(!audio.paused)SDL.playWebAudio(audio)});return}audio.webAudioNode=SDL.audioContext["createBufferSource"]();audio.webAudioNode["buffer"]=webAudio.decodedBuffer;audio.webAudioNode["loop"]=audio.loop;audio.webAudioNode["onended"]=audio["onended"];audio.webAudioPannerNode=SDL.audioContext["createPanner"]();audio.webAudioPannerNode["setPosition"](0,0,-.5);audio.webAudioPannerNode["panningModel"]="equalpower";audio.webAudioGainNode=SDL.audioContext["createGain"]();audio.webAudioGainNode["gain"]["value"]=audio.volume;audio.webAudioNode["connect"](audio.webAudioPannerNode);audio.webAudioPannerNode["connect"](audio.webAudioGainNode);audio.webAudioGainNode["connect"](SDL.audioContext["destination"]);audio.webAudioNode["start"](0,audio.currentPosition);audio.startTime=SDL.audioContext["currentTime"]-audio.currentPosition}catch(e){err(`playWebAudio failed: ${e}`)}},pauseWebAudio(audio){if(!audio)return;if(audio.webAudioNode){try{audio.currentPosition=(SDL.audioContext["currentTime"]-audio.startTime)%audio.resource.webAudio.decodedBuffer.duration;audio.webAudioNode["onended"]=undefined;audio.webAudioNode.stop(0);audio.webAudioNode=undefined}catch(e){err(`pauseWebAudio failed: ${e}`)}}audio.paused=true},openAudioContext(){if(!SDL.audioContext){if(typeof AudioContext!="undefined")SDL.audioContext=new AudioContext;else if(typeof webkitAudioContext!="undefined")SDL.audioContext=new webkitAudioContext}},webAudioAvailable:()=>!!SDL.audioContext,fillWebAudioBufferFromHeap(heapPtr,sizeSamplesPerChannel,dstAudioBuffer){var audio=SDL.audio;var numChannels=audio.channels;for(var c=0;c>>1>>>0]/32768}}else if(audio.format==8){for(var j=0;j>>0];channelData[j]=(v>=0?v-128:v+128)/128}}else if(audio.format==33056){for(var j=0;j>>2>>>0]}}else{throw"Invalid SDL audio format "+audio.format+"!"}}},joystickEventState:1,lastJoystickState:{},joystickNamePool:{},recordJoystickState(joystick,state){var buttons=new Array(state.buttons.length);for(var i=0;i0},queryJoysticks(){for(var joystick in SDL.lastJoystickState){var state=SDL.getGamepad(joystick-1);var prevState=SDL.lastJoystickState[joystick];if(typeof state=="undefined")return;if(state===null)return;if(typeof state.timestamp!="number"||state.timestamp!=prevState.timestamp||!state.timestamp){var i;for(i=0;ideviceIndex&&deviceIndex>=0){return gamepads[deviceIndex]}return null}};Module["SDL"]=SDL;function _SDL_Linked_Version(){if(SDL.version===null){SDL.version=_malloc(3);HEAP8[SDL.version+0>>>0]=1;HEAP8[SDL.version+1>>>0]=3;HEAP8[SDL.version+2>>>0]=0}return SDL.version}Module["_SDL_Linked_Version"]=_SDL_Linked_Version;_SDL_Linked_Version.sig="p";var _SDL_Init=initFlags=>{SDL.startTime=Date.now();SDL.initFlags=initFlags;if(!Module["doNotCaptureKeyboard"]){var keyboardListeningElement=Module["keyboardListeningElement"]||document;keyboardListeningElement.addEventListener("keydown",SDL.receiveEvent);keyboardListeningElement.addEventListener("keyup",SDL.receiveEvent);keyboardListeningElement.addEventListener("keypress",SDL.receiveEvent);window.addEventListener("focus",SDL.receiveEvent);window.addEventListener("blur",SDL.receiveEvent);document.addEventListener("visibilitychange",SDL.receiveEvent)}window.addEventListener("unload",SDL.receiveEvent);SDL.keyboardState=_malloc(65536);zeroMemory(SDL.keyboardState,65536);SDL.DOMEventToSDLEvent["keydown"]=768;SDL.DOMEventToSDLEvent["keyup"]=769;SDL.DOMEventToSDLEvent["keypress"]=771;SDL.DOMEventToSDLEvent["mousedown"]=1025;SDL.DOMEventToSDLEvent["mouseup"]=1026;SDL.DOMEventToSDLEvent["mousemove"]=1024;SDL.DOMEventToSDLEvent["wheel"]=1027;SDL.DOMEventToSDLEvent["touchstart"]=1792;SDL.DOMEventToSDLEvent["touchend"]=1793;SDL.DOMEventToSDLEvent["touchmove"]=1794;SDL.DOMEventToSDLEvent["unload"]=256;SDL.DOMEventToSDLEvent["resize"]=28673;SDL.DOMEventToSDLEvent["visibilitychange"]=512;SDL.DOMEventToSDLEvent["focus"]=512;SDL.DOMEventToSDLEvent["blur"]=512;SDL.DOMEventToSDLEvent["joystick_axis_motion"]=1536;SDL.DOMEventToSDLEvent["joystick_button_down"]=1539;SDL.DOMEventToSDLEvent["joystick_button_up"]=1540;return 0};Module["_SDL_Init"]=_SDL_Init;_SDL_Init.sig="ii";var _SDL_WasInit=flags=>{if(SDL.startTime===null){_SDL_Init(0)}return 1};Module["_SDL_WasInit"]=_SDL_WasInit;_SDL_WasInit.sig="ii";function _SDL_GetVideoInfo(){var ret=_malloc(20);zeroMemory(ret,3);HEAP32[ret+12>>>2>>>0]=Module["canvas"].width;HEAP32[ret+16>>>2>>>0]=Module["canvas"].height;return ret}Module["_SDL_GetVideoInfo"]=_SDL_GetVideoInfo;_SDL_GetVideoInfo.sig="p";function _SDL_ListModes(format,flags){format>>>=0;return-1}Module["_SDL_ListModes"]=_SDL_ListModes;_SDL_ListModes.sig="ppi";var _SDL_VideoModeOK=(width,height,depth,flags)=>depth;Module["_SDL_VideoModeOK"]=_SDL_VideoModeOK;_SDL_VideoModeOK.sig="iiiii";function _SDL_VideoDriverName(buf,max_size){buf>>>=0;if(SDL.startTime===null){return 0}var driverName=[101,109,115,99,114,105,112,116,101,110,95,115,100,108,95,100,114,105,118,101,114];var index=0;var size=driverName.length;if(max_size<=size){size=max_size-1}while(index>>0]=value;index++}HEAP8[buf+index>>>0]=0;return buf}Module["_SDL_VideoDriverName"]=_SDL_VideoDriverName;_SDL_VideoDriverName.sig="ppi";var _SDL_AudioDriverName=_SDL_VideoDriverName;Module["_SDL_AudioDriverName"]=_SDL_AudioDriverName;_SDL_AudioDriverName.sig="ppi";var _SDL_SetVideoMode=function(width,height,depth,flags){["touchstart","touchend","touchmove","mousedown","mouseup","mousemove","mousewheel","wheel","mouseout","DOMMouseScroll"].forEach(e=>Module["canvas"].addEventListener(e,SDL.receiveEvent,true));var canvas=Module["canvas"];if(width==0&&height==0){width=canvas.width;height=canvas.height}if(!SDL.addedResizeListener){SDL.addedResizeListener=true;Browser.resizeListeners.push((w,h)=>{if(!SDL.settingVideoMode){SDL.receiveEvent({type:"resize",w:w,h:h})}})}SDL.settingVideoMode=true;Browser.setCanvasSize(width,height);SDL.settingVideoMode=false;if(SDL.screen){SDL.freeSurface(SDL.screen);assert(!SDL.screen)}if(SDL.GL)flags=flags|67108864;SDL.screen=SDL.makeSurface(width,height,flags,true,"screen");return SDL.screen};Module["_SDL_SetVideoMode"]=_SDL_SetVideoMode;_SDL_SetVideoMode.sig="piiii";function _SDL_GetVideoSurface(){return SDL.screen}Module["_SDL_GetVideoSurface"]=_SDL_GetVideoSurface;_SDL_GetVideoSurface.sig="p";var _SDL_AudioQuit=()=>{for(var i=0;iout("SDL_VideoQuit called (and ignored)");Module["_SDL_VideoQuit"]=_SDL_VideoQuit;_SDL_VideoQuit.sig="v";var _SDL_QuitSubSystem=flags=>out("SDL_QuitSubSystem called (and ignored)");Module["_SDL_QuitSubSystem"]=_SDL_QuitSubSystem;_SDL_QuitSubSystem.sig="vi";var _SDL_Quit=()=>{_SDL_AudioQuit();out("SDL_Quit called (and ignored)")};Module["_SDL_Quit"]=_SDL_Quit;_SDL_Quit.sig="v";function _SDL_UnlockSurface(surf){surf>>>=0;assert(!SDL.GL);var surfData=SDL.surfaces[surf];if(!surfData.locked||--surfData.locked>0){return}if(surfData.isFlagSet(2097152)){SDL.copyIndexedColorData(surfData)}else if(!surfData.colors){var data=surfData.image.data;var buffer=surfData.buffer;assert(buffer%4==0,"Invalid buffer offset: "+buffer);var src=buffer>>>2;var dst=0;var isScreen=surf==SDL.screen;var num;if(typeof CanvasPixelArray!="undefined"&&data instanceof CanvasPixelArray){num=data.length;while(dst>>0];data[dst]=val&255;data[dst+1]=val>>8&255;data[dst+2]=val>>16&255;data[dst+3]=isScreen?255:val>>24&255;src++;dst+=4}}else{var data32=new Uint32Array(data.buffer);if(isScreen&&SDL.defaults.opaqueFrontBuffer){num=data32.length;data32.set(HEAP32.subarray(src>>>0,src+num>>>0));var data8=new Uint8Array(data.buffer);var i=3;var j=i+4*num;if(num%8==0){while(i>>0,src+data32.length>>>0))}}}else{var width=Module["canvas"].width;var height=Module["canvas"].height;var s=surfData.buffer;var data=surfData.image.data;var colors=surfData.colors;for(var y=0;y>>0]*4;var start=base+x*4;data[start]=colors[val];data[start+1]=colors[val+1];data[start+2]=colors[val+2]}s+=width*3}}surfData.ctx.putImageData(surfData.image,0,0)}Module["_SDL_UnlockSurface"]=_SDL_UnlockSurface;_SDL_UnlockSurface.sig="vp";function _SDL_Flip(surf){surf>>>=0}Module["_SDL_Flip"]=_SDL_Flip;_SDL_Flip.sig="ip";function _SDL_UpdateRect(surf,x,y,w,h){surf>>>=0}Module["_SDL_UpdateRect"]=_SDL_UpdateRect;_SDL_UpdateRect.sig="vpiiii";function _SDL_UpdateRects(surf,numrects,rects){surf>>>=0;rects>>>=0}Module["_SDL_UpdateRects"]=_SDL_UpdateRects;_SDL_UpdateRects.sig="vpip";var _SDL_Delay=delay=>{if(!ENVIRONMENT_IS_WORKER)abort("SDL_Delay called on the main thread! Potential infinite loop, quitting. (consider building with async support like ASYNCIFY)");var now=Date.now();while(Date.now()-now>>=0;icon>>>=0;if(title){_emscripten_set_window_title(title)}icon&&=UTF8ToString(icon)}Module["_SDL_WM_SetCaption"]=_SDL_WM_SetCaption;_SDL_WM_SetCaption.sig="vpp";var _SDL_EnableKeyRepeat=(delay,interval)=>{};Module["_SDL_EnableKeyRepeat"]=_SDL_EnableKeyRepeat;_SDL_EnableKeyRepeat.sig="iii";function _SDL_GetKeyboardState(numKeys){numKeys>>>=0;if(numKeys){HEAP32[numKeys>>>2>>>0]=65536}return SDL.keyboardState}Module["_SDL_GetKeyboardState"]=_SDL_GetKeyboardState;_SDL_GetKeyboardState.sig="pp";var _SDL_GetKeyState=()=>_SDL_GetKeyboardState(0);Module["_SDL_GetKeyState"]=_SDL_GetKeyState;function _SDL_GetKeyName(key){SDL.keyName||=stringToNewUTF8("unknown key");return SDL.keyName}Module["_SDL_GetKeyName"]=_SDL_GetKeyName;_SDL_GetKeyName.sig="pi";var _SDL_GetModState=()=>SDL.modState;Module["_SDL_GetModState"]=_SDL_GetModState;_SDL_GetModState.sig="i";function _SDL_GetMouseState(x,y){x>>>=0;y>>>=0;if(x)HEAP32[x>>>2>>>0]=Browser.mouseX;if(y)HEAP32[y>>>2>>>0]=Browser.mouseY;return SDL.buttonState}Module["_SDL_GetMouseState"]=_SDL_GetMouseState;_SDL_GetMouseState.sig="ipp";var _SDL_WarpMouse=(x,y)=>{};Module["_SDL_WarpMouse"]=_SDL_WarpMouse;_SDL_WarpMouse.sig="vii";var _SDL_ShowCursor=toggle=>{switch(toggle){case 0:if(Browser.isFullscreen){Module["canvas"].requestPointerLock();return 0}return 1;case 1:Module["canvas"].exitPointerLock();return 1;case-1:return!Browser.pointerLock;default:err(`SDL_ShowCursor called with unknown toggle parameter value: ${toggle}`);break}};Module["_SDL_ShowCursor"]=_SDL_ShowCursor;_SDL_ShowCursor.sig="ii";function _SDL_GetError(){SDL.errorMessage||=stringToNewUTF8("unknown SDL-emscripten error");return SDL.errorMessage}Module["_SDL_GetError"]=_SDL_GetError;_SDL_GetError.sig="p";function _SDL_SetError(fmt,varargs){fmt>>>=0;varargs>>>=0}Module["_SDL_SetError"]=_SDL_SetError;_SDL_SetError.sig="vpp";function _SDL_CreateRGBSurface(flags,width,height,depth,rmask,gmask,bmask,amask){return SDL.makeSurface(width,height,flags,false,"CreateRGBSurface",rmask,gmask,bmask,amask)}Module["_SDL_CreateRGBSurface"]=_SDL_CreateRGBSurface;_SDL_CreateRGBSurface.sig="piiiiiiii";function _SDL_CreateRGBSurfaceFrom(pixels,width,height,depth,pitch,rmask,gmask,bmask,amask){pixels>>>=0;var surf=SDL.makeSurface(width,height,0,false,"CreateRGBSurfaceFrom",rmask,gmask,bmask,amask);if(depth!==32){err("TODO: Partially unimplemented SDL_CreateRGBSurfaceFrom called!");return surf}var data=SDL.surfaces[surf];var image=data.ctx.createImageData(width,height);var pitchOfDst=width*4;for(var row=0;row>>0]}}data.ctx.putImageData(image,0,0);return surf}Module["_SDL_CreateRGBSurfaceFrom"]=_SDL_CreateRGBSurfaceFrom;_SDL_CreateRGBSurfaceFrom.sig="ppiiiiiiii";function _SDL_ConvertSurface(surf,format,flags){surf>>>=0;format>>>=0;if(format){SDL.checkPixelFormat(format)}var oldData=SDL.surfaces[surf];var ret=SDL.makeSurface(oldData.width,oldData.height,oldData.flags,false,"copy:"+oldData.source);var newData=SDL.surfaces[ret];newData.ctx.globalCompositeOperation="copy";newData.ctx.drawImage(oldData.canvas,0,0);newData.ctx.globalCompositeOperation=oldData.ctx.globalCompositeOperation;return ret}Module["_SDL_ConvertSurface"]=_SDL_ConvertSurface;_SDL_ConvertSurface.sig="pppi";function _SDL_DisplayFormatAlpha(surf){surf>>>=0;return _SDL_ConvertSurface(surf,0,0)}Module["_SDL_DisplayFormatAlpha"]=_SDL_DisplayFormatAlpha;_SDL_DisplayFormatAlpha.sig="pp";function _SDL_FreeSurface(surf){surf>>>=0;if(surf)SDL.freeSurface(surf)}Module["_SDL_FreeSurface"]=_SDL_FreeSurface;_SDL_FreeSurface.sig="vp";function _SDL_UpperBlit(src,srcrect,dst,dstrect){src>>>=0;srcrect>>>=0;dst>>>=0;dstrect>>>=0;return SDL.blitSurface(src,srcrect,dst,dstrect,false)}Module["_SDL_UpperBlit"]=_SDL_UpperBlit;_SDL_UpperBlit.sig="ipppp";function _SDL_UpperBlitScaled(src,srcrect,dst,dstrect){src>>>=0;srcrect>>>=0;dst>>>=0;dstrect>>>=0;return SDL.blitSurface(src,srcrect,dst,dstrect,true)}Module["_SDL_UpperBlitScaled"]=_SDL_UpperBlitScaled;_SDL_UpperBlitScaled.sig="ipppp";var _SDL_LowerBlit=_SDL_UpperBlit;Module["_SDL_LowerBlit"]=_SDL_LowerBlit;_SDL_LowerBlit.sig="ipppp";var _SDL_LowerBlitScaled=_SDL_UpperBlitScaled;Module["_SDL_LowerBlitScaled"]=_SDL_LowerBlitScaled;_SDL_LowerBlitScaled.sig="ipppp";function _SDL_GetClipRect(surf,rect){surf>>>=0;rect>>>=0;assert(rect);var surfData=SDL.surfaces[surf];var r=surfData.clipRect||{x:0,y:0,w:surfData.width,h:surfData.height};SDL.updateRect(rect,r)}Module["_SDL_GetClipRect"]=_SDL_GetClipRect;_SDL_GetClipRect.sig="vpp";function _SDL_SetClipRect(surf,rect){surf>>>=0;rect>>>=0;var surfData=SDL.surfaces[surf];if(rect){surfData.clipRect=SDL.intersectionOfRects({x:0,y:0,w:surfData.width,h:surfData.height},SDL.loadRect(rect))}else{delete surfData.clipRect}}Module["_SDL_SetClipRect"]=_SDL_SetClipRect;_SDL_SetClipRect.sig="ipp";function _SDL_FillRect(surf,rect,color){surf>>>=0;rect>>>=0;var surfData=SDL.surfaces[surf];assert(!surfData.locked);if(surfData.isFlagSet(2097152)){color=surfData.colors32[color]}var r=rect?SDL.loadRect(rect):{x:0,y:0,w:surfData.width,h:surfData.height};if(surfData.clipRect){r=SDL.intersectionOfRects(surfData.clipRect,r);if(rect){SDL.updateRect(rect,r)}}surfData.ctx.save();surfData.ctx.fillStyle=SDL.translateColorToCSSRGBA(color);surfData.ctx.fillRect(r.x,r.y,r.w,r.h);surfData.ctx.restore();return 0}Module["_SDL_FillRect"]=_SDL_FillRect;_SDL_FillRect.sig="ippi";function _zoomSurface(src,x,y,smooth){src>>>=0;var srcData=SDL.surfaces[src];var w=srcData.width*x;var h=srcData.height*y;var ret=SDL.makeSurface(Math.abs(w),Math.abs(h),srcData.flags,false,"zoomSurface");var dstData=SDL.surfaces[ret];if(x>=0&&y>=0)dstData.ctx.drawImage(srcData.canvas,0,0,w,h);else{dstData.ctx.save();dstData.ctx.scale(x<0?-1:1,y<0?-1:1);dstData.ctx.drawImage(srcData.canvas,w<0?w:0,h<0?h:0,Math.abs(w),Math.abs(h));dstData.ctx.restore()}return ret}Module["_zoomSurface"]=_zoomSurface;_zoomSurface.sig="ppddi";function _rotozoomSurface(src,angle,zoom,smooth){src>>>=0;if(angle%360===0){return _zoomSurface(src,zoom,zoom,smooth)}var srcData=SDL.surfaces[src];var w=srcData.width*zoom;var h=srcData.height*zoom;var diagonal=Math.ceil(Math.sqrt(Math.pow(w,2)+Math.pow(h,2)));var ret=SDL.makeSurface(diagonal,diagonal,srcData.flags,false,"rotozoomSurface");var dstData=SDL.surfaces[ret];dstData.ctx.translate(diagonal/2,diagonal/2);dstData.ctx.rotate(-angle*Math.PI/180);dstData.ctx.drawImage(srcData.canvas,-w/2,-h/2,w,h);return ret}Module["_rotozoomSurface"]=_rotozoomSurface;_rotozoomSurface.sig="ppddi";function _SDL_SetAlpha(surf,flag,alpha){surf>>>=0;var surfData=SDL.surfaces[surf];surfData.alpha=alpha;if(!(flag&65536)){surfData.alpha=255}}Module["_SDL_SetAlpha"]=_SDL_SetAlpha;_SDL_SetAlpha.sig="ipii";function _SDL_SetColorKey(surf,flag,key){surf>>>=0;warnOnce("SDL_SetColorKey is a no-op for performance reasons");return 0}Module["_SDL_SetColorKey"]=_SDL_SetColorKey;_SDL_SetColorKey.sig="ipii";function _SDL_PollEvent(ptr){ptr>>>=0;return SDL.pollEvent(ptr)}Module["_SDL_PollEvent"]=_SDL_PollEvent;_SDL_PollEvent.sig="ip";function _SDL_PushEvent(ptr){ptr>>>=0;var copy=_malloc(28);_memcpy(copy,ptr,28);SDL.events.push(copy);return 0}Module["_SDL_PushEvent"]=_SDL_PushEvent;_SDL_PushEvent.sig="ip";function _SDL_PeepEvents(events,requestedEventCount,action,from,to){events>>>=0;switch(action){case 2:{assert(requestedEventCount==1);var index=0;var retrievedEventCount=0;while(indexSDL.events.forEach(SDL.handleEvent);Module["_SDL_PumpEvents"]=_SDL_PumpEvents;_SDL_PumpEvents.sig="v";function _emscripten_SDL_SetEventHandler(handler,userdata){handler>>>=0;userdata>>>=0;SDL.eventHandler=handler;SDL.eventHandlerContext=userdata;if(!SDL.eventHandlerTemp)SDL.eventHandlerTemp=_malloc(28)}Module["_emscripten_SDL_SetEventHandler"]=_emscripten_SDL_SetEventHandler;_emscripten_SDL_SetEventHandler.sig="vpp";function _SDL_SetColors(surf,colors,firstColor,nColors){surf>>>=0;colors>>>=0;var surfData=SDL.surfaces[surf];if(!surfData.colors){var buffer=new ArrayBuffer(256*4);surfData.colors=new Uint8Array(buffer);surfData.colors32=new Uint32Array(buffer)}for(var i=0;i>>0];surfData.colors[index+1]=HEAPU8[colors+(i*4+1)>>>0];surfData.colors[index+2]=HEAPU8[colors+(i*4+2)>>>0];surfData.colors[index+3]=255}return 1}Module["_SDL_SetColors"]=_SDL_SetColors;_SDL_SetColors.sig="ippii";function _SDL_SetPalette(surf,flags,colors,firstColor,nColors){surf>>>=0;colors>>>=0;return _SDL_SetColors(surf,colors,firstColor,nColors)}Module["_SDL_SetPalette"]=_SDL_SetPalette;_SDL_SetPalette.sig="ipipii";function _SDL_MapRGB(fmt,r,g,b){fmt>>>=0;SDL.checkPixelFormat(fmt);return r&255|(g&255)<<8|(b&255)<<16|4278190080}Module["_SDL_MapRGB"]=_SDL_MapRGB;_SDL_MapRGB.sig="ipiii";function _SDL_MapRGBA(fmt,r,g,b,a){fmt>>>=0;SDL.checkPixelFormat(fmt);return r&255|(g&255)<<8|(b&255)<<16|(a&255)<<24}Module["_SDL_MapRGBA"]=_SDL_MapRGBA;_SDL_MapRGBA.sig="ipiiii";function _SDL_GetRGB(pixel,fmt,r,g,b){fmt>>>=0;r>>>=0;g>>>=0;b>>>=0;SDL.checkPixelFormat(fmt);if(r){HEAP8[r>>>0]=pixel&255}if(g){HEAP8[g>>>0]=pixel>>8&255}if(b){HEAP8[b>>>0]=pixel>>16&255}}Module["_SDL_GetRGB"]=_SDL_GetRGB;_SDL_GetRGB.sig="vipppp";function _SDL_GetRGBA(pixel,fmt,r,g,b,a){fmt>>>=0;r>>>=0;g>>>=0;b>>>=0;a>>>=0;SDL.checkPixelFormat(fmt);if(r){HEAP8[r>>>0]=pixel&255}if(g){HEAP8[g>>>0]=pixel>>8&255}if(b){HEAP8[b>>>0]=pixel>>16&255}if(a){HEAP8[a>>>0]=pixel>>24&255}}Module["_SDL_GetRGBA"]=_SDL_GetRGBA;_SDL_GetRGBA.sig="vippppp";var _SDL_GetAppState=()=>{var state=0;if(Browser.pointerLock){state|=1}if(document.hasFocus()){state|=2}state|=4;return state};Module["_SDL_GetAppState"]=_SDL_GetAppState;_SDL_GetAppState.sig="i";var _SDL_WM_GrabInput=()=>{};Module["_SDL_WM_GrabInput"]=_SDL_WM_GrabInput;_SDL_WM_GrabInput.sig="ii";function _SDL_WM_ToggleFullScreen(surf){surf>>>=0;if(Browser.exitFullscreen()){return 1}if(!SDL.canRequestFullscreen){return 0}SDL.isRequestingFullscreen=true;return 1}Module["_SDL_WM_ToggleFullScreen"]=_SDL_WM_ToggleFullScreen;_SDL_WM_ToggleFullScreen.sig="ip";var _IMG_Init=flags=>flags;Module["_IMG_Init"]=_IMG_Init;_IMG_Init.sig="ii";function _SDL_FreeRW(rwopsID){rwopsID>>>=0;SDL.rwops[rwopsID]=null;while(SDL.rwops.length>0&&SDL.rwops[SDL.rwops.length-1]===null){SDL.rwops.pop()}}Module["_SDL_FreeRW"]=_SDL_FreeRW;_SDL_FreeRW.sig="vp";var _IMG_Load_RW=function(rwopsID,freeSrc){rwopsID>>>=0;var sp=stackSave();try{var cleanup=()=>{stackRestore(sp);if(rwops&&freeSrc)_SDL_FreeRW(rwopsID)};var addCleanup=func=>{var old=cleanup;cleanup=()=>{old();func()}};var callStbImage=(func,params)=>{var x=stackAlloc(4);var y=stackAlloc(4);var comp=stackAlloc(4);var data=Module["_"+func](...params,x,y,comp,0);if(!data)return null;addCleanup(()=>Module["_stbi_image_free"](data));return{rawData:true,data:data,width:HEAP32[x>>>2>>>0],height:HEAP32[y>>>2>>>0],size:HEAP32[x>>>2>>>0]*HEAP32[y>>>2>>>0]*HEAP32[comp>>>2>>>0],bpp:HEAP32[comp>>>2>>>0]}};var rwops=SDL.rwops[rwopsID];if(rwops===undefined){return 0}var raw;var filename=rwops.filename;if(filename===undefined){warnOnce("Only file names that have been preloaded are supported for IMG_Load_RW. Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js), or package files with --use-preload-plugins");return 0}if(!raw){filename=PATH_FS.resolve(filename);raw=preloadedImages[filename];if(!raw){if(raw===null)err("Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!");warnOnce("Cannot find preloaded image "+filename);warnOnce("Cannot find preloaded image "+filename+". Consider using STB_IMAGE=1 if you want synchronous image decoding (see settings.js), or package files with --use-preload-plugins");return 0}else if(Module["freePreloadedMediaOnUse"]){preloadedImages[filename]=null}}var surf=SDL.makeSurface(raw.width,raw.height,0,false,"load:"+filename);var surfData=SDL.surfaces[surf];surfData.ctx.globalCompositeOperation="copy";if(!raw.rawData){surfData.ctx.drawImage(raw,0,0,raw.width,raw.height,0,0,raw.width,raw.height)}else{var imageData=surfData.ctx.getImageData(0,0,surfData.width,surfData.height);if(raw.bpp==4){imageData.data.set(HEAPU8.subarray(raw.data>>>0,raw.data+raw.size>>>0))}else if(raw.bpp==3){var pixels=raw.size/3;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];data[destPtr++]=HEAPU8[sourcePtr++>>>0];data[destPtr++]=HEAPU8[sourcePtr++>>>0];data[destPtr++]=255}}else if(raw.bpp==2){var pixels=raw.size;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];var alpha=HEAPU8[sourcePtr++>>>0];data[destPtr++]=gray;data[destPtr++]=gray;data[destPtr++]=gray;data[destPtr++]=alpha}}else if(raw.bpp==1){var pixels=raw.size;var data=imageData.data;var sourcePtr=raw.data;var destPtr=0;for(var i=0;i>>0];data[destPtr++]=value;data[destPtr++]=value;data[destPtr++]=value;data[destPtr++]=255}}else{err(`cannot handle bpp ${raw.bpp}`);return 0}surfData.ctx.putImageData(imageData,0,0)}surfData.ctx.globalCompositeOperation="source-over";_SDL_LockSurface(surf);surfData.locked--;if(SDL.GL){surfData.canvas=surfData.ctx=null}return surf}finally{cleanup()}};Module["_IMG_Load_RW"]=_IMG_Load_RW;_IMG_Load_RW.sig="ppi";var _SDL_LoadBMP_RW=_IMG_Load_RW;Module["_SDL_LoadBMP_RW"]=_SDL_LoadBMP_RW;_SDL_LoadBMP_RW.sig="ppi";function _SDL_RWFromFile(_name,mode){_name>>>=0;mode>>>=0;var id=SDL.rwops.length;var filename=UTF8ToString(_name);SDL.rwops.push({filename:filename,mimetype:Browser.getMimetype(filename)});return id}Module["_SDL_RWFromFile"]=_SDL_RWFromFile;_SDL_RWFromFile.sig="ppp";function _IMG_Load(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_IMG_Load_RW(rwops,1);return result}Module["_IMG_Load"]=_IMG_Load;_IMG_Load.sig="pp";var _IMG_Quit=()=>out("IMG_Quit called (and ignored)");Module["_IMG_Quit"]=_IMG_Quit;_IMG_Quit.sig="v";function _SDL_OpenAudio(desired,obtained){desired>>>=0;obtained>>>=0;try{SDL.audio={freq:HEAPU32[desired>>>2>>>0],format:HEAPU16[desired+4>>>1>>>0],channels:HEAPU8[desired+6>>>0],samples:HEAPU16[desired+8>>>1>>>0],callback:HEAPU32[desired+16>>>2>>>0],userdata:HEAPU32[desired+20>>>2>>>0],paused:true,timer:null};if(SDL.audio.format==8){SDL.audio.silence=128}else if(SDL.audio.format==32784){SDL.audio.silence=0}else if(SDL.audio.format==33056){SDL.audio.silence=0}else{throw"Invalid SDL audio format "+SDL.audio.format+"!"}if(SDL.audio.freq<=0){throw"Unsupported sound frequency "+SDL.audio.freq+"!"}else if(SDL.audio.freq<=22050){SDL.audio.freq=22050}else if(SDL.audio.freq<=32e3){SDL.audio.freq=32e3}else if(SDL.audio.freq<=44100){SDL.audio.freq=44100}else if(SDL.audio.freq<=48e3){SDL.audio.freq=48e3}else if(SDL.audio.freq<=96e3){SDL.audio.freq=96e3}else{throw`Unsupported sound frequency ${SDL.audio.freq}!`}if(SDL.audio.channels==0){SDL.audio.channels=1}else if(SDL.audio.channels<0||SDL.audio.channels>32){throw`Unsupported number of audio channels for SDL audio: ${SDL.audio.channels}!`}else if(SDL.audio.channels!=1&&SDL.audio.channels!=2){out(`Warning: Using untested number of audio channels ${SDL.audio.channels}`)}if(SDL.audio.samples<128||SDL.audio.samples>524288){throw`Unsupported audio callback buffer size ${SDL.audio.samples}!`}else if((SDL.audio.samples&SDL.audio.samples-1)!=0){throw`Audio callback buffer size ${SDL.audio.samples} must be a power-of-two!`}var totalSamples=SDL.audio.samples*SDL.audio.channels;if(SDL.audio.format==8){SDL.audio.bytesPerSample=1}else if(SDL.audio.format==32784){SDL.audio.bytesPerSample=2}else if(SDL.audio.format==33056){SDL.audio.bytesPerSample=4}else{throw`Invalid SDL audio format ${SDL.audio.format}!`}SDL.audio.bufferSize=totalSamples*SDL.audio.bytesPerSample;SDL.audio.bufferDurationSecs=SDL.audio.bufferSize/SDL.audio.bytesPerSample/SDL.audio.channels/SDL.audio.freq;SDL.audio.bufferingDelay=50/1e3;SDL.audio.buffer=_malloc(SDL.audio.bufferSize);SDL.audio.numSimultaneouslyQueuedBuffers=Module["SDL_numSimultaneouslyQueuedBuffers"]||5;SDL.audio.queueNewAudioData=()=>{if(!SDL.audio)return;for(var i=0;i=SDL.audio.bufferingDelay+SDL.audio.bufferDurationSecs*SDL.audio.numSimultaneouslyQueuedBuffers)return;getWasmTableEntry(SDL.audio.callback)(SDL.audio.userdata,SDL.audio.buffer,SDL.audio.bufferSize);SDL.audio.pushAudio(SDL.audio.buffer,SDL.audio.bufferSize)}};SDL.audio.caller=()=>{if(!SDL.audio)return;--SDL.audio.numAudioTimersPending;SDL.audio.queueNewAudioData();var secsUntilNextPlayStart=SDL.audio.nextPlayTime-SDL.audioContext["currentTime"];var preemptBufferFeedSecs=SDL.audio.bufferDurationSecs/2;if(SDL.audio.numAudioTimersPending{try{if(SDL.audio.paused)return;var sizeSamples=sizeBytes/SDL.audio.bytesPerSample;var sizeSamplesPerChannel=sizeSamples/SDL.audio.channels;if(sizeSamplesPerChannel!=SDL.audio.samples){throw"Received mismatching audio buffer size!"}var source=SDL.audioContext["createBufferSource"]();var soundBuffer=SDL.audioContext["createBuffer"](SDL.audio.channels,sizeSamplesPerChannel,SDL.audio.freq);source["connect"](SDL.audioContext["destination"]);SDL.fillWebAudioBufferFromHeap(ptr,sizeSamplesPerChannel,soundBuffer);source["buffer"]=soundBuffer;var curtime=SDL.audioContext["currentTime"];var playtime=Math.max(curtime+SDL.audio.bufferingDelay,SDL.audio.nextPlayTime);if(typeof source["start"]!="undefined"){source["start"](playtime)}else if(typeof source["noteOn"]!="undefined"){source["noteOn"](playtime)}SDL.audio.nextPlayTime=playtime+SDL.audio.bufferDurationSecs}catch(e){err(`Web Audio API error playing back audio: ${e.toString()}`)}};if(obtained){HEAP32[obtained>>>2>>>0]=SDL.audio.freq;HEAP16[obtained+4>>>1>>>0]=SDL.audio.format;HEAP8[obtained+6>>>0]=SDL.audio.channels;HEAP8[obtained+7>>>0]=SDL.audio.silence;HEAP16[obtained+8>>>1>>>0]=SDL.audio.samples;HEAPU32[obtained+16>>>2>>>0]=SDL.audio.callback;HEAPU32[obtained+20>>>2>>>0]=SDL.audio.userdata}SDL.allocateChannels(32)}catch(e){err(`Initializing SDL audio threw an exception: "${e.toString()}"! Continuing without audio`);SDL.audio=null;SDL.allocateChannels(0);if(obtained){HEAP32[obtained>>>2>>>0]=0;HEAP16[obtained+4>>>1>>>0]=0;HEAP8[obtained+6>>>0]=0;HEAP8[obtained+7>>>0]=0;HEAP16[obtained+8>>>1>>>0]=0;HEAPU32[obtained+16>>>2>>>0]=0;HEAPU32[obtained+20>>>2>>>0]=0}}if(!SDL.audio){return-1}return 0}Module["_SDL_OpenAudio"]=_SDL_OpenAudio;_SDL_OpenAudio.sig="ipp";var _SDL_PauseAudio=pauseOn=>{if(!SDL.audio){return}if(pauseOn){if(SDL.audio.timer!==undefined){clearTimeout(SDL.audio.timer);SDL.audio.numAudioTimersPending=0;SDL.audio.timer=undefined}}else if(!SDL.audio.timer){SDL.audio.numAudioTimersPending=1;SDL.audio.timer=safeSetTimeout(SDL.audio.caller,1)}SDL.audio.paused=pauseOn};Module["_SDL_PauseAudio"]=_SDL_PauseAudio;_SDL_PauseAudio.sig="vi";var _SDL_CloseAudio=()=>{if(SDL.audio){if(SDL.audio.callbackRemover){SDL.audio.callbackRemover();SDL.audio.callbackRemover=null}_SDL_PauseAudio(1);_free(SDL.audio.buffer);SDL.audio=null;SDL.allocateChannels(0)}};Module["_SDL_CloseAudio"]=_SDL_CloseAudio;_SDL_CloseAudio.sig="v";var _SDL_LockAudio=()=>{};Module["_SDL_LockAudio"]=_SDL_LockAudio;_SDL_LockAudio.sig="v";var _SDL_UnlockAudio=()=>{};Module["_SDL_UnlockAudio"]=_SDL_UnlockAudio;_SDL_UnlockAudio.sig="v";function _SDL_CreateMutex(){return 0}Module["_SDL_CreateMutex"]=_SDL_CreateMutex;_SDL_CreateMutex.sig="p";function _SDL_mutexP(mutex){mutex>>>=0;return 0}Module["_SDL_mutexP"]=_SDL_mutexP;_SDL_mutexP.sig="ip";function _SDL_mutexV(mutex){mutex>>>=0;return 0}Module["_SDL_mutexV"]=_SDL_mutexV;_SDL_mutexV.sig="ip";function _SDL_DestroyMutex(mutex){mutex>>>=0}Module["_SDL_DestroyMutex"]=_SDL_DestroyMutex;_SDL_DestroyMutex.sig="vp";function _SDL_CreateCond(){return 0}Module["_SDL_CreateCond"]=_SDL_CreateCond;_SDL_CreateCond.sig="p";function _SDL_CondSignal(cond){cond>>>=0}Module["_SDL_CondSignal"]=_SDL_CondSignal;_SDL_CondSignal.sig="ip";function _SDL_CondWait(cond,mutex){cond>>>=0;mutex>>>=0}Module["_SDL_CondWait"]=_SDL_CondWait;_SDL_CondWait.sig="ipp";function _SDL_DestroyCond(cond){cond>>>=0}Module["_SDL_DestroyCond"]=_SDL_DestroyCond;_SDL_DestroyCond.sig="vp";var _SDL_StartTextInput=()=>{SDL.textInput=true};Module["_SDL_StartTextInput"]=_SDL_StartTextInput;_SDL_StartTextInput.sig="v";var _SDL_StopTextInput=()=>{SDL.textInput=false};Module["_SDL_StopTextInput"]=_SDL_StopTextInput;_SDL_StopTextInput.sig="v";var _Mix_Init=flags=>{if(!flags)return 0;return 8};Module["_Mix_Init"]=_Mix_Init;_Mix_Init.sig="ii";var _Mix_Quit=()=>{};Module["_Mix_Quit"]=_Mix_Quit;_Mix_Quit.sig="v";var _Mix_OpenAudio=(frequency,format,channels,chunksize)=>{SDL.openAudioContext();autoResumeAudioContext(SDL.audioContext);SDL.allocateChannels(32);SDL.mixerFrequency=frequency;SDL.mixerFormat=format;SDL.mixerNumChannels=channels;SDL.mixerChunkSize=chunksize;return 0};Module["_Mix_OpenAudio"]=_Mix_OpenAudio;_Mix_OpenAudio.sig="iiiii";var _Mix_CloseAudio=_SDL_CloseAudio;Module["_Mix_CloseAudio"]=_Mix_CloseAudio;_Mix_CloseAudio.sig="v";var _Mix_AllocateChannels=num=>{SDL.allocateChannels(num);return num};Module["_Mix_AllocateChannels"]=_Mix_AllocateChannels;_Mix_AllocateChannels.sig="ii";function _Mix_ChannelFinished(func){func>>>=0;SDL.channelFinished=func}Module["_Mix_ChannelFinished"]=_Mix_ChannelFinished;_Mix_ChannelFinished.sig="vp";var _Mix_Volume=(channel,volume)=>{if(channel==-1){for(var i=0;i{left/=255;right/=255;SDL.setPannerPosition(SDL.channels[channel],right-left,0,.1);return 1};Module["_Mix_SetPanning"]=_Mix_SetPanning;_Mix_SetPanning.sig="iiii";function _Mix_LoadWAV_RW(rwopsID,freesrc){rwopsID>>>=0;var rwops=SDL.rwops[rwopsID];if(rwops===undefined)return 0;var filename="";var audio;var webAudio;var bytes;if(rwops.filename!==undefined){filename=PATH_FS.resolve(rwops.filename);var raw=preloadedAudios[filename];if(!raw){if(raw===null)err("Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!");if(!Module.noAudioDecoding)warnOnce("Cannot find preloaded audio "+filename);try{bytes=FS.readFile(filename)}catch(e){err(`Couldn't find file for: ${filename}`);return 0}}if(Module["freePreloadedMediaOnUse"]){preloadedAudios[filename]=null}audio=raw}else if(rwops.bytes!==undefined){if(SDL.webAudioAvailable())bytes=HEAPU8.buffer.slice(rwops.bytes,rwops.bytes+rwops.count);else bytes=HEAPU8.subarray(rwops.bytes>>>0,rwops.bytes+rwops.count>>>0)}else{return 0}var arrayBuffer=bytes?bytes.buffer||bytes:bytes;var canPlayWithWebAudio=Module["SDL_canPlayWithWebAudio"]===undefined||Module["SDL_canPlayWithWebAudio"](filename,arrayBuffer);if(bytes!==undefined&&SDL.webAudioAvailable()&&canPlayWithWebAudio){audio=undefined;webAudio={};webAudio.onDecodeComplete=[];var onDecodeComplete=data=>{webAudio.decodedBuffer=data;webAudio.onDecodeComplete.forEach(e=>e());webAudio.onDecodeComplete=undefined};SDL.audioContext["decodeAudioData"](arrayBuffer,onDecodeComplete)}else if(audio===undefined&&bytes){var blob=new Blob([bytes],{type:rwops.mimetype});var url=URL.createObjectURL(blob);audio=new Audio;audio.src=url;audio.mozAudioChannelType="content"}var id=SDL.audios.length;SDL.audios.push({source:filename,audio:audio,webAudio:webAudio});return id}Module["_Mix_LoadWAV_RW"]=_Mix_LoadWAV_RW;_Mix_LoadWAV_RW.sig="ppi";function _Mix_LoadWAV(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_Mix_LoadWAV_RW(rwops,0);_SDL_FreeRW(rwops);return result}Module["_Mix_LoadWAV"]=_Mix_LoadWAV;_Mix_LoadWAV.sig="pp";function _Mix_QuickLoad_RAW(mem,len){mem>>>=0;var audio;var webAudio;var numSamples=len>>1;var buffer=new Float32Array(numSamples);for(var i=0;i>>1>>>0]/32768}if(SDL.webAudioAvailable()){webAudio={};webAudio.decodedBuffer=buffer}else{audio=new Audio;audio.mozAudioChannelType="content";audio.numChannels=SDL.mixerNumChannels;audio.frequency=SDL.mixerFrequency}var id=SDL.audios.length;SDL.audios.push({source:"",audio:audio,webAudio:webAudio,buffer:buffer});return id}Module["_Mix_QuickLoad_RAW"]=_Mix_QuickLoad_RAW;_Mix_QuickLoad_RAW.sig="ppi";function _Mix_FreeChunk(id){id>>>=0;SDL.audios[id]=null}Module["_Mix_FreeChunk"]=_Mix_FreeChunk;_Mix_FreeChunk.sig="vp";var _Mix_ReserveChannels=num=>{SDL.channelMinimumNumber=num};Module["_Mix_ReserveChannels"]=_Mix_ReserveChannels;_Mix_ReserveChannels.sig="ii";function _Mix_PlayChannelTimed(channel,id,loops,ticks){id>>>=0;assert(ticks==-1);var info=SDL.audios[id];if(!info)return-1;if(!info.audio&&!info.webAudio)return-1;if(channel==-1){for(var i=SDL.channelMinimumNumber;i0;Module["_Mix_FadingChannel"]=_Mix_FadingChannel;_Mix_FadingChannel.sig="ii";var _Mix_HaltChannel=channel=>{function halt(channel){var info=SDL.channels[channel];if(info.audio){info.audio.pause();info.audio=null}if(SDL.channelFinished){getWasmTableEntry(SDL.channelFinished)(channel)}}if(channel!=-1){halt(channel)}else{for(var i=0;i{var audio=SDL.music.audio;if(audio){audio.src=audio.src;audio.currentPosition=0;audio.pause()}SDL.music.audio=null;if(SDL.hookMusicFinished){getWasmTableEntry(SDL.hookMusicFinished)()}return 0};Module["_Mix_HaltMusic"]=_Mix_HaltMusic;_Mix_HaltMusic.sig="i";function _Mix_HookMusicFinished(func){func>>>=0;SDL.hookMusicFinished=func;if(SDL.music.audio){SDL.music.audio["onended"]=_Mix_HaltMusic}}Module["_Mix_HookMusicFinished"]=_Mix_HookMusicFinished;_Mix_HookMusicFinished.sig="vp";var _Mix_VolumeMusic=volume=>SDL.setGetVolume(SDL.music,volume);Module["_Mix_VolumeMusic"]=_Mix_VolumeMusic;_Mix_VolumeMusic.sig="ii";function _Mix_LoadMUS_RW(filename){filename>>>=0;return _Mix_LoadWAV_RW(filename,0)}Module["_Mix_LoadMUS_RW"]=_Mix_LoadMUS_RW;_Mix_LoadMUS_RW.sig="pp";function _Mix_LoadMUS(filename){filename>>>=0;var rwops=_SDL_RWFromFile(filename,0);var result=_Mix_LoadMUS_RW(rwops);_SDL_FreeRW(rwops);return result}Module["_Mix_LoadMUS"]=_Mix_LoadMUS;_Mix_LoadMUS.sig="pp";var _Mix_FreeMusic=_Mix_FreeChunk;Module["_Mix_FreeMusic"]=_Mix_FreeMusic;_Mix_FreeMusic.sig="vp";function _Mix_PlayMusic(id,loops){id>>>=0;if(SDL.music.audio){if(!SDL.music.audio.paused)err(`Music is already playing. ${SDL.music.source}`);SDL.music.audio.pause()}var info=SDL.audios[id];var audio;if(info.webAudio){audio={};audio.resource=info;audio.paused=false;audio.currentPosition=0;audio.play=function(){SDL.playWebAudio(this)};audio.pause=function(){SDL.pauseWebAudio(this)}}else if(info.audio){audio=info.audio}audio["onended"]=function(){if(SDL.music.audio==this)_Mix_HaltMusic()};audio.loop=loops!=0&&loops!=1;audio.volume=SDL.music.volume;SDL.music.audio=audio;audio.play();return 0}Module["_Mix_PlayMusic"]=_Mix_PlayMusic;_Mix_PlayMusic.sig="ipi";var _Mix_PauseMusic=()=>{var audio=SDL.music.audio;audio?.pause()};Module["_Mix_PauseMusic"]=_Mix_PauseMusic;_Mix_PauseMusic.sig="v";var _Mix_ResumeMusic=()=>{var audio=SDL.music.audio;audio?.play()};Module["_Mix_ResumeMusic"]=_Mix_ResumeMusic;_Mix_ResumeMusic.sig="v";var _Mix_FadeInMusicPos=_Mix_PlayMusic;Module["_Mix_FadeInMusicPos"]=_Mix_FadeInMusicPos;_Mix_FadeInMusicPos.sig="ipiid";var _Mix_FadeOutMusic=_Mix_HaltMusic;Module["_Mix_FadeOutMusic"]=_Mix_FadeOutMusic;_Mix_FadeOutMusic.sig="ii";var _Mix_PlayingMusic=()=>SDL.music.audio&&!SDL.music.audio.paused?1:0;Module["_Mix_PlayingMusic"]=_Mix_PlayingMusic;_Mix_PlayingMusic.sig="i";var _Mix_Playing=channel=>{if(channel===-1){var count=0;for(var i=0;i{if(channel===-1){for(var i=0;i{if(channel===-1){var pausedCount=0;for(var i=0;iSDL.music.audio?.paused?1:0;Module["_Mix_PausedMusic"]=_Mix_PausedMusic;_Mix_PausedMusic.sig="i";var _Mix_Resume=channel=>{if(channel===-1){for(var i=0;i{try{var offscreenCanvas=new OffscreenCanvas(0,0);SDL.ttfContext=offscreenCanvas.getContext("2d");if(typeof SDL.ttfContext.measureText!="function"){throw"bad context"}}catch(ex){var canvas=document.createElement("canvas");SDL.ttfContext=canvas.getContext("2d")}return 0};Module["_TTF_Init"]=_TTF_Init;_TTF_Init.sig="i";function _TTF_OpenFont(name,size){name>>>=0;name=PATH.normalize(UTF8ToString(name));var id=SDL.fonts.length;SDL.fonts.push({name:name,size:size});return id}Module["_TTF_OpenFont"]=_TTF_OpenFont;_TTF_OpenFont.sig="ppi";function _TTF_CloseFont(font){font>>>=0;SDL.fonts[font]=null}Module["_TTF_CloseFont"]=_TTF_CloseFont;_TTF_CloseFont.sig="vp";function _TTF_RenderText_Solid(font,text,color){font>>>=0;text>>>=0;color>>>=0;text=UTF8ToString(text)||" ";var fontData=SDL.fonts[font];var w=SDL.estimateTextWidth(fontData,text);var h=fontData.size;color=SDL.loadColorToCSSRGB(color);var fontString=SDL.makeFontString(h,fontData.name);var surf=SDL.makeSurface(w,h,0,false,"text:"+text);var surfData=SDL.surfaces[surf];surfData.ctx.save();surfData.ctx.fillStyle=color;surfData.ctx.font=fontString;surfData.ctx.textBaseline="bottom";surfData.ctx.fillText(text,0,h|0);surfData.ctx.restore();return surf}Module["_TTF_RenderText_Solid"]=_TTF_RenderText_Solid;_TTF_RenderText_Solid.sig="pppp";var _TTF_RenderText_Blended=_TTF_RenderText_Solid;Module["_TTF_RenderText_Blended"]=_TTF_RenderText_Blended;_TTF_RenderText_Blended.sig="pppp";var _TTF_RenderText_Shaded=_TTF_RenderText_Solid;Module["_TTF_RenderText_Shaded"]=_TTF_RenderText_Shaded;_TTF_RenderText_Shaded.sig="ppppp";var _TTF_RenderUTF8_Solid=_TTF_RenderText_Solid;Module["_TTF_RenderUTF8_Solid"]=_TTF_RenderUTF8_Solid;_TTF_RenderUTF8_Solid.sig="pppp";function _TTF_SizeText(font,text,w,h){font>>>=0;text>>>=0;w>>>=0;h>>>=0;var fontData=SDL.fonts[font];if(w){HEAP32[w>>>2>>>0]=SDL.estimateTextWidth(fontData,UTF8ToString(text))}if(h){HEAP32[h>>>2>>>0]=fontData.size}return 0}Module["_TTF_SizeText"]=_TTF_SizeText;_TTF_SizeText.sig="ipppp";var _TTF_SizeUTF8=_TTF_SizeText;Module["_TTF_SizeUTF8"]=_TTF_SizeUTF8;_TTF_SizeUTF8.sig="ipppp";function _TTF_GlyphMetrics(font,ch,minx,maxx,miny,maxy,advance){font>>>=0;minx>>>=0;maxx>>>=0;miny>>>=0;maxy>>>=0;advance>>>=0;var fontData=SDL.fonts[font];var width=SDL.estimateTextWidth(fontData,String.fromCharCode(ch));if(advance){HEAP32[advance>>>2>>>0]=width}if(minx){HEAP32[minx>>>2>>>0]=0}if(maxx){HEAP32[maxx>>>2>>>0]=width}if(miny){HEAP32[miny>>>2>>>0]=0}if(maxy){HEAP32[maxy>>>2>>>0]=fontData.size}}Module["_TTF_GlyphMetrics"]=_TTF_GlyphMetrics;_TTF_GlyphMetrics.sig="ipippppp";function _TTF_FontAscent(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size*.98|0}Module["_TTF_FontAscent"]=_TTF_FontAscent;_TTF_FontAscent.sig="ip";function _TTF_FontDescent(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size*.02|0}Module["_TTF_FontDescent"]=_TTF_FontDescent;_TTF_FontDescent.sig="ip";function _TTF_FontHeight(font){font>>>=0;var fontData=SDL.fonts[font];return fontData.size}Module["_TTF_FontHeight"]=_TTF_FontHeight;_TTF_FontHeight.sig="ip";var _TTF_FontLineSkip=_TTF_FontHeight;Module["_TTF_FontLineSkip"]=_TTF_FontLineSkip;_TTF_FontLineSkip.sig="ip";var _TTF_Quit=()=>out("TTF_Quit called (and ignored)");Module["_TTF_Quit"]=_TTF_Quit;_TTF_Quit.sig="v";var SDL_gfx={drawRectangle:(surf,x1,y1,x2,y2,action,cssColor)=>{x1=x1<<16>>16;y1=y1<<16>>16;x2=x2<<16>>16;y2=y2<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);var x=x1{x1=x1<<16>>16;y1=y1<<16>>16;x2=x2<<16>>16;y2=y2<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);surfData.ctx.save();surfData.ctx.strokeStyle=cssColor;surfData.ctx.beginPath();surfData.ctx.moveTo(x1,y1);surfData.ctx.lineTo(x2,y2);surfData.ctx.stroke();surfData.ctx.restore()},drawEllipse:(surf,x,y,rx,ry,action,cssColor)=>{x=x<<16>>16;y=y<<16>>16;rx=rx<<16>>16;ry=ry<<16>>16;var surfData=SDL.surfaces[surf];assert(!surfData.locked);surfData.ctx.save();surfData.ctx.beginPath();surfData.ctx.translate(x,y);surfData.ctx.scale(rx,ry);surfData.ctx.arc(0,0,1,0,2*Math.PI);surfData.ctx.restore();surfData.ctx.save();surfData.ctx[action+"Style"]=cssColor;surfData.ctx[action]();surfData.ctx.restore()},translateColorToCSSRGBA:rgba=>`rgba(${rgba>>>24},${rgba>>16&255},${rgba>>8&255},${rgba&255})`};Module["SDL_gfx"]=SDL_gfx;function _boxColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"fill",SDL_gfx.translateColorToCSSRGBA(color))}Module["_boxColor"]=_boxColor;_boxColor.sig="ipiiiii";function _boxRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"fill",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_boxRGBA"]=_boxRGBA;_boxRGBA.sig="ipiiiiiiii";function _rectangleColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"stroke",SDL_gfx.translateColorToCSSRGBA(color))}Module["_rectangleColor"]=_rectangleColor;_rectangleColor.sig="ipiiiii";function _rectangleRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawRectangle(surf,x1,y1,x2,y2,"stroke",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_rectangleRGBA"]=_rectangleRGBA;_rectangleRGBA.sig="ipiiiiiiii";function _ellipseColor(surf,x,y,rx,ry,color){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"stroke",SDL_gfx.translateColorToCSSRGBA(color))}Module["_ellipseColor"]=_ellipseColor;_ellipseColor.sig="ipiiiii";function _ellipseRGBA(surf,x,y,rx,ry,r,g,b,a){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"stroke",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_ellipseRGBA"]=_ellipseRGBA;_ellipseRGBA.sig="ipiiiiiiii";function _filledEllipseColor(surf,x,y,rx,ry,color){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"fill",SDL_gfx.translateColorToCSSRGBA(color))}Module["_filledEllipseColor"]=_filledEllipseColor;_filledEllipseColor.sig="ipiiiii";function _filledEllipseRGBA(surf,x,y,rx,ry,r,g,b,a){surf>>>=0;return SDL_gfx.drawEllipse(surf,x,y,rx,ry,"fill",SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_filledEllipseRGBA"]=_filledEllipseRGBA;_filledEllipseRGBA.sig="ipiiiiiiii";function _lineColor(surf,x1,y1,x2,y2,color){surf>>>=0;return SDL_gfx.drawLine(surf,x1,y1,x2,y2,SDL_gfx.translateColorToCSSRGBA(color))}Module["_lineColor"]=_lineColor;_lineColor.sig="ipiiiii";function _lineRGBA(surf,x1,y1,x2,y2,r,g,b,a){surf>>>=0;return SDL_gfx.drawLine(surf,x1,y1,x2,y2,SDL.translateRGBAToCSSRGBA(r,g,b,a))}Module["_lineRGBA"]=_lineRGBA;_lineRGBA.sig="ipiiiiiiii";function _pixelRGBA(surf,x1,y1,r,g,b,a){surf>>>=0;return _boxRGBA(surf,x1,y1,x1,y1,r,g,b,a)}Module["_pixelRGBA"]=_pixelRGBA;_pixelRGBA.sig="ipiiiiii";var _SDL_GL_SetAttribute=(attr,value)=>{if(!(attr in SDL.glAttributes)){abort("Unknown SDL GL attribute ("+attr+"). Please check if your SDL version is supported.")}SDL.glAttributes[attr]=value};Module["_SDL_GL_SetAttribute"]=_SDL_GL_SetAttribute;_SDL_GL_SetAttribute.sig="iii";function _SDL_GL_GetAttribute(attr,value){value>>>=0;if(!(attr in SDL.glAttributes)){abort("Unknown SDL GL attribute ("+attr+"). Please check if your SDL version is supported.")}if(value)HEAP32[value>>>2>>>0]=SDL.glAttributes[attr];return 0}Module["_SDL_GL_GetAttribute"]=_SDL_GL_GetAttribute;_SDL_GL_GetAttribute.sig="iip";var _SDL_GL_SwapBuffers=()=>{Browser.doSwapBuffers?.()};Module["_SDL_GL_SwapBuffers"]=_SDL_GL_SwapBuffers;_SDL_GL_SwapBuffers.sig="v";function _SDL_GL_ExtensionSupported(extension){extension>>>=0;return Module.ctx.getExtension(extension)|0}Module["_SDL_GL_ExtensionSupported"]=_SDL_GL_ExtensionSupported;_SDL_GL_ExtensionSupported.sig="ip";function _SDL_DestroyWindow(window){window>>>=0}Module["_SDL_DestroyWindow"]=_SDL_DestroyWindow;_SDL_DestroyWindow.sig="vp";function _SDL_DestroyRenderer(renderer){renderer>>>=0}Module["_SDL_DestroyRenderer"]=_SDL_DestroyRenderer;_SDL_DestroyRenderer.sig="vp";function _SDL_GetWindowFlags(window){window>>>=0;if(Browser.isFullscreen){return 1}return 0}Module["_SDL_GetWindowFlags"]=_SDL_GetWindowFlags;_SDL_GetWindowFlags.sig="ip";function _SDL_GL_SwapWindow(window){window>>>=0}Module["_SDL_GL_SwapWindow"]=_SDL_GL_SwapWindow;_SDL_GL_SwapWindow.sig="vp";function _SDL_GL_MakeCurrent(window,context){window>>>=0;context>>>=0}Module["_SDL_GL_MakeCurrent"]=_SDL_GL_MakeCurrent;_SDL_GL_MakeCurrent.sig="ipp";function _SDL_GL_DeleteContext(context){context>>>=0}Module["_SDL_GL_DeleteContext"]=_SDL_GL_DeleteContext;_SDL_GL_DeleteContext.sig="vp";var _SDL_GL_GetSwapInterval=()=>{if(Browser.mainLoop.timingMode==1)return Browser.mainLoop.timingValue;else return 0};Module["_SDL_GL_GetSwapInterval"]=_SDL_GL_GetSwapInterval;_SDL_GL_GetSwapInterval.sig="i";var _SDL_GL_SetSwapInterval=state=>{_emscripten_set_main_loop_timing(1,state)};Module["_SDL_GL_SetSwapInterval"]=_SDL_GL_SetSwapInterval;_SDL_GL_SetSwapInterval.sig="ii";function _SDL_SetWindowTitle(window,title){window>>>=0;title>>>=0;if(title)document.title=UTF8ToString(title)}Module["_SDL_SetWindowTitle"]=_SDL_SetWindowTitle;_SDL_SetWindowTitle.sig="vpp";function _SDL_GetWindowSize(window,width,height){window>>>=0;width>>>=0;height>>>=0;var w=Module["canvas"].width;var h=Module["canvas"].height;if(width)HEAP32[width>>>2>>>0]=w;if(height)HEAP32[height>>>2>>>0]=h}Module["_SDL_GetWindowSize"]=_SDL_GetWindowSize;_SDL_GetWindowSize.sig="vppp";function _SDL_LogSetOutputFunction(callback,userdata){callback>>>=0;userdata>>>=0}Module["_SDL_LogSetOutputFunction"]=_SDL_LogSetOutputFunction;_SDL_LogSetOutputFunction.sig="vpp";function _SDL_SetWindowFullscreen(window,fullscreen){window>>>=0;if(Browser.isFullscreen){Module["canvas"].exitFullscreen();return 1}return 0}Module["_SDL_SetWindowFullscreen"]=_SDL_SetWindowFullscreen;_SDL_SetWindowFullscreen.sig="ipi";var _SDL_ClearError=()=>{};Module["_SDL_ClearError"]=_SDL_ClearError;_SDL_ClearError.sig="v";var _SDL_SetGamma=(r,g,b)=>-1;Module["_SDL_SetGamma"]=_SDL_SetGamma;_SDL_SetGamma.sig="ifff";function _SDL_SetGammaRamp(redTable,greenTable,blueTable){redTable>>>=0;greenTable>>>=0;blueTable>>>=0;return-1}Module["_SDL_SetGammaRamp"]=_SDL_SetGammaRamp;_SDL_SetGammaRamp.sig="ippp";var _SDL_NumJoysticks=()=>{var count=0;var gamepads=SDL.getGamepads();for(var i=0;iSDL.lastJoystickState.hasOwnProperty(deviceIndex+1)?1:0;Module["_SDL_JoystickOpened"]=_SDL_JoystickOpened;_SDL_JoystickOpened.sig="ii";function _SDL_JoystickIndex(joystick){joystick>>>=0;return joystick-1}Module["_SDL_JoystickIndex"]=_SDL_JoystickIndex;_SDL_JoystickIndex.sig="ip";function _SDL_JoystickNumAxes(joystick){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad){return gamepad.axes.length}return 0}Module["_SDL_JoystickNumAxes"]=_SDL_JoystickNumAxes;_SDL_JoystickNumAxes.sig="ip";function _SDL_JoystickNumBalls(joystick){joystick>>>=0;return 0}Module["_SDL_JoystickNumBalls"]=_SDL_JoystickNumBalls;_SDL_JoystickNumBalls.sig="ip";function _SDL_JoystickNumHats(joystick){joystick>>>=0;return 0}Module["_SDL_JoystickNumHats"]=_SDL_JoystickNumHats;_SDL_JoystickNumHats.sig="ip";function _SDL_JoystickNumButtons(joystick){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad){return gamepad.buttons.length}return 0}Module["_SDL_JoystickNumButtons"]=_SDL_JoystickNumButtons;_SDL_JoystickNumButtons.sig="ip";var _SDL_JoystickUpdate=()=>SDL.queryJoysticks();Module["_SDL_JoystickUpdate"]=_SDL_JoystickUpdate;_SDL_JoystickUpdate.sig="v";var _SDL_JoystickEventState=state=>{if(state<0){return SDL.joystickEventState}return SDL.joystickEventState=state};Module["_SDL_JoystickEventState"]=_SDL_JoystickEventState;_SDL_JoystickEventState.sig="ii";function _SDL_JoystickGetAxis(joystick,axis){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad&&gamepad.axes.length>axis){return SDL.joystickAxisValueConversion(gamepad.axes[axis])}return 0}Module["_SDL_JoystickGetAxis"]=_SDL_JoystickGetAxis;_SDL_JoystickGetAxis.sig="ipi";function _SDL_JoystickGetHat(joystick,hat){joystick>>>=0;return 0}Module["_SDL_JoystickGetHat"]=_SDL_JoystickGetHat;_SDL_JoystickGetHat.sig="ipi";function _SDL_JoystickGetBall(joystick,ball,dxptr,dyptr){joystick>>>=0;dxptr>>>=0;dyptr>>>=0;return-1}Module["_SDL_JoystickGetBall"]=_SDL_JoystickGetBall;_SDL_JoystickGetBall.sig="ipipp";function _SDL_JoystickGetButton(joystick,button){joystick>>>=0;var gamepad=SDL.getGamepad(joystick-1);if(gamepad&&gamepad.buttons.length>button){return SDL.getJoystickButtonState(gamepad.buttons[button])?1:0}return 0}Module["_SDL_JoystickGetButton"]=_SDL_JoystickGetButton;_SDL_JoystickGetButton.sig="ipi";function _SDL_JoystickClose(joystick){joystick>>>=0;delete SDL.lastJoystickState[joystick]}Module["_SDL_JoystickClose"]=_SDL_JoystickClose;_SDL_JoystickClose.sig="vp";var _SDL_InitSubSystem=flags=>0;Module["_SDL_InitSubSystem"]=_SDL_InitSubSystem;_SDL_InitSubSystem.sig="ii";function _SDL_RWFromConstMem(mem,size){mem>>>=0;var id=SDL.rwops.length;SDL.rwops.push({bytes:mem,count:size});return id}Module["_SDL_RWFromConstMem"]=_SDL_RWFromConstMem;_SDL_RWFromConstMem.sig="ppi";var _SDL_RWFromMem=_SDL_RWFromConstMem;Module["_SDL_RWFromMem"]=_SDL_RWFromMem;_SDL_RWFromMem.sig="ppi";var _SDL_GetNumAudioDrivers=()=>1;Module["_SDL_GetNumAudioDrivers"]=_SDL_GetNumAudioDrivers;_SDL_GetNumAudioDrivers.sig="i";function _SDL_GetCurrentAudioDriver(){return stringToNewUTF8("Emscripten Audio")}Module["_SDL_GetCurrentAudioDriver"]=_SDL_GetCurrentAudioDriver;_SDL_GetCurrentAudioDriver.sig="p";var _SDL_GetScancodeFromKey=key=>SDL.scanCodes[key];Module["_SDL_GetScancodeFromKey"]=_SDL_GetScancodeFromKey;_SDL_GetScancodeFromKey.sig="ii";function _SDL_GetAudioDriver(index){return _SDL_GetCurrentAudioDriver()}Module["_SDL_GetAudioDriver"]=_SDL_GetAudioDriver;_SDL_GetAudioDriver.sig="pi";var _SDL_EnableUNICODE=on=>{var ret=SDL.unicode||0;SDL.unicode=on;return ret};Module["_SDL_EnableUNICODE"]=_SDL_EnableUNICODE;_SDL_EnableUNICODE.sig="ii";var _SDL_AddTimer=function(interval,callback,param){callback>>>=0;param>>>=0;return safeSetTimeout(()=>getWasmTableEntry(callback)(interval,param),interval)};Module["_SDL_AddTimer"]=_SDL_AddTimer;_SDL_AddTimer.sig="iipp";var _SDL_RemoveTimer=id=>{clearTimeout(id);return true};Module["_SDL_RemoveTimer"]=_SDL_RemoveTimer;_SDL_RemoveTimer.sig="ii";function _SDL_CreateThread(fs,data,pfnBeginThread,pfnEndThread){fs>>>=0;data>>>=0;throw"SDL threads cannot be supported in the web platform because they assume shared state. See emscripten_create_worker etc. for a message-passing concurrency model that does let you run code in another thread."}Module["_SDL_CreateThread"]=_SDL_CreateThread;_SDL_CreateThread.sig="ppp";function _SDL_WaitThread(thread,status){thread>>>=0;status>>>=0;throw"SDL_WaitThread"}Module["_SDL_WaitThread"]=_SDL_WaitThread;_SDL_WaitThread.sig="vpp";function _SDL_GetThreadID(thread){thread>>>=0;throw"SDL_GetThreadID"}Module["_SDL_GetThreadID"]=_SDL_GetThreadID;_SDL_GetThreadID.sig="pp";function _SDL_ThreadID(){return 0}Module["_SDL_ThreadID"]=_SDL_ThreadID;_SDL_ThreadID.sig="p";function _SDL_AllocRW(){throw"SDL_AllocRW: TODO"}Module["_SDL_AllocRW"]=_SDL_AllocRW;_SDL_AllocRW.sig="p";function _SDL_CondBroadcast(cond){cond>>>=0;throw"SDL_CondBroadcast: TODO"}Module["_SDL_CondBroadcast"]=_SDL_CondBroadcast;_SDL_CondBroadcast.sig="ip";function _SDL_CondWaitTimeout(cond,mutex,ms){cond>>>=0;mutex>>>=0;throw"SDL_CondWaitTimeout: TODO"}Module["_SDL_CondWaitTimeout"]=_SDL_CondWaitTimeout;_SDL_CondWaitTimeout.sig="ippi";var _SDL_WM_IconifyWindow=()=>{throw"SDL_WM_IconifyWindow TODO"};Module["_SDL_WM_IconifyWindow"]=_SDL_WM_IconifyWindow;_SDL_WM_IconifyWindow.sig="i";function _Mix_SetPostMix(func,arg){func>>>=0;arg>>>=0;return warnOnce("Mix_SetPostMix: TODO")}Module["_Mix_SetPostMix"]=_Mix_SetPostMix;_Mix_SetPostMix.sig="vpp";function _Mix_VolumeChunk(chunk,volume){chunk>>>=0;throw"Mix_VolumeChunk: TODO"}Module["_Mix_VolumeChunk"]=_Mix_VolumeChunk;_Mix_VolumeChunk.sig="ipi";var _Mix_SetPosition=(channel,angle,distance)=>{throw"Mix_SetPosition: TODO"};Module["_Mix_SetPosition"]=_Mix_SetPosition;_Mix_SetPosition.sig="iiii";function _Mix_QuerySpec(frequency,format,channels){frequency>>>=0;format>>>=0;channels>>>=0;throw"Mix_QuerySpec: TODO"}Module["_Mix_QuerySpec"]=_Mix_QuerySpec;_Mix_QuerySpec.sig="ippp";function _Mix_FadeInChannelTimed(channel,chunk,loop,ms,ticks){chunk>>>=0;throw"Mix_FadeInChannelTimed"}Module["_Mix_FadeInChannelTimed"]=_Mix_FadeInChannelTimed;_Mix_FadeInChannelTimed.sig="iipiii";var _Mix_FadeOutChannel=()=>{throw"Mix_FadeOutChannel"};Module["_Mix_FadeOutChannel"]=_Mix_FadeOutChannel;_Mix_FadeOutChannel.sig="iii";function _Mix_Linked_Version(){throw"Mix_Linked_Version: TODO"}Module["_Mix_Linked_Version"]=_Mix_Linked_Version;_Mix_Linked_Version.sig="p";function _SDL_SaveBMP_RW(surface,dst,freedst){surface>>>=0;dst>>>=0;throw"SDL_SaveBMP_RW: TODO"}Module["_SDL_SaveBMP_RW"]=_SDL_SaveBMP_RW;_SDL_SaveBMP_RW.sig="ippi";function _SDL_WM_SetIcon(icon,mask){icon>>>=0;mask>>>=0}Module["_SDL_WM_SetIcon"]=_SDL_WM_SetIcon;_SDL_WM_SetIcon.sig="vpp";var _SDL_HasRDTSC=()=>0;Module["_SDL_HasRDTSC"]=_SDL_HasRDTSC;_SDL_HasRDTSC.sig="i";var _SDL_HasMMX=()=>0;Module["_SDL_HasMMX"]=_SDL_HasMMX;_SDL_HasMMX.sig="i";var _SDL_HasMMXExt=()=>0;Module["_SDL_HasMMXExt"]=_SDL_HasMMXExt;_SDL_HasMMXExt.sig="i";var _SDL_Has3DNow=()=>0;Module["_SDL_Has3DNow"]=_SDL_Has3DNow;_SDL_Has3DNow.sig="i";var _SDL_Has3DNowExt=()=>0;Module["_SDL_Has3DNowExt"]=_SDL_Has3DNowExt;_SDL_Has3DNowExt.sig="i";var _SDL_HasSSE=()=>0;Module["_SDL_HasSSE"]=_SDL_HasSSE;_SDL_HasSSE.sig="i";var _SDL_HasSSE2=()=>0;Module["_SDL_HasSSE2"]=_SDL_HasSSE2;_SDL_HasSSE2.sig="i";var _SDL_HasAltiVec=()=>0;Module["_SDL_HasAltiVec"]=_SDL_HasAltiVec;_SDL_HasAltiVec.sig="i";if(!Module.createInvoke){Module.createInvoke=Module.createInvokeFunction}registerWasmPlugin();FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;if(ENVIRONMENT_IS_NODE){NODEFS.staticInit()}var GLctx;for(var i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i)}var miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<288;++i){miniTempWebGLIntBuffers[i]=miniTempWebGLIntBuffersStorage.subarray(0,i)}var emSetImmediate;var emClearImmediate;if(typeof setImmediate!="undefined"){emSetImmediate=setImmediateWrapped;emClearImmediate=clearImmediateWrapped}else if(typeof addEventListener=="function"){var __setImmediate_id_counter=0;var __setImmediate_queue=[];var __setImmediate_message_id="_si";var __setImmediate_cb=e=>{if(e.data===__setImmediate_message_id){e.stopPropagation();__setImmediate_queue.shift()();++__setImmediate_id_counter}};addEventListener("message",__setImmediate_cb,true);emSetImmediate=func=>{postMessage(__setImmediate_message_id,"*");return __setImmediate_id_counter+__setImmediate_queue.push(func)-1};emClearImmediate=id=>{var index=id-__setImmediate_id_counter;if(index>=0&&index<__setImmediate_queue.length)__setImmediate_queue[index]=()=>{}}}Module["requestFullscreen"]=Browser.requestFullscreen;Module["requestAnimationFrame"]=Browser.requestAnimationFrame;Module["setCanvasSize"]=Browser.setCanvasSize;Module["pauseMainLoop"]=Browser.mainLoop.pause;Module["resumeMainLoop"]=Browser.mainLoop.resume;Module["getUserMedia"]=Browser.getUserMedia;Module["createContext"]=Browser.createContext;var preloadedImages={};var preloadedAudios={};var wasmImports={IMG_Init:_IMG_Init,IMG_Load:_IMG_Load,IMG_Load_RW:_IMG_Load_RW,IMG_Quit:_IMG_Quit,JsArray_count_js:JsArray_count_js,JsArray_index_js:JsArray_index_js,JsArray_inplace_repeat_js:JsArray_inplace_repeat_js,JsArray_repeat_js:JsArray_repeat_js,JsArray_reverse_js:JsArray_reverse_js,JsArray_reversed_iterator:JsArray_reversed_iterator,JsBuffer_DecodeString_js:JsBuffer_DecodeString_js,JsBuffer_get_info:JsBuffer_get_info,JsDoubleProxy_unwrap_helper:JsDoubleProxy_unwrap_helper,JsException_new_helper:JsException_new_helper,JsMap_GetIter_js:JsMap_GetIter_js,JsMap_clear_js:JsMap_clear_js,JsModule_GetAll_js:JsModule_GetAll_js,JsObjMap_GetIter_js:JsObjMap_GetIter_js,JsObjMap_ass_subscript_js:JsObjMap_ass_subscript_js,JsObjMap_contains_js:JsObjMap_contains_js,JsObjMap_length_js:JsObjMap_length_js,JsObjMap_subscript_js:JsObjMap_subscript_js,JsProxy_Bool_js:JsProxy_Bool_js,JsProxy_DelAttr_js:JsProxy_DelAttr_js,JsProxy_Dir_js:JsProxy_Dir_js,JsProxy_GetAsyncIter_js:JsProxy_GetAsyncIter_js,JsProxy_GetAttr_js:JsProxy_GetAttr_js,JsProxy_GetIter_js:JsProxy_GetIter_js,JsProxy_SetAttr_js:JsProxy_SetAttr_js,JsProxy_compute_typeflags:JsProxy_compute_typeflags,JsProxy_subscript_js:JsProxy_subscript_js,JsvArray_Check:JsvArray_Check,JsvArray_Delete:JsvArray_Delete,JsvArray_Extend:JsvArray_Extend,JsvArray_Get:JsvArray_Get,JsvArray_Insert:JsvArray_Insert,JsvArray_New:JsvArray_New,JsvArray_Push:JsvArray_Push,JsvArray_Set:JsvArray_Set,JsvArray_ShallowCopy:JsvArray_ShallowCopy,JsvArray_slice:JsvArray_slice,JsvArray_slice_assign:JsvArray_slice_assign,JsvAsyncGenerator_Check:JsvAsyncGenerator_Check,JsvBuffer_assignFromPtr:JsvBuffer_assignFromPtr,JsvBuffer_assignToPtr:JsvBuffer_assignToPtr,JsvBuffer_intoFile:JsvBuffer_intoFile,JsvBuffer_readFromFile:JsvBuffer_readFromFile,JsvBuffer_writeToFile:JsvBuffer_writeToFile,JsvError_Throw:JsvError_Throw,JsvFunction_CallBound:JsvFunction_CallBound,JsvFunction_Call_OneArg:JsvFunction_Call_OneArg,JsvFunction_Check:JsvFunction_Check,JsvFunction_Construct:JsvFunction_Construct,JsvGenerator_Check:JsvGenerator_Check,JsvLiteralMap_New:JsvLiteralMap_New,JsvMap_New:JsvMap_New,JsvMap_Set:JsvMap_Set,JsvNoValue_Check:JsvNoValue_Check,JsvNum_fromDigits:JsvNum_fromDigits,JsvNum_fromDouble:JsvNum_fromDouble,JsvNum_fromInt:JsvNum_fromInt,JsvObject_CallMethod:JsvObject_CallMethod,JsvObject_CallMethod_NoArgs:JsvObject_CallMethod_NoArgs,JsvObject_CallMethod_OneArg:JsvObject_CallMethod_OneArg,JsvObject_CallMethod_TwoArgs:JsvObject_CallMethod_TwoArgs,JsvObject_Entries:JsvObject_Entries,JsvObject_Keys:JsvObject_Keys,JsvObject_New:JsvObject_New,JsvObject_SetAttr:JsvObject_SetAttr,JsvObject_Values:JsvObject_Values,JsvObject_toString:JsvObject_toString,JsvPromise_Check:JsvPromise_Check,JsvPromise_Resolve:JsvPromise_Resolve,JsvPromise_Syncify_handleError:JsvPromise_Syncify_handleError,JsvSet_Add:JsvSet_Add,JsvSet_New:JsvSet_New,JsvUTF8ToString:JsvUTF8ToString,Jsv_constructorName:Jsv_constructorName,Jsv_equal:Jsv_equal,Jsv_greater_than:Jsv_greater_than,Jsv_greater_than_equal:Jsv_greater_than_equal,Jsv_less_than:Jsv_less_than,Jsv_less_than_equal:Jsv_less_than_equal,Jsv_not_equal:Jsv_not_equal,Jsv_to_bool:Jsv_to_bool,Jsv_typeof:Jsv_typeof,Mix_AllocateChannels:_Mix_AllocateChannels,Mix_ChannelFinished:_Mix_ChannelFinished,Mix_CloseAudio:_Mix_CloseAudio,Mix_FadeInChannelTimed:_Mix_FadeInChannelTimed,Mix_FadeInMusicPos:_Mix_FadeInMusicPos,Mix_FadeOutChannel:_Mix_FadeOutChannel,Mix_FadeOutMusic:_Mix_FadeOutMusic,Mix_FadingChannel:_Mix_FadingChannel,Mix_FreeChunk:_Mix_FreeChunk,Mix_FreeMusic:_Mix_FreeMusic,Mix_HaltChannel:_Mix_HaltChannel,Mix_HaltMusic:_Mix_HaltMusic,Mix_HookMusicFinished:_Mix_HookMusicFinished,Mix_Init:_Mix_Init,Mix_Linked_Version:_Mix_Linked_Version,Mix_LoadMUS:_Mix_LoadMUS,Mix_LoadMUS_RW:_Mix_LoadMUS_RW,Mix_LoadWAV:_Mix_LoadWAV,Mix_LoadWAV_RW:_Mix_LoadWAV_RW,Mix_OpenAudio:_Mix_OpenAudio,Mix_Pause:_Mix_Pause,Mix_PauseMusic:_Mix_PauseMusic,Mix_Paused:_Mix_Paused,Mix_PausedMusic:_Mix_PausedMusic,Mix_PlayChannelTimed:_Mix_PlayChannelTimed,Mix_PlayMusic:_Mix_PlayMusic,Mix_Playing:_Mix_Playing,Mix_PlayingMusic:_Mix_PlayingMusic,Mix_QuerySpec:_Mix_QuerySpec,Mix_QuickLoad_RAW:_Mix_QuickLoad_RAW,Mix_Quit:_Mix_Quit,Mix_ReserveChannels:_Mix_ReserveChannels,Mix_Resume:_Mix_Resume,Mix_ResumeMusic:_Mix_ResumeMusic,Mix_SetPanning:_Mix_SetPanning,Mix_SetPosition:_Mix_SetPosition,Mix_SetPostMix:_Mix_SetPostMix,Mix_Volume:_Mix_Volume,Mix_VolumeChunk:_Mix_VolumeChunk,Mix_VolumeMusic:_Mix_VolumeMusic,SDL_AddTimer:_SDL_AddTimer,SDL_AllocRW:_SDL_AllocRW,SDL_AudioDriverName:_SDL_AudioDriverName,SDL_AudioQuit:_SDL_AudioQuit,SDL_ClearError:_SDL_ClearError,SDL_CloseAudio:_SDL_CloseAudio,SDL_CondBroadcast:_SDL_CondBroadcast,SDL_CondSignal:_SDL_CondSignal,SDL_CondWait:_SDL_CondWait,SDL_CondWaitTimeout:_SDL_CondWaitTimeout,SDL_ConvertSurface:_SDL_ConvertSurface,SDL_CreateCond:_SDL_CreateCond,SDL_CreateMutex:_SDL_CreateMutex,SDL_CreateRGBSurface:_SDL_CreateRGBSurface,SDL_CreateRGBSurfaceFrom:_SDL_CreateRGBSurfaceFrom,SDL_CreateThread:_SDL_CreateThread,SDL_Delay:_SDL_Delay,SDL_DestroyCond:_SDL_DestroyCond,SDL_DestroyMutex:_SDL_DestroyMutex,SDL_DestroyRenderer:_SDL_DestroyRenderer,SDL_DestroyWindow:_SDL_DestroyWindow,SDL_DisplayFormatAlpha:_SDL_DisplayFormatAlpha,SDL_EnableKeyRepeat:_SDL_EnableKeyRepeat,SDL_EnableUNICODE:_SDL_EnableUNICODE,SDL_FillRect:_SDL_FillRect,SDL_Flip:_SDL_Flip,SDL_FreeRW:_SDL_FreeRW,SDL_FreeSurface:_SDL_FreeSurface,SDL_GL_DeleteContext:_SDL_GL_DeleteContext,SDL_GL_ExtensionSupported:_SDL_GL_ExtensionSupported,SDL_GL_GetAttribute:_SDL_GL_GetAttribute,SDL_GL_GetSwapInterval:_SDL_GL_GetSwapInterval,SDL_GL_MakeCurrent:_SDL_GL_MakeCurrent,SDL_GL_SetAttribute:_SDL_GL_SetAttribute,SDL_GL_SetSwapInterval:_SDL_GL_SetSwapInterval,SDL_GL_SwapBuffers:_SDL_GL_SwapBuffers,SDL_GL_SwapWindow:_SDL_GL_SwapWindow,SDL_GetAppState:_SDL_GetAppState,SDL_GetAudioDriver:_SDL_GetAudioDriver,SDL_GetClipRect:_SDL_GetClipRect,SDL_GetCurrentAudioDriver:_SDL_GetCurrentAudioDriver,SDL_GetError:_SDL_GetError,SDL_GetKeyName:_SDL_GetKeyName,SDL_GetKeyState:_SDL_GetKeyState,SDL_GetKeyboardState:_SDL_GetKeyboardState,SDL_GetModState:_SDL_GetModState,SDL_GetMouseState:_SDL_GetMouseState,SDL_GetNumAudioDrivers:_SDL_GetNumAudioDrivers,SDL_GetRGB:_SDL_GetRGB,SDL_GetRGBA:_SDL_GetRGBA,SDL_GetScancodeFromKey:_SDL_GetScancodeFromKey,SDL_GetThreadID:_SDL_GetThreadID,SDL_GetTicks:_SDL_GetTicks,SDL_GetVideoInfo:_SDL_GetVideoInfo,SDL_GetVideoSurface:_SDL_GetVideoSurface,SDL_GetWindowFlags:_SDL_GetWindowFlags,SDL_GetWindowSize:_SDL_GetWindowSize,SDL_Has3DNow:_SDL_Has3DNow,SDL_Has3DNowExt:_SDL_Has3DNowExt,SDL_HasAltiVec:_SDL_HasAltiVec,SDL_HasMMX:_SDL_HasMMX,SDL_HasMMXExt:_SDL_HasMMXExt,SDL_HasRDTSC:_SDL_HasRDTSC,SDL_HasSSE:_SDL_HasSSE,SDL_HasSSE2:_SDL_HasSSE2,SDL_Init:_SDL_Init,SDL_InitSubSystem:_SDL_InitSubSystem,SDL_JoystickClose:_SDL_JoystickClose,SDL_JoystickEventState:_SDL_JoystickEventState,SDL_JoystickGetAxis:_SDL_JoystickGetAxis,SDL_JoystickGetBall:_SDL_JoystickGetBall,SDL_JoystickGetButton:_SDL_JoystickGetButton,SDL_JoystickGetHat:_SDL_JoystickGetHat,SDL_JoystickIndex:_SDL_JoystickIndex,SDL_JoystickName:_SDL_JoystickName,SDL_JoystickNumAxes:_SDL_JoystickNumAxes,SDL_JoystickNumBalls:_SDL_JoystickNumBalls,SDL_JoystickNumButtons:_SDL_JoystickNumButtons,SDL_JoystickNumHats:_SDL_JoystickNumHats,SDL_JoystickOpen:_SDL_JoystickOpen,SDL_JoystickOpened:_SDL_JoystickOpened,SDL_JoystickUpdate:_SDL_JoystickUpdate,SDL_Linked_Version:_SDL_Linked_Version,SDL_ListModes:_SDL_ListModes,SDL_LoadBMP_RW:_SDL_LoadBMP_RW,SDL_LockAudio:_SDL_LockAudio,SDL_LockSurface:_SDL_LockSurface,SDL_LogSetOutputFunction:_SDL_LogSetOutputFunction,SDL_LowerBlit:_SDL_LowerBlit,SDL_LowerBlitScaled:_SDL_LowerBlitScaled,SDL_MapRGB:_SDL_MapRGB,SDL_MapRGBA:_SDL_MapRGBA,SDL_NumJoysticks:_SDL_NumJoysticks,SDL_OpenAudio:_SDL_OpenAudio,SDL_PauseAudio:_SDL_PauseAudio,SDL_PeepEvents:_SDL_PeepEvents,SDL_PollEvent:_SDL_PollEvent,SDL_PumpEvents:_SDL_PumpEvents,SDL_PushEvent:_SDL_PushEvent,SDL_Quit:_SDL_Quit,SDL_QuitSubSystem:_SDL_QuitSubSystem,SDL_RWFromConstMem:_SDL_RWFromConstMem,SDL_RWFromFile:_SDL_RWFromFile,SDL_RWFromMem:_SDL_RWFromMem,SDL_RemoveTimer:_SDL_RemoveTimer,SDL_SaveBMP_RW:_SDL_SaveBMP_RW,SDL_SetAlpha:_SDL_SetAlpha,SDL_SetClipRect:_SDL_SetClipRect,SDL_SetColorKey:_SDL_SetColorKey,SDL_SetColors:_SDL_SetColors,SDL_SetError:_SDL_SetError,SDL_SetGamma:_SDL_SetGamma,SDL_SetGammaRamp:_SDL_SetGammaRamp,SDL_SetPalette:_SDL_SetPalette,SDL_SetVideoMode:_SDL_SetVideoMode,SDL_SetWindowFullscreen:_SDL_SetWindowFullscreen,SDL_SetWindowTitle:_SDL_SetWindowTitle,SDL_ShowCursor:_SDL_ShowCursor,SDL_StartTextInput:_SDL_StartTextInput,SDL_StopTextInput:_SDL_StopTextInput,SDL_ThreadID:_SDL_ThreadID,SDL_UnlockAudio:_SDL_UnlockAudio,SDL_UnlockSurface:_SDL_UnlockSurface,SDL_UpdateRect:_SDL_UpdateRect,SDL_UpdateRects:_SDL_UpdateRects,SDL_UpperBlit:_SDL_UpperBlit,SDL_UpperBlitScaled:_SDL_UpperBlitScaled,SDL_VideoDriverName:_SDL_VideoDriverName,SDL_VideoModeOK:_SDL_VideoModeOK,SDL_VideoQuit:_SDL_VideoQuit,SDL_WM_GrabInput:_SDL_WM_GrabInput,SDL_WM_IconifyWindow:_SDL_WM_IconifyWindow,SDL_WM_SetCaption:_SDL_WM_SetCaption,SDL_WM_SetIcon:_SDL_WM_SetIcon,SDL_WM_ToggleFullScreen:_SDL_WM_ToggleFullScreen,SDL_WaitThread:_SDL_WaitThread,SDL_WarpMouse:_SDL_WarpMouse,SDL_WasInit:_SDL_WasInit,SDL_mutexP:_SDL_mutexP,SDL_mutexV:_SDL_mutexV,TTF_CloseFont:_TTF_CloseFont,TTF_FontAscent:_TTF_FontAscent,TTF_FontDescent:_TTF_FontDescent,TTF_FontHeight:_TTF_FontHeight,TTF_FontLineSkip:_TTF_FontLineSkip,TTF_GlyphMetrics:_TTF_GlyphMetrics,TTF_Init:_TTF_Init,TTF_OpenFont:_TTF_OpenFont,TTF_Quit:_TTF_Quit,TTF_RenderText_Blended:_TTF_RenderText_Blended,TTF_RenderText_Shaded:_TTF_RenderText_Shaded,TTF_RenderText_Solid:_TTF_RenderText_Solid,TTF_RenderUTF8_Solid:_TTF_RenderUTF8_Solid,TTF_SizeText:_TTF_SizeText,TTF_SizeUTF8:_TTF_SizeUTF8,_JsArray_PostProcess_helper:_JsArray_PostProcess_helper,_JsArray_PushEntry_helper:_JsArray_PushEntry_helper,_PyEM_GetCountArgsPtr:_PyEM_GetCountArgsPtr,_PyEM_TrampolineCall_JS:_PyEM_TrampolineCall_JS,_PyImport_InitFunc_TrampolineCall:_PyImport_InitFunc_TrampolineCall,_Py_CheckEmscriptenSignals_Helper:_Py_CheckEmscriptenSignals_Helper,_Py_emscripten_runtime:_Py_emscripten_runtime,_Unwind_Backtrace:__Unwind_Backtrace,_Unwind_DeleteException:__Unwind_DeleteException,_Unwind_FindEnclosingFunction:__Unwind_FindEnclosingFunction,_Unwind_GetIPInfo:__Unwind_GetIPInfo,_Unwind_RaiseException:__Unwind_RaiseException,__asctime_r:___asctime_r,__assert_fail:___assert_fail,__call_sighandler:___call_sighandler,__cxa_begin_catch:___cxa_begin_catch,__cxa_call_unexpected:___cxa_call_unexpected,__cxa_current_primary_exception:___cxa_current_primary_exception,__cxa_end_catch:___cxa_end_catch,__cxa_find_matching_catch_2:___cxa_find_matching_catch_2,__cxa_find_matching_catch_3:___cxa_find_matching_catch_3,__cxa_find_matching_catch_4:___cxa_find_matching_catch_4,__cxa_get_exception_ptr:___cxa_get_exception_ptr,__cxa_rethrow:___cxa_rethrow,__cxa_rethrow_primary_exception:___cxa_rethrow_primary_exception,__cxa_throw:___cxa_throw,__cxa_uncaught_exceptions:___cxa_uncaught_exceptions,__global_base:___global_base,__heap_base:___heap_base,__hiwire_deduplicate_delete:__hiwire_deduplicate_delete,__hiwire_deduplicate_get:__hiwire_deduplicate_get,__hiwire_deduplicate_new:__hiwire_deduplicate_new,__hiwire_deduplicate_set:__hiwire_deduplicate_set,__indirect_function_table:wasmTable,__memory_base:___memory_base,__resumeException:___resumeException,__stack_high:___stack_high,__stack_low:___stack_low,__stack_pointer:___stack_pointer,__syscall__newselect:___syscall__newselect,__syscall_accept4:___syscall_accept4,__syscall_bind:___syscall_bind,__syscall_chdir:___syscall_chdir,__syscall_chmod:___syscall_chmod,__syscall_connect:___syscall_connect,__syscall_dup:___syscall_dup,__syscall_dup3:___syscall_dup3,__syscall_faccessat:___syscall_faccessat,__syscall_fadvise64:___syscall_fadvise64,__syscall_fallocate:___syscall_fallocate,__syscall_fchdir:___syscall_fchdir,__syscall_fchmod:___syscall_fchmod,__syscall_fchmodat2:___syscall_fchmodat2,__syscall_fchown32:___syscall_fchown32,__syscall_fchownat:___syscall_fchownat,__syscall_fcntl64:___syscall_fcntl64,__syscall_fdatasync:___syscall_fdatasync,__syscall_fstat64:___syscall_fstat64,__syscall_fstatfs64:___syscall_fstatfs64,__syscall_ftruncate64:___syscall_ftruncate64,__syscall_getcwd:___syscall_getcwd,__syscall_getdents64:___syscall_getdents64,__syscall_getpeername:___syscall_getpeername,__syscall_getsockname:___syscall_getsockname,__syscall_getsockopt:___syscall_getsockopt,__syscall_ioctl:___syscall_ioctl,__syscall_listen:___syscall_listen,__syscall_lstat64:___syscall_lstat64,__syscall_mkdirat:___syscall_mkdirat,__syscall_mknodat:___syscall_mknodat,__syscall_newfstatat:___syscall_newfstatat,__syscall_openat:___syscall_openat,__syscall_pipe:___syscall_pipe,__syscall_poll:___syscall_poll,__syscall_readlinkat:___syscall_readlinkat,__syscall_recvfrom:___syscall_recvfrom,__syscall_recvmsg:___syscall_recvmsg,__syscall_renameat:___syscall_renameat,__syscall_rmdir:___syscall_rmdir,__syscall_sendmsg:___syscall_sendmsg,__syscall_sendto:___syscall_sendto,__syscall_socket:___syscall_socket,__syscall_stat64:___syscall_stat64,__syscall_statfs64:___syscall_statfs64,__syscall_symlink:___syscall_symlink,__syscall_symlinkat:___syscall_symlinkat,__syscall_truncate64:___syscall_truncate64,__syscall_unlinkat:___syscall_unlinkat,__syscall_utimensat:___syscall_utimensat,__table_base:___table_base,_agen_handle_result_js:_agen_handle_result_js,_dlopen_js:__dlopen_js,_dlsym_catchup_js:__dlsym_catchup_js,_dlsym_js:__dlsym_js,_emscripten_dlopen_js:__emscripten_dlopen_js,_emscripten_fs_load_embedded_files:__emscripten_fs_load_embedded_files,_emscripten_get_now_is_monotonic:__emscripten_get_now_is_monotonic,_emscripten_get_progname:__emscripten_get_progname,_emscripten_lookup_name:__emscripten_lookup_name,_emscripten_push_main_loop_blocker:__emscripten_push_main_loop_blocker,_emscripten_push_uncounted_main_loop_blocker:__emscripten_push_uncounted_main_loop_blocker,_emscripten_runtime_keepalive_clear:__emscripten_runtime_keepalive_clear,_emscripten_set_offscreencanvas_size:__emscripten_set_offscreencanvas_size,_emscripten_system:__emscripten_system,_emscripten_throw_longjmp:__emscripten_throw_longjmp,_glGetActiveAttribOrUniform:__glGetActiveAttribOrUniform,_gmtime_js:__gmtime_js,_localtime_js:__localtime_js,_mktime_js:__mktime_js,_mmap_js:__mmap_js,_msync_js:__msync_js,_munmap_js:__munmap_js,_pyproxyGen_make_result:_pyproxyGen_make_result,_pyproxy_get_buffer_result:_pyproxy_get_buffer_result,_python2js_add_to_cache:_python2js_add_to_cache,_python2js_addto_postprocess_list:_python2js_addto_postprocess_list,_python2js_buffer_inner:_python2js_buffer_inner,_python2js_cache_lookup:_python2js_cache_lookup,_python2js_handle_postprocess_list:_python2js_handle_postprocess_list,_python2js_ucs1:_python2js_ucs1,_python2js_ucs2:_python2js_ucs2,_python2js_ucs4:_python2js_ucs4,_setitimer_js:__setitimer_js,_timegm_js:__timegm_js,_tzset_js:__tzset_js,abort:_abort,array_to_js:array_to_js,boxColor:_boxColor,boxRGBA:_boxRGBA,can_run_sync_js:can_run_sync_js,capture_stderr:capture_stderr,clock_res_get:_clock_res_get,clock_time_get:_clock_time_get,create_once_callable:create_once_callable,create_promise_handles:create_promise_handles,destroy_jsarray_entries:destroy_jsarray_entries,destroy_proxies:destroy_proxies,destroy_proxies_js:destroy_proxies_js,destroy_proxy:destroy_proxy,eglBindAPI:_eglBindAPI,eglChooseConfig:_eglChooseConfig,eglCreateContext:_eglCreateContext,eglCreateWindowSurface:_eglCreateWindowSurface,eglDestroyContext:_eglDestroyContext,eglDestroySurface:_eglDestroySurface,eglGetConfigAttrib:_eglGetConfigAttrib,eglGetConfigs:_eglGetConfigs,eglGetCurrentContext:_eglGetCurrentContext,eglGetCurrentDisplay:_eglGetCurrentDisplay,eglGetCurrentSurface:_eglGetCurrentSurface,eglGetDisplay:_eglGetDisplay,eglGetError:_eglGetError,eglInitialize:_eglInitialize,eglMakeCurrent:_eglMakeCurrent,eglQueryAPI:_eglQueryAPI,eglQueryContext:_eglQueryContext,eglQueryString:_eglQueryString,eglQuerySurface:_eglQuerySurface,eglReleaseThread:_eglReleaseThread,eglSwapBuffers:_eglSwapBuffers,eglSwapInterval:_eglSwapInterval,eglTerminate:_eglTerminate,eglWaitClient:_eglWaitClient,eglWaitGL:_eglWaitGL,eglWaitNative:_eglWaitNative,ellipseColor:_ellipseColor,ellipseRGBA:_ellipseRGBA,emscripten_SDL_SetEventHandler:_emscripten_SDL_SetEventHandler,emscripten_asm_const_async_on_main_thread:_emscripten_asm_const_async_on_main_thread,emscripten_asm_const_double:_emscripten_asm_const_double,emscripten_asm_const_double_sync_on_main_thread:_emscripten_asm_const_double_sync_on_main_thread,emscripten_asm_const_int:_emscripten_asm_const_int,emscripten_asm_const_int_sync_on_main_thread:_emscripten_asm_const_int_sync_on_main_thread,emscripten_asm_const_ptr:_emscripten_asm_const_ptr,emscripten_asm_const_ptr_sync_on_main_thread:_emscripten_asm_const_ptr_sync_on_main_thread,emscripten_async_call:_emscripten_async_call,emscripten_async_load_script:_emscripten_async_load_script,emscripten_async_run_script:_emscripten_async_run_script,emscripten_async_wget:_emscripten_async_wget,emscripten_async_wget2:_emscripten_async_wget2,emscripten_async_wget2_abort:_emscripten_async_wget2_abort,emscripten_async_wget2_data:_emscripten_async_wget2_data,emscripten_async_wget_data:_emscripten_async_wget_data,emscripten_call_worker:_emscripten_call_worker,emscripten_cancel_animation_frame:_emscripten_cancel_animation_frame,emscripten_cancel_main_loop:_emscripten_cancel_main_loop,emscripten_clear_immediate:_emscripten_clear_immediate,emscripten_clear_interval:_emscripten_clear_interval,emscripten_clear_timeout:_emscripten_clear_timeout,emscripten_console_error:_emscripten_console_error,emscripten_console_log:_emscripten_console_log,emscripten_console_warn:_emscripten_console_warn,emscripten_create_worker:_emscripten_create_worker,emscripten_date_now:_emscripten_date_now,emscripten_debugger:_emscripten_debugger,emscripten_destroy_worker:_emscripten_destroy_worker,emscripten_enter_soft_fullscreen:_emscripten_enter_soft_fullscreen,emscripten_err:_emscripten_err,emscripten_errn:_emscripten_errn,emscripten_exit_fullscreen:_emscripten_exit_fullscreen,emscripten_exit_pointerlock:_emscripten_exit_pointerlock,emscripten_exit_soft_fullscreen:_emscripten_exit_soft_fullscreen,emscripten_exit_with_live_runtime:_emscripten_exit_with_live_runtime,emscripten_force_exit:_emscripten_force_exit,emscripten_get_battery_status:_emscripten_get_battery_status,emscripten_get_callstack:_emscripten_get_callstack,emscripten_get_canvas_element_size:_emscripten_get_canvas_element_size,emscripten_get_canvas_size:_emscripten_get_canvas_size,emscripten_get_compiler_setting:_emscripten_get_compiler_setting,emscripten_get_device_pixel_ratio:_emscripten_get_device_pixel_ratio,emscripten_get_devicemotion_status:_emscripten_get_devicemotion_status,emscripten_get_deviceorientation_status:_emscripten_get_deviceorientation_status,emscripten_get_element_css_size:_emscripten_get_element_css_size,emscripten_get_fullscreen_status:_emscripten_get_fullscreen_status,emscripten_get_gamepad_status:_emscripten_get_gamepad_status,emscripten_get_heap_max:_emscripten_get_heap_max,emscripten_get_main_loop_timing:_emscripten_get_main_loop_timing,emscripten_get_module_name:_emscripten_get_module_name,emscripten_get_mouse_status:_emscripten_get_mouse_status,emscripten_get_now:_emscripten_get_now,emscripten_get_now_res:_emscripten_get_now_res,emscripten_get_num_gamepads:_emscripten_get_num_gamepads,emscripten_get_orientation_status:_emscripten_get_orientation_status,emscripten_get_pointerlock_status:_emscripten_get_pointerlock_status,emscripten_get_preloaded_image_data:_emscripten_get_preloaded_image_data,emscripten_get_preloaded_image_data_from_FILE:_emscripten_get_preloaded_image_data_from_FILE,emscripten_get_screen_size:_emscripten_get_screen_size,emscripten_get_visibility_status:_emscripten_get_visibility_status,emscripten_get_window_title:_emscripten_get_window_title,emscripten_get_worker_queue_size:_emscripten_get_worker_queue_size,emscripten_glActiveTexture:_emscripten_glActiveTexture,emscripten_glAttachShader:_emscripten_glAttachShader,emscripten_glBegin:_emscripten_glBegin,emscripten_glBeginQueryEXT:_emscripten_glBeginQueryEXT,emscripten_glBindAttribLocation:_emscripten_glBindAttribLocation,emscripten_glBindBuffer:_emscripten_glBindBuffer,emscripten_glBindFramebuffer:_emscripten_glBindFramebuffer,emscripten_glBindRenderbuffer:_emscripten_glBindRenderbuffer,emscripten_glBindTexture:_emscripten_glBindTexture,emscripten_glBindVertexArray:_emscripten_glBindVertexArray,emscripten_glBindVertexArrayOES:_emscripten_glBindVertexArrayOES,emscripten_glBlendColor:_emscripten_glBlendColor,emscripten_glBlendEquation:_emscripten_glBlendEquation,emscripten_glBlendEquationSeparate:_emscripten_glBlendEquationSeparate,emscripten_glBlendFunc:_emscripten_glBlendFunc,emscripten_glBlendFuncSeparate:_emscripten_glBlendFuncSeparate,emscripten_glBufferData:_emscripten_glBufferData,emscripten_glBufferSubData:_emscripten_glBufferSubData,emscripten_glCheckFramebufferStatus:_emscripten_glCheckFramebufferStatus,emscripten_glClear:_emscripten_glClear,emscripten_glClearColor:_emscripten_glClearColor,emscripten_glClearDepth:_emscripten_glClearDepth,emscripten_glClearDepthf:_emscripten_glClearDepthf,emscripten_glClearStencil:_emscripten_glClearStencil,emscripten_glColorMask:_emscripten_glColorMask,emscripten_glCompileShader:_emscripten_glCompileShader,emscripten_glCompressedTexImage2D:_emscripten_glCompressedTexImage2D,emscripten_glCompressedTexSubImage2D:_emscripten_glCompressedTexSubImage2D,emscripten_glCopyTexImage2D:_emscripten_glCopyTexImage2D,emscripten_glCopyTexSubImage2D:_emscripten_glCopyTexSubImage2D,emscripten_glCreateProgram:_emscripten_glCreateProgram,emscripten_glCreateShader:_emscripten_glCreateShader,emscripten_glCullFace:_emscripten_glCullFace,emscripten_glDeleteBuffers:_emscripten_glDeleteBuffers,emscripten_glDeleteFramebuffers:_emscripten_glDeleteFramebuffers,emscripten_glDeleteProgram:_emscripten_glDeleteProgram,emscripten_glDeleteQueriesEXT:_emscripten_glDeleteQueriesEXT,emscripten_glDeleteRenderbuffers:_emscripten_glDeleteRenderbuffers,emscripten_glDeleteShader:_emscripten_glDeleteShader,emscripten_glDeleteTextures:_emscripten_glDeleteTextures,emscripten_glDeleteVertexArrays:_emscripten_glDeleteVertexArrays,emscripten_glDeleteVertexArraysOES:_emscripten_glDeleteVertexArraysOES,emscripten_glDepthFunc:_emscripten_glDepthFunc,emscripten_glDepthMask:_emscripten_glDepthMask,emscripten_glDepthRange:_emscripten_glDepthRange,emscripten_glDepthRangef:_emscripten_glDepthRangef,emscripten_glDetachShader:_emscripten_glDetachShader,emscripten_glDisable:_emscripten_glDisable,emscripten_glDisableVertexAttribArray:_emscripten_glDisableVertexAttribArray,emscripten_glDrawArrays:_emscripten_glDrawArrays,emscripten_glDrawArraysInstanced:_emscripten_glDrawArraysInstanced,emscripten_glDrawArraysInstancedANGLE:_emscripten_glDrawArraysInstancedANGLE,emscripten_glDrawArraysInstancedARB:_emscripten_glDrawArraysInstancedARB,emscripten_glDrawArraysInstancedEXT:_emscripten_glDrawArraysInstancedEXT,emscripten_glDrawArraysInstancedNV:_emscripten_glDrawArraysInstancedNV,emscripten_glDrawBuffers:_emscripten_glDrawBuffers,emscripten_glDrawBuffersEXT:_emscripten_glDrawBuffersEXT,emscripten_glDrawBuffersWEBGL:_emscripten_glDrawBuffersWEBGL,emscripten_glDrawElements:_emscripten_glDrawElements,emscripten_glDrawElementsInstanced:_emscripten_glDrawElementsInstanced,emscripten_glDrawElementsInstancedANGLE:_emscripten_glDrawElementsInstancedANGLE,emscripten_glDrawElementsInstancedARB:_emscripten_glDrawElementsInstancedARB,emscripten_glDrawElementsInstancedEXT:_emscripten_glDrawElementsInstancedEXT,emscripten_glDrawElementsInstancedNV:_emscripten_glDrawElementsInstancedNV,emscripten_glEnable:_emscripten_glEnable,emscripten_glEnableVertexAttribArray:_emscripten_glEnableVertexAttribArray,emscripten_glEndQueryEXT:_emscripten_glEndQueryEXT,emscripten_glFinish:_emscripten_glFinish,emscripten_glFlush:_emscripten_glFlush,emscripten_glFramebufferRenderbuffer:_emscripten_glFramebufferRenderbuffer,emscripten_glFramebufferTexture2D:_emscripten_glFramebufferTexture2D,emscripten_glFrontFace:_emscripten_glFrontFace,emscripten_glGenBuffers:_emscripten_glGenBuffers,emscripten_glGenFramebuffers:_emscripten_glGenFramebuffers,emscripten_glGenQueriesEXT:_emscripten_glGenQueriesEXT,emscripten_glGenRenderbuffers:_emscripten_glGenRenderbuffers,emscripten_glGenTextures:_emscripten_glGenTextures,emscripten_glGenVertexArrays:_emscripten_glGenVertexArrays,emscripten_glGenVertexArraysOES:_emscripten_glGenVertexArraysOES,emscripten_glGenerateMipmap:_emscripten_glGenerateMipmap,emscripten_glGetActiveAttrib:_emscripten_glGetActiveAttrib,emscripten_glGetActiveUniform:_emscripten_glGetActiveUniform,emscripten_glGetAttachedShaders:_emscripten_glGetAttachedShaders,emscripten_glGetAttribLocation:_emscripten_glGetAttribLocation,emscripten_glGetBooleanv:_emscripten_glGetBooleanv,emscripten_glGetBufferParameteriv:_emscripten_glGetBufferParameteriv,emscripten_glGetError:_emscripten_glGetError,emscripten_glGetFloatv:_emscripten_glGetFloatv,emscripten_glGetFramebufferAttachmentParameteriv:_emscripten_glGetFramebufferAttachmentParameteriv,emscripten_glGetIntegerv:_emscripten_glGetIntegerv,emscripten_glGetProgramInfoLog:_emscripten_glGetProgramInfoLog,emscripten_glGetProgramiv:_emscripten_glGetProgramiv,emscripten_glGetQueryObjecti64vEXT:_emscripten_glGetQueryObjecti64vEXT,emscripten_glGetQueryObjectivEXT:_emscripten_glGetQueryObjectivEXT,emscripten_glGetQueryObjectui64vEXT:_emscripten_glGetQueryObjectui64vEXT,emscripten_glGetQueryObjectuivEXT:_emscripten_glGetQueryObjectuivEXT,emscripten_glGetQueryivEXT:_emscripten_glGetQueryivEXT,emscripten_glGetRenderbufferParameteriv:_emscripten_glGetRenderbufferParameteriv,emscripten_glGetShaderInfoLog:_emscripten_glGetShaderInfoLog,emscripten_glGetShaderPrecisionFormat:_emscripten_glGetShaderPrecisionFormat,emscripten_glGetShaderSource:_emscripten_glGetShaderSource,emscripten_glGetShaderiv:_emscripten_glGetShaderiv,emscripten_glGetString:_emscripten_glGetString,emscripten_glGetTexParameterfv:_emscripten_glGetTexParameterfv,emscripten_glGetTexParameteriv:_emscripten_glGetTexParameteriv,emscripten_glGetUniformLocation:_emscripten_glGetUniformLocation,emscripten_glGetUniformfv:_emscripten_glGetUniformfv,emscripten_glGetUniformiv:_emscripten_glGetUniformiv,emscripten_glGetVertexAttribPointerv:_emscripten_glGetVertexAttribPointerv,emscripten_glGetVertexAttribfv:_emscripten_glGetVertexAttribfv,emscripten_glGetVertexAttribiv:_emscripten_glGetVertexAttribiv,emscripten_glHint:_emscripten_glHint,emscripten_glIsBuffer:_emscripten_glIsBuffer,emscripten_glIsEnabled:_emscripten_glIsEnabled,emscripten_glIsFramebuffer:_emscripten_glIsFramebuffer,emscripten_glIsProgram:_emscripten_glIsProgram,emscripten_glIsQueryEXT:_emscripten_glIsQueryEXT,emscripten_glIsRenderbuffer:_emscripten_glIsRenderbuffer,emscripten_glIsShader:_emscripten_glIsShader,emscripten_glIsTexture:_emscripten_glIsTexture,emscripten_glIsVertexArray:_emscripten_glIsVertexArray,emscripten_glIsVertexArrayOES:_emscripten_glIsVertexArrayOES,emscripten_glLineWidth:_emscripten_glLineWidth,emscripten_glLinkProgram:_emscripten_glLinkProgram,emscripten_glLoadIdentity:_emscripten_glLoadIdentity,emscripten_glMatrixMode:_emscripten_glMatrixMode,emscripten_glMultiDrawArrays:_emscripten_glMultiDrawArrays,emscripten_glMultiDrawArraysANGLE:_emscripten_glMultiDrawArraysANGLE,emscripten_glMultiDrawArraysInstancedANGLE:_emscripten_glMultiDrawArraysInstancedANGLE,emscripten_glMultiDrawArraysInstancedWEBGL:_emscripten_glMultiDrawArraysInstancedWEBGL,emscripten_glMultiDrawArraysWEBGL:_emscripten_glMultiDrawArraysWEBGL,emscripten_glMultiDrawElements:_emscripten_glMultiDrawElements,emscripten_glMultiDrawElementsANGLE:_emscripten_glMultiDrawElementsANGLE,emscripten_glMultiDrawElementsInstancedANGLE:_emscripten_glMultiDrawElementsInstancedANGLE,emscripten_glMultiDrawElementsInstancedWEBGL:_emscripten_glMultiDrawElementsInstancedWEBGL,emscripten_glMultiDrawElementsWEBGL:_emscripten_glMultiDrawElementsWEBGL,emscripten_glPixelStorei:_emscripten_glPixelStorei,emscripten_glPolygonOffset:_emscripten_glPolygonOffset,emscripten_glQueryCounterEXT:_emscripten_glQueryCounterEXT,emscripten_glReadPixels:_emscripten_glReadPixels,emscripten_glReleaseShaderCompiler:_emscripten_glReleaseShaderCompiler,emscripten_glRenderbufferStorage:_emscripten_glRenderbufferStorage,emscripten_glSampleCoverage:_emscripten_glSampleCoverage,emscripten_glScissor:_emscripten_glScissor,emscripten_glShaderBinary:_emscripten_glShaderBinary,emscripten_glShaderSource:_emscripten_glShaderSource,emscripten_glStencilFunc:_emscripten_glStencilFunc,emscripten_glStencilFuncSeparate:_emscripten_glStencilFuncSeparate,emscripten_glStencilMask:_emscripten_glStencilMask,emscripten_glStencilMaskSeparate:_emscripten_glStencilMaskSeparate,emscripten_glStencilOp:_emscripten_glStencilOp,emscripten_glStencilOpSeparate:_emscripten_glStencilOpSeparate,emscripten_glTexImage2D:_emscripten_glTexImage2D,emscripten_glTexParameterf:_emscripten_glTexParameterf,emscripten_glTexParameterfv:_emscripten_glTexParameterfv,emscripten_glTexParameteri:_emscripten_glTexParameteri,emscripten_glTexParameteriv:_emscripten_glTexParameteriv,emscripten_glTexSubImage2D:_emscripten_glTexSubImage2D,emscripten_glUniform1f:_emscripten_glUniform1f,emscripten_glUniform1fv:_emscripten_glUniform1fv,emscripten_glUniform1i:_emscripten_glUniform1i,emscripten_glUniform1iv:_emscripten_glUniform1iv,emscripten_glUniform2f:_emscripten_glUniform2f,emscripten_glUniform2fv:_emscripten_glUniform2fv,emscripten_glUniform2i:_emscripten_glUniform2i,emscripten_glUniform2iv:_emscripten_glUniform2iv,emscripten_glUniform3f:_emscripten_glUniform3f,emscripten_glUniform3fv:_emscripten_glUniform3fv,emscripten_glUniform3i:_emscripten_glUniform3i,emscripten_glUniform3iv:_emscripten_glUniform3iv,emscripten_glUniform4f:_emscripten_glUniform4f,emscripten_glUniform4fv:_emscripten_glUniform4fv,emscripten_glUniform4i:_emscripten_glUniform4i,emscripten_glUniform4iv:_emscripten_glUniform4iv,emscripten_glUniformMatrix2fv:_emscripten_glUniformMatrix2fv,emscripten_glUniformMatrix3fv:_emscripten_glUniformMatrix3fv,emscripten_glUniformMatrix4fv:_emscripten_glUniformMatrix4fv,emscripten_glUseProgram:_emscripten_glUseProgram,emscripten_glValidateProgram:_emscripten_glValidateProgram,emscripten_glVertexAttrib1f:_emscripten_glVertexAttrib1f,emscripten_glVertexAttrib1fv:_emscripten_glVertexAttrib1fv,emscripten_glVertexAttrib2f:_emscripten_glVertexAttrib2f,emscripten_glVertexAttrib2fv:_emscripten_glVertexAttrib2fv,emscripten_glVertexAttrib3f:_emscripten_glVertexAttrib3f,emscripten_glVertexAttrib3fv:_emscripten_glVertexAttrib3fv,emscripten_glVertexAttrib4f:_emscripten_glVertexAttrib4f,emscripten_glVertexAttrib4fv:_emscripten_glVertexAttrib4fv,emscripten_glVertexAttribDivisor:_emscripten_glVertexAttribDivisor,emscripten_glVertexAttribDivisorANGLE:_emscripten_glVertexAttribDivisorANGLE,emscripten_glVertexAttribDivisorARB:_emscripten_glVertexAttribDivisorARB,emscripten_glVertexAttribDivisorEXT:_emscripten_glVertexAttribDivisorEXT,emscripten_glVertexAttribDivisorNV:_emscripten_glVertexAttribDivisorNV,emscripten_glVertexAttribPointer:_emscripten_glVertexAttribPointer,emscripten_glVertexPointer:_emscripten_glVertexPointer,emscripten_glViewport:_emscripten_glViewport,emscripten_has_asyncify:_emscripten_has_asyncify,emscripten_hide_mouse:_emscripten_hide_mouse,emscripten_html5_remove_all_event_listeners:_emscripten_html5_remove_all_event_listeners,emscripten_is_main_browser_thread:_emscripten_is_main_browser_thread,emscripten_is_webgl_context_lost:_emscripten_is_webgl_context_lost,emscripten_lock_orientation:_emscripten_lock_orientation,emscripten_log:_emscripten_log,emscripten_math_acos:_emscripten_math_acos,emscripten_math_acosh:_emscripten_math_acosh,emscripten_math_asin:_emscripten_math_asin,emscripten_math_asinh:_emscripten_math_asinh,emscripten_math_atan:_emscripten_math_atan,emscripten_math_atan2:_emscripten_math_atan2,emscripten_math_atanh:_emscripten_math_atanh,emscripten_math_cbrt:_emscripten_math_cbrt,emscripten_math_cos:_emscripten_math_cos,emscripten_math_cosh:_emscripten_math_cosh,emscripten_math_exp:_emscripten_math_exp,emscripten_math_expm1:_emscripten_math_expm1,emscripten_math_fmod:_emscripten_math_fmod,emscripten_math_hypot:_emscripten_math_hypot,emscripten_math_log:_emscripten_math_log,emscripten_math_log10:_emscripten_math_log10,emscripten_math_log1p:_emscripten_math_log1p,emscripten_math_log2:_emscripten_math_log2,emscripten_math_pow:_emscripten_math_pow,emscripten_math_random:_emscripten_math_random,emscripten_math_round:_emscripten_math_round,emscripten_math_sign:_emscripten_math_sign,emscripten_math_sin:_emscripten_math_sin,emscripten_math_sinh:_emscripten_math_sinh,emscripten_math_sqrt:_emscripten_math_sqrt,emscripten_math_tan:_emscripten_math_tan,emscripten_math_tanh:_emscripten_math_tanh,emscripten_notify_memory_growth:_emscripten_notify_memory_growth,emscripten_out:_emscripten_out,emscripten_outn:_emscripten_outn,emscripten_pause_main_loop:_emscripten_pause_main_loop,emscripten_pc_get_column:_emscripten_pc_get_column,emscripten_pc_get_file:_emscripten_pc_get_file,emscripten_pc_get_function:_emscripten_pc_get_function,emscripten_pc_get_line:_emscripten_pc_get_line,emscripten_performance_now:_emscripten_performance_now,emscripten_print_double:_emscripten_print_double,emscripten_promise_all:_emscripten_promise_all,emscripten_promise_all_settled:_emscripten_promise_all_settled,emscripten_promise_any:_emscripten_promise_any,emscripten_promise_await:_emscripten_promise_await,emscripten_promise_create:_emscripten_promise_create,emscripten_promise_destroy:_emscripten_promise_destroy,emscripten_promise_race:_emscripten_promise_race,emscripten_promise_resolve:_emscripten_promise_resolve,emscripten_promise_then:_emscripten_promise_then,emscripten_random:_emscripten_random,emscripten_request_animation_frame:_emscripten_request_animation_frame,emscripten_request_animation_frame_loop:_emscripten_request_animation_frame_loop,emscripten_request_fullscreen:_emscripten_request_fullscreen,emscripten_request_fullscreen_strategy:_emscripten_request_fullscreen_strategy,emscripten_request_pointerlock:_emscripten_request_pointerlock,emscripten_resize_heap:_emscripten_resize_heap,emscripten_resume_main_loop:_emscripten_resume_main_loop,emscripten_return_address:_emscripten_return_address,emscripten_run_preload_plugins:_emscripten_run_preload_plugins,emscripten_run_preload_plugins_data:_emscripten_run_preload_plugins_data,emscripten_run_script:_emscripten_run_script,emscripten_run_script_int:_emscripten_run_script_int,emscripten_run_script_string:_emscripten_run_script_string,emscripten_runtime_keepalive_check:_emscripten_runtime_keepalive_check,emscripten_runtime_keepalive_pop:_emscripten_runtime_keepalive_pop,emscripten_runtime_keepalive_push:_emscripten_runtime_keepalive_push,emscripten_sample_gamepad_data:_emscripten_sample_gamepad_data,emscripten_set_batterychargingchange_callback_on_thread:_emscripten_set_batterychargingchange_callback_on_thread,emscripten_set_batterylevelchange_callback_on_thread:_emscripten_set_batterylevelchange_callback_on_thread,emscripten_set_beforeunload_callback_on_thread:_emscripten_set_beforeunload_callback_on_thread,emscripten_set_blur_callback_on_thread:_emscripten_set_blur_callback_on_thread,emscripten_set_canvas_element_size:_emscripten_set_canvas_element_size,emscripten_set_canvas_size:_emscripten_set_canvas_size,emscripten_set_click_callback_on_thread:_emscripten_set_click_callback_on_thread,emscripten_set_dblclick_callback_on_thread:_emscripten_set_dblclick_callback_on_thread,emscripten_set_devicemotion_callback_on_thread:_emscripten_set_devicemotion_callback_on_thread,emscripten_set_deviceorientation_callback_on_thread:_emscripten_set_deviceorientation_callback_on_thread,emscripten_set_element_css_size:_emscripten_set_element_css_size,emscripten_set_focus_callback_on_thread:_emscripten_set_focus_callback_on_thread,emscripten_set_focusin_callback_on_thread:_emscripten_set_focusin_callback_on_thread,emscripten_set_focusout_callback_on_thread:_emscripten_set_focusout_callback_on_thread,emscripten_set_fullscreenchange_callback_on_thread:_emscripten_set_fullscreenchange_callback_on_thread,emscripten_set_gamepadconnected_callback_on_thread:_emscripten_set_gamepadconnected_callback_on_thread,emscripten_set_gamepaddisconnected_callback_on_thread:_emscripten_set_gamepaddisconnected_callback_on_thread,emscripten_set_immediate:_emscripten_set_immediate,emscripten_set_immediate_loop:_emscripten_set_immediate_loop,emscripten_set_interval:_emscripten_set_interval,emscripten_set_keydown_callback_on_thread:_emscripten_set_keydown_callback_on_thread,emscripten_set_keypress_callback_on_thread:_emscripten_set_keypress_callback_on_thread,emscripten_set_keyup_callback_on_thread:_emscripten_set_keyup_callback_on_thread,emscripten_set_main_loop:_emscripten_set_main_loop,emscripten_set_main_loop_arg:_emscripten_set_main_loop_arg,emscripten_set_main_loop_expected_blockers:_emscripten_set_main_loop_expected_blockers,emscripten_set_main_loop_timing:_emscripten_set_main_loop_timing,emscripten_set_mousedown_callback_on_thread:_emscripten_set_mousedown_callback_on_thread,emscripten_set_mouseenter_callback_on_thread:_emscripten_set_mouseenter_callback_on_thread,emscripten_set_mouseleave_callback_on_thread:_emscripten_set_mouseleave_callback_on_thread,emscripten_set_mousemove_callback_on_thread:_emscripten_set_mousemove_callback_on_thread,emscripten_set_mouseout_callback_on_thread:_emscripten_set_mouseout_callback_on_thread,emscripten_set_mouseover_callback_on_thread:_emscripten_set_mouseover_callback_on_thread,emscripten_set_mouseup_callback_on_thread:_emscripten_set_mouseup_callback_on_thread,emscripten_set_orientationchange_callback_on_thread:_emscripten_set_orientationchange_callback_on_thread,emscripten_set_pointerlockchange_callback_on_thread:_emscripten_set_pointerlockchange_callback_on_thread,emscripten_set_pointerlockerror_callback_on_thread:_emscripten_set_pointerlockerror_callback_on_thread,emscripten_set_resize_callback_on_thread:_emscripten_set_resize_callback_on_thread,emscripten_set_scroll_callback_on_thread:_emscripten_set_scroll_callback_on_thread,emscripten_set_socket_close_callback:_emscripten_set_socket_close_callback,emscripten_set_socket_connection_callback:_emscripten_set_socket_connection_callback,emscripten_set_socket_error_callback:_emscripten_set_socket_error_callback,emscripten_set_socket_listen_callback:_emscripten_set_socket_listen_callback,emscripten_set_socket_message_callback:_emscripten_set_socket_message_callback,emscripten_set_socket_open_callback:_emscripten_set_socket_open_callback,emscripten_set_timeout:_emscripten_set_timeout,emscripten_set_timeout_loop:_emscripten_set_timeout_loop,emscripten_set_touchcancel_callback_on_thread:_emscripten_set_touchcancel_callback_on_thread,emscripten_set_touchend_callback_on_thread:_emscripten_set_touchend_callback_on_thread,emscripten_set_touchmove_callback_on_thread:_emscripten_set_touchmove_callback_on_thread,emscripten_set_touchstart_callback_on_thread:_emscripten_set_touchstart_callback_on_thread,emscripten_set_visibilitychange_callback_on_thread:_emscripten_set_visibilitychange_callback_on_thread,emscripten_set_webglcontextlost_callback_on_thread:_emscripten_set_webglcontextlost_callback_on_thread,emscripten_set_webglcontextrestored_callback_on_thread:_emscripten_set_webglcontextrestored_callback_on_thread,emscripten_set_wheel_callback_on_thread:_emscripten_set_wheel_callback_on_thread,emscripten_set_window_title:_emscripten_set_window_title,emscripten_stack_snapshot:_emscripten_stack_snapshot,emscripten_stack_unwind_buffer:_emscripten_stack_unwind_buffer,emscripten_supports_offscreencanvas:_emscripten_supports_offscreencanvas,emscripten_throw_number:_emscripten_throw_number,emscripten_throw_string:_emscripten_throw_string,emscripten_unlock_orientation:_emscripten_unlock_orientation,emscripten_unwind_to_js_event_loop:_emscripten_unwind_to_js_event_loop,emscripten_vibrate:_emscripten_vibrate,emscripten_vibrate_pattern:_emscripten_vibrate_pattern,emscripten_webgl_commit_frame:_emscripten_webgl_commit_frame,emscripten_webgl_create_context:_emscripten_webgl_create_context,emscripten_webgl_destroy_context:_emscripten_webgl_destroy_context,emscripten_webgl_do_commit_frame:_emscripten_webgl_do_commit_frame,emscripten_webgl_do_create_context:_emscripten_webgl_do_create_context,emscripten_webgl_do_get_current_context:_emscripten_webgl_do_get_current_context,emscripten_webgl_enable_ANGLE_instanced_arrays:_emscripten_webgl_enable_ANGLE_instanced_arrays,emscripten_webgl_enable_OES_vertex_array_object:_emscripten_webgl_enable_OES_vertex_array_object,emscripten_webgl_enable_WEBGL_draw_buffers:_emscripten_webgl_enable_WEBGL_draw_buffers,emscripten_webgl_enable_WEBGL_multi_draw:_emscripten_webgl_enable_WEBGL_multi_draw,emscripten_webgl_enable_extension:_emscripten_webgl_enable_extension,emscripten_webgl_get_context_attributes:_emscripten_webgl_get_context_attributes,emscripten_webgl_get_current_context:_emscripten_webgl_get_current_context,emscripten_webgl_get_drawing_buffer_size:_emscripten_webgl_get_drawing_buffer_size,emscripten_webgl_get_parameter_d:_emscripten_webgl_get_parameter_d,emscripten_webgl_get_parameter_i64v:_emscripten_webgl_get_parameter_i64v,emscripten_webgl_get_parameter_o:_emscripten_webgl_get_parameter_o,emscripten_webgl_get_parameter_utf8:_emscripten_webgl_get_parameter_utf8,emscripten_webgl_get_parameter_v:_emscripten_webgl_get_parameter_v,emscripten_webgl_get_program_info_log_utf8:_emscripten_webgl_get_program_info_log_utf8,emscripten_webgl_get_program_parameter_d:_emscripten_webgl_get_program_parameter_d,emscripten_webgl_get_shader_info_log_utf8:_emscripten_webgl_get_shader_info_log_utf8,emscripten_webgl_get_shader_parameter_d:_emscripten_webgl_get_shader_parameter_d,emscripten_webgl_get_shader_source_utf8:_emscripten_webgl_get_shader_source_utf8,emscripten_webgl_get_supported_extensions:_emscripten_webgl_get_supported_extensions,emscripten_webgl_get_uniform_d:_emscripten_webgl_get_uniform_d,emscripten_webgl_get_uniform_v:_emscripten_webgl_get_uniform_v,emscripten_webgl_get_vertex_attrib_d:_emscripten_webgl_get_vertex_attrib_d,emscripten_webgl_get_vertex_attrib_o:_emscripten_webgl_get_vertex_attrib_o,emscripten_webgl_get_vertex_attrib_v:_emscripten_webgl_get_vertex_attrib_v,emscripten_webgl_make_context_current:_emscripten_webgl_make_context_current,emscripten_websocket_close:_emscripten_websocket_close,emscripten_websocket_deinitialize:_emscripten_websocket_deinitialize,emscripten_websocket_delete:_emscripten_websocket_delete,emscripten_websocket_get_buffered_amount:_emscripten_websocket_get_buffered_amount,emscripten_websocket_get_extensions:_emscripten_websocket_get_extensions,emscripten_websocket_get_extensions_length:_emscripten_websocket_get_extensions_length,emscripten_websocket_get_protocol:_emscripten_websocket_get_protocol,emscripten_websocket_get_protocol_length:_emscripten_websocket_get_protocol_length,emscripten_websocket_get_ready_state:_emscripten_websocket_get_ready_state,emscripten_websocket_get_url:_emscripten_websocket_get_url,emscripten_websocket_get_url_length:_emscripten_websocket_get_url_length,emscripten_websocket_is_supported:_emscripten_websocket_is_supported,emscripten_websocket_new:_emscripten_websocket_new,emscripten_websocket_send_binary:_emscripten_websocket_send_binary,emscripten_websocket_send_utf8_text:_emscripten_websocket_send_utf8_text,emscripten_websocket_set_onclose_callback_on_thread:_emscripten_websocket_set_onclose_callback_on_thread,emscripten_websocket_set_onerror_callback_on_thread:_emscripten_websocket_set_onerror_callback_on_thread,emscripten_websocket_set_onmessage_callback_on_thread:_emscripten_websocket_set_onmessage_callback_on_thread,emscripten_websocket_set_onopen_callback_on_thread:_emscripten_websocket_set_onopen_callback_on_thread,endprotoent:_endprotoent,environ_get:_environ_get,environ_sizes_get:_environ_sizes_get,exit:_exit,fail_test:fail_test,fd_close:_fd_close,fd_fdstat_get:_fd_fdstat_get,fd_pread:_fd_pread,fd_pwrite:_fd_pwrite,fd_read:_fd_read,fd_seek:_fd_seek,fd_sync:_fd_sync,fd_write:_fd_write,ffi_call_js:ffi_call_js,ffi_closure_alloc_js:ffi_closure_alloc_js,ffi_closure_free_js:ffi_closure_free_js,ffi_prep_closure_loc_js:ffi_prep_closure_loc_js,filledEllipseColor:_filledEllipseColor,filledEllipseRGBA:_filledEllipseRGBA,gc_register_proxies:gc_register_proxies,get_async_js_call_done_callback:get_async_js_call_done_callback,get_length_helper:get_length_helper,get_length_string:get_length_string,get_suspender:get_suspender,getaddrinfo:_getaddrinfo,getentropy:_getentropy,getnameinfo:_getnameinfo,getprotobyname:_getprotobyname,getprotobynumber:_getprotobynumber,getprotoent:_getprotoent,glActiveTexture:_glActiveTexture,glAttachShader:_glAttachShader,glBegin:_glBegin,glBeginQueryEXT:_glBeginQueryEXT,glBindAttribLocation:_glBindAttribLocation,glBindBuffer:_glBindBuffer,glBindFramebuffer:_glBindFramebuffer,glBindRenderbuffer:_glBindRenderbuffer,glBindTexture:_glBindTexture,glBindVertexArray:_glBindVertexArray,glBindVertexArrayOES:_glBindVertexArrayOES,glBlendColor:_glBlendColor,glBlendEquation:_glBlendEquation,glBlendEquationSeparate:_glBlendEquationSeparate,glBlendFunc:_glBlendFunc,glBlendFuncSeparate:_glBlendFuncSeparate,glBufferData:_glBufferData,glBufferSubData:_glBufferSubData,glCheckFramebufferStatus:_glCheckFramebufferStatus,glClear:_glClear,glClearColor:_glClearColor,glClearDepth:_glClearDepth,glClearDepthf:_glClearDepthf,glClearStencil:_glClearStencil,glColorMask:_glColorMask,glCompileShader:_glCompileShader,glCompressedTexImage2D:_glCompressedTexImage2D,glCompressedTexSubImage2D:_glCompressedTexSubImage2D,glCopyTexImage2D:_glCopyTexImage2D,glCopyTexSubImage2D:_glCopyTexSubImage2D,glCreateProgram:_glCreateProgram,glCreateShader:_glCreateShader,glCullFace:_glCullFace,glDeleteBuffers:_glDeleteBuffers,glDeleteFramebuffers:_glDeleteFramebuffers,glDeleteProgram:_glDeleteProgram,glDeleteQueriesEXT:_glDeleteQueriesEXT,glDeleteRenderbuffers:_glDeleteRenderbuffers,glDeleteShader:_glDeleteShader,glDeleteTextures:_glDeleteTextures,glDeleteVertexArrays:_glDeleteVertexArrays,glDeleteVertexArraysOES:_glDeleteVertexArraysOES,glDepthFunc:_glDepthFunc,glDepthMask:_glDepthMask,glDepthRange:_glDepthRange,glDepthRangef:_glDepthRangef,glDetachShader:_glDetachShader,glDisable:_glDisable,glDisableVertexAttribArray:_glDisableVertexAttribArray,glDrawArrays:_glDrawArrays,glDrawArraysInstanced:_glDrawArraysInstanced,glDrawArraysInstancedANGLE:_glDrawArraysInstancedANGLE,glDrawArraysInstancedARB:_glDrawArraysInstancedARB,glDrawArraysInstancedEXT:_glDrawArraysInstancedEXT,glDrawArraysInstancedNV:_glDrawArraysInstancedNV,glDrawBuffers:_glDrawBuffers,glDrawBuffersEXT:_glDrawBuffersEXT,glDrawBuffersWEBGL:_glDrawBuffersWEBGL,glDrawElements:_glDrawElements,glDrawElementsInstanced:_glDrawElementsInstanced,glDrawElementsInstancedANGLE:_glDrawElementsInstancedANGLE,glDrawElementsInstancedARB:_glDrawElementsInstancedARB,glDrawElementsInstancedEXT:_glDrawElementsInstancedEXT,glDrawElementsInstancedNV:_glDrawElementsInstancedNV,glEnable:_glEnable,glEnableVertexAttribArray:_glEnableVertexAttribArray,glEndQueryEXT:_glEndQueryEXT,glFinish:_glFinish,glFlush:_glFlush,glFramebufferRenderbuffer:_glFramebufferRenderbuffer,glFramebufferTexture2D:_glFramebufferTexture2D,glFrontFace:_glFrontFace,glGenBuffers:_glGenBuffers,glGenFramebuffers:_glGenFramebuffers,glGenQueriesEXT:_glGenQueriesEXT,glGenRenderbuffers:_glGenRenderbuffers,glGenTextures:_glGenTextures,glGenVertexArrays:_glGenVertexArrays,glGenVertexArraysOES:_glGenVertexArraysOES,glGenerateMipmap:_glGenerateMipmap,glGetActiveAttrib:_glGetActiveAttrib,glGetActiveUniform:_glGetActiveUniform,glGetAttachedShaders:_glGetAttachedShaders,glGetAttribLocation:_glGetAttribLocation,glGetBooleanv:_glGetBooleanv,glGetBufferParameteriv:_glGetBufferParameteriv,glGetError:_glGetError,glGetFloatv:_glGetFloatv,glGetFramebufferAttachmentParameteriv:_glGetFramebufferAttachmentParameteriv,glGetIntegerv:_glGetIntegerv,glGetProgramInfoLog:_glGetProgramInfoLog,glGetProgramiv:_glGetProgramiv,glGetQueryObjecti64vEXT:_glGetQueryObjecti64vEXT,glGetQueryObjectivEXT:_glGetQueryObjectivEXT,glGetQueryObjectui64vEXT:_glGetQueryObjectui64vEXT,glGetQueryObjectuivEXT:_glGetQueryObjectuivEXT,glGetQueryivEXT:_glGetQueryivEXT,glGetRenderbufferParameteriv:_glGetRenderbufferParameteriv,glGetShaderInfoLog:_glGetShaderInfoLog,glGetShaderPrecisionFormat:_glGetShaderPrecisionFormat,glGetShaderSource:_glGetShaderSource,glGetShaderiv:_glGetShaderiv,glGetString:_glGetString,glGetTexParameterfv:_glGetTexParameterfv,glGetTexParameteriv:_glGetTexParameteriv,glGetUniformLocation:_glGetUniformLocation,glGetUniformfv:_glGetUniformfv,glGetUniformiv:_glGetUniformiv,glGetVertexAttribPointerv:_glGetVertexAttribPointerv,glGetVertexAttribfv:_glGetVertexAttribfv,glGetVertexAttribiv:_glGetVertexAttribiv,glHint:_glHint,glIsBuffer:_glIsBuffer,glIsEnabled:_glIsEnabled,glIsFramebuffer:_glIsFramebuffer,glIsProgram:_glIsProgram,glIsQueryEXT:_glIsQueryEXT,glIsRenderbuffer:_glIsRenderbuffer,glIsShader:_glIsShader,glIsTexture:_glIsTexture,glIsVertexArray:_glIsVertexArray,glIsVertexArrayOES:_glIsVertexArrayOES,glLineWidth:_glLineWidth,glLinkProgram:_glLinkProgram,glLoadIdentity:_glLoadIdentity,glMatrixMode:_glMatrixMode,glMultiDrawArrays:_glMultiDrawArrays,glMultiDrawArraysANGLE:_glMultiDrawArraysANGLE,glMultiDrawArraysInstancedANGLE:_glMultiDrawArraysInstancedANGLE,glMultiDrawArraysInstancedWEBGL:_glMultiDrawArraysInstancedWEBGL,glMultiDrawArraysWEBGL:_glMultiDrawArraysWEBGL,glMultiDrawElements:_glMultiDrawElements,glMultiDrawElementsANGLE:_glMultiDrawElementsANGLE,glMultiDrawElementsInstancedANGLE:_glMultiDrawElementsInstancedANGLE,glMultiDrawElementsInstancedWEBGL:_glMultiDrawElementsInstancedWEBGL,glMultiDrawElementsWEBGL:_glMultiDrawElementsWEBGL,glPixelStorei:_glPixelStorei,glPolygonOffset:_glPolygonOffset,glQueryCounterEXT:_glQueryCounterEXT,glReadPixels:_glReadPixels,glReleaseShaderCompiler:_glReleaseShaderCompiler,glRenderbufferStorage:_glRenderbufferStorage,glSampleCoverage:_glSampleCoverage,glScissor:_glScissor,glShaderBinary:_glShaderBinary,glShaderSource:_glShaderSource,glStencilFunc:_glStencilFunc,glStencilFuncSeparate:_glStencilFuncSeparate,glStencilMask:_glStencilMask,glStencilMaskSeparate:_glStencilMaskSeparate,glStencilOp:_glStencilOp,glStencilOpSeparate:_glStencilOpSeparate,glTexImage2D:_glTexImage2D,glTexParameterf:_glTexParameterf,glTexParameterfv:_glTexParameterfv,glTexParameteri:_glTexParameteri,glTexParameteriv:_glTexParameteriv,glTexSubImage2D:_glTexSubImage2D,glUniform1f:_glUniform1f,glUniform1fv:_glUniform1fv,glUniform1i:_glUniform1i,glUniform1iv:_glUniform1iv,glUniform2f:_glUniform2f,glUniform2fv:_glUniform2fv,glUniform2i:_glUniform2i,glUniform2iv:_glUniform2iv,glUniform3f:_glUniform3f,glUniform3fv:_glUniform3fv,glUniform3i:_glUniform3i,glUniform3iv:_glUniform3iv,glUniform4f:_glUniform4f,glUniform4fv:_glUniform4fv,glUniform4i:_glUniform4i,glUniform4iv:_glUniform4iv,glUniformMatrix2fv:_glUniformMatrix2fv,glUniformMatrix3fv:_glUniformMatrix3fv,glUniformMatrix4fv:_glUniformMatrix4fv,glUseProgram:_glUseProgram,glValidateProgram:_glValidateProgram,glVertexAttrib1f:_glVertexAttrib1f,glVertexAttrib1fv:_glVertexAttrib1fv,glVertexAttrib2f:_glVertexAttrib2f,glVertexAttrib2fv:_glVertexAttrib2fv,glVertexAttrib3f:_glVertexAttrib3f,glVertexAttrib3fv:_glVertexAttrib3fv,glVertexAttrib4f:_glVertexAttrib4f,glVertexAttrib4fv:_glVertexAttrib4fv,glVertexAttribDivisor:_glVertexAttribDivisor,glVertexAttribDivisorANGLE:_glVertexAttribDivisorANGLE,glVertexAttribDivisorARB:_glVertexAttribDivisorARB,glVertexAttribDivisorEXT:_glVertexAttribDivisorEXT,glVertexAttribDivisorNV:_glVertexAttribDivisorNV,glVertexAttribPointer:_glVertexAttribPointer,glVertexPointer:_glVertexPointer,glViewport:_glViewport,handle_next_result_js:handle_next_result_js,hiwire_invalid_ref:hiwire_invalid_ref,invoke_diii:invoke_diii,invoke_fiii:invoke_fiii,invoke_i:invoke_i,invoke_ii:invoke_ii,invoke_iii:invoke_iii,invoke_iiii:invoke_iiii,invoke_iiiii:invoke_iiiii,invoke_iiiiid:invoke_iiiiid,invoke_iiiiii:invoke_iiiiii,invoke_iiiiiii:invoke_iiiiiii,invoke_iiiiiiii:invoke_iiiiiiii,invoke_iiiiiiiiiii:invoke_iiiiiiiiiii,invoke_iiiiiiiiiiii:invoke_iiiiiiiiiiii,invoke_iiiiiiiiiiiii:invoke_iiiiiiiiiiiii,invoke_iiiiij:invoke_iiiiij,invoke_iiiiijj:invoke_iiiiijj,invoke_iiji:invoke_iiji,invoke_j:invoke_j,invoke_ji:invoke_ji,invoke_jii:invoke_jii,invoke_jiii:invoke_jiii,invoke_jiiii:invoke_jiiii,invoke_v:invoke_v,invoke_vi:invoke_vi,invoke_vii:invoke_vii,invoke_viid:invoke_viid,invoke_viif:invoke_viif,invoke_viii:invoke_viii,invoke_viiidi:invoke_viiidi,invoke_viiifi:invoke_viiifi,invoke_viiii:invoke_viiii,invoke_viiiii:invoke_viiiii,invoke_viiiiii:invoke_viiiiii,invoke_viiiiiii:invoke_viiiiiii,invoke_viiiiiiiiii:invoke_viiiiiiiiii,invoke_viiiiiiiiiiiiiii:invoke_viiiiiiiiiiiiiii,invoke_viijii:invoke_viijii,invoke_viijj:invoke_viijj,is_comlink_proxy:is_comlink_proxy,js2python_convert:js2python_convert,js2python_immutable_js:js2python_immutable_js,js2python_js:js2python_js,jslib_init_buffers_js:jslib_init_buffers_js,jslib_init_js:jslib_init_js,lineColor:_lineColor,lineRGBA:_lineRGBA,llvm_eh_typeid_for:_llvm_eh_typeid_for,memory:wasmMemory,my_dict_converter:my_dict_converter,new_error:new_error,pixelRGBA:_pixelRGBA,proc_exit:_proc_exit,proxy_cache_get:proxy_cache_get,proxy_cache_set:proxy_cache_set,pyodide_js_init:pyodide_js_init,pyproxy_AsPyObject:pyproxy_AsPyObject,pyproxy_Check:pyproxy_Check,pyproxy_new:pyproxy_new,pyproxy_new_ex:pyproxy_new_ex,python2js__default_converter_js:python2js__default_converter_js,python2js_custom__create_jscontext:python2js_custom__create_jscontext,random_get:_random_get,raw_call_js:raw_call_js,rectangleColor:_rectangleColor,rectangleRGBA:_rectangleRGBA,restoreState:restoreState,restore_stderr:restore_stderr,rotozoomSurface:_rotozoomSurface,saveState:saveState,setNetworkCallback:_setNetworkCallback,set_pyodide_module:set_pyodide_module,set_suspender:set_suspender,setprotoent:_setprotoent,stackAlloc:_stackAlloc,stackRestore:_stackRestore,stackSave:_stackSave,strftime:_strftime,strftime_l:_strftime_l,strptime:_strptime,strptime_l:_strptime_l,syncifyHandler:syncifyHandler,throw_no_gil:throw_no_gil,wrap_async_generator:wrap_async_generator,wrap_generator:wrap_generator,zoomSurface:_zoomSurface};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["__wasm_call_ctors"])();var ___wasm_apply_data_relocs=()=>(___wasm_apply_data_relocs=wasmExports["__wasm_apply_data_relocs"])();var _set_method_docstring=Module["_set_method_docstring"]=(a0,a1)=>(_set_method_docstring=Module["_set_method_docstring"]=wasmExports["set_method_docstring"])(a0,a1);var _PyObject_GetAttrString=Module["_PyObject_GetAttrString"]=(a0,a1)=>(_PyObject_GetAttrString=Module["_PyObject_GetAttrString"]=wasmExports["PyObject_GetAttrString"])(a0,a1);var __PyUnicode_FromId=Module["__PyUnicode_FromId"]=a0=>(__PyUnicode_FromId=Module["__PyUnicode_FromId"]=wasmExports["_PyUnicode_FromId"])(a0);var _PyObject_VectorcallMethod=Module["_PyObject_VectorcallMethod"]=(a0,a1,a2,a3)=>(_PyObject_VectorcallMethod=Module["_PyObject_VectorcallMethod"]=wasmExports["PyObject_VectorcallMethod"])(a0,a1,a2,a3);var _PyUnicode_AsUTF8AndSize=Module["_PyUnicode_AsUTF8AndSize"]=(a0,a1)=>(_PyUnicode_AsUTF8AndSize=Module["_PyUnicode_AsUTF8AndSize"]=wasmExports["PyUnicode_AsUTF8AndSize"])(a0,a1);var _malloc=a0=>(_malloc=wasmExports["malloc"])(a0);var _memcpy=(a0,a1,a2)=>(_memcpy=wasmExports["memcpy"])(a0,a1,a2);var __Py_Dealloc=Module["__Py_Dealloc"]=a0=>(__Py_Dealloc=Module["__Py_Dealloc"]=wasmExports["_Py_Dealloc"])(a0);var _PyErr_Format=Module["_PyErr_Format"]=(a0,a1,a2)=>(_PyErr_Format=Module["_PyErr_Format"]=wasmExports["PyErr_Format"])(a0,a1,a2);var _add_methods_and_set_docstrings=Module["_add_methods_and_set_docstrings"]=(a0,a1,a2)=>(_add_methods_and_set_docstrings=Module["_add_methods_and_set_docstrings"]=wasmExports["add_methods_and_set_docstrings"])(a0,a1,a2);var _PyModule_AddFunctions=Module["_PyModule_AddFunctions"]=(a0,a1)=>(_PyModule_AddFunctions=Module["_PyModule_AddFunctions"]=wasmExports["PyModule_AddFunctions"])(a0,a1);var _docstring_init=Module["_docstring_init"]=()=>(_docstring_init=Module["_docstring_init"]=wasmExports["docstring_init"])();var _PyImport_ImportModule=Module["_PyImport_ImportModule"]=a0=>(_PyImport_ImportModule=Module["_PyImport_ImportModule"]=wasmExports["PyImport_ImportModule"])(a0);var _dump_traceback=Module["_dump_traceback"]=()=>(_dump_traceback=Module["_dump_traceback"]=wasmExports["dump_traceback"])();var _fileno=a0=>(_fileno=wasmExports["fileno"])(a0);var _PyGILState_GetThisThreadState=Module["_PyGILState_GetThisThreadState"]=()=>(_PyGILState_GetThisThreadState=Module["_PyGILState_GetThisThreadState"]=wasmExports["PyGILState_GetThisThreadState"])();var __Py_DumpTraceback=Module["__Py_DumpTraceback"]=(a0,a1)=>(__Py_DumpTraceback=Module["__Py_DumpTraceback"]=wasmExports["_Py_DumpTraceback"])(a0,a1);var _set_error=Module["_set_error"]=a0=>(_set_error=Module["_set_error"]=wasmExports["set_error"])(a0);var _PyErr_SetObject=Module["_PyErr_SetObject"]=(a0,a1)=>(_PyErr_SetObject=Module["_PyErr_SetObject"]=wasmExports["PyErr_SetObject"])(a0,a1);var _restore_sys_last_exception=Module["_restore_sys_last_exception"]=a0=>(_restore_sys_last_exception=Module["_restore_sys_last_exception"]=wasmExports["restore_sys_last_exception"])(a0);var _PySys_GetObject=Module["_PySys_GetObject"]=a0=>(_PySys_GetObject=Module["_PySys_GetObject"]=wasmExports["PySys_GetObject"])(a0);var _PyErr_SetRaisedException=Module["_PyErr_SetRaisedException"]=a0=>(_PyErr_SetRaisedException=Module["_PyErr_SetRaisedException"]=wasmExports["PyErr_SetRaisedException"])(a0);var _wrap_exception=Module["_wrap_exception"]=()=>(_wrap_exception=Module["_wrap_exception"]=wasmExports["wrap_exception"])();var _PyErr_GetRaisedException=Module["_PyErr_GetRaisedException"]=()=>(_PyErr_GetRaisedException=Module["_PyErr_GetRaisedException"]=wasmExports["PyErr_GetRaisedException"])();var _PyErr_GivenExceptionMatches=Module["_PyErr_GivenExceptionMatches"]=(a0,a1)=>(_PyErr_GivenExceptionMatches=Module["_PyErr_GivenExceptionMatches"]=wasmExports["PyErr_GivenExceptionMatches"])(a0,a1);var _PyErr_Print=Module["_PyErr_Print"]=()=>(_PyErr_Print=Module["_PyErr_Print"]=wasmExports["PyErr_Print"])();var __PyObject_GetAttrId=Module["__PyObject_GetAttrId"]=(a0,a1)=>(__PyObject_GetAttrId=Module["__PyObject_GetAttrId"]=wasmExports["_PyObject_GetAttrId"])(a0,a1);var _PyUnicode_AsUTF8=Module["_PyUnicode_AsUTF8"]=a0=>(_PyUnicode_AsUTF8=Module["_PyUnicode_AsUTF8"]=wasmExports["PyUnicode_AsUTF8"])(a0);var _JsvNull_Check=Module["_JsvNull_Check"]=a0=>(_JsvNull_Check=Module["_JsvNull_Check"]=wasmExports["JsvNull_Check"])(a0);var _PySys_WriteStderr=Module["_PySys_WriteStderr"]=(a0,a1)=>(_PySys_WriteStderr=Module["_PySys_WriteStderr"]=wasmExports["PySys_WriteStderr"])(a0,a1);var _PyErr_DisplayException=Module["_PyErr_DisplayException"]=a0=>(_PyErr_DisplayException=Module["_PyErr_DisplayException"]=wasmExports["PyErr_DisplayException"])(a0);var _JsvString_FromId=Module["_JsvString_FromId"]=a0=>(_JsvString_FromId=Module["_JsvString_FromId"]=wasmExports["JsvString_FromId"])(a0);var _pythonexc2js=Module["_pythonexc2js"]=()=>(_pythonexc2js=Module["_pythonexc2js"]=wasmExports["pythonexc2js"])();var _trigger_fatal_error=Module["_trigger_fatal_error"]=(a0,a1)=>(_trigger_fatal_error=Module["_trigger_fatal_error"]=wasmExports["trigger_fatal_error"])(a0,a1);var _raw_call=Module["_raw_call"]=(a0,a1)=>(_raw_call=Module["_raw_call"]=wasmExports["raw_call"])(a0,a1);var _JsProxy_Val=Module["_JsProxy_Val"]=a0=>(_JsProxy_Val=Module["_JsProxy_Val"]=wasmExports["JsProxy_Val"])(a0);var _error_handling_init=Module["_error_handling_init"]=a0=>(_error_handling_init=Module["_error_handling_init"]=wasmExports["error_handling_init"])(a0);var _hiwire_new_deduplicate=Module["_hiwire_new_deduplicate"]=a0=>(_hiwire_new_deduplicate=Module["_hiwire_new_deduplicate"]=wasmExports["hiwire_new_deduplicate"])(a0);var _hiwire_new=Module["_hiwire_new"]=a0=>(_hiwire_new=Module["_hiwire_new"]=wasmExports["hiwire_new"])(a0);var _hiwire_incref_deduplicate=Module["_hiwire_incref_deduplicate"]=a0=>(_hiwire_incref_deduplicate=Module["_hiwire_incref_deduplicate"]=wasmExports["hiwire_incref_deduplicate"])(a0);var _hiwire_decref=Module["_hiwire_decref"]=a0=>(_hiwire_decref=Module["_hiwire_decref"]=wasmExports["hiwire_decref"])(a0);var _init_pyodide_proxy=Module["_init_pyodide_proxy"]=()=>(_init_pyodide_proxy=Module["_init_pyodide_proxy"]=wasmExports["init_pyodide_proxy"])();var _python2js=Module["_python2js"]=a0=>(_python2js=Module["_python2js"]=wasmExports["python2js"])(a0);var _PyInit__pyodide_core=Module["_PyInit__pyodide_core"]=()=>(_PyInit__pyodide_core=Module["_PyInit__pyodide_core"]=wasmExports["PyInit__pyodide_core"])();var _PyErr_Occurred=Module["_PyErr_Occurred"]=()=>(_PyErr_Occurred=Module["_PyErr_Occurred"]=wasmExports["PyErr_Occurred"])();var __PyErr_FormatFromCause=Module["__PyErr_FormatFromCause"]=(a0,a1,a2)=>(__PyErr_FormatFromCause=Module["__PyErr_FormatFromCause"]=wasmExports["_PyErr_FormatFromCause"])(a0,a1,a2);var _PyModule_Create2=Module["_PyModule_Create2"]=(a0,a1)=>(_PyModule_Create2=Module["_PyModule_Create2"]=wasmExports["PyModule_Create2"])(a0,a1);var _PyImport_GetModuleDict=Module["_PyImport_GetModuleDict"]=()=>(_PyImport_GetModuleDict=Module["_PyImport_GetModuleDict"]=wasmExports["PyImport_GetModuleDict"])();var _PyDict_SetItemString=Module["_PyDict_SetItemString"]=(a0,a1,a2)=>(_PyDict_SetItemString=Module["_PyDict_SetItemString"]=wasmExports["PyDict_SetItemString"])(a0,a1,a2);var _jslib_init=Module["_jslib_init"]=()=>(_jslib_init=Module["_jslib_init"]=wasmExports["jslib_init"])();var _python2js_init=Module["_python2js_init"]=a0=>(_python2js_init=Module["_python2js_init"]=wasmExports["python2js_init"])(a0);var _jsproxy_init=Module["_jsproxy_init"]=a0=>(_jsproxy_init=Module["_jsproxy_init"]=wasmExports["jsproxy_init"])(a0);var _jsproxy_call_init=Module["_jsproxy_call_init"]=a0=>(_jsproxy_call_init=Module["_jsproxy_call_init"]=wasmExports["jsproxy_call_init"])(a0);var _pyproxy_init=Module["_pyproxy_init"]=a0=>(_pyproxy_init=Module["_pyproxy_init"]=wasmExports["pyproxy_init"])(a0);var _jsbind_init=Module["_jsbind_init"]=a0=>(_jsbind_init=Module["_jsbind_init"]=wasmExports["jsbind_init"])(a0);var _pyodide_export=Module["_pyodide_export"]=()=>(_pyodide_export=Module["_pyodide_export"]=wasmExports["pyodide_export"])();var _py_version_major=Module["_py_version_major"]=()=>(_py_version_major=Module["_py_version_major"]=wasmExports["py_version_major"])();var _set_new_cframe=Module["_set_new_cframe"]=a0=>(_set_new_cframe=Module["_set_new_cframe"]=wasmExports["set_new_cframe"])(a0);var _PyUnicode_Data=Module["_PyUnicode_Data"]=a0=>(_PyUnicode_Data=Module["_PyUnicode_Data"]=wasmExports["PyUnicode_Data"])(a0);var __js2python_none=Module["__js2python_none"]=()=>(__js2python_none=Module["__js2python_none"]=wasmExports["_js2python_none"])();var __js2python_true=Module["__js2python_true"]=()=>(__js2python_true=Module["__js2python_true"]=wasmExports["_js2python_true"])();var __js2python_false=Module["__js2python_false"]=()=>(__js2python_false=Module["__js2python_false"]=wasmExports["_js2python_false"])();var __js2python_pyproxy=Module["__js2python_pyproxy"]=a0=>(__js2python_pyproxy=Module["__js2python_pyproxy"]=wasmExports["_js2python_pyproxy"])(a0);var _js2python_immutable=Module["_js2python_immutable"]=a0=>(_js2python_immutable=Module["_js2python_immutable"]=wasmExports["js2python_immutable"])(a0);var _js2python=Module["_js2python"]=a0=>(_js2python=Module["_js2python"]=wasmExports["js2python"])(a0);var _JsProxy_getflags=Module["_JsProxy_getflags"]=a0=>(_JsProxy_getflags=Module["_JsProxy_getflags"]=wasmExports["JsProxy_getflags"])(a0);var _PyLong_AsLong=Module["_PyLong_AsLong"]=a0=>(_PyLong_AsLong=Module["_PyLong_AsLong"]=wasmExports["PyLong_AsLong"])(a0);var _JsProxy_is_py_json=Module["_JsProxy_is_py_json"]=a0=>(_JsProxy_is_py_json=Module["_JsProxy_is_py_json"]=wasmExports["JsProxy_is_py_json"])(a0);var _js2python_as_py_json=Module["_js2python_as_py_json"]=a0=>(_js2python_as_py_json=Module["_js2python_as_py_json"]=wasmExports["js2python_as_py_json"])(a0);var _JsProxy_create_with_type=Module["_JsProxy_create_with_type"]=(a0,a1,a2,a3)=>(_JsProxy_create_with_type=Module["_JsProxy_create_with_type"]=wasmExports["JsProxy_create_with_type"])(a0,a1,a2,a3);var _JsProxy_bind_sig=Module["_JsProxy_bind_sig"]=(a0,a1)=>(_JsProxy_bind_sig=Module["_JsProxy_bind_sig"]=wasmExports["JsProxy_bind_sig"])(a0,a1);var _hiwire_get=Module["_hiwire_get"]=a0=>(_hiwire_get=Module["_hiwire_get"]=wasmExports["hiwire_get"])(a0);var _JsRef_toVal=Module["_JsRef_toVal"]=a0=>(_JsRef_toVal=Module["_JsRef_toVal"]=wasmExports["JsRef_toVal"])(a0);var _PyErr_SetString=Module["_PyErr_SetString"]=(a0,a1)=>(_PyErr_SetString=Module["_PyErr_SetString"]=wasmExports["PyErr_SetString"])(a0,a1);var _JsProxy_create_with_this=Module["_JsProxy_create_with_this"]=(a0,a1,a2,a3)=>(_JsProxy_create_with_this=Module["_JsProxy_create_with_this"]=wasmExports["JsProxy_create_with_this"])(a0,a1,a2,a3);var _clear_method_call_singleton=Module["_clear_method_call_singleton"]=()=>(_clear_method_call_singleton=Module["_clear_method_call_singleton"]=wasmExports["clear_method_call_singleton"])();var _JsProxy_GetMethod=Module["_JsProxy_GetMethod"]=(a0,a1)=>(_JsProxy_GetMethod=Module["_JsProxy_GetMethod"]=wasmExports["JsProxy_GetMethod"])(a0,a1);var __PyObject_GenericGetAttrWithDict=Module["__PyObject_GenericGetAttrWithDict"]=(a0,a1,a2,a3)=>(__PyObject_GenericGetAttrWithDict=Module["__PyObject_GenericGetAttrWithDict"]=wasmExports["_PyObject_GenericGetAttrWithDict"])(a0,a1,a2,a3);var _strcmp=Module["_strcmp"]=(a0,a1)=>(_strcmp=Module["_strcmp"]=wasmExports["strcmp"])(a0,a1);var __PyObject_CallMethodIdObjArgs=Module["__PyObject_CallMethodIdObjArgs"]=(a0,a1,a2)=>(__PyObject_CallMethodIdObjArgs=Module["__PyObject_CallMethodIdObjArgs"]=wasmExports["_PyObject_CallMethodIdObjArgs"])(a0,a1,a2);var __PyArg_ParseTuple_SizeT=Module["__PyArg_ParseTuple_SizeT"]=(a0,a1,a2)=>(__PyArg_ParseTuple_SizeT=Module["__PyArg_ParseTuple_SizeT"]=wasmExports["_PyArg_ParseTuple_SizeT"])(a0,a1,a2);var _Js2PyConverter_convert=Module["_Js2PyConverter_convert"]=(a0,a1,a2)=>(_Js2PyConverter_convert=Module["_Js2PyConverter_convert"]=wasmExports["Js2PyConverter_convert"])(a0,a1,a2);var _hiwire_incref=Module["_hiwire_incref"]=a0=>(_hiwire_incref=Module["_hiwire_incref"]=wasmExports["hiwire_incref"])(a0);var _JsProxy_GetAttr=Module["_JsProxy_GetAttr"]=(a0,a1)=>(_JsProxy_GetAttr=Module["_JsProxy_GetAttr"]=wasmExports["JsProxy_GetAttr"])(a0,a1);var _handle_next_result=Module["_handle_next_result"]=(a0,a1,a2)=>(_handle_next_result=Module["_handle_next_result"]=wasmExports["handle_next_result"])(a0,a1,a2);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["free"])(a0);var _JsProxy_create_objmap=Module["_JsProxy_create_objmap"]=(a0,a1)=>(_JsProxy_create_objmap=Module["_JsProxy_create_objmap"]=wasmExports["JsProxy_create_objmap"])(a0,a1);var _JsProxy_am_send=Module["_JsProxy_am_send"]=(a0,a1,a2)=>(_JsProxy_am_send=Module["_JsProxy_am_send"]=wasmExports["JsProxy_am_send"])(a0,a1,a2);var _python2js_track_proxies=Module["_python2js_track_proxies"]=(a0,a1,a2)=>(_python2js_track_proxies=Module["_python2js_track_proxies"]=wasmExports["python2js_track_proxies"])(a0,a1,a2);var _JsvObject_CallMethodId_OneArg=Module["_JsvObject_CallMethodId_OneArg"]=(a0,a1,a2)=>(_JsvObject_CallMethodId_OneArg=Module["_JsvObject_CallMethodId_OneArg"]=wasmExports["JsvObject_CallMethodId_OneArg"])(a0,a1,a2);var _JsProxy_IterNext=Module["_JsProxy_IterNext"]=a0=>(_JsProxy_IterNext=Module["_JsProxy_IterNext"]=wasmExports["JsProxy_IterNext"])(a0);var __PyGen_SetStopIterationValue=Module["__PyGen_SetStopIterationValue"]=a0=>(__PyGen_SetStopIterationValue=Module["__PyGen_SetStopIterationValue"]=wasmExports["_PyGen_SetStopIterationValue"])(a0);var _JsGenerator_send=Module["_JsGenerator_send"]=(a0,a1)=>(_JsGenerator_send=Module["_JsGenerator_send"]=wasmExports["JsGenerator_send"])(a0,a1);var _PyErr_SetNone=Module["_PyErr_SetNone"]=a0=>(_PyErr_SetNone=Module["_PyErr_SetNone"]=wasmExports["PyErr_SetNone"])(a0);var _JsException_js_error_getter=Module["_JsException_js_error_getter"]=(a0,a1)=>(_JsException_js_error_getter=Module["_JsException_js_error_getter"]=wasmExports["JsException_js_error_getter"])(a0,a1);var _process_throw_args=Module["_process_throw_args"]=(a0,a1,a2,a3)=>(_process_throw_args=Module["_process_throw_args"]=wasmExports["process_throw_args"])(a0,a1,a2,a3);var _PyErr_NormalizeException=Module["_PyErr_NormalizeException"]=(a0,a1,a2)=>(_PyErr_NormalizeException=Module["_PyErr_NormalizeException"]=wasmExports["PyErr_NormalizeException"])(a0,a1,a2);var _PyException_GetTraceback=Module["_PyException_GetTraceback"]=a0=>(_PyException_GetTraceback=Module["_PyException_GetTraceback"]=wasmExports["PyException_GetTraceback"])(a0);var _PyException_SetTraceback=Module["_PyException_SetTraceback"]=(a0,a1)=>(_PyException_SetTraceback=Module["_PyException_SetTraceback"]=wasmExports["PyException_SetTraceback"])(a0,a1);var _PyErr_Restore=Module["_PyErr_Restore"]=(a0,a1,a2)=>(_PyErr_Restore=Module["_PyErr_Restore"]=wasmExports["PyErr_Restore"])(a0,a1,a2);var _PyErr_ExceptionMatches=Module["_PyErr_ExceptionMatches"]=a0=>(_PyErr_ExceptionMatches=Module["_PyErr_ExceptionMatches"]=wasmExports["PyErr_ExceptionMatches"])(a0);var _PyErr_Clear=Module["_PyErr_Clear"]=()=>(_PyErr_Clear=Module["_PyErr_Clear"]=wasmExports["PyErr_Clear"])();var _JsvObject_CallMethodId_NoArgs=Module["_JsvObject_CallMethodId_NoArgs"]=(a0,a1)=>(_JsvObject_CallMethodId_NoArgs=Module["_JsvObject_CallMethodId_NoArgs"]=wasmExports["JsvObject_CallMethodId_NoArgs"])(a0,a1);var _PyErr_Fetch=Module["_PyErr_Fetch"]=(a0,a1,a2)=>(_PyErr_Fetch=Module["_PyErr_Fetch"]=wasmExports["PyErr_Fetch"])(a0,a1,a2);var __agen_handle_result_js_c=Module["__agen_handle_result_js_c"]=(a0,a1,a2,a3,a4)=>(__agen_handle_result_js_c=Module["__agen_handle_result_js_c"]=wasmExports["_agen_handle_result_js_c"])(a0,a1,a2,a3,a4);var _PyObject_CallOneArg=Module["_PyObject_CallOneArg"]=(a0,a1)=>(_PyObject_CallOneArg=Module["_PyObject_CallOneArg"]=wasmExports["PyObject_CallOneArg"])(a0,a1);var __agen_handle_result=Module["__agen_handle_result"]=(a0,a1)=>(__agen_handle_result=Module["__agen_handle_result"]=wasmExports["_agen_handle_result"])(a0,a1);var _JsArray_sq_item=Module["_JsArray_sq_item"]=(a0,a1)=>(_JsArray_sq_item=Module["_JsArray_sq_item"]=wasmExports["JsArray_sq_item"])(a0,a1);var _JsArray_sq_ass_item=Module["_JsArray_sq_ass_item"]=(a0,a1,a2)=>(_JsArray_sq_ass_item=Module["_JsArray_sq_ass_item"]=wasmExports["JsArray_sq_ass_item"])(a0,a1,a2);var _JsTypedArray_sq_ass_item=Module["_JsTypedArray_sq_ass_item"]=(a0,a1,a2)=>(_JsTypedArray_sq_ass_item=Module["_JsTypedArray_sq_ass_item"]=wasmExports["JsTypedArray_sq_ass_item"])(a0,a1,a2);var _JsMap_update=Module["_JsMap_update"]=(a0,a1,a2)=>(_JsMap_update=Module["_JsMap_update"]=wasmExports["JsMap_update"])(a0,a1,a2);var _wrap_promise=Module["_wrap_promise"]=(a0,a1,a2)=>(_wrap_promise=Module["_wrap_promise"]=wasmExports["wrap_promise"])(a0,a1,a2);var _PyTuple_GetItem=Module["_PyTuple_GetItem"]=(a0,a1)=>(_PyTuple_GetItem=Module["_PyTuple_GetItem"]=wasmExports["PyTuple_GetItem"])(a0,a1);var _JsvObject_CallMethodId=Module["_JsvObject_CallMethodId"]=(a0,a1,a2)=>(_JsvObject_CallMethodId=Module["_JsvObject_CallMethodId"]=wasmExports["JsvObject_CallMethodId"])(a0,a1,a2);var _JsModule_GetAll=Module["_JsModule_GetAll"]=(a0,a1)=>(_JsModule_GetAll=Module["_JsModule_GetAll"]=wasmExports["JsModule_GetAll"])(a0,a1);var _PyType_IsSubtype=Module["_PyType_IsSubtype"]=(a0,a1)=>(_PyType_IsSubtype=Module["_PyType_IsSubtype"]=wasmExports["PyType_IsSubtype"])(a0,a1);var _JsProxy_Check=Module["_JsProxy_Check"]=a0=>(_JsProxy_Check=Module["_JsProxy_Check"]=wasmExports["JsProxy_Check"])(a0);var _JsBuffer_CopyIntoMemoryView=Module["_JsBuffer_CopyIntoMemoryView"]=(a0,a1,a2,a3)=>(_JsBuffer_CopyIntoMemoryView=Module["_JsBuffer_CopyIntoMemoryView"]=wasmExports["JsBuffer_CopyIntoMemoryView"])(a0,a1,a2,a3);var _PyMem_Malloc=Module["_PyMem_Malloc"]=a0=>(_PyMem_Malloc=Module["_PyMem_Malloc"]=wasmExports["PyMem_Malloc"])(a0);var _PyMemoryView_FromObject=Module["_PyMemoryView_FromObject"]=a0=>(_PyMemoryView_FromObject=Module["_PyMemoryView_FromObject"]=wasmExports["PyMemoryView_FromObject"])(a0);var _JsBuffer_cinit=Module["_JsBuffer_cinit"]=a0=>(_JsBuffer_cinit=Module["_JsBuffer_cinit"]=wasmExports["JsBuffer_cinit"])(a0);var _JsRef_new=Module["_JsRef_new"]=a0=>(_JsRef_new=Module["_JsRef_new"]=wasmExports["JsRef_new"])(a0);var _PyTuple_Pack=Module["_PyTuple_Pack"]=(a0,a1)=>(_PyTuple_Pack=Module["_PyTuple_Pack"]=wasmExports["PyTuple_Pack"])(a0,a1);var _PyLong_FromLong=Module["_PyLong_FromLong"]=a0=>(_PyLong_FromLong=Module["_PyLong_FromLong"]=wasmExports["PyLong_FromLong"])(a0);var _PyDict_GetItemWithError=Module["_PyDict_GetItemWithError"]=(a0,a1)=>(_PyDict_GetItemWithError=Module["_PyDict_GetItemWithError"]=wasmExports["PyDict_GetItemWithError"])(a0,a1);var _PyObject_SelfIter=Module["_PyObject_SelfIter"]=a0=>(_PyObject_SelfIter=Module["_PyObject_SelfIter"]=wasmExports["PyObject_SelfIter"])(a0);var _PyVectorcall_Call=Module["_PyVectorcall_Call"]=(a0,a1,a2)=>(_PyVectorcall_Call=Module["_PyVectorcall_Call"]=wasmExports["PyVectorcall_Call"])(a0,a1,a2);var _PyErr_NoMemory=Module["_PyErr_NoMemory"]=()=>(_PyErr_NoMemory=Module["_PyErr_NoMemory"]=wasmExports["PyErr_NoMemory"])();var _PyType_FromSpecWithBases=Module["_PyType_FromSpecWithBases"]=(a0,a1)=>(_PyType_FromSpecWithBases=Module["_PyType_FromSpecWithBases"]=wasmExports["PyType_FromSpecWithBases"])(a0,a1);var __PyObject_SetAttrId=Module["__PyObject_SetAttrId"]=(a0,a1,a2)=>(__PyObject_SetAttrId=Module["__PyObject_SetAttrId"]=wasmExports["_PyObject_SetAttrId"])(a0,a1,a2);var _PyMem_Free=Module["_PyMem_Free"]=a0=>(_PyMem_Free=Module["_PyMem_Free"]=wasmExports["PyMem_Free"])(a0);var _PyDict_SetItem=Module["_PyDict_SetItem"]=(a0,a1,a2)=>(_PyDict_SetItem=Module["_PyDict_SetItem"]=wasmExports["PyDict_SetItem"])(a0,a1,a2);var _JsProxy_create=Module["_JsProxy_create"]=a0=>(_JsProxy_create=Module["_JsProxy_create"]=wasmExports["JsProxy_create"])(a0);var _JsProxy_init_docstrings=Module["_JsProxy_init_docstrings"]=a0=>(_JsProxy_init_docstrings=Module["_JsProxy_init_docstrings"]=wasmExports["JsProxy_init_docstrings"])(a0);var _run_sync_not_supported=Module["_run_sync_not_supported"]=(a0,a1)=>(_run_sync_not_supported=Module["_run_sync_not_supported"]=wasmExports["run_sync_not_supported"])(a0,a1);var _run_sync=Module["_run_sync"]=(a0,a1)=>(_run_sync=Module["_run_sync"]=wasmExports["run_sync"])(a0,a1);var _py_is_awaitable=Module["_py_is_awaitable"]=a0=>(_py_is_awaitable=Module["_py_is_awaitable"]=wasmExports["py_is_awaitable"])(a0);var _JsvPromise_Syncify=Module["_JsvPromise_Syncify"]=a0=>(_JsvPromise_Syncify=Module["_JsvPromise_Syncify"]=wasmExports["JsvPromise_Syncify"])(a0);var _can_run_sync=Module["_can_run_sync"]=(a0,a1)=>(_can_run_sync=Module["_can_run_sync"]=wasmExports["can_run_sync"])(a0,a1);var _PyDict_New=Module["_PyDict_New"]=()=>(_PyDict_New=Module["_PyDict_New"]=wasmExports["PyDict_New"])();var _PyObject_SetAttrString=Module["_PyObject_SetAttrString"]=(a0,a1,a2)=>(_PyObject_SetAttrString=Module["_PyObject_SetAttrString"]=wasmExports["PyObject_SetAttrString"])(a0,a1,a2);var _PyModule_AddObject=Module["_PyModule_AddObject"]=(a0,a1,a2)=>(_PyModule_AddObject=Module["_PyModule_AddObject"]=wasmExports["PyModule_AddObject"])(a0,a1,a2);var _PyType_Ready=Module["_PyType_Ready"]=a0=>(_PyType_Ready=Module["_PyType_Ready"]=wasmExports["PyType_Ready"])(a0);var _JsMethod_Vectorcall_impl=Module["_JsMethod_Vectorcall_impl"]=(a0,a1,a2,a3,a4,a5)=>(_JsMethod_Vectorcall_impl=Module["_JsMethod_Vectorcall_impl"]=wasmExports["JsMethod_Vectorcall_impl"])(a0,a1,a2,a3,a4,a5);var _JsvObject_CallMethodId_TwoArgs=Module["_JsvObject_CallMethodId_TwoArgs"]=(a0,a1,a2,a3)=>(_JsvObject_CallMethodId_TwoArgs=Module["_JsvObject_CallMethodId_TwoArgs"]=wasmExports["JsvObject_CallMethodId_TwoArgs"])(a0,a1,a2,a3);var _PyObject_Repr=Module["_PyObject_Repr"]=a0=>(_PyObject_Repr=Module["_PyObject_Repr"]=wasmExports["PyObject_Repr"])(a0);var _PyIndex_Check=Module["_PyIndex_Check"]=a0=>(_PyIndex_Check=Module["_PyIndex_Check"]=wasmExports["PyIndex_Check"])(a0);var _PyNumber_AsSsize_t=Module["_PyNumber_AsSsize_t"]=(a0,a1)=>(_PyNumber_AsSsize_t=Module["_PyNumber_AsSsize_t"]=wasmExports["PyNumber_AsSsize_t"])(a0,a1);var _PySlice_Unpack=Module["_PySlice_Unpack"]=(a0,a1,a2,a3)=>(_PySlice_Unpack=Module["_PySlice_Unpack"]=wasmExports["PySlice_Unpack"])(a0,a1,a2,a3);var _PySlice_AdjustIndices=Module["_PySlice_AdjustIndices"]=(a0,a1,a2,a3)=>(_PySlice_AdjustIndices=Module["_PySlice_AdjustIndices"]=wasmExports["PySlice_AdjustIndices"])(a0,a1,a2,a3);var _PySequence_Fast=Module["_PySequence_Fast"]=(a0,a1)=>(_PySequence_Fast=Module["_PySequence_Fast"]=wasmExports["PySequence_Fast"])(a0,a1);var __PyArg_ParseTupleAndKeywords_SizeT=Module["__PyArg_ParseTupleAndKeywords_SizeT"]=(a0,a1,a2,a3,a4)=>(__PyArg_ParseTupleAndKeywords_SizeT=Module["__PyArg_ParseTupleAndKeywords_SizeT"]=wasmExports["_PyArg_ParseTupleAndKeywords_SizeT"])(a0,a1,a2,a3,a4);var _PySet_New=Module["_PySet_New"]=a0=>(_PySet_New=Module["_PySet_New"]=wasmExports["PySet_New"])(a0);var __PySet_Update=Module["__PySet_Update"]=(a0,a1)=>(__PySet_Update=Module["__PySet_Update"]=wasmExports["_PySet_Update"])(a0,a1);var _PyUnicode_FromString=Module["_PyUnicode_FromString"]=a0=>(_PyUnicode_FromString=Module["_PyUnicode_FromString"]=wasmExports["PyUnicode_FromString"])(a0);var _PySet_Discard=Module["_PySet_Discard"]=(a0,a1)=>(_PySet_Discard=Module["_PySet_Discard"]=wasmExports["PySet_Discard"])(a0,a1);var _PyList_New=Module["_PyList_New"]=a0=>(_PyList_New=Module["_PyList_New"]=wasmExports["PyList_New"])(a0);var __PyList_Extend=Module["__PyList_Extend"]=(a0,a1)=>(__PyList_Extend=Module["__PyList_Extend"]=wasmExports["_PyList_Extend"])(a0,a1);var _PyList_Sort=Module["_PyList_Sort"]=a0=>(_PyList_Sort=Module["_PyList_Sort"]=wasmExports["PyList_Sort"])(a0);var __PyArg_ParseStack_SizeT=Module["__PyArg_ParseStack_SizeT"]=(a0,a1,a2,a3)=>(__PyArg_ParseStack_SizeT=Module["__PyArg_ParseStack_SizeT"]=wasmExports["_PyArg_ParseStack_SizeT"])(a0,a1,a2,a3);var _PyObject_GetIter=Module["_PyObject_GetIter"]=a0=>(_PyObject_GetIter=Module["_PyObject_GetIter"]=wasmExports["PyObject_GetIter"])(a0);var _PyObject_RichCompareBool=Module["_PyObject_RichCompareBool"]=(a0,a1,a2)=>(_PyObject_RichCompareBool=Module["_PyObject_RichCompareBool"]=wasmExports["PyObject_RichCompareBool"])(a0,a1,a2);var __PyArg_ParseStackAndKeywords_SizeT=Module["__PyArg_ParseStackAndKeywords_SizeT"]=(a0,a1,a2,a3,a4)=>(__PyArg_ParseStackAndKeywords_SizeT=Module["__PyArg_ParseStackAndKeywords_SizeT"]=wasmExports["_PyArg_ParseStackAndKeywords_SizeT"])(a0,a1,a2,a3,a4);var _hiwire_pop=Module["_hiwire_pop"]=a0=>(_hiwire_pop=Module["_hiwire_pop"]=wasmExports["hiwire_pop"])(a0);var _puts=Module["_puts"]=a0=>(_puts=Module["_puts"]=wasmExports["puts"])(a0);var _strncmp=Module["_strncmp"]=(a0,a1,a2)=>(_strncmp=Module["_strncmp"]=wasmExports["strncmp"])(a0,a1,a2);var _PyObject_GenericSetAttr=Module["_PyObject_GenericSetAttr"]=(a0,a1,a2)=>(_PyObject_GenericSetAttr=Module["_PyObject_GenericSetAttr"]=wasmExports["PyObject_GenericSetAttr"])(a0,a1,a2);var __Py_HashBytes=Module["__Py_HashBytes"]=(a0,a1)=>(__Py_HashBytes=Module["__Py_HashBytes"]=wasmExports["_Py_HashBytes"])(a0,a1);var _JsMethod_Construct_impl=Module["_JsMethod_Construct_impl"]=(a0,a1,a2,a3,a4)=>(_JsMethod_Construct_impl=Module["_JsMethod_Construct_impl"]=wasmExports["JsMethod_Construct_impl"])(a0,a1,a2,a3,a4);var __PyArg_CheckPositional=Module["__PyArg_CheckPositional"]=(a0,a1,a2,a3)=>(__PyArg_CheckPositional=Module["__PyArg_CheckPositional"]=wasmExports["_PyArg_CheckPositional"])(a0,a1,a2,a3);var __PyNumber_Index=Module["__PyNumber_Index"]=a0=>(__PyNumber_Index=Module["__PyNumber_Index"]=wasmExports["_PyNumber_Index"])(a0);var _PyLong_AsSsize_t=Module["_PyLong_AsSsize_t"]=a0=>(_PyLong_AsSsize_t=Module["_PyLong_AsSsize_t"]=wasmExports["PyLong_AsSsize_t"])(a0);var _PyLong_FromSsize_t=Module["_PyLong_FromSsize_t"]=a0=>(_PyLong_FromSsize_t=Module["_PyLong_FromSsize_t"]=wasmExports["PyLong_FromSsize_t"])(a0);var _PyObject_GetItem=Module["_PyObject_GetItem"]=(a0,a1)=>(_PyObject_GetItem=Module["_PyObject_GetItem"]=wasmExports["PyObject_GetItem"])(a0,a1);var _PyObject_DelItem=Module["_PyObject_DelItem"]=(a0,a1)=>(_PyObject_DelItem=Module["_PyObject_DelItem"]=wasmExports["PyObject_DelItem"])(a0,a1);var _PyObject_SetItem=Module["_PyObject_SetItem"]=(a0,a1,a2)=>(_PyObject_SetItem=Module["_PyObject_SetItem"]=wasmExports["PyObject_SetItem"])(a0,a1,a2);var _PyObject_GetBuffer=Module["_PyObject_GetBuffer"]=(a0,a1,a2)=>(_PyObject_GetBuffer=Module["_PyObject_GetBuffer"]=wasmExports["PyObject_GetBuffer"])(a0,a1,a2);var _PyBuffer_Release=Module["_PyBuffer_Release"]=a0=>(_PyBuffer_Release=Module["_PyBuffer_Release"]=wasmExports["PyBuffer_Release"])(a0);var _PyBytes_FromStringAndSize=Module["_PyBytes_FromStringAndSize"]=(a0,a1)=>(_PyBytes_FromStringAndSize=Module["_PyBytes_FromStringAndSize"]=wasmExports["PyBytes_FromStringAndSize"])(a0,a1);var _PyObject_Vectorcall=Module["_PyObject_Vectorcall"]=(a0,a1,a2,a3)=>(_PyObject_Vectorcall=Module["_PyObject_Vectorcall"]=wasmExports["PyObject_Vectorcall"])(a0,a1,a2,a3);var _Py_EnterRecursiveCall=Module["_Py_EnterRecursiveCall"]=a0=>(_Py_EnterRecursiveCall=Module["_Py_EnterRecursiveCall"]=wasmExports["Py_EnterRecursiveCall"])(a0);var _Py_LeaveRecursiveCall=Module["_Py_LeaveRecursiveCall"]=()=>(_Py_LeaveRecursiveCall=Module["_Py_LeaveRecursiveCall"]=wasmExports["Py_LeaveRecursiveCall"])();var _Py2JsConverter_convert=Module["_Py2JsConverter_convert"]=(a0,a1,a2)=>(_Py2JsConverter_convert=Module["_Py2JsConverter_convert"]=wasmExports["Py2JsConverter_convert"])(a0,a1,a2);var __PyUnicode_EQ=Module["__PyUnicode_EQ"]=(a0,a1)=>(__PyUnicode_EQ=Module["__PyUnicode_EQ"]=wasmExports["_PyUnicode_EQ"])(a0,a1);var _PyUnicode_FromFormat=Module["_PyUnicode_FromFormat"]=(a0,a1)=>(_PyUnicode_FromFormat=Module["_PyUnicode_FromFormat"]=wasmExports["PyUnicode_FromFormat"])(a0,a1);var _PyType_GenericNew=Module["_PyType_GenericNew"]=(a0,a1,a2)=>(_PyType_GenericNew=Module["_PyType_GenericNew"]=wasmExports["PyType_GenericNew"])(a0,a1,a2);var _PyObject_IsInstance=Module["_PyObject_IsInstance"]=(a0,a1)=>(_PyObject_IsInstance=Module["_PyObject_IsInstance"]=wasmExports["PyObject_IsInstance"])(a0,a1);var _python2js_inner=Module["_python2js_inner"]=(a0,a1,a2,a3,a4)=>(_python2js_inner=Module["_python2js_inner"]=wasmExports["python2js_inner"])(a0,a1,a2,a3,a4);var _python2js_custom=Module["_python2js_custom"]=(a0,a1,a2,a3,a4)=>(_python2js_custom=Module["_python2js_custom"]=wasmExports["python2js_custom"])(a0,a1,a2,a3,a4);var _PyObject_GC_UnTrack=Module["_PyObject_GC_UnTrack"]=a0=>(_PyObject_GC_UnTrack=Module["_PyObject_GC_UnTrack"]=wasmExports["PyObject_GC_UnTrack"])(a0);var _check_gil=Module["_check_gil"]=()=>(_check_gil=Module["_check_gil"]=wasmExports["check_gil"])();var _PyGILState_Check=Module["_PyGILState_Check"]=()=>(_PyGILState_Check=Module["_PyGILState_Check"]=wasmExports["PyGILState_Check"])();var _PyGen_GetCode=Module["_PyGen_GetCode"]=a0=>(_PyGen_GetCode=Module["_PyGen_GetCode"]=wasmExports["PyGen_GetCode"])(a0);var _pyproxy_getflags=Module["_pyproxy_getflags"]=(a0,a1)=>(_pyproxy_getflags=Module["_pyproxy_getflags"]=wasmExports["pyproxy_getflags"])(a0,a1);var _PyObject_HasAttr=Module["_PyObject_HasAttr"]=(a0,a1)=>(_PyObject_HasAttr=Module["_PyObject_HasAttr"]=wasmExports["PyObject_HasAttr"])(a0,a1);var __PyObject_NextNotImplemented=Module["__PyObject_NextNotImplemented"]=a0=>(__PyObject_NextNotImplemented=Module["__PyObject_NextNotImplemented"]=wasmExports["_PyObject_NextNotImplemented"])(a0);var _PyObject_IsSubclass=Module["_PyObject_IsSubclass"]=(a0,a1)=>(_PyObject_IsSubclass=Module["_PyObject_IsSubclass"]=wasmExports["PyObject_IsSubclass"])(a0,a1);var __pyproxy_repr=Module["__pyproxy_repr"]=a0=>(__pyproxy_repr=Module["__pyproxy_repr"]=wasmExports["_pyproxy_repr"])(a0);var _PyObject_Str=Module["_PyObject_Str"]=a0=>(_PyObject_Str=Module["_PyObject_Str"]=wasmExports["PyObject_Str"])(a0);var __pyproxy_type=Module["__pyproxy_type"]=a0=>(__pyproxy_type=Module["__pyproxy_type"]=wasmExports["_pyproxy_type"])(a0);var __pyproxy_hasattr=Module["__pyproxy_hasattr"]=(a0,a1)=>(__pyproxy_hasattr=Module["__pyproxy_hasattr"]=wasmExports["_pyproxy_hasattr"])(a0,a1);var _python2js_json_adaptor=Module["_python2js_json_adaptor"]=(a0,a1,a2)=>(_python2js_json_adaptor=Module["_python2js_json_adaptor"]=wasmExports["python2js_json_adaptor"])(a0,a1,a2);var __pyproxy_getattr=Module["__pyproxy_getattr"]=(a0,a1,a2)=>(__pyproxy_getattr=Module["__pyproxy_getattr"]=wasmExports["_pyproxy_getattr"])(a0,a1,a2);var __PyObject_GetMethod=Module["__PyObject_GetMethod"]=(a0,a1,a2)=>(__PyObject_GetMethod=Module["__PyObject_GetMethod"]=wasmExports["_PyObject_GetMethod"])(a0,a1,a2);var __pyproxy_setattr=Module["__pyproxy_setattr"]=(a0,a1,a2)=>(__pyproxy_setattr=Module["__pyproxy_setattr"]=wasmExports["_pyproxy_setattr"])(a0,a1,a2);var _PyObject_SetAttr=Module["_PyObject_SetAttr"]=(a0,a1,a2)=>(_PyObject_SetAttr=Module["_PyObject_SetAttr"]=wasmExports["PyObject_SetAttr"])(a0,a1,a2);var __pyproxy_delattr=Module["__pyproxy_delattr"]=(a0,a1)=>(__pyproxy_delattr=Module["__pyproxy_delattr"]=wasmExports["_pyproxy_delattr"])(a0,a1);var __pyproxy_getitem=Module["__pyproxy_getitem"]=(a0,a1,a2,a3)=>(__pyproxy_getitem=Module["__pyproxy_getitem"]=wasmExports["_pyproxy_getitem"])(a0,a1,a2,a3);var __pyproxy_setitem=Module["__pyproxy_setitem"]=(a0,a1,a2)=>(__pyproxy_setitem=Module["__pyproxy_setitem"]=wasmExports["_pyproxy_setitem"])(a0,a1,a2);var __pyproxy_delitem=Module["__pyproxy_delitem"]=(a0,a1)=>(__pyproxy_delitem=Module["__pyproxy_delitem"]=wasmExports["_pyproxy_delitem"])(a0,a1);var __pyproxy_slice_assign=Module["__pyproxy_slice_assign"]=(a0,a1,a2,a3)=>(__pyproxy_slice_assign=Module["__pyproxy_slice_assign"]=wasmExports["_pyproxy_slice_assign"])(a0,a1,a2,a3);var _PySequence_Size=Module["_PySequence_Size"]=a0=>(_PySequence_Size=Module["_PySequence_Size"]=wasmExports["PySequence_Size"])(a0);var _PySequence_GetSlice=Module["_PySequence_GetSlice"]=(a0,a1,a2)=>(_PySequence_GetSlice=Module["_PySequence_GetSlice"]=wasmExports["PySequence_GetSlice"])(a0,a1,a2);var _PySequence_SetSlice=Module["_PySequence_SetSlice"]=(a0,a1,a2,a3)=>(_PySequence_SetSlice=Module["_PySequence_SetSlice"]=wasmExports["PySequence_SetSlice"])(a0,a1,a2,a3);var _python2js_with_depth=Module["_python2js_with_depth"]=(a0,a1,a2)=>(_python2js_with_depth=Module["_python2js_with_depth"]=wasmExports["python2js_with_depth"])(a0,a1,a2);var __pyproxy_pop=Module["__pyproxy_pop"]=(a0,a1)=>(__pyproxy_pop=Module["__pyproxy_pop"]=wasmExports["_pyproxy_pop"])(a0,a1);var __pyproxy_contains=Module["__pyproxy_contains"]=(a0,a1)=>(__pyproxy_contains=Module["__pyproxy_contains"]=wasmExports["_pyproxy_contains"])(a0,a1);var _PySequence_Contains=Module["_PySequence_Contains"]=(a0,a1)=>(_PySequence_Contains=Module["_PySequence_Contains"]=wasmExports["PySequence_Contains"])(a0,a1);var __pyproxy_ownKeys=Module["__pyproxy_ownKeys"]=a0=>(__pyproxy_ownKeys=Module["__pyproxy_ownKeys"]=wasmExports["_pyproxy_ownKeys"])(a0);var _PyObject_Dir=Module["_PyObject_Dir"]=a0=>(_PyObject_Dir=Module["_PyObject_Dir"]=wasmExports["PyObject_Dir"])(a0);var _PyList_Size=Module["_PyList_Size"]=a0=>(_PyList_Size=Module["_PyList_Size"]=wasmExports["PyList_Size"])(a0);var _PyList_GetItem=Module["_PyList_GetItem"]=(a0,a1)=>(_PyList_GetItem=Module["_PyList_GetItem"]=wasmExports["PyList_GetItem"])(a0,a1);var __pyproxy_apply=Module["__pyproxy_apply"]=(a0,a1,a2,a3,a4)=>(__pyproxy_apply=Module["__pyproxy_apply"]=wasmExports["_pyproxy_apply"])(a0,a1,a2,a3,a4);var _PyTuple_New=Module["_PyTuple_New"]=a0=>(_PyTuple_New=Module["_PyTuple_New"]=wasmExports["PyTuple_New"])(a0);var __pyproxy_apply_promising=Module["__pyproxy_apply_promising"]=(a0,a1,a2,a3,a4,a5,a6)=>(__pyproxy_apply_promising=Module["__pyproxy_apply_promising"]=wasmExports["_pyproxy_apply_promising"])(a0,a1,a2,a3,a4,a5,a6);var _get_cframe=Module["_get_cframe"]=()=>(_get_cframe=Module["_get_cframe"]=wasmExports["get_cframe"])();var _exit_cframe=Module["_exit_cframe"]=a0=>(_exit_cframe=Module["_exit_cframe"]=wasmExports["exit_cframe"])(a0);var __iscoroutinefunction=Module["__iscoroutinefunction"]=a0=>(__iscoroutinefunction=Module["__iscoroutinefunction"]=wasmExports["_iscoroutinefunction"])(a0);var __pyproxy_iter_next=Module["__pyproxy_iter_next"]=(a0,a1,a2)=>(__pyproxy_iter_next=Module["__pyproxy_iter_next"]=wasmExports["_pyproxy_iter_next"])(a0,a1,a2);var _PyIter_Next=Module["_PyIter_Next"]=a0=>(_PyIter_Next=Module["_PyIter_Next"]=wasmExports["PyIter_Next"])(a0);var __pyproxyGen_Send=Module["__pyproxyGen_Send"]=(a0,a1)=>(__pyproxyGen_Send=Module["__pyproxyGen_Send"]=wasmExports["_pyproxyGen_Send"])(a0,a1);var _PyIter_Send=Module["_PyIter_Send"]=(a0,a1,a2)=>(_PyIter_Send=Module["_PyIter_Send"]=wasmExports["PyIter_Send"])(a0,a1,a2);var __pyproxyGen_return=Module["__pyproxyGen_return"]=(a0,a1)=>(__pyproxyGen_return=Module["__pyproxyGen_return"]=wasmExports["_pyproxyGen_return"])(a0,a1);var __PyGen_FetchStopIterationValue=Module["__PyGen_FetchStopIterationValue"]=a0=>(__PyGen_FetchStopIterationValue=Module["__PyGen_FetchStopIterationValue"]=wasmExports["_PyGen_FetchStopIterationValue"])(a0);var __pyproxyGen_throw=Module["__pyproxyGen_throw"]=(a0,a1)=>(__pyproxyGen_throw=Module["__pyproxyGen_throw"]=wasmExports["_pyproxyGen_throw"])(a0,a1);var __pyproxyGen_ascend=Module["__pyproxyGen_ascend"]=(a0,a1)=>(__pyproxyGen_ascend=Module["__pyproxyGen_ascend"]=wasmExports["_pyproxyGen_ascend"])(a0,a1);var __pyproxyGen_areturn=Module["__pyproxyGen_areturn"]=a0=>(__pyproxyGen_areturn=Module["__pyproxyGen_areturn"]=wasmExports["_pyproxyGen_areturn"])(a0);var __pyproxyGen_athrow=Module["__pyproxyGen_athrow"]=(a0,a1)=>(__pyproxyGen_athrow=Module["__pyproxyGen_athrow"]=wasmExports["_pyproxyGen_athrow"])(a0,a1);var __pyproxy_aiter_next=Module["__pyproxy_aiter_next"]=a0=>(__pyproxy_aiter_next=Module["__pyproxy_aiter_next"]=wasmExports["_pyproxy_aiter_next"])(a0);var _FutureDoneCallback_call_resolve=Module["_FutureDoneCallback_call_resolve"]=(a0,a1)=>(_FutureDoneCallback_call_resolve=Module["_FutureDoneCallback_call_resolve"]=wasmExports["FutureDoneCallback_call_resolve"])(a0,a1);var _FutureDoneCallback_call_reject=Module["_FutureDoneCallback_call_reject"]=a0=>(_FutureDoneCallback_call_reject=Module["_FutureDoneCallback_call_reject"]=wasmExports["FutureDoneCallback_call_reject"])(a0);var _FutureDoneCallback_call=Module["_FutureDoneCallback_call"]=(a0,a1,a2)=>(_FutureDoneCallback_call=Module["_FutureDoneCallback_call"]=wasmExports["FutureDoneCallback_call"])(a0,a1,a2);var _PyArg_UnpackTuple=Module["_PyArg_UnpackTuple"]=(a0,a1,a2,a3,a4)=>(_PyArg_UnpackTuple=Module["_PyArg_UnpackTuple"]=wasmExports["PyArg_UnpackTuple"])(a0,a1,a2,a3,a4);var __pyproxy_ensure_future=Module["__pyproxy_ensure_future"]=(a0,a1,a2)=>(__pyproxy_ensure_future=Module["__pyproxy_ensure_future"]=wasmExports["_pyproxy_ensure_future"])(a0,a1,a2);var __pyproxy_get_buffer=Module["__pyproxy_get_buffer"]=a0=>(__pyproxy_get_buffer=Module["__pyproxy_get_buffer"]=wasmExports["_pyproxy_get_buffer"])(a0);var _PyBuffer_FillContiguousStrides=Module["_PyBuffer_FillContiguousStrides"]=(a0,a1,a2,a3,a4)=>(_PyBuffer_FillContiguousStrides=Module["_PyBuffer_FillContiguousStrides"]=wasmExports["PyBuffer_FillContiguousStrides"])(a0,a1,a2,a3,a4);var _PyBuffer_IsContiguous=Module["_PyBuffer_IsContiguous"]=(a0,a1)=>(_PyBuffer_IsContiguous=Module["_PyBuffer_IsContiguous"]=wasmExports["PyBuffer_IsContiguous"])(a0,a1);var _create_promise_handles_result_helper=Module["_create_promise_handles_result_helper"]=(a0,a1,a2)=>(_create_promise_handles_result_helper=Module["_create_promise_handles_result_helper"]=wasmExports["create_promise_handles_result_helper"])(a0,a1,a2);var __python2js_buffer=Module["__python2js_buffer"]=a0=>(__python2js_buffer=Module["__python2js_buffer"]=wasmExports["_python2js_buffer"])(a0);var _jslib_init_buffers=Module["_jslib_init_buffers"]=()=>(_jslib_init_buffers=Module["_jslib_init_buffers"]=wasmExports["jslib_init_buffers"])();var _JsRef_pop=Module["_JsRef_pop"]=a0=>(_JsRef_pop=Module["_JsRef_pop"]=wasmExports["JsRef_pop"])(a0);var _JsrString_FromId=Module["_JsrString_FromId"]=a0=>(_JsrString_FromId=Module["_JsrString_FromId"]=wasmExports["JsrString_FromId"])(a0);var _hiwire_intern=Module["_hiwire_intern"]=a0=>(_hiwire_intern=Module["_hiwire_intern"]=wasmExports["hiwire_intern"])(a0);var __python2js=Module["__python2js"]=(a0,a1)=>(__python2js=Module["__python2js"]=wasmExports["_python2js"])(a0,a1);var _PySequence_GetItem=Module["_PySequence_GetItem"]=(a0,a1)=>(_PySequence_GetItem=Module["_PySequence_GetItem"]=wasmExports["PySequence_GetItem"])(a0,a1);var _PyObject_CheckBuffer=Module["_PyObject_CheckBuffer"]=a0=>(_PyObject_CheckBuffer=Module["_PyObject_CheckBuffer"]=wasmExports["PyObject_CheckBuffer"])(a0);var _PyFloat_AsDouble=Module["_PyFloat_AsDouble"]=a0=>(_PyFloat_AsDouble=Module["_PyFloat_AsDouble"]=wasmExports["PyFloat_AsDouble"])(a0);var _python2js__default_converter=Module["_python2js__default_converter"]=(a0,a1)=>(_python2js__default_converter=Module["_python2js__default_converter"]=wasmExports["python2js__default_converter"])(a0,a1);var _PyLong_AsLongAndOverflow=Module["_PyLong_AsLongAndOverflow"]=(a0,a1)=>(_PyLong_AsLongAndOverflow=Module["_PyLong_AsLongAndOverflow"]=wasmExports["PyLong_AsLongAndOverflow"])(a0,a1);var __PyLong_NumBits=Module["__PyLong_NumBits"]=a0=>(__PyLong_NumBits=Module["__PyLong_NumBits"]=wasmExports["_PyLong_NumBits"])(a0);var __PyLong_AsByteArray=Module["__PyLong_AsByteArray"]=(a0,a1,a2,a3,a4)=>(__PyLong_AsByteArray=Module["__PyLong_AsByteArray"]=wasmExports["_PyLong_AsByteArray"])(a0,a1,a2,a3,a4);var _py_version_minor=Module["_py_version_minor"]=()=>(_py_version_minor=Module["_py_version_minor"]=wasmExports["py_version_minor"])();var _py_version_micro=Module["_py_version_micro"]=()=>(_py_version_micro=Module["_py_version_micro"]=wasmExports["py_version_micro"])();var _saveAsyncioState=Module["_saveAsyncioState"]=a0=>(_saveAsyncioState=Module["_saveAsyncioState"]=wasmExports["saveAsyncioState"])(a0);var _PyObject_Hash=Module["_PyObject_Hash"]=a0=>(_PyObject_Hash=Module["_PyObject_Hash"]=wasmExports["PyObject_Hash"])(a0);var __PyDict_GetItem_KnownHash=Module["__PyDict_GetItem_KnownHash"]=(a0,a1,a2)=>(__PyDict_GetItem_KnownHash=Module["__PyDict_GetItem_KnownHash"]=wasmExports["_PyDict_GetItem_KnownHash"])(a0,a1,a2);var _restoreAsyncioState=Module["_restoreAsyncioState"]=a0=>(_restoreAsyncioState=Module["_restoreAsyncioState"]=wasmExports["restoreAsyncioState"])(a0);var _captureThreadState=Module["_captureThreadState"]=()=>(_captureThreadState=Module["_captureThreadState"]=wasmExports["captureThreadState"])();var _PyInterpreterState_Get=Module["_PyInterpreterState_Get"]=()=>(_PyInterpreterState_Get=Module["_PyInterpreterState_Get"]=wasmExports["PyInterpreterState_Get"])();var _PyThreadState_New=Module["_PyThreadState_New"]=a0=>(_PyThreadState_New=Module["_PyThreadState_New"]=wasmExports["PyThreadState_New"])(a0);var _restoreThreadState=Module["_restoreThreadState"]=a0=>(_restoreThreadState=Module["_restoreThreadState"]=wasmExports["restoreThreadState"])(a0);var _PyThreadState_Delete=Module["_PyThreadState_Delete"]=a0=>(_PyThreadState_Delete=Module["_PyThreadState_Delete"]=wasmExports["PyThreadState_Delete"])(a0);var _PyThreadState_Get=Module["_PyThreadState_Get"]=()=>(_PyThreadState_Get=Module["_PyThreadState_Get"]=wasmExports["PyThreadState_Get"])();var _restore_cframe=Module["_restore_cframe"]=a0=>(_restore_cframe=Module["_restore_cframe"]=wasmExports["restore_cframe"])(a0);var _PyObject_GetArenaAllocator=Module["_PyObject_GetArenaAllocator"]=a0=>(_PyObject_GetArenaAllocator=Module["_PyObject_GetArenaAllocator"]=wasmExports["PyObject_GetArenaAllocator"])(a0);var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["__main_argc_argv"])(a0,a1);var _PyImport_AppendInittab=Module["_PyImport_AppendInittab"]=(a0,a1)=>(_PyImport_AppendInittab=Module["_PyImport_AppendInittab"]=wasmExports["PyImport_AppendInittab"])(a0,a1);var _PyPreConfig_InitPythonConfig=Module["_PyPreConfig_InitPythonConfig"]=a0=>(_PyPreConfig_InitPythonConfig=Module["_PyPreConfig_InitPythonConfig"]=wasmExports["PyPreConfig_InitPythonConfig"])(a0);var _Py_PreInitializeFromBytesArgs=Module["_Py_PreInitializeFromBytesArgs"]=(a0,a1,a2,a3)=>(_Py_PreInitializeFromBytesArgs=Module["_Py_PreInitializeFromBytesArgs"]=wasmExports["Py_PreInitializeFromBytesArgs"])(a0,a1,a2,a3);var _PyStatus_Exception=Module["_PyStatus_Exception"]=a0=>(_PyStatus_Exception=Module["_PyStatus_Exception"]=wasmExports["PyStatus_Exception"])(a0);var _PyConfig_InitPythonConfig=Module["_PyConfig_InitPythonConfig"]=a0=>(_PyConfig_InitPythonConfig=Module["_PyConfig_InitPythonConfig"]=wasmExports["PyConfig_InitPythonConfig"])(a0);var _PyConfig_SetBytesArgv=Module["_PyConfig_SetBytesArgv"]=(a0,a1,a2,a3)=>(_PyConfig_SetBytesArgv=Module["_PyConfig_SetBytesArgv"]=wasmExports["PyConfig_SetBytesArgv"])(a0,a1,a2,a3);var _PyConfig_SetBytesString=Module["_PyConfig_SetBytesString"]=(a0,a1,a2,a3)=>(_PyConfig_SetBytesString=Module["_PyConfig_SetBytesString"]=wasmExports["PyConfig_SetBytesString"])(a0,a1,a2,a3);var _Py_InitializeFromConfig=Module["_Py_InitializeFromConfig"]=(a0,a1)=>(_Py_InitializeFromConfig=Module["_Py_InitializeFromConfig"]=wasmExports["Py_InitializeFromConfig"])(a0,a1);var _PyConfig_Clear=Module["_PyConfig_Clear"]=a0=>(_PyConfig_Clear=Module["_PyConfig_Clear"]=wasmExports["PyConfig_Clear"])(a0);var _Py_ExitStatusException=Module["_Py_ExitStatusException"]=a0=>(_Py_ExitStatusException=Module["_Py_ExitStatusException"]=wasmExports["Py_ExitStatusException"])(a0);var _run_main=Module["_run_main"]=()=>(_run_main=Module["_run_main"]=wasmExports["run_main"])();var _Py_GetBuildInfo=Module["_Py_GetBuildInfo"]=()=>(_Py_GetBuildInfo=Module["_Py_GetBuildInfo"]=wasmExports["Py_GetBuildInfo"])();var _PyOS_snprintf=Module["_PyOS_snprintf"]=(a0,a1,a2,a3)=>(_PyOS_snprintf=Module["_PyOS_snprintf"]=wasmExports["PyOS_snprintf"])(a0,a1,a2,a3);var __Py_gitversion=Module["__Py_gitversion"]=()=>(__Py_gitversion=Module["__Py_gitversion"]=wasmExports["_Py_gitversion"])();var __Py_gitidentifier=Module["__Py_gitidentifier"]=()=>(__Py_gitidentifier=Module["__Py_gitidentifier"]=wasmExports["_Py_gitidentifier"])();var __PyToken_OneChar=Module["__PyToken_OneChar"]=a0=>(__PyToken_OneChar=Module["__PyToken_OneChar"]=wasmExports["_PyToken_OneChar"])(a0);var __PyToken_TwoChars=Module["__PyToken_TwoChars"]=(a0,a1)=>(__PyToken_TwoChars=Module["__PyToken_TwoChars"]=wasmExports["_PyToken_TwoChars"])(a0,a1);var __PyToken_ThreeChars=Module["__PyToken_ThreeChars"]=(a0,a1,a2)=>(__PyToken_ThreeChars=Module["__PyToken_ThreeChars"]=wasmExports["_PyToken_ThreeChars"])(a0,a1,a2);var _strlen=Module["_strlen"]=a0=>(_strlen=Module["_strlen"]=wasmExports["strlen"])(a0);var _PyUnicode_DecodeUTF8=Module["_PyUnicode_DecodeUTF8"]=(a0,a1,a2)=>(_PyUnicode_DecodeUTF8=Module["_PyUnicode_DecodeUTF8"]=wasmExports["PyUnicode_DecodeUTF8"])(a0,a1,a2);var _PyUnicode_Substring=Module["_PyUnicode_Substring"]=(a0,a1,a2)=>(_PyUnicode_Substring=Module["_PyUnicode_Substring"]=wasmExports["PyUnicode_Substring"])(a0,a1,a2);var __PyImport_GetModuleAttrString=Module["__PyImport_GetModuleAttrString"]=(a0,a1)=>(__PyImport_GetModuleAttrString=Module["__PyImport_GetModuleAttrString"]=wasmExports["_PyImport_GetModuleAttrString"])(a0,a1);var __PyUnicode_EqualToASCIIString=Module["__PyUnicode_EqualToASCIIString"]=(a0,a1)=>(__PyUnicode_EqualToASCIIString=Module["__PyUnicode_EqualToASCIIString"]=wasmExports["_PyUnicode_EqualToASCIIString"])(a0,a1);var __PyArena_Malloc=Module["__PyArena_Malloc"]=(a0,a1)=>(__PyArena_Malloc=Module["__PyArena_Malloc"]=wasmExports["_PyArena_Malloc"])(a0,a1);var _strncpy=Module["_strncpy"]=(a0,a1,a2)=>(_strncpy=Module["_strncpy"]=wasmExports["strncpy"])(a0,a1,a2);var _PyMem_Realloc=Module["_PyMem_Realloc"]=(a0,a1)=>(_PyMem_Realloc=Module["_PyMem_Realloc"]=wasmExports["PyMem_Realloc"])(a0,a1);var _PyMem_Calloc=Module["_PyMem_Calloc"]=(a0,a1)=>(_PyMem_Calloc=Module["_PyMem_Calloc"]=wasmExports["PyMem_Calloc"])(a0,a1);var __PyArena_AddPyObject=Module["__PyArena_AddPyObject"]=(a0,a1)=>(__PyArena_AddPyObject=Module["__PyArena_AddPyObject"]=wasmExports["_PyArena_AddPyObject"])(a0,a1);var _PyBytes_AsString=Module["_PyBytes_AsString"]=a0=>(_PyBytes_AsString=Module["_PyBytes_AsString"]=wasmExports["PyBytes_AsString"])(a0);var _PyUnicode_InternFromString=Module["_PyUnicode_InternFromString"]=a0=>(_PyUnicode_InternFromString=Module["_PyUnicode_InternFromString"]=wasmExports["PyUnicode_InternFromString"])(a0);var __PyObject_FastCall=Module["__PyObject_FastCall"]=(a0,a1,a2)=>(__PyObject_FastCall=Module["__PyObject_FastCall"]=wasmExports["_PyObject_FastCall"])(a0,a1,a2);var __PyType_Name=Module["__PyType_Name"]=a0=>(__PyType_Name=Module["__PyType_Name"]=wasmExports["_PyType_Name"])(a0);var __PyUnicode_InternImmortal=Module["__PyUnicode_InternImmortal"]=(a0,a1)=>(__PyUnicode_InternImmortal=Module["__PyUnicode_InternImmortal"]=wasmExports["_PyUnicode_InternImmortal"])(a0,a1);var _PyBytes_AsStringAndSize=Module["_PyBytes_AsStringAndSize"]=(a0,a1,a2)=>(_PyBytes_AsStringAndSize=Module["_PyBytes_AsStringAndSize"]=wasmExports["PyBytes_AsStringAndSize"])(a0,a1,a2);var _strchr=Module["_strchr"]=(a0,a1)=>(_strchr=Module["_strchr"]=wasmExports["strchr"])(a0,a1);var _PyUnicode_CompareWithASCIIString=Module["_PyUnicode_CompareWithASCIIString"]=(a0,a1)=>(_PyUnicode_CompareWithASCIIString=Module["_PyUnicode_CompareWithASCIIString"]=wasmExports["PyUnicode_CompareWithASCIIString"])(a0,a1);var ___errno_location=()=>(___errno_location=wasmExports["__errno_location"])();var _PyOS_strtoul=Module["_PyOS_strtoul"]=(a0,a1,a2)=>(_PyOS_strtoul=Module["_PyOS_strtoul"]=wasmExports["PyOS_strtoul"])(a0,a1,a2);var _PyLong_FromString=Module["_PyLong_FromString"]=(a0,a1,a2)=>(_PyLong_FromString=Module["_PyLong_FromString"]=wasmExports["PyLong_FromString"])(a0,a1,a2);var _PyOS_strtol=Module["_PyOS_strtol"]=(a0,a1,a2)=>(_PyOS_strtol=Module["_PyOS_strtol"]=wasmExports["PyOS_strtol"])(a0,a1,a2);var _PyOS_string_to_double=Module["_PyOS_string_to_double"]=(a0,a1,a2)=>(_PyOS_string_to_double=Module["_PyOS_string_to_double"]=wasmExports["PyOS_string_to_double"])(a0,a1,a2);var _PyComplex_FromCComplex=Module["_PyComplex_FromCComplex"]=a0=>(_PyComplex_FromCComplex=Module["_PyComplex_FromCComplex"]=wasmExports["PyComplex_FromCComplex"])(a0);var _PyFloat_FromDouble=Module["_PyFloat_FromDouble"]=a0=>(_PyFloat_FromDouble=Module["_PyFloat_FromDouble"]=wasmExports["PyFloat_FromDouble"])(a0);var _Py_BuildValue=Module["_Py_BuildValue"]=(a0,a1)=>(_Py_BuildValue=Module["_Py_BuildValue"]=wasmExports["Py_BuildValue"])(a0,a1);var _PyUnicode_FromFormatV=Module["_PyUnicode_FromFormatV"]=(a0,a1)=>(_PyUnicode_FromFormatV=Module["_PyUnicode_FromFormatV"]=wasmExports["PyUnicode_FromFormatV"])(a0,a1);var __PyErr_ProgramDecodedTextObject=Module["__PyErr_ProgramDecodedTextObject"]=(a0,a1,a2)=>(__PyErr_ProgramDecodedTextObject=Module["__PyErr_ProgramDecodedTextObject"]=wasmExports["_PyErr_ProgramDecodedTextObject"])(a0,a1,a2);var _PyUnicode_FromStringAndSize=Module["_PyUnicode_FromStringAndSize"]=(a0,a1)=>(_PyUnicode_FromStringAndSize=Module["_PyUnicode_FromStringAndSize"]=wasmExports["PyUnicode_FromStringAndSize"])(a0,a1);var _strcpy=Module["_strcpy"]=(a0,a1)=>(_strcpy=Module["_strcpy"]=wasmExports["strcpy"])(a0,a1);var __PyUnicode_InternMortal=Module["__PyUnicode_InternMortal"]=(a0,a1)=>(__PyUnicode_InternMortal=Module["__PyUnicode_InternMortal"]=wasmExports["_PyUnicode_InternMortal"])(a0,a1);var _PyUnicode_GetLength=Module["_PyUnicode_GetLength"]=a0=>(_PyUnicode_GetLength=Module["_PyUnicode_GetLength"]=wasmExports["PyUnicode_GetLength"])(a0);var _PyBytes_FromString=Module["_PyBytes_FromString"]=a0=>(_PyBytes_FromString=Module["_PyBytes_FromString"]=wasmExports["PyBytes_FromString"])(a0);var _PyBytes_Concat=Module["_PyBytes_Concat"]=(a0,a1)=>(_PyBytes_Concat=Module["_PyBytes_Concat"]=wasmExports["PyBytes_Concat"])(a0,a1);var __PyUnicodeWriter_Init=Module["__PyUnicodeWriter_Init"]=a0=>(__PyUnicodeWriter_Init=Module["__PyUnicodeWriter_Init"]=wasmExports["_PyUnicodeWriter_Init"])(a0);var __PyUnicodeWriter_WriteStr=Module["__PyUnicodeWriter_WriteStr"]=(a0,a1)=>(__PyUnicodeWriter_WriteStr=Module["__PyUnicodeWriter_WriteStr"]=wasmExports["_PyUnicodeWriter_WriteStr"])(a0,a1);var __PyUnicodeWriter_Dealloc=Module["__PyUnicodeWriter_Dealloc"]=a0=>(__PyUnicodeWriter_Dealloc=Module["__PyUnicodeWriter_Dealloc"]=wasmExports["_PyUnicodeWriter_Dealloc"])(a0);var __PyUnicodeWriter_Finish=Module["__PyUnicodeWriter_Finish"]=a0=>(__PyUnicodeWriter_Finish=Module["__PyUnicodeWriter_Finish"]=wasmExports["_PyUnicodeWriter_Finish"])(a0);var _strpbrk=Module["_strpbrk"]=(a0,a1)=>(_strpbrk=Module["_strpbrk"]=wasmExports["strpbrk"])(a0,a1);var _PyUnicode_DecodeUTF8Stateful=Module["_PyUnicode_DecodeUTF8Stateful"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF8Stateful=Module["_PyUnicode_DecodeUTF8Stateful"]=wasmExports["PyUnicode_DecodeUTF8Stateful"])(a0,a1,a2,a3);var _siprintf=Module["_siprintf"]=(a0,a1,a2)=>(_siprintf=Module["_siprintf"]=wasmExports["siprintf"])(a0,a1,a2);var __PyUnicode_DecodeUnicodeEscapeInternal=Module["__PyUnicode_DecodeUnicodeEscapeInternal"]=(a0,a1,a2,a3,a4)=>(__PyUnicode_DecodeUnicodeEscapeInternal=Module["__PyUnicode_DecodeUnicodeEscapeInternal"]=wasmExports["_PyUnicode_DecodeUnicodeEscapeInternal"])(a0,a1,a2,a3,a4);var __PyErr_BadInternalCall=Module["__PyErr_BadInternalCall"]=(a0,a1)=>(__PyErr_BadInternalCall=Module["__PyErr_BadInternalCall"]=wasmExports["_PyErr_BadInternalCall"])(a0,a1);var __PyBytes_DecodeEscape=Module["__PyBytes_DecodeEscape"]=(a0,a1,a2,a3)=>(__PyBytes_DecodeEscape=Module["__PyBytes_DecodeEscape"]=wasmExports["_PyBytes_DecodeEscape"])(a0,a1,a2,a3);var _PyErr_WarnExplicitObject=Module["_PyErr_WarnExplicitObject"]=(a0,a1,a2,a3,a4,a5)=>(_PyErr_WarnExplicitObject=Module["_PyErr_WarnExplicitObject"]=wasmExports["PyErr_WarnExplicitObject"])(a0,a1,a2,a3,a4,a5);var _PySys_Audit=Module["_PySys_Audit"]=(a0,a1,a2)=>(_PySys_Audit=Module["_PySys_Audit"]=wasmExports["PySys_Audit"])(a0,a1,a2);var _fflush=Module["_fflush"]=a0=>(_fflush=Module["_fflush"]=wasmExports["fflush"])(a0);var _fputs=Module["_fputs"]=(a0,a1)=>(_fputs=Module["_fputs"]=wasmExports["fputs"])(a0,a1);var _PyMem_RawFree=Module["_PyMem_RawFree"]=a0=>(_PyMem_RawFree=Module["_PyMem_RawFree"]=wasmExports["PyMem_RawFree"])(a0);var _PyEval_RestoreThread=Module["_PyEval_RestoreThread"]=a0=>(_PyEval_RestoreThread=Module["_PyEval_RestoreThread"]=wasmExports["PyEval_RestoreThread"])(a0);var _PyEval_SaveThread=Module["_PyEval_SaveThread"]=()=>(_PyEval_SaveThread=Module["_PyEval_SaveThread"]=wasmExports["PyEval_SaveThread"])();var _PyMem_RawRealloc=Module["_PyMem_RawRealloc"]=(a0,a1)=>(_PyMem_RawRealloc=Module["_PyMem_RawRealloc"]=wasmExports["PyMem_RawRealloc"])(a0,a1);var _clearerr=Module["_clearerr"]=a0=>(_clearerr=Module["_clearerr"]=wasmExports["clearerr"])(a0);var _fgets=Module["_fgets"]=(a0,a1,a2)=>(_fgets=Module["_fgets"]=wasmExports["fgets"])(a0,a1,a2);var _feof=Module["_feof"]=a0=>(_feof=Module["_feof"]=wasmExports["feof"])(a0);var __PyOS_InterruptOccurred=Module["__PyOS_InterruptOccurred"]=a0=>(__PyOS_InterruptOccurred=Module["__PyOS_InterruptOccurred"]=wasmExports["_PyOS_InterruptOccurred"])(a0);var _PyErr_CheckSignals=Module["_PyErr_CheckSignals"]=()=>(_PyErr_CheckSignals=Module["_PyErr_CheckSignals"]=wasmExports["PyErr_CheckSignals"])();var _PyOS_Readline=Module["_PyOS_Readline"]=(a0,a1,a2)=>(_PyOS_Readline=Module["_PyOS_Readline"]=wasmExports["PyOS_Readline"])(a0,a1,a2);var _PyThread_allocate_lock=Module["_PyThread_allocate_lock"]=()=>(_PyThread_allocate_lock=Module["_PyThread_allocate_lock"]=wasmExports["PyThread_allocate_lock"])();var _PyThread_acquire_lock=Module["_PyThread_acquire_lock"]=(a0,a1)=>(_PyThread_acquire_lock=Module["_PyThread_acquire_lock"]=wasmExports["PyThread_acquire_lock"])(a0,a1);var _isatty=Module["_isatty"]=a0=>(_isatty=Module["_isatty"]=wasmExports["isatty"])(a0);var _PyThread_release_lock=Module["_PyThread_release_lock"]=a0=>(_PyThread_release_lock=Module["_PyThread_release_lock"]=wasmExports["PyThread_release_lock"])(a0);var _PyUnicode_Decode=Module["_PyUnicode_Decode"]=(a0,a1,a2,a3)=>(_PyUnicode_Decode=Module["_PyUnicode_Decode"]=wasmExports["PyUnicode_Decode"])(a0,a1,a2,a3);var _PyUnicode_AsUTF8String=Module["_PyUnicode_AsUTF8String"]=a0=>(_PyUnicode_AsUTF8String=Module["_PyUnicode_AsUTF8String"]=wasmExports["PyUnicode_AsUTF8String"])(a0);var __Py_FatalErrorFunc=Module["__Py_FatalErrorFunc"]=(a0,a1)=>(__Py_FatalErrorFunc=Module["__Py_FatalErrorFunc"]=wasmExports["_Py_FatalErrorFunc"])(a0,a1);var __Py_dup=Module["__Py_dup"]=a0=>(__Py_dup=Module["__Py_dup"]=wasmExports["_Py_dup"])(a0);var _fdopen=Module["_fdopen"]=(a0,a1)=>(_fdopen=Module["_fdopen"]=wasmExports["fdopen"])(a0,a1);var _fclose=Module["_fclose"]=a0=>(_fclose=Module["_fclose"]=wasmExports["fclose"])(a0);var _memcmp=Module["_memcmp"]=(a0,a1,a2)=>(_memcmp=Module["_memcmp"]=wasmExports["memcmp"])(a0,a1,a2);var _tolower=Module["_tolower"]=a0=>(_tolower=Module["_tolower"]=wasmExports["tolower"])(a0);var __PyUnicode_ScanIdentifier=Module["__PyUnicode_ScanIdentifier"]=a0=>(__PyUnicode_ScanIdentifier=Module["__PyUnicode_ScanIdentifier"]=wasmExports["_PyUnicode_ScanIdentifier"])(a0);var __PyUnicode_IsPrintable=Module["__PyUnicode_IsPrintable"]=a0=>(__PyUnicode_IsPrintable=Module["__PyUnicode_IsPrintable"]=wasmExports["_PyUnicode_IsPrintable"])(a0);var _isxdigit=Module["_isxdigit"]=a0=>(_isxdigit=Module["_isxdigit"]=wasmExports["isxdigit"])(a0);var _PyObject_CallNoArgs=Module["_PyObject_CallNoArgs"]=a0=>(_PyObject_CallNoArgs=Module["_PyObject_CallNoArgs"]=wasmExports["PyObject_CallNoArgs"])(a0);var _getc=Module["_getc"]=a0=>(_getc=Module["_getc"]=wasmExports["getc"])(a0);var _ungetc=Module["_ungetc"]=(a0,a1)=>(_ungetc=Module["_ungetc"]=wasmExports["ungetc"])(a0,a1);var __Py_UniversalNewlineFgetsWithSize=Module["__Py_UniversalNewlineFgetsWithSize"]=(a0,a1,a2,a3,a4)=>(__Py_UniversalNewlineFgetsWithSize=Module["__Py_UniversalNewlineFgetsWithSize"]=wasmExports["_Py_UniversalNewlineFgetsWithSize"])(a0,a1,a2,a3,a4);var _memchr=Module["_memchr"]=(a0,a1,a2)=>(_memchr=Module["_memchr"]=wasmExports["memchr"])(a0,a1,a2);var _PyObject_Malloc=Module["_PyObject_Malloc"]=a0=>(_PyObject_Malloc=Module["_PyObject_Malloc"]=wasmExports["PyObject_Malloc"])(a0);var _PyObject_Free=Module["_PyObject_Free"]=a0=>(_PyObject_Free=Module["_PyObject_Free"]=wasmExports["PyObject_Free"])(a0);var _ftell=Module["_ftell"]=a0=>(_ftell=Module["_ftell"]=wasmExports["ftell"])(a0);var _lseek=Module["_lseek"]=(a0,a1,a2)=>(_lseek=Module["_lseek"]=wasmExports["lseek"])(a0,a1,a2);var _PyErr_SetFromErrnoWithFilename=Module["_PyErr_SetFromErrnoWithFilename"]=(a0,a1)=>(_PyErr_SetFromErrnoWithFilename=Module["_PyErr_SetFromErrnoWithFilename"]=wasmExports["PyErr_SetFromErrnoWithFilename"])(a0,a1);var __PyObject_CallFunction_SizeT=Module["__PyObject_CallFunction_SizeT"]=(a0,a1,a2)=>(__PyObject_CallFunction_SizeT=Module["__PyObject_CallFunction_SizeT"]=wasmExports["_PyObject_CallFunction_SizeT"])(a0,a1,a2);var _PyObject_GetAttr=Module["_PyObject_GetAttr"]=(a0,a1)=>(_PyObject_GetAttr=Module["_PyObject_GetAttr"]=wasmExports["PyObject_GetAttr"])(a0,a1);var __PyObject_MakeTpCall=Module["__PyObject_MakeTpCall"]=(a0,a1,a2,a3,a4)=>(__PyObject_MakeTpCall=Module["__PyObject_MakeTpCall"]=wasmExports["_PyObject_MakeTpCall"])(a0,a1,a2,a3,a4);var __Py_CheckFunctionResult=Module["__Py_CheckFunctionResult"]=(a0,a1,a2,a3)=>(__Py_CheckFunctionResult=Module["__Py_CheckFunctionResult"]=wasmExports["_Py_CheckFunctionResult"])(a0,a1,a2,a3);var _strcspn=Module["_strcspn"]=(a0,a1)=>(_strcspn=Module["_strcspn"]=wasmExports["strcspn"])(a0,a1);var __Py_BuildValue_SizeT=Module["__Py_BuildValue_SizeT"]=(a0,a1)=>(__Py_BuildValue_SizeT=Module["__Py_BuildValue_SizeT"]=wasmExports["_Py_BuildValue_SizeT"])(a0,a1);var _PyObject_Type=Module["_PyObject_Type"]=a0=>(_PyObject_Type=Module["_PyObject_Type"]=wasmExports["PyObject_Type"])(a0);var __PyErr_SetString=Module["__PyErr_SetString"]=(a0,a1,a2)=>(__PyErr_SetString=Module["__PyErr_SetString"]=wasmExports["_PyErr_SetString"])(a0,a1,a2);var _PyObject_Size=Module["_PyObject_Size"]=a0=>(_PyObject_Size=Module["_PyObject_Size"]=wasmExports["PyObject_Size"])(a0);var _PyMapping_Size=Module["_PyMapping_Size"]=a0=>(_PyMapping_Size=Module["_PyMapping_Size"]=wasmExports["PyMapping_Size"])(a0);var _PyObject_Length=Module["_PyObject_Length"]=a0=>(_PyObject_Length=Module["_PyObject_Length"]=wasmExports["PyObject_Length"])(a0);var __PyObject_HasLen=Module["__PyObject_HasLen"]=a0=>(__PyObject_HasLen=Module["__PyObject_HasLen"]=wasmExports["_PyObject_HasLen"])(a0);var _PyObject_LengthHint=Module["_PyObject_LengthHint"]=(a0,a1)=>(_PyObject_LengthHint=Module["_PyObject_LengthHint"]=wasmExports["PyObject_LengthHint"])(a0,a1);var __PyErr_ExceptionMatches=Module["__PyErr_ExceptionMatches"]=(a0,a1)=>(__PyErr_ExceptionMatches=Module["__PyErr_ExceptionMatches"]=wasmExports["_PyErr_ExceptionMatches"])(a0,a1);var __PyErr_Clear=Module["__PyErr_Clear"]=a0=>(__PyErr_Clear=Module["__PyErr_Clear"]=wasmExports["_PyErr_Clear"])(a0);var __PyObject_LookupSpecial=Module["__PyObject_LookupSpecial"]=(a0,a1)=>(__PyObject_LookupSpecial=Module["__PyObject_LookupSpecial"]=wasmExports["_PyObject_LookupSpecial"])(a0,a1);var _Py_GenericAlias=Module["_Py_GenericAlias"]=(a0,a1)=>(_Py_GenericAlias=Module["_Py_GenericAlias"]=wasmExports["Py_GenericAlias"])(a0,a1);var __PyObject_LookupAttr=Module["__PyObject_LookupAttr"]=(a0,a1,a2)=>(__PyObject_LookupAttr=Module["__PyObject_LookupAttr"]=wasmExports["_PyObject_LookupAttr"])(a0,a1,a2);var __PyErr_Format=Module["__PyErr_Format"]=(a0,a1,a2,a3)=>(__PyErr_Format=Module["__PyErr_Format"]=wasmExports["_PyErr_Format"])(a0,a1,a2,a3);var _PySequence_SetItem=Module["_PySequence_SetItem"]=(a0,a1,a2)=>(_PySequence_SetItem=Module["_PySequence_SetItem"]=wasmExports["PySequence_SetItem"])(a0,a1,a2);var _PySequence_DelItem=Module["_PySequence_DelItem"]=(a0,a1)=>(_PySequence_DelItem=Module["_PySequence_DelItem"]=wasmExports["PySequence_DelItem"])(a0,a1);var _PyObject_DelItemString=Module["_PyObject_DelItemString"]=(a0,a1)=>(_PyObject_DelItemString=Module["_PyObject_DelItemString"]=wasmExports["PyObject_DelItemString"])(a0,a1);var _PyObject_CheckReadBuffer=Module["_PyObject_CheckReadBuffer"]=a0=>(_PyObject_CheckReadBuffer=Module["_PyObject_CheckReadBuffer"]=wasmExports["PyObject_CheckReadBuffer"])(a0);var _PyObject_AsCharBuffer=Module["_PyObject_AsCharBuffer"]=(a0,a1,a2)=>(_PyObject_AsCharBuffer=Module["_PyObject_AsCharBuffer"]=wasmExports["PyObject_AsCharBuffer"])(a0,a1,a2);var _PyObject_AsReadBuffer=Module["_PyObject_AsReadBuffer"]=(a0,a1,a2)=>(_PyObject_AsReadBuffer=Module["_PyObject_AsReadBuffer"]=wasmExports["PyObject_AsReadBuffer"])(a0,a1,a2);var _PyObject_AsWriteBuffer=Module["_PyObject_AsWriteBuffer"]=(a0,a1,a2)=>(_PyObject_AsWriteBuffer=Module["_PyObject_AsWriteBuffer"]=wasmExports["PyObject_AsWriteBuffer"])(a0,a1,a2);var _PyBuffer_GetPointer=Module["_PyBuffer_GetPointer"]=(a0,a1)=>(_PyBuffer_GetPointer=Module["_PyBuffer_GetPointer"]=wasmExports["PyBuffer_GetPointer"])(a0,a1);var __Py_add_one_to_index_F=Module["__Py_add_one_to_index_F"]=(a0,a1,a2)=>(__Py_add_one_to_index_F=Module["__Py_add_one_to_index_F"]=wasmExports["_Py_add_one_to_index_F"])(a0,a1,a2);var __Py_add_one_to_index_C=Module["__Py_add_one_to_index_C"]=(a0,a1,a2)=>(__Py_add_one_to_index_C=Module["__Py_add_one_to_index_C"]=wasmExports["_Py_add_one_to_index_C"])(a0,a1,a2);var _PyBuffer_SizeFromFormat=Module["_PyBuffer_SizeFromFormat"]=a0=>(_PyBuffer_SizeFromFormat=Module["_PyBuffer_SizeFromFormat"]=wasmExports["PyBuffer_SizeFromFormat"])(a0);var _PyObject_CallFunctionObjArgs=Module["_PyObject_CallFunctionObjArgs"]=(a0,a1)=>(_PyObject_CallFunctionObjArgs=Module["_PyObject_CallFunctionObjArgs"]=wasmExports["PyObject_CallFunctionObjArgs"])(a0,a1);var _PyBuffer_FromContiguous=Module["_PyBuffer_FromContiguous"]=(a0,a1,a2,a3)=>(_PyBuffer_FromContiguous=Module["_PyBuffer_FromContiguous"]=wasmExports["PyBuffer_FromContiguous"])(a0,a1,a2,a3);var _memset=Module["_memset"]=(a0,a1,a2)=>(_memset=Module["_memset"]=wasmExports["memset"])(a0,a1,a2);var _PyObject_CopyData=Module["_PyObject_CopyData"]=(a0,a1)=>(_PyObject_CopyData=Module["_PyObject_CopyData"]=wasmExports["PyObject_CopyData"])(a0,a1);var _PyBuffer_FillInfo=Module["_PyBuffer_FillInfo"]=(a0,a1,a2,a3,a4,a5)=>(_PyBuffer_FillInfo=Module["_PyBuffer_FillInfo"]=wasmExports["PyBuffer_FillInfo"])(a0,a1,a2,a3,a4,a5);var _PyObject_Format=Module["_PyObject_Format"]=(a0,a1)=>(_PyObject_Format=Module["_PyObject_Format"]=wasmExports["PyObject_Format"])(a0,a1);var _PyUnicode_New=Module["_PyUnicode_New"]=(a0,a1)=>(_PyUnicode_New=Module["_PyUnicode_New"]=wasmExports["PyUnicode_New"])(a0,a1);var _PyNumber_Check=Module["_PyNumber_Check"]=a0=>(_PyNumber_Check=Module["_PyNumber_Check"]=wasmExports["PyNumber_Check"])(a0);var _PyNumber_Or=Module["_PyNumber_Or"]=(a0,a1)=>(_PyNumber_Or=Module["_PyNumber_Or"]=wasmExports["PyNumber_Or"])(a0,a1);var _PyNumber_Xor=Module["_PyNumber_Xor"]=(a0,a1)=>(_PyNumber_Xor=Module["_PyNumber_Xor"]=wasmExports["PyNumber_Xor"])(a0,a1);var _PyNumber_And=Module["_PyNumber_And"]=(a0,a1)=>(_PyNumber_And=Module["_PyNumber_And"]=wasmExports["PyNumber_And"])(a0,a1);var _PyNumber_Lshift=Module["_PyNumber_Lshift"]=(a0,a1)=>(_PyNumber_Lshift=Module["_PyNumber_Lshift"]=wasmExports["PyNumber_Lshift"])(a0,a1);var _PyNumber_Rshift=Module["_PyNumber_Rshift"]=(a0,a1)=>(_PyNumber_Rshift=Module["_PyNumber_Rshift"]=wasmExports["PyNumber_Rshift"])(a0,a1);var _PyNumber_Subtract=Module["_PyNumber_Subtract"]=(a0,a1)=>(_PyNumber_Subtract=Module["_PyNumber_Subtract"]=wasmExports["PyNumber_Subtract"])(a0,a1);var _PyNumber_Divmod=Module["_PyNumber_Divmod"]=(a0,a1)=>(_PyNumber_Divmod=Module["_PyNumber_Divmod"]=wasmExports["PyNumber_Divmod"])(a0,a1);var _PyNumber_Add=Module["_PyNumber_Add"]=(a0,a1)=>(_PyNumber_Add=Module["_PyNumber_Add"]=wasmExports["PyNumber_Add"])(a0,a1);var _PyNumber_Multiply=Module["_PyNumber_Multiply"]=(a0,a1)=>(_PyNumber_Multiply=Module["_PyNumber_Multiply"]=wasmExports["PyNumber_Multiply"])(a0,a1);var _PyNumber_MatrixMultiply=Module["_PyNumber_MatrixMultiply"]=(a0,a1)=>(_PyNumber_MatrixMultiply=Module["_PyNumber_MatrixMultiply"]=wasmExports["PyNumber_MatrixMultiply"])(a0,a1);var _PyNumber_FloorDivide=Module["_PyNumber_FloorDivide"]=(a0,a1)=>(_PyNumber_FloorDivide=Module["_PyNumber_FloorDivide"]=wasmExports["PyNumber_FloorDivide"])(a0,a1);var _PyNumber_TrueDivide=Module["_PyNumber_TrueDivide"]=(a0,a1)=>(_PyNumber_TrueDivide=Module["_PyNumber_TrueDivide"]=wasmExports["PyNumber_TrueDivide"])(a0,a1);var _PyNumber_Remainder=Module["_PyNumber_Remainder"]=(a0,a1)=>(_PyNumber_Remainder=Module["_PyNumber_Remainder"]=wasmExports["PyNumber_Remainder"])(a0,a1);var _PyNumber_Power=Module["_PyNumber_Power"]=(a0,a1,a2)=>(_PyNumber_Power=Module["_PyNumber_Power"]=wasmExports["PyNumber_Power"])(a0,a1,a2);var _PyNumber_InPlaceOr=Module["_PyNumber_InPlaceOr"]=(a0,a1)=>(_PyNumber_InPlaceOr=Module["_PyNumber_InPlaceOr"]=wasmExports["PyNumber_InPlaceOr"])(a0,a1);var _PyNumber_InPlaceXor=Module["_PyNumber_InPlaceXor"]=(a0,a1)=>(_PyNumber_InPlaceXor=Module["_PyNumber_InPlaceXor"]=wasmExports["PyNumber_InPlaceXor"])(a0,a1);var _PyNumber_InPlaceAnd=Module["_PyNumber_InPlaceAnd"]=(a0,a1)=>(_PyNumber_InPlaceAnd=Module["_PyNumber_InPlaceAnd"]=wasmExports["PyNumber_InPlaceAnd"])(a0,a1);var _PyNumber_InPlaceLshift=Module["_PyNumber_InPlaceLshift"]=(a0,a1)=>(_PyNumber_InPlaceLshift=Module["_PyNumber_InPlaceLshift"]=wasmExports["PyNumber_InPlaceLshift"])(a0,a1);var _PyNumber_InPlaceRshift=Module["_PyNumber_InPlaceRshift"]=(a0,a1)=>(_PyNumber_InPlaceRshift=Module["_PyNumber_InPlaceRshift"]=wasmExports["PyNumber_InPlaceRshift"])(a0,a1);var _PyNumber_InPlaceSubtract=Module["_PyNumber_InPlaceSubtract"]=(a0,a1)=>(_PyNumber_InPlaceSubtract=Module["_PyNumber_InPlaceSubtract"]=wasmExports["PyNumber_InPlaceSubtract"])(a0,a1);var _PyNumber_InPlaceMatrixMultiply=Module["_PyNumber_InPlaceMatrixMultiply"]=(a0,a1)=>(_PyNumber_InPlaceMatrixMultiply=Module["_PyNumber_InPlaceMatrixMultiply"]=wasmExports["PyNumber_InPlaceMatrixMultiply"])(a0,a1);var _PyNumber_InPlaceFloorDivide=Module["_PyNumber_InPlaceFloorDivide"]=(a0,a1)=>(_PyNumber_InPlaceFloorDivide=Module["_PyNumber_InPlaceFloorDivide"]=wasmExports["PyNumber_InPlaceFloorDivide"])(a0,a1);var _PyNumber_InPlaceTrueDivide=Module["_PyNumber_InPlaceTrueDivide"]=(a0,a1)=>(_PyNumber_InPlaceTrueDivide=Module["_PyNumber_InPlaceTrueDivide"]=wasmExports["PyNumber_InPlaceTrueDivide"])(a0,a1);var _PyNumber_InPlaceRemainder=Module["_PyNumber_InPlaceRemainder"]=(a0,a1)=>(_PyNumber_InPlaceRemainder=Module["_PyNumber_InPlaceRemainder"]=wasmExports["PyNumber_InPlaceRemainder"])(a0,a1);var _PyNumber_InPlaceAdd=Module["_PyNumber_InPlaceAdd"]=(a0,a1)=>(_PyNumber_InPlaceAdd=Module["_PyNumber_InPlaceAdd"]=wasmExports["PyNumber_InPlaceAdd"])(a0,a1);var _PyNumber_InPlaceMultiply=Module["_PyNumber_InPlaceMultiply"]=(a0,a1)=>(_PyNumber_InPlaceMultiply=Module["_PyNumber_InPlaceMultiply"]=wasmExports["PyNumber_InPlaceMultiply"])(a0,a1);var _PyNumber_InPlacePower=Module["_PyNumber_InPlacePower"]=(a0,a1,a2)=>(_PyNumber_InPlacePower=Module["_PyNumber_InPlacePower"]=wasmExports["PyNumber_InPlacePower"])(a0,a1,a2);var _PyNumber_Negative=Module["_PyNumber_Negative"]=a0=>(_PyNumber_Negative=Module["_PyNumber_Negative"]=wasmExports["PyNumber_Negative"])(a0);var _PyNumber_Positive=Module["_PyNumber_Positive"]=a0=>(_PyNumber_Positive=Module["_PyNumber_Positive"]=wasmExports["PyNumber_Positive"])(a0);var _PyNumber_Invert=Module["_PyNumber_Invert"]=a0=>(_PyNumber_Invert=Module["_PyNumber_Invert"]=wasmExports["PyNumber_Invert"])(a0);var _PyNumber_Absolute=Module["_PyNumber_Absolute"]=a0=>(_PyNumber_Absolute=Module["_PyNumber_Absolute"]=wasmExports["PyNumber_Absolute"])(a0);var _PyErr_WarnFormat=Module["_PyErr_WarnFormat"]=(a0,a1,a2,a3)=>(_PyErr_WarnFormat=Module["_PyErr_WarnFormat"]=wasmExports["PyErr_WarnFormat"])(a0,a1,a2,a3);var _PyNumber_Index=Module["_PyNumber_Index"]=a0=>(_PyNumber_Index=Module["_PyNumber_Index"]=wasmExports["PyNumber_Index"])(a0);var __PyLong_Copy=Module["__PyLong_Copy"]=a0=>(__PyLong_Copy=Module["__PyLong_Copy"]=wasmExports["_PyLong_Copy"])(a0);var _PyNumber_Long=Module["_PyNumber_Long"]=a0=>(_PyNumber_Long=Module["_PyNumber_Long"]=wasmExports["PyNumber_Long"])(a0);var _PyErr_WarnEx=Module["_PyErr_WarnEx"]=(a0,a1,a2)=>(_PyErr_WarnEx=Module["_PyErr_WarnEx"]=wasmExports["PyErr_WarnEx"])(a0,a1,a2);var _PyLong_FromUnicodeObject=Module["_PyLong_FromUnicodeObject"]=(a0,a1)=>(_PyLong_FromUnicodeObject=Module["_PyLong_FromUnicodeObject"]=wasmExports["PyLong_FromUnicodeObject"])(a0,a1);var __PyLong_FromBytes=Module["__PyLong_FromBytes"]=(a0,a1,a2)=>(__PyLong_FromBytes=Module["__PyLong_FromBytes"]=wasmExports["_PyLong_FromBytes"])(a0,a1,a2);var _PyNumber_Float=Module["_PyNumber_Float"]=a0=>(_PyNumber_Float=Module["_PyNumber_Float"]=wasmExports["PyNumber_Float"])(a0);var _PyLong_AsDouble=Module["_PyLong_AsDouble"]=a0=>(_PyLong_AsDouble=Module["_PyLong_AsDouble"]=wasmExports["PyLong_AsDouble"])(a0);var _PyFloat_FromString=Module["_PyFloat_FromString"]=a0=>(_PyFloat_FromString=Module["_PyFloat_FromString"]=wasmExports["PyFloat_FromString"])(a0);var _PyNumber_ToBase=Module["_PyNumber_ToBase"]=(a0,a1)=>(_PyNumber_ToBase=Module["_PyNumber_ToBase"]=wasmExports["PyNumber_ToBase"])(a0,a1);var __PyLong_Format=Module["__PyLong_Format"]=(a0,a1)=>(__PyLong_Format=Module["__PyLong_Format"]=wasmExports["_PyLong_Format"])(a0,a1);var _PySequence_Check=Module["_PySequence_Check"]=a0=>(_PySequence_Check=Module["_PySequence_Check"]=wasmExports["PySequence_Check"])(a0);var _PySequence_Length=Module["_PySequence_Length"]=a0=>(_PySequence_Length=Module["_PySequence_Length"]=wasmExports["PySequence_Length"])(a0);var _PySequence_Concat=Module["_PySequence_Concat"]=(a0,a1)=>(_PySequence_Concat=Module["_PySequence_Concat"]=wasmExports["PySequence_Concat"])(a0,a1);var _PySequence_Repeat=Module["_PySequence_Repeat"]=(a0,a1)=>(_PySequence_Repeat=Module["_PySequence_Repeat"]=wasmExports["PySequence_Repeat"])(a0,a1);var _PySequence_InPlaceConcat=Module["_PySequence_InPlaceConcat"]=(a0,a1)=>(_PySequence_InPlaceConcat=Module["_PySequence_InPlaceConcat"]=wasmExports["PySequence_InPlaceConcat"])(a0,a1);var _PySequence_InPlaceRepeat=Module["_PySequence_InPlaceRepeat"]=(a0,a1)=>(_PySequence_InPlaceRepeat=Module["_PySequence_InPlaceRepeat"]=wasmExports["PySequence_InPlaceRepeat"])(a0,a1);var __PySlice_FromIndices=Module["__PySlice_FromIndices"]=(a0,a1)=>(__PySlice_FromIndices=Module["__PySlice_FromIndices"]=wasmExports["_PySlice_FromIndices"])(a0,a1);var _PySequence_DelSlice=Module["_PySequence_DelSlice"]=(a0,a1,a2)=>(_PySequence_DelSlice=Module["_PySequence_DelSlice"]=wasmExports["PySequence_DelSlice"])(a0,a1,a2);var _PySequence_Tuple=Module["_PySequence_Tuple"]=a0=>(_PySequence_Tuple=Module["_PySequence_Tuple"]=wasmExports["PySequence_Tuple"])(a0);var _PyList_AsTuple=Module["_PyList_AsTuple"]=a0=>(_PyList_AsTuple=Module["_PyList_AsTuple"]=wasmExports["PyList_AsTuple"])(a0);var __PyTuple_Resize=Module["__PyTuple_Resize"]=(a0,a1)=>(__PyTuple_Resize=Module["__PyTuple_Resize"]=wasmExports["_PyTuple_Resize"])(a0,a1);var _PySeqIter_New=Module["_PySeqIter_New"]=a0=>(_PySeqIter_New=Module["_PySeqIter_New"]=wasmExports["PySeqIter_New"])(a0);var _PySequence_List=Module["_PySequence_List"]=a0=>(_PySequence_List=Module["_PySequence_List"]=wasmExports["PySequence_List"])(a0);var __PySequence_IterSearch=Module["__PySequence_IterSearch"]=(a0,a1,a2)=>(__PySequence_IterSearch=Module["__PySequence_IterSearch"]=wasmExports["_PySequence_IterSearch"])(a0,a1,a2);var _PySequence_Count=Module["_PySequence_Count"]=(a0,a1)=>(_PySequence_Count=Module["_PySequence_Count"]=wasmExports["PySequence_Count"])(a0,a1);var _PySequence_In=Module["_PySequence_In"]=(a0,a1)=>(_PySequence_In=Module["_PySequence_In"]=wasmExports["PySequence_In"])(a0,a1);var _PySequence_Index=Module["_PySequence_Index"]=(a0,a1)=>(_PySequence_Index=Module["_PySequence_Index"]=wasmExports["PySequence_Index"])(a0,a1);var _PyMapping_Check=Module["_PyMapping_Check"]=a0=>(_PyMapping_Check=Module["_PyMapping_Check"]=wasmExports["PyMapping_Check"])(a0);var _PyMapping_Length=Module["_PyMapping_Length"]=a0=>(_PyMapping_Length=Module["_PyMapping_Length"]=wasmExports["PyMapping_Length"])(a0);var _PyMapping_GetItemString=Module["_PyMapping_GetItemString"]=(a0,a1)=>(_PyMapping_GetItemString=Module["_PyMapping_GetItemString"]=wasmExports["PyMapping_GetItemString"])(a0,a1);var _PyMapping_SetItemString=Module["_PyMapping_SetItemString"]=(a0,a1,a2)=>(_PyMapping_SetItemString=Module["_PyMapping_SetItemString"]=wasmExports["PyMapping_SetItemString"])(a0,a1,a2);var _PyMapping_HasKeyString=Module["_PyMapping_HasKeyString"]=(a0,a1)=>(_PyMapping_HasKeyString=Module["_PyMapping_HasKeyString"]=wasmExports["PyMapping_HasKeyString"])(a0,a1);var _PyMapping_HasKey=Module["_PyMapping_HasKey"]=(a0,a1)=>(_PyMapping_HasKey=Module["_PyMapping_HasKey"]=wasmExports["PyMapping_HasKey"])(a0,a1);var _PyMapping_Keys=Module["_PyMapping_Keys"]=a0=>(_PyMapping_Keys=Module["_PyMapping_Keys"]=wasmExports["PyMapping_Keys"])(a0);var _PyDict_Keys=Module["_PyDict_Keys"]=a0=>(_PyDict_Keys=Module["_PyDict_Keys"]=wasmExports["PyDict_Keys"])(a0);var _PyMapping_Items=Module["_PyMapping_Items"]=a0=>(_PyMapping_Items=Module["_PyMapping_Items"]=wasmExports["PyMapping_Items"])(a0);var _PyDict_Items=Module["_PyDict_Items"]=a0=>(_PyDict_Items=Module["_PyDict_Items"]=wasmExports["PyDict_Items"])(a0);var _PyMapping_Values=Module["_PyMapping_Values"]=a0=>(_PyMapping_Values=Module["_PyMapping_Values"]=wasmExports["PyMapping_Values"])(a0);var _PyDict_Values=Module["_PyDict_Values"]=a0=>(_PyDict_Values=Module["_PyDict_Values"]=wasmExports["PyDict_Values"])(a0);var __Py_CheckRecursiveCall=Module["__Py_CheckRecursiveCall"]=(a0,a1)=>(__Py_CheckRecursiveCall=Module["__Py_CheckRecursiveCall"]=wasmExports["_Py_CheckRecursiveCall"])(a0,a1);var _PyObject_IsTrue=Module["_PyObject_IsTrue"]=a0=>(_PyObject_IsTrue=Module["_PyObject_IsTrue"]=wasmExports["PyObject_IsTrue"])(a0);var __PyObject_RealIsInstance=Module["__PyObject_RealIsInstance"]=(a0,a1)=>(__PyObject_RealIsInstance=Module["__PyObject_RealIsInstance"]=wasmExports["_PyObject_RealIsInstance"])(a0,a1);var __PyObject_RealIsSubclass=Module["__PyObject_RealIsSubclass"]=(a0,a1)=>(__PyObject_RealIsSubclass=Module["__PyObject_RealIsSubclass"]=wasmExports["_PyObject_RealIsSubclass"])(a0,a1);var _PyIter_Check=Module["_PyIter_Check"]=a0=>(_PyIter_Check=Module["_PyIter_Check"]=wasmExports["PyIter_Check"])(a0);var _PyObject_GetAIter=Module["_PyObject_GetAIter"]=a0=>(_PyObject_GetAIter=Module["_PyObject_GetAIter"]=wasmExports["PyObject_GetAIter"])(a0);var _PyAIter_Check=Module["_PyAIter_Check"]=a0=>(_PyAIter_Check=Module["_PyAIter_Check"]=wasmExports["PyAIter_Check"])(a0);var __PySequence_BytesToCharpArray=Module["__PySequence_BytesToCharpArray"]=a0=>(__PySequence_BytesToCharpArray=Module["__PySequence_BytesToCharpArray"]=wasmExports["_PySequence_BytesToCharpArray"])(a0);var __Py_FreeCharPArray=Module["__Py_FreeCharPArray"]=a0=>(__Py_FreeCharPArray=Module["__Py_FreeCharPArray"]=wasmExports["_Py_FreeCharPArray"])(a0);var _PyBool_FromLong=Module["_PyBool_FromLong"]=a0=>(_PyBool_FromLong=Module["_PyBool_FromLong"]=wasmExports["PyBool_FromLong"])(a0);var __PyArg_NoKeywords=Module["__PyArg_NoKeywords"]=(a0,a1)=>(__PyArg_NoKeywords=Module["__PyArg_NoKeywords"]=wasmExports["_PyArg_NoKeywords"])(a0,a1);var __PyArg_NoKwnames=Module["__PyArg_NoKwnames"]=(a0,a1)=>(__PyArg_NoKwnames=Module["__PyArg_NoKwnames"]=wasmExports["_PyArg_NoKwnames"])(a0,a1);var _memrchr=Module["_memrchr"]=(a0,a1,a2)=>(_memrchr=Module["_memrchr"]=wasmExports["memrchr"])(a0,a1,a2);var __PyEval_SliceIndex=Module["__PyEval_SliceIndex"]=(a0,a1)=>(__PyEval_SliceIndex=Module["__PyEval_SliceIndex"]=wasmExports["_PyEval_SliceIndex"])(a0,a1);var _PyByteArray_FromObject=Module["_PyByteArray_FromObject"]=a0=>(_PyByteArray_FromObject=Module["_PyByteArray_FromObject"]=wasmExports["PyByteArray_FromObject"])(a0);var _PyByteArray_FromStringAndSize=Module["_PyByteArray_FromStringAndSize"]=(a0,a1)=>(_PyByteArray_FromStringAndSize=Module["_PyByteArray_FromStringAndSize"]=wasmExports["PyByteArray_FromStringAndSize"])(a0,a1);var __PyObject_New=Module["__PyObject_New"]=a0=>(__PyObject_New=Module["__PyObject_New"]=wasmExports["_PyObject_New"])(a0);var _PyByteArray_Size=Module["_PyByteArray_Size"]=a0=>(_PyByteArray_Size=Module["_PyByteArray_Size"]=wasmExports["PyByteArray_Size"])(a0);var _PyByteArray_AsString=Module["_PyByteArray_AsString"]=a0=>(_PyByteArray_AsString=Module["_PyByteArray_AsString"]=wasmExports["PyByteArray_AsString"])(a0);var _PyByteArray_Resize=Module["_PyByteArray_Resize"]=(a0,a1)=>(_PyByteArray_Resize=Module["_PyByteArray_Resize"]=wasmExports["PyByteArray_Resize"])(a0,a1);var _PyObject_Realloc=Module["_PyObject_Realloc"]=(a0,a1)=>(_PyObject_Realloc=Module["_PyObject_Realloc"]=wasmExports["PyObject_Realloc"])(a0,a1);var _PyByteArray_Concat=Module["_PyByteArray_Concat"]=(a0,a1)=>(_PyByteArray_Concat=Module["_PyByteArray_Concat"]=wasmExports["PyByteArray_Concat"])(a0,a1);var __Py_GetConfig=Module["__Py_GetConfig"]=()=>(__Py_GetConfig=Module["__Py_GetConfig"]=wasmExports["_Py_GetConfig"])();var __PyObject_GC_New=Module["__PyObject_GC_New"]=a0=>(__PyObject_GC_New=Module["__PyObject_GC_New"]=wasmExports["_PyObject_GC_New"])(a0);var __PyArg_UnpackKeywords=Module["__PyArg_UnpackKeywords"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(__PyArg_UnpackKeywords=Module["__PyArg_UnpackKeywords"]=wasmExports["_PyArg_UnpackKeywords"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var __PyArg_BadArgument=Module["__PyArg_BadArgument"]=(a0,a1,a2,a3)=>(__PyArg_BadArgument=Module["__PyArg_BadArgument"]=wasmExports["_PyArg_BadArgument"])(a0,a1,a2,a3);var _PyUnicode_AsEncodedString=Module["_PyUnicode_AsEncodedString"]=(a0,a1,a2)=>(_PyUnicode_AsEncodedString=Module["_PyUnicode_AsEncodedString"]=wasmExports["PyUnicode_AsEncodedString"])(a0,a1,a2);var _PyBuffer_ToContiguous=Module["_PyBuffer_ToContiguous"]=(a0,a1,a2,a3)=>(_PyBuffer_ToContiguous=Module["_PyBuffer_ToContiguous"]=wasmExports["PyBuffer_ToContiguous"])(a0,a1,a2,a3);var _PyObject_GC_Del=Module["_PyObject_GC_Del"]=a0=>(_PyObject_GC_Del=Module["_PyObject_GC_Del"]=wasmExports["PyObject_GC_Del"])(a0);var __PyBytes_FormatEx=Module["__PyBytes_FormatEx"]=(a0,a1,a2,a3)=>(__PyBytes_FormatEx=Module["__PyBytes_FormatEx"]=wasmExports["_PyBytes_FormatEx"])(a0,a1,a2,a3);var __PyBytes_Repeat=Module["__PyBytes_Repeat"]=(a0,a1,a2,a3)=>(__PyBytes_Repeat=Module["__PyBytes_Repeat"]=wasmExports["_PyBytes_Repeat"])(a0,a1,a2,a3);var _memmove=Module["_memmove"]=(a0,a1,a2)=>(_memmove=Module["_memmove"]=wasmExports["memmove"])(a0,a1,a2);var __PyObject_GetState=Module["__PyObject_GetState"]=a0=>(__PyObject_GetState=Module["__PyObject_GetState"]=wasmExports["_PyObject_GetState"])(a0);var _PyUnicode_DecodeLatin1=Module["_PyUnicode_DecodeLatin1"]=(a0,a1,a2)=>(_PyUnicode_DecodeLatin1=Module["_PyUnicode_DecodeLatin1"]=wasmExports["PyUnicode_DecodeLatin1"])(a0,a1,a2);var __PyLong_AsInt=Module["__PyLong_AsInt"]=a0=>(__PyLong_AsInt=Module["__PyLong_AsInt"]=wasmExports["_PyLong_AsInt"])(a0);var _PyLong_FromSize_t=Module["_PyLong_FromSize_t"]=a0=>(_PyLong_FromSize_t=Module["_PyLong_FromSize_t"]=wasmExports["PyLong_FromSize_t"])(a0);var _PyUnicode_GetDefaultEncoding=Module["_PyUnicode_GetDefaultEncoding"]=()=>(_PyUnicode_GetDefaultEncoding=Module["_PyUnicode_GetDefaultEncoding"]=wasmExports["PyUnicode_GetDefaultEncoding"])();var _PyUnicode_FromEncodedObject=Module["_PyUnicode_FromEncodedObject"]=(a0,a1,a2)=>(_PyUnicode_FromEncodedObject=Module["_PyUnicode_FromEncodedObject"]=wasmExports["PyUnicode_FromEncodedObject"])(a0,a1,a2);var __PyBytes_FromHex=Module["__PyBytes_FromHex"]=(a0,a1)=>(__PyBytes_FromHex=Module["__PyBytes_FromHex"]=wasmExports["_PyBytes_FromHex"])(a0,a1);var __Py_strhex_with_sep=Module["__Py_strhex_with_sep"]=(a0,a1,a2,a3)=>(__Py_strhex_with_sep=Module["__Py_strhex_with_sep"]=wasmExports["_Py_strhex_with_sep"])(a0,a1,a2,a3);var _PyList_Append=Module["_PyList_Append"]=(a0,a1)=>(_PyList_Append=Module["_PyList_Append"]=wasmExports["PyList_Append"])(a0,a1);var _PyList_Reverse=Module["_PyList_Reverse"]=a0=>(_PyList_Reverse=Module["_PyList_Reverse"]=wasmExports["PyList_Reverse"])(a0);var __PyEval_GetBuiltin=Module["__PyEval_GetBuiltin"]=a0=>(__PyEval_GetBuiltin=Module["__PyEval_GetBuiltin"]=wasmExports["_PyEval_GetBuiltin"])(a0);var _PyObject_GenericGetAttr=Module["_PyObject_GenericGetAttr"]=(a0,a1)=>(_PyObject_GenericGetAttr=Module["_PyObject_GenericGetAttr"]=wasmExports["PyObject_GenericGetAttr"])(a0,a1);var _PyType_GenericAlloc=Module["_PyType_GenericAlloc"]=(a0,a1)=>(_PyType_GenericAlloc=Module["_PyType_GenericAlloc"]=wasmExports["PyType_GenericAlloc"])(a0,a1);var _PyObject_Calloc=Module["_PyObject_Calloc"]=(a0,a1)=>(_PyObject_Calloc=Module["_PyObject_Calloc"]=wasmExports["PyObject_Calloc"])(a0,a1);var __Py_NewReference=Module["__Py_NewReference"]=a0=>(__Py_NewReference=Module["__Py_NewReference"]=wasmExports["_Py_NewReference"])(a0);var _PyBytes_FromFormatV=Module["_PyBytes_FromFormatV"]=(a0,a1)=>(_PyBytes_FromFormatV=Module["_PyBytes_FromFormatV"]=wasmExports["PyBytes_FromFormatV"])(a0,a1);var __PyBytesWriter_Resize=Module["__PyBytesWriter_Resize"]=(a0,a1,a2)=>(__PyBytesWriter_Resize=Module["__PyBytesWriter_Resize"]=wasmExports["_PyBytesWriter_Resize"])(a0,a1,a2);var __PyBytesWriter_Finish=Module["__PyBytesWriter_Finish"]=(a0,a1)=>(__PyBytesWriter_Finish=Module["__PyBytesWriter_Finish"]=wasmExports["_PyBytesWriter_Finish"])(a0,a1);var __PyBytesWriter_Init=Module["__PyBytesWriter_Init"]=a0=>(__PyBytesWriter_Init=Module["__PyBytesWriter_Init"]=wasmExports["_PyBytesWriter_Init"])(a0);var __PyBytesWriter_Alloc=Module["__PyBytesWriter_Alloc"]=(a0,a1)=>(__PyBytesWriter_Alloc=Module["__PyBytesWriter_Alloc"]=wasmExports["_PyBytesWriter_Alloc"])(a0,a1);var __PyBytesWriter_WriteBytes=Module["__PyBytesWriter_WriteBytes"]=(a0,a1,a2,a3)=>(__PyBytesWriter_WriteBytes=Module["__PyBytesWriter_WriteBytes"]=wasmExports["_PyBytesWriter_WriteBytes"])(a0,a1,a2,a3);var __PyBytes_Resize=Module["__PyBytes_Resize"]=(a0,a1)=>(__PyBytes_Resize=Module["__PyBytes_Resize"]=wasmExports["_PyBytes_Resize"])(a0,a1);var __PyBytesWriter_Dealloc=Module["__PyBytesWriter_Dealloc"]=a0=>(__PyBytesWriter_Dealloc=Module["__PyBytesWriter_Dealloc"]=wasmExports["_PyBytesWriter_Dealloc"])(a0);var _PyBytes_FromFormat=Module["_PyBytes_FromFormat"]=(a0,a1)=>(_PyBytes_FromFormat=Module["_PyBytes_FromFormat"]=wasmExports["PyBytes_FromFormat"])(a0,a1);var _PyObject_ASCII=Module["_PyObject_ASCII"]=a0=>(_PyObject_ASCII=Module["_PyObject_ASCII"]=wasmExports["PyObject_ASCII"])(a0);var __PyLong_FormatBytesWriter=Module["__PyLong_FormatBytesWriter"]=(a0,a1,a2,a3,a4)=>(__PyLong_FormatBytesWriter=Module["__PyLong_FormatBytesWriter"]=wasmExports["_PyLong_FormatBytesWriter"])(a0,a1,a2,a3,a4);var __PyUnicode_FormatLong=Module["__PyUnicode_FormatLong"]=(a0,a1,a2,a3)=>(__PyUnicode_FormatLong=Module["__PyUnicode_FormatLong"]=wasmExports["_PyUnicode_FormatLong"])(a0,a1,a2,a3);var _PyOS_double_to_string=Module["_PyOS_double_to_string"]=(a0,a1,a2,a3,a4)=>(_PyOS_double_to_string=Module["_PyOS_double_to_string"]=wasmExports["PyOS_double_to_string"])(a0,a1,a2,a3,a4);var __PyBytesWriter_Prepare=Module["__PyBytesWriter_Prepare"]=(a0,a1,a2)=>(__PyBytesWriter_Prepare=Module["__PyBytesWriter_Prepare"]=wasmExports["_PyBytesWriter_Prepare"])(a0,a1,a2);var _PyBytes_DecodeEscape=Module["_PyBytes_DecodeEscape"]=(a0,a1,a2,a3,a4)=>(_PyBytes_DecodeEscape=Module["_PyBytes_DecodeEscape"]=wasmExports["PyBytes_DecodeEscape"])(a0,a1,a2,a3,a4);var _PyBytes_Size=Module["_PyBytes_Size"]=a0=>(_PyBytes_Size=Module["_PyBytes_Size"]=wasmExports["PyBytes_Size"])(a0);var __PyBytes_Find=Module["__PyBytes_Find"]=(a0,a1,a2,a3,a4)=>(__PyBytes_Find=Module["__PyBytes_Find"]=wasmExports["_PyBytes_Find"])(a0,a1,a2,a3,a4);var __PyBytes_ReverseFind=Module["__PyBytes_ReverseFind"]=(a0,a1,a2,a3,a4)=>(__PyBytes_ReverseFind=Module["__PyBytes_ReverseFind"]=wasmExports["_PyBytes_ReverseFind"])(a0,a1,a2,a3,a4);var _PyBytes_Repr=Module["_PyBytes_Repr"]=(a0,a1)=>(_PyBytes_Repr=Module["_PyBytes_Repr"]=wasmExports["PyBytes_Repr"])(a0,a1);var __PyBytes_Join=Module["__PyBytes_Join"]=(a0,a1)=>(__PyBytes_Join=Module["__PyBytes_Join"]=wasmExports["_PyBytes_Join"])(a0,a1);var _PyBytes_FromObject=Module["_PyBytes_FromObject"]=a0=>(_PyBytes_FromObject=Module["_PyBytes_FromObject"]=wasmExports["PyBytes_FromObject"])(a0);var _PyErr_BadArgument=Module["_PyErr_BadArgument"]=()=>(_PyErr_BadArgument=Module["_PyErr_BadArgument"]=wasmExports["PyErr_BadArgument"])();var __Py_NewReferenceNoTotal=Module["__Py_NewReferenceNoTotal"]=a0=>(__Py_NewReferenceNoTotal=Module["__Py_NewReferenceNoTotal"]=wasmExports["_Py_NewReferenceNoTotal"])(a0);var _PyBytes_ConcatAndDel=Module["_PyBytes_ConcatAndDel"]=(a0,a1)=>(_PyBytes_ConcatAndDel=Module["_PyBytes_ConcatAndDel"]=wasmExports["PyBytes_ConcatAndDel"])(a0,a1);var __PyErr_FormatFromCauseTstate=Module["__PyErr_FormatFromCauseTstate"]=(a0,a1,a2,a3)=>(__PyErr_FormatFromCauseTstate=Module["__PyErr_FormatFromCauseTstate"]=wasmExports["_PyErr_FormatFromCauseTstate"])(a0,a1,a2,a3);var __Py_FatalErrorFormat=Module["__Py_FatalErrorFormat"]=(a0,a1,a2)=>(__Py_FatalErrorFormat=Module["__Py_FatalErrorFormat"]=wasmExports["_Py_FatalErrorFormat"])(a0,a1,a2);var __PyObject_FastCallDictTstate=Module["__PyObject_FastCallDictTstate"]=(a0,a1,a2,a3,a4)=>(__PyObject_FastCallDictTstate=Module["__PyObject_FastCallDictTstate"]=wasmExports["_PyObject_FastCallDictTstate"])(a0,a1,a2,a3,a4);var _PyVectorcall_Function=Module["_PyVectorcall_Function"]=a0=>(_PyVectorcall_Function=Module["_PyVectorcall_Function"]=wasmExports["PyVectorcall_Function"])(a0);var __PyErr_NoMemory=Module["__PyErr_NoMemory"]=a0=>(__PyErr_NoMemory=Module["__PyErr_NoMemory"]=wasmExports["_PyErr_NoMemory"])(a0);var _PyDict_Next=Module["_PyDict_Next"]=(a0,a1,a2,a3)=>(_PyDict_Next=Module["_PyDict_Next"]=wasmExports["PyDict_Next"])(a0,a1,a2,a3);var _PyObject_VectorcallDict=Module["_PyObject_VectorcallDict"]=(a0,a1,a2,a3)=>(_PyObject_VectorcallDict=Module["_PyObject_VectorcallDict"]=wasmExports["PyObject_VectorcallDict"])(a0,a1,a2,a3);var _PyModule_GetNameObject=Module["_PyModule_GetNameObject"]=a0=>(_PyModule_GetNameObject=Module["_PyModule_GetNameObject"]=wasmExports["PyModule_GetNameObject"])(a0);var _PyCallable_Check=Module["_PyCallable_Check"]=a0=>(_PyCallable_Check=Module["_PyCallable_Check"]=wasmExports["PyCallable_Check"])(a0);var __PyStack_AsDict=Module["__PyStack_AsDict"]=(a0,a1)=>(__PyStack_AsDict=Module["__PyStack_AsDict"]=wasmExports["_PyStack_AsDict"])(a0,a1);var __PyObject_Call=Module["__PyObject_Call"]=(a0,a1,a2,a3)=>(__PyObject_Call=Module["__PyObject_Call"]=wasmExports["_PyObject_Call"])(a0,a1,a2,a3);var _PyObject_Call=Module["_PyObject_Call"]=(a0,a1,a2)=>(_PyObject_Call=Module["_PyObject_Call"]=wasmExports["PyObject_Call"])(a0,a1,a2);var _PyCFunction_Call=Module["_PyCFunction_Call"]=(a0,a1,a2)=>(_PyCFunction_Call=Module["_PyCFunction_Call"]=wasmExports["PyCFunction_Call"])(a0,a1,a2);var __PyFunction_Vectorcall=Module["__PyFunction_Vectorcall"]=(a0,a1,a2,a3)=>(__PyFunction_Vectorcall=Module["__PyFunction_Vectorcall"]=wasmExports["_PyFunction_Vectorcall"])(a0,a1,a2,a3);var _PyEval_CallObjectWithKeywords=Module["_PyEval_CallObjectWithKeywords"]=(a0,a1,a2)=>(_PyEval_CallObjectWithKeywords=Module["_PyEval_CallObjectWithKeywords"]=wasmExports["PyEval_CallObjectWithKeywords"])(a0,a1,a2);var _PyObject_CallObject=Module["_PyObject_CallObject"]=(a0,a1)=>(_PyObject_CallObject=Module["_PyObject_CallObject"]=wasmExports["PyObject_CallObject"])(a0,a1);var __PyObject_Call_Prepend=Module["__PyObject_Call_Prepend"]=(a0,a1,a2,a3,a4)=>(__PyObject_Call_Prepend=Module["__PyObject_Call_Prepend"]=wasmExports["_PyObject_Call_Prepend"])(a0,a1,a2,a3,a4);var _PyObject_CallFunction=Module["_PyObject_CallFunction"]=(a0,a1,a2)=>(_PyObject_CallFunction=Module["_PyObject_CallFunction"]=wasmExports["PyObject_CallFunction"])(a0,a1,a2);var __Py_VaBuildStack_SizeT=Module["__Py_VaBuildStack_SizeT"]=(a0,a1,a2,a3,a4)=>(__Py_VaBuildStack_SizeT=Module["__Py_VaBuildStack_SizeT"]=wasmExports["_Py_VaBuildStack_SizeT"])(a0,a1,a2,a3,a4);var __Py_VaBuildStack=Module["__Py_VaBuildStack"]=(a0,a1,a2,a3,a4)=>(__Py_VaBuildStack=Module["__Py_VaBuildStack"]=wasmExports["_Py_VaBuildStack"])(a0,a1,a2,a3,a4);var _PyEval_CallFunction=Module["_PyEval_CallFunction"]=(a0,a1,a2)=>(_PyEval_CallFunction=Module["_PyEval_CallFunction"]=wasmExports["PyEval_CallFunction"])(a0,a1,a2);var _PyObject_CallMethod=Module["_PyObject_CallMethod"]=(a0,a1,a2,a3)=>(_PyObject_CallMethod=Module["_PyObject_CallMethod"]=wasmExports["PyObject_CallMethod"])(a0,a1,a2,a3);var _PyEval_CallMethod=Module["_PyEval_CallMethod"]=(a0,a1,a2,a3)=>(_PyEval_CallMethod=Module["_PyEval_CallMethod"]=wasmExports["PyEval_CallMethod"])(a0,a1,a2,a3);var __PyObject_CallMethod=Module["__PyObject_CallMethod"]=(a0,a1,a2,a3)=>(__PyObject_CallMethod=Module["__PyObject_CallMethod"]=wasmExports["_PyObject_CallMethod"])(a0,a1,a2,a3);var __PyObject_CallMethodId=Module["__PyObject_CallMethodId"]=(a0,a1,a2,a3)=>(__PyObject_CallMethodId=Module["__PyObject_CallMethodId"]=wasmExports["_PyObject_CallMethodId"])(a0,a1,a2,a3);var __PyObject_CallMethod_SizeT=Module["__PyObject_CallMethod_SizeT"]=(a0,a1,a2,a3)=>(__PyObject_CallMethod_SizeT=Module["__PyObject_CallMethod_SizeT"]=wasmExports["_PyObject_CallMethod_SizeT"])(a0,a1,a2,a3);var __PyObject_CallMethodId_SizeT=Module["__PyObject_CallMethodId_SizeT"]=(a0,a1,a2,a3)=>(__PyObject_CallMethodId_SizeT=Module["__PyObject_CallMethodId_SizeT"]=wasmExports["_PyObject_CallMethodId_SizeT"])(a0,a1,a2,a3);var _PyObject_CallMethodObjArgs=Module["_PyObject_CallMethodObjArgs"]=(a0,a1,a2)=>(_PyObject_CallMethodObjArgs=Module["_PyObject_CallMethodObjArgs"]=wasmExports["PyObject_CallMethodObjArgs"])(a0,a1,a2);var _PyVectorcall_NARGS=Module["_PyVectorcall_NARGS"]=a0=>(_PyVectorcall_NARGS=Module["_PyVectorcall_NARGS"]=wasmExports["PyVectorcall_NARGS"])(a0);var _PyCapsule_New=Module["_PyCapsule_New"]=(a0,a1,a2)=>(_PyCapsule_New=Module["_PyCapsule_New"]=wasmExports["PyCapsule_New"])(a0,a1,a2);var _PyCapsule_IsValid=Module["_PyCapsule_IsValid"]=(a0,a1)=>(_PyCapsule_IsValid=Module["_PyCapsule_IsValid"]=wasmExports["PyCapsule_IsValid"])(a0,a1);var _PyCapsule_GetPointer=Module["_PyCapsule_GetPointer"]=(a0,a1)=>(_PyCapsule_GetPointer=Module["_PyCapsule_GetPointer"]=wasmExports["PyCapsule_GetPointer"])(a0,a1);var _PyCapsule_GetName=Module["_PyCapsule_GetName"]=a0=>(_PyCapsule_GetName=Module["_PyCapsule_GetName"]=wasmExports["PyCapsule_GetName"])(a0);var _PyCapsule_GetDestructor=Module["_PyCapsule_GetDestructor"]=a0=>(_PyCapsule_GetDestructor=Module["_PyCapsule_GetDestructor"]=wasmExports["PyCapsule_GetDestructor"])(a0);var _PyCapsule_GetContext=Module["_PyCapsule_GetContext"]=a0=>(_PyCapsule_GetContext=Module["_PyCapsule_GetContext"]=wasmExports["PyCapsule_GetContext"])(a0);var _PyCapsule_SetPointer=Module["_PyCapsule_SetPointer"]=(a0,a1)=>(_PyCapsule_SetPointer=Module["_PyCapsule_SetPointer"]=wasmExports["PyCapsule_SetPointer"])(a0,a1);var _PyCapsule_SetName=Module["_PyCapsule_SetName"]=(a0,a1)=>(_PyCapsule_SetName=Module["_PyCapsule_SetName"]=wasmExports["PyCapsule_SetName"])(a0,a1);var _PyCapsule_SetDestructor=Module["_PyCapsule_SetDestructor"]=(a0,a1)=>(_PyCapsule_SetDestructor=Module["_PyCapsule_SetDestructor"]=wasmExports["PyCapsule_SetDestructor"])(a0,a1);var _PyCapsule_SetContext=Module["_PyCapsule_SetContext"]=(a0,a1)=>(_PyCapsule_SetContext=Module["_PyCapsule_SetContext"]=wasmExports["PyCapsule_SetContext"])(a0,a1);var _PyCapsule_Import=Module["_PyCapsule_Import"]=(a0,a1)=>(_PyCapsule_Import=Module["_PyCapsule_Import"]=wasmExports["PyCapsule_Import"])(a0,a1);var _PyCell_New=Module["_PyCell_New"]=a0=>(_PyCell_New=Module["_PyCell_New"]=wasmExports["PyCell_New"])(a0);var _PyCell_Get=Module["_PyCell_Get"]=a0=>(_PyCell_Get=Module["_PyCell_Get"]=wasmExports["PyCell_Get"])(a0);var _PyCell_Set=Module["_PyCell_Set"]=(a0,a1)=>(_PyCell_Set=Module["_PyCell_Set"]=wasmExports["PyCell_Set"])(a0,a1);var _PyObject_RichCompare=Module["_PyObject_RichCompare"]=(a0,a1,a2)=>(_PyObject_RichCompare=Module["_PyObject_RichCompare"]=wasmExports["PyObject_RichCompare"])(a0,a1,a2);var _PyMethod_Function=Module["_PyMethod_Function"]=a0=>(_PyMethod_Function=Module["_PyMethod_Function"]=wasmExports["PyMethod_Function"])(a0);var _PyMethod_Self=Module["_PyMethod_Self"]=a0=>(_PyMethod_Self=Module["_PyMethod_Self"]=wasmExports["PyMethod_Self"])(a0);var _PyMethod_New=Module["_PyMethod_New"]=(a0,a1)=>(_PyMethod_New=Module["_PyMethod_New"]=wasmExports["PyMethod_New"])(a0,a1);var _PyObject_ClearWeakRefs=Module["_PyObject_ClearWeakRefs"]=a0=>(_PyObject_ClearWeakRefs=Module["_PyObject_ClearWeakRefs"]=wasmExports["PyObject_ClearWeakRefs"])(a0);var __Py_HashPointer=Module["__Py_HashPointer"]=a0=>(__Py_HashPointer=Module["__Py_HashPointer"]=wasmExports["_Py_HashPointer"])(a0);var __PyType_GetDict=Module["__PyType_GetDict"]=a0=>(__PyType_GetDict=Module["__PyType_GetDict"]=wasmExports["_PyType_GetDict"])(a0);var __PyType_Lookup=Module["__PyType_Lookup"]=(a0,a1)=>(__PyType_Lookup=Module["__PyType_Lookup"]=wasmExports["_PyType_Lookup"])(a0,a1);var _PyInstanceMethod_New=Module["_PyInstanceMethod_New"]=a0=>(_PyInstanceMethod_New=Module["_PyInstanceMethod_New"]=wasmExports["PyInstanceMethod_New"])(a0);var _PyInstanceMethod_Function=Module["_PyInstanceMethod_Function"]=a0=>(_PyInstanceMethod_Function=Module["_PyInstanceMethod_Function"]=wasmExports["PyInstanceMethod_Function"])(a0);var _PyCode_AddWatcher=Module["_PyCode_AddWatcher"]=a0=>(_PyCode_AddWatcher=Module["_PyCode_AddWatcher"]=wasmExports["PyCode_AddWatcher"])(a0);var _PyCode_ClearWatcher=Module["_PyCode_ClearWatcher"]=a0=>(_PyCode_ClearWatcher=Module["_PyCode_ClearWatcher"]=wasmExports["PyCode_ClearWatcher"])(a0);var __PyCode_Validate=Module["__PyCode_Validate"]=a0=>(__PyCode_Validate=Module["__PyCode_Validate"]=wasmExports["_PyCode_Validate"])(a0);var __PyCode_New=Module["__PyCode_New"]=a0=>(__PyCode_New=Module["__PyCode_New"]=wasmExports["_PyCode_New"])(a0);var __PyObject_NewVar=Module["__PyObject_NewVar"]=(a0,a1)=>(__PyObject_NewVar=Module["__PyObject_NewVar"]=wasmExports["_PyObject_NewVar"])(a0,a1);var _PyFrozenSet_New=Module["_PyFrozenSet_New"]=a0=>(_PyFrozenSet_New=Module["_PyFrozenSet_New"]=wasmExports["PyFrozenSet_New"])(a0);var _PyUnstable_Code_NewWithPosOnlyArgs=Module["_PyUnstable_Code_NewWithPosOnlyArgs"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17)=>(_PyUnstable_Code_NewWithPosOnlyArgs=Module["_PyUnstable_Code_NewWithPosOnlyArgs"]=wasmExports["PyUnstable_Code_NewWithPosOnlyArgs"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17);var _PyUnicode_Compare=Module["_PyUnicode_Compare"]=(a0,a1)=>(_PyUnicode_Compare=Module["_PyUnicode_Compare"]=wasmExports["PyUnicode_Compare"])(a0,a1);var _PyUnstable_Code_New=Module["_PyUnstable_Code_New"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)=>(_PyUnstable_Code_New=Module["_PyUnstable_Code_New"]=wasmExports["PyUnstable_Code_New"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16);var _PyCode_NewEmpty=Module["_PyCode_NewEmpty"]=(a0,a1,a2)=>(_PyCode_NewEmpty=Module["_PyCode_NewEmpty"]=wasmExports["PyCode_NewEmpty"])(a0,a1,a2);var _PyUnicode_DecodeFSDefault=Module["_PyUnicode_DecodeFSDefault"]=a0=>(_PyUnicode_DecodeFSDefault=Module["_PyUnicode_DecodeFSDefault"]=wasmExports["PyUnicode_DecodeFSDefault"])(a0);var _PyCode_Addr2Line=Module["_PyCode_Addr2Line"]=(a0,a1)=>(_PyCode_Addr2Line=Module["_PyCode_Addr2Line"]=wasmExports["PyCode_Addr2Line"])(a0,a1);var __PyCode_CheckLineNumber=Module["__PyCode_CheckLineNumber"]=(a0,a1)=>(__PyCode_CheckLineNumber=Module["__PyCode_CheckLineNumber"]=wasmExports["_PyCode_CheckLineNumber"])(a0,a1);var _PyCode_Addr2Location=Module["_PyCode_Addr2Location"]=(a0,a1,a2,a3,a4,a5)=>(_PyCode_Addr2Location=Module["_PyCode_Addr2Location"]=wasmExports["PyCode_Addr2Location"])(a0,a1,a2,a3,a4,a5);var _PyUnstable_Code_GetExtra=Module["_PyUnstable_Code_GetExtra"]=(a0,a1,a2)=>(_PyUnstable_Code_GetExtra=Module["_PyUnstable_Code_GetExtra"]=wasmExports["PyUnstable_Code_GetExtra"])(a0,a1,a2);var _PyUnstable_Code_SetExtra=Module["_PyUnstable_Code_SetExtra"]=(a0,a1,a2)=>(_PyUnstable_Code_SetExtra=Module["_PyUnstable_Code_SetExtra"]=wasmExports["PyUnstable_Code_SetExtra"])(a0,a1,a2);var _PyCode_GetVarnames=Module["_PyCode_GetVarnames"]=a0=>(_PyCode_GetVarnames=Module["_PyCode_GetVarnames"]=wasmExports["PyCode_GetVarnames"])(a0);var _PyCode_GetCellvars=Module["_PyCode_GetCellvars"]=a0=>(_PyCode_GetCellvars=Module["_PyCode_GetCellvars"]=wasmExports["PyCode_GetCellvars"])(a0);var _PyCode_GetFreevars=Module["_PyCode_GetFreevars"]=a0=>(_PyCode_GetFreevars=Module["_PyCode_GetFreevars"]=wasmExports["PyCode_GetFreevars"])(a0);var _PyCode_GetCode=Module["_PyCode_GetCode"]=a0=>(_PyCode_GetCode=Module["_PyCode_GetCode"]=wasmExports["PyCode_GetCode"])(a0);var __PyCode_ConstantKey=Module["__PyCode_ConstantKey"]=a0=>(__PyCode_ConstantKey=Module["__PyCode_ConstantKey"]=wasmExports["_PyCode_ConstantKey"])(a0);var _PyComplex_AsCComplex=Module["_PyComplex_AsCComplex"]=(a0,a1)=>(_PyComplex_AsCComplex=Module["_PyComplex_AsCComplex"]=wasmExports["PyComplex_AsCComplex"])(a0,a1);var __PySet_NextEntry=Module["__PySet_NextEntry"]=(a0,a1,a2,a3)=>(__PySet_NextEntry=Module["__PySet_NextEntry"]=wasmExports["_PySet_NextEntry"])(a0,a1,a2,a3);var _PyLong_FromVoidPtr=Module["_PyLong_FromVoidPtr"]=a0=>(_PyLong_FromVoidPtr=Module["_PyLong_FromVoidPtr"]=wasmExports["PyLong_FromVoidPtr"])(a0);var __PyUnicode_FromASCII=Module["__PyUnicode_FromASCII"]=(a0,a1)=>(__PyUnicode_FromASCII=Module["__PyUnicode_FromASCII"]=wasmExports["_PyUnicode_FromASCII"])(a0,a1);var _PyErr_WriteUnraisable=Module["_PyErr_WriteUnraisable"]=a0=>(_PyErr_WriteUnraisable=Module["_PyErr_WriteUnraisable"]=wasmExports["PyErr_WriteUnraisable"])(a0);var __PyUnicode_Copy=Module["__PyUnicode_Copy"]=a0=>(__PyUnicode_Copy=Module["__PyUnicode_Copy"]=wasmExports["_PyUnicode_Copy"])(a0);var __Py_c_sum=Module["__Py_c_sum"]=(a0,a1,a2)=>(__Py_c_sum=Module["__Py_c_sum"]=wasmExports["_Py_c_sum"])(a0,a1,a2);var __Py_c_diff=Module["__Py_c_diff"]=(a0,a1,a2)=>(__Py_c_diff=Module["__Py_c_diff"]=wasmExports["_Py_c_diff"])(a0,a1,a2);var __Py_c_neg=Module["__Py_c_neg"]=(a0,a1)=>(__Py_c_neg=Module["__Py_c_neg"]=wasmExports["_Py_c_neg"])(a0,a1);var __Py_c_prod=Module["__Py_c_prod"]=(a0,a1,a2)=>(__Py_c_prod=Module["__Py_c_prod"]=wasmExports["_Py_c_prod"])(a0,a1,a2);var __Py_c_quot=Module["__Py_c_quot"]=(a0,a1,a2)=>(__Py_c_quot=Module["__Py_c_quot"]=wasmExports["_Py_c_quot"])(a0,a1,a2);var __Py_c_pow=Module["__Py_c_pow"]=(a0,a1,a2)=>(__Py_c_pow=Module["__Py_c_pow"]=wasmExports["_Py_c_pow"])(a0,a1,a2);var _hypot=Module["_hypot"]=(a0,a1)=>(_hypot=Module["_hypot"]=wasmExports["hypot"])(a0,a1);var _atan2=Module["_atan2"]=(a0,a1)=>(_atan2=Module["_atan2"]=wasmExports["atan2"])(a0,a1);var _pow=Module["_pow"]=(a0,a1)=>(_pow=Module["_pow"]=wasmExports["pow"])(a0,a1);var _log=Module["_log"]=a0=>(_log=Module["_log"]=wasmExports["log"])(a0);var _exp=Module["_exp"]=a0=>(_exp=Module["_exp"]=wasmExports["exp"])(a0);var _sin=Module["_sin"]=a0=>(_sin=Module["_sin"]=wasmExports["sin"])(a0);var _cos=Module["_cos"]=a0=>(_cos=Module["_cos"]=wasmExports["cos"])(a0);var __Py_c_abs=Module["__Py_c_abs"]=a0=>(__Py_c_abs=Module["__Py_c_abs"]=wasmExports["_Py_c_abs"])(a0);var _PyComplex_FromDoubles=Module["_PyComplex_FromDoubles"]=(a0,a1)=>(_PyComplex_FromDoubles=Module["_PyComplex_FromDoubles"]=wasmExports["PyComplex_FromDoubles"])(a0,a1);var _PyComplex_RealAsDouble=Module["_PyComplex_RealAsDouble"]=a0=>(_PyComplex_RealAsDouble=Module["_PyComplex_RealAsDouble"]=wasmExports["PyComplex_RealAsDouble"])(a0);var _PyComplex_ImagAsDouble=Module["_PyComplex_ImagAsDouble"]=a0=>(_PyComplex_ImagAsDouble=Module["_PyComplex_ImagAsDouble"]=wasmExports["PyComplex_ImagAsDouble"])(a0);var __Py_HashDouble=Module["__Py_HashDouble"]=(a0,a1)=>(__Py_HashDouble=Module["__Py_HashDouble"]=wasmExports["_Py_HashDouble"])(a0,a1);var __PyUnicode_TransformDecimalAndSpaceToASCII=Module["__PyUnicode_TransformDecimalAndSpaceToASCII"]=a0=>(__PyUnicode_TransformDecimalAndSpaceToASCII=Module["__PyUnicode_TransformDecimalAndSpaceToASCII"]=wasmExports["_PyUnicode_TransformDecimalAndSpaceToASCII"])(a0);var __Py_string_to_number_with_underscores=Module["__Py_string_to_number_with_underscores"]=(a0,a1,a2,a3,a4,a5)=>(__Py_string_to_number_with_underscores=Module["__Py_string_to_number_with_underscores"]=wasmExports["_Py_string_to_number_with_underscores"])(a0,a1,a2,a3,a4,a5);var _PyCMethod_New=Module["_PyCMethod_New"]=(a0,a1,a2,a3)=>(_PyCMethod_New=Module["_PyCMethod_New"]=wasmExports["PyCMethod_New"])(a0,a1,a2,a3);var _PyMember_GetOne=Module["_PyMember_GetOne"]=(a0,a1)=>(_PyMember_GetOne=Module["_PyMember_GetOne"]=wasmExports["PyMember_GetOne"])(a0,a1);var _PyMember_SetOne=Module["_PyMember_SetOne"]=(a0,a1,a2)=>(_PyMember_SetOne=Module["_PyMember_SetOne"]=wasmExports["PyMember_SetOne"])(a0,a1,a2);var _PyTuple_GetSlice=Module["_PyTuple_GetSlice"]=(a0,a1,a2)=>(_PyTuple_GetSlice=Module["_PyTuple_GetSlice"]=wasmExports["PyTuple_GetSlice"])(a0,a1,a2);var _PyDescr_NewMethod=Module["_PyDescr_NewMethod"]=(a0,a1)=>(_PyDescr_NewMethod=Module["_PyDescr_NewMethod"]=wasmExports["PyDescr_NewMethod"])(a0,a1);var __PyObject_FunctionStr=Module["__PyObject_FunctionStr"]=a0=>(__PyObject_FunctionStr=Module["__PyObject_FunctionStr"]=wasmExports["_PyObject_FunctionStr"])(a0);var _PyDescr_NewClassMethod=Module["_PyDescr_NewClassMethod"]=(a0,a1)=>(_PyDescr_NewClassMethod=Module["_PyDescr_NewClassMethod"]=wasmExports["PyDescr_NewClassMethod"])(a0,a1);var _PyDescr_NewMember=Module["_PyDescr_NewMember"]=(a0,a1)=>(_PyDescr_NewMember=Module["_PyDescr_NewMember"]=wasmExports["PyDescr_NewMember"])(a0,a1);var _PyDescr_NewGetSet=Module["_PyDescr_NewGetSet"]=(a0,a1)=>(_PyDescr_NewGetSet=Module["_PyDescr_NewGetSet"]=wasmExports["PyDescr_NewGetSet"])(a0,a1);var _PyDescr_NewWrapper=Module["_PyDescr_NewWrapper"]=(a0,a1,a2)=>(_PyDescr_NewWrapper=Module["_PyDescr_NewWrapper"]=wasmExports["PyDescr_NewWrapper"])(a0,a1,a2);var _PyDescr_IsData=Module["_PyDescr_IsData"]=a0=>(_PyDescr_IsData=Module["_PyDescr_IsData"]=wasmExports["PyDescr_IsData"])(a0);var _PyDictProxy_New=Module["_PyDictProxy_New"]=a0=>(_PyDictProxy_New=Module["_PyDictProxy_New"]=wasmExports["PyDictProxy_New"])(a0);var __PyTrash_cond=Module["__PyTrash_cond"]=(a0,a1)=>(__PyTrash_cond=Module["__PyTrash_cond"]=wasmExports["_PyTrash_cond"])(a0,a1);var __PyThreadState_UncheckedGet=Module["__PyThreadState_UncheckedGet"]=()=>(__PyThreadState_UncheckedGet=Module["__PyThreadState_UncheckedGet"]=wasmExports["_PyThreadState_UncheckedGet"])();var __PyTrash_begin=Module["__PyTrash_begin"]=(a0,a1)=>(__PyTrash_begin=Module["__PyTrash_begin"]=wasmExports["_PyTrash_begin"])(a0,a1);var __PyTrash_end=Module["__PyTrash_end"]=a0=>(__PyTrash_end=Module["__PyTrash_end"]=wasmExports["_PyTrash_end"])(a0);var _PyWrapper_New=Module["_PyWrapper_New"]=(a0,a1)=>(_PyWrapper_New=Module["_PyWrapper_New"]=wasmExports["PyWrapper_New"])(a0,a1);var _PyType_GetQualName=Module["_PyType_GetQualName"]=a0=>(_PyType_GetQualName=Module["_PyType_GetQualName"]=wasmExports["PyType_GetQualName"])(a0);var __PyType_GetDocFromInternalDoc=Module["__PyType_GetDocFromInternalDoc"]=(a0,a1)=>(__PyType_GetDocFromInternalDoc=Module["__PyType_GetDocFromInternalDoc"]=wasmExports["_PyType_GetDocFromInternalDoc"])(a0,a1);var __PyType_GetTextSignatureFromInternalDoc=Module["__PyType_GetTextSignatureFromInternalDoc"]=(a0,a1)=>(__PyType_GetTextSignatureFromInternalDoc=Module["__PyType_GetTextSignatureFromInternalDoc"]=wasmExports["_PyType_GetTextSignatureFromInternalDoc"])(a0,a1);var _PyDict_Contains=Module["_PyDict_Contains"]=(a0,a1)=>(_PyDict_Contains=Module["_PyDict_Contains"]=wasmExports["PyDict_Contains"])(a0,a1);var __PyArg_UnpackStack=Module["__PyArg_UnpackStack"]=(a0,a1,a2,a3,a4,a5)=>(__PyArg_UnpackStack=Module["__PyArg_UnpackStack"]=wasmExports["_PyArg_UnpackStack"])(a0,a1,a2,a3,a4,a5);var __PyObject_IsAbstract=Module["__PyObject_IsAbstract"]=a0=>(__PyObject_IsAbstract=Module["__PyObject_IsAbstract"]=wasmExports["_PyObject_IsAbstract"])(a0);var _PyException_GetCause=Module["_PyException_GetCause"]=a0=>(_PyException_GetCause=Module["_PyException_GetCause"]=wasmExports["PyException_GetCause"])(a0);var _PyException_SetCause=Module["_PyException_SetCause"]=(a0,a1)=>(_PyException_SetCause=Module["_PyException_SetCause"]=wasmExports["PyException_SetCause"])(a0,a1);var _PyException_GetContext=Module["_PyException_GetContext"]=a0=>(_PyException_GetContext=Module["_PyException_GetContext"]=wasmExports["PyException_GetContext"])(a0);var _PyException_SetContext=Module["_PyException_SetContext"]=(a0,a1)=>(_PyException_SetContext=Module["_PyException_SetContext"]=wasmExports["PyException_SetContext"])(a0,a1);var _PyException_GetArgs=Module["_PyException_GetArgs"]=a0=>(_PyException_GetArgs=Module["_PyException_GetArgs"]=wasmExports["PyException_GetArgs"])(a0);var _PyException_SetArgs=Module["_PyException_SetArgs"]=(a0,a1)=>(_PyException_SetArgs=Module["_PyException_SetArgs"]=wasmExports["PyException_SetArgs"])(a0,a1);var _PyExceptionClass_Name=Module["_PyExceptionClass_Name"]=a0=>(_PyExceptionClass_Name=Module["_PyExceptionClass_Name"]=wasmExports["PyExceptionClass_Name"])(a0);var __PyExc_CreateExceptionGroup=Module["__PyExc_CreateExceptionGroup"]=(a0,a1)=>(__PyExc_CreateExceptionGroup=Module["__PyExc_CreateExceptionGroup"]=wasmExports["_PyExc_CreateExceptionGroup"])(a0,a1);var __PyExc_PrepReraiseStar=Module["__PyExc_PrepReraiseStar"]=(a0,a1)=>(__PyExc_PrepReraiseStar=Module["__PyExc_PrepReraiseStar"]=wasmExports["_PyExc_PrepReraiseStar"])(a0,a1);var _PyUnstable_Exc_PrepReraiseStar=Module["_PyUnstable_Exc_PrepReraiseStar"]=(a0,a1)=>(_PyUnstable_Exc_PrepReraiseStar=Module["_PyUnstable_Exc_PrepReraiseStar"]=wasmExports["PyUnstable_Exc_PrepReraiseStar"])(a0,a1);var _PyUnicodeEncodeError_GetEncoding=Module["_PyUnicodeEncodeError_GetEncoding"]=a0=>(_PyUnicodeEncodeError_GetEncoding=Module["_PyUnicodeEncodeError_GetEncoding"]=wasmExports["PyUnicodeEncodeError_GetEncoding"])(a0);var _PyUnicodeDecodeError_GetEncoding=Module["_PyUnicodeDecodeError_GetEncoding"]=a0=>(_PyUnicodeDecodeError_GetEncoding=Module["_PyUnicodeDecodeError_GetEncoding"]=wasmExports["PyUnicodeDecodeError_GetEncoding"])(a0);var _PyUnicodeEncodeError_GetObject=Module["_PyUnicodeEncodeError_GetObject"]=a0=>(_PyUnicodeEncodeError_GetObject=Module["_PyUnicodeEncodeError_GetObject"]=wasmExports["PyUnicodeEncodeError_GetObject"])(a0);var _PyUnicodeDecodeError_GetObject=Module["_PyUnicodeDecodeError_GetObject"]=a0=>(_PyUnicodeDecodeError_GetObject=Module["_PyUnicodeDecodeError_GetObject"]=wasmExports["PyUnicodeDecodeError_GetObject"])(a0);var _PyUnicodeTranslateError_GetObject=Module["_PyUnicodeTranslateError_GetObject"]=a0=>(_PyUnicodeTranslateError_GetObject=Module["_PyUnicodeTranslateError_GetObject"]=wasmExports["PyUnicodeTranslateError_GetObject"])(a0);var _PyUnicodeEncodeError_GetStart=Module["_PyUnicodeEncodeError_GetStart"]=(a0,a1)=>(_PyUnicodeEncodeError_GetStart=Module["_PyUnicodeEncodeError_GetStart"]=wasmExports["PyUnicodeEncodeError_GetStart"])(a0,a1);var _PyUnicodeDecodeError_GetStart=Module["_PyUnicodeDecodeError_GetStart"]=(a0,a1)=>(_PyUnicodeDecodeError_GetStart=Module["_PyUnicodeDecodeError_GetStart"]=wasmExports["PyUnicodeDecodeError_GetStart"])(a0,a1);var _PyUnicodeTranslateError_GetStart=Module["_PyUnicodeTranslateError_GetStart"]=(a0,a1)=>(_PyUnicodeTranslateError_GetStart=Module["_PyUnicodeTranslateError_GetStart"]=wasmExports["PyUnicodeTranslateError_GetStart"])(a0,a1);var _PyUnicodeEncodeError_SetStart=Module["_PyUnicodeEncodeError_SetStart"]=(a0,a1)=>(_PyUnicodeEncodeError_SetStart=Module["_PyUnicodeEncodeError_SetStart"]=wasmExports["PyUnicodeEncodeError_SetStart"])(a0,a1);var _PyUnicodeDecodeError_SetStart=Module["_PyUnicodeDecodeError_SetStart"]=(a0,a1)=>(_PyUnicodeDecodeError_SetStart=Module["_PyUnicodeDecodeError_SetStart"]=wasmExports["PyUnicodeDecodeError_SetStart"])(a0,a1);var _PyUnicodeTranslateError_SetStart=Module["_PyUnicodeTranslateError_SetStart"]=(a0,a1)=>(_PyUnicodeTranslateError_SetStart=Module["_PyUnicodeTranslateError_SetStart"]=wasmExports["PyUnicodeTranslateError_SetStart"])(a0,a1);var _PyUnicodeEncodeError_GetEnd=Module["_PyUnicodeEncodeError_GetEnd"]=(a0,a1)=>(_PyUnicodeEncodeError_GetEnd=Module["_PyUnicodeEncodeError_GetEnd"]=wasmExports["PyUnicodeEncodeError_GetEnd"])(a0,a1);var _PyUnicodeDecodeError_GetEnd=Module["_PyUnicodeDecodeError_GetEnd"]=(a0,a1)=>(_PyUnicodeDecodeError_GetEnd=Module["_PyUnicodeDecodeError_GetEnd"]=wasmExports["PyUnicodeDecodeError_GetEnd"])(a0,a1);var _PyUnicodeTranslateError_GetEnd=Module["_PyUnicodeTranslateError_GetEnd"]=(a0,a1)=>(_PyUnicodeTranslateError_GetEnd=Module["_PyUnicodeTranslateError_GetEnd"]=wasmExports["PyUnicodeTranslateError_GetEnd"])(a0,a1);var _PyUnicodeEncodeError_SetEnd=Module["_PyUnicodeEncodeError_SetEnd"]=(a0,a1)=>(_PyUnicodeEncodeError_SetEnd=Module["_PyUnicodeEncodeError_SetEnd"]=wasmExports["PyUnicodeEncodeError_SetEnd"])(a0,a1);var _PyUnicodeDecodeError_SetEnd=Module["_PyUnicodeDecodeError_SetEnd"]=(a0,a1)=>(_PyUnicodeDecodeError_SetEnd=Module["_PyUnicodeDecodeError_SetEnd"]=wasmExports["PyUnicodeDecodeError_SetEnd"])(a0,a1);var _PyUnicodeTranslateError_SetEnd=Module["_PyUnicodeTranslateError_SetEnd"]=(a0,a1)=>(_PyUnicodeTranslateError_SetEnd=Module["_PyUnicodeTranslateError_SetEnd"]=wasmExports["PyUnicodeTranslateError_SetEnd"])(a0,a1);var _PyUnicodeEncodeError_GetReason=Module["_PyUnicodeEncodeError_GetReason"]=a0=>(_PyUnicodeEncodeError_GetReason=Module["_PyUnicodeEncodeError_GetReason"]=wasmExports["PyUnicodeEncodeError_GetReason"])(a0);var _PyUnicodeDecodeError_GetReason=Module["_PyUnicodeDecodeError_GetReason"]=a0=>(_PyUnicodeDecodeError_GetReason=Module["_PyUnicodeDecodeError_GetReason"]=wasmExports["PyUnicodeDecodeError_GetReason"])(a0);var _PyUnicodeTranslateError_GetReason=Module["_PyUnicodeTranslateError_GetReason"]=a0=>(_PyUnicodeTranslateError_GetReason=Module["_PyUnicodeTranslateError_GetReason"]=wasmExports["PyUnicodeTranslateError_GetReason"])(a0);var _PyUnicodeEncodeError_SetReason=Module["_PyUnicodeEncodeError_SetReason"]=(a0,a1)=>(_PyUnicodeEncodeError_SetReason=Module["_PyUnicodeEncodeError_SetReason"]=wasmExports["PyUnicodeEncodeError_SetReason"])(a0,a1);var _PyUnicodeDecodeError_SetReason=Module["_PyUnicodeDecodeError_SetReason"]=(a0,a1)=>(_PyUnicodeDecodeError_SetReason=Module["_PyUnicodeDecodeError_SetReason"]=wasmExports["PyUnicodeDecodeError_SetReason"])(a0,a1);var _PyUnicodeTranslateError_SetReason=Module["_PyUnicodeTranslateError_SetReason"]=(a0,a1)=>(_PyUnicodeTranslateError_SetReason=Module["_PyUnicodeTranslateError_SetReason"]=wasmExports["PyUnicodeTranslateError_SetReason"])(a0,a1);var _PyUnicodeDecodeError_Create=Module["_PyUnicodeDecodeError_Create"]=(a0,a1,a2,a3,a4,a5)=>(_PyUnicodeDecodeError_Create=Module["_PyUnicodeDecodeError_Create"]=wasmExports["PyUnicodeDecodeError_Create"])(a0,a1,a2,a3,a4,a5);var __PyUnicodeTranslateError_Create=Module["__PyUnicodeTranslateError_Create"]=(a0,a1,a2,a3)=>(__PyUnicodeTranslateError_Create=Module["__PyUnicodeTranslateError_Create"]=wasmExports["_PyUnicodeTranslateError_Create"])(a0,a1,a2,a3);var _PyModule_GetDict=Module["_PyModule_GetDict"]=a0=>(_PyModule_GetDict=Module["_PyModule_GetDict"]=wasmExports["PyModule_GetDict"])(a0);var _PyErr_NewException=Module["_PyErr_NewException"]=(a0,a1,a2)=>(_PyErr_NewException=Module["_PyErr_NewException"]=wasmExports["PyErr_NewException"])(a0,a1,a2);var __PyException_AddNote=Module["__PyException_AddNote"]=(a0,a1)=>(__PyException_AddNote=Module["__PyException_AddNote"]=wasmExports["_PyException_AddNote"])(a0,a1);var _PySet_Add=Module["_PySet_Add"]=(a0,a1)=>(_PySet_Add=Module["_PySet_Add"]=wasmExports["PySet_Add"])(a0,a1);var _PySet_Contains=Module["_PySet_Contains"]=(a0,a1)=>(_PySet_Contains=Module["_PySet_Contains"]=wasmExports["PySet_Contains"])(a0,a1);var _PyTuple_Size=Module["_PyTuple_Size"]=a0=>(_PyTuple_Size=Module["_PyTuple_Size"]=wasmExports["PyTuple_Size"])(a0);var _PyDict_Copy=Module["_PyDict_Copy"]=a0=>(_PyDict_Copy=Module["_PyDict_Copy"]=wasmExports["PyDict_Copy"])(a0);var _PyUnicode_ReadChar=Module["_PyUnicode_ReadChar"]=(a0,a1)=>(_PyUnicode_ReadChar=Module["_PyUnicode_ReadChar"]=wasmExports["PyUnicode_ReadChar"])(a0,a1);var _PyObject_GenericGetDict=Module["_PyObject_GenericGetDict"]=(a0,a1)=>(_PyObject_GenericGetDict=Module["_PyObject_GenericGetDict"]=wasmExports["PyObject_GenericGetDict"])(a0,a1);var _PyObject_GenericSetDict=Module["_PyObject_GenericSetDict"]=(a0,a1,a2)=>(_PyObject_GenericSetDict=Module["_PyObject_GenericSetDict"]=wasmExports["PyObject_GenericSetDict"])(a0,a1,a2);var _PyList_SetSlice=Module["_PyList_SetSlice"]=(a0,a1,a2,a3)=>(_PyList_SetSlice=Module["_PyList_SetSlice"]=wasmExports["PyList_SetSlice"])(a0,a1,a2,a3);var __PyUnicodeWriter_WriteASCIIString=Module["__PyUnicodeWriter_WriteASCIIString"]=(a0,a1,a2)=>(__PyUnicodeWriter_WriteASCIIString=Module["__PyUnicodeWriter_WriteASCIIString"]=wasmExports["_PyUnicodeWriter_WriteASCIIString"])(a0,a1,a2);var _PyObject_GC_Track=Module["_PyObject_GC_Track"]=a0=>(_PyObject_GC_Track=Module["_PyObject_GC_Track"]=wasmExports["PyObject_GC_Track"])(a0);var __PyGen_Finalize=Module["__PyGen_Finalize"]=a0=>(__PyGen_Finalize=Module["__PyGen_Finalize"]=wasmExports["_PyGen_Finalize"])(a0);var _PyObject_CallFinalizerFromDealloc=Module["_PyObject_CallFinalizerFromDealloc"]=a0=>(_PyObject_CallFinalizerFromDealloc=Module["_PyObject_CallFinalizerFromDealloc"]=wasmExports["PyObject_CallFinalizerFromDealloc"])(a0);var __PyObject_GC_NewVar=Module["__PyObject_GC_NewVar"]=(a0,a1)=>(__PyObject_GC_NewVar=Module["__PyObject_GC_NewVar"]=wasmExports["_PyObject_GC_NewVar"])(a0,a1);var _PyUnstable_InterpreterFrame_GetLine=Module["_PyUnstable_InterpreterFrame_GetLine"]=a0=>(_PyUnstable_InterpreterFrame_GetLine=Module["_PyUnstable_InterpreterFrame_GetLine"]=wasmExports["PyUnstable_InterpreterFrame_GetLine"])(a0);var _PyGen_NewWithQualName=Module["_PyGen_NewWithQualName"]=(a0,a1,a2)=>(_PyGen_NewWithQualName=Module["_PyGen_NewWithQualName"]=wasmExports["PyGen_NewWithQualName"])(a0,a1,a2);var _PyGen_New=Module["_PyGen_New"]=a0=>(_PyGen_New=Module["_PyGen_New"]=wasmExports["PyGen_New"])(a0);var _PyCoro_New=Module["_PyCoro_New"]=(a0,a1,a2)=>(_PyCoro_New=Module["_PyCoro_New"]=wasmExports["PyCoro_New"])(a0,a1,a2);var _PyAsyncGen_New=Module["_PyAsyncGen_New"]=(a0,a1,a2)=>(_PyAsyncGen_New=Module["_PyAsyncGen_New"]=wasmExports["PyAsyncGen_New"])(a0,a1,a2);var __PyErr_ChainStackItem=Module["__PyErr_ChainStackItem"]=a0=>(__PyErr_ChainStackItem=Module["__PyErr_ChainStackItem"]=wasmExports["_PyErr_ChainStackItem"])(a0);var __PyEval_EvalFrameDefault=Module["__PyEval_EvalFrameDefault"]=(a0,a1,a2)=>(__PyEval_EvalFrameDefault=Module["__PyEval_EvalFrameDefault"]=wasmExports["_PyEval_EvalFrameDefault"])(a0,a1,a2);var _PyFile_FromFd=Module["_PyFile_FromFd"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_PyFile_FromFd=Module["_PyFile_FromFd"]=wasmExports["PyFile_FromFd"])(a0,a1,a2,a3,a4,a5,a6,a7);var _PyFile_GetLine=Module["_PyFile_GetLine"]=(a0,a1)=>(_PyFile_GetLine=Module["_PyFile_GetLine"]=wasmExports["PyFile_GetLine"])(a0,a1);var _PyFile_WriteObject=Module["_PyFile_WriteObject"]=(a0,a1,a2)=>(_PyFile_WriteObject=Module["_PyFile_WriteObject"]=wasmExports["PyFile_WriteObject"])(a0,a1,a2);var _PyFile_WriteString=Module["_PyFile_WriteString"]=(a0,a1)=>(_PyFile_WriteString=Module["_PyFile_WriteString"]=wasmExports["PyFile_WriteString"])(a0,a1);var _PyObject_AsFileDescriptor=Module["_PyObject_AsFileDescriptor"]=a0=>(_PyObject_AsFileDescriptor=Module["_PyObject_AsFileDescriptor"]=wasmExports["PyObject_AsFileDescriptor"])(a0);var __PyLong_FileDescriptor_Converter=Module["__PyLong_FileDescriptor_Converter"]=(a0,a1)=>(__PyLong_FileDescriptor_Converter=Module["__PyLong_FileDescriptor_Converter"]=wasmExports["_PyLong_FileDescriptor_Converter"])(a0,a1);var _flockfile=Module["_flockfile"]=a0=>(_flockfile=Module["_flockfile"]=wasmExports["flockfile"])(a0);var _getc_unlocked=Module["_getc_unlocked"]=a0=>(_getc_unlocked=Module["_getc_unlocked"]=wasmExports["getc_unlocked"])(a0);var _funlockfile=Module["_funlockfile"]=a0=>(_funlockfile=Module["_funlockfile"]=wasmExports["funlockfile"])(a0);var _Py_UniversalNewlineFgets=Module["_Py_UniversalNewlineFgets"]=(a0,a1,a2,a3)=>(_Py_UniversalNewlineFgets=Module["_Py_UniversalNewlineFgets"]=wasmExports["Py_UniversalNewlineFgets"])(a0,a1,a2,a3);var _PyFile_NewStdPrinter=Module["_PyFile_NewStdPrinter"]=a0=>(_PyFile_NewStdPrinter=Module["_PyFile_NewStdPrinter"]=wasmExports["PyFile_NewStdPrinter"])(a0);var _PyFile_SetOpenCodeHook=Module["_PyFile_SetOpenCodeHook"]=(a0,a1)=>(_PyFile_SetOpenCodeHook=Module["_PyFile_SetOpenCodeHook"]=wasmExports["PyFile_SetOpenCodeHook"])(a0,a1);var _Py_IsInitialized=Module["_Py_IsInitialized"]=()=>(_Py_IsInitialized=Module["_Py_IsInitialized"]=wasmExports["Py_IsInitialized"])();var _PyFile_OpenCodeObject=Module["_PyFile_OpenCodeObject"]=a0=>(_PyFile_OpenCodeObject=Module["_PyFile_OpenCodeObject"]=wasmExports["PyFile_OpenCodeObject"])(a0);var _PyFile_OpenCode=Module["_PyFile_OpenCode"]=a0=>(_PyFile_OpenCode=Module["_PyFile_OpenCode"]=wasmExports["PyFile_OpenCode"])(a0);var __PyUnicode_AsUTF8String=Module["__PyUnicode_AsUTF8String"]=(a0,a1)=>(__PyUnicode_AsUTF8String=Module["__PyUnicode_AsUTF8String"]=wasmExports["_PyUnicode_AsUTF8String"])(a0,a1);var __Py_write=Module["__Py_write"]=(a0,a1,a2)=>(__Py_write=Module["__Py_write"]=wasmExports["_Py_write"])(a0,a1,a2);var _PyFloat_GetMax=Module["_PyFloat_GetMax"]=()=>(_PyFloat_GetMax=Module["_PyFloat_GetMax"]=wasmExports["PyFloat_GetMax"])();var _PyFloat_GetMin=Module["_PyFloat_GetMin"]=()=>(_PyFloat_GetMin=Module["_PyFloat_GetMin"]=wasmExports["PyFloat_GetMin"])();var _PyFloat_GetInfo=Module["_PyFloat_GetInfo"]=()=>(_PyFloat_GetInfo=Module["_PyFloat_GetInfo"]=wasmExports["PyFloat_GetInfo"])();var _PyStructSequence_New=Module["_PyStructSequence_New"]=a0=>(_PyStructSequence_New=Module["_PyStructSequence_New"]=wasmExports["PyStructSequence_New"])(a0);var __PyLong_Sign=Module["__PyLong_Sign"]=a0=>(__PyLong_Sign=Module["__PyLong_Sign"]=wasmExports["_PyLong_Sign"])(a0);var _frexp=Module["_frexp"]=(a0,a1)=>(_frexp=Module["_frexp"]=wasmExports["frexp"])(a0,a1);var _modf=Module["_modf"]=(a0,a1)=>(_modf=Module["_modf"]=wasmExports["modf"])(a0,a1);var _PyLong_FromDouble=Module["_PyLong_FromDouble"]=a0=>(_PyLong_FromDouble=Module["_PyLong_FromDouble"]=wasmExports["PyLong_FromDouble"])(a0);var __PyLong_Lshift=Module["__PyLong_Lshift"]=(a0,a1)=>(__PyLong_Lshift=Module["__PyLong_Lshift"]=wasmExports["_PyLong_Lshift"])(a0,a1);var __PyFloat_DebugMallocStats=Module["__PyFloat_DebugMallocStats"]=a0=>(__PyFloat_DebugMallocStats=Module["__PyFloat_DebugMallocStats"]=wasmExports["_PyFloat_DebugMallocStats"])(a0);var __PyDebugAllocatorStats=Module["__PyDebugAllocatorStats"]=(a0,a1,a2,a3)=>(__PyDebugAllocatorStats=Module["__PyDebugAllocatorStats"]=wasmExports["_PyDebugAllocatorStats"])(a0,a1,a2,a3);var _PyFloat_Pack2=Module["_PyFloat_Pack2"]=(a0,a1,a2)=>(_PyFloat_Pack2=Module["_PyFloat_Pack2"]=wasmExports["PyFloat_Pack2"])(a0,a1,a2);var _ldexp=Module["_ldexp"]=(a0,a1)=>(_ldexp=Module["_ldexp"]=wasmExports["ldexp"])(a0,a1);var _PyFloat_Pack4=Module["_PyFloat_Pack4"]=(a0,a1,a2)=>(_PyFloat_Pack4=Module["_PyFloat_Pack4"]=wasmExports["PyFloat_Pack4"])(a0,a1,a2);var _PyFloat_Pack8=Module["_PyFloat_Pack8"]=(a0,a1,a2)=>(_PyFloat_Pack8=Module["_PyFloat_Pack8"]=wasmExports["PyFloat_Pack8"])(a0,a1,a2);var _PyFloat_Unpack2=Module["_PyFloat_Unpack2"]=(a0,a1)=>(_PyFloat_Unpack2=Module["_PyFloat_Unpack2"]=wasmExports["PyFloat_Unpack2"])(a0,a1);var _PyFloat_Unpack4=Module["_PyFloat_Unpack4"]=(a0,a1)=>(_PyFloat_Unpack4=Module["_PyFloat_Unpack4"]=wasmExports["PyFloat_Unpack4"])(a0,a1);var _PyFloat_Unpack8=Module["_PyFloat_Unpack8"]=(a0,a1)=>(_PyFloat_Unpack8=Module["_PyFloat_Unpack8"]=wasmExports["PyFloat_Unpack8"])(a0,a1);var _fmod=Module["_fmod"]=(a0,a1)=>(_fmod=Module["_fmod"]=wasmExports["fmod"])(a0,a1);var _PyErr_SetFromErrno=Module["_PyErr_SetFromErrno"]=a0=>(_PyErr_SetFromErrno=Module["_PyErr_SetFromErrno"]=wasmExports["PyErr_SetFromErrno"])(a0);var _round=Module["_round"]=a0=>(_round=Module["_round"]=wasmExports["round"])(a0);var __Py_dg_dtoa=Module["__Py_dg_dtoa"]=(a0,a1,a2,a3,a4,a5)=>(__Py_dg_dtoa=Module["__Py_dg_dtoa"]=wasmExports["_Py_dg_dtoa"])(a0,a1,a2,a3,a4,a5);var __Py_dg_strtod=Module["__Py_dg_strtod"]=(a0,a1)=>(__Py_dg_strtod=Module["__Py_dg_strtod"]=wasmExports["_Py_dg_strtod"])(a0,a1);var __Py_dg_freedtoa=Module["__Py_dg_freedtoa"]=a0=>(__Py_dg_freedtoa=Module["__Py_dg_freedtoa"]=wasmExports["_Py_dg_freedtoa"])(a0);var __Py_parse_inf_or_nan=Module["__Py_parse_inf_or_nan"]=(a0,a1)=>(__Py_parse_inf_or_nan=Module["__Py_parse_inf_or_nan"]=wasmExports["_Py_parse_inf_or_nan"])(a0,a1);var _strtol=Module["_strtol"]=(a0,a1,a2)=>(_strtol=Module["_strtol"]=wasmExports["strtol"])(a0,a1,a2);var __PyFloat_FormatAdvancedWriter=Module["__PyFloat_FormatAdvancedWriter"]=(a0,a1,a2,a3,a4)=>(__PyFloat_FormatAdvancedWriter=Module["__PyFloat_FormatAdvancedWriter"]=wasmExports["_PyFloat_FormatAdvancedWriter"])(a0,a1,a2,a3,a4);var _PyFrame_GetLineNumber=Module["_PyFrame_GetLineNumber"]=a0=>(_PyFrame_GetLineNumber=Module["_PyFrame_GetLineNumber"]=wasmExports["PyFrame_GetLineNumber"])(a0);var _PyFrame_New=Module["_PyFrame_New"]=(a0,a1,a2,a3)=>(_PyFrame_New=Module["_PyFrame_New"]=wasmExports["PyFrame_New"])(a0,a1,a2,a3);var _PyDict_Size=Module["_PyDict_Size"]=a0=>(_PyDict_Size=Module["_PyDict_Size"]=wasmExports["PyDict_Size"])(a0);var _PyDict_Merge=Module["_PyDict_Merge"]=(a0,a1,a2)=>(_PyDict_Merge=Module["_PyDict_Merge"]=wasmExports["PyDict_Merge"])(a0,a1,a2);var _PyFrame_GetVar=Module["_PyFrame_GetVar"]=(a0,a1)=>(_PyFrame_GetVar=Module["_PyFrame_GetVar"]=wasmExports["PyFrame_GetVar"])(a0,a1);var __PyUnicode_Equal=Module["__PyUnicode_Equal"]=(a0,a1)=>(__PyUnicode_Equal=Module["__PyUnicode_Equal"]=wasmExports["_PyUnicode_Equal"])(a0,a1);var _PyFrame_GetVarString=Module["_PyFrame_GetVarString"]=(a0,a1)=>(_PyFrame_GetVarString=Module["_PyFrame_GetVarString"]=wasmExports["PyFrame_GetVarString"])(a0,a1);var _PyFrame_FastToLocalsWithError=Module["_PyFrame_FastToLocalsWithError"]=a0=>(_PyFrame_FastToLocalsWithError=Module["_PyFrame_FastToLocalsWithError"]=wasmExports["PyFrame_FastToLocalsWithError"])(a0);var _PyFrame_FastToLocals=Module["_PyFrame_FastToLocals"]=a0=>(_PyFrame_FastToLocals=Module["_PyFrame_FastToLocals"]=wasmExports["PyFrame_FastToLocals"])(a0);var _PyFrame_LocalsToFast=Module["_PyFrame_LocalsToFast"]=(a0,a1)=>(_PyFrame_LocalsToFast=Module["_PyFrame_LocalsToFast"]=wasmExports["PyFrame_LocalsToFast"])(a0,a1);var __PyFrame_IsEntryFrame=Module["__PyFrame_IsEntryFrame"]=a0=>(__PyFrame_IsEntryFrame=Module["__PyFrame_IsEntryFrame"]=wasmExports["_PyFrame_IsEntryFrame"])(a0);var _PyFrame_GetCode=Module["_PyFrame_GetCode"]=a0=>(_PyFrame_GetCode=Module["_PyFrame_GetCode"]=wasmExports["PyFrame_GetCode"])(a0);var _PyFrame_GetBack=Module["_PyFrame_GetBack"]=a0=>(_PyFrame_GetBack=Module["_PyFrame_GetBack"]=wasmExports["PyFrame_GetBack"])(a0);var _PyFrame_GetLocals=Module["_PyFrame_GetLocals"]=a0=>(_PyFrame_GetLocals=Module["_PyFrame_GetLocals"]=wasmExports["PyFrame_GetLocals"])(a0);var _PyFrame_GetGlobals=Module["_PyFrame_GetGlobals"]=a0=>(_PyFrame_GetGlobals=Module["_PyFrame_GetGlobals"]=wasmExports["PyFrame_GetGlobals"])(a0);var _PyFrame_GetBuiltins=Module["_PyFrame_GetBuiltins"]=a0=>(_PyFrame_GetBuiltins=Module["_PyFrame_GetBuiltins"]=wasmExports["PyFrame_GetBuiltins"])(a0);var _PyFrame_GetLasti=Module["_PyFrame_GetLasti"]=a0=>(_PyFrame_GetLasti=Module["_PyFrame_GetLasti"]=wasmExports["PyFrame_GetLasti"])(a0);var _PyFrame_GetGenerator=Module["_PyFrame_GetGenerator"]=a0=>(_PyFrame_GetGenerator=Module["_PyFrame_GetGenerator"]=wasmExports["PyFrame_GetGenerator"])(a0);var _PyCompile_OpcodeStackEffect=Module["_PyCompile_OpcodeStackEffect"]=(a0,a1)=>(_PyCompile_OpcodeStackEffect=Module["_PyCompile_OpcodeStackEffect"]=wasmExports["PyCompile_OpcodeStackEffect"])(a0,a1);var _PyFunction_AddWatcher=Module["_PyFunction_AddWatcher"]=a0=>(_PyFunction_AddWatcher=Module["_PyFunction_AddWatcher"]=wasmExports["PyFunction_AddWatcher"])(a0);var _PyFunction_ClearWatcher=Module["_PyFunction_ClearWatcher"]=a0=>(_PyFunction_ClearWatcher=Module["_PyFunction_ClearWatcher"]=wasmExports["PyFunction_ClearWatcher"])(a0);var _PyFunction_NewWithQualName=Module["_PyFunction_NewWithQualName"]=(a0,a1,a2)=>(_PyFunction_NewWithQualName=Module["_PyFunction_NewWithQualName"]=wasmExports["PyFunction_NewWithQualName"])(a0,a1,a2);var _PyFunction_New=Module["_PyFunction_New"]=(a0,a1)=>(_PyFunction_New=Module["_PyFunction_New"]=wasmExports["PyFunction_New"])(a0,a1);var _PyFunction_GetCode=Module["_PyFunction_GetCode"]=a0=>(_PyFunction_GetCode=Module["_PyFunction_GetCode"]=wasmExports["PyFunction_GetCode"])(a0);var _PyFunction_GetGlobals=Module["_PyFunction_GetGlobals"]=a0=>(_PyFunction_GetGlobals=Module["_PyFunction_GetGlobals"]=wasmExports["PyFunction_GetGlobals"])(a0);var _PyFunction_GetModule=Module["_PyFunction_GetModule"]=a0=>(_PyFunction_GetModule=Module["_PyFunction_GetModule"]=wasmExports["PyFunction_GetModule"])(a0);var _PyFunction_GetDefaults=Module["_PyFunction_GetDefaults"]=a0=>(_PyFunction_GetDefaults=Module["_PyFunction_GetDefaults"]=wasmExports["PyFunction_GetDefaults"])(a0);var _PyFunction_SetDefaults=Module["_PyFunction_SetDefaults"]=(a0,a1)=>(_PyFunction_SetDefaults=Module["_PyFunction_SetDefaults"]=wasmExports["PyFunction_SetDefaults"])(a0,a1);var _PyFunction_SetVectorcall=Module["_PyFunction_SetVectorcall"]=(a0,a1)=>(_PyFunction_SetVectorcall=Module["_PyFunction_SetVectorcall"]=wasmExports["PyFunction_SetVectorcall"])(a0,a1);var _PyFunction_GetKwDefaults=Module["_PyFunction_GetKwDefaults"]=a0=>(_PyFunction_GetKwDefaults=Module["_PyFunction_GetKwDefaults"]=wasmExports["PyFunction_GetKwDefaults"])(a0);var _PyFunction_SetKwDefaults=Module["_PyFunction_SetKwDefaults"]=(a0,a1)=>(_PyFunction_SetKwDefaults=Module["_PyFunction_SetKwDefaults"]=wasmExports["PyFunction_SetKwDefaults"])(a0,a1);var _PyFunction_GetClosure=Module["_PyFunction_GetClosure"]=a0=>(_PyFunction_GetClosure=Module["_PyFunction_GetClosure"]=wasmExports["PyFunction_GetClosure"])(a0);var _PyFunction_SetClosure=Module["_PyFunction_SetClosure"]=(a0,a1)=>(_PyFunction_SetClosure=Module["_PyFunction_SetClosure"]=wasmExports["PyFunction_SetClosure"])(a0,a1);var _PyFunction_GetAnnotations=Module["_PyFunction_GetAnnotations"]=a0=>(_PyFunction_GetAnnotations=Module["_PyFunction_GetAnnotations"]=wasmExports["PyFunction_GetAnnotations"])(a0);var _PyFunction_SetAnnotations=Module["_PyFunction_SetAnnotations"]=(a0,a1)=>(_PyFunction_SetAnnotations=Module["_PyFunction_SetAnnotations"]=wasmExports["PyFunction_SetAnnotations"])(a0,a1);var _PyClassMethod_New=Module["_PyClassMethod_New"]=a0=>(_PyClassMethod_New=Module["_PyClassMethod_New"]=wasmExports["PyClassMethod_New"])(a0);var _PyStaticMethod_New=Module["_PyStaticMethod_New"]=a0=>(_PyStaticMethod_New=Module["_PyStaticMethod_New"]=wasmExports["PyStaticMethod_New"])(a0);var __PyInterpreterState_LookUpID=Module["__PyInterpreterState_LookUpID"]=a0=>(__PyInterpreterState_LookUpID=Module["__PyInterpreterState_LookUpID"]=wasmExports["_PyInterpreterState_LookUpID"])(a0);var __PyInterpreterState_IDDecref=Module["__PyInterpreterState_IDDecref"]=a0=>(__PyInterpreterState_IDDecref=Module["__PyInterpreterState_IDDecref"]=wasmExports["_PyInterpreterState_IDDecref"])(a0);var _PyLong_FromLongLong=Module["_PyLong_FromLongLong"]=a0=>(_PyLong_FromLongLong=Module["_PyLong_FromLongLong"]=wasmExports["PyLong_FromLongLong"])(a0);var _PyLong_AsLongLongAndOverflow=Module["_PyLong_AsLongLongAndOverflow"]=(a0,a1)=>(_PyLong_AsLongLongAndOverflow=Module["_PyLong_AsLongLongAndOverflow"]=wasmExports["PyLong_AsLongLongAndOverflow"])(a0,a1);var _PyArg_ParseTupleAndKeywords=Module["_PyArg_ParseTupleAndKeywords"]=(a0,a1,a2,a3,a4)=>(_PyArg_ParseTupleAndKeywords=Module["_PyArg_ParseTupleAndKeywords"]=wasmExports["PyArg_ParseTupleAndKeywords"])(a0,a1,a2,a3,a4);var __PyInterpreterState_IDIncref=Module["__PyInterpreterState_IDIncref"]=a0=>(__PyInterpreterState_IDIncref=Module["__PyInterpreterState_IDIncref"]=wasmExports["_PyInterpreterState_IDIncref"])(a0);var __PyInterpreterID_New=Module["__PyInterpreterID_New"]=a0=>(__PyInterpreterID_New=Module["__PyInterpreterID_New"]=wasmExports["_PyInterpreterID_New"])(a0);var __PyInterpreterState_GetIDObject=Module["__PyInterpreterState_GetIDObject"]=a0=>(__PyInterpreterState_GetIDObject=Module["__PyInterpreterState_GetIDObject"]=wasmExports["_PyInterpreterState_GetIDObject"])(a0);var __PyInterpreterState_IDInitref=Module["__PyInterpreterState_IDInitref"]=a0=>(__PyInterpreterState_IDInitref=Module["__PyInterpreterState_IDInitref"]=wasmExports["_PyInterpreterState_IDInitref"])(a0);var _PyInterpreterState_GetID=Module["_PyInterpreterState_GetID"]=a0=>(_PyInterpreterState_GetID=Module["_PyInterpreterState_GetID"]=wasmExports["PyInterpreterState_GetID"])(a0);var __PyInterpreterID_LookUp=Module["__PyInterpreterID_LookUp"]=a0=>(__PyInterpreterID_LookUp=Module["__PyInterpreterID_LookUp"]=wasmExports["_PyInterpreterID_LookUp"])(a0);var _PyLong_AsLongLong=Module["_PyLong_AsLongLong"]=a0=>(_PyLong_AsLongLong=Module["_PyLong_AsLongLong"]=wasmExports["PyLong_AsLongLong"])(a0);var _PyCallIter_New=Module["_PyCallIter_New"]=(a0,a1)=>(_PyCallIter_New=Module["_PyCallIter_New"]=wasmExports["PyCallIter_New"])(a0,a1);var __PyList_DebugMallocStats=Module["__PyList_DebugMallocStats"]=a0=>(__PyList_DebugMallocStats=Module["__PyList_DebugMallocStats"]=wasmExports["_PyList_DebugMallocStats"])(a0);var _PyList_SetItem=Module["_PyList_SetItem"]=(a0,a1,a2)=>(_PyList_SetItem=Module["_PyList_SetItem"]=wasmExports["PyList_SetItem"])(a0,a1,a2);var _PyList_Insert=Module["_PyList_Insert"]=(a0,a1,a2)=>(_PyList_Insert=Module["_PyList_Insert"]=wasmExports["PyList_Insert"])(a0,a1,a2);var _PyList_GetSlice=Module["_PyList_GetSlice"]=(a0,a1,a2)=>(_PyList_GetSlice=Module["_PyList_GetSlice"]=wasmExports["PyList_GetSlice"])(a0,a1,a2);var _Py_ReprEnter=Module["_Py_ReprEnter"]=a0=>(_Py_ReprEnter=Module["_Py_ReprEnter"]=wasmExports["Py_ReprEnter"])(a0);var __PyUnicodeWriter_WriteChar=Module["__PyUnicodeWriter_WriteChar"]=(a0,a1)=>(__PyUnicodeWriter_WriteChar=Module["__PyUnicodeWriter_WriteChar"]=wasmExports["_PyUnicodeWriter_WriteChar"])(a0,a1);var _Py_ReprLeave=Module["_Py_ReprLeave"]=a0=>(_Py_ReprLeave=Module["_Py_ReprLeave"]=wasmExports["Py_ReprLeave"])(a0);var __PyEval_SliceIndexNotNone=Module["__PyEval_SliceIndexNotNone"]=(a0,a1)=>(__PyEval_SliceIndexNotNone=Module["__PyEval_SliceIndexNotNone"]=wasmExports["_PyEval_SliceIndexNotNone"])(a0,a1);var _PyObject_HashNotImplemented=Module["_PyObject_HashNotImplemented"]=a0=>(_PyObject_HashNotImplemented=Module["_PyObject_HashNotImplemented"]=wasmExports["PyObject_HashNotImplemented"])(a0);var __PyLong_New=Module["__PyLong_New"]=a0=>(__PyLong_New=Module["__PyLong_New"]=wasmExports["_PyLong_New"])(a0);var __PyLong_FromDigits=Module["__PyLong_FromDigits"]=(a0,a1,a2)=>(__PyLong_FromDigits=Module["__PyLong_FromDigits"]=wasmExports["_PyLong_FromDigits"])(a0,a1,a2);var _PyLong_FromUnsignedLong=Module["_PyLong_FromUnsignedLong"]=a0=>(_PyLong_FromUnsignedLong=Module["_PyLong_FromUnsignedLong"]=wasmExports["PyLong_FromUnsignedLong"])(a0);var _PyLong_FromUnsignedLongLong=Module["_PyLong_FromUnsignedLongLong"]=a0=>(_PyLong_FromUnsignedLongLong=Module["_PyLong_FromUnsignedLongLong"]=wasmExports["PyLong_FromUnsignedLongLong"])(a0);var _PyLong_AsUnsignedLong=Module["_PyLong_AsUnsignedLong"]=a0=>(_PyLong_AsUnsignedLong=Module["_PyLong_AsUnsignedLong"]=wasmExports["PyLong_AsUnsignedLong"])(a0);var _PyLong_AsSize_t=Module["_PyLong_AsSize_t"]=a0=>(_PyLong_AsSize_t=Module["_PyLong_AsSize_t"]=wasmExports["PyLong_AsSize_t"])(a0);var _PyLong_AsUnsignedLongMask=Module["_PyLong_AsUnsignedLongMask"]=a0=>(_PyLong_AsUnsignedLongMask=Module["_PyLong_AsUnsignedLongMask"]=wasmExports["PyLong_AsUnsignedLongMask"])(a0);var __PyLong_FromByteArray=Module["__PyLong_FromByteArray"]=(a0,a1,a2,a3)=>(__PyLong_FromByteArray=Module["__PyLong_FromByteArray"]=wasmExports["_PyLong_FromByteArray"])(a0,a1,a2,a3);var _PyLong_AsVoidPtr=Module["_PyLong_AsVoidPtr"]=a0=>(_PyLong_AsVoidPtr=Module["_PyLong_AsVoidPtr"]=wasmExports["PyLong_AsVoidPtr"])(a0);var _PyLong_AsUnsignedLongLong=Module["_PyLong_AsUnsignedLongLong"]=a0=>(_PyLong_AsUnsignedLongLong=Module["_PyLong_AsUnsignedLongLong"]=wasmExports["PyLong_AsUnsignedLongLong"])(a0);var _PyLong_AsUnsignedLongLongMask=Module["_PyLong_AsUnsignedLongLongMask"]=a0=>(_PyLong_AsUnsignedLongLongMask=Module["_PyLong_AsUnsignedLongLongMask"]=wasmExports["PyLong_AsUnsignedLongLongMask"])(a0);var __PyLong_UnsignedShort_Converter=Module["__PyLong_UnsignedShort_Converter"]=(a0,a1)=>(__PyLong_UnsignedShort_Converter=Module["__PyLong_UnsignedShort_Converter"]=wasmExports["_PyLong_UnsignedShort_Converter"])(a0,a1);var __PyLong_UnsignedInt_Converter=Module["__PyLong_UnsignedInt_Converter"]=(a0,a1)=>(__PyLong_UnsignedInt_Converter=Module["__PyLong_UnsignedInt_Converter"]=wasmExports["_PyLong_UnsignedInt_Converter"])(a0,a1);var __PyLong_UnsignedLong_Converter=Module["__PyLong_UnsignedLong_Converter"]=(a0,a1)=>(__PyLong_UnsignedLong_Converter=Module["__PyLong_UnsignedLong_Converter"]=wasmExports["_PyLong_UnsignedLong_Converter"])(a0,a1);var __PyLong_UnsignedLongLong_Converter=Module["__PyLong_UnsignedLongLong_Converter"]=(a0,a1)=>(__PyLong_UnsignedLongLong_Converter=Module["__PyLong_UnsignedLongLong_Converter"]=wasmExports["_PyLong_UnsignedLongLong_Converter"])(a0,a1);var __PyLong_Size_t_Converter=Module["__PyLong_Size_t_Converter"]=(a0,a1)=>(__PyLong_Size_t_Converter=Module["__PyLong_Size_t_Converter"]=wasmExports["_PyLong_Size_t_Converter"])(a0,a1);var __PyUnicodeWriter_PrepareInternal=Module["__PyUnicodeWriter_PrepareInternal"]=(a0,a1,a2)=>(__PyUnicodeWriter_PrepareInternal=Module["__PyUnicodeWriter_PrepareInternal"]=wasmExports["_PyUnicodeWriter_PrepareInternal"])(a0,a1,a2);var __PyLong_FormatWriter=Module["__PyLong_FormatWriter"]=(a0,a1,a2,a3)=>(__PyLong_FormatWriter=Module["__PyLong_FormatWriter"]=wasmExports["_PyLong_FormatWriter"])(a0,a1,a2,a3);var __PyLong_Frexp=Module["__PyLong_Frexp"]=(a0,a1)=>(__PyLong_Frexp=Module["__PyLong_Frexp"]=wasmExports["_PyLong_Frexp"])(a0,a1);var __PyLong_Rshift=Module["__PyLong_Rshift"]=(a0,a1)=>(__PyLong_Rshift=Module["__PyLong_Rshift"]=wasmExports["_PyLong_Rshift"])(a0,a1);var __PyLong_GCD=Module["__PyLong_GCD"]=(a0,a1)=>(__PyLong_GCD=Module["__PyLong_GCD"]=wasmExports["_PyLong_GCD"])(a0,a1);var __PyLong_DivmodNear=Module["__PyLong_DivmodNear"]=(a0,a1)=>(__PyLong_DivmodNear=Module["__PyLong_DivmodNear"]=wasmExports["_PyLong_DivmodNear"])(a0,a1);var _PyLong_GetInfo=Module["_PyLong_GetInfo"]=()=>(_PyLong_GetInfo=Module["_PyLong_GetInfo"]=wasmExports["PyLong_GetInfo"])();var _PyUnstable_Long_IsCompact=Module["_PyUnstable_Long_IsCompact"]=a0=>(_PyUnstable_Long_IsCompact=Module["_PyUnstable_Long_IsCompact"]=wasmExports["PyUnstable_Long_IsCompact"])(a0);var _PyUnstable_Long_CompactValue=Module["_PyUnstable_Long_CompactValue"]=a0=>(_PyUnstable_Long_CompactValue=Module["_PyUnstable_Long_CompactValue"]=wasmExports["PyUnstable_Long_CompactValue"])(a0);var _PyObject_Bytes=Module["_PyObject_Bytes"]=a0=>(_PyObject_Bytes=Module["_PyObject_Bytes"]=wasmExports["PyObject_Bytes"])(a0);var __PyLong_FormatAdvancedWriter=Module["__PyLong_FormatAdvancedWriter"]=(a0,a1,a2,a3,a4)=>(__PyLong_FormatAdvancedWriter=Module["__PyLong_FormatAdvancedWriter"]=wasmExports["_PyLong_FormatAdvancedWriter"])(a0,a1,a2,a3,a4);var __PyDict_DebugMallocStats=Module["__PyDict_DebugMallocStats"]=a0=>(__PyDict_DebugMallocStats=Module["__PyDict_DebugMallocStats"]=wasmExports["_PyDict_DebugMallocStats"])(a0);var __PyDict_CheckConsistency=Module["__PyDict_CheckConsistency"]=(a0,a1)=>(__PyDict_CheckConsistency=Module["__PyDict_CheckConsistency"]=wasmExports["_PyDict_CheckConsistency"])(a0,a1);var __PyObject_AssertFailed=Module["__PyObject_AssertFailed"]=(a0,a1,a2,a3,a4,a5)=>(__PyObject_AssertFailed=Module["__PyObject_AssertFailed"]=wasmExports["_PyObject_AssertFailed"])(a0,a1,a2,a3,a4,a5);var __PyDict_HasOnlyStringKeys=Module["__PyDict_HasOnlyStringKeys"]=a0=>(__PyDict_HasOnlyStringKeys=Module["__PyDict_HasOnlyStringKeys"]=wasmExports["_PyDict_HasOnlyStringKeys"])(a0);var __PyDict_Next=Module["__PyDict_Next"]=(a0,a1,a2,a3,a4)=>(__PyDict_Next=Module["__PyDict_Next"]=wasmExports["_PyDict_Next"])(a0,a1,a2,a3,a4);var __PyDict_MaybeUntrack=Module["__PyDict_MaybeUntrack"]=a0=>(__PyDict_MaybeUntrack=Module["__PyDict_MaybeUntrack"]=wasmExports["_PyDict_MaybeUntrack"])(a0);var _PyObject_IS_GC=Module["_PyObject_IS_GC"]=a0=>(_PyObject_IS_GC=Module["_PyObject_IS_GC"]=wasmExports["PyObject_IS_GC"])(a0);var __PyDict_NewPresized=Module["__PyDict_NewPresized"]=a0=>(__PyDict_NewPresized=Module["__PyDict_NewPresized"]=wasmExports["_PyDict_NewPresized"])(a0);var _PyDict_GetItem=Module["_PyDict_GetItem"]=(a0,a1)=>(_PyDict_GetItem=Module["_PyDict_GetItem"]=wasmExports["PyDict_GetItem"])(a0,a1);var __PyDict_GetItemWithError=Module["__PyDict_GetItemWithError"]=(a0,a1)=>(__PyDict_GetItemWithError=Module["__PyDict_GetItemWithError"]=wasmExports["_PyDict_GetItemWithError"])(a0,a1);var __PyDict_GetItemIdWithError=Module["__PyDict_GetItemIdWithError"]=(a0,a1)=>(__PyDict_GetItemIdWithError=Module["__PyDict_GetItemIdWithError"]=wasmExports["_PyDict_GetItemIdWithError"])(a0,a1);var __PyDict_GetItemStringWithError=Module["__PyDict_GetItemStringWithError"]=(a0,a1)=>(__PyDict_GetItemStringWithError=Module["__PyDict_GetItemStringWithError"]=wasmExports["_PyDict_GetItemStringWithError"])(a0,a1);var __PyDict_SetItem_KnownHash=Module["__PyDict_SetItem_KnownHash"]=(a0,a1,a2,a3)=>(__PyDict_SetItem_KnownHash=Module["__PyDict_SetItem_KnownHash"]=wasmExports["_PyDict_SetItem_KnownHash"])(a0,a1,a2,a3);var _PyDict_DelItem=Module["_PyDict_DelItem"]=(a0,a1)=>(_PyDict_DelItem=Module["_PyDict_DelItem"]=wasmExports["PyDict_DelItem"])(a0,a1);var __PyDict_DelItem_KnownHash=Module["__PyDict_DelItem_KnownHash"]=(a0,a1,a2)=>(__PyDict_DelItem_KnownHash=Module["__PyDict_DelItem_KnownHash"]=wasmExports["_PyDict_DelItem_KnownHash"])(a0,a1,a2);var __PyErr_SetKeyError=Module["__PyErr_SetKeyError"]=a0=>(__PyErr_SetKeyError=Module["__PyErr_SetKeyError"]=wasmExports["_PyErr_SetKeyError"])(a0);var __PyDict_DelItemIf=Module["__PyDict_DelItemIf"]=(a0,a1,a2)=>(__PyDict_DelItemIf=Module["__PyDict_DelItemIf"]=wasmExports["_PyDict_DelItemIf"])(a0,a1,a2);var _PyDict_Clear=Module["_PyDict_Clear"]=a0=>(_PyDict_Clear=Module["_PyDict_Clear"]=wasmExports["PyDict_Clear"])(a0);var __PyDict_Pop=Module["__PyDict_Pop"]=(a0,a1,a2)=>(__PyDict_Pop=Module["__PyDict_Pop"]=wasmExports["_PyDict_Pop"])(a0,a1,a2);var _PyDict_MergeFromSeq2=Module["_PyDict_MergeFromSeq2"]=(a0,a1,a2)=>(_PyDict_MergeFromSeq2=Module["_PyDict_MergeFromSeq2"]=wasmExports["PyDict_MergeFromSeq2"])(a0,a1,a2);var _PyDict_SetDefault=Module["_PyDict_SetDefault"]=(a0,a1,a2)=>(_PyDict_SetDefault=Module["_PyDict_SetDefault"]=wasmExports["PyDict_SetDefault"])(a0,a1,a2);var _PyDict_Update=Module["_PyDict_Update"]=(a0,a1)=>(_PyDict_Update=Module["_PyDict_Update"]=wasmExports["PyDict_Update"])(a0,a1);var __PyDict_MergeEx=Module["__PyDict_MergeEx"]=(a0,a1,a2)=>(__PyDict_MergeEx=Module["__PyDict_MergeEx"]=wasmExports["_PyDict_MergeEx"])(a0,a1,a2);var __PyDict_SizeOf=Module["__PyDict_SizeOf"]=a0=>(__PyDict_SizeOf=Module["__PyDict_SizeOf"]=wasmExports["_PyDict_SizeOf"])(a0);var __PyDict_Contains_KnownHash=Module["__PyDict_Contains_KnownHash"]=(a0,a1,a2)=>(__PyDict_Contains_KnownHash=Module["__PyDict_Contains_KnownHash"]=wasmExports["_PyDict_Contains_KnownHash"])(a0,a1,a2);var __PyDict_ContainsId=Module["__PyDict_ContainsId"]=(a0,a1)=>(__PyDict_ContainsId=Module["__PyDict_ContainsId"]=wasmExports["_PyDict_ContainsId"])(a0,a1);var _PyArg_ValidateKeywordArguments=Module["_PyArg_ValidateKeywordArguments"]=a0=>(_PyArg_ValidateKeywordArguments=Module["_PyArg_ValidateKeywordArguments"]=wasmExports["PyArg_ValidateKeywordArguments"])(a0);var _PyDict_GetItemString=Module["_PyDict_GetItemString"]=(a0,a1)=>(_PyDict_GetItemString=Module["_PyDict_GetItemString"]=wasmExports["PyDict_GetItemString"])(a0,a1);var __PyDict_SetItemId=Module["__PyDict_SetItemId"]=(a0,a1,a2)=>(__PyDict_SetItemId=Module["__PyDict_SetItemId"]=wasmExports["_PyDict_SetItemId"])(a0,a1,a2);var __PyDict_DelItemId=Module["__PyDict_DelItemId"]=(a0,a1)=>(__PyDict_DelItemId=Module["__PyDict_DelItemId"]=wasmExports["_PyDict_DelItemId"])(a0,a1);var _PyDict_DelItemString=Module["_PyDict_DelItemString"]=(a0,a1)=>(_PyDict_DelItemString=Module["_PyDict_DelItemString"]=wasmExports["PyDict_DelItemString"])(a0,a1);var __PyDictView_New=Module["__PyDictView_New"]=(a0,a1)=>(__PyDictView_New=Module["__PyDictView_New"]=wasmExports["_PyDictView_New"])(a0,a1);var __PyDictView_Intersect=Module["__PyDictView_Intersect"]=(a0,a1)=>(__PyDictView_Intersect=Module["__PyDictView_Intersect"]=wasmExports["_PyDictView_Intersect"])(a0,a1);var __PyObject_VisitManagedDict=Module["__PyObject_VisitManagedDict"]=(a0,a1,a2)=>(__PyObject_VisitManagedDict=Module["__PyObject_VisitManagedDict"]=wasmExports["_PyObject_VisitManagedDict"])(a0,a1,a2);var __PyObject_ClearManagedDict=Module["__PyObject_ClearManagedDict"]=a0=>(__PyObject_ClearManagedDict=Module["__PyObject_ClearManagedDict"]=wasmExports["_PyObject_ClearManagedDict"])(a0);var _PyDict_Watch=Module["_PyDict_Watch"]=(a0,a1)=>(_PyDict_Watch=Module["_PyDict_Watch"]=wasmExports["PyDict_Watch"])(a0,a1);var _PyDict_Unwatch=Module["_PyDict_Unwatch"]=(a0,a1)=>(_PyDict_Unwatch=Module["_PyDict_Unwatch"]=wasmExports["PyDict_Unwatch"])(a0,a1);var _PyDict_AddWatcher=Module["_PyDict_AddWatcher"]=a0=>(_PyDict_AddWatcher=Module["_PyDict_AddWatcher"]=wasmExports["PyDict_AddWatcher"])(a0);var _PyDict_ClearWatcher=Module["_PyDict_ClearWatcher"]=a0=>(_PyDict_ClearWatcher=Module["_PyDict_ClearWatcher"]=wasmExports["PyDict_ClearWatcher"])(a0);var _PyODict_New=Module["_PyODict_New"]=()=>(_PyODict_New=Module["_PyODict_New"]=wasmExports["PyODict_New"])();var _PyODict_SetItem=Module["_PyODict_SetItem"]=(a0,a1,a2)=>(_PyODict_SetItem=Module["_PyODict_SetItem"]=wasmExports["PyODict_SetItem"])(a0,a1,a2);var __PyErr_ChainExceptions1=Module["__PyErr_ChainExceptions1"]=a0=>(__PyErr_ChainExceptions1=Module["__PyErr_ChainExceptions1"]=wasmExports["_PyErr_ChainExceptions1"])(a0);var _PyODict_DelItem=Module["_PyODict_DelItem"]=(a0,a1)=>(_PyODict_DelItem=Module["_PyODict_DelItem"]=wasmExports["PyODict_DelItem"])(a0,a1);var _PyMemoryView_FromMemory=Module["_PyMemoryView_FromMemory"]=(a0,a1,a2)=>(_PyMemoryView_FromMemory=Module["_PyMemoryView_FromMemory"]=wasmExports["PyMemoryView_FromMemory"])(a0,a1,a2);var _PyMemoryView_FromBuffer=Module["_PyMemoryView_FromBuffer"]=a0=>(_PyMemoryView_FromBuffer=Module["_PyMemoryView_FromBuffer"]=wasmExports["PyMemoryView_FromBuffer"])(a0);var _PyMemoryView_GetContiguous=Module["_PyMemoryView_GetContiguous"]=(a0,a1,a2)=>(_PyMemoryView_GetContiguous=Module["_PyMemoryView_GetContiguous"]=wasmExports["PyMemoryView_GetContiguous"])(a0,a1,a2);var _PyUnicode_AsASCIIString=Module["_PyUnicode_AsASCIIString"]=a0=>(_PyUnicode_AsASCIIString=Module["_PyUnicode_AsASCIIString"]=wasmExports["PyUnicode_AsASCIIString"])(a0);var _PyCFunction_New=Module["_PyCFunction_New"]=(a0,a1)=>(_PyCFunction_New=Module["_PyCFunction_New"]=wasmExports["PyCFunction_New"])(a0,a1);var _PyCFunction_NewEx=Module["_PyCFunction_NewEx"]=(a0,a1,a2)=>(_PyCFunction_NewEx=Module["_PyCFunction_NewEx"]=wasmExports["PyCFunction_NewEx"])(a0,a1,a2);var _PyCFunction_GetFunction=Module["_PyCFunction_GetFunction"]=a0=>(_PyCFunction_GetFunction=Module["_PyCFunction_GetFunction"]=wasmExports["PyCFunction_GetFunction"])(a0);var _PyCFunction_GetSelf=Module["_PyCFunction_GetSelf"]=a0=>(_PyCFunction_GetSelf=Module["_PyCFunction_GetSelf"]=wasmExports["PyCFunction_GetSelf"])(a0);var _PyCFunction_GetFlags=Module["_PyCFunction_GetFlags"]=a0=>(_PyCFunction_GetFlags=Module["_PyCFunction_GetFlags"]=wasmExports["PyCFunction_GetFlags"])(a0);var _PyModuleDef_Init=Module["_PyModuleDef_Init"]=a0=>(_PyModuleDef_Init=Module["_PyModuleDef_Init"]=wasmExports["PyModuleDef_Init"])(a0);var _PyModule_NewObject=Module["_PyModule_NewObject"]=a0=>(_PyModule_NewObject=Module["_PyModule_NewObject"]=wasmExports["PyModule_NewObject"])(a0);var _PyModule_New=Module["_PyModule_New"]=a0=>(_PyModule_New=Module["_PyModule_New"]=wasmExports["PyModule_New"])(a0);var __PyImport_IsInitialized=Module["__PyImport_IsInitialized"]=a0=>(__PyImport_IsInitialized=Module["__PyImport_IsInitialized"]=wasmExports["_PyImport_IsInitialized"])(a0);var __PyModule_CreateInitialized=Module["__PyModule_CreateInitialized"]=(a0,a1)=>(__PyModule_CreateInitialized=Module["__PyModule_CreateInitialized"]=wasmExports["_PyModule_CreateInitialized"])(a0,a1);var _PyModule_SetDocString=Module["_PyModule_SetDocString"]=(a0,a1)=>(_PyModule_SetDocString=Module["_PyModule_SetDocString"]=wasmExports["PyModule_SetDocString"])(a0,a1);var _PyModule_FromDefAndSpec2=Module["_PyModule_FromDefAndSpec2"]=(a0,a1,a2)=>(_PyModule_FromDefAndSpec2=Module["_PyModule_FromDefAndSpec2"]=wasmExports["PyModule_FromDefAndSpec2"])(a0,a1,a2);var __PyImport_CheckSubinterpIncompatibleExtensionAllowed=Module["__PyImport_CheckSubinterpIncompatibleExtensionAllowed"]=a0=>(__PyImport_CheckSubinterpIncompatibleExtensionAllowed=Module["__PyImport_CheckSubinterpIncompatibleExtensionAllowed"]=wasmExports["_PyImport_CheckSubinterpIncompatibleExtensionAllowed"])(a0);var _PyModule_ExecDef=Module["_PyModule_ExecDef"]=(a0,a1)=>(_PyModule_ExecDef=Module["_PyModule_ExecDef"]=wasmExports["PyModule_ExecDef"])(a0,a1);var _PyModule_GetName=Module["_PyModule_GetName"]=a0=>(_PyModule_GetName=Module["_PyModule_GetName"]=wasmExports["PyModule_GetName"])(a0);var _PyModule_GetFilenameObject=Module["_PyModule_GetFilenameObject"]=a0=>(_PyModule_GetFilenameObject=Module["_PyModule_GetFilenameObject"]=wasmExports["PyModule_GetFilenameObject"])(a0);var _PyModule_GetFilename=Module["_PyModule_GetFilename"]=a0=>(_PyModule_GetFilename=Module["_PyModule_GetFilename"]=wasmExports["PyModule_GetFilename"])(a0);var _PyModule_GetDef=Module["_PyModule_GetDef"]=a0=>(_PyModule_GetDef=Module["_PyModule_GetDef"]=wasmExports["PyModule_GetDef"])(a0);var _PyModule_GetState=Module["_PyModule_GetState"]=a0=>(_PyModule_GetState=Module["_PyModule_GetState"]=wasmExports["PyModule_GetState"])(a0);var __PyModule_Clear=Module["__PyModule_Clear"]=a0=>(__PyModule_Clear=Module["__PyModule_Clear"]=wasmExports["_PyModule_Clear"])(a0);var __PyModule_ClearDict=Module["__PyModule_ClearDict"]=a0=>(__PyModule_ClearDict=Module["__PyModule_ClearDict"]=wasmExports["_PyModule_ClearDict"])(a0);var __PyModuleSpec_IsInitializing=Module["__PyModuleSpec_IsInitializing"]=a0=>(__PyModuleSpec_IsInitializing=Module["__PyModuleSpec_IsInitializing"]=wasmExports["_PyModuleSpec_IsInitializing"])(a0);var _PySys_FormatStderr=Module["_PySys_FormatStderr"]=(a0,a1)=>(_PySys_FormatStderr=Module["_PySys_FormatStderr"]=wasmExports["PySys_FormatStderr"])(a0,a1);var _PyUnicode_Join=Module["_PyUnicode_Join"]=(a0,a1)=>(_PyUnicode_Join=Module["_PyUnicode_Join"]=wasmExports["PyUnicode_Join"])(a0,a1);var __PyNamespace_New=Module["__PyNamespace_New"]=a0=>(__PyNamespace_New=Module["__PyNamespace_New"]=wasmExports["_PyNamespace_New"])(a0);var __PyObject_CheckConsistency=Module["__PyObject_CheckConsistency"]=(a0,a1)=>(__PyObject_CheckConsistency=Module["__PyObject_CheckConsistency"]=wasmExports["_PyObject_CheckConsistency"])(a0,a1);var __PyType_CheckConsistency=Module["__PyType_CheckConsistency"]=a0=>(__PyType_CheckConsistency=Module["__PyType_CheckConsistency"]=wasmExports["_PyType_CheckConsistency"])(a0);var __PyUnicode_CheckConsistency=Module["__PyUnicode_CheckConsistency"]=(a0,a1)=>(__PyUnicode_CheckConsistency=Module["__PyUnicode_CheckConsistency"]=wasmExports["_PyUnicode_CheckConsistency"])(a0,a1);var __PyObject_IsFreed=Module["__PyObject_IsFreed"]=a0=>(__PyObject_IsFreed=Module["__PyObject_IsFreed"]=wasmExports["_PyObject_IsFreed"])(a0);var _fiprintf=Module["_fiprintf"]=(a0,a1,a2)=>(_fiprintf=Module["_fiprintf"]=wasmExports["fiprintf"])(a0,a1,a2);var _fwrite=Module["_fwrite"]=(a0,a1,a2,a3)=>(_fwrite=Module["_fwrite"]=wasmExports["fwrite"])(a0,a1,a2,a3);var _fputc=Module["_fputc"]=(a0,a1)=>(_fputc=Module["_fputc"]=wasmExports["fputc"])(a0,a1);var __PyObject_Dump=Module["__PyObject_Dump"]=a0=>(__PyObject_Dump=Module["__PyObject_Dump"]=wasmExports["_PyObject_Dump"])(a0);var _Py_IncRef=Module["_Py_IncRef"]=a0=>(_Py_IncRef=Module["_Py_IncRef"]=wasmExports["Py_IncRef"])(a0);var _Py_DecRef=Module["_Py_DecRef"]=a0=>(_Py_DecRef=Module["_Py_DecRef"]=wasmExports["Py_DecRef"])(a0);var __Py_IncRef=Module["__Py_IncRef"]=a0=>(__Py_IncRef=Module["__Py_IncRef"]=wasmExports["_Py_IncRef"])(a0);var __Py_DecRef=Module["__Py_DecRef"]=a0=>(__Py_DecRef=Module["__Py_DecRef"]=wasmExports["_Py_DecRef"])(a0);var _PyObject_Init=Module["_PyObject_Init"]=(a0,a1)=>(_PyObject_Init=Module["_PyObject_Init"]=wasmExports["PyObject_Init"])(a0,a1);var _PyObject_InitVar=Module["_PyObject_InitVar"]=(a0,a1,a2)=>(_PyObject_InitVar=Module["_PyObject_InitVar"]=wasmExports["PyObject_InitVar"])(a0,a1,a2);var _PyObject_CallFinalizer=Module["_PyObject_CallFinalizer"]=a0=>(_PyObject_CallFinalizer=Module["_PyObject_CallFinalizer"]=wasmExports["PyObject_CallFinalizer"])(a0);var _PyObject_Print=Module["_PyObject_Print"]=(a0,a1,a2)=>(_PyObject_Print=Module["_PyObject_Print"]=wasmExports["PyObject_Print"])(a0,a1,a2);var _ferror=Module["_ferror"]=a0=>(_ferror=Module["_ferror"]=wasmExports["ferror"])(a0);var __Py_BreakPoint=Module["__Py_BreakPoint"]=()=>(__Py_BreakPoint=Module["__Py_BreakPoint"]=wasmExports["_Py_BreakPoint"])();var _PyGILState_Ensure=Module["_PyGILState_Ensure"]=()=>(_PyGILState_Ensure=Module["_PyGILState_Ensure"]=wasmExports["PyGILState_Ensure"])();var _PyGILState_Release=Module["_PyGILState_Release"]=a0=>(_PyGILState_Release=Module["_PyGILState_Release"]=wasmExports["PyGILState_Release"])(a0);var __PyUnicode_AsASCIIString=Module["__PyUnicode_AsASCIIString"]=(a0,a1)=>(__PyUnicode_AsASCIIString=Module["__PyUnicode_AsASCIIString"]=wasmExports["_PyUnicode_AsASCIIString"])(a0,a1);var _PyUnicode_DecodeASCII=Module["_PyUnicode_DecodeASCII"]=(a0,a1,a2)=>(_PyUnicode_DecodeASCII=Module["_PyUnicode_DecodeASCII"]=wasmExports["PyUnicode_DecodeASCII"])(a0,a1,a2);var _PyObject_HasAttrString=Module["_PyObject_HasAttrString"]=(a0,a1)=>(_PyObject_HasAttrString=Module["_PyObject_HasAttrString"]=wasmExports["PyObject_HasAttrString"])(a0,a1);var __PyObject_LookupAttrId=Module["__PyObject_LookupAttrId"]=(a0,a1,a2)=>(__PyObject_LookupAttrId=Module["__PyObject_LookupAttrId"]=wasmExports["_PyObject_LookupAttrId"])(a0,a1,a2);var __PyObject_GetDictPtr=Module["__PyObject_GetDictPtr"]=a0=>(__PyObject_GetDictPtr=Module["__PyObject_GetDictPtr"]=wasmExports["_PyObject_GetDictPtr"])(a0);var __PyObject_GenericSetAttrWithDict=Module["__PyObject_GenericSetAttrWithDict"]=(a0,a1,a2,a3)=>(__PyObject_GenericSetAttrWithDict=Module["__PyObject_GenericSetAttrWithDict"]=wasmExports["_PyObject_GenericSetAttrWithDict"])(a0,a1,a2,a3);var _PyObject_Not=Module["_PyObject_Not"]=a0=>(_PyObject_Not=Module["_PyObject_Not"]=wasmExports["PyObject_Not"])(a0);var __PyObject_DebugTypeStats=Module["__PyObject_DebugTypeStats"]=a0=>(__PyObject_DebugTypeStats=Module["__PyObject_DebugTypeStats"]=wasmExports["_PyObject_DebugTypeStats"])(a0);var __PyTuple_DebugMallocStats=Module["__PyTuple_DebugMallocStats"]=a0=>(__PyTuple_DebugMallocStats=Module["__PyTuple_DebugMallocStats"]=wasmExports["_PyTuple_DebugMallocStats"])(a0);var _PyThreadState_GetDict=Module["_PyThreadState_GetDict"]=()=>(_PyThreadState_GetDict=Module["_PyThreadState_GetDict"]=wasmExports["PyThreadState_GetDict"])();var _PyThread_tss_get=Module["_PyThread_tss_get"]=a0=>(_PyThread_tss_get=Module["_PyThread_tss_get"]=wasmExports["PyThread_tss_get"])(a0);var _PyMem_RawMalloc=Module["_PyMem_RawMalloc"]=a0=>(_PyMem_RawMalloc=Module["_PyMem_RawMalloc"]=wasmExports["PyMem_RawMalloc"])(a0);var _PyThread_tss_set=Module["_PyThread_tss_set"]=(a0,a1)=>(_PyThread_tss_set=Module["_PyThread_tss_set"]=wasmExports["PyThread_tss_set"])(a0,a1);var _PyThread_tss_is_created=Module["_PyThread_tss_is_created"]=a0=>(_PyThread_tss_is_created=Module["_PyThread_tss_is_created"]=wasmExports["PyThread_tss_is_created"])(a0);var _PyObject_GET_WEAKREFS_LISTPTR=Module["_PyObject_GET_WEAKREFS_LISTPTR"]=a0=>(_PyObject_GET_WEAKREFS_LISTPTR=Module["_PyObject_GET_WEAKREFS_LISTPTR"]=wasmExports["PyObject_GET_WEAKREFS_LISTPTR"])(a0);var _Py_NewRef=Module["_Py_NewRef"]=a0=>(_Py_NewRef=Module["_Py_NewRef"]=wasmExports["Py_NewRef"])(a0);var _Py_XNewRef=Module["_Py_XNewRef"]=a0=>(_Py_XNewRef=Module["_Py_XNewRef"]=wasmExports["Py_XNewRef"])(a0);var _Py_Is=Module["_Py_Is"]=(a0,a1)=>(_Py_Is=Module["_Py_Is"]=wasmExports["Py_Is"])(a0,a1);var _Py_IsNone=Module["_Py_IsNone"]=a0=>(_Py_IsNone=Module["_Py_IsNone"]=wasmExports["Py_IsNone"])(a0);var _Py_IsTrue=Module["_Py_IsTrue"]=a0=>(_Py_IsTrue=Module["_Py_IsTrue"]=wasmExports["Py_IsTrue"])(a0);var _Py_IsFalse=Module["_Py_IsFalse"]=a0=>(_Py_IsFalse=Module["_Py_IsFalse"]=wasmExports["Py_IsFalse"])(a0);var _calloc=Module["_calloc"]=(a0,a1)=>(_calloc=Module["_calloc"]=wasmExports["calloc"])(a0,a1);var _realloc=Module["_realloc"]=(a0,a1)=>(_realloc=Module["_realloc"]=wasmExports["realloc"])(a0,a1);var __PyMem_SetDefaultAllocator=Module["__PyMem_SetDefaultAllocator"]=(a0,a1)=>(__PyMem_SetDefaultAllocator=Module["__PyMem_SetDefaultAllocator"]=wasmExports["_PyMem_SetDefaultAllocator"])(a0,a1);var __PyMem_GetAllocatorName=Module["__PyMem_GetAllocatorName"]=(a0,a1)=>(__PyMem_GetAllocatorName=Module["__PyMem_GetAllocatorName"]=wasmExports["_PyMem_GetAllocatorName"])(a0,a1);var __PyMem_SetupAllocators=Module["__PyMem_SetupAllocators"]=a0=>(__PyMem_SetupAllocators=Module["__PyMem_SetupAllocators"]=wasmExports["_PyMem_SetupAllocators"])(a0);var __PyMem_GetCurrentAllocatorName=Module["__PyMem_GetCurrentAllocatorName"]=()=>(__PyMem_GetCurrentAllocatorName=Module["__PyMem_GetCurrentAllocatorName"]=wasmExports["_PyMem_GetCurrentAllocatorName"])();var _PyMem_SetupDebugHooks=Module["_PyMem_SetupDebugHooks"]=()=>(_PyMem_SetupDebugHooks=Module["_PyMem_SetupDebugHooks"]=wasmExports["PyMem_SetupDebugHooks"])();var _PyMem_GetAllocator=Module["_PyMem_GetAllocator"]=(a0,a1)=>(_PyMem_GetAllocator=Module["_PyMem_GetAllocator"]=wasmExports["PyMem_GetAllocator"])(a0,a1);var _PyMem_SetAllocator=Module["_PyMem_SetAllocator"]=(a0,a1)=>(_PyMem_SetAllocator=Module["_PyMem_SetAllocator"]=wasmExports["PyMem_SetAllocator"])(a0,a1);var _PyObject_SetArenaAllocator=Module["_PyObject_SetArenaAllocator"]=a0=>(_PyObject_SetArenaAllocator=Module["_PyObject_SetArenaAllocator"]=wasmExports["PyObject_SetArenaAllocator"])(a0);var _PyMem_RawCalloc=Module["_PyMem_RawCalloc"]=(a0,a1)=>(_PyMem_RawCalloc=Module["_PyMem_RawCalloc"]=wasmExports["PyMem_RawCalloc"])(a0,a1);var __PyMem_RawWcsdup=Module["__PyMem_RawWcsdup"]=a0=>(__PyMem_RawWcsdup=Module["__PyMem_RawWcsdup"]=wasmExports["_PyMem_RawWcsdup"])(a0);var _wcslen=Module["_wcslen"]=a0=>(_wcslen=Module["_wcslen"]=wasmExports["wcslen"])(a0);var __PyMem_RawStrdup=Module["__PyMem_RawStrdup"]=a0=>(__PyMem_RawStrdup=Module["__PyMem_RawStrdup"]=wasmExports["_PyMem_RawStrdup"])(a0);var __PyMem_Strdup=Module["__PyMem_Strdup"]=a0=>(__PyMem_Strdup=Module["__PyMem_Strdup"]=wasmExports["_PyMem_Strdup"])(a0);var _PyPickleBuffer_FromObject=Module["_PyPickleBuffer_FromObject"]=a0=>(_PyPickleBuffer_FromObject=Module["_PyPickleBuffer_FromObject"]=wasmExports["PyPickleBuffer_FromObject"])(a0);var _PyPickleBuffer_GetBuffer=Module["_PyPickleBuffer_GetBuffer"]=a0=>(_PyPickleBuffer_GetBuffer=Module["_PyPickleBuffer_GetBuffer"]=wasmExports["PyPickleBuffer_GetBuffer"])(a0);var _PyPickleBuffer_Release=Module["_PyPickleBuffer_Release"]=a0=>(_PyPickleBuffer_Release=Module["_PyPickleBuffer_Release"]=wasmExports["PyPickleBuffer_Release"])(a0);var __PySlice_GetLongIndices=Module["__PySlice_GetLongIndices"]=(a0,a1,a2,a3,a4)=>(__PySlice_GetLongIndices=Module["__PySlice_GetLongIndices"]=wasmExports["_PySlice_GetLongIndices"])(a0,a1,a2,a3,a4);var _PySet_Size=Module["_PySet_Size"]=a0=>(_PySet_Size=Module["_PySet_Size"]=wasmExports["PySet_Size"])(a0);var _PySet_Clear=Module["_PySet_Clear"]=a0=>(_PySet_Clear=Module["_PySet_Clear"]=wasmExports["PySet_Clear"])(a0);var _PySet_Pop=Module["_PySet_Pop"]=a0=>(_PySet_Pop=Module["_PySet_Pop"]=wasmExports["PySet_Pop"])(a0);var _PySlice_New=Module["_PySlice_New"]=(a0,a1,a2)=>(_PySlice_New=Module["_PySlice_New"]=wasmExports["PySlice_New"])(a0,a1,a2);var _PySlice_GetIndices=Module["_PySlice_GetIndices"]=(a0,a1,a2,a3,a4)=>(_PySlice_GetIndices=Module["_PySlice_GetIndices"]=wasmExports["PySlice_GetIndices"])(a0,a1,a2,a3,a4);var _PySlice_GetIndicesEx=Module["_PySlice_GetIndicesEx"]=(a0,a1,a2,a3,a4,a5)=>(_PySlice_GetIndicesEx=Module["_PySlice_GetIndicesEx"]=wasmExports["PySlice_GetIndicesEx"])(a0,a1,a2,a3,a4,a5);var _PyStructSequence_SetItem=Module["_PyStructSequence_SetItem"]=(a0,a1,a2)=>(_PyStructSequence_SetItem=Module["_PyStructSequence_SetItem"]=wasmExports["PyStructSequence_SetItem"])(a0,a1,a2);var _PyStructSequence_GetItem=Module["_PyStructSequence_GetItem"]=(a0,a1)=>(_PyStructSequence_GetItem=Module["_PyStructSequence_GetItem"]=wasmExports["PyStructSequence_GetItem"])(a0,a1);var _PyStructSequence_InitType2=Module["_PyStructSequence_InitType2"]=(a0,a1)=>(_PyStructSequence_InitType2=Module["_PyStructSequence_InitType2"]=wasmExports["PyStructSequence_InitType2"])(a0,a1);var _PyStructSequence_InitType=Module["_PyStructSequence_InitType"]=(a0,a1)=>(_PyStructSequence_InitType=Module["_PyStructSequence_InitType"]=wasmExports["PyStructSequence_InitType"])(a0,a1);var __PyStructSequence_NewType=Module["__PyStructSequence_NewType"]=(a0,a1)=>(__PyStructSequence_NewType=Module["__PyStructSequence_NewType"]=wasmExports["_PyStructSequence_NewType"])(a0,a1);var _PyStructSequence_NewType=Module["_PyStructSequence_NewType"]=a0=>(_PyStructSequence_NewType=Module["_PyStructSequence_NewType"]=wasmExports["PyStructSequence_NewType"])(a0);var _PyTuple_SetItem=Module["_PyTuple_SetItem"]=(a0,a1,a2)=>(_PyTuple_SetItem=Module["_PyTuple_SetItem"]=wasmExports["PyTuple_SetItem"])(a0,a1,a2);var __PyTuple_MaybeUntrack=Module["__PyTuple_MaybeUntrack"]=a0=>(__PyTuple_MaybeUntrack=Module["__PyTuple_MaybeUntrack"]=wasmExports["_PyTuple_MaybeUntrack"])(a0);var __PyObject_GC_Resize=Module["__PyObject_GC_Resize"]=(a0,a1)=>(__PyObject_GC_Resize=Module["__PyObject_GC_Resize"]=wasmExports["_PyObject_GC_Resize"])(a0,a1);var _PyType_GetDict=Module["_PyType_GetDict"]=a0=>(_PyType_GetDict=Module["_PyType_GetDict"]=wasmExports["PyType_GetDict"])(a0);var _strrchr=Module["_strrchr"]=(a0,a1)=>(_strrchr=Module["_strrchr"]=wasmExports["strrchr"])(a0,a1);var _PyType_ClearCache=Module["_PyType_ClearCache"]=()=>(_PyType_ClearCache=Module["_PyType_ClearCache"]=wasmExports["PyType_ClearCache"])();var _PyType_AddWatcher=Module["_PyType_AddWatcher"]=a0=>(_PyType_AddWatcher=Module["_PyType_AddWatcher"]=wasmExports["PyType_AddWatcher"])(a0);var _PyType_ClearWatcher=Module["_PyType_ClearWatcher"]=a0=>(_PyType_ClearWatcher=Module["_PyType_ClearWatcher"]=wasmExports["PyType_ClearWatcher"])(a0);var _PyType_Watch=Module["_PyType_Watch"]=(a0,a1)=>(_PyType_Watch=Module["_PyType_Watch"]=wasmExports["PyType_Watch"])(a0,a1);var _PyType_Unwatch=Module["_PyType_Unwatch"]=(a0,a1)=>(_PyType_Unwatch=Module["_PyType_Unwatch"]=wasmExports["PyType_Unwatch"])(a0,a1);var _PyType_Modified=Module["_PyType_Modified"]=a0=>(_PyType_Modified=Module["_PyType_Modified"]=wasmExports["PyType_Modified"])(a0);var _PyUnstable_Type_AssignVersionTag=Module["_PyUnstable_Type_AssignVersionTag"]=a0=>(_PyUnstable_Type_AssignVersionTag=Module["_PyUnstable_Type_AssignVersionTag"]=wasmExports["PyUnstable_Type_AssignVersionTag"])(a0);var __PyObject_LookupSpecialId=Module["__PyObject_LookupSpecialId"]=(a0,a1)=>(__PyObject_LookupSpecialId=Module["__PyObject_LookupSpecialId"]=wasmExports["_PyObject_LookupSpecialId"])(a0,a1);var _PyType_GetFlags=Module["_PyType_GetFlags"]=a0=>(_PyType_GetFlags=Module["_PyType_GetFlags"]=wasmExports["PyType_GetFlags"])(a0);var _PyType_SUPPORTS_WEAKREFS=Module["_PyType_SUPPORTS_WEAKREFS"]=a0=>(_PyType_SUPPORTS_WEAKREFS=Module["_PyType_SUPPORTS_WEAKREFS"]=wasmExports["PyType_SUPPORTS_WEAKREFS"])(a0);var __PyType_CalculateMetaclass=Module["__PyType_CalculateMetaclass"]=(a0,a1)=>(__PyType_CalculateMetaclass=Module["__PyType_CalculateMetaclass"]=wasmExports["_PyType_CalculateMetaclass"])(a0,a1);var _PyType_FromMetaclass=Module["_PyType_FromMetaclass"]=(a0,a1,a2,a3)=>(_PyType_FromMetaclass=Module["_PyType_FromMetaclass"]=wasmExports["PyType_FromMetaclass"])(a0,a1,a2,a3);var _PyType_FromModuleAndSpec=Module["_PyType_FromModuleAndSpec"]=(a0,a1,a2)=>(_PyType_FromModuleAndSpec=Module["_PyType_FromModuleAndSpec"]=wasmExports["PyType_FromModuleAndSpec"])(a0,a1,a2);var _PyType_FromSpec=Module["_PyType_FromSpec"]=a0=>(_PyType_FromSpec=Module["_PyType_FromSpec"]=wasmExports["PyType_FromSpec"])(a0);var _PyType_GetName=Module["_PyType_GetName"]=a0=>(_PyType_GetName=Module["_PyType_GetName"]=wasmExports["PyType_GetName"])(a0);var _PyType_GetSlot=Module["_PyType_GetSlot"]=(a0,a1)=>(_PyType_GetSlot=Module["_PyType_GetSlot"]=wasmExports["PyType_GetSlot"])(a0,a1);var _PyType_GetModule=Module["_PyType_GetModule"]=a0=>(_PyType_GetModule=Module["_PyType_GetModule"]=wasmExports["PyType_GetModule"])(a0);var _PyType_GetModuleState=Module["_PyType_GetModuleState"]=a0=>(_PyType_GetModuleState=Module["_PyType_GetModuleState"]=wasmExports["PyType_GetModuleState"])(a0);var _PyType_GetModuleByDef=Module["_PyType_GetModuleByDef"]=(a0,a1)=>(_PyType_GetModuleByDef=Module["_PyType_GetModuleByDef"]=wasmExports["PyType_GetModuleByDef"])(a0,a1);var _PyObject_GetTypeData=Module["_PyObject_GetTypeData"]=(a0,a1)=>(_PyObject_GetTypeData=Module["_PyObject_GetTypeData"]=wasmExports["PyObject_GetTypeData"])(a0,a1);var _PyType_GetTypeDataSize=Module["_PyType_GetTypeDataSize"]=a0=>(_PyType_GetTypeDataSize=Module["_PyType_GetTypeDataSize"]=wasmExports["PyType_GetTypeDataSize"])(a0);var _PyObject_GetItemData=Module["_PyObject_GetItemData"]=a0=>(_PyObject_GetItemData=Module["_PyObject_GetItemData"]=wasmExports["PyObject_GetItemData"])(a0);var __PyType_LookupId=Module["__PyType_LookupId"]=(a0,a1)=>(__PyType_LookupId=Module["__PyType_LookupId"]=wasmExports["_PyType_LookupId"])(a0,a1);var _PyArg_ParseTuple=Module["_PyArg_ParseTuple"]=(a0,a1,a2)=>(_PyArg_ParseTuple=Module["_PyArg_ParseTuple"]=wasmExports["PyArg_ParseTuple"])(a0,a1,a2);var _PyUnicode_IsIdentifier=Module["_PyUnicode_IsIdentifier"]=a0=>(_PyUnicode_IsIdentifier=Module["_PyUnicode_IsIdentifier"]=wasmExports["PyUnicode_IsIdentifier"])(a0);var _PyEval_GetGlobals=Module["_PyEval_GetGlobals"]=()=>(_PyEval_GetGlobals=Module["_PyEval_GetGlobals"]=wasmExports["PyEval_GetGlobals"])();var __PyWeakref_ClearRef=Module["__PyWeakref_ClearRef"]=a0=>(__PyWeakref_ClearRef=Module["__PyWeakref_ClearRef"]=wasmExports["_PyWeakref_ClearRef"])(a0);var _PyWeakref_NewRef=Module["_PyWeakref_NewRef"]=(a0,a1)=>(_PyWeakref_NewRef=Module["_PyWeakref_NewRef"]=wasmExports["PyWeakref_NewRef"])(a0,a1);var _PyImport_GetModule=Module["_PyImport_GetModule"]=a0=>(_PyImport_GetModule=Module["_PyImport_GetModule"]=wasmExports["PyImport_GetModule"])(a0);var _PyImport_Import=Module["_PyImport_Import"]=a0=>(_PyImport_Import=Module["_PyImport_Import"]=wasmExports["PyImport_Import"])(a0);var __PyArg_UnpackKeywordsWithVararg=Module["__PyArg_UnpackKeywordsWithVararg"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(__PyArg_UnpackKeywordsWithVararg=Module["__PyArg_UnpackKeywordsWithVararg"]=wasmExports["_PyArg_UnpackKeywordsWithVararg"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);var __Py_hashtable_len=Module["__Py_hashtable_len"]=a0=>(__Py_hashtable_len=Module["__Py_hashtable_len"]=wasmExports["_Py_hashtable_len"])(a0);var __Py_GetErrorHandler=Module["__Py_GetErrorHandler"]=a0=>(__Py_GetErrorHandler=Module["__Py_GetErrorHandler"]=wasmExports["_Py_GetErrorHandler"])(a0);var __PyUnicode_FastCopyCharacters=Module["__PyUnicode_FastCopyCharacters"]=(a0,a1,a2,a3,a4)=>(__PyUnicode_FastCopyCharacters=Module["__PyUnicode_FastCopyCharacters"]=wasmExports["_PyUnicode_FastCopyCharacters"])(a0,a1,a2,a3,a4);var _PyUnicode_CopyCharacters=Module["_PyUnicode_CopyCharacters"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_CopyCharacters=Module["_PyUnicode_CopyCharacters"]=wasmExports["PyUnicode_CopyCharacters"])(a0,a1,a2,a3,a4);var _PyUnicode_Resize=Module["_PyUnicode_Resize"]=(a0,a1)=>(_PyUnicode_Resize=Module["_PyUnicode_Resize"]=wasmExports["PyUnicode_Resize"])(a0,a1);var _PyUnicode_FromWideChar=Module["_PyUnicode_FromWideChar"]=(a0,a1)=>(_PyUnicode_FromWideChar=Module["_PyUnicode_FromWideChar"]=wasmExports["PyUnicode_FromWideChar"])(a0,a1);var _PyUnicode_FromKindAndData=Module["_PyUnicode_FromKindAndData"]=(a0,a1,a2)=>(_PyUnicode_FromKindAndData=Module["_PyUnicode_FromKindAndData"]=wasmExports["PyUnicode_FromKindAndData"])(a0,a1,a2);var __PyUnicode_FindMaxChar=Module["__PyUnicode_FindMaxChar"]=(a0,a1,a2)=>(__PyUnicode_FindMaxChar=Module["__PyUnicode_FindMaxChar"]=wasmExports["_PyUnicode_FindMaxChar"])(a0,a1,a2);var _PyUnicode_AsUCS4=Module["_PyUnicode_AsUCS4"]=(a0,a1,a2,a3)=>(_PyUnicode_AsUCS4=Module["_PyUnicode_AsUCS4"]=wasmExports["PyUnicode_AsUCS4"])(a0,a1,a2,a3);var _PyUnicode_AsUCS4Copy=Module["_PyUnicode_AsUCS4Copy"]=a0=>(_PyUnicode_AsUCS4Copy=Module["_PyUnicode_AsUCS4Copy"]=wasmExports["PyUnicode_AsUCS4Copy"])(a0);var _PyUnicode_Fill=Module["_PyUnicode_Fill"]=(a0,a1,a2,a3)=>(_PyUnicode_Fill=Module["_PyUnicode_Fill"]=wasmExports["PyUnicode_Fill"])(a0,a1,a2,a3);var _PyUnicode_AsWideChar=Module["_PyUnicode_AsWideChar"]=(a0,a1,a2)=>(_PyUnicode_AsWideChar=Module["_PyUnicode_AsWideChar"]=wasmExports["PyUnicode_AsWideChar"])(a0,a1,a2);var _PyUnicode_AsWideCharString=Module["_PyUnicode_AsWideCharString"]=(a0,a1)=>(_PyUnicode_AsWideCharString=Module["_PyUnicode_AsWideCharString"]=wasmExports["PyUnicode_AsWideCharString"])(a0,a1);var __PyUnicode_WideCharString_Converter=Module["__PyUnicode_WideCharString_Converter"]=(a0,a1)=>(__PyUnicode_WideCharString_Converter=Module["__PyUnicode_WideCharString_Converter"]=wasmExports["_PyUnicode_WideCharString_Converter"])(a0,a1);var __PyUnicode_WideCharString_Opt_Converter=Module["__PyUnicode_WideCharString_Opt_Converter"]=(a0,a1)=>(__PyUnicode_WideCharString_Opt_Converter=Module["__PyUnicode_WideCharString_Opt_Converter"]=wasmExports["_PyUnicode_WideCharString_Opt_Converter"])(a0,a1);var _PyUnicode_FromOrdinal=Module["_PyUnicode_FromOrdinal"]=a0=>(_PyUnicode_FromOrdinal=Module["_PyUnicode_FromOrdinal"]=wasmExports["PyUnicode_FromOrdinal"])(a0);var _PyUnicode_FromObject=Module["_PyUnicode_FromObject"]=a0=>(_PyUnicode_FromObject=Module["_PyUnicode_FromObject"]=wasmExports["PyUnicode_FromObject"])(a0);var __PyInterpreterState_GetConfig=Module["__PyInterpreterState_GetConfig"]=a0=>(__PyInterpreterState_GetConfig=Module["__PyInterpreterState_GetConfig"]=wasmExports["_PyInterpreterState_GetConfig"])(a0);var __PyCodec_Lookup=Module["__PyCodec_Lookup"]=a0=>(__PyCodec_Lookup=Module["__PyCodec_Lookup"]=wasmExports["_PyCodec_Lookup"])(a0);var _PyCodec_LookupError=Module["_PyCodec_LookupError"]=a0=>(_PyCodec_LookupError=Module["_PyCodec_LookupError"]=wasmExports["PyCodec_LookupError"])(a0);var _PyUnicode_DecodeUTF16Stateful=Module["_PyUnicode_DecodeUTF16Stateful"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_DecodeUTF16Stateful=Module["_PyUnicode_DecodeUTF16Stateful"]=wasmExports["PyUnicode_DecodeUTF16Stateful"])(a0,a1,a2,a3,a4);var _PyUnicode_DecodeUTF32Stateful=Module["_PyUnicode_DecodeUTF32Stateful"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_DecodeUTF32Stateful=Module["_PyUnicode_DecodeUTF32Stateful"]=wasmExports["PyUnicode_DecodeUTF32Stateful"])(a0,a1,a2,a3,a4);var __PyCodec_DecodeText=Module["__PyCodec_DecodeText"]=(a0,a1,a2)=>(__PyCodec_DecodeText=Module["__PyCodec_DecodeText"]=wasmExports["_PyCodec_DecodeText"])(a0,a1,a2);var _PyUnicode_DecodeUTF16=Module["_PyUnicode_DecodeUTF16"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF16=Module["_PyUnicode_DecodeUTF16"]=wasmExports["PyUnicode_DecodeUTF16"])(a0,a1,a2,a3);var _PyUnicode_DecodeUTF32=Module["_PyUnicode_DecodeUTF32"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF32=Module["_PyUnicode_DecodeUTF32"]=wasmExports["PyUnicode_DecodeUTF32"])(a0,a1,a2,a3);var _PyUnicode_AsDecodedObject=Module["_PyUnicode_AsDecodedObject"]=(a0,a1,a2)=>(_PyUnicode_AsDecodedObject=Module["_PyUnicode_AsDecodedObject"]=wasmExports["PyUnicode_AsDecodedObject"])(a0,a1,a2);var _PyCodec_Decode=Module["_PyCodec_Decode"]=(a0,a1,a2)=>(_PyCodec_Decode=Module["_PyCodec_Decode"]=wasmExports["PyCodec_Decode"])(a0,a1,a2);var _PyUnicode_AsDecodedUnicode=Module["_PyUnicode_AsDecodedUnicode"]=(a0,a1,a2)=>(_PyUnicode_AsDecodedUnicode=Module["_PyUnicode_AsDecodedUnicode"]=wasmExports["PyUnicode_AsDecodedUnicode"])(a0,a1,a2);var _PyUnicode_AsEncodedObject=Module["_PyUnicode_AsEncodedObject"]=(a0,a1,a2)=>(_PyUnicode_AsEncodedObject=Module["_PyUnicode_AsEncodedObject"]=wasmExports["PyUnicode_AsEncodedObject"])(a0,a1,a2);var _PyCodec_Encode=Module["_PyCodec_Encode"]=(a0,a1,a2)=>(_PyCodec_Encode=Module["_PyCodec_Encode"]=wasmExports["PyCodec_Encode"])(a0,a1,a2);var _PyUnicode_EncodeLocale=Module["_PyUnicode_EncodeLocale"]=(a0,a1)=>(_PyUnicode_EncodeLocale=Module["_PyUnicode_EncodeLocale"]=wasmExports["PyUnicode_EncodeLocale"])(a0,a1);var __Py_EncodeLocaleEx=Module["__Py_EncodeLocaleEx"]=(a0,a1,a2,a3,a4,a5)=>(__Py_EncodeLocaleEx=Module["__Py_EncodeLocaleEx"]=wasmExports["_Py_EncodeLocaleEx"])(a0,a1,a2,a3,a4,a5);var _PyCodec_StrictErrors=Module["_PyCodec_StrictErrors"]=a0=>(_PyCodec_StrictErrors=Module["_PyCodec_StrictErrors"]=wasmExports["PyCodec_StrictErrors"])(a0);var _PyUnicode_EncodeFSDefault=Module["_PyUnicode_EncodeFSDefault"]=a0=>(_PyUnicode_EncodeFSDefault=Module["_PyUnicode_EncodeFSDefault"]=wasmExports["PyUnicode_EncodeFSDefault"])(a0);var __PyUnicode_EncodeUTF16=Module["__PyUnicode_EncodeUTF16"]=(a0,a1,a2)=>(__PyUnicode_EncodeUTF16=Module["__PyUnicode_EncodeUTF16"]=wasmExports["_PyUnicode_EncodeUTF16"])(a0,a1,a2);var __PyUnicode_EncodeUTF32=Module["__PyUnicode_EncodeUTF32"]=(a0,a1,a2)=>(__PyUnicode_EncodeUTF32=Module["__PyUnicode_EncodeUTF32"]=wasmExports["_PyUnicode_EncodeUTF32"])(a0,a1,a2);var __PyCodec_EncodeText=Module["__PyCodec_EncodeText"]=(a0,a1,a2)=>(__PyCodec_EncodeText=Module["__PyCodec_EncodeText"]=wasmExports["_PyCodec_EncodeText"])(a0,a1,a2);var _wcscmp=Module["_wcscmp"]=(a0,a1)=>(_wcscmp=Module["_wcscmp"]=wasmExports["wcscmp"])(a0,a1);var __PyUnicode_AsLatin1String=Module["__PyUnicode_AsLatin1String"]=(a0,a1)=>(__PyUnicode_AsLatin1String=Module["__PyUnicode_AsLatin1String"]=wasmExports["_PyUnicode_AsLatin1String"])(a0,a1);var _PyUnicode_AsEncodedUnicode=Module["_PyUnicode_AsEncodedUnicode"]=(a0,a1,a2)=>(_PyUnicode_AsEncodedUnicode=Module["_PyUnicode_AsEncodedUnicode"]=wasmExports["PyUnicode_AsEncodedUnicode"])(a0,a1,a2);var _PyUnicode_DecodeLocaleAndSize=Module["_PyUnicode_DecodeLocaleAndSize"]=(a0,a1,a2)=>(_PyUnicode_DecodeLocaleAndSize=Module["_PyUnicode_DecodeLocaleAndSize"]=wasmExports["PyUnicode_DecodeLocaleAndSize"])(a0,a1,a2);var __Py_DecodeLocaleEx=Module["__Py_DecodeLocaleEx"]=(a0,a1,a2,a3,a4,a5)=>(__Py_DecodeLocaleEx=Module["__Py_DecodeLocaleEx"]=wasmExports["_Py_DecodeLocaleEx"])(a0,a1,a2,a3,a4,a5);var _PyUnicode_DecodeLocale=Module["_PyUnicode_DecodeLocale"]=(a0,a1)=>(_PyUnicode_DecodeLocale=Module["_PyUnicode_DecodeLocale"]=wasmExports["PyUnicode_DecodeLocale"])(a0,a1);var _PyUnicode_DecodeFSDefaultAndSize=Module["_PyUnicode_DecodeFSDefaultAndSize"]=(a0,a1)=>(_PyUnicode_DecodeFSDefaultAndSize=Module["_PyUnicode_DecodeFSDefaultAndSize"]=wasmExports["PyUnicode_DecodeFSDefaultAndSize"])(a0,a1);var _PyUnicode_FSConverter=Module["_PyUnicode_FSConverter"]=(a0,a1)=>(_PyUnicode_FSConverter=Module["_PyUnicode_FSConverter"]=wasmExports["PyUnicode_FSConverter"])(a0,a1);var _PyOS_FSPath=Module["_PyOS_FSPath"]=a0=>(_PyOS_FSPath=Module["_PyOS_FSPath"]=wasmExports["PyOS_FSPath"])(a0);var _PyUnicode_FSDecoder=Module["_PyUnicode_FSDecoder"]=(a0,a1)=>(_PyUnicode_FSDecoder=Module["_PyUnicode_FSDecoder"]=wasmExports["PyUnicode_FSDecoder"])(a0,a1);var _wmemchr=Module["_wmemchr"]=(a0,a1,a2)=>(_wmemchr=Module["_wmemchr"]=wasmExports["wmemchr"])(a0,a1,a2);var _PyUnicode_GetSize=Module["_PyUnicode_GetSize"]=a0=>(_PyUnicode_GetSize=Module["_PyUnicode_GetSize"]=wasmExports["PyUnicode_GetSize"])(a0);var _PyUnicode_WriteChar=Module["_PyUnicode_WriteChar"]=(a0,a1,a2)=>(_PyUnicode_WriteChar=Module["_PyUnicode_WriteChar"]=wasmExports["PyUnicode_WriteChar"])(a0,a1,a2);var _PyUnicode_DecodeUTF7=Module["_PyUnicode_DecodeUTF7"]=(a0,a1,a2)=>(_PyUnicode_DecodeUTF7=Module["_PyUnicode_DecodeUTF7"]=wasmExports["PyUnicode_DecodeUTF7"])(a0,a1,a2);var _PyUnicode_DecodeUTF7Stateful=Module["_PyUnicode_DecodeUTF7Stateful"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeUTF7Stateful=Module["_PyUnicode_DecodeUTF7Stateful"]=wasmExports["PyUnicode_DecodeUTF7Stateful"])(a0,a1,a2,a3);var __PyUnicode_EncodeUTF7=Module["__PyUnicode_EncodeUTF7"]=(a0,a1,a2,a3)=>(__PyUnicode_EncodeUTF7=Module["__PyUnicode_EncodeUTF7"]=wasmExports["_PyUnicode_EncodeUTF7"])(a0,a1,a2,a3);var __Py_DecodeUTF8Ex=Module["__Py_DecodeUTF8Ex"]=(a0,a1,a2,a3,a4,a5)=>(__Py_DecodeUTF8Ex=Module["__Py_DecodeUTF8Ex"]=wasmExports["_Py_DecodeUTF8Ex"])(a0,a1,a2,a3,a4,a5);var __Py_DecodeUTF8_surrogateescape=Module["__Py_DecodeUTF8_surrogateescape"]=(a0,a1,a2)=>(__Py_DecodeUTF8_surrogateescape=Module["__Py_DecodeUTF8_surrogateescape"]=wasmExports["_Py_DecodeUTF8_surrogateescape"])(a0,a1,a2);var __Py_EncodeUTF8Ex=Module["__Py_EncodeUTF8Ex"]=(a0,a1,a2,a3,a4,a5)=>(__Py_EncodeUTF8Ex=Module["__Py_EncodeUTF8Ex"]=wasmExports["_Py_EncodeUTF8Ex"])(a0,a1,a2,a3,a4,a5);var _PyUnicode_AsUTF32String=Module["_PyUnicode_AsUTF32String"]=a0=>(_PyUnicode_AsUTF32String=Module["_PyUnicode_AsUTF32String"]=wasmExports["PyUnicode_AsUTF32String"])(a0);var _PyUnicode_AsUTF16String=Module["_PyUnicode_AsUTF16String"]=a0=>(_PyUnicode_AsUTF16String=Module["_PyUnicode_AsUTF16String"]=wasmExports["PyUnicode_AsUTF16String"])(a0);var __PyUnicode_DecodeUnicodeEscapeStateful=Module["__PyUnicode_DecodeUnicodeEscapeStateful"]=(a0,a1,a2,a3)=>(__PyUnicode_DecodeUnicodeEscapeStateful=Module["__PyUnicode_DecodeUnicodeEscapeStateful"]=wasmExports["_PyUnicode_DecodeUnicodeEscapeStateful"])(a0,a1,a2,a3);var _PyUnicode_DecodeUnicodeEscape=Module["_PyUnicode_DecodeUnicodeEscape"]=(a0,a1,a2)=>(_PyUnicode_DecodeUnicodeEscape=Module["_PyUnicode_DecodeUnicodeEscape"]=wasmExports["PyUnicode_DecodeUnicodeEscape"])(a0,a1,a2);var _PyUnicode_AsUnicodeEscapeString=Module["_PyUnicode_AsUnicodeEscapeString"]=a0=>(_PyUnicode_AsUnicodeEscapeString=Module["_PyUnicode_AsUnicodeEscapeString"]=wasmExports["PyUnicode_AsUnicodeEscapeString"])(a0);var __PyUnicode_DecodeRawUnicodeEscapeStateful=Module["__PyUnicode_DecodeRawUnicodeEscapeStateful"]=(a0,a1,a2,a3)=>(__PyUnicode_DecodeRawUnicodeEscapeStateful=Module["__PyUnicode_DecodeRawUnicodeEscapeStateful"]=wasmExports["_PyUnicode_DecodeRawUnicodeEscapeStateful"])(a0,a1,a2,a3);var _PyUnicode_DecodeRawUnicodeEscape=Module["_PyUnicode_DecodeRawUnicodeEscape"]=(a0,a1,a2)=>(_PyUnicode_DecodeRawUnicodeEscape=Module["_PyUnicode_DecodeRawUnicodeEscape"]=wasmExports["PyUnicode_DecodeRawUnicodeEscape"])(a0,a1,a2);var _PyUnicode_AsRawUnicodeEscapeString=Module["_PyUnicode_AsRawUnicodeEscapeString"]=a0=>(_PyUnicode_AsRawUnicodeEscapeString=Module["_PyUnicode_AsRawUnicodeEscapeString"]=wasmExports["PyUnicode_AsRawUnicodeEscapeString"])(a0);var _PyUnicode_AsLatin1String=Module["_PyUnicode_AsLatin1String"]=a0=>(_PyUnicode_AsLatin1String=Module["_PyUnicode_AsLatin1String"]=wasmExports["PyUnicode_AsLatin1String"])(a0);var __PyUnicodeWriter_PrepareKindInternal=Module["__PyUnicodeWriter_PrepareKindInternal"]=(a0,a1)=>(__PyUnicodeWriter_PrepareKindInternal=Module["__PyUnicodeWriter_PrepareKindInternal"]=wasmExports["_PyUnicodeWriter_PrepareKindInternal"])(a0,a1);var _PyUnicode_DecodeCharmap=Module["_PyUnicode_DecodeCharmap"]=(a0,a1,a2,a3)=>(_PyUnicode_DecodeCharmap=Module["_PyUnicode_DecodeCharmap"]=wasmExports["PyUnicode_DecodeCharmap"])(a0,a1,a2,a3);var _PyUnicode_BuildEncodingMap=Module["_PyUnicode_BuildEncodingMap"]=a0=>(_PyUnicode_BuildEncodingMap=Module["_PyUnicode_BuildEncodingMap"]=wasmExports["PyUnicode_BuildEncodingMap"])(a0);var __PyUnicode_EncodeCharmap=Module["__PyUnicode_EncodeCharmap"]=(a0,a1,a2)=>(__PyUnicode_EncodeCharmap=Module["__PyUnicode_EncodeCharmap"]=wasmExports["_PyUnicode_EncodeCharmap"])(a0,a1,a2);var _PyUnicode_AsCharmapString=Module["_PyUnicode_AsCharmapString"]=(a0,a1)=>(_PyUnicode_AsCharmapString=Module["_PyUnicode_AsCharmapString"]=wasmExports["PyUnicode_AsCharmapString"])(a0,a1);var _PyUnicode_Translate=Module["_PyUnicode_Translate"]=(a0,a1,a2)=>(_PyUnicode_Translate=Module["_PyUnicode_Translate"]=wasmExports["PyUnicode_Translate"])(a0,a1,a2);var __PyUnicode_IsWhitespace=Module["__PyUnicode_IsWhitespace"]=a0=>(__PyUnicode_IsWhitespace=Module["__PyUnicode_IsWhitespace"]=wasmExports["_PyUnicode_IsWhitespace"])(a0);var __PyUnicode_ToDecimalDigit=Module["__PyUnicode_ToDecimalDigit"]=a0=>(__PyUnicode_ToDecimalDigit=Module["__PyUnicode_ToDecimalDigit"]=wasmExports["_PyUnicode_ToDecimalDigit"])(a0);var __PyUnicode_InsertThousandsGrouping=Module["__PyUnicode_InsertThousandsGrouping"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(__PyUnicode_InsertThousandsGrouping=Module["__PyUnicode_InsertThousandsGrouping"]=wasmExports["_PyUnicode_InsertThousandsGrouping"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var _PyUnicode_Count=Module["_PyUnicode_Count"]=(a0,a1,a2,a3)=>(_PyUnicode_Count=Module["_PyUnicode_Count"]=wasmExports["PyUnicode_Count"])(a0,a1,a2,a3);var _PyUnicode_Find=Module["_PyUnicode_Find"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_Find=Module["_PyUnicode_Find"]=wasmExports["PyUnicode_Find"])(a0,a1,a2,a3,a4);var _PyUnicode_FindChar=Module["_PyUnicode_FindChar"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_FindChar=Module["_PyUnicode_FindChar"]=wasmExports["PyUnicode_FindChar"])(a0,a1,a2,a3,a4);var _PyUnicode_Tailmatch=Module["_PyUnicode_Tailmatch"]=(a0,a1,a2,a3,a4)=>(_PyUnicode_Tailmatch=Module["_PyUnicode_Tailmatch"]=wasmExports["PyUnicode_Tailmatch"])(a0,a1,a2,a3,a4);var __PyUnicode_JoinArray=Module["__PyUnicode_JoinArray"]=(a0,a1,a2)=>(__PyUnicode_JoinArray=Module["__PyUnicode_JoinArray"]=wasmExports["_PyUnicode_JoinArray"])(a0,a1,a2);var __PyUnicode_FastFill=Module["__PyUnicode_FastFill"]=(a0,a1,a2,a3)=>(__PyUnicode_FastFill=Module["__PyUnicode_FastFill"]=wasmExports["_PyUnicode_FastFill"])(a0,a1,a2,a3);var _PyUnicode_Splitlines=Module["_PyUnicode_Splitlines"]=(a0,a1)=>(_PyUnicode_Splitlines=Module["_PyUnicode_Splitlines"]=wasmExports["PyUnicode_Splitlines"])(a0,a1);var __PyUnicode_IsLinebreak=Module["__PyUnicode_IsLinebreak"]=a0=>(__PyUnicode_IsLinebreak=Module["__PyUnicode_IsLinebreak"]=wasmExports["_PyUnicode_IsLinebreak"])(a0);var _wmemcmp=Module["_wmemcmp"]=(a0,a1,a2)=>(_wmemcmp=Module["_wmemcmp"]=wasmExports["wmemcmp"])(a0,a1,a2);var __PyUnicode_EqualToASCIIId=Module["__PyUnicode_EqualToASCIIId"]=(a0,a1)=>(__PyUnicode_EqualToASCIIId=Module["__PyUnicode_EqualToASCIIId"]=wasmExports["_PyUnicode_EqualToASCIIId"])(a0,a1);var _PyUnicode_RichCompare=Module["_PyUnicode_RichCompare"]=(a0,a1,a2)=>(_PyUnicode_RichCompare=Module["_PyUnicode_RichCompare"]=wasmExports["PyUnicode_RichCompare"])(a0,a1,a2);var _PyUnicode_Contains=Module["_PyUnicode_Contains"]=(a0,a1)=>(_PyUnicode_Contains=Module["_PyUnicode_Contains"]=wasmExports["PyUnicode_Contains"])(a0,a1);var _PyUnicode_Concat=Module["_PyUnicode_Concat"]=(a0,a1)=>(_PyUnicode_Concat=Module["_PyUnicode_Concat"]=wasmExports["PyUnicode_Concat"])(a0,a1);var _PyUnicode_Append=Module["_PyUnicode_Append"]=(a0,a1)=>(_PyUnicode_Append=Module["_PyUnicode_Append"]=wasmExports["PyUnicode_Append"])(a0,a1);var _PyUnicode_AppendAndDel=Module["_PyUnicode_AppendAndDel"]=(a0,a1)=>(_PyUnicode_AppendAndDel=Module["_PyUnicode_AppendAndDel"]=wasmExports["PyUnicode_AppendAndDel"])(a0,a1);var __PyUnicode_IsXidStart=Module["__PyUnicode_IsXidStart"]=a0=>(__PyUnicode_IsXidStart=Module["__PyUnicode_IsXidStart"]=wasmExports["_PyUnicode_IsXidStart"])(a0);var __PyUnicode_IsXidContinue=Module["__PyUnicode_IsXidContinue"]=a0=>(__PyUnicode_IsXidContinue=Module["__PyUnicode_IsXidContinue"]=wasmExports["_PyUnicode_IsXidContinue"])(a0);var __PyUnicode_XStrip=Module["__PyUnicode_XStrip"]=(a0,a1,a2)=>(__PyUnicode_XStrip=Module["__PyUnicode_XStrip"]=wasmExports["_PyUnicode_XStrip"])(a0,a1,a2);var _PyUnicode_Replace=Module["_PyUnicode_Replace"]=(a0,a1,a2,a3)=>(_PyUnicode_Replace=Module["_PyUnicode_Replace"]=wasmExports["PyUnicode_Replace"])(a0,a1,a2,a3);var _PyUnicode_Split=Module["_PyUnicode_Split"]=(a0,a1,a2)=>(_PyUnicode_Split=Module["_PyUnicode_Split"]=wasmExports["PyUnicode_Split"])(a0,a1,a2);var _PyUnicode_Partition=Module["_PyUnicode_Partition"]=(a0,a1)=>(_PyUnicode_Partition=Module["_PyUnicode_Partition"]=wasmExports["PyUnicode_Partition"])(a0,a1);var _PyUnicode_RPartition=Module["_PyUnicode_RPartition"]=(a0,a1)=>(_PyUnicode_RPartition=Module["_PyUnicode_RPartition"]=wasmExports["PyUnicode_RPartition"])(a0,a1);var _PyUnicode_RSplit=Module["_PyUnicode_RSplit"]=(a0,a1,a2)=>(_PyUnicode_RSplit=Module["_PyUnicode_RSplit"]=wasmExports["PyUnicode_RSplit"])(a0,a1,a2);var __PyUnicodeWriter_WriteSubstring=Module["__PyUnicodeWriter_WriteSubstring"]=(a0,a1,a2,a3)=>(__PyUnicodeWriter_WriteSubstring=Module["__PyUnicodeWriter_WriteSubstring"]=wasmExports["_PyUnicodeWriter_WriteSubstring"])(a0,a1,a2,a3);var __PyUnicodeWriter_WriteLatin1String=Module["__PyUnicodeWriter_WriteLatin1String"]=(a0,a1,a2)=>(__PyUnicodeWriter_WriteLatin1String=Module["__PyUnicodeWriter_WriteLatin1String"]=wasmExports["_PyUnicodeWriter_WriteLatin1String"])(a0,a1,a2);var _PyUnicode_Format=Module["_PyUnicode_Format"]=(a0,a1)=>(_PyUnicode_Format=Module["_PyUnicode_Format"]=wasmExports["PyUnicode_Format"])(a0,a1);var __Py_hashtable_new_full=Module["__Py_hashtable_new_full"]=(a0,a1,a2,a3,a4)=>(__Py_hashtable_new_full=Module["__Py_hashtable_new_full"]=wasmExports["_Py_hashtable_new_full"])(a0,a1,a2,a3,a4);var __Py_hashtable_get=Module["__Py_hashtable_get"]=(a0,a1)=>(__Py_hashtable_get=Module["__Py_hashtable_get"]=wasmExports["_Py_hashtable_get"])(a0,a1);var __Py_hashtable_set=Module["__Py_hashtable_set"]=(a0,a1,a2)=>(__Py_hashtable_set=Module["__Py_hashtable_set"]=wasmExports["_Py_hashtable_set"])(a0,a1,a2);var __PyUnicode_InternInPlace=Module["__PyUnicode_InternInPlace"]=(a0,a1)=>(__PyUnicode_InternInPlace=Module["__PyUnicode_InternInPlace"]=wasmExports["_PyUnicode_InternInPlace"])(a0,a1);var _PyUnicode_InternInPlace=Module["_PyUnicode_InternInPlace"]=a0=>(_PyUnicode_InternInPlace=Module["_PyUnicode_InternInPlace"]=wasmExports["PyUnicode_InternInPlace"])(a0);var _PyUnicode_InternImmortal=Module["_PyUnicode_InternImmortal"]=a0=>(_PyUnicode_InternImmortal=Module["_PyUnicode_InternImmortal"]=wasmExports["PyUnicode_InternImmortal"])(a0);var __Py_hashtable_destroy=Module["__Py_hashtable_destroy"]=a0=>(__Py_hashtable_destroy=Module["__Py_hashtable_destroy"]=wasmExports["_Py_hashtable_destroy"])(a0);var _PyInit__string=Module["_PyInit__string"]=()=>(_PyInit__string=Module["_PyInit__string"]=wasmExports["PyInit__string"])();var __PyUnicode_IsLowercase=Module["__PyUnicode_IsLowercase"]=a0=>(__PyUnicode_IsLowercase=Module["__PyUnicode_IsLowercase"]=wasmExports["_PyUnicode_IsLowercase"])(a0);var __PyUnicode_IsUppercase=Module["__PyUnicode_IsUppercase"]=a0=>(__PyUnicode_IsUppercase=Module["__PyUnicode_IsUppercase"]=wasmExports["_PyUnicode_IsUppercase"])(a0);var __PyUnicode_IsTitlecase=Module["__PyUnicode_IsTitlecase"]=a0=>(__PyUnicode_IsTitlecase=Module["__PyUnicode_IsTitlecase"]=wasmExports["_PyUnicode_IsTitlecase"])(a0);var __PyUnicode_IsDecimalDigit=Module["__PyUnicode_IsDecimalDigit"]=a0=>(__PyUnicode_IsDecimalDigit=Module["__PyUnicode_IsDecimalDigit"]=wasmExports["_PyUnicode_IsDecimalDigit"])(a0);var __PyUnicode_IsDigit=Module["__PyUnicode_IsDigit"]=a0=>(__PyUnicode_IsDigit=Module["__PyUnicode_IsDigit"]=wasmExports["_PyUnicode_IsDigit"])(a0);var __PyUnicode_IsNumeric=Module["__PyUnicode_IsNumeric"]=a0=>(__PyUnicode_IsNumeric=Module["__PyUnicode_IsNumeric"]=wasmExports["_PyUnicode_IsNumeric"])(a0);var __PyUnicode_IsAlpha=Module["__PyUnicode_IsAlpha"]=a0=>(__PyUnicode_IsAlpha=Module["__PyUnicode_IsAlpha"]=wasmExports["_PyUnicode_IsAlpha"])(a0);var __PyUnicode_FormatAdvancedWriter=Module["__PyUnicode_FormatAdvancedWriter"]=(a0,a1,a2,a3,a4)=>(__PyUnicode_FormatAdvancedWriter=Module["__PyUnicode_FormatAdvancedWriter"]=wasmExports["_PyUnicode_FormatAdvancedWriter"])(a0,a1,a2,a3,a4);var __PyUnicode_ToTitleFull=Module["__PyUnicode_ToTitleFull"]=(a0,a1)=>(__PyUnicode_ToTitleFull=Module["__PyUnicode_ToTitleFull"]=wasmExports["_PyUnicode_ToTitleFull"])(a0,a1);var __PyUnicode_IsCaseIgnorable=Module["__PyUnicode_IsCaseIgnorable"]=a0=>(__PyUnicode_IsCaseIgnorable=Module["__PyUnicode_IsCaseIgnorable"]=wasmExports["_PyUnicode_IsCaseIgnorable"])(a0);var __PyUnicode_IsCased=Module["__PyUnicode_IsCased"]=a0=>(__PyUnicode_IsCased=Module["__PyUnicode_IsCased"]=wasmExports["_PyUnicode_IsCased"])(a0);var __PyUnicode_ToLowerFull=Module["__PyUnicode_ToLowerFull"]=(a0,a1)=>(__PyUnicode_ToLowerFull=Module["__PyUnicode_ToLowerFull"]=wasmExports["_PyUnicode_ToLowerFull"])(a0,a1);var __PyUnicode_ToFoldedFull=Module["__PyUnicode_ToFoldedFull"]=(a0,a1)=>(__PyUnicode_ToFoldedFull=Module["__PyUnicode_ToFoldedFull"]=wasmExports["_PyUnicode_ToFoldedFull"])(a0,a1);var __PyUnicode_ToUpperFull=Module["__PyUnicode_ToUpperFull"]=(a0,a1)=>(__PyUnicode_ToUpperFull=Module["__PyUnicode_ToUpperFull"]=wasmExports["_PyUnicode_ToUpperFull"])(a0,a1);var __PyUnicode_ToNumeric=Module["__PyUnicode_ToNumeric"]=a0=>(__PyUnicode_ToNumeric=Module["__PyUnicode_ToNumeric"]=wasmExports["_PyUnicode_ToNumeric"])(a0);var __PyUnicode_ToTitlecase=Module["__PyUnicode_ToTitlecase"]=a0=>(__PyUnicode_ToTitlecase=Module["__PyUnicode_ToTitlecase"]=wasmExports["_PyUnicode_ToTitlecase"])(a0);var __PyUnicode_ToDigit=Module["__PyUnicode_ToDigit"]=a0=>(__PyUnicode_ToDigit=Module["__PyUnicode_ToDigit"]=wasmExports["_PyUnicode_ToDigit"])(a0);var __PyUnicode_ToUppercase=Module["__PyUnicode_ToUppercase"]=a0=>(__PyUnicode_ToUppercase=Module["__PyUnicode_ToUppercase"]=wasmExports["_PyUnicode_ToUppercase"])(a0);var __PyUnicode_ToLowercase=Module["__PyUnicode_ToLowercase"]=a0=>(__PyUnicode_ToLowercase=Module["__PyUnicode_ToLowercase"]=wasmExports["_PyUnicode_ToLowercase"])(a0);var __PyWeakref_GetWeakrefCount=Module["__PyWeakref_GetWeakrefCount"]=a0=>(__PyWeakref_GetWeakrefCount=Module["__PyWeakref_GetWeakrefCount"]=wasmExports["_PyWeakref_GetWeakrefCount"])(a0);var _PyWeakref_NewProxy=Module["_PyWeakref_NewProxy"]=(a0,a1)=>(_PyWeakref_NewProxy=Module["_PyWeakref_NewProxy"]=wasmExports["PyWeakref_NewProxy"])(a0,a1);var _PyWeakref_GetObject=Module["_PyWeakref_GetObject"]=a0=>(_PyWeakref_GetObject=Module["_PyWeakref_GetObject"]=wasmExports["PyWeakref_GetObject"])(a0);var _PyErr_ResourceWarning=Module["_PyErr_ResourceWarning"]=(a0,a1,a2,a3)=>(_PyErr_ResourceWarning=Module["_PyErr_ResourceWarning"]=wasmExports["PyErr_ResourceWarning"])(a0,a1,a2,a3);var _PyErr_WarnExplicit=Module["_PyErr_WarnExplicit"]=(a0,a1,a2,a3,a4,a5)=>(_PyErr_WarnExplicit=Module["_PyErr_WarnExplicit"]=wasmExports["PyErr_WarnExplicit"])(a0,a1,a2,a3,a4,a5);var _PyErr_WarnExplicitFormat=Module["_PyErr_WarnExplicitFormat"]=(a0,a1,a2,a3,a4,a5,a6)=>(_PyErr_WarnExplicitFormat=Module["_PyErr_WarnExplicitFormat"]=wasmExports["PyErr_WarnExplicitFormat"])(a0,a1,a2,a3,a4,a5,a6);var __Py_IsInterpreterFinalizing=Module["__Py_IsInterpreterFinalizing"]=a0=>(__Py_IsInterpreterFinalizing=Module["__Py_IsInterpreterFinalizing"]=wasmExports["_Py_IsInterpreterFinalizing"])(a0);var __PyWarnings_Init=Module["__PyWarnings_Init"]=()=>(__PyWarnings_Init=Module["__PyWarnings_Init"]=wasmExports["_PyWarnings_Init"])();var _PyThreadState_GetFrame=Module["_PyThreadState_GetFrame"]=a0=>(_PyThreadState_GetFrame=Module["_PyThreadState_GetFrame"]=wasmExports["PyThreadState_GetFrame"])(a0);var __PySys_GetAttr=Module["__PySys_GetAttr"]=(a0,a1)=>(__PySys_GetAttr=Module["__PySys_GetAttr"]=wasmExports["_PySys_GetAttr"])(a0,a1);var __Py_DisplaySourceLine=Module["__Py_DisplaySourceLine"]=(a0,a1,a2,a3,a4,a5)=>(__Py_DisplaySourceLine=Module["__Py_DisplaySourceLine"]=wasmExports["_Py_DisplaySourceLine"])(a0,a1,a2,a3,a4,a5);var _PyModule_AddObjectRef=Module["_PyModule_AddObjectRef"]=(a0,a1,a2)=>(_PyModule_AddObjectRef=Module["_PyModule_AddObjectRef"]=wasmExports["PyModule_AddObjectRef"])(a0,a1,a2);var _PyInit__ast=Module["_PyInit__ast"]=()=>(_PyInit__ast=Module["_PyInit__ast"]=wasmExports["PyInit__ast"])();var _PyModule_AddIntConstant=Module["_PyModule_AddIntConstant"]=(a0,a1,a2)=>(_PyModule_AddIntConstant=Module["_PyModule_AddIntConstant"]=wasmExports["PyModule_AddIntConstant"])(a0,a1,a2);var _PyInit__tokenize=Module["_PyInit__tokenize"]=()=>(_PyInit__tokenize=Module["_PyInit__tokenize"]=wasmExports["PyInit__tokenize"])();var _PyModule_AddType=Module["_PyModule_AddType"]=(a0,a1)=>(_PyModule_AddType=Module["_PyModule_AddType"]=wasmExports["PyModule_AddType"])(a0,a1);var _PyErr_SyntaxLocationObject=Module["_PyErr_SyntaxLocationObject"]=(a0,a1,a2)=>(_PyErr_SyntaxLocationObject=Module["_PyErr_SyntaxLocationObject"]=wasmExports["PyErr_SyntaxLocationObject"])(a0,a1,a2);var _snprintf=Module["_snprintf"]=(a0,a1,a2,a3)=>(_snprintf=Module["_snprintf"]=wasmExports["snprintf"])(a0,a1,a2,a3);var _PyImport_ImportModuleLevelObject=Module["_PyImport_ImportModuleLevelObject"]=(a0,a1,a2,a3,a4)=>(_PyImport_ImportModuleLevelObject=Module["_PyImport_ImportModuleLevelObject"]=wasmExports["PyImport_ImportModuleLevelObject"])(a0,a1,a2,a3,a4);var _PyEval_MergeCompilerFlags=Module["_PyEval_MergeCompilerFlags"]=a0=>(_PyEval_MergeCompilerFlags=Module["_PyEval_MergeCompilerFlags"]=wasmExports["PyEval_MergeCompilerFlags"])(a0);var __PyArena_New=Module["__PyArena_New"]=()=>(__PyArena_New=Module["__PyArena_New"]=wasmExports["_PyArena_New"])();var __PyArena_Free=Module["__PyArena_Free"]=a0=>(__PyArena_Free=Module["__PyArena_Free"]=wasmExports["_PyArena_Free"])(a0);var __PyAST_Compile=Module["__PyAST_Compile"]=(a0,a1,a2,a3,a4)=>(__PyAST_Compile=Module["__PyAST_Compile"]=wasmExports["_PyAST_Compile"])(a0,a1,a2,a3,a4);var __Py_SourceAsString=Module["__Py_SourceAsString"]=(a0,a1,a2,a3,a4)=>(__Py_SourceAsString=Module["__Py_SourceAsString"]=wasmExports["_Py_SourceAsString"])(a0,a1,a2,a3,a4);var _Py_CompileStringObject=Module["_Py_CompileStringObject"]=(a0,a1,a2,a3,a4)=>(_Py_CompileStringObject=Module["_Py_CompileStringObject"]=wasmExports["Py_CompileStringObject"])(a0,a1,a2,a3,a4);var _PyEval_GetBuiltins=Module["_PyEval_GetBuiltins"]=()=>(_PyEval_GetBuiltins=Module["_PyEval_GetBuiltins"]=wasmExports["PyEval_GetBuiltins"])();var _PyEval_EvalCode=Module["_PyEval_EvalCode"]=(a0,a1,a2)=>(_PyEval_EvalCode=Module["_PyEval_EvalCode"]=wasmExports["PyEval_EvalCode"])(a0,a1,a2);var _PyRun_StringFlags=Module["_PyRun_StringFlags"]=(a0,a1,a2,a3,a4)=>(_PyRun_StringFlags=Module["_PyRun_StringFlags"]=wasmExports["PyRun_StringFlags"])(a0,a1,a2,a3,a4);var _PyEval_EvalCodeEx=Module["_PyEval_EvalCodeEx"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)=>(_PyEval_EvalCodeEx=Module["_PyEval_EvalCodeEx"]=wasmExports["PyEval_EvalCodeEx"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);var _Py_GetRecursionLimit=Module["_Py_GetRecursionLimit"]=()=>(_Py_GetRecursionLimit=Module["_Py_GetRecursionLimit"]=wasmExports["Py_GetRecursionLimit"])();var _Py_SetRecursionLimit=Module["_Py_SetRecursionLimit"]=a0=>(_Py_SetRecursionLimit=Module["_Py_SetRecursionLimit"]=wasmExports["Py_SetRecursionLimit"])(a0);var _PyEval_EvalFrame=Module["_PyEval_EvalFrame"]=a0=>(_PyEval_EvalFrame=Module["_PyEval_EvalFrame"]=wasmExports["PyEval_EvalFrame"])(a0);var _PyEval_EvalFrameEx=Module["_PyEval_EvalFrameEx"]=(a0,a1)=>(_PyEval_EvalFrameEx=Module["_PyEval_EvalFrameEx"]=wasmExports["PyEval_EvalFrameEx"])(a0,a1);var _PyTraceBack_Here=Module["_PyTraceBack_Here"]=a0=>(_PyTraceBack_Here=Module["_PyTraceBack_Here"]=wasmExports["PyTraceBack_Here"])(a0);var _PyErr_SetHandledException=Module["_PyErr_SetHandledException"]=a0=>(_PyErr_SetHandledException=Module["_PyErr_SetHandledException"]=wasmExports["PyErr_SetHandledException"])(a0);var __PyErr_GetTopmostException=Module["__PyErr_GetTopmostException"]=a0=>(__PyErr_GetTopmostException=Module["__PyErr_GetTopmostException"]=wasmExports["_PyErr_GetTopmostException"])(a0);var __PyErr_SetObject=Module["__PyErr_SetObject"]=(a0,a1,a2)=>(__PyErr_SetObject=Module["__PyErr_SetObject"]=wasmExports["_PyErr_SetObject"])(a0,a1,a2);var _PyThreadState_EnterTracing=Module["_PyThreadState_EnterTracing"]=a0=>(_PyThreadState_EnterTracing=Module["_PyThreadState_EnterTracing"]=wasmExports["PyThreadState_EnterTracing"])(a0);var _PyThreadState_LeaveTracing=Module["_PyThreadState_LeaveTracing"]=a0=>(_PyThreadState_LeaveTracing=Module["_PyThreadState_LeaveTracing"]=wasmExports["PyThreadState_LeaveTracing"])(a0);var _PyEval_SetProfile=Module["_PyEval_SetProfile"]=(a0,a1)=>(_PyEval_SetProfile=Module["_PyEval_SetProfile"]=wasmExports["PyEval_SetProfile"])(a0,a1);var __PyEval_SetProfile=Module["__PyEval_SetProfile"]=(a0,a1,a2)=>(__PyEval_SetProfile=Module["__PyEval_SetProfile"]=wasmExports["_PyEval_SetProfile"])(a0,a1,a2);var __PyErr_WriteUnraisableMsg=Module["__PyErr_WriteUnraisableMsg"]=(a0,a1)=>(__PyErr_WriteUnraisableMsg=Module["__PyErr_WriteUnraisableMsg"]=wasmExports["_PyErr_WriteUnraisableMsg"])(a0,a1);var _PyEval_SetProfileAllThreads=Module["_PyEval_SetProfileAllThreads"]=(a0,a1)=>(_PyEval_SetProfileAllThreads=Module["_PyEval_SetProfileAllThreads"]=wasmExports["PyEval_SetProfileAllThreads"])(a0,a1);var _PyInterpreterState_ThreadHead=Module["_PyInterpreterState_ThreadHead"]=a0=>(_PyInterpreterState_ThreadHead=Module["_PyInterpreterState_ThreadHead"]=wasmExports["PyInterpreterState_ThreadHead"])(a0);var _PyThreadState_Next=Module["_PyThreadState_Next"]=a0=>(_PyThreadState_Next=Module["_PyThreadState_Next"]=wasmExports["PyThreadState_Next"])(a0);var _PyEval_SetTrace=Module["_PyEval_SetTrace"]=(a0,a1)=>(_PyEval_SetTrace=Module["_PyEval_SetTrace"]=wasmExports["PyEval_SetTrace"])(a0,a1);var __PyEval_SetTrace=Module["__PyEval_SetTrace"]=(a0,a1,a2)=>(__PyEval_SetTrace=Module["__PyEval_SetTrace"]=wasmExports["_PyEval_SetTrace"])(a0,a1,a2);var _PyEval_SetTraceAllThreads=Module["_PyEval_SetTraceAllThreads"]=(a0,a1)=>(_PyEval_SetTraceAllThreads=Module["_PyEval_SetTraceAllThreads"]=wasmExports["PyEval_SetTraceAllThreads"])(a0,a1);var _PyEval_GetFrame=Module["_PyEval_GetFrame"]=()=>(_PyEval_GetFrame=Module["_PyEval_GetFrame"]=wasmExports["PyEval_GetFrame"])();var __PyEval_GetBuiltinId=Module["__PyEval_GetBuiltinId"]=a0=>(__PyEval_GetBuiltinId=Module["__PyEval_GetBuiltinId"]=wasmExports["_PyEval_GetBuiltinId"])(a0);var _PyEval_GetLocals=Module["_PyEval_GetLocals"]=()=>(_PyEval_GetLocals=Module["_PyEval_GetLocals"]=wasmExports["PyEval_GetLocals"])();var _PyEval_GetFuncName=Module["_PyEval_GetFuncName"]=a0=>(_PyEval_GetFuncName=Module["_PyEval_GetFuncName"]=wasmExports["PyEval_GetFuncName"])(a0);var _PyEval_GetFuncDesc=Module["_PyEval_GetFuncDesc"]=a0=>(_PyEval_GetFuncDesc=Module["_PyEval_GetFuncDesc"]=wasmExports["PyEval_GetFuncDesc"])(a0);var _PyUnstable_Eval_RequestCodeExtraIndex=Module["_PyUnstable_Eval_RequestCodeExtraIndex"]=a0=>(_PyUnstable_Eval_RequestCodeExtraIndex=Module["_PyUnstable_Eval_RequestCodeExtraIndex"]=wasmExports["PyUnstable_Eval_RequestCodeExtraIndex"])(a0);var _PyCodec_Register=Module["_PyCodec_Register"]=a0=>(_PyCodec_Register=Module["_PyCodec_Register"]=wasmExports["PyCodec_Register"])(a0);var _PyCodec_Unregister=Module["_PyCodec_Unregister"]=a0=>(_PyCodec_Unregister=Module["_PyCodec_Unregister"]=wasmExports["PyCodec_Unregister"])(a0);var _PyCodec_KnownEncoding=Module["_PyCodec_KnownEncoding"]=a0=>(_PyCodec_KnownEncoding=Module["_PyCodec_KnownEncoding"]=wasmExports["PyCodec_KnownEncoding"])(a0);var __PyCodecInfo_GetIncrementalDecoder=Module["__PyCodecInfo_GetIncrementalDecoder"]=(a0,a1)=>(__PyCodecInfo_GetIncrementalDecoder=Module["__PyCodecInfo_GetIncrementalDecoder"]=wasmExports["_PyCodecInfo_GetIncrementalDecoder"])(a0,a1);var __PyCodecInfo_GetIncrementalEncoder=Module["__PyCodecInfo_GetIncrementalEncoder"]=(a0,a1)=>(__PyCodecInfo_GetIncrementalEncoder=Module["__PyCodecInfo_GetIncrementalEncoder"]=wasmExports["_PyCodecInfo_GetIncrementalEncoder"])(a0,a1);var _PyCodec_Encoder=Module["_PyCodec_Encoder"]=a0=>(_PyCodec_Encoder=Module["_PyCodec_Encoder"]=wasmExports["PyCodec_Encoder"])(a0);var _PyCodec_Decoder=Module["_PyCodec_Decoder"]=a0=>(_PyCodec_Decoder=Module["_PyCodec_Decoder"]=wasmExports["PyCodec_Decoder"])(a0);var _PyCodec_IncrementalEncoder=Module["_PyCodec_IncrementalEncoder"]=(a0,a1)=>(_PyCodec_IncrementalEncoder=Module["_PyCodec_IncrementalEncoder"]=wasmExports["PyCodec_IncrementalEncoder"])(a0,a1);var _PyCodec_IncrementalDecoder=Module["_PyCodec_IncrementalDecoder"]=(a0,a1)=>(_PyCodec_IncrementalDecoder=Module["_PyCodec_IncrementalDecoder"]=wasmExports["PyCodec_IncrementalDecoder"])(a0,a1);var _PyCodec_StreamReader=Module["_PyCodec_StreamReader"]=(a0,a1,a2)=>(_PyCodec_StreamReader=Module["_PyCodec_StreamReader"]=wasmExports["PyCodec_StreamReader"])(a0,a1,a2);var _PyCodec_StreamWriter=Module["_PyCodec_StreamWriter"]=(a0,a1,a2)=>(_PyCodec_StreamWriter=Module["_PyCodec_StreamWriter"]=wasmExports["PyCodec_StreamWriter"])(a0,a1,a2);var __PyCodec_LookupTextEncoding=Module["__PyCodec_LookupTextEncoding"]=(a0,a1)=>(__PyCodec_LookupTextEncoding=Module["__PyCodec_LookupTextEncoding"]=wasmExports["_PyCodec_LookupTextEncoding"])(a0,a1);var _PyCodec_RegisterError=Module["_PyCodec_RegisterError"]=(a0,a1)=>(_PyCodec_RegisterError=Module["_PyCodec_RegisterError"]=wasmExports["PyCodec_RegisterError"])(a0,a1);var _PyCodec_IgnoreErrors=Module["_PyCodec_IgnoreErrors"]=a0=>(_PyCodec_IgnoreErrors=Module["_PyCodec_IgnoreErrors"]=wasmExports["PyCodec_IgnoreErrors"])(a0);var _PyCodec_ReplaceErrors=Module["_PyCodec_ReplaceErrors"]=a0=>(_PyCodec_ReplaceErrors=Module["_PyCodec_ReplaceErrors"]=wasmExports["PyCodec_ReplaceErrors"])(a0);var _PyCodec_XMLCharRefReplaceErrors=Module["_PyCodec_XMLCharRefReplaceErrors"]=a0=>(_PyCodec_XMLCharRefReplaceErrors=Module["_PyCodec_XMLCharRefReplaceErrors"]=wasmExports["PyCodec_XMLCharRefReplaceErrors"])(a0);var _PyCodec_BackslashReplaceErrors=Module["_PyCodec_BackslashReplaceErrors"]=a0=>(_PyCodec_BackslashReplaceErrors=Module["_PyCodec_BackslashReplaceErrors"]=wasmExports["PyCodec_BackslashReplaceErrors"])(a0);var _PyCodec_NameReplaceErrors=Module["_PyCodec_NameReplaceErrors"]=a0=>(_PyCodec_NameReplaceErrors=Module["_PyCodec_NameReplaceErrors"]=wasmExports["PyCodec_NameReplaceErrors"])(a0);var _PyCompile_OpcodeStackEffectWithJump=Module["_PyCompile_OpcodeStackEffectWithJump"]=(a0,a1,a2)=>(_PyCompile_OpcodeStackEffectWithJump=Module["_PyCompile_OpcodeStackEffectWithJump"]=wasmExports["PyCompile_OpcodeStackEffectWithJump"])(a0,a1,a2);var __PyCompile_CodeGen=Module["__PyCompile_CodeGen"]=(a0,a1,a2,a3,a4)=>(__PyCompile_CodeGen=Module["__PyCompile_CodeGen"]=wasmExports["_PyCompile_CodeGen"])(a0,a1,a2,a3,a4);var __PyCompile_OptimizeCfg=Module["__PyCompile_OptimizeCfg"]=(a0,a1,a2)=>(__PyCompile_OptimizeCfg=Module["__PyCompile_OptimizeCfg"]=wasmExports["_PyCompile_OptimizeCfg"])(a0,a1,a2);var __PyCompile_Assemble=Module["__PyCompile_Assemble"]=(a0,a1,a2)=>(__PyCompile_Assemble=Module["__PyCompile_Assemble"]=wasmExports["_PyCompile_Assemble"])(a0,a1,a2);var _PyCode_Optimize=Module["_PyCode_Optimize"]=(a0,a1,a2,a3)=>(_PyCode_Optimize=Module["_PyCode_Optimize"]=wasmExports["PyCode_Optimize"])(a0,a1,a2,a3);var _PySymtable_Lookup=Module["_PySymtable_Lookup"]=(a0,a1)=>(_PySymtable_Lookup=Module["_PySymtable_Lookup"]=wasmExports["PySymtable_Lookup"])(a0,a1);var _PyErr_ProgramTextObject=Module["_PyErr_ProgramTextObject"]=(a0,a1)=>(_PyErr_ProgramTextObject=Module["_PyErr_ProgramTextObject"]=wasmExports["PyErr_ProgramTextObject"])(a0,a1);var __PyContext_NewHamtForTests=Module["__PyContext_NewHamtForTests"]=()=>(__PyContext_NewHamtForTests=Module["__PyContext_NewHamtForTests"]=wasmExports["_PyContext_NewHamtForTests"])();var _PyContext_New=Module["_PyContext_New"]=()=>(_PyContext_New=Module["_PyContext_New"]=wasmExports["PyContext_New"])();var _PyContext_Copy=Module["_PyContext_Copy"]=a0=>(_PyContext_Copy=Module["_PyContext_Copy"]=wasmExports["PyContext_Copy"])(a0);var _PyContext_CopyCurrent=Module["_PyContext_CopyCurrent"]=()=>(_PyContext_CopyCurrent=Module["_PyContext_CopyCurrent"]=wasmExports["PyContext_CopyCurrent"])();var _PyContext_Enter=Module["_PyContext_Enter"]=a0=>(_PyContext_Enter=Module["_PyContext_Enter"]=wasmExports["PyContext_Enter"])(a0);var _PyContext_Exit=Module["_PyContext_Exit"]=a0=>(_PyContext_Exit=Module["_PyContext_Exit"]=wasmExports["PyContext_Exit"])(a0);var _PyContextVar_New=Module["_PyContextVar_New"]=(a0,a1)=>(_PyContextVar_New=Module["_PyContextVar_New"]=wasmExports["PyContextVar_New"])(a0,a1);var _PyContextVar_Get=Module["_PyContextVar_Get"]=(a0,a1,a2)=>(_PyContextVar_Get=Module["_PyContextVar_Get"]=wasmExports["PyContextVar_Get"])(a0,a1,a2);var _PyContextVar_Set=Module["_PyContextVar_Set"]=(a0,a1)=>(_PyContextVar_Set=Module["_PyContextVar_Set"]=wasmExports["PyContextVar_Set"])(a0,a1);var _PyContextVar_Reset=Module["_PyContextVar_Reset"]=(a0,a1)=>(_PyContextVar_Reset=Module["_PyContextVar_Reset"]=wasmExports["PyContextVar_Reset"])(a0,a1);var __PyErr_Restore=Module["__PyErr_Restore"]=(a0,a1,a2,a3)=>(__PyErr_Restore=Module["__PyErr_Restore"]=wasmExports["_PyErr_Restore"])(a0,a1,a2,a3);var __PyErr_SetNone=Module["__PyErr_SetNone"]=(a0,a1)=>(__PyErr_SetNone=Module["__PyErr_SetNone"]=wasmExports["_PyErr_SetNone"])(a0,a1);var __PyErr_NormalizeException=Module["__PyErr_NormalizeException"]=(a0,a1,a2,a3)=>(__PyErr_NormalizeException=Module["__PyErr_NormalizeException"]=wasmExports["_PyErr_NormalizeException"])(a0,a1,a2,a3);var __PyErr_Fetch=Module["__PyErr_Fetch"]=(a0,a1,a2,a3)=>(__PyErr_Fetch=Module["__PyErr_Fetch"]=wasmExports["_PyErr_Fetch"])(a0,a1,a2,a3);var __PyErr_GetExcInfo=Module["__PyErr_GetExcInfo"]=(a0,a1,a2,a3)=>(__PyErr_GetExcInfo=Module["__PyErr_GetExcInfo"]=wasmExports["_PyErr_GetExcInfo"])(a0,a1,a2,a3);var __PyErr_GetHandledException=Module["__PyErr_GetHandledException"]=a0=>(__PyErr_GetHandledException=Module["__PyErr_GetHandledException"]=wasmExports["_PyErr_GetHandledException"])(a0);var _PyErr_GetHandledException=Module["_PyErr_GetHandledException"]=()=>(_PyErr_GetHandledException=Module["_PyErr_GetHandledException"]=wasmExports["PyErr_GetHandledException"])();var __PyErr_SetHandledException=Module["__PyErr_SetHandledException"]=(a0,a1)=>(__PyErr_SetHandledException=Module["__PyErr_SetHandledException"]=wasmExports["_PyErr_SetHandledException"])(a0,a1);var _PyErr_GetExcInfo=Module["_PyErr_GetExcInfo"]=(a0,a1,a2)=>(_PyErr_GetExcInfo=Module["_PyErr_GetExcInfo"]=wasmExports["PyErr_GetExcInfo"])(a0,a1,a2);var _PyErr_SetExcInfo=Module["_PyErr_SetExcInfo"]=(a0,a1,a2)=>(_PyErr_SetExcInfo=Module["_PyErr_SetExcInfo"]=wasmExports["PyErr_SetExcInfo"])(a0,a1,a2);var __PyErr_StackItemToExcInfoTuple=Module["__PyErr_StackItemToExcInfoTuple"]=a0=>(__PyErr_StackItemToExcInfoTuple=Module["__PyErr_StackItemToExcInfoTuple"]=wasmExports["_PyErr_StackItemToExcInfoTuple"])(a0);var __PyErr_ChainExceptions=Module["__PyErr_ChainExceptions"]=(a0,a1,a2)=>(__PyErr_ChainExceptions=Module["__PyErr_ChainExceptions"]=wasmExports["_PyErr_ChainExceptions"])(a0,a1,a2);var _PyErr_SetFromErrnoWithFilenameObject=Module["_PyErr_SetFromErrnoWithFilenameObject"]=(a0,a1)=>(_PyErr_SetFromErrnoWithFilenameObject=Module["_PyErr_SetFromErrnoWithFilenameObject"]=wasmExports["PyErr_SetFromErrnoWithFilenameObject"])(a0,a1);var _PyErr_SetFromErrnoWithFilenameObjects=Module["_PyErr_SetFromErrnoWithFilenameObjects"]=(a0,a1,a2)=>(_PyErr_SetFromErrnoWithFilenameObjects=Module["_PyErr_SetFromErrnoWithFilenameObjects"]=wasmExports["PyErr_SetFromErrnoWithFilenameObjects"])(a0,a1,a2);var _strerror=Module["_strerror"]=a0=>(_strerror=Module["_strerror"]=wasmExports["strerror"])(a0);var _PyErr_SetImportErrorSubclass=Module["_PyErr_SetImportErrorSubclass"]=(a0,a1,a2,a3)=>(_PyErr_SetImportErrorSubclass=Module["_PyErr_SetImportErrorSubclass"]=wasmExports["PyErr_SetImportErrorSubclass"])(a0,a1,a2,a3);var _PyErr_SetImportError=Module["_PyErr_SetImportError"]=(a0,a1,a2)=>(_PyErr_SetImportError=Module["_PyErr_SetImportError"]=wasmExports["PyErr_SetImportError"])(a0,a1,a2);var _PyErr_BadInternalCall=Module["_PyErr_BadInternalCall"]=()=>(_PyErr_BadInternalCall=Module["_PyErr_BadInternalCall"]=wasmExports["PyErr_BadInternalCall"])();var _PyErr_FormatV=Module["_PyErr_FormatV"]=(a0,a1,a2)=>(_PyErr_FormatV=Module["_PyErr_FormatV"]=wasmExports["PyErr_FormatV"])(a0,a1,a2);var _PyErr_NewExceptionWithDoc=Module["_PyErr_NewExceptionWithDoc"]=(a0,a1,a2,a3)=>(_PyErr_NewExceptionWithDoc=Module["_PyErr_NewExceptionWithDoc"]=wasmExports["PyErr_NewExceptionWithDoc"])(a0,a1,a2,a3);var _PyTraceBack_Print=Module["_PyTraceBack_Print"]=(a0,a1)=>(_PyTraceBack_Print=Module["_PyTraceBack_Print"]=wasmExports["PyTraceBack_Print"])(a0,a1);var __PyTraceBack_FromFrame=Module["__PyTraceBack_FromFrame"]=(a0,a1)=>(__PyTraceBack_FromFrame=Module["__PyTraceBack_FromFrame"]=wasmExports["_PyTraceBack_FromFrame"])(a0,a1);var _PyErr_SyntaxLocation=Module["_PyErr_SyntaxLocation"]=(a0,a1)=>(_PyErr_SyntaxLocation=Module["_PyErr_SyntaxLocation"]=wasmExports["PyErr_SyntaxLocation"])(a0,a1);var _PyErr_SyntaxLocationEx=Module["_PyErr_SyntaxLocationEx"]=(a0,a1,a2)=>(_PyErr_SyntaxLocationEx=Module["_PyErr_SyntaxLocationEx"]=wasmExports["PyErr_SyntaxLocationEx"])(a0,a1,a2);var _PyErr_RangedSyntaxLocationObject=Module["_PyErr_RangedSyntaxLocationObject"]=(a0,a1,a2,a3,a4)=>(_PyErr_RangedSyntaxLocationObject=Module["_PyErr_RangedSyntaxLocationObject"]=wasmExports["PyErr_RangedSyntaxLocationObject"])(a0,a1,a2,a3,a4);var _PyErr_ProgramText=Module["_PyErr_ProgramText"]=(a0,a1)=>(_PyErr_ProgramText=Module["_PyErr_ProgramText"]=wasmExports["PyErr_ProgramText"])(a0,a1);var __Py_fopen_obj=Module["__Py_fopen_obj"]=(a0,a1)=>(__Py_fopen_obj=Module["__Py_fopen_obj"]=wasmExports["_Py_fopen_obj"])(a0,a1);var _PyUnstable_InterpreterFrame_GetCode=Module["_PyUnstable_InterpreterFrame_GetCode"]=a0=>(_PyUnstable_InterpreterFrame_GetCode=Module["_PyUnstable_InterpreterFrame_GetCode"]=wasmExports["PyUnstable_InterpreterFrame_GetCode"])(a0);var _PyUnstable_InterpreterFrame_GetLasti=Module["_PyUnstable_InterpreterFrame_GetLasti"]=a0=>(_PyUnstable_InterpreterFrame_GetLasti=Module["_PyUnstable_InterpreterFrame_GetLasti"]=wasmExports["PyUnstable_InterpreterFrame_GetLasti"])(a0);var _Py_FrozenMain=Module["_Py_FrozenMain"]=(a0,a1)=>(_Py_FrozenMain=Module["_Py_FrozenMain"]=wasmExports["Py_FrozenMain"])(a0,a1);var __PyRuntime_Initialize=Module["__PyRuntime_Initialize"]=a0=>(__PyRuntime_Initialize=Module["__PyRuntime_Initialize"]=wasmExports["_PyRuntime_Initialize"])(a0);var _Py_GETENV=Module["_Py_GETENV"]=a0=>(_Py_GETENV=Module["_Py_GETENV"]=wasmExports["Py_GETENV"])(a0);var _Py_GetVersion=Module["_Py_GetVersion"]=()=>(_Py_GetVersion=Module["_Py_GetVersion"]=wasmExports["Py_GetVersion"])();var _Py_GetCopyright=Module["_Py_GetCopyright"]=()=>(_Py_GetCopyright=Module["_Py_GetCopyright"]=wasmExports["Py_GetCopyright"])();var _PyImport_ImportFrozenModule=Module["_PyImport_ImportFrozenModule"]=a0=>(_PyImport_ImportFrozenModule=Module["_PyImport_ImportFrozenModule"]=wasmExports["PyImport_ImportFrozenModule"])(a0);var _PyRun_AnyFileExFlags=Module["_PyRun_AnyFileExFlags"]=(a0,a1,a2,a3)=>(_PyRun_AnyFileExFlags=Module["_PyRun_AnyFileExFlags"]=wasmExports["PyRun_AnyFileExFlags"])(a0,a1,a2,a3);var _Py_FinalizeEx=Module["_Py_FinalizeEx"]=()=>(_Py_FinalizeEx=Module["_Py_FinalizeEx"]=wasmExports["Py_FinalizeEx"])();var _PyArg_Parse=Module["_PyArg_Parse"]=(a0,a1,a2)=>(_PyArg_Parse=Module["_PyArg_Parse"]=wasmExports["PyArg_Parse"])(a0,a1,a2);var __PyArg_Parse_SizeT=Module["__PyArg_Parse_SizeT"]=(a0,a1,a2)=>(__PyArg_Parse_SizeT=Module["__PyArg_Parse_SizeT"]=wasmExports["_PyArg_Parse_SizeT"])(a0,a1,a2);var __PyArg_ParseStack=Module["__PyArg_ParseStack"]=(a0,a1,a2,a3)=>(__PyArg_ParseStack=Module["__PyArg_ParseStack"]=wasmExports["_PyArg_ParseStack"])(a0,a1,a2,a3);var _PyArg_VaParse=Module["_PyArg_VaParse"]=(a0,a1,a2)=>(_PyArg_VaParse=Module["_PyArg_VaParse"]=wasmExports["PyArg_VaParse"])(a0,a1,a2);var __PyArg_VaParse_SizeT=Module["__PyArg_VaParse_SizeT"]=(a0,a1,a2)=>(__PyArg_VaParse_SizeT=Module["__PyArg_VaParse_SizeT"]=wasmExports["_PyArg_VaParse_SizeT"])(a0,a1,a2);var _PyArg_VaParseTupleAndKeywords=Module["_PyArg_VaParseTupleAndKeywords"]=(a0,a1,a2,a3,a4)=>(_PyArg_VaParseTupleAndKeywords=Module["_PyArg_VaParseTupleAndKeywords"]=wasmExports["PyArg_VaParseTupleAndKeywords"])(a0,a1,a2,a3,a4);var __PyArg_VaParseTupleAndKeywords_SizeT=Module["__PyArg_VaParseTupleAndKeywords_SizeT"]=(a0,a1,a2,a3,a4)=>(__PyArg_VaParseTupleAndKeywords_SizeT=Module["__PyArg_VaParseTupleAndKeywords_SizeT"]=wasmExports["_PyArg_VaParseTupleAndKeywords_SizeT"])(a0,a1,a2,a3,a4);var __PyArg_ParseTupleAndKeywordsFast=Module["__PyArg_ParseTupleAndKeywordsFast"]=(a0,a1,a2,a3)=>(__PyArg_ParseTupleAndKeywordsFast=Module["__PyArg_ParseTupleAndKeywordsFast"]=wasmExports["_PyArg_ParseTupleAndKeywordsFast"])(a0,a1,a2,a3);var __PyArg_ParseTupleAndKeywordsFast_SizeT=Module["__PyArg_ParseTupleAndKeywordsFast_SizeT"]=(a0,a1,a2,a3)=>(__PyArg_ParseTupleAndKeywordsFast_SizeT=Module["__PyArg_ParseTupleAndKeywordsFast_SizeT"]=wasmExports["_PyArg_ParseTupleAndKeywordsFast_SizeT"])(a0,a1,a2,a3);var __PyArg_ParseStackAndKeywords=Module["__PyArg_ParseStackAndKeywords"]=(a0,a1,a2,a3,a4)=>(__PyArg_ParseStackAndKeywords=Module["__PyArg_ParseStackAndKeywords"]=wasmExports["_PyArg_ParseStackAndKeywords"])(a0,a1,a2,a3,a4);var __PyArg_VaParseTupleAndKeywordsFast=Module["__PyArg_VaParseTupleAndKeywordsFast"]=(a0,a1,a2,a3)=>(__PyArg_VaParseTupleAndKeywordsFast=Module["__PyArg_VaParseTupleAndKeywordsFast"]=wasmExports["_PyArg_VaParseTupleAndKeywordsFast"])(a0,a1,a2,a3);var __PyArg_VaParseTupleAndKeywordsFast_SizeT=Module["__PyArg_VaParseTupleAndKeywordsFast_SizeT"]=(a0,a1,a2,a3)=>(__PyArg_VaParseTupleAndKeywordsFast_SizeT=Module["__PyArg_VaParseTupleAndKeywordsFast_SizeT"]=wasmExports["_PyArg_VaParseTupleAndKeywordsFast_SizeT"])(a0,a1,a2,a3);var _PyThreadState_Swap=Module["_PyThreadState_Swap"]=a0=>(_PyThreadState_Swap=Module["_PyThreadState_Swap"]=wasmExports["PyThreadState_Swap"])(a0);var _PyThreadState_Clear=Module["_PyThreadState_Clear"]=a0=>(_PyThreadState_Clear=Module["_PyThreadState_Clear"]=wasmExports["PyThreadState_Clear"])(a0);var __PyArg_NoPositional=Module["__PyArg_NoPositional"]=(a0,a1)=>(__PyArg_NoPositional=Module["__PyArg_NoPositional"]=wasmExports["_PyArg_NoPositional"])(a0,a1);var _Py_GetCompiler=Module["_Py_GetCompiler"]=()=>(_Py_GetCompiler=Module["_Py_GetCompiler"]=wasmExports["Py_GetCompiler"])();var _Py_GetPlatform=Module["_Py_GetPlatform"]=()=>(_Py_GetPlatform=Module["_Py_GetPlatform"]=wasmExports["Py_GetPlatform"])();var __PyEval_SetSwitchInterval=Module["__PyEval_SetSwitchInterval"]=a0=>(__PyEval_SetSwitchInterval=Module["__PyEval_SetSwitchInterval"]=wasmExports["_PyEval_SetSwitchInterval"])(a0);var __PyEval_GetSwitchInterval=Module["__PyEval_GetSwitchInterval"]=()=>(__PyEval_GetSwitchInterval=Module["__PyEval_GetSwitchInterval"]=wasmExports["_PyEval_GetSwitchInterval"])();var _PyEval_ThreadsInitialized=Module["_PyEval_ThreadsInitialized"]=()=>(_PyEval_ThreadsInitialized=Module["_PyEval_ThreadsInitialized"]=wasmExports["PyEval_ThreadsInitialized"])();var _PyThread_init_thread=Module["_PyThread_init_thread"]=()=>(_PyThread_init_thread=Module["_PyThread_init_thread"]=wasmExports["PyThread_init_thread"])();var _pthread_mutex_lock=Module["_pthread_mutex_lock"]=a0=>(_pthread_mutex_lock=Module["_pthread_mutex_lock"]=wasmExports["pthread_mutex_lock"])(a0);var _pthread_cond_timedwait=Module["_pthread_cond_timedwait"]=(a0,a1,a2)=>(_pthread_cond_timedwait=Module["_pthread_cond_timedwait"]=wasmExports["pthread_cond_timedwait"])(a0,a1,a2);var _pthread_mutex_unlock=Module["_pthread_mutex_unlock"]=a0=>(_pthread_mutex_unlock=Module["_pthread_mutex_unlock"]=wasmExports["pthread_mutex_unlock"])(a0);var _pthread_cond_signal=Module["_pthread_cond_signal"]=a0=>(_pthread_cond_signal=Module["_pthread_cond_signal"]=wasmExports["pthread_cond_signal"])(a0);var _PyThread_exit_thread=Module["_PyThread_exit_thread"]=()=>(_PyThread_exit_thread=Module["_PyThread_exit_thread"]=wasmExports["PyThread_exit_thread"])();var _PyThread_get_thread_ident=Module["_PyThread_get_thread_ident"]=()=>(_PyThread_get_thread_ident=Module["_PyThread_get_thread_ident"]=wasmExports["PyThread_get_thread_ident"])();var _pthread_cond_destroy=Module["_pthread_cond_destroy"]=a0=>(_pthread_cond_destroy=Module["_pthread_cond_destroy"]=wasmExports["pthread_cond_destroy"])(a0);var _pthread_mutex_destroy=Module["_pthread_mutex_destroy"]=a0=>(_pthread_mutex_destroy=Module["_pthread_mutex_destroy"]=wasmExports["pthread_mutex_destroy"])(a0);var _PyEval_InitThreads=Module["_PyEval_InitThreads"]=()=>(_PyEval_InitThreads=Module["_PyEval_InitThreads"]=wasmExports["PyEval_InitThreads"])();var _PyEval_AcquireLock=Module["_PyEval_AcquireLock"]=()=>(_PyEval_AcquireLock=Module["_PyEval_AcquireLock"]=wasmExports["PyEval_AcquireLock"])();var _PyEval_ReleaseLock=Module["_PyEval_ReleaseLock"]=()=>(_PyEval_ReleaseLock=Module["_PyEval_ReleaseLock"]=wasmExports["PyEval_ReleaseLock"])();var _pthread_cond_wait=Module["_pthread_cond_wait"]=(a0,a1)=>(_pthread_cond_wait=Module["_pthread_cond_wait"]=wasmExports["pthread_cond_wait"])(a0,a1);var _PyEval_AcquireThread=Module["_PyEval_AcquireThread"]=a0=>(_PyEval_AcquireThread=Module["_PyEval_AcquireThread"]=wasmExports["PyEval_AcquireThread"])(a0);var _PyEval_ReleaseThread=Module["_PyEval_ReleaseThread"]=a0=>(_PyEval_ReleaseThread=Module["_PyEval_ReleaseThread"]=wasmExports["PyEval_ReleaseThread"])(a0);var __PyThread_at_fork_reinit=Module["__PyThread_at_fork_reinit"]=a0=>(__PyThread_at_fork_reinit=Module["__PyThread_at_fork_reinit"]=wasmExports["_PyThread_at_fork_reinit"])(a0);var __PyThreadState_DeleteExcept=Module["__PyThreadState_DeleteExcept"]=a0=>(__PyThreadState_DeleteExcept=Module["__PyThreadState_DeleteExcept"]=wasmExports["_PyThreadState_DeleteExcept"])(a0);var __PyEval_SignalAsyncExc=Module["__PyEval_SignalAsyncExc"]=a0=>(__PyEval_SignalAsyncExc=Module["__PyEval_SignalAsyncExc"]=wasmExports["_PyEval_SignalAsyncExc"])(a0);var __PyEval_SignalReceived=Module["__PyEval_SignalReceived"]=a0=>(__PyEval_SignalReceived=Module["__PyEval_SignalReceived"]=wasmExports["_PyEval_SignalReceived"])(a0);var __PyEval_AddPendingCall=Module["__PyEval_AddPendingCall"]=(a0,a1,a2,a3)=>(__PyEval_AddPendingCall=Module["__PyEval_AddPendingCall"]=wasmExports["_PyEval_AddPendingCall"])(a0,a1,a2,a3);var _Py_AddPendingCall=Module["_Py_AddPendingCall"]=(a0,a1)=>(_Py_AddPendingCall=Module["_Py_AddPendingCall"]=wasmExports["Py_AddPendingCall"])(a0,a1);var __PyErr_Print=Module["__PyErr_Print"]=a0=>(__PyErr_Print=Module["__PyErr_Print"]=wasmExports["_PyErr_Print"])(a0);var __PyEval_MakePendingCalls=Module["__PyEval_MakePendingCalls"]=a0=>(__PyEval_MakePendingCalls=Module["__PyEval_MakePendingCalls"]=wasmExports["_PyEval_MakePendingCalls"])(a0);var __PyErr_CheckSignalsTstate=Module["__PyErr_CheckSignalsTstate"]=a0=>(__PyErr_CheckSignalsTstate=Module["__PyErr_CheckSignalsTstate"]=wasmExports["_PyErr_CheckSignalsTstate"])(a0);var _Py_MakePendingCalls=Module["_Py_MakePendingCalls"]=()=>(_Py_MakePendingCalls=Module["_Py_MakePendingCalls"]=wasmExports["Py_MakePendingCalls"])();var _PyThread_free_lock=Module["_PyThread_free_lock"]=a0=>(_PyThread_free_lock=Module["_PyThread_free_lock"]=wasmExports["PyThread_free_lock"])(a0);var _pthread_mutex_init=Module["_pthread_mutex_init"]=(a0,a1)=>(_pthread_mutex_init=Module["_pthread_mutex_init"]=wasmExports["pthread_mutex_init"])(a0,a1);var __Py_hashtable_hash_ptr=Module["__Py_hashtable_hash_ptr"]=a0=>(__Py_hashtable_hash_ptr=Module["__Py_hashtable_hash_ptr"]=wasmExports["_Py_hashtable_hash_ptr"])(a0);var __Py_HashPointerRaw=Module["__Py_HashPointerRaw"]=a0=>(__Py_HashPointerRaw=Module["__Py_HashPointerRaw"]=wasmExports["_Py_HashPointerRaw"])(a0);var __Py_hashtable_compare_direct=Module["__Py_hashtable_compare_direct"]=(a0,a1)=>(__Py_hashtable_compare_direct=Module["__Py_hashtable_compare_direct"]=wasmExports["_Py_hashtable_compare_direct"])(a0,a1);var __Py_hashtable_size=Module["__Py_hashtable_size"]=a0=>(__Py_hashtable_size=Module["__Py_hashtable_size"]=wasmExports["_Py_hashtable_size"])(a0);var __Py_hashtable_steal=Module["__Py_hashtable_steal"]=(a0,a1)=>(__Py_hashtable_steal=Module["__Py_hashtable_steal"]=wasmExports["_Py_hashtable_steal"])(a0,a1);var __Py_hashtable_foreach=Module["__Py_hashtable_foreach"]=(a0,a1,a2)=>(__Py_hashtable_foreach=Module["__Py_hashtable_foreach"]=wasmExports["_Py_hashtable_foreach"])(a0,a1,a2);var __Py_hashtable_new=Module["__Py_hashtable_new"]=(a0,a1)=>(__Py_hashtable_new=Module["__Py_hashtable_new"]=wasmExports["_Py_hashtable_new"])(a0,a1);var __Py_hashtable_clear=Module["__Py_hashtable_clear"]=a0=>(__Py_hashtable_clear=Module["__Py_hashtable_clear"]=wasmExports["_Py_hashtable_clear"])(a0);var __PyImport_AcquireLock=Module["__PyImport_AcquireLock"]=a0=>(__PyImport_AcquireLock=Module["__PyImport_AcquireLock"]=wasmExports["_PyImport_AcquireLock"])(a0);var __PyImport_ReleaseLock=Module["__PyImport_ReleaseLock"]=a0=>(__PyImport_ReleaseLock=Module["__PyImport_ReleaseLock"]=wasmExports["_PyImport_ReleaseLock"])(a0);var __PyImport_GetModuleId=Module["__PyImport_GetModuleId"]=a0=>(__PyImport_GetModuleId=Module["__PyImport_GetModuleId"]=wasmExports["_PyImport_GetModuleId"])(a0);var __PyImport_SetModule=Module["__PyImport_SetModule"]=(a0,a1)=>(__PyImport_SetModule=Module["__PyImport_SetModule"]=wasmExports["_PyImport_SetModule"])(a0,a1);var __PyImport_SetModuleString=Module["__PyImport_SetModuleString"]=(a0,a1)=>(__PyImport_SetModuleString=Module["__PyImport_SetModuleString"]=wasmExports["_PyImport_SetModuleString"])(a0,a1);var _PyImport_AddModuleObject=Module["_PyImport_AddModuleObject"]=a0=>(_PyImport_AddModuleObject=Module["_PyImport_AddModuleObject"]=wasmExports["PyImport_AddModuleObject"])(a0);var _PyImport_AddModule=Module["_PyImport_AddModule"]=a0=>(_PyImport_AddModule=Module["_PyImport_AddModule"]=wasmExports["PyImport_AddModule"])(a0);var _PyState_FindModule=Module["_PyState_FindModule"]=a0=>(_PyState_FindModule=Module["_PyState_FindModule"]=wasmExports["PyState_FindModule"])(a0);var __PyState_AddModule=Module["__PyState_AddModule"]=(a0,a1,a2)=>(__PyState_AddModule=Module["__PyState_AddModule"]=wasmExports["_PyState_AddModule"])(a0,a1,a2);var _PyState_AddModule=Module["_PyState_AddModule"]=(a0,a1)=>(_PyState_AddModule=Module["_PyState_AddModule"]=wasmExports["PyState_AddModule"])(a0,a1);var _PyState_RemoveModule=Module["_PyState_RemoveModule"]=a0=>(_PyState_RemoveModule=Module["_PyState_RemoveModule"]=wasmExports["PyState_RemoveModule"])(a0);var __PyImport_ClearExtension=Module["__PyImport_ClearExtension"]=(a0,a1)=>(__PyImport_ClearExtension=Module["__PyImport_ClearExtension"]=wasmExports["_PyImport_ClearExtension"])(a0,a1);var __PyInterpreterState_HasFeature=Module["__PyInterpreterState_HasFeature"]=(a0,a1)=>(__PyInterpreterState_HasFeature=Module["__PyInterpreterState_HasFeature"]=wasmExports["_PyInterpreterState_HasFeature"])(a0,a1);var __PyImport_FixupExtensionObject=Module["__PyImport_FixupExtensionObject"]=(a0,a1,a2,a3)=>(__PyImport_FixupExtensionObject=Module["__PyImport_FixupExtensionObject"]=wasmExports["_PyImport_FixupExtensionObject"])(a0,a1,a2,a3);var __PyImport_FixupBuiltin=Module["__PyImport_FixupBuiltin"]=(a0,a1,a2)=>(__PyImport_FixupBuiltin=Module["__PyImport_FixupBuiltin"]=wasmExports["_PyImport_FixupBuiltin"])(a0,a1,a2);var _PyImport_ExtendInittab=Module["_PyImport_ExtendInittab"]=a0=>(_PyImport_ExtendInittab=Module["_PyImport_ExtendInittab"]=wasmExports["PyImport_ExtendInittab"])(a0);var _PyImport_GetMagicNumber=Module["_PyImport_GetMagicNumber"]=()=>(_PyImport_GetMagicNumber=Module["_PyImport_GetMagicNumber"]=wasmExports["PyImport_GetMagicNumber"])();var _PyImport_GetMagicTag=Module["_PyImport_GetMagicTag"]=()=>(_PyImport_GetMagicTag=Module["_PyImport_GetMagicTag"]=wasmExports["PyImport_GetMagicTag"])();var _PyImport_ExecCodeModule=Module["_PyImport_ExecCodeModule"]=(a0,a1)=>(_PyImport_ExecCodeModule=Module["_PyImport_ExecCodeModule"]=wasmExports["PyImport_ExecCodeModule"])(a0,a1);var _PyImport_ExecCodeModuleObject=Module["_PyImport_ExecCodeModuleObject"]=(a0,a1,a2,a3)=>(_PyImport_ExecCodeModuleObject=Module["_PyImport_ExecCodeModuleObject"]=wasmExports["PyImport_ExecCodeModuleObject"])(a0,a1,a2,a3);var _PyImport_ExecCodeModuleWithPathnames=Module["_PyImport_ExecCodeModuleWithPathnames"]=(a0,a1,a2,a3)=>(_PyImport_ExecCodeModuleWithPathnames=Module["_PyImport_ExecCodeModuleWithPathnames"]=wasmExports["PyImport_ExecCodeModuleWithPathnames"])(a0,a1,a2,a3);var _PyImport_ExecCodeModuleEx=Module["_PyImport_ExecCodeModuleEx"]=(a0,a1,a2)=>(_PyImport_ExecCodeModuleEx=Module["_PyImport_ExecCodeModuleEx"]=wasmExports["PyImport_ExecCodeModuleEx"])(a0,a1,a2);var _PyImport_ImportFrozenModuleObject=Module["_PyImport_ImportFrozenModuleObject"]=a0=>(_PyImport_ImportFrozenModuleObject=Module["_PyImport_ImportFrozenModuleObject"]=wasmExports["PyImport_ImportFrozenModuleObject"])(a0);var _PyMarshal_ReadObjectFromString=Module["_PyMarshal_ReadObjectFromString"]=(a0,a1)=>(_PyMarshal_ReadObjectFromString=Module["_PyMarshal_ReadObjectFromString"]=wasmExports["PyMarshal_ReadObjectFromString"])(a0,a1);var _PyImport_GetImporter=Module["_PyImport_GetImporter"]=a0=>(_PyImport_GetImporter=Module["_PyImport_GetImporter"]=wasmExports["PyImport_GetImporter"])(a0);var _PyImport_ImportModuleNoBlock=Module["_PyImport_ImportModuleNoBlock"]=a0=>(_PyImport_ImportModuleNoBlock=Module["_PyImport_ImportModuleNoBlock"]=wasmExports["PyImport_ImportModuleNoBlock"])(a0);var __PyTime_GetPerfCounter=Module["__PyTime_GetPerfCounter"]=()=>(__PyTime_GetPerfCounter=Module["__PyTime_GetPerfCounter"]=wasmExports["_PyTime_GetPerfCounter"])();var __PyTime_AsMicroseconds=Module["__PyTime_AsMicroseconds"]=(a0,a1)=>(__PyTime_AsMicroseconds=Module["__PyTime_AsMicroseconds"]=wasmExports["_PyTime_AsMicroseconds"])(a0,a1);var _PyImport_ImportModuleLevel=Module["_PyImport_ImportModuleLevel"]=(a0,a1,a2,a3,a4)=>(_PyImport_ImportModuleLevel=Module["_PyImport_ImportModuleLevel"]=wasmExports["PyImport_ImportModuleLevel"])(a0,a1,a2,a3,a4);var _PyImport_ReloadModule=Module["_PyImport_ReloadModule"]=a0=>(_PyImport_ReloadModule=Module["_PyImport_ReloadModule"]=wasmExports["PyImport_ReloadModule"])(a0);var _PyStatus_NoMemory=Module["_PyStatus_NoMemory"]=a0=>(_PyStatus_NoMemory=Module["_PyStatus_NoMemory"]=wasmExports["PyStatus_NoMemory"])(a0);var __PyImport_GetModuleAttr=Module["__PyImport_GetModuleAttr"]=(a0,a1)=>(__PyImport_GetModuleAttr=Module["__PyImport_GetModuleAttr"]=wasmExports["_PyImport_GetModuleAttr"])(a0,a1);var _PyInit__imp=Module["_PyInit__imp"]=()=>(_PyInit__imp=Module["_PyInit__imp"]=wasmExports["PyInit__imp"])();var _getenv=Module["_getenv"]=a0=>(_getenv=Module["_getenv"]=wasmExports["getenv"])(a0);var _PyStatus_Ok=Module["_PyStatus_Ok"]=a0=>(_PyStatus_Ok=Module["_PyStatus_Ok"]=wasmExports["PyStatus_Ok"])(a0);var _PyStatus_Error=Module["_PyStatus_Error"]=(a0,a1)=>(_PyStatus_Error=Module["_PyStatus_Error"]=wasmExports["PyStatus_Error"])(a0,a1);var _PyStatus_Exit=Module["_PyStatus_Exit"]=(a0,a1)=>(_PyStatus_Exit=Module["_PyStatus_Exit"]=wasmExports["PyStatus_Exit"])(a0,a1);var _PyStatus_IsError=Module["_PyStatus_IsError"]=a0=>(_PyStatus_IsError=Module["_PyStatus_IsError"]=wasmExports["PyStatus_IsError"])(a0);var _PyStatus_IsExit=Module["_PyStatus_IsExit"]=a0=>(_PyStatus_IsExit=Module["_PyStatus_IsExit"]=wasmExports["PyStatus_IsExit"])(a0);var __PyErr_SetFromPyStatus=Module["__PyErr_SetFromPyStatus"]=a0=>(__PyErr_SetFromPyStatus=Module["__PyErr_SetFromPyStatus"]=wasmExports["_PyErr_SetFromPyStatus"])(a0);var __PyWideStringList_Clear=Module["__PyWideStringList_Clear"]=a0=>(__PyWideStringList_Clear=Module["__PyWideStringList_Clear"]=wasmExports["_PyWideStringList_Clear"])(a0);var __PyWideStringList_Copy=Module["__PyWideStringList_Copy"]=(a0,a1)=>(__PyWideStringList_Copy=Module["__PyWideStringList_Copy"]=wasmExports["_PyWideStringList_Copy"])(a0,a1);var _PyWideStringList_Insert=Module["_PyWideStringList_Insert"]=(a0,a1,a2,a3)=>(_PyWideStringList_Insert=Module["_PyWideStringList_Insert"]=wasmExports["PyWideStringList_Insert"])(a0,a1,a2,a3);var _PyWideStringList_Append=Module["_PyWideStringList_Append"]=(a0,a1,a2)=>(_PyWideStringList_Append=Module["_PyWideStringList_Append"]=wasmExports["PyWideStringList_Append"])(a0,a1,a2);var __PyWideStringList_Extend=Module["__PyWideStringList_Extend"]=(a0,a1,a2)=>(__PyWideStringList_Extend=Module["__PyWideStringList_Extend"]=wasmExports["_PyWideStringList_Extend"])(a0,a1,a2);var __PyWideStringList_AsList=Module["__PyWideStringList_AsList"]=a0=>(__PyWideStringList_AsList=Module["__PyWideStringList_AsList"]=wasmExports["_PyWideStringList_AsList"])(a0);var _Py_SetStandardStreamEncoding=Module["_Py_SetStandardStreamEncoding"]=(a0,a1)=>(_Py_SetStandardStreamEncoding=Module["_Py_SetStandardStreamEncoding"]=wasmExports["Py_SetStandardStreamEncoding"])(a0,a1);var __Py_ClearStandardStreamEncoding=Module["__Py_ClearStandardStreamEncoding"]=()=>(__Py_ClearStandardStreamEncoding=Module["__Py_ClearStandardStreamEncoding"]=wasmExports["_Py_ClearStandardStreamEncoding"])();var __Py_ClearArgcArgv=Module["__Py_ClearArgcArgv"]=()=>(__Py_ClearArgcArgv=Module["__Py_ClearArgcArgv"]=wasmExports["_Py_ClearArgcArgv"])();var _Py_GetArgcArgv=Module["_Py_GetArgcArgv"]=(a0,a1)=>(_Py_GetArgcArgv=Module["_Py_GetArgcArgv"]=wasmExports["Py_GetArgcArgv"])(a0,a1);var __PyConfig_InitCompatConfig=Module["__PyConfig_InitCompatConfig"]=a0=>(__PyConfig_InitCompatConfig=Module["__PyConfig_InitCompatConfig"]=wasmExports["_PyConfig_InitCompatConfig"])(a0);var _PyConfig_InitIsolatedConfig=Module["_PyConfig_InitIsolatedConfig"]=a0=>(_PyConfig_InitIsolatedConfig=Module["_PyConfig_InitIsolatedConfig"]=wasmExports["PyConfig_InitIsolatedConfig"])(a0);var _PyConfig_SetString=Module["_PyConfig_SetString"]=(a0,a1,a2,a3)=>(_PyConfig_SetString=Module["_PyConfig_SetString"]=wasmExports["PyConfig_SetString"])(a0,a1,a2,a3);var __Py_PreInitializeFromConfig=Module["__Py_PreInitializeFromConfig"]=(a0,a1,a2)=>(__Py_PreInitializeFromConfig=Module["__Py_PreInitializeFromConfig"]=wasmExports["_Py_PreInitializeFromConfig"])(a0,a1,a2);var _Py_DecodeLocale=Module["_Py_DecodeLocale"]=(a0,a1)=>(_Py_DecodeLocale=Module["_Py_DecodeLocale"]=wasmExports["Py_DecodeLocale"])(a0,a1);var __PyConfig_AsDict=Module["__PyConfig_AsDict"]=a0=>(__PyConfig_AsDict=Module["__PyConfig_AsDict"]=wasmExports["_PyConfig_AsDict"])(a0);var __PyConfig_FromDict=Module["__PyConfig_FromDict"]=(a0,a1)=>(__PyConfig_FromDict=Module["__PyConfig_FromDict"]=wasmExports["_PyConfig_FromDict"])(a0,a1);var __Py_get_xoption=Module["__Py_get_xoption"]=(a0,a1)=>(__Py_get_xoption=Module["__Py_get_xoption"]=wasmExports["_Py_get_xoption"])(a0,a1);var _wcschr=Module["_wcschr"]=(a0,a1)=>(_wcschr=Module["_wcschr"]=wasmExports["wcschr"])(a0,a1);var _setvbuf=Module["_setvbuf"]=(a0,a1,a2,a3)=>(_setvbuf=Module["_setvbuf"]=wasmExports["setvbuf"])(a0,a1,a2,a3);var __PyArgv_AsWstrList=Module["__PyArgv_AsWstrList"]=(a0,a1,a2)=>(__PyArgv_AsWstrList=Module["__PyArgv_AsWstrList"]=wasmExports["_PyArgv_AsWstrList"])(a0,a1,a2);var _PyConfig_SetArgv=Module["_PyConfig_SetArgv"]=(a0,a1,a2,a3)=>(_PyConfig_SetArgv=Module["_PyConfig_SetArgv"]=wasmExports["PyConfig_SetArgv"])(a0,a1,a2,a3);var _PyConfig_SetWideStringList=Module["_PyConfig_SetWideStringList"]=(a0,a1,a2,a3,a4)=>(_PyConfig_SetWideStringList=Module["_PyConfig_SetWideStringList"]=wasmExports["PyConfig_SetWideStringList"])(a0,a1,a2,a3,a4);var _putchar=Module["_putchar"]=a0=>(_putchar=Module["_putchar"]=wasmExports["putchar"])(a0);var _iprintf=Module["_iprintf"]=(a0,a1)=>(_iprintf=Module["_iprintf"]=wasmExports["iprintf"])(a0,a1);var _wcstok=Module["_wcstok"]=(a0,a1,a2)=>(_wcstok=Module["_wcstok"]=wasmExports["wcstok"])(a0,a1,a2);var __Py_get_env_flag=Module["__Py_get_env_flag"]=(a0,a1,a2)=>(__Py_get_env_flag=Module["__Py_get_env_flag"]=wasmExports["_Py_get_env_flag"])(a0,a1,a2);var __Py_GetEnv=Module["__Py_GetEnv"]=(a0,a1)=>(__Py_GetEnv=Module["__Py_GetEnv"]=wasmExports["_Py_GetEnv"])(a0,a1);var _strtoul=Module["_strtoul"]=(a0,a1,a2)=>(_strtoul=Module["_strtoul"]=wasmExports["strtoul"])(a0,a1,a2);var __Py_str_to_int=Module["__Py_str_to_int"]=(a0,a1)=>(__Py_str_to_int=Module["__Py_str_to_int"]=wasmExports["_Py_str_to_int"])(a0,a1);var _wcstol=Module["_wcstol"]=(a0,a1,a2)=>(_wcstol=Module["_wcstol"]=wasmExports["wcstol"])(a0,a1,a2);var __Py_GetForceASCII=Module["__Py_GetForceASCII"]=()=>(__Py_GetForceASCII=Module["__Py_GetForceASCII"]=wasmExports["_Py_GetForceASCII"])();var _setlocale=Module["_setlocale"]=(a0,a1)=>(_setlocale=Module["_setlocale"]=wasmExports["setlocale"])(a0,a1);var __Py_IsLocaleCoercionTarget=Module["__Py_IsLocaleCoercionTarget"]=a0=>(__Py_IsLocaleCoercionTarget=Module["__Py_IsLocaleCoercionTarget"]=wasmExports["_Py_IsLocaleCoercionTarget"])(a0);var _PyConfig_Read=Module["_PyConfig_Read"]=(a0,a1)=>(_PyConfig_Read=Module["_PyConfig_Read"]=wasmExports["PyConfig_Read"])(a0,a1);var __Py_GetConfigsAsDict=Module["__Py_GetConfigsAsDict"]=()=>(__Py_GetConfigsAsDict=Module["__Py_GetConfigsAsDict"]=wasmExports["_Py_GetConfigsAsDict"])();var __Py_GetLocaleEncoding=Module["__Py_GetLocaleEncoding"]=()=>(__Py_GetLocaleEncoding=Module["__Py_GetLocaleEncoding"]=wasmExports["_Py_GetLocaleEncoding"])();var _PyMarshal_WriteLongToFile=Module["_PyMarshal_WriteLongToFile"]=(a0,a1,a2)=>(_PyMarshal_WriteLongToFile=Module["_PyMarshal_WriteLongToFile"]=wasmExports["PyMarshal_WriteLongToFile"])(a0,a1,a2);var _PyMarshal_WriteObjectToFile=Module["_PyMarshal_WriteObjectToFile"]=(a0,a1,a2)=>(_PyMarshal_WriteObjectToFile=Module["_PyMarshal_WriteObjectToFile"]=wasmExports["PyMarshal_WriteObjectToFile"])(a0,a1,a2);var _PyMarshal_ReadShortFromFile=Module["_PyMarshal_ReadShortFromFile"]=a0=>(_PyMarshal_ReadShortFromFile=Module["_PyMarshal_ReadShortFromFile"]=wasmExports["PyMarshal_ReadShortFromFile"])(a0);var _PyMarshal_ReadLongFromFile=Module["_PyMarshal_ReadLongFromFile"]=a0=>(_PyMarshal_ReadLongFromFile=Module["_PyMarshal_ReadLongFromFile"]=wasmExports["PyMarshal_ReadLongFromFile"])(a0);var _PyMarshal_ReadLastObjectFromFile=Module["_PyMarshal_ReadLastObjectFromFile"]=a0=>(_PyMarshal_ReadLastObjectFromFile=Module["_PyMarshal_ReadLastObjectFromFile"]=wasmExports["PyMarshal_ReadLastObjectFromFile"])(a0);var __Py_fstat_noraise=Module["__Py_fstat_noraise"]=(a0,a1)=>(__Py_fstat_noraise=Module["__Py_fstat_noraise"]=wasmExports["_Py_fstat_noraise"])(a0,a1);var _fread=Module["_fread"]=(a0,a1,a2,a3)=>(_fread=Module["_fread"]=wasmExports["fread"])(a0,a1,a2,a3);var _PyMarshal_ReadObjectFromFile=Module["_PyMarshal_ReadObjectFromFile"]=a0=>(_PyMarshal_ReadObjectFromFile=Module["_PyMarshal_ReadObjectFromFile"]=wasmExports["PyMarshal_ReadObjectFromFile"])(a0);var _PyMarshal_WriteObjectToString=Module["_PyMarshal_WriteObjectToString"]=(a0,a1)=>(_PyMarshal_WriteObjectToString=Module["_PyMarshal_WriteObjectToString"]=wasmExports["PyMarshal_WriteObjectToString"])(a0,a1);var _PyMarshal_Init=Module["_PyMarshal_Init"]=()=>(_PyMarshal_Init=Module["_PyMarshal_Init"]=wasmExports["PyMarshal_Init"])();var __Py_convert_optional_to_ssize_t=Module["__Py_convert_optional_to_ssize_t"]=(a0,a1)=>(__Py_convert_optional_to_ssize_t=Module["__Py_convert_optional_to_ssize_t"]=wasmExports["_Py_convert_optional_to_ssize_t"])(a0,a1);var _Py_VaBuildValue=Module["_Py_VaBuildValue"]=(a0,a1)=>(_Py_VaBuildValue=Module["_Py_VaBuildValue"]=wasmExports["Py_VaBuildValue"])(a0,a1);var __Py_VaBuildValue_SizeT=Module["__Py_VaBuildValue_SizeT"]=(a0,a1)=>(__Py_VaBuildValue_SizeT=Module["__Py_VaBuildValue_SizeT"]=wasmExports["_Py_VaBuildValue_SizeT"])(a0,a1);var __PyModule_Add=Module["__PyModule_Add"]=(a0,a1,a2)=>(__PyModule_Add=Module["__PyModule_Add"]=wasmExports["_PyModule_Add"])(a0,a1,a2);var _PyModule_AddStringConstant=Module["_PyModule_AddStringConstant"]=(a0,a1,a2)=>(_PyModule_AddStringConstant=Module["_PyModule_AddStringConstant"]=wasmExports["PyModule_AddStringConstant"])(a0,a1,a2);var _vsnprintf=Module["_vsnprintf"]=(a0,a1,a2,a3)=>(_vsnprintf=Module["_vsnprintf"]=wasmExports["vsnprintf"])(a0,a1,a2,a3);var _PyOS_vsnprintf=Module["_PyOS_vsnprintf"]=(a0,a1,a2,a3)=>(_PyOS_vsnprintf=Module["_PyOS_vsnprintf"]=wasmExports["PyOS_vsnprintf"])(a0,a1,a2,a3);var __PyPathConfig_ClearGlobal=Module["__PyPathConfig_ClearGlobal"]=()=>(__PyPathConfig_ClearGlobal=Module["__PyPathConfig_ClearGlobal"]=wasmExports["_PyPathConfig_ClearGlobal"])();var _wcscpy=Module["_wcscpy"]=(a0,a1)=>(_wcscpy=Module["_wcscpy"]=wasmExports["wcscpy"])(a0,a1);var _Py_SetPath=Module["_Py_SetPath"]=a0=>(_Py_SetPath=Module["_Py_SetPath"]=wasmExports["Py_SetPath"])(a0);var _Py_SetPythonHome=Module["_Py_SetPythonHome"]=a0=>(_Py_SetPythonHome=Module["_Py_SetPythonHome"]=wasmExports["Py_SetPythonHome"])(a0);var _Py_SetProgramName=Module["_Py_SetProgramName"]=a0=>(_Py_SetProgramName=Module["_Py_SetProgramName"]=wasmExports["Py_SetProgramName"])(a0);var __Py_SetProgramFullPath=Module["__Py_SetProgramFullPath"]=a0=>(__Py_SetProgramFullPath=Module["__Py_SetProgramFullPath"]=wasmExports["_Py_SetProgramFullPath"])(a0);var _Py_GetPath=Module["_Py_GetPath"]=()=>(_Py_GetPath=Module["_Py_GetPath"]=wasmExports["Py_GetPath"])();var _Py_GetPrefix=Module["_Py_GetPrefix"]=()=>(_Py_GetPrefix=Module["_Py_GetPrefix"]=wasmExports["Py_GetPrefix"])();var _Py_GetExecPrefix=Module["_Py_GetExecPrefix"]=()=>(_Py_GetExecPrefix=Module["_Py_GetExecPrefix"]=wasmExports["Py_GetExecPrefix"])();var _Py_GetProgramFullPath=Module["_Py_GetProgramFullPath"]=()=>(_Py_GetProgramFullPath=Module["_Py_GetProgramFullPath"]=wasmExports["Py_GetProgramFullPath"])();var _Py_GetPythonHome=Module["_Py_GetPythonHome"]=()=>(_Py_GetPythonHome=Module["_Py_GetPythonHome"]=wasmExports["Py_GetPythonHome"])();var _Py_GetProgramName=Module["_Py_GetProgramName"]=()=>(_Py_GetProgramName=Module["_Py_GetProgramName"]=wasmExports["Py_GetProgramName"])();var __Py_wgetcwd=Module["__Py_wgetcwd"]=(a0,a1)=>(__Py_wgetcwd=Module["__Py_wgetcwd"]=wasmExports["_Py_wgetcwd"])(a0,a1);var __Py_wreadlink=Module["__Py_wreadlink"]=(a0,a1,a2)=>(__Py_wreadlink=Module["__Py_wreadlink"]=wasmExports["_Py_wreadlink"])(a0,a1,a2);var _wcsrchr=Module["_wcsrchr"]=(a0,a1)=>(_wcsrchr=Module["_wcsrchr"]=wasmExports["wcsrchr"])(a0,a1);var _wcsncpy=Module["_wcsncpy"]=(a0,a1,a2)=>(_wcsncpy=Module["_wcsncpy"]=wasmExports["wcsncpy"])(a0,a1,a2);var __Py_wrealpath=Module["__Py_wrealpath"]=(a0,a1,a2)=>(__Py_wrealpath=Module["__Py_wrealpath"]=wasmExports["_Py_wrealpath"])(a0,a1,a2);var _wcsncmp=Module["_wcsncmp"]=(a0,a1,a2)=>(_wcsncmp=Module["_wcsncmp"]=wasmExports["wcsncmp"])(a0,a1,a2);var __PyPreConfig_InitCompatConfig=Module["__PyPreConfig_InitCompatConfig"]=a0=>(__PyPreConfig_InitCompatConfig=Module["__PyPreConfig_InitCompatConfig"]=wasmExports["_PyPreConfig_InitCompatConfig"])(a0);var _PyPreConfig_InitIsolatedConfig=Module["_PyPreConfig_InitIsolatedConfig"]=a0=>(_PyPreConfig_InitIsolatedConfig=Module["_PyPreConfig_InitIsolatedConfig"]=wasmExports["PyPreConfig_InitIsolatedConfig"])(a0);var __Py_SetLocaleFromEnv=Module["__Py_SetLocaleFromEnv"]=a0=>(__Py_SetLocaleFromEnv=Module["__Py_SetLocaleFromEnv"]=wasmExports["_Py_SetLocaleFromEnv"])(a0);var __Py_LegacyLocaleDetected=Module["__Py_LegacyLocaleDetected"]=a0=>(__Py_LegacyLocaleDetected=Module["__Py_LegacyLocaleDetected"]=wasmExports["_Py_LegacyLocaleDetected"])(a0);var __Py_CoerceLegacyLocale=Module["__Py_CoerceLegacyLocale"]=a0=>(__Py_CoerceLegacyLocale=Module["__Py_CoerceLegacyLocale"]=wasmExports["_Py_CoerceLegacyLocale"])(a0);var _PyHash_GetFuncDef=Module["_PyHash_GetFuncDef"]=()=>(_PyHash_GetFuncDef=Module["_PyHash_GetFuncDef"]=wasmExports["PyHash_GetFuncDef"])();var __PyRuntimeState_Init=Module["__PyRuntimeState_Init"]=(a0,a1)=>(__PyRuntimeState_Init=Module["__PyRuntimeState_Init"]=wasmExports["_PyRuntimeState_Init"])(a0,a1);var __PyRuntime_Finalize=Module["__PyRuntime_Finalize"]=()=>(__PyRuntime_Finalize=Module["__PyRuntime_Finalize"]=wasmExports["_PyRuntime_Finalize"])();var __PyRuntimeState_Fini=Module["__PyRuntimeState_Fini"]=a0=>(__PyRuntimeState_Fini=Module["__PyRuntimeState_Fini"]=wasmExports["_PyRuntimeState_Fini"])(a0);var __Py_IsFinalizing=Module["__Py_IsFinalizing"]=()=>(__Py_IsFinalizing=Module["__Py_IsFinalizing"]=wasmExports["_Py_IsFinalizing"])();var __Py_IsCoreInitialized=Module["__Py_IsCoreInitialized"]=()=>(__Py_IsCoreInitialized=Module["__Py_IsCoreInitialized"]=wasmExports["_Py_IsCoreInitialized"])();var _nl_langinfo=Module["_nl_langinfo"]=a0=>(_nl_langinfo=Module["_nl_langinfo"]=wasmExports["nl_langinfo"])(a0);var __Py_ResetForceASCII=Module["__Py_ResetForceASCII"]=()=>(__Py_ResetForceASCII=Module["__Py_ResetForceASCII"]=wasmExports["_Py_ResetForceASCII"])();var _setenv=Module["_setenv"]=(a0,a1,a2)=>(_setenv=Module["_setenv"]=wasmExports["setenv"])(a0,a1,a2);var __PyInterpreterState_SetConfig=Module["__PyInterpreterState_SetConfig"]=a0=>(__PyInterpreterState_SetConfig=Module["__PyInterpreterState_SetConfig"]=wasmExports["_PyInterpreterState_SetConfig"])(a0);var __Py_PreInitializeFromPyArgv=Module["__Py_PreInitializeFromPyArgv"]=(a0,a1,a2)=>(__Py_PreInitializeFromPyArgv=Module["__Py_PreInitializeFromPyArgv"]=wasmExports["_Py_PreInitializeFromPyArgv"])(a0,a1,a2);var _Py_PreInitializeFromArgs=Module["_Py_PreInitializeFromArgs"]=(a0,a1,a2,a3)=>(_Py_PreInitializeFromArgs=Module["_Py_PreInitializeFromArgs"]=wasmExports["Py_PreInitializeFromArgs"])(a0,a1,a2,a3);var _Py_PreInitialize=Module["_Py_PreInitialize"]=(a0,a1)=>(_Py_PreInitialize=Module["_Py_PreInitialize"]=wasmExports["Py_PreInitialize"])(a0,a1);var _Py_InitializeEx=Module["_Py_InitializeEx"]=a0=>(_Py_InitializeEx=Module["_Py_InitializeEx"]=wasmExports["Py_InitializeEx"])(a0);var _Py_FatalError=Module["_Py_FatalError"]=a0=>(_Py_FatalError=Module["_Py_FatalError"]=wasmExports["Py_FatalError"])(a0);var _Py_Initialize=Module["_Py_Initialize"]=()=>(_Py_Initialize=Module["_Py_Initialize"]=wasmExports["Py_Initialize"])();var __Py_InitializeMain=Module["__Py_InitializeMain"]=a0=>(__Py_InitializeMain=Module["__Py_InitializeMain"]=wasmExports["_Py_InitializeMain"])(a0);var _PyGC_Collect=Module["_PyGC_Collect"]=()=>(_PyGC_Collect=Module["_PyGC_Collect"]=wasmExports["PyGC_Collect"])();var _PyInterpreterState_Delete=Module["_PyInterpreterState_Delete"]=a0=>(_PyInterpreterState_Delete=Module["_PyInterpreterState_Delete"]=wasmExports["PyInterpreterState_Delete"])(a0);var _Py_Finalize=Module["_Py_Finalize"]=()=>(_Py_Finalize=Module["_Py_Finalize"]=wasmExports["Py_Finalize"])();var _Py_NewInterpreterFromConfig=Module["_Py_NewInterpreterFromConfig"]=(a0,a1,a2)=>(_Py_NewInterpreterFromConfig=Module["_Py_NewInterpreterFromConfig"]=wasmExports["Py_NewInterpreterFromConfig"])(a0,a1,a2);var _PyInterpreterState_New=Module["_PyInterpreterState_New"]=()=>(_PyInterpreterState_New=Module["_PyInterpreterState_New"]=wasmExports["PyInterpreterState_New"])();var __PyThreadState_New=Module["__PyThreadState_New"]=a0=>(__PyThreadState_New=Module["__PyThreadState_New"]=wasmExports["_PyThreadState_New"])(a0);var __PyThreadState_Bind=Module["__PyThreadState_Bind"]=a0=>(__PyThreadState_Bind=Module["__PyThreadState_Bind"]=wasmExports["_PyThreadState_Bind"])(a0);var _PyErr_PrintEx=Module["_PyErr_PrintEx"]=a0=>(_PyErr_PrintEx=Module["_PyErr_PrintEx"]=wasmExports["PyErr_PrintEx"])(a0);var _Py_NewInterpreter=Module["_Py_NewInterpreter"]=()=>(_Py_NewInterpreter=Module["_Py_NewInterpreter"]=wasmExports["Py_NewInterpreter"])();var _Py_EndInterpreter=Module["_Py_EndInterpreter"]=a0=>(_Py_EndInterpreter=Module["_Py_EndInterpreter"]=wasmExports["Py_EndInterpreter"])(a0);var __Py_DumpExtensionModules=Module["__Py_DumpExtensionModules"]=(a0,a1)=>(__Py_DumpExtensionModules=Module["__Py_DumpExtensionModules"]=wasmExports["_Py_DumpExtensionModules"])(a0,a1);var __Py_write_noraise=Module["__Py_write_noraise"]=(a0,a1,a2)=>(__Py_write_noraise=Module["__Py_write_noraise"]=wasmExports["_Py_write_noraise"])(a0,a1,a2);var __Py_DumpASCII=Module["__Py_DumpASCII"]=(a0,a1)=>(__Py_DumpASCII=Module["__Py_DumpASCII"]=wasmExports["_Py_DumpASCII"])(a0,a1);var __Py_DumpDecimal=Module["__Py_DumpDecimal"]=(a0,a1)=>(__Py_DumpDecimal=Module["__Py_DumpDecimal"]=wasmExports["_Py_DumpDecimal"])(a0,a1);var __Py_DumpHexadecimal=Module["__Py_DumpHexadecimal"]=(a0,a1,a2)=>(__Py_DumpHexadecimal=Module["__Py_DumpHexadecimal"]=wasmExports["_Py_DumpHexadecimal"])(a0,a1,a2);var __Py_DumpTracebackThreads=Module["__Py_DumpTracebackThreads"]=(a0,a1,a2)=>(__Py_DumpTracebackThreads=Module["__Py_DumpTracebackThreads"]=wasmExports["_Py_DumpTracebackThreads"])(a0,a1,a2);var _vfprintf=Module["_vfprintf"]=(a0,a1,a2)=>(_vfprintf=Module["_vfprintf"]=wasmExports["vfprintf"])(a0,a1,a2);var __Py_FatalRefcountErrorFunc=Module["__Py_FatalRefcountErrorFunc"]=(a0,a1)=>(__Py_FatalRefcountErrorFunc=Module["__Py_FatalRefcountErrorFunc"]=wasmExports["_Py_FatalRefcountErrorFunc"])(a0,a1);var _Py_AtExit=Module["_Py_AtExit"]=a0=>(_Py_AtExit=Module["_Py_AtExit"]=wasmExports["Py_AtExit"])(a0);var _Py_Exit=Module["_Py_Exit"]=a0=>(_Py_Exit=Module["_Py_Exit"]=wasmExports["Py_Exit"])(a0);var _Py_FdIsInteractive=Module["_Py_FdIsInteractive"]=(a0,a1)=>(_Py_FdIsInteractive=Module["_Py_FdIsInteractive"]=wasmExports["Py_FdIsInteractive"])(a0,a1);var __Py_FdIsInteractive=Module["__Py_FdIsInteractive"]=(a0,a1)=>(__Py_FdIsInteractive=Module["__Py_FdIsInteractive"]=wasmExports["_Py_FdIsInteractive"])(a0,a1);var _PyOS_getsig=Module["_PyOS_getsig"]=a0=>(_PyOS_getsig=Module["_PyOS_getsig"]=wasmExports["PyOS_getsig"])(a0);var _signal=Module["_signal"]=(a0,a1)=>(_signal=Module["_signal"]=wasmExports["signal"])(a0,a1);var _PyOS_setsig=Module["_PyOS_setsig"]=(a0,a1)=>(_PyOS_setsig=Module["_PyOS_setsig"]=wasmExports["PyOS_setsig"])(a0,a1);var _siginterrupt=Module["_siginterrupt"]=(a0,a1)=>(_siginterrupt=Module["_siginterrupt"]=wasmExports["siginterrupt"])(a0,a1);var __PyInterpreterState_Enable=Module["__PyInterpreterState_Enable"]=(a0,a1)=>(__PyInterpreterState_Enable=Module["__PyInterpreterState_Enable"]=wasmExports["_PyInterpreterState_Enable"])(a0,a1);var __PyTraceMalloc_Start=Module["__PyTraceMalloc_Start"]=a0=>(__PyTraceMalloc_Start=Module["__PyTraceMalloc_Start"]=wasmExports["_PyTraceMalloc_Start"])(a0);var _PySys_SetObject=Module["_PySys_SetObject"]=(a0,a1)=>(_PySys_SetObject=Module["_PySys_SetObject"]=wasmExports["PySys_SetObject"])(a0,a1);var _fcntl=Module["_fcntl"]=(a0,a1,a2)=>(_fcntl=Module["_fcntl"]=wasmExports["fcntl"])(a0,a1,a2);var _PyOS_mystrnicmp=Module["_PyOS_mystrnicmp"]=(a0,a1,a2)=>(_PyOS_mystrnicmp=Module["_PyOS_mystrnicmp"]=wasmExports["PyOS_mystrnicmp"])(a0,a1,a2);var __PyThreadState_GetCurrent=Module["__PyThreadState_GetCurrent"]=()=>(__PyThreadState_GetCurrent=Module["__PyThreadState_GetCurrent"]=wasmExports["_PyThreadState_GetCurrent"])();var _PyThread_tss_create=Module["_PyThread_tss_create"]=a0=>(_PyThread_tss_create=Module["_PyThread_tss_create"]=wasmExports["PyThread_tss_create"])(a0);var _PyThread_tss_delete=Module["_PyThread_tss_delete"]=a0=>(_PyThread_tss_delete=Module["_PyThread_tss_delete"]=wasmExports["PyThread_tss_delete"])(a0);var _PyInterpreterState_Clear=Module["_PyInterpreterState_Clear"]=a0=>(_PyInterpreterState_Clear=Module["_PyInterpreterState_Clear"]=wasmExports["PyInterpreterState_Clear"])(a0);var __PyThreadState_Swap=Module["__PyThreadState_Swap"]=(a0,a1)=>(__PyThreadState_Swap=Module["__PyThreadState_Swap"]=wasmExports["_PyThreadState_Swap"])(a0,a1);var __PyInterpreterState_SetRunningMain=Module["__PyInterpreterState_SetRunningMain"]=a0=>(__PyInterpreterState_SetRunningMain=Module["__PyInterpreterState_SetRunningMain"]=wasmExports["_PyInterpreterState_SetRunningMain"])(a0);var __PyInterpreterState_SetNotRunningMain=Module["__PyInterpreterState_SetNotRunningMain"]=a0=>(__PyInterpreterState_SetNotRunningMain=Module["__PyInterpreterState_SetNotRunningMain"]=wasmExports["_PyInterpreterState_SetNotRunningMain"])(a0);var __PyInterpreterState_IsRunningMain=Module["__PyInterpreterState_IsRunningMain"]=a0=>(__PyInterpreterState_IsRunningMain=Module["__PyInterpreterState_IsRunningMain"]=wasmExports["_PyInterpreterState_IsRunningMain"])(a0);var __PyInterpreterState_RequiresIDRef=Module["__PyInterpreterState_RequiresIDRef"]=a0=>(__PyInterpreterState_RequiresIDRef=Module["__PyInterpreterState_RequiresIDRef"]=wasmExports["_PyInterpreterState_RequiresIDRef"])(a0);var __PyInterpreterState_RequireIDRef=Module["__PyInterpreterState_RequireIDRef"]=(a0,a1)=>(__PyInterpreterState_RequireIDRef=Module["__PyInterpreterState_RequireIDRef"]=wasmExports["_PyInterpreterState_RequireIDRef"])(a0,a1);var __PyInterpreterState_GetMainModule=Module["__PyInterpreterState_GetMainModule"]=a0=>(__PyInterpreterState_GetMainModule=Module["__PyInterpreterState_GetMainModule"]=wasmExports["_PyInterpreterState_GetMainModule"])(a0);var _PyInterpreterState_GetDict=Module["_PyInterpreterState_GetDict"]=a0=>(_PyInterpreterState_GetDict=Module["_PyInterpreterState_GetDict"]=wasmExports["PyInterpreterState_GetDict"])(a0);var __PyThreadState_Prealloc=Module["__PyThreadState_Prealloc"]=a0=>(__PyThreadState_Prealloc=Module["__PyThreadState_Prealloc"]=wasmExports["_PyThreadState_Prealloc"])(a0);var __PyThreadState_Init=Module["__PyThreadState_Init"]=a0=>(__PyThreadState_Init=Module["__PyThreadState_Init"]=wasmExports["_PyThreadState_Init"])(a0);var __PyThreadState_DeleteCurrent=Module["__PyThreadState_DeleteCurrent"]=a0=>(__PyThreadState_DeleteCurrent=Module["__PyThreadState_DeleteCurrent"]=wasmExports["_PyThreadState_DeleteCurrent"])(a0);var _PyThreadState_DeleteCurrent=Module["_PyThreadState_DeleteCurrent"]=()=>(_PyThreadState_DeleteCurrent=Module["_PyThreadState_DeleteCurrent"]=wasmExports["PyThreadState_DeleteCurrent"])();var __PyThreadState_GetDict=Module["__PyThreadState_GetDict"]=a0=>(__PyThreadState_GetDict=Module["__PyThreadState_GetDict"]=wasmExports["_PyThreadState_GetDict"])(a0);var _PyThreadState_GetInterpreter=Module["_PyThreadState_GetInterpreter"]=a0=>(_PyThreadState_GetInterpreter=Module["_PyThreadState_GetInterpreter"]=wasmExports["PyThreadState_GetInterpreter"])(a0);var _PyThreadState_GetID=Module["_PyThreadState_GetID"]=a0=>(_PyThreadState_GetID=Module["_PyThreadState_GetID"]=wasmExports["PyThreadState_GetID"])(a0);var _PyThreadState_SetAsyncExc=Module["_PyThreadState_SetAsyncExc"]=(a0,a1)=>(_PyThreadState_SetAsyncExc=Module["_PyThreadState_SetAsyncExc"]=wasmExports["PyThreadState_SetAsyncExc"])(a0,a1);var _PyInterpreterState_Head=Module["_PyInterpreterState_Head"]=()=>(_PyInterpreterState_Head=Module["_PyInterpreterState_Head"]=wasmExports["PyInterpreterState_Head"])();var _PyInterpreterState_Main=Module["_PyInterpreterState_Main"]=()=>(_PyInterpreterState_Main=Module["_PyInterpreterState_Main"]=wasmExports["PyInterpreterState_Main"])();var _PyInterpreterState_Next=Module["_PyInterpreterState_Next"]=a0=>(_PyInterpreterState_Next=Module["_PyInterpreterState_Next"]=wasmExports["PyInterpreterState_Next"])(a0);var __PyThread_CurrentFrames=Module["__PyThread_CurrentFrames"]=()=>(__PyThread_CurrentFrames=Module["__PyThread_CurrentFrames"]=wasmExports["_PyThread_CurrentFrames"])();var __PyThread_CurrentExceptions=Module["__PyThread_CurrentExceptions"]=()=>(__PyThread_CurrentExceptions=Module["__PyThread_CurrentExceptions"]=wasmExports["_PyThread_CurrentExceptions"])();var __PyGILState_GetInterpreterStateUnsafe=Module["__PyGILState_GetInterpreterStateUnsafe"]=()=>(__PyGILState_GetInterpreterStateUnsafe=Module["__PyGILState_GetInterpreterStateUnsafe"]=wasmExports["_PyGILState_GetInterpreterStateUnsafe"])();var __PyCrossInterpreterData_Init=Module["__PyCrossInterpreterData_Init"]=(a0,a1,a2,a3,a4)=>(__PyCrossInterpreterData_Init=Module["__PyCrossInterpreterData_Init"]=wasmExports["_PyCrossInterpreterData_Init"])(a0,a1,a2,a3,a4);var __PyCrossInterpreterData_InitWithSize=Module["__PyCrossInterpreterData_InitWithSize"]=(a0,a1,a2,a3,a4)=>(__PyCrossInterpreterData_InitWithSize=Module["__PyCrossInterpreterData_InitWithSize"]=wasmExports["_PyCrossInterpreterData_InitWithSize"])(a0,a1,a2,a3,a4);var __PyCrossInterpreterData_Clear=Module["__PyCrossInterpreterData_Clear"]=(a0,a1)=>(__PyCrossInterpreterData_Clear=Module["__PyCrossInterpreterData_Clear"]=wasmExports["_PyCrossInterpreterData_Clear"])(a0,a1);var __PyObject_CheckCrossInterpreterData=Module["__PyObject_CheckCrossInterpreterData"]=a0=>(__PyObject_CheckCrossInterpreterData=Module["__PyObject_CheckCrossInterpreterData"]=wasmExports["_PyObject_CheckCrossInterpreterData"])(a0);var __PyObject_GetCrossInterpreterData=Module["__PyObject_GetCrossInterpreterData"]=(a0,a1)=>(__PyObject_GetCrossInterpreterData=Module["__PyObject_GetCrossInterpreterData"]=wasmExports["_PyObject_GetCrossInterpreterData"])(a0,a1);var __PyCrossInterpreterData_Release=Module["__PyCrossInterpreterData_Release"]=a0=>(__PyCrossInterpreterData_Release=Module["__PyCrossInterpreterData_Release"]=wasmExports["_PyCrossInterpreterData_Release"])(a0);var __PyCrossInterpreterData_NewObject=Module["__PyCrossInterpreterData_NewObject"]=a0=>(__PyCrossInterpreterData_NewObject=Module["__PyCrossInterpreterData_NewObject"]=wasmExports["_PyCrossInterpreterData_NewObject"])(a0);var __PyCrossInterpreterData_ReleaseAndRawFree=Module["__PyCrossInterpreterData_ReleaseAndRawFree"]=a0=>(__PyCrossInterpreterData_ReleaseAndRawFree=Module["__PyCrossInterpreterData_ReleaseAndRawFree"]=wasmExports["_PyCrossInterpreterData_ReleaseAndRawFree"])(a0);var __PyCrossInterpreterData_RegisterClass=Module["__PyCrossInterpreterData_RegisterClass"]=(a0,a1)=>(__PyCrossInterpreterData_RegisterClass=Module["__PyCrossInterpreterData_RegisterClass"]=wasmExports["_PyCrossInterpreterData_RegisterClass"])(a0,a1);var __PyCrossInterpreterData_UnregisterClass=Module["__PyCrossInterpreterData_UnregisterClass"]=a0=>(__PyCrossInterpreterData_UnregisterClass=Module["__PyCrossInterpreterData_UnregisterClass"]=wasmExports["_PyCrossInterpreterData_UnregisterClass"])(a0);var __PyCrossInterpreterData_Lookup=Module["__PyCrossInterpreterData_Lookup"]=a0=>(__PyCrossInterpreterData_Lookup=Module["__PyCrossInterpreterData_Lookup"]=wasmExports["_PyCrossInterpreterData_Lookup"])(a0);var __PyInterpreterState_GetEvalFrameFunc=Module["__PyInterpreterState_GetEvalFrameFunc"]=a0=>(__PyInterpreterState_GetEvalFrameFunc=Module["__PyInterpreterState_GetEvalFrameFunc"]=wasmExports["_PyInterpreterState_GetEvalFrameFunc"])(a0);var __PyInterpreterState_SetEvalFrameFunc=Module["__PyInterpreterState_SetEvalFrameFunc"]=(a0,a1)=>(__PyInterpreterState_SetEvalFrameFunc=Module["__PyInterpreterState_SetEvalFrameFunc"]=wasmExports["_PyInterpreterState_SetEvalFrameFunc"])(a0,a1);var __PyInterpreterState_GetConfigCopy=Module["__PyInterpreterState_GetConfigCopy"]=a0=>(__PyInterpreterState_GetConfigCopy=Module["__PyInterpreterState_GetConfigCopy"]=wasmExports["_PyInterpreterState_GetConfigCopy"])(a0);var __PyRun_AnyFileObject=Module["__PyRun_AnyFileObject"]=(a0,a1,a2,a3)=>(__PyRun_AnyFileObject=Module["__PyRun_AnyFileObject"]=wasmExports["_PyRun_AnyFileObject"])(a0,a1,a2,a3);var __PyRun_InteractiveLoopObject=Module["__PyRun_InteractiveLoopObject"]=(a0,a1,a2)=>(__PyRun_InteractiveLoopObject=Module["__PyRun_InteractiveLoopObject"]=wasmExports["_PyRun_InteractiveLoopObject"])(a0,a1,a2);var __PyRun_SimpleFileObject=Module["__PyRun_SimpleFileObject"]=(a0,a1,a2,a3)=>(__PyRun_SimpleFileObject=Module["__PyRun_SimpleFileObject"]=wasmExports["_PyRun_SimpleFileObject"])(a0,a1,a2,a3);var _rewind=Module["_rewind"]=a0=>(_rewind=Module["_rewind"]=wasmExports["rewind"])(a0);var _PyRun_InteractiveLoopFlags=Module["_PyRun_InteractiveLoopFlags"]=(a0,a1,a2)=>(_PyRun_InteractiveLoopFlags=Module["_PyRun_InteractiveLoopFlags"]=wasmExports["PyRun_InteractiveLoopFlags"])(a0,a1,a2);var _PyRun_InteractiveOneObject=Module["_PyRun_InteractiveOneObject"]=(a0,a1,a2)=>(_PyRun_InteractiveOneObject=Module["_PyRun_InteractiveOneObject"]=wasmExports["PyRun_InteractiveOneObject"])(a0,a1,a2);var _PyRun_InteractiveOneFlags=Module["_PyRun_InteractiveOneFlags"]=(a0,a1,a2)=>(_PyRun_InteractiveOneFlags=Module["_PyRun_InteractiveOneFlags"]=wasmExports["PyRun_InteractiveOneFlags"])(a0,a1,a2);var _PyRun_SimpleFileExFlags=Module["_PyRun_SimpleFileExFlags"]=(a0,a1,a2,a3)=>(_PyRun_SimpleFileExFlags=Module["_PyRun_SimpleFileExFlags"]=wasmExports["PyRun_SimpleFileExFlags"])(a0,a1,a2,a3);var _PyRun_SimpleStringFlags=Module["_PyRun_SimpleStringFlags"]=(a0,a1)=>(_PyRun_SimpleStringFlags=Module["_PyRun_SimpleStringFlags"]=wasmExports["PyRun_SimpleStringFlags"])(a0,a1);var __Py_HandleSystemExit=Module["__Py_HandleSystemExit"]=a0=>(__Py_HandleSystemExit=Module["__Py_HandleSystemExit"]=wasmExports["_Py_HandleSystemExit"])(a0);var _PyErr_Display=Module["_PyErr_Display"]=(a0,a1,a2)=>(_PyErr_Display=Module["_PyErr_Display"]=wasmExports["PyErr_Display"])(a0,a1,a2);var __PyErr_Display=Module["__PyErr_Display"]=(a0,a1,a2,a3)=>(__PyErr_Display=Module["__PyErr_Display"]=wasmExports["_PyErr_Display"])(a0,a1,a2,a3);var __Py_WriteIndentedMargin=Module["__Py_WriteIndentedMargin"]=(a0,a1,a2)=>(__Py_WriteIndentedMargin=Module["__Py_WriteIndentedMargin"]=wasmExports["_Py_WriteIndentedMargin"])(a0,a1,a2);var __Py_WriteIndent=Module["__Py_WriteIndent"]=(a0,a1)=>(__Py_WriteIndent=Module["__Py_WriteIndent"]=wasmExports["_Py_WriteIndent"])(a0,a1);var __PyErr_DisplayException=Module["__PyErr_DisplayException"]=(a0,a1)=>(__PyErr_DisplayException=Module["__PyErr_DisplayException"]=wasmExports["_PyErr_DisplayException"])(a0,a1);var _PyRun_FileExFlags=Module["_PyRun_FileExFlags"]=(a0,a1,a2,a3,a4,a5,a6)=>(_PyRun_FileExFlags=Module["_PyRun_FileExFlags"]=wasmExports["PyRun_FileExFlags"])(a0,a1,a2,a3,a4,a5,a6);var _Py_CompileStringExFlags=Module["_Py_CompileStringExFlags"]=(a0,a1,a2,a3,a4)=>(_Py_CompileStringExFlags=Module["_Py_CompileStringExFlags"]=wasmExports["Py_CompileStringExFlags"])(a0,a1,a2,a3,a4);var _PyRun_AnyFile=Module["_PyRun_AnyFile"]=(a0,a1)=>(_PyRun_AnyFile=Module["_PyRun_AnyFile"]=wasmExports["PyRun_AnyFile"])(a0,a1);var _PyRun_AnyFileEx=Module["_PyRun_AnyFileEx"]=(a0,a1,a2)=>(_PyRun_AnyFileEx=Module["_PyRun_AnyFileEx"]=wasmExports["PyRun_AnyFileEx"])(a0,a1,a2);var _PyRun_AnyFileFlags=Module["_PyRun_AnyFileFlags"]=(a0,a1,a2)=>(_PyRun_AnyFileFlags=Module["_PyRun_AnyFileFlags"]=wasmExports["PyRun_AnyFileFlags"])(a0,a1,a2);var _PyRun_File=Module["_PyRun_File"]=(a0,a1,a2,a3,a4)=>(_PyRun_File=Module["_PyRun_File"]=wasmExports["PyRun_File"])(a0,a1,a2,a3,a4);var _PyRun_FileEx=Module["_PyRun_FileEx"]=(a0,a1,a2,a3,a4,a5)=>(_PyRun_FileEx=Module["_PyRun_FileEx"]=wasmExports["PyRun_FileEx"])(a0,a1,a2,a3,a4,a5);var _PyRun_FileFlags=Module["_PyRun_FileFlags"]=(a0,a1,a2,a3,a4,a5)=>(_PyRun_FileFlags=Module["_PyRun_FileFlags"]=wasmExports["PyRun_FileFlags"])(a0,a1,a2,a3,a4,a5);var _PyRun_SimpleFile=Module["_PyRun_SimpleFile"]=(a0,a1)=>(_PyRun_SimpleFile=Module["_PyRun_SimpleFile"]=wasmExports["PyRun_SimpleFile"])(a0,a1);var _PyRun_SimpleFileEx=Module["_PyRun_SimpleFileEx"]=(a0,a1,a2)=>(_PyRun_SimpleFileEx=Module["_PyRun_SimpleFileEx"]=wasmExports["PyRun_SimpleFileEx"])(a0,a1,a2);var _PyRun_String=Module["_PyRun_String"]=(a0,a1,a2,a3)=>(_PyRun_String=Module["_PyRun_String"]=wasmExports["PyRun_String"])(a0,a1,a2,a3);var _PyRun_SimpleString=Module["_PyRun_SimpleString"]=a0=>(_PyRun_SimpleString=Module["_PyRun_SimpleString"]=wasmExports["PyRun_SimpleString"])(a0);var _Py_CompileString=Module["_Py_CompileString"]=(a0,a1,a2)=>(_Py_CompileString=Module["_Py_CompileString"]=wasmExports["Py_CompileString"])(a0,a1,a2);var _Py_CompileStringFlags=Module["_Py_CompileStringFlags"]=(a0,a1,a2,a3)=>(_Py_CompileStringFlags=Module["_Py_CompileStringFlags"]=wasmExports["Py_CompileStringFlags"])(a0,a1,a2,a3);var _PyRun_InteractiveOne=Module["_PyRun_InteractiveOne"]=(a0,a1)=>(_PyRun_InteractiveOne=Module["_PyRun_InteractiveOne"]=wasmExports["PyRun_InteractiveOne"])(a0,a1);var _PyRun_InteractiveLoop=Module["_PyRun_InteractiveLoop"]=(a0,a1)=>(_PyRun_InteractiveLoop=Module["_PyRun_InteractiveLoop"]=wasmExports["PyRun_InteractiveLoop"])(a0,a1);var __PyTraceBack_Print_Indented=Module["__PyTraceBack_Print_Indented"]=(a0,a1,a2,a3,a4,a5)=>(__PyTraceBack_Print_Indented=Module["__PyTraceBack_Print_Indented"]=wasmExports["_PyTraceBack_Print_Indented"])(a0,a1,a2,a3,a4,a5);var __PyTime_Add=Module["__PyTime_Add"]=(a0,a1)=>(__PyTime_Add=Module["__PyTime_Add"]=wasmExports["_PyTime_Add"])(a0,a1);var __PyTime_MulDiv=Module["__PyTime_MulDiv"]=(a0,a1,a2)=>(__PyTime_MulDiv=Module["__PyTime_MulDiv"]=wasmExports["_PyTime_MulDiv"])(a0,a1,a2);var __PyLong_AsTime_t=Module["__PyLong_AsTime_t"]=a0=>(__PyLong_AsTime_t=Module["__PyLong_AsTime_t"]=wasmExports["_PyLong_AsTime_t"])(a0);var __PyLong_FromTime_t=Module["__PyLong_FromTime_t"]=a0=>(__PyLong_FromTime_t=Module["__PyLong_FromTime_t"]=wasmExports["_PyLong_FromTime_t"])(a0);var __PyTime_ObjectToTime_t=Module["__PyTime_ObjectToTime_t"]=(a0,a1,a2)=>(__PyTime_ObjectToTime_t=Module["__PyTime_ObjectToTime_t"]=wasmExports["_PyTime_ObjectToTime_t"])(a0,a1,a2);var __PyTime_ObjectToTimespec=Module["__PyTime_ObjectToTimespec"]=(a0,a1,a2,a3)=>(__PyTime_ObjectToTimespec=Module["__PyTime_ObjectToTimespec"]=wasmExports["_PyTime_ObjectToTimespec"])(a0,a1,a2,a3);var __PyTime_ObjectToTimeval=Module["__PyTime_ObjectToTimeval"]=(a0,a1,a2,a3)=>(__PyTime_ObjectToTimeval=Module["__PyTime_ObjectToTimeval"]=wasmExports["_PyTime_ObjectToTimeval"])(a0,a1,a2,a3);var __PyTime_FromSeconds=Module["__PyTime_FromSeconds"]=a0=>(__PyTime_FromSeconds=Module["__PyTime_FromSeconds"]=wasmExports["_PyTime_FromSeconds"])(a0);var __PyTime_FromNanoseconds=Module["__PyTime_FromNanoseconds"]=a0=>(__PyTime_FromNanoseconds=Module["__PyTime_FromNanoseconds"]=wasmExports["_PyTime_FromNanoseconds"])(a0);var __PyTime_FromMicrosecondsClamp=Module["__PyTime_FromMicrosecondsClamp"]=a0=>(__PyTime_FromMicrosecondsClamp=Module["__PyTime_FromMicrosecondsClamp"]=wasmExports["_PyTime_FromMicrosecondsClamp"])(a0);var __PyTime_FromNanosecondsObject=Module["__PyTime_FromNanosecondsObject"]=(a0,a1)=>(__PyTime_FromNanosecondsObject=Module["__PyTime_FromNanosecondsObject"]=wasmExports["_PyTime_FromNanosecondsObject"])(a0,a1);var __PyTime_FromTimespec=Module["__PyTime_FromTimespec"]=(a0,a1)=>(__PyTime_FromTimespec=Module["__PyTime_FromTimespec"]=wasmExports["_PyTime_FromTimespec"])(a0,a1);var __PyTime_FromTimeval=Module["__PyTime_FromTimeval"]=(a0,a1)=>(__PyTime_FromTimeval=Module["__PyTime_FromTimeval"]=wasmExports["_PyTime_FromTimeval"])(a0,a1);var __PyTime_FromSecondsObject=Module["__PyTime_FromSecondsObject"]=(a0,a1,a2)=>(__PyTime_FromSecondsObject=Module["__PyTime_FromSecondsObject"]=wasmExports["_PyTime_FromSecondsObject"])(a0,a1,a2);var __PyTime_FromMillisecondsObject=Module["__PyTime_FromMillisecondsObject"]=(a0,a1,a2)=>(__PyTime_FromMillisecondsObject=Module["__PyTime_FromMillisecondsObject"]=wasmExports["_PyTime_FromMillisecondsObject"])(a0,a1,a2);var __PyTime_AsSecondsDouble=Module["__PyTime_AsSecondsDouble"]=a0=>(__PyTime_AsSecondsDouble=Module["__PyTime_AsSecondsDouble"]=wasmExports["_PyTime_AsSecondsDouble"])(a0);var __PyTime_AsNanosecondsObject=Module["__PyTime_AsNanosecondsObject"]=a0=>(__PyTime_AsNanosecondsObject=Module["__PyTime_AsNanosecondsObject"]=wasmExports["_PyTime_AsNanosecondsObject"])(a0);var __PyTime_AsNanoseconds=Module["__PyTime_AsNanoseconds"]=a0=>(__PyTime_AsNanoseconds=Module["__PyTime_AsNanoseconds"]=wasmExports["_PyTime_AsNanoseconds"])(a0);var __PyTime_AsMilliseconds=Module["__PyTime_AsMilliseconds"]=(a0,a1)=>(__PyTime_AsMilliseconds=Module["__PyTime_AsMilliseconds"]=wasmExports["_PyTime_AsMilliseconds"])(a0,a1);var __PyTime_AsTimeval=Module["__PyTime_AsTimeval"]=(a0,a1,a2)=>(__PyTime_AsTimeval=Module["__PyTime_AsTimeval"]=wasmExports["_PyTime_AsTimeval"])(a0,a1,a2);var __PyTime_AsTimeval_clamp=Module["__PyTime_AsTimeval_clamp"]=(a0,a1,a2)=>(__PyTime_AsTimeval_clamp=Module["__PyTime_AsTimeval_clamp"]=wasmExports["_PyTime_AsTimeval_clamp"])(a0,a1,a2);var __PyTime_AsTimevalTime_t=Module["__PyTime_AsTimevalTime_t"]=(a0,a1,a2,a3)=>(__PyTime_AsTimevalTime_t=Module["__PyTime_AsTimevalTime_t"]=wasmExports["_PyTime_AsTimevalTime_t"])(a0,a1,a2,a3);var __PyTime_AsTimespec_clamp=Module["__PyTime_AsTimespec_clamp"]=(a0,a1)=>(__PyTime_AsTimespec_clamp=Module["__PyTime_AsTimespec_clamp"]=wasmExports["_PyTime_AsTimespec_clamp"])(a0,a1);var __PyTime_AsTimespec=Module["__PyTime_AsTimespec"]=(a0,a1)=>(__PyTime_AsTimespec=Module["__PyTime_AsTimespec"]=wasmExports["_PyTime_AsTimespec"])(a0,a1);var __PyTime_GetSystemClock=Module["__PyTime_GetSystemClock"]=()=>(__PyTime_GetSystemClock=Module["__PyTime_GetSystemClock"]=wasmExports["_PyTime_GetSystemClock"])();var _clock_gettime=Module["_clock_gettime"]=(a0,a1)=>(_clock_gettime=Module["_clock_gettime"]=wasmExports["clock_gettime"])(a0,a1);var __PyTime_GetSystemClockWithInfo=Module["__PyTime_GetSystemClockWithInfo"]=(a0,a1)=>(__PyTime_GetSystemClockWithInfo=Module["__PyTime_GetSystemClockWithInfo"]=wasmExports["_PyTime_GetSystemClockWithInfo"])(a0,a1);var _clock_getres=Module["_clock_getres"]=(a0,a1)=>(_clock_getres=Module["_clock_getres"]=wasmExports["clock_getres"])(a0,a1);var __PyTime_GetMonotonicClock=Module["__PyTime_GetMonotonicClock"]=()=>(__PyTime_GetMonotonicClock=Module["__PyTime_GetMonotonicClock"]=wasmExports["_PyTime_GetMonotonicClock"])();var __PyTime_GetMonotonicClockWithInfo=Module["__PyTime_GetMonotonicClockWithInfo"]=(a0,a1)=>(__PyTime_GetMonotonicClockWithInfo=Module["__PyTime_GetMonotonicClockWithInfo"]=wasmExports["_PyTime_GetMonotonicClockWithInfo"])(a0,a1);var __PyTime_GetPerfCounterWithInfo=Module["__PyTime_GetPerfCounterWithInfo"]=(a0,a1)=>(__PyTime_GetPerfCounterWithInfo=Module["__PyTime_GetPerfCounterWithInfo"]=wasmExports["_PyTime_GetPerfCounterWithInfo"])(a0,a1);var __PyTime_localtime=Module["__PyTime_localtime"]=(a0,a1)=>(__PyTime_localtime=Module["__PyTime_localtime"]=wasmExports["_PyTime_localtime"])(a0,a1);var _localtime_r=Module["_localtime_r"]=(a0,a1)=>(_localtime_r=Module["_localtime_r"]=wasmExports["localtime_r"])(a0,a1);var __PyTime_gmtime=Module["__PyTime_gmtime"]=(a0,a1)=>(__PyTime_gmtime=Module["__PyTime_gmtime"]=wasmExports["_PyTime_gmtime"])(a0,a1);var _gmtime_r=Module["_gmtime_r"]=(a0,a1)=>(_gmtime_r=Module["_gmtime_r"]=wasmExports["gmtime_r"])(a0,a1);var __PyDeadline_Init=Module["__PyDeadline_Init"]=a0=>(__PyDeadline_Init=Module["__PyDeadline_Init"]=wasmExports["_PyDeadline_Init"])(a0);var __PyDeadline_Get=Module["__PyDeadline_Get"]=a0=>(__PyDeadline_Get=Module["__PyDeadline_Get"]=wasmExports["_PyDeadline_Get"])(a0);var __PyOS_URandom=Module["__PyOS_URandom"]=(a0,a1)=>(__PyOS_URandom=Module["__PyOS_URandom"]=wasmExports["_PyOS_URandom"])(a0,a1);var __Py_open=Module["__Py_open"]=(a0,a1)=>(__Py_open=Module["__Py_open"]=wasmExports["_Py_open"])(a0,a1);var _close=Module["_close"]=a0=>(_close=Module["_close"]=wasmExports["close"])(a0);var __Py_fstat=Module["__Py_fstat"]=(a0,a1)=>(__Py_fstat=Module["__Py_fstat"]=wasmExports["_Py_fstat"])(a0,a1);var __Py_read=Module["__Py_read"]=(a0,a1,a2)=>(__Py_read=Module["__Py_read"]=wasmExports["_Py_read"])(a0,a1,a2);var __Py_open_noraise=Module["__Py_open_noraise"]=(a0,a1)=>(__Py_open_noraise=Module["__Py_open_noraise"]=wasmExports["_Py_open_noraise"])(a0,a1);var _read=Module["_read"]=(a0,a1,a2)=>(_read=Module["_read"]=wasmExports["read"])(a0,a1,a2);var __PyOS_URandomNonblock=Module["__PyOS_URandomNonblock"]=(a0,a1)=>(__PyOS_URandomNonblock=Module["__PyOS_URandomNonblock"]=wasmExports["_PyOS_URandomNonblock"])(a0,a1);var _PySys_AddAuditHook=Module["_PySys_AddAuditHook"]=(a0,a1)=>(_PySys_AddAuditHook=Module["_PySys_AddAuditHook"]=wasmExports["PySys_AddAuditHook"])(a0,a1);var __PySys_GetSizeOf=Module["__PySys_GetSizeOf"]=a0=>(__PySys_GetSizeOf=Module["__PySys_GetSizeOf"]=wasmExports["_PySys_GetSizeOf"])(a0);var _PyUnstable_PerfMapState_Init=Module["_PyUnstable_PerfMapState_Init"]=()=>(_PyUnstable_PerfMapState_Init=Module["_PyUnstable_PerfMapState_Init"]=wasmExports["PyUnstable_PerfMapState_Init"])();var _getpid=Module["_getpid"]=()=>(_getpid=Module["_getpid"]=wasmExports["getpid"])();var _open=Module["_open"]=(a0,a1,a2)=>(_open=Module["_open"]=wasmExports["open"])(a0,a1,a2);var _PyUnstable_WritePerfMapEntry=Module["_PyUnstable_WritePerfMapEntry"]=(a0,a1,a2)=>(_PyUnstable_WritePerfMapEntry=Module["_PyUnstable_WritePerfMapEntry"]=wasmExports["PyUnstable_WritePerfMapEntry"])(a0,a1,a2);var _PyUnstable_PerfMapState_Fini=Module["_PyUnstable_PerfMapState_Fini"]=()=>(_PyUnstable_PerfMapState_Fini=Module["_PyUnstable_PerfMapState_Fini"]=wasmExports["PyUnstable_PerfMapState_Fini"])();var _PySys_ResetWarnOptions=Module["_PySys_ResetWarnOptions"]=()=>(_PySys_ResetWarnOptions=Module["_PySys_ResetWarnOptions"]=wasmExports["PySys_ResetWarnOptions"])();var _PySys_AddWarnOptionUnicode=Module["_PySys_AddWarnOptionUnicode"]=a0=>(_PySys_AddWarnOptionUnicode=Module["_PySys_AddWarnOptionUnicode"]=wasmExports["PySys_AddWarnOptionUnicode"])(a0);var _PySys_AddWarnOption=Module["_PySys_AddWarnOption"]=a0=>(_PySys_AddWarnOption=Module["_PySys_AddWarnOption"]=wasmExports["PySys_AddWarnOption"])(a0);var _PySys_HasWarnOptions=Module["_PySys_HasWarnOptions"]=()=>(_PySys_HasWarnOptions=Module["_PySys_HasWarnOptions"]=wasmExports["PySys_HasWarnOptions"])();var _PySys_AddXOption=Module["_PySys_AddXOption"]=a0=>(_PySys_AddXOption=Module["_PySys_AddXOption"]=wasmExports["PySys_AddXOption"])(a0);var _PySys_GetXOptions=Module["_PySys_GetXOptions"]=()=>(_PySys_GetXOptions=Module["_PySys_GetXOptions"]=wasmExports["PySys_GetXOptions"])();var _PyThread_GetInfo=Module["_PyThread_GetInfo"]=()=>(_PyThread_GetInfo=Module["_PyThread_GetInfo"]=wasmExports["PyThread_GetInfo"])();var _PySys_SetPath=Module["_PySys_SetPath"]=a0=>(_PySys_SetPath=Module["_PySys_SetPath"]=wasmExports["PySys_SetPath"])(a0);var _PySys_SetArgvEx=Module["_PySys_SetArgvEx"]=(a0,a1,a2)=>(_PySys_SetArgvEx=Module["_PySys_SetArgvEx"]=wasmExports["PySys_SetArgvEx"])(a0,a1,a2);var _PySys_SetArgv=Module["_PySys_SetArgv"]=(a0,a1)=>(_PySys_SetArgv=Module["_PySys_SetArgv"]=wasmExports["PySys_SetArgv"])(a0,a1);var _PySys_WriteStdout=Module["_PySys_WriteStdout"]=(a0,a1)=>(_PySys_WriteStdout=Module["_PySys_WriteStdout"]=wasmExports["PySys_WriteStdout"])(a0,a1);var _PySys_FormatStdout=Module["_PySys_FormatStdout"]=(a0,a1)=>(_PySys_FormatStdout=Module["_PySys_FormatStdout"]=wasmExports["PySys_FormatStdout"])(a0,a1);var _pthread_condattr_init=Module["_pthread_condattr_init"]=a0=>(_pthread_condattr_init=Module["_pthread_condattr_init"]=wasmExports["pthread_condattr_init"])(a0);var _pthread_condattr_setclock=Module["_pthread_condattr_setclock"]=(a0,a1)=>(_pthread_condattr_setclock=Module["_pthread_condattr_setclock"]=wasmExports["pthread_condattr_setclock"])(a0,a1);var _pthread_cond_init=Module["_pthread_cond_init"]=(a0,a1)=>(_pthread_cond_init=Module["_pthread_cond_init"]=wasmExports["pthread_cond_init"])(a0,a1);var _PyThread_start_new_thread=Module["_PyThread_start_new_thread"]=(a0,a1)=>(_PyThread_start_new_thread=Module["_PyThread_start_new_thread"]=wasmExports["PyThread_start_new_thread"])(a0,a1);var _pthread_attr_init=Module["_pthread_attr_init"]=a0=>(_pthread_attr_init=Module["_pthread_attr_init"]=wasmExports["pthread_attr_init"])(a0);var _pthread_attr_setstacksize=Module["_pthread_attr_setstacksize"]=(a0,a1)=>(_pthread_attr_setstacksize=Module["_pthread_attr_setstacksize"]=wasmExports["pthread_attr_setstacksize"])(a0,a1);var _pthread_attr_destroy=Module["_pthread_attr_destroy"]=a0=>(_pthread_attr_destroy=Module["_pthread_attr_destroy"]=wasmExports["pthread_attr_destroy"])(a0);var _pthread_create=Module["_pthread_create"]=(a0,a1,a2,a3)=>(_pthread_create=Module["_pthread_create"]=wasmExports["pthread_create"])(a0,a1,a2,a3);var _pthread_detach=Module["_pthread_detach"]=a0=>(_pthread_detach=Module["_pthread_detach"]=wasmExports["pthread_detach"])(a0);var _pthread_self=Module["_pthread_self"]=()=>(_pthread_self=Module["_pthread_self"]=wasmExports["pthread_self"])();var _pthread_exit=Module["_pthread_exit"]=a0=>(_pthread_exit=Module["_pthread_exit"]=wasmExports["pthread_exit"])(a0);var _PyThread_acquire_lock_timed=Module["_PyThread_acquire_lock_timed"]=(a0,a1,a2)=>(_PyThread_acquire_lock_timed=Module["_PyThread_acquire_lock_timed"]=wasmExports["PyThread_acquire_lock_timed"])(a0,a1,a2);var _pthread_mutex_trylock=Module["_pthread_mutex_trylock"]=a0=>(_pthread_mutex_trylock=Module["_pthread_mutex_trylock"]=wasmExports["pthread_mutex_trylock"])(a0);var _PyThread_create_key=Module["_PyThread_create_key"]=()=>(_PyThread_create_key=Module["_PyThread_create_key"]=wasmExports["PyThread_create_key"])();var _pthread_key_create=Module["_pthread_key_create"]=(a0,a1)=>(_pthread_key_create=Module["_pthread_key_create"]=wasmExports["pthread_key_create"])(a0,a1);var _pthread_key_delete=Module["_pthread_key_delete"]=a0=>(_pthread_key_delete=Module["_pthread_key_delete"]=wasmExports["pthread_key_delete"])(a0);var _PyThread_delete_key=Module["_PyThread_delete_key"]=a0=>(_PyThread_delete_key=Module["_PyThread_delete_key"]=wasmExports["PyThread_delete_key"])(a0);var _PyThread_delete_key_value=Module["_PyThread_delete_key_value"]=a0=>(_PyThread_delete_key_value=Module["_PyThread_delete_key_value"]=wasmExports["PyThread_delete_key_value"])(a0);var _pthread_setspecific=Module["_pthread_setspecific"]=(a0,a1)=>(_pthread_setspecific=Module["_pthread_setspecific"]=wasmExports["pthread_setspecific"])(a0,a1);var _PyThread_set_key_value=Module["_PyThread_set_key_value"]=(a0,a1)=>(_PyThread_set_key_value=Module["_PyThread_set_key_value"]=wasmExports["PyThread_set_key_value"])(a0,a1);var _PyThread_get_key_value=Module["_PyThread_get_key_value"]=a0=>(_PyThread_get_key_value=Module["_PyThread_get_key_value"]=wasmExports["PyThread_get_key_value"])(a0);var _pthread_getspecific=Module["_pthread_getspecific"]=a0=>(_pthread_getspecific=Module["_pthread_getspecific"]=wasmExports["pthread_getspecific"])(a0);var _PyThread_ReInitTLS=Module["_PyThread_ReInitTLS"]=()=>(_PyThread_ReInitTLS=Module["_PyThread_ReInitTLS"]=wasmExports["PyThread_ReInitTLS"])();var _PyThread_get_stacksize=Module["_PyThread_get_stacksize"]=()=>(_PyThread_get_stacksize=Module["_PyThread_get_stacksize"]=wasmExports["PyThread_get_stacksize"])();var _PyThread_set_stacksize=Module["_PyThread_set_stacksize"]=a0=>(_PyThread_set_stacksize=Module["_PyThread_set_stacksize"]=wasmExports["PyThread_set_stacksize"])(a0);var _PyThread_tss_alloc=Module["_PyThread_tss_alloc"]=()=>(_PyThread_tss_alloc=Module["_PyThread_tss_alloc"]=wasmExports["PyThread_tss_alloc"])();var _PyThread_tss_free=Module["_PyThread_tss_free"]=a0=>(_PyThread_tss_free=Module["_PyThread_tss_free"]=wasmExports["PyThread_tss_free"])(a0);var _confstr=Module["_confstr"]=(a0,a1,a2)=>(_confstr=Module["_confstr"]=wasmExports["confstr"])(a0,a1,a2);var __PyTraceback_Add=Module["__PyTraceback_Add"]=(a0,a1,a2)=>(__PyTraceback_Add=Module["__PyTraceback_Add"]=wasmExports["_PyTraceback_Add"])(a0,a1,a2);var __PyTraceMalloc_Init=Module["__PyTraceMalloc_Init"]=()=>(__PyTraceMalloc_Init=Module["__PyTraceMalloc_Init"]=wasmExports["_PyTraceMalloc_Init"])();var __PyTraceMalloc_Stop=Module["__PyTraceMalloc_Stop"]=()=>(__PyTraceMalloc_Stop=Module["__PyTraceMalloc_Stop"]=wasmExports["_PyTraceMalloc_Stop"])();var _PyTraceMalloc_Track=Module["_PyTraceMalloc_Track"]=(a0,a1,a2)=>(_PyTraceMalloc_Track=Module["_PyTraceMalloc_Track"]=wasmExports["PyTraceMalloc_Track"])(a0,a1,a2);var _PyTraceMalloc_Untrack=Module["_PyTraceMalloc_Untrack"]=(a0,a1)=>(_PyTraceMalloc_Untrack=Module["_PyTraceMalloc_Untrack"]=wasmExports["PyTraceMalloc_Untrack"])(a0,a1);var __PyTraceMalloc_GetTraceback=Module["__PyTraceMalloc_GetTraceback"]=(a0,a1)=>(__PyTraceMalloc_GetTraceback=Module["__PyTraceMalloc_GetTraceback"]=wasmExports["_PyTraceMalloc_GetTraceback"])(a0,a1);var __PyTraceMalloc_IsTracing=Module["__PyTraceMalloc_IsTracing"]=()=>(__PyTraceMalloc_IsTracing=Module["__PyTraceMalloc_IsTracing"]=wasmExports["_PyTraceMalloc_IsTracing"])();var __PyTraceMalloc_ClearTraces=Module["__PyTraceMalloc_ClearTraces"]=()=>(__PyTraceMalloc_ClearTraces=Module["__PyTraceMalloc_ClearTraces"]=wasmExports["_PyTraceMalloc_ClearTraces"])();var __PyTraceMalloc_GetTraces=Module["__PyTraceMalloc_GetTraces"]=()=>(__PyTraceMalloc_GetTraces=Module["__PyTraceMalloc_GetTraces"]=wasmExports["_PyTraceMalloc_GetTraces"])();var __PyTraceMalloc_GetObjectTraceback=Module["__PyTraceMalloc_GetObjectTraceback"]=a0=>(__PyTraceMalloc_GetObjectTraceback=Module["__PyTraceMalloc_GetObjectTraceback"]=wasmExports["_PyTraceMalloc_GetObjectTraceback"])(a0);var __PyTraceMalloc_GetTracebackLimit=Module["__PyTraceMalloc_GetTracebackLimit"]=()=>(__PyTraceMalloc_GetTracebackLimit=Module["__PyTraceMalloc_GetTracebackLimit"]=wasmExports["_PyTraceMalloc_GetTracebackLimit"])();var __PyTraceMalloc_GetMemory=Module["__PyTraceMalloc_GetMemory"]=()=>(__PyTraceMalloc_GetMemory=Module["__PyTraceMalloc_GetMemory"]=wasmExports["_PyTraceMalloc_GetMemory"])();var __PyTraceMalloc_GetTracedMemory=Module["__PyTraceMalloc_GetTracedMemory"]=()=>(__PyTraceMalloc_GetTracedMemory=Module["__PyTraceMalloc_GetTracedMemory"]=wasmExports["_PyTraceMalloc_GetTracedMemory"])();var __PyTraceMalloc_ResetPeak=Module["__PyTraceMalloc_ResetPeak"]=()=>(__PyTraceMalloc_ResetPeak=Module["__PyTraceMalloc_ResetPeak"]=wasmExports["_PyTraceMalloc_ResetPeak"])();var _PyOS_mystricmp=Module["_PyOS_mystricmp"]=(a0,a1)=>(_PyOS_mystricmp=Module["_PyOS_mystricmp"]=wasmExports["PyOS_mystricmp"])(a0,a1);var __Py_strhex=Module["__Py_strhex"]=(a0,a1)=>(__Py_strhex=Module["__Py_strhex"]=wasmExports["_Py_strhex"])(a0,a1);var __Py_strhex_bytes=Module["__Py_strhex_bytes"]=(a0,a1)=>(__Py_strhex_bytes=Module["__Py_strhex_bytes"]=wasmExports["_Py_strhex_bytes"])(a0,a1);var __Py_strhex_bytes_with_sep=Module["__Py_strhex_bytes_with_sep"]=(a0,a1,a2,a3)=>(__Py_strhex_bytes_with_sep=Module["__Py_strhex_bytes_with_sep"]=wasmExports["_Py_strhex_bytes_with_sep"])(a0,a1,a2,a3);var _localeconv=Module["_localeconv"]=()=>(_localeconv=Module["_localeconv"]=wasmExports["localeconv"])();var __Py_GetLocaleconvNumeric=Module["__Py_GetLocaleconvNumeric"]=(a0,a1,a2)=>(__Py_GetLocaleconvNumeric=Module["__Py_GetLocaleconvNumeric"]=wasmExports["_Py_GetLocaleconvNumeric"])(a0,a1,a2);var __Py_device_encoding=Module["__Py_device_encoding"]=a0=>(__Py_device_encoding=Module["__Py_device_encoding"]=wasmExports["_Py_device_encoding"])(a0);var __Py_GetLocaleEncodingObject=Module["__Py_GetLocaleEncodingObject"]=()=>(__Py_GetLocaleEncodingObject=Module["__Py_GetLocaleEncodingObject"]=wasmExports["_Py_GetLocaleEncodingObject"])();var _mbstowcs=Module["_mbstowcs"]=(a0,a1,a2)=>(_mbstowcs=Module["_mbstowcs"]=wasmExports["mbstowcs"])(a0,a1,a2);var _mbrtowc=Module["_mbrtowc"]=(a0,a1,a2,a3)=>(_mbrtowc=Module["_mbrtowc"]=wasmExports["mbrtowc"])(a0,a1,a2,a3);var _Py_EncodeLocale=Module["_Py_EncodeLocale"]=(a0,a1)=>(_Py_EncodeLocale=Module["_Py_EncodeLocale"]=wasmExports["Py_EncodeLocale"])(a0,a1);var __Py_EncodeLocaleRaw=Module["__Py_EncodeLocaleRaw"]=(a0,a1)=>(__Py_EncodeLocaleRaw=Module["__Py_EncodeLocaleRaw"]=wasmExports["_Py_EncodeLocaleRaw"])(a0,a1);var _fstat=Module["_fstat"]=(a0,a1)=>(_fstat=Module["_fstat"]=wasmExports["fstat"])(a0,a1);var _stat=Module["_stat"]=(a0,a1)=>(_stat=Module["_stat"]=wasmExports["stat"])(a0,a1);var __Py_stat=Module["__Py_stat"]=(a0,a1)=>(__Py_stat=Module["__Py_stat"]=wasmExports["_Py_stat"])(a0,a1);var __Py_get_inheritable=Module["__Py_get_inheritable"]=a0=>(__Py_get_inheritable=Module["__Py_get_inheritable"]=wasmExports["_Py_get_inheritable"])(a0);var __Py_set_inheritable=Module["__Py_set_inheritable"]=(a0,a1,a2)=>(__Py_set_inheritable=Module["__Py_set_inheritable"]=wasmExports["_Py_set_inheritable"])(a0,a1,a2);var __Py_set_inheritable_async_safe=Module["__Py_set_inheritable_async_safe"]=(a0,a1,a2)=>(__Py_set_inheritable_async_safe=Module["__Py_set_inheritable_async_safe"]=wasmExports["_Py_set_inheritable_async_safe"])(a0,a1,a2);var __Py_wfopen=Module["__Py_wfopen"]=(a0,a1)=>(__Py_wfopen=Module["__Py_wfopen"]=wasmExports["_Py_wfopen"])(a0,a1);var _wcstombs=Module["_wcstombs"]=(a0,a1,a2)=>(_wcstombs=Module["_wcstombs"]=wasmExports["wcstombs"])(a0,a1,a2);var _fopen=Module["_fopen"]=(a0,a1)=>(_fopen=Module["_fopen"]=wasmExports["fopen"])(a0,a1);var _write=Module["_write"]=(a0,a1,a2)=>(_write=Module["_write"]=wasmExports["write"])(a0,a1,a2);var _readlink=Module["_readlink"]=(a0,a1,a2)=>(_readlink=Module["_readlink"]=wasmExports["readlink"])(a0,a1,a2);var _realpath=Module["_realpath"]=(a0,a1)=>(_realpath=Module["_realpath"]=wasmExports["realpath"])(a0,a1);var _getcwd=Module["_getcwd"]=(a0,a1)=>(_getcwd=Module["_getcwd"]=wasmExports["getcwd"])(a0,a1);var __Py_normpath=Module["__Py_normpath"]=(a0,a1)=>(__Py_normpath=Module["__Py_normpath"]=wasmExports["_Py_normpath"])(a0,a1);var __Py_get_blocking=Module["__Py_get_blocking"]=a0=>(__Py_get_blocking=Module["__Py_get_blocking"]=wasmExports["_Py_get_blocking"])(a0);var __Py_set_blocking=Module["__Py_set_blocking"]=(a0,a1)=>(__Py_set_blocking=Module["__Py_set_blocking"]=wasmExports["_Py_set_blocking"])(a0,a1);var __Py_closerange=Module["__Py_closerange"]=(a0,a1)=>(__Py_closerange=Module["__Py_closerange"]=wasmExports["_Py_closerange"])(a0,a1);var __Py_UTF8_Edit_Cost=Module["__Py_UTF8_Edit_Cost"]=(a0,a1,a2)=>(__Py_UTF8_Edit_Cost=Module["__Py_UTF8_Edit_Cost"]=wasmExports["_Py_UTF8_Edit_Cost"])(a0,a1,a2);var _dlopen=Module["_dlopen"]=(a0,a1)=>(_dlopen=Module["_dlopen"]=wasmExports["dlopen"])(a0,a1);var _dlerror=Module["_dlerror"]=()=>(_dlerror=Module["_dlerror"]=wasmExports["dlerror"])();var _dlsym=Module["_dlsym"]=(a0,a1)=>(_dlsym=Module["_dlsym"]=wasmExports["dlsym"])(a0,a1);var _PyErr_SetInterruptEx=Module["_PyErr_SetInterruptEx"]=a0=>(_PyErr_SetInterruptEx=Module["_PyErr_SetInterruptEx"]=wasmExports["PyErr_SetInterruptEx"])(a0);var _PyInit__ctypes=Module["_PyInit__ctypes"]=()=>(_PyInit__ctypes=Module["_PyInit__ctypes"]=wasmExports["PyInit__ctypes"])();var _PyInit__posixsubprocess=Module["_PyInit__posixsubprocess"]=()=>(_PyInit__posixsubprocess=Module["_PyInit__posixsubprocess"]=wasmExports["PyInit__posixsubprocess"])();var _PyInit__bz2=Module["_PyInit__bz2"]=()=>(_PyInit__bz2=Module["_PyInit__bz2"]=wasmExports["PyInit__bz2"])();var _PyInit_zlib=Module["_PyInit_zlib"]=()=>(_PyInit_zlib=Module["_PyInit_zlib"]=wasmExports["PyInit_zlib"])();var _PyInit__xxsubinterpreters=Module["_PyInit__xxsubinterpreters"]=()=>(_PyInit__xxsubinterpreters=Module["_PyInit__xxsubinterpreters"]=wasmExports["PyInit__xxsubinterpreters"])();var _PyInit_array=Module["_PyInit_array"]=()=>(_PyInit_array=Module["_PyInit_array"]=wasmExports["PyInit_array"])();var _PyInit__asyncio=Module["_PyInit__asyncio"]=()=>(_PyInit__asyncio=Module["_PyInit__asyncio"]=wasmExports["PyInit__asyncio"])();var _PyInit__bisect=Module["_PyInit__bisect"]=()=>(_PyInit__bisect=Module["_PyInit__bisect"]=wasmExports["PyInit__bisect"])();var _PyInit__contextvars=Module["_PyInit__contextvars"]=()=>(_PyInit__contextvars=Module["_PyInit__contextvars"]=wasmExports["PyInit__contextvars"])();var _PyInit__csv=Module["_PyInit__csv"]=()=>(_PyInit__csv=Module["_PyInit__csv"]=wasmExports["PyInit__csv"])();var _PyInit__heapq=Module["_PyInit__heapq"]=()=>(_PyInit__heapq=Module["_PyInit__heapq"]=wasmExports["PyInit__heapq"])();var _PyInit__json=Module["_PyInit__json"]=()=>(_PyInit__json=Module["_PyInit__json"]=wasmExports["PyInit__json"])();var _PyInit__lsprof=Module["_PyInit__lsprof"]=()=>(_PyInit__lsprof=Module["_PyInit__lsprof"]=wasmExports["PyInit__lsprof"])();var _PyInit__opcode=Module["_PyInit__opcode"]=()=>(_PyInit__opcode=Module["_PyInit__opcode"]=wasmExports["PyInit__opcode"])();var _PyInit__pickle=Module["_PyInit__pickle"]=()=>(_PyInit__pickle=Module["_PyInit__pickle"]=wasmExports["PyInit__pickle"])();var _PyInit__queue=Module["_PyInit__queue"]=()=>(_PyInit__queue=Module["_PyInit__queue"]=wasmExports["PyInit__queue"])();var _PyInit__random=Module["_PyInit__random"]=()=>(_PyInit__random=Module["_PyInit__random"]=wasmExports["PyInit__random"])();var _PyInit__struct=Module["_PyInit__struct"]=()=>(_PyInit__struct=Module["_PyInit__struct"]=wasmExports["PyInit__struct"])();var _PyInit__zoneinfo=Module["_PyInit__zoneinfo"]=()=>(_PyInit__zoneinfo=Module["_PyInit__zoneinfo"]=wasmExports["PyInit__zoneinfo"])();var _PyInit_audioop=Module["_PyInit_audioop"]=()=>(_PyInit_audioop=Module["_PyInit_audioop"]=wasmExports["PyInit_audioop"])();var _PyInit_math=Module["_PyInit_math"]=()=>(_PyInit_math=Module["_PyInit_math"]=wasmExports["PyInit_math"])();var _PyInit_cmath=Module["_PyInit_cmath"]=()=>(_PyInit_cmath=Module["_PyInit_cmath"]=wasmExports["PyInit_cmath"])();var _PyInit__statistics=Module["_PyInit__statistics"]=()=>(_PyInit__statistics=Module["_PyInit__statistics"]=wasmExports["PyInit__statistics"])();var _PyInit__datetime=Module["_PyInit__datetime"]=()=>(_PyInit__datetime=Module["_PyInit__datetime"]=wasmExports["PyInit__datetime"])();var _PyInit__decimal=Module["_PyInit__decimal"]=()=>(_PyInit__decimal=Module["_PyInit__decimal"]=wasmExports["PyInit__decimal"])();var _PyInit_binascii=Module["_PyInit_binascii"]=()=>(_PyInit_binascii=Module["_PyInit_binascii"]=wasmExports["PyInit_binascii"])();var _PyInit__md5=Module["_PyInit__md5"]=()=>(_PyInit__md5=Module["_PyInit__md5"]=wasmExports["PyInit__md5"])();var _PyInit__sha1=Module["_PyInit__sha1"]=()=>(_PyInit__sha1=Module["_PyInit__sha1"]=wasmExports["PyInit__sha1"])();var _PyInit__sha2=Module["_PyInit__sha2"]=()=>(_PyInit__sha2=Module["_PyInit__sha2"]=wasmExports["PyInit__sha2"])();var _PyInit__sha3=Module["_PyInit__sha3"]=()=>(_PyInit__sha3=Module["_PyInit__sha3"]=wasmExports["PyInit__sha3"])();var _PyInit__blake2=Module["_PyInit__blake2"]=()=>(_PyInit__blake2=Module["_PyInit__blake2"]=wasmExports["PyInit__blake2"])();var _PyInit_pyexpat=Module["_PyInit_pyexpat"]=()=>(_PyInit_pyexpat=Module["_PyInit_pyexpat"]=wasmExports["PyInit_pyexpat"])();var _PyInit__elementtree=Module["_PyInit__elementtree"]=()=>(_PyInit__elementtree=Module["_PyInit__elementtree"]=wasmExports["PyInit__elementtree"])();var _PyInit__codecs_cn=Module["_PyInit__codecs_cn"]=()=>(_PyInit__codecs_cn=Module["_PyInit__codecs_cn"]=wasmExports["PyInit__codecs_cn"])();var _PyInit__codecs_hk=Module["_PyInit__codecs_hk"]=()=>(_PyInit__codecs_hk=Module["_PyInit__codecs_hk"]=wasmExports["PyInit__codecs_hk"])();var _PyInit__codecs_iso2022=Module["_PyInit__codecs_iso2022"]=()=>(_PyInit__codecs_iso2022=Module["_PyInit__codecs_iso2022"]=wasmExports["PyInit__codecs_iso2022"])();var _PyInit__codecs_jp=Module["_PyInit__codecs_jp"]=()=>(_PyInit__codecs_jp=Module["_PyInit__codecs_jp"]=wasmExports["PyInit__codecs_jp"])();var _PyInit__codecs_kr=Module["_PyInit__codecs_kr"]=()=>(_PyInit__codecs_kr=Module["_PyInit__codecs_kr"]=wasmExports["PyInit__codecs_kr"])();var _PyInit__codecs_tw=Module["_PyInit__codecs_tw"]=()=>(_PyInit__codecs_tw=Module["_PyInit__codecs_tw"]=wasmExports["PyInit__codecs_tw"])();var _PyInit__multibytecodec=Module["_PyInit__multibytecodec"]=()=>(_PyInit__multibytecodec=Module["_PyInit__multibytecodec"]=wasmExports["PyInit__multibytecodec"])();var _PyInit_unicodedata=Module["_PyInit_unicodedata"]=()=>(_PyInit_unicodedata=Module["_PyInit_unicodedata"]=wasmExports["PyInit_unicodedata"])();var _PyInit__crypt=Module["_PyInit__crypt"]=()=>(_PyInit__crypt=Module["_PyInit__crypt"]=wasmExports["PyInit__crypt"])();var _PyInit_mmap=Module["_PyInit_mmap"]=()=>(_PyInit_mmap=Module["_PyInit_mmap"]=wasmExports["PyInit_mmap"])();var _PyInit_select=Module["_PyInit_select"]=()=>(_PyInit_select=Module["_PyInit_select"]=wasmExports["PyInit_select"])();var _PyInit__socket=Module["_PyInit__socket"]=()=>(_PyInit__socket=Module["_PyInit__socket"]=wasmExports["PyInit__socket"])();var _PyInit_atexit=Module["_PyInit_atexit"]=()=>(_PyInit_atexit=Module["_PyInit_atexit"]=wasmExports["PyInit_atexit"])();var _PyInit_faulthandler=Module["_PyInit_faulthandler"]=()=>(_PyInit_faulthandler=Module["_PyInit_faulthandler"]=wasmExports["PyInit_faulthandler"])();var _PyInit_posix=Module["_PyInit_posix"]=()=>(_PyInit_posix=Module["_PyInit_posix"]=wasmExports["PyInit_posix"])();var _PyInit__signal=Module["_PyInit__signal"]=()=>(_PyInit__signal=Module["_PyInit__signal"]=wasmExports["PyInit__signal"])();var _PyInit__tracemalloc=Module["_PyInit__tracemalloc"]=()=>(_PyInit__tracemalloc=Module["_PyInit__tracemalloc"]=wasmExports["PyInit__tracemalloc"])();var _PyInit__codecs=Module["_PyInit__codecs"]=()=>(_PyInit__codecs=Module["_PyInit__codecs"]=wasmExports["PyInit__codecs"])();var _PyInit__collections=Module["_PyInit__collections"]=()=>(_PyInit__collections=Module["_PyInit__collections"]=wasmExports["PyInit__collections"])();var _PyInit_errno=Module["_PyInit_errno"]=()=>(_PyInit_errno=Module["_PyInit_errno"]=wasmExports["PyInit_errno"])();var _PyInit__io=Module["_PyInit__io"]=()=>(_PyInit__io=Module["_PyInit__io"]=wasmExports["PyInit__io"])();var _PyInit_itertools=Module["_PyInit_itertools"]=()=>(_PyInit_itertools=Module["_PyInit_itertools"]=wasmExports["PyInit_itertools"])();var _PyInit__sre=Module["_PyInit__sre"]=()=>(_PyInit__sre=Module["_PyInit__sre"]=wasmExports["PyInit__sre"])();var _PyInit__thread=Module["_PyInit__thread"]=()=>(_PyInit__thread=Module["_PyInit__thread"]=wasmExports["PyInit__thread"])();var _PyInit_time=Module["_PyInit_time"]=()=>(_PyInit_time=Module["_PyInit_time"]=wasmExports["PyInit_time"])();var _PyInit__typing=Module["_PyInit__typing"]=()=>(_PyInit__typing=Module["_PyInit__typing"]=wasmExports["PyInit__typing"])();var _PyInit__weakref=Module["_PyInit__weakref"]=()=>(_PyInit__weakref=Module["_PyInit__weakref"]=wasmExports["PyInit__weakref"])();var _PyInit__abc=Module["_PyInit__abc"]=()=>(_PyInit__abc=Module["_PyInit__abc"]=wasmExports["PyInit__abc"])();var _PyInit__functools=Module["_PyInit__functools"]=()=>(_PyInit__functools=Module["_PyInit__functools"]=wasmExports["PyInit__functools"])();var _PyInit__locale=Module["_PyInit__locale"]=()=>(_PyInit__locale=Module["_PyInit__locale"]=wasmExports["PyInit__locale"])();var _PyInit__operator=Module["_PyInit__operator"]=()=>(_PyInit__operator=Module["_PyInit__operator"]=wasmExports["PyInit__operator"])();var _PyInit__stat=Module["_PyInit__stat"]=()=>(_PyInit__stat=Module["_PyInit__stat"]=wasmExports["PyInit__stat"])();var _PyInit__symtable=Module["_PyInit__symtable"]=()=>(_PyInit__symtable=Module["_PyInit__symtable"]=wasmExports["PyInit__symtable"])();var _PyInit_gc=Module["_PyInit_gc"]=()=>(_PyInit_gc=Module["_PyInit_gc"]=wasmExports["PyInit_gc"])();var _Py_RunMain=Module["_Py_RunMain"]=()=>(_Py_RunMain=Module["_Py_RunMain"]=wasmExports["Py_RunMain"])();var _perror=Module["_perror"]=a0=>(_perror=Module["_perror"]=wasmExports["perror"])(a0);var _kill=Module["_kill"]=(a0,a1)=>(_kill=Module["_kill"]=wasmExports["kill"])(a0,a1);var _Py_Main=Module["_Py_Main"]=(a0,a1)=>(_Py_Main=Module["_Py_Main"]=wasmExports["Py_Main"])(a0,a1);var _Py_BytesMain=Module["_Py_BytesMain"]=(a0,a1)=>(_Py_BytesMain=Module["_Py_BytesMain"]=wasmExports["Py_BytesMain"])(a0,a1);var _PyGC_Enable=Module["_PyGC_Enable"]=()=>(_PyGC_Enable=Module["_PyGC_Enable"]=wasmExports["PyGC_Enable"])();var _PyGC_Disable=Module["_PyGC_Disable"]=()=>(_PyGC_Disable=Module["_PyGC_Disable"]=wasmExports["PyGC_Disable"])();var _PyGC_IsEnabled=Module["_PyGC_IsEnabled"]=()=>(_PyGC_IsEnabled=Module["_PyGC_IsEnabled"]=wasmExports["PyGC_IsEnabled"])();var _PyUnstable_Object_GC_NewWithExtraData=Module["_PyUnstable_Object_GC_NewWithExtraData"]=(a0,a1)=>(_PyUnstable_Object_GC_NewWithExtraData=Module["_PyUnstable_Object_GC_NewWithExtraData"]=wasmExports["PyUnstable_Object_GC_NewWithExtraData"])(a0,a1);var _PyObject_GC_IsTracked=Module["_PyObject_GC_IsTracked"]=a0=>(_PyObject_GC_IsTracked=Module["_PyObject_GC_IsTracked"]=wasmExports["PyObject_GC_IsTracked"])(a0);var _PyObject_GC_IsFinalized=Module["_PyObject_GC_IsFinalized"]=a0=>(_PyObject_GC_IsFinalized=Module["_PyObject_GC_IsFinalized"]=wasmExports["PyObject_GC_IsFinalized"])(a0);var _PyUnstable_GC_VisitObjects=Module["_PyUnstable_GC_VisitObjects"]=(a0,a1)=>(_PyUnstable_GC_VisitObjects=Module["_PyUnstable_GC_VisitObjects"]=wasmExports["PyUnstable_GC_VisitObjects"])(a0,a1);var _strcat=Module["_strcat"]=(a0,a1)=>(_strcat=Module["_strcat"]=wasmExports["strcat"])(a0,a1);var _ffi_closure_alloc=Module["_ffi_closure_alloc"]=(a0,a1)=>(_ffi_closure_alloc=Module["_ffi_closure_alloc"]=wasmExports["ffi_closure_alloc"])(a0,a1);var _ffi_prep_cif=Module["_ffi_prep_cif"]=(a0,a1,a2,a3,a4)=>(_ffi_prep_cif=Module["_ffi_prep_cif"]=wasmExports["ffi_prep_cif"])(a0,a1,a2,a3,a4);var _ffi_prep_closure_loc=Module["_ffi_prep_closure_loc"]=(a0,a1,a2,a3,a4)=>(_ffi_prep_closure_loc=Module["_ffi_prep_closure_loc"]=wasmExports["ffi_prep_closure_loc"])(a0,a1,a2,a3,a4);var _ffi_closure_free=Module["_ffi_closure_free"]=a0=>(_ffi_closure_free=Module["_ffi_closure_free"]=wasmExports["ffi_closure_free"])(a0);var _ffi_prep_cif_var=Module["_ffi_prep_cif_var"]=(a0,a1,a2,a3,a4,a5)=>(_ffi_prep_cif_var=Module["_ffi_prep_cif_var"]=wasmExports["ffi_prep_cif_var"])(a0,a1,a2,a3,a4,a5);var _ffi_call=Module["_ffi_call"]=(a0,a1,a2,a3)=>(_ffi_call=Module["_ffi_call"]=wasmExports["ffi_call"])(a0,a1,a2,a3);var _dlclose=Module["_dlclose"]=a0=>(_dlclose=Module["_dlclose"]=wasmExports["dlclose"])(a0);var ___extenddftf2=Module["___extenddftf2"]=(a0,a1)=>(___extenddftf2=Module["___extenddftf2"]=wasmExports["__extenddftf2"])(a0,a1);var ___trunctfdf2=Module["___trunctfdf2"]=(a0,a1)=>(___trunctfdf2=Module["___trunctfdf2"]=wasmExports["__trunctfdf2"])(a0,a1);var __Py_Gid_Converter=Module["__Py_Gid_Converter"]=(a0,a1)=>(__Py_Gid_Converter=Module["__Py_Gid_Converter"]=wasmExports["_Py_Gid_Converter"])(a0,a1);var __Py_Uid_Converter=Module["__Py_Uid_Converter"]=(a0,a1)=>(__Py_Uid_Converter=Module["__Py_Uid_Converter"]=wasmExports["_Py_Uid_Converter"])(a0,a1);var _PyOS_BeforeFork=Module["_PyOS_BeforeFork"]=()=>(_PyOS_BeforeFork=Module["_PyOS_BeforeFork"]=wasmExports["PyOS_BeforeFork"])();var _PyOS_AfterFork_Parent=Module["_PyOS_AfterFork_Parent"]=()=>(_PyOS_AfterFork_Parent=Module["_PyOS_AfterFork_Parent"]=wasmExports["PyOS_AfterFork_Parent"])();var _fork=Module["_fork"]=()=>(_fork=Module["_fork"]=wasmExports["fork"])();var _PyOS_AfterFork_Child=Module["_PyOS_AfterFork_Child"]=()=>(_PyOS_AfterFork_Child=Module["_PyOS_AfterFork_Child"]=wasmExports["PyOS_AfterFork_Child"])();var __exit=Module["__exit"]=a0=>(__exit=Module["__exit"]=wasmExports["_exit"])(a0);var _dup=Module["_dup"]=a0=>(_dup=Module["_dup"]=wasmExports["dup"])(a0);var _dup2=Module["_dup2"]=(a0,a1)=>(_dup2=Module["_dup2"]=wasmExports["dup2"])(a0,a1);var _chdir=Module["_chdir"]=a0=>(_chdir=Module["_chdir"]=wasmExports["chdir"])(a0);var _umask=Module["_umask"]=a0=>(_umask=Module["_umask"]=wasmExports["umask"])(a0);var __Py_RestoreSignals=Module["__Py_RestoreSignals"]=()=>(__Py_RestoreSignals=Module["__Py_RestoreSignals"]=wasmExports["_Py_RestoreSignals"])();var _setsid=Module["_setsid"]=()=>(_setsid=Module["_setsid"]=wasmExports["setsid"])();var _setpgid=Module["_setpgid"]=(a0,a1)=>(_setpgid=Module["_setpgid"]=wasmExports["setpgid"])(a0,a1);var _setregid=Module["_setregid"]=(a0,a1)=>(_setregid=Module["_setregid"]=wasmExports["setregid"])(a0,a1);var _setreuid=Module["_setreuid"]=(a0,a1)=>(_setreuid=Module["_setreuid"]=wasmExports["setreuid"])(a0,a1);var _execve=Module["_execve"]=(a0,a1,a2)=>(_execve=Module["_execve"]=wasmExports["execve"])(a0,a1,a2);var _execv=Module["_execv"]=(a0,a1)=>(_execv=Module["_execv"]=wasmExports["execv"])(a0,a1);var _opendir=Module["_opendir"]=a0=>(_opendir=Module["_opendir"]=wasmExports["opendir"])(a0);var _sysconf=Module["_sysconf"]=a0=>(_sysconf=Module["_sysconf"]=wasmExports["sysconf"])(a0);var _dirfd=Module["_dirfd"]=a0=>(_dirfd=Module["_dirfd"]=wasmExports["dirfd"])(a0);var _readdir=Module["_readdir"]=a0=>(_readdir=Module["_readdir"]=wasmExports["readdir"])(a0);var _closedir=Module["_closedir"]=a0=>(_closedir=Module["_closedir"]=wasmExports["closedir"])(a0);var _BZ2_bzCompressEnd=Module["_BZ2_bzCompressEnd"]=a0=>(_BZ2_bzCompressEnd=Module["_BZ2_bzCompressEnd"]=wasmExports["BZ2_bzCompressEnd"])(a0);var _BZ2_bzCompressInit=Module["_BZ2_bzCompressInit"]=(a0,a1,a2,a3)=>(_BZ2_bzCompressInit=Module["_BZ2_bzCompressInit"]=wasmExports["BZ2_bzCompressInit"])(a0,a1,a2,a3);var _BZ2_bzCompress=Module["_BZ2_bzCompress"]=(a0,a1)=>(_BZ2_bzCompress=Module["_BZ2_bzCompress"]=wasmExports["BZ2_bzCompress"])(a0,a1);var _BZ2_bzDecompressEnd=Module["_BZ2_bzDecompressEnd"]=a0=>(_BZ2_bzDecompressEnd=Module["_BZ2_bzDecompressEnd"]=wasmExports["BZ2_bzDecompressEnd"])(a0);var _BZ2_bzDecompressInit=Module["_BZ2_bzDecompressInit"]=(a0,a1,a2)=>(_BZ2_bzDecompressInit=Module["_BZ2_bzDecompressInit"]=wasmExports["BZ2_bzDecompressInit"])(a0,a1,a2);var _BZ2_bzDecompress=Module["_BZ2_bzDecompress"]=a0=>(_BZ2_bzDecompress=Module["_BZ2_bzDecompress"]=wasmExports["BZ2_bzDecompress"])(a0);var _adler32=Module["_adler32"]=(a0,a1,a2)=>(_adler32=Module["_adler32"]=wasmExports["adler32"])(a0,a1,a2);var _deflateInit2_=Module["_deflateInit2_"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_deflateInit2_=Module["_deflateInit2_"]=wasmExports["deflateInit2_"])(a0,a1,a2,a3,a4,a5,a6,a7);var _deflateEnd=Module["_deflateEnd"]=a0=>(_deflateEnd=Module["_deflateEnd"]=wasmExports["deflateEnd"])(a0);var _deflate=Module["_deflate"]=(a0,a1)=>(_deflate=Module["_deflate"]=wasmExports["deflate"])(a0,a1);var _deflateSetDictionary=Module["_deflateSetDictionary"]=(a0,a1,a2)=>(_deflateSetDictionary=Module["_deflateSetDictionary"]=wasmExports["deflateSetDictionary"])(a0,a1,a2);var _crc32=Module["_crc32"]=(a0,a1,a2)=>(_crc32=Module["_crc32"]=wasmExports["crc32"])(a0,a1,a2);var _inflateInit2_=Module["_inflateInit2_"]=(a0,a1,a2,a3)=>(_inflateInit2_=Module["_inflateInit2_"]=wasmExports["inflateInit2_"])(a0,a1,a2,a3);var _inflateEnd=Module["_inflateEnd"]=a0=>(_inflateEnd=Module["_inflateEnd"]=wasmExports["inflateEnd"])(a0);var _inflate=Module["_inflate"]=(a0,a1)=>(_inflate=Module["_inflate"]=wasmExports["inflate"])(a0,a1);var _inflateSetDictionary=Module["_inflateSetDictionary"]=(a0,a1,a2)=>(_inflateSetDictionary=Module["_inflateSetDictionary"]=wasmExports["inflateSetDictionary"])(a0,a1,a2);var _zlibVersion=Module["_zlibVersion"]=()=>(_zlibVersion=Module["_zlibVersion"]=wasmExports["zlibVersion"])();var _deflateCopy=Module["_deflateCopy"]=(a0,a1)=>(_deflateCopy=Module["_deflateCopy"]=wasmExports["deflateCopy"])(a0,a1);var _inflateCopy=Module["_inflateCopy"]=(a0,a1)=>(_inflateCopy=Module["_inflateCopy"]=wasmExports["inflateCopy"])(a0,a1);var _acos=Module["_acos"]=a0=>(_acos=Module["_acos"]=wasmExports["acos"])(a0);var _acosh=Module["_acosh"]=a0=>(_acosh=Module["_acosh"]=wasmExports["acosh"])(a0);var _asin=Module["_asin"]=a0=>(_asin=Module["_asin"]=wasmExports["asin"])(a0);var _asinh=Module["_asinh"]=a0=>(_asinh=Module["_asinh"]=wasmExports["asinh"])(a0);var _atan=Module["_atan"]=a0=>(_atan=Module["_atan"]=wasmExports["atan"])(a0);var _atanh=Module["_atanh"]=a0=>(_atanh=Module["_atanh"]=wasmExports["atanh"])(a0);var _cbrt=Module["_cbrt"]=a0=>(_cbrt=Module["_cbrt"]=wasmExports["cbrt"])(a0);var _copysign=Module["_copysign"]=(a0,a1)=>(_copysign=Module["_copysign"]=wasmExports["copysign"])(a0,a1);var _cosh=Module["_cosh"]=a0=>(_cosh=Module["_cosh"]=wasmExports["cosh"])(a0);var _erf=Module["_erf"]=a0=>(_erf=Module["_erf"]=wasmExports["erf"])(a0);var _erfc=Module["_erfc"]=a0=>(_erfc=Module["_erfc"]=wasmExports["erfc"])(a0);var _exp2=Module["_exp2"]=a0=>(_exp2=Module["_exp2"]=wasmExports["exp2"])(a0);var _expm1=Module["_expm1"]=a0=>(_expm1=Module["_expm1"]=wasmExports["expm1"])(a0);var _fabs=Module["_fabs"]=a0=>(_fabs=Module["_fabs"]=wasmExports["fabs"])(a0);var _sinh=Module["_sinh"]=a0=>(_sinh=Module["_sinh"]=wasmExports["sinh"])(a0);var _sqrt=Module["_sqrt"]=a0=>(_sqrt=Module["_sqrt"]=wasmExports["sqrt"])(a0);var _tan=Module["_tan"]=a0=>(_tan=Module["_tan"]=wasmExports["tan"])(a0);var _tanh=Module["_tanh"]=a0=>(_tanh=Module["_tanh"]=wasmExports["tanh"])(a0);var _fma=Module["_fma"]=(a0,a1,a2)=>(_fma=Module["_fma"]=wasmExports["fma"])(a0,a1,a2);var _nextafter=Module["_nextafter"]=(a0,a1)=>(_nextafter=Module["_nextafter"]=wasmExports["nextafter"])(a0,a1);var _log1p=Module["_log1p"]=a0=>(_log1p=Module["_log1p"]=wasmExports["log1p"])(a0);var _log10=Module["_log10"]=a0=>(_log10=Module["_log10"]=wasmExports["log10"])(a0);var _log2=Module["_log2"]=a0=>(_log2=Module["_log2"]=wasmExports["log2"])(a0);var _explicit_bzero=Module["_explicit_bzero"]=(a0,a1)=>(_explicit_bzero=Module["_explicit_bzero"]=wasmExports["explicit_bzero"])(a0,a1);var _strncat=Module["_strncat"]=(a0,a1,a2)=>(_strncat=Module["_strncat"]=wasmExports["strncat"])(a0,a1,a2);var _crypt_r=Module["_crypt_r"]=(a0,a1,a2)=>(_crypt_r=Module["_crypt_r"]=wasmExports["crypt_r"])(a0,a1,a2);var _mmap=Module["_mmap"]=(a0,a1,a2,a3,a4,a5)=>(_mmap=Module["_mmap"]=wasmExports["mmap"])(a0,a1,a2,a3,a4,a5);var _munmap=Module["_munmap"]=(a0,a1)=>(_munmap=Module["_munmap"]=wasmExports["munmap"])(a0,a1);var _msync=Module["_msync"]=(a0,a1,a2)=>(_msync=Module["_msync"]=wasmExports["msync"])(a0,a1,a2);var _madvise=Module["_madvise"]=(a0,a1,a2)=>(_madvise=Module["_madvise"]=wasmExports["madvise"])(a0,a1,a2);var _ftruncate=Module["_ftruncate"]=(a0,a1)=>(_ftruncate=Module["_ftruncate"]=wasmExports["ftruncate"])(a0,a1);var _mremap=Module["_mremap"]=(a0,a1,a2,a3,a4)=>(_mremap=Module["_mremap"]=wasmExports["mremap"])(a0,a1,a2,a3,a4);var _poll=Module["_poll"]=(a0,a1,a2)=>(_poll=Module["_poll"]=wasmExports["poll"])(a0,a1,a2);var _select=Module["_select"]=(a0,a1,a2,a3,a4)=>(_select=Module["_select"]=wasmExports["select"])(a0,a1,a2,a3,a4);var _inet_ntop=Module["_inet_ntop"]=(a0,a1,a2,a3)=>(_inet_ntop=Module["_inet_ntop"]=wasmExports["inet_ntop"])(a0,a1,a2,a3);var _gethostbyname=Module["_gethostbyname"]=a0=>(_gethostbyname=Module["_gethostbyname"]=wasmExports["gethostbyname"])(a0);var _gethostbyaddr=Module["_gethostbyaddr"]=(a0,a1,a2)=>(_gethostbyaddr=Module["_gethostbyaddr"]=wasmExports["gethostbyaddr"])(a0,a1,a2);var _gethostname=Module["_gethostname"]=(a0,a1)=>(_gethostname=Module["_gethostname"]=wasmExports["gethostname"])(a0,a1);var _getservbyname=Module["_getservbyname"]=(a0,a1)=>(_getservbyname=Module["_getservbyname"]=wasmExports["getservbyname"])(a0,a1);var _ntohs=a0=>(_ntohs=wasmExports["ntohs"])(a0);var _htons=a0=>(_htons=wasmExports["htons"])(a0);var _getservbyport=Module["_getservbyport"]=(a0,a1)=>(_getservbyport=Module["_getservbyport"]=wasmExports["getservbyport"])(a0,a1);var _ntohl=Module["_ntohl"]=a0=>(_ntohl=Module["_ntohl"]=wasmExports["ntohl"])(a0);var _htonl=a0=>(_htonl=wasmExports["htonl"])(a0);var _inet_aton=Module["_inet_aton"]=(a0,a1)=>(_inet_aton=Module["_inet_aton"]=wasmExports["inet_aton"])(a0,a1);var _inet_ntoa=Module["_inet_ntoa"]=a0=>(_inet_ntoa=Module["_inet_ntoa"]=wasmExports["inet_ntoa"])(a0);var _inet_pton=Module["_inet_pton"]=(a0,a1,a2)=>(_inet_pton=Module["_inet_pton"]=wasmExports["inet_pton"])(a0,a1,a2);var _gai_strerror=Module["_gai_strerror"]=a0=>(_gai_strerror=Module["_gai_strerror"]=wasmExports["gai_strerror"])(a0);var _freeaddrinfo=Module["_freeaddrinfo"]=a0=>(_freeaddrinfo=Module["_freeaddrinfo"]=wasmExports["freeaddrinfo"])(a0);var _if_nameindex=Module["_if_nameindex"]=()=>(_if_nameindex=Module["_if_nameindex"]=wasmExports["if_nameindex"])();var _if_freenameindex=Module["_if_freenameindex"]=a0=>(_if_freenameindex=Module["_if_freenameindex"]=wasmExports["if_freenameindex"])(a0);var _if_nametoindex=Module["_if_nametoindex"]=a0=>(_if_nametoindex=Module["_if_nametoindex"]=wasmExports["if_nametoindex"])(a0);var _if_indextoname=Module["_if_indextoname"]=(a0,a1)=>(_if_indextoname=Module["_if_indextoname"]=wasmExports["if_indextoname"])(a0,a1);var ___h_errno_location=Module["___h_errno_location"]=()=>(___h_errno_location=Module["___h_errno_location"]=wasmExports["__h_errno_location"])();var _hstrerror=Module["_hstrerror"]=a0=>(_hstrerror=Module["_hstrerror"]=wasmExports["hstrerror"])(a0);var _getsockname=Module["_getsockname"]=(a0,a1,a2)=>(_getsockname=Module["_getsockname"]=wasmExports["getsockname"])(a0,a1,a2);var _socket=Module["_socket"]=(a0,a1,a2)=>(_socket=Module["_socket"]=wasmExports["socket"])(a0,a1,a2);var _getsockopt=Module["_getsockopt"]=(a0,a1,a2,a3,a4)=>(_getsockopt=Module["_getsockopt"]=wasmExports["getsockopt"])(a0,a1,a2,a3,a4);var _bind=Module["_bind"]=(a0,a1,a2)=>(_bind=Module["_bind"]=wasmExports["bind"])(a0,a1,a2);var _getpeername=Module["_getpeername"]=(a0,a1,a2)=>(_getpeername=Module["_getpeername"]=wasmExports["getpeername"])(a0,a1,a2);var _listen=Module["_listen"]=(a0,a1)=>(_listen=Module["_listen"]=wasmExports["listen"])(a0,a1);var _setsockopt=Module["_setsockopt"]=(a0,a1,a2,a3,a4)=>(_setsockopt=Module["_setsockopt"]=wasmExports["setsockopt"])(a0,a1,a2,a3,a4);var _accept4=Module["_accept4"]=(a0,a1,a2,a3)=>(_accept4=Module["_accept4"]=wasmExports["accept4"])(a0,a1,a2,a3);var _accept=Module["_accept"]=(a0,a1,a2)=>(_accept=Module["_accept"]=wasmExports["accept"])(a0,a1,a2);var _connect=Module["_connect"]=(a0,a1,a2)=>(_connect=Module["_connect"]=wasmExports["connect"])(a0,a1,a2);var _recv=Module["_recv"]=(a0,a1,a2,a3)=>(_recv=Module["_recv"]=wasmExports["recv"])(a0,a1,a2,a3);var _recvfrom=Module["_recvfrom"]=(a0,a1,a2,a3,a4,a5)=>(_recvfrom=Module["_recvfrom"]=wasmExports["recvfrom"])(a0,a1,a2,a3,a4,a5);var _send=Module["_send"]=(a0,a1,a2,a3)=>(_send=Module["_send"]=wasmExports["send"])(a0,a1,a2,a3);var _sendto=Module["_sendto"]=(a0,a1,a2,a3,a4,a5)=>(_sendto=Module["_sendto"]=wasmExports["sendto"])(a0,a1,a2,a3,a4,a5);var _recvmsg=Module["_recvmsg"]=(a0,a1,a2)=>(_recvmsg=Module["_recvmsg"]=wasmExports["recvmsg"])(a0,a1,a2);var _sendmsg=Module["_sendmsg"]=(a0,a1,a2)=>(_sendmsg=Module["_sendmsg"]=wasmExports["sendmsg"])(a0,a1,a2);var __Py_AtExit=Module["__Py_AtExit"]=(a0,a1,a2)=>(__Py_AtExit=Module["__Py_AtExit"]=wasmExports["_Py_AtExit"])(a0,a1,a2);var _getrlimit=Module["_getrlimit"]=(a0,a1)=>(_getrlimit=Module["_getrlimit"]=wasmExports["getrlimit"])(a0,a1);var _setrlimit=Module["_setrlimit"]=(a0,a1)=>(_setrlimit=Module["_setrlimit"]=wasmExports["setrlimit"])(a0,a1);var _raise=Module["_raise"]=a0=>(_raise=Module["_raise"]=wasmExports["raise"])(a0);var _sigfillset=Module["_sigfillset"]=a0=>(_sigfillset=Module["_sigfillset"]=wasmExports["sigfillset"])(a0);var _pthread_sigmask=Module["_pthread_sigmask"]=(a0,a1,a2)=>(_pthread_sigmask=Module["_pthread_sigmask"]=wasmExports["pthread_sigmask"])(a0,a1,a2);var _PyOS_AfterFork=Module["_PyOS_AfterFork"]=()=>(_PyOS_AfterFork=Module["_PyOS_AfterFork"]=wasmExports["PyOS_AfterFork"])();var __PyLong_FromUid=Module["__PyLong_FromUid"]=a0=>(__PyLong_FromUid=Module["__PyLong_FromUid"]=wasmExports["_PyLong_FromUid"])(a0);var __PyLong_FromGid=Module["__PyLong_FromGid"]=a0=>(__PyLong_FromGid=Module["__PyLong_FromGid"]=wasmExports["_PyLong_FromGid"])(a0);var __Py_Sigset_Converter=Module["__Py_Sigset_Converter"]=(a0,a1)=>(__Py_Sigset_Converter=Module["__Py_Sigset_Converter"]=wasmExports["_Py_Sigset_Converter"])(a0,a1);var _sigemptyset=Module["_sigemptyset"]=a0=>(_sigemptyset=Module["_sigemptyset"]=wasmExports["sigemptyset"])(a0);var _sigaddset=Module["_sigaddset"]=(a0,a1)=>(_sigaddset=Module["_sigaddset"]=wasmExports["sigaddset"])(a0,a1);var _access=Module["_access"]=(a0,a1)=>(_access=Module["_access"]=wasmExports["access"])(a0,a1);var _ttyname_r=Module["_ttyname_r"]=(a0,a1,a2)=>(_ttyname_r=Module["_ttyname_r"]=wasmExports["ttyname_r"])(a0,a1,a2);var _fchdir=Module["_fchdir"]=a0=>(_fchdir=Module["_fchdir"]=wasmExports["fchdir"])(a0);var _fchmod=Module["_fchmod"]=(a0,a1)=>(_fchmod=Module["_fchmod"]=wasmExports["fchmod"])(a0,a1);var _fchmodat=Module["_fchmodat"]=(a0,a1,a2,a3)=>(_fchmodat=Module["_fchmodat"]=wasmExports["fchmodat"])(a0,a1,a2,a3);var _chmod=Module["_chmod"]=(a0,a1)=>(_chmod=Module["_chmod"]=wasmExports["chmod"])(a0,a1);var _fchown=Module["_fchown"]=(a0,a1,a2)=>(_fchown=Module["_fchown"]=wasmExports["fchown"])(a0,a1,a2);var _fchownat=Module["_fchownat"]=(a0,a1,a2,a3,a4)=>(_fchownat=Module["_fchownat"]=wasmExports["fchownat"])(a0,a1,a2,a3,a4);var _chown=Module["_chown"]=(a0,a1,a2)=>(_chown=Module["_chown"]=wasmExports["chown"])(a0,a1,a2);var _chroot=Module["_chroot"]=a0=>(_chroot=Module["_chroot"]=wasmExports["chroot"])(a0);var _ctermid=Module["_ctermid"]=a0=>(_ctermid=Module["_ctermid"]=wasmExports["ctermid"])(a0);var _fdopendir=Module["_fdopendir"]=a0=>(_fdopendir=Module["_fdopendir"]=wasmExports["fdopendir"])(a0);var _rewinddir=Module["_rewinddir"]=a0=>(_rewinddir=Module["_rewinddir"]=wasmExports["rewinddir"])(a0);var _mkdirat=Module["_mkdirat"]=(a0,a1,a2)=>(_mkdirat=Module["_mkdirat"]=wasmExports["mkdirat"])(a0,a1,a2);var _mkdir=Module["_mkdir"]=(a0,a1)=>(_mkdir=Module["_mkdir"]=wasmExports["mkdir"])(a0,a1);var _getpriority=Module["_getpriority"]=(a0,a1)=>(_getpriority=Module["_getpriority"]=wasmExports["getpriority"])(a0,a1);var _readlinkat=Module["_readlinkat"]=(a0,a1,a2,a3)=>(_readlinkat=Module["_readlinkat"]=wasmExports["readlinkat"])(a0,a1,a2,a3);var _unlinkat=Module["_unlinkat"]=(a0,a1,a2)=>(_unlinkat=Module["_unlinkat"]=wasmExports["unlinkat"])(a0,a1,a2);var _rmdir=Module["_rmdir"]=a0=>(_rmdir=Module["_rmdir"]=wasmExports["rmdir"])(a0);var _symlink=Module["_symlink"]=(a0,a1)=>(_symlink=Module["_symlink"]=wasmExports["symlink"])(a0,a1);var _system=Module["_system"]=a0=>(_system=Module["_system"]=wasmExports["system"])(a0);var _uname=Module["_uname"]=a0=>(_uname=Module["_uname"]=wasmExports["uname"])(a0);var _futimesat=Module["_futimesat"]=(a0,a1,a2)=>(_futimesat=Module["_futimesat"]=wasmExports["futimesat"])(a0,a1,a2);var _futimens=Module["_futimens"]=(a0,a1)=>(_futimens=Module["_futimens"]=wasmExports["futimens"])(a0,a1);var _times=Module["_times"]=a0=>(_times=Module["_times"]=wasmExports["times"])(a0);var _fexecve=Module["_fexecve"]=(a0,a1,a2)=>(_fexecve=Module["_fexecve"]=wasmExports["fexecve"])(a0,a1,a2);var _sched_yield=Module["_sched_yield"]=()=>(_sched_yield=Module["_sched_yield"]=wasmExports["sched_yield"])();var _login_tty=Module["_login_tty"]=a0=>(_login_tty=Module["_login_tty"]=wasmExports["login_tty"])(a0);var _getgid=Module["_getgid"]=()=>(_getgid=Module["_getgid"]=wasmExports["getgid"])();var _getpgrp=Module["_getpgrp"]=()=>(_getpgrp=Module["_getpgrp"]=wasmExports["getpgrp"])();var _getppid=Module["_getppid"]=()=>(_getppid=Module["_getppid"]=wasmExports["getppid"])();var _getuid=Module["_getuid"]=()=>(_getuid=Module["_getuid"]=wasmExports["getuid"])();var _getlogin=Module["_getlogin"]=()=>(_getlogin=Module["_getlogin"]=wasmExports["getlogin"])();var _killpg=Module["_killpg"]=(a0,a1)=>(_killpg=Module["_killpg"]=wasmExports["killpg"])(a0,a1);var _setuid=Module["_setuid"]=a0=>(_setuid=Module["_setuid"]=wasmExports["setuid"])(a0);var _setgid=Module["_setgid"]=a0=>(_setgid=Module["_setgid"]=wasmExports["setgid"])(a0);var _getpgid=Module["_getpgid"]=a0=>(_getpgid=Module["_getpgid"]=wasmExports["getpgid"])(a0);var _setpgrp=Module["_setpgrp"]=()=>(_setpgrp=Module["_setpgrp"]=wasmExports["setpgrp"])();var _wait=Module["_wait"]=a0=>(_wait=Module["_wait"]=wasmExports["wait"])(a0);var _waitid=Module["_waitid"]=(a0,a1,a2,a3)=>(_waitid=Module["_waitid"]=wasmExports["waitid"])(a0,a1,a2,a3);var _waitpid=Module["_waitpid"]=(a0,a1,a2)=>(_waitpid=Module["_waitpid"]=wasmExports["waitpid"])(a0,a1,a2);var _getsid=Module["_getsid"]=a0=>(_getsid=Module["_getsid"]=wasmExports["getsid"])(a0);var _tcgetpgrp=Module["_tcgetpgrp"]=a0=>(_tcgetpgrp=Module["_tcgetpgrp"]=wasmExports["tcgetpgrp"])(a0);var _tcsetpgrp=Module["_tcsetpgrp"]=(a0,a1)=>(_tcsetpgrp=Module["_tcsetpgrp"]=wasmExports["tcsetpgrp"])(a0,a1);var _openat=Module["_openat"]=(a0,a1,a2,a3)=>(_openat=Module["_openat"]=wasmExports["openat"])(a0,a1,a2,a3);var _dup3=Module["_dup3"]=(a0,a1,a2)=>(_dup3=Module["_dup3"]=wasmExports["dup3"])(a0,a1,a2);var _lockf=Module["_lockf"]=(a0,a1,a2)=>(_lockf=Module["_lockf"]=wasmExports["lockf"])(a0,a1,a2);var _readv=Module["_readv"]=(a0,a1,a2)=>(_readv=Module["_readv"]=wasmExports["readv"])(a0,a1,a2);var _pread=Module["_pread"]=(a0,a1,a2,a3)=>(_pread=Module["_pread"]=wasmExports["pread"])(a0,a1,a2,a3);var _writev=Module["_writev"]=(a0,a1,a2)=>(_writev=Module["_writev"]=wasmExports["writev"])(a0,a1,a2);var _pwrite=Module["_pwrite"]=(a0,a1,a2,a3)=>(_pwrite=Module["_pwrite"]=wasmExports["pwrite"])(a0,a1,a2,a3);var _pipe=Module["_pipe"]=a0=>(_pipe=Module["_pipe"]=wasmExports["pipe"])(a0);var _truncate=Module["_truncate"]=(a0,a1)=>(_truncate=Module["_truncate"]=wasmExports["truncate"])(a0,a1);var _posix_fadvise=Module["_posix_fadvise"]=(a0,a1,a2,a3)=>(_posix_fadvise=Module["_posix_fadvise"]=wasmExports["posix_fadvise"])(a0,a1,a2,a3);var _unsetenv=Module["_unsetenv"]=a0=>(_unsetenv=Module["_unsetenv"]=wasmExports["unsetenv"])(a0);var _fsync=Module["_fsync"]=a0=>(_fsync=Module["_fsync"]=wasmExports["fsync"])(a0);var _sync=Module["_sync"]=()=>(_sync=Module["_sync"]=wasmExports["sync"])();var _fdatasync=Module["_fdatasync"]=a0=>(_fdatasync=Module["_fdatasync"]=wasmExports["fdatasync"])(a0);var _fstatvfs=Module["_fstatvfs"]=(a0,a1)=>(_fstatvfs=Module["_fstatvfs"]=wasmExports["fstatvfs"])(a0,a1);var _statvfs=Module["_statvfs"]=(a0,a1)=>(_statvfs=Module["_statvfs"]=wasmExports["statvfs"])(a0,a1);var _fpathconf=Module["_fpathconf"]=(a0,a1)=>(_fpathconf=Module["_fpathconf"]=wasmExports["fpathconf"])(a0,a1);var _pathconf=Module["_pathconf"]=(a0,a1)=>(_pathconf=Module["_pathconf"]=wasmExports["pathconf"])(a0,a1);var _getloadavg=Module["_getloadavg"]=(a0,a1)=>(_getloadavg=Module["_getloadavg"]=wasmExports["getloadavg"])(a0,a1);var _lstat=Module["_lstat"]=(a0,a1)=>(_lstat=Module["_lstat"]=wasmExports["lstat"])(a0,a1);var _fstatat=Module["_fstatat"]=(a0,a1,a2,a3)=>(_fstatat=Module["_fstatat"]=wasmExports["fstatat"])(a0,a1,a2,a3);var _renameat=Module["_renameat"]=(a0,a1,a2,a3)=>(_renameat=Module["_renameat"]=wasmExports["renameat"])(a0,a1,a2,a3);var _rename=Module["_rename"]=(a0,a1)=>(_rename=Module["_rename"]=wasmExports["rename"])(a0,a1);var _unlink=Module["_unlink"]=a0=>(_unlink=Module["_unlink"]=wasmExports["unlink"])(a0);var _utimes=Module["_utimes"]=(a0,a1)=>(_utimes=Module["_utimes"]=wasmExports["utimes"])(a0,a1);var _qsort=Module["_qsort"]=(a0,a1,a2,a3)=>(_qsort=Module["_qsort"]=wasmExports["qsort"])(a0,a1,a2,a3);var __PyErr_CheckSignals=Module["__PyErr_CheckSignals"]=()=>(__PyErr_CheckSignals=Module["__PyErr_CheckSignals"]=wasmExports["_PyErr_CheckSignals"])();var _PyErr_SetInterrupt=Module["_PyErr_SetInterrupt"]=()=>(_PyErr_SetInterrupt=Module["_PyErr_SetInterrupt"]=wasmExports["PyErr_SetInterrupt"])();var _PyOS_InterruptOccurred=Module["_PyOS_InterruptOccurred"]=()=>(_PyOS_InterruptOccurred=Module["_PyOS_InterruptOccurred"]=wasmExports["PyOS_InterruptOccurred"])();var __PyOS_IsMainThread=Module["__PyOS_IsMainThread"]=()=>(__PyOS_IsMainThread=Module["__PyOS_IsMainThread"]=wasmExports["_PyOS_IsMainThread"])();var _getitimer=Module["_getitimer"]=(a0,a1)=>(_getitimer=Module["_getitimer"]=wasmExports["getitimer"])(a0,a1);var _strsignal=Module["_strsignal"]=a0=>(_strsignal=Module["_strsignal"]=wasmExports["strsignal"])(a0);var _strstr=Module["_strstr"]=(a0,a1)=>(_strstr=Module["_strstr"]=wasmExports["strstr"])(a0,a1);var _pause=Module["_pause"]=()=>(_pause=Module["_pause"]=wasmExports["pause"])();var _sigpending=Module["_sigpending"]=a0=>(_sigpending=Module["_sigpending"]=wasmExports["sigpending"])(a0);var _sigwait=Module["_sigwait"]=(a0,a1)=>(_sigwait=Module["_sigwait"]=wasmExports["sigwait"])(a0,a1);var _sigwaitinfo=Module["_sigwaitinfo"]=(a0,a1)=>(_sigwaitinfo=Module["_sigwaitinfo"]=wasmExports["sigwaitinfo"])(a0,a1);var _sigtimedwait=Module["_sigtimedwait"]=(a0,a1,a2)=>(_sigtimedwait=Module["_sigtimedwait"]=wasmExports["sigtimedwait"])(a0,a1,a2);var _sigismember=Module["_sigismember"]=(a0,a1)=>(_sigismember=Module["_sigismember"]=wasmExports["sigismember"])(a0,a1);var ___libc_current_sigrtmin=Module["___libc_current_sigrtmin"]=()=>(___libc_current_sigrtmin=Module["___libc_current_sigrtmin"]=wasmExports["__libc_current_sigrtmin"])();var ___libc_current_sigrtmax=Module["___libc_current_sigrtmax"]=()=>(___libc_current_sigrtmax=Module["___libc_current_sigrtmax"]=wasmExports["__libc_current_sigrtmax"])();var _isalnum=Module["_isalnum"]=a0=>(_isalnum=Module["_isalnum"]=wasmExports["isalnum"])(a0);var _toupper=Module["_toupper"]=a0=>(_toupper=Module["_toupper"]=wasmExports["toupper"])(a0);var _clock_settime=Module["_clock_settime"]=(a0,a1)=>(_clock_settime=Module["_clock_settime"]=wasmExports["clock_settime"])(a0,a1);var _pthread_getcpuclockid=Module["_pthread_getcpuclockid"]=(a0,a1)=>(_pthread_getcpuclockid=Module["_pthread_getcpuclockid"]=wasmExports["pthread_getcpuclockid"])(a0,a1);var _clock_nanosleep=Module["_clock_nanosleep"]=(a0,a1,a2,a3)=>(_clock_nanosleep=Module["_clock_nanosleep"]=wasmExports["clock_nanosleep"])(a0,a1,a2,a3);var _time=Module["_time"]=a0=>(_time=Module["_time"]=wasmExports["time"])(a0);var _mktime=Module["_mktime"]=a0=>(_mktime=Module["_mktime"]=wasmExports["mktime"])(a0);var _clock=Module["_clock"]=()=>(_clock=Module["_clock"]=wasmExports["clock"])();var _wcscoll=Module["_wcscoll"]=(a0,a1)=>(_wcscoll=Module["_wcscoll"]=wasmExports["wcscoll"])(a0,a1);var _wcsxfrm=Module["_wcsxfrm"]=(a0,a1,a2)=>(_wcsxfrm=Module["_wcsxfrm"]=wasmExports["wcsxfrm"])(a0,a1,a2);var _gettext=Module["_gettext"]=a0=>(_gettext=Module["_gettext"]=wasmExports["gettext"])(a0);var _dgettext=Module["_dgettext"]=(a0,a1)=>(_dgettext=Module["_dgettext"]=wasmExports["dgettext"])(a0,a1);var _dcgettext=Module["_dcgettext"]=(a0,a1,a2)=>(_dcgettext=Module["_dcgettext"]=wasmExports["dcgettext"])(a0,a1,a2);var _textdomain=Module["_textdomain"]=a0=>(_textdomain=Module["_textdomain"]=wasmExports["textdomain"])(a0);var _bindtextdomain=Module["_bindtextdomain"]=(a0,a1)=>(_bindtextdomain=Module["_bindtextdomain"]=wasmExports["bindtextdomain"])(a0,a1);var _bind_textdomain_codeset=Module["_bind_textdomain_codeset"]=(a0,a1)=>(_bind_textdomain_codeset=Module["_bind_textdomain_codeset"]=wasmExports["bind_textdomain_codeset"])(a0,a1);var _gettimeofday=Module["_gettimeofday"]=(a0,a1)=>(_gettimeofday=Module["_gettimeofday"]=wasmExports["gettimeofday"])(a0,a1);var ___small_fprintf=Module["___small_fprintf"]=(a0,a1,a2)=>(___small_fprintf=Module["___small_fprintf"]=wasmExports["__small_fprintf"])(a0,a1,a2);var __Py_Get_Getpath_CodeObject=Module["__Py_Get_Getpath_CodeObject"]=()=>(__Py_Get_Getpath_CodeObject=Module["__Py_Get_Getpath_CodeObject"]=wasmExports["_Py_Get_Getpath_CodeObject"])();var _ffi_prep_closure=Module["_ffi_prep_closure"]=(a0,a1,a2,a3)=>(_ffi_prep_closure=Module["_ffi_prep_closure"]=wasmExports["ffi_prep_closure"])(a0,a1,a2,a3);var _ffi_get_struct_offsets=Module["_ffi_get_struct_offsets"]=(a0,a1,a2)=>(_ffi_get_struct_offsets=Module["_ffi_get_struct_offsets"]=wasmExports["ffi_get_struct_offsets"])(a0,a1,a2);var _ffi_java_raw_size=Module["_ffi_java_raw_size"]=a0=>(_ffi_java_raw_size=Module["_ffi_java_raw_size"]=wasmExports["ffi_java_raw_size"])(a0);var _ffi_java_raw_to_ptrarray=Module["_ffi_java_raw_to_ptrarray"]=(a0,a1,a2)=>(_ffi_java_raw_to_ptrarray=Module["_ffi_java_raw_to_ptrarray"]=wasmExports["ffi_java_raw_to_ptrarray"])(a0,a1,a2);var _ffi_java_ptrarray_to_raw=Module["_ffi_java_ptrarray_to_raw"]=(a0,a1,a2)=>(_ffi_java_ptrarray_to_raw=Module["_ffi_java_ptrarray_to_raw"]=wasmExports["ffi_java_ptrarray_to_raw"])(a0,a1,a2);var _ffi_java_raw_call=Module["_ffi_java_raw_call"]=(a0,a1,a2,a3)=>(_ffi_java_raw_call=Module["_ffi_java_raw_call"]=wasmExports["ffi_java_raw_call"])(a0,a1,a2,a3);var _ffi_prep_java_raw_closure_loc=Module["_ffi_prep_java_raw_closure_loc"]=(a0,a1,a2,a3,a4)=>(_ffi_prep_java_raw_closure_loc=Module["_ffi_prep_java_raw_closure_loc"]=wasmExports["ffi_prep_java_raw_closure_loc"])(a0,a1,a2,a3,a4);var _ffi_prep_java_raw_closure=Module["_ffi_prep_java_raw_closure"]=(a0,a1,a2,a3)=>(_ffi_prep_java_raw_closure=Module["_ffi_prep_java_raw_closure"]=wasmExports["ffi_prep_java_raw_closure"])(a0,a1,a2,a3);var _ffi_tramp_is_supported=Module["_ffi_tramp_is_supported"]=()=>(_ffi_tramp_is_supported=Module["_ffi_tramp_is_supported"]=wasmExports["ffi_tramp_is_supported"])();var _ffi_tramp_alloc=Module["_ffi_tramp_alloc"]=a0=>(_ffi_tramp_alloc=Module["_ffi_tramp_alloc"]=wasmExports["ffi_tramp_alloc"])(a0);var _ffi_tramp_set_parms=Module["_ffi_tramp_set_parms"]=(a0,a1,a2)=>(_ffi_tramp_set_parms=Module["_ffi_tramp_set_parms"]=wasmExports["ffi_tramp_set_parms"])(a0,a1,a2);var _ffi_tramp_get_addr=Module["_ffi_tramp_get_addr"]=a0=>(_ffi_tramp_get_addr=Module["_ffi_tramp_get_addr"]=wasmExports["ffi_tramp_get_addr"])(a0);var _ffi_tramp_free=Module["_ffi_tramp_free"]=a0=>(_ffi_tramp_free=Module["_ffi_tramp_free"]=wasmExports["ffi_tramp_free"])(a0);var __hiwire_immortal_get=Module["__hiwire_immortal_get"]=a0=>(__hiwire_immortal_get=Module["__hiwire_immortal_get"]=wasmExports["_hiwire_immortal_get"])(a0);var __hiwire_get=Module["__hiwire_get"]=a0=>(__hiwire_get=Module["__hiwire_get"]=wasmExports["_hiwire_get"])(a0);var __hiwire_immortal_add=Module["__hiwire_immortal_add"]=a0=>(__hiwire_immortal_add=Module["__hiwire_immortal_add"]=wasmExports["_hiwire_immortal_add"])(a0);var __hiwire_table_init=Module["__hiwire_table_init"]=()=>(__hiwire_table_init=Module["__hiwire_table_init"]=wasmExports["_hiwire_table_init"])();var __hiwire_set=Module["__hiwire_set"]=(a0,a1)=>(__hiwire_set=Module["__hiwire_set"]=wasmExports["_hiwire_set"])(a0,a1);var _hiwire_num_refs=Module["_hiwire_num_refs"]=()=>(_hiwire_num_refs=Module["_hiwire_num_refs"]=wasmExports["hiwire_num_refs"])();var __hiwire_slot_info=Module["__hiwire_slot_info"]=a0=>(__hiwire_slot_info=Module["__hiwire_slot_info"]=wasmExports["_hiwire_slot_info"])(a0);var __hiwire_delete=Module["__hiwire_delete"]=a0=>(__hiwire_delete=Module["__hiwire_delete"]=wasmExports["_hiwire_delete"])(a0);var __hiwire_immortal_table_init=Module["__hiwire_immortal_table_init"]=()=>(__hiwire_immortal_table_init=Module["__hiwire_immortal_table_init"]=wasmExports["_hiwire_immortal_table_init"])();var _emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=a0=>(_emscripten_GetProcAddress=Module["_emscripten_GetProcAddress"]=wasmExports["emscripten_GetProcAddress"])(a0);var _emscripten_webgl1_get_proc_address=Module["_emscripten_webgl1_get_proc_address"]=a0=>(_emscripten_webgl1_get_proc_address=Module["_emscripten_webgl1_get_proc_address"]=wasmExports["emscripten_webgl1_get_proc_address"])(a0);var __webgl1_match_ext_proc_address_without_suffix=Module["__webgl1_match_ext_proc_address_without_suffix"]=a0=>(__webgl1_match_ext_proc_address_without_suffix=Module["__webgl1_match_ext_proc_address_without_suffix"]=wasmExports["_webgl1_match_ext_proc_address_without_suffix"])(a0);var _emscripten_webgl_get_proc_address=Module["_emscripten_webgl_get_proc_address"]=a0=>(_emscripten_webgl_get_proc_address=Module["_emscripten_webgl_get_proc_address"]=wasmExports["emscripten_webgl_get_proc_address"])(a0);var _SDL_GL_GetProcAddress=Module["_SDL_GL_GetProcAddress"]=a0=>(_SDL_GL_GetProcAddress=Module["_SDL_GL_GetProcAddress"]=wasmExports["SDL_GL_GetProcAddress"])(a0);var _eglGetProcAddress=Module["_eglGetProcAddress"]=a0=>(_eglGetProcAddress=Module["_eglGetProcAddress"]=wasmExports["eglGetProcAddress"])(a0);var _glfwGetProcAddress=Module["_glfwGetProcAddress"]=a0=>(_glfwGetProcAddress=Module["_glfwGetProcAddress"]=wasmExports["glfwGetProcAddress"])(a0);var _emscripten_webgl_init_context_attributes=Module["_emscripten_webgl_init_context_attributes"]=a0=>(_emscripten_webgl_init_context_attributes=Module["_emscripten_webgl_init_context_attributes"]=wasmExports["emscripten_webgl_init_context_attributes"])(a0);var _emscripten_is_main_runtime_thread=Module["_emscripten_is_main_runtime_thread"]=()=>(_emscripten_is_main_runtime_thread=Module["_emscripten_is_main_runtime_thread"]=wasmExports["emscripten_is_main_runtime_thread"])();var _adler32_z=Module["_adler32_z"]=(a0,a1,a2)=>(_adler32_z=Module["_adler32_z"]=wasmExports["adler32_z"])(a0,a1,a2);var _adler32_combine=Module["_adler32_combine"]=(a0,a1,a2)=>(_adler32_combine=Module["_adler32_combine"]=wasmExports["adler32_combine"])(a0,a1,a2);var _adler32_combine64=Module["_adler32_combine64"]=(a0,a1,a2)=>(_adler32_combine64=Module["_adler32_combine64"]=wasmExports["adler32_combine64"])(a0,a1,a2);var _compress2=Module["_compress2"]=(a0,a1,a2,a3,a4)=>(_compress2=Module["_compress2"]=wasmExports["compress2"])(a0,a1,a2,a3,a4);var _deflateInit_=Module["_deflateInit_"]=(a0,a1,a2,a3)=>(_deflateInit_=Module["_deflateInit_"]=wasmExports["deflateInit_"])(a0,a1,a2,a3);var _compress=Module["_compress"]=(a0,a1,a2,a3)=>(_compress=Module["_compress"]=wasmExports["compress"])(a0,a1,a2,a3);var _compressBound=Module["_compressBound"]=a0=>(_compressBound=Module["_compressBound"]=wasmExports["compressBound"])(a0);var _get_crc_table=Module["_get_crc_table"]=()=>(_get_crc_table=Module["_get_crc_table"]=wasmExports["get_crc_table"])();var _crc32_z=Module["_crc32_z"]=(a0,a1,a2)=>(_crc32_z=Module["_crc32_z"]=wasmExports["crc32_z"])(a0,a1,a2);var _crc32_combine64=Module["_crc32_combine64"]=(a0,a1,a2)=>(_crc32_combine64=Module["_crc32_combine64"]=wasmExports["crc32_combine64"])(a0,a1,a2);var _crc32_combine=Module["_crc32_combine"]=(a0,a1,a2)=>(_crc32_combine=Module["_crc32_combine"]=wasmExports["crc32_combine"])(a0,a1,a2);var _crc32_combine_gen64=Module["_crc32_combine_gen64"]=a0=>(_crc32_combine_gen64=Module["_crc32_combine_gen64"]=wasmExports["crc32_combine_gen64"])(a0);var _crc32_combine_gen=Module["_crc32_combine_gen"]=a0=>(_crc32_combine_gen=Module["_crc32_combine_gen"]=wasmExports["crc32_combine_gen"])(a0);var _crc32_combine_op=Module["_crc32_combine_op"]=(a0,a1,a2)=>(_crc32_combine_op=Module["_crc32_combine_op"]=wasmExports["crc32_combine_op"])(a0,a1,a2);var _zcalloc=Module["_zcalloc"]=(a0,a1,a2)=>(_zcalloc=Module["_zcalloc"]=wasmExports["zcalloc"])(a0,a1,a2);var _zcfree=Module["_zcfree"]=(a0,a1)=>(_zcfree=Module["_zcfree"]=wasmExports["zcfree"])(a0,a1);var _deflateReset=Module["_deflateReset"]=a0=>(_deflateReset=Module["_deflateReset"]=wasmExports["deflateReset"])(a0);var _deflateResetKeep=Module["_deflateResetKeep"]=a0=>(_deflateResetKeep=Module["_deflateResetKeep"]=wasmExports["deflateResetKeep"])(a0);var _deflateGetDictionary=Module["_deflateGetDictionary"]=(a0,a1,a2)=>(_deflateGetDictionary=Module["_deflateGetDictionary"]=wasmExports["deflateGetDictionary"])(a0,a1,a2);var __tr_init=Module["__tr_init"]=a0=>(__tr_init=Module["__tr_init"]=wasmExports["_tr_init"])(a0);var _deflateSetHeader=Module["_deflateSetHeader"]=(a0,a1)=>(_deflateSetHeader=Module["_deflateSetHeader"]=wasmExports["deflateSetHeader"])(a0,a1);var _deflatePending=Module["_deflatePending"]=(a0,a1,a2)=>(_deflatePending=Module["_deflatePending"]=wasmExports["deflatePending"])(a0,a1,a2);var _deflatePrime=Module["_deflatePrime"]=(a0,a1,a2)=>(_deflatePrime=Module["_deflatePrime"]=wasmExports["deflatePrime"])(a0,a1,a2);var __tr_flush_bits=Module["__tr_flush_bits"]=a0=>(__tr_flush_bits=Module["__tr_flush_bits"]=wasmExports["_tr_flush_bits"])(a0);var _deflateParams=Module["_deflateParams"]=(a0,a1,a2)=>(_deflateParams=Module["_deflateParams"]=wasmExports["deflateParams"])(a0,a1,a2);var __tr_align=Module["__tr_align"]=a0=>(__tr_align=Module["__tr_align"]=wasmExports["_tr_align"])(a0);var __tr_stored_block=Module["__tr_stored_block"]=(a0,a1,a2,a3)=>(__tr_stored_block=Module["__tr_stored_block"]=wasmExports["_tr_stored_block"])(a0,a1,a2,a3);var _deflateTune=Module["_deflateTune"]=(a0,a1,a2,a3,a4)=>(_deflateTune=Module["_deflateTune"]=wasmExports["deflateTune"])(a0,a1,a2,a3,a4);var _deflateBound=Module["_deflateBound"]=(a0,a1)=>(_deflateBound=Module["_deflateBound"]=wasmExports["deflateBound"])(a0,a1);var __tr_flush_block=Module["__tr_flush_block"]=(a0,a1,a2,a3)=>(__tr_flush_block=Module["__tr_flush_block"]=wasmExports["_tr_flush_block"])(a0,a1,a2,a3);var _gzclose=Module["_gzclose"]=a0=>(_gzclose=Module["_gzclose"]=wasmExports["gzclose"])(a0);var _gzclose_r=Module["_gzclose_r"]=a0=>(_gzclose_r=Module["_gzclose_r"]=wasmExports["gzclose_r"])(a0);var _gzclose_w=Module["_gzclose_w"]=a0=>(_gzclose_w=Module["_gzclose_w"]=wasmExports["gzclose_w"])(a0);var _gzopen=Module["_gzopen"]=(a0,a1)=>(_gzopen=Module["_gzopen"]=wasmExports["gzopen"])(a0,a1);var _gzopen64=Module["_gzopen64"]=(a0,a1)=>(_gzopen64=Module["_gzopen64"]=wasmExports["gzopen64"])(a0,a1);var _gzdopen=Module["_gzdopen"]=(a0,a1)=>(_gzdopen=Module["_gzdopen"]=wasmExports["gzdopen"])(a0,a1);var _gzbuffer=Module["_gzbuffer"]=(a0,a1)=>(_gzbuffer=Module["_gzbuffer"]=wasmExports["gzbuffer"])(a0,a1);var _gzrewind=Module["_gzrewind"]=a0=>(_gzrewind=Module["_gzrewind"]=wasmExports["gzrewind"])(a0);var _gzseek64=Module["_gzseek64"]=(a0,a1,a2)=>(_gzseek64=Module["_gzseek64"]=wasmExports["gzseek64"])(a0,a1,a2);var _gz_error=Module["_gz_error"]=(a0,a1,a2)=>(_gz_error=Module["_gz_error"]=wasmExports["gz_error"])(a0,a1,a2);var _gzseek=Module["_gzseek"]=(a0,a1,a2)=>(_gzseek=Module["_gzseek"]=wasmExports["gzseek"])(a0,a1,a2);var _gztell64=Module["_gztell64"]=a0=>(_gztell64=Module["_gztell64"]=wasmExports["gztell64"])(a0);var _gztell=Module["_gztell"]=a0=>(_gztell=Module["_gztell"]=wasmExports["gztell"])(a0);var _gzoffset64=Module["_gzoffset64"]=a0=>(_gzoffset64=Module["_gzoffset64"]=wasmExports["gzoffset64"])(a0);var _gzoffset=Module["_gzoffset"]=a0=>(_gzoffset=Module["_gzoffset"]=wasmExports["gzoffset"])(a0);var _gzeof=Module["_gzeof"]=a0=>(_gzeof=Module["_gzeof"]=wasmExports["gzeof"])(a0);var _gzerror=Module["_gzerror"]=(a0,a1)=>(_gzerror=Module["_gzerror"]=wasmExports["gzerror"])(a0,a1);var _gzclearerr=Module["_gzclearerr"]=a0=>(_gzclearerr=Module["_gzclearerr"]=wasmExports["gzclearerr"])(a0);var _gzread=Module["_gzread"]=(a0,a1,a2)=>(_gzread=Module["_gzread"]=wasmExports["gzread"])(a0,a1,a2);var _gzfread=Module["_gzfread"]=(a0,a1,a2,a3)=>(_gzfread=Module["_gzfread"]=wasmExports["gzfread"])(a0,a1,a2,a3);var _gzgetc=Module["_gzgetc"]=a0=>(_gzgetc=Module["_gzgetc"]=wasmExports["gzgetc"])(a0);var _gzgetc_=Module["_gzgetc_"]=a0=>(_gzgetc_=Module["_gzgetc_"]=wasmExports["gzgetc_"])(a0);var _gzungetc=Module["_gzungetc"]=(a0,a1)=>(_gzungetc=Module["_gzungetc"]=wasmExports["gzungetc"])(a0,a1);var _gzgets=Module["_gzgets"]=(a0,a1,a2)=>(_gzgets=Module["_gzgets"]=wasmExports["gzgets"])(a0,a1,a2);var _gzdirect=Module["_gzdirect"]=a0=>(_gzdirect=Module["_gzdirect"]=wasmExports["gzdirect"])(a0);var _inflateReset=Module["_inflateReset"]=a0=>(_inflateReset=Module["_inflateReset"]=wasmExports["inflateReset"])(a0);var _gzwrite=Module["_gzwrite"]=(a0,a1,a2)=>(_gzwrite=Module["_gzwrite"]=wasmExports["gzwrite"])(a0,a1,a2);var _gzfwrite=Module["_gzfwrite"]=(a0,a1,a2,a3)=>(_gzfwrite=Module["_gzfwrite"]=wasmExports["gzfwrite"])(a0,a1,a2,a3);var _gzputc=Module["_gzputc"]=(a0,a1)=>(_gzputc=Module["_gzputc"]=wasmExports["gzputc"])(a0,a1);var _gzputs=Module["_gzputs"]=(a0,a1)=>(_gzputs=Module["_gzputs"]=wasmExports["gzputs"])(a0,a1);var _gzvprintf=Module["_gzvprintf"]=(a0,a1,a2)=>(_gzvprintf=Module["_gzvprintf"]=wasmExports["gzvprintf"])(a0,a1,a2);var _gzprintf=Module["_gzprintf"]=(a0,a1,a2)=>(_gzprintf=Module["_gzprintf"]=wasmExports["gzprintf"])(a0,a1,a2);var _gzflush=Module["_gzflush"]=(a0,a1)=>(_gzflush=Module["_gzflush"]=wasmExports["gzflush"])(a0,a1);var _gzsetparams=Module["_gzsetparams"]=(a0,a1,a2)=>(_gzsetparams=Module["_gzsetparams"]=wasmExports["gzsetparams"])(a0,a1,a2);var _inflateBackInit_=Module["_inflateBackInit_"]=(a0,a1,a2,a3,a4)=>(_inflateBackInit_=Module["_inflateBackInit_"]=wasmExports["inflateBackInit_"])(a0,a1,a2,a3,a4);var _inflateBack=Module["_inflateBack"]=(a0,a1,a2,a3,a4)=>(_inflateBack=Module["_inflateBack"]=wasmExports["inflateBack"])(a0,a1,a2,a3,a4);var _inflate_table=Module["_inflate_table"]=(a0,a1,a2,a3,a4,a5)=>(_inflate_table=Module["_inflate_table"]=wasmExports["inflate_table"])(a0,a1,a2,a3,a4,a5);var _inflate_fast=Module["_inflate_fast"]=(a0,a1)=>(_inflate_fast=Module["_inflate_fast"]=wasmExports["inflate_fast"])(a0,a1);var _inflateBackEnd=Module["_inflateBackEnd"]=a0=>(_inflateBackEnd=Module["_inflateBackEnd"]=wasmExports["inflateBackEnd"])(a0);var _inflateResetKeep=Module["_inflateResetKeep"]=a0=>(_inflateResetKeep=Module["_inflateResetKeep"]=wasmExports["inflateResetKeep"])(a0);var _inflateReset2=Module["_inflateReset2"]=(a0,a1)=>(_inflateReset2=Module["_inflateReset2"]=wasmExports["inflateReset2"])(a0,a1);var _inflateInit_=Module["_inflateInit_"]=(a0,a1,a2)=>(_inflateInit_=Module["_inflateInit_"]=wasmExports["inflateInit_"])(a0,a1,a2);var _inflatePrime=Module["_inflatePrime"]=(a0,a1,a2)=>(_inflatePrime=Module["_inflatePrime"]=wasmExports["inflatePrime"])(a0,a1,a2);var _inflateGetDictionary=Module["_inflateGetDictionary"]=(a0,a1,a2)=>(_inflateGetDictionary=Module["_inflateGetDictionary"]=wasmExports["inflateGetDictionary"])(a0,a1,a2);var _inflateGetHeader=Module["_inflateGetHeader"]=(a0,a1)=>(_inflateGetHeader=Module["_inflateGetHeader"]=wasmExports["inflateGetHeader"])(a0,a1);var _inflateSync=Module["_inflateSync"]=a0=>(_inflateSync=Module["_inflateSync"]=wasmExports["inflateSync"])(a0);var _inflateSyncPoint=Module["_inflateSyncPoint"]=a0=>(_inflateSyncPoint=Module["_inflateSyncPoint"]=wasmExports["inflateSyncPoint"])(a0);var _inflateUndermine=Module["_inflateUndermine"]=(a0,a1)=>(_inflateUndermine=Module["_inflateUndermine"]=wasmExports["inflateUndermine"])(a0,a1);var _inflateValidate=Module["_inflateValidate"]=(a0,a1)=>(_inflateValidate=Module["_inflateValidate"]=wasmExports["inflateValidate"])(a0,a1);var _inflateMark=Module["_inflateMark"]=a0=>(_inflateMark=Module["_inflateMark"]=wasmExports["inflateMark"])(a0);var _inflateCodesUsed=Module["_inflateCodesUsed"]=a0=>(_inflateCodesUsed=Module["_inflateCodesUsed"]=wasmExports["inflateCodesUsed"])(a0);var __tr_tally=Module["__tr_tally"]=(a0,a1,a2)=>(__tr_tally=Module["__tr_tally"]=wasmExports["_tr_tally"])(a0,a1,a2);var _uncompress2=Module["_uncompress2"]=(a0,a1,a2,a3)=>(_uncompress2=Module["_uncompress2"]=wasmExports["uncompress2"])(a0,a1,a2,a3);var _uncompress=Module["_uncompress"]=(a0,a1,a2,a3)=>(_uncompress=Module["_uncompress"]=wasmExports["uncompress"])(a0,a1,a2,a3);var _zlibCompileFlags=Module["_zlibCompileFlags"]=()=>(_zlibCompileFlags=Module["_zlibCompileFlags"]=wasmExports["zlibCompileFlags"])();var _zError=Module["_zError"]=a0=>(_zError=Module["_zError"]=wasmExports["zError"])(a0);var _BZ2_blockSort=Module["_BZ2_blockSort"]=a0=>(_BZ2_blockSort=Module["_BZ2_blockSort"]=wasmExports["BZ2_blockSort"])(a0);var _BZ2_bz__AssertH__fail=Module["_BZ2_bz__AssertH__fail"]=a0=>(_BZ2_bz__AssertH__fail=Module["_BZ2_bz__AssertH__fail"]=wasmExports["BZ2_bz__AssertH__fail"])(a0);var _BZ2_bzlibVersion=Module["_BZ2_bzlibVersion"]=()=>(_BZ2_bzlibVersion=Module["_BZ2_bzlibVersion"]=wasmExports["BZ2_bzlibVersion"])();var _BZ2_compressBlock=Module["_BZ2_compressBlock"]=(a0,a1)=>(_BZ2_compressBlock=Module["_BZ2_compressBlock"]=wasmExports["BZ2_compressBlock"])(a0,a1);var _BZ2_indexIntoF=Module["_BZ2_indexIntoF"]=(a0,a1)=>(_BZ2_indexIntoF=Module["_BZ2_indexIntoF"]=wasmExports["BZ2_indexIntoF"])(a0,a1);var _BZ2_decompress=Module["_BZ2_decompress"]=a0=>(_BZ2_decompress=Module["_BZ2_decompress"]=wasmExports["BZ2_decompress"])(a0);var _BZ2_bzWriteOpen=Module["_BZ2_bzWriteOpen"]=(a0,a1,a2,a3,a4)=>(_BZ2_bzWriteOpen=Module["_BZ2_bzWriteOpen"]=wasmExports["BZ2_bzWriteOpen"])(a0,a1,a2,a3,a4);var _BZ2_bzWrite=Module["_BZ2_bzWrite"]=(a0,a1,a2,a3)=>(_BZ2_bzWrite=Module["_BZ2_bzWrite"]=wasmExports["BZ2_bzWrite"])(a0,a1,a2,a3);var _BZ2_bzWriteClose=Module["_BZ2_bzWriteClose"]=(a0,a1,a2,a3,a4)=>(_BZ2_bzWriteClose=Module["_BZ2_bzWriteClose"]=wasmExports["BZ2_bzWriteClose"])(a0,a1,a2,a3,a4);var _BZ2_bzWriteClose64=Module["_BZ2_bzWriteClose64"]=(a0,a1,a2,a3,a4,a5,a6)=>(_BZ2_bzWriteClose64=Module["_BZ2_bzWriteClose64"]=wasmExports["BZ2_bzWriteClose64"])(a0,a1,a2,a3,a4,a5,a6);var _BZ2_bzReadOpen=Module["_BZ2_bzReadOpen"]=(a0,a1,a2,a3,a4,a5)=>(_BZ2_bzReadOpen=Module["_BZ2_bzReadOpen"]=wasmExports["BZ2_bzReadOpen"])(a0,a1,a2,a3,a4,a5);var _BZ2_bzReadClose=Module["_BZ2_bzReadClose"]=(a0,a1)=>(_BZ2_bzReadClose=Module["_BZ2_bzReadClose"]=wasmExports["BZ2_bzReadClose"])(a0,a1);var _BZ2_bzRead=Module["_BZ2_bzRead"]=(a0,a1,a2,a3)=>(_BZ2_bzRead=Module["_BZ2_bzRead"]=wasmExports["BZ2_bzRead"])(a0,a1,a2,a3);var _fgetc=Module["_fgetc"]=a0=>(_fgetc=Module["_fgetc"]=wasmExports["fgetc"])(a0);var _BZ2_bzReadGetUnused=Module["_BZ2_bzReadGetUnused"]=(a0,a1,a2,a3)=>(_BZ2_bzReadGetUnused=Module["_BZ2_bzReadGetUnused"]=wasmExports["BZ2_bzReadGetUnused"])(a0,a1,a2,a3);var _BZ2_bzBuffToBuffCompress=Module["_BZ2_bzBuffToBuffCompress"]=(a0,a1,a2,a3,a4,a5,a6)=>(_BZ2_bzBuffToBuffCompress=Module["_BZ2_bzBuffToBuffCompress"]=wasmExports["BZ2_bzBuffToBuffCompress"])(a0,a1,a2,a3,a4,a5,a6);var _BZ2_bzBuffToBuffDecompress=Module["_BZ2_bzBuffToBuffDecompress"]=(a0,a1,a2,a3,a4,a5)=>(_BZ2_bzBuffToBuffDecompress=Module["_BZ2_bzBuffToBuffDecompress"]=wasmExports["BZ2_bzBuffToBuffDecompress"])(a0,a1,a2,a3,a4,a5);var _BZ2_bzopen=Module["_BZ2_bzopen"]=(a0,a1)=>(_BZ2_bzopen=Module["_BZ2_bzopen"]=wasmExports["BZ2_bzopen"])(a0,a1);var _BZ2_bzdopen=Module["_BZ2_bzdopen"]=(a0,a1)=>(_BZ2_bzdopen=Module["_BZ2_bzdopen"]=wasmExports["BZ2_bzdopen"])(a0,a1);var _BZ2_bzread=Module["_BZ2_bzread"]=(a0,a1,a2)=>(_BZ2_bzread=Module["_BZ2_bzread"]=wasmExports["BZ2_bzread"])(a0,a1,a2);var _BZ2_bzwrite=Module["_BZ2_bzwrite"]=(a0,a1,a2)=>(_BZ2_bzwrite=Module["_BZ2_bzwrite"]=wasmExports["BZ2_bzwrite"])(a0,a1,a2);var _BZ2_bzflush=Module["_BZ2_bzflush"]=a0=>(_BZ2_bzflush=Module["_BZ2_bzflush"]=wasmExports["BZ2_bzflush"])(a0);var _BZ2_bzclose=Module["_BZ2_bzclose"]=a0=>(_BZ2_bzclose=Module["_BZ2_bzclose"]=wasmExports["BZ2_bzclose"])(a0);var _BZ2_bzerror=Module["_BZ2_bzerror"]=(a0,a1)=>(_BZ2_bzerror=Module["_BZ2_bzerror"]=wasmExports["BZ2_bzerror"])(a0,a1);var _BZ2_bsInitWrite=Module["_BZ2_bsInitWrite"]=a0=>(_BZ2_bsInitWrite=Module["_BZ2_bsInitWrite"]=wasmExports["BZ2_bsInitWrite"])(a0);var _BZ2_hbMakeCodeLengths=Module["_BZ2_hbMakeCodeLengths"]=(a0,a1,a2,a3)=>(_BZ2_hbMakeCodeLengths=Module["_BZ2_hbMakeCodeLengths"]=wasmExports["BZ2_hbMakeCodeLengths"])(a0,a1,a2,a3);var _BZ2_hbAssignCodes=Module["_BZ2_hbAssignCodes"]=(a0,a1,a2,a3,a4)=>(_BZ2_hbAssignCodes=Module["_BZ2_hbAssignCodes"]=wasmExports["BZ2_hbAssignCodes"])(a0,a1,a2,a3,a4);var _BZ2_hbCreateDecodeTables=Module["_BZ2_hbCreateDecodeTables"]=(a0,a1,a2,a3,a4,a5,a6)=>(_BZ2_hbCreateDecodeTables=Module["_BZ2_hbCreateDecodeTables"]=wasmExports["BZ2_hbCreateDecodeTables"])(a0,a1,a2,a3,a4,a5,a6);var __emscripten_memcpy_bulkmem=Module["__emscripten_memcpy_bulkmem"]=(a0,a1,a2)=>(__emscripten_memcpy_bulkmem=Module["__emscripten_memcpy_bulkmem"]=wasmExports["_emscripten_memcpy_bulkmem"])(a0,a1,a2);var _emscripten_builtin_memcpy=Module["_emscripten_builtin_memcpy"]=(a0,a1,a2)=>(_emscripten_builtin_memcpy=Module["_emscripten_builtin_memcpy"]=wasmExports["emscripten_builtin_memcpy"])(a0,a1,a2);var ___memset=Module["___memset"]=(a0,a1,a2)=>(___memset=Module["___memset"]=wasmExports["__memset"])(a0,a1,a2);var __emscripten_memset_bulkmem=Module["__emscripten_memset_bulkmem"]=(a0,a1,a2)=>(__emscripten_memset_bulkmem=Module["__emscripten_memset_bulkmem"]=wasmExports["_emscripten_memset_bulkmem"])(a0,a1,a2);var _emscripten_builtin_memset=Module["_emscripten_builtin_memset"]=(a0,a1,a2)=>(_emscripten_builtin_memset=Module["_emscripten_builtin_memset"]=wasmExports["emscripten_builtin_memset"])(a0,a1,a2);var _getdate=Module["_getdate"]=a0=>(_getdate=Module["_getdate"]=wasmExports["getdate"])(a0);var _stime=Module["_stime"]=a0=>(_stime=Module["_stime"]=wasmExports["stime"])(a0);var _clock_getcpuclockid=Module["_clock_getcpuclockid"]=(a0,a1)=>(_clock_getcpuclockid=Module["_clock_getcpuclockid"]=wasmExports["clock_getcpuclockid"])(a0,a1);var _getpwnam=Module["_getpwnam"]=a0=>(_getpwnam=Module["_getpwnam"]=wasmExports["getpwnam"])(a0);var _getpwuid=Module["_getpwuid"]=a0=>(_getpwuid=Module["_getpwuid"]=wasmExports["getpwuid"])(a0);var _getpwnam_r=Module["_getpwnam_r"]=(a0,a1,a2,a3,a4)=>(_getpwnam_r=Module["_getpwnam_r"]=wasmExports["getpwnam_r"])(a0,a1,a2,a3,a4);var _getpwuid_r=Module["_getpwuid_r"]=(a0,a1,a2,a3,a4)=>(_getpwuid_r=Module["_getpwuid_r"]=wasmExports["getpwuid_r"])(a0,a1,a2,a3,a4);var _setpwent=Module["_setpwent"]=()=>(_setpwent=Module["_setpwent"]=wasmExports["setpwent"])();var _endpwent=Module["_endpwent"]=()=>(_endpwent=Module["_endpwent"]=wasmExports["endpwent"])();var _getpwent=Module["_getpwent"]=()=>(_getpwent=Module["_getpwent"]=wasmExports["getpwent"])();var _getgrnam=Module["_getgrnam"]=a0=>(_getgrnam=Module["_getgrnam"]=wasmExports["getgrnam"])(a0);var _getgrgid=Module["_getgrgid"]=a0=>(_getgrgid=Module["_getgrgid"]=wasmExports["getgrgid"])(a0);var _getgrnam_r=Module["_getgrnam_r"]=(a0,a1,a2,a3,a4)=>(_getgrnam_r=Module["_getgrnam_r"]=wasmExports["getgrnam_r"])(a0,a1,a2,a3,a4);var _getgrgid_r=Module["_getgrgid_r"]=(a0,a1,a2,a3,a4)=>(_getgrgid_r=Module["_getgrgid_r"]=wasmExports["getgrgid_r"])(a0,a1,a2,a3,a4);var _getgrent=Module["_getgrent"]=()=>(_getgrent=Module["_getgrent"]=wasmExports["getgrent"])();var _endgrent=Module["_endgrent"]=()=>(_endgrent=Module["_endgrent"]=wasmExports["endgrent"])();var _setgrent=Module["_setgrent"]=()=>(_setgrent=Module["_setgrent"]=wasmExports["setgrent"])();var _flock=Module["_flock"]=(a0,a1)=>(_flock=Module["_flock"]=wasmExports["flock"])(a0,a1);var _vfork=Module["_vfork"]=()=>(_vfork=Module["_vfork"]=wasmExports["vfork"])();var _posix_spawn=Module["_posix_spawn"]=(a0,a1,a2,a3,a4,a5)=>(_posix_spawn=Module["_posix_spawn"]=wasmExports["posix_spawn"])(a0,a1,a2,a3,a4,a5);var _popen=Module["_popen"]=(a0,a1)=>(_popen=Module["_popen"]=wasmExports["popen"])(a0,a1);var _pclose=Module["_pclose"]=a0=>(_pclose=Module["_pclose"]=wasmExports["pclose"])(a0);var _setgroups=Module["_setgroups"]=(a0,a1)=>(_setgroups=Module["_setgroups"]=wasmExports["setgroups"])(a0,a1);var _sigaltstack=Module["_sigaltstack"]=(a0,a1)=>(_sigaltstack=Module["_sigaltstack"]=wasmExports["sigaltstack"])(a0,a1);var ___syscall_uname=Module["___syscall_uname"]=a0=>(___syscall_uname=Module["___syscall_uname"]=wasmExports["__syscall_uname"])(a0);var ___syscall_setpgid=Module["___syscall_setpgid"]=(a0,a1)=>(___syscall_setpgid=Module["___syscall_setpgid"]=wasmExports["__syscall_setpgid"])(a0,a1);var ___syscall_sync=Module["___syscall_sync"]=()=>(___syscall_sync=Module["___syscall_sync"]=wasmExports["__syscall_sync"])();var ___syscall_getsid=Module["___syscall_getsid"]=a0=>(___syscall_getsid=Module["___syscall_getsid"]=wasmExports["__syscall_getsid"])(a0);var ___syscall_getpgid=Module["___syscall_getpgid"]=a0=>(___syscall_getpgid=Module["___syscall_getpgid"]=wasmExports["__syscall_getpgid"])(a0);var ___syscall_getpid=Module["___syscall_getpid"]=()=>(___syscall_getpid=Module["___syscall_getpid"]=wasmExports["__syscall_getpid"])();var ___syscall_getppid=Module["___syscall_getppid"]=()=>(___syscall_getppid=Module["___syscall_getppid"]=wasmExports["__syscall_getppid"])();var ___syscall_linkat=Module["___syscall_linkat"]=(a0,a1,a2,a3,a4)=>(___syscall_linkat=Module["___syscall_linkat"]=wasmExports["__syscall_linkat"])(a0,a1,a2,a3,a4);var ___syscall_getgroups32=Module["___syscall_getgroups32"]=(a0,a1)=>(___syscall_getgroups32=Module["___syscall_getgroups32"]=wasmExports["__syscall_getgroups32"])(a0,a1);var ___syscall_setsid=Module["___syscall_setsid"]=()=>(___syscall_setsid=Module["___syscall_setsid"]=wasmExports["__syscall_setsid"])();var ___syscall_umask=Module["___syscall_umask"]=a0=>(___syscall_umask=Module["___syscall_umask"]=wasmExports["__syscall_umask"])(a0);var ___syscall_setrlimit=Module["___syscall_setrlimit"]=(a0,a1)=>(___syscall_setrlimit=Module["___syscall_setrlimit"]=wasmExports["__syscall_setrlimit"])(a0,a1);var ___syscall_getrusage=Module["___syscall_getrusage"]=(a0,a1)=>(___syscall_getrusage=Module["___syscall_getrusage"]=wasmExports["__syscall_getrusage"])(a0,a1);var ___syscall_getpriority=Module["___syscall_getpriority"]=(a0,a1)=>(___syscall_getpriority=Module["___syscall_getpriority"]=wasmExports["__syscall_getpriority"])(a0,a1);var ___syscall_setpriority=Module["___syscall_setpriority"]=(a0,a1,a2)=>(___syscall_setpriority=Module["___syscall_setpriority"]=wasmExports["__syscall_setpriority"])(a0,a1,a2);var ___syscall_setdomainname=Module["___syscall_setdomainname"]=(a0,a1)=>(___syscall_setdomainname=Module["___syscall_setdomainname"]=wasmExports["__syscall_setdomainname"])(a0,a1);var ___syscall_getuid32=Module["___syscall_getuid32"]=()=>(___syscall_getuid32=Module["___syscall_getuid32"]=wasmExports["__syscall_getuid32"])();var ___syscall_getgid32=Module["___syscall_getgid32"]=()=>(___syscall_getgid32=Module["___syscall_getgid32"]=wasmExports["__syscall_getgid32"])();var ___syscall_geteuid32=Module["___syscall_geteuid32"]=()=>(___syscall_geteuid32=Module["___syscall_geteuid32"]=wasmExports["__syscall_geteuid32"])();var ___syscall_getegid32=Module["___syscall_getegid32"]=()=>(___syscall_getegid32=Module["___syscall_getegid32"]=wasmExports["__syscall_getegid32"])();var ___syscall_getresuid32=Module["___syscall_getresuid32"]=(a0,a1,a2)=>(___syscall_getresuid32=Module["___syscall_getresuid32"]=wasmExports["__syscall_getresuid32"])(a0,a1,a2);var ___syscall_getresgid32=Module["___syscall_getresgid32"]=(a0,a1,a2)=>(___syscall_getresgid32=Module["___syscall_getresgid32"]=wasmExports["__syscall_getresgid32"])(a0,a1,a2);var ___syscall_pause=Module["___syscall_pause"]=()=>(___syscall_pause=Module["___syscall_pause"]=wasmExports["__syscall_pause"])();var ___syscall_madvise=Module["___syscall_madvise"]=(a0,a1,a2)=>(___syscall_madvise=Module["___syscall_madvise"]=wasmExports["__syscall_madvise"])(a0,a1,a2);var ___syscall_mlock=Module["___syscall_mlock"]=(a0,a1)=>(___syscall_mlock=Module["___syscall_mlock"]=wasmExports["__syscall_mlock"])(a0,a1);var ___syscall_munlock=Module["___syscall_munlock"]=(a0,a1)=>(___syscall_munlock=Module["___syscall_munlock"]=wasmExports["__syscall_munlock"])(a0,a1);var ___syscall_mprotect=Module["___syscall_mprotect"]=(a0,a1,a2)=>(___syscall_mprotect=Module["___syscall_mprotect"]=wasmExports["__syscall_mprotect"])(a0,a1,a2);var ___syscall_mremap=Module["___syscall_mremap"]=(a0,a1,a2,a3,a4)=>(___syscall_mremap=Module["___syscall_mremap"]=wasmExports["__syscall_mremap"])(a0,a1,a2,a3,a4);var ___syscall_mlockall=Module["___syscall_mlockall"]=a0=>(___syscall_mlockall=Module["___syscall_mlockall"]=wasmExports["__syscall_mlockall"])(a0);var ___syscall_munlockall=Module["___syscall_munlockall"]=()=>(___syscall_munlockall=Module["___syscall_munlockall"]=wasmExports["__syscall_munlockall"])();var ___syscall_prlimit64=Module["___syscall_prlimit64"]=(a0,a1,a2,a3)=>(___syscall_prlimit64=Module["___syscall_prlimit64"]=wasmExports["__syscall_prlimit64"])(a0,a1,a2,a3);var ___syscall_ugetrlimit=Module["___syscall_ugetrlimit"]=(a0,a1)=>(___syscall_ugetrlimit=Module["___syscall_ugetrlimit"]=wasmExports["__syscall_ugetrlimit"])(a0,a1);var ___syscall_setsockopt=Module["___syscall_setsockopt"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_setsockopt=Module["___syscall_setsockopt"]=wasmExports["__syscall_setsockopt"])(a0,a1,a2,a3,a4,a5);var ___syscall_acct=Module["___syscall_acct"]=a0=>(___syscall_acct=Module["___syscall_acct"]=wasmExports["__syscall_acct"])(a0);var ___syscall_mincore=Module["___syscall_mincore"]=(a0,a1,a2)=>(___syscall_mincore=Module["___syscall_mincore"]=wasmExports["__syscall_mincore"])(a0,a1,a2);var ___syscall_pipe2=Module["___syscall_pipe2"]=(a0,a1)=>(___syscall_pipe2=Module["___syscall_pipe2"]=wasmExports["__syscall_pipe2"])(a0,a1);var ___syscall_pselect6=Module["___syscall_pselect6"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_pselect6=Module["___syscall_pselect6"]=wasmExports["__syscall_pselect6"])(a0,a1,a2,a3,a4,a5);var ___syscall_recvmmsg=Module["___syscall_recvmmsg"]=(a0,a1,a2,a3,a4)=>(___syscall_recvmmsg=Module["___syscall_recvmmsg"]=wasmExports["__syscall_recvmmsg"])(a0,a1,a2,a3,a4);var ___syscall_sendmmsg=Module["___syscall_sendmmsg"]=(a0,a1,a2,a3,a4)=>(___syscall_sendmmsg=Module["___syscall_sendmmsg"]=wasmExports["__syscall_sendmmsg"])(a0,a1,a2,a3,a4);var ___syscall_shutdown=Module["___syscall_shutdown"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_shutdown=Module["___syscall_shutdown"]=wasmExports["__syscall_shutdown"])(a0,a1,a2,a3,a4,a5);var ___syscall_socketpair=Module["___syscall_socketpair"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_socketpair=Module["___syscall_socketpair"]=wasmExports["__syscall_socketpair"])(a0,a1,a2,a3,a4,a5);var ___syscall_wait4=Module["___syscall_wait4"]=(a0,a1,a2,a3)=>(___syscall_wait4=Module["___syscall_wait4"]=wasmExports["__syscall_wait4"])(a0,a1,a2,a3);var _atexit=Module["_atexit"]=a0=>(_atexit=Module["_atexit"]=wasmExports["atexit"])(a0);var ___cxa_atexit=Module["___cxa_atexit"]=(a0,a1,a2)=>(___cxa_atexit=Module["___cxa_atexit"]=wasmExports["__cxa_atexit"])(a0,a1,a2);var ___cxa_finalize=Module["___cxa_finalize"]=a0=>(___cxa_finalize=Module["___cxa_finalize"]=wasmExports["__cxa_finalize"])(a0);var __Exit=Module["__Exit"]=a0=>(__Exit=Module["__Exit"]=wasmExports["_Exit"])(a0);var _cosf=Module["_cosf"]=a0=>(_cosf=Module["_cosf"]=wasmExports["cosf"])(a0);var _sinf=Module["_sinf"]=a0=>(_sinf=Module["_sinf"]=wasmExports["sinf"])(a0);var _expf=Module["_expf"]=a0=>(_expf=Module["_expf"]=wasmExports["expf"])(a0);var ___multf3=Module["___multf3"]=(a0,a1,a2,a3,a4)=>(___multf3=Module["___multf3"]=wasmExports["__multf3"])(a0,a1,a2,a3,a4);var ___addtf3=Module["___addtf3"]=(a0,a1,a2,a3,a4)=>(___addtf3=Module["___addtf3"]=wasmExports["__addtf3"])(a0,a1,a2,a3,a4);var ___subtf3=Module["___subtf3"]=(a0,a1,a2,a3,a4)=>(___subtf3=Module["___subtf3"]=wasmExports["__subtf3"])(a0,a1,a2,a3,a4);var ___ctype_b_loc=Module["___ctype_b_loc"]=()=>(___ctype_b_loc=Module["___ctype_b_loc"]=wasmExports["__ctype_b_loc"])();var ___ctype_get_mb_cur_max=Module["___ctype_get_mb_cur_max"]=()=>(___ctype_get_mb_cur_max=Module["___ctype_get_mb_cur_max"]=wasmExports["__ctype_get_mb_cur_max"])();var ___get_tp=Module["___get_tp"]=()=>(___get_tp=Module["___get_tp"]=wasmExports["__get_tp"])();var ___ctype_tolower_loc=Module["___ctype_tolower_loc"]=()=>(___ctype_tolower_loc=Module["___ctype_tolower_loc"]=wasmExports["__ctype_tolower_loc"])();var ___ctype_toupper_loc=Module["___ctype_toupper_loc"]=()=>(___ctype_toupper_loc=Module["___ctype_toupper_loc"]=wasmExports["__ctype_toupper_loc"])();var ___emscripten_environ_constructor=Module["___emscripten_environ_constructor"]=()=>(___emscripten_environ_constructor=Module["___emscripten_environ_constructor"]=wasmExports["__emscripten_environ_constructor"])();var _emscripten_builtin_malloc=Module["_emscripten_builtin_malloc"]=a0=>(_emscripten_builtin_malloc=Module["_emscripten_builtin_malloc"]=wasmExports["emscripten_builtin_malloc"])(a0);var ___flt_rounds=Module["___flt_rounds"]=()=>(___flt_rounds=Module["___flt_rounds"]=wasmExports["__flt_rounds"])();var _fegetround=Module["_fegetround"]=()=>(_fegetround=Module["_fegetround"]=wasmExports["fegetround"])();var ___fmodeflags=Module["___fmodeflags"]=a0=>(___fmodeflags=Module["___fmodeflags"]=wasmExports["__fmodeflags"])(a0);var ___fpclassify=Module["___fpclassify"]=a0=>(___fpclassify=Module["___fpclassify"]=wasmExports["__fpclassify"])(a0);var ___fpclassifyf=Module["___fpclassifyf"]=a0=>(___fpclassifyf=Module["___fpclassifyf"]=wasmExports["__fpclassifyf"])(a0);var ___fpclassifyl=Module["___fpclassifyl"]=(a0,a1)=>(___fpclassifyl=Module["___fpclassifyl"]=wasmExports["__fpclassifyl"])(a0,a1);var ___divtf3=Module["___divtf3"]=(a0,a1,a2,a3,a4)=>(___divtf3=Module["___divtf3"]=wasmExports["__divtf3"])(a0,a1,a2,a3,a4);var ___mo_lookup=Module["___mo_lookup"]=(a0,a1,a2)=>(___mo_lookup=Module["___mo_lookup"]=wasmExports["__mo_lookup"])(a0,a1,a2);var ___overflow=Module["___overflow"]=(a0,a1)=>(___overflow=Module["___overflow"]=wasmExports["__overflow"])(a0,a1);var _scalbn=Module["_scalbn"]=(a0,a1)=>(_scalbn=Module["_scalbn"]=wasmExports["scalbn"])(a0,a1);var _floor=Module["_floor"]=a0=>(_floor=Module["_floor"]=wasmExports["floor"])(a0);var ___lttf2=Module["___lttf2"]=(a0,a1,a2,a3)=>(___lttf2=Module["___lttf2"]=wasmExports["__lttf2"])(a0,a1,a2,a3);var ___fixtfdi=Module["___fixtfdi"]=(a0,a1)=>(___fixtfdi=Module["___fixtfdi"]=wasmExports["__fixtfdi"])(a0,a1);var ___gttf2=Module["___gttf2"]=(a0,a1,a2,a3)=>(___gttf2=Module["___gttf2"]=wasmExports["__gttf2"])(a0,a1,a2,a3);var ___fixtfsi=Module["___fixtfsi"]=(a0,a1)=>(___fixtfsi=Module["___fixtfsi"]=wasmExports["__fixtfsi"])(a0,a1);var ___floatsitf=Module["___floatsitf"]=(a0,a1)=>(___floatsitf=Module["___floatsitf"]=wasmExports["__floatsitf"])(a0,a1);var ___signbit=Module["___signbit"]=a0=>(___signbit=Module["___signbit"]=wasmExports["__signbit"])(a0);var ___signbitf=Module["___signbitf"]=a0=>(___signbitf=Module["___signbitf"]=wasmExports["__signbitf"])(a0);var ___signbitl=Module["___signbitl"]=(a0,a1)=>(___signbitl=Module["___signbitl"]=wasmExports["__signbitl"])(a0,a1);var ___wasi_syscall_ret=Module["___wasi_syscall_ret"]=a0=>(___wasi_syscall_ret=Module["___wasi_syscall_ret"]=wasmExports["__wasi_syscall_ret"])(a0);var ___synccall=Module["___synccall"]=(a0,a1)=>(___synccall=Module["___synccall"]=wasmExports["__synccall"])(a0,a1);var _fabsl=Module["_fabsl"]=(a0,a1,a2)=>(_fabsl=Module["_fabsl"]=wasmExports["fabsl"])(a0,a1,a2);var ___getf2=Module["___getf2"]=(a0,a1,a2,a3)=>(___getf2=Module["___getf2"]=wasmExports["__getf2"])(a0,a1,a2,a3);var ___uflow=Module["___uflow"]=a0=>(___uflow=Module["___uflow"]=wasmExports["__uflow"])(a0);var ___fxstat=Module["___fxstat"]=(a0,a1,a2)=>(___fxstat=Module["___fxstat"]=wasmExports["__fxstat"])(a0,a1,a2);var ___fxstatat=Module["___fxstatat"]=(a0,a1,a2,a3,a4)=>(___fxstatat=Module["___fxstatat"]=wasmExports["__fxstatat"])(a0,a1,a2,a3,a4);var ___lxstat=Module["___lxstat"]=(a0,a1,a2)=>(___lxstat=Module["___lxstat"]=wasmExports["__lxstat"])(a0,a1,a2);var ___xstat=Module["___xstat"]=(a0,a1,a2)=>(___xstat=Module["___xstat"]=wasmExports["__xstat"])(a0,a1,a2);var ___xmknod=Module["___xmknod"]=(a0,a1,a2,a3)=>(___xmknod=Module["___xmknod"]=wasmExports["__xmknod"])(a0,a1,a2,a3);var _mknod=Module["_mknod"]=(a0,a1,a2)=>(_mknod=Module["_mknod"]=wasmExports["mknod"])(a0,a1,a2);var ___xmknodat=Module["___xmknodat"]=(a0,a1,a2,a3,a4)=>(___xmknodat=Module["___xmknodat"]=wasmExports["__xmknodat"])(a0,a1,a2,a3,a4);var _mknodat=Module["_mknodat"]=(a0,a1,a2,a3)=>(_mknodat=Module["_mknodat"]=wasmExports["mknodat"])(a0,a1,a2,a3);var _a64l=Module["_a64l"]=a0=>(_a64l=Module["_a64l"]=wasmExports["a64l"])(a0);var _l64a=Module["_l64a"]=a0=>(_l64a=Module["_l64a"]=wasmExports["l64a"])(a0);var _abs=Module["_abs"]=a0=>(_abs=Module["_abs"]=wasmExports["abs"])(a0);var _acct=Module["_acct"]=a0=>(_acct=Module["_acct"]=wasmExports["acct"])(a0);var _acosf=Module["_acosf"]=a0=>(_acosf=Module["_acosf"]=wasmExports["acosf"])(a0);var _sqrtf=Module["_sqrtf"]=a0=>(_sqrtf=Module["_sqrtf"]=wasmExports["sqrtf"])(a0);var _acoshf=Module["_acoshf"]=a0=>(_acoshf=Module["_acoshf"]=wasmExports["acoshf"])(a0);var _log1pf=Module["_log1pf"]=a0=>(_log1pf=Module["_log1pf"]=wasmExports["log1pf"])(a0);var _logf=Module["_logf"]=a0=>(_logf=Module["_logf"]=wasmExports["logf"])(a0);var _acoshl=Module["_acoshl"]=(a0,a1,a2)=>(_acoshl=Module["_acoshl"]=wasmExports["acoshl"])(a0,a1,a2);var _acosl=Module["_acosl"]=(a0,a1,a2)=>(_acosl=Module["_acosl"]=wasmExports["acosl"])(a0,a1,a2);var ___eqtf2=Module["___eqtf2"]=(a0,a1,a2,a3)=>(___eqtf2=Module["___eqtf2"]=wasmExports["__eqtf2"])(a0,a1,a2,a3);var ___netf2=Module["___netf2"]=(a0,a1,a2,a3)=>(___netf2=Module["___netf2"]=wasmExports["__netf2"])(a0,a1,a2,a3);var _sqrtl=Module["_sqrtl"]=(a0,a1,a2)=>(_sqrtl=Module["_sqrtl"]=wasmExports["sqrtl"])(a0,a1,a2);var _alarm=Module["_alarm"]=a0=>(_alarm=Module["_alarm"]=wasmExports["alarm"])(a0);var _setitimer=Module["_setitimer"]=(a0,a1,a2)=>(_setitimer=Module["_setitimer"]=wasmExports["setitimer"])(a0,a1,a2);var _aligned_alloc=Module["_aligned_alloc"]=(a0,a1)=>(_aligned_alloc=Module["_aligned_alloc"]=wasmExports["aligned_alloc"])(a0,a1);var _posix_memalign=Module["_posix_memalign"]=(a0,a1,a2)=>(_posix_memalign=Module["_posix_memalign"]=wasmExports["posix_memalign"])(a0,a1,a2);var _alphasort=Module["_alphasort"]=(a0,a1)=>(_alphasort=Module["_alphasort"]=wasmExports["alphasort"])(a0,a1);var _strcoll=Module["_strcoll"]=(a0,a1)=>(_strcoll=Module["_strcoll"]=wasmExports["strcoll"])(a0,a1);var _asctime=Module["_asctime"]=a0=>(_asctime=Module["_asctime"]=wasmExports["asctime"])(a0);var ___nl_langinfo_l=Module["___nl_langinfo_l"]=(a0,a1)=>(___nl_langinfo_l=Module["___nl_langinfo_l"]=wasmExports["__nl_langinfo_l"])(a0,a1);var _asctime_r=Module["_asctime_r"]=(a0,a1)=>(_asctime_r=Module["_asctime_r"]=wasmExports["asctime_r"])(a0,a1);var _asinf=Module["_asinf"]=a0=>(_asinf=Module["_asinf"]=wasmExports["asinf"])(a0);var _fabsf=Module["_fabsf"]=a0=>(_fabsf=Module["_fabsf"]=wasmExports["fabsf"])(a0);var _asinhf=Module["_asinhf"]=a0=>(_asinhf=Module["_asinhf"]=wasmExports["asinhf"])(a0);var _asinhl=Module["_asinhl"]=(a0,a1,a2)=>(_asinhl=Module["_asinhl"]=wasmExports["asinhl"])(a0,a1,a2);var _asinl=Module["_asinl"]=(a0,a1,a2)=>(_asinl=Module["_asinl"]=wasmExports["asinl"])(a0,a1,a2);var _asprintf=Module["_asprintf"]=(a0,a1,a2)=>(_asprintf=Module["_asprintf"]=wasmExports["asprintf"])(a0,a1,a2);var _vasprintf=Module["_vasprintf"]=(a0,a1,a2)=>(_vasprintf=Module["_vasprintf"]=wasmExports["vasprintf"])(a0,a1,a2);var ___lock=Module["___lock"]=a0=>(___lock=Module["___lock"]=wasmExports["__lock"])(a0);var ___unlock=Module["___unlock"]=a0=>(___unlock=Module["___unlock"]=wasmExports["__unlock"])(a0);var _at_quick_exit=Module["_at_quick_exit"]=a0=>(_at_quick_exit=Module["_at_quick_exit"]=wasmExports["at_quick_exit"])(a0);var _atan2f=Module["_atan2f"]=(a0,a1)=>(_atan2f=Module["_atan2f"]=wasmExports["atan2f"])(a0,a1);var _atanf=Module["_atanf"]=a0=>(_atanf=Module["_atanf"]=wasmExports["atanf"])(a0);var _atan2l=Module["_atan2l"]=(a0,a1,a2,a3,a4)=>(_atan2l=Module["_atan2l"]=wasmExports["atan2l"])(a0,a1,a2,a3,a4);var _atanl=Module["_atanl"]=(a0,a1,a2)=>(_atanl=Module["_atanl"]=wasmExports["atanl"])(a0,a1,a2);var _atanhf=Module["_atanhf"]=a0=>(_atanhf=Module["_atanhf"]=wasmExports["atanhf"])(a0);var _atanhl=Module["_atanhl"]=(a0,a1,a2)=>(_atanhl=Module["_atanhl"]=wasmExports["atanhl"])(a0,a1,a2);var _log1pl=Module["_log1pl"]=(a0,a1,a2)=>(_log1pl=Module["_log1pl"]=wasmExports["log1pl"])(a0,a1,a2);var ____cxa_finalize=Module["____cxa_finalize"]=a0=>(____cxa_finalize=Module["____cxa_finalize"]=wasmExports["___cxa_finalize"])(a0);var ____cxa_atexit=Module["____cxa_atexit"]=(a0,a1,a2)=>(____cxa_atexit=Module["____cxa_atexit"]=wasmExports["___cxa_atexit"])(a0,a1,a2);var ___libc_calloc=Module["___libc_calloc"]=(a0,a1)=>(___libc_calloc=Module["___libc_calloc"]=wasmExports["__libc_calloc"])(a0,a1);var ___atexit=Module["___atexit"]=a0=>(___atexit=Module["___atexit"]=wasmExports["__atexit"])(a0);var _atof=Module["_atof"]=a0=>(_atof=Module["_atof"]=wasmExports["atof"])(a0);var _strtod=Module["_strtod"]=(a0,a1)=>(_strtod=Module["_strtod"]=wasmExports["strtod"])(a0,a1);var _atoi=Module["_atoi"]=a0=>(_atoi=Module["_atoi"]=wasmExports["atoi"])(a0);var _atol=Module["_atol"]=a0=>(_atol=Module["_atol"]=wasmExports["atol"])(a0);var _atoll=Module["_atoll"]=a0=>(_atoll=Module["_atoll"]=wasmExports["atoll"])(a0);var _basename=Module["_basename"]=a0=>(_basename=Module["_basename"]=wasmExports["basename"])(a0);var ___xpg_basename=Module["___xpg_basename"]=a0=>(___xpg_basename=Module["___xpg_basename"]=wasmExports["__xpg_basename"])(a0);var _bcmp=Module["_bcmp"]=(a0,a1,a2)=>(_bcmp=Module["_bcmp"]=wasmExports["bcmp"])(a0,a1,a2);var _bcopy=Module["_bcopy"]=(a0,a1,a2)=>(_bcopy=Module["_bcopy"]=wasmExports["bcopy"])(a0,a1,a2);var _strcasecmp=Module["_strcasecmp"]=(a0,a1)=>(_strcasecmp=Module["_strcasecmp"]=wasmExports["strcasecmp"])(a0,a1);var _bsearch=Module["_bsearch"]=(a0,a1,a2,a3,a4)=>(_bsearch=Module["_bsearch"]=wasmExports["bsearch"])(a0,a1,a2,a3,a4);var _btowc=Module["_btowc"]=a0=>(_btowc=Module["_btowc"]=wasmExports["btowc"])(a0);var _bzero=Module["_bzero"]=(a0,a1)=>(_bzero=Module["_bzero"]=wasmExports["bzero"])(a0,a1);var _c16rtomb=Module["_c16rtomb"]=(a0,a1,a2)=>(_c16rtomb=Module["_c16rtomb"]=wasmExports["c16rtomb"])(a0,a1,a2);var _wcrtomb=Module["_wcrtomb"]=(a0,a1,a2)=>(_wcrtomb=Module["_wcrtomb"]=wasmExports["wcrtomb"])(a0,a1,a2);var _c32rtomb=Module["_c32rtomb"]=(a0,a1,a2)=>(_c32rtomb=Module["_c32rtomb"]=wasmExports["c32rtomb"])(a0,a1,a2);var _cabs=Module["_cabs"]=a0=>(_cabs=Module["_cabs"]=wasmExports["cabs"])(a0);var _cabsf=Module["_cabsf"]=a0=>(_cabsf=Module["_cabsf"]=wasmExports["cabsf"])(a0);var _hypotf=Module["_hypotf"]=(a0,a1)=>(_hypotf=Module["_hypotf"]=wasmExports["hypotf"])(a0,a1);var _cabsl=Module["_cabsl"]=(a0,a1)=>(_cabsl=Module["_cabsl"]=wasmExports["cabsl"])(a0,a1);var _hypotl=Module["_hypotl"]=(a0,a1,a2,a3,a4)=>(_hypotl=Module["_hypotl"]=wasmExports["hypotl"])(a0,a1,a2,a3,a4);var _cacos=Module["_cacos"]=(a0,a1)=>(_cacos=Module["_cacos"]=wasmExports["cacos"])(a0,a1);var _casin=Module["_casin"]=(a0,a1)=>(_casin=Module["_casin"]=wasmExports["casin"])(a0,a1);var _cacosf=Module["_cacosf"]=(a0,a1)=>(_cacosf=Module["_cacosf"]=wasmExports["cacosf"])(a0,a1);var _casinf=Module["_casinf"]=(a0,a1)=>(_casinf=Module["_casinf"]=wasmExports["casinf"])(a0,a1);var _cacosh=Module["_cacosh"]=(a0,a1)=>(_cacosh=Module["_cacosh"]=wasmExports["cacosh"])(a0,a1);var _cacoshf=Module["_cacoshf"]=(a0,a1)=>(_cacoshf=Module["_cacoshf"]=wasmExports["cacoshf"])(a0,a1);var _cacoshl=Module["_cacoshl"]=(a0,a1)=>(_cacoshl=Module["_cacoshl"]=wasmExports["cacoshl"])(a0,a1);var _cacosl=Module["_cacosl"]=(a0,a1)=>(_cacosl=Module["_cacosl"]=wasmExports["cacosl"])(a0,a1);var _casinl=Module["_casinl"]=(a0,a1)=>(_casinl=Module["_casinl"]=wasmExports["casinl"])(a0,a1);var _call_once=Module["_call_once"]=(a0,a1)=>(_call_once=Module["_call_once"]=wasmExports["call_once"])(a0,a1);var _carg=Module["_carg"]=a0=>(_carg=Module["_carg"]=wasmExports["carg"])(a0);var _cargf=Module["_cargf"]=a0=>(_cargf=Module["_cargf"]=wasmExports["cargf"])(a0);var _cargl=Module["_cargl"]=(a0,a1)=>(_cargl=Module["_cargl"]=wasmExports["cargl"])(a0,a1);var _csqrt=Module["_csqrt"]=(a0,a1)=>(_csqrt=Module["_csqrt"]=wasmExports["csqrt"])(a0,a1);var _clog=Module["_clog"]=(a0,a1)=>(_clog=Module["_clog"]=wasmExports["clog"])(a0,a1);var _csqrtf=Module["_csqrtf"]=(a0,a1)=>(_csqrtf=Module["_csqrtf"]=wasmExports["csqrtf"])(a0,a1);var _clogf=Module["_clogf"]=(a0,a1)=>(_clogf=Module["_clogf"]=wasmExports["clogf"])(a0,a1);var _casinh=Module["_casinh"]=(a0,a1)=>(_casinh=Module["_casinh"]=wasmExports["casinh"])(a0,a1);var _casinhf=Module["_casinhf"]=(a0,a1)=>(_casinhf=Module["_casinhf"]=wasmExports["casinhf"])(a0,a1);var _casinhl=Module["_casinhl"]=(a0,a1)=>(_casinhl=Module["_casinhl"]=wasmExports["casinhl"])(a0,a1);var _csqrtl=Module["_csqrtl"]=(a0,a1)=>(_csqrtl=Module["_csqrtl"]=wasmExports["csqrtl"])(a0,a1);var _clogl=Module["_clogl"]=(a0,a1)=>(_clogl=Module["_clogl"]=wasmExports["clogl"])(a0,a1);var _catan=Module["_catan"]=(a0,a1)=>(_catan=Module["_catan"]=wasmExports["catan"])(a0,a1);var _catanf=Module["_catanf"]=(a0,a1)=>(_catanf=Module["_catanf"]=wasmExports["catanf"])(a0,a1);var _catanh=Module["_catanh"]=(a0,a1)=>(_catanh=Module["_catanh"]=wasmExports["catanh"])(a0,a1);var _catanhf=Module["_catanhf"]=(a0,a1)=>(_catanhf=Module["_catanhf"]=wasmExports["catanhf"])(a0,a1);var _catanhl=Module["_catanhl"]=(a0,a1)=>(_catanhl=Module["_catanhl"]=wasmExports["catanhl"])(a0,a1);var _catanl=Module["_catanl"]=(a0,a1)=>(_catanl=Module["_catanl"]=wasmExports["catanl"])(a0,a1);var _logl=Module["_logl"]=(a0,a1,a2)=>(_logl=Module["_logl"]=wasmExports["logl"])(a0,a1,a2);var ___trunctfsf2=Module["___trunctfsf2"]=(a0,a1)=>(___trunctfsf2=Module["___trunctfsf2"]=wasmExports["__trunctfsf2"])(a0,a1);var ___extendsftf2=Module["___extendsftf2"]=(a0,a1)=>(___extendsftf2=Module["___extendsftf2"]=wasmExports["__extendsftf2"])(a0,a1);var _catclose=Module["_catclose"]=a0=>(_catclose=Module["_catclose"]=wasmExports["catclose"])(a0);var _catgets=Module["_catgets"]=(a0,a1,a2,a3)=>(_catgets=Module["_catgets"]=wasmExports["catgets"])(a0,a1,a2,a3);var _catopen=Module["_catopen"]=(a0,a1)=>(_catopen=Module["_catopen"]=wasmExports["catopen"])(a0,a1);var _cbrtf=Module["_cbrtf"]=a0=>(_cbrtf=Module["_cbrtf"]=wasmExports["cbrtf"])(a0);var _cbrtl=Module["_cbrtl"]=(a0,a1,a2)=>(_cbrtl=Module["_cbrtl"]=wasmExports["cbrtl"])(a0,a1,a2);var _ccos=Module["_ccos"]=(a0,a1)=>(_ccos=Module["_ccos"]=wasmExports["ccos"])(a0,a1);var _ccosh=Module["_ccosh"]=(a0,a1)=>(_ccosh=Module["_ccosh"]=wasmExports["ccosh"])(a0,a1);var _ccosf=Module["_ccosf"]=(a0,a1)=>(_ccosf=Module["_ccosf"]=wasmExports["ccosf"])(a0,a1);var _ccoshf=Module["_ccoshf"]=(a0,a1)=>(_ccoshf=Module["_ccoshf"]=wasmExports["ccoshf"])(a0,a1);var _coshf=Module["_coshf"]=a0=>(_coshf=Module["_coshf"]=wasmExports["coshf"])(a0);var _sinhf=Module["_sinhf"]=a0=>(_sinhf=Module["_sinhf"]=wasmExports["sinhf"])(a0);var _copysignf=Module["_copysignf"]=(a0,a1)=>(_copysignf=Module["_copysignf"]=wasmExports["copysignf"])(a0,a1);var _ccoshl=Module["_ccoshl"]=(a0,a1)=>(_ccoshl=Module["_ccoshl"]=wasmExports["ccoshl"])(a0,a1);var _ccosl=Module["_ccosl"]=(a0,a1)=>(_ccosl=Module["_ccosl"]=wasmExports["ccosl"])(a0,a1);var _ceil=Module["_ceil"]=a0=>(_ceil=Module["_ceil"]=wasmExports["ceil"])(a0);var _ceilf=Module["_ceilf"]=a0=>(_ceilf=Module["_ceilf"]=wasmExports["ceilf"])(a0);var _ceill=Module["_ceill"]=(a0,a1,a2)=>(_ceill=Module["_ceill"]=wasmExports["ceill"])(a0,a1,a2);var _cexp=Module["_cexp"]=(a0,a1)=>(_cexp=Module["_cexp"]=wasmExports["cexp"])(a0,a1);var _cexpf=Module["_cexpf"]=(a0,a1)=>(_cexpf=Module["_cexpf"]=wasmExports["cexpf"])(a0,a1);var _cexpl=Module["_cexpl"]=(a0,a1)=>(_cexpl=Module["_cexpl"]=wasmExports["cexpl"])(a0,a1);var _cfgetospeed=Module["_cfgetospeed"]=a0=>(_cfgetospeed=Module["_cfgetospeed"]=wasmExports["cfgetospeed"])(a0);var _cfgetispeed=Module["_cfgetispeed"]=a0=>(_cfgetispeed=Module["_cfgetispeed"]=wasmExports["cfgetispeed"])(a0);var _cfmakeraw=Module["_cfmakeraw"]=a0=>(_cfmakeraw=Module["_cfmakeraw"]=wasmExports["cfmakeraw"])(a0);var _cfsetospeed=Module["_cfsetospeed"]=(a0,a1)=>(_cfsetospeed=Module["_cfsetospeed"]=wasmExports["cfsetospeed"])(a0,a1);var _cfsetispeed=Module["_cfsetispeed"]=(a0,a1)=>(_cfsetispeed=Module["_cfsetispeed"]=wasmExports["cfsetispeed"])(a0,a1);var _cfsetspeed=Module["_cfsetspeed"]=(a0,a1)=>(_cfsetspeed=Module["_cfsetspeed"]=wasmExports["cfsetspeed"])(a0,a1);var _cimag=Module["_cimag"]=a0=>(_cimag=Module["_cimag"]=wasmExports["cimag"])(a0);var _cimagf=Module["_cimagf"]=a0=>(_cimagf=Module["_cimagf"]=wasmExports["cimagf"])(a0);var _cimagl=Module["_cimagl"]=(a0,a1)=>(_cimagl=Module["_cimagl"]=wasmExports["cimagl"])(a0,a1);var _clearenv=Module["_clearenv"]=()=>(_clearenv=Module["_clearenv"]=wasmExports["clearenv"])();var _clearerr_unlocked=Module["_clearerr_unlocked"]=a0=>(_clearerr_unlocked=Module["_clearerr_unlocked"]=wasmExports["clearerr_unlocked"])(a0);var _emscripten_thread_sleep=Module["_emscripten_thread_sleep"]=a0=>(_emscripten_thread_sleep=Module["_emscripten_thread_sleep"]=wasmExports["emscripten_thread_sleep"])(a0);var _cnd_broadcast=Module["_cnd_broadcast"]=a0=>(_cnd_broadcast=Module["_cnd_broadcast"]=wasmExports["cnd_broadcast"])(a0);var _cnd_destroy=Module["_cnd_destroy"]=a0=>(_cnd_destroy=Module["_cnd_destroy"]=wasmExports["cnd_destroy"])(a0);var _cnd_init=Module["_cnd_init"]=a0=>(_cnd_init=Module["_cnd_init"]=wasmExports["cnd_init"])(a0);var _cnd_signal=Module["_cnd_signal"]=a0=>(_cnd_signal=Module["_cnd_signal"]=wasmExports["cnd_signal"])(a0);var _cnd_timedwait=Module["_cnd_timedwait"]=(a0,a1,a2)=>(_cnd_timedwait=Module["_cnd_timedwait"]=wasmExports["cnd_timedwait"])(a0,a1,a2);var _cnd_wait=Module["_cnd_wait"]=(a0,a1)=>(_cnd_wait=Module["_cnd_wait"]=wasmExports["cnd_wait"])(a0,a1);var _conj=Module["_conj"]=(a0,a1)=>(_conj=Module["_conj"]=wasmExports["conj"])(a0,a1);var _conjf=Module["_conjf"]=(a0,a1)=>(_conjf=Module["_conjf"]=wasmExports["conjf"])(a0,a1);var _conjl=Module["_conjl"]=(a0,a1)=>(_conjl=Module["_conjl"]=wasmExports["conjl"])(a0,a1);var _copysignl=Module["_copysignl"]=(a0,a1,a2,a3,a4)=>(_copysignl=Module["_copysignl"]=wasmExports["copysignl"])(a0,a1,a2,a3,a4);var _expm1f=Module["_expm1f"]=a0=>(_expm1f=Module["_expm1f"]=wasmExports["expm1f"])(a0);var _coshl=Module["_coshl"]=(a0,a1,a2)=>(_coshl=Module["_coshl"]=wasmExports["coshl"])(a0,a1,a2);var _cosl=Module["_cosl"]=(a0,a1,a2)=>(_cosl=Module["_cosl"]=wasmExports["cosl"])(a0,a1,a2);var _cpow=Module["_cpow"]=(a0,a1,a2)=>(_cpow=Module["_cpow"]=wasmExports["cpow"])(a0,a1,a2);var ___muldc3=Module["___muldc3"]=(a0,a1,a2,a3,a4)=>(___muldc3=Module["___muldc3"]=wasmExports["__muldc3"])(a0,a1,a2,a3,a4);var _cpowf=Module["_cpowf"]=(a0,a1,a2)=>(_cpowf=Module["_cpowf"]=wasmExports["cpowf"])(a0,a1,a2);var ___mulsc3=Module["___mulsc3"]=(a0,a1,a2,a3,a4)=>(___mulsc3=Module["___mulsc3"]=wasmExports["__mulsc3"])(a0,a1,a2,a3,a4);var _cpowl=Module["_cpowl"]=(a0,a1,a2)=>(_cpowl=Module["_cpowl"]=wasmExports["cpowl"])(a0,a1,a2);var ___unordtf2=Module["___unordtf2"]=(a0,a1,a2,a3)=>(___unordtf2=Module["___unordtf2"]=wasmExports["__unordtf2"])(a0,a1,a2,a3);var ___multc3=Module["___multc3"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(___multc3=Module["___multc3"]=wasmExports["__multc3"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var _cproj=Module["_cproj"]=(a0,a1)=>(_cproj=Module["_cproj"]=wasmExports["cproj"])(a0,a1);var _cprojf=Module["_cprojf"]=(a0,a1)=>(_cprojf=Module["_cprojf"]=wasmExports["cprojf"])(a0,a1);var _cprojl=Module["_cprojl"]=(a0,a1)=>(_cprojl=Module["_cprojl"]=wasmExports["cprojl"])(a0,a1);var _creal=Module["_creal"]=a0=>(_creal=Module["_creal"]=wasmExports["creal"])(a0);var _crealf=Module["_crealf"]=a0=>(_crealf=Module["_crealf"]=wasmExports["crealf"])(a0);var _creall=Module["_creall"]=(a0,a1)=>(_creall=Module["_creall"]=wasmExports["creall"])(a0,a1);var _creat=Module["_creat"]=(a0,a1)=>(_creat=Module["_creat"]=wasmExports["creat"])(a0,a1);var _crypt=Module["_crypt"]=(a0,a1)=>(_crypt=Module["_crypt"]=wasmExports["crypt"])(a0,a1);var ___crypt_blowfish=Module["___crypt_blowfish"]=(a0,a1,a2)=>(___crypt_blowfish=Module["___crypt_blowfish"]=wasmExports["__crypt_blowfish"])(a0,a1,a2);var ___crypt_des=Module["___crypt_des"]=(a0,a1,a2)=>(___crypt_des=Module["___crypt_des"]=wasmExports["__crypt_des"])(a0,a1,a2);var ___crypt_md5=Module["___crypt_md5"]=(a0,a1,a2)=>(___crypt_md5=Module["___crypt_md5"]=wasmExports["__crypt_md5"])(a0,a1,a2);var _strnlen=Module["_strnlen"]=(a0,a1)=>(_strnlen=Module["_strnlen"]=wasmExports["strnlen"])(a0,a1);var ___crypt_sha256=Module["___crypt_sha256"]=(a0,a1,a2)=>(___crypt_sha256=Module["___crypt_sha256"]=wasmExports["__crypt_sha256"])(a0,a1,a2);var ___crypt_sha512=Module["___crypt_sha512"]=(a0,a1,a2)=>(___crypt_sha512=Module["___crypt_sha512"]=wasmExports["__crypt_sha512"])(a0,a1,a2);var _sprintf=Module["_sprintf"]=(a0,a1,a2)=>(_sprintf=Module["_sprintf"]=wasmExports["sprintf"])(a0,a1,a2);var _csin=Module["_csin"]=(a0,a1)=>(_csin=Module["_csin"]=wasmExports["csin"])(a0,a1);var _csinh=Module["_csinh"]=(a0,a1)=>(_csinh=Module["_csinh"]=wasmExports["csinh"])(a0,a1);var _csinf=Module["_csinf"]=(a0,a1)=>(_csinf=Module["_csinf"]=wasmExports["csinf"])(a0,a1);var _csinhf=Module["_csinhf"]=(a0,a1)=>(_csinhf=Module["_csinhf"]=wasmExports["csinhf"])(a0,a1);var _csinhl=Module["_csinhl"]=(a0,a1)=>(_csinhl=Module["_csinhl"]=wasmExports["csinhl"])(a0,a1);var _csinl=Module["_csinl"]=(a0,a1)=>(_csinl=Module["_csinl"]=wasmExports["csinl"])(a0,a1);var _ctan=Module["_ctan"]=(a0,a1)=>(_ctan=Module["_ctan"]=wasmExports["ctan"])(a0,a1);var _ctanh=Module["_ctanh"]=(a0,a1)=>(_ctanh=Module["_ctanh"]=wasmExports["ctanh"])(a0,a1);var _ctanf=Module["_ctanf"]=(a0,a1)=>(_ctanf=Module["_ctanf"]=wasmExports["ctanf"])(a0,a1);var _ctanhf=Module["_ctanhf"]=(a0,a1)=>(_ctanhf=Module["_ctanhf"]=wasmExports["ctanhf"])(a0,a1);var _tanf=Module["_tanf"]=a0=>(_tanf=Module["_tanf"]=wasmExports["tanf"])(a0);var _ctanhl=Module["_ctanhl"]=(a0,a1)=>(_ctanhl=Module["_ctanhl"]=wasmExports["ctanhl"])(a0,a1);var _ctanl=Module["_ctanl"]=(a0,a1)=>(_ctanl=Module["_ctanl"]=wasmExports["ctanl"])(a0,a1);var _ctime=Module["_ctime"]=a0=>(_ctime=Module["_ctime"]=wasmExports["ctime"])(a0);var _localtime=Module["_localtime"]=a0=>(_localtime=Module["_localtime"]=wasmExports["localtime"])(a0);var _ctime_r=Module["_ctime_r"]=(a0,a1)=>(_ctime_r=Module["_ctime_r"]=wasmExports["ctime_r"])(a0,a1);var _dcngettext=Module["_dcngettext"]=(a0,a1,a2,a3,a4)=>(_dcngettext=Module["_dcngettext"]=wasmExports["dcngettext"])(a0,a1,a2,a3,a4);var ___gettextdomain=Module["___gettextdomain"]=()=>(___gettextdomain=Module["___gettextdomain"]=wasmExports["__gettextdomain"])();var _dngettext=Module["_dngettext"]=(a0,a1,a2,a3)=>(_dngettext=Module["_dngettext"]=wasmExports["dngettext"])(a0,a1,a2,a3);var _difftime=Module["_difftime"]=(a0,a1)=>(_difftime=Module["_difftime"]=wasmExports["difftime"])(a0,a1);var _dirname=Module["_dirname"]=a0=>(_dirname=Module["_dirname"]=wasmExports["dirname"])(a0);var _div=Module["_div"]=(a0,a1,a2)=>(_div=Module["_div"]=wasmExports["div"])(a0,a1,a2);var _dladdr=Module["_dladdr"]=(a0,a1)=>(_dladdr=Module["_dladdr"]=wasmExports["dladdr"])(a0,a1);var ___libc_free=Module["___libc_free"]=a0=>(___libc_free=Module["___libc_free"]=wasmExports["__libc_free"])(a0);var ___libc_malloc=Module["___libc_malloc"]=a0=>(___libc_malloc=Module["___libc_malloc"]=wasmExports["__libc_malloc"])(a0);var ___dl_seterr=(a0,a1)=>(___dl_seterr=wasmExports["__dl_seterr"])(a0,a1);var _dn_comp=Module["_dn_comp"]=(a0,a1,a2,a3,a4)=>(_dn_comp=Module["_dn_comp"]=wasmExports["dn_comp"])(a0,a1,a2,a3,a4);var _dn_expand=Module["_dn_expand"]=(a0,a1,a2,a3,a4)=>(_dn_expand=Module["_dn_expand"]=wasmExports["dn_expand"])(a0,a1,a2,a3,a4);var _dn_skipname=Module["_dn_skipname"]=(a0,a1)=>(_dn_skipname=Module["_dn_skipname"]=wasmExports["dn_skipname"])(a0,a1);var _dprintf=Module["_dprintf"]=(a0,a1,a2)=>(_dprintf=Module["_dprintf"]=wasmExports["dprintf"])(a0,a1,a2);var _vdprintf=Module["_vdprintf"]=(a0,a1,a2)=>(_vdprintf=Module["_vdprintf"]=wasmExports["vdprintf"])(a0,a1,a2);var _erand48=Module["_erand48"]=a0=>(_erand48=Module["_erand48"]=wasmExports["erand48"])(a0);var _drand48=Module["_drand48"]=()=>(_drand48=Module["_drand48"]=wasmExports["drand48"])();var ___wasi_fd_is_valid=Module["___wasi_fd_is_valid"]=a0=>(___wasi_fd_is_valid=Module["___wasi_fd_is_valid"]=wasmExports["__wasi_fd_is_valid"])(a0);var ___duplocale=Module["___duplocale"]=a0=>(___duplocale=Module["___duplocale"]=wasmExports["__duplocale"])(a0);var _duplocale=Module["_duplocale"]=a0=>(_duplocale=Module["_duplocale"]=wasmExports["duplocale"])(a0);var _new_dlevent=Module["_new_dlevent"]=(a0,a1)=>(_new_dlevent=Module["_new_dlevent"]=wasmExports["new_dlevent"])(a0,a1);var _pthread_setcancelstate=Module["_pthread_setcancelstate"]=(a0,a1)=>(_pthread_setcancelstate=Module["_pthread_setcancelstate"]=wasmExports["pthread_setcancelstate"])(a0,a1);var _emscripten_dlopen=Module["_emscripten_dlopen"]=(a0,a1,a2,a3,a4)=>(_emscripten_dlopen=Module["_emscripten_dlopen"]=wasmExports["emscripten_dlopen"])(a0,a1,a2,a3,a4);var _emscripten_dlopen_promise=Module["_emscripten_dlopen_promise"]=(a0,a1)=>(_emscripten_dlopen_promise=Module["_emscripten_dlopen_promise"]=wasmExports["emscripten_dlopen_promise"])(a0,a1);var _strspn=Module["_strspn"]=(a0,a1)=>(_strspn=Module["_strspn"]=wasmExports["strspn"])(a0,a1);var _ecvt=Module["_ecvt"]=(a0,a1,a2,a3)=>(_ecvt=Module["_ecvt"]=wasmExports["ecvt"])(a0,a1,a2,a3);var _emscripten_console_logf=Module["_emscripten_console_logf"]=(a0,a1)=>(_emscripten_console_logf=Module["_emscripten_console_logf"]=wasmExports["emscripten_console_logf"])(a0,a1);var _emscripten_console_errorf=Module["_emscripten_console_errorf"]=(a0,a1)=>(_emscripten_console_errorf=Module["_emscripten_console_errorf"]=wasmExports["emscripten_console_errorf"])(a0,a1);var _emscripten_console_warnf=Module["_emscripten_console_warnf"]=(a0,a1)=>(_emscripten_console_warnf=Module["_emscripten_console_warnf"]=wasmExports["emscripten_console_warnf"])(a0,a1);var _emscripten_outf=Module["_emscripten_outf"]=(a0,a1)=>(_emscripten_outf=Module["_emscripten_outf"]=wasmExports["emscripten_outf"])(a0,a1);var _emscripten_errf=Module["_emscripten_errf"]=(a0,a1)=>(_emscripten_errf=Module["_emscripten_errf"]=wasmExports["emscripten_errf"])(a0,a1);var _emscripten_fiber_init=Module["_emscripten_fiber_init"]=(a0,a1,a2,a3,a4,a5,a6)=>(_emscripten_fiber_init=Module["_emscripten_fiber_init"]=wasmExports["emscripten_fiber_init"])(a0,a1,a2,a3,a4,a5,a6);var _emscripten_fiber_init_from_current_context=Module["_emscripten_fiber_init_from_current_context"]=(a0,a1,a2)=>(_emscripten_fiber_init_from_current_context=Module["_emscripten_fiber_init_from_current_context"]=wasmExports["emscripten_fiber_init_from_current_context"])(a0,a1,a2);var _emscripten_stack_get_base=Module["_emscripten_stack_get_base"]=()=>(_emscripten_stack_get_base=Module["_emscripten_stack_get_base"]=wasmExports["emscripten_stack_get_base"])();var _emscripten_stack_get_end=Module["_emscripten_stack_get_end"]=()=>(_emscripten_stack_get_end=Module["_emscripten_stack_get_end"]=wasmExports["emscripten_stack_get_end"])();var _emscripten_get_heap_size=Module["_emscripten_get_heap_size"]=()=>(_emscripten_get_heap_size=Module["_emscripten_get_heap_size"]=wasmExports["emscripten_get_heap_size"])();var ___syscall_munmap=Module["___syscall_munmap"]=(a0,a1)=>(___syscall_munmap=Module["___syscall_munmap"]=wasmExports["__syscall_munmap"])(a0,a1);var _emscripten_builtin_free=Module["_emscripten_builtin_free"]=a0=>(_emscripten_builtin_free=Module["_emscripten_builtin_free"]=wasmExports["emscripten_builtin_free"])(a0);var ___syscall_msync=Module["___syscall_msync"]=(a0,a1,a2)=>(___syscall_msync=Module["___syscall_msync"]=wasmExports["__syscall_msync"])(a0,a1,a2);var ___syscall_mmap2=Module["___syscall_mmap2"]=(a0,a1,a2,a3,a4,a5)=>(___syscall_mmap2=Module["___syscall_mmap2"]=wasmExports["__syscall_mmap2"])(a0,a1,a2,a3,a4,a5);var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["emscripten_builtin_memalign"])(a0,a1);var _emscripten_scan_stack=Module["_emscripten_scan_stack"]=a0=>(_emscripten_scan_stack=Module["_emscripten_scan_stack"]=wasmExports["emscripten_scan_stack"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["emscripten_stack_get_current"])();var ___clock=Module["___clock"]=()=>(___clock=Module["___clock"]=wasmExports["__clock"])();var ___time=Module["___time"]=a0=>(___time=Module["___time"]=wasmExports["__time"])(a0);var ___clock_getres=Module["___clock_getres"]=(a0,a1)=>(___clock_getres=Module["___clock_getres"]=wasmExports["__clock_getres"])(a0,a1);var ___gettimeofday=Module["___gettimeofday"]=(a0,a1)=>(___gettimeofday=Module["___gettimeofday"]=wasmExports["__gettimeofday"])(a0,a1);var _dysize=Module["_dysize"]=a0=>(_dysize=Module["_dysize"]=wasmExports["dysize"])(a0);var _setkey=Module["_setkey"]=a0=>(_setkey=Module["_setkey"]=wasmExports["setkey"])(a0);var _encrypt=Module["_encrypt"]=(a0,a1)=>(_encrypt=Module["_encrypt"]=wasmExports["encrypt"])(a0,a1);var _sethostent=Module["_sethostent"]=a0=>(_sethostent=Module["_sethostent"]=wasmExports["sethostent"])(a0);var _gethostent=Module["_gethostent"]=()=>(_gethostent=Module["_gethostent"]=wasmExports["gethostent"])();var _getnetent=Module["_getnetent"]=()=>(_getnetent=Module["_getnetent"]=wasmExports["getnetent"])();var _endhostent=Module["_endhostent"]=()=>(_endhostent=Module["_endhostent"]=wasmExports["endhostent"])();var _setnetent=Module["_setnetent"]=a0=>(_setnetent=Module["_setnetent"]=wasmExports["setnetent"])(a0);var _endnetent=Module["_endnetent"]=()=>(_endnetent=Module["_endnetent"]=wasmExports["endnetent"])();var _erff=Module["_erff"]=a0=>(_erff=Module["_erff"]=wasmExports["erff"])(a0);var _erfcf=Module["_erfcf"]=a0=>(_erfcf=Module["_erfcf"]=wasmExports["erfcf"])(a0);var _erfl=Module["_erfl"]=(a0,a1,a2)=>(_erfl=Module["_erfl"]=wasmExports["erfl"])(a0,a1,a2);var _erfcl=Module["_erfcl"]=(a0,a1,a2)=>(_erfcl=Module["_erfcl"]=wasmExports["erfcl"])(a0,a1,a2);var _vwarn=Module["_vwarn"]=(a0,a1)=>(_vwarn=Module["_vwarn"]=wasmExports["vwarn"])(a0,a1);var _fprintf=Module["_fprintf"]=(a0,a1,a2)=>(_fprintf=Module["_fprintf"]=wasmExports["fprintf"])(a0,a1,a2);var _vwarnx=Module["_vwarnx"]=(a0,a1)=>(_vwarnx=Module["_vwarnx"]=wasmExports["vwarnx"])(a0,a1);var _putc=Module["_putc"]=(a0,a1)=>(_putc=Module["_putc"]=wasmExports["putc"])(a0,a1);var _verr=Module["_verr"]=(a0,a1,a2)=>(_verr=Module["_verr"]=wasmExports["verr"])(a0,a1,a2);var _verrx=Module["_verrx"]=(a0,a1,a2)=>(_verrx=Module["_verrx"]=wasmExports["verrx"])(a0,a1,a2);var _warn=Module["_warn"]=(a0,a1)=>(_warn=Module["_warn"]=wasmExports["warn"])(a0,a1);var _warnx=Module["_warnx"]=(a0,a1)=>(_warnx=Module["_warnx"]=wasmExports["warnx"])(a0,a1);var _err=Module["_err"]=(a0,a1,a2)=>(_err=Module["_err"]=wasmExports["err"])(a0,a1,a2);var _errx=Module["_errx"]=(a0,a1,a2)=>(_errx=Module["_errx"]=wasmExports["errx"])(a0,a1,a2);var _ether_aton_r=Module["_ether_aton_r"]=(a0,a1)=>(_ether_aton_r=Module["_ether_aton_r"]=wasmExports["ether_aton_r"])(a0,a1);var _ether_aton=Module["_ether_aton"]=a0=>(_ether_aton=Module["_ether_aton"]=wasmExports["ether_aton"])(a0);var _ether_ntoa_r=Module["_ether_ntoa_r"]=(a0,a1)=>(_ether_ntoa_r=Module["_ether_ntoa_r"]=wasmExports["ether_ntoa_r"])(a0,a1);var _ether_ntoa=Module["_ether_ntoa"]=a0=>(_ether_ntoa=Module["_ether_ntoa"]=wasmExports["ether_ntoa"])(a0);var _ether_line=Module["_ether_line"]=(a0,a1,a2)=>(_ether_line=Module["_ether_line"]=wasmExports["ether_line"])(a0,a1,a2);var _ether_ntohost=Module["_ether_ntohost"]=(a0,a1)=>(_ether_ntohost=Module["_ether_ntohost"]=wasmExports["ether_ntohost"])(a0,a1);var _ether_hostton=Module["_ether_hostton"]=(a0,a1)=>(_ether_hostton=Module["_ether_hostton"]=wasmExports["ether_hostton"])(a0,a1);var _execl=Module["_execl"]=(a0,a1,a2)=>(_execl=Module["_execl"]=wasmExports["execl"])(a0,a1,a2);var _execle=Module["_execle"]=(a0,a1,a2)=>(_execle=Module["_execle"]=wasmExports["execle"])(a0,a1,a2);var _execlp=Module["_execlp"]=(a0,a1,a2)=>(_execlp=Module["_execlp"]=wasmExports["execlp"])(a0,a1,a2);var _execvp=Module["_execvp"]=(a0,a1)=>(_execvp=Module["_execvp"]=wasmExports["execvp"])(a0,a1);var _execvpe=Module["_execvpe"]=(a0,a1,a2)=>(_execvpe=Module["_execvpe"]=wasmExports["execvpe"])(a0,a1,a2);var _exp10=Module["_exp10"]=a0=>(_exp10=Module["_exp10"]=wasmExports["exp10"])(a0);var _pow10=Module["_pow10"]=a0=>(_pow10=Module["_pow10"]=wasmExports["pow10"])(a0);var _exp10f=Module["_exp10f"]=a0=>(_exp10f=Module["_exp10f"]=wasmExports["exp10f"])(a0);var _modff=Module["_modff"]=(a0,a1)=>(_modff=Module["_modff"]=wasmExports["modff"])(a0,a1);var _exp2f=Module["_exp2f"]=a0=>(_exp2f=Module["_exp2f"]=wasmExports["exp2f"])(a0);var _pow10f=Module["_pow10f"]=a0=>(_pow10f=Module["_pow10f"]=wasmExports["pow10f"])(a0);var _exp10l=Module["_exp10l"]=(a0,a1,a2)=>(_exp10l=Module["_exp10l"]=wasmExports["exp10l"])(a0,a1,a2);var _modfl=Module["_modfl"]=(a0,a1,a2,a3)=>(_modfl=Module["_modfl"]=wasmExports["modfl"])(a0,a1,a2,a3);var _exp2l=Module["_exp2l"]=(a0,a1,a2)=>(_exp2l=Module["_exp2l"]=wasmExports["exp2l"])(a0,a1,a2);var _powl=Module["_powl"]=(a0,a1,a2,a3,a4)=>(_powl=Module["_powl"]=wasmExports["powl"])(a0,a1,a2,a3,a4);var _pow10l=Module["_pow10l"]=(a0,a1,a2)=>(_pow10l=Module["_pow10l"]=wasmExports["pow10l"])(a0,a1,a2);var ___letf2=Module["___letf2"]=(a0,a1,a2,a3)=>(___letf2=Module["___letf2"]=wasmExports["__letf2"])(a0,a1,a2,a3);var _scalbnl=Module["_scalbnl"]=(a0,a1,a2,a3)=>(_scalbnl=Module["_scalbnl"]=wasmExports["scalbnl"])(a0,a1,a2,a3);var _expl=Module["_expl"]=(a0,a1,a2)=>(_expl=Module["_expl"]=wasmExports["expl"])(a0,a1,a2);var _expm1l=Module["_expm1l"]=(a0,a1,a2)=>(_expm1l=Module["_expm1l"]=wasmExports["expm1l"])(a0,a1,a2);var __flushlbf=Module["__flushlbf"]=()=>(__flushlbf=Module["__flushlbf"]=wasmExports["_flushlbf"])();var ___fsetlocking=Module["___fsetlocking"]=(a0,a1)=>(___fsetlocking=Module["___fsetlocking"]=wasmExports["__fsetlocking"])(a0,a1);var ___fwriting=Module["___fwriting"]=a0=>(___fwriting=Module["___fwriting"]=wasmExports["__fwriting"])(a0);var ___freading=Module["___freading"]=a0=>(___freading=Module["___freading"]=wasmExports["__freading"])(a0);var ___freadable=Module["___freadable"]=a0=>(___freadable=Module["___freadable"]=wasmExports["__freadable"])(a0);var ___fwritable=Module["___fwritable"]=a0=>(___fwritable=Module["___fwritable"]=wasmExports["__fwritable"])(a0);var ___flbf=Module["___flbf"]=a0=>(___flbf=Module["___flbf"]=wasmExports["__flbf"])(a0);var ___fbufsize=Module["___fbufsize"]=a0=>(___fbufsize=Module["___fbufsize"]=wasmExports["__fbufsize"])(a0);var ___fpending=Module["___fpending"]=a0=>(___fpending=Module["___fpending"]=wasmExports["__fpending"])(a0);var ___fpurge=Module["___fpurge"]=a0=>(___fpurge=Module["___fpurge"]=wasmExports["__fpurge"])(a0);var _fpurge=Module["_fpurge"]=a0=>(_fpurge=Module["_fpurge"]=wasmExports["fpurge"])(a0);var ___freadahead=Module["___freadahead"]=a0=>(___freadahead=Module["___freadahead"]=wasmExports["__freadahead"])(a0);var ___freadptr=Module["___freadptr"]=(a0,a1)=>(___freadptr=Module["___freadptr"]=wasmExports["__freadptr"])(a0,a1);var ___freadptrinc=Module["___freadptrinc"]=(a0,a1)=>(___freadptrinc=Module["___freadptrinc"]=wasmExports["__freadptrinc"])(a0,a1);var ___fseterr=Module["___fseterr"]=a0=>(___fseterr=Module["___fseterr"]=wasmExports["__fseterr"])(a0);var _faccessat=Module["_faccessat"]=(a0,a1,a2,a3)=>(_faccessat=Module["_faccessat"]=wasmExports["faccessat"])(a0,a1,a2,a3);var _fcvt=Module["_fcvt"]=(a0,a1,a2,a3)=>(_fcvt=Module["_fcvt"]=wasmExports["fcvt"])(a0,a1,a2,a3);var _fdim=Module["_fdim"]=(a0,a1)=>(_fdim=Module["_fdim"]=wasmExports["fdim"])(a0,a1);var _fdimf=Module["_fdimf"]=(a0,a1)=>(_fdimf=Module["_fdimf"]=wasmExports["fdimf"])(a0,a1);var _fdiml=Module["_fdiml"]=(a0,a1,a2,a3,a4)=>(_fdiml=Module["_fdiml"]=wasmExports["fdiml"])(a0,a1,a2,a3,a4);var _fegetexceptflag=Module["_fegetexceptflag"]=(a0,a1)=>(_fegetexceptflag=Module["_fegetexceptflag"]=wasmExports["fegetexceptflag"])(a0,a1);var _fetestexcept=Module["_fetestexcept"]=a0=>(_fetestexcept=Module["_fetestexcept"]=wasmExports["fetestexcept"])(a0);var _feholdexcept=Module["_feholdexcept"]=a0=>(_feholdexcept=Module["_feholdexcept"]=wasmExports["feholdexcept"])(a0);var _fegetenv=Module["_fegetenv"]=a0=>(_fegetenv=Module["_fegetenv"]=wasmExports["fegetenv"])(a0);var _feclearexcept=Module["_feclearexcept"]=a0=>(_feclearexcept=Module["_feclearexcept"]=wasmExports["feclearexcept"])(a0);var _feraiseexcept=Module["_feraiseexcept"]=a0=>(_feraiseexcept=Module["_feraiseexcept"]=wasmExports["feraiseexcept"])(a0);var ___fesetround=Module["___fesetround"]=a0=>(___fesetround=Module["___fesetround"]=wasmExports["__fesetround"])(a0);var _fesetenv=Module["_fesetenv"]=a0=>(_fesetenv=Module["_fesetenv"]=wasmExports["fesetenv"])(a0);var _feof_unlocked=Module["_feof_unlocked"]=a0=>(_feof_unlocked=Module["_feof_unlocked"]=wasmExports["feof_unlocked"])(a0);var __IO_feof_unlocked=Module["__IO_feof_unlocked"]=a0=>(__IO_feof_unlocked=Module["__IO_feof_unlocked"]=wasmExports["_IO_feof_unlocked"])(a0);var _ferror_unlocked=Module["_ferror_unlocked"]=a0=>(_ferror_unlocked=Module["_ferror_unlocked"]=wasmExports["ferror_unlocked"])(a0);var __IO_ferror_unlocked=Module["__IO_ferror_unlocked"]=a0=>(__IO_ferror_unlocked=Module["__IO_ferror_unlocked"]=wasmExports["_IO_ferror_unlocked"])(a0);var _fesetexceptflag=Module["_fesetexceptflag"]=(a0,a1)=>(_fesetexceptflag=Module["_fesetexceptflag"]=wasmExports["fesetexceptflag"])(a0,a1);var _fesetround=Module["_fesetround"]=a0=>(_fesetround=Module["_fesetround"]=wasmExports["fesetround"])(a0);var _feupdateenv=Module["_feupdateenv"]=a0=>(_feupdateenv=Module["_feupdateenv"]=wasmExports["feupdateenv"])(a0);var _fflush_unlocked=Module["_fflush_unlocked"]=a0=>(_fflush_unlocked=Module["_fflush_unlocked"]=wasmExports["fflush_unlocked"])(a0);var _ffs=Module["_ffs"]=a0=>(_ffs=Module["_ffs"]=wasmExports["ffs"])(a0);var _ffsl=Module["_ffsl"]=a0=>(_ffsl=Module["_ffsl"]=wasmExports["ffsl"])(a0);var _ffsll=Module["_ffsll"]=a0=>(_ffsll=Module["_ffsll"]=wasmExports["ffsll"])(a0);var _emscripten_futex_wake=Module["_emscripten_futex_wake"]=(a0,a1)=>(_emscripten_futex_wake=Module["_emscripten_futex_wake"]=wasmExports["emscripten_futex_wake"])(a0,a1);var _fgetln=Module["_fgetln"]=(a0,a1)=>(_fgetln=Module["_fgetln"]=wasmExports["fgetln"])(a0,a1);var _getline=Module["_getline"]=(a0,a1,a2)=>(_getline=Module["_getline"]=wasmExports["getline"])(a0,a1,a2);var _fgetpos=Module["_fgetpos"]=(a0,a1)=>(_fgetpos=Module["_fgetpos"]=wasmExports["fgetpos"])(a0,a1);var _fgets_unlocked=Module["_fgets_unlocked"]=(a0,a1,a2)=>(_fgets_unlocked=Module["_fgets_unlocked"]=wasmExports["fgets_unlocked"])(a0,a1,a2);var ___fgetwc_unlocked=Module["___fgetwc_unlocked"]=a0=>(___fgetwc_unlocked=Module["___fgetwc_unlocked"]=wasmExports["__fgetwc_unlocked"])(a0);var _fwide=Module["_fwide"]=(a0,a1)=>(_fwide=Module["_fwide"]=wasmExports["fwide"])(a0,a1);var _mbtowc=Module["_mbtowc"]=(a0,a1,a2)=>(_mbtowc=Module["_mbtowc"]=wasmExports["mbtowc"])(a0,a1,a2);var _fgetwc=Module["_fgetwc"]=a0=>(_fgetwc=Module["_fgetwc"]=wasmExports["fgetwc"])(a0);var _fgetwc_unlocked=Module["_fgetwc_unlocked"]=a0=>(_fgetwc_unlocked=Module["_fgetwc_unlocked"]=wasmExports["fgetwc_unlocked"])(a0);var _getwc_unlocked=Module["_getwc_unlocked"]=a0=>(_getwc_unlocked=Module["_getwc_unlocked"]=wasmExports["getwc_unlocked"])(a0);var _fgetws=Module["_fgetws"]=(a0,a1,a2)=>(_fgetws=Module["_fgetws"]=wasmExports["fgetws"])(a0,a1,a2);var _fgetws_unlocked=Module["_fgetws_unlocked"]=(a0,a1,a2)=>(_fgetws_unlocked=Module["_fgetws_unlocked"]=wasmExports["fgetws_unlocked"])(a0,a1,a2);var _fileno_unlocked=Module["_fileno_unlocked"]=a0=>(_fileno_unlocked=Module["_fileno_unlocked"]=wasmExports["fileno_unlocked"])(a0);var _finite=Module["_finite"]=a0=>(_finite=Module["_finite"]=wasmExports["finite"])(a0);var _finitef=Module["_finitef"]=a0=>(_finitef=Module["_finitef"]=wasmExports["finitef"])(a0);var ___floatunsitf=Module["___floatunsitf"]=(a0,a1)=>(___floatunsitf=Module["___floatunsitf"]=wasmExports["__floatunsitf"])(a0,a1);var _fmodl=Module["_fmodl"]=(a0,a1,a2,a3,a4)=>(_fmodl=Module["_fmodl"]=wasmExports["fmodl"])(a0,a1,a2,a3,a4);var _ftrylockfile=Module["_ftrylockfile"]=a0=>(_ftrylockfile=Module["_ftrylockfile"]=wasmExports["ftrylockfile"])(a0);var _floorf=Module["_floorf"]=a0=>(_floorf=Module["_floorf"]=wasmExports["floorf"])(a0);var _floorl=Module["_floorl"]=(a0,a1,a2)=>(_floorl=Module["_floorl"]=wasmExports["floorl"])(a0,a1,a2);var _fmaf=Module["_fmaf"]=(a0,a1,a2)=>(_fmaf=Module["_fmaf"]=wasmExports["fmaf"])(a0,a1,a2);var _fmal=Module["_fmal"]=(a0,a1,a2,a3,a4,a5,a6)=>(_fmal=Module["_fmal"]=wasmExports["fmal"])(a0,a1,a2,a3,a4,a5,a6);var _frexpl=Module["_frexpl"]=(a0,a1,a2,a3)=>(_frexpl=Module["_frexpl"]=wasmExports["frexpl"])(a0,a1,a2,a3);var _nextafterl=Module["_nextafterl"]=(a0,a1,a2,a3,a4)=>(_nextafterl=Module["_nextafterl"]=wasmExports["nextafterl"])(a0,a1,a2,a3,a4);var _ilogbl=Module["_ilogbl"]=(a0,a1)=>(_ilogbl=Module["_ilogbl"]=wasmExports["ilogbl"])(a0,a1);var _fmax=Module["_fmax"]=(a0,a1)=>(_fmax=Module["_fmax"]=wasmExports["fmax"])(a0,a1);var _fmaxf=Module["_fmaxf"]=(a0,a1)=>(_fmaxf=Module["_fmaxf"]=wasmExports["fmaxf"])(a0,a1);var _fmaxl=Module["_fmaxl"]=(a0,a1,a2,a3,a4)=>(_fmaxl=Module["_fmaxl"]=wasmExports["fmaxl"])(a0,a1,a2,a3,a4);var _fmemopen=Module["_fmemopen"]=(a0,a1,a2)=>(_fmemopen=Module["_fmemopen"]=wasmExports["fmemopen"])(a0,a1,a2);var _fmin=Module["_fmin"]=(a0,a1)=>(_fmin=Module["_fmin"]=wasmExports["fmin"])(a0,a1);var _fminf=Module["_fminf"]=(a0,a1)=>(_fminf=Module["_fminf"]=wasmExports["fminf"])(a0,a1);var _fminl=Module["_fminl"]=(a0,a1,a2,a3,a4)=>(_fminl=Module["_fminl"]=wasmExports["fminl"])(a0,a1,a2,a3,a4);var _fmodf=Module["_fmodf"]=(a0,a1)=>(_fmodf=Module["_fmodf"]=wasmExports["fmodf"])(a0,a1);var _fmtmsg=Module["_fmtmsg"]=(a0,a1,a2,a3,a4,a5)=>(_fmtmsg=Module["_fmtmsg"]=wasmExports["fmtmsg"])(a0,a1,a2,a3,a4,a5);var _fnmatch=Module["_fnmatch"]=(a0,a1,a2)=>(_fnmatch=Module["_fnmatch"]=wasmExports["fnmatch"])(a0,a1,a2);var _towupper=Module["_towupper"]=a0=>(_towupper=Module["_towupper"]=wasmExports["towupper"])(a0);var _towlower=Module["_towlower"]=a0=>(_towlower=Module["_towlower"]=wasmExports["towlower"])(a0);var _wctype=Module["_wctype"]=a0=>(_wctype=Module["_wctype"]=wasmExports["wctype"])(a0);var _iswctype=Module["_iswctype"]=(a0,a1)=>(_iswctype=Module["_iswctype"]=wasmExports["iswctype"])(a0,a1);var _fopencookie=Module["_fopencookie"]=(a0,a1,a2)=>(_fopencookie=Module["_fopencookie"]=wasmExports["fopencookie"])(a0,a1,a2);var _forkpty=Module["_forkpty"]=(a0,a1,a2,a3)=>(_forkpty=Module["_forkpty"]=wasmExports["forkpty"])(a0,a1,a2,a3);var _openpty=Module["_openpty"]=(a0,a1,a2,a3,a4)=>(_openpty=Module["_openpty"]=wasmExports["openpty"])(a0,a1,a2,a3,a4);var _pipe2=Module["_pipe2"]=(a0,a1)=>(_pipe2=Module["_pipe2"]=wasmExports["pipe2"])(a0,a1);var _vfiprintf=Module["_vfiprintf"]=(a0,a1,a2)=>(_vfiprintf=Module["_vfiprintf"]=wasmExports["vfiprintf"])(a0,a1,a2);var ___small_vfprintf=Module["___small_vfprintf"]=(a0,a1,a2)=>(___small_vfprintf=Module["___small_vfprintf"]=wasmExports["__small_vfprintf"])(a0,a1,a2);var _fputs_unlocked=Module["_fputs_unlocked"]=(a0,a1)=>(_fputs_unlocked=Module["_fputs_unlocked"]=wasmExports["fputs_unlocked"])(a0,a1);var ___fputwc_unlocked=Module["___fputwc_unlocked"]=(a0,a1)=>(___fputwc_unlocked=Module["___fputwc_unlocked"]=wasmExports["__fputwc_unlocked"])(a0,a1);var _wctomb=Module["_wctomb"]=(a0,a1)=>(_wctomb=Module["_wctomb"]=wasmExports["wctomb"])(a0,a1);var _fputwc=Module["_fputwc"]=(a0,a1)=>(_fputwc=Module["_fputwc"]=wasmExports["fputwc"])(a0,a1);var _fputwc_unlocked=Module["_fputwc_unlocked"]=(a0,a1)=>(_fputwc_unlocked=Module["_fputwc_unlocked"]=wasmExports["fputwc_unlocked"])(a0,a1);var _putwc_unlocked=Module["_putwc_unlocked"]=(a0,a1)=>(_putwc_unlocked=Module["_putwc_unlocked"]=wasmExports["putwc_unlocked"])(a0,a1);var _fputws=Module["_fputws"]=(a0,a1)=>(_fputws=Module["_fputws"]=wasmExports["fputws"])(a0,a1);var _wcsrtombs=Module["_wcsrtombs"]=(a0,a1,a2,a3)=>(_wcsrtombs=Module["_wcsrtombs"]=wasmExports["wcsrtombs"])(a0,a1,a2,a3);var _fputws_unlocked=Module["_fputws_unlocked"]=(a0,a1)=>(_fputws_unlocked=Module["_fputws_unlocked"]=wasmExports["fputws_unlocked"])(a0,a1);var _fread_unlocked=Module["_fread_unlocked"]=(a0,a1,a2,a3)=>(_fread_unlocked=Module["_fread_unlocked"]=wasmExports["fread_unlocked"])(a0,a1,a2,a3);var _freelocale=Module["_freelocale"]=a0=>(_freelocale=Module["_freelocale"]=wasmExports["freelocale"])(a0);var ___freelocale=Module["___freelocale"]=a0=>(___freelocale=Module["___freelocale"]=wasmExports["__freelocale"])(a0);var _freopen=Module["_freopen"]=(a0,a1,a2)=>(_freopen=Module["_freopen"]=wasmExports["freopen"])(a0,a1,a2);var _frexpf=Module["_frexpf"]=(a0,a1)=>(_frexpf=Module["_frexpf"]=wasmExports["frexpf"])(a0,a1);var _fscanf=Module["_fscanf"]=(a0,a1,a2)=>(_fscanf=Module["_fscanf"]=wasmExports["fscanf"])(a0,a1,a2);var _vfscanf=Module["_vfscanf"]=(a0,a1,a2)=>(_vfscanf=Module["_vfscanf"]=wasmExports["vfscanf"])(a0,a1,a2);var ___isoc99_fscanf=Module["___isoc99_fscanf"]=(a0,a1,a2)=>(___isoc99_fscanf=Module["___isoc99_fscanf"]=wasmExports["__isoc99_fscanf"])(a0,a1,a2);var _fseek=Module["_fseek"]=(a0,a1,a2)=>(_fseek=Module["_fseek"]=wasmExports["fseek"])(a0,a1,a2);var _fseeko=Module["_fseeko"]=(a0,a1,a2)=>(_fseeko=Module["_fseeko"]=wasmExports["fseeko"])(a0,a1,a2);var _fsetpos=Module["_fsetpos"]=(a0,a1)=>(_fsetpos=Module["_fsetpos"]=wasmExports["fsetpos"])(a0,a1);var _ftello=Module["_ftello"]=a0=>(_ftello=Module["_ftello"]=wasmExports["ftello"])(a0);var _ftime=Module["_ftime"]=a0=>(_ftime=Module["_ftime"]=wasmExports["ftime"])(a0);var _utimensat=Module["_utimensat"]=(a0,a1,a2,a3)=>(_utimensat=Module["_utimensat"]=wasmExports["utimensat"])(a0,a1,a2,a3);var _fwprintf=Module["_fwprintf"]=(a0,a1,a2)=>(_fwprintf=Module["_fwprintf"]=wasmExports["fwprintf"])(a0,a1,a2);var _vfwprintf=Module["_vfwprintf"]=(a0,a1,a2)=>(_vfwprintf=Module["_vfwprintf"]=wasmExports["vfwprintf"])(a0,a1,a2);var _fwrite_unlocked=Module["_fwrite_unlocked"]=(a0,a1,a2,a3)=>(_fwrite_unlocked=Module["_fwrite_unlocked"]=wasmExports["fwrite_unlocked"])(a0,a1,a2,a3);var _fwscanf=Module["_fwscanf"]=(a0,a1,a2)=>(_fwscanf=Module["_fwscanf"]=wasmExports["fwscanf"])(a0,a1,a2);var _vfwscanf=Module["_vfwscanf"]=(a0,a1,a2)=>(_vfwscanf=Module["_vfwscanf"]=wasmExports["vfwscanf"])(a0,a1,a2);var ___isoc99_fwscanf=Module["___isoc99_fwscanf"]=(a0,a1,a2)=>(___isoc99_fwscanf=Module["___isoc99_fwscanf"]=wasmExports["__isoc99_fwscanf"])(a0,a1,a2);var _gcvt=Module["_gcvt"]=(a0,a1,a2)=>(_gcvt=Module["_gcvt"]=wasmExports["gcvt"])(a0,a1,a2);var _get_current_dir_name=Module["_get_current_dir_name"]=()=>(_get_current_dir_name=Module["_get_current_dir_name"]=wasmExports["get_current_dir_name"])();var _strdup=Module["_strdup"]=a0=>(_strdup=Module["_strdup"]=wasmExports["strdup"])(a0);var __IO_getc=Module["__IO_getc"]=a0=>(__IO_getc=Module["__IO_getc"]=wasmExports["_IO_getc"])(a0);var _fgetc_unlocked=Module["_fgetc_unlocked"]=a0=>(_fgetc_unlocked=Module["_fgetc_unlocked"]=wasmExports["fgetc_unlocked"])(a0);var __IO_getc_unlocked=Module["__IO_getc_unlocked"]=a0=>(__IO_getc_unlocked=Module["__IO_getc_unlocked"]=wasmExports["_IO_getc_unlocked"])(a0);var _getchar=Module["_getchar"]=()=>(_getchar=Module["_getchar"]=wasmExports["getchar"])();var _getchar_unlocked=Module["_getchar_unlocked"]=()=>(_getchar_unlocked=Module["_getchar_unlocked"]=wasmExports["getchar_unlocked"])();var _getdelim=Module["_getdelim"]=(a0,a1,a2,a3)=>(_getdelim=Module["_getdelim"]=wasmExports["getdelim"])(a0,a1,a2,a3);var ___getdelim=Module["___getdelim"]=(a0,a1,a2,a3)=>(___getdelim=Module["___getdelim"]=wasmExports["__getdelim"])(a0,a1,a2,a3);var _getdents=Module["_getdents"]=(a0,a1,a2)=>(_getdents=Module["_getdents"]=wasmExports["getdents"])(a0,a1,a2);var _getdomainname=Module["_getdomainname"]=(a0,a1)=>(_getdomainname=Module["_getdomainname"]=wasmExports["getdomainname"])(a0,a1);var _getegid=Module["_getegid"]=()=>(_getegid=Module["_getegid"]=wasmExports["getegid"])();var _geteuid=Module["_geteuid"]=()=>(_geteuid=Module["_geteuid"]=wasmExports["geteuid"])();var _getgroups=Module["_getgroups"]=(a0,a1)=>(_getgroups=Module["_getgroups"]=wasmExports["getgroups"])(a0,a1);var _gethostid=Module["_gethostid"]=()=>(_gethostid=Module["_gethostid"]=wasmExports["gethostid"])();var _freeifaddrs=Module["_freeifaddrs"]=a0=>(_freeifaddrs=Module["_freeifaddrs"]=wasmExports["freeifaddrs"])(a0);var _getifaddrs=Module["_getifaddrs"]=a0=>(_getifaddrs=Module["_getifaddrs"]=wasmExports["getifaddrs"])(a0);var ___getitimer=Module["___getitimer"]=(a0,a1,a2)=>(___getitimer=Module["___getitimer"]=wasmExports["__getitimer"])(a0,a1,a2);var _getlogin_r=Module["_getlogin_r"]=(a0,a1)=>(_getlogin_r=Module["_getlogin_r"]=wasmExports["getlogin_r"])(a0,a1);var _getopt=Module["_getopt"]=(a0,a1,a2)=>(_getopt=Module["_getopt"]=wasmExports["getopt"])(a0,a1,a2);var ___posix_getopt=Module["___posix_getopt"]=(a0,a1,a2)=>(___posix_getopt=Module["___posix_getopt"]=wasmExports["__posix_getopt"])(a0,a1,a2);var _getopt_long=Module["_getopt_long"]=(a0,a1,a2,a3,a4)=>(_getopt_long=Module["_getopt_long"]=wasmExports["getopt_long"])(a0,a1,a2,a3,a4);var _getopt_long_only=Module["_getopt_long_only"]=(a0,a1,a2,a3,a4)=>(_getopt_long_only=Module["_getopt_long_only"]=wasmExports["getopt_long_only"])(a0,a1,a2,a3,a4);var _mblen=Module["_mblen"]=(a0,a1)=>(_mblen=Module["_mblen"]=wasmExports["mblen"])(a0,a1);var _getpagesize=Module["_getpagesize"]=()=>(_getpagesize=Module["_getpagesize"]=wasmExports["getpagesize"])();var _getresgid=Module["_getresgid"]=(a0,a1,a2)=>(_getresgid=Module["_getresgid"]=wasmExports["getresgid"])(a0,a1,a2);var _getresuid=Module["_getresuid"]=(a0,a1,a2)=>(_getresuid=Module["_getresuid"]=wasmExports["getresuid"])(a0,a1,a2);var _getrusage=Module["_getrusage"]=(a0,a1)=>(_getrusage=Module["_getrusage"]=wasmExports["getrusage"])(a0,a1);var _gets=Module["_gets"]=a0=>(_gets=Module["_gets"]=wasmExports["gets"])(a0);var _getservbyname_r=Module["_getservbyname_r"]=(a0,a1,a2,a3,a4,a5)=>(_getservbyname_r=Module["_getservbyname_r"]=wasmExports["getservbyname_r"])(a0,a1,a2,a3,a4,a5);var _getservbyport_r=Module["_getservbyport_r"]=(a0,a1,a2,a3,a4,a5)=>(_getservbyport_r=Module["_getservbyport_r"]=wasmExports["getservbyport_r"])(a0,a1,a2,a3,a4,a5);var _getsubopt=Module["_getsubopt"]=(a0,a1,a2)=>(_getsubopt=Module["_getsubopt"]=wasmExports["getsubopt"])(a0,a1,a2);var _gettid=Module["_gettid"]=()=>(_gettid=Module["_gettid"]=wasmExports["gettid"])();var _getw=Module["_getw"]=a0=>(_getw=Module["_getw"]=wasmExports["getw"])(a0);var _getwc=Module["_getwc"]=a0=>(_getwc=Module["_getwc"]=wasmExports["getwc"])(a0);var _getwchar=Module["_getwchar"]=()=>(_getwchar=Module["_getwchar"]=wasmExports["getwchar"])();var _getwchar_unlocked=Module["_getwchar_unlocked"]=()=>(_getwchar_unlocked=Module["_getwchar_unlocked"]=wasmExports["getwchar_unlocked"])();var _glob=Module["_glob"]=(a0,a1,a2,a3)=>(_glob=Module["_glob"]=wasmExports["glob"])(a0,a1,a2,a3);var _globfree=Module["_globfree"]=a0=>(_globfree=Module["_globfree"]=wasmExports["globfree"])(a0);var _gmtime=Module["_gmtime"]=a0=>(_gmtime=Module["_gmtime"]=wasmExports["gmtime"])(a0);var _herror=Module["_herror"]=a0=>(_herror=Module["_herror"]=wasmExports["herror"])(a0);var _hcreate=Module["_hcreate"]=a0=>(_hcreate=Module["_hcreate"]=wasmExports["hcreate"])(a0);var _hdestroy=Module["_hdestroy"]=()=>(_hdestroy=Module["_hdestroy"]=wasmExports["hdestroy"])();var _hsearch=Module["_hsearch"]=(a0,a1)=>(_hsearch=Module["_hsearch"]=wasmExports["hsearch"])(a0,a1);var _hcreate_r=Module["_hcreate_r"]=(a0,a1)=>(_hcreate_r=Module["_hcreate_r"]=wasmExports["hcreate_r"])(a0,a1);var _hdestroy_r=Module["_hdestroy_r"]=a0=>(_hdestroy_r=Module["_hdestroy_r"]=wasmExports["hdestroy_r"])(a0);var _hsearch_r=Module["_hsearch_r"]=(a0,a1,a2,a3)=>(_hsearch_r=Module["_hsearch_r"]=wasmExports["hsearch_r"])(a0,a1,a2,a3);var _iconv_open=Module["_iconv_open"]=(a0,a1)=>(_iconv_open=Module["_iconv_open"]=wasmExports["iconv_open"])(a0,a1);var _iconv=Module["_iconv"]=(a0,a1,a2,a3,a4)=>(_iconv=Module["_iconv"]=wasmExports["iconv"])(a0,a1,a2,a3,a4);var _iconv_close=Module["_iconv_close"]=a0=>(_iconv_close=Module["_iconv_close"]=wasmExports["iconv_close"])(a0);var _ioctl=Module["_ioctl"]=(a0,a1,a2)=>(_ioctl=Module["_ioctl"]=wasmExports["ioctl"])(a0,a1,a2);var _ilogb=Module["_ilogb"]=a0=>(_ilogb=Module["_ilogb"]=wasmExports["ilogb"])(a0);var _ilogbf=Module["_ilogbf"]=a0=>(_ilogbf=Module["_ilogbf"]=wasmExports["ilogbf"])(a0);var _imaxabs=Module["_imaxabs"]=a0=>(_imaxabs=Module["_imaxabs"]=wasmExports["imaxabs"])(a0);var _imaxdiv=Module["_imaxdiv"]=(a0,a1,a2)=>(_imaxdiv=Module["_imaxdiv"]=wasmExports["imaxdiv"])(a0,a1,a2);var _index=Module["_index"]=(a0,a1)=>(_index=Module["_index"]=wasmExports["index"])(a0,a1);var _inet_addr=Module["_inet_addr"]=a0=>(_inet_addr=Module["_inet_addr"]=wasmExports["inet_addr"])(a0);var _inet_network=Module["_inet_network"]=a0=>(_inet_network=Module["_inet_network"]=wasmExports["inet_network"])(a0);var _inet_makeaddr=Module["_inet_makeaddr"]=(a0,a1)=>(_inet_makeaddr=Module["_inet_makeaddr"]=wasmExports["inet_makeaddr"])(a0,a1);var _inet_lnaof=Module["_inet_lnaof"]=a0=>(_inet_lnaof=Module["_inet_lnaof"]=wasmExports["inet_lnaof"])(a0);var _inet_netof=Module["_inet_netof"]=a0=>(_inet_netof=Module["_inet_netof"]=wasmExports["inet_netof"])(a0);var _insque=Module["_insque"]=(a0,a1)=>(_insque=Module["_insque"]=wasmExports["insque"])(a0,a1);var _remque=Module["_remque"]=a0=>(_remque=Module["_remque"]=wasmExports["remque"])(a0);var ___intscan=Module["___intscan"]=(a0,a1,a2,a3)=>(___intscan=Module["___intscan"]=wasmExports["__intscan"])(a0,a1,a2,a3);var ___multi3=Module["___multi3"]=(a0,a1,a2,a3,a4)=>(___multi3=Module["___multi3"]=wasmExports["__multi3"])(a0,a1,a2,a3,a4);var ___isalnum_l=Module["___isalnum_l"]=(a0,a1)=>(___isalnum_l=Module["___isalnum_l"]=wasmExports["__isalnum_l"])(a0,a1);var _isalnum_l=Module["_isalnum_l"]=(a0,a1)=>(_isalnum_l=Module["_isalnum_l"]=wasmExports["isalnum_l"])(a0,a1);var _isalpha=Module["_isalpha"]=a0=>(_isalpha=Module["_isalpha"]=wasmExports["isalpha"])(a0);var ___isalpha_l=Module["___isalpha_l"]=(a0,a1)=>(___isalpha_l=Module["___isalpha_l"]=wasmExports["__isalpha_l"])(a0,a1);var _isalpha_l=Module["_isalpha_l"]=(a0,a1)=>(_isalpha_l=Module["_isalpha_l"]=wasmExports["isalpha_l"])(a0,a1);var _isascii=Module["_isascii"]=a0=>(_isascii=Module["_isascii"]=wasmExports["isascii"])(a0);var _isblank=Module["_isblank"]=a0=>(_isblank=Module["_isblank"]=wasmExports["isblank"])(a0);var ___isblank_l=Module["___isblank_l"]=(a0,a1)=>(___isblank_l=Module["___isblank_l"]=wasmExports["__isblank_l"])(a0,a1);var _isblank_l=Module["_isblank_l"]=(a0,a1)=>(_isblank_l=Module["_isblank_l"]=wasmExports["isblank_l"])(a0,a1);var _iscntrl=Module["_iscntrl"]=a0=>(_iscntrl=Module["_iscntrl"]=wasmExports["iscntrl"])(a0);var ___iscntrl_l=Module["___iscntrl_l"]=(a0,a1)=>(___iscntrl_l=Module["___iscntrl_l"]=wasmExports["__iscntrl_l"])(a0,a1);var _iscntrl_l=Module["_iscntrl_l"]=(a0,a1)=>(_iscntrl_l=Module["_iscntrl_l"]=wasmExports["iscntrl_l"])(a0,a1);var _isdigit=Module["_isdigit"]=a0=>(_isdigit=Module["_isdigit"]=wasmExports["isdigit"])(a0);var ___isdigit_l=Module["___isdigit_l"]=(a0,a1)=>(___isdigit_l=Module["___isdigit_l"]=wasmExports["__isdigit_l"])(a0,a1);var _isdigit_l=Module["_isdigit_l"]=(a0,a1)=>(_isdigit_l=Module["_isdigit_l"]=wasmExports["isdigit_l"])(a0,a1);var _isgraph=Module["_isgraph"]=a0=>(_isgraph=Module["_isgraph"]=wasmExports["isgraph"])(a0);var ___isgraph_l=Module["___isgraph_l"]=(a0,a1)=>(___isgraph_l=Module["___isgraph_l"]=wasmExports["__isgraph_l"])(a0,a1);var _isgraph_l=Module["_isgraph_l"]=(a0,a1)=>(_isgraph_l=Module["_isgraph_l"]=wasmExports["isgraph_l"])(a0,a1);var _islower=Module["_islower"]=a0=>(_islower=Module["_islower"]=wasmExports["islower"])(a0);var ___islower_l=Module["___islower_l"]=(a0,a1)=>(___islower_l=Module["___islower_l"]=wasmExports["__islower_l"])(a0,a1);var _islower_l=Module["_islower_l"]=(a0,a1)=>(_islower_l=Module["_islower_l"]=wasmExports["islower_l"])(a0,a1);var _isprint=Module["_isprint"]=a0=>(_isprint=Module["_isprint"]=wasmExports["isprint"])(a0);var ___isprint_l=Module["___isprint_l"]=(a0,a1)=>(___isprint_l=Module["___isprint_l"]=wasmExports["__isprint_l"])(a0,a1);var _isprint_l=Module["_isprint_l"]=(a0,a1)=>(_isprint_l=Module["_isprint_l"]=wasmExports["isprint_l"])(a0,a1);var _ispunct=Module["_ispunct"]=a0=>(_ispunct=Module["_ispunct"]=wasmExports["ispunct"])(a0);var ___ispunct_l=Module["___ispunct_l"]=(a0,a1)=>(___ispunct_l=Module["___ispunct_l"]=wasmExports["__ispunct_l"])(a0,a1);var _ispunct_l=Module["_ispunct_l"]=(a0,a1)=>(_ispunct_l=Module["_ispunct_l"]=wasmExports["ispunct_l"])(a0,a1);var _issetugid=Module["_issetugid"]=()=>(_issetugid=Module["_issetugid"]=wasmExports["issetugid"])();var _isspace=Module["_isspace"]=a0=>(_isspace=Module["_isspace"]=wasmExports["isspace"])(a0);var ___isspace_l=Module["___isspace_l"]=(a0,a1)=>(___isspace_l=Module["___isspace_l"]=wasmExports["__isspace_l"])(a0,a1);var _isspace_l=Module["_isspace_l"]=(a0,a1)=>(_isspace_l=Module["_isspace_l"]=wasmExports["isspace_l"])(a0,a1);var _isupper=Module["_isupper"]=a0=>(_isupper=Module["_isupper"]=wasmExports["isupper"])(a0);var ___isupper_l=Module["___isupper_l"]=(a0,a1)=>(___isupper_l=Module["___isupper_l"]=wasmExports["__isupper_l"])(a0,a1);var _isupper_l=Module["_isupper_l"]=(a0,a1)=>(_isupper_l=Module["_isupper_l"]=wasmExports["isupper_l"])(a0,a1);var _iswalnum=Module["_iswalnum"]=a0=>(_iswalnum=Module["_iswalnum"]=wasmExports["iswalnum"])(a0);var _iswalpha=Module["_iswalpha"]=a0=>(_iswalpha=Module["_iswalpha"]=wasmExports["iswalpha"])(a0);var ___iswalnum_l=Module["___iswalnum_l"]=(a0,a1)=>(___iswalnum_l=Module["___iswalnum_l"]=wasmExports["__iswalnum_l"])(a0,a1);var _iswalnum_l=Module["_iswalnum_l"]=(a0,a1)=>(_iswalnum_l=Module["_iswalnum_l"]=wasmExports["iswalnum_l"])(a0,a1);var ___iswalpha_l=Module["___iswalpha_l"]=(a0,a1)=>(___iswalpha_l=Module["___iswalpha_l"]=wasmExports["__iswalpha_l"])(a0,a1);var _iswalpha_l=Module["_iswalpha_l"]=(a0,a1)=>(_iswalpha_l=Module["_iswalpha_l"]=wasmExports["iswalpha_l"])(a0,a1);var _iswblank=Module["_iswblank"]=a0=>(_iswblank=Module["_iswblank"]=wasmExports["iswblank"])(a0);var ___iswblank_l=Module["___iswblank_l"]=(a0,a1)=>(___iswblank_l=Module["___iswblank_l"]=wasmExports["__iswblank_l"])(a0,a1);var _iswblank_l=Module["_iswblank_l"]=(a0,a1)=>(_iswblank_l=Module["_iswblank_l"]=wasmExports["iswblank_l"])(a0,a1);var _iswcntrl=Module["_iswcntrl"]=a0=>(_iswcntrl=Module["_iswcntrl"]=wasmExports["iswcntrl"])(a0);var ___iswcntrl_l=Module["___iswcntrl_l"]=(a0,a1)=>(___iswcntrl_l=Module["___iswcntrl_l"]=wasmExports["__iswcntrl_l"])(a0,a1);var _iswcntrl_l=Module["_iswcntrl_l"]=(a0,a1)=>(_iswcntrl_l=Module["_iswcntrl_l"]=wasmExports["iswcntrl_l"])(a0,a1);var _iswgraph=Module["_iswgraph"]=a0=>(_iswgraph=Module["_iswgraph"]=wasmExports["iswgraph"])(a0);var _iswlower=Module["_iswlower"]=a0=>(_iswlower=Module["_iswlower"]=wasmExports["iswlower"])(a0);var _iswprint=Module["_iswprint"]=a0=>(_iswprint=Module["_iswprint"]=wasmExports["iswprint"])(a0);var _iswpunct=Module["_iswpunct"]=a0=>(_iswpunct=Module["_iswpunct"]=wasmExports["iswpunct"])(a0);var _iswspace=Module["_iswspace"]=a0=>(_iswspace=Module["_iswspace"]=wasmExports["iswspace"])(a0);var _iswupper=Module["_iswupper"]=a0=>(_iswupper=Module["_iswupper"]=wasmExports["iswupper"])(a0);var _iswxdigit=Module["_iswxdigit"]=a0=>(_iswxdigit=Module["_iswxdigit"]=wasmExports["iswxdigit"])(a0);var ___iswctype_l=Module["___iswctype_l"]=(a0,a1,a2)=>(___iswctype_l=Module["___iswctype_l"]=wasmExports["__iswctype_l"])(a0,a1,a2);var ___wctype_l=Module["___wctype_l"]=(a0,a1)=>(___wctype_l=Module["___wctype_l"]=wasmExports["__wctype_l"])(a0,a1);var _iswctype_l=Module["_iswctype_l"]=(a0,a1,a2)=>(_iswctype_l=Module["_iswctype_l"]=wasmExports["iswctype_l"])(a0,a1,a2);var _wctype_l=Module["_wctype_l"]=(a0,a1)=>(_wctype_l=Module["_wctype_l"]=wasmExports["wctype_l"])(a0,a1);var _iswdigit=Module["_iswdigit"]=a0=>(_iswdigit=Module["_iswdigit"]=wasmExports["iswdigit"])(a0);var ___iswdigit_l=Module["___iswdigit_l"]=(a0,a1)=>(___iswdigit_l=Module["___iswdigit_l"]=wasmExports["__iswdigit_l"])(a0,a1);var _iswdigit_l=Module["_iswdigit_l"]=(a0,a1)=>(_iswdigit_l=Module["_iswdigit_l"]=wasmExports["iswdigit_l"])(a0,a1);var ___iswgraph_l=Module["___iswgraph_l"]=(a0,a1)=>(___iswgraph_l=Module["___iswgraph_l"]=wasmExports["__iswgraph_l"])(a0,a1);var _iswgraph_l=Module["_iswgraph_l"]=(a0,a1)=>(_iswgraph_l=Module["_iswgraph_l"]=wasmExports["iswgraph_l"])(a0,a1);var ___iswlower_l=Module["___iswlower_l"]=(a0,a1)=>(___iswlower_l=Module["___iswlower_l"]=wasmExports["__iswlower_l"])(a0,a1);var _iswlower_l=Module["_iswlower_l"]=(a0,a1)=>(_iswlower_l=Module["_iswlower_l"]=wasmExports["iswlower_l"])(a0,a1);var ___iswprint_l=Module["___iswprint_l"]=(a0,a1)=>(___iswprint_l=Module["___iswprint_l"]=wasmExports["__iswprint_l"])(a0,a1);var _iswprint_l=Module["_iswprint_l"]=(a0,a1)=>(_iswprint_l=Module["_iswprint_l"]=wasmExports["iswprint_l"])(a0,a1);var ___iswpunct_l=Module["___iswpunct_l"]=(a0,a1)=>(___iswpunct_l=Module["___iswpunct_l"]=wasmExports["__iswpunct_l"])(a0,a1);var _iswpunct_l=Module["_iswpunct_l"]=(a0,a1)=>(_iswpunct_l=Module["_iswpunct_l"]=wasmExports["iswpunct_l"])(a0,a1);var ___iswspace_l=Module["___iswspace_l"]=(a0,a1)=>(___iswspace_l=Module["___iswspace_l"]=wasmExports["__iswspace_l"])(a0,a1);var _iswspace_l=Module["_iswspace_l"]=(a0,a1)=>(_iswspace_l=Module["_iswspace_l"]=wasmExports["iswspace_l"])(a0,a1);var ___iswupper_l=Module["___iswupper_l"]=(a0,a1)=>(___iswupper_l=Module["___iswupper_l"]=wasmExports["__iswupper_l"])(a0,a1);var _iswupper_l=Module["_iswupper_l"]=(a0,a1)=>(_iswupper_l=Module["_iswupper_l"]=wasmExports["iswupper_l"])(a0,a1);var ___iswxdigit_l=Module["___iswxdigit_l"]=(a0,a1)=>(___iswxdigit_l=Module["___iswxdigit_l"]=wasmExports["__iswxdigit_l"])(a0,a1);var _iswxdigit_l=Module["_iswxdigit_l"]=(a0,a1)=>(_iswxdigit_l=Module["_iswxdigit_l"]=wasmExports["iswxdigit_l"])(a0,a1);var ___isxdigit_l=Module["___isxdigit_l"]=(a0,a1)=>(___isxdigit_l=Module["___isxdigit_l"]=wasmExports["__isxdigit_l"])(a0,a1);var _isxdigit_l=Module["_isxdigit_l"]=(a0,a1)=>(_isxdigit_l=Module["_isxdigit_l"]=wasmExports["isxdigit_l"])(a0,a1);var _j0=Module["_j0"]=a0=>(_j0=Module["_j0"]=wasmExports["j0"])(a0);var _y0=Module["_y0"]=a0=>(_y0=Module["_y0"]=wasmExports["y0"])(a0);var _j0f=Module["_j0f"]=a0=>(_j0f=Module["_j0f"]=wasmExports["j0f"])(a0);var _y0f=Module["_y0f"]=a0=>(_y0f=Module["_y0f"]=wasmExports["y0f"])(a0);var _j1=Module["_j1"]=a0=>(_j1=Module["_j1"]=wasmExports["j1"])(a0);var _y1=Module["_y1"]=a0=>(_y1=Module["_y1"]=wasmExports["y1"])(a0);var _j1f=Module["_j1f"]=a0=>(_j1f=Module["_j1f"]=wasmExports["j1f"])(a0);var _y1f=Module["_y1f"]=a0=>(_y1f=Module["_y1f"]=wasmExports["y1f"])(a0);var _jn=Module["_jn"]=(a0,a1)=>(_jn=Module["_jn"]=wasmExports["jn"])(a0,a1);var _yn=Module["_yn"]=(a0,a1)=>(_yn=Module["_yn"]=wasmExports["yn"])(a0,a1);var _jnf=Module["_jnf"]=(a0,a1)=>(_jnf=Module["_jnf"]=wasmExports["jnf"])(a0,a1);var _ynf=Module["_ynf"]=(a0,a1)=>(_ynf=Module["_ynf"]=wasmExports["ynf"])(a0,a1);var _labs=Module["_labs"]=a0=>(_labs=Module["_labs"]=wasmExports["labs"])(a0);var ___nl_langinfo=Module["___nl_langinfo"]=a0=>(___nl_langinfo=Module["___nl_langinfo"]=wasmExports["__nl_langinfo"])(a0);var _nl_langinfo_l=Module["_nl_langinfo_l"]=(a0,a1)=>(_nl_langinfo_l=Module["_nl_langinfo_l"]=wasmExports["nl_langinfo_l"])(a0,a1);var _lchmod=Module["_lchmod"]=(a0,a1)=>(_lchmod=Module["_lchmod"]=wasmExports["lchmod"])(a0,a1);var _lchown=Module["_lchown"]=(a0,a1,a2)=>(_lchown=Module["_lchown"]=wasmExports["lchown"])(a0,a1,a2);var _lcong48=Module["_lcong48"]=a0=>(_lcong48=Module["_lcong48"]=wasmExports["lcong48"])(a0);var _ldexpf=Module["_ldexpf"]=(a0,a1)=>(_ldexpf=Module["_ldexpf"]=wasmExports["ldexpf"])(a0,a1);var _scalbnf=Module["_scalbnf"]=(a0,a1)=>(_scalbnf=Module["_scalbnf"]=wasmExports["scalbnf"])(a0,a1);var _ldexpl=Module["_ldexpl"]=(a0,a1,a2,a3)=>(_ldexpl=Module["_ldexpl"]=wasmExports["ldexpl"])(a0,a1,a2,a3);var _ldiv=Module["_ldiv"]=(a0,a1,a2)=>(_ldiv=Module["_ldiv"]=wasmExports["ldiv"])(a0,a1,a2);var _get_nprocs_conf=Module["_get_nprocs_conf"]=()=>(_get_nprocs_conf=Module["_get_nprocs_conf"]=wasmExports["get_nprocs_conf"])();var _get_nprocs=Module["_get_nprocs"]=()=>(_get_nprocs=Module["_get_nprocs"]=wasmExports["get_nprocs"])();var _get_phys_pages=Module["_get_phys_pages"]=()=>(_get_phys_pages=Module["_get_phys_pages"]=wasmExports["get_phys_pages"])();var _get_avphys_pages=Module["_get_avphys_pages"]=()=>(_get_avphys_pages=Module["_get_avphys_pages"]=wasmExports["get_avphys_pages"])();var _lgamma=Module["_lgamma"]=a0=>(_lgamma=Module["_lgamma"]=wasmExports["lgamma"])(a0);var _lgamma_r=Module["_lgamma_r"]=(a0,a1)=>(_lgamma_r=Module["_lgamma_r"]=wasmExports["lgamma_r"])(a0,a1);var _lgammaf=Module["_lgammaf"]=a0=>(_lgammaf=Module["_lgammaf"]=wasmExports["lgammaf"])(a0);var _lgammaf_r=Module["_lgammaf_r"]=(a0,a1)=>(_lgammaf_r=Module["_lgammaf_r"]=wasmExports["lgammaf_r"])(a0,a1);var ___lgammal_r=Module["___lgammal_r"]=(a0,a1,a2,a3)=>(___lgammal_r=Module["___lgammal_r"]=wasmExports["__lgammal_r"])(a0,a1,a2,a3);var _lgammal=Module["_lgammal"]=(a0,a1,a2)=>(_lgammal=Module["_lgammal"]=wasmExports["lgammal"])(a0,a1,a2);var _lgammal_r=Module["_lgammal_r"]=(a0,a1,a2,a3)=>(_lgammal_r=Module["_lgammal_r"]=wasmExports["lgammal_r"])(a0,a1,a2,a3);var _emscripten_has_threading_support=Module["_emscripten_has_threading_support"]=()=>(_emscripten_has_threading_support=Module["_emscripten_has_threading_support"]=wasmExports["emscripten_has_threading_support"])();var _emscripten_num_logical_cores=Module["_emscripten_num_logical_cores"]=()=>(_emscripten_num_logical_cores=Module["_emscripten_num_logical_cores"]=wasmExports["emscripten_num_logical_cores"])();var _emscripten_force_num_logical_cores=Module["_emscripten_force_num_logical_cores"]=a0=>(_emscripten_force_num_logical_cores=Module["_emscripten_force_num_logical_cores"]=wasmExports["emscripten_force_num_logical_cores"])(a0);var _emscripten_futex_wait=Module["_emscripten_futex_wait"]=(a0,a1,a2)=>(_emscripten_futex_wait=Module["_emscripten_futex_wait"]=wasmExports["emscripten_futex_wait"])(a0,a1,a2);var _emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=()=>(_emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=wasmExports["emscripten_main_thread_process_queued_calls"])();var _emscripten_current_thread_process_queued_calls=Module["_emscripten_current_thread_process_queued_calls"]=()=>(_emscripten_current_thread_process_queued_calls=Module["_emscripten_current_thread_process_queued_calls"]=wasmExports["emscripten_current_thread_process_queued_calls"])();var __emscripten_yield=Module["__emscripten_yield"]=a0=>(__emscripten_yield=Module["__emscripten_yield"]=wasmExports["_emscripten_yield"])(a0);var __emscripten_check_timers=Module["__emscripten_check_timers"]=a0=>(__emscripten_check_timers=Module["__emscripten_check_timers"]=wasmExports["_emscripten_check_timers"])(a0);var _pthread_mutex_consistent=Module["_pthread_mutex_consistent"]=a0=>(_pthread_mutex_consistent=Module["_pthread_mutex_consistent"]=wasmExports["pthread_mutex_consistent"])(a0);var _pthread_barrier_init=Module["_pthread_barrier_init"]=(a0,a1,a2)=>(_pthread_barrier_init=Module["_pthread_barrier_init"]=wasmExports["pthread_barrier_init"])(a0,a1,a2);var _pthread_barrier_destroy=Module["_pthread_barrier_destroy"]=a0=>(_pthread_barrier_destroy=Module["_pthread_barrier_destroy"]=wasmExports["pthread_barrier_destroy"])(a0);var _pthread_barrier_wait=Module["_pthread_barrier_wait"]=a0=>(_pthread_barrier_wait=Module["_pthread_barrier_wait"]=wasmExports["pthread_barrier_wait"])(a0);var _pthread_cond_broadcast=Module["_pthread_cond_broadcast"]=a0=>(_pthread_cond_broadcast=Module["_pthread_cond_broadcast"]=wasmExports["pthread_cond_broadcast"])(a0);var _pthread_atfork=Module["_pthread_atfork"]=(a0,a1,a2)=>(_pthread_atfork=Module["_pthread_atfork"]=wasmExports["pthread_atfork"])(a0,a1,a2);var _pthread_cancel=Module["_pthread_cancel"]=a0=>(_pthread_cancel=Module["_pthread_cancel"]=wasmExports["pthread_cancel"])(a0);var _pthread_testcancel=Module["_pthread_testcancel"]=()=>(_pthread_testcancel=Module["_pthread_testcancel"]=wasmExports["pthread_testcancel"])();var ___pthread_detach=Module["___pthread_detach"]=a0=>(___pthread_detach=Module["___pthread_detach"]=wasmExports["__pthread_detach"])(a0);var _pthread_equal=Module["_pthread_equal"]=(a0,a1)=>(_pthread_equal=Module["_pthread_equal"]=wasmExports["pthread_equal"])(a0,a1);var _pthread_mutexattr_init=Module["_pthread_mutexattr_init"]=a0=>(_pthread_mutexattr_init=Module["_pthread_mutexattr_init"]=wasmExports["pthread_mutexattr_init"])(a0);var _pthread_mutexattr_setprotocol=Module["_pthread_mutexattr_setprotocol"]=(a0,a1)=>(_pthread_mutexattr_setprotocol=Module["_pthread_mutexattr_setprotocol"]=wasmExports["pthread_mutexattr_setprotocol"])(a0,a1);var _pthread_mutexattr_settype=Module["_pthread_mutexattr_settype"]=(a0,a1)=>(_pthread_mutexattr_settype=Module["_pthread_mutexattr_settype"]=wasmExports["pthread_mutexattr_settype"])(a0,a1);var _pthread_mutexattr_destroy=Module["_pthread_mutexattr_destroy"]=a0=>(_pthread_mutexattr_destroy=Module["_pthread_mutexattr_destroy"]=wasmExports["pthread_mutexattr_destroy"])(a0);var _pthread_mutexattr_setpshared=Module["_pthread_mutexattr_setpshared"]=(a0,a1)=>(_pthread_mutexattr_setpshared=Module["_pthread_mutexattr_setpshared"]=wasmExports["pthread_mutexattr_setpshared"])(a0,a1);var _pthread_condattr_destroy=Module["_pthread_condattr_destroy"]=a0=>(_pthread_condattr_destroy=Module["_pthread_condattr_destroy"]=wasmExports["pthread_condattr_destroy"])(a0);var _pthread_condattr_setpshared=Module["_pthread_condattr_setpshared"]=(a0,a1)=>(_pthread_condattr_setpshared=Module["_pthread_condattr_setpshared"]=wasmExports["pthread_condattr_setpshared"])(a0,a1);var _pthread_getattr_np=Module["_pthread_getattr_np"]=(a0,a1)=>(_pthread_getattr_np=Module["_pthread_getattr_np"]=wasmExports["pthread_getattr_np"])(a0,a1);var _pthread_setcanceltype=Module["_pthread_setcanceltype"]=(a0,a1)=>(_pthread_setcanceltype=Module["_pthread_setcanceltype"]=wasmExports["pthread_setcanceltype"])(a0,a1);var _pthread_rwlock_init=Module["_pthread_rwlock_init"]=(a0,a1)=>(_pthread_rwlock_init=Module["_pthread_rwlock_init"]=wasmExports["pthread_rwlock_init"])(a0,a1);var _pthread_rwlock_destroy=Module["_pthread_rwlock_destroy"]=a0=>(_pthread_rwlock_destroy=Module["_pthread_rwlock_destroy"]=wasmExports["pthread_rwlock_destroy"])(a0);var _pthread_rwlock_rdlock=Module["_pthread_rwlock_rdlock"]=a0=>(_pthread_rwlock_rdlock=Module["_pthread_rwlock_rdlock"]=wasmExports["pthread_rwlock_rdlock"])(a0);var _pthread_rwlock_tryrdlock=Module["_pthread_rwlock_tryrdlock"]=a0=>(_pthread_rwlock_tryrdlock=Module["_pthread_rwlock_tryrdlock"]=wasmExports["pthread_rwlock_tryrdlock"])(a0);var _pthread_rwlock_timedrdlock=Module["_pthread_rwlock_timedrdlock"]=(a0,a1)=>(_pthread_rwlock_timedrdlock=Module["_pthread_rwlock_timedrdlock"]=wasmExports["pthread_rwlock_timedrdlock"])(a0,a1);var _pthread_rwlock_wrlock=Module["_pthread_rwlock_wrlock"]=a0=>(_pthread_rwlock_wrlock=Module["_pthread_rwlock_wrlock"]=wasmExports["pthread_rwlock_wrlock"])(a0);var _pthread_rwlock_trywrlock=Module["_pthread_rwlock_trywrlock"]=a0=>(_pthread_rwlock_trywrlock=Module["_pthread_rwlock_trywrlock"]=wasmExports["pthread_rwlock_trywrlock"])(a0);var _pthread_rwlock_timedwrlock=Module["_pthread_rwlock_timedwrlock"]=(a0,a1)=>(_pthread_rwlock_timedwrlock=Module["_pthread_rwlock_timedwrlock"]=wasmExports["pthread_rwlock_timedwrlock"])(a0,a1);var _pthread_rwlock_unlock=Module["_pthread_rwlock_unlock"]=a0=>(_pthread_rwlock_unlock=Module["_pthread_rwlock_unlock"]=wasmExports["pthread_rwlock_unlock"])(a0);var _pthread_rwlockattr_init=Module["_pthread_rwlockattr_init"]=a0=>(_pthread_rwlockattr_init=Module["_pthread_rwlockattr_init"]=wasmExports["pthread_rwlockattr_init"])(a0);var _pthread_rwlockattr_destroy=Module["_pthread_rwlockattr_destroy"]=a0=>(_pthread_rwlockattr_destroy=Module["_pthread_rwlockattr_destroy"]=wasmExports["pthread_rwlockattr_destroy"])(a0);var _pthread_rwlockattr_setpshared=Module["_pthread_rwlockattr_setpshared"]=(a0,a1)=>(_pthread_rwlockattr_setpshared=Module["_pthread_rwlockattr_setpshared"]=wasmExports["pthread_rwlockattr_setpshared"])(a0,a1);var _pthread_spin_init=Module["_pthread_spin_init"]=(a0,a1)=>(_pthread_spin_init=Module["_pthread_spin_init"]=wasmExports["pthread_spin_init"])(a0,a1);var _pthread_spin_destroy=Module["_pthread_spin_destroy"]=a0=>(_pthread_spin_destroy=Module["_pthread_spin_destroy"]=wasmExports["pthread_spin_destroy"])(a0);var _pthread_spin_lock=Module["_pthread_spin_lock"]=a0=>(_pthread_spin_lock=Module["_pthread_spin_lock"]=wasmExports["pthread_spin_lock"])(a0);var _pthread_spin_trylock=Module["_pthread_spin_trylock"]=a0=>(_pthread_spin_trylock=Module["_pthread_spin_trylock"]=wasmExports["pthread_spin_trylock"])(a0);var _pthread_spin_unlock=Module["_pthread_spin_unlock"]=a0=>(_pthread_spin_unlock=Module["_pthread_spin_unlock"]=wasmExports["pthread_spin_unlock"])(a0);var _sem_init=Module["_sem_init"]=(a0,a1,a2)=>(_sem_init=Module["_sem_init"]=wasmExports["sem_init"])(a0,a1,a2);var _sem_post=Module["_sem_post"]=a0=>(_sem_post=Module["_sem_post"]=wasmExports["sem_post"])(a0);var _sem_wait=Module["_sem_wait"]=a0=>(_sem_wait=Module["_sem_wait"]=wasmExports["sem_wait"])(a0);var _sem_trywait=Module["_sem_trywait"]=a0=>(_sem_trywait=Module["_sem_trywait"]=wasmExports["sem_trywait"])(a0);var _sem_destroy=Module["_sem_destroy"]=a0=>(_sem_destroy=Module["_sem_destroy"]=wasmExports["sem_destroy"])(a0);var _pthread_mutex_timedlock=Module["_pthread_mutex_timedlock"]=(a0,a1)=>(_pthread_mutex_timedlock=Module["_pthread_mutex_timedlock"]=wasmExports["pthread_mutex_timedlock"])(a0,a1);var _emscripten_builtin_pthread_create=Module["_emscripten_builtin_pthread_create"]=(a0,a1,a2,a3)=>(_emscripten_builtin_pthread_create=Module["_emscripten_builtin_pthread_create"]=wasmExports["emscripten_builtin_pthread_create"])(a0,a1,a2,a3);var _emscripten_builtin_pthread_join=Module["_emscripten_builtin_pthread_join"]=(a0,a1)=>(_emscripten_builtin_pthread_join=Module["_emscripten_builtin_pthread_join"]=wasmExports["emscripten_builtin_pthread_join"])(a0,a1);var _pthread_join=Module["_pthread_join"]=(a0,a1)=>(_pthread_join=Module["_pthread_join"]=wasmExports["pthread_join"])(a0,a1);var _pthread_once=Module["_pthread_once"]=(a0,a1)=>(_pthread_once=Module["_pthread_once"]=wasmExports["pthread_once"])(a0,a1);var _emscripten_builtin_pthread_exit=Module["_emscripten_builtin_pthread_exit"]=a0=>(_emscripten_builtin_pthread_exit=Module["_emscripten_builtin_pthread_exit"]=wasmExports["emscripten_builtin_pthread_exit"])(a0);var _emscripten_builtin_pthread_detach=Module["_emscripten_builtin_pthread_detach"]=a0=>(_emscripten_builtin_pthread_detach=Module["_emscripten_builtin_pthread_detach"]=wasmExports["emscripten_builtin_pthread_detach"])(a0);var _thrd_detach=Module["_thrd_detach"]=a0=>(_thrd_detach=Module["_thrd_detach"]=wasmExports["thrd_detach"])(a0);var _link=Module["_link"]=(a0,a1)=>(_link=Module["_link"]=wasmExports["link"])(a0,a1);var _linkat=Module["_linkat"]=(a0,a1,a2,a3,a4)=>(_linkat=Module["_linkat"]=wasmExports["linkat"])(a0,a1,a2,a3,a4);var _llabs=Module["_llabs"]=a0=>(_llabs=Module["_llabs"]=wasmExports["llabs"])(a0);var _lldiv=Module["_lldiv"]=(a0,a1,a2)=>(_lldiv=Module["_lldiv"]=wasmExports["lldiv"])(a0,a1,a2);var _llrint=Module["_llrint"]=a0=>(_llrint=Module["_llrint"]=wasmExports["llrint"])(a0);var _rint=Module["_rint"]=a0=>(_rint=Module["_rint"]=wasmExports["rint"])(a0);var _llrintf=Module["_llrintf"]=a0=>(_llrintf=Module["_llrintf"]=wasmExports["llrintf"])(a0);var _rintf=Module["_rintf"]=a0=>(_rintf=Module["_rintf"]=wasmExports["rintf"])(a0);var _llrintl=Module["_llrintl"]=(a0,a1)=>(_llrintl=Module["_llrintl"]=wasmExports["llrintl"])(a0,a1);var _rintl=Module["_rintl"]=(a0,a1,a2)=>(_rintl=Module["_rintl"]=wasmExports["rintl"])(a0,a1,a2);var _llround=Module["_llround"]=a0=>(_llround=Module["_llround"]=wasmExports["llround"])(a0);var _llroundf=Module["_llroundf"]=a0=>(_llroundf=Module["_llroundf"]=wasmExports["llroundf"])(a0);var _roundf=Module["_roundf"]=a0=>(_roundf=Module["_roundf"]=wasmExports["roundf"])(a0);var _llroundl=Module["_llroundl"]=(a0,a1)=>(_llroundl=Module["_llroundl"]=wasmExports["llroundl"])(a0,a1);var _roundl=Module["_roundl"]=(a0,a1,a2)=>(_roundl=Module["_roundl"]=wasmExports["roundl"])(a0,a1,a2);var _log10f=Module["_log10f"]=a0=>(_log10f=Module["_log10f"]=wasmExports["log10f"])(a0);var _log10l=Module["_log10l"]=(a0,a1,a2)=>(_log10l=Module["_log10l"]=wasmExports["log10l"])(a0,a1,a2);var _log2f=Module["_log2f"]=a0=>(_log2f=Module["_log2f"]=wasmExports["log2f"])(a0);var _log2l=Module["_log2l"]=(a0,a1,a2)=>(_log2l=Module["_log2l"]=wasmExports["log2l"])(a0,a1,a2);var _logb=Module["_logb"]=a0=>(_logb=Module["_logb"]=wasmExports["logb"])(a0);var _logbf=Module["_logbf"]=a0=>(_logbf=Module["_logbf"]=wasmExports["logbf"])(a0);var _logbl=Module["_logbl"]=(a0,a1,a2)=>(_logbl=Module["_logbl"]=wasmExports["logbl"])(a0,a1,a2);var _strtoull=Module["_strtoull"]=(a0,a1,a2)=>(_strtoull=Module["_strtoull"]=wasmExports["strtoull"])(a0,a1,a2);var _nrand48=Module["_nrand48"]=a0=>(_nrand48=Module["_nrand48"]=wasmExports["nrand48"])(a0);var _lrand48=Module["_lrand48"]=()=>(_lrand48=Module["_lrand48"]=wasmExports["lrand48"])();var _lrint=Module["_lrint"]=a0=>(_lrint=Module["_lrint"]=wasmExports["lrint"])(a0);var _lrintf=Module["_lrintf"]=a0=>(_lrintf=Module["_lrintf"]=wasmExports["lrintf"])(a0);var _lrintl=Module["_lrintl"]=(a0,a1)=>(_lrintl=Module["_lrintl"]=wasmExports["lrintl"])(a0,a1);var _lround=Module["_lround"]=a0=>(_lround=Module["_lround"]=wasmExports["lround"])(a0);var _lroundf=Module["_lroundf"]=a0=>(_lroundf=Module["_lroundf"]=wasmExports["lroundf"])(a0);var _lroundl=Module["_lroundl"]=(a0,a1)=>(_lroundl=Module["_lroundl"]=wasmExports["lroundl"])(a0,a1);var _lsearch=Module["_lsearch"]=(a0,a1,a2,a3,a4)=>(_lsearch=Module["_lsearch"]=wasmExports["lsearch"])(a0,a1,a2,a3,a4);var _lfind=Module["_lfind"]=(a0,a1,a2,a3,a4)=>(_lfind=Module["_lfind"]=wasmExports["lfind"])(a0,a1,a2,a3,a4);var _mbrlen=Module["_mbrlen"]=(a0,a1,a2)=>(_mbrlen=Module["_mbrlen"]=wasmExports["mbrlen"])(a0,a1,a2);var _mbrtoc16=Module["_mbrtoc16"]=(a0,a1,a2,a3)=>(_mbrtoc16=Module["_mbrtoc16"]=wasmExports["mbrtoc16"])(a0,a1,a2,a3);var _mbrtoc32=Module["_mbrtoc32"]=(a0,a1,a2,a3)=>(_mbrtoc32=Module["_mbrtoc32"]=wasmExports["mbrtoc32"])(a0,a1,a2,a3);var _mbsinit=Module["_mbsinit"]=a0=>(_mbsinit=Module["_mbsinit"]=wasmExports["mbsinit"])(a0);var _mbsnrtowcs=Module["_mbsnrtowcs"]=(a0,a1,a2,a3,a4)=>(_mbsnrtowcs=Module["_mbsnrtowcs"]=wasmExports["mbsnrtowcs"])(a0,a1,a2,a3,a4);var _mbsrtowcs=Module["_mbsrtowcs"]=(a0,a1,a2,a3)=>(_mbsrtowcs=Module["_mbsrtowcs"]=wasmExports["mbsrtowcs"])(a0,a1,a2,a3);var _memccpy=Module["_memccpy"]=(a0,a1,a2,a3)=>(_memccpy=Module["_memccpy"]=wasmExports["memccpy"])(a0,a1,a2,a3);var _memmem=Module["_memmem"]=(a0,a1,a2,a3)=>(_memmem=Module["_memmem"]=wasmExports["memmem"])(a0,a1,a2,a3);var _mempcpy=Module["_mempcpy"]=(a0,a1,a2)=>(_mempcpy=Module["_mempcpy"]=wasmExports["mempcpy"])(a0,a1,a2);var _mincore=Module["_mincore"]=(a0,a1,a2)=>(_mincore=Module["_mincore"]=wasmExports["mincore"])(a0,a1,a2);var _mkdtemp=Module["_mkdtemp"]=a0=>(_mkdtemp=Module["_mkdtemp"]=wasmExports["mkdtemp"])(a0);var _mkfifo=Module["_mkfifo"]=(a0,a1)=>(_mkfifo=Module["_mkfifo"]=wasmExports["mkfifo"])(a0,a1);var _mkfifoat=Module["_mkfifoat"]=(a0,a1,a2)=>(_mkfifoat=Module["_mkfifoat"]=wasmExports["mkfifoat"])(a0,a1,a2);var _mkostemp=Module["_mkostemp"]=(a0,a1)=>(_mkostemp=Module["_mkostemp"]=wasmExports["mkostemp"])(a0,a1);var _mkostemps=Module["_mkostemps"]=(a0,a1,a2)=>(_mkostemps=Module["_mkostemps"]=wasmExports["mkostemps"])(a0,a1,a2);var _mkstemp=Module["_mkstemp"]=a0=>(_mkstemp=Module["_mkstemp"]=wasmExports["mkstemp"])(a0);var _mkstemps=Module["_mkstemps"]=(a0,a1)=>(_mkstemps=Module["_mkstemps"]=wasmExports["mkstemps"])(a0,a1);var _mktemp=Module["_mktemp"]=a0=>(_mktemp=Module["_mktemp"]=wasmExports["mktemp"])(a0);var _timegm=Module["_timegm"]=a0=>(_timegm=Module["_timegm"]=wasmExports["timegm"])(a0);var _tzset=Module["_tzset"]=()=>(_tzset=Module["_tzset"]=wasmExports["tzset"])();var _mlock=Module["_mlock"]=(a0,a1)=>(_mlock=Module["_mlock"]=wasmExports["mlock"])(a0,a1);var _mlockall=Module["_mlockall"]=a0=>(_mlockall=Module["_mlockall"]=wasmExports["mlockall"])(a0);var _emscripten_builtin_mmap=Module["_emscripten_builtin_mmap"]=(a0,a1,a2,a3,a4,a5)=>(_emscripten_builtin_mmap=Module["_emscripten_builtin_mmap"]=wasmExports["emscripten_builtin_mmap"])(a0,a1,a2,a3,a4,a5);var _setmntent=Module["_setmntent"]=(a0,a1)=>(_setmntent=Module["_setmntent"]=wasmExports["setmntent"])(a0,a1);var _endmntent=Module["_endmntent"]=a0=>(_endmntent=Module["_endmntent"]=wasmExports["endmntent"])(a0);var _getmntent_r=Module["_getmntent_r"]=(a0,a1,a2,a3)=>(_getmntent_r=Module["_getmntent_r"]=wasmExports["getmntent_r"])(a0,a1,a2,a3);var _sscanf=Module["_sscanf"]=(a0,a1,a2)=>(_sscanf=Module["_sscanf"]=wasmExports["sscanf"])(a0,a1,a2);var _getmntent=Module["_getmntent"]=a0=>(_getmntent=Module["_getmntent"]=wasmExports["getmntent"])(a0);var _addmntent=Module["_addmntent"]=(a0,a1)=>(_addmntent=Module["_addmntent"]=wasmExports["addmntent"])(a0,a1);var _hasmntopt=Module["_hasmntopt"]=(a0,a1)=>(_hasmntopt=Module["_hasmntopt"]=wasmExports["hasmntopt"])(a0,a1);var _mprotect=Module["_mprotect"]=(a0,a1,a2)=>(_mprotect=Module["_mprotect"]=wasmExports["mprotect"])(a0,a1,a2);var _jrand48=Module["_jrand48"]=a0=>(_jrand48=Module["_jrand48"]=wasmExports["jrand48"])(a0);var _mrand48=Module["_mrand48"]=()=>(_mrand48=Module["_mrand48"]=wasmExports["mrand48"])();var _mtx_destroy=Module["_mtx_destroy"]=a0=>(_mtx_destroy=Module["_mtx_destroy"]=wasmExports["mtx_destroy"])(a0);var _mtx_init=Module["_mtx_init"]=(a0,a1)=>(_mtx_init=Module["_mtx_init"]=wasmExports["mtx_init"])(a0,a1);var _mtx_lock=Module["_mtx_lock"]=a0=>(_mtx_lock=Module["_mtx_lock"]=wasmExports["mtx_lock"])(a0);var _mtx_timedlock=Module["_mtx_timedlock"]=(a0,a1)=>(_mtx_timedlock=Module["_mtx_timedlock"]=wasmExports["mtx_timedlock"])(a0,a1);var _mtx_trylock=Module["_mtx_trylock"]=a0=>(_mtx_trylock=Module["_mtx_trylock"]=wasmExports["mtx_trylock"])(a0);var _mtx_unlock=Module["_mtx_unlock"]=a0=>(_mtx_unlock=Module["_mtx_unlock"]=wasmExports["mtx_unlock"])(a0);var _munlock=Module["_munlock"]=(a0,a1)=>(_munlock=Module["_munlock"]=wasmExports["munlock"])(a0,a1);var _munlockall=Module["_munlockall"]=()=>(_munlockall=Module["_munlockall"]=wasmExports["munlockall"])();var _emscripten_builtin_munmap=Module["_emscripten_builtin_munmap"]=(a0,a1)=>(_emscripten_builtin_munmap=Module["_emscripten_builtin_munmap"]=wasmExports["emscripten_builtin_munmap"])(a0,a1);var _nan=Module["_nan"]=a0=>(_nan=Module["_nan"]=wasmExports["nan"])(a0);var _nanf=Module["_nanf"]=a0=>(_nanf=Module["_nanf"]=wasmExports["nanf"])(a0);var _nanl=Module["_nanl"]=(a0,a1)=>(_nanl=Module["_nanl"]=wasmExports["nanl"])(a0,a1);var _nanosleep=Module["_nanosleep"]=(a0,a1)=>(_nanosleep=Module["_nanosleep"]=wasmExports["nanosleep"])(a0,a1);var _nearbyint=Module["_nearbyint"]=a0=>(_nearbyint=Module["_nearbyint"]=wasmExports["nearbyint"])(a0);var _nearbyintf=Module["_nearbyintf"]=a0=>(_nearbyintf=Module["_nearbyintf"]=wasmExports["nearbyintf"])(a0);var _nearbyintl=Module["_nearbyintl"]=(a0,a1,a2)=>(_nearbyintl=Module["_nearbyintl"]=wasmExports["nearbyintl"])(a0,a1,a2);var _getnetbyaddr=Module["_getnetbyaddr"]=(a0,a1)=>(_getnetbyaddr=Module["_getnetbyaddr"]=wasmExports["getnetbyaddr"])(a0,a1);var _getnetbyname=Module["_getnetbyname"]=a0=>(_getnetbyname=Module["_getnetbyname"]=wasmExports["getnetbyname"])(a0);var ___newlocale=Module["___newlocale"]=(a0,a1,a2)=>(___newlocale=Module["___newlocale"]=wasmExports["__newlocale"])(a0,a1,a2);var _newlocale=Module["_newlocale"]=(a0,a1,a2)=>(_newlocale=Module["_newlocale"]=wasmExports["newlocale"])(a0,a1,a2);var _nextafterf=Module["_nextafterf"]=(a0,a1)=>(_nextafterf=Module["_nextafterf"]=wasmExports["nextafterf"])(a0,a1);var _nexttoward=Module["_nexttoward"]=(a0,a1,a2)=>(_nexttoward=Module["_nexttoward"]=wasmExports["nexttoward"])(a0,a1,a2);var _nexttowardf=Module["_nexttowardf"]=(a0,a1,a2)=>(_nexttowardf=Module["_nexttowardf"]=wasmExports["nexttowardf"])(a0,a1,a2);var _nexttowardl=Module["_nexttowardl"]=(a0,a1,a2,a3,a4)=>(_nexttowardl=Module["_nexttowardl"]=wasmExports["nexttowardl"])(a0,a1,a2,a3,a4);var _nftw=Module["_nftw"]=(a0,a1,a2,a3)=>(_nftw=Module["_nftw"]=wasmExports["nftw"])(a0,a1,a2,a3);var _nice=Module["_nice"]=a0=>(_nice=Module["_nice"]=wasmExports["nice"])(a0);var _setpriority=Module["_setpriority"]=(a0,a1,a2)=>(_setpriority=Module["_setpriority"]=wasmExports["setpriority"])(a0,a1,a2);var _ns_get16=Module["_ns_get16"]=a0=>(_ns_get16=Module["_ns_get16"]=wasmExports["ns_get16"])(a0);var _ns_get32=Module["_ns_get32"]=a0=>(_ns_get32=Module["_ns_get32"]=wasmExports["ns_get32"])(a0);var _ns_put16=Module["_ns_put16"]=(a0,a1)=>(_ns_put16=Module["_ns_put16"]=wasmExports["ns_put16"])(a0,a1);var _ns_put32=Module["_ns_put32"]=(a0,a1)=>(_ns_put32=Module["_ns_put32"]=wasmExports["ns_put32"])(a0,a1);var _ns_skiprr=Module["_ns_skiprr"]=(a0,a1,a2,a3)=>(_ns_skiprr=Module["_ns_skiprr"]=wasmExports["ns_skiprr"])(a0,a1,a2,a3);var _ns_initparse=Module["_ns_initparse"]=(a0,a1,a2)=>(_ns_initparse=Module["_ns_initparse"]=wasmExports["ns_initparse"])(a0,a1,a2);var _ns_name_uncompress=Module["_ns_name_uncompress"]=(a0,a1,a2,a3,a4)=>(_ns_name_uncompress=Module["_ns_name_uncompress"]=wasmExports["ns_name_uncompress"])(a0,a1,a2,a3,a4);var _ns_parserr=Module["_ns_parserr"]=(a0,a1,a2,a3)=>(_ns_parserr=Module["_ns_parserr"]=wasmExports["ns_parserr"])(a0,a1,a2,a3);var _open_memstream=Module["_open_memstream"]=(a0,a1)=>(_open_memstream=Module["_open_memstream"]=wasmExports["open_memstream"])(a0,a1);var _open_wmemstream=Module["_open_wmemstream"]=(a0,a1)=>(_open_wmemstream=Module["_open_wmemstream"]=wasmExports["open_wmemstream"])(a0,a1);var _tcsetattr=Module["_tcsetattr"]=(a0,a1,a2)=>(_tcsetattr=Module["_tcsetattr"]=wasmExports["tcsetattr"])(a0,a1,a2);var _posix_close=Module["_posix_close"]=(a0,a1)=>(_posix_close=Module["_posix_close"]=wasmExports["posix_close"])(a0,a1);var _posix_fallocate=Module["_posix_fallocate"]=(a0,a1,a2)=>(_posix_fallocate=Module["_posix_fallocate"]=wasmExports["posix_fallocate"])(a0,a1,a2);var _posix_madvise=Module["_posix_madvise"]=(a0,a1,a2)=>(_posix_madvise=Module["_posix_madvise"]=wasmExports["posix_madvise"])(a0,a1,a2);var _posix_spawn_file_actions_addchdir_np=Module["_posix_spawn_file_actions_addchdir_np"]=(a0,a1)=>(_posix_spawn_file_actions_addchdir_np=Module["_posix_spawn_file_actions_addchdir_np"]=wasmExports["posix_spawn_file_actions_addchdir_np"])(a0,a1);var _posix_spawn_file_actions_addclose=Module["_posix_spawn_file_actions_addclose"]=(a0,a1)=>(_posix_spawn_file_actions_addclose=Module["_posix_spawn_file_actions_addclose"]=wasmExports["posix_spawn_file_actions_addclose"])(a0,a1);var _posix_spawn_file_actions_adddup2=Module["_posix_spawn_file_actions_adddup2"]=(a0,a1,a2)=>(_posix_spawn_file_actions_adddup2=Module["_posix_spawn_file_actions_adddup2"]=wasmExports["posix_spawn_file_actions_adddup2"])(a0,a1,a2);var _posix_spawn_file_actions_addfchdir_np=Module["_posix_spawn_file_actions_addfchdir_np"]=(a0,a1)=>(_posix_spawn_file_actions_addfchdir_np=Module["_posix_spawn_file_actions_addfchdir_np"]=wasmExports["posix_spawn_file_actions_addfchdir_np"])(a0,a1);var _posix_spawn_file_actions_addopen=Module["_posix_spawn_file_actions_addopen"]=(a0,a1,a2,a3,a4)=>(_posix_spawn_file_actions_addopen=Module["_posix_spawn_file_actions_addopen"]=wasmExports["posix_spawn_file_actions_addopen"])(a0,a1,a2,a3,a4);var _posix_spawn_file_actions_destroy=Module["_posix_spawn_file_actions_destroy"]=a0=>(_posix_spawn_file_actions_destroy=Module["_posix_spawn_file_actions_destroy"]=wasmExports["posix_spawn_file_actions_destroy"])(a0);var _posix_spawn_file_actions_init=Module["_posix_spawn_file_actions_init"]=a0=>(_posix_spawn_file_actions_init=Module["_posix_spawn_file_actions_init"]=wasmExports["posix_spawn_file_actions_init"])(a0);var _posix_spawnattr_destroy=Module["_posix_spawnattr_destroy"]=a0=>(_posix_spawnattr_destroy=Module["_posix_spawnattr_destroy"]=wasmExports["posix_spawnattr_destroy"])(a0);var _posix_spawnattr_getflags=Module["_posix_spawnattr_getflags"]=(a0,a1)=>(_posix_spawnattr_getflags=Module["_posix_spawnattr_getflags"]=wasmExports["posix_spawnattr_getflags"])(a0,a1);var _posix_spawnattr_getpgroup=Module["_posix_spawnattr_getpgroup"]=(a0,a1)=>(_posix_spawnattr_getpgroup=Module["_posix_spawnattr_getpgroup"]=wasmExports["posix_spawnattr_getpgroup"])(a0,a1);var _posix_spawnattr_getsigdefault=Module["_posix_spawnattr_getsigdefault"]=(a0,a1)=>(_posix_spawnattr_getsigdefault=Module["_posix_spawnattr_getsigdefault"]=wasmExports["posix_spawnattr_getsigdefault"])(a0,a1);var _posix_spawnattr_getsigmask=Module["_posix_spawnattr_getsigmask"]=(a0,a1)=>(_posix_spawnattr_getsigmask=Module["_posix_spawnattr_getsigmask"]=wasmExports["posix_spawnattr_getsigmask"])(a0,a1);var _posix_spawnattr_init=Module["_posix_spawnattr_init"]=a0=>(_posix_spawnattr_init=Module["_posix_spawnattr_init"]=wasmExports["posix_spawnattr_init"])(a0);var _posix_spawnattr_getschedparam=Module["_posix_spawnattr_getschedparam"]=(a0,a1)=>(_posix_spawnattr_getschedparam=Module["_posix_spawnattr_getschedparam"]=wasmExports["posix_spawnattr_getschedparam"])(a0,a1);var _posix_spawnattr_setschedparam=Module["_posix_spawnattr_setschedparam"]=(a0,a1)=>(_posix_spawnattr_setschedparam=Module["_posix_spawnattr_setschedparam"]=wasmExports["posix_spawnattr_setschedparam"])(a0,a1);var _posix_spawnattr_getschedpolicy=Module["_posix_spawnattr_getschedpolicy"]=(a0,a1)=>(_posix_spawnattr_getschedpolicy=Module["_posix_spawnattr_getschedpolicy"]=wasmExports["posix_spawnattr_getschedpolicy"])(a0,a1);var _posix_spawnattr_setschedpolicy=Module["_posix_spawnattr_setschedpolicy"]=(a0,a1)=>(_posix_spawnattr_setschedpolicy=Module["_posix_spawnattr_setschedpolicy"]=wasmExports["posix_spawnattr_setschedpolicy"])(a0,a1);var _posix_spawnattr_setflags=Module["_posix_spawnattr_setflags"]=(a0,a1)=>(_posix_spawnattr_setflags=Module["_posix_spawnattr_setflags"]=wasmExports["posix_spawnattr_setflags"])(a0,a1);var _posix_spawnattr_setpgroup=Module["_posix_spawnattr_setpgroup"]=(a0,a1)=>(_posix_spawnattr_setpgroup=Module["_posix_spawnattr_setpgroup"]=wasmExports["posix_spawnattr_setpgroup"])(a0,a1);var _posix_spawnattr_setsigdefault=Module["_posix_spawnattr_setsigdefault"]=(a0,a1)=>(_posix_spawnattr_setsigdefault=Module["_posix_spawnattr_setsigdefault"]=wasmExports["posix_spawnattr_setsigdefault"])(a0,a1);var _posix_spawnattr_setsigmask=Module["_posix_spawnattr_setsigmask"]=(a0,a1)=>(_posix_spawnattr_setsigmask=Module["_posix_spawnattr_setsigmask"]=wasmExports["posix_spawnattr_setsigmask"])(a0,a1);var _powf=Module["_powf"]=(a0,a1)=>(_powf=Module["_powf"]=wasmExports["powf"])(a0,a1);var _preadv=Module["_preadv"]=(a0,a1,a2,a3)=>(_preadv=Module["_preadv"]=wasmExports["preadv"])(a0,a1,a2,a3);var _printf=Module["_printf"]=(a0,a1)=>(_printf=Module["_printf"]=wasmExports["printf"])(a0,a1);var ___small_printf=Module["___small_printf"]=(a0,a1)=>(___small_printf=Module["___small_printf"]=wasmExports["__small_printf"])(a0,a1);var _em_proxying_queue_create=Module["_em_proxying_queue_create"]=()=>(_em_proxying_queue_create=Module["_em_proxying_queue_create"]=wasmExports["em_proxying_queue_create"])();var _em_proxying_queue_destroy=Module["_em_proxying_queue_destroy"]=a0=>(_em_proxying_queue_destroy=Module["_em_proxying_queue_destroy"]=wasmExports["em_proxying_queue_destroy"])(a0);var _emscripten_proxy_get_system_queue=Module["_emscripten_proxy_get_system_queue"]=()=>(_emscripten_proxy_get_system_queue=Module["_emscripten_proxy_get_system_queue"]=wasmExports["emscripten_proxy_get_system_queue"])();var _emscripten_proxy_execute_queue=Module["_emscripten_proxy_execute_queue"]=a0=>(_emscripten_proxy_execute_queue=Module["_emscripten_proxy_execute_queue"]=wasmExports["emscripten_proxy_execute_queue"])(a0);var _emscripten_proxy_finish=Module["_emscripten_proxy_finish"]=a0=>(_emscripten_proxy_finish=Module["_emscripten_proxy_finish"]=wasmExports["emscripten_proxy_finish"])(a0);var _emscripten_proxy_async=Module["_emscripten_proxy_async"]=(a0,a1,a2,a3)=>(_emscripten_proxy_async=Module["_emscripten_proxy_async"]=wasmExports["emscripten_proxy_async"])(a0,a1,a2,a3);var _emscripten_proxy_sync=Module["_emscripten_proxy_sync"]=(a0,a1,a2,a3)=>(_emscripten_proxy_sync=Module["_emscripten_proxy_sync"]=wasmExports["emscripten_proxy_sync"])(a0,a1,a2,a3);var _emscripten_proxy_sync_with_ctx=Module["_emscripten_proxy_sync_with_ctx"]=(a0,a1,a2,a3)=>(_emscripten_proxy_sync_with_ctx=Module["_emscripten_proxy_sync_with_ctx"]=wasmExports["emscripten_proxy_sync_with_ctx"])(a0,a1,a2,a3);var _pselect=Module["_pselect"]=(a0,a1,a2,a3,a4,a5)=>(_pselect=Module["_pselect"]=wasmExports["pselect"])(a0,a1,a2,a3,a4,a5);var _pthread_attr_getdetachstate=Module["_pthread_attr_getdetachstate"]=(a0,a1)=>(_pthread_attr_getdetachstate=Module["_pthread_attr_getdetachstate"]=wasmExports["pthread_attr_getdetachstate"])(a0,a1);var _pthread_attr_getguardsize=Module["_pthread_attr_getguardsize"]=(a0,a1)=>(_pthread_attr_getguardsize=Module["_pthread_attr_getguardsize"]=wasmExports["pthread_attr_getguardsize"])(a0,a1);var _pthread_attr_getinheritsched=Module["_pthread_attr_getinheritsched"]=(a0,a1)=>(_pthread_attr_getinheritsched=Module["_pthread_attr_getinheritsched"]=wasmExports["pthread_attr_getinheritsched"])(a0,a1);var _pthread_attr_getschedparam=Module["_pthread_attr_getschedparam"]=(a0,a1)=>(_pthread_attr_getschedparam=Module["_pthread_attr_getschedparam"]=wasmExports["pthread_attr_getschedparam"])(a0,a1);var _pthread_attr_getschedpolicy=Module["_pthread_attr_getschedpolicy"]=(a0,a1)=>(_pthread_attr_getschedpolicy=Module["_pthread_attr_getschedpolicy"]=wasmExports["pthread_attr_getschedpolicy"])(a0,a1);var _pthread_attr_getscope=Module["_pthread_attr_getscope"]=(a0,a1)=>(_pthread_attr_getscope=Module["_pthread_attr_getscope"]=wasmExports["pthread_attr_getscope"])(a0,a1);var _pthread_attr_getstack=Module["_pthread_attr_getstack"]=(a0,a1,a2)=>(_pthread_attr_getstack=Module["_pthread_attr_getstack"]=wasmExports["pthread_attr_getstack"])(a0,a1,a2);var _pthread_attr_getstacksize=Module["_pthread_attr_getstacksize"]=(a0,a1)=>(_pthread_attr_getstacksize=Module["_pthread_attr_getstacksize"]=wasmExports["pthread_attr_getstacksize"])(a0,a1);var _pthread_barrierattr_getpshared=Module["_pthread_barrierattr_getpshared"]=(a0,a1)=>(_pthread_barrierattr_getpshared=Module["_pthread_barrierattr_getpshared"]=wasmExports["pthread_barrierattr_getpshared"])(a0,a1);var _pthread_condattr_getclock=Module["_pthread_condattr_getclock"]=(a0,a1)=>(_pthread_condattr_getclock=Module["_pthread_condattr_getclock"]=wasmExports["pthread_condattr_getclock"])(a0,a1);var _pthread_condattr_getpshared=Module["_pthread_condattr_getpshared"]=(a0,a1)=>(_pthread_condattr_getpshared=Module["_pthread_condattr_getpshared"]=wasmExports["pthread_condattr_getpshared"])(a0,a1);var _pthread_mutexattr_getprotocol=Module["_pthread_mutexattr_getprotocol"]=(a0,a1)=>(_pthread_mutexattr_getprotocol=Module["_pthread_mutexattr_getprotocol"]=wasmExports["pthread_mutexattr_getprotocol"])(a0,a1);var _pthread_mutexattr_getpshared=Module["_pthread_mutexattr_getpshared"]=(a0,a1)=>(_pthread_mutexattr_getpshared=Module["_pthread_mutexattr_getpshared"]=wasmExports["pthread_mutexattr_getpshared"])(a0,a1);var _pthread_mutexattr_getrobust=Module["_pthread_mutexattr_getrobust"]=(a0,a1)=>(_pthread_mutexattr_getrobust=Module["_pthread_mutexattr_getrobust"]=wasmExports["pthread_mutexattr_getrobust"])(a0,a1);var _pthread_mutexattr_gettype=Module["_pthread_mutexattr_gettype"]=(a0,a1)=>(_pthread_mutexattr_gettype=Module["_pthread_mutexattr_gettype"]=wasmExports["pthread_mutexattr_gettype"])(a0,a1);var _pthread_rwlockattr_getpshared=Module["_pthread_rwlockattr_getpshared"]=(a0,a1)=>(_pthread_rwlockattr_getpshared=Module["_pthread_rwlockattr_getpshared"]=wasmExports["pthread_rwlockattr_getpshared"])(a0,a1);var _pthread_attr_setdetachstate=Module["_pthread_attr_setdetachstate"]=(a0,a1)=>(_pthread_attr_setdetachstate=Module["_pthread_attr_setdetachstate"]=wasmExports["pthread_attr_setdetachstate"])(a0,a1);var _pthread_attr_setguardsize=Module["_pthread_attr_setguardsize"]=(a0,a1)=>(_pthread_attr_setguardsize=Module["_pthread_attr_setguardsize"]=wasmExports["pthread_attr_setguardsize"])(a0,a1);var _pthread_attr_setinheritsched=Module["_pthread_attr_setinheritsched"]=(a0,a1)=>(_pthread_attr_setinheritsched=Module["_pthread_attr_setinheritsched"]=wasmExports["pthread_attr_setinheritsched"])(a0,a1);var _pthread_attr_setschedparam=Module["_pthread_attr_setschedparam"]=(a0,a1)=>(_pthread_attr_setschedparam=Module["_pthread_attr_setschedparam"]=wasmExports["pthread_attr_setschedparam"])(a0,a1);var _pthread_attr_setschedpolicy=Module["_pthread_attr_setschedpolicy"]=(a0,a1)=>(_pthread_attr_setschedpolicy=Module["_pthread_attr_setschedpolicy"]=wasmExports["pthread_attr_setschedpolicy"])(a0,a1);var _pthread_attr_setscope=Module["_pthread_attr_setscope"]=(a0,a1)=>(_pthread_attr_setscope=Module["_pthread_attr_setscope"]=wasmExports["pthread_attr_setscope"])(a0,a1);var _pthread_attr_setstack=Module["_pthread_attr_setstack"]=(a0,a1,a2)=>(_pthread_attr_setstack=Module["_pthread_attr_setstack"]=wasmExports["pthread_attr_setstack"])(a0,a1,a2);var __pthread_cleanup_push=Module["__pthread_cleanup_push"]=(a0,a1,a2)=>(__pthread_cleanup_push=Module["__pthread_cleanup_push"]=wasmExports["_pthread_cleanup_push"])(a0,a1,a2);var __pthread_cleanup_pop=Module["__pthread_cleanup_pop"]=(a0,a1)=>(__pthread_cleanup_pop=Module["__pthread_cleanup_pop"]=wasmExports["_pthread_cleanup_pop"])(a0,a1);var _pthread_getconcurrency=Module["_pthread_getconcurrency"]=()=>(_pthread_getconcurrency=Module["_pthread_getconcurrency"]=wasmExports["pthread_getconcurrency"])();var _pthread_getschedparam=Module["_pthread_getschedparam"]=(a0,a1,a2)=>(_pthread_getschedparam=Module["_pthread_getschedparam"]=wasmExports["pthread_getschedparam"])(a0,a1,a2);var _thrd_current=Module["_thrd_current"]=()=>(_thrd_current=Module["_thrd_current"]=wasmExports["thrd_current"])();var _emscripten_main_runtime_thread_id=Module["_emscripten_main_runtime_thread_id"]=()=>(_emscripten_main_runtime_thread_id=Module["_emscripten_main_runtime_thread_id"]=wasmExports["emscripten_main_runtime_thread_id"])();var _pthread_setconcurrency=Module["_pthread_setconcurrency"]=a0=>(_pthread_setconcurrency=Module["_pthread_setconcurrency"]=wasmExports["pthread_setconcurrency"])(a0);var _pthread_setschedprio=Module["_pthread_setschedprio"]=(a0,a1)=>(_pthread_setschedprio=Module["_pthread_setschedprio"]=wasmExports["pthread_setschedprio"])(a0,a1);var ___sig_is_blocked=Module["___sig_is_blocked"]=a0=>(___sig_is_blocked=Module["___sig_is_blocked"]=wasmExports["__sig_is_blocked"])(a0);var _sigorset=Module["_sigorset"]=(a0,a1,a2)=>(_sigorset=Module["_sigorset"]=wasmExports["sigorset"])(a0,a1,a2);var _sigandset=Module["_sigandset"]=(a0,a1,a2)=>(_sigandset=Module["_sigandset"]=wasmExports["sigandset"])(a0,a1,a2);var _sigdelset=Module["_sigdelset"]=(a0,a1)=>(_sigdelset=Module["_sigdelset"]=wasmExports["sigdelset"])(a0,a1);var _ptsname=Module["_ptsname"]=a0=>(_ptsname=Module["_ptsname"]=wasmExports["ptsname"])(a0);var _posix_openpt=Module["_posix_openpt"]=a0=>(_posix_openpt=Module["_posix_openpt"]=wasmExports["posix_openpt"])(a0);var _grantpt=Module["_grantpt"]=a0=>(_grantpt=Module["_grantpt"]=wasmExports["grantpt"])(a0);var _unlockpt=Module["_unlockpt"]=a0=>(_unlockpt=Module["_unlockpt"]=wasmExports["unlockpt"])(a0);var _ptsname_r=Module["_ptsname_r"]=(a0,a1,a2)=>(_ptsname_r=Module["_ptsname_r"]=wasmExports["ptsname_r"])(a0,a1,a2);var __IO_putc=Module["__IO_putc"]=(a0,a1)=>(__IO_putc=Module["__IO_putc"]=wasmExports["_IO_putc"])(a0,a1);var _putc_unlocked=Module["_putc_unlocked"]=(a0,a1)=>(_putc_unlocked=Module["_putc_unlocked"]=wasmExports["putc_unlocked"])(a0,a1);var _fputc_unlocked=Module["_fputc_unlocked"]=(a0,a1)=>(_fputc_unlocked=Module["_fputc_unlocked"]=wasmExports["fputc_unlocked"])(a0,a1);var __IO_putc_unlocked=Module["__IO_putc_unlocked"]=(a0,a1)=>(__IO_putc_unlocked=Module["__IO_putc_unlocked"]=wasmExports["_IO_putc_unlocked"])(a0,a1);var _putchar_unlocked=Module["_putchar_unlocked"]=a0=>(_putchar_unlocked=Module["_putchar_unlocked"]=wasmExports["putchar_unlocked"])(a0);var _putenv=Module["_putenv"]=a0=>(_putenv=Module["_putenv"]=wasmExports["putenv"])(a0);var _putw=Module["_putw"]=(a0,a1)=>(_putw=Module["_putw"]=wasmExports["putw"])(a0,a1);var _putwc=Module["_putwc"]=(a0,a1)=>(_putwc=Module["_putwc"]=wasmExports["putwc"])(a0,a1);var _putwchar=Module["_putwchar"]=a0=>(_putwchar=Module["_putwchar"]=wasmExports["putwchar"])(a0);var _putwchar_unlocked=Module["_putwchar_unlocked"]=a0=>(_putwchar_unlocked=Module["_putwchar_unlocked"]=wasmExports["putwchar_unlocked"])(a0);var _pwritev=Module["_pwritev"]=(a0,a1,a2,a3)=>(_pwritev=Module["_pwritev"]=wasmExports["pwritev"])(a0,a1,a2,a3);var _qsort_r=Module["_qsort_r"]=(a0,a1,a2,a3,a4)=>(_qsort_r=Module["_qsort_r"]=wasmExports["qsort_r"])(a0,a1,a2,a3,a4);var _quick_exit=Module["_quick_exit"]=a0=>(_quick_exit=Module["_quick_exit"]=wasmExports["quick_exit"])(a0);var _action_abort=Module["_action_abort"]=a0=>(_action_abort=Module["_action_abort"]=wasmExports["action_abort"])(a0);var _action_terminate=Module["_action_terminate"]=a0=>(_action_terminate=Module["_action_terminate"]=wasmExports["action_terminate"])(a0);var _srand=Module["_srand"]=a0=>(_srand=Module["_srand"]=wasmExports["srand"])(a0);var _rand=Module["_rand"]=()=>(_rand=Module["_rand"]=wasmExports["rand"])();var _rand_r=Module["_rand_r"]=a0=>(_rand_r=Module["_rand_r"]=wasmExports["rand_r"])(a0);var _srandom=Module["_srandom"]=a0=>(_srandom=Module["_srandom"]=wasmExports["srandom"])(a0);var _initstate=Module["_initstate"]=(a0,a1,a2)=>(_initstate=Module["_initstate"]=wasmExports["initstate"])(a0,a1,a2);var _setstate=Module["_setstate"]=a0=>(_setstate=Module["_setstate"]=wasmExports["setstate"])(a0);var _random=Module["_random"]=()=>(_random=Module["_random"]=wasmExports["random"])();var _readdir_r=Module["_readdir_r"]=(a0,a1,a2)=>(_readdir_r=Module["_readdir_r"]=wasmExports["readdir_r"])(a0,a1,a2);var _recvmmsg=Module["_recvmmsg"]=(a0,a1,a2,a3,a4)=>(_recvmmsg=Module["_recvmmsg"]=wasmExports["recvmmsg"])(a0,a1,a2,a3,a4);var _regcomp=Module["_regcomp"]=(a0,a1,a2)=>(_regcomp=Module["_regcomp"]=wasmExports["regcomp"])(a0,a1,a2);var _regfree=Module["_regfree"]=a0=>(_regfree=Module["_regfree"]=wasmExports["regfree"])(a0);var _regerror=Module["_regerror"]=(a0,a1,a2,a3)=>(_regerror=Module["_regerror"]=wasmExports["regerror"])(a0,a1,a2,a3);var _regexec=Module["_regexec"]=(a0,a1,a2,a3,a4)=>(_regexec=Module["_regexec"]=wasmExports["regexec"])(a0,a1,a2,a3,a4);var _remainder=Module["_remainder"]=(a0,a1)=>(_remainder=Module["_remainder"]=wasmExports["remainder"])(a0,a1);var _remquo=Module["_remquo"]=(a0,a1,a2)=>(_remquo=Module["_remquo"]=wasmExports["remquo"])(a0,a1,a2);var _drem=Module["_drem"]=(a0,a1)=>(_drem=Module["_drem"]=wasmExports["drem"])(a0,a1);var _remainderf=Module["_remainderf"]=(a0,a1)=>(_remainderf=Module["_remainderf"]=wasmExports["remainderf"])(a0,a1);var _remquof=Module["_remquof"]=(a0,a1,a2)=>(_remquof=Module["_remquof"]=wasmExports["remquof"])(a0,a1,a2);var _dremf=Module["_dremf"]=(a0,a1)=>(_dremf=Module["_dremf"]=wasmExports["dremf"])(a0,a1);var _remainderl=Module["_remainderl"]=(a0,a1,a2,a3,a4)=>(_remainderl=Module["_remainderl"]=wasmExports["remainderl"])(a0,a1,a2,a3,a4);var _remquol=Module["_remquol"]=(a0,a1,a2,a3,a4,a5)=>(_remquol=Module["_remquol"]=wasmExports["remquol"])(a0,a1,a2,a3,a4,a5);var _remove=Module["_remove"]=a0=>(_remove=Module["_remove"]=wasmExports["remove"])(a0);var _res_init=Module["_res_init"]=()=>(_res_init=Module["_res_init"]=wasmExports["res_init"])();var _res_mkquery=Module["_res_mkquery"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(_res_mkquery=Module["_res_mkquery"]=wasmExports["res_mkquery"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var ___res_msend=Module["___res_msend"]=(a0,a1,a2,a3,a4,a5)=>(___res_msend=Module["___res_msend"]=wasmExports["__res_msend"])(a0,a1,a2,a3,a4,a5);var _res_send=Module["_res_send"]=(a0,a1,a2,a3)=>(_res_send=Module["_res_send"]=wasmExports["res_send"])(a0,a1,a2,a3);var ___res_state=Module["___res_state"]=()=>(___res_state=Module["___res_state"]=wasmExports["__res_state"])();var _rindex=Module["_rindex"]=(a0,a1)=>(_rindex=Module["_rindex"]=wasmExports["rindex"])(a0,a1);var _emscripten_get_sbrk_ptr=Module["_emscripten_get_sbrk_ptr"]=()=>(_emscripten_get_sbrk_ptr=Module["_emscripten_get_sbrk_ptr"]=wasmExports["emscripten_get_sbrk_ptr"])();var _sbrk=Module["_sbrk"]=a0=>(_sbrk=Module["_sbrk"]=wasmExports["sbrk"])(a0);var _brk=Module["_brk"]=a0=>(_brk=Module["_brk"]=wasmExports["brk"])(a0);var _scalb=Module["_scalb"]=(a0,a1)=>(_scalb=Module["_scalb"]=wasmExports["scalb"])(a0,a1);var _scalbf=Module["_scalbf"]=(a0,a1)=>(_scalbf=Module["_scalbf"]=wasmExports["scalbf"])(a0,a1);var _scalbln=Module["_scalbln"]=(a0,a1)=>(_scalbln=Module["_scalbln"]=wasmExports["scalbln"])(a0,a1);var _scalblnf=Module["_scalblnf"]=(a0,a1)=>(_scalblnf=Module["_scalblnf"]=wasmExports["scalblnf"])(a0,a1);var _scalblnl=Module["_scalblnl"]=(a0,a1,a2,a3)=>(_scalblnl=Module["_scalblnl"]=wasmExports["scalblnl"])(a0,a1,a2,a3);var _scandir=Module["_scandir"]=(a0,a1,a2,a3)=>(_scandir=Module["_scandir"]=wasmExports["scandir"])(a0,a1,a2,a3);var _scanf=Module["_scanf"]=(a0,a1)=>(_scanf=Module["_scanf"]=wasmExports["scanf"])(a0,a1);var _vscanf=Module["_vscanf"]=(a0,a1)=>(_vscanf=Module["_vscanf"]=wasmExports["vscanf"])(a0,a1);var ___isoc99_scanf=Module["___isoc99_scanf"]=(a0,a1)=>(___isoc99_scanf=Module["___isoc99_scanf"]=wasmExports["__isoc99_scanf"])(a0,a1);var _secure_getenv=Module["_secure_getenv"]=a0=>(_secure_getenv=Module["_secure_getenv"]=wasmExports["secure_getenv"])(a0);var _seed48=Module["_seed48"]=a0=>(_seed48=Module["_seed48"]=wasmExports["seed48"])(a0);var _seekdir=Module["_seekdir"]=(a0,a1)=>(_seekdir=Module["_seekdir"]=wasmExports["seekdir"])(a0,a1);var _sendmmsg=Module["_sendmmsg"]=(a0,a1,a2,a3)=>(_sendmmsg=Module["_sendmmsg"]=wasmExports["sendmmsg"])(a0,a1,a2,a3);var _endservent=Module["_endservent"]=()=>(_endservent=Module["_endservent"]=wasmExports["endservent"])();var _setservent=Module["_setservent"]=a0=>(_setservent=Module["_setservent"]=wasmExports["setservent"])(a0);var _getservent=Module["_getservent"]=()=>(_getservent=Module["_getservent"]=wasmExports["getservent"])();var _setbuf=Module["_setbuf"]=(a0,a1)=>(_setbuf=Module["_setbuf"]=wasmExports["setbuf"])(a0,a1);var _setbuffer=Module["_setbuffer"]=(a0,a1,a2)=>(_setbuffer=Module["_setbuffer"]=wasmExports["setbuffer"])(a0,a1,a2);var _setdomainname=Module["_setdomainname"]=(a0,a1)=>(_setdomainname=Module["_setdomainname"]=wasmExports["setdomainname"])(a0,a1);var _setegid=Module["_setegid"]=a0=>(_setegid=Module["_setegid"]=wasmExports["setegid"])(a0);var _seteuid=Module["_seteuid"]=a0=>(_seteuid=Module["_seteuid"]=wasmExports["seteuid"])(a0);var __emscripten_timeout=(a0,a1)=>(__emscripten_timeout=wasmExports["_emscripten_timeout"])(a0,a1);var _setlinebuf=Module["_setlinebuf"]=a0=>(_setlinebuf=Module["_setlinebuf"]=wasmExports["setlinebuf"])(a0);var _setresgid=Module["_setresgid"]=(a0,a1,a2)=>(_setresgid=Module["_setresgid"]=wasmExports["setresgid"])(a0,a1,a2);var _setresuid=Module["_setresuid"]=(a0,a1,a2)=>(_setresuid=Module["_setresuid"]=wasmExports["setresuid"])(a0,a1,a2);var _shm_open=Module["_shm_open"]=(a0,a1,a2)=>(_shm_open=Module["_shm_open"]=wasmExports["shm_open"])(a0,a1,a2);var _shm_unlink=Module["_shm_unlink"]=a0=>(_shm_unlink=Module["_shm_unlink"]=wasmExports["shm_unlink"])(a0);var _sigaction=Module["_sigaction"]=(a0,a1,a2)=>(_sigaction=Module["_sigaction"]=wasmExports["sigaction"])(a0,a1,a2);var _sigisemptyset=Module["_sigisemptyset"]=a0=>(_sigisemptyset=Module["_sigisemptyset"]=wasmExports["sigisemptyset"])(a0);var _bsd_signal=Module["_bsd_signal"]=(a0,a1)=>(_bsd_signal=Module["_bsd_signal"]=wasmExports["bsd_signal"])(a0,a1);var ___sysv_signal=Module["___sysv_signal"]=(a0,a1)=>(___sysv_signal=Module["___sysv_signal"]=wasmExports["__sysv_signal"])(a0,a1);var _significand=Module["_significand"]=a0=>(_significand=Module["_significand"]=wasmExports["significand"])(a0);var _significandf=Module["_significandf"]=a0=>(_significandf=Module["_significandf"]=wasmExports["significandf"])(a0);var _sigprocmask=Module["_sigprocmask"]=(a0,a1,a2)=>(_sigprocmask=Module["_sigprocmask"]=wasmExports["sigprocmask"])(a0,a1,a2);var _sincos=Module["_sincos"]=(a0,a1,a2)=>(_sincos=Module["_sincos"]=wasmExports["sincos"])(a0,a1,a2);var _sincosf=Module["_sincosf"]=(a0,a1,a2)=>(_sincosf=Module["_sincosf"]=wasmExports["sincosf"])(a0,a1,a2);var _sincosl=Module["_sincosl"]=(a0,a1,a2,a3)=>(_sincosl=Module["_sincosl"]=wasmExports["sincosl"])(a0,a1,a2,a3);var _sinhl=Module["_sinhl"]=(a0,a1,a2)=>(_sinhl=Module["_sinhl"]=wasmExports["sinhl"])(a0,a1,a2);var _sinl=Module["_sinl"]=(a0,a1,a2)=>(_sinl=Module["_sinl"]=wasmExports["sinl"])(a0,a1,a2);var _sleep=Module["_sleep"]=a0=>(_sleep=Module["_sleep"]=wasmExports["sleep"])(a0);var _sockatmark=Module["_sockatmark"]=a0=>(_sockatmark=Module["_sockatmark"]=wasmExports["sockatmark"])(a0);var _vsprintf=Module["_vsprintf"]=(a0,a1,a2)=>(_vsprintf=Module["_vsprintf"]=wasmExports["vsprintf"])(a0,a1,a2);var _vsiprintf=Module["_vsiprintf"]=(a0,a1,a2)=>(_vsiprintf=Module["_vsiprintf"]=wasmExports["vsiprintf"])(a0,a1,a2);var ___small_sprintf=Module["___small_sprintf"]=(a0,a1,a2)=>(___small_sprintf=Module["___small_sprintf"]=wasmExports["__small_sprintf"])(a0,a1,a2);var ___small_vsprintf=Module["___small_vsprintf"]=(a0,a1,a2)=>(___small_vsprintf=Module["___small_vsprintf"]=wasmExports["__small_vsprintf"])(a0,a1,a2);var _srand48=Module["_srand48"]=a0=>(_srand48=Module["_srand48"]=wasmExports["srand48"])(a0);var _vsscanf=Module["_vsscanf"]=(a0,a1,a2)=>(_vsscanf=Module["_vsscanf"]=wasmExports["vsscanf"])(a0,a1,a2);var ___isoc99_sscanf=Module["___isoc99_sscanf"]=(a0,a1,a2)=>(___isoc99_sscanf=Module["___isoc99_sscanf"]=wasmExports["__isoc99_sscanf"])(a0,a1,a2);var _statfs=Module["_statfs"]=(a0,a1)=>(_statfs=Module["_statfs"]=wasmExports["statfs"])(a0,a1);var _fstatfs=Module["_fstatfs"]=(a0,a1)=>(_fstatfs=Module["_fstatfs"]=wasmExports["fstatfs"])(a0,a1);var _statx=Module["_statx"]=(a0,a1,a2,a3,a4)=>(_statx=Module["_statx"]=wasmExports["statx"])(a0,a1,a2,a3,a4);var _stpcpy=Module["_stpcpy"]=(a0,a1)=>(_stpcpy=Module["_stpcpy"]=wasmExports["stpcpy"])(a0,a1);var _stpncpy=Module["_stpncpy"]=(a0,a1,a2)=>(_stpncpy=Module["_stpncpy"]=wasmExports["stpncpy"])(a0,a1,a2);var ___strcasecmp_l=Module["___strcasecmp_l"]=(a0,a1,a2)=>(___strcasecmp_l=Module["___strcasecmp_l"]=wasmExports["__strcasecmp_l"])(a0,a1,a2);var _strcasecmp_l=Module["_strcasecmp_l"]=(a0,a1,a2)=>(_strcasecmp_l=Module["_strcasecmp_l"]=wasmExports["strcasecmp_l"])(a0,a1,a2);var _strcasestr=Module["_strcasestr"]=(a0,a1)=>(_strcasestr=Module["_strcasestr"]=wasmExports["strcasestr"])(a0,a1);var _strncasecmp=Module["_strncasecmp"]=(a0,a1,a2)=>(_strncasecmp=Module["_strncasecmp"]=wasmExports["strncasecmp"])(a0,a1,a2);var _strchrnul=Module["_strchrnul"]=(a0,a1)=>(_strchrnul=Module["_strchrnul"]=wasmExports["strchrnul"])(a0,a1);var ___strcoll_l=Module["___strcoll_l"]=(a0,a1,a2)=>(___strcoll_l=Module["___strcoll_l"]=wasmExports["__strcoll_l"])(a0,a1,a2);var _strcoll_l=Module["_strcoll_l"]=(a0,a1,a2)=>(_strcoll_l=Module["_strcoll_l"]=wasmExports["strcoll_l"])(a0,a1,a2);var ___strerror_l=Module["___strerror_l"]=(a0,a1)=>(___strerror_l=Module["___strerror_l"]=wasmExports["__strerror_l"])(a0,a1);var _strerror_l=Module["_strerror_l"]=(a0,a1)=>(_strerror_l=Module["_strerror_l"]=wasmExports["strerror_l"])(a0,a1);var _strerror_r=Module["_strerror_r"]=(a0,a1,a2)=>(_strerror_r=Module["_strerror_r"]=wasmExports["strerror_r"])(a0,a1,a2);var ___xpg_strerror_r=Module["___xpg_strerror_r"]=(a0,a1,a2)=>(___xpg_strerror_r=Module["___xpg_strerror_r"]=wasmExports["__xpg_strerror_r"])(a0,a1,a2);var _strfmon_l=Module["_strfmon_l"]=(a0,a1,a2,a3,a4)=>(_strfmon_l=Module["_strfmon_l"]=wasmExports["strfmon_l"])(a0,a1,a2,a3,a4);var _strfmon=Module["_strfmon"]=(a0,a1,a2,a3)=>(_strfmon=Module["_strfmon"]=wasmExports["strfmon"])(a0,a1,a2,a3);var _strlcat=Module["_strlcat"]=(a0,a1,a2)=>(_strlcat=Module["_strlcat"]=wasmExports["strlcat"])(a0,a1,a2);var _strlcpy=Module["_strlcpy"]=(a0,a1,a2)=>(_strlcpy=Module["_strlcpy"]=wasmExports["strlcpy"])(a0,a1,a2);var _strlwr=Module["_strlwr"]=a0=>(_strlwr=Module["_strlwr"]=wasmExports["strlwr"])(a0);var ___strncasecmp_l=Module["___strncasecmp_l"]=(a0,a1,a2,a3)=>(___strncasecmp_l=Module["___strncasecmp_l"]=wasmExports["__strncasecmp_l"])(a0,a1,a2,a3);var _strncasecmp_l=Module["_strncasecmp_l"]=(a0,a1,a2,a3)=>(_strncasecmp_l=Module["_strncasecmp_l"]=wasmExports["strncasecmp_l"])(a0,a1,a2,a3);var _strndup=Module["_strndup"]=(a0,a1)=>(_strndup=Module["_strndup"]=wasmExports["strndup"])(a0,a1);var _strsep=Module["_strsep"]=(a0,a1)=>(_strsep=Module["_strsep"]=wasmExports["strsep"])(a0,a1);var _strtof=Module["_strtof"]=(a0,a1)=>(_strtof=Module["_strtof"]=wasmExports["strtof"])(a0,a1);var _strtold=Module["_strtold"]=(a0,a1,a2)=>(_strtold=Module["_strtold"]=wasmExports["strtold"])(a0,a1,a2);var _strtof_l=Module["_strtof_l"]=(a0,a1,a2)=>(_strtof_l=Module["_strtof_l"]=wasmExports["strtof_l"])(a0,a1,a2);var _strtod_l=Module["_strtod_l"]=(a0,a1,a2)=>(_strtod_l=Module["_strtod_l"]=wasmExports["strtod_l"])(a0,a1,a2);var _strtold_l=Module["_strtold_l"]=(a0,a1,a2,a3)=>(_strtold_l=Module["_strtold_l"]=wasmExports["strtold_l"])(a0,a1,a2,a3);var ___strtof_l=Module["___strtof_l"]=(a0,a1,a2)=>(___strtof_l=Module["___strtof_l"]=wasmExports["__strtof_l"])(a0,a1,a2);var ___strtod_l=Module["___strtod_l"]=(a0,a1,a2)=>(___strtod_l=Module["___strtod_l"]=wasmExports["__strtod_l"])(a0,a1,a2);var ___strtold_l=Module["___strtold_l"]=(a0,a1,a2,a3)=>(___strtold_l=Module["___strtold_l"]=wasmExports["__strtold_l"])(a0,a1,a2,a3);var _strtok=Module["_strtok"]=(a0,a1)=>(_strtok=Module["_strtok"]=wasmExports["strtok"])(a0,a1);var _strtok_r=Module["_strtok_r"]=(a0,a1,a2)=>(_strtok_r=Module["_strtok_r"]=wasmExports["strtok_r"])(a0,a1,a2);var _strtoll=Module["_strtoll"]=(a0,a1,a2)=>(_strtoll=Module["_strtoll"]=wasmExports["strtoll"])(a0,a1,a2);var _strtoimax=Module["_strtoimax"]=(a0,a1,a2)=>(_strtoimax=Module["_strtoimax"]=wasmExports["strtoimax"])(a0,a1,a2);var _strtoumax=Module["_strtoumax"]=(a0,a1,a2)=>(_strtoumax=Module["_strtoumax"]=wasmExports["strtoumax"])(a0,a1,a2);var ___strtol_internal=Module["___strtol_internal"]=(a0,a1,a2)=>(___strtol_internal=Module["___strtol_internal"]=wasmExports["__strtol_internal"])(a0,a1,a2);var ___strtoul_internal=Module["___strtoul_internal"]=(a0,a1,a2)=>(___strtoul_internal=Module["___strtoul_internal"]=wasmExports["__strtoul_internal"])(a0,a1,a2);var ___strtoll_internal=Module["___strtoll_internal"]=(a0,a1,a2)=>(___strtoll_internal=Module["___strtoll_internal"]=wasmExports["__strtoll_internal"])(a0,a1,a2);var ___strtoull_internal=Module["___strtoull_internal"]=(a0,a1,a2)=>(___strtoull_internal=Module["___strtoull_internal"]=wasmExports["__strtoull_internal"])(a0,a1,a2);var ___strtoimax_internal=Module["___strtoimax_internal"]=(a0,a1,a2)=>(___strtoimax_internal=Module["___strtoimax_internal"]=wasmExports["__strtoimax_internal"])(a0,a1,a2);var ___strtoumax_internal=Module["___strtoumax_internal"]=(a0,a1,a2)=>(___strtoumax_internal=Module["___strtoumax_internal"]=wasmExports["__strtoumax_internal"])(a0,a1,a2);var _strtoull_l=Module["_strtoull_l"]=(a0,a1,a2,a3)=>(_strtoull_l=Module["_strtoull_l"]=wasmExports["strtoull_l"])(a0,a1,a2,a3);var _strtoll_l=Module["_strtoll_l"]=(a0,a1,a2,a3)=>(_strtoll_l=Module["_strtoll_l"]=wasmExports["strtoll_l"])(a0,a1,a2,a3);var _strtoul_l=Module["_strtoul_l"]=(a0,a1,a2,a3)=>(_strtoul_l=Module["_strtoul_l"]=wasmExports["strtoul_l"])(a0,a1,a2,a3);var _strtol_l=Module["_strtol_l"]=(a0,a1,a2,a3)=>(_strtol_l=Module["_strtol_l"]=wasmExports["strtol_l"])(a0,a1,a2,a3);var _strupr=Module["_strupr"]=a0=>(_strupr=Module["_strupr"]=wasmExports["strupr"])(a0);var _strverscmp=Module["_strverscmp"]=(a0,a1)=>(_strverscmp=Module["_strverscmp"]=wasmExports["strverscmp"])(a0,a1);var ___strxfrm_l=Module["___strxfrm_l"]=(a0,a1,a2,a3)=>(___strxfrm_l=Module["___strxfrm_l"]=wasmExports["__strxfrm_l"])(a0,a1,a2,a3);var _strxfrm=Module["_strxfrm"]=(a0,a1,a2)=>(_strxfrm=Module["_strxfrm"]=wasmExports["strxfrm"])(a0,a1,a2);var _strxfrm_l=Module["_strxfrm_l"]=(a0,a1,a2,a3)=>(_strxfrm_l=Module["_strxfrm_l"]=wasmExports["strxfrm_l"])(a0,a1,a2,a3);var _swab=Module["_swab"]=(a0,a1,a2)=>(_swab=Module["_swab"]=wasmExports["swab"])(a0,a1,a2);var _swprintf=Module["_swprintf"]=(a0,a1,a2,a3)=>(_swprintf=Module["_swprintf"]=wasmExports["swprintf"])(a0,a1,a2,a3);var _vswprintf=Module["_vswprintf"]=(a0,a1,a2,a3)=>(_vswprintf=Module["_vswprintf"]=wasmExports["vswprintf"])(a0,a1,a2,a3);var _swscanf=Module["_swscanf"]=(a0,a1,a2)=>(_swscanf=Module["_swscanf"]=wasmExports["swscanf"])(a0,a1,a2);var _vswscanf=Module["_vswscanf"]=(a0,a1,a2)=>(_vswscanf=Module["_vswscanf"]=wasmExports["vswscanf"])(a0,a1,a2);var ___isoc99_swscanf=Module["___isoc99_swscanf"]=(a0,a1,a2)=>(___isoc99_swscanf=Module["___isoc99_swscanf"]=wasmExports["__isoc99_swscanf"])(a0,a1,a2);var _symlinkat=Module["_symlinkat"]=(a0,a1,a2)=>(_symlinkat=Module["_symlinkat"]=wasmExports["symlinkat"])(a0,a1,a2);var _setlogmask=Module["_setlogmask"]=a0=>(_setlogmask=Module["_setlogmask"]=wasmExports["setlogmask"])(a0);var _closelog=Module["_closelog"]=()=>(_closelog=Module["_closelog"]=wasmExports["closelog"])();var _openlog=Module["_openlog"]=(a0,a1,a2)=>(_openlog=Module["_openlog"]=wasmExports["openlog"])(a0,a1,a2);var _syslog=Module["_syslog"]=(a0,a1,a2)=>(_syslog=Module["_syslog"]=wasmExports["syslog"])(a0,a1,a2);var _vsyslog=Module["_vsyslog"]=(a0,a1,a2)=>(_vsyslog=Module["_vsyslog"]=wasmExports["vsyslog"])(a0,a1,a2);var _tanhf=Module["_tanhf"]=a0=>(_tanhf=Module["_tanhf"]=wasmExports["tanhf"])(a0);var _tanhl=Module["_tanhl"]=(a0,a1,a2)=>(_tanhl=Module["_tanhl"]=wasmExports["tanhl"])(a0,a1,a2);var _tanl=Module["_tanl"]=(a0,a1,a2)=>(_tanl=Module["_tanl"]=wasmExports["tanl"])(a0,a1,a2);var _tcdrain=Module["_tcdrain"]=a0=>(_tcdrain=Module["_tcdrain"]=wasmExports["tcdrain"])(a0);var _tcflow=Module["_tcflow"]=(a0,a1)=>(_tcflow=Module["_tcflow"]=wasmExports["tcflow"])(a0,a1);var _tcflush=Module["_tcflush"]=(a0,a1)=>(_tcflush=Module["_tcflush"]=wasmExports["tcflush"])(a0,a1);var _tcgetattr=Module["_tcgetattr"]=(a0,a1)=>(_tcgetattr=Module["_tcgetattr"]=wasmExports["tcgetattr"])(a0,a1);var _tcgetsid=Module["_tcgetsid"]=a0=>(_tcgetsid=Module["_tcgetsid"]=wasmExports["tcgetsid"])(a0);var _tcgetwinsize=Module["_tcgetwinsize"]=(a0,a1)=>(_tcgetwinsize=Module["_tcgetwinsize"]=wasmExports["tcgetwinsize"])(a0,a1);var _tcsendbreak=Module["_tcsendbreak"]=(a0,a1)=>(_tcsendbreak=Module["_tcsendbreak"]=wasmExports["tcsendbreak"])(a0,a1);var _tcsetwinsize=Module["_tcsetwinsize"]=(a0,a1)=>(_tcsetwinsize=Module["_tcsetwinsize"]=wasmExports["tcsetwinsize"])(a0,a1);var _tdelete=Module["_tdelete"]=(a0,a1,a2)=>(_tdelete=Module["_tdelete"]=wasmExports["tdelete"])(a0,a1,a2);var _tdestroy=Module["_tdestroy"]=(a0,a1)=>(_tdestroy=Module["_tdestroy"]=wasmExports["tdestroy"])(a0,a1);var _telldir=Module["_telldir"]=a0=>(_telldir=Module["_telldir"]=wasmExports["telldir"])(a0);var _tempnam=Module["_tempnam"]=(a0,a1)=>(_tempnam=Module["_tempnam"]=wasmExports["tempnam"])(a0,a1);var _ngettext=Module["_ngettext"]=(a0,a1,a2)=>(_ngettext=Module["_ngettext"]=wasmExports["ngettext"])(a0,a1,a2);var _tfind=Module["_tfind"]=(a0,a1,a2)=>(_tfind=Module["_tfind"]=wasmExports["tfind"])(a0,a1,a2);var _tgamma=Module["_tgamma"]=a0=>(_tgamma=Module["_tgamma"]=wasmExports["tgamma"])(a0);var _tgammaf=Module["_tgammaf"]=a0=>(_tgammaf=Module["_tgammaf"]=wasmExports["tgammaf"])(a0);var _tgammal=Module["_tgammal"]=(a0,a1,a2)=>(_tgammal=Module["_tgammal"]=wasmExports["tgammal"])(a0,a1,a2);var _thrd_create=Module["_thrd_create"]=(a0,a1,a2)=>(_thrd_create=Module["_thrd_create"]=wasmExports["thrd_create"])(a0,a1,a2);var _thrd_exit=Module["_thrd_exit"]=a0=>(_thrd_exit=Module["_thrd_exit"]=wasmExports["thrd_exit"])(a0);var _thrd_join=Module["_thrd_join"]=(a0,a1)=>(_thrd_join=Module["_thrd_join"]=wasmExports["thrd_join"])(a0,a1);var _thrd_sleep=Module["_thrd_sleep"]=(a0,a1)=>(_thrd_sleep=Module["_thrd_sleep"]=wasmExports["thrd_sleep"])(a0,a1);var _thrd_yield=Module["_thrd_yield"]=()=>(_thrd_yield=Module["_thrd_yield"]=wasmExports["thrd_yield"])();var _emscripten_set_thread_name=Module["_emscripten_set_thread_name"]=(a0,a1)=>(_emscripten_set_thread_name=Module["_emscripten_set_thread_name"]=wasmExports["emscripten_set_thread_name"])(a0,a1);var _timespec_get=Module["_timespec_get"]=(a0,a1)=>(_timespec_get=Module["_timespec_get"]=wasmExports["timespec_get"])(a0,a1);var _tmpfile=Module["_tmpfile"]=()=>(_tmpfile=Module["_tmpfile"]=wasmExports["tmpfile"])();var _tmpnam=Module["_tmpnam"]=a0=>(_tmpnam=Module["_tmpnam"]=wasmExports["tmpnam"])(a0);var _toascii=Module["_toascii"]=a0=>(_toascii=Module["_toascii"]=wasmExports["toascii"])(a0);var ___tolower_l=Module["___tolower_l"]=(a0,a1)=>(___tolower_l=Module["___tolower_l"]=wasmExports["__tolower_l"])(a0,a1);var _tolower_l=Module["_tolower_l"]=(a0,a1)=>(_tolower_l=Module["_tolower_l"]=wasmExports["tolower_l"])(a0,a1);var ___toupper_l=Module["___toupper_l"]=(a0,a1)=>(___toupper_l=Module["___toupper_l"]=wasmExports["__toupper_l"])(a0,a1);var _toupper_l=Module["_toupper_l"]=(a0,a1)=>(_toupper_l=Module["_toupper_l"]=wasmExports["toupper_l"])(a0,a1);var ___towupper_l=Module["___towupper_l"]=(a0,a1)=>(___towupper_l=Module["___towupper_l"]=wasmExports["__towupper_l"])(a0,a1);var ___towlower_l=Module["___towlower_l"]=(a0,a1)=>(___towlower_l=Module["___towlower_l"]=wasmExports["__towlower_l"])(a0,a1);var _towupper_l=Module["_towupper_l"]=(a0,a1)=>(_towupper_l=Module["_towupper_l"]=wasmExports["towupper_l"])(a0,a1);var _towlower_l=Module["_towlower_l"]=(a0,a1)=>(_towlower_l=Module["_towlower_l"]=wasmExports["towlower_l"])(a0,a1);var _trunc=Module["_trunc"]=a0=>(_trunc=Module["_trunc"]=wasmExports["trunc"])(a0);var _truncf=Module["_truncf"]=a0=>(_truncf=Module["_truncf"]=wasmExports["truncf"])(a0);var _truncl=Module["_truncl"]=(a0,a1,a2)=>(_truncl=Module["_truncl"]=wasmExports["truncl"])(a0,a1,a2);var _tsearch=Module["_tsearch"]=(a0,a1,a2)=>(_tsearch=Module["_tsearch"]=wasmExports["tsearch"])(a0,a1,a2);var _tss_create=Module["_tss_create"]=(a0,a1)=>(_tss_create=Module["_tss_create"]=wasmExports["tss_create"])(a0,a1);var _tss_delete=Module["_tss_delete"]=a0=>(_tss_delete=Module["_tss_delete"]=wasmExports["tss_delete"])(a0);var _tss_set=Module["_tss_set"]=(a0,a1)=>(_tss_set=Module["_tss_set"]=wasmExports["tss_set"])(a0,a1);var _ttyname=Module["_ttyname"]=a0=>(_ttyname=Module["_ttyname"]=wasmExports["ttyname"])(a0);var _twalk=Module["_twalk"]=(a0,a1)=>(_twalk=Module["_twalk"]=wasmExports["twalk"])(a0,a1);var _ualarm=Module["_ualarm"]=(a0,a1)=>(_ualarm=Module["_ualarm"]=wasmExports["ualarm"])(a0,a1);var _ungetwc=Module["_ungetwc"]=(a0,a1)=>(_ungetwc=Module["_ungetwc"]=wasmExports["ungetwc"])(a0,a1);var ___uselocale=Module["___uselocale"]=a0=>(___uselocale=Module["___uselocale"]=wasmExports["__uselocale"])(a0);var _uselocale=Module["_uselocale"]=a0=>(_uselocale=Module["_uselocale"]=wasmExports["uselocale"])(a0);var _usleep=Module["_usleep"]=a0=>(_usleep=Module["_usleep"]=wasmExports["usleep"])(a0);var _utime=Module["_utime"]=(a0,a1)=>(_utime=Module["_utime"]=wasmExports["utime"])(a0,a1);var _versionsort=Module["_versionsort"]=(a0,a1)=>(_versionsort=Module["_versionsort"]=wasmExports["versionsort"])(a0,a1);var ___vfprintf_internal=Module["___vfprintf_internal"]=(a0,a1,a2,a3,a4)=>(___vfprintf_internal=Module["___vfprintf_internal"]=wasmExports["__vfprintf_internal"])(a0,a1,a2,a3,a4);var ___isoc99_vfscanf=Module["___isoc99_vfscanf"]=(a0,a1,a2)=>(___isoc99_vfscanf=Module["___isoc99_vfscanf"]=wasmExports["__isoc99_vfscanf"])(a0,a1,a2);var _wcsnlen=Module["_wcsnlen"]=(a0,a1)=>(_wcsnlen=Module["_wcsnlen"]=wasmExports["wcsnlen"])(a0,a1);var ___isoc99_vfwscanf=Module["___isoc99_vfwscanf"]=(a0,a1,a2)=>(___isoc99_vfwscanf=Module["___isoc99_vfwscanf"]=wasmExports["__isoc99_vfwscanf"])(a0,a1,a2);var _vprintf=Module["_vprintf"]=(a0,a1)=>(_vprintf=Module["_vprintf"]=wasmExports["vprintf"])(a0,a1);var ___isoc99_vscanf=Module["___isoc99_vscanf"]=(a0,a1)=>(___isoc99_vscanf=Module["___isoc99_vscanf"]=wasmExports["__isoc99_vscanf"])(a0,a1);var _vsniprintf=Module["_vsniprintf"]=(a0,a1,a2,a3)=>(_vsniprintf=Module["_vsniprintf"]=wasmExports["vsniprintf"])(a0,a1,a2,a3);var ___small_vsnprintf=Module["___small_vsnprintf"]=(a0,a1,a2,a3)=>(___small_vsnprintf=Module["___small_vsnprintf"]=wasmExports["__small_vsnprintf"])(a0,a1,a2,a3);var ___isoc99_vsscanf=Module["___isoc99_vsscanf"]=(a0,a1,a2)=>(___isoc99_vsscanf=Module["___isoc99_vsscanf"]=wasmExports["__isoc99_vsscanf"])(a0,a1,a2);var ___isoc99_vswscanf=Module["___isoc99_vswscanf"]=(a0,a1,a2)=>(___isoc99_vswscanf=Module["___isoc99_vswscanf"]=wasmExports["__isoc99_vswscanf"])(a0,a1,a2);var _vwprintf=Module["_vwprintf"]=(a0,a1)=>(_vwprintf=Module["_vwprintf"]=wasmExports["vwprintf"])(a0,a1);var _vwscanf=Module["_vwscanf"]=(a0,a1)=>(_vwscanf=Module["_vwscanf"]=wasmExports["vwscanf"])(a0,a1);var ___isoc99_vwscanf=Module["___isoc99_vwscanf"]=(a0,a1)=>(___isoc99_vwscanf=Module["___isoc99_vwscanf"]=wasmExports["__isoc99_vwscanf"])(a0,a1);var _wcpcpy=Module["_wcpcpy"]=(a0,a1)=>(_wcpcpy=Module["_wcpcpy"]=wasmExports["wcpcpy"])(a0,a1);var _wcpncpy=Module["_wcpncpy"]=(a0,a1,a2)=>(_wcpncpy=Module["_wcpncpy"]=wasmExports["wcpncpy"])(a0,a1,a2);var _wcscasecmp=Module["_wcscasecmp"]=(a0,a1)=>(_wcscasecmp=Module["_wcscasecmp"]=wasmExports["wcscasecmp"])(a0,a1);var _wcsncasecmp=Module["_wcsncasecmp"]=(a0,a1,a2)=>(_wcsncasecmp=Module["_wcsncasecmp"]=wasmExports["wcsncasecmp"])(a0,a1,a2);var _wcscasecmp_l=Module["_wcscasecmp_l"]=(a0,a1,a2)=>(_wcscasecmp_l=Module["_wcscasecmp_l"]=wasmExports["wcscasecmp_l"])(a0,a1,a2);var _wcscat=Module["_wcscat"]=(a0,a1)=>(_wcscat=Module["_wcscat"]=wasmExports["wcscat"])(a0,a1);var ___wcscoll_l=Module["___wcscoll_l"]=(a0,a1,a2)=>(___wcscoll_l=Module["___wcscoll_l"]=wasmExports["__wcscoll_l"])(a0,a1,a2);var _wcscoll_l=Module["_wcscoll_l"]=(a0,a1,a2)=>(_wcscoll_l=Module["_wcscoll_l"]=wasmExports["wcscoll_l"])(a0,a1,a2);var _wcscspn=Module["_wcscspn"]=(a0,a1)=>(_wcscspn=Module["_wcscspn"]=wasmExports["wcscspn"])(a0,a1);var _wcsdup=Module["_wcsdup"]=a0=>(_wcsdup=Module["_wcsdup"]=wasmExports["wcsdup"])(a0);var _wmemcpy=Module["_wmemcpy"]=(a0,a1,a2)=>(_wmemcpy=Module["_wmemcpy"]=wasmExports["wmemcpy"])(a0,a1,a2);var _wcsncasecmp_l=Module["_wcsncasecmp_l"]=(a0,a1,a2,a3)=>(_wcsncasecmp_l=Module["_wcsncasecmp_l"]=wasmExports["wcsncasecmp_l"])(a0,a1,a2,a3);var _wcsncat=Module["_wcsncat"]=(a0,a1,a2)=>(_wcsncat=Module["_wcsncat"]=wasmExports["wcsncat"])(a0,a1,a2);var _wmemset=Module["_wmemset"]=(a0,a1,a2)=>(_wmemset=Module["_wmemset"]=wasmExports["wmemset"])(a0,a1,a2);var _wcsnrtombs=Module["_wcsnrtombs"]=(a0,a1,a2,a3,a4)=>(_wcsnrtombs=Module["_wcsnrtombs"]=wasmExports["wcsnrtombs"])(a0,a1,a2,a3,a4);var _wcspbrk=Module["_wcspbrk"]=(a0,a1)=>(_wcspbrk=Module["_wcspbrk"]=wasmExports["wcspbrk"])(a0,a1);var _wcsspn=Module["_wcsspn"]=(a0,a1)=>(_wcsspn=Module["_wcsspn"]=wasmExports["wcsspn"])(a0,a1);var _wcsstr=Module["_wcsstr"]=(a0,a1)=>(_wcsstr=Module["_wcsstr"]=wasmExports["wcsstr"])(a0,a1);var _wcstof=Module["_wcstof"]=(a0,a1)=>(_wcstof=Module["_wcstof"]=wasmExports["wcstof"])(a0,a1);var _wcstod=Module["_wcstod"]=(a0,a1)=>(_wcstod=Module["_wcstod"]=wasmExports["wcstod"])(a0,a1);var _wcstold=Module["_wcstold"]=(a0,a1,a2)=>(_wcstold=Module["_wcstold"]=wasmExports["wcstold"])(a0,a1,a2);var _wcstoull=Module["_wcstoull"]=(a0,a1,a2)=>(_wcstoull=Module["_wcstoull"]=wasmExports["wcstoull"])(a0,a1,a2);var _wcstoll=Module["_wcstoll"]=(a0,a1,a2)=>(_wcstoll=Module["_wcstoll"]=wasmExports["wcstoll"])(a0,a1,a2);var _wcstoul=Module["_wcstoul"]=(a0,a1,a2)=>(_wcstoul=Module["_wcstoul"]=wasmExports["wcstoul"])(a0,a1,a2);var _wcstoimax=Module["_wcstoimax"]=(a0,a1,a2)=>(_wcstoimax=Module["_wcstoimax"]=wasmExports["wcstoimax"])(a0,a1,a2);var _wcstoumax=Module["_wcstoumax"]=(a0,a1,a2)=>(_wcstoumax=Module["_wcstoumax"]=wasmExports["wcstoumax"])(a0,a1,a2);var _wcswcs=Module["_wcswcs"]=(a0,a1)=>(_wcswcs=Module["_wcswcs"]=wasmExports["wcswcs"])(a0,a1);var _wcswidth=Module["_wcswidth"]=(a0,a1)=>(_wcswidth=Module["_wcswidth"]=wasmExports["wcswidth"])(a0,a1);var _wcwidth=Module["_wcwidth"]=a0=>(_wcwidth=Module["_wcwidth"]=wasmExports["wcwidth"])(a0);var ___wcsxfrm_l=Module["___wcsxfrm_l"]=(a0,a1,a2,a3)=>(___wcsxfrm_l=Module["___wcsxfrm_l"]=wasmExports["__wcsxfrm_l"])(a0,a1,a2,a3);var _wcsxfrm_l=Module["_wcsxfrm_l"]=(a0,a1,a2,a3)=>(_wcsxfrm_l=Module["_wcsxfrm_l"]=wasmExports["wcsxfrm_l"])(a0,a1,a2,a3);var _wctob=Module["_wctob"]=a0=>(_wctob=Module["_wctob"]=wasmExports["wctob"])(a0);var _wctrans=Module["_wctrans"]=a0=>(_wctrans=Module["_wctrans"]=wasmExports["wctrans"])(a0);var _towctrans=Module["_towctrans"]=(a0,a1)=>(_towctrans=Module["_towctrans"]=wasmExports["towctrans"])(a0,a1);var ___wctrans_l=Module["___wctrans_l"]=(a0,a1)=>(___wctrans_l=Module["___wctrans_l"]=wasmExports["__wctrans_l"])(a0,a1);var ___towctrans_l=Module["___towctrans_l"]=(a0,a1,a2)=>(___towctrans_l=Module["___towctrans_l"]=wasmExports["__towctrans_l"])(a0,a1,a2);var _wctrans_l=Module["_wctrans_l"]=(a0,a1)=>(_wctrans_l=Module["_wctrans_l"]=wasmExports["wctrans_l"])(a0,a1);var _towctrans_l=Module["_towctrans_l"]=(a0,a1,a2)=>(_towctrans_l=Module["_towctrans_l"]=wasmExports["towctrans_l"])(a0,a1,a2);var _wmemmove=Module["_wmemmove"]=(a0,a1,a2)=>(_wmemmove=Module["_wmemmove"]=wasmExports["wmemmove"])(a0,a1,a2);var _wprintf=Module["_wprintf"]=(a0,a1)=>(_wprintf=Module["_wprintf"]=wasmExports["wprintf"])(a0,a1);var _wscanf=Module["_wscanf"]=(a0,a1)=>(_wscanf=Module["_wscanf"]=wasmExports["wscanf"])(a0,a1);var ___isoc99_wscanf=Module["___isoc99_wscanf"]=(a0,a1)=>(___isoc99_wscanf=Module["___isoc99_wscanf"]=wasmExports["__isoc99_wscanf"])(a0,a1);var ___libc_realloc=Module["___libc_realloc"]=(a0,a1)=>(___libc_realloc=Module["___libc_realloc"]=wasmExports["__libc_realloc"])(a0,a1);var _realloc_in_place=Module["_realloc_in_place"]=(a0,a1)=>(_realloc_in_place=Module["_realloc_in_place"]=wasmExports["realloc_in_place"])(a0,a1);var _memalign=Module["_memalign"]=(a0,a1)=>(_memalign=Module["_memalign"]=wasmExports["memalign"])(a0,a1);var _valloc=Module["_valloc"]=a0=>(_valloc=Module["_valloc"]=wasmExports["valloc"])(a0);var _pvalloc=Module["_pvalloc"]=a0=>(_pvalloc=Module["_pvalloc"]=wasmExports["pvalloc"])(a0);var _mallinfo=Module["_mallinfo"]=a0=>(_mallinfo=Module["_mallinfo"]=wasmExports["mallinfo"])(a0);var _mallopt=Module["_mallopt"]=(a0,a1)=>(_mallopt=Module["_mallopt"]=wasmExports["mallopt"])(a0,a1);var _malloc_trim=Module["_malloc_trim"]=a0=>(_malloc_trim=Module["_malloc_trim"]=wasmExports["malloc_trim"])(a0);var _malloc_usable_size=Module["_malloc_usable_size"]=a0=>(_malloc_usable_size=Module["_malloc_usable_size"]=wasmExports["malloc_usable_size"])(a0);var _malloc_footprint=Module["_malloc_footprint"]=()=>(_malloc_footprint=Module["_malloc_footprint"]=wasmExports["malloc_footprint"])();var _malloc_max_footprint=Module["_malloc_max_footprint"]=()=>(_malloc_max_footprint=Module["_malloc_max_footprint"]=wasmExports["malloc_max_footprint"])();var _malloc_footprint_limit=Module["_malloc_footprint_limit"]=()=>(_malloc_footprint_limit=Module["_malloc_footprint_limit"]=wasmExports["malloc_footprint_limit"])();var _malloc_set_footprint_limit=Module["_malloc_set_footprint_limit"]=a0=>(_malloc_set_footprint_limit=Module["_malloc_set_footprint_limit"]=wasmExports["malloc_set_footprint_limit"])(a0);var _independent_calloc=Module["_independent_calloc"]=(a0,a1,a2)=>(_independent_calloc=Module["_independent_calloc"]=wasmExports["independent_calloc"])(a0,a1,a2);var _independent_comalloc=Module["_independent_comalloc"]=(a0,a1,a2)=>(_independent_comalloc=Module["_independent_comalloc"]=wasmExports["independent_comalloc"])(a0,a1,a2);var _bulk_free=Module["_bulk_free"]=(a0,a1)=>(_bulk_free=Module["_bulk_free"]=wasmExports["bulk_free"])(a0,a1);var ___trap=Module["___trap"]=()=>(___trap=Module["___trap"]=wasmExports["__trap"])();var ___absvdi2=Module["___absvdi2"]=a0=>(___absvdi2=Module["___absvdi2"]=wasmExports["__absvdi2"])(a0);var ___absvsi2=Module["___absvsi2"]=a0=>(___absvsi2=Module["___absvsi2"]=wasmExports["__absvsi2"])(a0);var ___absvti2=Module["___absvti2"]=(a0,a1,a2)=>(___absvti2=Module["___absvti2"]=wasmExports["__absvti2"])(a0,a1,a2);var ___adddf3=Module["___adddf3"]=(a0,a1)=>(___adddf3=Module["___adddf3"]=wasmExports["__adddf3"])(a0,a1);var ___fe_getround=Module["___fe_getround"]=()=>(___fe_getround=Module["___fe_getround"]=wasmExports["__fe_getround"])();var ___fe_raise_inexact=Module["___fe_raise_inexact"]=()=>(___fe_raise_inexact=Module["___fe_raise_inexact"]=wasmExports["__fe_raise_inexact"])();var ___addsf3=Module["___addsf3"]=(a0,a1)=>(___addsf3=Module["___addsf3"]=wasmExports["__addsf3"])(a0,a1);var ___ashlti3=Module["___ashlti3"]=(a0,a1,a2,a3)=>(___ashlti3=Module["___ashlti3"]=wasmExports["__ashlti3"])(a0,a1,a2,a3);var ___lshrti3=Module["___lshrti3"]=(a0,a1,a2,a3)=>(___lshrti3=Module["___lshrti3"]=wasmExports["__lshrti3"])(a0,a1,a2,a3);var ___addvdi3=Module["___addvdi3"]=(a0,a1)=>(___addvdi3=Module["___addvdi3"]=wasmExports["__addvdi3"])(a0,a1);var ___addvsi3=Module["___addvsi3"]=(a0,a1)=>(___addvsi3=Module["___addvsi3"]=wasmExports["__addvsi3"])(a0,a1);var ___addvti3=Module["___addvti3"]=(a0,a1,a2,a3,a4)=>(___addvti3=Module["___addvti3"]=wasmExports["__addvti3"])(a0,a1,a2,a3,a4);var ___ashldi3=Module["___ashldi3"]=(a0,a1)=>(___ashldi3=Module["___ashldi3"]=wasmExports["__ashldi3"])(a0,a1);var ___ashrdi3=Module["___ashrdi3"]=(a0,a1)=>(___ashrdi3=Module["___ashrdi3"]=wasmExports["__ashrdi3"])(a0,a1);var ___ashrti3=Module["___ashrti3"]=(a0,a1,a2,a3)=>(___ashrti3=Module["___ashrti3"]=wasmExports["__ashrti3"])(a0,a1,a2,a3);var ___atomic_is_lock_free=Module["___atomic_is_lock_free"]=(a0,a1)=>(___atomic_is_lock_free=Module["___atomic_is_lock_free"]=wasmExports["__atomic_is_lock_free"])(a0,a1);var ___atomic_load=Module["___atomic_load"]=(a0,a1,a2,a3)=>(___atomic_load=Module["___atomic_load"]=wasmExports["__atomic_load"])(a0,a1,a2,a3);var ___atomic_store=Module["___atomic_store"]=(a0,a1,a2,a3)=>(___atomic_store=Module["___atomic_store"]=wasmExports["__atomic_store"])(a0,a1,a2,a3);var ___atomic_compare_exchange=Module["___atomic_compare_exchange"]=(a0,a1,a2,a3,a4,a5)=>(___atomic_compare_exchange=Module["___atomic_compare_exchange"]=wasmExports["__atomic_compare_exchange"])(a0,a1,a2,a3,a4,a5);var ___atomic_exchange=Module["___atomic_exchange"]=(a0,a1,a2,a3,a4)=>(___atomic_exchange=Module["___atomic_exchange"]=wasmExports["__atomic_exchange"])(a0,a1,a2,a3,a4);var ___atomic_load_1=Module["___atomic_load_1"]=(a0,a1)=>(___atomic_load_1=Module["___atomic_load_1"]=wasmExports["__atomic_load_1"])(a0,a1);var ___atomic_load_2=Module["___atomic_load_2"]=(a0,a1)=>(___atomic_load_2=Module["___atomic_load_2"]=wasmExports["__atomic_load_2"])(a0,a1);var ___atomic_load_4=Module["___atomic_load_4"]=(a0,a1)=>(___atomic_load_4=Module["___atomic_load_4"]=wasmExports["__atomic_load_4"])(a0,a1);var ___atomic_load_8=Module["___atomic_load_8"]=(a0,a1)=>(___atomic_load_8=Module["___atomic_load_8"]=wasmExports["__atomic_load_8"])(a0,a1);var ___atomic_load_16=Module["___atomic_load_16"]=(a0,a1,a2)=>(___atomic_load_16=Module["___atomic_load_16"]=wasmExports["__atomic_load_16"])(a0,a1,a2);var ___atomic_store_1=Module["___atomic_store_1"]=(a0,a1,a2)=>(___atomic_store_1=Module["___atomic_store_1"]=wasmExports["__atomic_store_1"])(a0,a1,a2);var ___atomic_store_2=Module["___atomic_store_2"]=(a0,a1,a2)=>(___atomic_store_2=Module["___atomic_store_2"]=wasmExports["__atomic_store_2"])(a0,a1,a2);var ___atomic_store_4=Module["___atomic_store_4"]=(a0,a1,a2)=>(___atomic_store_4=Module["___atomic_store_4"]=wasmExports["__atomic_store_4"])(a0,a1,a2);var ___atomic_store_8=Module["___atomic_store_8"]=(a0,a1,a2)=>(___atomic_store_8=Module["___atomic_store_8"]=wasmExports["__atomic_store_8"])(a0,a1,a2);var ___atomic_store_16=Module["___atomic_store_16"]=(a0,a1,a2,a3)=>(___atomic_store_16=Module["___atomic_store_16"]=wasmExports["__atomic_store_16"])(a0,a1,a2,a3);var ___atomic_exchange_1=Module["___atomic_exchange_1"]=(a0,a1,a2)=>(___atomic_exchange_1=Module["___atomic_exchange_1"]=wasmExports["__atomic_exchange_1"])(a0,a1,a2);var ___atomic_exchange_2=Module["___atomic_exchange_2"]=(a0,a1,a2)=>(___atomic_exchange_2=Module["___atomic_exchange_2"]=wasmExports["__atomic_exchange_2"])(a0,a1,a2);var ___atomic_exchange_4=Module["___atomic_exchange_4"]=(a0,a1,a2)=>(___atomic_exchange_4=Module["___atomic_exchange_4"]=wasmExports["__atomic_exchange_4"])(a0,a1,a2);var ___atomic_exchange_8=Module["___atomic_exchange_8"]=(a0,a1,a2)=>(___atomic_exchange_8=Module["___atomic_exchange_8"]=wasmExports["__atomic_exchange_8"])(a0,a1,a2);var ___atomic_exchange_16=Module["___atomic_exchange_16"]=(a0,a1,a2,a3,a4)=>(___atomic_exchange_16=Module["___atomic_exchange_16"]=wasmExports["__atomic_exchange_16"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_1=Module["___atomic_compare_exchange_1"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_1=Module["___atomic_compare_exchange_1"]=wasmExports["__atomic_compare_exchange_1"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_2=Module["___atomic_compare_exchange_2"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_2=Module["___atomic_compare_exchange_2"]=wasmExports["__atomic_compare_exchange_2"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_4=Module["___atomic_compare_exchange_4"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_4=Module["___atomic_compare_exchange_4"]=wasmExports["__atomic_compare_exchange_4"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_8=Module["___atomic_compare_exchange_8"]=(a0,a1,a2,a3,a4)=>(___atomic_compare_exchange_8=Module["___atomic_compare_exchange_8"]=wasmExports["__atomic_compare_exchange_8"])(a0,a1,a2,a3,a4);var ___atomic_compare_exchange_16=Module["___atomic_compare_exchange_16"]=(a0,a1,a2,a3,a4,a5)=>(___atomic_compare_exchange_16=Module["___atomic_compare_exchange_16"]=wasmExports["__atomic_compare_exchange_16"])(a0,a1,a2,a3,a4,a5);var ___atomic_fetch_add_1=Module["___atomic_fetch_add_1"]=(a0,a1,a2)=>(___atomic_fetch_add_1=Module["___atomic_fetch_add_1"]=wasmExports["__atomic_fetch_add_1"])(a0,a1,a2);var ___atomic_fetch_add_2=Module["___atomic_fetch_add_2"]=(a0,a1,a2)=>(___atomic_fetch_add_2=Module["___atomic_fetch_add_2"]=wasmExports["__atomic_fetch_add_2"])(a0,a1,a2);var ___atomic_fetch_add_4=Module["___atomic_fetch_add_4"]=(a0,a1,a2)=>(___atomic_fetch_add_4=Module["___atomic_fetch_add_4"]=wasmExports["__atomic_fetch_add_4"])(a0,a1,a2);var ___atomic_fetch_add_8=Module["___atomic_fetch_add_8"]=(a0,a1,a2)=>(___atomic_fetch_add_8=Module["___atomic_fetch_add_8"]=wasmExports["__atomic_fetch_add_8"])(a0,a1,a2);var ___atomic_fetch_add_16=Module["___atomic_fetch_add_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_add_16=Module["___atomic_fetch_add_16"]=wasmExports["__atomic_fetch_add_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_sub_1=Module["___atomic_fetch_sub_1"]=(a0,a1,a2)=>(___atomic_fetch_sub_1=Module["___atomic_fetch_sub_1"]=wasmExports["__atomic_fetch_sub_1"])(a0,a1,a2);var ___atomic_fetch_sub_2=Module["___atomic_fetch_sub_2"]=(a0,a1,a2)=>(___atomic_fetch_sub_2=Module["___atomic_fetch_sub_2"]=wasmExports["__atomic_fetch_sub_2"])(a0,a1,a2);var ___atomic_fetch_sub_4=Module["___atomic_fetch_sub_4"]=(a0,a1,a2)=>(___atomic_fetch_sub_4=Module["___atomic_fetch_sub_4"]=wasmExports["__atomic_fetch_sub_4"])(a0,a1,a2);var ___atomic_fetch_sub_8=Module["___atomic_fetch_sub_8"]=(a0,a1,a2)=>(___atomic_fetch_sub_8=Module["___atomic_fetch_sub_8"]=wasmExports["__atomic_fetch_sub_8"])(a0,a1,a2);var ___atomic_fetch_sub_16=Module["___atomic_fetch_sub_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_sub_16=Module["___atomic_fetch_sub_16"]=wasmExports["__atomic_fetch_sub_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_and_1=Module["___atomic_fetch_and_1"]=(a0,a1,a2)=>(___atomic_fetch_and_1=Module["___atomic_fetch_and_1"]=wasmExports["__atomic_fetch_and_1"])(a0,a1,a2);var ___atomic_fetch_and_2=Module["___atomic_fetch_and_2"]=(a0,a1,a2)=>(___atomic_fetch_and_2=Module["___atomic_fetch_and_2"]=wasmExports["__atomic_fetch_and_2"])(a0,a1,a2);var ___atomic_fetch_and_4=Module["___atomic_fetch_and_4"]=(a0,a1,a2)=>(___atomic_fetch_and_4=Module["___atomic_fetch_and_4"]=wasmExports["__atomic_fetch_and_4"])(a0,a1,a2);var ___atomic_fetch_and_8=Module["___atomic_fetch_and_8"]=(a0,a1,a2)=>(___atomic_fetch_and_8=Module["___atomic_fetch_and_8"]=wasmExports["__atomic_fetch_and_8"])(a0,a1,a2);var ___atomic_fetch_and_16=Module["___atomic_fetch_and_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_and_16=Module["___atomic_fetch_and_16"]=wasmExports["__atomic_fetch_and_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_or_1=Module["___atomic_fetch_or_1"]=(a0,a1,a2)=>(___atomic_fetch_or_1=Module["___atomic_fetch_or_1"]=wasmExports["__atomic_fetch_or_1"])(a0,a1,a2);var ___atomic_fetch_or_2=Module["___atomic_fetch_or_2"]=(a0,a1,a2)=>(___atomic_fetch_or_2=Module["___atomic_fetch_or_2"]=wasmExports["__atomic_fetch_or_2"])(a0,a1,a2);var ___atomic_fetch_or_4=Module["___atomic_fetch_or_4"]=(a0,a1,a2)=>(___atomic_fetch_or_4=Module["___atomic_fetch_or_4"]=wasmExports["__atomic_fetch_or_4"])(a0,a1,a2);var ___atomic_fetch_or_8=Module["___atomic_fetch_or_8"]=(a0,a1,a2)=>(___atomic_fetch_or_8=Module["___atomic_fetch_or_8"]=wasmExports["__atomic_fetch_or_8"])(a0,a1,a2);var ___atomic_fetch_or_16=Module["___atomic_fetch_or_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_or_16=Module["___atomic_fetch_or_16"]=wasmExports["__atomic_fetch_or_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_xor_1=Module["___atomic_fetch_xor_1"]=(a0,a1,a2)=>(___atomic_fetch_xor_1=Module["___atomic_fetch_xor_1"]=wasmExports["__atomic_fetch_xor_1"])(a0,a1,a2);var ___atomic_fetch_xor_2=Module["___atomic_fetch_xor_2"]=(a0,a1,a2)=>(___atomic_fetch_xor_2=Module["___atomic_fetch_xor_2"]=wasmExports["__atomic_fetch_xor_2"])(a0,a1,a2);var ___atomic_fetch_xor_4=Module["___atomic_fetch_xor_4"]=(a0,a1,a2)=>(___atomic_fetch_xor_4=Module["___atomic_fetch_xor_4"]=wasmExports["__atomic_fetch_xor_4"])(a0,a1,a2);var ___atomic_fetch_xor_8=Module["___atomic_fetch_xor_8"]=(a0,a1,a2)=>(___atomic_fetch_xor_8=Module["___atomic_fetch_xor_8"]=wasmExports["__atomic_fetch_xor_8"])(a0,a1,a2);var ___atomic_fetch_xor_16=Module["___atomic_fetch_xor_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_xor_16=Module["___atomic_fetch_xor_16"]=wasmExports["__atomic_fetch_xor_16"])(a0,a1,a2,a3,a4);var ___atomic_fetch_nand_1=Module["___atomic_fetch_nand_1"]=(a0,a1,a2)=>(___atomic_fetch_nand_1=Module["___atomic_fetch_nand_1"]=wasmExports["__atomic_fetch_nand_1"])(a0,a1,a2);var ___atomic_fetch_nand_2=Module["___atomic_fetch_nand_2"]=(a0,a1,a2)=>(___atomic_fetch_nand_2=Module["___atomic_fetch_nand_2"]=wasmExports["__atomic_fetch_nand_2"])(a0,a1,a2);var ___atomic_fetch_nand_4=Module["___atomic_fetch_nand_4"]=(a0,a1,a2)=>(___atomic_fetch_nand_4=Module["___atomic_fetch_nand_4"]=wasmExports["__atomic_fetch_nand_4"])(a0,a1,a2);var ___atomic_fetch_nand_8=Module["___atomic_fetch_nand_8"]=(a0,a1,a2)=>(___atomic_fetch_nand_8=Module["___atomic_fetch_nand_8"]=wasmExports["__atomic_fetch_nand_8"])(a0,a1,a2);var ___atomic_fetch_nand_16=Module["___atomic_fetch_nand_16"]=(a0,a1,a2,a3,a4)=>(___atomic_fetch_nand_16=Module["___atomic_fetch_nand_16"]=wasmExports["__atomic_fetch_nand_16"])(a0,a1,a2,a3,a4);var _atomic_flag_clear=Module["_atomic_flag_clear"]=a0=>(_atomic_flag_clear=Module["_atomic_flag_clear"]=wasmExports["atomic_flag_clear"])(a0);var _atomic_flag_clear_explicit=Module["_atomic_flag_clear_explicit"]=(a0,a1)=>(_atomic_flag_clear_explicit=Module["_atomic_flag_clear_explicit"]=wasmExports["atomic_flag_clear_explicit"])(a0,a1);var _atomic_flag_test_and_set=Module["_atomic_flag_test_and_set"]=a0=>(_atomic_flag_test_and_set=Module["_atomic_flag_test_and_set"]=wasmExports["atomic_flag_test_and_set"])(a0);var _atomic_flag_test_and_set_explicit=Module["_atomic_flag_test_and_set_explicit"]=(a0,a1)=>(_atomic_flag_test_and_set_explicit=Module["_atomic_flag_test_and_set_explicit"]=wasmExports["atomic_flag_test_and_set_explicit"])(a0,a1);var _atomic_signal_fence=Module["_atomic_signal_fence"]=a0=>(_atomic_signal_fence=Module["_atomic_signal_fence"]=wasmExports["atomic_signal_fence"])(a0);var _atomic_thread_fence=Module["_atomic_thread_fence"]=a0=>(_atomic_thread_fence=Module["_atomic_thread_fence"]=wasmExports["atomic_thread_fence"])(a0);var ___bswapdi2=Module["___bswapdi2"]=a0=>(___bswapdi2=Module["___bswapdi2"]=wasmExports["__bswapdi2"])(a0);var ___bswapsi2=Module["___bswapsi2"]=a0=>(___bswapsi2=Module["___bswapsi2"]=wasmExports["__bswapsi2"])(a0);var ___clear_cache=Module["___clear_cache"]=(a0,a1)=>(___clear_cache=Module["___clear_cache"]=wasmExports["__clear_cache"])(a0,a1);var ___clzdi2=Module["___clzdi2"]=a0=>(___clzdi2=Module["___clzdi2"]=wasmExports["__clzdi2"])(a0);var ___clzsi2=Module["___clzsi2"]=a0=>(___clzsi2=Module["___clzsi2"]=wasmExports["__clzsi2"])(a0);var ___clzti2=Module["___clzti2"]=(a0,a1)=>(___clzti2=Module["___clzti2"]=wasmExports["__clzti2"])(a0,a1);var ___cmpdi2=Module["___cmpdi2"]=(a0,a1)=>(___cmpdi2=Module["___cmpdi2"]=wasmExports["__cmpdi2"])(a0,a1);var ___cmpti2=Module["___cmpti2"]=(a0,a1,a2,a3)=>(___cmpti2=Module["___cmpti2"]=wasmExports["__cmpti2"])(a0,a1,a2,a3);var ___ledf2=Module["___ledf2"]=(a0,a1)=>(___ledf2=Module["___ledf2"]=wasmExports["__ledf2"])(a0,a1);var ___gedf2=Module["___gedf2"]=(a0,a1)=>(___gedf2=Module["___gedf2"]=wasmExports["__gedf2"])(a0,a1);var ___unorddf2=Module["___unorddf2"]=(a0,a1)=>(___unorddf2=Module["___unorddf2"]=wasmExports["__unorddf2"])(a0,a1);var ___eqdf2=Module["___eqdf2"]=(a0,a1)=>(___eqdf2=Module["___eqdf2"]=wasmExports["__eqdf2"])(a0,a1);var ___ltdf2=Module["___ltdf2"]=(a0,a1)=>(___ltdf2=Module["___ltdf2"]=wasmExports["__ltdf2"])(a0,a1);var ___nedf2=Module["___nedf2"]=(a0,a1)=>(___nedf2=Module["___nedf2"]=wasmExports["__nedf2"])(a0,a1);var ___gtdf2=Module["___gtdf2"]=(a0,a1)=>(___gtdf2=Module["___gtdf2"]=wasmExports["__gtdf2"])(a0,a1);var ___lesf2=Module["___lesf2"]=(a0,a1)=>(___lesf2=Module["___lesf2"]=wasmExports["__lesf2"])(a0,a1);var ___gesf2=Module["___gesf2"]=(a0,a1)=>(___gesf2=Module["___gesf2"]=wasmExports["__gesf2"])(a0,a1);var ___unordsf2=Module["___unordsf2"]=(a0,a1)=>(___unordsf2=Module["___unordsf2"]=wasmExports["__unordsf2"])(a0,a1);var ___eqsf2=Module["___eqsf2"]=(a0,a1)=>(___eqsf2=Module["___eqsf2"]=wasmExports["__eqsf2"])(a0,a1);var ___ltsf2=Module["___ltsf2"]=(a0,a1)=>(___ltsf2=Module["___ltsf2"]=wasmExports["__ltsf2"])(a0,a1);var ___nesf2=Module["___nesf2"]=(a0,a1)=>(___nesf2=Module["___nesf2"]=wasmExports["__nesf2"])(a0,a1);var ___gtsf2=Module["___gtsf2"]=(a0,a1)=>(___gtsf2=Module["___gtsf2"]=wasmExports["__gtsf2"])(a0,a1);var ___ctzdi2=Module["___ctzdi2"]=a0=>(___ctzdi2=Module["___ctzdi2"]=wasmExports["__ctzdi2"])(a0);var ___ctzsi2=Module["___ctzsi2"]=a0=>(___ctzsi2=Module["___ctzsi2"]=wasmExports["__ctzsi2"])(a0);var ___ctzti2=Module["___ctzti2"]=(a0,a1)=>(___ctzti2=Module["___ctzti2"]=wasmExports["__ctzti2"])(a0,a1);var ___divdc3=Module["___divdc3"]=(a0,a1,a2,a3,a4)=>(___divdc3=Module["___divdc3"]=wasmExports["__divdc3"])(a0,a1,a2,a3,a4);var ___divdf3=Module["___divdf3"]=(a0,a1)=>(___divdf3=Module["___divdf3"]=wasmExports["__divdf3"])(a0,a1);var ___divdi3=Module["___divdi3"]=(a0,a1)=>(___divdi3=Module["___divdi3"]=wasmExports["__divdi3"])(a0,a1);var ___udivmoddi4=Module["___udivmoddi4"]=(a0,a1,a2)=>(___udivmoddi4=Module["___udivmoddi4"]=wasmExports["__udivmoddi4"])(a0,a1,a2);var ___divmoddi4=Module["___divmoddi4"]=(a0,a1,a2)=>(___divmoddi4=Module["___divmoddi4"]=wasmExports["__divmoddi4"])(a0,a1,a2);var ___divmodsi4=Module["___divmodsi4"]=(a0,a1,a2)=>(___divmodsi4=Module["___divmodsi4"]=wasmExports["__divmodsi4"])(a0,a1,a2);var ___udivmodsi4=Module["___udivmodsi4"]=(a0,a1,a2)=>(___udivmodsi4=Module["___udivmodsi4"]=wasmExports["__udivmodsi4"])(a0,a1,a2);var ___divmodti4=Module["___divmodti4"]=(a0,a1,a2,a3,a4,a5)=>(___divmodti4=Module["___divmodti4"]=wasmExports["__divmodti4"])(a0,a1,a2,a3,a4,a5);var ___udivmodti4=Module["___udivmodti4"]=(a0,a1,a2,a3,a4,a5)=>(___udivmodti4=Module["___udivmodti4"]=wasmExports["__udivmodti4"])(a0,a1,a2,a3,a4,a5);var ___divsc3=Module["___divsc3"]=(a0,a1,a2,a3,a4)=>(___divsc3=Module["___divsc3"]=wasmExports["__divsc3"])(a0,a1,a2,a3,a4);var ___divsf3=Module["___divsf3"]=(a0,a1)=>(___divsf3=Module["___divsf3"]=wasmExports["__divsf3"])(a0,a1);var ___divsi3=Module["___divsi3"]=(a0,a1)=>(___divsi3=Module["___divsi3"]=wasmExports["__divsi3"])(a0,a1);var ___divtc3=Module["___divtc3"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(___divtc3=Module["___divtc3"]=wasmExports["__divtc3"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var ___divti3=Module["___divti3"]=(a0,a1,a2,a3,a4)=>(___divti3=Module["___divti3"]=wasmExports["__divti3"])(a0,a1,a2,a3,a4);var _setThrew=(a0,a1)=>(_setThrew=wasmExports["setThrew"])(a0,a1);var ___wasm_setjmp=Module["___wasm_setjmp"]=(a0,a1,a2)=>(___wasm_setjmp=Module["___wasm_setjmp"]=wasmExports["__wasm_setjmp"])(a0,a1,a2);var ___wasm_setjmp_test=Module["___wasm_setjmp_test"]=(a0,a1)=>(___wasm_setjmp_test=Module["___wasm_setjmp_test"]=wasmExports["__wasm_setjmp_test"])(a0,a1);var _emscripten_longjmp=Module["_emscripten_longjmp"]=(a0,a1)=>(_emscripten_longjmp=Module["_emscripten_longjmp"]=wasmExports["emscripten_longjmp"])(a0,a1);var __emscripten_tempret_set=a0=>(__emscripten_tempret_set=wasmExports["_emscripten_tempret_set"])(a0);var __emscripten_tempret_get=()=>(__emscripten_tempret_get=wasmExports["_emscripten_tempret_get"])();var ___get_temp_ret=Module["___get_temp_ret"]=()=>(___get_temp_ret=Module["___get_temp_ret"]=wasmExports["__get_temp_ret"])();var ___set_temp_ret=Module["___set_temp_ret"]=a0=>(___set_temp_ret=Module["___set_temp_ret"]=wasmExports["__set_temp_ret"])(a0);var _getTempRet0=Module["_getTempRet0"]=()=>(_getTempRet0=Module["_getTempRet0"]=wasmExports["getTempRet0"])();var _setTempRet0=Module["_setTempRet0"]=a0=>(_setTempRet0=Module["_setTempRet0"]=wasmExports["setTempRet0"])(a0);var ___emutls_get_address=Module["___emutls_get_address"]=a0=>(___emutls_get_address=Module["___emutls_get_address"]=wasmExports["__emutls_get_address"])(a0);var ___enable_execute_stack=Module["___enable_execute_stack"]=a0=>(___enable_execute_stack=Module["___enable_execute_stack"]=wasmExports["__enable_execute_stack"])(a0);var ___extendhfsf2=Module["___extendhfsf2"]=a0=>(___extendhfsf2=Module["___extendhfsf2"]=wasmExports["__extendhfsf2"])(a0);var ___gnu_h2f_ieee=Module["___gnu_h2f_ieee"]=a0=>(___gnu_h2f_ieee=Module["___gnu_h2f_ieee"]=wasmExports["__gnu_h2f_ieee"])(a0);var ___extendsfdf2=Module["___extendsfdf2"]=a0=>(___extendsfdf2=Module["___extendsfdf2"]=wasmExports["__extendsfdf2"])(a0);var ___ffsdi2=Module["___ffsdi2"]=a0=>(___ffsdi2=Module["___ffsdi2"]=wasmExports["__ffsdi2"])(a0);var ___ffssi2=Module["___ffssi2"]=a0=>(___ffssi2=Module["___ffssi2"]=wasmExports["__ffssi2"])(a0);var ___ffsti2=Module["___ffsti2"]=(a0,a1)=>(___ffsti2=Module["___ffsti2"]=wasmExports["__ffsti2"])(a0,a1);var ___fixdfdi=Module["___fixdfdi"]=a0=>(___fixdfdi=Module["___fixdfdi"]=wasmExports["__fixdfdi"])(a0);var ___fixunsdfdi=Module["___fixunsdfdi"]=a0=>(___fixunsdfdi=Module["___fixunsdfdi"]=wasmExports["__fixunsdfdi"])(a0);var ___fixdfsi=Module["___fixdfsi"]=a0=>(___fixdfsi=Module["___fixdfsi"]=wasmExports["__fixdfsi"])(a0);var ___fixdfti=Module["___fixdfti"]=(a0,a1)=>(___fixdfti=Module["___fixdfti"]=wasmExports["__fixdfti"])(a0,a1);var ___fixsfdi=Module["___fixsfdi"]=a0=>(___fixsfdi=Module["___fixsfdi"]=wasmExports["__fixsfdi"])(a0);var ___fixunssfdi=Module["___fixunssfdi"]=a0=>(___fixunssfdi=Module["___fixunssfdi"]=wasmExports["__fixunssfdi"])(a0);var ___fixsfsi=Module["___fixsfsi"]=a0=>(___fixsfsi=Module["___fixsfsi"]=wasmExports["__fixsfsi"])(a0);var ___fixsfti=Module["___fixsfti"]=(a0,a1)=>(___fixsfti=Module["___fixsfti"]=wasmExports["__fixsfti"])(a0,a1);var ___fixtfti=Module["___fixtfti"]=(a0,a1,a2)=>(___fixtfti=Module["___fixtfti"]=wasmExports["__fixtfti"])(a0,a1,a2);var ___fixunsdfsi=Module["___fixunsdfsi"]=a0=>(___fixunsdfsi=Module["___fixunsdfsi"]=wasmExports["__fixunsdfsi"])(a0);var ___fixunsdfti=Module["___fixunsdfti"]=(a0,a1)=>(___fixunsdfti=Module["___fixunsdfti"]=wasmExports["__fixunsdfti"])(a0,a1);var ___fixunssfsi=Module["___fixunssfsi"]=a0=>(___fixunssfsi=Module["___fixunssfsi"]=wasmExports["__fixunssfsi"])(a0);var ___fixunssfti=Module["___fixunssfti"]=(a0,a1)=>(___fixunssfti=Module["___fixunssfti"]=wasmExports["__fixunssfti"])(a0,a1);var ___fixunstfdi=Module["___fixunstfdi"]=(a0,a1)=>(___fixunstfdi=Module["___fixunstfdi"]=wasmExports["__fixunstfdi"])(a0,a1);var ___fixunstfsi=Module["___fixunstfsi"]=(a0,a1)=>(___fixunstfsi=Module["___fixunstfsi"]=wasmExports["__fixunstfsi"])(a0,a1);var ___fixunstfti=Module["___fixunstfti"]=(a0,a1,a2)=>(___fixunstfti=Module["___fixunstfti"]=wasmExports["__fixunstfti"])(a0,a1,a2);var ___floatdidf=Module["___floatdidf"]=a0=>(___floatdidf=Module["___floatdidf"]=wasmExports["__floatdidf"])(a0);var ___floatdisf=Module["___floatdisf"]=a0=>(___floatdisf=Module["___floatdisf"]=wasmExports["__floatdisf"])(a0);var ___floatditf=Module["___floatditf"]=(a0,a1)=>(___floatditf=Module["___floatditf"]=wasmExports["__floatditf"])(a0,a1);var ___floatsidf=Module["___floatsidf"]=a0=>(___floatsidf=Module["___floatsidf"]=wasmExports["__floatsidf"])(a0);var ___floatsisf=Module["___floatsisf"]=a0=>(___floatsisf=Module["___floatsisf"]=wasmExports["__floatsisf"])(a0);var ___floattidf=Module["___floattidf"]=(a0,a1)=>(___floattidf=Module["___floattidf"]=wasmExports["__floattidf"])(a0,a1);var ___floattisf=Module["___floattisf"]=(a0,a1)=>(___floattisf=Module["___floattisf"]=wasmExports["__floattisf"])(a0,a1);var ___floattitf=Module["___floattitf"]=(a0,a1,a2)=>(___floattitf=Module["___floattitf"]=wasmExports["__floattitf"])(a0,a1,a2);var ___floatundidf=Module["___floatundidf"]=a0=>(___floatundidf=Module["___floatundidf"]=wasmExports["__floatundidf"])(a0);var ___floatundisf=Module["___floatundisf"]=a0=>(___floatundisf=Module["___floatundisf"]=wasmExports["__floatundisf"])(a0);var ___floatunditf=Module["___floatunditf"]=(a0,a1)=>(___floatunditf=Module["___floatunditf"]=wasmExports["__floatunditf"])(a0,a1);var ___floatunsidf=Module["___floatunsidf"]=a0=>(___floatunsidf=Module["___floatunsidf"]=wasmExports["__floatunsidf"])(a0);var ___floatunsisf=Module["___floatunsisf"]=a0=>(___floatunsisf=Module["___floatunsisf"]=wasmExports["__floatunsisf"])(a0);var ___floatuntidf=Module["___floatuntidf"]=(a0,a1)=>(___floatuntidf=Module["___floatuntidf"]=wasmExports["__floatuntidf"])(a0,a1);var ___floatuntisf=Module["___floatuntisf"]=(a0,a1)=>(___floatuntisf=Module["___floatuntisf"]=wasmExports["__floatuntisf"])(a0,a1);var ___floatuntitf=Module["___floatuntitf"]=(a0,a1,a2)=>(___floatuntitf=Module["___floatuntitf"]=wasmExports["__floatuntitf"])(a0,a1,a2);var ___lshrdi3=Module["___lshrdi3"]=(a0,a1)=>(___lshrdi3=Module["___lshrdi3"]=wasmExports["__lshrdi3"])(a0,a1);var ___moddi3=Module["___moddi3"]=(a0,a1)=>(___moddi3=Module["___moddi3"]=wasmExports["__moddi3"])(a0,a1);var ___modsi3=Module["___modsi3"]=(a0,a1)=>(___modsi3=Module["___modsi3"]=wasmExports["__modsi3"])(a0,a1);var ___modti3=Module["___modti3"]=(a0,a1,a2,a3,a4)=>(___modti3=Module["___modti3"]=wasmExports["__modti3"])(a0,a1,a2,a3,a4);var ___muldf3=Module["___muldf3"]=(a0,a1)=>(___muldf3=Module["___muldf3"]=wasmExports["__muldf3"])(a0,a1);var ___muldi3=Module["___muldi3"]=(a0,a1)=>(___muldi3=Module["___muldi3"]=wasmExports["__muldi3"])(a0,a1);var ___mulodi4=Module["___mulodi4"]=(a0,a1,a2)=>(___mulodi4=Module["___mulodi4"]=wasmExports["__mulodi4"])(a0,a1,a2);var ___mulosi4=Module["___mulosi4"]=(a0,a1,a2)=>(___mulosi4=Module["___mulosi4"]=wasmExports["__mulosi4"])(a0,a1,a2);var ___muloti4=Module["___muloti4"]=(a0,a1,a2,a3,a4,a5)=>(___muloti4=Module["___muloti4"]=wasmExports["__muloti4"])(a0,a1,a2,a3,a4,a5);var ___udivti3=Module["___udivti3"]=(a0,a1,a2,a3,a4)=>(___udivti3=Module["___udivti3"]=wasmExports["__udivti3"])(a0,a1,a2,a3,a4);var ___mulsf3=Module["___mulsf3"]=(a0,a1)=>(___mulsf3=Module["___mulsf3"]=wasmExports["__mulsf3"])(a0,a1);var ___mulvdi3=Module["___mulvdi3"]=(a0,a1)=>(___mulvdi3=Module["___mulvdi3"]=wasmExports["__mulvdi3"])(a0,a1);var ___mulvsi3=Module["___mulvsi3"]=(a0,a1)=>(___mulvsi3=Module["___mulvsi3"]=wasmExports["__mulvsi3"])(a0,a1);var ___mulvti3=Module["___mulvti3"]=(a0,a1,a2,a3,a4)=>(___mulvti3=Module["___mulvti3"]=wasmExports["__mulvti3"])(a0,a1,a2,a3,a4);var ___negdf2=Module["___negdf2"]=a0=>(___negdf2=Module["___negdf2"]=wasmExports["__negdf2"])(a0);var ___negdi2=Module["___negdi2"]=a0=>(___negdi2=Module["___negdi2"]=wasmExports["__negdi2"])(a0);var ___negsf2=Module["___negsf2"]=a0=>(___negsf2=Module["___negsf2"]=wasmExports["__negsf2"])(a0);var ___negti2=Module["___negti2"]=(a0,a1,a2)=>(___negti2=Module["___negti2"]=wasmExports["__negti2"])(a0,a1,a2);var ___negvdi2=Module["___negvdi2"]=a0=>(___negvdi2=Module["___negvdi2"]=wasmExports["__negvdi2"])(a0);var ___negvsi2=Module["___negvsi2"]=a0=>(___negvsi2=Module["___negvsi2"]=wasmExports["__negvsi2"])(a0);var ___negvti2=Module["___negvti2"]=(a0,a1,a2)=>(___negvti2=Module["___negvti2"]=wasmExports["__negvti2"])(a0,a1,a2);var ___paritydi2=Module["___paritydi2"]=a0=>(___paritydi2=Module["___paritydi2"]=wasmExports["__paritydi2"])(a0);var ___paritysi2=Module["___paritysi2"]=a0=>(___paritysi2=Module["___paritysi2"]=wasmExports["__paritysi2"])(a0);var ___parityti2=Module["___parityti2"]=(a0,a1)=>(___parityti2=Module["___parityti2"]=wasmExports["__parityti2"])(a0,a1);var ___popcountdi2=Module["___popcountdi2"]=a0=>(___popcountdi2=Module["___popcountdi2"]=wasmExports["__popcountdi2"])(a0);var ___popcountsi2=Module["___popcountsi2"]=a0=>(___popcountsi2=Module["___popcountsi2"]=wasmExports["__popcountsi2"])(a0);var ___popcountti2=Module["___popcountti2"]=(a0,a1)=>(___popcountti2=Module["___popcountti2"]=wasmExports["__popcountti2"])(a0,a1);var ___powidf2=Module["___powidf2"]=(a0,a1)=>(___powidf2=Module["___powidf2"]=wasmExports["__powidf2"])(a0,a1);var ___powisf2=Module["___powisf2"]=(a0,a1)=>(___powisf2=Module["___powisf2"]=wasmExports["__powisf2"])(a0,a1);var ___powitf2=Module["___powitf2"]=(a0,a1,a2,a3)=>(___powitf2=Module["___powitf2"]=wasmExports["__powitf2"])(a0,a1,a2,a3);var _emscripten_stack_init=Module["_emscripten_stack_init"]=()=>(_emscripten_stack_init=Module["_emscripten_stack_init"]=wasmExports["emscripten_stack_init"])();var _emscripten_stack_set_limits=Module["_emscripten_stack_set_limits"]=(a0,a1)=>(_emscripten_stack_set_limits=Module["_emscripten_stack_set_limits"]=wasmExports["emscripten_stack_set_limits"])(a0,a1);var _emscripten_stack_get_free=Module["_emscripten_stack_get_free"]=()=>(_emscripten_stack_get_free=Module["_emscripten_stack_get_free"]=wasmExports["emscripten_stack_get_free"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["_emscripten_stack_restore"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["_emscripten_stack_alloc"])(a0);var ___subdf3=Module["___subdf3"]=(a0,a1)=>(___subdf3=Module["___subdf3"]=wasmExports["__subdf3"])(a0,a1);var ___subsf3=Module["___subsf3"]=(a0,a1)=>(___subsf3=Module["___subsf3"]=wasmExports["__subsf3"])(a0,a1);var ___subvdi3=Module["___subvdi3"]=(a0,a1)=>(___subvdi3=Module["___subvdi3"]=wasmExports["__subvdi3"])(a0,a1);var ___subvsi3=Module["___subvsi3"]=(a0,a1)=>(___subvsi3=Module["___subvsi3"]=wasmExports["__subvsi3"])(a0,a1);var ___subvti3=Module["___subvti3"]=(a0,a1,a2,a3,a4)=>(___subvti3=Module["___subvti3"]=wasmExports["__subvti3"])(a0,a1,a2,a3,a4);var ___truncdfhf2=Module["___truncdfhf2"]=a0=>(___truncdfhf2=Module["___truncdfhf2"]=wasmExports["__truncdfhf2"])(a0);var ___truncdfsf2=Module["___truncdfsf2"]=a0=>(___truncdfsf2=Module["___truncdfsf2"]=wasmExports["__truncdfsf2"])(a0);var ___truncsfhf2=Module["___truncsfhf2"]=a0=>(___truncsfhf2=Module["___truncsfhf2"]=wasmExports["__truncsfhf2"])(a0);var ___gnu_f2h_ieee=Module["___gnu_f2h_ieee"]=a0=>(___gnu_f2h_ieee=Module["___gnu_f2h_ieee"]=wasmExports["__gnu_f2h_ieee"])(a0);var ___ucmpdi2=Module["___ucmpdi2"]=(a0,a1)=>(___ucmpdi2=Module["___ucmpdi2"]=wasmExports["__ucmpdi2"])(a0,a1);var ___ucmpti2=Module["___ucmpti2"]=(a0,a1,a2,a3)=>(___ucmpti2=Module["___ucmpti2"]=wasmExports["__ucmpti2"])(a0,a1,a2,a3);var ___udivdi3=Module["___udivdi3"]=(a0,a1)=>(___udivdi3=Module["___udivdi3"]=wasmExports["__udivdi3"])(a0,a1);var ___udivsi3=Module["___udivsi3"]=(a0,a1)=>(___udivsi3=Module["___udivsi3"]=wasmExports["__udivsi3"])(a0,a1);var ___umoddi3=Module["___umoddi3"]=(a0,a1)=>(___umoddi3=Module["___umoddi3"]=wasmExports["__umoddi3"])(a0,a1);var ___umodsi3=Module["___umodsi3"]=(a0,a1)=>(___umodsi3=Module["___umodsi3"]=wasmExports["__umodsi3"])(a0,a1);var ___umodti3=Module["___umodti3"]=(a0,a1,a2,a3,a4)=>(___umodti3=Module["___umodti3"]=wasmExports["__umodti3"])(a0,a1,a2,a3,a4);var ___cxa_allocate_exception=Module["___cxa_allocate_exception"]=a0=>(___cxa_allocate_exception=Module["___cxa_allocate_exception"]=wasmExports["__cxa_allocate_exception"])(a0);var ___cxa_free_exception=a0=>(___cxa_free_exception=wasmExports["__cxa_free_exception"])(a0);var ___cxa_pure_virtual=Module["___cxa_pure_virtual"]=()=>(___cxa_pure_virtual=Module["___cxa_pure_virtual"]=wasmExports["__cxa_pure_virtual"])();var ___cxa_decrement_exception_refcount=a0=>(___cxa_decrement_exception_refcount=wasmExports["__cxa_decrement_exception_refcount"])(a0);var ___cxa_increment_exception_refcount=a0=>(___cxa_increment_exception_refcount=wasmExports["__cxa_increment_exception_refcount"])(a0);var ___cxa_init_primary_exception=Module["___cxa_init_primary_exception"]=(a0,a1,a2)=>(___cxa_init_primary_exception=Module["___cxa_init_primary_exception"]=wasmExports["__cxa_init_primary_exception"])(a0,a1,a2);var ___dynamic_cast=Module["___dynamic_cast"]=(a0,a1,a2,a3)=>(___dynamic_cast=Module["___dynamic_cast"]=wasmExports["__dynamic_cast"])(a0,a1,a2,a3);var ___cxa_bad_cast=Module["___cxa_bad_cast"]=()=>(___cxa_bad_cast=Module["___cxa_bad_cast"]=wasmExports["__cxa_bad_cast"])();var ___cxa_bad_typeid=Module["___cxa_bad_typeid"]=()=>(___cxa_bad_typeid=Module["___cxa_bad_typeid"]=wasmExports["__cxa_bad_typeid"])();var ___cxa_throw_bad_array_new_length=Module["___cxa_throw_bad_array_new_length"]=()=>(___cxa_throw_bad_array_new_length=Module["___cxa_throw_bad_array_new_length"]=wasmExports["__cxa_throw_bad_array_new_length"])();var ___cxa_demangle=(a0,a1,a2,a3)=>(___cxa_demangle=wasmExports["__cxa_demangle"])(a0,a1,a2,a3);var ___gxx_personality_v0=Module["___gxx_personality_v0"]=(a0,a1,a2,a3,a4)=>(___gxx_personality_v0=Module["___gxx_personality_v0"]=wasmExports["__gxx_personality_v0"])(a0,a1,a2,a3,a4);var ___thrown_object_from_unwind_exception=Module["___thrown_object_from_unwind_exception"]=a0=>(___thrown_object_from_unwind_exception=Module["___thrown_object_from_unwind_exception"]=wasmExports["__thrown_object_from_unwind_exception"])(a0);var ___get_exception_message=(a0,a1,a2)=>(___get_exception_message=wasmExports["__get_exception_message"])(a0,a1,a2);var ___get_exception_terminate_message=Module["___get_exception_terminate_message"]=a0=>(___get_exception_terminate_message=Module["___get_exception_terminate_message"]=wasmExports["__get_exception_terminate_message"])(a0);var ___cxa_guard_acquire=Module["___cxa_guard_acquire"]=a0=>(___cxa_guard_acquire=Module["___cxa_guard_acquire"]=wasmExports["__cxa_guard_acquire"])(a0);var ___cxa_guard_release=Module["___cxa_guard_release"]=a0=>(___cxa_guard_release=Module["___cxa_guard_release"]=wasmExports["__cxa_guard_release"])(a0);var ___cxa_guard_abort=Module["___cxa_guard_abort"]=a0=>(___cxa_guard_abort=Module["___cxa_guard_abort"]=wasmExports["__cxa_guard_abort"])(a0);var ___cxa_thread_atexit=Module["___cxa_thread_atexit"]=(a0,a1,a2)=>(___cxa_thread_atexit=Module["___cxa_thread_atexit"]=wasmExports["__cxa_thread_atexit"])(a0,a1,a2);var ___cxa_deleted_virtual=Module["___cxa_deleted_virtual"]=()=>(___cxa_deleted_virtual=Module["___cxa_deleted_virtual"]=wasmExports["__cxa_deleted_virtual"])();var ___cxa_can_catch=(a0,a1,a2)=>(___cxa_can_catch=wasmExports["__cxa_can_catch"])(a0,a1,a2);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["__cxa_is_pointer_type"])(a0);var _gethostbyaddr_r=Module["_gethostbyaddr_r"]=(a0,a1,a2,a3,a4,a5,a6,a7)=>(_gethostbyaddr_r=Module["_gethostbyaddr_r"]=wasmExports["gethostbyaddr_r"])(a0,a1,a2,a3,a4,a5,a6,a7);var _gethostbyname2=Module["_gethostbyname2"]=(a0,a1)=>(_gethostbyname2=Module["_gethostbyname2"]=wasmExports["gethostbyname2"])(a0,a1);var _gethostbyname2_r=Module["_gethostbyname2_r"]=(a0,a1,a2,a3,a4,a5,a6)=>(_gethostbyname2_r=Module["_gethostbyname2_r"]=wasmExports["gethostbyname2_r"])(a0,a1,a2,a3,a4,a5,a6);var _gethostbyname_r=Module["_gethostbyname_r"]=(a0,a1,a2,a3,a4,a5)=>(_gethostbyname_r=Module["_gethostbyname_r"]=wasmExports["gethostbyname_r"])(a0,a1,a2,a3,a4,a5);var _shutdown=Module["_shutdown"]=(a0,a1)=>(_shutdown=Module["_shutdown"]=wasmExports["shutdown"])(a0,a1);var _socketpair=Module["_socketpair"]=(a0,a1,a2,a3)=>(_socketpair=Module["_socketpair"]=wasmExports["socketpair"])(a0,a1,a2,a3);var _py_docstring_mod=Module["_py_docstring_mod"]=4580544;var _PyExc_AttributeError=Module["_PyExc_AttributeError"]=3194552;var _stdout=Module["_stdout"]=4429104;var _PyExc_ModuleNotFoundError=Module["_PyExc_ModuleNotFoundError"]=3189676;var __Py_NoneStruct=Module["__Py_NoneStruct"]=3221384;var _internal_error=Module["_internal_error"]=4580552;var _conversion_error=Module["_conversion_error"]=4580556;var _PyExc_ImportError=Module["_PyExc_ImportError"]=3189464;var _pyodide_export_=Module["_pyodide_export_"]=3171360;var _py_version_major_=Module["_py_version_major_"]=3171364;var _set_new_cframe_=Module["_set_new_cframe_"]=3171368;var __Py_TrueStruct=Module["__Py_TrueStruct"]=3175940;var __Py_FalseStruct=Module["__Py_FalseStruct"]=3175956;var _jsbind=Module["_jsbind"]=4580612;var _PyExc_TypeError=Module["_PyExc_TypeError"]=3187976;var _Jsr_undefined=Module["_Jsr_undefined"]=255184;var _PyExc_StopIteration=Module["_PyExc_StopIteration"]=3188400;var _PyTraceBack_Type=Module["_PyTraceBack_Type"]=3722844;var _PyExc_GeneratorExit=Module["_PyExc_GeneratorExit"]=3188612;var _PyExc_StopAsyncIteration=Module["_PyExc_StopAsyncIteration"]=3188188;var _PyExc_RuntimeError=Module["_PyExc_RuntimeError"]=3193492;var _PyExc_IndexError=Module["_PyExc_IndexError"]=3195612;var _PyExc_Exception=Module["_PyExc_Exception"]=3187764;var _PyExc_BaseException=Module["_PyExc_BaseException"]=3187552;var _methods=Module["_methods"]=3172592;var _PyExc_SystemError=Module["_PyExc_SystemError"]=3198152;var _PyExc_KeyError=Module["_PyExc_KeyError"]=3195824;var _PySlice_Type=Module["_PySlice_Type"]=3226288;var _PyLong_Type=Module["_PyLong_Type"]=3211952;var _PyBool_Type=Module["_PyBool_Type"]=3176116;var _PyExc_ValueError=Module["_PyExc_ValueError"]=3188832;var _PyExc_NotImplementedError=Module["_PyExc_NotImplementedError"]=3193916;var _PyBaseObject_Type=Module["_PyBaseObject_Type"]=3228312;var _PyExc_OverflowError=Module["_PyExc_OverflowError"]=3197728;var _PyList_Type=Module["_PyList_Type"]=3210800;var _PyTuple_Type=Module["_PyTuple_Type"]=3226640;var __Py_NotImplementedStruct=Module["__Py_NotImplementedStruct"]=3222160;var _default_signature=Module["_default_signature"]=4580620;var _no_default=Module["_no_default"]=4580616;var _PyCoro_Type=Module["_PyCoro_Type"]=3204784;var _PyGen_Type=Module["_PyGen_Type"]=3204576;var _PyDict_Type=Module["_PyDict_Type"]=3213240;var _compat_to_string_repr=Module["_compat_to_string_repr"]=4580636;var _PyMethod_Type=Module["_PyMethod_Type"]=3181048;var _PyFunction_Type=Module["_PyFunction_Type"]=3208300;var _py_buffer_len_offset=Module["_py_buffer_len_offset"]=3174680;var _py_buffer_shape_offset=Module["_py_buffer_shape_offset"]=3174684;var _Jsr_true=Module["_Jsr_true"]=255188;var _Jsr_false=Module["_Jsr_false"]=255192;var _Jsr_novalue=Module["_Jsr_novalue"]=255196;var _PySet_Type=Module["_PySet_Type"]=3224912;var _PyFloat_Type=Module["_PyFloat_Type"]=3207040;var _threadstate_freelist_len=Module["_threadstate_freelist_len"]=4580712;var _threadstate_freelist=Module["_threadstate_freelist"]=4580672;var _size_of_cframe=Module["_size_of_cframe"]=3175244;var __PyParser_TokenNames=Module["__PyParser_TokenNames"]=3175248;var _PyExc_SyntaxError=Module["_PyExc_SyntaxError"]=3194764;var _PyExc_LookupError=Module["_PyExc_LookupError"]=3195400;var _PyExc_UnicodeDecodeError=Module["_PyExc_UnicodeDecodeError"]=3196668;var _PyExc_IndentationError=Module["_PyExc_IndentationError"]=3194976;var _PyExc_KeyboardInterrupt=Module["_PyExc_KeyboardInterrupt"]=3189252;var _PyExc_TabError=Module["_PyExc_TabError"]=3195188;var _PyExc_UnicodeError=Module["_PyExc_UnicodeError"]=3196244;var _stdin=Module["_stdin"]=4428952;var _PyExc_MemoryError=Module["_PyExc_MemoryError"]=3198368;var __PyRuntime=Module["__PyRuntime"]=3248360;var _PyComplex_Type=Module["_PyComplex_Type"]=3183164;var _PyBytes_Type=Module["_PyBytes_Type"]=3178520;var _PyUnicode_Type=Module["_PyUnicode_Type"]=3234880;var __Py_EllipsisObject=Module["__Py_EllipsisObject"]=3226144;var __Py_ctype_table=Module["__Py_ctype_table"]=456608;var _PyExc_DeprecationWarning=Module["_PyExc_DeprecationWarning"]=3199424;var _PyExc_SyntaxWarning=Module["_PyExc_SyntaxWarning"]=3199848;var __PyOS_ReadlineTState=Module["__PyOS_ReadlineTState"]=4580772;var _stderr=Module["_stderr"]=4428800;var _PyOS_InputHook=Module["_PyOS_InputHook"]=4580776;var _PyOS_ReadlineFunctionPointer=Module["_PyOS_ReadlineFunctionPointer"]=4580780;var _PyExc_OSError=Module["_PyExc_OSError"]=3189888;var _PyType_Type=Module["_PyType_Type"]=3227264;var _PyExc_BufferError=Module["_PyExc_BufferError"]=3198788;var _PyCFunction_Type=Module["_PyCFunction_Type"]=3220052;var _PyByteArray_Type=Module["_PyByteArray_Type"]=3176324;var __PyByteArray_empty_string=Module["__PyByteArray_empty_string"]=4580788;var __Py_ctype_tolower=Module["__Py_ctype_tolower"]=457632;var __Py_ctype_toupper=Module["__Py_ctype_toupper"]=457888;var _Py_hexdigits=Module["_Py_hexdigits"]=3243880;var _PyExc_BytesWarning=Module["_PyExc_BytesWarning"]=3200908;var _PyByteArrayIter_Type=Module["_PyByteArrayIter_Type"]=3177680;var __PyLong_DigitValue=Module["__PyLong_DigitValue"]=3212160;var _PyBytesIter_Type=Module["_PyBytesIter_Type"]=3179728;var _PyModule_Type=Module["_PyModule_Type"]=3220680;var _PyCapsule_Type=Module["_PyCapsule_Type"]=3180592;var _PyCell_Type=Module["_PyCell_Type"]=3180800;var _PyInstanceMethod_Type=Module["_PyInstanceMethod_Type"]=3181400;var _PyCode_Type=Module["_PyCode_Type"]=3181704;var _PyFrozenSet_Type=Module["_PyFrozenSet_Type"]=3225472;var _PyExc_ZeroDivisionError=Module["_PyExc_ZeroDivisionError"]=3197940;var __PyMethodWrapper_Type=Module["__PyMethodWrapper_Type"]=3185576;var _PyMethodDescr_Type=Module["_PyMethodDescr_Type"]=3183920;var _PyClassMethodDescr_Type=Module["_PyClassMethodDescr_Type"]=3184128;var _PyMemberDescr_Type=Module["_PyMemberDescr_Type"]=3184396;var _PyGetSetDescr_Type=Module["_PyGetSetDescr_Type"]=3184668;var _PyWrapperDescr_Type=Module["_PyWrapperDescr_Type"]=3184960;var _PyDictProxy_Type=Module["_PyDictProxy_Type"]=3185168;var _PyProperty_Type=Module["_PyProperty_Type"]=3186344;var _PyReversed_Type=Module["_PyReversed_Type"]=3187056;var _PyEnum_Type=Module["_PyEnum_Type"]=3186784;var _PyExc_BaseExceptionGroup=Module["_PyExc_BaseExceptionGroup"]=3188828;var _PyExc_UnicodeTranslateError=Module["_PyExc_UnicodeTranslateError"]=3196880;var _PyExc_BlockingIOError=Module["_PyExc_BlockingIOError"]=3190100;var _PyExc_BrokenPipeError=Module["_PyExc_BrokenPipeError"]=3190736;var _PyExc_ChildProcessError=Module["_PyExc_ChildProcessError"]=3190524;var _PyExc_ConnectionAbortedError=Module["_PyExc_ConnectionAbortedError"]=3190948;var _PyExc_ConnectionRefusedError=Module["_PyExc_ConnectionRefusedError"]=3191160;var _PyExc_ConnectionResetError=Module["_PyExc_ConnectionResetError"]=3191372;var _PyExc_FileExistsError=Module["_PyExc_FileExistsError"]=3191584;var _PyExc_FileNotFoundError=Module["_PyExc_FileNotFoundError"]=3191796;var _PyExc_IsADirectoryError=Module["_PyExc_IsADirectoryError"]=3192008;var _PyExc_NotADirectoryError=Module["_PyExc_NotADirectoryError"]=3192220;var _PyExc_InterruptedError=Module["_PyExc_InterruptedError"]=3192432;var _PyExc_PermissionError=Module["_PyExc_PermissionError"]=3192644;var _PyExc_ProcessLookupError=Module["_PyExc_ProcessLookupError"]=3192856;var _PyExc_TimeoutError=Module["_PyExc_TimeoutError"]=3193068;var _PyExc_EnvironmentError=Module["_PyExc_EnvironmentError"]=4580792;var _PyExc_IOError=Module["_PyExc_IOError"]=4580796;var _PyExc_SystemExit=Module["_PyExc_SystemExit"]=3188824;var _PyExc_ConnectionError=Module["_PyExc_ConnectionError"]=3190312;var _PyExc_EOFError=Module["_PyExc_EOFError"]=3193280;var _PyExc_RecursionError=Module["_PyExc_RecursionError"]=3193704;var _PyExc_NameError=Module["_PyExc_NameError"]=3194128;var _PyExc_UnboundLocalError=Module["_PyExc_UnboundLocalError"]=3194340;var _PyExc_UnicodeEncodeError=Module["_PyExc_UnicodeEncodeError"]=3196456;var _PyExc_AssertionError=Module["_PyExc_AssertionError"]=3197092;var _PyExc_ArithmeticError=Module["_PyExc_ArithmeticError"]=3197304;var _PyExc_FloatingPointError=Module["_PyExc_FloatingPointError"]=3197516;var _PyExc_ReferenceError=Module["_PyExc_ReferenceError"]=3198364;var _PyExc_Warning=Module["_PyExc_Warning"]=3199e3;var _PyExc_UserWarning=Module["_PyExc_UserWarning"]=3199212;var _PyExc_PendingDeprecationWarning=Module["_PyExc_PendingDeprecationWarning"]=3199636;var _PyExc_RuntimeWarning=Module["_PyExc_RuntimeWarning"]=3200060;var _PyExc_FutureWarning=Module["_PyExc_FutureWarning"]=3200272;var _PyExc_ImportWarning=Module["_PyExc_ImportWarning"]=3200484;var _PyExc_UnicodeWarning=Module["_PyExc_UnicodeWarning"]=3200696;var _PyExc_EncodingWarning=Module["_PyExc_EncodingWarning"]=3201120;var _PyExc_ResourceWarning=Module["_PyExc_ResourceWarning"]=3201332;var _Py_GenericAliasType=Module["_Py_GenericAliasType"]=3203852;var _PyAsyncGen_Type=Module["_PyAsyncGen_Type"]=3204112;var __PyAsyncGenWrappedValue_Type=Module["__PyAsyncGenWrappedValue_Type"]=3206160;var __PyCoroWrapper_Type=Module["__PyCoroWrapper_Type"]=3205360;var __PyAsyncGenASend_Type=Module["__PyAsyncGenASend_Type"]=3205952;var __PyAsyncGenAThrow_Type=Module["__PyAsyncGenAThrow_Type"]=3206448;var _PyStdPrinter_Type=Module["_PyStdPrinter_Type"]=3206656;var __Py_SwappedOp=Module["__Py_SwappedOp"]=3221392;var _PyFrame_Type=Module["_PyFrame_Type"]=3208072;var _PyClassMethod_Type=Module["_PyClassMethod_Type"]=3208956;var _PyStaticMethod_Type=Module["_PyStaticMethod_Type"]=3209292;var __PyInterpreterID_Type=Module["__PyInterpreterID_Type"]=3209780;var _PySeqIter_Type=Module["_PySeqIter_Type"]=321e4;var _PyCallIter_Type=Module["_PyCallIter_Type"]=3210272;var _PyListIter_Type=Module["_PyListIter_Type"]=3211392;var _PyListRevIter_Type=Module["_PyListRevIter_Type"]=3211664;var _PyDictIterKey_Type=Module["_PyDictIterKey_Type"]=3213968;var _PyDictRevIterKey_Type=Module["_PyDictRevIterKey_Type"]=3214592;var _PyDictRevIterValue_Type=Module["_PyDictRevIterValue_Type"]=3215008;var _PyDictKeys_Type=Module["_PyDictKeys_Type"]=3215216;var _PyDictItems_Type=Module["_PyDictItems_Type"]=3215424;var _PyDictIterItem_Type=Module["_PyDictIterItem_Type"]=3214384;var _PyDictIterValue_Type=Module["_PyDictIterValue_Type"]=3214176;var _PyDictRevIterItem_Type=Module["_PyDictRevIterItem_Type"]=3214800;var _PyDictValues_Type=Module["_PyDictValues_Type"]=3216080;var _PyODict_Type=Module["_PyODict_Type"]=3216776;var _PyODictIter_Type=Module["_PyODictIter_Type"]=3217024;var _PyODictKeys_Type=Module["_PyODictKeys_Type"]=3217264;var _PyODictValues_Type=Module["_PyODictValues_Type"]=3217744;var _PyODictItems_Type=Module["_PyODictItems_Type"]=3217504;var __PyManagedBuffer_Type=Module["__PyManagedBuffer_Type"]=3218344;var _PyMemoryView_Type=Module["_PyMemoryView_Type"]=3219252;var _PyCMethod_Type=Module["_PyCMethod_Type"]=3219844;var _PyModuleDef_Type=Module["_PyModuleDef_Type"]=3220472;var __PyNamespace_Type=Module["__PyNamespace_Type"]=3221176;var __PyNone_Type=Module["__PyNone_Type"]=3221560;var __PyNotImplemented_Type=Module["__PyNotImplemented_Type"]=3221952;var _PyContextToken_Type=Module["_PyContextToken_Type"]=3244464;var _PyContextVar_Type=Module["_PyContextVar_Type"]=3244256;var _PyContext_Type=Module["_PyContext_Type"]=3244048;var _PyEllipsis_Type=Module["_PyEllipsis_Type"]=3225936;var _PyFilter_Type=Module["_PyFilter_Type"]=3241600;var _PyLongRangeIter_Type=Module["_PyLongRangeIter_Type"]=3223904;var _PyMap_Type=Module["_PyMap_Type"]=3241840;var _PyPickleBuffer_Type=Module["_PyPickleBuffer_Type"]=3222728;var _PyRangeIter_Type=Module["_PyRangeIter_Type"]=3223632;var _PyRange_Type=Module["_PyRange_Type"]=3223360;var _PySetIter_Type=Module["_PySetIter_Type"]=3224160;var _PySuper_Type=Module["_PySuper_Type"]=3228816;var _PyTupleIter_Type=Module["_PyTupleIter_Type"]=3227056;var _PyUnicodeIter_Type=Module["_PyUnicodeIter_Type"]=3236800;var _PyZip_Type=Module["_PyZip_Type"]=3242096;var __PyBufferWrapper_Type=Module["__PyBufferWrapper_Type"]=3228528;var __PyWeakref_CallableProxyType=Module["__PyWeakref_CallableProxyType"]=3239264;var __PyWeakref_ProxyType=Module["__PyWeakref_ProxyType"]=3239056;var __PyWeakref_RefType=Module["__PyWeakref_RefType"]=3238600;var __PySet_Dummy=Module["__PySet_Dummy"]=3225688;var _PyStructSequence_UnnamedField=Module["_PyStructSequence_UnnamedField"]=3226516;var __Py_ascii_whitespace=Module["__Py_ascii_whitespace"]=308784;var _Py_Version=Module["_Py_Version"]=441460;var _PyImport_Inittab=Module["_PyImport_Inittab"]=3246992;var __PyImport_FrozenBootstrap=Module["__PyImport_FrozenBootstrap"]=4423776;var _PyImport_FrozenModules=Module["_PyImport_FrozenModules"]=4592792;var __PyImport_FrozenStdlib=Module["__PyImport_FrozenStdlib"]=4424112;var __PyImport_FrozenTest=Module["__PyImport_FrozenTest"]=4424368;var _Py_IgnoreEnvironmentFlag=Module["_Py_IgnoreEnvironmentFlag"]=4582604;var _Py_IsolatedFlag=Module["_Py_IsolatedFlag"]=4582624;var _Py_BytesWarningFlag=Module["_Py_BytesWarningFlag"]=4582596;var _Py_InspectFlag=Module["_Py_InspectFlag"]=4582584;var _Py_InteractiveFlag=Module["_Py_InteractiveFlag"]=4582580;var _Py_OptimizeFlag=Module["_Py_OptimizeFlag"]=4582588;var _Py_DebugFlag=Module["_Py_DebugFlag"]=4582568;var _Py_VerboseFlag=Module["_Py_VerboseFlag"]=4582572;var _Py_QuietFlag=Module["_Py_QuietFlag"]=4582576;var _Py_FrozenFlag=Module["_Py_FrozenFlag"]=4582600;var _Py_UnbufferedStdioFlag=Module["_Py_UnbufferedStdioFlag"]=4582616;var _Py_NoSiteFlag=Module["_Py_NoSiteFlag"]=4582592;var _Py_DontWriteBytecodeFlag=Module["_Py_DontWriteBytecodeFlag"]=4582608;var _Py_NoUserSiteDirectory=Module["_Py_NoUserSiteDirectory"]=4582612;var _Py_HashRandomizationFlag=Module["_Py_HashRandomizationFlag"]=4582620;var _Py_FileSystemDefaultEncoding=Module["_Py_FileSystemDefaultEncoding"]=4582672;var _Py_HasFileSystemDefaultEncoding=Module["_Py_HasFileSystemDefaultEncoding"]=4582676;var _Py_FileSystemDefaultEncodeErrors=Module["_Py_FileSystemDefaultEncodeErrors"]=4582680;var __Py_HasFileSystemDefaultEncodeErrors=Module["__Py_HasFileSystemDefaultEncodeErrors"]=4582684;var _Py_UTF8Mode=Module["_Py_UTF8Mode"]=4582564;var __Py_HashSecret=Module["__Py_HashSecret"]=4582688;var _Py_EMSCRIPTEN_SIGNAL_HANDLING=Module["_Py_EMSCRIPTEN_SIGNAL_HANDLING"]=4583804;var __PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET=Module["__PyEM_EMSCRIPTEN_COUNT_ARGS_OFFSET"]=472248;var _ffi_type_pointer=Module["_ffi_type_pointer"]=2818724;var _ffi_type_void=Module["_ffi_type_void"]=2818616;var _ffi_type_sint32=Module["_ffi_type_sint32"]=2818688;var _ffi_type_uint8=Module["_ffi_type_uint8"]=2818628;var _ffi_type_double=Module["_ffi_type_double"]=2818748;var _ffi_type_longdouble=Module["_ffi_type_longdouble"]=2818760;var _ffi_type_float=Module["_ffi_type_float"]=2818736;var _ffi_type_sint16=Module["_ffi_type_sint16"]=2818664;var _ffi_type_uint16=Module["_ffi_type_uint16"]=2818652;var _ffi_type_uint32=Module["_ffi_type_uint32"]=2818676;var _ffi_type_sint64=Module["_ffi_type_sint64"]=2818712;var _ffi_type_uint64=Module["_ffi_type_uint64"]=2818700;var _ffi_type_sint8=Module["_ffi_type_sint8"]=2818640;var _environ=Module["_environ"]=4592816;var __deduplicate_map=Module["__deduplicate_map"]=4592796;var _z_errmsg=Module["_z_errmsg"]=4424672;var __length_code=Module["__length_code"]=2829376;var __dist_code=Module["__dist_code"]=2828864;var _deflate_copyright=Module["_deflate_copyright"]=2824032;var _inflate_copyright=Module["_inflate_copyright"]=2828560;var _BZ2_crc32Table=Module["_BZ2_crc32Table"]=4424784;var _BZ2_rNums=Module["_BZ2_rNums"]=4425808;var ___environ=Module["___environ"]=4592816;var ____environ=Module["____environ"]=4592816;var __environ=Module["__environ"]=4592816;var _timezone=Module["_timezone"]=4593480;var _daylight=Module["_daylight"]=4593484;var _tzname=Module["_tzname"]=4593488;var ___progname=Module["___progname"]=4594704;var ___optreset=Module["___optreset"]=4593668;var _optind=Module["_optind"]=4428072;var ___optpos=Module["___optpos"]=4593672;var _optarg=Module["_optarg"]=4593676;var _optopt=Module["_optopt"]=4593680;var _opterr=Module["_opterr"]=4428076;var _optreset=Module["_optreset"]=4593668;var _h_errno=Module["_h_errno"]=4593804;var ___signgam=Module["___signgam"]=4609100;var __ns_flagdata=Module["__ns_flagdata"]=3016752;var ___progname_full=Module["___progname_full"]=4594708;var _program_invocation_short_name=Module["_program_invocation_short_name"]=4594704;var _program_invocation_name=Module["_program_invocation_name"]=4594708;var ___sig_pending=Module["___sig_pending"]=4599080;var ___sig_actions=Module["___sig_actions"]=46e5;var _signgam=Module["_signgam"]=4609100;var ___THREW__=Module["___THREW__"]=4616e3;var ___threwValue=Module["___threwValue"]=4616004;var ___cxa_unexpected_handler=Module["___cxa_unexpected_handler"]=4439364;var ___cxa_terminate_handler=Module["___cxa_terminate_handler"]=4439360;var ___cxa_new_handler=Module["___cxa_new_handler"]=4638784;var _in6addr_any=Module["_in6addr_any"]=3171248;var _in6addr_loopback=Module["_in6addr_loopback"]=3171264;var ___start_em_js=Module["___start_em_js"]=4446856;var ___stop_em_js=Module["___stop_em_js"]=4580244;function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiifi(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiidi(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_j(index){var sp=stackSave();try{return getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_ji(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_v(index){var sp=stackSave();try{getWasmTableEntry(index)()}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiij(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiid(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiijj(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_fiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_diii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiji(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_jiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0);return 0n}}function invoke_viif(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viid(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viijj(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_pppp=f=>(a0,a1,a2)=>f(a0,a1,a2)>>>0;var makeWrapper_p=f=>()=>f()>>>0;var makeWrapper_ppp=f=>(a0,a1)=>f(a0,a1)>>>0;var makeWrapper_pP=f=>a0=>f(a0)>>>0;wasmExports["malloc"]=makeWrapper_pp(wasmExports["malloc"]);wasmExports["memcpy"]=makeWrapper_pppp(wasmExports["memcpy"]);wasmExports["__errno_location"]=makeWrapper_p(wasmExports["__errno_location"]);wasmExports["pthread_self"]=makeWrapper_p(wasmExports["pthread_self"]);wasmExports["emscripten_builtin_malloc"]=makeWrapper_pp(wasmExports["emscripten_builtin_malloc"]);wasmExports["emscripten_stack_get_base"]=makeWrapper_p(wasmExports["emscripten_stack_get_base"]);wasmExports["emscripten_stack_get_end"]=makeWrapper_p(wasmExports["emscripten_stack_get_end"]);wasmExports["emscripten_builtin_memalign"]=makeWrapper_ppp(wasmExports["emscripten_builtin_memalign"]);wasmExports["emscripten_stack_get_current"]=makeWrapper_p(wasmExports["emscripten_stack_get_current"]);wasmExports["emscripten_main_runtime_thread_id"]=makeWrapper_p(wasmExports["emscripten_main_runtime_thread_id"]);wasmExports["sbrk"]=makeWrapper_pP(wasmExports["sbrk"]);wasmExports["memalign"]=makeWrapper_ppp(wasmExports["memalign"]);wasmExports["_emscripten_stack_alloc"]=makeWrapper_pp(wasmExports["_emscripten_stack_alloc"]);return wasmExports}Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["FS_createPath"]=FS.createPath;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;Module["ERRNO_CODES"]=ERRNO_CODES;Module["wasmTable"]=wasmTable;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_unlink"]=FS.unlink;Module["LZ4"]=LZ4;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=resolveGlobalSymbol("main").sym;if(!entryFunction)return;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();moduleRtn=readyPromise; + + + return moduleRtn; +} +); +})(); +globalThis._createPyodideModule = _createPyodideModule; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.wasm b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.wasm new file mode 100755 index 0000000000..41fd27cf91 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.asm.wasm differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.d.ts b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.d.ts new file mode 100644 index 0000000000..14a7f6b244 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.d.ts @@ -0,0 +1,1630 @@ +// Generated by dts-bundle-generator v8.1.2 + +/** + * + * The Pyodide version. + * + * The version here is a Python version, following :pep:`440`. This is different + * from the version in ``package.json`` which follows the node package manager + * version convention. + */ +export declare const version: string; +interface CanvasInterface { + setCanvas2D(canvas: HTMLCanvasElement): void; + getCanvas2D(): HTMLCanvasElement | undefined; + setCanvas3D(canvas: HTMLCanvasElement): void; + getCanvas3D(): HTMLCanvasElement | undefined; +} +type InFuncType = () => null | undefined | string | ArrayBuffer | Uint8Array | number; +declare function setStdin(options?: { + stdin?: InFuncType; + read?: (buffer: Uint8Array) => number; + error?: boolean; + isatty?: boolean; + autoEOF?: boolean; +}): void; +declare function setStdout(options?: { + batched?: (output: string) => void; + raw?: (charCode: number) => void; + write?: (buffer: Uint8Array) => number; + isatty?: boolean; +}): void; +declare function setStderr(options?: { + batched?: (output: string) => void; + raw?: (charCode: number) => void; + write?: (buffer: Uint8Array) => number; + isatty?: boolean; +}): void; +/** @deprecated Use `import type { TypedArray } from "pyodide/ffi"` instead */ +export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array; +type FSNode = { + timestamp: number; + rdev: number; + contents: Uint8Array; + mode: number; +}; +type FSStream = { + tty?: boolean; + seekable?: boolean; + stream_ops: FSStreamOps; + node: FSNode; +}; +type FSStreamOps = FSStreamOpsGen; +type FSStreamOpsGen = { + open: (a: T) => void; + close: (a: T) => void; + fsync: (a: T) => void; + read: (a: T, b: Uint8Array, offset: number, length: number, pos: number) => number; + write: (a: T, b: Uint8Array, offset: number, length: number, pos: number) => number; +}; +interface FSType { + unlink: (path: string) => void; + mkdirTree: (path: string, mode?: number) => void; + chdir: (path: string) => void; + symlink: (target: string, src: string) => FSNode; + createDevice: ((parent: string, name: string, input?: (() => number | null) | null, output?: ((code: number) => void) | null) => FSNode) & { + major: number; + }; + closeStream: (fd: number) => void; + open: (path: string, flags: string | number, mode?: number) => FSStream; + makedev: (major: number, minor: number) => number; + mkdev: (path: string, dev: number) => FSNode; + filesystems: any; + stat: (path: string, dontFollow?: boolean) => any; + readdir: (path: string) => string[]; + isDir: (mode: number) => boolean; + isMountpoint: (mode: FSNode) => boolean; + lookupPath: (path: string, options?: { + follow_mount?: boolean; + }) => { + node: FSNode; + }; + isFile: (mode: number) => boolean; + writeFile: (path: string, contents: any, o?: { + canOwn?: boolean; + }) => void; + chmod: (path: string, mode: number) => void; + utime: (path: string, atime: number, mtime: number) => void; + rmdir: (path: string) => void; + mount: (type: any, opts: any, mountpoint: string) => any; + write: (stream: FSStream, buffer: any, offset: number, length: number, position?: number) => number; + close: (stream: FSStream) => void; + ErrnoError: { + new (errno: number): Error; + }; + registerDevice(dev: number, ops: FSStreamOpsGen): void; + syncfs(dir: boolean, oncomplete: (val: void) => void): void; + findObject(a: string, dontResolveLastLink?: boolean): any; + readFile(a: string): Uint8Array; +} +type PackageType = "package" | "cpython_module" | "shared_library" | "static_library"; +interface PackageData { + name: string; + version: string; + fileName: string; + /** @experimental */ + packageType: PackageType; +} +type LoadedPackages = Record; +/** @deprecated Use `import type { PyProxy } from "pyodide/ffi"` instead */ +interface PyProxy { + [x: string]: any; +} +declare class PyProxy { + /** @private */ + $$flags: number; + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; + /** + * @hideconstructor + */ + constructor(); + /** @hidden */ + get [Symbol.toStringTag](): string; + /** + * The name of the type of the object. + * + * Usually the value is ``"module.name"`` but for builtins or + * interpreter-defined types it is just ``"name"``. As pseudocode this is: + * + * .. code-block:: python + * + * ty = type(x) + * if ty.__module__ == 'builtins' or ty.__module__ == "__main__": + * return ty.__name__ + * else: + * ty.__module__ + "." + ty.__name__ + * + */ + get type(): string; + /** + * Returns `str(o)` (unless `pyproxyToStringRepr: true` was passed to + * :js:func:`~globalThis.loadPyodide` in which case it will return `repr(o)`) + */ + toString(): string; + /** + * Destroy the :js:class:`~pyodide.ffi.PyProxy`. This will release the memory. Any further attempt + * to use the object will raise an error. + * + * In a browser supporting :js:data:`FinalizationRegistry`, Pyodide will + * automatically destroy the :js:class:`~pyodide.ffi.PyProxy` when it is garbage collected, however + * there is no guarantee that the finalizer will be run in a timely manner so + * it is better to destroy the proxy explicitly. + * + * @param options + * @param options.message The error message to print if use is attempted after + * destroying. Defaults to "Object has already been destroyed". + * + */ + destroy(options?: { + message?: string; + destroyRoundtrip?: boolean; + }): void; + /** + * Make a new :js:class:`~pyodide.ffi.PyProxy` pointing to the same Python object. + * Useful if the :js:class:`~pyodide.ffi.PyProxy` is destroyed somewhere else. + */ + copy(): PyProxy; + /** + * Converts the :js:class:`~pyodide.ffi.PyProxy` into a JavaScript object as best as possible. By + * default does a deep conversion, if a shallow conversion is desired, you can + * use ``proxy.toJs({depth : 1})``. See :ref:`Explicit Conversion of PyProxy + * ` for more info. + * @param options + * @return The JavaScript object resulting from the conversion. + */ + toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, }?: { + /** How many layers deep to perform the conversion. Defaults to infinite */ + depth?: number; + /** + * If provided, :js:meth:`toJs` will store all PyProxies created in this + * list. This allows you to easily destroy all the PyProxies by iterating + * the list without having to recurse over the generated structure. The most + * common use case is to create a new empty list, pass the list as + * ``pyproxies``, and then later iterate over ``pyproxies`` to destroy all of + * created proxies. + */ + pyproxies?: PyProxy[]; + /** + * If false, :js:meth:`toJs` will throw a + * :py:exc:`~pyodide.ffi.ConversionError` rather than producing a + * :js:class:`~pyodide.ffi.PyProxy`. + */ + create_pyproxies?: boolean; + /** + * A function to be called on an iterable of pairs ``[key, value]``. Convert + * this iterable of pairs to the desired output. For instance, + * :js:func:`Object.fromEntries` would convert the dict to an object, + * :js:func:`Array.from` converts it to an :js:class:`Array` of pairs, and + * ``(it) => new Map(it)`` converts it to a :js:class:`Map` (which is the + * default behavior). + */ + dict_converter?: (array: Iterable<[ + key: string, + value: any + ]>) => any; + /** + * Optional argument to convert objects with no default conversion. See the + * documentation of :meth:`~pyodide.ffi.to_js`. + */ + default_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any; + }): any; +} +declare class PyProxyWithLength extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyProxyWithLength } from "pyodide/ffi"` instead */ +interface PyProxyWithLength extends PyLengthMethods { +} +declare class PyLengthMethods { + /** + * The length of the object. + */ + get length(): number; +} +declare class PyProxyWithGet extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyProxyWithGet } from "pyodide/ffi"` instead */ +interface PyProxyWithGet extends PyGetItemMethods { +} +declare class PyGetItemMethods { + /** + * This translates to the Python code ``obj[key]``. + * + * @param key The key to look up. + * @returns The corresponding value. + */ + get(key: any): any; + /** + * Returns the object treated as a json adaptor. + * + * With a JsonAdaptor: + * 1. property access / modification / deletion is implemented with + * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and + * :meth:`~object.__delitem__` respectively. + * 2. If an attribute is accessed and the result implements + * :meth:`~object.__getitem__` then the result will also be a json + * adaptor. + * + * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an + * inverse to Python's :py:func:`json.loads`. + */ + asJsJson(): PyProxy & {}; +} +declare class PyProxyWithSet extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyProxyWithSet } from "pyodide/ffi"` instead */ +interface PyProxyWithSet extends PySetItemMethods { +} +declare class PySetItemMethods { + /** + * This translates to the Python code ``obj[key] = value``. + * + * @param key The key to set. + * @param value The value to set it to. + */ + set(key: any, value: any): void; + /** + * This translates to the Python code ``del obj[key]``. + * + * @param key The key to delete. + */ + delete(key: any): void; +} +declare class PyProxyWithHas extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyProxyWithHas } from "pyodide/ffi"` instead */ +interface PyProxyWithHas extends PyContainsMethods { +} +declare class PyContainsMethods { + /** + * This translates to the Python code ``key in obj``. + * + * @param key The key to check for. + * @returns Is ``key`` present? + */ + has(key: any): boolean; +} +declare class PyIterable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyIterable } from "pyodide/ffi"` instead */ +interface PyIterable extends PyIterableMethods { +} +declare class PyIterableMethods { + /** + * This translates to the Python code ``iter(obj)``. Return an iterator + * associated to the proxy. See the documentation for + * :js:data:`Symbol.iterator`. + * + * This will be used implicitly by ``for(let x of proxy){}``. + */ + [Symbol.iterator](): Iterator; +} +declare class PyAsyncIterable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyAsyncIterable } from "pyodide/ffi"` instead */ +interface PyAsyncIterable extends PyAsyncIterableMethods { +} +declare class PyAsyncIterableMethods { + /** + * This translates to the Python code ``aiter(obj)``. Return an async iterator + * associated to the proxy. See the documentation for :js:data:`Symbol.asyncIterator`. + * + * This will be used implicitly by ``for(await let x of proxy){}``. + */ + [Symbol.asyncIterator](): AsyncIterator; +} +declare class PyIterator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyIterator } from "pyodide/ffi"` instead */ +interface PyIterator extends PyIteratorMethods { +} +declare class PyIteratorMethods { + /** @private */ + [Symbol.iterator](): this; + /** + * This translates to the Python code ``next(obj)``. Returns the next value of + * the generator. See the documentation for :js:meth:`Generator.next` The + * argument will be sent to the Python generator. + * + * This will be used implicitly by ``for(let x of proxy){}``. + * + * @param arg The value to send to the generator. The value will be assigned + * as a result of a yield expression. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``next`` returns ``{done : false, value : + * some_value}``. When the generator raises a :py:exc:`StopIteration` + * exception, ``next`` returns ``{done : true, value : result_value}``. + */ + next(arg?: any): IteratorResult; +} +declare class PyGenerator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyGenerator } from "pyodide/ffi"` instead */ +interface PyGenerator extends PyGeneratorMethods { +} +declare class PyGeneratorMethods { + /** + * Throws an exception into the Generator. + * + * See the documentation for :js:meth:`Generator.throw`. + * + * @param exc Error The error to throw into the generator. Must be an + * instanceof ``Error``. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a + * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : + * true, value : result_value}``. + */ + throw(exc: any): IteratorResult; + /** + * Throws a :py:exc:`GeneratorExit` into the generator and if the + * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: + * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and + * returns or yields another value the next value of the generator this is + * returned in the normal way. If it throws some error other than + * :py:exc:`GeneratorExit` or :py:exc:`StopIteration`, that error is propagated. See + * the documentation for :js:meth:`Generator.return`. + * + * @param v The value to return from the generator. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a + * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : + * true, value : result_value}``. + */ + return(v: any): IteratorResult; +} +declare class PyAsyncIterator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyAsyncIterator } from "pyodide/ffi"` instead */ +interface PyAsyncIterator extends PyAsyncIteratorMethods { +} +declare class PyAsyncIteratorMethods { + /** @private */ + [Symbol.asyncIterator](): this; + /** + * This translates to the Python code ``anext(obj)``. Returns the next value + * of the asynchronous iterator. The argument will be sent to the Python + * iterator (if it's a generator for instance). + * + * This will be used implicitly by ``for(let x of proxy){}``. + * + * @param arg The value to send to a generator. The value will be assigned as + * a result of a yield expression. + * @returns An Object with two properties: ``done`` and ``value``. When the + * iterator yields ``some_value``, ``next`` returns ``{done : false, value : + * some_value}``. When the giterator is done, ``next`` returns + * ``{done : true }``. + */ + next(arg?: any): Promise>; +} +declare class PyAsyncGenerator extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyAsyncGenerator } from "pyodide/ffi"` instead */ +interface PyAsyncGenerator extends PyAsyncGeneratorMethods { +} +declare class PyAsyncGeneratorMethods { + /** + * Throws an exception into the Generator. + * + * See the documentation for :js:meth:`AsyncGenerator.throw`. + * + * @param exc Error The error to throw into the generator. Must be an + * instanceof ``Error``. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a + * ``StopIteration(result_value)`` exception, ``return`` returns ``{done : + * true, value : result_value}``. + */ + throw(exc: any): Promise>; + /** + * Throws a :py:exc:`GeneratorExit` into the generator and if the + * :py:exc:`GeneratorExit` is not caught returns the argument value ``{done: + * true, value: v}``. If the generator catches the :py:exc:`GeneratorExit` and + * returns or yields another value the next value of the generator this is + * returned in the normal way. If it throws some error other than + * :py:exc:`GeneratorExit` or :py:exc:`StopAsyncIteration`, that error is + * propagated. See the documentation for :js:meth:`AsyncGenerator.throw` + * + * @param v The value to return from the generator. + * @returns An Object with two properties: ``done`` and ``value``. When the + * generator yields ``some_value``, ``return`` returns ``{done : false, value + * : some_value}``. When the generator raises a :py:exc:`StopAsyncIteration` + * exception, ``return`` returns ``{done : true, value : result_value}``. + */ + return(v: any): Promise>; +} +declare class PySequence extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PySequence } from "pyodide/ffi"` instead */ +interface PySequence extends PySequenceMethods { +} +declare class PySequenceMethods { + /** @hidden */ + get [Symbol.isConcatSpreadable](): boolean; + /** + * See :js:meth:`Array.join`. The :js:meth:`Array.join` method creates and + * returns a new string by concatenating all of the elements in the + * :py:class:`~collections.abc.Sequence`. + * + * @param separator A string to separate each pair of adjacent elements of the + * Sequence. + * + * @returns A string with all Sequence elements joined. + */ + join(separator?: string): string; + /** + * See :js:meth:`Array.slice`. The :js:meth:`Array.slice` method returns a + * shallow copy of a portion of a :py:class:`~collections.abc.Sequence` into a + * new array object selected from ``start`` to ``stop`` (`stop` not included) + * @param start Zero-based index at which to start extraction. Negative index + * counts back from the end of the Sequence. + * @param stop Zero-based index at which to end extraction. Negative index + * counts back from the end of the Sequence. + * @returns A new array containing the extracted elements. + */ + slice(start?: number, stop?: number): any; + /** + * See :js:meth:`Array.lastIndexOf`. Returns the last index at which a given + * element can be found in the Sequence, or -1 if it is not present. + * @param elt Element to locate in the Sequence. + * @param fromIndex Zero-based index at which to start searching backwards, + * converted to an integer. Negative index counts back from the end of the + * Sequence. + * @returns The last index of the element in the Sequence; -1 if not found. + */ + lastIndexOf(elt: any, fromIndex?: number): number; + /** + * See :js:meth:`Array.indexOf`. Returns the first index at which a given + * element can be found in the Sequence, or -1 if it is not present. + * @param elt Element to locate in the Sequence. + * @param fromIndex Zero-based index at which to start searching, converted to + * an integer. Negative index counts back from the end of the Sequence. + * @returns The first index of the element in the Sequence; -1 if not found. + */ + indexOf(elt: any, fromIndex?: number): number; + /** + * See :js:meth:`Array.forEach`. Executes a provided function once for each + * ``Sequence`` element. + * @param callbackfn A function to execute for each element in the ``Sequence``. Its + * return value is discarded. + * @param thisArg A value to use as ``this`` when executing ``callbackFn``. + */ + forEach(callbackfn: (elt: any) => void, thisArg?: any): void; + /** + * See :js:meth:`Array.map`. Creates a new array populated with the results of + * calling a provided function on every element in the calling ``Sequence``. + * @param callbackfn A function to execute for each element in the ``Sequence``. Its + * return value is added as a single element in the new array. + * @param thisArg A value to use as ``this`` when executing ``callbackFn``. + */ + map(callbackfn: (elt: any, index: number, array: any) => U, thisArg?: any): U[]; + /** + * See :js:meth:`Array.filter`. Creates a shallow copy of a portion of a given + * ``Sequence``, filtered down to just the elements from the given array that pass + * the test implemented by the provided function. + * @param predicate A function to execute for each element in the array. It + * should return a truthy value to keep the element in the resulting array, + * and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + */ + filter(predicate: (elt: any, index: number, array: any) => boolean, thisArg?: any): any[]; + /** + * See :js:meth:`Array.some`. Tests whether at least one element in the + * ``Sequence`` passes the test implemented by the provided function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate the element + * passes the test, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + */ + some(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; + /** + * See :js:meth:`Array.every`. Tests whether every element in the ``Sequence`` + * passes the test implemented by the provided function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate the element + * passes the test, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + */ + every(predicate: (value: any, index: number, array: any[]) => unknown, thisArg?: any): boolean; + /** + * See :js:meth:`Array.reduce`. Executes a user-supplied "reducer" callback + * function on each element of the Sequence, in order, passing in the return + * value from the calculation on the preceding element. The final result of + * running the reducer across all elements of the Sequence is a single value. + * @param callbackfn A function to execute for each element in the ``Sequence``. Its + * return value is discarded. + */ + reduce(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue?: any): any; + /** + * See :js:meth:`Array.reduceRight`. Applies a function against an accumulator + * and each value of the Sequence (from right to left) to reduce it to a + * single value. + * @param callbackfn A function to execute for each element in the Sequence. + * Its return value is discarded. + */ + reduceRight(callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any) => any, initialValue: any): any; + /** + * See :js:meth:`Array.at`. Takes an integer value and returns the item at + * that index. + * @param index Zero-based index of the Sequence element to be returned, + * converted to an integer. Negative index counts back from the end of the + * Sequence. + * @returns The element in the Sequence matching the given index. + */ + at(index: number): any; + /** + * The :js:meth:`Array.concat` method is used to merge two or more arrays. + * This method does not change the existing arrays, but instead returns a new + * array. + * @param rest Arrays and/or values to concatenate into a new array. + * @returns A new Array instance. + */ + concat(...rest: ConcatArray[]): any[]; + /** + * The :js:meth:`Array.includes` method determines whether a Sequence + * includes a certain value among its entries, returning true or false as + * appropriate. + * @param elt + * @returns + */ + includes(elt: any): any; + /** + * The :js:meth:`Array.entries` method returns a new iterator object that + * contains the key/value pairs for each index in the ``Sequence``. + * @returns A new iterator object. + */ + entries(): IterableIterator<[ + number, + any + ]>; + /** + * The :js:meth:`Array.keys` method returns a new iterator object that + * contains the keys for each index in the ``Sequence``. + * @returns A new iterator object. + */ + keys(): IterableIterator; + /** + * The :js:meth:`Array.values` method returns a new iterator object that + * contains the values for each index in the ``Sequence``. + * @returns A new iterator object. + */ + values(): IterableIterator; + /** + * The :js:meth:`Array.find` method returns the first element in the provided + * array that satisfies the provided testing function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate a matching + * element has been found, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + * @returns The first element in the ``Sequence`` that satisfies the provided + * testing function. + */ + find(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): any; + /** + * The :js:meth:`Array.findIndex` method returns the index of the first + * element in the provided array that satisfies the provided testing function. + * @param predicate A function to execute for each element in the + * ``Sequence``. It should return a truthy value to indicate a matching + * element has been found, and a falsy value otherwise. + * @param thisArg A value to use as ``this`` when executing ``predicate``. + * @returns The index of the first element in the ``Sequence`` that satisfies + * the provided testing function. + */ + findIndex(predicate: (value: any, index: number, obj: any[]) => any, thisArg?: any): number; + toJSON(this: any): unknown[]; + /** + * Returns the object treated as a json adaptor. + * + * With a JsonAdaptor: + * 1. property access / modification / deletion is implemented with + * :meth:`~object.__getitem__`, :meth:`~object.__setitem__`, and + * :meth:`~object.__delitem__` respectively. + * 2. If an attribute is accessed and the result implements + * :meth:`~object.__getitem__` then the result will also be a json + * adaptor. + * + * For instance, ``JSON.stringify(proxy.asJsJson())`` acts like an + * inverse to Python's :py:func:`json.loads`. + */ + asJsJson(): PyProxy & {}; +} +declare class PyMutableSequence extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyMutableSequence } from "pyodide/ffi"` instead */ +interface PyMutableSequence extends PyMutableSequenceMethods { +} +declare class PyMutableSequenceMethods { + /** + * The :js:meth:`Array.reverse` method reverses a :js:class:`PyMutableSequence` in + * place. + * @returns A reference to the same :js:class:`PyMutableSequence` + */ + reverse(): PyMutableSequence; + /** + * The :js:meth:`Array.sort` method sorts the elements of a + * :js:class:`PyMutableSequence` in place. + * @param compareFn A function that defines the sort order. + * @returns A reference to the same :js:class:`PyMutableSequence` + */ + sort(compareFn?: (a: any, b: any) => number): PyMutableSequence; + /** + * The :js:meth:`Array.splice` method changes the contents of a + * :js:class:`PyMutableSequence` by removing or replacing existing elements and/or + * adding new elements in place. + * @param start Zero-based index at which to start changing the + * :js:class:`PyMutableSequence`. + * @param deleteCount An integer indicating the number of elements in the + * :js:class:`PyMutableSequence` to remove from ``start``. + * @param items The elements to add to the :js:class:`PyMutableSequence`, beginning from + * ``start``. + * @returns An array containing the deleted elements. + */ + splice(start: number, deleteCount?: number, ...items: any[]): any[]; + /** + * The :js:meth:`Array.push` method adds the specified elements to the end of + * a :js:class:`PyMutableSequence`. + * @param elts The element(s) to add to the end of the :js:class:`PyMutableSequence`. + * @returns The new length property of the object upon which the method was + * called. + */ + push(...elts: any[]): any; + /** + * The :js:meth:`Array.pop` method removes the last element from a + * :js:class:`PyMutableSequence`. + * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the + * :js:class:`PyMutableSequence` is empty. + */ + pop(): any; + /** + * The :js:meth:`Array.shift` method removes the first element from a + * :js:class:`PyMutableSequence`. + * @returns The removed element from the :js:class:`PyMutableSequence`; undefined if the + * :js:class:`PyMutableSequence` is empty. + */ + shift(): any; + /** + * The :js:meth:`Array.unshift` method adds the specified elements to the + * beginning of a :js:class:`PyMutableSequence`. + * @param elts The elements to add to the front of the :js:class:`PyMutableSequence`. + * @returns The new length of the :js:class:`PyMutableSequence`. + */ + unshift(...elts: any[]): any; + /** + * The :js:meth:`Array.copyWithin` method shallow copies part of a + * :js:class:`PyMutableSequence` to another location in the same :js:class:`PyMutableSequence` + * without modifying its length. + * @param target Zero-based index at which to copy the sequence to. + * @param start Zero-based index at which to start copying elements from. + * @param end Zero-based index at which to end copying elements from. + * @returns The modified :js:class:`PyMutableSequence`. + */ + copyWithin(target: number, start?: number, end?: number): any; + /** + * The :js:meth:`Array.fill` method changes all elements in an array to a + * static value, from a start index to an end index. + * @param value Value to fill the array with. + * @param start Zero-based index at which to start filling. Default 0. + * @param end Zero-based index at which to end filling. Default + * ``list.length``. + * @returns + */ + fill(value: any, start?: number, end?: number): any; +} +declare class PyAwaitable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyAwaitable } from "pyodide/ffi"` instead */ +interface PyAwaitable extends Promise { +} +declare class PyCallable extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyCallable; +} +/** @deprecated Use `import type { PyCallable } from "pyodide/ffi"` instead */ +interface PyCallable extends PyCallableMethods { + (...args: any[]): any; +} +declare class PyCallableMethods { + /** + * The ``apply()`` method calls the specified function with a given this + * value, and arguments provided as an array (or an array-like object). Like + * :js:meth:`Function.apply`. + * + * @param thisArg The ``this`` argument. Has no effect unless the + * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If + * :js:meth:`captureThis` is set, it will be passed as the first argument to + * the Python function. + * @param jsargs The array of arguments + * @returns The result from the function call. + */ + apply(thisArg: any, jsargs: any): any; + /** + * Calls the function with a given this value and arguments provided + * individually. See :js:meth:`Function.call`. + * + * @param thisArg The ``this`` argument. Has no effect unless the + * :js:class:`~pyodide.ffi.PyCallable` has :js:meth:`captureThis` set. If + * :js:meth:`captureThis` is set, it will be passed as the first argument to + * the Python function. + * @param jsargs The arguments + * @returns The result from the function call. + */ + call(thisArg: any, ...jsargs: any): any; + /** + * Call the Python function. The first parameter controls various parameters + * that change the way the call is performed. + * + * @param options + * @param options.kwargs If true, the last argument is treated as a collection + * of keyword arguments. + * @param options.promising If true, the call is made with stack switching + * enabled. Not needed if the callee is an async + * Python function. + * @param options.relaxed If true, extra arguments are ignored instead of + * raising a :py:exc:`TypeError`. + * @param jsargs Arguments to the Python function. + * @returns + */ + callWithOptions({ relaxed, kwargs, promising, }: { + relaxed?: boolean; + kwargs?: boolean; + promising?: boolean; + }, ...jsargs: any): any; + /** + * Call the function with keyword arguments. The last argument must be an + * object with the keyword arguments. + */ + callKwargs(...jsargs: any): any; + /** + * Call the function in a "relaxed" manner. Any extra arguments will be + * ignored. This matches the behavior of JavaScript functions more accurately. + * + * Any extra arguments will be ignored. This matches the behavior of + * JavaScript functions more accurately. Missing arguments are **NOT** filled + * with `None`. If too few arguments are passed, this will still raise a + * TypeError. + * + * This uses :py:func:`pyodide.code.relaxed_call`. + */ + callRelaxed(...jsargs: any): any; + /** + * Call the function with keyword arguments in a "relaxed" manner. The last + * argument must be an object with the keyword arguments. Any extra arguments + * will be ignored. This matches the behavior of JavaScript functions more + * accurately. + * + * Missing arguments are **NOT** filled with ``None``. If too few arguments are + * passed, this will still raise a :py:exc:`TypeError`. Also, if the same argument is + * passed as both a keyword argument and a positional argument, it will raise + * an error. + * + * This uses :py:func:`pyodide.code.relaxed_call`. + */ + callKwargsRelaxed(...jsargs: any): any; + /** + * Call the function with stack switching enabled. The last argument must be + * an object with the keyword arguments. Functions called this way can use + * :py:meth:`~pyodide.ffi.run_sync` to block until an + * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes + * with JS Promise integration. + * + * .. admonition:: Experimental + * :class: warning + * + * This feature is not yet stable. + * + * @experimental + */ + callPromising(...jsargs: any): Promise; + /** + * Call the function with stack switching enabled. The last argument must be + * an object with the keyword arguments. Functions called this way can use + * :py:meth:`~pyodide.ffi.run_sync` to block until an + * :py:class:`~collections.abc.Awaitable` is resolved. Only works in runtimes + * with JS Promise integration. + * + * .. admonition:: Experimental + * :class: warning + * + * This feature is not yet stable. + * + * @experimental + */ + callPromisingKwargs(...jsargs: any): Promise; + /** + * The ``bind()`` method creates a new function that, when called, has its + * ``this`` keyword set to the provided value, with a given sequence of + * arguments preceding any provided when the new function is called. See + * :js:meth:`Function.bind`. + * + * If the :js:class:`~pyodide.ffi.PyCallable` does not have + * :js:meth:`captureThis` set, the ``this`` parameter will be discarded. If it + * does have :js:meth:`captureThis` set, ``thisArg`` will be set to the first + * argument of the Python function. The returned proxy and the original proxy + * have the same lifetime so destroying either destroys both. + * + * @param thisArg The value to be passed as the ``this`` parameter to the + * target function ``func`` when the bound function is called. + * @param jsargs Extra arguments to prepend to arguments provided to the bound + * function when invoking ``func``. + * @returns + */ + bind(thisArg: any, ...jsargs: any): PyProxy; + /** + * Returns a :js:class:`~pyodide.ffi.PyProxy` that passes ``this`` as the first argument to the + * Python function. The returned :js:class:`~pyodide.ffi.PyProxy` has the internal ``captureThis`` + * property set. + * + * It can then be used as a method on a JavaScript object. The returned proxy + * and the original proxy have the same lifetime so destroying either destroys + * both. + * + * For example: + * + * .. code-block:: pyodide + * + * let obj = { a : 7 }; + * pyodide.runPython(` + * def f(self): + * return self.a + * `); + * // Without captureThis, it doesn't work to use f as a method for obj: + * obj.f = pyodide.globals.get("f"); + * obj.f(); // raises "TypeError: f() missing 1 required positional argument: 'self'" + * // With captureThis, it works fine: + * obj.f = pyodide.globals.get("f").captureThis(); + * obj.f(); // returns 7 + * + * @returns The resulting :js:class:`~pyodide.ffi.PyProxy`. It has the same lifetime as the + * original :js:class:`~pyodide.ffi.PyProxy` but passes ``this`` to the wrapped function. + * + */ + captureThis(): PyProxy; +} +declare class PyBuffer extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyBuffer; +} +/** @deprecated Use `import type { PyBuffer } from "pyodide/ffi"` instead */ +interface PyBuffer extends PyBufferMethods { +} +declare class PyBufferMethods { + /** + * Get a view of the buffer data which is usable from JavaScript. No copy is + * ever performed. + * + * We do not support suboffsets, if the buffer requires suboffsets we will + * throw an error. JavaScript nd array libraries can't handle suboffsets + * anyways. In this case, you should use the :js:meth:`~PyProxy.toJs` api or + * copy the buffer to one that doesn't use suboffsets (using e.g., + * :py:func:`numpy.ascontiguousarray`). + * + * If the buffer stores big endian data or half floats, this function will + * fail without an explicit type argument. For big endian data you can use + * :js:meth:`~PyProxy.toJs`. :js:class:`DataView` has support for big endian + * data, so you might want to pass ``'dataview'`` as the type argument in that + * case. + * + * @param type The type of the :js:attr:`~pyodide.ffi.PyBufferView.data` field + * in the output. Should be one of: ``"i8"``, ``"u8"``, ``"u8clamped"``, + * ``"i16"``, ``"u16"``, ``"i32"``, ``"u32"``, ``"i32"``, ``"u32"``, + * ``"i64"``, ``"u64"``, ``"f32"``, ``"f64"``, or ``"dataview"``. This argument + * is optional, if absent :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will try + * to determine the appropriate output type based on the buffer format string + * (see :std:ref:`struct-format-strings`). + */ + getBuffer(type?: string): PyBufferView; +} +declare class PyDict extends PyProxy { + /** @private */ + static [Symbol.hasInstance](obj: any): obj is PyProxy; +} +/** @deprecated Use `import type { PyDict } from "pyodide/ffi"` instead */ +interface PyDict extends PyProxyWithGet, PyProxyWithSet, PyProxyWithHas, PyProxyWithLength, PyIterable { +} +/** @deprecated Use `import type { PyBufferView } from "pyodide/ffi"` instead */ +declare class PyBufferView { + /** + * The offset of the first entry of the array. For instance if our array + * is 3d, then you will find ``array[0,0,0]`` at + * ``pybuf.data[pybuf.offset]`` + */ + offset: number; + /** + * If the data is read only, you should not modify it. There is no way for us + * to enforce this, but it may cause very weird behavior. See + * :py:attr:`memoryview.readonly`. + */ + readonly: boolean; + /** + * The format string for the buffer. See :ref:`struct-format-strings` + * and :py:attr:`memoryview.format`. + */ + format: string; + /** + * How large is each entry in bytes? See :py:attr:`memoryview.itemsize`. + */ + itemsize: number; + /** + * The number of dimensions of the buffer. If ``ndim`` is 0, the buffer + * represents a single scalar or struct. Otherwise, it represents an + * array. See :py:attr:`memoryview.ndim`. + */ + ndim: number; + /** + * The total number of bytes the buffer takes up. This is equal to + * :js:attr:`buff.data.byteLength `. See + * :py:attr:`memoryview.nbytes`. + */ + nbytes: number; + /** + * The shape of the buffer, that is how long it is in each dimension. + * The length will be equal to ``ndim``. For instance, a 2x3x4 array + * would have shape ``[2, 3, 4]``. See :py:attr:`memoryview.shape`. + */ + shape: number[]; + /** + * An array of of length ``ndim`` giving the number of elements to skip + * to get to a new element in each dimension. See the example definition + * of a ``multiIndexToIndex`` function above. See :py:attr:`memoryview.strides`. + */ + strides: number[]; + /** + * The actual data. A typed array of an appropriate size backed by a segment + * of the WASM memory. + * + * The ``type`` argument of :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` determines + * which sort of :js:class:`TypedArray` or :js:class:`DataView` to return. By + * default :js:meth:`~pyodide.ffi.PyBuffer.getBuffer` will look at the format string + * to determine the most appropriate option. Most often the result is a + * :js:class:`Uint8Array`. + * + * .. admonition:: Contiguity + * :class: warning + * + * If the buffer is not contiguous, the :js:attr:`~PyBufferView.readonly` + * TypedArray will contain data that is not part of the buffer. Modifying + * this data leads to undefined behavior. + * + * .. admonition:: Read only buffers + * :class: warning + * + * If :js:attr:`buffer.readonly ` is ``true``, you + * should not modify the buffer. Modifying a read only buffer leads to + * undefined behavior. + * + */ + data: TypedArray; + /** + * Is it C contiguous? See :py:attr:`memoryview.c_contiguous`. + */ + c_contiguous: boolean; + /** + * Is it Fortran contiguous? See :py:attr:`memoryview.f_contiguous`. + */ + f_contiguous: boolean; + /** + * @private + */ + _released: boolean; + /** + * @private + */ + _view_ptr: number; + /** @private */ + constructor(); + /** + * Release the buffer. This allows the memory to be reclaimed. + */ + release(): void; +} +declare class PythonError extends Error { + /** + * The address of the error we are wrapping. We may later compare this + * against sys.last_exc. + * WARNING: we don't own a reference to this pointer, dereferencing it + * may be a use-after-free error! + * @private + */ + __error_address: number; + /** + * The name of the Python error class, e.g, :py:exc:`RuntimeError` or + * :py:exc:`KeyError`. + */ + type: string; + constructor(type: string, message: string, error_address: number); +} +type NativeFS = { + syncfs: () => Promise; +}; +declare class PyodideAPI { + /** @hidden */ + static version: string; + /** @hidden */ + static loadPackage: (names: string | PyProxy | Array, options?: { + messageCallback?: (message: string) => void; + errorCallback?: (message: string) => void; + checkIntegrity?: boolean; + }) => Promise>; + /** @hidden */ + static loadedPackages: LoadedPackages; + /** @hidden */ + static ffi: { + PyProxy: typeof PyProxy; + PyProxyWithLength: typeof PyProxyWithLength; + PyProxyWithGet: typeof PyProxyWithGet; + PyProxyWithSet: typeof PyProxyWithSet; + PyProxyWithHas: typeof PyProxyWithHas; + PyDict: typeof PyDict; + PyIterable: typeof PyIterable; + PyAsyncIterable: typeof PyAsyncIterable; + PyIterator: typeof PyIterator; + PyAsyncIterator: typeof PyAsyncIterator; + PyGenerator: typeof PyGenerator; + PyAsyncGenerator: typeof PyAsyncGenerator; + PyAwaitable: typeof PyAwaitable; + PyCallable: typeof PyCallable; + PyBuffer: typeof PyBuffer; + PyBufferView: typeof PyBufferView; + PythonError: typeof PythonError; + PySequence: typeof PySequence; + PyMutableSequence: typeof PyMutableSequence; + }; + /** @hidden */ + static setStdin: typeof setStdin; + /** @hidden */ + static setStdout: typeof setStdout; + /** @hidden */ + static setStderr: typeof setStderr; + /** + * + * An alias to the global Python namespace. + * + * For example, to access a variable called ``foo`` in the Python global + * scope, use ``pyodide.globals.get("foo")`` + */ + static globals: PyProxy; + /** + * An alias to the `Emscripten File System API + * `_. + * + * This provides a wide range of POSIX-`like` file/device operations, including + * `mount + * `_ + * which can be used to extend the in-memory filesystem with features like `persistence + * `_. + * + * While all the file systems implementations are enabled, only the default + * ``MEMFS`` is guaranteed to work in all runtime settings. The implementations + * are available as members of ``FS.filesystems``: + * ``IDBFS``, ``NODEFS``, ``PROXYFS``, ``WORKERFS``. + */ + static FS: FSType; + /** + * An alias to the `Emscripten Path API + * `_. + * + * This provides a variety of operations for working with file system paths, such as + * ``dirname``, ``normalize``, and ``splitPath``. + */ + static PATH: any; + /** + * APIs to set a canvas for rendering graphics. + * @summaryLink :ref:`canvas ` + * @omitFromAutoModule + */ + static canvas: CanvasInterface; + /** + * A map from posix error names to error codes. + */ + static ERRNO_CODES: { + [code: string]: number; + }; + /** + * An alias to the Python :ref:`pyodide ` package. + * + * You can use this to call functions defined in the Pyodide Python package + * from JavaScript. + */ + static pyodide_py: PyProxy; + /** + * Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to install + * any known packages that the code chunk imports. Uses the Python API + * :func:`pyodide.code.find\_imports` to inspect the code. + * + * For example, given the following code as input + * + * .. code-block:: python + * + * import numpy as np + * x = np.array([1, 2, 3]) + * + * :js:func:`loadPackagesFromImports` will call + * ``pyodide.loadPackage(['numpy'])``. + * + * @param code The code to inspect. + * @param options Options passed to :js:func:`pyodide.loadPackage`. + * @param options.messageCallback A callback, called with progress messages + * (optional) + * @param options.errorCallback A callback, called with error/warning messages + * (optional) + * @param options.checkIntegrity If true, check the integrity of the downloaded + * packages (default: true) + */ + static loadPackagesFromImports(code: string, options?: { + messageCallback?: (message: string) => void; + errorCallback?: (message: string) => void; + checkIntegrity?: boolean; + }): Promise>; + /** + * Runs a string of Python code from JavaScript, using :py:func:`~pyodide.code.eval_code` + * to evaluate the code. If the last statement in the Python code is an + * expression (and the code doesn't end with a semicolon), the value of the + * expression is returned. + * + * @param code The Python code to run + * @param options + * @param options.globals An optional Python dictionary to use as the globals. + * Defaults to :js:attr:`pyodide.globals`. + * @param options.locals An optional Python dictionary to use as the locals. + * Defaults to the same as ``globals``. + * @param options.filename An optional string to use as the file name. + * Defaults to ``""``. If a custom file name is given, the + * traceback for any exception that is thrown will show source lines + * (unless the given file name starts with ``<`` and ends with ``>``). + * @returns The result of the Python code translated to JavaScript. See the + * documentation for :py:func:`~pyodide.code.eval_code` for more info. + * @example + * async function main(){ + * const pyodide = await loadPyodide(); + * console.log(pyodide.runPython("1 + 2")); + * // 3 + * + * const globals = pyodide.toPy({ x: 3 }); + * console.log(pyodide.runPython("x + 1", { globals })); + * // 4 + * + * const locals = pyodide.toPy({ arr: [1, 2, 3] }); + * console.log(pyodide.runPython("sum(arr)", { locals })); + * // 6 + * } + * main(); + */ + static runPython(code: string, options?: { + globals?: PyProxy; + locals?: PyProxy; + filename?: string; + }): any; + /** + * Run a Python code string with top level await using + * :py:func:`~pyodide.code.eval_code_async` to evaluate the code. Returns a promise which + * resolves when execution completes. If the last statement in the Python code + * is an expression (and the code doesn't end with a semicolon), the returned + * promise will resolve to the value of this expression. + * + * For example: + * + * .. code-block:: pyodide + * + * let result = await pyodide.runPythonAsync(` + * from js import fetch + * response = await fetch("./pyodide-lock.json") + * packages = await response.json() + * # If final statement is an expression, its value is returned to JavaScript + * len(packages.packages.object_keys()) + * `); + * console.log(result); // 79 + * + * .. admonition:: Python imports + * :class: warning + * + * Since pyodide 0.18.0, you must call :js:func:`loadPackagesFromImports` to + * import any python packages referenced via ``import`` statements in your + * code. This function will no longer do it for you. + * + * @param code The Python code to run + * @param options + * @param options.globals An optional Python dictionary to use as the globals. + * Defaults to :js:attr:`pyodide.globals`. + * @param options.locals An optional Python dictionary to use as the locals. + * Defaults to the same as ``globals``. + * @param options.filename An optional string to use as the file name. + * Defaults to ``""``. If a custom file name is given, the + * traceback for any exception that is thrown will show source lines + * (unless the given file name starts with ``<`` and ends with ``>``). + * @returns The result of the Python code translated to JavaScript. + */ + static runPythonAsync(code: string, options?: { + globals?: PyProxy; + locals?: PyProxy; + filename?: string; + }): Promise; + /** + * Registers the JavaScript object ``module`` as a JavaScript module named + * ``name``. This module can then be imported from Python using the standard + * Python import system. If another module by the same name has already been + * imported, this won't have much effect unless you also delete the imported + * module from :py:data:`sys.modules`. This calls + * :func:`~pyodide.ffi.register_js_module`. + * + * Any attributes of the JavaScript objects which are themselves objects will + * be treated as submodules: + * ```pyodide + * pyodide.registerJsModule("mymodule", { submodule: { value: 7 } }); + * pyodide.runPython(` + * from mymodule.submodule import value + * assert value == 7 + * `); + * ``` + * If you wish to prevent this, try the following instead: + * ```pyodide + * const sys = pyodide.pyimport("sys"); + * sys.modules.set("mymodule", { obj: { value: 7 } }); + * pyodide.runPython(` + * from mymodule import obj + * assert obj.value == 7 + * # attempting to treat obj as a submodule raises ModuleNotFoundError: + * # "No module named 'mymodule.obj'; 'mymodule' is not a package" + * from mymodule.obj import value + * `); + * ``` + * + * @param name Name of the JavaScript module to add + * @param module JavaScript object backing the module + */ + static registerJsModule(name: string, module: object): void; + /** + * Unregisters a JavaScript module with given name that has been previously + * registered with :js:func:`pyodide.registerJsModule` or + * :func:`~pyodide.ffi.register_js_module`. If a JavaScript module with that + * name does not already exist, will throw an error. Note that if the module has + * already been imported, this won't have much effect unless you also delete the + * imported module from :py:data:`sys.modules`. This calls + * :func:`~pyodide.ffi.unregister_js_module`. + * + * @param name Name of the JavaScript module to remove + */ + static unregisterJsModule(name: string): void; + /** + * Convert a JavaScript object to a Python object as best as possible. + * + * This is similar to :py:meth:`~pyodide.ffi.JsProxy.to_py` but for use from + * JavaScript. If the object is immutable or a :js:class:`~pyodide.ffi.PyProxy`, + * it will be returned unchanged. If the object cannot be converted into Python, + * it will be returned unchanged. + * + * See :ref:`type-translations-jsproxy-to-py` for more information. + * + * @param obj The object to convert. + * @param options + * @returns The object converted to Python. + */ + static toPy(obj: any, { depth, defaultConverter, }?: { + /** + * Optional argument to limit the depth of the conversion. + */ + depth: number; + /** + * Optional argument to convert objects with no default conversion. See the + * documentation of :py:meth:`~pyodide.ffi.JsProxy.to_py`. + */ + defaultConverter?: (value: any, converter: (value: any) => any, cacheConversion: (input: any, output: any) => void) => any; + }): any; + /** + * Imports a module and returns it. + * + * If `name` has no dot in it, then `pyimport(name)` is approximately + * equivalent to: + * ```js + * pyodide.runPython(`import ${name}; ${name}`) + * ``` + * except that `name` is not introduced into the Python global namespace. If + * the name has one or more dots in it, say it is of the form `path.name` + * where `name` has no dots but path may have zero or more dots. Then it is + * approximately the same as: + * ```js + * pyodide.runPython(`from ${path} import ${name}; ${name}`); + * ``` + * + * @param mod_name The name of the module to import + * + * @example + * pyodide.pyimport("math.comb")(4, 2) // returns 4 choose 2 = 6 + */ + static pyimport(mod_name: string): any; + /** + * Unpack an archive into a target directory. + * + * @param buffer The archive as an :js:class:`ArrayBuffer` or :js:class:`TypedArray`. + * @param format The format of the archive. Should be one of the formats + * recognized by :py:func:`shutil.unpack_archive`. By default the options are + * ``'bztar'``, ``'gztar'``, ``'tar'``, ``'zip'``, and ``'wheel'``. Several + * synonyms are accepted for each format, e.g., for ``'gztar'`` any of + * ``'.gztar'``, ``'.tar.gz'``, ``'.tgz'``, ``'tar.gz'`` or ``'tgz'`` are + * considered to be + * synonyms. + * + * @param options + * @param options.extractDir The directory to unpack the archive into. Defaults + * to the working directory. + */ + static unpackArchive(buffer: TypedArray | ArrayBuffer, format: string, options?: { + extractDir?: string; + }): void; + /** + * Mounts a :js:class:`FileSystemDirectoryHandle` into the target directory. + * Currently it's only possible to acquire a + * :js:class:`FileSystemDirectoryHandle` in Chrome. + * + * @param path The absolute path in the Emscripten file system to mount the + * native directory. If the directory does not exist, it will be created. If + * it does exist, it must be empty. + * @param fileSystemHandle A handle returned by + * :js:func:`navigator.storage.getDirectory() ` or + * :js:func:`window.showDirectoryPicker() `. + */ + static mountNativeFS(path: string, fileSystemHandle: FileSystemDirectoryHandle): Promise; + /** + * Mounts a host directory into Pyodide file system. Only works in node. + * + * @param emscriptenPath The absolute path in the Emscripten file system to + * mount the native directory. If the directory does not exist, it will be + * created. If it does exist, it must be empty. + * @param hostPath The host path to mount. It must be a directory that exists. + */ + static mountNodeFS(emscriptenPath: string, hostPath: string): void; + /** + * Tell Pyodide about Comlink. + * Necessary to enable importing Comlink proxies into Python. + */ + static registerComlink(Comlink: any): void; + /** + * Sets the interrupt buffer to be ``interrupt_buffer``. This is only useful + * when Pyodide is used in a webworker. The buffer should be a + * :js:class:`SharedArrayBuffer` shared with the main browser thread (or another + * worker). In that case, signal ``signum`` may be sent by writing ``signum`` + * into the interrupt buffer. If ``signum`` does not satisfy 0 < ``signum`` < 65 + * it will be silently ignored. + * + * You can disable interrupts by calling ``setInterruptBuffer(undefined)``. + * + * If you wish to trigger a :py:exc:`KeyboardInterrupt`, write ``SIGINT`` (a 2) + * into the interrupt buffer. + * + * By default ``SIGINT`` raises a :py:exc:`KeyboardInterrupt` and all other signals + * are ignored. You can install custom signal handlers with the signal module. + * Even signals that normally have special meaning and can't be overridden like + * ``SIGKILL`` and ``SIGSEGV`` are ignored by default and can be used for any + * purpose you like. + */ + static setInterruptBuffer(interrupt_buffer: TypedArray): void; + /** + * Throws a :py:exc:`KeyboardInterrupt` error if a :py:exc:`KeyboardInterrupt` has + * been requested via the interrupt buffer. + * + * This can be used to enable keyboard interrupts during execution of JavaScript + * code, just as :c:func:`PyErr_CheckSignals` is used to enable keyboard interrupts + * during execution of C code. + */ + static checkInterrupt(): void; + /** + * Turn on or off debug mode. In debug mode, some error messages are improved + * at a performance cost. + * @param debug If true, turn debug mode on. If false, turn debug mode off. + * @returns The old value of the debug flag. + */ + static setDebug(debug: boolean): boolean; + /** + * + * @param param0 + * @returns + */ + static makeMemorySnapshot({ serializer, }?: { + serializer?: (obj: any) => any; + }): Uint8Array; +} +/** @hidden */ +export type PyodideInterface = typeof PyodideAPI; +/** + * See documentation for loadPyodide. + * @hidden + */ +type ConfigType = { + indexURL: string; + packageCacheDir: string; + lockFileURL: string; + fullStdLib?: boolean; + stdLibURL?: string; + stdin?: () => string; + stdout?: (msg: string) => void; + stderr?: (msg: string) => void; + jsglobals?: object; + _sysExecutable?: string; + args: string[]; + fsInit?: (FS: FSType, info: { + sitePackages: string; + }) => Promise; + env: { + [key: string]: string; + }; + packages: string[]; + _makeSnapshot: boolean; + enableRunUntilComplete: boolean; + checkAPIVersion: boolean; + BUILD_ID: string; +}; +/** + * Load the main Pyodide wasm module and initialize it. + * + * @returns The :ref:`js-api-pyodide` module. + * @example + * async function main() { + * const pyodide = await loadPyodide({ + * fullStdLib: true, + * stdout: (msg) => console.log(`Pyodide: ${msg}`), + * }); + * console.log("Loaded Pyodide"); + * } + * main(); + */ +export declare function loadPyodide(options?: { + /** + * The URL from which Pyodide will load the main Pyodide runtime and + * packages. It is recommended that you leave this unchanged, providing an + * incorrect value can cause broken behavior. + * + * Default: The url that Pyodide is loaded from with the file name + * (``pyodide.js`` or ``pyodide.mjs``) removed. + */ + indexURL?: string; + /** + * The file path where packages will be cached in node. If a package + * exists in ``packageCacheDir`` it is loaded from there, otherwise it is + * downloaded from the JsDelivr CDN and then cached into ``packageCacheDir``. + * Only applies when running in node; ignored in browsers. + * + * Default: same as indexURL + */ + packageCacheDir?: string; + /** + * The URL from which Pyodide will load the Pyodide ``pyodide-lock.json`` lock + * file. You can produce custom lock files with :py:func:`micropip.freeze`. + * Default: ```${indexURL}/pyodide-lock.json``` + */ + lockFileURL?: string; + /** + * Load the full Python standard library. Setting this to false excludes + * unvendored modules from the standard library. + * Default: ``false`` + */ + fullStdLib?: boolean; + /** + * The URL from which to load the standard library ``python_stdlib.zip`` + * file. This URL includes the most of the Python standard library. Some + * stdlib modules were unvendored, and can be loaded separately + * with ``fullStdLib: true`` option or by their package name. + * Default: ```${indexURL}/python_stdlib.zip``` + */ + stdLibURL?: string; + /** + * Override the standard input callback. Should ask the user for one line of + * input. The :js:func:`pyodide.setStdin` function is more flexible and + * should be preferred. + */ + stdin?: () => string; + /** + * Override the standard output callback. The :js:func:`pyodide.setStdout` + * function is more flexible and should be preferred in most cases, but + * depending on the ``args`` passed to ``loadPyodide``, Pyodide may write to + * stdout on startup, which can only be controlled by passing a custom + * ``stdout`` function. + */ + stdout?: (msg: string) => void; + /** + * Override the standard error output callback. The + * :js:func:`pyodide.setStderr` function is more flexible and should be + * preferred in most cases, but depending on the ``args`` passed to + * ``loadPyodide``, Pyodide may write to stdout on startup, which can only + * be controlled by passing a custom ``stdout`` function. + */ + stderr?: (msg: string) => void; + /** + * The object that Pyodide will use for the ``js`` module. + * Default: ``globalThis`` + */ + jsglobals?: object; + /** + * Determine the value of ``sys.executable``. + * @ignore + */ + _sysExecutable?: string; + /** + * Command line arguments to pass to Python on startup. See `Python command + * line interface options + * `_ for + * more details. Default: ``[]`` + */ + args?: string[]; + /** + * Environment variables to pass to Python. This can be accessed inside of + * Python at runtime via :py:data:`os.environ`. Certain environment variables change + * the way that Python loads: + * https://docs.python.org/3.10/using/cmdline.html#environment-variables + * Default: ``{}``. + * If ``env.HOME`` is undefined, it will be set to a default value of + * ``"/home/pyodide"`` + */ + env?: { + [key: string]: string; + }; + /** + * A list of packages to load as Pyodide is initializing. + * + * This is the same as loading the packages with + * :js:func:`pyodide.loadPackage` after Pyodide is loaded except using the + * ``packages`` option is more efficient because the packages are downloaded + * while Pyodide bootstraps itself. + */ + packages?: string[]; + /** + * Opt into the old behavior where :js:func:`PyProxy.toString() ` + * calls :py:func:`repr` and not :py:class:`str() `. + * @deprecated + */ + pyproxyToStringRepr?: boolean; + /** + * Make loop.run_until_complete() function correctly using stack switching + */ + enableRunUntilComplete?: boolean; + /** + * If true (default), throw an error if the version of Pyodide core does not + * match the version of the Pyodide js package. + */ + checkAPIVersion?: boolean; + /** + * This is a hook that allows modification of the file system before the + * main() function is called and the intereter is started. When this is + * called, it is guaranteed that there is an empty site-packages directory. + * @experimental + */ + fsInit?: (FS: FSType, info: { + sitePackages: string; + }) => Promise; + /** @ignore */ + _makeSnapshot?: boolean; + /** @ignore */ + _loadSnapshot?: Uint8Array | ArrayBuffer | PromiseLike; + /** @ignore */ + _snapshotDeserializer?: (obj: any) => any; +}): Promise; + +export type {}; +export type {PackageData}; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.js new file mode 100644 index 0000000000..de1656cd6c --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.js @@ -0,0 +1,6 @@ +"use strict";var loadPyodide=(()=>{var ne=Object.create;var F=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var oe=Object.getPrototypeOf,ae=Object.prototype.hasOwnProperty;var s=(e,t)=>F(e,"name",{value:t,configurable:!0}),p=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,i)=>(typeof require<"u"?require:t)[i]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});var se=(e,t)=>{for(var i in t)F(e,i,{get:t[i],enumerable:!0})},$=(e,t,i,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of ie(t))!ae.call(e,a)&&a!==i&&F(e,a,{get:()=>t[a],enumerable:!(r=re(t,a))||r.enumerable});return e};var b=(e,t,i)=>(i=e!=null?ne(oe(e)):{},$(t||!e||!e.__esModule?F(i,"default",{value:e,enumerable:!0}):i,e)),ce=e=>$(F({},"__esModule",{value:!0}),e);var Fe={};se(Fe,{loadPyodide:()=>B,version:()=>x});function le(e){return!isNaN(parseFloat(e))&&isFinite(e)}s(le,"_isNumber");function w(e){return e.charAt(0).toUpperCase()+e.substring(1)}s(w,"_capitalize");function L(e){return function(){return this[e]}}s(L,"_getter");var _=["isConstructor","isEval","isNative","isToplevel"],I=["columnNumber","lineNumber"],P=["fileName","functionName","source"],de=["args"],ue=["evalOrigin"],O=_.concat(I,P,de,ue);function g(e){if(e)for(var t=0;t-1&&(n=n.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var o=n.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),c=o.match(/ (\(.+\)$)/);o=c?o.replace(c[0],""):o;var l=this.extractLocation(c?c[1]:o),d=c&&o||void 0,u=["eval",""].indexOf(l[0])>-1?void 0:l[0];return new A({functionName:d,fileName:u,lineNumber:l[1],columnNumber:l[2],source:n})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:s(function(r){var a=r.stack.split(` +`).filter(function(n){return!n.match(t)},this);return a.map(function(n){if(n.indexOf(" > eval")>-1&&(n=n.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),n.indexOf("@")===-1&&n.indexOf(":")===-1)return new A({functionName:n});var o=/((.*".+"[^@]*)?[^@]*)(?:@)/,c=n.match(o),l=c&&c[1]?c[1]:void 0,d=this.extractLocation(n.replace(o,""));return new A({functionName:l,fileName:d[0],lineNumber:d[1],columnNumber:d[2],source:n})},this)},"ErrorStackParser$$parseFFOrSafari")}}s(fe,"ErrorStackParser");var me=new fe;var j=me;var y=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,T=y&&typeof module<"u"&&typeof module.exports<"u"&&typeof p<"u"&&typeof __dirname<"u",H=y&&!T,Le=typeof globalThis.Bun<"u",pe=typeof Deno<"u",z=!y&&!pe,V=z&&typeof window=="object"&&typeof document=="object"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof importScripts!="function",q=z&&typeof importScripts=="function"&&typeof self=="object",Te=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")==-1&&navigator.userAgent.indexOf("Safari")>-1;var K,U,Y,J,M;async function C(){if(!y||(K=(await import(/* webpackIgnore */"node:url")).default,J=await import(/* webpackIgnore */"node:fs"),M=await import(/* webpackIgnore */"node:fs/promises"),Y=(await import(/* webpackIgnore */"node:vm")).default,U=await import(/* webpackIgnore */"node:path"),W=U.sep,typeof p<"u"))return;let e=J,t=await import(/* webpackIgnore */"node:crypto"),i=await import(/* webpackIgnore */"ws"),r=await import(/* webpackIgnore */"node:child_process"),a={fs:e,crypto:t,ws:i,child_process:r};globalThis.require=function(n){return a[n]}}s(C,"initNodeModules");function ge(e,t){return U.resolve(t||".",e)}s(ge,"node_resolvePath");function ye(e,t){return t===void 0&&(t=location),new URL(e,t).toString()}s(ye,"browser_resolvePath");var D;y?D=ge:D=ye;var W;y||(W="/");function be(e,t){return e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?{response:fetch(e)}:{binary:M.readFile(e).then(i=>new Uint8Array(i.buffer,i.byteOffset,i.byteLength))}}s(be,"node_getBinaryResponse");function ve(e,t){let i=new URL(e,location);return{response:fetch(i,t?{integrity:t}:{})}}s(ve,"browser_getBinaryResponse");var k;y?k=be:k=ve;async function G(e,t){let{response:i,binary:r}=k(e,t);if(r)return r;let a=await i;if(!a.ok)throw new Error(`Failed to load '${e}': request failed.`);return new Uint8Array(await a.arrayBuffer())}s(G,"loadBinaryFile");var R;if(V)R=s(async e=>await import(/* webpackIgnore */e),"loadScript");else if(q)R=s(async e=>{try{globalThis.importScripts(e)}catch(t){if(t instanceof TypeError)await import(/* webpackIgnore */e);else throw t}},"loadScript");else if(y)R=he;else throw new Error("Cannot determine runtime environment");async function he(e){e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?Y.runInThisContext(await(await fetch(e)).text()):await import(/* webpackIgnore */K.pathToFileURL(e).href)}s(he,"nodeLoadScript");async function X(e){if(y){await C();let t=await M.readFile(e,{encoding:"utf8"});return JSON.parse(t)}else return await(await fetch(e)).json()}s(X,"loadLockFile");async function Q(){if(T)return __dirname;let e;try{throw new Error}catch(r){e=r}let t=j.parse(e)[0].fileName;if(y&&!t.startsWith("file://")&&(t=`file://${t}`),H){let r=await import(/* webpackIgnore */"node:path");return(await import(/* webpackIgnore */"node:url")).fileURLToPath(r.dirname(t))}let i=t.lastIndexOf(W);if(i===-1)throw new Error("Could not extract indexURL path from pyodide module location");return t.slice(0,i)}s(Q,"calculateDirname");function Z(e){let t=e.FS,i=e.FS.filesystems.MEMFS,r=e.PATH,a={DIR_MODE:16895,FILE_MODE:33279,mount:function(n){if(!n.opts.fileSystemHandle)throw new Error("opts.fileSystemHandle is required");return i.mount.apply(null,arguments)},syncfs:async(n,o,c)=>{try{let l=a.getLocalSet(n),d=await a.getRemoteSet(n),u=o?d:l,m=o?l:d;await a.reconcile(n,u,m),c(null)}catch(l){c(l)}},getLocalSet:n=>{let o=Object.create(null);function c(u){return u!=="."&&u!==".."}s(c,"isRealDir");function l(u){return m=>r.join2(u,m)}s(l,"toAbsolute");let d=t.readdir(n.mountpoint).filter(c).map(l(n.mountpoint));for(;d.length;){let u=d.pop(),m=t.stat(u);t.isDir(m.mode)&&d.push.apply(d,t.readdir(u).filter(c).map(l(u))),o[u]={timestamp:m.mtime,mode:m.mode}}return{type:"local",entries:o}},getRemoteSet:async n=>{let o=Object.create(null),c=await Ee(n.opts.fileSystemHandle);for(let[l,d]of c)l!=="."&&(o[r.join2(n.mountpoint,l)]={timestamp:d.kind==="file"?new Date((await d.getFile()).lastModified):new Date,mode:d.kind==="file"?a.FILE_MODE:a.DIR_MODE});return{type:"remote",entries:o,handles:c}},loadLocalEntry:n=>{let c=t.lookupPath(n).node,l=t.stat(n);if(t.isDir(l.mode))return{timestamp:l.mtime,mode:l.mode};if(t.isFile(l.mode))return c.contents=i.getFileDataAsTypedArray(c),{timestamp:l.mtime,mode:l.mode,contents:c.contents};throw new Error("node type not supported")},storeLocalEntry:(n,o)=>{if(t.isDir(o.mode))t.mkdirTree(n,o.mode);else if(t.isFile(o.mode))t.writeFile(n,o.contents,{canOwn:!0});else throw new Error("node type not supported");t.chmod(n,o.mode),t.utime(n,o.timestamp,o.timestamp)},removeLocalEntry:n=>{var o=t.stat(n);t.isDir(o.mode)?t.rmdir(n):t.isFile(o.mode)&&t.unlink(n)},loadRemoteEntry:async n=>{if(n.kind==="file"){let o=await n.getFile();return{contents:new Uint8Array(await o.arrayBuffer()),mode:a.FILE_MODE,timestamp:new Date(o.lastModified)}}else{if(n.kind==="directory")return{mode:a.DIR_MODE,timestamp:new Date};throw new Error("unknown kind: "+n.kind)}},storeRemoteEntry:async(n,o,c)=>{let l=n.get(r.dirname(o)),d=t.isFile(c.mode)?await l.getFileHandle(r.basename(o),{create:!0}):await l.getDirectoryHandle(r.basename(o),{create:!0});if(d.kind==="file"){let u=await d.createWritable();await u.write(c.contents),await u.close()}n.set(o,d)},removeRemoteEntry:async(n,o)=>{await n.get(r.dirname(o)).removeEntry(r.basename(o)),n.delete(o)},reconcile:async(n,o,c)=>{let l=0,d=[];Object.keys(o.entries).forEach(function(f){let v=o.entries[f],N=c.entries[f];(!N||t.isFile(v.mode)&&v.timestamp.getTime()>N.timestamp.getTime())&&(d.push(f),l++)}),d.sort();let u=[];if(Object.keys(c.entries).forEach(function(f){o.entries[f]||(u.push(f),l++)}),u.sort().reverse(),!l)return;let m=o.type==="remote"?o.handles:c.handles;for(let f of d){let v=r.normalize(f.replace(n.mountpoint,"/")).substring(1);if(c.type==="local"){let N=m.get(v),te=await a.loadRemoteEntry(N);a.storeLocalEntry(f,te)}else{let N=a.loadLocalEntry(f);await a.storeRemoteEntry(m,v,N)}}for(let f of u)if(c.type==="local")a.removeLocalEntry(f);else{let v=r.normalize(f.replace(n.mountpoint,"/")).substring(1);await a.removeRemoteEntry(m,v)}}};e.FS.filesystems.NATIVEFS_ASYNC=a}s(Z,"initializeNativeFS");var Ee=s(async e=>{let t=[];async function i(a){for await(let n of a.values())t.push(n),n.kind==="directory"&&await i(n)}s(i,"collect"),await i(e);let r=new Map;r.set(".",e);for(let a of t){let n=(await e.resolve(a)).join("/");r.set(n,a)}return r},"getFsHandles");function ee(e){let t={noImageDecoding:!0,noAudioDecoding:!0,noWasmDecoding:!1,preRun:Ie(e),quit(i,r){throw t.exited={status:i,toThrow:r},r},print:e.stdout,printErr:e.stderr,thisProgram:e._sysExecutable,arguments:e.args,API:{config:e},locateFile:i=>e.indexURL+i,instantiateWasm:Pe(e.indexURL)};return t}s(ee,"createSettings");function Se(e){return function(t){let i="/";try{t.FS.mkdirTree(e)}catch(r){console.error(`Error occurred while making a home directory '${e}':`),console.error(r),console.error(`Using '${i}' for a home directory instead`),e=i}t.FS.chdir(e)}}s(Se,"createHomeDirectory");function we(e){return function(t){Object.assign(t.ENV,e)}}s(we,"setEnvironment");function Ne(e){return e?[async t=>{t.addRunDependency("fsInitHook");try{await e(t.FS,{sitePackages:t.API.sitePackages})}finally{t.removeRunDependency("fsInitHook")}}]:[]}s(Ne,"callFsInitHook");function _e(e){let t=G(e);return async i=>{let r=i._py_version_major(),a=i._py_version_minor();i.FS.mkdirTree("/lib"),i.API.sitePackages=`/lib/python${r}.${a}/site-packages`,i.FS.mkdirTree(i.API.sitePackages),i.addRunDependency("install-stdlib");try{let n=await t;i.FS.writeFile(`/lib/python${r}${a}.zip`,n)}catch(n){console.error("Error occurred while installing the standard library:"),console.error(n)}finally{i.removeRunDependency("install-stdlib")}}}s(_e,"installStdlib");function Ie(e){let t;return e.stdLibURL!=null?t=e.stdLibURL:t=e.indexURL+"python_stdlib.zip",[...Ne(e.fsInit),_e(t),Se(e.env.HOME),we(e.env),Z]}s(Ie,"getFileSystemInitializationFuncs");function Pe(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:i}=k(e+"pyodide.asm.wasm");return function(r,a){return async function(){try{let n;i?n=await WebAssembly.instantiateStreaming(i,r):n=await WebAssembly.instantiate(await t,r);let{instance:o,module:c}=n;a(o,c)}catch(n){console.warn("wasm instantiation failed!"),console.warn(n)}}(),{}}}s(Pe,"getInstantiateWasmFunc");var x="0.27.5";async function B(e={}){var u,m;await C();let t=e.indexURL||await Q();t=D(t),t.endsWith("/")||(t+="/"),e.indexURL=t;let i={fullStdLib:!1,jsglobals:globalThis,stdin:globalThis.prompt?globalThis.prompt:void 0,lockFileURL:t+"pyodide-lock.json",args:[],env:{},packageCacheDir:t,packages:[],enableRunUntilComplete:!1,checkAPIVersion:!0,BUILD_ID:"bd0388b62e760f8ba04185eb443fec955f25434f49c7b951efe5b1f792dbe5d4"},r=Object.assign(i,e);(u=r.env).HOME??(u.HOME="/home/pyodide"),(m=r.env).PYTHONINSPECT??(m.PYTHONINSPECT="1");let a=ee(r),n=a.API;if(n.lockFilePromise=X(r.lockFileURL),typeof _createPyodideModule!="function"){let f=`${r.indexURL}pyodide.asm.js`;await R(f)}let o;if(e._loadSnapshot){let f=await e._loadSnapshot;ArrayBuffer.isView(f)?o=f:o=new Uint8Array(f),a.noInitialRun=!0,a.INITIAL_MEMORY=o.length}let c=await _createPyodideModule(a);if(a.exited)throw a.exited.toThrow;if(e.pyproxyToStringRepr&&n.setPyProxyToStringMethod(!0),n.version!==x&&r.checkAPIVersion)throw new Error(`Pyodide version does not match: '${x}' <==> '${n.version}'. If you updated the Pyodide version, make sure you also updated the 'indexURL' parameter passed to loadPyodide.`);c.locateFile=f=>{throw new Error("Didn't expect to load any more file_packager files!")};let l;o&&(l=n.restoreSnapshot(o));let d=n.finalizeBootstrap(l,e._snapshotDeserializer);return n.sys.path.insert(0,n.config.env.HOME),d.version.includes("dev")||n.setCdnUrl(`https://cdn.jsdelivr.net/pyodide/v${d.version}/full/`),n._pyodide.set_excepthook(),await n.packageIndexReady,n.initializeStreams(r.stdin,r.stdout,r.stderr),d}s(B,"loadPyodide");globalThis.loadPyodide=B;return ce(Fe);})(); +try{Object.assign(exports,loadPyodide)}catch(_){} +globalThis.loadPyodide=loadPyodide.loadPyodide; +//# sourceMappingURL=pyodide.js.map diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.mjs b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.mjs new file mode 100644 index 0000000000..4f872cce4b --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/pyodide.mjs @@ -0,0 +1,4 @@ +var Q=Object.defineProperty;var s=(e,t)=>Q(e,"name",{value:t,configurable:!0}),R=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,o)=>(typeof require<"u"?require:t)[o]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')});function Z(e){return!isNaN(parseFloat(e))&&isFinite(e)}s(Z,"_isNumber");function E(e){return e.charAt(0).toUpperCase()+e.substring(1)}s(E,"_capitalize");function x(e){return function(){return this[e]}}s(x,"_getter");var w=["isConstructor","isEval","isNative","isToplevel"],N=["columnNumber","lineNumber"],_=["fileName","functionName","source"],ee=["args"],te=["evalOrigin"],P=w.concat(N,_,ee,te);function p(e){if(e)for(var t=0;t-1&&(n=n.replace(/eval code/g,"eval").replace(/(\(eval at [^()]*)|(,.*$)/g,""));var i=n.replace(/^\s+/,"").replace(/\(eval code/g,"(").replace(/^.*?\s+/,""),c=i.match(/ (\(.+\)$)/);i=c?i.replace(c[0],""):i;var l=this.extractLocation(c?c[1]:i),d=c&&i||void 0,u=["eval",""].indexOf(l[0])>-1?void 0:l[0];return new k({functionName:d,fileName:u,lineNumber:l[1],columnNumber:l[2],source:n})},this)},"ErrorStackParser$$parseV8OrIE"),parseFFOrSafari:s(function(r){var a=r.stack.split(` +`).filter(function(n){return!n.match(t)},this);return a.map(function(n){if(n.indexOf(" > eval")>-1&&(n=n.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),n.indexOf("@")===-1&&n.indexOf(":")===-1)return new k({functionName:n});var i=/((.*".+"[^@]*)?[^@]*)(?:@)/,c=n.match(i),l=c&&c[1]?c[1]:void 0,d=this.extractLocation(n.replace(i,""));return new k({functionName:l,fileName:d[0],lineNumber:d[1],columnNumber:d[2],source:n})},this)},"ErrorStackParser$$parseFFOrSafari")}}s(ne,"ErrorStackParser");var re=new ne;var C=re;var g=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string"&&!process.browser,A=g&&typeof module<"u"&&typeof module.exports<"u"&&typeof R<"u"&&typeof __dirname<"u",W=g&&!A,Ne=typeof globalThis.Bun<"u",ie=typeof Deno<"u",B=!g&&!ie,$=B&&typeof window=="object"&&typeof document=="object"&&typeof document.createElement=="function"&&"sessionStorage"in window&&typeof importScripts!="function",j=B&&typeof importScripts=="function"&&typeof self=="object",_e=typeof navigator=="object"&&typeof navigator.userAgent=="string"&&navigator.userAgent.indexOf("Chrome")==-1&&navigator.userAgent.indexOf("Safari")>-1;var z,D,V,H,L;async function T(){if(!g||(z=(await import("node:url")).default,H=await import("node:fs"),L=await import("node:fs/promises"),V=(await import("node:vm")).default,D=await import("node:path"),U=D.sep,typeof R<"u"))return;let e=H,t=await import("node:crypto"),o=await import("ws"),r=await import("node:child_process"),a={fs:e,crypto:t,ws:o,child_process:r};globalThis.require=function(n){return a[n]}}s(T,"initNodeModules");function oe(e,t){return D.resolve(t||".",e)}s(oe,"node_resolvePath");function ae(e,t){return t===void 0&&(t=location),new URL(e,t).toString()}s(ae,"browser_resolvePath");var O;g?O=oe:O=ae;var U;g||(U="/");function se(e,t){return e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?{response:fetch(e)}:{binary:L.readFile(e).then(o=>new Uint8Array(o.buffer,o.byteOffset,o.byteLength))}}s(se,"node_getBinaryResponse");function ce(e,t){let o=new URL(e,location);return{response:fetch(o,t?{integrity:t}:{})}}s(ce,"browser_getBinaryResponse");var F;g?F=se:F=ce;async function q(e,t){let{response:o,binary:r}=F(e,t);if(r)return r;let a=await o;if(!a.ok)throw new Error(`Failed to load '${e}': request failed.`);return new Uint8Array(await a.arrayBuffer())}s(q,"loadBinaryFile");var I;if($)I=s(async e=>await import(e),"loadScript");else if(j)I=s(async e=>{try{globalThis.importScripts(e)}catch(t){if(t instanceof TypeError)await import(e);else throw t}},"loadScript");else if(g)I=le;else throw new Error("Cannot determine runtime environment");async function le(e){e.startsWith("file://")&&(e=e.slice(7)),e.includes("://")?V.runInThisContext(await(await fetch(e)).text()):await import(z.pathToFileURL(e).href)}s(le,"nodeLoadScript");async function J(e){if(g){await T();let t=await L.readFile(e,{encoding:"utf8"});return JSON.parse(t)}else return await(await fetch(e)).json()}s(J,"loadLockFile");async function K(){if(A)return __dirname;let e;try{throw new Error}catch(r){e=r}let t=C.parse(e)[0].fileName;if(g&&!t.startsWith("file://")&&(t=`file://${t}`),W){let r=await import("node:path");return(await import("node:url")).fileURLToPath(r.dirname(t))}let o=t.lastIndexOf(U);if(o===-1)throw new Error("Could not extract indexURL path from pyodide module location");return t.slice(0,o)}s(K,"calculateDirname");function Y(e){let t=e.FS,o=e.FS.filesystems.MEMFS,r=e.PATH,a={DIR_MODE:16895,FILE_MODE:33279,mount:function(n){if(!n.opts.fileSystemHandle)throw new Error("opts.fileSystemHandle is required");return o.mount.apply(null,arguments)},syncfs:async(n,i,c)=>{try{let l=a.getLocalSet(n),d=await a.getRemoteSet(n),u=i?d:l,m=i?l:d;await a.reconcile(n,u,m),c(null)}catch(l){c(l)}},getLocalSet:n=>{let i=Object.create(null);function c(u){return u!=="."&&u!==".."}s(c,"isRealDir");function l(u){return m=>r.join2(u,m)}s(l,"toAbsolute");let d=t.readdir(n.mountpoint).filter(c).map(l(n.mountpoint));for(;d.length;){let u=d.pop(),m=t.stat(u);t.isDir(m.mode)&&d.push.apply(d,t.readdir(u).filter(c).map(l(u))),i[u]={timestamp:m.mtime,mode:m.mode}}return{type:"local",entries:i}},getRemoteSet:async n=>{let i=Object.create(null),c=await de(n.opts.fileSystemHandle);for(let[l,d]of c)l!=="."&&(i[r.join2(n.mountpoint,l)]={timestamp:d.kind==="file"?new Date((await d.getFile()).lastModified):new Date,mode:d.kind==="file"?a.FILE_MODE:a.DIR_MODE});return{type:"remote",entries:i,handles:c}},loadLocalEntry:n=>{let c=t.lookupPath(n).node,l=t.stat(n);if(t.isDir(l.mode))return{timestamp:l.mtime,mode:l.mode};if(t.isFile(l.mode))return c.contents=o.getFileDataAsTypedArray(c),{timestamp:l.mtime,mode:l.mode,contents:c.contents};throw new Error("node type not supported")},storeLocalEntry:(n,i)=>{if(t.isDir(i.mode))t.mkdirTree(n,i.mode);else if(t.isFile(i.mode))t.writeFile(n,i.contents,{canOwn:!0});else throw new Error("node type not supported");t.chmod(n,i.mode),t.utime(n,i.timestamp,i.timestamp)},removeLocalEntry:n=>{var i=t.stat(n);t.isDir(i.mode)?t.rmdir(n):t.isFile(i.mode)&&t.unlink(n)},loadRemoteEntry:async n=>{if(n.kind==="file"){let i=await n.getFile();return{contents:new Uint8Array(await i.arrayBuffer()),mode:a.FILE_MODE,timestamp:new Date(i.lastModified)}}else{if(n.kind==="directory")return{mode:a.DIR_MODE,timestamp:new Date};throw new Error("unknown kind: "+n.kind)}},storeRemoteEntry:async(n,i,c)=>{let l=n.get(r.dirname(i)),d=t.isFile(c.mode)?await l.getFileHandle(r.basename(i),{create:!0}):await l.getDirectoryHandle(r.basename(i),{create:!0});if(d.kind==="file"){let u=await d.createWritable();await u.write(c.contents),await u.close()}n.set(i,d)},removeRemoteEntry:async(n,i)=>{await n.get(r.dirname(i)).removeEntry(r.basename(i)),n.delete(i)},reconcile:async(n,i,c)=>{let l=0,d=[];Object.keys(i.entries).forEach(function(f){let y=i.entries[f],S=c.entries[f];(!S||t.isFile(y.mode)&&y.timestamp.getTime()>S.timestamp.getTime())&&(d.push(f),l++)}),d.sort();let u=[];if(Object.keys(c.entries).forEach(function(f){i.entries[f]||(u.push(f),l++)}),u.sort().reverse(),!l)return;let m=i.type==="remote"?i.handles:c.handles;for(let f of d){let y=r.normalize(f.replace(n.mountpoint,"/")).substring(1);if(c.type==="local"){let S=m.get(y),X=await a.loadRemoteEntry(S);a.storeLocalEntry(f,X)}else{let S=a.loadLocalEntry(f);await a.storeRemoteEntry(m,y,S)}}for(let f of u)if(c.type==="local")a.removeLocalEntry(f);else{let y=r.normalize(f.replace(n.mountpoint,"/")).substring(1);await a.removeRemoteEntry(m,y)}}};e.FS.filesystems.NATIVEFS_ASYNC=a}s(Y,"initializeNativeFS");var de=s(async e=>{let t=[];async function o(a){for await(let n of a.values())t.push(n),n.kind==="directory"&&await o(n)}s(o,"collect"),await o(e);let r=new Map;r.set(".",e);for(let a of t){let n=(await e.resolve(a)).join("/");r.set(n,a)}return r},"getFsHandles");function G(e){let t={noImageDecoding:!0,noAudioDecoding:!0,noWasmDecoding:!1,preRun:ge(e),quit(o,r){throw t.exited={status:o,toThrow:r},r},print:e.stdout,printErr:e.stderr,thisProgram:e._sysExecutable,arguments:e.args,API:{config:e},locateFile:o=>e.indexURL+o,instantiateWasm:ye(e.indexURL)};return t}s(G,"createSettings");function ue(e){return function(t){let o="/";try{t.FS.mkdirTree(e)}catch(r){console.error(`Error occurred while making a home directory '${e}':`),console.error(r),console.error(`Using '${o}' for a home directory instead`),e=o}t.FS.chdir(e)}}s(ue,"createHomeDirectory");function fe(e){return function(t){Object.assign(t.ENV,e)}}s(fe,"setEnvironment");function me(e){return e?[async t=>{t.addRunDependency("fsInitHook");try{await e(t.FS,{sitePackages:t.API.sitePackages})}finally{t.removeRunDependency("fsInitHook")}}]:[]}s(me,"callFsInitHook");function pe(e){let t=q(e);return async o=>{let r=o._py_version_major(),a=o._py_version_minor();o.FS.mkdirTree("/lib"),o.API.sitePackages=`/lib/python${r}.${a}/site-packages`,o.FS.mkdirTree(o.API.sitePackages),o.addRunDependency("install-stdlib");try{let n=await t;o.FS.writeFile(`/lib/python${r}${a}.zip`,n)}catch(n){console.error("Error occurred while installing the standard library:"),console.error(n)}finally{o.removeRunDependency("install-stdlib")}}}s(pe,"installStdlib");function ge(e){let t;return e.stdLibURL!=null?t=e.stdLibURL:t=e.indexURL+"python_stdlib.zip",[...me(e.fsInit),pe(t),ue(e.env.HOME),fe(e.env),Y]}s(ge,"getFileSystemInitializationFuncs");function ye(e){if(typeof WasmOffsetConverter<"u")return;let{binary:t,response:o}=F(e+"pyodide.asm.wasm");return function(r,a){return async function(){try{let n;o?n=await WebAssembly.instantiateStreaming(o,r):n=await WebAssembly.instantiate(await t,r);let{instance:i,module:c}=n;a(i,c)}catch(n){console.warn("wasm instantiation failed!"),console.warn(n)}}(),{}}}s(ye,"getInstantiateWasmFunc");var M="0.27.5";async function $e(e={}){var u,m;await T();let t=e.indexURL||await K();t=O(t),t.endsWith("/")||(t+="/"),e.indexURL=t;let o={fullStdLib:!1,jsglobals:globalThis,stdin:globalThis.prompt?globalThis.prompt:void 0,lockFileURL:t+"pyodide-lock.json",args:[],env:{},packageCacheDir:t,packages:[],enableRunUntilComplete:!1,checkAPIVersion:!0,BUILD_ID:"bd0388b62e760f8ba04185eb443fec955f25434f49c7b951efe5b1f792dbe5d4"},r=Object.assign(o,e);(u=r.env).HOME??(u.HOME="/home/pyodide"),(m=r.env).PYTHONINSPECT??(m.PYTHONINSPECT="1");let a=G(r),n=a.API;if(n.lockFilePromise=J(r.lockFileURL),typeof _createPyodideModule!="function"){let f=`${r.indexURL}pyodide.asm.js`;await I(f)}let i;if(e._loadSnapshot){let f=await e._loadSnapshot;ArrayBuffer.isView(f)?i=f:i=new Uint8Array(f),a.noInitialRun=!0,a.INITIAL_MEMORY=i.length}let c=await _createPyodideModule(a);if(a.exited)throw a.exited.toThrow;if(e.pyproxyToStringRepr&&n.setPyProxyToStringMethod(!0),n.version!==M&&r.checkAPIVersion)throw new Error(`Pyodide version does not match: '${M}' <==> '${n.version}'. If you updated the Pyodide version, make sure you also updated the 'indexURL' parameter passed to loadPyodide.`);c.locateFile=f=>{throw new Error("Didn't expect to load any more file_packager files!")};let l;i&&(l=n.restoreSnapshot(i));let d=n.finalizeBootstrap(l,e._snapshotDeserializer);return n.sys.path.insert(0,n.config.env.HOME),d.version.includes("dev")||n.setCdnUrl(`https://cdn.jsdelivr.net/pyodide/v${d.version}/full/`),n._pyodide.set_excepthook(),await n.packageIndexReady,n.initializeStreams(r.stdin,r.stdout,r.stderr),d}s($e,"loadPyodide");export{$e as loadPyodide,M as version}; +//# sourceMappingURL=pyodide.mjs.map diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/python_stdlib.zip b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/python_stdlib.zip new file mode 100644 index 0000000000..f1193b6261 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/pyodide/python_stdlib.zip differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js new file mode 100644 index 0000000000..40c6083afc --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python-worker.js @@ -0,0 +1,230 @@ +self.pyodideUrl = null; +self.appPackageUrl = null; +self.micropipIncludePre = false; +self.pythonModuleName = null; +self.documentUrl = null; +self.initialized = false; +self.flet_js = {}; // namespace for Python global functions + +// Flipped to true right before `runpy.run_module` runs the user app. +// Until then, stdout/stderr is bootstrap diagnostics ("Downloading app +// archive", micropip install logs, etc.) — those go to the dev console +// rather than the user-visible Console pane. +self.userAppRunning = false; +self.flet_js.userAppStarting = function () { + self.userAppRunning = true; +}; +self.sendPythonOutput = function (text, isStderr) { + // No bridge yet, or not in user-code mode — surface in dev console. + // The boot script registers `flet_js.send_python_output` after the + // user-app deps are installed (msgpack typically rides in via flet); + // if msgpack isn't available it stays unset and prints fall through + // to the dev console silently. + if (!self.userAppRunning || !(self.flet_js && self.flet_js.send_python_output)) { + if (isStderr) { + console.error(text); + } else { + console.log(text); + } + return; + } + // Pyodide invokes stdout/stderr hooks with the GIL released, so + // calling back into Python synchronously throws NoGilError. Defer + // to a microtask — by the time it runs, the GIL state is normal. + queueMicrotask(function () { + self.flet_js.send_python_output(text, isStderr); + }); +}; + +self.initPyodide = async function () { + try { + importScripts(self.pyodideUrl); + self.pyodide = await loadPyodide({ + stdout: (text) => self.sendPythonOutput(text, false), + stderr: (text) => self.sendPythonOutput(text, true), + }); + self.pyodide.registerJsModule("flet_js", flet_js); + self.pyodide.globals.set("app_package_url", self.appPackageUrl); + self.pyodide.globals.set("python_module_name", self.pythonModuleName); + self.pyodide.globals.set("micropip_include_pre", self.micropipIncludePre); + flet_js.documentUrl = documentUrl; + await self.pyodide.runPythonAsync(` + import flet_js, os, runpy, sys, traceback + from pyodide.http import pyfetch + + py_args = flet_js.args.to_py() if flet_js.args else None + + if "app_package_url" in py_args: + app_package_url = py_args["app_package_url"] + + if "python_module_name" in py_args: + python_module_name = py_args["python_module_name"] + + if python_module_name is None: + python_module_name = "main" + + if "micropip_include_pre" in py_args: + micropip_include_pre = py_args["micropip_include_pre"] + + if micropip_include_pre is None: + micropip_include_pre = False + + print("python_module_name:", python_module_name) + print("micropip_include_pre:", micropip_include_pre) + + if "script" not in py_args: + print("Downloading app archive") + response = await pyfetch(app_package_url) + # Pick format from the URL's path extension. Pyodide's + # filename-based sniff trips over query strings like + # ?v=42. We only support zip and tar.gz (matching what + # our server and "flet publish" emit). + from urllib.parse import urlparse + _archive_path = urlparse(app_package_url).path.lower() + if _archive_path.endswith(".zip"): + _archive_format = "zip" + elif _archive_path.endswith((".tar.gz", ".tgz")): + _archive_format = "gztar" + else: + raise ValueError( + f"Unsupported app package URL: {app_package_url} " + "(expected .zip or .tar.gz)" + ) + await response.unpack_archive(format=_archive_format) + else: + print("Saving script to a file") + with open(f"{python_module_name}.py", "w") as f: + f.write(py_args["script"]); + + pkgs_path = "__pypackages__" + if os.path.exists(pkgs_path): + print(f"Adding {pkgs_path} to sys.path") + sys.path.insert(0, pkgs_path) + + async def ensure_micropip(): + try: + import micropip + except ImportError: + import pyodide_js + await pyodide_js.loadPackage("micropip") + import micropip + return micropip + + if os.path.exists("requirements.txt"): + with open("requirements.txt", "r") as f: + deps = [ + line + for req in f + if (line := req.strip()) and not line.startswith("#") + ] + if deps: + micropip = await ensure_micropip() + print("Loading requirements.txt:", deps) + await micropip.install(deps, pre=micropip_include_pre) + + if os.path.exists("pyproject.toml"): + import tomllib + with open("pyproject.toml", "rb") as f: + pyproject = tomllib.load(f) + project_deps = list( + pyproject.get("project", {}).get("dependencies", []) or [] + ) + web_deps = list( + pyproject.get("tool", {}) + .get("flet", {}) + .get("web", {}) + .get("dependencies", []) + or [] + ) + # [tool.flet.web].dependencies overrides [project].dependencies + # by package name — install in order so the web-specific specs + # win through micropip's last-writer-wins dedupe. + pyproject_deps = project_deps + web_deps + if pyproject_deps: + micropip = await ensure_micropip() + print("Loading pyproject.toml deps:", pyproject_deps) + await micropip.install(pyproject_deps, pre=micropip_include_pre) + + if "dependencies" in py_args: + micropip = await ensure_micropip() + await micropip.install(py_args["dependencies"], pre=micropip_include_pre) + + # Install the python_output bridge. msgpack normally rides in + # with the user's flet dependency, but apps without a flet dep + # (or without a pyproject.toml at all) would otherwise leave the + # bridge unregistered and their prints stranded in the dev + # console. Pyodide ships msgpack as a prebuilt package, so we + # load it explicitly when it isn't already importable. + try: + import msgpack as _msgpack + except ImportError: + import pyodide_js + await pyodide_js.loadPackage("msgpack") + import msgpack as _msgpack + + def _send_python_output(text, is_stderr): + flet_js.receive_callback( + _msgpack.packb( + [7, {"text": text, "is_stderr": bool(is_stderr)}] + ) + ) + + flet_js.send_python_output = _send_python_output + + # Flip the worker into "user code" mode so stdout/stderr starts + # flowing to the host page's Console pane instead of dev console. + flet_js.userAppStarting() + + # Execute app. Treat a clean SystemExit (exit() / exit(0)) as + # normal termination so the no-UI path below kicks in instead + # of surfacing a Pyodide traceback. Non-zero codes propagate as + # Script errors. + try: + runpy.run_module(python_module_name, run_name="__main__") + except SystemExit as _exit: + if _exit.code not in (None, 0): + raise + `); + // `start_connection` is registered by `PyodideConnection.__init__`, + // which only runs when the user app calls `ft.run(...)`. If the + // script finished without it (e.g. a print-only test program), + // surface a friendly message instead of a cryptic TypeError. + // The `__flet_no_ui__:` sentinel lets host pages render a + // neutral message rather than a Script error panel. + if (typeof self.flet_js.start_connection !== "function") { + self.postMessage( + "__flet_no_ui__:Script finished without starting a Flet UI.\n" + + "Add ft.run(main) at the end of your script to display the app." + ); + return; + } + await self.flet_js.start_connection(self.receiveCallback); + self.postMessage("initialized"); + } catch (error) { + self.postMessage(error.toString()); + } +}; + +self.receiveCallback = (message) => { + self.postMessage(message.toJs()); +} +// Same channel as `receiveCallback`, exposed under `flet_js` so the +// Python python_output shim can post pre-encoded msgpack frames. +self.flet_js.receive_callback = self.receiveCallback; + +self.onmessage = async (event) => { + // run only once + if (!self.initialized) { + self.initialized = true; + self.pyodideUrl = event.data.pyodideUrl; + self.flet_js.args = event.data.args; + self.documentUrl = event.data.documentUrl; + self.appPackageUrl = event.data.appPackageUrl; + self.micropipIncludePre = event.data.micropipIncludePre; + self.pythonModuleName = event.data.pythonModuleName; + await self.initPyodide(); + } else { + // message + flet_js.send(event.data); + } +}; diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js new file mode 100644 index 0000000000..db2e34a9f0 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/web/python.js @@ -0,0 +1,70 @@ +const defaultPyodideUrl = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js"; + +let _apps = {}; +let _documentUrl = document.URL; + +// This method is called from Dart on backend.connect() +// dartOnMessage is called on backend.onMessage +// it accepts "data" of type JSUint8Array +globalThis.jsConnect = async function(appId, args, dartOnMessage) { + let app = { + "dartOnMessage": dartOnMessage + }; + console.log(`Starting up Python worker: ${appId}, args: ${args}`); + _apps[appId] = app; + app.worker = new Worker("python-worker.js"); + + var error; + app.worker.onmessage = (event) => { + if (typeof event.data === "string") { + if (event.data != "initialized") { + error = event.data; + } + app.onPythonInitialized(); + } else { + app.dartOnMessage(event.data); + } + }; + + let pythonInitialized = new Promise((resolveCallback) => app.onPythonInitialized = resolveCallback); + + // initialize worker + app.worker.postMessage({ + pyodideUrl: flet.noCdn ? flet.pyodideUrl : defaultPyodideUrl, + args: args, + documentUrl: _documentUrl, + appPackageUrl: flet.appPackageUrl, + micropipIncludePre: flet.micropipIncludePre, + pythonModuleName: flet.pythonModuleName + }); + + await pythonInitialized; + + if (error) { + console.log("Python worker init error:", error); + throw error; + } else { + console.log(`Python worker initialized: ${appId}`); + } +} + +// Called from Dart on backend.send +// data is a message serialized to JSUint8Array +globalThis.jsSend = async function(appId, data) { + if (appId in _apps) { + const app = _apps[appId]; + app.worker.postMessage(data); + } +} + +// Called from Dart on channel.disconnect +globalThis.jsDisconnect = async function(appId) { + if (appId in _apps) { + console.log(`Terminating Python worker: ${appId}`); + const app = _apps[appId]; + delete _apps[appId]; + app.worker.terminate(); + app.worker.onmessage = null; + app.worker.onerror = null; + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/.gitignore b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/.gitignore new file mode 100644 index 0000000000..d492d0d98c --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/CMakeLists.txt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/CMakeLists.txt new file mode 100644 index 0000000000..7bddc41709 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project({{ cookiecutter.project_name }} LANGUAGES CXX) + +# The name of the application target. The on-disk name is set in +# runner/CMakeLists.txt to keep Flutter tooling behavior intact. +set(BINARY_NAME "{{ cookiecutter.project_name }}") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/CMakeLists.txt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000000..903f4899d6 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..7e706c9e85 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,35 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + BatteryPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin")); + ConnectivityPlusWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + ScreenBrightnessWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); + ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); + SeriousPythonWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SeriousPythonWindowsPluginCApi")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); + WindowManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowManagerPlugin")); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..dc139d85a9 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..da335d2930 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/flutter/generated_plugins.cmake @@ -0,0 +1,31 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + battery_plus + connectivity_plus + screen_brightness_windows + screen_retriever_windows + serious_python_windows + share_plus + url_launcher_windows + window_manager +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/CMakeLists.txt b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/CMakeLists.txt new file mode 100644 index 0000000000..1f14dcfed7 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Keep the target name stable for Flutter tooling, but set the output name. +# OUTPUT_NAME controls the on-disk executable name (artifact). +set_target_properties(${BINARY_NAME} PROPERTIES OUTPUT_NAME "{{ cookiecutter.artifact_name }}") + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/Runner.rc b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/Runner.rc new file mode 100644 index 0000000000..60a1e5bb96 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "{{ cookiecutter.company_name }}" "\0" + VALUE "FileDescription", "{{ cookiecutter.product_name }}" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "{{ cookiecutter.artifact_name }}" "\0" + VALUE "LegalCopyright", "{{ cookiecutter.copyright }}" "\0" + VALUE "OriginalFilename", "{{ cookiecutter.artifact_name }}.exe" "\0" + VALUE "ProductName", "{{ cookiecutter.product_name }}" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/flutter_window.cpp b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/flutter_window.cpp new file mode 100644 index 0000000000..955ee3038f --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/flutter_window.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/flutter_window.h new file mode 100644 index 0000000000..6da0652f05 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp new file mode 100644 index 0000000000..7c91006a81 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"{{ cookiecutter.product_name }}", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/resource.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/resource.h new file mode 100644 index 0000000000..cb9fd879eb --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{ "{{" }}NO_DEPENDENCIES{{ "}}" }} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/resources/app_icon.ico b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000..c04e20caf6 Binary files /dev/null and b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/resources/app_icon.ico differ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/runner.exe.manifest b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/runner.exe.manifest new file mode 100644 index 0000000000..153653e8d6 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/utils.cpp b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/utils.cpp new file mode 100644 index 0000000000..3a0b46511a --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/utils.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/utils.h new file mode 100644 index 0000000000..3879d54755 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/win32_window.cpp b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/win32_window.cpp new file mode 100644 index 0000000000..60608d0fe5 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/win32_window.h b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/win32_window.h new file mode 100644 index 0000000000..e901dde684 --- /dev/null +++ b/sdk/python/templates/build/{{cookiecutter.out_dir}}/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/sdk/python/uv.lock b/sdk/python/uv.lock deleted file mode 100644 index 582ab0ebdd..0000000000 --- a/sdk/python/uv.lock +++ /dev/null @@ -1,2132 +0,0 @@ -version = 1 -requires-python = ">=3.10, <3.14" -resolution-markers = [ - "(python_full_version >= '3.12' and sys_platform == 'darwin') or (python_full_version >= '3.12' and sys_platform == 'win32')", - "(python_full_version == '3.11.*' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and sys_platform == 'win32')", - "(python_full_version < '3.11' and sys_platform == 'darwin') or (python_full_version < '3.11' and sys_platform == 'win32')", - "python_full_version >= '3.12' and sys_platform != 'darwin' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'win32'", - "python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'win32'", -] - -[manifest] -members = [ - "flet", - "flet-cli", - "flet-desktop", - "flet-project", - "flet-web", -] - -[[package]] -name = "altgraph" -version = "0.17.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/de/a8/7145824cf0b9e3c28046520480f207df47e927df83aa9555fb47f8505922/altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406", size = 48418 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/3f/3bc3f1d83f6e4a7fcb834d3720544ca597590425be5ba9db032b2bf322a2/altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff", size = 21212 }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 }, -] - -[[package]] -name = "arrow" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "python-dateutil" }, - { name = "types-python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 }, -] - -[[package]] -name = "binaryornot" -version = "0.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "chardet" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/fe/7ebfec74d49f97fc55cd38240c7a7d08134002b1e14be8c3897c0dd5e49b/binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", size = 371054 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4", size = 9006 }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618 }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, -] - -[[package]] -name = "cfgv" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, -] - -[[package]] -name = "chardet" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385 }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 }, - { url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 }, - { url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 }, - { url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 }, - { url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 }, - { url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 }, - { url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 }, - { url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 }, - { url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 }, - { url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 }, - { url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 }, - { url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 }, - { url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 }, - { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 }, - { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 }, - { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 }, - { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 }, - { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 }, - { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 }, - { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 }, - { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 }, - { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 }, - { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 }, - { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 }, - { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 }, - { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 }, - { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, - { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, - { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, - { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, - { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, - { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, - { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, - { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, - { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, - { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, - { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, - { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, - { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, - { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, - { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, - { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, - { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, - { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, - { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, - { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, - { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, - { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, - { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, - { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, - { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, - { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, - { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, -] - -[[package]] -name = "click" -version = "8.1.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, -] - -[[package]] -name = "contourpy" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, - { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, - { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061 }, - { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956 }, - { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872 }, - { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027 }, - { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641 }, - { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075 }, - { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534 }, - { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188 }, - { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636 }, - { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636 }, - { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053 }, - { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985 }, - { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750 }, - { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246 }, - { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728 }, - { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762 }, - { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196 }, - { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017 }, - { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580 }, - { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530 }, - { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688 }, - { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331 }, - { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963 }, - { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681 }, - { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674 }, - { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480 }, - { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489 }, - { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042 }, - { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630 }, - { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670 }, - { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694 }, - { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986 }, - { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060 }, - { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747 }, - { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895 }, - { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098 }, - { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535 }, - { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096 }, - { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090 }, - { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643 }, - { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443 }, - { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865 }, - { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162 }, - { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355 }, - { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935 }, - { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168 }, - { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550 }, - { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214 }, - { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681 }, - { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101 }, - { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, - { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807 }, - { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729 }, - { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791 }, -] - -[[package]] -name = "cookiecutter" -version = "2.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "arrow" }, - { name = "binaryornot" }, - { name = "click" }, - { name = "jinja2" }, - { name = "python-slugify" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "rich" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/52/17/9f2cd228eb949a91915acd38d3eecdc9d8893dde353b603f0db7e9f6be55/cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c", size = 158767 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d", size = 39177 }, -] - -[[package]] -name = "cryptography" -version = "44.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cd/25/4ce80c78963834b8a9fd1cc1266be5ed8d1840785c0f2e1b73b8d128d505/cryptography-44.0.2.tar.gz", hash = "sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0", size = 710807 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/ef/83e632cfa801b221570c5f58c0369db6fa6cef7d9ff859feab1aae1a8a0f/cryptography-44.0.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7", size = 6676361 }, - { url = "https://files.pythonhosted.org/packages/30/ec/7ea7c1e4c8fc8329506b46c6c4a52e2f20318425d48e0fe597977c71dbce/cryptography-44.0.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1", size = 3952350 }, - { url = "https://files.pythonhosted.org/packages/27/61/72e3afdb3c5ac510330feba4fc1faa0fe62e070592d6ad00c40bb69165e5/cryptography-44.0.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb", size = 4166572 }, - { url = "https://files.pythonhosted.org/packages/26/e4/ba680f0b35ed4a07d87f9e98f3ebccb05091f3bf6b5a478b943253b3bbd5/cryptography-44.0.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843", size = 3958124 }, - { url = "https://files.pythonhosted.org/packages/9c/e8/44ae3e68c8b6d1cbc59040288056df2ad7f7f03bbcaca6b503c737ab8e73/cryptography-44.0.2-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5", size = 3678122 }, - { url = "https://files.pythonhosted.org/packages/27/7b/664ea5e0d1eab511a10e480baf1c5d3e681c7d91718f60e149cec09edf01/cryptography-44.0.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c", size = 4191831 }, - { url = "https://files.pythonhosted.org/packages/2a/07/79554a9c40eb11345e1861f46f845fa71c9e25bf66d132e123d9feb8e7f9/cryptography-44.0.2-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a", size = 3960583 }, - { url = "https://files.pythonhosted.org/packages/bb/6d/858e356a49a4f0b591bd6789d821427de18432212e137290b6d8a817e9bf/cryptography-44.0.2-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308", size = 4191753 }, - { url = "https://files.pythonhosted.org/packages/b2/80/62df41ba4916067fa6b125aa8c14d7e9181773f0d5d0bd4dcef580d8b7c6/cryptography-44.0.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688", size = 4079550 }, - { url = "https://files.pythonhosted.org/packages/f3/cd/2558cc08f7b1bb40683f99ff4327f8dcfc7de3affc669e9065e14824511b/cryptography-44.0.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7", size = 4298367 }, - { url = "https://files.pythonhosted.org/packages/71/59/94ccc74788945bc3bd4cf355d19867e8057ff5fdbcac781b1ff95b700fb1/cryptography-44.0.2-cp37-abi3-win32.whl", hash = "sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79", size = 2772843 }, - { url = "https://files.pythonhosted.org/packages/ca/2c/0d0bbaf61ba05acb32f0841853cfa33ebb7a9ab3d9ed8bb004bd39f2da6a/cryptography-44.0.2-cp37-abi3-win_amd64.whl", hash = "sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa", size = 3209057 }, - { url = "https://files.pythonhosted.org/packages/9e/be/7a26142e6d0f7683d8a382dd963745e65db895a79a280a30525ec92be890/cryptography-44.0.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3", size = 6677789 }, - { url = "https://files.pythonhosted.org/packages/06/88/638865be7198a84a7713950b1db7343391c6066a20e614f8fa286eb178ed/cryptography-44.0.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639", size = 3951919 }, - { url = "https://files.pythonhosted.org/packages/d7/fc/99fe639bcdf58561dfad1faa8a7369d1dc13f20acd78371bb97a01613585/cryptography-44.0.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd", size = 4167812 }, - { url = "https://files.pythonhosted.org/packages/53/7b/aafe60210ec93d5d7f552592a28192e51d3c6b6be449e7fd0a91399b5d07/cryptography-44.0.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181", size = 3958571 }, - { url = "https://files.pythonhosted.org/packages/16/32/051f7ce79ad5a6ef5e26a92b37f172ee2d6e1cce09931646eef8de1e9827/cryptography-44.0.2-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea", size = 3679832 }, - { url = "https://files.pythonhosted.org/packages/78/2b/999b2a1e1ba2206f2d3bca267d68f350beb2b048a41ea827e08ce7260098/cryptography-44.0.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699", size = 4193719 }, - { url = "https://files.pythonhosted.org/packages/72/97/430e56e39a1356e8e8f10f723211a0e256e11895ef1a135f30d7d40f2540/cryptography-44.0.2-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9", size = 3960852 }, - { url = "https://files.pythonhosted.org/packages/89/33/c1cf182c152e1d262cac56850939530c05ca6c8d149aa0dcee490b417e99/cryptography-44.0.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23", size = 4193906 }, - { url = "https://files.pythonhosted.org/packages/e1/99/87cf26d4f125380dc674233971069bc28d19b07f7755b29861570e513650/cryptography-44.0.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922", size = 4081572 }, - { url = "https://files.pythonhosted.org/packages/b3/9f/6a3e0391957cc0c5f84aef9fbdd763035f2b52e998a53f99345e3ac69312/cryptography-44.0.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4", size = 4298631 }, - { url = "https://files.pythonhosted.org/packages/e2/a5/5bc097adb4b6d22a24dea53c51f37e480aaec3465285c253098642696423/cryptography-44.0.2-cp39-abi3-win32.whl", hash = "sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5", size = 2773792 }, - { url = "https://files.pythonhosted.org/packages/33/cf/1f7649b8b9a3543e042d3f348e398a061923ac05b507f3f4d95f11938aa9/cryptography-44.0.2-cp39-abi3-win_amd64.whl", hash = "sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6", size = 3210957 }, - { url = "https://files.pythonhosted.org/packages/99/10/173be140714d2ebaea8b641ff801cbcb3ef23101a2981cbf08057876f89e/cryptography-44.0.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb", size = 3396886 }, - { url = "https://files.pythonhosted.org/packages/2f/b4/424ea2d0fce08c24ede307cead3409ecbfc2f566725d4701b9754c0a1174/cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41", size = 3892387 }, - { url = "https://files.pythonhosted.org/packages/28/20/8eaa1a4f7c68a1cb15019dbaad59c812d4df4fac6fd5f7b0b9c5177f1edd/cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562", size = 4109922 }, - { url = "https://files.pythonhosted.org/packages/11/25/5ed9a17d532c32b3bc81cc294d21a36c772d053981c22bd678396bc4ae30/cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5", size = 3895715 }, - { url = "https://files.pythonhosted.org/packages/63/31/2aac03b19c6329b62c45ba4e091f9de0b8f687e1b0cd84f101401bece343/cryptography-44.0.2-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa", size = 4109876 }, - { url = "https://files.pythonhosted.org/packages/99/ec/6e560908349843718db1a782673f36852952d52a55ab14e46c42c8a7690a/cryptography-44.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d", size = 3131719 }, - { url = "https://files.pythonhosted.org/packages/d6/d7/f30e75a6aa7d0f65031886fa4a1485c2fbfe25a1896953920f6a9cfe2d3b/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d", size = 3887513 }, - { url = "https://files.pythonhosted.org/packages/9c/b4/7a494ce1032323ca9db9a3661894c66e0d7142ad2079a4249303402d8c71/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471", size = 4107432 }, - { url = "https://files.pythonhosted.org/packages/45/f8/6b3ec0bc56123b344a8d2b3264a325646d2dcdbdd9848b5e6f3d37db90b3/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615", size = 3891421 }, - { url = "https://files.pythonhosted.org/packages/57/ff/f3b4b2d007c2a646b0f69440ab06224f9cf37a977a72cdb7b50632174e8a/cryptography-44.0.2-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390", size = 4107081 }, -] - -[[package]] -name = "cycler" -version = "0.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, -] - -[[package]] -name = "distlib" -version = "0.3.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, -] - -[[package]] -name = "exceptiongroup" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164 }, -] - -[[package]] -name = "filelock" -version = "3.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215 }, -] - -[[package]] -name = "flet" -version = "0.1.0" -source = { editable = "packages/flet" } -dependencies = [ - { name = "httpx", marker = "platform_system != 'Pyodide'" }, - { name = "msgpack" }, - { name = "oauthlib", marker = "platform_system != 'Pyodide'" }, - { name = "repath" }, -] - -[package.optional-dependencies] -all = [ - { name = "flet-cli" }, - { name = "flet-desktop" }, - { name = "flet-web" }, -] -cli = [ - { name = "flet-cli" }, -] -desktop = [ - { name = "flet-desktop" }, -] -web = [ - { name = "flet-web" }, -] - -[package.metadata] -requires-dist = [ - { name = "flet-cli", marker = "extra == 'all'", editable = "packages/flet-cli" }, - { name = "flet-cli", marker = "extra == 'cli'", editable = "packages/flet-cli" }, - { name = "flet-desktop", marker = "(sys_platform == 'darwin' and extra == 'desktop') or (sys_platform == 'win32' and extra == 'desktop')", editable = "packages/flet-desktop" }, - { name = "flet-desktop", marker = "extra == 'all'", editable = "packages/flet-desktop" }, - { name = "flet-desktop", marker = "extra == 'desktop'", editable = "packages/flet-desktop" }, - { name = "flet-web", marker = "extra == 'all'", editable = "packages/flet-web" }, - { name = "flet-web", marker = "extra == 'web'", editable = "packages/flet-web" }, - { name = "httpx", marker = "platform_system != 'Pyodide'", specifier = ">=0.28.1" }, - { name = "msgpack", specifier = ">=1.1.0" }, - { name = "oauthlib", marker = "platform_system != 'Pyodide'", specifier = ">=3.2.2" }, - { name = "repath", specifier = ">=0.9.0" }, -] - -[[package]] -name = "flet-cli" -version = "0.1.0" -source = { editable = "packages/flet-cli" } -dependencies = [ - { name = "cookiecutter" }, - { name = "flet" }, - { name = "packaging" }, - { name = "qrcode" }, - { name = "toml" }, - { name = "watchdog" }, -] - -[package.metadata] -requires-dist = [ - { name = "cookiecutter", specifier = ">=2.6.0" }, - { name = "flet", editable = "packages/flet" }, - { name = "packaging", specifier = ">=25.0" }, - { name = "qrcode", specifier = ">=7.4.2" }, - { name = "toml", specifier = ">=0.10.2" }, - { name = "watchdog", specifier = ">=4.0.0" }, -] - -[[package]] -name = "flet-desktop" -version = "0.1.0" -source = { editable = "packages/flet-desktop" } -dependencies = [ - { name = "flet" }, -] - -[package.metadata] -requires-dist = [{ name = "flet", editable = "packages/flet" }] - -[[package]] -name = "flet-project" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "flet" }, - { name = "flet-cli" }, - { name = "flet-desktop" }, - { name = "flet-web" }, -] - -[package.dev-dependencies] -dev = [ - { name = "cryptography" }, - { name = "gunicorn" }, - { name = "hypercorn" }, - { name = "matplotlib" }, - { name = "pandas" }, - { name = "pillow" }, - { name = "plotly" }, - { name = "pre-commit" }, - { name = "pyinstaller" }, - { name = "pypi-cleanup" }, - { name = "pytest" }, - { name = "ruff" }, - { name = "tomlkit" }, -] - -[package.metadata] -requires-dist = [ - { name = "flet", editable = "packages/flet" }, - { name = "flet-cli", editable = "packages/flet-cli" }, - { name = "flet-desktop", editable = "packages/flet-desktop" }, - { name = "flet-web", editable = "packages/flet-web" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "cryptography", specifier = ">=39.0.0" }, - { name = "gunicorn", specifier = ">=21.2.0" }, - { name = "hypercorn", specifier = ">=0.14.4" }, - { name = "matplotlib", specifier = ">=3.10.1" }, - { name = "pandas", specifier = ">=2.2.3" }, - { name = "pillow", specifier = ">=10.3.0" }, - { name = "plotly", specifier = ">=6.0.1" }, - { name = "pre-commit", specifier = ">=2.21.0" }, - { name = "pyinstaller", specifier = ">=6.6.0" }, - { name = "pypi-cleanup", specifier = "==0.1.4" }, - { name = "pytest", specifier = ">=7.2.0" }, - { name = "ruff", specifier = ">=0.11.7" }, - { name = "tomlkit", specifier = ">=0.11.6" }, -] - -[[package]] -name = "flet-web" -version = "0.1.0" -source = { editable = "packages/flet-web" } -dependencies = [ - { name = "fastapi" }, - { name = "flet" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[package.metadata] -requires-dist = [ - { name = "fastapi", specifier = ">=0.115.12" }, - { name = "flet", editable = "packages/flet" }, - { name = "uvicorn", extras = ["standard"], specifier = ">=0.34.2" }, -] - -[[package]] -name = "fonttools" -version = "4.57.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/2d/a9a0b6e3a0cf6bd502e64fc16d894269011930cabfc89aee20d1635b1441/fonttools-4.57.0.tar.gz", hash = "sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de", size = 3492448 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/17/3ddfd1881878b3f856065130bb603f5922e81ae8a4eb53bce0ea78f765a8/fonttools-4.57.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41", size = 2756260 }, - { url = "https://files.pythonhosted.org/packages/26/2b/6957890c52c030b0bf9e0add53e5badab4682c6ff024fac9a332bb2ae063/fonttools-4.57.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02", size = 2284691 }, - { url = "https://files.pythonhosted.org/packages/cc/8e/c043b4081774e5eb06a834cedfdb7d432b4935bc8c4acf27207bdc34dfc4/fonttools-4.57.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e", size = 4566077 }, - { url = "https://files.pythonhosted.org/packages/59/bc/e16ae5d9eee6c70830ce11d1e0b23d6018ddfeb28025fda092cae7889c8b/fonttools-4.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab", size = 4608729 }, - { url = "https://files.pythonhosted.org/packages/25/13/e557bf10bb38e4e4c436d3a9627aadf691bc7392ae460910447fda5fad2b/fonttools-4.57.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1", size = 4759646 }, - { url = "https://files.pythonhosted.org/packages/bc/c9/5e2952214d4a8e31026bf80beb18187199b7001e60e99a6ce19773249124/fonttools-4.57.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f", size = 4941652 }, - { url = "https://files.pythonhosted.org/packages/df/04/e80242b3d9ec91a1f785d949edc277a13ecfdcfae744de4b170df9ed77d8/fonttools-4.57.0-cp310-cp310-win32.whl", hash = "sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec", size = 2159432 }, - { url = "https://files.pythonhosted.org/packages/33/ba/e858cdca275daf16e03c0362aa43734ea71104c3b356b2100b98543dba1b/fonttools-4.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db", size = 2203869 }, - { url = "https://files.pythonhosted.org/packages/81/1f/e67c99aa3c6d3d2f93d956627e62a57ae0d35dc42f26611ea2a91053f6d6/fonttools-4.57.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4", size = 2757392 }, - { url = "https://files.pythonhosted.org/packages/aa/f1/f75770d0ddc67db504850898d96d75adde238c35313409bfcd8db4e4a5fe/fonttools-4.57.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8", size = 2285609 }, - { url = "https://files.pythonhosted.org/packages/f5/d3/bc34e4953cb204bae0c50b527307dce559b810e624a733351a654cfc318e/fonttools-4.57.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683", size = 4873292 }, - { url = "https://files.pythonhosted.org/packages/41/b8/d5933559303a4ab18c799105f4c91ee0318cc95db4a2a09e300116625e7a/fonttools-4.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746", size = 4902503 }, - { url = "https://files.pythonhosted.org/packages/32/13/acb36bfaa316f481153ce78de1fa3926a8bad42162caa3b049e1afe2408b/fonttools-4.57.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344", size = 5077351 }, - { url = "https://files.pythonhosted.org/packages/b5/23/6d383a2ca83b7516d73975d8cca9d81a01acdcaa5e4db8579e4f3de78518/fonttools-4.57.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f", size = 5275067 }, - { url = "https://files.pythonhosted.org/packages/bc/ca/31b8919c6da0198d5d522f1d26c980201378c087bdd733a359a1e7485769/fonttools-4.57.0-cp311-cp311-win32.whl", hash = "sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36", size = 2158263 }, - { url = "https://files.pythonhosted.org/packages/13/4c/de2612ea2216eb45cfc8eb91a8501615dd87716feaf5f8fb65cbca576289/fonttools-4.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d", size = 2204968 }, - { url = "https://files.pythonhosted.org/packages/cb/98/d4bc42d43392982eecaaca117d79845734d675219680cd43070bb001bc1f/fonttools-4.57.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31", size = 2751824 }, - { url = "https://files.pythonhosted.org/packages/1a/62/7168030eeca3742fecf45f31e63b5ef48969fa230a672216b805f1d61548/fonttools-4.57.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92", size = 2283072 }, - { url = "https://files.pythonhosted.org/packages/5d/82/121a26d9646f0986ddb35fbbaf58ef791c25b59ecb63ffea2aab0099044f/fonttools-4.57.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888", size = 4788020 }, - { url = "https://files.pythonhosted.org/packages/5b/26/e0f2fb662e022d565bbe280a3cfe6dafdaabf58889ff86fdef2d31ff1dde/fonttools-4.57.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6", size = 4859096 }, - { url = "https://files.pythonhosted.org/packages/9e/44/9075e323347b1891cdece4b3f10a3b84a8f4c42a7684077429d9ce842056/fonttools-4.57.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98", size = 4964356 }, - { url = "https://files.pythonhosted.org/packages/48/28/caa8df32743462fb966be6de6a79d7f30393859636d7732e82efa09fbbb4/fonttools-4.57.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8", size = 5226546 }, - { url = "https://files.pythonhosted.org/packages/f6/46/95ab0f0d2e33c5b1a4fc1c0efe5e286ba9359602c0a9907adb1faca44175/fonttools-4.57.0-cp312-cp312-win32.whl", hash = "sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac", size = 2146776 }, - { url = "https://files.pythonhosted.org/packages/06/5d/1be5424bb305880e1113631f49a55ea7c7da3a5fe02608ca7c16a03a21da/fonttools-4.57.0-cp312-cp312-win_amd64.whl", hash = "sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9", size = 2193956 }, - { url = "https://files.pythonhosted.org/packages/e9/2f/11439f3af51e4bb75ac9598c29f8601aa501902dcedf034bdc41f47dd799/fonttools-4.57.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef", size = 2739175 }, - { url = "https://files.pythonhosted.org/packages/25/52/677b55a4c0972dc3820c8dba20a29c358197a78229daa2ea219fdb19e5d5/fonttools-4.57.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c", size = 2276583 }, - { url = "https://files.pythonhosted.org/packages/64/79/184555f8fa77b827b9460a4acdbbc0b5952bb6915332b84c615c3a236826/fonttools-4.57.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72", size = 4766437 }, - { url = "https://files.pythonhosted.org/packages/f8/ad/c25116352f456c0d1287545a7aa24e98987b6d99c5b0456c4bd14321f20f/fonttools-4.57.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817", size = 4838431 }, - { url = "https://files.pythonhosted.org/packages/53/ae/398b2a833897297797a44f519c9af911c2136eb7aa27d3f1352c6d1129fa/fonttools-4.57.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9", size = 4951011 }, - { url = "https://files.pythonhosted.org/packages/b7/5d/7cb31c4bc9ffb9a2bbe8b08f8f53bad94aeb158efad75da645b40b62cb73/fonttools-4.57.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13", size = 5205679 }, - { url = "https://files.pythonhosted.org/packages/4c/e4/6934513ec2c4d3d69ca1bc3bd34d5c69dafcbf68c15388dd3bb062daf345/fonttools-4.57.0-cp313-cp313-win32.whl", hash = "sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199", size = 2144833 }, - { url = "https://files.pythonhosted.org/packages/c4/0d/2177b7fdd23d017bcfb702fd41e47d4573766b9114da2fddbac20dcc4957/fonttools-4.57.0-cp313-cp313-win_amd64.whl", hash = "sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3", size = 2190799 }, - { url = "https://files.pythonhosted.org/packages/90/27/45f8957c3132917f91aaa56b700bcfc2396be1253f685bd5c68529b6f610/fonttools-4.57.0-py3-none-any.whl", hash = "sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f", size = 1093605 }, -] - -[[package]] -name = "gunicorn" -version = "23.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029 }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, -] - -[[package]] -name = "h2" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/38/d7f80fd13e6582fb8e0df8c9a653dcc02b03ca34f4d72f34869298c5baf8/h2-4.2.0.tar.gz", hash = "sha256:c8a52129695e88b1a0578d8d2cc6842bbd79128ac685463b887ee278126ad01f", size = 2150682 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/9e/984486f2d0a0bd2b024bf4bc1c62688fcafa9e61991f041fb0e2def4a982/h2-4.2.0-py3-none-any.whl", hash = "sha256:479a53ad425bb29af087f3458a61d30780bc818e4ebcf01f0b536ba916462ed0", size = 60957 }, -] - -[[package]] -name = "hpack" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357 }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780 }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297 }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130 }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148 }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949 }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591 }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344 }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029 }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492 }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891 }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788 }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214 }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120 }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565 }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683 }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337 }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796 }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837 }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, -] - -[[package]] -name = "hypercorn" -version = "0.17.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "h11" }, - { name = "h2" }, - { name = "priority" }, - { name = "taskgroup", marker = "python_full_version < '3.11'" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, - { name = "wsproto" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/3a/df6c27642e0dcb7aff688ca4be982f0fb5d89f2afd3096dc75347c16140f/hypercorn-0.17.3.tar.gz", hash = "sha256:1b37802ee3ac52d2d85270700d565787ab16cf19e1462ccfa9f089ca17574165", size = 44409 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/3b/dfa13a8d96aa24e40ea74a975a9906cfdc2ab2f4e3b498862a57052f04eb/hypercorn-0.17.3-py3-none-any.whl", hash = "sha256:059215dec34537f9d40a69258d323f56344805efb462959e727152b0aa504547", size = 61742 }, -] - -[[package]] -name = "hyperframe" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007 }, -] - -[[package]] -name = "identify" -version = "2.6.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0c/83/b6ea0334e2e7327084a46aaaf71f2146fc061a192d6518c0d020120cd0aa/identify-2.6.10.tar.gz", hash = "sha256:45e92fd704f3da71cc3880036633f48b4b7265fd4de2b57627cb157216eb7eb8", size = 99201 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/d3/85feeba1d097b81a44bcffa6a0beab7b4dfffe78e82fc54978d3ac380736/identify-2.6.10-py2.py3-none-any.whl", hash = "sha256:5f34248f54136beed1a7ba6a6b5c4b6cf21ff495aac7c359e1ef831ae3b8ab25", size = 99101 }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, -] - -[[package]] -name = "iniconfig" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, -] - -[[package]] -name = "kiwisolver" -version = "1.4.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/5f/4d8e9e852d98ecd26cdf8eaf7ed8bc33174033bba5e07001b289f07308fd/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db", size = 124623 }, - { url = "https://files.pythonhosted.org/packages/1d/70/7f5af2a18a76fe92ea14675f8bd88ce53ee79e37900fa5f1a1d8e0b42998/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b", size = 66720 }, - { url = "https://files.pythonhosted.org/packages/c6/13/e15f804a142353aefd089fadc8f1d985561a15358c97aca27b0979cb0785/kiwisolver-1.4.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d", size = 65413 }, - { url = "https://files.pythonhosted.org/packages/ce/6d/67d36c4d2054e83fb875c6b59d0809d5c530de8148846b1370475eeeece9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d", size = 1650826 }, - { url = "https://files.pythonhosted.org/packages/de/c6/7b9bb8044e150d4d1558423a1568e4f227193662a02231064e3824f37e0a/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c", size = 1628231 }, - { url = "https://files.pythonhosted.org/packages/b6/38/ad10d437563063eaaedbe2c3540a71101fc7fb07a7e71f855e93ea4de605/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3", size = 1408938 }, - { url = "https://files.pythonhosted.org/packages/52/ce/c0106b3bd7f9e665c5f5bc1e07cc95b5dabd4e08e3dad42dbe2faad467e7/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed", size = 1422799 }, - { url = "https://files.pythonhosted.org/packages/d0/87/efb704b1d75dc9758087ba374c0f23d3254505edaedd09cf9d247f7878b9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f", size = 1354362 }, - { url = "https://files.pythonhosted.org/packages/eb/b3/fd760dc214ec9a8f208b99e42e8f0130ff4b384eca8b29dd0efc62052176/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff", size = 2222695 }, - { url = "https://files.pythonhosted.org/packages/a2/09/a27fb36cca3fc01700687cc45dae7a6a5f8eeb5f657b9f710f788748e10d/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d", size = 2370802 }, - { url = "https://files.pythonhosted.org/packages/3d/c3/ba0a0346db35fe4dc1f2f2cf8b99362fbb922d7562e5f911f7ce7a7b60fa/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c", size = 2334646 }, - { url = "https://files.pythonhosted.org/packages/41/52/942cf69e562f5ed253ac67d5c92a693745f0bed3c81f49fc0cbebe4d6b00/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605", size = 2467260 }, - { url = "https://files.pythonhosted.org/packages/32/26/2d9668f30d8a494b0411d4d7d4ea1345ba12deb6a75274d58dd6ea01e951/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e", size = 2288633 }, - { url = "https://files.pythonhosted.org/packages/98/99/0dd05071654aa44fe5d5e350729961e7bb535372935a45ac89a8924316e6/kiwisolver-1.4.8-cp310-cp310-win_amd64.whl", hash = "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751", size = 71885 }, - { url = "https://files.pythonhosted.org/packages/6c/fc/822e532262a97442989335394d441cd1d0448c2e46d26d3e04efca84df22/kiwisolver-1.4.8-cp310-cp310-win_arm64.whl", hash = "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271", size = 65175 }, - { url = "https://files.pythonhosted.org/packages/da/ed/c913ee28936c371418cb167b128066ffb20bbf37771eecc2c97edf8a6e4c/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84", size = 124635 }, - { url = "https://files.pythonhosted.org/packages/4c/45/4a7f896f7467aaf5f56ef093d1f329346f3b594e77c6a3c327b2d415f521/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561", size = 66717 }, - { url = "https://files.pythonhosted.org/packages/5f/b4/c12b3ac0852a3a68f94598d4c8d569f55361beef6159dce4e7b624160da2/kiwisolver-1.4.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7", size = 65413 }, - { url = "https://files.pythonhosted.org/packages/a9/98/1df4089b1ed23d83d410adfdc5947245c753bddfbe06541c4aae330e9e70/kiwisolver-1.4.8-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03", size = 1343994 }, - { url = "https://files.pythonhosted.org/packages/8d/bf/b4b169b050c8421a7c53ea1ea74e4ef9c335ee9013216c558a047f162d20/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954", size = 1434804 }, - { url = "https://files.pythonhosted.org/packages/66/5a/e13bd341fbcf73325ea60fdc8af752addf75c5079867af2e04cc41f34434/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79", size = 1450690 }, - { url = "https://files.pythonhosted.org/packages/9b/4f/5955dcb376ba4a830384cc6fab7d7547bd6759fe75a09564910e9e3bb8ea/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6", size = 1376839 }, - { url = "https://files.pythonhosted.org/packages/3a/97/5edbed69a9d0caa2e4aa616ae7df8127e10f6586940aa683a496c2c280b9/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0", size = 1435109 }, - { url = "https://files.pythonhosted.org/packages/13/fc/e756382cb64e556af6c1809a1bbb22c141bbc2445049f2da06b420fe52bf/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab", size = 2245269 }, - { url = "https://files.pythonhosted.org/packages/76/15/e59e45829d7f41c776d138245cabae6515cb4eb44b418f6d4109c478b481/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc", size = 2393468 }, - { url = "https://files.pythonhosted.org/packages/e9/39/483558c2a913ab8384d6e4b66a932406f87c95a6080112433da5ed668559/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25", size = 2355394 }, - { url = "https://files.pythonhosted.org/packages/01/aa/efad1fbca6570a161d29224f14b082960c7e08268a133fe5dc0f6906820e/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc", size = 2490901 }, - { url = "https://files.pythonhosted.org/packages/c9/4f/15988966ba46bcd5ab9d0c8296914436720dd67fca689ae1a75b4ec1c72f/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67", size = 2312306 }, - { url = "https://files.pythonhosted.org/packages/2d/27/bdf1c769c83f74d98cbc34483a972f221440703054894a37d174fba8aa68/kiwisolver-1.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34", size = 71966 }, - { url = "https://files.pythonhosted.org/packages/4a/c9/9642ea855604aeb2968a8e145fc662edf61db7632ad2e4fb92424be6b6c0/kiwisolver-1.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2", size = 65311 }, - { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152 }, - { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555 }, - { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067 }, - { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443 }, - { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728 }, - { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388 }, - { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849 }, - { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533 }, - { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898 }, - { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605 }, - { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801 }, - { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077 }, - { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410 }, - { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853 }, - { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424 }, - { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156 }, - { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555 }, - { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071 }, - { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053 }, - { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278 }, - { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139 }, - { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517 }, - { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952 }, - { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132 }, - { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997 }, - { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060 }, - { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471 }, - { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793 }, - { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855 }, - { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430 }, - { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294 }, - { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736 }, - { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194 }, - { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942 }, - { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341 }, - { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455 }, - { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138 }, - { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857 }, - { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129 }, - { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538 }, - { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661 }, - { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710 }, - { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213 }, - { url = "https://files.pythonhosted.org/packages/1f/f9/ae81c47a43e33b93b0a9819cac6723257f5da2a5a60daf46aa5c7226ea85/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a", size = 60403 }, - { url = "https://files.pythonhosted.org/packages/58/ca/f92b5cb6f4ce0c1ebfcfe3e2e42b96917e16f7090e45b21102941924f18f/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8", size = 58657 }, - { url = "https://files.pythonhosted.org/packages/80/28/ae0240f732f0484d3a4dc885d055653c47144bdf59b670aae0ec3c65a7c8/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0", size = 84948 }, - { url = "https://files.pythonhosted.org/packages/5d/eb/78d50346c51db22c7203c1611f9b513075f35c4e0e4877c5dde378d66043/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c", size = 81186 }, - { url = "https://files.pythonhosted.org/packages/43/f8/7259f18c77adca88d5f64f9a522792e178b2691f3748817a8750c2d216ef/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b", size = 80279 }, - { url = "https://files.pythonhosted.org/packages/3a/1d/50ad811d1c5dae091e4cf046beba925bcae0a610e79ae4c538f996f63ed5/kiwisolver-1.4.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b", size = 71762 }, -] - -[[package]] -name = "macholib" -version = "1.16.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "altgraph", marker = "sys_platform == 'darwin' or sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/ee/af1a3842bdd5902ce133bd246eb7ffd4375c38642aeb5dc0ae3a0329dfa2/macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30", size = 59309 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/5d/c059c180c84f7962db0aeae7c3b9303ed1d73d76f2bfbc32bc231c8be314/macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c", size = 38094 }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, -] - -[[package]] -name = "matplotlib" -version = "3.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2f/08/b89867ecea2e305f408fbb417139a8dd941ecf7b23a2e02157c36da546f0/matplotlib-3.10.1.tar.gz", hash = "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba", size = 36743335 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/b1/f70e27cf1cd76ce2a5e1aa5579d05afe3236052c6d9b9a96325bc823a17e/matplotlib-3.10.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ff2ae14910be903f4a24afdbb6d7d3a6c44da210fc7d42790b87aeac92238a16", size = 8163654 }, - { url = "https://files.pythonhosted.org/packages/26/af/5ec3d4636106718bb62503a03297125d4514f98fe818461bd9e6b9d116e4/matplotlib-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0721a3fd3d5756ed593220a8b86808a36c5031fce489adb5b31ee6dbb47dd5b2", size = 8037943 }, - { url = "https://files.pythonhosted.org/packages/a1/3d/07f9003a71b698b848c9925d05979ffa94a75cd25d1a587202f0bb58aa81/matplotlib-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0673b4b8f131890eb3a1ad058d6e065fb3c6e71f160089b65f8515373394698", size = 8449510 }, - { url = "https://files.pythonhosted.org/packages/12/87/9472d4513ff83b7cd864311821793ab72234fa201ab77310ec1b585d27e2/matplotlib-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e875b95ac59a7908978fe307ecdbdd9a26af7fa0f33f474a27fcf8c99f64a19", size = 8586585 }, - { url = "https://files.pythonhosted.org/packages/31/9e/fe74d237d2963adae8608faeb21f778cf246dbbf4746cef87cffbc82c4b6/matplotlib-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2589659ea30726284c6c91037216f64a506a9822f8e50592d48ac16a2f29e044", size = 9397911 }, - { url = "https://files.pythonhosted.org/packages/b6/1b/025d3e59e8a4281ab463162ad7d072575354a1916aba81b6a11507dfc524/matplotlib-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a97ff127f295817bc34517255c9db6e71de8eddaab7f837b7d341dee9f2f587f", size = 8052998 }, - { url = "https://files.pythonhosted.org/packages/a5/14/a1b840075be247bb1834b22c1e1d558740b0f618fe3a823740181ca557a1/matplotlib-3.10.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401", size = 8174669 }, - { url = "https://files.pythonhosted.org/packages/0a/e4/300b08e3e08f9c98b0d5635f42edabf2f7a1d634e64cb0318a71a44ff720/matplotlib-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe", size = 8047996 }, - { url = "https://files.pythonhosted.org/packages/75/f9/8d99ff5a2498a5f1ccf919fb46fb945109623c6108216f10f96428f388bc/matplotlib-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd", size = 8461612 }, - { url = "https://files.pythonhosted.org/packages/40/b8/53fa08a5eaf78d3a7213fd6da1feec4bae14a81d9805e567013811ff0e85/matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c", size = 8602258 }, - { url = "https://files.pythonhosted.org/packages/40/87/4397d2ce808467af86684a622dd112664553e81752ea8bf61bdd89d24a41/matplotlib-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7", size = 9408896 }, - { url = "https://files.pythonhosted.org/packages/d7/68/0d03098b3feb786cbd494df0aac15b571effda7f7cbdec267e8a8d398c16/matplotlib-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a", size = 8061281 }, - { url = "https://files.pythonhosted.org/packages/7c/1d/5e0dc3b59c034e43de16f94deb68f4ad8a96b3ea00f4b37c160b7474928e/matplotlib-3.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107", size = 8175488 }, - { url = "https://files.pythonhosted.org/packages/7a/81/dae7e14042e74da658c3336ab9799128e09a1ee03964f2d89630b5d12106/matplotlib-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be", size = 8046264 }, - { url = "https://files.pythonhosted.org/packages/21/c4/22516775dcde10fc9c9571d155f90710761b028fc44f660508106c363c97/matplotlib-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6", size = 8452048 }, - { url = "https://files.pythonhosted.org/packages/63/23/c0615001f67ce7c96b3051d856baedc0c818a2ed84570b9bf9bde200f85d/matplotlib-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d", size = 8597111 }, - { url = "https://files.pythonhosted.org/packages/ca/c0/a07939a82aed77770514348f4568177d7dadab9787ebc618a616fe3d665e/matplotlib-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea", size = 9402771 }, - { url = "https://files.pythonhosted.org/packages/a6/b6/a9405484fb40746fdc6ae4502b16a9d6e53282ba5baaf9ebe2da579f68c4/matplotlib-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c", size = 8063742 }, - { url = "https://files.pythonhosted.org/packages/60/73/6770ff5e5523d00f3bc584acb6031e29ee5c8adc2336b16cd1d003675fe0/matplotlib-3.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b", size = 8176112 }, - { url = "https://files.pythonhosted.org/packages/08/97/b0ca5da0ed54a3f6599c3ab568bdda65269bc27c21a2c97868c1625e4554/matplotlib-3.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1", size = 8046931 }, - { url = "https://files.pythonhosted.org/packages/df/9a/1acbdc3b165d4ce2dcd2b1a6d4ffb46a7220ceee960c922c3d50d8514067/matplotlib-3.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3", size = 8453422 }, - { url = "https://files.pythonhosted.org/packages/51/d0/2bc4368abf766203e548dc7ab57cf7e9c621f1a3c72b516cc7715347b179/matplotlib-3.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6", size = 8596819 }, - { url = "https://files.pythonhosted.org/packages/ab/1b/8b350f8a1746c37ab69dda7d7528d1fc696efb06db6ade9727b7887be16d/matplotlib-3.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b", size = 9402782 }, - { url = "https://files.pythonhosted.org/packages/89/06/f570373d24d93503988ba8d04f213a372fa1ce48381c5eb15da985728498/matplotlib-3.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473", size = 8063812 }, - { url = "https://files.pythonhosted.org/packages/fc/e0/8c811a925b5a7ad75135f0e5af46408b78af88bbb02a1df775100ef9bfef/matplotlib-3.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01", size = 8214021 }, - { url = "https://files.pythonhosted.org/packages/4a/34/319ec2139f68ba26da9d00fce2ff9f27679fb799a6c8e7358539801fd629/matplotlib-3.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb", size = 8090782 }, - { url = "https://files.pythonhosted.org/packages/77/ea/9812124ab9a99df5b2eec1110e9b2edc0b8f77039abf4c56e0a376e84a29/matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972", size = 8478901 }, - { url = "https://files.pythonhosted.org/packages/c9/db/b05bf463689134789b06dea85828f8ebe506fa1e37593f723b65b86c9582/matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3", size = 8613864 }, - { url = "https://files.pythonhosted.org/packages/c2/04/41ccec4409f3023a7576df3b5c025f1a8c8b81fbfe922ecfd837ac36e081/matplotlib-3.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f", size = 9409487 }, - { url = "https://files.pythonhosted.org/packages/ac/c2/0d5aae823bdcc42cc99327ecdd4d28585e15ccd5218c453b7bcd827f3421/matplotlib-3.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9", size = 8134832 }, - { url = "https://files.pythonhosted.org/packages/c8/f6/10adb696d8cbeed2ab4c2e26ecf1c80dd3847bbf3891f4a0c362e0e08a5a/matplotlib-3.10.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:648406f1899f9a818cef8c0231b44dcfc4ff36f167101c3fd1c9151f24220fdc", size = 8158685 }, - { url = "https://files.pythonhosted.org/packages/3f/84/0603d917406072763e7f9bb37747d3d74d7ecd4b943a8c947cc3ae1cf7af/matplotlib-3.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:02582304e352f40520727984a5a18f37e8187861f954fea9be7ef06569cf85b4", size = 8035491 }, - { url = "https://files.pythonhosted.org/packages/fd/7d/6a8b31dd07ed856b3eae001c9129670ef75c4698fa1c2a6ac9f00a4a7054/matplotlib-3.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3809916157ba871bcdd33d3493acd7fe3037db5daa917ca6e77975a94cef779", size = 8590087 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - -[[package]] -name = "msgpack" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cb/d0/7555686ae7ff5731205df1012ede15dd9d927f6227ea151e901c7406af4f/msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e", size = 167260 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/f9/a892a6038c861fa849b11a2bb0502c07bc698ab6ea53359e5771397d883b/msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd", size = 150428 }, - { url = "https://files.pythonhosted.org/packages/df/7a/d174cc6a3b6bb85556e6a046d3193294a92f9a8e583cdbd46dc8a1d7e7f4/msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d", size = 84131 }, - { url = "https://files.pythonhosted.org/packages/08/52/bf4fbf72f897a23a56b822997a72c16de07d8d56d7bf273242f884055682/msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5", size = 81215 }, - { url = "https://files.pythonhosted.org/packages/02/95/dc0044b439b518236aaf012da4677c1b8183ce388411ad1b1e63c32d8979/msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5", size = 371229 }, - { url = "https://files.pythonhosted.org/packages/ff/75/09081792db60470bef19d9c2be89f024d366b1e1973c197bb59e6aabc647/msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e", size = 378034 }, - { url = "https://files.pythonhosted.org/packages/32/d3/c152e0c55fead87dd948d4b29879b0f14feeeec92ef1fd2ec21b107c3f49/msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b", size = 363070 }, - { url = "https://files.pythonhosted.org/packages/d9/2c/82e73506dd55f9e43ac8aa007c9dd088c6f0de2aa19e8f7330e6a65879fc/msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f", size = 359863 }, - { url = "https://files.pythonhosted.org/packages/cb/a0/3d093b248837094220e1edc9ec4337de3443b1cfeeb6e0896af8ccc4cc7a/msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68", size = 368166 }, - { url = "https://files.pythonhosted.org/packages/e4/13/7646f14f06838b406cf5a6ddbb7e8dc78b4996d891ab3b93c33d1ccc8678/msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b", size = 370105 }, - { url = "https://files.pythonhosted.org/packages/67/fa/dbbd2443e4578e165192dabbc6a22c0812cda2649261b1264ff515f19f15/msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044", size = 68513 }, - { url = "https://files.pythonhosted.org/packages/24/ce/c2c8fbf0ded750cb63cbcbb61bc1f2dfd69e16dca30a8af8ba80ec182dcd/msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f", size = 74687 }, - { url = "https://files.pythonhosted.org/packages/b7/5e/a4c7154ba65d93be91f2f1e55f90e76c5f91ccadc7efc4341e6f04c8647f/msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7", size = 150803 }, - { url = "https://files.pythonhosted.org/packages/60/c2/687684164698f1d51c41778c838d854965dd284a4b9d3a44beba9265c931/msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa", size = 84343 }, - { url = "https://files.pythonhosted.org/packages/42/ae/d3adea9bb4a1342763556078b5765e666f8fdf242e00f3f6657380920972/msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701", size = 81408 }, - { url = "https://files.pythonhosted.org/packages/dc/17/6313325a6ff40ce9c3207293aee3ba50104aed6c2c1559d20d09e5c1ff54/msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6", size = 396096 }, - { url = "https://files.pythonhosted.org/packages/a8/a1/ad7b84b91ab5a324e707f4c9761633e357820b011a01e34ce658c1dda7cc/msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59", size = 403671 }, - { url = "https://files.pythonhosted.org/packages/bb/0b/fd5b7c0b308bbf1831df0ca04ec76fe2f5bf6319833646b0a4bd5e9dc76d/msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0", size = 387414 }, - { url = "https://files.pythonhosted.org/packages/f0/03/ff8233b7c6e9929a1f5da3c7860eccd847e2523ca2de0d8ef4878d354cfa/msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e", size = 383759 }, - { url = "https://files.pythonhosted.org/packages/1f/1b/eb82e1fed5a16dddd9bc75f0854b6e2fe86c0259c4353666d7fab37d39f4/msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6", size = 394405 }, - { url = "https://files.pythonhosted.org/packages/90/2e/962c6004e373d54ecf33d695fb1402f99b51832631e37c49273cc564ffc5/msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5", size = 396041 }, - { url = "https://files.pythonhosted.org/packages/f8/20/6e03342f629474414860c48aeffcc2f7f50ddaf351d95f20c3f1c67399a8/msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88", size = 68538 }, - { url = "https://files.pythonhosted.org/packages/aa/c4/5a582fc9a87991a3e6f6800e9bb2f3c82972912235eb9539954f3e9997c7/msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788", size = 74871 }, - { url = "https://files.pythonhosted.org/packages/e1/d6/716b7ca1dbde63290d2973d22bbef1b5032ca634c3ff4384a958ec3f093a/msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d", size = 152421 }, - { url = "https://files.pythonhosted.org/packages/70/da/5312b067f6773429cec2f8f08b021c06af416bba340c912c2ec778539ed6/msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2", size = 85277 }, - { url = "https://files.pythonhosted.org/packages/28/51/da7f3ae4462e8bb98af0d5bdf2707f1b8c65a0d4f496e46b6afb06cbc286/msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420", size = 82222 }, - { url = "https://files.pythonhosted.org/packages/33/af/dc95c4b2a49cff17ce47611ca9ba218198806cad7796c0b01d1e332c86bb/msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2", size = 392971 }, - { url = "https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39", size = 401403 }, - { url = "https://files.pythonhosted.org/packages/97/8c/e333690777bd33919ab7024269dc3c41c76ef5137b211d776fbb404bfead/msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f", size = 385356 }, - { url = "https://files.pythonhosted.org/packages/57/52/406795ba478dc1c890559dd4e89280fa86506608a28ccf3a72fbf45df9f5/msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247", size = 383028 }, - { url = "https://files.pythonhosted.org/packages/e7/69/053b6549bf90a3acadcd8232eae03e2fefc87f066a5b9fbb37e2e608859f/msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c", size = 391100 }, - { url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254 }, - { url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085 }, - { url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347 }, - { url = "https://files.pythonhosted.org/packages/c8/b0/380f5f639543a4ac413e969109978feb1f3c66e931068f91ab6ab0f8be00/msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf", size = 151142 }, - { url = "https://files.pythonhosted.org/packages/c8/ee/be57e9702400a6cb2606883d55b05784fada898dfc7fd12608ab1fdb054e/msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330", size = 84523 }, - { url = "https://files.pythonhosted.org/packages/7e/3a/2919f63acca3c119565449681ad08a2f84b2171ddfcff1dba6959db2cceb/msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734", size = 81556 }, - { url = "https://files.pythonhosted.org/packages/7c/43/a11113d9e5c1498c145a8925768ea2d5fce7cbab15c99cda655aa09947ed/msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e", size = 392105 }, - { url = "https://files.pythonhosted.org/packages/2d/7b/2c1d74ca6c94f70a1add74a8393a0138172207dc5de6fc6269483519d048/msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca", size = 399979 }, - { url = "https://files.pythonhosted.org/packages/82/8c/cf64ae518c7b8efc763ca1f1348a96f0e37150061e777a8ea5430b413a74/msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915", size = 383816 }, - { url = "https://files.pythonhosted.org/packages/69/86/a847ef7a0f5ef3fa94ae20f52a4cacf596a4e4a010197fbcc27744eb9a83/msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d", size = 380973 }, - { url = "https://files.pythonhosted.org/packages/aa/90/c74cf6e1126faa93185d3b830ee97246ecc4fe12cf9d2d31318ee4246994/msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434", size = 387435 }, - { url = "https://files.pythonhosted.org/packages/7a/40/631c238f1f338eb09f4acb0f34ab5862c4e9d7eda11c1b685471a4c5ea37/msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c", size = 399082 }, - { url = "https://files.pythonhosted.org/packages/e9/1b/fa8a952be252a1555ed39f97c06778e3aeb9123aa4cccc0fd2acd0b4e315/msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc", size = 69037 }, - { url = "https://files.pythonhosted.org/packages/b6/bc/8bd826dd03e022153bfa1766dcdec4976d6c818865ed54223d71f07862b3/msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f", size = 75140 }, -] - -[[package]] -name = "narwhals" -version = "1.36.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/92/503f99e2244a271aacd6c2588e0af1b59232292b217708748cdb30214dc3/narwhals-1.36.0.tar.gz", hash = "sha256:7cd860e7e066609bd8a042bb5b8e4193275532114448210a91cbd5c622b6e5eb", size = 270385 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/bf/fbcbd9f8676e06ed43d644a4ddbf31478a44056487578ce67f191da430cb/narwhals-1.36.0-py3-none-any.whl", hash = "sha256:e3c50dd1d769bc145f57ae17c1f0f0da6c3d397d62cdd0bb167e9b618e95c9d6", size = 331018 }, -] - -[[package]] -name = "nodeenv" -version = "1.9.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, -] - -[[package]] -name = "numpy" -version = "2.2.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/b2/ce4b867d8cd9c0ee84938ae1e6a6f7926ebf928c9090d036fc3c6a04f946/numpy-2.2.5.tar.gz", hash = "sha256:a9c0d994680cd991b1cb772e8b297340085466a6fe964bc9d4e80f5e2f43c291", size = 20273920 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/4e/3d9e6d16237c2aa5485695f0626cbba82f6481efca2e9132368dea3b885e/numpy-2.2.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f4a922da1729f4c40932b2af4fe84909c7a6e167e6e99f71838ce3a29f3fe26", size = 21252117 }, - { url = "https://files.pythonhosted.org/packages/38/e4/db91349d4079cd15c02ff3b4b8882a529991d6aca077db198a2f2a670406/numpy-2.2.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6f91524d31b34f4a5fee24f5bc16dcd1491b668798b6d85585d836c1e633a6a", size = 14424615 }, - { url = "https://files.pythonhosted.org/packages/f8/59/6e5b011f553c37b008bd115c7ba7106a18f372588fbb1b430b7a5d2c41ce/numpy-2.2.5-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:19f4718c9012e3baea91a7dba661dcab2451cda2550678dc30d53acb91a7290f", size = 5428691 }, - { url = "https://files.pythonhosted.org/packages/a2/58/d5d70ebdac82b3a6ddf409b3749ca5786636e50fd64d60edb46442af6838/numpy-2.2.5-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:eb7fd5b184e5d277afa9ec0ad5e4eb562ecff541e7f60e69ee69c8d59e9aeaba", size = 6965010 }, - { url = "https://files.pythonhosted.org/packages/dc/a8/c290394be346d4e7b48a40baf292626fd96ec56a6398ace4c25d9079bc6a/numpy-2.2.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6413d48a9be53e183eb06495d8e3b006ef8f87c324af68241bbe7a39e8ff54c3", size = 14369885 }, - { url = "https://files.pythonhosted.org/packages/c2/70/fed13c70aabe7049368553e81d7ca40f305f305800a007a956d7cd2e5476/numpy-2.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7451f92eddf8503c9b8aa4fe6aa7e87fd51a29c2cfc5f7dbd72efde6c65acf57", size = 16418372 }, - { url = "https://files.pythonhosted.org/packages/04/ab/c3c14f25ddaecd6fc58a34858f6a93a21eea6c266ba162fa99f3d0de12ac/numpy-2.2.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0bcb1d057b7571334139129b7f941588f69ce7c4ed15a9d6162b2ea54ded700c", size = 15883173 }, - { url = "https://files.pythonhosted.org/packages/50/18/f53710a19042911c7aca824afe97c203728a34b8cf123e2d94621a12edc3/numpy-2.2.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36ab5b23915887543441efd0417e6a3baa08634308894316f446027611b53bf1", size = 18206881 }, - { url = "https://files.pythonhosted.org/packages/6b/ec/5b407bab82f10c65af5a5fe754728df03f960fd44d27c036b61f7b3ef255/numpy-2.2.5-cp310-cp310-win32.whl", hash = "sha256:422cc684f17bc963da5f59a31530b3936f57c95a29743056ef7a7903a5dbdf88", size = 6609852 }, - { url = "https://files.pythonhosted.org/packages/b6/f5/467ca8675c7e6c567f571d8db942cc10a87588bd9e20a909d8af4171edda/numpy-2.2.5-cp310-cp310-win_amd64.whl", hash = "sha256:e4f0b035d9d0ed519c813ee23e0a733db81ec37d2e9503afbb6e54ccfdee0fa7", size = 12944922 }, - { url = "https://files.pythonhosted.org/packages/f5/fb/e4e4c254ba40e8f0c78218f9e86304628c75b6900509b601c8433bdb5da7/numpy-2.2.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c42365005c7a6c42436a54d28c43fe0e01ca11eb2ac3cefe796c25a5f98e5e9b", size = 21256475 }, - { url = "https://files.pythonhosted.org/packages/81/32/dd1f7084f5c10b2caad778258fdaeedd7fbd8afcd2510672811e6138dfac/numpy-2.2.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:498815b96f67dc347e03b719ef49c772589fb74b8ee9ea2c37feae915ad6ebda", size = 14461474 }, - { url = "https://files.pythonhosted.org/packages/0e/65/937cdf238ef6ac54ff749c0f66d9ee2b03646034c205cea9b6c51f2f3ad1/numpy-2.2.5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6411f744f7f20081b1b4e7112e0f4c9c5b08f94b9f086e6f0adf3645f85d3a4d", size = 5426875 }, - { url = "https://files.pythonhosted.org/packages/25/17/814515fdd545b07306eaee552b65c765035ea302d17de1b9cb50852d2452/numpy-2.2.5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9de6832228f617c9ef45d948ec1cd8949c482238d68b2477e6f642c33a7b0a54", size = 6969176 }, - { url = "https://files.pythonhosted.org/packages/e5/32/a66db7a5c8b5301ec329ab36d0ecca23f5e18907f43dbd593c8ec326d57c/numpy-2.2.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:369e0d4647c17c9363244f3468f2227d557a74b6781cb62ce57cf3ef5cc7c610", size = 14374850 }, - { url = "https://files.pythonhosted.org/packages/ad/c9/1bf6ada582eebcbe8978f5feb26584cd2b39f94ededeea034ca8f84af8c8/numpy-2.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:262d23f383170f99cd9191a7c85b9a50970fe9069b2f8ab5d786eca8a675d60b", size = 16430306 }, - { url = "https://files.pythonhosted.org/packages/6a/f0/3f741863f29e128f4fcfdb99253cc971406b402b4584663710ee07f5f7eb/numpy-2.2.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa70fdbdc3b169d69e8c59e65c07a1c9351ceb438e627f0fdcd471015cd956be", size = 15884767 }, - { url = "https://files.pythonhosted.org/packages/98/d9/4ccd8fd6410f7bf2d312cbc98892e0e43c2fcdd1deae293aeb0a93b18071/numpy-2.2.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37e32e985f03c06206582a7323ef926b4e78bdaa6915095ef08070471865b906", size = 18219515 }, - { url = "https://files.pythonhosted.org/packages/b1/56/783237243d4395c6dd741cf16eeb1a9035ee3d4310900e6b17e875d1b201/numpy-2.2.5-cp311-cp311-win32.whl", hash = "sha256:f5045039100ed58fa817a6227a356240ea1b9a1bc141018864c306c1a16d4175", size = 6607842 }, - { url = "https://files.pythonhosted.org/packages/98/89/0c93baaf0094bdaaaa0536fe61a27b1dce8a505fa262a865ec142208cfe9/numpy-2.2.5-cp311-cp311-win_amd64.whl", hash = "sha256:b13f04968b46ad705f7c8a80122a42ae8f620536ea38cf4bdd374302926424dd", size = 12949071 }, - { url = "https://files.pythonhosted.org/packages/e2/f7/1fd4ff108cd9d7ef929b8882692e23665dc9c23feecafbb9c6b80f4ec583/numpy-2.2.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ee461a4eaab4f165b68780a6a1af95fb23a29932be7569b9fab666c407969051", size = 20948633 }, - { url = "https://files.pythonhosted.org/packages/12/03/d443c278348371b20d830af155ff2079acad6a9e60279fac2b41dbbb73d8/numpy-2.2.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec31367fd6a255dc8de4772bd1658c3e926d8e860a0b6e922b615e532d320ddc", size = 14176123 }, - { url = "https://files.pythonhosted.org/packages/2b/0b/5ca264641d0e7b14393313304da48b225d15d471250376f3fbdb1a2be603/numpy-2.2.5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:47834cde750d3c9f4e52c6ca28a7361859fcaf52695c7dc3cc1a720b8922683e", size = 5163817 }, - { url = "https://files.pythonhosted.org/packages/04/b3/d522672b9e3d28e26e1613de7675b441bbd1eaca75db95680635dd158c67/numpy-2.2.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2c1a1c6ccce4022383583a6ded7bbcda22fc635eb4eb1e0a053336425ed36dfa", size = 6698066 }, - { url = "https://files.pythonhosted.org/packages/a0/93/0f7a75c1ff02d4b76df35079676b3b2719fcdfb39abdf44c8b33f43ef37d/numpy-2.2.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d75f338f5f79ee23548b03d801d28a505198297534f62416391857ea0479571", size = 14087277 }, - { url = "https://files.pythonhosted.org/packages/b0/d9/7c338b923c53d431bc837b5b787052fef9ae68a56fe91e325aac0d48226e/numpy-2.2.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a801fef99668f309b88640e28d261991bfad9617c27beda4a3aec4f217ea073", size = 16135742 }, - { url = "https://files.pythonhosted.org/packages/2d/10/4dec9184a5d74ba9867c6f7d1e9f2e0fb5fe96ff2bf50bb6f342d64f2003/numpy-2.2.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:abe38cd8381245a7f49967a6010e77dbf3680bd3627c0fe4362dd693b404c7f8", size = 15581825 }, - { url = "https://files.pythonhosted.org/packages/80/1f/2b6fcd636e848053f5b57712a7d1880b1565eec35a637fdfd0a30d5e738d/numpy-2.2.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5a0ac90e46fdb5649ab6369d1ab6104bfe5854ab19b645bf5cda0127a13034ae", size = 17899600 }, - { url = "https://files.pythonhosted.org/packages/ec/87/36801f4dc2623d76a0a3835975524a84bd2b18fe0f8835d45c8eae2f9ff2/numpy-2.2.5-cp312-cp312-win32.whl", hash = "sha256:0cd48122a6b7eab8f06404805b1bd5856200e3ed6f8a1b9a194f9d9054631beb", size = 6312626 }, - { url = "https://files.pythonhosted.org/packages/8b/09/4ffb4d6cfe7ca6707336187951992bd8a8b9142cf345d87ab858d2d7636a/numpy-2.2.5-cp312-cp312-win_amd64.whl", hash = "sha256:ced69262a8278547e63409b2653b372bf4baff0870c57efa76c5703fd6543282", size = 12645715 }, - { url = "https://files.pythonhosted.org/packages/e2/a0/0aa7f0f4509a2e07bd7a509042967c2fab635690d4f48c6c7b3afd4f448c/numpy-2.2.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:059b51b658f4414fff78c6d7b1b4e18283ab5fa56d270ff212d5ba0c561846f4", size = 20935102 }, - { url = "https://files.pythonhosted.org/packages/7e/e4/a6a9f4537542912ec513185396fce52cdd45bdcf3e9d921ab02a93ca5aa9/numpy-2.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:47f9ed103af0bc63182609044b0490747e03bd20a67e391192dde119bf43d52f", size = 14191709 }, - { url = "https://files.pythonhosted.org/packages/be/65/72f3186b6050bbfe9c43cb81f9df59ae63603491d36179cf7a7c8d216758/numpy-2.2.5-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:261a1ef047751bb02f29dfe337230b5882b54521ca121fc7f62668133cb119c9", size = 5149173 }, - { url = "https://files.pythonhosted.org/packages/e5/e9/83e7a9432378dde5802651307ae5e9ea07bb72b416728202218cd4da2801/numpy-2.2.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4520caa3807c1ceb005d125a75e715567806fed67e315cea619d5ec6e75a4191", size = 6684502 }, - { url = "https://files.pythonhosted.org/packages/ea/27/b80da6c762394c8ee516b74c1f686fcd16c8f23b14de57ba0cad7349d1d2/numpy-2.2.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d14b17b9be5f9c9301f43d2e2a4886a33b53f4e6fdf9ca2f4cc60aeeee76372", size = 14084417 }, - { url = "https://files.pythonhosted.org/packages/aa/fc/ebfd32c3e124e6a1043e19c0ab0769818aa69050ce5589b63d05ff185526/numpy-2.2.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba321813a00e508d5421104464510cc962a6f791aa2fca1c97b1e65027da80d", size = 16133807 }, - { url = "https://files.pythonhosted.org/packages/bf/9b/4cc171a0acbe4666f7775cfd21d4eb6bb1d36d3a0431f48a73e9212d2278/numpy-2.2.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4cbdef3ddf777423060c6f81b5694bad2dc9675f110c4b2a60dc0181543fac7", size = 15575611 }, - { url = "https://files.pythonhosted.org/packages/a3/45/40f4135341850df48f8edcf949cf47b523c404b712774f8855a64c96ef29/numpy-2.2.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54088a5a147ab71a8e7fdfd8c3601972751ded0739c6b696ad9cb0343e21ab73", size = 17895747 }, - { url = "https://files.pythonhosted.org/packages/f8/4c/b32a17a46f0ffbde8cc82df6d3daeaf4f552e346df143e1b188a701a8f09/numpy-2.2.5-cp313-cp313-win32.whl", hash = "sha256:c8b82a55ef86a2d8e81b63da85e55f5537d2157165be1cb2ce7cfa57b6aef38b", size = 6309594 }, - { url = "https://files.pythonhosted.org/packages/13/ae/72e6276feb9ef06787365b05915bfdb057d01fceb4a43cb80978e518d79b/numpy-2.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:d8882a829fd779f0f43998e931c466802a77ca1ee0fe25a3abe50278616b1471", size = 12638356 }, - { url = "https://files.pythonhosted.org/packages/79/56/be8b85a9f2adb688e7ded6324e20149a03541d2b3297c3ffc1a73f46dedb/numpy-2.2.5-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e8b025c351b9f0e8b5436cf28a07fa4ac0204d67b38f01433ac7f9b870fa38c6", size = 20963778 }, - { url = "https://files.pythonhosted.org/packages/ff/77/19c5e62d55bff507a18c3cdff82e94fe174957bad25860a991cac719d3ab/numpy-2.2.5-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dfa94b6a4374e7851bbb6f35e6ded2120b752b063e6acdd3157e4d2bb922eba", size = 14207279 }, - { url = "https://files.pythonhosted.org/packages/75/22/aa11f22dc11ff4ffe4e849d9b63bbe8d4ac6d5fae85ddaa67dfe43be3e76/numpy-2.2.5-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:97c8425d4e26437e65e1d189d22dff4a079b747ff9c2788057bfb8114ce1e133", size = 5199247 }, - { url = "https://files.pythonhosted.org/packages/4f/6c/12d5e760fc62c08eded0394f62039f5a9857f758312bf01632a81d841459/numpy-2.2.5-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:352d330048c055ea6db701130abc48a21bec690a8d38f8284e00fab256dc1376", size = 6711087 }, - { url = "https://files.pythonhosted.org/packages/ef/94/ece8280cf4218b2bee5cec9567629e61e51b4be501e5c6840ceb593db945/numpy-2.2.5-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b4c0773b6ada798f51f0f8e30c054d32304ccc6e9c5d93d46cb26f3d385ab19", size = 14059964 }, - { url = "https://files.pythonhosted.org/packages/39/41/c5377dac0514aaeec69115830a39d905b1882819c8e65d97fc60e177e19e/numpy-2.2.5-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55f09e00d4dccd76b179c0f18a44f041e5332fd0e022886ba1c0bbf3ea4a18d0", size = 16121214 }, - { url = "https://files.pythonhosted.org/packages/db/54/3b9f89a943257bc8e187145c6bc0eb8e3d615655f7b14e9b490b053e8149/numpy-2.2.5-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02f226baeefa68f7d579e213d0f3493496397d8f1cff5e2b222af274c86a552a", size = 15575788 }, - { url = "https://files.pythonhosted.org/packages/b1/c4/2e407e85df35b29f79945751b8f8e671057a13a376497d7fb2151ba0d290/numpy-2.2.5-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c26843fd58f65da9491165072da2cccc372530681de481ef670dcc8e27cfb066", size = 17893672 }, - { url = "https://files.pythonhosted.org/packages/29/7e/d0b44e129d038dba453f00d0e29ebd6eaf2f06055d72b95b9947998aca14/numpy-2.2.5-cp313-cp313t-win32.whl", hash = "sha256:1a161c2c79ab30fe4501d5a2bbfe8b162490757cf90b7f05be8b80bc02f7bb8e", size = 6377102 }, - { url = "https://files.pythonhosted.org/packages/63/be/b85e4aa4bf42c6502851b971f1c326d583fcc68227385f92089cf50a7b45/numpy-2.2.5-cp313-cp313t-win_amd64.whl", hash = "sha256:d403c84991b5ad291d3809bace5e85f4bbf44a04bdc9a88ed2bb1807b3360bb8", size = 12750096 }, - { url = "https://files.pythonhosted.org/packages/35/e4/5ef5ef1d4308f96961198b2323bfc7c7afb0ccc0d623b01c79bc87ab496d/numpy-2.2.5-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b4ea7e1cff6784e58fe281ce7e7f05036b3e1c89c6f922a6bfbc0a7e8768adbe", size = 21083404 }, - { url = "https://files.pythonhosted.org/packages/a3/5f/bde9238e8e977652a16a4b114ed8aa8bb093d718c706eeecb5f7bfa59572/numpy-2.2.5-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d7543263084a85fbc09c704b515395398d31d6395518446237eac219eab9e55e", size = 6828578 }, - { url = "https://files.pythonhosted.org/packages/ef/7f/813f51ed86e559ab2afb6a6f33aa6baf8a560097e25e4882a938986c76c2/numpy-2.2.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0255732338c4fdd00996c0421884ea8a3651eea555c3a56b84892b66f696eb70", size = 16234796 }, - { url = "https://files.pythonhosted.org/packages/68/67/1175790323026d3337cc285cc9c50eca637d70472b5e622529df74bb8f37/numpy-2.2.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d2e3bdadaba0e040d1e7ab39db73e0afe2c74ae277f5614dad53eadbecbbb169", size = 12859001 }, -] - -[[package]] -name = "oauthlib" -version = "3.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/fa/fbf4001037904031639e6bfbfc02badfc7e12f137a8afa254df6c4c8a670/oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918", size = 177352 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", size = 151688 }, -] - -[[package]] -name = "packaging" -version = "25.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, -] - -[[package]] -name = "pandas" -version = "2.2.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "tzdata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/70/c853aec59839bceed032d52010ff5f1b8d87dc3114b762e4ba2727661a3b/pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", size = 12580827 }, - { url = "https://files.pythonhosted.org/packages/99/f2/c4527768739ffa4469b2b4fff05aa3768a478aed89a2f271a79a40eee984/pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", size = 11303897 }, - { url = "https://files.pythonhosted.org/packages/ed/12/86c1747ea27989d7a4064f806ce2bae2c6d575b950be087837bdfcabacc9/pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", size = 66480908 }, - { url = "https://files.pythonhosted.org/packages/44/50/7db2cd5e6373ae796f0ddad3675268c8d59fb6076e66f0c339d61cea886b/pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", size = 13064210 }, - { url = "https://files.pythonhosted.org/packages/61/61/a89015a6d5536cb0d6c3ba02cebed51a95538cf83472975275e28ebf7d0c/pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", size = 16754292 }, - { url = "https://files.pythonhosted.org/packages/ce/0d/4cc7b69ce37fac07645a94e1d4b0880b15999494372c1523508511b09e40/pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", size = 14416379 }, - { url = "https://files.pythonhosted.org/packages/31/9e/6ebb433de864a6cd45716af52a4d7a8c3c9aaf3a98368e61db9e69e69a9c/pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", size = 11598471 }, - { url = "https://files.pythonhosted.org/packages/a8/44/d9502bf0ed197ba9bf1103c9867d5904ddcaf869e52329787fc54ed70cc8/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", size = 12602222 }, - { url = "https://files.pythonhosted.org/packages/52/11/9eac327a38834f162b8250aab32a6781339c69afe7574368fffe46387edf/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", size = 11321274 }, - { url = "https://files.pythonhosted.org/packages/45/fb/c4beeb084718598ba19aa9f5abbc8aed8b42f90930da861fcb1acdb54c3a/pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", size = 15579836 }, - { url = "https://files.pythonhosted.org/packages/cd/5f/4dba1d39bb9c38d574a9a22548c540177f78ea47b32f99c0ff2ec499fac5/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", size = 13058505 }, - { url = "https://files.pythonhosted.org/packages/b9/57/708135b90391995361636634df1f1130d03ba456e95bcf576fada459115a/pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", size = 16744420 }, - { url = "https://files.pythonhosted.org/packages/86/4a/03ed6b7ee323cf30404265c284cee9c65c56a212e0a08d9ee06984ba2240/pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", size = 14440457 }, - { url = "https://files.pythonhosted.org/packages/ed/8c/87ddf1fcb55d11f9f847e3c69bb1c6f8e46e2f40ab1a2d2abadb2401b007/pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", size = 11617166 }, - { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893 }, - { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475 }, - { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645 }, - { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445 }, - { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 }, - { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 }, - { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 }, - { url = "https://files.pythonhosted.org/packages/64/22/3b8f4e0ed70644e85cfdcd57454686b9057c6c38d2f74fe4b8bc2527214a/pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", size = 12477643 }, - { url = "https://files.pythonhosted.org/packages/e4/93/b3f5d1838500e22c8d793625da672f3eec046b1a99257666c94446969282/pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", size = 11281573 }, - { url = "https://files.pythonhosted.org/packages/f5/94/6c79b07f0e5aab1dcfa35a75f4817f5c4f677931d4234afcd75f0e6a66ca/pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", size = 15196085 }, - { url = "https://files.pythonhosted.org/packages/e8/31/aa8da88ca0eadbabd0a639788a6da13bb2ff6edbbb9f29aa786450a30a91/pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", size = 12711809 }, - { url = "https://files.pythonhosted.org/packages/ee/7c/c6dbdb0cb2a4344cacfb8de1c5808ca885b2e4dcfde8008266608f9372af/pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", size = 16356316 }, - { url = "https://files.pythonhosted.org/packages/57/b7/8b757e7d92023b832869fa8881a992696a0bfe2e26f72c9ae9f255988d42/pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", size = 14022055 }, - { url = "https://files.pythonhosted.org/packages/3b/bc/4b18e2b8c002572c5a441a64826252ce5da2aa738855747247a971988043/pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", size = 11481175 }, - { url = "https://files.pythonhosted.org/packages/76/a3/a5d88146815e972d40d19247b2c162e88213ef51c7c25993942c39dbf41d/pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", size = 12615650 }, - { url = "https://files.pythonhosted.org/packages/9c/8c/f0fd18f6140ddafc0c24122c8a964e48294acc579d47def376fef12bcb4a/pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", size = 11290177 }, - { url = "https://files.pythonhosted.org/packages/ed/f9/e995754eab9c0f14c6777401f7eece0943840b7a9fc932221c19d1abee9f/pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", size = 14651526 }, - { url = "https://files.pythonhosted.org/packages/25/b0/98d6ae2e1abac4f35230aa756005e8654649d305df9a28b16b9ae4353bff/pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", size = 11871013 }, - { url = "https://files.pythonhosted.org/packages/cc/57/0f72a10f9db6a4628744c8e8f0df4e6e21de01212c7c981d31e50ffc8328/pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", size = 15711620 }, - { url = "https://files.pythonhosted.org/packages/ab/5f/b38085618b950b79d2d9164a711c52b10aefc0ae6833b96f626b7021b2ed/pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", size = 13098436 }, -] - -[[package]] -name = "pefile" -version = "2023.2.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/78/c5/3b3c62223f72e2360737fd2a57c30e5b2adecd85e70276879609a7403334/pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc", size = 74854 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/26/d0ad8b448476d0a1e8d3ea5622dc77b916db84c6aa3cb1e1c0965af948fc/pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6", size = 71791 }, -] - -[[package]] -name = "pillow" -version = "11.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/8b/b158ad57ed44d3cc54db8d68ad7c0a58b8fc0e4c7a3f995f9d62d5b464a1/pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047", size = 3198442 }, - { url = "https://files.pythonhosted.org/packages/b1/f8/bb5d956142f86c2d6cc36704943fa761f2d2e4c48b7436fd0a85c20f1713/pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95", size = 3030553 }, - { url = "https://files.pythonhosted.org/packages/22/7f/0e413bb3e2aa797b9ca2c5c38cb2e2e45d88654e5b12da91ad446964cfae/pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61", size = 4405503 }, - { url = "https://files.pythonhosted.org/packages/f3/b4/cc647f4d13f3eb837d3065824aa58b9bcf10821f029dc79955ee43f793bd/pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1", size = 4490648 }, - { url = "https://files.pythonhosted.org/packages/c2/6f/240b772a3b35cdd7384166461567aa6713799b4e78d180c555bd284844ea/pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c", size = 4508937 }, - { url = "https://files.pythonhosted.org/packages/f3/5e/7ca9c815ade5fdca18853db86d812f2f188212792780208bdb37a0a6aef4/pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d", size = 4599802 }, - { url = "https://files.pythonhosted.org/packages/02/81/c3d9d38ce0c4878a77245d4cf2c46d45a4ad0f93000227910a46caff52f3/pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97", size = 4576717 }, - { url = "https://files.pythonhosted.org/packages/42/49/52b719b89ac7da3185b8d29c94d0e6aec8140059e3d8adcaa46da3751180/pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579", size = 4654874 }, - { url = "https://files.pythonhosted.org/packages/5b/0b/ede75063ba6023798267023dc0d0401f13695d228194d2242d5a7ba2f964/pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d", size = 2331717 }, - { url = "https://files.pythonhosted.org/packages/ed/3c/9831da3edea527c2ed9a09f31a2c04e77cd705847f13b69ca60269eec370/pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad", size = 2676204 }, - { url = "https://files.pythonhosted.org/packages/01/97/1f66ff8a1503d8cbfc5bae4dc99d54c6ec1e22ad2b946241365320caabc2/pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2", size = 2414767 }, - { url = "https://files.pythonhosted.org/packages/68/08/3fbf4b98924c73037a8e8b4c2c774784805e0fb4ebca6c5bb60795c40125/pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70", size = 3198450 }, - { url = "https://files.pythonhosted.org/packages/84/92/6505b1af3d2849d5e714fc75ba9e69b7255c05ee42383a35a4d58f576b16/pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf", size = 3030550 }, - { url = "https://files.pythonhosted.org/packages/3c/8c/ac2f99d2a70ff966bc7eb13dacacfaab57c0549b2ffb351b6537c7840b12/pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7", size = 4415018 }, - { url = "https://files.pythonhosted.org/packages/1f/e3/0a58b5d838687f40891fff9cbaf8669f90c96b64dc8f91f87894413856c6/pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8", size = 4498006 }, - { url = "https://files.pythonhosted.org/packages/21/f5/6ba14718135f08fbfa33308efe027dd02b781d3f1d5c471444a395933aac/pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600", size = 4517773 }, - { url = "https://files.pythonhosted.org/packages/20/f2/805ad600fc59ebe4f1ba6129cd3a75fb0da126975c8579b8f57abeb61e80/pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788", size = 4607069 }, - { url = "https://files.pythonhosted.org/packages/71/6b/4ef8a288b4bb2e0180cba13ca0a519fa27aa982875882392b65131401099/pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e", size = 4583460 }, - { url = "https://files.pythonhosted.org/packages/62/ae/f29c705a09cbc9e2a456590816e5c234382ae5d32584f451c3eb41a62062/pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e", size = 4661304 }, - { url = "https://files.pythonhosted.org/packages/6e/1a/c8217b6f2f73794a5e219fbad087701f412337ae6dbb956db37d69a9bc43/pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6", size = 2331809 }, - { url = "https://files.pythonhosted.org/packages/e2/72/25a8f40170dc262e86e90f37cb72cb3de5e307f75bf4b02535a61afcd519/pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193", size = 2676338 }, - { url = "https://files.pythonhosted.org/packages/06/9e/76825e39efee61efea258b479391ca77d64dbd9e5804e4ad0fa453b4ba55/pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7", size = 2414918 }, - { url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185 }, - { url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306 }, - { url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121 }, - { url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707 }, - { url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921 }, - { url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523 }, - { url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836 }, - { url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390 }, - { url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309 }, - { url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768 }, - { url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087 }, - { url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098 }, - { url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166 }, - { url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674 }, - { url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005 }, - { url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707 }, - { url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008 }, - { url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420 }, - { url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655 }, - { url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329 }, - { url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388 }, - { url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950 }, - { url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759 }, - { url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284 }, - { url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826 }, - { url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329 }, - { url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049 }, - { url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408 }, - { url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863 }, - { url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938 }, - { url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774 }, - { url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895 }, - { url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234 }, - { url = "https://files.pythonhosted.org/packages/33/49/c8c21e4255b4f4a2c0c68ac18125d7f5460b109acc6dfdef1a24f9b960ef/pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156", size = 3181727 }, - { url = "https://files.pythonhosted.org/packages/6d/f1/f7255c0838f8c1ef6d55b625cfb286835c17e8136ce4351c5577d02c443b/pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772", size = 2999833 }, - { url = "https://files.pythonhosted.org/packages/e2/57/9968114457bd131063da98d87790d080366218f64fa2943b65ac6739abb3/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363", size = 3437472 }, - { url = "https://files.pythonhosted.org/packages/b2/1b/e35d8a158e21372ecc48aac9c453518cfe23907bb82f950d6e1c72811eb0/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0", size = 3459976 }, - { url = "https://files.pythonhosted.org/packages/26/da/2c11d03b765efff0ccc473f1c4186dc2770110464f2177efaed9cf6fae01/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01", size = 3527133 }, - { url = "https://files.pythonhosted.org/packages/79/1a/4e85bd7cadf78412c2a3069249a09c32ef3323650fd3005c97cca7aa21df/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193", size = 3571555 }, - { url = "https://files.pythonhosted.org/packages/69/03/239939915216de1e95e0ce2334bf17a7870ae185eb390fab6d706aadbfc0/pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013", size = 2674713 }, - { url = "https://files.pythonhosted.org/packages/a4/ad/2613c04633c7257d9481ab21d6b5364b59fc5d75faafd7cb8693523945a3/pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed", size = 3181734 }, - { url = "https://files.pythonhosted.org/packages/a4/fd/dcdda4471ed667de57bb5405bb42d751e6cfdd4011a12c248b455c778e03/pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c", size = 2999841 }, - { url = "https://files.pythonhosted.org/packages/ac/89/8a2536e95e77432833f0db6fd72a8d310c8e4272a04461fb833eb021bf94/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd", size = 3437470 }, - { url = "https://files.pythonhosted.org/packages/9d/8f/abd47b73c60712f88e9eda32baced7bfc3e9bd6a7619bb64b93acff28c3e/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076", size = 3460013 }, - { url = "https://files.pythonhosted.org/packages/f6/20/5c0a0aa83b213b7a07ec01e71a3d6ea2cf4ad1d2c686cc0168173b6089e7/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b", size = 3527165 }, - { url = "https://files.pythonhosted.org/packages/58/0e/2abab98a72202d91146abc839e10c14f7cf36166f12838ea0c4db3ca6ecb/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f", size = 3571586 }, - { url = "https://files.pythonhosted.org/packages/21/2c/5e05f58658cf49b6667762cca03d6e7d85cededde2caf2ab37b81f80e574/pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044", size = 2674751 }, -] - -[[package]] -name = "platformdirs" -version = "4.3.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/2d/7d512a3913d60623e7eb945c6d1b4f0bddf1d0b7ada5225274c87e5b53d1/platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351", size = 21291 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/45/59578566b3275b8fd9157885918fcd0c4d74162928a5310926887b856a51/platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94", size = 18499 }, -] - -[[package]] -name = "plotly" -version = "6.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "narwhals" }, - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c7/cc/e41b5f697ae403f0b50e47b7af2e36642a193085f553bf7cc1169362873a/plotly-6.0.1.tar.gz", hash = "sha256:dd8400229872b6e3c964b099be699f8d00c489a974f2cfccfad5e8240873366b", size = 8094643 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/02/65/ad2bc85f7377f5cfba5d4466d5474423a3fb7f6a97fd807c06f92dd3e721/plotly-6.0.1-py3-none-any.whl", hash = "sha256:4714db20fea57a435692c548a4eb4fae454f7daddf15f8d8ba7e1045681d7768", size = 14805757 }, -] - -[[package]] -name = "pluggy" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, -] - -[[package]] -name = "pre-commit" -version = "4.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cfgv" }, - { name = "identify" }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707 }, -] - -[[package]] -name = "priority" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/3c/eb7c35f4dcede96fca1842dac5f4f5d15511aa4b52f3a961219e68ae9204/priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0", size = 24792 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl", hash = "sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa", size = 8946 }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, -] - -[[package]] -name = "pydantic" -version = "2.11.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/10/2e/ca897f093ee6c5f3b0bee123ee4465c50e75431c3d5b6a3b44a47134e891/pydantic-2.11.3.tar.gz", hash = "sha256:7471657138c16adad9322fe3070c0116dd6c3ad8d649300e3cbdfe91f4db4ec3", size = 785513 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/1d/407b29780a289868ed696d1616f4aad49d6388e5a77f567dcd2629dcd7b8/pydantic-2.11.3-py3-none-any.whl", hash = "sha256:a082753436a07f9ba1289c6ffa01cd93db3548776088aa917cc43b63f68fa60f", size = 443591 }, -] - -[[package]] -name = "pydantic-core" -version = "2.33.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/17/19/ed6a078a5287aea7922de6841ef4c06157931622c89c2a47940837b5eecd/pydantic_core-2.33.1.tar.gz", hash = "sha256:bcc9c6fdb0ced789245b02b7d6603e17d1563064ddcfc36f046b61c0c05dd9df", size = 434395 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/ea/5f572806ab4d4223d11551af814d243b0e3e02cc6913def4d1fe4a5ca41c/pydantic_core-2.33.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3077cfdb6125cc8dab61b155fdd714663e401f0e6883f9632118ec12cf42df26", size = 2044021 }, - { url = "https://files.pythonhosted.org/packages/8c/d1/f86cc96d2aa80e3881140d16d12ef2b491223f90b28b9a911346c04ac359/pydantic_core-2.33.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ffab8b2908d152e74862d276cf5017c81a2f3719f14e8e3e8d6b83fda863927", size = 1861742 }, - { url = "https://files.pythonhosted.org/packages/37/08/fbd2cd1e9fc735a0df0142fac41c114ad9602d1c004aea340169ae90973b/pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5183e4f6a2d468787243ebcd70cf4098c247e60d73fb7d68d5bc1e1beaa0c4db", size = 1910414 }, - { url = "https://files.pythonhosted.org/packages/7f/73/3ac217751decbf8d6cb9443cec9b9eb0130eeada6ae56403e11b486e277e/pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:398a38d323f37714023be1e0285765f0a27243a8b1506b7b7de87b647b517e48", size = 1996848 }, - { url = "https://files.pythonhosted.org/packages/9a/f5/5c26b265cdcff2661e2520d2d1e9db72d117ea00eb41e00a76efe68cb009/pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:87d3776f0001b43acebfa86f8c64019c043b55cc5a6a2e313d728b5c95b46969", size = 2141055 }, - { url = "https://files.pythonhosted.org/packages/5d/14/a9c3cee817ef2f8347c5ce0713e91867a0dceceefcb2973942855c917379/pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c566dd9c5f63d22226409553531f89de0cac55397f2ab8d97d6f06cfce6d947e", size = 2753806 }, - { url = "https://files.pythonhosted.org/packages/f2/68/866ce83a51dd37e7c604ce0050ff6ad26de65a7799df89f4db87dd93d1d6/pydantic_core-2.33.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d5f3acc81452c56895e90643a625302bd6be351e7010664151cc55b7b97f89", size = 2007777 }, - { url = "https://files.pythonhosted.org/packages/b6/a8/36771f4404bb3e49bd6d4344da4dede0bf89cc1e01f3b723c47248a3761c/pydantic_core-2.33.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d3a07fadec2a13274a8d861d3d37c61e97a816beae717efccaa4b36dfcaadcde", size = 2122803 }, - { url = "https://files.pythonhosted.org/packages/18/9c/730a09b2694aa89360d20756369822d98dc2f31b717c21df33b64ffd1f50/pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f99aeda58dce827f76963ee87a0ebe75e648c72ff9ba1174a253f6744f518f65", size = 2086755 }, - { url = "https://files.pythonhosted.org/packages/54/8e/2dccd89602b5ec31d1c58138d02340ecb2ebb8c2cac3cc66b65ce3edb6ce/pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:902dbc832141aa0ec374f4310f1e4e7febeebc3256f00dc359a9ac3f264a45dc", size = 2257358 }, - { url = "https://files.pythonhosted.org/packages/d1/9c/126e4ac1bfad8a95a9837acdd0963695d69264179ba4ede8b8c40d741702/pydantic_core-2.33.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fe44d56aa0b00d66640aa84a3cbe80b7a3ccdc6f0b1ca71090696a6d4777c091", size = 2257916 }, - { url = "https://files.pythonhosted.org/packages/7d/ba/91eea2047e681a6853c81c20aeca9dcdaa5402ccb7404a2097c2adf9d038/pydantic_core-2.33.1-cp310-cp310-win32.whl", hash = "sha256:ed3eb16d51257c763539bde21e011092f127a2202692afaeaccb50db55a31383", size = 1923823 }, - { url = "https://files.pythonhosted.org/packages/94/c0/fcdf739bf60d836a38811476f6ecd50374880b01e3014318b6e809ddfd52/pydantic_core-2.33.1-cp310-cp310-win_amd64.whl", hash = "sha256:694ad99a7f6718c1a498dc170ca430687a39894a60327f548e02a9c7ee4b6504", size = 1952494 }, - { url = "https://files.pythonhosted.org/packages/d6/7f/c6298830cb780c46b4f46bb24298d01019ffa4d21769f39b908cd14bbd50/pydantic_core-2.33.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e966fc3caaf9f1d96b349b0341c70c8d6573bf1bac7261f7b0ba88f96c56c24", size = 2044224 }, - { url = "https://files.pythonhosted.org/packages/a8/65/6ab3a536776cad5343f625245bd38165d6663256ad43f3a200e5936afd6c/pydantic_core-2.33.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bfd0adeee563d59c598ceabddf2c92eec77abcb3f4a391b19aa7366170bd9e30", size = 1858845 }, - { url = "https://files.pythonhosted.org/packages/e9/15/9a22fd26ba5ee8c669d4b8c9c244238e940cd5d818649603ca81d1c69861/pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91815221101ad3c6b507804178a7bb5cb7b2ead9ecd600041669c8d805ebd595", size = 1910029 }, - { url = "https://files.pythonhosted.org/packages/d5/33/8cb1a62818974045086f55f604044bf35b9342900318f9a2a029a1bec460/pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9fea9c1869bb4742d174a57b4700c6dadea951df8b06de40c2fedb4f02931c2e", size = 1997784 }, - { url = "https://files.pythonhosted.org/packages/c0/ca/49958e4df7715c71773e1ea5be1c74544923d10319173264e6db122543f9/pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d20eb4861329bb2484c021b9d9a977566ab16d84000a57e28061151c62b349a", size = 2141075 }, - { url = "https://files.pythonhosted.org/packages/7b/a6/0b3a167a9773c79ba834b959b4e18c3ae9216b8319bd8422792abc8a41b1/pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb935c5591573ae3201640579f30128ccc10739b45663f93c06796854405505", size = 2745849 }, - { url = "https://files.pythonhosted.org/packages/0b/60/516484135173aa9e5861d7a0663dce82e4746d2e7f803627d8c25dfa5578/pydantic_core-2.33.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c964fd24e6166420d18fb53996d8c9fd6eac9bf5ae3ec3d03015be4414ce497f", size = 2005794 }, - { url = "https://files.pythonhosted.org/packages/86/70/05b1eb77459ad47de00cf78ee003016da0cedf8b9170260488d7c21e9181/pydantic_core-2.33.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:681d65e9011f7392db5aa002b7423cc442d6a673c635668c227c6c8d0e5a4f77", size = 2123237 }, - { url = "https://files.pythonhosted.org/packages/c7/57/12667a1409c04ae7dc95d3b43158948eb0368e9c790be8b095cb60611459/pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e100c52f7355a48413e2999bfb4e139d2977a904495441b374f3d4fb4a170961", size = 2086351 }, - { url = "https://files.pythonhosted.org/packages/57/61/cc6d1d1c1664b58fdd6ecc64c84366c34ec9b606aeb66cafab6f4088974c/pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:048831bd363490be79acdd3232f74a0e9951b11b2b4cc058aeb72b22fdc3abe1", size = 2258914 }, - { url = "https://files.pythonhosted.org/packages/d1/0a/edb137176a1f5419b2ddee8bde6a0a548cfa3c74f657f63e56232df8de88/pydantic_core-2.33.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bdc84017d28459c00db6f918a7272a5190bec3090058334e43a76afb279eac7c", size = 2257385 }, - { url = "https://files.pythonhosted.org/packages/26/3c/48ca982d50e4b0e1d9954919c887bdc1c2b462801bf408613ccc641b3daa/pydantic_core-2.33.1-cp311-cp311-win32.whl", hash = "sha256:32cd11c5914d1179df70406427097c7dcde19fddf1418c787540f4b730289896", size = 1923765 }, - { url = "https://files.pythonhosted.org/packages/33/cd/7ab70b99e5e21559f5de38a0928ea84e6f23fdef2b0d16a6feaf942b003c/pydantic_core-2.33.1-cp311-cp311-win_amd64.whl", hash = "sha256:2ea62419ba8c397e7da28a9170a16219d310d2cf4970dbc65c32faf20d828c83", size = 1950688 }, - { url = "https://files.pythonhosted.org/packages/4b/ae/db1fc237b82e2cacd379f63e3335748ab88b5adde98bf7544a1b1bd10a84/pydantic_core-2.33.1-cp311-cp311-win_arm64.whl", hash = "sha256:fc903512177361e868bc1f5b80ac8c8a6e05fcdd574a5fb5ffeac5a9982b9e89", size = 1908185 }, - { url = "https://files.pythonhosted.org/packages/c8/ce/3cb22b07c29938f97ff5f5bb27521f95e2ebec399b882392deb68d6c440e/pydantic_core-2.33.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1293d7febb995e9d3ec3ea09caf1a26214eec45b0f29f6074abb004723fc1de8", size = 2026640 }, - { url = "https://files.pythonhosted.org/packages/19/78/f381d643b12378fee782a72126ec5d793081ef03791c28a0fd542a5bee64/pydantic_core-2.33.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:99b56acd433386c8f20be5c4000786d1e7ca0523c8eefc995d14d79c7a081498", size = 1852649 }, - { url = "https://files.pythonhosted.org/packages/9d/2b/98a37b80b15aac9eb2c6cfc6dbd35e5058a352891c5cce3a8472d77665a6/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35a5ec3fa8c2fe6c53e1b2ccc2454398f95d5393ab398478f53e1afbbeb4d939", size = 1892472 }, - { url = "https://files.pythonhosted.org/packages/4e/d4/3c59514e0f55a161004792b9ff3039da52448f43f5834f905abef9db6e4a/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b172f7b9d2f3abc0efd12e3386f7e48b576ef309544ac3a63e5e9cdd2e24585d", size = 1977509 }, - { url = "https://files.pythonhosted.org/packages/a9/b6/c2c7946ef70576f79a25db59a576bce088bdc5952d1b93c9789b091df716/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9097b9f17f91eea659b9ec58148c0747ec354a42f7389b9d50701610d86f812e", size = 2128702 }, - { url = "https://files.pythonhosted.org/packages/88/fe/65a880f81e3f2a974312b61f82a03d85528f89a010ce21ad92f109d94deb/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc77ec5b7e2118b152b0d886c7514a4653bcb58c6b1d760134a9fab915f777b3", size = 2679428 }, - { url = "https://files.pythonhosted.org/packages/6f/ff/4459e4146afd0462fb483bb98aa2436d69c484737feaceba1341615fb0ac/pydantic_core-2.33.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3d15245b08fa4a84cefc6c9222e6f37c98111c8679fbd94aa145f9a0ae23d", size = 2008753 }, - { url = "https://files.pythonhosted.org/packages/7c/76/1c42e384e8d78452ededac8b583fe2550c84abfef83a0552e0e7478ccbc3/pydantic_core-2.33.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef99779001d7ac2e2461d8ab55d3373fe7315caefdbecd8ced75304ae5a6fc6b", size = 2114849 }, - { url = "https://files.pythonhosted.org/packages/00/72/7d0cf05095c15f7ffe0eb78914b166d591c0eed72f294da68378da205101/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fc6bf8869e193855e8d91d91f6bf59699a5cdfaa47a404e278e776dd7f168b39", size = 2069541 }, - { url = "https://files.pythonhosted.org/packages/b3/69/94a514066bb7d8be499aa764926937409d2389c09be0b5107a970286ef81/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:b1caa0bc2741b043db7823843e1bde8aaa58a55a58fda06083b0569f8b45693a", size = 2239225 }, - { url = "https://files.pythonhosted.org/packages/84/b0/e390071eadb44b41f4f54c3cef64d8bf5f9612c92686c9299eaa09e267e2/pydantic_core-2.33.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ec259f62538e8bf364903a7d0d0239447059f9434b284f5536e8402b7dd198db", size = 2248373 }, - { url = "https://files.pythonhosted.org/packages/d6/b2/288b3579ffc07e92af66e2f1a11be3b056fe1214aab314748461f21a31c3/pydantic_core-2.33.1-cp312-cp312-win32.whl", hash = "sha256:e14f369c98a7c15772b9da98987f58e2b509a93235582838bd0d1d8c08b68fda", size = 1907034 }, - { url = "https://files.pythonhosted.org/packages/02/28/58442ad1c22b5b6742b992ba9518420235adced665513868f99a1c2638a5/pydantic_core-2.33.1-cp312-cp312-win_amd64.whl", hash = "sha256:1c607801d85e2e123357b3893f82c97a42856192997b95b4d8325deb1cd0c5f4", size = 1956848 }, - { url = "https://files.pythonhosted.org/packages/a1/eb/f54809b51c7e2a1d9f439f158b8dd94359321abcc98767e16fc48ae5a77e/pydantic_core-2.33.1-cp312-cp312-win_arm64.whl", hash = "sha256:8d13f0276806ee722e70a1c93da19748594f19ac4299c7e41237fc791d1861ea", size = 1903986 }, - { url = "https://files.pythonhosted.org/packages/7a/24/eed3466a4308d79155f1cdd5c7432c80ddcc4530ba8623b79d5ced021641/pydantic_core-2.33.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:70af6a21237b53d1fe7b9325b20e65cbf2f0a848cf77bed492b029139701e66a", size = 2033551 }, - { url = "https://files.pythonhosted.org/packages/ab/14/df54b1a0bc9b6ded9b758b73139d2c11b4e8eb43e8ab9c5847c0a2913ada/pydantic_core-2.33.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:282b3fe1bbbe5ae35224a0dbd05aed9ccabccd241e8e6b60370484234b456266", size = 1852785 }, - { url = "https://files.pythonhosted.org/packages/fa/96/e275f15ff3d34bb04b0125d9bc8848bf69f25d784d92a63676112451bfb9/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b315e596282bbb5822d0c7ee9d255595bd7506d1cb20c2911a4da0b970187d3", size = 1897758 }, - { url = "https://files.pythonhosted.org/packages/b7/d8/96bc536e975b69e3a924b507d2a19aedbf50b24e08c80fb00e35f9baaed8/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dfae24cf9921875ca0ca6a8ecb4bb2f13c855794ed0d468d6abbec6e6dcd44a", size = 1986109 }, - { url = "https://files.pythonhosted.org/packages/90/72/ab58e43ce7e900b88cb571ed057b2fcd0e95b708a2e0bed475b10130393e/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6dd8ecfde08d8bfadaea669e83c63939af76f4cf5538a72597016edfa3fad516", size = 2129159 }, - { url = "https://files.pythonhosted.org/packages/dc/3f/52d85781406886c6870ac995ec0ba7ccc028b530b0798c9080531b409fdb/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f593494876eae852dc98c43c6f260f45abdbfeec9e4324e31a481d948214764", size = 2680222 }, - { url = "https://files.pythonhosted.org/packages/f4/56/6e2ef42f363a0eec0fd92f74a91e0ac48cd2e49b695aac1509ad81eee86a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:948b73114f47fd7016088e5186d13faf5e1b2fe83f5e320e371f035557fd264d", size = 2006980 }, - { url = "https://files.pythonhosted.org/packages/4c/c0/604536c4379cc78359f9ee0aa319f4aedf6b652ec2854953f5a14fc38c5a/pydantic_core-2.33.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e11f3864eb516af21b01e25fac915a82e9ddad3bb0fb9e95a246067398b435a4", size = 2120840 }, - { url = "https://files.pythonhosted.org/packages/1f/46/9eb764814f508f0edfb291a0f75d10854d78113fa13900ce13729aaec3ae/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:549150be302428b56fdad0c23c2741dcdb5572413776826c965619a25d9c6bde", size = 2072518 }, - { url = "https://files.pythonhosted.org/packages/42/e3/fb6b2a732b82d1666fa6bf53e3627867ea3131c5f39f98ce92141e3e3dc1/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:495bc156026efafd9ef2d82372bd38afce78ddd82bf28ef5276c469e57c0c83e", size = 2248025 }, - { url = "https://files.pythonhosted.org/packages/5c/9d/fbe8fe9d1aa4dac88723f10a921bc7418bd3378a567cb5e21193a3c48b43/pydantic_core-2.33.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ec79de2a8680b1a67a07490bddf9636d5c2fab609ba8c57597e855fa5fa4dacd", size = 2254991 }, - { url = "https://files.pythonhosted.org/packages/aa/99/07e2237b8a66438d9b26482332cda99a9acccb58d284af7bc7c946a42fd3/pydantic_core-2.33.1-cp313-cp313-win32.whl", hash = "sha256:ee12a7be1742f81b8a65b36c6921022301d466b82d80315d215c4c691724986f", size = 1915262 }, - { url = "https://files.pythonhosted.org/packages/8a/f4/e457a7849beeed1e5defbcf5051c6f7b3c91a0624dd31543a64fc9adcf52/pydantic_core-2.33.1-cp313-cp313-win_amd64.whl", hash = "sha256:ede9b407e39949d2afc46385ce6bd6e11588660c26f80576c11c958e6647bc40", size = 1956626 }, - { url = "https://files.pythonhosted.org/packages/20/d0/e8d567a7cff7b04e017ae164d98011f1e1894269fe8e90ea187a3cbfb562/pydantic_core-2.33.1-cp313-cp313-win_arm64.whl", hash = "sha256:aa687a23d4b7871a00e03ca96a09cad0f28f443690d300500603bd0adba4b523", size = 1909590 }, - { url = "https://files.pythonhosted.org/packages/ef/fd/24ea4302d7a527d672c5be06e17df16aabfb4e9fdc6e0b345c21580f3d2a/pydantic_core-2.33.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:401d7b76e1000d0dd5538e6381d28febdcacb097c8d340dde7d7fc6e13e9f95d", size = 1812963 }, - { url = "https://files.pythonhosted.org/packages/5f/95/4fbc2ecdeb5c1c53f1175a32d870250194eb2fdf6291b795ab08c8646d5d/pydantic_core-2.33.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aeb055a42d734c0255c9e489ac67e75397d59c6fbe60d155851e9782f276a9c", size = 1986896 }, - { url = "https://files.pythonhosted.org/packages/71/ae/fe31e7f4a62431222d8f65a3bd02e3fa7e6026d154a00818e6d30520ea77/pydantic_core-2.33.1-cp313-cp313t-win_amd64.whl", hash = "sha256:338ea9b73e6e109f15ab439e62cb3b78aa752c7fd9536794112e14bee02c8d18", size = 1931810 }, - { url = "https://files.pythonhosted.org/packages/9c/c7/8b311d5adb0fe00a93ee9b4e92a02b0ec08510e9838885ef781ccbb20604/pydantic_core-2.33.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c834f54f8f4640fd7e4b193f80eb25a0602bba9e19b3cd2fc7ffe8199f5ae02", size = 2041659 }, - { url = "https://files.pythonhosted.org/packages/8a/d6/4f58d32066a9e26530daaf9adc6664b01875ae0691570094968aaa7b8fcc/pydantic_core-2.33.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:049e0de24cf23766f12cc5cc71d8abc07d4a9deb9061b334b62093dedc7cb068", size = 1873294 }, - { url = "https://files.pythonhosted.org/packages/f7/3f/53cc9c45d9229da427909c751f8ed2bf422414f7664ea4dde2d004f596ba/pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a28239037b3d6f16916a4c831a5a0eadf856bdd6d2e92c10a0da3a59eadcf3e", size = 1903771 }, - { url = "https://files.pythonhosted.org/packages/f0/49/bf0783279ce674eb9903fb9ae43f6c614cb2f1c4951370258823f795368b/pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d3da303ab5f378a268fa7d45f37d7d85c3ec19769f28d2cc0c61826a8de21fe", size = 2083558 }, - { url = "https://files.pythonhosted.org/packages/9c/5b/0d998367687f986c7d8484a2c476d30f07bf5b8b1477649a6092bd4c540e/pydantic_core-2.33.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25626fb37b3c543818c14821afe0fd3830bc327a43953bc88db924b68c5723f1", size = 2118038 }, - { url = "https://files.pythonhosted.org/packages/b3/33/039287d410230ee125daee57373ac01940d3030d18dba1c29cd3089dc3ca/pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3ab2d36e20fbfcce8f02d73c33a8a7362980cff717926bbae030b93ae46b56c7", size = 2079315 }, - { url = "https://files.pythonhosted.org/packages/1f/85/6d8b2646d99c062d7da2d0ab2faeb0d6ca9cca4c02da6076376042a20da3/pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:2f9284e11c751b003fd4215ad92d325d92c9cb19ee6729ebd87e3250072cdcde", size = 2249063 }, - { url = "https://files.pythonhosted.org/packages/17/d7/c37d208d5738f7b9ad8f22ae8a727d88ebf9c16c04ed2475122cc3f7224a/pydantic_core-2.33.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:048c01eee07d37cbd066fc512b9d8b5ea88ceeb4e629ab94b3e56965ad655add", size = 2254631 }, - { url = "https://files.pythonhosted.org/packages/13/e0/bafa46476d328e4553b85ab9b2f7409e7aaef0ce4c937c894821c542d347/pydantic_core-2.33.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5ccd429694cf26af7997595d627dd2637e7932214486f55b8a357edaac9dae8c", size = 2080877 }, - { url = "https://files.pythonhosted.org/packages/0b/76/1794e440c1801ed35415238d2c728f26cd12695df9057154ad768b7b991c/pydantic_core-2.33.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3a371dc00282c4b84246509a5ddc808e61b9864aa1eae9ecc92bb1268b82db4a", size = 2042858 }, - { url = "https://files.pythonhosted.org/packages/73/b4/9cd7b081fb0b1b4f8150507cd59d27b275c3e22ad60b35cb19ea0977d9b9/pydantic_core-2.33.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f59295ecc75a1788af8ba92f2e8c6eeaa5a94c22fc4d151e8d9638814f85c8fc", size = 1873745 }, - { url = "https://files.pythonhosted.org/packages/e1/d7/9ddb7575d4321e40d0363903c2576c8c0c3280ebea137777e5ab58d723e3/pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08530b8ac922003033f399128505f513e30ca770527cc8bbacf75a84fcc2c74b", size = 1904188 }, - { url = "https://files.pythonhosted.org/packages/d1/a8/3194ccfe461bb08da19377ebec8cb4f13c9bd82e13baebc53c5c7c39a029/pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae370459da6a5466978c0eacf90690cb57ec9d533f8e63e564ef3822bfa04fe", size = 2083479 }, - { url = "https://files.pythonhosted.org/packages/42/c7/84cb569555d7179ca0b3f838cef08f66f7089b54432f5b8599aac6e9533e/pydantic_core-2.33.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e3de2777e3b9f4d603112f78006f4ae0acb936e95f06da6cb1a45fbad6bdb4b5", size = 2118415 }, - { url = "https://files.pythonhosted.org/packages/3b/67/72abb8c73e0837716afbb58a59cc9e3ae43d1aa8677f3b4bc72c16142716/pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a64e81e8cba118e108d7126362ea30e021291b7805d47e4896e52c791be2761", size = 2079623 }, - { url = "https://files.pythonhosted.org/packages/0b/cd/c59707e35a47ba4cbbf153c3f7c56420c58653b5801b055dc52cccc8e2dc/pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:52928d8c1b6bda03cc6d811e8923dffc87a2d3c8b3bfd2ce16471c7147a24850", size = 2250175 }, - { url = "https://files.pythonhosted.org/packages/84/32/e4325a6676b0bed32d5b084566ec86ed7fd1e9bcbfc49c578b1755bde920/pydantic_core-2.33.1-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1b30d92c9412beb5ac6b10a3eb7ef92ccb14e3f2a8d7732e2d739f58b3aa7544", size = 2254674 }, - { url = "https://files.pythonhosted.org/packages/12/6f/5596dc418f2e292ffc661d21931ab34591952e2843e7168ea5a52591f6ff/pydantic_core-2.33.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f995719707e0e29f0f41a8aa3bcea6e761a36c9136104d3189eafb83f5cec5e5", size = 2080951 }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, -] - -[[package]] -name = "pyinstaller" -version = "6.13.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "altgraph" }, - { name = "macholib", marker = "sys_platform == 'darwin'" }, - { name = "packaging" }, - { name = "pefile", marker = "sys_platform == 'win32'" }, - { name = "pyinstaller-hooks-contrib" }, - { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a8/b1/2949fe6d3874e961898ca5cfc1bf2cf13bdeea488b302e74a745bc28c8ba/pyinstaller-6.13.0.tar.gz", hash = "sha256:38911feec2c5e215e5159a7e66fdb12400168bd116143b54a8a7a37f08733456", size = 4276427 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/02/d1a347d35b1b627da1e148159e617576555619ac3bb8bbd5fed661fc7bb5/pyinstaller-6.13.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:aa404f0b02cd57948098055e76ee190b8e65ccf7a2a3f048e5000f668317069f", size = 1001923 }, - { url = "https://files.pythonhosted.org/packages/6b/80/6da39f7aeac65c9ca5afad0fac37887d75fdfd480178a7077c9d30b0704c/pyinstaller-6.13.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:92efcf2f09e78f07b568c5cb7ed48c9940f5dad627af4b49bede6320fab2a06e", size = 718135 }, - { url = "https://files.pythonhosted.org/packages/05/2c/d21d31f780a489609e7bf6385c0f7635238dc98b37cba8645b53322b7450/pyinstaller-6.13.0-py3-none-manylinux2014_i686.whl", hash = "sha256:9f82f113c463f012faa0e323d952ca30a6f922685d9636e754bd3a256c7ed200", size = 728543 }, - { url = "https://files.pythonhosted.org/packages/e1/20/e6ca87bbed6c0163533195707f820f05e10b8da1223fc6972cfe3c3c50c7/pyinstaller-6.13.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:db0e7945ebe276f604eb7c36e536479556ab32853412095e19172a5ec8fca1c5", size = 726868 }, - { url = "https://files.pythonhosted.org/packages/20/d5/53b19285f8817ab6c4b07c570208d62606bab0e5a049d50c93710a1d9dc6/pyinstaller-6.13.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:92fe7337c5aa08d42b38d7a79614492cb571489f2cb0a8f91dc9ef9ccbe01ed3", size = 725037 }, - { url = "https://files.pythonhosted.org/packages/84/5b/08e0b305ba71e6d7cb247e27d714da7536895b0283132d74d249bf662366/pyinstaller-6.13.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:bc09795f5954135dd4486c1535650958c8218acb954f43860e4b05fb515a21c0", size = 721027 }, - { url = "https://files.pythonhosted.org/packages/1f/9c/d8d0a7120103471be8dbe1c5419542aa794b9b9ec2ef628b542f9e6f9ef0/pyinstaller-6.13.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:589937548d34978c568cfdc39f31cf386f45202bc27fdb8facb989c79dfb4c02", size = 723443 }, - { url = "https://files.pythonhosted.org/packages/52/c7/8a9d81569dda2352068ecc6ee779d5feff6729569dd1b4ffd1236ecd38fe/pyinstaller-6.13.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b7260832f7501ba1d2ce1834d4cddc0f2b94315282bc89c59333433715015447", size = 719915 }, - { url = "https://files.pythonhosted.org/packages/d5/e6/cccadb02b90198c7ed4ffb8bc34d420efb72b996f47cbd4738067a602d65/pyinstaller-6.13.0-py3-none-win32.whl", hash = "sha256:80c568848529635aa7ca46d8d525f68486d53e03f68b7bb5eba2c88d742e302c", size = 1294997 }, - { url = "https://files.pythonhosted.org/packages/1a/06/15cbe0e25d1e73d5b981fa41ff0bb02b15e924e30b8c61256f4a28c4c837/pyinstaller-6.13.0-py3-none-win_amd64.whl", hash = "sha256:8d4296236b85aae570379488c2da833b28828b17c57c2cc21fccd7e3811fe372", size = 1352714 }, - { url = "https://files.pythonhosted.org/packages/83/ef/74379298d46e7caa6aa7ceccc865106d3d4b15ac487ffdda2a35bfb6fe79/pyinstaller-6.13.0-py3-none-win_arm64.whl", hash = "sha256:d9f21d56ca2443aa6a1e255e7ad285c76453893a454105abe1b4d45e92bb9a20", size = 1293589 }, -] - -[[package]] -name = "pyinstaller-hooks-contrib" -version = "2025.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/46/195324574e44e52c1ba7f7b0607bc9d488b057d93e253918f1a2759d6a98/pyinstaller_hooks_contrib-2025.3.tar.gz", hash = "sha256:af129da5cd6219669fbda360e295cc822abac55b7647d03fec63a8fcf0a608cf", size = 162501 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/98/0273ffc4f85a4038c8d316a75ef5ac1f10f1bbe5ba50c27871b73da2e3d2/pyinstaller_hooks_contrib-2025.3-py3-none-any.whl", hash = "sha256:70cba46b1a6b82ae9104f074c25926e31f3dde50ff217434d1d660355b949683", size = 434307 }, -] - -[[package]] -name = "pyparsing" -version = "3.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120 }, -] - -[[package]] -name = "pypi-cleanup" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/31/72/db855234dd42f9ba9fa0fa83f485574cbcb29bf90ece677ad166539e69f3/pypi-cleanup-0.1.4.tar.gz", hash = "sha256:46ff485e7cda3534f9f30398fc0f622e5450d4197efb04c55512dbd1303e5ba7", size = 6942 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/7f/211d78d65d7e4d959e5740c520654f7875c6c22c02fc8a894715281c426a/pypi_cleanup-0.1.4-py3-none-any.whl", hash = "sha256:f389ded592caf1d46531b94dac5ef6da11dea8c172c18ff8324de8bbcd1ff6eb", size = 7177 }, -] - -[[package]] -name = "pytest" -version = "8.3.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 }, -] - -[[package]] -name = "python-slugify" -version = "8.0.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "text-unidecode" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051 }, -] - -[[package]] -name = "pytz" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, -] - -[[package]] -name = "pywin32-ctypes" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756 }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, -] - -[[package]] -name = "qrcode" -version = "8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/d4/d222d00f65c81945b55e8f64011c33cb11a2931957ba3e2845fb0874fffe/qrcode-8.1.tar.gz", hash = "sha256:e8df73caf72c3bace3e93d9fa0af5aa78267d4f3f5bc7ab1b208f271605a5e48", size = 41549 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/e6/273de1f5cda537b00bc2947082be747f1d76358db8b945f3a60837bcd0f6/qrcode-8.1-py3-none-any.whl", hash = "sha256:9beba317d793ab8b3838c52af72e603b8ad2599c4e9bbd5c3da37c7dcc13c5cf", size = 45711 }, -] - -[[package]] -name = "repath" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/65/e1/824989291d0f01886074fdf9504ba54598f5665bc4dd373b589b87e76608/repath-0.9.0.tar.gz", hash = "sha256:8292139bac6a0e43fd9d70605d4e8daeb25d46672e484ed31a24c7ce0aef0fb7", size = 5492 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/ed/92e9b8a3ffc562f21df14ef2538f54e911df29730e1f0d79130a4edc86e7/repath-0.9.0-py3-none-any.whl", hash = "sha256:ee079d6c91faeb843274d22d8f786094ee01316ecfe293a1eb6546312bb6a318", size = 4738 }, -] - -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 }, -] - -[[package]] -name = "ruff" -version = "0.11.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/89/6f9c9674818ac2e9cc2f2b35b704b7768656e6b7c139064fc7ba8fbc99f1/ruff-0.11.7.tar.gz", hash = "sha256:655089ad3224070736dc32844fde783454f8558e71f501cb207485fe4eee23d4", size = 4054861 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/ec/21927cb906c5614b786d1621dba405e3d44f6e473872e6df5d1a6bca0455/ruff-0.11.7-py3-none-linux_armv6l.whl", hash = "sha256:d29e909d9a8d02f928d72ab7837b5cbc450a5bdf578ab9ebee3263d0a525091c", size = 10245403 }, - { url = "https://files.pythonhosted.org/packages/e2/af/fec85b6c2c725bcb062a354dd7cbc1eed53c33ff3aa665165871c9c16ddf/ruff-0.11.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dd1fb86b168ae349fb01dd497d83537b2c5541fe0626e70c786427dd8363aaee", size = 11007166 }, - { url = "https://files.pythonhosted.org/packages/31/9a/2d0d260a58e81f388800343a45898fd8df73c608b8261c370058b675319a/ruff-0.11.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d3d7d2e140a6fbbc09033bce65bd7ea29d6a0adeb90b8430262fbacd58c38ada", size = 10378076 }, - { url = "https://files.pythonhosted.org/packages/c2/c4/9b09b45051404d2e7dd6d9dbcbabaa5ab0093f9febcae664876a77b9ad53/ruff-0.11.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4809df77de390a1c2077d9b7945d82f44b95d19ceccf0c287c56e4dc9b91ca64", size = 10557138 }, - { url = "https://files.pythonhosted.org/packages/5e/5e/f62a1b6669870a591ed7db771c332fabb30f83c967f376b05e7c91bccd14/ruff-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3a0c2e169e6b545f8e2dba185eabbd9db4f08880032e75aa0e285a6d3f48201", size = 10095726 }, - { url = "https://files.pythonhosted.org/packages/45/59/a7aa8e716f4cbe07c3500a391e58c52caf665bb242bf8be42c62adef649c/ruff-0.11.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49b888200a320dd96a68e86736cf531d6afba03e4f6cf098401406a257fcf3d6", size = 11672265 }, - { url = "https://files.pythonhosted.org/packages/dd/e3/101a8b707481f37aca5f0fcc3e42932fa38b51add87bfbd8e41ab14adb24/ruff-0.11.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2b19cdb9cf7dae00d5ee2e7c013540cdc3b31c4f281f1dacb5a799d610e90db4", size = 12331418 }, - { url = "https://files.pythonhosted.org/packages/dd/71/037f76cbe712f5cbc7b852e4916cd3cf32301a30351818d32ab71580d1c0/ruff-0.11.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64e0ee994c9e326b43539d133a36a455dbaab477bc84fe7bfbd528abe2f05c1e", size = 11794506 }, - { url = "https://files.pythonhosted.org/packages/ca/de/e450b6bab1fc60ef263ef8fcda077fb4977601184877dce1c59109356084/ruff-0.11.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bad82052311479a5865f52c76ecee5d468a58ba44fb23ee15079f17dd4c8fd63", size = 13939084 }, - { url = "https://files.pythonhosted.org/packages/0e/2c/1e364cc92970075d7d04c69c928430b23e43a433f044474f57e425cbed37/ruff-0.11.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7940665e74e7b65d427b82bffc1e46710ec7f30d58b4b2d5016e3f0321436502", size = 11450441 }, - { url = "https://files.pythonhosted.org/packages/9d/7d/1b048eb460517ff9accd78bca0fa6ae61df2b276010538e586f834f5e402/ruff-0.11.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:169027e31c52c0e36c44ae9a9c7db35e505fee0b39f8d9fca7274a6305295a92", size = 10441060 }, - { url = "https://files.pythonhosted.org/packages/3a/57/8dc6ccfd8380e5ca3d13ff7591e8ba46a3b330323515a4996b991b10bd5d/ruff-0.11.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:305b93f9798aee582e91e34437810439acb28b5fc1fee6b8205c78c806845a94", size = 10058689 }, - { url = "https://files.pythonhosted.org/packages/23/bf/20487561ed72654147817885559ba2aa705272d8b5dee7654d3ef2dbf912/ruff-0.11.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a681db041ef55550c371f9cd52a3cf17a0da4c75d6bd691092dfc38170ebc4b6", size = 11073703 }, - { url = "https://files.pythonhosted.org/packages/9d/27/04f2db95f4ef73dccedd0c21daf9991cc3b7f29901a4362057b132075aa4/ruff-0.11.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:07f1496ad00a4a139f4de220b0c97da6d4c85e0e4aa9b2624167b7d4d44fd6b6", size = 11532822 }, - { url = "https://files.pythonhosted.org/packages/e1/72/43b123e4db52144c8add336581de52185097545981ff6e9e58a21861c250/ruff-0.11.7-py3-none-win32.whl", hash = "sha256:f25dfb853ad217e6e5f1924ae8a5b3f6709051a13e9dad18690de6c8ff299e26", size = 10362436 }, - { url = "https://files.pythonhosted.org/packages/c5/a0/3e58cd76fdee53d5c8ce7a56d84540833f924ccdf2c7d657cb009e604d82/ruff-0.11.7-py3-none-win_amd64.whl", hash = "sha256:0a931d85959ceb77e92aea4bbedfded0a31534ce191252721128f77e5ae1f98a", size = 11566676 }, - { url = "https://files.pythonhosted.org/packages/68/ca/69d7c7752bce162d1516e5592b1cc6b6668e9328c0d270609ddbeeadd7cf/ruff-0.11.7-py3-none-win_arm64.whl", hash = "sha256:778c1e5d6f9e91034142dfd06110534ca13220bfaad5c3735f6cb844654f6177", size = 10677936 }, -] - -[[package]] -name = "setuptools" -version = "79.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/71/b6365e6325b3290e14957b2c3a804a529968c77a049b2ed40c095f749707/setuptools-79.0.1.tar.gz", hash = "sha256:128ce7b8f33c3079fd1b067ecbb4051a66e8526e7b65f6cec075dfc650ddfa88", size = 1367909 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/6d/b4752b044bf94cb802d88a888dc7d288baaf77d7910b7dedda74b5ceea0c/setuptools-79.0.1-py3-none-any.whl", hash = "sha256:e147c0549f27767ba362f9da434eab9c5dc0045d5304feb602a0af001089fc51", size = 1256281 }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037 }, -] - -[[package]] -name = "taskgroup" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f0/8d/e218e0160cc1b692e6e0e5ba34e8865dbb171efeb5fc9a704544b3020605/taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d", size = 11504 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/b1/74babcc824a57904e919f3af16d86c08b524c0691504baf038ef2d7f655c/taskgroup-0.2.2-py2.py3-none-any.whl", hash = "sha256:e2c53121609f4ae97303e9ea1524304b4de6faf9eb2c9280c7f87976479a52fb", size = 14237 }, -] - -[[package]] -name = "text-unidecode" -version = "1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154 }, -] - -[[package]] -name = "toml" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, -] - -[[package]] -name = "tomli" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, - { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, - { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, - { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, - { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, - { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, - { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, - { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, - { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, - { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, - { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, - { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, - { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, - { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, - { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, - { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, - { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, - { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, - { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, - { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, - { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, - { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, - { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, - { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, - { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, - { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, - { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, - { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, - { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, - { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, - { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, -] - -[[package]] -name = "tomlkit" -version = "0.13.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 }, -] - -[[package]] -name = "types-python-dateutil" -version = "2.9.0.20241206" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 }, -] - -[[package]] -name = "typing-extensions" -version = "4.13.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 }, -] - -[[package]] -name = "tzdata" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680 }, -] - -[[package]] -name = "uvicorn" -version = "0.34.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483 }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019 }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898 }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735 }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126 }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789 }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523 }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410 }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476 }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855 }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185 }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256 }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323 }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284 }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349 }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089 }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 }, -] - -[[package]] -name = "virtualenv" -version = "20.30.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "distlib" }, - { name = "filelock" }, - { name = "platformdirs" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/e0/633e369b91bbc664df47dcb5454b6c7cf441e8f5b9d0c250ce9f0546401e/virtualenv-20.30.0.tar.gz", hash = "sha256:800863162bcaa5450a6e4d721049730e7f2dae07720e0902b0e4040bd6f9ada8", size = 4346945 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/ed/3cfeb48175f0671ec430ede81f628f9fb2b1084c9064ca67ebe8c0ed6a05/virtualenv-20.30.0-py3-none-any.whl", hash = "sha256:e34302959180fca3af42d1800df014b35019490b119eba981af27f2fa486e5d6", size = 4329461 }, -] - -[[package]] -name = "watchdog" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390 }, - { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389 }, - { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020 }, - { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 }, - { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 }, - { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 }, - { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 }, - { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 }, - { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 }, - { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 }, - { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 }, - { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 }, - { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902 }, - { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380 }, - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632 }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734 }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008 }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029 }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916 }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763 }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891 }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921 }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422 }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675 }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921 }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526 }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336 }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977 }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232 }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151 }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054 }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955 }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234 }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750 }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591 }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370 }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791 }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622 }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699 }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511 }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715 }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138 }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592 }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532 }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865 }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887 }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498 }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663 }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410 }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965 }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693 }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287 }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531 }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417 }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423 }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185 }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696 }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327 }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741 }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995 }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693 }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677 }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804 }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087 }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947 }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276 }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550 }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542 }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423 }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080 }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329 }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312 }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319 }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631 }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016 }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426 }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360 }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388 }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830 }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423 }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082 }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330 }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878 }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883 }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252 }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521 }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958 }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918 }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388 }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828 }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437 }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096 }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332 }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152 }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096 }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523 }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790 }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165 }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160 }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395 }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841 }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440 }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098 }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329 }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111 }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054 }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496 }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829 }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217 }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195 }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393 }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837 }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109 }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343 }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599 }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207 }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155 }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884 }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, -] - -[[package]] -name = "wsproto" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226 }, -] diff --git a/tools/crocodocs/.gitignore b/tools/crocodocs/.gitignore new file mode 100644 index 0000000000..b782143f5f --- /dev/null +++ b/tools/crocodocs/.gitignore @@ -0,0 +1,135 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +!templates/build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock +uv.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# VS Code +.vscode/ + +# PDM +.pdm.toml +__pypackages__/ + +.ruff_cache/ +*.pyc +*.pyo diff --git a/tools/crocodocs/README.md b/tools/crocodocs/README.md new file mode 100644 index 0000000000..97826a75ed --- /dev/null +++ b/tools/crocodocs/README.md @@ -0,0 +1,304 @@ + + +# CrocoDocs + +CrocoDocs is the internal documentation toolchain that generates structured API artifacts for the Flet Docusaurus website. + +It lives in [tools/crocodocs](./) and is invoked by the website build in [website/package.json](../../website/package.json). + +## What It Does + +CrocoDocs runs a single `generate` command that: + +- renders `website/sidebars.js` from the hand-authored `website/sidebars.yml` +- extracts API data from Python packages using Griffe +- builds the `xref_map` for cross-reference resolution +- generates MDX partials (CLI docs, PyPI index, cross-platform permissions) +- generates code example data from `sdk/python/examples` +- syncs image assets into Docusaurus static paths + +## Build Pipeline + +```text +website/docs (hand-authored) +website/sidebars.yml (hand-authored) +sdk/python/packages/*/src (Python source) +sdk/python/examples (code examples + screenshots) + -> crocodocs generate + -> website/sidebars.js + -> website/.crocodocs/api-data.json + -> website/.crocodocs/code-examples.json + -> website/.crocodocs/*.mdx (partials) + -> website/static/docs/* (synced assets) + +Docusaurus + -> website/build +``` + +### Building locally + +```bash +# Requires Node.js 20+ +nvm use 20 + +cd website +yarn install +yarn build # runs crocodocs generate + docusaurus build +yarn start # runs crocodocs watch + docusaurus dev server +``` + +### Running CrocoDocs directly + +```bash +uv --directory ./tools/crocodocs run crocodocs generate +``` + +`yarn start` runs the Docusaurus dev server through `crocodocs watch`, which: + +- performs an initial `generate` +- watches CrocoDocs inputs for changes +- regenerates API data, sidebars, partials, manifests, and synced assets after saves + +Watched inputs include: + +- `website/sidebars.yml` +- `sdk/python/packages/*/src` +- `sdk/python/examples` +- configured CrocoDocs asset source directories + +`website/docs/**/*.{md,mdx}` is intentionally excluded: Docusaurus hot-reloads +those directly, so regenerating on every prose edit would be redundant. If you +add a new `` (or similar structural change) to a markdown +file, run `crocodocs generate` manually or restart the watcher so the manifest +is refreshed. + +Watch and regenerate without starting Docusaurus: + +```bash +uv --directory ./tools/crocodocs run crocodocs watch +``` + +Watch and run a child process, using `--` to separate the child command: + +```bash +uv --directory ./tools/crocodocs run crocodocs watch --child-cwd ../../website -- yarn exec docusaurus start +``` + +## Configuration + +CrocoDocs is configured in [tools/crocodocs/pyproject.toml](./pyproject.toml). + +### `[tool.crocodocs]` + +Core paths and settings: + +| Key | Purpose | +|-----------------------|------------------------------------------| +| `docs_path` | Path to `website/docs` | +| `api_output` | Where to write `api-data.json` | +| `manifest_output` | Where to write `docs-manifest.json` | +| `partials_output_dir` | Where to write generated `.mdx` partials | +| `sidebars_source` | Path to `sidebars.yml` | +| `sidebars_output` | Path to generated `sidebars.js` | +| `base_url` | Base URL for docs routes (e.g. `/docs`) | +| `examples_root` | Path to code examples directory | +| `extensions` | Griffe extensions to load | + +### `[tool.crocodocs.packages]` + +Maps Python import names to source roots. These packages are scanned during API extraction. + +### `[tool.crocodocs.asset_mappings.*]` + +Defines directories to bulk-copy into `website/static/docs/` during generate. Each mapping has: + +| Key | Purpose | +|------------------|-----------------------------------------------------------| +| `source_path` | Source directory to copy from | +| `static_subpath` | Destination under `website/static/` | +| `include_exts` | File extensions to copy (e.g. `[".png", ".gif", ".svg"]`) | + +Current mappings: + +- `examples` — `sdk/python/examples` (screenshots alongside code examples) +- `test-images` — `sdk/python/packages/flet/integration_tests` (golden test images) +- `test-images-charts` — `sdk/python/packages/flet-charts/integration_tests` + +### `[tool.crocodocs.member_filters]` + +Controls which class members are hidden from API output (e.g. `init`, `before_update`). + +## `sidebars.yml` Format + +[website/sidebars.yml](../../website/sidebars.yml) is the hand-authored sidebar source. +CrocoDocs generates [website/sidebars.js](../../website/sidebars.js) from it during `crocodocs generate`. + +### Rules + +- Top-level keys become sidebar categories +- Nested mapping keys become nested categories +- `Label: path.md` — labeled doc item +- `- path.md` — doc item with label inferred from the page title +- `_index: path.md` — category links to that document +- `_meta` — category options (e.g. `collapsed`) +- `_generated_index` — Docusaurus auto-generated index page with `title`, `slug`, `description` + +### Example + +```yml +docs: + Getting started: + - index.md + - getting-started/installation.md + + Tutorials: + Calculator: tutorials/calculator.md + ToDo: tutorials/todo.md + + Reference: + Controls: + _generated_index: + title: Controls + slug: /controls + description: Browse the complete catalog of controls. + AlertDialog: controls/alertdialog.md + AppBar: controls/appbar.md + + Services: + _index: services/index.md + _meta: + collapsed: false + Audio: services/audio/index.md +``` + +## Doc Page Format + +### Front matter + +```yaml +--- +class_name: "flet.Container" +examples: "controls/container" # relative to examples_root +example_images: "test-images/examples/material/golden/macos/container" # relative to /docs/ static root +example_media: "examples/controls/container/media" # relative to /docs/ static root +title: "Container" +--- +``` + +- `examples` — path relative to the configured `examples_root`, used by `` +- `example_images` / `example_media` — paths relative to `/docs/` static root, used by ``. No `../` navigation needed regardless of doc file depth. + +### Cross-references in docstrings + +Python docstrings use reST-style cross-references: + +```python +"""See :class:`~flet.Page` and :attr:`flet.Control.visible`.""" +``` + +Supported roles: `:class:`, `:attr:`, `:meth:`, `:func:`, `:data:`, `:mod:`, `:obj:` + +The website strips a leading `flet.` or `ft.` from rendered labels automatically +and renders reST API cross-references as inline code links +(for example, `:attr:`flet.Control.visible`` displays as ``Control.visible``). +The `~` prefix still shortens the display to the last component +(for example, `:attr:`~flet.Control.visible`` displays as ``visible``). + +### Cross-references in Markdown + +Hand-written docs use standard Markdown links with relative `.md` paths: + +```markdown +See [`Page`](../controls/page.md) and its [`visible`](../controls/control.md#flet.Control.visible) property. +``` + +Anchor format uses dots: `#flet.ClassName.member_name` + +### Admonitions in docstrings + +Google-style docstring sections are rendered as Docusaurus admonitions: + +```python +""" +Note: + This only works on mobile platforms. + +Warning: + Deprecated since v0.80. +""" +``` + +Supported admonition types: `note`, `tip`, `info`, `warning`, `danger`, `caution`. Other section types (like `Example:`) are rendered as `tip` admonitions. Non-recognized titles are rendered as plain text. + +## How Rendering Works + +CrocoDocs generates data; the Docusaurus website renders it. + +Website components in [website/src/components/crocodocs/](../../website/src/components/crocodocs/): + +| Component | Purpose | +|-------------------|---------------------------------------------------------| +| `ClassAll.js` | Full class page (summary + members) | +| `ClassSummary.js` | Class header with signature, image, inherits | +| `ClassMembers.js` | Properties, events, and methods listing | +| `ClassBlock.js` | Individual member rendering | +| `CodeExample.js` | Inline code example with syntax highlighting | +| `Image.js` | Doc image with `/docs/` prefix for root-relative paths | +| `utils.js` | Markdown rendering, xref resolution, admonition support | + +### Key rendering features + +- Griffe-based class/function/alias rendering with Google-style docstring sections +- Qualified anchors: `#flet.ClassName.member_name` +- reST cross-reference resolution (`:class:`, `:attr:`, `:meth:`, etc.) +- Inherited member resolution via base class walking +- Public alias resolution (e.g. `flet_ads.BaseAd` → `flet_ads.base_ad.BaseAd`) +- Generated TOC injection for properties, events, and methods + +## Verification + +### Broken link check + +Docusaurus checks for broken links and anchors during `yarn build`. The build fails if any are found. + +### Broken image check + +Run after building: + +```bash +bash .github/scripts/check_docs.sh website/build +``` + +This scans all built HTML for `` tags pointing to missing files and for unresolved reST xrefs (`:attr:`, `:class:`, etc.) in the output. + +## CI Integration + +The `docs_build` job in [.github/workflows/ci.yml](../../.github/workflows/ci.yml) runs the full build and verification on every push. It gates the publishing jobs — no release can proceed with broken documentation. + +Cloudflare Pages runs the same build via `pip install uv && yarn build` with root directory set to `website/`. + +## Source Files + +Core tool: + +- [cli.py](./src/crocodocs/cli.py) — CLI entry point +- [config.py](./src/crocodocs/config.py) — Configuration loading +- [generate.py](./src/crocodocs/generate.py) — Main generate command +- [griffe_extract_script.py](./src/crocodocs/griffe_extract_script.py) — Griffe API extraction +- [partials.py](./src/crocodocs/partials.py) — MDX partial generation +- [sidebars.py](./src/crocodocs/sidebars.py) — Sidebar YAML → JS conversion +- [assets.py](./src/crocodocs/assets.py) — Asset bulk copying +- [docs.py](./src/crocodocs/docs.py) — Markdown/MDX parsing helpers +- [pypi_index.py](./src/crocodocs/pypi_index.py) — PyPI package index renderer +- [scripts/](./src/crocodocs/scripts/) — CLI and permissions renderers (run via subprocess in `sdk/python` venv) + +Website integration: + +- [website/package.json](../../website/package.json) — Build scripts +- [website/plugins/remark-api-links.js](../../website/plugins/remark-api-links.js) — Remark plugin for xref resolution in Markdown +- [website/src/components/crocodocs/](../../website/src/components/crocodocs/) — React rendering components +- [website/src/theme/DocItem/Layout/index.js](../../website/src/theme/DocItem/Layout/index.js) — Swizzled doc layout +- [website/src/theme/DocCard/index.js](../../website/src/theme/DocCard/index.js) — Swizzled card component (compact, no emoji) +- [website/src/css/custom.css](../../website/src/css/custom.css) — Custom styles including generated-index grid diff --git a/tools/crocodocs/media/crocodocs-logo.png b/tools/crocodocs/media/crocodocs-logo.png new file mode 100644 index 0000000000..42a88eb472 Binary files /dev/null and b/tools/crocodocs/media/crocodocs-logo.png differ diff --git a/tools/crocodocs/pyproject.toml b/tools/crocodocs/pyproject.toml new file mode 100644 index 0000000000..5d89833ce9 --- /dev/null +++ b/tools/crocodocs/pyproject.toml @@ -0,0 +1,79 @@ +[project] +name = "crocodocs" +version = "0.1.0" +description = "CrocoDocs tooling for Flet docs migration and API data generation" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "griffe>=2.0.0", + "packaging>=23.0", + "PyYAML>=6.0", + "ruff>=0.13.1", + "tomli >=2.0.1; python_version < '3.11'", + "watchdog >=4.0.0", +] + +[project.scripts] +crocodocs = "crocodocs.cli:main" + +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.package-dir] +"" = "src" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.crocodocs] +docs_path = "../../website/docs" +manifest_output = "../../website/.crocodocs/docs-manifest.json" +api_output = "../../website/.crocodocs/api-data.json" +partials_output_dir = "../../website/.crocodocs" +sidebars_source = "../../website/sidebars.yml" +sidebars_output = "../../website/sidebars.js" +base_url = "/docs" +extensions = ["flet.utils.griffe_deprecations"] +examples_root = "../../sdk/python/examples" + +[tool.crocodocs.member_filters] +methods = ["init", "before_update"] + +[tool.crocodocs.asset_mappings.examples] +source_path = "../../sdk/python/examples" +static_subpath = "docs/examples" +include_exts = [".png", ".gif", ".svg"] + +[tool.crocodocs.asset_mappings."test-images"] +source_path = "../../sdk/python/packages/flet/integration_tests" +static_subpath = "docs/test-images" +include_exts = [".png", ".gif", ".svg"] + +[tool.crocodocs.asset_mappings."test-images-charts"] +source_path = "../../sdk/python/packages/flet-charts/integration_tests" +static_subpath = "docs/test-images-charts" +include_exts = [".png", ".gif", ".svg"] + +[tool.crocodocs.packages] +flet = "../../sdk/python/packages/flet/src" +flet_ads = "../../sdk/python/packages/flet-ads/src" +flet_audio = "../../sdk/python/packages/flet-audio/src" +flet_audio_recorder = "../../sdk/python/packages/flet-audio-recorder/src" +flet_camera = "../../sdk/python/packages/flet-camera/src" +flet_charts = "../../sdk/python/packages/flet-charts/src" +flet_cli = "../../sdk/python/packages/flet-cli/src" +flet_code_editor = "../../sdk/python/packages/flet-code-editor/src" +flet_color_pickers = "../../sdk/python/packages/flet-color-pickers/src" +flet_datatable2 = "../../sdk/python/packages/flet-datatable2/src" +flet_desktop = "../../sdk/python/packages/flet-desktop/src" +flet_flashlight = "../../sdk/python/packages/flet-flashlight/src" +flet_geolocator = "../../sdk/python/packages/flet-geolocator/src" +flet_lottie = "../../sdk/python/packages/flet-lottie/src" +flet_map = "../../sdk/python/packages/flet-map/src" +flet_permission_handler = "../../sdk/python/packages/flet-permission-handler/src" +flet_rive = "../../sdk/python/packages/flet-rive/src" +flet_secure_storage = "../../sdk/python/packages/flet-secure-storage/src" +flet_video = "../../sdk/python/packages/flet-video/src" +flet_web = "../../sdk/python/packages/flet-web/src" +flet_webview = "../../sdk/python/packages/flet-webview/src" diff --git a/tools/crocodocs/src/crocodocs/__init__.py b/tools/crocodocs/src/crocodocs/__init__.py new file mode 100644 index 0000000000..61c516def0 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/__init__.py @@ -0,0 +1,5 @@ +"""CrocoDocs tooling package.""" + +__all__ = ["__version__"] + +__version__ = "0.1.0" diff --git a/tools/crocodocs/src/crocodocs/__main__.py b/tools/crocodocs/src/crocodocs/__main__.py new file mode 100644 index 0000000000..a049ad7aea --- /dev/null +++ b/tools/crocodocs/src/crocodocs/__main__.py @@ -0,0 +1,5 @@ +from .cli import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/crocodocs/src/crocodocs/assets.py b/tools/crocodocs/src/crocodocs/assets.py new file mode 100644 index 0000000000..ee126c487b --- /dev/null +++ b/tools/crocodocs/src/crocodocs/assets.py @@ -0,0 +1,29 @@ +"""Asset syncing helpers.""" + +from __future__ import annotations + +import shutil +from pathlib import Path + + +def bulk_copy_assets( + source_root: Path, + dest_root: Path, + include_exts: set[str] | None = None, +) -> int: + """Copy all matching files from *source_root* to *dest_root*. + + Returns the number of files copied. + """ + copied = 0 + for source_path in sorted(source_root.rglob("*")): + if not source_path.is_file(): + continue + if include_exts and source_path.suffix.lower() not in include_exts: + continue + relative = source_path.relative_to(source_root) + dest_path = dest_root / relative + dest_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source_path, dest_path) + copied += 1 + return copied diff --git a/tools/crocodocs/src/crocodocs/cli.py b/tools/crocodocs/src/crocodocs/cli.py new file mode 100644 index 0000000000..9fef61b593 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/cli.py @@ -0,0 +1,182 @@ +"""CrocoDocs CLI entrypoint.""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from .config import ( + apply_package_overrides, + apply_path_override, + apply_value_override, + load_config, +) +from .generate import run_generate +from .watch import run_watch + + +def _add_shared_generate_arguments(parser: argparse.ArgumentParser) -> None: + """Register CLI options that both `generate` and `watch` understand.""" + parser.add_argument( + "--docs-path", + metavar="PATH", + help="Path to the docs directory containing .md/.mdx files. " + "Overrides 'docs_path' from pyproject.toml.", + ) + parser.add_argument( + "--manifest-output", + metavar="PATH", + help="Where to write the docs-manifest JSON file. " + "Overrides 'manifest_output' from pyproject.toml.", + ) + parser.add_argument( + "--output", + metavar="PATH", + help="Where to write the api-data JSON file. " + "Overrides 'api_output' from pyproject.toml.", + ) + parser.add_argument( + "--sidebars-source", + metavar="PATH", + help="Path to the sidebars YAML source file. " + "Overrides 'sidebars_source' from pyproject.toml.", + ) + parser.add_argument( + "--sidebars-output", + metavar="PATH", + help="Where to write the generated sidebars.js file. " + "Overrides 'sidebars_output' from pyproject.toml.", + ) + parser.add_argument( + "--base-url", + metavar="URL", + help="Base URL prefix for generated doc routes (e.g. '/docs'). " + "Overrides 'base_url' from pyproject.toml.", + ) + parser.add_argument( + "--package", + action="append", + metavar="NAME:PATH", + help="Add or override a Python package source root for API extraction. " + "Can be specified multiple times. Example: --package flet:../../sdk/python/packages/flet/src", + ) + parser.add_argument( + "--extensions", + action="append", + metavar="MODULE", + help="Griffe extension module to load during API extraction. " + "Can be specified multiple times.", + ) + + +def _apply_shared_generate_overrides(config, args: argparse.Namespace) -> None: + """Apply path/value/package overrides shared by generation-oriented commands.""" + apply_path_override(config, "docs_path", args.docs_path) + apply_path_override(config, "manifest_output", args.manifest_output) + apply_path_override(config, "api_output", args.output) + apply_path_override(config, "sidebars_source", args.sidebars_source) + apply_path_override(config, "sidebars_output", args.sidebars_output) + apply_value_override(config, "base_url", args.base_url) + apply_package_overrides(config, args.package) + if args.extensions: + config.extensions = args.extensions + + +def build_parser() -> argparse.ArgumentParser: + """Build and return the top-level argument parser with all subcommands registered.""" + parser = argparse.ArgumentParser( + prog="crocodocs", + description="CrocoDocs — documentation artifact generator for the Flet project. " + "Reads configuration from [tool.crocodocs] in pyproject.toml. " + "All path options are resolved relative to the working directory.", + ) + subparsers = parser.add_subparsers(dest="command", required=True) + + generate = subparsers.add_parser( + "generate", + help="Run a one-shot generation of all documentation artifacts.", + description="Generate all documentation artifacts: sidebars, docs manifest, " + "MDX partials, code examples, API data (via Griffe), and asset copies. " + "Defaults are loaded from [tool.crocodocs] in pyproject.toml; " + "CLI flags override individual settings.", + ) + _add_shared_generate_arguments(generate) + + watch = subparsers.add_parser( + "watch", + help="Watch source files and regenerate on changes, optionally running a child process.", + description="Run an initial generation, then watch source files for changes and " + "regenerate automatically. Optionally starts a child process (e.g. Docusaurus " + "dev server) that runs alongside the watcher. The watcher stops when the child " + "exits or when interrupted with Ctrl+C.", + ) + _add_shared_generate_arguments(watch) + watch.add_argument( + "--debounce", + type=float, + default=0.5, + metavar="SECS", + help="Quiet period in seconds after the last detected change before " + "triggering regeneration. Prevents redundant rebuilds during multi-file " + "saves (default: %(default)s).", + ) + watch.add_argument( + "--child-cwd", + metavar="PATH", + help="Working directory for the child command. " + "Resolved relative to the current working directory.", + ) + watch.add_argument( + "watch_command", + nargs=argparse.REMAINDER, + metavar="COMMAND", + help="Command to run alongside the watcher (e.g. a dev server). " + "Use -- before the command to separate it from CrocoDocs options. " + "Example: crocodocs watch -- yarn exec docusaurus start", + ) + + return parser + + +def main(argv: list[str] | None = None) -> int: + """Parse CLI arguments, apply any overrides to the loaded config, and run the command. + + Returns an exit code (0 on success, 2 on error). + """ + parser = build_parser() + args = parser.parse_args(argv) + + # Resolved relative to the CrocoDocs tool directory (Path.cwd() when invoked + # via `uv --directory ./tools/crocodocs`), NOT the repo root. All relative + # paths in pyproject.toml and CLI flags are interpreted from here. + crocodocs_root = Path.cwd() + config = load_config(crocodocs_root) + + if args.command == "generate": + _apply_shared_generate_overrides(config, args) + run_generate( + config, + docs_path=config.docs_path, + manifest_output=config.manifest_output, + api_output=config.api_output, + base_url=config.base_url, + ) + return 0 + + if args.command == "watch": + _apply_shared_generate_overrides(config, args) + command = list(args.watch_command) + if command and command[0] == "--": + command = command[1:] + child_cwd = ( + (crocodocs_root / args.child_cwd).resolve() if args.child_cwd else None + ) + return run_watch( + config, + debounce=args.debounce, + command=command or None, + command_cwd=child_cwd, + ) + + parser.error(f"Unsupported command: {args.command}") + return 2 diff --git a/tools/crocodocs/src/crocodocs/config.py b/tools/crocodocs/src/crocodocs/config.py new file mode 100644 index 0000000000..de938d591f --- /dev/null +++ b/tools/crocodocs/src/crocodocs/config.py @@ -0,0 +1,134 @@ +"""CrocoDocs config loading.""" + +from __future__ import annotations + +import argparse +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +try: + import tomllib +except ModuleNotFoundError: # pragma: no cover + import tomli as tomllib + + +@dataclass +class AssetMapping: + ref_root: str + source_path: Path + static_subpath: str + include_exts: set[str] | None + + +@dataclass +class CrocoDocsConfig: + project_root: Path + docs_path: Path + manifest_output: Path + api_output: Path + partials_output_dir: Path + sidebars_source: Path + sidebars_output: Path + examples_root: Path + asset_mappings: dict[str, AssetMapping] + base_url: str + extensions: list[str] + packages: dict[str, Path] + member_filters: dict[str, set[str]] + + +def _resolve_path(project_root: Path, value: str) -> Path: + """Join project_root with value and return the resolved absolute path.""" + return (project_root / value).resolve() + + +def load_config(project_root: Path) -> CrocoDocsConfig: + """Read [tool.crocodocs] from pyproject.toml and return a CrocoDocsConfig instance.""" + pyproject_path = project_root / "pyproject.toml" + if not pyproject_path.exists(): + raise FileNotFoundError(f"CrocoDocs config not found: {pyproject_path}") + + data = tomllib.loads(pyproject_path.read_text(encoding="utf-8")) + tool = data.get("tool", {}) + raw = tool.get("crocodocs", {}) + raw_packages = raw.get("packages", {}) + raw_member_filters = raw.get("member_filters", {}) + raw_asset_mappings = raw.get("asset_mappings", {}) + asset_mappings = { + ref_root: AssetMapping( + ref_root=ref_root, + source_path=_resolve_path(project_root, mapping["source_path"]), + static_subpath=str(mapping["static_subpath"]).strip("/"), + include_exts=set(mapping["include_exts"]) + if "include_exts" in mapping + else None, + ) + for ref_root, mapping in raw_asset_mappings.items() + } + examples_root_value = raw.get("examples_root") + if examples_root_value is None: + raise KeyError("CrocoDocs config requires 'examples_root'.") + examples_root = _resolve_path(project_root, examples_root_value) + + return CrocoDocsConfig( + project_root=project_root, + docs_path=_resolve_path(project_root, raw["docs_path"]), + manifest_output=_resolve_path(project_root, raw["manifest_output"]), + api_output=_resolve_path(project_root, raw["api_output"]), + partials_output_dir=_resolve_path(project_root, raw["partials_output_dir"]), + sidebars_source=_resolve_path(project_root, raw["sidebars_source"]), + sidebars_output=_resolve_path(project_root, raw["sidebars_output"]), + examples_root=examples_root, + asset_mappings=asset_mappings, + base_url=str(raw["base_url"]), + extensions=list(raw.get("extensions", [])), + packages={ + name: _resolve_path(project_root, path) + for name, path in raw_packages.items() + }, + member_filters={ + key: {str(item) for item in values} + for key, values in raw_member_filters.items() + if isinstance(values, list) + }, + ) + + +def apply_path_override( + config: CrocoDocsConfig, field_name: str, value: str | None +) -> None: + """Set a Path field on config from a CLI string value, resolving it relative to project_root. + + Does nothing when value is None. + """ + if value is None: + return + setattr(config, field_name, (config.project_root / value).resolve()) + + +def apply_value_override( + config: CrocoDocsConfig, field_name: str, value: Any | None +) -> None: + """Set a scalar field on config to value. Does nothing when value is None.""" + if value is None: + return + setattr(config, field_name, value) + + +def apply_package_overrides( + config: CrocoDocsConfig, overrides: list[str] | None +) -> None: + """Apply NAME:PATH package entries from CLI --package flags to config.packages. + + Each override must have the form 'NAME:PATH'; raises ArgumentTypeError otherwise. + """ + if not overrides: + return + for item in overrides: + if ":" not in item: + raise argparse.ArgumentTypeError( + f"Invalid --package value '{item}'. Expected NAME:PATH." + ) + name, path = item.split(":", 1) + config.packages[name] = (config.project_root / path).resolve() diff --git a/tools/crocodocs/src/crocodocs/docs.py b/tools/crocodocs/src/crocodocs/docs.py new file mode 100644 index 0000000000..d33f53ac4f --- /dev/null +++ b/tools/crocodocs/src/crocodocs/docs.py @@ -0,0 +1,68 @@ +"""Markdown and MDX parsing helpers.""" + +from __future__ import annotations + +import re +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any + +from .frontmatter import FrontMatterDocument, parse_front_matter + +COMPONENT_TAG_RE = re.compile(r"<(ClassSummary|ClassMembers|ClassAll)\b([^>]*)/>") +IMPORT_PARTIAL_RE = re.compile(r"@site/\.crocodocs/([a-z0-9._-]+\.mdx)") + + +@dataclass +class SymbolBlock: + kind: str + symbol: str | None + options: dict[str, Any] = field(default_factory=dict) + + +def iter_markdown_files(root: Path) -> list[Path]: + """Return all .md and .mdx files under root, sorted by path.""" + return sorted( + path + for path in root.rglob("*") + if path.is_file() and path.suffix.lower() in {".md", ".mdx"} + ) + + +def extract_symbol_blocks_from_mdx( + text: str, front_matter: dict[str, Any] +) -> list[SymbolBlock]: + """Scan MDX body for ClassSummary/ClassMembers/ClassAll JSX tags and return SymbolBlock entries. + + Symbol names may be literal (name="Foo") or resolved from front matter + (name={frontMatter.key}). + """ + blocks: list[SymbolBlock] = [] + for match in COMPONENT_TAG_RE.finditer(text): + component = match.group(1) + attrs = match.group(2) + symbol = None + options: dict[str, Any] = {} + name_match = re.search(r'name="([^"]+)"', attrs) + if name_match: + symbol = name_match.group(1) + else: + fm_match = re.search(r"name=\{frontMatter\.([a-zA-Z0-9_]+)\}", attrs) + if fm_match: + raw = front_matter.get(fm_match.group(1)) + if isinstance(raw, str): + symbol = raw + if re.search(r"showRootHeading=\{true\}", attrs): + options["showRootHeading"] = True + kind = { + "ClassSummary": "class_summary", + "ClassMembers": "class_members", + "ClassAll": "class_all_options", + }[component] + blocks.append(SymbolBlock(kind=kind, symbol=symbol, options=options)) + return blocks + + +def parse_document(text: str) -> FrontMatterDocument: + """Parse a Markdown/MDX document string into a FrontMatterDocument with data and body.""" + return parse_front_matter(text) diff --git a/tools/crocodocs/src/crocodocs/frontmatter.py b/tools/crocodocs/src/crocodocs/frontmatter.py new file mode 100644 index 0000000000..6506a05ae8 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/frontmatter.py @@ -0,0 +1,73 @@ +"""Minimal front matter parsing helpers.""" + +from __future__ import annotations + +import re +from dataclasses import dataclass +from typing import Any + + +@dataclass +class FrontMatterDocument: + data: dict[str, Any] + body: str + + +_FRONT_MATTER_RE = re.compile(r"\A---\n(.*?)\n---\n?", re.DOTALL) + + +def _parse_scalar(value: str) -> Any: + """Parse a YAML scalar string into a Python bool, int, None, or plain string.""" + value = value.strip() + if value == "": + return "" + if value.lower() == "true": + return True + if value.lower() == "false": + return False + if value.lower() == "null": + return None + if (value.startswith('"') and value.endswith('"')) or ( + value.startswith("'") and value.endswith("'") + ): + return value[1:-1] + try: + return int(value) + except ValueError: + pass + return value + + +def parse_front_matter(text: str) -> FrontMatterDocument: + """Split a document string into a front matter data dict and the remaining body text. + + Returns a FrontMatterDocument with empty data when no front matter block is present. + """ + match = _FRONT_MATTER_RE.match(text) + if not match: + return FrontMatterDocument(data={}, body=text) + + raw = match.group(1).splitlines() + data: dict[str, Any] = {} + current_list_key: str | None = None + + for line in raw: + if not line.strip(): + continue + if line.startswith(" - ") and current_list_key is not None: + value = _parse_scalar(line[4:]) + data.setdefault(current_list_key, []).append(value) + continue + current_list_key = None + if ":" not in line: + continue + key, value = line.split(":", 1) + key = key.strip() + if value.strip() == "": + data[key] = [] + current_list_key = key + else: + data[key] = _parse_scalar(value) + + body = text[match.end() :] + return FrontMatterDocument(data=data, body=body) diff --git a/tools/crocodocs/src/crocodocs/generate.py b/tools/crocodocs/src/crocodocs/generate.py new file mode 100644 index 0000000000..fb8c370ebf --- /dev/null +++ b/tools/crocodocs/src/crocodocs/generate.py @@ -0,0 +1,342 @@ +"""Steady-state manifest and API generation.""" + +from __future__ import annotations + +import json +import os +import re +import subprocess +import sys +from pathlib import Path +from typing import Any + +from .assets import bulk_copy_assets +from .config import CrocoDocsConfig +from .docs import ( + IMPORT_PARTIAL_RE, + extract_symbol_blocks_from_mdx, + iter_markdown_files, + parse_document, +) +from .partials import write_partials +from .progress import ProgressReporter, Summary +from .sidebars import write_sidebars_js_from_source + + +def _normalize_anchor(name: str) -> str: + """Convert a name to a URL-safe anchor string by stripping/replacing special characters.""" + anchor = re.sub(r"""["']""", "", str(name)) + anchor = re.sub(r"\[([^\]]+)\]", r"-\1", anchor) + anchor = re.sub(r"[^A-Za-z0-9._-]+", "-", anchor) + anchor = re.sub(r"-+", "-", anchor) + return anchor.strip("-") + + +def _root_anchor(symbol: str) -> str: + """Return the anchor ID for the root heading of a symbol's documentation page.""" + return _normalize_anchor(symbol) + + +def _member_anchor(symbol: str, member_name: str) -> str: + """Return the anchor ID for a named member (property, event, or method) of a symbol.""" + return _normalize_anchor(f"{symbol}.{member_name}") + + +def _apply_public_aliases( + entries: dict[str, Any], + aliases: dict[str, str], +) -> dict[str, Any]: + """Return a copy of entries augmented with public-alias copies tagged with public_qualname. + + For each (public_name -> qualname) pair in aliases, a copy of the qualname entry is + inserted under public_name with a 'public_qualname' field added. + """ + aliased = dict(entries) + for public_name, qualname in aliases.items(): + entry = entries.get(qualname) + if entry is None: + continue + copied = dict(entry) + copied["public_qualname"] = public_name + aliased[public_name] = copied + return aliased + + +def _extract_api_data_with_griffe( + config: CrocoDocsConfig, + symbols: list[str], +) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any], dict[str, str]]: + """Run the griffe extraction script in a subprocess and return (classes, functions, aliases, public_aliases). + + The script receives a JSON payload on stdin and writes a JSON result to stdout. + Raises RuntimeError if the subprocess exits with a non-zero code. + """ + script_path = config.project_root / "src" / "crocodocs" / "griffe_extract_script.py" + search_paths = [str(path) for path in config.packages.values()] + payload = { + "packages": sorted({symbol.split(".", 1)[0] for symbol in symbols}), + "search_paths": search_paths, + "extensions": config.extensions, + "symbols": symbols, + "member_filters": { + key: sorted(values) for key, values in config.member_filters.items() + }, + } + env = os.environ.copy() + existing_pythonpath = env.get("PYTHONPATH") + env["PYTHONPATH"] = os.pathsep.join( + [*search_paths, *([existing_pythonpath] if existing_pythonpath else [])] + ) + result = subprocess.run( + [sys.executable, str(script_path)], + input=json.dumps(payload), + text=True, + capture_output=True, + cwd=config.project_root.parent.parent, + env=env, + ) + if result.returncode != 0: + details = ["CrocoDocs Griffe extraction failed."] + if result.stdout.strip(): + details.append(f"stdout:\n{result.stdout.strip()}") + if result.stderr.strip(): + details.append(f"stderr:\n{result.stderr.strip()}") + raise RuntimeError("\n\n".join(details)) + data = json.loads(result.stdout) + return ( + data["classes"], + data["functions"], + data.get("aliases", {}), + data.get("public_aliases", {}), + ) + + +def _should_skip_example_path(root: Path, path: Path) -> bool: + """Return True if path is inside a hidden directory or a build/dist/cache directory.""" + relative_parts = path.relative_to(root).parts + return any( + part.startswith(".") or part in {"__pycache__", "build", "dist"} + for part in relative_parts + ) + + +def _generate_code_examples(examples_root: Path, output_path: Path) -> int: + """Write a JSON file mapping relative example paths to their source text. + + Skips hidden directories and build/dist artifacts. Returns the count of entries written. + """ + mapping: dict[str, str] = {} + if not examples_root.exists(): + output_path.write_text("{}", encoding="utf-8") + return 0 + + for source_path in sorted(examples_root.rglob("*.py")): + if _should_skip_example_path(examples_root, source_path): + continue + relative = source_path.relative_to(examples_root).as_posix() + content = source_path.read_text(encoding="utf-8") + mapping[relative] = content + + output_path.write_text( + json.dumps(mapping, indent=2, sort_keys=True), encoding="utf-8" + ) + return len(mapping) + + +def run_generate( + config: CrocoDocsConfig, + docs_path: Path, + manifest_output: Path, + api_output: Path, + base_url: str, +) -> None: + """Orchestrate the full generate pipeline. + + Steps in order: + 1. Write the Docusaurus sidebars.js from the YAML source. + 2. Scan docs to build the page manifest (symbol blocks + partials). + 3. Write the manifest JSON file. + 4. Generate MDX partial files for CLI docs, permissions, and PyPI index. + 5. Write the code-examples JSON file. + 6. Extract API data (classes, functions, aliases) via Griffe. + 7. Write the api-data JSON file with xref map. + 8. Sync asset files to the static directory. + """ + reporter = ProgressReporter("generate") + summary = Summary("generate") + + reporter.stage("Generating sidebar runtime config") + write_sidebars_js_from_source(config.sidebars_source, config.sidebars_output) + + reporter.stage("Scanning docs for API symbols and partials") + docs = iter_markdown_files(docs_path) + pages: list[dict[str, Any]] = [] + partial_filenames: set[str] = set() + for path in docs: + content = path.read_text(encoding="utf-8") + document = parse_document(content) + blocks = [ + {"kind": b.kind, "symbol": b.symbol, "options": b.options} + for b in extract_symbol_blocks_from_mdx(document.body, document.data) + ] + if blocks: + relative = path.relative_to(docs_path).as_posix() + doc_id = relative.removesuffix(".md").removesuffix(".mdx") + route_path = ( + doc_id.removesuffix("/index") if doc_id.endswith("/index") else doc_id + ) + pages.append({"route": f"{base_url}/{route_path}", "symbol_blocks": blocks}) + partial_filenames.update(IMPORT_PARTIAL_RE.findall(content)) + + reporter.stage("Writing manifest") + manifest_output.parent.mkdir(parents=True, exist_ok=True) + manifest_output.write_text( + json.dumps({"version": "1.0", "pages": pages}, indent=2, sort_keys=True), + encoding="utf-8", + ) + + reporter.stage("Generating MDX partials") + try: + generated_partials = write_partials(config, partial_filenames) + except Exception as exc: # noqa: BLE001 + generated_partials = 0 + summary.warn(f"Could not generate partials: {exc}") + + reporter.stage("Generating code example data") + code_examples_output = config.partials_output_dir / "code-examples.json" + code_example_entries = _generate_code_examples( + config.examples_root, code_examples_output + ) + + reporter.stage("Extracting API data") + missing_roots = [path for path in config.packages.values() if not path.exists()] + for package_root in missing_roots: + summary.warn(f"Configured package root does not exist: {package_root}") + requested_symbols = sorted( + { + block["symbol"] + for page in pages + for block in page["symbol_blocks"] + if isinstance(block.get("symbol"), str) and block["symbol"] + } + ) + classes, functions, aliases, public_aliases = _extract_api_data_with_griffe( + config, requested_symbols + ) + + class_aliases = { + public_name: qualname + for public_name, qualname in public_aliases.items() + if qualname in classes + } + function_aliases = { + public_name: qualname + for public_name, qualname in public_aliases.items() + if qualname in functions + } + + classes = _apply_public_aliases(classes, class_aliases) + functions = _apply_public_aliases(functions, function_aliases) + + # Build reverse map: internal qualname -> public name + reverse_aliases: dict[str, str] = { + qualname: public_name for public_name, qualname in public_aliases.items() + } + + # Normalize bases in all class entries to use public names + for cls_entry in classes.values(): + bases = cls_entry.get("bases") + if not bases: + continue + cls_entry["bases"] = [reverse_aliases.get(b, b) for b in bases] + + xref_map: dict[str, str] = {} + for page in pages: + route = page["route"] + for block in page["symbol_blocks"]: + symbol = block.get("symbol") + if isinstance(symbol, str) and symbol: + use_root_anchor = block.get("options", {}).get("showRootHeading") + xref_map[symbol] = ( + f"{route}#{_root_anchor(symbol)}" if use_root_anchor else route + ) + api_entry = classes.get(symbol) + if api_entry: + for prop in api_entry.get("properties", []): + xref_map[f"{symbol}.{prop['name']}"] = ( + f"{route}#{_member_anchor(symbol, prop['name'])}" + ) + for event in api_entry.get("events", []): + xref_map[f"{symbol}.{event['name']}"] = ( + f"{route}#{_member_anchor(symbol, event['name'])}" + ) + for method in api_entry.get("methods", []): + xref_map[f"{symbol}.{method['name']}"] = ( + f"{route}#{_member_anchor(symbol, method['name'])}" + ) + + # Add public-alias xref entries so short names like flet_ads.BaseAd resolve + for public_name, qualname in class_aliases.items(): + if qualname in xref_map and public_name not in xref_map: + xref_map[public_name] = xref_map[qualname] + # Also alias members: flet_ads.BaseAd.on_open -> flet_ads.base_ad.BaseAd.on_open + prefix = f"{qualname}." + public_prefix = f"{public_name}." + for key, url in list(xref_map.items()): + if key.startswith(prefix): + member_alias = public_prefix + key[len(prefix) :] + if member_alias not in xref_map: + xref_map[member_alias] = url + + reporter.stage("Writing API data") + api_output.parent.mkdir(parents=True, exist_ok=True) + api_output.write_text( + json.dumps( + { + "version": "1.0", + "canonical_map": reverse_aliases, + "classes": classes, + "functions": functions, + "aliases": aliases, + "enums": {}, + "xref_map": xref_map, + }, + indent=2, + sort_keys=True, + ), + encoding="utf-8", + ) + + reporter.stage("Syncing assets") + static_root = docs_path.parent / "static" + synced_assets = 0 + for mapping in config.asset_mappings.values(): + if not mapping.source_path.exists(): + continue + dest = static_root / mapping.static_subpath + synced_assets += bulk_copy_assets( + mapping.source_path, dest, mapping.include_exts + ) + + summary.add("docs scanned", len(docs)) + summary.add("packages loaded", len(config.packages)) + summary.add("symbols serialized", len(classes) + len(functions) + len(aliases)) + summary.add("partials generated", generated_partials) + summary.add("code example entries", code_example_entries) + try: + sidebar_source = config.sidebars_source.relative_to( + config.project_root + ).as_posix() + except ValueError: + sidebar_source = config.sidebars_source.as_posix() + try: + sidebar_output = config.sidebars_output.relative_to( + config.project_root + ).as_posix() + except ValueError: + sidebar_output = config.sidebars_output.as_posix() + summary.add("sidebar source", sidebar_source) + summary.add("sidebar output", sidebar_output) + summary.add("assets copied", synced_assets) + summary.add("xref entries", len(xref_map)) + summary.print() diff --git a/tools/crocodocs/src/crocodocs/griffe_extract_script.py b/tools/crocodocs/src/crocodocs/griffe_extract_script.py new file mode 100644 index 0000000000..f98b70cb87 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/griffe_extract_script.py @@ -0,0 +1,763 @@ +"""Extract API data using Griffe inside the sdk/python environment.""" + +from __future__ import annotations + +import ast +import json +import os +import subprocess +import sys +from functools import lru_cache +from pathlib import Path +from typing import Any + + +SIGNATURE_LINE_LENGTH = 60 +# Skips time consuming tasks (ex: Ruff signature formatting) when set. +FAST_MODE = bool(os.environ.get("FLET_DOCS_FAST")) + + +def _normalize_path(value: str | None) -> str | None: + """Convert a path string to use forward slashes, or return None if value is None.""" + if value is None: + return None + return str(value).replace("\\", "/") + + +MEMBER_FILTERS: dict[str, set[str]] = { + "all": set(), + "properties": set(), + "events": set(), + "methods": set(), +} + + +def _load_member_filters(payload: dict[str, Any]) -> None: + """Populate the global MEMBER_FILTERS dict from the payload's 'member_filters' key.""" + raw = payload.get("member_filters", {}) + for key in MEMBER_FILTERS: + values = raw.get(key, []) + MEMBER_FILTERS[key] = {str(value) for value in values} + + +def _resolve_extensions( + extensions: list[str], + search_paths: list[str], +) -> list[str]: + """Resolve extension names to file paths where possible. + + The known extension 'flet.utils.griffe_deprecations' is looked up in search_paths + and replaced with its absolute file path if found. + """ + resolved: list[str] = [] + for extension in extensions: + if extension == "flet.utils.griffe_deprecations": + file_path = None + for search_path in search_paths: + candidate = ( + Path(search_path) / "flet" / "utils" / "griffe_deprecations.py" + ) + if candidate.exists(): + file_path = candidate + break + if file_path is not None: + resolved.append(str(file_path)) + continue + resolved.append(extension) + return resolved + + +def _is_filtered_member(kind: str, name: str) -> bool: + """Return True if name appears in the global exclusion filter for its kind or for 'all'.""" + return name in MEMBER_FILTERS["all"] or name in MEMBER_FILTERS.get(kind, set()) + + +def _unwrap(obj: Any) -> Any: + """Follow Alias chains to reach the underlying Griffe object. + + Returns None if a cycle is detected or if the alias target cannot be resolved. + """ + target = obj + seen: set[int] = set() + while target.__class__.__name__ == "Alias" and id(target) not in seen: + seen.add(id(target)) + try: + target = target.target + except Exception: + return None + return target + + +def _docstring_value(obj: Any) -> str | None: + """Return the raw docstring text for a Griffe object, or None if absent.""" + docstring = getattr(obj, "docstring", None) + if docstring is None: + return None + return docstring.value or None + + +def _annotation_to_text(value: Any) -> str | None: + """Convert a Griffe annotation object to its string representation, or None.""" + if value is None: + return None + return _modernize_annotation_text(str(value)) + + +def _split_top_level_commas(text: str) -> list[str]: + """Split comma-separated annotation parts while preserving nested expressions.""" + parts: list[str] = [] + start = 0 + depth = 0 + quote: str | None = None + + for index, char in enumerate(text): + previous = text[index - 1] if index > 0 else "" + if quote: + if char == quote and previous != "\\": + quote = None + continue + if char in {"'", '"'}: + quote = char + continue + if char in "([{": + depth += 1 + continue + if char in ")]}": + depth = max(0, depth - 1) + continue + if char == "," and depth == 0: + parts.append(text[start:index].strip()) + start = index + 1 + + tail = text[start:].strip() + if tail: + parts.append(tail) + return parts + + +def _matching_bracket_index(text: str, open_index: int) -> int: + """Return the index of the closing bracket matching text[open_index].""" + pairs = {"[": "]", "(": ")", "{": "}"} + open_char = text[open_index] + close_char = pairs[open_char] + depth = 0 + quote: str | None = None + + for index in range(open_index, len(text)): + char = text[index] + previous = text[index - 1] if index > 0 else "" + if quote: + if char == quote and previous != "\\": + quote = None + continue + if char in {"'", '"'}: + quote = char + continue + if char == open_char: + depth += 1 + continue + if char == close_char: + depth -= 1 + if depth == 0: + return index + return -1 + + +def _modernize_annotation_text(text: str) -> str: + """Render annotations in docs-friendly modern Python syntax.""" + result: list[str] = [] + index = 0 + + while index < len(text): + if text[index].isidentifier() or text[index] == ".": + start = index + while index < len(text) and (text[index].isalnum() or text[index] in "_."): + index += 1 + name = text[start:index] + if index < len(text) and text[index] == "[": + close_index = _matching_bracket_index(text, index) + if close_index != -1: + inner = text[index + 1 : close_index] + inner_parts = [ + _modernize_annotation_text(part) + for part in _split_top_level_commas(inner) + ] + short_name = name.rsplit(".", 1)[-1] + if short_name == "Annotated" and inner_parts: + result.append(inner_parts[0]) + elif short_name == "Optional" and len(inner_parts) == 1: + result.append(f"{inner_parts[0]} | None") + elif short_name == "Union" and inner_parts: + result.append(" | ".join(inner_parts)) + else: + result.append(f"{name}[{', '.join(inner_parts)}]") + index = close_index + 1 + continue + result.append(name) + continue + + result.append(text[index]) + index += 1 + + return "".join(result) + + +def _parameter_lookup(obj: Any) -> dict[str, Any]: + """Return a name-keyed dict of parameter objects for a Griffe function or method.""" + target = _unwrap(obj) + if target is None: + return {} + parameters = getattr(target, "parameters", []) or [] + return {parameter.name: parameter for parameter in parameters} + + +def _docstring_sections(obj: Any) -> list[dict[str, Any]]: + """Parse a Griffe docstring into a list of structured section dicts. + + Each dict has a 'kind' key ('text', 'parameters', 'returns', 'raises', 'admonition') + plus kind-specific fields. Returns an empty list when griffe is unavailable or the + object has no docstring. + """ + try: + from griffe import ( + DocstringSectionAdmonition, + DocstringSectionParameters, + DocstringSectionRaises, + DocstringSectionReturns, + DocstringSectionText, + ) + except Exception: # pragma: no cover + return [] + + docstring = getattr(obj, "docstring", None) + if docstring is None: + return [] + + parameter_lookup = _parameter_lookup(obj) + sections: list[dict[str, Any]] = [] + for section in docstring.parsed: + if isinstance(section, DocstringSectionText): + value = getattr(section, "value", None) + if isinstance(value, str) and value.strip(): + sections.append({"kind": "text", "value": value}) + elif isinstance(section, DocstringSectionParameters): + items = [] + for item in getattr(section, "value", []) or []: + parameter = parameter_lookup.get(getattr(item, "name", "")) + default = getattr(item, "value", None) + if default is None and parameter is not None: + default = getattr(parameter, "default", None) + items.append( + { + "name": getattr(item, "name", "") or "", + "type": _annotation_to_text( + getattr(item, "annotation", None) + or getattr(parameter, "annotation", None) + if parameter + else None + ), + "default": _annotation_to_text(default), + "description": getattr(item, "description", None) or None, + } + ) + if items: + sections.append({"kind": "parameters", "items": items}) + elif isinstance(section, DocstringSectionReturns): + items = [] + for item in getattr(section, "value", []) or []: + items.append( + { + "name": getattr(item, "name", "") or "", + "type": _annotation_to_text(getattr(item, "annotation", None)), + "description": getattr(item, "description", None) or None, + } + ) + if items: + sections.append({"kind": "returns", "items": items}) + elif isinstance(section, DocstringSectionRaises): + items = [] + for item in getattr(section, "value", []) or []: + items.append( + { + "type": _annotation_to_text(getattr(item, "annotation", None)), + "description": getattr(item, "description", None) or None, + } + ) + if items: + sections.append({"kind": "raises", "items": items}) + elif isinstance(section, DocstringSectionAdmonition): + admonition = getattr(section, "value", None) + if admonition is not None: + raw_kind = getattr(admonition, "annotation", "note") or "note" + description = getattr(admonition, "description", "") or "" + title = getattr(section, "title", None) + if not description.strip(): + continue + admonition_map = { + "note": "note", + "notes": "note", + "tip": "tip", + "hint": "tip", + "example": "tip", + "examples": "tip", + "info": "info", + "warning": "warning", + "warn": "warning", + "important": "warning", + "danger": "danger", + "caution": "caution", + } + mapped_kind = admonition_map.get(raw_kind) + if mapped_kind: + entry: dict[str, Any] = { + "kind": "admonition", + "admonition_kind": mapped_kind, + "value": description, + } + if title: + entry["title"] = title + sections.append(entry) + else: + # Not a real admonition — fold back into text + text = f"{title}:\n\n{description}" if title else description + sections.append({"kind": "text", "value": text}) + return sections + + +def _deprecation_value(obj: Any) -> str | None: + """Extract the text of a 'Deprecated' admonition from a docstring, or return None.""" + try: + from griffe import DocstringSectionAdmonition + except Exception: # pragma: no cover + return None + + docstring = getattr(obj, "docstring", None) + if docstring is None: + return None + for section in docstring.parsed: + if ( + isinstance(section, DocstringSectionAdmonition) + and section.title == "Deprecated" + ): + value = getattr(section, "value", None) + text = getattr(value, "contents", None) or getattr( + value, "description", None + ) + if isinstance(text, str) and text.strip(): + return text + return None + + +def _labels(obj: Any) -> list[str]: + """Return sorted label strings (e.g. 'classmethod', 'property') attached to an object.""" + target = _unwrap(obj) + if target is None: + return [] + return sorted(str(label) for label in getattr(target, "labels", set())) + + +def _annotation_text(obj: Any) -> str | None: + """Return the type annotation of a Griffe object as a string, or None.""" + target = _unwrap(obj) + if target is None: + return None + annotation = getattr(target, "annotation", None) + if annotation is None: + return None + return _annotation_to_text(annotation) + + +def _value_text(obj: Any) -> str | None: + """Return the default/assigned value of a Griffe object as a string, or None.""" + target = _unwrap(obj) + if target is None: + return None + value = getattr(target, "value", None) + if value is None: + return None + return str(value) + + +def _bases_text(obj: Any) -> list[str]: + """Return the list of base-class path strings for a Griffe class object.""" + target = _unwrap(obj) + if target is None: + return [] + result = [] + for base in getattr(target, "bases", []): + # Try to get the fully-qualified path via griffe resolution + canonical = getattr(base, "canonical_path", None) + result.append(canonical if canonical else str(base)) + return result + + +def _parameter_text(parameter: Any) -> str: + """Format a single Griffe parameter as 'name: type = default' text, with * or ** prefix when needed.""" + prefix = "" + kind = str(getattr(parameter, "kind", "")) + if "keyword_variadic" in kind or "var_keyword" in kind: + prefix = "**" + elif "variadic" in kind or "var_positional" in kind: + prefix = "*" + + text = prefix + parameter.name + if getattr(parameter, "annotation", None) is not None: + text += f": {_annotation_to_text(parameter.annotation)}" + if getattr(parameter, "default", None) is not None: + text += f" = {parameter.default}" + return text + + +def _parameters_text(parameters: Any, *, strip_implicit_self: bool = False) -> str: + """Format Griffe parameters as comma-separated Python parameter text.""" + rendered_parameters = list(parameters) + if ( + strip_implicit_self + and rendered_parameters + and rendered_parameters[0].name in {"self", "cls"} + ): + rendered_parameters = rendered_parameters[1:] + return ", ".join(_parameter_text(parameter) for parameter in rendered_parameters) + + +def _signature_text(obj: Any) -> str: + """Format the full function/method signature as 'name(param, ...)' text.""" + target = _unwrap(obj) + if target is None: + return obj.name + rendered = _parameters_text(getattr(target, "parameters", [])) + return f"{obj.name}({rendered})" + + +def _normalize_python_statement(code: str) -> tuple[str, bool]: + """Normalize a synthetic Python statement before sending it to Ruff.""" + try: + return ast.unparse(ast.parse(code)).strip(), True + except SyntaxError: + return code.strip(), False + + +@lru_cache(maxsize=2048) +def _format_python_statement(code: str) -> str: + """Format a synthetic Python statement with Ruff, falling back to normalized code.""" + normalized, is_valid_python = _normalize_python_statement(code) + if len(normalized) < SIGNATURE_LINE_LENGTH or not is_valid_python: + return normalized + + if FAST_MODE: + return normalized + + try: + result = subprocess.run( + [ + sys.executable, + "-m", + "ruff", + "format", + "--line-length", + str(SIGNATURE_LINE_LENGTH), + "--stdin-filename", + "signature.py", + "-", + ], + input=f"{normalized}\n", + text=True, + capture_output=True, + timeout=5, + ) + except subprocess.TimeoutExpired: + return normalized + + if result.returncode != 0: + return normalized + return result.stdout.strip() + + +def _formatted_function_signature(obj: Any) -> str: + """Return a Ruff-formatted function/method signature without the leading 'def'.""" + target = _unwrap(obj) + if target is None: + return obj.name + + parameters = _parameters_text( + getattr(target, "parameters", []), strip_implicit_self=True + ) + returns = getattr(target, "returns", None) + return_suffix = f" -> {_annotation_to_text(returns)}" if returns is not None else "" + formatted = _format_python_statement( + f"def {obj.name}({parameters}){return_suffix}: pass" + ) + + if formatted.startswith("def "): + formatted = formatted[4:] + for suffix in (":\n pass", ": pass"): + if formatted.endswith(suffix): + formatted = formatted[: -len(suffix)] + break + return formatted.strip() + + +def _formatted_attribute_signature(obj: Any) -> str | None: + """Return a Ruff-formatted attribute signature, or None when no type is known.""" + annotation = _annotation_text(obj) + if annotation is None: + return None + + default = _value_text(obj) + signature = f"{obj.name}: {annotation}" + if default is not None: + signature += f" = {default}" + return _format_python_statement(signature) + + +def _attribute_entry(obj: Any) -> dict[str, Any]: + """Serialize a Griffe attribute object to a JSON-ready dict.""" + target = _unwrap(obj) + if target is None: + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": None, + "type": None, + "default": None, + "formatted_signature": None, + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "deprecation": _deprecation_value(obj), + "labels": [], + "inherited_from": None, + "lineno": None, + } + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": getattr(target, "path", None), + "type": _annotation_text(obj), + "default": _value_text(obj), + "formatted_signature": _formatted_attribute_signature(obj), + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "deprecation": _deprecation_value(obj), + "labels": _labels(obj), + "inherited_from": None, + "lineno": getattr(target, "lineno", None), + } + + +def _function_entry(obj: Any) -> dict[str, Any]: + """Serialize a Griffe function object to a JSON-ready dict including signature and return type.""" + target = _unwrap(obj) + if target is None: + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": None, + "signature": obj.name, + "formatted_signature": obj.name, + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "parameters": [], + "return_type": None, + "deprecation": _deprecation_value(obj), + "labels": [], + "lineno": None, + } + returns = getattr(target, "returns", None) + return_type = _annotation_to_text(returns) + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": getattr(target, "path", None), + "signature": _signature_text(obj), + "formatted_signature": _formatted_function_signature(obj), + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "parameters": [ + parameter.name for parameter in getattr(target, "parameters", []) + ], + "return_type": return_type, + "deprecation": _deprecation_value(obj), + "labels": _labels(obj), + "lineno": getattr(target, "lineno", None), + } + + +def _class_entry(obj: Any) -> dict[str, Any]: + """Serialize a Griffe class object (with its properties, events, and methods) to a JSON-ready dict.""" + target = _unwrap(obj) + if target is None: + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": None, + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "bases": [], + "deprecation": _deprecation_value(obj), + "labels": [], + "properties": [], + "events": [], + "methods": [], + "lineno": None, + } + properties: list[dict[str, Any]] = [] + events: list[dict[str, Any]] = [] + methods: list[dict[str, Any]] = [] + + members = getattr(obj, "members", None) or getattr(target, "members", {}) + for member in members.values(): + resolved = _unwrap(member) + if resolved is None: + continue + member_type = resolved.__class__.__name__ + if member_type == "Attribute": + item = _attribute_entry(member) + if item["name"].startswith("on_"): + if _is_filtered_member("events", item["name"]): + continue + events.append(item) + elif not item["name"].startswith("_"): + if _is_filtered_member("properties", item["name"]): + continue + properties.append(item) + elif member_type == "Function" and not member.name.startswith("_"): + if _is_filtered_member("methods", member.name): + continue + methods.append(_function_entry(member)) + + properties.sort(key=lambda item: item["name"].casefold()) + events.sort(key=lambda item: item["name"].casefold()) + methods.sort(key=lambda item: item["name"].casefold()) + + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": getattr(target, "path", None), + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "bases": _bases_text(obj), + "deprecation": _deprecation_value(obj), + "labels": _labels(obj), + "properties": properties, + "events": events, + "methods": methods, + "lineno": getattr(target, "lineno", None), + } + + +def _alias_entry(obj: Any) -> dict[str, Any]: + """Serialize a Griffe alias object to a JSON-ready dict with target kind and path info.""" + target = _unwrap(obj) + target_kind = target.__class__.__name__ if target is not None else None + value = _value_text(obj) + if value is not None: + value = _modernize_annotation_text(value) + return { + "name": obj.name, + "qualname": getattr(obj, "path", None), + "canonical_path": getattr(target, "path", None) if target else None, + "docstring": _docstring_value(obj), + "docstring_sections": _docstring_sections(obj), + "value": value, + "target_kind": target_kind, + "deprecation": _deprecation_value(obj), + "labels": _labels(obj), + "lineno": getattr(target, "lineno", None) if target else None, + } + + +def main() -> int: + """Read a JSON payload from stdin, extract API data via Griffe, and write JSON to stdout. + + The payload must contain 'packages', 'search_paths', 'extensions', 'symbols', and + 'member_filters' keys. The output is a JSON object with 'classes', 'functions', + 'aliases', and 'public_aliases' keys. + """ + payload = json.loads(sys.stdin.read()) + _load_member_filters(payload) + + from griffe import GriffeLoader, load_extensions + + search_paths = sorted({_normalize_path(path) for path in payload["search_paths"]}) + extensions = _resolve_extensions(payload["extensions"], search_paths) + loader = GriffeLoader( + search_paths=search_paths, + extensions=load_extensions(*extensions), + docstring_parser="google", + ) + + classes: dict[str, Any] = {} + functions: dict[str, Any] = {} + aliases: dict[str, Any] = {} + public_aliases: dict[str, str] = {} + + # Walk all modules recursively to discover every path a symbol is exported as + canonical_to_paths: dict[str, list[str]] = {} + + def _walk_module(mod: Any) -> None: + """Recursively walk a Griffe module and populate canonical_to_paths with every export path.""" + for member in mod.members.values(): + # Recurse into sub-modules first + member_kind = member.__class__.__name__ + if member_kind == "Module": + _walk_module(member) + continue + resolved = _unwrap(member) + if resolved is None: + continue + kind = resolved.__class__.__name__ + if kind not in {"Class", "Function"}: + continue + canonical = getattr(resolved, "path", "") + alias_path = getattr(member, "path", "") + if canonical and alias_path: + canonical_to_paths.setdefault(canonical, []).append(alias_path) + + for package_name in payload["packages"]: + module = loader.load(package_name) + _walk_module(module) + + # Pick the shortest public path for each canonical symbol + for canonical, paths in canonical_to_paths.items(): + shortest = min(paths, key=len) + if shortest != canonical: + public_aliases[shortest] = canonical + + modules_collection = loader.modules_collection + for symbol in payload["symbols"]: + try: + obj = modules_collection.get_member(symbol) + except Exception: + continue + obj_kind = obj.__class__.__name__ + resolved = _unwrap(obj) + if resolved is None: + continue + kind = resolved.__class__.__name__ + if obj_kind == "Alias": + aliases[symbol] = _alias_entry(obj) + if kind == "Class": + classes[symbol] = _class_entry(obj) + elif kind == "Function": + functions[symbol] = _function_entry(obj) + elif kind == "Class": + classes[symbol] = _class_entry(obj) + elif kind == "Function": + functions[symbol] = _function_entry(obj) + + sys.stdout.write( + json.dumps( + { + "aliases": aliases, + "classes": classes, + "functions": functions, + "public_aliases": public_aliases, + }, + sort_keys=True, + ) + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/crocodocs/src/crocodocs/partials.py b/tools/crocodocs/src/crocodocs/partials.py new file mode 100644 index 0000000000..75cd2fbfb0 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/partials.py @@ -0,0 +1,254 @@ +"""Generated partial handling.""" + +from __future__ import annotations + +import json +import os +import re +import subprocess +from pathlib import Path + +from .config import CrocoDocsConfig + +LOCAL_MARKDOWN_LINK_RE = re.compile( + r"(?P\]\()(?P(?![a-z][a-z0-9+.-]*:|/|#)[^)]+?\.md)(?P#[^)]+)?(?P\))", + re.IGNORECASE, +) +CLI_H3_TICK_RE = re.compile(r"^(### )`([^`]+)`$", re.MULTILINE) +ANGLE_TAG_RE = re.compile(r"<([a-z][a-z0-9_-]*)>", re.IGNORECASE) +ESCAPED_PLACEHOLDER_RE = re.compile(r"<([^>\n]+?)>") + + +def _normalize_local_markdown_links(content: str) -> str: + """Rewrite relative .md links to strip the .md extension, collapsing 'index.md' to '.'.""" + + def replace(match: re.Match[str]) -> str: + path = match.group("target") + anchor = match.group("anchor") or "" + if path == "index.md": + normalized = "." + elif path.endswith("/index.md"): + normalized = path.removesuffix("/index.md") + else: + normalized = path.removesuffix(".md") + return f"{match.group('prefix')}{normalized}{anchor}{match.group('suffix')}" + + return LOCAL_MARKDOWN_LINK_RE.sub(replace, content) + + +def _escape_mdx_text_outside_code(content: str) -> str: + """Escape bare HTML-like angle-bracket tags to <tag> in non-code regions of MDX content. + + Leaves fenced code blocks and inline backtick spans untouched. + """ + lines = content.splitlines() + normalized: list[str] = [] + in_fence = False + + for line in lines: + stripped = line.strip() + if stripped.startswith("```"): + in_fence = not in_fence + normalized.append(line) + continue + + if in_fence: + normalized.append(line) + continue + + parts = line.split("`") + for index in range(0, len(parts), 2): + parts[index] = ANGLE_TAG_RE.sub(r"<\1>", parts[index]) + normalized.append("`".join(parts)) + + return "\n".join(normalized) + ("\n" if content.endswith("\n") else "") + + +def _normalize_cli_partial_markdown(content: str) -> str: + """Apply CLI-partial normalizations: strip backticks from H3 headings, escape angle brackets, and convert escaped placeholders back to inline code.""" + content = CLI_H3_TICK_RE.sub(r"\1\2", content) + content = _escape_mdx_text_outside_code(content) + return ESCAPED_PLACEHOLDER_RE.sub(r"`<\1>`", content) + + +# --------------------------------------------------------------------------- +# Flet-CLI-dependent partials (batched subprocess) +# --------------------------------------------------------------------------- + +_FLET_CLI_SCRIPT_DIR = Path(__file__).parent / "scripts" + + +def _run_flet_cli_partials( + config: CrocoDocsConfig, requests: dict[str, dict] +) -> dict[str, str]: + """Run a single subprocess that generates all flet-cli-dependent partials. + + *requests* maps partial keys to their parameters. Returns a dict + mapping the same keys to rendered Markdown strings. + """ + cli_script = _FLET_CLI_SCRIPT_DIR / "cli_to_md.py" + permissions_script = _FLET_CLI_SCRIPT_DIR / "cross_platform_permissions.py" + script = f""" +import importlib.util, json, sys + +def _load(name, path): + spec = importlib.util.spec_from_file_location(name, path) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + +cli_mod = _load("cli_to_md", {str(cli_script)!r}) +perm_mod = _load("cross_platform_permissions", {str(permissions_script)!r}) + +requests = json.loads({json.dumps(requests)!r}) +results = {{}} +for key, params in requests.items(): + if params.get("type") == "cli": + results[key] = cli_mod.render_flet_cli_as_markdown( + command=params["command"], subcommands_only=True + ) + elif params.get("type") == "permissions": + results[key] = perm_mod.cross_platform_permissions_list() +print(json.dumps(results)) +""" + repo_root = config.project_root.parent.parent + env = {k: v for k, v in os.environ.items() if k != "VIRTUAL_ENV"} + result = subprocess.run( + [ + "uv", + "--directory", + str(repo_root / "sdk/python"), + "run", + "python", + "-c", + script, + ], + check=True, + capture_output=True, + text=True, + cwd=repo_root, + env=env, + ) + stdout = result.stdout + # Strip non-JSON lines (e.g. flet-cli "Error getting Git version" warnings) + json_start = stdout.find("{") + if json_start > 0: + stdout = stdout[json_start:] + try: + return json.loads(stdout) + except json.JSONDecodeError as exc: + raise RuntimeError( + f"JSON parse failed: {exc}\nstdout: {result.stdout[:500]}\nstderr: {result.stderr[:500]}" + ) from exc + + +# --------------------------------------------------------------------------- +# PyPI index partial (in-process, no flet dependency) +# --------------------------------------------------------------------------- + + +def _render_pypi_partial() -> str: + """Fetch and render the PyPI package index, filtering non-flet packages and converting admonition syntax to MDX format.""" + from .pypi_index import render_pypi_index + + rendered = render_pypi_index( + base_url="https://pypi.flet.dev/", + timeout_s=20.0, + workers=12, + output_format="md", + strict=False, + ) + lines = rendered.splitlines() + if len(lines) < 2: + return rendered + + filtered_lines = lines[:2] + row_pattern = re.compile(r"^\|\s*\[`([^`]+)`\]\([^)]+\)(?:\s*\([^)]*\))?\s*\|") + for line in lines[2:]: + match = row_pattern.match(line) + if not match: + filtered_lines.append(line) + continue + package_name = match.group(1) + if not package_name.startswith("flet") or package_name.startswith("flet-lib"): + filtered_lines.append(line) + normalized_lines: list[str] = [] + index = 0 + while index < len(filtered_lines): + if filtered_lines[index].strip() != "!!! warning": + normalized_lines.append(filtered_lines[index]) + index += 1 + continue + + normalized_lines.append(":::warning") + index += 1 + while index < len(filtered_lines): + line = filtered_lines[index] + if line.startswith(" "): + line = line[4:] + elif line.strip(): + break + + if line.startswith("- ") and ": " in line: + package_name, error_text = line[2:].split(": ", 1) + escaped_error = error_text.replace("`", "\\`") + line = f"- {package_name}: `{escaped_error}`" + normalized_lines.append(line) + index += 1 + normalized_lines.append(":::") + + return "\n".join(normalized_lines) + ("\n" if rendered.endswith("\n") else "") + + +# --------------------------------------------------------------------------- +# Public API +# --------------------------------------------------------------------------- + + +def render_partials(config: CrocoDocsConfig, filenames: set[str]) -> dict[str, str]: + """Render all requested partials, batching subprocess calls.""" + results: dict[str, str] = {} + + # Classify partials + flet_cli_requests: dict[str, dict] = {} + pypi_filenames: list[str] = [] + for filename in filenames: + if filename == "pypi-index.mdx": + pypi_filenames.append(filename) + elif filename == "cross-platform-permissions.mdx": + flet_cli_requests[filename] = {"type": "permissions"} + elif filename.startswith("cli-") and filename.endswith(".mdx"): + command = ( + filename.removesuffix(".mdx").removeprefix("cli-").replace("-", " ") + ) + if command == "root": + command = "" + flet_cli_requests[filename] = {"type": "cli", "command": command} + + # Batch flet-cli subprocess + if flet_cli_requests: + rendered = _run_flet_cli_partials(config, flet_cli_requests) + for filename, content in rendered.items(): + if filename.startswith("cli-"): + results[filename] = _normalize_cli_partial_markdown(content) + else: + results[filename] = content + + # PyPI index (in-process) + for filename in pypi_filenames: + results[filename] = _render_pypi_partial() + + return results + + +def write_partials(config: CrocoDocsConfig, filenames: set[str]) -> int: + """Render and write all requested partials. Returns count written.""" + rendered = render_partials(config, filenames) + count = 0 + for filename, content in rendered.items(): + target = config.partials_output_dir / filename + target.parent.mkdir(parents=True, exist_ok=True) + normalized = _normalize_local_markdown_links(content) + target.write_text(normalized, encoding="utf-8") + count += 1 + return count diff --git a/tools/crocodocs/src/crocodocs/progress.py b/tools/crocodocs/src/crocodocs/progress.py new file mode 100644 index 0000000000..ae06731855 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/progress.py @@ -0,0 +1,49 @@ +"""Small terminal UX helpers for CrocoDocs commands.""" + +from __future__ import annotations + +from dataclasses import dataclass, field + + +@dataclass +class Summary: + command: str + rows: list[tuple[str, str]] = field(default_factory=list) + warnings: list[str] = field(default_factory=list) + + def add(self, label: str, value: object) -> None: + """Append a label/value row to the summary table.""" + self.rows.append((label, str(value))) + + def warn(self, message: str) -> None: + """Append a warning message to the summary.""" + self.warnings.append(message) + + def print(self) -> None: + """Print the command name, all rows, and any warnings to stdout.""" + print() + print(f"Summary: {self.command}") + for label, value in self.rows: + print(f" {label}: {value}") + if self.warnings: + print(" warnings:") + for warning in self.warnings: + print(f" - {warning}") + + +class ProgressReporter: + """Simple stage-based progress logging.""" + + def __init__(self, command: str) -> None: + """Initialize the reporter with the name of the command being tracked.""" + self.command = command + self._last_stage: str | None = None + + def stage(self, name: str) -> None: + """Log the start of a named processing stage to stdout.""" + self._last_stage = name + print(f"[{self.command}] {name}") + + def info(self, message: str) -> None: + """Log an informational message to stdout.""" + print(f"[{self.command}] {message}") diff --git a/tools/crocodocs/src/crocodocs/pypi_index.py b/tools/crocodocs/src/crocodocs/pypi_index.py new file mode 100644 index 0000000000..ed87b86cc6 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/pypi_index.py @@ -0,0 +1,601 @@ +""" +Helpers for the MkDocs macros plugin to render a package index from a PEP 503 "simple" +repository (used for https://pypi.flet.dev). + +This module runs during docs builds, so it is intentionally dependency-light and aims to +be resilient to minor HTML/layout changes. + +What it reads (PEP 503 "simple"): +- A root HTML page listing project names as `project` +- Per-project HTML pages listing distribution files as `filename.whl` + +What it outputs: +- `render_pypi_index(..., output_format="md")` -> Markdown table, + where each package name links to its per-project page in the same index. +- `output_format="json"` -> JSON object with `packages`, `platforms`, `errors`. +- `output_format="text"` -> plain-text listing. + +How parsing works: +- `html.parser` collects anchor text/hrefs (no external HTML dependency). +- `packaging` parses versions and wheel tags from filenames (avoids fragile regexes). + +Platform detection: +If wheel tags indicate only Android or only iOS, the package row is annotated as +`(Android only)` / `(iOS only)`. + +Failure behavior: +With `strict=False` (default), network/parsing failures render warnings (or populate +`errors` in JSON) rather than crashing the docs build. +""" + +import concurrent.futures +import json +import re +import urllib.parse +import urllib.request +from collections.abc import Iterable +from functools import lru_cache +from html.parser import HTMLParser +from typing import Optional + +try: + from packaging.utils import parse_sdist_filename, parse_wheel_filename + from packaging.version import InvalidVersion, Version +except Exception: + parse_sdist_filename = None + parse_wheel_filename = None + InvalidVersion = Exception + Version = None + + +DEFAULT_PYPI_FLET_DEV_BASE_URL = "https://pypi.flet.dev/" +DEFAULT_USER_AGENT = "flet-docs-pypi-index-macro/0.1 (+https://flet.dev)" + +# These projects tend to have lots of releases; +# for docs we link out instead of listing every version. +_ALL_VERSIONS_PROJECTS = { + "flet", + "flet-cli", + "flet-desktop", + "flet-web", +} + +ProjectIndexEntry = tuple[tuple[str, ...], tuple[str, ...]] # (versions, platforms) +ProjectIndex = dict[str, ProjectIndexEntry] +IndexFetchResult = tuple[str, ProjectIndex, tuple[tuple[str, str], ...]] + + +class _AnchorCollector(HTMLParser): + """Collect `` tags and their text/href from an HTML page.""" + + def __init__(self) -> None: + super().__init__(convert_charrefs=True) + self._current: Optional[dict[str, object]] = None + self.anchors: list[dict[str, object]] = [] + + def handle_starttag(self, tag: str, attrs: list[tuple[str, Optional[str]]]) -> None: + if tag != "a": + return + attributes = dict(attrs) + self._current = { + "href": attributes.get("href") or "", + "text": "", + "attrs": attributes, + } + + def handle_data(self, data: str) -> None: + if self._current is None: + return + self._current["text"] = f"{self._current['text']}{data}" + + def handle_endtag(self, tag: str) -> None: + if tag != "a" or self._current is None: + return + self.anchors.append(self._current) + self._current = None + + +def _normalize_base_url(base_url: str) -> str: + """Normalize and validate a base URL (ensure http(s) and trailing slash).""" + + base_url = base_url.strip() + if not base_url: + raise ValueError("base_url must not be empty") + if not base_url.startswith(("http://", "https://")): + raise ValueError("base_url must be an http(s) URL") + if not base_url.endswith("/"): + base_url += "/" + parts = urllib.parse.urlsplit(base_url) + path = parts.path or "/" + if not path.endswith("/"): + path += "/" + return urllib.parse.urlunsplit((parts.scheme, parts.netloc, path, "", "")) + + +def _candidate_simple_root_urls(base_url: str) -> list[str]: + """Return candidate root URLs for a "simple" index. + + Some deployments expose the simple index at `/simple/`, + others at `/` via rewrite rules. + """ + + base_url = _normalize_base_url(base_url) + parts = urllib.parse.urlsplit(base_url) + path = parts.path or "/" + normalized_path = path.rstrip("/") + + # Try the user-provided URL first, then a likely alternative. + candidates = [base_url] + if normalized_path == "/simple": + candidates.append( + urllib.parse.urlunsplit((parts.scheme, parts.netloc, "/", "", "")) + ) + elif normalized_path in ("", "/"): + candidates.append( + urllib.parse.urlunsplit((parts.scheme, parts.netloc, "/simple/", "", "")) + ) + + out: list[str] = [] + seen: set[str] = set() + for url in candidates: + if url in seen: + continue + seen.add(url) + out.append(url) + return out + + +def _fetch_text(url: str, *, timeout_s: float, user_agent: str) -> str: + """Fetch a URL and decode it as text using response headers (fallback to UTF-8).""" + + # Use urllib to avoid bringing in an HTTP client dependency for docs builds. + request = urllib.request.Request(url, headers={"User-Agent": user_agent}) + with urllib.request.urlopen(request, timeout=timeout_s) as response: + charset = response.headers.get_content_charset() or "utf-8" + return response.read().decode(charset, errors="replace") + + +def _parse_anchor_text_and_href(html: str) -> list[tuple[str, str]]: + """Parse all anchors and return `(anchor_text, href)` tuples.""" + + parser = _AnchorCollector() + parser.feed(html) + out: list[tuple[str, str]] = [] + for a in parser.anchors: + text = str(a.get("text") or "").strip() + href = str(a.get("href") or "").strip() + if not text and not href: + continue + out.append((text, href)) + return out + + +def _list_projects(simple_index_html: str) -> list[str]: + """Parse the root index HTML and return sorted project names.""" + + projects: set[str] = set() + for text, href in _parse_anchor_text_and_href(simple_index_html): + candidate = (text or href).strip().strip("/").strip() + if candidate: + projects.add(candidate) + # Sort case-insensitively + return sorted(projects, key=str.casefold) + + +def _filename_from_href_or_text(text: str, href: str) -> str: + """ + Return a dist filename, preferring anchor text (as produced by the index generator). + """ + + if text: + return text + parsed = urllib.parse.urlsplit(href) + return urllib.parse.unquote(parsed.path.rsplit("/", 1)[-1]) + + +def _version_from_filename(filename: str) -> Optional[str]: + """Extract a version from a wheel/sdist filename, or return None if unknown.""" + + filename = filename.strip() + if not filename: + return None + + # Prefer wheel parsing when possible (more reliable than heuristics). + if filename.endswith(".whl") and parse_wheel_filename is not None: + try: + _, version, _, _ = parse_wheel_filename(filename) + except Exception: + return None + return str(version) + + if parse_sdist_filename is not None: + try: + _, version = parse_sdist_filename(filename) + except Exception: + return None + return str(version) + + return None + + +def _platforms_from_wheel_tags(tags) -> set[str]: + """Infer whether a wheel is Android/iOS-specific from its platform tags.""" + + platforms: set[str] = set() + for tag in tags: + platform_tag = getattr(tag, "platform", "") + if not platform_tag: + continue + # `any` means a universal wheel; treat it as available on both platforms. + if platform_tag == "any": + platforms.update({"android", "ios"}) + continue + platform_lower = platform_tag.lower() + if "android" in platform_lower: + platforms.add("android") + if "ios" in platform_lower or "iphone" in platform_lower: + platforms.add("ios") + return platforms + + +def _platform_suffix(project_platforms: set[str]) -> str: + """Human-friendly platform marker for a per-project availability set.""" + + if project_platforms == {"android"}: + return " (Android only)" + if project_platforms == {"ios"}: + return " (iOS only)" + return "" + + +def _normalize_project_name(name: str) -> str: + """Normalize project names similar to PEP 503 / wheel index generation.""" + + return re.sub(r"[-_.]+", "-", name).casefold() + + +def _sorted_versions(versions: Iterable[str]) -> list[str]: + """ + Return unique versions sorted newest-first using PEP 440 semantics when possible. + """ + + versions_set = {v.strip() for v in versions if v.strip()} + if not versions_set: + return [] + + if Version is None: + return sorted(versions_set) + + valid: list[tuple[Version, str]] = [] + invalid: list[str] = [] + for v in versions_set: + try: + valid.append((Version(v), v)) + except InvalidVersion: + invalid.append(v) + + valid.sort(key=lambda t: t[0], reverse=True) + invalid.sort() + return [v for _, v in valid] + invalid + + +def _format_md( + packages: dict[str, list[str]], + platforms: dict[str, set[str]], + resolved_base_url: str, + *, + all_versions_projects: set[str], +) -> str: + """ + Render a Markdown table of packages and versions, with optional platform markers. + """ + + lines = ["| Package | Versions |", "|---|---|"] + for name, versions in packages.items(): + # Link each package name to its per-project page in the same index. + project_url = urllib.parse.urljoin( + resolved_base_url, f"{urllib.parse.quote(name)}/" + ) + project_platforms = platforms.get(name) or set() + platform_suffix = _platform_suffix(project_platforms) + if _normalize_project_name(name) in all_versions_projects: + versions_cell = "All versions" + else: + versions_cell = ", ".join(versions) if versions else "" + package_cell = f"[`{name}`]({project_url}){platform_suffix}" + lines.append(f"| {package_cell} | {versions_cell} |") + return "\n".join(lines) + "\n" + + +@lru_cache(maxsize=8) +def _fetch_packages_and_versions_cached( + base_url: str, + timeout_s: float, + workers: int, + limit_projects: Optional[int], + user_agent: str, +) -> IndexFetchResult: + """Fetch and parse the index into `(resolved_base_url, project_index, errors)`. + + - `resolved_base_url` is the candidate URL that + actually served a non-empty project list. + - `project_index` maps `project -> (versions, platforms)`. + - `errors` contains per-project fetch + failures (kept non-fatal unless `strict=True`). + """ + + # Cache within a single MkDocs run so multiple pages can reuse the same fetch. + last_error: Optional[Exception] = None + resolved_base_url: Optional[str] = None + projects: list[str] = [] + + for candidate in _candidate_simple_root_urls(base_url): + try: + candidate_html = _fetch_text( + candidate, timeout_s=timeout_s, user_agent=user_agent + ) + except Exception as e: + last_error = e + continue + + # Accept the first candidate that yields a non-empty project list. + candidate_projects = _list_projects(candidate_html) + if not candidate_projects: + last_error = ValueError(f"No projects found at {candidate}") + continue + + resolved_base_url = candidate + projects = candidate_projects + break + + if resolved_base_url is None: + if last_error is not None: + raise last_error + raise ValueError("Failed to resolve a simple index base URL") + + if limit_projects is not None: + projects = projects[: max(0, limit_projects)] + + results: ProjectIndex = {} + errors: list[tuple[str, str]] = [] + + def fetch_one(project: str) -> tuple[str, tuple[str, ...], tuple[str, ...]]: + # Each project has its own simple index page with links to distribution files. + project_url = urllib.parse.urljoin(resolved_base_url, f"{project}/") + html = _fetch_text(project_url, timeout_s=timeout_s, user_agent=user_agent) + versions: set[str] = set() + project_platforms: set[str] = set() + for text, href in _parse_anchor_text_and_href(html): + filename = _filename_from_href_or_text(text, href) + if filename.endswith(".whl") and parse_wheel_filename is not None: + try: + _, version, _, tags = parse_wheel_filename(filename) + except Exception: + continue + versions.add(str(version)) + project_platforms.update(_platforms_from_wheel_tags(tags)) + continue + version = _version_from_filename(filename) + if version is not None: + versions.add(version) + return ( + project, + tuple(_sorted_versions(versions)), + tuple(sorted(project_platforms)), + ) + + # Fetch per-project pages concurrently to keep docs builds snappy. + with concurrent.futures.ThreadPoolExecutor(max_workers=max(1, workers)) as executor: + future_to_project = {executor.submit(fetch_one, p): p for p in projects} + for future in concurrent.futures.as_completed(future_to_project): + project = future_to_project[future] + try: + project, versions, project_platforms = future.result() + except Exception as e: + # Collect errors but don't fail the whole page unless in strict mode + errors.append((project, f"{type(e).__name__}: {e}")) + continue + results[project] = (versions, project_platforms) + + # Sort case-insensitively + results_sorted = dict(sorted(results.items(), key=lambda item: item[0].casefold())) + return resolved_base_url, results_sorted, tuple(errors) + + +def _merge_duplicate_projects(packages_raw: ProjectIndex) -> ProjectIndex: + """Collapse duplicates such as `Brotli` vs `brotli` by normalized project name. + + The index can contain multiple entries for the same logical project due to casing or + `-`/`_`/`.` normalization differences. We merge those entries by: + - grouping by normalized name, and + - unioning versions and platforms. + + The display name is chosen from the grouped variants (preferring "nicer" casing). + """ + + def uppercase_weight(s: str) -> int: + return sum(1 for ch in s if ch.isupper()) + + grouped: dict[str, list[tuple[str, tuple[str, ...], tuple[str, ...]]]] = {} + for name, (versions, plats) in packages_raw.items(): + grouped.setdefault(_normalize_project_name(name), []).append( + (name, versions, plats) + ) + + merged: ProjectIndex = {} + for _, items in grouped.items(): + if len(items) == 1: + name, versions, plats = items[0] + merged[name] = (versions, plats) + continue + + # Prefer the variant with more uppercase letters (e.g. "PyYAML" over "pyyaml"). + best_name = max(items, key=lambda t: (uppercase_weight(t[0]), t[0].casefold()))[ + 0 + ] + + versions_union: set[str] = set() + platforms_union: set[str] = set() + for _, versions, plats in items: + versions_union.update(versions) + platforms_union.update(plats) + + merged[best_name] = ( + tuple(_sorted_versions(versions_union)), + tuple(sorted(platforms_union)), + ) + + return dict(sorted(merged.items(), key=lambda item: item[0].casefold())) + + +def render_pypi_index( + base_url: str = DEFAULT_PYPI_FLET_DEV_BASE_URL, + *, + timeout_s: float = 20.0, + workers: int = 12, + limit_projects: Optional[int] = None, + max_versions: Optional[int] = None, + user_agent: str = DEFAULT_USER_AGENT, + output_format: str = "md", + strict: bool = False, +) -> str: + """Render a packages+versions listing from a PEP-503 'simple' index. + + Platform detection: + If a project has wheels whose platform tags include Android or iOS, the rendered + table marks that project as "(Android only)" / "(iOS only)" when appropriate. + + Args: + base_url: Index base URL. This can be either `/` or `/simple/`. + timeout_s: Per-request timeout. + workers: Parallel fetches for per-project pages. + limit_projects: Optional cap on number of projects (useful for local testing). + max_versions: Optional cap on number of versions per project (latest first). + user_agent: HTTP User-Agent header. + output_format: One of: "md", "json", "text". + strict: If True, raise on fetch failures; + else render partial results + a warning block. + """ + try: + resolved_base_url, packages_raw, errors = _fetch_packages_and_versions_cached( + base_url=base_url, + timeout_s=timeout_s, + workers=workers, + limit_projects=limit_projects, + user_agent=user_agent, + ) + except Exception as e: + if strict: + raise + message = f"{type(e).__name__}: {e}" + + if output_format == "json": + rendered = json.dumps( + { + "packages": {}, + "platforms": {}, + "errors": [{"project": "__index__", "error": message}], + }, + indent=2, + sort_keys=True, + ) + return rendered + "\n" + if output_format == "text": + return f"ERROR: {message}\n" + return "\n".join( + [ + "!!! warning", + f" Failed to fetch package index from `{base_url}`.", + f" {message}", + "", + ] + ) + + packages_raw = _merge_duplicate_projects(packages_raw) + + all_versions_projects = { + _normalize_project_name(name) for name in _ALL_VERSIONS_PROJECTS + } + + packages: dict[str, list[str]] = {} + platforms: dict[str, set[str]] = {} + for name, (versions, project_platforms) in packages_raw.items(): + packages[name] = list(versions) + platforms[name] = set(project_platforms) + + # Output is embedded directly into Markdown pages, so keep formats simple and stable + if output_format == "json": + rendered = json.dumps( + { + "packages": packages, + "platforms": {name: sorted(vals) for name, vals in platforms.items()}, + "errors": [{"project": name, "error": err} for name, err in errors], + }, + indent=2, + sort_keys=True, + ) + return rendered + "\n" + + if max_versions is not None: + # Keep the table compact (latest-first) when a limit is requested. + cap = max(0, max_versions) + packages = {name: versions[:cap] for name, versions in packages.items()} + + if output_format == "text": + + def _versions_text(name: str, versions: list[str]) -> str: + if _normalize_project_name(name) in all_versions_projects: + return "All versions" + return ", ".join(versions) if versions else "(no versions)" + + rendered = "\n".join( + f"{name}{_platform_suffix(platforms.get(name) or set())}: {_versions_text(name, versions)}" # noqa: E501 + for name, versions in packages.items() + ) + rendered += "\n" + if errors: + rendered += f"\nWarnings: {len(errors)} project(s) failed:\n" + rendered += ( + "\n".join(f"- {name}: {err}" for name, err in errors[:10]) + "\n" + ) + if len(errors) > 10: + rendered += f"... and {len(errors) - 10} more\n" + return rendered + + rendered = _format_md( + packages, + platforms, + resolved_base_url, + all_versions_projects=all_versions_projects, + ) + if errors: + message = ( + f"Failed to fetch {len(errors)} project page(s) from `{resolved_base_url}`" + ) + if strict: + raise RuntimeError(message) + details = "\n".join(f" - `{name}`: {err}" for name, err in errors[:10]) + if len(errors) > 10: + details += f"\n - ... and {len(errors) - 10} more" + rendered += "\n".join( + [ + "", + "!!! warning", + f" {message}.", + " ", + details, + "", + ] + ) + + return rendered + + +if __name__ == "__main__": + print( + render_pypi_index( + DEFAULT_PYPI_FLET_DEV_BASE_URL, + limit_projects=25, + max_versions=5, + ) + ) diff --git a/tools/crocodocs/src/crocodocs/scripts/__init__.py b/tools/crocodocs/src/crocodocs/scripts/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/crocodocs/src/crocodocs/scripts/cli_to_md.py b/tools/crocodocs/src/crocodocs/scripts/cli_to_md.py new file mode 100644 index 0000000000..819bdf2d28 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/scripts/cli_to_md.py @@ -0,0 +1,395 @@ +import argparse +import re +import textwrap +from typing import Optional + +from flet_cli.cli import get_parser + + +def render_flet_cli_as_markdown( + command: str = "", + subcommands_only: bool = True, +) -> str: + """Return Markdown for a single argparse command/subcommand (for MkDocs pages). + + Output structure: + 1) Plain description paragraph (dedented, capitalized, period-added) + 2) "Usage" section (always starts with "flet") + 3) "Positional arguments" as titled entries (required-first) + - Shows **Default:** when present + - Else shows **Required:** true/false + - Shows **Possible values:** a, b, c (inline) when choices exist + - Shows **Value:** only when it adds information (type/nargs) beyond DEST + 4) "Options" as titled entries (Style 1) + - Title is the canonical flag (prefer long; else short) + - Shows **Default:** when present + - Shows **Required:** true only if explicitly required + - Shows **Possible values:** inline when choices exist + - Shows **Aliases:** other flags, excluding the title flag + 5) "Subcommands" list (names with first-line description) + + Args: + command: Space-separated subcommand chain (e.g., "", "create", "doctor"). + subcommands_only: If True and the command has subcommands, list them briefly. + + Returns: + Markdown string for the selected command/subcommand. + """ + + # ---------------- helpers ---------------- + def _is_suppress(v: object) -> bool: + """True if argparse 'suppress' sentinel.""" + return v is argparse.SUPPRESS or v == "==SUPPRESS==" + + def _takes_value(a: argparse.Action) -> bool: + """True if this action consumes a value (not boolean/count/help/version).""" + return not isinstance( + a, + ( + argparse._StoreTrueAction, + argparse._StoreFalseAction, + argparse._CountAction, + argparse._HelpAction, + argparse._VersionAction, + ), + ) + + def _all_flags(a: argparse.Action) -> list[str]: + """All switches for an option, short first then long.""" + shorts = [ + s for s in a.option_strings if s.startswith("-") and not s.startswith("--") + ] + longs = [s for s in a.option_strings if s.startswith("--")] + return shorts + longs if (shorts or longs) else list(a.option_strings) + + def _canonical_heading_flag(a: argparse.Action) -> str: + """ + Canonical flag for the option heading (prefer long; else short; else dest). + """ + longs = [s for s in a.option_strings if s.startswith("--")] + if longs: + return longs[0] + shorts = [ + s for s in a.option_strings if s.startswith("-") and not s.startswith("--") + ] + if shorts: + return shorts[0] + return a.option_strings[0] if a.option_strings else a.dest + + def _clean(s: Optional[str]) -> Optional[str]: + """Dedent and trim leading/trailing whitespace.""" + return textwrap.dedent(s).strip() if s else s + + def _cap_first(s: Optional[str]) -> Optional[str]: + """Capitalize first letter and ensure trailing period; do not change grammar.""" + if not s: + return s + t = s.strip() + if not t: + return t + t = t[0].upper() + t[1:] + if t[-1] not in ".!?": + t += "." + return t + + def _extract_env_vars(s: Optional[str]) -> tuple[Optional[str], list[str]]: + """Extract `[env: VAR=]` annotations from help text.""" + if not s: + return s, [] + env_vars = re.findall(r"\[env:\s*([A-Z0-9_]+)=\]", s) + text = re.sub(r"\s*\[env:\s*[A-Z0-9_]+=\]", "", s).strip() + return text, env_vars + + def _env_var_link(env_var: str) -> str: + """Return a markdown link to the environment variable reference entry.""" + anchor = env_var.lower() + return f"[`{env_var}`](../reference/environment-variables.md#{anchor})" + + def _head(level: int, text: str, anchor_id: Optional[str] = None) -> str: + """Markdown heading helper.""" + heading = f"{'#' * level} {text}" + if anchor_id: + heading += f" {{/* #{anchor_id} */}}" + return heading + + def _ensure_blank(lines: list[str]) -> None: + """Append a blank line if the last line is not blank.""" + if lines and lines[-1] != "": + lines.append("") + + def _format_default(a: argparse.Action) -> Optional[str]: + """Formatted default if meaningful, else None.""" + if _is_suppress(a.default): + return None + if isinstance(a, (argparse._StoreTrueAction, argparse._StoreFalseAction)): + return f"`{bool(a.default)}`" if bool(a.default) else None + if isinstance(a, argparse._CountAction): + return f"`{a.default}`" if a.default not in (None, 0) else None + if getattr(a, "const", None) is not None and a.default == a.const: + return None + if a.default not in (None, "", []): + return f"`{a.default}`" + return None + + def _metavar_if_informative( + a: argparse.Action, *, positional: bool + ) -> Optional[str]: + """Return informative metavar or None when redundant. + + - Suppress for flags without values or when choices exist. + - Suppress when token is just DEST in upper-case and there is no extra info. + - Include type/nargs adornments when present. + """ + if not positional and not _takes_value(a): + return None + if a.choices: + return None + + base = a.metavar or (a.dest.upper().replace("-", "_")) + dest_upper = (a.dest or "").upper().replace("-", "_") + + # nargs adornment + nargs_suffix = "" + if a.nargs in ("*", "+"): + nargs_suffix = a.nargs + elif isinstance(a.nargs, int) and a.nargs > 1: + nargs_suffix = f"×{a.nargs}" + + # type adornment + t = getattr(a, "type", None) + tname = getattr(t, "__name__", "") if callable(t) else "" + has_type = bool(tname and tname != "str") + + informative = (nargs_suffix != "") or has_type + if not informative and base == dest_upper: + return None + + token = base + nargs_suffix + if has_type: + token += f" <{tname}>" + return token + + def _choices_inline(a: argparse.Action) -> Optional[str]: + """Inline choices like: `a`, `b`, `c` (stable, sorted if needed).""" + if not a.choices: + return None + # choices might be a set -> make stable (sorted by str) + try: + items = list(a.choices) + except TypeError: + # If choices isn't iterable in a friendly way, fallback to repr + items = [a.choices] + # Sort for stability across runs + items = sorted(items, key=str) + return ", ".join(f"`{c}`" for c in items) + + # ---------------- resolve command ---------------- + root = get_parser() + raw_prog = getattr(root, "prog", None) or "cli" + + def _resolve( + p: argparse.ArgumentParser, parts: list[str] + ) -> argparse.ArgumentParser: + """Walk subcommands like ['build', 'ios'] and return that subparser.""" + if not parts: + return p + cur = p + used: list[str] = [] + for tok in parts: + used.append(tok) + subparsers = next( + ( + act + for act in cur._actions + if isinstance(act, argparse._SubParsersAction) + ), + None, + ) + if not subparsers: + raise ValueError( + f"No subcommands under: {' '.join(used[:-1]) or '(root)'}" + ) + if tok not in subparsers.choices: + opts = ", ".join(sorted(subparsers.choices.keys())) + raise ValueError(f"Unknown subcommand '{tok}'. Available: {opts}") + cur = subparsers.choices[tok] + return cur + + parts = [p for p in command.split() if p] + parser = _resolve(root, parts) + + # ---------------- build markdown ---------------- + out: list[str] = [] + heading_level = 2 + section_level = heading_level # e.g., 2 -> "##" + entry_level = heading_level + 1 # e.g., 3 -> "###" + + # 1) Description + desc = _cap_first(_clean(parser.description)) + if desc: + out.append(desc) + out.append("") + + # 2) Usage + usage = parser.format_usage().strip() + if usage.lower().startswith("usage:"): + usage = usage[6:].strip() + usage = usage.replace(raw_prog, "flet", 1) + out.append(_head(section_level, "Usage")) + out.append("") + out.append("```bash") + out.append(usage) + out.append("```") + + # 3) Collect actions + positionals_indexed: list[tuple[int, argparse.Action]] = [] + options: list[argparse.Action] = [] + subparsers = None + for idx, act in enumerate(parser._actions): + if isinstance(act, argparse._SubParsersAction): + subparsers = act + elif act.option_strings: + options.append(act) + else: + positionals_indexed.append((idx, act)) + + # 4) Positional arguments + if positionals_indexed: + # required first, stable in original order within groups + positionals_indexed.sort(key=lambda ia: (0 if ia[1].required else 1, ia[0])) + + out.append("") + out.append(_head(section_level, "Positional arguments")) + out.append("") + for _, a in positionals_indexed: + title = a.metavar or a.dest + out.append(_head(entry_level, title, anchor_id=title)) + + body_lines: list[str] = [] + help_text_raw, env_vars = _extract_env_vars(_clean(a.help)) + help_text = _cap_first(help_text_raw) or "" + if help_text: + body_lines.append(help_text) + + # Choices (inline) OR informative value + if a.choices: + _ensure_blank(body_lines) + body_lines.append(f"**Possible values:** {_choices_inline(a)}") + else: + meta = _metavar_if_informative(a, positional=True) + if meta: + _ensure_blank(body_lines) + body_lines.append(f"**Value:** `{meta}`") + + default = _format_default(a) + if default: + _ensure_blank(body_lines) + body_lines.append(f"**Default:** {default}") + else: + # No default -> explicit required true/false + _ensure_blank(body_lines) + body_lines.append(f"**Required:** {'true' if a.required else 'false'}") + + if env_vars: + _ensure_blank(body_lines) + label = ( + "**Environment variable:**" + if len(env_vars) == 1 + else "**Environment variables:**" + ) + body_lines.append( + label + + " " + + ", ".join(_env_var_link(env_var) for env_var in env_vars) + ) + + if body_lines: + out.extend(body_lines) + out.append("") + + # 5) Options + if options: + out.append("") + out.append(_head(section_level, "Options")) + out.append("") + + # stable sort by long flag + def _sort(a: argparse.Action) -> str: + longs = sorted([s for s in a.option_strings if s.startswith("--")]) or [ + "~" + (sorted(a.option_strings)[0] if a.option_strings else "") + ] + return longs[0] + + options = sorted(options, key=_sort) + + for a in options: + title_flag = _canonical_heading_flag(a) + out.append(_head(entry_level, title_flag, anchor_id=title_flag)) + + body_lines: list[str] = [] + help_text_raw, env_vars = _extract_env_vars(_clean(a.help)) + help_text = _cap_first(help_text_raw) or "" + if help_text: + body_lines.append(help_text) + + # Choices (inline) OR informative value + if a.choices: + _ensure_blank(body_lines) + body_lines.append(f"**Possible values:** {_choices_inline(a)}") + else: + meta = _metavar_if_informative(a, positional=False) + if meta: + _ensure_blank(body_lines) + body_lines.append(f"**Value:** `{meta}`") + + default = _format_default(a) + if default: + _ensure_blank(body_lines) + body_lines.append(f"**Default:** {default}") + + # Only show 'Required: true' for required options + if getattr(a, "required", False): + _ensure_blank(body_lines) + body_lines.append("**Required:** true") + + if env_vars: + _ensure_blank(body_lines) + label = ( + "**Environment variable:**" + if len(env_vars) == 1 + else "**Environment variables:**" + ) + body_lines.append( + label + + " " + + ", ".join(_env_var_link(env_var) for env_var in env_vars) + ) + + # Aliases (excluding the title flag) + aliases = [f for f in _all_flags(a) if f != title_flag] + if aliases: + _ensure_blank(body_lines) + body_lines.append( + "**Aliases:** " + ", ".join(f"`{f}`" for f in aliases) + ) + + if body_lines: + out.extend(body_lines) + out.append("") + + # 6) Subcommands (list only) + if subcommands_only and subparsers and subparsers.choices: + out.append("") + out.append(_head(section_level, "Subcommands")) + out.append("") + for name, sub in sorted(subparsers.choices.items()): + d = _clean(sub.description) or "" + first = _cap_first(d.splitlines()[0]) if d else "" + out.append(f"- [`{name}`](flet-{name}.md): {first}") + + return "\n".join(out) + + +if __name__ == "__main__": + print(render_flet_cli_as_markdown("create")) + print(render_flet_cli_as_markdown("", subcommands_only=True)) diff --git a/tools/crocodocs/src/crocodocs/scripts/cross_platform_permissions.py b/tools/crocodocs/src/crocodocs/scripts/cross_platform_permissions.py new file mode 100644 index 0000000000..6f91b202b4 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/scripts/cross_platform_permissions.py @@ -0,0 +1,114 @@ +import argparse + + +def _indent_block(text: str, indent: int) -> str: + """Indent every line of text by the given number of spaces.""" + prefix = " " * indent + return "\n".join(f"{prefix}{line}" for line in text.splitlines()) + + +def _toml_key(key: str) -> str: + """Return the TOML representation of a key, quoting it if it contains special characters.""" + if key.replace("-", "").replace("_", "").isalnum(): + return key + escaped = key.replace("\\", "\\\\").replace('"', '\\"') + return f'"{escaped}"' + + +def _toml_value(value) -> str: + """Return the TOML representation of a scalar Python value (bool, None, or string).""" + if isinstance(value, bool): + return "true" if value else "false" + if value is None: + return "null" + escaped = str(value).replace("\\", "\\\\").replace('"', '\\"') + return f'"{escaped}"' + + +def _load_cross_platform_permissions() -> dict: + """Load the cross-platform permissions dict from flet-cli's BaseBuildCommand.""" + from flet_cli.commands.build_base import BaseBuildCommand + + parser = argparse.ArgumentParser(add_help=False) + command = BaseBuildCommand(parser) + return command.cross_platform_permissions + + +def _render_toml_block(config: dict) -> str: + """Render a single permission config entry as a TOML snippet covering iOS, macOS, and Android sections.""" + ios_info_plist = config.get("ios_info_plist") or {} + macos_info_plist = config.get("macos_info_plist") or {} + legacy_info_plist = config.get("info_plist") or {} + macos_entitlements = config.get("macos_entitlements") or {} + android_permissions = config.get("android_permissions") or {} + android_features = config.get("android_features") or {} + + sections = [] + + if legacy_info_plist: + if not ios_info_plist: + ios_info_plist = legacy_info_plist + if not macos_info_plist: + macos_info_plist = legacy_info_plist + + if ios_info_plist: + lines = ["# iOS", "[tool.flet.ios.info]"] + for key, value in ios_info_plist.items(): + lines.append(f"{_toml_key(key)} = {_toml_value(value)}") + sections.append("\n".join(lines)) + + if macos_info_plist or macos_entitlements: + lines = ["# macOS"] + if macos_info_plist: + lines.append("[tool.flet.macos.info]") + for key, value in macos_info_plist.items(): + lines.append(f"{_toml_key(key)} = {_toml_value(value)}") + if macos_entitlements: + if macos_info_plist: + lines.append("") + lines.append("[tool.flet.macos.entitlement]") + for key, value in macos_entitlements.items(): + lines.append(f"{_toml_key(key)} = {_toml_value(value)}") + sections.append("\n".join(lines)) + + if android_permissions: + lines = ["# Android", "[tool.flet.android.permission]"] + for key, value in android_permissions.items(): + lines.append(f"{_toml_key(key)} = {_toml_value(value)}") + if android_features: + lines.extend(["", "[tool.flet.android.feature]"]) + for key, value in android_features.items(): + lines.append(f"{_toml_key(key)} = {_toml_value(value)}") + sections.append("\n".join(lines)) + + return "\n\n".join(sections) + + +def cross_platform_permissions_list() -> str: + """Render all cross-platform permissions as a Markdown list with collapsible pyproject.toml code blocks.""" + permissions = _load_cross_platform_permissions() + items = [] + for name, config in permissions.items(): + toml_block = _indent_block(_render_toml_block(config), 4) + items.append( + "\n".join( + [ + f"- `{name}`", + "", + "
", + " pyproject.toml equivalent", + "", + " ```toml", + toml_block, + " ```", + "", + "
", + ] + ) + ) + + return "\n\n".join(items) + "\n" + + +if __name__ == "__main__": + print(cross_platform_permissions_list()) diff --git a/tools/crocodocs/src/crocodocs/sidebars.py b/tools/crocodocs/src/crocodocs/sidebars.py new file mode 100644 index 0000000000..aebee214d4 --- /dev/null +++ b/tools/crocodocs/src/crocodocs/sidebars.py @@ -0,0 +1,155 @@ +"""Sidebar source and Docusaurus sidebar generation.""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +try: + import yaml +except ModuleNotFoundError: # pragma: no cover + yaml = None + +SPECIAL_KEYS = {"_index", "_generated_index", "_meta"} + + +def _doc_id(ref: str) -> str: + """Strip .md and .mdx suffixes from a doc reference to produce a Docusaurus doc ID.""" + return ref.removesuffix(".md").removesuffix(".mdx") + + +def _load_yaml(text_path: Path) -> Any: + """Read and parse a YAML file. Raises RuntimeError if PyYAML is not installed.""" + if yaml is None: # pragma: no cover + raise RuntimeError( + "PyYAML is required to parse sidebar YAML. Install CrocoDocs dependencies first." + ) + return yaml.safe_load(text_path.read_text(encoding="utf-8")) + + +def _load_sidebar_source(sidebars_yml: Path) -> Any: + """Load and return the top-level 'docs' section from the sidebar YAML file.""" + data = _load_yaml(sidebars_yml) or {} + docs = data.get("docs") + if docs is None: + raise ValueError(f"Expected top-level 'docs' key in {sidebars_yml}") + return docs + + +def _doc_item(label: str, ref: str) -> dict[str, Any]: + """Build a Docusaurus doc-type sidebar item with an optional label.""" + item: dict[str, Any] = {"type": "doc", "id": _doc_id(ref)} + if label: + item["label"] = label + return item + + +def _convert_source_entry(entry: Any) -> dict[str, Any]: + """Convert a sidebar source entry (bare string or {label: value} dict) to a Docusaurus item dict.""" + if isinstance(entry, str): + return _doc_item("", entry) + + if not isinstance(entry, dict) or len(entry) != 1: + raise ValueError(f"Unsupported sidebar source entry: {entry!r}") + + label, value = next(iter(entry.items())) + return _convert_labeled_source_entry(str(label), value) + + +def _convert_category_mapping( + label: str, + mapping: dict[str, Any], +) -> dict[str, Any]: + """Convert a dict-form sidebar category to a Docusaurus category item. + + Handles optional _meta (for collapsed state), _index (category link doc), and + _generated_index (generated-index link) special keys. + """ + collapsed = True + meta = mapping.get("_meta") + if isinstance(meta, dict) and "collapsed" in meta: + collapsed = bool(meta["collapsed"]) + + items: list[dict[str, Any]] = [] + for child_label, child_value in mapping.items(): + if child_label in SPECIAL_KEYS: + continue + items.append(_convert_labeled_source_entry(str(child_label), child_value)) + + category: dict[str, Any] = { + "type": "category", + "label": label, + "collapsed": collapsed, + "items": items, + } + generated_index = mapping.get("_generated_index") + if isinstance(generated_index, dict): + link: dict[str, Any] = {"type": "generated-index"} + if "title" in generated_index: + link["title"] = generated_index["title"] + if "slug" in generated_index: + link["slug"] = generated_index["slug"] + if "description" in generated_index: + link["description"] = generated_index["description"] + category["link"] = link + else: + index_ref = mapping.get("_index") + if isinstance(index_ref, str): + category["link"] = _doc_item("", index_ref) + return category + + +def _convert_labeled_source_entry( + label: str, + value: Any, +) -> dict[str, Any]: + """Convert a labeled sidebar entry (str, list, or dict) to a Docusaurus item dict.""" + if isinstance(value, str): + return _doc_item(label, value) + if isinstance(value, list): + return { + "type": "category", + "label": label, + "collapsed": True, + "items": [_convert_source_entry(child) for child in value], + } + if isinstance(value, dict): + return _convert_category_mapping(label, value) + raise ValueError(f"Unsupported sidebar source group for {label!r}: {value!r}") + + +def build_sidebar_items_from_source( + sidebars_yml: Path, +) -> list[dict[str, Any]]: + """Read the sidebar YAML and return a list of Docusaurus sidebar item dicts.""" + docs = _load_sidebar_source(sidebars_yml) + + if isinstance(docs, dict): + entries = [{label: value} for label, value in docs.items()] + elif isinstance(docs, list): + entries = docs + else: + raise ValueError(f"Unsupported 'docs' sidebar source in {sidebars_yml}") + + return [_convert_source_entry(entry) for entry in entries] + + +def render_sidebars_js(sidebar_items: list[dict[str, Any]]) -> str: + """Wrap sidebar items in a CommonJS module.exports string for Docusaurus.""" + payload = json.dumps({"docs": sidebar_items}, indent=2) + return ( + "// Generated by CrocoDocs from website/sidebars.yml.\n" + "// Do not edit by hand.\n\n" + f"module.exports = {payload};\n" + ) + + +def write_sidebars_js_from_source( + sidebars_yml: Path, + output_path: Path, +) -> None: + """Read the sidebar YAML and write the generated sidebars.js to output_path.""" + sidebar_items = build_sidebar_items_from_source(sidebars_yml) + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(render_sidebars_js(sidebar_items), encoding="utf-8") diff --git a/tools/crocodocs/src/crocodocs/watch.py b/tools/crocodocs/src/crocodocs/watch.py new file mode 100644 index 0000000000..34090dfcdd --- /dev/null +++ b/tools/crocodocs/src/crocodocs/watch.py @@ -0,0 +1,389 @@ +"""File watching support for long-running CrocoDocs development workflows. + +CrocoDocs generates JSON/MDX artifacts that Docusaurus consumes at runtime. +When edits are made to the Python source files, examples, or sidebar config while the +docs dev server is already running, those generated artifacts must be refreshed +explicitly. This module owns that refresh loop. +""" + +import signal +import subprocess +import threading +from dataclasses import dataclass +from pathlib import Path +from typing import Callable, Iterable, Optional + +from watchdog.events import FileSystemEventHandler +from watchdog.observers import Observer + +from .config import CrocoDocsConfig +from .generate import run_generate +from .progress import ProgressReporter + +# Directories that should never trigger documentation regeneration. +# They are either editor/build artifacts or trees CrocoDocs itself writes. +IGNORED_DIRECTORY_NAMES = { + ".git", + ".idea", + ".pytest_cache", + ".ruff_cache", + ".venv", + "__pycache__", + "build", + "dist", + "node_modules", +} + + +@dataclass(frozen=True) +class WatchTarget: + """A single filesystem target to watch.""" + + path: Path + """Absolute path to the watched file or directory.""" + + suffixes: Optional[frozenset[str]] = None + """ + File suffixes that matter when `path` is a directory. + A value of `None` means "watch every file beneath this directory". + """ + + is_file: bool = False + """Whether `path` should be treated as an individual file target.""" + + +class WatchEventHandler(FileSystemEventHandler): + """Collect relevant filesystem changes and expose them after a debounce window.""" + + def __init__(self, targets: list[WatchTarget]) -> None: + super().__init__() + self._targets = targets + self._lock = threading.Lock() + self._pending_changes: set[Path] = set() + # Set whenever a matching change arrives. Also used by `wake()` to unblock + # the main loop during shutdown. + self._change_event = threading.Event() + + def on_any_event(self, event) -> None: + """Track create/modify/delete/move events for configured watch targets.""" + if event.is_directory or event.event_type not in { + "created", + "deleted", + "modified", + "moved", + }: + return + + changed_paths = { + path + for path in _event_paths(event) + if _matches_any_target(path, self._targets) + } + if not changed_paths: + return + + with self._lock: + self._pending_changes.update(changed_paths) + self._change_event.set() + + def has_pending(self) -> bool: + """Return True if there are buffered changes waiting to be drained.""" + with self._lock: + return bool(self._pending_changes) + + def wait_for_change(self) -> None: + """Block until a change arrives or `wake()` is called.""" + self._change_event.wait() + self._change_event.clear() + + def wait_for_quiet_period( + self, debounce: float, should_abort: Callable[[], bool] + ) -> None: + """Block until `debounce` seconds elapse without new changes.""" + while self._change_event.wait(timeout=debounce): + self._change_event.clear() + if should_abort(): + return + + def wake(self) -> None: + """Unblock any in-progress wait so the main loop can re-check shutdown flags.""" + self._change_event.set() + + def drain_pending(self) -> list[Path]: + """Return and clear the buffered change set.""" + with self._lock: + ready = sorted(self._pending_changes) + self._pending_changes.clear() + return ready + + +def build_watch_targets(config: CrocoDocsConfig) -> list[WatchTarget]: + """Return the concrete files and directories that should trigger regeneration. + + The watch list covers only inputs whose changes produce new files under the + generated artifact roots (`.crocodocs`, `sidebars.js`, static assets) — + Python package sources, examples, sidebar YAML, and asset mappings. + Hand-authored `.md`/`.mdx` under `docs_path` are intentionally NOT watched: + Docusaurus hot-reloads those natively, so regenerating on every prose edit + would only trigger redundant rebuilds. If a structural edit requires a fresh + manifest (e.g. adding a new symbol-block import), run `crocodocs generate` + manually or restart the watcher. + """ + targets: list[WatchTarget] = [ + WatchTarget(config.sidebars_source, is_file=True), + WatchTarget(config.examples_root, frozenset({".py", ".png", ".gif", ".svg"})), + ] + + for package_root in sorted(config.packages.values(), key=str): + targets.append(WatchTarget(package_root, frozenset({".py"}))) + + for mapping in config.asset_mappings.values(): + suffixes = ( + frozenset(ext.lower() for ext in mapping.include_exts) + if mapping.include_exts + else None + ) + targets.append(WatchTarget(mapping.source_path, suffixes)) + + # Multiple config entries can collapse to the same directory (for example + # examples_root and the examples asset mapping). Deduplicate to avoid repeated + # scans while preserving a deterministic order for debug output. + unique_targets: list[WatchTarget] = [] + seen: set[tuple[Path, Optional[frozenset[str]], bool]] = set() + for target in targets: + key = (target.path, target.suffixes, target.is_file) + if key in seen: + continue + seen.add(key) + unique_targets.append(target) + return unique_targets + + +def run_watch( + config: CrocoDocsConfig, + *, + debounce: float, + command: Optional[list[str]] = None, + command_cwd: Optional[Path] = None, +) -> int: + """Regenerate CrocoDocs outputs on input changes and optionally run a child process. + + The child process is usually the Docusaurus dev server. The watcher keeps that + process running while a watchdog observer tracks changes and reruns `generate` + after a short debounce window so multi-file edits only trigger one regeneration. + """ + reporter = ProgressReporter("watch") + targets = build_watch_targets(config) + event_handler = WatchEventHandler(targets) + observer = Observer() + observer_started = False + child: Optional[subprocess.Popen[str]] = None + child_exit_code: Optional[int] = None + + stop_requested = False + + def request_stop(signum: int, _frame: object) -> None: + nonlocal stop_requested + stop_requested = True + reporter.info(f"Received signal {signum}; stopping watcher.") + event_handler.wake() + + def should_abort() -> bool: + return stop_requested or child_exit_code is not None + + original_handlers = { + sig: signal.getsignal(sig) for sig in (signal.SIGINT, signal.SIGTERM) + } + for sig in original_handlers: + signal.signal(sig, request_stop) + + try: + _run_generate_cycle(config, reporter) + _schedule_targets(observer, event_handler, targets, reporter) + observer.start() + observer_started = True + child = _start_child(command, command_cwd, reporter) + + if child is not None: + + def _monitor_child() -> None: + nonlocal child_exit_code + assert child is not None + child_exit_code = child.wait() + reporter.info( + f"Child process exited with code {child_exit_code}; stopping watcher." + ) + event_handler.wake() + + threading.Thread(target=_monitor_child, daemon=True).start() + + while not should_abort(): + event_handler.wait_for_change() + if should_abort(): + break + if not event_handler.has_pending(): + # Spurious wake (e.g. `wake()` called for shutdown check); re-evaluate. + continue + + event_handler.wait_for_quiet_period(debounce, should_abort) + if should_abort(): + break + + ready_changes = event_handler.drain_pending() + if ready_changes: + reporter.info(_format_change_message(ready_changes)) + _run_generate_cycle(config, reporter) + + return child_exit_code if child_exit_code is not None else 0 + finally: + for sig, handler in original_handlers.items(): + signal.signal(sig, handler) + if observer_started: + observer.stop() + observer.join(timeout=5) + _stop_child(child, reporter) + + +def _run_generate_cycle(config: CrocoDocsConfig, reporter: ProgressReporter) -> None: + """Run a single CrocoDocs generation cycle and keep watching on failure.""" + reporter.stage("Regenerating CrocoDocs artifacts") + try: + run_generate( + config, + docs_path=config.docs_path, + manifest_output=config.manifest_output, + api_output=config.api_output, + base_url=config.base_url, + ) + except Exception as exc: # noqa: BLE001 + # A failed regeneration should not kill the dev server or the watcher. + # Contributors often fix docs errors incrementally and expect the next save to + # retry automatically. + reporter.info(f"Generation failed: {exc}") + + +def _start_child( + command: Optional[list[str]], + command_cwd: Optional[Path], + reporter: ProgressReporter, +) -> Optional[subprocess.Popen[str]]: + """Spawn the optional child process that should run alongside the watcher.""" + if not command: + return None + + reporter.info( + "Starting child process: " + + " ".join(command) + + (f" (cwd={command_cwd})" if command_cwd else "") + ) + return subprocess.Popen(command, cwd=command_cwd, text=True) # noqa: S603 + + +def _stop_child( + child: Optional[subprocess.Popen[str]], reporter: ProgressReporter +) -> None: + """Terminate the child process gracefully, then force kill if needed.""" + if child is None or child.poll() is not None: + return + + reporter.info("Stopping child process.") + child.terminate() + try: + child.wait(timeout=10) + except subprocess.TimeoutExpired: + reporter.info("Child did not exit in time; killing it.") + child.kill() + child.wait() + + +def _format_change_message(changed_paths: list[Path]) -> str: + """Render a compact log line for detected file changes.""" + preview = ", ".join(path.name for path in changed_paths[:4]) + if len(changed_paths) > 4: + preview += f", +{len(changed_paths) - 4} more" + return f"Detected changes in {len(changed_paths)} file(s): {preview}" + + +def _schedule_targets( + observer: Observer, + event_handler: WatchEventHandler, + targets: Iterable[WatchTarget], + reporter: ProgressReporter, +) -> None: + """Register the minimum set of observer roots needed for all watch targets.""" + scheduled_roots: dict[Path, bool] = {} + for target in targets: + resolved = _watch_root(target, reporter) + if resolved is None: + continue + root, recursive = resolved + scheduled_roots[root] = scheduled_roots.get(root, False) or recursive + + for root, recursive in sorted(scheduled_roots.items()): + observer.schedule(event_handler, str(root), recursive=recursive) + + +def _watch_root( + target: WatchTarget, reporter: ProgressReporter +) -> Optional[tuple[Path, bool]]: + """Return the concrete observer root for a watch target, or None if it is missing. + + Missing targets are skipped with a warning instead of walking up to an existing + ancestor — a silent walk-up can expand the watch scope to the entire repo when a + configured path has a typo or points at an un-checked-out package. + """ + root = target.path.parent if target.is_file else target.path + if not root.exists(): + reporter.info(f"Skipping watch target {target.path} — path does not exist.") + return None + return root, not target.is_file + + +def _event_paths(event) -> list[Path]: + """Return the event source and destination paths, normalized to absolute paths.""" + paths = [Path(event.src_path).resolve()] + dest_path = getattr(event, "dest_path", None) + if dest_path: + paths.append(Path(dest_path).resolve()) + return paths + + +def _matches_any_target(path: Path, targets: Iterable[WatchTarget]) -> bool: + """Return True when a path belongs to at least one configured watch target.""" + return any(_matches_target(path, target) for target in targets) + + +def _matches_target(path: Path, target: WatchTarget) -> bool: + """Return True when a path should trigger regeneration for a specific target.""" + if target.is_file: + return path == target.path and _matches_suffixes(path, target.suffixes) + + try: + relative_path = path.relative_to(target.path) + except ValueError: + return False + + if not relative_path.parts: + return False + + if _should_skip_parts(relative_path.parts): + return False + + return _matches_suffixes(path, target.suffixes) + + +def _should_skip_parts(parts: tuple[str, ...]) -> bool: + """Return True for files inside ignored directories or hidden paths.""" + for part in parts: + if part in IGNORED_DIRECTORY_NAMES: + return True + if part.startswith(".") and part not in {".env"}: + return True + return False + + +def _matches_suffixes(path: Path, suffixes: Optional[frozenset[str]]) -> bool: + """Return True when a path should be included for a directory target.""" + if suffixes is None: + return True + return path.suffix.lower() in suffixes diff --git a/website/.agents/skills/flet-release-announcement/SKILL.md b/website/.agents/skills/flet-release-announcement/SKILL.md new file mode 100644 index 0000000000..3666265a71 --- /dev/null +++ b/website/.agents/skills/flet-release-announcement/SKILL.md @@ -0,0 +1,104 @@ +--- +name: flet-release-announcement +description: Create or update a Flet release announcement blog post from changelog notes, matching existing /blog style. Use when asked to draft, plan, or revise posts like "Flet X.Y.Z release announcement" with major feature sections, screenshots, code samples, upgrade instructions (pip and uv/pyproject.toml), and a compact "other changes" summary. +--- + +# Flet Release Announcement + +Use this skill when the user asks to plan/write/refine a Flet release blog post. + +## Inputs to collect + +- Release version (example: `0.81.0`) +- Target blog file path (or create one) +- Changelog source (local repo path or GitHub link) +- Preferred title (if provided) +- Any must-include or must-exclude topics + +If inputs are missing, infer from open files and recent release posts. + +## Style targets + +- Match tone/structure of recent release posts in `/blog`. +- Keep writing practical and concise. +- Avoid excessive emoji and unnecessary bold formatting. +- Lead with substantial features; keep long tail in "Other changes and bug fixes". +- Format GitHub issue/PR references as Markdown link labels like `[#6190](https://github.com/.../issues/6190)`, not bare URLs. +- Wrap control/service/type names in backticks in prose and labels (for example, `` `Clipboard` docs ``). + +## Workflow + +1. Inspect prior release posts for structure +- Read 2-3 recent release posts in `/blog`. +- Reuse conventions: frontmatter, short intro, highlights bullets, `{/* truncate */}`, upgrade section, major feature sections, improvements, other changes, conclusion. + +2. Ground facts in changelog +- Use the exact release section from `CHANGELOG.md` or the release branch/tag anchor. +- Do not invent claims, platforms, or options. +- Keep issue/PR links for traceability. + +3. Select major vs other items +- Promote 5-8 most substantial features to dedicated sections. +- Keep less substantial or niche items in compact bullets at the end. + +4. Source screenshots +- Prefer existing docs/integration golden images. +- Typical sources: + - `sdk/python/packages/flet/integration_tests/.../golden/...` + - `sdk/python/examples/.../media/...` +- Copy selected assets into website repo: + - `static/img/blog/flet-/...` +- If an image is unavailable, explicitly note the gap. + +5. Build each major feature section +For each major feature include: +- What it is +- What problem it solves +- Short code sample +- Screenshot (``) +- "More info" links (docs + issue/PR) + +6. Upgrade instructions +Always include both flows: + +- pip: +```bash +pip install 'flet[all]' --upgrade +``` + +- uv + `pyproject.toml`: +```bash +uv sync --upgrade +``` + +```bash +uv sync --upgrade-package flet \ + --upgrade-package flet-cli \ + --upgrade-package flet-desktop \ + --upgrade-package flet-web +``` + +On Linux, mention that some setups use `flet-desktop-light` instead of `flet-desktop`; in that case `--upgrade-package flet-desktop-light` should be used. + +7. Verify before handoff +- Title and slug align with repo naming conventions. +- All image paths exist in `static/img/...`. +- Docs/issue links resolve and match section claims. +- "Other changes" list mirrors changelog items accurately. + +## Useful command patterns + +```bash +rg --files blog | rg 'release-announcement|flet-v-0-' +sed -n '1,260p' blog/.md +sed -n '1,260p' /CHANGELOG.md +rg --files /sdk/python/packages/flet/integration_tests | rg '.*(png|gif|jpg)$' +mkdir -p static/img/blog/flet- +cp static/img/blog/flet-/.png +``` + +## Output checklist + +- New or updated blog post in `/blog` +- Referenced screenshots copied under `static/img/blog/flet-/` +- Final text includes major sections, upgrades (pip + uv), improvements, and concise other changes diff --git a/website/.gitattributes b/website/.gitattributes new file mode 100644 index 0000000000..dfe0770424 --- /dev/null +++ b/website/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000000..cf48be5921 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,35 @@ +# Dependencies +/node_modules + +# Production +/build + +# Generated files +.docusaurus +.cache-loader + +# Misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Yarn +/.yarn + +.venv/ +.crocodocs/ + +# Generated CrocoDocs asset mirrors +/docs/assets/ +/docs/examples/ +/docs/test-images/ +/docs/test-images-charts/ +/static/docs/examples/ +/static/docs/test-images/ +/static/docs/test-images-charts/ diff --git a/website/.yarnrc.yml b/website/.yarnrc.yml new file mode 100644 index 0000000000..3186f3f079 --- /dev/null +++ b/website/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/website/LICENSE b/website/LICENSE new file mode 100644 index 0000000000..82e1078aac --- /dev/null +++ b/website/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Appveyor Systems Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/website/README.md b/website/README.md new file mode 100644 index 0000000000..51e6db3e1b --- /dev/null +++ b/website/README.md @@ -0,0 +1,27 @@ +# Website + +This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. + +View the live site at [https://flet.dev](https://flet.dev). + +### Installation + +``` +$ yarn +``` + +### Local Development + +``` +$ yarn start +``` + +This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. + +### Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory and can be served using any static contents hosting service. diff --git a/website/babel.config.js b/website/babel.config.js new file mode 100644 index 0000000000..e00595dae7 --- /dev/null +++ b/website/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [require.resolve('@docusaurus/core/lib/babel/preset')], +}; diff --git a/website/blog/2022-06-02-introducing-flet.md b/website/blog/2022-06-02-introducing-flet.md new file mode 100644 index 0000000000..abc0115dbf --- /dev/null +++ b/website/blog/2022-06-02-introducing-flet.md @@ -0,0 +1,28 @@ +--- +slug: introducing-flet +title: Introducing Flet +authors: feodor +tags: [news, product] +--- + +Today we announce the first release of Flet! + +Flet is a framework for building real-time web, desktop and mobile applications in Python. + +No more complex architecture with JavaScript frontend, REST API backend, database, cache, etc. With Flet you just write a monolith stateful app in Python only and get multi-user, realtime Single-Page Application (SPA) or a mobile app. + +To start developing with Flet, you just need your favorite IDE or text editor. No SDKs, no thousands of dependencies, no complex tooling - Flet has built-in web server with assets hosting and desktop clients. + +Flet UI is built with [Flutter](https://flutter.dev), so your app looks professional and can be delivered to any platform. Flet simplifies Flutter model by combining smaller "widgets" into ready-to-use "controls" with imperative programming model. +You get all the power of Flutter without having to learn Dart! + +Flet app is deployed as a regular web app and can be instanly accessed with a browser or installed as a [PWA](https://web.dev/what-are-pwas/) on a mobile device. Web app also exposes an API that can be used by a Flet client (planned for [future releases](/roadmap)) running on iOS and Android and providing native mobile experience. + +Some examples: + +* [Greeter](https://github.com/flet-dev/examples/blob/main/python/apps/greeter/greeter.py) +* [Counter](https://github.com/flet-dev/examples/blob/main/python/apps/counter/counter.py) +* [To-Do](https://github.com/flet-dev/examples/blob/main/python/apps/todo/todo.py) +* [Icons Browser](https://github.com/flet-dev/examples/blob/main/python/apps/icons-browser/main.py) ([Online Demo](https://gallery.flet.dev/icons-browser/)) + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-06-12-using-custom-fonts-in-flet-app.md b/website/blog/2022-06-12-using-custom-fonts-in-flet-app.md new file mode 100644 index 0000000000..d572828381 --- /dev/null +++ b/website/blog/2022-06-12-using-custom-fonts-in-flet-app.md @@ -0,0 +1,83 @@ +--- +slug: using-custom-fonts-in-flet-app +title: Using custom fonts in a Flet app +authors: feodor +tags: [how-to] +--- + +You can now use your own fonts in a Flet app! + +The following font formats are supported: + +* `.ttc` +* `.ttf` +* `.otf` + +Use [`page.fonts`](https://flet.dev/docs/controls/page/#flet.Page.fonts) property to import fonts. + +{/* truncate */} + +Set `page.fonts` property to a dictionary where key is the font family name to refer that font and the value is the URL of the font file to import: + +```python +def main(page: ft.Page): + page.fonts = { + "Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf", + "Aleo Bold Italic": "https://raw.githubusercontent.com/google/fonts/master/ofl/aleo/Aleo-BoldItalic.ttf" + } + page.update() + + # ... +``` + +Font can be imported from external resource by providing an absolute URL or from application assets by providing relative URL and `assets_dir`. + +Specify `assets_dir` in `flet.app()` call to set the location of assets that should be available to the application. `assets_dir` could be a relative to your `main.py` directory or an absolute path. For example, consider the following program structure: + +``` +/assets + /fonts + /OpenSans-Regular.ttf +main.py +``` + +## Code sample + +The following program loads "Kanit" font from GitHub and "Open Sans" from the assets. "Kanit" is set as a default app font and "Open Sans" is used for a specific Text control: + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "Custom fonts" + + page.fonts = { + "Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf", + "Open Sans": "fonts/OpenSans-Regular.ttf", + } + + page.theme = ft.Theme(font_family="Kanit") + + page.add( + ft.Text("This is rendered with Kanit font"), + ft.Text("This is Open Sans font example", font_family="Open Sans"), + ) + +ft.run(main, assets_dir="assets") +``` + + + +## Static vs Variable fonts + +At the moment only [static](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#standard_or_static_fonts) fonts are supported, i.e. fonts containing only one specific width/weight/style combination, for example "Open Sans Regular" or "Roboto Bold Italic". + +[Variable](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#variable_fonts) fonts support is still [work in progress](https://github.com/flutter/flutter/issues/33709). + +However, if you need to use a variable font in your app you can create static "instantiations" at specific weights using [fonttools](https://pypi.org/project/fonttools/), then use those: + + fonttools varLib.mutator ./YourVariableFont-VF.ttf wght=140 width=85 + +To explore available font features (e.g. possible options for `wght`) use [Wakamai Fondue](https://wakamaifondue.com/beta/) online tool. + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-07-14-drag-and-drop-release.md b/website/blog/2022-07-14-drag-and-drop-release.md new file mode 100644 index 0000000000..04e537b299 --- /dev/null +++ b/website/blog/2022-07-14-drag-and-drop-release.md @@ -0,0 +1,66 @@ +--- +slug: drag-and-drop-release +title: 'New release: Drag and Drop, absolute positioning and clickable container' +authors: feodor +tags: [release] +--- + +We have just released [Flet 0.1.41](https://pypi.org/project/flet/0.1.41/) with drag-and-drop support and other neat features such as absolute positioning of controls inside stack and clickable container! + +## Drag and Drop + +Making drag-and-drop in Flet is a real joy - thanks to a smart drag-and-drop implementation in Flutter! You just have "draggable" control which could be dragged to a "drag target" which calls `on_accept` event handler when draggable is dropped. + + + +Take a look at [Drag-and-Drop example](https://github.com/flet-dev/examples/blob/main/python/controls/drag-and-drop/drag-drop-colors.py). + +Explore [`Draggable`](https://flet.dev/docs/controls/draggable/) and [`DragTarget`](https://flet.dev/docs/controls/dragtarget/) controls, their properties and events. + +{/* truncate */} + +## Absolute positioning inside Stack + +All visible controls now have `left` `top`, `right` and `bottom` properties to let them be absolutely positioned inside [`Stack`](https://flet.dev/docs/controls/stack/), for example: + +```python {13-17} +import flet as ft + +def main(page: ft.Page): + + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + page.add( + ft.Container( + ft.Stack( + [ + ft.Text("1", color=ft.Colors.WHITE), + ft.Text("2", color=ft.Colors.WHITE, right=0), + ft.Text("3", color=ft.Colors.WHITE, right=0, bottom=0), + ft.Text("4", color=ft.Colors.WHITE, left=0, bottom=0), + ft.Text("5", color=ft.Colors.WHITE, left=40, top=35), + ] + ), + border_radius=8, + padding=5, + width=100, + height=100, + bgcolor=ft.Colors.BROWN_700, + ) + ) + +ft.run(main) +``` + + + +## Clickable container + +[`Container`](https://flet.dev/docs/controls/container/) control has got `on_click` event which allows you to make a button from any control and with a beautiful material ripple effect when `ink` is set to `True`! + + + +See [source code](https://github.com/flet-dev/examples/blob/main/python/controls/container/clickable-container.py) for the example above. + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-07-23-navigation-and-routing.md b/website/blog/2022-07-23-navigation-and-routing.md new file mode 100644 index 0000000000..63852628ee --- /dev/null +++ b/website/blog/2022-07-23-navigation-and-routing.md @@ -0,0 +1,184 @@ +--- +slug: navigation-and-routing +title: Navigation and Routing +authors: feodor +tags: [release] +--- + +[Flet 0.1.42](https://pypi.org/project/flet/0.1.42/) has been released with navigation and routing! + +Navigation and routing is an essential feature of Single Page Applications (SPA) which allows organizing application user interface into virtual pages (views) and "navigate" between them while application URL reflects the current state of the app. + +For mobile apps navigation and routing serves as a [deep linking](https://docs.flutter.dev/development/ui/navigation/deep-linking) to specific application parts. + +Well, it took [more efforts](https://github.com/flet-dev/flet/pull/95/files) than expected to add navigation and routing into Flet as the implementation is based on [Navigator 2.0](https://medium.com/flutter/learning-flutters-new-navigation-and-routing-system-7c9068155ade) Flutter API and required to replace Flet's "Page" abstraction with "Page and Views". Flutter's newer navigation and routing API has substantial improvements such as: + +1. Programmatic control over history stack. +2. An easy way to intercept a call to "Back" button in AppBar. +3. Robust synchronization with browser history. + + + +Explore [source code](https://github.com/flet-dev/examples/blob/main/python/apps/routing-navigation/building-views-on-route-change.py) of the example above. + +{/* truncate */} + +## Page route + +Page route is a portion of application URL after `#` symbol: + + + +Default application route, if not set in application URL by the user, is `/`. All routes start with `/`, for example `/store`, `/authors/1/books/2`. + +Application route can be obtained by reading `page.route` property, for example: + +```python +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text(f"Initial route: {page.route}")) + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Grab application URL, open a new browser tab, paste the URL, modify its part after `#` to `/test` and hit enter. You should see "Initial route: /test". + +Every time the route in the URL is changed (by editing the URL or navigating browser history with Back/Forward buttons) Flet calls `page.on_route_change` event handler: + +```python +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text(f"Initial route: {page.route}")) + + def route_change(route): + page.add(ft.Text(f"New route: {route}")) + + page.on_route_change = route_change + page.update() + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Now try updating URL hash a few times and then use Back/Forward buttons! You should see a new message added to a page each time the route changes: + + + +Route can be changed programmatically, by updating `page.route` property: + +```python +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text(f"Initial route: {page.route}")) + + def route_change(route): + page.add(ft.Text(f"New route: {route}")) + + def go_store(e): + page.route = "/store" + page.update() + + page.on_route_change = route_change + page.add(ft.ElevatedButton("Go to Store", on_click=go_store)) + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Click "Go to Store" button and you'll see application URL is changed and a new item is pushed in a browser history. You can use browser "Back" button to navigate to a previous route. + +## Page views + +Flet's [Page](https://flet.dev/docs/controls/page/) now is not just a single page, but a container for [View](https://flet.dev/docs/controls/view/) layered on top of each other like a sandwich: + + + +A collection of views represents navigator history. Page has [`page.views`](https://flet.dev/docs/controls/page/#flet.Page.views) property to access views collection. + +The last view in the list is the one currently displayed on a page. Views list must have at least one element (root view). + +To simulate a transition between pages change `page.route` and add a new `View` in the end of `page.view` list. + +Pop the last view from the collection and change route to a "previous" one in [`page.on_view_pop`](https://flet.dev/docs/controls/page/#flet.Page.on_view_pop) event handler to go back. + +## Building views on route change + +To build a reliable navigation there must be a single place in the program which builds a list of views depending on the current route. Other words, navigation history stack (represented by the list of views) must be a function of a route. + +This place is [`page.on_route_change`](https://flet.dev/docs/controls/page/#flet.Page.on_route_change) event handler. + +Let's put everything together into a complete example which allows navigating between two pages: + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "Routes Example" + + def route_change(route): + page.views.clear() + page.views.append( + ft.View( + "/", + [ + ft.AppBar(title=ft.Text("Flet app"), bgcolor=ft.Colors.SURFACE_VARIANT), + ft.ElevatedButton("Visit Store", on_click=lambda _: page.go("/store")), + ], + ) + ) + if page.route == "/store": + page.views.append( + ft.View( + "/store", + [ + ft.AppBar(title=ft.Text("Store"), bgcolor=ft.Colors.SURFACE_VARIANT), + ft.ElevatedButton("Go Home", on_click=lambda _: page.go("/")), + ], + ) + ) + page.update() + + def view_pop(view): + page.views.pop() + top_view = page.views[-1] + page.go(top_view.route) + + page.on_route_change = route_change + page.on_view_pop = view_pop + page.go(page.route) + + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Try navigating between pages using "Visit Store" and "Go Home" buttons, Back/Forward browser buttons, manually changing route in the URL - it works no matter what! :) + +:::note +To "navigate" between pages we used [`page.go(route)`](https://flet.dev/docs/controls/page/#flet.Page.go) - a helper method that updates [`page.route`](https://flet.dev/docs/controls/page/#flet.Page.route), calls [`page.on_route_change`](https://flet.dev/docs/controls/page/#flet.Page.on_route_change) event handler to update views and finally calls `page.update()`. +::: + +Notice the usage of [`page.on_view_pop`](https://flet.dev/docs/controls/page/#flet.Page.on_view_pop) event handler. It fires when the user clicks automatic "Back" button in [`AppBar`](https://flet.dev/docs/controls/appbar/) control. In the handler we remove the last element from views collection and navigate to view's root "under" it. + +## Route templates + +Flet offers [`TemplateRoute`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-core/src/flet_core/template_route.py) - an utility class based on [repath](https://github.com/nickcoutsos/python-repath) library which allows matching ExpressJS-like routes and parsing their parameters, for example `/account/:account_id/orders/:order_id`. + +`TemplateRoute` plays great with route change event: + +```python +troute = TemplateRoute(page.route) + +if troute.match("/books/:id"): + print("Book view ID:", troute.id) +elif troute.match("/account/:account_id/orders/:order_id"): + print("Account:", troute.account_id, "Order:", troute.order_id) +else: + print("Unknown route") +``` + +You can read more about template syntax supported by `repath` library [here](https://github.com/nickcoutsos/python-repath#parameters). + +That's all for today! + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-07-24-flet-mobile-strategy.md b/website/blog/2022-07-24-flet-mobile-strategy.md new file mode 100644 index 0000000000..153e000749 --- /dev/null +++ b/website/blog/2022-07-24-flet-mobile-strategy.md @@ -0,0 +1,63 @@ +--- +slug: flet-mobile-strategy +title: Flet Mobile Strategy +authors: feodor +tags: [product] +--- + +Flet project has received a lot of attention recently and we would like to thank all the developers who tried Flet and have been spreading the word about it in the communities! Your support motivates us to move Flet project forward with faster pace! + +New Flet developers are constantly asking if there is a way to package Flet program to an `.apk` file to deploy to Android devices or `.ipa` to deploy to iOS. + +In this post I would like to share our vision for Flet going mobile and provide a roadmap. + +{/* truncate */} + +## Server-Driven UI + +Flet is a Server-driven UI (SDUI) framework. SDUI is an emerging technology which is the best described in [Technology Radar post](https://www.thoughtworks.com/en-ca/radar/techniques/server-driven-ui): + +> Server-driven UI separates the rendering into a generic container in the mobile app while the structure and data for each view is provided by the server. This means that changes that once required a round trip to an app store can now be accomplished via simple changes to the responses the server sends. + +Companies like [DoorDash](https://doordash.engineering/2021/08/24/improving-development-velocity-with-generic-server-driven-ui-components/), [Airbnb](https://medium.com/airbnb-engineering/a-deep-dive-into-airbnbs-server-driven-ui-system-842244c5f5), [Lyft](https://podcasts.apple.com/us/podcast/server-driven-ui-with-kevin-fang-jeff-hurray/id1453587931?i=1000509742062) and others have been successfully implementing Server-driven UI in their mobile apps to reduce time-to-market. + +### Flet approach + +Flet is going to implement Server-Driven UI approach where program written in Python or other language is running on the server and only a thin client - either standalone Flutter app (`.apk` or `.ipa` package) in app store or a Flutter widget as a part of another app - is delivered to a mobile: + + + +Once SDUI experience is ready we'll start working on a [standalone mobile package](#standalone-mobile-package-for-flet-app). + +## Roadmap + +To provide the best experience for Flet apps on mobile platforms, we plan to release the following items by the end of this year: + +### Flet widget for Flutter + +The first step we are going to do is to separate Flet client into a Flutter widget and publish the package at https://pub.dev. +Flet widget could be then integrated by mobile developers into existing or new Flutter apps for adding dynamic server-driven UI experiences to the core app functionality. A new Flutter app could be also created with a single Flet widget just for the purpose of hosting a complete Flet app. + +Developers will follow Flutter guide for packaging, signing and distributing their apps to [Android](https://docs.flutter.dev/deployment/android), [iOS](https://docs.flutter.dev/deployment/ios), [Linux](https://docs.flutter.dev/deployment/linux), [macOS](https://docs.flutter.dev/deployment/macos) or [Windows](https://docs.flutter.dev/deployment/windows) platforms. + +Flet team will provide sample CI pipelines to automate packaging, signing and publishing of Flutter apps. + +### Flet Studio for iOS and Android + +The next step is a standalone "Flet Studio" app (the name is not final) in App Store and Google Play for "testing mobile experiences developed with Flet framework". Developers or beta testers will be able to "register" URL of their hosted Flet app within Flet Studio and instantly see how it performs on a mobile device. + +### White-labeled Flet mobile app + +We are going to provide a guide and CI pipeline for automatic publishing of white-labeled Flet app to a user App Store or Google Play account. This app will be "pinned" to a specific app URL and could additionally bundle app assets (media, fonts) to minimize network usage. + +### Standalone mobile package for Flet app + +We are going to investigate the way and develop a prototype for bundling together Flet framework, user program, language runtime and all dependencies into a standalone mobile package (`.apk` or `.ipa` package), so Flet program does not require a web server. + +### Embedding Flet into native apps + +We are going to provide a guide, sample apps and CI pipeline to integrate Flet widget into existing native Android and iOS apps (not developed with Flutter) using [Flutter Add-to-App](https://docs.flutter.dev/development/add-to-app) feature. [Put Flutter to work](https://medium.com/flutter/put-flutter-to-work-95f5fdcc592e) article gives a real-world example on how to integrate Flutter into existing mobile app. + +This is the current plan. + +In the meantime, [give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-08-03-control-refs.md b/website/blog/2022-08-03-control-refs.md new file mode 100644 index 0000000000..e6fb3814db --- /dev/null +++ b/website/blog/2022-08-03-control-refs.md @@ -0,0 +1,119 @@ +--- +slug: control-refs +title: Control Refs +authors: feodor +tags: [how-to] +--- + +Flet controls are objects and to access their properties we need to keep references (variables) to those objects. + +Consider the following example: + +```python {6-8,18,19,21} +import flet as ft + +def main(page): + + first_name = ft.TextField(label="First name", autofocus=True) + last_name = ft.TextField(label="Last name") + greetings = ft.Column() + + def btn_click(e): + greetings.controls.append(ft.Text(f"Hello, {first_name.value} {last_name.value}!")) + first_name.value = "" + last_name.value = "" + page.update() + first_name.focus() + + page.add( + first_name, + last_name, + ft.ElevatedButton("Say hello!", on_click=btn_click), + greetings, + ) + +ft.run(main) +``` + +In the very beginning of `main()` method we create three controls which we are going to use in button's `on_click` handler: two `TextField` for first and last names and a `Column` - container for greeting messages. We create controls with all their properties set and in the end of `main()` method, in `page.add()` call, we use their references (variables). + +When more and mode controls and event handlers added it becomes challenging to keep all control definitions in one place, so they become scattered across `main()` body. Glancing at `page.add()` parameters it's hard to imagine (without constant jumping to variable definitions in IDE) what would the end form look like: + +```python {2-5} + page.add( + first_name, + last_name, + ft.ElevatedButton("Say hello!", on_click=btn_click), + greetings, + ) +``` + +Is `first_name` a TextField, does it have autofocus set? Is greetings a `Row` or a `Column`? + +{/* truncate */} + +## `Ref` class + +Flet provides `Ref` utility class which allows to define a reference to the control, use that reference in event handlers and set the reference to a real control later, while building a tree. The idea comes from [React](https://reactjs.org/docs/refs-and-the-dom.html). + +To define a new typed control reference: + +```python +first_name = ft.Ref[ft.TextField]() +``` + +To access referenced control (control de-reference) use `Ref.current` property: + +```python +# empty first name +first_name.current.value = "" +``` + +To assign control to a reference set `Control.ref` property to a reference: + +```python {2} +page.add( + ft.TextField(ref=first_name, label="First name", autofocus=True) +) +``` + +:::note +All Flet controls have `ref` property. +::: + +We could re-write our program to use references: + +```python {7-9,21-24} +import flet as ft + + +def main(page): + + first_name = ft.Ref[ft.TextField]() + last_name = ft.Ref[ft.TextField]() + greetings = ft.Ref[ft.Column]() + + def btn_click(e): + greetings.current.controls.append( + ft.Text(f"Hello, {first_name.current.value} {last_name.current.value}!") + ) + first_name.current.value = "" + last_name.current.value = "" + page.update() + first_name.current.focus() + + page.add( + ft.TextField(ref=first_name, label="First name", autofocus=True), + ft.TextField(ref=last_name, label="Last name"), + ft.ElevatedButton("Say hello!", on_click=btn_click), + ft.Column(ref=greetings), + ) + +ft.run(main) +``` + +Now we can clearly see in `page.add()` the structure of the page and all the controls it's built of. + +Yes, the logic becomes a little bit more verbose as you need to add `.current.` to access ref's control, but it's a matter of personal preference :) + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-08-04-gradients-button-textfield-styles.md b/website/blog/2022-08-04-gradients-button-textfield-styles.md new file mode 100644 index 0000000000..22b4b656fc --- /dev/null +++ b/website/blog/2022-08-04-gradients-button-textfield-styles.md @@ -0,0 +1,324 @@ +--- +slug: gradients-button-textfield-styles +title: Beautiful gradients, button styles and TextField rounded corners in a new Flet release +authors: feodor +tags: [release] +--- + +We've just released [Flet 0.1.46](https://pypi.org/project/flet/0.1.46/) adding new exciting features: + +* Gradient backgrounds in Container +* Extensive styling for buttons, TextField and Dropdown controls +* ...and more + +{/* truncate */} + +## Gradient backgrounds + +### Linear gradient + + + +```python +import math +import flet as ft + +def main(page: ft.Page): + + page.add( + ft.Container( + alignment=ft.alignment.center, + gradient=ft.LinearGradient( + begin=ft.alignment.top_left, + end=Alignment(0.8, 1), + colors=[ + "0xff1f005c", + "0xff5b0060", + "0xff870160", + "0xffac255e", + "0xffca485c", + "0xffe16b5c", + "0xfff39060", + "0xffffb56b", + ], + tile_mode=ft.GradientTileMode.MIRROR, + rotation=math.pi / 3, + ), + width=150, + height=150, + border_radius=5, + ) + ) + +ft.run(main) +``` + +Check [`LinearGradient`](https://flet.dev/docs/types/lineargradient/) docs for more information about `LinearGradient` properties. + +### Radial gradient + + + +```python +import flet as ft + +def main(page: ft.Page): + + page.add( + ft.Container( + alignment=ft.alignment.center, + gradient=ft.RadialGradient( + center=Alignment(0.7, -0.6), + radius=0.2, + colors=[ + "0xFFFFFF00", # yellow sun + "0xFF0099FF", # blue sky + ], + stops=[0.4, 1.0], + ), + width=150, + height=150, + border_radius=5, + ) + ) + +ft.run(main) +``` + +Check [`RadialGradient`](https://flet.dev/docs/types/radialgradient/) docs for more information about `RadialGradient` properties. + +### Sweep gradient + + + +```python +import math +import flet as ft + +def main(page: ft.Page): + + page.add( + ft.Container( + alignment=ft.alignment.center, + gradient=SweepGradient( + center=ft.alignment.center, + start_angle=0.0, + end_angle=math.pi * 2, + colors=[ + "0xFF4285F4", + "0xFF34A853", + "0xFFFBBC05", + "0xFFEA4335", + "0xFF4285F4", + ], + stops=[0.0, 0.25, 0.5, 0.75, 1.0], + ), + width=150, + height=150, + border_radius=5, + ) + ) + +ft.run(main) +``` + +Check [`SweepGradient`](https://flet.dev/docs/types/sweepgradient/) docs for more information about `SweepGradient` properties. + +## Buttons styling + +This Flet release introduces `style` property to all button controls which is an instance of `ButtonStyle` class. +`ButtonStyle` allows controlling all visual aspects of a button, such as shape, foreground, background and shadow colors, content padding, border width and radius! + +Moreover, each individual style attribute could be configured for a different "Material states" of a button, such as "hovered", "focused", "disabled" and others. For example, you can configure a different shape, background color for a hovered state and configure fallback values for all other states. + +Check this "extreme" styling example: + + + +```python +import flet as ft +from flet.border import BorderSide +from flet.buttons import RoundedRectangleBorder + +def main(page: ft.Page): + + page.add( + ft.ElevatedButton( + "Styled button 1", + style=ft.ButtonStyle( + color={ + ft.MaterialState.HOVERED: ft.Colors.WHITE, + ft.MaterialState.FOCUSED: ft.Colors.BLUE, + ft.MaterialState.DEFAULT: ft.Colors.BLACK, + }, + bgcolor={ft.MaterialState.FOCUSED: ft.Colors.PINK_200, "": ft.Colors.YELLOW}, + padding={ft.MaterialState.HOVERED: 20}, + overlay_color=ft.Colors.TRANSPARENT, + elevation={"pressed": 0, "": 1}, + animation_duration=500, + side={ + ft.MaterialState.DEFAULT: BorderSide(1, ft.Colors.BLUE), + ft.MaterialState.HOVERED: BorderSide(2, ft.Colors.BLUE), + }, + shape={ + ft.MaterialState.HOVERED: RoundedRectangleBorder(radius=20), + ft.MaterialState.DEFAULT: RoundedRectangleBorder(radius=2), + }, + ), + ) + ) + +ft.run(main) +``` + +`ft.MaterialState.DEFAULT` state is a fallback style. + +Button shape could also be changed with `ButtonStyle.shape` property: + + + +```python +import flet as ft +from flet.buttons import ( + BeveledRectangleBorder, + CircleBorder, + ContinuousRectangleBorder, + RoundedRectangleBorder, + StadiumBorder, +) + +def main(page: ft.Page): + page.padding = 30 + page.spacing = 30 + page.add( + ft.FilledButton( + "Stadium", + style=ft.ButtonStyle( + shape=ft.StadiumBorder(), + ), + ), + ft.FilledButton( + "Rounded rectangle", + style=ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10), + ), + ), + ft.FilledButton( + "Continuous rectangle", + style=ft.ButtonStyle( + shape=ft.ContinuousRectangleBorder(radius=30), + ), + ), + ft.FilledButton( + "Beveled rectangle", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=10), + ), + ), + ft.FilledButton( + "Circle", + style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=30), + ), + ) + +ft.run(main) +``` + +Check [`ElevatedButton.style`](https://flet.dev/docs/controls/elevatedbutton/#style) property docs for a complete description of `ButtonStyle` class and its properties. + +## TextField and Dropdown styling + +It is now possible to configure text size, border style and corners radius for normal and focused states of `TextField` and `Dropdown` controls. `TextField` also allows configuring colors for a cursor and selection. + +Additionally, the maximum length of entered into `TextField` can now be limited with `max_length` property. + +We also introduced `capitalization` property for automatic capitalization of characters as you type them into `TextField`. You can choose from 4 capitalization strategies: `none` (default), `characters`, `words` and `sentences`. + +An example of styled `TextField` with `max_length` and `capitalization`: + + + +```python +import flet as ft + +def main(page: ft.Page): + page.padding = 50 + page.add( + ft.TextField( + text_size=30, + cursor_color=ft.Colors.RED, + selection_color=ft.Colors.YELLOW, + color=ft.Colors.PINK, + bgcolor=ft.Colors.BLACK26, + filled=True, + focused_color=ft.Colors.GREEN, + focused_bgcolor=ft.Colors.CYAN_200, + border_radius=30, + border_color=ft.Colors.GREEN_800, + focused_border_color=ft.Colors.GREEN_ACCENT_400, + max_length=20, + capitalization="characters", + ) + ) + +ft.run(main) +``` + +An example of styled `Dropdown` control: + + + +```python +import flet as ft + +def main(page: ft.Page): + page.padding = 50 + page.add( + ft.Dropdown( + options=[ + ft.dropdown.Option("a", "Item A"), + ft.dropdown.Option("b", "Item B"), + ft.dropdown.Option("c", "Item C"), + ], + border_radius=30, + filled=True, + border_color=ft.Colors.TRANSPARENT, + bgcolor=ft.Colors.BLACK12, + focused_bgcolor=ft.Colors.BLUE_100, + ) + ) + +ft.run(main) +``` + +## Other changes + +`IconButton` got `selected` state which plays nice with a new `style`. + +This is an example of a toggle icon button: + + + +```python +import flet as ft + +def main(page: ft.Page): + + def toggle_icon_button(e): + e.control.selected = not e.control.selected + e.control.update() + + page.add( + ft.IconButton( + icon=ft.Icons.BATTERY_1_BAR, + selected_icon=ft.Icons.BATTERY_FULL, + on_click=toggle_icon_button, + selected=False, + style=ft.ButtonStyle(color={"selected": ft.Colors.GREEN, "": ft.Colors.RED}), + ) + ) + +ft.run(main) +``` + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-08-21-fun-with-animations.md b/website/blog/2022-08-21-fun-with-animations.md new file mode 100644 index 0000000000..8ca8800ace --- /dev/null +++ b/website/blog/2022-08-21-fun-with-animations.md @@ -0,0 +1,74 @@ +--- +slug: fun-with-animations +title: Fun with animations +authors: feodor +tags: [release] +--- + +Despite Flet release debuting animations support was released some time ago, we've just finished documenting its new features! We all know if the feature is not documented it just doesn't exist! 😉 + +Flutter offers [multiple approaches](https://docs.flutter.dev/development/ui/animations) for creating animations such "implicit", "explicit", "tween", "stagered", "pre-canned" animations as well as displaying animation scenes prepared in Rive and Lottie editors. + +We are starting with "implicit" animations which allows you to animate a control property by setting a target value; whenever that target value changes, the control animates the property from the old value to the new one. + +{/* truncate */} + +## Demo time + +
+ + + +[Explore demo sources](https://github.com/flet-dev/flet-heroku-app). The demo is hosted on Heroku, by the way, so you can use it as a starting point for your own deployments. + +## Implicit animations + +Implicit animations can be enabled for the following control properties: + +* [Opacity](https://flet.dev/docs/cookbook/animations/#opacity-animation) +* [Rotation](https://flet.dev/docs/cookbook/animations/#rotation-animation) (new in this release) +* [Scale](https://flet.dev/docs/cookbook/animations/#scale-animation) (new in this release) +* [Offset](https://flet.dev/docs/cookbook/animations/#offset-animation) (new in this release) +* [Position](https://flet.dev/docs/cookbook/animations/#position-animation) + +Additionally, all `Container` control properties [can be now animated](https://flet.dev/docs/cookbook/animations/#animated-container) and there is a new [`AnimatedSwitcher`](https://flet.dev/docs/controls/animatedswitcher/) control for animated transition between old a new content. + + + +## Other new features + +### `Markdown` control + +Allows to render text in Markdown format. Supports various extensions: `CommonMark`, `GitHub Web` and `GitHub Flavored`. + +[See `Markdown` control docs](https://flet.dev/docs/controls/markdown/) for more information and examples. + +### URL launcher + +`page.launch_url(url)` method allows programmatically opening a URL in a new browser window, for example: + +```python +page.launch_url("https://google.com") +``` + +It also works nice with `Markdown` control for opening links within markdown document. + +### Keyboard shortcuts + +`Page` now contains [`on_keyboard_event`](https://flet.dev/docs/controls/page/#flet.Page.on_keyboard_event) event handlet to globally intercept all keystrokes. + +Check this [simple usage example](https://github.com/flet-dev/examples/blob/main/python/controls/page/keyboard-events.py). + +### Accessibility improvements + +We added [Accessibility](https://flet.dev/docs/cookbook/accessibility/) section to the docs covering semantics support for screen readers. + +### `ShaderMark` control + +A control that applies a mask generated by a shader to its content. Allows making nice effects like [gradually fading out images](https://flet.dev/docs/controls/shadermask/#fade-out-bottom-edge-of-an-image). + +That's it! + +[Give Flet a try](https://flet.dev/docs/) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2022-09-02-file-picker-and-uploads.md b/website/blog/2022-09-02-file-picker-and-uploads.md new file mode 100644 index 0000000000..ea8cc4627f --- /dev/null +++ b/website/blog/2022-09-02-file-picker-and-uploads.md @@ -0,0 +1,159 @@ +--- +slug: file-picker-and-uploads +title: File picker and uploads +authors: feodor +tags: [release] +--- + +Finally, File picker with uploads has arrived! 🎉 + +File picker control opens a native OS dialog for selecting files and directories. It's based on a fantastic [file_picker](https://pub.dev/packages/file_picker) Flutter package. + +It works on all platforms: Web, macOS, Window, Linux, iOS and Android. + + + +Check out [source code of the demo above](https://github.com/flet-dev/examples/blob/main/python/controls/file-picker/file-picker-all-modes.py). + +File picker allows opening three dialogs: + +* **Pick files** - one or multiple, any files or only specific types. +* **Save file** - choose directory and file name. +* **Get directory** - select directory. + +{/* truncate */} + +When running Flet app in a browser only "Pick files" option is available and it's used for uploads only as it, obviously, doesn't return a full path to a selected file. + +Where file picker really shines is a desktop! All three dialogs return full paths to selected files and directories - great assistance to your users! + +## Using file picker in your app + +It is recommended to add file picker to [`page.overlay.controls`](https://flet.dev/docs/controls/page/#flet.Page.overlay) collection, so it doesn't affect the layout of your app. Despite file picker has 0x0 size it is still considered as a control when put into `Row` or `Column`. + +```python +import flet as ft + +file_picker = ft.FilePicker() +page.overlay.append(file_picker) +page.update() +``` + +To open file picker dialog call one of the three methods: + +* `pick_files()` +* `save_file()` +* `get_directory_path()` + +Lambda works pretty nice for that: + +```python +ft.ElevatedButton("Choose files...", + on_click=lambda _: file_picker.pick_files(allow_multiple=True)) +``` + +When dialog is closed `FilePicker.on_result` event handler is called which event object has one of the following properties set: + +* `files` - "Pick files" dialog only, a list of selected files or `None` if dialog was cancelled. +* `path` - "Save file" and "Get directory" dialogs, a full path to a file or directory or `None` if dialog was cancelled. + +```python +import flet as ft + +def on_dialog_result(e: ft.FilePickerResultEvent): + print("Selected files:", e.files) + print("Selected file or directory:", e.path) + +file_picker = ft.FilePicker(on_result=on_dialog_result) +``` + +The last result is always available in `FilePicker.result` property. + +Check [File picker](https://flet.dev/docs/services/filepicker/) control docs for all available dialog methods and their parameters. + +## Uploading files + +File picker has built-in upload capabilities that work on all platforms and the web. + +To upload one or more files you should call `FilePicker.pick_files()` first. +When the files are selected by the user they are not automatically uploaded anywhere, but instead their references are kept in the file picker state. + +To perform an actual upload you should call `FilePicker.upload()` method and pass the list of files that need to be uploaded along with their upload URLs and upload method (`PUT` or `POST`): + +```python +import flet as ft + +def upload_files(e): + upload_list = [] + if file_picker.result != None and file_picker.result.files != None: + for f in file_picker.result.files: + upload_list.append( + FilePickerUploadFile( + f.name, + upload_url=page.get_upload_url(f.name, 600), + ) + ) + file_picker.upload(upload_list) + +ft.ElevatedButton("Upload", on_click=upload_files) +``` + +:::note +If you need to separate uploads for each user you can specify a filename prepended with any number of directories in `page.get_upload_url()` call, for example: + +```python +upload_url = page.get_upload_url(f"/{username}/pictures/{f.name}", 600) +``` + +`/{username}/pictures` directories will be automatically created inside `upload_dir` if not exist. +::: + +### Upload storage + +Notice the usage of `page.get_upload_url()` method - it generates a presigned upload URL for Flet's internal upload storage. + +:::note Use any storage for file uploads +You can [generate presigned upload URL](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html#generating-a-presigned-url-to-upload-a-file) for AWS S3 storage using boto3 library. + +The same technique should work for [Wasabi](https://wasabi.com/), [Backblaze](https://www.backblaze.com/), [MinIO](https://min.io/) and any other storage providers with S3-compatible API. +::: + +To enable Flet saving uploaded files to a directory provide full or relative path to that directory in `flet.app()` call: + +```python +ft.run(main, upload_dir="uploads") +``` + +You can even put uploads inside "assets" directory, so uploaded files, e.g. pictures, docs or other media, can be accessed from a Flet client right away: + +```python +ft.run(main, assets_dir="assets", upload_dir="assets/uploads") +``` + +and somewhere in your app you can display uploaded picture with: + +```python +page.add(ft.Image(src="/uploads/")) +``` + +### Upload progress + +Once `FilePicker.upload()` method is called Flet client asynchronously starts uploading selected files one-by-one and reports the progress via `FilePicker.on_upload` callback. + +Event object of `on_upload` event is an instance of `FilePickerUploadEvent` class with the following fields: + +* `file_name` +* `progress` - a value from `0.0` to `1.0`. +* `error` + +The callback is called at least twice for every uploaded file: with `0` progress before upload begins and with `1.0` progress when upload is finished. For files larger than 1 MB a progress is additionally reported for every 10% uploaded. + +Check that [example](https://github.com/flet-dev/examples/blob/main/python/controls/file-picker/file-picker-upload-progress.py) demonstrating multiple file uploads: + + + +See [File picker](https://flet.dev/docs/services/filepicker/) control docs for all its properties and examples. + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), give File Picker a try and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Enjoy! diff --git a/website/blog/2022-09-27-user-authentication.md b/website/blog/2022-09-27-user-authentication.md new file mode 100644 index 0000000000..4988c7273c --- /dev/null +++ b/website/blog/2022-09-27-user-authentication.md @@ -0,0 +1,174 @@ +--- +slug: user-authentication +title: User authentication +authors: feodor +tags: [release] +--- + +import TOCInline from '@theme/TOCInline'; + +User authentication in Flet is here! 🎉 + +Now you can implement user authentication ("Login with X" buttons) in your Flet app using 3rd-party identity providers such as GitHub, Google, Azure, Auth0, LinkedIn and others: + + + +Traditionally, this release is not just about authentication, but it adds a ton of accompanying functionality and small improvements: + + + +{/* truncate */} + +## Authentication + +Flet authentication features: + +* Works with Flet desktop, web and mobile apps. +* Using multiple authentication providers in one app. +* Built-in OAuth providers with automatic user details fetching: + * GitHub + * Azure + * Google + * Auth0 +* Optional groups fetching. +* Automatic token refresh. +* Login with a saved token ("Remember me"). +* Custom OAuth providers. + +A simple example on how to add "Login with GitHub" button to your Flet app: + +```python +import os + +import flet as ft +from flet.auth.providers.github_oauth_provider import GitHubOAuthProvider + +def main(page: ft.Page): + + provider = GitHubOAuthProvider( + client_id=os.getenv("GITHUB_CLIENT_ID"), + client_secret=os.getenv("GITHUB_CLIENT_SECRET"), + redirect_url="http://localhost:8550/api/oauth/redirect", + ) + + def login_click(e): + page.login(provider) + + def on_login(e): + print("Access token:", page.auth.token.access_token) + print("User ID:", page.auth.user.id) + + page.on_login = on_login + page.add(ft.ElevatedButton("Login with GitHub", on_click=login_click)) + +ft.run(main, port=8550, view=ft.AppView.WEB_BROWSER) +``` + +:::note +Before running the app set the secret environment variables in a command line: + +``` +$ export GITHUB_CLIENT_ID="" +$ export GITHUB_CLIENT_SECRET="" +``` +::: + +[Read Authentication guide for more information and examples](https://flet.dev/docs/cookbook/authentication/). + +## Client storage + +Flet's client storage API that allows storing key-value data on a client side in a persistent storage. Flet implementation uses [`shared_preferences`](https://pub.dev/packages/shared_preferences) Flutter package. + +Writing data to the storage: + +```python +page.client_storage.set("key", "value") +``` + +Reading data: + +```python +value = page.client_storage.get("key") +``` + +[Read Client storage guide for more information and examples](https://flet.dev/docs/cookbook/client-storage/). + +## Session storage + +Flet introduces an API for storing key-value data in user's session on a server side. + +Writing data to the session: + +```python +page.session.set("key", "value") +``` + +Reading data: + +```python +value = page.session.get("key") +``` + +[Read Session storage guide for more information and examples](https://flet.dev/docs/cookbook/session-storage/) + +## Encryption API + +In this release Flet introduces utility methods to encrypt and decrypt sensitive text data using symmetric algorithm (where the same key is used for encryption and decryption). It uses [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) implementation from [cryptography](https://pypi.org/project/cryptography/) package, which is AES 128 with some additional hardening, plus PBKDF2 to derive encryption key from a user passphrase. + +Encrypting data: + +```python +from flet.security import encrypt, decrypt +secret_key = "S3CreT!" +plain_text = "This is a secret message!" +encrypted_data = encrypt(plain_text, secret_key) +``` + +Decrypting data: + +```python +from flet.security import encrypt, decrypt +secret_key = "S3CreT!" +plain_text = decrypt(encrypted_data, secret_key) +print(plain_text) +``` + +[Continue reading for more information and examples](https://flet.dev/docs/cookbook/encrypting-sensitive-data/). + +## Other improvements + +* SVG image support ([example](https://github.com/flet-dev/examples/blob/main/python/controls/image/svg-image.py)) and new images properties: + * [`Image.color`](https://flet.dev/docs/controls/image/#flet.Image.color) + * [`Image.color_blend_mode`](https://flet.dev/docs/controls/image/#flet.Image.color_blend_mode) + * [`Image.semantics_label`](https://flet.dev/docs/controls/image/#flet.Image.semantics_label) + * [`Image.gapless_playback`](https://flet.dev/docs/controls/image/#flet.Image.gapless_playback) +* [`on_animation_end` callback](https://flet.dev/docs/cookbook/animations/#animation-end-callback) to chain animations. +* [`Container.clip_behavior` property](https://flet.dev/docs/controls/container/#flet.Container.clip_behavior). +* [`page.window.bgcolor`](https://flet.dev/docs/types/window/#flet.Window.bgcolor) to make cool transparent app window: + +```python +import flet as ft +def main(page: ft.Page): + page.window_bgcolor = ft.Colors.TRANSPARENT + page.bgcolor=ft.Colors.TRANSPARENT + page.window_title_bar_hidden = True + page.window_frameless = True + page.window_left = 400 + page.window_top = 400 + page.add(ft.ElevatedButton("I'm a floating button!")) +ft.run(main) +``` + +* [`page.get_clipboard()`](https://flet.dev/docs/controls/page/#flet.Page.get_clipboard) +* [`page.launch_url()`](https://flet.dev/docs/controls/page/#flet.Page.launch_url) - better control with additional arguments: + * `web_window_name` - window tab/name to open URL in: `_self` - the same tab, `_blank` - a new tab or `` - a named tab. + * `web_popup_window` - set to `True` to display a URL in a browser popup window. Default is `False`. + * `window_width` - optional, popup window width. + * `window_height` - optional, popup window height. +* [`page.window.to_front()`](https://flet.dev/docs/types/window/#flet.Window.to_front) +* [`page.close_in_app_web_view()`](https://flet.dev/docs/controls/page/#flet.Page.close_in_app_web_view) + + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), integrate auth in your app and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Enjoy! diff --git a/website/blog/2022-10-11-gesture-detector.md b/website/blog/2022-10-11-gesture-detector.md new file mode 100644 index 0000000000..a4ee64b9d3 --- /dev/null +++ b/website/blog/2022-10-11-gesture-detector.md @@ -0,0 +1,46 @@ +--- +slug: gesture-detector +title: Gesture detector +authors: feodor +tags: [release] +--- + +We've just released [Flet 0.1.62](https://pypi.org/project/flet/0.1.62/) with support of gestures processing! + +There is a new control - [GestureDetector](https://flet.dev/docs/controls/gesturedetector/) which allows handling all sorts of gestures: single and double taps with a left (primary) and right (secondary) mouse (pointer) buttons, vertical, horizontal and bi-directional drags, zoom (pinch-in and pinch-out) gestures as well as hover events. Now, by wrapping it into `GestureDetector`, you can make any Flet control "clickable" and "draggable"! + +Here is a simple example of an app which allows you to drag containers inside a Stack: + + + +{/* truncate */} + +```python +import flet as ft + +def main(page: ft.Page): + def on_pan_update(e: ft.DragUpdateEvent): + e.control.top = max(0, e.control.top + e.delta_y) + e.control.left = max(0, e.control.left + e.delta_x) + e.control.update() + + gd = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + on_vertical_drag_update=on_pan_update, + left=100, + top=100, + content=ft.Container(bgcolor=ft.Colors.BLUE, width=50, height=50, border_radius=5), + ) + + page.add( ft.Stack([gd], expand=True)) + +ft.run(main) +``` + +Gesture detector is yet another great addition to a collection of Flet primitives that allows you to build apps limited only by your imagination. 2D drawing coming later this month is going to complete that ensemble! + +That release wasn't about only gestures though - that was a "stabilization" release too. We fixed a number of bugs and added a bunch of other small features which you can [see here](https://github.com/flet-dev/flet/issues?q=is%3Aissue+milestone%3AControls-S2+is%3Aclosed). + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), integrate auth in your app and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Enjoy! diff --git a/website/blog/2022-10-24-matplotlib-and-plotly-charts.md b/website/blog/2022-10-24-matplotlib-and-plotly-charts.md new file mode 100644 index 0000000000..6703f5825f --- /dev/null +++ b/website/blog/2022-10-24-matplotlib-and-plotly-charts.md @@ -0,0 +1,48 @@ +--- +slug: matplotlib-and-plotly-charts +title: Matplotlib and Plotly charts +authors: feodor +tags: [release] +--- + +We are thrilled to introduce Matplotlib and Plotly charting controls in [Flet 0.1.63](https://pypi.org/project/flet/0.1.63/)! + +[Matplotlib](https://matplotlib.org/) and [Plotly](https://plotly.com/python/) are the most recognized Python charting libraries with a ton of features. They are greatly compatible with other scientific Python libraries such as Numpy or Pandas. + +No doubt, it would be nearly impossible to replicate their functionality as pure Flutter widgets. Fortunately, both Matplotlib and Plotly can export charts into various formats, such as SVG. On the other hand Flet can [display SVG images](https://github.com/flet-dev/examples/blob/main/python/controls/image/svg-image.py) and that gives a perfect combination - Flet charting controls for Matplotlib and Plotly! + +The resulting solution works so great that it's possible to display almost any example from [Matplotlib](https://matplotlib.org/stable/gallery/index.html) and [Plotly](https://plotly.com/python/) galleries - your imagination is the only limit! + +Plot a [simple bar chart](https://github.com/flet-dev/examples/blob/main/python/controls/charts/mpl-barchart.py): + + + +a nice [scatter with legend](https://github.com/flet-dev/examples/blob/main/python/controls/charts/mpl-scatter.py): + + + +or some multi-chart [contour plot](https://github.com/flet-dev/examples/blob/main/python/controls/charts/mpl-contour.py): + + + +Check the docs for Matplotlib and Plotly charting controls: + +* [MatplotlibChart](https://flet.dev/docs/charts/matplotlib_chart/) +* [PlotlyChart](https://flet.dev/docs/charts/plotly_chart/) + +Explore [Flet chart examples](https://github.com/flet-dev/examples/tree/main/python/controls/charts). + +{/* truncate */} + +Learn Python libraries by examples: + +* [Matplotlib gallery](https://matplotlib.org/stable/gallery/index.html) +* [Plotly gallery](https://plotly.com/python/) + +In the future releases, we may add an interactive "toolbar" for Matplotlib charts by implementing a custom [backend](https://matplotlib.org/stable/users/explain/backends.html). Or maybe it's a great exercise for Flet users? 😉 + +Also, when it's time for Flet to support other languages we would need to re-visit charting to make it language-agnostic as the current charting implementation relies on Python libraries. + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), integrate auth in your app and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Enjoy! diff --git a/website/blog/2022-11-13-responsive-row-and-mobile-controls.md b/website/blog/2022-11-13-responsive-row-and-mobile-controls.md new file mode 100644 index 0000000000..40df5d8da6 --- /dev/null +++ b/website/blog/2022-11-13-responsive-row-and-mobile-controls.md @@ -0,0 +1,174 @@ +--- +slug: responsive-row-and-mobile-controls +title: ResponsiveRow and mobile controls +authors: feodor +tags: [release] +--- + +We just released [Flet 0.1.65](https://pypi.org/project/flet/0.1.65/) which is adding a bunch of mobile-optimized controls, fixing some bugs and introducing a new layout control - `ResponsiveRow`. + +## `ResponsiveRow` control + +`ResponsiveRow` borrows the idea of grid layout from [Bootstrap](https://getbootstrap.com/docs/5.2/layout/grid/) web framework. + +`ResponsiveRow` allows aligning child controls to virtual columns. By default, a virtual grid has 12 columns, but that can be customized with `ResponsiveRow.columns` property. + +Similar to `expand` property every control now has `col` property which allows specifying how many columns a control should span. For example, to make a layout consisting of two columns spanning 6 virtual columns each: + +```python +import flet as ft + +ft.ResponsiveRow([ + ft.Column(col=6, controls=ft.Text("Column 1")), + ft.Column(col=6, controls=ft.Text("Column 2")) +]) +``` + +{/* truncate */} + +`ResponsiveRow` is "responsive" because it can adapt the size of its children to a changing screen (page, window) size. `col` property in the example above is a constant number which means the child will span 6 columns for any screen size. + +If `ResponsiveRow`'s child doesn't have `col` property specified it spans the maximum number of columns. + +`col` can be configured to have a different value for specific "breakpoints". Breakpoints are named dimension ranges: + +| Breakpoint | Dimension | +|---|---| +| xs | \<576px | +| sm | ≥576px | +| md | ≥768px | +| lg | ≥992px | +| xl | ≥1200px | +| xxl | ≥1400px | + +For example, the following example collapses content into a single column on a mobile device and takes two columns on larger screens: + +```python +import flet as ft + +ft.ResponsiveRow([ + ft.Column(col={"sm": 6}, controls=ft.Text("Column 1")), + ft.Column(col={"sm": 6}, controls=ft.Text("Column 2")) +]) +``` + +Here is more elaborate example of responsive layout: + + + +```python +import flet as ft + +def main(page: ft.Page): + def page_resize(e): + pw.value = f"{page.width} px" + pw.update() + + page.on_resize = page_resize + + pw = ft.Text(bottom=50, right=50, style="displaySmall") + page.overlay.append(pw) + page.add( + ft.ResponsiveRow( + [ + ft.Container( + ft.Text("Column 1"), + padding=5, + bgcolor=ft.Colors.YELLOW, + col={"sm": 6, "md": 4, "xl": 2}, + ), + ft.Container( + ft.Text("Column 2"), + padding=5, + bgcolor=ft.Colors.GREEN, + col={"sm": 6, "md": 4, "xl": 2}, + ), + ft.Container( + ft.Text("Column 3"), + padding=5, + bgcolor=ft.Colors.BLUE, + col={"sm": 6, "md": 4, "xl": 2}, + ), + ft.Container( + ft.Text("Column 4"), + padding=5, + bgcolor=ft.Colors.PINK_300, + col={"sm": 6, "md": 4, "xl": 2}, + ), + ], + ), + ft.ResponsiveRow( + [ + ft.TextField(label="TextField 1", col={"md": 4}), + ft.TextField(label="TextField 2", col={"md": 4}), + ft.TextField(label="TextField 3", col={"md": 4}), + ], + run_spacing={"xs": 10}, + ), + ) + page_resize(None) + +ft.run(main) +``` + +`ResponsiveRow` [docs](https://flet.dev/docs/controls/responsiverow/), [example](https://github.com/flet-dev/examples/blob/main/python/controls/responsive-row/responsive-layout.py). + +## Other new controls + +This release adds new visual and non-visual controls requested by Flet community and also required to build UI of the upcoming [Flet Studio](https://flet.dev/docs/getting-started/testing-on-mobile/). + +### BottomSheet + +Shows a modal Material Design bottom sheet: + + + +`BottomSheet` [docs](https://flet.dev/docs/controls/bottomsheet/), [example](https://github.com/flet-dev/examples/blob/main/python/controls/bottom-sheet/modal-bottom-sheet.py). + +### NavigationBar + +Bottom Navigation bar which offers a persistent and convenient way to switch between primary destinations in an app: + + + +`NavigationBar` [docs](https://flet.dev/docs/controls/navigationbar/), [example](https://github.com/flet-dev/examples/blob/main/python/controls/navigation-bar/navigation-bar-sample.py). + +### Tooltip + +A tooltip control: + + + +`Tooltip` [docs](https://flet.dev/docs/types/tooltip/), [example](https://github.com/flet-dev/examples/blob/main/python/controls/tooltip/custom-tooltip.py). + +### HapticFeedback + +Allows access to the haptic feedback (clicks and vibrates) interface on the device. + +`HapticFeedback` [docs](https://flet.dev/docs/services/hapticfeedback/). + +### ShakeDetector + +A control to detect phone shakes. Based on [shake](https://pub.dev/packages/shake) widget. + +`ShakeDetector` [docs](https://flet.dev/docs/services/shakedetector/). + +## Other improvements + +### Markdown code syntax highlight + +[Sample code](https://github.com/flet-dev/examples/blob/main/python/controls/markdown/markdown-code-highlight.py). + + + +### Variable fonts support + +Flutter has finally supported [variable fonts](https://fonts.google.com/knowledge/introducing_type/introducing_variable_fonts) and we bring that into Flet too! + +[Sample code](https://github.com/flet-dev/examples/blob/main/python/controls/text/variable-weight-font.py). + + + +Upgrade Flet module to the latest version (`pip install flet --upgrade`) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Enjoy! diff --git a/website/blog/2022-11-16-flet-versioning-and-pre-releases.md b/website/blog/2022-11-16-flet-versioning-and-pre-releases.md new file mode 100644 index 0000000000..cfec3e008d --- /dev/null +++ b/website/blog/2022-11-16-flet-versioning-and-pre-releases.md @@ -0,0 +1,40 @@ +--- +slug: flet-versioning-and-pre-releases +title: Flet versioning and pre-releases +authors: feodor +tags: [news] +--- + +Flet is a fast-evolving framework with a new functionality and bug fixes being committed every other day. + +The development model with one pull request per release didn't work well for the project as users waited for weeks to get hands on a new release and, honestly, from development perspective producing large "heroic" releases takes a lot of energy 🫠. + +From now on we'll be breaking releases into multiple pull requests with one feature/bugfix per PR. + +Every PR merged into `main` branch will be publishing pre-release (developmental release) package to [pypi.org](https://pypi.org/project/flet/) having version format of `X.Y.Z.devN`. + +{/* truncate */} + +## Installing pre-releases + +To install Flet pre-release package use the following command: + +``` +pip install flet --pre +``` + +:::info +We recommend installing pre-release builds into a virtual environment. +::: + +## Flet versioning + +Flet is switching to [Semanting Versioning](https://semver.org/) with a version number `MAJOR.MINOR.PATCH`: + +1. `MAJOR` will be incremented when there are "incompatible API changes". Right now it's `0` and we expect to make it `1` when we feel that Flet API is stable enough. +2. `MINOR` will be incremented when a new functionality added in a backwards compatible manner. +3. `PATCH` will be incremented when we make backward compatible bug fixes. + +According to that rule, upcoming Flet release will have version `0.2.0`. Bug fixes for that release will be labeled as `0.2.1`, `0.2.2`, etc. The release after that release will be `0.3.0` and so on. + +Flet pre-releases will have a format of `MAJOR.{LAST_MINOR + 1}.0.dev{BUILD}` where `LAST_MINOR` is `MINOR` version of the last release and `{BUILD}` is a build number set by [CI](https://ci.appveyor.com/project/flet-dev/flet). For example, if the last published release is `0.1.65` pre-releases will have versions `0.2.0.dev{BUILD}`. Pre-releases after `0.2.0` release will be labeled as `0.3.0.dev{BUILD}`. diff --git a/website/blog/2022-12-08-flet-mobile-update.md b/website/blog/2022-12-08-flet-mobile-update.md new file mode 100644 index 0000000000..357aedd173 --- /dev/null +++ b/website/blog/2022-12-08-flet-mobile-update.md @@ -0,0 +1,81 @@ +--- +slug: flet-mobile-update +title: Flet mobile update +authors: feodor +tags: [news] +--- + +This post is a continuation of [Flet mobile strategy](/blog/flet-mobile-strategy) published a few months ago. + +Our original approach to Flet running on a mobile device was Server-Driven UI. Though SDUI has its own benefits (like bypassing App Store for app updates) it doesn't work in all cases, requires web server to host Python part of the app and, as a result, adds latency which is not great for user actions requiring nearly instance UI response, like drawing apps. + +I've been thinking on how to make Python runtime embedded into Flutter iOS or Android app to run user Python program. No doubt, it's technically possible as Kivy and BeeWare projects do that already. + +{/* truncate */} + +## Current Flet architecture + +The current architecture of Flet desktop app is shown on the diagram below: + + + +Running Flet program on a desktop involves three applications (processes) working together: + +* **Python runtime** (`python3`) - Python interpreter running your Python script. This is what you are starting from a command line. Python starts Fletd server and connects to it via WebSockets. +* **Fletd server** (`fletd`)- Flet web server written in Go, listening on a TCP port. Fletd holds the state of all user sessions (for desktop app there is only one session) and dispatches page updates and user generated events between Python program and Flet client. +* **Flet client** (`flet`) - desktop app written in Flutter and displaying UI in a native OS window. Flet client connects to Fletd server via WebSockets. + +The architecture above works well for Flet web apps where web server is essential part, but for desktop it seems redundant: + +* If all three processes run on the same computer WebSockets could be replaced with sockets or named pipes with less overhead. +* Fletd server has no much sense as there is only one user session and UI state is persistently stored in Flet desktop client which is never "reloaded". + +## Flet new desktop architecture + +Flet desktop app architecture can be simplified by replacing Fletd with a "stub" written in Python and communicating with Flet desktop client via sockets (Windows) and named pipes (macOS and Linux): + + + +## Flet mobile architecture + +Mobile applications are running in a very strict context with a number of limitations. For example, on iOS the app cannot spawn a new processes. Other words, Flet Flutter app cannot just start "python.exe" and pass your script as an argument. + +Luckily for us, [Python can be embedded](https://docs.python.org/3/extending/embedding.html) into another app as a C library and Dart (the language in which Flutter apps are written) allows calling C libraries via [FFI](https://dart.dev/guides/libraries/c-interop) (Foreign Function Interface). + +Additionally, while Android allows loading of dynamically linked libraries iOS requires all libraries statically linked into app executable. [This article](https://blog.logrocket.com/dart-ffi-native-libraries-flutter/) covers Dart FFI in more details, if you are curious. + +Flet mobile architecture could look like this: + + + +Python runtime will be statically or dynamically linked with Flutter client app and called via FFI and/or named pipes. + +Running Python on mobile will have some limitations though. Most notable one is the requirement to use "pure" Python modules or modules with native code compiled specifically for mobile ARM64 architecture. + +## Asyncio support + +[Asyncio](https://docs.python.org/3/library/asyncio.html) is part of Python 3 and we start seeing more and more libraries catching up with async/await programming model which is more effective for I/O-bound and UI logic. + +Currently, Flet is spawning all UI event handlers in new threads and it's also a pain to see `threading.sleep()` calls hogging threads here and there just to do some UI animation. All that looks expensive. + +Using of async libraries from a sync code is [possible](https://github.com/flet-dev/flet/issues/128), but looks hacky and inefficient as it keeps CPU busy just to wait async method to finish. So, we want a first-class support of async code in Flet app. + +Async/await model is a state machine switching between tasks in a single thread. By going async Flet will able to utilize [streams](https://docs.python.org/3/library/asyncio-stream.html) for socket server and use async [WebSockets library](https://pypi.org/project/websockets/) library. It will be possible to use both sync and async event handlers in a single Flet app without any compromises or hacks. + +Even more exciting, async Flet will be able to run entirely in the browser within [Pyodide](https://pyodide.org/) - Python distribution based on WebAssembly (WASM). WebAssembly doesn't have multi-threading support yet, so running in a single thread is a must. Just imagine, Flet web app with a truly offline Flet PWA that does not require a web server to run a Python code! + +## Development plan + +We are going to crunch the scope above in a few iterations: + +1. Async API support with async WebSockets library. Works with the same Fletd in Go. +2. Fletd server ("stub") in Python to use with a desktop. +3. Embedding Python with Fletd "stub" and user program into iOS. +4. Embedding Python into Android. +5. Packaging mobile apps for iOS and Android. + +:::caution HELP WANTED +🙏 I'm looking for a help from the community with developing C/C++/native code integration part between Flutter and Python on iOS and Android. It could be either free help or a paid job - let me know if you are interested! +::: + +Hop to [Discord](https://discord.gg/dzWXP8SHG8) to discuss the plan, offer help, ask questions! diff --git a/website/blog/2023-01-04-packaging-desktop-apps-with-custom-icon.md b/website/blog/2023-01-04-packaging-desktop-apps-with-custom-icon.md new file mode 100644 index 0000000000..46a2fa8784 --- /dev/null +++ b/website/blog/2023-01-04-packaging-desktop-apps-with-custom-icon.md @@ -0,0 +1,26 @@ +--- +slug: packaging-desktop-apps-with-custom-icon +title: Packaging desktop apps with a custom icon +authors: feodor +tags: [releases] +--- + +Happy New Year! [Flet project](https://github.com/flet-dev/flet) has reached ⭐️ 3.3K stars ⭐️ on GitHub which is very exciting and encouraging! Thank you all for your support! + +We are starting this year with the release of [Flet 0.3.2](https://pypi.org/project/flet/) bringing a long-awaited feature: creating standalone desktop bundles with a custom icon! + +`flet` command has been used for running Flet program with [hot reload](https://flet.dev/docs/cli/flet-run/), but we recently re-worked Flet CLI to support multiple actions. + +There is a new `flet pack` command that wraps [PyInstaller](https://github.com/pyinstaller/pyinstaller) API to package your Flet Python app into a standalone Windows executable or macOS app bundle which can be run by a user with no Python installed. + +Command's `--icon` argument is now changing not only executable's icon, but Flet's app window icon and the icon shown in macOS dock, Windows taskbar, macOS "About" dialog, Task Manager and Activity Monitor: + + + +Bundle name, version and copyright can be changed too: + + + +Find all available options for packaging desktop apps in the [updated guide](https://flet.dev/docs/publish/). + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), give `flet pack` command a try and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2023-02-06-standalone-flet-web-apps-with-pyodide.md b/website/blog/2023-02-06-standalone-flet-web-apps-with-pyodide.md new file mode 100644 index 0000000000..cc511b5928 --- /dev/null +++ b/website/blog/2023-02-06-standalone-flet-web-apps-with-pyodide.md @@ -0,0 +1,155 @@ +--- +slug: standalone-flet-web-apps-with-pyodide +title: Standalone Flet web apps with Pyodide +authors: feodor +tags: [releases] +--- + +import Card from '@site/src/components/card'; + +We've just released [Flet 0.4.0](https://pypi.org/project/flet/) with a super exciting new feature - [packaging Flet apps into a standalone static website](https://flet.dev/docs/publish/web/static-website/) that can be run entirely in the browser! The app can be published to any free hosting for static websites such as GitHub Pages or Cloudflare Pages. Thanks to [Pyodide](https://pyodide.org/en/stable/) - a Python port to WebAssembly! + + + +You can quickly build awesome single-page applications (SPA) entirely in Python and host them everywhere! No HTML, CSS or JavaScript required! + +{/* truncate */} + +## Quick Flet with Pyodide demo + +Install the latest Flet package: + +``` +pip install flet --upgrade +``` + +Create a simple `counter.py` app: + +```python title="counter.py" +import flet as ft + +def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + page.update() + + page.add( + ft.Row( + [ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + txt_number, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + ) + +ft.run(main) +``` + +Run a brand-new `flet publish` command to publish Flet app as a static website: + +``` +flet publish counter.py +``` + +The website will be published to `dist` directory next to `counter.py`. +Give website a try using built-in Python web server: + +``` +python -m http.server --directory dist +``` + +Open `http://localhost:8000` in your browser to check the published app. + + + +Here are a few live Flet apps hosted at Cloudflare Pages: + +export const ImageCard = ({title, href, imageUrl}) => ( +
+ + +

{title}

+
+
+); + +
+
+ + + + + +
+
+ +[Check the guide](https://flet.dev/docs/publish/web/static-website/) for more information about publishing Flet apps as standalone websites. + +## Built-in Fletd server in Python + +Flet 0.4.0 also implements a [new Flet desktop architecture](https://flet.dev/blog/flet-mobile-update#flet-new-desktop-architecture). + +It replaces Fletd server written in Go with a light-weight shim written in Python with a number of pros: + +1. Only 2 system processes are needed to run Flet app: Python interpreter and Flutter client. +2. Less communication overhead (minus two network hops between Python and Fletd) and lower latency (shim uses TCP on Windows and Unix domain sockets on macOS/Linux). +3. Shim binds to `127.0.0.1` on Windows by default which is more secure. +4. The size of a standalone app bundle produced by `flet pack` reduced by ~8 MB. + +The implementation was also required to support Pyodide (we can't run Go web server in the browser, right?) and paves the way to iOS and Android support. + +### Other changes + +* All controls loading resources from web URLs (`Image.src`, `Audio.src`, `Page.fonts`, `Container.image_src`) are now able to load them from local files too, by providing a full path in the file system, and from `assets` directory by providing relative path. For desktop apps a path in `src` property could be one of the following: + * A path relative to `assets` directory, with or without starting slash, for example: `/image.png` or `image.png`. The name of artifact dir should not be included. + * An absolute path within a computer file system, e.g. `C:\projects\app\assets\image.png` or `/Users/john/images/picture.png`. + * A full URL, e.g. `https://mysite.com/images/pic.png`. + * Add `page.on_error = lambda e: print("Page error:", e.data)` to see failing images. +* `flet` Python package has separated into two packages: `flet-core` and `flet`. +* PDM replaced with Poetry. +* `beartype` removed everywhere. + +### 💥 Breaking changes + +* Default routing scheme changed from "hash" to "path" (no `/#/` at the end of app URL). Use `ft.run(main, route_url_strategy="hash")` to get original behavior. +* OAuth authentication is not supported anymore in standalone desktop Flet apps. + +## Async support + +Flet apps can now be written as async apps and use `asyncio` with other Python async libraries. Calling coroutines is naturally supported in Flet, so you don't need to wrap them to run synchronously. + +To start with an async Flet app you should make `main()` method `async`: + +```python +import flet as ft + +async def main(page: ft.Page): + await page.add_async(ft.Text("Hello, async world!")) + +ft.run(main) +``` + +[Read the guide](https://flet.dev/docs/cookbook/async-apps/) for more information about writing async Flet apps. + +## Conclusion + +Flet 0.4.0 brings the following exciting features: + +- Standalone web apps with Pyodide running in the browser and hosted on a cheap hosting. +- Faster and more secure architecture with a built-in Fletd server. +- Async apps support. + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), give `flet publish` command a try and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Hey, by the way, [Flet project](https://github.com/flet-dev/flet) has reached ⭐️ 4.2K stars ⭐️ (+1K in just one month) - keep going! diff --git a/website/blog/2023-04-12-flet-charts.md b/website/blog/2023-04-12-flet-charts.md new file mode 100644 index 0000000000..ce97185586 --- /dev/null +++ b/website/blog/2023-04-12-flet-charts.md @@ -0,0 +1,50 @@ +--- +slug: flet-charts +title: Flet Charts +authors: feodor +tags: [releases] +--- + +Last year we introduced support for [Matplotlib and Plotly charts](/blog/matplotlib-and-plotly-charts). Both libraries are able to export charts as SVG images which are then displayed in a Flet app. However, such charts, while serving the purpose of visualization, are lacking interactivity and animation. + +Today we are releasing [Flet 0.5.2](https://pypi.org/project/flet/) with built-in charts 📊 based on the awesome [fl_chart](https://pub.dev/packages/fl_chart) library! + +{/* truncate */} + +Three new chart controls have been introduced: + +## LineChart + + + +[Docs](https://flet.dev/docs/charts/line_chart/) · [Examples](https://github.com/flet-dev/examples/tree/main/python/controls/charts) + +## BarChart + + + +[Docs](https://flet.dev/docs/charts/bar_chart/) · [Examples](https://github.com/flet-dev/examples/tree/main/python/controls/charts) + +## PieChart + + + +[Docs](https://flet.dev/docs/charts/pie_chart/) · [Examples](https://github.com/flet-dev/examples/tree/main/python/controls/charts) + +:::note +We spent a lot of time studying `fl_chart` library while trying to implement most of its features in a Flet way. However, if you see anything missing in Flet, but available in a library please [submit a new feature request](https://github.com/flet-dev/flet/issues). +::: + +## Other changes + +### Pyodide 0.23 + +Pyodide, which provides Python runtime in a browser and is used to run Flet app as a static website, was upgraded to version 0.23 which is based on Python 3.11.2 and giving some [size and performance improvements](https://blog.pyodide.org/posts/0.23-release/). + +### Memory leak fixes + +In this release we paid a lot of attention to memory leak issues in Flet apps. Now, when a user session is closed its memory is reliably released and garbage-collected. That makes Flet ready for production applications with a lot of users. + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), give charts a try and [let us know](https://discord.gg/dzWXP8SHG8) what you think! + +Hey, [Flet project](https://github.com/flet-dev/flet) has reached ⭐️ 5K stars ⭐️ - thank you all for your continuing support! diff --git a/website/blog/2023-04-26-canvas.md b/website/blog/2023-04-26-canvas.md new file mode 100644 index 0000000000..d34568ab8e --- /dev/null +++ b/website/blog/2023-04-26-canvas.md @@ -0,0 +1,115 @@ +--- +slug: canvas +title: Canvas +authors: feodor +tags: [releases] +--- + +Unleash your inner artist 🧑‍🎨 and boost your Flet creativity with brand-new [Canvas](https://flet.dev/docs/controls/canvas/) control just released in [Flet 0.6.0](https://pypi.org/project/flet/)! + +Canvas enables you to draw arbitrary graphics using a set of primitives, or "shapes", such as line, circle, arc, path and text. I bet you can even implement your own version of [charts](/blog/flet-charts) using Canvas control! + +Combine Canvas with [GestureDetector](https://flet.dev/docs/controls/gesturedetector/) and you get a free-hand drawing app - Flet Brush 😀! + + + +[Example source](https://github.com/flet-dev/examples/blob/main/python/controls/canvas/canvas-flet-brush.py) + +{/* truncate */} + +`Canvas` control is located in `flet.canvas` package. You need another import to use it: + +```python +import flet.canvas as cv +``` + +Here's a simple program drawing a smiley face with [`Circle`](https://flet.dev/docs/controls/canvas/circle/) and [`Arc`](https://flet.dev/docs/controls/canvas/arc/) shapes using filled and stroke [`Paint`](https://flet.dev/docs/types/paint/): + +```python +import math +import flet as ft +import flet.canvas as cv + +def main(page: ft.Page): + stroke_paint = paint = ft.Paint(stroke_width=2, style=ft.PaintingStyle.STROKE) + fill_paint = paint = ft.Paint(style=ft.PaintingStyle.FILL) + cp = cv.Canvas( + [ + cv.Circle(100, 100, 50, stroke_paint), + cv.Circle(80, 90, 10, stroke_paint), + cv.Circle(84, 87, 5, fill_paint), + cv.Circle(120, 90, 10, stroke_paint), + cv.Circle(124, 87, 5, fill_paint), + cv.Arc(70, 95, 60, 40, 0, math.pi, paint=stroke_paint), + ], + width=float("inf"), + expand=True, + ) + + page.add(cp) + +ft.run(main) +``` + + + +Read more about Canvas in [docs](https://flet.dev/docs/controls/canvas/) and explore [Canvas examples](https://github.com/flet-dev/examples/tree/main/python/controls/canvas)! + +## Other changes + +### Rich text support + +While working on [drawing text on Canvas](https://flet.dev/docs/controls/canvas/text/), as a bonus to this release, we implemented a new [`TextSpan`](https://flet.dev/docs/types/textspan/) control which can now be used with [`Text.spans`](https://flet.dev/docs/controls/text/#flet.Text.spans) to output rich text. + + + +Check rich text examples: [one](https://flet.dev/docs/controls/text/#basic-rich-text-example), [two](https://flet.dev/docs/controls/text/#rich-text-with-borders-and-stroke) and [three](https://flet.dev/docs/controls/text/#rich-text-with-gradient). + +### `url` property for buttons + +If you need to open a URL by clicking on a button or any other control with `on_click` event you can just provide that URL in `url` instead of doing that in the code with [`page.launch_url()`](https://flet.dev/docs/controls/page/#flet.Page.launch_url) method. + +Instead of that: + +```python +ft.ElevatedButton("Go to Google", on_click=lambda e: e.page.launch_url("https://google.com")) +``` + +you can just do this: + +```python +ft.ElevatedButton("Go to Google", url="https://google.com") +``` + +A new `url` property also solves [blocked window on Safari](https://github.com/flet-dev/flet/issues/1105) issue. + +### Auto-follow links in `Markdown` + +As a continuation of `url` property `Markdown` control can now be enabled to auto-follow URLs in the document: + +```python +import flet as ft + +md = """ +[Go to Google](https://www.google.com) +""" + +def main(page: ft.Page): + page.add( + ft.Markdown( + md, + extension_set=ft.MarkdownExtensionSet.GITHUB_WEB, + auto_follow_links=True, + ) + ) + +ft.run(main) +``` + +### Better web support + +In this release we also did some improvements to web support like [capturing user info in `page.client_id` and `page.client_user_agent`](https://github.com/flet-dev/flet/pull/1302) as well as fixing nasty [#1333](https://github.com/flet-dev/flet/pull/1333) and [#1289](https://github.com/flet-dev/flet/pull/1289) bugs related to routing. + +That's all for today! + +Upgrade Flet module to the latest version (`pip install flet --upgrade`), give canvas and rich text a try and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2023-05-12-theming-and-scrollables.md b/website/blog/2023-05-12-theming-and-scrollables.md new file mode 100644 index 0000000000..a892f2abed --- /dev/null +++ b/website/blog/2023-05-12-theming-and-scrollables.md @@ -0,0 +1,235 @@ +--- +slug: scrolling-controls-and-theming +title: Scrolling controls and Theming +authors: feodor +tags: [releases] +--- + +Flet 0.7.1 enables developers [changing scroll position](#controlling-scroll-position) and [receiving scroll notifications](#receiving-scroll-notifications) from `Page`, `View`, `Column`, `Row`, `ListView` and `GridView` controls. + +The release also introduces theming improvements: +* [Color scheme customization](#color-scheme-customization) +* [Nested themes](#nested-themes) +* [Text theming](#text-theming) +* [Scrollbar theming](#scrollbar-theme) +* [Tabs theming](#tabs-theming) + +{/* truncate */} + +## Controlling scroll position + +Scrollable controls (`Page`, `View`, `Column`, `Row`, `ListView` and `GridView`) introduce `scroll_to()` method to change their scroll position to either absolute `offset`, relative `delta` or jump to the control with specified `key`. + +Moving to a `key` is particularly exciting as it allows simulating the navigation between page bookmarks, kind of HTML hrefs with `#`: + + + +Check the [source code](https://github.com/flet-dev/examples/blob/main/python/controls/column/column-scroll-to-key.py) of the example above. + +See [`Column.scroll_to`](https://flet.dev/docs/controls/column/#flet.Column.scroll_to) for more details about controlling scroll position. + +## Receiving scroll notifications + +All scrollable controls now provide `on_scroll` event handler which fires when a scroll position is changed. From event object properties you can determine whether scroll operation has started, finished, changed direction or scroll position went behind scrolling extent (overscroll). You can also get updates of the current scroll position as well as dimensions of the scroll area, for example: + +```python +import flet as ft + +def main(page: ft.Page): + def on_column_scroll(e: ft.OnScrollEvent): + print( + f"Type: {e.event_type}, pixels: {e.pixels}, min_scroll_extent: {e.min_scroll_extent}, max_scroll_extent: {e.max_scroll_extent}" + ) + + cl = ft.Column( + spacing=10, + height=200, + width=200, + scroll=ft.ScrollMode.ALWAYS, + on_scroll=on_column_scroll, + ) + for i in range(0, 50): + cl.controls.append(ft.Text(f"Text line {i}", key=str(i))) + + page.add( + ft.Container(cl, border=ft.Border.all(1)), + ) + +ft.run(main) +``` + +See [`Column.on_scroll`](https://flet.dev/docs/controls/column/#flet.Column.on_scroll) for more details about scroll notification. + +Check [infinite scroll example](https://github.com/flet-dev/examples/blob/main/python/controls/column/column-infinite-list.py). + +## Color scheme customization + +Until today the only way to control color scheme for your application was specifying `color_scheme_seed` when creating a new `ft.Theme` object. + +This release enables you to fine tune all 30 colors based on the [Material spec](https://m3.material.io/styles/color/the-color-system/color-roles) and used by various Flet controls. + + + +You can even use [Material Theme Builder](https://m3.material.io/theme-builder#/dynamic) and apply exported color palette to your app, for example: + +```python +page.theme = ft.Theme( + color_scheme=ft.ColorScheme( + primary=ft.Colors.GREEN, + primary_container=ft.Colors.GREEN_200 + # ... + ), +) +``` + +See [`ColorScheme` class](https://flet.dev/docs/types/colorscheme/) for more details. + +## Nested themes + +Another awesome feature of this release is nested themes! + +You can have a part of your app to use a different theme or override some theme styles for specific controls. + +Remember `page` object having `theme` and `theme_mode` properties? Now `Container` has `theme` and `theme_mode` properties too! + +`Container.theme` accepts the same `ft.Theme` object as a page. Specifying `theme_mode` in the container means you don't want to inherit parent theme, but want a completely new, unique scheme for all controls inside the container. However, if the container does not have `theme_mode` property set then the styles from its `theme` property will override the ones from the parent, inherited theme: + +```python +import flet as ft + +def main(page: ft.Page): + # Yellow page theme with SYSTEM (default) mode + page.theme = ft.Theme( + color_scheme_seed=ft.Colors.YELLOW, + ) + + page.add( + # Page theme + ft.Container( + content=ft.ElevatedButton("Page theme button"), + bgcolor=ft.Colors.SURFACE_VARIANT, + padding=20, + width=300, + ), + + # Inherited theme with primary color overridden + ft.Container( + theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.PINK)), + content=ft.ElevatedButton("Inherited theme button"), + bgcolor=ft.Colors.SURFACE_VARIANT, + padding=20, + width=300, + ), + + # Unique always DARK theme + ft.Container( + theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), + theme_mode=ft.ThemeMode.DARK, + content=ft.ElevatedButton("Unique theme button"), + bgcolor=ft.Colors.SURFACE_VARIANT, + padding=20, + width=300, + ), + ) + +ft.run(main) +``` + + + +## Scrollbar theme + +You can now customize the look and fill of scrollbars in your application (or a particular scroillbar with [nested themes](#nested-themes)). + +It could be done via [`page.theme.scrollbar_theme`](https://flet.dev/docs/types/scrollbartheme/) property, for example: + +```python +page.theme = ft.Theme( + scrollbar_theme=ft.ScrollbarTheme( + track_color={ + ft.MaterialState.HOVERED: ft.Colors.AMBER, + ft.MaterialState.DEFAULT: ft.Colors.TRANSPARENT, + }, + track_visibility=True, + track_border_color=ft.Colors.BLUE, + thumb_visibility=True, + thumb_color={ + ft.MaterialState.HOVERED: ft.Colors.RED, + ft.MaterialState.DEFAULT: ft.Colors.GREY_300, + }, + thickness=30, + radius=15, + main_axis_margin=5, + cross_axis_margin=10, + ) +) +``` + + + +## Text theming + +Material 3 design defines [5 groups of text styles with 3 sizes in each group](https://flet.dev/docs/controls/text/#pre-defined-theme-text-styles): "Display", "Headline", "Title", "Label" and "Body" which are used across Flet controls. You can now customize each of those styles with `page.theme.text_theme`, for example: + +```python +import flet as ft + +def main(page: ft.Page): + page.theme = ft.Theme( + text_theme=ft.TextTheme(body_medium=ft.TextStyle(color=ft.Colors.GREEN)) + ) + + page.add(ft.Text("Hello, green world!")) + +ft.run(main) +``` + + + +Apparently, `Body Medium` is used by `Text` control as a default style. + +See [`TextTheme` class](https://flet.dev/docs/types/texttheme/) for more details. + +## Tabs theming + +You can now control the look and feel of `Tabs` control. In this release `Tabs` adds a bunch of new properties and there is a new [`page.theme.tabs_theme`](https://flet.dev/docs/types/tabstheme/) property to style all tabs in your app: + +```python +page.theme = ft.Theme( + tabs_theme=ft.TabsTheme( + divider_color=ft.Colors.BLUE, + indicator_color=ft.Colors.RED, + indicator_tab_size=True, + label_color=ft.Colors.GREEN, + unselected_label_color=ft.Colors.AMBER, + overlay_color={ + ft.MaterialState.FOCUSED: ft.Colors.with_opacity(0.2, ft.Colors.GREEN), + ft.MaterialState.DEFAULT: ft.Colors.with_opacity(0.2, ft.Colors.PINK), + }, + ) +) +``` + + + +See [`TabsTheme` class](https://flet.dev/docs/types/tabstheme/) for more details. + +## Other changes + +### Flutter 3.10 + +This Flet release is based on Flutter 3.10 which [brings new features, performance and size optimizations](https://medium.com/flutter/whats-new-in-flutter-3-10-b21db2c38c73). As a result, most of Flet dependencies bumped their versions too, so if you notice any issues please let us know. + +### Color emoji in web apps + +Color emoji support in web apps are back! In Flutter 3.7 color emoji were disabled in "CanvasKit" renderer (default in Flet) because of their font size (8 MB!) and returned back as an opt-in in Flutter 3.10. You can enable color emoji in server-driven app with `use_color_emoji` argument: + +```python +ft.run(main, use_color_emoji=True) +``` + +and [use `--use-color-emoji` switch](https://flet.dev/docs/publish/web/static-website/#color-emojis) when publishing app as a static side. + +That's all for today! + +Upgrade Flet module to the latest version (`pip install flet --upgrade`) and [let us know](https://discord.gg/dzWXP8SHG8) what you think! diff --git a/website/blog/2023-07-05-flet-for-ios.md b/website/blog/2023-07-05-flet-for-ios.md new file mode 100644 index 0000000000..b92eba2859 --- /dev/null +++ b/website/blog/2023-07-05-flet-for-ios.md @@ -0,0 +1,42 @@ +--- +slug: flet-for-ios +title: Flet for iOS +authors: feodor +tags: [releases] +--- + +🎉 Whoo-hoo, Flet app is now on App Store! 🎉 + + + +With Flet iOS app you can see how your Flet Python app looks and behaves on iPhone or iPad while the app itself is running on your computer. + +But it's more than just testing Flet apps on the phone! Flet mobile app itself is written in Python and its publishing to App Store is an important milestone for the entire Flet project. It is a successful proof that you can create awesome mobile apps in Python only and package them so that they are accepted in App Store! + +**[Follow this guide](https://flet.dev/docs/getting-started/testing-on-mobile/)** to get started with testing your Flet apps on iPhone or iPad. Explore the app, browse gallery, play with sample projects and app settings. + +I would like to thank [Kivy project](https://kivy.org/) for making a [toolchain for iOS](https://github.com/kivy/kivy-ios) which we used to compile Python interpreter and dependencies for iOS devices. We published [serious_python](https://pub.dev/packages/serious_python) package for adding Python runtime to any Flutter app. + +{/* truncate */} + +## FAQ + +### When Android is supported? + +Soon. It has #1 priority now and we've already started working on it. + +### How to package my Flet app for App Store? + +We are going to provide a project template for bootstrap Flutter app and a guide how to combine Flutter, `serious_python` package and your Python app together to create a standalone iOS app and publish it to App Store. + +Later this year we'll create a CI pipeline to fully automate the process. + +Check [`serious_python`'s readme](https://github.com/flet-dev/serious-python#usage) for instructions on how create a Flutter bootstrap and package your Python app to run within it. Use [flet_example](https://github.com/flet-dev/serious-python/tree/main/src/serious_python/example/flet_example) project as a starting point. + +## Flet v0.8.0 release notes + +For testing on iOS you need to upgrade your Flet installation to v0.8.0. + +It's been [changed a lot](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#080) in v0.8.0 and there were some breaking changes. Bear with us while you are upgrading to 0.8.0 and let us know if you have any troubles with it. + +Enjoy! diff --git a/website/blog/2023-07-08-flet-for-android.md b/website/blog/2023-07-08-flet-for-android.md new file mode 100644 index 0000000000..0f7fc97e03 --- /dev/null +++ b/website/blog/2023-07-08-flet-for-android.md @@ -0,0 +1,38 @@ +--- +slug: flet-for-android +title: Flet for Android +authors: feodor +tags: [releases] +--- + +🤖 Android support is here! + + + +With Flet Android app you can see how your Flet Python app looks and behaves on Android devices while the app itself is running on your computer. + +Similar to iOS, Flet for Android is a Flutter app written entirely in Python with the help of two open-source packages: [`serious_python`](https://pub.dev/packages/serious_python) and [`flet`](https://pub.dev/packages/flet). Resulting app package is technically compliant with Google Play requirements, so you can publish awesome Android apps in pure Python. + +**[Follow this guide](https://flet.dev/docs/getting-started/testing-on-mobile/)** to get started with testing your Flet apps on Android. Explore the app, browse gallery, play with sample projects and app settings. + +{/* truncate */} + +## FAQ + +### How to package my Flet app for Google Play? + +We are going to provide a project template for bootstrap Flutter app and a guide how to combine Flutter, `serious_python` package and your Python app together to create a standalone Android app and publish it to Google Play. + +Check [`serious_python`'s readme](https://github.com/flet-dev/serious-python#usage) for instructions on how create a Flutter bootstrap and package your Python app to run within it. Use [flet_example](https://github.com/flet-dev/serious-python/tree/main/example/flet_example) project as a starting point. + +### Will you provide packaging for Windows, macOS and Linux? + +Yes! At the moment Flet desktop apps are packaged with `flet pack` command and PyInstaller. Produced app bundle adds performance and size overhead and is hard to customize, so we are going to replace it with native Flutter packaging. + +## Flet v0.9.0 release notes + +For testing on Android you need to upgrade your Flet installation to v0.9.0. + +There were [a few changes](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#090) mainly to support Android in Flet CLI. Let us know if you notice something unusual. + +Enjoy! diff --git a/website/blog/2023-08-30-flet-for-fastapi.md b/website/blog/2023-08-30-flet-for-fastapi.md new file mode 100644 index 0000000000..b38d23467c --- /dev/null +++ b/website/blog/2023-08-30-flet-for-fastapi.md @@ -0,0 +1,64 @@ +--- +slug: flet-for-fastapi +title: Flet for FastAPI +authors: feodor +tags: [releases] +--- + +We've just released Flet 0.10.0 with FastAPI support! + + + +[FastAPI](https://fastapi.tiangolo.com/) coupled with Uvicorn, Hypercorn, Gunicorn or other web server replaces built-in Flet web server (Fletd) to reliably run production Flet workloads. + +On the other hand, seasoned FastAPI developers can use Flet to easily add interactive, real-time dashboards and admin UI to their existing or new FastAPI services. + +{/* truncate */} + +## A minimal app example + +```python +import flet as ft +import flet_fastapi + +async def main(page: ft.Page): + await page.add_async( + ft.Text("Hello, Flet!") + ) + +app = flet_fastapi.app(main) +``` + +It's a simple app that just outputs "Hello, Flet!" on a web page. + +To run the app install Flet for FastAPI and Uvicorn: + +``` +pip install flet-fastapi +pip install uvicorn +``` + +Save the code above to `hello.py` and then start uvicorn as: + +``` +uvicorn hello:app +``` + +Open the browser and navigate to http://127.0.0.1:8000 to see the app running. + +:::note +Flet app must be [async](https://flet.dev/docs/cookbook/async-apps/) in order to work with FastAPI WebSocket handler. +::: + +## Features and benefits + +* [Multiple Flet apps on a single domain](https://flet.dev/docs/publish/web/dynamic-website/#hosting-multiple-flet-apps-under-the-same-domain) - mapped to the root and/or sub-paths. +* Simple [one-line mappings](https://flet.dev/docs/publish/web/dynamic-website/#flet-fastapi-app) or [individual endpoint configurations](https://flet.dev/docs/publish/web/dynamic-website/#configuring-individual-flet-endpoints). +* Light-weight async wrapper around FastAPI WebSocket connection for greater concurrency. +* Serves Flet static files with user assets and app meta-information customization. +* Uploads handler for `FilePicker` control. +* OAuth callback handler for authentication flows. + +Check [the guide](https://flet.dev/docs/publish/web/dynamic-website/) for complete information about Flet with FastAPI. + +Let us know what you think by joining [Flet Discord server](https://discord.gg/dzWXP8SHG8) or creating a new thread on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). diff --git a/website/blog/2023-12-30-packaging-apps-for-distribution.md b/website/blog/2023-12-30-packaging-apps-for-distribution.md new file mode 100644 index 0000000000..fe129ae200 --- /dev/null +++ b/website/blog/2023-12-30-packaging-apps-for-distribution.md @@ -0,0 +1,41 @@ +--- +slug: packaging-apps-for-distribution +title: Packaging apps for distribution +authors: feodor +tags: [releases] +--- + +Dear friends! In the final post of this year I would like to thank you all for your contributions +to Flet project whether it's spreading a word, submitting pull request, joining Discord discussion or a even sending an annoying bug report! + +{/* truncate */} + +With your fantastic support we achieved a lot in year 2023: + +* 70+ controls (special thanks to [@ndonkoHenri](https://github.com/ndonkoHenri) for his tremendous contribution). +* 7,700 stars on GitHub. +* 2,150 users with community moderators (thank you guys!) on Discord. +* Flet integration with Pyodide for pure client-side Python apps - no other frameworks provide a better UI for Pyodide! +* Flet app in AppStore and Google Play - great way to test on mobile devices and real proof of Flet apps being accepted in stores. +* ...and finally... drum roll...🥁🥁🥁 `flet build` command is here! 🎉🎉🎉 + +🎄 "New Year" 🎄 edition of Flet 0.18.0 has been just released which allows packaging +your Flet apps for distribution on all platforms: iOS, Android, Web, macOS, Windows and Linux! + +**The one command to rule them all!** + +The full circle is now closed: you can create (`flet create`), run (`flet run`) and build (`flet build`) your Flet apps with Flet CLI. + +Flet CLI provides `flet build` command that allows packaging Flet app into a standalone executable or install package for distribution. + +`flet build` command supersedes both [`flet pack`](https://flet.dev/docs/cookbook/packaging-desktop-app/) (packaging into desktop app) and [`flet publish`](https://flet.dev/docs/publish/web/static-website/) (packaging into a static website) commands and allows converting your Flet app into Android or iOS bundle, desktop app and a static website. + +For building desktop apps `flet build` does not longer rely on PyInstaller like `flet pack` does, but uses Flutter SDK to produce a fast, offline, fully customizable (your own icons, about dialog and metadata) executable for Windows, Linux and macOS with Python runtime embedded into executable and running in-process. + +Static websites built with `flet build`, compared to `flet publish`, have faster load time as all Python dependencies are now packaged into a single archive instead of being pulled in runtime with `micropip`. `flet build web` also detects native Python [packages built into Pyodide](https://pyodide.org/en/stable/usage/packages-in-pyodide.html), such as `bcrypt`, `html5lib`, `numpy` and many others, and installs them from Pyodide package registry. + +Check [Packaging app for distribution](https://flet.dev/docs/publish/) guide for complete information about `flet build` command. + +Let us know what you think by joining [Flet Discord server](https://discord.gg/dzWXP8SHG8) or creating a new thread on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +We wish you Happy New Year! Enjoy your holidays! diff --git a/website/blog/2024-02-14-flet-adaptive-and-custom-controls.md b/website/blog/2024-02-14-flet-adaptive-and-custom-controls.md new file mode 100644 index 0000000000..4371a31eaa --- /dev/null +++ b/website/blog/2024-02-14-flet-adaptive-and-custom-controls.md @@ -0,0 +1,89 @@ +--- +slug: flet-adaptive-and-custom-controls +title: Flet adaptive UI and custom controls release +authors: feodor +tags: [releases] +--- + +🥰 Happy Valentine's Day lovely people! 🥰 + +We just released Flet 0.20.0 with the focus on: + +1) Adaptive UI. +2) Extending Flet apps with 3rd-party Flutter packages. +3) New controls: [`Video`](https://flet.dev/docs/video/) (yay!), [`AudioRecorder`](https://flet.dev/docs/audio_recorder/) and a bunch of `Cupertino`-like controls. Flet now includes 97 built-in controls! + +{/* truncate */} + +:::warning +Flet 0.20.0 includes a new [`Video`](https://flet.dev/docs/video/) control. While macOS and Windows already include all required media libraries to test Flet apps on Linux, the [libmpv](https://mpv.io/) package must be installed. On Ubuntu/Debian in can be installed with: + +``` +sudo apt install libmpv-dev mpv +``` +::: + +## Adaptive UI + +Adaptive controls allow writing apps with a single code base which look and behave differently depending on the platform they are running on. + +To the date Flet provides 11 adaptive controls. To make control adaptive you should set its `adaptive` property to `True`. + +In Flet 0.20.0 we introduce `adaptive` property to all container-alike controls. +Setting `adaptive=True` on a container propagates this property to all child adaptive controls. + +Page adds `design` property which enables granular control over controls design language and can have the following values: `ft.PageDesign.ADAPTIVE`, `ft.PageDesign.MATERIAL` or `ft.PageDesign.CUPERTINO`. + +By setting just `page.design = ft.PageDesign.ADAPTIVE` you can make you app looking awesome on both iOS and Android devices: + +
+
+

iPhone

+ +
+
+

Android

+ +
+
+ +## Integrating existing Flutter packages + +Today Flet offers almost 100 controls, but, as you can imagine, not every Flutter library/widget could be added to the core Flet library and Flet team couldn't do that alone in the acceptable timeframe. + +At the same time we do not want to put early adopters, who chose Flet to build their next commercial or corporate app, into a situation where their progress depends on Flet team availability and desire to implement a Flutter control they need. + +In Flet 0.20.0 we re-factored Flutter core packages and identified the API that can be used by 3rd-party developers to add their own Flet controls written in Dart. + +We are currently working on API docs, but you can learn now how custom Flutter packages are implemented by looking at Dart sources for [`Video`](https://github.com/flet-dev/flet/tree/main/packages/flet_video), and [`Audio`](https://github.com/flet-dev/flet/tree/main/packages/flet_audio) controls. + +In short, you have to create a new Flutter package which implements and exports two methods: + +```dart +void ensureInitialized(); +Widget createControl(CreateControlArgs args); +``` + +See [`ensureInitialized()`](https://github.com/flet-dev/flet/blob/main/packages/flet_video/lib/src/create_control.dart#L16-L18) and [`createControl()`](https://github.com/flet-dev/flet/blob/main/packages/flet_video/lib/src/create_control.dart#L6-L14) implementations for `Video` control. + +On Python side you create a new class inherited from `Control` (non-visual or overlay controls) or `ConstrainedControl`. + +See [`Video`](https://github.com/flet-dev/flet/blob/main/sdk/python/packages/flet-core/src/flet_core/video.py#L44) class implementation in Python. + +To integrate a custom Flutter package while building your Flet app with `flet build` command you can list extra packages with either `--include-packages` option or in `pubspec.yaml` file put into root of your Flet app. + +## `Video` control + +`Video` control is implemented in a separate Flutter package. + +To build your Flet app with `Video` control add `--include-packages flet_video` to your `flet build` command, for example: + +``` +flet build apk --include-packages flet_video +``` + +Flet 0.20.0 is a relatively ["large" release](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0200) and could break some things. + +Upgrade to Flet 0.20.0, test your apps and let us know what you think by joining [Flet Discord server](https://discord.gg/dzWXP8SHG8) or creating a new thread on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Enjoy! diff --git a/website/blog/2024-03-06-flet-fastapi-and-async-api-improvements.md b/website/blog/2024-03-06-flet-fastapi-and-async-api-improvements.md new file mode 100644 index 0000000000..d13a660d01 --- /dev/null +++ b/website/blog/2024-03-06-flet-fastapi-and-async-api-improvements.md @@ -0,0 +1,245 @@ +--- +slug: flet-fastapi-and-async-api-improvements +title: Flet FastAPI and async API improvements +authors: feodor +tags: [releases] +--- + +Flet makes writing dynamic, real-time web apps a real fun! + +Flet 0.21.0 further improves web apps development experience as well as using asyncio APIs in your Flet apps. + +Here's what's new in Flet 0.21.0: + +{/* truncate */} + +## FastAPI with Uvicorn replaces built-in web server + +From very beginning of Flet life to serve web apps there was a built-in web server written in Go +and called "Fletd". It's being started on the background when you run your app with `flet run --web`. +Fletd was part of Flet Python wheel contributing a few megabytes to its size. +Additionally, Python app was using WebSockets to talk to Fletd web server which was adding sometimes noticeable overhead. + +Then, in [Flet 0.10.0](/blog/flet-for-fastapi) we have added FastAPI support to build "serious" web apps using AsyncIO API. + +Now, in Flet 0.21.0 built-in web server has been completely removed and replaced with FastAPI and Uvicorn. Fletd is not +a part of Flet distribution anymore. + +Using FastAPI means there is no more communication overhead as web server is a part of Flet app. +Also, you don't need to do any additional steps to host your app in production with FastAPI - +you just use the same `ft.run(main)` command to run your app. + +:::warning Breaking change + +`flet_fastapi` package has been deprecated and its contents moved to `flet` package as `flet.fastapi` +module. If you were using FastAPI in your Flet app replace: + +```python +import flet_fastapi +``` + +with + +```python +import flet.fastapi as flet_fastapi +``` +::: + +**Use any ASGI web server for hosting** + +You can host your Flet web app with any ASGI-compatible server such as [Uvicorn](https://www.uvicorn.org/) (used by default), [Hypercorn](https://pgjones.gitlab.io/hypercorn/) or [Daphne](https://github.com/django/daphne). + +Just tell Flet to export ASGI app: + +```python title="main.py" +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text("Hello ASGI!")) + +app = ft.run(main, export_asgi_app=True) +``` + +and then run with Hypercorn as: + +``` +hypercorn main:app --bind 0.0.0.0:8000 +``` + +**Web app environment variables** + +Every aspect of web app hosting can be controlled with environment variables: + +* `FLET_FORCE_WEB_SERVER` - `true` to force running app as a web app. Automatically set on headless Linux hosts. +* `FLET_SERVER_PORT` - TCP port to run app on. `8000` if the program is running on a Linux server or `FLET_FORCE_WEB_SERVER` is set; otherwise random port. +* `FLET_SERVER_IP` - IP address to listen web app on, e.g. `127.0.0.1`. Default is `0.0.0.0` - bound to all server IPs. +* `FLET_ASSETS_DIR` - absolute path to app "assets" directory. +* `FLET_UPLOAD_DIR` - absolute path to app "upload" directory. +* `FLET_MAX_UPLOAD_SIZE` - max allowed size of uploaded file, in bytes. Unlimited if not specified. +* `FLET_SECRET_KEY` - a secret key to sign temporary upload URLs. +* `FLET_WEB_APP_PATH` - a URL path after domain name to host web app under, e.g. `/apps/myapp`. Default is `/` - host app in the root. +* `FLET_SESSION_TIMEOUT` - session lifetime, in seconds. Default is `3600`. +* `FLET_OAUTH_STATE_TIMEOUT` - max allowed time to complete OAuth web flow, in seconds. Default is `600`. +* `FLET_WEB_RENDERER` - Flutter rendering mode: `canvaskit` (default), `html` or `auto`. +* `FLET_WEB_USE_COLOR_EMOJI` - `true`, or `True` or `1` to load web font with colorful emojis. +* `FLET_WEB_ROUTE_URL_STRATEGY` - `path` (default) or `hash`. +* `FLET_WEBSOCKET_HANDLER_ENDPOINT` - custom path for WebSocket handler. Default is `/ws`. +* `FLET_UPLOAD_HANDLER_ENDPOINT` - custom path for upload handler. Default is `/upload`. +* `FLET_OAUTH_CALLBACK_HANDLER_ENDPOINT` - custom path for OAuth handler. Default is `/oauth_callback`. + +## Async-first framework + +Flet is now async-first framework which means you don't have to decide whether your app is entirely sync or async, but you can mix both sync and async methods in the same app. + +For example, in Flet 0.21.0 you can write an app like this: + +```python +import flet as ft +import time +import asyncio + +def main(page: ft.Page): + + def handler(e): + time.sleep(3) + page.add(ft.Text("Handler clicked")) + + async def handler_async(e): + await asyncio.sleep(3) + page.add(ft.Text("Async handler clicked")) + + page.add( + ft.ElevatedButton("Call handler", on_click=handler), + ft.ElevatedButton("Call async handler", on_click=handler_async) + ) + +ft.run(main) +``` + +In the example above a click on one button is handled by a "blocking" handler while a click +on second button calls asynchronous handler. The first handler is run in a `threading.Thread` while second handler is run in `asyncio.Task`. + +Also, notice in `async def` handler you are not required to use `await page.add_async()` anymore, but a regular `page.add()` works just fine. + +:::info API changes +Most of `Page._async()` and `Control._async()` methods have been deprecated and their `Page.()` and `Control.()` counterparts should be used instead. + +The only exception here is methods returning results, like those ones in `Audio` control: you still have to use async methods in async event handlers. +::: + +## Custom controls API normalized + +In this Flet release we also re-visited API for writing custom controls in Python. + +As a result `UserControl` class has been deprecated. You just inherit from a specific control with layout that works for your needs. + +For example, `Countdown` custom control is just a `Text` and could be implemented as following: + +```python +import asyncio + +import flet as ft + +class Countdown(ft.Text): + def __init__(self, seconds): + super().__init__() + self.seconds = seconds + + def did_mount(self): + self.running = True + self.page.run_task(self.update_timer) + + def will_unmount(self): + self.running = False + + async def update_timer(self): + while self.seconds and self.running: + mins, secs = divmod(self.seconds, 60) + self.value = "{:02d}:{:02d}".format(mins, secs) + self.update() + await asyncio.sleep(1) + self.seconds -= 1 + +def main(page: ft.Page): + page.add(Countdown(120), Countdown(60)) + +ft.run(main) +``` + +Notice the usage of `self.page.run_task(self.update_timer)` to start a new task. +There is also `self.page.run_thread()` method that must be used by control developer to start a new background job in a thread. + +If you want to spawn your own tasks or threads Flet provides the current event loop and thread executor via `Page.loop` and `Page.executor` properties respectively. + +:::info API changes +`Control._before_build_command()` replaced with `Control.before_update()` + +`Control.build()` should not return any control now, but must update inherited control properties, for example: + +```python +def build(): + self.controls.append(ft.Text("Something")) +``` + +`Control.did_mount_async()` and `Control.will_unmount_async()` are deprecated. Use `Control.did_mount()` and `Control.will_unmount()` instead. +::: + +## New Cupertino controls + +This Flet release adds more Cupertino controls to make your apps shine on iOS: + +* `CupertinoActivityIndicator` +* `CupertinoActionSheet` +* `CupertinoSlidingSegmentedButton` +* `CupertinoSegmentedButton` +* `CupertinoTimerPicker` +* `CupertinoPicker` +* `CupertinoDatePicker` +* `CupertinoContextMenu` + +## Accessibility improvements + +Now Flet has complete implementation of `Semantics` control and new `SemanticsService` control. + +## App lifecycle change event + +There is a new `Page.on_app_lifecycle_state_change` event that allows listening for changes in the application lifecycle. + +For example, you can now update UI with the latest information when the app becomes active (brought to the front). This event works on iOS, Android, all desktop platforms and web! + +The following app lifecycle transitions are recognized: + +* `SHOW` +* `RESUME` +* `HIDE` +* `INACTIVE` +* `PAUSE` +* `DETACH` +* `RESTART` + +:::note +Read more about each [lifecycle state](https://flet.dev/docs/controls/page/#flet.Page.on_app_lifecycle_state_change). +::: + +Here's a small example of how this event can be used: + +```python +import flet as ft + +def main(page: ft.Page): + + def app_lifecycle_change(e: ft.AppLifecycleStateChangeEvent): + if e.state == ft.AppLifecycleState.RESUME: + print("Update UI with fresh data!") + + page.on_app_lifecycle_state_change = app_lifecycle_change + page.add(ft.Text("Hello World")) + +ft.run(main) +``` + +Flet 0.21.0 release has some breaking changes. Upgrade to it, test your apps and let us know how it worked for you. +Join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Enjoy! diff --git a/website/blog/2024-04-10-controls-and-theming-enhancements.md b/website/blog/2024-04-10-controls-and-theming-enhancements.md new file mode 100644 index 0000000000..8a32c46c16 --- /dev/null +++ b/website/blog/2024-04-10-controls-and-theming-enhancements.md @@ -0,0 +1,172 @@ +--- +slug: controls-and-theming-enhancements +title: Controls and theming enhancements +authors: henri +tags: [releases] +--- + +One month after the release of Flet 0.21.0, we are excited to announce the release of Flet 0.22.0. + +This release comes with a lot of enhancements, bug fixes, and deprecations: + +{/* truncate */} + +## Enhancements + +This was one of the main concerns while coming up with this release. Two types of enhancements were made: + +### Controls Enhancement + +We went through the long list of already-present controls and exposed, where possible, more +properties - [PR #2882](https://github.com/flet-dev/flet/pull/2882). This will grant you more power/control over the +Flet Controls you use in your awesome applications. + +Below is the complete list: + +- [`AppBar`](https://flet.dev/docs/controls/appbar/): elevation_on_scroll, exclude_header_semantics, + force_material_transparency, is_secondary, shadow_color, surface_tint_color, clip_behavior, title_spacing, + toolbar_opacity, title_text_style, toolbar_text_style, shape +- [`AlertDialog`](https://flet.dev/docs/controls/alertdialog/): action_button_padding, clip_behavior, icon_padding, + shadow_color, surface_tint_color +- [`Banner`](https://flet.dev/docs/controls/banner/): content_text_style, margin, elevation, divider_color, shadow_color, + surface_tint_color, on_visible +- [`CupertinoListTile`](https://flet.dev/docs/controls/cupertinolisttile/): leading_size, leading_to_title +- [`CupertinoSegmentedButton`](https://flet.dev/docs/controls/cupertinosegmentedbutton/): click_color +- [`CupertinoSwitch`](https://flet.dev/docs/controls/cupertinoswitch/):on_label_color, off_label_color +- [`CupertinoTimerPicker`](https://flet.dev/docs/controls/cupertinotimerpicker/): item_extent +- [`Chip`](https://flet.dev/docs/controls/chip/): surface_tint_color, color, click_elevation, clip_behavior, + visual_density, border_side +- [`Divider`](https://flet.dev/docs/controls/divider/): leading_indent, trailing_indent +- [`ExpansionTile`](https://flet.dev/docs/controls/expansiontile/): dense, enable_feedback, visual_density +- [`Card`](https://flet.dev/docs/controls/card/): clip_behavior, is_semantic_container, show_border_on_foreground, + variant +- [`Checkbox`](https://flet.dev/docs/controls/checkbox/): border_side, semantics_label, shape, splash_radius, is_error, + visual_density, mouse_cursor +- [`CircleAvatar`](https://flet.dev/docs/controls/circleavatar/): on_image_error +- [`DataTable`](https://flet.dev/docs/controls/datatable/): clip_behavior +- [`DatePicker`](https://flet.dev/docs/controls/datepicker/): on_entry_mode_change +- [`Draggable`](https://flet.dev/docs/controls/draggable/): on_drag_complete, on_drag_start +- [`DragTarget`](https://flet.dev/docs/controls/dragtarget/): on_move +- [`Dropdown`](https://flet.dev/docs/controls/dropdown/): fill_color, hint_content, icon_content, elevation, item_height, + max_menu_height, icon_size, enable_feedback, padding, icon_enabled_color, icon_disabled_color, on_click +- [`ElevatedButton`](https://flet.dev/docs/controls/elevatedbutton/): clip_behavior +- [`FloatingActionButton`](https://flet.dev/docs/controls/floatingactionbutton/): clip_behavior, enable_feedback, + focus_color, foreground_color, disabled_elevation, elevation, focus_elevation, highlight_elevation, hover_elevation, + mouse_cursor +- [`GridView`](https://flet.dev/docs/controls/gridview/): cache_extent, clip_behavior, semantic_child_count +- [`IconButton`](https://flet.dev/docs/controls/iconbutton/): alignment, disabled_color, focus_color, enable_feedback, + hover_color, padding, splash_color, splash_radius, focus_color, mouse_cursor, visual_density +- [`Image`](https://flet.dev/docs/controls/image/): exclude_from_semantics, filter_quality +- [`ListTile`](https://flet.dev/docs/controls/listtile/): enable_feedback, horizontal_spacing, min_leading_width, + min_vertical_padding, selected_color, selected_tile_color, style, title_alignment, icon_color, text_color, shape, + visual_density, mouse_cursor, title_text_style, subtitle_text_style, leading_and_trailing_text_style +- [`ListView`](https://flet.dev/docs/controls/listview/): cache_extent, clip_behavior, semantic_child_count +- [`NavigationBar`](https://flet.dev/docs/controls/navigationbar/): animation_duration, overlay_color +- [`NavigationDrawerDestination`](https://flet.dev/docs/controls/navigationdrawer/): bgcolor +- [`NavigationBarDestination`](https://flet.dev/docs/controls/navigationbardestination/): bgcolor +- [`NavigationRail`](https://flet.dev/docs/controls/navigationrail/): selected_label_text_style, + unselected_label_text_style +- [`NavigationRailDestination`](https://flet.dev/docs/controls/navigationrail/): indicator_color, indicator_shape +- [`Option`](https://flet.dev/docs/controls/dropdownoption/#flet.DropdownOption): alignment, on_click +- [`OutlinedButton`](https://flet.dev/docs/controls/outlinedbutton/): clip_behavior +- [`Page`](https://flet.dev/docs/controls/page/): locale_configuration +- [`PopupMenuItem`](https://flet.dev/docs/controls/popupmenubutton/#flet.PopupMenuItem): height, padding, + mouse_cursor +- [`PopupMenuButton`](https://flet.dev/docs/controls/popupmenubutton/): bgcolor, clip_behavior, elevation, + enable_feedback, icon_color, shadow_color, surface_tint_color, icon_size, padding, splash_radius, shape, on_open, + on_cancel +- [`ProgressBar`](https://flet.dev/docs/controls/progressbar/): border_radius, semantics_label, semantics_value +- [`ProgressRing`](https://flet.dev/docs/controls/progressring/): semantics_label, semantics_value, stroke_cap, + stroke_align +- [`Radio`](https://flet.dev/docs/controls/radio/): focus_color, hover_color, overlay_color, splash_radius, toggleable, + visual_density, mouse_cursor +- [`SearchBar`](https://flet.dev/docs/controls/searchbar/): keyboard_type, view_surface_tint_color, autofocus +- [`SelectionArea`](https://flet.dev/docs/controls/selectionarea/): on_change +- [`Slider`](https://flet.dev/docs/controls/slider/): interaction, overlay_color, mouse_cursor, secondary_track_value, + secondary_active_color +- [`Stack`](https://flet.dev/docs/controls/stack/): alignment, fit +- [`SnackBar`](https://flet.dev/docs/controls/snackbar/): clip_behavior, shape, on_visible, action_overflow_threshold +- [`Switch`](https://flet.dev/docs/controls/switch/): hover_color, splash_radius, overlay_color, track_outline_color, + mouse_cursor +- [`Tabs`](https://flet.dev/docs/controls/tabs/): divider_height, enable_feedback, indicator_thickness, is_secondary, + mouse_cursor, clip_behavior +- [`TextField`](https://flet.dev/docs/controls/textfield/): fill_color, hover_color +- [`TimePicker`](https://flet.dev/docs/controls/timepicker/): orientation, on_entry_mode_change +- [`Tooltip`](https://flet.dev/docs/types/tooltip/): enable_tap_to_dismiss, exclude_from_semantics +- [`VerticalDivider`](https://flet.dev/docs/controls/verticaldivider/): leading_indent, trailing_indent + +If you however feel that something lacks and should be added, don't hesitate to let us know. + +Check out the article I wrote +concerning `Page.locale_configuration` [here](https://ndonkohenri.medium.com/app-localization-in-flet-5b523e83ca89). + +### Theme Enhancements + +The Theme class which is used for application theming in light and dark mode has equally been further enhanced. +Lots of new themes were introduced - [PR #2955](https://github.com/flet-dev/flet/pull/2955). + +See the Theming Guide [here](https://flet.dev/docs/cookbook/theming/). + +## Rive Animations + +[Rive](https://rive.app/) is a very popular real-time interactive design and animation tool. +The newly introduced [`Rive`](https://flet.dev/docs/rive/) Control allows you to load and visualize any Rive +animation in your applications. + +The animation's source (`Rive.src`) can either be a local asset file or a URL - as usual, it all depends on your needs. + +## Parent Control + +As requested in [#952](https://github.com/flet-dev/flet/issues/952), the ability to access the parent of any control has +been added: `Control.parent`. + +Read more on it [here](https://ndonkohenri.medium.com/access-any-controls-parent-flet-98e2c60dfab8). + +## Bug Fixes + +The below issues were successfully fixed: + +- [#2560](https://github.com/flet-dev/flet/issues/2560) - `Dropdown.bgcolor` was not visually respected +- [#2740](https://github.com/flet-dev/flet/issues/2740) - `CircleAvatar` not working with local asset images +- [#2781](https://github.com/flet-dev/flet/issues/2781) - `'FletSocketServer'` Error raised on Linux +- [#2826](https://github.com/flet-dev/flet/issues/2826) - `PopupMenuItem.data` not respected +- [#2839](https://github.com/flet-dev/flet/issues/2839) - `ExpansionTile.initially_expanded` had no visual effect +- [#2867](https://github.com/flet-dev/flet/issues/2867) - `PopupMenuButton` had an always-visible tooltip of "Show menu" +- On some Python versions, you might have seen a RuntimeError('Event loop is closed') which usually shows up when + closing the app's window. The Python-dev + team [fixed](https://github.com/python/cpython/issues/109538#issuecomment-1823306415) this asyncio-related issue + recently, but this fix is only present in the versions released from the year 2024. So if you face this issue, + please [download](https://www.python.org/downloads/) one of the latest Python releases and replace the one used in + your environment. + +Special Thanks to the dynamic Flet community for reporting all the issues they encountered. We keep working hard on +solving the remaining ones. + +## Deprecations + +As previously mentioned in the [announcement](https://python.plainenglish.io/whats-new-in-flet-0-21-0-ca482ab4520b) +concerning Flet v0.21.0, all deprecations will be completely removed from the API in version 1.0 - so you have enough +time to update your apps. + +You must not completely memorize what has been deprecated as we've added DeprecationWarnings which will be shown +directly in your console (without breaking your app). + +- [`PopupMenuButton.on_cancelled`](https://flet.dev/docs/controls/popupmenubutton/#flet.PopupMenuButton.on_cancel) has been renamed + to [`on_cancel`](https://flet.dev/docs/controls/popupmenubutton/#flet.PopupMenuButton.on_cancel) +- [`foreground_image_url`](https://flet.dev/docs/controls/circleavatar/#flet.CircleAvatar.foreground_image_src) + and [`background_image_url`](https://flet.dev/docs/controls/circleavatar/#flet.CircleAvatar.background_image_src) properties + of [`CircleAvatar`](https://flet.dev/docs/controls/circleavatar/) were renamed + to [`foreground_image_src`](https://flet.dev/docs/controls/circleavatar/#flet.CircleAvatar.foreground_image_src) + and [`background_image_src`](https://flet.dev/docs/controls/circleavatar/#flet.CircleAvatar.background_image_src) respectively +- `DragTargetAcceptEvent` used in the [`DragTarget.on_accept`](https://flet.dev/docs/controls/dragtarget/#flet.DragTarget.on_accept) has + been renamed to `DragTargetEvent` + +## Documentation + +The Flet documentation has been reorganized to ease navigation (especially for beginners/new users). + +Upgrade to Flet 0.22.0, test your apps and let us know how you find the new features we added. +If you have any questions, please join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Happy Flet-ing! diff --git a/website/blog/2024-05-01-flet-packaging-update.md b/website/blog/2024-05-01-flet-packaging-update.md new file mode 100644 index 0000000000..f160330e53 --- /dev/null +++ b/website/blog/2024-05-01-flet-packaging-update.md @@ -0,0 +1,116 @@ +--- +slug: flet-packaging-update +title: Flet packaging update +authors: feodor +tags: [releases] +--- + +## The problem + +When you package your Flet program in Python to run on a mobile device (or desktop) the resulting +bundle (.apk, .ipa, .exe, .app) contains your Python program, Python interpreter and [Python Standard Library](https://docs.python.org/3/library/index.html). + +If your program uses only Python standard library then packaging process is relatively easy - Flet zips your code and combines Flutter app together with Python interpreter and standard library both compiled for the target platform: Android or iOS. + +However, problems may arise when your Flet program uses third-party packages, with thousands of them published on PyPI or Conda. + +{/* truncate */} + +There are two kinds of third-party packages: + +### Pure-Python packages + +A "pure-Python" package is a package that only contains Python code, and doesn't include extensions written in C, C++, Rust or other languages. You only need a Python interpreter and the Python Standard Library to run a pure-Python package, and it doesn't matter what your OS or platform is. + +Examples of such packages: `httpx`, `click`, `rich`, `requests`. + +To verify if the package is pure, find that package on [PyPI](https://pypi.org) and navigate to its "Download files" page. If under "Built distribution" section there is only one wheel ending with `-py3-none-any.whl` then *most probably* it's a pure Python package that will work "as is" on any device with Python. + + + +We say *"probably"* because that pure package could depend on a non-pure package which brings you to the next section. For example, [`pydantic`](https://pypi.org/project/pydantic/#files) is a pure package, but to work properly it requires [`pydantic-core`](https://pypi.org/project/pydantic-core/#files) non-pure package written in Rust. + +### Non-pure Python packages + +A "non-pure Python" package is one that is fully or partially written in C, C++, Rust, or another language and must be compiled to machine code for the platform on which it will run. + +Examples of such packages: `cryptography`, `opencv-python`, `numpy`, `msgpack`. + +On "Download files" page of non-pure package you will find a bunch of wheels pre-built for various platforms: macOS, Windows, Linux. + + + +When you run `pip install ` pip tries to find a wheel for your specific platform and Python version looking at +wheel suffixes that include that information. + +It's a courtesy of package developer to provide pre-compiled wheels for multiple platforms. There could be missing wheels for some platforms, or no wheels at all - just `.tar.gz` under "Source distribution" with package sources. + +#### Building package from sources is hard + +To install a package with source distribution only, pip will attempt to build non-Python code on your machine using installed compilers, linkers, libraries, and SDKs. However, this process can be lengthy and error-prone. The compiled code base might be large, and your machine could lack the required libraries or toolchains. + +#### No wheels for iOS and Android yet + +There are no pre-built wheels for iOS and Android on PyPI and PyPI's validation process won't allow package developers to upload them anyway as both iOS and Android are not officially supported platforms in Python. + +There is a process ([PEP 730](https://peps.python.org/pep-0730/) and [PEP 738](https://peps.python.org/pep-0738/)) to add official support for iOS and Android to Python 3.13, so, hopefully, the developer experience will improve. + +#### Package dependencies + +Pure-Python packages can import or depend on non-pure packages and you should keep that in mind while packaging your Flet app to run on a mobile device. + +For example, `supabase` package, to access Supabase API, is a pure package which depends on `pydantic` package which is also pure Python package. In its turn `pydantic` package depends on `pydantic-core` which is a non-pure package written in Rust. Thus, to run your Flet app using Supabase API the packaging process should be able to find a pre-build wheel for your target platform. If PyPI doesn't have that wheel then it could be either Flet developers, building that wheel on their servers and hosting it somewhere, or you, building that wheel on your own machine. + +To see a dependency graph for a package you can use [`pipgrip`](https://pypi.org/project/pipgrip/). + +Run it with `--tree` option to get a tree view of dependencies: + +``` +$ pipgrip --tree fastapi + +fastapi (0.110.3) +├── pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4 (2.7.1) +│ ├── annotated-types>=0.4.0 (0.6.0) +│ ├── pydantic-core==2.18.2 (2.18.2) +│ │ └── typing-extensions!=4.7.0,>=4.6.0 (4.11.0) +│ └── typing-extensions>=4.6.1 (4.11.0) +├── starlette<0.38.0,>=0.37.2 (0.37.2) +│ └── anyio<5,>=3.4.0 (4.3.0) +│ ├── idna>=2.8 (3.7) +│ └── sniffio>=1.1 (1.3.1) +└── typing-extensions>=4.8.0 (4.11.0) +``` + +## Current approach + +We released the first version of packaging [4 months ago](/blog/packaging-apps-for-distribution) and since then, we have realized that the initial approach has multiple flaws and should be improved. + +When you run `flet build apk` with the current Flet version it downloads Python runtime with standard library both pre-built for Android (or iOS if ran with `flet build ipa`). + +For non-pure packages, like `numpy`, Flet is asking you to build those packages by yourself using "Python for Android" (p4a) tool from Kivy and then provide a path to "p4a" distributive where those pre-build packages could be found. + +This is problem #1 - you are forced to struggle with a complicated process of installing "p4a" tool and compiling Python modules on your machine. + +Problem #2 - all packages from p4a's `dist` directory will be included into a final application bundle - it could contain non-relevant packages and other junk. + +Problem #3 - non-pure packages must be built *before* running `flet build` command. You have to analyze all dependencies of your app and separate what must be built with p4a. + +Problem #4 - p4a "recipes" to build packages could be either very old or missing. You hope that older version of the package works with your app, try authoring a "recipe" and hope it works or submit a request for new recipe in Kivy repository. + +When you're done with building non-pure packages using p4a, Flet requires you to specify only pure packages in `requirements.txt` which doesn't work if pure package directly or indirectly depends on non-pure (see [example above](#package-dependencies)) - this is problem #5. There is a [recent example](https://github.com/flet-dev/flet/issues/3114) of this problem: `flet build` replaces `flet` with `flet-embed` in `requirements.txt`, but it's unable to know if there is a 3rd-party package depending on `flet`, thus both `flet-embed` and non-suitable-for-mobile `flet` are installed. This is not a solution, but a hack! + +## Packaging 2.0 + +In the next iteration of Flet's packaging implementation, we are going to move away from Kivy and replace it with [Mobile Forge](https://github.com/flet-dev/mobile-forge). Mobile Forge has been created by Beeware team based and their experience with Briefcase and Chaquopy. Mobile Forge is a clean-room implementation of a packaging tool for binary Python packages which is relies on [crossenv](https://github.com/benfogle/crossenv). + +The main promise of Mobile Forge with `crossenv` is that most existing non-pure Python packages will be able to compile for iOS and/or Android by simply adding a recipe with `meta.yaml` file only, without requiring any hacks or patches. + +We are going to use Mobile Forge to pre-build the most popular non-pure Python packages for iOS and Android and host them in our own public repository. You will be able to use that tool to build and contribute other packages, non present in our repository. + +We've created a new ["Packages" category in Flet discussions](https://github.com/flet-dev/flet/discussions/categories/packages) where you can post, vote and discuss requests for non-pure (native) Python packages that work with Flet (check [rules](https://github.com/flet-dev/flet/discussions/3139) before posting there). Flet's goal is to provide the most comprehensive catalog of pre-built Python packages and make the process of adding new packages as friendly and transparent as possible. + +The new version of `flet build` will use a custom-made virtual pip index. This index will analyze dependencies, detect non-pure packages, and offer to pip mobile packages. For all other packages, it will fall back to PyPI. + +The new packaging will be hopefully available in a few weeks. While we are working we encourage you to visit [Packages](https://github.com/flet-dev/flet/discussions/categories/packages) and see if the package you need is there. Submitting a request or voting for existing package will help us to prioritize package "recipes". + +Thank you! diff --git a/website/blog/2024-05-24-flet-at-pycon-us-2024.md b/website/blog/2024-05-24-flet-at-pycon-us-2024.md new file mode 100644 index 0000000000..e3348963e3 --- /dev/null +++ b/website/blog/2024-05-24-flet-at-pycon-us-2024.md @@ -0,0 +1,24 @@ +--- +slug: flet-at-pycon-us-2024 +title: Flet at PyCon US 2024 +authors: feodor +--- + +Last week we attended PyCon US in a beautiful city of Pittsburgh, PA! + +I've been on many conferences, but at PyCon I was amazed by the spacious venue, flawless event organization, high-quality content and welcoming community 😎, ...and good food 🍔! + + + +We met a lot of great people and, especially, wonderful people from Beeware (hello Russell, Malcolm and Russell 👋). They did a great job of popularizing Python on mobile and advocating the addition of iOS and Android to the list of supported platforms in the next release of Python 3.13 🎉! + +We enjoyed good talks and inspirational key notes, learned new things, enjoyed the city. Lightning talks (short 5-minute presentations) were real fun! + +Oh, I saw Guido van Rossum (The Creator of Python himself, in case you didn't know 😅) at Microsoft booth, but didn't have a chance to take a picture with him as there was a line up 😉. + +As first time attendees we did't do talks or presentations, but watched and learned instead. +We plan to present next year 🤞. + +Next PyCon US is going to be at the same place. Will come again and hope to see more of you there! + + diff --git a/website/blog/2024-06-18-flet-v-0-23-release-announcement.md b/website/blog/2024-06-18-flet-v-0-23-release-announcement.md new file mode 100644 index 0000000000..a1fd3fb723 --- /dev/null +++ b/website/blog/2024-06-18-flet-v-0-23-release-announcement.md @@ -0,0 +1,125 @@ +--- +slug: flet-v-0-23-release-announcement +title: Flet v0.23.0 Release Announcement +authors: henri +tags: [releases] +--- + +We are excited to announce the release of Flet 0.23.0. It is a big release with many new features and bug fixes. + +{/* truncate */} + +## New Controls + +- [`AutoComplete`](https://flet.dev/docs/controls/autocomplete/) +- [`AutoFillGroup`](https://flet.dev/docs/controls/autofillgroup/) +- [`Flashlight`](https://flet.dev/docs/flashlight/) +- [`Geolocator`](https://flet.dev/docs/geolocator/) +- [`Map`](https://flet.dev/docs/map/) +- [`PermissionHandler`](https://flet.dev/docs/permission_handler/) + +## New Properties + +- [`Option`](https://flet.dev/docs/controls/dropdownoption/#flet.DropdownOption): `content`, `text_style` +- [`TextStyle`](https://flet.dev/docs/types/textstyle/): `baseline`, `overflow`, `word_spacing` + +## Error Handling + +> PEP 20 (Zen of Python): Errors should never pass silently. + +Several devs reported that, on some occasions, a control might visually break without clear information on what caused +the break. + +For example, in issue [#3149](https://github.com/flet-dev/flet/issues/3149), @base-13 mentioned that _"in a DataTable if +the number of columns is less than the number of datacells in any row it will grey out whole table without throwing +error"_. + +Knowing this, we added more assertion-checks in most of the controls, such that, when you provide them with a wrong +value, an AssertionError is raised with a very clear message of what was wrongly done. + +If you find out that some checks are still missing, please point them out so they can be addressed. + +## Command Line (CLI) Output + +The output of the `flet build` command has been prettified. + +Also, a new option has been added --show-platform-matrix which displays a table containing the build platform matrix, +which has header columns "Command" (possible build commands) and "Platform" (the device you should use with the +respective command). + +Furthermore, when the targeted platform can't be built on your device, a table displaying the build platform matrix is +shown with an informative message. + +## Breaking Changes + +While doing "Error Handling" mentioned above, we had to mark some important properties as required. + +The following properties are now "required" (must be provided and visible) when creating an instance of their classes: + +* [`AnimatedSwitcher.content`](https://flet.dev/docs/controls/animatedswitcher/#flet.AnimatedSwitcher.content) +* [`Banner.content`](https://flet.dev/docs/controls/banner/#flet.Banner.content), [`Banner.actions`](https://flet.dev/docs/controls/banner/#flet.Banner.actions) +* [`BottomSheet.content`](https://flet.dev/docs/controls/bottomsheet/#flet.BottomSheet.content) +* [`CupertinoActionSheetAction.content`](https://flet.dev/docs/controls/cupertinoactionsheetaction/#flet.CupertinoActionSheetAction.content) +* [`DataRow.cells`](https://flet.dev/docs/controls/datatable/) +* [`DataTable.columns`](https://flet.dev/docs/controls/datatable/) +* [`DragTarget.content`](https://flet.dev/docs/controls/dragtarget/#flet.DragTarget.content) +* [`Draggable.content`](https://flet.dev/docs/controls/draggable/#flet.Draggable.content) +* [`ExpansionTile.title`](https://flet.dev/docs/controls/expansiontile/#flet.ExpansionTile.title) +* [`MenuBar.controls`](https://flet.dev/docs/controls/menubar/#flet.MenuBar.controls) +* [`Pagelet.content`](https://flet.dev/docs/controls/pagelet/#flet.Pagelet.content) +* [`RadioGroup.content`](https://flet.dev/docs/controls/radio/#flet.Radio.content) +* [`SafeArea.content`](https://flet.dev/docs/controls/safearea/#flet.SafeArea.content) +* [`ShaderMask.shader`](https://flet.dev/docs/controls/shadermask/#flet.ShaderMask.shader) +* [`WindowDragArea.content`](https://flet.dev/docs/controls/windowdragarea/#flet.WindowDragArea.content) + +## Bug Fixes + +The below issues were successfully fixed: + +* [#3144](https://github.com/flet-dev/flet/issues/3144): `ScrollbarTheme.thickness` value not respected when not + interacting with +* [#3072](https://github.com/flet-dev/flet/issues/3072): High-resolution videos play laggy on Android TV devices. +* [#3023](https://github.com/flet-dev/flet/issues/3023): (Regression) Some `LineChart` colors not visually respected +* [#2989](https://github.com/flet-dev/flet/issues/2989): Color of [`Dropdown`](https://flet.dev/docs/controls/dropdown/) when disabled + doesn't reflect its disabled state +* [#1753](https://github.com/flet-dev/flet/issues/1753): [`Markdown`](https://flet.dev/docs/controls/markdown/) code block not selectable +* [#3097](https://github.com/flet-dev/flet/issues/3097): Hot-reload occurs when a file is opened +* [#1647](https://github.com/flet-dev/flet/issues/1647): [`Container.theme_mode`](https://flet.dev/docs/controls/container/#flet.Container.theme_mode) + not honoured when `Container.theme=None` +* [#3064](https://github.com/flet-dev/flet/issues/3064): [`Container.on_tap_down`](https://flet.dev/docs/controls/container/#flet.Container.on_tap_down) + not called when `Container.on_click=None` + +Special Thanks to the dynamic Flet community for reporting all the issues they encountered. We keep working hard on +solving the remaining ones. + +## Deprecations + +* All the `Page.window_***` properties are now deprecated and moved to [`Page.window`](https://flet.dev/docs/controls/page/#flet.Page.window) + property, which is of type [`Window`](https://flet.dev/docs/types/window/). + To migrate, simply use change `window_` to `window.` as seen below: + ```python + # before + page.window_height = 200 + page.on_window_event = lambda e: print(e.type) + + # now + page.window.height = 200 + page.window.on_event = lambda e: print(e.type) + ``` + +* `SafeArea.minimum` is deprecated and has been renamed + to [`minimum_padding`](https://flet.dev/docs/controls/safearea/#flet.SafeArea.minimum_padding) +* `MaterialState` enum is deprecated and has been renamed to [`ControlState`](https://flet.dev/docs/types/controlstate/) +* `NavigationDestination` is deprecated and has been renamed + to [`NavigationBarDestination`](https://flet.dev/docs/controls/navigationbardestination/#flet.NavigationBarDestination) + +Also, the deprecation policy has been modified. While Flet is pre-1.0, all deprecations will be removed from the API after the next 3 releases. +So the above deprecations made in v0.23.0 (and all the other deprecations made in the previous versions), will be removed in v0.26.0. + +That's it! :) + +Upgrade to Flet 0.23.0, test your apps and let us know how you find the new features we added. +If you have any questions, please join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Happy Flet-ing! diff --git a/website/blog/2024-08-31-flet-v-0-24-release-announcement.md b/website/blog/2024-08-31-flet-v-0-24-release-announcement.md new file mode 100644 index 0000000000..711dc51cb5 --- /dev/null +++ b/website/blog/2024-08-31-flet-v-0-24-release-announcement.md @@ -0,0 +1,174 @@ +--- +slug: flet-v-0-24-release-announcement +title: Flet v0.24.0 Release Announcement +authors: henri +tags: [releases] +--- + +I am very happy to announce the release of Flet version 0.24.0! +It comes with a very long list of bug fixes, several enhancements and new features. + +{/* truncate */} + +## New Controls + +- [`InteractiveViewer`](https://flet.dev/docs/controls/interactiveviewer/) +- [`Placeholder`](https://flet.dev/docs/controls/placeholder/) + +## New Properties + +- [`AudioRecorder`](https://flet.dev/docs/audio_recorder/): `cancel_recording()` +- [`Video`](https://flet.dev/docs/video/): `on_completed`, `on_track_changed` +- [`InputFilter`](https://flet.dev/docs/types/inputfilter/): `unicode`, `case_sensitive`, `dot_all`, `multiline` +- [`Geolocator`](https://flet.dev/docs/geolocator/): `on_error`, `on_position_change` +- [`Barchart`](https://flet.dev/docs/charts/bar_chart/), [`LineChart`](https://flet.dev/docs/charts/line_chart/): `tooltip_border_side`, `tooltip_direction`, `tooltip_fit_inside_horizontally`, `tooltip_fit_inside_vertically`, `tooltip_horizontal_offset`, `tooltip_margin`, `tooltip_max_content_width`, `tooltip_padding`, `tooltip_rounded_radius`, `tooltip_rotate_angle` +- [`Container`](https://flet.dev/docs/controls/container/): `decoration`, `foreground_decoration`, `ignore_interactions`, `image` +- [`Page`](https://flet.dev/docs/controls/page/), [`View`](https://flet.dev/docs/controls/view/): `decoration`, `foreground_decoration` +- [`CupertinoTextField`](https://flet.dev/docs/controls/cupertinotextfield/): `enable_scribble`, `image`, `obscuring_character`, `padding`, `scroll_padding`, `on_click` +- [`DataTable`](https://flet.dev/docs/controls/datatable/): `heading_row_alignment` +- [`TextField`](https://flet.dev/docs/controls/textfield/): `counter`, `disabled_hint_content`, `options_fill_horizontally` +- [`ExpansionTile`](https://flet.dev/docs/controls/expansiontile/): `min_tile_height`, `show_trailing_icon` +- [`Markdown`](https://flet.dev/docs/controls/markdown/): `fit_content`, `img_error_content`, `md_style_sheet`, `shrink_wrap`, `soft_line_break`, `on_selection_change` +- [`MenuItemButton`](https://flet.dev/docs/controls/menuitembutton/): `autofocus`, `overflow_axis`, `semantic_label` +- [`Tabs`](https://flet.dev/docs/controls/tabs/): `label_padding`, `label_text_style`, `padding`, `splash_border_radius`, `unselected_label_text_style`, `on_click` +- and lot of [new classes](https://flet.dev/docs/reference/) (enums, dataclasses, events)… + +## Enhancements +- Better string output of Events when printed +- `Image.filter_quality` now has a default of `FilterQuality.MEDIUM` (previously `FilterQuality.LOW`), which is a better default for downscaled images. +- `Geolocator` control has been improved to support location streaming through the newly added on_position_change event. When defined, you will be able to "listen" to location changes as they happen. +- When `AppBar.adaptive=True` and the app is running on an Apple platform, the `AppBar.actions` controls are now wrapped in a `Row`, then displayed. Before this, only the first item of `AppBar.actions` list was displayed. +- The `Markdown` control has been significantly improved. It can now display SVG images and be much more customized. +- A very requested feature was the ability to set a background image or gradient for the application. In [#3820](https://github.com/flet-dev/flet/pull/3820), we made this possible and easy to use. +- rtl (right-to-left) property has been added to more controls (`NavigationRailDestination`, `NavigationRail`, `AppBar`, `CupertinoAppBar`, and `NavigationDrawer` ) to improve support for right-to-left text directions. +- Introduced `--no-rich-output` flag (only in `flet build` command for now) to make it possible to disable rich output (mainly emojis) in the console. More information in [#3708](https://github.com/flet-dev/flet/pull/3708). +- Typing has been significantly improved, particularly for event-handler properties. In modern IDEs like PyCharm and VSCode, you can now easily determine the type of an event handler's argument by simply hovering over the event in the control. Additionally, the IDE will highlight errors when you attempt to access a non-existent property on the event handler argument, ensuring more robust and error-free code. + +## Bug Fixes + +The below issues were successfully fixed: + +- [#3769](https://github.com/flet-dev/flet/issues/3769): `InputFilter` clears the `TextField` text content when an invalid character is entered +- [#3770](https://github.com/flet-dev/flet/issues/3770): `Theme.floating_action_button_theme` non existent +- [#3734](https://github.com/flet-dev/flet/issues/3734): Ensure `Dropdown.alignment` is respected. +- [#3730](https://github.com/flet-dev/flet/issues/3730): `UnicodeEncodeError` raised when packaging on WindowOS +- [#2160](https://github.com/flet-dev/flet/issues/2160): `Markdown` control can't render svg images +- [#2158](https://github.com/flet-dev/flet/issues/2158): `Markdown` broken when an image is not found +- [#3679](https://github.com/flet-dev/flet/issues/3679): Broken `Dismissible` +- [#3670](https://github.com/flet-dev/flet/issues/3670): `Switch.height` and `Switch.width` not respected +- [#3612](https://github.com/flet-dev/flet/issues/3612), [#3566](https://github.com/flet-dev/flet/issues/3566): Broken `OnScrollEvent` +- [#3564](https://github.com/flet-dev/flet/issues/3564): Broken `TextField.capitalization` +- [#3649](https://github.com/flet-dev/flet/issues/3649): `CupertinoPicker` jumps-scroll on some platforms +- [#3557](https://github.com/flet-dev/flet/issues/3557): Impeller causes blank screen on mac Intel +- [#3574](https://github.com/flet-dev/flet/issues/3574): `Geolocator` not working on Android devices +- [#3505](https://github.com/flet-dev/flet/issues/3505): `WindowEventType` doesn't contain fullscreen all events + +Thanks to all those who reported them! + +## Deprecations + +All deprecated items from this release will be removed in version 0.27.0. + +- `ThemeVisualDensity` is deprecated and has been renamed to [`VisualDensity`](https://flet.dev/docs/types/visualdensity/) +- [`CupertinoButton`](https://flet.dev/docs/controls/cupertinobutton/): `disabled_color` is deprecated and has been renamed to `disabled_bgcolor`, which better reflects its use +- [`Markdown`](https://flet.dev/docs/controls/markdown/): `code_style` is deprecated and should now be accessed as `code_style_sheet.code_text_style` +- [`Container`](https://flet.dev/docs/controls/container/): `image_fit`, `image_opacity`, `image_repeat`, `image_src` and `image_src_base64` are deprecated and should now be accessed from `image` which is of type [`DecorationImage`](https://flet.dev/docs/types/decorationimage/) + +## Breaking Changes and Migration + +### Tooltip +The Tooltip class is no more a Flet control and is from now on a simple Python dataclass. The tooltip property (available in almost all controls) now supports both strings and Tooltip objects. + +Below is how to migrate: + +```python +# before +page.add( + ft.Tooltip( + message="This is tooltip", + content=ft.Text("Hover to see tooltip"), + padding=20, + border_radius=10, + ) +) + +# after +page.add( + ft.Text( + "Hover to see tooltip", + tooltip=ft.Tooltip( + message="This is tooltip", + padding=20, + border_radius=10, + ) + ) +) +``` + +### TextField InputFilter +We modified how `InputFilter.regex_string` is internally handled. As a result of this, you (might) now have to anchor your regex pattern. This simply implies using start (^) and end ($) regex anchors. +For example: `r"[0-9]"` now becomes `r"^[0-9]$"`. Using this new string will lead work as expected and only numbers/digits will be allowed, but you might notice another issue: the last character of the text field cannot be deleted. To resolve this, you need to add an asterisk (*) in the regex which in this case will simply mean "match zero or more digits (including an empty string)". The new regex now becomes `r"^[0-9]*$"`. +To ease this migration, you can use an AI tool with the following simple prompt: `"update the following regex pattern: #### ensuring that the entire string matches the pattern and it allows for an empty string"`. + +### Event-Handler subscription +The possibility to "subscribe" more than one callback to an event handler has been removed, as this was somehow biased (was only possible on some, and not all). +Below is a simple example: + +```python +import flet as ft + +def main(page: ft.Page): + def print_one(e): + print("1") + def print_two(e): + print("2") + def print_three(e): + print("3") + c = ft.Container( + bgcolor=ft.Colors.random_color(), + width=300, + height=300, + ) + + # subscribe callbacks + c.on_tap_down = print_one + c.on_tap_down = print_two + c.on_tap_down = print_three + page.add(c) + +ft.run(main) +``` + +In the above code, we subscribe multiple callbacks to the [`Container.on_tap_down`](https://flet.dev/docs/controls/container/#flet.Container.on_tap_down) event. Prior to Flet version 0.24.0, running this code and tapping on the `Container`, you will see all the callbacks getting called ("1", "2" and "3" are printed out). +From Flet version 0.24.0 going forward, one event = one callback. Meaning only the lastly subscribed callback will get executed ("3" is printed out) +So, if you still want the final output to resemble the first one you can simply create one callback which calls the others: + +```python + +def main(page: ft.Page): + #.... + + def print_all(e): + print_one(e) + print_two(e) + print_three(e) + + c = ft.Container( + bgcolor=ft.Colors.random_color(), + width=300, + height=300, + on_tap_down=print_all, + ) + + # OR + c.on_tap_down = print_all +``` + +## Conclusion +As you can see, we made a lot of changes in this release and as usual, your feedback is highly welcomed! + +Upgrade to Flet 0.24.0, test your apps and let us know how you find the new features we added. +If you have any questions, please join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Happy Flet-ing! 👾 diff --git a/website/blog/2024-10-10-flet-new-packaging-pre-release.md b/website/blog/2024-10-10-flet-new-packaging-pre-release.md new file mode 100644 index 0000000000..181f6bef52 --- /dev/null +++ b/website/blog/2024-10-10-flet-new-packaging-pre-release.md @@ -0,0 +1,300 @@ +--- +slug: flet-new-packaging-pre-release +title: Flet new packaging pre-release +authors: feodor +--- + +Flet packaging for iOS and Android has been relying on Kivy and it was super annoying when your app depends on Python binary packages, such as Numpy or Pillow. You needed to compile those packages yourself using Kivy command line tools. It was really frustrating and even hopeless if Kivy didn't have "recipes" for some packages, like Pydantic. + +Kivy no more! We've just published Flet 0.25.0.dev3519 pre-release with the improved `flet build` command which does not use Kivy! Flet is now using its own Python runtime "meticulously crafted in-house". + +Flet packaging implementation for iOS and Android adheres to strict specifications defined in [PEP 730](https://peps.python.org/pep-0730/) (iOS) and [PEP 738](https://peps.python.org/pep-0738/) (Android) which were implemented and released in Python 3.13 (and back-ported to Python 3.12). When pypi.org supports wheel tags for iOS and Android and 3rd-party Python package maintainers start uploading their mobile packages Flet will be compatible with them and you'll be able to use them in your Flet app. + +{/* truncate */} + +## Installing pre-release + +``` +pip install flet==0.25.0.dev3519 +``` + +:::note +For testing purposes we suggest installing Flet pre-release in a dedicated Python virtual environment. +::: + +## Building the app with pre-release + +To build your app with `flet build` command and pre-release version of Flet make sure your `requirements.txt` either contains exact version specifier: + +``` +flet==0.25.0.dev3519 +``` + +or `--pre` flag before `flet` dependency: + +``` +--pre +flet +``` + +## Python 3.12 + +Packaged Flet app runs on Python 3.12.6 runtime for all platforms. + +## Pre-built binary packages + +`flet build` command for iOS and Android is now installing pre-built binary packages from https://pypi.flet.dev. + +New packages can be built with creating a recipe in [Mobile Forge](https://github.com/flet-dev/mobile-forge) project. For now, Flet team is authoring those recipes for you, but when the process is polished and fully-automated you'll be able to send a PR and test the compiled package right away. + +If you don't yet see a package at https://pypi.flet.dev you can request it in [Flet discussions - Packages](https://github.com/flet-dev/flet/discussions/categories/packages). Please do not request pure Python packages. Go to package's "Download files" section at https://pypi.org and make sure it contains binary platform-specific wheels. + +Packaging behavior was changed too: + +- The packaging is not trying to replace `flet` dependency with `flet-runtime`, `flet-embed` or `flet-pyodide`, but install all dependencies "as is" from `requirements.txt` or `pyproject.toml` - thanks to the new Flet packages structure (link). +- If the binary package for target platform is not found the packaging won't be trying to compile it from source distribution, but will fail instead with a meaningful error. + +## New packages structure + +The structure avoids rewriting pip dependencies while installing `flet` package on various platforms. There was a problem of detecting the correct `flet` package to install (`flet-runtime`, `flet-embed` or`flet-pyodide`?) if `flet` was not a direct dependency in user's app. + +New Flet packages: + +* `flet` - required for minimal Flet setup, app entry point for various platforms. Installed on all platforms. +* `flet-core` - required for minimal Flet setup, core logic and controls. Installed on all platforms. +* `flet-cli` - contains Flet CLI commands. Installed on desktop only. +* `flet-desktop` - contains pre-built Flet "client" app binary for macOS, Windows and Linux. By default installed on macOS and Windows desktops only. +* `flet-desktop-light` - contains a light-weight version (without Audio and Video controls) of Flet "client" for Linux. By default installed on Linux desktops only. +* `flet-web` - contains Flet web "client" and FastAPI integration. Installed on desktop only. + +Other words, packaged Flet app contains only `flet` and `flet-core` packages. + +### "Light" client for Linux + +A light-weight desktop client, without Audio and Video controls, is not installed on Linux by default. It improves initial user experience as user doesn't need to immediately deal with gstreamer (audio) and mpv (video) dependencies right away and Flet "just works". + +Once user got some Flet experience and wants to use Video and Audio controls in their application they can install gstreamer and/or mpv and replace Flet desktop with a full version. + +Uninstall "light" Flet client: + +``` +pip uninstall flet-desktop-light --yes +``` + +Install full Flet desktop client: + +``` +pip install flet-desktop==0.25.0.dev3519 +``` + +## Permissions + +New `flet build` command allows granular control over permissions, features and entitlements embedded into `AndroidManifest.xml`, `Info.plist` and `.entitlements` files. + +No more hard-coded permissions in those files! + +### iOS + +Setting iOS permissions: + +``` +flet build --info-plist permission_1=True|False|description permission_2=True|False|description ... +``` + +For example: + +``` +flet build --info-plist NSLocationWhenInUseUsageDescription=This app uses location service when in use. +``` + +### macOS + +Setting macOS entitlements: + +``` +flet build --macos-entitlements name_1=True|False name_2=True|False ... +``` + +Default macOS entitlements: + +* `com.apple.security.app-sandbox = False` +* `com.apple.security.cs.allow-jit = True` +* `com.apple.security.network.client = True` +* `com.apple.security.network.server" = True` + +### Android + +Setting Android permissions and features: + +``` +flet build --android-permissions permission=True|False ... --android-features feature_name=True|False +``` + +For example: + +``` +flet build \ + --android-permissions android.permission.READ_EXTERNAL_STORAGE=True \ + android.permission.WRITE_EXTERNAL_STORAGE=True \ + --android-features android.hardware.location.network=False +``` + +Default Android permissions: + +* `android.permission.INTERNET` + +Default permissions can be disabled with `--android-permissions` option and `False` value, for example: + +``` +flet build --android-permissions android.permission.INTERNET=False +``` + +Default Android features: + +* `android.software.leanback=False` (`False` means it's written in manifest as `android:required="false"`) +* `android.hardware.touchscreen=False` + +### Cross-platform permission groups + +There are pre-defined permissions that mapped to `Info.plist`, `*.entitlements` and `AndroidManifest.xml` for respective platforms. + +Setting cross-platform permissions: + +``` +flet build --permissions permission_1 permission_2 ... +``` + +Supported permissions: + +* `location` +* `camera` +* `microphone` +* `photo_library` + +#### iOS mapping to `Info.plist` entries + +* `location` + * `NSLocationWhenInUseUsageDescription = This app uses location service when in use.` + * `NSLocationAlwaysAndWhenInUseUsageDescription = This app uses location service.` +* `camera` + * `NSCameraUsageDescription = This app uses the camera to capture photos and videos.` +* `microphone` + * `NSMicrophoneUsageDescription = This app uses microphone to record sounds.` +* `photo_library` + * `NSPhotoLibraryUsageDescription = This app saves photos and videos to the photo library.` + +#### macOS mapping to entitlements + +* `location` + * `com.apple.security.personal-information.location = True` +* `camera` + * `com.apple.security.device.camera = True` +* `microphone` + * `com.apple.security.device.audio-input = True` +* `photo_library` + * `com.apple.security.personal-information.photos-library = True` + +#### Android mappings + +* `location` + * permissions: + * `android.permission.ACCESS_FINE_LOCATION": True` + * `android.permission.ACCESS_COARSE_LOCATION": True` + * `android.permission.ACCESS_BACKGROUND_LOCATION": True` + * features: + * `android.hardware.location.network": False` + * `android.hardware.location.gps": False` +* `camera` + * permissions: + * `android.permission.CAMERA": True` + * features: + * `android.hardware.camera": False` + * `android.hardware.camera.any": False` + * `android.hardware.camera.front": False` + * `android.hardware.camera.external": False` + * `android.hardware.camera.autofocus": False` +* `microphone` + * permissions: + * `android.permission.RECORD_AUDIO": True` + * `android.permission.WRITE_EXTERNAL_STORAGE": True` + * `android.permission.READ_EXTERNAL_STORAGE": True` +* `photo_library` + * permissions: + * `android.permission.READ_MEDIA_VISUAL_USER_SELECTED": True` + +## Control over app compilation and cleanup + +`flet build` command is no longer compiling app `.py` files into `.pyc` by default which allows you to avoid (defer?) discovery of any syntax errors in your app and complete the packaging. + +You can control the compilation and cleanup with the following new options: + +* `--compile-app` - compile app's `.py` files. +* `--compile-packages` - compile installed packages' `.py` files. +* `--cleanup-on-compile` - remove unnecessary files upon successful compilation. + +## Signing Android bundles + +Added new options for signing Android builds: + +* `--android-signing-key-store` - path to an upload keystore `.jks` file for Android apps. +* `--android-signing-key-store-password` - Android signing store password. +* `--android-signing-key-alias` - Android signing key alias. Default is "upload". +* `--android-signing-key-password` - Android signing key password. + +Read [Build and release an Android app](https://docs.flutter.dev/deployment/android#signing-the-app) for more information on how to configure upload key for Android builds. + +## "Data" and "Temp" directories for the app + +Flet developers have been asking where to store application data, such as uploaded files, SQLite databases, etc. that are persistent across application updates. + +This release introduce two environment variables that are available in your Flet apps: + +* `FLET_APP_STORAGE_DATA` - directory for storing application data that is preserved between app updates. That directory is already pre-created. +* `FLET_APP_STORAGE_TEMP` - directory for temporary application files, i.e. cache. That directory is already pre-created. + +For example, data folder path can be read in your app as: + +``` +import os + +# it's `None` when running the app in web mode +data_dir = os.getenv("FLET_APP_STORAGE_DATA") +``` + +:::note +`flet run` command creates data and temp directories and sets `FLET_APP_STORAGE_DATA` and `FLET_APP_STORAGE_TEMP` to their paths. +::: + +## Deep linking configuration + +There is a new `--deep-linking-url` option to configure deep linking for iOS and Android builds. The value must be in the format `://`. + +## Faster re-builds + +Ephemeral Flutter app created by `flet build` command is not re-created all the time in a temp directory, but cached in `build/flutter` directory which gives faster re-builds, improves packaging troubleshooting and does not pollute temp directory. + +## Split APKs per ABI + +`flet build` now provides the built-in `--split-per-abi` option to split the APKs per ABIs. + +## Known pre-release issues + +* `flet publish` is not yet working. + +## What else coming in the release + +We would like to include a few more things into Flet 0.25.0 release. Expect more pre-releases in the coming weeks. + +### `pyproject.toml` support + +It's inconvenient and bulky to carry all `flet build` settings as command line options. + +You will be able to store project and build settings in `[tool.flet]` section of `pyproject.toml`. + +### Running Flet app on simulator + +We will add an option to `flet build` and run packaged app on a real device or simulator. + +### Installing Flutter + +`flet build` will download and configure Flutter for you if there is no suitable installation available on your machine. diff --git a/website/blog/2024-10-15-pyproject-toml-support-for-flet-build-command.md b/website/blog/2024-10-15-pyproject-toml-support-for-flet-build-command.md new file mode 100644 index 0000000000..39c76ae156 --- /dev/null +++ b/website/blog/2024-10-15-pyproject-toml-support-for-flet-build-command.md @@ -0,0 +1,299 @@ +--- +slug: pyproject-toml-support-for-flet-build-command +title: pyproject.toml support for flet build command +authors: feodor +--- + +The number of options for `flet build` command grew substantially over the time and it's been inconvenient to carry all these settings in a command line. + +Today, we are excited to announce another Flet pre-release which now allows configuring app build settings in `pyproject.toml`! + +{/* truncate */} + +## Installing pre-release + +``` +pip install flet==0.25.0.dev3526 +``` + +:::note +For testing purposes we suggest installing Flet pre-release in a dedicated Python virtual environment. +::: + +## Building the app with pre-release + +To build your app with `flet build` command and pre-release version of Flet make sure your `requirements.txt` either contains exact version specifier: + +``` +flet==0.25.0.dev3526 +``` + +or `--pre` flag before `flet` dependency: + +``` +--pre +flet +``` + +## Quick start + +Create the following minimal `pyproject.toml` file in the root of your Flet app or run `flet create` to create a new app from template: + +```toml +[project] +name = "my_app" +version = "1.0.0" +description = "My first Flet project" +authors = [ + {name = "John Smith", email = "john@email.com"} +] +dependencies = ["flet==0.25.0.dev3526"] +``` + +:::note +With `pyproject.toml`, you no longer need `requirements.txt`. However, if a `requirements.txt` file exists in the app's directory, the flet build command will prioritize reading dependencies from it instead of those listed in `pyproject.toml`. +::: + +`[project]` is the standard required section of `project.toml`. + +:::note +Flet also supports `[tool.poetry]` section created by Poetry which contains project settings. +::: + +A minimal `pyproject.toml` for Poetry, which is also supported by `flet build` command, is the following: + +```toml +[tool.poetry] +name = "my_app" +version = "1.0.0" +description = "My first Flet project" +authors = ["John Smith "] + +[tool.poetry.dependencies] +python = "^3.10" +flet = "0.25.0.dev3526" +``` + +`project.name` (or `tool.poetry.name`) corresponds to `--project` option of `flet build` command and it will be the name of app bundle or executable. The value of `project.name` will be "slugified" where all non-alphanumeric values are replaced with dashes `-`. + +`project.version` (or `tool.poetry.version`) corresponds to `--build-version` option and it is a value in "x.y.z" string used as the version number shown to users. + +`project.description` (or `tool.poetry.description`) corresponds to `--description` option which is the description to use for executable or bundle. + +:::note +`project.authors` and `tool.poetry.authors` are not used by `flet build`, but required by a standard and other tools. +::: + +### Overriding config with CLI options + +All settings in `pyproject.toml` have corresponding `flet build` CLI options. If you run the flet build command and specify options that are already configured in `pyproject.toml`, the CLI option values will override those from the configuration file. + +## Project dependencies + +List project dependencies in `project.dependencies` section. The value is an array with pip-like requirement specifiers: + +``` +[project] +dependencies = [ + "flet==0.25.0.dev3526", + "numpy" +] +``` + +## Product information + +All Flet specific settings should be put into `[tool.flet]` section and sub-sections below it. + +Product information settings complement the ones in `[project]` section and allows configuring app bundle identifier and product display name. + +```toml +[tool.flet] +org = "com.mycompany" # --org +product = "Product name" # --product +company = "My Company" # --company +copyright = "Copyright (C) 2024 by MyCompany" # --copyright +build_number = 1 # --build-number +``` + +## App package contents + +The following settings control the contents of Python app archive and compilation of app/packages sources. + +```toml +[tool.flet] +app.module = "main" # --module-name +app.path = "src" # path to Python app relative to `pyproject.toml` +app.exclude = ["assets"] # --exclude + +compile.app = false # --compile-app +compile.packages = false # --compile-packages +compile.cleanup = false # --cleanup-on-compile +``` + +They could be alternatively written under their own sub-sections as: + +```toml +[tool.flet.app] +module = "main" +path = "src" +exclude = ["assets"] + +[tool.flet.compile] +app = false +packages = false +cleanup = false +``` + +## Splash + +```toml +[tool.flet.splash] +color = "" # --splash-color +dark_color = "" # --splash-dark-color +web = false # --no-web-splash +ios = false # --no-ios-splash +android = false # --no-android-splash +``` + +## Permissions + +```toml +[tool.flet] +permissions = ["camera", "microphone"] # --permissions +``` + +## Deep linking + +```toml +[tool.flet.deep_linking] +scheme = "https" # --deep-linking-scheme +host = "mydomain.com" # --deep-linking-host +``` + +### Android settings + +```toml +[tool.flet.android] +adaptive_icon_background = "" # --android-adaptive-icon-background +split_per_abi = false # --split-per-abi +``` + +Permissions (notice quotes `"` around key names): + +```toml +[tool.flet.android.permission] # --android-permissions +"android.permission.CAMERA" = true +"android.permission.CAMERA" = true +``` + +Features (notice quotes `"` around key names): + +```toml +[tool.flet.android.feature] # --android-features +"android.hardware.camera" = false +``` + +Android-specific deep-linking: + +```toml +[tool.flet.android.deep_linking] +scheme = "https" # --deep-linking-scheme +host = "mydomain.com" # --deep-linking-host +``` + +Android bundle signing options: + +```toml +[tool.flet.android.signing] +# store and key passwords can be passed with `--android-signing-key-store-password` +# and `--android-signing-key-password` options or +# FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD +# and FLET_ANDROID_SIGNING_KEY_PASSWORD environment variables. +key_store = "path/to/store.jks" # --android-signing-key-store +key_alias = "upload" +``` + +### iOS settings + +```toml +[tool.flet.ios] +team = "team_id" # --team + +[tool.flet.ios.info] # --info-plist +NSCameraUsageDescription = "This app uses the camera to ..." + +[tool.flet.ios.info.deep_linking] +scheme = "https" +host = "mydomain.com" +``` + +### macOS settings + +```toml +[tool.flet.macos] +entitlement."com.apple.security.personal-information.photos-library" = true +``` + +```toml +[tool.flet] +build_arch = "arm64" # --arch - if arch is not specified Flet will build universal package for both arm64 and x86_64 archs +``` + +### Web settings + +```toml +[tool.flet.web] +base_url = "/" # --base-url +renderer = "canvaskit" # --web-renderer +use_color_emoji = false # --use-color-emoji +route_url_strategy = "path" # --route-url-strategy +``` + +## Flutter settings + +### Dependencies + +```toml +flutter.dependencies = ["flet_video", "flet_audio"] # --include-packages +``` + +or with alternative syntax with versions: + +```toml +[tool.flet.flutter.dependencies] +flet_video = "1.0.0" +flet_audio = "2.0.0" +``` + +or with path to the package on your disk: + +```toml +[tool.flet.flutter.dependencies.my_package] +path = "/path/to/my_package" +``` + +### Extra build args + +flutter.build_args = ["--some-flutter-arg"] # --flutter-build-args + +### Extra `pubspec.yaml` settings + +Allows injecting arbitrary content into resulting `pubspec.yaml`, for example: + +```toml +[tool.flet.flutter.pubspec.dependency_overrides] +web = "1.0.0" +``` + +## Custom template + +```toml +[tool.flet.template] +path = "gh:some-github/repo" # --template +dir = "" # --template-dir +ref = "" # --template-ref +``` + +That's it! Upgrade to Flet 0.25.0.dev3526, give this new feature and try and let us know what you think! + +Cheers! diff --git a/website/blog/2024-11-27-flet-v-0-25-release-announcement.md b/website/blog/2024-11-27-flet-v-0-25-release-announcement.md new file mode 100644 index 0000000000..c2ed9c75e8 --- /dev/null +++ b/website/blog/2024-11-27-flet-v-0-25-release-announcement.md @@ -0,0 +1,314 @@ +--- +slug: flet-v-0-25-release-announcement +title: Flet v0.25.0 Release Announcement +authors: feodor +tags: [releases] +--- + +Hey Flet developers, we’ve got something exciting to share — Flet 0.25.0 is officially released! + +The biggest news? No more Kivy for iOS and Android packaging. No more dealing with frustrating Python binary dependencies — Flet now uses its own custom Python runtime, so your app builds are easier than ever. Plus, we’ve added loads of new features like better permissions control, faster rebuilds, and even a lightweight Linux client that skips the bloat. + +Let’s dive into all the cool stuff Flet 0.25.0 has to offer! 🚀 + +{/* truncate */} + +## How to upgrade + +Run the following command to upgrade Flet: + +``` +pip install 'flet[all]' --upgrade +``` + +:::note +`[all]` is an "extra" specifier which tells pip to install all `flet` package dependencies. See [New Python packages structure](#new-python-packages-structure) section below for the explanation. +::: + +Bump `flet` package version to `0.25.0` (or remove it at all to use the latest) in `requirements.txt` or `pyproject.toml`. + +## New packaging + +Flet packaging for iOS and Android has been relying on Kivy and it was super annoying when your app depends on Python binary packages, such as Numpy or Pillow. You needed to compile those packages yourself using Kivy command line tools. It was really frustrating and even hopeless if Kivy didn't have "recipes" for some packages, like Pydantic. + +Flet does not depend on Kivy anymore and uses its own Python runtime "meticulously crafted in-house". + +Flet packaging implementation for iOS and Android adheres to strict specifications defined in [PEP 730](https://peps.python.org/pep-0730/) (iOS) and [PEP 738](https://peps.python.org/pep-0738/) (Android) which were implemented and released in Python 3.13 (and back-ported to Python 3.12). When pypi.org supports wheel tags for iOS and Android and 3rd-party Python package maintainers start uploading their mobile packages Flet will be compatible with them and you'll be able to use them in your Flet app. + +### Pre-built binary packages + +`flet build` command for iOS and Android is now installing pre-built binary packages from https://pypi.flet.dev. + +New packages can be built with creating a recipe in [Mobile Forge](https://github.com/flet-dev/mobile-forge) project. For now, Flet team is authoring those recipes for you, but when the process is polished and fully-automated you'll be able to send a PR and test the compiled package right away. + +If you don't yet see a package you require at https://pypi.flet.dev, you can request it in [Flet discussions - Packages](https://github.com/flet-dev/flet/discussions/categories/packages). Please do not request pure Python packages. Go to package's "Download files" section at https://pypi.org and make sure it contains binary platform-specific wheels. + +Packaging behavior was changed too: + +- The packaging is not trying to replace `flet` dependency with `flet-runtime`, `flet-embed` or `flet-pyodide`, but install all dependencies "as is" from `requirements.txt` or `pyproject.toml` - thanks to the [new Flet packages structure](#new-python-packages-structure). +- If the binary package for target platform is not found the packaging won't be trying to compile it from source distribution, but will fail instead with a meaningful error. + +### Python 3.12 + +Packaged Flet app runs on Python 3.12.7 runtime on all platforms. + +### Permissions + +New `flet build` command allows granular control over permissions, features and entitlements embedded into `AndroidManifest.xml`, `Info.plist` and `.entitlements` files. + +No more hard-coded permissions in those files! + +For example, setting permissions for iOS bundle: + +``` +flet build --info-plist NSLocationWhenInUseUsageDescription="This app uses location service when in use." +``` + +or the same in `pyproject.toml` (read about `pyproject.toml` support below): + +```toml +[tool.flet.ios.info] # --info-plist +NSLocationWhenInUseUsageDescription = "This app uses location service when in use." +``` + +An example of setting Android permissions and features: + +``` +flet build \ + --android-permissions android.permission.READ_EXTERNAL_STORAGE=True \ + android.permission.WRITE_EXTERNAL_STORAGE=True \ + --android-features android.hardware.location.network=False +``` + +[Read more about permissions in the docs](https://flet.dev/docs/publish/#permissions). + +### Control over app compilation and cleanup + +`flet build` command is no longer compiling app `.py` files into `.pyc` by default which allows you to defer discovery of any syntax errors in your app and complete the packaging. + +You can control the compilation and cleanup with the following new options: + +* `--compile-app` - compile app's `.py` files. +* `--compile-packages` - compile installed packages' `.py` files. +* `--cleanup-on-compile` - remove unnecessary files upon successful compilation. + +### Signing Android bundles + +We also added new options for signing Android builds: + +* `--android-signing-key-store` - path to an upload keystore `.jks` file for Android apps. +* `--android-signing-key-store-password` - Android signing store password. +* `--android-signing-key-alias` - Android signing key alias. Default is "upload". +* `--android-signing-key-password` - Android signing key password. + +Read [Build and release an Android app](https://docs.flutter.dev/deployment/android#signing-the-app) for more information on how to configure upload key for Android builds. + +### Deep linking configuration + +There is a new `--deep-linking-url` option to configure deep linking for iOS and Android builds. The value must be in the format `://`. + +### Faster re-builds + +Ephemeral Flutter app created by `flet build` command is no longer being re-created on every build in a temp directory, but cached in `build/flutter` directory which gives faster re-builds, improves packaging troubleshooting and does not pollute user temp directory. + +You can use `--clear-cache` option to do a clean build though. + +### Split APKs per ABI + +`flet build` now provides the built-in `--split-per-abi` option to split the APKs per ABIs. + +## "Data" and "Temp" directories for the app + +Flet developers have been asking where to store application data, such as uploaded files, SQLite databases, etc. that are persistent across application updates. + +This release introduce two environment variables that are available in your Flet apps: + +* `FLET_APP_STORAGE_DATA` - directory for storing application data that is preserved between app updates. That directory is already pre-created and its location depends on the platform the app is running on. +* `FLET_APP_STORAGE_TEMP` - directory for temporary application files, i.e. cache. That directory is already pre-created and its location depends on the platform the app is running on. + +For example, data folder path can be read in your app as: + +``` +import os + +# it's `None` when running the app in web mode +data_dir = os.getenv("FLET_APP_STORAGE_DATA") +``` + +:::note +`flet run` command creates data and temp directories and sets `FLET_APP_STORAGE_DATA` and `FLET_APP_STORAGE_TEMP` to their paths. +::: + +## `pyproject.toml` support + +It's inconvenient and bulky to carry all `flet build` settings as command line options. + +In Flet 0.25.0 release is now possible to configure `flet build`, `flet run`, and `flet publish` settings in `pyproject.toml`! + +Flet adds `tool.flet` section and sub-sections to `pyproject.toml`. Here's the minimal version of `pyproject.toml` you can put into root folder of your app: + +```toml +[project] +name = "my_app" +version = "1.0.0" +description = "My first Flet project" +authors = [ + {name = "John Smith", email = "john@email.com"} +] +dependencies = ["flet"] +``` + +You can also generate a starting `pyproject.toml` (and other files) for your project with `flet create` command. + + +## New Python packages structure + +We re-factored Flet Python packages and removed `flet-core`, `flet-runtime`, `flet-embed` or`flet-pyodide` packages. + +The new structure avoids rewriting pip dependencies while installing `flet` package on various platforms. There was a problem of detecting the correct `flet` package to install (`flet-runtime`, `flet-embed` or`flet-pyodide`?) if `flet` was not a direct dependency in user's app. + +New Flet packages: + +* `flet` - required for minimal Flet setup, app entry point for various platforms with core logic and controls. Installed on all platforms. +* `flet-cli` - contains Flet CLI commands. Installed on desktop only. +* `flet-desktop` - contains pre-built Flet "client" app binary for macOS, Windows and Linux. By default installed on macOS and Windows desktops only. +* `flet-desktop-light` - contains a light-weight version (without Audio and Video controls) of Flet "client" for Linux. By default installed on Linux desktops only. +* `flet-web` - contains Flet web "client" and FastAPI integration. Installed on desktop only. + +Packaged Flet app contains only `flet` package now. + +### `flet` package extras + +`flet` package defines the following extras that can be specified when installing Flet with pip, uv, poetry and other package manager: + +* `flet[all]` - installs `flet`, `flet-cli`, `flet-desktop` and `flet-web`. Recommended for development. +* `flet[cli]` - installs `flet` and `flet-cli`. Can be used in CI environment for packaging only. +* `flet[web]` - installs `flet` and `flet-web`. Used for deploying Flet web apps. +* `flet[desktop]` - installs `flet` and `flet-desktop`. Used for desktop-only development. + +### New Flet install and upgrade commands + +Starting from this release the development version of `flet` package should be installed with the following command: + +``` +pip install 'flet[all]' +``` + +Upgrading `flet` package: + +``` +pip install 'flet[all]' --upgrade +``` + +:::note +`pip install flet` still works too, but it will install `flet` package only and dependent packages will be installed on demand. For example, when you run any `flet` CLI command `flet-cli` will be installed, or when you run `flet run` command `flet-desktop` package will be installed. +::: + +## "Light" client for Linux + +A lightweight desktop client, without Audio and Video controls, is now installed on Linux by default. It improves initial user experience as user doesn't need to immediately deal with `gstreamer` (audio) and `mpv` (video) dependencies and Flet "just works". + +Once user got some Flet experience and wants to use Video and Audio controls in their application they can install gstreamer and/or mpv and replace Flet desktop with a full version. + +Uninstall "light" Flet client: + +``` +pip uninstall flet-desktop-light --yes +``` + +Install full Flet desktop client: + +``` +pip install flet-desktop +``` + +## New controls + +* Mobile Ads (`Banner` and `Interstitial`) ([details and example](https://github.com/flet-dev/flet/pull/3288)). +* `Button` control ([#4265](https://github.com/flet-dev/flet/pull/4265)) - which is just an alias for `ElevatedButton` control. + +## Breaking changes + +* Refactor `Badge` Control to a Dataclass; added new `badge` property to all controls ([#4077](https://github.com/flet-dev/flet/pull/4077)). + +Below is how to migrate: + +```python +# before + page.navigation_bar = ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination( + icon_content=ft.Badge( + content=ft.Icon(ft.Icons.PHONE), + text=10, + ), + label="Calls", + ), + ] + ) + +# after + page.navigation_bar = ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination( + icon=ft.Icon( + ft.Icons.PHONE, + badge="10", + ), + label="Calls", + ), + ] + ) +``` + +## Other changes + +* Added `{value_length}`, `{max_length}`, and `{symbols_left}` placeholders to `TextField.counter_text` ([#4403](https://github.com/flet-dev/flet/pull/4403)). +* Added `--skip-flutter-doctor` to build cli command ([#4388](https://github.com/flet-dev/flet/pull/4388)). +* `WebView` enhancements ([#4018](https://github.com/flet-dev/flet/pull/4018)). +* `Map` control enhancements ([#3994](https://github.com/flet-dev/flet/pull/3994)). +* Exposed more `Theme` props ([#4278](https://github.com/flet-dev/flet/pull/4278), [#4278](https://github.com/flet-dev/flet/pull/4278)). +* Exposed more properties in multiple Controls ([#4105](https://github.com/flet-dev/flet/pull/4105)) +* Added `__contains__` methods in container-alike Controls ([#4374](https://github.com/flet-dev/flet/pull/4374)). +* Added a custom `Markdown` code theme ([#4343](https://github.com/flet-dev/flet/pull/4343)). +* Added `barrier_color` prop to dialogs ([#4236](https://github.com/flet-dev/flet/pull/4236)). +* Merged `icon` and `icon_content` props into `icon: str | Control` ([#4305](https://github.com/flet-dev/flet/pull/4305)). +* Migrated `colors` and `icons` variables to Enums ([#4180](https://github.com/flet-dev/flet/pull/4180)). +* TextField: `suffix_icon`, `prefix_icon` and `icon` can be `Control` or `str` ([#4173](https://github.com/flet-dev/flet/pull/4173)). +* Added `--pyinstaller-build-args` to `flet pack` CLI command ([#4187](https://github.com/flet-dev/flet/pull/4187)). +* Made SearchBar's view height adjustable; added new properties ([#4039](https://github.com/flet-dev/flet/pull/4039)). +* Bumped Rive version and fixed Linux app build template for `rive_common`. + +## Bug fixes + +* Fixed `Icon` rotation ([#4384](https://github.com/flet-dev/flet/pull/4384)). +* Fixed regression in `Markdown.code_theme` when using `MarkdownCodeTheme` enum ([#4373](https://github.com/flet-dev/flet/pull/4373)). +* Fixed `Segment` and `NavigationBarDestination` accept only string tooltips ([#4326](https://github.com/flet-dev/flet/pull/4326)). +* Display informative message when `date` has wrong format ([#4019](https://github.com/flet-dev/flet/pull/4019)). +* Fixed `MapConfiguration.interaction_configuration` is not honoured ([#3976](https://github.com/flet-dev/flet/pull/3976)). +* Fixed `Video.jump_to()` fails with negative indexes ([#4294](https://github.com/flet-dev/flet/pull/4294)). +* Fixed condition in `AppBar.tooltip_opacity` ([#4280](https://github.com/flet-dev/flet/pull/4280)). +* Fixed wrong type (asyncio.Future -> concurrent.futures.Future) and handle `CancelledError` ([#4268](https://github.com/flet-dev/flet/pull/4268)). +* Fixed clicking on `CupertinoContextMenuAction` doesn't close context menu ([#3948](https://github.com/flet-dev/flet/pull/3948)). +* Fixed dropdown `max_menu_height` ([#3974](https://github.com/flet-dev/flet/pull/3974)). +* Fixed prevent button style from being modified in `before_update()` ([#4181](https://github.com/flet-dev/flet/pull/4181)). +* Fixed disabling filled buttons is not visually respected ([#4090](https://github.com/flet-dev/flet/pull/4090)). +* when `label` is set, use `MainAxisSize.min` for the `Row` ([#3998](https://github.com/flet-dev/flet/pull/3998)). +* Fixed `NavigationBarDestination.disabled` has no visual effect ([#4073](https://github.com/flet-dev/flet/pull/4073)). +* Fixed autofill in `CupertinoTextField` ([#4103](https://github.com/flet-dev/flet/pull/4103)). +* Linechart: `jsonDecode` tooltip before displaying ([#4069](https://github.com/flet-dev/flet/pull/4069)). +* Fixed button's `bgcolor`, `color` and `elevation` ([#4126](https://github.com/flet-dev/flet/pull/4126)). +* Fixed scrolling issues on Windows ([#4145](https://github.com/flet-dev/flet/pull/4145)). +* Skip running flutter doctor on windows if `no_rich_output` is `True` ([#4108](https://github.com/flet-dev/flet/pull/4108)). +* Fixed `TextField` freezes on Linux Mint #4422](https://github.com/flet-dev/flet/pull/4422)). + +## Conclusion + +Flet 0.25.0 is a huge release and your feedback is highly welcomed! + +Upgrade to Flet 0.25.0, test your apps and let us know how you find the new features we added. + +If you have any questions, please join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Happy Flet-ing! 👾 diff --git a/website/blog/2025-01-24-flet-v-0-26-release-announcement.md b/website/blog/2025-01-24-flet-v-0-26-release-announcement.md new file mode 100644 index 0000000000..a3b3f8bd5b --- /dev/null +++ b/website/blog/2025-01-24-flet-v-0-26-release-announcement.md @@ -0,0 +1,141 @@ +--- +slug: flet-v-0-26-release-announcement +title: Flet v0.26.0 Release Announcement +authors: feodor +tags: [releases] +--- + +The Flet 0.26.0 release is here, featuring a significant update to the extensibility approach! + +In summary, a Flet extension is now a single Python package that bundles both Python and Flutter code. This package can be part of your Flet project or hosted in a public Git repository or PyPI. + +Built-in Flet extensions, such as `Audio`, `Video`, and `Map`, have been moved to their own repositories. You’re welcome to fork these extensions to create your own or contribute to Flet! These extensions have been published to PyPI, making them easy to include in your Flet app. To use them, simply add the desired extensions to the `dependencies` section of your `pyproject.toml` file. + +{/* truncate */} + +## How to upgrade + +Run the following command to upgrade Flet: + +``` +pip install 'flet[all]' --upgrade +``` + +:::note +`[all]` is an "extra" specifier which tells pip to install or upgrade all `flet` packages: `flet`, `flet-cli`, `flet-desktop` and `flet-web`. +::: + +Bump `flet` package version to `0.26.0` (or remove it at all to use the latest) in your `pyproject.toml`. + +## Extensibility changes + +### Built-in extensions + +Flet controls based on 3rd-party Flutter packages that used to be a part of Flet repository, now have been moved to separate repos and published on pypi: + +* [flet-ads](https://pypi.org/project/flet-ads/) +* [flet-audio](https://pypi.org/project/flet-audio/) +* [flet-audio-recorder](https://pypi.org/project/flet-audio-recorder/) +* [flet-flashlight](https://pypi.org/project/flet-flashlight/) +* [flet-geolocator](https://pypi.org/project/flet-geolocator/) +* [flet-lottie](https://pypi.org/project/flet-lottie/) +* [flet-map](https://pypi.org/project/flet-map/) +* [flet-permission-handler](https://pypi.org/project/flet-permission-handler/) +* [flet-rive](https://pypi.org/project/flet-rive/) +* [flet-video](https://pypi.org/project/flet-video/) +* [flet-webview](https://pypi.org/project/flet-webview/) + +To use a built-in Flet extension in your project, add it to the `dependencies` section of your `pyproject.toml` file, for example: + +``` +dependencies = [ + "flet-audio", + "flet>=0.26.0", +] +``` + +### User extensions + +Flet now makes it easy to create and build projects with your custom controls based on Flutter widgets or Flutter 3rd-party packages: + +1. Create new virtual environment and [install Flet](https://flet.dev/docs/getting-started/installation/#virtual-environment) there. + +2. Create new Flet extension project from template: + +``` +flet create --template extension --project-name my-control +``` + +A project with new MyControl control will be created. The control is just a Flutter Text widget with a single `text` property. + +3. Build your app. + +Flet project created from extension template has `examples/my_control_example` folder with the example app. + +When in the folder where your `pyproject.toml` for the app is, run `flet build` command, for example, for macOS: + +``` +flet build macos -v +``` + +Run the app and see the new custom Flet Control: + +``` +open build/macos/my-control-example.app +``` + + + +Read more about how to customise your extension [here](https://flet.dev/docs/extend/user-extensions/). + +## Development environment configuration + +To enhance the developer experience with the `flet build` command, Flet 0.26.0 ensures that the correct versions of Flutter SDK, Java (JDK), and Android SDK are installed. If any of these are missing or outdated, it automatically installs them for you. + +You still need to install Visual Studio 2022 yourself if you're building a Flet app for Windows, or Xcode if you're building for iOS or macOS. + +In the next releases we are going to introduce automatic configuration and startup of Android and iOS emulators. + +## Flutter 3.27 + +Flet has been migrated to Flutter SDK 3.27. See [this pull request](https://github.com/flet-dev/flet/pull/4703) for new and updated control properties. + +## Python 3.9 + +Flet 0.26.0 requires Python 3.9 or later. Python 3.8 has reached [EOL](https://devguide.python.org/versions/). + +## Other changes + +* Optional on-demand creation of `ListView.controls` ([#3931](https://github.com/flet-dev/flet/issues/3931)) +* Reset `InteractiveViewer` transformations ([#4391](https://github.com/flet-dev/flet/issues/4391)) +* Passthrough of mouse events from main window to other applications ([#1438](https://github.com/flet-dev/flet/issues/1438)) +* Implemented `Window.ignore_mouse_events` ([#4465](https://github.com/flet-dev/flet/pull/4465)) +* Adding Google/Android TV platform support ([#4581](https://github.com/flet-dev/flet/pull/4581)) +* Remove `Optional[]` from predefined typing `*Value`s ([#4702](https://github.com/flet-dev/flet/pull/4702)) +* Throttle `InteractiveViewer` update events ([#4704](https://github.com/flet-dev/flet/pull/4704)) +* Remove v0.26.0-related deprecations ([#4456](https://github.com/flet-dev/flet/issues/4456)) + +## Bug fixes + +* Fixed: Update project_dependencies.py ([#4459](https://github.com/flet-dev/flet/pull/4459)) +* Fixed: `SafeArea` object has no attribute `_SafeArea__minimum` ([#4500](https://github.com/flet-dev/flet/pull/4500)) +* Fixed: Tooltip corruption in `Segment` and `BarChartRod` on `update()` ([#4525](https://github.com/flet-dev/flet/pull/4525)) +* Fixed: Setting `CheckBox.border_side.stroke_align` to an Enum fails ([#4526](https://github.com/flet-dev/flet/pull/4526)) +* Fixed: `ControlState` should be resolved based on user-defined order ([#4556](https://github.com/flet-dev/flet/pull/4556)) +* Fixed: broken `Dismissible.dismiss_direction` ([#4557](https://github.com/flet-dev/flet/pull/4557)) +* Fixed: Fix Rive not updating ([#4582](https://github.com/flet-dev/flet/pull/4582)) +* Fixed: `DatePicker` regression with first and last dates ([#4661](https://github.com/flet-dev/flet/pull/4661)) +* `flet build` command: Copy `flutter-packages`, support for platform-specific dependencies ([#4667](https://github.com/flet-dev/flet/pull/4667)) +* Fixed: `CupertinoBottomSheet` applies a red color and yellow underline to `Text` content ([#4673](https://github.com/flet-dev/flet/pull/4673)) +* Fixed: setting `ButtonTheme` displays a grey screen ([#4731](https://github.com/flet-dev/flet/pull/4731)) +* Fixed: `Textfield` input border color considers user-specified `border_color` property ([#4735](https://github.com/flet-dev/flet/pull/4735)) +* Fixed: make `Tooltip.message` a required parameter ([#4736](https://github.com/flet-dev/flet/pull/4736)) + +## Conclusion + +Upgrade to Flet 0.26.0, test your apps and let us know how you find the new features we added. + +If you have any questions, please join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Happy Flet-ing! 👾 diff --git a/website/blog/2025-02-20-flet-v-0-27-release-announcement.md b/website/blog/2025-02-20-flet-v-0-27-release-announcement.md new file mode 100644 index 0000000000..0f159842b7 --- /dev/null +++ b/website/blog/2025-02-20-flet-v-0-27-release-announcement.md @@ -0,0 +1,120 @@ +--- +slug: flet-v-0-27-release-announcement +title: Flet v0.27.0 Release Announcement +authors: feodor +tags: [releases] +--- + +Flet 0.27.0 is now released with exciting new features and improvements! + +* **iOS packaging & signing updates** – ensures compliance with App Store Connect verification requirements. +* **Reduced startup delay** – faster initial launch for desktop applications. +* **Faster incremental re-builds** – enhances development efficiency with quicker iteration times. +* **Enhanced Dropdown control** – improved functionality and user experience. +* **Bug fixes & stability improvements** – various fixes to enhance overall performance and reliability. + +{/* truncate */} + +## How to upgrade + +Run the following command to upgrade Flet: + +``` +pip install 'flet[all]' --upgrade +``` + +:::note +`[all]` is an "extra" specifier which tells pip to install or upgrade all `flet` packages: `flet`, `flet-cli`, `flet-desktop` and `flet-web`. +::: + +Bump `flet` package version to `0.27.0` (or remove it at all to use the latest) in your `pyproject.toml`. + +## Revamped iOS Packaging + +* Third-party Flet app dependencies (also known as “site packages” like `numpy`, `pandas`, `flet`, etc.) are now bundled inside a framework, ensuring Xcode signs all files correctly and passes App Store Connect verification. +* New `flet build` options for proper iOS package signing. +* Comprehensive step-by-step documentation for packaging and deploying iOS apps. [Learn more!](https://flet.dev/docs/publish/ios/) + +## Enhanced startup performance for desktop apps + +Currently, when packaging for macOS, Windows, and Linux, third-party Flet app dependencies (e.g., numpy, pandas, flet, etc.), also known as **site packages**, are bundled inside the app.zip artifact. This can cause a startup delay, sometimes significant, as the app needs to extract the artifact to the user’s file system before launching. + +With Flet 0.27.0, site packages are now copied in an **unpacked state** directly into the application bundle instead of being compressed into app.zip. This change significantly reduces the first launch time. + +## Faster incremental re-builds + +If certain parts of the build configuration remain unchanged, the `flet build` command attempts to skip or optimize specific build pipeline steps (such as re-installing Flet app dependencies), reducing the overall completion time for consecutive builds. + +Faster builds mean happier developers! 😄 + +## Pyodide 0.27.2 + +Pyodide 0.27.2 is based on Python 3.12 and has some serious performance improvements to foreign function interface (FFI). + +Flet now supports Python 3.12 across all packaging platforms. + +The next stop is Python 3.13! + +## Enhanced `Dropdown` control. + +Since version 0.27.0, Flet uses [DropdownMenu](https://api.flutter.dev/flutter/material/DropdownMenu-class.html) flutter widget for [Dropdown](https://flet.dev/docs/controls/dropdown/) control, which is a Material 3 version of previously used DropdownButton. Additionally to enhanced look and feel, it allows filter the list based on the text input or search one item in the menu list. + + + +Some properties of previous Dropdown implementation are not available in the new version and were "stubbed" - they will not break your program but don't do anything. See the list of deprecated properties [here](https://flet.dev/docs/controls/dropdown/). + +Previous version of Dropdown control is available as [`DropdownM2`](https://flet.dev/docs/controls/dropdownm2/) control and will be removed in Flet 0.30.0. + +## 💥 Breaking changes + +### `flet build` command + +- `--team` option renamed to `--ios-team-id`. +- `--include-packages` has been removed. Just add extension package into `dependencies` section of your `pyproject.toml` file: https://flet.dev/docs/extend/built-in-extensions/ +- `--cleanup-on-compile` removed and two new options added to separate cleanup of app and 3rd-party site packages: `--cleanup-app` and `--cleanup-packages`. Two additional options: `--cleanup-app-files` and `--cleanup-package-files` work together with `--cleanup-*` and allow specifying lists of globs to exclude from app and site packages. +- `tool.flet.build_arch` renamed to `tool.flet.target_arch`. + +### Removed `v0.24.0` Deprecations + +The following items, deprecated in Flet 0.24.0, have been removed: https://flet.dev/blog/flet-v-0-24-release-announcement#deprecations + +### `CupertinoCheckbox.inactive_color` property + +The `inactive_color` property of the [`CupertinoCheckbox`](https://flet.dev/docs/controls/cupertinocheckbox/) has been removed in favor of [`fill_color`](https://flet.dev/docs/controls/cupertinocheckbox/#flet.CupertinoCheckbox.fill_color). + +## Other changes + +The full list of changes can be found in the [CHANGELOG](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md). + +### New features + +* feat: `ReorderableListView` Control ([#4865](https://github.com/flet-dev/flet/pull/4865)) +* feat: Implement `Container.dark_theme` property ([#4857](https://github.com/flet-dev/flet/issues/4857)) +* Upgrade to Pyodide 0.27 for `httpx` Support ([#4840](https://github.com/flet-dev/flet/issues/4840)) +* Remove `CupertinoCheckbox.inactive_color` in favor of `fill_color` ([#4837](https://github.com/flet-dev/flet/issues/4837)) +* feat: `flet build`: use Provisioning Profile to sign iOS app archive (`.ipa`), deprecate `--team` option ([#4869](https://github.com/flet-dev/flet/issues/4869)) +* feat: `flet doctor` CLI command ([#4803](https://github.com/flet-dev/flet/pull/4803)) +* feat: implement button themes (for `ElevatedButton`, `OutlinedButton`, `TextButton`, `FilledButton`, `IconButton `) ([#4872](https://github.com/flet-dev/flet/pull/4872)) +* feat: `ControlEvent.data` should be of type `Optional[str]` and default to `None` ([#4786](https://github.com/flet-dev/flet/issues/4786)) +* feat: `flet build`: add `--source-packages` to allow installing certain Python packages from source distros ([#4762](https://github.com/flet-dev/flet/issues/4762)) + +### Bug fixes + +* Fixed: Disable rich's Markup for stdout logs ([#4795](https://github.com/flet-dev/flet/issues/4795)) +* Fixed: Setting `SearchBar.bar_border_side` isn't visually honoured ([#4767](https://github.com/flet-dev/flet/issues/4767)) +* Fixed: Dropdown: Long options cause the down-arrow to overflow ([#4838](https://github.com/flet-dev/flet/issues/4838)) +* Fixed: CupertinoSlider initialisation does not allow values less then zero/greater then 1 ([#4853](https://github.com/flet-dev/flet/issues/4853)) +* Fixed: Same code shows different appearance in Flet APP/Web/PC local. ([#4855](https://github.com/flet-dev/flet/issues/4855)) +* Fixed: Transforming scale renders a grey screen ([#4759](https://github.com/flet-dev/flet/issues/4759)) +* Fixed: UnicodeDecodeError when using accented characters in manifest.json ([#4713](https://github.com/flet-dev/flet/issues/4713)) +* Fixed: Implement `SearchBar.blur()` to programmatically unfocus the bar ([#4827](https://github.com/flet-dev/flet/issues/4827)) +* Fixed: Disable markup for flet-cli stdout logs ([#4796](https://github.com/flet-dev/flet/pull/4796)) + +## Conclusion + +Upgrade to Flet 0.27.0, test your apps and let us know how you find the new features we added. + +If you have any questions, please join [Flet Discord server](https://discord.gg/dzWXP8SHG8) or create a new thread +on [Flet GitHub discussions](https://github.com/flet-dev/flet/discussions). + +Happy Flet-ing! 👾 diff --git a/website/blog/2025-02-23-tap-into-native-android-and-ios-apis-with-pyjnius-and-pyobjus.md b/website/blog/2025-02-23-tap-into-native-android-and-ios-apis-with-pyjnius-and-pyobjus.md new file mode 100644 index 0000000000..2f8d893e1f --- /dev/null +++ b/website/blog/2025-02-23-tap-into-native-android-and-ios-apis-with-pyjnius-and-pyobjus.md @@ -0,0 +1,185 @@ +--- +slug: tap-into-native-android-and-ios-apis-with-Pyjnius-and-pyobjus +title: Tap into native Android and iOS APIs with Pyjnius and Pyobjus +authors: feodor +tags: [news] +--- + +When building mobile apps with Flet, you may need to interact directly with platform-specific APIs. Whether it’s accessing system information, managing Bluetooth devices, or working with user preferences, **Pyjnius** and **Pyobjus** by Kivy provide a seamless way to bridge Python with Java (for Android) and Objective-C (for iOS). + +You can now integrate both Pyjnius and Pyobjus into your Flet apps! 🚀 + +{/* truncate */} + +## Pyjnius for Android + +Pyjnius is a Python library for accessing Java classes using the **Java Native Interface** (JNI). + +### Adding to a project + +Add `pyjnius` dependency for Android builds only (other settings in `pyproject.toml` were omitted for brevity): + +```toml +[project] +name = "pyjnius_demo" +version = "0.1.0" +dependencies = [ + "flet==0.27.1" +] + +[tool.flet.android] +dependencies = [ + "pyjnius" +] +``` + +### Usage examples + +Here are some example of how Pyjnius can be used in your Flet Android app. + +#### Getting Android OS details + +```python +from jnius import autoclass + +# Get Build and Build.VERSION classes +Build = autoclass('android.os.Build') +Version = autoclass('android.os.Build$VERSION') + +# Get OS details +device_model = Build.MODEL +manufacturer = Build.MANUFACTURER +brand = Build.BRAND +hardware = Build.HARDWARE +product = Build.PRODUCT +device = Build.DEVICE +os_version = Version.RELEASE +sdk_version = Version.SDK_INT +``` + +#### Listing Bluetooth devices + +```python +from jnius import autoclass + +# Get BluetoothAdapter instance +BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter') +bluetooth_adapter = BluetoothAdapter.getDefaultAdapter() + +if bluetooth_adapter is None: + print("Bluetooth not supported on this device") +else: + if not bluetooth_adapter.isEnabled(): + print("Bluetooth is disabled. Please enable it.") + else: + print("Bluetooth is enabled.") + + # Get paired devices + paired_devices = bluetooth_adapter.getBondedDevices() + for device in paired_devices.toArray(): + print(f"Device Name: {device.getName()}, MAC Address: {device.getAddress()}") +``` + +### Accessing the Activity + +App main activity instance can be retrieved with the following code: + +```python +import os +from jnius import autoclass + +activity_host_class = os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME") +assert activity_host_class +activity_host = autoclass(activity_host_class) +activity = activity_host.mActivity +``` + +Heck, you can basically call any Android API using Pyjnius - endless possibilities! + +Check complete [Flet Pyjnius example](https://github.com/flet-dev/python-package-tests/tree/main/pyjnius). + +For more Pyjnius examples and API refer to the [Pyjnius Documentation](https://Pyjnius.readthedocs.io/en/latest/quickstart.html). + +...or just use ChatGPT (or your favorite LLM) to get more ideas and solutions! 😅 + +## Pyobjus for iOS + +Pyobjus is a library for accessing Objective-C classes as Python classes using Objective-C runtime reflection. + +### Adding to a project + +Add `pyobjus` dependency for iOS builds only (other settings in `pyproject.toml` were omitted for brevity): + +```toml +[project] +name = "Pyjnius" +version = "0.1.0" +dependencies = [ + "flet==0.27.1" +] + +[tool.flet.ios] +dependencies = [ + "pyobjus" +] +``` + +### Usage examples + +#### The simplest example + +```python +from pyobjus import autoclass + +NSString = autoclass('NSString') +text = NSString.alloc().initWithUTF8String_('Hello world') +print(text.UTF8String()) +``` + +#### Getting OS details + +```python +from pyobjus import autoclass +from pyobjus.dylib_manager import load_framework, INCLUDE + +# Load Foundation framework +load_framework(INCLUDE.Foundation) + +# Get NSProcessInfo instance +NSProcessInfo = autoclass('NSProcessInfo') +process_info = NSProcessInfo.processInfo() + +# Retrieve OS version as a string +os_version = process_info.operatingSystemVersionString.UTF8String() + +print(f"iOS Version: {os_version}") +``` + +#### Working with app user settings + +```python +from pyobjus import autoclass, objc_str + +NSUserDefaults = autoclass('NSUserDefaults') + +key = "pyobjus_hello_world_key" +value = "Hello, world!" + +# set key +NSUserDefaults.standardUserDefaults().setObject_forKey_(objc_str(value), objc_str(key)) + +# get key +ret = NSUserDefaults.standardUserDefaults().stringForKey_(objc_str(key)) + +assert ret.UTF8String() == value +``` + +Check complete [Flet Pyobjus example](https://github.com/flet-dev/python-package-tests/tree/main/pyobjus). + +For more Pyobjus examples and API refer to the [Pyobjus Documentation](https://pyobjus.readthedocs.io/en/latest/quickstart.html). + +## Plyer challenge + +There is a [Plyer](https://github.com/kivy/plyer) project by Kivy team which uses both Pyjnius and Pyobjus under the hood. + +It's not ported to Flet yet. You can either get more usage examples for [Android](https://github.com/kivy/plyer/tree/master/plyer/platforms/android) and [iOS](https://github.com/kivy/plyer/tree/master/plyer/platforms/ios) from there or help us with porting it to Flet. diff --git a/website/blog/2025-06-26-introducing-flet-1-0-alpha.md b/website/blog/2025-06-26-introducing-flet-1-0-alpha.md new file mode 100644 index 0000000000..85ff4d7b7a --- /dev/null +++ b/website/blog/2025-06-26-introducing-flet-1-0-alpha.md @@ -0,0 +1,507 @@ +--- +slug: introducing-flet-1-0-alpha +title: Introducing Flet 1.0 Alpha +authors: feodor +tags: [news] +--- + +Flet has been in the making for over three years, steadily gaining traction and building a vibrant user community. As more developers adopt Flet for real-world projects, one thing has become clear: people are ready to commit — but they also want to see the same commitment from us. + +Releasing **Flet 1.0** isn’t just about a version number. It’s about signaling stability, maturity, and long-term vision. A stable API, comprehensive documentation, better testing and clearly communicated roadmap — these are the foundational pieces developers need to confidently build serious apps on Flet. + +But **Flet 1.0 isn’t just the next incremental release. It’s a complete re-architecture**. + +The first versions of Flet inherited design decisions from Pglet — a web-based framework with a focus on multi-language support. While that served as a useful starting point, Flet has since evolved into a Python-centric framework for building cross-platform apps — web, desktop, and mobile. + +With that evolution came technical debt, architectural misfits, and increasing complexity. Rather than patch over the cracks, we made a bold decision: to rewrite Flet from the ground up. It’s always risky to rewrite, but there’s no better time than now — before 1.0 — while the user base is still manageable and we can afford to break things in the name of long-term simplicity and maintainability. + +After nearly five months of work, **today we’re releasing the Flet 1.0 Alpha — a technical preview of what’s coming.** + +{/* truncate */} + +## What’s new + +Flet 1.0 introduces major changes that simplify how you build, run, and scale apps. Some are improvements, some are breaking — all are focused on giving you a faster, more flexible developer experience. + +* **Declarative approach to building Flet apps** - alongside the traditional imperative style. +* **Auto-update** - automatic page updates after event handler completion. +* **Services** - persistent, non-UI components that live across UI rebuilds and navigation. Existing controls such as `Audio`, `FilePicker`, `Clipboard` were re-written as services. +* **Complete WASM (WebAssembly) support for web apps** - faster download and performance on modern browsers. +* **Offline (no-CDN) mode for web apps** - Flutter resources and Pyodide are bundled with the app. +* **Embedding Flet apps into existing web page** - render Flet app into an HTML element on any web page. +* **Enhanced Extensions API** - to export services along with controls, with a room for future customizations like splash and loading screens. + +### Declarative approach + +Flet 1.0 introduces a **declarative/reactive approach** to building UIs in Flet. Developers can now mix **imperative** and **declarative** patterns in the same app, enabling more flexible and functional UI code. + +#### Basic declarative Flet app example + +```py +from dataclasses import dataclass + +import flet as ft + + +@dataclass +class AppState: + count: int + + def increment(self): + self.count += 1 + + +def main(page: ft.Page): + state = AppState(count=0) + + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, on_click=state.increment + ) + page.add( + ft.ControlBuilder( + state, + lambda state: ft.SafeArea( + ft.Container( + ft.Text(value=f"{state.count}", size=50), + alignment=ft.Alignment.center(), + ), + expand=True, + ), + expand=True, + ) + ) + + +ft.run(main) +``` + +More declarative examples: + +* [Edit form](https://github.com/flet-dev/examples/blob/v1/python/apps/declarative/edit-form.py) +* [Progress bar with yield](https://github.com/flet-dev/examples/blob/v1/python/apps/declarative/progress-with-yield.py) +* 🚀 [Reactive ToDo app](https://github.com/flet-dev/examples/blob/v1/python/apps/todo/todo-reactive.py) + +🚧 Documentation is in progress 🚧 + +### Auto-update + +`Control.update()` is now automatically called once its event handler method is finished. +Most of Flet apps will now work without explicit `update()` calls. + +Use `yield` inside long-running event handlers to refresh UI, for example: + +```py +async def button_click(): + progress.value = "Something started" + yield + await asyncio.sleep(3) + progress.value = "Something finished" +``` + +🚧 Documentation is in progress 🚧 + +### Services + +"Service" is a persistent, non-visual control that can "survive" page updates and navigation transitions. + +Some of the existing controls were re-implemented as services (breaking change): + +* `Audio` ([extension](https://pypi.org/project/flet-audio/)) +* `AudioRecorder` ([extension](https://pypi.org/project/flet-audio-recorder/)) +* `FilePicker` +* `Flashlight` ([extension](https://pypi.org/project/flet-flashlight/)) +* `Geolocator` ([extension](https://pypi.org/project/flet-geolocator/)) +* `HapticFeedback` +* `InterstitialAd` ([extension](https://pypi.org/project/flet-ads/)) +* `PermissionHandler` ([extension](https://pypi.org/project/flet-permission-handler/)) +* `SemanticsService` +* `ShakeDetector` + +Service instances must be added to `page.services` list to work. + +### WebAssembly support + +Flet 1.0 web apps use WebAssembly (WASM) by default on [selected browsers](https://docs.flutter.dev/platform-integration/web/wasm#learn-more-about-browser-compatibility). + +Built-in Flet web client and Flet apps built with `flet build web` are now include both Dart2JS (with CanvasKit as a renderer) and WebAssembly (with SKWASM renderer) targets. + +🚧 Documentation is in progress 🚧 + +### Offline mode for web apps + +Flet 1.0 has "no-CDN" mode which allows bundling the following resources along with your app instead of loading them from external CDNs: + +* CanvasKit +* SkWASM +* Pyodide +* Fonts + +To enable no-CDN during runtime either add `no_cdn=True` to `ft.run()` (it's a new `ft.run()`) call: + +```py +ft.run(main, no_cdn=True) +``` + +or set `FLET_WEB_NO_CDN` environment variable to `1`, `true` or `yes`. + +To enable no-CDN for `flet build` add `--no-cdn` argument. + +🚧 Documentation is in progress 🚧 + +### Embedding Flet web apps + +You can now embed a Flet web app into any HTML element within an existing web page. + +It's also possible to render multiple views of the same app in different HTML elements. + +🚧 Documentation is in progress 🚧 + +### Enhanced Extensions API + +The new extensions API allows exporting from your Flutter package of both control and service widgets. Technically, an extension is a class now rather than a method which will allow us to add more hooks into it like custom splash and loading screens. + +For example, `flet-ads` extension before has just one `createControl` method: + +```dart title="create_control.dart" +import 'package:flet/flet.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import 'banner.dart'; +import 'interstitial.dart'; + +CreateControlFactory createControl = (CreateControlArgs args) { + switch (args.control.type) { + case "banner_ad": + return BannerAdControl( + parent: args.parent, control: args.control, backend: args.backend); + case "interstitial_ad": + return InterstitialAdControl( + parent: args.parent, control: args.control, backend: args.backend); + default: + return null; + } +}; + +void ensureInitialized() { + if (isMobilePlatform()) { + MobileAds.instance.initialize(); + } +} +``` + +and for Flet v1 it has two methods `createWidget` and `createService`: + +```dart title="extension.dart" +import 'package:flet/flet.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:google_mobile_ads/google_mobile_ads.dart'; + +import 'banner.dart'; +import 'interstitial.dart'; + +class Extension extends FletExtension { + @override + void ensureInitialized() { + if (isMobilePlatform()) { + MobileAds.instance.initialize(); + } + } + + @override + FletService? createService(Control control) { + switch (control.type) { + case "InterstitialAd": + return InterstitialAdService(control: control); + default: + return null; + } + } + + @override + Widget? createWidget(Key? key, Control control) { + switch (control.type) { + case "BannerAd": + return BannerAdControl(control: control); + default: + return null; + } + } +} +``` + +This change is breaking. + +🚧 Documentation is in progress 🚧 + +### Other changes and improvements + +### `ft.run` with `before_main` + +A new `before_main` arg added to `ft.run()` (replaces `ft.run()`). `before_main` is a hook that allows to reliable configure page-level event handlers before Flutter client starts sending events. `before_main` is a function that accepts one parameter: `page: ft.Page` + +Example usage: + +```py +def config(page: ft.Page): + page.on_resize = lambda e: print("Page resized!") + +def main(page: ft.Page): + page.add(ft.Text("Hello!")) + +ft.run(main, before_main=config) +``` + +#### Storage paths + +There is a new `page.storage_paths` multi-platform API based on [path_provider](https://pub.dev/packages/path_provider) for finding commonly used locations on the filesystem: + +```py +get_application_cache_directory_async(self) -> str +get_application_documents_directory_async(self) -> str +get_application_support_directory_async(self) -> str +get_downloads_directory_async(self) -> Optional[str] +get_external_cache_directories_async(self) -> Optional[List[str]] +get_external_storage_directories_async(self) -> Optional[List[str]] +get_library_directory_async(self) -> str +get_external_cache_directory_async(self) -> Optional[str] +get_temporary_directory_async(self) -> str +get_console_log_filename_async(self) -> str +``` + +🚧 Documentation is in progress 🚧 + +#### Event handlers without `e` + +Event handlers can now omit `e` parameter, for example both of these work: + +```py +button_1.on_click = lambda: print("Clicked!") +button_2.on_click = lambda e: print("Clicked!", e) +``` + +or + +```py +def increment(): + print("Increment clicked") + +inc_btn.on_click = increment +``` + +#### `Control.before_event(e)` hook + +The method is called before calling any event handler. + +It receives an instance of `ControlEvent` as parameter and should return either `True` or `False`. Returning `False` cancels event handler. Example implementation in `Page` class: + +```py + def before_event(self, e: ControlEvent): + if isinstance(e, RouteChangeEvent): + if self.route == e.route: + return False + self.query() + return super().before_event(e) +``` + +#### `ft.context.page` works everywhere + +It's now possible to get a reference to a current `Page` instance in any part of Flet program. + +## The new Architecture + +Flet 1.0 is not just a feature release — it's a ground-up rewrite designed to address technical debt, improve maintainability, and unlock long-term performance and flexibility. Here are some of the most impactful architectural changes: + +### Simplified Python control implementation + +- Controls are now implemented as Python **dataclasses**, bringing: + - Automatic constructor generation + - Native support for default values, type annotations, and field validation + - No more manual conversions to/from `str` or `JSON` + - Seamless support for **complex property types** (nested dataclasses, enums, etc.) + +- This significantly reduces boilerplate and makes adding new controls trivial — often zero-maintenance. + +### Strong typing and IDE support + +- Event handlers are now **strongly typed**, improving both runtime safety and developer ergonomics. +- All controls include **docstrings**, enabling rich auto-generated API documentation with **Docusaurus**. + +### Smarter UI diffing + +- A new **diffing algorithm** powers efficient updates to the UI tree. +- It’s optimized for both **imperative** and **declarative** Flet programming styles. +- This results in faster rebuilds and fewer unnecessary redraws. + +### Dart runtime modernization + +- Replaced the old Redux-based state management with **InheritedWidget** + **Provider**. +- The internal control hierarchy on the Dart side now mirrors the Python control tree, enabling **more efficient traversal and updates**. + +### Binary protocol for performance + +- A new **binary serialization protocol** (MessagePack) replaces the JSON-based message format: + - Significantly reduces traffic size + - No more base64 encoding for transferring binary data (e.g., images, files) + +- Control property names in Dart now **exactly match their Python counterparts**, making it easier to debug and extend across both runtimes. + +## Breaking changes + +Flet 1.0 is a major release and includes breaking changes — for good reason! + +The Flet team maintains a list of known breaking changes in [this issue](https://github.com/flet-dev/flet/issues/5238). + +If you discover something else that’s broken or incorrect, please submit a new issue or discussion. Once confirmed, we’ll update the list. + +Below is a summary of the most significant and impactful breaking changes: + +### Single-threaded async UI model + +Flet 1.0 adopts a single-threaded async UI model, similar to JavaScript or Flutter. This design makes concurrency more predictable and better suited for the browser and mobile platforms. + +* Blocking calls like `time.sleep()` will freeze the UI. Instead of `time.sleep()` use `async def` event handlers and using `await asyncio.sleep()` for delays. +* Switch to async APIs whenever possible. +* For CPU-bound tasks, offload them to threads using `asyncio.to_thread(...)`. + +🚧 Example with CPU-bound method updating progress bar 🚧 + +### Async control methods + +All controls' get- and set- methods are async now. + +Methods that do not return any results have fire-and-forget sync wrappers. + +🚧 Documentation is in progress 🚧 + +### `ft.run()` replaces `ft.run()` + +`target` argument renamed to `main` and the rest of method arguments stays the same. A new `before_main` argument added (see above). + +### `Page` split + +`Page` split into `Page` and `PageView`. + +To support Flet embedding with multi-views. + +It's not a breaking-change per-se if you just continue to use `page` instance methods or properties. + +🚧 Documentation is in progress 🚧 + +### Dialogs + +To display a dialog, banner, snack bar, drawer, or any similar popup control, use `page.show_dialog(dialog_control)` instead of `page.open()`. + +To close the topmost popup, use `page.pop_dialog()`. + +### Drawers + +`page.drawer` and `page.end_drawer` were removed. + +:::note +We might re-introduce this in the future, to fix displaying of the top menu icon button as in this [example](https://api.flutter.dev/flutter/material/Scaffold/endDrawer.html). +::: + +Use `NavigationDrawer.position` property and then `page.show_dialog()` to display drawer instead of `page.drawer` and `page.end_drawer`. + +### FilePicker + +FilePicker is now a service and must be added to `page.services` list to work. + +API re-worked to provide async methods immediately returning dialog results without using "result" event handlers. + +```py +files: list[FilePickerFile] = await file_picker.pick_files_async(allow_multiple=True) +file_name: str = await file_picker.save_file_async() +dir_name: str = await file_picker.get_directory_path_async() +``` + +Full examples: + +* [All dialogs](https://github.com/flet-dev/examples/blob/v1/python/controls/utility/file-picker/file-picker-all-modes.py) +* [Upload](https://github.com/flet-dev/examples/blob/v1/python/controls/utility/file-picker/file-picker-upload-progress.py) + +### Clipboard + +Instead of `page.set_clipboard()` use `page.clipboard.set_async()`. + +Instead of `page.get_clipboard()` use `page.clipboard.get_async()`. + +### Client storage + +"Client storage" is now "Shared Preferences". + +`page.client_storage` property renamed to `page.shared_preferences`. + +### Scrollables + +In scrollable controls `on_scroll_interval` property renamed to `scroll_interval`. + +### Buttons + +All buttons: no `text` property, use `content` instead. + +### Charts + +Chart controls have been moved to a separate package [flet-charts](https://pypi.org/project/flet-charts/). + +### Control ID is integer + +`e.target` is a number now, not a string. + +## Trying Flet 1.0 Alpha + +We are releasing Flet 1.0 Alpha as [0.70.0.devXXXX](https://pypi.org/project/flet/#history). + +:::info +Going forward Flet 1.0 will be called `v1` and Flet 0.x will be called `v0`. + +`main` branch of Flet repository will have Flet 1.0 and `v0` branch will have Flet 0.x. +::: + +:::caution +Make sure you are installing Flet pre-release to a new virtual environment. +::: + +To install Flet v1 Alpha with pip: + +``` +pip install --pre 'flet[all]>=0.70.0.dev0' +``` + +or install with uv: + +``` +uv add 'flet[all]>=0.70.0.dev0' --prerelease=allow +``` + +or add `flet >=0.70.0.dev0` to dependencies of your Python project. + +### `flet build` + +To make `flet build` work with Flet 1.0 Alpha specify exact version of `flet` and all extension packages in `dependencies` section of your `pyproject.toml`: + +``` +dependencies=[ + "flet >=0.70.0.dev0", + "flet-audio >=0.2.0.dev0", + "flet-video >=0.2.0.dev0", + ... +] +``` + +Extensions for Flet v1 will have version `0.2.x` and above and Flet v0 extensions will have version `0.1.x`. + +## Roadmap to Flet 1.0 + +* Flet 0.70 aka "**Flet 1.0 Alpha**" - this release. Generated docs are not yet included. We may release a few Flet 0.71, 0.72, 0.73, etc. to fix things. +* Flet 0.80 aka "**Flet 1.0 Beta**" - docs generated from sources are ready. All extensions are working and documented. Integration tests are available. +* Flet 0.90 aka "**Flet 1.0 RC**" - website landing page is updated, API complete and frozen. +* Flet 1.0 aka "**Flet 1.0 RTM**" - final release! :tada: + +## Conclusion + +Flet 1.0 Alpha marks the beginning of a new chapter for the framework — one focused on performance, maintainability, and developer experience. It introduces a streamlined architecture, a powerful declarative programming model, and a reimagined extension system — all while laying the groundwork for a stable and scalable 1.0 release. + +This is a technical preview, and while it's not production-ready yet, we invite you to try it out, share your feedback, and help us shape the future of Flet. + +We’re incredibly excited about what’s coming next — and we’re just getting started. diff --git a/website/blog/2025-10-08-introducing-declarative-ui-in-flet.md b/website/blog/2025-10-08-introducing-declarative-ui-in-flet.md new file mode 100644 index 0000000000..e882f6edf0 --- /dev/null +++ b/website/blog/2025-10-08-introducing-declarative-ui-in-flet.md @@ -0,0 +1,398 @@ +--- +slug: introducing-declarative-ui-in-flet +title: Introducing Declarative UI in Flet +authors: feodor +tags: [news] +toc_max_heading_level: 2 +--- + +Flet 1.0 is about more than a facelift. Our goal is to help Python developers build production-grade apps that scale from a handful of screens to hundreds of pages, views, and dialogs. + +Dogfooding Flet — building our own products like the Flet mobile app and the Control Gallery — made it clear that the imperative approach becomes hard to manage as apps grow. + +That’s why Flet 1.0 introduces a declarative approach alongside the existing imperative API, drawing inspiration from frameworks such as React, SwiftUI, and Jetpack Compose. + +Here's a quick look at a counter app written declaratively: + +```py +import flet as ft + +@ft.component +def App(): + count, set_count = ft.use_state(0) + + return ft.Row( + controls=[ + ft.Text(value=f"{count}"), + ft.Button("Add", on_click=lambda: set_count(count + 1)), + ], + ) + +ft.run(lambda page: page.render(App)) +``` + +Keep reading to see how it works and how you can start using it today. + +{/* truncate */} + +## What is imperative UI + +Imperative UI is when you tell the framework *exactly how* to build and update the interface step by step. You manipulate the UI directly — create controls, change their properties, insert or remove them in response to user actions. + +For example, in an imperative style you might write: + +> “Create a button, then when it's clicked, change the label's text and move it below the image.” + +```py +left_column.visible = False +right_column.visible = True +right_column.controls.append(ft.Text("Complete!")) +``` + +Flet has championed imperative UI from the beginning, and we still believe it is a valid and straightforward approach — especially for small apps or developers without frontend experience. + +The problem with the imperative approach, though, is that the app's state, logic, and UI all live in the same place. You constantly have to synchronize the app state and every UI element that depends on it. Add a new user to a `list`? You also have to add a corresponding `ft.Row` to display that record. As your app grows, the number of spots that must stay synchronized grows exponentially. + +## What is declarative UI + +The declarative approach means you describe *what* the UI should look like for a given state, not how to build or update it. Instead of manually creating, changing, or removing controls, you write a function that returns the UI structure based on current data — and the framework figures out the minimal updates needed to make it real. + +In other words, your UI becomes a *pure expression of state*: whenever the state changes, the framework re-renders the view so it always stays consistent. + +``` +UI = f(state) +``` + +This makes the code simpler, more predictable, and easier to reason about. + +## Declarative Hello World + +Here's a simple declarative "Hello, world" Flet app: + +```py +import flet as ft + +def App(): + return ft.Text("Hello, world!") + +ft.run(lambda page: page.render(App)) +``` + +Your app must be declarative from top to bottom, similar to how async code needs to remain async all the way. The new `page.render()` bootstrap method makes that possible. + +For clarity, without using lambdas, the code can be rewritten as: + +```py +@ft.component +def App(): + return ft.Text("Hello, Flet!") + +def main(page: ft.Page): + page.render(App) + +ft.run(main) # as before +``` + +This app does nothing fancy — it simply displays the message and does not respond to user actions in any way. + +## Declarative Counter + +Here's a simple declarative "counter" Flet app: + +```py +import flet as ft + +@ft.component +def App(): + count, set_count = ft.use_state(0) + + return ft.Row( + controls=[ + ft.Text(value=f"{count}"), + ft.Button("Add", on_click=lambda: set_count(count + 1)), + ], + ) + +ft.run(lambda page: page.render(App)) +``` + +You may notice a couple of new ideas here: the `@component` decorator and the `use_state()` hook — we explain both shortly. + +The takeaway is that the `App` function is a component that returns a fresh UI (`Row`) every time the app's state changes. + +## Components + +In Flet's declarative approach, a component is simply a **reusable function** that describes a piece of UI as a function of state. + +You can think of it as a self-contained unit that takes inputs (properties, data, event handlers) and returns Flet controls — like `Column`, `Text`, `Button`, etc. Every time its inputs or internal state change, the component rebuilds its UI, and Flet automatically updates only the changed parts. + +Example: + +```py +@ft.component +def Counter(value, on_increment): + return ft.Row([ + ft.Text(f"Count: {value}"), + ft.Button("Increment", on_click=on_increment) + ]) +``` + +Use the `@component` decorator to mark a function as a component. + +### Controls vs Components + +A **control** is a UI element — the basic building block rendered on screen. +It's a concrete thing like a `Text`, `Button`, `Row`, or `Column`. Controls have properties (e.g., `text`, `color`, `alignment`) and can contain child controls. + +Example: + +```py +ft.Text("Hello") +ft.Button("Click me") +ft.Column([ft.Text("A"), ft.Text("B")]) +``` + +A **component** is a *piece of logic that builds and returns controls*. +It's not rendered directly — instead, it describes how to create controls based on inputs or state. +Components let you group logic, reuse UI patterns, and define your own higher-level abstractions. + +Example: + +```py +@ft.component +def Greeting(name): + return ft.Text(f"Hello, {name}!") +``` + +Here `Greeting()` is a component, and `ft.Text` is a control. +You can combine controls inside components, and combine components to form bigger ones — but only controls end up in the final UI tree that Flet renders. + +## Hooks + +Hooks are lightweight functions that let components **store state**, **react to lifecycle events**, or **access shared context** — all without writing classes or managing manual state objects. + +Example: + +```py +@ft.component +def Counter(): + count, set_count = ft.use_state(0) + + return ft.Row( + controls=[ + ft.Text(value=f"{count}"), + ft.Button("Add", on_click=lambda: set_count(count + 1)), + ], + ) +``` + +Here: + +* The `Counter()` component reads like a simple function. +* `use_state(0)` gives it persistent state. +* When `set_count()` is called, Flet re-runs the component and re-renders only what changed. + +That persistence is crucial: ordinary local variables are re-created on every render, so their values would disappear. Hook state survives re-renders, giving your functional components memory without resorting to globals or classes. + +To better understand what hooks are (in an OOP analogy), imagine the `Counter` is a class, not a function. In pseudo-code the example above becomes: + +```py +class Counter(Component): + count: state(0) + + def build(self): + return Row(...) +``` + +Here, `count` is a field that holds the current counter state. + +Hooks are a smart way to add state and behavior to functional, stateless-looking components. The idea is not unique to Flet; we borrowed it from React. + +Flet offers the following built-in hooks: + +* `use_state` - Store local state across rebuilds. +* `use_effect` - Run side effects when something changes. +* `use_context` - Access shared data or services. +* `use_memo` - Memoize computed values. + +## Observable + +Observables make the declarative UI approachable for newcomers compared to a purely React-style model. You can find observables in frameworks such as SolidJS, SwiftUI, and Jetpack Compose. + +An observable is a reactive data holder that keeps your UI in sync automatically — whenever its value changes, the corresponding parts of the UI update instantly and efficiently. + +There are two ways to make a class observable: + +Inherit from `ft.Observable`: + +```py +@dataclass +class CounterState(ft.Observable): + count: int +``` + +Apply `ft.observable` decorator: + +```py +@dataclass +@ft.observable +class CounterState: + count: int +``` + +Observables fit nicely into Flet's declarative approach: + +* A component that accepts an observable parameter automatically re-renders when that observable updates. +* `use_state` and `use_context` hooks that reference observables trigger a re-render when the observable changes. + +Example: + +```py +import asyncio +from dataclasses import dataclass + +import flet as ft + +@dataclass +@ft.observable +class AppState: + counter: float + + async def start_counter(self): + self.counter = 0 + for _ in range(0, 10): + self.counter += 0.1 + await asyncio.sleep(0.5) + + +@ft.component +def App(): + state, _ = ft.use_state(AppState(counter=0)) + + return [ + ft.ProgressBar(state.counter), + ft.Button("Run!", on_click=state.start_counter), + ] + +ft.run(lambda page: page.render(App)) +``` + +Here, `AppState` is observable state, and whenever its `counter` property updates, the `App` component re-renders. + +Compared to a pure React model, an observable makes life easier by allowing mutable state, while React assumes immutable state that must be replaced entirely to trigger a re-render. + +For better performance, multiple updates to observable properties are coalesced, resulting in fewer UI updates when control returns to the UI loop. + +## Examples + +Explore the [declarative examples collection](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/apps/declarative) to see the new approach in action — from the simple [Counter](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/declarative/counter.py) and classic [To-Do](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/declarative/todo.py) to games like [Tic-Tac-Toe](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/declarative/tic-tac-toe.py), [Minesweeper](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/declarative/minesweeper.py), and [Solitaire](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire_declarative/solitaire-final/main.py). + +For a deeper dive, walk through the [Declarative vs Imperative CRUD app cookbook](https://flet.dev/docs/cookbook/declarative-vs-imperative-crud-app/#observables-your-source-of-truth). + +Minesweeper game built with declarative Flet components + +## FAQ + +### Do I need to rewrite my existing Flet apps in declarative style? + +No! Flet supports both the current imperative approach and the new declarative approach. + +### Where are the `StateView` and `ControlBuilder` controls? + +They are gone! They were in-place prototypes for the broader declarative concept. Mixing declarative and imperative styles in the same app caused issues. + +### Do I need to call `update()` in a declarative app? + +No! In a declarative app a component is the unit of update. Whenever a component's parameters or state change, it re-renders automatically. + +### How do I access the `page` instance? + +Use `ft.context`: + +```py +print(ft.context.page.web) +``` + +### How do I call a control method? + +Use an `ft.Ref` to get a reference to a control: + +```py +@dataclass +class State: + txt_name: ft.Ref[ft.TextField] = field(default_factory=lambda: ft.Ref()) + +@ft.component +def App(state): + return ft.TextField(ref=state.txt_name) +``` + +### How do I use a `TextField` or other input control? + +The recommended approach is to use "controlled" inputs, where controls keep their state in the app's state: + +```py +from dataclasses import dataclass +from typing import cast + +import flet as ft + + +@dataclass +@ft.observable +class Form: + name: str = "" + + def set_name(self, value): + self.name = value + + async def submit(self, e: ft.Event[ft.Button]): + e.page.show_dialog( + ft.AlertDialog( + title="Hello", + content=ft.Text(f"Hello, {self.name}!"), + ) + ) + + async def reset(self): + self.name = "" + + +@ft.component +def App(): + form, _ = ft.use_state(Form()) + + return [ + ft.TextField( + label="Your name", + value=form.name, + on_change=lambda e: form.set_name(e.control.value), + ), + ft.Row( + cast( + list[ft.Control], + [ + ft.FilledButton("Submit", on_click=form.submit), + ft.FilledTonalButton("Reset", on_click=form.reset), + ], + ) + ), + ] + + +ft.run(lambda page: page.render(App)) +``` + +Here, the `value` of `TextField` is stored in `state.name`, and the `on_change` handler keeps it in sync. + +## Call to action + +Try the new Flet declarative approach in the latest [0.70.0.dev](https://pypi.org/project/flet/#history) releases and let us know what you think! + +While we update the docs to cover declarative programming in more depth, we encourage you to check the [React introduction](https://react.dev/learn) and try the [Tic-Tac-Toe tutorial](https://react.dev/learn/tutorial-tic-tac-toe). It's not Python, but the JavaScript is simple to follow. + +We built a similar [declarative Tic-Tac-Toe](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/declarative/tic-tac-toe.py) Flet app that you can compare with its React counterpart as you work through the tutorial. + +The next stop is the Flet 1.0 Beta release. We're almost there — new docs (you can follow their progress [here](https://flet.dev/docs/)), more integration tests, and plenty of polish are underway. + +Happy Fletting! diff --git a/website/blog/2025-12-02-flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices.md b/website/blog/2025-12-02-flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices.md new file mode 100644 index 0000000000..b51187fae1 --- /dev/null +++ b/website/blog/2025-12-02-flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices.md @@ -0,0 +1,140 @@ +--- +slug: flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices +title: 'flet debug: the new CLI for testing Flet apps on mobile devices' +authors: feodor +tags: [news] +toc_max_heading_level: 2 +--- + +Flet provides ["Flet" app](https://flet.dev/docs/getting-started/testing-on-mobile/), for both iOS and Android, to "experience" your app on a real device. While using Flet app your Python app is still running on your computer and UI changes are streamed to a mobile device. While this approach is fast and convenient it has limitations: the app is able to only use sensors,libraries and permissions coming with Flet app and you can't know whether the app and all its dependencies are going to work when packaged and executed by a Python mobile runtime. + +In the latest Flet v1 pre-release we have introduced three new Flet CLI commands to package and run Flet app on a real device or emulator: + +- [`flet debug`](https://flet.dev/docs/cli/flet-debug/) - to run Flet app on a device or emulator. +- [`flet devices`](https://flet.dev/docs/cli/flet-devices/) - to list connected devices. +- [`flet emulators`](https://flet.dev/docs/cli/flet-emulators/) - to list iOS/Android emulators and manage Android emulators. + +{/* truncate */} + +This is a screenshot of a simple Flet app running on my iPhone: + +flet debug CLI on a real device + +## How to use + +Run this command to list all connected iOS/Android devices and emulators: + +``` +flet devices +``` + +If you see empty list make sure emulator is running or device connected. + +Copy device ID you'd like to run your app on. + +Run the following command to build Flet app and run on your device: + +``` +flet debug --device-id -v +``` + +> You can omit `-v` option next time you run the command, if everything worked OK. + +## Testing on Android emulator + +To list available iOS and Android emulators run this command: + +``` +flet emulators +``` + +> This command requires Android SDK - you will be asked to install/update it. + +To create a new Android emulator run: + +``` +flet emulators create my-emulator +``` + +To start an emulator: + +``` +flet emulators start my-emulator +``` + +## Testing on iOS/iPadOS emulator + +To create a new iOS/iPadOS simulator: + +List simulator models: + +``` +xcrun simctl list devicetypes +``` + +List available runtimes: + +``` +xcrun simctl list runtimes +``` + +Create simulator: + +``` +xcrun simctl create "" "" "" +``` + +For example: + +``` +xcrun simctl create "My iPhone 17 Pro" "iPhone 17 Pro" com.apple.CoreSimulator.SimRuntime.iOS-26-1 +``` + +Start Apple Simulator with: + +``` +open -a Simulator +``` + +Open "File -> Open Simulator -> ``". + +Run this command to get simulator device ID: + +``` +flet devices +``` + +## Testing on a real iPhone/iPad device + +* Enable developer mode on your device. +* Connect the device with USB cable. You can use debug via Wi-Fi, but it's significantly slower than via cable. +* Open XCode, go to "Window -> Devices and Simulators". Wait until "device support files" are copied - it could take a few minutes. + +> When you connect an iOS device and open Xcode, it automatically downloads “device support” and symbol files from the iPhone. These files allow Xcode (and Flutter) to understand the exact iOS version on the device and provide fast, reliable debugging. Without them, Xcode can’t map system libraries correctly, which leads to slow startup, missing breakpoints, or warnings like “LLDB could not find the on-disk shared cache.” This setup happens only once per iOS version and is required for running or debugging apps on a physical device. + +* Create a new [provisioning profile](https://flet.dev/docs/publish/ios/#provisioning-profile) that includes your device ID and developer certificate. +* Configure app bundle ID and "debugging" profile in `pyproject.toml`: + +```toml +[tool.flet.ios] +bundle_id = "com.your-company.app" + +[tool.flet.ios.export_methods."debugging"] +provisioning_profile = "Development com.your-company.app" +``` + +## FAQ + +### Does `flet debug` replace "Flet" mobile app? + +No. "Flet" app will stay there and will be updated by Flet v1 Beta release. + +"Flet" app allows quickly experience your app on a mobile device, but with limited capabilities (not all permissions are enabled and the app itself is running on your computer). + +`flet debug` allows running on emulator or a real device without making IPA/APK package and manually uploading it to a device. Your entire app is packaged and run on a device. You can customize permissions and other settings in `pyproject.toml`. + +### When is stable Flet v1 going to be released? + +We are going to release a stable Flet v1 Beta before Christmas. + +Best regards and happy Fletting! diff --git a/website/blog/2025-12-10-sensor-and-system-services.md b/website/blog/2025-12-10-sensor-and-system-services.md new file mode 100644 index 0000000000..9075be4fe5 --- /dev/null +++ b/website/blog/2025-12-10-sensor-and-system-services.md @@ -0,0 +1,98 @@ +--- +slug: sensor-and-system-services +title: Sensor and system services +authors: feodor +tags: [news] +toc_max_heading_level: 2 +--- + +We've just merged a [pull request](https://github.com/flet-dev/flet/pull/5846) introducing 10 new device and platform services to the Flet SDK, significantly expanding access to hardware sensors and system capabilities. + +### New sensor services + +* [Accelerometer](https://flet.dev/docs/services/accelerometer/) – Reads raw acceleration along the X, Y, and Z axes, including gravity. +* [Barometer](https://flet.dev/docs/services/barometer/) – Provides atmospheric pressure readings useful for altitude estimation. +* [Gyroscope](https://flet.dev/docs/services/gyroscope/) – Measures device rotation around each axis. +* [Magnetometer](https://flet.dev/docs/services/magnetometer/) – Detects magnetic field strength, commonly used for compass functionality. +* [UserAccelerometer](https://flet.dev/docs/services/useraccelerometer/) – Reports acceleration data with gravity filtered out for cleaner motion detection. + +### New system services + +* [Battery](https://flet.dev/docs/services/battery/) – Monitors battery level, charging state, and power source changes. +* [Connectivity](https://flet.dev/docs/services/connectivity/) – Detects network status and connection type (Wi-Fi, mobile, offline). +* [ScreenBrightness](https://flet.dev/docs/services/screenbrightness/) – Allows reading and adjusting the device screen brightness. +* [Share](https://flet.dev/docs/services/share/) – Invokes the system share sheet to share text, files, or URLs. +* [Wakelock](https://flet.dev/docs/services/wakelock/) – Prevents the device screen from dimming or sleeping while active. + +Flet sensor and system services + +{/* truncate */} + +Sensor services mostly work on iOS and Android devices. Using them in a web app is also possible to some extent, but only under specific browser and hardware conditions. + +System services are supported on all mobile and desktop platforms. + +## How to test + +Install the latest [Flet 0.70.0.devXYZ](https://pypi.org/project/flet/#history) pre-release. + +Use the [`flet debug`](/blog/flet-debug-the-new-cli-for-testing-flet-apps-on-mobile-devices) command to run your app on a real iOS/Android device or emulator. + +Testing in the Android emulator is especially convenient, as it allows you to experiment with virtually all available sensors: + +Flet sensors testing in Android emulator + +## Services API + +Previously, some services were exposed as page properties, such as `page.clipboard` or `page.shared_preferences`. + +All services are now standalone and should be used by creating their own instances. For example: + +```py +clipboard = ft.Clipboard() +await clipboard.set("Hello, world!") +``` + +or simply: + +```py +await ft.Clipboard().set("Hello, world!") +``` + +When you create a new instance of a service, it is automatically registered within the page and disposed of when it is no longer referenced - for example, at the end of a method call. + +However, if you need to assign an event handler to a service that must persist across method calls, you must keep a reference to that service to prevent it from being disposed. + +In an imperative Flet app, you can use the `page.services` list, which holds service instances. For example: + +```py +async def main(page: ft.Page): + battery = ft.Battery() + page.services.append(battery) # need to keep a reference to the service + + async def on_state_change(e: ft.BatteryStateChangeEvent): + print(f"State changed: {e.state}") + + battery.on_state_change = on_state_change + + ... +``` + +In a declarative Flet app, you can use the `use_ref` or `use_state` hook to hold a service reference. For example: + +```py +import flet as ft + +@ft.component +def App(): + async def on_state_change(e: ft.BatteryStateChangeEvent): + print(f"State changed: {e.state}") + + ft.use_ref(lambda: ft.Battery(on_state_change=on_state_change)) + + return ft.Text("Battery status app") + +ft.run(lambda page: page.render(App)) +``` + +That's all for today, folks! Happy Fletting! diff --git a/website/blog/2025-12-24-flet-1-0-beta.md b/website/blog/2025-12-24-flet-1-0-beta.md new file mode 100644 index 0000000000..e2117720b2 --- /dev/null +++ b/website/blog/2025-12-24-flet-1-0-beta.md @@ -0,0 +1,78 @@ +--- +slug: flet-1-0-beta +title: Flet 1.0 Beta +authors: feodor +tags: [news] +toc_max_heading_level: 2 +--- + +Today, we're releasing **Flet 1.0 Beta**, published as version 0.80.0! + +Flet 1.0 is a huge leap forward! Its goal is to ensure long-term growth, with an architecture designed to scale to larger projects, more users, and an expanding feature set. + +- Developers can use either imperative or [declarative style](/blog/introducing-declarative-ui-in-flet) to write their Flet apps. +- The new [documentation website](https://flet.dev/docs/) based on mkdocs, generated from Flet code base and always up-to-date. +- End-to-end [integration tests](https://github.com/flet-dev/flet/tree/main/sdk/python/packages/flet/integration_tests) for all controls and examples. +- [Extensions](https://github.com/flet-dev/flet/tree/main/sdk/python/packages) are back in Flet main repo, with combined docs and covered by tests. +- [Examples](https://github.com/flet-dev/flet/tree/main/sdk/python/examples) are back to main Flet repo, always in sync with Flet API and covered by tests. +- [flet debug](https://flet.dev/docs/cli/flet-debug/) CLI for debugging app on real [devices](https://flet.dev/docs/cli/flet-devices/) and [emulators](https://flet.dev/docs/cli/flet-emulators/). +- Build, test and release [workflows](https://github.com/flet-dev/flet/actions) are automated with GitHub Actions. +- Clean extensibility model with simplified API on Python and Flutter sides. + +{/* truncate */} + +## Upgrading to Flet 1.0 Beta + +This release differs from the [Alpha](/blog/introducing-flet-1-0-alpha) in that it is no longer a pre-release (there is no `"dev"` suffix) and it **replaces** version **0.28.3** as the current release on PyPI. + +This means that if you install `flet` (or any other Flet package), or add it as a dependency **without specifying a version**, you will get **0.80.0** by default. + +Why is this important? **0.80.0 is not a drop-in upgrade** — it includes [breaking changes](https://github.com/flet-dev/flet/issues/5238). To run an existing app on **0.80.0**, you will need to migrate it manually. + +If you use pip to manage your environment just run: + +``` +pip install 'flet[all]' --upgrade +``` + +For projects managed by uv you just remove lock file and re-sync: + +``` +rm uv.lock +uv sync +``` + +The latest `flet` 0.80.x package version will be installed. + +Built-in Flet extensions such as `flet_audio`, `flet_video`, and others are now published with the same version as the core `flet` packages, so be sure to update and pin their dependencies as well. + +## Staying on Flet 0.28.x + +If you do not plan to upgrade your existing app to Flet 1.0, you will need to pin the Flet version to **0.28.3** in your `requirements.txt` or `pyproject.toml`: + +``` +flet==0.28.3 +``` + +## Flet app for iOS and Android + +:::warning Work in progress +The App Store and Google Play currently host a Flet app built for Flet 0.28.3. +An updated app supporting Flet API 0.80.0 is under development and coming soon. + +Please join the [Flet Discord server](https://discord.gg/dzWXP8SHG8) - we'll post an announcement there when a new Flet app becomes available. +::: + +[Read more about testing on iOS and Android](https://flet.dev/docs/getting-started/testing-on-mobile/). + +## Next steps + +If you're starting a new app, we recommend using Flet 0.80.0 (aka "Beta"). + +"Beta" means the Flet API is 99% stable and will not change before the 1.0 final release. Flet 1.0 Beta is safe for all new applications. + +For Flet 0.28.x (also known as *Flet v0*), we will continue to provide minor updates for bug fixes and security issues, but no new features will be added. + +Try Flet 0.80.0 and let us know what you think! + +We wish you a Merry Christmas and a Happy New Year! 🎄✨ diff --git a/website/blog/2026-02-24-flet-v-0-81-release-announcement.md b/website/blog/2026-02-24-flet-v-0-81-release-announcement.md new file mode 100644 index 0000000000..518a6e117f --- /dev/null +++ b/website/blog/2026-02-24-flet-v-0-81-release-announcement.md @@ -0,0 +1,342 @@ +--- +slug: flet-v-0-81-release-announcement +title: "Flet 0.81.0: Camera, CodeEditor, color pickers and more" +authors: feodor +tags: [releases] +--- + +Flet 0.81.0 is now available with new controls, better platform integration, and build workflow improvements. + +Highlights in this release: + +* New controls: `Camera`, `CodeEditor`, `PageView`, color pickers, `RotatedBox`. +* Advanced visual transitions with `Hero` animations and `Matrix4` transforms. +* Better app packaging with `flet build ios-simulator` and `flet build --artifact`. +* `Clipboard` APIs for images and files. +* Web `FilePicker` support for direct file content (`with_data=True`). +* Platform locale info and locale change events. +* New `LayoutControl.on_size_change` event for size-aware UI. + +{/* truncate */} + +## How to upgrade + +If you use pip: + +```bash +pip install 'flet[all]' --upgrade +``` + +If you use uv with `pyproject.toml` and want to upgrade everything: + +```bash +uv sync --upgrade +``` + +If you want to upgrade only Flet packages: + +```bash +uv sync --upgrade-package flet \ + --upgrade-package flet-cli \ + --upgrade-package flet-desktop \ + --upgrade-package flet-web +``` + +On Linux, your project might use `flet-desktop-light` instead of `flet-desktop`. In that case, upgrade `flet-desktop-light` package instead. + +## `Camera` + +`Camera` is a new control for live camera preview, image capture, video recording, and frame streaming. + +It is currently supported on web, iOS, and Android, which makes it practical for cross-platform scanning, media capture, and computer vision scenarios from a single Flet codebase. + + + +```python +import flet as ft +import flet_camera as fc + + +def main(page: ft.Page): + page.add( + fc.Camera( + expand=True, + preview_enabled=True, + ) + ) + + +ft.run(main) +``` + +More info: + +* Docs: https://flet.dev/docs/camera/ +* Issue: [#6190](https://github.com/flet-dev/flet/issues/6190) + +## `CodeEditor` + +`CodeEditor` brings an embedded source editor into Flet apps. + +This is useful for developer tools, education apps, playgrounds, and it is also part of the groundwork for the upcoming FletPad experience. + + + +```python +import flet as ft +import flet_code_editor as fce + + +def main(page: ft.Page): + page.add( + fce.CodeEditor( + language=fce.CodeLanguage.PYTHON, + code_theme=fce.CodeTheme.ATOM_ONE_LIGHT, + value="print('Hello, Flet')", + expand=True, + ) + ) + + +ft.run(main) +``` + +More info: + +* Docs: https://flet.dev/docs/codeeditor/ +* Issue: [#6162](https://github.com/flet-dev/flet/issues/6162) + +## `PageView` + +`PageView` provides swipe-based paging with viewport control and programmatic navigation. + +It solves a common mobile-style UX need for onboarding, content carousels, step-by-step flows, and story-like interfaces. + + + +```python +import flet as ft + + +def main(page: ft.Page): + page.add( + ft.PageView( + expand=True, + viewport_fraction=0.9, + selected_index=1, + controls=[ + ft.Container( + bgcolor=ft.Colors.INDIGO_400, + alignment=ft.Alignment.CENTER, + content=ft.Text("Page 1", size=24, color=ft.Colors.WHITE), + ), + ft.Container( + bgcolor=ft.Colors.PINK_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("Page 2", size=24, color=ft.Colors.WHITE), + ), + ft.Container( + bgcolor=ft.Colors.TEAL_300, + alignment=ft.Alignment.CENTER, + content=ft.Text("Page 3", size=24, color=ft.Colors.WHITE), + ), + ], + ) + ) + + +ft.run(main) +``` + +More info: + +* Docs: https://flet.dev/docs/controls/pageview/ +* Issue: [#6158](https://github.com/flet-dev/flet/issues/6158) + +## Color pickers + +Flet now includes multiple color picker controls powered by `flutter_colorpicker`. + +This makes it easier to build design tools, theming UIs, and customization dialogs without third-party integration work. + + + +```python +import flet as ft +from flet_color_pickers import MaterialPicker + + +def main(page: ft.Page): + page.add( + MaterialPicker( + color="#ff9800", + on_color_change=lambda e: print(e.data), + ) + ) + + +ft.run(main) +``` + +More info: + +* Docs: https://flet.dev/docs/colorpickers/ +* Issue: [#6109](https://github.com/flet-dev/flet/issues/6109) + +## `Hero` animations + +`Hero` animations add shared-element transitions between routes. + +They solve abrupt navigation changes by visually connecting matching elements across screens, which improves perceived continuity and polish. + + + +[Code example](https://flet.dev/docs/controls/hero/#basic-example) + +More info: + +* Docs: https://flet.dev/docs/controls/hero/ +* Issue: [#6157](https://github.com/flet-dev/flet/issues/6157) + +## `Matrix4` transforms and `RotatedBox` + +This release adds `Matrix4`-based transforms to `LayoutControl.transform` and introduces `RotatedBox`. + +Together, they cover both advanced transform pipelines and layout-aware quarter-turn rotation. This helps when building rich interactions, visual effects, and precise UI compositions. + + + + + +```python +import flet as ft +from math import pi + + +def main(page: ft.Page): + page.add( + ft.Container( + width=220, + height=130, + bgcolor=ft.Colors.CYAN_300, + transform=ft.Transform( + matrix=ft.Matrix4.identity().set_entry(3, 2, 0.0018).rotate_y(pi / 8) + ), + ), + ft.RotatedBox(quarter_turns=1, content=ft.Text("Rotated")), + ) + + +ft.run(main) +``` + +More info: + +* `LayoutControl` docs: https://flet.dev/docs/controls/layoutcontrol/ +* `RotatedBox` docs: https://flet.dev/docs/controls/rotatedbox/ +* Issue: [#6198](https://github.com/flet-dev/flet/issues/6198) + +## Build workflow updates: iOS simulator target and artifact naming + +Packaging for iOS simulator now produces an unsigned `.app` you can drag and drop into the simulator: + +```bash +flet build ios-simulator +``` + +At the same time, `flet build --artifact` gives better control over output artifact naming without affecting bundle IDs: + +```bash +flet build macos --artifact "My Awesome App" +``` + +More info: + +* iOS simulator build: https://flet.dev/docs/publish/ios/#flet-build-ios-simulator +* Artifact name docs: https://flet.dev/docs/publish/#artifact-name +* Issues: [#6188](https://github.com/flet-dev/flet/issues/6188), [#6074](https://github.com/flet-dev/flet/issues/6074) + +## `Clipboard`, `FilePicker`, locales, and size-aware layouts + +This release improves app integration with operating systems and browsers: + +* `Clipboard` can now get/set images and files. +* Web `FilePicker` can return picked file content as `bytes` with `with_data=True`. +* Platform locales and locale change events are available. +* `LayoutControl.on_size_change` helps build size-aware UI logic. + +```python +import flet as ft + + +def main(page: ft.Page): + async def pick_text_file(_): + files = await ft.FilePicker().pick_files(with_data=True) + print(files[0].bytes if files else None) + + page.add(ft.Button("Pick file", on_click=pick_text_file)) + + +ft.run(main) +``` + +```python +import flet as ft + + +def main(page: ft.Page): + def handle_size_change(e: ft.LayoutSizeChangeEvent[ft.Container]): + e.control.content.value = f"{int(e.width)} x {int(e.height)}" + + page.add( + ft.Container( + expand=True, + content=ft.Text(), + on_size_change=handle_size_change, + ) + ) + + +ft.run(main) +``` + +More info: + +* `Clipboard` docs: https://flet.dev/docs/services/clipboard/ +* `FilePicker` docs: https://flet.dev/docs/services/filepicker/ +* Locale type docs: https://flet.dev/docs/types/locale/ +* `LayoutControl` docs: https://flet.dev/docs/controls/layoutcontrol/ +* Issues: [#6141](https://github.com/flet-dev/flet/issues/6141), [#6199](https://github.com/flet-dev/flet/issues/6199), [#6191](https://github.com/flet-dev/flet/issues/6191), [#6099](https://github.com/flet-dev/flet/issues/6099) + +## Improvements + +0.81.0 reduces memory churn in control diffing algorithm, which is especially important for web apps with frequent UI diffs. + +* Optimize `object_patch` memory churn ([#6204](https://github.com/flet-dev/flet/issues/6204)). +* Add `ignore_up_down_keys` to `TextField` and `CupertinoTextField` ([#6183](https://github.com/flet-dev/flet/issues/6183)). + +## Other changes and bug fixes + +* Bump Flutter to 3.41.2 (italic font finally looks nice!). +* Register MIME types for `.mjs` and `.wasm` ([#6140](https://github.com/flet-dev/flet/issues/6140)). +* Skip component migrate/diff when function signatures differ ([#6181](https://github.com/flet-dev/flet/issues/6181)). +* Fix memory leaks in Flet web app ([#6186](https://github.com/flet-dev/flet/issues/6186)). +* Fix desktop window frameless/titlebar update sync and progress bar clearing ([#6114](https://github.com/flet-dev/flet/issues/6114)). +* Fix first-time button `style` patching and clear stale style state ([#6119](https://github.com/flet-dev/flet/issues/6119)). +* Fix map layer rebuilds on marker updates ([#6113](https://github.com/flet-dev/flet/issues/6113)). +* Fix `AlertDialog` and `CupertinoAlertDialog` barrier color updates ([#6097](https://github.com/flet-dev/flet/issues/6097)). +* Fix `ControlEvent` runtime type hints ([#6102](https://github.com/flet-dev/flet/issues/6102)). + +## `Flet` app update on mobile stores + +An updated `Flet` app for testing on mobile devices is coming to the App Store and Google Play soon. + +For now, see the current mobile testing guide: https://flet.dev/docs/getting-started/testing-on-mobile/ + +## Conclusion + +Flet 0.81.0 is focused on practical app-building features: richer UI controls, stronger system integration, and smoother build workflows. + +Try it in your apps and share feedback in [GitHub Discussions](https://github.com/flet-dev/flet/discussions) or on [Discord](https://discord.gg/dzWXP8SHG8). + +Happy Flet-ing! diff --git a/website/blog/2026-03-26-flet-v-0-83-release-announcement.md b/website/blog/2026-03-26-flet-v-0-83-release-announcement.md new file mode 100644 index 0000000000..37332c5452 --- /dev/null +++ b/website/blog/2026-03-26-flet-v-0-83-release-announcement.md @@ -0,0 +1,160 @@ +--- +slug: flet-v-0-83-release-announcement +title: "Flet 0.83.0: Faster diffs, leaner packages, road to 1.0" +authors: feodor +tags: [releases] +--- + +Flet 0.83.0 is here with major performance gains, a reworked packaging pipeline, and better project transparency - all part of our push toward a rock-solid 1.0. + +Highlights in this release: + +* Up to 6.7× faster control diffing for both imperative and declarative apps. +* Smarter `.update()` logic that eliminates redundant updates. +* Declarative field validation with `Annotated` types. +* Desktop binaries and build templates moved from PyPI to GitHub Releases - smaller installs, pinned versions. +* Better release traceability with milestones and pre-releases on GitHub. + +{/* truncate */} + +## How to upgrade + +If you use pip: + +```bash +pip install 'flet[all]' --upgrade +``` + +If you use uv with `pyproject.toml` and want to upgrade everything: + +```bash +uv sync --upgrade +``` + +If you want to upgrade only Flet packages: + +```bash +uv sync --upgrade-package flet \ + --upgrade-package flet-cli \ + --upgrade-package flet-desktop \ + --upgrade-package flet-web +``` + +## Faster control diffing + +Every time your app calls `page.update()` or rebuilds a declarative component, Flet computes a diff - the set of property changes to send to Flutter. In 0.83.0 we overhauled this mechanism for both programming styles, and the results are dramatic. + +### Imperative apps + +**Before:** every `page.update()` walked through *all* properties of every control and compared them to the previous snapshot - even properties you never touched. If your control has 20 properties and you changed one, Flet still compared all 20. + +**After:** a new `Prop` descriptor tracks which properties were actually written since the last diff. When you set `button.text = "Click me"`, only `text` is flagged as dirty. On the next `page.update()`, Flet sends only the dirty properties to Flutter and skips the rest. Think of it like only checking the light switches you actually flipped, instead of walking through every room in the house. + +### Declarative apps + +**Before:** when a component rebuilt, Flet compared every field of the new control tree against the old one - including nested value objects like `Alignment`, `BorderRadius`, and `BoxDecoration`. Since these objects were recreated on every build, they always looked "new" even when nothing changed. + +**After:** ~150 data types now use a new `@value` decorator that makes them comparable by content rather than identity. Combined with a two-pass diff that first checks structural changes and then compares only fields that actually differ, the diff skips unchanged subtrees entirely. + +### Benchmarks + +Measured on Python 3.14.2, Apple Silicon: + +* Frozen controls with 20 fields, 2 changed: **3.2–3.4× faster** (100–300 controls). +* Mixed keyed/unkeyed lists: **1.9–2.0× faster**. +* Non-frozen rebuilt lists: **2.9–4.5× faster**. +* [Sunflower demo](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/declarative/sunflower.py) (500 seeds): **6.7× faster**. + +More info: + +* PR: [#6296](https://github.com/flet-dev/flet/pull/6296) + +## Smarter `.update()` logic + +In previous versions, Flet automatically called `page.update()` at the end of every event handler. If your handler already called `.update()` explicitly - say, to show a spinner before starting work - the framework would fire a second, redundant update at the end. This double-update could cause visual glitches or wasted work. + +0.83.0 tracks whether `.update()` was called during handler execution. If it was, the automatic update at the end is skipped. This also means that apps migrated "as is" from Flet 0.28.3 (where there was no auto-update) will behave as expected without changes. + +More info: + +* PR: [#6298](https://github.com/flet-dev/flet/pull/6298) +* Issue: [#6236](https://github.com/flet-dev/flet/issues/6236) + +## Declarative field validation + +Control fields can now declare validation rules inline using Python's `Annotated` types and a new `V` rule set. Instead of writing manual checks in `__init__` or `before_update()`, you express constraints declaratively: + +```python +from typing import Annotated +from flet.core.validation import V + +entries: Annotated[list, V.or_(V.empty, V.min_length(3))] +``` + +This keeps validation close to the field definition and makes it easier to reason about invariants at a glance. Deprecation warnings also get auto-generated admonitions in the docs, so deprecated fields are clearly flagged without manual documentation effort. + +More info: + +* PR: [#6278](https://github.com/flet-dev/flet/pull/6278) + +## Packaging: client binaries to GitHub Releases + +Until now, Flet desktop binaries (the Flutter client for Windows, macOS, and Linux) were bundled inside PyPI wheels. This made the wheels large and consumed significant PyPI storage. We can't ask PyPI team for storage increase forever! 😊 + +Starting with 0.83.0, the desktop client is downloaded on first run from GitHub Releases and cached locally at `~/.flet/client/`. The `flet-desktop` package is now a single, tiny, platform-independent wheel. + +What this means for you: + +* **Faster installs.** `pip install flet` downloads a small wheel instead of a platform-specific binary. +* **One package.** The separate `flet-desktop-light` package is gone - choose the "light" or "full" flavor via `FLET_DESKTOP_FLAVOR` env var or `[tool.flet]` in `pyproject.toml`. On Linux the "light" flavor is used by default if not specified. +* **Air-gapped setups.** Set `FLET_CLIENT_URL` to point at a local mirror if your environment can't reach GitHub. + +More info: + +* PR: [#6309](https://github.com/flet-dev/flet/pull/6309) + +## Packaging: templates to GitHub Releases + +The `flet-build-template` and `flet-app-templates` repositories have been consolidated into the main Flet monorepo and are now distributed as zip archives attached to each GitHub Release. + +When you run `flet build` or `flet create`, the CLI downloads the template zip that matches your installed Flet version. **Versions are pinned** - even for pre-releases - so you always get templates compatible with your Flet version. No more mismatches between the framework and the build template. + +For stable releases, the `flet` Flutter package is published to pub.dev as usual. For pre-releases, the build template references the exact commit SHA via a Git dependency - so `flet build` always compiles against the precise Flutter code that matches your Python package. + +More info: + +* PR: [#6331](https://github.com/flet-dev/flet/pull/6331) + +## Better release traceability + +We've improved how you can track what's in each release: + +* **Pre-releases on GitHub.** Every dev build now creates a [GitHub Release](https://github.com/flet-dev/flet/releases) (e.g., `v0.83.0.dev6045`). You can browse pre-releases to see exactly which fixes and features landed in each build - no more guessing whether your bug fix is in the latest dev version. +* **Milestones on issues and PRs.** Issues and pull requests are now assigned to [milestones](https://github.com/flet-dev/flet/milestones?state=closed). Want to know when your issue was fixed? Check the milestone - it tells you the release version. + +## Road to 1.0 + +We're working hard to make Flet a scalable, sustainable framework, and 0.83.0 reflects that commitment. + +**Everything is automated.** Our CI pipeline handles building, testing, packaging, and publishing end-to-end. Every push to `main` triggers a full build of all platform binaries, runs the test suite, executes `flet build` for all targets, and publishes dev releases to GitHub and pub.dev. There are no manual steps. + +**Comprehensive integration testing.** We now run 200+ integration tests on macOS across 12 parallel test suites - covering core controls, Material and Cupertino widgets, services, themes, extensions, and example apps. A full run takes about 85 minutes and catches regressions before they reach you. Integration suites for other platforms are coming! + +**New documentation is coming.** We're moving back to Docusaurus for the Flet docs, which will bring a better reading experience, improved search, and easier contribution workflow. Stay tuned. + +## Other changes and bug fixes + +* Customizable scrollbars ([#6282](https://github.com/flet-dev/flet/issues/6282)). +* Scrollable `ExpansionPanelList` ([#6294](https://github.com/flet-dev/flet/issues/6294)). +* `SharedPreferences` now supports `int`, `float`, `bool`, and `list[str]` types ([#6267](https://github.com/flet-dev/flet/issues/6267)). +* Align Python defaults with Dart defaults across all packages ([#6330](https://github.com/flet-dev/flet/issues/6330)). +* Fix `ReorderableListView` event deserialization for `on_reorder_start`/`on_reorder_end` ([#6315](https://github.com/flet-dev/flet/issues/6315)). +* Skip micropip load for apps with `pyproject.toml` ([#6300](https://github.com/flet-dev/flet/issues/6300)). + +## Conclusion + +Flet 0.83.0 is a release about foundations: faster internals, cleaner packaging, and better tooling. These are the kinds of improvements that compound - every future release builds on a faster, more reliable base. + +Try it in your apps and share feedback in [GitHub Discussions](https://github.com/flet-dev/flet/discussions) or on [Discord](https://discord.gg/dzWXP8SHG8). + +Happy Flet-ing! diff --git a/website/blog/2026-04-01-flet-v-0-84-release-announcement.md b/website/blog/2026-04-01-flet-v-0-84-release-announcement.md new file mode 100644 index 0000000000..173483d241 --- /dev/null +++ b/website/blog/2026-04-01-flet-v-0-84-release-announcement.md @@ -0,0 +1,205 @@ +--- +slug: flet-v-0-84-release-announcement +title: "Flet 0.84.0: Goodbye MkDocs, hello CrocoDocs!" +authors: feodor +tags: [releases] +--- + +Flet 0.84.0 is a developer-experience release: new documentation website and re-worked examples. + +Highlights in this release: + +* Flet docs are back on Docusaurus - fast dev server, working hot reload, unified website. +* Meet CrocoDocs, our new tool that bridges Python docstrings and Docusaurus. +* All 466 Flet examples migrated to standalone projects with rich metadata for Gallery and AI discovery. + +{/* truncate */} + +## How to upgrade + +If you use pip: + +```bash +pip install 'flet[all]' --upgrade +``` + +If you use uv with `pyproject.toml` and want to upgrade everything: + +```bash +uv sync --upgrade +``` + +If you want to upgrade only Flet packages: + +```bash +uv sync --upgrade-package flet \ + --upgrade-package flet-cli \ + --upgrade-package flet-desktop \ + --upgrade-package flet-web +``` + +## Goodbye, MkDocs! Hello, CrocoDocs! + +The Flet website has always been built on [Docusaurus](https://docusaurus.io/) - it's fast, extensible, and has great MDX support. But we were authoring API docs manually, which caused synchronization issues with the source code and a lot of duplication: we'd write the same content in Python docstrings and then again in Docusaurus pages. + +For Flet "v1", [@ndonkoHenri](https://github.com/ndonkoHenri) made a huge push by moving all API docs into Python docstrings and configuring [MkDocs](https://www.mkdocs.org/) + [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) + [mkdocstrings](https://mkdocstrings.github.io/) to serve Flet documentation. It was a great and timely decision to make docstrings the single source of truth. + +And it worked, but with some quirks: + +* Flet has a large codebase with many cross-references. The docs dev server took **around 3 minutes** to start. +* For [some](https://github.com/mkdocs/mkdocs/issues/4032) [reason](https://github.com/squidfunk/mkdocs-material/issues/8478), hot reload was not working - which meant making a change, restarting, and waiting another 3 minutes to see the result! + +Then, one day, we saw this warning in a build log and got a feeling that something was off: + +:::warning +WARNING - MkDocs 2.0 is incompatible with Material for MkDocs +::: + +Apparently, there is a [whole story](https://fpgmaas.com/blog/collapse-of-mkdocs/) that has been developing for a few years. The short version: the MkDocs original author started working on MkDocs 2.0 which drops plugin support and is not compatible with MkDocs 1.x. The Material for MkDocs team started working on [Zensical](https://zensical.io/), a MkDocs rewrite in Rust that is backward-compatible but launched with many plugins still missing. + +We decided to bring docs back to Docusaurus - but this time with a tool that keeps docstrings as the single source of truth. + +### Meet CrocoDocs + + + +CrocoDocs is our home-grown tool that transforms Flet API data into a form that Docusaurus can render. The idea is simple: extract API information from Python docstrings using [Griffe](https://mkdocstrings.github.io/griffe/), produce JSON data and MDX partials, and let Docusaurus render everything using custom MDX components and remark plugins. + +The pipeline looks like this: + +1. **Extract** - Griffe parses all Python packages and collects classes, functions, docstrings, and type annotations. +2. **Transform** - CrocoDocs builds an `api-data.json` with all API entries and a cross-reference map (`xref_map`) that resolves symbol names to documentation URLs. +3. **Generate** - MDX partials are produced for CLI docs, permissions, and the PyPI package index. Code examples are indexed from the examples directory. +4. **Render** - Docusaurus picks up the generated data and a custom remark plugin resolves cross-references into clickable links. + +It's a modern Python project, managed with uv and configured entirely via `pyproject.toml`. + +### New cross-reference format + +We switched from [mkdocstrings-python-xref](https://analog-garage.github.io/mkdocstrings-python-xref/latest/) format to reST-style roles in docstrings. This was a deliberate choice: reST roles are a well-known standard, and - crucially - they are navigable in VS Code and other editors that render docstring tooltips. + +Before (mkdocstrings): + +```python +"""See [Page][flet.] and [Control.visible][flet.] for details.""" +``` + +After (reST roles): + +```python +"""See :class:`~flet.Page` and :attr:`flet.Control.visible` for details.""" +``` + +The supported roles are `:class:`, `:attr:`, `:meth:`, `:func:`, `:mod:`, `:data:`, and `:obj:`. The `~` prefix shortens the display name - `:class:`~flet.Page`` renders as just "Page" while still linking to the full path. + +Here's what it looks like in VS Code - docstring links are rendered and navigable right in the tooltip: + + + +### Strict CI checks + +In addition to the broken-link checks that Docusaurus performs during build, we added a custom CI script with strict validation: + +* **Broken images** - verifies that every `` points to an existing file. +* **Unresolved reST xrefs** - catches any `:class:`, `:attr:`, `:meth:` markers that were not resolved to links. +* **Missing code examples** - flags `` components that reference non-existent example files. +* **Missing API entries** - detects symbols referenced in docs but absent from `api-data.json`. + +If any check fails, the build fails. No broken docs make it to production. + +### The results + +The migration from MkDocs to Docusaurus brought exactly what we hoped for: + +* The generate phase and Docusaurus dev server **start in a few seconds** (down from ~3 minutes). +* **Hot reload works.** Change a page, save, see the update. +* A **single unified website** for the landing page and docs, with a modern design. +* **Full-text search with Algolia.** +* A tool we own and can evolve as Flet grows. + +CrocoDocs is not yet available on PyPI, but if you'd like to adopt it for your Python project - let me know! + +More info: + +* PR: [#6359](https://github.com/flet-dev/flet/pull/6359) + +## Examples migrated to projects + +Every Flet example is now a standalone project with its own `pyproject.toml` and rich metadata. Here's why we made this change: + +**Better discovery.** Each project carries structured metadata - categories, description, keywords, a list of controls used, complexity level, and more. We need this data for building Gallery v2 (available on the website and as a Flet app) and for building the index for Flet MCP, so AI assistants can find the right example for you. + +**Easier to build and run.** Previously, if you wanted to try an example, you'd copy it into your own project, figure out the dependencies, and wire things up. Now every example is a complete project you can clone and run directly with `flet run`. + +**Self-contained.** Every project includes all its dependencies (`flet_charts`, `flet_map`, etc.), permissions, bundle IDs, and assets needed to successfully build and run on any platform. + +### What a project looks like + +Before - a flat Python file with no metadata: + +``` +sdk/python/examples/controls/ +├── button_examples.py +├── canvas_examples.py +└── ... +``` + +After - a structured project directory: + +``` +sdk/python/examples/controls/ +├── material/ +│ └── button/ +│ ├── basic/ +│ │ ├── main.py +│ │ └── pyproject.toml +│ ├── icons/ +│ │ ├── main.py +│ │ └── pyproject.toml +│ └── styling/ +│ ├── main.py +│ └── pyproject.toml +├── core/ +│ └── canvas/ +│ ├── bezier_curves/ +│ ├── brush/ +│ └── ... +└── cupertino/ + └── cupertino_button/ + └── basic/ +``` + +Each `pyproject.toml` includes Gallery and MCP metadata: + +```toml +[project] +name = "button-basic" +version = "1.0.0" +description = "Basic enabled and disabled Button examples." +keywords = ["button", "material", "basic", "disabled"] +dependencies = ["flet"] + +[tool.flet.gallery] +categories = ["Buttons/Button"] + +[tool.flet.metadata] +title = "Basic button" +controls = ["SafeArea", "Column", "Button"] +layout_pattern = "inline-actions" +complexity = "basic" +features = ["enabled and disabled states"] +``` + +In total, **466 examples** were migrated to this format. + +More info: + +* PR: [#6355](https://github.com/flet-dev/flet/pull/6355) + +## Conclusion + +Flet 0.84.0 is about the ecosystem around the framework: better docs, better examples, better tooling. CrocoDocs gives us a documentation pipeline we can trust and evolve. Standalone example projects make every sample discoverable, runnable, and ready for AI-assisted workflows. + +Try it and share feedback in [GitHub Discussions](https://github.com/flet-dev/flet/discussions) or on [Discord](https://discord.gg/dzWXP8SHG8). + +Happy Flet-ing! diff --git a/website/blog/2026-05-11-flet-v-0-85-release-announcement.md b/website/blog/2026-05-11-flet-v-0-85-release-announcement.md new file mode 100644 index 0000000000..8ef24c7b01 --- /dev/null +++ b/website/blog/2026-05-11-flet-v-0-85-release-announcement.md @@ -0,0 +1,283 @@ +--- +slug: flet-v-0-85-release-announcement +title: "Flet 0.85.0: Declarative apps grow up — Router, dialogs, and more" +authors: feodor +tags: [releases] +--- + +Flet 0.85.0 brings first-class declarative navigation and dialog management, richer media controls, and a long list of bug fixes. + +Highlights in this release: + +* Declarative `ft.Router` for `@ft.component` apps — nested routes, layouts with outlets, dynamic segments, data loaders, and `manage_views=True` for native view-stack navigation. +* New `ft.use_dialog()` hook — dialogs are now reactive state in declarative apps, not imperative `page.show_dialog()` calls. +* `flet-video`: configurable controls, `Video.take_screenshot()`, and `on_position_change` / `on_duration_change` events. +* `AudioRecorder` PCM16 streaming via `on_stream` chunks and direct upload through `AudioRecorderUploadSettings`. +* Tons of bug fixes — charts, web assets, packaging, mobile orientation, and more. + +{/* truncate */} + +## How to upgrade + +If you use pip: + +```bash +pip install 'flet[all]' --upgrade +``` + +If you use uv with `pyproject.toml` and want to upgrade everything: + +```bash +uv sync --upgrade +``` + +If you want to upgrade only Flet packages: + +```bash +uv sync --upgrade-package flet \ + --upgrade-package flet-cli \ + --upgrade-package flet-desktop \ + --upgrade-package flet-web +``` + +## Declarative Router + +Imperative Flet apps have always had `Page.route` and `Page.views` for navigation. But declarative apps — the ones built around `@ft.component` — had to roll their own: subscribe to route changes, parse the path, render the right component. It worked, but it was boilerplate that every app reinvented. + +0.85.0 adds `ft.Router`: a declarative, React Router-style component that matches the current page route against a tree of `ft.Route` definitions and renders the matched component chain. Here's the simplest possible example: + +```python +import flet as ft + +@ft.component +def Home(): + return ft.Text("Home page", size=24) + +@ft.component +def About(): + return ft.Text("About page", size=24) + +@ft.component +def App(): + return ft.SafeArea( + content=ft.Column([ + ft.Row([ + ft.Button("Home", on_click=lambda: ft.context.page.navigate("/")), + ft.Button("About", on_click=lambda: ft.context.page.navigate("/about")), + ]), + ft.Router([ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ]), + ]) + ) + +ft.run(lambda page: page.render(App)) +``` + +Routes can nest, and a parent route can render a shared layout that wraps its children using `ft.use_route_outlet()`: + +```python +@ft.component +def AppLayout(): + outlet = ft.use_route_outlet() + return ft.Column([ + ft.Container( + content=ft.Row([ + ft.Text("My App", size=20, weight=ft.FontWeight.BOLD), + ft.Button("Home", on_click=lambda: ft.context.page.navigate("/")), + ft.Button("About", on_click=lambda: ft.context.page.navigate("/about")), + ]), + bgcolor=ft.Colors.SURFACE_BRIGHT, + padding=10, + ), + ft.Container(content=outlet, padding=20), + ]) + +@ft.component +def App(): + return ft.Router([ + ft.Route(component=AppLayout, children=[ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ]), + ]) +``` + +What `Router` supports: + +* **Nested routes** with shared layouts via `outlet=True` and `ft.use_route_outlet()`. +* **Dynamic segments** like `/users/:id` and **optional segments** like `/posts/:id?`. +* **Splats** for catch-all paths (`/files/*`). +* **Custom regex constraints** on segment values. +* **Data loaders** that run before a route renders. +* **Active link detection** so navigation UI can highlight the current route. +* **Authentication patterns** for guarded routes. +* **`manage_views=True`** — switches the router into view-stack mode where each route returns a full `View` with its own `AppBar`. Navigating deeper pushes views onto the stack, and the user can swipe back or tap the AppBar back button on mobile. + +More info: + +* PR: [#6406](https://github.com/flet-dev/flet/pull/6406) +* Guide: [Router](/docs/cookbook/router) +* Docs: [Router](https://flet.dev/docs/controls/router) + +## `use_dialog()` hook + +Dialogs in imperative Flet are imperative: you call `page.show_dialog(...)` to open, `page.close_dialog()` to close. That model doesn't fit declarative apps, where the UI is supposed to be a function of state. Until now, the workaround was to keep a reference to the dialog and toggle `open` manually — fiddly and easy to get wrong. + +The new `ft.use_dialog()` hook closes that gap. Pass a `DialogControl` to show it, pass `None` to dismiss it. The dialog is portaled into the page's dialog overlay automatically, and removed when the component unmounts: + +```python +import asyncio +import flet as ft + +@ft.component +def App(): + show, set_show = ft.use_state(False) + deleting, set_deleting = ft.use_state(False) + + async def handle_delete(): + set_deleting(True) + await asyncio.sleep(2) + set_deleting(False) + set_show(False) + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete report.pdf?"), + content=ft.Text( + "Deleting, please wait..." if deleting else "This cannot be undone." + ), + actions=[ + ft.Button( + "Deleting..." if deleting else "Delete", + disabled=deleting, + on_click=handle_delete, + ), + ft.TextButton( + "Cancel", + on_click=lambda: set_show(False), + disabled=deleting, + ), + ], + on_dismiss=lambda: set_show(False), + ) + if show + else None + ) + + return ft.Button("Delete File", icon=ft.Icons.DELETE, on_click=lambda: set_show(True)) +``` + +A subtle but important detail: the hook uses **frozen-diff reactive updates**. When the component re-renders and you pass back a *new* dialog instance with different field values, the hook diffs it field-by-field against the previous instance and emits only the actual deltas — instead of replacing the dialog wholesale. That means a `TextField` inside an `AlertDialog` keeps its cursor, focus, and selection across re-renders, even though Python is handing the framework a brand-new control object on every build. + +You can also call `use_dialog()` multiple times in the same component to manage independent dialogs (e.g. a rename dialog and a delete dialog on the same screen), and each one is tracked separately. + +More info: + +* PR: [#6335](https://github.com/flet-dev/flet/pull/6335) + +## Better video controls + +`flet-video` got a substantial upgrade. The control bar is now fully configurable: you can use the built-in controls, replace them with your own widgets, hide them entirely, or specify different controls for normal and fullscreen modes. There's also a new `Video.take_screenshot()` method for capturing the currently displayed frame, and two new events for keeping your UI in sync with playback: + +* `on_position_change` — fires as playback progresses, useful for driving a custom progress bar. +* `on_duration_change` — fires when the video's duration becomes known (or changes between playlist entries). + +```python +async def handle_screenshot(e): + image_bytes = await video.take_screenshot() + # save, upload, display in an Image, etc. + +video = ft.Video( + playlist=[ft.VideoMedia("https://example.com/clip.mp4")], + on_position_change=lambda e: print(f"At {e.position}s"), + on_duration_change=lambda e: print(f"Duration: {e.duration}s"), +) +``` + +More info: + +* PR: [#6463](https://github.com/flet-dev/flet/pull/6463) + +## AudioRecorder streaming + +Until 0.85.0, `AudioRecorder` recorded to a file and you read the file back when you were done. That's fine for "record then transcribe" flows, but it doesn't work for real-time use cases — voice activity detection, live transcription, streaming an LLM voice assistant. + +Now `AudioRecorder` can stream raw PCM16 chunks via the new `on_stream` event as audio is captured. Here's the core of the streaming example — receive chunks, buffer them, and write a WAV when recording stops: + +```python +import flet as ft +import flet_audio_recorder as far + +def main(page: ft.Page): + buffer = bytearray() + + def handle_stream(e: far.AudioRecorderStreamEvent): + buffer.extend(e.chunk) + status.value = f"Streaming chunk {e.sequence}; {e.bytes_streamed} bytes." + + async def start(e): + buffer.clear() + await recorder.start_recording( + configuration=far.AudioRecorderConfiguration( + encoder=far.AudioEncoder.PCM16BITS, + sample_rate=44100, + channels=1, + ), + ) + + recorder = far.AudioRecorder(on_stream=handle_stream) + page.add(ft.Button("Start", on_click=start), status := ft.Text()) +``` + +For server-side capture without buffering through Python, point the recorder at an upload URL and the audio uploads as it streams: + +```python +upload_url = page.get_upload_url(file_name="rec.pcm", expires=600) +await recorder.start_recording( + upload=far.AudioRecorderUploadSettings(upload_url=upload_url, file_name="rec.pcm"), + configuration=far.AudioRecorderConfiguration(encoder=far.AudioEncoder.PCM16BITS), +) +``` + +More info: + +* PR: [#6423](https://github.com/flet-dev/flet/pull/6423) +* Issue: [#5858](https://github.com/flet-dev/flet/issues/5858) + +## Other improvements + +* Scrollable `NavigationRail` with optional `pin_leading_to_top` and `pin_trailing_to_bottom` ([#6356](https://github.com/flet-dev/flet/pull/6356)). +* Scroll support on `ResponsiveRow` for layouts whose content exceeds available height ([#6417](https://github.com/flet-dev/flet/pull/6417)). +* `CodeEditor.issues` for displaying analysis error markers in the gutter, with analysis performed in Python ([#6407](https://github.com/flet-dev/flet/pull/6407)). +* `Page.pop_views_until()` to pop multiple views and return a result to the destination ([#6347](https://github.com/flet-dev/flet/pull/6347)). +* `NavigationDrawerDestination.label` now accepts custom controls; new `NavigationDrawerTheme.icon_theme` ([#6395](https://github.com/flet-dev/flet/pull/6395)). +* `DragTargetEvent.local_position` and `global_position` (deprecating `x`, `y`, `offset`) ([#6401](https://github.com/flet-dev/flet/pull/6401)). +* `Page.theme_animation_style` for customizing the theme cross-fade between `theme` and `dark_theme` ([#6476](https://github.com/flet-dev/flet/pull/6476)). + +## Bug fixes worth calling out + +* Unbounded browser memory growth in `MatplotlibChart` on Flutter web during animations ([#6473](https://github.com/flet-dev/flet/pull/6473)). +* 3- and 4-digit hex color shorthand (`#c00`, `#fc00`) rendering as invisible ([#6421](https://github.com/flet-dev/flet/pull/6421)). +* `auto_scroll` silently doing nothing unless `scroll` was also explicitly set ([#6404](https://github.com/flet-dev/flet/pull/6404)). +* Flet web returning `index.html` with `200 OK` for missing asset files instead of a proper `404` ([#6425](https://github.com/flet-dev/flet/pull/6425)). +* `Lottie` failing to load local asset files on Windows desktop ([#6426](https://github.com/flet-dev/flet/pull/6426)). +* `Page.on_resize` and `Page.on_media_change` not firing after mobile orientation changes ([#6423](https://github.com/flet-dev/flet/pull/6423)). +* `flet pack` desktop bundles missing the client archive on Windows and Linux ([#6403](https://github.com/flet-dev/flet/pull/6403)). +* `Duration` fields silently decoding to `0` when given a Python `float` (e.g. `Duration(seconds=2.0)`) ([#6480](https://github.com/flet-dev/flet/pull/6480)). +* `page.window.destroy()` taking several seconds to close Windows desktop apps when `prevent_close` is enabled ([#6428](https://github.com/flet-dev/flet/pull/6428)). +* `Page` and `View` vertical centering when scrolling is enabled ([#6450](https://github.com/flet-dev/flet/pull/6450)). +* `LineChart` silently dropping custom axis labels whose value matched a tick after floating-point rounding ([#6459](https://github.com/flet-dev/flet/pull/6459)). +* Linux memory retention when repeatedly removing `flet_video.Video` controls ([#6416](https://github.com/flet-dev/flet/pull/6416)). + +See the full [CHANGELOG](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#0850) for the complete list. + +## Conclusion + +Flet 0.85.0 fills in two pieces that declarative apps were really missing: routing and dialogs. Combined with smoother video, real-time audio, and a healthy round of bug fixes, this release moves the `@ft.component` programming model from "promising" to "production-ready for real apps". + +Try it in your apps and share feedback in [GitHub Discussions](https://github.com/flet-dev/flet/discussions) or on [Discord](https://discord.gg/dzWXP8SHG8). + +Happy Flet-ing! diff --git a/website/blog/authors.yml b/website/blog/authors.yml new file mode 100644 index 0000000000..fa3fc34bb6 --- /dev/null +++ b/website/blog/authors.yml @@ -0,0 +1,17 @@ +feodor: + name: Feodor Fitsner + title: Flet founder and developer + url: ttps://github.com/FeodorFitsner + image_url: https://avatars0.githubusercontent.com/u/5041459?s=400&v=4 + socials: + github: FeodorFitsner + x: fletdev + +henri: + name: Henri Ndonko + title: Flet Contributor and Maintainer + url: https://github.com/ndonkoHenri + image_url: https://avatars.githubusercontent.com/u/98978078?v=4 + socials: + github: ndonkoHenri + x: ndonkoHenri \ No newline at end of file diff --git a/website/docs/archive/flet-controls.md b/website/docs/archive/flet-controls.md new file mode 100644 index 0000000000..cbc8f15cda --- /dev/null +++ b/website/docs/archive/flet-controls.md @@ -0,0 +1,279 @@ +--- +title: "flet-controls" +--- + +User interface is made of **Controls** (aka widgets). + +To make controls visible to a user they must be added to a [`Page`](../controls/page.md) (the top-most control in the tree) +or inside other controls. +Nesting controls into each other could be represented as a tree with [`Page`](../controls/page.md) as a root. + +Controls are just regular Python classes. Create control instances via constructors with parameters matching +their properties, for example: + +```python +ft.Text(value="Hello, world!", color="green") +``` + +To display control on a page add it to `controls` list of a Page and call `page.update()` to send page changes to a browser or desktop client: + +```python +import flet as ft + +def main(page: ft.Page): + t = ft.Text(value="Hello, world!", color="green") + page.controls.append(t) + page.update() + +ft.run(main) +``` + + +:::note +In the following examples we will be showing just the contents of `main` function. +::: +You can modify control properties and the UI will be updated on the next `page.update()`: + +```python +t = ft.Text() +page.add(t) # it's a shortcut for page.controls.append(t) and then page.update() + +for i in range(10): + t.value = f"Step {i}" + page.update() + time.sleep(1) +``` + +Some controls are "container" controls (like Page) which could contain other controls. For example, `Row` control allows arranging other controls in a row one-by-one: + +```python +page.add( + ft.Row( + controls=[ + ft.Text("A"), + ft.Text("B"), + ft.Text("C") + ] + ) +) +``` + +or `TextField` and `Button` next to it: + +```python +page.add( + ft.Row( + controls=[ + ft.TextField(label="Your name"), + ft.Button(text="Say my name!") + ] + ) +) +``` + +`page.update()` is smart enough to send only the changes made since its last call, so you can add a couple of new controls to the page, remove some of them, change other controls' properties and then call `page.update()` to do a batched update, for example: + +```python +for i in range(10): + page.controls.append(ft.Text(f"Line {i}")) + if i > 4: + page.controls.pop(0) + page.update() + time.sleep(0.3) +``` + +Some controls, like buttons, could have event handlers reacting on a user input, for example `Button.on_click`: + +```python +def button_clicked(e): + page.add(ft.Text("Clicked!")) + +page.add(ft.Button(text="Click me", on_click=button_clicked)) +``` + +and more advanced example for a simple To-Do: + +```python +import flet as ft + +def main(page): + async def add_clicked(e): + page.add(ft.Checkbox(label=new_task.value)) + new_task.value = "" + await new_task.focus() + new_task.update() + + new_task = ft.TextField(hint_text="What's needs to be done?", width=300) + page.add(ft.Row([new_task, ft.Button("Add", on_click=add_clicked)])) + +ft.run(main) +``` + + +:::info +Flet implements *imperative* UI model where you "manually" build application UI with stateful controls +and then mutate it by updating control properties. Flutter implements *declarative* model where UI is +automatically re-built on application data changes. +Managing application state in modern frontend applications is inherently complex task and Flet's "old-school" +approach could be more attractive to programmers without frontend experience. +::: +### `disabled` property + +Every control has `disabled` property which is `false` by default - control and all its children are enabled. +`disabled` property is mostly used with data entry controls like `TextField`, `Dropdown`, `Checkbox`, buttons. +However, `disabled` could be set to a parent control and its value will be propagated down to all children recursively. + +For example, if you have a form with multiple entry control you can set `disabled` property for each control individually: + +```python +first_name = ft.TextField() +last_name = ft.TextField() +first_name.disabled = True +last_name.disabled = True +page.add(first_name, last_name) +``` + +or you can put form controls into container, e.g. `Column` and then set `disabled` for the column: + +```python +first_name = ft.TextField() +last_name = ft.TextField() +c = ft.Column(controls=[ + first_name, + last_name +]) +c.disabled = True +page.add(c) +``` + +## Buttons + +`Button` is the most essential input control which generates `click` event when pressed: + +```python +btn = ft.Button("Click me!") +page.add(btn) +``` + + + +All events generated by controls on a web page are continuously sent back to your script, so how do you respond to a button click? + +## Event handlers + +Buttons with events in "Counter" app: + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + txt_number = ft.TextField(value="0", text_align="right", width=100) + + def minus_click(e): + txt_number.value = str(int(txt_number.value) - 1) + page.update() + + def plus_click(e): + txt_number.value = str(int(txt_number.value) + 1) + page.update() + + page.add( + ft.Row( + [ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + txt_number, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], + alignment=ft.MainAxisAlignment.CENTER, + ) + ) + +ft.run(main) +``` + + + +## Textbox + +Flet provides a number of [controls](/docs/controls) for building forms: +[`TextField`](../controls/textfield.md), [`Checkbox`](../controls/checkbox.md), [`Dropdown`](../controls/dropdown/index.md), +[`Button`](../controls/button.md). + +Let's ask a user for a name: + +```python +import flet as ft + +def main(page): + def btn_click(e): + if not txt_name.value: + txt_name.error_text = "Please enter your name" + page.update() + else: + name = txt_name.value + page.clean() + page.add(ft.Text(f"Hello, {name}!")) + + txt_name = ft.TextField(label="Your name") + + page.add(txt_name, ft.Button("Say hello!", on_click=btn_click)) + +ft.run(main) +``` + + + +## Checkbox + +The [`Checkbox`](../controls/checkbox.md) control provides you with various properties and events emmiters for ease of use. + +Let's create a one checkbox ToDo: + +```python +import flet as ft + +def main(page): + def checkbox_changed(e): + output_text.value = ( + f"You have learned how to ski : {todo_check.value}." + ) + page.update() + + output_text = ft.Text() + todo_check = ft.Checkbox(label="ToDo: Learn how to use ski", value=False, on_change=checkbox_changed) + page.add(todo_check, output_text) + +ft.run(main) +``` + + + +## Dropdown + +```python +import flet as ft + +def main(page: ft.Page): + def button_clicked(e): + output_text.value = f"Dropdown value is: {color_dropdown.value}" + page.update() + + output_text = ft.Text() + submit_btn = ft.Button(text="Submit", on_click=button_clicked) + color_dropdown = ft.Dropdown( + width=100, + options=[ + ft.dropdown.Option("Red"), + ft.dropdown.Option("Green"), + ft.dropdown.Option("Blue"), + ], + ) + page.add(color_dropdown, submit_btn, output_text) + +ft.run(main) +``` + + diff --git a/website/docs/archive/mobile-support.md b/website/docs/archive/mobile-support.md new file mode 100644 index 0000000000..5fcc6924a6 --- /dev/null +++ b/website/docs/archive/mobile-support.md @@ -0,0 +1,51 @@ +--- +title: "Mobile support" +sidebar_label: "Mobile support" +--- + +This article covers Flet's vision for going mobile and provides a roadmap. + +## Server-Driven UI + +Flet is a Server-driven UI (SDUI) framework. SDUI is an emerging technology which is the best described in [Technology Radar post](https://www.thoughtworks.com/en-ca/radar/techniques/server-driven-ui): + +> Server-driven UI separates the rendering into a generic container in the mobile app while the structure and data for each view is provided by the server. This means that changes that once required a round trip to an app store can now be accomplished via simple changes to the responses the server sends. + +Companies like [DoorDash](https://doordash.engineering/2021/08/24/improving-development-velocity-with-generic-server-driven-ui-components/), [Airbnb](https://medium.com/airbnb-engineering/a-deep-dive-into-airbnbs-server-driven-ui-system-842244c5f5), [Lyft](https://podcasts.apple.com/us/podcast/server-driven-ui-with-kevin-fang-jeff-hurray/id1453587931?i=1000509742062) and others have been successfully implementing Server-driven UI in their mobile apps to reduce time-to-market. + +### Flet approach + +Flet is going to implement Server-Driven UI approach where program written in Python or other language is running on the server and only a thin client - either standalone Flutter app (`.apk` or `.ipa` package) in app store or a Flutter widget as a part of another app - is delivered to a mobile: + +> Missing image omitted: Flet highlevel diagram + +Once SDUI experience is ready we'll start working on a [standalone mobile package](#standalone-mobile-package-for-flet-app). + +## Roadmap + +To provide the best experience for Flet apps on mobile platforms, we plan to release the following items by the end of this year: + +### Flet widget for Flutter + +The first step we are going to do is to separate Flet client into a Flutter widget and publish the package at https://pub.dev. +Flet widget could be then integrated by mobile developers into existing or new Flutter apps for adding dynamic server-driven UI experiences to the core app functionality. A new Flutter app could be also created with a single Flet widget just for the purpose of hosting a complete Flet app. + +Developers will follow Flutter guide for packaging, signing and distributing their apps to [Android](https://docs.flutter.dev/deployment/android), [iOS](https://docs.flutter.dev/deployment/ios), [Linux](https://docs.flutter.dev/deployment/linux), [macOS](https://docs.flutter.dev/deployment/macos) or [Windows](https://docs.flutter.dev/deployment/windows) platforms. + +Flet team will provide sample CI pipelines to automate packaging, signing and publishing of Flutter apps. + +### Flet Studio for iOS and Android + +The next step is a standalone "Flet Studio" app (the name is not final) in App Store and Google Play for "testing mobile experiences developed with Flet framework". Developers or beta testers will be able to "register" URL of their hosted Flet app within Flet Studio and instantly see how it performs on a mobile device. + +### White-labeled Flet mobile app + +We are going to provide a guide and CI pipeline for automatic publishing of white-labeled Flet app to a user App Store or Google Play account. This app will be "pinned" to a specific app URL and could additionally bundle app assets (media, fonts) to minimize network usage. + +### Standalone mobile package for Flet app + +We are going to investigate the way and develop a prototype for bundling together Flet framework, user program, language runtime and all dependencies into a standalone mobile package (`.apk` or `.ipa` package), so Flet program does not require a web server. + +### Embedding Flet into native apps + +We are going to provide a guide, sample apps and CI pipeline to integrate Flet widget into existing native Android and iOS apps (not developed with Flutter) using [Flutter Add-to-App](https://docs.flutter.dev/development/add-to-app) feature. [Put Flutter to work](https://medium.com/flutter/put-flutter-to-work-95f5fdcc592e) article gives a real-world example on how to integrate Flutter into existing mobile app. diff --git a/website/docs/archive/packaging-desktop-app-with-pyinstaller.md b/website/docs/archive/packaging-desktop-app-with-pyinstaller.md new file mode 100644 index 0000000000..7ce8e91b72 --- /dev/null +++ b/website/docs/archive/packaging-desktop-app-with-pyinstaller.md @@ -0,0 +1,152 @@ +--- +title: "packaging-desktop-app-with-pyinstaller" +--- + +:::danger[A better way to package is here] + +You can now use `flet build` command to package your Flet app into executable or install bundle for +macOS, Windows and Linux. + +`flet build` does not longer rely on PyInstaller like `flet pack` does, but uses Flutter SDK to produce a fast, offline, fully customizable (your own icons, about dialog and metadata) executable for Windows, Linux and macOS with Python runtime embedded into executable and running in-process. + +[Follow this guide for desktop packaging](../publish/index.md) +::: + +Flet Python app and all its dependencies can be packaged into an executable and user can run it on their computer without installing a Python interpreter or any modules. + +Flet wraps [PyInstaller](https://pyinstaller.org/en/stable/index.html) API to package Flet Python app and all its dependencies into a single package for Windows, macOS and Linux. To create Windows package, PyInstaller must be run on Windows; to build Linux app, it must be run on Linux; and to build macOS app - on macOS. + +Start from installing PyInstaller: + +``` +pip install pyinstaller +``` + +Navigate to the directory where your `.py` file is located and build your app with the following command: + +``` +flet pack your_program.py +``` + +Your bundled Flet app should now be available in `dist` folder. Try running the program to see if it works. + +On macOS: + +``` +open dist/your_program.app +``` + +on Windows: + +``` +dist\your_program.exe +``` + +on Linux: + +``` +dist/your_program +``` + +Now you can just zip the contents of `dist` folder and distribute to your users! They don't need Python or Flet installed to run your packaged program - what a great alternative to Electron! + +By default, an executable/bundle has the same name as a Python script. You can change it with `--name` argument: + +``` +flet pack your_program.py --name bundle_name +``` + +## Customizing package icon + +Default bundle app icon is diskette which might be confusing for younger developers missed those ancient times when [floppy disks](https://en.wikipedia.org/wiki/Floppy_disk) were used to store computer data. + +You can replace the icon with your own by adding `--icon` argument: + +``` +flet pack your_program.py --icon +``` + +PyInstaller will convert provided PNG to a platform specific format (`.ico` for Windows and `.icns` for macOS), but you need to install [Pillow](https://pillow.readthedocs.io/en/stable/) module for that: + +``` +pip install pillow +``` + +## Packaging assets + +Your Flet app can include [assets](../cookbook/assets.md). Provided app assets are in `assets` folder next to `your_program.py` they can be added to an application package with `--add-data` argument, on macOS/Linux: + +``` +flet pack your_program.py --add-data "assets:assets" +``` + +On Windows `assets;assets` must be delimited with `;`: + +``` +flet pack your_program.py --add-data "assets;assets" +``` + +## Customizing macOS bundle + +macOS bundle details can be customized with the following `flet pack` macOS-specific arguments: + +* `--product-name` - display name of macOS bundle, shown in Dock, Activity Monitor, About dialog. +* `--product-version` - bundle version shown in "About" dialog. +* `--copyright` - copyright notice shown in "About" dialog. +* `--bundle-id` unique bundle ID. + +
Flet app bundle about
+ +## Customizing Windows executable metadata + +Windows executable "Details" properties dialog can be customized with the following `flet pack` arguments: + +* `--product-name` - "Product name" field. +* `--product-version` - "Product version" field. +* `--file-version` - "File version" field. +* `--file-description` - "File description" field, also program display name in Task Manager. +* `--copyright` - "Copyright" field. + +## Using CI for multi-platform packaging + +To create an app package with PyInstaller for specific OS it must be run on that OS. + +If you don't have an access to Mac or PC you can bundle your app for all three platforms with [AppVeyor](https://www.appveyor.com) - Continuous Integration service for Windows, Linux and macOS. In short, Continuous Integration (CI) is an automated process of building, testing and deploying (Continuous Delivery - CD) application on every push to a repository. + +AppVeyor is free for open source projects hosted on GitHub, GitLab and Bitbucket. To use AppVeyor, push your app to a repository within one of those source-control providers. + +:::note +AppVeyor is the company behind Flet. +::: + +To get started with AppVeyor [sign up for a free account](https://ci.appveyor.com/signup). + +Click "New project" button, authorize AppVeyor to access your GitHub, GitLab or Bitbucket account, choose a repository with your program and create a new project. + +Now, to configure packaging of your app for Windows, Linux and macOS, add file with [the following contents](https://github.com/flet-dev/python-ci-example/blob/main/appveyor.yml) into the root of your repository `appveyor.yml`. `appveyor.yml` is a build configuration file, or CI workflow, describing build, test, packaging and deploy commands that must be run on every commit. + +:::note +You can just fork [flet-dev/python-ci-example](https://github.com/flet-dev/python-ci-example) repository and customize it to your needs. +::: + +When you push any changes to GitHub repository, AppVeyor will automatically start a new build: + +> Missing image omitted: AppVeyor CI Flet Python project + +What that [CI workflow](https://ci.appveyor.com/project/flet-dev/python-ci-example) does on every push to the repository: + +* Clones the repository to a clean virtual machine. +* Installs app dependencies using `pip`. +* Runs `flet pack` to package Python app into a bundle for **Windows**, **macOS** and **Ubuntu**. +* Zip/Tar app bundles and uploads them to ["Artifacts"](https://ci.appveyor.com/project/flet-dev/python-ci-example/build/job/g2j2lhstv04eyxcm/artifacts). +* Uploads app bundles to [**GitHub releases**](https://github.com/flet-dev/python-ci-example/releases) when a new tag is pushed. Just push a new tag to make a release! + +:::note[GITHUB_TOKEN] +`GITHUB_TOKEN` in `appveyor.yml` is a GitHub Personal Access Token (PAT) used by AppVeyor to publish created packages to repository "Releases". You need to generate your own token and replace it in `appveyor.yml`. Login to your GitHub account and navigate to [Personal access token](https://github.com/settings/tokens) page. Click "Generate new token" and select "public_repo" or "repo" scope for public or private repository respectively. Copy generated token to a clipboard and return to AppVeyor Portal. Navigate to [Encrypt configuration data](https://ci.appveyor.com/tools/encrypt) page and paste token to "Value to encrypt" field, click "Encrypt" button. Put encrypted value under `GITHUB_TOKEN` in your `appveyor.yml`. +::: + +Configure AppVeyor for your Python project, push a new tag to a repository and "automagically" get desktop bundle for all three platforms in GitHub releases! 🎉 + +> Missing image omitted: AppVeyor CI Flet GitHub releases + +In addition to [GitHub Releases](https://www.appveyor.com/docs/deployment/github/), you can also configure releasing of artifacts to [Amazon S3 bucket](https://www.appveyor.com/docs/deployment/amazon-s3/) or [Azure Blob storage](https://www.appveyor.com/docs/deployment/azure-blob/). diff --git a/website/docs/cli/flet-build.md b/website/docs/cli/flet-build.md new file mode 100644 index 0000000000..312e00280f --- /dev/null +++ b/website/docs/cli/flet-build.md @@ -0,0 +1,7 @@ +--- +title: "flet build" +--- + +import CliBuild from '@site/.crocodocs/cli-build.mdx'; + + diff --git a/website/docs/cli/flet-create.md b/website/docs/cli/flet-create.md new file mode 100644 index 0000000000..1e37a64e8a --- /dev/null +++ b/website/docs/cli/flet-create.md @@ -0,0 +1,7 @@ +--- +title: "flet create" +--- + +import CliCreate from '@site/.crocodocs/cli-create.mdx'; + + diff --git a/website/docs/cli/flet-debug.md b/website/docs/cli/flet-debug.md new file mode 100644 index 0000000000..5b5a26c805 --- /dev/null +++ b/website/docs/cli/flet-debug.md @@ -0,0 +1,7 @@ +--- +title: "flet debug" +--- + +import CliDebug from '@site/.crocodocs/cli-debug.mdx'; + + diff --git a/website/docs/cli/flet-devices.md b/website/docs/cli/flet-devices.md new file mode 100644 index 0000000000..08094a100e --- /dev/null +++ b/website/docs/cli/flet-devices.md @@ -0,0 +1,7 @@ +--- +title: "flet devices" +--- + +import CliDevices from '@site/.crocodocs/cli-devices.mdx'; + + diff --git a/website/docs/cli/flet-doctor.md b/website/docs/cli/flet-doctor.md new file mode 100644 index 0000000000..1d0a041cec --- /dev/null +++ b/website/docs/cli/flet-doctor.md @@ -0,0 +1,7 @@ +--- +title: "flet doctor" +--- + +import CliDoctor from '@site/.crocodocs/cli-doctor.mdx'; + + diff --git a/website/docs/cli/flet-emulators.md b/website/docs/cli/flet-emulators.md new file mode 100644 index 0000000000..5857ad958e --- /dev/null +++ b/website/docs/cli/flet-emulators.md @@ -0,0 +1,7 @@ +--- +title: "flet emulators" +--- + +import CliEmulators from '@site/.crocodocs/cli-emulators.mdx'; + + diff --git a/website/docs/cli/flet-pack.md b/website/docs/cli/flet-pack.md new file mode 100644 index 0000000000..51114ea78b --- /dev/null +++ b/website/docs/cli/flet-pack.md @@ -0,0 +1,7 @@ +--- +title: "flet pack" +--- + +import CliPack from '@site/.crocodocs/cli-pack.mdx'; + + diff --git a/website/docs/cli/flet-publish.md b/website/docs/cli/flet-publish.md new file mode 100644 index 0000000000..b825bd1c30 --- /dev/null +++ b/website/docs/cli/flet-publish.md @@ -0,0 +1,7 @@ +--- +title: "flet publish" +--- + +import CliPublish from '@site/.crocodocs/cli-publish.mdx'; + + diff --git a/website/docs/cli/flet-run.md b/website/docs/cli/flet-run.md new file mode 100644 index 0000000000..2379171ab9 --- /dev/null +++ b/website/docs/cli/flet-run.md @@ -0,0 +1,7 @@ +--- +title: "flet run" +--- + +import CliRun from '@site/.crocodocs/cli-run.mdx'; + + diff --git a/website/docs/cli/flet-serve.md b/website/docs/cli/flet-serve.md new file mode 100644 index 0000000000..d929cee846 --- /dev/null +++ b/website/docs/cli/flet-serve.md @@ -0,0 +1,7 @@ +--- +title: "flet serve" +--- + +import CliServe from '@site/.crocodocs/cli-serve.mdx'; + + diff --git a/website/docs/cli/index.md b/website/docs/cli/index.md new file mode 100644 index 0000000000..85abe39297 --- /dev/null +++ b/website/docs/cli/index.md @@ -0,0 +1,11 @@ +--- +title: "Overview" +--- + +import CliRoot from '@site/.crocodocs/cli-root.mdx'; + +# Flet CLI + +Flet command-line interface (CLI) provides an easy way to create, run, test and package Flet apps. + + diff --git a/website/docs/controls/adaptivecontrol.md b/website/docs/controls/adaptivecontrol.md new file mode 100644 index 0000000000..1be74841ae --- /dev/null +++ b/website/docs/controls/adaptivecontrol.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.AdaptiveControl" +title: "AdaptiveControl" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/bannerad.md b/website/docs/controls/ads/bannerad.md new file mode 100644 index 0000000000..d91c3b16d3 --- /dev/null +++ b/website/docs/controls/ads/bannerad.md @@ -0,0 +1,20 @@ +--- +class_name: "flet_ads.banner_ad.BannerAd" +examples: "extensions/ads" +example_images: "examples/extensions/ads/media" +title: "BannerAd" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + + + diff --git a/website/docs/controls/ads/basead.md b/website/docs/controls/ads/basead.md new file mode 100644 index 0000000000..b06bd00678 --- /dev/null +++ b/website/docs/controls/ads/basead.md @@ -0,0 +1,7 @@ +--- +title: "BaseAd" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/index.md b/website/docs/controls/ads/index.md new file mode 100644 index 0000000000..c946b693d2 --- /dev/null +++ b/website/docs/controls/ads/index.md @@ -0,0 +1,113 @@ +--- +examples: "extensions/ads" +example_images: "examples/extensions/ads/media" +title: "Ads" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +# Ads + +Displaying Google Ads in [Flet](https://flet.dev) apps. + +It is powered by the [google_mobile_ads](https://pub.dev/packages/google_mobile_ads) Flutter package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | + +## Usage + +To use ads controls add `flet-ads` package to your project dependencies: + + + +```bash +uv add flet-ads +``` + + + +```bash +pip install flet-ads # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Requirements + +The below sections show the required configurations for each platform. + +### Android + +A valid [AdMob app ID](https://support.google.com/admob/answer/7356431) +is required to be specified, otherwise the app might crash on launch or behave unexpectedly. + + + +```bash +flet build apk \ + --android-meta-data com.google.android.gms.ads.APPLICATION_ID="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy" +``` + + +```toml +[tool.flet.android.meta_data] +"com.google.android.gms.ads.APPLICATION_ID" = "ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy" +``` + + +See also: + +- [setting Android permissions](../../publish/android.md#permissions) +- [AdMob app ID for testing purposes](#test-values) + +### iOS + +A valid [AdMob app ID](https://support.google.com/admob/answer/7356431) +is required to be specified, otherwise the app might crash on launch or behave unexpectedly. + + + +```bash +flet build ipa \ + --info-plist GADApplicationIdentifier="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy" +``` + + +```toml +[tool.flet.ios.info] +GADApplicationIdentifier = "ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy" +``` + + +See also: + +- [setting iOS permissions](../../publish/ios.md#permissions) +- [AdMob app ID for testing purposes](#test-values) + +### Test Values + +AdMob [provides](https://developers.google.com/admob/flutter/banner#always_test_with_test_ads) app and ad unit IDs for +testing purposes. + +* **AdMob app ID**: `"ca-app-pub-3940256099942544~3347511713"` +* [`BannerAd.unit_id`](bannerad.md) + - **Android**: `"ca-app-pub-3940256099942544/9214589741"` + - **iOS**: `"ca-app-pub-3940256099942544/2435281174"` +* [`InterstitialAd.unit_id`](interstitialad.md) + - **Android**: `"ca-app-pub-3940256099942544/1033173712"` + - **iOS**: `"ca-app-pub-3940256099942544/4411468910"` + +**They are not meant to be used in production.** + +## Example + + + + diff --git a/website/docs/controls/ads/interstitialad.md b/website/docs/controls/ads/interstitialad.md new file mode 100644 index 0000000000..8e559976a9 --- /dev/null +++ b/website/docs/controls/ads/interstitialad.md @@ -0,0 +1,20 @@ +--- +class_name: "flet_ads.interstitial_ad.InterstitialAd" +examples: "extensions/ads" +example_images: "examples/extensions/ads/media" +title: "InterstitialAd" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + + + diff --git a/website/docs/controls/ads/types/adrequest.md b/website/docs/controls/ads/types/adrequest.md new file mode 100644 index 0000000000..fd1f035823 --- /dev/null +++ b/website/docs/controls/ads/types/adrequest.md @@ -0,0 +1,7 @@ +--- +title: "AdRequest" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/types/paidadevent.md b/website/docs/controls/ads/types/paidadevent.md new file mode 100644 index 0000000000..6de2004e96 --- /dev/null +++ b/website/docs/controls/ads/types/paidadevent.md @@ -0,0 +1,7 @@ +--- +title: "PaidAdRequest" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/ads/types/precisiontype.md b/website/docs/controls/ads/types/precisiontype.md new file mode 100644 index 0000000000..1113c6cbc7 --- /dev/null +++ b/website/docs/controls/ads/types/precisiontype.md @@ -0,0 +1,7 @@ +--- +title: "PrecisionType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/alertdialog.md b/website/docs/controls/alertdialog.md new file mode 100644 index 0000000000..5c2e131b9d --- /dev/null +++ b/website/docs/controls/alertdialog.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.AlertDialog" +examples: "controls/material/alert_dialog" +example_images: "test-images/examples/controls/material/golden/macos/alert_dialog" +title: "AlertDialog" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/alertdialog) + +### Modal and non-modal dialogs + + + +Modal and non-modal dialogs + + diff --git a/website/docs/controls/animatedswitcher.md b/website/docs/controls/animatedswitcher.md new file mode 100644 index 0000000000..6789fa7966 --- /dev/null +++ b/website/docs/controls/animatedswitcher.md @@ -0,0 +1,30 @@ +--- +class_name: "flet.AnimatedSwitcher" +examples: "controls/core/animated_switcher" +example_images: "examples/controls/core/animated_switcher/media" +title: "AnimatedSwitcher" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/animations/animated_switcher) + +### Animated switching between two containers with scale effect + + + +scale-effect + +### Animate Image switch + + + +### Animate Image switch buffered + + + + diff --git a/website/docs/controls/appbar.md b/website/docs/controls/appbar.md new file mode 100644 index 0000000000..df5a292160 --- /dev/null +++ b/website/docs/controls/appbar.md @@ -0,0 +1,29 @@ +--- +class_name: "flet.AppBar" +examples: "controls/material/app_bar" +example_images: "test-images/examples/controls/material/golden/macos/app_bar" +example_media: "examples/controls/material/app_bar/media" +title: "AppBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/appbar) + +### Actions and Popup Menu + + + +actions-and-popup-menu + +### Theme and Material Mode Toggles + + + +theme-and-material-mode-toggles + + diff --git a/website/docs/controls/autocomplete.md b/website/docs/controls/autocomplete.md new file mode 100644 index 0000000000..f90be7ae78 --- /dev/null +++ b/website/docs/controls/autocomplete.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.AutoComplete" +examples: "controls/material/auto_complete" +example_images: "test-images/examples/controls/material/golden/macos/auto_complete" +title: "AutoComplete" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/autocomplete) + +### Basic example + + + +auto-complete-basic-example + + diff --git a/website/docs/controls/autofillgroup.md b/website/docs/controls/autofillgroup.md new file mode 100644 index 0000000000..59c3805cdf --- /dev/null +++ b/website/docs/controls/autofillgroup.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.AutofillGroup" +examples: "controls/material/autofill_group" +example_images: "examples/controls/material/autofill_group/media" +title: "AutofillGroup" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/autofillgroup) + +### Basic example + + + +basic + + diff --git a/website/docs/controls/banner.md b/website/docs/controls/banner.md new file mode 100644 index 0000000000..f782b6b01d --- /dev/null +++ b/website/docs/controls/banner.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.Banner" +examples: "controls/material/banner" +example_images: "test-images/examples/controls/material/golden/macos/banner" +example_media: "examples/controls/material/banner/media" +title: "Banner" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/banner) + +### Basic example + + + +basic + + diff --git a/website/docs/controls/basecontrol.md b/website/docs/controls/basecontrol.md new file mode 100644 index 0000000000..39bd7f2eec --- /dev/null +++ b/website/docs/controls/basecontrol.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.BaseControl" +title: "BaseControl" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/basepage.md b/website/docs/controls/basepage.md new file mode 100644 index 0000000000..3c920c9eca --- /dev/null +++ b/website/docs/controls/basepage.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.BasePage" +title: "BasePage" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/bottomappbar.md b/website/docs/controls/bottomappbar.md new file mode 100644 index 0000000000..816f7e5182 --- /dev/null +++ b/website/docs/controls/bottomappbar.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.BottomAppBar" +examples: "controls/material/bottom_app_bar" +example_images: "test-images/examples/controls/material/golden/macos/bottom_app_bar" +title: "BottomAppBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/bottomappbar) + +### Notched `FloatingActionButton` + + + + + +### Custom border radius + + + + + + diff --git a/website/docs/controls/bottomsheet.md b/website/docs/controls/bottomsheet.md new file mode 100644 index 0000000000..1b065339f2 --- /dev/null +++ b/website/docs/controls/bottomsheet.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.BottomSheet" +examples: "controls/material/bottom_sheet" +example_images: "test-images/examples/controls/material/golden/macos/bottom_sheet" +title: "BottomSheet" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/bottomsheet) + +### Basic example + + + + + +### Fullscreen + + + + + + diff --git a/website/docs/controls/button.md b/website/docs/controls/button.md new file mode 100644 index 0000000000..2cc965769c --- /dev/null +++ b/website/docs/controls/button.md @@ -0,0 +1,62 @@ +--- +class_name: "flet.Button" +examples: "controls/material/button" +example_images: "test-images/examples/controls/material/golden/macos/button" +title: "Button" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/elevatedbutton) + +### Button + + + +Basic button + +### Icons + + + +Basic button + +### Handling clicks + + + +Handling clicks + +### Custom content + + + +Buttons with custom content + +### Shapes + + + +Buttons with different shapes + +### Styling + + + +Styled button - default state + +Styled button - hovered state + +### Animate on hover + + + +Unhovered button + +Hovered button + + diff --git a/website/docs/controls/camera/index.md b/website/docs/controls/camera/index.md new file mode 100644 index 0000000000..ce765eb7cb --- /dev/null +++ b/website/docs/controls/camera/index.md @@ -0,0 +1,129 @@ +--- +class_name: "flet_camera.Camera" +examples: "extensions/camera" +title: "Camera" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Camera + +Display a live camera preview, capture photos and videos, and stream camera frames directly in your Flet apps. + +Powered by the [camera](https://pub.dev/packages/camera) Flutter package. + +## Platform Support + +| Platform | iOS | Android | Web | Windows | macOS | Linux | +|-----------|-----|---------|-----|---------|-------|-------| +| Supported | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | + +## Usage + +Add the `flet-camera` package to your project dependencies: + + + +```bash +uv add flet-camera +``` + + + +```bash +pip install flet-camera # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +:::tip[Permissions] +Request camera (and microphone if recording video with audio) permissions on mobile platforms before initializing the control. You can use [`PermissionHandler`](../../services/permissionhandler/index.md) to prompt the user. +You can also use [predefined cross-platform permission bundles](../../publish/index.md#predefined-cross-platform-permission-bundles) for camera and microphone permissions. +::: + +## Requirements + +The below sections show the required configurations for each platform. + +### Android + +Configuration to be made to access the camera and optionally the microphone: + +- [`android.permission.CAMERA`](https://developer.android.com/reference/android/Manifest.permission#CAMERA): Allows camera usage. +- [`android.permission.RECORD_AUDIO`](https://developer.android.com/reference/android/Manifest.permission#RECORD_AUDIO) (optional): Allows video recording with audio. + + + +```bash +flet build apk \ + --android-permissions android.permission.CAMERA=true \ + --android-permissions android.permission.RECORD_AUDIO=true +``` + + +```toml +[tool.flet.android.permission] +"android.permission.CAMERA" = true +"android.permission.RECORD_AUDIO" = true +``` + + +See also: + +- [setting Android permissions](../../publish/android.md#permissions) + +### iOS + +Configuration to be made to access the camera and optionally the microphone: + +- [`NSCameraUsageDescription`](https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSCameraUsageDescription): Required for camera usage. +- [`NSMicrophoneUsageDescription`](https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSMicrophoneUsageDescription) (optional): Required only for video recording with audio. For example, when `enable_audio` parameter of [`Camera.initialize`](index.md#flet_camera.Camera.initialize) is set to `True` (default). + + + +```bash +flet build ipa \ + --info-plist NSCameraUsageDescription="Some message to describe why you need this permission..." \ + --info-plist NSMicrophoneUsageDescription="Some message to describe why you need this permission..." +``` + + +```toml +[tool.flet.ios.info] +NSCameraUsageDescription = "Some message to describe why you need this permission..." +NSMicrophoneUsageDescription = "Some message to describe why you need this permission..." +``` + + +See also: + +- [setting iOS permissions](../../publish/ios.md#permissions) + +### Cross-platform + +Additionally/alternatively, you can make use of our predefined cross-platform `camera` (and optionally `microphone`) +[permission bundles](../../publish/index.md#predefined-cross-platform-permission-bundles): + + + +```bash +flet build --permissions camera microphone +``` + + +```toml +[tool.flet] +permissions = ["camera", "microphone"] +``` + + +## Example + + + +## Description + + diff --git a/website/docs/controls/camera/types/cameradescription.md b/website/docs/controls/camera/types/cameradescription.md new file mode 100644 index 0000000000..1da067741f --- /dev/null +++ b/website/docs/controls/camera/types/cameradescription.md @@ -0,0 +1,7 @@ +--- +title: "CameraDescription" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/cameraimageevent.md b/website/docs/controls/camera/types/cameraimageevent.md new file mode 100644 index 0000000000..dc393e2ed1 --- /dev/null +++ b/website/docs/controls/camera/types/cameraimageevent.md @@ -0,0 +1,7 @@ +--- +title: "CameraImageEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/cameralensdirection.md b/website/docs/controls/camera/types/cameralensdirection.md new file mode 100644 index 0000000000..07a0df80d3 --- /dev/null +++ b/website/docs/controls/camera/types/cameralensdirection.md @@ -0,0 +1,7 @@ +--- +title: "CameraLensDirection" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/cameralenstype.md b/website/docs/controls/camera/types/cameralenstype.md new file mode 100644 index 0000000000..4d3ebf57d2 --- /dev/null +++ b/website/docs/controls/camera/types/cameralenstype.md @@ -0,0 +1,7 @@ +--- +title: "CameraLensType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/camerapreviewsize.md b/website/docs/controls/camera/types/camerapreviewsize.md new file mode 100644 index 0000000000..4200b32619 --- /dev/null +++ b/website/docs/controls/camera/types/camerapreviewsize.md @@ -0,0 +1,7 @@ +--- +title: "CameraPreviewSize" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/camerastateevent.md b/website/docs/controls/camera/types/camerastateevent.md new file mode 100644 index 0000000000..641b11e257 --- /dev/null +++ b/website/docs/controls/camera/types/camerastateevent.md @@ -0,0 +1,7 @@ +--- +title: "CameraStateEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/exposuremode.md b/website/docs/controls/camera/types/exposuremode.md new file mode 100644 index 0000000000..d308f1591b --- /dev/null +++ b/website/docs/controls/camera/types/exposuremode.md @@ -0,0 +1,7 @@ +--- +title: "ExposureMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/flashmode.md b/website/docs/controls/camera/types/flashmode.md new file mode 100644 index 0000000000..9770c0d3d7 --- /dev/null +++ b/website/docs/controls/camera/types/flashmode.md @@ -0,0 +1,7 @@ +--- +title: "FlashMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/focusmode.md b/website/docs/controls/camera/types/focusmode.md new file mode 100644 index 0000000000..bf8088cdd9 --- /dev/null +++ b/website/docs/controls/camera/types/focusmode.md @@ -0,0 +1,7 @@ +--- +title: "FocusMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/imageformatgroup.md b/website/docs/controls/camera/types/imageformatgroup.md new file mode 100644 index 0000000000..9d73eaf407 --- /dev/null +++ b/website/docs/controls/camera/types/imageformatgroup.md @@ -0,0 +1,7 @@ +--- +title: "ImageFormatGroup" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/camera/types/resolutionpreset.md b/website/docs/controls/camera/types/resolutionpreset.md new file mode 100644 index 0000000000..df95d08f17 --- /dev/null +++ b/website/docs/controls/camera/types/resolutionpreset.md @@ -0,0 +1,7 @@ +--- +title: "ResolutionPreset" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/arc.md b/website/docs/controls/canvas/arc.md new file mode 100644 index 0000000000..bdc121ad8b --- /dev/null +++ b/website/docs/controls/canvas/arc.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Arc" +title: "Arc" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/circle.md b/website/docs/controls/canvas/circle.md new file mode 100644 index 0000000000..d9524ef426 --- /dev/null +++ b/website/docs/controls/canvas/circle.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Circle" +title: "Circle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/color.md b/website/docs/controls/canvas/color.md new file mode 100644 index 0000000000..f9f70a1857 --- /dev/null +++ b/website/docs/controls/canvas/color.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Color" +title: "Color" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/fill.md b/website/docs/controls/canvas/fill.md new file mode 100644 index 0000000000..72ca09930b --- /dev/null +++ b/website/docs/controls/canvas/fill.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Fill" +title: "Fill" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/image.md b/website/docs/controls/canvas/image.md new file mode 100644 index 0000000000..71124e2f74 --- /dev/null +++ b/website/docs/controls/canvas/image.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Image" +title: "Image" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/index.md b/website/docs/controls/canvas/index.md new file mode 100644 index 0000000000..c08f95cab2 --- /dev/null +++ b/website/docs/controls/canvas/index.md @@ -0,0 +1,57 @@ +--- +class_name: "flet.canvas.Canvas" +examples: "controls/core/canvas" +example_images: "test-images/examples/controls/core/golden/macos/canvas" +example_media: "examples/controls/core/canvas/media" +title: "Canvas" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# Canvas + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/canvas) + +### Smiling face + + + +smiling-face + +### Flet logo + + + +flet-logo + +### Triangles + + + +triangles + +### Bezier curves + + + +bezier-curves + +### Text + + + +text + +### Free-hand drawing with image capture + + + +### Gradients + + + + diff --git a/website/docs/controls/canvas/line.md b/website/docs/controls/canvas/line.md new file mode 100644 index 0000000000..6ff9aadec2 --- /dev/null +++ b/website/docs/controls/canvas/line.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Line" +title: "Line" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/oval.md b/website/docs/controls/canvas/oval.md new file mode 100644 index 0000000000..ba49f4c6ed --- /dev/null +++ b/website/docs/controls/canvas/oval.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Oval" +title: "Oval" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/path.md b/website/docs/controls/canvas/path.md new file mode 100644 index 0000000000..5144f13243 --- /dev/null +++ b/website/docs/controls/canvas/path.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Path" +title: "Path" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/points.md b/website/docs/controls/canvas/points.md new file mode 100644 index 0000000000..8136defa47 --- /dev/null +++ b/website/docs/controls/canvas/points.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Points" +title: "Points" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/rect.md b/website/docs/controls/canvas/rect.md new file mode 100644 index 0000000000..a9124dbbd3 --- /dev/null +++ b/website/docs/controls/canvas/rect.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Rect" +title: "Rect" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/shadow.md b/website/docs/controls/canvas/shadow.md new file mode 100644 index 0000000000..91205fc1d0 --- /dev/null +++ b/website/docs/controls/canvas/shadow.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Shadow" +title: "Shadow" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/shape.md b/website/docs/controls/canvas/shape.md new file mode 100644 index 0000000000..6a864f2ecf --- /dev/null +++ b/website/docs/controls/canvas/shape.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Shape" +title: "Shape" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/canvas/text.md b/website/docs/controls/canvas/text.md new file mode 100644 index 0000000000..562195e576 --- /dev/null +++ b/website/docs/controls/canvas/text.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.canvas.Text" +title: "Text" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/card.md b/website/docs/controls/card.md new file mode 100644 index 0000000000..48ca5260a3 --- /dev/null +++ b/website/docs/controls/card.md @@ -0,0 +1,20 @@ +--- +class_name: "flet.Card" +examples: "controls/material/card" +example_images: "test-images/examples/controls/material/golden/macos/card" +title: "Card" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/card) + + + +music-info + + diff --git a/website/docs/controls/charts/barchart.md b/website/docs/controls/charts/barchart.md new file mode 100644 index 0000000000..07aae7bc1a --- /dev/null +++ b/website/docs/controls/charts/barchart.md @@ -0,0 +1,27 @@ +--- +class_name: "flet_charts.bar_chart.BarChart" +examples: "extensions/charts/bar_chart" +example_images: "test-images-charts/examples/golden/macos/bar_chart" +diagram: "/docs/assets/controls/charts/bar-chart-diagram.svg" +title: "BarChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + + +### Example 2 + + + + + + diff --git a/website/docs/controls/charts/candlestickchart.md b/website/docs/controls/charts/candlestickchart.md new file mode 100644 index 0000000000..1b0176d772 --- /dev/null +++ b/website/docs/controls/charts/candlestickchart.md @@ -0,0 +1,20 @@ +--- +class_name: "flet_charts.candlestick_chart.CandlestickChart" +examples: "extensions/charts/candlestick_chart" +example_images: "test-images-charts/examples/golden/macos/candlestick_chart" +title: "CandlestickChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Candlestick Chart + + + + + + diff --git a/website/docs/controls/charts/index.md b/website/docs/controls/charts/index.md new file mode 100644 index 0000000000..3cc60f56c8 --- /dev/null +++ b/website/docs/controls/charts/index.md @@ -0,0 +1,49 @@ +--- +examples: "extensions/charts" +title: "Overview" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +# Charts + +Interactive chart controls powered by [flet-charts](https://pypi.org/project/flet-charts/) let you display data as bar, line, pie, scatter and plotly visualisations directly in your Flet apps. + +It is built on top of the [fl_chart](https://pub.dev/packages/fl_chart) Flutter package and ships with helper classes for axis labels, tooltips and more. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-charts` to your project dependencies: + + + +```bash +uv add flet-charts +``` + + + +```bash +pip install flet-charts # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Available Charts + +- [`BarChart`](barchart.md) +- [`CandlestickChart`](candlestickchart.md) +- [`LineChart`](linechart.md) +- [`MatplotlibChart`](matplotlibchart.md) +- [`PieChart`](piechart.md) +- [`PlotlyChart`](plotlychart.md) +- [`RadarChart`](radarchart.md) +- [`ScatterChart`](scatterchart.md) diff --git a/website/docs/controls/charts/linechart.md b/website/docs/controls/charts/linechart.md new file mode 100644 index 0000000000..d6a4912eae --- /dev/null +++ b/website/docs/controls/charts/linechart.md @@ -0,0 +1,27 @@ +--- +class_name: "flet_charts.line_chart.LineChart" +examples: "extensions/charts/line_chart" +example_images: "test-images-charts/examples/golden/macos/line_chart" +diagram: "/docs/assets/controls/charts/line-chart-diagram.svg" +title: "LineChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + + +### Example 2 + + + + + + diff --git a/website/docs/controls/charts/matplotlibchart.md b/website/docs/controls/charts/matplotlibchart.md new file mode 100644 index 0000000000..ad71b65565 --- /dev/null +++ b/website/docs/controls/charts/matplotlibchart.md @@ -0,0 +1,23 @@ +--- +class_name: "flet_charts.matplotlib_chart.MatplotlibChart" +examples: "extensions/charts/matplotlib_chart" +example_images: "test-images-charts/examples/golden/macos/matplotlib_chart" +example_media: "examples/extensions/charts/matplotlib_chart/media" +title: "MatplotlibChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Bar chart + +Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/lines_bars_and_markers/bar_colors.html#sphx-glr-gallery-lines-bars-and-markers-bar-colors-py). + + + + + + diff --git a/website/docs/controls/charts/matplotlibchartwithtoolbar.md b/website/docs/controls/charts/matplotlibchartwithtoolbar.md new file mode 100644 index 0000000000..41728d9833 --- /dev/null +++ b/website/docs/controls/charts/matplotlibchartwithtoolbar.md @@ -0,0 +1,41 @@ +--- +class_name: "flet_charts.matplotlib_chart_with_toolbar.MatplotlibChartWithToolbar" +examples: "extensions/charts/matplotlib_chart" +example_images: "test-images-charts/examples/golden/macos/matplotlib_chart" +example_media: "examples/extensions/charts/matplotlib_chart/media" +title: "MatplotlibChartWithToolbar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic + +Based on an official [Matplotlib example](https://matplotlib.org/stable/gallery/lines_bars_and_markers/cohere.html#sphx-glr-gallery-lines-bars-and-markers-cohere-py). + + + + + +### 3D chart + + + + + +### Handle events + + + + + +### Animated chart + + + + + + diff --git a/website/docs/controls/charts/piechart.md b/website/docs/controls/charts/piechart.md new file mode 100644 index 0000000000..6c4b3dbd79 --- /dev/null +++ b/website/docs/controls/charts/piechart.md @@ -0,0 +1,33 @@ +--- +class_name: "flet_charts.pie_chart.PieChart" +examples: "extensions/charts/pie_chart" +example_images: "test-images-charts/examples/golden/macos/pie_chart" +diagram: "/docs/assets/controls/charts/pie-chart-diagram.svg" +title: "PieChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + + +### Example 2 + + + + + +### Example 3 + + + + + + diff --git a/website/docs/controls/charts/plotlychart.md b/website/docs/controls/charts/plotlychart.md new file mode 100644 index 0000000000..d125a595df --- /dev/null +++ b/website/docs/controls/charts/plotlychart.md @@ -0,0 +1,46 @@ +--- +class_name: "flet_charts.plotly_chart.PlotlyChart" +examples: "extensions/charts/plotly_chart" +example_images: "test-images-charts/examples/golden/macos/plotly_chart" +title: "PlotlyChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + +Based on an official [Plotly example](https://plotly.com/python/line-charts). + + + + + +### Example 2 + +Based on an official [Plotly example](https://plotly.com/python/bar-charts). + + + + + +### Example 3 + +Based on an official [Plotly example](https://plotly.com/python/pie-charts). + + + + + +### Example 4 + +Based on an official [Plotly example](https://plotly.com/python/box-plots). + + + + + + diff --git a/website/docs/controls/charts/radarchart.md b/website/docs/controls/charts/radarchart.md new file mode 100644 index 0000000000..dac5aaa738 --- /dev/null +++ b/website/docs/controls/charts/radarchart.md @@ -0,0 +1,20 @@ +--- +class_name: "flet_charts.radar_chart.RadarChart" +examples: "extensions/charts/radar_chart" +example_images: "test-images-charts/examples/golden/macos/radar_chart" +title: "RadarChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + + + diff --git a/website/docs/controls/charts/scatterchart.md b/website/docs/controls/charts/scatterchart.md new file mode 100644 index 0000000000..7850a9b727 --- /dev/null +++ b/website/docs/controls/charts/scatterchart.md @@ -0,0 +1,20 @@ +--- +class_name: "flet_charts.scatter_chart.ScatterChart" +examples: "extensions/charts/scatter_chart" +example_images: "test-images-charts/examples/golden/macos/scatter_chart" +title: "ScatterChart" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Scatter Chart + + + + + + diff --git a/website/docs/controls/charts/types/barchartevent.md b/website/docs/controls/charts/types/barchartevent.md new file mode 100644 index 0000000000..9fee4b52a4 --- /dev/null +++ b/website/docs/controls/charts/types/barchartevent.md @@ -0,0 +1,7 @@ +--- +title: "BarChartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/barchartgroup.md b/website/docs/controls/charts/types/barchartgroup.md new file mode 100644 index 0000000000..db30a06424 --- /dev/null +++ b/website/docs/controls/charts/types/barchartgroup.md @@ -0,0 +1,7 @@ +--- +title: "BarChartGroup" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/barchartrod.md b/website/docs/controls/charts/types/barchartrod.md new file mode 100644 index 0000000000..12f6ccd872 --- /dev/null +++ b/website/docs/controls/charts/types/barchartrod.md @@ -0,0 +1,7 @@ +--- +title: "BarChartRod" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/barchartrodstackitem.md b/website/docs/controls/charts/types/barchartrodstackitem.md new file mode 100644 index 0000000000..53181853c7 --- /dev/null +++ b/website/docs/controls/charts/types/barchartrodstackitem.md @@ -0,0 +1,7 @@ +--- +title: "BarChartRodStackItem" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/barchartrodtooltip.md b/website/docs/controls/charts/types/barchartrodtooltip.md new file mode 100644 index 0000000000..fff9d690c8 --- /dev/null +++ b/website/docs/controls/charts/types/barchartrodtooltip.md @@ -0,0 +1,7 @@ +--- +title: "BarChartRodTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/barcharttooltip.md b/website/docs/controls/charts/types/barcharttooltip.md new file mode 100644 index 0000000000..09cff32158 --- /dev/null +++ b/website/docs/controls/charts/types/barcharttooltip.md @@ -0,0 +1,7 @@ +--- +title: "BarChartTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/barcharttooltipdirection.md b/website/docs/controls/charts/types/barcharttooltipdirection.md new file mode 100644 index 0000000000..07bb9a17be --- /dev/null +++ b/website/docs/controls/charts/types/barcharttooltipdirection.md @@ -0,0 +1,7 @@ +--- +title: "BarChartTooltipDirection" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/candlestickchartevent.md b/website/docs/controls/charts/types/candlestickchartevent.md new file mode 100644 index 0000000000..456c5fac9e --- /dev/null +++ b/website/docs/controls/charts/types/candlestickchartevent.md @@ -0,0 +1,7 @@ +--- +title: "CandlestickChartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/candlestickchartspot.md b/website/docs/controls/charts/types/candlestickchartspot.md new file mode 100644 index 0000000000..f9f131e3c8 --- /dev/null +++ b/website/docs/controls/charts/types/candlestickchartspot.md @@ -0,0 +1,7 @@ +--- +title: "CandlestickChartSpot" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/candlestickchartspottooltip.md b/website/docs/controls/charts/types/candlestickchartspottooltip.md new file mode 100644 index 0000000000..a73393891d --- /dev/null +++ b/website/docs/controls/charts/types/candlestickchartspottooltip.md @@ -0,0 +1,7 @@ +--- +title: "CandlestickChartSpotTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/candlestickcharttooltip.md b/website/docs/controls/charts/types/candlestickcharttooltip.md new file mode 100644 index 0000000000..f1d4cbcbd7 --- /dev/null +++ b/website/docs/controls/charts/types/candlestickcharttooltip.md @@ -0,0 +1,7 @@ +--- +title: "CandlestickChartTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartaxis.md b/website/docs/controls/charts/types/chartaxis.md new file mode 100644 index 0000000000..007c6da213 --- /dev/null +++ b/website/docs/controls/charts/types/chartaxis.md @@ -0,0 +1,7 @@ +--- +title: "ChartAxis" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartaxislabel.md b/website/docs/controls/charts/types/chartaxislabel.md new file mode 100644 index 0000000000..cf3341263d --- /dev/null +++ b/website/docs/controls/charts/types/chartaxislabel.md @@ -0,0 +1,7 @@ +--- +title: "ChartAxisLabel" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartcirclepoint.md b/website/docs/controls/charts/types/chartcirclepoint.md new file mode 100644 index 0000000000..3eb0ff1ed4 --- /dev/null +++ b/website/docs/controls/charts/types/chartcirclepoint.md @@ -0,0 +1,7 @@ +--- +title: "ChartCirclePoint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartcrosspoint.md b/website/docs/controls/charts/types/chartcrosspoint.md new file mode 100644 index 0000000000..a92a3840fe --- /dev/null +++ b/website/docs/controls/charts/types/chartcrosspoint.md @@ -0,0 +1,7 @@ +--- +title: "ChartCrossPoint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartdatapointtooltip.md b/website/docs/controls/charts/types/chartdatapointtooltip.md new file mode 100644 index 0000000000..f74fabab82 --- /dev/null +++ b/website/docs/controls/charts/types/chartdatapointtooltip.md @@ -0,0 +1,7 @@ +--- +title: "ChartDataPointTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/charteventtype.md b/website/docs/controls/charts/types/charteventtype.md new file mode 100644 index 0000000000..86841f1e43 --- /dev/null +++ b/website/docs/controls/charts/types/charteventtype.md @@ -0,0 +1,7 @@ +--- +title: "ChartEventType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartgridlines.md b/website/docs/controls/charts/types/chartgridlines.md new file mode 100644 index 0000000000..b6205bf988 --- /dev/null +++ b/website/docs/controls/charts/types/chartgridlines.md @@ -0,0 +1,7 @@ +--- +title: "ChartGridLines" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartpointline.md b/website/docs/controls/charts/types/chartpointline.md new file mode 100644 index 0000000000..9f63f64d07 --- /dev/null +++ b/website/docs/controls/charts/types/chartpointline.md @@ -0,0 +1,7 @@ +--- +title: "ChartPointLine" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartpointshape.md b/website/docs/controls/charts/types/chartpointshape.md new file mode 100644 index 0000000000..00323488f6 --- /dev/null +++ b/website/docs/controls/charts/types/chartpointshape.md @@ -0,0 +1,7 @@ +--- +title: "ChartPointShape" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/chartsquarepoint.md b/website/docs/controls/charts/types/chartsquarepoint.md new file mode 100644 index 0000000000..52ae17e2c2 --- /dev/null +++ b/website/docs/controls/charts/types/chartsquarepoint.md @@ -0,0 +1,7 @@ +--- +title: "ChartSquarePoint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/horizontalalignment.md b/website/docs/controls/charts/types/horizontalalignment.md new file mode 100644 index 0000000000..86523eea81 --- /dev/null +++ b/website/docs/controls/charts/types/horizontalalignment.md @@ -0,0 +1,7 @@ +--- +title: "HorizontalAlignment" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/linechartdata.md b/website/docs/controls/charts/types/linechartdata.md new file mode 100644 index 0000000000..d8fd0d1854 --- /dev/null +++ b/website/docs/controls/charts/types/linechartdata.md @@ -0,0 +1,7 @@ +--- +title: "LineChartData" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/linechartdatapoint.md b/website/docs/controls/charts/types/linechartdatapoint.md new file mode 100644 index 0000000000..f425912a7e --- /dev/null +++ b/website/docs/controls/charts/types/linechartdatapoint.md @@ -0,0 +1,7 @@ +--- +title: "LineChartDataPoint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/linechartdatapointtooltip.md b/website/docs/controls/charts/types/linechartdatapointtooltip.md new file mode 100644 index 0000000000..3f5d556b67 --- /dev/null +++ b/website/docs/controls/charts/types/linechartdatapointtooltip.md @@ -0,0 +1,7 @@ +--- +title: "LineChartDataPointTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/linechartevent.md b/website/docs/controls/charts/types/linechartevent.md new file mode 100644 index 0000000000..74b693bee8 --- /dev/null +++ b/website/docs/controls/charts/types/linechartevent.md @@ -0,0 +1,7 @@ +--- +title: "LineChartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/linecharteventspot.md b/website/docs/controls/charts/types/linecharteventspot.md new file mode 100644 index 0000000000..20f9786fc4 --- /dev/null +++ b/website/docs/controls/charts/types/linecharteventspot.md @@ -0,0 +1,7 @@ +--- +title: "LineChartEventSpot" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/linecharttooltip.md b/website/docs/controls/charts/types/linecharttooltip.md new file mode 100644 index 0000000000..a859a7ee8c --- /dev/null +++ b/website/docs/controls/charts/types/linecharttooltip.md @@ -0,0 +1,7 @@ +--- +title: "LineChartTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/piechartevent.md b/website/docs/controls/charts/types/piechartevent.md new file mode 100644 index 0000000000..3d7d895d7e --- /dev/null +++ b/website/docs/controls/charts/types/piechartevent.md @@ -0,0 +1,7 @@ +--- +title: "PieChartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/piechartsection.md b/website/docs/controls/charts/types/piechartsection.md new file mode 100644 index 0000000000..83a03a85d8 --- /dev/null +++ b/website/docs/controls/charts/types/piechartsection.md @@ -0,0 +1,7 @@ +--- +title: "PieChartSection" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/radarchartevent.md b/website/docs/controls/charts/types/radarchartevent.md new file mode 100644 index 0000000000..c40d550c55 --- /dev/null +++ b/website/docs/controls/charts/types/radarchartevent.md @@ -0,0 +1,7 @@ +--- +title: "RadarChartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/radarcharttitle.md b/website/docs/controls/charts/types/radarcharttitle.md new file mode 100644 index 0000000000..f955057c0b --- /dev/null +++ b/website/docs/controls/charts/types/radarcharttitle.md @@ -0,0 +1,7 @@ +--- +title: "RadarChartTitle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/radardataset.md b/website/docs/controls/charts/types/radardataset.md new file mode 100644 index 0000000000..afb0be5893 --- /dev/null +++ b/website/docs/controls/charts/types/radardataset.md @@ -0,0 +1,7 @@ +--- +title: "RadarDataSet" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/radardatasetentry.md b/website/docs/controls/charts/types/radardatasetentry.md new file mode 100644 index 0000000000..83566e6924 --- /dev/null +++ b/website/docs/controls/charts/types/radardatasetentry.md @@ -0,0 +1,7 @@ +--- +title: "RadarDataSetEntry" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/radarshape.md b/website/docs/controls/charts/types/radarshape.md new file mode 100644 index 0000000000..8917aafaf0 --- /dev/null +++ b/website/docs/controls/charts/types/radarshape.md @@ -0,0 +1,7 @@ +--- +title: "RadarShape" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/scatterchartevent.md b/website/docs/controls/charts/types/scatterchartevent.md new file mode 100644 index 0000000000..3a38faa180 --- /dev/null +++ b/website/docs/controls/charts/types/scatterchartevent.md @@ -0,0 +1,7 @@ +--- +title: "ScatterChartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/scatterchartspot.md b/website/docs/controls/charts/types/scatterchartspot.md new file mode 100644 index 0000000000..11feffc436 --- /dev/null +++ b/website/docs/controls/charts/types/scatterchartspot.md @@ -0,0 +1,7 @@ +--- +title: "ScatterChartSpot" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/scatterchartspottooltip.md b/website/docs/controls/charts/types/scatterchartspottooltip.md new file mode 100644 index 0000000000..ba163004cf --- /dev/null +++ b/website/docs/controls/charts/types/scatterchartspottooltip.md @@ -0,0 +1,7 @@ +--- +title: "ScatterChartSpotTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/charts/types/scattercharttooltip.md b/website/docs/controls/charts/types/scattercharttooltip.md new file mode 100644 index 0000000000..b81a9876c3 --- /dev/null +++ b/website/docs/controls/charts/types/scattercharttooltip.md @@ -0,0 +1,7 @@ +--- +title: "ScatterChartTooltip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/checkbox.md b/website/docs/controls/checkbox.md new file mode 100644 index 0000000000..4ceb56c455 --- /dev/null +++ b/website/docs/controls/checkbox.md @@ -0,0 +1,34 @@ +--- +class_name: "flet.Checkbox" +examples: "controls/material/checkbox" +example_images: "test-images/examples/controls/material/golden/macos/checkbox" +title: "Checkbox" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/checkbox) + +### Basic Example + + + +basic + +### Handling events + + + +handling-events + +### Styled checkboxes + + + +Styled checkboxes + + diff --git a/website/docs/controls/chip.md b/website/docs/controls/chip.md new file mode 100644 index 0000000000..5bb9516d73 --- /dev/null +++ b/website/docs/controls/chip.md @@ -0,0 +1,41 @@ +--- +class_name: "flet.Chip" +examples: "controls/material/chip" +example_images: "test-images/examples/controls/material/golden/macos/chip" +example_media: "examples/controls/material/chip/media" +title: "Chip" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/chip) + +### Assist chips + +Assist chips are chips with [`leading`](chip.md#flet.Chip.leading) icon +and [`on_click`](chip.md#flet.Chip.on_click) event specified. + +They represent smart or automated actions that appear dynamically and contextually in a UI. + +An alternative to assist chips are buttons, which should appear persistently and consistently. + + + +assist-chips + +### Filter chips + +Filter chips are chips with [`on_select`](chip.md#flet.Chip.on_select) event specified. + +They use tags or descriptive words provided in the [`label`](chip.md#flet.Chip.label) to filter content. +They can be a good alternative to switches or checkboxes. + + + +filter-chips + + diff --git a/website/docs/controls/circleavatar.md b/website/docs/controls/circleavatar.md new file mode 100644 index 0000000000..6e47dbee8c --- /dev/null +++ b/website/docs/controls/circleavatar.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CircleAvatar" +examples: "controls/material/circle_avatar" +example_images: "test-images/examples/controls/material/golden/macos/circle_avatar" +example_media: "examples/controls/material/circle_avatar/media" +title: "CircleAvatar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/circleavatar) + +### User avatars + + + +user-avatars + + diff --git a/website/docs/controls/codeeditor/index.md b/website/docs/controls/codeeditor/index.md new file mode 100644 index 0000000000..db56616908 --- /dev/null +++ b/website/docs/controls/codeeditor/index.md @@ -0,0 +1,52 @@ +--- +class_name: "flet_code_editor.CodeEditor" +examples: "extensions/code_editor" +example_images: "test-images/examples/extensions/code_editor/golden/macos/code_editor" +title: "CodeEditor" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Usage + +Add `flet-code-editor` to your project dependencies: + + + +```bash +uv add flet-code-editor +``` + + + +```bash +pip install flet-code-editor # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Examples + +### Basic example + + +code-editor-example-1 + +### Selection handling + + + +code-editor-example-2 + +### Folding and initial selection + + + +code-editor-example-3 + + diff --git a/website/docs/controls/codeeditor/types/codelanguage.md b/website/docs/controls/codeeditor/types/codelanguage.md new file mode 100644 index 0000000000..35426a7ce5 --- /dev/null +++ b/website/docs/controls/codeeditor/types/codelanguage.md @@ -0,0 +1,7 @@ +--- +title: "CodeLanguage" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/codeeditor/types/codetheme.md b/website/docs/controls/codeeditor/types/codetheme.md new file mode 100644 index 0000000000..81f247a5f4 --- /dev/null +++ b/website/docs/controls/codeeditor/types/codetheme.md @@ -0,0 +1,7 @@ +--- +title: "CodeTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/codeeditor/types/customcodetheme.md b/website/docs/controls/codeeditor/types/customcodetheme.md new file mode 100644 index 0000000000..ddca0b1df5 --- /dev/null +++ b/website/docs/controls/codeeditor/types/customcodetheme.md @@ -0,0 +1,7 @@ +--- +title: "CustomCodeTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/codeeditor/types/gutterstyle.md b/website/docs/controls/codeeditor/types/gutterstyle.md new file mode 100644 index 0000000000..2dc4318c66 --- /dev/null +++ b/website/docs/controls/codeeditor/types/gutterstyle.md @@ -0,0 +1,7 @@ +--- +title: "GutterStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/colorpickers/blockpicker.md b/website/docs/controls/colorpickers/blockpicker.md new file mode 100644 index 0000000000..6ff023b604 --- /dev/null +++ b/website/docs/controls/colorpickers/blockpicker.md @@ -0,0 +1,18 @@ +--- +class_name: "flet_color_pickers.BlockPicker" +examples: "extensions/color_pickers" +example_images: "test-images/examples/extensions/color_pickers/golden/macos/color_pickers" +title: "BlockPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + +# BlockPicker + + + +## Example + + + + diff --git a/website/docs/controls/colorpickers/colorpicker.md b/website/docs/controls/colorpickers/colorpicker.md new file mode 100644 index 0000000000..d2515f389b --- /dev/null +++ b/website/docs/controls/colorpickers/colorpicker.md @@ -0,0 +1,18 @@ +--- +class_name: "flet_color_pickers.ColorPicker" +examples: "extensions/color_pickers" +example_images: "test-images/examples/extensions/color_pickers/golden/macos/color_pickers" +title: "ColorPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + +# ColorPicker + + + +## Example + + + + diff --git a/website/docs/controls/colorpickers/hueringpicker.md b/website/docs/controls/colorpickers/hueringpicker.md new file mode 100644 index 0000000000..99d671fc7c --- /dev/null +++ b/website/docs/controls/colorpickers/hueringpicker.md @@ -0,0 +1,18 @@ +--- +class_name: "flet_color_pickers.HueRingPicker" +examples: "extensions/color_pickers" +example_images: "test-images/examples/extensions/color_pickers/golden/macos/color_pickers" +title: "HueRingPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + +# HueRingPicker + + + +## Example + + + + diff --git a/website/docs/controls/colorpickers/index.md b/website/docs/controls/colorpickers/index.md new file mode 100644 index 0000000000..9ccdb98df9 --- /dev/null +++ b/website/docs/controls/colorpickers/index.md @@ -0,0 +1,40 @@ +--- +examples: "extensions/color_pickers" +title: "Color pickers" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +# Color pickers + +Multiple color picker controls built on Flutter's +[`flutter_colorpicker`](https://pub.dev/packages/flutter_colorpicker) package. + +## Usage + +Add `flet-color-pickers` to your project dependencies: + + + +```bash +uv add flet-color-pickers +``` + + + +```bash +pip install flet-color-pickers # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Available color pickers + +- [ColorPicker](colorpicker.md) +- [BlockPicker](blockpicker.md) +- [HueRingPicker](hueringpicker.md) +- [MaterialPicker](materialpicker.md) +- [MultipleChoiceBlockPicker](multiplechoiceblockpicker.md) +- [SlidePicker](slidepicker.md) diff --git a/website/docs/controls/colorpickers/materialpicker.md b/website/docs/controls/colorpickers/materialpicker.md new file mode 100644 index 0000000000..1a2ca3baaa --- /dev/null +++ b/website/docs/controls/colorpickers/materialpicker.md @@ -0,0 +1,18 @@ +--- +class_name: "flet_color_pickers.MaterialPicker" +examples: "extensions/color_pickers" +example_images: "test-images/examples/extensions/color_pickers/golden/macos/color_pickers" +title: "MaterialPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + +# MaterialPicker + + + +## Example + + + + diff --git a/website/docs/controls/colorpickers/multiplechoiceblockpicker.md b/website/docs/controls/colorpickers/multiplechoiceblockpicker.md new file mode 100644 index 0000000000..903ebfce81 --- /dev/null +++ b/website/docs/controls/colorpickers/multiplechoiceblockpicker.md @@ -0,0 +1,18 @@ +--- +class_name: "flet_color_pickers.MultipleChoiceBlockPicker" +examples: "extensions/color_pickers" +example_images: "test-images/examples/extensions/color_pickers/golden/macos/color_pickers" +title: "MultipleChoiceBlockPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + +# MultipleChoiceBlockPicker + + + +## Example + + + + diff --git a/website/docs/controls/colorpickers/slidepicker.md b/website/docs/controls/colorpickers/slidepicker.md new file mode 100644 index 0000000000..393967c3a4 --- /dev/null +++ b/website/docs/controls/colorpickers/slidepicker.md @@ -0,0 +1,18 @@ +--- +class_name: "flet_color_pickers.SlidePicker" +examples: "extensions/color_pickers" +example_images: "test-images/examples/extensions/color_pickers/golden/macos/color_pickers" +title: "SlidePicker" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + +# SlidePicker + + + +## Example + + + + diff --git a/website/docs/controls/column.md b/website/docs/controls/column.md new file mode 100644 index 0000000000..6515a79109 --- /dev/null +++ b/website/docs/controls/column.md @@ -0,0 +1,58 @@ +--- +class_name: "flet.Column" +examples: "controls/core/column" +example_images: "test-images/examples/controls/core/golden/macos/column" +example_media: "examples/controls/core/column/media" +title: "Column" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/column) + +### Column `spacing` + + + +spacing + +### Column wrapping + + + +wrap + +### Column vertical alignments + + + +alignment + +### Column horizontal alignments + + + +horizontal-alignment + +### Infinite scrolling + +This example demonstrates adding of list items on-the-fly, as user scroll to the bottom, +creating the illusion of infinite list: + + + +### Scrolling programmatically + +This example shows how to use [`scroll_to()`](column.md) to programmatically scroll a column: + + + +programmatic-scroll + +[//]: # (### Custom scrollbar) + + diff --git a/website/docs/controls/container.md b/website/docs/controls/container.md new file mode 100644 index 0000000000..f12b3ba4ba --- /dev/null +++ b/website/docs/controls/container.md @@ -0,0 +1,73 @@ +--- +class_name: "flet.Container" +examples: "controls/core/container" +example_media: "examples/controls/core/container/media" +example_images: "test-images/examples/controls/core/golden/macos/container" +title: "Container" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/container) + +### Clickable container + + + + + +### Handling clicks + + + + + +### Handling hovers + + + + + +### Animate 1 + + + + + +### Animate 2 + + + +### Animate 3 + + + +### Nested themes 1 + + + + + +### Nested themes 2 + + + + + +### Nested themes 3 + + + + + +### Size aware + + + + + + diff --git a/website/docs/controls/contextmenu.md b/website/docs/controls/contextmenu.md new file mode 100644 index 0000000000..4743331fe5 --- /dev/null +++ b/website/docs/controls/contextmenu.md @@ -0,0 +1,32 @@ +--- +class_name: "flet.ContextMenu" +examples: "controls/material/context_menu" +example_images: "test-images/examples/controls/material/golden/macos/context_menu" +title: "ContextMenu" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Triggers + + + + + +### Programmatic open + + + + + +### Programmatic open with custom trigger + + + + + + diff --git a/website/docs/controls/control.md b/website/docs/controls/control.md new file mode 100644 index 0000000000..02318e5d49 --- /dev/null +++ b/website/docs/controls/control.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.Control" +title: "Control" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/cupertinoactionsheet/index.md b/website/docs/controls/cupertinoactionsheet/index.md new file mode 100644 index 0000000000..9f9468dccc --- /dev/null +++ b/website/docs/controls/cupertinoactionsheet/index.md @@ -0,0 +1,25 @@ +--- +class_name: "flet.CupertinoActionSheet" +examples: "controls/cupertino/cupertino_action_sheet" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_action_sheet" +example_media: "examples/controls/cupertino/cupertino_action_sheet/media" +title: "CupertinoActionSheet" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# CupertinoActionSheet + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinoactionsheet) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinoactionsheetaction.md b/website/docs/controls/cupertinoactionsheetaction.md new file mode 100644 index 0000000000..9c67829197 --- /dev/null +++ b/website/docs/controls/cupertinoactionsheetaction.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.CupertinoActionSheetAction" +title: "CupertinoActionSheetAction" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/cupertinoactivityindicator.md b/website/docs/controls/cupertinoactivityindicator.md new file mode 100644 index 0000000000..56ede40e9e --- /dev/null +++ b/website/docs/controls/cupertinoactivityindicator.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoActivityIndicator" +examples: "controls/cupertino/cupertino_activity_indicator" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_activity_indicator" +example_media: "examples/controls/cupertino/cupertino_activity_indicator/media" +title: "CupertinoActivityIndicator" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/cupertinoactivityindicator) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinoalertdialog.md b/website/docs/controls/cupertinoalertdialog.md new file mode 100644 index 0000000000..5f85abc6e2 --- /dev/null +++ b/website/docs/controls/cupertinoalertdialog.md @@ -0,0 +1,26 @@ +--- +class_name: "flet.CupertinoAlertDialog" +examples: "controls/cupertino/cupertino_alert_dialog" +example_images: "examples/controls/cupertino/cupertino_alert_dialog/media" +title: "CupertinoAlertDialog" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinoalertdialog) + +### File deletion confirmation + + + +file-deletion-confirmation + +### Cupertino, material and adaptive alert dialogs + + + + diff --git a/website/docs/controls/cupertinoappbar.md b/website/docs/controls/cupertinoappbar.md new file mode 100644 index 0000000000..8a73b8f740 --- /dev/null +++ b/website/docs/controls/cupertinoappbar.md @@ -0,0 +1,26 @@ +--- +class_name: "flet.CupertinoAppBar" +examples: "controls/cupertino/cupertino_app_bar" +example_images: "examples/controls/cupertino/cupertino_app_bar/media" +title: "CupertinoAppBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/cupertinoappbar) + +### Basic Example + + + +basic + +### App bar with theme mode toggle + + + + diff --git a/website/docs/controls/cupertinobottomsheet.md b/website/docs/controls/cupertinobottomsheet.md new file mode 100644 index 0000000000..a16fe1126a --- /dev/null +++ b/website/docs/controls/cupertinobottomsheet.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.CupertinoBottomSheet" +examples: "controls/cupertino/cupertino_action_sheet" +example_images: "examples/controls/cupertino/cupertino_action_sheet/media" +title: "CupertinoBottomSheet" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinobottomsheet) + +### Displaying a `CupertinoActionSheet` + + + +cupertinoactionsheet + + diff --git a/website/docs/controls/cupertinobutton.md b/website/docs/controls/cupertinobutton.md new file mode 100644 index 0000000000..e25251f317 --- /dev/null +++ b/website/docs/controls/cupertinobutton.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoButton" +examples: "controls/cupertino/cupertino_button" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_button" +example_media: "examples/controls/cupertino/cupertino_button/media" +title: "CupertinoButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/cupertinobutton) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinocheckbox.md b/website/docs/controls/cupertinocheckbox.md new file mode 100644 index 0000000000..6042f3db78 --- /dev/null +++ b/website/docs/controls/cupertinocheckbox.md @@ -0,0 +1,27 @@ +--- +class_name: "flet.CupertinoCheckbox" +examples: "controls/cupertino/cupertino_checkbox" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_checkbox" +example_media: "examples/controls/cupertino/cupertino_checkbox/media" +title: "CupertinoCheckbox" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/cupertinocheckbox) + +### Cupertino, Material and Adaptive Checkboxes + + + +cupertino-material-and-adaptive + +### Styled checkboxes + + + + diff --git a/website/docs/controls/cupertinocontextmenu/index.md b/website/docs/controls/cupertinocontextmenu/index.md new file mode 100644 index 0000000000..6f5c1b769c --- /dev/null +++ b/website/docs/controls/cupertinocontextmenu/index.md @@ -0,0 +1,24 @@ +--- +class_name: "flet.CupertinoContextMenu" +examples: "controls/cupertino/cupertino_context_menu" +example_images: "examples/controls/cupertino/cupertino_context_menu/media" +title: "CupertinoContextMenu" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# CupertinoContextMenu + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinocontextmenu) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinocontextmenuaction.md b/website/docs/controls/cupertinocontextmenuaction.md new file mode 100644 index 0000000000..2e43e5a6b3 --- /dev/null +++ b/website/docs/controls/cupertinocontextmenuaction.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.CupertinoContextMenuAction" +title: "CupertinoContextMenuAction" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/cupertinodatepicker.md b/website/docs/controls/cupertinodatepicker.md new file mode 100644 index 0000000000..23947eed76 --- /dev/null +++ b/website/docs/controls/cupertinodatepicker.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.CupertinoDatePicker" +examples: "controls/cupertino/cupertino_date_picker" +example_images: "examples/controls/cupertino/cupertino_date_picker/media" +title: "CupertinoDatePicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinodatepicker) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinodialogaction.md b/website/docs/controls/cupertinodialogaction.md new file mode 100644 index 0000000000..c54741d7b3 --- /dev/null +++ b/website/docs/controls/cupertinodialogaction.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.CupertinoDialogAction" +title: "CupertinoDialogAction" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See [these](cupertinoalertdialog.md#examples). + + diff --git a/website/docs/controls/cupertinofilledbutton.md b/website/docs/controls/cupertinofilledbutton.md new file mode 100644 index 0000000000..afdbab6fc3 --- /dev/null +++ b/website/docs/controls/cupertinofilledbutton.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoFilledButton" +examples: "controls/cupertino/cupertino_filled_button" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_filled_button" +example_media: "examples/controls/cupertino/cupertino_filled_button/media" +title: "CupertinoFilledButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/cupertinofilledbutton) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinolisttile.md b/website/docs/controls/cupertinolisttile.md new file mode 100644 index 0000000000..fab8ceea95 --- /dev/null +++ b/website/docs/controls/cupertinolisttile.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoListTile" +examples: "controls/cupertino/cupertino_list_tile" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_list_tile" +example_media: "examples/controls/cupertino/cupertino_list_tile/media" +title: "CupertinoListTile" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/cupertinolisttile) + +### Notched and non-notched list tiles + + + +notched + + diff --git a/website/docs/controls/cupertinonavigationbar.md b/website/docs/controls/cupertinonavigationbar.md new file mode 100644 index 0000000000..fbdff805aa --- /dev/null +++ b/website/docs/controls/cupertinonavigationbar.md @@ -0,0 +1,26 @@ +--- +class_name: "flet.CupertinoNavigationBar" +examples: "controls/cupertino/cupertino_navigation_bar" +example_images: "examples/controls/cupertino/cupertino_navigation_bar/media" +title: "CupertinoNavigationBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/cupertinonavigationbar) + +### Basic Example + + + +basic + +### Wired navigation bar + + + + diff --git a/website/docs/controls/cupertinopicker.md b/website/docs/controls/cupertinopicker.md new file mode 100644 index 0000000000..51a28335e7 --- /dev/null +++ b/website/docs/controls/cupertinopicker.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.CupertinoPicker" +examples: "controls/cupertino/cupertino_picker" +example_images: "examples/controls/cupertino/cupertino_picker/media" +title: "CupertinoPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinotimerpicker) + +### Fruit selection + + + +fruit-selection + + diff --git a/website/docs/controls/cupertinoradio.md b/website/docs/controls/cupertinoradio.md new file mode 100644 index 0000000000..76af4198f1 --- /dev/null +++ b/website/docs/controls/cupertinoradio.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoRadio" +examples: "controls/cupertino/cupertino_radio" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_radio" +example_media: "examples/controls/cupertino/cupertino_radio/media" +title: "CupertinoRadio" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/cupertinoradio) + +### Cupertino, Material and Adaptive Radios + + + +cupertino-material-and-adaptive + + diff --git a/website/docs/controls/cupertinosegmentedbutton.md b/website/docs/controls/cupertinosegmentedbutton.md new file mode 100644 index 0000000000..1ab0e1b70a --- /dev/null +++ b/website/docs/controls/cupertinosegmentedbutton.md @@ -0,0 +1,27 @@ +--- +class_name: "flet.CupertinoSegmentedButton" +examples: "controls/cupertino/cupertino_segmented_button" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_segmented_button" +example_media: "examples/controls/cupertino/cupertino_segmented_button/media" +title: "CupertinoSegmentedButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/cupertinosegmentedbutton) + +### Basic Example + + + +basic + +### Adjusting segments padding + + + + diff --git a/website/docs/controls/cupertinoslider.md b/website/docs/controls/cupertinoslider.md new file mode 100644 index 0000000000..8345600c18 --- /dev/null +++ b/website/docs/controls/cupertinoslider.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoSlider" +examples: "controls/cupertino/cupertino_slider" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_slider" +example_media: "examples/controls/cupertino/cupertino_slider/media" +title: "CupertinoSlider" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/cupertinoslider) + +### Handling events + + + +handling-events + + diff --git a/website/docs/controls/cupertinoslidingsegmentedbutton.md b/website/docs/controls/cupertinoslidingsegmentedbutton.md new file mode 100644 index 0000000000..ae0f02c6e2 --- /dev/null +++ b/website/docs/controls/cupertinoslidingsegmentedbutton.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoSlidingSegmentedButton" +examples: "controls/cupertino/cupertino_sliding_segmented_button" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_sliding_segmented_button" +example_media: "examples/controls/cupertino/cupertino_sliding_segmented_button/media" +title: "CupertinoSlidingSegmentedButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/cupertinoslidingsegmentedbutton) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinoswitch.md b/website/docs/controls/cupertinoswitch.md new file mode 100644 index 0000000000..c36f846d25 --- /dev/null +++ b/website/docs/controls/cupertinoswitch.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoSwitch" +examples: "controls/cupertino/cupertino_switch" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_switch" +example_media: "examples/controls/cupertino/cupertino_switch/media" +title: "CupertinoSwitch" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/cupertinoswitch) + +### Cupertino, Material and Adaptive Switches + + + +cupertino-material-and-adaptive + + diff --git a/website/docs/controls/cupertinotextfield.md b/website/docs/controls/cupertinotextfield.md new file mode 100644 index 0000000000..84b2e0cbde --- /dev/null +++ b/website/docs/controls/cupertinotextfield.md @@ -0,0 +1,31 @@ +--- +class_name: "flet.CupertinoTextField" +examples: "controls/cupertino/cupertino_text_field" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_textfield" +example_media: "examples/controls/cupertino/cupertino_text_field/media" +title: "CupertinoTextField" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/cupertinotextfield) + +### Basic Example + + + +cupertino-material-and-adaptive + +### Handling selection changes + + + +### Background image + + + + diff --git a/website/docs/controls/cupertinotimerpicker.md b/website/docs/controls/cupertinotimerpicker.md new file mode 100644 index 0000000000..3b59023602 --- /dev/null +++ b/website/docs/controls/cupertinotimerpicker.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.CupertinoTimerPicker" +examples: "controls/cupertino/cupertino_timer_picker" +example_media: "examples/controls/cupertino/cupertino_timer_picker/media" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_timer_picker" +title: "CupertinoTimerPicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/cupertinotimerpicker) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/cupertinotintedbutton.md b/website/docs/controls/cupertinotintedbutton.md new file mode 100644 index 0000000000..507766d556 --- /dev/null +++ b/website/docs/controls/cupertinotintedbutton.md @@ -0,0 +1,11 @@ +--- +class_name: "flet.CupertinoTintedButton" +example_images: "test-images/examples/controls/cupertino/golden/macos/cupertino_tinted_button" +title: "CupertinoTintedButton" +--- + +import {ClassMembers, ClassSummary} from '@site/src/components/crocodocs'; + + + + diff --git a/website/docs/controls/datacell.md b/website/docs/controls/datacell.md new file mode 100644 index 0000000000..e6151ca818 --- /dev/null +++ b/website/docs/controls/datacell.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.DataCell" +title: "DataCell" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See [these](datatable/index.md#examples). + + diff --git a/website/docs/controls/datacolumn.md b/website/docs/controls/datacolumn.md new file mode 100644 index 0000000000..5a048ba64a --- /dev/null +++ b/website/docs/controls/datacolumn.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.DataColumn" +title: "DataColumn" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See [these](datatable/index.md#examples). + + diff --git a/website/docs/controls/datarow.md b/website/docs/controls/datarow.md new file mode 100644 index 0000000000..a88bc1b8f4 --- /dev/null +++ b/website/docs/controls/datarow.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.DataRow" +title: "DataRow" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See [these](datatable/index.md#examples). + + diff --git a/website/docs/controls/datatable/index.md b/website/docs/controls/datatable/index.md new file mode 100644 index 0000000000..b88227eb42 --- /dev/null +++ b/website/docs/controls/datatable/index.md @@ -0,0 +1,59 @@ +--- +class_name: "flet.DataTable" +examples: "controls/material/data_table" +example_images: "test-images/examples/controls/material/golden/macos/datatable" +title: "DataTable" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# DataTable + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/datatable) + +### Basic Example + + + + + +### Horizontal margin and column spacing + +Use [`horizontal_margin`](index.md#flet.DataTable.horizontal_margin) to control the left and right +edge spacing of the first and last columns. +Use [`column_spacing`](index.md#flet.DataTable.column_spacing) to control spacing between columns. + + + + + +### Adaptive row heights + +Setting [`data_row_max_height`](index.md#flet.DataTable.data_row_max_height) to `float('inf')` +(infinity) will cause the `DataTable` to let each individual row adapt its height to its +respective content, instead of all rows having the same height. + + + + + +### Sortable columns and selectable rows + +This example demonstrates row selection (including select-all), +sortable string and numeric columns, and stable selection across sorts and refreshes. + + + + + +### Handling events + + + + + + diff --git a/website/docs/controls/datatable2/datacolumn2.md b/website/docs/controls/datatable2/datacolumn2.md new file mode 100644 index 0000000000..d117f69055 --- /dev/null +++ b/website/docs/controls/datatable2/datacolumn2.md @@ -0,0 +1,7 @@ +--- +title: "DataColumn2" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/datatable2/datarow2.md b/website/docs/controls/datatable2/datarow2.md new file mode 100644 index 0000000000..2b720e2d95 --- /dev/null +++ b/website/docs/controls/datatable2/datarow2.md @@ -0,0 +1,7 @@ +--- +title: "DataRow2" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/datatable2/index.md b/website/docs/controls/datatable2/index.md new file mode 100644 index 0000000000..01f777461e --- /dev/null +++ b/website/docs/controls/datatable2/index.md @@ -0,0 +1,66 @@ +--- +examples: "extensions/datatable2" +example_media: "examples/extensions/datatable2/media" +example_images: "test-images/examples/extensions/datatable2/golden/macos/datatable2" +title: "Overview" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + +# DataTable2 + +Enhanced data table for [Flet](https://flet.dev) that adds sticky headers, fixed rows/columns, and other UX improvements via the `flet-datatable2` extension. + +It wraps the Flutter [`data_table_2`](https://pub.dev/packages/data_table_2) package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-datatable2` to your project dependencies: + + + +```bash +uv add flet-datatable2 +``` + + + +```bash +pip install flet-datatable2 # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + + +## Examples + +### Empty state + + + + + +### Sortable and selectable + + + + + +### Column widths + + + + + +## Description + + diff --git a/website/docs/controls/datatable2/types/datacolumnsize.md b/website/docs/controls/datatable2/types/datacolumnsize.md new file mode 100644 index 0000000000..e36c4ff3b0 --- /dev/null +++ b/website/docs/controls/datatable2/types/datacolumnsize.md @@ -0,0 +1,7 @@ +--- +title: "DataColumnSize" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/datepicker.md b/website/docs/controls/datepicker.md new file mode 100644 index 0000000000..ec67110d10 --- /dev/null +++ b/website/docs/controls/datepicker.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.DatePicker" +examples: "controls/material/date_picker" +example_images: "test-images/examples/controls/material/golden/macos/date_picker" +title: "DatePicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/datepicker) + +### Basic Example + + + +basic + +### Custom locale + + + +custom-locale + + diff --git a/website/docs/controls/daterangepicker.md b/website/docs/controls/daterangepicker.md new file mode 100644 index 0000000000..7d83190ddf --- /dev/null +++ b/website/docs/controls/daterangepicker.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.DateRangePicker" +examples: "controls/material/date_range_picker" +example_images: "test-images/examples/controls/material/golden/macos/date_range_picker" +title: "DateRangePicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/daterangepicker) + +### Basic Example + + + +basic + +### Custom locale + + + +custom-locale + + diff --git a/website/docs/controls/dialogcontrol.md b/website/docs/controls/dialogcontrol.md new file mode 100644 index 0000000000..f0d3431019 --- /dev/null +++ b/website/docs/controls/dialogcontrol.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.DialogControl" +title: "DialogControl" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/dismissible.md b/website/docs/controls/dismissible.md new file mode 100644 index 0000000000..a97c2644ce --- /dev/null +++ b/website/docs/controls/dismissible.md @@ -0,0 +1,46 @@ +--- +class_name: "flet.Dismissible" +examples: "controls/core/dismissible" +example_images: "examples/controls/core/dismissible/media" +title: "Dismissible" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/dismissible) + +### Dismissible `ListTile`s + + + +dismissible-list-tiles + +### Remove Dismissible `on_dismiss` inside component + +:::warning[Important] +Always specify a key for `Dismissible` when using inside Flet component. +::: + +The issue you may encounter here is specific to the `Dismissible` control used inside Flet component (declarative UI). + +When a user swipes (dismisses) an item, that widget is marked as “dismissed” on the Flutter side and effectively removed from the UI. +However, when Flet recalculates the UI diff on the Python side, it may attempt to reuse widgets in the list based on their order rather than their identity. + +If no key is provided, Flet’s diffing algorithm can’t tell that a particular `Dismissible` corresponds to a specific item — so it assumes the items have merely shifted. +That leads to update commands like: + +> “Update text in items 0…N-1, then delete the last item (N).” + +On Flutter’s side, though, the already-dismissed `Dismissible` widget in the middle of the list can’t be updated — it’s gone — causing runtime errors. + +**Always assign a stable, unique key to each `Dismissible`, typically based on the item’s identifier or index.** + +Example: + + + + diff --git a/website/docs/controls/divider.md b/website/docs/controls/divider.md new file mode 100644 index 0000000000..bff91f27dd --- /dev/null +++ b/website/docs/controls/divider.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.Divider" +examples: "controls/material/divider" +example_images: "test-images/examples/controls/material/golden/macos/divider" +example_media: "examples/controls/material/divider/media" +title: "Divider" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/divider) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/draggable.md b/website/docs/controls/draggable.md new file mode 100644 index 0000000000..67778aa479 --- /dev/null +++ b/website/docs/controls/draggable.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.Draggable" +examples: "controls/core/drag_target_and_draggable" +example_images: "examples/controls/core/drag_target_and_draggable/media" +title: "Draggable" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/utility/draggable) + +### Drag and drop Containers + +#### Imperative + + + +#### Declarative + + + +drag-and-drop-containers + + diff --git a/website/docs/controls/dragtarget.md b/website/docs/controls/dragtarget.md new file mode 100644 index 0000000000..c19cd87e5d --- /dev/null +++ b/website/docs/controls/dragtarget.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.DragTarget" +title: "DragTarget" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See [these](draggable.md#examples). + + diff --git a/website/docs/controls/dropdown/index.md b/website/docs/controls/dropdown/index.md new file mode 100644 index 0000000000..6226e7f360 --- /dev/null +++ b/website/docs/controls/dropdown/index.md @@ -0,0 +1,48 @@ +--- +class_name: "flet.Dropdown" +examples: "controls/material/dropdown" +example_images: "test-images/examples/controls/material/golden/macos/dropdown" +title: "Dropdown" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# Dropdown + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/dropdown) + +### Color selection with filtering + + + +color-selection-with-filtering + +### Icon selection + + + +icon-selection + +### Declarative dropdown + + + +declarative-dropdown + +### Select and change events + + + +select-and-change-events + +### Styled dropdowns + + + +styled-dropdowns + + diff --git a/website/docs/controls/dropdownm2.md b/website/docs/controls/dropdownm2.md new file mode 100644 index 0000000000..0574737690 --- /dev/null +++ b/website/docs/controls/dropdownm2.md @@ -0,0 +1,41 @@ +--- +class_name: "flet.DropdownM2" +examples: "controls/material/dropdown_m2" +example_images: "test-images/examples/controls/material/golden/macos/dropdown_m2" +example_media: "examples/controls/material/dropdown_m2/media" +title: "DropdownM2" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/dropdown) + +### Basic Example + + + +basic + +### Dropdown with label and hint + + + +label-and-hint + +### Handling events + + + +handling-events + +### Add and delete options + + + +add-and-delete-options + + diff --git a/website/docs/controls/dropdownoption.md b/website/docs/controls/dropdownoption.md new file mode 100644 index 0000000000..0aed26e59c --- /dev/null +++ b/website/docs/controls/dropdownoption.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.DropdownOption" +title: "DropdownOption" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/expansionpanel.md b/website/docs/controls/expansionpanel.md new file mode 100644 index 0000000000..1067a751de --- /dev/null +++ b/website/docs/controls/expansionpanel.md @@ -0,0 +1,11 @@ +--- +class_name: "flet.ExpansionPanel" +example_images: "test-images/examples/controls/material/golden/macos/expansion_panel" +title: "ExpansionPanel" +--- + +import {ClassMembers, ClassSummary} from '@site/src/components/crocodocs'; + + + + diff --git a/website/docs/controls/expansionpanellist.md b/website/docs/controls/expansionpanellist.md new file mode 100644 index 0000000000..a0467d35dc --- /dev/null +++ b/website/docs/controls/expansionpanellist.md @@ -0,0 +1,31 @@ +--- +class_name: "flet.ExpansionPanelList" +examples: "controls/material/expansion_panel_list" +example_images: "test-images/examples/controls/material/golden/macos/expansion_panel_list" +example_media: "examples/controls/material/expansion_panel_list/media" +title: "ExpansionPanelList" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/expansionpanellist) + +### Basic Example + + + + + +### Scrolling + +`ExpansionPanelList` supports scrolling through its [`scroll`](expansionpanellist.md) property. + + + + + + diff --git a/website/docs/controls/expansiontile.md b/website/docs/controls/expansiontile.md new file mode 100644 index 0000000000..822a99e448 --- /dev/null +++ b/website/docs/controls/expansiontile.md @@ -0,0 +1,44 @@ +--- +class_name: "flet.ExpansionTile" +examples: "controls/material/expansion_tile" +example_images: "test-images/examples/controls/material/golden/macos/expansion_tile" +title: "ExpansionTile" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/expansiontile) + +### Basic Example + + + + + +### Programmatic expansion/collapse + + + + + +### Custom animations + + + + + +### Theme mode toggle + + + +### Borders + + + + + + diff --git a/website/docs/controls/filledbutton.md b/website/docs/controls/filledbutton.md new file mode 100644 index 0000000000..33c8ecdaf1 --- /dev/null +++ b/website/docs/controls/filledbutton.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.FilledButton" +examples: "controls/material/filled_button" +example_images: "test-images/examples/controls/material/golden/macos/filled_button" +example_media: "examples/controls/material/filled_button/media" +title: "FilledButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/filledbutton) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/fillediconbutton.md b/website/docs/controls/fillediconbutton.md new file mode 100644 index 0000000000..b9194aeb60 --- /dev/null +++ b/website/docs/controls/fillediconbutton.md @@ -0,0 +1,11 @@ +--- +class_name: "flet.FilledIconButton" +example_images: "test-images/examples/controls/material/golden/macos/filled_icon_button" +title: "FilledIconButton" +--- + +import {ClassMembers, ClassSummary} from '@site/src/components/crocodocs'; + + + + diff --git a/website/docs/controls/filledtonalbutton.md b/website/docs/controls/filledtonalbutton.md new file mode 100644 index 0000000000..f6d62d33f0 --- /dev/null +++ b/website/docs/controls/filledtonalbutton.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.FilledTonalButton" +examples: "controls/material/filled_tonal_button" +example_images: "test-images/examples/controls/material/golden/macos/filled_tonal_button" +example_media: "examples/controls/material/filled_tonal_button/media" +title: "FilledTonalButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/filledtonalbutton) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/filledtonaliconbutton.md b/website/docs/controls/filledtonaliconbutton.md new file mode 100644 index 0000000000..80d3478bdb --- /dev/null +++ b/website/docs/controls/filledtonaliconbutton.md @@ -0,0 +1,11 @@ +--- +class_name: "flet.FilledTonalIconButton" +example_images: "test-images/examples/controls/material/golden/macos/filled_tonal_icon_button" +title: "FilledTonalIconButton" +--- + +import {ClassMembers, ClassSummary} from '@site/src/components/crocodocs'; + + + + diff --git a/website/docs/controls/fletapp.md b/website/docs/controls/fletapp.md new file mode 100644 index 0000000000..664da209e6 --- /dev/null +++ b/website/docs/controls/fletapp.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.FletApp" +title: "FletApp" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/floatingactionbutton.md b/website/docs/controls/floatingactionbutton.md new file mode 100644 index 0000000000..85fe6fb02a --- /dev/null +++ b/website/docs/controls/floatingactionbutton.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.FloatingActionButton" +examples: "controls/material/floating_action_button" +example_images: "test-images/examples/controls/material/golden/macos/floating_action_button" +example_media: "examples/controls/material/floating_action_button/media" +title: "FloatingActionButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/floatingactionbutton) + +### Handling clicks + + + +handling-clicks + + diff --git a/website/docs/controls/formfieldcontrol.md b/website/docs/controls/formfieldcontrol.md new file mode 100644 index 0000000000..0ccf62eded --- /dev/null +++ b/website/docs/controls/formfieldcontrol.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.FormFieldControl" +title: "FormFieldControl" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/gesturedetector.md b/website/docs/controls/gesturedetector.md new file mode 100644 index 0000000000..aadcfef5a8 --- /dev/null +++ b/website/docs/controls/gesturedetector.md @@ -0,0 +1,41 @@ +--- +class_name: "flet.GestureDetector" +examples: "controls/core/gesture_detector" +example_images: "examples/controls/core/gesture_detector/media" +title: "GestureDetector" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/utility/gesturedetector) + +[Solitaire game tutorial](https://flet.dev/docs/tutorials/python-solitaire) + +### Handling events + + + +### Draggable containers + +The following example demonstrates how a control can be freely dragged inside a Stack. + +The sample also shows that GestureDetector can have a child control (blue container) as well as be nested +inside another control (yellow container) giving the same results. + + + +draggable-containers + +### Window drag area + + + +### Mouse Cursors + + + + diff --git a/website/docs/controls/gridview.md b/website/docs/controls/gridview.md new file mode 100644 index 0000000000..89dbda99bc --- /dev/null +++ b/website/docs/controls/gridview.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.GridView" +examples: "controls/core/grid_view" +example_images: "test-images/examples/controls/core/golden/macos/grid_view" +example_media: "examples/controls/core/grid_view/media" +title: "GridView" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/gridview) + +### Photo gallery + + + +photo-gallery + + diff --git a/website/docs/controls/hero.md b/website/docs/controls/hero.md new file mode 100644 index 0000000000..511bc5ef4a --- /dev/null +++ b/website/docs/controls/hero.md @@ -0,0 +1,24 @@ +--- +class_name: "flet.Hero" +examples: "controls/core/hero" +example_images: "test-images/examples/controls/core/golden/macos/hero" +title: "Hero" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + + +### Gallery + + + + diff --git a/website/docs/controls/icon.md b/website/docs/controls/icon.md new file mode 100644 index 0000000000..62b53aa4f3 --- /dev/null +++ b/website/docs/controls/icon.md @@ -0,0 +1,26 @@ +--- +class_name: "flet.Icon" +examples: "controls/core/icon" +example_images: "test-images/examples/controls/core/golden/macos/icon" +example_media: "examples/controls/core/icon/media" +title: "Icon" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +To browse and visualize all available icons, +visit our [icons browser](https://examples.flet.dev/icons_browser/) + +[Live example](https://flet-controls-gallery.fly.dev/displays/icon) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/iconbutton.md b/website/docs/controls/iconbutton.md new file mode 100644 index 0000000000..cd9d7145f6 --- /dev/null +++ b/website/docs/controls/iconbutton.md @@ -0,0 +1,35 @@ +--- +class_name: "flet.IconButton" +examples: "controls/material/icon_button" +example_images: "test-images/examples/controls/material/golden/macos/icon_button" +example_media: "examples/controls/material/icon_button/media" +title: "IconButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/iconbutton) + +### Handling clicks + + + +handling-clicks + +### Selected icon + + + +selected-icon + +### Variants + + + +variants + + diff --git a/website/docs/controls/image.md b/website/docs/controls/image.md new file mode 100644 index 0000000000..a89c94bfb6 --- /dev/null +++ b/website/docs/controls/image.md @@ -0,0 +1,52 @@ +--- +class_name: "flet.Image" +examples: "controls/core/image" +example_images: "test-images/examples/controls/core/golden/macos/image" +example_media: "examples/controls/core/image/media" +title: "Image" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/image) + +### Image gallery + + + + + +### Fade-in images with a placeholder + + + +### Displaying images from base64 strings and byte data + + + +### Displaying a static SVG image + + + +### Displaying a dynamic SVG image + + + +### Displaying a Lucide icon + + + +### Gapless playback when changing image sources + +This example updates both images to a new network URL on each click. With +[`gapless_playback`](image.md#flet.Image.gapless_playback) set to `True`, the previous frame remains visible while the next +image loads. With [`gapless_playback`](image.md#flet.Image.gapless_playback) set to `False`, the image area can +briefly be empty, causing a flicker/blink effect. + + + + diff --git a/website/docs/controls/interactiveviewer.md b/website/docs/controls/interactiveviewer.md new file mode 100644 index 0000000000..8cb56a20d4 --- /dev/null +++ b/website/docs/controls/interactiveviewer.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.InteractiveViewer" +examples: "controls/core/interactive_viewer" +title: "InteractiveViewer" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/utility/interactiveviewer) + +### Handling events + + + +### Programmatic transformations + + + + diff --git a/website/docs/controls/keyboardlistener.md b/website/docs/controls/keyboardlistener.md new file mode 100644 index 0000000000..c730a871b9 --- /dev/null +++ b/website/docs/controls/keyboardlistener.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.KeyboardListener" +examples: "controls/core/keyboard_listener" +title: "KeyboardListener" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Press any keys + + + + diff --git a/website/docs/controls/layoutcontrol.md b/website/docs/controls/layoutcontrol.md new file mode 100644 index 0000000000..cbbaef7a97 --- /dev/null +++ b/website/docs/controls/layoutcontrol.md @@ -0,0 +1,51 @@ +--- +class_name: "flet.LayoutControl" +examples: "controls/core/layout_control" +example_images: "test-images/controls/core/golden/macos/layout_control" +example_images_examples: "../test-images/examples/controls/core/golden/macos/layout_control" +title: "LayoutControl" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Flip + + + + + +### Rotate + + + + + +### RotatedBox + + + + + +### Scale + + + + + +### Offset + + + + + +### Matrix4 Transform + + + + + + diff --git a/website/docs/controls/listtile.md b/website/docs/controls/listtile.md new file mode 100644 index 0000000000..6325116ea7 --- /dev/null +++ b/website/docs/controls/listtile.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.ListTile" +examples: "controls/material/list_tile" +example_images: "test-images/examples/controls/material/golden/macos/list_tile" +example_media: "examples/controls/material/list_tile/media" +title: "ListTile" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/listtile) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/listview.md b/website/docs/controls/listview.md new file mode 100644 index 0000000000..94f2b48587 --- /dev/null +++ b/website/docs/controls/listview.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.ListView" +examples: "controls/core/list_view" +example_media: "examples/controls/core/list_view/media" +example_images: "test-images/examples/controls/core/golden/macos/list_view" +title: "ListView" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/listview) + +### Auto-scrolling and dynamical items addition + + + +autoscroll-and-dynamic-items + + diff --git a/website/docs/controls/lottie/index.md b/website/docs/controls/lottie/index.md new file mode 100644 index 0000000000..600fc98b2a --- /dev/null +++ b/website/docs/controls/lottie/index.md @@ -0,0 +1,48 @@ +--- +class_name: "flet_lottie.Lottie" +examples: "extensions/lottie" +title: "Lottie" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Lottie + +Render rich [Lottie](https://airbnb.design/lottie/) animations inside your [Flet](https://flet.dev) apps with a simple control. + +It is backed by the [lottie](https://pub.dev/packages/lottie) Flutter package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add the `flet-lottie` package to your project dependencies: + + + +```bash +uv add flet-lottie +``` + + + +```bash +pip install flet-lottie # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Example + + + +## Description + + diff --git a/website/docs/controls/map/baseoverlayimage.md b/website/docs/controls/map/baseoverlayimage.md new file mode 100644 index 0000000000..59c11bf3ad --- /dev/null +++ b/website/docs/controls/map/baseoverlayimage.md @@ -0,0 +1,7 @@ +--- +title: "BaseOverlayImage" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/circlelayer.md b/website/docs/controls/map/circlelayer.md new file mode 100644 index 0000000000..a862a069a9 --- /dev/null +++ b/website/docs/controls/map/circlelayer.md @@ -0,0 +1,7 @@ +--- +title: "CircleLayer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/circlemarker.md b/website/docs/controls/map/circlemarker.md new file mode 100644 index 0000000000..41f45f8812 --- /dev/null +++ b/website/docs/controls/map/circlemarker.md @@ -0,0 +1,7 @@ +--- +title: "CircleMarker" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/imagesourceattribution.md b/website/docs/controls/map/imagesourceattribution.md new file mode 100644 index 0000000000..a9c5fbed89 --- /dev/null +++ b/website/docs/controls/map/imagesourceattribution.md @@ -0,0 +1,7 @@ +--- +title: "ImageSourceAttribution" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/index.md b/website/docs/controls/map/index.md new file mode 100644 index 0000000000..30440ae55e --- /dev/null +++ b/website/docs/controls/map/index.md @@ -0,0 +1,83 @@ +--- +examples: "extensions/map" +title: "Overview" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {CodeExample} from '@site/src/components/crocodocs'; + +# Map + +Display interactive maps in your [Flet](https://flet.dev) apps with markers, overlays, and rich attributions provided by the `flet-map` extension. The control is built on top of [`flutter_map`](https://pub.dev/packages/flutter_map) and supports multiple tile providers and layers. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add the `flet-map` package to your project dependencies: + + + +```bash +uv add flet-map +``` + + + +```bash +pip install flet-map # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +:::danger[Important] +Different tile providers have their own usage policies. +Make sure you fully comply with their requirements (ex: attribution, rate limits) +when using them in your app, to avoid being blocked or facing legal issues. +More details [here](tilelayer.md). +::: + +## Examples + +### Basic + + + +### Attributions + + + +### Camera Controls + + + +### Idle Camera + + + +### Interaction Flags + + + +### Multiple Layers + + + +### Overlay Images + + + +## Reference + +- [`Map`](mapcontrol.md) + - Layers: [`TileLayer`](tilelayer.md), [`MarkerLayer`](markerlayer.md), [`OverlayImageLayer`](overlayimagelayer.md), [`CircleLayer`](circlelayer.md), [`PolygonLayer`](polygonlayer.md), [`PolylineLayer`](polylinelayer.md) + - Markers and overlays: [`Marker`](marker.md), [`CircleMarker`](circlemarker.md), [`PolygonMarker`](polygonmarker.md), [`PolylineMarker`](polylinemarker.md), [`OverlayImage`](overlayimage.md), [`RotatedOverlayImage`](rotatedoverlayimage.md) + - Attributions: [`SimpleAttribution`](simpleattribution.md), [`RichAttribution`](richattribution.md), [`SourceAttribution`](sourceattribution.md) + +See the [types](types/attributionalignment.md) section for additional configuration helpers. diff --git a/website/docs/controls/map/mapcontrol.md b/website/docs/controls/map/mapcontrol.md new file mode 100644 index 0000000000..c71c8f1227 --- /dev/null +++ b/website/docs/controls/map/mapcontrol.md @@ -0,0 +1,7 @@ +--- +title: "Map" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/maplayer.md b/website/docs/controls/map/maplayer.md new file mode 100644 index 0000000000..5a44647e73 --- /dev/null +++ b/website/docs/controls/map/maplayer.md @@ -0,0 +1,7 @@ +--- +title: "MapLayer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/marker.md b/website/docs/controls/map/marker.md new file mode 100644 index 0000000000..370ead2fbb --- /dev/null +++ b/website/docs/controls/map/marker.md @@ -0,0 +1,7 @@ +--- +title: "Marker" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/markerlayer.md b/website/docs/controls/map/markerlayer.md new file mode 100644 index 0000000000..1522b940fb --- /dev/null +++ b/website/docs/controls/map/markerlayer.md @@ -0,0 +1,7 @@ +--- +title: "MarkerLayer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/overlayimage.md b/website/docs/controls/map/overlayimage.md new file mode 100644 index 0000000000..1efaee20c3 --- /dev/null +++ b/website/docs/controls/map/overlayimage.md @@ -0,0 +1,14 @@ +--- +examples: "extensions/map" +title: "OverlayImage" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic example + + diff --git a/website/docs/controls/map/overlayimagelayer.md b/website/docs/controls/map/overlayimagelayer.md new file mode 100644 index 0000000000..a78993eb87 --- /dev/null +++ b/website/docs/controls/map/overlayimagelayer.md @@ -0,0 +1,14 @@ +--- +examples: "extensions/map" +title: "OverlayImageLayer" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic example + + diff --git a/website/docs/controls/map/polygonlayer.md b/website/docs/controls/map/polygonlayer.md new file mode 100644 index 0000000000..5ac4e2619c --- /dev/null +++ b/website/docs/controls/map/polygonlayer.md @@ -0,0 +1,7 @@ +--- +title: "PolygonLayer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/polygonmarker.md b/website/docs/controls/map/polygonmarker.md new file mode 100644 index 0000000000..6fbd525f1e --- /dev/null +++ b/website/docs/controls/map/polygonmarker.md @@ -0,0 +1,7 @@ +--- +title: "PolygonMarker" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/polylinelayer.md b/website/docs/controls/map/polylinelayer.md new file mode 100644 index 0000000000..c4d00a6d9d --- /dev/null +++ b/website/docs/controls/map/polylinelayer.md @@ -0,0 +1,7 @@ +--- +title: "PolylineLayer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/polylinemarker.md b/website/docs/controls/map/polylinemarker.md new file mode 100644 index 0000000000..1f3a2cdee0 --- /dev/null +++ b/website/docs/controls/map/polylinemarker.md @@ -0,0 +1,7 @@ +--- +title: "PolylineMarker" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/richattribution.md b/website/docs/controls/map/richattribution.md new file mode 100644 index 0000000000..a1f54b6d4d --- /dev/null +++ b/website/docs/controls/map/richattribution.md @@ -0,0 +1,7 @@ +--- +title: "RichAttribution" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/rotatedoverlayimage.md b/website/docs/controls/map/rotatedoverlayimage.md new file mode 100644 index 0000000000..6027173d1e --- /dev/null +++ b/website/docs/controls/map/rotatedoverlayimage.md @@ -0,0 +1,14 @@ +--- +examples: "extensions/map" +title: "RotatedOverlayImage" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic example + + diff --git a/website/docs/controls/map/simpleattribution.md b/website/docs/controls/map/simpleattribution.md new file mode 100644 index 0000000000..429ac78dd8 --- /dev/null +++ b/website/docs/controls/map/simpleattribution.md @@ -0,0 +1,7 @@ +--- +title: "SimpleAttribution" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/sourceattribution.md b/website/docs/controls/map/sourceattribution.md new file mode 100644 index 0000000000..870c50e7b8 --- /dev/null +++ b/website/docs/controls/map/sourceattribution.md @@ -0,0 +1,7 @@ +--- +title: "SourceAttribution" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/textsourceattribution.md b/website/docs/controls/map/textsourceattribution.md new file mode 100644 index 0000000000..321efc1b69 --- /dev/null +++ b/website/docs/controls/map/textsourceattribution.md @@ -0,0 +1,7 @@ +--- +title: "TextSourceAttribution" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/tilelayer.md b/website/docs/controls/map/tilelayer.md new file mode 100644 index 0000000000..39a3083743 --- /dev/null +++ b/website/docs/controls/map/tilelayer.md @@ -0,0 +1,7 @@ +--- +title: "TileLayer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/attributionalignment.md b/website/docs/controls/map/types/attributionalignment.md new file mode 100644 index 0000000000..aec21b2041 --- /dev/null +++ b/website/docs/controls/map/types/attributionalignment.md @@ -0,0 +1,7 @@ +--- +title: "AttributionAlignment" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/camera.md b/website/docs/controls/map/types/camera.md new file mode 100644 index 0000000000..a3f2e3b303 --- /dev/null +++ b/website/docs/controls/map/types/camera.md @@ -0,0 +1,7 @@ +--- +title: "Camera" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/camerafit.md b/website/docs/controls/map/types/camerafit.md new file mode 100644 index 0000000000..fe7defbd18 --- /dev/null +++ b/website/docs/controls/map/types/camerafit.md @@ -0,0 +1,7 @@ +--- +title: "CameraFit" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/cursorkeyboardrotationconfiguration.md b/website/docs/controls/map/types/cursorkeyboardrotationconfiguration.md new file mode 100644 index 0000000000..3b806d9760 --- /dev/null +++ b/website/docs/controls/map/types/cursorkeyboardrotationconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "CursorKeyboardRotationConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/cursorrotationbehaviour.md b/website/docs/controls/map/types/cursorrotationbehaviour.md new file mode 100644 index 0000000000..020cc899c3 --- /dev/null +++ b/website/docs/controls/map/types/cursorrotationbehaviour.md @@ -0,0 +1,7 @@ +--- +title: "CursorRotationBehaviour" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/dashedstrokepattern.md b/website/docs/controls/map/types/dashedstrokepattern.md new file mode 100644 index 0000000000..f4332a494c --- /dev/null +++ b/website/docs/controls/map/types/dashedstrokepattern.md @@ -0,0 +1,7 @@ +--- +title: "DashedStrokePattern" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/dottedstrokepattern.md b/website/docs/controls/map/types/dottedstrokepattern.md new file mode 100644 index 0000000000..84c1e3d928 --- /dev/null +++ b/website/docs/controls/map/types/dottedstrokepattern.md @@ -0,0 +1,7 @@ +--- +title: "DottedStrokePattern" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/fadeintiledisplay.md b/website/docs/controls/map/types/fadeintiledisplay.md new file mode 100644 index 0000000000..c9c761321c --- /dev/null +++ b/website/docs/controls/map/types/fadeintiledisplay.md @@ -0,0 +1,7 @@ +--- +title: "FadeInTileDisplay" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/instantaneoustiledisplay.md b/website/docs/controls/map/types/instantaneoustiledisplay.md new file mode 100644 index 0000000000..9d2e7b653b --- /dev/null +++ b/website/docs/controls/map/types/instantaneoustiledisplay.md @@ -0,0 +1,7 @@ +--- +title: "InstantaneousTileDisplay" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/interactionconfiguration.md b/website/docs/controls/map/types/interactionconfiguration.md new file mode 100644 index 0000000000..3841867258 --- /dev/null +++ b/website/docs/controls/map/types/interactionconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "InteractionConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/interactionflag.md b/website/docs/controls/map/types/interactionflag.md new file mode 100644 index 0000000000..148a15b51d --- /dev/null +++ b/website/docs/controls/map/types/interactionflag.md @@ -0,0 +1,7 @@ +--- +title: "InteractionFlag" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/keyboardconfiguration.md b/website/docs/controls/map/types/keyboardconfiguration.md new file mode 100644 index 0000000000..6d33e50124 --- /dev/null +++ b/website/docs/controls/map/types/keyboardconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "KeyboardConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/mapevent.md b/website/docs/controls/map/types/mapevent.md new file mode 100644 index 0000000000..bde647a37b --- /dev/null +++ b/website/docs/controls/map/types/mapevent.md @@ -0,0 +1,7 @@ +--- +title: "MapEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/mapeventsource.md b/website/docs/controls/map/types/mapeventsource.md new file mode 100644 index 0000000000..9bc60cfbb3 --- /dev/null +++ b/website/docs/controls/map/types/mapeventsource.md @@ -0,0 +1,7 @@ +--- +title: "MapEventSource" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/mapeventtype.md b/website/docs/controls/map/types/mapeventtype.md new file mode 100644 index 0000000000..edcf1c22c3 --- /dev/null +++ b/website/docs/controls/map/types/mapeventtype.md @@ -0,0 +1,7 @@ +--- +title: "MapEventType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/maphoverevent.md b/website/docs/controls/map/types/maphoverevent.md new file mode 100644 index 0000000000..f40de349f9 --- /dev/null +++ b/website/docs/controls/map/types/maphoverevent.md @@ -0,0 +1,7 @@ +--- +title: "MapHoverEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/maplatitudelongitude.md b/website/docs/controls/map/types/maplatitudelongitude.md new file mode 100644 index 0000000000..2088e2e4d6 --- /dev/null +++ b/website/docs/controls/map/types/maplatitudelongitude.md @@ -0,0 +1,7 @@ +--- +title: "MapLatitudeLongitude" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/maplatitudelongitudebounds.md b/website/docs/controls/map/types/maplatitudelongitudebounds.md new file mode 100644 index 0000000000..bc30ef8995 --- /dev/null +++ b/website/docs/controls/map/types/maplatitudelongitudebounds.md @@ -0,0 +1,7 @@ +--- +title: "MapLatitudeLongitudeBounds" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/mappointerevent.md b/website/docs/controls/map/types/mappointerevent.md new file mode 100644 index 0000000000..923297e590 --- /dev/null +++ b/website/docs/controls/map/types/mappointerevent.md @@ -0,0 +1,7 @@ +--- +title: "MapPointerEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/mappositionchangeevent.md b/website/docs/controls/map/types/mappositionchangeevent.md new file mode 100644 index 0000000000..d6ded6fb56 --- /dev/null +++ b/website/docs/controls/map/types/mappositionchangeevent.md @@ -0,0 +1,7 @@ +--- +title: "MapPositionChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/maptapevent.md b/website/docs/controls/map/types/maptapevent.md new file mode 100644 index 0000000000..931af150aa --- /dev/null +++ b/website/docs/controls/map/types/maptapevent.md @@ -0,0 +1,7 @@ +--- +title: "MapTapEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/multifingergesture.md b/website/docs/controls/map/types/multifingergesture.md new file mode 100644 index 0000000000..9a40acb846 --- /dev/null +++ b/website/docs/controls/map/types/multifingergesture.md @@ -0,0 +1,7 @@ +--- +title: "MultiFingerGesture" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/patternfit.md b/website/docs/controls/map/types/patternfit.md new file mode 100644 index 0000000000..6966a5bc64 --- /dev/null +++ b/website/docs/controls/map/types/patternfit.md @@ -0,0 +1,7 @@ +--- +title: "PatternFit" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/solidstrokepattern.md b/website/docs/controls/map/types/solidstrokepattern.md new file mode 100644 index 0000000000..939247c757 --- /dev/null +++ b/website/docs/controls/map/types/solidstrokepattern.md @@ -0,0 +1,7 @@ +--- +title: "SolidStrokePattern" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/strokepattern.md b/website/docs/controls/map/types/strokepattern.md new file mode 100644 index 0000000000..a52ffee548 --- /dev/null +++ b/website/docs/controls/map/types/strokepattern.md @@ -0,0 +1,7 @@ +--- +title: "StrokePattern" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/tiledisplay.md b/website/docs/controls/map/types/tiledisplay.md new file mode 100644 index 0000000000..c6dd612c2d --- /dev/null +++ b/website/docs/controls/map/types/tiledisplay.md @@ -0,0 +1,7 @@ +--- +title: "TileDisplay" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/tilelayerevicterrortilestrategy.md b/website/docs/controls/map/types/tilelayerevicterrortilestrategy.md new file mode 100644 index 0000000000..218081b884 --- /dev/null +++ b/website/docs/controls/map/types/tilelayerevicterrortilestrategy.md @@ -0,0 +1,7 @@ +--- +title: "TileLayerEvictErrorTileStrategy" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/map/types/wmstilelayerconfiguration.md b/website/docs/controls/map/types/wmstilelayerconfiguration.md new file mode 100644 index 0000000000..74516a9463 --- /dev/null +++ b/website/docs/controls/map/types/wmstilelayerconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "WMSTileLayerConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/markdown.md b/website/docs/controls/markdown.md new file mode 100644 index 0000000000..7689273d3c --- /dev/null +++ b/website/docs/controls/markdown.md @@ -0,0 +1,33 @@ +--- +class_name: "flet.Markdown" +examples: "controls/core/markdown" +example_images: "test-images/examples/controls/core/golden/macos/markdown" +example_media: "examples/controls/core/markdown/media" +title: "Markdown" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/markdown) + +### Basic Example + + + +basic + +### Code syntax highlight + + + +code-syntax-highlight + +### Custom text theme + + + + diff --git a/website/docs/controls/menubar.md b/website/docs/controls/menubar.md new file mode 100644 index 0000000000..f0e785d290 --- /dev/null +++ b/website/docs/controls/menubar.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.MenuBar" +examples: "controls/material/menu_bar" +example_images: "test-images/examples/controls/material/golden/macos/menu_bar" +title: "MenuBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/menubar) + +### `MenuBar` with Nested Submenus + + + + + + diff --git a/website/docs/controls/menuitembutton.md b/website/docs/controls/menuitembutton.md new file mode 100644 index 0000000000..46866376e7 --- /dev/null +++ b/website/docs/controls/menuitembutton.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.MenuItemButton" +examples: "controls/material/menu_item_button" +example_images: "test-images/examples/controls/material/golden/macos/menu_item_button" +title: "MenuItemButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/menuitembutton) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/mergesemantics.md b/website/docs/controls/mergesemantics.md new file mode 100644 index 0000000000..177340069f --- /dev/null +++ b/website/docs/controls/mergesemantics.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.MergeSemantics" +title: "MergeSemantics" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/multiview.md b/website/docs/controls/multiview.md new file mode 100644 index 0000000000..245766e2cb --- /dev/null +++ b/website/docs/controls/multiview.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.MultiView" +title: "MultiView" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/navigationbar/index.md b/website/docs/controls/navigationbar/index.md new file mode 100644 index 0000000000..0bf1260210 --- /dev/null +++ b/website/docs/controls/navigationbar/index.md @@ -0,0 +1,34 @@ +--- +class_name: "flet.NavigationBar" +examples: "controls/material/navigation_bar" +example_images: "test-images/examples/controls/material/golden/macos/navigation_bar" +title: "NavigationBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# NavigationBar + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/navigationbar) + +### Basic Example + + + +basic + +### Adaptive navigation + +This example switches between a `NavigationBar` +on narrow layouts and a [`NavigationRail`](../navigationrail/index.md) with an +end [`NavigationDrawer`](../navigationdrawer/index.md) on wider layouts. + + + +Adaptive navigation example switching between a navigation bar and a navigation rail with an end drawer + + diff --git a/website/docs/controls/navigationbardestination.md b/website/docs/controls/navigationbardestination.md new file mode 100644 index 0000000000..aa0e22e079 --- /dev/null +++ b/website/docs/controls/navigationbardestination.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.NavigationBarDestination" +title: "NavigationBarDestination" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/navigationdrawer/index.md b/website/docs/controls/navigationdrawer/index.md new file mode 100644 index 0000000000..31384499e2 --- /dev/null +++ b/website/docs/controls/navigationdrawer/index.md @@ -0,0 +1,46 @@ +--- +class_name: "flet.NavigationDrawer" +examples: "controls/material/navigation_drawer" +example_images: "test-images/examples/controls/material/golden/macos/navigation_drawer" +title: "NavigationDrawer" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# NavigationDrawer + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/navigationdrawer) + +### Start-aligned drawer + + + +Start-aligned navigation drawer example + +### End-aligned drawer + + + +End-aligned navigation drawer example + +### Theming + + + +Themed navigation drawer example + +### Adaptive navigation + +This example switches between a [`NavigationBar`](../navigationbar/index.md) +on narrow layouts and a [`NavigationRail`](../navigationrail/index.md) with an +end [`NavigationDrawer`](../navigationdrawer/index.md) on wider layouts. + + + +Adaptive navigation example switching between a navigation bar and a navigation rail with an end drawer + + diff --git a/website/docs/controls/navigationdrawerdestination.md b/website/docs/controls/navigationdrawerdestination.md new file mode 100644 index 0000000000..bb97626e8f --- /dev/null +++ b/website/docs/controls/navigationdrawerdestination.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.NavigationDrawerDestination" +title: "NavigationDrawerDestination" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/navigationrail/index.md b/website/docs/controls/navigationrail/index.md new file mode 100644 index 0000000000..266f93ca13 --- /dev/null +++ b/website/docs/controls/navigationrail/index.md @@ -0,0 +1,34 @@ +--- +class_name: "flet.NavigationRail" +examples: "controls/material/navigation_rail" +example_images: "test-images/examples/controls/material/golden/macos/navigation_rail" +title: "NavigationRail" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# NavigationRail + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/navigation/navigationrail) + +### Basic Example + + + +basic + +### Adaptive navigation + +This example switches between a [`NavigationBar`](../navigationbar/index.md) +on narrow layouts and a `NavigationRail` with an +end [`NavigationDrawer`](../navigationdrawer/index.md) on wider layouts. + + + +Adaptive navigation example switching between a navigation bar and a navigation rail with an end drawer + + diff --git a/website/docs/controls/navigationraildestination.md b/website/docs/controls/navigationraildestination.md new file mode 100644 index 0000000000..d254894c21 --- /dev/null +++ b/website/docs/controls/navigationraildestination.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.NavigationRailDestination" +title: "NavigationRailDestination" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/outlinedbutton.md b/website/docs/controls/outlinedbutton.md new file mode 100644 index 0000000000..b075132e8d --- /dev/null +++ b/website/docs/controls/outlinedbutton.md @@ -0,0 +1,41 @@ +--- +class_name: "flet.OutlinedButton" +examples: "controls/material/outlined_button" +example_media: "examples/controls/material/outlined_button/media" +example_images: "test-images/examples/controls/material/golden/macos/outlined_button" +title: "OutlinedButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/outlinedbutton) + +### Basic example + + + +basic + +### Handling clicks + + + +handling-clicks + +### Icons + + + +icons + +### Custom content + + + +custom-content + + diff --git a/website/docs/controls/outlinediconbutton.md b/website/docs/controls/outlinediconbutton.md new file mode 100644 index 0000000000..f157fbd8a4 --- /dev/null +++ b/website/docs/controls/outlinediconbutton.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.OutlinedIconButton" +title: "OutlinedIconButton" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See `IconButton` [examples](iconbutton.md#examples). + + diff --git a/website/docs/controls/page.md b/website/docs/controls/page.md new file mode 100644 index 0000000000..215822b7e0 --- /dev/null +++ b/website/docs/controls/page.md @@ -0,0 +1,50 @@ +--- +class_name: "flet.Page" +examples: "controls/core/page" +example_images: "examples/controls/core/page/media" +title: "Page" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Listening to keyboard events + + + +### Mobile device orientation configuration + +Shows how to lock your app to specific device orientations +(e.g., portrait up, landscape right) and listen for orientation changes on mobile devices. + + + +### App exit confirmation + + + +### Hidden app window on startup + +A Flet desktop app (Windows, macOS, or Linux) can start with its window hidden. +This lets your app perform initial setup (for example, add content, resize +or position the window) before showing it to the user. + +In the example below, the window is resized and centered before becoming visible: + + + +If you need this feature when packaging a desktop app using +[`flet build`](../cli/flet-build.md), see [this](../publish/index.md#hidden-app-window-on-startup). + +### Toggle semantics debugger + + + +### Get device locales + + + + diff --git a/website/docs/controls/pagelet.md b/website/docs/controls/pagelet.md new file mode 100644 index 0000000000..bb48f995e8 --- /dev/null +++ b/website/docs/controls/pagelet.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.Pagelet" +examples: "controls/core/pagelet" +example_images: "test-images/examples/controls/core/golden/macos/pagelet" +title: "Pagelet" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/pagelet) + +### Basic example + + + + + + diff --git a/website/docs/controls/pageview.md b/website/docs/controls/pageview.md new file mode 100644 index 0000000000..e7598c82fa --- /dev/null +++ b/website/docs/controls/pageview.md @@ -0,0 +1,21 @@ +--- +class_name: "flet.PageView" +examples: "controls/core/page_view" +title: "PageView" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + +### Programmatic Swipes + + + + diff --git a/website/docs/controls/placeholder.md b/website/docs/controls/placeholder.md new file mode 100644 index 0000000000..786734de30 --- /dev/null +++ b/website/docs/controls/placeholder.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.Placeholder" +examples: "controls/core/placeholder" +example_images: "test-images/examples/controls/core/golden/macos/placeholder" +title: "Placeholder" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/placeholder) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/popupmenubutton.md b/website/docs/controls/popupmenubutton.md new file mode 100644 index 0000000000..0f03d35dfd --- /dev/null +++ b/website/docs/controls/popupmenubutton.md @@ -0,0 +1,26 @@ +--- +class_name: "flet.PopupMenuButton" +examples: "controls/material/popup_menu_button" +example_media: "examples/controls/material/popup_menu_button/media" +example_images: "test-images/examples/controls/material/golden/macos/popup_menu_button" +popup_menu_item_class_name: "flet.PopupMenuItem" +title: "PopupMenuButton" +--- + +import {ClassAll, ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/popupmenubutton) + +### Basic Example + + + +basic + + + + diff --git a/website/docs/controls/progressbar.md b/website/docs/controls/progressbar.md new file mode 100644 index 0000000000..ed79d0a920 --- /dev/null +++ b/website/docs/controls/progressbar.md @@ -0,0 +1,23 @@ +--- +class_name: "flet.ProgressBar" +examples: "controls/material/progress_bar" +example_media: "examples/controls/material/progress_bar/media" +example_images: "test-images/examples/controls/material/golden/macos/progress_bar" +title: "ProgressBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/progressbar) + +### Determinate and indeterminate progress bars + + + +determinate-and-indeterminate + + diff --git a/website/docs/controls/progressring.md b/website/docs/controls/progressring.md new file mode 100644 index 0000000000..a4b2c5e0fb --- /dev/null +++ b/website/docs/controls/progressring.md @@ -0,0 +1,29 @@ +--- +class_name: "flet.ProgressRing" +examples: "controls/material/progress_ring" +example_images: "test-images/examples/controls/material/golden/macos/progress_ring" +example_media: "examples/controls/material/progress_ring/media" +title: "ProgressRing" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/progressring) + +### Determinate and indeterminate progress rings + + + +determinate-and-indeterminate + +### Gauge with progress + + + +determinate-and-indeterminate + + diff --git a/website/docs/controls/radio.md b/website/docs/controls/radio.md new file mode 100644 index 0000000000..a243d3eeff --- /dev/null +++ b/website/docs/controls/radio.md @@ -0,0 +1,34 @@ +--- +class_name: "flet.Radio" +examples: "controls/material/radio" +example_images: "test-images/examples/controls/material/golden/macos/radio" +title: "Radio" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/radio) + +### Basic Example + + + +basic + +### Handling selection changes + + + +handling-selection-changes + +### Styled radio buttons + + + +styled + + diff --git a/website/docs/controls/radiogroup.md b/website/docs/controls/radiogroup.md new file mode 100644 index 0000000000..ca9222c95d --- /dev/null +++ b/website/docs/controls/radiogroup.md @@ -0,0 +1,12 @@ +--- +class_name: "flet.RadioGroup" +title: "RadioGroup" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +## Examples + +See [these](radio.md#examples). + + diff --git a/website/docs/controls/rangeslider.md b/website/docs/controls/rangeslider.md new file mode 100644 index 0000000000..518b82218e --- /dev/null +++ b/website/docs/controls/rangeslider.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.RangeSlider" +examples: "controls/material/range_slider" +example_images: "test-images/examples/controls/material/golden/macos/range_slider" +title: "RangeSlider" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/rangeslider) + +### Basic Example + + + +basic + +### RangeSlider with events + + + +handling_events + + diff --git a/website/docs/controls/reorderabledraghandle.md b/website/docs/controls/reorderabledraghandle.md new file mode 100644 index 0000000000..f5a8fcd61b --- /dev/null +++ b/website/docs/controls/reorderabledraghandle.md @@ -0,0 +1,21 @@ +--- +class_name: "flet.ReorderableDragHandle" +examples: "controls/material/reorderable_drag_handle" +example_images: "test-images/examples/controls/material/golden/macos/reorderable_drag_handle" +example_media: "examples/controls/material/reorderable_drag_handle/media" +title: "ReorderableDragHandle" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/reorderablelistview.md b/website/docs/controls/reorderablelistview.md new file mode 100644 index 0000000000..da2e76714a --- /dev/null +++ b/website/docs/controls/reorderablelistview.md @@ -0,0 +1,27 @@ +--- +class_name: "flet.ReorderableListView" +examples: "controls/material/reorderable_list_view" +example_images: "test-images/examples/controls/material/golden/macos/reorderable_list_view" +example_media: "examples/controls/material/reorderable_list_view/media" +title: "ReorderableListView" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/autofillgroup) + +### Horizontal and Vertical + + + +horizontal-and-vertical + +### Custom drag handle + +See [this](reorderabledraghandle.md#examples). + + diff --git a/website/docs/controls/responsiverow.md b/website/docs/controls/responsiverow.md new file mode 100644 index 0000000000..cf4a2e63bd --- /dev/null +++ b/website/docs/controls/responsiverow.md @@ -0,0 +1,32 @@ +--- +class_name: "flet.ResponsiveRow" +examples: "controls/core/responsive_row" +example_images: "test-images/examples/controls/core/golden/macos/responsive_row" +title: "ResponsiveRow" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/responsiverow) + +### ResponsiveRow + + + + + +### Custom breakpoints + + + + + +### Scrollable content + + + + diff --git a/website/docs/controls/rive/index.md b/website/docs/controls/rive/index.md new file mode 100644 index 0000000000..cd5b4d65be --- /dev/null +++ b/website/docs/controls/rive/index.md @@ -0,0 +1,50 @@ +--- +class_name: "flet_rive.Rive" +examples: "extensions/rive" +title: "Rive" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Rive + +Render [Rive](https://rive.app/) animations in your [Flet](https://flet.dev) app with the `flet-rive` extension. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ (x64 only) | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-rive` to your project dependencies: + + + +```bash +uv add flet-rive +``` + + + +```bash +pip install flet-rive # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +:::tip[Hosting Rive files] +Host `.riv` files locally or load them from a CDN. Use `placeholder` to keep layouts responsive while animations load. +::: + +## Example + + + +## Description + + diff --git a/website/docs/controls/rotatedbox.md b/website/docs/controls/rotatedbox.md new file mode 100644 index 0000000000..c0269198e1 --- /dev/null +++ b/website/docs/controls/rotatedbox.md @@ -0,0 +1,18 @@ +--- +class_name: "flet.RotatedBox" +examples: "controls/core/rotated_box" +example_images: "test-images/examples/controls/core/golden/macos/rotated_box" +title: "RotatedBox" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Example + + + + + + diff --git a/website/docs/controls/router.md b/website/docs/controls/router.md new file mode 100644 index 0000000000..3c1842cc53 --- /dev/null +++ b/website/docs/controls/router.md @@ -0,0 +1,63 @@ +--- +title: "Router" +class_name: flet.Router +examples: apps/router +--- + +import {ClassSummary, ClassMembers, CodeExample} from '@site/src/components/crocodocs'; + + + +`Router` matches the current page route against a tree of [Route](../types/route.md) definitions +and renders the matched component chain with nested outlet contexts. + +Navigation is done via [page.navigate()](../controls/page.md#flet.Page.navigate) or [page.push_route()](../controls/page.md#flet.Page.push_route). + +## Examples + +### Basic + + + +### Layout with outlet + + + +### Dynamic segments + + + +### Loaders + + + +### Active links + + + +### Featured + + + +### Managed views — nested routes + +Each route component returns a [View](../controls/view.md) with its own [AppBar](../controls/appbar.md). +Navigating deeper pushes views onto the stack; swipe-back and AppBar back button pop them. + + + +### Managed views — shared layout with outlet + +A layout route with `outlet=True` wraps child routes in a shared [View](../controls/view.md). +Leaf components return regular controls; the layout provides the View. + + + +### Managed views — full app with NavigationRail + +Complete app with [NavigationRail](../controls/navigationrail), stacked project views, +and tabbed settings — all using `manage_views=True`. + + + + diff --git a/website/docs/controls/row.md b/website/docs/controls/row.md new file mode 100644 index 0000000000..bdf7630cba --- /dev/null +++ b/website/docs/controls/row.md @@ -0,0 +1,40 @@ +--- +class_name: "flet.Row" +examples: "controls/core/row" +example_images: "test-images/examples/controls/core/golden/macos/row" +title: "Row" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/row) + +### Spacing children + + + +spacing + +### Wrapping children + + + +wrap + +### Setting horizontal alignment + + + +alignment + +### Setting vertical alignment + + + +vertical-alignment + + diff --git a/website/docs/controls/safearea.md b/website/docs/controls/safearea.md new file mode 100644 index 0000000000..b7a3f5133d --- /dev/null +++ b/website/docs/controls/safearea.md @@ -0,0 +1,19 @@ +--- +class_name: "flet.SafeArea" +examples: "controls/core/safe_area" +title: "SafeArea" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Example + +[Live example](https://flet-controls-gallery.fly.dev/layout/safearea) + +### Basic Example + + + + diff --git a/website/docs/controls/screenshot.md b/website/docs/controls/screenshot.md new file mode 100644 index 0000000000..3e0be32a61 --- /dev/null +++ b/website/docs/controls/screenshot.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.Screenshot" +examples: "controls/core/screenshot" +title: "Screenshot" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Taking control screenshot + + + + diff --git a/website/docs/controls/scrollablecontrol.md b/website/docs/controls/scrollablecontrol.md new file mode 100644 index 0000000000..278de6142e --- /dev/null +++ b/website/docs/controls/scrollablecontrol.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.ScrollableControl" +title: "ScrollableControl" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/searchbar.md b/website/docs/controls/searchbar.md new file mode 100644 index 0000000000..91564f0514 --- /dev/null +++ b/website/docs/controls/searchbar.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.SearchBar" +examples: "controls/material/search_bar" +example_images: "test-images/examples/controls/material/golden/macos/search_bar" +title: "SearchBar" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/searchbar) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/segment.md b/website/docs/controls/segment.md new file mode 100644 index 0000000000..71cbb65c04 --- /dev/null +++ b/website/docs/controls/segment.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.Segment" +title: "Segment" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/segmentedbutton/index.md b/website/docs/controls/segmentedbutton/index.md new file mode 100644 index 0000000000..f05610e18d --- /dev/null +++ b/website/docs/controls/segmentedbutton/index.md @@ -0,0 +1,24 @@ +--- +class_name: "flet.SegmentedButton" +examples: "controls/material/segmented_button" +example_images: "test-images/examples/controls/material/golden/macos/segmented_button" +title: "SegmentedButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# SegmentedButton + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/segmentedbutton) + +### Basic Example + + + + + + diff --git a/website/docs/controls/selectionarea.md b/website/docs/controls/selectionarea.md new file mode 100644 index 0000000000..92ed6fabfa --- /dev/null +++ b/website/docs/controls/selectionarea.md @@ -0,0 +1,21 @@ +--- +class_name: "flet.SelectionArea" +examples: "controls/material/selection_area" +example_images: "test-images/examples/controls/material/golden/macos/selection_area" +example_media: "examples/controls/material/selection_area/media" +title: "SelectionArea" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/semantics.md b/website/docs/controls/semantics.md new file mode 100644 index 0000000000..2bf73a7a31 --- /dev/null +++ b/website/docs/controls/semantics.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.Semantics" +examples: "controls/core/semantics" +title: "Semantics" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + diff --git a/website/docs/controls/service.md b/website/docs/controls/service.md new file mode 100644 index 0000000000..cd1e7849be --- /dev/null +++ b/website/docs/controls/service.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.Service" +title: "Service" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/shadermask.md b/website/docs/controls/shadermask.md new file mode 100644 index 0000000000..75b32946d2 --- /dev/null +++ b/website/docs/controls/shadermask.md @@ -0,0 +1,34 @@ +--- +class_name: "flet.ShaderMask" +examples: "controls/core/shader_mask" +example_images: "test-images/examples/controls/core/golden/macos/shader_mask" +title: "ShaderMask" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/utility/shadermask) + +### Pink glow around image edges + + + +pink-radial-glow + +### Fade out bottom edge of an image + + + +fade-out-image-bottom + +### Applying linear and radial gradients/shaders + + + +fade-out-image-bottom + + diff --git a/website/docs/controls/shimmer.md b/website/docs/controls/shimmer.md new file mode 100644 index 0000000000..9b7174d7a4 --- /dev/null +++ b/website/docs/controls/shimmer.md @@ -0,0 +1,32 @@ +--- +class_name: "flet.Shimmer" +examples: "controls/core/shimmer" +example_images: "test-images/examples/controls/core/golden/macos/shimmer" +title: "Shimmer" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic + + + +custom-label + +### Skeleton list placeholders + + + +custom-label + +### Custom gradients and directions + + + +custom-label + + diff --git a/website/docs/controls/slider.md b/website/docs/controls/slider.md new file mode 100644 index 0000000000..bed7120587 --- /dev/null +++ b/website/docs/controls/slider.md @@ -0,0 +1,41 @@ +--- +class_name: "flet.Slider" +examples: "controls/material/slider" +example_images: "test-images/examples/controls/material/golden/macos/slider" +example_media: "examples/controls/material/slider/media" +title: "Slider" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/slider/basic) + +### Basic Example + + + +basic + +### Setting a custom label + + + +custom-label + +### Handling events + + + +handling-events + +### Random values + + + +random-values + + diff --git a/website/docs/controls/snackbar.md b/website/docs/controls/snackbar.md new file mode 100644 index 0000000000..9104aee4ea --- /dev/null +++ b/website/docs/controls/snackbar.md @@ -0,0 +1,39 @@ +--- +class_name: "flet.SnackBar" +examples: "controls/material/snack_bar" +example_images: "test-images/examples/controls/material/golden/macos/snack_bar" +snack_bar_action_class_name: "flet.SnackBarAction" +title: "SnackBar" +--- + +import {ClassAll, ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/snackbar) + +### Basic Example + + + +basic + +### Counter + + + +Snack bar with counter + +### Action + + + +Snack bar with a simple action + +Snack bar with a custom action + + + + diff --git a/website/docs/controls/stack.md b/website/docs/controls/stack.md new file mode 100644 index 0000000000..ec2cb9fa9e --- /dev/null +++ b/website/docs/controls/stack.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.Stack" +examples: "controls/core/stack" +example_images: "test-images/examples/controls/core/golden/macos/stack" +title: "Stack" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/stack) + +### Avatar with online status + + + +online-avatar + +### Absolute positioning + + + +absolute-positioning + + diff --git a/website/docs/controls/submenubutton.md b/website/docs/controls/submenubutton.md new file mode 100644 index 0000000000..78e38ba958 --- /dev/null +++ b/website/docs/controls/submenubutton.md @@ -0,0 +1,29 @@ +--- +class_name: "flet.SubmenuButton" +examples: "controls/material/submenu_button" +example_images: "test-images/examples/controls/material/golden/macos/submenu_button" +example_media: "examples/controls/material/submenu_button/media" +title: "SubmenuButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/submenubutton) + +### Basic Example + + + +basic + +### Standalone Example + + + +standalone + + diff --git a/website/docs/controls/switch.md b/website/docs/controls/switch.md new file mode 100644 index 0000000000..61e525e681 --- /dev/null +++ b/website/docs/controls/switch.md @@ -0,0 +1,28 @@ +--- +class_name: "flet.Switch" +examples: "controls/material/switch" +example_images: "test-images/examples/controls/material/golden/macos/switch" +title: "Switch" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/switch) + +### Basic Example + + + +basic + +### Handling change events + + + +handling-events + + diff --git a/website/docs/controls/tab.md b/website/docs/controls/tab.md new file mode 100644 index 0000000000..3ded7c7c96 --- /dev/null +++ b/website/docs/controls/tab.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.Tab" +title: "Tab" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/tabbar.md b/website/docs/controls/tabbar.md new file mode 100644 index 0000000000..17ebc38b06 --- /dev/null +++ b/website/docs/controls/tabbar.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.TabBar" +title: "TabBar" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/tabbarview.md b/website/docs/controls/tabbarview.md new file mode 100644 index 0000000000..6e89128294 --- /dev/null +++ b/website/docs/controls/tabbarview.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.TabBarView" +title: "TabBarView" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/tabs/index.md b/website/docs/controls/tabs/index.md new file mode 100644 index 0000000000..f445a77d18 --- /dev/null +++ b/website/docs/controls/tabs/index.md @@ -0,0 +1,41 @@ +--- +class_name: "flet.Tabs" +examples: "controls/material/tabs" +example_images: "test-images/examples/controls/material/golden/macos/tabs" +example_media: "examples/controls/material/tabs/media" +title: "Tabs" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + +# Tabs + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/tabs) + +### Basic Example + + + + + +### Nesting tabs + + + +### Dynamic tab addition + + + +### Custom indicator + + + +### Programmatical Tab switch + + + + diff --git a/website/docs/controls/text.md b/website/docs/controls/text.md new file mode 100644 index 0000000000..e796845352 --- /dev/null +++ b/website/docs/controls/text.md @@ -0,0 +1,53 @@ +--- +class_name: "flet.Text" +examples: "controls/core/text" +example_images: "test-images/examples/controls/core/golden/macos/text" +example_media: "examples/controls/core/text/media" +title: "Text" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/text) + +### Custom text styles + + + + + +### Pre-defined theme text styles + + + + + +### Font with variable weight + + + + + +### Basic rich text example + + + + + +### Rich text with borders and stroke + + + + + +### Rich text with gradient + + + + + + diff --git a/website/docs/controls/textbutton.md b/website/docs/controls/textbutton.md new file mode 100644 index 0000000000..3cfa0a9290 --- /dev/null +++ b/website/docs/controls/textbutton.md @@ -0,0 +1,40 @@ +--- +class_name: "flet.TextButton" +examples: "controls/material/text_button" +example_images: "test-images/examples/controls/material/golden/macos/text_button" +title: "TextButton" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/buttons/textbutton) + +### Basic Example + + + +basic + +### Icons + + + +icons + +### Handling clicks + + + +handling-clicks + +### Custom content + + + +custom-content + + diff --git a/website/docs/controls/textfield.md b/website/docs/controls/textfield.md new file mode 100644 index 0000000000..fa24ad8123 --- /dev/null +++ b/website/docs/controls/textfield.md @@ -0,0 +1,71 @@ +--- +class_name: "flet.TextField" +examples: "controls/material/text_field" +example_images: "test-images/examples/controls/material/golden/macos/textfield" +example_media: "examples/controls/material/text_field/media" +title: "TextField" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/input/textfield) + +### Basic Example + + + +basic + +### Handling change events + + + +handling-change-events + +### Handling selection changes + + + +selection-change + +### Password with reveal button + + + +password + +### Multiline fields + + + +multiline + +### Underlined and borderless TextFields + + + +underlined-and-borderless + +### Setting prefixes and suffixes + + + +prefix-and-suffix + +### Styled TextField + + + +styled + +### Custom label, hint, helper, and counter texts and styles + + + +label-hint-helper-counter + + diff --git a/website/docs/controls/timepicker.md b/website/docs/controls/timepicker.md new file mode 100644 index 0000000000..4b11fc1508 --- /dev/null +++ b/website/docs/controls/timepicker.md @@ -0,0 +1,34 @@ +--- +class_name: "flet.TimePicker" +examples: "controls/material/time_picker" +example_images: "test-images/examples/controls/material/golden/macos/time_picker" +title: "TimePicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/dialogs/timepicker) + +### Basic Example + + + + + +### Hour Formats + + + + + +### Custom Locale + + + + + + diff --git a/website/docs/controls/transparentpointer.md b/website/docs/controls/transparentpointer.md new file mode 100644 index 0000000000..0894b0e183 --- /dev/null +++ b/website/docs/controls/transparentpointer.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TransparentPointer" +examples: "controls/core/transparent_pointer" +title: "TransparentPointer" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Example + +## Basic Example + + + + diff --git a/website/docs/controls/verticaldivider.md b/website/docs/controls/verticaldivider.md new file mode 100644 index 0000000000..61d175847f --- /dev/null +++ b/website/docs/controls/verticaldivider.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.VerticalDivider" +examples: "controls/core/vertical_divider" +example_images: "test-images/examples/controls/core/golden/macos/vertical_divider" +title: "VerticalDivider" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/layout/verticaldivider) + +### Basic Example + + + +basic + + diff --git a/website/docs/controls/video/index.md b/website/docs/controls/video/index.md new file mode 100644 index 0000000000..7c798c31be --- /dev/null +++ b/website/docs/controls/video/index.md @@ -0,0 +1,164 @@ +--- +class_name: "flet_video.Video" +examples: "extensions/video" +title: "Video" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Video + +Embed a full-featured video player in your [Flet](https://flet.dev) app with playlist support, hardware acceleration controls, and subtitle configuration. + +It is powered by the [media_kit](https://pub.dev/packages/media_kit) Flutter package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add the `flet-video` package to your project dependencies: + + + +```bash +uv add flet-video +``` + + + +```bash +pip install flet-video # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Requirements + +The below sections show the required configurations for each platform. + +### Android + +You may need to declare and request file-system/storage permissions, depending on your use case: + +- [`android.permission.READ_MEDIA_AUDIO`](https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_AUDIO) (optional): Allows to read audio files from external storage. Android 13 or higher. +- [`android.permission.READ_MEDIA_VIDEO`](https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_VIDEO) (optional): Allows to read video files from external storage. Android 13 or higher. +- [`android.permission.READ_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE) (optional): Allows reading from external storage. Android 12 or lower. +- [`android.permission.WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) (optional): Allows writing to external storage. Android 12 or lower. + + + +```bash +flet build apk \ + --android-permissions android.permission.READ_MEDIA_AUDIO=true \ + --android-permissions android.permission.READ_MEDIA_VIDEO=true \ + --android-permissions android.permission.READ_EXTERNAL_STORAGE=true \ + --android-permissions android.permission.WRITE_EXTERNAL_STORAGE=true +``` + + +```toml +[tool.flet.android.permission] +"android.permission.READ_MEDIA_AUDIO" = true +"android.permission.READ_MEDIA_VIDEO" = true +"android.permission.READ_EXTERNAL_STORAGE" = true +"android.permission.WRITE_EXTERNAL_STORAGE" = true +``` + + +Use [`PermissionHandler`](../../services/permissionhandler/index.md) to **request** permissions at runtime. + +See also: + +- [setting Android permissions](../../publish/android.md#permissions) + +### Linux + +[`libmpv`](https://github.com/mpv-player/mpv) libraries must be installed and present on the machine running the app. + +On Ubuntu/Debian, this can be done with: +```bash +sudo apt install libmpv-dev mpv +``` + +If you encounter `libmpv.so.1` load errors, run: + +```bash +sudo apt update +sudo apt install libmpv-dev libmpv2 +sudo ln -s /usr/lib/x86_64-linux-gnu/libmpv.so /usr/lib/libmpv.so.1 +``` + +## Examples + +### Basic + + + +### Playback + +Drive playback programmatically with methods like +[`play()`][flet_video.Video.play], [`pause()`][flet_video.Video.pause], [`stop()`][flet_video.Video.stop], [`seek()`][flet_video.Video.seek], [`next()`][flet_video.Video.next], and [`previous()`][flet_video.Video.previous], +and inspect status with methods like [`is_playing()`][flet_video.Video.is_playing], [`get_current_position()`][flet_video.Video.get_current_position], and [`get_duration()`][flet_video.Video.get_duration]. + + + +### Screenshot + +Shows how to capture the current video frame with +[`take_screenshot()`][flet_video.Video.take_screenshot] and display it as an image. + + + +### Playlist + +Mutate [`playlist`][flet_video.Video.playlist] directly to add, +remove, or replace items, and navigate between tracks. + + + +### Events + +Listen for player [events](#flet_video.Video-events) like +[`on_load`][flet_video.Video.on_load], [`on_complete`][flet_video.Video.on_complete], [`on_track_change`][flet_video.Video.on_track_change], etc. + + + +### Subtitles + +Attach a [`VideoSubtitleTrack`][flet_video.VideoSubtitleTrack] (here, raw VTT text) +and customize its appearance with [`VideoSubtitleConfiguration`][flet_video.VideoSubtitleConfiguration]. + + + +### Controls + +Switch between [`AdaptiveVideoControls`][flet_video.AdaptiveVideoControls], [`MaterialVideoControls`][flet_video.MaterialVideoControls], [`MaterialDesktopVideoControls`][flet_video.MaterialDesktopVideoControls], custom, and hidden control sets at runtime. + + + +### Mode-specific Controls + +Show different controls in normal vs. fullscreen mode by mapping each +[`VideoControlsMode`][flet_video.VideoControlsMode] to its own [`controls`][flet_video.Video.controls] value. + + + +### Button Bars + +Customize the [`primary_button_bar`][flet_video.MaterialDesktopVideoControls.primary_button_bar], +[`top_button_bar`][flet_video.MaterialDesktopVideoControls.top_button_bar], and +[`bottom_button_bar`][flet_video.MaterialDesktopVideoControls.bottom_button_bar] of +[`MaterialDesktopVideoControls`][flet_video.MaterialDesktopVideoControls] with built-in and custom items. + + + +## Description + + diff --git a/website/docs/controls/video/types/adaptivevideocontrols.md b/website/docs/controls/video/types/adaptivevideocontrols.md new file mode 100644 index 0000000000..dea2fba5e8 --- /dev/null +++ b/website/docs/controls/video/types/adaptivevideocontrols.md @@ -0,0 +1,7 @@ +--- +title: "AdaptiveVideoControls" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/materialdesktopvideocontrols.md b/website/docs/controls/video/types/materialdesktopvideocontrols.md new file mode 100644 index 0000000000..7d2b006e88 --- /dev/null +++ b/website/docs/controls/video/types/materialdesktopvideocontrols.md @@ -0,0 +1,7 @@ +--- +title: "MaterialDesktopVideoControls" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/materialvideocontrols.md b/website/docs/controls/video/types/materialvideocontrols.md new file mode 100644 index 0000000000..0ff1627835 --- /dev/null +++ b/website/docs/controls/video/types/materialvideocontrols.md @@ -0,0 +1,7 @@ +--- +title: "MaterialVideoControls" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/playlistmode.md b/website/docs/controls/video/types/playlistmode.md new file mode 100644 index 0000000000..b8afcaf44b --- /dev/null +++ b/website/docs/controls/video/types/playlistmode.md @@ -0,0 +1,7 @@ +--- +title: "PlaylistMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videobaritem.md b/website/docs/controls/video/types/videobaritem.md new file mode 100644 index 0000000000..ae21403178 --- /dev/null +++ b/website/docs/controls/video/types/videobaritem.md @@ -0,0 +1,7 @@ +--- +title: "VideoBarItem" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videoconfiguration.md b/website/docs/controls/video/types/videoconfiguration.md new file mode 100644 index 0000000000..f392ba0a19 --- /dev/null +++ b/website/docs/controls/video/types/videoconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "VideoConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videocontrols.md b/website/docs/controls/video/types/videocontrols.md new file mode 100644 index 0000000000..e962164fe4 --- /dev/null +++ b/website/docs/controls/video/types/videocontrols.md @@ -0,0 +1,7 @@ +--- +title: "VideoControls" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videocontrolsmode.md b/website/docs/controls/video/types/videocontrolsmode.md new file mode 100644 index 0000000000..a1d1841a77 --- /dev/null +++ b/website/docs/controls/video/types/videocontrolsmode.md @@ -0,0 +1,7 @@ +--- +title: "VideoControlsMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videofullscreenbutton.md b/website/docs/controls/video/types/videofullscreenbutton.md new file mode 100644 index 0000000000..dc28b411a9 --- /dev/null +++ b/website/docs/controls/video/types/videofullscreenbutton.md @@ -0,0 +1,7 @@ +--- +title: "VideoFullscreenButton" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videomedia.md b/website/docs/controls/video/types/videomedia.md new file mode 100644 index 0000000000..4ecd06291c --- /dev/null +++ b/website/docs/controls/video/types/videomedia.md @@ -0,0 +1,7 @@ +--- +title: "VideoMedia" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videoplayorpausebutton.md b/website/docs/controls/video/types/videoplayorpausebutton.md new file mode 100644 index 0000000000..386584d402 --- /dev/null +++ b/website/docs/controls/video/types/videoplayorpausebutton.md @@ -0,0 +1,7 @@ +--- +title: "VideoPlayOrPauseButton" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videopositionindicator.md b/website/docs/controls/video/types/videopositionindicator.md new file mode 100644 index 0000000000..425491943b --- /dev/null +++ b/website/docs/controls/video/types/videopositionindicator.md @@ -0,0 +1,7 @@ +--- +title: "VideoPositionIndicator" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videoskipnextbutton.md b/website/docs/controls/video/types/videoskipnextbutton.md new file mode 100644 index 0000000000..b7980c4cde --- /dev/null +++ b/website/docs/controls/video/types/videoskipnextbutton.md @@ -0,0 +1,7 @@ +--- +title: "VideoSkipNextButton" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videoskippreviousbutton.md b/website/docs/controls/video/types/videoskippreviousbutton.md new file mode 100644 index 0000000000..6b5015fc53 --- /dev/null +++ b/website/docs/controls/video/types/videoskippreviousbutton.md @@ -0,0 +1,7 @@ +--- +title: "VideoSkipPreviousButton" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videospacer.md b/website/docs/controls/video/types/videospacer.md new file mode 100644 index 0000000000..ceeb6dab3b --- /dev/null +++ b/website/docs/controls/video/types/videospacer.md @@ -0,0 +1,7 @@ +--- +title: "VideoSpacer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videosubtitleconfiguration.md b/website/docs/controls/video/types/videosubtitleconfiguration.md new file mode 100644 index 0000000000..b39d05e186 --- /dev/null +++ b/website/docs/controls/video/types/videosubtitleconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "VideoSubtitleConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videosubtitletrack.md b/website/docs/controls/video/types/videosubtitletrack.md new file mode 100644 index 0000000000..5c21dad8bb --- /dev/null +++ b/website/docs/controls/video/types/videosubtitletrack.md @@ -0,0 +1,7 @@ +--- +title: "VideoSubtitleTrack" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/video/types/videovolumebutton.md b/website/docs/controls/video/types/videovolumebutton.md new file mode 100644 index 0000000000..ba78639372 --- /dev/null +++ b/website/docs/controls/video/types/videovolumebutton.md @@ -0,0 +1,11 @@ +--- +title: "VideoVolumeButton" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +:::note +`VideoVolumeButton` is currently rendered only by [`MaterialDesktopVideoControls`](materialdesktopvideocontrols.md). +::: + + diff --git a/website/docs/controls/view.md b/website/docs/controls/view.md new file mode 100644 index 0000000000..6a6077e760 --- /dev/null +++ b/website/docs/controls/view.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.View" +title: "View" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/webview/index.md b/website/docs/controls/webview/index.md new file mode 100644 index 0000000000..b9a849d7fd --- /dev/null +++ b/website/docs/controls/webview/index.md @@ -0,0 +1,73 @@ +--- +class_name: "flet_webview.WebView" +examples: "extensions/webview" +title: "WebView" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# WebView + +Display web content in a WebView to be shown in your [Flet](https://flet.dev) apps. + +It is powered by the [webview_flutter](https://pub.dev/packages/webview_flutter) +and [webview_flutter_web](https://pub.dev/packages/webview_flutter_web) Flutter packages. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-webview` to your project dependencies: + + + +```bash +uv add flet-webview +``` + + + +```bash +pip install flet-webview # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Example + + + +## Troubleshooting + +### NET::ERR_CLEARTEXT_NOT_PERMITTED Error + +If you run into the NET::ERR_CLEARTEXT_NOT_PERMITTED error in Android, +then the app you’re using is trying to access a web page that wants to +transmit cleartext or unsecured information. Android blocks apps from +doing this in order to avoid compromising user data. + +For more details, see [this](https://developer.android.com/privacy-and-security/security-config#CleartextTraffic) +and [this](https://kinsta.com/blog/net-err_cleartext_not_permitted/). + +To fix it, your app's configuration +(precisely, the [manifest application attributes](../../publish/android.md#application-attributes)) +needs to be modified as follows: + + + +```toml +[tool.flet.android.manifest_application] +usesCleartextTraffic = "true" +``` + + +## Description + + diff --git a/website/docs/controls/webview/types/loglevelseverity.md b/website/docs/controls/webview/types/loglevelseverity.md new file mode 100644 index 0000000000..a56b0eaf6d --- /dev/null +++ b/website/docs/controls/webview/types/loglevelseverity.md @@ -0,0 +1,7 @@ +--- +title: "LogLevelSeverity" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/webview/types/requestmethod.md b/website/docs/controls/webview/types/requestmethod.md new file mode 100644 index 0000000000..98fffe0bea --- /dev/null +++ b/website/docs/controls/webview/types/requestmethod.md @@ -0,0 +1,7 @@ +--- +title: "RequestMethod" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/webview/types/webviewconsolemessageevent.md b/website/docs/controls/webview/types/webviewconsolemessageevent.md new file mode 100644 index 0000000000..fc2b85119b --- /dev/null +++ b/website/docs/controls/webview/types/webviewconsolemessageevent.md @@ -0,0 +1,7 @@ +--- +title: "WebViewConsoleMessageEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/webview/types/webviewjavascriptevent.md b/website/docs/controls/webview/types/webviewjavascriptevent.md new file mode 100644 index 0000000000..d55e2a89f6 --- /dev/null +++ b/website/docs/controls/webview/types/webviewjavascriptevent.md @@ -0,0 +1,7 @@ +--- +title: "WebViewJavaScriptEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/webview/types/webviewscrollevent.md b/website/docs/controls/webview/types/webviewscrollevent.md new file mode 100644 index 0000000000..1433ecfb95 --- /dev/null +++ b/website/docs/controls/webview/types/webviewscrollevent.md @@ -0,0 +1,7 @@ +--- +title: "WebViewScrollEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/controls/windowdragarea.md b/website/docs/controls/windowdragarea.md new file mode 100644 index 0000000000..3d038f87df --- /dev/null +++ b/website/docs/controls/windowdragarea.md @@ -0,0 +1,20 @@ +--- +class_name: "flet.WindowDragArea" +examples: "controls/core/window_drag_area" +example_images: "test-images/examples/controls/core/golden/macos/window_drag_area" +title: "WindowDragArea" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### No frame window + + + +no-frame-window + + diff --git a/website/docs/cookbook/accessibility.md b/website/docs/cookbook/accessibility.md new file mode 100644 index 0000000000..bd3afd57cd --- /dev/null +++ b/website/docs/cookbook/accessibility.md @@ -0,0 +1,63 @@ +--- +title: "Accessibility" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +Flet is based on [Flutter](https://flutter.dev) which includes first-class framework support for +accessibility in addition to that provided by the underlying operating system. + +## Screen readers + +For mobile, screen readers ([TalkBack](https://support.google.com/accessibility/android/answer/6283677?hl=en), [VoiceOver](https://www.apple.com/lae/accessibility/iphone/vision/)) enable visually +impaired users to get spoken feedback about the contents of the screen and interact +with the UI via gestures on mobile and keyboard shortcuts on desktop. +Turn on VoiceOver or TalkBack on your mobile device and navigate around your app. + +For web, the following screen readers are currently supported: + +Mobile Browsers: + +* iOS - VoiceOver +* Android - TalkBack + +Desktop Browsers: + +* MacOS - VoiceOver +* Windows - JAWs & NVDA + +Screen Readers users on web will need to toggle "Enable accessibility" +button to build the semantics tree. + +### Text + +Use `Text.semantics_label` property to override default Text control semantics. + +### Buttons + +All buttons with text on them generate proper semantics. + +Use `tooltip` property to add screen reader semantics for +[`IconButton`](../controls/iconbutton.md), [`FloatingActionButton`](../controls/floatingactionbutton.md) +and [`PopupMenuButton`](../controls/popupmenubutton.md) buttons. + +### `TextField` and `Dropdown` + +Use `TextField.label` and `Dropdown.label` properties to add screen +reader semantics to those controls. + +### Custom semantics + +For any specific requirements use [`Semantics`](../controls/semantics.md) control. + +### Debugging semantics + +Set [`Page.show_semantics_debugger`](../controls/page.md) to `True` +to show an overlay that shows the accessibility information reported by the framework. + +You can implement a specific [keyboard shortcut](keyboard-shortcuts.md) to conveniently toggle +semantics debugger during app development: + + + + diff --git a/website/docs/cookbook/adaptive-apps.md b/website/docs/cookbook/adaptive-apps.md new file mode 100644 index 0000000000..35a6cd1d70 --- /dev/null +++ b/website/docs/cookbook/adaptive-apps.md @@ -0,0 +1,209 @@ +--- +title: "Adaptive apps" +--- + +import {Image} from '@site/src/components/crocodocs'; + +Flet framework allows you to develop adaptive apps, which means having a single codebase that +will deliver a different look depending on the device's platform. + +Below is an example of a very simple app that has a different look on iOS and Android platforms: + +```python +import flet as ft + +def main(page): + + page.adaptive = True + + page.appbar = ft.AppBar( + leading=ft.TextButton("New", style=ft.ButtonStyle(padding=0)), + title=ft.Text("Adaptive AppBar"), + actions=[ + ft.IconButton(ft.cupertino_icons.ADD, style=ft.ButtonStyle(padding=0)) + ], + bgcolor=ft.Colors.with_opacity(0.04, ft.CupertinoColors.SYSTEM_BACKGROUND), + ) + + page.navigation_bar = ft.NavigationBar( + destinations=[ + ft.NavigationBarDestination(icon=ft.Icons.EXPLORE, label="Explore"), + ft.NavigationBarDestination(icon=ft.Icons.COMMUTE, label="Commute"), + ft.NavigationBarDestination( + icon=ft.Icons.BOOKMARK_BORDER, + selected_icon=ft.Icons.BOOKMARK, + label="Bookmark", + ), + ], + border=ft.Border( + top=ft.BorderSide(color=ft.CupertinoColors.SYSTEM_GREY2, width=0) + ), + ) + + page.add( + ft.SafeArea( + ft.Column( + [ + ft.Checkbox(value=False, label="Dark Mode"), + ft.Text("First field:"), + ft.TextField(keyboard_type=ft.KeyboardType.TEXT), + ft.Text("Second field:"), + ft.TextField(keyboard_type=ft.KeyboardType.TEXT), + ft.Switch(label="A switch"), + ft.FilledButton(content=ft.Text("Adaptive button")), + ft.Text("Text line 1"), + ft.Text("Text line 2"), + ft.Text("Text line 3"), + ] + ) + ) + ) + +ft.run(main) +``` + +By setting just `page.adaptive = True` you can make your app look awesome on both iOS and Android devices: + +| iPhone | Android | +|:---:|:---:| +| | | + +## Material and Cupertino controls + +Most of Flet controls are based on [Material design](https://m3.material.io/). + +There is also a number of iOS-style controls in Flet that are called Cupertino controls. + +Cupertino controls usually have a matching Material control that has [`adaptive`](../controls/adaptivecontrol.md#flet.AdaptiveControl.adaptive) property +which defaults to`False`. When using a Material control with `adaptive` property set to `True`, +a different control will +be created depending on the platform, for example: +```python +ft.Checkbox(adaptive=True, value=True, label="Adaptive Checkbox") +``` + +Flet checks the value of [`Page.platform`](../controls/page.md#flet.Page.platform) property and if it is +`PagePlatform.IOS` or `ft.PagePlatform.MACOS`, Cupertino control will be created; +in all other cases Material control will be created. + +:::note[Note] +[`adaptive`](../controls/adaptivecontrol.md#flet.AdaptiveControl.adaptive) property can be set for an individual control or +a container-controls (ex: [`Row`](../controls/row.md), [`Column`](../controls/column.md)) that has children controls. +If a container-control is made adaptive, all its children will be adaptive too, +unless `adaptive` property is explicitly set to `False` for a child control. +::: + +
+Material vs Cupertino + +Below is the list of adaptive Material controls and their matching Cupertino controls: + +| Material | Cupertino | +|:---:|:---:| +| [`AlertDialog`](../controls/alertdialog.md) | [`CupertinoAlertDialog`](../controls/cupertinoalertdialog.md) | +| | | +| [`Dialog actions`](../controls/button.md) | [`CupertinoDialogAction`](../controls/cupertinodialogaction.md) | +| | | +| [`AppBar`](../controls/appbar.md) | [`CupertinoAppBar`](../controls/cupertinoappbar.md) | +| | | +| [`NavigationBar`](../controls/navigationbar/index.md) | [`CupertinoNavigationBar`](../controls/cupertinonavigationbar.md) | +| | | +| [`ListTile`](../controls/listtile.md) | [`CupertinoListTile`](../controls/cupertinolisttile.md) | +| | | +| [`TextField`](../controls/textfield.md) | [`CupertinoTextField`](../controls/cupertinotextfield.md) | +| | | +| [`Checkbox`](../controls/checkbox.md) | [`CupertinoCheckbox`](../controls/cupertinocheckbox.md) | +| | | +| [`Slider`](../controls/slider.md) | [`CupertinoSlider`](../controls/cupertinoslider.md) | +| | | +| [`Switch`](../controls/switch.md) | [`CupertinoSwitch`](../controls/cupertinoswitch.md) | +| | | +| [`Radio`](../controls/radio.md) | [`CupertinoRadio`](../controls/cupertinoradio.md) | +| | | +| [`FilledButton`](../controls/filledbutton.md) | [`CupertinoFilledButton`](../controls/cupertinofilledbutton.md) | +| | | +| [`FilledTonalButton`](../controls/filledtonalbutton.md) | [`CupertinoButton`](../controls/cupertinobutton.md) | +| | | +| [`IconButton`](../controls/iconbutton.md) | [`CupertinoButton`](../controls/cupertinobutton.md) | +| | | +| [`Button`](../controls/button.md) / [`OutlinedButton`](../controls/outlinedbutton.md) / [`TextButton`](../controls/textbutton.md) | [`CupertinoButton`](../controls/cupertinobutton.md) | +| | | + +
+ +## Custom adaptive controls + +While Flet offers a number of [controls](#material-and-cupertino-controls) that will be adapted to a platform + +automatically using their [`adaptive`](../controls/adaptivecontrol.md#flet.AdaptiveControl.adaptive) property, there will be +cases when you need more specific adaptive UI presentation, for example, using different +icon, background color, padding, etc., depending on the platform. + +With Flet, you can create your own reusable custom controls in Python that will inherit from a Flet control +and implement specific properties you need. + +In the example below, we are creating a new `AdaptiveNavigationBarDestination` +[custom control](custom-controls.md) that will be displaying different icon on iOS and Android, and use it +as destination for the [`NavigationBar`](../controls/navigationbar/index.md): + +```python +import flet as ft + +class AdaptiveNavigationBarDestination(ft.NavigationBarDestination): + def __init__(self, ios_icon, android_icon, label): + super().__init__() + self._ios_icon = ios_icon + self._android_icon = android_icon + self.label = label + + def build(self): + # we can check for platform in build method because self.page is known + self.icon = ( + self._ios_icon + if self.page.platform == ft.PagePlatform.IOS + or self.page.platform == ft.PagePlatform.MACOS + else self._android_icon + ) + +def main(page: ft.Page): + page.adaptive = True + + page.navigation_bar = ft.NavigationBar( + selected_index=2, + destinations=[ + AdaptiveNavigationBarDestination( + ios_icon=ft.cupertino_icons.PERSON_3_FILL, + android_icon=ft.Icons.PERSON, + label="Contacts", + ), + AdaptiveNavigationBarDestination( + ios_icon=ft.cupertino_icons.CHAT_BUBBLE_2, + android_icon=ft.Icons.CHAT, + label="Chats", + ), + AdaptiveNavigationBarDestination( + ios_icon=ft.cupertino_icons.SETTINGS, + android_icon=ft.Icons.SETTINGS, + label="Settings", + ), + ], + ) + + page.update() + +ft.run(main) +``` + +Now the `NavigationBar` and icons within it will look like different on Android and iOS: + +| iOS | Android | +|:---:|:---:| +| | | + +:::note[Note] +You may utilise [reusable controls approach](../cookbook/custom-controls.md) to +adapt your app not only depending on the [`Page.platform`](../controls/page.md#flet.Page.platform), +but also use [`Page.web`](../controls/page.md#flet.Page.web) property to have different UI depending on whether the +app is running in a browser or not, or even combine the usage of both properties to have specific +UI for your apps. +::: diff --git a/website/docs/cookbook/animations.md b/website/docs/cookbook/animations.md new file mode 100644 index 0000000000..b28e1dd14a --- /dev/null +++ b/website/docs/cookbook/animations.md @@ -0,0 +1,169 @@ +--- +title: "Animations" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +## Implicit animations + +With implicit animations, you can animate a control property by setting a target value; whenever that target +value changes, the control animates the property from the old value to the new one. + +Animation produces interpolated values between the old and the new value over the given *duration*. + +By default, the animation is *linearly* increasing the animation value, however, a *curve* can be +applied to the animation which changes the value according to the provided curve. +For example, [`AnimationCurve.EASE_OUT_CUBIC`](../types/animationcurve.md#flet.AnimationCurve.EASE_OUT_CUBIC) curve increases the animation value quickly at the +beginning of the animation and then slows down until the target value is reached: + + + +[`LayoutControl`](../controls/layoutcontrol.md) (and its subclasses) provides a number of `animate_{something}` +properties, described below, to enable implicit animation of its appearance: + +* `animate_opacity` +* `animate_rotation` +* `animate_scale` +* `animate_offset` +* `animate_position` +* `animate` (`Container`) + +`animate_*` properties could have one of the following values: + +* Instance of [`Animation`](../types/animation.md) - allows configuring the duration and the curve of the +* animation, for example `animate_rotation=Animation(duration=300, curve=AnimationCurve.BOUNCE_OUT)`. + See [this](https://api.flutter.dev/flutter/animation/Curves-class.html) Flutter docs on animation curves for possible values. Default is [`AnimationCurve.LINEAR`](../types/animationcurve.md#flet.AnimationCurve.LINEAR). +* `int` value - enables animation with specified duration in milliseconds and [`AnimationCurve.LINEAR`](../types/animationcurve.md#flet.AnimationCurve.LINEAR) curve. +* `bool` value - enables animation with the duration of 1000 milliseconds and [`AnimationCurve.LINEAR`](../types/animationcurve.md#flet.AnimationCurve.LINEAR) curve. + +### Opacity animation + +Setting control's `animate_opacity` to either `True`, number or an instance of `Animation` class (see above) +enables implicit animation of [`Control.opacity`](../controls/control.md#flet.Control.opacity) property. + + + +animate-opacity + +### Rotation animation + +Setting control's `animate_rotation` to either `True`, number or an instance of `Animation` class (see above) +enables implicit animation of [`LayoutControl.rotate`](../controls/layoutcontrol.md#flet.LayoutControl.rotate) property. + + + +animate-rotation + +### Scale animation + +Setting control's `animate_scale` to either `True`, number or an instance of `Animation` class (see above) +enables implicit animation of [`LayoutControl.scale`](../controls/layoutcontrol.md#flet.LayoutControl.scale) property. + + + +animate-scale + +### Offset animation + +Setting control's `animate_offset` to either `True`, number or an instance of `Animation` class (see above) +enables implicit animation of [`LayoutControl.offset`](../controls/layoutcontrol.md#flet.LayoutControl.offset) property. + +`offset` property is an instance of `Offset` class which specifies horizontal `x` and vertical `y` +offset of a control scaled to control's size. For example, an offset `Offset(-0.25, 0)` will result in +a horizontal translation of one quarter the width of the control. + +Offset animation is used for various sliding effects: + + + +animate-offset + +### Position animation + +Setting control's `animate_position` to either `True`, number or an instance of `Animation` class +(see above) enables implicit animation of the following `LayoutControl` properties: +[`left`](../controls/layoutcontrol.md#flet.LayoutControl.left), [`right`](../controls/layoutcontrol.md#flet.LayoutControl.right), +[`bottom`](../controls/layoutcontrol.md#flet.LayoutControl.bottom), [`top`](../controls/layoutcontrol.md#flet.LayoutControl.top). + +Note: + Positioning is effective only if the control is a descendant of one of the following: + + - [`Stack`](../controls/stack.md) control + - [`Page.overlay`](../controls/page.md) list + + + +animate-position + +### Animate + +Setting [`Container.animate`](../controls/container.md#flet.Container.animate) to [`AnimationValue`](../types/aliases.md#flet.AnimationValue) +enables implicit animation of container properties such as size, background color, border style, gradient. + + + +animate + +### Animated content switcher + +[`AnimatedSwitcher`](../controls/animatedswitcher.md) allows animated transition between two controls ('new' and 'old'). + +```python +import time + +import flet as ft + +def main(page: ft.Page): + i = ft.Image(src="https://picsum.photos/150/150", width=150, height=150) + + def animate(e): + sw.content = ft.Image( + src=f"https://picsum.photos/150/150?{time.time()}", width=150, height=150 + ) + page.update() + + sw = ft.AnimatedSwitcher( + i, + transition=ft.AnimatedSwitcherTransition.SCALE, + duration=500, + reverse_duration=500, + switch_in_curve=ft.AnimationCurve.BOUNCE_OUT, + switch_out_curve=ft.AnimationCurve.BOUNCE_IN, + ) + + page.add( + sw, + ft.Button("Animate!", on_click=animate), + ) + +ft.run(main) +``` + +animated-switcher + +### Animation end callback + +[`LayoutControl`](../controls/layoutcontrol.md) also has an +[`on_animation_end`](../controls/layoutcontrol.md#flet.LayoutControl.on_animation_end) event handler, which is called +when an animation is complete. It can be used to chain multiple animations. + +Event's [`data`](../types/event.md#flet.Event.data) field/property contains the name of animation: + +* `"opacity"` +* `"rotation"` +* `"scale"` +* `"offset"` +* `"position"` +* `"container"` + +For example: + +```python +ft.Container( + content=ft.Text("Animate me!"), + animate=ft.Animation(1000, ft.AnimationCurve.BOUNCE_OUT), + on_animation_end=lambda e: print("Container animation end:", e.data) +) +``` diff --git a/website/docs/cookbook/assets.md b/website/docs/cookbook/assets.md new file mode 100644 index 0000000000..cfd05cbabf --- /dev/null +++ b/website/docs/cookbook/assets.md @@ -0,0 +1,82 @@ +--- +title: "Assets" +--- + +Flet apps can include both code and assets/resources. +An asset is a file that is bundled and deployed with your app and is accessible at runtime. +Common types of assets include static data (e.g., JSON files), configuration files, icons, images, videos, etc. + +To use relative paths for your asset files, you need to provide a path to your assets directory +when launching your app with the `ft.run()` function. +The parameter for this is called `assets_dir`, which defaults to `"assets"`. +This parameter specifies the folder where local assets are stored and can be either an absolute +path or a path relative to the app's entry point file, such as `main.py`. + +## Example: Displaying a Local Image + +Suppose you have a folder named `assets` in the same directory as your `main.py` file, and +this folder contains an image file named `sample.png` in a subfolder called `images`: + +```tree +assets + images + sample.png +main.py +``` + +To display this image in your app, you can do the following: + +```python +import flet as ft + +def main(page: ft.Page): + page.add( + ft.Image(src="images/sample.png") + ) + +ft.run(main, assets_dir="assets") +``` + +The same approach applies to other asset types like fonts, Lottie animations, Rive files, etc. + +## Accessing Asset Files in Production + +For UI controls such as [`Image`](../controls/image.md), you usually pass a path relative to `assets_dir`: + +```python +ft.Image(src="images/sample.png") +``` + +For non-UI file operations (ex: reading JSON, opening a bundled SQLite database, loading ML models, etc.), +it is often more convenient to use an absolute path to your assets directory. +For this reason, Flet sets the [`FLET_ASSETS_DIR`](../reference/environment-variables.md#flet_assets_dir) +environment variable (in production apps built with [`flet build`](../publish/index.md),excluding `web`) +to an absolute path to your assets directory. + +You can use it with a local-development fallback, as shown in the below example (which assumes the asset folder is named `"assets"`): + +```python +import json +import os +from pathlib import Path + +import flet as ft + +def get_assets_dir() -> Path: + default_assets_dir = Path(__file__).parent / "assets" # fallback for local runs + return Path(os.environ.get("FLET_ASSETS_DIR", str(default_assets_dir))).resolve() + +def main(page: ft.Page): + assets_dir = get_assets_dir() + + # load a JSON file + with (assets_dir / "data" / "some_config.json").open() as f: + config = json.load(f) + + page.add(ft.Text(f"Loaded profile: {config['profile_name']}")) + +ft.run(main, assets_dir="assets") +``` + +This gives you a single way to resolve bundled files across local runs and production builds. +See [`FLET_ASSETS_DIR`](../reference/environment-variables.md#flet_assets_dir) for details. diff --git a/website/docs/cookbook/async-apps.md b/website/docs/cookbook/async-apps.md new file mode 100644 index 0000000000..593d078245 --- /dev/null +++ b/website/docs/cookbook/async-apps.md @@ -0,0 +1,122 @@ +--- +title: "Async apps" +--- + +Flet app can be written as an async app and use `asyncio` and other Python async libraries. Calling coroutines is +naturally supported in Flet, so you don't need to wrap them to run synchronously. + +By default, Flet executes control event handlers in separate threads, but sometimes that could be an ineffective +usage of CPU or it does nothing while waiting for a HTTP response or executing `sleep()`. + +Asyncio, on the other hand, allows implementing concurrency in a single thread by switching execution context +between "coroutines". This is especially important for apps that are going to be [published as static websites](../publish/web/static-website/index.md) using [Pyodide](https://pyodide.org/en/stable/). Pyodide is a Python runtime built as a WebAssembly (WASM) and running in the browser. At the time of writing it doesn't support [threading](https://github.com/pyodide/pyodide/issues/237) yet. + +## Getting started with async + +You could mark `main()` method of Flet app as `async` and then use any asyncio API inside it: + +```python +import flet as ft + +async def main(page: ft.Page): + await asyncio.sleep(1) + page.add(ft.Text("Hello, async world!")) + +ft.run(main) +``` + +You can use `await ft.run_async(main)` if Flet app is part of a larger app and called from `async` code. + +## Control event handlers + +Control event handlers could be both sync and `async`. + +If a handler does not call any async methods it could be a regular sync method: + +```python +def page_resize(e): + print("New page size:", page.window.width, page.window.height) + +page.on_resize = page_resize +``` + +However, if a handler calls async logic it must be async too: + +```python +async def main(page: ft.Page): + + async def button_click(e): + await some_async_method() + page.add(ft.Text("Hello!")) + + page.add(ft.Button("Say hello!", on_click=button_click)) + +ft.run(main) +``` + +### Async lambdas + +There are no async lambdas in Python. It's perfectly fine to have a lambda event handler in async app for simple things: + +```python +page.on_error = lambda e: print("Page error:", e.data) +``` + +but you can't have an async lambda, so an async event handler must be used. + +## Sleeping + +To delay code execution in async Flet app you should use [`asyncio.sleep()`](https://docs.python.org/3/library/asyncio-task.html#asyncio.sleep) instead of `time.sleep()`, for example: + +```python +import asyncio +import flet as ft + +def main(page: ft.Page): + async def button_click(e): + await asyncio.sleep(1) + page.add(ft.Text("Hello!")) + + page.add( + ft.Button("Say hello with delay!", on_click=button_click) + ) + +ft.run(main) +``` + +## Threading + +To run something in the background use [`page.run_task()`](../controls/page.md#flet.Page.run_task). For example, "Countdown" custom control +which is self-updating on background could be implemented as following: + +```python +import asyncio +import flet as ft + +class Countdown(ft.Text): + def __init__(self, seconds): + super().__init__() + self.seconds = seconds + + def did_mount(self): + self.running = True + self.page.run_task(self.update_timer) + + def will_unmount(self): + self.running = False + + async def update_timer(self): + while self.seconds and self.running: + mins, secs = divmod(self.seconds, 60) + self.value = "{:02d}:{:02d}".format(mins, secs) + self.update() + await asyncio.sleep(1) + self.seconds -= 1 + +def main(page: ft.Page): + page.add(Countdown(120), Countdown(60)) + +ft.run(main) +``` + + diff --git a/website/docs/cookbook/authentication.md b/website/docs/cookbook/authentication.md new file mode 100644 index 0000000000..29e73dd5bd --- /dev/null +++ b/website/docs/cookbook/authentication.md @@ -0,0 +1,459 @@ +--- +title: "Authentication" +--- + +import {Image} from '@site/src/components/crocodocs'; + +You can implement user authentication ("Login with X" buttons) in your Flet app using +3rd-party identity providers such as GitHub, Google, Azure, Auth0, LinkedIn and others. + +Identity provider must support [OAuth 2.0 Authorization Code Flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) to retrieve API access token. + +Built-in Flet login with credentials and user management is planned for future releases. +If you have a requirement to create and manage user accounts in your app you can implement it +by your own or use [Auth0](https://auth0.com/user-management) identity provider which provides +a generous free tier. + +Flet authentication features: + +* Works with Flet desktop, web and mobile apps. +* Using multiple authentication providers in one app. +* Built-in OAuth providers with automatic user details fetching: + * GitHub + * Azure + * Google + * Auth0 +* Optional groups fetching. +* Automatic token refresh. +* Login with a saved token ("Remember me"). +* Custom OAuth providers. + +## Login process overview + +* Configure OAuth provider (built-in or generic) with Client ID, Client secret, Redirect URL. +* Call `page.login(provider)` to initiate OAuth web flow. +* User is being redirected to OAuth provider website. +* On provider website user signs in and gives consent to access service API with requested scopes. +* Provider website redirects to Flet's OAuth callback URL with authorization code. +* Flet exchanges authorization code for a token and calls `page.on_login` event handler. +* Flet app can retrieve API token from `page.auth.token` property and user details from `page.auth.user`. + +## Configuring OAuth provider + +Flet has the following built-in OAuth providers: + +* GitHub +* Azure +* Google +* Auth0 + +Additionally, you can configure a generic OAuth provider and provide authorization, token and user info endpoints. + +In this guide we will configure Flet login page with GitHub account. + +To integrate Flet authentication with GitHub a new [GitHub OAuth app](https://github.com/settings/developers) should be registered first (**Profile settings** → **Developer settings** → **OAuth Apps**). + +**Authorization callback URL** should be in the format: + +``` +{application-url}/oauth_callback +``` + +GitHub new OAuth app + +On OAuth app details page click "Generate a new client secret" button. +Copy "Client ID" and "Client secret" values to a safe place - you'll need them in a Flet app. + +GitHub OAuth app details + +## Sign in with OAuth provider + +```python +import os + +import flet as ft +from flet.auth.providers import GitHubOAuthProvider + +GITHUB_CLIENT_ID = os.getenv("GITHUB_CLIENT_ID") +assert GITHUB_CLIENT_ID, "set GITHUB_CLIENT_ID environment variable" +GITHUB_CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET") +assert GITHUB_CLIENT_SECRET, "set GITHUB_CLIENT_SECRET environment variable" + +def main(page: ft.Page): + provider = GitHubOAuthProvider( + client_id=GITHUB_CLIENT_ID, + client_secret=GITHUB_CLIENT_SECRET, + redirect_url="http://localhost:8550/oauth_callback", + ) + + def login_click(e): + page.login(provider) + + def on_login(e): + print("Login error:", e.error) + print("Access token:", page.auth.token.access_token) + print("User ID:", page.auth.user.id) + + page.on_login = on_login + page.add(ft.Button("Login with GitHub", on_click=login_click)) + +ft.run(main, port=8550, view=ft.WEB_BROWSER) +``` + +:::danger[Caution] +Notice, we are fetching OAuth app client ID and client secret from an environment variables. +Do not embed any secrets into source code to avoid accidental exposure to a public! +::: + +Before running the app set the secret environment variables in a command line: + +``` +$ export GITHUB_CLIENT_ID="" +$ export GITHUB_CLIENT_SECRET="" +``` + +Run the program and click "Login with GitHub" button. GitHub authorize app page will be opened in: + +* **Desktop** app - a new browser window or tab. +* **Web** app - a new popup window (make sure popup blocker is off). +* **Mobile** app - an in-app web browser. + +GitHub OAuth authorize + +### Redirect URL + +We used `http://localhost:8550/oauth_callback` as a redirect URL while registering GitHub OAuth app. +Notice it has a fixed port `8550`. To run your Flet app on a fixed port use `port` argument in `flet.app` call: + +```python +ft.run(main, port=8550) +``` + +### Scope + +Most of OAuth providers allows applications to request one or more scopes to limit application's access to a +user's account. + +Built-in Flet providers, by default, request scopes to access user profile, but you can request additional scopes in login method, like `public_repo` in the example above: + +```python +page.login( + provider, + scope=["public_repo"] +) +``` + +`page.login()` method has a number of arguments to control authentication process: + +* `fetch_user` (bool) - whether to fetch user details into `page.auth.user`. Default is `True`. +* `fetch_groups` (bool) - whether to fetch user groups into `page.auth.user.groups`. Default is `False`. +* `scope` - a list of scopes to request. +* `saved_token` - a JSON snapshot of `page.auth.token` to restore authorization from. Token can be serialized with `page.auth.token.to_json()`, encrypted and saved in [`page.client_storage`](../cookbook/client-storage.md). See below. +* `on_open_authorization_url` - a callback to open a browser with authorization URL. See below. +* `complete_page_html` - a custom HTML contents of "You've been successfully authenticated. Close this page now" page. +* `redirect_to_page` (bool) - used with Flet web app only when authorization page is opened in the same browser tab. + +The result of `page.login()` call is an instance of `Authorization` class with the following fields: + +* **`token`** - OAuth token used to access provider's API. See below. +* **`user`** - user details with a mandatory `id` field and other fields specific to OAuth provider. +* **`provider`** - an instance of OAuth provider used for authorization. + +A reference to the last authorization is saved in `page.auth` property. + +If your app allows authorizations with multiple OAuth providers you can save authorizations in a session, +for example: + +```python +page.session["github_auth"] = page.login(github_provider) +page.session["google_auth"] = page.login(google_provider) +``` + +### Checking authentication results + +Upon successful or failed authorization `page.on_login` event handler is called. + +Event handler argument `e` is an instance of `LoginEvent` class with the following properties: + +* `error` (str) - OAuth error. +* `error_description` (str) - OAuth error description. + +Authorization was successful if `error` is an empty string. + +You can use this event handler to toggle signed in/out UI, for example: + +```python +import os + +import flet as ft +from flet.auth.providers import GitHubOAuthProvider + +def main(page: ft.Page): + provider = GitHubOAuthProvider( + client_id=os.getenv("GITHUB_CLIENT_ID"), + client_secret=os.getenv("GITHUB_CLIENT_SECRET"), + redirect_url="http://localhost:8550/oauth_callback", + ) + + def login_button_click(e): + page.login(provider, scope=["public_repo"]) + + def on_login(e: ft.LoginEvent): + if not e.error: + toggle_login_buttons() + + def logout_button_click(e): + page.logout() + + def on_logout(e): + toggle_login_buttons() + + def toggle_login_buttons(): + login_button.visible = page.auth is None + logout_button.visible = page.auth is not None + page.update() + + login_button = ft.Button("Login with GitHub", on_click=login_button_click) + logout_button = ft.Button("Logout", on_click=logout_button_click) + toggle_login_buttons() + + page.on_login = on_login + page.on_logout = on_logout + + page.add(login_button, logout_button) + +ft.run(main, port=8550, view=ft.AppView.WEB_BROWSER) +``` + +## Accessing user details + +If `page.login()` method is called with `fetch_user=True` (default) a user profile will +be assigned to `page.auth.user`. + +All built-in OAuth providers implement `user.id` property - unique user identifier - which value depends +on the provider (a number, Guid or email) and can be used in your app as a user key. + +The rest of user profile properties depends on provider and can be accessed with an indexer. +For example, to print some properties of GitHub user: + +```python +print("Name:", page.auth.user["name"]) +print("Login:", page.auth.user["login"]) +print("Email:", page.auth.user["email"]) +``` + +## Using OAuth token + +Upon successful authorization `page.auth.token` will contain OAuth token that can be used to access providers's API. Token object has the following properties: + +* `access_token` - access token used as an authorization token in API request header. +* `scope` - token's scope. +* `token_type` - access token type, e.g. `Bearer`. +* `expires_in` - optional number of seconds when access token expires. +* `expires_at` - optional time (`time.time()` + `expires_in`) when access token expires. +* `refresh_token` - optional refresh token which is used to get a new access token, when the old one expires. + +Usually, only `page.auth.token.access_token` is needed to call provider's API, +for example to list user's GitHub repositories: + +```python +import requests +headers = {"Authorization": "Bearer {}".format(page.auth.token.access_token)} +repos_resp = requests.get("https://api.github.com/user/repos", headers=headers) +user_repos = json.loads(repos_resp.text) +for repo in user_repos: + print(repo["full_name"]) +``` + +:::note +Do not save a reference to `page.auth.token` somewhere in your code, but rather call `page.auth.token` +every time you need to grab access token. `page.auth.token` is a property which automatically refreshes +OAuth token if/when it expires. + +Correct code: + +```python +access_token = page.auth.token.access_token +``` + +Wrong code: + +```python +token = page.auth.token +# some other code +access_token = token.access_token # token could expire by this moment +``` +::: + +## Saving and restoring an auth token + +To implement persistent login ("Remember me" checkbox on login page) you can save auth token in a [client storage](../cookbook/client-storage.md) and use it to login next time a user opens your Flet app. + +To serialize auth token to JSON: + +```python +jt = page.auth.token.to_json() +``` + +:::caution +Encrypt sensitive data before sending it to a client storage. +::: + +Flet includes utility methods for encrypting text data using symmetric algorithm (where the same key is used for encryption and decryption). They use [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) implementation from [cryptography](https://pypi.org/project/cryptography/) package, which is AES 128 with some additional hardening, plus PBKDF2 to derive encryption key from a user passphrase. + +To encrypt JSON token: + +```python +import os +from flet.security import encrypt, decrypt + +secret_key = os.getenv("MY_APP_SECRET_KEY") +# returns base64-encoded string +ejt = encrypt(jt, secret_key) +``` + +:::caution +Notice, we are fetching a secret key (aka passphrase, password, etc.) from an environment variable. +Do not embed any secrets into source code to avoid accidental exposure to a public! +::: + +Before running the app set the secret in a command line: + +``` +$ export MY_APP_SECRET_KEY="" +``` + +Now, encrypted value can be stored in a client storage: + +```python +await page.shared_preferences.set("myapp.auth_token", ejt) +``` + +Next time a user opens the app you can read encrypted token from a client storage and, if it exists, +decrypt it and use in `page.login()` method: + +```python +ejt = await page.shared_preferences.get("myapp.auth_token") +if ejt: + jt = decrypt(ejt, secret_key) + page.login(provider, saved_token=jt) +``` + +[See complete app example](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/authentication/github_repos_browser/main.py). + +## Signing out + +Calling `page.logout()` resets `page.auth` reference and triggers `page.on_logout` event handlers. + +You can remove saved token in logout method, for example: + +```python +async def logout_button_click(e): + await page.shared_preferences.remove(AUTH_TOKEN_KEY) + page.logout() +``` + +[See complete app example](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/authentication/github_repos_browser/main.py). + +## Customizing authorization flow + +By default, OAuth authorization flow is happening in either new browser window/tab (desktop app), browser popup window (web) or in-app web view (mobile). + +Upon completion of authorization flow a user is redirected to Flet's OAuth callback page (`/oauth_callback`) which tries to close a browser window/tab with JavaScript and provides user with instructions to close the window manually if JavaScript close didn't work. + +This section is applicable to Flet desktop and web apps only as in-app web view in mobile apps can be closed by Flet without relying on JavaScript. + +You can customize the contents of "Authorization complete" page in `page.login()` method, for example: + +```python +complete_page_html = """ + + + + Signed in to MyApp + + + +

You've been successfully signed in! You can close this tab or window now.

+ + +""" + +page.login( + provider, + complete_page_html=complete_page_html, +) +``` + +You can also change web app to open provider's authorization page in the same tab which might be more familiar to your users and save them from dealing with popup blockers: + +```python +page.login( + provider, + on_open_authorization_url=lambda url: asyncio.create_task(page.launch_url(url, web_window_name="_self")), + redirect_to_page=True +) +``` + +To open flow in a new tab (notice `_self` replaced with `_blank`): + +```python +page.login( + provider, + on_open_authorization_url=lambda url: asyncio.create_task(page.launch_url(url, web_window_name="_blank")) +) +``` + +## Configuring a custom OAuth provider + +You can configure any OAuth-compatible authentication provider in your app with `flet.auth.oauth_provider.OAuthProvider` class. + +Following the instructions in [LinkedIn Authorization Code Flow guide](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow?context=linkedin%2Fcontext&tabs=HTTPS) we are able +to get all required parameters to configure LinkedIn OAuth provider to allow users of your Flet app to login +with their LinkedIn accounts: + +```python {9-16} +import os + +import flet +from flet import Button, Page +from flet.auth import OAuthProvider + +def main(page: Page): + provider = OAuthProvider( + client_id=os.getenv("LINKEDIN_CLIENT_ID"), + client_secret=os.getenv("LINKEDIN_CLIENT_SECRET"), + authorization_endpoint="https://www.linkedin.com/oauth/v2/authorization", + token_endpoint="https://www.linkedin.com/oauth/v2/accessToken", + user_endpoint="https://api.linkedin.com/v2/me", + user_scopes=["r_liteprofile", "r_emailaddress"], + user_id_fn=lambda u: u["id"], + redirect_url="http://localhost:8550/oauth_callback", + ) + + def login_click(e): + page.login(provider) + + def on_login(e): + if e.error: + raise RuntimeError(e.error) + print("User ID:", page.auth.user.id) + print("Access token:", page.auth.token.access_token) + + page.on_login = on_login + page.add(Button("Login with LinkedIn", on_click=login_click)) + +flet.app(main, port=8550, view=flet.WEB_BROWSER) +``` + +Mandatory provider settings: + +* `client_id` +* `client_secret` +* `authorization_endpoint` +* `token_endpoint` +* `redirect_url` + +Similar to other examples client ID and client secret are fetched from environment variables. diff --git a/website/docs/cookbook/client-storage.md b/website/docs/cookbook/client-storage.md new file mode 100644 index 0000000000..61dff6215b --- /dev/null +++ b/website/docs/cookbook/client-storage.md @@ -0,0 +1,69 @@ +--- +title: "Client Storage" +--- + +Flet's client storage API allows storing key-value data on a client side in a persistent storage. +Flet implementation uses [`shared_preferences`](https://pub.dev/packages/shared_preferences) Flutter package. + +The actual storage mechanism depends on a platform where Flet app is running: + +* Web - [Local storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage). +* Desktop - JSON file. +* iOS - [NSUserDefaults](https://developer.apple.com/documentation/foundation/nsuserdefaults). +* Android - [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences). + +Writing data to the storage: +```python +# strings +await page.shared_preferences.set("key", "value") + +# numbers, booleans +await page.shared_preferences.set("number.setting", 12345) +await page.shared_preferences.set("bool_setting", True) + +# lists +await page.shared_preferences.set("favorite_colors", ["red", "green", "blue"]) +``` + +:::note +Each Flutter application using `shared_preferences` plugin has its own set of preferences. As the same Flet client (which is a Flutter app) is used to run UI for multiple Flet apps any values stored in one Flet application are visible/available to another Flet app running by the same user. + +To distinguish one application settings from another it is recommended to use some unique prefix for all storage keys, for example `{company}.{product}.`. For example to store auth token in one app you could use `acme.one_app.auth_token` key and in another app use `acme.second_app.auth_token`. +::: + +:::caution[Caution] +It is responsibility of Flet app developer to encrypt sensitive data before sending it to a client storage, so it's not read/tampered by another app or an app user. +::: + +Reading data: +```python +# The value is automatically converted back to the original type +value = await page.shared_preferences.get("key") + +colors = await page.shared_preferences.get("favorite_colors") +# colors = ["red", "green", "blue"] +``` + +Check if a key exists: +```python +await page.shared_preferences.contains_key("key") # True if the key exists +``` + +Get all keys: +```python +await page.shared_preferences.get_keys("key-prefix.") +``` + +Remove a value: +```python +await page.shared_preferences.remove("key") +``` + +Clear the storage: +```python +await page.shared_preferences.clear() +``` + +:::caution[Caution] +`clear()` is a dangerous function that removes all preferences of all Flet apps ever run by the same user and serves as a heads-up that permanent application data shouldn't be stored in the client storage. +::: diff --git a/website/docs/cookbook/colors.md b/website/docs/cookbook/colors.md new file mode 100644 index 0000000000..100192f95c --- /dev/null +++ b/website/docs/cookbook/colors.md @@ -0,0 +1,180 @@ +--- +title: "Working with Colors" +--- + + + +Flet supports two primary ways of defining colors: + +1. Hexadecimal values +2. Named colors + +## Hexadecimal Values + +Hex color values follow either of these formats: + +* `#aarrggbb` or `0xaarrggbb` +* `#rrggbb` or `0xrrggbb` (opacity defaults to `ff` if `aa` is omitted) + +```python-repl +>>> ft.Container(bgcolor="#ff0000") +``` + +[Live example](https://flet-controls-gallery.fly.dev/colors/controlcolors) + +## Named Color + +Flet uses Material Design [theme colors](https://m3.material.io/styles/color-the-color-system/color-roles) +and [color palettes](https://m2.material.io/design/color/the-color-system.html#color-usage-and-palettes). + +You can define named colors in two ways: + +* As a **string** (e.g., `"blue"`, `"redAccent100"`) +* Using the `Colors` or `CupertinoColors` **enums** for better type safety and autocompletion + +```python-repl +>>> ft.Container(bgcolor="yellow") +>>> ft.Container(bgcolor=ft.Colors.YELLOW) +>>> ft.Container(bgcolor=ft.CupertinoColors.DESTRUCTIVE_RED) +``` + +### Theme Colors + + + +[Live Example](https://flet-controls-gallery.fly.dev/colors/themecolors) + +There are 30 named theme colors in [`Theme.color_scheme`](../types/theme/index.md#flet.Theme.color_scheme) that are generated based on +the [`Theme.color_scheme_seed`](../types/theme/index.md#flet.Theme.color_scheme_seed), which defaults to [`Colors.BLUE`](../types/colors.md#flet.Colors.BLUE). + +```python-repl +>>> page.theme = ft.Theme(color_scheme_seed=ft.Colors.GREEN) +``` + +Any of the 30 theme scheme colors can be overridden, in which case they will have an absolute value +that will no longer be dependent on the seed color. + +```python +page.theme = ft.Theme( + color_scheme=ft.ColorScheme( + primary=ft.Colors.GREEN, + error=ft.Colors.RED, + ), +) +``` + + + +Theme colors serve as fallback values for most Flet controls. + +### Color Palettes + + + +[Live example](https://flet-controls-gallery.fly.dev/colors/colorspalettes) + +Originally introduced by Material Design in 2014, **color palettes** are collections of coordinated +colors designed to work together harmoniously. + +Each **color swatch** (palette) includes multiple shades of a specific color, where lower numbers +represent lighter shades and higher numbers represent darker ones. +Most palettes range from `50` to `900`, in increments of `100`, while **accent swatches** +(e.g., [`Colors.RED_ACCENT`](../types/colors.md#flet.Colors.RED_ACCENT)) have only `100`, `200`, `400`, and `700`. + +In addition to color swatches, Flet provides named black and white variants with built-in opacities, such as: +- [`Colors.BLACK_54`](../types/colors.md#flet.Colors.BLACK_54) → black at 54% opacity +- [`Colors.WHITE_70`](../types/colors.md#flet.Colors.WHITE_70) → white at 70% opacity + +These palette colors can be used: +- directly as values for control color properties (e.g., `bgcolor`, `color`) +- as seed colors for generating dynamic theme color schemes using [`Theme.color_scheme_seed`](../types/theme/index.md#flet.Theme.color_scheme_seed) + +### Color opacity + +Flet provides multiple ways to set opacity: + +#### Using `with_opacity` + +This method is present in both [`Colors`](../types/colors.md) and [`CupertinoColors`](../types/cupertinocolors.md) enums. +It takes a [color](#) and an opacity, and returns a string in the format `"color,opacity"`, understood by Flet. + +```python-repl +>>> ft.Colors.with_opacity(0.5, ft.Colors.RED) +"red,0.5" +>>> ft.CupertinoColors.with_opacity(0.8, ft.CupertinoColors.LINK) +"link,0.8" +``` + +#### Embedding Opacity in Hex Code + +For colors in hex format, you can specify the `aa` channel with values between `00` and `ff`. + +```python-repl +>>> "#7fff6666" # (1)! +``` + +1. Red color at 50% opacity (`7f`). + +## Defining colors for Flet controls + +Most Flet controls have default colors defined by the [`Theme.color_scheme`](../types/theme/index.md#flet.Theme.color_scheme), +and these can be overridden at various levels. + +[Live example](https://flet-controls-gallery.fly.dev/colors/controlcolors) + + + +### Control Level + +If a color is provided as value for a control's color-like property, it will be used directly. + +```python +>>> ft.Card(bgcolor=ft.Colors.GREEN_200) +``` + +Note: + Not every Flet control has a color property that can be set on the control level. + For example, [`FilledButton`](../controls/filledbutton.md) always has a default "primary" color + that is defined by the nearest ancestor's `theme`. + +### Control Theme Level + +The [`Theme`](../types/theme/index.md) object has a lot of properties that can be used to override default +colors for Flet controls. + +For example, the nearest [`Theme.card_bgcolor`](../types/theme/index.md#flet.Theme.card_bgcolor) will be used for the +[`Card`](../controls/card.md) control. + +Note: + If you need to change theme for particular descendants, you can wrap + them in a [`Container`](../controls/container.md), for example, and customize its + [`theme`](../controls/container.md#flet.Container.theme) property, which will be applied to + all its descendants. + +### Ancestor Theme Level + +Flet searches upward in the widget tree to find the nearest ancestor with a defined `theme`, and will take color +from its [`Theme.color_scheme`](../types/theme/index.md#flet.Theme.color_scheme). In the example below, the nearest ancestor for the [`FilledButton`](../controls/filledbutton.md) +is [`Container`](../controls/container.md), and the `primary` color that is used for the button will be taken from the +[`Container.theme`](../controls/container.md#flet.Container.theme). + +```python +import flet as ft + +def main(page: ft.Page): + page.add( + ft.Container( + width=200, + height=200, + border=ft.Border.all(1, ft.Colors.BLACK), + content=ft.FilledButton("Primary color"), + theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.YELLOW)) + ) + ) + +ft.run(main) +``` + +If no theme is defined for a control, its parent, or its parent’s ancestors, the control defaults to +using the uppermost ancestor's theme, which is [`Page.theme`](../controls/page.md) +(or [`Page.dark_theme`](../controls/page.md) in dark mode). diff --git a/website/docs/cookbook/control-refs.md b/website/docs/cookbook/control-refs.md new file mode 100644 index 0000000000..d503cf7cd4 --- /dev/null +++ b/website/docs/cookbook/control-refs.md @@ -0,0 +1,115 @@ +--- +title: "Control Refs" +--- + +Flet controls are objects and to access their properties we need to keep references (variables) to those objects. + +Consider the following example: + +```python {6-8,18,19,21} +import flet as ft + +def main(page): + first_name = ft.TextField(label="First name", autofocus=True) + last_name = ft.TextField(label="Last name") + greetings = ft.Column() + + async def btn_click(e): + greetings.controls.append(ft.Text(f"Hello, {first_name.value} {last_name.value}!")) + first_name.value = "" + last_name.value = "" + page.update() + await first_name.focus() + + page.add( + first_name, + last_name, + ft.Button("Say hello!", on_click=btn_click), + greetings, + ) + +ft.run(main) +``` + +In the very beginning of `main()` method we create three controls which we are going to use in button's +`on_click` handler: two `TextField` for first and last names and a `Column` - container for greeting messages. +We create controls with all their properties set and in the end of `main()` method, in `page.add()` call, +we use their references (variables). + +When more and more controls and event handlers are added it becomes challenging to keep all control +definitions in one place, so they become scattered across `main()` body. Glancing at `page.add()` parameters it's +hard to imagine (without constant jumping to variable definitions in IDE) what would the end form look like: + +```python {2-5} + page.add( + first_name, + last_name, + ft.Button("Say hello!", on_click=btn_click), + greetings, + ) +``` + +Is `first_name` a TextField, does it have autofocus set? Is greetings a `Row` or a `Column`? + +## `Ref` class + +Flet provides `Ref` utility class which allows to define a reference to the control, use that reference in event handlers and set the reference to a real control later, while building a tree. The idea comes from [React](https://reactjs.org/docs/refs-and-the-dom.html). + +To define a new typed control reference: + +```python +first_name = ft.Ref[ft.TextField]() +``` + +To access referenced control (control de-reference) use `Ref.current` property: + +```python +# empty first name +first_name.current.value = "" +``` + +To assign control to a reference set `Control.ref` property to a reference: + +```python {2} +page.add( + ft.TextField(ref=first_name, label="First name", autofocus=True) +) +``` + +:::note +All Flet controls have `ref` property. +::: + +We could re-write our program to use references: + +```python {7-9,21-24} +import flet as ft + +def main(page): + + first_name = ft.Ref[ft.TextField]() + last_name = ft.Ref[ft.TextField]() + greetings = ft.Ref[ft.Column]() + + async def btn_click(e): + greetings.current.controls.append( + ft.Text(f"Hello, {first_name.current.value} {last_name.current.value}!") + ) + first_name.current.value = "" + last_name.current.value = "" + page.update() + await first_name.current.focus() + + page.add( + ft.TextField(ref=first_name, label="First name", autofocus=True), + ft.TextField(ref=last_name, label="Last name"), + ft.Button("Say hello!", on_click=btn_click), + ft.Column(ref=greetings), + ) + +ft.run(main) +``` + +Now we can clearly see in `page.add()` the structure of the page and all the controls it's built of. + +Yes, the logic becomes a little bit more verbose as you need to add `.current.` to access ref's control, but it's a matter of personal preference :) diff --git a/website/docs/cookbook/custom-controls.md b/website/docs/cookbook/custom-controls.md new file mode 100644 index 0000000000..36089a5783 --- /dev/null +++ b/website/docs/cookbook/custom-controls.md @@ -0,0 +1,199 @@ +--- +title: "Custom Controls" +--- + +import {Image} from '@site/src/components/crocodocs'; + +While Flet provides 140+ built-in controls that can be used on their own, the real beauty of programming with Flet is that all those controls can be utilized for creating your own reusable UI components using Python object-oriented programming concepts. + +You can create custom controls in Python by styling and/or combining existing Flet controls. + +## Styled controls + +The most simple custom control you can create is a styled control, for example, a button of a certain color and behaviour that will be used multiple times throughout your app. + +To create a styled control, you need to create a new dataclass in Python that inherits from the Flet control you are going to customize, `Button` in this case: + +```python +@ft.control +class MyButton(ft.Button): + bgcolor: ft.Colors = ft.Colors.ORANGE_300 + color: ft.Colors = ft.Colors.GREEN_800 + style: ft.ButtonStyle = field( + default_factory=lambda: ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10) + ) + ) + expand: int = 1 +``` + +You can define either `@dataclass` or `@ft.control` decorator on the inherited class - both methods works the same: + +```python +@dataclass +class MyButton(ft.Button): + bgcolor: ft.Colors = ft.Colors.ORANGE_300 + color: ft.Colors = ft.Colors.GREEN_800 + style: ft.ButtonStyle = field( + default_factory=lambda: ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10) + ) + ) + expand: int = 1 +``` + +You can also set properties in `init()` method: +```python +@ft.control +class MyButton(ft.Button): + def init(self): + self.bgcolor = ft.Colors.ORANGE_300 + self.color = ft.Colors.GREEN_800 + self.style = ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10) + ) + self.expand = 1 +``` + +:::note[Rules] + +* You should define either @dataclass or @ft.control decorator on the inherited class - both methods works the same. + +* A field, to be a class field, must have a type annotation, so `expand: int = 1` will override inherited property, but `expand = 1` won't. Not sure which type to use? Just `Any` will work, for example `expand: Any = 1`. + +* Use literal default value for simple data types, such as `int`, `bool`, `str` and `field(default_factory=lambda: )` for immutable types such as `class`, `list`, `dict`. + +* You can set property values in `init()` method, but you won't be able to override if write `MyButton3(expand=False)`. +::: + +Now you can use your brand-new control in your app: + +```python +import flet as ft + +@ft.control +class MyButton(ft.Button): + bgcolor: ft.Colors = ft.Colors.ORANGE_300 + color: ft.Colors = ft.Colors.GREEN_800 + +def main(page: ft.Page): + def ok_clicked(e): + print("OK clicked") + + def cancel_clicked(e): + print("Cancel clicked") + + page.add( + MyButton(content="OK", on_click=ok_clicked), + MyButton(content="Cancel", on_click=cancel_clicked), + ) + +ft.run(main) +``` + +Styled controls + +See example of using styled controls in [Calculator App tutorial](../tutorials/calculator.md#styled-controls). + +## Composite controls + +Composite custom controls inherit from container controls such as `Column`, `Row`, `Stack` or even `View` to combine multiple Flet controls. The example below is a `Task` control that can be used in a To-Do app: + +```python +import flet as ft + +@ft.control +class Task(ft.Row): + text: str = "" + + def init(self): + self.text_view = ft.Text(value=self.text) + self.text_edit = ft.TextField(value=self.text, visible=False) + self.edit_button = ft.IconButton(icon=ft.Icons.EDIT, on_click=self.edit) + self.save_button = ft.IconButton( + visible=False, icon=ft.Icons.SAVE, on_click=self.save + ) + self.controls = [ + ft.Checkbox(), + self.text_view, + self.text_edit, + self.edit_button, + self.save_button, + ] + + def edit(self, e): + self.edit_button.visible = False + self.save_button.visible = True + self.text_view.visible = False + self.text_edit.visible = True + self.update() + + def save(self, e): + self.edit_button.visible = True + self.save_button.visible = False + self.text_view.visible = True + self.text_edit.visible = False + self.text_view.value = self.text_edit.value + self.update() + +def main(page: ft.Page): + page.add( + Task(text="Do laundry"), + Task(text="Cook dinner"), + ) + +ft.run(main) +``` + +Composite controls + +## Life-cycle methods + +Custom controls provide life-cycle "hook" methods that you may need to use for different use cases in your app. + +### `build()` + +`build()` method is called when the control is being created and assigned its `self.page`. + +Override `build()` method if you need to implement logic that cannot be executed in control's constructor because +it requires access to the `self.page`. For example, choose the right icon depending on `self.page.platform` +for your [adaptive app](adaptive-apps.md#custom-adaptive-controls). + +### `did_mount()` + +`did_mount()` method is called after the control is added to the page and assigned transient `uid`. + +Override `did_mount()` method if you need to implement logic that needs to be executed after the control +was added to the page, for example [Weather widget](https://github.com/flet-dev/examples/tree/main/python/community/weather_widget) +which calls Open Weather API every minute to update itself with the new weather conditions. + +### `will_unmount()` + +`will_unmount()` method is called before the control is removed from the page. + +Override `will_unmount()` method to execute clean-up code. + +### `before_update()` + +`before_update()` method is called every time when the control is being updated. + +Make sure not to call `update()` method within `before_update()`. + +## Isolated controls + +Custom control has `is_isolated` property which defaults to `False`. + +If you set `is_isolated` to `True`, your control will be isolated from outside layout, i.e. when `update()` method is called for the parent control, the control itself will be updated but any changes to the controls' children are not included into the update digest. Isolated controls should call `self.update()` to push its changes to a Flet page. + +As a best practice, any custom control that calls `self.update()` inside its class methods should be isolated. + +In the above examples, simple styled `MyButton` doesn't need to be isolated, but the `Task` should be: + +```python +class Task(ft.Row): + def __init__(self, text): + super().__init__() + + def is_isolated(self): + return True +``` diff --git a/website/docs/cookbook/declarative-dialogs.md b/website/docs/cookbook/declarative-dialogs.md new file mode 100644 index 0000000000..852bc307df --- /dev/null +++ b/website/docs/cookbook/declarative-dialogs.md @@ -0,0 +1,202 @@ +--- +title: "Declarative dialogs" +--- + +[`ft.use_dialog()`](../types/usedialog.md) lets a component show and update dialogs declaratively. +Instead of imperatively calling [`page.show_dialog()`](../controls/page.md#flet.Page.show_dialog) and later +remembering to close or remove the dialog, you render a [`DialogControl`](../controls/dialogcontrol.md) +from component state: + +- pass a dialog instance to show it; +- pass `None` to hide it. + +This keeps dialog logic in the same state flow as the rest of a declarative app: + +- state decides whether the dialog is visible; +- dialog content updates when state changes; +- there is no [`page.update()`](../controls/page.md#flet.Page.update) call in the component. + +## Basic pattern + +Call [`ft.use_dialog()`](../types/usedialog.md) on every render. When the dialog should be open, +return a dialog control; otherwise return `None`. + +```python +import flet as ft + + +@ft.component +def App(): + show, set_show = ft.use_state(False) + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete report.pdf?"), + content=ft.Text("This cannot be undone."), + actions=[ + ft.TextButton("Delete", on_click=lambda: set_show(False)), + ft.TextButton("Cancel", on_click=lambda: set_show(False)), + ], + on_dismiss=lambda: set_show(False), + ) + if show + else None + ) + + return ft.Column( + controls=[ + ft.TextButton("Open dialog", on_click=lambda: set_show(True)), + ] + ) + + +ft.run(lambda page: page.render(App)) +``` + +The important part is that `show` is the source of truth. The dialog is not opened by +mutating the page tree directly; it appears because the component renders it. + +## Updating dialog content from state + +Because the dialog is declarative, its content can react to state changes while it is open. +This is useful for confirmations, form validation, and async workflows: + +```python +import asyncio +import flet as ft + + +@ft.component +def App(): + show, set_show = ft.use_state(False) + deleting, set_deleting = ft.use_state(False) + + async def handle_delete(): + set_deleting(True) + await asyncio.sleep(2) + set_deleting(False) + set_show(False) + + ft.use_dialog( + ft.AlertDialog( + modal=True, + title=ft.Text("Delete report.pdf?"), + content=ft.Text( + "Deleting, please wait..." if deleting else "This cannot be undone." + ), + actions=[ + ft.Button( + "Deleting..." if deleting else "Delete", + disabled=deleting, + on_click=handle_delete, + ), + ft.TextButton( + "Cancel", + disabled=deleting, + on_click=lambda: set_show(False), + ), + ], + on_dismiss=lambda: set_show(False), + ) + if show + else None + ) + + return ft.TextButton("Delete file", on_click=lambda: set_show(True)) + +ft.run(lambda page: page.render(App)) +``` + +This pattern works well with `asyncio` and other async APIs in Flet apps. For more +background, see [Async apps](async-apps.md). + +## Chaining dialogs + +You can call [`ft.use_dialog()`](../types/usedialog.md) more than once in the same component. That +makes follow-up flows straightforward, for example: + +- confirmation dialog; +- async action; +- success dialog after the first dialog fully closes. + +```python +import flet as ft + + +@ft.component +def App(): + show_confirm, set_show_confirm = ft.use_state(False) + show_success, set_show_success = ft.use_state(False) + should_chain = ft.use_ref(False) + + def confirm_delete(): + should_chain.current = True + set_show_confirm(False) + + def on_confirm_dismiss(): + if should_chain.current: + should_chain.current = False + set_show_success(True) + + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("Delete file?"), + actions=[ + ft.TextButton("Delete", on_click=confirm_delete), + ft.TextButton("Cancel", on_click=lambda: set_show_confirm(False)), + ], + on_dismiss=on_confirm_dismiss, + ) + if show_confirm + else None + ) + + ft.use_dialog( + ft.AlertDialog( + title=ft.Text("Done"), + content=ft.Text("The file was deleted."), + actions=[ + ft.TextButton("OK", on_click=lambda: set_show_success(False)), + ], + ) + if show_success + else None + ) + + return ft.TextButton("Open", on_click=lambda: set_show_confirm(True)) + +ft.run(lambda page: page.render(App)) +``` + +[`ft.use_ref()`](../types/useref.md) is helpful here because the value survives re-renders without +causing another render by itself. + +## `on_dismiss` timing + +[`DialogControl.on_dismiss`](../controls/dialogcontrol.md#flet.DialogControl.on_dismiss) fires after the dialog close +animation completes, not immediately when `open` changes to `False`. This makes it safe to +start follow-up UI after the dialog has actually finished closing. + +Use `on_dismiss` for logic that should happen after the dialog is fully gone, such as: + +- opening the next dialog in a chain; +- resetting temporary dialog-local state; +- starting a follow-up animation or toast. + +## When to use `page.show_dialog()` instead + +[`ft.use_dialog()`](../types/usedialog.md) is a better fit inside [`@ft.component`](../types/component.md) +functions and other declarative flows. + +[`page.show_dialog()`](../controls/page.md#flet.Page.show_dialog) is still a good option when: + +- the app is written imperatively; +- dialog lifecycle is handled outside the component tree; +- you need to trigger a dialog from existing page-level event code and do not want to convert + that part of the app to declarative style yet. + +In practice, the two APIs serve different styles: + +- use declarative dialogs when UI should follow component state; +- use imperative dialogs when UI is managed by direct page mutation. diff --git a/website/docs/cookbook/declarative-vs-imperative-crud-app.md b/website/docs/cookbook/declarative-vs-imperative-crud-app.md new file mode 100644 index 0000000000..956d27c2b4 --- /dev/null +++ b/website/docs/cookbook/declarative-vs-imperative-crud-app.md @@ -0,0 +1,384 @@ +--- +title: "Declarative vs Imperative CRUD app" +--- + +# From Imperative to Declarative in Flet: Migrating a Simple CRUD “User Manager” + +If you’ve been using Flet, you’ve probably built your apps the imperative way, maybe without even noticing. You flip visibility flags, set control values, update lists of controls and call `page.update()` - that is the imperative approach, meaning you change UI directly when handling events. Flet now supports a declarative style: stop mutating controls, change state instead, and Flet updates the UI automatically. + +We’ll show the switch using a tiny CRUD “User Manager” app. First, the imperative version: UI-first, mutate controls, then update the page. Then the declarative rewrite: model-first, observable classes for data, components that return UI from state. + +The behavior in both examples stays the same - in the app you can see the list of users, add user, inline edit with save/cancel buttons and delete. This is how this simple app looks in both examples: + +
view
+ +After clicking inline Edit button: + +
view
+ +## Example 1 — Imperative + +In the imperative version, you think **UI-first**: decide exactly how the screen should look, and how it should change on each button click. Event handlers directly toggle control properties (like `visible`, `value`), insert/remove controls, and then call `page.update()` to push those visual changes. **Edit** hides the read-only label and action buttons, shows inputs and **Save/Cancel**; **Save** copies text field values back into the label and restores the original view; **Cancel** just restores the original view; **Delete** removes the whole row from the page. In short, behavior is implemented by **mutating controls** and **manually triggering re-renders**, not by evolving a separate state model. + +```python +import flet as ft + +class Item(ft.Row): + def __init__(self, first_name, last_name): + super().__init__() + + self.first_name_field = ft.TextField(first_name) + self.last_name_field = ft.TextField(last_name) + self.text = ft.Text(f"{first_name} {last_name}") + self.edit_text = ft.Row( + [ + self.first_name_field, + self.last_name_field, + ], + visible=False, + ) + self.edit_button = ft.Button("Edit", on_click=self.edit_item) + self.delete_button = ft.Button("Delete", on_click=self.delete_item) + self.save_button = ft.Button("Save", on_click=self.save_item, visible=False) + self.cancel_button = ft.Button( + "Cancel", on_click=self.cancel_item, visible=False + ) + self.controls = [ + self.text, + self.edit_text, + self.edit_button, + self.delete_button, + self.save_button, + self.cancel_button, + ] + + def delete_item(self, e): + self.page.controls.remove(self) + self.page.update() + + def edit_item(self, e): + print("edit_item") + self.text.visible = False + self.edit_button.visible = False + self.delete_button.visible = False + self.save_button.visible = True + self.cancel_button.visible = True + self.edit_text.visible = True + self.page.update() + + def save_item(self, e): + self.text.value = f"{self.first_name_field.value} {self.last_name_field.value}" + self.text.visible = True + self.edit_button.visible = True + self.delete_button.visible = True + self.save_button.visible = False + self.cancel_button.visible = False + self.edit_text.visible = False + self.page.update() + + def cancel_item(self, e): + self.text.visible = True + self.edit_button.visible = True + self.delete_button.visible = True + self.save_button.visible = False + self.cancel_button.visible = False + self.edit_text.visible = False + self.page.update() + +def main(page: ft.Page): + page.title = "CRUD Imperative Example" + + def add_item(e): + item = Item(first_name.value, last_name=last_name.value) + page.add(item) + first_name.value = "" + last_name.value = "" + page.update() + + first_name = ft.TextField(label="First Name", width=200) + last_name = ft.TextField(label="Last Name", width=200) + + page.add( + ft.Row( + [ + first_name, + last_name, + ft.Button("Add", on_click=add_item), + ] + ) + ) + +ft.run(main) +``` + +## Example 2 — Declarative + +In the declarative version, you think **model-first**: the model is a set of classes, and the data their objects hold is the single source of truth. In our CRUD app, the model consists of `User` (persisted fields `first_name`, `last_name`) and a top-level `App` that owns `users: list[User]` plus actions like `add_user(first, last)` and `delete_user(user)`. Both classes are marked `@ft.observable`, so assigning to their attributes (e.g., `user.update(...)`, `app.users.remove(user)`) triggers re-rendering — no `page.update()`. + +The UI is composed as components marked with `@ft.component` that return a view of the current state. Each row decides whether to show a read-only view or an inline editor using its own short-lived, local values (hooks), while the durable data lives on the model objects. Event handlers update state only (e.g., modify a user or add/remove items), not the controls themselves; Flet detects those changes and re-renders the affected parts. In short: **UI = f(state)**, with `User` and `App` providing the authoritative data. + +
diagram
+ +```python +from dataclasses import dataclass, field + +import flet as ft + +@ft.observable +@dataclass +class User: + first_name: str + last_name: str + + def update(self, first_name: str, last_name: str): + self.first_name = first_name + self.last_name = last_name + +@ft.observable +@dataclass +class App: + users: list[User] = field(default_factory=list) + + def add_user(self, first_name: str, last_name: str): + if first_name.strip() or last_name.strip(): + self.users.append(User(first_name, last_name)) + + def delete_user(self, user: User): + self.users.remove(user) + +@ft.component +def UserView(user: User, delete_user) -> ft.Control: + # Local (transient) editing state—NOT in User + is_editing, set_is_editing = ft.use_state(False) + new_first_name, set_new_first_name = ft.use_state(user.first_name) + new_last_name, set_new_last_name = ft.use_state(user.last_name) + + def start_edit(): + set_new_first_name(user.first_name) + set_new_last_name(user.last_name) + set_is_editing(True) + + def save(): + user.update(new_first_name, new_last_name) + set_is_editing(False) + + def cancel(): + set_is_editing(False) + + if not is_editing: + return ft.Row( + [ + ft.Text(f"{user.first_name} {user.last_name}"), + ft.Button("Edit", on_click=start_edit), + ft.Button("Delete", on_click=lambda: delete_user(user)), + ] + ) + + return ft.Row( + [ + ft.TextField( + label="First Name", + value=new_first_name, + on_change=lambda e: set_new_first_name(e.control.value), + width=180, + ), + ft.TextField( + label="Last Name", + value=new_last_name, + on_change=lambda e: set_new_last_name(e.control.value), + width=180, + ), + ft.Button("Save", on_click=save), + ft.Button("Cancel", on_click=cancel), + ] + ) + +@ft.component +def AddUserForm(add_user) -> ft.Control: + # Uses local buffers; calls parent action on Add + new_first_name, set_new_first_name = ft.use_state("") + new_last_name, set_new_last_name = ft.use_state("") + + def add_user_and_clear(): + add_user(new_first_name, new_last_name) + set_new_first_name("") + set_new_last_name("") + + return ft.Row( + controls=[ + ft.TextField( + label="First Name", + width=200, + value=new_first_name, + on_change=lambda e: set_new_first_name(e.control.value), + ), + ft.TextField( + label="Last Name", + width=200, + value=new_last_name, + on_change=lambda e: set_new_last_name(e.control.value), + ), + ft.Button("Add", on_click=add_user_and_clear), + ] + ) + +@ft.component +def AppView() -> list[ft.Control]: + app, _ = ft.use_state( + App( + users=[ + User("John", "Doe"), + User("Jane", "Doe"), + User("Foo", "Bar"), + ] + ) + ) + + return [ + AddUserForm(app.add_user), + *[UserView(user, app.delete_user) for user in app.users], + ] + +ft.run(lambda page: page.render(AppView)) +``` + +--- + +## Mindset shift: UI = f(state) + +The core idea is **determinism**: given the same state, your component should return the same UI. Think in two phases: + +1. **Handle event → update state** + Event handlers change *data only* (e.g., `set_is_editing(True)`, `user.update(...)`). + They don’t hide/show controls or call `page.update()`. + +2. **Render → derive UI from state** + The component *returns* controls based on the current state snapshot. + Because models are `@ft.observable` and locals come from `ft.use_state`, Flet re-runs the component when state changes and re-renders the right subtree. + +## Declarative Building Blocks: Observables, Components, Hooks + +Below are the key pieces of the Flet framework that make the declarative approach work: + +### Observables — your source of truth + +`@ft.observable` marks a dataclass as **reactive**. When you assign to its fields (`user.first_name = "Ada"` or `app.users.append(user)`), Flet re-renders any components that read those fields - no `page.update()` calls. Use observables for **persisted/domain data** (things you actually save). + +```python +from dataclasses import dataclass, field +import flet as ft + +@ft.observable +@dataclass +class User: + first_name: str + last_name: str + +@ft.observable +@dataclass +class AppState: + users: list[User] = field(default_factory=list) +``` + +### Components — functions that return UI + +`@ft.component` turns a function into a **rendering unit**. It takes props (regular args), may use hooks, and **returns controls** that describe the UI for the current state. Components do **not** imperatively mutate the page tree; they just return what the UI *should* look like now. + +```python +import flet as ft + +@ft.component +def UserRow(user: User, on_delete) -> ft.Control: + # returns a row for the current snapshot of `user` + return ft.Row([ + ft.Text(f"{user.first_name} {user.last_name}"), + ft.Button("Delete", on_click=lambda _: on_delete(user)), + ]) +``` + +### Hooks — local, short-lived UI state + +Why they are needed: components are functions that **re-run on every render**. Plain local variables get reinitialized each time, and changing them doesn’t tell Flet to update the view. Hooks (e.g., `ft.use_state`) give a component a place to persist values across renders and a way to signal a re-render when those values change. + +**What hooks solve** + +* **Persistence:** locals reset on each render; hook state survives. +* **Reactivity:** modifying a local doesn’t refresh the UI; a hook’s setter schedules a re-render. +* **Fresh values in handlers:** event callbacks won’t see stale locals; they read the latest hook state. + +**Use hooks for** short-lived, view-only concerns (like an “is editing?” flag or current input text) that belong to a single component. +**Use observables** for durable app/domain data shared across components. + +**Example** + +```python +# Broken: local resets every render and doesn't trigger updates +@ft.component +def CounterBroken(): + count = 0 + return ft.Row([ + ft.Text(str(count)), + ft.Button("+", on_click=lambda _: (count := count + 1)), # no re-render + ]) + +# Correct: persists across renders and re-renders when updated +@ft.component +def Counter(): + count, set_count = ft.use_state(0) + return ft.Row([ + ft.Text(str(count)), + ft.Button("+", on_click=lambda _: set_count(count + 1)), + ]) +``` + +**Rule of thumb:** if a value must survive re-renders and updating it should change the UI, don’t use a plain local — use hook state (for local UI) or an observable (for shared, persisted data). + +## Rewrite recipes (imperative → declarative) + +### 1) Visibility toggles → Conditional rendering + +```python +# Imperative +self.text.visible = False +self.save_button.visible = True +self.page.update() + +# Declarative +return ( + ft.Row([...read-only...]) + if not is_editing + else ft.Row([...edit form...]) +) +``` + +### 2) Direct control mutation → Model mutation + +```python +# Imperative +self.text.value = f"{first} {last}" + +# Declarative +user.update(new_first_name, new_last_name) +``` + +### 3) `page.update()` everywhere → Nowhere + +* Imperative handlers end with `page.update()`. +* Declarative code updates **observable fields** or **`use_state` values** and lets Flet re-render. + +### 4) Handlers manipulate **state**, not the view + +```python +# Declarative example +set_is_editing(True) +set_new_first_name(user.first_name) +``` + +### 5) Extract UI into components + +* `UserView` = one row (read-only/editing) +* `AddUserForm` = small, reusable add form + +## Summary + +The declarative style makes your UI a straightforward function of your data. It may not be make a big difference for a very simple app, but as your screen grows, you’ll add **state** and **components**, not scattered mutations of controls in different places. The result: code that’s easier to understand, maintain, and change — without chasing `visible` flags or manual updates. diff --git a/website/docs/cookbook/drag-and-drop.md b/website/docs/cookbook/drag-and-drop.md new file mode 100644 index 0000000000..4685b5e010 --- /dev/null +++ b/website/docs/cookbook/drag-and-drop.md @@ -0,0 +1,178 @@ +--- +title: "Drag and Drop" +--- + +import {Image} from '@site/src/components/crocodocs'; + +The mechanics of drag-and-drop in Flet is pretty simple - a user starts dragging [`Draggable`](../controls/draggable.md) +control and "drops" it on [`DragTarget`](../controls/dragtarget.md). If both draggable and drag target has the same `group` a +drag target will call `on_accept` event handler and pass draggable control ID as event data. In this case draggable serves as a source "data" for drag-and-drop operation. + +Let's take a look at the following example. In the program below you can drag left control displaying "1" on top of +the right control displaying "0" and when drag operation completes left control is replaced with "0" and the right control becomes "1": + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "Drag and Drop example" + + def drag_accept(e): + # update text inside draggable (source) control + e.src.content.content.value = "0" + # update text inside drag target control + e.control.content.content.value = "1" + page.update() + + page.add( + ft.Row( + controls=[ + ft.Draggable( + group="number", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN_200, + border_radius=5, + content=ft.Text("1", size=20), + alignment=ft.Alignment.CENTER, + ), + ), + ft.Container(width=100), + ft.DragTarget( + group="number", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.PINK_200, + border_radius=5, + content=ft.Text("0", size=20), + alignment=ft.Alignment.CENTER, + ), + on_accept=drag_accept, + ), + ] + ) + ) + +ft.run(main) +``` + +Drag and drop number + +So, it's developer's responsibility to determine what happens with "source" (draggable) and "destination" (drag target) +controls when `on_accept` event occurs. + +:::note[Try something] +Change DragTarget's group property to `number1` and note `on_accept` is not called any more when you drop "1" on the target. +::: + +There are additional properties and event handlers to make drag-and-drop operation even more interactive. +For example, draggable has `content_when_dragging` property to display a different control instead of `content` +when drag operation is under way. There is also `content_feedback` property to show a different control +under the pointer. By default, the same `content` control, but with 50% opacity is displayed under cursor when dragging. + +Let's modify Draggable in our example to display a "hole" in place of dragged control and +just "1" under cursor while dragging: + +```python +... + ft.Draggable( + group="number", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN_200, + border_radius=5, + content=ft.Text("1", size=20), + alignment=ft.alignment.center, + ), + content_when_dragging=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.BLUE_GREY_200, + border_radius=5, + ), + content_feedback=ft.Text("1"), + ), +... +``` + +Drag and drop number 2 + +Drag target control additionally has `on_will_accept` and `on_leave` event handlers which help better +visualize when it's a good time to "drop" something on the target. Let's modify DragTarget in our example +to draw a border around target control when it's ready to accept incoming drag: + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "Drag and Drop example 2" + + def drag_accept(e): + # update text inside draggable (source) control + e.src.content.content.value = "0" + # reset source group, so it cannot be dropped to a target anymore + e.src.group = "" + # update text inside drag target control + e.control.content.content.value = "1" + # reset border + e.control.content.border = None + page.update() + + def drag_will_accept(e): + # black border when it's allowed to drop and red when it's not + e.control.content.border = ft.Border.all( + 2, ft.Colors.BLACK_45 if e.data == "true" else ft.Colors.RED + ) + e.control.update() + + def drag_leave(e): + e.control.content.border = None + e.control.update() + + page.add( + ft.Row( + controls=[ + ft.Draggable( + group="number", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.CYAN_200, + border_radius=5, + content=ft.Text("1", size=20), + alignment=ft.Alignment.CENTER, + ), + content_when_dragging=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.BLUE_GREY_200, + border_radius=5, + ), + content_feedback=ft.Text("1"), + ), + ft.Container(width=100), + ft.DragTarget( + group="number", + content=ft.Container( + width=50, + height=50, + bgcolor=ft.Colors.PINK_200, + border_radius=5, + content=ft.Text("0", size=20), + alignment=ft.Alignment.CENTER, + ), + on_accept=drag_accept, + on_will_accept=drag_will_accept, + on_leave=drag_leave, + ), + ] + ) + ) + +ft.run(main) +``` + +Drag and drop number 3 diff --git a/website/docs/cookbook/encrypting-sensitive-data.md b/website/docs/cookbook/encrypting-sensitive-data.md new file mode 100644 index 0000000000..06a136a8fd --- /dev/null +++ b/website/docs/cookbook/encrypting-sensitive-data.md @@ -0,0 +1,71 @@ +--- +title: "Encrypting sensitive data" +--- + +Sensitive data such as tokens, keys, credit card numbers and other "secrets" must be stored at rest +(database, files, [client storage](client-storage.md)) in encrypted form to avoid data breaches. + +Flet includes utility methods to encrypt and decrypt sensitive text data using symmetric algorithm +(where the same key is used for encryption and decryption). They use [Fernet](https://github.com/fernet/spec/blob/master/Spec.md) implementation from +[cryptography](https://pypi.org/project/cryptography/) package, which is AES 128 with some additional hardening, +plus PBKDF2 to derive encryption key from a user passphrase. + +## Secret key + +Encryption secret key (aka password, or passphrase) is an arbitrary password-like string configured +by a user and used for encrypting and decrypting data. Crypto algorithm uses secret key to "derive" encryption key (32 bytes). + +:::danger +Do not embed any secrets into the source code to avoid accidental exposure to the public! +::: + +You can provide a secret to your app via environment variable: + +```python +import os +secret_key = os.getenv("MY_APP_SECRET_KEY") +``` + +Before running the app set the secret in a command line: + +``` +$ export MY_APP_SECRET_KEY="" +``` + +:::note +While passing secrets via environment variables is a common practice amongst developers and service +providers it does not fully prevent secrets leaking in some environments. Other mechanisms can be used +to inject secrets to your application such as mounting secret files or vault services. +::: + +## Encrypting data + +Use `encrypt()` method to encrypt a string: + +```python +import os +from flet.security import encrypt, decrypt + +secret_key = os.getenv("MY_APP_SECRET_KEY") +plain_text = "This is a secret message!" +encrypted_data = encrypt(plain_text, secret_key) +``` + +`encrypted_data` is a URL-safe base64-encoded string. + +`encrypt` accepts strings only, so any objects must be serialized to +JSON, XML or other text-based format before encryption. + +## Decrypting data + +Use `decrypt()` method to decrypt the data: + +```python +import os +from flet.security import encrypt, decrypt + +secret_key = os.getenv("MY_APP_SECRET_KEY") +encrypted_data = "601llp2zpPp4QjBWe2cOwGdBQUFBQUJqTTFJbmgyWU5jblVp..." +plain_text = decrypt(encrypted_data, secret_key) +print(plain_text) +``` diff --git a/website/docs/cookbook/expanding-controls.md b/website/docs/cookbook/expanding-controls.md new file mode 100644 index 0000000000..1db25131ed --- /dev/null +++ b/website/docs/cookbook/expanding-controls.md @@ -0,0 +1,81 @@ +--- +title: "Expanding Controls" +examples: "controls/core/control" +example_images: "test-images/examples/controls/core/golden/macos/control" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +## `expand` + +When a child control is placed into a [`Row`](../controls/row.md), [`Column`](../controls/column.md), [`View`](../controls/view.md) +or [`Page`](../controls/page.md) you can "expand" it to fill the available space. + +When adding child controls to a [`Row`](../controls/row.md), you can make them automatically +grow to fill available horizontal space using the [`expand`](../controls/control.md#flet.Control.expand) property, +which all Flet controls (inheriting from [`Control`](../controls/control.md)) have. + +It lets you control how they use free space inside a +layout like [`Row`](../controls/row.md) or [`Column`](../controls/column.md). + +You can set `expand` to one of the following values: + +* a boolean — Whether the control should take all the available space. +* an integer — Used to proportionally divide free space among multiple expanding controls (useful when you want more control over sizing). + +### Example 1 + +In this example, a [`TextField`](../controls/textfield.md) stretches to fill all remaining space in the row, +while the [`Button`](../controls/button.md) stays sized to its content: + + + +expand textfield in row + +### Example 2 + +In this example, we create a [`Row`](../controls/row.md) with three [`Container`](../controls/container.md)s, distributed like 20% / 60% / 20%: + + + +Here, the available space is split into 5 total parts (1+3+1). +The first and third containers get 1 part each (20%), and the middle one gets 3 parts (60%). + +expand row proportional 1 3 1 + +### Example 3 + +This example demonstrates how two controls inside a [`Row`](../controls/row.md) can +each expand to fill half of the available horizontal space using expand=True. + +The layout uses a parent [`Container`](../controls/container.md) and a nested row, where both controls are +expanded equally, resulting in a 50/50 split. + + + +expand row equal split + +## `expand_loose` + +The [`expand_loose`](../controls/control.md#flet.Control.expand_loose) property allows a control to *optionally* expand +and fill the available space along the main axis of its parent container +(e.g., horizontally in a [`Row`](../controls/row.md), or vertically in a [`Column`](../controls/column.md)). + +Unlike [`expand`](../controls/control.md#flet.Control.expand), which *forces* the control to occupy all available space, +`expand_loose` gives the control **flexibility** to grow **if needed**, but it’s not required to fill the space. + +:::note[Note] +For this property to have effect: + +- it must be used on child controls within the following layout containers, +or any of their subclasses: [`Row`](../controls/row.md), [`Column`](../controls/column.md), [`View`](../controls/view.md), [`Page`](../controls/page.md) +- the control using this property must have a non-none value for [`expand`](../controls/control.md#flet.Control.expand). +::: + +### Example 1 + +In this example, [`Container`](../controls/container.md)s being placed in [`Row`](../controls/row.md)s with `expand_loose = True`: + + + +expand loose chat messages diff --git a/website/docs/cookbook/fonts.md b/website/docs/cookbook/fonts.md new file mode 100644 index 0000000000..9eea653455 --- /dev/null +++ b/website/docs/cookbook/fonts.md @@ -0,0 +1,81 @@ +--- +title: "Fonts" +--- + +## System fonts + +You can use the (system) fonts installed on your computer, e.g. "Consolas", "Arial", "Verdana", "Tahoma", etc. + +:::note[Limitation] +System fonts cannot be used in Flet web apps rendered with [canvas kit](../types/webrenderer.md#flet.WebRenderer.CANVAS_KIT) web renderer. +::: + +### Usage Example + +The following example demonstrates how to use the "Consolas" font in a Flet application. + +```python +import flet as ft + +def main(page: ft.Page): + page.add( + ft.Text( + value="This text is rendered with Consolas font", + font_family="Consolas" + ) + ) + +ft.run(main) +``` + +## Importing Fonts + +Font can be imported from external resource by providing an absolute URL or +from application assets directory (see [Assets Guide](assets.md)). + +This is done by setting the page's [`fonts`](../controls/page.md#flet.Page.fonts) property. + +To apply one of the imported fonts, you can: +- Use [`Theme.font_family`](../types/theme/index.md#flet.Theme.font_family) to set a default/fallback app-wide font family. +- Specify a font for individual controls. For example, [`Text.font_family`](../controls/text.md#flet.Text.font_family). + +### Usage Example + +The example below loads the "Kanit" font from GitHub and `"Open Sans"` from local assets. +"Kanit" is set as the default app font, while `"Open Sans"` is applied to a specific [`Text`](../controls/text.md) control. + +```python +import flet as ft + +def main(page: ft.Page): + page.fonts = { + "Kanit": "https://raw.githubusercontent.com/google/fonts/master/ofl/kanit/Kanit-Bold.ttf", + "Open Sans": "/fonts/OpenSans-Regular.ttf" + } + + page.theme = Theme(font_family="Kanit") # Default app font + + page.add( + ft.Text("This text uses the Kanit font"), + ft.Text("This text uses the Open Sans font", font_family="Open Sans") + ) + +ft.run(main, assets_dir="assets") +``` + +### Static and Variable Fonts + +Currently, only [static fonts](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#standard_or_static_fonts) are supported. These fonts have a specific width, +weight, or style combination (e.g., "Open Sans Regular"). + +Support for [variable fonts](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#variable_fonts) is in progress. + +However, to use variable fonts, you can create static instances at specific weights +using [fonttools](https://pypi.org/project/fonttools/), e.g.: + +```bash +fonttools varLib.mutator ./YourVariableFont-VF.ttf wght=140 wdth=85 +``` + +To explore available font features (e.g. possible options for `wght`) +use [Wakamai Fondue](https://wakamaifondue.com/beta/) online tool. diff --git a/website/docs/cookbook/keyboard-shortcuts.md b/website/docs/cookbook/keyboard-shortcuts.md new file mode 100644 index 0000000000..03d18f42d1 --- /dev/null +++ b/website/docs/cookbook/keyboard-shortcuts.md @@ -0,0 +1,44 @@ +--- +title: "Keyboard Shortcuts" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +A solid keyboard support is a key for user productivity while using your web and, especially, desktop app. Indeed, it could be really annoying to constantly switch between mouse and keyboard. + +In addition to form controls' `.autofocus` property and [`TextField.focus()`](../controls/formfieldcontrol.md#flet.FormFieldControl.focus) method Flet allows handling "global" keyboard events. + +To capture all keystrokes implement `page.on_keyboard_event` handler. Event handler parameter `e` is an instance of `KeyboardEvent` class with the following properties: + +* `key` - a textual representation of a pressed key, e.g. `A`, `Enter` or `F5`. +* `shift` - `True` if "Shift" key is pressed. +* `ctrl` - `True` if "Control" key is pressed. +* `alt` - `True` if "Alt" ("Option") key is pressed. +* `meta` - `True` if "Command" key is pressed. + +This is a simple usage example: + +```python +import flet as ft + +def main(page: ft.Page): + def on_keyboard(e: ft.KeyboardEvent): + page.add( + ft.Text( + f"Key: {e.key}, Shift: {e.shift}, Control: {e.ctrl}, Alt: {e.alt}, Meta: {e.meta}" + ) + ) + + page.on_keyboard_event = on_keyboard + page.add( + ft.Text("Press any key with a combination of CTRL, ALT, SHIFT and META keys...") + ) + +ft.run(main) +``` + +Keyboard shortcuts + +Below is a more advanced example: + + diff --git a/website/docs/cookbook/large-lists.md b/website/docs/cookbook/large-lists.md new file mode 100644 index 0000000000..757346ecfc --- /dev/null +++ b/website/docs/cookbook/large-lists.md @@ -0,0 +1,160 @@ +--- +title: "Large Lists" +--- + +You can use [`Column`](../controls/column.md) and [`Row`](../controls/row.md) controls to display lists in the most cases, but if the list contains hundreds or thousands of items `Column` and `Row` will be ineffective with lagging UI as they render all items at once even they are not visible at the current scrolling position. + +In the following example we are adding 5,000 text controls to a page. Page uses `Column` as a default layout container: + +```python +import flet as ft + +def main(page: ft.Page): + for i in range(5000): + page.controls.append(ft.Text(f"Line {i}")) + page.scroll = "always" + page.update() + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Run the program and notice that it's not just it takes a couple of seconds to initially load and render all text lines on a page, but scrolling is slow and laggy too: + +
Scroll column
+ +For displaying lists with a lot of items use [`ListView`](../controls/listview.md) and [`GridView`](../controls/gridview.md) controls which render items on demand, visible at the current scrolling position only. + +## ListView + +[`ListView`](../controls/listview.md) could be either vertical (default) or horizontal. ListView items are displayed one after another in the scroll direction. + +ListView already implements effective on demand rendering of its children, but scrolling performance could be further improved if you can set the same fixed height or width (for `horizontal` ListView) for all items ("extent"). This could be done by either setting absolute extent with `item_extent` property or making the extent of all children equal to the extent of the first child by setting `first_item_prototype` to `True`. + +Let's output a list of 5,000 items using ListView control: + +```python +import flet as ft + +def main(page: ft.Page): + lv = ft.ListView(expand=True, spacing=10) + for i in range(5000): + lv.controls.append(ft.Text(f"Line {i}")) + page.add(lv) + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Now the scrolling is smooth and fast enough to follow mouse movements: + +
Scroll listview
+ +:::note +We used `expand=True` in ListView constructor. In order to function properly, +ListView must have a height (or width if `horizontal`) specified. +You could set an absolute size, e.g. `ListView(height=300, spacing=10)`, but in the +example above we make ListView to take all available space on the page, i.e. expand. +Read more about [`Control.expand`](../controls/control.md#flet.Control.expand) property. +::: + +## GridView + +[`GridView`](../controls/gridview.md) allows arranging controls into a scrollable grid. + +You can make a "grid" with `ft.Column(wrap=True)` or `ft.Row(wrap=True)`, for example: + +```python +import os +import flet as ft + +os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000" + +def main(page: ft.Page): + r = ft.Row(wrap=True, scroll="always", expand=True) + page.add(r) + + for i in range(5000): + r.controls.append( + ft.Container( + ft.Text(f"Item {i}"), + width=100, + height=100, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.AMBER_100, + border=ft.Border.all(1, ft.Colors.AMBER_400), + border_radius=ft.BorderRadius.all(5), + ) + ) + page.update() + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +
Row wrap as grid
+ +Try scrolling and resizing the browser window - everything works, but very laggy. + +:::note +At the start of the program we are setting the value of `FLET_WS_MAX_MESSAGE_SIZE` environment variable to `8000000` - this is the maximum size of WebSocket message in bytes that can be received by Flet Server rendering the page. Default size is 1 MB, but the size of JSON message describing 5,000 container controls would exceed 1 MB, so we are increasing allowed size to 8 MB. + +Squeezing large messages through WebSocket channel is, generally, not a good idea, so use [batched updates](#batch-updates) approach to control channel load. +::: + +GridView, similar to ListView, is very effective to render a lot of children. Let's implement the example above using GridView: + +```python +import os +import flet as ft + +os.environ["FLET_WS_MAX_MESSAGE_SIZE"] = "8000000" + +def main(page: ft.Page): + gv = ft.GridView(expand=True, max_extent=150, child_aspect_ratio=1) + page.add(gv) + + for i in range(5000): + gv.controls.append( + ft.Container( + ft.Text(f"Item {i}"), + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.AMBER_100, + border=ft.Border.all(1, ft.Colors.AMBER_400), + border_radius=ft.BorderRadius.all(5), + ) + ) + page.update() + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +
Grid view
+ +With GridView scrolling and window resizing are smooth and responsive! + +You can specify either fixed number of rows or columns (runs) with `runs_count` property or the maximum size of a "tile" with `max_extent` property, so the number of runs can vary automatically. In our example we set the maximum tile size to 150 pixels and set its shape to "square" with `child_aspect_ratio=1`. `child_aspect_ratio` is the ratio of the cross-axis to the main-axis extent of each child. Try changing it to `0.5` or `2`. + +## Batch updates + +When `page.update()` is called a message is being sent to Flet server over WebSockets containing page updates since the last `page.update()`. Sending a large message with thousands of added controls could make a user waiting for a few seconds until the messages is fully received and controls rendered. + +To increase usability of your program and present the results to a user as soon as possible you can send page updates in batches. For example, the following program adds 5,100 child controls to a ListView in batches of 500 items: + +```python +import flet as ft + +def main(page: ft.Page): + + # add ListView to a page first + lv = ft.ListView(expand=1, spacing=10, item_extent=50) + page.add(lv) + + for i in range(5100): + lv.controls.append(ft.Text(f"Line {i}")) + # send page to a page + if i % 500 == 0: + page.update() + # send the rest to a page + page.update() + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` +
Sending page updates in batches
diff --git a/website/docs/cookbook/logging.md b/website/docs/cookbook/logging.md new file mode 100644 index 0000000000..a6f88f4553 --- /dev/null +++ b/website/docs/cookbook/logging.md @@ -0,0 +1,74 @@ +--- +title: "Logging" +--- + +This article explains how to control level of the logs messages generated by Flet library and its underlying components. +You may need to enable detailed logging to troubleshoot Flet library or when submitting a new Flet issue. + +## Python + +Flet Python uses the following named loggers: + +- `flet` - general framework and transport logging. +- `flet_object_patch` - detailed control tree diff/patch logging. +- `flet_components` - declarative component lifecycle logging. + +For normal use, configure logging before calling `ft.run()`: + +```python +import logging + +logging.basicConfig(level=logging.INFO) +``` + +This gives you the usual `flet` logs without too much noise. + +To see more detail from the main `flet` logger, either raise the root logging level: + +```python +import logging + +logging.basicConfig(level=logging.DEBUG) +``` + +or set the `flet` logger explicitly: + +```python +import logging + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet").setLevel(logging.DEBUG) +``` + +`flet_object_patch` and `flet_components` set their own level to `INFO`, so +they do not inherit the root `DEBUG` level unless you enable them explicitly. + +To enable the most verbose diagnostics, set the corresponding loggers to `DEBUG`: + +```python +import logging + +logging.basicConfig(level=logging.DEBUG) +logging.getLogger("flet_object_patch").setLevel(logging.DEBUG) +logging.getLogger("flet_components").setLevel(logging.DEBUG) +``` + +Use this level mostly for troubleshooting and issue reports. + +## Built-in Web Server + +When running a web app, Flet starts its built-in web transport on top of +FastAPI and Uvicorn. + +The effective level of the `flet` Python logger is passed to the built-in web +server, so configure `flet` logging before starting the app: + +```python +import logging + +logging.basicConfig(level=logging.INFO) +logging.getLogger("flet").setLevel(logging.DEBUG) +``` + +If you host a Flet ASGI app with your own server process, such as `uvicorn` or +`gunicorn`, configure that server's logging separately using its own options. diff --git a/website/docs/cookbook/navigation-and-routing.md b/website/docs/cookbook/navigation-and-routing.md new file mode 100644 index 0000000000..1b1e44c970 --- /dev/null +++ b/website/docs/cookbook/navigation-and-routing.md @@ -0,0 +1,148 @@ +--- +title: "Navigation and Routing" +--- + +import {CodeExample} from '@site/src/components/crocodocs'; + +Navigation and routing is the core of building multi-screen Flet apps. +It lets you organize your UI into virtual pages ([`View`](../controls/view.md) objects), +keep URL/history in sync, and support deep links to specific app states. + +This page focuses on the current routing model and maintained examples. + +## Routing model in Flet + +A [`Page`](../controls/page.md) is a container of views ([`page.views`](../controls/page.md)), where each view represents one route-level screen. + +- [`page.route`](../controls/page.md#flet.Page.route) is the current route string (for example `/`, `/store`, `/settings/mail`). +- [`page.views`](../controls/page.md) is the active navigation stack. +- [`page.on_route_change`](../controls/page.md#flet.Page.on_route_change) rebuilds the stack when route changes. +- [`page.on_view_pop`](../controls/page.md#flet.Page.on_view_pop) handles Back navigation (system Back, AppBar Back, browser Back). + +A reliable setup uses a single source of truth: derive [`page.views`](../controls/page.md) from [`page.route`](../controls/page.md#flet.Page.route). + +## Route basics + +The default route is `/` when no route is provided. + + + +All routes should start with `/`, for example `/store`, `/products/42`, `/settings/mail`. + +## Handling route changes + +Whenever route changes (URL edit, browser Back/Forward, or app navigation), +[`page.on_route_change`](../controls/page.md#flet.Page.on_route_change) event is triggered. +Use this event as the place where you decide which views must exist for the current route. + + + +## Building views from route + +The pattern below is the baseline for most apps: + +1. Clear [`page.views`](../controls/page.md). +2. Add root view (`/`). +3. Add extra views conditionally based on [`page.route`](../controls/page.md#flet.Page.route). +4. Handle Back in [`page.on_view_pop`](../controls/page.md#flet.Page.on_view_pop) and navigate to the new top view. + +:::tip[Why is this pattern important?] +- Keeps URL, history stack, and visible UI synchronized. +- Supports deep links and reloads naturally. +- Makes navigation deterministic and easier to debug. +::: + + + +## Programmatic navigation + +Use [`page.navigate()`](../controls/page.md#flet.Page.navigate) to navigate from synchronous callbacks +(e.g. `on_click`), or [`page.push_route()`](../controls/page.md#flet.Page.push_route) in async contexts: + +```python +# Sync (on_click, etc.) +page.navigate("/search", q="flet", page=2) + +# Async +await page.push_route("/search", q="flet", page=2) +``` + +## Back navigation and pop confirmation + +When users go back, Flet triggers [`page.on_view_pop`](../controls/page.md#flet.Page.on_view_pop). +For flows requiring confirmation (for example, unsaved changes), disable automatic pop +and confirm manually with [`View.can_pop`](../controls/view.md#flet.View.can_pop) + [`View.on_confirm_pop`](../controls/view.md#flet.View.on_confirm_pop). + + + +## Pop multiple views with a result + +When a multi-step flow finishes deep in the view stack, use +[`page.pop_views_until()`](../controls/page.md#flet.Page.pop_views_until) +to jump back to a target route and deliver a result to the destination view +via [`page.on_views_pop_until`](../controls/page.md#flet.Page.on_views_pop_until). + + + +## Navigation UI patterns + +Routing composes well with navigation controls such as drawer, rail, and tabs. +This example shows route-driven drawer navigation with multiple top-level destinations: + + + +## Route templates (parameterized routes) + +Use [`TemplateRoute`](../types/templateroute.md) to match and parse route parameters, for example `/books/:id`. +Template syntax is provided by [repath](https://github.com/nickcoutsos/python-repath#parameters). + +```python +import flet as ft + +troute = ft.TemplateRoute(page.route) + +if troute.match("/books/:id"): + print("Book ID:", troute.id) +elif troute.match("/account/:account_id/orders/:order_id"): + print("Account:", troute.account_id, "Order:", troute.order_id) +else: + print("Unknown route") +``` + +## Web URL strategy + +Flet web apps support two URL strategies : + +- `"path"` (default): in the form `https://myapp.dev/store` +- `"hash"`: `https://myapp.dev/#/store` + +It can be set via `route_url_strategy` in `ft.run()` +```python +import flet as ft +ft.run(main, route_url_strategy="hash") +``` + +For Flet server deployments, you can also set the [`FLET_ROUTE_URL_STRATEGY`](../reference/environment-variables.md#flet_web_route_url_strategy) +environment variable. + +## Declarative Router + +For declarative apps using `@component`, Flet provides a +[**Router**](router.md) system inspired by React Router. It handles +nested routes, layout routes with outlets, dynamic segments, data loaders, +and active link detection — all without manual route matching. + +With `manage_views=True`, Router can also manage the view stack directly, +enabling swipe-back gestures and AppBar back buttons on mobile. Route +components return [`View`](../controls/view.md) objects with their own +[`AppBar`](../controls/appbar.md), and navigating deeper pushes views +onto the stack. + +See the [Router cookbook](router.md) for a complete guide. + +## Practical recommendations + +- Always keep a root `/` view in [`page.views`](../controls/page.md). +- Keep route handling centralized in [`page.on_route_change`](../controls/page.md#flet.Page.on_route_change); avoid mutating [`page.views`](../controls/page.md) from many places. +- When adding new routes, test these cases: direct deep link, browser Back/Forward, app Back button, and reload. +- Use route templates for dynamic segments instead of manual string splitting. diff --git a/website/docs/cookbook/pub-sub.md b/website/docs/cookbook/pub-sub.md new file mode 100644 index 0000000000..1cf48df56d --- /dev/null +++ b/website/docs/cookbook/pub-sub.md @@ -0,0 +1,50 @@ +--- +title: "PubSub" +--- + +import {Image} from '@site/src/components/crocodocs'; + +If you build a chat app using Flet you need somehow to pass user messages between sessions. When a user sends a message it should be broadcasted to all other app sessions and displayed on their pages. + +Flet provides a simple built-in PubSub mechanism for asynchronous communication between page sessions. + +Flet PubSub allows broadcasting messages to all app sessions or sending only to specific "topic" (or "channel") subscribers. + +A typical PubSub usage would be: + +* [`subscribe()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.subscribe) to broadcast messages or [`subscribe_topic()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.subscribe_topic) on app session start. +* [`send_all()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.send_all) broadcast message or [`send_all_on_topic()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.send_all_on_topic) on some event, like "Send" button click. +* [`unsubscribe()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.unsubscribe) from broadcast messages or [`unsubscribe_topic()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.unsubscribe_topic) on some event, like "Leave" button click. +* [`unsubscribe_all()`](../types/pubsub/pubsubclient.md#flet.pubsub.PubSubClient.unsubscribe_all) from everything on [`page.on_close`](../controls/page.md#flet.Page.on_close). + +This is an example of a simple chat application that uses PubSub: + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "Flet Chat" + + # subscribe to broadcast messages + def on_message(msg): + messages.controls.append(ft.Text(msg)) + page.update() + + page.pubsub.subscribe(on_message) + + def send_click(e): + page.pubsub.send_all(f"{user.value}: {message.value}") + # clean up the form + message.value = "" + page.update() + + messages = ft.Column() + user = ft.TextField(hint_text="Your name", width=150) + message = ft.TextField(hint_text="Your message...", expand=True) # fill all the space + send = ft.Button("Send", on_click=send_click) + page.add(messages, ft.Row(controls=[user, message, send])) + +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +Chat app diff --git a/website/docs/cookbook/read-and-write-files.md b/website/docs/cookbook/read-and-write-files.md new file mode 100644 index 0000000000..330f231a1f --- /dev/null +++ b/website/docs/cookbook/read-and-write-files.md @@ -0,0 +1,167 @@ +--- +title: "Read and Write Files" +--- + +In some cases, you need to read and write files to disk. +For example, you might need to persist data across app launches, or download data from the internet and save it for later offline use. + +Flet makes it easy to work with files and directories on the mobile/desktop device, as seen in the following example. + +### Storage Paths + +Flet provides two directory paths for data storage, available as environment variables: +[`FLET_APP_STORAGE_DATA`](../reference/environment-variables.md#flet_app_storage_data) and +[`FLET_APP_STORAGE_TEMP`](../reference/environment-variables.md#flet_app_storage_temp). + +Their values can be gotten as follows: + +```python +import os + +app_data_path = os.getenv("FLET_APP_STORAGE_DATA") +app_temp_path = os.getenv("FLET_APP_STORAGE_TEMP") +``` + +### Writing to a File + +To write data to a new/existing file, you can use the built-in [`open`](https://docs.python.org/3/library/functions.html#open) function. + +For example: + +```python +import os + +app_data_path = os.getenv("FLET_APP_STORAGE_DATA") +my_file_path = os.path.join(app_data_path, "test_file.txt") + +with open(my_file_path, "w") as f: + f.write("Some file content...") +``` + +### Reading from a File + +To read data from an existing file, you can equally use the built-in [`open`](https://docs.python.org/3/library/functions.html#open) function. + +For example: + +```python +import os + +app_data_path = os.getenv("FLET_APP_STORAGE_DATA") +my_file_path = os.path.join(app_data_path, "test_file.txt") + +with open(my_file_path, "r") as f: + file_content = f.read() + print(file_content) +``` + +Also, you can use the [`os`](https://docs.python.org/3/library/os.html) module (or any other out there) to perform various file operations like renaming, deleting, listing files present in the directory, etc. + +## Example: Counter App + +Below is an example that showcases a basic Counter application, whose value persists across app launches. +This is made possible by writing the counter value to a file in the app's data storage directory and reading it when the app launches. + + + +```python +import os +from datetime import datetime +import flet as ft + +# constants +FLET_APP_STORAGE_DATA = os.getenv("FLET_APP_STORAGE_DATA") +COUNTER_FILE_PATH = os.path.join(FLET_APP_STORAGE_DATA, "counter.txt") +FLET_APP_CONSOLE = os.getenv("FLET_APP_CONSOLE") + +class Counter(ft.Text): + def __init__(self, storage_path=COUNTER_FILE_PATH): + super().__init__(theme_style=ft.TextThemeStyle.HEADLINE_LARGE) + self.storage_path = storage_path + self.count = self.__read_from_storage() + + def increment(self): + """Increment the counter, store the new value, and return it.""" + self.count += 1 + self.update() + self.__write_to_storage() + + def before_update(self): + super().before_update() + self.value = f"Button tapped {self.count} time{'' if self.count == 1 else 's'}" + + def __log(self, action: str, value: int = None): + """Log executed action.""" + if value is None: + value = self.count + print(f"{datetime.now().strftime('%Y/%m/%d %H:%M:%S')} - {action} = {value}") + + def __read_from_storage(self): + """Read counter value. If an error occurs, use 0.""" + try: + with open(self.storage_path, "r") as f: + value = int(f.read().strip()) + except (FileNotFoundError, ValueError): + # file does not exist or int parsing failed + value = 0 + + self.__log("READ", value) + return value + + def __write_to_storage(self): + """Write current counter value to storage.""" + with open(self.storage_path, "w") as f: + f.write(str(self.count)) + self.__log("WRITE") + +def main(page: ft.Page): + page.theme_mode = ft.ThemeMode.LIGHT + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + def show_logs(e: ft.ControlEvent): + if FLET_APP_CONSOLE is not None: + with open(FLET_APP_CONSOLE, "r") as f: + dlg = ft.AlertDialog( + title=ft.Text("App Logs"), + content=ft.Text(f.read()), + scrollable=True, + ) + page.open(dlg) + + counter = Counter() + page.appbar = ft.AppBar( + title=ft.Text("Storage Playground", weight=ft.FontWeight.BOLD), + center_title=True, + bgcolor=ft.Colors.BLUE, + color=ft.Colors.WHITE, + adaptive=True, + actions=[ + ft.IconButton( + icon=ft.Icons.REMOVE_RED_EYE, + tooltip="Show logs", + visible=FLET_APP_CONSOLE is not None, + on_click=show_logs, + ), + ], + ) + page.floating_action_button = ft.FloatingActionButton( + icon=ft.Icons.ADD, + text="Increment Counter", + foreground_color=ft.Colors.WHITE, + bgcolor=ft.Colors.BLUE, + on_click=lambda e: counter.increment(), + ) + page.floating_action_button_location = ft.FloatingActionButtonLocation.CENTER_FLOAT + + page.add(ft.SafeArea(counter)) + +ft.run(main) +``` + +- `Counter` class is a custom control, which is a subclass/extension of the [`Text`](../controls/text.md) control. More information [here](../cookbook/custom-controls.md). +- [`FLET_APP_CONSOLE`](../reference/environment-variables.md#flet_app_console) is an environment variable that points to the application's console log file (`console.log`) which contains the app's [console output](https://flet.dev/docs/publish#console-output) (ex: `print()` statements). Its value is set in production mode. +- If you have an android emulator or physical device, you can download and install this [apk](https://github.com/ndonkoHenri/flet-storage-cookbook/releases). +- Follow [this](../publish/index.md) guide to package your app for all platforms. diff --git a/website/docs/cookbook/router.md b/website/docs/cookbook/router.md new file mode 100644 index 0000000000..2f4bf31ad1 --- /dev/null +++ b/website/docs/cookbook/router.md @@ -0,0 +1,396 @@ +--- +title: "Router" +--- + +Router is a declarative routing system for Flet apps, inspired by React Router. +It handles nested route matching, layout routes with outlets, dynamic segments, +data loading, view-stack navigation, and provides hooks for accessing route state. + +## Why Router? + +Without Router, multi-page Flet apps require manual route matching, conditional +rendering, and parameter extraction. Router automates all of this: + +- **Nested routes** — define parent/child hierarchies +- **Layout routes** — share layouts across pages using [use_route_outlet()](../types/use_route_outlet.md) +- **Dynamic segments** — `:paramName` in paths, accessed via [use_route_params()](../types/use_route_params.md) +- **Data loading** — fetch data before rendering with `loader` +- **Active link detection** — highlight nav items with [is_route_active()](../types/is_route_active.md) +- **View-stack navigation** — swipe-back and AppBar back button with `manage_views=True` + +## Quick start + +```python +@ft.component +def Home(): + return ft.Text("Welcome home!") + +@ft.component +def About(): + return ft.Text("About us") + +@ft.component +def App(): + return ft.Router([ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ]) + +ft.run(lambda page: page.render(App)) +``` + +See [full example](../controls/router.md#basic). + +## Defining routes + +Routes are defined as a tree of [Route](../types/route.md) objects. + +### Flat routes + +All routes at the top level: + +```python +ft.Router([ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ft.Route(path="contact", component=Contact), +]) +``` + +### Nested routes + +Child routes are nested under parent routes. The parent's path is +automatically prepended: + +```python +ft.Route( + path="products", + component=ProductsList, + children=[ + ft.Route(path=":pid", component=ProductDetails), + ], +) +# /products → ProductsList +# /products/42 → ProductDetails (params: {"pid": "42"}) +``` + +See [full example](../controls/router.md#dynamic-segments). + +### Index routes + +An index route (`index=True`) matches when the parent path matches exactly, +with no further segments: + +```python +ft.Route(path="settings", children=[ + ft.Route(index=True, component=SettingsHome), # /settings + ft.Route(path="profile", component=Profile), # /settings/profile +]) +``` + +### Prefix routes + +**Pathless layout routes** — group children under a shared layout without +adding a path segment: + +```python +ft.Route(component=AdminLayout, children=[ + ft.Route(path="users", component=Users), # /users + ft.Route(path="settings", component=Settings), # /settings +]) +``` + +**Path-only routes** — add a path prefix without rendering a component: + +```python +ft.Route(path="api", children=[ + ft.Route(path="users", component=ApiUsers), # /api/users + ft.Route(path="products", component=ApiProducts), # /api/products +]) +``` + +## Layout routes and `use_route_outlet()` + +A layout route has both a `component` and `children`. Its component renders +shared UI (header, sidebar, footer) and calls [use_route_outlet()](../types/use_route_outlet.md) +to place the matched child: + +```python +@ft.component +def AppLayout(): + outlet = ft.use_route_outlet() + return ft.Column([ + ft.AppBar(title=ft.Text("My App")), + ft.Container(content=outlet, expand=True), + ft.Text("Footer"), + ]) + +ft.Router([ + ft.Route(component=AppLayout, children=[ + ft.Route(index=True, component=Home), + ft.Route(path="about", component=About), + ]), +]) +``` + +Layout routes can be nested to any depth. Each level calls `use_route_outlet()` to +get its immediate child. See [full example](../controls/router.md#layout-with-outlet). + +## Dynamic segments, optional segments, and splats + +Route paths support Express-style patterns via the `repath` library. + +**Dynamic segments** — `:paramName` matches a single path segment: + +```python +ft.Route(path="users/:userId", component=UserProfile) +# /users/42 → use_route_params() returns {"userId": "42"} +``` + +**Optional segments** — `:paramName?` may be absent: + +```python +ft.Route(path="users/:userId?", component=UserProfile) +# /users → {"userId": None} +# /users/42 → {"userId": "42"} +``` + +**Splats (catch-all)** — `:paramName*` matches zero or more segments: + +```python +ft.Route(path="files/:path*", component=FileBrowser) +# /files/a/b/c → {"path": "a/b/c"} +``` + +**Custom regex** — `:paramName(\\d+)` constrains a segment: + +```python +ft.Route(path="item/:id(\\d+)", component=ItemDetails) +# /item/42 → matches +# /item/abc → does NOT match +``` + +## Navigation + +Use [page.navigate()](../controls/page.md#flet.Page.navigate) from synchronous callbacks: + +```python +ft.Button("About", on_click=lambda: ft.context.page.navigate("/about")) +``` + +For async contexts, use [page.push_route()](../controls/page.md#flet.Page.push_route) with `await`. +The Router automatically re-renders when the route changes. + +## Active links with `is_route_active()` + +[is_route_active(path)](../types/is_route_active.md) returns `True` if the given path matches +the current location: + +```python +ft.Button( + "Products", + style=ft.ButtonStyle( + bgcolor=ft.Colors.PRIMARY_CONTAINER + if ft.is_route_active("/products") + else None, + ), + on_click=lambda: ft.context.page.navigate("/products"), +) +``` + +By default it uses prefix matching — `is_route_active("/products")` returns +`True` for `/products/42`. Pass `exact=True` for exact matching. +See [full example](../controls/router.md#active-links). + +## Data loading + +Routes can define a `loader` function. It runs when the route matches and its +return value is available via [use_route_loader_data()](../types/use_route_loader_data.md): + +```python +def load_user(params): + return db.get_user(params["userId"]) + +ft.Route(path="users/:userId", component=UserProfile, loader=load_user) +``` + +```python +@ft.component +def UserProfile(): + user = ft.use_route_loader_data() + return ft.Text(f"Hello, {user.name}") +``` + +See [full example](../controls/router.md#loaders). + +## Authentication + +Auth is implemented using layout routes as guards — no special Router API needed. + +**Page redirect** — redirect to `/login` if not authenticated: + +```python +@ft.component +def ProtectedRoute(): + outlet = ft.use_route_outlet() + if not auth.is_authenticated: + ft.context.page.navigate("/login") + return ft.Text("Redirecting...") + return outlet +``` + +**Role-based access** — nest guard routes for layered access control: + +```python +ft.Router([ + ft.Route(component=ProtectedRoute, children=[ + ft.Route(index=True, component=Home), + ft.Route(component=AdminOnly, children=[ + ft.Route(path="admin", component=AdminPanel), + ]), + ]), +]) +``` + +## 404 handling + +Pass a `not_found` component to render when no route matches: + +```python +@ft.component +def NotFound(): + location = ft.use_route_location() + return ft.Text(f"Page not found: {location}") + +ft.Router(routes, not_found=NotFound) +``` + +## Multi-view navigation + +By default, Router renders all route content within a single [View](../controls/view.md). +With `manage_views=True`, the Router returns a list of Views — one per path level. +This enables: + +- Swipe-back gesture on mobile +- System back button +- [AppBar](../controls/appbar.md) implicit back button +- Slide transition between route levels + +Use [page.render_views()](../controls/page.md#flet.Page.render_views) instead of +`page.render()`. + +### Components return Views + +Each route component returns a [View](../controls/view.md) with `route`, `appbar`, +and `controls`: + +```python +@ft.component +def ProductDetails(): + params = ft.use_route_params() + return ft.View( + route=f"/products/{params['pid']}", + appbar=ft.AppBar(title=ft.Text(f"Product #{params['pid']}")), + controls=[ + ft.Text(f"Details for product #{params['pid']}"), + ], + ) +``` + +### Nested route hierarchy + +Structure routes as a nested tree. A pathless root ensures it is always +in the view stack: + +```python +ft.Router([ + ft.Route(component=Home, children=[ + ft.Route(path="products", component=ProductsList, children=[ + ft.Route(path=":pid", component=ProductDetails), + ]), + ]), +], manage_views=True) +``` + +:::tip[View stack] +- `/` — 1 view (Home) +- `/products` — 2 views (Home, Products) — back button to Home +- `/products/1` — 3 views (Home, Products, Product Details) — back button to Products +::: + +See [full example](../controls/router.md#managed-views--nested-routes). + +### Shared layouts with `outlet=True` + +Set `outlet=True` on a route to make it a layout that wraps child routes +via [use_route_outlet()](../types/use_route_outlet.md). The layout returns a +[View](../controls/view.md); child components return regular controls. + +Use [use_view_path()](../types/use_view_path.md) for `View.route` — it returns +the resolved URL for each child view level, so Flutter's Navigator gets a +unique key per view in the stack: + +```python +@ft.component +def ProductsLayout(): + outlet = ft.use_route_outlet() + return ft.View( + route=ft.use_view_path(), + appbar=ft.AppBar(title=ft.Text("Products")), + controls=[ + ft.Container(content=outlet, expand=True), + ft.Text("Footer"), + ], + ) + +ft.Route(path="products", component=ProductsLayout, outlet=True, children=[ + ft.Route(component=ProductsList, children=[ + ft.Route(path=":pid", component=ProductDetails), + ]), +]) +``` + +:::note[`use_route_location()` vs `use_view_path()`] +`use_route_location()` always returns the full current URL. `use_view_path()` +returns the URL for the *current view level only* — essential as `View.route` +when a single layout component wraps multiple child views, so the Flutter +Navigator can distinguish them. +::: + +The layout's shared UI appears on every child route's View, and each child +is still a separate View in the stack — back navigation works between them. +See [full example](../controls/router.md#managed-views--shared-layout-with-outlet). + +### Avoiding transition animation + +When switching between top-level NavigationRail destinations, set a fixed +`route` value on the root layout's View to prevent slide transitions: + +```python +@ft.component +def RootLayout(): + outlet = ft.use_route_outlet() + return ft.View( + route="/", # fixed key — no animation between top-level pages + can_pop=False, + controls=[ + ft.Row([ + ft.NavigationRail(...), + ft.Container(content=outlet, expand=True), + ], expand=True), + ], + ) +``` + +See [full example](../controls/router.md#managed-views--full-app-with-navigationrail). + +## Hooks reference + +| Hook | Returns | Description | +|------|---------|-------------| +| [use_route_params()](../types/use_route_params.md) | `dict[str, str]` | All dynamic segment values from the matched route chain | +| [use_route_location()](../types/use_route_location.md) | `str` | Current URL pathname | +| [use_view_path()](../types/use_view_path.md) | `str` | Resolved URL for the current view level (unique per view in `manage_views` mode) | +| [use_route_outlet()](../types/use_route_outlet.md) | component | Matched child route component (for layout routes) | +| [use_route_loader_data()](../types/use_route_loader_data.md) | `Any` | Return value of the current route's `loader` | +| [is_route_active(path)](../types/is_route_active.md) | `bool` | Whether `path` matches the current location | diff --git a/website/docs/cookbook/session-storage.md b/website/docs/cookbook/session-storage.md new file mode 100644 index 0000000000..eb8c61888f --- /dev/null +++ b/website/docs/cookbook/session-storage.md @@ -0,0 +1,60 @@ +--- +title: "Session Storage" +--- + +Flet provides an API for storing key-value data in user's session on a server side. + +:::caution +In the current Flet implementation the data stored in a session store +is transient and is not preserved between app restarts. +::: + +### Write data + +```python +# strings +page.session.store.set("key", "value") + +# numbers +page.session.store.set("number.setting", 12345) + +# booleans +page.session.store.set("bool_setting", True) + +# lists +page.session.store.set("favorite_colors", ["red", "green", "blue"]) +``` + +### Read data + +```python +# The value is automatically converted back to the original type +value = page.session.store.get("key") + +colors = page.session.store.get("favorite_colors") +# colors = ["red", "green", "blue"] +``` + +### Check key existence + +```python +page.session.store.contains_key("key") # True if the key exists +``` + +### Get all keys + +```python +page.session.store.get_keys() +``` + +#### Remove data by key + +```python +page.session.store.remove("key") +``` + +#### Clear all data + +```python +page.session.store.clear() +``` diff --git a/website/docs/cookbook/subprocess.md b/website/docs/cookbook/subprocess.md new file mode 100644 index 0000000000..7f3ee649ac --- /dev/null +++ b/website/docs/cookbook/subprocess.md @@ -0,0 +1,103 @@ +--- +title: "Subprocess" +--- + +In this cookbook recipe, you'll learn how to run external system commands from your +Flet app using Python's built-in [`subprocess`](https://docs.python.org/3/library/subprocess.html) module. + +This approach is useful when you need to interact with platform tools or system utilities +that are not exposed through Flet APIs. + +:::note[Note] +Running external commands is **not supported when your app runs in a browser**. +::: + +## Examples + +### Launching another Android app + +Sometimes your Flet app may need to open another Android application. +For example, you might want to open the **Settings** app so the user can adjust system or app settings. + +On Android, this can be done using the [`am start`](https://developer.android.com/tools/adb#IntentSpec) +command, which launches activities from the Android shell. + +The command requires the **component name** (`-n`) of the target activity in the form: `package.name/.ActivityName`. + +For example, the Android Settings app uses: + +```text +com.android.settings/.Settings +``` + +It is also recommended to pass the `--user` flag. Without it, the command may fail with an error such as: + +```bash +Security exception: Permission Denial: startActivityAsUser asks to run as +user -2 but is calling from uid u0a164; this requires android.permission.INTERACT_ACROSS_USERS_FULL +``` + +This happens because Android may attempt to launch the activity for a different user +than the one your app runs under. Setting `--user 0` ensures the command runs for the primary user. + +The full command therefore becomes: + +```bash +am start -n com.android.settings/.Settings --user 0 +``` + +And can be run from a Flet app like this: + +```python +import subprocess +import flet as ft + +def main(page: ft.Page): + def open_settings(e): + result = subprocess.run( + ["am", "start", "-n", "com.android.settings/.Settings", "--user", "0"], + shell=False, # default + capture_output=True, + text=True, + ) + + print("STDOUT:", result.stdout) + print("STDERR:", result.stderr) + + page.add( + ft.SafeArea( + content=ft.Button("Open Settings app", on_click=open_settings) + ) + ) + +ft.run(main) +``` + +Running this app on an Android device, you should see the **Settings** app launch when the button is clicked. + +#### Common Pitfall + +When using `subprocess.run()`, be careful with the `shell` argument. + +This will **not work correctly**: + +```python +subprocess.run( + ["am", "start", "-n", "com.android.settings/.Settings", "--user", "0"], + shell=True +) +``` + +Because when `shell=True` is used, the command must be passed as a **single string**, not a list. + +Correct usage: + +```python +subprocess.run( + "am start -n com.android.settings/.Settings --user 0", + shell=True +) +``` + +However, when possible, prefer **`shell=False` with a list of arguments**, +as shown in the main example. This is generally safer and avoids shell parsing issues. diff --git a/website/docs/cookbook/theming.md b/website/docs/cookbook/theming.md new file mode 100644 index 0000000000..de1f1ebf22 --- /dev/null +++ b/website/docs/cookbook/theming.md @@ -0,0 +1,74 @@ +--- +title: "Theming" +--- + +It is possible to configure your application and/or the containing controls to follow a particular themes. + +### App-wide themes + +The [`Page`](../controls/page.md) control (uppermost control in the tree) has two useful properties for this: [`theme`](../controls/page.md) +and [`dark_theme`](../controls/page.md) properties to configure the appearance/theme of the entire app in light and +dark theme modes respectively. + +Both of type [`Theme`](../types/theme/index.md), they represent the default/fallback themes to be used app-wide, +except explicitly modified/overriden in the tree. + +```python +page.theme = ft.Theme(color_scheme_seed=ft.Colors.GREEN) +page.dark_theme = ft.Theme(color_scheme_seed=ft.Colors.BLUE) +``` + +### Nested themes + +You can have a part of your app to use a different theme or override some theme styles for specific controls. + +Some container-like controls have `theme` and `theme_mode` properties of type +[`Theme`](../types/theme/index.md) and [`ThemeMode`](../types/thememode.md) respectively. + +Specifying `theme_mode` in the `Container` means you don't want to inherit parent theme mode, +but want a completely new, unique scheme for all controls inside the container. +However, if the container does not have `theme_mode` property set then the styles from its theme property +will override the ones from the parent inherited theme: + +```python +import flet as ft + +def main(page: ft.Page): + # Yellow page theme with SYSTEM (default) mode + page.theme = ft.Theme( + color_scheme_seed=ft.Colors.YELLOW, + ) + + page.add( + # Page theme + ft.Container( + content=ft.Button("Page theme button"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + padding=20, + width=300, + ), + + # Inherited theme with primary color overridden + ft.Container( + theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.PINK)), + content=ft.Button("Inherited theme button"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + padding=20, + width=300, + ), + + # Unique always DARK theme + ft.Container( + theme=ft.Theme(color_scheme_seed=ft.Colors.INDIGO), + theme_mode=ft.ThemeMode.DARK, + content=ft.Button("Unique theme button"), + bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST, + padding=20, + width=300, + ), + ) + +ft.run(main) +``` + +
Nested themes
diff --git a/website/docs/extend/built-in-extensions.md b/website/docs/extend/built-in-extensions.md new file mode 100644 index 0000000000..a7b1bb312a --- /dev/null +++ b/website/docs/extend/built-in-extensions.md @@ -0,0 +1,30 @@ +--- +title: "Built-in Extensions" +--- + +Flet controls based on 3rd-party Flutter packages that used to be a part of Flet repository, now have been moved to separate repos and published on pypi: + +* [flet-ads](https://pypi.org/project/flet-ads/) +* [flet-audio](https://pypi.org/project/flet-audio/) +* [flet-audio-recorder](https://pypi.org/project/flet-audio-recorder/) +* [flet-camera](https://pypi.org/project/flet-camera/) +* [flet-charts](https://pypi.org/project/flet-charts/) +* [flet-datatable2](https://pypi.org/project/flet-datatable2/) +* [flet-flashlight](https://pypi.org/project/flet-flashlight/) +* [flet-geolocator](https://pypi.org/project/flet-geolocator/) +* [flet-lottie](https://pypi.org/project/flet-lottie/) +* [flet-map](https://pypi.org/project/flet-map/) +* [flet-permission-handler](https://pypi.org/project/flet-permission-handler/) +* [flet-rive](https://pypi.org/project/flet-rive/) +* [flet-secure-storage](https://pypi.org/project/flet-secure-storage/) +* [flet-video](https://pypi.org/project/flet-video/) +* [flet-webview](https://pypi.org/project/flet-webview/) + +To use a built-in Flet extension in your project, add it to the `dependencies` section of your `pyproject.toml` file, for example: + +``` +dependencies = [ + "flet-audio", + "flet>=0.26.0", +] +``` diff --git a/website/docs/extend/user-extensions.md b/website/docs/extend/user-extensions.md new file mode 100644 index 0000000000..efcf1ada06 --- /dev/null +++ b/website/docs/extend/user-extensions.md @@ -0,0 +1,469 @@ +--- +title: "Creating an Extension" +--- + +While [Flet controls](/docs/controls) leverage many built-in [Flutter widgets](https://docs.flutter.dev/ui/widgets) to enable the creation of complex applications, not all Flutter widgets or third-party packages can be directly supported by the Flet team or included in the core Flet framework. At the same time, the Flutter ecosystem is vast and offers developers a wide range of possibilities to extend functionality beyond the core. + +To address this, the Flet framework provides an extensibility mechanism. This allows you to incorporate widgets and APIs from your own custom Flutter packages or [third-party libraries](https://pub.dev/packages?sort=popularity) directly into your Flet application. + +In this guide, you will learn how to create Flet extension from template and then customize it to integrate 3rd-party Flutter package into your Flet app. + +### Prerequisites + +To integrate custom Flutter package into Flet you need to have basic understanding of how to create Flutter apps and packages in Dart language and have Flutter development environment configured. See [Flutter Getting Started](https://docs.flutter.dev/get-started/install) for more information about Flutter and Dart. + +## Create Flet extension from template + +Flet now makes it easy to create and build projects with your custom controls based on Flutter widgets or Flutter 3rd-party packages. In the example below, we will be creating a custom Flet extension based on the [flutter_spinkit](https://pub.dev/packages/flutter_spinkit) package. + +**Step 1.** Create new virtual environment and [install Flet](../getting-started/installation.md) there. + +**Step 2.** Create new extension project from template. + +``` +flet create --template extension --project-name flet-spinkit +``` + +A project with new FletSpinkit control will be created. The control is just a Flutter Text widget with text property, which we will customize later. + +**Step 3.** Build example app. + +Flet project created from extension template has `examples/flet_spinkit_example` folder with the example app. + +When in the folder where your `pyproject.toml` for the app is (`examples/flet_spinkit_example`), run `flet build` command, for example, for macos: + +``` +flet build macos -v +``` + +Open the app and see the new custom Flet Control: + +``` +open build/macos/flet-spinkit-example.app +``` + + + +#### Change Python files + +Once the project was built for desktop once, you can make changes to your python files and run it without rebuilding. + +First, if you are not using uv, install dependencies from pyproject.toml: + +``` +pip install . +``` +or +``` +poetry install +``` + +Now you can make changes to your example app main.py: + +```python +import flet as ft + +from flet_spinkit import FletSpinkit + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.Container( + height=150, + width=300, + alignment=ft.Alignment.CENTER, + bgcolor=ft.Colors.PINK_200, + content=FletSpinkit( + tooltip="My new PINK FletSpinkit Control tooltip", + value="My new PINK FletSpinkit Flet Control", + ), + ), + ) + +ft.run(main) +``` + +and run: + +``` +flet run +``` + + + +#### Change Flutter package + +When you make any changes to your flutter package, you need to rebuild: + +``` +flet build macos -v +``` + +If you need to debug, run this command: + +``` +build/macos/flet-spinkit-example.app/Contents/MacOS/flet-spinkit-example --debug +``` + +## Integrate 3rd-party Flutter package + +Let's integrate [flutter_spinkit](https://pub.dev/packages/flutter_spinkit) package into our Flet app. + +**Step 1.** Add dependency + +Go to `src/flutter/flet_spinkit` folder and run this command to add dependency to `flutter_spinkit` to `pubspec.yaml`: + +``` +flutter pub add flutter_spinkit +``` + +Read more information about using Flutter packages [here](https://docs.flutter.dev/packages-and-plugins/using-packages). + +**Step 2.** Modify `dart` file + +In the `src/flutter/flet_spinkit/lib/src/flet_spinkit.dart` file, add import statement and replace Text widget with `SpinKitRotatingCircle` widget: + +```dart +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; + +class FletSpinkitControl extends StatelessWidget { + final Control control; + + const FletSpinkitControl({ + super.key, + required this.control, + }); + + @override + Widget build(BuildContext context) { + Widget myControl = SpinKitRotatingCircle(color: Colors.red, size: 100.0); + + return LayoutControl(control: control, child: myControl); + } +} +``` + +**Step 3.** Rebuild example app + +Go to `examples/flet_spinkit_example`, clear cache and rebuild your app: + +``` +flet build macos -v +``` + +**Step 4.** Run your app + + + +## Flet extension structure + +After creating new Flet project from extension template, you will see the following folder structure: + +``` +├── LICENSE +├── mkdocs.yml +├── README.md +├── docs +│ └── index.md +│ └── FletSpinkit.md +├── examples +│ └── flet_spinkit_example +│ ├── README.md +│ ├── pyproject.toml +│ └── src +│ └── main.py +├── pyproject.toml +└── src + ├── flet_spinkit + │ ├── __init__.py + │ └── flet_spinkit.py + └── flutter + └── flet_spinkit + ├── CHANGELOG.md + ├── LICENSE + ├── README.md + ├── lib + │ ├── flet_spinkit.dart + │ └── src + │ ├── create_control.dart + │ └── flet_spinkit.dart + └── pubspec.yaml +``` + +Flet extension consists of: +* **package**, located in `src` folder +* **example app**, located in `examples/flet-spinkit_example` folder +* **docs**, located in `docs` folder + +### Package + +Package is the component that will be used in your app. It consists of two parts: Python and Flutter. + +#### Python + +##### flet_spinkit.py + +Defines the Python-side Flet control. `FletSpinkit` is registered with `@ft.control("flet_spinkit")` and inherits from `ft.LayoutControl`, which ties it to the Flutter `Control.type` handled in the extension. The class currently includes a value: str property and a placeholder docstring. + +#### Flutter + +##### pubspec.yaml + +Flutter package manifest for the extension. Declares SDK constraints and dependencies. Notable deps: + +* `flet` for Flet extension APIs +* `flutter_spinkit` for the spinner widgets used by the control + +##### flet_spinkit.dart + +Library entrypoint. Exports the public `Extension` class from `extension.dart`. + +##### src/extension.dart + +Registers the extension with Flet. `Extension.createWidget` maps `Control.type` to the Flutter widget; currently maps "flet_spinkit" to FletSpinkitControl. + +##### src/flet_spinkit.dart + +Flutter wrapper widget for the control. `FletSpinkitControl` builds a `SpinKitRotatingCircle` and wraps it with `LayoutControl` so layout/state from the Python control are applied. + +### Example app + +##### src/main.py + +Python program that uses Flet Python control. + +##### pyproject.toml + +Here you specify dependency to your package, which can be: + +* **Path dependency** + +Absolute path to your Flet extension folder, for example: + +``` +dependencies = [ + "flet-spinkit @ file:///Users/user-name/projects/flet-spinkit", + "flet>=0.80.2", +] +``` + +* **Git dependency** + +Link to git repository, for example: + +``` +dependencies = [ + "flet-ads @ git+https://github.com/flet-dev/flet-ads.git", + "flet>=0.80.2", +] +``` + +* **PyPi dependency** + +Name of the package published on pypi.org, for example: + +``` +dependencies = [ + "flet-ads", + "flet>=0.80.2", +] +``` + +### Docs + +If you are planning to share your extension with community, you can easily generate documentation from your source code using [mkdocs](https://www.mkdocs.org/). + +Flet extension comes with a `docs` folder containing initial files for your documentation and a `mkdocs.yml` file at the project root. + +From the folder that contains `mkdocs.yml`, run the following command to see how your docs look locally: + +``` +mkdocs serve +``` + +Open http://127.0.0.1:8000 in your browser: + + + +Once your documentation is ready, if your package is hosted on GitHub, your can run the following command to host your documentation on GitHub pages: + +``` +mkdocs gh-deploy +``` + +You may find [this guide](https://realpython.com/python-project-documentation-with-mkdocs/#step-5-build-your-documentation-with-mkdocs) helpful to get started with mkdocs. + +## Customize properties + +In the example above, Spinkit control creates a hardcoded Flutter widget. Now let's customize its properties. + +### Common properties + +Generally, there are three types of controls in Flet: + +1. Visual controls that are added to the app/page surface, such as FletSpinkit. + +2. Dialog and other popup controls (dialogs, pickers, panels, etc.) that are opened from the page (for example, `page.open(dlg)`). + +3. Services (Clipboard, Battery, Video, Audio, etc.) that are created as standalone instances and automatically registered with the page. + +When creating a visual control that should participate in layout (size, position, transforms, margin, etc.), define a dataclass-based control annotated with `@ft.control("control_name")` and inherit from [`LayoutControl`](../controls/layoutcontrol.md). In its Dart counterpart (`src/flet_spinkit.dart`), wrap your Flutter widget with `LayoutControl(...)`. + +When creating a dialog or other popup control (opened with `page.open(...)`), define a dataclass-based control annotated with `@ft.control("control_name")` and inherit from [`DialogControl`](../controls/dialogcontrol.md). In its Dart counterpart, show the dialog/popup (for example, `showDialog` or `showModalBottomSheet`) and return a placeholder widget like `SizedBox.shrink()` instead of wrapping with `LayoutControl(...)` or `BaseControl(...)`. + +When creating a service control (Clipboard, Battery, Video, Audio, etc.), define a dataclass-based control annotated with `@ft.control("control_name")` and inherit from [`Service`](../controls/service.md). In its Dart counterpart, implement `FletService` and register it via `FletExtension.createService` (no widget wrapper). + +You can use all `LayoutControl`, `DialogControl`, and `Service` properties inherited by your dataclass-based control without re-declaring them as fields (unless you want to override defaults or metadata). + +If you have created your extension project from Flet extension template, your Python Control is already inherited from `LayoutControl` and you can use its properties in your example app: + +```python +import flet as ft + +from flet_spinkit import FletSpinkit + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.Stack( + [ + ft.Container(height=200, width=200, bgcolor=ft.Colors.BLUE_100), + FletSpinkit(opacity=0.5, tooltip="Spinkit tooltip", top=0, left=0), + ] + ) + ) + +ft.run(main) +``` + + + +### Control-specific properties + +Now that you have taken full advantage of the properties Flet `LayoutControl` offer, let's define the properties that are specific to the new Control you are building. + +In the FletSpinkit example, let's define its `color` and `size`. + +In Python class, define new `color` and `size` properties: + +```python +from typing import Optional + +import flet as ft + +@ft.control("flet_spinkit") +class FletSpinkit(ft.LayoutControl): + """ + FletSpinkit Control description. + """ + + color: Optional[ft.ColorValue] = None + size: float = 100.00 +``` + +In `src/flet_spinkit.dart` file, use helper methods `getColor` and `getDouble` to access color and size values: + +```dart +import 'package:flet/flet.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; + +class FletSpinkitControl extends StatelessWidget { + final Control control; + + const FletSpinkitControl({ + super.key, + required this.control, + }); + + @override + Widget build(BuildContext context) { + Widget myControl = SpinKitRotatingCircle( + color: control.getColor("color", context), + size: control.getDouble("size") ?? 100.0, + ); + + return LayoutControl(control: control, child: myControl); + } +} +``` + +Use `color` and `size` properties in your app: + +```python +import flet as ft + +from flet_spinkit import FletSpinkit + +def main(page: ft.Page): + page.vertical_alignment = ft.MainAxisAlignment.CENTER + page.horizontal_alignment = ft.CrossAxisAlignment.CENTER + + page.add( + ft.Stack( + controls=[ + ft.Container(height=200, width=200, bgcolor=ft.Colors.BLUE_100), + FletSpinkit( + color=ft.Colors.YELLOW, + size=150, + opacity=0.5, + tooltip="Spinkit tooltip", + top=0, + left=0, + ), + ] + ) + ) + +ft.run(main) +``` + +Rebuild and run: + + + +:::warning[Important: Default values must match on both sides] + +Properties with default values on the Python side are **not sent to Flutter** when the user hasn't changed them from the default. This means your Dart code **must provide the same default value** for every property that has one in Python. + +For example, if your Python control declares: + +```python +size: float = 100.0 +animate: bool = True +``` + +Then your Dart code **must** use matching defaults: + +```dart +// Correct - defaults match Python +final size = control.getDouble("size", 100.0)!; +final animate = control.getBool("animate", true)!; + +// Wrong - no default, will be null when user doesn't set the property +final size = control.getDouble("size"); // returns null! +final animate = control.getBool("animate"); // returns null! +``` + +This also applies to `@ft.value` types parsed with helper functions. If a value type field has a default, the corresponding `parseDouble()`, `parseBool()`, `parseDuration()`, etc. call on the Dart side must provide the same default. + +Common pitfalls: + +- **Missing defaults**: `control.getDouble("prop")` instead of `control.getDouble("prop", 0.0)!` +- **Mismatched defaults**: Python has `True` but Dart defaults to `false` +- **Unit mismatches**: Python uses `Duration(milliseconds=150)` but Dart uses `Duration(microseconds: 150)` +- **Empty collections**: `field(default_factory=list)` means an empty list won't be sent; Dart must handle null with `?? const []` + +::: + +You can find source code for this example [here](https://github.com/flet-dev/flet-spinkit). + +## Examples + +Flet has controls that are implemented as [built-in extensions](built-in-extensions.md) and could serve as a starting point for your own controls. diff --git a/website/docs/fastapi/app.md b/website/docs/fastapi/app.md new file mode 100644 index 0000000000..3673383250 --- /dev/null +++ b/website/docs/fastapi/app.md @@ -0,0 +1,7 @@ +--- +title: "app" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/fastapi/app_manager.md b/website/docs/fastapi/app_manager.md new file mode 100644 index 0000000000..4d1d744f13 --- /dev/null +++ b/website/docs/fastapi/app_manager.md @@ -0,0 +1,7 @@ +--- +title: "app_manager" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/fastapi/fastapi.md b/website/docs/fastapi/fastapi.md new file mode 100644 index 0000000000..3291988705 --- /dev/null +++ b/website/docs/fastapi/fastapi.md @@ -0,0 +1,7 @@ +--- +title: "FastAPI" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/fastapi/fletapp.md b/website/docs/fastapi/fletapp.md new file mode 100644 index 0000000000..74c499dba7 --- /dev/null +++ b/website/docs/fastapi/fletapp.md @@ -0,0 +1,7 @@ +--- +title: "FletApp" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/fastapi/fletoauth.md b/website/docs/fastapi/fletoauth.md new file mode 100644 index 0000000000..6c80eb1596 --- /dev/null +++ b/website/docs/fastapi/fletoauth.md @@ -0,0 +1,7 @@ +--- +title: "FletOAuth" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/fastapi/fletstaticfiles.md b/website/docs/fastapi/fletstaticfiles.md new file mode 100644 index 0000000000..ace6dd4301 --- /dev/null +++ b/website/docs/fastapi/fletstaticfiles.md @@ -0,0 +1,7 @@ +--- +title: "FletStaticFiles" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/fastapi/fletupload.md b/website/docs/fastapi/fletupload.md new file mode 100644 index 0000000000..3cd72317e1 --- /dev/null +++ b/website/docs/fastapi/fletupload.md @@ -0,0 +1,7 @@ +--- +title: "FletUpload" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/getting-started/create-flet-app.md b/website/docs/getting-started/create-flet-app.md new file mode 100644 index 0000000000..c446c3bce8 --- /dev/null +++ b/website/docs/getting-started/create-flet-app.md @@ -0,0 +1,111 @@ +--- +title: "Creating a new Flet app" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Create a new directory (or directory with `pyproject.toml` already exists if initialized with a project manager) and switch into it. + +To create a new "minimal" Flet app run the following command: + + + +```bash +uv run flet create +``` + + +```bash +flet create +``` + + +:::danger[Important] +Any existing `README.md` or `pyproject.toml` (for example, created by `uv init`) +will be replaced by the one created by [`flet create`](../cli/flet-create.md) command. +::: + +The command will create the following directory structure: + +```tree +README.md +pyproject.toml +src + assets + icon.png + main.py # (1)! +storage + data + temp +``` + +1. Contains a simple Flet program. + It has `main()` function where you would add UI elements (controls) to a page or a window. + The application ends with a `ft.run()` function which initializes the Flet app and [runs](running-app.md) `main()`. + +You can find more information about `flet create` command [here](../cli/flet-create.md). + +## Auto-update + +Flet automatically calls `page.update()` (or `.update()` on the nearest isolated ancestor) at the end of every event handler and `main()` function. This means you don't need to call `.update()` yourself in most cases: + +```python +import flet as ft + +def main(page: ft.Page): + def button_click(e): + page.controls.append(ft.Text("Clicked!")) + # no need to call page.update() — it happens automatically + + page.controls.append(ft.Button("Click me", on_click=button_click)) + # no need to call page.update() here either + +ft.run(main) +``` + +:::note[Note] +If your event handler already calls `.update()` explicitly (e.g. code written for Flet 0.x), the automatic update is skipped to avoid a redundant double update. +::: + +### Disabling auto-update + +You can disable auto-update for fine-grained control over when updates are sent to the client. Use `ft.context.disable_auto_update()` and `ft.context.enable_auto_update()` to toggle the behavior. + +When called inside a handler, the setting applies to the current handler context only: + +```python +import flet as ft + +def main(page: ft.Page): + def add_many_items(e): + ft.context.disable_auto_update() + for i in range(100): + page.controls.append(ft.Text(f"Item {i}")) + page.update() # single update for all 100 items + + page.controls.append(ft.Button("Add items", on_click=add_many_items)) + +ft.run(main) +``` + +When called outside of event handlers (e.g. at the module level), it controls the global default for the entire app: + +```python +import flet as ft + +# disable auto-update globally +ft.context.disable_auto_update() + +def main(page: ft.Page): + def button_click(e): + page.controls.append(ft.Text("Clicked!")) + page.update() # must call explicitly since auto-update is off + + page.controls.append(ft.Button("Click me", on_click=button_click)) + page.update() + +ft.run(main) +``` + +**Now let's see Flet in action by [running the app](running-app.md)!** diff --git a/website/docs/getting-started/installation.md b/website/docs/getting-started/installation.md new file mode 100644 index 0000000000..3236a7d21d --- /dev/null +++ b/website/docs/getting-started/installation.md @@ -0,0 +1,157 @@ +--- +title: "Installation" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +## Prerequisites + +### Python version + +Flet requires [Python](https://www.python.org/downloads/) 3.10 or later. (1) + +1. Check your Python version using `python --version`. + +### Operating System + +#### macOS + +Flet supports macOS 12 (Monterey) or later. + +#### Windows + +Flet supports 64-bit version of Microsoft Windows 10 and Windows 11. + +#### Linux + +Flet supports Debian 10, 11 and 12 and Ubuntu 20.04, 22.04 and 24.04 LTS. + +
+Desktop flavor (audio & video support) + +On Linux, the Flet desktop client is available in two flavors: **full** and **light**. + +The **light** flavor (default on Linux) does not include audio and video extensions, resulting in a smaller download. The **full** flavor bundles audio and video support out of the box. + +To select the flavor, either set the `FLET_DESKTOP_FLAVOR` environment variable: + +```bash +export FLET_DESKTOP_FLAVOR=full +``` + +or add the setting to your project's `pyproject.toml`: + +```toml +[tool.flet] +desktop_flavor = "full" +``` + +If you use the **light** flavor and need audio or video, you will need to install the required libraries yourself — see the [Audio](../services/audio/index.md#usage) and [Video](../controls/video/index.md#linux) setup guides. +
+ +
+Windows Subsystem for Linux (WSL) + +Flet apps can be run on WSL 2 (Windows Subsystem for Linux 2). + +However, if you are getting `cannot open display` error follow this +[guide](https://github.com/microsoft/wslg/wiki/Diagnosing-%22cannot-open-display%22-type-issues-with-WSLg) for troubleshooting. +
+ +## Creating a virtual environment (venv) + +We recommend using a virtual environment for your Flet projects to keep dependencies +isolated and avoid conflicts with your other Python projects. + +First, create a new directory for your Flet project and switch into it: + +```bash +mkdir my-app +cd my-app +``` + +Next, create and activate a virtual environment (we recommend using `uv` as package manager): + + + +[**uv**](https://docs.astral.sh/uv/) is "An extremely fast Python package and project manager, written in Rust". + +[Install `uv`](https://docs.astral.sh/uv/getting-started/installation) if you haven't already, then run the following commands: + +```bash +uv init --python='>=3.10' +uv venv +source .venv/bin/activate # (1)! +``` + +1. If you are on Windows, use `.venv\Scripts\activate` instead. + + +Using Python's built-in [`venv`](https://docs.python.org/3/library/venv.html) module: +```bash +python -m venv .venv # (1)! +source .venv/bin/activate # (2)! +``` + +1. On Unix-like systems (Linux, macOS), use `python3 -m venv .venv` if `python` points to Python 2.x. +2. If you are on Windows, use `.venv\Scripts\activate` instead. + + +## Install Flet + +To install Flet and add it to your project dependencies, +do the following depending on your package manager: + + + +```bash +uv add 'flet[all]' +``` + + +```bash +pip install 'flet[all]' # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Verify installation + +To make sure Flet has been installed correctly, we can check its version using the `--version` (or `-V`) flag or the [`doctor`](../cli/flet-doctor.md) command: + + + +```bash +uv run flet --version +# or +uv run flet doctor +``` + + +```bash +flet --version +# or +flet doctor +``` + + +Now you are ready to [create your first Flet app](create-flet-app.md). + +## Upgrade Flet + +To upgrade Flet to its latest version: + + + +```bash +uv add 'flet[all]' --upgrade +``` + + +```bash +pip install 'flet[all]' --upgrade +``` + + diff --git a/website/docs/getting-started/running-app.md b/website/docs/getting-started/running-app.md new file mode 100644 index 0000000000..84e5b67b49 --- /dev/null +++ b/website/docs/getting-started/running-app.md @@ -0,0 +1,109 @@ +--- +title: "Running a Flet app (Hot Reload)" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {Image} from '@site/src/components/crocodocs'; + +Flet apps can be executed as either desktop or web applications using the [`flet run`](../cli/flet-run.md) command. +Doing so will start the app in a native OS window or a web browser, respectively, with hot reload enabled to view changes in real-time. + +## Desktop app + +To run Flet app as a desktop app, use the following command: + + + +```bash +uv run flet run +``` + + +```bash +flet run +``` + + +When you run the command without any arguments, `main.py` script in the current directory will be executed, by default. + +If you need to provide a different path, use the following command: + + + +```bash +uv run flet run [script] +``` + + +```bash +flet run [script] +``` + + +Where `[script]` is a relative (ex: `counter.py`) or absolute (ex: `/Users/john/projects/flet-app/main.py`) path to the Python script you want to run. + +The app will be started in a native OS window: + +
+ +- **macOS** + + --- + macOS + +- **Windows** + + --- + windows + +
+ +## Web app + +To run Flet app as a web app, use the `--web` (or `-w`) option: + + +```bash +uv run flet run --web [script] # (1)! +``` + +1. A fixed port can be specified using `--port` ( or `-p`) option, followed by the port number. + + +```bash +flet run --web [script] # (1)! +``` + +1. A fixed port can be specified using `--port` ( or `-p`) option, followed by the port number. + + +A new browser window/tab will be opened and the app will be using a random TCP port: + +Web + +## Watching for changes + +By default, Flet will watch the script file that was run and reload the app whenever the contents +of this file are modified+saved, but will **not** watch for changes in other files. + +To modify this behavior, you can use one or more of these [`flet run`](../cli/flet-run.md) options: + +* `-d` or `--directory` to watch for changes in the `[script]`s directory only +* `-r` or `--recursive` to watch for changes in the `[script]`s directory and all sub-directories recursively + +:::note[Example] + + + +```bash +uv run flet run --recursive [script] +``` + + +```bash +flet run --recursive [script] +``` + + +::: diff --git a/website/docs/getting-started/testing-on-mobile.md b/website/docs/getting-started/testing-on-mobile.md new file mode 100644 index 0000000000..b7b7658138 --- /dev/null +++ b/website/docs/getting-started/testing-on-mobile.md @@ -0,0 +1,94 @@ +--- +title: "Testing on Mobile" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {Image} from '@site/src/components/crocodocs'; + +Start building awesome mobile apps in Python using just your computer and mobile phone! + +:::note[Important] +- Make sure your computer fulfills [these requirements](installation.md#prerequisites). +- Your device and computer must be connected to the same Wi-Fi or local network. +- We recommend starting with the [creation of a new virtual environment](installation.md#creating-a-virtual-environment-venv). +::: + + + + +Install the [Flet iOS app](https://apps.apple.com/app/flet/id1624979699) on your iOS device. +You will be using this app to see how your Flet project is working on iPhone or iPad. + +Get it on App Store + +Run the following command to start Flet development server with your app: + + + +```bash +uv run flet run --ios [script] # (1)! +``` + +1. [`flet run`](../cli/flet-run.md) starts your app in hot reload mode. More info [here](running-app.md). + + +```bash +flet run --ios [script] # (1)! +``` + +1. [`flet run`](../cli/flet-run.md) starts your app in hot reload mode. More info [here](running-app.md#watching-for-changes). + + + + + +Install the [Flet Android app](https://play.google.com/store/apps/details?id=com.appveyor.flet) on your Android device. +You will be using this app to see how your Flet project is working on Android device. + +Get it on Google Play + +Run the following command to start Flet development server with your app: + + + +```bash +uv run flet run --android [script] # (1)! +``` + +1. [`flet run`](../cli/flet-run.md) starts your app in hot reload mode. More info [here](running-app.md). + + +```bash +flet run --android [script] # (1)! +``` + +1. [`flet run`](../cli/flet-run.md) starts your app in hot reload mode. More info [here](running-app.md#watching-for-changes). + + + + +A QR code with encoded project URL will be displayed in the terminal: + +app-qr-code + +Open **Camera** app on your Android device, point to QR code you got and click URL to open it in Flet app. + +Try updating your `[script]` - the app will be instantly refreshed on your Android device. + +To return to "Home" tab either: + +* Long-press anywhere on the screen with 3 fingers or +* Shake your Android device. + +You can also "manually" add a new project by clicking **"+"** floating action button in the app and typing in its URL. + +:::note[Examples] + +- Below is a URL to a "Counter" Flet app that we hosted for testing purposes: + ``` + https://flet-counter-test-ios.fly.dev + ``` +- The "Gallery" tab of the app has some more examples that you can try out. +- Explore [Flet examples](https://github.com/flet-dev/flet/blob/main/sdk/python/examples) for even more examples. +::: diff --git a/website/docs/index.md b/website/docs/index.md new file mode 100644 index 0000000000..c08e643d98 --- /dev/null +++ b/website/docs/index.md @@ -0,0 +1,66 @@ +--- +title: "Introduction" +--- + +Flet is a framework that allows building web, desktop and mobile applications in Python without prior experience in frontend development. + +## Flet app example + +Below is a simple "Counter" app, with a text field and two buttons to increment and decrement the counter value: + +```python title="counter.py" +import flet as ft + +def main(page: ft.Page): + page.title = "Flet counter example" + page.vertical_alignment = ft.MainAxisAlignment.CENTER + + input = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100) + + def minus_click(e): + input.value = str(int(input.value) - 1) + + def plus_click(e): + input.value = str(int(input.value) + 1) + + page.add( + ft.Row( + alignment=ft.MainAxisAlignment.CENTER, + controls=[ + ft.IconButton(ft.Icons.REMOVE, on_click=minus_click), + input, + ft.IconButton(ft.Icons.ADD, on_click=plus_click), + ], + ) + ) + +ft.run(main) +``` + +To run the app, [install `flet`](getting-started/installation.md): + +```bash +pip install 'flet[all]' +``` + +then launch the app: + +```bash +flet run counter.py +``` + +This will open the app in a native OS window - what a nice alternative to Electron! 🙂 + +

+ +

+ +To run the same app as a web app use `--web` option with `flet run` command: + +```bash +flet run --web counter.py +``` + +

+ +

diff --git a/website/docs/publish/android.md b/website/docs/publish/android.md new file mode 100644 index 0000000000..9d1dadf50b --- /dev/null +++ b/website/docs/publish/android.md @@ -0,0 +1,707 @@ +--- +title: "Packaging app for Android" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Instructions for packaging a Flet app into an +Android APK and Android App Bundle (AAB). + +:::tip[Info] +This guide provides detailed Android-specific information. +Complementary and more general information is available [here](index.md). +::: + +## Prerequisites + +### Android SDK + +The build process requires both **Java** (JDK 17) and the **Android SDK**. + +If either component is missing or an incompatible version is detected, the required tools will be +**automatically installed** during the first run of the [`flet build`](../cli/flet-build.md) command. + +- The JDK is installed in `$HOME/java/` (for example, `17.0.13+11`). +- If [**Android Studio**](https://developer.android.com/studio) is installed, Flet CLI will use its SDK: + - macOS: `~/Library/Android/sdk` + - Windows: `%LOCALAPPDATA%\Android\Sdk` + - Linux: `~/Android/Sdk` +- Otherwise, a standalone Android SDK is installed in: + - macOS/Linux: `~/Android/sdk` + - Windows: `%USERPROFILE%\Android\sdk` + +`ANDROID_HOME` and `ANDROID_SDK_ROOT` are also respected if set. + +### Android wheels for binary Python packages + +Binary Python packages (in contrast to "pure" Python packages written in Python only) +are packages that are partially written in C, Rust, or other languages producing native code. +Example packages are `numpy`, `cryptography`, or `pydantic-core`. + +Make sure all non-pure (binary) packages used in your Flet app have +[pre-built wheels for Android](../reference/binary-packages-android-ios.md). + +## `flet build apk` + +:::note[Note] +This command can be run on a **macOS**, **Linux**, or **Windows**. +::: + +Builds a **release** Android APK. + +Release builds are optimized for production, meaning they **don’t support debugging** +and are intended for publishing to app stores such as Google Play. + +For Play Store deployment, it’s recommended to: + +- Use an [**Android App Bundle (AAB)**](#flet-build-aab) for more efficient delivery and smaller install size +- Or [**split the APK by ABI**](#split-apk-per-abi) to reduce the APK size + +### Split APK per ABI + +Android devices use different CPUs, so APKs can target different +[Application Binary Interfaces (ABIs)](https://developer.android.com/ndk/guides/abis). + +By default, Flet builds a single "fat" APK that contains +native binaries for all supported ABIs. This maximizes +device compatibility but increases APK size. + +Enabling ABI splits produces one APK per ABI, which reduces file size but +requires distributing the correct APK for each device. + +#### Supported target architectures + +The following target architectures are supported: + +- [`arm64-v8a`](https://developer.android.com/ndk/guides/abis#arm64-v8a) +- [`armeabi-v7a`](https://developer.android.com/ndk/guides/abis#v7a) +- [`x86_64`](https://developer.android.com/ndk/guides/abis#86-64) +- [`x86`](https://developer.android.com/ndk/guides/abis#x86) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--split-per-abi`](../cli/flet-build.md#--split-per-abi) +2. `[tool.flet.android].split_per_abi` +3. `false` + +When enabled, 3 APKs are produced by default, one for each of the following ABIs: `arm64-v8a`, +`armeabi-v7a`, and `x86_64`. These can be customized by setting [`target architectures`](index.md#target-architecture). + +#### Example + + + +```bash +flet build apk --split-per-abi +``` + + +```toml +[tool.flet.android] +split_per_abi = true +``` + + +## `flet build aab` + +:::note[Note] +This command can be run on a **macOS**, **Linux**, or **Windows**. +::: + +Builds a **release** [Android App Bundle (AAB)](https://developer.android.com/guide/app-bundle) file. + +Release builds are optimized for production, meaning they **don’t support debugging** +and are intended for publishing to app stores such as the [Google Play Store](https://play.google.com/store/). + +It is recommended to use this AAB format (instead of [APK](#flet-build-apk)) for publishing to the +Google Play Store due to its optimized app size. + +If you need to limit the ABIs included in the bundle, use +[`--arch`](index.md#target-architecture) / `[tool.flet.android].target_arch` +while `split_per_abi` is `false`. + +## Signing an Android bundle + +Android requires that all APKs be digitally signed with a certificate before they are installed +on a device or updated. When releasing using [Android App Bundles](#flet-build-aab), you need to sign your app bundle +with an upload key before uploading it to the Play Console, and Play App Signing takes care of the rest. +For apps distributing using APKs on the Play Store or on other stores, you must manually sign your APKs for upload. + +For detailed information, see this [guide](https://developer.android.com/studio/publish/app-signing). + +To publish on the Play Store, you need to sign your app with a digital certificate. + +Android uses two signing keys: upload and app signing. + +- Developers upload an `.aab` or `.apk` file signed with an upload key to the Play Store. +- The end-users download the `.apk` file signed with an app signing key. + +To create your app signing key, use Play App Signing as described in the +[official Play Store documentation](https://support.google.com/googleplay/android-developer/answer/7384423?hl=en). + +To sign your app, use the following instructions. + +:::note[Note] +If you don't provide an upload keystore, release builds are signed with the +debug key. This is fine for local testing but cannot be uploaded to the Play Store. +::: + +### Create an upload keystore + +If you have an existing keystore, skip to the next step. +If not, create one using one of the following methods: + +1. Follow the [Android Studio key generation steps](https://developer.android.com/studio/publish/app-signing#generate-key). +2. Run the following command at the command line: + On macOS or Linux, use the following command: + + ```bash + keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \ + -keysize 2048 -validity 10000 -alias upload + ``` + + On Windows, use the following command in PowerShell: + + ```powershell + keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks ` + -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 ` + -alias upload + ``` + You will be prompted for several details, such as a keystore password, + a key alias, your names, and location. Remember the password and alias + for use in the configuration steps below. + + A file named `upload-keystore.jks` will be created in your home directory. + If you want to store it elsewhere, change the argument passed to the `-keystore` parameter. + The location of the keystore file is equally important for the [key store](#key-store) step below. + +:::note[Note] + - The `keytool` command might not be in your path—it's part of Java, which is installed as part of Android Studio. + For the concrete path, run `flutter doctor -v` and locate the path printed after 'Java binary at:'. + Then use that fully qualified path replacing `java` (at the end) with `keytool`. + If your path includes space-separated names, such as Program Files, use platform-appropriate notation + for the names. For example, on macOS and Linux use `Program\ Files`, and on Windows use `"Program Files"`. + + - The `-storetype JKS` tag is only required for Java 9 or newer. + As of the Java 9 release, the keystore type defaults to PKCS12. +::: + +:::warning[Important] +Keep your `keystore` file private; never check it into public source control! +::: + +### Key alias + +An alias name for the key within the keystore. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-signing-key-alias`](../cli/flet-build.md#--android-signing-key-alias) +2. `FLET_ANDROID_SIGNING_KEY_ALIAS` +3. `[tool.flet.android.signing].key_alias` +4. `"upload"` + +#### Example + + + +```bash +flet build aab --android-signing-key-alias value +``` + + +```toml +[tool.flet.android.signing] +key_alias = "value" +``` + + +```dotenv +FLET_ANDROID_SIGNING_KEY_ALIAS="value" +``` + + +### Key store + +The path to the keystore file (with extension `.jks`). + +If you used the CLI commands [above](#create-an-upload-keystore) as-is, this file might be +located at `/Users//upload-keystore.jks` on macOS +or `C:\Users\\upload-keystore.jks` on Windows. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-signing-key-store`](../cli/flet-build.md#--android-signing-key-store) +2. `[tool.flet.android.signing].key_store` +3. `FLET_ANDROID_SIGNING_KEY_STORE` + +#### Example + + + +```bash +flet build aab --android-signing-key-store path/to/store.jks +``` + + +```toml +[tool.flet.android.signing] +key_store = "path/to/store.jks" +``` + + +```dotenv +FLET_ANDROID_SIGNING_KEY_STORE="path/to/store.jks" +``` + + +### Key store password + +A password to unlock the keystore file (can contain multiple key entries). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-signing-key-store-password`](../cli/flet-build.md#--android-signing-key-store-password) +2. `FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD` +3. [key password](#key-password) + +#### Example + + + +```bash +flet build aab --android-signing-key-store-password value +``` + + +For security reasons, the keystore password is not read from `pyproject.toml` to +prevent accidental exposure in source control. See the other tabs for supported alternatives. + + +```dotenv +FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD="value" +``` + + +### Key password + +A password used to access the private key inside the keystore. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-signing-key-password`](../cli/flet-build.md#--android-signing-key-password) +2. `FLET_ANDROID_SIGNING_KEY_PASSWORD` +3. [key store password](#key-store-password) + +#### Example + + + +```bash +flet build aab --android-signing-key-password value +``` + + +For security reasons, the keystore password is not read from `pyproject.toml` to +prevent accidental exposure in source control. See the other tabs for supported alternatives. + + +```dotenv +FLET_ANDROID_SIGNING_KEY_PASSWORD="value" +``` + + +## Android Manifest + +The [Android Manifest](https://developer.android.com/guide/topics/manifest/manifest-intro) describes +essential information about your app to the Android build tools, +the Android operating system, and Google Play. The file in which this information is written +is `AndroidManifest.xml`, which gets populated with the information you provide. + +### Application attributes + +You can add or override attributes on the `` element of the +`AndroidManifest.xml` file in the [build template](index.md#build-template). + +See also: + +- [`` element](https://developer.android.com/guide/topics/manifest/application-element) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. `[tool.flet.android.manifest_application]` + +#### Example + + + +```toml +[tool.flet.android.manifest_application] +usesCleartextTraffic = "true" +allowBackup = "false" +``` + + +
+Template translation + +In the [`AndroidManifest.xml`](index.md#build-template), +the `pyproject.toml` example above will be translated accordingly into this: + +```xml + + +``` +
+ +### Meta-data + +A name-value pair for an item of additional, arbitrary data that can be supplied to the parent component. +More information [here](https://developer.android.com/guide/topics/manifest/meta-data-element). + +A meta-data item is composed of: + +- `name`: A unique name for the item, usually with a Java-style naming convention, for example `"com.sample.project.activity.fred"`. +- `value`: The value of the item. Android supports strings, integers, booleans, and floats. + Flet writes values as strings, so pass the literal value you want Android to read + (for example `"true"`, `"123"`, `"1.23"`). + +See also: + +- [`` element](https://developer.android.com/guide/topics/manifest/meta-data-element) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-meta-data`](../cli/flet-build.md#--android-meta-data) +2. `[tool.flet.android.meta_data]` + +#### Example + + + +```bash +flet build apk \ + --android-meta-data firebase_analytics_collection_enabled=true \ + --android-meta-data default_timeout_seconds=30 +``` + + +```toml +[tool.flet.android.meta_data] +"firebase_analytics_collection_enabled" = "true" +"default_timeout_seconds" = "30" +``` + + +
+Template translation + +In the [`AndroidManifest.xml`](index.md#build-template), +the `pyproject.toml` example above will be translated accordingly into this: + +```xml + + + + +``` +
+ +### Features + +A hardware or software feature that is used by the application. +More information [here](https://developer.android.com/guide/topics/manifest/uses-feature-element). + +- `name`: Specifies a single hardware or software feature used by the application as a descriptor string. + Valid attribute values are listed in the Hardware features and Software features sections. + These attribute values are case-sensitive. +- `required`: A boolean value (`true` or `false`) that indicates whether the application requires the feature specified by the `name`. + +See also: + +- [`` element](https://developer.android.com/guide/topics/manifest/uses-feature-element) +- [Features reference](https://developer.android.com/guide/topics/manifest/uses-feature-element#features-reference) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-features`](../cli/flet-build.md#--android-features) +2. `[tool.flet.android.feature]` +3. Values injected by [cross-platform permission bundles](index.md#permissions), if any. +4. defaults: `android.software.leanback=false`, `android.hardware.touchscreen=false` + +#### Supported value forms + + + +Accepts repeated `=` entries. +The `` value can be `true` or `false` (case-insensitive). + + +Use boolean values. TOML booleans must be lowercase: `true` or `false`. + + +#### Example + + + +```bash +flet build apk \ + --android-features android.hardware.camera=true \ + --android-features android.hardware.location.gps=false +``` + + +```toml +[tool.flet.android.feature] +"android.hardware.camera" = true +"android.hardware.location.gps" = false +``` + + +
+Template translation + +In the [`AndroidManifest.xml`](index.md#build-template), +the example above will be translated accordingly into this: + +```xml + + + + +``` +
+ +### Permissions + +Use cross-platform permissions from [Permissions](index.md#permissions) when possible, +and add Android-specific permissions or features here. + +See also: + +- [`Manifest.permission` constants](https://developer.android.com/reference/android/Manifest.permission) +- [Request app permissions](https://developer.android.com/training/permissions/requesting) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-permissions`](../cli/flet-build.md#--android-permissions) +2. `[tool.flet.android.permission]` +3. Values injected by [cross-platform permission bundles](index.md#permissions), if any. +4. defaults: `android.permission.INTERNET=true` + +#### Supported value forms + + + +Accepts repeated `=` entries. +The `` value can be `true` or `false` (case-insensitive). +Permissions with `false` are omitted from the generated manifest. + + +Use boolean values. TOML booleans must be lowercase: `true` or `false`. +Permissions set to `false` are omitted from the generated manifest. + + +#### Example + + + +```bash +flet build apk \ + --android-permissions android.permission.READ_EXTERNAL_STORAGE=true \ + --android-permissions android.permission.WRITE_EXTERNAL_STORAGE=true +``` + + +```toml +[tool.flet.android.permission] +"android.permission.READ_EXTERNAL_STORAGE" = true +"android.permission.WRITE_EXTERNAL_STORAGE" = true +``` + + +
+Template translation + +In the [`AndroidManifest.xml`](index.md#build-template), +the `pyproject.toml` example above will be translated accordingly into this: + +```xml + + + + +``` +
+ +### Minimum SDK version + +The minimum Android API level your app can be installed on. + +See also: + +- [`` element (`minSdkVersion`)](https://developer.android.com/guide/topics/manifest/uses-sdk-element) +- [Android API level reference](https://developer.android.com/guide/topics/manifest/uses-sdk-element#ApiLevels) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. `[tool.flet.android].min_sdk_version` +2. Flutter default: `flutter.minSdkVersion` + +#### Example + + + +```toml +[tool.flet.android] +min_sdk_version = 24 +``` + + +
+Template translation + +In the [`android/app/build.gradle.kts`](index.md#build-template), +the `pyproject.toml` example above will be translated accordingly into this: + +```kotlin +defaultConfig { + val resolvedMinSdk = 24 + minSdk = resolvedMinSdk +} +``` +
+ +### Target SDK version + +The Android API level your app targets for runtime behavior and compatibility. + +See also: + +- [`` element (`targetSdkVersion`)](https://developer.android.com/guide/topics/manifest/uses-sdk-element) +- [Target API level requirements and behavior changes](https://developer.android.com/google/play/requirements/target-sdk) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. `[tool.flet.android].target_sdk_version` +2. Flutter default: `flutter.targetSdkVersion` + +#### Example + + + +```toml +[tool.flet.android] +target_sdk_version = 35 +``` + + +
+Template translation + +In the [`android/app/build.gradle.kts`](index.md#build-template), +the `pyproject.toml` example above will be translated accordingly into this: + +```kotlin +defaultConfig { + val resolvedTargetSdk = 35 + targetSdk = resolvedTargetSdk +} +``` +
+ +### Adaptive icon background + +The background color used for the Android adaptive launcher icon. + +This value is applied when app icons are generated for Android. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--android-adaptive-icon-background`](../cli/flet-build.md#--android-adaptive-icon-background) +2. `[tool.flet.android].adaptive_icon_background` +3. [Build template](index.md#build-template) default: `#ffffff` + +#### Example + + + +```bash +flet build apk --android-adaptive-icon-background "#0B6BFF" +``` + + +```toml +[tool.flet.android] +adaptive_icon_background = "#0B6BFF" +``` + + +## ADB Tips + +[Android Debug Bridge (adb)](https://developer.android.com/tools/adb) is a +command-line tool included in the Android SDK that lets you communicate +with Android devices and emulators. + +If you installed Android Studio on macOS, +`adb` is typically located at: `~/Library/Android/sdk/platform-tools/adb`. + +See this [guide](https://www.makeuseof.com/install-apps-via-adb-android/) for +help installing and using adb on different platforms. + +1. To run interactive commands inside an Android simulator or device: + ```bash + adb shell + ``` + +2. To overcome "permissions denied" error while trying to browse file system in interactive Android shell: + ```bash + su + ``` + +3. To download a file from a device to your local computer: + ```bash + adb pull + ``` + +4. To install an APK on an Android device: + ```bash + adb install + ``` + + This works for both physical devices and emulators. If more than one device is connected, specify the target device: + ```bash + adb -s install + ``` + + You can list available devices with: + ```bash + adb devices + ``` diff --git a/website/docs/publish/index.md b/website/docs/publish/index.md new file mode 100644 index 0000000000..f0184a3101 --- /dev/null +++ b/website/docs/publish/index.md @@ -0,0 +1,1580 @@ +--- +title: "Publishing a Flet app" +--- + +import CrossPlatformPermissions from '@site/.crocodocs/cross-platform-permissions.mdx'; +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +# Publishing a Flet app + +Flet CLI provides the [`flet build`](../cli/flet-build.md) command to package a +Flet app into a standalone executable or installable package for distribution. + +## Prerequisites + +### Platform matrix + +Use the following matrix to determine on which OS `flet build` can be run in order to target each platform: + +| Run on | [apk/aab](./android.md) | [ipa/ios-simulator](./ios.md) | [macos](./macos.md) | [linux](./linux.md) | [windows](./windows.md) | [web](./web/index.md) | +|--------|---------|-------------------|-------|-------|---------|-----| +| macOS | ✅ | ✅ | ✅ | | | ✅ | +| Windows| ✅ | | | ✅ (WSL) | ✅ | ✅ | +| Linux | ✅ | | | ✅ | | ✅ | + + + +### Flutter SDK + +[Flutter](https://flutter.dev) is required to build Flet apps for any platform. + +If the minimum required version of the Flutter SDK is not already +available in the system `PATH`, it will be automatically downloaded +and installed (in the `$HOME/flutter/{version}` directory) during +the first build process. + +:::tip[Tip] +The recommended (minimum required) Flutter SDK version +depends on the Flet version installed or in use. + +It can be viewed by running one of the following commands: + +```bash +flet --version +``` +```bash +uv run python -c "import flet.version; print(flet.version.flutter_version)" +``` + +or the below Python code snippet: + +```python +import flet.version +print(flet.version.flutter_version) +``` +::: + +## Project structure + +The `flet build` command assumes the following minimal Flet project structure: + +```tree +README.md +pyproject.toml # (1)! +src + assets # (2)! + icon.png + main.py # (3)! +``` + +1. Serves as the main configuration file for your application. + It includes metadata, dependencies, and build settings. + At a minimum, the `dependencies` section should specify `flet` package. + +:::note[Example] + Below is an example of a `pyproject.toml` file: + ```toml title="pyproject.toml" + [project] + name = "example" + version = "0.1.0" + description = "An Example." + readme = "README.md" + requires-python = ">=3.10" + authors = [{ name = "Me", email = "me@example.com" }] + dependencies = [ + "flet" + ] + + [tool.flet] + org = "com.mycompany" + product = "My App" + company = "My Company" + copyright = "Copyright (C) 2025 by My Company" + + [tool.flet.app] + path = "src" + ``` +::: + +2. An optional directory that contains application assets + (images, sound, text, and other files required by your app) as well as images + used for package [icons](#icons) and [splash screens](#splash-screen). +3. The main [entry point](#entry-point) of your Flet app. It usually contains the call to `ft.run()`. + +:::tip[Tip] +To quickly set up a project with the correct structure, use the [`flet create`](../cli/flet-create.md) command: + +```bash +flet create +``` + +Where `` is the name for your project directory. +::: + +:::note[Using `requirements.txt` instead of `pyproject.toml`] +Instead of a `pyproject.toml` file, you can also use a `requirements.txt` file to specify dependencies. + +In this case, two things to keep in mind: + +- if both files are present, `flet build` will ignore `requirements.txt`. +- don't use `pip freeze > requirements.txt` to generate this file or fill it with dependencies, + as it may include packages incompatible with the target platform. Instead, hand-pick and include + only the direct dependencies required by your app, including `flet`. +::: + +## How it works + +When you run `flet build `, the pipeline is: + +1. Create a Flutter project in `{flet_app_directory}/build/flutter` from the [template](#template-source). + The Flutter app embeds your packaged Python app in its assets and uses `flet` and + [`serious_python`](https://pub.dev/packages/serious_python) to run the app and render the UI. + The project is cached and reused across builds for rapid iterations; + use [`--clear-cache`](../cli/flet-build.md#--clear-cache) to force a rebuild. +2. Copy custom [icons](#icons) and [splash images](#splash-screen) from `assets` into the + Flutter project, then generate: + - Icons for all platforms via [`flutter_launcher_icons`](https://pub.dev/packages/flutter_launcher_icons). + - Splash screens for web, iOS, and Android via [`flutter_native_splash`](https://pub.dev/packages/flutter_native_splash). +3. Package the Python app using `serious_python package`: + - Install app dependencies from [pypi.org](https://pypi.org) and + [pypi.flet.dev](https://pypi.flet.dev) for the selected platform, as configured in + [App dependencies](#app-dependencies) and [Source packages](#source-packages). + - If [configured](#compilation-and-cleanup), compile `.py` files to `.pyc`. + - Add all project files, except those [excluded](#excluding-files-and-directories), to the app asset. +4. Run [`flutter build`](https://docs.flutter.dev/deployment) to produce the + executable or installable package. +5. Copy build outputs from Step 4 into the [output directory](#output-directory). + +## Configuration options + +:::note[Placeholders] +Throughout this documentation, the following placeholders are used: + +- [``](../cli/flet-build.md#target_platform) - one of: `apk`, `aab`, `ipa`, `ios-simulator`, `web`, `macos`, `windows`, `linux`. +- `` - the config namespace under `[tool.flet.]`; one of: `android` (for `apk` and `aab` targets), `ios` (for `ipa` and `ios-simulator` targets), `web`, `macos`, `windows`, `linux`. +- [``](../cli/flet-build.md#python_app_path) - the path passed to `flet build` (defaults to the current directory). +- `` - the resolved project root for ``; `pyproject.toml` and `requirements.txt` are read from here. +- `` - the version of Flet in use. You can check with `flet --version` or + `uv run python -c "import flet; print(flet.__version__)"`. +::: + +:::note[Understanding `pyproject.toml` structure] +Flet loads `pyproject.toml` as a nested dictionary and looks up settings using +dot-separated paths (for example, `tool.flet.web.base_url`). + +The two forms below are equivalent and resolve to the same key-value pair: + +- **Form 1** (will be used/preferred throughout this documentation) + ```toml + [tool.flet.section] + key = "value" + ``` + +- **Form 2** + ```toml + [tool.flet] + section.key = "value" + ``` + +But they are different or should not be confused with the +below ("quoted keys" are literals and do not create nesting): + +```toml +[tool.flet] +"section.key" = "value" +``` +::: + +### App path + +Defines the root directory of your Python app within ``. +Flet looks for the [entry point](#entry-point), the `assets` directory, and +[exclude paths](#excluding-files-and-directories) relative to this directory. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. `[tool.flet.app].path` +2. `` + +`path` is resolved relative to ``. + +#### Example + + + +```toml +[tool.flet.app] +path = "src" +``` + + + +### Entry point + +This is the Python module that starts your app and contains the call to +`flet.run()` or `flet.render()`. Flet uses the module *stem* and looks for +`.py` in your [app path](#app-path). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--module-name`](../cli/flet-build.md#--module-name) +2. `[tool.flet.app].module` +3. `"main"` (entry file `main.py`) + +Its value can either be `` or `.py`; both resolve to the same Python module. + +#### Example + + + +```bash +flet build --module-name app.py +``` + + +```toml +[tool.flet.app] +module = "app.py" +``` + + + +### Project name + +The project name is the base identifier for [bundle IDs](#bundle-id) and other internal +names. The source value is normalized to a safe identifier: lowercased, punctuation +and spaces removed or collapsed, and hyphens converted to underscores (for example, +`My App` or `my-app` becomes `my_app`). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--project`](../cli/flet-build.md#--project) +2. `[project].name` +3. project/app directory name + +#### Example + + + +```bash +flet build --project my_app +``` + + +```toml +[project] +name = "my_app" +``` + + + +### Product name + +The display (user-facing) name shown in window titles, launcher labels, and about dialogs. + +It does **not** control the on-disk executable or bundle name. Use the +[artifact name](#artifact-name) for artifact naming. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--product`](../cli/flet-build.md#--product) +2. `[tool.flet].product` +3. [`--project`](../cli/flet-build.md#--project) +4. `[project].name` +5. project/app directory name + +#### Example + + + +```bash +flet build --product "My Awesome App" +``` + + +```toml +[tool.flet] +product = "My Awesome App" +``` + + + +### Artifact name + +The on-disk name for executables and/or app bundles. For example, on Windows it +determines the name of the `.exe` file, and on macOS it sets the name of the `.app` bundle. + +It does **not** affect [bundle ID](#bundle-id)s or package identifiers. + +It can contain spaces or accents, but keep file system restrictions in mind on +your target platforms. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--artifact`](../cli/flet-build.md#--artifact) +2. `[tool.flet.].artifact` +3. [`--project`](../cli/flet-build.md#--project) +4. `[project].name` +5. project/app directory name + +#### Example + + + +```bash +flet build --artifact "My Awesome App" +``` + + +```toml +[tool.flet] +artifact = "My Awesome App" +``` + + + +### Organization name + +:::note[Platform support] +[Android](android.md), [iOS](ios.md), +[macOS](macos.md), and [Linux](linux.md) only. +::: + +The organization name in reverse domain name notation, typically in the form +`com.mycompany`. It is used as the prefix for the [bundle ID](#bundle-id) and +for package identifiers on mobile and desktop targets. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--org`](../cli/flet-build.md#--org) +2. `[tool.flet.].org` +3. `[tool.flet].org` +4. `"com.flet"` + +#### Example + + + +```bash +flet build --org com.mycompany +``` + + +```toml +[tool.flet] # or [tool.flet.] +org = "com.mycompany" +``` + + + +### Bundle ID + +:::note[Platform support] +[Android](android.md), [iOS](ios.md), +[macOS](macos.md), and [Linux](linux.md) only. +::: + +The bundle ID for the application, typically in the form `"com.mycompany.my_app"`. + +If not explicitly specified, it is derived from the [organization name](#organization-name) +and the [project name](#project-name) used by the build template. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--bundle-id`](../cli/flet-build.md#--bundle-id) +2. `[tool.flet.].bundle_id` +3. `[tool.flet].bundle_id` + +#### Example + + + +```bash +flet build --bundle-id com.mycompany.my_app +``` + + +```toml +[tool.flet] # or [tool.flet.] +bundle_id = "com.mycompany.my_app" +``` + + + +### Company Name + +:::note[Platform support] +[Windows](windows.md) and [macOS](macos.md) only. +::: + +The company name displayed in about app dialogs and metadata (notably on desktop builds). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--company`](../cli/flet-build.md#--company) +2. `[tool.flet].company` +3. Build template default (see [Template Source](#template-source)) + +#### Example + + + +```bash +flet build --company "My Company Inc." +``` + + +```toml +[tool.flet] +company = "My Company Inc." +``` + + + +### Copyright + +:::note[Platform support] +[Windows](windows.md) and [macOS](macos.md) only. +::: + +Copyright text displayed in about app dialogs and metadata. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--copyright`](../cli/flet-build.md#--copyright) +2. `[tool.flet].copyright` +3. Build template default (see [Template Source](#template-source)) + +#### Example + + + +```bash +flet build --copyright "Copyright © 2026 My Company Inc." +``` + + +```toml +[tool.flet] +copyright = "Copyright © 2026 My Company Inc." +``` + + + +### Versioning + +#### Build Number + +An integer identifier used internally to distinguish one build from another. + +Each new build must have a unique, incrementing number; +higher numbers indicate more recent builds. + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--build-number`](../cli/flet-build.md#--build-number) +2. `[tool.flet].build_number` +3. Otherwise, the build number from the generated `pubspec.yaml` + (see [Template Source](#template-source)) will be used. + +##### Example + + + +```bash +flet build --build-number 1 +``` + + +```toml +[tool.flet] +build_number = 1 +``` + + + +#### Build Version + +A user‑facing version string in `x.y.z` format. +Increment this for each new release to differentiate it from previous versions. + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. `--build-version` +2. `[project].version` +3. `[tool.poetry].version` +4. Otherwise, the build version from the generated `pubspec.yaml` + (see [Template Source](#template-source)) will be used. + +##### Example + + + +```bash +flet build --build-version 1.0.0 +``` + + +```toml +[project] +version = "1.0.0" +``` + + + +### Output directory + +The directory where the build output is saved. +If the directory already exists, it is deleted and recreated on each build. + +For web builds, the app's `assets` directory is copied into the output directory. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--output`](../cli/flet-build.md#--output) (or `-o`) +2. `/build/` + +#### Example + + + +```bash +flet build --output +``` + + + +### App dependencies + +These are the Python packages that your Flet app depends on to function correctly. + +#### Resolution order + +Its value is determined in the following order of precedence: + +- `[tool.poetry].dependencies` if present; otherwise `[project].dependencies` (PEP 621). +- If `[tool.flet.].dependencies` is set (where `` corresponds to ``), its values are appended to the list above. +- If the result of all above is empty and `requirements.txt` exists in ``, it is used. +- If the result of all the above is empty, `flet==` is used. + +To use a local development version of a dependency during builds, configure +`[tool.flet].dev_packages` or `[tool.flet.].dev_packages` with a +package name to path mapping. + +If your app uses Flet extensions (third-party packages), list them in your +Python dependencies so they are packaged with the app. Examples of extensions +can be found in [Built-in extensions](../extend/built-in-extensions.md). + +#### Example + + + +```toml +[project] +dependencies = [ + "flet", + "requests", + "flet-extension1", + "flet-extension2 @ git+https://github.com/account/flet-extension2.git", # git repo + "flet-extension3 @ file:///path/to/flet-extension3", # local package +] + +[tool.flet.] # will be used/appended only if corresponds to +dependencies = [ + "dep1", + "dep2", +] +``` + + + +### Source packages + +:::note[Platform support] +[Android](android.md), [iOS](ios.md), and [Web](web/static-website/index.md#flet-build-web) only. +::: + +By default, packaging for mobile and web only installs binary wheels. Use source packages +to allow specific dependencies to be installed from [source distributions (sdists)](https://pydevtools.com/handbook/reference/sdist/). + +This can be useful for installing - pure Python - dependencies that do not have pre-built wheels for the +target platform or an all-platform wheel (`*-py3-none-any.whl`), but instead provide a source distribution (`*.tar.gz`). + +For more information on pure vs non-pure Python packages, see our +[blog post](https://flet.dev/blog/flet-packaging-update#pure-python-packages) on the topic. + +On desktop targets, source installs are already allowed, so this setting is mainly useful for +[Android](android.md), [iOS](ios.md), and [Web](web/static-website/index.md#flet-build-web) +(`flet build web` only — [not `flet publish`](web/static-website/index.md#sdist-only-dependencies)). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--source-packages`](../cli/flet-build.md#--source-packages) +2. `[tool.flet.].source_packages` +3. `[tool.flet].source_packages` + +#### Example + + + +```bash +flet build --source-packages package1 package2 +``` + + +```toml +[tool.flet] +source_packages = ["package1", "package2"] +``` + + + +### Icons + +:::note[Platform support] +[Android](android.md), [iOS](ios.md), [macOS](macos.md), [Windows](windows.md) +and [Web](web/static-website/index.md#flet-build-web) only. +::: + +You can customize app icons for all platforms (except Linux) using image files placed in +the `assets` directory of your Flet app. + +If a platform-specific icon (as in the table below) is not provided, `icon.png` +(or any supported format like `.bmp`, `.jpg`, or `.webp`) will be used as fallback. +For the iOS platform, transparency (alpha channel) will be automatically removed, if present. + +| Platform | File Name | Recommended Size | Notes | +|----------|------------------------------------------|------------------|---------------------------------------------------------------------------------------------| +| iOS | `icon_ios.png` | ≥ 1024×1024 px | Transparency (alpha channel) is not supported and will be automatically removed if present. | +| Android | `icon_android.png` | ≥ 192×192 px | | +| Web | `icon_web.png` | ≥ 512×512 px | | +| Windows | `icon_windows.ico` or `icon_windows.png` | 256×256 px | `.png` file will be internally converted to a 256×256 px `.ico` icon. | +| macOS | `icon_macos.png` | ≥ 1024×1024 px | | + +### Splash screen + +:::note[Platform support] +[Android](android.md), [iOS](ios.md), +and [Web](web/static-website/index.md#flet-build-web) only. +::: + +A splash screen is a visual element displayed when an app is launching, +typically showing a logo or image while the app loads. + +You can customize splash screens for iOS, Android, and Web platforms by +placing image files in the `assets` directory of your Flet app. + +If platform-specific splash images are not provided, Flet will fall back to `splash.png`. +If that is also missing, it will use `icon.png` or any supported format such as `.bmp`, `.jpg`, or `.webp`. + +#### Splash images + +| Platform | Dark Fallback Order | Light Fallback Order | +|----------|--------------------------------------------------------------------------------------------------|--------------------------------------------------| +| iOS | `splash_dark_ios.png` → `splash_dark.png` → `splash_ios.png` → `splash.png` → `icon.png` | `splash_ios.png` → `splash.png` → `icon.png` | +| Android | `splash_dark_android.png` → `splash_dark.png` → `splash_android.png` → `splash.png` → `icon.png` | `splash_android.png` → `splash.png` → `icon.png` | +| Web | `splash_dark_web.png` → `splash_dark.png` → `splash_web.png` → `splash.png` → `icon.png` | `splash_web.png` → `splash.png` → `icon.png` | + +#### Splash Background Colors + +You can customize splash background colors using the following options: + +- **Splash Color**: Background color for light mode splash screens. +- **Splash Dark Color**: Background color for dark mode splash screens. + +##### Resolution order + +Their values are respectively determined in the following order of precedence: + +1. [`--splash-color`](../cli/flet-build.md#--splash-color) / [`--splash-dark-color`](../cli/flet-build.md#--splash-dark-color) +2. `[tool.flet..splash].color` / `[tool.flet..splash].dark_color` +3. `[tool.flet.splash].color` / `[tool.flet.splash].dark_color` +4. [Build template](#build-template) defaults + +##### Example + + + +``` +flet build --splash-color #ffffff --splash-dark-color #333333 +``` + + +```toml +[tool.flet.splash] +color = "#ffffff" +dark_color = "#333333" +``` + + + +#### Disabling Splash Screens + +Splash screens are enabled by default but can be disabled. + +##### Resolution order + +Its value is determined in the following order of precedence: + +- on Android: + - [`--no-android-splash`](../cli/flet-build.md#--no-android-splash) + - `[tool.flet.splash].android` +- on iOS: + - [`--no-ios-splash`](../cli/flet-build.md#--no-ios-splash) + - `[tool.flet.splash].ios` +- on Web: + - [`--no-web-splash`](../cli/flet-build.md#--no-web-splash) + - `[tool.flet.splash].web` + +##### Example + + + +```bash +flet build apk --no-android-splash +flet build ipa --no-ios-splash +flet build ios-simulator --no-ios-splash +flet build web --no-web-splash +``` + + +```toml +[tool.flet.splash] +android = false +ios = false +web = false +``` + + + +### Boot screen + +:::note[Platform support] +[Windows](windows.md), [macOS](macos.md), [Linux](linux.md), +[Android](android.md), and [iOS](ios.md) only. +::: + +The boot screen is shown while the packaged app archive (`app.zip`) is extracted +to the app data directory (typically on first launch or after the app bundle changes). +It appears after the [splash screen](#splash-screen) and before the +[startup screen](#startup-screen). + +It is not shown by default. Enable it, for example, when then extraction time is noticeable. + +#### Example + + + +```toml +[tool.flet.app.boot_screen] # or [tool.flet..app.boot_screen] +show = true +message = "Preparing the app for its first launch…" +``` + + + +### Startup screen + +:::note[Platform support] +[Windows](windows.md), [macOS](macos.md), [Linux](linux.md), +[Android](android.md), and [iOS](ios.md) only. +::: + +The startup screen is shown while the Python runtime and your app are starting. +On mobile targets this can include preparing packaged dependencies. It appears +after the [boot screen](#boot-screen). + +It is not shown by default. + +#### Example + + + +```toml +[tool.flet.app.startup_screen] # or [tool.flet..app.startup_screen] +show = true +message = "Starting up the app…" +``` + + + +### Hidden app window on startup + +:::note[Platform support] +[Windows](windows.md), [macOS](macos.md), and [Linux](linux.md) only. +::: + +A Flet desktop app (Windows, macOS, or Linux) can start with its window hidden. +This lets your app perform initial setup (for example, add content, resize or +position the window) before showing it to the user. + +See this [code example](../controls/page.md#hidden-app-window-on-startup). + +#### Resolution order + +Its value is determined in the following order of precedence: + +- `[tool.flet..app].hide_window_on_start`, where `` can be `windows`, `macos` or `linux` +- `[tool.flet.app].hide_window_on_start` +- [`FLET_HIDE_WINDOW_ON_START`](../reference/environment-variables.md#flet_hide_window_on_start) + +#### Example + + + +```toml +[tool.flet.app] # or [tool.flet..app] +hide_window_on_start = true +``` + + + +### Deep linking + +:::note[Platform support] +[Android](android.md) and [iOS](ios.md) only. +::: + +[Deep linking](https://en.wikipedia.org/wiki/Mobile_deep_linking) allows users +to navigate directly to specific content within a mobile app +using a [URI (Uniform Resource Identifier)](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier). +Instead of opening the app's homepage, deep links direct users to a specific page, +feature, or content within the app, enhancing user experience and engagement. + +- **Scheme**: deep linking URL scheme, e.g. `"https"` or `"myapp"`. +- **Host**: deep linking URL host. + +See also: + +- [Flutter deep linking](https://docs.flutter.dev/ui/navigation/deep-linking) +- [Android intents and intent filters](https://developer.android.com/guide/components/intents-filters) +- [Defining a custom URL scheme for your app](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) +- [Universal Links](https://developer.apple.com/ios/universal-links/) + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--deep-linking-scheme`](../cli/flet-build.md#--deep-linking-scheme) and + [`--deep-linking-host`](../cli/flet-build.md#--deep-linking-host) (only when both are provided) +2. `[tool.flet..deep_linking].scheme` / `[tool.flet..deep_linking].host`, where `` can be android or ios +3. `[tool.flet.deep_linking].scheme` / `[tool.flet.deep_linking].host` + +Both scheme and host are required; if either is missing, the deep-linking entries are not added. + +#### Example + + + +```bash +flet build \ + --deep-linking-scheme "https" \ + --deep-linking-host "mydomain.com" +``` + + +```toml +[tool.flet.deep_linking] # or [tool.flet..deep_linking] +scheme = "https" +host = "mydomain.com" +``` + + + +
+Template translation + +In the Android [`AndroidManifest.xml`](android.md#android-manifest), +the `pyproject.toml` example above will be translated accordingly into this: + +```xml + + + + + + + +``` + +In the iOS [`ios/Runner/Info.plist`](ios.md#infoplist), +the `pyproject.toml` example above will be translated accordingly into this: + +```xml +FlutterDeepLinkingEnabled + +CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + mydomain.com + CFBundleURLSchemes + + https + + + +``` +
+ +### Target Architecture + +:::note[Platform support] +[Android](android.md) and [macOS](macos.md) only. +::: + +A target platform can have different CPU architectures, +which in turn support different instruction sets. + +It is possible to build your app for specific CPU architectures. +This is useful for reducing the size of the resulting binary or package, +or for targeting specific devices. + +For more/complementary information, see the specific platform guides: +[Android](android.md#supported-target-architectures), [macOS](macos.md#target-architecture). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--arch`](../cli/flet-build.md#--arch) +2. `[tool.flet.].target_arch`, where `` can be `android` or `macos` +3. `[tool.flet].target_arch` +4. Platform defaults for the `` + +#### Example + + + +```bash +flet build macos --arch arm64 x86_64 +``` + + +```toml +[tool.flet.macos] # or [tool.flet] +target_arch = ["arm64", "x86_64"] +``` + + + +### Excluding files and directories + +Files and/or directories can be excluded from the build process. +This can be useful for reducing the size of the resulting binary or package. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--exclude`](../cli/flet-build.md#--exclude) (can be used multiple times) +2. `[tool.flet..app].exclude` (type: list of strings) +3. `[tool.flet.app].exclude` (type: list of strings) + +The files and/or directories specified should be provided as relative +paths to the [app path](#app-path) directory. Paths are matched exactly (no globs), and +directories are excluded recursively. + +By default, the `build` directory is always excluded. +Additionally, when the target_platform is web, the `assets` +directory is always excluded. + +#### Example + + + +```bash +flet build --exclude .git .venv +``` + + +```toml +[tool.flet.app] # or [tool.flet..app] +exclude = [".git", ".venv"] +``` + + + +### Compilation and cleanup + +Flet can compile your app's `.py` files and/or installed packages' `.py` files into +`.pyc` files during the packaging process (via `python -m compileall -b`). Cleanup +removes known junk files and any additional globs you specify. + +1. Compilation: + * `compile-app`: compile app's `.py` files + * `compile-packages`: compile site/installed packages' `.py` files + +2. Cleanup: + * `cleanup-app`: remove junk files from the app directory + * `cleanup-app-files`: additional globs to delete from the app directory + (implies `cleanup-app`) + * `cleanup-package-files`: additional globs to delete from site-packages + (implies `cleanup-packages`) + * `cleanup-packages`: remove junk files from site-packages (defaults to `true`) + +By default, Flet does **not** compile your app files during packaging. +This allows the build process to complete even if there are syntax errors, +which can be useful for debugging or rapid iteration. + +#### Resolution order + +The values of `compile-app` and `cleanup-app` are respectively determined in the following order of precedence: + +1. [`--compile-app`](../cli/flet-build.md#--compile-app) / [`--cleanup-app`](../cli/flet-build.md#--cleanup-app) +2. `[tool.flet..compile].app` / `[tool.flet..cleanup].app` +3. `[tool.flet.compile].app` / `[tool.flet.cleanup].app` +4. empty list / empty list + +The values of `compile-packages` and `cleanup-packages` are respectively determined in the following order of precedence: + +1. [`--compile-packages`](../cli/flet-build.md#--compile-packages) / [`--cleanup-packages`](../cli/flet-build.md#--cleanup-packages) +2. `[tool.flet..compile].packages` / `[tool.flet..cleanup].packages` +3. `[tool.flet.compile].packages` / `[tool.flet.cleanup].packages` +4. `False` / `True` + +The values of `cleanup-app-files` and `cleanup-package-files` are respectively determined in the following order of precedence: + +1. [`--cleanup-app-files`](../cli/flet-build.md#--cleanup-app-files) / [`--cleanup-package-files`](../cli/flet-build.md#--cleanup-package-files) +2. `[tool.flet..cleanup].app_files` / `[tool.flet..cleanup].package_files` +3. `[tool.flet.cleanup].app_files` / `[tool.flet.cleanup].package_files` +4. `False` / `False` + +#### Example + + + +```bash +flet build \ + --compile-app --compile-packages \ + --cleanup-app-files "**/*.c" "**/*.h" --cleanup-package-files "**/*.pyi" +``` + + +```toml +[tool.flet.compile] # or [tool.flet..compile] +app = true +packages = true + +[tool.flet.cleanup] # or [tool.flet..cleanup] +app = true +packages = true +app_files = ["**/*.c", "**/*.h"] +package_files = ["**/*.pyi"] +``` + + + +### Permissions + +:::note[Platform support] +[Android](android.md), [iOS](ios.md), and [macOS](macos.md) only. +::: + +`flet build` allows granular control over permissions, features, and entitlements +embedded into `AndroidManifest.xml`, `Info.plist` and `.entitlements` files. + +See platform guides for setting specific [iOS](ios.md#permissions), +[Android](android.md#permissions) and [macOS](macos.md) permissions. + +#### Predefined cross-platform permission bundles + +Cross-platform permissions are named and predefined bundles that apply a baseline set of +platform-specific entries required for a feature. Each bundle expands into the +corresponding platform-specific equivalents. This is especially useful for beginners +who may be unfamiliar with the underlying platform APIs or prefer not to interact with them directly. + +Only the bundles you list are applied. If you need different wording or extra +entries, set the platform-specific tables directly; those values are merged on top and +can override the bundle defaults. The examples below show the exact `pyproject.toml` equivalents for each bundle. + +Below is a list of available bundles: + + + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--permissions`](../cli/flet-build.md#--permissions) +2. `[tool.flet].permissions` (type: list of strings) +3. `[]` + +##### Example + + + +```bash +flet build --permissions location microphone +``` + + +```toml +[tool.flet] +permissions = ["location", "microphone"] +``` + + + +### Build template + +`flet build` creates (and reuses) a Flutter project under `/build/flutter` using a +[cookiecutter](https://cookiecutter.readthedocs.io/en/stable/) template. By default, the template +is downloaded as a zip artifact from the matching Flet GitHub Release. The version of the template +used is determined by the installed Flet version. + +The cached project is refreshed when template inputs change or when you pass +[`--clear-cache`](../cli/flet-build.md#--clear-cache). + +#### Template Source + +Defines the location of the cookiecutter build-template to be used. + +Supported values include: + +- A GitHub repository using the `gh:` prefix (e.g., `gh:org/template`) +- A full Git URL (e.g., `https://github.com/org/template.git`) +- A zip URL (e.g., `https://github.com/flet-dev/flet/releases/download/v0.83.0/flet-build-template.zip`) +- A local directory path + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--template`](../cli/flet-build.md#--template) +2. `[tool.flet.template].url` +3. The default zip URL from the Flet GitHub Release matching the installed version + +#### Example + + + +```bash +flet build apk --template gh:my-org/my-custom-template +``` + + +```toml +[tool.flet.template] +url = "gh:my-org/my-custom-template" +``` + + + +#### Template Reference + +Defines the branch, tag, or commit to check out from the [template source](#template-source). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--template-ref`](../cli/flet-build.md#--template-ref) +2. `[tool.flet.template].ref` +3. [``](#configuration-options) + +#### Example + + + +```bash +flet build --template-ref main +``` + + +```toml +[tool.flet.template] +ref = "main" +``` + + + +#### Template Directory + +Defines the relative path to the cookiecutter template. +If [template source](#template-source) is set, the path is treated as a +subdirectory within its root; otherwise, it is relative to the template root. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--template-dir`](../cli/flet-build.md#--template-dir) +2. `[tool.flet.template].dir` +3. root of the [template source](#template-source) + +#### Example + + + +```bash +flet build --template gh:org/template --template-dir sub/directory +``` + + +```toml +[tool.flet.template] +url = "gh:org/template" +dir = "sub/directory" +``` + + + +### Additional `flutter build` Arguments + +During the `flet build` process, `flutter build` command gets called internally to +package your app for the specified platform. However, not all `flutter build` +arguments are exposed or usable through the `flet build` command directly. + +For possible `flutter build` arguments, see [Flutter docs](https://docs.flutter.dev/deployment) +guide. For most targets, run `flutter build --help`; for +[`ios-simulator`](ios.md#flet-build-ios-simulator), run `flutter build ios --simulator --help`. + +:::warning[Important] +Passing additional `flutter build` arguments might cause unexpected behavior. +Use at your own risk, and only if you fully know what you're doing! +::: + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. `--flutter-build-args` (can be used multiple times) +2. `[tool.flet..flutter].build_args` +3. `[tool.flet.flutter].build_args` + +#### Example + + + +```bash +flet build apk \ + --flutter-build-args=--obfuscate \ + --flutter-build-args=--export-method=development \ + --flutter-build-args=--dart-define=API_URL=https://api.example.com +``` + + +```toml +[tool.flet.flutter] # or [tool.flet..flutter] +build_args = [ + "--obfuscate", + "--export-method=development", + "--dart-define=API_URL=https://api.example.com", +] +``` + + + +### Flutter dependencies + +When you run `flet build`, Flet generates a Flutter shell project and then +updates its [`pubspec.yaml`](#build-template) using values from `pyproject.toml`. + +Use: + +- `[tool.flet.flutter.pubspec.dependencies]` for normal package declarations. + ([Dart docs](https://dart.dev/tools/pub/dependencies)) +- `[tool.flet.flutter.pubspec.dependency_overrides]` when you must force a + version or source, for example, a local path or Git fork. + ([Dart docs](https://dart.dev/tools/pub/dependencies#dependency-overrides)) + +Values follow [standard Pub dependency syntax](https://dart.dev/tools/pub/dependencies#dependency-sources), +expressed in TOML. + +:::note[Note] +- **Important:** In most cases, you usually do not need to add/override Flutter dependencies. + We recommend doing it only if you fully know what you are doing, as it can lead to + unexpected behavior. +- If the same package appears in both `pyproject.toml` and the resulting `pubspec.yaml`, + the value from `pyproject.toml` wins. +- If you use `{ path = "..." }` under `[tool.flet.flutter.pubspec.dependencies]` + or `[tool.flet.flutter.pubspec.dependency_overrides]`, that path is resolved by + Flutter from the generated `pubspec.yaml` location: `/build/flutter/pubspec.yaml`. + This means relative paths are **not** resolved from your `pyproject.toml` file. +::: + +#### Example + + + +```toml +[tool.flet.flutter.pubspec.dependencies] # or [tool.flet.flutter.pubspec.dependency_overrides] +# Version +pkg_1 = "^1.2.3" + +# Local path +pkg_2 = { path = "../pkg_2" } + +# Git (short form) +pkg_3 = { git = "https://github.com/org/pkg_3.git" } + +# Git (expanded form: URL + ref + subdirectory) +pkg_4 = { git = { url = "https://github.com/org/mono_repo.git", ref = "main", path = "packages/pkg_4" } } + +# Hosted source +pkg_5 = { hosted = { name = "pkg_5", url = "https://pub.dev" }, version = "^1.0.0" } + +# SDK package (dependencies only; typically not used in dependency_overrides) +flutter_test = { sdk = "flutter" } +``` + + + +### Verbose logging + +The [`-v`](../cli/flet-build.md#--verbose) (or `--verbose`) and `-vv` flags +enable detailed output from all commands during the flet build process. + +Use `-v` for standard/basic verbose logging, or `-vv` for even more detailed +output (higher verbosity level). If you need support, +we may ask you to share this verbose log. + +## Console output + +In packaged apps (`flet build` output), all output from your Python code such as +`print()` statements, `sys.stdout.write()` calls, and messages from the Python +`logging` module is redirected to a `console.log` file. The full path to this file is available via +[`StoragePaths.get_console_log_filename()`](../services/storagepaths.md#flet.StoragePaths.get_console_log_filename) or the +`FLET_APP_CONSOLE` environment variable. + +Note: `FLET_APP_CONSOLE` is only set in production builds; +in development runs, output stays in your terminal. + +The log file is written in an unbuffered manner, allowing you to read +it at any point in your Python program using: + +```python +import os +import flet as ft + +async def main(page: ft.Page): + log_file = await ft.StoragePaths().get_console_log_filename() + # or + # log_file = os.getenv("FLET_APP_CONSOLE") + + with open(log_file, "r") as f: + logs = f.read() + page.add(ft.Text(logs)) # display on UI + +ft.run(main) +``` + +If your program calls `sys.exit(100)`, the complete log will automatically be shown in a scrollable window. +This is a special "magic" exit code for debugging purposes: + +```python +import sys +sys.exit(100) +``` + +Calling `sys.exit()` with any other code will terminate the app without displaying the log. + +## Continuous Integration/Continuous Deployment (CI/CD) + +You can use `flet build` command in your CI/CD pipelines to automate +the build and release process of your Flet apps. + +### GitHub Actions + +You can use [GitHub Actions](https://docs.github.com/en/actions) to build your +Flet app automatically on every push, pull request, or manual run. + +```yaml +name: Build Flet App # (1)! + +on: # (2)! + push: # (3)! + pull_request: # (4)! + workflow_dispatch: # (5)! + +env: # (6)! + UV_PYTHON: 3.12 # (7)! + PYTHONUTF8: 1 # (8)! + + # https://flet.dev/docs/reference/environment-variables + FLET_CLI_NO_RICH_OUTPUT: 1 # (9)! + +jobs: + build: + name: Build ${{ matrix.name }} + runs-on: ${{ matrix.runner }} + strategy: # (10)! + fail-fast: false + matrix: + include: + # -------- Desktop -------- + - name: linux + runner: ubuntu-latest + build_cmd: "flet build linux" + artifact_path: build/linux + needs_linux_deps: true + + - name: macos + runner: macos-26 + build_cmd: "flet build macos" + artifact_path: build/macos + needs_linux_deps: false + + - name: windows + runner: windows-latest + build_cmd: "flet build windows" + artifact_path: build/windows + needs_linux_deps: false + + # -------- Android -------- + - name: aab + runner: ubuntu-latest + build_cmd: "flet build aab" + artifact_path: build/aab + needs_linux_deps: false + + - name: apk + runner: ubuntu-latest + build_cmd: "flet build apk" + artifact_path: build/apk + needs_linux_deps: false + + # -------- iOS -------- + - name: ipa + runner: macos-26 + build_cmd: "flet build ipa" + artifact_path: build/ipa + needs_linux_deps: false + + - name: ios-simulator + runner: macos-26 + build_cmd: "flet build ios-simulator" + artifact_path: build/ios-simulator + needs_linux_deps: false + + # -------- Web -------- + - name: web + runner: ubuntu-latest + build_cmd: "flet build web" + artifact_path: build/web + needs_linux_deps: false + + steps: + - name: Checkout repository + uses: actions/checkout@v4 # (11)! + + - name: Setup uv + uses: astral-sh/setup-uv@v6 # (12)! + + - name: Install Linux dependencies # (13)! + if: matrix.needs_linux_deps # (14)! + shell: bash + run: | + sudo apt update --allow-releaseinfo-change + LINUX_DEPS="$(uv run python -c 'from flet.utils.linux_deps import linux_dependencies; print(" ".join(linux_dependencies))')" + sudo apt-get install -y --no-install-recommends $LINUX_DEPS + sudo apt-get clean + + - name: Build app # (15)! + shell: bash + run: | + uv run ${{ matrix.build_cmd }} --yes --verbose + + - name: Upload Artifact + uses: actions/upload-artifact@v5.0.0 # (16)! + with: + name: ${{ matrix.name }}-build-artifact + path: ${{ matrix.artifact_path }} # (17)! + if-no-files-found: error # (18)! + overwrite: false +``` + +1. Workflow display name shown in the **Actions** tab. +2. Trigger block for automatic and manual workflow runs. +3. Runs this workflow on every push (unless you restrict branches). +4. Runs this workflow when pull requests are opened/updated. +5. Enables manual runs from GitHub UI (**Actions** → **Run workflow**). +6. Environment variables shared by all jobs and steps. +7. Python version used by `uv`. +8. Forces UTF-8 mode for Python output/IO. Especially useful on Windows builds. +9. Disables rich output from `flet build` for better readability in CI logs. +10. Matrix strategy: each `include` item becomes a parallel build job. +11. Checks out your repository so this workflow can access project files. View its docs [here](https://github.com/actions/checkout). +12. Installs `uv` on the runner. View its docs [here](https://github.com/astral-sh/setup-uv). +13. Installs Linux system packages required by Linux desktop builds. +14. Runs Linux package installation only for matrix entries that need it. +15. Main build step for each target. Executes the target-specific command defined by `matrix.build_cmd`. +16. Uploads build output files as downloadable artifacts. View its docs [here](https://github.com/actions/upload-artifact). +17. Artifact path expected from each build target. +18. If no files were found to upload, the workflow fails, indicating something went wrong during the build. + +The workflow file above builds for all major targets and uploads each build output as an artifact. +You can further customize the workflow for your specific needs, for example, +restricting the build targets or adding additional steps. + +See it in action [here](https://github.com/ndonkoHenri/flet-github-action-workflows). + +## Troubleshooting + +### Prerelease compatibility + +If you are using a prerelease version of the [Flet Python package](https://pypi.org/project/flet) (for example, `0.80.6.devNNNN`) to build an app, +the [build template](#build-template) may still resolve the latest **stable** [`flet` Flutter package](https://pub.dev/packages/flet), which can lead to version incompatibility issues. + +**Why?**: Under normal circumstances, each prerelease of the Flet Python package would require +a matching prerelease of the Flutter Flet package to guarantee compatibility. +However, we don't publish prerelease versions of the Flutter package to [pub.dev](https://pub.dev/). +Because of this, the build template resolves the latest **stable** Flutter `flet` release instead. + +This creates a version mismatch/incompatibility for apps packaged with `flet build`: + +* Your Python code may depend on newly introduced controls or features. +* The packaged Flutter shell may still be using an older stable `flet` version. +* At runtime, the app fails because the Flutter layer does not recognize the new controls/features in your prerelease `flet` package, leading to errors like `Unknown control: `. + +**Note**: this issue does not affect the development workflows (ex: running an app with [`flet run`](../getting-started/running-app.md)), +as the `flet` Flutter dependency is only resolved during the `flet build` process. + +### Solution + +The rule-of-thumb is, if you are using a prerelease Flet Python package, always ensure the Flutter `flet` +dependency is aligned with the same development version before building your app: + +1. Override the Flutter `flet` dependency to point to the corresponding development Git reference. + + + + ```toml + [tool.flet.flutter.pubspec.dependency_overrides] + flet = { git = { url = "https://github.com/flet-dev/flet.git", ref = "main", path = "packages/flet" } } + ``` + + +2. Rebuild the app with the build cache cleared (use [`--clear-cache`](../cli/flet-build.md#--clear-cache); or manually delete `build/flutter`) + +To ensure reproducible builds (ex: in production or CI), prefer using a specific commit SHA, instead of a branch or tag ref. diff --git a/website/docs/publish/ios.md b/website/docs/publish/ios.md new file mode 100644 index 0000000000..2d321e6075 --- /dev/null +++ b/website/docs/publish/ios.md @@ -0,0 +1,703 @@ +--- +title: "Packaging app for iOS" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Instructions for packaging a Flet app into an Xcode archive and, when signing +is configured, an IPA for distribution. + +:::tip[Info] +This guide provides detailed on iOS-specific information. +Complementary and more general information is available [here](index.md). +::: + +## Prerequisites + +### Rosetta 2 + +Some Flutter tooling and dependencies still ship as Intel binaries. Install +[Rosetta 2](https://support.apple.com/en-us/HT211861) on Apple Silicon if Flutter +or CocoaPods prompts for it: + +```bash +sudo softwareupdate --install-rosetta --agree-to-license +``` + +### Xcode + +[Xcode](https://developer.apple.com/xcode/) 15 or later to compile native Swift or Objective-C code. +Open Xcode once after installation to accept the license and install additional components. + +### CocoaPods + +[CocoaPods](https://cocoapods.org/) 1.16 or later to compile and enable Flutter plugins. + +### iOS wheels for binary Python packages + +Binary Python packages (vs "pure" Python packages written in Python only) +are packages that are partially written in C, Rust, or other languages producing native code. +Example packages are `numpy`, `cryptography`, or `pydantic-core`. + +Make sure all non-pure (binary) packages used in your Flet app have +[pre-built wheels for iOS](../reference/binary-packages-android-ios.md). + +## `flet build ipa` + +:::caution[Supported host platforms] +This command can be run on **macOS only**. +::: + +Builds an iOS app archive (`.xcarchive`) and, when signing is configured, +exports an `.ipa` for testing or distribution. + +To generate an `.ipa` for testing on your device or uploading to App Store Connect +for distribution, you will need the following: + +- [Apple Developer Program](https://developer.apple.com/programs/) subscription with + access to [App Store Connect](https://appstoreconnect.apple.com/) +- [Application Identifier](#application-identifier-app-id) +- [Bundle ID](index.md#bundle-id) configured in your Flet project (must match the App ID) +- [Signing Certificate](#signing-certificate) +- [Provisioning Profile](#provisioning-profile) + +## `flet build ios-simulator` + +:::caution[Supported host platforms] +This command can be run on **macOS only**. +::: + +Builds an (unsigned) iOS Simulator `.app` bundle, intended for testing on iOS Simulator +and does **not** require a signing certificate, provisioning profile, or Apple Developer Program setup. + +## Configuration options + +### Application Identifier (App ID) + +A unique string that identifies your app within the Apple ecosystem. +It is required to sign and distribute an iOS app and is used for various services like +Push Notifications, App Groups, iCloud, and In-App Purchases. + +It consists of two parts: + +1. [**Team ID**](#team-id): A unique 10-character string assigned by Apple to your developer account. +2. [**Bundle ID**](index.md#bundle-id): A reverse domain-style identifier for your app (e.g., `com.example.myapp`). + +```mermaid +graph TD + A[App ID: ABCDEFE234.com.example.myapp] --> B[Team ID: ABCDEFE234] + A --> C[Bundle ID: com.example.myapp] +``` + +The [Bundle ID](index.md#bundle-id) in your Flet configuration must match the Bundle ID registered +in the App ID. + +#### Creating a new App ID + +1. Visit [Apple Developer Portal](https://developer.apple.com/account/resources/identifiers/list). +2. Sign in with your **Apple Developer Account**. +3. Click the **"+"** button to add a new identifier. +4. Select **"App IDs"** and click **Continue**. +5. **Enter a Description** – This is just for reference (e.g., "MyApp Identifier"). +6. **Choose the App ID Type:** + - Select **"App"** for a standard iOS/macOS app. + - If you need an identifier for services like Apple Pay or Passbook, select the appropriate option. +7. **Bundle ID** – Choose: + - **Explicit Bundle ID** (`com.example.myapp`) – Recommended for most apps. + - **Wildcard Bundle ID** (`com.example.*`) – Allows multiple apps to use the same identifier (rarely used). +8. **Enable App Services** – Check the boxes for any services your app needs (e.g., Push Notifications, Sign in with Apple, etc.). +9. Click **Continue** and **Register**. + +Now you have **Bundle ID** and **Team ID** that will be used to identify your app. + +#### Team ID + +The developer team ID to include in export options. + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--ios-team-id`](../cli/flet-build.md#--ios-team-id) +2. `[tool.flet.ios].team_id` +3. `[tool.flet.ios.export_methods."EXPORT_METHOD"].team_id` + +##### Example + + + +```bash +flet build ipa --ios-team-id ABCDEFE234 +``` + + +```toml +[tool.flet.ios] +team_id = "ABCDEFE234" +``` + + +### Signing Certificate + +The certificate name, SHA-1 hash, or automatic selector to use for signing the iOS app bundle. +Automatic selectors allow Xcode to pick the newest installed certificate of a particular type. + +The available automatic selectors are: + +- `"Apple Development"` +- `"Apple Distribution"` +- `"Developer ID Application"` +- `"iOS Developer"` +- `"iOS Distribution"` +- `"Mac App Distribution"` +- `"Mac Developer"` + +#### Generating a Certificate Signing Request (CSR) + +Before creating a development or distribution certificate, you need a **CSR (Certificate Signing Request)**. + +1. **Open Keychain Access** on your Mac (++cmd+space++, then search for "Keychain Access"). +2. In the top menu, go to **Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority…** +3. Fill in: + - **User Email Address:** Your Apple Developer email. + - **Common Name:** A descriptive name (e.g., "My App Distribution"). + - **CA Email Address:** Leave this blank. + - **Request is for:** Select "**Saved to disk**". +4. Click **Continue**, choose a location to save the `.certSigningRequest` file, and click **Save**. + +#### Creating a Certificate in Apple Developer Portal + +1. Go to the [Apple Developer Certificates Page](https://developer.apple.com/account/resources/certificates/list). +2. Click the **"+"** button to create a new certificate. +3. Select **"Apple Distribution"** (for App Store & Ad Hoc) or **"Apple Development"** + (for development) and click **Continue**. +4. Upload the **CSR file** you created earlier and click **Continue**. +5. Apple will generate the certificate. Click **Download** to get the `.cer` file. +6. Double-click the downloaded `.cer` file to install it in **Keychain Access**. +7. Open the **Keychain Access** app and ensure the certificate is installed under **"login"** keychain. + The name of the development certificate usually starts with **"Apple development:"** and the name of + the distribution certificate starts with **"Apple distribution:"**. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--ios-signing-certificate`](../cli/flet-build.md#--ios-signing-certificate) +2. `[tool.flet.ios].signing_certificate` +3. `[tool.flet.ios.export_methods."EXPORT_METHOD"].signing_certificate` + +#### Example + + + +```bash +flet build ipa --ios-signing-certificate "Apple Distribution" +``` + + +```toml +[tool.flet.ios] +signing_certificate = "Apple Distribution" +``` + + +### Provisioning Profile + +A **Provisioning Profile** is a file that allows an iOS app to run on physical devices and be +distributed through the App Store or internally. It links your **App ID**, +**Developer/Distribution Certificate**, and **Registered Devices**. + +There are different types of provisioning profiles: + +1. **Development Profile** – Used for testing on physical devices. +2. **Ad Hoc Profile** – Used for distributing an app outside the App Store to specific devices. +3. **App Store Profile** – Used for submitting an app to the App Store. +4. **Enterprise Profile** – Used for internal distribution within an organization. + +#### Creating a New Provisioning Profile + +Follow these steps to create a provisioning profile via the Apple Developer Portal: + +##### Step 1: Go to Apple Developer Portal + +- Visit the [Apple Developer Portal](https://developer.apple.com/account/resources/profiles/list); +- Sign in with your **Apple Developer Account** + +##### Step 2: Create a New Provisioning Profile + +- Click the **"+"** button to add a new provisioning profile; +- Choose the **type of profile**: + - **iOS App Development** – for testing on devices + - **Ad Hoc** – for distributing to specific devices + - **App Store** – for submitting an app to the App Store + - **In-House** – for internal distribution (Enterprise accounts only) +- Click **Continue** + +##### Step 3: Select an App ID + +- Choose the **App ID** that matches your app; +- Click **Continue**. + +##### Step 4: Select a Distribution Certificate + +- Choose the appropriate certificate: + - **iOS Development Certificate** - for **iOS App Development** profile + - **iOS Distribution Certificate** - for **Ad Hoc** or **App Store** profiles +- Click **Continue**. + +##### Step 5: Select Registered Devices (for Development & Ad Hoc) + +- If you selected an **iOS App Development** or **Ad Hoc** profile, select the devices to include; +- Click **Continue**. + +##### Step 6: Name and Generate the Profile + +- Enter a **Profile Name** (e.g., `MyApp Development Profile`); +- Click **Generate**; +- Click **Download** to get the `.mobileprovision` file. + +#### Installing Provisioning Profile + +Provisioning profiles are stored in `~/Library/MobileDevice/Provisioning Profiles` directory. + +To install a downloaded provisioning profile, copy it to `~/Library/MobileDevice/Provisioning\ Profiles` +directory with a new `{UUID}.mobileprovision` name. + +Run the following command to get profile UUID: + +```bash +profile_uuid=$(security cms -D -i ~/Downloads/{profile-name}.mobileprovision | xmllint --xpath "string(//key[.='UUID']/following-sibling::string[1])" -) +echo $profile_uuid +``` + +Run this command to copy profile to `~/Library/MobileDevice/Provisioning Profiles` with a new name `{UUID}.mobileprovision`: + +```bash +cp ~/Downloads/{profile-name}.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/${profile_uuid}.mobileprovision +``` + +:::note[Note] +If the copied profile disappears from the `~/Library/MobileDevice/Provisioning Profiles` directory, +ensure that the Xcode process is not running in the background. +::: + +Finally, you can use the command below to list all installed provisioning profiles, with their names and UUIDs: + +```bash +for profile in ~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision; do security cms -D -i "$profile" | grep -E -A1 '(Name|UUID)' | sed -n 's/.*\(.*\)<\/string>/\1/p' | paste -d ' | ' - -; done +``` + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--ios-provisioning-profile`](../cli/flet-build.md#--ios-provisioning-profile) +2. `[tool.flet.ios].provisioning_profile` +3. `[tool.flet.ios.export_methods."EXPORT_METHOD"].provisioning_profile` + +The profile must match your [Bundle ID](index.md#bundle-id). + +#### Example + + + +```bash +flet build ipa --ios-provisioning-profile "release-testing com.mycompany.example-app" +``` + + +```toml +[tool.flet.ios] +provisioning_profile = "release-testing com.mycompany.example-app" +``` + + +### Export configuration + +#### Export options + +Additional keys to include in the generated `exportOptions.plist` +of the [build template](index.md#build-template). + +For a complete list of supported keys and values, run the following command: + +```bash +xcodebuild -help +``` + +and find the section titled **"Available keys for -exportOptionsPlist"**. + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. `[tool.flet.ios].export_options` (if set, per-method export options are ignored) +2. `[tool.flet.ios.export_methods."EXPORT_METHOD"].export_options` (see [export methods](#export-methods)) +3. `{}` (no extra keys) + +##### Supported value forms + + + +Both simple and complex structures are supported: + +- string +- boolean +- dictionary (nested key-value object) +- array of strings +- array of booleans +- array of dictionaries (including dictionaries that contain arrays) + +Numbers are not yet supported. + + +##### Example + + + +```toml +[tool.flet.ios.export_options] +uploadSymbols = false +compileBitcode = false +thinning = "" + +[tool.flet.ios.export_options.manifest] +appURL = "https://example.com/app.ipa" +displayImageURL = "https://example.com/icon57.png" +fullSizeImageURL = "https://example.com/icon512.png" +``` + + +
+Template translation + +In the [`ios/exportOptions.plist`](index.md#build-template), +the example above will be translated accordingly into this: + +```xml +uploadSymbols + +compileBitcode + +thinning +<none> +manifest + + appURL + https://example.com/app.ipa + displayImageURL + https://example.com/icon57.png + fullSizeImageURL + https://example.com/icon512.png + +``` +
+ +#### Export method + +Defines how the app should be packaged when exporting the `.ipa` file. + +Can be one of the following: + +- `debugging` (or deprecated `development`): used for debugging and testing on development devices. +- `release-testing` (or deprecated `ad-hoc`): used for distributing the app outside the App Store to specific registered devices. +- `app-store-connect` (or deprecated `app-store`): used for submitting the app to the App Store. +- `enterprise`: used for internal distribution within an organization (requires an enterprise account). + +To configure individual settings for one or more export methods, see [export methods](#export-methods). + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--ios-export-method`](../cli/flet-build.md#--ios-export-method) +2. `[tool.flet.ios].export_method` +3. `"debugging"` + +##### Example + + + +```bash +flet build ipa --ios-export-method debugging +``` + + +```toml +[tool.flet.ios] +export_method = "debugging" +``` + + +#### Export methods + +Signing settings can be configured individually per [export method](#export-method). + +Per-method values are used only when the corresponding top-level +`[tool.flet.ios]` setting is not set. The method key must match the `export_method` value exactly. + +Supported keys (same as the top-level settings): + +- [`provisioning_profile`](#provisioning-profile) +- [`signing_certificate`](#signing-certificate) +- [`export_options`](#export-options) +- [`team_id`](#team-id) + +##### Example + + + +```toml +[tool.flet.ios.export_methods."debugging"] +provisioning_profile = "debugging com.mycompany.example-app" +signing_certificate = "Apple Development" + +[tool.flet.ios.export_methods."release-testing"] +provisioning_profile = "release-testing com.mycompany.example-app" +team_id = "ABCDEFE234" +signing_certificate = "Apple Distribution" +export_options = { uploadSymbols = false } + +[tool.flet.ios.export_methods."app-store-connect"] +provisioning_profile = "app-store-connect com.mycompany.example-app" +team_id = "ABCDEFE234" +signing_certificate = "Apple Distribution" +export_options = { uploadSymbols = true } +``` + + +### Permissions + +iOS permissions are declared through [`Info.plist`](#infoplist) privacy usage strings. +You can also use the [cross-platform permission bundles](index.md#predefined-cross-platform-permission-bundles) +to inject common entries, then override or extend them with platform-specific values. + +#### Info.plist + +Add or override `Info.plist` entries for iOS builds. +These values are written to `ios/Runner/Info.plist` of the [build project](index.md#build-template). + +##### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--info-plist`](../cli/flet-build.md#--info-plist) +2. `[tool.flet.ios.info]` +3. Values injected by [cross-platform permission bundles](index.md#permissions), if any. + +#### Supported value forms + + + +Accepts repeated `=` entries. +The `` can be in one of the following forms: + +- `true` or `false` (case-insensitive) for boolean values +- integer and real number literals, for example `32` or `0.5` +- TOML array literals, for example `["myapp", "myapp-beta"]` +- TOML inline tables, for example `{ NSAllowsArbitraryLoads = false }` +- any other value is treated as a string + + +Both simple and complex structures are supported: + +- string +- boolean +- integer +- real +- dictionary (nested key-value object) +- array of strings +- array of booleans +- array of integers +- array of reals +- array of dictionaries (including dictionaries that contain arrays) + + +##### Example + + + +```bash +flet build ipa \ + --info-plist NSCameraUsageDescription="This app needs camera access." \ + --info-plist UIFileSharingEnabled=true \ + --info-plist ExampleInteger=32 \ + --info-plist ExampleReal=0.5 \ + --info-plist 'LSApplicationQueriesSchemes=["myapp", "myapp-beta"]' \ + --info-plist 'FeatureFlags=[true, false]' \ + --info-plist 'RetryDelays=[1, 2, 3]' \ + --info-plist 'OpacitySteps=[0.25, 0.5, 0.75]' \ + --info-plist 'NSAppTransportSecurity={ NSAllowsArbitraryLoads = false }' \ + --info-plist 'CFBundleURLTypes=[{ CFBundleTypeRole = "Editor", CFBundleURLName = "example.com", CFBundleURLSchemes = ["myapp"] }, { CFBundleTypeRole = "Viewer", CFBundleURLName = "example.org", CFBundleURLSchemes = ["myapp-beta"] }]' +``` + + +```toml +[tool.flet.ios.info] +NSCameraUsageDescription = "This app needs camera access." +UIFileSharingEnabled = true +ExampleInteger = 32 +ExampleReal = 0.5 +LSApplicationQueriesSchemes = ["myapp", "myapp-beta"] +FeatureFlags = [true, false] +RetryDelays = [1, 2, 3] +OpacitySteps = [0.25, 0.5, 0.75] +NSAppTransportSecurity = { NSAllowsArbitraryLoads = false } +CFBundleURLTypes = [ + { CFBundleTypeRole = "Editor", CFBundleURLName = "example.com", CFBundleURLSchemes = ["myapp"] }, + { CFBundleTypeRole = "Viewer", CFBundleURLName = "example.org", CFBundleURLSchemes = ["myapp-beta"] }, +] +``` + + +
+Template translation + +In the [`ios/Runner/Info.plist`](index.md#build-template), the +example above will be translated accordingly into this: + +```xml + + + + NSCameraUsageDescription + This app needs camera access. + + UIFileSharingEnabled + + + ExampleInteger + 32 + + ExampleReal + 0.5 + + LSApplicationQueriesSchemes + + myapp + myapp-beta + + + FeatureFlags + + + + + + RetryDelays + + 1 + 2 + 3 + + + OpacitySteps + + 0.25 + 0.5 + 0.75 + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + example.com + CFBundleURLSchemes + + myapp + + + + CFBundleTypeRole + Viewer + CFBundleURLName + example.org + CFBundleURLSchemes + + myapp-beta + + + + + + +``` +
+ +## Deploying an App to an Apple Device for Testing + +You can deploy `.ipa` files directly to an iPhone or iPad on macOS—ideal for +internal testing without publishing to the App Store. + +Follow these steps: + +#### Install and Launch Apple Configurator + +- Install [Apple Configurator](https://apps.apple.com/ca/app/apple-configurator/id1037126344?mt=12) from App Store; +- Find and open it from your Applications folder. + +#### Connect Your iOS Device + +- Connect your device (iPhone or iPad) to your Mac via USB; +- Unlock the connected device, and tap **Trust This Computer**, if prompted; +- Wait for this device to appear in the Apple Configurator. + +#### Add the `.ipa` File + +- Either drag the `.ipa` file onto the connected device in Apple Configurator; +- Or click **Add → Apps**, then browse and select the `.ipa` file from your Mac. + +#### Install the App + +- Click **Prepare** or **Install** to begin the deployment/installation; +- Apple Configurator will install the app on the connected device. + +#### Trust the Developer (for Ad Hoc or Enterprise apps) + +If your app is signed with an **Ad Hoc** or **Enterprise** [provisioning profile](#provisioning-profile), +you'll need to manually trust the developer: + +- On the iOS device, go to **Settings → General → VPN & Device Management**; +- Under **Developer App**, tap your **Developer Profile**; +- Tap **Trust [Your Developer Name]**, then confirm. + +## Uploading app to App Store Connect for distribution + +#### Install and Sign in to Transporter + +- Install and open [**Transporter**](https://apps.apple.com/us/app/transporter/id1450874784) from the Mac App Store. +- Sign in using your **Apple Developer Account** credentials (the same account used for App Store Connect). + +#### Prepare Your `.ipa` File + +- Build your app and export an `.ipa` file using the **app-store-connect** export method. + (**release-testing** is for Ad Hoc device distribution, not App Store Connect.) + +#### Upload the `.ipa` File in Transporter + +- Drag and drop the `.ipa` file directly into the Transporter window, or click "Add App" and select your `.ipa` file from your Mac. +- Click the "..." button next to "Deliver", and select "Verify". +- Wait for Transporter to complete the verification process. +- After successful verification, click "Deliver" to upload your `.ipa` file to App Store Connect. + +#### Check Upload Status + +- Transporter will display a success message upon completion. +- If errors occur, carefully review the details provided, correct the issues, and repeat the upload process. + +#### Confirm Upload in App Store Connect + +- Go to [App Store Connect](https://appstoreconnect.apple.com/). +- Navigate to **Apps → Your App → TestFlight or App Store Version**. +- Your newly uploaded build will initially appear under **Processing** (processing typically takes a few minutes to an hour). +- Once processing completes, your build will become available for submission. You can now **submit the app for review**. diff --git a/website/docs/publish/linux.md b/website/docs/publish/linux.md new file mode 100644 index 0000000000..6a1e1c63cd --- /dev/null +++ b/website/docs/publish/linux.md @@ -0,0 +1,18 @@ +--- +title: "Packaging app for Linux" +--- + +Instructions for packaging a Flet app into a Linux executable. + +:::tip[Note] +This guide provides detailed Linux-specific information. +Complementary and more general information is available [here](index.md). +::: + +## `flet build linux` + +:::note[Note] +This command can be run on **Linux only** (or [WSL](https://docs.microsoft.com/en-us/windows/wsl/about)). +::: + +Builds a Linux executable. diff --git a/website/docs/publish/macos.md b/website/docs/publish/macos.md new file mode 100644 index 0000000000..f50483b8e0 --- /dev/null +++ b/website/docs/publish/macos.md @@ -0,0 +1,359 @@ +--- +title: "Packaging app for macOS" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Instructions for packaging a Flet app into a macOS application bundle. + +:::tip[Info] +This guide provides detailed macOS-specific information. +Complementary and more general information is available [here](index.md). +::: + +## Prerequisites + +### Rosetta 2 + +[Flutter](https://flutter.dev), which we use for packaging, +requires [Rosetta 2](https://support.apple.com/en-us/HT211861) on Apple Silicon: + +```bash +sudo softwareupdate --install-rosetta --agree-to-license +``` + +### Xcode + +[Xcode](https://developer.apple.com/xcode/) 15 or later is required to compile +native Swift or Objective-C code. + +### CocoaPods + +[CocoaPods](https://cocoapods.org/) 1.16 or later is required to install and +compile Flutter plugins. + +## `flet build macos` + +:::note[Note] +This command can be run on **macOS only**. +::: + +Builds a macOS application bundle from your Flet app. + +## Target architecture + +By default, `flet build macos` creates a universal bundle that runs on both +Apple Silicon and Intel Macs. Packaging downloads Python wheels for both +`arm64` and `x86_64` architectures. + +To limit packaging to a specific architecture, see [this](index.md#target-architecture). +This affects which Python wheels are bundled and, in turn, which CPU architectures the app will run on. +You will then have to provide your users with the correct build for their Macs. + +## Permissions + +macOS permissions are declared through [`Info.plist`](#infoplist) privacy usage strings and +app [entitlements](#entitlements). You can also use the [cross-platform permission bundles](index.md#predefined-cross-platform-permission-bundles) +to inject common entries, then override or extend them with platform-specific values. + +### Info.plist + +Add or override `Info.plist` entries for macOS builds. +These values are written to `macos/Runner/Info.plist` of the [build project](index.md#build-template). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--info-plist`](../cli/flet-build.md#--info-plist) +2. `[tool.flet.macos.info]` +3. Values injected by [cross-platform permission bundles](index.md#permissions), if any. + +#### Supported value forms + + + +Accepts repeated `=` entries. +The `` can be in one of the following forms: + +- `true` or `false` (case-insensitive) for boolean values +- integer and real number literals, for example `32` or `0.5` +- TOML array literals, for example `["basic", "advanced"]` +- TOML inline tables, for example `{ NSAllowsArbitraryLoads = false }` +- any other value is treated as a string + + +Both simple and complex structures are supported: + +- string +- boolean +- integer +- real +- dictionary (nested key-value object) +- array of strings +- array of booleans +- array of integers +- array of reals +- array of dictionaries (including dictionaries that contain arrays) + + +#### Example + + + +```bash +flet build macos \ + --info-plist LSApplicationCategoryType="public.app-category.utilities" \ + --info-plist NSSupportsSuddenTermination=true \ + --info-plist ExampleInteger=32 \ + --info-plist ExampleReal=0.5 \ + --info-plist 'SupportedModes=["basic", "advanced"]' \ + --info-plist 'FeatureFlags=[true, false]' \ + --info-plist 'RetryDelays=[1, 2, 3]' \ + --info-plist 'OpacitySteps=[0.25, 0.5, 0.75]' \ + --info-plist 'NSAppTransportSecurity={ NSAllowsArbitraryLoads = false }' \ + --info-plist 'CFBundleDocumentTypes=[{ CFBundleTypeName = "Data File", CFBundleTypeExtensions = ["dat"] }, { CFBundleTypeName = "JSON File", CFBundleTypeExtensions = ["json"] }]' +``` + + +```toml +[tool.flet.macos.info] +LSApplicationCategoryType = "public.app-category.utilities" +NSSupportsSuddenTermination = true +ExampleInteger = 32 +ExampleReal = 0.5 +SupportedModes = ["basic", "advanced"] +FeatureFlags = [true, false] +RetryDelays = [1, 2, 3] +OpacitySteps = [0.25, 0.5, 0.75] +NSAppTransportSecurity = { NSAllowsArbitraryLoads = false } +CFBundleDocumentTypes = [ + { CFBundleTypeName = "Data File", CFBundleTypeExtensions = ["dat"] }, + { CFBundleTypeName = "JSON File", CFBundleTypeExtensions = ["json"] }, +] +``` + + +
+Template translation + +In the [`macos/Runner/Info.plist`](index.md#build-template), the +example above will be translated accordingly into this: + +```xml + + + + LSApplicationCategoryType + public.app-category.utilities + + NSSupportsSuddenTermination + + + ExampleInteger + 32 + + ExampleReal + 0.5 + + SupportedModes + + basic + advanced + + + FeatureFlags + + + + + + RetryDelays + + 1 + 2 + 3 + + + OpacitySteps + + 0.25 + 0.5 + 0.75 + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + + CFBundleDocumentTypes + + + CFBundleTypeName + Data File + CFBundleTypeExtensions + + dat + + + + CFBundleTypeName + JSON File + CFBundleTypeExtensions + + json + + + + + + +``` +
+ +### Entitlements + +Entitlements are property-list key-value pairs that grant an executable permission +to use a service or technology. The supported value type depends on the entitlement +key defined in the +[Apple Developer Entitlements Reference](https://developer.apple.com/documentation/bundleresources/entitlements). + +Entitlements are written to `macos/Runner/DebugProfile.entitlements` and +`macos/Runner/Release.entitlements` in the [build template](index.md#build-template). + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--macos-entitlements`](../cli/flet-build.md#--macos-entitlements) +2. `[tool.flet.macos.entitlement]` +3. Values injected by [cross-platform permission bundles](index.md#permissions), if any. +4. Defaults: + + ```toml + [tool.flet.macos.entitlement] + "com.apple.security.app-sandbox" = false + "com.apple.security.cs.allow-jit" = true + "com.apple.security.network.client" = true + "com.apple.security.network.server" = true + "com.apple.security.files.user-selected.read-write" = true + ``` + +#### Supported value forms + + + +Accepts repeated `=` entries. +The `` can be in one of the following forms: + +- `true` or `false` (case-insensitive) for boolean values +- integer and real number literals, for example `32` or `0.5` +- TOML array literals, for example `["group.example.one", "group.example.two"]` +- TOML inline tables, for example `{ "com.apple.mail" = ["compose"] }` +- any other value is treated as a string + + +Both simple and complex structures are supported: + +- string +- boolean +- integer +- real +- dictionary (nested key-value object) +- array of strings +- array of booleans +- array of integers +- array of reals +- array of dictionaries (including dictionaries that contain arrays) + + +#### Example + + + +```bash +flet build macos \ + --macos-entitlements com.apple.security.network.client=true \ + --macos-entitlements com.apple.developer.ubiquity-kvstore-identifier=ABCDE12345.dev.example.myapp \ + --macos-entitlements ExampleInteger=32 \ + --macos-entitlements ExampleReal=0.5 \ + --macos-entitlements 'com.apple.security.application-groups=["group.dev.example.myapp", "group.dev.example.shared"]' \ + --macos-entitlements 'ExampleBooleanArray=[true, false]' \ + --macos-entitlements 'com.apple.security.scripting-targets={ "com.apple.mail" = ["compose", "send"] }' \ + --macos-entitlements 'ExampleArrayOfDictionaries=[{ Name = "alpha", Enabled = true }, { Name = "beta", Enabled = false }]' +``` + + +```toml +[tool.flet.macos.entitlement] +"com.apple.security.network.client" = true +"com.apple.developer.ubiquity-kvstore-identifier" = "ABCDE12345.dev.example.myapp" +ExampleInteger = 32 +ExampleReal = 0.5 +"com.apple.security.application-groups" = [ + "group.dev.example.myapp", + "group.dev.example.shared", +] +ExampleBooleanArray = [true, false] +"com.apple.security.scripting-targets" = { "com.apple.mail" = ["compose", "send"] } +ExampleArrayOfDictionaries = [ + { Name = "alpha", Enabled = true }, + { Name = "beta", Enabled = false }, +] +``` + + +
+Template translation + +In both [`macos/Runner/DebugProfile.entitlements`](index.md#build-template) and +[`macos/Runner/Release.entitlements`](index.md#build-template), the example above +will be translated accordingly into this: + +```xml +com.apple.security.network.client + +com.apple.developer.ubiquity-kvstore-identifier +ABCDE12345.dev.example.myapp +ExampleInteger +32 +ExampleReal +0.5 +com.apple.security.application-groups + + group.dev.example.myapp + group.dev.example.shared + +ExampleBooleanArray + + + + +com.apple.security.scripting-targets + + com.apple.mail + + compose + send + + +ExampleArrayOfDictionaries + + + Name + alpha + Enabled + + + + Name + beta + Enabled + + + +``` +
diff --git a/website/docs/publish/web/dynamic-website/hosting/fly-io.md b/website/docs/publish/web/dynamic-website/hosting/fly-io.md new file mode 100644 index 0000000000..d9aa96bd6c --- /dev/null +++ b/website/docs/publish/web/dynamic-website/hosting/fly-io.md @@ -0,0 +1,105 @@ +--- +title: "Fly.io" +--- + +[Fly.io](https://fly.io) works well for Flet apps: it supports WebSockets, deploys close to users via multiple [regions](https://fly.io/docs/reference/regions/), and has a [free tier](https://fly.io/docs/about/pricing/#free-allowances) suitable for small projects. + +## Prerequisites + +1. Install [flyctl](https://fly.io/docs/getting-started/installing-flyctl/). +2. Authenticate: + +```bash +fly auth login +``` + +## Project files + +Place the following files in your app directory. + +### `requirements.txt` + +At minimum: + +```txt title="requirements.txt" +flet +``` + +### `fly.toml` + +Fly app configuration: + +```toml title="fly.toml" +app = "" + +kill_signal = "SIGINT" +kill_timeout = 5 +processes = [] + +[env] + FLET_SESSION_TIMEOUT = "60" + +[http_service] + internal_port = 8000 + force_https = true + auto_stop_machines = true + auto_start_machines = true + min_machines_running = 0 + + [http_service.concurrency] + type = "connections" + soft_limit = 200 + hard_limit = 250 +``` + +- Replace `` with the app name you want. It will also be used in the final + URL of your app, in the form, `https://.fly.dev`. +- `internal_port` must correspond to the [`FLET_SERVER_PORT`](../../../../reference/environment-variables.md#flet_server_port), which is `8000` by default. +- [`FLET_SESSION_TIMEOUT`](../../../../reference/environment-variables.md#flet_session_timeout) controls session lifetime (seconds). +- For other variables, see [environment variables reference](../../../../reference/environment-variables.md). + +### `Dockerfile` + +Create a `Dockerfile` containing the commands to build your application container, +for example: + +```Dockerfile title="Dockerfile" +FROM python:3-alpine + +WORKDIR /app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8000 + +CMD ["python", "main.py"] +``` + +`main.py` is the app's [entry point](../../../index.md#entry-point). If your file name differs, update accordingly. + +:::info[Info] +Fly.io deploys apps as Docker containers and provides a free remote Docker builder, +so you don’t need Docker installed locally. +::: + +## Deploy + +From your app directory: + +1. Create the Fly app: + ```bash + fly apps create --name + ``` + +2. Deploy: + ```bash + fly deploy + ``` + +3. Open app in browser: + ```bash + fly apps open + ``` diff --git a/website/docs/publish/web/dynamic-website/hosting/index.md b/website/docs/publish/web/dynamic-website/hosting/index.md new file mode 100644 index 0000000000..e1b5cc30bd --- /dev/null +++ b/website/docs/publish/web/dynamic-website/hosting/index.md @@ -0,0 +1,13 @@ +--- +title: "Hosting" +--- + +Flet apps use WebSockets for real-time partial updates of their UI and sending events back to your program. +When choosing a hosting provider for your Flet app you should pay attention to their support of WebSockets. +Sometimes WebSockets are not allowed or come as a part of more expensive offering, sometimes there is a proxy +that periodically breaks WebSocket connection by a timeout (Flet implements re-connection logic, but it could +be unpleasant behavior for users of your app anyway). + +Another important factor while choosing a hosting provider for Flet app is latency. Every user action on UI sends +a message to Flet app and the app sends updated UI back to user. Make sure your hosting provider has multiple data +centers, so you can run your app closer to the majority of your users. diff --git a/website/docs/publish/web/dynamic-website/hosting/replit.md b/website/docs/publish/web/dynamic-website/hosting/replit.md new file mode 100644 index 0000000000..d225b54213 --- /dev/null +++ b/website/docs/publish/web/dynamic-website/hosting/replit.md @@ -0,0 +1,33 @@ +--- +title: "Replit" +--- + +[Replit](https://replit.com/) is an online IDE and hosting platform for web apps written in any language. Their free tier allows running any number of apps with some performance limitations. + +To run your app on Replit: + +* [Sign up](https://replit.com/signup?from=landing) on Replit. +* Click "New Repl" button, select "Python" template and type the name of your repl, e.g. `my-flet-app`. Alternatively, go to [Flet template](https://replit.com/@fletdev/Flet?v=1) page and click **Use Template** button. Flet template has everything configured for you, so you can jump to `main.py` and update your program right away. + +* Open `.replit` file on the left and add these two options to the root: + +```toml +# Stops the packager from installing packages when running the Repl +disableInstallBeforeRun = true +# Stops the packager from guessing and auto-installing packages, but it still runs to install packages when running the Repl +disableGuessImports = true +``` + + + +* On "Tools" pane click "Dependencies" and search for `flet` package and click "Install" button. +* Open `main.py` on "Files" pane and copy-paste your app. +* Modify call to `ft.run()` and include `view=ft.AppView.WEB_BROWSER` parameter: + +```python +ft.run(main, view=ft.AppView.WEB_BROWSER) +``` + +* Run the app. Enjoy. + + diff --git a/website/docs/publish/web/dynamic-website/hosting/self-hosting.md b/website/docs/publish/web/dynamic-website/hosting/self-hosting.md new file mode 100644 index 0000000000..6e18b6c930 --- /dev/null +++ b/website/docs/publish/web/dynamic-website/hosting/self-hosting.md @@ -0,0 +1,111 @@ +--- +title: "Self-Hosting" +--- + +Host a Flet app on your own server with NGINX. + +There are free and inexpensive cloud server tiers available at [AWS](https://aws.amazon.com/free/), [Oracle](https://www.oracle.com/cloud/free/), [Linode](https://www.linode.com/pricing/), and more. + +## Setup Flet Environment + +### `requirements.txt` and virtualenv + +Create `requirements.txt` with a list of application dependencies. At minimum it should contain `flet` module: + +```txt +flet +``` + +Create a virtualenv and install requirements: + +``` +python -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +### Sample Flet app + +```python +import flet as ft + +def main(page: ft.Page): + page.title = "My Flet app" + page.add(ft.Text("Hello, world!")) + +if __name__ == "__main__": + ft.run(main) +``` + +Flet app will be served from the root URL, but you can configure `FLET_WEB_APP_PATH` environment variable +to serve beneath the root e.g. `/apps/myapp`. + +By default, Flet web app will be running on port `8000`, but you can change that by setting up `FLET_SERVER_PORT` environment variable. + +[Complete list of environment variables](../../../../publish/web/dynamic-website/index.md#environment-variables) supported by a web app. + +## Automatically start Flet app + +### Create `systemd` unit file + +Automatically start the Flet app using a `systemd` service unit file `flet.service`. + +Setup below assumes your Flet app script is defined in `$HOME/flet-app/main.py`. Replace `User`, `Group`, `WorkingDirectory`, etc. as per your setup. + +```ini +[Unit] +Description=Flet App +After=network.target + +[Service] +User=ubuntu +Group=ubuntu +WorkingDirectory=/home/ubuntu/flet-app +Environment="PATH=/home/ubuntu/flet-app/.venv/bin" +ExecStart=/home/ubuntu/flet-app/.venv/bin/python /home/ubuntu/flet-app/main.py + +[Install] +WantedBy=multi-user.target +``` + +### Enable Flet app service + +``` +cd /etc/systemd/system +sudo ln -s /home/ubuntu/flet-app/flet.service +sudo systemctl start flet +sudo systemctl enable flet +sudo systemctl status flet +``` + +## NGINX Proxy Setup + +NGINX will proxy the Flet app and the websocket. + +In your `/etc/nginx/sites-available/*` config file, updating path and port as needed: + +```txt + location / { + proxy_pass http://127.0.0.1:8000/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection keep-alive; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /ws { + proxy_pass http://127.0.0.1:8000/ws; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +``` + +That's it! Restart NGINX, and open your app in a browser. diff --git a/website/docs/publish/web/dynamic-website/index.md b/website/docs/publish/web/dynamic-website/index.md new file mode 100644 index 0000000000..bdced2e703 --- /dev/null +++ b/website/docs/publish/web/dynamic-website/index.md @@ -0,0 +1,358 @@ +--- +title: "Publish web app as dynamic website" +--- + +Flet runs your app as a [FastAPI](https://fastapi.tiangolo.com/) (ASGI) app +to serve a dynamic website. + +It uses [Uvicorn](https://www.uvicorn.org/) by default, but any ASGI-compatible server can be used instead. + +### Sync and async handlers + +In a Flet web app you can mix sync and async handlers. + +For example, you can write an app like this: + +```python +import flet as ft +import time +import asyncio + +def main(page: ft.Page): + + def handler(e): + time.sleep(3) + page.add(ft.Text("Handler clicked")) + + async def handler_async(e): + await asyncio.sleep(3) + page.add(ft.Text("Async handler clicked")) + + page.add( + ft.Button("Call handler", on_click=handler), + ft.Button("Call async handler", on_click=handler_async) + ) + +ft.run(main) +``` + +In the example, a click on one button is handled by a blocking handler while a click +on the second button calls an async handler. The first handler runs in a +`threading.Thread`, while the second runs as an `asyncio.Task`. + +In web apps, threads are a finite resource. A thread pool is usually used and can +become a bottleneck as the number of users grows. + +If your app is mostly doing I/O (database, web API) and you can use async-ready +libraries, prefer async handlers. + +Check [FastAPI's article about async/await](https://fastapi.tiangolo.com/async/) to better understand the differences between concurrency and parallelism. + +## Running the app locally + +Use `--web` (`-w`) option to start a Flet app as a web app: + +```bash +flet run --web app.py +``` + +A new browser window/tab will be opened and the app will use a random TCP port. + +To run on a fixed port use `--port` (`-p`): + +```bash +flet run --web --port 8000 app.py +``` + +## Running the app in production + +You can run your program directly with `python`: + +```bash +python app.py +``` + +[Uvicorn](https://www.uvicorn.org/) web server is used by default to host the web app. + +If Flet detects a headless Linux environment (such as a Docker container +or EC2 VM): +1. Port `8000` will be used to run the app. +2. A browser window will not be opened. + +If Flet cannot detect a headless environment, you can force that behavior +by defining the following environment variable: + +```bash +FLET_FORCE_WEB_SERVER=true +``` + +### ASGI web server + +You can host your Flet web app with any ASGI-compatible server such as [Uvicorn](https://www.uvicorn.org/) (used by default), [Hypercorn](https://pgjones.gitlab.io/hypercorn/) or [Daphne](https://github.com/django/daphne). + +Just tell Flet to export ASGI app: + +```python title="main.py" +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text("Hello ASGI!")) + +app = ft.run(main, export_asgi_app=True) +``` + +#### Hypercorn + +[Hypercorn](https://github.com/pgjones/hypercorn/) is another ASGI web server inspired by Gunicorn. + +To run the app with Hypercorn: + +```bash +hypercorn main:app --bind 0.0.0.0:8000 +``` + +#### Daphne + +[Daphne](https://github.com/django/daphne) is a HTTP, HTTP2 and WebSocket protocol server for ASGI and ASGI-HTTP, developed to power Django Channels. + +To run the app with Daphne: + +```bash +daphne -b 0.0.0.0 -p 8000 main:app +``` + +#### Gunicorn + +[Gunicorn](https://gunicorn.org/) is popular web server to run Python web applications. While it implements WSGI specification it's possible to run ASGI FastAPI apps with a [worker process class](https://fastapi.tiangolo.com/deployment/server-workers/) provided by Uvicorn: + +```bash +gunicorn --bind 0.0.0.0:8000 -k uvicorn.workers.UvicornWorker counter:app +``` + +## Assets + +When you open a Flet app in the browser, its `index.html`, Flutter engine, +favicon, images and other web app resources are served by a web server. +These resources are bundled with `flet` Python package. However, there are +situations when you need to modify the contents of certain files to customize +the appearance of your app or its behavior, for example: + +* Favicon. +* App loading animation. +* `manifest.json` with PWA details. + +You can specify `assets_dir` in `flet.run()` to set the location of assets that +should be available to the application. `assets_dir` should be relative to +your `main.py` directory or an absolute path. +Default value for `assets_dir` argument is `assets`. + +For example, consider the following program structure: + +``` +/assets + /images/my-image.png +main.py +``` + +You can access your images in the application as follows: + +```python +import flet as ft + +def main(page: ft.Page): + page.add(ft.Image(src=f"/images/my-image.png")) + +ft.run(main, assets_dir="assets") +``` + +### Customizing web app + +#### Favicon + +To override favicon with your own put `favicon.png` file into the root of assets directory. +It should be a PNG image with the size of at least 32x32 pixels. + +#### Loading animation + +To override the Flet animation image, put `icons/loading-animation.png` with your own app logo +in the root of the assets directory. + +#### PWA + +Progressive Web Apps, or PWAs, offer a way to turn app-like websites into website-like apps. + +Check [PWAs Turn Websites Into Apps: Here's How](https://www.pcmag.com/how-to/how-to-use-progressive-web-apps) for the PWA introduction. + +Browsers that support PWA ([installation instructions](#pwa)): + +* **Chrome** on all platforms +* **Edge** on all platforms +* **Firefox** on Android +* **Safari** on iOS and iPadOS + +:::info[Info] +The information in this section is based on the following sources (check them out for more details): + +* [General information about PWAs](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps) +* [PWA manifests](https://developer.mozilla.org/en-US/docs/Web/Manifest) +::: + +#### Manifest + +You can change PWA's name, description, colors and other information in `manifest.json` that must be put +in the root of `assets` directory. + +Here are the links to the most common manifest items that you'd like to customize: + +* [`name`](https://developer.mozilla.org/en-US/docs/Web/Manifest/name) - the name of the web application as it is usually displayed to the user. +* [`short_name`](https://developer.mozilla.org/en-US/docs/Web/Manifest/short_name) - the name of the web application displayed to the user if there is not enough space to display `name`. +* [`description`](https://developer.mozilla.org/en-US/docs/Web/Manifest/description) - explains what the application does. +* [`theme_color`](https://developer.mozilla.org/en-US/docs/Web/Manifest/theme_color) - defines the default theme color for the application. +* [`background_color`](https://developer.mozilla.org/en-US/docs/Web/Manifest/background_color) - defines a placeholder background color for the application page to display before its stylesheet is loaded. + +#### Icons + +Custom icons should be placed in `assets/icons` directory: + +* `icon-192.png`, `icon-512.png` - app icons displayed in Windows taskbar. +* `icon-maskable-192.png`, `icon-maskable-512.png` - app icons displayed in Android. +* `apple-touch-icon-192.png` - app icon displayed in iOS. + +## Environment variables + +Every aspect of web app hosting can be additionally controlled +with [environment variables](../../../reference/environment-variables.md). + +## Advanced FastAPI scenarios + +### Flet FastAPI app + +- `flet.fastapi.app()` creates a FastAPI application to handle Flet sessions and + mounts the following endpoints at the app root: + - `/ws` (WS) - WebSocket handler for the Flet app. It calls `main()` when a new + WebSocket connection is established and a new app session is created. +- `/upload` (PUT) - file uploads handler. +- `/oauth_callback` (GET) - OAuth flow callback handler. +- `/` (GET) - Flet app static files with SPA catch-all handler. + +### Hosting multiple Flet apps under the same domain + +```python +import flet as ft +import flet.fastapi as flet_fastapi + +async def root_main(page: ft.Page): + page.add(ft.Text("This is root app!")) + +async def sub_main(page: ft.Page): + page.add(ft.Text("This is sub app!")) + +app = flet_fastapi.FastAPI() + +app.mount("/sub-app", flet_fastapi.app(sub_main)) +app.mount("/", flet_fastapi.app(root_main)) +``` + +Sub-apps must be mapped before the root Flet app as it configures catch-all `index.html` for SPA. + +Run the app with `uvicorn` and visit http://127.0.0.1:8000 and +then http://127.0.0.1:8000/sub-app/ to see both Flet apps running. + +Notice the trailing slash in `/sub-app/` - without it the request will be routed to the root app. + +### Adding Flet to the existing FastAPI app + +```python +from contextlib import asynccontextmanager + +import flet as ft +import flet.fastapi as flet_fastapi +from fastapi import FastAPI + +@asynccontextmanager +async def lifespan(app: FastAPI): + await flet_fastapi.app_manager.start() + yield + await flet_fastapi.app_manager.shutdown() + +app = FastAPI(lifespan=lifespan) + +async def main(page: ft.Page): + page.add(ft.Text("Hello, Flet!")) + +app.mount("/flet-app", flet_fastapi.app(main)) +``` + +When adding a Flet app to an existing FastAPI app you need to call +`flet_fastapi.app_manager.start()` on app start and +`flet_fastapi.app_manager.shutdown()` on shutdown. Use the way that best suits you: +lifespan (in the example above) or app events. + +`app_manager.start()` method starts background tasks cleaning up expired sessions and OAuth flow states. + +`app_manager.shutdown()` method removes any temporary files created by a Flet app. + +### Configuring individual Flet endpoints + +#### Static files + +A FastAPI app to serve static Flet app files (index.html, manifest.json, Flutter JS app, etc.) and user assets. + +```python +from flet.fastapi import FastAPI, FletStaticFiles + +app = FastAPI() + +# mount to the root of web app +app.mount(path="/", app=FletStaticFiles()) +``` + +#### WebSocket handler + +Handles WebSocket connections from the Flet client running in the browser. The WebSocket +channel is used to send events from the browser to the backend and receive page updates. + +```python +import asyncio +import flet as ft +from flet.fastapi import FletApp, app_manager + +async def main(page: ft.Page): + page.add(ft.Text("Hello, Flet!")) + +@app.websocket("/app1/ws") +async def flet_app(websocket: WebSocket): + await FletApp( + loop=asyncio.get_running_loop(), + executor=app_manager.executor, + main=main, + before_main=None, + ).handle(websocket) +``` + +#### Uploads handler + +Handles file uploads by [`FilePicker`](../../../services/filepicker.md) control. +This endpoint is optional - if your app doesn't use +[`FilePicker`](../../../services/filepicker.md), then it's unnecessary. + +```python +from flet.fastapi import FletUpload + +@app.put("/upload") +async def flet_uploads(request: Request): + await FletUpload("/Users/feodor/Downloads/123").handle(request) +``` + +#### OAuth callback handler + +Handles OAuth flow callback requests. If your app doesn't use +[authentication](../../../cookbook/authentication.md), then this endpoint is unnecessary. + +```python +from flet.fastapi import FletOAuth + +@app.get("/oauth_callback") +async def flet_oauth(request: Request): + return await FletOAuth().handle(request) +``` diff --git a/website/docs/publish/web/index.md b/website/docs/publish/web/index.md new file mode 100644 index 0000000000..cadefd8522 --- /dev/null +++ b/website/docs/publish/web/index.md @@ -0,0 +1,25 @@ +--- +title: "Publish Flet web app" +--- + +# Publish Flet web app + +Flet allows publishing your app as a **static** or **dynamic** website. + +1. **[Static website]** - content is delivered as-is and Python runs in the browser (Pyodide). + +2. **[Dynamic website]** - content is generated per user and Python runs on the server. + +Here is a table comparing Flet app running as a static vs dynamic website: + +| | [Static website] | [Dynamic website] | +|--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| +| **Loading time** | ⬇️ Slower - Python runtime (Pyodide) along with app's Python code and all its dependencies must be loaded into the browser. Pyodide initialization takes time too. | ✅ Faster - the app stays and runs on the server. | +| **Python compatibility** | ⬇️ Not every program that works with native Python [can be run with Pyodide](https://pyodide.org/en/stable/usage/wasm-constraints.html) | ✅ Any Python package can be used. | +| **Responsiveness** | ✅ Zero latency between user-generated events (clicks, text field changes, drags) and page updates. | ⬇️ Non-zero latency - user-generated events are communicated to a server via WebSockets. UI updates are communicated back. | +| **Performance** | ⬇️ Slower - Pyodide is currently 3x-5x slower than native Python because of WASM | ✅ Faster - the code is running on the server by native Python. | +| **Code protection** | ⬇️ Low - app's code is loaded into a web browser and can be inspected by a user. | ✅ High - the app is running on the server. | +| **Hosting** | ✅ Cheap/Free - no code is running on the server and thus the app can be hosted anywhere: GitHub Pages, Cloudflare Pages, Replit, Vercel, a shared hosting or your own VPS. | ⬇️ Paid - the app requires Python code to run on the server and communicate with a web browser via WebSockets. | + +[Static website]: static-website/index.md +[Dynamic website]: dynamic-website/index.md diff --git a/website/docs/publish/web/static-website/hosting/cloudflare.md b/website/docs/publish/web/static-website/hosting/cloudflare.md new file mode 100644 index 0000000000..0f4d709c13 --- /dev/null +++ b/website/docs/publish/web/static-website/hosting/cloudflare.md @@ -0,0 +1,107 @@ +--- +title: "Hosting Flet website on Cloudflare" +--- + +This guide provides the instructions for hosting Flet static website on Cloudflare. + +Before we get to the deployment, you will need an account. Get one from [here](https://dash.cloudflare.com/sign-up/pages), or simply login if you already have one. After signing up, you will have to verify your email address by clicking the link you will receive in your email. Check the spams too, if you don’t get it in your inbox. + +In your account, from the side menu, select "Pages" as shown below: + + + +And from there, select the “Create a project” button: + + + +Cloudflare proposes three ways to create a project. Only the first two will be exposed here: +- Connect to a git provider +- Direct upload + + + +## Connecting to a Git provider + +:::note +This method works for `flet publish` command only. +::: +For this, you will need to have a [GitHub](https://github.com/) or [GitLab](https://gitlab.com/) account. In this account should be the repository you plan to use. An example could be found in this [repo](https://github.com/ndonkoHenri/Flutter-Counter-Clone). + +Click on the “Connect to Git” blue button: + + + +From there, select the tab with the service containing your repository. Then, connect your account. Select one of the suggested options, then click on “Install & Authorize”. + + + +Choose the repository to be used, and press on the “Begin setup” button. + + + +Before moving on, add a `runtime.txt` file in your repo. It should contain the python version to be used. In the file enter 3.7 which is the latest python version Cloudflare uses at time of writing. + +[Here](https://github.com/ndonkoHenri/Flutter-Counter-Clone/blob/master/runtime.txt) is an example from the repo above. + +Having this done, we can now move to the next step which will be to configure some build and deployment settings for your site. + +Set the name of your project, and the production branch to be used. The production branch is simply the branch of your repo to which any push of a commit will automatically trigger a deployment to your production environment. Pushes to your other branches will trigger deployment instead to your preview environment. + +After setting these two, jump down to the “Build settings” section where we will be setting up the build instructions. + +Skip the “Framework preset” (allow None) because Flet is neither in the list nor a JavaScript framework :) + +The “Build command” depends on your application's structure. Follow the guide in the sections above to come up with your custom build command. + + + +When the build command is ran by flet, a folder named ‘dist’ is created which will contain all the web files required by Cloudflare pages. Set it as your output directory. Note that this file will not be added to your repository, because Cloudflare only has read access to your code. + + + +You could optionally specify advanced parameters: the root directory (the directory in which Cloudflare runs the build command), and Environment variables (variables to be used during build time). +Now, click on the “Save and Deploy” button and let Cloudflare do the remaining job for you. + + + +Click on the URL that will be shown to move to your deployed site. + + + +If when opening the site you see a Cloudflare error, it means they haven’t completely finished the setup. So, simply wait for a minute then refresh the page, and you will see your application running. +Test the above deployed site [here](https://flet-counter.pages.dev/). + +## Direct Upload + +:::note +This method works for both `flet build web` and `flet publish` commands. +::: +Click on “Upload assets”. In step one, give your project a name. Remember that the name you will give will be used to determine the link to which your project will be deployed to. + +The second step requires you to upload your project’s assets, either as folder or a zip file (with all the assets inside). If you already have one of them, then use the drag-and-drop or select them using the folder picker. + +If you don’t yet have these assets but already have an app you've built, use the `flet publish` command in the directory containing your app files, and a `dist` folder will be created which you will then upload to Cloudflare pages as mentioned above. + +After the upload press on “Deploy site” button at the bottom. + + + +You will then see a success message with a link to your deployed website. Test an example of a deployed site [here](https://todo-2.pages.dev/). + + + +If when opening the site you see a Cloudflare error, it means they haven’t completely finished the setup. So, simply wait for a minute then refresh the page, and you will see your application running. +You can now click on the “Continue to project” button to monitor your deployments, or create new ones following the same steps above. + +## Troubleshooting + +When Flet app is running in a web browser all its `print()` statements are displayed in "Console" tab of Developer Tools in a browser. `print()` can be used as a simple debugging tool. + +You can also use `logging` module and output messages to Console with different severity. + +To enable detailed Flet logging add this to your program: + +```python +import logging +logging.basicConfig(level=logging.DEBUG) +``` diff --git a/website/docs/publish/web/static-website/hosting/github-pages.md b/website/docs/publish/web/static-website/hosting/github-pages.md new file mode 100644 index 0000000000..a6b7d202c3 --- /dev/null +++ b/website/docs/publish/web/static-website/hosting/github-pages.md @@ -0,0 +1,119 @@ +--- +title: "Hosting Flet website on GitHub Pages" +--- + +This guide shows how to build a Flet static web app and deploy it to [GitHub Pages](https://pages.github.com/) with GitHub Actions. + +## Setup + +1. Open your repository root. +2. Create this folder if it does not exist: `.github/workflows/` +3. Create a workflow file in that folder, for example: `.github/workflows/build-deploy.yml` - must have the `.yml` or `.yaml` file extension. +4. Copy the [workflow configuration](#workflow) below into that file and adjust to your needs. +5. Commit and push to GitHub. +6. Open the **Actions** tab to monitor build/deploy progress. + +:::danger[Repository settings] +In GitHub, open **Settings** → **Pages** and make sure deployment source is **GitHub Actions**. +::: + +## Workflow + +```yaml +name: Web Build + Deploy to GitHub Pages # (1)! + +on: # (2)! + push: # (3)! + pull_request: # (4)! + workflow_dispatch: # (5)! + +concurrency: # (6)! + group: "pages" # (7)! + cancel-in-progress: false # (8)! + +env: # (9)! + UV_PYTHON: 3.12 # (10)! + + # https://flet.dev/docs/reference/environment-variables + FLET_CLI_NO_RICH_OUTPUT: 1 # (11)! + +jobs: + build: + name: Build web app + runs-on: ubuntu-latest # (12)! + + steps: + - name: Checkout repository + uses: actions/checkout@v4 # (13)! + + - name: Setup uv + uses: astral-sh/setup-uv@v6 # (14)! + + - name: Build app + shell: bash + run: | # (15)! + uv run flet build web --yes --verbose --base-url ${GITHUB_REPOSITORY#*/} --route-url-strategy hash + + - name: Upload Pages Artifact + uses: actions/upload-pages-artifact@v4.0.0 # (16)! + with: + path: build/web # (17)! + name: web-build-artifact # (18)! + retention-days: 20 # (19)! + + deploy: + name: Deploy to GitHub Pages + if: github.event_name == 'push' && github.ref == 'refs/heads/main' # (20)! + needs: build # (21)! + runs-on: ubuntu-latest + + permissions: # (22)! + pages: write + id-token: write + + environment: # (23)! + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + steps: + - name: Setup Pages + uses: actions/configure-pages@v5 # (24)! + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4.0.5 # (25)! + with: + artifact_name: web-build-artifact # (26)! +``` + +1. Workflow name shown in the Actions list. +2. Trigger block for the workflow. +3. Builds on every push. +4. Builds on pull request updates. +5. Allows manual runs from the Actions tab. +6. Concurrency settings for GitHub Pages deployments. +7. Places deployments into the same `pages` concurrency group. +8. Keeps the currently running deployment instead of canceling it. +9. Environment variables available to all jobs. +10. Python version used by `uv`. +11. Produces cleaner CI logs by disabling rich output. +12. Runs the build job on GitHub-hosted Ubuntu. +13. Checks out repository code. View its docs [here](https://github.com/actions/checkout). +14. Installs `uv`. View its docs [here](https://github.com/astral-sh/setup-uv). +15. Builds static web output and sets: + - `--base-url ${GITHUB_REPOSITORY#*/}` so project pages deploy under `//`. + If your repository is `.github.io`, use `--base-url /` instead of repository name. ([docs](../index.md#base-url)) + - `--route-url-strategy hash` so routing works on static hosting without server-side rewrites. ([docs](../index.md#route-url-strategy)) +16. Uploads static files as a Pages artifact. View its docs [here](https://github.com/actions/upload-pages-artifact). +17. Uses `build/web` as artifact source. +18. Artifact name used later by deploy step. +19. Keeps the artifact for 20 days. +20. Deploys only on pushes to `main`. PRs only build but don't deploy. Adjust as needed. +21. Waits for successful build job before deploy. +22. Required permissions for Pages deployment. +23. Connects deployment output URL to the GitHub environment. +24. Configures Pages runtime. View its docs [here](https://github.com/actions/configure-pages). +25. Deploys artifact to GitHub Pages. View its docs [here](https://github.com/actions/deploy-pages). +26. Must match the uploaded artifact name. + +See it in action [here](https://github.com/ndonkoHenri/flet-github-action-workflows). diff --git a/website/docs/publish/web/static-website/index.md b/website/docs/publish/web/static-website/index.md new file mode 100644 index 0000000000..7b9c15926e --- /dev/null +++ b/website/docs/publish/web/static-website/index.md @@ -0,0 +1,304 @@ +--- +title: "Publish web app as static website" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; + +Instructions for publishing a Flet app as a standalone static website (SPA) that +runs entirely in the browser with [Pyodide](https://pyodide.org/en/stable/index.html). +No Python code runs on the server. + +Pyodide is a port of CPython to WebAssembly (WASM) and has +some [limitations](https://pyodide.org/en/stable/usage/wasm-constraints.html). + +:::note[Native Python packages] +Native Python packages (vs "pure" Python packages written in Python only) are packages +partially written in C, Rust, or other languages producing native code. +Example packages are `numpy`, `cryptography`, `lxml`, `pydantic-core`. + +Pyodide comes with a list of [built-in packages](https://pyodide.org/en/stable/usage/packages-in-pyodide.html). +To use a package from PyPI, it must be pure Python or provide a wheel built for +[Emscripten](https://pyodide.org/en/stable/development/new-packages.html). +::: + +:::note[Async and threading] +Static websites run in a single browser thread. You can use sync and async handlers, +but long-running CPU work or blocking calls will freeze the UI. Prefer async I/O, +or move heavy work to a server and call it via a web API. +::: + +:::tip[Micropip] +Pyodide installs packages with [micropip](https://pypi.org/project/micropip/). +You can use the [Micropip API](https://micropip.pyodide.org/en/stable/project/api.html) +directly in your Flet app: + +```python +import sys + +if sys.platform == "emscripten": + import micropip + await micropip.install("regex") +``` +::: + +## Differences + +There are two ways to publish a static website: [`flet build web`](#flet-build-web) and [`flet publish`](#flet-publish). +Both produce a static site that runs in the browser via Pyodide. They +differ mainly in how and when Python dependencies are installed: + +| | [`flet publish`](#flet-publish) | [`flet build web`](#flet-build-web) | +|-------------------------------|-------------------------------------------------------|--------------------------------------------------------------------------------------| +| Flutter required | No | Yes | +| Dependency install | At runtime, in the browser (`micropip`) | At build time, on your machine (`pip`) | +| Build time | Faster — no Flutter compilation, no local pip install | Slower — Flutter build + local dependency install | +| Initial load time | Slower — wheels are fetched from PyPI on page load | Faster — dependencies are already bundled | +| Pure-Python wheels | ✅ | ✅ | +| Pyodide-built binary wheels | ✅ (from Pyodide CDN) | ✅ (auto-detected from Pyodide registry) | +| Source distributions (sdists) | ❌ `micropip` can't build sdists in the browser | ✅ pure-Python sdists, opt in via [`source_packages`](../../index.md#source-packages) | + +### Sdist-only dependencies + +A common failure mode with `flet publish` is a (transitive) dependency that ships only a +source distribution (`.tar.gz`, no wheel) — for example, +[`docopt`](https://pypi.org/project/docopt/#files). `micropip` cannot build +sdists, so load fails with: + +``` +ValueError: Can't find a pure Python 3 wheel for '' +``` + +In such cases, we suggest switching to [`flet build web`](#flet-build-web) and +adding the package to [`source_packages`](../../index.md#source-packages). +**Note** that `source_packages` only works for **pure-Python** sdists. Sdists with C/Rust +extensions (e.g. `numpy`, `cryptography`) cannot be built for Pyodide — use Pyodide's +[built-in packages](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) instead. + +## `flet publish` + +Does not require Flutter. It packages your app and installs dependencies in the +browser at runtime via [micropip](https://pypi.org/project/micropip/). + +To publish an app, run: + +```bash +flet publish +``` + +The website is published to [`--distpath`](../../../cli/flet-publish.md#--distpath) (default: `./dist`). + +### Testing the site + +You can try published Flet app using [`flet serve`](../../../cli/flet-serve.md) command: + +```bash +flet serve dist +``` + +Then, open `http://localhost:8000` in your browser to check the published app. + +### Assets + +If the [assets](../../../cookbook/assets.md) directory exists (default: `./assets`), its contents are copied +to the published site root. Use [`--assets`](../../../cli/flet-publish.md#--assets) to point to a different +folder. Assets are not packaged inside the `app.tar.gz`. + +## `flet build web` + +Uses [Flutter](https://flutter.dev/) and [Pyodide](https://pyodide.org/en/stable/index.html). +Dependencies are resolved and installed locally at build time (via `pip`), then bundled into the output archive. + +:::tip[Note] +Complementary and more general information is available [here](../../index.md). +::: + +### Testing the site + +[`flet serve`](../../../cli/flet-serve.md) serves the default +[output directory](../../index.md#output-directory) (`./build/web`): + +```bash +flet serve +``` + +## Configuration options + +These settings apply to `flet build web` and `flet publish`, unless noted. + +### Base URL + +Use a base URL when hosting your app in a subdirectory. Flet normalizes it to +`//` and uses `/` when unset. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--base-url`](../../../cli/flet-build.md#--base-url) +2. `[tool.flet.web].base_url` +3. `"/"` + +#### Example + + + +```bash +flet build web --base-url /myapp/ +``` + + +```toml +[tool.flet.web] +base_url = "/myapp/" +``` + + +### Route URL strategy + +Controls how routes are represented in the URL: + +- `path` - clean paths; requires SPA-capable hosting. +- `hash` - uses the URL hash; works on static hosts without SPA support. + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--route-url-strategy`](../../../cli/flet-build.md#--route-url-strategy) +2. `[tool.flet.web].route_url_strategy` +3. `"path"` + +#### Example + + + +```bash +flet build web --route-url-strategy hash +``` + + +```toml +[tool.flet.web] +route_url_strategy = "hash" +``` + + +### Web renderer + +Selects the Flutter web renderer: + +- `auto` (default) - let Flutter choose the best renderer +- `canvaskit` +- `skwasm` + +#### Resolution order + +Its value is determined in the following order of precedence: + +1. [`--web-renderer`](../../../cli/flet-build.md#--web-renderer) +2. `[tool.flet.web].renderer` +3. `"auto"` + +#### Example + + + +```bash +flet build web --web-renderer canvaskit +``` + + +```toml +[tool.flet.web] +renderer = "canvaskit" +``` + + +### CDN assets + +By default, Pyodide, CanvasKit, and fonts are loaded from CDNs to keep the output +small. Disable CDN loading for offline or air-gapped deployments. + +#### Resolution order + +CDN loading is disabled in the following order of precedence: + +1. [`--no-cdn`](../../../cli/flet-build.md#--no-cdn) +2. `[tool.flet.web].cdn = false` +3. default: CDN enabled + +#### Example + + + +```bash +flet build web --no-cdn +``` + + +```toml +[tool.flet.web] +cdn = false +``` + + +### PWA colors + +Configure PWA colors used in `manifest.json` and browser UI. + +#### Resolution order + +For each setting: + +1. [`--pwa-background-color`](../../../cli/flet-build.md#--pwa-background-color) / [`--pwa-theme-color`](../../../cli/flet-build.md#--pwa-theme-color) +2. `[tool.flet.web].pwa_background_color` / `[tool.flet.web].pwa_theme_color` +3. `#FFFFFF` / `#0175C2` + +#### Example + + + +```bash +flet build web --pwa-background-color "#000000" --pwa-theme-color "#FF0000" +``` + + +```toml +[tool.flet.web] +pwa_background_color = "#000000" +pwa_theme_color = "#FF0000" +``` + + +### WASM output + +By default, [`flet build web`](#flet-build-web) enables Flutter's WASM output. + +:::note[Note] +[`flet build web`](#flet-build-web) only. +::: + +#### Resolution order + +The WASM output is disabled in the following order of precedence: + +1. [`--no-wasm`](../../../cli/flet-build.md#--no-wasm) +2. `[tool.flet.web].wasm = false` +3. default: WASM enabled + +#### Example + + + +```bash +flet build web --no-wasm +``` + + +```toml +[tool.flet.web] +wasm = false +``` + + diff --git a/website/docs/publish/windows.md b/website/docs/publish/windows.md new file mode 100644 index 0000000000..57d021bf52 --- /dev/null +++ b/website/docs/publish/windows.md @@ -0,0 +1,47 @@ +--- +title: "Packaging app for Windows" +--- + +Instructions for packaging a Flet app into a Windows application. + +:::tip[Info] +This guide provides detailed Windows-specific information. +Complementary and more general information is available [here](index.md). +::: + +## Prerequisites + +### Visual Studio + +Visual Studio ([2022](https://learn.microsoft.com/en-us/visualstudio/install/install-visual-studio?view=vs-2022) +or [2026](https://learn.microsoft.com/en-us/visualstudio/install/install-visual-studio?view=visualstudio)) +is required with the **Desktop development with C++** workload installed. + +Follow this [guide](https://medium.com/@teamcode20233/a-guide-to-install-desktop-development-with-c-workload-542bb92cfe90) +for instructions on downloading and installing correct Visual Studio +components for Flutter desktop development. + +## `flet build windows` + +:::note[Note] +This command can be run on **Windows only**. +::: + +Builds a Windows application. + +## Troubleshooting + +### Developer mode + +If you get the below error: + +``` +Building with plugins requires symlink support. + +Please enable Developer Mode in your system settings. Run + start ms-settings:developers +to open settings. +``` + +Then, you need to enable Developer Mode as it indicates. +Follow this [guide](https://stackoverflow.com/a/70994092/1435891) on how to do that. diff --git a/website/docs/reference/binary-packages-android-ios.md b/website/docs/reference/binary-packages-android-ios.md new file mode 100644 index 0000000000..ea1df9c291 --- /dev/null +++ b/website/docs/reference/binary-packages-android-ios.md @@ -0,0 +1,31 @@ +--- +title: "Built-in binary Python packages for Android and iOS" +--- + +import PypiIndex from '@site/.crocodocs/pypi-index.mdx'; + +Binary Python packages (as opposed to "pure" Python packages written entirely in Python) +contain components written in C, Rust, or other languages that produce native code. +Common examples include `numpy`, `cryptography`, and `pydantic`. + +Flet provides an alternative package index, [pypi.flet.dev](https://pypi.flet.dev), +which hosts prebuilt Python binary wheels (`.whl` files used by `pip`) for iOS and Android platforms. + +:::danger[Work in progress] +New packages are created by adding a recipe to the +[Mobile Forge](https://github.com/flet-dev/mobile-forge) project. +Currently, we author these recipes for you; once the build process +is fully automated, you'll be able to submit a PR and test the +compiled package immediately. + +If a package is not available on [pypi.flet.dev](https://pypi.flet.dev), +you can request it in [Flet discussions - Packages](https://github.com/flet-dev/flet/discussions/categories/packages). +Please do not request "pure" Python packages. Check out this +[guide](https://flet.dev/blog/flet-packaging-update#pure-python-packages) +for more details on the difference between pure and binary packages. +::: + +Below is the list of packages hosted on [pypi.flet.dev](https://pypi.flet.dev) +and the specific wheel versions currently built and supported: + + diff --git a/website/docs/reference/environment-variables.md b/website/docs/reference/environment-variables.md new file mode 100644 index 0000000000..d85c18f22f --- /dev/null +++ b/website/docs/reference/environment-variables.md @@ -0,0 +1,196 @@ +--- +title: "Environment Variables" +--- + +:::tip[Setting boolean values] +To set a boolean `True`, use one of the following string values: `"true"`, `"1"` or `"yes"`. +Any other value will be interpreted as `False`. +::: + +### `FLET_APP_CONSOLE` + +The path to the application's console log file (`console.log`) in the temporary storage directory. + +Its value is set in production mode. + +### `FLET_APP_STORAGE_DATA` + +A directory for the storage of persistent application data that is preserved between app updates. +It is already pre-created and its location depends on the platform the app is running on. + +### `FLET_APP_STORAGE_TEMP` + +A directory for the storage of temporary application files, i.e. cache. +It is already pre-created and its location depends on the platform the app is running on. + +### `FLET_APP_USER_MODEL_ID` + +Windows [AppUserModelID](https://learn.microsoft.com/en-us/windows/win32/shell/appids) +used by the desktop client process for taskbar grouping and pinning. + +For apps packaged with [`flet pack`](../cli/flet-pack.md), this value is set automatically +so taskbar pins point to the packaged app executable instead of the cached Flet client executable. + +### `FLET_ASSETS_DIR` + +Absolute path to the app's assets directory. + +In production apps built with [`flet build`](../publish/index.md), this environment-variable points to the bundled assets absolute location at runtime. +Use it when your code needs a filesystem path to bundled files (for example, JSON configs, databases, or model files). + +For local runs, it may be unset depending on how the app is started, so use a fallback: + +```python +import os +from pathlib import Path +import flet as ft + +default_assets_dir = Path(__file__).parent / "assets" +assets_dir = Path(os.environ.get("FLET_ASSETS_DIR", str(default_assets_dir))).resolve() + +def main(page: ft.Page): + ... + +ft.run(main, assets_dir="assets") +``` + +For control properties like [`Image.src`](../controls/image.md#flet.Image.src), continue using paths relative +to the `ft.run(assets_dir=...)`, as described in the [assets cookbook](../cookbook/assets.md). + +### `FLET_ANDROID_SIGNING_KEY_ALIAS` + +Android signing key alias used by +[`flet build`](../publish/android.md#key-alias) for Android app signing. + +It is used only when a [keystore](../publish/android.md#key-store) is configured. + +### `FLET_ANDROID_SIGNING_KEY_PASSWORD` + +Android signing key password used by +[`flet build`](../publish/android.md#key-password) for Android app signing. + +If [`FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD`](#flet_android_signing_key_store_password) is set +but this variable is not, the keystore password is reused as the key password. + +### `FLET_ANDROID_SIGNING_KEY_STORE` + +Path to the Android upload keystore (`.jks`) used by [`flet build`](../publish/android.md#key-store) +for Android app signing. + +### `FLET_ANDROID_SIGNING_KEY_STORE_PASSWORD` + +Android signing keystore password used by +[`flet build`](../publish/android.md#key-store-password) for Android app signing. + +If [`FLET_ANDROID_SIGNING_KEY_PASSWORD`](#flet_android_signing_key_password) is set +but this variable is not, the key password is reused as the keystore password. + +### `FLET_CLI_NO_RICH_OUTPUT` + +Whether to disable rich output in the console. + +Defaults to `"false"`. + +### `FLET_PLATFORM` + +The platform on which the application is running. +Its value is one of the following: `"android"`, `"ios"`, `"linux"`, `"macos"`, `"windows"` or `"fuchsia"`. + +### `FLET_CLI_SKIP_FLUTTER_DOCTOR` + +Whether to skip running `flutter doctor` when a build fails. + +Defaults to `False`. + +### `FLET_HIDE_WINDOW_ON_START` + +Set to `true` to start app with the main window hidden. + +Defaults to `False`. + +### `FLET_FORCE_WEB_SERVER` + +Set to `true` to force running app as a web app. Automatically set on headless Linux hosts. + +### `FLET_OAUTH_CALLBACK_HANDLER_ENDPOINT` + +Custom path for OAuth handler. + +Defaults to `"/oauth_callback"`. + +### `FLET_OAUTH_STATE_TIMEOUT` + +Maximum allowed time (in seconds) to complete OAuth web flow. + +Defaults to `600`. + +### `FLET_MAX_UPLOAD_SIZE` + +Maximum allowed size (in bytes) of uploaded files. + +Default is unlimited. + +### `FLET_SECRET_KEY` + +A secret key to sign temporary upload URLs. + +### `FLET_SERVER_IP` + +IP address to listen web app on, e.g. `"127.0.0.1"`. + +Defaults to `0.0.0.0` - bound to all server IPs. + +### `FLET_SERVER_PORT` + +TCP port to run app on. + +`8000` if the program is running on a Linux server or [`FLET_FORCE_WEB_SERVER`](#flet_force_web_server) is set; otherwise +random port. + +### `FLET_SERVER_UDS_PATH` + +The Unix Domain Socket (UDS) path for the Flet server. It enables inter-process communication on Unix-based systems, with its value being a socket file path in the format `flet_.sock`. + +### `FLET_SESSION_TIMEOUT` + +Session lifetime in seconds. + +Defaults to `3600`. + +### `FLET_UPLOAD_DIR` + +Absolute path to app "upload" directory. + +### `FLET_UPLOAD_HANDLER_ENDPOINT` + +Custom path for upload handler. + +Defaults to `"/upload"`. + +### `FLET_WEB_APP_PATH` + +A URL path after domain name to host web app under, e.g. `"/apps/myapp"`. + +Defaults to `"/"` - host app in the root. + +### `FLET_WEB_NO_CDN` + +Set to `true` to avoid loading CanvasKit, Pyodide, and fonts from CDNs. + +### `FLET_WEBSOCKET_HANDLER_ENDPOINT` + +Custom path for WebSocket handler. + +Defaults to `"/ws"`. + +### `FLET_WEB_RENDERER` + +Web rendering mode: `"canvaskit"` (default), `"skwasm"` or `"auto"`. + +### `FLET_WEB_USE_COLOR_EMOJI` + +Set to `True`, `true` or `1` to load web font with colorful emojis. + +### `FLET_WEB_ROUTE_URL_STRATEGY` + +The URL strategy of the web application. Its value can be either `"path"` (default) or `"hash"`. diff --git a/website/docs/reference/index.md b/website/docs/reference/index.md new file mode 100644 index 0000000000..119c0a54df --- /dev/null +++ b/website/docs/reference/index.md @@ -0,0 +1,12 @@ +--- +title: "Overview" +--- + +# API Reference + +- [Controls](/docs/controls) - UI building blocks with properties, events, and usage examples. +- [Services](/docs/services) - Device and platform capabilities such as sensors, storage, and permissions. +- [CLI](../cli/index.md) - `flet` commands for creating, running, packaging, and debugging apps. +- [Types](../types/index.md) - Core types, enums, events, exceptions, and utilities shared across the SDK. +- [Built-in binary Python packages for Android and iOS](../reference/binary-packages-android-ios.md) - Prebuilt wheels available from `https://pypi.flet.dev` for mobile targets. +- [Environment Variables](../reference/environment-variables.md) - Runtime configuration toggles for apps and the CLI. diff --git a/website/docs/services/accelerometer.md b/website/docs/services/accelerometer.md new file mode 100644 index 0000000000..2579013f12 --- /dev/null +++ b/website/docs/services/accelerometer.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Accelerometer" +examples: "services/accelerometer" +title: "Accelerometer" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/audio/index.md b/website/docs/services/audio/index.md new file mode 100644 index 0000000000..df826d6e3f --- /dev/null +++ b/website/docs/services/audio/index.md @@ -0,0 +1,76 @@ +--- +class_name: "flet_audio.Audio" +examples: "extensions/audio" +title: "Audio" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Audio + +Allows playing audio in [Flet](https://flet.dev) apps. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +To use `Audio` control add `flet-audio` package to your project dependencies: + + + +```bash +uv add flet-audio +``` + + +```bash +pip install flet-audio # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +:::note[Linux requirements] +To play audio on Linux (or [WSL](https://docs.microsoft.com/en-us/windows/wsl/about)) you need to +install [`GStreamer`](https://github.com/GStreamer/gstreamer) library. + +To install the minimal set of GStreamer libs on Ubuntu/Debian, run: + +```bash +sudo apt install libgtk-3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev +``` + +To install the full set: + +```bash +sudo apt install \ + libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-bad1.0-dev \ + gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools \ + gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 \ + gstreamer1.0-qt5 gstreamer1.0-pulseaudio +``` + +If you receive `error while loading shared libraries: libgstapp-1.0.so.0`, +it means `GStreamer` is not installed in your WSL environment. +Install the full set of GStreamer libs, as shown above. + +See [this guide](https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=c) +for installing on other Linux distributions. +::: + +## Examples + +### Basic example + + + +## Description + + diff --git a/website/docs/services/audio/types/audiodurationchangeevent.md b/website/docs/services/audio/types/audiodurationchangeevent.md new file mode 100644 index 0000000000..1bc810c677 --- /dev/null +++ b/website/docs/services/audio/types/audiodurationchangeevent.md @@ -0,0 +1,7 @@ +--- +title: "AudioDurationChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audio/types/audiopositionchangeevent.md b/website/docs/services/audio/types/audiopositionchangeevent.md new file mode 100644 index 0000000000..244fecf2ea --- /dev/null +++ b/website/docs/services/audio/types/audiopositionchangeevent.md @@ -0,0 +1,7 @@ +--- +title: "AudioPositionChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audio/types/audiostate.md b/website/docs/services/audio/types/audiostate.md new file mode 100644 index 0000000000..0ff9055ef9 --- /dev/null +++ b/website/docs/services/audio/types/audiostate.md @@ -0,0 +1,7 @@ +--- +title: "AudioState" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audio/types/audiostatechangeevent.md b/website/docs/services/audio/types/audiostatechangeevent.md new file mode 100644 index 0000000000..dde07daf0a --- /dev/null +++ b/website/docs/services/audio/types/audiostatechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "AudioStateChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audio/types/releasemode.md b/website/docs/services/audio/types/releasemode.md new file mode 100644 index 0000000000..d01b77220d --- /dev/null +++ b/website/docs/services/audio/types/releasemode.md @@ -0,0 +1,7 @@ +--- +title: "ReleaseMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/index.md b/website/docs/services/audiorecorder/index.md new file mode 100644 index 0000000000..1426c9105e --- /dev/null +++ b/website/docs/services/audiorecorder/index.md @@ -0,0 +1,212 @@ +--- +class_name: "flet_audio_recorder.AudioRecorder" +examples: "extensions/audio_recorder" +title: "AudioRecorder" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Audio Recorder + +Allows recording audio in [Flet](https://flet.dev) apps. + +It is based on the [record](https://pub.dev/packages/record) Flutter package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +To use `AudioRecorder` service add `flet-audio-recorder` package to your project dependencies: + + + +```bash +uv add flet-audio-recorder +``` + + + +```bash +pip install flet-audio-recorder # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Requirements + +The below sections show the required configurations for each platform. + +### Android + +Configuration to be made to access the microphone: + +- [`android.permission.RECORD_AUDIO`](https://developer.android.com/reference/android/Manifest.permission#RECORD_AUDIO): Allows audio recording. +- [`android.permission.WRITE_EXTERNAL_STORAGE`](https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE) (optional): Allows saving your recordings in public folders. +- [`android.permission.MODIFY_AUDIO_SETTINGS`](https://developer.android.com/reference/android/Manifest.permission#MODIFY_AUDIO_SETTINGS) (optional): Allows using bluetooth telephony device like headset/earbuds. + + + +```bash +flet build apk \ + --android-permissions android.permission.RECORD_AUDIO=true \ + --android-permissions android.permission.WRITE_EXTERNAL_STORAGE=true \ + --android-permissions android.permission.MODIFY_AUDIO_SETTINGS=true +``` + + +```toml +[tool.flet.android.permission] +"android.permission.RECORD_AUDIO" = true +"android.permission.WRITE_EXTERNAL_STORAGE" = true +"android.permission.MODIFY_AUDIO_SETTINGS" = true +``` + + +See also: + +- [setting Android permissions](../../publish/android.md#permissions) +- [Audio formats sample rate hints](https://developer.android.com/guide/topics/media/media-formats#audio-formats) + +### iOS + +Configuration to be made to access the microphone: + +- [`NSMicrophoneUsageDescription`](https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSMicrophoneUsageDescription): Required for recording audio. + + + +```bash +flet build ipa \ + --info-plist NSMicrophoneUsageDescription="Some message to describe why you need this permission..." +``` + + +```toml +[tool.flet.ios.info] +NSMicrophoneUsageDescription = "Some message to describe why you need this permission..." +``` + + +See also: + +- [setting iOS permissions](../../publish/ios.md#permissions). + +### macOS + +Configuration to be made to access the microphone: + +- [`NSMicrophoneUsageDescription`](https://developer.apple.com/documentation/BundleResources/Information-Property-List/NSMicrophoneUsageDescription): Allows recording audio. +- [`com.apple.security.device.audio-input`](https://developer.apple.com/documentation/BundleResources/Entitlements/com.apple.security.device.audio-input): Allows recording audio using the built-in microphone and accessing audio input using Core Audio. + + + +```bash +flet build macos \ + --info-plist NSMicrophoneUsageDescription="Some message to describe why you need this permission..." \ + --macos-entitlements com.apple.security.device.audio-input=true +``` + + +```toml +[tool.flet.macos.info] +NSMicrophoneUsageDescription = "Some message to describe why you need this permission..." + +[tool.flet.macos.entitlement] +"com.apple.security.device.audio-input" = true +``` + + +See also: + +- [setting macOS permissions](../../publish/macos.md#permissions) +- [setting macOS entitlements](../../publish/macos.md#entitlements) + +### Linux + +The following dependencies are required (and widely available on your system): + +- `parecord`: Used for audio input. +- `pactl`: Used for utility methods like getting available devices. +- [`ffmpeg`](https://ffmpeg.org): Used for encoding and output. + +On Ubuntu 24.04.3 LTS, you can install them using: +```bash +sudo apt install pulseaudio-utils ffmpeg +``` + +### Cross-platform + +Additionally/alternatively, you can make use of our predefined cross-platform `microphone` +[permission bundle](../../publish/index.md#predefined-cross-platform-permission-bundles): + + + +```bash +flet build --permissions microphone +``` + + +```toml +[tool.flet] +permissions = ["microphone"] +``` + + + +## Examples + +### Basic recording + + + +### Stream chunks and save/download \{#stream-chunks-and-save-download} + +On web, [`AudioRecorder.stop_recording()`][flet_audio_recorder.AudioRecorder.stop_recording] +returns a browser-local Blob URL. Use streaming when your app needs access to the recorded bytes. + +Set [`AudioRecorderConfiguration.encoder`][flet_audio_recorder.AudioRecorderConfiguration.encoder] +to [`AudioEncoder.PCM16BITS`][flet_audio_recorder.AudioEncoder.PCM16BITS] +and handle [`AudioRecorder.on_stream`][flet_audio_recorder.AudioRecorder.on_stream] +to receive [`AudioRecorderStreamEvent.chunk`][flet_audio_recorder.AudioRecorderStreamEvent.chunk] +bytes in Python. + +[`AudioEncoder.PCM16BITS`][flet_audio_recorder.AudioEncoder.PCM16BITS] +encoded streams are supported on all platforms. Stream chunks are raw PCM16 bytes and are not directly +playable as an audio file. Wrap the bytes in a container such as WAV in Python when +the destination needs a directly playable recording. + +The example below collects the streamed chunks, wraps the PCM16 bytes in a WAV container, +and passes the resulting bytes to [`FilePicker.save_file()`][flet.FilePicker.save_file] +so users can save or download the recording. + + + +### Streaming upload + +Pass [`AudioRecorderUploadSettings`][flet_audio_recorder.AudioRecorderUploadSettings] to +[`AudioRecorder.start_recording()`][flet_audio_recorder.AudioRecorder.start_recording] +to upload [`AudioEncoder.PCM16BITS`][flet_audio_recorder.AudioEncoder.PCM16BITS] +recording bytes directly while recording. + +The uploaded file contains raw PCM16 bytes, so a `.pcm` extension is intentional. +See the [stream chunks and save/download example](#stream-chunks-and-save-download) +for inspiration, if you need to create a playable WAV file. + +:::note +Built-in upload URLs from [`Page.get_upload_url()`][flet.Page.get_upload_url] +require upload storage and a signing key. Run with `upload_dir` and set +[`FLET_SECRET_KEY`](../../reference/environment-variables.md#flet_secret_key). +::: + + + +## Description + + diff --git a/website/docs/services/audiorecorder/types/androidaudiosource.md b/website/docs/services/audiorecorder/types/androidaudiosource.md new file mode 100644 index 0000000000..cc6b0a674c --- /dev/null +++ b/website/docs/services/audiorecorder/types/androidaudiosource.md @@ -0,0 +1,7 @@ +--- +title: "AndroidAudioSource" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/androidrecorderconfiguration.md b/website/docs/services/audiorecorder/types/androidrecorderconfiguration.md new file mode 100644 index 0000000000..8bef9e922d --- /dev/null +++ b/website/docs/services/audiorecorder/types/androidrecorderconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "AndroidRecorderConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audioencoder.md b/website/docs/services/audiorecorder/types/audioencoder.md new file mode 100644 index 0000000000..3030568d11 --- /dev/null +++ b/website/docs/services/audiorecorder/types/audioencoder.md @@ -0,0 +1,7 @@ +--- +title: "AudioEncoder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audiorecorderconfiguration.md b/website/docs/services/audiorecorder/types/audiorecorderconfiguration.md new file mode 100644 index 0000000000..d887863762 --- /dev/null +++ b/website/docs/services/audiorecorder/types/audiorecorderconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "AudioRecorderConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audiorecorderstate.md b/website/docs/services/audiorecorder/types/audiorecorderstate.md new file mode 100644 index 0000000000..0b37c269d8 --- /dev/null +++ b/website/docs/services/audiorecorder/types/audiorecorderstate.md @@ -0,0 +1,7 @@ +--- +title: "AudioRecorderState" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audiorecorderstatechangeevent.md b/website/docs/services/audiorecorder/types/audiorecorderstatechangeevent.md new file mode 100644 index 0000000000..f87bfe4636 --- /dev/null +++ b/website/docs/services/audiorecorder/types/audiorecorderstatechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "AudioRecorderStateChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audiorecorderstreamevent.md b/website/docs/services/audiorecorder/types/audiorecorderstreamevent.md new file mode 100644 index 0000000000..ad7f79d645 --- /dev/null +++ b/website/docs/services/audiorecorder/types/audiorecorderstreamevent.md @@ -0,0 +1,7 @@ +--- +title: "AudioRecorderStreamEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audiorecorderuploadevent.md b/website/docs/services/audiorecorder/types/audiorecorderuploadevent.md new file mode 100644 index 0000000000..4889fad12d --- /dev/null +++ b/website/docs/services/audiorecorder/types/audiorecorderuploadevent.md @@ -0,0 +1,7 @@ +--- +title: "AudioRecorderUploadEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/audiorecorderuploadsettings.md b/website/docs/services/audiorecorder/types/audiorecorderuploadsettings.md new file mode 100644 index 0000000000..49f4cddf64 --- /dev/null +++ b/website/docs/services/audiorecorder/types/audiorecorderuploadsettings.md @@ -0,0 +1,7 @@ +--- +title: "AudioRecorderUploadSettings" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/inputdevice.md b/website/docs/services/audiorecorder/types/inputdevice.md new file mode 100644 index 0000000000..8323f830c5 --- /dev/null +++ b/website/docs/services/audiorecorder/types/inputdevice.md @@ -0,0 +1,7 @@ +--- +title: "InputDevice" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/iosaudiocategoryoption.md b/website/docs/services/audiorecorder/types/iosaudiocategoryoption.md new file mode 100644 index 0000000000..5eec938e20 --- /dev/null +++ b/website/docs/services/audiorecorder/types/iosaudiocategoryoption.md @@ -0,0 +1,7 @@ +--- +title: "IosAudioCategoryOption" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/audiorecorder/types/iosrecorderconfiguration.md b/website/docs/services/audiorecorder/types/iosrecorderconfiguration.md new file mode 100644 index 0000000000..3c41f08298 --- /dev/null +++ b/website/docs/services/audiorecorder/types/iosrecorderconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "IosRecorderConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/barometer.md b/website/docs/services/barometer.md new file mode 100644 index 0000000000..6744dafe80 --- /dev/null +++ b/website/docs/services/barometer.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Barometer" +examples: "services/barometer" +title: "Barometer" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/battery.md b/website/docs/services/battery.md new file mode 100644 index 0000000000..5985c2d630 --- /dev/null +++ b/website/docs/services/battery.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Battery" +examples: "services/battery" +title: "Battery" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/browsercontextmenu.md b/website/docs/services/browsercontextmenu.md new file mode 100644 index 0000000000..3eb4d39b4a --- /dev/null +++ b/website/docs/services/browsercontextmenu.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.BrowserContextMenu" +examples: "services/browsercontextmenu" +title: "BrowserContextMenu" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/clipboard.md b/website/docs/services/clipboard.md new file mode 100644 index 0000000000..0cb0cd244c --- /dev/null +++ b/website/docs/services/clipboard.md @@ -0,0 +1,25 @@ +--- +class_name: "flet.Clipboard" +examples: "services/clipboard" +title: "Clipboard" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Text + + + +### Images + + + +### Files + + + + diff --git a/website/docs/services/connectivity.md b/website/docs/services/connectivity.md new file mode 100644 index 0000000000..f88b55129c --- /dev/null +++ b/website/docs/services/connectivity.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Connectivity" +examples: "services/connectivity" +title: "Connectivity" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/filepicker.md b/website/docs/services/filepicker.md new file mode 100644 index 0000000000..539399dcc3 --- /dev/null +++ b/website/docs/services/filepicker.md @@ -0,0 +1,114 @@ +--- +class_name: "flet.FilePicker" +examples: "services/file_picker" +example_images: "examples/services/file_picker/media" +title: "FilePicker" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Usage + +Create an instance of `FilePicker`: + +```python +import flet as ft + +file_picker = ft.FilePicker() +``` + +To open the file picker dialog call one of these three methods: +[`pick_files()`](filepicker.md#flet.FilePicker.pick_files), [`save_file()`](filepicker.md#flet.FilePicker.save_file) +or [`get_directory_path()`](filepicker.md#flet.FilePicker.get_directory_path), depending on the use case. + +In most cases you can use a lambda function for that: + +```python +ft.Button( + content="Pick files, + on_click=lambda _: file_picker.pick_files(allow_multiple=True) +) +``` + +### Uploading files + +To upload one or more files, call [`FilePicker.pick_files()`](filepicker.md#flet.FilePicker.pick_files) +to let the user select files, then pass the returned list to +[`FilePicker.upload()`](filepicker.md#flet.FilePicker.upload) to perform the upload. + +:::note[Separate uploads per user] +If you need to separate uploads for each user you can specify a filename +prepended with any number of directories in +[`page.get_upload_url()`](../controls/page.md#flet.Page.get_upload_url) call, for example: + +```python +upload_url = page.get_upload_url(f"/{username}/pictures/{f.name}", 600) +``` + +`/{username}/pictures` directories will be automatically created inside `upload_dir` if non-existent. +::: + +### Upload storage + +Notice the usage of [`page.get_upload_url()`](../controls/page.md#flet.Page.get_upload_url) method – +it generates a presigned upload URL for Flet's internal upload storage. + +:::note[Use any storage for file uploads] +You can [generate presigned upload URL](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html#generating-a-presigned-url-to-upload-a-file) +for AWS S3 storage using boto3 library. + +The same technique should work for [Wasabi](https://wasabi.com/), [Backblaze](https://www.backblaze.com/), +[MinIO](https://min.io/) and any other storage providers with S3-compatible API. +::: + +To enable Flet saving uploaded files to a directory provide a full or +relative path to that directory in `flet.run()` call: + +```python +ft.run(main, upload_dir="uploads") +``` + +You can even put uploads inside [assets](../cookbook/assets.md) directory, +so uploaded files, e.g. pictures, docs, or other media, +can be accessed from a Flet client right away: + +```python +ft.run(main, assets_dir="assets", upload_dir="assets/uploads") +``` + +and in your app you can display the uploaded picture with: + +```python +ft.Image(src="/uploads/") +``` + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/utility/filepicker) + +### Pick, save, and get directory paths + + + + + +### Pick and upload files + +The following example demonstrates multi-file [pick](filepicker.md#flet.FilePicker.pick_files) +and [upload](filepicker.md#flet.FilePicker.upload) app. + + + + + +### Pick text content and save/download it + +Use [`pick_files()`](filepicker.md#flet.FilePicker.pick_files) with `with_data=True` when +you need file contents directly, such as in web apps where +[`FilePickerFile.path`](../types/filepickerfile.md#flet.FilePickerFile.path) is not available. + + + + diff --git a/website/docs/services/flashlight/index.md b/website/docs/services/flashlight/index.md new file mode 100644 index 0000000000..b391fec29f --- /dev/null +++ b/website/docs/services/flashlight/index.md @@ -0,0 +1,46 @@ +--- +class_name: "flet_flashlight.Flashlight" +examples: "extensions/flashlight" +title: "Flashlight" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Flashlight + +Control the device torch/flashlight in your [Flet](https://flet.dev) app via the `flet-flashlight` extension, built on top of Flutter's [`flashlight`](https://pub.dev/packages/flashlight) package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | + +## Usage + +Add `flet-flashlight` to your project dependencies: + + + +```bash +uv add flet-flashlight +``` + + + +```bash +pip install flet-flashlight # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Example + + + +## Description + + diff --git a/website/docs/services/geolocator/index.md b/website/docs/services/geolocator/index.md new file mode 100644 index 0000000000..517c9e4aca --- /dev/null +++ b/website/docs/services/geolocator/index.md @@ -0,0 +1,209 @@ +--- +class_name: "flet_geolocator.Geolocator" +examples: "extensions/geolocator" +title: "Geolocator" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Geolocator + +Access device location services in your [Flet](https://flet.dev) app using the `flet-geolocator` extension. +The control wraps Flutter's [`geolocator`](https://pub.dev/packages/geolocator) package and exposes async helpers for permission checks and position streams. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-geolocator` to your project dependencies: + + + +```bash +uv add flet-geolocator +``` + + + +```bash +pip install flet-geolocator # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Requirements + +The below sections show the required configurations for each platform. + +### Android + +Configuration to be made to access the device's location: + +- [`ACCESS_FINE_LOCATION`](https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION): Allows access precise location. Will be preferred over `ACCESS_COARSE_LOCATION`, if both are set. +- [`ACCESS_COARSE_LOCATION`](https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION): Allows access approximate location. +- [`ACCESS_BACKGROUND_LOCATION`](https://developer.android.com/reference/android/Manifest.permission#ACCESS_BACKGROUND_LOCATION) (optional): Allows access to location even when the app is in the background. Effective as from Android 10 (API level 29). +- [`FOREGROUND_SERVICE_LOCATION`](https://developer.android.com/reference/android/Manifest.permission#FOREGROUND_SERVICE_LOCATION) (optional): Allows access to location even when the app is in the foreground. Effective as from Android 14 (API level 34). + +:::note[Note] +- At least one of `ACCESS_FINE_LOCATION` or `ACCESS_COARSE_LOCATION` permission is **required** to get location updates, with the former being preferred if both are set. +- Specifying the `ACCESS_COARSE_LOCATION` permission results in location updates with + accuracy approximately equivalent to a city block. It might take a long time (minutes) + before you will get your first locations fix as `ACCESS_COARSE_LOCATION` will only use + the network services to calculate the position of the device. More information + [here](https://developer.android.com/training/location/retrieve-current#permissions). +::: + + + +```bash +flet build apk \ + --android-permissions android.permission.ACCESS_FINE_LOCATION=true \ + --android-permissions android.permission.ACCESS_COARSE_LOCATION=true \ + --android-permissions android.permission.ACCESS_BACKGROUND_LOCATION=true \ + --android-permissions android.permission.FOREGROUND_SERVICE_LOCATION=true +``` + + +```toml +[tool.flet.android.permission] +"android.permission.ACCESS_FINE_LOCATION" = true +"android.permission.ACCESS_COARSE_LOCATION" = true +"android.permission.ACCESS_BACKGROUND_LOCATION" = true +"android.permission.FOREGROUND_SERVICE_LOCATION" = true +``` + + +See also: + +- [setting Android permissions](../../publish/android.md#permissions) + +### iOS + +Configuration to be made to access the device's location: + + + +```bash +flet build ipa \ + --info-plist NSLocationWhenInUseUsageDescription="Some message to describe why you need this permission..." +``` + + +```toml +[tool.flet.ios.info] +NSLocationWhenInUseUsageDescription = "Some message to describe why you need this permission..." +``` + + +See also: + +- [setting iOS Info.plist entries](../../publish/ios.md#infoplist) + +### macOS + +Configuration to be made to access the device's location: + + + +```bash +flet build macos \ + --info-plist NSLocationUsageDescription="Some message to describe why you need this permission..." \ + --macos-entitlements com.apple.security.personal-information.location=true +``` + + +```toml +[tool.flet.macos.info] +NSLocationUsageDescription = "Some message to describe why you need this permission..." + +[tool.flet.macos.entitlement] +"com.apple.security.personal-information.location" = true +``` + + +See also: + +- [macOS permissions](../../publish/macos.md#permissions) +- [macOS entitlements](../../publish/macos.md#entitlements) + +### Cross-platform + +Additionally/alternatively, you can make use of our predefined cross-platform `location` +[permission bundle](../../publish/index.md#predefined-cross-platform-permission-bundles): + + + +```bash +flet build --permissions location +``` + + +```toml +[tool.flet] +permissions = ["location"] +``` + + +## Web: cached vs. fresh positions + +On the web, `Geolocator.get_current_position` accepts a position from the +browser's cache up to **5 minutes old by default**, otherwise it asks the +browser for a fresh fix and times out after 30 seconds if none arrives. This +default exists because desktop browsers' on-demand location pipeline is slow +and frequently fails on stationary devices. + +If you need stricter freshness (or a longer cache window), pass a +[`GeolocatorWebConfiguration`](./types/geolocatorwebconfiguration.md) with an +explicit `maximum_age` and/or `time_limit`: + +```python +geo = ftg.Geolocator( + configuration=ftg.GeolocatorWebConfiguration( + accuracy=ftg.GeolocatorPositionAccuracy.HIGH, + maximum_age=ft.Duration(seconds=10), + time_limit=ft.Duration(seconds=15), + ), +) +``` + +## Troubleshooting + +### macOS: web browser returns `POSITION_UNAVAILABLE` or never resolves + +When running a Flet app in `--web` mode on macOS, the browser may fail to obtain +a position even though Location Services is on and the browser is allowed in +*System Settings → Privacy & Security → Location Services*. Symptoms include: + +- `getCurrentPosition` hanging or returning a `Location request timed out.` error. +- The position stream emitting `Failed to obtain position: Position update is unavailable` + (this is the W3C `POSITION_UNAVAILABLE` / error code 2 from the browser). + +This is a known issue with macOS' `locationd` daemon getting into a stuck state +where it reports the browser as authorized but never delivers a fix. Restart it: + +```bash +sudo killall locationd +``` + +The daemon respawns automatically. You can verify the browser side independently +by visiting [browserleaks.com/geo](https://browserleaks.com/geo) — if that page +also fails to obtain a position, the problem is with the OS, not your Flet app. + +The native (non-web) macOS Flet app is unaffected because it uses CoreLocation +directly through the platform plugin rather than going through the browser's +Geolocation API. + +## Example + + + +## Description + + diff --git a/website/docs/services/geolocator/types/foregroundnotificationconfiguration.md b/website/docs/services/geolocator/types/foregroundnotificationconfiguration.md new file mode 100644 index 0000000000..d9907fa57c --- /dev/null +++ b/website/docs/services/geolocator/types/foregroundnotificationconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "ForegroundNotificationConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorandroidconfiguration.md b/website/docs/services/geolocator/types/geolocatorandroidconfiguration.md new file mode 100644 index 0000000000..77769f61f7 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorandroidconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorAndroidConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorconfiguration.md b/website/docs/services/geolocator/types/geolocatorconfiguration.md new file mode 100644 index 0000000000..18e83b6401 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatoriosactivitytype.md b/website/docs/services/geolocator/types/geolocatoriosactivitytype.md new file mode 100644 index 0000000000..d23cb6184e --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatoriosactivitytype.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorIosActivityType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatoriosconfiguration.md b/website/docs/services/geolocator/types/geolocatoriosconfiguration.md new file mode 100644 index 0000000000..0c90a67f55 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatoriosconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorIosConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorpermissionstatus.md b/website/docs/services/geolocator/types/geolocatorpermissionstatus.md new file mode 100644 index 0000000000..96ce19cce9 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorpermissionstatus.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorPermissionStatus" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorposition.md b/website/docs/services/geolocator/types/geolocatorposition.md new file mode 100644 index 0000000000..df7de67670 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorposition.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorPosition" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorpositionaccuracy.md b/website/docs/services/geolocator/types/geolocatorpositionaccuracy.md new file mode 100644 index 0000000000..2574f7a3af --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorpositionaccuracy.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorPositionAccuracy" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorpositionchangeevent.md b/website/docs/services/geolocator/types/geolocatorpositionchangeevent.md new file mode 100644 index 0000000000..9a85ba26e8 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorpositionchangeevent.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorPositionChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/geolocator/types/geolocatorwebconfiguration.md b/website/docs/services/geolocator/types/geolocatorwebconfiguration.md new file mode 100644 index 0000000000..60f2173249 --- /dev/null +++ b/website/docs/services/geolocator/types/geolocatorwebconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "GeolocatorWebConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/gyroscope.md b/website/docs/services/gyroscope.md new file mode 100644 index 0000000000..27d24904ea --- /dev/null +++ b/website/docs/services/gyroscope.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Gyroscope" +examples: "services/gyroscope" +title: "Gyroscope" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/hapticfeedback.md b/website/docs/services/hapticfeedback.md new file mode 100644 index 0000000000..56ea20572e --- /dev/null +++ b/website/docs/services/hapticfeedback.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.HapticFeedback" +examples: "services/haptic_feedback" +title: "HapticFeedback" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + diff --git a/website/docs/services/magnetometer.md b/website/docs/services/magnetometer.md new file mode 100644 index 0000000000..dacbbebef3 --- /dev/null +++ b/website/docs/services/magnetometer.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Magnetometer" +examples: "services/magnetometer" +title: "Magnetometer" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/permissionhandler/index.md b/website/docs/services/permissionhandler/index.md new file mode 100644 index 0000000000..dad9f8104f --- /dev/null +++ b/website/docs/services/permissionhandler/index.md @@ -0,0 +1,72 @@ +--- +class_name: "flet_permission_handler.PermissionHandler" +examples: "extensions/permission_handler" +title: "PermissionHandler" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Permission Handler + +Helps manage runtime permissions in your [Flet](https://flet.dev) apps. + +It is powered by the Flutter [`permission_handler`](https://pub.dev/packages/permission_handler) package. + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|-----------|---------|-------|-------|-----|---------|-----| +| Supported | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-permission-handler` to your project dependencies: + + + +```bash +uv add flet-permission-handler +``` + + + +```bash +pip install flet-permission-handler # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +:::note[Note] +On mobile platforms you must also declare permissions in the native project files. See [Flet publish docs](../../publish/index.md#permissions). +::: + +## Requirements + +While the permissions are being requested during runtime, +you'll still need to tell the OS which permissions your app might potentially use. + +### Android + +See: + +- [full list of Android permissions](https://developer.android.com/reference/android/Manifest.permission) +- [`Permission`](types/permission.md) enum, which lists all the supported permissions +- [setting Android permissions](../../publish/android.md#permissions) + +### iOS + +See: + +- [`Permission`](types/permission.md) enum, which lists all the supported permissions and their `Info.plist` keys +- [setting iOS permissions](../../publish/ios.md#permissions) + +## Example + + + +## Description + + diff --git a/website/docs/services/permissionhandler/types/permission.md b/website/docs/services/permissionhandler/types/permission.md new file mode 100644 index 0000000000..0cfa1a011c --- /dev/null +++ b/website/docs/services/permissionhandler/types/permission.md @@ -0,0 +1,7 @@ +--- +title: "Permission" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/permissionhandler/types/permissionstatus.md b/website/docs/services/permissionhandler/types/permissionstatus.md new file mode 100644 index 0000000000..9418e4236b --- /dev/null +++ b/website/docs/services/permissionhandler/types/permissionstatus.md @@ -0,0 +1,7 @@ +--- +title: "PermissionStatus" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/screenbrightness.md b/website/docs/services/screenbrightness.md new file mode 100644 index 0000000000..57aaaa84bd --- /dev/null +++ b/website/docs/services/screenbrightness.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.ScreenBrightness" +examples: "services/screen_brightness" +title: "ScreenBrightness" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/securestorage/index.md b/website/docs/services/securestorage/index.md new file mode 100644 index 0000000000..de802d2c29 --- /dev/null +++ b/website/docs/services/securestorage/index.md @@ -0,0 +1,58 @@ +--- +class_name: "flet_secure_storage.SecureStorage" +examples: "extensions/secure_storage" +title: "SecureStorage" +--- + +import TabItem from '@theme/TabItem'; +import Tabs from '@theme/Tabs'; +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + +# Secure Storage + +A service for safely storing sensitive key–value data using the platform’s native secure storage mechanisms—Keychain on iOS/macOS, Windows Credential Manager, libsecret on Linux, and Keystore on Android. + +Powered by Flutter's [`flutter_secure_storage`](https://pub.dev/packages/flutter_secure_storage) package. + +:::note +You need `libsecret-1-dev` on your machine to build the project, and `libsecret-1-0` to run the application (add it as a dependency after packaging your app). If you using snapcraft to build the project use the following. + +Apart from `libsecret` you also need a keyring service, for that you need either [`gnome-keyring`](https://wiki.gnome.org/Projects/GnomeKeyring) (for Gnome users) or [`kwalletmanager`](https://wiki.archlinux.org/title/KDE_Wallet) (for KDE users) or other light provider like [`secret-service`](https://github.com/yousefvand/secret-service). + +```bash +sudo apt-get install libsecret-1-dev libsecret-1-0 +``` +::: + +## Platform Support + +| Platform | Windows | macOS | Linux | iOS | Android | Web | +|----------|---------|-------|-------|-----|---------|-----| +| Supported| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | + +## Usage + +Add `flet-secure-storage` to your project dependencies: + + + +```bash +uv add flet-secure-storage +``` + + + +```bash +pip install flet-secure-storage # (1)! +``` + +1. After this, you will have to manually add this package to your `requirements.txt` or `pyproject.toml`. + + +## Example + + + +## Description + + diff --git a/website/docs/services/securestorage/types/accesscontrolflag.md b/website/docs/services/securestorage/types/accesscontrolflag.md new file mode 100644 index 0000000000..2caf66f8a1 --- /dev/null +++ b/website/docs/services/securestorage/types/accesscontrolflag.md @@ -0,0 +1,20 @@ +--- +title: "AccessControlFlag" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage example +Require biometrics OR device passcode: + +```python +options = IOSOptions( + access_control_flags=[ + AccessControlFlag.BIOMETRY_ANY, + AccessControlFlag.OR, + AccessControlFlag.DEVICE_PASSCODE + ] +) +``` diff --git a/website/docs/services/securestorage/types/androidoptions.md b/website/docs/services/securestorage/types/androidoptions.md new file mode 100644 index 0000000000..3d54d6b4a9 --- /dev/null +++ b/website/docs/services/securestorage/types/androidoptions.md @@ -0,0 +1,134 @@ +--- +title: "AndroidOptions" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Disabling Auto Backup + +By default Android backups data on Google Drive. It can cause exception `java.security.InvalidKeyException: Failed to unwrap key`. +You need to: + +- [Disable autobackup](https://developer.android.com/guide/topics/data/autobackup#EnablingAutoBackup), [details](https://github.com/juliansteenbakker/flutter_secure_storage/issues/13#issuecomment-421083742) +- [Exclude sharedprefs](https://developer.android.com/guide/topics/data/autobackup#IncludingFiles) used by `SecureStorage` + +Add the following to your `pyproject.toml`: + +```toml +[tool.flet.android.manifest_application] +"allowBackup" = "false" +"fullBackupContent" = "false" +``` + +## Encryption Options + +### Default +```python +AndroidOptions() +``` + +- **Key Cipher:** RSA/ECB/OAEPWithSHA-256AndMGF1Padding +- **Storage Cipher:** AES/GCM/NoPadding +- **Biometric Support:** No +- **Description:** Standard secure storage with RSA OAEP key wrapping. Strong authenticated encryption without biometrics. Recommended for most use cases. + +### Optional Biometrics +```python +AndroidOptions( + enforce_biometrics=False, + key_cipher_algorithm=KeyCipherAlgorithm.AES_GCM_NO_PADDING, +) +``` + +- **Key Cipher:** AES/GCM/NoPadding +- **Storage Cipher:** AES/GCM/NoPadding +- **Biometric Support:** Optional +- **Description:** KeyStore-based with optional biometric authentication. Gracefully degrades if biometrics unavailable. + +### Required Biometrics +```python +AndroidOptions( + enforce_biometrics=True, + key_cipher_algorithm=KeyCipherAlgorithm.AES_GCM_NO_PADDING, +) +``` + +- **Key Cipher:** AES/GCM/NoPadding +- **Storage Cipher:** AES/GCM/NoPadding +- **Biometric Support:** Required (API 28+) +- **Description:** KeyStore-based requiring biometric/PIN authentication. Throws error if device security not available. + +## Custom Cipher Combinations + +For advanced users, all combinations below are supported using the `AndroidOptions()` constructor with custom parameters: + +| Key Cipher Algorithm | Storage Cipher Algorithm | Implementation | Biometric Support | +|---------------------------------------------|--------------------------|-----------------|-------------------------------------| +| `RSA_ECB_PKCS1_PADDING` | `AES_CBC_PKCS7_PADDING` | RSA-wrapped AES | No | +| `RSA_ECB_PKCS1_PADDING` | `AES_GCM_NO_PADDING` | RSA-wrapped AES | No | +| `RSA_ECB_OAEP_WITH_SHA256_AND_MGF1_PADDING` | `AES_CBC_PKCS7_PADDING` | RSA-wrapped AES | No | +| `RSA_ECB_OAEP_WITH_SHA256_AND_MGF1_PADDING` | `AES_GCM_NO_PADDING` | RSA-wrapped AES | No | +| `AES_GCM_NO_PADDING` | `AES_CBC_PKCS7_PADDING` | KeyStore AES | Optional (via `enforce_biometrics`) | +| `AES_GCM_NO_PADDING` | `AES_GCM_NO_PADDING` | KeyStore AES | Optional (via `enforce_biometrics`) | + +## Biometric Authentication + +Secure Storage supports biometric authentication (fingerprint, face recognition, etc.) on Android API 23+. + +### Required Permissions + +To use biometric authentication on Android, you need to grant the necessary permissions (`USE_BIOMETRIC` and optionally `USE_FINGERPRINT`) in your project. + +For configure permissions in your `pyproject.toml` or when building the app using `flet build`. + +See the official Flet documentation for details: [Android Permissions in Flet](https://flet.dev/docs/publish/android/#permissions) + +Example configuration in `pyproject.toml`: + +```toml +[tool.flet.android.permission] +"android.permission.USE_BIOMETRIC" = true +"android.permission.USE_FINGERPRINT" = true +``` + +You can also pass permissions when building your Android app: + +```bash +flet build \ + --android-permissions android.permission.USE_BIOMETRIC=True \ + android.permission.USE_FINGERPRINT=True +``` + +This ensures that biometric authentication works correctly on all supported Android devices. + +### Using Biometric Authentication + +You can enable biometric authentication: + +```python +# Optional biometric authentication (graceful degradation) +storage = SecureStorage( + android_options=AndroidOptions( + enforce_biometrics=False, # Default - works without biometrics + biometric_prompt_title='Unlock to access your data', + biometric_prompt_subtitle='Use fingerprint or face unlock', + ), +) + +# Strict biometric enforcement (requires device security) +storage = SecureStorage( + android_options=AndroidOptions( + enforce_biometrics=True, # Requires biometric/PIN/pattern + biometric_prompt_title: 'Biometric authentication required', + ), +) +``` + +### Requirements + +- **API Level**: Android 6.0 (API 23) minimum for basic encryption +- **API Level**: Android 9.0 (API 28) minimum for enforced biometric authentication +- **Device Security**: Device must have a PIN, pattern, password, or biometric enrolled (when using `enforce_biometrics = True`) +- **Permissions**: `USE_BIOMETRIC` permission in [pyproject.toml](#required-permissions) diff --git a/website/docs/services/securestorage/types/appleoptions.md b/website/docs/services/securestorage/types/appleoptions.md new file mode 100644 index 0000000000..a802ca2017 --- /dev/null +++ b/website/docs/services/securestorage/types/appleoptions.md @@ -0,0 +1,7 @@ +--- +title: "AppleOptions" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/securestorage/types/iosoptions.md b/website/docs/services/securestorage/types/iosoptions.md new file mode 100644 index 0000000000..849f1aaf42 --- /dev/null +++ b/website/docs/services/securestorage/types/iosoptions.md @@ -0,0 +1,38 @@ +--- +title: "IOSOptions" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage Example + +### Usage with accessibility control +```python +from flet_secure_storage import SecureStorage +from flet_secure_storage.types import IOSOptions, KeychainAccessibility + +storage = SecureStorage( + ios_options=IOSOptions( + accessibility=KeychainAccessibility.FIRST_UNLOCK + ) +) + +await storage.set(key="token", value="secret_value") +``` + +### Biometric authentication: +```python +from flet_secure_storage.types import IOSOptions, AccessControlFlag + +options = IOSOptions( + access_control_flags=[ + AccessControlFlag.BIOMETRY_ANY, + AccessControlFlag.OR, + AccessControlFlag.DEVICE_PASSCODE + ] +) + +await storage.set(key="secure_key", value="secure_value", ios=options) +``` diff --git a/website/docs/services/securestorage/types/keychainaccessibility.md b/website/docs/services/securestorage/types/keychainaccessibility.md new file mode 100644 index 0000000000..e30da87a24 --- /dev/null +++ b/website/docs/services/securestorage/types/keychainaccessibility.md @@ -0,0 +1,7 @@ +--- +title: "KeychainAccessibility" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/securestorage/types/keycipheralgorithm.md b/website/docs/services/securestorage/types/keycipheralgorithm.md new file mode 100644 index 0000000000..bafebc18a4 --- /dev/null +++ b/website/docs/services/securestorage/types/keycipheralgorithm.md @@ -0,0 +1,7 @@ +--- +title: "KeyCipherAlgorithm" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/securestorage/types/macosoptions.md b/website/docs/services/securestorage/types/macosoptions.md new file mode 100644 index 0000000000..c91adb737c --- /dev/null +++ b/website/docs/services/securestorage/types/macosoptions.md @@ -0,0 +1,7 @@ +--- +title: "MacOsOptions" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/securestorage/types/securestorageevent.md b/website/docs/services/securestorage/types/securestorageevent.md new file mode 100644 index 0000000000..0365862792 --- /dev/null +++ b/website/docs/services/securestorage/types/securestorageevent.md @@ -0,0 +1,7 @@ +--- +title: "SecureStorageEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/securestorage/types/storagecipheralgorithm.md b/website/docs/services/securestorage/types/storagecipheralgorithm.md new file mode 100644 index 0000000000..d21e1e5291 --- /dev/null +++ b/website/docs/services/securestorage/types/storagecipheralgorithm.md @@ -0,0 +1,7 @@ +--- +title: "StorageCipherAlgorithm" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/securestorage/types/weboptions.md b/website/docs/services/securestorage/types/weboptions.md new file mode 100644 index 0000000000..fbb7a2ff76 --- /dev/null +++ b/website/docs/services/securestorage/types/weboptions.md @@ -0,0 +1,41 @@ +--- +title: "WebOptions" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Important Security Considerations + +SecureStorage uses an experimental implementation using WebCrypto API. +Use at your own risk. The browser creates the private key, and encrypted +strings in localStorage are not portable to other browsers or machines +and will only work on the same domain. + +You MUST have HTTP Strict Forward Secrecy enabled and proper +headers applied to your responses, or you could be subject to JavaScript hijacking. + +Required security measures: + +- Enable HSTS (HTTP Strict Transport Security) +- Use proper security headers + +References: + +- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security +- https://www.netsparker.com/blog/web-security/http-security-headers/ + +## Application-Specific Key Wrapping + +On web, all keys are stored in LocalStorage. You can wrap this stored key +with an application-specific key to make it more difficult to analyze: + +```python +storage = SecureStorage( + web_options=WebOptions( + wrap_key='your_application_specific_key', + wrap_key_iv='your_application_specific_iv', + ), +) +``` diff --git a/website/docs/services/securestorage/types/windowsoptions.md b/website/docs/services/securestorage/types/windowsoptions.md new file mode 100644 index 0000000000..723e047daf --- /dev/null +++ b/website/docs/services/securestorage/types/windowsoptions.md @@ -0,0 +1,7 @@ +--- +title: "WindowsOptions" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/services/semanticsservice.md b/website/docs/services/semanticsservice.md new file mode 100644 index 0000000000..8bc11eec02 --- /dev/null +++ b/website/docs/services/semanticsservice.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.SemanticsService" +examples: "services/semantics_service" +title: "SemanticsService" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Retrieve accessibility features + + + + diff --git a/website/docs/services/shakedetector.md b/website/docs/services/shakedetector.md new file mode 100644 index 0000000000..5cfae204cc --- /dev/null +++ b/website/docs/services/shakedetector.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ShakeDetector" +examples: "services/shake_detector" +title: "ShakeDetector" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + diff --git a/website/docs/services/share.md b/website/docs/services/share.md new file mode 100644 index 0000000000..e30257677f --- /dev/null +++ b/website/docs/services/share.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Share" +examples: "services/share" +title: "Share" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/sharedpreferences.md b/website/docs/services/sharedpreferences.md new file mode 100644 index 0000000000..8f52baa708 --- /dev/null +++ b/website/docs/services/sharedpreferences.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.SharedPreferences" +examples: "services/sharedpreferences" +title: "SharedPreferences" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + diff --git a/website/docs/services/storagepaths.md b/website/docs/services/storagepaths.md new file mode 100644 index 0000000000..27c5ca2855 --- /dev/null +++ b/website/docs/services/storagepaths.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.StoragePaths" +examples: "services/storagepaths" +title: "StoragePaths" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + diff --git a/website/docs/services/urllauncher.md b/website/docs/services/urllauncher.md new file mode 100644 index 0000000000..56306a612d --- /dev/null +++ b/website/docs/services/urllauncher.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.UrlLauncher" +examples: "services/urllauncher" +title: "UrlLauncher" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Basic Example + + + + diff --git a/website/docs/services/useraccelerometer.md b/website/docs/services/useraccelerometer.md new file mode 100644 index 0000000000..79e09b80ed --- /dev/null +++ b/website/docs/services/useraccelerometer.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.UserAccelerometer" +examples: "services/user_accelerometer" +title: "UserAccelerometer" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/services/wakelock.md b/website/docs/services/wakelock.md new file mode 100644 index 0000000000..68515ad874 --- /dev/null +++ b/website/docs/services/wakelock.md @@ -0,0 +1,15 @@ +--- +class_name: "flet.Wakelock" +examples: "services/wakelock" +title: "Wakelock" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + + + + diff --git a/website/docs/tutorials/calculator.md b/website/docs/tutorials/calculator.md new file mode 100644 index 0000000000..35bcbbc78a --- /dev/null +++ b/website/docs/tutorials/calculator.md @@ -0,0 +1,287 @@ +--- +title: "Calculator Tutorial" +examples: "tutorials/calculator" +example_images: "test-images/tutorials/golden/macos/calculator" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +In this tutorial you will learn, step-by-step, how to create a Calculator app in +Python using Flet framework and publish it as a desktop, mobile or web app. +The app is a simple console program, yet it is a multi-platform application with +similar to iPhone calculator app UI: + +calc-app + +You can find a live demo [here](https://examples.flet.dev/calculator/). + +In this tutorial, we will cover all of the basic concepts for creating a Flet app: +building a page layout, adding controls, making reusable UI components, handling +events, and publishing options. + +## Getting started with Flet + +To create a multi-platform app in Python with Flet, you don't need to know HTML, +CSS or JavaScript, but you do need a basic knowledge of Python and object-oriented +programming. + +Before you can create your first Flet app, you need to +[setup your development environment](../getting-started/installation.md), which requires Python 3.10 or +above and `flet` package. + +Once you have Flet installed, let's [create](../getting-started/create-flet-app.md) a simple hello-world app. + +Create `hello.py` with the following contents: + +```python title="hello.py" +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text(value="Hello, world!")) + +ft.run(main) +``` + +Run this app and you will see a new window with a greeting: + +hello-world + +## Adding page controls + +Now you are ready to create a calculator app. + +To start, you'll need a [`Text`](../controls/text.md) control for showing the result of calculation, +and a few [`Button`](../controls/button.md)s with all the numbers and actions on them. + +Create `calc.py` with the following contents: + + + +Run the app and you should see a page like this: + +calc1 + +## Building page layout + +Now let's arrange the text and buttons in 6 horizontal [`Row`](../controls/row.md)s. + +Replace `calc.py` contents with the following: + + + +Run the app and you should see a page like this: + +calc2 + +### Using Container for decoration + +To add a black background with rounded border around the calculator, we will be using [`Container`](../controls/container.md) control. +Container may decorate only one control, so we will need to wrap all the 6 rows into a single vertical +[`Column`](../controls/column.md) that will be used as the container's [`content`](../controls/container.md#flet.Container.content): + +container-layout + +Here is the code for adding the container to the page: + +```python + page.add( + ft.Container( + width=350, + bgcolor=ft.Colors.BLACK, + border_radius=ft.BorderRadius.all(20), + padding=20, + content=ft.Column( + controls= [], # (1)! + ) + ) + ) +``` + +1. This controls list (of the `Column`) will contain the six rows of buttons. + +### Styled Controls + +To complete the UI portion of the program, we need to update style for result text and buttons to look similar to iPhone calculator app. + +For the result text, let's specify its `color` and `size` properties: +```python +result = ft.Text(value="0", color=ft.Colors.WHITE, size=20) +``` + +For the buttons, if we look again at the UI we are aiming to achieve, there are 3 types of buttons: + +1. **Digit Buttons**. They have dark grey background color and white text, size is the same for all except `0` button which is twice as large. + +2. **Action Buttons**. They have orange background color and white text, size is the same for all. + +3. **Extra action buttons**. They have light grey background color and dark text, size is the same for all. + +The buttons will be used multiple time in the program, so we will be creating +custom [Styled Controls](../cookbook/custom-controls.md#styled-controls) to reuse the code. + +Since all those types should inherit from `Button` class and have common `text` and `expand` properties, let's create a parent `CalcButton` class: + +```python +@ft.control +class CalcButton(ft.Button): + expand: int = 1 +``` + +Now let's create child classes for all three types of buttons: + +```python +@ft.control +class DigitButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.WHITE_24 + color: ft.Colors = ft.Colors.WHITE + +@ft.control +class ActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.ORANGE + color: ft.Colors = ft.Colors.WHITE + +@ft.control +class ExtraActionButton(CalcButton): + bgcolor: ft.Colors = ft.Colors.BLUE_GREY_100 + color: ft.Colors = ft.Colors.BLACK +``` + +We will be using these new classes now to create rows of buttons in the Container: + +```python +content = ft.Column( + controls=[ + ft.Row( + controls=[result], + alignment=ft.MainAxisAlignment.END, + ), + ft.Row( + controls=[ + ExtraActionButton(content="AC"), + ExtraActionButton(content="+/-"), + ExtraActionButton(content="%"), + ActionButton(content="/"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="7"), + DigitButton(content="8"), + DigitButton(content="9"), + ActionButton(content="*"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="4"), + DigitButton(content="5"), + DigitButton(content="6"), + ActionButton(content="-"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="1"), + DigitButton(content="2"), + DigitButton(content="3"), + ActionButton(content="+"), + ] + ), + ft.Row( + controls=[ + DigitButton(content="0", expand=2), + DigitButton(content="."), + ActionButton(content="="), + ] + ), + ] + ) +``` + +
+Full code + + open: true + +
+ +calc3 + +Just what we wanted! + +## Reusable UI components + +While you can continue writing your app in the `main` function, the best practice +would be to create a [reusable UI component](../cookbook/custom-controls.md#composite-controls). + +Imagine you are working on an app header, a side menu, or UI that will be a part +of a larger project (for example, at Flet we will be using this Calculator app in a bigger "Gallery" app that will show all the examples for Flet framework). + +Even if you can't think of such uses right now, we still recommend creating all your +Flet apps with composability and reusability in mind. + +To make a reusable Calc app component, we are going to encapsulate its state and +presentation logic in a separate `CalculatorApp` class. + +Copy the entire code for this step from [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/calculator/calc4.py). + +:::note[Try something] +Try adding two `CalculatorApp` components to the page: + +```python +# create application instance +calc1 = CalculatorApp() +calc2 = CalculatorApp() + +# add application's root control to the page +page.add(calc1, calc2) +``` +::: + +## Handling events + +Now let's make the calculator do its job. We will be using the same event handler +for all the buttons and use `content` property to differentiate between the actions +depending on the button clicked. + +We will define `button_click` method in `CalculatorClass` and pass it to each button. +Below is `on_click` event handler that will reset the Text value when "AC" button is clicked: + +```python +def button_clicked(self, e): + data = e.control.content + print(f"Button clicked with data = {data}") + if data == "AC": + self.result.value = "0" +``` + +With similar approach, `button_click` method will handle different calculator actions +depending on `content` property for each button. +Copy the entire code for this step from +[here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/calculator/calc.py). + +Run the app and see it in the action: +calc-app2 + +## Publishing your app + +Congratulations! You have created your Calculator app with Flet, and it looks awesome! +Now it's time to share your app with the world! + +Flet Python app and all its dependencies can be packaged into a standalone executable a +package for distribution using [`flet build`](../cli/flet-build.md) command. + +[Follow these instructions](../publish/index.md) to package your Calculator app into a desktop executable, +mobile app bundle or web app. + +## Summary + +In this tutorial you have learned how to: + +* [Create](../getting-started/create-flet-app.md) a simple Flet app; +* Work with [Reusable UI components](../cookbook/custom-controls.md); +* Design UI layout using `Column`, `Row` and `Container` controls; +* Handle events; +* [Publish](../publish/index.md) your Flet app to multiple platforms; + +For further reading you can explore [controls](/docs/controls) and [examples](https://github.com/flet-dev/flet/tree/main/sdk/python/examples). diff --git a/website/docs/tutorials/chat.md b/website/docs/tutorials/chat.md new file mode 100644 index 0000000000..6c831aeb77 --- /dev/null +++ b/website/docs/tutorials/chat.md @@ -0,0 +1,447 @@ +--- +title: "Chat Tutorial" +examples: "tutorials/chat" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +In this tutorial we are going to create a trivial in-memory Chat app that will help you understand Flet framework basics. +This app could be a good starting point to creating your own more complex and useful projects. + +In this tutorial you will learn how to: + +* [Create your first Flet app](#getting-started-with-flet) +* [Add page controls and handle events](#adding-page-controls-and-handling-events) +* [Broadcast messages using built-in PubSub library](#broadcasting-chat-messages) +* [Use AlertDialog control for accepting user name](#user-name-dialog) +* [Enhance user interface with reusable controls](#enhancing-user-interface) +* [Deploy the app as a web app](#deploying-the-app) + +The complete application will look like this: + +chat + +You can try the live demo [here](https://flet-chat.fly.dev). + +## Getting started with Flet + +It's a tradition to start with "Hello, world!" app! + +To create a multi-platform app in Python with Flet, you don't need to know HTML, CSS or JavaScript, but you do need a basic knowledge of Python and object-oriented programming. + +Before you can create your first Flet app, you need to [setup your development environment](../getting-started/installation.md). + +Once you have Flet installed, let's [create](../getting-started/create-flet-app.md) a hello-world app. + +Create `hello.py` with the following contents: + +```python title="hello.py" +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text(value="Hello, world!")) + +ft.run(main) +``` + +Run this app you will see a new window with a greeting: + +hello-world + +## Adding page controls and handling events + +To start, we want to be able to take user input (chat message) and show messages history on the screen. +The layout for this step could look like this: + +chat-layout-1 + +To implement this layout, we will be using these Flet controls: + +* [`Column`](../controls/column.md) - a container to display chat messages (`Text` controls) vertically. +* [`Text`](../controls/text.md) - chat message displayed in the chat Column. +* [`Row`](../controls/row.md) - a container to display `TextField` and `Button` horizontally. +* [`TextField`](../controls/textfield.md) - input control used for taking new message input from the user. +* [`Button`](../controls/button.md) - "Send" button that will add new message to the chat Column. + +Create `chat.py` with the following contents: + + + +When user clicks on the "Send" button, it triggers [`on_click`](../controls/button.md#flet.Button.on_click) event which calls `send_click` method. `send_click` +then adds new [`Text`](../controls/text.md) control to the list of [`Column.controls`](../controls/column.md#flet.Column.controls) and clears `new_message` text field value. + +:::note[Note] +After any properties of a control are updated in event handler, there is no need to call an `update()` method as the update will be done automatically, but it should be called in case properties are updated outside of the event. +::: + +Chat app now looks like this: +chat-1 + +## Broadcasting chat messages + +In the previous step we have created a simple app that takes input from the user and displays chats messages on the screen. + +If you open this app in two web browser tabs, it will create two app sessions. Each session will have its own list of messages. + +:::tip[Tip] +To open your app in two web browser tabs locally, run the following command: +``` +flet run --web +``` +Once it is opened, copy the url and paste it into a new tab. +::: + +To build a realtime chat app, you need to somehow pass the messages between chat app sessions. +When a user sends a message, it should be broadcasted to all other app sessions and displayed on their pages. + +Flet provides a simple built-in [PubSub](../cookbook/pub-sub.md) mechanism for asynchronous communication between page sessions. + +First, we need subscribe the user to receive broadcast messages: +```python + page.pubsub.subscribe(on_message) +``` + +`pubsub.subscribe()` method will add current app session to the list of subscribers. +It accepts `handler` as an argument, that will later be called at the moment a publisher calls `pubsub.send_all()` method. + +In the `handler` we will be adding new message (`Text`) to the list of chat `controls`: +```python + def on_message(message: Message): + chat.controls.append(ft.Text(f"{message.user}: {message.text}")) + page.update() +``` + +Finally, you need to call `pubsub.send_all()` method when the user clicks on "Send" button: +```python + def send_click(e): + page.pubsub.send_all(Message(user=page.session.index, text=new_message.value)) + new_message.value = "" + page.update() + + page.add(chat, ft.Row([new_message, ft.Button("Send", on_click=send_click)])) +``` + +`pubsub.send_all()` will call the `on_message()` and pass on the Message object down to it. + +Here is the full code for this step: + + + +chat-2 + +## User name dialog + +Chat app that you have created in the previous step has basic functionality needed to exchange messages between user sessions. It is not very user-friendly though, since it shows `session.id` that sent a message, which doesn't tell much about who you are communicating with. + +Let's improve our app to show user name instead of `session.id` for each message. To capture user name we will be using [`AlertDialog`](../controls/alertdialog.md) control. Let's add it to the page: + +```python + user_name = ft.TextField(label="Enter your name") + + page.show_dialog( + ft.AlertDialog( + open=True, + modal=True, + title=ft.Text("Welcome!"), + content=ft.Column([user_name], tight=True), + actions=[ft.Button(content="Join chat", on_click=join_click)], + actions_alignment=ft.MainAxisAlignment.END, + ) + ) +``` + +:::note[Note] +A dialog will be opened on the start of the program since we have set its `open` property to `True`. +::: + +username-dialog + +When the user clicks on "Join chat" button, it will call `join_click` method that should send a message to all subscribers, informing them that the user has joined the chat. This message should look different from the regular chat message, for example, like this: + +chat-4 + +Let's add `message_type` property to the `Message` class to differentiate between login and chat messages: + +```python +@dataclass +class Message: + user: str + text: str + message_type: str +``` + +We will be checking `message_type` in `on_message` method: + +```python +def on_message(message: Message): + if message.message_type == "chat_message": + chat.controls.append(ft.Text(f"{message.user}: {message.text}")) + elif message.message_type == "login_message": + chat.controls.append( + ft.Text(message.text, italic=True, color=ft.Colors.BLACK_45, size=12) + ) + page.update() +``` + +Messages of "login_message" and "chat_message" types will now be sent on two events: +when user joins the chat and when user sends a message. + +Let's create `join_click` method: + +```python +def join_click(e): + if not user_name.value: + user_name.error = "Name cannot be blank!" + user_name.update() + else: + page.session.store.set("user_name", user_name.value) + page.pop_dialog() + page.pubsub.send_all(Message(user=user_name.value, text=f"{user_name.value} has joined the chat.", message_type="login_message")) +``` + +We used [page session storage](../cookbook/session-storage.md) to store user_name for its future use in `send_click` method to send chat messages. + +:::note[Note] +User name dialog will close as soon as we call `page.pop_dialog()` method. +::: + +Finally, let's update `send_click` method to use `user_name` that we previously saved using `page.session.store`: + +```python +def send_click(e): + page.pubsub.send_all(Message(user=page.session.store.get('user_name'), text=new_message.value, message_type="chat_message")) + new_message.value = "" +``` + +
+Code + +
+ +chat-3 + +## Enhancing user interface + +Chat app that you have created in the previous step already serves its purpose of +exchanging messages between users with basic login functionality. + +Before moving on to [deploying your app](#deploying-the-app), we suggest adding some extra features to it that will improve user experience and make the app look more professional. + +### Reusable user controls + +You may want to show messages in a different format, like this: + +chat-layout-chatmessage + +Chat message will now be a [`Row`](../controls/row.md) containing [`CircleAvatar`](../controls/circleavatar.md) with username initials and +[`Column`](../controls/column.md) that contains two [`Text`](../controls/text.md) controls: user name and message text. + +We will need to show quite a few chat messages in the chat app, so it makes sense to create your own [reusable control](../cookbook/custom-controls.md). Lets create a new `ChatMessage` dataclass that will inherit from [`Row`](../controls/row.md). + +When creating an instance of `ChatMessage` class, we will pass a `Message` object as an argument and then `ChatMessage` will display itself based on `message.user_name` and `message.text`: + +```python +@ft.control +class ChatMessage(ft.Row): + def __init__(self, message: Message): + super().__init__() + self.message = message + self.vertical_alignment = ft.CrossAxisAlignment.START + self.controls = [ + ft.CircleAvatar( + content=ft.Text(self.get_initials(self.message.user_name)), + color=ft.Colors.WHITE, + bgcolor=self.get_avatar_color(self.message.user_name), + ), + ft.Column( + tight=True, + spacing=5, + controls=[ + ft.Text(self.message.user_name, weight=ft.FontWeight.BOLD), + ft.Text(self.message.text, selectable=True), + ], + ), + ] + + def get_initials(self, user_name: str): + if user_name: + return user_name[:1].capitalize() + else: + return "Unknown" # or any default value you prefer + + def get_avatar_color(self, user_name: str): + colors_lookup = [ + ft.Colors.AMBER, + ft.Colors.BLUE, + ft.Colors.BROWN, + ft.Colors.CYAN, + ft.Colors.GREEN, + ft.Colors.INDIGO, + ft.Colors.LIME, + ft.Colors.ORANGE, + ft.Colors.PINK, + ft.Colors.PURPLE, + ft.Colors.RED, + ft.Colors.TEAL, + ft.Colors.YELLOW, + ] + return colors_lookup[hash(user_name) % len(colors_lookup)] + +``` +`ChatMessage` control extracts initials and algorithmically derives avatar color from a username. +Later, if you decide to improve control layout or its logic, it won't affect the rest of the program - that's the power of encapsulation! + +### Laying out controls + +Now you can use your brand new `ChatMessage` to build a better layout for the chat app: + +chat-layout-2 + +Instances of `ChatMessage` will be created instead of plain `Text` chat messages in `on_message` method: + +```python + def on_message(message: Message): + if message.message_type == "chat_message": + m = ChatMessage(message) + elif message.message_type == "login_message": + m = ft.Text(message.text, italic=True, color=ft.Colors.BLACK_45, size=12) + chat.controls.append(m) + page.update() +``` + +Other improvements suggested with the new layout are: + +* [`ListView`](../controls/listview.md) instead of [`Column`](../controls/column.md) for displaying messages, to be able to scroll through the messages later +* [`Container`](../controls/container.md) for displaying border around [`ListView`](../controls/listview.md) +* [`IconButton`](../controls/iconbutton.md) instead of [`Button`](../controls/button.md) to send messages +* Use of [`expand`](../controls/control.md#flet.Control.expand) property for controls to fill available space + +Here is how you can implement this layout: + +```python + # Chat messages + chat = ft.ListView( + expand=True, + spacing=10, + auto_scroll=True, + ) + + # A new message entry form + new_message = ft.TextField( + hint_text="Write a message...", + autofocus=True, + shift_enter=True, + min_lines=1, + max_lines=5, + filled=True, + expand=True, + on_submit=send_message_click, + ) + + # Add everything to the page + page.add( + ft.Container( + content=chat, + border=ft.Border.all(1, ft.Colors.OUTLINE), + border_radius=5, + padding=10, + expand=True, + ), + ft.Row( + [ + new_message, + ft.IconButton( + icon=ft.Icons.SEND_ROUNDED, + tooltip="Send message", + on_click=send_message_click, + ), + ] + ), + ) +``` + +
+Full code + + open: true + +
+ +This is the final version of the chat app for the purpose of this tutorial. +Below you can read more about the enhancements that we have made. + +### Keyboard support + +#### Focusing input controls + +All data entry controls have `autofocus` property which when set to `True` moves +initial focus to the control. If there is more than one control on a page with `autofocus` set, then the first one added to the page will get focus. + +We set `autofocus=True` on a username TextField inside a dialog and then on a TextField for entering chat message to set initial focus on it when the dialog is closed. + +When a user click "Send" button or presses Enter to submit a chat message, TextField loses focus. +To programmatically set control focus we used [`TextField.focus()`](../controls/formfieldcontrol.md#flet.FormFieldControl.focus) method. + +#### Submitting forms on `Enter` + +It's so tempting to submit forms with just pushing `Enter` button on the keyboard! +Type your name in the dialog, hit `Enter`, type a new message, hit `Enter`, type another, hit `Enter` - no mouse involved at all! 🚀 + +Flet has support for that by providing [`TextField.on_submit`](../controls/textfield.md#flet.TextField.on_submit) event handler which fires when a user press `Enter` button while the focus is on the TextField. + +#### Entering multiline messages + +What about multiline TextFields where `Enter` must advance a cursor to the next line? +We've got that covered too! `TextField` control has [`shift_enter`](../controls/textfield.md#flet.TextField.shift_enter) property which when set to `True` enables Discord-like behavior: to get to a new line user presses `Shift`+`Enter` while hitting just `Enter` submits a form. + +### Animated scrolling to the last message + +Noticed a nice animation of scrolling to the last message in a chat window? +It could be enabled by setting [`ListView.auto_scroll`](../controls/listview.md) property to `True`. +The top most `Page` class, being a scrollable container itself, also supports [`auto_scroll`](../controls/page.md). + +### Page title + +Final touch - page title that could be changed as simply as: + +```python +page.title = "Flet Chat" +page.update() +``` + +## Deploying the app + +Congratulations! You have created your Chat app in Python with Flet, and it looks awesome! + +Now it's time to share your app with the world! + +[Follow these instructions](../publish/web/dynamic-website/hosting/index.md) to deploy your Flet app as a web app to Fly.io or Replit. + +## What's next + +There are plenty of features we could implement to improve this chat app: + +* Disconnect, reconnect, session timeout +* Upload/download images +* Authentication, avatars +* Using database for the storage +* Chat channels, topics +* Full-text search +* Emojis, markdown +* Bots +* Mobile app + +Please let us know if you would like to contribute to the app/tutorial and share it with other Flet developers. + +## Summary + +In this tutorial, you have learnt how to: + +* Create a simple Flet app; +* Add page controls and handle events; +* Use built in PubSub library; +* User AlertDialog for entering user name; +* Build page layout with reusable controls; +* Deploy your Flet app to the web; + +For further reading you can explore [controls](/docs/controls) and [examples](https://github.com/flet-dev/flet/tree/main/sdk/python/examples). diff --git a/website/docs/tutorials/solitaire.md b/website/docs/tutorials/solitaire.md new file mode 100644 index 0000000000..0b55378cfb --- /dev/null +++ b/website/docs/tutorials/solitaire.md @@ -0,0 +1,1293 @@ +--- +title: "Solitaire Tutorial" +--- + +import {Image} from '@site/src/components/crocodocs'; + +In this tutorial we will show you step-by-step creation of a famous Klondike solitaire game in Python with Flet. For an inspiration, we looked at this online game: https://www.solitr.com/ + +This tutorial is aimed at beginner/intermediate level Python developers who have basic knowledge of Python and object oriented programming. + +You can find a live demo [here](https://examples.flet.dev/solitaire/). + +solitaire + +We have broken down the game implementation into the following steps: + +* [Getting started with Flet](#getting-started-with-flet) +* [Proof of concept app for draggable cards](#proof-of-concept-app-for-draggable-cards) +* [Fanned card piles](#fanned-card-piles) +* [Solitaire setup](#solitaire-setup) +* [Solitaire rules](#solitaire-rules) +* [Winning the game](#winning-the-game) +* [Deploying the app](#deploying-the-app) + +In the Part 2 (will be covered in the next tutorial) we'll be adding Appbar with options to start new game, +view game rules and change game settings. + +## Getting started with Flet + +To create a multi-platform app in Python with Flet, you don't need to know HTML, CSS or JavaScript, +but you do need a basic knowledge of Python and object-oriented programming. + +Before you can create your first Flet app, you need to +[setup your development environment](../getting-started/installation.md), which requires Python 3.9 or above and `flet` package. + +Once you have Flet installed, let's [create](../getting-started/create-flet-app.md) a simple hello-world app. + +Create `hello.py` with the following contents: + +```python title="hello.py" +import flet as ft + +def main(page: ft.Page): + page.add(ft.Text(value="Hello, world!")) + +ft.run(main) +``` + +Run this app and you will see a new window with a greeting: + +hello-world + +## Proof of concept app for draggable cards + +For the proof of concept, we will only be using three types of controls: + +* [`Stack`](../controls/stack.md) - will be used as a parent control for absolute positioning of slots and cards +* [`GestureDetector`](../controls/gesturedetector.md) - the card that will be moved within the [`Stack`](../controls/stack.md) +* [`Container`](../controls/container.md) - the slot where the card will be dropped. Will also be used as `content` for the [`GestureDetector`](../controls/gesturedetector.md). + +We have broken down the proof of concept app into four easy steps, so that after each step you have +a complete short program to run and test. + +### Step 1: Drag the card around + +In this step we will create a [`Stack`](../controls/stack.md) (Solitaire game field) +and a [`GestureDetector`](../controls/gesturedetector.md) (Solitaire card). +The card will then be added to the list of the [`Stack.controls`](../controls/stack.md#flet.Stack.controls). +[`top`](../controls/gesturedetector.md) and [`left`](../controls/gesturedetector.md) properties of the +`GestureDetector` are used for absolute positioning of the card in the `Stack`. + +```python +import flet as ft + +def main(page: ft.Page): + def drag(e: ft.DragUpdateEvent): + ... + + card = ft.GestureDetector( + on_pan_update=drag, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), + ) + + page.add(ft.Stack(controls=[card], width=1000, height=500)) + +ft.run(main) +``` + +Run the app to see the card added to the stack: + +drag_and_drop1 + +To be able to move the card, we'll update the `drag` method that is called in [`on_pan_update`](../controls/gesturedetector.md#flet.GestureDetector.on_pan_update) +event of `GestureDetector` which happens every [`drag_interval`](../controls/gesturedetector.md#flet.GestureDetector.drag_interval) while the user drags the card with their mouse. + +To show the card's movement, we’ll be updating the card’s [`top`](../controls/gesturedetector.md) and [`left`](../controls/gesturedetector.md) properties in the `drag` +callback each time the [`on_pan_update`](../controls/gesturedetector.md#flet.GestureDetector.on_pan_update) event happens. + +Below is the simplest code for dragging `GestureDetector` in `Stack`: + +```python +import flet as ft + +# Use of GestureDetector with on_pan_update event for dragging card +# Absolute positioning of controls within stack + +def main(page: ft.Page): + def drag(e: ft.DragUpdateEvent): + e.control.top = max(0, e.control.top + e.local_delta.y) + e.control.left = max(0, e.control.left + e.local_delta.x) + e.control.update() + + card = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_update=drag, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), + ) + + page.add(ft.Stack(controls=[card], width=1000, height=500)) + +ft.run(main) +``` + +Now you can see the card moving: + +drag_and_drop2 + +:::note[Note] +After any properties of a control are updated, an `update()` method of the control (or its parent control) should be called for the update to take effect. +::: + +### Step 2: Drop the card in the slot or bounce it back + +The goal of this step is to be able to drop a card into a slot if it is close enough and bounce it back if it’s not. + +drag-and-drop3 + +Let’s create a [`Container`](../controls/container.md) control that will represent a slot to which we’ll be dropping the card: + +```python +slot = ft.Container( + width=70, + height=100, + left=200, + top=0, + border=ft.border.all(1) +) +page.add(ft.Stack(controls = [slot, card], width=1000, height=500)) +``` + +`on_pan_end` event of the card is called when the card is dropped: + +```python +card = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_update=drag, + on_pan_end=drop, + left=0, + top=0, + content=ft.Container(bgcolor=ft.Colors.GREEN, width=70, height=100), +) +``` + +On this event, we’ll call `drop` method to check if the card is close enough to the slot +(let’s say it’s closer than 20px to the slot), and `place` it there: + +```python +def drop(e: ft.DragEndEvent): + if ( + abs(e.control.top - slot.top) < 20 + and abs(e.control.left - slot.left) < 20 + ): + place(e.control, slot) + e.control.update() + +def place(card, slot): + """place card to the slot""" + card.top = slot.top + card.left = slot.left + page.update() +``` + +Now, if the card is not close enough, we need to bounce it back to its original position. +Unfortunately, we don’t know the original position coordinates, since the card’s `top` and `left` properties were changed on `on_pan_update` event. + +To solve this problem, let’s create a `Solitaire` class object to keep track of the original position of +the card when [`on_pan_start`](../controls/gesturedetector.md#flet.GestureDetector.on_pan_start) event of the card is called: + +```python +class Solitaire: + def __init__(self): + self.start_top = 0 + self.start_left = 0 + +solitaire = Solitaire() + +def start_drag(e: ft.DragStartEvent): + solitaire.start_top = e.control.top + solitaire.start_left = e.control.left + e.control.update() +``` + +Now let’s update [`on_pan_end`](../controls/gesturedetector.md#flet.GestureDetector.on_pan_end) event with the option to bounce card back: +```python +def bounce_back(game, card): + """return card to its original position""" + card.top = game.start_top + card.left = game.start_left + page.update() + +def drop(e: ft.DragEndEvent): + if ( + abs(e.control.top - slot.top) < 20 + and abs(e.control.left - slot.left) < 20 + ): + place(e.control, slot) + else: + bounce_back(solitaire, e.control) + + e.control.update() +``` + +The full code for this step can be found [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step2.py). + +### Step 3: Adding a second card + +Eventually, we’ll need 52 cards to play the game. For our proof of concept, let’s add a second card: + +```python + + card2 = ft.GestureDetector( + mouse_cursor=ft.MouseCursor.MOVE, + drag_interval=5, + on_pan_start=start_drag, + on_pan_update=drag, + on_pan_end=drop, + left=100, + top=0, + content=ft.Container(bgcolor=ft.Colors.YELLOW, width=70, height=100), + ) + + controls = [slot, card1, card2] + page.add(ft.Stack(controls=controls, width=1000, height=500)) +``` + +Now, if you run the app with the two cards, you will notice that when you move the cards around, the +yellow card (`card2`) is moving as expected but the green the card (`card1`) is moving under the yellow card. + +drag_and_drop4.gif + +It happens because `card2` is added to the list of stack's [`controls`](../controls/stack.md#flet.Stack.controls) after `card1`. To fix this problem, +we need to move the draggable card to the top of the list of controls on [`on_pan_start`](../controls/gesturedetector.md#flet.GestureDetector.on_pan_start) event: + +```python +def move_on_top(card, controls): + """Moves draggable card to the top of the stack""" + controls.remove(card) + controls.append(card) + page.update() + +def start_drag(e: ft.DragStartEvent): + move_on_top(e.control, controls) + solitaire.start_top = e.control.top + solitaire.start_left = e.control.left +``` + +Now the two cards can be dragged without issues: + +drag_and_drop5.gif + +The full code for this step can be found [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step3.py). + +### Step 4: Adding more slots + +As a final step for the proof of concept app, let’s create two more slots: +```python +slot0 = ft.Container( + width=70, height=100, left=0, top=0, border=ft.border.all(1) +) + +slot1 = ft.Container( + width=70, height=100, left=200, top=0, border=ft.border.all(1) +) + +slot2 = ft.Container( + width=70, height=100, left=300, top=0, border=ft.border.all(1) +) + +slots = [slot0, slot1, slot2] +``` + +When creating new cards, we will not specify their `top` and `left` position now, but instead, +will place them to the `slot0`: + +```python +# deal cards +place(card1, slot0) +place(card2, slot0) +``` + +`on_pan_end` event, where we check if a card is close to a slot, we will now go through the +list of slots to find where the card should be dropped: + +```python +def drop(e: ft.DragEndEvent): + for slot in slots: + if ( + abs(e.control.top - slot.top) < 20 + and abs(e.control.left - slot.left) < 20 + ): + place(e.control, slot) + e.control.update() + return + + bounce_back(solitaire, e.control) + e.control.update() +``` + +As a result, the two cards can be dragged between the three slots: + +drag_and_drop6.gif + +The full code for this step can be found [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-drag-and-drop/step4.py). + +Congratulations on completing the proof of concept app for the Solitaire game! +Now you can work with [`GestureDetector`](../controls/gesturedetector.md) to move cards inside [`Stack`](../controls/stack.md) and place them to +certain `Container`s, which is a great part of the game to begin with. + +## Fanned card piles + +In the proof of concept app you have accomplished the task of dropping a card into a slot in +proximity or bounce it back. If there is already a card in that slot, the new card is placed on top of it, +covering it completely. + +In the actual Solitaire game, if there is already a card in a *tableau* slot, you want to +place the draggable card a bit lower, so that you can see the previous card too, and if there are two cards, +even lower. Those are called “fanned piles”. + +Then, we want to be able to pick a card from the fanned pile that is not the top card of +the pile and drag the card together with all the cards below it: + +fanned_piles1.gif + +To be able to do that, it would be useful to have the information about the pile of cards +in the slot from which the card is dragged, as well as in the slot to which it is being dropped. +Let’s restructure our program and get it ready for the implementation of the fanned piles. + +### Slot, Card and Solitaire classes + +A slot could have a `pile` property that would hold a list of cards that were placed there. +Now the slot is a [`Container`](../controls/container.md) control object, and we can’t add any new properties to it. +Let’s create a new `Slot` class that will inherit from `Container` and add a `pile` property to it: + +```python +SLOT_WIDTH = 70 +SLOT_HEIGHT = 100 + +import flet as ft + +class Slot(ft.Container): + def __init__(self, top, left): + super().__init__() + self.pile=[] + self.width=SLOT_WIDTH + self.height=SLOT_HEIGHT + self.left=left + self.top=top + self.border=ft.border.all(1) +``` + +Similarly to `Slot` class, let’s create a new `Card` class with `slot` property to remember in which slot it resides. +It will inherit from [`GestureDetector`](../controls/gesturedetector.md) and we’ll move all card-related methods to it: +```python +CARD_WIDTH = 70 +CARD_HEIGHT = 100 +DROP_PROXIMITY = 20 + +import flet as ft + +class Card(ft.GestureDetector): + def __init__(self, solitaire, color): + super().__init__() + self.slot = None + self.mouse_cursor=ft.MouseCursor.MOVE + self.drag_interval=5 + self.on_pan_start=self.start_drag + self.on_pan_update=self.drag + self.on_pan_end=self.drop + self.left=None + self.top=None + self.solitaire = solitaire + self.color = color + self.content=ft.Container(bgcolor=self.color, width=CARD_WIDTH, height=CARD_HEIGHT) + + def move_on_top(self): + """Moves draggable card to the top of the stack""" + self.solitaire.controls.remove(self) + self.solitaire.controls.append(self) + self.solitaire.update() + + def bounce_back(self): + """Returns card to its original position""" + self.top = self.slot.top + self.left = self.slot.left + self.update() + + def place(self, slot): + """Place card to the slot""" + self.top = slot.top + self.left = slot.left + self.slot = slot + + def start_drag(self, e: ft.DragStartEvent): + self.move_on_top() + self.update() + + def drag(self, e: ft.DragUpdateEvent): + self.top = max(0, self.top + e.local_delta.y) + self.left = max(0, self.left + e.local_delta.x) + self.update() + + def drop(self, e: ft.DragEndEvent): + for slot in self.solitaire.slots: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.update() + return + + self.bounce_back() + self.update() +``` + +:::note[Note] +Since each card has `slot` property now, there is no need to remember `start_left` and `start_top` +position of the draggable card in Solitaire class anymore, because we can just bounce it back to its slot. +::: + +Let’s update `Solitaire` class to inherit from [`Stack`](../controls/stack.md), and move the creation of cards and slots there: + +```python +SOLITAIRE_WIDTH = 1000 +SOLITAIRE_HEIGHT = 500 + +import flet as ft +from slot import Slot +from card import Card + +class Solitaire(ft.Stack): + def __init__(self): + super().__init__() + self.controls = [] + self.slots = [] + self.cards = [] + self.width = SOLITAIRE_WIDTH + self.height = SOLITAIRE_HEIGHT + + def did_mount(self): + self.create_card_deck() + self.create_slots() + self.deal_cards() + + def create_card_deck(self): + card1 = Card(self, color="GREEN") + card2 = Card(self, color="YELLOW") + self.cards = [card1, card2] + + def create_slots(self): + self.slots.append(Slot(top=0, left=0)) + self.slots.append(Slot(top=0, left=200)) + self.slots.append(Slot(top=0, left=300)) + self.controls.extend(self.slots) + self.update() + + def deal_cards(self): + self.controls.extend(self.cards) + for card in self.cards: + card.place(self.slots[0]) + self.update() +``` + +:::note[Note] +If you try to call `create_slots()` and `create_card_deck()` and `deal_cards()` methods `__init__()` +method of the Solitaire class, it will cause an error “Control must be added to the page first”. +To fix this, we create slots and cards inside the `did_mount()` method, which happens immediately +after the stack is added to the page. +::: + +Our main program will be very simple now: +```python +import flet as ft +from solitaire import Solitaire + +def main(page: ft.Page): + + solitaire = Solitaire() + + page.add(solitaire) + +ft.run(main) +``` + +You can find the full source code for this step [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-classes). It works exactly the same way as +the proof of concept app, but re-written with the new classes to be ready for adding more +complex functionality to it. + +### Placing card with offset + +When the card is being placed to a slot in the `card.place()` method, we need to do three things: +* Remove the card from its original slot, if it exists +* Change card’s slot to the new slot +* Add the card to the new slot’s pile +```python +def place(self, slot): + self.top = slot.top + self.left = slot.left + + # remove card from it's original slot, if exists + if self.slot is not None: + self.slot.pile.remove(self) + + # change card's slot to a new slot + self.slot = slot + + # add card to the new slot's pile + slot.pile.append(self) +``` + +When updating card’s `top` and `left` position, `left` should remain the same, but `top` +will depend on the length of the new slot’s pile and `CARD_OFFSET`: +```python +CARD_OFFSET = 20 + +... + +def place(self, slot): + self.top = slot.top + len(slot.pile) * CARD_OFFSET + self.left = slot.left + ... +``` + +Now the cards are placed with offset which gives us the fanned pile look: + +fanned_piles1 + +### Drag pile of cards + +If you try to drag the card from the bottom of the pile now, it will look like this: + +drag_pile + +To fix this problem, we need to update all the methods in `card.py` that work with the draggable +card to work with the draggable pile instead. + +Let’s create `get_draggable_pile()` method that will get the list of cards that need to be dragged +together, starting with the card you picked: +```python + def get_draggable_pile(self): + """returns list of cards that will be dragged together, starting with the current card""" + if self.slot is not None: + self.draggable_pile = self.slot.pile[self.slot.pile.index(self) :] + else: # slot == None when the cards are dealt and need to be place in slot for the first time + self.draggable_pile = [self] +``` + +Since `self.draggable_pile` is a new `Card` attribute, Let’s add it to `__init__()`: +```python +class Card(ft.GestureDetector): + def __init__(self, solitaire, color): + super().__init__() + ... + self.draggable_pile = [self] +``` + +Now we need to update `start_drag()` method to get the draggable pile each time a drag starts: +```python + def start_drag(self, e: ft.DragStartEvent): + self.get_draggable_pile() + self.move_on_top() + self.solitaire.update() +``` + +Then, we’ll update `move_on_top()` method: +```python + def move_on_top(self): + """Brings draggable card pile to the top of the stack""" + + # for card in self.get_draggable_pile(): + for card in self.draggable_pile: + self.solitaire.controls.remove(card) + self.solitaire.controls.append(card) + self.solitaire.update() +``` + +Additionally, we need to update `drag()` method to go through the draggable pile and update +positions of all the cards being dragged: +```python + def drag(self, e: ft.DragUpdateEvent): + for card in self.draggable_pile: + card.top = ( + max(0, self.top + e.local_delta.y) + + self.draggable_pile.index(card) * CARD_OFFSET + ) + card.left = max(0, self.left + e.local_delta.x) + self.solitaire.update() +``` + +Also, we need to update `place()` method to place the draggable pile to the slot: +```python + def place(self, slot): + """Place draggable pile to the slot""" + for card in self.draggable_pile: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + card.left = slot.left + + # remove card from it's original slot, if it exists + if card.slot is not None: + card.slot.pile.remove(card) + + # change card's slot to a new slot + card.slot = slot + + # add card to the new slot's pile + slot.pile.append(card) + + self.solitaire.update() +``` + +Finally, if no slot in proximity is found, we need to bounce the whole pile back to its original position: +```python + def bounce_back(self): + """Returns draggable pile to its original position""" + for card in self.draggable_pile: + card.top = card.slot.top + card.slot.pile.index(card) * CARD_OFFSET + card.left = card.slot.left + self.solitaire.update() +``` + +The full source code of this step can be found [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-fanned-piles). Now we can drag and drop cards in fanned piles, +which means we are ready for the real deal! + +## Solitaire setup + +Let’s take a look at the [wikipedia article about Klondike (solitaire)](https://en.wikipedia.org/wiki/Klondike_(solitaire)#Rules): + +> Klondike is played with a standard 52-card deck. + +> After shuffling, a tableau of seven fanned piles of cards is laid from left to right. +> From left to right, each pile contains one more card than the last. +> The first and left-most pile contains a single upturned card, the second pile contains two cards, +> the third pile contains three cards, the fourth pile contains four cards, +> the fifth pile contains five cards, the sixth pile contains six cards, and the seventh pile contains seven cards. +> The topmost card of each pile is turned face up. +> The remaining cards form the stock and are placed facedown at the upper left of the layout. + +> The four foundations (light rectangles in the upper right of the figure) are built up by suit from Ace (low in this game) to King, and the tableau piles can be built down by alternate colors. + +game_setup_wiki + +We will now work on this setup step by step. + +### Create card deck + +The first step is to create a full deck of cards in Solitaire class. Each card should have a `suit` property +(hearts, diamonds, clubs and spades) and a `rank` property (from Ace to King). +For the suit, its `color` is important, because tableau piles are built by alternate colors. + +For the rank, its `value` is important, because foundations are built from the lowest (Ace) to the highest (King) rank value. + +In solitaire.py, create `Suite` and `Rank` classes: +```python +class Suite: + def __init__(self, suite_name, suite_color): + self.name = suite_name + self.color = suite_color + +class Rank: + def __init__(self, card_name, card_value): + self.name = card_name + self.value = card_value +``` +Now, in the `Card` class, instead of accepting the color as an argument, we’ll be accepting `suite` and +`rank` in `__init__()`. Additionally, we’ll add `face_up` property to the card and the Container will now has image of the back of the card as its `content`: +```python +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + super().__init__() + self.mouse_cursor=ft.MouseCursor.MOVE + self.drag_interval=5 + self.on_pan_start=self.start_drag + self.on_pan_update=self.drag + self.on_pan_end=self.drop + self.suite=suite + self.rank=rank + self.face_up=False + self.top=None + self.left=None + self.solitaire = solitaire + self.slot = None + self.content=ft.Container( + width=CARD_WIDTH, + height=CARD_HEIGHT, + border_radius = ft.border_radius.all(6), + content=ft.Image(src="images/card_back.png")) +``` +All the [images](https://github.com/flet-dev/flet/tree/main/sdk/python/examples/tutorials/solitaire/solitaire-game-setup/assets/images) +for the face up cards, as well as card back are stored in the “assets/images” folder in the same directory as main.py. + +:::note +You could specify the assets folder, see [Assets](../cookbook/assets.md) guide for more information and examples. +::: +Finally, in `solitaire.create_card_deck()` we'll create lists of suites and ranks and then the 52-card deck: +```python +def create_card_deck(self): + suites = [ + Suite("hearts", "RED"), + Suite("diamonds", "RED"), + Suite("clubs", "BLACK"), + Suite("spades", "BLACK"), + ] + ranks = [ + Rank("Ace", 1), + Rank("2", 2), + Rank("3", 3), + Rank("4", 4), + Rank("5", 5), + Rank("6", 6), + Rank("7", 7), + Rank("8", 8), + Rank("9", 9), + Rank("10", 10), + Rank("Jack", 11), + Rank("Queen", 12), + Rank("King", 13), + ] + + self.cards = [] + + for suite in suites: + for rank in ranks: + self.cards.append(Card(solitaire=self, suite=suite, rank=rank)) +``` +The card deck is ready to be dealt, and now we need to create the layout for it. + +### Create slots + +Klondike solitaire game layout should look like this: + +solitaire-layout + +Now, in the `Slot` class, we’ll be accepting `solitaire`, `border` and `border_radius` +as arguments in `__init__()`: +```python +class Slot(ft.Container): + def __init__(self, top, left, border): + super().__init__() + ... + self.solitaire = solitaire + self.border = border + self.border_radius = ft.border_radius.all(6) +``` + +Let’s create all those slots in `solitaire.create_slots()`: +```python +def create_slots(self): + + self.stock = Slot(self, top=0, left=0, border=ft.border.all(1)) + self.waste = Slot(self, top=0, left=100, border=None) + + self.foundations = [] + x = 300 + for i in range(4): + self.foundations.append(Slot(self, top=0, left=x, border=ft.border.all(1, "outline"))) + x += 100 + + self.tableau = [] + x = 0 + for i in range(7): + self.tableau.append(Slot(self, top=150, left=x, border=None)) + x += 100 + + self.controls.append(self.stock) + self.controls.append(self.waste) + self.controls.extend(self.foundations) + self.controls.extend(self.tableau) + self.update() +``` + +:::note[Note] +Note: some slots should have visible border and some shouldn’t, so we added border to the list of arguments for the creation of `Slot` objects. +::: + +:::note[Note] +If you try to run the app, it will cause an error “IndexError: list index out of range”. +To fix this, update `deal_cards()` method as described below. +::: + +### Deal cards + +Let's start with shuffling the cards and adding them to the list of controls: +```python +import random + +... + +def deal_cards(self): + random.shuffle(self.cards) + self.controls.extend(self.cards) + self.update() +``` + +Then we'll deal the cards to the tableau piles from left to right so that each pile contains one more card +than the last, and place the remaining cards to the stock pile: +```python +def deal_cards(self): + random.shuffle(self.cards) + self.controls.extend(self.cards) + + # deal to tableau + first_slot = 0 + remaining_cards = self.cards + + while first_slot < len(self.tableau): + for slot in self.tableau[first_slot:]: + top_card = remaining_cards[0] + top_card.place(slot) + remaining_cards.remove(top_card) + first_slot +=1 + + # place remaining cards to stock pile + for card in remaining_cards: + card.place(self.stock) + + self.update() +``` + +Let’s run the program and see where we are at now: + +game-setup1 + +Cards in stock were placed in a fanned pile in the same manner as to the tableau, +but they should have been placed to a regular pile instead. To fix this problem, +let’s add this condition to the `card.place()` method: +```python +def place(self, slot): + """Place draggable pile to the slot""" + for card in self.draggable_pile: + if slot in self.solitaire.tableau: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + else: + card.top = slot.top + self.left = slot.left + ... +``` +Now cards are only placed in fanned piles to tableau: + +game-setup2 + +If you try moving the cards around now, the program won’t work. +The reason for this is that in the `card.drop()` method iterates through list of slots which we don’t have now. + +Let’s update the method to go separately through foundations and tableau: +```python +def drop(self, e: ft.DragEndEvent): + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.solitaire.update() + return + + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + self.solitaire.update() + return + + self.bounce_back() +``` + +### Reveal top cards in tableau piles + +Now we have the correct game setup and as a last touch we need to reveal the topmost cards in tableau piles. + +In `Slot` class, create a `get_top_card()` method: +```python +def get_top_card(self): + if len(self.pile) > 0: + return self.pile[-1] +``` +In `Card` class, create `turn_face_up()` method: +```python +def turn_face_up(self): + self.face_up = True + self.content.content.src=f"images/{self.rank.name}_{self.suite.name}.svg" + self.solitaire.update() +``` +Finally, reveal the topmost cards at the end of `solitaire.deal_cards()`: +```python +def deal_cards(self): + ... + self.update() + + for slot in self.tableau: + slot.get_top_card().turn_face_up() + + self.update() +``` + +Let’s see how it looks now: + +game-setup3 + +The full source code for this step can be found [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-game-setup). + +Congratulations on completing the Solitaire game setup! You’ve created a full 52-card deck, +built layout with stock, waste, foundations and tableau piles, dealt the cards and revealed the top cards in tableau. Let’s move on to the next item on our todo list, which is Solitaire Rules. + +## Solitaire rules + +If you run your current version of Solitaire, you’ll notice that you can do some crazy things with your cards: + +game-rules1 + +Now it is time to implement some rules. + +### General rules + +Currently, we can move any card, but only face-up cards should be moved. +Let’s add this check in `start_drag`, `drag` and `drop` methods of the card: +```python +def start_drag(self, e: ft.DragStartEvent): + if self.face_up: + self.move_on_top() + self.solitaire.update() + +def drag(self, e: ft.DragUpdateEvent): + if self.face_up: + for card in self.draggable_pile: + card.top = max(0, self.top + e.local_delta.y) + self.draggable_pile.index(card) * CARD_OFFSET + card.left = max(0, self.left + e.local_delta.x) + card.solitaire.update() + +def drop(self, e: ft.DragEndEvent): + if self.face_up: + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + return + + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + return + + self.bounce_back() +``` + +Now let’s specify `click` method for the `on_tap` event of the card to reveal the card +if you click on a faced-down top card in a tableau pile: +```python +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + ... + self.on_tap = self.click + ... + + ... + + def click(self, e): + if self.slot in self.solitaire.tableau: + if not self.face_up and self == self.slot.get_top_card(): + self.turn_face_up() + self.solitaire.update() +``` + +Let's check how it works: + +game_rules2 + +### Foundations rules + +At the moment we can place fanned piles to foundations, which shouldn’t be allowed. +Let’s check the draggable pile length to fix it: + +```python +def drop(self, e: ft.DragEndEvent): + if self.face_up: + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + return + + if len(self.draggable_pile) == 1: + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + return + + self.bounce_back() +``` + +Then, of course, not any card can be placed to a foundation. According to the rules, a foundation should +start with an Ace and then the cards of the same suite can be placed on top of it to build a pile form Ace to King. + +Let’s add this rule to Solitaire class: +```python +def check_foundations_rules(self, card, slot): + top_card = slot.get_top_card() + if top_card is not None: + return ( + card.suite.name == top_card.suite.name + and card.rank.value - top_card.rank.value == 1 + ) + else: + return card.rank.name == "Ace" +``` + +We’ll check this rule in `drop()` method of the card before placing a card to a foundation slot: +```python +def drop(self, e: ft.DragEndEvent): + if self.face_up: + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ): + self.place(slot) + return + + if len(self.draggable_pile) == 1: + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return + + self.bounce_back() +``` + +As a final touch for foundations rules, let’s implement `doubleclick` method for `on_double_tap` event of a card. +It will be checking if the faced-up card fits into any of the foundations and place it there: +```python +class Card(ft.GestureDetector): + def __init__(self, solitaire, suite, rank): + ... + self.on_double_tap = self.doubleclick + ... + + ... + + def doubleclick(self, e): + self.get_draggable_pile() + if self.face_up and len(self.draggable_pile) == 1: + self.move_on_top() + for slot in self.solitaire.foundations: + if self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return +``` + +### Tableau rules + +Finally, let's implement the rules to build tableau piles down from King to Ace by alternating suite color. +Additionally, only King can be placed to an empty tableau slot. + +Let’s add these rules for Solitaire class: +```python +def check_tableau_rules(self, card, slot): + top_card = slot.get_top_card() + if top_card is not None: + return ( + card.suite.color != top_card.suite.color + and top_card.rank.value - card.rank.value == 1 + and top_card.face_up + ) + else: + return card.rank.name == "King" +``` +Similarly to the foundations rules, we’ll check tableau rules before placing a card to a tableau pile: +```python +def drop(self, e: ft.DragEndEvent): + if self.face_up: + for slot in self.solitaire.tableau: + if ( + abs(self.top - (slot.top + len(slot.pile) * CARD_OFFSET)) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_tableau_rules(self, slot): + self.place(slot) + return + + if len(self.draggable_pile) == 1: + for slot in self.solitaire.foundations: + if ( + abs(self.top - slot.top) < DROP_PROXIMITY + and abs(self.left - slot.left) < DROP_PROXIMITY + ) and self.solitaire.check_foundations_rules(self, slot): + self.place(slot) + return + + self.bounce_back() +``` + +### Stock and waste + +To properly play Solitaire game right now we are missing the remaining cards that are piled in the stock. + +Let’s update `click()` method of the card to go through the stock pile and place the cards to waste as we go: +```python +def click(self, e): + if self.slot in self.solitaire.tableau: + if not self.face_up and self == self.slot.get_top_card(): + self.turn_face_up() + elif self.slot == self.solitaire.stock: + self.move_on_top() + self.place(self.solitaire.waste) + self.turn_face_up() +``` + +Now, in `Card` class, create `turn_face_down()` method: +``` +def turn_face_down(self): + """Hides card""" + self.face_up = False + self.content.content.src = "/images/card_back.png" + self.solitaire.update() +``` + +That’s it! Now you can properly play solitaire, but it very difficult to win the game if +you cannot pass though the waste again. Let’s implement `click()` for `on_click` event of +the stock Slot to go thought the stock pile again: +```python +class Slot(ft.Container): + def __init__(self, solitaire, top, left, border): + super().__init__() + self.pile=[] + self.width=SLOT_WIDTH + self.height=SLOT_HEIGHT + self.left=left + self.top=top + self.on_click=self.click + self.solitaire=solitaire + self.border=border + self.border_radius = ft.border_radius.all(6) + + def click(self, e): + if self == self.solitaire.stock: + self.solitaire.restart_stock() +``` + +`restart_stock()` method in `Solitaire` class will place all cards from waste to stock again: +```python +def restart_stock(self): + while len(self.waste.pile) > 0: + card = self.waste.get_top_card() + card.turn_face_down() + card.move_on_top() + card.place(self.stock) +``` + +For `card.place()` method to work properly with cards from Stock and Waste, we’ve added a +condition to `card.get_draggable_pile()`, so that it returns the top card only and not the whole pile: +```python + def get_draggable_pile(self): + """returns list of cards that will be dragged together, starting with the current card""" + + if ( + self.slot is not None + and self.slot != self.solitaire.stock + and self.slot != self.solitaire.waste + ): + self.draggable_pile = self.slot.pile[self.slot.pile.index(self) :] + else: # slot == None when the cards are dealt and need to be place in slot for the first time + self.draggable_pile = [self] +``` +All done! The full source code for this step can be found [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-game-rules). + +Let’s move on to the last step of the game itself - detecting the situation when you have won. + +## Winning the game + +According to [wikipedia](https://en.wikipedia.org/wiki/Klondike_(solitaire)#Probability_of_winning), some suggest the chances of winning the game as being 1 in 30 games. + +Knowing that the chances of winning are quite low, we should plan on showing the user something exciting when that finally happens. + +First, let’s add a check for the winning condition to `Solitaire` class. If all four foundations contain total of 52 cards, then you have won: +```python +def check_win(self): + cards_num = 0 + for slot in self.foundations: + cards_num += len(slot.pile) + if cards_num == 52: + return True + return False +``` + +We’ll be checking if this condition is true each time a card is placed to a foundation: +```python +def place(self, slot): + """Place draggable pile to the slot""" + + for card in self.draggable_pile: + if slot in self.solitaire.tableau: + card.top = slot.top + len(slot.pile) * CARD_OFFSET + else: + card.top = slot.top + card.left = slot.left + + # remove card from it's original slot, if exists + if card.slot is not None: + card.slot.pile.remove(card) + + # change card's slot to a new slot + card.slot = slot + + # add card to the new slot's pile + slot.pile.append(card) + + if self.solitaire.check_win(): + self.solitaire.winning_sequence() + + self.solitaire.update() +``` + +Finally, if the winning condition is met, it will trigger a winning sequence involving [position animation](../cookbook/animations#position-animation): +```python +def winning_sequence(self): + for slot in self.foundations: + for card in slot.pile: + card.animate_position=1000 + card.move_on_top() + card.top = random.randint(0, SOLITAIRE_HEIGHT) + card.left = random.randint(0, SOLITAIRE_WIDTH) + self.update() + self.controls.append(ft.AlertDialog(title=ft.Text("Congratulations! You won!"), open=True)) +``` + +winning_the_game + +Wow! We did it. You can find the full source code for the Solitaire game +[here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/solitaire/solitaire-final-part1). + +Now, as we have a decent desktop version of the game, let’s deploy it as a web app to share with your friends and colleagues. + +## Deploying the app + +Congratulations! You have created your Solitaire game app in Python with Flet, and it looks awesome! + +Now it's time to share your app with the world! + +[Follow these instructions](../publish/web/index.md) to deploy your Flet app as a web app to Fly.io or Replit. + +## Summary + +In this tutorial, you have learnt how to: + +* [Create](../getting-started/create-flet-app.md) a simple Flet app; +* Drag and drop cards with [`GestureDetector`](../controls/gesturedetector.md); +* [Create your own classes](../cookbook/custom-controls.md) that inherit from Flet controls; +* Design UI layout using absolute positioning of controls in [`Stack`](../controls/stack.md); +* Implement [implicit animations](../cookbook/animations.md); +* [Deploy](../publish/web/index.md) your Flet app to the web; + +For further reading you can explore [controls](/docs/controls) and [examples](https://github.com/flet-dev/flet/tree/main/sdk/python/examples). + +We would love to hear your feedback! Please drop us an [email](mailto:hello@flet.dev), join the discussion on [Discord](https://discord.gg/dzWXP8SHG8). diff --git a/website/docs/tutorials/todo.md b/website/docs/tutorials/todo.md new file mode 100644 index 0000000000..b8b9ee2016 --- /dev/null +++ b/website/docs/tutorials/todo.md @@ -0,0 +1,273 @@ +--- +title: "ToDo Tutorial" +examples: "tutorials/todo" +--- + +import {CodeExample, Image} from '@site/src/components/crocodocs'; + +In this tutorial we will show you, step-by-step, how to create a To-Do app in Python +using Flet framework and then publish it as a desktop, mobile or web app. +The app is a single-file console program of just +[164 lines (formatted!) of Python code](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/apps/todo/basic/main.py), +yet it is a multi-platform application with rich, responsive UI: + + + +You can see the live demo [here](https://examples.flet.dev/todo/). + +We chose a To-Do app for the tutorial, because it covers all of the basic concepts you +would need to create a Flet app: building a page layout, adding controls, handling events, +displaying and editing lists, making reusable UI components, and publishing options. + +The tutorial consists of the following steps: + +* [Getting started with Flet](#getting-started-with-flet) +* [Adding page controls and handling events](#adding-page-controls-and-handling-events) +* [View, edit and delete list items](#view-edit-and-delete-list-items) +* [Filtering list items](#filtering-list-items) +* [Final touches](#final-touches) +* [Publishing the app](#publishing-the-app) + +## Getting started with Flet + +To create a multi-platform app in Python with Flet, you don't need to know HTML, +CSS or JavaScript, but you do need a basic knowledge of Python and object-oriented +programming. + +Before you can create your first Flet app, you need to +[setup your development environment](../getting-started/installation.md), which requires Python 3.10 or above and `flet` package. + +Once you have Flet installed, let's [create](../getting-started/create-flet-app.md) a simple hello-world app. + +Create `hello.py` with the following contents: + + + +Run this app and you will see a new window with a greeting: + + + +## Adding page controls and handling events + +To start, we'll need a [`TextField`](../controls/textfield.md) for entering a task name, and "+" +[`FloatingActionButton`](../controls/floatingactionbutton.md) with an event handler that +will display a [`Checkbox`](../controls/checkbox.md) with a new task. + +Create `todo.py` with the following contents: + + + +Run the app and you should see a page like this: + + + +### Page layout + +Now let's make the app look nice! We want the entire app to be at the top +center of the page, taking up 600 px width. The TextField and the "+" +button should be aligned horizontally, and take up full app width: + + + +[`Row`](../controls/row.md) is a control that is used to lay its children controls out horizontally on a page. +[`Column`](../controls/column.md) is a control that is used to lay its children controls out vertically on a page. + +Replace `todo.py` contents with the following: + + + +Run the app and you should see a page like this: + + + +### Reusable UI components + +While we could continue writing our app in the `main` function, the best practice +would be to create a [reusable UI component](../cookbook/custom-controls.md). Imagine you are working on an +app header, a side menu, or UI that will be a part of a larger project. Even if +you can't think of such uses right now, we still recommend creating all your +Flet apps with composability and reusability in mind. + +To make a reusable To-Do app component, we are going to encapsulate its state +and presentation logic in a separate class: + + + +
+Try this out! + +Try adding two `TodoApp` components to the page: + +```python +# create application instance +app1 = TodoApp() +app2 = TodoApp() + +# add application's root control to the page +page.add(app1, app2) +``` +
+ +## View, edit and delete list items + +In the [previous step](#adding-page-controls-and-handling-events), we created a basic To-Do app with task items shown as checkboxes. +Let's improve the app by adding "Edit" and "Delete" buttons next to a task name. +The "Edit" button will switch a task item to edit mode. + + + +Each task item is represented by two rows: `display_view` row with Checkbox, +"Edit" and "Delete" buttons and `edit_view` row with TextField and "Save" button. +`view` column serves as a container for both `display_view` and `edit_view` rows. + +To encapsulate task item views and actions, we introduced a new `Task` class. + +Additionally, we changed `TodoApp` class to create and hold `Task` instances +when the "Add" button is clicked. + +For "Delete" task operation, we implemented `task_delete()` method in `TodoApp` +class which accepts task control instance as a parameter. + +Then, we passed a reference to `task_delete` method into Task constructor and +called it on "Delete" button event handler. + + + +Run the app and try to edit and delete tasks: + + + +## Filtering list items + +We already have a functional To-Do app where we can create, edit, and delete tasks. +To be even more productive, we want to be able to filter tasks by their status. + +Copy the entire code for this step from [here](https://github.com/flet-dev/flet/blob/main/sdk/python/examples/tutorials/todo/todo.py). +Below we will explain the changes we've done to implement filtering. + +`Tabs` control is used to display filter: + +```python title="todo.py" +# ... + +class TodoApp(ft.Column): + # application's root control is a Column containing all other controls + def init(self): + self.new_task = ft.TextField(hint_text="Whats needs to be done?", expand=True) + self.tasks = ft.Column() + + self.filter = ft.TabBar( + scrollable=False, + tabs=[ + ft.Tab(label="all"), + ft.Tab(label="active"), + ft.Tab(label="completed"), + ], + ) + + self.filter_tabs = ft.Tabs( + length=3, + selected_index=0, + on_change=lambda e: self.update(), + content=self.filter, + ) + + # ... +``` + +To display different lists of tasks depending on their statuses, we could maintain +three lists with "All", "Active" and "Completed" tasks. We, however, chose an easier +approach where we maintain the same list and only change a task's visibility depending on its status. + +In `TodoApp` class we overrode [`before_update()`](../cookbook/custom-controls.md#before_update) method called every time when +the control is being updated. It iterates through all the tasks and updates their +`visible` property depending on the status of the task: + +```python title="todo.py" +class TodoApp(ft.Column): + + # ... + + def before_update(self): + status = self.filter.tabs[self.filter.selected_index].text + for task in self.tasks.controls: + task.visible = ( + status == "all" + or (status == "active" and task.completed == False) + or (status == "completed" and task.completed) + ) +``` + +Filtering should occur when we click on a tab or change a task status. +`TodoApp.before_update()` method is called when Tabs selected value is changed +or Task item checkbox is clicked: + +```python title="todo.py" +class TodoApp(ft.Column): + + # ... + + def tabs_changed(self, e): + self.update() + + def task_status_change(self, e): + self.update() + + def add_clicked(self, e): + task = Task( + task_name=self.new_task.value, + on_status_change=self.task_status_change, + on_delete=self.task_delete, + ) + self.tasks.controls.append(task) + self.new_task.value = "" + self.update() + # ... + +class Task(ft.Column): + task_name: str = "" + on_status_change: Callable[[], None] = field(default=lambda: None) + on_delete: Callable[["Task"], None] = field(default=lambda task: None) + + # ... + + def status_changed(self, e): + self.completed = self.display_task.value + self.task_status_change() +``` + +Run the app and try filtering tasks by clicking on the tabs: + + + +## Final touches + +Our Todo app is almost complete now. As a final touch, we will add a footer (`Column` control) displaying the number of incomplete tasks (`Text` control) and a "Clear completed" button. + +
+Full code + + +
+ +app-4 + +## Publishing the app + +Congratulations! You have created your first Python app with Flet, and it looks awesome! + +Now it's time to share your app with the world! + +[Follow these instructions](../publish/index.md) to publish your Flet app as a mobile, desktop or web app. + +## Summary + +In this tutorial, you have learnt how to: + +* Create a simple Flet app; +* Work with [Reusable UI components](../cookbook/custom-controls.md); +* Design UI layout using [`Column`](../controls/column.md) and [`Row`](../controls/row.md) controls; +* Work with lists: view, edit and delete items, filtering; +* [Publish](../publish/index.md) your Flet app to multiple platforms; + +For further reading you can explore [controls](/docs/controls) and [examples](https://github.com/flet-dev/flet/tree/main/sdk/python/examples). diff --git a/website/docs/types/accelerometerreadingevent.md b/website/docs/types/accelerometerreadingevent.md new file mode 100644 index 0000000000..9b0f114a60 --- /dev/null +++ b/website/docs/types/accelerometerreadingevent.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.AccelerometerReadingEvent" +title: "AccelerometerReadingEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/aliases.md b/website/docs/types/aliases.md new file mode 100644 index 0000000000..dae91afc13 --- /dev/null +++ b/website/docs/types/aliases.md @@ -0,0 +1,34 @@ +--- +title: "Aliases" +--- + +import {ClassSummary} from '@site/src/components/crocodocs'; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/docs/types/alignment.md b/website/docs/types/alignment.md new file mode 100644 index 0000000000..a6163ea06f --- /dev/null +++ b/website/docs/types/alignment.md @@ -0,0 +1,17 @@ +--- +examples: "controls/core/types/alignment" +example_media: "examples/controls/core/types/alignment/media" +title: "Alignment" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + + diff --git a/website/docs/types/androidbuildversion.md b/website/docs/types/androidbuildversion.md new file mode 100644 index 0000000000..8a4c7ddbc0 --- /dev/null +++ b/website/docs/types/androidbuildversion.md @@ -0,0 +1,7 @@ +--- +title: "AndroidBuildVersion" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/androiddeviceinfo.md b/website/docs/types/androiddeviceinfo.md new file mode 100644 index 0000000000..6a535210ee --- /dev/null +++ b/website/docs/types/androiddeviceinfo.md @@ -0,0 +1,7 @@ +--- +title: "AndroidDeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/animatedswitchertransition.md b/website/docs/types/animatedswitchertransition.md new file mode 100644 index 0000000000..bfd9a8094b --- /dev/null +++ b/website/docs/types/animatedswitchertransition.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.AnimatedSwitcherTransition" +examples: "controls/core/types/animated_switcher_transition" +title: "AnimatedSwitcherTransition" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/animation.md b/website/docs/types/animation.md new file mode 100644 index 0000000000..71cf41b724 --- /dev/null +++ b/website/docs/types/animation.md @@ -0,0 +1,7 @@ +--- +title: "Animation" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/animationcurve.md b/website/docs/types/animationcurve.md new file mode 100644 index 0000000000..80ce999868 --- /dev/null +++ b/website/docs/types/animationcurve.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.AnimationCurve" +examples: "controls/core/types/animation_curve" +title: "AnimationCurve" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/animationstyle.md b/website/docs/types/animationstyle.md new file mode 100644 index 0000000000..0ee14f0f25 --- /dev/null +++ b/website/docs/types/animationstyle.md @@ -0,0 +1,7 @@ +--- +title: "AnimationStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/appbartheme.md b/website/docs/types/appbartheme.md new file mode 100644 index 0000000000..8453d338e9 --- /dev/null +++ b/website/docs/types/appbartheme.md @@ -0,0 +1,7 @@ +--- +title: "AppBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/applifecyclestate.md b/website/docs/types/applifecyclestate.md new file mode 100644 index 0000000000..556ab0dab6 --- /dev/null +++ b/website/docs/types/applifecyclestate.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.AppLifecycleState" +examples: "controls/core/types/app_lifecycle_state" +title: "AppLifecycleState" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/applifecyclestatechangeevent.md b/website/docs/types/applifecyclestatechangeevent.md new file mode 100644 index 0000000000..555d5e4e4a --- /dev/null +++ b/website/docs/types/applifecyclestatechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "AppLifecycleStateChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/appview.md b/website/docs/types/appview.md new file mode 100644 index 0000000000..a319d46a96 --- /dev/null +++ b/website/docs/types/appview.md @@ -0,0 +1,7 @@ +--- +title: "AppView" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/assertiveness.md b/website/docs/types/assertiveness.md new file mode 100644 index 0000000000..c72d579069 --- /dev/null +++ b/website/docs/types/assertiveness.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.Assertiveness" +examples: "controls/core/types/assertiveness" +title: "Assertiveness" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/auth/auth0oauthprovider.md b/website/docs/types/auth/auth0oauthprovider.md new file mode 100644 index 0000000000..aa914fd24e --- /dev/null +++ b/website/docs/types/auth/auth0oauthprovider.md @@ -0,0 +1,7 @@ +--- +title: "Auth0OAuthProvider" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/authorization.md b/website/docs/types/auth/authorization.md new file mode 100644 index 0000000000..ad0b135bc2 --- /dev/null +++ b/website/docs/types/auth/authorization.md @@ -0,0 +1,7 @@ +--- +title: "Authorization" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/authorizationservice.md b/website/docs/types/auth/authorizationservice.md new file mode 100644 index 0000000000..066c30376e --- /dev/null +++ b/website/docs/types/auth/authorizationservice.md @@ -0,0 +1,7 @@ +--- +title: "AuthorizationService" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/azureoauthprovider.md b/website/docs/types/auth/azureoauthprovider.md new file mode 100644 index 0000000000..cd60f7fc06 --- /dev/null +++ b/website/docs/types/auth/azureoauthprovider.md @@ -0,0 +1,7 @@ +--- +title: "AzureOAuthProvider" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/githuboauthprovider.md b/website/docs/types/auth/githuboauthprovider.md new file mode 100644 index 0000000000..70197e5ad6 --- /dev/null +++ b/website/docs/types/auth/githuboauthprovider.md @@ -0,0 +1,7 @@ +--- +title: "GitHubOAuthProvider" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/googleoauthprovider.md b/website/docs/types/auth/googleoauthprovider.md new file mode 100644 index 0000000000..d42cd7e81f --- /dev/null +++ b/website/docs/types/auth/googleoauthprovider.md @@ -0,0 +1,7 @@ +--- +title: "GoogleOAuthProvider" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/group.md b/website/docs/types/auth/group.md new file mode 100644 index 0000000000..f00b4d071a --- /dev/null +++ b/website/docs/types/auth/group.md @@ -0,0 +1,7 @@ +--- +title: "Group" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/oauthprovider/index.md b/website/docs/types/auth/oauthprovider/index.md new file mode 100644 index 0000000000..3dcc201b8c --- /dev/null +++ b/website/docs/types/auth/oauthprovider/index.md @@ -0,0 +1,7 @@ +--- +title: "OAuthProvider" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/oauthtoken.md b/website/docs/types/auth/oauthtoken.md new file mode 100644 index 0000000000..1a6fcf21ef --- /dev/null +++ b/website/docs/types/auth/oauthtoken.md @@ -0,0 +1,7 @@ +--- +title: "OAuthToken" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/auth/user.md b/website/docs/types/auth/user.md new file mode 100644 index 0000000000..25856c7b91 --- /dev/null +++ b/website/docs/types/auth/user.md @@ -0,0 +1,7 @@ +--- +title: "User" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/autocompleteselectevent.md b/website/docs/types/autocompleteselectevent.md new file mode 100644 index 0000000000..f503d3b2e0 --- /dev/null +++ b/website/docs/types/autocompleteselectevent.md @@ -0,0 +1,7 @@ +--- +title: "AutoCompleteSelectEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/autocompletesuggestion.md b/website/docs/types/autocompletesuggestion.md new file mode 100644 index 0000000000..488254d02e --- /dev/null +++ b/website/docs/types/autocompletesuggestion.md @@ -0,0 +1,7 @@ +--- +title: "AutoCompleteSuggestion" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/autofillgroupdisposeaction.md b/website/docs/types/autofillgroupdisposeaction.md new file mode 100644 index 0000000000..4b523f4dbf --- /dev/null +++ b/website/docs/types/autofillgroupdisposeaction.md @@ -0,0 +1,7 @@ +--- +title: "AutoFillGroupDisposeAction" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/autofillhint.md b/website/docs/types/autofillhint.md new file mode 100644 index 0000000000..53e64c0378 --- /dev/null +++ b/website/docs/types/autofillhint.md @@ -0,0 +1,7 @@ +--- +title: "AutoFillHint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/automaticnotchshape.md b/website/docs/types/automaticnotchshape.md new file mode 100644 index 0000000000..12edee140d --- /dev/null +++ b/website/docs/types/automaticnotchshape.md @@ -0,0 +1,7 @@ +--- +title: "AutomaticNotchShape" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/axis.md b/website/docs/types/axis.md new file mode 100644 index 0000000000..a65783f2c3 --- /dev/null +++ b/website/docs/types/axis.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.Axis" +examples: "controls/core/types/axis" +title: "Axis" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/badge.md b/website/docs/types/badge.md new file mode 100644 index 0000000000..230de0975f --- /dev/null +++ b/website/docs/types/badge.md @@ -0,0 +1,22 @@ +--- +class_name: "flet.Badge" +examples: "controls/material/badge" +example_images: "test-images/examples/controls/material/golden/macos/badge" +title: "Badge" +--- + +import {ClassMembers, ClassSummary, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +[Live example](https://flet-controls-gallery.fly.dev/displays/badge) + +### Badge decorating an icon on a NavigationBar + + + + + + diff --git a/website/docs/types/badgetheme.md b/website/docs/types/badgetheme.md new file mode 100644 index 0000000000..da0c6494d5 --- /dev/null +++ b/website/docs/types/badgetheme.md @@ -0,0 +1,7 @@ +--- +title: "BadgeTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/bannertheme.md b/website/docs/types/bannertheme.md new file mode 100644 index 0000000000..8072277361 --- /dev/null +++ b/website/docs/types/bannertheme.md @@ -0,0 +1,7 @@ +--- +title: "BannerTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/barometerreadingevent.md b/website/docs/types/barometerreadingevent.md new file mode 100644 index 0000000000..9b6c7e377f --- /dev/null +++ b/website/docs/types/barometerreadingevent.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.BarometerReadingEvent" +title: "BarometerReadingEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/batterystate.md b/website/docs/types/batterystate.md new file mode 100644 index 0000000000..e621bd13fd --- /dev/null +++ b/website/docs/types/batterystate.md @@ -0,0 +1,7 @@ +--- +title: "BatteryState" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/batterystatechangeevent.md b/website/docs/types/batterystatechangeevent.md new file mode 100644 index 0000000000..841835a485 --- /dev/null +++ b/website/docs/types/batterystatechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "BatteryStateChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/beveledrectangleborder.md b/website/docs/types/beveledrectangleborder.md new file mode 100644 index 0000000000..e3ca002216 --- /dev/null +++ b/website/docs/types/beveledrectangleborder.md @@ -0,0 +1,7 @@ +--- +title: "BeveledRectangleBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/blendmode.md b/website/docs/types/blendmode.md new file mode 100644 index 0000000000..3cd941464e --- /dev/null +++ b/website/docs/types/blendmode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BlendMode" +examples: "controls/core/types/blend_mode" +title: "BlendMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/blur.md b/website/docs/types/blur.md new file mode 100644 index 0000000000..e88bf07680 --- /dev/null +++ b/website/docs/types/blur.md @@ -0,0 +1,15 @@ +--- +title: "Blur" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + +container diff --git a/website/docs/types/blurstyle.md b/website/docs/types/blurstyle.md new file mode 100644 index 0000000000..60f7a7cd6b --- /dev/null +++ b/website/docs/types/blurstyle.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BlurStyle" +examples: "controls/core/types/blur_style" +title: "BlurStyle" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/blurtilemode.md b/website/docs/types/blurtilemode.md new file mode 100644 index 0000000000..d912193195 --- /dev/null +++ b/website/docs/types/blurtilemode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BlurTileMode" +examples: "controls/core/types/blur_tile_mode" +title: "BlurTileMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/border.md b/website/docs/types/border.md new file mode 100644 index 0000000000..02cb310535 --- /dev/null +++ b/website/docs/types/border.md @@ -0,0 +1,13 @@ +--- +title: "Border" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + diff --git a/website/docs/types/borderradius.md b/website/docs/types/borderradius.md new file mode 100644 index 0000000000..6dd90e71a2 --- /dev/null +++ b/website/docs/types/borderradius.md @@ -0,0 +1,13 @@ +--- +title: "BorderRadius" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage example + +```python +container_1.border_radius= ft.BorderRadius.all(30) +``` diff --git a/website/docs/types/borderside.md b/website/docs/types/borderside.md new file mode 100644 index 0000000000..d2cfd0ee45 --- /dev/null +++ b/website/docs/types/borderside.md @@ -0,0 +1,7 @@ +--- +title: "BorderSide" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/bordersidestrokealign.md b/website/docs/types/bordersidestrokealign.md new file mode 100644 index 0000000000..4db62b4a42 --- /dev/null +++ b/website/docs/types/bordersidestrokealign.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BorderSideStrokeAlign" +examples: "controls/core/types/border_side_stroke_align" +title: "BorderSideStrokeAlign" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/borderstyle.md b/website/docs/types/borderstyle.md new file mode 100644 index 0000000000..7014a35447 --- /dev/null +++ b/website/docs/types/borderstyle.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BorderStyle" +examples: "controls/core/types/border_style" +title: "BorderStyle" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/bottomappbartheme.md b/website/docs/types/bottomappbartheme.md new file mode 100644 index 0000000000..e2b6b97c2e --- /dev/null +++ b/website/docs/types/bottomappbartheme.md @@ -0,0 +1,7 @@ +--- +title: "BottomAppBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/bottomsheettheme.md b/website/docs/types/bottomsheettheme.md new file mode 100644 index 0000000000..69bb49e449 --- /dev/null +++ b/website/docs/types/bottomsheettheme.md @@ -0,0 +1,7 @@ +--- +title: "BottomSheetTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/boxconstraints.md b/website/docs/types/boxconstraints.md new file mode 100644 index 0000000000..5210ee5117 --- /dev/null +++ b/website/docs/types/boxconstraints.md @@ -0,0 +1,7 @@ +--- +title: "BoxConstraints" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/boxdecoration.md b/website/docs/types/boxdecoration.md new file mode 100644 index 0000000000..828650731e --- /dev/null +++ b/website/docs/types/boxdecoration.md @@ -0,0 +1,7 @@ +--- +title: "BoxDecoration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/boxfit.md b/website/docs/types/boxfit.md new file mode 100644 index 0000000000..d706d7e008 --- /dev/null +++ b/website/docs/types/boxfit.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BoxFit" +examples: "controls/core/types/box_fit" +title: "BoxFit" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/boxshadow.md b/website/docs/types/boxshadow.md new file mode 100644 index 0000000000..02181eb76f --- /dev/null +++ b/website/docs/types/boxshadow.md @@ -0,0 +1,13 @@ +--- +title: "BoxShadow" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + diff --git a/website/docs/types/boxshape.md b/website/docs/types/boxshape.md new file mode 100644 index 0000000000..b7c58940ea --- /dev/null +++ b/website/docs/types/boxshape.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.BoxShape" +examples: "controls/core/types/box_shape" +title: "BoxShape" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/brightness.md b/website/docs/types/brightness.md new file mode 100644 index 0000000000..f28630204d --- /dev/null +++ b/website/docs/types/brightness.md @@ -0,0 +1,7 @@ +--- +title: "Brightness" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/browserconfiguration.md b/website/docs/types/browserconfiguration.md new file mode 100644 index 0000000000..482b667615 --- /dev/null +++ b/website/docs/types/browserconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "BrowserConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/buttonstyle.md b/website/docs/types/buttonstyle.md new file mode 100644 index 0000000000..eee6a0b392 --- /dev/null +++ b/website/docs/types/buttonstyle.md @@ -0,0 +1,115 @@ +--- +title: "ButtonStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage example + +You can configure a different shape, background color for a hovered state and configure fallback values for all other states. + +To configure style attribute for all Material states set its value to a literal (or class instance). For example, if you set `color` property to a literal the value will be applied to all button states: + +```python +ButtonStyle( + color=ft.Colors.WHITE +) +``` + +To configure style attribute for specific Material states set its value to a dictionary where the key is state name. For example, to configure different background colors for `HOVERED` and `FOCUSED` states and another colors for all other states: + +```python +ButtonStyle( + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + } +) +``` + +### Various button shapes example + + + +```python +import flet as ft + +def main(page: ft.Page): + page.padding = 30 + page.spacing = 30 + page.add( + ft.FilledButton( + "Stadium", + style=ft.ButtonStyle( + shape=ft.StadiumBorder(), + ), + ), + ft.FilledButton( + "Rounded rectangle", + style=ft.ButtonStyle( + shape=ft.RoundedRectangleBorder(radius=10), + ), + ), + ft.FilledButton( + "Continuous rectangle", + style=ft.ButtonStyle( + shape=ft.ContinuousRectangleBorder(radius=30), + ), + ), + ft.FilledButton( + "Beveled rectangle", + style=ft.ButtonStyle( + shape=ft.BeveledRectangleBorder(radius=10), + ), + ), + ft.FilledButton( + "Circle", + style=ft.ButtonStyle(shape=ft.CircleBorder(), padding=30), + ), + ) + +ft.run(main) +``` + +### Styled button example + +Check the following example: + + + +```python +import flet as ft + +def main(page: ft.Page): + + page.add( + ft.Button( + "Styled button 1", + style=ft.ButtonStyle( + color={ + ft.ControlState.HOVERED: ft.Colors.WHITE, + ft.ControlState.FOCUSED: ft.Colors.BLUE, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + }, + bgcolor={ft.ControlState.FOCUSED: ft.Colors.PINK_200, "": ft.Colors.YELLOW}, + padding={ft.ControlState.HOVERED: 20}, + overlay_color=ft.Colors.TRANSPARENT, + elevation={"pressed": 0, "": 1}, + animation_duration=500, + side={ + ft.ControlState.DEFAULT: ft.BorderSide(1, ft.Colors.BLUE), + ft.ControlState.HOVERED: ft.BorderSide(2, ft.Colors.BLUE), + }, + shape={ + ft.ControlState.HOVERED: ft.RoundedRectangleBorder(radius=20), + ft.ControlState.DEFAULT: ft.RoundedRectangleBorder(radius=2), + }, + ), + ) + ) + +ft.run(main) +``` diff --git a/website/docs/types/buttontheme.md b/website/docs/types/buttontheme.md new file mode 100644 index 0000000000..c0c7cbe6a4 --- /dev/null +++ b/website/docs/types/buttontheme.md @@ -0,0 +1,7 @@ +--- +title: "ButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/canvasresizeevent.md b/website/docs/types/canvasresizeevent.md new file mode 100644 index 0000000000..af1a9162d8 --- /dev/null +++ b/website/docs/types/canvasresizeevent.md @@ -0,0 +1,7 @@ +--- +title: "CanvasResizeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/cardtheme.md b/website/docs/types/cardtheme.md new file mode 100644 index 0000000000..f145087096 --- /dev/null +++ b/website/docs/types/cardtheme.md @@ -0,0 +1,7 @@ +--- +title: "CardTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/cardvariant.md b/website/docs/types/cardvariant.md new file mode 100644 index 0000000000..9ed6f37eec --- /dev/null +++ b/website/docs/types/cardvariant.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.CardVariant" +examples: "controls/core/types/card_variant" +title: "CardVariant" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/checkboxtheme.md b/website/docs/types/checkboxtheme.md new file mode 100644 index 0000000000..6aeb510842 --- /dev/null +++ b/website/docs/types/checkboxtheme.md @@ -0,0 +1,7 @@ +--- +title: "CheckboxTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/chiptheme.md b/website/docs/types/chiptheme.md new file mode 100644 index 0000000000..b44e12f90c --- /dev/null +++ b/website/docs/types/chiptheme.md @@ -0,0 +1,7 @@ +--- +title: "ChipTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/circleborder.md b/website/docs/types/circleborder.md new file mode 100644 index 0000000000..1acaf4825d --- /dev/null +++ b/website/docs/types/circleborder.md @@ -0,0 +1,7 @@ +--- +title: "CircleBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/circularrectanglenotchshape.md b/website/docs/types/circularrectanglenotchshape.md new file mode 100644 index 0000000000..534f8892fd --- /dev/null +++ b/website/docs/types/circularrectanglenotchshape.md @@ -0,0 +1,7 @@ +--- +title: "CircularRectangleNotchShape" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/clipbehavior.md b/website/docs/types/clipbehavior.md new file mode 100644 index 0000000000..87f8deec34 --- /dev/null +++ b/website/docs/types/clipbehavior.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ClipBehavior" +examples: "controls/core/types/clip_behavior" +title: "ClipBehavior" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/colorfilter.md b/website/docs/types/colorfilter.md new file mode 100644 index 0000000000..68edcdd8d2 --- /dev/null +++ b/website/docs/types/colorfilter.md @@ -0,0 +1,7 @@ +--- +title: "ColorFilter" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/colors.md b/website/docs/types/colors.md new file mode 100644 index 0000000000..bbb71a41e8 --- /dev/null +++ b/website/docs/types/colors.md @@ -0,0 +1,9 @@ +--- +hide: + - "toc" +title: "Colors" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/colorscheme.md b/website/docs/types/colorscheme.md new file mode 100644 index 0000000000..d8bf50867d --- /dev/null +++ b/website/docs/types/colorscheme.md @@ -0,0 +1,7 @@ +--- +title: "ColorScheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/component.md b/website/docs/types/component.md new file mode 100644 index 0000000000..f2547fa3c5 --- /dev/null +++ b/website/docs/types/component.md @@ -0,0 +1,9 @@ +--- +title: "component" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +# \@component + + diff --git a/website/docs/types/connectivitychangeevent.md b/website/docs/types/connectivitychangeevent.md new file mode 100644 index 0000000000..1d8d70c330 --- /dev/null +++ b/website/docs/types/connectivitychangeevent.md @@ -0,0 +1,7 @@ +--- +title: "ConnectivityChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/connectivitytype.md b/website/docs/types/connectivitytype.md new file mode 100644 index 0000000000..08ef345538 --- /dev/null +++ b/website/docs/types/connectivitytype.md @@ -0,0 +1,7 @@ +--- +title: "ConnectivityType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/context.md b/website/docs/types/context.md new file mode 100644 index 0000000000..ef5c80e5c2 --- /dev/null +++ b/website/docs/types/context.md @@ -0,0 +1,7 @@ +--- +title: "Context" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/contextmenudismissevent.md b/website/docs/types/contextmenudismissevent.md new file mode 100644 index 0000000000..0767d0fe09 --- /dev/null +++ b/website/docs/types/contextmenudismissevent.md @@ -0,0 +1,7 @@ +--- +title: "ContextMenuDismissEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/contextmenuselectevent.md b/website/docs/types/contextmenuselectevent.md new file mode 100644 index 0000000000..1ba71328c3 --- /dev/null +++ b/website/docs/types/contextmenuselectevent.md @@ -0,0 +1,7 @@ +--- +title: "ContextMenuSelectEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/contextmenutrigger.md b/website/docs/types/contextmenutrigger.md new file mode 100644 index 0000000000..9c21a6dea7 --- /dev/null +++ b/website/docs/types/contextmenutrigger.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ContextMenuTrigger" +examples: "controls/core/types/context_menu_trigger" +title: "ContextMenuTrigger" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/continuousrectangleborder.md b/website/docs/types/continuousrectangleborder.md new file mode 100644 index 0000000000..271ed1a588 --- /dev/null +++ b/website/docs/types/continuousrectangleborder.md @@ -0,0 +1,7 @@ +--- +title: "ContinuousRectangleBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/control.md b/website/docs/types/control.md new file mode 100644 index 0000000000..fb09e381e2 --- /dev/null +++ b/website/docs/types/control.md @@ -0,0 +1,9 @@ +--- +title: "control" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +# \@control + + diff --git a/website/docs/types/controlstate.md b/website/docs/types/controlstate.md new file mode 100644 index 0000000000..1bcf9815b4 --- /dev/null +++ b/website/docs/types/controlstate.md @@ -0,0 +1,47 @@ +--- +title: "ControlState" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage Example + +Configuring `fill_color` can be done in two ways: + +### 1. Single Value for All States + +If you want to use the same color across all Material states, simply assign `fill_color` to a single color: + +```python +ft.Radio(fill_color=ft.Colors.GREEN) +``` + +### 2. Specific Values for Each State + +For more control, you can provide a dictionary where the key is the state name and the value is the corresponding color. + +#### **Ordering Matters** + +- The order in which states appear in the dictionary will determine their priority, allowing for flexibility and + customization. +- The position of `DEFAULT` does not affect behavior—it always has the least priority and can be placed anywhere in the + dictionary. + +#### **Example** + +To configure different fill colors of a [`Radio`](../controls/radio.md) button for `ControlState.HOVERED` and +`ControlState.FOCUSED`, with a fallback color for all other states: + +```python +ft.Radio( + fill_color={ + ft.ControlState.HOVERED: ft.Colors.GREEN, + ft.ControlState.FOCUSED: ft.Colors.RED, + ft.ControlState.DEFAULT: ft.Colors.BLACK, + } +) +``` + +This setup ensures that `HOVERED` and `FOCUSED` states take precedence, while all unspecified states default to `BLACK`. diff --git a/website/docs/types/createcontext.md b/website/docs/types/createcontext.md new file mode 100644 index 0000000000..0094bd15d9 --- /dev/null +++ b/website/docs/types/createcontext.md @@ -0,0 +1,7 @@ +--- +title: "create_context" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/crossaxisalignment.md b/website/docs/types/crossaxisalignment.md new file mode 100644 index 0000000000..d37c4e03ac --- /dev/null +++ b/website/docs/types/crossaxisalignment.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.CrossAxisAlignment" +examples: "controls/core/types/cross_axis_alignment" +title: "CrossAxisAlignment" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/cupertinobuttonsize.md b/website/docs/types/cupertinobuttonsize.md new file mode 100644 index 0000000000..c03b70e5fd --- /dev/null +++ b/website/docs/types/cupertinobuttonsize.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.CupertinoButtonSize" +examples: "controls/core/types/cupertino_button_size" +title: "CupertinoButtonSize" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/cupertinocolors.md b/website/docs/types/cupertinocolors.md new file mode 100644 index 0000000000..6f179bedc4 --- /dev/null +++ b/website/docs/types/cupertinocolors.md @@ -0,0 +1,9 @@ +--- +hide: + - "toc" +title: "CupertinoColors" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/cupertinodatepickerdateorder.md b/website/docs/types/cupertinodatepickerdateorder.md new file mode 100644 index 0000000000..5dd29f6592 --- /dev/null +++ b/website/docs/types/cupertinodatepickerdateorder.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.CupertinoDatePickerDateOrder" +examples: "controls/core/types/cupertino_date_picker_date_order" +title: "CupertinoDatePickerDateOrder" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/cupertinodatepickermode.md b/website/docs/types/cupertinodatepickermode.md new file mode 100644 index 0000000000..9c9952860a --- /dev/null +++ b/website/docs/types/cupertinodatepickermode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.CupertinoDatePickerMode" +examples: "controls/core/types/cupertino_date_picker_mode" +title: "CupertinoDatePickerMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/cupertinoicons.md b/website/docs/types/cupertinoicons.md new file mode 100644 index 0000000000..d6b86d0b92 --- /dev/null +++ b/website/docs/types/cupertinoicons.md @@ -0,0 +1,9 @@ +--- +hide: + - "toc" +title: "CupertinoIcons" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/cupertinotimerpickermode.md b/website/docs/types/cupertinotimerpickermode.md new file mode 100644 index 0000000000..d43dfbb406 --- /dev/null +++ b/website/docs/types/cupertinotimerpickermode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.CupertinoTimerPickerMode" +examples: "controls/core/types/cupertino_timer_picker_mode" +title: "CupertinoTimerPickerMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/datacolumnsortevent.md b/website/docs/types/datacolumnsortevent.md new file mode 100644 index 0000000000..bafe83e929 --- /dev/null +++ b/website/docs/types/datacolumnsortevent.md @@ -0,0 +1,7 @@ +--- +title: "DataColumnSortEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/datatabletheme.md b/website/docs/types/datatabletheme.md new file mode 100644 index 0000000000..0bc03b8ff0 --- /dev/null +++ b/website/docs/types/datatabletheme.md @@ -0,0 +1,7 @@ +--- +title: "DataTableTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/datepickerentrymode.md b/website/docs/types/datepickerentrymode.md new file mode 100644 index 0000000000..7ca12bf60e --- /dev/null +++ b/website/docs/types/datepickerentrymode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.DatePickerEntryMode" +examples: "controls/core/types/date_picker_entry_mode" +title: "DatePickerEntryMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/datepickerentrymodechangeevent.md b/website/docs/types/datepickerentrymodechangeevent.md new file mode 100644 index 0000000000..100b04d9ce --- /dev/null +++ b/website/docs/types/datepickerentrymodechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "DatePickerEntryModeChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/datepickermode.md b/website/docs/types/datepickermode.md new file mode 100644 index 0000000000..67b681826d --- /dev/null +++ b/website/docs/types/datepickermode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.DatePickerMode" +examples: "controls/core/types/date_picker_mode" +title: "DatePickerMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/datepickertheme.md b/website/docs/types/datepickertheme.md new file mode 100644 index 0000000000..eccba25a34 --- /dev/null +++ b/website/docs/types/datepickertheme.md @@ -0,0 +1,7 @@ +--- +title: "DatePickerTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/decorationimage.md b/website/docs/types/decorationimage.md new file mode 100644 index 0000000000..326d4a44f8 --- /dev/null +++ b/website/docs/types/decorationimage.md @@ -0,0 +1,7 @@ +--- +title: "DecorationImage" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/deviceinfo/index.md b/website/docs/types/deviceinfo/index.md new file mode 100644 index 0000000000..6a67f48b2f --- /dev/null +++ b/website/docs/types/deviceinfo/index.md @@ -0,0 +1,7 @@ +--- +title: "DeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/deviceorientation.md b/website/docs/types/deviceorientation.md new file mode 100644 index 0000000000..3f18c9dd56 --- /dev/null +++ b/website/docs/types/deviceorientation.md @@ -0,0 +1,18 @@ +--- +class_name: "flet.DeviceOrientation" +title: "DeviceOrientation" +--- + +import {ClassMembers, ClassSummary} from '@site/src/components/crocodocs'; + + + +## Examples + +### Mobile device orientation configuration + +See the [Page mobile device orientation example](../controls/page.md#mobile-device-orientation-configuration), +which demonstrates how to use [`DeviceOrientation`](deviceorientation.md) +with [`Page.set_allowed_device_orientations()`](../controls/page.md#flet.Page.set_allowed_device_orientations). + + diff --git a/website/docs/types/dialogtheme.md b/website/docs/types/dialogtheme.md new file mode 100644 index 0000000000..d1adf1d15f --- /dev/null +++ b/website/docs/types/dialogtheme.md @@ -0,0 +1,7 @@ +--- +title: "DialogTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dismissdirection.md b/website/docs/types/dismissdirection.md new file mode 100644 index 0000000000..8e769363e5 --- /dev/null +++ b/website/docs/types/dismissdirection.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.DismissDirection" +examples: "controls/core/types/dismiss_direction" +title: "DismissDirection" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/dismissibledismissevent.md b/website/docs/types/dismissibledismissevent.md new file mode 100644 index 0000000000..a0fe043c07 --- /dev/null +++ b/website/docs/types/dismissibledismissevent.md @@ -0,0 +1,7 @@ +--- +title: "DismissibleDismissEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dismissibleupdateevent.md b/website/docs/types/dismissibleupdateevent.md new file mode 100644 index 0000000000..64ca764dfb --- /dev/null +++ b/website/docs/types/dismissibleupdateevent.md @@ -0,0 +1,7 @@ +--- +title: "DismissibleUpdateEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dividertheme.md b/website/docs/types/dividertheme.md new file mode 100644 index 0000000000..6eed1139f0 --- /dev/null +++ b/website/docs/types/dividertheme.md @@ -0,0 +1,7 @@ +--- +title: "DividerTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dragendevent.md b/website/docs/types/dragendevent.md new file mode 100644 index 0000000000..448720ca71 --- /dev/null +++ b/website/docs/types/dragendevent.md @@ -0,0 +1,7 @@ +--- +title: "DragEndEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dragstartevent.md b/website/docs/types/dragstartevent.md new file mode 100644 index 0000000000..2edd1f39d2 --- /dev/null +++ b/website/docs/types/dragstartevent.md @@ -0,0 +1,7 @@ +--- +title: "DragStartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dragtargetevent.md b/website/docs/types/dragtargetevent.md new file mode 100644 index 0000000000..1469e4495a --- /dev/null +++ b/website/docs/types/dragtargetevent.md @@ -0,0 +1,7 @@ +--- +title: "DragTargetEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dragtargetleaveevent.md b/website/docs/types/dragtargetleaveevent.md new file mode 100644 index 0000000000..606f221485 --- /dev/null +++ b/website/docs/types/dragtargetleaveevent.md @@ -0,0 +1,7 @@ +--- +title: "DragTargetLeaveEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dragupdateevent.md b/website/docs/types/dragupdateevent.md new file mode 100644 index 0000000000..e8ac7eaf26 --- /dev/null +++ b/website/docs/types/dragupdateevent.md @@ -0,0 +1,7 @@ +--- +title: "DragUpdateEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dragwillacceptevent.md b/website/docs/types/dragwillacceptevent.md new file mode 100644 index 0000000000..f49c2a2b15 --- /dev/null +++ b/website/docs/types/dragwillacceptevent.md @@ -0,0 +1,7 @@ +--- +title: "DragWillAcceptEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/dropdowntheme.md b/website/docs/types/dropdowntheme.md new file mode 100644 index 0000000000..8182f190a6 --- /dev/null +++ b/website/docs/types/dropdowntheme.md @@ -0,0 +1,7 @@ +--- +title: "DropdownTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/duration.md b/website/docs/types/duration.md new file mode 100644 index 0000000000..8c717eba55 --- /dev/null +++ b/website/docs/types/duration.md @@ -0,0 +1,7 @@ +--- +title: "Duration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/event.md b/website/docs/types/event.md new file mode 100644 index 0000000000..c0aeb8b55e --- /dev/null +++ b/website/docs/types/event.md @@ -0,0 +1,7 @@ +--- +title: "Event" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/expansionpanellistchangeevent.md b/website/docs/types/expansionpanellistchangeevent.md new file mode 100644 index 0000000000..7cc0dd0d1d --- /dev/null +++ b/website/docs/types/expansionpanellistchangeevent.md @@ -0,0 +1,7 @@ +--- +title: "ExpansionPanelListChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/expansiontiletheme.md b/website/docs/types/expansiontiletheme.md new file mode 100644 index 0000000000..d4455882b5 --- /dev/null +++ b/website/docs/types/expansiontiletheme.md @@ -0,0 +1,7 @@ +--- +title: "ExpansionTileTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/filepickerfile.md b/website/docs/types/filepickerfile.md new file mode 100644 index 0000000000..3816d5e03e --- /dev/null +++ b/website/docs/types/filepickerfile.md @@ -0,0 +1,7 @@ +--- +title: "FilePickerFile" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/filepickerfiletype.md b/website/docs/types/filepickerfiletype.md new file mode 100644 index 0000000000..adfd0ba1fc --- /dev/null +++ b/website/docs/types/filepickerfiletype.md @@ -0,0 +1,7 @@ +--- +title: "FilePickerFileType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/filepickeruploadevent.md b/website/docs/types/filepickeruploadevent.md new file mode 100644 index 0000000000..c077a179fd --- /dev/null +++ b/website/docs/types/filepickeruploadevent.md @@ -0,0 +1,7 @@ +--- +title: "FilePickerUploadEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/filepickeruploadfile.md b/website/docs/types/filepickeruploadfile.md new file mode 100644 index 0000000000..e7044cb8d0 --- /dev/null +++ b/website/docs/types/filepickeruploadfile.md @@ -0,0 +1,7 @@ +--- +title: "FilePickerUploadFile" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/filledbuttontheme.md b/website/docs/types/filledbuttontheme.md new file mode 100644 index 0000000000..8b28a23130 --- /dev/null +++ b/website/docs/types/filledbuttontheme.md @@ -0,0 +1,7 @@ +--- +title: "FilledButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/filterquality.md b/website/docs/types/filterquality.md new file mode 100644 index 0000000000..8faf828b7d --- /dev/null +++ b/website/docs/types/filterquality.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.FilterQuality" +examples: "controls/core/types/filter_quality" +title: "FilterQuality" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/finder.md b/website/docs/types/finder.md new file mode 100644 index 0000000000..8446c3b26f --- /dev/null +++ b/website/docs/types/finder.md @@ -0,0 +1,5 @@ +--- +title: "Finder" +--- + +::: flet.testing.finder.Finder diff --git a/website/docs/types/fletexception/index.md b/website/docs/types/fletexception/index.md new file mode 100644 index 0000000000..1ab9269ba8 --- /dev/null +++ b/website/docs/types/fletexception/index.md @@ -0,0 +1,7 @@ +--- +title: "FletException" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/fletpagedisconnectedexception.md b/website/docs/types/fletpagedisconnectedexception.md new file mode 100644 index 0000000000..43d5c01a33 --- /dev/null +++ b/website/docs/types/fletpagedisconnectedexception.md @@ -0,0 +1,7 @@ +--- +title: "FletPageDisconnectedException" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/flettestapp.md b/website/docs/types/flettestapp.md new file mode 100644 index 0000000000..93170351a6 --- /dev/null +++ b/website/docs/types/flettestapp.md @@ -0,0 +1,5 @@ +--- +title: "FletTestApp" +--- + +::: flet.testing.flet_test_app.FletTestApp diff --git a/website/docs/types/fletunimplementedplatformexception.md b/website/docs/types/fletunimplementedplatformexception.md new file mode 100644 index 0000000000..666f1e2fb8 --- /dev/null +++ b/website/docs/types/fletunimplementedplatformexception.md @@ -0,0 +1,7 @@ +--- +title: "FletUnimplementedPlatformException" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/fletunsupportedplatformexception.md b/website/docs/types/fletunsupportedplatformexception.md new file mode 100644 index 0000000000..f918ff27d4 --- /dev/null +++ b/website/docs/types/fletunsupportedplatformexception.md @@ -0,0 +1,7 @@ +--- +title: "FletUnsupportedPlatformException" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/flip.md b/website/docs/types/flip.md new file mode 100644 index 0000000000..09500d49f9 --- /dev/null +++ b/website/docs/types/flip.md @@ -0,0 +1,7 @@ +--- +title: "Flip" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/floatingactionbuttonlocation.md b/website/docs/types/floatingactionbuttonlocation.md new file mode 100644 index 0000000000..65e9219167 --- /dev/null +++ b/website/docs/types/floatingactionbuttonlocation.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.FloatingActionButtonLocation" +examples: "controls/core/types/floating_action_button_location" +title: "FloatingActionButtonLocation" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/floatingactionbuttontheme.md b/website/docs/types/floatingactionbuttontheme.md new file mode 100644 index 0000000000..ca7b248434 --- /dev/null +++ b/website/docs/types/floatingactionbuttontheme.md @@ -0,0 +1,7 @@ +--- +title: "FloatingActionButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/fontweight.md b/website/docs/types/fontweight.md new file mode 100644 index 0000000000..00de084014 --- /dev/null +++ b/website/docs/types/fontweight.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.FontWeight" +examples: "controls/core/types/font_weight" +title: "FontWeight" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/gradient/index.md b/website/docs/types/gradient/index.md new file mode 100644 index 0000000000..9e97f593d7 --- /dev/null +++ b/website/docs/types/gradient/index.md @@ -0,0 +1,13 @@ +--- +title: "Gradient" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +### Examples + +### Containers with gradients + + diff --git a/website/docs/types/gradienttilemode.md b/website/docs/types/gradienttilemode.md new file mode 100644 index 0000000000..4c81a73c45 --- /dev/null +++ b/website/docs/types/gradienttilemode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.GradientTileMode" +examples: "controls/core/types/gradient_tile_mode" +title: "GradientTileMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/gyroscopereadingevent.md b/website/docs/types/gyroscopereadingevent.md new file mode 100644 index 0000000000..3c3bc51591 --- /dev/null +++ b/website/docs/types/gyroscopereadingevent.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.GyroscopeReadingEvent" +title: "GyroscopeReadingEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/hoverevent.md b/website/docs/types/hoverevent.md new file mode 100644 index 0000000000..df052b7248 --- /dev/null +++ b/website/docs/types/hoverevent.md @@ -0,0 +1,7 @@ +--- +title: "HoverEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/iconbuttontheme.md b/website/docs/types/iconbuttontheme.md new file mode 100644 index 0000000000..485f338ac5 --- /dev/null +++ b/website/docs/types/iconbuttontheme.md @@ -0,0 +1,7 @@ +--- +title: "IconButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/icons.md b/website/docs/types/icons.md new file mode 100644 index 0000000000..e6dc89bfff --- /dev/null +++ b/website/docs/types/icons.md @@ -0,0 +1,9 @@ +--- +hide: + - "toc" +title: "Icons" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/icontheme.md b/website/docs/types/icontheme.md new file mode 100644 index 0000000000..a8e9e11291 --- /dev/null +++ b/website/docs/types/icontheme.md @@ -0,0 +1,7 @@ +--- +title: "IconTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/imagerepeat.md b/website/docs/types/imagerepeat.md new file mode 100644 index 0000000000..03dd068450 --- /dev/null +++ b/website/docs/types/imagerepeat.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ImageRepeat" +examples: "controls/core/types/image_repeat" +title: "ImageRepeat" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/index.md b/website/docs/types/index.md new file mode 100644 index 0000000000..6376574638 --- /dev/null +++ b/website/docs/types/index.md @@ -0,0 +1,16 @@ +--- +title: "Overview" +--- + +# Types + +Explore the shared building blocks that power Flet apps: aliases, base controls, reusable classes, enums, events, and exceptions. + +- [Aliases](aliases.md) - shorthand names and conveniences for common patterns. +- [Base Controls](../controls/basecontrol.md) - foundational control types to extend and compose. +- [Classes](alignment.md) - core data structures (layout, animation, theming, platform info, and more). +- [Decorators](component.md) - helpers for defining components, controls, and observables. +- [Enums](animationcurve.md) - constant sets that define options for controls and services. +- [Events](accelerometerreadingevent.md) - callback payloads emitted by controls and services. +- [Exceptions](fletexception/index.md) - Flet-specific error types for diagnostics and handling. +- [Methods](createcontext.md) - utilities for lifecycle, hooks, and component state. diff --git a/website/docs/types/inputborder.md b/website/docs/types/inputborder.md new file mode 100644 index 0000000000..0eb2a23c80 --- /dev/null +++ b/website/docs/types/inputborder.md @@ -0,0 +1,7 @@ +--- +title: "InputBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/inputfilter.md b/website/docs/types/inputfilter.md new file mode 100644 index 0000000000..11a46d9642 --- /dev/null +++ b/website/docs/types/inputfilter.md @@ -0,0 +1,28 @@ +--- +title: "InputFilter" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Predefined filters + + + + +## Usage example + +```python +ft.CupertinoTextField( + placeholder_text="Only numbers are allowed", + input_filter=ft.InputFilter(allow=True, regex_string=r"^[0-9]*$", replacement_string="") +) +``` + +```python +ft.TextField( + label="Only letters are allowed", + input_filter=ft.TextOnlyInputFilter() +) +``` diff --git a/website/docs/types/iosdeviceinfo.md b/website/docs/types/iosdeviceinfo.md new file mode 100644 index 0000000000..39bfd58a1b --- /dev/null +++ b/website/docs/types/iosdeviceinfo.md @@ -0,0 +1,7 @@ +--- +title: "IosDeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/iosutsname.md b/website/docs/types/iosutsname.md new file mode 100644 index 0000000000..122ab2de77 --- /dev/null +++ b/website/docs/types/iosutsname.md @@ -0,0 +1,7 @@ +--- +title: "IosUtsname" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/is_route_active.md b/website/docs/types/is_route_active.md new file mode 100644 index 0000000000..095ab20d02 --- /dev/null +++ b/website/docs/types/is_route_active.md @@ -0,0 +1,7 @@ +--- +title: "is_route_active" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/key/index.md b/website/docs/types/key/index.md new file mode 100644 index 0000000000..874be23925 --- /dev/null +++ b/website/docs/types/key/index.md @@ -0,0 +1,7 @@ +--- +title: "Key" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/keyboardevent.md b/website/docs/types/keyboardevent.md new file mode 100644 index 0000000000..5d85eb3530 --- /dev/null +++ b/website/docs/types/keyboardevent.md @@ -0,0 +1,7 @@ +--- +title: "KeyboardEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/keyboardtype.md b/website/docs/types/keyboardtype.md new file mode 100644 index 0000000000..c8d3425275 --- /dev/null +++ b/website/docs/types/keyboardtype.md @@ -0,0 +1,7 @@ +--- +title: "KeyboardType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/keydownevent.md b/website/docs/types/keydownevent.md new file mode 100644 index 0000000000..3341ae690a --- /dev/null +++ b/website/docs/types/keydownevent.md @@ -0,0 +1,7 @@ +--- +title: "KeyDownEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/keyrepeatevent.md b/website/docs/types/keyrepeatevent.md new file mode 100644 index 0000000000..b1689a439a --- /dev/null +++ b/website/docs/types/keyrepeatevent.md @@ -0,0 +1,7 @@ +--- +title: "KeyRepeatEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/keyupevent.md b/website/docs/types/keyupevent.md new file mode 100644 index 0000000000..620664859b --- /dev/null +++ b/website/docs/types/keyupevent.md @@ -0,0 +1,7 @@ +--- +title: "KeyUpEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/labelposition.md b/website/docs/types/labelposition.md new file mode 100644 index 0000000000..9164915cc0 --- /dev/null +++ b/website/docs/types/labelposition.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.LabelPosition" +examples: "controls/core/types/label_position" +title: "LabelPosition" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/launchmode.md b/website/docs/types/launchmode.md new file mode 100644 index 0000000000..acc76a0c2e --- /dev/null +++ b/website/docs/types/launchmode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.LaunchMode" +examples: "controls/core/types/launch_mode" +title: "LaunchMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/lineargradient.md b/website/docs/types/lineargradient.md new file mode 100644 index 0000000000..68296381d6 --- /dev/null +++ b/website/docs/types/lineargradient.md @@ -0,0 +1,15 @@ +--- +title: "LinearGradient" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Container with linear gradient + + + +container diff --git a/website/docs/types/linuxdeviceinfo.md b/website/docs/types/linuxdeviceinfo.md new file mode 100644 index 0000000000..37bff912e3 --- /dev/null +++ b/website/docs/types/linuxdeviceinfo.md @@ -0,0 +1,7 @@ +--- +title: "LinuxDeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/listtilestyle.md b/website/docs/types/listtilestyle.md new file mode 100644 index 0000000000..c69bdd3bd4 --- /dev/null +++ b/website/docs/types/listtilestyle.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ListTileStyle" +examples: "controls/core/types/list_tile_style" +title: "ListTileStyle" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/listtiletheme.md b/website/docs/types/listtiletheme.md new file mode 100644 index 0000000000..0bc0adf842 --- /dev/null +++ b/website/docs/types/listtiletheme.md @@ -0,0 +1,7 @@ +--- +title: "ListTileTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/listtiletitlealignment.md b/website/docs/types/listtiletitlealignment.md new file mode 100644 index 0000000000..f29883675b --- /dev/null +++ b/website/docs/types/listtiletitlealignment.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ListTileTitleAlignment" +examples: "controls/core/types/list_tile_title_alignment" +title: "ListTileTitleAlignment" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/locale.md b/website/docs/types/locale.md new file mode 100644 index 0000000000..28999401f7 --- /dev/null +++ b/website/docs/types/locale.md @@ -0,0 +1,7 @@ +--- +title: "Locale" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/localechangeevent.md b/website/docs/types/localechangeevent.md new file mode 100644 index 0000000000..358a4d2701 --- /dev/null +++ b/website/docs/types/localechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "LocaleChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/localeconfiguration.md b/website/docs/types/localeconfiguration.md new file mode 100644 index 0000000000..b4c7b362ef --- /dev/null +++ b/website/docs/types/localeconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "LocaleConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/locationinfo.md b/website/docs/types/locationinfo.md new file mode 100644 index 0000000000..53afed76b1 --- /dev/null +++ b/website/docs/types/locationinfo.md @@ -0,0 +1,7 @@ +--- +title: "LocationInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/loginevent.md b/website/docs/types/loginevent.md new file mode 100644 index 0000000000..bc546c6598 --- /dev/null +++ b/website/docs/types/loginevent.md @@ -0,0 +1,7 @@ +--- +title: "LoginEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/longpressendevent.md b/website/docs/types/longpressendevent.md new file mode 100644 index 0000000000..16b18662b2 --- /dev/null +++ b/website/docs/types/longpressendevent.md @@ -0,0 +1,7 @@ +--- +title: "LongPressEndEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/longpressstartevent.md b/website/docs/types/longpressstartevent.md new file mode 100644 index 0000000000..7f265ad1ef --- /dev/null +++ b/website/docs/types/longpressstartevent.md @@ -0,0 +1,7 @@ +--- +title: "LongPressStartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/macosdeviceinfo.md b/website/docs/types/macosdeviceinfo.md new file mode 100644 index 0000000000..a76451297b --- /dev/null +++ b/website/docs/types/macosdeviceinfo.md @@ -0,0 +1,7 @@ +--- +title: "MacOsDeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/magnetometerreadingevent.md b/website/docs/types/magnetometerreadingevent.md new file mode 100644 index 0000000000..0a488baeea --- /dev/null +++ b/website/docs/types/magnetometerreadingevent.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.MagnetometerReadingEvent" +title: "MagnetometerReadingEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/mainaxisalignment.md b/website/docs/types/mainaxisalignment.md new file mode 100644 index 0000000000..fdb4ec6745 --- /dev/null +++ b/website/docs/types/mainaxisalignment.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.MainAxisAlignment" +examples: "controls/core/types/main_axis_alignment" +title: "MainAxisAlignment" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/margin.md b/website/docs/types/margin.md new file mode 100644 index 0000000000..bbf0d391ae --- /dev/null +++ b/website/docs/types/margin.md @@ -0,0 +1,13 @@ +--- +title: "Margin" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + diff --git a/website/docs/types/markdowncodetheme.md b/website/docs/types/markdowncodetheme.md new file mode 100644 index 0000000000..9e9c89ad23 --- /dev/null +++ b/website/docs/types/markdowncodetheme.md @@ -0,0 +1,7 @@ +--- +title: "MarkdownCodeTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/markdowncustomcodetheme.md b/website/docs/types/markdowncustomcodetheme.md new file mode 100644 index 0000000000..7c86e96cbb --- /dev/null +++ b/website/docs/types/markdowncustomcodetheme.md @@ -0,0 +1,7 @@ +--- +title: "MarkdownCustomCodeTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/markdownextensionset.md b/website/docs/types/markdownextensionset.md new file mode 100644 index 0000000000..2351d57f0f --- /dev/null +++ b/website/docs/types/markdownextensionset.md @@ -0,0 +1,7 @@ +--- +title: "MarkdownExtensionSet" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/markdownstylesheet.md b/website/docs/types/markdownstylesheet.md new file mode 100644 index 0000000000..ee8953dd15 --- /dev/null +++ b/website/docs/types/markdownstylesheet.md @@ -0,0 +1,7 @@ +--- +title: "MarkdownStyleSheet" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/matrix4.md b/website/docs/types/matrix4.md new file mode 100644 index 0000000000..a8bd3e8cc5 --- /dev/null +++ b/website/docs/types/matrix4.md @@ -0,0 +1,7 @@ +--- +title: "Matrix4" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/memo.md b/website/docs/types/memo.md new file mode 100644 index 0000000000..e5717e26c8 --- /dev/null +++ b/website/docs/types/memo.md @@ -0,0 +1,7 @@ +--- +title: "memo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/menustyle.md b/website/docs/types/menustyle.md new file mode 100644 index 0000000000..8cfa3aba27 --- /dev/null +++ b/website/docs/types/menustyle.md @@ -0,0 +1,7 @@ +--- +title: "MenuStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/mousecursor.md b/website/docs/types/mousecursor.md new file mode 100644 index 0000000000..8b4140766e --- /dev/null +++ b/website/docs/types/mousecursor.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.MouseCursor" +examples: "controls/core/types/mouse_cursor" +title: "MouseCursor" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/multitapevent.md b/website/docs/types/multitapevent.md new file mode 100644 index 0000000000..198763f338 --- /dev/null +++ b/website/docs/types/multitapevent.md @@ -0,0 +1,7 @@ +--- +title: "MultiTapEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/multiviewaddevent.md b/website/docs/types/multiviewaddevent.md new file mode 100644 index 0000000000..fab5efcc28 --- /dev/null +++ b/website/docs/types/multiviewaddevent.md @@ -0,0 +1,7 @@ +--- +title: "MultiViewAddEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/multiviewremoveevent.md b/website/docs/types/multiviewremoveevent.md new file mode 100644 index 0000000000..32f7d6348d --- /dev/null +++ b/website/docs/types/multiviewremoveevent.md @@ -0,0 +1,7 @@ +--- +title: "MultiViewRemoveEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/navigationbarlabelbehavior.md b/website/docs/types/navigationbarlabelbehavior.md new file mode 100644 index 0000000000..a6d7eb9b48 --- /dev/null +++ b/website/docs/types/navigationbarlabelbehavior.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.NavigationBarLabelBehavior" +examples: "controls/core/types/navigation_bar_label_behavior" +title: "NavigationBarLabelBehavior" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/navigationbartheme.md b/website/docs/types/navigationbartheme.md new file mode 100644 index 0000000000..0a023ffbbd --- /dev/null +++ b/website/docs/types/navigationbartheme.md @@ -0,0 +1,7 @@ +--- +title: "NavigationBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/navigationdrawertheme.md b/website/docs/types/navigationdrawertheme.md new file mode 100644 index 0000000000..fddee84f2e --- /dev/null +++ b/website/docs/types/navigationdrawertheme.md @@ -0,0 +1,7 @@ +--- +title: "NavigationDrawerTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/navigationraillabeltype.md b/website/docs/types/navigationraillabeltype.md new file mode 100644 index 0000000000..1f70d7edef --- /dev/null +++ b/website/docs/types/navigationraillabeltype.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.NavigationRailLabelType" +examples: "controls/core/types/navigation_rail_label_type" +title: "NavigationRailLabelType" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/navigationrailtheme.md b/website/docs/types/navigationrailtheme.md new file mode 100644 index 0000000000..92fa71521d --- /dev/null +++ b/website/docs/types/navigationrailtheme.md @@ -0,0 +1,7 @@ +--- +title: "NavigationRailTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/notchshape/index.md b/website/docs/types/notchshape/index.md new file mode 100644 index 0000000000..f401d3ef0c --- /dev/null +++ b/website/docs/types/notchshape/index.md @@ -0,0 +1,7 @@ +--- +title: "NotchShape" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/observable.md b/website/docs/types/observable.md new file mode 100644 index 0000000000..4ded35fa22 --- /dev/null +++ b/website/docs/types/observable.md @@ -0,0 +1,7 @@ +--- +title: "Observable" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/observabledecorator.md b/website/docs/types/observabledecorator.md new file mode 100644 index 0000000000..dc0405defd --- /dev/null +++ b/website/docs/types/observabledecorator.md @@ -0,0 +1,9 @@ +--- +title: "observable" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +# \@observable + + diff --git a/website/docs/types/offset.md b/website/docs/types/offset.md new file mode 100644 index 0000000000..a34e73b2d9 --- /dev/null +++ b/website/docs/types/offset.md @@ -0,0 +1,7 @@ +--- +title: "Offset" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/onmounted.md b/website/docs/types/onmounted.md new file mode 100644 index 0000000000..bbff8e1f0e --- /dev/null +++ b/website/docs/types/onmounted.md @@ -0,0 +1,7 @@ +--- +title: "on_mounted" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/onreorderevent.md b/website/docs/types/onreorderevent.md new file mode 100644 index 0000000000..21f0085979 --- /dev/null +++ b/website/docs/types/onreorderevent.md @@ -0,0 +1,7 @@ +--- +title: "OnReorderEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/onscrollevent.md b/website/docs/types/onscrollevent.md new file mode 100644 index 0000000000..640e622577 --- /dev/null +++ b/website/docs/types/onscrollevent.md @@ -0,0 +1,7 @@ +--- +title: "OnScrollEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/onunmounted.md b/website/docs/types/onunmounted.md new file mode 100644 index 0000000000..d097f9ed38 --- /dev/null +++ b/website/docs/types/onunmounted.md @@ -0,0 +1,7 @@ +--- +title: "on_unmounted" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/onupdated.md b/website/docs/types/onupdated.md new file mode 100644 index 0000000000..715244f444 --- /dev/null +++ b/website/docs/types/onupdated.md @@ -0,0 +1,7 @@ +--- +title: "on_updated" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/orientation.md b/website/docs/types/orientation.md new file mode 100644 index 0000000000..eae6e622e9 --- /dev/null +++ b/website/docs/types/orientation.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.Orientation" +examples: "controls/core/types/orientation" +title: "Orientation" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/outlinedborder/index.md b/website/docs/types/outlinedborder/index.md new file mode 100644 index 0000000000..0c761ce4a9 --- /dev/null +++ b/website/docs/types/outlinedborder/index.md @@ -0,0 +1,7 @@ +--- +title: "OutlinedBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/outlinedbuttontheme.md b/website/docs/types/outlinedbuttontheme.md new file mode 100644 index 0000000000..e6165ec0ed --- /dev/null +++ b/website/docs/types/outlinedbuttontheme.md @@ -0,0 +1,7 @@ +--- +title: "OutlinedButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/overlayvisibilitymode.md b/website/docs/types/overlayvisibilitymode.md new file mode 100644 index 0000000000..6a93296f90 --- /dev/null +++ b/website/docs/types/overlayvisibilitymode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.OverlayVisibilityMode" +examples: "controls/core/types/overlay_visibility_mode" +title: "OverlayVisibilityMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/padding.md b/website/docs/types/padding.md new file mode 100644 index 0000000000..94ac9330df --- /dev/null +++ b/website/docs/types/padding.md @@ -0,0 +1,15 @@ +--- +title: "Padding" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + + + +container diff --git a/website/docs/types/pagemediadata.md b/website/docs/types/pagemediadata.md new file mode 100644 index 0000000000..1fb47092cd --- /dev/null +++ b/website/docs/types/pagemediadata.md @@ -0,0 +1,7 @@ +--- +title: "PageMediaData" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pageplatform.md b/website/docs/types/pageplatform.md new file mode 100644 index 0000000000..1a6e5c3d44 --- /dev/null +++ b/website/docs/types/pageplatform.md @@ -0,0 +1,7 @@ +--- +title: "PagePlatform" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pageresizeevent.md b/website/docs/types/pageresizeevent.md new file mode 100644 index 0000000000..aae64b3cde --- /dev/null +++ b/website/docs/types/pageresizeevent.md @@ -0,0 +1,7 @@ +--- +title: "PageResizeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pagetransitionstheme.md b/website/docs/types/pagetransitionstheme.md new file mode 100644 index 0000000000..e123dfb607 --- /dev/null +++ b/website/docs/types/pagetransitionstheme.md @@ -0,0 +1,7 @@ +--- +title: "PageTransitionsTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pagetransitiontheme.md b/website/docs/types/pagetransitiontheme.md new file mode 100644 index 0000000000..6039f0b0d3 --- /dev/null +++ b/website/docs/types/pagetransitiontheme.md @@ -0,0 +1,7 @@ +--- +title: "PageTransitionTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/paint.md b/website/docs/types/paint.md new file mode 100644 index 0000000000..10d486d8f1 --- /dev/null +++ b/website/docs/types/paint.md @@ -0,0 +1,7 @@ +--- +title: "Paint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/paintgradient/index.md b/website/docs/types/paintgradient/index.md new file mode 100644 index 0000000000..eb405bf165 --- /dev/null +++ b/website/docs/types/paintgradient/index.md @@ -0,0 +1,13 @@ +--- +title: "PaintGradient" +--- + +import {ClassAll, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Canvas paint + + diff --git a/website/docs/types/paintingstyle.md b/website/docs/types/paintingstyle.md new file mode 100644 index 0000000000..b734d7b80d --- /dev/null +++ b/website/docs/types/paintingstyle.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.PaintingStyle" +examples: "controls/core/types/painting_style" +title: "PaintingStyle" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/paintlineargradient.md b/website/docs/types/paintlineargradient.md new file mode 100644 index 0000000000..7326573c31 --- /dev/null +++ b/website/docs/types/paintlineargradient.md @@ -0,0 +1,15 @@ +--- +title: "PaintLinearGradient" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Canvas paint + + + +canvas-paint diff --git a/website/docs/types/paintradialgradient.md b/website/docs/types/paintradialgradient.md new file mode 100644 index 0000000000..294b4881fe --- /dev/null +++ b/website/docs/types/paintradialgradient.md @@ -0,0 +1,15 @@ +--- +title: "PaintRadialGradient" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Canvas paint + + + +canvas-paint diff --git a/website/docs/types/paintsweepgradient.md b/website/docs/types/paintsweepgradient.md new file mode 100644 index 0000000000..637f67a7d1 --- /dev/null +++ b/website/docs/types/paintsweepgradient.md @@ -0,0 +1,15 @@ +--- +title: "PaintSweepGradient" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Canvas paint + + + +canvas-paint diff --git a/website/docs/types/platformbrightnesschangeevent.md b/website/docs/types/platformbrightnesschangeevent.md new file mode 100644 index 0000000000..80dacd0d85 --- /dev/null +++ b/website/docs/types/platformbrightnesschangeevent.md @@ -0,0 +1,7 @@ +--- +title: "PlatformBrightnessChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pointerdevicetype.md b/website/docs/types/pointerdevicetype.md new file mode 100644 index 0000000000..feda7a79bc --- /dev/null +++ b/website/docs/types/pointerdevicetype.md @@ -0,0 +1,7 @@ +--- +title: "PointerDeviceType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pointerevent.md b/website/docs/types/pointerevent.md new file mode 100644 index 0000000000..c208f184cf --- /dev/null +++ b/website/docs/types/pointerevent.md @@ -0,0 +1,7 @@ +--- +title: "PointerEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pointmode.md b/website/docs/types/pointmode.md new file mode 100644 index 0000000000..89a4342545 --- /dev/null +++ b/website/docs/types/pointmode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.canvas.PointMode" +examples: "controls/core/types/point_mode" +title: "PointMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/popupmenuposition.md b/website/docs/types/popupmenuposition.md new file mode 100644 index 0000000000..3192f9ab3f --- /dev/null +++ b/website/docs/types/popupmenuposition.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.PopupMenuPosition" +examples: "controls/core/types/popup_menu_position" +title: "PopupMenuPosition" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/popupmenutheme.md b/website/docs/types/popupmenutheme.md new file mode 100644 index 0000000000..4d2b2ec9db --- /dev/null +++ b/website/docs/types/popupmenutheme.md @@ -0,0 +1,7 @@ +--- +title: "PopupMenuTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/progressindicatortheme.md b/website/docs/types/progressindicatortheme.md new file mode 100644 index 0000000000..8a41c00057 --- /dev/null +++ b/website/docs/types/progressindicatortheme.md @@ -0,0 +1,7 @@ +--- +title: "ProgressIndicatorTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pubsub/pubsubclient.md b/website/docs/types/pubsub/pubsubclient.md new file mode 100644 index 0000000000..6744816fe6 --- /dev/null +++ b/website/docs/types/pubsub/pubsubclient.md @@ -0,0 +1,7 @@ +--- +title: "PubSubClient" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/pubsub/pubsubhub.md b/website/docs/types/pubsub/pubsubhub.md new file mode 100644 index 0000000000..3ad61b22b5 --- /dev/null +++ b/website/docs/types/pubsub/pubsubhub.md @@ -0,0 +1,7 @@ +--- +title: "PubSubHub" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/radialgradient.md b/website/docs/types/radialgradient.md new file mode 100644 index 0000000000..addbba7843 --- /dev/null +++ b/website/docs/types/radialgradient.md @@ -0,0 +1,15 @@ +--- +title: "RadialGradient" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Container with radial gradient + + + +container diff --git a/website/docs/types/radiotheme.md b/website/docs/types/radiotheme.md new file mode 100644 index 0000000000..6ee650af31 --- /dev/null +++ b/website/docs/types/radiotheme.md @@ -0,0 +1,7 @@ +--- +title: "RadioTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/rect.md b/website/docs/types/rect.md new file mode 100644 index 0000000000..0b1f5bcbbd --- /dev/null +++ b/website/docs/types/rect.md @@ -0,0 +1,7 @@ +--- +title: "Rect" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/ref.md b/website/docs/types/ref.md new file mode 100644 index 0000000000..93abb5a510 --- /dev/null +++ b/website/docs/types/ref.md @@ -0,0 +1,7 @@ +--- +title: "Ref" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/responsiverowbreakpoint.md b/website/docs/types/responsiverowbreakpoint.md new file mode 100644 index 0000000000..1c04e6be8a --- /dev/null +++ b/website/docs/types/responsiverowbreakpoint.md @@ -0,0 +1,7 @@ +--- +title: "ResponsiveRowBreakpoint" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/rotate.md b/website/docs/types/rotate.md new file mode 100644 index 0000000000..42aaa28ac2 --- /dev/null +++ b/website/docs/types/rotate.md @@ -0,0 +1,7 @@ +--- +title: "Rotate" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/roundedrectangleborder.md b/website/docs/types/roundedrectangleborder.md new file mode 100644 index 0000000000..f05c77213a --- /dev/null +++ b/website/docs/types/roundedrectangleborder.md @@ -0,0 +1,7 @@ +--- +title: "RoundedRectangleBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/route.md b/website/docs/types/route.md new file mode 100644 index 0000000000..7a236f069b --- /dev/null +++ b/website/docs/types/route.md @@ -0,0 +1,7 @@ +--- +title: "Route" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/routechangeevent.md b/website/docs/types/routechangeevent.md new file mode 100644 index 0000000000..eaba64bc52 --- /dev/null +++ b/website/docs/types/routechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "RouteChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/routeurlstrategy.md b/website/docs/types/routeurlstrategy.md new file mode 100644 index 0000000000..772e6f5c8f --- /dev/null +++ b/website/docs/types/routeurlstrategy.md @@ -0,0 +1,7 @@ +--- +title: "RouteUrlStrategy" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scale.md b/website/docs/types/scale.md new file mode 100644 index 0000000000..f9b6436d8e --- /dev/null +++ b/website/docs/types/scale.md @@ -0,0 +1,7 @@ +--- +title: "Scale" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scaleendevent.md b/website/docs/types/scaleendevent.md new file mode 100644 index 0000000000..56d580ecb4 --- /dev/null +++ b/website/docs/types/scaleendevent.md @@ -0,0 +1,7 @@ +--- +title: "ScaleEndEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scalestartevent.md b/website/docs/types/scalestartevent.md new file mode 100644 index 0000000000..5b195b0a36 --- /dev/null +++ b/website/docs/types/scalestartevent.md @@ -0,0 +1,7 @@ +--- +title: "ScaleStartEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scaleupdateevent.md b/website/docs/types/scaleupdateevent.md new file mode 100644 index 0000000000..7eb44f831b --- /dev/null +++ b/website/docs/types/scaleupdateevent.md @@ -0,0 +1,7 @@ +--- +title: "ScaleUpdateEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/screenbrightnesschangeevent.md b/website/docs/types/screenbrightnesschangeevent.md new file mode 100644 index 0000000000..e833d1d14e --- /dev/null +++ b/website/docs/types/screenbrightnesschangeevent.md @@ -0,0 +1,7 @@ +--- +title: "ScreenBrightnessChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scrollbar.md b/website/docs/types/scrollbar.md new file mode 100644 index 0000000000..7f12e234a4 --- /dev/null +++ b/website/docs/types/scrollbar.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.Scrollbar" +examples: "controls/core/types/scroll_bar" +title: "Scrollbar" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/scrollbarorientation.md b/website/docs/types/scrollbarorientation.md new file mode 100644 index 0000000000..99da18d614 --- /dev/null +++ b/website/docs/types/scrollbarorientation.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ScrollbarOrientation" +examples: "controls/core/types/scroll_bar_orientation" +title: "ScrollbarOrientation" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/scrollbartheme.md b/website/docs/types/scrollbartheme.md new file mode 100644 index 0000000000..9d0ff40c3a --- /dev/null +++ b/website/docs/types/scrollbartheme.md @@ -0,0 +1,7 @@ +--- +title: "ScrollBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scrolldirection.md b/website/docs/types/scrolldirection.md new file mode 100644 index 0000000000..acaacd2f5f --- /dev/null +++ b/website/docs/types/scrolldirection.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ScrollDirection" +examples: "controls/core/types/scroll_direction" +title: "ScrollDirection" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/scrollevent.md b/website/docs/types/scrollevent.md new file mode 100644 index 0000000000..256c357ab3 --- /dev/null +++ b/website/docs/types/scrollevent.md @@ -0,0 +1,7 @@ +--- +title: "ScrollEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scrollkey.md b/website/docs/types/scrollkey.md new file mode 100644 index 0000000000..2e13092623 --- /dev/null +++ b/website/docs/types/scrollkey.md @@ -0,0 +1,7 @@ +--- +title: "ScrollKey" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/scrollmode.md b/website/docs/types/scrollmode.md new file mode 100644 index 0000000000..a5c63b05f3 --- /dev/null +++ b/website/docs/types/scrollmode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ScrollMode" +examples: "controls/core/types/scroll_mode" +title: "ScrollMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/scrolltype.md b/website/docs/types/scrolltype.md new file mode 100644 index 0000000000..acc9053604 --- /dev/null +++ b/website/docs/types/scrolltype.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ScrollType" +examples: "controls/core/types/scroll_type" +title: "ScrollType" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/searchbartheme.md b/website/docs/types/searchbartheme.md new file mode 100644 index 0000000000..057dfe8206 --- /dev/null +++ b/website/docs/types/searchbartheme.md @@ -0,0 +1,7 @@ +--- +title: "SearchBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/searchviewtheme.md b/website/docs/types/searchviewtheme.md new file mode 100644 index 0000000000..f54d8fead7 --- /dev/null +++ b/website/docs/types/searchviewtheme.md @@ -0,0 +1,7 @@ +--- +title: "SearchViewTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/segmentedbuttontheme.md b/website/docs/types/segmentedbuttontheme.md new file mode 100644 index 0000000000..54c7453a05 --- /dev/null +++ b/website/docs/types/segmentedbuttontheme.md @@ -0,0 +1,7 @@ +--- +title: "SegmentedButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/sensorerrorevent.md b/website/docs/types/sensorerrorevent.md new file mode 100644 index 0000000000..b6ba8be57b --- /dev/null +++ b/website/docs/types/sensorerrorevent.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.SensorErrorEvent" +title: "SensorErrorEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/shapeborder.md b/website/docs/types/shapeborder.md new file mode 100644 index 0000000000..16ed164da7 --- /dev/null +++ b/website/docs/types/shapeborder.md @@ -0,0 +1,7 @@ +--- +title: "ShapeBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/sharecupertinoactivitytype.md b/website/docs/types/sharecupertinoactivitytype.md new file mode 100644 index 0000000000..a085077396 --- /dev/null +++ b/website/docs/types/sharecupertinoactivitytype.md @@ -0,0 +1,7 @@ +--- +title: "ShareCupertinoActivityType" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/sharefile.md b/website/docs/types/sharefile.md new file mode 100644 index 0000000000..543d6cc9fe --- /dev/null +++ b/website/docs/types/sharefile.md @@ -0,0 +1,7 @@ +--- +title: "ShareFile" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/shareresult.md b/website/docs/types/shareresult.md new file mode 100644 index 0000000000..0553523bbf --- /dev/null +++ b/website/docs/types/shareresult.md @@ -0,0 +1,7 @@ +--- +title: "ShareResult" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/shareresultstatus.md b/website/docs/types/shareresultstatus.md new file mode 100644 index 0000000000..fa0f796c9e --- /dev/null +++ b/website/docs/types/shareresultstatus.md @@ -0,0 +1,7 @@ +--- +title: "ShareResultStatus" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/size.md b/website/docs/types/size.md new file mode 100644 index 0000000000..2fc61c8e31 --- /dev/null +++ b/website/docs/types/size.md @@ -0,0 +1,7 @@ +--- +title: "Size" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/sliderinteraction.md b/website/docs/types/sliderinteraction.md new file mode 100644 index 0000000000..62f3a0f0f6 --- /dev/null +++ b/website/docs/types/sliderinteraction.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.SliderInteraction" +examples: "controls/core/types/slider_interaction" +title: "SliderInteraction" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/slidertheme.md b/website/docs/types/slidertheme.md new file mode 100644 index 0000000000..32f144adea --- /dev/null +++ b/website/docs/types/slidertheme.md @@ -0,0 +1,7 @@ +--- +title: "SliderTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/snackbarbehavior.md b/website/docs/types/snackbarbehavior.md new file mode 100644 index 0000000000..06e0193610 --- /dev/null +++ b/website/docs/types/snackbarbehavior.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.SnackBarBehavior" +examples: "controls/core/types/snack_bar_behavior" +title: "SnackBarBehavior" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/snackbartheme.md b/website/docs/types/snackbartheme.md new file mode 100644 index 0000000000..09dda6154d --- /dev/null +++ b/website/docs/types/snackbartheme.md @@ -0,0 +1,7 @@ +--- +title: "SnackBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/stackfit.md b/website/docs/types/stackfit.md new file mode 100644 index 0000000000..9b0a2261ac --- /dev/null +++ b/website/docs/types/stackfit.md @@ -0,0 +1,7 @@ +--- +title: "StackFit" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/stadiumborder.md b/website/docs/types/stadiumborder.md new file mode 100644 index 0000000000..63d100c9f2 --- /dev/null +++ b/website/docs/types/stadiumborder.md @@ -0,0 +1,7 @@ +--- +title: "StadiumBorder" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/strokecap.md b/website/docs/types/strokecap.md new file mode 100644 index 0000000000..54314a27d0 --- /dev/null +++ b/website/docs/types/strokecap.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.StrokeCap" +examples: "controls/core/types/stroke_cap" +title: "StrokeCap" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/strokejoin.md b/website/docs/types/strokejoin.md new file mode 100644 index 0000000000..bb68bd89a8 --- /dev/null +++ b/website/docs/types/strokejoin.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.StrokeJoin" +examples: "controls/core/types/stroke_join" +title: "StrokeJoin" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/strutstyle.md b/website/docs/types/strutstyle.md new file mode 100644 index 0000000000..5202257066 --- /dev/null +++ b/website/docs/types/strutstyle.md @@ -0,0 +1,7 @@ +--- +title: "StrutStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/sweepgradient.md b/website/docs/types/sweepgradient.md new file mode 100644 index 0000000000..76e9ab8b03 --- /dev/null +++ b/website/docs/types/sweepgradient.md @@ -0,0 +1,15 @@ +--- +title: "SweepGradient" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Container with sweep gradient + + + +container diff --git a/website/docs/types/switchtheme.md b/website/docs/types/switchtheme.md new file mode 100644 index 0000000000..68e4be10ac --- /dev/null +++ b/website/docs/types/switchtheme.md @@ -0,0 +1,7 @@ +--- +title: "SwitchTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/systemoverlaystyle.md b/website/docs/types/systemoverlaystyle.md new file mode 100644 index 0000000000..8f5f904af4 --- /dev/null +++ b/website/docs/types/systemoverlaystyle.md @@ -0,0 +1,7 @@ +--- +title: "SystemOverlayStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/tabalignment.md b/website/docs/types/tabalignment.md new file mode 100644 index 0000000000..27984940cc --- /dev/null +++ b/website/docs/types/tabalignment.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TabAlignment" +examples: "controls/core/types/tab_alignment" +title: "TabAlignment" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/tabbarhoverevent.md b/website/docs/types/tabbarhoverevent.md new file mode 100644 index 0000000000..e83d2acb0d --- /dev/null +++ b/website/docs/types/tabbarhoverevent.md @@ -0,0 +1,7 @@ +--- +title: "TabBarHoverEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/tabbarindicatorsize.md b/website/docs/types/tabbarindicatorsize.md new file mode 100644 index 0000000000..d0b856cc46 --- /dev/null +++ b/website/docs/types/tabbarindicatorsize.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TabBarIndicatorSize" +examples: "controls/core/types/tab_bar_indicator_size" +title: "TabBarIndicatorSize" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/tabbartheme.md b/website/docs/types/tabbartheme.md new file mode 100644 index 0000000000..f07b14ecc5 --- /dev/null +++ b/website/docs/types/tabbartheme.md @@ -0,0 +1,27 @@ +--- +title: "TabBarTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Examples + +### Example 1 + +```python +page.theme = ft.Theme( + tabs_theme=ft.TabBarTheme( + divider_color=ft.Colors.BLUE, + indicator_color=ft.Colors.RED, + indicator_tab_size=True, + label_color=ft.Colors.GREEN, + unselected_label_color=ft.Colors.AMBER, + overlay_color={ + ft.MaterialState.FOCUSED: ft.Colors.with_opacity(0.2, ft.Colors.GREEN), + ft.MaterialState.DEFAULT: ft.Colors.with_opacity(0.2, ft.Colors.PINK), + }, + ) +) +``` diff --git a/website/docs/types/tabindicatoranimation.md b/website/docs/types/tabindicatoranimation.md new file mode 100644 index 0000000000..4d5f4ffe29 --- /dev/null +++ b/website/docs/types/tabindicatoranimation.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TabIndicatorAnimation" +examples: "controls/core/types/tab_indicator_animation" +title: "TabIndicatorAnimation" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/tapevent.md b/website/docs/types/tapevent.md new file mode 100644 index 0000000000..9b11562e40 --- /dev/null +++ b/website/docs/types/tapevent.md @@ -0,0 +1,7 @@ +--- +title: "TapEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/templateroute.md b/website/docs/types/templateroute.md new file mode 100644 index 0000000000..39b9617b5b --- /dev/null +++ b/website/docs/types/templateroute.md @@ -0,0 +1,7 @@ +--- +title: "TemplateRoute" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/tester.md b/website/docs/types/tester.md new file mode 100644 index 0000000000..415180a981 --- /dev/null +++ b/website/docs/types/tester.md @@ -0,0 +1,5 @@ +--- +title: "Tester" +--- + +::: flet.testing.tester.Tester diff --git a/website/docs/types/textaffinity.md b/website/docs/types/textaffinity.md new file mode 100644 index 0000000000..c86e785896 --- /dev/null +++ b/website/docs/types/textaffinity.md @@ -0,0 +1,7 @@ +--- +title: "TextAffinity" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textalign.md b/website/docs/types/textalign.md new file mode 100644 index 0000000000..4a6ea28135 --- /dev/null +++ b/website/docs/types/textalign.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TextAlign" +examples: "controls/core/types/text_align" +title: "TextAlign" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/textbaseline.md b/website/docs/types/textbaseline.md new file mode 100644 index 0000000000..25cda92115 --- /dev/null +++ b/website/docs/types/textbaseline.md @@ -0,0 +1,7 @@ +--- +title: "TextBaseline" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textbuttontheme.md b/website/docs/types/textbuttontheme.md new file mode 100644 index 0000000000..3e1e432d41 --- /dev/null +++ b/website/docs/types/textbuttontheme.md @@ -0,0 +1,7 @@ +--- +title: "TextButtonTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textcapitalization.md b/website/docs/types/textcapitalization.md new file mode 100644 index 0000000000..bb3952ea4a --- /dev/null +++ b/website/docs/types/textcapitalization.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TextCapitalization" +examples: "controls/core/types/text_capitalization" +title: "TextCapitalization" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/textdecoration.md b/website/docs/types/textdecoration.md new file mode 100644 index 0000000000..fb1d05c9e8 --- /dev/null +++ b/website/docs/types/textdecoration.md @@ -0,0 +1,15 @@ +--- +title: "TextDecoration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage Example + +The enum is a flag, so multiple decorations can be combined together as follows: + +```python +style = ft.TextStyle(decoration=ft.TextDecoration.UNDERLINE | ft.TextDecoration.OVERLINE) +``` diff --git a/website/docs/types/textdecorationstyle.md b/website/docs/types/textdecorationstyle.md new file mode 100644 index 0000000000..f841742a3f --- /dev/null +++ b/website/docs/types/textdecorationstyle.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TextDecorationStyle" +examples: "controls/core/types/text_decoration_style" +title: "TextDecorationStyle" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/textoverflow.md b/website/docs/types/textoverflow.md new file mode 100644 index 0000000000..a964438fda --- /dev/null +++ b/website/docs/types/textoverflow.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TextOverflow" +examples: "controls/core/types/text_overflow" +title: "TextOverflow" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/textselection.md b/website/docs/types/textselection.md new file mode 100644 index 0000000000..70cdf07527 --- /dev/null +++ b/website/docs/types/textselection.md @@ -0,0 +1,7 @@ +--- +title: "TextSelection" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textselectionchangecause.md b/website/docs/types/textselectionchangecause.md new file mode 100644 index 0000000000..9068b85329 --- /dev/null +++ b/website/docs/types/textselectionchangecause.md @@ -0,0 +1,7 @@ +--- +title: "TextSelectionChangeCause" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textselectionchangeevent.md b/website/docs/types/textselectionchangeevent.md new file mode 100644 index 0000000000..91c935cee3 --- /dev/null +++ b/website/docs/types/textselectionchangeevent.md @@ -0,0 +1,7 @@ +--- +title: "TextSelectionChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textspan.md b/website/docs/types/textspan.md new file mode 100644 index 0000000000..6aa17f19f5 --- /dev/null +++ b/website/docs/types/textspan.md @@ -0,0 +1,7 @@ +--- +title: "TextSpan" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textstyle.md b/website/docs/types/textstyle.md new file mode 100644 index 0000000000..a55da612d9 --- /dev/null +++ b/website/docs/types/textstyle.md @@ -0,0 +1,7 @@ +--- +title: "TextStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/texttheme.md b/website/docs/types/texttheme.md new file mode 100644 index 0000000000..e1d84bf22e --- /dev/null +++ b/website/docs/types/texttheme.md @@ -0,0 +1,7 @@ +--- +title: "TextTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/textthemestyle.md b/website/docs/types/textthemestyle.md new file mode 100644 index 0000000000..955ad5c411 --- /dev/null +++ b/website/docs/types/textthemestyle.md @@ -0,0 +1,7 @@ +--- +title: "TextThemeStyle" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/theme/index.md b/website/docs/types/theme/index.md new file mode 100644 index 0000000000..4d73e951db --- /dev/null +++ b/website/docs/types/theme/index.md @@ -0,0 +1,7 @@ +--- +title: "Theme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/thememode.md b/website/docs/types/thememode.md new file mode 100644 index 0000000000..13b124684b --- /dev/null +++ b/website/docs/types/thememode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.ThemeMode" +examples: "controls/core/types/theme_mode" +title: "ThemeMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/tileaffinity.md b/website/docs/types/tileaffinity.md new file mode 100644 index 0000000000..31a30cd368 --- /dev/null +++ b/website/docs/types/tileaffinity.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TileAffinity" +examples: "controls/core/types/tile_affinity" +title: "TileAffinity" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/timepickerentrymode.md b/website/docs/types/timepickerentrymode.md new file mode 100644 index 0000000000..1ba7a45b6e --- /dev/null +++ b/website/docs/types/timepickerentrymode.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TimePickerEntryMode" +examples: "controls/core/types/time_picker_entry_mode" +title: "TimePickerEntryMode" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/timepickerentrymodechangeevent.md b/website/docs/types/timepickerentrymodechangeevent.md new file mode 100644 index 0000000000..f519d587e4 --- /dev/null +++ b/website/docs/types/timepickerentrymodechangeevent.md @@ -0,0 +1,7 @@ +--- +title: "TimePickerEntryModeChangeEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/timepickerhourformat.md b/website/docs/types/timepickerhourformat.md new file mode 100644 index 0000000000..04c4058bfd --- /dev/null +++ b/website/docs/types/timepickerhourformat.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.TimePickerHourFormat" +examples: "controls/core/types/time_picker_hour_format" +title: "TimePickerHourFormat" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/timepickertheme.md b/website/docs/types/timepickertheme.md new file mode 100644 index 0000000000..97d9926332 --- /dev/null +++ b/website/docs/types/timepickertheme.md @@ -0,0 +1,7 @@ +--- +title: "TimePickerTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/tooltip.md b/website/docs/types/tooltip.md new file mode 100644 index 0000000000..f27574df4e --- /dev/null +++ b/website/docs/types/tooltip.md @@ -0,0 +1,15 @@ +--- +title: "Tooltip" +--- + +import {ClassAll, CodeExample, Image} from '@site/src/components/crocodocs'; + + + +## Examples + +### Tooltip with decoration + + + +with-decoration diff --git a/website/docs/types/tooltiptheme.md b/website/docs/types/tooltiptheme.md new file mode 100644 index 0000000000..159a31b14c --- /dev/null +++ b/website/docs/types/tooltiptheme.md @@ -0,0 +1,7 @@ +--- +title: "TooltipTheme" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/tooltiptriggermode.md b/website/docs/types/tooltiptriggermode.md new file mode 100644 index 0000000000..5d09d20621 --- /dev/null +++ b/website/docs/types/tooltiptriggermode.md @@ -0,0 +1,7 @@ +--- +title: "TooltipTriggerMode" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/transform.md b/website/docs/types/transform.md new file mode 100644 index 0000000000..67aff7424d --- /dev/null +++ b/website/docs/types/transform.md @@ -0,0 +1,7 @@ +--- +title: "Transform" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/underlinetabindicator.md b/website/docs/types/underlinetabindicator.md new file mode 100644 index 0000000000..1e873cc499 --- /dev/null +++ b/website/docs/types/underlinetabindicator.md @@ -0,0 +1,7 @@ +--- +title: "UnderlineTabIndicator" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/url.md b/website/docs/types/url.md new file mode 100644 index 0000000000..a0c823dd1d --- /dev/null +++ b/website/docs/types/url.md @@ -0,0 +1,7 @@ +--- +title: "Url" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/urltarget.md b/website/docs/types/urltarget.md new file mode 100644 index 0000000000..2aa2c12d24 --- /dev/null +++ b/website/docs/types/urltarget.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.UrlTarget" +examples: "controls/core/types/url_target" +title: "UrlTarget" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/use_route_loader_data.md b/website/docs/types/use_route_loader_data.md new file mode 100644 index 0000000000..7180e49442 --- /dev/null +++ b/website/docs/types/use_route_loader_data.md @@ -0,0 +1,7 @@ +--- +title: "use_route_loader_data" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/use_route_location.md b/website/docs/types/use_route_location.md new file mode 100644 index 0000000000..9da2fb590a --- /dev/null +++ b/website/docs/types/use_route_location.md @@ -0,0 +1,7 @@ +--- +title: "use_route_location" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/use_route_outlet.md b/website/docs/types/use_route_outlet.md new file mode 100644 index 0000000000..8b74416bb1 --- /dev/null +++ b/website/docs/types/use_route_outlet.md @@ -0,0 +1,7 @@ +--- +title: "use_route_outlet" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/use_route_params.md b/website/docs/types/use_route_params.md new file mode 100644 index 0000000000..f5b0c1365a --- /dev/null +++ b/website/docs/types/use_route_params.md @@ -0,0 +1,7 @@ +--- +title: "use_route_params" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/use_view_path.md b/website/docs/types/use_view_path.md new file mode 100644 index 0000000000..d150f2a917 --- /dev/null +++ b/website/docs/types/use_view_path.md @@ -0,0 +1,7 @@ +--- +title: "use_view_path" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/usecallback.md b/website/docs/types/usecallback.md new file mode 100644 index 0000000000..d1fa349dcd --- /dev/null +++ b/website/docs/types/usecallback.md @@ -0,0 +1,7 @@ +--- +title: "use_callback" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/usecontext.md b/website/docs/types/usecontext.md new file mode 100644 index 0000000000..d86629c3a6 --- /dev/null +++ b/website/docs/types/usecontext.md @@ -0,0 +1,7 @@ +--- +title: "use_context" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/usedialog.md b/website/docs/types/usedialog.md new file mode 100644 index 0000000000..5f9e2abc7f --- /dev/null +++ b/website/docs/types/usedialog.md @@ -0,0 +1,7 @@ +--- +title: "use_dialog" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/useeffect.md b/website/docs/types/useeffect.md new file mode 100644 index 0000000000..de3cde955d --- /dev/null +++ b/website/docs/types/useeffect.md @@ -0,0 +1,7 @@ +--- +title: "use_effect" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/usememo.md b/website/docs/types/usememo.md new file mode 100644 index 0000000000..ccace534c9 --- /dev/null +++ b/website/docs/types/usememo.md @@ -0,0 +1,7 @@ +--- +title: "use_memo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/useraccelerometerreadingevent.md b/website/docs/types/useraccelerometerreadingevent.md new file mode 100644 index 0000000000..70ce3119cb --- /dev/null +++ b/website/docs/types/useraccelerometerreadingevent.md @@ -0,0 +1,8 @@ +--- +class_name: "flet.UserAccelerometerReadingEvent" +title: "UserAccelerometerReadingEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/useref.md b/website/docs/types/useref.md new file mode 100644 index 0000000000..c0343e885b --- /dev/null +++ b/website/docs/types/useref.md @@ -0,0 +1,7 @@ +--- +title: "use_ref" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/usestate.md b/website/docs/types/usestate.md new file mode 100644 index 0000000000..cb03fdd3be --- /dev/null +++ b/website/docs/types/usestate.md @@ -0,0 +1,7 @@ +--- +title: "use_state" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/value.md b/website/docs/types/value.md new file mode 100644 index 0000000000..390eee7a87 --- /dev/null +++ b/website/docs/types/value.md @@ -0,0 +1,9 @@ +--- +title: "value" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + +# \@value + + diff --git a/website/docs/types/valuekey.md b/website/docs/types/valuekey.md new file mode 100644 index 0000000000..7b81905048 --- /dev/null +++ b/website/docs/types/valuekey.md @@ -0,0 +1,7 @@ +--- +title: "ValueKey" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/verticalalignment.md b/website/docs/types/verticalalignment.md new file mode 100644 index 0000000000..0fddb6d0d5 --- /dev/null +++ b/website/docs/types/verticalalignment.md @@ -0,0 +1,7 @@ +--- +title: "VerticalAlignment" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/viewpopevent.md b/website/docs/types/viewpopevent.md new file mode 100644 index 0000000000..1dca9a714b --- /dev/null +++ b/website/docs/types/viewpopevent.md @@ -0,0 +1,7 @@ +--- +title: "ViewPopEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/visualdensity.md b/website/docs/types/visualdensity.md new file mode 100644 index 0000000000..c6ae826f7c --- /dev/null +++ b/website/docs/types/visualdensity.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.VisualDensity" +examples: "controls/core/types/visual_density" +title: "VisualDensity" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/webbrowsername.md b/website/docs/types/webbrowsername.md new file mode 100644 index 0000000000..3d0794677a --- /dev/null +++ b/website/docs/types/webbrowsername.md @@ -0,0 +1,7 @@ +--- +title: "WebBrowserName" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/webdeviceinfo.md b/website/docs/types/webdeviceinfo.md new file mode 100644 index 0000000000..7623811a40 --- /dev/null +++ b/website/docs/types/webdeviceinfo.md @@ -0,0 +1,7 @@ +--- +title: "WebDeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/webrenderer.md b/website/docs/types/webrenderer.md new file mode 100644 index 0000000000..b527bc84c2 --- /dev/null +++ b/website/docs/types/webrenderer.md @@ -0,0 +1,21 @@ +--- +title: "WebRenderer" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + + +## Usage Example + +You can explicitly set what renderer to use when running a Flet program +in web mode using the `web_renderer` parameter of the `ft.run`. + +```python +import flet as ft + +def main(page: ft.Page): + ... + +ft.run(main, view=ft.AppView.WEB_BROWSER, web_renderer=ft.WebRenderer.CANVAS_KIT) +``` diff --git a/website/docs/types/webviewconfiguration.md b/website/docs/types/webviewconfiguration.md new file mode 100644 index 0000000000..8e8e5de66e --- /dev/null +++ b/website/docs/types/webviewconfiguration.md @@ -0,0 +1,7 @@ +--- +title: "WebViewConfiguration" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/window.md b/website/docs/types/window.md new file mode 100644 index 0000000000..e32b0b926f --- /dev/null +++ b/website/docs/types/window.md @@ -0,0 +1,7 @@ +--- +title: "Window" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/windowevent.md b/website/docs/types/windowevent.md new file mode 100644 index 0000000000..08bdf065d3 --- /dev/null +++ b/website/docs/types/windowevent.md @@ -0,0 +1,7 @@ +--- +title: "WindowEvent" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/windoweventtype.md b/website/docs/types/windoweventtype.md new file mode 100644 index 0000000000..79d6f2d656 --- /dev/null +++ b/website/docs/types/windoweventtype.md @@ -0,0 +1,17 @@ +--- +class_name: "flet.WindowEventType" +examples: "controls/core/types/window_event_type" +title: "WindowEventType" +--- + +import {ClassMembers, ClassSummary, CodeExample} from '@site/src/components/crocodocs'; + + + +## Examples + +### Showcase + + + + diff --git a/website/docs/types/windowresizeedge.md b/website/docs/types/windowresizeedge.md new file mode 100644 index 0000000000..547b81b2f2 --- /dev/null +++ b/website/docs/types/windowresizeedge.md @@ -0,0 +1,7 @@ +--- +title: "WindowResizeEdge" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docs/types/windowsdeviceinfo.md b/website/docs/types/windowsdeviceinfo.md new file mode 100644 index 0000000000..8598fe9ed0 --- /dev/null +++ b/website/docs/types/windowsdeviceinfo.md @@ -0,0 +1,7 @@ +--- +title: "WindowsDeviceInfo" +--- + +import {ClassAll} from '@site/src/components/crocodocs'; + + diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js new file mode 100644 index 0000000000..9bd28469d1 --- /dev/null +++ b/website/docusaurus.config.js @@ -0,0 +1,201 @@ +const TwitterSvg = + ''; + +const { themes } = require('prism-react-renderer'); + +module.exports = { + future: { + v4: true, // opt-in for Docusaurus v4 planned changes + faster: false, // turns Docusaurus Faster on globally + }, + title: 'Flet', + tagline: 'Build multi-platform apps in Python', + url: 'https://flet.dev', + baseUrl: '/', + favicon: 'img/favicon.ico', + organizationName: 'flet-dev', // Usually your GitHub org/user name. + projectName: 'flet', // Usually your repo name. + customFields: { + heroTitle: 'Build cross-platform apps in Python', + heroSubTitle: 'Easily build realtime web, mobile and desktop apps in pure Python. No frontend experience required.', + }, + themes: [ + 'docusaurus-theme-github-codeblock', + '@docusaurus/theme-mermaid', + ], + markdown: { + mermaid: true, + }, + plugins: ['@docsearch/docusaurus-adapter'], + themeConfig: { + docsearch: { + appId: 'ESNSJEY7OD', + apiKey: '4b060907ba79d92e8869e9d1ff80bce7', + indexName: 'flet', + // askAi: { + // assistantId: '48c9b8c8-278a-48b3-aa3e-ed18efad6fdd', + // agentStudio: true, + // sidePanel: true, + // }, + contextualSearch: true, + }, + // github codeblock theme configuration + codeblock: { + showGithubLink: true, + githubLinkLabel: 'View on GitHub', + showRunmeLink: false, + runmeLinkLabel: 'Checkout via Runme' + }, + docs: { + sidebar: { + hideable: true, + autoCollapseCategories: true, + } + }, + colorMode: { + defaultMode: 'light', + disableSwitch: false, + respectPrefersColorScheme: true, + }, + announcementBar: { + id: 'announcementBar-2', // Increment on change + content: `⭐️ If you like Flet, give it a star on GitHub and join the discussion on Discord.`, + }, + navbar: { + hideOnScroll: true, + title: 'Flet', + logo: { + alt: 'Flet Logo', + src: 'img/logo.svg', + srcDark: 'img/logo.svg', + }, + items: [ + { + to: 'docs', + activeBasePath: 'docs', + label: 'Docs', + position: 'left', + }, + { + to: 'gallery', + activeBasePath: 'gallery', + label: 'Gallery', + position: 'left', + }, + { + to: 'roadmap', + activeBasePath: 'roadmap', + label: 'Roadmap', + position: 'left', + }, + { + to: 'blog', + label: 'Blog', + position: 'left' + }, + { + href: 'https://github.com/flet-dev/flet', + position: 'right', + className: 'header-github-link', + 'aria-label': 'GitHub repository', + }, + ], + }, + prism: { + theme: themes.github, + darkTheme: themes.dracula, + additionalLanguages: ['python', 'yaml', 'toml', 'bash', 'dart'], + }, + footer: { + style: 'light', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Introduction', + to: '/docs', + }, + { + label: 'Reference', + to: '/docs/reference', + } + ], + }, + { + title: 'Community', + items: [ + { + label: 'Discord', + href: 'https://discord.gg/dzWXP8SHG8', + }, + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/flet', + }, + { + label: 'X', + href: 'https://x.com/fletdev', + }, + { + label: 'Bluesky', + href: 'https://bsky.app/profile/fletdev.bsky.social', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: '/blog', + }, + { + label: 'GitHub', + href: 'https://github.com/flet-dev/flet', + }, + { + label: 'Support', + href: '/support', + }, + ], + }, + { + title: 'Legal', + items: [ + { + label: 'Privacy policy', + to: 'privacy-policy', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} Appveyor Systems Inc. Built with Docusaurus.`, + }, + }, + presets: [ + [ + '@docusaurus/preset-classic', + { + docs: { + // It is recommended to set document id as docs home page (`docs/` path). + sidebarPath: require.resolve('./sidebars.js'), + remarkPlugins: [require('./plugins/remark-api-links'), require('./plugins/remark-code-annotations')], + editUrl: + 'https://github.com/flet-dev/flet/website/edit/main/', + }, + blog: { + blogSidebarTitle: 'All posts', + blogSidebarCount: 'ALL', + postsPerPage: 5, + showReadingTime: true, + editUrl: + 'https://github.com/flet-dev/flet/website/edit/main/', + }, + theme: { + customCss: require.resolve('./src/css/custom.css'), + }, + }, + ], + ], +}; diff --git a/website/functions/api/confirm-subscription.js b/website/functions/api/confirm-subscription.js new file mode 100644 index 0000000000..6f0948abb1 --- /dev/null +++ b/website/functions/api/confirm-subscription.js @@ -0,0 +1,50 @@ +import { sha1, callMailgunApi } from "./utils"; + +// Environment variables used in the handler: +// MAILGUN_API_KEY - Mailgun private API key +// MAILGUN_MAILING_LIST - Mailgun mailing list email address, e.g. news@mydomain.com +// CONFIRM_SECRET - A random value that is used to calculate email confirmation code + +// Function GET handler +export async function onRequestGet(context) { + const { request, env } = context; + + // get request params + const { searchParams } = new URL(request.url) + const email = searchParams.get('email') + const code = searchParams.get('code') + + if (!code || !email) { + throw "Invalid request parameters" + } + + // validate confirmation code + const calculatedCode = await sha1(email + env.CONFIRM_SECRET) + if (calculatedCode !== code) { + throw "Invalid email or confirmation code" + } + + // update subscription status + await subscribeMailingListMember(env.MAILGUN_API_KEY, env.MAILGUN_MAILING_LIST, email); + + // redirect to a home page + return Response.redirect(new URL(request.url).origin + "?signup-confirmed", 302) +} + +// Updates mailing list member's status to "subscribed=yes" +async function subscribeMailingListMember(mailgunApiKey, listName, memberAddress) { + const data = { + address: memberAddress, + subscribed: 'yes' + } + + const response = await callMailgunApi(mailgunApiKey, + 'PUT', `https://api.mailgun.net/v3/lists/${listName}/members/${encodeURIComponent(memberAddress)}`, data) + + if (response.status === 200) { + return true; // member has been subscribed + } else { + const responseBody = await response.text() + throw `Error updating mailing list member: ${responseBody}` + } +} \ No newline at end of file diff --git a/website/functions/api/email-signup.js b/website/functions/api/email-signup.js new file mode 100644 index 0000000000..62c949f746 --- /dev/null +++ b/website/functions/api/email-signup.js @@ -0,0 +1,123 @@ +import { urlEncodeObject, sha1, callMailgunApi } from "./utils"; +import { fromTemplate, subjectTemplate, bodyTemplate } from "./email-template" + +// Environment variables used in the handler: +// HCAPTCHA_SECRET - A secret corresponding to a site key and used to verify your hCaptcha account +// MAILGUN_API_KEY - Mailgun private API key +// MAILGUN_MAILING_LIST - Mailgun mailing list email address, e.g. news@mydomain.com +// CONFIRM_SECRET - A random value that is used to calculate email confirmation code + +// Function POST handler +export async function onRequestPost(context) { + const { request, env } = context; + const { headers } = request; + + // validate content type + const contentType = headers.get('content-type'); + if (!contentType.includes('application/json')) { + throw "Content type not recognized" + } + + // get request body + const reqBody = await request.json(); + const email = reqBody.email; + const captchaToken = reqBody.captchaToken; + + // verify parameters + if (!email || !captchaToken) { + throw "Invalid request parameters" + } + + // validate hCaptcha response + await validateCaptcha(captchaToken, env.HCAPTCHA_SECRET) + + // add email address to the mailing list + var added = await addMailingListMember(env.MAILGUN_API_KEY, env.MAILGUN_MAILING_LIST, email); + if (added) { + // build confirmation link + const urlParams = { + email: email, + code: await sha1(email + env.CONFIRM_SECRET) + } + const url = new URL(request.url); + + var templateData = { + confirmUrl: `${url.origin}/api/confirm-subscription?${urlEncodeObject(urlParams)}` + } + + // send email with a confirmation link + await sendEmail(env.MAILGUN_API_KEY, env.MAILGUN_MAILING_LIST.split('@').pop(), + fromTemplate(templateData), email, subjectTemplate(templateData), bodyTemplate(templateData)); + } + + // send successful response + return new Response(JSON.stringify({ result: "OK" }), { + headers: { 'content-type': 'application/json' } + }) +} + +// Validates hCaptcha response and throws if invalid +async function validateCaptcha(token, secret) { + const data = { + response: token, + secret: secret + } + + const encData = urlEncodeObject(data) + const captchaResponse = await fetch( + `https://hcaptcha.com/siteverify`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': encData.length.toString() + }, + body: encData + } + ) + const captchaBody = await captchaResponse.json() + if (!captchaBody.success) { + throw captchaBody["error-codes"] + } +} + +// Adds a new member (email address) into Mailgun mailing list +// returns `true` if the member was successfully added +// returns `false` if the member already exists in the list +async function addMailingListMember(mailgunApiKey, listName, memberAddress) { + const data = { + address: memberAddress, + subscribed: 'no', + upsert: 'no' + } + + const response = await callMailgunApi(mailgunApiKey, + 'POST', `https://api.mailgun.net/v3/lists/${listName}/members`, data) + + if (response.status === 200) { + return true; // member has been added + } else if (response.status === 400) { + return false; // member already added + } else { + const responseBody = await response.json() + throw `Error adding mailing list member: ${responseBody.message}` + } +} + +// Sends email message via Mailgun API +async function sendEmail(mailgunApiKey, mailDomain, from, to, subject, htmlBody) { + const data = { + from: from, + to: to, + subject: subject, + html: htmlBody + } + + const response = await callMailgunApi(mailgunApiKey, + 'POST', `https://api.mailgun.net/v3/${mailDomain}/messages`, data) + + if (response.status !== 200) { + const responseBody = await response.text() + throw `Error sending email message: ${responseBody}` + } +} diff --git a/website/functions/api/email-template.js b/website/functions/api/email-template.js new file mode 100644 index 0000000000..3cc25b6f41 --- /dev/null +++ b/website/functions/api/email-template.js @@ -0,0 +1,33 @@ +export function fromTemplate(data) { + return `Flet ` +} + +export function subjectTemplate(data) { + return `Confirm your subscription to Flet mailing list` +} + +export function bodyTemplate(data) { + return ` + + + + + + + Email Template + + + +

+ Click here to confirm your subscription to Flet project mailing list! +

+

+ If you didn't subscribe to this list or you're not sure why you received this email, you can delete it. You will not be subscribed if you don't click on the link above. +

+ + + ` +} \ No newline at end of file diff --git a/website/functions/api/utils.js b/website/functions/api/utils.js new file mode 100644 index 0000000000..a61d9b3f37 --- /dev/null +++ b/website/functions/api/utils.js @@ -0,0 +1,26 @@ +export function urlEncodeObject(obj) { + return Object.keys(obj) + .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(obj[k])) + .join('&') + } + +export async function sha1(str) { + var buffer = await crypto.subtle.digest("SHA-1", new TextEncoder("utf-8").encode(str)); + return Array.prototype.map.call(new Uint8Array(buffer), x=>(('00'+x.toString(16)).slice(-2))).join(''); +} + +export function callMailgunApi(mailgunApiKey, method, url, data) { + const encData = urlEncodeObject(data) + return fetch( + url, + { + method: method, + headers: { + Authorization: 'Basic ' + btoa('api:' + mailgunApiKey), + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': encData.length.toString() + }, + body: encData + } + ) + } \ No newline at end of file diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 0000000000..1b02e1c473 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,19298 @@ +{ + "name": "flet-dev", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "flet-dev", + "version": "0.0.0", + "dependencies": { + "@docusaurus/core": "^3.9.2", + "@docusaurus/plugin-client-redirects": "^3.9.2", + "@docusaurus/preset-classic": "^3.9.2", + "@hcaptcha/react-hcaptcha": "^1.0.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^1.1.1", + "docusaurus-theme-github-codeblock": "^2.0.2", + "prism-react-renderer": "^2.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "wrangler": "^0.0.7" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.15.2.tgz", + "integrity": "sha512-rF7vRVE61E0QORw8e2NNdnttcl3jmFMWS9B4hhdga12COe+lMa26bQLfcBn/Nbp9/AF/8gXdaRCPsVns3CnjsA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.19.2.tgz", + "integrity": "sha512-mKv7RyuAzXvwmq+0XRK8HqZXt9iZ5Kkm2huLjgn5JoCPtDy+oh9yxUMfDDaVCw0oyzZ1isdJBc7l9nuCyyR7Nw==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.19.2", + "@algolia/autocomplete-shared": "1.19.2" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz", + "integrity": "sha512-TjxbcC/r4vwmnZaPwrHtkXNeqvlpdyR+oR9Wi2XyfORkiGkLTVhX2j+O9SaCCINbKoDfc+c2PB8NjfOnz7+oKg==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.19.2" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz", + "integrity": "sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.49.2.tgz", + "integrity": "sha512-XyvKCm0RRmovMI/ChaAVjTwpZhXdbgt3iZofK914HeEHLqD1MUFFVLz7M0+Ou7F56UkHXwRbpHwb9xBDNopprQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.49.2.tgz", + "integrity": "sha512-jq/3qvtmj3NijZlhq7A1B0Cl41GfaBpjJxcwukGsYds6aMSCWrEAJ9pUqw/C9B3hAmILYKl7Ljz3N9SFvekD3Q==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.49.2.tgz", + "integrity": "sha512-bn0biLequn3epobCfjUqCxlIlurLr4RHu7RaE4trgN+RDcUq6HCVC3/yqq1hwbNYpVtulnTOJzcaxYlSr1fnuw==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.49.2.tgz", + "integrity": "sha512-z14wfFs1T3eeYbCArC8pvntAWsPo9f6hnUGoj8IoRUJTwgJiiySECkm8bmmV47/x0oGHfsVn3kBdjMX0yq0sNA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.49.2.tgz", + "integrity": "sha512-GpRf7yuuAX93+Qt0JGEJZwgtL0MFdjFO9n7dn8s2pA9mTjzl0Sc5+uTk1VPbIAuf7xhCP9Mve+URGb6J+EYxgA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.49.2.tgz", + "integrity": "sha512-HZwApmNkp0DiAjZcLYdQLddcG4Agb88OkojiAHGgcm5DVXobT5uSZ9lmyrbw/tmQBJwgu2CNw4zTyXoIB7YbPA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.49.2.tgz", + "integrity": "sha512-y1IOpG6OSmTpGg/CT0YBb/EAhR2nsC18QWp9Jy8HO9iGySpcwaTvs5kHa17daP3BMTwWyaX9/1tDTDQshZzXdg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/events": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@algolia/events/-/events-4.0.1.tgz", + "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==", + "license": "MIT" + }, + "node_modules/@algolia/ingestion": { + "version": "1.49.2", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.49.2.tgz", + "integrity": "sha512-YYJRjaZ2bqk923HxE4um7j/Cm3/xoSkF2HC2ZweOF8cXL3sqnlndSUYmCaxHFjNPWLaSHk2IfssX6J/tdKTULw==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.49.2", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.49.2.tgz", + "integrity": "sha512-9WgH+Dha39EQQyGKCHlGYnxW/7W19DIrEbCEbnzwAMpGAv1yTWCHMPXHxYa+LcL3eCp2V/5idD1zHNlIKmHRHg==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.49.2.tgz", + "integrity": "sha512-K7Gp5u+JtVYgaVpBxF5rGiM+Ia8SsMdcAJMTDV93rwh00DKNllC19o1g+PwrDjDvyXNrnTEbofzbTs2GLfFyKA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.49.2.tgz", + "integrity": "sha512-3UhYCcWX6fbtN8ABcxZlhaQEwXFh3CsFtARyyadQShHMPe3mJV9Wel4FpJTa+seugRkbezFz0tt6aPTZSYTBuA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.49.2.tgz", + "integrity": "sha512-G94VKSGbsr+WjsDDOBe5QDQ82QYgxvpxRGJfCHZBnYKYsy/jv9qGIDb93biza+LJWizQBUtDj7bZzp3QZyzhPQ==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.49.2.tgz", + "integrity": "sha512-UuihBGHafG/ENsrcTGAn5rsOffrCIRuHMOsD85fZGLEY92ate+BMTUqxz60dv5zerh8ZumN4bRm8eW2z9L11jA==", + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", + "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.6.tgz", + "integrity": "sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", + "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.6.tgz", + "integrity": "sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.28.6.tgz", + "integrity": "sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", + "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.6.tgz", + "integrity": "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.28.6.tgz", + "integrity": "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.6.tgz", + "integrity": "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.6.tgz", + "integrity": "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", + "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/template": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.28.6.tgz", + "integrity": "sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.6.tgz", + "integrity": "sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.6.tgz", + "integrity": "sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.28.6.tgz", + "integrity": "sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.6.tgz", + "integrity": "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.0.tgz", + "integrity": "sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.0.tgz", + "integrity": "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.28.6.tgz", + "integrity": "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", + "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.6.tgz", + "integrity": "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.28.6.tgz", + "integrity": "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.6.tgz", + "integrity": "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.28.6.tgz", + "integrity": "sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.28.6.tgz", + "integrity": "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.28.6.tgz", + "integrity": "sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/plugin-syntax-jsx": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.0.tgz", + "integrity": "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.28.6.tgz", + "integrity": "sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.0.tgz", + "integrity": "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", + "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.28.6.tgz", + "integrity": "sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.28.6.tgz", + "integrity": "sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.28.5", + "@babel/helper-plugin-utils": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", + "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", + "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.29.2.tgz", + "integrity": "sha512-Lc94FOD5+0aXhdb0Tdg3RUtqT6yWbI/BbFWvlaSJ3gAb9Ks+99nHRDKADVqC37er4eCB0fHyWT+y+K3QOvJKbw==", + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.48.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/cascade-layer-name-parser": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@csstools/cascade-layer-name-parser/-/cascade-layer-name-parser-2.0.5.tgz", + "integrity": "sha512-p1ko5eHgV+MgXFVa4STPKpvPxr6ReS8oS2jzTukjR74i5zJNyWO1ZM1m8YKBXnzDKWfBN1ztLYlHxbVemDD88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/postcss-alpha-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-alpha-function/-/postcss-alpha-function-1.0.1.tgz", + "integrity": "sha512-isfLLwksH3yHkFXfCI2Gcaqg7wGGHZZwunoJzEZk0yKYIokgre6hYVFibKL3SYAoR1kBXova8LB+JoO5vZzi9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-5.0.2.tgz", + "integrity": "sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-4.0.12.tgz", + "integrity": "sha512-yx3cljQKRaSBc2hfh8rMZFZzChaFgwmO2JfFgFr1vMcF3C/uyy5I4RFIBOIWGq1D+XbKCG789CGkG6zzkLpagA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-function-display-p3-linear": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function-display-p3-linear/-/postcss-color-function-display-p3-linear-1.0.1.tgz", + "integrity": "sha512-E5qusdzhlmO1TztYzDIi8XPdPoYOjoTY6HBYBCYSj+Gn4gQRBlvjgPQXzfzuPQqt8EhkC/SzPKObg4Mbn8/xMg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-function": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-function/-/postcss-color-mix-function-3.0.12.tgz", + "integrity": "sha512-4STERZfCP5Jcs13P1U5pTvI9SkgLgfMUMhdXW8IlJWkzOOOqhZIjcNhWtNJZes2nkBDsIKJ0CJtFtuaZ00moag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-color-mix-variadic-function-arguments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-mix-variadic-function-arguments/-/postcss-color-mix-variadic-function-arguments-1.0.2.tgz", + "integrity": "sha512-rM67Gp9lRAkTo+X31DUqMEq+iK+EFqsidfecmhrteErxJZb6tUoJBVQca1Vn1GpDql1s1rD1pKcuYzMsg7Z1KQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-content-alt-text": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@csstools/postcss-content-alt-text/-/postcss-content-alt-text-2.0.8.tgz", + "integrity": "sha512-9SfEW9QCxEpTlNMnpSqFaHyzsiRpZ5J5+KqCu1u5/eEJAWsMhzT40qf0FIbeeglEvrGRMdDzAxMIz3wqoGSb+Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-contrast-color-function": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-contrast-color-function/-/postcss-contrast-color-function-2.0.12.tgz", + "integrity": "sha512-YbwWckjK3qwKjeYz/CijgcS7WDUCtKTd8ShLztm3/i5dhh4NaqzsbYnhm4bjrpFpnLZ31jVcbK8YL77z3GBPzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-exponential-functions": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-exponential-functions/-/postcss-exponential-functions-2.0.9.tgz", + "integrity": "sha512-abg2W/PI3HXwS/CZshSa79kNWNZHdJPMBXeZNyPQFbbj8sKO3jXxOt/wF7juJVjyDTc6JrvaUZYFcSBZBhaxjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-4.0.0.tgz", + "integrity": "sha512-usBzw9aCRDvchpok6C+4TXC57btc4bJtmKQWOHQxOVKen1ZfVqBUuCZ/wuqdX5GHsD0NRSr9XTP+5ID1ZZQBXw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gamut-mapping": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gamut-mapping/-/postcss-gamut-mapping-2.0.11.tgz", + "integrity": "sha512-fCpCUgZNE2piVJKC76zFsgVW1apF6dpYsqGyH8SIeCcM4pTEsRTWTLCaJIMKFEundsCKwY1rwfhtrio04RJ4Dw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-gradients-interpolation-method": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-gradients-interpolation-method/-/postcss-gradients-interpolation-method-5.0.12.tgz", + "integrity": "sha512-jugzjwkUY0wtNrZlFeyXzimUL3hN4xMvoPnIXxoZqxDvjZRiSh+itgHcVUWzJ2VwD/VAMEgCLvtaJHX+4Vj3Ow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-4.0.12.tgz", + "integrity": "sha512-mL/+88Z53KrE4JdePYFJAQWFrcADEqsLprExCM04GDNgHIztwFzj0Mbhd/yxMBngq0NIlz58VVxjt5abNs1VhA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-4.0.4.tgz", + "integrity": "sha512-yQ4VmossuOAql65sCPppVO1yfb7hDscf4GseF0VCA/DTDaBc0Wtf8MTqVPfjGYlT5+2buokG0Gp7y0atYZpwjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-initial": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-initial/-/postcss-initial-2.0.1.tgz", + "integrity": "sha512-L1wLVMSAZ4wovznquK0xmC7QSctzO4D0Is590bxpGqhqjboLXYA16dWZpfwImkdOgACdQ9PqXsuRroW6qPlEsg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-5.0.3.tgz", + "integrity": "sha512-jS/TY4SpG4gszAtIg7Qnf3AS2pjcUM5SzxpApOrlndMeGhIbaTzWBzzP/IApXoNWEW7OhcjkRT48jnAUIFXhAQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-light-dark-function": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@csstools/postcss-light-dark-function/-/postcss-light-dark-function-2.0.11.tgz", + "integrity": "sha512-fNJcKXJdPM3Lyrbmgw2OBbaioU7yuKZtiXClf4sGdQttitijYlZMD5K7HrC/eF83VRWRrYq6OZ0Lx92leV2LFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-float-and-clear": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-float-and-clear/-/postcss-logical-float-and-clear-3.0.0.tgz", + "integrity": "sha512-SEmaHMszwakI2rqKRJgE+8rpotFfne1ZS6bZqBoQIicFyV+xT1UF42eORPxJkVJVrH9C0ctUgwMSn3BLOIZldQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overflow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overflow/-/postcss-logical-overflow-2.0.0.tgz", + "integrity": "sha512-spzR1MInxPuXKEX2csMamshR4LRaSZ3UXVaRGjeQxl70ySxOhMpP2252RAFsg8QyyBXBzuVOOdx1+bVO5bPIzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-overscroll-behavior": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-overscroll-behavior/-/postcss-logical-overscroll-behavior-2.0.0.tgz", + "integrity": "sha512-e/webMjoGOSYfqLunyzByZj5KKe5oyVg/YSbie99VEaSDE2kimFm0q1f6t/6Jo+VVCQ/jbe2Xy+uX+C4xzWs4w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-resize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-resize/-/postcss-logical-resize-3.0.0.tgz", + "integrity": "sha512-DFbHQOFW/+I+MY4Ycd/QN6Dg4Hcbb50elIJCfnwkRTCX05G11SwViI5BbBlg9iHRl4ytB7pmY5ieAFk3ws7yyg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-logical-viewport-units": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-logical-viewport-units/-/postcss-logical-viewport-units-3.0.4.tgz", + "integrity": "sha512-q+eHV1haXA4w9xBwZLKjVKAWn3W2CMqmpNpZUk5kRprvSiBEGMgrNH3/sJZ8UA3JgyHaOt3jwT9uFa4wLX4EqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-minmax": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-minmax/-/postcss-media-minmax-2.0.9.tgz", + "integrity": "sha512-af9Qw3uS3JhYLnCbqtZ9crTvvkR+0Se+bBqSr7ykAnl9yKhk6895z9rf+2F4dClIDJWxgn0iZZ1PSdkhrbs2ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-media-queries-aspect-ratio-number-values": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/postcss-media-queries-aspect-ratio-number-values/-/postcss-media-queries-aspect-ratio-number-values-3.0.5.tgz", + "integrity": "sha512-zhAe31xaaXOY2Px8IYfoVTB3wglbJUVigGphFLj6exb7cjZRH9A6adyE22XfFK3P2PzwRk0VDeTJmaxpluyrDg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-4.0.0.tgz", + "integrity": "sha512-jMYDdqrQQxE7k9+KjstC3NbsmC063n1FTPLCgCRS2/qHUbHM0mNy9pIn4QIiQGs9I/Bg98vMqw7mJXBxa0N88A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.1.tgz", + "integrity": "sha512-TQUGBuRvxdc7TgNSTevYqrL8oItxiwPDixk20qCB5me/W8uF7BPbhRrAvFuhEoywQp/woRsUZ6SJ+sU5idZAIA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.12.tgz", + "integrity": "sha512-HhlSmnE1NKBhXsTnNGjxvhryKtO7tJd1w42DKOGFD6jSHtYOrsJTQDKPMwvOfrzUAk8t7GcpIfRyM7ssqHpFjg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-position-area-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-position-area-property/-/postcss-position-area-property-1.0.0.tgz", + "integrity": "sha512-fUP6KR8qV2NuUZV3Cw8itx0Ep90aRjAZxAEzC3vrl6yjFv+pFsQbR18UuQctEKmA72K9O27CoYiKEgXxkqjg8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.2.1.tgz", + "integrity": "sha512-uPiiXf7IEKtUQXsxu6uWtOlRMXd2QWWy5fhxHDnPdXKCQckPP3E34ZgDoZ62r2iT+UOgWsSbM4NvHE5m3mAEdw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-property-rule-prelude-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-property-rule-prelude-list/-/postcss-property-rule-prelude-list-1.0.0.tgz", + "integrity": "sha512-IxuQjUXq19fobgmSSvUDO7fVwijDJaZMvWQugxfEUxmjBeDCVaDuMpsZ31MsTm5xbnhA+ElDi0+rQ7sQQGisFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-random-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-random-function/-/postcss-random-function-2.0.1.tgz", + "integrity": "sha512-q+FQaNiRBhnoSNo+GzqGOIBKoHQ43lYz0ICrV+UudfWnEF6ksS6DsBIJSISKQT2Bvu3g4k6r7t0zYrk5pDlo8w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-relative-color-syntax": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/@csstools/postcss-relative-color-syntax/-/postcss-relative-color-syntax-3.0.12.tgz", + "integrity": "sha512-0RLIeONxu/mtxRtf3o41Lq2ghLimw0w9ByLWnnEVuy89exmEEq8bynveBxNW3nyHqLAFEeNtVEmC1QK9MZ8Huw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-scope-pseudo-class/-/postcss-scope-pseudo-class-4.0.1.tgz", + "integrity": "sha512-IMi9FwtH6LMNuLea1bjVMQAsUhFxJnyLSgOp/cpv5hrzWmrUYU5fm0EguNDIIOHUqzXode8F/1qkC/tEo/qN8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@csstools/postcss-sign-functions": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/postcss-sign-functions/-/postcss-sign-functions-1.1.4.tgz", + "integrity": "sha512-P97h1XqRPcfcJndFdG95Gv/6ZzxUBBISem0IDqPZ7WMvc/wlO+yU0c5D/OCpZ5TJoTt63Ok3knGk64N+o6L2Pg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-4.0.9.tgz", + "integrity": "sha512-h9btycWrsex4dNLeQfyU3y3w40LMQooJWFMm/SK9lrKguHDcFl4VMkncKKoXi2z5rM9YGWbUQABI8BT2UydIcA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-syntax-descriptor-syntax-production": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-syntax-descriptor-syntax-production/-/postcss-syntax-descriptor-syntax-production-1.0.1.tgz", + "integrity": "sha512-GneqQWefjM//f4hJ/Kbox0C6f2T7+pi4/fqTqOFGTL3EjnvOReTqO1qUQ30CaUjkwjYq9qZ41hzarrAxCc4gow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-system-ui-font-family": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-system-ui-font-family/-/postcss-system-ui-font-family-1.0.0.tgz", + "integrity": "sha512-s3xdBvfWYfoPSBsikDXbuorcMG1nN1M6GdU0qBsGfcmNR0A/qhloQZpTxjA3Xsyrk1VJvwb2pOfiOT3at/DuIQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-4.0.3.tgz", + "integrity": "sha512-KSkGgZfx0kQjRIYnpsD7X2Om9BUXX/Kii77VBifQW9Ih929hK0KNjVngHDH0bFB9GmfWcR9vJYJJRvw/NQjkrA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/color-helpers": "^5.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-4.0.9.tgz", + "integrity": "sha512-Hnh5zJUdpNrJqK9v1/E3BbrQhaDTj5YiX7P61TOvUhoDHnUmsNNxcDAgkQ32RrcWx9GVUvfUNPcUkn8R3vIX6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-calc": "^2.1.4", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-4.0.0.tgz", + "integrity": "sha512-cBz3tOCI5Fw6NIFEwU3RiwK6mn3nKegjpJuzCndoGq3BZPkUjnsq7uQmIeMNeMbMk7YD2MfKcgCpZwX5jyXqCA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@csstools/utilities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/utilities/-/utilities-2.0.0.tgz", + "integrity": "sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docsearch/core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/core/-/core-4.6.0.tgz", + "integrity": "sha512-IqG3oSd529jVRQ4dWZQKwZwQLVd//bWJTz2HiL0LkiHrI4U/vLrBasKB7lwQB/69nBAcCgs3TmudxTZSLH/ZQg==", + "license": "MIT", + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@docsearch/css": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.0.tgz", + "integrity": "sha512-YlcAimkXclvqta47g47efzCM5CFxDwv2ClkDfEs/fC/Ak0OxPH2b3czwa4o8O1TRBf+ujFF2RiUwszz2fPVNJQ==", + "license": "MIT" + }, + "node_modules/@docsearch/react": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-4.6.0.tgz", + "integrity": "sha512-j8H5B4ArGxBPBWvw3X0J0Rm/Pjv2JDa2rV5OE0DLTp5oiBCptIJ/YlNOhZxuzbO2nwge+o3Z52nJRi3hryK9cA==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-core": "1.19.2", + "@docsearch/core": "4.6.0", + "@docsearch/css": "4.6.0" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@docusaurus/babel": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/babel/-/babel-3.9.2.tgz", + "integrity": "sha512-GEANdi/SgER+L7Japs25YiGil/AUDnFFHaCGPBbundxoWtCkA2lmy7/tFmgED4y1htAy6Oi4wkJEQdGssnw9MA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.25.9", + "@babel/preset-env": "^7.25.9", + "@babel/preset-react": "^7.25.9", + "@babel/preset-typescript": "^7.25.9", + "@babel/runtime": "^7.25.9", + "@babel/runtime-corejs3": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "babel-plugin-dynamic-import-node": "^2.3.3", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/bundler": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/bundler/-/bundler-3.9.2.tgz", + "integrity": "sha512-ZOVi6GYgTcsZcUzjblpzk3wH1Fya2VNpd5jtHoCCFcJlMQ1EYXZetfAnRHLcyiFeBABaI1ltTYbOBtH/gahGVA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.9", + "@docusaurus/babel": "3.9.2", + "@docusaurus/cssnano-preset": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "babel-loader": "^9.2.1", + "clean-css": "^5.3.3", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.11.0", + "css-minimizer-webpack-plugin": "^5.0.1", + "cssnano": "^6.1.2", + "file-loader": "^6.2.0", + "html-minifier-terser": "^7.2.0", + "mini-css-extract-plugin": "^2.9.2", + "null-loader": "^4.0.1", + "postcss": "^8.5.4", + "postcss-loader": "^7.3.4", + "postcss-preset-env": "^10.2.1", + "terser-webpack-plugin": "^5.3.9", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "webpack": "^5.95.0", + "webpackbar": "^6.0.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/faster": "*" + }, + "peerDependenciesMeta": { + "@docusaurus/faster": { + "optional": true + } + } + }, + "node_modules/@docusaurus/core": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-3.9.2.tgz", + "integrity": "sha512-HbjwKeC+pHUFBfLMNzuSjqFE/58+rLVKmOU3lxQrpsxLBOGosYco/Q0GduBb0/jEMRiyEqjNT/01rRdOMWq5pw==", + "license": "MIT", + "dependencies": { + "@docusaurus/babel": "3.9.2", + "@docusaurus/bundler": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "boxen": "^6.2.1", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cli-table3": "^0.6.3", + "combine-promises": "^1.1.0", + "commander": "^5.1.0", + "core-js": "^3.31.1", + "detect-port": "^1.5.1", + "escape-html": "^1.0.3", + "eta": "^2.2.0", + "eval": "^0.1.8", + "execa": "5.1.1", + "fs-extra": "^11.1.1", + "html-tags": "^3.3.1", + "html-webpack-plugin": "^5.6.0", + "leven": "^3.1.0", + "lodash": "^4.17.21", + "open": "^8.4.0", + "p-map": "^4.0.0", + "prompts": "^2.4.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0", + "react-loadable-ssr-addon-v5-slorber": "^1.0.1", + "react-router": "^5.3.4", + "react-router-config": "^5.1.1", + "react-router-dom": "^5.3.4", + "semver": "^7.5.4", + "serve-handler": "^6.1.6", + "tinypool": "^1.0.2", + "tslib": "^2.6.0", + "update-notifier": "^6.0.2", + "webpack": "^5.95.0", + "webpack-bundle-analyzer": "^4.10.2", + "webpack-dev-server": "^5.2.2", + "webpack-merge": "^6.0.1" + }, + "bin": { + "docusaurus": "bin/docusaurus.mjs" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@mdx-js/react": "^3.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/cssnano-preset": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-3.9.2.tgz", + "integrity": "sha512-8gBKup94aGttRduABsj7bpPFTX7kbwu+xh3K9NMCF5K4bWBqTFYW+REKHF6iBVDHRJ4grZdIPbvkiHd/XNKRMQ==", + "license": "MIT", + "dependencies": { + "cssnano-preset-advanced": "^6.1.2", + "postcss": "^8.5.4", + "postcss-sort-media-queries": "^5.2.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/logger": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-3.9.2.tgz", + "integrity": "sha512-/SVCc57ByARzGSU60c50rMyQlBuMIJCjcsJlkphxY6B0GV4UH3tcA1994N8fFfbJ9kX3jIBe/xg3XP5qBtGDbA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/mdx-loader": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-3.9.2.tgz", + "integrity": "sha512-wiYoGwF9gdd6rev62xDU8AAM8JuLI/hlwOtCzMmYcspEkzecKrP8J8X+KpYnTlACBUUtXNJpSoCwFWJhLRevzQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "@mdx-js/mdx": "^3.0.0", + "@slorber/remark-comment": "^1.0.0", + "escape-html": "^1.0.3", + "estree-util-value-to-estree": "^3.0.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "image-size": "^2.0.2", + "mdast-util-mdx": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "rehype-raw": "^7.0.0", + "remark-directive": "^3.0.0", + "remark-emoji": "^4.0.0", + "remark-frontmatter": "^5.0.0", + "remark-gfm": "^4.0.0", + "stringify-object": "^3.3.0", + "tslib": "^2.6.0", + "unified": "^11.0.3", + "unist-util-visit": "^5.0.0", + "url-loader": "^4.1.1", + "vfile": "^6.0.1", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/module-type-aliases": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz", + "integrity": "sha512-8qVe2QA9hVLzvnxP46ysuofJUIc/yYQ82tvA/rBTrnpXtCjNSFLxEZfd5U8cYZuJIVlkPxamsIgwd5tGZXfvew==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.9.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "@types/react-router-dom": "*", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "react-loadable": "npm:@docusaurus/react-loadable@6.0.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@docusaurus/plugin-client-redirects": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-3.9.2.tgz", + "integrity": "sha512-lUgMArI9vyOYMzLRBUILcg9vcPTCyyI2aiuXq/4npcMVqOr6GfmwtmBYWSbNMlIUM0147smm4WhpXD0KFboffw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-blog": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.9.2.tgz", + "integrity": "sha512-3I2HXy3L1QcjLJLGAoTvoBnpOwa6DPUa3Q0dMK19UTY9mhPkKQg/DYhAGTiBUKcTR0f08iw7kLPqOhIgdV3eVQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "cheerio": "1.0.0-rc.12", + "feed": "^4.2.2", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "srcset": "^4.0.0", + "tslib": "^2.6.0", + "unist-util-visit": "^5.0.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-docs": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz", + "integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/module-type-aliases": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "@types/react-router-config": "^5.0.7", + "combine-promises": "^1.1.0", + "fs-extra": "^11.1.1", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "schema-dts": "^1.1.2", + "tslib": "^2.6.0", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-content-pages": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.9.2.tgz", + "integrity": "sha512-s4849w/p4noXUrGpPUF0BPqIAfdAe76BLaRGAGKZ1gTDNiGxGcpsLcwJ9OTi1/V8A+AzvsmI9pkjie2zjIQZKA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "fs-extra": "^11.1.1", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-css-cascade-layers": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.9.2.tgz", + "integrity": "sha512-w1s3+Ss+eOQbscGM4cfIFBlVg/QKxyYgj26k5AnakuHkKxH6004ZtuLe5awMBotIYF2bbGDoDhpgQ4r/kcj4rQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/plugin-debug": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-3.9.2.tgz", + "integrity": "sha512-j7a5hWuAFxyQAkilZwhsQ/b3T7FfHZ+0dub6j/GxKNFJp2h9qk/P1Bp7vrGASnvA9KNQBBL1ZXTe7jlh4VdPdA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "fs-extra": "^11.1.1", + "react-json-view-lite": "^2.3.0", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-analytics": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.9.2.tgz", + "integrity": "sha512-mAwwQJ1Us9jL/lVjXtErXto4p4/iaLlweC54yDUK1a97WfkC6Z2k5/769JsFgwOwOP+n5mUQGACXOEQ0XDuVUw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-gtag": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.9.2.tgz", + "integrity": "sha512-YJ4lDCphabBtw19ooSlc1MnxtYGpjFV9rEdzjLsUnBCeis2djUyCozZaFhCg6NGEwOn7HDDyMh0yzcdRpnuIvA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "@types/gtag.js": "^0.0.12", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-google-tag-manager": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.9.2.tgz", + "integrity": "sha512-LJtIrkZN/tuHD8NqDAW1Tnw0ekOwRTfobWPsdO15YxcicBo2ykKF0/D6n0vVBfd3srwr9Z6rzrIWYrMzBGrvNw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-sitemap": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.9.2.tgz", + "integrity": "sha512-WLh7ymgDXjG8oPoM/T4/zUP7KcSuFYRZAUTl8vR6VzYkfc18GBM4xLhcT+AKOwun6kBivYKUJf+vlqYJkm+RHw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "fs-extra": "^11.1.1", + "sitemap": "^7.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/plugin-svgr": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-svgr/-/plugin-svgr-3.9.2.tgz", + "integrity": "sha512-n+1DE+5b3Lnf27TgVU5jM1d4x5tUh2oW5LTsBxJX4PsAPV0JGcmI6p3yLYtEY0LRVEIJh+8RsdQmRE66wSV8mw==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "@svgr/core": "8.1.0", + "@svgr/webpack": "^8.1.0", + "tslib": "^2.6.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/preset-classic": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-3.9.2.tgz", + "integrity": "sha512-IgyYO2Gvaigi21LuDIe+nvmN/dfGXAiMcV/murFqcpjnZc7jxFAxW+9LEjdPt61uZLxG4ByW/oUmX/DDK9t/8w==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/plugin-content-blog": "3.9.2", + "@docusaurus/plugin-content-docs": "3.9.2", + "@docusaurus/plugin-content-pages": "3.9.2", + "@docusaurus/plugin-css-cascade-layers": "3.9.2", + "@docusaurus/plugin-debug": "3.9.2", + "@docusaurus/plugin-google-analytics": "3.9.2", + "@docusaurus/plugin-google-gtag": "3.9.2", + "@docusaurus/plugin-google-tag-manager": "3.9.2", + "@docusaurus/plugin-sitemap": "3.9.2", + "@docusaurus/plugin-svgr": "3.9.2", + "@docusaurus/theme-classic": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/theme-search-algolia": "3.9.2", + "@docusaurus/types": "3.9.2" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-3.9.2.tgz", + "integrity": "sha512-IGUsArG5hhekXd7RDb11v94ycpJpFdJPkLnt10fFQWOVxAtq5/D7hT6lzc2fhyQKaaCE62qVajOMKL7OiAFAIA==", + "license": "MIT", + "dependencies": { + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/module-type-aliases": "3.9.2", + "@docusaurus/plugin-content-blog": "3.9.2", + "@docusaurus/plugin-content-docs": "3.9.2", + "@docusaurus/plugin-content-pages": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/theme-translations": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "@mdx-js/react": "^3.0.0", + "clsx": "^2.0.0", + "infima": "0.2.0-alpha.45", + "lodash": "^4.17.21", + "nprogress": "^0.2.0", + "postcss": "^8.5.4", + "prism-react-renderer": "^2.3.0", + "prismjs": "^1.29.0", + "react-router-dom": "^5.3.4", + "rtlcss": "^4.1.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-classic/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@docusaurus/theme-common": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.9.2.tgz", + "integrity": "sha512-6c4DAbR6n6nPbnZhY2V3tzpnKnGL+6aOsLvFL26VRqhlczli9eWG0VDUNoCQEPnGwDMhPS42UhSAnz5pThm5Ag==", + "license": "MIT", + "dependencies": { + "@docusaurus/mdx-loader": "3.9.2", + "@docusaurus/module-type-aliases": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router-config": "*", + "clsx": "^2.0.0", + "parse-numeric-range": "^1.3.0", + "prism-react-renderer": "^2.3.0", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "@docusaurus/plugin-content-docs": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-common/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@docusaurus/theme-search-algolia": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.9.2.tgz", + "integrity": "sha512-GBDSFNwjnh5/LdkxCKQHkgO2pIMX1447BxYUBG2wBiajS21uj64a+gH/qlbQjDLxmGrbrllBrtJkUHxIsiwRnw==", + "license": "MIT", + "dependencies": { + "@docsearch/react": "^3.9.0 || ^4.1.0", + "@docusaurus/core": "3.9.2", + "@docusaurus/logger": "3.9.2", + "@docusaurus/plugin-content-docs": "3.9.2", + "@docusaurus/theme-common": "3.9.2", + "@docusaurus/theme-translations": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-validation": "3.9.2", + "algoliasearch": "^5.37.0", + "algoliasearch-helper": "^3.26.0", + "clsx": "^2.0.0", + "eta": "^2.2.0", + "fs-extra": "^11.1.1", + "lodash": "^4.17.21", + "tslib": "^2.6.0", + "utility-types": "^3.10.0" + }, + "engines": { + "node": ">=20.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/theme-search-algolia/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@docusaurus/theme-translations": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-3.9.2.tgz", + "integrity": "sha512-vIryvpP18ON9T9rjgMRFLr2xJVDpw1rtagEGf8Ccce4CkTrvM/fRB8N2nyWYOW5u3DdjkwKw5fBa+3tbn9P4PA==", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.1", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-3.9.2.tgz", + "integrity": "sha512-Ux1JUNswg+EfUEmajJjyhIohKceitY/yzjRUpu04WXgvVz+fbhVC0p+R0JhvEu4ytw8zIAys2hrdpQPBHRIa8Q==", + "license": "MIT", + "dependencies": { + "@mdx-js/mdx": "^3.0.0", + "@types/history": "^4.7.11", + "@types/mdast": "^4.0.2", + "@types/react": "*", + "commander": "^5.1.0", + "joi": "^17.9.2", + "react-helmet-async": "npm:@slorber/react-helmet-async@1.3.0", + "utility-types": "^3.10.0", + "webpack": "^5.95.0", + "webpack-merge": "^5.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@docusaurus/types/node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@docusaurus/utils": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-3.9.2.tgz", + "integrity": "sha512-lBSBiRruFurFKXr5Hbsl2thmGweAPmddhF3jb99U4EMDA5L+e5Y1rAkOS07Nvrup7HUMBDrCV45meaxZnt28nQ==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.9.2", + "@docusaurus/types": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "escape-string-regexp": "^4.0.0", + "execa": "5.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^11.1.1", + "github-slugger": "^1.5.0", + "globby": "^11.1.0", + "gray-matter": "^4.0.3", + "jiti": "^1.20.0", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "micromatch": "^4.0.5", + "p-queue": "^6.6.2", + "prompts": "^2.4.2", + "resolve-pathname": "^3.0.0", + "tslib": "^2.6.0", + "url-loader": "^4.1.1", + "utility-types": "^3.10.0", + "webpack": "^5.88.1" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-common": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-3.9.2.tgz", + "integrity": "sha512-I53UC1QctruA6SWLvbjbhCpAw7+X7PePoe5pYcwTOEXD/PxeP8LnECAhTHHwWCblyUX5bMi4QLRkxvyZ+IT8Aw==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "3.9.2", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@docusaurus/utils-validation": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-3.9.2.tgz", + "integrity": "sha512-l7yk3X5VnNmATbwijJkexdhulNsQaNDwoagiwujXoxFbWLcxHQqNQ+c/IAlzrfMMOfa/8xSBZ7KEKDesE/2J7A==", + "license": "MIT", + "dependencies": { + "@docusaurus/logger": "3.9.2", + "@docusaurus/utils": "3.9.2", + "@docusaurus/utils-common": "3.9.2", + "fs-extra": "^11.2.0", + "joi": "^17.9.2", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "tslib": "^2.6.0" + }, + "engines": { + "node": ">=20.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@hcaptcha/loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.0.0.tgz", + "integrity": "sha512-fFQH6ApU/zCCl6Y1bnbsxsp1Er/lKX+qlgljrpWDeFcenpEtoP68hExlKSXECospzKLeSWcr06cbTjlR/x3IJA==", + "license": "MIT" + }, + "node_modules/@hcaptcha/react-hcaptcha": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@hcaptcha/react-hcaptcha/-/react-hcaptcha-1.12.0.tgz", + "integrity": "sha512-QiHnQQ52k8SJJSHkc3cq4TlYzag7oPd4f5ZqnjVSe4fJDSlZaOQFtu5F5AYisVslwaitdDELPVLRsRJxiiI0Aw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.9", + "@hcaptcha/loader": "^2.0.0" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "license": "ISC" + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/buffers": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.1.tgz", + "integrity": "sha512-YrEi/ZPmgc+GfdO0esBF04qv8boK9Dg9WpRQw/+vM8Qt3nnVIJWIa8HwZ/LXVZ0DB11XUROM8El/7yYTJX+WtA==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.1", + "@jsonjoy.com/fs-node-utils": "4.57.1", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.1.tgz", + "integrity": "sha512-ooEPvSW/HQDivPDPZMibHGKZf/QS4WRir1czGZmXmp3MsQqLECZEpN0JobrD8iV9BzsuwdIv+PxtWX9WpPLsIA==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.1", + "@jsonjoy.com/fs-node-builtins": "4.57.1", + "@jsonjoy.com/fs-node-utils": "4.57.1", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.1.tgz", + "integrity": "sha512-3YaKhP8gXEKN+2O49GLNfNb5l2gbnCFHyAaybbA2JkkbQP3dpdef7WcUaHAulg/c5Dg4VncHsA3NWAUSZMR5KQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.1", + "@jsonjoy.com/fs-node-builtins": "4.57.1", + "@jsonjoy.com/fs-node-utils": "4.57.1", + "@jsonjoy.com/fs-print": "4.57.1", + "@jsonjoy.com/fs-snapshot": "4.57.1", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.1.tgz", + "integrity": "sha512-XHkFKQ5GSH3uxm8c3ZYXVrexGdscpWKIcMWKFQpMpMJc8gA3AwOMBJXJlgpdJqmrhPyQXxaY9nbkNeYpacC0Og==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.1.tgz", + "integrity": "sha512-pqGHyWWzNck4jRfaGV39hkqpY5QjRUQ/nRbNT7FYbBa0xf4bDG+TE1Gt2KWZrSkrkZZDE3qZUjYMbjwSliX6pg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-fsa": "4.57.1", + "@jsonjoy.com/fs-node-builtins": "4.57.1", + "@jsonjoy.com/fs-node-utils": "4.57.1" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.1.tgz", + "integrity": "sha512-vp+7ZzIB8v43G+GLXTS4oDUSQmhAsRz532QmmWBbdYA20s465JvwhkSFvX9cVTqRRAQg+vZ7zWDaIEh0lFe2gw==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.1" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.1.tgz", + "integrity": "sha512-Ynct7ZJmfk6qoXDOKfpovNA36ITUx8rChLmRQtW08J73VOiuNsU8PB6d/Xs7fxJC2ohWR3a5AqyjmLojfrw5yw==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-utils": "4.57.1", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.1.tgz", + "integrity": "sha512-/oG8xBNFMbDXTq9J7vepSA1kerS5vpgd3p5QZSPd+nX59uwodGJftI51gDYyHRpP57P3WCQf7LHtBYPqwUg2Bg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.57.1", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/util": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@mdx-js/mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.1.0.tgz", + "integrity": "sha512-/QxEhPAvGwbQmy1Px8F899L5Uc2KZ6JtXwlCgJmjSTBedwOZkByYcBG4GceIGPXRDsmfxhHazuS+hlOShRLeDw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdx": "^2.0.0", + "collapse-white-space": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-util-scope": "^1.0.0", + "estree-walker": "^3.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "markdown-extensions": "^2.0.0", + "recma-build-jsx": "^1.0.0", + "recma-jsx": "^1.0.0", + "recma-stringify": "^1.0.0", + "rehype-recma": "^1.0.0", + "remark-mdx": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "source-map": "^0.7.0", + "unified": "^11.0.0", + "unist-util-position-from-estree": "^2.0.0", + "unist-util-stringify-position": "^4.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/@mdx-js/react": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz", + "integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==", + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/@miniflare/cache": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/cache/-/cache-2.0.0-rc.5.tgz", + "integrity": "sha512-i7T6OYCQOrJ2XqMYW5uDZ03K3zMSku3d7Mny6+yT6BCqMw0amTLnEGvqR/rwxmInSAF9Y4KHXH/VyhLggocMFQ==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "http-cache-semantics": "^4.1.0", + "undici": "^4.11.1" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/cli-parser": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/cli-parser/-/cli-parser-2.0.0-rc.5.tgz", + "integrity": "sha512-p5xKD0sGQBa681/U/2a8de4nw5ua6BHD4y3/AmF1j8kjwp3Fbz/TodLscuoMxwMcP8+f86mf5xX1Py84yD7azw==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/shared": "2.0.0-rc.5", + "kleur": "^4.1.4" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/cli-parser/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@miniflare/core": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/core/-/core-2.0.0-rc.5.tgz", + "integrity": "sha512-nZNlvx0ck/M04ow7q3YD9xxkbT53E7BkYWR68ECvxXQHWTBqje7Weg3yzWu3UbhnAgugB6Q5h5FFmGGYT1mfhQ==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@iarna/toml": "^2.2.5", + "@miniflare/shared": "2.0.0-rc.5", + "busboy": "^0.3.1", + "dotenv": "^10.0.0", + "kleur": "^4.1.4", + "set-cookie-parser": "^2.4.8", + "undici": "^4.11.1" + }, + "engines": { + "node": ">=16.7" + }, + "peerDependencies": { + "@miniflare/watcher": "2.0.0-rc.5" + }, + "peerDependenciesMeta": { + "@miniflare/watcher": { + "optional": true + } + } + }, + "node_modules/@miniflare/core/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@miniflare/durable-objects": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/durable-objects/-/durable-objects-2.0.0-rc.5.tgz", + "integrity": "sha512-Re/r8qQdCk7CcxqaVm78vGAkFqlB49oZ2Vfrd+85xupSySiSrhs5MPIaKvn7gp0Msq86LOWDbKTN0r80rfp0Dw==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "@miniflare/storage-memory": "2.0.0-rc.5", + "undici": "^4.11.1" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/html-rewriter": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/html-rewriter/-/html-rewriter-2.0.0-rc.5.tgz", + "integrity": "sha512-S3iRohlCiMoT8EiW7luUoZWhetyuDFGfso4MPB5GvNgDHzRyrVooK/myHhLXMfH+fVEF3+tkgGyMavd+G0XJ3w==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "html-rewriter-wasm": "^0.3.2", + "undici": "^4.11.1" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/http-server": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/http-server/-/http-server-2.0.0-rc.5.tgz", + "integrity": "sha512-6hn3gSFFh1wtDUcg6SS5nZuy+Oy3iGPseV3EO3qhD4rEJFEFBMu9mlow8Dj8CeTJeMgy8UjlLbH5MJUV3hyTLA==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "@miniflare/web-sockets": "2.0.0-rc.5", + "kleur": "^4.1.4", + "selfsigned": "^1.10.11", + "undici": "^4.11.1", + "ws": "^8.2.2", + "youch": "^2.2.2" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/http-server/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@miniflare/http-server/node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@miniflare/http-server/node_modules/selfsigned": { + "version": "1.10.14", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz", + "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", + "license": "MIT", + "dependencies": { + "node-forge": "^0.10.0" + } + }, + "node_modules/@miniflare/http-server/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@miniflare/kv": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/kv/-/kv-2.0.0-rc.5.tgz", + "integrity": "sha512-2dyeELSebysfddfga8tP9fysxOCP3xXXOaBMeiMxa2GfX5eN/kluCwyvJxzlUvUHcZhNwNrYZCApXsaWf6z/5w==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/shared": "2.0.0-rc.5" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/runner-vm": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/runner-vm/-/runner-vm-2.0.0-rc.5.tgz", + "integrity": "sha512-yQLtvoG+hkZ9Gn/GsHNVytqFah0lckrtoP6TyE/aNrY23/cH8PRS0l8jgjq6tmdDHWH5F+UYUqYyILQykeY5JA==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/shared": "2.0.0-rc.5" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/scheduler": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/scheduler/-/scheduler-2.0.0-rc.5.tgz", + "integrity": "sha512-PPc/o4dVwhiB42fTlCROWy4fjHAwBhPGA61lcoqAJsEyVdS6bJHbJF0W95KICldEvqLmdQKWnMSR+MrYnAo7lA==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "cron-schedule": "^3.0.4" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/shared": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/shared/-/shared-2.0.0-rc.5.tgz", + "integrity": "sha512-ubyp0v5lQh1so5W4InT5zQKKRUZ+dYPJUI0TrLyne4DWd4Nwi2uEmrxEc5ZwEZ/n8VxzxI96jybcEwDXoUirFw==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "ignore": "^5.1.8", + "kleur": "^4.1.4" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/shared/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@miniflare/sites": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/sites/-/sites-2.0.0-rc.5.tgz", + "integrity": "sha512-Qw4B2BXcl9aMj7FfgswTQcmOl52XUxtij9LfTzvGk1JOAf5GzwLLpmKWunF2rr6X/1NHsNRXFeGq23eMzHQpuQ==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/kv": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "@miniflare/storage-file": "2.0.0-rc.5" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/storage-file": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/storage-file/-/storage-file-2.0.0-rc.5.tgz", + "integrity": "sha512-ogm0E5Hwen00xmT3nJ91c6fvHIv6vmv3sf3IFn5yul4disX9A7VDlQF9ZxlXaGgcD4k97T5HhL68L7zj15ugUA==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/shared": "2.0.0-rc.5", + "@miniflare/storage-memory": "2.0.0-rc.5" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/storage-memory": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/storage-memory/-/storage-memory-2.0.0-rc.5.tgz", + "integrity": "sha512-SWmOY2fu+1I/p0SM6+nAn8dq2ie1diuqy9Su7yaMxj5oTLUgdWbXutX0UTqYhDn2shTw+P6jGHv6tf0LGCW7Hg==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/shared": "2.0.0-rc.5" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/watcher": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/watcher/-/watcher-2.0.0-rc.5.tgz", + "integrity": "sha512-Cx5lSzPN5xoTC6gTGxzx5YPzGGeLGK7MHL86tMZqfxcku/pjdup3h2NkhGiwUAatm1DX05xrj6FmDJaJOc+FNA==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/shared": "2.0.0-rc.5" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/web-sockets": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/@miniflare/web-sockets/-/web-sockets-2.0.0-rc.5.tgz", + "integrity": "sha512-HXTjmf46S9HdwWm2OinOsve3ld9EX8wgzgHnqAGGVop/TkeBUsQ4mO53cGRPjNdu9cDT8ukr312xtX/wFe0Jsg==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "undici": "^4.11.1", + "ws": "^8.2.2" + }, + "engines": { + "node": ">=16.7" + } + }, + "node_modules/@miniflare/web-sockets/node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", + "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", + "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", + "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", + "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", + "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", + "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pfx": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", + "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "license": "MIT", + "dependencies": { + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", + "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", + "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "license": "MIT" + }, + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@slorber/remark-comment": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@slorber/remark-comment/-/remark-comment-1.0.0.tgz", + "integrity": "sha512-RCE24n7jsOj1M0UPvIQCHTe7fI0sFL4S2nwKVWwHyVr/wI/H8GosgsJGyhnsZoGFnD/P2hLf1mSbrrgSLN93NA==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.1.0", + "micromark-util-symbol": "^1.0.1" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "license": "MIT", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@types/acorn": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz", + "integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/gtag.js": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@types/gtag.js/-/gtag.js-0.0.12.tgz", + "integrity": "sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==", + "license": "MIT" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "license": "MIT" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "license": "MIT" + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.13.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", + "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.0.11", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.11.tgz", + "integrity": "sha512-vrdxRZfo9ALXth6yPfV16PYTLZwsUWhVjjC+DkfE5t1suNSbBrWC9YqSuuxJZ8Ps6z1o2ycRpIqzZJIgklq4Tw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-config": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@types/react-router-config/-/react-router-config-5.0.11.tgz", + "integrity": "sha512-WmSAg7WgqW7m4x8Mt4N6ZyKz0BubSj/2tVUMsAHp+Yd2AMwcSbeFq9WympT19p5heCFmF97R9eD5uUR/t4HEqw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "^5.1.0" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "license": "MIT" + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-trace": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/stack-trace/-/stack-trace-0.0.29.tgz", + "integrity": "sha512-TgfOX+mGY/NyNxJLIbDWrO9DjGoVSW9+aB8H2yy1fy32jsvxijhmyJI9fDFgvz3YP4lvJaq9DzdR/M1bOgVc9g==", + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/algoliasearch": { + "version": "5.49.2", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.49.2.tgz", + "integrity": "sha512-1K0wtDaRONwfhL4h8bbJ9qTjmY6rhGgRvvagXkMBsAOMNr+3Q2SffHECh9DIuNVrMA1JwA0zCwhyepgBZVakng==", + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.15.2", + "@algolia/client-abtesting": "5.49.2", + "@algolia/client-analytics": "5.49.2", + "@algolia/client-common": "5.49.2", + "@algolia/client-insights": "5.49.2", + "@algolia/client-personalization": "5.49.2", + "@algolia/client-query-suggestions": "5.49.2", + "@algolia/client-search": "5.49.2", + "@algolia/ingestion": "1.49.2", + "@algolia/monitoring": "1.49.2", + "@algolia/recommend": "5.49.2", + "@algolia/requester-browser-xhr": "5.49.2", + "@algolia/requester-fetch": "5.49.2", + "@algolia/requester-node-http": "5.49.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/algoliasearch-helper": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.28.0.tgz", + "integrity": "sha512-GBN0xsxGggaCPElZq24QzMdfphrjIiV2xA+hRXE4/UMpN3nsF2WrM8q+x80OGvGpJWtB7F+4Hq5eSfWwuejXrg==", + "license": "MIT", + "dependencies": { + "@algolia/events": "^4.0.1" + }, + "peerDependencies": { + "algoliasearch": ">= 3.1 < 6" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/astring": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz", + "integrity": "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==", + "license": "MIT", + "bin": { + "astring": "bin/astring" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001774", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "license": "MIT" + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-6.2.1.tgz", + "integrity": "sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^6.2.0", + "chalk": "^4.1.2", + "cli-boxes": "^3.0.0", + "string-width": "^5.0.1", + "type-fest": "^2.5.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/busboy": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz", + "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==", + "dependencies": { + "dicer": "0.3.0" + }, + "engines": { + "node": ">=4.5.0" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001780", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz", + "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/collapse-white-space": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", + "integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/combine-promises": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/combine-promises/-/combine-promises-1.2.0.tgz", + "integrity": "sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "license": "ISC" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compressible/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.41.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.41.0.tgz", + "integrity": "sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", + "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cron-schedule": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/cron-schedule/-/cron-schedule-3.0.6.tgz", + "integrity": "sha512-izfGgKyzzIyLaeb1EtZ3KbglkS6AKp9cv7LxmiyoOu+fXfol1tQDC0Cof0enVZGNtudTHW+3lfuW9ZkLQss4Wg==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/css-blank-pseudo": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-7.0.1.tgz", + "integrity": "sha512-jf+twWGDf6LDoXDUode+nc7ZlrqfaNphrBIBrcmeP3D8yw1uPaix1gCC8LUQUGQ6CycuK2opkbFFWFuq/a94ag==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.1.tgz", + "integrity": "sha512-gz6x+KkgNCjxq3Var03pRYLhyNfwhkKF1g/yoLgDNtFvVu0/fOLV9C8fFEZRjACp/XQLumjAYo7JVjzH3wLbxA==", + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-7.0.3.tgz", + "integrity": "sha512-oG+vKuGyqe/xvEMoxAQrhi7uY16deJR3i7wwhBerVrGQKSqUC5GiOVxTpM9F9B9hw0J+eKeOWLH7E9gZ1Dr5rA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-5.0.1.tgz", + "integrity": "sha512-3caImjKFQkS+ws1TGcFn0V1HyDJFq1Euy589JlD6/3rV2kj+w7r5G9WDMgSHvpvXHNZ2calVypZWuEDQd9wfLg==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "cssnano": "^6.0.1", + "jest-worker": "^29.4.3", + "postcss": "^8.4.24", + "schema-utils": "^4.0.1", + "serialize-javascript": "^6.0.1" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-10.0.0.tgz", + "integrity": "sha512-VCtXZAWivRglTZditUfB4StnsWr6YVZ2PRtuxQLKTNRdtAf8tpzaVPE9zXIF3VaSc7O70iK/j1+NXxyQCqdPjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.8.0.tgz", + "integrity": "sha512-QbLeyz2Bgso1iRlh7IpWk6OKa3lLNGXsujVjDMPl9rOZpxKeiG69icLpbLCFxeURwmcdIfZqQyhlooKJYM4f8Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + } + ], + "license": "MIT-0" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-advanced": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-advanced/-/cssnano-preset-advanced-6.1.2.tgz", + "integrity": "sha512-Nhao7eD8ph2DoHolEzQs5CfRpiEP0xa1HBdnFZ82kvqdmbwVBUr2r1QuQ4t1pi+D1ZpqpcO4T+wy/7RxzJ/WPQ==", + "license": "MIT", + "dependencies": { + "autoprefixer": "^10.4.19", + "browserslist": "^4.23.0", + "cssnano-preset-default": "^6.1.2", + "postcss-discard-unused": "^6.0.5", + "postcss-merge-idents": "^6.0.3", + "postcss-reduce-idents": "^6.0.3", + "postcss-zindex": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "license": "MIT" + }, + "node_modules/detect-port": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.6.1.tgz", + "integrity": "sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dicer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz", + "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==", + "dependencies": { + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=4.5.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/docusaurus-theme-github-codeblock": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/docusaurus-theme-github-codeblock/-/docusaurus-theme-github-codeblock-2.0.2.tgz", + "integrity": "sha512-H2WoQPWOLjGZO6KS58Gsd+eUVjTFJemkReiSSu9chqokyLc/3Ih3+zPRYfuEZ/HsDvSMIarf7CNcp+Vt+/G+ig==", + "license": "MIT", + "dependencies": { + "@docusaurus/types": "^3.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=10" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.321", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "license": "MIT" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/emoticon": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.1.0.tgz", + "integrity": "sha512-VWZfnxqwNcc51hIy/sbOdEem6D+cVtpPzEEtVAFdaas30+1dgkyaOQ4sQ6Bp0tOMqWO1v+HQfYaoodOkdhK6SQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esast-util-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", + "integrity": "sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esast-util-from-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esast-util-from-js/-/esast-util-from-js-2.0.1.tgz", + "integrity": "sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "acorn": "^8.0.0", + "esast-util-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esbuild": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.1.tgz", + "integrity": "sha512-J/LhUwELcmz0+CJfiaKzu7Rnj9ffWFLvMx+dKvdOfg+fQmoP6q9glla26LCm9BxpnPUjXChHeubLiMlKab/PYg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "optionalDependencies": { + "esbuild-android-arm64": "0.14.1", + "esbuild-darwin-64": "0.14.1", + "esbuild-darwin-arm64": "0.14.1", + "esbuild-freebsd-64": "0.14.1", + "esbuild-freebsd-arm64": "0.14.1", + "esbuild-linux-32": "0.14.1", + "esbuild-linux-64": "0.14.1", + "esbuild-linux-arm": "0.14.1", + "esbuild-linux-arm64": "0.14.1", + "esbuild-linux-mips64le": "0.14.1", + "esbuild-linux-ppc64le": "0.14.1", + "esbuild-netbsd-64": "0.14.1", + "esbuild-openbsd-64": "0.14.1", + "esbuild-sunos-64": "0.14.1", + "esbuild-windows-32": "0.14.1", + "esbuild-windows-64": "0.14.1", + "esbuild-windows-arm64": "0.14.1" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.1.tgz", + "integrity": "sha512-elQd3hTg93nU2GQ5PPCDAFe5+utxZX96RG8RixqIPxf8pzmyIzcpKG76L/9FabPf3LT1z+nLF1sajCU8eVRDyg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/esbuild-darwin-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.1.tgz", + "integrity": "sha512-PR3HZgbPRwsQbbOR1fJrfkt/Cs0JDyI3yzOKg2PPWk0H1AseZDBqPUY9b/0+BIjFwA5Jz/aAiq832hppsuJtNw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.1.tgz", + "integrity": "sha512-/fiSSOkOEa3co6yYtwgXouz8jZrG0qnXPEKiktFf2BQE8NON3ARTw43ZegaH+xMRFNgYBJEOOZIdzI3sIFEAxw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.1.tgz", + "integrity": "sha512-ZJV+nfa8E8PdXnRc05PO3YMfgSj7Ko+kdHyGDE6OaNo1cO8ZyfacqLaWkY35shDDaeacklhD8ZR4qq5nbJKX1A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.1.tgz", + "integrity": "sha512-6N9zTD+SecJr2g9Ohl9C10WIk5FpQ+52bNamRy0sJoHwP31G5ObzKzq8jAtg1Jeggpu6P8auz3P/UL+3YioSwQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.1.tgz", + "integrity": "sha512-RtPgE6e7WefbAxRjVryisKFJ0nUwR2DMjwmYW/a1a0F1+Ge6FR+RqvgiY0DrM9TtxSUU0eryDXNF4n3UfxX3mg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.1.tgz", + "integrity": "sha512-JpxM0ar6Z+2v3vfFrxP7bFb8Wzb6gcGL9MxRqAJplDfGnee8HbfPge6svaazXeX9XJceeEqwxwWGB0qyCcxo7A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.1.tgz", + "integrity": "sha512-eBRHexCijAYWzcvQLGHxyxIlYOkYhXvcb/O7HvzJfCAVWCnTx9TxxYJ3UppBC6dDFbAq4HwKhskvmesQdKMeBg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.1.tgz", + "integrity": "sha512-cFbeZf171bIf+PPLlQDBzagK85lCCxxVdMV1IVUA96Y3kvEgqcy2n9mha+QE1M/T+lIOPDsmLRgH1XqMFwLTSg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.1.tgz", + "integrity": "sha512-UGb+sqHkL7wOQFLH0RoFhcRAlJNqbqs6GtJd1It5jJ2juOGqAkCv8V12aGDX9oRB6a+Om7cdHcH+6AMZ+qlaww==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.1.tgz", + "integrity": "sha512-LIHGkGdy9wYlmkkoVHm6feWhkoi4VBXDiEVyNjXEhlzsBcP/CaRy+B8IJulzaU1ALLiGcsCQ2MC5UbFn/iTvmA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.1.tgz", + "integrity": "sha512-TWc1QIgtPwaK5nC1GT2ASTuy/CJhNKHN4h5PJRP1186VfI+k2uvXakS7bqO/M26F6jAMy8jDeCtilacqpwsvfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ] + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.1.tgz", + "integrity": "sha512-Z9/Zb77K+pK9s7mAsvwS56K8tCbLvNZ9UI4QVJSYqDgOmmDJOBT4owWnCqZ5cJI+2y4/F9KwCpFFTNUdPglPKA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.1.tgz", + "integrity": "sha512-c4sF8146kNW8529wfkB6vO0ZqPgokyS2hORqKa4p/QKZdp+xrF2NPmvX5aN+Zt14oe6wVZuhYo6LGv7V4Gg04g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ] + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.1.tgz", + "integrity": "sha512-XP8yElaJtLGGjH7D72t5IWtP0jmc1Jqm4IjQARB17l0LTJO/n+N2X64rDWePJv6qimYxa5p2vTjkZc5v+YZTSQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.1.tgz", + "integrity": "sha512-fe+ShdyfiuGcCEdVKW//6MaM4MwikiWBWSBn8mebNAbjRqicH0injDOFVI7aUovAfrEt7+FGkf402s//hi0BVg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.1.tgz", + "integrity": "sha512-wBVakhcIzQ3NZ33DFM6TjIObXPHaXOsqzvPwefXHvwBSC/N/e/g6fBeM7N/Moj3AmxLjKaB+vePvTGdxk6RPCg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-attach-comments": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz", + "integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-build-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz", + "integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "estree-walker": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-scope": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-util-scope/-/estree-util-scope-1.0.0.tgz", + "integrity": "sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-to-js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz", + "integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "astring": "^1.8.0", + "source-map": "^0.7.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-util-value-to-estree": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/estree-util-value-to-estree/-/estree-util-value-to-estree-3.5.0.tgz", + "integrity": "sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/remcohaszing" + } + }, + "node_modules/estree-util-visit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz", + "integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-2.2.0.tgz", + "integrity": "sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/eta-dev/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eval": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eval/-/eval-0.1.8.tgz", + "integrity": "sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==", + "dependencies": { + "@types/node": "*", + "require-like": ">= 0.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/express/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fault": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz", + "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/feed": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz", + "integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/file-loader/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/file-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/file-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "license": "MIT", + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", + "license": "ISC" + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-slugger": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", + "license": "ISC" + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "license": "MIT", + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-raw": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-from-parse5": "^8.0.0", + "hast-util-to-parse5": "^8.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "parse5": "^7.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-estree": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.3.tgz", + "integrity": "sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-attach-comments": "^3.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.1.tgz", + "integrity": "sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "web-namespaces": "^2.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/html-rewriter-wasm": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/html-rewriter-wasm/-/html-rewriter-wasm-0.3.2.tgz", + "integrity": "sha512-b+pOh+bs00uRVNIZoTgGBREjUKN47pchTNwkxKuP4ecQTFcOA6KJIW+jjvjjXrkSRURZsideLxFKqX7hnxdegQ==", + "license": "BSD-3-Clause" + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz", + "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.20.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/html-webpack-plugin/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/html-webpack-plugin/node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "license": "MIT", + "engines": { + "node": ">=10.18" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-2.0.2.tgz", + "integrity": "sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==", + "license": "MIT", + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/infima": { + "version": "0.2.0-alpha.45", + "resolved": "https://registry.npmjs.org/infima/-/infima-0.2.0-alpha.45.tgz", + "integrity": "sha512-uyH0zfr1erU1OohLk0fT4Rrb94AOhguWNOcD9uGrSpRvNB+6gZXUoJX5J0NtvzBO10YZ9PgvA4NFgt+fYg8ojw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "license": "MIT", + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "license": "MIT", + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-network-error": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz", + "integrity": "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.13.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.13.3.tgz", + "integrity": "sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.3.0", + "@hapi/topo": "^5.1.0", + "@sideway/address": "^4.1.5", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/launch-editor": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz", + "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/markdown-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz", + "integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-directive": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-directive/-/mdast-util-directive-3.1.0.tgz", + "integrity": "sha512-I3fNFt+DHmpWCYAT7quoM6lHf9wuqtI+oCOfvILnoicNIqjh5E3dEJWiXuYME2gNe8vl1iMQwyUHa7bgFmak6Q==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-frontmatter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz", + "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "escape-string-regexp": "^5.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/mdast-util-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "4.57.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.1.tgz", + "integrity": "sha512-WvzrWPwMQT+PtbX2Et64R4qXKK0fj/8pO85MrUCzymX3twwCiJCdvntW3HdhG1teLJcHDDLIKx5+c3HckWYZtQ==", + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.1", + "@jsonjoy.com/fs-fsa": "4.57.1", + "@jsonjoy.com/fs-node": "4.57.1", + "@jsonjoy.com/fs-node-builtins": "4.57.1", + "@jsonjoy.com/fs-node-to-fsa": "4.57.1", + "@jsonjoy.com/fs-node-utils": "4.57.1", + "@jsonjoy.com/fs-print": "4.57.1", + "@jsonjoy.com/fs-snapshot": "4.57.1", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-directive": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-3.0.2.tgz", + "integrity": "sha512-wjcXHgk+PPdmvR58Le9d7zQYWy+vKEU9Se44p2CrCDPiLr2FMyiT4Fyb5UFKFC66wGB3kPlgD7q3TnoqPS7SZA==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-frontmatter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz", + "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==", + "license": "MIT", + "dependencies": { + "fault": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-frontmatter/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-footnote/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-table/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm-task-list-item/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz", + "integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.1.tgz", + "integrity": "sha512-vNuFb9czP8QCtAQcEJn0UJQJZA8Dk6DXKBqx+bg/w0WGuSxDxNr7hErW89tHUY31dUW4NqEOWwmEUNhjTFmHkg==", + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdxjs-esm/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.2.tgz", + "integrity": "sha512-5E5I2pFzJyg2CtemqAbcyCktpHXuJbABnsb32wX2U8IQKhhVFBqkcZR5LRm1WVoFqa4kTueZK4abep7wdo9nrw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-mdx-expression/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-space/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character/node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz", + "integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/acorn": "^4.0.0", + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, + "node_modules/micromark-util-events-to-acorn/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-normalize-identifier/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark/node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark/node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.1.tgz", + "integrity": "sha512-k7G3Y5QOegl380tXmZ68foBRRjE9Ljavx835ObdvmZjQ639izvZD8CS7BkWw1qKPPzHsGL/JDhl0uyU1zc2rJw==", + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/miniflare": { + "version": "2.0.0-rc.5", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-2.0.0-rc.5.tgz", + "integrity": "sha512-4i6qC+jLpsV8c/W2m04qMokrXY9ybg0jeK9F3+F/4fkpvtT784dMhdhdKbfY2qGr9q+CuAmMkO6myOrs7F6RHA==", + "deprecated": "Miniflare v2 is no longer supported. Please upgrade to Miniflare v4", + "license": "MIT", + "dependencies": { + "@miniflare/cache": "2.0.0-rc.5", + "@miniflare/cli-parser": "2.0.0-rc.5", + "@miniflare/core": "2.0.0-rc.5", + "@miniflare/durable-objects": "2.0.0-rc.5", + "@miniflare/html-rewriter": "2.0.0-rc.5", + "@miniflare/http-server": "2.0.0-rc.5", + "@miniflare/kv": "2.0.0-rc.5", + "@miniflare/runner-vm": "2.0.0-rc.5", + "@miniflare/scheduler": "2.0.0-rc.5", + "@miniflare/shared": "2.0.0-rc.5", + "@miniflare/sites": "2.0.0-rc.5", + "@miniflare/storage-file": "2.0.0-rc.5", + "@miniflare/storage-memory": "2.0.0-rc.5", + "@miniflare/watcher": "2.0.0-rc.5", + "@miniflare/web-sockets": "2.0.0-rc.5", + "kleur": "^4.1.4", + "semiver": "^1.1.0", + "source-map-support": "^0.5.20", + "undici": "^4.11.1" + }, + "bin": { + "miniflare": "bootstrap.js" + }, + "engines": { + "node": ">=16.7" + }, + "peerDependencies": { + "@miniflare/storage-redis": "2.0.0-rc.5", + "cron-schedule": "^3.0.4", + "ioredis": "^4.27.9" + }, + "peerDependenciesMeta": { + "@miniflare/storage-redis": { + "optional": true + }, + "ioredis": { + "optional": true + } + } + }, + "node_modules/miniflare/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", + "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/null-loader": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/null-loader/-/null-loader-4.0.1.tgz", + "integrity": "sha512-pxqVbi4U6N26lq+LmgIbB5XATP0VdZKOG25DhHi8btMmJJefGArFyDg1yc4U3hWCJbMqSrw0qyrz1UQX+qYXqg==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/null-loader/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/null-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/null-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/null-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "license": "(WTFPL OR MIT)", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "license": "MIT", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-numeric-range": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", + "license": "ISC" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", + "integrity": "sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g==", + "license": "MIT", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkijs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", + "license": "BSD-3-Clause", + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-7.0.1.tgz", + "integrity": "sha512-Uai+SupNSqzlschRyNx3kbCTWgY/2hcwtHEI/ej2LJWc9JJ77qKgGptd8DHwY1mXtZ7Aoh4z4yxfwMBue9eNgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-7.0.12.tgz", + "integrity": "sha512-TLCW9fN5kvO/u38/uesdpbx3e8AkTYhMvDZYa9JpmImWuTE99bDQ7GU7hdOADIZsiI9/zuxfAJxny/khknp1Zw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-10.0.0.tgz", + "integrity": "sha512-1kervM2cnlgPs2a8Vt/Qbe5cQ++N7rkYo/2rz2BkqJZIHQwaVuJgQH38REHrAi4uM0b1fqxMkWYmese94iMp3w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-10.0.0.tgz", + "integrity": "sha512-JFta737jSP+hdAIEhk1Vs0q0YF5P8fFcj+09pweS8ktuGuZ8pPlykHsk6mPxZ8awDl4TrcxUqJo9l1IhVr/OjQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-custom-media": { + "version": "11.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-11.0.6.tgz", + "integrity": "sha512-C4lD4b7mUIw+RZhtY7qUbf4eADmb7Ey8BFA2px9jUbwg7pjTZDl4KY4bvlUV+/vXQvzQRfiGEVJyAbtOsCMInw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-properties": { + "version": "14.0.6", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-14.0.6.tgz", + "integrity": "sha512-fTYSp3xuk4BUeVhxCSJdIPhDLpJfNakZKoiTDx7yRGCdlZrSJR7mWKVOBS4sBF+5poPQFMj2YdXx1VHItBGihQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-8.0.5.tgz", + "integrity": "sha512-9PGmckHQswiB2usSO6XMSswO2yFWVoCAuih1yl9FVcwkscLjRKjwsjM3t+NIWpSU2Jx3eOiK2+t4vVTQaoCHHg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/cascade-layer-name-parser": "^2.0.5", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-9.0.1.tgz", + "integrity": "sha512-tRBEK0MHYvcMUrAuYMEOa0zg9APqirBcgzi6P21OhxtJyJADo/SWBwY1CAwEohQ/6HDaa9jCjLRG7K3PVQYHEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-unused": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-6.0.5.tgz", + "integrity": "sha512-wHalBlRHkaNnNwfC8z+ppX57VhvS+HWgjW508esjdaEYr3Mx7Gnn2xA4R/CKf5+Z9S5qsqC+Uzh4ueENWwCVUA==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-6.0.4.tgz", + "integrity": "sha512-m6IKmxo7FxSP5nF2l63QbCC3r+bWpFUWmZXZf096WxG0m7Vl1Q1+ruFOhpdDRmKrRS+S3Jtk+TVk/7z0+BVK6g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-10.0.1.tgz", + "integrity": "sha512-U58wyjS/I1GZgjRok33aE8juW9qQgQUNwTSdxQGuShHzwuYdcklnvK/+qOWX1Q9kr7ysbraQ6ht6r+udansalA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-focus-within": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-9.0.1.tgz", + "integrity": "sha512-fzNUyS1yOYa7mOjpci/bR+u+ESvdar6hk8XNK/TRR0fiGTp2QT5N+ducP0n3rfH/m9I7H/EQU6lsa2BrgxkEjw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-6.0.0.tgz", + "integrity": "sha512-Om0WPjEwiM9Ru+VhfEDPZJAKWUd0mV1HmNXqp2C29z80aQ2uP9UVhLc7e3aYMIor/S5cVhoPgYQ7RtfeZpYTRw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-image-set-function": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-7.0.0.tgz", + "integrity": "sha512-QL7W7QNlZuzOwBTeXEmbVckNt1FSmhQtbMRvGGqqU4Nf4xk6KUEQhAoWuMzwbSv5jxiRiSZ5Tv7eiDB9U87znA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/utilities": "^2.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-lab-function": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-7.0.12.tgz", + "integrity": "sha512-tUcyRk1ZTPec3OuKFsqtRzW2Go5lehW29XA21lZ65XmzQkz43VY2tyWEC202F7W3mILOjw0voOiuxRGTsN+J9w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/css-color-parser": "^3.1.0", + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/utilities": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-loader": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", + "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "license": "MIT", + "dependencies": { + "cosmiconfig": "^8.3.5", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-8.1.0.tgz", + "integrity": "sha512-pL1hXFQ2fEXNKiNiAgtfA005T9FBxky5zkX6s4GZM2D8RkVgRqz3f4g1JUoq925zXv495qk8UNldDwh8uGEDoA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-merge-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-6.0.3.tgz", + "integrity": "sha512-1oIoAsODUs6IHQZkLQGO15uGEbK3EAl5wi9SS8hs45VgsxQfMnxvt+L+zIr7ifZFIH14cfAeVe2uCTa+SPRa3g==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-13.0.2.tgz", + "integrity": "sha512-1YCI290TX+VP0U/K/aFxzHzQWHWURL+CtHMSbex1lCdpXD1SoR2sYuxDu5aNI9lPoXpKTCggFZiDJbwylU0LEQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/selector-resolve-nested": "^3.1.0", + "@csstools/selector-specificity": "^5.0.0", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-resolve-nested": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-3.1.0.tgz", + "integrity": "sha512-mf1LEW0tJLKfWyvn5KdDrhpxHyuxpbNwTIwOYLIvsTffeyOf85j5oIzfG0yosxDgx/sswlqBnESYUcQH0vgZ0g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-3.0.0.tgz", + "integrity": "sha512-K6HGVzyxUxd/VgZdX04DCtdwWJ4NGLG212US4/LA1TLAbHgmAsTWVR86o+gGIbFtnTkfOpb9sCRBx8K7HO66qQ==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-6.0.0.tgz", + "integrity": "sha512-BdDl/AbVkDjoTofzDQnwDdm/Ym6oS9KgmO7Gr+LHYjNWJ6ExORe4+3pcLQsLA9gIROMkiGVjjwZNoL/mpXHd5Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-10.0.0.tgz", + "integrity": "sha512-5EBrMzat2pPAxQNWYavwAfoKfYcTADJ8AXGVPcUZ2UkNloUTWzJQExgrzrDkh3EKzmAx1evfTAzF9I8NGcc+qw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-preset-env": { + "version": "10.6.1", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-10.6.1.tgz", + "integrity": "sha512-yrk74d9EvY+W7+lO9Aj1QmjWY9q5NsKjK2V9drkOPZB/X6KZ0B3igKsHUYakb7oYVhnioWypQX3xGuePf89f3g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "@csstools/postcss-alpha-function": "^1.0.1", + "@csstools/postcss-cascade-layers": "^5.0.2", + "@csstools/postcss-color-function": "^4.0.12", + "@csstools/postcss-color-function-display-p3-linear": "^1.0.1", + "@csstools/postcss-color-mix-function": "^3.0.12", + "@csstools/postcss-color-mix-variadic-function-arguments": "^1.0.2", + "@csstools/postcss-content-alt-text": "^2.0.8", + "@csstools/postcss-contrast-color-function": "^2.0.12", + "@csstools/postcss-exponential-functions": "^2.0.9", + "@csstools/postcss-font-format-keywords": "^4.0.0", + "@csstools/postcss-gamut-mapping": "^2.0.11", + "@csstools/postcss-gradients-interpolation-method": "^5.0.12", + "@csstools/postcss-hwb-function": "^4.0.12", + "@csstools/postcss-ic-unit": "^4.0.4", + "@csstools/postcss-initial": "^2.0.1", + "@csstools/postcss-is-pseudo-class": "^5.0.3", + "@csstools/postcss-light-dark-function": "^2.0.11", + "@csstools/postcss-logical-float-and-clear": "^3.0.0", + "@csstools/postcss-logical-overflow": "^2.0.0", + "@csstools/postcss-logical-overscroll-behavior": "^2.0.0", + "@csstools/postcss-logical-resize": "^3.0.0", + "@csstools/postcss-logical-viewport-units": "^3.0.4", + "@csstools/postcss-media-minmax": "^2.0.9", + "@csstools/postcss-media-queries-aspect-ratio-number-values": "^3.0.5", + "@csstools/postcss-nested-calc": "^4.0.0", + "@csstools/postcss-normalize-display-values": "^4.0.1", + "@csstools/postcss-oklab-function": "^4.0.12", + "@csstools/postcss-position-area-property": "^1.0.0", + "@csstools/postcss-progressive-custom-properties": "^4.2.1", + "@csstools/postcss-property-rule-prelude-list": "^1.0.0", + "@csstools/postcss-random-function": "^2.0.1", + "@csstools/postcss-relative-color-syntax": "^3.0.12", + "@csstools/postcss-scope-pseudo-class": "^4.0.1", + "@csstools/postcss-sign-functions": "^1.1.4", + "@csstools/postcss-stepped-value-functions": "^4.0.9", + "@csstools/postcss-syntax-descriptor-syntax-production": "^1.0.1", + "@csstools/postcss-system-ui-font-family": "^1.0.0", + "@csstools/postcss-text-decoration-shorthand": "^4.0.3", + "@csstools/postcss-trigonometric-functions": "^4.0.9", + "@csstools/postcss-unset-value": "^4.0.0", + "autoprefixer": "^10.4.23", + "browserslist": "^4.28.1", + "css-blank-pseudo": "^7.0.1", + "css-has-pseudo": "^7.0.3", + "css-prefers-color-scheme": "^10.0.0", + "cssdb": "^8.6.0", + "postcss-attribute-case-insensitive": "^7.0.1", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^7.0.12", + "postcss-color-hex-alpha": "^10.0.0", + "postcss-color-rebeccapurple": "^10.0.0", + "postcss-custom-media": "^11.0.6", + "postcss-custom-properties": "^14.0.6", + "postcss-custom-selectors": "^8.0.5", + "postcss-dir-pseudo-class": "^9.0.1", + "postcss-double-position-gradients": "^6.0.4", + "postcss-focus-visible": "^10.0.1", + "postcss-focus-within": "^9.0.1", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^6.0.0", + "postcss-image-set-function": "^7.0.0", + "postcss-lab-function": "^7.0.12", + "postcss-logical": "^8.1.0", + "postcss-nesting": "^13.0.2", + "postcss-opacity-percentage": "^3.0.0", + "postcss-overflow-shorthand": "^6.0.0", + "postcss-page-break": "^3.0.4", + "postcss-place": "^10.0.0", + "postcss-pseudo-class-any-link": "^10.0.1", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^8.0.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-10.0.1.tgz", + "integrity": "sha512-3el9rXlBOqTFaMFkWDOkHUTQekFIYnaQY55Rsp8As8QQkpiSgIYEcF/6Ond93oHiDsGb4kad8zjt+NPlOC1H0Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-reduce-idents": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-6.0.3.tgz", + "integrity": "sha512-G3yCqZDpsNPoQgbDUy3T0E6hqOQ5xigUtBQyrmq3tn2GxlyiL0yyl7H+T8ulQR6kOcHJ9t7/9H4/R2tv8tJbMA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "license": "MIT", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-8.0.1.tgz", + "integrity": "sha512-kmVy/5PYVb2UOhy0+LqUYAhKj7DUGDpSWa5LZqlkWJaaAV+dxxsOG3+St0yNLu6vsKD7Dmqx+nWQt0iil89+WA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-sort-media-queries": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-5.2.0.tgz", + "integrity": "sha512-AZ5fDMLD8SldlAYlvi8NIqo0+Z8xnXU2ia0jxmuhxAU+Lqt9K+AlmLNJ/zWEnE9x+Zx3qL3+1K20ATgNOr3fAA==", + "license": "MIT", + "dependencies": { + "sort-css-media-queries": "2.2.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.4.23" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss-zindex": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-6.0.2.tgz", + "integrity": "sha512-5BxW9l1evPB/4ZIc+2GobEBoKC+h8gPGCMi+jxsYvd2x0mjq7wazk6DrP71pStqxE9Foxh5TVnonbWpFZzXaYg==", + "license": "MIT", + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz", + "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prism-react-renderer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", + "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", + "license": "MIT", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "node_modules/prism-react-renderer/node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/property-information": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.0.0.tgz", + "integrity": "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "license": "MIT", + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, + "node_modules/react-helmet-async": { + "name": "@slorber/react-helmet-async", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@slorber/react-helmet-async/-/react-helmet-async-1.3.0.tgz", + "integrity": "sha512-e9/OK8VhwUSc67diWI8Rb3I0YgI9/SBQtnhe9aEuK6MhZm7ntZZimXgwXnd8W96YTmSOb9M4d8LwhRZyhWr/1A==", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.12.5", + "invariant": "^2.2.4", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.2.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-json-view-lite": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/react-json-view-lite/-/react-json-view-lite-2.5.0.tgz", + "integrity": "sha512-tk7o7QG9oYyELWHL8xiMQ8x4WzjCzbWNyig3uexmkLb54r8jO0yH3WCWx8UZS0c49eSA4QUmG5caiRJ8fAn58g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-loadable": { + "name": "@docusaurus/react-loadable", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz", + "integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-loadable-ssr-addon-v5-slorber": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", + "integrity": "sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.3" + }, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "react-loadable": "*", + "webpack": ">=4.41.1 || 5.x" + } + }, + "node_modules/react-router": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz", + "integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-config": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-router-config/-/react-router-config-5.1.1.tgz", + "integrity": "sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + }, + "peerDependencies": { + "react": ">=15", + "react-router": ">=5" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz", + "integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.3.4", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recma-build-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", + "integrity": "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-build-jsx": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-jsx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-jsx/-/recma-jsx-1.0.0.tgz", + "integrity": "sha512-5vwkv65qWwYxg+Atz95acp8DMu1JDSqdGkA2Of1j6rCreyFUE/gp15fC8MnGEuG1W68UKjM6x6+YTWIh7hZM/Q==", + "license": "MIT", + "dependencies": { + "acorn-jsx": "^5.0.0", + "estree-util-to-js": "^2.0.0", + "recma-parse": "^1.0.0", + "recma-stringify": "^1.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-parse/-/recma-parse-1.0.0.tgz", + "integrity": "sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "esast-util-from-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/recma-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/recma-stringify/-/recma-stringify-1.0.0.tgz", + "integrity": "sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-util-to-js": "^2.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/rehype-raw": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "hast-util-raw": "^9.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-recma": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rehype-recma/-/rehype-recma-1.0.0.tgz", + "integrity": "sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "hast-util-to-estree": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remark-directive": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-directive/-/remark-directive-3.0.1.tgz", + "integrity": "sha512-gwglrEQEZcZYgVyG1tQuA+h58EZfq5CSULw7J90AFuCTyib1thgHPoqQ+h9iFvU6R+vnZ5oNFQR5QKgGpk741A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-directive": "^3.0.0", + "micromark-extension-directive": "^3.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-emoji": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-4.0.1.tgz", + "integrity": "sha512-fHdvsTR1dHkWKev9eNyhTo4EFwbUvJ8ka9SgeWkMPYFX4WoI7ViVBms3PjlQYgw5TLvNQso3GUB/b/8t3yo+dg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.2", + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^3.0.1", + "node-emoji": "^2.1.0", + "unified": "^11.0.4" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/remark-frontmatter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz", + "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-frontmatter": "^2.0.0", + "micromark-extension-frontmatter": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-mdx": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.0.tgz", + "integrity": "sha512-Ngl/H3YXyBV9RcRNdlYsZujAmhsxwzxpDzpDEhFBVAGthS4GDgnctpDjgFl/ULx5UEDzqtW1cyBSNKqYYrqLBA==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", + "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/renderkid/node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/renderkid/node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha512-oyrU88skkMtDdauHDuKVrgR+zuItqr6/c//FXzvmxRGMexSDc6hNvJInGW3LL46n+8b50RykrvwSUIIQH2LQ5A==", + "engines": { + "node": "*" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", + "license": "MIT" + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-dts": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz", + "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==", + "license": "Apache-2.0" + }, + "node_modules/schema-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", + "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", + "license": "MIT", + "dependencies": { + "@peculiar/x509": "^1.14.2", + "pkijs": "^3.3.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/semiver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", + "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-handler": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz", + "integrity": "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==", + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.2", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "license": "MIT" + }, + "node_modules/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/sitemap": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-7.1.3.tgz", + "integrity": "sha512-tAjEd+wt/YwnEbfNB2ht51ybBJxbEWwe5ki/Z//Wh0rpBFTCUSj46GnxUKEWzhfuJTsee8x3lybHxFgUMig2hw==", + "license": "MIT", + "dependencies": { + "@types/node": "^17.0.5", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.2.4" + }, + "bin": { + "sitemap": "dist/cli.js" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.6.0" + } + }, + "node_modules/sitemap/node_modules/@types/node": { + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sort-css-media-queries": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz", + "integrity": "sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA==", + "license": "MIT", + "engines": { + "node": ">= 6.3.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/srcset": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz", + "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "license": "BSD-2-Clause", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.16.tgz", + "integrity": "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.8" + } + }, + "node_modules/style-to-object": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", + "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "license": "MIT" + }, + "node_modules/svgo": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "license": "MIT", + "dependencies": { + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/thingies": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz", + "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==", + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/undici": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-4.16.0.tgz", + "integrity": "sha512-tkZSECUYi+/T1i4u+4+lwZmQgLXd4BLGlrc7KZPcLIW7Jpq99+Xpc30ONv7nS6F5UNOxp/HBZSSL9MafUrvJbw==", + "license": "MIT", + "engines": { + "node": ">=12.18" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position-from-estree": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz", + "integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/url-loader/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/url-loader/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/url-loader/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "license": "MIT" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==", + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpack": { + "version": "5.98.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", + "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/webpack-dev-middleware/node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack-dev-server": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.3.tgz", + "integrity": "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==", + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.25", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.8.1", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.22.1", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^5.5.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpack/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/webpackbar": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-6.0.1.tgz", + "integrity": "sha512-TnErZpmuKdwWBdMoexjio3KKX6ZtoKHRVvLIU0A47R0VVBDtx3ZyOJDktgYixhoJokZTYTt1Z37OkO9pnGJa9Q==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "consola": "^3.2.3", + "figures": "^3.2.0", + "markdown-table": "^2.0.0", + "pretty-time": "^1.1.0", + "std-env": "^3.7.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "webpack": "3 || 4 || 5" + } + }, + "node_modules/webpackbar/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/webpackbar/node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/webpackbar/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpackbar/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "license": "MIT" + }, + "node_modules/wrangler": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-0.0.7.tgz", + "integrity": "sha512-qFUjilp2mIP3zy1TNSTF2zhS2cM3l9jjscjkMM5d8hUmbDObMQfi/H8nMFszWQAtPF/B3vEVs5xA9r0b59TZKQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "esbuild": "0.14.1", + "miniflare": "2.0.0-rc.5", + "path-to-regexp": "^6.2.0", + "semiver": "^1.1.0" + }, + "bin": { + "wrangler": "bin/wrangler.js", + "wrangler2": "bin/wrangler.js" + }, + "engines": { + "node": ">=16.7.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/wrangler/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/youch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/youch/-/youch-2.2.2.tgz", + "integrity": "sha512-/FaCeG3GkuJwaMR34GHVg0l8jCbafZLHiFowSjqLlqhC6OMyf2tPJBu8UirF7/NI9X/R5ai4QfEKUCOxMAGxZQ==", + "license": "MIT", + "dependencies": { + "@types/stack-trace": "0.0.29", + "cookie": "^0.4.1", + "mustache": "^4.2.0", + "stack-trace": "0.0.10" + } + }, + "node_modules/youch/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000000..ce3c2442c6 --- /dev/null +++ b/website/package.json @@ -0,0 +1,42 @@ +{ + "name": "flet-dev", + "version": "0.0.0", + "private": true, + "scripts": { + "crocodocs:generate": "cd .. && uv --directory ./tools/crocodocs run crocodocs generate", + "docs:check": "cd .. && bash .github/scripts/check_docs.sh website/build", + "start": "cd .. && uv --directory ./tools/crocodocs run crocodocs watch --child-cwd ../../website -- yarn exec docusaurus start", + "build": "yarn crocodocs:generate && docusaurus build && yarn docs:check", + "swizzle": "docusaurus swizzle", + "deploy": "docusaurus deploy" + }, + "dependencies": { + "@docsearch/docusaurus-adapter": "^4.6.2", + "@docusaurus/core": "^3.10.0", + "@docusaurus/faster": "^3.10.0", + "@docusaurus/plugin-client-redirects": "^3.10.0", + "@docusaurus/preset-classic": "^3.10.0", + "@docusaurus/theme-mermaid": "^3.10.0", + "@hcaptcha/react-hcaptcha": "^1.0.0", + "@mdx-js/react": "^3.0.0", + "clsx": "^1.1.1", + "docusaurus-theme-github-codeblock": "^2.0.2", + "prism-react-renderer": "^2.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "wrangler": "^0.0.7" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "packageManager": "yarn@4.6.0" +} diff --git a/website/plugins/remark-api-links.js b/website/plugins/remark-api-links.js new file mode 100644 index 0000000000..ef622309f9 --- /dev/null +++ b/website/plugins/remark-api-links.js @@ -0,0 +1,85 @@ +const fs = require("fs"); +const path = require("path"); + +function visit(node, fn) { + fn(node); + if (Array.isArray(node.children)) { + for (const child of node.children) { + visit(child, fn); + } + } +} + +module.exports = function remarkApiLinks() { + const apiDataPath = path.join(__dirname, "..", ".crocodocs", "api-data.json"); + let xrefMap = {}; + if (fs.existsSync(apiDataPath)) { + const data = JSON.parse(fs.readFileSync(apiDataPath, "utf8")); + xrefMap = data.xref_map || {}; + } + + return (tree) => { + visit(tree, (node) => { + if (!Array.isArray(node.children) || node.children.length < 3) { + return; + } + + let changed = false; + do { + changed = false; + const rewritten = []; + for (let i = 0; i < node.children.length; i += 1) { + const current = node.children[i]; + const next = node.children[i + 1]; + const after = node.children[i + 2]; + + if ( + current?.type === "text" && + current.value.endsWith("[") && + next?.type === "inlineCode" && + after?.type === "text" + ) { + const match = after.value.match(/^\]\[([^\]]+)\](.*)$/s); + const url = match ? xrefMap[match[1]] : null; + if (url) { + const prefix = current.value.slice(0, -1); + if (prefix) { + rewritten.push({...current, value: prefix}); + } + rewritten.push({ + type: "link", + url, + children: [{...next}], + }); + if (match[2]) { + rewritten.push({...after, value: match[2]}); + } + i += 2; + changed = true; + continue; + } + } + + rewritten.push(current); + } + + node.children = rewritten; + } while (changed); + }); + + visit(tree, (node) => { + if (node.type !== "linkReference") { + return; + } + const url = xrefMap[node.identifier]; + if (!url) { + return; + } + node.type = "link"; + node.url = url; + delete node.identifier; + delete node.referenceType; + delete node.label; + }); + }; +}; diff --git a/website/plugins/remark-code-annotations.js b/website/plugins/remark-code-annotations.js new file mode 100644 index 0000000000..771cd46b6b --- /dev/null +++ b/website/plugins/remark-code-annotations.js @@ -0,0 +1,204 @@ +/** + * Remark plugin that implements MkDocs Material-style code annotations. + * + * Detects `# (N)!` markers in code blocks, strips them from displayed code, + * collects the corresponding numbered list items that follow, and replaces + * the code node with an MDX component. + */ + +const MARKER_RE = /^(.*?)\s*#\s*\((\d+)\)!\s*$/m; +const LINE_MARKER_RE = /^(.*?)\s*#\s*\((\d+)\)!\s*$/; + +function extractMarkers(code) { + const lines = code.split("\n"); + const markers = new Map(); // number -> lineIndex + const cleanedLines = []; + + for (let i = 0; i < lines.length; i++) { + const match = LINE_MARKER_RE.exec(lines[i]); + if (match) { + markers.set(parseInt(match[2], 10), i); + cleanedLines.push(match[1].trimEnd()); + } else { + cleanedLines.push(lines[i]); + } + } + + return { cleanedCode: cleanedLines.join("\n"), markers }; +} + +/** + * Recursively extract text/HTML from an mdast node. + * Handles: text, inlineCode, link, emphasis, strong, paragraph, and nested children. + */ +function mdastToHtml(node) { + if (!node) return ""; + + if (node.type === "text") { + return escapeHtml(node.value); + } + if (node.type === "inlineCode") { + return `${escapeHtml(node.value)}`; + } + if (node.type === "code") { + return `
${escapeHtml(node.value)}
`; + } + if (node.type === "link") { + const children = (node.children || []).map(mdastToHtml).join(""); + const href = escapeHtml(node.url || ""); + return `${children}`; + } + if (node.type === "emphasis") { + return `${(node.children || []).map(mdastToHtml).join("")}`; + } + if (node.type === "strong") { + return `${(node.children || []).map(mdastToHtml).join("")}`; + } + if (node.type === "paragraph") { + return `

${(node.children || []).map(mdastToHtml).join("")}

`; + } + if (node.type === "list") { + const tag = node.ordered ? "ol" : "ul"; + const items = (node.children || []).map(mdastToHtml).join(""); + return `<${tag}>${items}`; + } + if (node.type === "listItem") { + return `
  • ${(node.children || []).map(mdastToHtml).join("")}
  • `; + } + if (node.type === "html") { + return node.value || ""; + } + if (Array.isArray(node.children)) { + return node.children.map(mdastToHtml).join(""); + } + return ""; +} + +function escapeHtml(str) { + return str + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function renderListItem(listItem) { + return (listItem.children || []).map(mdastToHtml).join(""); +} + +function parseMeta(meta) { + if (!meta) return {}; + const titleMatch = meta.match(/title="([^"]+)"/); + return titleMatch ? { title: titleMatch[1] } : {}; +} + +/** + * Check if a node is a boundary that stops annotation list collection. + */ +function isBoundary(node) { + return ( + node.type === "heading" || + node.type === "code" || + node.type === "thematicBreak" + ); +} + +function visitParents(tree, fn) { + if (Array.isArray(tree.children)) { + fn(tree); + for (const child of tree.children) { + visitParents(child, fn); + } + } +} + +module.exports = function remarkCodeAnnotations() { + return (tree, file) => { + visitParents(tree, (parent) => { + if (!Array.isArray(parent.children)) return; + + const newChildren = []; + let i = 0; + + while (i < parent.children.length) { + const child = parent.children[i]; + + if (child.type !== "code" || !MARKER_RE.test(child.value)) { + newChildren.push(child); + i++; + continue; + } + + const { cleanedCode, markers } = extractMarkers(child.value); + const needed = new Set(markers.keys()); + const annotations = {}; + + // Walk forward collecting annotation lists + let j = i + 1; + while (j < parent.children.length && needed.size > 0) { + const sibling = parent.children[j]; + + if (isBoundary(sibling)) break; + + if (sibling.type === "list" && sibling.ordered) { + const start = sibling.start || 1; + for (let k = 0; k < sibling.children.length; k++) { + const num = start + k; + if (needed.has(num)) { + annotations[num] = { + line: markers.get(num), + html: renderListItem(sibling.children[k]), + }; + needed.delete(num); + } + } + j++; + } else { + // Skip non-list nodes (admonitions, paragraphs) if we still + // have unmatched annotations — handles split-list case + j++; + } + } + + const meta = parseMeta(child.meta); + + // Create MDX JSX element for + const jsxNode = { + type: "mdxJsxFlowElement", + name: "AnnotatedCodeBlock", + attributes: [ + { + type: "mdxJsxAttribute", + name: "code", + value: cleanedCode, + }, + { + type: "mdxJsxAttribute", + name: "lang", + value: child.lang || "", + }, + { + type: "mdxJsxAttribute", + name: "annotations", + value: JSON.stringify(annotations), + }, + ], + children: [], + }; + + if (meta.title) { + jsxNode.attributes.push({ + type: "mdxJsxAttribute", + name: "title", + value: meta.title, + }); + } + + newChildren.push(jsxNode); + i = j; // skip consumed siblings + } + + parent.children = newChildren; + }); + }; +}; diff --git a/website/sidebars.js b/website/sidebars.js new file mode 100644 index 0000000000..d0028f4a27 --- /dev/null +++ b/website/sidebars.js @@ -0,0 +1,3864 @@ +// Generated by CrocoDocs from website/sidebars.yml. +// Do not edit by hand. + +module.exports = { + "docs": [ + { + "type": "doc", + "id": "index", + "label": "Introduction" + }, + { + "type": "category", + "label": "Getting started", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "getting-started/installation" + }, + { + "type": "doc", + "id": "getting-started/create-flet-app" + }, + { + "type": "doc", + "id": "getting-started/running-app" + }, + { + "type": "doc", + "id": "getting-started/testing-on-mobile" + } + ] + }, + { + "type": "category", + "label": "Tutorials", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "tutorials/calculator", + "label": "Calculator" + }, + { + "type": "doc", + "id": "tutorials/todo", + "label": "ToDo" + }, + { + "type": "doc", + "id": "tutorials/chat", + "label": "Chat" + }, + { + "type": "doc", + "id": "tutorials/solitaire", + "label": "Solitaire" + } + ] + }, + { + "type": "category", + "label": "Cookbook", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "cookbook/expanding-controls", + "label": "Expanding Controls" + }, + { + "type": "doc", + "id": "cookbook/colors", + "label": "Colors" + }, + { + "type": "doc", + "id": "cookbook/fonts", + "label": "Fonts" + }, + { + "type": "doc", + "id": "cookbook/theming", + "label": "Theming" + }, + { + "type": "doc", + "id": "cookbook/assets", + "label": "Assets" + }, + { + "type": "doc", + "id": "cookbook/animations", + "label": "Animations" + }, + { + "type": "doc", + "id": "cookbook/adaptive-apps", + "label": "Adaptive apps" + }, + { + "type": "doc", + "id": "cookbook/keyboard-shortcuts", + "label": "Keyboard Shortcuts" + }, + { + "type": "doc", + "id": "cookbook/drag-and-drop", + "label": "Drag and Drop" + }, + { + "type": "doc", + "id": "cookbook/large-lists", + "label": "Large Lists" + }, + { + "type": "doc", + "id": "cookbook/accessibility", + "label": "Accessibility" + }, + { + "type": "doc", + "id": "cookbook/navigation-and-routing", + "label": "Navigation and Routing" + }, + { + "type": "doc", + "id": "cookbook/router", + "label": "Router" + }, + { + "type": "doc", + "id": "cookbook/control-refs", + "label": "Control Refs" + }, + { + "type": "doc", + "id": "cookbook/custom-controls", + "label": "Custom Controls" + }, + { + "type": "doc", + "id": "cookbook/declarative-vs-imperative-crud-app", + "label": "Declarative vs Imperative CRUD app" + }, + { + "type": "doc", + "id": "cookbook/async-apps", + "label": "Async apps" + }, + { + "type": "doc", + "id": "cookbook/read-and-write-files", + "label": "Read and Write Files" + }, + { + "type": "doc", + "id": "cookbook/client-storage", + "label": "Client Storage" + }, + { + "type": "doc", + "id": "cookbook/session-storage", + "label": "Session Storage" + }, + { + "type": "doc", + "id": "cookbook/pub-sub", + "label": "PubSub" + }, + { + "type": "doc", + "id": "cookbook/subprocess", + "label": "Subprocess" + }, + { + "type": "doc", + "id": "cookbook/logging", + "label": "Logging" + }, + { + "type": "doc", + "id": "cookbook/authentication", + "label": "Authentication" + }, + { + "type": "doc", + "id": "cookbook/encrypting-sensitive-data", + "label": "Encrypting sensitive data" + } + ] + }, + { + "type": "category", + "label": "Publishing Flet app", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "publish/android", + "label": "Android" + }, + { + "type": "doc", + "id": "publish/ios", + "label": "iOS" + }, + { + "type": "doc", + "id": "publish/linux", + "label": "Linux" + }, + { + "type": "doc", + "id": "publish/macos", + "label": "macOS" + }, + { + "type": "doc", + "id": "publish/windows", + "label": "Windows" + }, + { + "type": "category", + "label": "Web", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Dynamic Website", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Hosting", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "publish/web/dynamic-website/hosting/fly-io", + "label": "Fly.io" + }, + { + "type": "doc", + "id": "publish/web/dynamic-website/hosting/replit", + "label": "Replit" + }, + { + "type": "doc", + "id": "publish/web/dynamic-website/hosting/self-hosting", + "label": "Self-Hosting" + } + ], + "link": { + "type": "doc", + "id": "publish/web/dynamic-website/hosting/index" + } + } + ], + "link": { + "type": "doc", + "id": "publish/web/dynamic-website/index" + } + }, + { + "type": "category", + "label": "Static Website", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Hosting", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "publish/web/static-website/hosting/cloudflare", + "label": "Cloudflare" + }, + { + "type": "doc", + "id": "publish/web/static-website/hosting/github-pages", + "label": "GitHub Pages" + } + ] + } + ], + "link": { + "type": "doc", + "id": "publish/web/static-website/index" + } + } + ], + "link": { + "type": "doc", + "id": "publish/web/index" + } + } + ], + "link": { + "type": "doc", + "id": "publish/index" + } + }, + { + "type": "category", + "label": "Extending Flet", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "extend/user-extensions" + }, + { + "type": "doc", + "id": "extend/built-in-extensions" + } + ] + }, + { + "type": "category", + "label": "Reference", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Controls", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Ads", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/ads/bannerad", + "label": "BannerAd" + }, + { + "type": "doc", + "id": "controls/ads/basead", + "label": "BaseAd" + }, + { + "type": "doc", + "id": "controls/ads/interstitialad", + "label": "InterstitialAd" + } + ], + "link": { + "type": "doc", + "id": "controls/ads/index" + } + }, + { + "type": "doc", + "id": "controls/alertdialog", + "label": "AlertDialog" + }, + { + "type": "doc", + "id": "controls/animatedswitcher", + "label": "AnimatedSwitcher" + }, + { + "type": "doc", + "id": "controls/appbar", + "label": "AppBar" + }, + { + "type": "doc", + "id": "controls/autocomplete", + "label": "AutoComplete" + }, + { + "type": "doc", + "id": "controls/autofillgroup", + "label": "AutofillGroup" + }, + { + "type": "doc", + "id": "types/badge", + "label": "Badge" + }, + { + "type": "doc", + "id": "controls/banner", + "label": "Banner" + }, + { + "type": "doc", + "id": "controls/bottomappbar", + "label": "BottomAppBar" + }, + { + "type": "doc", + "id": "controls/bottomsheet", + "label": "BottomSheet" + }, + { + "type": "doc", + "id": "controls/button", + "label": "Button" + }, + { + "type": "doc", + "id": "controls/camera/index", + "label": "Camera" + }, + { + "type": "category", + "label": "Canvas", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/canvas/arc", + "label": "Arc" + }, + { + "type": "doc", + "id": "controls/canvas/circle", + "label": "Circle" + }, + { + "type": "doc", + "id": "controls/canvas/color", + "label": "Color" + }, + { + "type": "doc", + "id": "controls/canvas/fill", + "label": "Fill" + }, + { + "type": "doc", + "id": "controls/canvas/image", + "label": "Image" + }, + { + "type": "doc", + "id": "controls/canvas/line", + "label": "Line" + }, + { + "type": "doc", + "id": "controls/canvas/oval", + "label": "Oval" + }, + { + "type": "doc", + "id": "controls/canvas/path", + "label": "Path" + }, + { + "type": "doc", + "id": "controls/canvas/points", + "label": "Points" + }, + { + "type": "doc", + "id": "controls/canvas/rect", + "label": "Rect" + }, + { + "type": "doc", + "id": "controls/canvas/shadow", + "label": "Shadow" + }, + { + "type": "doc", + "id": "controls/canvas/shape", + "label": "Shape" + }, + { + "type": "doc", + "id": "controls/canvas/text", + "label": "Text" + } + ], + "link": { + "type": "doc", + "id": "controls/canvas/index" + } + }, + { + "type": "doc", + "id": "controls/card", + "label": "Card" + }, + { + "type": "category", + "label": "Charts", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/charts/barchart", + "label": "BarChart" + }, + { + "type": "doc", + "id": "controls/charts/candlestickchart", + "label": "CandlestickChart" + }, + { + "type": "doc", + "id": "controls/charts/linechart", + "label": "LineChart" + }, + { + "type": "doc", + "id": "controls/charts/matplotlibchart", + "label": "MatplotlibChart" + }, + { + "type": "doc", + "id": "controls/charts/matplotlibchartwithtoolbar", + "label": "MatplotlibChartWithToolbar" + }, + { + "type": "doc", + "id": "controls/charts/piechart", + "label": "PieChart" + }, + { + "type": "doc", + "id": "controls/charts/plotlychart", + "label": "PlotlyChart" + }, + { + "type": "doc", + "id": "controls/charts/radarchart", + "label": "RadarChart" + }, + { + "type": "doc", + "id": "controls/charts/scatterchart", + "label": "ScatterChart" + } + ], + "link": { + "type": "doc", + "id": "controls/charts/index" + } + }, + { + "type": "doc", + "id": "controls/checkbox", + "label": "Checkbox" + }, + { + "type": "doc", + "id": "controls/chip", + "label": "Chip" + }, + { + "type": "doc", + "id": "controls/circleavatar", + "label": "CircleAvatar" + }, + { + "type": "doc", + "id": "controls/codeeditor/index", + "label": "CodeEditor" + }, + { + "type": "category", + "label": "Color pickers", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/colorpickers/colorpicker", + "label": "ColorPicker" + }, + { + "type": "doc", + "id": "controls/colorpickers/blockpicker", + "label": "BlockPicker" + }, + { + "type": "doc", + "id": "controls/colorpickers/hueringpicker", + "label": "HueRingPicker" + }, + { + "type": "doc", + "id": "controls/colorpickers/materialpicker", + "label": "MaterialPicker" + }, + { + "type": "doc", + "id": "controls/colorpickers/multiplechoiceblockpicker", + "label": "MultipleChoiceBlockPicker" + }, + { + "type": "doc", + "id": "controls/colorpickers/slidepicker", + "label": "SlidePicker" + } + ], + "link": { + "type": "doc", + "id": "controls/colorpickers/index" + } + }, + { + "type": "doc", + "id": "controls/column", + "label": "Column" + }, + { + "type": "doc", + "id": "controls/container", + "label": "Container" + }, + { + "type": "doc", + "id": "controls/contextmenu", + "label": "ContextMenu" + }, + { + "type": "category", + "label": "CupertinoActionSheet", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/cupertinoactionsheetaction", + "label": "CupertinoActionSheetAction" + } + ], + "link": { + "type": "doc", + "id": "controls/cupertinoactionsheet/index" + } + }, + { + "type": "doc", + "id": "controls/cupertinoactivityindicator", + "label": "CupertinoActivityIndicator" + }, + { + "type": "doc", + "id": "controls/cupertinoalertdialog", + "label": "CupertinoAlertDialog" + }, + { + "type": "doc", + "id": "controls/cupertinoappbar", + "label": "CupertinoAppBar" + }, + { + "type": "doc", + "id": "controls/cupertinobottomsheet", + "label": "CupertinoBottomSheet" + }, + { + "type": "doc", + "id": "controls/cupertinobutton", + "label": "CupertinoButton" + }, + { + "type": "doc", + "id": "controls/cupertinocheckbox", + "label": "CupertinoCheckbox" + }, + { + "type": "category", + "label": "CupertinoContextMenu", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/cupertinocontextmenuaction", + "label": "CupertinoContextMenuAction" + } + ], + "link": { + "type": "doc", + "id": "controls/cupertinocontextmenu/index" + } + }, + { + "type": "doc", + "id": "controls/cupertinodatepicker", + "label": "CupertinoDatePicker" + }, + { + "type": "doc", + "id": "controls/cupertinodialogaction", + "label": "CupertinoDialogAction" + }, + { + "type": "doc", + "id": "controls/cupertinofilledbutton", + "label": "CupertinoFilledButton" + }, + { + "type": "doc", + "id": "controls/cupertinolisttile", + "label": "CupertinoListTile" + }, + { + "type": "doc", + "id": "controls/cupertinonavigationbar", + "label": "CupertinoNavigationBar" + }, + { + "type": "doc", + "id": "controls/cupertinopicker", + "label": "CupertinoPicker" + }, + { + "type": "doc", + "id": "controls/cupertinoradio", + "label": "CupertinoRadio" + }, + { + "type": "doc", + "id": "controls/cupertinosegmentedbutton", + "label": "CupertinoSegmentedButton" + }, + { + "type": "doc", + "id": "controls/cupertinoslider", + "label": "CupertinoSlider" + }, + { + "type": "doc", + "id": "controls/cupertinoslidingsegmentedbutton", + "label": "CupertinoSlidingSegmentedButton" + }, + { + "type": "doc", + "id": "controls/cupertinoswitch", + "label": "CupertinoSwitch" + }, + { + "type": "doc", + "id": "controls/cupertinotextfield", + "label": "CupertinoTextField" + }, + { + "type": "doc", + "id": "controls/cupertinotimerpicker", + "label": "CupertinoTimerPicker" + }, + { + "type": "doc", + "id": "controls/cupertinotintedbutton", + "label": "CupertinoTintedButton" + }, + { + "type": "doc", + "id": "controls/datepicker", + "label": "DatePicker" + }, + { + "type": "doc", + "id": "controls/daterangepicker", + "label": "DateRangePicker" + }, + { + "type": "category", + "label": "DataTable", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/datacell", + "label": "DataCell" + }, + { + "type": "doc", + "id": "controls/datacolumn", + "label": "DataColumn" + }, + { + "type": "doc", + "id": "controls/datarow", + "label": "DataRow" + } + ], + "link": { + "type": "doc", + "id": "controls/datatable/index" + } + }, + { + "type": "category", + "label": "DataTable2", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/datatable2/datacolumn2", + "label": "DataColumn2" + }, + { + "type": "doc", + "id": "controls/datatable2/datarow2", + "label": "DataRow2" + } + ], + "link": { + "type": "doc", + "id": "controls/datatable2/index" + } + }, + { + "type": "doc", + "id": "controls/dismissible", + "label": "Dismissible" + }, + { + "type": "doc", + "id": "controls/divider", + "label": "Divider" + }, + { + "type": "doc", + "id": "controls/dragtarget", + "label": "DragTarget" + }, + { + "type": "doc", + "id": "controls/draggable", + "label": "Draggable" + }, + { + "type": "category", + "label": "Dropdown", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/dropdownoption", + "label": "DropdownOption" + } + ], + "link": { + "type": "doc", + "id": "controls/dropdown/index" + } + }, + { + "type": "doc", + "id": "controls/expansionpanel", + "label": "ExpansionPanel" + }, + { + "type": "doc", + "id": "controls/expansionpanellist", + "label": "ExpansionPanelList" + }, + { + "type": "doc", + "id": "controls/expansiontile", + "label": "ExpansionTile" + }, + { + "type": "doc", + "id": "controls/filledbutton", + "label": "FilledButton" + }, + { + "type": "doc", + "id": "controls/fillediconbutton", + "label": "FilledIconButton" + }, + { + "type": "doc", + "id": "controls/filledtonalbutton", + "label": "FilledTonalButton" + }, + { + "type": "doc", + "id": "controls/filledtonaliconbutton", + "label": "FilledTonalIconButton" + }, + { + "type": "doc", + "id": "controls/fletapp", + "label": "FletApp" + }, + { + "type": "doc", + "id": "controls/floatingactionbutton", + "label": "FloatingActionButton" + }, + { + "type": "doc", + "id": "controls/gesturedetector", + "label": "GestureDetector" + }, + { + "type": "doc", + "id": "controls/gridview", + "label": "GridView" + }, + { + "type": "doc", + "id": "controls/hero", + "label": "Hero" + }, + { + "type": "doc", + "id": "controls/icon", + "label": "Icon" + }, + { + "type": "doc", + "id": "controls/iconbutton", + "label": "IconButton" + }, + { + "type": "doc", + "id": "controls/image", + "label": "Image" + }, + { + "type": "doc", + "id": "controls/interactiveviewer", + "label": "InteractiveViewer" + }, + { + "type": "doc", + "id": "controls/keyboardlistener", + "label": "KeyboardListener" + }, + { + "type": "doc", + "id": "controls/listtile", + "label": "ListTile" + }, + { + "type": "doc", + "id": "controls/listview", + "label": "ListView" + }, + { + "type": "doc", + "id": "controls/lottie/index", + "label": "Lottie" + }, + { + "type": "category", + "label": "Map", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/map/mapcontrol", + "label": "Map" + }, + { + "type": "category", + "label": "Layers", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/map/maplayer" + }, + { + "type": "doc", + "id": "controls/map/tilelayer" + }, + { + "type": "doc", + "id": "controls/map/markerlayer" + }, + { + "type": "doc", + "id": "controls/map/overlayimagelayer" + }, + { + "type": "doc", + "id": "controls/map/circlelayer" + }, + { + "type": "doc", + "id": "controls/map/polygonlayer" + }, + { + "type": "doc", + "id": "controls/map/polylinelayer" + } + ] + }, + { + "type": "category", + "label": "Markers", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/map/marker" + }, + { + "type": "doc", + "id": "controls/map/circlemarker" + }, + { + "type": "doc", + "id": "controls/map/polygonmarker" + }, + { + "type": "doc", + "id": "controls/map/polylinemarker" + } + ] + }, + { + "type": "category", + "label": "Overlays", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/map/baseoverlayimage" + }, + { + "type": "doc", + "id": "controls/map/overlayimage" + }, + { + "type": "doc", + "id": "controls/map/rotatedoverlayimage" + } + ] + }, + { + "type": "category", + "label": "Attributions", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/map/sourceattribution" + }, + { + "type": "doc", + "id": "controls/map/simpleattribution" + }, + { + "type": "doc", + "id": "controls/map/richattribution" + }, + { + "type": "doc", + "id": "controls/map/textsourceattribution" + }, + { + "type": "doc", + "id": "controls/map/imagesourceattribution" + } + ] + } + ], + "link": { + "type": "doc", + "id": "controls/map/index" + } + }, + { + "type": "doc", + "id": "controls/markdown", + "label": "Markdown" + }, + { + "type": "doc", + "id": "controls/menubar", + "label": "MenuBar" + }, + { + "type": "doc", + "id": "controls/menuitembutton", + "label": "MenuItemButton" + }, + { + "type": "doc", + "id": "controls/mergesemantics", + "label": "MergeSemantics" + }, + { + "type": "doc", + "id": "controls/multiview", + "label": "MultiView" + }, + { + "type": "category", + "label": "NavigationBar", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/navigationbardestination", + "label": "NavigationBarDestination" + } + ], + "link": { + "type": "doc", + "id": "controls/navigationbar/index" + } + }, + { + "type": "category", + "label": "NavigationDrawer", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/navigationdrawerdestination", + "label": "NavigationDrawerDestination" + } + ], + "link": { + "type": "doc", + "id": "controls/navigationdrawer/index" + } + }, + { + "type": "category", + "label": "NavigationRail", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/navigationraildestination", + "label": "NavigationRailDestination" + } + ], + "link": { + "type": "doc", + "id": "controls/navigationrail/index" + } + }, + { + "type": "doc", + "id": "controls/outlinedbutton", + "label": "OutlinedButton" + }, + { + "type": "doc", + "id": "controls/outlinediconbutton", + "label": "OutlinedIconButton" + }, + { + "type": "doc", + "id": "controls/page", + "label": "Page" + }, + { + "type": "doc", + "id": "controls/pagelet", + "label": "Pagelet" + }, + { + "type": "doc", + "id": "controls/pageview", + "label": "PageView" + }, + { + "type": "doc", + "id": "controls/placeholder", + "label": "Placeholder" + }, + { + "type": "doc", + "id": "controls/popupmenubutton", + "label": "PopupMenuButton" + }, + { + "type": "doc", + "id": "controls/progressbar", + "label": "ProgressBar" + }, + { + "type": "doc", + "id": "controls/progressring", + "label": "ProgressRing" + }, + { + "type": "doc", + "id": "controls/radio", + "label": "Radio" + }, + { + "type": "doc", + "id": "controls/radiogroup", + "label": "RadioGroup" + }, + { + "type": "doc", + "id": "controls/rangeslider", + "label": "RangeSlider" + }, + { + "type": "doc", + "id": "controls/reorderabledraghandle", + "label": "ReorderableDragHandle" + }, + { + "type": "doc", + "id": "controls/reorderablelistview", + "label": "ReorderableListView" + }, + { + "type": "doc", + "id": "controls/responsiverow", + "label": "ResponsiveRow" + }, + { + "type": "doc", + "id": "controls/rotatedbox", + "label": "RotatedBox" + }, + { + "type": "doc", + "id": "controls/router", + "label": "Router" + }, + { + "type": "doc", + "id": "controls/row", + "label": "Row" + }, + { + "type": "doc", + "id": "controls/rive/index", + "label": "Rive" + }, + { + "type": "doc", + "id": "controls/safearea", + "label": "SafeArea" + }, + { + "type": "doc", + "id": "controls/searchbar", + "label": "SearchBar" + }, + { + "type": "category", + "label": "SegmentedButton", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/segment", + "label": "Segment" + } + ], + "link": { + "type": "doc", + "id": "controls/segmentedbutton/index" + } + }, + { + "type": "doc", + "id": "controls/selectionarea", + "label": "SelectionArea" + }, + { + "type": "doc", + "id": "controls/semantics", + "label": "Semantics" + }, + { + "type": "doc", + "id": "controls/screenshot", + "label": "Screenshot" + }, + { + "type": "doc", + "id": "controls/shadermask", + "label": "ShaderMask" + }, + { + "type": "doc", + "id": "controls/shimmer", + "label": "Shimmer" + }, + { + "type": "doc", + "id": "controls/slider", + "label": "Slider" + }, + { + "type": "doc", + "id": "controls/snackbar", + "label": "SnackBar" + }, + { + "type": "doc", + "id": "controls/stack", + "label": "Stack" + }, + { + "type": "doc", + "id": "controls/submenubutton", + "label": "SubmenuButton" + }, + { + "type": "doc", + "id": "controls/switch", + "label": "Switch" + }, + { + "type": "category", + "label": "Tabs", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/tab", + "label": "Tab" + }, + { + "type": "doc", + "id": "controls/tabbar", + "label": "TabBar" + }, + { + "type": "doc", + "id": "controls/tabbarview", + "label": "TabBarView" + } + ], + "link": { + "type": "doc", + "id": "controls/tabs/index" + } + }, + { + "type": "doc", + "id": "controls/text", + "label": "Text" + }, + { + "type": "doc", + "id": "controls/textbutton", + "label": "TextButton" + }, + { + "type": "doc", + "id": "controls/textfield", + "label": "TextField" + }, + { + "type": "doc", + "id": "controls/timepicker", + "label": "TimePicker" + }, + { + "type": "doc", + "id": "controls/transparentpointer", + "label": "TransparentPointer" + }, + { + "type": "doc", + "id": "controls/verticaldivider", + "label": "VerticalDivider" + }, + { + "type": "doc", + "id": "controls/video/index", + "label": "Video" + }, + { + "type": "doc", + "id": "controls/view", + "label": "View" + }, + { + "type": "doc", + "id": "controls/webview/index", + "label": "WebView" + }, + { + "type": "doc", + "id": "controls/windowdragarea", + "label": "WindowDragArea" + } + ], + "link": { + "type": "generated-index", + "title": "Controls", + "slug": "/controls", + "description": "Browse the complete catalog of controls available in Flet." + } + }, + { + "type": "category", + "label": "Services", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "services/accelerometer", + "label": "Accelerometer" + }, + { + "type": "doc", + "id": "services/audio/index", + "label": "Audio" + }, + { + "type": "doc", + "id": "services/audiorecorder/index", + "label": "AudioRecorder" + }, + { + "type": "doc", + "id": "services/barometer", + "label": "Barometer" + }, + { + "type": "doc", + "id": "services/battery", + "label": "Battery" + }, + { + "type": "doc", + "id": "services/browsercontextmenu", + "label": "BrowserContextMenu" + }, + { + "type": "doc", + "id": "services/clipboard", + "label": "Clipboard" + }, + { + "type": "doc", + "id": "services/connectivity", + "label": "Connectivity" + }, + { + "type": "doc", + "id": "services/filepicker", + "label": "FilePicker" + }, + { + "type": "doc", + "id": "services/flashlight/index", + "label": "Flashlight" + }, + { + "type": "doc", + "id": "services/geolocator/index", + "label": "Geolocator" + }, + { + "type": "doc", + "id": "services/gyroscope", + "label": "Gyroscope" + }, + { + "type": "doc", + "id": "services/hapticfeedback", + "label": "HapticFeedback" + }, + { + "type": "doc", + "id": "services/magnetometer", + "label": "Magnetometer" + }, + { + "type": "doc", + "id": "services/permissionhandler/index", + "label": "PermissionHandler" + }, + { + "type": "doc", + "id": "services/screenbrightness", + "label": "ScreenBrightness" + }, + { + "type": "doc", + "id": "services/semanticsservice", + "label": "SemanticsService" + }, + { + "type": "doc", + "id": "services/shakedetector", + "label": "ShakeDetector" + }, + { + "type": "doc", + "id": "services/share", + "label": "Share" + }, + { + "type": "doc", + "id": "services/securestorage/index", + "label": "SecureStorage" + }, + { + "type": "doc", + "id": "services/sharedpreferences", + "label": "SharedPreferences" + }, + { + "type": "doc", + "id": "services/storagepaths", + "label": "StoragePaths" + }, + { + "type": "doc", + "id": "services/urllauncher", + "label": "UrlLauncher" + }, + { + "type": "doc", + "id": "services/useraccelerometer", + "label": "UserAccelerometer" + }, + { + "type": "doc", + "id": "services/wakelock", + "label": "Wakelock" + } + ], + "link": { + "type": "generated-index", + "title": "Services", + "slug": "/services", + "description": "Browse the complete catalog of services available in Flet." + } + }, + { + "type": "category", + "label": "Types", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/aliases", + "label": "Aliases" + }, + { + "type": "category", + "label": "Authentication", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/auth/authorization" + }, + { + "type": "doc", + "id": "types/auth/authorizationservice" + }, + { + "type": "doc", + "id": "types/auth/group" + }, + { + "type": "doc", + "id": "types/auth/oauthtoken" + }, + { + "type": "category", + "label": "OAuthProvider", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/auth/auth0oauthprovider", + "label": "Auth0OAuthProvider" + }, + { + "type": "doc", + "id": "types/auth/azureoauthprovider", + "label": "AzureOAuthProvider" + }, + { + "type": "doc", + "id": "types/auth/githuboauthprovider", + "label": "GitHubOAuthProvider" + }, + { + "type": "doc", + "id": "types/auth/googleoauthprovider", + "label": "GoogleOAuthProvider" + } + ], + "link": { + "type": "doc", + "id": "types/auth/oauthprovider/index" + } + }, + { + "type": "doc", + "id": "types/auth/user" + } + ] + }, + { + "type": "category", + "label": "Base Controls", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/adaptivecontrol" + }, + { + "type": "doc", + "id": "controls/basecontrol" + }, + { + "type": "doc", + "id": "controls/basepage" + }, + { + "type": "doc", + "id": "controls/control" + }, + { + "type": "doc", + "id": "controls/dialogcontrol" + }, + { + "type": "doc", + "id": "controls/formfieldcontrol" + }, + { + "type": "doc", + "id": "controls/layoutcontrol" + }, + { + "type": "doc", + "id": "controls/scrollablecontrol" + }, + { + "type": "doc", + "id": "controls/service" + }, + { + "type": "doc", + "id": "types/window" + } + ] + }, + { + "type": "category", + "label": "Classes", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Ads", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/ads/types/adrequest" + } + ] + }, + { + "type": "doc", + "id": "types/alignment" + }, + { + "type": "doc", + "id": "types/androidbuildversion" + }, + { + "type": "doc", + "id": "types/animation" + }, + { + "type": "doc", + "id": "types/animationstyle" + }, + { + "type": "category", + "label": "Audio", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "services/audio/types/audiodurationchangeevent" + }, + { + "type": "doc", + "id": "services/audio/types/audiopositionchangeevent" + }, + { + "type": "doc", + "id": "services/audio/types/audiostatechangeevent" + }, + { + "type": "doc", + "id": "services/audio/types/audiostate" + }, + { + "type": "doc", + "id": "services/audio/types/releasemode" + } + ] + }, + { + "type": "category", + "label": "AudioRecorder", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "services/audiorecorder/types/androidaudiosource" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/androidrecorderconfiguration" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audioencoder" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audiorecorderconfiguration" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audiorecorderstatechangeevent" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audiorecorderstreamevent" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audiorecorderstate" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audiorecorderuploadevent" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/audiorecorderuploadsettings" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/inputdevice" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/iosaudiocategoryoption" + }, + { + "type": "doc", + "id": "services/audiorecorder/types/iosrecorderconfiguration" + } + ] + }, + { + "type": "doc", + "id": "types/autocompletesuggestion" + }, + { + "type": "doc", + "id": "types/blur" + }, + { + "type": "doc", + "id": "types/border" + }, + { + "type": "doc", + "id": "types/borderradius" + }, + { + "type": "doc", + "id": "types/borderside" + }, + { + "type": "doc", + "id": "types/boxconstraints" + }, + { + "type": "doc", + "id": "types/boxdecoration" + }, + { + "type": "doc", + "id": "types/boxshadow" + }, + { + "type": "doc", + "id": "types/buttonstyle" + }, + { + "type": "category", + "label": "Camera", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/camera/types/cameradescription" + }, + { + "type": "doc", + "id": "controls/camera/types/cameraimageevent" + }, + { + "type": "doc", + "id": "controls/camera/types/cameralensdirection" + }, + { + "type": "doc", + "id": "controls/camera/types/cameralenstype" + }, + { + "type": "doc", + "id": "controls/camera/types/camerapreviewsize" + }, + { + "type": "doc", + "id": "controls/camera/types/camerastateevent" + }, + { + "type": "doc", + "id": "controls/camera/types/exposuremode" + }, + { + "type": "doc", + "id": "controls/camera/types/flashmode" + }, + { + "type": "doc", + "id": "controls/camera/types/focusmode" + }, + { + "type": "doc", + "id": "controls/camera/types/imageformatgroup" + }, + { + "type": "doc", + "id": "controls/camera/types/resolutionpreset" + } + ] + }, + { + "type": "category", + "label": "Charts", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/charts/types/barchartevent" + }, + { + "type": "doc", + "id": "controls/charts/types/barchartgroup" + }, + { + "type": "doc", + "id": "controls/charts/types/barchartrod" + }, + { + "type": "doc", + "id": "controls/charts/types/barchartrodstackitem" + }, + { + "type": "doc", + "id": "controls/charts/types/barchartrodtooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/barcharttooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/barcharttooltipdirection" + }, + { + "type": "doc", + "id": "controls/charts/types/candlestickchartevent" + }, + { + "type": "doc", + "id": "controls/charts/types/candlestickchartspot" + }, + { + "type": "doc", + "id": "controls/charts/types/candlestickchartspottooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/candlestickcharttooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/chartaxis" + }, + { + "type": "doc", + "id": "controls/charts/types/chartaxislabel" + }, + { + "type": "doc", + "id": "controls/charts/types/chartcirclepoint" + }, + { + "type": "doc", + "id": "controls/charts/types/chartcrosspoint" + }, + { + "type": "doc", + "id": "controls/charts/types/chartdatapointtooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/charteventtype" + }, + { + "type": "doc", + "id": "controls/charts/types/chartgridlines" + }, + { + "type": "doc", + "id": "controls/charts/types/chartpointline" + }, + { + "type": "doc", + "id": "controls/charts/types/chartpointshape" + }, + { + "type": "doc", + "id": "controls/charts/types/chartsquarepoint" + }, + { + "type": "doc", + "id": "controls/charts/types/horizontalalignment" + }, + { + "type": "doc", + "id": "controls/charts/types/linechartdata" + }, + { + "type": "doc", + "id": "controls/charts/types/linechartdatapoint" + }, + { + "type": "doc", + "id": "controls/charts/types/linechartdatapointtooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/linechartevent" + }, + { + "type": "doc", + "id": "controls/charts/types/linecharteventspot" + }, + { + "type": "doc", + "id": "controls/charts/types/linecharttooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/piechartevent" + }, + { + "type": "doc", + "id": "controls/charts/types/piechartsection" + }, + { + "type": "doc", + "id": "controls/charts/types/radarchartevent" + }, + { + "type": "doc", + "id": "controls/charts/types/radarcharttitle" + }, + { + "type": "doc", + "id": "controls/charts/types/radardataset" + }, + { + "type": "doc", + "id": "controls/charts/types/radardatasetentry" + }, + { + "type": "doc", + "id": "controls/charts/types/radarshape" + }, + { + "type": "doc", + "id": "controls/charts/types/scatterchartevent" + }, + { + "type": "doc", + "id": "controls/charts/types/scatterchartspot" + }, + { + "type": "doc", + "id": "controls/charts/types/scatterchartspottooltip" + }, + { + "type": "doc", + "id": "controls/charts/types/scattercharttooltip" + } + ] + }, + { + "type": "doc", + "id": "types/colorfilter" + }, + { + "type": "doc", + "id": "types/context" + }, + { + "type": "doc", + "id": "types/controlstate" + }, + { + "type": "doc", + "id": "types/decorationimage" + }, + { + "type": "category", + "label": "DeviceInfo", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/androiddeviceinfo", + "label": "AndroidDeviceInfo" + }, + { + "type": "doc", + "id": "types/iosdeviceinfo", + "label": "IosDeviceInfo" + }, + { + "type": "doc", + "id": "types/linuxdeviceinfo", + "label": "LinuxDeviceInfo" + }, + { + "type": "doc", + "id": "types/macosdeviceinfo", + "label": "MacOsDeviceInfo" + }, + { + "type": "doc", + "id": "types/webdeviceinfo", + "label": "WebDeviceInfo" + }, + { + "type": "doc", + "id": "types/windowsdeviceinfo", + "label": "WindowsDeviceInfo" + } + ], + "link": { + "type": "doc", + "id": "types/deviceinfo/index" + } + }, + { + "type": "doc", + "id": "types/duration" + }, + { + "type": "doc", + "id": "types/filepickerfile" + }, + { + "type": "doc", + "id": "types/filepickeruploadfile" + }, + { + "type": "doc", + "id": "types/finder" + }, + { + "type": "doc", + "id": "types/flip" + }, + { + "type": "doc", + "id": "types/flettestapp" + }, + { + "type": "category", + "label": "Geolocator", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "services/geolocator/types/foregroundnotificationconfiguration" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorandroidconfiguration" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorconfiguration" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatoriosactivitytype" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatoriosconfiguration" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorpermissionstatus" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorposition" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorpositionaccuracy" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorpositionchangeevent" + }, + { + "type": "doc", + "id": "services/geolocator/types/geolocatorwebconfiguration" + } + ] + }, + { + "type": "category", + "label": "Gradient", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/lineargradient", + "label": "LinearGradient" + }, + { + "type": "doc", + "id": "types/radialgradient", + "label": "RadialGradient" + }, + { + "type": "doc", + "id": "types/sweepgradient", + "label": "SweepGradient" + } + ], + "link": { + "type": "doc", + "id": "types/gradient/index" + } + }, + { + "type": "doc", + "id": "types/inputborder" + }, + { + "type": "doc", + "id": "types/inputfilter" + }, + { + "type": "doc", + "id": "types/iosutsname" + }, + { + "type": "category", + "label": "Key", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/scrollkey", + "label": "ScrollKey" + }, + { + "type": "doc", + "id": "types/valuekey", + "label": "ValueKey" + } + ], + "link": { + "type": "doc", + "id": "types/key/index" + } + }, + { + "type": "doc", + "id": "types/locale" + }, + { + "type": "doc", + "id": "types/localeconfiguration" + }, + { + "type": "doc", + "id": "types/locationinfo" + }, + { + "type": "category", + "label": "Map", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/map/types/attributionalignment" + }, + { + "type": "doc", + "id": "controls/map/types/camera" + }, + { + "type": "doc", + "id": "controls/map/types/camerafit" + }, + { + "type": "doc", + "id": "controls/map/types/cursorkeyboardrotationconfiguration" + }, + { + "type": "doc", + "id": "controls/map/types/cursorrotationbehaviour" + }, + { + "type": "doc", + "id": "controls/map/types/dashedstrokepattern" + }, + { + "type": "doc", + "id": "controls/map/types/dottedstrokepattern" + }, + { + "type": "doc", + "id": "controls/map/types/fadeintiledisplay" + }, + { + "type": "doc", + "id": "controls/map/types/instantaneoustiledisplay" + }, + { + "type": "doc", + "id": "controls/map/types/interactionconfiguration" + }, + { + "type": "doc", + "id": "controls/map/types/interactionflag" + }, + { + "type": "doc", + "id": "controls/map/types/keyboardconfiguration" + }, + { + "type": "doc", + "id": "controls/map/types/mapevent" + }, + { + "type": "doc", + "id": "controls/map/types/mapeventtype" + }, + { + "type": "doc", + "id": "controls/map/types/mapeventsource" + }, + { + "type": "doc", + "id": "controls/map/types/maphoverevent" + }, + { + "type": "doc", + "id": "controls/map/types/maplatitudelongitude" + }, + { + "type": "doc", + "id": "controls/map/types/maplatitudelongitudebounds" + }, + { + "type": "doc", + "id": "controls/map/types/mappointerevent" + }, + { + "type": "doc", + "id": "controls/map/types/mappositionchangeevent" + }, + { + "type": "doc", + "id": "controls/map/types/maptapevent" + }, + { + "type": "doc", + "id": "controls/map/types/multifingergesture" + }, + { + "type": "doc", + "id": "controls/map/types/patternfit" + }, + { + "type": "doc", + "id": "controls/map/types/solidstrokepattern" + }, + { + "type": "doc", + "id": "controls/map/types/strokepattern" + }, + { + "type": "doc", + "id": "controls/map/types/tiledisplay" + }, + { + "type": "doc", + "id": "controls/map/types/tilelayerevicterrortilestrategy" + }, + { + "type": "doc", + "id": "controls/map/types/wmstilelayerconfiguration" + } + ] + }, + { + "type": "doc", + "id": "types/margin" + }, + { + "type": "doc", + "id": "types/matrix4" + }, + { + "type": "doc", + "id": "types/markdowncustomcodetheme" + }, + { + "type": "doc", + "id": "types/markdownstylesheet" + }, + { + "type": "doc", + "id": "types/menustyle" + }, + { + "type": "category", + "label": "NotchShape", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/automaticnotchshape", + "label": "AutomaticNotchShape" + }, + { + "type": "doc", + "id": "types/circularrectanglenotchshape", + "label": "CircularRectangleNotchShape" + } + ], + "link": { + "type": "doc", + "id": "types/notchshape/index" + } + }, + { + "type": "doc", + "id": "types/observable" + }, + { + "type": "doc", + "id": "types/offset" + }, + { + "type": "category", + "label": "OutlinedBorder", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/beveledrectangleborder", + "label": "BeveledRectangleBorder" + }, + { + "type": "doc", + "id": "types/circleborder", + "label": "CircleBorder" + }, + { + "type": "doc", + "id": "types/continuousrectangleborder", + "label": "ContinuousRectangleBorder" + }, + { + "type": "doc", + "id": "types/roundedrectangleborder", + "label": "RoundedRectangleBorder" + }, + { + "type": "doc", + "id": "types/stadiumborder", + "label": "StadiumBorder" + } + ], + "link": { + "type": "doc", + "id": "types/outlinedborder/index" + } + }, + { + "type": "doc", + "id": "types/padding" + }, + { + "type": "doc", + "id": "types/paint" + }, + { + "type": "category", + "label": "PaintGradient", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/paintlineargradient", + "label": "PaintLinearGradient" + }, + { + "type": "doc", + "id": "types/paintradialgradient", + "label": "PaintRadialGradient" + }, + { + "type": "doc", + "id": "types/paintsweepgradient", + "label": "PaintSweepGradient" + } + ], + "link": { + "type": "doc", + "id": "types/paintgradient/index" + } + }, + { + "type": "category", + "label": "PermissionHandler", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "services/permissionhandler/types/permission" + }, + { + "type": "doc", + "id": "services/permissionhandler/types/permissionstatus" + } + ] + }, + { + "type": "doc", + "id": "types/pubsub/pubsubclient" + }, + { + "type": "doc", + "id": "types/pubsub/pubsubhub" + }, + { + "type": "doc", + "id": "types/rect" + }, + { + "type": "doc", + "id": "types/ref" + }, + { + "type": "doc", + "id": "types/responsiverowbreakpoint" + }, + { + "type": "doc", + "id": "types/rotate" + }, + { + "type": "doc", + "id": "types/scale" + }, + { + "type": "category", + "label": "SecureStorage", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "services/securestorage/types/windowsoptions" + }, + { + "type": "doc", + "id": "services/securestorage/types/androidoptions" + }, + { + "type": "doc", + "id": "services/securestorage/types/appleoptions" + }, + { + "type": "doc", + "id": "services/securestorage/types/macosoptions" + }, + { + "type": "doc", + "id": "services/securestorage/types/iosoptions" + }, + { + "type": "doc", + "id": "services/securestorage/types/weboptions" + } + ] + }, + { + "type": "doc", + "id": "types/shapeborder" + }, + { + "type": "doc", + "id": "types/size" + }, + { + "type": "doc", + "id": "types/strutstyle" + }, + { + "type": "doc", + "id": "types/templateroute" + }, + { + "type": "doc", + "id": "types/tester" + }, + { + "type": "doc", + "id": "types/textdecoration" + }, + { + "type": "doc", + "id": "types/textselection" + }, + { + "type": "doc", + "id": "types/textspan" + }, + { + "type": "doc", + "id": "types/textstyle" + }, + { + "type": "doc", + "id": "types/textthemestyle" + }, + { + "type": "doc", + "id": "types/transform" + }, + { + "type": "category", + "label": "Theme", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/appbartheme", + "label": "AppBarTheme" + }, + { + "type": "doc", + "id": "types/badgetheme", + "label": "BadgeTheme" + }, + { + "type": "doc", + "id": "types/bannertheme", + "label": "BannerTheme" + }, + { + "type": "doc", + "id": "types/bottomappbartheme", + "label": "BottomAppBarTheme" + }, + { + "type": "doc", + "id": "types/bottomsheettheme", + "label": "BottomSheetTheme" + }, + { + "type": "doc", + "id": "types/buttontheme", + "label": "ButtonTheme" + }, + { + "type": "doc", + "id": "types/cardtheme", + "label": "CardTheme" + }, + { + "type": "doc", + "id": "types/checkboxtheme", + "label": "CheckboxTheme" + }, + { + "type": "doc", + "id": "types/chiptheme", + "label": "ChipTheme" + }, + { + "type": "doc", + "id": "types/colorscheme", + "label": "ColorScheme" + }, + { + "type": "doc", + "id": "types/datatabletheme", + "label": "DataTableTheme" + }, + { + "type": "doc", + "id": "types/datepickertheme", + "label": "DatePickerTheme" + }, + { + "type": "doc", + "id": "types/dialogtheme", + "label": "DialogTheme" + }, + { + "type": "doc", + "id": "types/dividertheme", + "label": "DividerTheme" + }, + { + "type": "doc", + "id": "types/dropdowntheme", + "label": "DropdownTheme" + }, + { + "type": "doc", + "id": "types/expansiontiletheme", + "label": "ExpansionTileTheme" + }, + { + "type": "doc", + "id": "types/filledbuttontheme", + "label": "FilledButtonTheme" + }, + { + "type": "doc", + "id": "types/floatingactionbuttontheme", + "label": "FloatingActionButtonTheme" + }, + { + "type": "doc", + "id": "types/iconbuttontheme", + "label": "IconButtonTheme" + }, + { + "type": "doc", + "id": "types/icontheme", + "label": "IconTheme" + }, + { + "type": "doc", + "id": "types/listtiletheme", + "label": "ListTileTheme" + }, + { + "type": "doc", + "id": "types/navigationbartheme", + "label": "NavigationBarTheme" + }, + { + "type": "doc", + "id": "types/navigationdrawertheme", + "label": "NavigationDrawerTheme" + }, + { + "type": "doc", + "id": "types/navigationrailtheme", + "label": "NavigationRailTheme" + }, + { + "type": "doc", + "id": "types/outlinedbuttontheme", + "label": "OutlinedButtonTheme" + }, + { + "type": "doc", + "id": "types/pagetransitionstheme", + "label": "PageTransitionsTheme" + }, + { + "type": "doc", + "id": "types/pagetransitiontheme", + "label": "PageTransitionTheme" + }, + { + "type": "doc", + "id": "types/popupmenutheme", + "label": "PopupMenuTheme" + }, + { + "type": "doc", + "id": "types/progressindicatortheme", + "label": "ProgressIndicatorTheme" + }, + { + "type": "doc", + "id": "types/radiotheme", + "label": "RadioTheme" + }, + { + "type": "doc", + "id": "types/scrollbartheme", + "label": "ScrollBarTheme" + }, + { + "type": "doc", + "id": "types/searchbartheme", + "label": "SearchBarTheme" + }, + { + "type": "doc", + "id": "types/searchviewtheme", + "label": "SearchViewTheme" + }, + { + "type": "doc", + "id": "types/segmentedbuttontheme", + "label": "SegmentedButtonTheme" + }, + { + "type": "doc", + "id": "types/slidertheme", + "label": "SliderTheme" + }, + { + "type": "doc", + "id": "types/snackbartheme", + "label": "SnackBarTheme" + }, + { + "type": "doc", + "id": "types/switchtheme", + "label": "SwitchTheme" + }, + { + "type": "doc", + "id": "types/systemoverlaystyle", + "label": "SystemOverlayStyle" + }, + { + "type": "doc", + "id": "types/tabbartheme", + "label": "TabBarTheme" + }, + { + "type": "doc", + "id": "types/textbuttontheme", + "label": "TextButtonTheme" + }, + { + "type": "doc", + "id": "types/texttheme", + "label": "TextTheme" + }, + { + "type": "doc", + "id": "types/timepickertheme", + "label": "TimePickerTheme" + }, + { + "type": "doc", + "id": "types/tooltiptheme", + "label": "TooltipTheme" + } + ], + "link": { + "type": "doc", + "id": "types/theme/index" + } + }, + { + "type": "doc", + "id": "types/browserconfiguration" + }, + { + "type": "doc", + "id": "types/tooltip" + }, + { + "type": "doc", + "id": "types/url" + }, + { + "type": "doc", + "id": "types/webviewconfiguration" + }, + { + "type": "doc", + "id": "types/underlinetabindicator" + }, + { + "type": "category", + "label": "CodeEditor", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/codeeditor/types/codelanguage" + }, + { + "type": "doc", + "id": "controls/codeeditor/types/codetheme" + }, + { + "type": "doc", + "id": "controls/codeeditor/types/customcodetheme" + }, + { + "type": "doc", + "id": "controls/codeeditor/types/gutterstyle" + } + ] + }, + { + "type": "category", + "label": "Video", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/video/types/adaptivevideocontrols" + }, + { + "type": "doc", + "id": "controls/video/types/materialdesktopvideocontrols" + }, + { + "type": "doc", + "id": "controls/video/types/materialvideocontrols" + }, + { + "type": "doc", + "id": "controls/video/types/playlistmode" + }, + { + "type": "doc", + "id": "controls/video/types/videobaritem" + }, + { + "type": "doc", + "id": "controls/video/types/videoconfiguration" + }, + { + "type": "doc", + "id": "controls/video/types/videocontrols" + }, + { + "type": "doc", + "id": "controls/video/types/videocontrolsmode" + }, + { + "type": "doc", + "id": "controls/video/types/videofullscreenbutton" + }, + { + "type": "doc", + "id": "controls/video/types/videomedia" + }, + { + "type": "doc", + "id": "controls/video/types/videoplayorpausebutton" + }, + { + "type": "doc", + "id": "controls/video/types/videopositionindicator" + }, + { + "type": "doc", + "id": "controls/video/types/videoskipnextbutton" + }, + { + "type": "doc", + "id": "controls/video/types/videoskippreviousbutton" + }, + { + "type": "doc", + "id": "controls/video/types/videospacer" + }, + { + "type": "doc", + "id": "controls/video/types/videosubtitleconfiguration" + }, + { + "type": "doc", + "id": "controls/video/types/videosubtitletrack" + }, + { + "type": "doc", + "id": "controls/video/types/videovolumebutton" + } + ] + }, + { + "type": "category", + "label": "WebView", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/webview/types/requestmethod" + }, + { + "type": "doc", + "id": "controls/webview/types/loglevelseverity" + }, + { + "type": "doc", + "id": "controls/webview/types/webviewconsolemessageevent" + }, + { + "type": "doc", + "id": "controls/webview/types/webviewjavascriptevent" + }, + { + "type": "doc", + "id": "controls/webview/types/webviewscrollevent" + } + ] + } + ] + }, + { + "type": "category", + "label": "Decorators", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/component" + }, + { + "type": "doc", + "id": "types/control" + }, + { + "type": "doc", + "id": "types/observabledecorator" + }, + { + "type": "doc", + "id": "types/value" + } + ] + }, + { + "type": "category", + "label": "Enums", + "collapsed": true, + "items": [ + { + "type": "category", + "label": "Ads", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/ads/types/precisiontype" + } + ] + }, + { + "type": "doc", + "id": "types/animatedswitchertransition" + }, + { + "type": "doc", + "id": "types/animationcurve" + }, + { + "type": "doc", + "id": "types/applifecyclestate" + }, + { + "type": "doc", + "id": "types/appview" + }, + { + "type": "doc", + "id": "types/assertiveness" + }, + { + "type": "doc", + "id": "types/autofillgroupdisposeaction" + }, + { + "type": "doc", + "id": "types/autofillhint" + }, + { + "type": "doc", + "id": "types/axis" + }, + { + "type": "doc", + "id": "types/blendmode" + }, + { + "type": "doc", + "id": "types/blurstyle" + }, + { + "type": "doc", + "id": "types/blurtilemode" + }, + { + "type": "doc", + "id": "types/bordersidestrokealign" + }, + { + "type": "doc", + "id": "types/borderstyle" + }, + { + "type": "doc", + "id": "types/boxfit" + }, + { + "type": "doc", + "id": "types/boxshape" + }, + { + "type": "doc", + "id": "types/brightness" + }, + { + "type": "doc", + "id": "types/cardvariant" + }, + { + "type": "doc", + "id": "types/clipbehavior" + }, + { + "type": "doc", + "id": "types/colors" + }, + { + "type": "doc", + "id": "types/contextmenutrigger" + }, + { + "type": "doc", + "id": "types/crossaxisalignment" + }, + { + "type": "doc", + "id": "types/cupertinobuttonsize" + }, + { + "type": "doc", + "id": "types/cupertinocolors" + }, + { + "type": "doc", + "id": "types/cupertinodatepickerdateorder" + }, + { + "type": "doc", + "id": "types/cupertinodatepickermode" + }, + { + "type": "doc", + "id": "types/cupertinoicons" + }, + { + "type": "doc", + "id": "types/cupertinotimerpickermode" + }, + { + "type": "category", + "label": "DataTable2", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/datatable2/types/datacolumnsize" + } + ] + }, + { + "type": "doc", + "id": "types/datepickerentrymode" + }, + { + "type": "doc", + "id": "types/datepickermode" + }, + { + "type": "doc", + "id": "types/dismissdirection" + }, + { + "type": "doc", + "id": "types/filepickerfiletype" + }, + { + "type": "doc", + "id": "types/filterquality" + }, + { + "type": "doc", + "id": "types/floatingactionbuttonlocation" + }, + { + "type": "doc", + "id": "types/fontweight" + }, + { + "type": "doc", + "id": "types/gradienttilemode" + }, + { + "type": "doc", + "id": "types/icons" + }, + { + "type": "doc", + "id": "types/imagerepeat" + }, + { + "type": "doc", + "id": "types/keyboardtype" + }, + { + "type": "doc", + "id": "types/labelposition" + }, + { + "type": "doc", + "id": "types/listtilestyle" + }, + { + "type": "doc", + "id": "types/listtiletitlealignment" + }, + { + "type": "doc", + "id": "types/mainaxisalignment" + }, + { + "type": "doc", + "id": "types/mousecursor" + }, + { + "type": "doc", + "id": "types/markdowncodetheme" + }, + { + "type": "doc", + "id": "types/markdownextensionset" + }, + { + "type": "doc", + "id": "types/navigationbarlabelbehavior" + }, + { + "type": "doc", + "id": "types/navigationraillabeltype" + }, + { + "type": "doc", + "id": "types/deviceorientation" + }, + { + "type": "doc", + "id": "types/orientation" + }, + { + "type": "doc", + "id": "types/overlayvisibilitymode" + }, + { + "type": "doc", + "id": "types/pageplatform" + }, + { + "type": "doc", + "id": "types/paintingstyle" + }, + { + "type": "doc", + "id": "types/pointerdevicetype" + }, + { + "type": "doc", + "id": "types/pointmode" + }, + { + "type": "doc", + "id": "types/popupmenuposition" + }, + { + "type": "doc", + "id": "types/route" + }, + { + "type": "doc", + "id": "types/routeurlstrategy" + }, + { + "type": "doc", + "id": "types/scrollbar" + }, + { + "type": "doc", + "id": "types/scrollbarorientation" + }, + { + "type": "doc", + "id": "types/scrolldirection" + }, + { + "type": "doc", + "id": "types/scrollmode" + }, + { + "type": "doc", + "id": "types/scrolltype" + }, + { + "type": "doc", + "id": "types/sliderinteraction" + }, + { + "type": "doc", + "id": "types/snackbarbehavior" + }, + { + "type": "doc", + "id": "types/stackfit" + }, + { + "type": "doc", + "id": "types/strokecap" + }, + { + "type": "doc", + "id": "types/strokejoin" + }, + { + "type": "doc", + "id": "types/tabalignment" + }, + { + "type": "doc", + "id": "types/tabbarindicatorsize" + }, + { + "type": "doc", + "id": "types/tabindicatoranimation" + }, + { + "type": "doc", + "id": "types/textaffinity" + }, + { + "type": "doc", + "id": "types/textalign" + }, + { + "type": "doc", + "id": "types/textbaseline" + }, + { + "type": "doc", + "id": "types/textcapitalization" + }, + { + "type": "doc", + "id": "types/textdecorationstyle" + }, + { + "type": "doc", + "id": "types/textoverflow" + }, + { + "type": "doc", + "id": "types/textselectionchangecause" + }, + { + "type": "doc", + "id": "types/thememode" + }, + { + "type": "doc", + "id": "types/tileaffinity" + }, + { + "type": "doc", + "id": "types/timepickerentrymode" + }, + { + "type": "doc", + "id": "types/timepickerhourformat" + }, + { + "type": "doc", + "id": "types/tooltiptriggermode" + }, + { + "type": "doc", + "id": "types/launchmode" + }, + { + "type": "doc", + "id": "types/urltarget" + }, + { + "type": "doc", + "id": "types/verticalalignment" + }, + { + "type": "doc", + "id": "types/visualdensity" + }, + { + "type": "doc", + "id": "types/webbrowsername" + }, + { + "type": "doc", + "id": "types/webrenderer" + }, + { + "type": "doc", + "id": "types/windoweventtype" + }, + { + "type": "doc", + "id": "types/windowresizeedge" + }, + { + "type": "doc", + "id": "services/securestorage/types/accesscontrolflag" + }, + { + "type": "doc", + "id": "services/securestorage/types/keychainaccessibility" + }, + { + "type": "doc", + "id": "services/securestorage/types/keycipheralgorithm" + }, + { + "type": "doc", + "id": "services/securestorage/types/storagecipheralgorithm" + } + ] + }, + { + "type": "category", + "label": "Events", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/accelerometerreadingevent" + }, + { + "type": "category", + "label": "Ads", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "controls/ads/types/paidadevent" + } + ] + }, + { + "type": "doc", + "id": "types/applifecyclestatechangeevent" + }, + { + "type": "doc", + "id": "types/autocompleteselectevent" + }, + { + "type": "doc", + "id": "types/barometerreadingevent" + }, + { + "type": "doc", + "id": "types/batterystate" + }, + { + "type": "doc", + "id": "types/batterystatechangeevent" + }, + { + "type": "doc", + "id": "types/connectivitytype" + }, + { + "type": "doc", + "id": "types/connectivitychangeevent" + }, + { + "type": "doc", + "id": "types/canvasresizeevent" + }, + { + "type": "doc", + "id": "types/contextmenudismissevent" + }, + { + "type": "doc", + "id": "types/contextmenuselectevent" + }, + { + "type": "doc", + "id": "types/datacolumnsortevent" + }, + { + "type": "doc", + "id": "types/datepickerentrymodechangeevent" + }, + { + "type": "doc", + "id": "types/dismissibledismissevent" + }, + { + "type": "doc", + "id": "types/dismissibleupdateevent" + }, + { + "type": "doc", + "id": "types/dragendevent" + }, + { + "type": "doc", + "id": "types/dragstartevent" + }, + { + "type": "doc", + "id": "types/dragtargetevent" + }, + { + "type": "doc", + "id": "types/dragtargetleaveevent" + }, + { + "type": "doc", + "id": "types/dragupdateevent" + }, + { + "type": "doc", + "id": "types/dragwillacceptevent" + }, + { + "type": "doc", + "id": "types/event" + }, + { + "type": "doc", + "id": "types/expansionpanellistchangeevent" + }, + { + "type": "doc", + "id": "types/filepickeruploadevent" + }, + { + "type": "doc", + "id": "types/gyroscopereadingevent" + }, + { + "type": "doc", + "id": "types/hoverevent" + }, + { + "type": "doc", + "id": "types/keyboardevent" + }, + { + "type": "doc", + "id": "types/keydownevent" + }, + { + "type": "doc", + "id": "types/keyrepeatevent" + }, + { + "type": "doc", + "id": "types/keyupevent" + }, + { + "type": "doc", + "id": "types/localechangeevent" + }, + { + "type": "doc", + "id": "types/loginevent" + }, + { + "type": "doc", + "id": "types/longpressendevent" + }, + { + "type": "doc", + "id": "types/longpressstartevent" + }, + { + "type": "doc", + "id": "types/magnetometerreadingevent" + }, + { + "type": "doc", + "id": "types/multitapevent" + }, + { + "type": "doc", + "id": "types/multiviewaddevent" + }, + { + "type": "doc", + "id": "types/multiviewremoveevent" + }, + { + "type": "doc", + "id": "types/onreorderevent" + }, + { + "type": "doc", + "id": "types/onscrollevent" + }, + { + "type": "doc", + "id": "types/pagemediadata" + }, + { + "type": "doc", + "id": "types/pageresizeevent" + }, + { + "type": "doc", + "id": "types/platformbrightnesschangeevent" + }, + { + "type": "doc", + "id": "types/pointerevent" + }, + { + "type": "doc", + "id": "types/routechangeevent" + }, + { + "type": "doc", + "id": "types/sensorerrorevent" + }, + { + "type": "doc", + "id": "types/scaleendevent" + }, + { + "type": "doc", + "id": "types/scalestartevent" + }, + { + "type": "doc", + "id": "types/scaleupdateevent" + }, + { + "type": "doc", + "id": "types/screenbrightnesschangeevent" + }, + { + "type": "doc", + "id": "types/shareresult" + }, + { + "type": "doc", + "id": "types/shareresultstatus" + }, + { + "type": "doc", + "id": "types/sharefile" + }, + { + "type": "doc", + "id": "types/sharecupertinoactivitytype" + }, + { + "type": "doc", + "id": "types/scrollevent" + }, + { + "type": "doc", + "id": "services/securestorage/types/securestorageevent" + }, + { + "type": "doc", + "id": "types/tabbarhoverevent" + }, + { + "type": "doc", + "id": "types/tapevent" + }, + { + "type": "doc", + "id": "types/textselectionchangeevent" + }, + { + "type": "doc", + "id": "types/timepickerentrymodechangeevent" + }, + { + "type": "doc", + "id": "types/useraccelerometerreadingevent" + }, + { + "type": "doc", + "id": "types/viewpopevent" + }, + { + "type": "doc", + "id": "types/windowevent" + } + ] + }, + { + "type": "category", + "label": "Exceptions", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/fletpagedisconnectedexception", + "label": "FletPageDisconnectedException" + }, + { + "type": "doc", + "id": "types/fletunimplementedplatformexception", + "label": "FletUnimplementedPlatformException" + }, + { + "type": "doc", + "id": "types/fletunsupportedplatformexception", + "label": "FletUnsupportedPlatformException" + } + ], + "link": { + "type": "doc", + "id": "types/fletexception/index" + } + }, + { + "type": "category", + "label": "FastAPI", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "fastapi/app" + }, + { + "type": "doc", + "id": "fastapi/app_manager" + }, + { + "type": "doc", + "id": "fastapi/fastapi" + }, + { + "type": "doc", + "id": "fastapi/fletapp" + }, + { + "type": "doc", + "id": "fastapi/fletoauth" + }, + { + "type": "doc", + "id": "fastapi/fletstaticfiles" + }, + { + "type": "doc", + "id": "fastapi/fletupload" + } + ] + }, + { + "type": "category", + "label": "Methods", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "types/createcontext" + }, + { + "type": "doc", + "id": "types/is_route_active" + }, + { + "type": "doc", + "id": "types/memo" + }, + { + "type": "doc", + "id": "types/onmounted" + }, + { + "type": "doc", + "id": "types/onunmounted" + }, + { + "type": "doc", + "id": "types/onupdated" + }, + { + "type": "doc", + "id": "types/usecallback" + }, + { + "type": "doc", + "id": "types/usecontext" + }, + { + "type": "doc", + "id": "types/useeffect" + }, + { + "type": "doc", + "id": "types/usememo" + }, + { + "type": "doc", + "id": "types/useref" + }, + { + "type": "doc", + "id": "types/use_route_loader_data" + }, + { + "type": "doc", + "id": "types/use_route_location" + }, + { + "type": "doc", + "id": "types/use_route_outlet" + }, + { + "type": "doc", + "id": "types/use_route_params" + }, + { + "type": "doc", + "id": "types/use_view_path" + }, + { + "type": "doc", + "id": "types/usestate" + } + ] + } + ], + "link": { + "type": "doc", + "id": "types/index" + } + }, + { + "type": "category", + "label": "CLI", + "collapsed": true, + "items": [ + { + "type": "doc", + "id": "cli/flet-build", + "label": "flet build" + }, + { + "type": "doc", + "id": "cli/flet-create", + "label": "flet create" + }, + { + "type": "doc", + "id": "cli/flet-debug", + "label": "flet debug" + }, + { + "type": "doc", + "id": "cli/flet-devices", + "label": "flet devices" + }, + { + "type": "doc", + "id": "cli/flet-doctor", + "label": "flet doctor" + }, + { + "type": "doc", + "id": "cli/flet-emulators", + "label": "flet emulators" + }, + { + "type": "doc", + "id": "cli/flet-pack", + "label": "flet pack" + }, + { + "type": "doc", + "id": "cli/flet-publish", + "label": "flet publish" + }, + { + "type": "doc", + "id": "cli/flet-run", + "label": "flet run" + }, + { + "type": "doc", + "id": "cli/flet-serve", + "label": "flet serve" + } + ], + "link": { + "type": "doc", + "id": "cli/index" + } + }, + { + "type": "doc", + "id": "reference/binary-packages-android-ios", + "label": "Python packages built in Flet" + }, + { + "type": "doc", + "id": "reference/environment-variables", + "label": "Environment Variables" + } + ], + "link": { + "type": "doc", + "id": "reference/index" + } + } + ] +}; diff --git a/website/sidebars.yml b/website/sidebars.yml new file mode 100644 index 0000000000..1c62adc184 --- /dev/null +++ b/website/sidebars.yml @@ -0,0 +1,847 @@ +# This is the CrocoDocs sidebar source consumed by `crocodocs generate`. + +docs: + Introduction: index.md + Getting started: + - getting-started/installation.md + - getting-started/create-flet-app.md + - getting-started/running-app.md + - getting-started/testing-on-mobile.md + Tutorials: + - Calculator: tutorials/calculator.md + - ToDo: tutorials/todo.md + - Chat: tutorials/chat.md + - Solitaire: tutorials/solitaire.md + Cookbook: + Expanding Controls: cookbook/expanding-controls.md + Colors: cookbook/colors.md + Fonts: cookbook/fonts.md + Theming: cookbook/theming.md + Assets: cookbook/assets.md + Animations: cookbook/animations.md + Adaptive apps: cookbook/adaptive-apps.md + Keyboard Shortcuts: cookbook/keyboard-shortcuts.md + Drag and Drop: cookbook/drag-and-drop.md + Large Lists: cookbook/large-lists.md + Accessibility: cookbook/accessibility.md + Navigation and Routing: cookbook/navigation-and-routing.md + Router: cookbook/router.md + Control Refs: cookbook/control-refs.md + Custom Controls: cookbook/custom-controls.md + Declarative vs Imperative CRUD app: cookbook/declarative-vs-imperative-crud-app.md + Async apps: cookbook/async-apps.md + Read and Write Files: cookbook/read-and-write-files.md + Client Storage: cookbook/client-storage.md + Session Storage: cookbook/session-storage.md + PubSub: cookbook/pub-sub.md + Subprocess: cookbook/subprocess.md + Logging: cookbook/logging.md + Authentication: cookbook/authentication.md + Encrypting sensitive data: cookbook/encrypting-sensitive-data.md + Publishing Flet app: + _index: publish/index.md + Android: publish/android.md + iOS: publish/ios.md + Linux: publish/linux.md + macOS: publish/macos.md + Windows: publish/windows.md + Web: + _index: publish/web/index.md + Dynamic Website: + _index: publish/web/dynamic-website/index.md + Hosting: + _index: publish/web/dynamic-website/hosting/index.md + Fly.io: publish/web/dynamic-website/hosting/fly-io.md + Replit: publish/web/dynamic-website/hosting/replit.md + Self-Hosting: publish/web/dynamic-website/hosting/self-hosting.md + Static Website: + _index: publish/web/static-website/index.md + Hosting: + - Cloudflare: publish/web/static-website/hosting/cloudflare.md + - GitHub Pages: publish/web/static-website/hosting/github-pages.md + Extending Flet: + - extend/user-extensions.md + - extend/built-in-extensions.md + Reference: + _index: reference/index.md + Controls: + _generated_index: + title: Controls + slug: /controls + description: Browse the complete catalog of controls available in Flet. + Ads: + _index: controls/ads/index.md + BannerAd: controls/ads/bannerad.md + BaseAd: controls/ads/basead.md + InterstitialAd: controls/ads/interstitialad.md + AlertDialog: controls/alertdialog.md + AnimatedSwitcher: controls/animatedswitcher.md + AppBar: controls/appbar.md + AutoComplete: controls/autocomplete.md + AutofillGroup: controls/autofillgroup.md + Badge: types/badge.md + Banner: controls/banner.md + BottomAppBar: controls/bottomappbar.md + BottomSheet: controls/bottomsheet.md + Button: controls/button.md + Camera: controls/camera/index.md + Canvas: + _index: controls/canvas/index.md + Arc: controls/canvas/arc.md + Circle: controls/canvas/circle.md + Color: controls/canvas/color.md + Fill: controls/canvas/fill.md + Image: controls/canvas/image.md + Line: controls/canvas/line.md + Oval: controls/canvas/oval.md + Path: controls/canvas/path.md + Points: controls/canvas/points.md + Rect: controls/canvas/rect.md + Shadow: controls/canvas/shadow.md + Shape: controls/canvas/shape.md + Text: controls/canvas/text.md + Card: controls/card.md + Charts: + _index: controls/charts/index.md + BarChart: controls/charts/barchart.md + CandlestickChart: controls/charts/candlestickchart.md + LineChart: controls/charts/linechart.md + MatplotlibChart: controls/charts/matplotlibchart.md + MatplotlibChartWithToolbar: controls/charts/matplotlibchartwithtoolbar.md + PieChart: controls/charts/piechart.md + PlotlyChart: controls/charts/plotlychart.md + RadarChart: controls/charts/radarchart.md + ScatterChart: controls/charts/scatterchart.md + Checkbox: controls/checkbox.md + Chip: controls/chip.md + CircleAvatar: controls/circleavatar.md + CodeEditor: controls/codeeditor/index.md + Color pickers: + _index: controls/colorpickers/index.md + ColorPicker: controls/colorpickers/colorpicker.md + BlockPicker: controls/colorpickers/blockpicker.md + HueRingPicker: controls/colorpickers/hueringpicker.md + MaterialPicker: controls/colorpickers/materialpicker.md + MultipleChoiceBlockPicker: controls/colorpickers/multiplechoiceblockpicker.md + SlidePicker: controls/colorpickers/slidepicker.md + Column: controls/column.md + Container: controls/container.md + ContextMenu: controls/contextmenu.md + CupertinoActionSheet: + _index: controls/cupertinoactionsheet/index.md + CupertinoActionSheetAction: controls/cupertinoactionsheetaction.md + CupertinoActivityIndicator: controls/cupertinoactivityindicator.md + CupertinoAlertDialog: controls/cupertinoalertdialog.md + CupertinoAppBar: controls/cupertinoappbar.md + CupertinoBottomSheet: controls/cupertinobottomsheet.md + CupertinoButton: controls/cupertinobutton.md + CupertinoCheckbox: controls/cupertinocheckbox.md + CupertinoContextMenu: + _index: controls/cupertinocontextmenu/index.md + CupertinoContextMenuAction: controls/cupertinocontextmenuaction.md + CupertinoDatePicker: controls/cupertinodatepicker.md + CupertinoDialogAction: controls/cupertinodialogaction.md + CupertinoFilledButton: controls/cupertinofilledbutton.md + CupertinoListTile: controls/cupertinolisttile.md + CupertinoNavigationBar: controls/cupertinonavigationbar.md + CupertinoPicker: controls/cupertinopicker.md + CupertinoRadio: controls/cupertinoradio.md + CupertinoSegmentedButton: controls/cupertinosegmentedbutton.md + CupertinoSlider: controls/cupertinoslider.md + CupertinoSlidingSegmentedButton: controls/cupertinoslidingsegmentedbutton.md + CupertinoSwitch: controls/cupertinoswitch.md + CupertinoTextField: controls/cupertinotextfield.md + CupertinoTimerPicker: controls/cupertinotimerpicker.md + CupertinoTintedButton: controls/cupertinotintedbutton.md + DatePicker: controls/datepicker.md + DateRangePicker: controls/daterangepicker.md + DataTable: + _index: controls/datatable/index.md + DataCell: controls/datacell.md + DataColumn: controls/datacolumn.md + DataRow: controls/datarow.md + DataTable2: + _index: controls/datatable2/index.md + DataColumn2: controls/datatable2/datacolumn2.md + DataRow2: controls/datatable2/datarow2.md + Dismissible: controls/dismissible.md + Divider: controls/divider.md + DragTarget: controls/dragtarget.md + Draggable: controls/draggable.md + Dropdown: + _index: controls/dropdown/index.md + DropdownOption: controls/dropdownoption.md + #DropdownM2: controls/dropdownm2.md + ExpansionPanel: controls/expansionpanel.md + ExpansionPanelList: controls/expansionpanellist.md + ExpansionTile: controls/expansiontile.md + FilledButton: controls/filledbutton.md + FilledIconButton: controls/fillediconbutton.md + FilledTonalButton: controls/filledtonalbutton.md + FilledTonalIconButton: controls/filledtonaliconbutton.md + FletApp: controls/fletapp.md + FloatingActionButton: controls/floatingactionbutton.md + GestureDetector: controls/gesturedetector.md + GridView: controls/gridview.md + Hero: controls/hero.md + Icon: controls/icon.md + IconButton: controls/iconbutton.md + Image: controls/image.md + InteractiveViewer: controls/interactiveviewer.md + KeyboardListener: controls/keyboardlistener.md + ListTile: controls/listtile.md + ListView: controls/listview.md + Lottie: controls/lottie/index.md + Map: + _index: controls/map/index.md + Map: controls/map/mapcontrol.md + Layers: + - controls/map/maplayer.md + - controls/map/tilelayer.md + - controls/map/markerlayer.md + - controls/map/overlayimagelayer.md + - controls/map/circlelayer.md + - controls/map/polygonlayer.md + - controls/map/polylinelayer.md + Markers: + - controls/map/marker.md + - controls/map/circlemarker.md + - controls/map/polygonmarker.md + - controls/map/polylinemarker.md + Overlays: + - controls/map/baseoverlayimage.md + - controls/map/overlayimage.md + - controls/map/rotatedoverlayimage.md + Attributions: + - controls/map/sourceattribution.md + - controls/map/simpleattribution.md + - controls/map/richattribution.md + - controls/map/textsourceattribution.md + - controls/map/imagesourceattribution.md + Markdown: controls/markdown.md + MenuBar: controls/menubar.md + MenuItemButton: controls/menuitembutton.md + MergeSemantics: controls/mergesemantics.md + MultiView: controls/multiview.md + NavigationBar: + _index: controls/navigationbar/index.md + NavigationBarDestination: controls/navigationbardestination.md + NavigationDrawer: + _index: controls/navigationdrawer/index.md + NavigationDrawerDestination: controls/navigationdrawerdestination.md + NavigationRail: + _index: controls/navigationrail/index.md + NavigationRailDestination: controls/navigationraildestination.md + OutlinedButton: controls/outlinedbutton.md + OutlinedIconButton: controls/outlinediconbutton.md + Page: controls/page.md + Pagelet: controls/pagelet.md + PageView: controls/pageview.md + Placeholder: controls/placeholder.md + PopupMenuButton: controls/popupmenubutton.md + ProgressBar: controls/progressbar.md + ProgressRing: controls/progressring.md + Radio: controls/radio.md + RadioGroup: controls/radiogroup.md + RangeSlider: controls/rangeslider.md + ReorderableDragHandle: controls/reorderabledraghandle.md + ReorderableListView: controls/reorderablelistview.md + ResponsiveRow: controls/responsiverow.md + RotatedBox: controls/rotatedbox.md + Router: controls/router.md + Row: controls/row.md + Rive: controls/rive/index.md + SafeArea: controls/safearea.md + SearchBar: controls/searchbar.md + SegmentedButton: + _index: controls/segmentedbutton/index.md + Segment: controls/segment.md + SelectionArea: controls/selectionarea.md + Semantics: controls/semantics.md + Screenshot: controls/screenshot.md + ShaderMask: controls/shadermask.md + Shimmer: controls/shimmer.md + Slider: controls/slider.md + SnackBar: controls/snackbar.md + Stack: controls/stack.md + SubmenuButton: controls/submenubutton.md + Switch: controls/switch.md + Tabs: + _index: controls/tabs/index.md + Tab: controls/tab.md + TabBar: controls/tabbar.md + TabBarView: controls/tabbarview.md + Text: controls/text.md + TextButton: controls/textbutton.md + TextField: controls/textfield.md + TimePicker: controls/timepicker.md + TransparentPointer: controls/transparentpointer.md + VerticalDivider: controls/verticaldivider.md + Video: controls/video/index.md + View: controls/view.md + WebView: controls/webview/index.md + WindowDragArea: controls/windowdragarea.md + Services: + _generated_index: + title: Services + slug: /services + description: Browse the complete catalog of services available in Flet. + Accelerometer: services/accelerometer.md + Audio: services/audio/index.md + AudioRecorder: services/audiorecorder/index.md + Barometer: services/barometer.md + Battery: services/battery.md + BrowserContextMenu: services/browsercontextmenu.md + Clipboard: services/clipboard.md + Connectivity: services/connectivity.md + FilePicker: services/filepicker.md + Flashlight: services/flashlight/index.md + Geolocator: services/geolocator/index.md + Gyroscope: services/gyroscope.md + HapticFeedback: services/hapticfeedback.md + Magnetometer: services/magnetometer.md + PermissionHandler: services/permissionhandler/index.md + ScreenBrightness: services/screenbrightness.md + SemanticsService: services/semanticsservice.md + ShakeDetector: services/shakedetector.md + Share: services/share.md + SecureStorage: services/securestorage/index.md + SharedPreferences: services/sharedpreferences.md + StoragePaths: services/storagepaths.md + UrlLauncher: services/urllauncher.md + UserAccelerometer: services/useraccelerometer.md + Wakelock: services/wakelock.md + Types: + _index: types/index.md + Aliases: types/aliases.md + Authentication: + - types/auth/authorization.md + - types/auth/authorizationservice.md + - types/auth/group.md + - types/auth/oauthtoken.md + - OAuthProvider: + _index: types/auth/oauthprovider/index.md + Auth0OAuthProvider: types/auth/auth0oauthprovider.md + AzureOAuthProvider: types/auth/azureoauthprovider.md + GitHubOAuthProvider: types/auth/githuboauthprovider.md + GoogleOAuthProvider: types/auth/googleoauthprovider.md + - types/auth/user.md + Base Controls: + - controls/adaptivecontrol.md + - controls/basecontrol.md + - controls/basepage.md + - controls/control.md + - controls/dialogcontrol.md + - controls/formfieldcontrol.md + - controls/layoutcontrol.md + - controls/scrollablecontrol.md + - controls/service.md + - types/window.md + Classes: + - Ads: + - controls/ads/types/adrequest.md + - types/alignment.md + - types/androidbuildversion.md + - types/animation.md + - types/animationstyle.md + - Audio: + - services/audio/types/audiodurationchangeevent.md + - services/audio/types/audiopositionchangeevent.md + - services/audio/types/audiostatechangeevent.md + - services/audio/types/audiostate.md + - services/audio/types/releasemode.md + - AudioRecorder: + - services/audiorecorder/types/androidaudiosource.md + - services/audiorecorder/types/androidrecorderconfiguration.md + - services/audiorecorder/types/audioencoder.md + - services/audiorecorder/types/audiorecorderconfiguration.md + - services/audiorecorder/types/audiorecorderstatechangeevent.md + - services/audiorecorder/types/audiorecorderstreamevent.md + - services/audiorecorder/types/audiorecorderstate.md + - services/audiorecorder/types/audiorecorderuploadevent.md + - services/audiorecorder/types/audiorecorderuploadsettings.md + - services/audiorecorder/types/inputdevice.md + - services/audiorecorder/types/iosaudiocategoryoption.md + - services/audiorecorder/types/iosrecorderconfiguration.md + - types/autocompletesuggestion.md + - types/blur.md + - types/border.md + - types/borderradius.md + - types/borderside.md + - types/boxconstraints.md + - types/boxdecoration.md + - types/boxshadow.md + - types/buttonstyle.md + - Camera: + - controls/camera/types/cameradescription.md + - controls/camera/types/cameraimageevent.md + - controls/camera/types/cameralensdirection.md + - controls/camera/types/cameralenstype.md + - controls/camera/types/camerapreviewsize.md + - controls/camera/types/camerastateevent.md + - controls/camera/types/exposuremode.md + - controls/camera/types/flashmode.md + - controls/camera/types/focusmode.md + - controls/camera/types/imageformatgroup.md + - controls/camera/types/resolutionpreset.md + - Charts: + - controls/charts/types/barchartevent.md + - controls/charts/types/barchartgroup.md + - controls/charts/types/barchartrod.md + - controls/charts/types/barchartrodstackitem.md + - controls/charts/types/barchartrodtooltip.md + - controls/charts/types/barcharttooltip.md + - controls/charts/types/barcharttooltipdirection.md + - controls/charts/types/candlestickchartevent.md + - controls/charts/types/candlestickchartspot.md + - controls/charts/types/candlestickchartspottooltip.md + - controls/charts/types/candlestickcharttooltip.md + - controls/charts/types/chartaxis.md + - controls/charts/types/chartaxislabel.md + - controls/charts/types/chartcirclepoint.md + - controls/charts/types/chartcrosspoint.md + - controls/charts/types/chartdatapointtooltip.md + - controls/charts/types/charteventtype.md + - controls/charts/types/chartgridlines.md + - controls/charts/types/chartpointline.md + - controls/charts/types/chartpointshape.md + - controls/charts/types/chartsquarepoint.md + - controls/charts/types/horizontalalignment.md + - controls/charts/types/linechartdata.md + - controls/charts/types/linechartdatapoint.md + - controls/charts/types/linechartdatapointtooltip.md + - controls/charts/types/linechartevent.md + - controls/charts/types/linecharteventspot.md + - controls/charts/types/linecharttooltip.md + - controls/charts/types/piechartevent.md + - controls/charts/types/piechartsection.md + - controls/charts/types/radarchartevent.md + - controls/charts/types/radarcharttitle.md + - controls/charts/types/radardataset.md + - controls/charts/types/radardatasetentry.md + - controls/charts/types/radarshape.md + - controls/charts/types/scatterchartevent.md + - controls/charts/types/scatterchartspot.md + - controls/charts/types/scatterchartspottooltip.md + - controls/charts/types/scattercharttooltip.md + - types/colorfilter.md + - types/context.md + - types/controlstate.md + - types/decorationimage.md + - DeviceInfo: + _index: types/deviceinfo/index.md + AndroidDeviceInfo: types/androiddeviceinfo.md + IosDeviceInfo: types/iosdeviceinfo.md + LinuxDeviceInfo: types/linuxdeviceinfo.md + MacOsDeviceInfo: types/macosdeviceinfo.md + WebDeviceInfo: types/webdeviceinfo.md + WindowsDeviceInfo: types/windowsdeviceinfo.md + - types/duration.md + - types/filepickerfile.md + - types/filepickeruploadfile.md + - types/finder.md + - types/flip.md + - types/flettestapp.md + - Geolocator: + - services/geolocator/types/foregroundnotificationconfiguration.md + - services/geolocator/types/geolocatorandroidconfiguration.md + - services/geolocator/types/geolocatorconfiguration.md + - services/geolocator/types/geolocatoriosactivitytype.md + - services/geolocator/types/geolocatoriosconfiguration.md + - services/geolocator/types/geolocatorpermissionstatus.md + - services/geolocator/types/geolocatorposition.md + - services/geolocator/types/geolocatorpositionaccuracy.md + - services/geolocator/types/geolocatorpositionchangeevent.md + - services/geolocator/types/geolocatorwebconfiguration.md + - Gradient: + _index: types/gradient/index.md + LinearGradient: types/lineargradient.md + RadialGradient: types/radialgradient.md + SweepGradient: types/sweepgradient.md + - types/inputborder.md + - types/inputfilter.md + - types/iosutsname.md + - Key: + _index: types/key/index.md + ScrollKey: types/scrollkey.md + ValueKey: types/valuekey.md + - types/locale.md + - types/localeconfiguration.md + - types/locationinfo.md + - Map: + - controls/map/types/attributionalignment.md + - controls/map/types/camera.md + - controls/map/types/camerafit.md + - controls/map/types/cursorkeyboardrotationconfiguration.md + - controls/map/types/cursorrotationbehaviour.md + - controls/map/types/dashedstrokepattern.md + - controls/map/types/dottedstrokepattern.md + - controls/map/types/fadeintiledisplay.md + - controls/map/types/instantaneoustiledisplay.md + - controls/map/types/interactionconfiguration.md + - controls/map/types/interactionflag.md + - controls/map/types/keyboardconfiguration.md + - controls/map/types/mapevent.md + - controls/map/types/mapeventtype.md + - controls/map/types/mapeventsource.md + - controls/map/types/maphoverevent.md + - controls/map/types/maplatitudelongitude.md + - controls/map/types/maplatitudelongitudebounds.md + - controls/map/types/mappointerevent.md + - controls/map/types/mappositionchangeevent.md + - controls/map/types/maptapevent.md + - controls/map/types/multifingergesture.md + - controls/map/types/patternfit.md + - controls/map/types/solidstrokepattern.md + - controls/map/types/strokepattern.md + - controls/map/types/tiledisplay.md + - controls/map/types/tilelayerevicterrortilestrategy.md + - controls/map/types/wmstilelayerconfiguration.md + - types/margin.md + - types/matrix4.md + - types/markdowncustomcodetheme.md + - types/markdownstylesheet.md + - types/menustyle.md + - NotchShape: + _index: types/notchshape/index.md + AutomaticNotchShape: types/automaticnotchshape.md + CircularRectangleNotchShape: types/circularrectanglenotchshape.md + - types/observable.md + - types/offset.md + - OutlinedBorder: + _index: types/outlinedborder/index.md + BeveledRectangleBorder: types/beveledrectangleborder.md + CircleBorder: types/circleborder.md + ContinuousRectangleBorder: types/continuousrectangleborder.md + RoundedRectangleBorder: types/roundedrectangleborder.md + StadiumBorder: types/stadiumborder.md + - types/padding.md + - types/paint.md + - PaintGradient: + _index: types/paintgradient/index.md + PaintLinearGradient: types/paintlineargradient.md + PaintRadialGradient: types/paintradialgradient.md + PaintSweepGradient: types/paintsweepgradient.md + - PermissionHandler: + - services/permissionhandler/types/permission.md + - services/permissionhandler/types/permissionstatus.md + - types/pubsub/pubsubclient.md + - types/pubsub/pubsubhub.md + - types/rect.md + - types/ref.md + - types/responsiverowbreakpoint.md + - types/rotate.md + - types/scale.md + - SecureStorage: + - services/securestorage/types/windowsoptions.md + - services/securestorage/types/androidoptions.md + - services/securestorage/types/appleoptions.md + - services/securestorage/types/macosoptions.md + - services/securestorage/types/iosoptions.md + - services/securestorage/types/weboptions.md + - types/shapeborder.md + - types/size.md + - types/strutstyle.md + - types/templateroute.md + - types/tester.md + - types/textdecoration.md + - types/textselection.md + - types/textspan.md + - types/textstyle.md + - types/textthemestyle.md + - types/transform.md + - Theme: + _index: types/theme/index.md + AppBarTheme: types/appbartheme.md + BadgeTheme: types/badgetheme.md + BannerTheme: types/bannertheme.md + BottomAppBarTheme: types/bottomappbartheme.md + BottomSheetTheme: types/bottomsheettheme.md + ButtonTheme: types/buttontheme.md + CardTheme: types/cardtheme.md + CheckboxTheme: types/checkboxtheme.md + ChipTheme: types/chiptheme.md + ColorScheme: types/colorscheme.md + DataTableTheme: types/datatabletheme.md + DatePickerTheme: types/datepickertheme.md + DialogTheme: types/dialogtheme.md + DividerTheme: types/dividertheme.md + DropdownTheme: types/dropdowntheme.md + ExpansionTileTheme: types/expansiontiletheme.md + FilledButtonTheme: types/filledbuttontheme.md + FloatingActionButtonTheme: types/floatingactionbuttontheme.md + IconButtonTheme: types/iconbuttontheme.md + IconTheme: types/icontheme.md + ListTileTheme: types/listtiletheme.md + NavigationBarTheme: types/navigationbartheme.md + NavigationDrawerTheme: types/navigationdrawertheme.md + NavigationRailTheme: types/navigationrailtheme.md + OutlinedButtonTheme: types/outlinedbuttontheme.md + PageTransitionsTheme: types/pagetransitionstheme.md + PageTransitionTheme: types/pagetransitiontheme.md + PopupMenuTheme: types/popupmenutheme.md + ProgressIndicatorTheme: types/progressindicatortheme.md + RadioTheme: types/radiotheme.md + ScrollBarTheme: types/scrollbartheme.md + SearchBarTheme: types/searchbartheme.md + SearchViewTheme: types/searchviewtheme.md + SegmentedButtonTheme: types/segmentedbuttontheme.md + SliderTheme: types/slidertheme.md + SnackBarTheme: types/snackbartheme.md + SwitchTheme: types/switchtheme.md + SystemOverlayStyle: types/systemoverlaystyle.md + TabBarTheme: types/tabbartheme.md + TextButtonTheme: types/textbuttontheme.md + TextTheme: types/texttheme.md + TimePickerTheme: types/timepickertheme.md + TooltipTheme: types/tooltiptheme.md + - types/browserconfiguration.md + - types/tooltip.md + - types/url.md + - types/webviewconfiguration.md + - types/underlinetabindicator.md + - CodeEditor: + - controls/codeeditor/types/codelanguage.md + - controls/codeeditor/types/codetheme.md + - controls/codeeditor/types/customcodetheme.md + - controls/codeeditor/types/gutterstyle.md + - Video: + - controls/video/types/adaptivevideocontrols.md + - controls/video/types/materialdesktopvideocontrols.md + - controls/video/types/materialvideocontrols.md + - controls/video/types/playlistmode.md + - controls/video/types/videobaritem.md + - controls/video/types/videoconfiguration.md + - controls/video/types/videocontrols.md + - controls/video/types/videocontrolsmode.md + - controls/video/types/videofullscreenbutton.md + - controls/video/types/videomedia.md + - controls/video/types/videoplayorpausebutton.md + - controls/video/types/videopositionindicator.md + - controls/video/types/videoskipnextbutton.md + - controls/video/types/videoskippreviousbutton.md + - controls/video/types/videospacer.md + - controls/video/types/videosubtitleconfiguration.md + - controls/video/types/videosubtitletrack.md + - controls/video/types/videovolumebutton.md + - WebView: + - controls/webview/types/requestmethod.md + - controls/webview/types/loglevelseverity.md + - controls/webview/types/webviewconsolemessageevent.md + - controls/webview/types/webviewjavascriptevent.md + - controls/webview/types/webviewscrollevent.md + Decorators: + - types/component.md + - types/control.md + - types/observabledecorator.md + - types/value.md + Enums: + - Ads: + - controls/ads/types/precisiontype.md + - types/animatedswitchertransition.md + - types/animationcurve.md + - types/applifecyclestate.md + - types/appview.md + - types/assertiveness.md + - types/autofillgroupdisposeaction.md + - types/autofillhint.md + - types/axis.md + - types/blendmode.md + - types/blurstyle.md + - types/blurtilemode.md + - types/bordersidestrokealign.md + - types/borderstyle.md + - types/boxfit.md + - types/boxshape.md + - types/brightness.md + - types/cardvariant.md + - types/clipbehavior.md + - types/colors.md + - types/contextmenutrigger.md + - types/crossaxisalignment.md + - types/cupertinobuttonsize.md + - types/cupertinocolors.md + - types/cupertinodatepickerdateorder.md + - types/cupertinodatepickermode.md + - types/cupertinoicons.md + - types/cupertinotimerpickermode.md + - DataTable2: + - controls/datatable2/types/datacolumnsize.md + - types/datepickerentrymode.md + - types/datepickermode.md + - types/dismissdirection.md + - types/filepickerfiletype.md + - types/filterquality.md + - types/floatingactionbuttonlocation.md + - types/fontweight.md + - types/gradienttilemode.md + - types/icons.md + - types/imagerepeat.md + - types/keyboardtype.md + - types/labelposition.md + - types/listtilestyle.md + - types/listtiletitlealignment.md + - types/mainaxisalignment.md + - types/mousecursor.md + - types/markdowncodetheme.md + - types/markdownextensionset.md + - types/navigationbarlabelbehavior.md + - types/navigationraillabeltype.md + - types/deviceorientation.md + - types/orientation.md + - types/overlayvisibilitymode.md + - types/pageplatform.md + - types/paintingstyle.md + - types/pointerdevicetype.md + - types/pointmode.md + - types/popupmenuposition.md + - types/route.md + - types/routeurlstrategy.md + - types/scrollbar.md + - types/scrollbarorientation.md + - types/scrolldirection.md + - types/scrollmode.md + - types/scrolltype.md + - types/sliderinteraction.md + - types/snackbarbehavior.md + - types/stackfit.md + - types/strokecap.md + - types/strokejoin.md + - types/tabalignment.md + - types/tabbarindicatorsize.md + - types/tabindicatoranimation.md + - types/textaffinity.md + - types/textalign.md + - types/textbaseline.md + - types/textcapitalization.md + - types/textdecorationstyle.md + - types/textoverflow.md + - types/textselectionchangecause.md + - types/thememode.md + - types/tileaffinity.md + - types/timepickerentrymode.md + - types/timepickerhourformat.md + - types/tooltiptriggermode.md + - types/launchmode.md + - types/urltarget.md + - types/verticalalignment.md + - types/visualdensity.md + - types/webbrowsername.md + - types/webrenderer.md + - types/windoweventtype.md + - types/windowresizeedge.md + - services/securestorage/types/accesscontrolflag.md + - services/securestorage/types/keychainaccessibility.md + - services/securestorage/types/keycipheralgorithm.md + - services/securestorage/types/storagecipheralgorithm.md + Events: + - types/accelerometerreadingevent.md + - Ads: + - controls/ads/types/paidadevent.md + - types/applifecyclestatechangeevent.md + - types/autocompleteselectevent.md + - types/barometerreadingevent.md + - types/batterystate.md + - types/batterystatechangeevent.md + - types/connectivitytype.md + - types/connectivitychangeevent.md + - types/canvasresizeevent.md + - types/contextmenudismissevent.md + - types/contextmenuselectevent.md + - types/datacolumnsortevent.md + - types/datepickerentrymodechangeevent.md + - types/dismissibledismissevent.md + - types/dismissibleupdateevent.md + - types/dragendevent.md + - types/dragstartevent.md + - types/dragtargetevent.md + - types/dragtargetleaveevent.md + - types/dragupdateevent.md + - types/dragwillacceptevent.md + - types/event.md + - types/expansionpanellistchangeevent.md + - types/filepickeruploadevent.md + - types/gyroscopereadingevent.md + - types/hoverevent.md + - types/keyboardevent.md + - types/keydownevent.md + - types/keyrepeatevent.md + - types/keyupevent.md + - types/localechangeevent.md + - types/loginevent.md + - types/longpressendevent.md + - types/longpressstartevent.md + - types/magnetometerreadingevent.md + - types/multitapevent.md + - types/multiviewaddevent.md + - types/multiviewremoveevent.md + - types/onreorderevent.md + - types/onscrollevent.md + - types/pagemediadata.md + - types/pageresizeevent.md + - types/platformbrightnesschangeevent.md + - types/pointerevent.md + - types/routechangeevent.md + - types/sensorerrorevent.md + - types/scaleendevent.md + - types/scalestartevent.md + - types/scaleupdateevent.md + - types/screenbrightnesschangeevent.md + - types/shareresult.md + - types/shareresultstatus.md + - types/sharefile.md + - types/sharecupertinoactivitytype.md + - types/scrollevent.md + - services/securestorage/types/securestorageevent.md + - types/tabbarhoverevent.md + - types/tapevent.md + - types/textselectionchangeevent.md + - types/timepickerentrymodechangeevent.md + - types/useraccelerometerreadingevent.md + - types/viewpopevent.md + - types/windowevent.md + Exceptions: + _index: types/fletexception/index.md + FletPageDisconnectedException: types/fletpagedisconnectedexception.md + FletUnimplementedPlatformException: types/fletunimplementedplatformexception.md + FletUnsupportedPlatformException: types/fletunsupportedplatformexception.md + FastAPI: + - fastapi/app.md + - fastapi/app_manager.md + - fastapi/fastapi.md + - fastapi/fletapp.md + - fastapi/fletoauth.md + - fastapi/fletstaticfiles.md + - fastapi/fletupload.md + Methods: + - types/createcontext.md + - types/is_route_active.md + - types/memo.md + - types/onmounted.md + - types/onunmounted.md + - types/onupdated.md + - types/usecallback.md + - types/usecontext.md + - types/useeffect.md + - types/usememo.md + - types/useref.md + - types/use_route_loader_data.md + - types/use_route_location.md + - types/use_route_outlet.md + - types/use_route_params.md + - types/use_view_path.md + - types/usestate.md + CLI: + _index: cli/index.md + flet build: cli/flet-build.md + flet create: cli/flet-create.md + flet debug: cli/flet-debug.md + flet devices: cli/flet-devices.md + flet doctor: cli/flet-doctor.md + flet emulators: cli/flet-emulators.md + flet pack: cli/flet-pack.md + flet publish: cli/flet-publish.md + flet run: cli/flet-run.md + flet serve: cli/flet-serve.md + Python packages built in Flet: reference/binary-packages-android-ios.md + Environment Variables: reference/environment-variables.md diff --git a/website/src/components/AnnotatedCodeBlock/index.js b/website/src/components/AnnotatedCodeBlock/index.js new file mode 100644 index 0000000000..ad31c5b8a9 --- /dev/null +++ b/website/src/components/AnnotatedCodeBlock/index.js @@ -0,0 +1,145 @@ +import React, { useEffect, useRef, useState } from "react"; +import CodeBlock from "@theme/CodeBlock"; +import styles from "./styles.module.css"; + +const MARKER_SVG = + ''; + +function injectMarkers(container, annotations, markerClass, onClickMarker) { + // Remove any existing markers first + container.querySelectorAll(`.${markerClass}`).forEach((el) => el.remove()); + + const codeEl = container.querySelector("code"); + if (!codeEl) return; + + const lines = codeEl.querySelectorAll(".token-line"); + + Object.entries(annotations).forEach(([num, { line }]) => { + const lineEl = lines[line]; + if (!lineEl) return; + + const marker = document.createElement("button"); + marker.className = markerClass; + marker.type = "button"; + marker.innerHTML = MARKER_SVG; + marker.setAttribute("aria-label", `Annotation ${num}`); + marker.dataset.annotationNum = num; + marker.addEventListener("click", (e) => { + e.stopPropagation(); + onClickMarker(num, marker); + }); + + const br = lineEl.querySelector("br"); + if (br) { + lineEl.insertBefore(marker, br); + } else { + lineEl.appendChild(marker); + } + }); +} + +export default function AnnotatedCodeBlock({ + code, + lang, + title, + annotations: annotationsJson, +}) { + const containerRef = useRef(null); + const [activeAnnotation, setActiveAnnotation] = useState(null); + const [tooltipStyle, setTooltipStyle] = useState({}); + const annotationsRef = useRef(null); + + if (annotationsRef.current === null) { + annotationsRef.current = + typeof annotationsJson === "string" + ? JSON.parse(annotationsJson) + : annotationsJson || {}; + } + const annotations = annotationsRef.current; + + const handleMarkerClick = (num, markerEl) => { + const container = containerRef.current; + if (!container) return; + + const containerRect = container.getBoundingClientRect(); + const markerRect = markerEl.getBoundingClientRect(); + + setActiveAnnotation((prev) => { + if (prev === num) return null; + setTooltipStyle({ + top: markerRect.bottom - containerRect.top + 6, + left: markerRect.left - containerRect.left, + }); + return num; + }); + }; + + // Close tooltip when clicking outside + useEffect(() => { + if (activeAnnotation === null) return; + + function handleClick(e) { + const isMarker = + e.target.closest && e.target.closest(`.${styles.marker}`); + const tooltip = containerRef.current?.querySelector( + `.${styles.tooltip}`, + ); + const isInTooltip = tooltip && tooltip.contains(e.target); + if (!isMarker && !isInTooltip) { + setActiveAnnotation(null); + } + } + document.addEventListener("click", handleClick); + return () => document.removeEventListener("click", handleClick); + }, [activeAnnotation]); + + // Inject markers after hydration, and re-inject if DOM changes + useEffect(() => { + const container = containerRef.current; + if (!container) return; + + const doInject = () => + injectMarkers( + container, + annotations, + styles.marker, + handleMarkerClick, + ); + + // Initial injection after a tick (CodeBlock needs to render) + const timer = setTimeout(doInject, 50); + + // Re-inject if React re-renders the CodeBlock (hydration, tab switch, etc.) + const observer = new MutationObserver(() => { + // Only re-inject if markers are missing + if (!container.querySelector(`.${styles.marker}`)) { + doInject(); + } + }); + observer.observe(container, { childList: true, subtree: true }); + + return () => { + clearTimeout(timer); + observer.disconnect(); + }; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + const activeData = activeAnnotation + ? annotations[activeAnnotation] + : null; + + return ( +
    + + {code} + + {activeData && ( +
    + )} +
    + ); +} diff --git a/website/src/components/AnnotatedCodeBlock/styles.module.css b/website/src/components/AnnotatedCodeBlock/styles.module.css new file mode 100644 index 0000000000..3e16c2aa5d --- /dev/null +++ b/website/src/components/AnnotatedCodeBlock/styles.module.css @@ -0,0 +1,82 @@ +.wrapper { + position: relative; + margin-bottom: 1rem; +} + +.marker { + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + margin-left: 6px; + padding: 0; + border: none; + border-radius: 50%; + background: var(--ifm-color-emphasis-500); + color: #fff; + cursor: pointer; + vertical-align: middle; + transition: color 0.15s, background 0.15s; +} + +.marker:hover { + background: var(--ifm-color-primary); + color: #fff; +} + +.tooltip { + position: absolute; + z-index: 100; + min-width: 200px; + max-width: 420px; + padding: 12px 16px; + border-radius: 6px; + background: var(--ifm-background-surface-color, #fff); + border: 1px solid var(--ifm-color-emphasis-200); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); + font-size: 0.9rem; + line-height: 1.5; + animation: tooltipFadeIn 0.15s ease-out; +} + +.tooltip p { + margin: 0 0 0.5em; +} + +.tooltip p:last-child { + margin-bottom: 0; +} + +.tooltip code { + background: var(--ifm-color-emphasis-100); + padding: 2px 5px; + border-radius: 3px; + font-size: 0.85em; +} + +.tooltip a { + color: var(--ifm-color-primary); + text-decoration: underline; +} + +@keyframes tooltipFadeIn { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +[data-theme="dark"] .marker { + color: #1e1e1e; +} + +[data-theme="dark"] .tooltip { + background: var(--ifm-background-surface-color, #1e1e1e); + border-color: var(--ifm-color-emphasis-300); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); +} diff --git a/website/src/components/card/index.js b/website/src/components/card/index.js new file mode 100644 index 0000000000..f1c397c3b0 --- /dev/null +++ b/website/src/components/card/index.js @@ -0,0 +1,15 @@ + +import React from 'react'; +import styles from './styles.module.css'; +import clsx from 'clsx'; + +export default function Card(props) { + + return props.href ? + {props.children} + :
    + {props.children} +
    +}; \ No newline at end of file diff --git a/website/src/components/card/styles.module.css b/website/src/components/card/styles.module.css new file mode 100644 index 0000000000..e032445d9a --- /dev/null +++ b/website/src/components/card/styles.module.css @@ -0,0 +1,39 @@ +.cardContainer { + --ifm-link-color: var(--ifm-color-emphasis-800); + --ifm-link-hover-color: var(--ifm-color-emphasis-700); + --ifm-link-hover-decoration: none; + + box-shadow: 0 1.5px 3px 0 rgb(0 0 0 / 15%); + border: 1px solid var(--ifm-color-emphasis-200); + transition: all var(--ifm-transition-fast) ease; + transition-property: border, box-shadow; +} + +.cardContainer:hover { + border-color: var(--ifm-color-primary); + box-shadow: 0 3px 6px 0 rgb(0 0 0 / 20%); +} + +.cardContainer *:last-child { + margin-bottom: 0; +} + +.cardTitle { + font-size: 1.2rem; +} + +.cardDescription { + font-size: 0.8rem; +} + +.cardContainer img { + max-width: 150px; + height: 100px; + object-fit: contain; + object-position: top; +} + +.cardContainer h2 { + font-size: 1.2rem; + margin-bottom: 0.5rem; +} \ No newline at end of file diff --git a/website/src/components/crocodocs/ClassAll.js b/website/src/components/crocodocs/ClassAll.js new file mode 100644 index 0000000000..2df355d4b7 --- /dev/null +++ b/website/src/components/crocodocs/ClassAll.js @@ -0,0 +1,11 @@ +import React from "react"; + +import ClassBlock from "./ClassBlock"; + +/** + * Renders a full API class block (docstring, bases, summary, and members). + * Passes all props directly to ClassBlock with no overrides. + */ +export default function ClassAll(props) { + return ; +} diff --git a/website/src/components/crocodocs/ClassBlock.js b/website/src/components/crocodocs/ClassBlock.js new file mode 100644 index 0000000000..3dfa4f3899 --- /dev/null +++ b/website/src/components/crocodocs/ClassBlock.js @@ -0,0 +1,559 @@ +import React, {useEffect, useRef, useState} from "react"; +import Heading from "@theme/Heading"; +import {useDoc} from "@docusaurus/plugin-content-docs/client"; + +import { + firstSentenceFromDocstring, + getApiData, + memberAnchor, + renderCodeExpression, + renderDocstring, + renderDocstringSections, + renderInlineMarkdown, + resolveDocAssetUrl, + rootAnchor, + sectionAnchor, +} from "./utils"; + +const MEMBER_KIND_META = { + property: {icon: "build", className: "crocodocs-member-icon--property"}, + event: {icon: "bolt", className: "crocodocs-member-icon--event"}, + method: {icon: "deployed_code", className: "crocodocs-member-icon--method"}, +}; + +/** + * Remove implicit `self` (with optional type annotation) from a Python method signature string. + * Handles both `(self, ...)` and `(self)` forms. + */ +function stripImplicitSelf(signatureText) { + if (!signatureText) { + return signatureText; + } + + return signatureText + .replace(/\(\s*self(?:\s*:\s*[^,)]+)?\s*,\s*/g, "(") + .replace(/\(\s*self(?:\s*:\s*[^,)]+)?\s*\)/g, "()"); +} + +/** + * Renders a Docusaurus-aware heading element at the given level with an anchor id. + */ +function HeadingLink({level: Tag, id, children}) { + return ( + + {children} + + ); +} + +/** Renders a small metadata badge label (e.g. "classmethod", "deprecated"). */ +function Badge({children, title}) { + return ( + + {children} + + ); +} + +/** + * Renders a styled signature box with a copy-to-clipboard button. + * `text` is the plain string written to the clipboard; `children` is the rendered content. + */ +function SignatureBox({text, children}) { + const [copied, setCopied] = useState(false); + + /** Copy `text` to the clipboard and briefly show a "Copied" confirmation. */ + async function onCopy() { + if (!navigator?.clipboard || !text) { + return; + } + try { + await navigator.clipboard.writeText(text); + setCopied(true); + window.setTimeout(() => setCopied(false), 1500); + } catch { + // Ignore clipboard failures and leave the button idle. + } + } + + return ( +
    + +
    +        {children}
    +      
    +
    + ); +} + +/** + * Renders a titled section (Properties, Events, or Methods) containing a list of member items. + * Returns null when items is empty. + */ +function Section({title, items, renderItem}) { + if (!items || items.length === 0) { + return null; + } + + return ( +
    + + {title} + + {items.map(renderItem)} +
    + ); +} + +/** + * Create a DOM span element bearing the Material Symbols icon for a member kind + * ('property', 'event', or 'method'), for injection into the table-of-contents. + * Returns null for unknown kinds. + */ +function createMemberIconNode(kind) { + const meta = MEMBER_KIND_META[kind]; + if (!meta) { + return null; + } + const icon = document.createElement("span"); + icon.className = `material-symbols-outlined crocodocs-member-icon crocodocs-member-icon--toc ${meta.className}`; + icon.setAttribute("aria-hidden", "true"); + icon.textContent = meta.icon; + return icon; +} + +let tocOwnerCounter = 0; + +/** + * Hook that injects API-member entries into Docusaurus's table-of-contents sidebar. + * Each call owns a unique set of TOC nodes identified by an auto-incremented owner ID, + * and cleans them up on unmount or when sectionGroups changes. + */ +function useInjectedToc(sectionGroups) { + const ownerRef = useRef(null); + if (ownerRef.current == null) { + tocOwnerCounter += 1; + ownerRef.current = `crocodocs-${tocOwnerCounter}`; + } + + useEffect(() => { + const tocRoot = document.querySelector("ul.table-of-contents"); + if (!tocRoot) { + return undefined; + } + + tocRoot + .querySelectorAll( + `[data-crocodocs-toc='true'][data-crocodocs-toc-owner='${ownerRef.current}']` + ) + .forEach((node) => node.remove()); + + const created = []; + for (const group of sectionGroups) { + if (!group.items.length && !group.showWhenEmpty) { + continue; + } + + const top = document.createElement("li"); + top.className = [ + "table-of-contents__list-item", + group.items.length ? "table-of-contents__list-item--nested" : "", + "generated-crocodocs-toc", + ] + .filter(Boolean) + .join(" "); + top.dataset.crocodocsToc = "true"; + top.dataset.crocodocsTocOwner = ownerRef.current; + + const link = document.createElement("a"); + link.className = "table-of-contents__link toc-highlight"; + link.href = `#${group.id}`; + link.textContent = group.title; + top.appendChild(link); + + if (group.items.length) { + const nested = document.createElement("ul"); + nested.className = "table-of-contents__sublist"; + for (const item of group.items) { + const nestedItem = document.createElement("li"); + nestedItem.className = + "table-of-contents__list-item generated-crocodocs-toc"; + nestedItem.dataset.crocodocsToc = "true"; + nestedItem.dataset.crocodocsTocOwner = ownerRef.current; + + const nestedLink = document.createElement("a"); + nestedLink.className = + "table-of-contents__link toc-highlight crocodocs-member-toc-link"; + nestedLink.href = `#${item.id}`; + const icon = createMemberIconNode(item.kind); + if (icon) { + nestedLink.appendChild(icon); + } + const label = document.createElement("span"); + label.textContent = item.label; + nestedLink.appendChild(label); + nestedItem.appendChild(nestedLink); + nested.appendChild(nestedItem); + created.push(nestedItem); + } + top.appendChild(nested); + } + tocRoot.appendChild(top); + created.push(top); + } + + return () => { + created.forEach((node) => node.remove()); + }; + }, [sectionGroups]); +} + +/** + * Render an h3 heading for an API member with its icon and any label badges. + * + * @param item - The member entry (must have name and labels fields). + * @param classSymbol - The fully-qualified class name used to build the anchor id. + * @param kind - 'property', 'event', or 'method'. + */ +function renderMemberHeading(item, classSymbol, kind) { + const id = memberAnchor(classSymbol, item.name); + const meta = MEMBER_KIND_META[kind]; + return ( + + + {meta ? ( + + ) : null} + {item.name} + {(item.labels || []).length ? ( + + {(item.labels || []).map((label) => ( + {label} + ))} + + ) : null} + + + ); +} + +/** + * Render a full detail entry for a property or event attribute member, + * including its type signature box and docstring. + */ +function renderAttribute(item, classSymbol, docId) { + const fallbackSignatureText = `${item.name}: ${item.type}${item.default != null ? ` = ${item.default}` : ""}`; + const signatureText = item.formatted_signature ?? fallbackSignatureText; + const kind = item.name.startsWith("on_") ? "event" : "property"; + return ( +
    + {renderMemberHeading(item, classSymbol, kind)} + {item.type ? ( + + {renderCodeExpression(signatureText, {classSymbol, docId})} + + ) : null} + {renderDocstringSections(item.docstring_sections, {classSymbol, docId}) ?? + renderDocstring(item.docstring, {classSymbol, docId})} +
    + ); +} + +/** + * Render a full detail entry for a method member, + * including its signature box (with `self` stripped) and docstring. + */ +function renderMethod(item, classSymbol, docId) { + const fallbackSignatureText = stripImplicitSelf(item.signature ?? item.name); + const typedSignatureText = + item.return_type && !fallbackSignatureText.includes("->") + ? `${fallbackSignatureText} -> ${item.return_type}` + : fallbackSignatureText; + const signatureText = item.formatted_signature ?? typedSignatureText; + return ( +
    + {renderMemberHeading(item, classSymbol, "method")} + + {renderCodeExpression(signatureText, {classSymbol, docId})} + + {renderDocstringSections(item.docstring_sections, {classSymbol, docId}) ?? + renderDocstring(item.docstring, {classSymbol, docId})} +
    + ); +} + +/** + * Build the compact member data used by ClassSummary lists. + * Carries labels so summary rows can show important badges without requiring + * readers to scroll to the full member documentation. + */ +function memberSummary(item, kind) { + return { + name: item.name, + kind, + labels: item.labels ?? [], + summary: firstSentenceFromDocstring(item.docstring, item.docstring_sections), + }; +} + +/** + * Return labels that should be visible in compact summary rows. + * Keep this intentionally narrower than full member headings to avoid duplicating + * section context such as "property" or "method". + */ +function summaryLabels(item) { + return (item.labels ?? []).filter((label) => label === "deprecated"); +} + +/** + * Renders a compact summary list of member names with their first-sentence descriptions, + * each linking to the corresponding detail anchor. Returns null when items is empty. + */ +function SummarySection({title, items, classSymbol}) { + if (!items.length) { + return null; + } + + return ( +
    + {title} +
      + {items.map((item) => { + const labels = summaryLabels(item); + return ( +
    • + + {item.name} + + {labels.length ? ( + <> + {" "} + + {labels.map((label) => ( + {label} + ))} + + + ) : null} + {item.summary ? ( + <> + {" "}{"-"}{" "} + {renderInlineMarkdown(item.summary, {classSymbol})} + + ) : null} +
    • + ); + })} +
    +
    + ); +} + +/** + * Core component that renders a complete API entry (class, function, or alias). + * Controlled by show* flags so that ClassSummary, ClassMembers, and ClassAll + * can reuse it with different visibility combinations. + * + * @param {string} name - Fully-qualified API symbol name to look up in api-data.json. + * @param {boolean} [showRootHeading=false] - Whether to render an h2 heading for the symbol. + * @param {boolean} [showDocstring=true] - Whether to render the class-level docstring. + * @param {boolean} [showBases=true] - Whether to render the "Inherits:" base-class list. + * @param {boolean} [showSummary=true] - Whether to render the member summary tables. + * @param {boolean} [showMembers=true] - Whether to render the full per-member detail sections. + * @param {string} [image] - Optional screenshot image path to display after the docstring. + * @param {string} [imageCaption] - Optional figcaption for the screenshot image. + * @param {string} [imageWidth="40%"] - CSS width for the screenshot image. + */ +export default function ClassBlock({ + name, + showRootHeading = false, + showDocstring = true, + showBases = true, + showSummary = true, + showMembers = true, + image, + imageCaption, + imageWidth = "40%", +}) { + const {metadata} = useDoc(); + const api = getApiData(); + const classEntry = api.classes?.[name]; + const functionEntry = api.functions?.[name]; + const aliasEntry = api.aliases?.[name]; + const entry = classEntry ?? functionEntry ?? aliasEntry; + + if (!entry) { + return
    Missing API entry for {name}.
    ; + } + + if (!classEntry && !functionEntry && aliasEntry) { + useInjectedToc( + showRootHeading + ? [{title: entry.name, id: rootAnchor(name), items: [], showWhenEmpty: true}] + : [] + ); + return ( +
    + {showRootHeading ? ( + + {entry.name} + + ) : null} + {showDocstring + ? (renderDocstringSections(entry.docstring_sections, {classSymbol: name, docId: metadata?.id}) ?? + renderDocstring(entry.docstring, {classSymbol: name, docId: metadata?.id})) + : null} + {entry.value ? ( + + {renderCodeExpression(entry.value, { + api, + classSymbol: name, + docId: metadata?.id, + })} + + ) : null} +
    + ); + } + + const properties = entry.properties ?? []; + const events = entry.events ?? []; + const methods = entry.methods ?? []; + const propertySummaries = properties.map((item) => memberSummary(item, "property")); + const eventSummaries = events.map((item) => memberSummary(item, "event")); + const methodSummaries = methods.map((item) => memberSummary(item, "method")); + + const propertiesWithSectionId = properties.map((item) => ({ + ...item, + __sectionId: sectionAnchor(name, "properties"), + })); + const eventsWithSectionId = events.map((item) => ({ + ...item, + __sectionId: sectionAnchor(name, "events"), + })); + const methodsWithSectionId = methods.map((item) => ({ + ...item, + __sectionId: sectionAnchor(name, "methods"), + })); + + useInjectedToc( + [ + ...(showRootHeading + ? [{title: entry.name, id: rootAnchor(name), items: [], showWhenEmpty: true}] + : []), + ...(showMembers + ? [ + { + title: "Properties", + id: sectionAnchor(name, "properties"), + items: properties.map((item) => ({ + id: memberAnchor(name, item.name), + kind: "property", + label: item.name, + })), + }, + { + title: "Events", + id: sectionAnchor(name, "events"), + items: events.map((item) => ({ + id: memberAnchor(name, item.name), + kind: "event", + label: item.name, + })), + }, + { + title: "Methods", + id: sectionAnchor(name, "methods"), + items: methods.map((item) => ({ + id: memberAnchor(name, item.name), + kind: "method", + label: item.name, + })), + }, + ] + : []), + ] + ); + + return ( +
    + {showRootHeading ? ( + + {entry.name} + + ) : null} + {showDocstring + ? (renderDocstringSections(entry.docstring_sections, {classSymbol: name, docId: metadata?.id}) ?? + renderDocstring(entry.docstring, {classSymbol: name, docId: metadata?.id})) + : null} + {image ? ( +
    + {entry.name} + {imageCaption ?
    {imageCaption}
    : null} +
    + ) : null} + {showBases && entry.bases?.length ? ( +

    + Inherits:{" "} + {entry.bases.map((baseName, index) => { + return ( + + {index > 0 ? ", " : ""} + + {renderCodeExpression(baseName, { + api, + classSymbol: name, + docId: metadata?.id, + })} + + + ); + })} +

    + ) : null} + {showSummary ? ( +
    + + + +
    + ) : null} + {showMembers ? ( + <> +
    renderAttribute(item, name, metadata?.id)} + /> +
    renderAttribute(item, name, metadata?.id)} + /> +
    renderMethod(item, name, metadata?.id)} + /> + + ) : null} +
    + ); +} diff --git a/website/src/components/crocodocs/ClassMembers.js b/website/src/components/crocodocs/ClassMembers.js new file mode 100644 index 0000000000..d5f2ff9d56 --- /dev/null +++ b/website/src/components/crocodocs/ClassMembers.js @@ -0,0 +1,18 @@ +import React from "react"; + +import ClassBlock from "./ClassBlock"; + +/** + * Renders only the members section (properties, events, methods) of an API class. + * Hides the docstring, base-class list, and summary table. + */ +export default function ClassMembers(props) { + return ( + + ); +} diff --git a/website/src/components/crocodocs/ClassSummary.js b/website/src/components/crocodocs/ClassSummary.js new file mode 100644 index 0000000000..55b252cb31 --- /dev/null +++ b/website/src/components/crocodocs/ClassSummary.js @@ -0,0 +1,11 @@ +import React from "react"; + +import ClassBlock from "./ClassBlock"; + +/** + * Renders the docstring, base-class list, and member summary table for an API class. + * Hides the full per-member detail sections. + */ +export default function ClassSummary(props) { + return ; +} diff --git a/website/src/components/crocodocs/CodeExample.js b/website/src/components/crocodocs/CodeExample.js new file mode 100644 index 0000000000..da1638eba9 --- /dev/null +++ b/website/src/components/crocodocs/CodeExample.js @@ -0,0 +1,26 @@ +import React from "react"; +import CodeBlock from "@theme/CodeBlock"; + +import {getExampleSource} from "./utils"; + +/** + * Renders a syntax-highlighted code block for a bundled example file. + * Shows an error message if the example path is not found in the code-examples bundle. + * + * @param {string} path - Relative path to the example file within the examples root. + * @param {string} [language="python"] - Language identifier for syntax highlighting. + * @param {string} [title] - Optional title displayed above the code block. + */ +export default function CodeExample({path, language = "python", title}) { + const source = getExampleSource(path); + + if (source == null) { + return
    Missing code example for {path}.
    ; + } + + return ( + + {source} + + ); +} diff --git a/website/src/components/crocodocs/Image.js b/website/src/components/crocodocs/Image.js new file mode 100644 index 0000000000..f5a743da8a --- /dev/null +++ b/website/src/components/crocodocs/Image.js @@ -0,0 +1,33 @@ +import React from "react"; +import {useDoc} from "@docusaurus/plugin-content-docs/client"; + +import {resolveDocAssetUrl} from "./utils"; + +/** + * Renders a documentation screenshot figure with optional caption and link wrapper. + * Resolves relative src paths against the current doc's location. + * + * @param {string} src - Image source path (absolute or relative to the doc). + * @param {string} [alt] - Alt text for the image. + * @param {string} [width] - CSS width value applied as an inline style. + * @param {string} [caption] - Optional figcaption text. + * @param {string} [link] - Optional URL to wrap the image in an anchor tag. + */ +export default function Image({src, alt, width, caption, link}) { + const {metadata} = useDoc(); + const resolvedSrc = resolveDocAssetUrl(src, metadata?.id); + const image = ( + {alt + ); + return ( +
    + {link ? {image} : image} + {caption ?
    {caption}
    : null} +
    + ); +} diff --git a/website/src/components/crocodocs/index.js b/website/src/components/crocodocs/index.js new file mode 100644 index 0000000000..adb39d9866 --- /dev/null +++ b/website/src/components/crocodocs/index.js @@ -0,0 +1,6 @@ +export {default as ClassAll} from "./ClassAll"; +export {default as ClassBlock} from "./ClassBlock"; +export {default as ClassMembers} from "./ClassMembers"; +export {default as ClassSummary} from "./ClassSummary"; +export {default as CodeExample} from "./CodeExample"; +export {default as Image} from "./Image"; diff --git a/website/src/components/crocodocs/utils.js b/website/src/components/crocodocs/utils.js new file mode 100644 index 0000000000..379505cb59 --- /dev/null +++ b/website/src/components/crocodocs/utils.js @@ -0,0 +1,1282 @@ +import React from "react"; +import apiData from "@site/.crocodocs/api-data.json"; +import codeExamples from "@site/.crocodocs/code-examples.json"; +import Admonition from "@theme/Admonition"; +import CodeBlock from "@theme/CodeBlock"; +import {unified} from "unified"; +import remarkDirective from "remark-directive"; +import remarkGfm from "remark-gfm"; +import remarkMdx from "remark-mdx"; +import remarkParse from "remark-parse"; + +const IMAGE_LINE_RE = /^!\[([^\]]*)\]\(([^)]+)\)(\{[^}]*\})?$/; +const WIDTH_RE = /width="([^"]+)"/; +const XREF_TEXT_RE = /\[([^\]]+)\]\[((?:[^\]]|\](?=[^.]))+?)\]/g; +const REST_XREF_RE = /^:(?:py:)?(class|attr|meth|func|data|mod|obj):`([^`\n]+)`/; +// Qualified references like `flet.Page` or `ft.Control.visible`. Safe to auto-link +// anywhere — the `flet.`/`ft.` prefix unambiguously marks this as an API reference. +const API_QUALIFIED_SYMBOL_RE = + /\b(?:ft|flet(?:_[a-z0-9_]+)?)\.[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*\b/g; +// Qualified OR bare capitalized identifiers (`Page`, `Control.visible`). Only safe +// inside code expressions (signature boxes, type annotations) where every capitalized +// token is an identifier. In prose, bare words like "Event", "Text", or "When" would +// be false positives — use API_QUALIFIED_SYMBOL_RE there instead. +const API_SYMBOL_RE = + /\b(?:ft|flet(?:_[a-z0-9_]+)?)\.[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*\b|\b[A-Z][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*\b/g; +// Public API labels should hide the import package while preserving class/member names. +// This covers core aliases (`ft.`, `flet.`) and extension packages (`flet_map.`, etc.). +const FLET_DISPLAY_PREFIX_RE = /^(?:ft|flet(?:_[a-z0-9_]+)?)\./; +const MARKDOWN_PARSER = unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkDirective) + .use(remarkMdx); + +/** + * Inline HTML-like elements that are safe to preserve from docstrings. + * Keep this list narrow: unknown MDX elements are intentionally dropped. + */ +const SAFE_INLINE_MDX_ELEMENTS = new Set(["kbd"]); + +/** Return the bundled api-data.json object. */ +export function getApiData() { + return apiData; +} + +/** + * Return the source code string for a bundled example file, or null if not found. + * @param {string} path - Relative path key as it appears in code-examples.json. + */ +export function getExampleSource(path) { + return codeExamples[path] ?? null; +} + +/** + * Convert a name string to a URL-safe anchor by stripping quotes, replacing brackets, + * collapsing non-alphanumeric runs to hyphens, and trimming leading/trailing hyphens. + */ +export function normalizeAnchor(name) { + return String(name) + .replace(/["']/g, "") + .replace(/\[([^\]]+)\]/g, "-$1") + .replace(/[^A-Za-z0-9._-]+/g, "-") + .replace(/-+/g, "-") + .replace(/^-|-$/g, ""); +} + +/** Return the anchor ID for the root heading of a symbol's documentation page. */ +export function rootAnchor(symbol) { + return normalizeAnchor(symbol); +} + +/** Return the anchor ID for a named section (e.g. 'properties', 'events') within a symbol's page. */ +export function sectionAnchor(symbol, sectionName) { + return normalizeAnchor(`${symbol}-${sectionName.toLowerCase()}`); +} + +/** Return the anchor ID for a named member (property, event, or method) within a symbol's page. */ +export function memberAnchor(symbol, memberName) { + return normalizeAnchor(`${symbol}.${memberName}`); +} + +/** + * Return all package-path prefixes of classSymbol (longest first) as symbol resolution candidates. + * Used to expand an unqualified name like 'Text' to 'flet.controls.text.Text', etc. + */ +function classPackageCandidates(classSymbol) { + if (!classSymbol || !classSymbol.includes(".")) { + return []; + } + const parts = classSymbol.split(".").slice(0, -1); + const candidates = []; + for (let i = parts.length; i > 0; i -= 1) { + const candidate = parts.slice(0, i).join("."); + if (!candidates.includes(candidate)) { + candidates.push(candidate); + } + } + return candidates; +} + +/** Strip surrounding single or double quotes from a symbol string. */ +function cleanApiSymbol(symbol) { + return symbol.replace(/^['"]|['"]$/g, ""); +} + +/** + * Format a symbol for display in a code link by stripping the leading package prefix + * (ft., flet., or flet_*.) so that only the short class/member name is shown. + */ +function formatApiSymbolLabel(symbol) { + const cleanSymbol = cleanApiSymbol(symbol); + return cleanSymbol.replace(FLET_DISPLAY_PREFIX_RE, ""); +} + +/** Look up a symbol in classes, functions, or aliases and return the first match, or null. */ +function getApiEntry(symbol, api) { + return api.classes?.[symbol] ?? api.functions?.[symbol] ?? api.aliases?.[symbol] ?? null; +} + +/** + * Resolve a single candidate symbol string to a documentation URL. + * First checks xref_map directly, then falls back to the entry's qualname/canonical_path. + * Returns null if no URL can be found. + */ +function resolveApiCandidateHref(candidate, api) { + if (!candidate) { + return null; + } + + const directHref = api.xref_map?.[candidate]; + if (directHref) { + return directHref; + } + + const entry = getApiEntry(candidate, api); + if (!entry) { + return null; + } + + return ( + api.xref_map?.[entry.qualname] ?? + api.xref_map?.[entry.canonical_path] ?? + api.xref_map?.[entry.target_path] ?? + null + ); +} + +/** + * Resolve a symbol string to its documentation URL, trying multiple candidate forms. + * Handles ft./flet. aliases and unqualified names relative to the current class context. + * + * @param {string} symbol - Symbol to resolve (may be qualified or unqualified). + * @param {object} [context] - Optional context with api and classSymbol fields. + * @returns {string|null} The resolved URL, or null if not found. + */ +export function resolveApiSymbolHref(symbol, context = {}) { + if (!symbol) { + return null; + } + + const api = context.api ?? getApiData(); + const cleanSymbol = cleanApiSymbol(symbol); + const candidates = []; + + /** Append candidate to the list if it is non-empty and not already present. */ + function addCandidate(candidate) { + if (!candidate || candidates.includes(candidate)) { + return; + } + candidates.push(candidate); + } + + addCandidate(cleanSymbol); + if (cleanSymbol.startsWith("ft.")) { + addCandidate(`flet.${cleanSymbol.slice(3)}`); + } + + if (!cleanSymbol.includes(".")) { + for (const packageName of classPackageCandidates(context.classSymbol)) { + addCandidate(`${packageName}.${cleanSymbol}`); + } + addCandidate(`flet.${cleanSymbol}`); + } else if ( + !cleanSymbol.startsWith("ft.") && + !cleanSymbol.startsWith("flet.") && + !cleanSymbol.startsWith("flet_") + ) { + for (const packageName of classPackageCandidates(context.classSymbol)) { + addCandidate(`${packageName}.${cleanSymbol}`); + } + addCandidate(`flet.${cleanSymbol}`); + } + + for (const candidate of candidates) { + const href = resolveApiCandidateHref(candidate, api); + if (href) { + return href; + } + } + + return null; +} + +/** + * Return the value of the first 'text' section in a docstring sections array, or null. + * Used to fall back to structured sections when a plain docstring string is absent. + */ +function firstTextSectionValue(sections) { + if (!sections || sections.length === 0) { + return null; + } + const textSection = sections.find( + (section) => section.kind === "text" && typeof section.value === "string" && section.value.trim(), + ); + return textSection?.value ?? null; +} + +/** + * Extract the first sentence from a docstring string or its structured sections, + * for use in summary tables. Returns null when no text is available. + */ +export function firstSentenceFromDocstring(docstring, docstringSections) { + const source = (typeof docstring === "string" && docstring.trim()) ? docstring : firstTextSectionValue(docstringSections); + if (!source) { + return null; + } + + const firstParagraph = source + .replace(/\n\s*\n[\s\S]*$/, "") + .replace(/\s+/g, " ") + .trim(); + + const sentenceMatch = firstParagraph.match(/^(.+?[.!?])(?:\s|$)/); + return sentenceMatch ? sentenceMatch[1].trim() : firstParagraph; +} + +/** + * Resolve a split URL path array by processing '..' and '.' segments, + * returning the resulting parts array without empty or '.' entries. + */ +function normalizeDocPath(parts) { + const out = []; + for (const part of parts) { + if (!part || part === ".") { + continue; + } + if (part === "..") { + out.pop(); + continue; + } + out.push(part); + } + return out; +} + +/** + * Resolve a doc-relative asset path to an absolute URL. + * Absolute URLs, protocol-relative URLs, root-relative paths, and fragment refs are returned as-is. + * Paths without '..' are served from the /docs/ static root. + * Paths with '..' are resolved relative to the current doc's directory. + * + * @param {string} src - The image or asset source path. + * @param {string} docId - The current doc's ID (e.g. 'controls/button'). + * @returns {string} The resolved absolute URL. + */ +export function resolveDocAssetUrl(src, docId) { + if (!src || /^(?:[a-z]+:)?\/\//i.test(src) || src.startsWith("/") || src.startsWith("#")) { + return src; + } + // Paths without ../ are relative to /docs/ static root + if (!src.startsWith("..")) { + return `/docs/${src}`; + } + if (!docId) { + return src; + } + const sourceDir = docId.includes("/") ? docId.split("/").slice(0, -1) : []; + const resolved = normalizeDocPath([...sourceDir, ...src.split("/")]); + return `/${["docs", ...resolved].join("/")}`; +} + +/** Remove leading and trailing backtick characters from a string. */ +function stripTicks(text) { + return text.replace(/^`|`$/g, ""); +} + +/** Return the API entry for context.classSymbol, or null when no classSymbol is set. */ +function getContextEntry(context, api) { + return context?.classSymbol ? getApiEntry(context.classSymbol, api) : null; +} + +/** + * Resolve memberName to an anchor ID within the current class context. + * Matches the class name itself, any of its properties/events/methods, or section names. + * Returns null when there is no match. + */ +function resolveLocalMemberAnchor(memberName, context, api) { + const classSymbol = context?.classSymbol; + const classEntry = getContextEntry(context, api); + if (!classSymbol || !classEntry) { + return null; + } + + if (classEntry.name === memberName) { + return rootAnchor(classSymbol); + } + + if ( + classEntry.properties?.some((item) => item.name === memberName) || + classEntry.events?.some((item) => item.name === memberName) || + classEntry.methods?.some((item) => item.name === memberName) + ) { + return memberAnchor(classSymbol, memberName); + } + + if (["properties", "events", "methods"].includes(memberName.toLowerCase())) { + return sectionAnchor(classSymbol, memberName); + } + + return null; +} + +/** + * Build a full href (route + anchor) for a member name within the current class context. + * Returns null when the class route or member anchor cannot be resolved. + */ +function resolveLocalMemberHref(memberName, context, api) { + const classSymbol = context?.classSymbol; + if (!classSymbol) { + return null; + } + + const classRoute = resolveApiSymbolHref(classSymbol, {...context, api}); + const anchor = resolveLocalMemberAnchor(memberName, context, api); + if (!classRoute || !anchor) { + return null; + } + + const classBaseRoute = classRoute.split("#", 1)[0]; + return `${classBaseRoute}#${anchor}`; +} + +/** + * Return symbol if it exists in the API, or its canonical public name if found via canonical_map. + * Returns null when neither form resolves to an API entry. + */ +function resolveQualifiedSymbol(symbol, api) { + if (getApiEntry(symbol, api)) { + return symbol; + } + const publicName = api.canonical_map?.[symbol]; + if (publicName && getApiEntry(publicName, api)) { + return publicName; + } + return null; +} + +/** Return the last dot-separated segment of a qualified name (e.g. 'flet.Button' -> 'Button'). */ +function shortenQualifiedDisplay(target) { + return target.split(".").at(-1) ?? target; +} + +/** + * Strip the leading public Flet module alias from a display label while preserving + * the remaining qualified path (e.g. 'flet.Page.route' -> 'Page.route', + * 'flet_map.Map.animation_curve' -> 'Map.animation_curve'). + */ +function stripFletDisplayPrefix(target) { + return target.replace(FLET_DISPLAY_PREFIX_RE, ""); +} + +/** + * Format the display label for a reStructuredText cross-reference target. + * A leading '~' causes the label to be shortened to just the last component. + * Otherwise, leading Flet package aliases are stripped from the rendered label. + * A trailing '()' is preserved on the display label. + */ +function formatRestXrefLabel(target) { + const shortened = target.startsWith("~"); + const normalized = shortened ? target.slice(1) : target; + const hasCall = normalized.endsWith("()"); + const base = hasCall ? normalized.slice(0, -2) : normalized; + const display = shortened + ? shortenQualifiedDisplay(base) + : stripFletDisplayPrefix(base); + return hasCall ? `${display}()` : display; +} + +/** + * Resolve a reStructuredText cross-reference (:py:class:`Foo`, :attr:`bar`, etc.) to a href and label. + * Tries local member resolution, then class context, then full symbol lookup, then base class walking. + * Returns null when no href can be found. + */ +function resolveRestCrossReference(role, target, context) { + const api = context?.api ?? getApiData(); + const trimmed = target.trim(); + if (!trimmed || trimmed.includes("<")) { + return null; + } + + const normalized = trimmed.startsWith("~") ? trimmed.slice(1) : trimmed; + const lookupTarget = role === "meth" && normalized.endsWith("()") + ? normalized.slice(0, -2) + : normalized; + + let href = null; + if (!lookupTarget.includes(".") && ["attr", "meth", "data", "obj"].includes(role)) { + href = resolveLocalMemberHref(lookupTarget, context, api); + } + + if (!href && !lookupTarget.includes(".") && role === "class") { + const contextEntry = getContextEntry(context, api); + if (contextEntry?.name === lookupTarget) { + href = resolveApiSymbolHref(context.classSymbol, {...context, api}); + } + } + + if (!href) { + href = resolveApiSymbolHref(lookupTarget, {...context, api}); + } + + // For unqualified members, try base classes (handles inherited members) + if (!href && !lookupTarget.includes(".") && context?.classSymbol) { + const entry = getApiEntry(context.classSymbol, api); + for (const base of entry?.bases ?? []) { + const resolvedBase = resolveQualifiedSymbol(base, api); + if (!resolvedBase) continue; + href = resolveLocalMemberHref(lookupTarget, {...context, classSymbol: resolvedBase}, api); + if (href) break; + } + } + + // For qualified member targets (e.g. flet.Card.margin), resolve class then walk bases + if (!href && lookupTarget.includes(".")) { + const lastDot = lookupTarget.lastIndexOf("."); + const classPart = lookupTarget.slice(0, lastDot); + const memberName = lookupTarget.slice(lastDot + 1); + const resolvedClass = resolveQualifiedSymbol(classPart, api); + if (resolvedClass) { + href = resolveLocalMemberHref(memberName, {classSymbol: resolvedClass}, api); + if (!href) { + const entry = getApiEntry(resolvedClass, api); + for (const base of entry?.bases ?? []) { + const resolvedBase = resolveQualifiedSymbol(base, api); + if (!resolvedBase) continue; + href = resolveLocalMemberHref(memberName, {classSymbol: resolvedBase}, api); + if (href) break; + } + } + } + } + + if (!href) { + return null; + } + + return { + href, + label: formatRestXrefLabel(trimmed), + }; +} + +/** + * Resolve a CrocoDocs cross-reference target string (from [label][target] syntax) to a href. + * Special targets: '(c)' = current class, '(c).' = local member, '(c).Foo' = specific local member, + * 'Pkg.' = absolute qualified lookup (appended with label). All other values use resolveApiSymbolHref. + */ +function resolveCrossReference(target, label, context) { + const api = getApiData(); + const cleanLabel = stripTicks(label); + + if (target === "(c)") { + return resolveApiSymbolHref(context?.classSymbol, {...context, api}); + } + if (target === "(c)." || target === "..") { + return resolveLocalMemberHref(cleanLabel, context, api); + } + if (target.startsWith("(c).")) { + return resolveLocalMemberHref(target.slice(4), context, api); + } + if (target.endsWith(".")) { + const absoluteTarget = target + cleanLabel; + return resolveApiCandidateHref(absoluteTarget, api); + } + return resolveApiSymbolHref(target, {...context, api}); +} + +/** + * Scan text for API symbol patterns and wrap each resolved symbol in an anchor element. + * When code=true, uses formatApiSymbolLabel for the link label and adds a code-link class. + * In prose (code=false), only qualified `flet.X`/`ft.X` references are matched — bare + * capitalized words are skipped to avoid linking common English words like "Event". + * Returns the original text string when no symbols resolve. + */ +function renderAutolinkedText(text, context, code = false) { + const nodes = []; + let lastIndex = 0; + let key = 0; + + const pattern = code ? API_SYMBOL_RE : API_QUALIFIED_SYMBOL_RE; + for (const match of text.matchAll(pattern)) { + const matchText = match[0]; + const href = resolveApiSymbolHref(matchText, context); + if (!href) { + continue; + } + if (match.index > lastIndex) { + nodes.push(text.slice(lastIndex, match.index)); + } + nodes.push( + + {code ? formatApiSymbolLabel(matchText) : matchText} + , + ); + lastIndex = match.index + matchText.length; + } + + if (lastIndex < text.length) { + nodes.push(text.slice(lastIndex)); + } + + return nodes.length ? nodes : text; +} + +/** + * Render a text string by resolving explicit [label][target] cross-references. + * Bare API symbols in prose are not auto-linked; use reST roles or CrocoDocs + * Markdown cross-references when a link is intended. + */ +function renderTextWithCrossReferences(text, context, keyPrefix) { + const nodes = []; + let lastIndex = 0; + let key = 0; + + for (const match of text.matchAll(XREF_TEXT_RE)) { + if (match.index > lastIndex) { + nodes.push(text.slice(lastIndex, match.index)); + } + + const href = resolveCrossReference(match[2], match[1], context); + if (href) { + nodes.push( + + {renderInlineMarkdown(match[1], context)} + + ); + } else { + nodes.push(match[0]); + } + + lastIndex = match.index + match[0].length; + } + + if (lastIndex < text.length) { + nodes.push(text.slice(lastIndex)); + } + + return nodes.length ? nodes : text; +} + +/** + * Replace [label][target] cross-references in markdown text with standard [label](href) links + * before the text is fed to the Markdown parser. Skips fenced code blocks. + */ +function preprocessCrossReferenceMarkdown(text, context) { + if (!text) { + return text; + } + + const segments = text.split(/(```[\s\S]*?```)/g); + return segments + .map((segment) => { + if (segment.startsWith("```")) { + return segment; + } + return segment.replace(XREF_TEXT_RE, (full, label, target) => { + const href = resolveCrossReference(target, label, context); + return href ? `[${label}](${href})` : full; + }); + }) + .join(""); +} + +/** + * Replace reStructuredText :role:`target` cross-references in markdown text with + * [`label`](href) links before the text is fed to the Markdown parser. + * Skips fenced code blocks and inline code spans. + */ +function preprocessRestCrossReferenceMarkdown(text, context) { + if (!text) { + return text; + } + + let index = 0; + let output = ""; + + while (index < text.length) { + if (text.startsWith("```", index)) { + const fenceEnd = text.indexOf("```", index + 3); + if (fenceEnd < 0) { + output += text.slice(index); + break; + } + output += text.slice(index, fenceEnd + 3); + index = fenceEnd + 3; + continue; + } + + const roleMatch = REST_XREF_RE.exec(text.slice(index)); + if (roleMatch) { + const resolved = resolveRestCrossReference(roleMatch[1], roleMatch[2], context); + if (resolved) { + output += `[\`${resolved.label}\`](${resolved.href})`; + } else { + output += roleMatch[0]; + } + index += roleMatch[0].length; + continue; + } + + if (text[index] === "`") { + const inlineEnd = text.indexOf("`", index + 1); + if (inlineEnd < 0) { + output += text.slice(index); + break; + } + output += text.slice(index, inlineEnd + 1); + index = inlineEnd + 1; + continue; + } + + output += text[index]; + index += 1; + } + + return output; +} + +/** + * Escape bare '<' characters (not followed by tag-start or '!') to '<' in non-code text. + * Prevents MDX from treating angle brackets in docstrings as JSX elements. + * Skips fenced code blocks and inline backtick spans. + */ +function escapeMdxUnsafeAngles(text) { + if (!text) { + return text; + } + + const fenceSplit = text.split(/(```[\s\S]*?```)/g); + return fenceSplit + .map((fenceSegment) => { + if (fenceSegment.startsWith("```")) { + return fenceSegment; + } + const inlineSplit = fenceSegment.split(/(`[^`\n]+`)/g); + return inlineSplit + .map((inlineSegment) => { + if (inlineSegment.startsWith("`") && inlineSegment.endsWith("`")) { + return inlineSegment; + } + return inlineSegment.replace(/<(?![A-Za-z!/])/g, "<"); + }) + .join(""); + }) + .join(""); +} + +/** + * Render a code expression string as React nodes, auto-linking any API symbols it contains. + * Intended for use inside signature boxes and inline type/default value displays. + */ +export function renderCodeExpression(text, context = {}) { + return renderAutolinkedText(text, context, true); +} + +/** Render a fenced code block using the Docusaurus CodeBlock theme component. */ +function renderCodeBlock(code, language, key) { + return ( + + {code} + + ); +} + +/** + * Render an image figure from a regex match array [_, alt, url, attrs]. + * Resolves the src path via resolveDocAssetUrl and applies an optional width override. + */ +function renderImageFromMatch(match, context, key, widthOverride = null) { + const width = widthOverride ?? WIDTH_RE.exec(match[3] ?? "")?.[1]; + const src = resolveDocAssetUrl(match[2], context?.docId); + return ( +
    + {match[1]} +
    + ); +} + +/** + * Render a single markdown line as either an image figure (if it matches IMAGE_LINE_RE) + * or a plain paragraph with inline markdown. + */ +function renderImage(line, context, key) { + const match = IMAGE_LINE_RE.exec(line.trim()); + if (!match) { + return

    {renderInlineMarkdown(line, context)}

    ; + } + return renderImageFromMatch(match, context, key); +} + +/** + * Transform docstring Markdown that uses the Python '/// admonition' convention into + * Docusaurus ':::type' admonition syntax. Also strips '/// caption' and bare '///' lines. + */ +function normalizeDocstringMarkdown(docstring) { + const lines = docstring.split("\n"); + const output = []; + let index = 0; + + while (index < lines.length) { + const trimmed = lines[index].trim(); + if (trimmed.startsWith("/// caption")) { + index += 1; + if (index < lines.length && lines[index].trim() === "///") { + index += 1; + } + continue; + } + if (trimmed === "///") { + index += 1; + continue; + } + const admonitionMatch = trimmed.match( + /^\/\/\/\s*admonition(?:\s*\|\s*(.+))?$/ + ); + if (!admonitionMatch) { + output.push(lines[index]); + index += 1; + continue; + } + + const title = admonitionMatch[1]?.trim(); + let admonitionType = "note"; + const body = []; + index += 1; + + while (index < lines.length) { + const bodyLine = lines[index]; + const bodyTrimmed = bodyLine.trim(); + if (bodyTrimmed === "///") { + index += 1; + break; + } + const typeMatch = bodyTrimmed.match(/^type:\s*(\w+)\s*$/); + if (typeMatch) { + admonitionType = + typeMatch[1] === "example" ? "note" : typeMatch[1]; + } else { + body.push(bodyLine); + } + index += 1; + } + + output.push(`:::${admonitionType}${title ? `[${title}]` : ""}`); + output.push(...body); + output.push(":::"); + } + + return output.join("\n"); +} + +/** + * Extract the directiveLabel paragraph child from a directive node and render it. + * Returns the rendered label and the remaining children array (without the label node). + */ +function extractDirectiveLabel(node, context, keyPrefix) { + const labelIndex = node.children?.findIndex( + (child) => child.type === "paragraph" && child.data?.directiveLabel + ); + if (labelIndex == null || labelIndex < 0) { + return {label: undefined, children: node.children ?? []}; + } + const labelNode = node.children[labelIndex]; + const label = renderInlineNodes( + labelNode.children ?? [], + context, + `${keyPrefix}-label` + ); + const children = node.children.filter((_, index) => index !== labelIndex); + return {label, children}; +} + +/** + * Extract a width value from an mdxTextExpression, mdxJsxFlowElement, or mdxJsxTextElement node. + * Returns null when no width is present. + */ +function extractImageWidth(node) { + if (!node) { + return null; + } + if (node.type === "mdxTextExpression") { + return node.value.match(/^width\s*=\s*"([^"]+)"$/)?.[1] ?? null; + } + if ( + node.type === "mdxJsxFlowElement" || + node.type === "mdxJsxTextElement" + ) { + const widthAttr = node.attributes?.find((attr) => attr.name === "width"); + return typeof widthAttr?.value === "string" ? widthAttr.value : null; + } + return null; +} + +/** + * Render an image figure from a raw HTML img string, resolving the src and applying width. + * Returns null when no src attribute is found in the string. + */ +function renderHtmlImage(raw, context, key, widthOverride = null) { + const srcMatch = raw.match(/\bsrc="([^"]+)"/); + if (!srcMatch) { + return null; + } + const alt = raw.match(/\balt="([^"]*)"/)?.[1] ?? ""; + const width = widthOverride ?? raw.match(/\bwidth="([^"]+)"/)?.[1] ?? null; + const src = resolveDocAssetUrl(srcMatch[1], context?.docId); + return ( +
    + {alt} +
    + ); +} + +/** + * Render an array of inline AST nodes to React elements. + * Pre-processes adjacent text/inlineCode/text triplets that form '[`code`][target]' + * cross-references into synthetic 'crocodocsCodeReference' nodes before rendering. + */ +function renderInlineNodes(nodes, context, keyPrefix) { + const repaired = []; + for (let index = 0; index < nodes.length; index += 1) { + const node = nodes[index]; + const next = nodes[index + 1]; + const nextNext = nodes[index + 2]; + if ( + node?.type === "text" && + next?.type === "inlineCode" && + nextNext?.type === "text" + ) { + const prefixMatch = node.value.match(/^(.*)\[$/s); + const suffixMatch = nextNext.value.match(/^\]\[([^\]]+)\](.*)$/s); + if (prefixMatch && suffixMatch) { + if (prefixMatch[1]) { + repaired.push({...node, value: prefixMatch[1]}); + } + repaired.push({ + type: "crocodocsCodeReference", + value: next.value, + target: suffixMatch[1], + }); + if (suffixMatch[2]) { + repaired.push({...nextNext, value: suffixMatch[2]}); + } + index += 2; + continue; + } + } + repaired.push(node); + } + + return repaired.flatMap((node, index) => + renderMarkdownNode(node, context, `${keyPrefix}-${index}`, true) + ); +} + +/** + * Recursively render a single remark AST node to React elements. + * Handles all standard Markdown node types plus MDX JSX image elements, + * directives (admonitions), tables, and the custom 'crocodocsCodeReference' type. + * Returns an empty array for unknown or unsupported node types. + */ +function renderMarkdownNode(node, context, key, inline = false) { + if (!node) { + return []; + } + + switch (node.type) { + case "root": + return node.children.flatMap((child, index) => + renderMarkdownNode(child, context, `${key}-${index}`) + ); + case "paragraph": { + if (!inline && node.children?.length) { + const first = node.children[0]; + const second = node.children[1]; + if ( + first.type === "image" && + (node.children.length === 1 || + (node.children.length === 2 && + second?.type === "mdxTextExpression")) + ) { + const match = [ + "", + first.alt ?? "", + first.url, + second ? `{width="${extractImageWidth(second)}"}` : "", + ]; + return renderImageFromMatch( + match, + context, + key, + second ? extractImageWidth(second) : null + ); + } + if ( + first.type === "mdxJsxFlowElement" && + first.name === "img" && + node.children.length === 1 + ) { + const raw = ` typeof attr.value === "string") + .map((attr) => `${attr.name}="${attr.value}"`) + .join(" ")} />`; + return renderHtmlImage(raw, context, key); + } + } + return

    {renderInlineNodes(node.children ?? [], context, key)}

    ; + } + case "text": + return [].concat(renderTextWithCrossReferences(node.value, context, key)); + case "strong": + return ( + + {renderInlineNodes(node.children ?? [], context, key)} + + ); + case "emphasis": + return {renderInlineNodes(node.children ?? [], context, key)}; + case "delete": + return {renderInlineNodes(node.children ?? [], context, key)}; + case "inlineCode": + return {node.value}; + case "break": + return
    ; + case "link": + return ( + + {renderInlineNodes(node.children ?? [], context, key)} + + ); + case "linkReference": { + const href = resolveCrossReference( + node.identifier, + node.label ?? "", + context + ); + if (!href) { + return renderInlineNodes(node.children ?? [], context, key); + } + return ( + + {renderInlineNodes(node.children ?? [], context, key)} + + ); + } + case "crocodocsCodeReference": { + const href = resolveCrossReference(node.target, node.value, context); + if (!href) { + return {node.value}; + } + return ( + + {node.value} + + ); + } + case "list": + return React.createElement( + node.ordered ? "ol" : "ul", + {key}, + node.children.flatMap((child, index) => + renderMarkdownNode(child, context, `${key}-${index}`) + ) + ); + case "listItem": + if ( + node.children?.length === 1 && + node.children[0]?.type === "paragraph" + ) { + return ( +
  • + {renderInlineNodes(node.children[0].children ?? [], context, key)} +
  • + ); + } + return ( +
  • + {node.children.flatMap((child, index) => + renderMarkdownNode(child, context, `${key}-${index}`) + )} +
  • + ); + case "code": + return renderCodeBlock(node.value, node.lang, key); + case "image": { + const match = ["", node.alt ?? "", node.url, ""]; + return renderImageFromMatch(match, context, key); + } + case "heading": + return React.createElement( + `h${Math.min(node.depth, 6)}`, + {key}, + renderInlineNodes(node.children ?? [], context, key) + ); + case "blockquote": + return ( +
    + {node.children.flatMap((child, index) => + renderMarkdownNode(child, context, `${key}-${index}`) + )} +
    + ); + case "thematicBreak": + return
    ; + case "containerDirective": { + const {label, children} = extractDirectiveLabel(node, context, key); + return ( + + {children.flatMap((child, index) => + renderMarkdownNode(child, context, `${key}-${index}`) + )} + + ); + } + case "mdxJsxFlowElement": + case "mdxJsxTextElement": + if (node.name === "img") { + const raw = ` typeof attr.value === "string") + .map((attr) => `${attr.name}="${attr.value}"`) + .join(" ")} />`; + return renderHtmlImage(raw, context, key, extractImageWidth(node)); + } + + // Preserve safe semantic inline tags from Python docstrings. + if (inline && SAFE_INLINE_MDX_ELEMENTS.has(node.name)) { + return React.createElement( + node.name, + {key}, + renderInlineNodes(node.children ?? [], context, key) + ); + } + return []; + case "html": + if (node.value.trim().startsWith("; + case "table": + return ( + + + {node.children.slice(0, 1).flatMap((child, i) => + renderMarkdownNode( + {...child, data: {...child.data, isHeader: true}}, + context, + `${key}-h${i}` + ) + )} + + + {node.children.slice(1).flatMap((child, i) => + renderMarkdownNode(child, context, `${key}-b${i}`) + )} + +
    + ); + case "tableRow": + return ( + + {node.children.flatMap((child, i) => + renderMarkdownNode( + node.data?.isHeader + ? {...child, data: {...child.data, isHeader: true}} + : child, + context, + `${key}-${i}` + ) + )} + + ); + case "tableCell": { + const Tag = node.data?.isHeader ? "th" : "td"; + return ( + + {node.children.flatMap((child, i) => + renderMarkdownNode(child, context, `${key}-${i}`) + )} + + ); + } + default: + return []; + } +} + +/** + * Parse and render a markdown text string as inline React nodes. + * Applies cross-reference preprocessing and MDX angle-bracket escaping before parsing. + * Returns null for empty/null input. + */ +export function renderInlineMarkdown(text, context) { + if (!text) { + return null; + } + const tree = MARKDOWN_PARSER.parse( + escapeMdxUnsafeAngles( + preprocessRestCrossReferenceMarkdown( + preprocessCrossReferenceMarkdown(text, context), + context + ) + ) + ); + const paragraph = + tree.children.length === 1 && tree.children[0].type === "paragraph" + ? tree.children[0] + : tree; + return paragraph.type === "paragraph" + ? renderInlineNodes(paragraph.children ?? [], context, "inline") + : renderMarkdownNode(paragraph, context, "inline"); +} + +/** + * Parse and render a full docstring as block React elements. + * Applies admonition normalization, cross-reference preprocessing, and MDX escaping. + * Returns null for empty/null input. + */ +export function renderDocstring(docstring, context = {}, keyPrefix = "doc") { + if (!docstring) { + return null; + } + const tree = MARKDOWN_PARSER.parse( + escapeMdxUnsafeAngles( + preprocessRestCrossReferenceMarkdown( + preprocessCrossReferenceMarkdown( + normalizeDocstringMarkdown(docstring), + context + ), + context + ) + ) + ); + return renderMarkdownNode(tree, context, keyPrefix); +} + +/** + * Render a structured docstring sections array (as produced by griffe_extract_script) to React elements. + * Handles 'text', 'admonition', 'parameters', 'returns', and 'raises' section kinds. + * Returns null when sections is empty or null. + */ +export function renderDocstringSections(sections, context = {}) { + if (!sections || sections.length === 0) { + return null; + } + + const blocks = []; + let key = 0; + + for (const section of sections) { + if (section.kind === "text") { + blocks.push(...(renderDocstring(section.value, context, `section-${key++}`) ?? [])); + continue; + } + + if (section.kind === "admonition") { + const VALID_TYPES = new Set([ + "note", "tip", "info", "warning", "danger", "caution", + ]); + const admonitionType = VALID_TYPES.has(section.admonition_kind) + ? section.admonition_kind + : "note"; + blocks.push( + + {renderDocstring(section.value, context, `adm-${key}`)} + + ); + continue; + } + + if (!section.items?.length) { + continue; + } + + const title = + section.kind === "parameters" + ? "Parameters" + : section.kind === "returns" + ? "Returns" + : section.kind === "raises" + ? "Raises" + : null; + + if (!title) { + continue; + } + + blocks.push( +
    +

    + {title}: +

    +
      + {section.items.map((item, index) => { + const fragments = []; + let openedMeta = false; + if (item.name) { + fragments.push( + + {item.name} + + ); + } + if (item.type) { + fragments.push( + + {item.name ? " (" : ""} + + {renderCodeExpression(item.type, context)} + + + ); + openedMeta = Boolean(item.name); + } + if (item.default != null) { + fragments.push( + + {openedMeta ? ", " : item.name ? " (" : ""} + default: {item.default} + + ); + openedMeta = Boolean(item.name); + } + if (openedMeta) { + fragments.push()); + } + if (item.description) { + if (fragments.length) { + fragments.push( + + {" "}{"-"}{" "} + + ); + } + fragments.push( + + {renderInlineMarkdown(item.description.replace(/\s*\n\s*/g, " "), context)} + + ); + } + + return
    • {fragments}
    • ; + })} +
    +
    + ); + } + + return blocks; +} diff --git a/website/src/components/signup-form/index.js b/website/src/components/signup-form/index.js new file mode 100644 index 0000000000..44466a2d63 --- /dev/null +++ b/website/src/components/signup-form/index.js @@ -0,0 +1,80 @@ +import React, { useEffect, useRef, useState } from "react"; +import BrowserOnly from '@docusaurus/BrowserOnly'; +import HCaptcha from "@hcaptcha/react-hcaptcha"; +import styles from './styles.module.css'; + +export default function SignupForm() { + const [token, setToken] = useState(null); + const [email, setEmail] = useState(""); + const captchaRef = useRef(null); + + const onSubmit = (event) => { + event.preventDefault(); + captchaRef.current.execute(); + }; + + const onExpire = () => { + console.log("hCaptcha Token Expired"); + }; + + const onError = (err) => { + console.log(`hCaptcha Error: ${err}`); + }; + + useEffect(() => { + if (token) { + const asyncFn = async () => { + var data = { + email: email, + captchaToken: token + }; + + // send message + const response = await fetch("/api/email-signup", { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + const results = await response.json(); + console.log(`Results:`, results); + }; + asyncFn(); + } + }, [token, email]); + + return ( +
    + Loading...
    }> + {() => { + if (token) { + // signup submitted + return
    Thank you! You will receive the confirmation email shortly.
    + } else if (window.location.href.endsWith('?signup-confirmed')) { + // signup confirmed + return
    🎉Congratulations! You have successfully subscribed to Flet newsletter.
    + } else { + // signup form + return
    +

    Subscribe to Flet newsletter for project updates and tutorials!

    + setEmail(evt.target.value)} + /> + + + + } + }} + +
    + ); +} diff --git a/website/src/components/signup-form/styles.module.css b/website/src/components/signup-form/styles.module.css new file mode 100644 index 0000000000..14d8085c7f --- /dev/null +++ b/website/src/components/signup-form/styles.module.css @@ -0,0 +1,74 @@ +.signupForm { + text-align: center; + margin: 1rem auto 2rem auto; + padding: 20px; + max-width: 600px; + width: 100%; + /* background-color: var(--ifm-color-secondary); */ + border-radius: 8px; + box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.1); + ; +} + +.signupForm h3 { + font-size: 15px; + font-weight: 600; +} + +.signupForm input[type=email], +.signupForm input[type=email]:focus { + border-style: solid; + border-width: 1px 0 1px 1px; + border-color: var(--ifm-color-primary-light); + border-radius: 4px 0 0 4px; + background-color: transparent; + font-size: 15px; + font-weight: 500; + padding: 0 15px; + height: 40px; + width: 80%; +} + +.signupForm input[type=submit] { + background-color: #e5e5e5; + display: inline-block; + line-height: 1.2em; + text-decoration: none !important; + transition: background 0.6s; + border-color: var(--ifm-color-primary-light); + border-style: solid; + border-radius: 0 4px 4px 0; + border-width: 1px 1px 1px 0; + /* color: var(--ifm-color-primary-dark); */ + font-size: 15px; + font-weight: 500; + height: 40px; + padding: 0 20px; + cursor: pointer; +} + +html[data-theme='dark'] .signupForm input[type=submit] { + background-color: #333; +} + +@media only screen and (max-width: 768px) { + + /* For mobile phones: */ + .signupForm { + margin: 1rem auto 1rem auto; + padding: 10px 5px; + max-width: 300px; + } + + .signupForm input[type=email], + .signupForm input[type=email]:focus { + width: 60%; + padding: 0 10px; + height: 30px; + } + + .signupForm input[type=submit] { + padding: 0 10px; + height: 30px; + } +} \ No newline at end of file diff --git a/website/src/css/custom.css b/website/src/css/custom.css new file mode 100644 index 0000000000..4b0dc4c85c --- /dev/null +++ b/website/src/css/custom.css @@ -0,0 +1,557 @@ +/* stylelint-disable docusaurus/copyright-header */ +/** + * Any CSS included here will be global. The classic template + * bundles Infima by default. Infima is a CSS framework designed to + * work well for content-centric websites. + */ + +@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,200,1,200&icon_names=bolt,build,deployed_code"); + +/* You can override the default Infima variables here. */ +:root { + --ifm-color-primary: #0098da; + --ifm-color-primary-dark: #0089c4; + --ifm-color-primary-darker: #0081b9; + --ifm-color-primary-darkest: #006a99; + --ifm-color-primary-light: #00a7f0; + --ifm-color-primary-lighter: #00affb; + --ifm-color-primary-lightest: #1cbaff; + + --ifm-color-secondary: #f8f8f8; + + --ifm-code-font-size: 95%; + --ifm-h4-font-size: 1.1rem; + + --flet-link-color: #008dfb; + --ifm-link-color: var(--flet-link-color); + --ifm-navbar-link-hover-color: var(--flet-link-color); + + --docusaurus-highlighted-code-line-bg: rgb(220, 221, 223); + + /* navbar */ + /* --ifm-navbar-padding-vertical: 0.5rem; + --ifm-navbar-padding-horizontal: 0.7rem; */ + --ifm-navbar-background-color: #fff; + + /* menu */ + --ifm-menu-color-active: var(--flet-link-color); + --ifm-tabs-color-active: var(--flet-link-color); +} + + + +.navbar__logo { + /* width: 42px; */ + height: 30px; +} + +.flet-hero h1 { + color: rgb(14, 165, 230); + font-size: 60px; + font-weight: 600; + margin-top: 2rem; +} + +.hero__subtitle { + color: #555; + font-size: 27px; + font-weight: 400; +} + +@media only screen and (max-width: 768px) { + + /* For mobile phones: */ + .flet-hero h1 { + font-size: 60px; + font-weight: 500; + margin: 1rem; + text-align: center; + } + + .hero__subtitle { + font-size: 18px; + } +} + +.header-github-link:hover { + opacity: 0.6; +} + +.header-github-link::before { + content: ''; + width: 24px; + height: 24px; + display: flex; + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat; +} + +[data-theme='dark'] .header-github-link::before { + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat; +} + +.card { + height: 100%; +} + +.gallery-grid { + display: grid; + gap: 24px; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); +} + +.gallery-footer { + display: flex; + flex-direction: row; +} + +.gallery-github-link::before { + content: ''; + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat; + background-size: 18px; + margin-top: 10px; + width: 20px; + height: 20px; + display: flex; + text-align: right; +} + +.gallery-github-link:hover { + opacity: 0.6; +} + +[data-theme='dark'] .gallery-github-link::before { + background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat; +} + +.gallery-live-link { + flex: 1; +} + +.gallery-live-link img { + border-radius: 5px; + height: inherit !important; + max-width: inherit !important; + max-height: 200px; +} + +.gallery-description { + font-size: 0.9rem; +} + +/* h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 700; +} */ + +.icon-button { + vertical-align: text-bottom; + background-color: #eee; + border-radius: 2px; + padding: 1px; + width: 22px; +} + +:not(pre) > code { + background: var(--ifm-code-background); + border: 0; + border-radius: var(--ifm-code-border-radius); + box-shadow: none; + padding: 0.1em 0.35em; +} + +.crocodocs-member-heading { + align-items: center; + column-gap: 0.5rem; + display: inline-flex; + flex-wrap: wrap; +} + +.material-symbols-outlined { + direction: ltr; + display: inline-block; + font-family: "Material Symbols Outlined"; + font-size: 1em; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-height: 1; + text-transform: none; + white-space: nowrap; + word-wrap: normal; + font-variation-settings: "FILL" 1, "GRAD" 200, "opsz" 24, "wght" 200; + -webkit-font-feature-settings: "liga"; + -webkit-font-smoothing: antialiased; +} + +.crocodocs-member-icon { + line-height: 1; + vertical-align: middle; +} + +.crocodocs-member-icon--heading { + font-size: 1rem; + position: relative; + top: 0.12em; +} + +.crocodocs-member-icon--toc { + font-size: 0.82rem; + position: relative; + top: 0.07em; +} + +.crocodocs-member-toc-link { + align-items: center; + column-gap: 0.35rem; + display: inline-flex; + line-height: 1.2; +} + +.crocodocs-member-icon--property { + color: #0b8dd9; +} + +.crocodocs-member-icon--event { + color: #f8aa01; +} + +.crocodocs-member-icon--method { + color: #7c4dff; +} + +.crocodocs-member-badges { + align-items: center; + column-gap: 0.35rem; + display: inline-flex; + flex-wrap: wrap; + position: relative; + top: 0.08em; +} + +.crocodocs-member-badge { + border: 1px solid var(--ifm-toc-border-color); + border-radius: 999px; + color: var(--ifm-color-emphasis-700); + display: inline-block; + font-size: 0.72rem; + font-weight: 500; + line-height: 1.2; + padding: 0.05rem 0.45rem; +} + +.crocodocs-summary-name { + font-weight: 600; +} + +.crocodocs-signature-box { + margin-bottom: var(--ifm-paragraph-margin-bottom); + position: relative; +} + +.crocodocs-signature-copy { + background: var(--ifm-color-emphasis-200); + border: 0; + border-radius: 999px; + color: var(--ifm-font-color-base); + cursor: pointer; + font-size: 0.72rem; + line-height: 1; + opacity: 0; + padding: 0.35rem 0.55rem; + position: absolute; + right: 0.75rem; + top: 0.75rem; + transition: opacity 0.15s ease-in-out; + z-index: 1; +} + +.crocodocs-signature-box:hover .crocodocs-signature-copy, +.crocodocs-signature-copy:focus-visible { + opacity: 1; +} + +.crocodocs-signature-pre { + background: var(--ifm-code-background); + border-radius: var(--ifm-code-border-radius); + margin: 0; + overflow-x: auto; + padding: 1rem 1.25rem; +} + +.crocodocs-signature-content { + color: var(--ifm-font-color-base); + display: block; + font-family: var(--ifm-font-family-monospace); + font-size: 0.95rem; + line-height: 1.6; + white-space: pre; +} + +.crocodocs-inline-code { + background: var(--ifm-code-background); + border-radius: var(--ifm-code-border-radius); + font-family: var(--ifm-font-family-monospace); + font-size: 0.95em; + padding: 0.1em 0.35em; +} + +.crocodocs-code-link { + color: var(--ifm-link-color); + text-decoration: none; +} + +.crocodocs-signature-content .crocodocs-code-link, +.crocodocs-inline-code .crocodocs-code-link { + color: var(--ifm-link-color); +} + +.crocodocs-code-link:hover, +.crocodocs-code-link:focus-visible { + text-decoration: underline; +} + +.doc-screenshot-figure, +.screenshot, +[class^='screenshot-'], +[class*=' screenshot-'] { + display: block; + text-align: center; + margin: auto auto var(--ifm-paragraph-margin-bottom); +} + +.doc-screenshot-figure { + padding: 0.5rem 0 1rem; +} + +.doc-screenshot { + display: block; + margin: 0 auto; + max-width: 100%; +} + +.doc-screenshot-figure figcaption { + margin-top: 0.75rem; +} + +.doc-screenshot-figure img, +.screenshot img, +[class^='screenshot-'] img, +[class*=' screenshot-'] img { + display: block; + margin: 0 auto; + max-width: 100%; +} + +.screenshot { + width: 100%; +} + +.screenshot-10 { + width: 10%; +} + +.screenshot-20 { + width: 20%; +} + +.screenshot-30 { + width: 30%; +} + +.screenshot-40 { + width: 40%; +} + +.screenshot-50 { + width: 50%; +} + +.screenshot-60 { + width: 60%; +} + +.screenshot-70 { + width: 70%; +} + +.screenshot-80 { + width: 80%; +} + +.screenshot-90 { + width: 90%; +} + +.screenshot-100 { + width: 100%; +} + +.screenshot-rounded { + border-radius: 7px; + box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px; +} + +@media only screen and (max-width: 768px) { + .doc-screenshot-figure, + .screenshot, + [class^='screenshot-'], + [class*=' screenshot-'] { + width: 100% !important; + max-width: 100%; + } + + .doc-screenshot, + .doc-screenshot-figure img, + .screenshot img, + [class^='screenshot-'] img, + [class*=' screenshot-'] img, + .screenshot-80, + .screenshot-90, + .screenshot-100 { + width: 100% !important; + max-width: 100%; + height: auto; + } +} + +.control-demo { + color: var(--ifm-color-secondary-lightest); + text-decoration: none; + border-radius: 5px; + padding: 10px 20px; + background-color: var(--ifm-color-primary); + transition: background 0.6s; +} + +.control-demo:hover { + color: var(--ifm-color-secondary-lightest); + text-decoration: none; + background-color: var(--ifm-color-primary-darkest); +} + +/* Dark theme */ +html[data-theme='dark']:root { + --flet-link-color: #02aaf2; + --ifm-background-color: #181A21; + --ifm-navbar-background-color: #181A21; + --ifm-footer-background-color: #1f2127; + --ifm-color-secondary: #2f2f2f; + --docusaurus-highlighted-code-line-bg: rgb(76, 81, 90); +} + +html[data-theme='dark'] .navbar__title { + color: #f0f0f0; +} + +html[data-theme='dark'] .flet-hero h1 { + color: #3ba9fd; +} + +html[data-theme='dark'] .hero__subtitle { + color: var(--ifm-color-emphasis-600); +} + +html[data-theme='dark'] .docusaurus-highlight-code-line { + background-color: rgb(50, 52, 64); +} + +.legal ol { + counter-reset: item; + list-style-type: none; +} + +.legal>ol>li { + text-transform: uppercase; + font-size: 1.1rem; + margin: 1.5rem 0; +} + +.legal ol li:before { + content: counters(item, ".") ". "; + counter-increment: item; +} + +.legal ol ol ol li:before { + content: none; +} + +.legal ol ol { + list-style-type: none; +} + +.legal ol ol li { + text-transform: none; + margin: 0.5rem 0; +} + +.legal ol ol ol { + list-style-type: lower-alpha; +} + +.legal ol ol ol ol { + list-style-type: lower-roman; +} + +.legal ol ol ol ol ol { + list-style-type: upper-alpha; +} + +/* Compact card grid for generated-index pages (Controls, Services, Cookbook) */ +/* Compact card grid for generated-index pages (Controls, Services, Cookbook) */ +[class*="generatedIndexPage"] .card.padding--lg { + padding: 0.6rem 0.85rem !important; + box-shadow: none; + border: 1px solid var(--ifm-color-emphasis-200); + border-radius: 0.3rem; + display: flex; + align-items: center; + justify-content: flex-start; + min-height: 0; +} + +[class*="generatedIndexPage"] .card.padding--lg:hover { + border-color: var(--ifm-color-primary); +} + +[class*="generatedIndexPage"] [class*="cardTitle"] { + font-size: 0.95rem; + font-weight: 500; + margin: 0; + text-align: left; + width: 100%; +} + +[class*="generatedIndexPage"] [class*="cardDescription"] { + display: none; +} + +[class*="generatedIndexPage"] [class*="docCardListItem"] { + margin-bottom: 0.5rem; +} + +[class*="generatedIndexPage"] .col--6 { + --ifm-col-width: 25%; + padding: 0 0.3rem; +} + +@media (max-width: 1200px) { + [class*="generatedIndexPage"] .col--6 { + --ifm-col-width: 33.333%; + } +} + +@media (max-width: 768px) { + [class*="generatedIndexPage"] .col--6 { + --ifm-col-width: 50%; + } +} + +@media (max-width: 480px) { + [class*="generatedIndexPage"] .col--6 { + --ifm-col-width: 100%; + } +} diff --git a/website/src/pages/gallery.md b/website/src/pages/gallery.md new file mode 100644 index 0000000000..ff3ae3d0e2 --- /dev/null +++ b/website/src/pages/gallery.md @@ -0,0 +1,126 @@ +--- +title: Gallery +slug: gallery +--- + +import Card from '@site/src/components/card'; + +export const GalleryCard = ({title, liveUrl, sourcesUrl, description, imageUrl}) => ( + + + +

    {title}

    +
    {description}
    +
    +
    + +
    +
    +); + +# Gallery + +
    +
    + + + + + + + + + + + + + + + + +
    +
    diff --git a/website/src/pages/index.js b/website/src/pages/index.js new file mode 100644 index 0000000000..3aa64a40e6 --- /dev/null +++ b/website/src/pages/index.js @@ -0,0 +1,160 @@ +import React from 'react'; +import clsx from 'clsx'; +import Layout from '@theme/Layout'; +import Link from '@docusaurus/Link'; +import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import useBaseUrl from '@docusaurus/useBaseUrl'; +import styles from './styles.module.css'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import SignupForm from '@site/src/components/signup-form' +import CodeBlock from '@theme/CodeBlock'; + +const features = [ + { + title: <>Single code base for any device, + imageUrl: 'img/pages/home/single-code-base.svg', + description: ( + <> + Your app will look equally great on iOS, Android, Windows, Linux, macOS and web. + + ), + }, + { + title: <>Build an entire app in Python, + imageUrl: 'img/pages/home/python.svg', + description: ( + <> + Build a cross-platform app without knowledge of Dart, Swift, Kotlin, HTML or JavaScript - only Python! + + ), + }, + { + title: <>150+ built-in controls and services, + imageUrl: 'img/pages/home/controls.svg', + description: ( + <> + Beautiful UI widgets with Material and Cupertino design: layout, navigation, dialogs, charts - Flet uses Flutter to render UI. + + ), + }, + { + title: <>50+ Python packages for iOS and Android, + imageUrl: 'img/pages/home/python-packages.svg', + description: ( + <> + Numpy, pandas, pydantic, cryptography, opencv, pillow and other popular libraries. + + ), + }, + { + title: <>Full web support, + imageUrl: 'img/pages/home/web-support.svg', + description: ( + <> + Flet apps run natively in modern browsers using WebAssembly and Pyodide, with no server required. Prefer server-side? Deploy as a Python web app with real-time UI updates. + + ), + }, + { + title: <>Built-in packaging, + imageUrl: 'img/pages/home/packaging.svg', + description: ( + <> + Build standalone executables or bundles for iOS, Android, Windows, Linux, macOS and web. Instantly deploy to App Store and Google Play. + + ), + }, + { + title: <>Test on iOS and Android, + imageUrl: 'img/pages/home/test-on-ios-android.svg', + description: ( + <> + Test your project on your own mobile device with Flet App. See your app updates as you make changes. + + ), + }, + { + title: <>Extensible, + imageUrl: 'img/pages/home/extensible.svg', + description: ( + <> + Easily wrap any of thousands of Flutter packages to use with Flet or build new controls in pure Python using built-in UI primitives. + + ), + }, + { + title: <>Accessible, + imageUrl: 'img/pages/home/accessible.svg', + description: ( + <> + Flet is built with Flutter which has solid accessibility foundations on Android, iOS, web, and desktop. + + ), + }, +]; + +function Feature({ imageUrl, title, description }) { + const imgUrl = useBaseUrl(imageUrl); + return ( +
    + {imgUrl && ( +
    + {title} +
    + )} +

    {title}

    +

    {description}

    +
    + ); +} + +function Home() { + const context = useDocusaurusContext(); + const { siteConfig = {} } = context; + return ( + +
    +
    +
    +
    +
    + +
    +
    +

    {siteConfig.customFields.heroTitle}

    +

    {siteConfig.customFields.heroSubTitle}

    +
    + + Get Started + +
    +
    +
    +
    +
    +
    +

    Flet awesome features

    + {features && features.length > 0 && ( +
    +
    +
    + {features.map((props, idx) => ( + + ))} +
    +
    +
    + )} +
    + +
    +
    + ); +} + +export default Home; diff --git a/website/src/pages/privacy-policy.md b/website/src/pages/privacy-policy.md new file mode 100644 index 0000000000..085998c772 --- /dev/null +++ b/website/src/pages/privacy-policy.md @@ -0,0 +1,146 @@ +--- +title: Flet Privacy Policy +hide_table_of_contents: true +--- + +# Privacy Policy + + \ No newline at end of file diff --git a/website/src/pages/roadmap.md b/website/src/pages/roadmap.md new file mode 100644 index 0000000000..8c196e108f --- /dev/null +++ b/website/src/pages/roadmap.md @@ -0,0 +1,36 @@ +--- +title: Roadmap +slug: roadmap +--- + +# Roadmap + +## 2026 + +### Flet 1.0 + +* **Long-term maintainability:** Controls are implemented using Python **dataclasses**, while the Flutter client adopts the built-in state management approach, eliminating the need for Redux. Ensures symmetric data structures in Python and Dart. +* **Enhanced Developer Experience (DX):** Control documentation is generated directly from source code, preventing discrepancies between docs, comments, and examples. Provides accurate IDE assistance. +* **Optimized Communication:** A binary protocol between Python and Dart eliminates unnecessary base64-to-bytes conversions, reducing CPU overhead and improving memory efficiency. + +### Website + +* **Ecosystem:** Community gallery for apps, extensions and educational materials (videos, tutorials, talks, etc.). +* FletPad for playground and sharing Flet apps. + +### Testing + +* End-to-end UI tests for Flet apps. +* Test suite for binary Python packages. + +### AI + +* MCP server for Flet. + +### Community + +* Attending [PyCon US 2026](https://us.pycon.org/2026/). + +### Packaging + +* Flet Packaging and Publishing Service (FPS). \ No newline at end of file diff --git a/website/src/pages/styles.module.css b/website/src/pages/styles.module.css new file mode 100644 index 0000000000..0d28266029 --- /dev/null +++ b/website/src/pages/styles.module.css @@ -0,0 +1,110 @@ +/* stylelint-disable docusaurus/copyright-header */ + +/** + * CSS files with the .module.css suffix will be treated as CSS modules + * and scoped locally. + */ + + .heroBanner { + padding: 0; + /* background: url('/img/hero_back_light.svg') right 60px/115% auto no-repeat; */ + /* text-align: center; */ +} + +.codeSample { + width: 100%; + margin: 2rem auto; +} + +/* html[data-theme='dark'] .heroBanner { + background-image: url('/img/hero_back_dark.svg'); +} + +html[data-theme='dark'] .bkg { + background-image: url('/img/hero_flet_dark.svg'); +} */ + +.right { + padding: 3rem 5rem 0 0; +} + +@media screen and (max-width: 768px) { + .heroBanner { + /* padding: 1rem; */ + text-align: center; + } + + .heroBanner .hero__title { + font-size: 2rem; + text-align: center; + } +} + +.buttons { + display: flex; + align-items: flex-start; + justify-content: center; + margin-top: 2rem; +} + +.features { + display: flex; + align-items: center; + padding: 2rem 0; + width: 100%; +} + +.featuresSection h2 { + font-size: 2.2rem; + font-weight: 500; + color: #333; +} + +.feature h3 { + font-size: 1.5rem; + font-weight: 500; + text-align: center; + margin: 1rem 0; + color: #333; +} + +html[data-theme='dark'] .featuresSection h2 { + color: #e6e6e6; +} + +html[data-theme='dark'] .feature h3 { + color: #e6e6e6; +} + +html[data-theme='dark'] .feature p { + color: #a7a7a7; +} + +.feature p { + text-align: center; + color: #555; +} + +.featureImage { + height: 50px; + width: 50px; +} + +.indexCtasGetStartedButton { + background-color: #f81d5b; + display: inline-block; + line-height: 1.2em; + text-decoration: none !important; + transition: background 0.6s; + border-radius: 8px; + border-width: 2px; + color: #fff; + font-size: 22px; + font-weight: 500; + padding: 14px 25px; +} + +.indexCtasGetStartedButton:hover { + color: #fff; + background-color: #db0f49; +} \ No newline at end of file diff --git a/website/src/pages/support.md b/website/src/pages/support.md new file mode 100644 index 0000000000..a317c01c17 --- /dev/null +++ b/website/src/pages/support.md @@ -0,0 +1,30 @@ +--- +title: Support +hide_table_of_contents: true +--- + +# Support + +## Documentation + +Browse [Flet docs](https://flet.dev/docs/). + +## Discord + +Meet Flet community on [Flet Discord server](https://discord.gg/dzWXP8SHG8). + +## GitHub issues + +Submit an issue or feature request at [Flet project issues](https://github.com/flet-dev/flet/issues). + +## GitHub discussions + +Start a new discussion at [Flet project discussions](https://github.com/flet-dev/flet/discussions). + +## StackOverflow + +Ask your question or search for solution on [StackOverflow](https://stackoverflow.com/questions/tagged/flet). + +## Email + +Contact us by email: hello@flet.dev diff --git a/website/src/theme/DocCard/index.js b/website/src/theme/DocCard/index.js new file mode 100644 index 0000000000..f296bec92d --- /dev/null +++ b/website/src/theme/DocCard/index.js @@ -0,0 +1,100 @@ +import React from "react"; +import clsx from "clsx"; +import Link from "@docusaurus/Link"; +import { + useDocById, + findFirstSidebarItemLink, +} from "@docusaurus/plugin-content-docs/client"; +import { usePluralForm } from "@docusaurus/theme-common"; +import isInternalUrl from "@docusaurus/isInternalUrl"; +import { translate } from "@docusaurus/Translate"; +import Heading from "@theme/Heading"; +import styles from "./styles.module.css"; + +function useCategoryItemsPlural() { + const { selectMessage } = usePluralForm(); + return (count) => + selectMessage( + count, + translate( + { + message: "1 item|{count} items", + id: "theme.docs.DocCard.categoryDescription.plurals", + }, + { count } + ) + ); +} + +function CardContainer({ href, children, className }) { + return ( + + {children} + + ); +} + +function CardLayout({ href, title, description, className }) { + return ( + + + {title} + + {description && ( +

    + {description} +

    + )} +
    + ); +} + +function CardCategory({ item }) { + const href = findFirstSidebarItemLink(item); + const categoryItemsPlural = useCategoryItemsPlural(); + if (!href) { + return null; + } + return ( + + ); +} + +function CardLink({ item }) { + const icon = isInternalUrl(item.href) ? "" : "🔗 "; + const doc = useDocById(item.docId ?? undefined); + return ( + + ); +} + +export default function DocCard({ item }) { + switch (item.type) { + case "link": + return ; + case "category": + return ; + default: + throw new Error(`unknown item type ${JSON.stringify(item)}`); + } +} diff --git a/website/src/theme/DocCard/styles.module.css b/website/src/theme/DocCard/styles.module.css new file mode 100644 index 0000000000..4f7ad27f40 --- /dev/null +++ b/website/src/theme/DocCard/styles.module.css @@ -0,0 +1,27 @@ +.cardContainer { + --ifm-link-color: var(--ifm-color-emphasis-800); + --ifm-link-hover-color: var(--ifm-color-emphasis-700); + --ifm-link-hover-decoration: none; + + box-shadow: 0 1.5px 3px 0 rgb(0 0 0 / 15%); + border: 1px solid var(--ifm-color-emphasis-200); + transition: all var(--ifm-transition-fast) ease; + transition-property: border, box-shadow; +} + +.cardContainer:hover { + border-color: var(--ifm-color-primary); + box-shadow: 0 3px 6px 0 rgb(0 0 0 / 20%); +} + +.cardContainer *:last-child { + margin-bottom: 0; +} + +.cardTitle { + font-size: 1.2rem; +} + +.cardDescription { + font-size: 0.8rem; +} diff --git a/website/src/theme/DocItem/Layout/index.js b/website/src/theme/DocItem/Layout/index.js new file mode 100644 index 0000000000..bf85f639d3 --- /dev/null +++ b/website/src/theme/DocItem/Layout/index.js @@ -0,0 +1,119 @@ +import React, {useEffect} from "react"; +import clsx from "clsx"; +import {ThemeClassNames, useWindowSize} from "@docusaurus/theme-common"; +import {useDoc} from "@docusaurus/plugin-content-docs/client"; +import {useLocation} from "@docusaurus/router"; +import DocItemPaginator from "@theme/DocItem/Paginator"; +import DocVersionBanner from "@theme/DocVersionBanner"; +import DocVersionBadge from "@theme/DocVersionBadge"; +import DocItemFooter from "@theme/DocItem/Footer"; +import DocItemTOCMobile from "@theme/DocItem/TOC/Mobile"; +import DocItemTOCDesktop from "@theme/DocItem/TOC/Desktop"; +import DocItemContent from "@theme/DocItem/Content"; +import DocBreadcrumbs from "@theme/DocBreadcrumbs"; +import ContentVisibility from "@theme/ContentVisibility"; +import docManifest from "@site/.crocodocs/docs-manifest.json"; + +import styles from "./styles.module.css"; + +function hasCrocoDocsSymbols(metadata) { + if (!metadata?.permalink) { + return false; + } + const page = docManifest.pages.find((entry) => entry.route === metadata.permalink); + return Boolean(page?.symbol_blocks?.length); +} + +function CrocoDocsTOCDesktopPlaceholder() { + return ( +
    +
      +
    + ); +} + +function useDocTOC() { + const {frontMatter, metadata, toc} = useDoc(); + const windowSize = useWindowSize(); + const hidden = frontMatter.hide_table_of_contents; + const hasStaticTOC = toc.length > 0; + const hasCrocoDocsTOC = hasCrocoDocsSymbols(metadata); + const canRender = !hidden && (hasStaticTOC || hasCrocoDocsTOC); + + const mobile = hasStaticTOC && canRender ? : undefined; + const desktop = + canRender && (windowSize === "desktop" || windowSize === "ssr") ? ( + hasStaticTOC ? ( + + ) : ( + + ) + ) : undefined; + + return { + hidden, + mobile, + desktop, + }; +} + +function useHashAnchorScroll() { + const location = useLocation(); + + useEffect(() => { + if (!location.hash) { + return undefined; + } + + const targetId = decodeURIComponent(location.hash.slice(1)); + let frameId = null; + let attempts = 0; + + const scrollToAnchor = () => { + const element = document.getElementById(targetId); + if (element) { + element.scrollIntoView(); + return; + } + if (attempts >= 30) { + return; + } + attempts += 1; + frameId = window.requestAnimationFrame(scrollToAnchor); + }; + + frameId = window.requestAnimationFrame(scrollToAnchor); + + return () => { + if (frameId != null) { + window.cancelAnimationFrame(frameId); + } + }; + }, [location.pathname, location.hash]); +} + +export default function DocItemLayout({children}) { + const docTOC = useDocTOC(); + const {metadata} = useDoc(); + useHashAnchorScroll(); + + return ( +
    +
    + + +
    +
    + + + {docTOC.mobile} + {children} + +
    + +
    +
    + {docTOC.desktop ?
    {docTOC.desktop}
    : null} +
    + ); +} diff --git a/website/src/theme/DocItem/Layout/styles.module.css b/website/src/theme/DocItem/Layout/styles.module.css new file mode 100644 index 0000000000..784498f2e1 --- /dev/null +++ b/website/src/theme/DocItem/Layout/styles.module.css @@ -0,0 +1,17 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.docItemContainer header + *, +.docItemContainer article > *:first-child { + margin-top: 0; +} + +@media (min-width: 997px) { + .docItemCol { + max-width: 75% !important; + } +} diff --git a/website/src/theme/MDXComponents.js b/website/src/theme/MDXComponents.js new file mode 100644 index 0000000000..9f0aa3792e --- /dev/null +++ b/website/src/theme/MDXComponents.js @@ -0,0 +1,7 @@ +import MDXComponents from "@theme-original/MDXComponents"; +import AnnotatedCodeBlock from "@site/src/components/AnnotatedCodeBlock"; + +export default { + ...MDXComponents, + AnnotatedCodeBlock, +}; diff --git a/website/src/theme/prism-include-languages.js b/website/src/theme/prism-include-languages.js new file mode 100644 index 0000000000..67ff7f7b35 --- /dev/null +++ b/website/src/theme/prism-include-languages.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; +import siteConfig from '@generated/docusaurus.config'; + +const prismIncludeLanguages = (PrismObject) => { + if (ExecutionEnvironment.canUseDOM) { + const { + themeConfig: {prism: {additionalLanguages = []} = {}}, + } = siteConfig; + window.Prism = PrismObject; + additionalLanguages.forEach((lang) => { + require(`prismjs/components/prism-${lang}`); // eslint-disable-line + }); + require('prismjs/components/prism-powershell'); + delete window.Prism; + } +}; + +export default prismIncludeLanguages; diff --git a/website/static/_redirects b/website/static/_redirects new file mode 100644 index 0000000000..0629d03a75 --- /dev/null +++ b/website/static/_redirects @@ -0,0 +1 @@ +# nope diff --git a/website/static/assets/extensions/example-pink.png b/website/static/assets/extensions/example-pink.png new file mode 100644 index 0000000000..96954f2110 Binary files /dev/null and b/website/static/assets/extensions/example-pink.png differ diff --git a/website/static/assets/extensions/example.png b/website/static/assets/extensions/example.png new file mode 100644 index 0000000000..8ff8362899 Binary files /dev/null and b/website/static/assets/extensions/example.png differ diff --git a/website/static/assets/extensions/mkdocs.png b/website/static/assets/extensions/mkdocs.png new file mode 100644 index 0000000000..e7a6bcfd54 Binary files /dev/null and b/website/static/assets/extensions/mkdocs.png differ diff --git a/website/static/assets/extensions/spinkit1.gif b/website/static/assets/extensions/spinkit1.gif new file mode 100644 index 0000000000..d94138fa2c Binary files /dev/null and b/website/static/assets/extensions/spinkit1.gif differ diff --git a/website/static/assets/extensions/spinkit2.gif b/website/static/assets/extensions/spinkit2.gif new file mode 100644 index 0000000000..ebfb3f65e2 Binary files /dev/null and b/website/static/assets/extensions/spinkit2.gif differ diff --git a/website/static/assets/extensions/spinkit3.gif b/website/static/assets/extensions/spinkit3.gif new file mode 100644 index 0000000000..aef62c777b Binary files /dev/null and b/website/static/assets/extensions/spinkit3.gif differ diff --git a/website/static/assets/extensions/unknown-control.png b/website/static/assets/extensions/unknown-control.png new file mode 100644 index 0000000000..0e2309f491 Binary files /dev/null and b/website/static/assets/extensions/unknown-control.png differ diff --git a/website/static/docs/assets/badges/docs-coverage/.gitignore b/website/static/docs/assets/badges/docs-coverage/.gitignore new file mode 100644 index 0000000000..756b22fa2d --- /dev/null +++ b/website/static/docs/assets/badges/docs-coverage/.gitignore @@ -0,0 +1 @@ +*.svg diff --git a/website/static/docs/assets/badges/docs-coverage/placeholder.txt b/website/static/docs/assets/badges/docs-coverage/placeholder.txt new file mode 100644 index 0000000000..6d99603f94 --- /dev/null +++ b/website/static/docs/assets/badges/docs-coverage/placeholder.txt @@ -0,0 +1 @@ +This directory contains generated docs coverage badges. diff --git a/website/static/docs/assets/controls/alert-dialog/example-1.gif b/website/static/docs/assets/controls/alert-dialog/example-1.gif new file mode 100644 index 0000000000..796e5af5e6 Binary files /dev/null and b/website/static/docs/assets/controls/alert-dialog/example-1.gif differ diff --git a/website/static/docs/assets/controls/animated-switcher/example-1.gif b/website/static/docs/assets/controls/animated-switcher/example-1.gif new file mode 100644 index 0000000000..70010844ea Binary files /dev/null and b/website/static/docs/assets/controls/animated-switcher/example-1.gif differ diff --git a/website/static/docs/assets/controls/app-bar/example-1.gif b/website/static/docs/assets/controls/app-bar/example-1.gif new file mode 100644 index 0000000000..3ce841fc91 Binary files /dev/null and b/website/static/docs/assets/controls/app-bar/example-1.gif differ diff --git a/website/static/docs/assets/controls/charts/bar-chart-diagram.svg b/website/static/docs/assets/controls/charts/bar-chart-diagram.svg new file mode 100644 index 0000000000..36c9fa4e73 --- /dev/null +++ b/website/static/docs/assets/controls/charts/bar-chart-diagram.svg @@ -0,0 +1,614 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + Left Axis +
    +
    +
    +
    + + Left Axis + +
    +
    + + + + + +
    +
    +
    + Top Axis +
    +
    +
    +
    + + Top Axis + +
    +
    + + + + + +
    +
    +
    + Right Axis +
    +
    +
    +
    + + Right Axis + +
    +
    + + + +
    +
    +
    + Bottom Axis +
    +
    +
    +
    + + Bottom Axis + +
    +
    + + + + + + +
    +
    +
    + Labels +
    +
    +
    +
    + + Labels + +
    +
    + + + + + + +
    +
    +
    + Title +
    +
    +
    +
    + + Title + +
    +
    + + + + + + + + + +
    +
    +
    + 10 +
    +
    +
    +
    + + 10 + +
    +
    + + + +
    +
    +
    + 20 +
    +
    +
    +
    + + 20 + +
    +
    + + + +
    +
    +
    + 30 +
    +
    +
    +
    + 30 + +
    +
    + + + +
    +
    +
    + Left Axis Title +
    +
    +
    +
    + Left Axis Title + +
    +
    + + + +
    +
    +
    + Group A +
    +
    +
    +
    + Group + A + +
    +
    + + + +
    +
    +
    + 0 +
    +
    +
    +
    + 0 + +
    +
    + + + +
    +
    +
    + Group B +
    +
    +
    +
    + Group + B + +
    +
    + + + +
    +
    +
    + Group C +
    +
    +
    +
    + Group + C + +
    +
    + + + +
    +
    +
    + Bottom Axis Title +
    +
    +
    +
    + Bottom Axis Title + +
    +
    + + + +
    +
    +
    + Border +
    +
    +
    +
    + + Border + +
    +
    + + + + + + + + +
    +
    +
    + Grid lines +
    +
    +
    +
    + Grid + lines + +
    +
    + + + +
    +
    +
    + Vertical +
    +
    +
    +
    + + Vertical + +
    +
    + + + +
    +
    +
    + Horizontal +
    +
    +
    +
    + + Horizontal + +
    +
    + + + + + + + + + +
    +
    +
    + BarChartGroup +
    +
    +
    +
    + + BarChartGr... + +
    +
    + + + + + + + + + +
    +
    +
    + BarChartRodStackItem +
    +
    +
    +
    + + BarChartRo... + +
    +
    + + + + + + + +
    +
    +
    + BarChartRod +
    +
    +
    +
    + + BarChartRod + +
    +
    + + + + + + + + + + + +
    +
    +
    + BarChartGroup +
    +
    +
    +
    + + BarChartGr... + +
    +
    + + + + + +
    +
    +
    + group_vertically +
    +
    +
    +
    + + group_vertically + +
    +
    + + + +
    +
    +
    + Text +
    +
    +
    +
    + + Text + +
    +
    +
    + + + + Text is not SVG - cannot display + + +
    diff --git a/website/static/docs/assets/controls/charts/line-chart-diagram.svg b/website/static/docs/assets/controls/charts/line-chart-diagram.svg new file mode 100644 index 0000000000..968087bcc9 --- /dev/null +++ b/website/static/docs/assets/controls/charts/line-chart-diagram.svg @@ -0,0 +1,609 @@ + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + Left Axis +
    +
    +
    +
    + + Left Axis + +
    +
    + + + + + +
    +
    +
    + Top Axis +
    +
    +
    +
    + + Top Axis + +
    +
    + + + + + +
    +
    +
    + Right Axis +
    +
    +
    +
    + + Right Axis + +
    +
    + + + +
    +
    +
    + Bottom Axis +
    +
    +
    +
    + + Bottom Axis + +
    +
    + + + + + + +
    +
    +
    + Labels +
    +
    +
    +
    + + Labels + +
    +
    + + + + + + +
    +
    +
    + Title +
    +
    +
    +
    + + Title + +
    +
    + + + + + + + + + +
    +
    +
    + Cold +
    +
    +
    +
    + + Cold + +
    +
    + + + +
    +
    +
    + Warm +
    +
    +
    +
    + + Warm + +
    +
    + + + +
    +
    +
    + Hot +
    +
    +
    +
    + Hot + +
    +
    + + + +
    +
    +
    + Temp +
    +
    +
    +
    + Temp + +
    +
    + + + +
    +
    +
    + 1 +
    +
    +
    +
    + 1 + +
    +
    + + + +
    +
    +
    + 0 +
    +
    +
    +
    + 0 + +
    +
    + + + +
    +
    +
    + 2 +
    +
    +
    +
    + 2 + +
    +
    + + + +
    +
    +
    + 3 +
    +
    +
    +
    + 3 + +
    +
    + + + +
    +
    +
    + 4 +
    +
    +
    +
    + 4 + +
    +
    + + + +
    +
    +
    + Time +
    +
    +
    +
    + Time + +
    +
    + + + +
    +
    +
    + Border +
    +
    +
    +
    + + Border + +
    +
    + + + + + + + + + + +
    +
    +
    + Points +
    +
    +
    +
    + + Points + +
    +
    + + + + + + + + + + + + + + +
    +
    +
    + Grid lines +
    +
    +
    +
    + Grid + lines + +
    +
    + + + +
    +
    +
    + Vertical +
    +
    +
    +
    + + Vertical + +
    +
    + + + + +
    +
    +
    + Horizontal +
    +
    +
    +
    + + Horizontal + +
    +
    + + + + + + + +
    +
    +
    + Data series (LineChartData) +
    +
    +
    +
    + Data + series (LineChartData) + +
    +
    + + + + + + + +
    +
    +
    + curved +
    +
    +
    +
    + curved + +
    +
    + + + +
    +
    +
    + below line +
    +
    +
    +
    + below + line + +
    +
    + + + +
    +
    +
    + above line +
    +
    +
    +
    + above + line + +
    +
    +
    + + + + Text is not SVG - cannot display + + +
    diff --git a/website/static/docs/assets/controls/charts/pie-chart-diagram.svg b/website/static/docs/assets/controls/charts/pie-chart-diagram.svg new file mode 100644 index 0000000000..648302f6f4 --- /dev/null +++ b/website/static/docs/assets/controls/charts/pie-chart-diagram.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + Badge +
    +
    +
    +
    + Badge + +
    +
    + + + + + + +
    +
    +
    + PieChartSection +
    +
    +
    +
    + + PieChartSe... + +
    +
    + + + + + + + + +
    +
    +
    + Center space +
    +
    +
    +
    + + Center spa... + +
    +
    + + + + + + + + + +
    +
    +
    + Radius +
    +
    +
    +
    + + Radius + +
    +
    + + +
    + + + + Text is not SVG - cannot display + + +
    diff --git a/website/static/docs/assets/controls/control/expand-loose.png b/website/static/docs/assets/controls/control/expand-loose.png new file mode 100644 index 0000000000..2ba8f4e7ac Binary files /dev/null and b/website/static/docs/assets/controls/control/expand-loose.png differ diff --git a/website/static/docs/assets/controls/cupertino-action-sheet/example-1.png b/website/static/docs/assets/controls/cupertino-action-sheet/example-1.png new file mode 100644 index 0000000000..6288de3f4b Binary files /dev/null and b/website/static/docs/assets/controls/cupertino-action-sheet/example-1.png differ diff --git a/website/static/docs/assets/cookbook/accessibility/debug-accessibility-toggle.gif b/website/static/docs/assets/cookbook/accessibility/debug-accessibility-toggle.gif new file mode 100644 index 0000000000..e16c5e753b Binary files /dev/null and b/website/static/docs/assets/cookbook/accessibility/debug-accessibility-toggle.gif differ diff --git a/website/static/docs/assets/cookbook/adaptive-apps/android.png b/website/static/docs/assets/cookbook/adaptive-apps/android.png new file mode 100644 index 0000000000..ec00ed1b8d Binary files /dev/null and b/website/static/docs/assets/cookbook/adaptive-apps/android.png differ diff --git a/website/static/docs/assets/cookbook/adaptive-apps/iphone.png b/website/static/docs/assets/cookbook/adaptive-apps/iphone.png new file mode 100644 index 0000000000..92063d4ef0 Binary files /dev/null and b/website/static/docs/assets/cookbook/adaptive-apps/iphone.png differ diff --git a/website/static/docs/assets/cookbook/animations/animate-container.gif b/website/static/docs/assets/cookbook/animations/animate-container.gif new file mode 100644 index 0000000000..a47044f89b Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animate-container.gif differ diff --git a/website/static/docs/assets/cookbook/animations/animate-offset.gif b/website/static/docs/assets/cookbook/animations/animate-offset.gif new file mode 100644 index 0000000000..f3e4262ff0 Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animate-offset.gif differ diff --git a/website/static/docs/assets/cookbook/animations/animate-opacity.gif b/website/static/docs/assets/cookbook/animations/animate-opacity.gif new file mode 100644 index 0000000000..8bc32fa324 Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animate-opacity.gif differ diff --git a/website/static/docs/assets/cookbook/animations/animate-position.gif b/website/static/docs/assets/cookbook/animations/animate-position.gif new file mode 100644 index 0000000000..7ebe705ebc Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animate-position.gif differ diff --git a/website/static/docs/assets/cookbook/animations/animate-rotation.gif b/website/static/docs/assets/cookbook/animations/animate-rotation.gif new file mode 100644 index 0000000000..1290682bb1 Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animate-rotation.gif differ diff --git a/website/static/docs/assets/cookbook/animations/animate-scale.gif b/website/static/docs/assets/cookbook/animations/animate-scale.gif new file mode 100644 index 0000000000..58dce9b043 Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animate-scale.gif differ diff --git a/website/static/docs/assets/cookbook/animations/animated-switcher.gif b/website/static/docs/assets/cookbook/animations/animated-switcher.gif new file mode 100644 index 0000000000..f9429bebdb Binary files /dev/null and b/website/static/docs/assets/cookbook/animations/animated-switcher.gif differ diff --git a/website/static/docs/assets/cookbook/async-apps/async-countdown.gif b/website/static/docs/assets/cookbook/async-apps/async-countdown.gif new file mode 100644 index 0000000000..adad0a8caa Binary files /dev/null and b/website/static/docs/assets/cookbook/async-apps/async-countdown.gif differ diff --git a/website/static/docs/assets/cookbook/authentication/github-new-oauth-app.png b/website/static/docs/assets/cookbook/authentication/github-new-oauth-app.png new file mode 100644 index 0000000000..0fb914727f Binary files /dev/null and b/website/static/docs/assets/cookbook/authentication/github-new-oauth-app.png differ diff --git a/website/static/docs/assets/cookbook/authentication/github-oauth-app-details.png b/website/static/docs/assets/cookbook/authentication/github-oauth-app-details.png new file mode 100644 index 0000000000..8d963f7f60 Binary files /dev/null and b/website/static/docs/assets/cookbook/authentication/github-oauth-app-details.png differ diff --git a/website/static/docs/assets/cookbook/authentication/github-oauth-authorize.png b/website/static/docs/assets/cookbook/authentication/github-oauth-authorize.png new file mode 100644 index 0000000000..5fecaf1c29 Binary files /dev/null and b/website/static/docs/assets/cookbook/authentication/github-oauth-authorize.png differ diff --git a/website/static/docs/assets/cookbook/custom-controls/composite-controls.gif b/website/static/docs/assets/cookbook/custom-controls/composite-controls.gif new file mode 100644 index 0000000000..a7f9f757e7 Binary files /dev/null and b/website/static/docs/assets/cookbook/custom-controls/composite-controls.gif differ diff --git a/website/static/docs/assets/cookbook/custom-controls/styled-controls.png b/website/static/docs/assets/cookbook/custom-controls/styled-controls.png new file mode 100644 index 0000000000..4b09407199 Binary files /dev/null and b/website/static/docs/assets/cookbook/custom-controls/styled-controls.png differ diff --git a/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud-declarative.drawio b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud-declarative.drawio new file mode 100644 index 0000000000..aab1bfba85 --- /dev/null +++ b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud-declarative.drawio @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud-declarative.drawio.png b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud-declarative.drawio.png new file mode 100644 index 0000000000..1ee82e67a9 Binary files /dev/null and b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud-declarative.drawio.png differ diff --git a/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud1.png b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud1.png new file mode 100644 index 0000000000..fa4656dbe7 Binary files /dev/null and b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud1.png differ diff --git a/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud2.png b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud2.png new file mode 100644 index 0000000000..0c5af9a28f Binary files /dev/null and b/website/static/docs/assets/cookbook/declarative-vs-imperative-crud-app/crud2.png differ diff --git a/website/static/docs/assets/cookbook/drag-and-drop/image-1.gif b/website/static/docs/assets/cookbook/drag-and-drop/image-1.gif new file mode 100644 index 0000000000..0a472dbc55 Binary files /dev/null and b/website/static/docs/assets/cookbook/drag-and-drop/image-1.gif differ diff --git a/website/static/docs/assets/cookbook/drag-and-drop/image-2.gif b/website/static/docs/assets/cookbook/drag-and-drop/image-2.gif new file mode 100644 index 0000000000..0f93fb6378 Binary files /dev/null and b/website/static/docs/assets/cookbook/drag-and-drop/image-2.gif differ diff --git a/website/static/docs/assets/cookbook/drag-and-drop/image-3.gif b/website/static/docs/assets/cookbook/drag-and-drop/image-3.gif new file mode 100644 index 0000000000..577477fc47 Binary files /dev/null and b/website/static/docs/assets/cookbook/drag-and-drop/image-3.gif differ diff --git a/website/static/docs/assets/cookbook/keyboard/shortcuts.png b/website/static/docs/assets/cookbook/keyboard/shortcuts.png new file mode 100644 index 0000000000..d6015c9c82 Binary files /dev/null and b/website/static/docs/assets/cookbook/keyboard/shortcuts.png differ diff --git a/website/static/docs/assets/cookbook/large-lists/grid-view.png b/website/static/docs/assets/cookbook/large-lists/grid-view.png new file mode 100644 index 0000000000..e73a3118ef Binary files /dev/null and b/website/static/docs/assets/cookbook/large-lists/grid-view.png differ diff --git a/website/static/docs/assets/cookbook/large-lists/row-wrap-as-grid.png b/website/static/docs/assets/cookbook/large-lists/row-wrap-as-grid.png new file mode 100644 index 0000000000..cd9aefdbda Binary files /dev/null and b/website/static/docs/assets/cookbook/large-lists/row-wrap-as-grid.png differ diff --git a/website/static/docs/assets/cookbook/large-lists/scroll-column.gif b/website/static/docs/assets/cookbook/large-lists/scroll-column.gif new file mode 100644 index 0000000000..e388831eac Binary files /dev/null and b/website/static/docs/assets/cookbook/large-lists/scroll-column.gif differ diff --git a/website/static/docs/assets/cookbook/large-lists/scroll-listview.gif b/website/static/docs/assets/cookbook/large-lists/scroll-listview.gif new file mode 100644 index 0000000000..f79894c198 Binary files /dev/null and b/website/static/docs/assets/cookbook/large-lists/scroll-listview.gif differ diff --git a/website/static/docs/assets/cookbook/large-lists/sending-page-updates-in-batches.png b/website/static/docs/assets/cookbook/large-lists/sending-page-updates-in-batches.png new file mode 100644 index 0000000000..6d29e67bd2 Binary files /dev/null and b/website/static/docs/assets/cookbook/large-lists/sending-page-updates-in-batches.png differ diff --git a/website/static/docs/assets/cookbook/pub-sub/chat-app.gif b/website/static/docs/assets/cookbook/pub-sub/chat-app.gif new file mode 100644 index 0000000000..b483ae89b1 Binary files /dev/null and b/website/static/docs/assets/cookbook/pub-sub/chat-app.gif differ diff --git a/website/static/docs/assets/cookbook/theming/material-theme-builder.png b/website/static/docs/assets/cookbook/theming/material-theme-builder.png new file mode 100644 index 0000000000..64d3cec4f1 Binary files /dev/null and b/website/static/docs/assets/cookbook/theming/material-theme-builder.png differ diff --git a/website/static/docs/assets/cookbook/theming/nested-themes.png b/website/static/docs/assets/cookbook/theming/nested-themes.png new file mode 100644 index 0000000000..744a21ed08 Binary files /dev/null and b/website/static/docs/assets/cookbook/theming/nested-themes.png differ diff --git a/website/static/docs/assets/cookbook/theming/tabs-theme.png b/website/static/docs/assets/cookbook/theming/tabs-theme.png new file mode 100644 index 0000000000..cad87a67d8 Binary files /dev/null and b/website/static/docs/assets/cookbook/theming/tabs-theme.png differ diff --git a/website/static/docs/assets/cookbook/theming/text-theme.png b/website/static/docs/assets/cookbook/theming/text-theme.png new file mode 100644 index 0000000000..4dd8dd82a1 Binary files /dev/null and b/website/static/docs/assets/cookbook/theming/text-theme.png differ diff --git a/website/static/docs/assets/extensions/example-pink.png b/website/static/docs/assets/extensions/example-pink.png new file mode 100644 index 0000000000..96954f2110 Binary files /dev/null and b/website/static/docs/assets/extensions/example-pink.png differ diff --git a/website/static/docs/assets/extensions/example.png b/website/static/docs/assets/extensions/example.png new file mode 100644 index 0000000000..8ff8362899 Binary files /dev/null and b/website/static/docs/assets/extensions/example.png differ diff --git a/website/static/docs/assets/extensions/mkdocs.png b/website/static/docs/assets/extensions/mkdocs.png new file mode 100644 index 0000000000..e7a6bcfd54 Binary files /dev/null and b/website/static/docs/assets/extensions/mkdocs.png differ diff --git a/website/static/docs/assets/extensions/spinkit1.gif b/website/static/docs/assets/extensions/spinkit1.gif new file mode 100644 index 0000000000..d94138fa2c Binary files /dev/null and b/website/static/docs/assets/extensions/spinkit1.gif differ diff --git a/website/static/docs/assets/extensions/spinkit2.gif b/website/static/docs/assets/extensions/spinkit2.gif new file mode 100644 index 0000000000..ebfb3f65e2 Binary files /dev/null and b/website/static/docs/assets/extensions/spinkit2.gif differ diff --git a/website/static/docs/assets/extensions/spinkit3.gif b/website/static/docs/assets/extensions/spinkit3.gif new file mode 100644 index 0000000000..aef62c777b Binary files /dev/null and b/website/static/docs/assets/extensions/spinkit3.gif differ diff --git a/website/static/docs/assets/extensions/unknown-control.png b/website/static/docs/assets/extensions/unknown-control.png new file mode 100644 index 0000000000..0e2309f491 Binary files /dev/null and b/website/static/docs/assets/extensions/unknown-control.png differ diff --git a/website/static/docs/assets/getting-started/counter-app/macos.png b/website/static/docs/assets/getting-started/counter-app/macos.png new file mode 100644 index 0000000000..84749744e5 Binary files /dev/null and b/website/static/docs/assets/getting-started/counter-app/macos.png differ diff --git a/website/static/docs/assets/getting-started/counter-app/safari.png b/website/static/docs/assets/getting-started/counter-app/safari.png new file mode 100644 index 0000000000..9ca3a44e5b Binary files /dev/null and b/website/static/docs/assets/getting-started/counter-app/safari.png differ diff --git a/website/static/docs/assets/getting-started/counter-app/windows.png b/website/static/docs/assets/getting-started/counter-app/windows.png new file mode 100644 index 0000000000..8b7911850e Binary files /dev/null and b/website/static/docs/assets/getting-started/counter-app/windows.png differ diff --git a/website/static/docs/assets/getting-started/package-desktop/flet-app-bundle-about-clean.png b/website/static/docs/assets/getting-started/package-desktop/flet-app-bundle-about-clean.png new file mode 100644 index 0000000000..4db9936b8d Binary files /dev/null and b/website/static/docs/assets/getting-started/package-desktop/flet-app-bundle-about-clean.png differ diff --git a/website/static/docs/assets/getting-started/package-desktop/flet-app-bundle-about.png b/website/static/docs/assets/getting-started/package-desktop/flet-app-bundle-about.png new file mode 100644 index 0000000000..03771a72cd Binary files /dev/null and b/website/static/docs/assets/getting-started/package-desktop/flet-app-bundle-about.png differ diff --git a/website/static/docs/assets/getting-started/package-desktop/macos-dock.png b/website/static/docs/assets/getting-started/package-desktop/macos-dock.png new file mode 100644 index 0000000000..abbfe98408 Binary files /dev/null and b/website/static/docs/assets/getting-started/package-desktop/macos-dock.png differ diff --git a/website/static/docs/assets/getting-started/testing-on-mobile/android/app-qr-code.png b/website/static/docs/assets/getting-started/testing-on-mobile/android/app-qr-code.png new file mode 100644 index 0000000000..f713821bda Binary files /dev/null and b/website/static/docs/assets/getting-started/testing-on-mobile/android/app-qr-code.png differ diff --git a/website/static/docs/assets/getting-started/testing-on-mobile/android/google-play-badge.png b/website/static/docs/assets/getting-started/testing-on-mobile/android/google-play-badge.png new file mode 100644 index 0000000000..131f3acaa2 Binary files /dev/null and b/website/static/docs/assets/getting-started/testing-on-mobile/android/google-play-badge.png differ diff --git a/website/static/docs/assets/getting-started/testing-on-mobile/ios/app-qr-code.png b/website/static/docs/assets/getting-started/testing-on-mobile/ios/app-qr-code.png new file mode 100644 index 0000000000..c741339e4a Binary files /dev/null and b/website/static/docs/assets/getting-started/testing-on-mobile/ios/app-qr-code.png differ diff --git a/website/static/docs/assets/getting-started/testing-on-mobile/ios/flet-local-network.png b/website/static/docs/assets/getting-started/testing-on-mobile/ios/flet-local-network.png new file mode 100644 index 0000000000..7019c1cc9d Binary files /dev/null and b/website/static/docs/assets/getting-started/testing-on-mobile/ios/flet-local-network.png differ diff --git a/website/static/docs/assets/getting-started/testing-on-mobile/ios/qr-code.jpg b/website/static/docs/assets/getting-started/testing-on-mobile/ios/qr-code.jpg new file mode 100644 index 0000000000..bced0a730e Binary files /dev/null and b/website/static/docs/assets/getting-started/testing-on-mobile/ios/qr-code.jpg differ diff --git a/website/static/docs/assets/navigation-routing/page-address-route.png b/website/static/docs/assets/navigation-routing/page-address-route.png new file mode 100644 index 0000000000..2de931159c Binary files /dev/null and b/website/static/docs/assets/navigation-routing/page-address-route.png differ diff --git a/website/static/docs/assets/navigation-routing/page-route-change-event.gif b/website/static/docs/assets/navigation-routing/page-route-change-event.gif new file mode 100644 index 0000000000..b0fbece5ce Binary files /dev/null and b/website/static/docs/assets/navigation-routing/page-route-change-event.gif differ diff --git a/website/static/docs/assets/navigation-routing/page-views.svg b/website/static/docs/assets/navigation-routing/page-views.svg new file mode 100644 index 0000000000..1c8acaf7d6 --- /dev/null +++ b/website/static/docs/assets/navigation-routing/page-views.svg @@ -0,0 +1,3 @@ + + +
    Page
    Page
    Page
    Page
    Page
    Page
    View
    View
    Top view is displayed
    Top view is displayed
    Root view
    cannot be popped
    Root view...
    Viewer does not support full SVG 1.1
    diff --git a/website/static/docs/assets/navigation-routing/pop-until-with-result-example.gif b/website/static/docs/assets/navigation-routing/pop-until-with-result-example.gif new file mode 100644 index 0000000000..753a9715ac Binary files /dev/null and b/website/static/docs/assets/navigation-routing/pop-until-with-result-example.gif differ diff --git a/website/static/docs/assets/navigation-routing/routing-app-example.gif b/website/static/docs/assets/navigation-routing/routing-app-example.gif new file mode 100644 index 0000000000..6572d31a51 Binary files /dev/null and b/website/static/docs/assets/navigation-routing/routing-app-example.gif differ diff --git a/website/static/img/blog/adaptive/android-adaptive-app.png b/website/static/img/blog/adaptive/android-adaptive-app.png new file mode 100644 index 0000000000..1c8ca1007d Binary files /dev/null and b/website/static/img/blog/adaptive/android-adaptive-app.png differ diff --git a/website/static/img/blog/adaptive/iphone-adaptive-app.png b/website/static/img/blog/adaptive/iphone-adaptive-app.png new file mode 100644 index 0000000000..41e35cedb3 Binary files /dev/null and b/website/static/img/blog/adaptive/iphone-adaptive-app.png differ diff --git a/website/static/img/blog/animations/flet-animation-demo.gif b/website/static/img/blog/animations/flet-animation-demo.gif new file mode 100644 index 0000000000..75ddd63b40 Binary files /dev/null and b/website/static/img/blog/animations/flet-animation-demo.gif differ diff --git a/website/static/img/blog/animations/flet-animation-demo.png b/website/static/img/blog/animations/flet-animation-demo.png new file mode 100644 index 0000000000..c3662dbb10 Binary files /dev/null and b/website/static/img/blog/animations/flet-animation-demo.png differ diff --git a/website/static/img/blog/declarative-ui/minesweeper.png b/website/static/img/blog/declarative-ui/minesweeper.png new file mode 100644 index 0000000000..a7cdf0aba8 Binary files /dev/null and b/website/static/img/blog/declarative-ui/minesweeper.png differ diff --git a/website/static/img/blog/declarative-ui/todo.png b/website/static/img/blog/declarative-ui/todo.png new file mode 100644 index 0000000000..bb51c63f6c Binary files /dev/null and b/website/static/img/blog/declarative-ui/todo.png differ diff --git a/website/static/img/blog/drag-and-drop/absolute-positioned-numbers.png b/website/static/img/blog/drag-and-drop/absolute-positioned-numbers.png new file mode 100644 index 0000000000..100d68d320 Binary files /dev/null and b/website/static/img/blog/drag-and-drop/absolute-positioned-numbers.png differ diff --git a/website/static/img/blog/extensions/example.png b/website/static/img/blog/extensions/example.png new file mode 100644 index 0000000000..c11599d400 Binary files /dev/null and b/website/static/img/blog/extensions/example.png differ diff --git a/website/static/img/blog/fastapi/fastapi-logo-teal.png b/website/static/img/blog/fastapi/fastapi-logo-teal.png new file mode 100644 index 0000000000..f08144cd92 Binary files /dev/null and b/website/static/img/blog/fastapi/fastapi-logo-teal.png differ diff --git a/website/static/img/blog/flet-0-81/camera.png b/website/static/img/blog/flet-0-81/camera.png new file mode 100644 index 0000000000..be2733685d Binary files /dev/null and b/website/static/img/blog/flet-0-81/camera.png differ diff --git a/website/static/img/blog/flet-0-81/code-editor.png b/website/static/img/blog/flet-0-81/code-editor.png new file mode 100644 index 0000000000..2b2b3aa0b2 Binary files /dev/null and b/website/static/img/blog/flet-0-81/code-editor.png differ diff --git a/website/static/img/blog/flet-0-81/color-pickers.png b/website/static/img/blog/flet-0-81/color-pickers.png new file mode 100644 index 0000000000..1451c03816 Binary files /dev/null and b/website/static/img/blog/flet-0-81/color-pickers.png differ diff --git a/website/static/img/blog/flet-0-81/hero.gif b/website/static/img/blog/flet-0-81/hero.gif new file mode 100644 index 0000000000..110a9b101d Binary files /dev/null and b/website/static/img/blog/flet-0-81/hero.gif differ diff --git a/website/static/img/blog/flet-0-81/matrix4-transform.png b/website/static/img/blog/flet-0-81/matrix4-transform.png new file mode 100644 index 0000000000..23b5dca9d8 Binary files /dev/null and b/website/static/img/blog/flet-0-81/matrix4-transform.png differ diff --git a/website/static/img/blog/flet-0-81/page-view.gif b/website/static/img/blog/flet-0-81/page-view.gif new file mode 100644 index 0000000000..775467dfbe Binary files /dev/null and b/website/static/img/blog/flet-0-81/page-view.gif differ diff --git a/website/static/img/blog/flet-0-81/rotated-box.png b/website/static/img/blog/flet-0-81/rotated-box.png new file mode 100644 index 0000000000..2da745d479 Binary files /dev/null and b/website/static/img/blog/flet-0-81/rotated-box.png differ diff --git a/website/static/img/blog/flet-0-84/crocodocs-logo.png b/website/static/img/blog/flet-0-84/crocodocs-logo.png new file mode 100644 index 0000000000..42a88eb472 Binary files /dev/null and b/website/static/img/blog/flet-0-84/crocodocs-logo.png differ diff --git a/website/static/img/blog/flet-0-84/vscode-docstring.png b/website/static/img/blog/flet-0-84/vscode-docstring.png new file mode 100644 index 0000000000..4050498e8d Binary files /dev/null and b/website/static/img/blog/flet-0-84/vscode-docstring.png differ diff --git a/website/static/img/blog/flet-debug/flet-debug-on-real-iphone.png b/website/static/img/blog/flet-debug/flet-debug-on-real-iphone.png new file mode 100644 index 0000000000..160d4c0247 Binary files /dev/null and b/website/static/img/blog/flet-debug/flet-debug-on-real-iphone.png differ diff --git a/website/static/img/blog/gesture-detector/gesture-detector-demo.gif b/website/static/img/blog/gesture-detector/gesture-detector-demo.gif new file mode 100644 index 0000000000..1277f43a51 Binary files /dev/null and b/website/static/img/blog/gesture-detector/gesture-detector-demo.gif differ diff --git a/website/static/img/blog/gradients/button-shapes.png b/website/static/img/blog/gradients/button-shapes.png new file mode 100644 index 0000000000..bcc1ba8bf2 Binary files /dev/null and b/website/static/img/blog/gradients/button-shapes.png differ diff --git a/website/static/img/blog/gradients/linear-gradient.png b/website/static/img/blog/gradients/linear-gradient.png new file mode 100644 index 0000000000..f1b7e2dfda Binary files /dev/null and b/website/static/img/blog/gradients/linear-gradient.png differ diff --git a/website/static/img/blog/gradients/radial-gradient.png b/website/static/img/blog/gradients/radial-gradient.png new file mode 100644 index 0000000000..9fcdc8123c Binary files /dev/null and b/website/static/img/blog/gradients/radial-gradient.png differ diff --git a/website/static/img/blog/gradients/styled-button.gif b/website/static/img/blog/gradients/styled-button.gif new file mode 100644 index 0000000000..e6e2dfe12d Binary files /dev/null and b/website/static/img/blog/gradients/styled-button.gif differ diff --git a/website/static/img/blog/gradients/styled-dropdown.gif b/website/static/img/blog/gradients/styled-dropdown.gif new file mode 100644 index 0000000000..789108fb25 Binary files /dev/null and b/website/static/img/blog/gradients/styled-dropdown.gif differ diff --git a/website/static/img/blog/gradients/styled-textfield.gif b/website/static/img/blog/gradients/styled-textfield.gif new file mode 100644 index 0000000000..be31c5fc85 Binary files /dev/null and b/website/static/img/blog/gradients/styled-textfield.gif differ diff --git a/website/static/img/blog/gradients/sweep-gradient.png b/website/static/img/blog/gradients/sweep-gradient.png new file mode 100644 index 0000000000..718fe78f2e Binary files /dev/null and b/website/static/img/blog/gradients/sweep-gradient.png differ diff --git a/website/static/img/blog/gradients/toggle-icon-button.gif b/website/static/img/blog/gradients/toggle-icon-button.gif new file mode 100644 index 0000000000..a2dcf95501 Binary files /dev/null and b/website/static/img/blog/gradients/toggle-icon-button.gif differ diff --git a/website/static/img/blog/ios/flet-1080x1080.png b/website/static/img/blog/ios/flet-1080x1080.png new file mode 100644 index 0000000000..6dc046a4a2 Binary files /dev/null and b/website/static/img/blog/ios/flet-1080x1080.png differ diff --git a/website/static/img/blog/mobile-update/flet-desktop-architecture-v2.svg b/website/static/img/blog/mobile-update/flet-desktop-architecture-v2.svg new file mode 100644 index 0000000000..9471011c15 --- /dev/null +++ b/website/static/img/blog/mobile-update/flet-desktop-architecture-v2.svg @@ -0,0 +1,3 @@ + + +
    Flet client
    Flet client
    Python
    Python
    Python runtime (python.exe)
    Python runtime (python.exe)
    Flutter app (.exe)
    Flutter app (.exe)
      Events  
      Events  
      Page updates  
      Page updates  
    Translates JSON into Flutter widgets
    Translates JSON into F...
    Sends events to Flet server via WebSockets
    Sends events to Flet s...
    tcp://127.0.0.1:port
    unix:///var/run/flet
    tcp://127.0.0.1:port...
    User program
    User program
    Fletd
    Fletd
    Text is not SVG - cannot display
    \ No newline at end of file diff --git a/website/static/img/blog/mobile-update/flet-desktop-architecture.svg b/website/static/img/blog/mobile-update/flet-desktop-architecture.svg new file mode 100644 index 0000000000..b9556018f5 --- /dev/null +++ b/website/static/img/blog/mobile-update/flet-desktop-architecture.svg @@ -0,0 +1,3 @@ + + +
    Python runtime
    Python runtime
    Compiled Flutter app
    .exe, .apk, .ipa
    Compiled Flutter app...
    Flet client
    Flet client
    Python program
    Python program
    WebSockets
    WebSockets
      JSON updates  
      JSON updates  
      Events  
      Events  
      Events  
      Events  
      Page updates  
      Page updates  
    WebSockets
    WebSockets
    Compiled Go app
    Compiled Go app
    page.update() sends page update commands to Flet server
    page.update() sends pa...
    Dispatches events to controls
    Dispatches events to c...
    Fletd server
    Fletd server
    Translates page update commands into JSON and sends to Flet client
    Translates page update...
    Routes events back to a user program
    Routes events back to...
    Translates JSON into Flutter widgets
    Translates JSON into F...
    Sends events to Flet server via WebSockets
    Sends events to Flet s...
    http://127.0.0.1:port
    http://127.0.0.1:port
    Text is not SVG - cannot display
    \ No newline at end of file diff --git a/website/static/img/blog/mobile-update/flet-mobile-architecture-v2.svg b/website/static/img/blog/mobile-update/flet-mobile-architecture-v2.svg new file mode 100644 index 0000000000..cd99731003 --- /dev/null +++ b/website/static/img/blog/mobile-update/flet-mobile-architecture-v2.svg @@ -0,0 +1,4 @@ + + + +
    Flet client
    Flet client
    Python
    Python
    Python runtime (python.exe)
    Python runtime (python.exe)
    User program
    User program
    Fletd
    Fletd
    Flutter app
    .apk, .ipa
    Flutter app...
    FFI
    unix:///var/run/flet
    FFI...
    Text is not SVG - cannot display
    \ No newline at end of file diff --git a/website/static/img/blog/packaging/pypi-non-pure-package.png b/website/static/img/blog/packaging/pypi-non-pure-package.png new file mode 100644 index 0000000000..21ef9ece27 Binary files /dev/null and b/website/static/img/blog/packaging/pypi-non-pure-package.png differ diff --git a/website/static/img/blog/packaging/pypi-pure-package.png b/website/static/img/blog/packaging/pypi-pure-package.png new file mode 100644 index 0000000000..b55c9de4ca Binary files /dev/null and b/website/static/img/blog/packaging/pypi-pure-package.png differ diff --git a/website/static/img/blog/pglet-introduction/pglet-highlevel-design.png b/website/static/img/blog/pglet-introduction/pglet-highlevel-design.png new file mode 100644 index 0000000000..8b5a3633ff Binary files /dev/null and b/website/static/img/blog/pglet-introduction/pglet-highlevel-design.png differ diff --git a/website/static/img/blog/pycon-us-2024/pycon-us-2024-collage.jpg b/website/static/img/blog/pycon-us-2024/pycon-us-2024-collage.jpg new file mode 100644 index 0000000000..a85c3b1ba0 Binary files /dev/null and b/website/static/img/blog/pycon-us-2024/pycon-us-2024-collage.jpg differ diff --git a/website/static/img/blog/pyodide/pyodide-logo.png b/website/static/img/blog/pyodide/pyodide-logo.png new file mode 100644 index 0000000000..f794573b23 Binary files /dev/null and b/website/static/img/blog/pyodide/pyodide-logo.png differ diff --git a/website/static/img/blog/sensors/flet-sensor-android-emulator.png b/website/static/img/blog/sensors/flet-sensor-android-emulator.png new file mode 100644 index 0000000000..3e56afc11e Binary files /dev/null and b/website/static/img/blog/sensors/flet-sensor-android-emulator.png differ diff --git a/website/static/img/blog/sensors/flet-sensor-services.png b/website/static/img/blog/sensors/flet-sensor-services.png new file mode 100644 index 0000000000..6114f01f5e Binary files /dev/null and b/website/static/img/blog/sensors/flet-sensor-services.png differ diff --git a/website/static/img/blog/theme-scrolling/material-theme-builder.png b/website/static/img/blog/theme-scrolling/material-theme-builder.png new file mode 100644 index 0000000000..64d3cec4f1 Binary files /dev/null and b/website/static/img/blog/theme-scrolling/material-theme-builder.png differ diff --git a/website/static/img/blog/theme-scrolling/nested-themes.png b/website/static/img/blog/theme-scrolling/nested-themes.png new file mode 100644 index 0000000000..744a21ed08 Binary files /dev/null and b/website/static/img/blog/theme-scrolling/nested-themes.png differ diff --git a/website/static/img/blog/theme-scrolling/tabs-theme.png b/website/static/img/blog/theme-scrolling/tabs-theme.png new file mode 100644 index 0000000000..cad87a67d8 Binary files /dev/null and b/website/static/img/blog/theme-scrolling/tabs-theme.png differ diff --git a/website/static/img/blog/theme-scrolling/text-theme.png b/website/static/img/blog/theme-scrolling/text-theme.png new file mode 100644 index 0000000000..4dd8dd82a1 Binary files /dev/null and b/website/static/img/blog/theme-scrolling/text-theme.png differ diff --git a/website/static/img/blog/using-custom-fonts-in-flet-app/custom-fonts-example.png b/website/static/img/blog/using-custom-fonts-in-flet-app/custom-fonts-example.png new file mode 100644 index 0000000000..29e4c47b1a Binary files /dev/null and b/website/static/img/blog/using-custom-fonts-in-flet-app/custom-fonts-example.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/app-link-1.png b/website/static/img/docs/cloudflare-pages-deploy/app-link-1.png new file mode 100644 index 0000000000..2566e68685 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/app-link-1.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/app-link-2.png b/website/static/img/docs/cloudflare-pages-deploy/app-link-2.png new file mode 100644 index 0000000000..20e3675f56 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/app-link-2.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/assets-upload.png b/website/static/img/docs/cloudflare-pages-deploy/assets-upload.png new file mode 100644 index 0000000000..1bc981c3b3 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/assets-upload.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/build-settings.png b/website/static/img/docs/cloudflare-pages-deploy/build-settings.png new file mode 100644 index 0000000000..d5c5e7bedc Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/build-settings.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/deployment-methods.png b/website/static/img/docs/cloudflare-pages-deploy/deployment-methods.png new file mode 100644 index 0000000000..76587e66cd Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/deployment-methods.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/flet-publish-help.png b/website/static/img/docs/cloudflare-pages-deploy/flet-publish-help.png new file mode 100644 index 0000000000..52172f6ef8 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/flet-publish-help.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/git-account-selection.png b/website/static/img/docs/cloudflare-pages-deploy/git-account-selection.png new file mode 100644 index 0000000000..eada9db659 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/git-account-selection.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/git-auth.png b/website/static/img/docs/cloudflare-pages-deploy/git-auth.png new file mode 100644 index 0000000000..624e37e696 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/git-auth.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/pages-from-sidebar.png b/website/static/img/docs/cloudflare-pages-deploy/pages-from-sidebar.png new file mode 100644 index 0000000000..149b25c34f Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/pages-from-sidebar.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/project-creation.png b/website/static/img/docs/cloudflare-pages-deploy/project-creation.png new file mode 100644 index 0000000000..8816def272 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/project-creation.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/repo-selection.png b/website/static/img/docs/cloudflare-pages-deploy/repo-selection.png new file mode 100644 index 0000000000..2f731f939a Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/repo-selection.png differ diff --git a/website/static/img/docs/cloudflare-pages-deploy/successful-deployment.png b/website/static/img/docs/cloudflare-pages-deploy/successful-deployment.png new file mode 100644 index 0000000000..9fbd71b350 Binary files /dev/null and b/website/static/img/docs/cloudflare-pages-deploy/successful-deployment.png differ diff --git a/website/static/img/docs/colors/color_palettes.png b/website/static/img/docs/colors/color_palettes.png new file mode 100644 index 0000000000..02b82f3536 Binary files /dev/null and b/website/static/img/docs/colors/color_palettes.png differ diff --git a/website/static/img/docs/colors/color_palettes_2.png b/website/static/img/docs/colors/color_palettes_2.png new file mode 100644 index 0000000000..8d3c8afc35 Binary files /dev/null and b/website/static/img/docs/colors/color_palettes_2.png differ diff --git a/website/static/img/docs/colors/colors_fallback.svg b/website/static/img/docs/colors/colors_fallback.svg new file mode 100644 index 0000000000..083d1c4946 --- /dev/null +++ b/website/static/img/docs/colors/colors_fallback.svg @@ -0,0 +1,4 @@ + + + +


    If color property is defined on the control level, it will be used.

    Otherwise, fallback to Control Theme level
    If color property is defined on the...


    Flet will check for the nearest ancestor that has <Control>Theme defined, for example TabsTheme. If color is defined there, it will be used.

    Otherwise, fallback to Theme level
    Flet will check for the nearest ance...


    Flet will check for the nearest ancestor that has Theme defined and will use the color from the ColorScheme.

    By default, ColorScheme is defined for the page with seed_color "blue"
    Flet will check for the nearest ance...
    Control level
    Control level
    Control Theme level
    Control Theme level
    Theme level
    Theme level
    Text is not SVG - cannot display
    diff --git a/website/static/img/docs/colors/theme_colors.png b/website/static/img/docs/colors/theme_colors.png new file mode 100644 index 0000000000..f529a07088 Binary files /dev/null and b/website/static/img/docs/colors/theme_colors.png differ diff --git a/website/static/img/docs/colors/theme_colors_green.png b/website/static/img/docs/colors/theme_colors_green.png new file mode 100644 index 0000000000..2be2877ac0 Binary files /dev/null and b/website/static/img/docs/colors/theme_colors_green.png differ diff --git a/website/static/img/docs/getting-started/add-box-icon.svg b/website/static/img/docs/getting-started/add-box-icon.svg new file mode 100644 index 0000000000..b85a07c656 --- /dev/null +++ b/website/static/img/docs/getting-started/add-box-icon.svg @@ -0,0 +1 @@ + diff --git a/website/static/img/docs/getting-started/appveyor-ci-flet-github-releases.png b/website/static/img/docs/getting-started/appveyor-ci-flet-github-releases.png new file mode 100644 index 0000000000..0b424f1ccd Binary files /dev/null and b/website/static/img/docs/getting-started/appveyor-ci-flet-github-releases.png differ diff --git a/website/static/img/docs/getting-started/appveyor-ci-flet-python-project.png b/website/static/img/docs/getting-started/appveyor-ci-flet-python-project.png new file mode 100644 index 0000000000..6f145a0ac5 Binary files /dev/null and b/website/static/img/docs/getting-started/appveyor-ci-flet-python-project.png differ diff --git a/website/static/img/docs/getting-started/basic-app-structure.png b/website/static/img/docs/getting-started/basic-app-structure.png new file mode 100644 index 0000000000..8ab0ac793e Binary files /dev/null and b/website/static/img/docs/getting-started/basic-app-structure.png differ diff --git a/website/static/img/docs/getting-started/chat-app-example.gif b/website/static/img/docs/getting-started/chat-app-example.gif new file mode 100644 index 0000000000..b483ae89b1 Binary files /dev/null and b/website/static/img/docs/getting-started/chat-app-example.gif differ diff --git a/website/static/img/docs/getting-started/chrome-pwa-install.png b/website/static/img/docs/getting-started/chrome-pwa-install.png new file mode 100644 index 0000000000..b104adb5ec Binary files /dev/null and b/website/static/img/docs/getting-started/chrome-pwa-install.png differ diff --git a/website/static/img/docs/getting-started/control-refs-rewritten.png b/website/static/img/docs/getting-started/control-refs-rewritten.png new file mode 100644 index 0000000000..53b1238320 Binary files /dev/null and b/website/static/img/docs/getting-started/control-refs-rewritten.png differ diff --git a/website/static/img/docs/getting-started/control-refs.png b/website/static/img/docs/getting-started/control-refs.png new file mode 100644 index 0000000000..509fa67fec Binary files /dev/null and b/website/static/img/docs/getting-started/control-refs.png differ diff --git a/website/static/img/docs/getting-started/controls-text.png b/website/static/img/docs/getting-started/controls-text.png new file mode 100644 index 0000000000..4831deca6e Binary files /dev/null and b/website/static/img/docs/getting-started/controls-text.png differ diff --git a/website/static/img/docs/getting-started/debug-accessibility-toggle.gif b/website/static/img/docs/getting-started/debug-accessibility-toggle.gif new file mode 100644 index 0000000000..e16c5e753b Binary files /dev/null and b/website/static/img/docs/getting-started/debug-accessibility-toggle.gif differ diff --git a/website/static/img/docs/getting-started/displaying-data-text.png b/website/static/img/docs/getting-started/displaying-data-text.png new file mode 100644 index 0000000000..2d9608a1b6 Binary files /dev/null and b/website/static/img/docs/getting-started/displaying-data-text.png differ diff --git a/website/static/img/docs/getting-started/drag-and-drop-number-2.gif b/website/static/img/docs/getting-started/drag-and-drop-number-2.gif new file mode 100644 index 0000000000..0f93fb6378 Binary files /dev/null and b/website/static/img/docs/getting-started/drag-and-drop-number-2.gif differ diff --git a/website/static/img/docs/getting-started/drag-and-drop-number-3.gif b/website/static/img/docs/getting-started/drag-and-drop-number-3.gif new file mode 100644 index 0000000000..577477fc47 Binary files /dev/null and b/website/static/img/docs/getting-started/drag-and-drop-number-3.gif differ diff --git a/website/static/img/docs/getting-started/drag-and-drop-number.gif b/website/static/img/docs/getting-started/drag-and-drop-number.gif new file mode 100644 index 0000000000..0a472dbc55 Binary files /dev/null and b/website/static/img/docs/getting-started/drag-and-drop-number.gif differ diff --git a/website/static/img/docs/getting-started/edge-pwa-install.png b/website/static/img/docs/getting-started/edge-pwa-install.png new file mode 100644 index 0000000000..545ebea09d Binary files /dev/null and b/website/static/img/docs/getting-started/edge-pwa-install.png differ diff --git a/website/static/img/docs/getting-started/flet-counter-macos.png b/website/static/img/docs/getting-started/flet-counter-macos.png new file mode 100644 index 0000000000..5dc3e12503 Binary files /dev/null and b/website/static/img/docs/getting-started/flet-counter-macos.png differ diff --git a/website/static/img/docs/getting-started/flet-counter-safari.png b/website/static/img/docs/getting-started/flet-counter-safari.png new file mode 100644 index 0000000000..1f64f6eb66 Binary files /dev/null and b/website/static/img/docs/getting-started/flet-counter-safari.png differ diff --git a/website/static/img/docs/getting-started/flet-counter-windows.png b/website/static/img/docs/getting-started/flet-counter-windows.png new file mode 100644 index 0000000000..b44fba60cf Binary files /dev/null and b/website/static/img/docs/getting-started/flet-counter-windows.png differ diff --git a/website/static/img/docs/getting-started/flet-highlevel-diagram.svg b/website/static/img/docs/getting-started/flet-highlevel-diagram.svg new file mode 100644 index 0000000000..954f13b3cc --- /dev/null +++ b/website/static/img/docs/getting-started/flet-highlevel-diagram.svg @@ -0,0 +1,3 @@ + + +
    WebSockets, IPC
    WebSockets, IPC
      JSON updates  
      JSON updates  
      Events  
      Events  
    Python, C#, Go, etc.
    Python, C#, Go, etc.
      Events  
      Events  
      Page updates  
      Page updates  
    Internet
    Internet
    Mobile device
    Mobile device
    Server
    Server
    WebSockets
    WebSockets
    Compiled Flutter app
    .exe, .apk, .ipa
    Compiled Flutter app...
    Compiled Go app
    Compiled Go app
    User program
    User program
    page.update() sends page update commands to Flet server
    page.update() sends pa...
    Dispatches events to controls
    Dispatches events to c...
    Flet server
    Flet server
    Translates page update commands into JSON and sends to Flet client
    Translates page update...
    Routes events back to a user program
    Routes events back to...
    Translates JSON into Flutter widgets
    Translates JSON into F...
    Sends events to Flet server via WebSockets
    Sends events to Flet s...
    Flet client
    Flet client
    Viewer does not support full SVG 1.1
    diff --git a/website/static/img/docs/getting-started/getting-user-input-checkbox.png b/website/static/img/docs/getting-started/getting-user-input-checkbox.png new file mode 100644 index 0000000000..5f5e0720a3 Binary files /dev/null and b/website/static/img/docs/getting-started/getting-user-input-checkbox.png differ diff --git a/website/static/img/docs/getting-started/getting-user-input-dropdown.png b/website/static/img/docs/getting-started/getting-user-input-dropdown.png new file mode 100644 index 0000000000..044db5bcfd Binary files /dev/null and b/website/static/img/docs/getting-started/getting-user-input-dropdown.png differ diff --git a/website/static/img/docs/getting-started/getting-user-input-elevated-button.png b/website/static/img/docs/getting-started/getting-user-input-elevated-button.png new file mode 100644 index 0000000000..6ae3676f2f Binary files /dev/null and b/website/static/img/docs/getting-started/getting-user-input-elevated-button.png differ diff --git a/website/static/img/docs/getting-started/getting-user-input-event-handlers.png b/website/static/img/docs/getting-started/getting-user-input-event-handlers.png new file mode 100644 index 0000000000..401d5bcf01 Binary files /dev/null and b/website/static/img/docs/getting-started/getting-user-input-event-handlers.png differ diff --git a/website/static/img/docs/getting-started/getting-user-input-textbox.png b/website/static/img/docs/getting-started/getting-user-input-textbox.png new file mode 100644 index 0000000000..0742c3ad9c Binary files /dev/null and b/website/static/img/docs/getting-started/getting-user-input-textbox.png differ diff --git a/website/static/img/docs/getting-started/grid-view.png b/website/static/img/docs/getting-started/grid-view.png new file mode 100644 index 0000000000..e73a3118ef Binary files /dev/null and b/website/static/img/docs/getting-started/grid-view.png differ diff --git a/website/static/img/docs/getting-started/ios-share-icon.svg b/website/static/img/docs/getting-started/ios-share-icon.svg new file mode 100644 index 0000000000..da0e62297a --- /dev/null +++ b/website/static/img/docs/getting-started/ios-share-icon.svg @@ -0,0 +1 @@ + diff --git a/website/static/img/docs/getting-started/keyboard-shortcuts.png b/website/static/img/docs/getting-started/keyboard-shortcuts.png new file mode 100644 index 0000000000..d6015c9c82 Binary files /dev/null and b/website/static/img/docs/getting-started/keyboard-shortcuts.png differ diff --git a/website/static/img/docs/getting-started/more-vert-icon.svg b/website/static/img/docs/getting-started/more-vert-icon.svg new file mode 100644 index 0000000000..2311f07a5f --- /dev/null +++ b/website/static/img/docs/getting-started/more-vert-icon.svg @@ -0,0 +1 @@ + diff --git a/website/static/img/docs/getting-started/row-wrap-as-grid.png b/website/static/img/docs/getting-started/row-wrap-as-grid.png new file mode 100644 index 0000000000..cd9aefdbda Binary files /dev/null and b/website/static/img/docs/getting-started/row-wrap-as-grid.png differ diff --git a/website/static/img/docs/getting-started/scroll-column.gif b/website/static/img/docs/getting-started/scroll-column.gif new file mode 100644 index 0000000000..e388831eac Binary files /dev/null and b/website/static/img/docs/getting-started/scroll-column.gif differ diff --git a/website/static/img/docs/getting-started/scroll-listview.gif b/website/static/img/docs/getting-started/scroll-listview.gif new file mode 100644 index 0000000000..f79894c198 Binary files /dev/null and b/website/static/img/docs/getting-started/scroll-listview.gif differ diff --git a/website/static/img/docs/getting-started/sending-page-updates-in-batches.png b/website/static/img/docs/getting-started/sending-page-updates-in-batches.png new file mode 100644 index 0000000000..6d29e67bd2 Binary files /dev/null and b/website/static/img/docs/getting-started/sending-page-updates-in-batches.png differ diff --git a/website/static/img/docs/getting-started/simple-ToDo.png b/website/static/img/docs/getting-started/simple-ToDo.png new file mode 100644 index 0000000000..9079ffa684 Binary files /dev/null and b/website/static/img/docs/getting-started/simple-ToDo.png differ diff --git a/website/static/img/docs/getting-started/user-control-countdown.gif b/website/static/img/docs/getting-started/user-control-countdown.gif new file mode 100644 index 0000000000..adad0a8caa Binary files /dev/null and b/website/static/img/docs/getting-started/user-control-countdown.gif differ diff --git a/website/static/img/docs/getting-started/user-control-counter.gif b/website/static/img/docs/getting-started/user-control-counter.gif new file mode 100644 index 0000000000..7694a38a86 Binary files /dev/null and b/website/static/img/docs/getting-started/user-control-counter.gif differ diff --git a/website/static/img/docs/hosting-replit/replit-disable-guess-imports.png b/website/static/img/docs/hosting-replit/replit-disable-guess-imports.png new file mode 100644 index 0000000000..99cc34c25a Binary files /dev/null and b/website/static/img/docs/hosting-replit/replit-disable-guess-imports.png differ diff --git a/website/static/img/docs/hosting-replit/replit-running-app.png b/website/static/img/docs/hosting-replit/replit-running-app.png new file mode 100644 index 0000000000..3b6bc4a918 Binary files /dev/null and b/website/static/img/docs/hosting-replit/replit-running-app.png differ diff --git a/website/static/img/favicon.ico b/website/static/img/favicon.ico new file mode 100644 index 0000000000..a8b1a00da1 Binary files /dev/null and b/website/static/img/favicon.ico differ diff --git a/website/static/img/flet-logo-300.png b/website/static/img/flet-logo-300.png new file mode 100644 index 0000000000..7317adc6c7 Binary files /dev/null and b/website/static/img/flet-logo-300.png differ diff --git a/website/static/img/gallery/calc.png b/website/static/img/gallery/calc.png new file mode 100644 index 0000000000..6e6aec8fc7 Binary files /dev/null and b/website/static/img/gallery/calc.png differ diff --git a/website/static/img/gallery/chat.gif b/website/static/img/gallery/chat.gif new file mode 100644 index 0000000000..b1fea20cc8 Binary files /dev/null and b/website/static/img/gallery/chat.gif differ diff --git a/website/static/img/gallery/controls-gallery.png b/website/static/img/gallery/controls-gallery.png new file mode 100644 index 0000000000..2b929475fe Binary files /dev/null and b/website/static/img/gallery/controls-gallery.png differ diff --git a/website/static/img/gallery/counter.png b/website/static/img/gallery/counter.png new file mode 100644 index 0000000000..e131161fca Binary files /dev/null and b/website/static/img/gallery/counter.png differ diff --git a/website/static/img/gallery/emoji-enigma.png b/website/static/img/gallery/emoji-enigma.png new file mode 100644 index 0000000000..3a6d8ea5c4 Binary files /dev/null and b/website/static/img/gallery/emoji-enigma.png differ diff --git a/website/static/img/gallery/flet-animation.png b/website/static/img/gallery/flet-animation.png new file mode 100644 index 0000000000..a6e673b8d0 Binary files /dev/null and b/website/static/img/gallery/flet-animation.png differ diff --git a/website/static/img/gallery/greeter.png b/website/static/img/gallery/greeter.png new file mode 100644 index 0000000000..ec17911c42 Binary files /dev/null and b/website/static/img/gallery/greeter.png differ diff --git a/website/static/img/gallery/hello-world.png b/website/static/img/gallery/hello-world.png new file mode 100644 index 0000000000..3acb43eb84 Binary files /dev/null and b/website/static/img/gallery/hello-world.png differ diff --git a/website/static/img/gallery/icons-browser.png b/website/static/img/gallery/icons-browser.png new file mode 100644 index 0000000000..7cfa118594 Binary files /dev/null and b/website/static/img/gallery/icons-browser.png differ diff --git a/website/static/img/gallery/routing.gif b/website/static/img/gallery/routing.gif new file mode 100644 index 0000000000..ffeacedece Binary files /dev/null and b/website/static/img/gallery/routing.gif differ diff --git a/website/static/img/gallery/seven-spell.png b/website/static/img/gallery/seven-spell.png new file mode 100644 index 0000000000..08f11af0ec Binary files /dev/null and b/website/static/img/gallery/seven-spell.png differ diff --git a/website/static/img/gallery/solitaire.png b/website/static/img/gallery/solitaire.png new file mode 100644 index 0000000000..0a1ba8cfab Binary files /dev/null and b/website/static/img/gallery/solitaire.png differ diff --git a/website/static/img/gallery/todo.png b/website/static/img/gallery/todo.png new file mode 100644 index 0000000000..bd0c7dbb80 Binary files /dev/null and b/website/static/img/gallery/todo.png differ diff --git a/website/static/img/gallery/trolli.png b/website/static/img/gallery/trolli.png new file mode 100644 index 0000000000..11e7c2e644 Binary files /dev/null and b/website/static/img/gallery/trolli.png differ diff --git a/website/static/img/logo.svg b/website/static/img/logo.svg new file mode 100644 index 0000000000..4762afefc6 --- /dev/null +++ b/website/static/img/logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/website/static/img/pages/home/accessible.svg b/website/static/img/pages/home/accessible.svg new file mode 100644 index 0000000000..9488e3ac09 --- /dev/null +++ b/website/static/img/pages/home/accessible.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/controls.svg b/website/static/img/pages/home/controls.svg new file mode 100644 index 0000000000..cae2bee2d1 --- /dev/null +++ b/website/static/img/pages/home/controls.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/extensible.svg b/website/static/img/pages/home/extensible.svg new file mode 100644 index 0000000000..3463a2b6e9 --- /dev/null +++ b/website/static/img/pages/home/extensible.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/flet-home.png b/website/static/img/pages/home/flet-home.png new file mode 100644 index 0000000000..7ac5cc9e02 Binary files /dev/null and b/website/static/img/pages/home/flet-home.png differ diff --git a/website/static/img/pages/home/packaging.svg b/website/static/img/pages/home/packaging.svg new file mode 100644 index 0000000000..5e337178b5 --- /dev/null +++ b/website/static/img/pages/home/packaging.svg @@ -0,0 +1 @@ + diff --git a/website/static/img/pages/home/python-packages.svg b/website/static/img/pages/home/python-packages.svg new file mode 100644 index 0000000000..0c98198683 --- /dev/null +++ b/website/static/img/pages/home/python-packages.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/python.svg b/website/static/img/pages/home/python.svg new file mode 100644 index 0000000000..1766ef3e50 --- /dev/null +++ b/website/static/img/pages/home/python.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/single-code-base.svg b/website/static/img/pages/home/single-code-base.svg new file mode 100644 index 0000000000..ddd03f8507 --- /dev/null +++ b/website/static/img/pages/home/single-code-base.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/test-on-ios-android.svg b/website/static/img/pages/home/test-on-ios-android.svg new file mode 100644 index 0000000000..33aa50421f --- /dev/null +++ b/website/static/img/pages/home/test-on-ios-android.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/static/img/pages/home/web-support.svg b/website/static/img/pages/home/web-support.svg new file mode 100644 index 0000000000..adcd2bede1 --- /dev/null +++ b/website/static/img/pages/home/web-support.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/yarn.lock b/website/yarn.lock new file mode 100644 index 0000000000..2826c31389 --- /dev/null +++ b/website/yarn.lock @@ -0,0 +1,15772 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@algolia/abtesting@npm:1.15.2": + version: 1.15.2 + resolution: "@algolia/abtesting@npm:1.15.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/99f45db6748c967e0514c1b85b6b757bdee3acd6565404c8553e5d200fe2932acbf4624e109d6901ee339ca63ca000f9216b1b9114533b68e90abaa6faf11af2 + languageName: node + linkType: hard + +"@algolia/autocomplete-core@npm:1.19.2": + version: 1.19.2 + resolution: "@algolia/autocomplete-core@npm:1.19.2" + dependencies: + "@algolia/autocomplete-plugin-algolia-insights": "npm:1.19.2" + "@algolia/autocomplete-shared": "npm:1.19.2" + checksum: 10c0/383952bc43a31f0771987416c350471824e480fcd15e1db8ae13386cd387879f1c81eadafceffa69f87e6b8e59fb1aa713da375fc07a30c5d8edb16a157b5f45 + languageName: node + linkType: hard + +"@algolia/autocomplete-core@npm:^1.19.2": + version: 1.19.8 + resolution: "@algolia/autocomplete-core@npm:1.19.8" + dependencies: + "@algolia/autocomplete-plugin-algolia-insights": "npm:1.19.8" + "@algolia/autocomplete-shared": "npm:1.19.8" + checksum: 10c0/7cf3a5ba3da36a665f3899fa30108c0f1123ec105e1a707411a63a0871d4b3dcb67874414f8206debb1007f0d4d3bb74dc87d5bf80efaf8d363a7953d8aa5355 + languageName: node + linkType: hard + +"@algolia/autocomplete-plugin-algolia-insights@npm:1.19.2": + version: 1.19.2 + resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.19.2" + dependencies: + "@algolia/autocomplete-shared": "npm:1.19.2" + peerDependencies: + search-insights: ">= 1 < 3" + checksum: 10c0/8548b6514004dbf6fb34d6da176ac911371f3e84724ef6b94600cd84d29339d2f44cead03d7c0d507b130da0d9acc61f6e4c9a0fba6f967a5ae2a42eea93f0c1 + languageName: node + linkType: hard + +"@algolia/autocomplete-plugin-algolia-insights@npm:1.19.8": + version: 1.19.8 + resolution: "@algolia/autocomplete-plugin-algolia-insights@npm:1.19.8" + dependencies: + "@algolia/autocomplete-shared": "npm:1.19.8" + peerDependencies: + search-insights: ">= 1 < 3" + checksum: 10c0/f187316bf90417628d8c15d107eb9659fcf8020d8457c30af675c2f8acbe5ea027d46faf83c2d1c6dd646f5016e03fcd8acafdd3c961c7d03e450fd8e3f5875e + languageName: node + linkType: hard + +"@algolia/autocomplete-shared@npm:1.19.2": + version: 1.19.2 + resolution: "@algolia/autocomplete-shared@npm:1.19.2" + peerDependencies: + "@algolia/client-search": ">= 4.9.1 < 6" + algoliasearch: ">= 4.9.1 < 6" + checksum: 10c0/eee6615e6d9e6db7727727e442b876a554a6eda6f14c1d55d667ed2d14702c4c888a34b9bfb18f66ccc6d402995b2c7c37ace9f19ce9fc9c83bbb623713efbc4 + languageName: node + linkType: hard + +"@algolia/autocomplete-shared@npm:1.19.8": + version: 1.19.8 + resolution: "@algolia/autocomplete-shared@npm:1.19.8" + peerDependencies: + "@algolia/client-search": ">= 4.9.1 < 6" + algoliasearch: ">= 4.9.1 < 6" + checksum: 10c0/235218aefa4dbe8558c699d8888c79ecf611180d8ac6d6ad24c3ee964ece61b1b6e206335d051fa5578fba6cbf900ad6f4a6a19ab2682dc0f3d63617af33f755 + languageName: node + linkType: hard + +"@algolia/client-abtesting@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-abtesting@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/57e5965c56e2816ca1dc51dca8707c648eff1978758fe7647f1f1cea1330f842754905970e22c9148bbb5238aefb382b90e5265906b86cec270334a474428e38 + languageName: node + linkType: hard + +"@algolia/client-analytics@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-analytics@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/cce5972c9dcc2b8e25b80dca958fb96537cc898d1cbeab85a28c947ac9fdf2f8e5b5f43f9d9ee332ecaed42b35f50120143042910e078d7b8e24d8a2a9546a19 + languageName: node + linkType: hard + +"@algolia/client-common@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-common@npm:5.49.2" + checksum: 10c0/cbb13330c1ada67fa881e5efc39838fa77c9bdbaa6cdf0debb6e8ec1d58e76475967e1371e32fa81d5106985ac9326721a4b2bb14afb2b532fbd9c51b86dd06a + languageName: node + linkType: hard + +"@algolia/client-insights@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-insights@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/78301982bf8a5d85a31d193ffff65c9eec35dd697ad848bd42c5dcb8bfc90e418b0ab6b132cf7fbbdba7ad243b8ac389202d95e29d8101f835452362996e76f0 + languageName: node + linkType: hard + +"@algolia/client-personalization@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-personalization@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/876dd78bf6762d2d08b761fb1470466c96ba7288f096d27f85ea8379dfbb5d553dc3d144c3f555c812e0157e055e7907af10ad535a0e94c4cf3c6e227cba0f4b + languageName: node + linkType: hard + +"@algolia/client-query-suggestions@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-query-suggestions@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/d04b2588e5342722f137a80567adbe8aed1edec8d9fc8aa8c0a3540e0536ff6a5df8ef48114e92fdb0377b3eb3470725689b4248fc32785920d0afc92097f5b0 + languageName: node + linkType: hard + +"@algolia/client-search@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/client-search@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/fbd19a75008810a29df05094b143b9f154e5772db62ae2549da42461fa41586e1e886875f5ccbc74046e1429f6e3a1294acc1a2cd34998782b91e82774bf76f8 + languageName: node + linkType: hard + +"@algolia/events@npm:^4.0.1": + version: 4.0.1 + resolution: "@algolia/events@npm:4.0.1" + checksum: 10c0/f398d815c6ed21ac08f6caadf1e9155add74ac05d99430191c3b1f1335fd91deaf468c6b304e6225c9885d3d44c06037c53def101e33d9c22daff175b2a65ca9 + languageName: node + linkType: hard + +"@algolia/ingestion@npm:1.49.2": + version: 1.49.2 + resolution: "@algolia/ingestion@npm:1.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/367a0dbbb29f23697f68c5cbdb9ae307a46b4562e2ee9d86cab10be0eb8db5d80c8cafa5b89d346682238dd6df297b62560a519cb5a8bfe7f42951af9e7feb7f + languageName: node + linkType: hard + +"@algolia/monitoring@npm:1.49.2": + version: 1.49.2 + resolution: "@algolia/monitoring@npm:1.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/d630d7064f4ec4fd7760bf4f4b356231a15fbcddd1b22fae6abbc84d2a29d72d3180ddd8b8b14415bc4298132f16247b10a071b62ab9813e01be88096f7b5143 + languageName: node + linkType: hard + +"@algolia/recommend@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/recommend@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/4037c43a945eb1fde1a7a8a653ec3aca66ec98b8a452de5c1000bd911e9f1ad7bf8e2aac450e9c2a53ab01e6798777384398e5de413c85868b0eed0148e4e0b0 + languageName: node + linkType: hard + +"@algolia/requester-browser-xhr@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/requester-browser-xhr@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + checksum: 10c0/8db8481baf7dd4ea2803c9c200d95bb2c4b2dfdf3ec52a7c3a2d30bd60eb86df455a6f868284ec5d9a3660fd2117314ada499bcfa00c4a2d83376a8848c620d4 + languageName: node + linkType: hard + +"@algolia/requester-fetch@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/requester-fetch@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + checksum: 10c0/378dd1786be1772f1adab3c306c4e641ebaf5ed374a40b406498c692d5b0513b3828a6d4c5de30910fe907c6f75c26681c6a63480dabd17969c8fcd41ca9d767 + languageName: node + linkType: hard + +"@algolia/requester-node-http@npm:5.49.2": + version: 5.49.2 + resolution: "@algolia/requester-node-http@npm:5.49.2" + dependencies: + "@algolia/client-common": "npm:5.49.2" + checksum: 10c0/493d384b03964229494aa5fc20c7abd0c807ecd3315b674f3bbed80ff00282ce6d21cfd7643e38a4fa30a20621fa81337cd4e1a12ee787b827964f46c527becb + languageName: node + linkType: hard + +"@antfu/install-pkg@npm:^1.1.0": + version: 1.1.0 + resolution: "@antfu/install-pkg@npm:1.1.0" + dependencies: + package-manager-detector: "npm:^1.3.0" + tinyexec: "npm:^1.0.1" + checksum: 10c0/140d5994c76fd3d0e824c88f1ce91b3370e8066a8bc2f5729ae133bf768caa239f7915e29c78f239b7ead253113ace51293e95127fafe2b786b88eb615b3be47 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/code-frame@npm:7.29.0" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.28.5" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/d34cc504e7765dfb576a663d97067afb614525806b5cad1a5cc1a7183b916fec8ff57fa233585e3926fd5a9e6b31aae6df91aa81ae9775fb7a28f658d3346f0d + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.28.6, @babel/compat-data@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/compat-data@npm:7.29.0" + checksum: 10c0/08f348554989d23aa801bf1405aa34b15e841c0d52d79da7e524285c77a5f9d298e70e11d91cc578d8e2c9542efc586d50c5f5cf8e1915b254a9dcf786913a94 + languageName: node + linkType: hard + +"@babel/core@npm:^7.21.3, @babel/core@npm:^7.25.9": + version: 7.29.0 + resolution: "@babel/core@npm:7.29.0" + dependencies: + "@babel/code-frame": "npm:^7.29.0" + "@babel/generator": "npm:^7.29.0" + "@babel/helper-compilation-targets": "npm:^7.28.6" + "@babel/helper-module-transforms": "npm:^7.28.6" + "@babel/helpers": "npm:^7.28.6" + "@babel/parser": "npm:^7.29.0" + "@babel/template": "npm:^7.28.6" + "@babel/traverse": "npm:^7.29.0" + "@babel/types": "npm:^7.29.0" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/5127d2e8e842ae409e11bcbb5c2dff9874abf5415e8026925af7308e903f4f43397341467a130490d1a39884f461bc2b67f3063bce0be44340db89687fd852aa + languageName: node + linkType: hard + +"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.29.0": + version: 7.29.1 + resolution: "@babel/generator@npm:7.29.1" + dependencies: + "@babel/parser": "npm:^7.29.0" + "@babel/types": "npm:^7.29.0" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/349086e6876258ef3fb2823030fee0f6c0eb9c3ebe35fc572e16997f8c030d765f636ddc6299edae63e760ea6658f8ee9a2edfa6d6b24c9a80c917916b973551 + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.27.1, @babel/helper-annotate-as-pure@npm:^7.27.3": + version: 7.27.3 + resolution: "@babel/helper-annotate-as-pure@npm:7.27.3" + dependencies: + "@babel/types": "npm:^7.27.3" + checksum: 10c0/94996ce0a05b7229f956033e6dcd69393db2b0886d0db6aff41e704390402b8cdcca11f61449cb4f86cfd9e61b5ad3a73e4fa661eeed7846b125bd1c33dbc633 + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.27.1, @babel/helper-compilation-targets@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-compilation-targets@npm:7.28.6" + dependencies: + "@babel/compat-data": "npm:^7.28.6" + "@babel/helper-validator-option": "npm:^7.27.1" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/3fcdf3b1b857a1578e99d20508859dbd3f22f3c87b8a0f3dc540627b4be539bae7f6e61e49d931542fe5b557545347272bbdacd7f58a5c77025a18b745593a50 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-create-class-features-plugin@npm:7.28.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.3" + "@babel/helper-member-expression-to-functions": "npm:^7.28.5" + "@babel/helper-optimise-call-expression": "npm:^7.27.1" + "@babel/helper-replace-supers": "npm:^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.6" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/0b62b46717891f4366006b88c9b7f277980d4f578c4c3789b7a4f5a2e09e121de4cda9a414ab403986745cd3ad1af3fe2d948c9f78ab80d4dc085afc9602af50 + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.27.1, @babel/helper-create-regexp-features-plugin@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.28.5" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.3" + regexpu-core: "npm:^6.3.1" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/7af3d604cadecdb2b0d2cedd696507f02a53a58be0523281c2d6766211443b55161dde1e6c0d96ab16ddfd82a2607a2f792390caa24797e9733631f8aa86859f + languageName: node + linkType: hard + +"@babel/helper-define-polyfill-provider@npm:^0.6.5, @babel/helper-define-polyfill-provider@npm:^0.6.8": + version: 0.6.8 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.8" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + debug: "npm:^4.4.3" + lodash.debounce: "npm:^4.0.8" + resolve: "npm:^1.22.11" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/306a169f2cb285f368578219ef18ea9702860d3d02d64334f8d45ea38648be0b9e1edad8c8f732fa34bb4206ccbb9883c395570fd57ab7bbcf293bc5964c5b3a + languageName: node + linkType: hard + +"@babel/helper-globals@npm:^7.28.0": + version: 7.28.0 + resolution: "@babel/helper-globals@npm:7.28.0" + checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232 + languageName: node + linkType: hard + +"@babel/helper-member-expression-to-functions@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-member-expression-to-functions@npm:7.28.5" + dependencies: + "@babel/traverse": "npm:^7.28.5" + "@babel/types": "npm:^7.28.5" + checksum: 10c0/4e6e05fbf4dffd0bc3e55e28fcaab008850be6de5a7013994ce874ec2beb90619cda4744b11607a60f8aae0227694502908add6188ceb1b5223596e765b44814 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-module-imports@npm:7.28.6" + dependencies: + "@babel/traverse": "npm:^7.28.6" + "@babel/types": "npm:^7.28.6" + checksum: 10c0/b49d8d8f204d9dbfd5ac70c54e533e5269afb3cea966a9d976722b13e9922cc773a653405f53c89acb247d5aebdae4681d631a3ae3df77ec046b58da76eda2ac + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-module-transforms@npm:7.28.6" + dependencies: + "@babel/helper-module-imports": "npm:^7.28.6" + "@babel/helper-validator-identifier": "npm:^7.28.5" + "@babel/traverse": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/6f03e14fc30b287ce0b839474b5f271e72837d0cafe6b172d759184d998fbee3903a035e81e07c2c596449e504f453463d58baa65b6f40a37ded5bec74620b2b + languageName: node + linkType: hard + +"@babel/helper-optimise-call-expression@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-optimise-call-expression@npm:7.27.1" + dependencies: + "@babel/types": "npm:^7.27.1" + checksum: 10c0/6b861e7fcf6031b9c9fc2de3cd6c005e94a459d6caf3621d93346b52774925800ca29d4f64595a5ceacf4d161eb0d27649ae385110ed69491d9776686fa488e6 + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.27.1, @babel/helper-plugin-utils@npm:^7.28.6, @babel/helper-plugin-utils@npm:^7.8.0": + version: 7.28.6 + resolution: "@babel/helper-plugin-utils@npm:7.28.6" + checksum: 10c0/3f5f8acc152fdbb69a84b8624145ff4f9b9f6e776cb989f9f968f8606eb7185c5c3cfcf3ba08534e37e1e0e1c118ac67080610333f56baa4f7376c99b5f1143d + languageName: node + linkType: hard + +"@babel/helper-remap-async-to-generator@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-remap-async-to-generator@npm:7.27.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.1" + "@babel/helper-wrap-function": "npm:^7.27.1" + "@babel/traverse": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/5ba6258f4bb57c7c9fa76b55f416b2d18c867b48c1af4f9f2f7cd7cc933fe6da7514811d08ceb4972f1493be46f4b69c40282b811d1397403febae13c2ec57b5 + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.27.1, @babel/helper-replace-supers@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-replace-supers@npm:7.28.6" + dependencies: + "@babel/helper-member-expression-to-functions": "npm:^7.28.5" + "@babel/helper-optimise-call-expression": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/04663c6389551b99b8c3e7ba4e2638b8ca2a156418c26771516124c53083aa8e74b6a45abe5dd46360af79709a0e9c6b72c076d0eab9efecdd5aaf836e79d8d5 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.27.1" + dependencies: + "@babel/traverse": "npm:^7.27.1" + "@babel/types": "npm:^7.27.1" + checksum: 10c0/f625013bcdea422c470223a2614e90d2c1cc9d832e97f32ca1b4f82b34bb4aa67c3904cb4b116375d3b5b753acfb3951ed50835a1e832e7225295c7b0c24dff7 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-validator-identifier@npm:7.28.5" + checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-option@npm:7.27.1" + checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148 + languageName: node + linkType: hard + +"@babel/helper-wrap-function@npm:^7.27.1": + version: 7.28.6 + resolution: "@babel/helper-wrap-function@npm:7.28.6" + dependencies: + "@babel/template": "npm:^7.28.6" + "@babel/traverse": "npm:^7.28.6" + "@babel/types": "npm:^7.28.6" + checksum: 10c0/110674c7aa705dd8cc34f278628f540b37a4cb35e81fcaf557772e026a6fd95f571feb51a8efb146e4e91bbf567dc9dd7f534f78da80f55f4be2ec842f36b678 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.28.6": + version: 7.29.2 + resolution: "@babel/helpers@npm:7.29.2" + dependencies: + "@babel/template": "npm:^7.28.6" + "@babel/types": "npm:^7.29.0" + checksum: 10c0/dab0e65b9318b2502a62c58bc0913572318595eec0482c31f0ad416b72636e6698a1d7c57cd2791d4528eb8c548bca88d338dc4d2a55a108dc1f6702f9bc5512 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": + version: 7.29.2 + resolution: "@babel/parser@npm:7.29.2" + dependencies: + "@babel/types": "npm:^7.29.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/e5a4e69e3ac7acdde995f37cf299a68458cfe7009dff66bd0962fd04920bef287201169006af365af479c08ff216bfefbb595e331f87f6ae7283858aebbc3317 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.28.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.5" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/844b7c7e9eec6d858262b2f3d5af75d3a6bbd9d3ecc740d95271fbdd84985731674536f5d8ac98f2dc0e8872698b516e406636e4d0cb04b50afe471172095a53 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/2cd7a55a856e5e59bbd9484247c092a41e0d9f966778e7019da324d9e0928892d26afc4fbb2ac3d76a3c5a631cd3cf0d72dd2653b44f634f6c663b9e6f80aacd + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/cf29835498c4a25bd470908528919729a0799b2ec94e89004929a5532c94a5e4b1a49bc5d6673a22e5afe05d08465873e14ee3b28c42eb3db489cdf5ca47c680 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.27.1" + "@babel/plugin-transform-optional-chaining": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.13.0 + checksum: 10c0/eddcd056f76e198868cbff883eb148acfade8f0890973ab545295df0c08e39573a72e65372bcc0b0bfadba1b043fe1aea6b0907d0b4889453ac154c404194ebc + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/traverse": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/f1a9194e8d1742081def7af748e9249eb5082c25d0ced292720a1f054895f99041c764a05f45af669a2c8898aeb79266058aedb0d3e1038963ad49be8288918a + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": + version: 7.21.0-placeholder-for-preset-env.2 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/e605e0070da087f6c35579499e65801179a521b6842c15181a1e305c04fded2393f11c1efd09b087be7f8b083d1b75e8f3efcbc1292b4f60d3369e14812cff63 + languageName: node + linkType: hard + +"@babel/plugin-syntax-dynamic-import@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/9c50927bf71adf63f60c75370e2335879402648f468d0172bc912e303c6a3876927d8eb35807331b57f415392732ed05ab9b42c68ac30a936813ab549e0246c5 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-assertions@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/f3b8bdccb9b4d3e3b9226684ca518e055399d05579da97dfe0160a38d65198cfe7dce809e73179d6463a863a040f980de32425a876d88efe4eda933d0d95982c + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/1be160e2c426faa74e5be2e30e39e8d0d8c543063bd5d06cd804f8751b8fbcb82ce824ca7f9ce4b09c003693f6c06a11ce503b7e34d85e1a259631e4c3f72ad2 + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.27.1, @babel/plugin-syntax-jsx@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-syntax-jsx@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b98fc3cd75e4ca3d5ca1162f610c286e14ede1486e0d297c13a5eb0ac85680ac9656d17d348bddd9160a54d797a08cea5eaac02b9330ddebb7b26732b7b99fb5 + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-syntax-typescript@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b0c392a35624883ac480277401ac7d92d8646b66e33639f5d350de7a6723924265985ae11ab9ebd551740ded261c443eaa9a87ea19def9763ca1e0d78c97dea8 + languageName: node + linkType: hard + +"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/9144e5b02a211a4fb9a0ce91063f94fbe1004e80bde3485a0910c9f14897cf83fabd8c21267907cff25db8e224858178df0517f14333cfcf3380ad9a4139cb50 + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/19abd7a7d11eef58c9340408a4c2594503f6c4eaea1baa7b0e5fbdda89df097e50663edb3448ad2300170b39efca98a75e5767af05cad3b0facb4944326896a3 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-generator-functions@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.29.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-remap-async-to-generator": "npm:^7.27.1" + "@babel/traverse": "npm:^7.29.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4080fc5e7dad7761bfebbb4fbe06bdfeb3a8bf0c027bcb4373e59e6b3dc7c5002eca7cbb1afba801d6439df8f92f7bcb3fb862e8fbbe43a9e59bb5653dcc0568 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.28.6" + dependencies: + "@babel/helper-module-imports": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-remap-async-to-generator": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/2eb0826248587df6e50038f36194a138771a7df22581020451c7779edeaf9ef39bf47c5b7a20ae2645af6416e8c896feeca273317329652e84abd79a4ab920ad + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/3313130ba3bf0699baad0e60da1c8c3c2f0c2c0a7039cd0063e54e72e739c33f1baadfc9d8c73b3fea8c85dd7250c3964fb09c8e1fa62ba0b24a9fefe0a8dbde + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-block-scoping@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/2e3e09e1f9770b56cef4dcbffddf262508fd03416072f815ac66b2b224a3a12cd285cfec12fc067f1add414e7db5ce6dafb5164a6e0fb1a728e6a97d0c6f6e9d + languageName: node + linkType: hard + +"@babel/plugin-transform-class-properties@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-class-properties@npm:7.28.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/c4327fcd730c239d9f173f9b695b57b801729e273b4848aef1f75818069dfd31d985d75175db188d947b9b1bbe5353dae298849042026a5e4fcf07582ff3f9f1 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-class-static-block@npm:7.28.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 10c0/dbe9b1fd302ae41b73186e17ac8d8ecf625ebc2416a91f2dc8013977a1bdf21e6ea288a83f084752b412242f3866e789d4fddeb428af323fe35b60e0fae4f98c + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-classes@npm:7.28.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.3" + "@babel/helper-compilation-targets": "npm:^7.28.6" + "@babel/helper-globals": "npm:^7.28.0" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-replace-supers": "npm:^7.28.6" + "@babel/traverse": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/dc22f1f6eadab17305128fbf9cc5f30e87a51a77dd0a6d5498097994e8a9b9a90ab298c11edf2342acbeaac9edc9c601cad72eedcf4b592cd465a787d7f41490 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-computed-properties@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/template": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/1e9893503ae6d651125701cc29450e87c0b873c8febebff19da75da9c40cfb7968c52c28bf948244e461110aeb7b3591f2cc199b7406ff74a24c50c7a5729f39 + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/plugin-transform-destructuring@npm:7.28.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/traverse": "npm:^7.28.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/288207f488412b23bb206c7c01ba143714e2506b72a9ec09e993f28366cc8188d121bde714659b3437984a86d2881d9b1b06de3089d5582823ccf2f3b3eaa2c4 + languageName: node + linkType: hard + +"@babel/plugin-transform-dotall-regex@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.28.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.28.5" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/e2fb76b7ae99087cf4212013a3ca9dee07048f90f98fd6264855080fb6c3f169be11c9b8c9d8b26cf9a407e4d0a5fa6e103f7cef433a542b75cf7127c99d4f97 + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-keys@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/22a822e5342b7066f83eaedc4fd9bb044ac6bc68725484690b33ba04a7104980e43ea3229de439286cb8db8e7db4a865733a3f05123ab58a10f189f03553746f + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.29.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.28.5" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/6f03d9e5e31a05b28555541be6e283407e08447a36be6ddf8068b3efa970411d832e04b1282e2b894baf89a3864ff7e7f1e36346652a8d983170c6d548555167 + languageName: node + linkType: hard + +"@babel/plugin-transform-dynamic-import@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/8dcd3087aca134b064fc361d2cc34eec1f900f6be039b6368104afcef10bb75dea726bb18cabd046716b89b0edaa771f50189fa16bc5c5914a38cbcf166350f7 + languageName: node + linkType: hard + +"@babel/plugin-transform-explicit-resource-management@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-explicit-resource-management@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/plugin-transform-destructuring": "npm:^7.28.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/e6ea28c26e058fe61ada3e70b0def1992dd5a44f5fc14d8e2c6a3a512fb4d4c6dc96a3e1d0b466d83db32a9101e0b02df94051e48d3140da115b8ea9f8a31f37 + languageName: node + linkType: hard + +"@babel/plugin-transform-exponentiation-operator@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4572d955a50dbc9a652a19431b4bb822cb479ee6045f4e6df72659c499c13036da0a2adf650b07ca995f2781e80aa868943bea1e7bff1de3169ec3f0a73a902e + languageName: node + linkType: hard + +"@babel/plugin-transform-export-namespace-from@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/d7165cad11f571a54c8d9263d6c6bf2b817aff4874f747cb51e6e49efb32f2c9b37a6850cdb5e3b81e0b638141bb77dc782a6ec1a94128859fbdf7767581e07c + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-for-of@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4635763173a23aae24480681f2b0996b4f54a0cb2368880301a1801638242e263132d1e8adbe112ab272913d1d900ee0d6f7dea79443aef9d3325168cd88b3fb + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-function-name@npm:7.27.1" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/traverse": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5abdc7b5945fbd807269dcc6e76e52b69235056023b0b35d311e8f5dfd6c09d9f225839798998fc3b663f50cf701457ddb76517025a0d7a5474f3fe56e567a4c + languageName: node + linkType: hard + +"@babel/plugin-transform-json-strings@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-json-strings@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/ab1091798c58e6c0bb8a864ee2b727c400924592c6ed69797a26b4c205f850a935de77ad516570be0419c279a3d9f7740c2aa448762eb8364ea77a6a357a9653 + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-literals@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/c40dc3eb2f45a92ee476412314a40e471af51a0f51a24e91b85cef5fc59f4fe06758088f541643f07f949d2c67ee7bdce10e11c5ec56791ae09b15c3b451eeca + languageName: node + linkType: hard + +"@babel/plugin-transform-logical-assignment-operators@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4632a35453d2131f0be466681d0a33e3db44d868ff51ec46cd87e0ebd1e47c6a39b894f7d1c9b06f931addf6efa9d30e60c4cdedeb4f69d426f683e11f8490cf + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/0874ccebbd1c6a155e5f6b3b29729fade1221b73152567c1af1e1a7c12848004dffecbd7eded6dc463955120040ae57c17cb586b53fb5a7a27fcd88177034c30 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-modules-amd@npm:7.27.1" + dependencies: + "@babel/helper-module-transforms": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/76e86cd278b6a3c5b8cca8dfb3428e9cd0c81a5df7096e04c783c506696b916a9561386d610a9d846ef64804640e0bd818ea47455fed0ee89b7f66c555b29537 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.27.1, @babel/plugin-transform-modules-commonjs@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.28.6" + dependencies: + "@babel/helper-module-transforms": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/7c45992797c6150644c8552feff4a016ba7bd6d59ff2b039ed969a9c5b20a6804cd9d21db5045fc8cca8ca7f08262497e354e93f8f2be6a1cdf3fbfa8c31a9b6 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.29.0" + dependencies: + "@babel/helper-module-transforms": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-validator-identifier": "npm:^7.28.5" + "@babel/traverse": "npm:^7.29.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/44ea502f2c990398b7d9adc5b44d9e1810a0a5e86eebc05c92d039458f0b3994fe243efa9353b90f8a648d8a91b79845fb353d8679d7324cc9de0162d732771d + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-modules-umd@npm:7.27.1" + dependencies: + "@babel/helper-module-transforms": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/e5962a8874889da2ab1aa32eb93ec21d419c7423c766e4befb39b4bb512b9ad44b47837b6cd1c8f1065445cbbcc6dc2be10298ac6e734e5ca1059fc23698daed + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.29.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.28.5" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/1904db22da7f2bc3e380cd2c0786bda330ee1b1b3efa3f5203d980708c4bfeb5daa4dff48d01692193040bcc5f275dbdc0c2eadc8b1eb1b6dfe363564ad6e898 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-new-target@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/9b0581412fcc5ab1b9a2d86a0c5407bd959391f0a1e77a46953fef9f7a57f3f4020d75f71098c5f9e5dcc680a87f9fd99b3205ab12e25ef8c19eed038c1e4b28 + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/6607f2201d66ccb688f0b1db09475ef995837df19f14705da41f693b669f834c206147a854864ab107913d7b4f4748878b0cd9fe9ca8bfd1bee0c206fc027b49 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/191097d8d2753cdd16d1acca65a945d1645ab20b65655c2f5b030a9e38967a52e093dcb21ebf391e342222705c6ffe5dea15dafd6257f7b51b77fb64a830b637 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.28.6" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/plugin-transform-destructuring": "npm:^7.28.5" + "@babel/plugin-transform-parameters": "npm:^7.27.7" + "@babel/traverse": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/f55334352d4fcde385f2e8a58836687e71ff668c9b6e4c34d52575bf2789cdde92d9d3116edba13647ac0bc3e51fb2a6d1e8fb822dce7e8123334b82600bc4c3 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-object-super@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-replace-supers": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/efa2d092ef55105deb06d30aff4e460c57779b94861188128489b72378bf1f0ab0f06a4a4d68b9ae2a59a79719fbb2d148b9a3dca19ceff9c73b1f1a95e0527c + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-catch-binding@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/36e8face000ee65e478a55febf687ce9be7513ad498c60dfe585851555565e0c28e7cb891b3c59709318539ce46f7697d5f42130eb18f385cd47e47cfa297446 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.27.1, @babel/plugin-transform-optional-chaining@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/c159cc74115c2266be21791f192dd079e2aeb65c8731157e53b80fcefa41e8e28ad370021d4dfbdb31f25e5afa0322669a8eb2d032cd96e65ac37e020324c763 + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.27.7": + version: 7.27.7 + resolution: "@babel/plugin-transform-parameters@npm:7.27.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/f2da3804e047d9f1cfb27be6c014e2c7f6cf5e1e38290d1cb3cb2607859e3d6facb4ee8c8c1e336e9fbb440091a174ce95ce156582d7e8bf9c0e735d11681f0f + languageName: node + linkType: hard + +"@babel/plugin-transform-private-methods@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-private-methods@npm:7.28.6" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/fb504e2bfdcf3f734d2a90ab20d61427c58385f57f950d3de6ff4e6d12dd4aa7d552147312d218367e129b7920dccfc3230ba554de861986cda38921bad84067 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.28.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.3" + "@babel/helper-create-class-features-plugin": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/0f6bbc6ec3f93b556d3de7d56bf49335255fc4c43488e51a5025d6ee0286183fd3cf950ffcac1bbeed8a45777f860a49996455c8d3b4a04c3b1a5f28e697fe31 + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-property-literals@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/15713a87edd6db620d6e66eb551b4fbfff5b8232c460c7c76cedf98efdc5cd21080c97040231e19e06594c6d7dfa66e1ab3d0951e29d5814fb25e813f6d6209c + languageName: node + linkType: hard + +"@babel/plugin-transform-react-constant-elements@npm:^7.21.3": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-constant-elements@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/07fa88dd312c97d05de95e344a11a78e24d711e7bde879076d8880869ad7b0dc69c5a5ad056790595043cb9c533fd93af0ba015eed4631315282295f767ccfbe + languageName: node + linkType: hard + +"@babel/plugin-transform-react-display-name@npm:^7.28.0": + version: 7.28.0 + resolution: "@babel/plugin-transform-react-display-name@npm:7.28.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/f5f86d2ad92be3e962158f344c2e385e23e2dfae7c8c7dc32138fb2cc46f63f5e50386c9f6c6fc16dbf1792c7bb650ad92c18203d0c2c0bd875bc28b0b80ef30 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-development@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.27.1" + dependencies: + "@babel/plugin-transform-react-jsx": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/eb8c4b6a79dc5c49b41e928e2037e1ee0bbfa722e4fd74c0b7c0d11103c82c2c25c434000e1b051d534c7261ab5c92b6d1e85313bf1b26e37db3f051ae217b58 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.27.1": + version: 7.28.6 + resolution: "@babel/plugin-transform-react-jsx@npm:7.28.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.3" + "@babel/helper-module-imports": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/plugin-syntax-jsx": "npm:^7.28.6" + "@babel/types": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/cc75b9bb3997751df6cf7e86afe1b3fa33130b5031a412f6f12cc5faec083650fe852de0af5ec8f88d3588cc3428a3f514d3bc1f423d26f8b014cc5dff9f15a7 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-pure-annotations@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.27.1" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/34bc090f4a7e460d82a851971b4d0f32e4bb519bafb927154f4174506283fe02b0f471fc20655c6050a8bf7b748bfa31c7e8f7d688849476d8266623554fbb28 + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/plugin-transform-regenerator@npm:7.29.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/86c7db9b97f85ee47c0fae0528802cbc06e5775e61580ee905335c16bb971270086764a3859873d9adcd7d0f913a5b93eb0dc271aec8fb9e93e090e4ac95e29e + languageName: node + linkType: hard + +"@babel/plugin-transform-regexp-modifiers@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-regexp-modifiers@npm:7.28.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.28.5" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/97e36b086800f71694fa406abc00192e3833662f2bdd5f51c018bd0c95eef247c4ae187417c207d03a9c5374342eac0bb65a39112c431a9b23b09b1eda1562e5 + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-reserved-words@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/e1a87691cce21a644a474d7c9a8107d4486c062957be32042d40f0a3d0cc66e00a3150989655019c255ff020d2640ac16aaf544792717d586f219f3bad295567 + languageName: node + linkType: hard + +"@babel/plugin-transform-runtime@npm:^7.25.9": + version: 7.29.0 + resolution: "@babel/plugin-transform-runtime@npm:7.29.0" + dependencies: + "@babel/helper-module-imports": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + babel-plugin-polyfill-corejs2: "npm:^0.4.14" + babel-plugin-polyfill-corejs3: "npm:^0.13.0" + babel-plugin-polyfill-regenerator: "npm:^0.6.5" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/05a451cb96a1e6ccfdd1a123773208615cd14cb156aa0aa99a448d86e4326b36b9ab2be8267037bd27644a5918dac88378b791d020b3c08a4fd8f3415621a006 + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/bd5544b89520a22c41a6df5ddac9039821d3334c0ef364d18b0ba9674c5071c223bcc98be5867dc3865cb10796882b7594e2c40dedaff38e1b1273913fe353e1 + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-spread@npm:7.28.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/bcac50e558d6f0c501cbce19ec197af558cef51fe3b3a6eba27276e323e57a5be28109b4264a5425ac12a67bf95d6af9c2a42b05e79c522ce913fb9529259d76 + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5698df2d924f0b1b7bdb7ef370e83f99ed3f0964eb3b9c27d774d021bee7f6d45f9a73e2be369d90b4aff1603ce29827f8743f091789960e7669daf9c3cda850 + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-template-literals@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/c90f403e42ef062b60654d1c122c70f3ec6f00c2f304b0931ebe6d0b432498ef8a5ef9266ddf00debc535f8390842207e44d3900eff1d2bab0cc1a700f03e083 + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a13c68015311fefa06a51830bc69d5badd06c881b13d5cf9ba04bf7c73e3fc6311cc889e18d9645ce2a64a79456dc9c7be88476c0b6802f62a686cb6f662ecd6 + languageName: node + linkType: hard + +"@babel/plugin-transform-typescript@npm:^7.28.5": + version: 7.28.6 + resolution: "@babel/plugin-transform-typescript@npm:7.28.6" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.27.3" + "@babel/helper-create-class-features-plugin": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.27.1" + "@babel/plugin-syntax-typescript": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/72dbfd3e5f71c4e30445e610758ec0eef65347fafd72bd46f4903733df0d537663a72a81c1626f213a0feab7afc68ba83f1648ffece888dd0868115c9cb748f6 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a6809e0ca69d77ee9804e0c1164e8a2dea5e40718f6dcf234aeddf7292e7414f7ee331d87f17eb6f160823a329d1d6751bd49b35b392ac4a6efc032e4d3038d8 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-property-regex@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.28.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.28.5" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b25f8cde643f4f47e0fa4f7b5c552e2dfbb6ad0ce07cf40f7e8ae40daa9855ad855d76d4d6d010153b74e48c8794685955c92ca637c0da152ce5f0fa9e7c90fa + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-regex@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.27.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.27.1" + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/6abda1bcffb79feba6f5c691859cdbe984cc96481ea65d5af5ba97c2e843154005f0886e25006a37a2d213c0243506a06eaeafd93a040dbe1f79539016a0d17a + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-sets-regex@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.28.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.28.5" + "@babel/helper-plugin-utils": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/c03c8818736b138db73d1f7a96fbfa22d1994639164d743f0f00e6383d3b7b3144d333de960ff4afad0bddd0baaac257295e3316969eba995b1b6a1b4dec933e + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.20.2, @babel/preset-env@npm:^7.25.9": + version: 7.29.2 + resolution: "@babel/preset-env@npm:7.29.2" + dependencies: + "@babel/compat-data": "npm:^7.29.0" + "@babel/helper-compilation-targets": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" + "@babel/helper-validator-option": "npm:^7.27.1" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.28.5" + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^7.27.1" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.27.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.27.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.28.6" + "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-import-assertions": "npm:^7.28.6" + "@babel/plugin-syntax-import-attributes": "npm:^7.28.6" + "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" + "@babel/plugin-transform-arrow-functions": "npm:^7.27.1" + "@babel/plugin-transform-async-generator-functions": "npm:^7.29.0" + "@babel/plugin-transform-async-to-generator": "npm:^7.28.6" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.27.1" + "@babel/plugin-transform-block-scoping": "npm:^7.28.6" + "@babel/plugin-transform-class-properties": "npm:^7.28.6" + "@babel/plugin-transform-class-static-block": "npm:^7.28.6" + "@babel/plugin-transform-classes": "npm:^7.28.6" + "@babel/plugin-transform-computed-properties": "npm:^7.28.6" + "@babel/plugin-transform-destructuring": "npm:^7.28.5" + "@babel/plugin-transform-dotall-regex": "npm:^7.28.6" + "@babel/plugin-transform-duplicate-keys": "npm:^7.27.1" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^7.29.0" + "@babel/plugin-transform-dynamic-import": "npm:^7.27.1" + "@babel/plugin-transform-explicit-resource-management": "npm:^7.28.6" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.28.6" + "@babel/plugin-transform-export-namespace-from": "npm:^7.27.1" + "@babel/plugin-transform-for-of": "npm:^7.27.1" + "@babel/plugin-transform-function-name": "npm:^7.27.1" + "@babel/plugin-transform-json-strings": "npm:^7.28.6" + "@babel/plugin-transform-literals": "npm:^7.27.1" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.28.6" + "@babel/plugin-transform-member-expression-literals": "npm:^7.27.1" + "@babel/plugin-transform-modules-amd": "npm:^7.27.1" + "@babel/plugin-transform-modules-commonjs": "npm:^7.28.6" + "@babel/plugin-transform-modules-systemjs": "npm:^7.29.0" + "@babel/plugin-transform-modules-umd": "npm:^7.27.1" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.29.0" + "@babel/plugin-transform-new-target": "npm:^7.27.1" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.28.6" + "@babel/plugin-transform-numeric-separator": "npm:^7.28.6" + "@babel/plugin-transform-object-rest-spread": "npm:^7.28.6" + "@babel/plugin-transform-object-super": "npm:^7.27.1" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.28.6" + "@babel/plugin-transform-optional-chaining": "npm:^7.28.6" + "@babel/plugin-transform-parameters": "npm:^7.27.7" + "@babel/plugin-transform-private-methods": "npm:^7.28.6" + "@babel/plugin-transform-private-property-in-object": "npm:^7.28.6" + "@babel/plugin-transform-property-literals": "npm:^7.27.1" + "@babel/plugin-transform-regenerator": "npm:^7.29.0" + "@babel/plugin-transform-regexp-modifiers": "npm:^7.28.6" + "@babel/plugin-transform-reserved-words": "npm:^7.27.1" + "@babel/plugin-transform-shorthand-properties": "npm:^7.27.1" + "@babel/plugin-transform-spread": "npm:^7.28.6" + "@babel/plugin-transform-sticky-regex": "npm:^7.27.1" + "@babel/plugin-transform-template-literals": "npm:^7.27.1" + "@babel/plugin-transform-typeof-symbol": "npm:^7.27.1" + "@babel/plugin-transform-unicode-escapes": "npm:^7.27.1" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.28.6" + "@babel/plugin-transform-unicode-regex": "npm:^7.27.1" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.28.6" + "@babel/preset-modules": "npm:0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2: "npm:^0.4.15" + babel-plugin-polyfill-corejs3: "npm:^0.14.0" + babel-plugin-polyfill-regenerator: "npm:^0.6.6" + core-js-compat: "npm:^3.48.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/d49cb005f2dbc3f2293ab6d80ee8f1380e6215af5518fe26b087c8961c1ea8ebaa554dfce589abe1fbebac25ad7c2515d943dec3859ea2d4981a3f8f4711c580 + languageName: node + linkType: hard + +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.0.0" + "@babel/types": "npm:^7.4.4" + esutils: "npm:^2.0.2" + peerDependencies: + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/9d02f70d7052446c5f3a4fb39e6b632695fb6801e46d31d7f7c5001f7c18d31d1ea8369212331ca7ad4e7877b73231f470b0d559162624128f1b80fe591409e6 + languageName: node + linkType: hard + +"@babel/preset-react@npm:^7.18.6, @babel/preset-react@npm:^7.25.9": + version: 7.28.5 + resolution: "@babel/preset-react@npm:7.28.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-validator-option": "npm:^7.27.1" + "@babel/plugin-transform-react-display-name": "npm:^7.28.0" + "@babel/plugin-transform-react-jsx": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-development": "npm:^7.27.1" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/0d785e708ff301f4102bd4738b77e550e32f981e54dfd3de1191b4d68306bbb934d2d465fc78a6bc22fff0a6b3ce3195a53984f52755c4349e7264c7e01e8c7c + languageName: node + linkType: hard + +"@babel/preset-typescript@npm:^7.21.0, @babel/preset-typescript@npm:^7.25.9": + version: 7.28.5 + resolution: "@babel/preset-typescript@npm:7.28.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-validator-option": "npm:^7.27.1" + "@babel/plugin-syntax-jsx": "npm:^7.27.1" + "@babel/plugin-transform-modules-commonjs": "npm:^7.27.1" + "@babel/plugin-transform-typescript": "npm:^7.28.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b3d55548854c105085dd80f638147aa8295bc186d70492289242d6c857cb03a6c61ec15186440ea10ed4a71cdde7d495f5eb3feda46273f36b0ac926e8409629 + languageName: node + linkType: hard + +"@babel/runtime-corejs3@npm:^7.25.9": + version: 7.29.2 + resolution: "@babel/runtime-corejs3@npm:7.29.2" + dependencies: + core-js-pure: "npm:^3.48.0" + checksum: 10c0/24a9de8b592cf67fbe62c36c002a0da8c0456079a0543646a40e2b1b0838e7712f5ff49e9551624395ccd67a409c63e7c638b23e3bebbfdf54e373b1c707ebff + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.17.9, @babel/runtime@npm:^7.25.9": + version: 7.26.10 + resolution: "@babel/runtime@npm:7.26.10" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10c0/6dc6d88c7908f505c4f7770fb4677dfa61f68f659b943c2be1f2a99cb6680343462867abf2d49822adc435932919b36c77ac60125793e719ea8745f2073d3745 + languageName: node + linkType: hard + +"@babel/template@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/template@npm:7.28.6" + dependencies: + "@babel/code-frame": "npm:^7.28.6" + "@babel/parser": "npm:^7.28.6" + "@babel/types": "npm:^7.28.6" + checksum: 10c0/66d87225ed0bc77f888181ae2d97845021838c619944877f7c4398c6748bcf611f216dfd6be74d39016af502bca876e6ce6873db3c49e4ac354c56d34d57e9f5 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.5, @babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.29.0": + version: 7.29.0 + resolution: "@babel/traverse@npm:7.29.0" + dependencies: + "@babel/code-frame": "npm:^7.29.0" + "@babel/generator": "npm:^7.29.0" + "@babel/helper-globals": "npm:^7.28.0" + "@babel/parser": "npm:^7.29.0" + "@babel/template": "npm:^7.28.6" + "@babel/types": "npm:^7.29.0" + debug: "npm:^4.3.1" + checksum: 10c0/f63ef6e58d02a9fbf3c0e2e5f1c877da3e0bc57f91a19d2223d53e356a76859cbaf51171c9211c71816d94a0e69efa2732fd27ffc0e1bbc84b636e60932333eb + languageName: node + linkType: hard + +"@babel/types@npm:^7.21.3, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0, @babel/types@npm:^7.4.4": + version: 7.29.0 + resolution: "@babel/types@npm:7.29.0" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.28.5" + checksum: 10c0/23cc3466e83bcbfab8b9bd0edaafdb5d4efdb88b82b3be6728bbade5ba2f0996f84f63b1c5f7a8c0d67efded28300898a5f930b171bb40b311bca2029c4e9b4f + languageName: node + linkType: hard + +"@braintree/sanitize-url@npm:^7.1.1": + version: 7.1.2 + resolution: "@braintree/sanitize-url@npm:7.1.2" + checksum: 10c0/62f2aa0cf58626e3880b2dc1025c42064b4639abd157ae4e1c35f4c2f5031e9273772046a423979845069c814e27ff818e8e669280dc53585e6f033d5b7a59cb + languageName: node + linkType: hard + +"@chevrotain/cst-dts-gen@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/cst-dts-gen@npm:11.1.2" + dependencies: + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/372a9573a404a1d717c92875024588a53d1eb078f12d2cd1d79d9c2c888c9b429eb62bbc85501b8ff168c14b22a675da99d97bb39b0a774e9fee000dc60fd8ff + languageName: node + linkType: hard + +"@chevrotain/gast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/gast@npm:11.1.2" + dependencies: + "@chevrotain/types": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/540bfc9270d752f398b29efe9c89bb907d2984a47db4308a943e50c1cbd261ee13ecbef15c0e07808cf476d835bc36e65854db0bd214c277296cc14013eca8f4 + languageName: node + linkType: hard + +"@chevrotain/regexp-to-ast@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/regexp-to-ast@npm:11.1.2" + checksum: 10c0/645f02ac94cb33e04c10547b197762c6936c7b7668966240684795ce131cb515a76b63e0cc500e787d669f1a36bd2f902ec518f27843ec857ecf9043c717527e + languageName: node + linkType: hard + +"@chevrotain/types@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/types@npm:11.1.2" + checksum: 10c0/c0c4679a3d407df34e18d5adfa7ac599b4a2bfddbf68da6e43678b9b3e16ab911de7766b37b9fc466261c3dead3db1b620e2e344f800fa9f0f381720475eda8f + languageName: node + linkType: hard + +"@chevrotain/utils@npm:11.1.2": + version: 11.1.2 + resolution: "@chevrotain/utils@npm:11.1.2" + checksum: 10c0/72989e7051781b9084252486712844c55e3b454318c7da4a5f6ded28dcd3947ba2882773a6bf09b7e744599e8c8025df8d3de0d487121734e6edb66999450438 + languageName: node + linkType: hard + +"@colors/colors@npm:1.5.0": + version: 1.5.0 + resolution: "@colors/colors@npm:1.5.0" + checksum: 10c0/eb42729851adca56d19a08e48d5a1e95efd2a32c55ae0323de8119052be0510d4b7a1611f2abcbf28c044a6c11e6b7d38f99fccdad7429300c37a8ea5fb95b44 + languageName: node + linkType: hard + +"@csstools/cascade-layer-name-parser@npm:^2.0.5": + version: 2.0.5 + resolution: "@csstools/cascade-layer-name-parser@npm:2.0.5" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10c0/b6c73d5c8132f922edc88b9df5272c93c9753945f1e1077b80d03b314076ffe03c2cc9bf6cbc85501ee7c7f27e477263df96997c9125fd2fd0cfe82fe2d7c141 + languageName: node + linkType: hard + +"@csstools/color-helpers@npm:^5.1.0": + version: 5.1.0 + resolution: "@csstools/color-helpers@npm:5.1.0" + checksum: 10c0/b7f99d2e455cf1c9b41a67a5327d5d02888cd5c8802a68b1887dffef537d9d4bc66b3c10c1e62b40bbed638b6c1d60b85a232f904ed7b39809c4029cb36567db + languageName: node + linkType: hard + +"@csstools/css-calc@npm:^2.1.4": + version: 2.1.4 + resolution: "@csstools/css-calc@npm:2.1.4" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10c0/42ce5793e55ec4d772083808a11e9fb2dfe36db3ec168713069a276b4c3882205b3507c4680224c28a5d35fe0bc2d308c77f8f2c39c7c09aad8747708eb8ddd8 + languageName: node + linkType: hard + +"@csstools/css-color-parser@npm:^3.1.0": + version: 3.1.0 + resolution: "@csstools/css-color-parser@npm:3.1.0" + dependencies: + "@csstools/color-helpers": "npm:^5.1.0" + "@csstools/css-calc": "npm:^2.1.4" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10c0/0e0c670ad54ec8ec4d9b07568b80defd83b9482191f5e8ca84ab546b7be6db5d7cc2ba7ac9fae54488b129a4be235d6183d3aab4416fec5e89351f73af4222c5 + languageName: node + linkType: hard + +"@csstools/css-parser-algorithms@npm:^3.0.5": + version: 3.0.5 + resolution: "@csstools/css-parser-algorithms@npm:3.0.5" + peerDependencies: + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10c0/d9a1c888bd43849ae3437ca39251d5c95d2c8fd6b5ccdb7c45491dfd2c1cbdc3075645e80901d120e4d2c1993db9a5b2d83793b779dbbabcfb132adb142eb7f7 + languageName: node + linkType: hard + +"@csstools/css-tokenizer@npm:^3.0.4": + version: 3.0.4 + resolution: "@csstools/css-tokenizer@npm:3.0.4" + checksum: 10c0/3b589f8e9942075a642213b389bab75a2d50d05d203727fcdac6827648a5572674caff07907eff3f9a2389d86a4ee47308fafe4f8588f4a77b7167c588d2559f + languageName: node + linkType: hard + +"@csstools/media-query-list-parser@npm:^4.0.3": + version: 4.0.3 + resolution: "@csstools/media-query-list-parser@npm:4.0.3" + peerDependencies: + "@csstools/css-parser-algorithms": ^3.0.5 + "@csstools/css-tokenizer": ^3.0.4 + checksum: 10c0/e29d856d57e9a036694662163179fc061a99579f05e7c3c35438b3e063790ae8a9ee9f1fb4b4693d8fc7672ae0801764fe83762ab7b9df2921fcc6172cfd5584 + languageName: node + linkType: hard + +"@csstools/postcss-alpha-function@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-alpha-function@npm:1.0.1" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/35ca209e572534ade21ac5c18aad702aa492eb39e2d0e475f441371063418fe9650554e6a59b1318d3a615da83ef54d9a588faa27063ecc0a568ef7290a6b488 + languageName: node + linkType: hard + +"@csstools/postcss-cascade-layers@npm:^5.0.2": + version: 5.0.2 + resolution: "@csstools/postcss-cascade-layers@npm:5.0.2" + dependencies: + "@csstools/selector-specificity": "npm:^5.0.0" + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/dd8e29cfd3a93932fa35e3a59aa62fd2e720772d450f40f38f65ce1e736e2fe839635eb6f033abcc8ee8bc2856161a297f4458b352b26d2216856feb03176612 + languageName: node + linkType: hard + +"@csstools/postcss-color-function-display-p3-linear@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-color-function-display-p3-linear@npm:1.0.1" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/d02d45410c9257f5620c766f861f8fa3762b74ef01fdba8060b33a4c98f929e2219cd476b25bd4181ac186158a4d99a0da555c0b6ba45a7ac4a3a5885baad1f5 + languageName: node + linkType: hard + +"@csstools/postcss-color-function@npm:^4.0.12": + version: 4.0.12 + resolution: "@csstools/postcss-color-function@npm:4.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/a355b04d90f89c8e37a4a23543151558060acc68fb2e7d1c3549bebeeae2b147eec26af1fbc6ee690f0ba4830263f2d181f5331d16d3483b5542be46996fa755 + languageName: node + linkType: hard + +"@csstools/postcss-color-mix-function@npm:^3.0.12": + version: 3.0.12 + resolution: "@csstools/postcss-color-mix-function@npm:3.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/3e98a5118852083d1f87a3f842f78088192b1f9f08fdf1f3b3ef1e8969e18fdadc1e3bcac3d113a07c8917a7e8fa65fdec55a31df9a1b726c8d7ae89db86e8e5 + languageName: node + linkType: hard + +"@csstools/postcss-color-mix-variadic-function-arguments@npm:^1.0.2": + version: 1.0.2 + resolution: "@csstools/postcss-color-mix-variadic-function-arguments@npm:1.0.2" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/34073f0f0d33e4958f90763e692955a8e8c678b74284234497c4aa0d2143756e1b3616e0c09832caad498870e227ca0a681316afe3a71224fc40ade0ead1bdd9 + languageName: node + linkType: hard + +"@csstools/postcss-content-alt-text@npm:^2.0.8": + version: 2.0.8 + resolution: "@csstools/postcss-content-alt-text@npm:2.0.8" + dependencies: + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/4c330cc2a1e434688a62613ecceb1434cd725ce024c1ad8d4a4c76b9839d1f3ea8566a8c6494921e2b46ec7feef6af8ed6548c216dcb8f0feab4b1d52c96228e + languageName: node + linkType: hard + +"@csstools/postcss-contrast-color-function@npm:^2.0.12": + version: 2.0.12 + resolution: "@csstools/postcss-contrast-color-function@npm:2.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/b783ce948cdf1513ee238e9115b42881a8d3e5d13c16038601b1c470d661cfaeeece4eea29904fb9fcae878bad86f766810fa798a703ab9ad4b0cf276b173f8f + languageName: node + linkType: hard + +"@csstools/postcss-exponential-functions@npm:^2.0.9": + version: 2.0.9 + resolution: "@csstools/postcss-exponential-functions@npm:2.0.9" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/78ea627a87fb23e12616c4e54150363b0e8793064634983dbe0368a0aca1ff73206c2d1f29845773daaf42787e7d1f180ce1b57c43e2b0d10da450101f9f34b6 + languageName: node + linkType: hard + +"@csstools/postcss-font-format-keywords@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/postcss-font-format-keywords@npm:4.0.0" + dependencies: + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/eb794fb95fefcac75e606d185255e601636af177866a317b0c6b6c375055e7240be53918229fd8d4bba00df01bedd2256bdac2b0ad4a4c2ec64f9d27cd6ff639 + languageName: node + linkType: hard + +"@csstools/postcss-gamut-mapping@npm:^2.0.11": + version: 2.0.11 + resolution: "@csstools/postcss-gamut-mapping@npm:2.0.11" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/490b8ccf10e30879a4415afbdd3646e1cdac3671586b7916855cf47a536f3be75eed014396056bde6528e0cb76d904e79bad78afc0b499e837264cf22519d145 + languageName: node + linkType: hard + +"@csstools/postcss-gradients-interpolation-method@npm:^5.0.12": + version: 5.0.12 + resolution: "@csstools/postcss-gradients-interpolation-method@npm:5.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/70b3d6c7050ce882ed2281e71eb4493531ae8d55d21899920eeeb6c205d90aaf430419a66235484ccce3a1a1891367dfc0ef772f3866ae3a9d8ec5ddd0cfe894 + languageName: node + linkType: hard + +"@csstools/postcss-hwb-function@npm:^4.0.12": + version: 4.0.12 + resolution: "@csstools/postcss-hwb-function@npm:4.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/d0dac34da9d7ac654060b6b27690a419718e990b21ff3e63266ea59934a865bc6aeae8eb8e1ca3e227a8b2a208657e3ab70ccdf0437f1f09d21ab848bbffcaa2 + languageName: node + linkType: hard + +"@csstools/postcss-ic-unit@npm:^4.0.4": + version: 4.0.4 + resolution: "@csstools/postcss-ic-unit@npm:4.0.4" + dependencies: + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/20168e70ecb4abf7a69e407d653b6c7c9c82f2c7b1da0920e1d035f62b5ef8552cc7f1b62e0dca318df13c348e79fba862e1a4bb0e9432119a82b10aeb511752 + languageName: node + linkType: hard + +"@csstools/postcss-initial@npm:^2.0.1": + version: 2.0.1 + resolution: "@csstools/postcss-initial@npm:2.0.1" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/dbff7084ef4f1c4647efe2b147001daf172003c15b5e22689f0540d03c8d362f2a332cd9cf136e6c8dcda7564ee30492a4267ea188f72cb9c1000fb9bcfbfef8 + languageName: node + linkType: hard + +"@csstools/postcss-is-pseudo-class@npm:^5.0.3": + version: 5.0.3 + resolution: "@csstools/postcss-is-pseudo-class@npm:5.0.3" + dependencies: + "@csstools/selector-specificity": "npm:^5.0.0" + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/7980f1cabf32850bac72552e4e9de47412359e36e259a92b9b9af25dae4cce42bbcc5fdca8f384a589565bf383ecb23dec3af9f084d8df18b82552318b2841b6 + languageName: node + linkType: hard + +"@csstools/postcss-light-dark-function@npm:^2.0.11": + version: 2.0.11 + resolution: "@csstools/postcss-light-dark-function@npm:2.0.11" + dependencies: + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/0175be41bb0044a48bc98d5c55cce41ed6b9ada88253c5f20d0ca17287cba4b429742b458ac5744675b9a286109e13ac51d64e226ab16040d7b051ba64c0c77b + languageName: node + linkType: hard + +"@csstools/postcss-logical-float-and-clear@npm:^3.0.0": + version: 3.0.0 + resolution: "@csstools/postcss-logical-float-and-clear@npm:3.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/71a20e8c37877bf68ae615d7bb93fc11b4f8da8be8b1dc1a6e0fc69e27f189712ed71436b8ed51fa69fdb98b8e6718df2b5f42f246c4d39badaf0e43020fcfd4 + languageName: node + linkType: hard + +"@csstools/postcss-logical-overflow@npm:^2.0.0": + version: 2.0.0 + resolution: "@csstools/postcss-logical-overflow@npm:2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/0e103343d3ff8b34eef01b02355c5e010d272fd12d149a242026bb13ab1577b7f3a11fd4514be9342d96f73d61dac1f093a9bd36ece591753ed09a84eb7fca0a + languageName: node + linkType: hard + +"@csstools/postcss-logical-overscroll-behavior@npm:^2.0.0": + version: 2.0.0 + resolution: "@csstools/postcss-logical-overscroll-behavior@npm:2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/1649601bb26f04d760fb5ebc42cdf414fa2a380b8ec22fe1c117f664c286665a786bd7bbda01b7e7567eaf3cc018a4f36a5c9805f6751cc497da223e0ffe9524 + languageName: node + linkType: hard + +"@csstools/postcss-logical-resize@npm:^3.0.0": + version: 3.0.0 + resolution: "@csstools/postcss-logical-resize@npm:3.0.0" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/4f12efcaf5468ff359bb3f32f0f66034b9acc9b3ac21fcd2f30a1c8998fc653ebac0091f35c8b7e8dbfe6ccf595aee67f9b06a67adf45a8844e49a82d98b4386 + languageName: node + linkType: hard + +"@csstools/postcss-logical-viewport-units@npm:^3.0.4": + version: 3.0.4 + resolution: "@csstools/postcss-logical-viewport-units@npm:3.0.4" + dependencies: + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/f0b5ba38acde3bf0ca880c6e0a883950c99fa9919b0e6290c894d5716569663590f26aa1170fd9483ce14544e46afac006ab3b02781410d5e7c8dd1467c674ce + languageName: node + linkType: hard + +"@csstools/postcss-media-minmax@npm:^2.0.9": + version: 2.0.9 + resolution: "@csstools/postcss-media-minmax@npm:2.0.9" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/media-query-list-parser": "npm:^4.0.3" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/d82622ee9de6eacba1abbf31718cd58759d158ed8a575f36f08e982d07a7d83e51fb184178b96c6f7b76cb333bb33cac04d06a750b6b9c5c43ae1c56232880f9 + languageName: node + linkType: hard + +"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^3.0.5": + version: 3.0.5 + resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:3.0.5" + dependencies: + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/media-query-list-parser": "npm:^4.0.3" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/a47abdaa7f4b26596bd9d6bb77aed872a232fc12bd144d2c062d9da626e8dfd8336e2fff67617dba61a1666c2b8027145b390d70d5cd4d4f608604e077cfb04e + languageName: node + linkType: hard + +"@csstools/postcss-nested-calc@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/postcss-nested-calc@npm:4.0.0" + dependencies: + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/fb61512fa4909bdf0ee32a23e771145086c445f2208a737b52093c8adfab7362c56d3aeaf2a6e33ffcec067e99a07219775465d2fbb1a3ac30cdcfb278b218b7 + languageName: node + linkType: hard + +"@csstools/postcss-normalize-display-values@npm:^4.0.1": + version: 4.0.1 + resolution: "@csstools/postcss-normalize-display-values@npm:4.0.1" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/5d19364bad8554b047cebd94ad7e203723ed76abaf690e4b92c74e6fc7c3642cb8858ade3263da61aff26d97bb258af567b1036e97865b7aa3b17522241fd1e1 + languageName: node + linkType: hard + +"@csstools/postcss-oklab-function@npm:^4.0.12": + version: 4.0.12 + resolution: "@csstools/postcss-oklab-function@npm:4.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/40d4f51b568c8299c054f8971d0e85fa7da609ba23ce6c84dc17e16bc3838640ed6da75c3886dc9a96a11005773c6e23cba13a5510c781b2d633d07ad7bda6b7 + languageName: node + linkType: hard + +"@csstools/postcss-position-area-property@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-position-area-property@npm:1.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/38f770454d46bfed01d43a3f5e7ac07d3111399b374a7198ae6503cdb6288e410c7b4199f5a7af8f16aeb688216445ade97be417c084313d6c56f55e50d34559 + languageName: node + linkType: hard + +"@csstools/postcss-progressive-custom-properties@npm:^4.2.1": + version: 4.2.1 + resolution: "@csstools/postcss-progressive-custom-properties@npm:4.2.1" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/56e9a147799719fd5c550c035437693dd50cdfef46d66a4f2ce8f196e1006a096aa47d412710a89c3dc9808068a0a101c7f607a507ed68e925580c6f921e84d5 + languageName: node + linkType: hard + +"@csstools/postcss-property-rule-prelude-list@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-property-rule-prelude-list@npm:1.0.0" + dependencies: + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/ae8bbca3a77ca59c21c11899a904f9d9417a19a3359d01dee042e0489b7ddfe7cea13ae275b7e7936d9b0b99c0a13f7f685f962cd63ca3d3d2b6e5eacc293a0d + languageName: node + linkType: hard + +"@csstools/postcss-random-function@npm:^2.0.1": + version: 2.0.1 + resolution: "@csstools/postcss-random-function@npm:2.0.1" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/475bacf685b8bb82942d388e9e3b95f4156800f370299f19f5acc490475dc2813100de81a5a6bf48b696b4d83247622005b616af3166a668556b4b1aceded70d + languageName: node + linkType: hard + +"@csstools/postcss-relative-color-syntax@npm:^3.0.12": + version: 3.0.12 + resolution: "@csstools/postcss-relative-color-syntax@npm:3.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/11af386c8193e22c148ac034eee94c56da3060bdbde3196d2d641b088e12de35bef187bcd7d421f9e4d49c4f1cfc28b24e136e62107e02ed7007a3a28f635d06 + languageName: node + linkType: hard + +"@csstools/postcss-scope-pseudo-class@npm:^4.0.1": + version: 4.0.1 + resolution: "@csstools/postcss-scope-pseudo-class@npm:4.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/6a0ca50fae655f4498200d1ce298ca794c85fbe2e3fd5d6419843254f055df5007a973e09b5f1e78e376c02b54278e411516c8d824300c68b265d3e5b311d7ee + languageName: node + linkType: hard + +"@csstools/postcss-sign-functions@npm:^1.1.4": + version: 1.1.4 + resolution: "@csstools/postcss-sign-functions@npm:1.1.4" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/ff58108b2527832a84c571a1f40224b5c8d2afa8db2fe3b1e3599ff6f3469d9f4c528a70eb3c25c5d7801e30474fabfec04e7c23bfdad8572ad492053cd4f899 + languageName: node + linkType: hard + +"@csstools/postcss-stepped-value-functions@npm:^4.0.9": + version: 4.0.9 + resolution: "@csstools/postcss-stepped-value-functions@npm:4.0.9" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/f143ca06338c30abb2aa37adc3d7e43a78f3b4493093160cb5babe3ec8cf6b86d83876746ee8e162db87b5e9af6e0066958d89fe8b4a503a29568e5c57c1bf8a + languageName: node + linkType: hard + +"@csstools/postcss-syntax-descriptor-syntax-production@npm:^1.0.1": + version: 1.0.1 + resolution: "@csstools/postcss-syntax-descriptor-syntax-production@npm:1.0.1" + dependencies: + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/b9b3d84a50b86b1af1b8b7e56a64d5eebc1c89c323a5263306c5c69ddb05a4d468d7072a7786b0ea6601629035df0089565e9d98d55d0f4eb7201cf7ed1bb3e9 + languageName: node + linkType: hard + +"@csstools/postcss-system-ui-font-family@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-system-ui-font-family@npm:1.0.0" + dependencies: + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/6a81761ae3cae643659b1416a7a892cf1505474896193b8abc26cff319cb6b1a20b64c5330d64019fba458e058da3abc9407d0ebf0c102289c0b79ef99b4c6d6 + languageName: node + linkType: hard + +"@csstools/postcss-text-decoration-shorthand@npm:^4.0.3": + version: 4.0.3 + resolution: "@csstools/postcss-text-decoration-shorthand@npm:4.0.3" + dependencies: + "@csstools/color-helpers": "npm:^5.1.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/f6af7d5dcf599edcf76c5e396ef2d372bbe1c1f3fbaaccd91e91049e64b6ff68b44f459277aef0a8110baca3eaa21275012adc52ccb8c0fc526a4c35577f8fce + languageName: node + linkType: hard + +"@csstools/postcss-trigonometric-functions@npm:^4.0.9": + version: 4.0.9 + resolution: "@csstools/postcss-trigonometric-functions@npm:4.0.9" + dependencies: + "@csstools/css-calc": "npm:^2.1.4" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/6ba3d381c977c224f01d47a36f78c9b99d3b89d060a357a9f8840537fdf497d9587a28165dc74e96abdf02f8db0a277d3558646355085a74c8915ee73c6780d1 + languageName: node + linkType: hard + +"@csstools/postcss-unset-value@npm:^4.0.0": + version: 4.0.0 + resolution: "@csstools/postcss-unset-value@npm:4.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/8424ac700ded5bf59d49310335896f10c069e2c3fc6a676b5d13ca5a6fb78689b948f50494df875da284c4c76651deb005eafba70d87e693274628c5a685abfa + languageName: node + linkType: hard + +"@csstools/selector-resolve-nested@npm:^3.1.0": + version: 3.1.0 + resolution: "@csstools/selector-resolve-nested@npm:3.1.0" + peerDependencies: + postcss-selector-parser: ^7.0.0 + checksum: 10c0/c2b1a930ad03c1427ab90b28c4940424fb39e8175130148f16209be3a3937f7a146d5483ca1da1dfc100aa7ae86df713f0ee82d4bbaa9b986e7f47f35cb67cca + languageName: node + linkType: hard + +"@csstools/selector-specificity@npm:^5.0.0": + version: 5.0.0 + resolution: "@csstools/selector-specificity@npm:5.0.0" + peerDependencies: + postcss-selector-parser: ^7.0.0 + checksum: 10c0/186b444cabcdcdeb553bfe021f80c58bfe9ef38dcc444f2b1f34a5aab9be063ab4e753022b2d5792049c041c28cfbb78e4b707ec398459300e402030d35c07eb + languageName: node + linkType: hard + +"@csstools/utilities@npm:^2.0.0": + version: 2.0.0 + resolution: "@csstools/utilities@npm:2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/be5c31437b726928f64cd4bb3e47f5b90bfd2e2a69a8eaabd8e89cc6c0977e4f0f7ee48de50c8ed8b07e04e3956a02293247e0da3236d521fb2e836f88f65822 + languageName: node + linkType: hard + +"@discoveryjs/json-ext@npm:0.5.7": + version: 0.5.7 + resolution: "@discoveryjs/json-ext@npm:0.5.7" + checksum: 10c0/e10f1b02b78e4812646ddf289b7d9f2cb567d336c363b266bd50cd223cf3de7c2c74018d91cd2613041568397ef3a4a2b500aba588c6e5bd78c38374ba68f38c + languageName: node + linkType: hard + +"@docsearch/core@npm:4.6.2": + version: 4.6.2 + resolution: "@docsearch/core@npm:4.6.2" + peerDependencies: + "@types/react": ">= 16.8.0 < 20.0.0" + react: ">= 16.8.0 < 20.0.0" + react-dom: ">= 16.8.0 < 20.0.0" + peerDependenciesMeta: + "@types/react": + optional: true + react: + optional: true + react-dom: + optional: true + checksum: 10c0/daeda4af110bef09a094853c6e67e13f5183eaeabdc91b3b8ca008e02f34cbe8b16a812d5d0618ba4ff7dca64e0ca7da26cc8dfcba437a61305a6e9e2de7b1b1 + languageName: node + linkType: hard + +"@docsearch/css@npm:4.6.2": + version: 4.6.2 + resolution: "@docsearch/css@npm:4.6.2" + checksum: 10c0/2f86dcaa90871eec1b8f71de2ec2a7c3e64fac21167d4ee5b83e25df54706cb9709327dc41ca49cdde441b731bb3024c4afe67b2705736e0e11610e0ae4cdad2 + languageName: node + linkType: hard + +"@docsearch/docusaurus-adapter@npm:^4.6.2": + version: 4.6.2 + resolution: "@docsearch/docusaurus-adapter@npm:4.6.2" + dependencies: + "@docsearch/react": "npm:4.6.2" + "@docusaurus/core": "npm:^3.9.2" + "@docusaurus/plugin-content-docs": "npm:^3.9.2" + "@docusaurus/theme-common": "npm:^3.9.2" + "@docusaurus/theme-translations": "npm:^3.9.2" + algoliasearch: "npm:^5.37.0" + algoliasearch-helper: "npm:^3.26.0" + clsx: "npm:^2.0.0" + eta: "npm:^2.2.0" + fs-extra: "npm:^11.1.1" + joi: "npm:^17.9.2" + lodash: "npm:^4.17.21" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/26434e3714beec505ba93a9cb4c50e5933df449bddd450de169d986b62f36e9434ed7bf8bbb90cbba4007dac706fd774571a5fd28e93cc09f005c23d266c7bac + languageName: node + linkType: hard + +"@docsearch/react@npm:4.6.2, @docsearch/react@npm:^3.9.0 || ^4.3.2": + version: 4.6.2 + resolution: "@docsearch/react@npm:4.6.2" + dependencies: + "@algolia/autocomplete-core": "npm:1.19.2" + "@docsearch/core": "npm:4.6.2" + "@docsearch/css": "npm:4.6.2" + peerDependencies: + "@types/react": ">= 16.8.0 < 20.0.0" + react: ">= 16.8.0 < 20.0.0" + react-dom: ">= 16.8.0 < 20.0.0" + search-insights: ">= 1 < 3" + peerDependenciesMeta: + "@types/react": + optional: true + react: + optional: true + react-dom: + optional: true + search-insights: + optional: true + checksum: 10c0/33f6ddc1d6f648e0b80f86435c80654a59ddff9deb6a9236b863438a9cbc1b0283fa30437819e01d861451c88ea88990f7115e8b669a5d8ae7534decb71b085b + languageName: node + linkType: hard + +"@docusaurus/babel@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/babel@npm:3.10.0" + dependencies: + "@babel/core": "npm:^7.25.9" + "@babel/generator": "npm:^7.25.9" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-transform-runtime": "npm:^7.25.9" + "@babel/preset-env": "npm:^7.25.9" + "@babel/preset-react": "npm:^7.25.9" + "@babel/preset-typescript": "npm:^7.25.9" + "@babel/runtime": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + babel-plugin-dynamic-import-node: "npm:^2.3.3" + fs-extra: "npm:^11.1.1" + tslib: "npm:^2.6.0" + checksum: 10c0/d79bd3e8805036e35b09ec4c7ebbf6060b07c1a375b3d27c727cc3122d25c9fddd98d450a22b70eaa9f7f3be0a7c3c5bd36819a7c1abcde4c7b4d3356248a9e3 + languageName: node + linkType: hard + +"@docusaurus/babel@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/babel@npm:3.9.2" + dependencies: + "@babel/core": "npm:^7.25.9" + "@babel/generator": "npm:^7.25.9" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-transform-runtime": "npm:^7.25.9" + "@babel/preset-env": "npm:^7.25.9" + "@babel/preset-react": "npm:^7.25.9" + "@babel/preset-typescript": "npm:^7.25.9" + "@babel/runtime": "npm:^7.25.9" + "@babel/runtime-corejs3": "npm:^7.25.9" + "@babel/traverse": "npm:^7.25.9" + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + babel-plugin-dynamic-import-node: "npm:^2.3.3" + fs-extra: "npm:^11.1.1" + tslib: "npm:^2.6.0" + checksum: 10c0/8147451a8ba79d35405ec8720c1cded7e84643867cb32877827799e5d36932cf56beaefd9fe4b25b9d855b38a9c08bc5397faddf73b63d7c52b05bf24ca99ee8 + languageName: node + linkType: hard + +"@docusaurus/bundler@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/bundler@npm:3.10.0" + dependencies: + "@babel/core": "npm:^7.25.9" + "@docusaurus/babel": "npm:3.10.0" + "@docusaurus/cssnano-preset": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + babel-loader: "npm:^9.2.1" + clean-css: "npm:^5.3.3" + copy-webpack-plugin: "npm:^11.0.0" + css-loader: "npm:^6.11.0" + css-minimizer-webpack-plugin: "npm:^5.0.1" + cssnano: "npm:^6.1.2" + file-loader: "npm:^6.2.0" + html-minifier-terser: "npm:^7.2.0" + mini-css-extract-plugin: "npm:^2.9.2" + null-loader: "npm:^4.0.1" + postcss: "npm:^8.5.4" + postcss-loader: "npm:^7.3.4" + postcss-preset-env: "npm:^10.2.1" + terser-webpack-plugin: "npm:^5.3.9" + tslib: "npm:^2.6.0" + url-loader: "npm:^4.1.1" + webpack: "npm:^5.95.0" + webpackbar: "npm:^6.0.1" + peerDependencies: + "@docusaurus/faster": "*" + peerDependenciesMeta: + "@docusaurus/faster": + optional: true + checksum: 10c0/49af1eba5e45126e972f943148b891c9e167e4510e6f349060ef210c648f28b5ee6344280e1ade0c2e1317bdd165ed3615aa71f95e91bd11e00a7dbb6795a0e3 + languageName: node + linkType: hard + +"@docusaurus/bundler@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/bundler@npm:3.9.2" + dependencies: + "@babel/core": "npm:^7.25.9" + "@docusaurus/babel": "npm:3.9.2" + "@docusaurus/cssnano-preset": "npm:3.9.2" + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/types": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + babel-loader: "npm:^9.2.1" + clean-css: "npm:^5.3.3" + copy-webpack-plugin: "npm:^11.0.0" + css-loader: "npm:^6.11.0" + css-minimizer-webpack-plugin: "npm:^5.0.1" + cssnano: "npm:^6.1.2" + file-loader: "npm:^6.2.0" + html-minifier-terser: "npm:^7.2.0" + mini-css-extract-plugin: "npm:^2.9.2" + null-loader: "npm:^4.0.1" + postcss: "npm:^8.5.4" + postcss-loader: "npm:^7.3.4" + postcss-preset-env: "npm:^10.2.1" + terser-webpack-plugin: "npm:^5.3.9" + tslib: "npm:^2.6.0" + url-loader: "npm:^4.1.1" + webpack: "npm:^5.95.0" + webpackbar: "npm:^6.0.1" + peerDependencies: + "@docusaurus/faster": "*" + peerDependenciesMeta: + "@docusaurus/faster": + optional: true + checksum: 10c0/dcbb7d51eef3fcd57161cb356f63487dbc5a433eea02bc0dfb2a59439884543e76efa3c311ca01c582c2ca33caff19e887303bf72aad04ee374fd013fdcca31f + languageName: node + linkType: hard + +"@docusaurus/core@npm:3.10.0, @docusaurus/core@npm:^3.10.0": + version: 3.10.0 + resolution: "@docusaurus/core@npm:3.10.0" + dependencies: + "@docusaurus/babel": "npm:3.10.0" + "@docusaurus/bundler": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/mdx-loader": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + boxen: "npm:^6.2.1" + chalk: "npm:^4.1.2" + chokidar: "npm:^3.5.3" + cli-table3: "npm:^0.6.3" + combine-promises: "npm:^1.1.0" + commander: "npm:^5.1.0" + core-js: "npm:^3.31.1" + detect-port: "npm:^1.5.1" + escape-html: "npm:^1.0.3" + eta: "npm:^2.2.0" + eval: "npm:^0.1.8" + execa: "npm:^5.1.1" + fs-extra: "npm:^11.1.1" + html-tags: "npm:^3.3.1" + html-webpack-plugin: "npm:^5.6.0" + leven: "npm:^3.1.0" + lodash: "npm:^4.17.21" + open: "npm:^8.4.0" + p-map: "npm:^4.0.0" + prompts: "npm:^2.4.2" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + react-loadable: "npm:@docusaurus/react-loadable@6.0.0" + react-loadable-ssr-addon-v5-slorber: "npm:^1.0.3" + react-router: "npm:^5.3.4" + react-router-config: "npm:^5.1.1" + react-router-dom: "npm:^5.3.4" + semver: "npm:^7.5.4" + serve-handler: "npm:^6.1.7" + tinypool: "npm:^1.0.2" + tslib: "npm:^2.6.0" + update-notifier: "npm:^6.0.2" + webpack: "npm:^5.95.0" + webpack-bundle-analyzer: "npm:^4.10.2" + webpack-dev-server: "npm:^5.2.2" + webpack-merge: "npm:^6.0.1" + peerDependencies: + "@docusaurus/faster": "*" + "@mdx-js/react": ^3.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@docusaurus/faster": + optional: true + bin: + docusaurus: bin/docusaurus.mjs + checksum: 10c0/2a00cd5f1a22a737d37d127f5e5e6aee3ed51563884136fc76d2fa97cb71a7d577e28959f25ec2065c0e232efc003def1d6db94fcee0533063de87484bb39c86 + languageName: node + linkType: hard + +"@docusaurus/core@npm:3.9.2, @docusaurus/core@npm:^3.9.2": + version: 3.9.2 + resolution: "@docusaurus/core@npm:3.9.2" + dependencies: + "@docusaurus/babel": "npm:3.9.2" + "@docusaurus/bundler": "npm:3.9.2" + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/mdx-loader": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + "@docusaurus/utils-common": "npm:3.9.2" + "@docusaurus/utils-validation": "npm:3.9.2" + boxen: "npm:^6.2.1" + chalk: "npm:^4.1.2" + chokidar: "npm:^3.5.3" + cli-table3: "npm:^0.6.3" + combine-promises: "npm:^1.1.0" + commander: "npm:^5.1.0" + core-js: "npm:^3.31.1" + detect-port: "npm:^1.5.1" + escape-html: "npm:^1.0.3" + eta: "npm:^2.2.0" + eval: "npm:^0.1.8" + execa: "npm:5.1.1" + fs-extra: "npm:^11.1.1" + html-tags: "npm:^3.3.1" + html-webpack-plugin: "npm:^5.6.0" + leven: "npm:^3.1.0" + lodash: "npm:^4.17.21" + open: "npm:^8.4.0" + p-map: "npm:^4.0.0" + prompts: "npm:^2.4.2" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + react-loadable: "npm:@docusaurus/react-loadable@6.0.0" + react-loadable-ssr-addon-v5-slorber: "npm:^1.0.1" + react-router: "npm:^5.3.4" + react-router-config: "npm:^5.1.1" + react-router-dom: "npm:^5.3.4" + semver: "npm:^7.5.4" + serve-handler: "npm:^6.1.6" + tinypool: "npm:^1.0.2" + tslib: "npm:^2.6.0" + update-notifier: "npm:^6.0.2" + webpack: "npm:^5.95.0" + webpack-bundle-analyzer: "npm:^4.10.2" + webpack-dev-server: "npm:^5.2.2" + webpack-merge: "npm:^6.0.1" + peerDependencies: + "@mdx-js/react": ^3.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + bin: + docusaurus: bin/docusaurus.mjs + checksum: 10c0/6058e2ca596ba0225f26f15baaf0c8fa5e91ddf794c3b942161702c44833baaf15be3acb71d42cf6e359a83e80be609485b6c1080802927591fe38bfc915aa11 + languageName: node + linkType: hard + +"@docusaurus/cssnano-preset@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/cssnano-preset@npm:3.10.0" + dependencies: + cssnano-preset-advanced: "npm:^6.1.2" + postcss: "npm:^8.5.4" + postcss-sort-media-queries: "npm:^5.2.0" + tslib: "npm:^2.6.0" + checksum: 10c0/635df6b05241f73b333b3d7d451d37ec56d7982a8c430afc2e8e8cf7c9e506b499b64d6bba14ccdf79b8afe84452d159516897741aa2fa838194964574da8881 + languageName: node + linkType: hard + +"@docusaurus/cssnano-preset@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/cssnano-preset@npm:3.9.2" + dependencies: + cssnano-preset-advanced: "npm:^6.1.2" + postcss: "npm:^8.5.4" + postcss-sort-media-queries: "npm:^5.2.0" + tslib: "npm:^2.6.0" + checksum: 10c0/98ca8939ba9c7c6d45cccdaa4028412cd84ea04c39b641d14e3870ee880d83cef8e04cdb485327b36e40550676ee1d614f1e89c9aa822b78e7d0c7dc0321f8db + languageName: node + linkType: hard + +"@docusaurus/faster@npm:^3.10.0": + version: 3.10.0 + resolution: "@docusaurus/faster@npm:3.10.0" + dependencies: + "@docusaurus/types": "npm:3.10.0" + "@rspack/core": "npm:^1.7.10" + "@swc/core": "npm:^1.7.39" + "@swc/html": "npm:^1.13.5" + browserslist: "npm:^4.24.2" + lightningcss: "npm:^1.27.0" + semver: "npm:^7.5.4" + swc-loader: "npm:^0.2.6" + tslib: "npm:^2.6.0" + webpack: "npm:^5.95.0" + peerDependencies: + "@docusaurus/types": "*" + checksum: 10c0/9e2b1b19a67443c23eceda80606a0e305a586addf991724b923f7756cfdced1a0d6d64426a1790fa81bbc0032ab56041823fe4a694d2392b0ef4ad85dc4089e8 + languageName: node + linkType: hard + +"@docusaurus/logger@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/logger@npm:3.10.0" + dependencies: + chalk: "npm:^4.1.2" + tslib: "npm:^2.6.0" + checksum: 10c0/f9bc2b7037fb7dff8a5aba06807e4f9601e422b91d0bb7e462ecdb33d71e1c9ee3d9dfb5c37af66f6f35c43310e461857af0dda96531928af3c22678fa77ec18 + languageName: node + linkType: hard + +"@docusaurus/logger@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/logger@npm:3.9.2" + dependencies: + chalk: "npm:^4.1.2" + tslib: "npm:^2.6.0" + checksum: 10c0/a21e0796873386a9be56f25906092a5d67c9bba5e52abf88e4c3c69d7c1e21467c04b3650c2ff2b9a803507aa4946c4173612791a87f04480d63ed87207b124a + languageName: node + linkType: hard + +"@docusaurus/mdx-loader@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/mdx-loader@npm:3.10.0" + dependencies: + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + "@mdx-js/mdx": "npm:^3.0.0" + "@slorber/remark-comment": "npm:^1.0.0" + escape-html: "npm:^1.0.3" + estree-util-value-to-estree: "npm:^3.0.1" + file-loader: "npm:^6.2.0" + fs-extra: "npm:^11.1.1" + image-size: "npm:^2.0.2" + mdast-util-mdx: "npm:^3.0.0" + mdast-util-to-string: "npm:^4.0.0" + rehype-raw: "npm:^7.0.0" + remark-directive: "npm:^3.0.0" + remark-emoji: "npm:^4.0.0" + remark-frontmatter: "npm:^5.0.0" + remark-gfm: "npm:^4.0.0" + stringify-object: "npm:^3.3.0" + tslib: "npm:^2.6.0" + unified: "npm:^11.0.3" + unist-util-visit: "npm:^5.0.0" + url-loader: "npm:^4.1.1" + vfile: "npm:^6.0.1" + webpack: "npm:^5.88.1" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/0b94f20398a2fd39e54215895d2607d277d0cf3a80728adbbadcbf2443063e8e1082929242ccdc4ebe393c6c4010a5ccdecf6f2a8478d90b20c74d032940d33a + languageName: node + linkType: hard + +"@docusaurus/mdx-loader@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/mdx-loader@npm:3.9.2" + dependencies: + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + "@docusaurus/utils-validation": "npm:3.9.2" + "@mdx-js/mdx": "npm:^3.0.0" + "@slorber/remark-comment": "npm:^1.0.0" + escape-html: "npm:^1.0.3" + estree-util-value-to-estree: "npm:^3.0.1" + file-loader: "npm:^6.2.0" + fs-extra: "npm:^11.1.1" + image-size: "npm:^2.0.2" + mdast-util-mdx: "npm:^3.0.0" + mdast-util-to-string: "npm:^4.0.0" + rehype-raw: "npm:^7.0.0" + remark-directive: "npm:^3.0.0" + remark-emoji: "npm:^4.0.0" + remark-frontmatter: "npm:^5.0.0" + remark-gfm: "npm:^4.0.0" + stringify-object: "npm:^3.3.0" + tslib: "npm:^2.6.0" + unified: "npm:^11.0.3" + unist-util-visit: "npm:^5.0.0" + url-loader: "npm:^4.1.1" + vfile: "npm:^6.0.1" + webpack: "npm:^5.88.1" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/4f3afa817f16fd04dd338a35c04be59fdc0e799a93c6d56dc99b1f42f9a5156691737df62751e14466acbbd65c932e1f77d06a915c9c4ad8f2ad24b2f5479269 + languageName: node + linkType: hard + +"@docusaurus/module-type-aliases@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/module-type-aliases@npm:3.10.0" + dependencies: + "@docusaurus/types": "npm:3.10.0" + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + "@types/react-router-config": "npm:*" + "@types/react-router-dom": "npm:*" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + react-loadable: "npm:@docusaurus/react-loadable@6.0.0" + peerDependencies: + react: "*" + react-dom: "*" + checksum: 10c0/61952050bef257a0999db849a328655a4141d31b8d4fa4d54828da7ee8f710d7e592081a150c8b9750640bcaf78f3b7ca7165aefbcc0048c328407d582fe21b8 + languageName: node + linkType: hard + +"@docusaurus/module-type-aliases@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/module-type-aliases@npm:3.9.2" + dependencies: + "@docusaurus/types": "npm:3.9.2" + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + "@types/react-router-config": "npm:*" + "@types/react-router-dom": "npm:*" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + react-loadable: "npm:@docusaurus/react-loadable@6.0.0" + peerDependencies: + react: "*" + react-dom: "*" + checksum: 10c0/60f163ff9004bb1fcbbad94b18200b6bca967da14576f78f5c533f8535aae0a3a723245cb28e1ca93f9d5881d3f1077e03ebf12bbad59d0e1c6916300d086642 + languageName: node + linkType: hard + +"@docusaurus/plugin-client-redirects@npm:^3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-client-redirects@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + eta: "npm:^2.2.0" + fs-extra: "npm:^11.1.1" + lodash: "npm:^4.17.21" + tslib: "npm:^2.6.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/06dced23c81d0008a9b0856cad74b76d20d93f8191bc6484770f23473e128e46524442f6f7569d2df9d1c745bea6d2c8d18a70834395bc88335b233febb314fe + languageName: node + linkType: hard + +"@docusaurus/plugin-content-blog@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-content-blog@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/mdx-loader": "npm:3.10.0" + "@docusaurus/theme-common": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + cheerio: "npm:1.0.0-rc.12" + combine-promises: "npm:^1.1.0" + feed: "npm:^4.2.2" + fs-extra: "npm:^11.1.1" + lodash: "npm:^4.17.21" + schema-dts: "npm:^1.1.2" + srcset: "npm:^4.0.0" + tslib: "npm:^2.6.0" + unist-util-visit: "npm:^5.0.0" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.88.1" + peerDependencies: + "@docusaurus/plugin-content-docs": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/80295c4d217c45d2685d71e3e898e4e67715ce3ecf684063927e0f9c771a2156af2aefb813b61ed33d8a14bc0dbc820da9cd745b32fe4ef5baa03091165b3542 + languageName: node + linkType: hard + +"@docusaurus/plugin-content-docs@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-content-docs@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/mdx-loader": "npm:3.10.0" + "@docusaurus/module-type-aliases": "npm:3.10.0" + "@docusaurus/theme-common": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + "@types/react-router-config": "npm:^5.0.7" + combine-promises: "npm:^1.1.0" + fs-extra: "npm:^11.1.1" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + schema-dts: "npm:^1.1.2" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.88.1" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/d1d61c85363231216e7f02731806c1519804c14b1a59bab84c386f4dfb45433081ed516cca42d8d891b9855a9ec996d53fe1a7624474a70d64515e7205beb791 + languageName: node + linkType: hard + +"@docusaurus/plugin-content-docs@npm:^3.9.2": + version: 3.9.2 + resolution: "@docusaurus/plugin-content-docs@npm:3.9.2" + dependencies: + "@docusaurus/core": "npm:3.9.2" + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/mdx-loader": "npm:3.9.2" + "@docusaurus/module-type-aliases": "npm:3.9.2" + "@docusaurus/theme-common": "npm:3.9.2" + "@docusaurus/types": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + "@docusaurus/utils-common": "npm:3.9.2" + "@docusaurus/utils-validation": "npm:3.9.2" + "@types/react-router-config": "npm:^5.0.7" + combine-promises: "npm:^1.1.0" + fs-extra: "npm:^11.1.1" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + schema-dts: "npm:^1.1.2" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.88.1" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/f2df62f6e03a383a8e7f81b29bea81de9b69e918dfaa668cef15a6f787943d3c148bfd8ba120d89cd96a3bbb23cd3d29ce0658f8dee07380ad612db66e835fa4 + languageName: node + linkType: hard + +"@docusaurus/plugin-content-pages@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-content-pages@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/mdx-loader": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + fs-extra: "npm:^11.1.1" + tslib: "npm:^2.6.0" + webpack: "npm:^5.88.1" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/780bf847a37a2bd7732870f2f8e7395aa82c0f9cba61353225fe6c1abfe48b1403b21f2ad67983db0f0712b01be277796e8d4d51d16e082447c269fe5afadb6c + languageName: node + linkType: hard + +"@docusaurus/plugin-css-cascade-layers@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-css-cascade-layers@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + tslib: "npm:^2.6.0" + checksum: 10c0/ebbfadc70293ff30878f263a166cd0c1e0bea24067acfc8ccb5d45adb9cc653c753fa9a27d874cd5e7855e2f7e5a35f1d337f07b6b28edabc77524f3533f47ea + languageName: node + linkType: hard + +"@docusaurus/plugin-debug@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-debug@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + fs-extra: "npm:^11.1.1" + react-json-view-lite: "npm:^2.3.0" + tslib: "npm:^2.6.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/575c364dcd2595928ebbc8ce6e90113e6bdcc2658ae59f3ddcd0fa2699880a81648765dc7083058bcc957bafd0f7e116c61c62e0cb6b678af97f7e719b5d2db7 + languageName: node + linkType: hard + +"@docusaurus/plugin-google-analytics@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-google-analytics@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + tslib: "npm:^2.6.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/f3814d3ec0c7e2040ac5f3a21a9e1dbb19d58af5a1096fe8376a8661fac92e9e77d3d48742ed7dfb0a1e635360bf1a4e2dd456b5d9d8746e490a250f9b7da097 + languageName: node + linkType: hard + +"@docusaurus/plugin-google-gtag@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-google-gtag@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + "@types/gtag.js": "npm:^0.0.20" + tslib: "npm:^2.6.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/31739d936f9ffa4c500d518816b17ac4f2ba2e75e20e5a6708eb2ed5d488465146b5a632899ab894cf8d8233306d212ac79d89c4c6a26c45f6dd15d31638444d + languageName: node + linkType: hard + +"@docusaurus/plugin-google-tag-manager@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-google-tag-manager@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + tslib: "npm:^2.6.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/6937bd384653ef938a5b66cf56bce458cc39c33aa35a6ebc43139abb393cfc7cf7865dcf6af60a2dbf65ebb06d40303530430a52e30a119b9c3d7419e53f3a6d + languageName: node + linkType: hard + +"@docusaurus/plugin-sitemap@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-sitemap@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + fs-extra: "npm:^11.1.1" + sitemap: "npm:^7.1.1" + tslib: "npm:^2.6.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/a0538da02713caaf844cd3b489a360408bb6868ceefbe3e51e7d02223919e8349b219aac1d111e258a29be5eeaea53d712448abf9d7d860f0af89b12d6652a86 + languageName: node + linkType: hard + +"@docusaurus/plugin-svgr@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/plugin-svgr@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + "@svgr/core": "npm:8.1.0" + "@svgr/webpack": "npm:^8.1.0" + tslib: "npm:^2.6.0" + webpack: "npm:^5.88.1" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/31a049eaf82c80296b0dc4d7d7bd292bda13dbcf9f07943db4cd2b721276185cb95f6058c406ff4602f4ff408f0fb042f3ade8c8e1d009054ecfa55d99960a88 + languageName: node + linkType: hard + +"@docusaurus/preset-classic@npm:^3.10.0": + version: 3.10.0 + resolution: "@docusaurus/preset-classic@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/plugin-content-blog": "npm:3.10.0" + "@docusaurus/plugin-content-docs": "npm:3.10.0" + "@docusaurus/plugin-content-pages": "npm:3.10.0" + "@docusaurus/plugin-css-cascade-layers": "npm:3.10.0" + "@docusaurus/plugin-debug": "npm:3.10.0" + "@docusaurus/plugin-google-analytics": "npm:3.10.0" + "@docusaurus/plugin-google-gtag": "npm:3.10.0" + "@docusaurus/plugin-google-tag-manager": "npm:3.10.0" + "@docusaurus/plugin-sitemap": "npm:3.10.0" + "@docusaurus/plugin-svgr": "npm:3.10.0" + "@docusaurus/theme-classic": "npm:3.10.0" + "@docusaurus/theme-common": "npm:3.10.0" + "@docusaurus/theme-search-algolia": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/c7d9ce9b76f309b65a3cdba6702f49adb4c518da3e3c4a4f745c5ad659cab9a9d1bf3841d49817fa4a1e3d226c2f683d6e263bb36d9d9bb6143f9fc4d36add42 + languageName: node + linkType: hard + +"@docusaurus/theme-classic@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/theme-classic@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/mdx-loader": "npm:3.10.0" + "@docusaurus/module-type-aliases": "npm:3.10.0" + "@docusaurus/plugin-content-blog": "npm:3.10.0" + "@docusaurus/plugin-content-docs": "npm:3.10.0" + "@docusaurus/plugin-content-pages": "npm:3.10.0" + "@docusaurus/theme-common": "npm:3.10.0" + "@docusaurus/theme-translations": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + "@mdx-js/react": "npm:^3.0.0" + clsx: "npm:^2.0.0" + copy-text-to-clipboard: "npm:^3.2.0" + infima: "npm:0.2.0-alpha.45" + lodash: "npm:^4.17.21" + nprogress: "npm:^0.2.0" + postcss: "npm:^8.5.4" + prism-react-renderer: "npm:^2.3.0" + prismjs: "npm:^1.29.0" + react-router-dom: "npm:^5.3.4" + rtlcss: "npm:^4.1.0" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/920df8c75701cd462cc414440b446157b6c831432bb2fe0e506268a5a72ef7fefe58568d8fb12bfc61845e8809f5fe6900314f39e9867a0aedabd184cbaa05b9 + languageName: node + linkType: hard + +"@docusaurus/theme-common@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/theme-common@npm:3.10.0" + dependencies: + "@docusaurus/mdx-loader": "npm:3.10.0" + "@docusaurus/module-type-aliases": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + "@types/react-router-config": "npm:*" + clsx: "npm:^2.0.0" + parse-numeric-range: "npm:^1.3.0" + prism-react-renderer: "npm:^2.3.0" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + peerDependencies: + "@docusaurus/plugin-content-docs": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/16cda69e916adfc2cfdeea6940264c01d56e8b87e87fca887d7d28933712333b5b60ce60a64d505ddda8da2c6538b50f3aa4e16351e3d05df9f8e590b407be6e + languageName: node + linkType: hard + +"@docusaurus/theme-common@npm:3.9.2, @docusaurus/theme-common@npm:^3.9.2": + version: 3.9.2 + resolution: "@docusaurus/theme-common@npm:3.9.2" + dependencies: + "@docusaurus/mdx-loader": "npm:3.9.2" + "@docusaurus/module-type-aliases": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + "@docusaurus/utils-common": "npm:3.9.2" + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + "@types/react-router-config": "npm:*" + clsx: "npm:^2.0.0" + parse-numeric-range: "npm:^1.3.0" + prism-react-renderer: "npm:^2.3.0" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + peerDependencies: + "@docusaurus/plugin-content-docs": "*" + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/4ecb8570e1fee75a6048ddb43065252e7b5b058f075867b541219830fb01bdc4b41b8f5f0251d6e9e7ffbe3704fd23d16ef90f92a3e2511ecc7ff6d9a2d5bfd6 + languageName: node + linkType: hard + +"@docusaurus/theme-mermaid@npm:^3.10.0": + version: 3.10.0 + resolution: "@docusaurus/theme-mermaid@npm:3.10.0" + dependencies: + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/module-type-aliases": "npm:3.10.0" + "@docusaurus/theme-common": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + mermaid: "npm:>=11.6.0" + tslib: "npm:^2.6.0" + peerDependencies: + "@mermaid-js/layout-elk": ^0.1.9 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@mermaid-js/layout-elk": + optional: true + checksum: 10c0/2bf6c0b0c7a7a55f7a89e6af7abef5ce2ca8f2e3c4a5e5be5b99cc9d8043135253dd73a588f008d3a5abf4133a3cc631983153e60fa05236398a7a2bac3f3cf7 + languageName: node + linkType: hard + +"@docusaurus/theme-search-algolia@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/theme-search-algolia@npm:3.10.0" + dependencies: + "@algolia/autocomplete-core": "npm:^1.19.2" + "@docsearch/react": "npm:^3.9.0 || ^4.3.2" + "@docusaurus/core": "npm:3.10.0" + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/plugin-content-docs": "npm:3.10.0" + "@docusaurus/theme-common": "npm:3.10.0" + "@docusaurus/theme-translations": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-validation": "npm:3.10.0" + algoliasearch: "npm:^5.37.0" + algoliasearch-helper: "npm:^3.26.0" + clsx: "npm:^2.0.0" + eta: "npm:^2.2.0" + fs-extra: "npm:^11.1.1" + lodash: "npm:^4.17.21" + tslib: "npm:^2.6.0" + utility-types: "npm:^3.10.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/63dd5f7e99457a71f0eb7916e18fa421e3194018975a52e8d8bd197abfdf5f19d85348a8a7e0713bccac413e9d5b1cb54b9c69c28a868e0473c1cf0b806f3faa + languageName: node + linkType: hard + +"@docusaurus/theme-translations@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/theme-translations@npm:3.10.0" + dependencies: + fs-extra: "npm:^11.1.1" + tslib: "npm:^2.6.0" + checksum: 10c0/62fa157763e2ad4d8c7afea0edebce895f85da5384c48222a1f697932716c550eeda34310d473643d037ae6d41720909174abf409971fcddd0eadb63daafced6 + languageName: node + linkType: hard + +"@docusaurus/theme-translations@npm:^3.9.2": + version: 3.9.2 + resolution: "@docusaurus/theme-translations@npm:3.9.2" + dependencies: + fs-extra: "npm:^11.1.1" + tslib: "npm:^2.6.0" + checksum: 10c0/543ee40933a8805357575c14d4fc8f8d504f6464796f5fa27ec13d8b0cec669617961edb206d5b74ba1d776d9486656fefdb1c777e2908cb1752ee6fbe28686c + languageName: node + linkType: hard + +"@docusaurus/types@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/types@npm:3.10.0" + dependencies: + "@mdx-js/mdx": "npm:^3.0.0" + "@types/history": "npm:^4.7.11" + "@types/mdast": "npm:^4.0.2" + "@types/react": "npm:*" + commander: "npm:^5.1.0" + joi: "npm:^17.9.2" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.95.0" + webpack-merge: "npm:^5.9.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/0d0f5f57bb82f190385a506192d882a5072e833af55a35cb5fb69048bb4258012eebe51448b8ace9d77d05d69a99d7fd2dcae25bb4babfa205abfbca222de8d5 + languageName: node + linkType: hard + +"@docusaurus/types@npm:3.9.2, @docusaurus/types@npm:^3.0.0": + version: 3.9.2 + resolution: "@docusaurus/types@npm:3.9.2" + dependencies: + "@mdx-js/mdx": "npm:^3.0.0" + "@types/history": "npm:^4.7.11" + "@types/mdast": "npm:^4.0.2" + "@types/react": "npm:*" + commander: "npm:^5.1.0" + joi: "npm:^17.9.2" + react-helmet-async: "npm:@slorber/react-helmet-async@1.3.0" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.95.0" + webpack-merge: "npm:^5.9.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + checksum: 10c0/e50a9931e97944d39375a97a45ded13bc35baf3c9c14fe66d30944ebe1203df7748a7631291f937bef1a7a98db73c23505620cd8f03d109fbbdfa83725fb2857 + languageName: node + linkType: hard + +"@docusaurus/utils-common@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/utils-common@npm:3.10.0" + dependencies: + "@docusaurus/types": "npm:3.10.0" + tslib: "npm:^2.6.0" + checksum: 10c0/12e54b8e29d1d8d78f85598a154fc122f4d93bdd143b55fd7a474c2d9eab431bbf13ac61e008f1c4f34ffce76578fe95b441f6a6469a752d7396f9d9c000f6e4 + languageName: node + linkType: hard + +"@docusaurus/utils-common@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/utils-common@npm:3.9.2" + dependencies: + "@docusaurus/types": "npm:3.9.2" + tslib: "npm:^2.6.0" + checksum: 10c0/0e34186ca66cf3c537935d998cfb2ce59beaad31ccb9b41c2288618f386d72dc4359e15e8cb012525211d1f1d753fc439d6c7e9701d6ac801e1121cfa3223d69 + languageName: node + linkType: hard + +"@docusaurus/utils-validation@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/utils-validation@npm:3.10.0" + dependencies: + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/utils": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + fs-extra: "npm:^11.2.0" + joi: "npm:^17.9.2" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + tslib: "npm:^2.6.0" + checksum: 10c0/ab1aee9c9b236d4c5247f33b245c016a2ef501ef154f5f5392a98e706d448ee60c32746b4c58e4954be24393eee6db06cb3192efa8df00343176c558fca33924 + languageName: node + linkType: hard + +"@docusaurus/utils-validation@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/utils-validation@npm:3.9.2" + dependencies: + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/utils": "npm:3.9.2" + "@docusaurus/utils-common": "npm:3.9.2" + fs-extra: "npm:^11.2.0" + joi: "npm:^17.9.2" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + tslib: "npm:^2.6.0" + checksum: 10c0/681b8c7fe0e2930affa388340f3db596a894affdb390e058277edd230181edca6f5593d37b48fb19c5077bbd5438549d944591f366b9f21ffff81feac1e1ae66 + languageName: node + linkType: hard + +"@docusaurus/utils@npm:3.10.0": + version: 3.10.0 + resolution: "@docusaurus/utils@npm:3.10.0" + dependencies: + "@docusaurus/logger": "npm:3.10.0" + "@docusaurus/types": "npm:3.10.0" + "@docusaurus/utils-common": "npm:3.10.0" + escape-string-regexp: "npm:^4.0.0" + execa: "npm:^5.1.1" + file-loader: "npm:^6.2.0" + fs-extra: "npm:^11.1.1" + github-slugger: "npm:^1.5.0" + globby: "npm:^11.1.0" + gray-matter: "npm:^4.0.3" + jiti: "npm:^1.20.0" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + micromatch: "npm:^4.0.5" + p-queue: "npm:^6.6.2" + prompts: "npm:^2.4.2" + resolve-pathname: "npm:^3.0.0" + tslib: "npm:^2.6.0" + url-loader: "npm:^4.1.1" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.88.1" + checksum: 10c0/0f3488c38fbc985378f93f6573cf080559207ae367b0052df2ad42d667726ec766900db68184ec1746bcf4c38c9a1289d9f54fbd71a857dc592363996295afff + languageName: node + linkType: hard + +"@docusaurus/utils@npm:3.9.2": + version: 3.9.2 + resolution: "@docusaurus/utils@npm:3.9.2" + dependencies: + "@docusaurus/logger": "npm:3.9.2" + "@docusaurus/types": "npm:3.9.2" + "@docusaurus/utils-common": "npm:3.9.2" + escape-string-regexp: "npm:^4.0.0" + execa: "npm:5.1.1" + file-loader: "npm:^6.2.0" + fs-extra: "npm:^11.1.1" + github-slugger: "npm:^1.5.0" + globby: "npm:^11.1.0" + gray-matter: "npm:^4.0.3" + jiti: "npm:^1.20.0" + js-yaml: "npm:^4.1.0" + lodash: "npm:^4.17.21" + micromatch: "npm:^4.0.5" + p-queue: "npm:^6.6.2" + prompts: "npm:^2.4.2" + resolve-pathname: "npm:^3.0.0" + tslib: "npm:^2.6.0" + url-loader: "npm:^4.1.1" + utility-types: "npm:^3.10.0" + webpack: "npm:^5.88.1" + checksum: 10c0/9796b2e7bc93e47cb27ce81185264c6390b56cd9e68831f6013e4418af512a736f1baf9b97e5df8d646ef4da0650151512abf598f5d58793a3e6c0833c80e06a + languageName: node + linkType: hard + +"@emnapi/core@npm:^1.5.0": + version: 1.9.2 + resolution: "@emnapi/core@npm:1.9.2" + dependencies: + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10c0/5500393f953951bad0768fafaa9191f2d938956b20c6d6a79e5ab696a613a25ce6ad23422bc18e86e6ce8deb147619d8d0d7d413a69f84adc01a6633cc353cd9 + languageName: node + linkType: hard + +"@emnapi/runtime@npm:^1.5.0": + version: 1.9.2 + resolution: "@emnapi/runtime@npm:1.9.2" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/61c3a59e0c36784558b8d58eb02bd04815aa5fb0dbfbaf84d1b3050a78aa0cc63ea129ae806bd1e48062bfeb7fc36eb0e5431740d62f64ea51bdf426404b8caa + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 + languageName: node + linkType: hard + +"@gar/promise-retry@npm:^1.0.0": + version: 1.0.3 + resolution: "@gar/promise-retry@npm:1.0.3" + checksum: 10c0/885b02c8b0d75b2d215da25f3b639158c4fbe8fefe0d79163304534b9a6d0710db4b7699f7cd3cc1a730792bff04cbe19f4850a62d3e105a663eaeec88f38332 + languageName: node + linkType: hard + +"@hapi/hoek@npm:^9.0.0, @hapi/hoek@npm:^9.3.0": + version: 9.3.0 + resolution: "@hapi/hoek@npm:9.3.0" + checksum: 10c0/a096063805051fb8bba4c947e293c664b05a32b47e13bc654c0dd43813a1cec993bdd8f29ceb838020299e1d0f89f68dc0d62a603c13c9cc8541963f0beca055 + languageName: node + linkType: hard + +"@hapi/topo@npm:^5.1.0": + version: 5.1.0 + resolution: "@hapi/topo@npm:5.1.0" + dependencies: + "@hapi/hoek": "npm:^9.0.0" + checksum: 10c0/b16b06d9357947149e032bdf10151eb71aea8057c79c4046bf32393cb89d0d0f7ca501c40c0f7534a5ceca078de0700d2257ac855c15e59fe4e00bba2f25c86f + languageName: node + linkType: hard + +"@hcaptcha/loader@npm:^2.0.0": + version: 2.0.0 + resolution: "@hcaptcha/loader@npm:2.0.0" + checksum: 10c0/c69c8e62ccf41cc5cce8f25721b9bd8284e201da608022476dc6d69afbd70512a6f272dd2bfe558c4b5fdbc0ee20fb5f062033c4d556e6d523ecb2448203298f + languageName: node + linkType: hard + +"@hcaptcha/react-hcaptcha@npm:^1.0.0": + version: 1.12.0 + resolution: "@hcaptcha/react-hcaptcha@npm:1.12.0" + dependencies: + "@babel/runtime": "npm:^7.17.9" + "@hcaptcha/loader": "npm:^2.0.0" + peerDependencies: + react: ">= 16.3.0" + react-dom: ">= 16.3.0" + checksum: 10c0/58fddf7cbbeb1c9d784a90a4ee76604efd8d0c968d1d256f72d112d95c8d68bbb1255dd4184148e7e43e38491c5614b3747f4d17393a17d320e28935da47f8e8 + languageName: node + linkType: hard + +"@iarna/toml@npm:^2.2.5": + version: 2.2.5 + resolution: "@iarna/toml@npm:2.2.5" + checksum: 10c0/d095381ad4554aca233b7cf5a91f243ef619e5e15efd3157bc640feac320545450d14b394aebbf6f02a2047437ced778ae598d5879a995441ab7b6c0b2c2f201 + languageName: node + linkType: hard + +"@iconify/types@npm:^2.0.0": + version: 2.0.0 + resolution: "@iconify/types@npm:2.0.0" + checksum: 10c0/65a3be43500c7ccacf360e136d00e1717f050b7b91da644e94370256ac66f582d59212bdb30d00788aab4fc078262e91c95b805d1808d654b72f6d2072a7e4b2 + languageName: node + linkType: hard + +"@iconify/utils@npm:^3.0.2": + version: 3.1.0 + resolution: "@iconify/utils@npm:3.1.0" + dependencies: + "@antfu/install-pkg": "npm:^1.1.0" + "@iconify/types": "npm:^2.0.0" + mlly: "npm:^1.8.0" + checksum: 10c0/a39445e892b248486c186306e1ccba4b07ed1d5b21b143ddf279b33062063173feb84954b9a82e05713b927872787d6c0081073d23f55c44294de37615d4a1f7 + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" + dependencies: + "@sinclair/typebox": "npm:^0.27.8" + checksum: 10c0/b329e89cd5f20b9278ae1233df74016ebf7b385e0d14b9f4c1ad18d096c4c19d1e687aa113a9c976b16ec07f021ae53dea811fb8c1248a50ac34fbe009fdf6be + languageName: node + linkType: hard + +"@jest/types@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/types@npm:29.6.3" + dependencies: + "@jest/schemas": "npm:^29.6.3" + "@types/istanbul-lib-coverage": "npm:^2.0.0" + "@types/istanbul-reports": "npm:^3.0.0" + "@types/node": "npm:*" + "@types/yargs": "npm:^17.0.8" + chalk: "npm:^4.0.0" + checksum: 10c0/ea4e493dd3fb47933b8ccab201ae573dcc451f951dc44ed2a86123cd8541b82aa9d2b1031caf9b1080d6673c517e2dcc25a44b2dc4f3fbc37bfc965d444888c0 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.13 + resolution: "@jridgewell/gen-mapping@npm:0.3.13" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.0" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b + languageName: node + linkType: hard + +"@jridgewell/remapping@npm:^2.3.5": + version: 2.3.5 + resolution: "@jridgewell/remapping@npm:2.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/source-map@npm:^0.3.3": + version: 0.3.6 + resolution: "@jridgewell/source-map@npm:0.3.6" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + checksum: 10c0/6a4ecc713ed246ff8e5bdcc1ef7c49aaa93f7463d948ba5054dda18b02dcc6a055e2828c577bcceee058f302ce1fc95595713d44f5c45e43d459f88d267f2f04 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25, @jridgewell/trace-mapping@npm:^0.3.28": + version: 0.3.31 + resolution: "@jridgewell/trace-mapping@npm:0.3.31" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 + languageName: node + linkType: hard + +"@jsonjoy.com/base64@npm:17.67.0": + version: 17.67.0 + resolution: "@jsonjoy.com/base64@npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 10c0/d9616ec1ac0ea6aa455968b1f96f2d48ce38a2b1835922a909a55147d7b8cff3d648d45e9efe6781c6926beb5f04dc41c75ce548b6b84141b14bc122893e16ee + languageName: node + linkType: hard + +"@jsonjoy.com/base64@npm:^1.1.2": + version: 1.1.2 + resolution: "@jsonjoy.com/base64@npm:1.1.2" + peerDependencies: + tslib: 2 + checksum: 10c0/88717945f66dc89bf58ce75624c99fe6a5c9a0c8614e26d03e406447b28abff80c69fb37dabe5aafef1862cf315071ae66e5c85f6018b437d95f8d13d235e6eb + languageName: node + linkType: hard + +"@jsonjoy.com/buffers@npm:17.67.0, @jsonjoy.com/buffers@npm:^17.65.0": + version: 17.67.0 + resolution: "@jsonjoy.com/buffers@npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 10c0/ee46d3ea6c2dee4dd5dffd8b156745baeecfe796c7bb3f091f9fe64c402aca5e4d86ba3d736545682f919303fb15359c1f00d41ac91ea1b5d4edbbe74f540d35 + languageName: node + linkType: hard + +"@jsonjoy.com/buffers@npm:^1.0.0, @jsonjoy.com/buffers@npm:^1.2.0": + version: 1.2.1 + resolution: "@jsonjoy.com/buffers@npm:1.2.1" + peerDependencies: + tslib: 2 + checksum: 10c0/5edaf761b78b730ae0598824adb37473fef5b40a8fc100625159700eb36e00057c5129c7ad15fc0e3178e8de58a044da65728e8d7b05fd3eed58e9b9a0d02b5a + languageName: node + linkType: hard + +"@jsonjoy.com/codegen@npm:17.67.0": + version: 17.67.0 + resolution: "@jsonjoy.com/codegen@npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 10c0/3cc529377cc315acf373dc52dbd39d56285b31ba8ca90a4447230e37e405372cc13bed7df638dc81f9071ff8f4eb8e825217987397d80182d08ded761e609a93 + languageName: node + linkType: hard + +"@jsonjoy.com/codegen@npm:^1.0.0": + version: 1.0.0 + resolution: "@jsonjoy.com/codegen@npm:1.0.0" + peerDependencies: + tslib: 2 + checksum: 10c0/54686352248440ad1484ce7db0270a5a72424fb9651b090e5f1c8e2cd8e55e6c7a3f67dfe4ed90c689cf01ed949e794764a8069f5f52510eaf0a2d0c41d324cd + languageName: node + linkType: hard + +"@jsonjoy.com/fs-core@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-core@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-node-builtins": "npm:4.57.1" + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + thingies: "npm:^2.5.0" + peerDependencies: + tslib: 2 + checksum: 10c0/8269bb457dfbb783705b12962a2aaae8e40b180801750b8f4029ee8a6ee9941c039e88804eae2764f9a024992ff87bebdd006a65cb0d027fdec11a37b77ac209 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-fsa@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-fsa@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-core": "npm:4.57.1" + "@jsonjoy.com/fs-node-builtins": "npm:4.57.1" + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + thingies: "npm:^2.5.0" + peerDependencies: + tslib: 2 + checksum: 10c0/644e1af00d5ab5bae840c737dd7885e92d423fec8fbe77d605f30dd77a858fef0112e2d77fd4009fc4acce7f2344eacb2bcd695052c2240d5b39532aac9bcada + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node-builtins@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-node-builtins@npm:4.57.1" + peerDependencies: + tslib: 2 + checksum: 10c0/971d46ea04fbe8803967d2fa7fdf9959bbe395cc740fbcf07f2b8632cd5abd242ec10adef29b4d6019de5753aa1e8a4c4e3cd14592bcebef918bdc7078be974b + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node-to-fsa@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-node-to-fsa@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-fsa": "npm:4.57.1" + "@jsonjoy.com/fs-node-builtins": "npm:4.57.1" + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + peerDependencies: + tslib: 2 + checksum: 10c0/8efd27c4411cce5f5ee26f27c41f65aef069807b0f98496cbb7e73775328a14a9a9da04ec1bd7e1276674e7467712cb05fc729a5fb5fe8353cad9f4de1bf2843 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node-utils@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-node-utils@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-node-builtins": "npm:4.57.1" + peerDependencies: + tslib: 2 + checksum: 10c0/eea2c25483d304488f9572aaea0940e2528ddb7aa529e9b9ae8ec6f828413cb5597f574510c0adef0d0d54c0de2dfd50f666f24a98a24166e9dc72f3b144f8c5 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-node@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-node@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-core": "npm:4.57.1" + "@jsonjoy.com/fs-node-builtins": "npm:4.57.1" + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + "@jsonjoy.com/fs-print": "npm:4.57.1" + "@jsonjoy.com/fs-snapshot": "npm:4.57.1" + glob-to-regex.js: "npm:^1.0.0" + thingies: "npm:^2.5.0" + peerDependencies: + tslib: 2 + checksum: 10c0/b98f2671330d04191f61f282b65d773ae8bf5dca2f0b8c339e34f0d6a76e949ff3439a9e45dc417d8d661b1b6311cd0699289b72f0ae80d3b5d6211e5086485f + languageName: node + linkType: hard + +"@jsonjoy.com/fs-print@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-print@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + tree-dump: "npm:^1.1.0" + peerDependencies: + tslib: 2 + checksum: 10c0/c611103134aefa1d111b375a8509a3b58381a6fae3b9cc01b35e16dd4a1d9ef0e21648b51f97d2a442adbc9d4a462179285564e1deaefea4e2cb920dccc24922 + languageName: node + linkType: hard + +"@jsonjoy.com/fs-snapshot@npm:4.57.1": + version: 4.57.1 + resolution: "@jsonjoy.com/fs-snapshot@npm:4.57.1" + dependencies: + "@jsonjoy.com/buffers": "npm:^17.65.0" + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + "@jsonjoy.com/json-pack": "npm:^17.65.0" + "@jsonjoy.com/util": "npm:^17.65.0" + peerDependencies: + tslib: 2 + checksum: 10c0/ded857cebc0bb3de03f2c1520b1c000cb498e99c47b20e7231fa87eb87b42e600b9804e06e3e7136432a503d330a33da31185871192b93873719b300c533b5aa + languageName: node + linkType: hard + +"@jsonjoy.com/json-pack@npm:^1.11.0": + version: 1.21.0 + resolution: "@jsonjoy.com/json-pack@npm:1.21.0" + dependencies: + "@jsonjoy.com/base64": "npm:^1.1.2" + "@jsonjoy.com/buffers": "npm:^1.2.0" + "@jsonjoy.com/codegen": "npm:^1.0.0" + "@jsonjoy.com/json-pointer": "npm:^1.0.2" + "@jsonjoy.com/util": "npm:^1.9.0" + hyperdyperid: "npm:^1.2.0" + thingies: "npm:^2.5.0" + tree-dump: "npm:^1.1.0" + peerDependencies: + tslib: 2 + checksum: 10c0/0183eccccf2ab912389a6784ae81c1a7da48cf178902efe093fb60c457359c7c75da2803f869e0a1489f1342dfa4f8ab9b27b65adc9f44fd9646823773b71e9d + languageName: node + linkType: hard + +"@jsonjoy.com/json-pack@npm:^17.65.0": + version: 17.67.0 + resolution: "@jsonjoy.com/json-pack@npm:17.67.0" + dependencies: + "@jsonjoy.com/base64": "npm:17.67.0" + "@jsonjoy.com/buffers": "npm:17.67.0" + "@jsonjoy.com/codegen": "npm:17.67.0" + "@jsonjoy.com/json-pointer": "npm:17.67.0" + "@jsonjoy.com/util": "npm:17.67.0" + hyperdyperid: "npm:^1.2.0" + thingies: "npm:^2.5.0" + tree-dump: "npm:^1.1.0" + peerDependencies: + tslib: 2 + checksum: 10c0/fee56d024c84f031ef011a85ccca071c73b8a0739506083bd3dc7a17c720a498599f285e79082a9626314324ea938f189d18d47a03341cb76286ca2e7098bf53 + languageName: node + linkType: hard + +"@jsonjoy.com/json-pointer@npm:17.67.0": + version: 17.67.0 + resolution: "@jsonjoy.com/json-pointer@npm:17.67.0" + dependencies: + "@jsonjoy.com/util": "npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 10c0/763e0b1bc274390a605073b49e5bf55bdf386e784f5940d456faca958d90915b7d9a47dd9d58a08e2113f40167b0640d313897811680eb91630726920618fe7d + languageName: node + linkType: hard + +"@jsonjoy.com/json-pointer@npm:^1.0.2": + version: 1.0.2 + resolution: "@jsonjoy.com/json-pointer@npm:1.0.2" + dependencies: + "@jsonjoy.com/codegen": "npm:^1.0.0" + "@jsonjoy.com/util": "npm:^1.9.0" + peerDependencies: + tslib: 2 + checksum: 10c0/8d959c0fdd77d937d2a829270de51533bb9e3b887b3f6f02943884dc33dd79225071218c93f4bafdee6a3412fd5153264997953a86de444d85c1fff67915af54 + languageName: node + linkType: hard + +"@jsonjoy.com/util@npm:17.67.0, @jsonjoy.com/util@npm:^17.65.0": + version: 17.67.0 + resolution: "@jsonjoy.com/util@npm:17.67.0" + dependencies: + "@jsonjoy.com/buffers": "npm:17.67.0" + "@jsonjoy.com/codegen": "npm:17.67.0" + peerDependencies: + tslib: 2 + checksum: 10c0/44be53d94c99ce74a0eff1bb111f0ff4392a1226e34637321c8bc45b569da3f9e12db8b225eef3694c44b9fd2e9b800d7baf5ea0d38e1d7767bfcbef4fbf91b0 + languageName: node + linkType: hard + +"@jsonjoy.com/util@npm:^1.9.0": + version: 1.9.0 + resolution: "@jsonjoy.com/util@npm:1.9.0" + dependencies: + "@jsonjoy.com/buffers": "npm:^1.0.0" + "@jsonjoy.com/codegen": "npm:^1.0.0" + peerDependencies: + tslib: 2 + checksum: 10c0/a720a6accaae71fa9e7fa06e93e382702aa5760ef2bdc3bc45c19dc2228a01cc735d36cb970c654bc5e88f1328d55d1f0d5eceef0b76bcc327a2ce863e7b0021 + languageName: node + linkType: hard + +"@leichtgewicht/ip-codec@npm:^2.0.1": + version: 2.0.5 + resolution: "@leichtgewicht/ip-codec@npm:2.0.5" + checksum: 10c0/14a0112bd59615eef9e3446fea018045720cd3da85a98f801a685a818b0d96ef2a1f7227e8d271def546b2e2a0fe91ef915ba9dc912ab7967d2317b1a051d66b + languageName: node + linkType: hard + +"@mdx-js/mdx@npm:^3.0.0": + version: 3.1.0 + resolution: "@mdx-js/mdx@npm:3.1.0" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdx": "npm:^2.0.0" + collapse-white-space: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + estree-util-scope: "npm:^1.0.0" + estree-walker: "npm:^3.0.0" + hast-util-to-jsx-runtime: "npm:^2.0.0" + markdown-extensions: "npm:^2.0.0" + recma-build-jsx: "npm:^1.0.0" + recma-jsx: "npm:^1.0.0" + recma-stringify: "npm:^1.0.0" + rehype-recma: "npm:^1.0.0" + remark-mdx: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-rehype: "npm:^11.0.0" + source-map: "npm:^0.7.0" + unified: "npm:^11.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/e586ab772dcfee2bab334d5aac54c711e6d6d550085271c38a49c629b3e3954b5f41f488060761284a5e00649d0638d6aba6c0a7c66f91db80dee0ccc304ab32 + languageName: node + linkType: hard + +"@mdx-js/react@npm:^3.0.0": + version: 3.1.0 + resolution: "@mdx-js/react@npm:3.1.0" + dependencies: + "@types/mdx": "npm:^2.0.0" + peerDependencies: + "@types/react": ">=16" + react: ">=16" + checksum: 10c0/381ed1211ba2b8491bf0ad9ef0d8d1badcdd114e1931d55d44019d4b827cc2752586708f9c7d2f9c3244150ed81f1f671a6ca95fae0edd5797fb47a22e06ceca + languageName: node + linkType: hard + +"@mermaid-js/parser@npm:^1.0.1": + version: 1.0.1 + resolution: "@mermaid-js/parser@npm:1.0.1" + dependencies: + langium: "npm:^4.0.0" + checksum: 10c0/34231cb63412ddbb3c8c6dba6366b958f98b66293b2e5748d3bd6c286acde47862a6ac86b2f6a33e7b5dee6a1895035af06ee48863c787bc20415b89fe77d705 + languageName: node + linkType: hard + +"@miniflare/cache@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/cache@npm:2.0.0-rc.5" + dependencies: + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + http-cache-semantics: "npm:^4.1.0" + undici: "npm:^4.11.1" + checksum: 10c0/fa1811a5d06cdc393f20ecc083903c9613eb27f006b76ca3cdd9cc98ea1ab4a4267373fe6af900fdf83dce4891bacdd26e8b0fd8133e68a43a7d68aabd7e59bb + languageName: node + linkType: hard + +"@miniflare/cli-parser@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/cli-parser@npm:2.0.0-rc.5" + dependencies: + "@miniflare/shared": "npm:2.0.0-rc.5" + kleur: "npm:^4.1.4" + checksum: 10c0/f1abea3e62f85195f8412ec63ab2f990798dbf4c2a561d513a32902282a844e27404520d23f612509a26d56c4dc2ba519fee8328b1f7d78d168e5797d7df0eea + languageName: node + linkType: hard + +"@miniflare/core@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/core@npm:2.0.0-rc.5" + dependencies: + "@iarna/toml": "npm:^2.2.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + busboy: "npm:^0.3.1" + dotenv: "npm:^10.0.0" + kleur: "npm:^4.1.4" + set-cookie-parser: "npm:^2.4.8" + undici: "npm:^4.11.1" + peerDependencies: + "@miniflare/watcher": 2.0.0-rc.5 + peerDependenciesMeta: + "@miniflare/watcher": + optional: true + checksum: 10c0/1708b081eb557b9ff5eb41cad9a9f190bb5541b4c298cb62f78f168ec0c158a90142ca0275bfa00522305dcf1773cc30165c83334e51b79529c5228c1c2525c6 + languageName: node + linkType: hard + +"@miniflare/durable-objects@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/durable-objects@npm:2.0.0-rc.5" + dependencies: + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + "@miniflare/storage-memory": "npm:2.0.0-rc.5" + undici: "npm:^4.11.1" + checksum: 10c0/cf15fee1e15ee18e389af7b0f09d8764700cc14f536d31a5033293af987bedb9d8acb27f33b4c4cfce18ee1c468d5dbd5ae367e83df133631bd51a5386bce748 + languageName: node + linkType: hard + +"@miniflare/html-rewriter@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/html-rewriter@npm:2.0.0-rc.5" + dependencies: + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + html-rewriter-wasm: "npm:^0.3.2" + undici: "npm:^4.11.1" + checksum: 10c0/f95de64296581ca5cd310ae1ff904b76658d064bea60091507011432c61f8170ff85de20c8f125defbc6528093aad9c2530ec58d0c413c7645dc6b7559792575 + languageName: node + linkType: hard + +"@miniflare/http-server@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/http-server@npm:2.0.0-rc.5" + dependencies: + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + "@miniflare/web-sockets": "npm:2.0.0-rc.5" + kleur: "npm:^4.1.4" + selfsigned: "npm:^1.10.11" + undici: "npm:^4.11.1" + ws: "npm:^8.2.2" + youch: "npm:^2.2.2" + checksum: 10c0/9c6c5cf2d086edcf4cd28a38b27e3ec19d80bff75bf0733a197e1f942a36993685bdb4731c1377e4c3ebade1aede1f930ccc81012db93319a72546f28807beb6 + languageName: node + linkType: hard + +"@miniflare/kv@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/kv@npm:2.0.0-rc.5" + dependencies: + "@miniflare/shared": "npm:2.0.0-rc.5" + checksum: 10c0/c88e99c06ab330b1e91318ac257ddd20e5b5af626f97811607616440ade604de33f639705d55be2a903c3cb4225489cc502e3784f19661acd3b70e2fa3c4e115 + languageName: node + linkType: hard + +"@miniflare/runner-vm@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/runner-vm@npm:2.0.0-rc.5" + dependencies: + "@miniflare/shared": "npm:2.0.0-rc.5" + checksum: 10c0/86e3171507753a6edc88b52b0c803273e9a074a0658486ff52516a1c970b28a8ee037b0f67b3a908fb75f855d0a94647707fa9b33d46dccade630f5af220a977 + languageName: node + linkType: hard + +"@miniflare/scheduler@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/scheduler@npm:2.0.0-rc.5" + dependencies: + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + cron-schedule: "npm:^3.0.4" + checksum: 10c0/e0aaf664b02d41686ab6f5cb4aed773cbbb5fb2c4ea617acbb13a177dc208a9c48159d35730ba781b5d1e78fcc90480687eaae5ada7196a152347fb19203ac3b + languageName: node + linkType: hard + +"@miniflare/shared@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/shared@npm:2.0.0-rc.5" + dependencies: + ignore: "npm:^5.1.8" + kleur: "npm:^4.1.4" + checksum: 10c0/07aa713a5e47b606ea158037303722db7cbc88fbc7a475a2320cfd73f9ca689c667ab5584c32e77cffe9293ac95ca20c326fdfc751a85a510d830046df9915e8 + languageName: node + linkType: hard + +"@miniflare/sites@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/sites@npm:2.0.0-rc.5" + dependencies: + "@miniflare/kv": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + "@miniflare/storage-file": "npm:2.0.0-rc.5" + checksum: 10c0/90c38f0cae40f937c0a5fea389e009fa61d8892e2bf25c88a100094530c14e855c303afd1d73dc14eb97ace1fd6986492a5410e2560c2775523553e7a0430a45 + languageName: node + linkType: hard + +"@miniflare/storage-file@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/storage-file@npm:2.0.0-rc.5" + dependencies: + "@miniflare/shared": "npm:2.0.0-rc.5" + "@miniflare/storage-memory": "npm:2.0.0-rc.5" + checksum: 10c0/e8dfb214d2c90d81062d0fd0f33a36b96abb85f075cf96dd69ace668e2d3f85d7ec60307f9d855c237a837007694c2b828505a8c12684611020bfe5cb4913e8f + languageName: node + linkType: hard + +"@miniflare/storage-memory@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/storage-memory@npm:2.0.0-rc.5" + dependencies: + "@miniflare/shared": "npm:2.0.0-rc.5" + checksum: 10c0/d127989e5b6409bf5b59bcd8008d28a8d9dbb2950033d8b9e957eb1d24ac33cd761619c03d9c82f928b35f200ca83ddf3cada2075a4b079ae0ae9768e7d64d08 + languageName: node + linkType: hard + +"@miniflare/watcher@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/watcher@npm:2.0.0-rc.5" + dependencies: + "@miniflare/shared": "npm:2.0.0-rc.5" + checksum: 10c0/1b72cc31d932358957fcb1cb1fe0fc64d6ce883fc27730716817ac8941fcc9cc0566e0610813b6dfe79e0f1c5171d0516545ab1ccaa225a5aa456b0db088f85d + languageName: node + linkType: hard + +"@miniflare/web-sockets@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "@miniflare/web-sockets@npm:2.0.0-rc.5" + dependencies: + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + undici: "npm:^4.11.1" + ws: "npm:^8.2.2" + checksum: 10c0/a9a42b8961df4116f5671ad063ea75495ebe66bea515a961b40f62be27f759524696ec9fc930567d040d331d437fcb24f6cfcf0c44511ef1514b20da04db0bb6 + languageName: node + linkType: hard + +"@module-federation/error-codes@npm:0.22.0": + version: 0.22.0 + resolution: "@module-federation/error-codes@npm:0.22.0" + checksum: 10c0/a9b25e8c930971e146e6352f482f915f1b54965ce54706984e834a87be714d30caebbd3946f9eb408e7821b2cc326b90787eeb2f8306edf1d322d9931543a139 + languageName: node + linkType: hard + +"@module-federation/runtime-core@npm:0.22.0": + version: 0.22.0 + resolution: "@module-federation/runtime-core@npm:0.22.0" + dependencies: + "@module-federation/error-codes": "npm:0.22.0" + "@module-federation/sdk": "npm:0.22.0" + checksum: 10c0/0406c26b119065dca23a8fb65872b8ab5794984d5d82984ed625c433658693050a8a800cde8c97cc1572b0bc154a7824fa9db5bb05106b7250643e799ba7091d + languageName: node + linkType: hard + +"@module-federation/runtime-tools@npm:0.22.0": + version: 0.22.0 + resolution: "@module-federation/runtime-tools@npm:0.22.0" + dependencies: + "@module-federation/runtime": "npm:0.22.0" + "@module-federation/webpack-bundler-runtime": "npm:0.22.0" + checksum: 10c0/fbe76616fb176ce03550e3ce2bb43fa5d44c12d7d0939593f29dab5658accfb559b857df4180f7f681dc601aab928658cd9b49a78daad866089390b820854fbd + languageName: node + linkType: hard + +"@module-federation/runtime@npm:0.22.0": + version: 0.22.0 + resolution: "@module-federation/runtime@npm:0.22.0" + dependencies: + "@module-federation/error-codes": "npm:0.22.0" + "@module-federation/runtime-core": "npm:0.22.0" + "@module-federation/sdk": "npm:0.22.0" + checksum: 10c0/f9cfaf7f8599a215195cb612a5d4532d4399cc8eb5a928ced60c4bdf0e7e2028849cdc384fa3f1506f9e7e0e112f74f6c30a5a76136dc56e155012d111ea075b + languageName: node + linkType: hard + +"@module-federation/sdk@npm:0.22.0": + version: 0.22.0 + resolution: "@module-federation/sdk@npm:0.22.0" + checksum: 10c0/c09ba0147368151b67ba33b9174ef451a028e1709d2208aa811cacc1ae4efcae0f1987f02119f9b54754ee6430af3610e357c9b744147f112a25d8f7564f8041 + languageName: node + linkType: hard + +"@module-federation/webpack-bundler-runtime@npm:0.22.0": + version: 0.22.0 + resolution: "@module-federation/webpack-bundler-runtime@npm:0.22.0" + dependencies: + "@module-federation/runtime": "npm:0.22.0" + "@module-federation/sdk": "npm:0.22.0" + checksum: 10c0/4c1354b881ffc0c1521f1d676c9301db0b0d59186c386dde4dbb6d33f00fdb16bf118e85cfc38e2ffb36084fa87df8390d415a41c0c93b33bd0e5460a9a934f5 + languageName: node + linkType: hard + +"@napi-rs/wasm-runtime@npm:1.0.7": + version: 1.0.7 + resolution: "@napi-rs/wasm-runtime@npm:1.0.7" + dependencies: + "@emnapi/core": "npm:^1.5.0" + "@emnapi/runtime": "npm:^1.5.0" + "@tybys/wasm-util": "npm:^0.10.1" + checksum: 10c0/2d8635498136abb49d6dbf7395b78c63422292240963bf055f307b77aeafbde57ae2c0ceaaef215601531b36d6eb92a2cdd6f5ba90ed2aa8127c27aff9c4ae55 + languageName: node + linkType: hard + +"@noble/hashes@npm:1.4.0": + version: 1.4.0 + resolution: "@noble/hashes@npm:1.4.0" + checksum: 10c0/8c3f005ee72e7b8f9cff756dfae1241485187254e3f743873e22073d63906863df5d4f13d441b7530ea614b7a093f0d889309f28b59850f33b66cb26a779a4a5 + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": "npm:2.0.5" + run-parallel: "npm:^1.1.9" + checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": "npm:2.1.5" + fastq: "npm:^1.6.0" + checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/agent@npm:4.0.0" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^11.2.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10c0/f7b5ce0f3dd42c3f8c6546e8433573d8049f67ef11ec22aa4704bc41483122f68bf97752e06302c455ead667af5cb753e6a09bff06632bc465c1cfd4c4b75a53 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^5.0.0": + version: 5.0.0 + resolution: "@npmcli/fs@npm:5.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/26e376d780f60ff16e874a0ac9bc3399186846baae0b6e1352286385ac134d900cc5dafaded77f38d77f86898fc923ae1cee9d7399f0275b1aa24878915d722b + languageName: node + linkType: hard + +"@npmcli/redact@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/redact@npm:4.0.0" + checksum: 10c0/a1e9ba9c70a6b40e175bda2c3dd8cfdaf096e6b7f7a132c855c083c8dfe545c3237cd56702e2e6627a580b1d63373599d49a1192c4078a85bf47bbde824df31c + languageName: node + linkType: hard + +"@peculiar/asn1-cms@npm:^2.6.0, @peculiar/asn1-cms@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-cms@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + "@peculiar/asn1-x509-attr": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/682e952fb35dec229bf54ecaff58bdf56281c1d718b5bcc2da103d67b5be302452c6275300c9f9fce1ed02f03792dab3ebe98c903117e0a5b0d9e5d861356280 + languageName: node + linkType: hard + +"@peculiar/asn1-csr@npm:^2.6.0": + version: 2.6.1 + resolution: "@peculiar/asn1-csr@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/5ea1ef27bf3879c793acb0b370b9fc1cb45df244b4706cecf075e45b58d19d65e612f4777eb12aa37f2037c1c725e96543ab9caf41d5a92378c5069071deae1f + languageName: node + linkType: hard + +"@peculiar/asn1-ecc@npm:^2.6.0": + version: 2.6.1 + resolution: "@peculiar/asn1-ecc@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/7804600f12a8993085232839ea020f51a329a195ce991ebbce077668d9ee1e57301bf97d5ef9657bd81717888f36f51f7aed3a9eee59fe4345c55d04eff89927 + languageName: node + linkType: hard + +"@peculiar/asn1-pfx@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-pfx@npm:2.6.1" + dependencies: + "@peculiar/asn1-cms": "npm:^2.6.1" + "@peculiar/asn1-pkcs8": "npm:^2.6.1" + "@peculiar/asn1-rsa": "npm:^2.6.1" + "@peculiar/asn1-schema": "npm:^2.6.0" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/69c86ed339b945f7c77173da06207af71553a5b033cc1f2bde262085e7b5870543f358a29efd8981ca7247ec7f1c5d722a014cc0979679045909cb13e2ca527e + languageName: node + linkType: hard + +"@peculiar/asn1-pkcs8@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-pkcs8@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/d712dc79ab877152f20c1772cbe065f5beb2a20e3dcae7892cc72f3227a1d3f7ae8eecba8bc29cf2b77cfdd8a01b0660f5390a416ca78ca7147f0e3c13d4d755 + languageName: node + linkType: hard + +"@peculiar/asn1-pkcs9@npm:^2.6.0": + version: 2.6.1 + resolution: "@peculiar/asn1-pkcs9@npm:2.6.1" + dependencies: + "@peculiar/asn1-cms": "npm:^2.6.1" + "@peculiar/asn1-pfx": "npm:^2.6.1" + "@peculiar/asn1-pkcs8": "npm:^2.6.1" + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + "@peculiar/asn1-x509-attr": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/4a2f815bbeee3f65aea391d5e2287a19701d757d2781b3ecfd908a67028f2752796bd22f8ba3eb486911fcc34b52b0f7c1ff3e3b7d7f04ef58767be9ddbc851d + languageName: node + linkType: hard + +"@peculiar/asn1-rsa@npm:^2.6.0, @peculiar/asn1-rsa@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-rsa@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/4d7c71c5bddf7be3b0270c4d95b8274a392185cad4939a7a837d9c4c612601fee1a1ccabe414383b26629fb2013608e60a58ecd665c371617c1f177431a88ff2 + languageName: node + linkType: hard + +"@peculiar/asn1-schema@npm:^2.6.0": + version: 2.6.0 + resolution: "@peculiar/asn1-schema@npm:2.6.0" + dependencies: + asn1js: "npm:^3.0.6" + pvtsutils: "npm:^1.3.6" + tslib: "npm:^2.8.1" + checksum: 10c0/8c283b10a2e4aca4cb20d242cde773c9a798ea15a6c221d1474ef483e182d48195aeb5dde3f7b518f236eceb7808ae4438539d41a3aa9ed6d20aa4d36a21a0c2 + languageName: node + linkType: hard + +"@peculiar/asn1-x509-attr@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-x509-attr@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.1" + asn1js: "npm:^3.0.6" + tslib: "npm:^2.8.1" + checksum: 10c0/de8634ec12ef34b430e5a458151e856f954e15fe9e08d056dca51db6962e849a951820ab66d291e2452799576c44221b40087b9350dc3728d3770a46fcdeffc5 + languageName: node + linkType: hard + +"@peculiar/asn1-x509@npm:^2.6.0, @peculiar/asn1-x509@npm:^2.6.1": + version: 2.6.1 + resolution: "@peculiar/asn1-x509@npm:2.6.1" + dependencies: + "@peculiar/asn1-schema": "npm:^2.6.0" + asn1js: "npm:^3.0.6" + pvtsutils: "npm:^1.3.6" + tslib: "npm:^2.8.1" + checksum: 10c0/2e73a0ce6521eeb2d876e0b52e9fae2de4e2d183be5fba77d5fae9b7724de446d02c0b4e5fb04d4fedb50eed0de842f29f4d7cf2e998eaed6a2d2952f5c52d2c + languageName: node + linkType: hard + +"@peculiar/x509@npm:^1.14.2": + version: 1.14.3 + resolution: "@peculiar/x509@npm:1.14.3" + dependencies: + "@peculiar/asn1-cms": "npm:^2.6.0" + "@peculiar/asn1-csr": "npm:^2.6.0" + "@peculiar/asn1-ecc": "npm:^2.6.0" + "@peculiar/asn1-pkcs9": "npm:^2.6.0" + "@peculiar/asn1-rsa": "npm:^2.6.0" + "@peculiar/asn1-schema": "npm:^2.6.0" + "@peculiar/asn1-x509": "npm:^2.6.0" + pvtsutils: "npm:^1.3.6" + reflect-metadata: "npm:^0.2.2" + tslib: "npm:^2.8.1" + tsyringe: "npm:^4.10.0" + checksum: 10c0/949231ca9daf84534bfe255f28a856df497302fed294d227c6a28e50f5cfb67ed1d91afe6db787b88294ce042295243dbcb44455fe2efa5ed07428a74392eec9 + languageName: node + linkType: hard + +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: 10c0/4cfc4a5c49ab3d0c6a1f196cfd4146374768b0243d441c7de8fa7bd28eaab6290f514b98490472cc65dbd080d34369447b3e9302585e1d5c099befd7c8b5e55f + languageName: node + linkType: hard + +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" + dependencies: + graceful-fs: "npm:4.2.10" + checksum: 10c0/95f6e0e38d047aca3283550719155ce7304ac00d98911e4ab026daedaf640a63bd83e3d13e17c623fa41ac72f3801382ba21260bcce431c14fbbc06430ecb776 + languageName: node + linkType: hard + +"@pnpm/npm-conf@npm:^2.1.0": + version: 2.3.1 + resolution: "@pnpm/npm-conf@npm:2.3.1" + dependencies: + "@pnpm/config.env-replace": "npm:^1.1.0" + "@pnpm/network.ca-file": "npm:^1.0.1" + config-chain: "npm:^1.1.11" + checksum: 10c0/778a3a34ff7d6000a2594d2a9821f873f737bc56367865718b2cf0ba5d366e49689efe7975148316d7afd8e6f1dcef7d736fbb6ea7ef55caadd1dc93a36bb302 + languageName: node + linkType: hard + +"@polka/url@npm:^1.0.0-next.24": + version: 1.0.0-next.28 + resolution: "@polka/url@npm:1.0.0-next.28" + checksum: 10c0/acc5ea62597e4da2fb42dbee02749d07f102ae7d6d2c966bf7e423c79cd65d1621da305af567e6e7c232f3b565e242d1ec932cbb3dcc0db1508d02e9a2cafa2e + languageName: node + linkType: hard + +"@rspack/binding-darwin-arm64@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-darwin-arm64@npm:1.7.11" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rspack/binding-darwin-x64@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-darwin-x64@npm:1.7.11" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rspack/binding-linux-arm64-gnu@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-linux-arm64-gnu@npm:1.7.11" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rspack/binding-linux-arm64-musl@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-linux-arm64-musl@npm:1.7.11" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rspack/binding-linux-x64-gnu@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-linux-x64-gnu@npm:1.7.11" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rspack/binding-linux-x64-musl@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-linux-x64-musl@npm:1.7.11" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rspack/binding-wasm32-wasi@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-wasm32-wasi@npm:1.7.11" + dependencies: + "@napi-rs/wasm-runtime": "npm:1.0.7" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@rspack/binding-win32-arm64-msvc@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-win32-arm64-msvc@npm:1.7.11" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rspack/binding-win32-ia32-msvc@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-win32-ia32-msvc@npm:1.7.11" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rspack/binding-win32-x64-msvc@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding-win32-x64-msvc@npm:1.7.11" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rspack/binding@npm:1.7.11": + version: 1.7.11 + resolution: "@rspack/binding@npm:1.7.11" + dependencies: + "@rspack/binding-darwin-arm64": "npm:1.7.11" + "@rspack/binding-darwin-x64": "npm:1.7.11" + "@rspack/binding-linux-arm64-gnu": "npm:1.7.11" + "@rspack/binding-linux-arm64-musl": "npm:1.7.11" + "@rspack/binding-linux-x64-gnu": "npm:1.7.11" + "@rspack/binding-linux-x64-musl": "npm:1.7.11" + "@rspack/binding-wasm32-wasi": "npm:1.7.11" + "@rspack/binding-win32-arm64-msvc": "npm:1.7.11" + "@rspack/binding-win32-ia32-msvc": "npm:1.7.11" + "@rspack/binding-win32-x64-msvc": "npm:1.7.11" + dependenciesMeta: + "@rspack/binding-darwin-arm64": + optional: true + "@rspack/binding-darwin-x64": + optional: true + "@rspack/binding-linux-arm64-gnu": + optional: true + "@rspack/binding-linux-arm64-musl": + optional: true + "@rspack/binding-linux-x64-gnu": + optional: true + "@rspack/binding-linux-x64-musl": + optional: true + "@rspack/binding-wasm32-wasi": + optional: true + "@rspack/binding-win32-arm64-msvc": + optional: true + "@rspack/binding-win32-ia32-msvc": + optional: true + "@rspack/binding-win32-x64-msvc": + optional: true + checksum: 10c0/9f0421dc3b3ab32bc76d2e5f280361be4c24f05a11814b64bf8b5c3ba589f03da3a5d20a54df20e2b73b25cd0d33c5d2016287108190f833977dc2aa99dba0d7 + languageName: node + linkType: hard + +"@rspack/core@npm:^1.7.10": + version: 1.7.11 + resolution: "@rspack/core@npm:1.7.11" + dependencies: + "@module-federation/runtime-tools": "npm:0.22.0" + "@rspack/binding": "npm:1.7.11" + "@rspack/lite-tapable": "npm:1.1.0" + peerDependencies: + "@swc/helpers": ">=0.5.1" + peerDependenciesMeta: + "@swc/helpers": + optional: true + checksum: 10c0/a1df355d94a7d7737729aa816f6d0cd3ef481a05dff02486fb4e6f7155b9c76653ed57aed5cfe56dc6c686a1cae4167d4de16c68e71d60d7191c8d2613a171f7 + languageName: node + linkType: hard + +"@rspack/lite-tapable@npm:1.1.0": + version: 1.1.0 + resolution: "@rspack/lite-tapable@npm:1.1.0" + checksum: 10c0/15059d1da73192b150339ceba3142a2d0073fa298dad9a497cc8c6037c597c3a982ed4c88dc50afa7b70d0757df1b47af7ae407cfe8acd31d333d524b84a7a4b + languageName: node + linkType: hard + +"@sideway/address@npm:^4.1.5": + version: 4.1.5 + resolution: "@sideway/address@npm:4.1.5" + dependencies: + "@hapi/hoek": "npm:^9.0.0" + checksum: 10c0/638eb6f7e7dba209053dd6c8da74d7cc995e2b791b97644d0303a7dd3119263bcb7225a4f6804d4db2bc4f96e5a9d262975a014f58eae4d1753c27cbc96ef959 + languageName: node + linkType: hard + +"@sideway/formula@npm:^3.0.1": + version: 3.0.1 + resolution: "@sideway/formula@npm:3.0.1" + checksum: 10c0/3fe81fa9662efc076bf41612b060eb9b02e846ea4bea5bd114f1662b7f1541e9dedcf98aff0d24400bcb92f113964a50e0290b86e284edbdf6346fa9b7e2bf2c + languageName: node + linkType: hard + +"@sideway/pinpoint@npm:^2.0.0": + version: 2.0.0 + resolution: "@sideway/pinpoint@npm:2.0.0" + checksum: 10c0/d2ca75dacaf69b8fc0bb8916a204e01def3105ee44d8be16c355e5f58189eb94039e15ce831f3d544f229889ccfa35562a0ce2516179f3a7ee1bbe0b71e55b36 + languageName: node + linkType: hard + +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.10 + resolution: "@sinclair/typebox@npm:0.27.10" + checksum: 10c0/ca42a02817656dbdae464ed4bb8aca6ad4718d7618e270760fea84a834ad0ecc1a22eba51421f09e5047174571131356ff3b5d80d609ced775d631df7b404b0d + languageName: node + linkType: hard + +"@sindresorhus/is@npm:^4.6.0": + version: 4.6.0 + resolution: "@sindresorhus/is@npm:4.6.0" + checksum: 10c0/33b6fb1d0834ec8dd7689ddc0e2781c2bfd8b9c4e4bacbcb14111e0ae00621f2c264b8a7d36541799d74888b5dccdf422a891a5cb5a709ace26325eedc81e22e + languageName: node + linkType: hard + +"@sindresorhus/is@npm:^5.2.0": + version: 5.6.0 + resolution: "@sindresorhus/is@npm:5.6.0" + checksum: 10c0/66727344d0c92edde5760b5fd1f8092b717f2298a162a5f7f29e4953e001479927402d9d387e245fb9dc7d3b37c72e335e93ed5875edfc5203c53be8ecba1b52 + languageName: node + linkType: hard + +"@slorber/remark-comment@npm:^1.0.0": + version: 1.0.0 + resolution: "@slorber/remark-comment@npm:1.0.0" + dependencies: + micromark-factory-space: "npm:^1.0.0" + micromark-util-character: "npm:^1.1.0" + micromark-util-symbol: "npm:^1.0.1" + checksum: 10c0/b8da9d8f560740959c421d3ce5be43952eace1c95cb65402d9473a15e66463346a37fb5f121a6b22a83af51e8845b0b4ff3c321f14ce31bd58fb126acf6c8ed9 + languageName: node + linkType: hard + +"@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a50bd0baa34faf16bcba712091f94c7f0e230431fe99a9dfc3401fa92823ad3f68495b86ab9bf9044b53839e8c416cfbb37eb3f246ff33f261e0fa9ee1779c5b + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/8a98e59bd9971e066815b4129409932f7a4db4866834fe75677ea6d517972fb40b380a69a4413189f20e7947411f9ab1b0f029dd5e8068686a5a0188d3ccd4c7 + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/517dcca75223bd05d3f056a8514dbba3031278bea4eadf0842c576d84f4651e7a4e0e7082d3ee4ef42456de0f9c4531d8a1917c04876ca64b014b859ca8f1bde + languageName: node + linkType: hard + +"@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/004bd1892053b7e9c1b0bb14acc44e77634ec393722b87b1e4fae53e2c35122a2dd0d5c15e9070dbeec274e22e7693a2b8b48506733a8009ee92b12946fcb10a + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/80e0a7fcf902f984c705051ca5c82ea6050ccbb70b651a8fea6d0eb5809e4dac274b49ea6be2d87f1eb9dfc0e2d6cdfffe1669ec2117f44b67a60a07d4c0b8b8 + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/73e92c8277a89279745c0c500f59f083279a8dc30cd552b22981fade2a77628fb2bd2819ee505725fcd2e93f923e3790b52efcff409a159e657b46604a0b9a21 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/655ed6bc7a208ceaa4ecff0a54ccc36008c3cb31efa90d11e171cab325ebbb21aa78f09c7b65f9b3ddeda3a85f348c0c862902c48be13c14b4de165c847974e3 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-svg-component@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-transform-svg-component@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4ac00bb99a3db4ef05e4362f116a3c608ee365a2d26cf7318d8d41a4a5b30a02c80455cce0e62c65b60ed815b5d632bedabac2ccd4b56f998fadef5286e3ded4 + languageName: node + linkType: hard + +"@svgr/babel-preset@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-preset@npm:8.1.0" + dependencies: + "@svgr/babel-plugin-add-jsx-attribute": "npm:8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute": "npm:8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression": "npm:8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value": "npm:8.0.0" + "@svgr/babel-plugin-svg-dynamic-title": "npm:8.0.0" + "@svgr/babel-plugin-svg-em-dimensions": "npm:8.0.0" + "@svgr/babel-plugin-transform-react-native-svg": "npm:8.1.0" + "@svgr/babel-plugin-transform-svg-component": "npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/49367d3ad0831f79b1056871b91766246f449d4d1168623af5e283fbaefce4a01d77ab00de6b045b55e956f9aae27895823198493cd232d88d3435ea4517ffc5 + languageName: node + linkType: hard + +"@svgr/core@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/core@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@svgr/babel-preset": "npm:8.1.0" + camelcase: "npm:^6.2.0" + cosmiconfig: "npm:^8.1.3" + snake-case: "npm:^3.0.4" + checksum: 10c0/6a2f6b1bc79bce39f66f088d468985d518005fc5147ebf4f108570a933818b5951c2cb7da230ddff4b7c8028b5a672b2d33aa2acce012b8b9770073aa5a2d041 + languageName: node + linkType: hard + +"@svgr/hast-util-to-babel-ast@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/hast-util-to-babel-ast@npm:8.0.0" + dependencies: + "@babel/types": "npm:^7.21.3" + entities: "npm:^4.4.0" + checksum: 10c0/f4165b583ba9eaf6719e598977a7b3ed182f177983e55f9eb55a6a73982d81277510e9eb7ab41f255151fb9ed4edd11ac4bef95dd872f04ed64966d8c85e0f79 + languageName: node + linkType: hard + +"@svgr/plugin-jsx@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-jsx@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@svgr/babel-preset": "npm:8.1.0" + "@svgr/hast-util-to-babel-ast": "npm:8.0.0" + svg-parser: "npm:^2.0.4" + peerDependencies: + "@svgr/core": "*" + checksum: 10c0/07b4d9e00de795540bf70556fa2cc258774d01e97a12a26234c6fdf42b309beb7c10f31ee24d1a71137239347b1547b8bb5587d3a6de10669f95dcfe99cddc56 + languageName: node + linkType: hard + +"@svgr/plugin-svgo@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-svgo@npm:8.1.0" + dependencies: + cosmiconfig: "npm:^8.1.3" + deepmerge: "npm:^4.3.1" + svgo: "npm:^3.0.2" + peerDependencies: + "@svgr/core": "*" + checksum: 10c0/bfd25460f23f1548bfb8f6f3bedd6d6972c1a4f8881bd35a4f8c115218da6e999e8f9ac0ef0ed88c4e0b93fcec37f382b94c0322f4ec2b26752a89e5cc8b9d7a + languageName: node + linkType: hard + +"@svgr/webpack@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/webpack@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@babel/plugin-transform-react-constant-elements": "npm:^7.21.3" + "@babel/preset-env": "npm:^7.20.2" + "@babel/preset-react": "npm:^7.18.6" + "@babel/preset-typescript": "npm:^7.21.0" + "@svgr/core": "npm:8.1.0" + "@svgr/plugin-jsx": "npm:8.1.0" + "@svgr/plugin-svgo": "npm:8.1.0" + checksum: 10c0/4c1cac45bd5890de8643e5a7bfb71f3bcd8b85ae5bbacf10b8ad9f939b7a98e8d601c3ada204ffb95223abf4a24beeac5a2a0d6928a52a1ab72a29da3c015c22 + languageName: node + linkType: hard + +"@swc/core-darwin-arm64@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-darwin-arm64@npm:1.15.24" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@swc/core-darwin-x64@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-darwin-x64@npm:1.15.24" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@swc/core-linux-arm-gnueabihf@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.15.24" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@swc/core-linux-arm64-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-arm64-gnu@npm:1.15.24" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-arm64-musl@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-arm64-musl@npm:1.15.24" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@swc/core-linux-ppc64-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-ppc64-gnu@npm:1.15.24" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-s390x-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-s390x-gnu@npm:1.15.24" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-x64-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-x64-gnu@npm:1.15.24" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@swc/core-linux-x64-musl@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-linux-x64-musl@npm:1.15.24" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@swc/core-win32-arm64-msvc@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-win32-arm64-msvc@npm:1.15.24" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@swc/core-win32-ia32-msvc@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-win32-ia32-msvc@npm:1.15.24" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@swc/core-win32-x64-msvc@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/core-win32-x64-msvc@npm:1.15.24" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@swc/core@npm:^1.7.39": + version: 1.15.24 + resolution: "@swc/core@npm:1.15.24" + dependencies: + "@swc/core-darwin-arm64": "npm:1.15.24" + "@swc/core-darwin-x64": "npm:1.15.24" + "@swc/core-linux-arm-gnueabihf": "npm:1.15.24" + "@swc/core-linux-arm64-gnu": "npm:1.15.24" + "@swc/core-linux-arm64-musl": "npm:1.15.24" + "@swc/core-linux-ppc64-gnu": "npm:1.15.24" + "@swc/core-linux-s390x-gnu": "npm:1.15.24" + "@swc/core-linux-x64-gnu": "npm:1.15.24" + "@swc/core-linux-x64-musl": "npm:1.15.24" + "@swc/core-win32-arm64-msvc": "npm:1.15.24" + "@swc/core-win32-ia32-msvc": "npm:1.15.24" + "@swc/core-win32-x64-msvc": "npm:1.15.24" + "@swc/counter": "npm:^0.1.3" + "@swc/types": "npm:^0.1.26" + peerDependencies: + "@swc/helpers": ">=0.5.17" + dependenciesMeta: + "@swc/core-darwin-arm64": + optional: true + "@swc/core-darwin-x64": + optional: true + "@swc/core-linux-arm-gnueabihf": + optional: true + "@swc/core-linux-arm64-gnu": + optional: true + "@swc/core-linux-arm64-musl": + optional: true + "@swc/core-linux-ppc64-gnu": + optional: true + "@swc/core-linux-s390x-gnu": + optional: true + "@swc/core-linux-x64-gnu": + optional: true + "@swc/core-linux-x64-musl": + optional: true + "@swc/core-win32-arm64-msvc": + optional: true + "@swc/core-win32-ia32-msvc": + optional: true + "@swc/core-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@swc/helpers": + optional: true + checksum: 10c0/dfa963d88c2044517b483dfe2104744018c59c8524b3d82c61a15132558ba03e73d7b8ee79824509c7ae5f962a5dcd27b6e5acbeec66978e0fc757bec2b9603e + languageName: node + linkType: hard + +"@swc/counter@npm:^0.1.3": + version: 0.1.3 + resolution: "@swc/counter@npm:0.1.3" + checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356 + languageName: node + linkType: hard + +"@swc/html-darwin-arm64@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-darwin-arm64@npm:1.15.24" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@swc/html-darwin-x64@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-darwin-x64@npm:1.15.24" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@swc/html-linux-arm-gnueabihf@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-arm-gnueabihf@npm:1.15.24" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@swc/html-linux-arm64-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-arm64-gnu@npm:1.15.24" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@swc/html-linux-arm64-musl@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-arm64-musl@npm:1.15.24" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@swc/html-linux-ppc64-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-ppc64-gnu@npm:1.15.24" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@swc/html-linux-s390x-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-s390x-gnu@npm:1.15.24" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@swc/html-linux-x64-gnu@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-x64-gnu@npm:1.15.24" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@swc/html-linux-x64-musl@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-linux-x64-musl@npm:1.15.24" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@swc/html-win32-arm64-msvc@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-win32-arm64-msvc@npm:1.15.24" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@swc/html-win32-ia32-msvc@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-win32-ia32-msvc@npm:1.15.24" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@swc/html-win32-x64-msvc@npm:1.15.24": + version: 1.15.24 + resolution: "@swc/html-win32-x64-msvc@npm:1.15.24" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@swc/html@npm:^1.13.5": + version: 1.15.24 + resolution: "@swc/html@npm:1.15.24" + dependencies: + "@swc/counter": "npm:^0.1.3" + "@swc/html-darwin-arm64": "npm:1.15.24" + "@swc/html-darwin-x64": "npm:1.15.24" + "@swc/html-linux-arm-gnueabihf": "npm:1.15.24" + "@swc/html-linux-arm64-gnu": "npm:1.15.24" + "@swc/html-linux-arm64-musl": "npm:1.15.24" + "@swc/html-linux-ppc64-gnu": "npm:1.15.24" + "@swc/html-linux-s390x-gnu": "npm:1.15.24" + "@swc/html-linux-x64-gnu": "npm:1.15.24" + "@swc/html-linux-x64-musl": "npm:1.15.24" + "@swc/html-win32-arm64-msvc": "npm:1.15.24" + "@swc/html-win32-ia32-msvc": "npm:1.15.24" + "@swc/html-win32-x64-msvc": "npm:1.15.24" + dependenciesMeta: + "@swc/html-darwin-arm64": + optional: true + "@swc/html-darwin-x64": + optional: true + "@swc/html-linux-arm-gnueabihf": + optional: true + "@swc/html-linux-arm64-gnu": + optional: true + "@swc/html-linux-arm64-musl": + optional: true + "@swc/html-linux-ppc64-gnu": + optional: true + "@swc/html-linux-s390x-gnu": + optional: true + "@swc/html-linux-x64-gnu": + optional: true + "@swc/html-linux-x64-musl": + optional: true + "@swc/html-win32-arm64-msvc": + optional: true + "@swc/html-win32-ia32-msvc": + optional: true + "@swc/html-win32-x64-msvc": + optional: true + checksum: 10c0/6dccc1f8cb8605639a2502db637cfd85864028e3dce0b9a6579c273d3ab54ce395f2be2bc2f693ff065eb0ab7162aab2a06eb3ce76b69a5e6104fe52bd2b4bf2 + languageName: node + linkType: hard + +"@swc/types@npm:^0.1.26": + version: 0.1.26 + resolution: "@swc/types@npm:0.1.26" + dependencies: + "@swc/counter": "npm:^0.1.3" + checksum: 10c0/8449341e8bbff81c14e9918c25421143cf605dff20f70f048847e1f7cede396f8dd73903cbef331a809b4a8e15d0db374a5f6809003e7b440f93df1dd4934d28 + languageName: node + linkType: hard + +"@szmarczak/http-timer@npm:^5.0.1": + version: 5.0.1 + resolution: "@szmarczak/http-timer@npm:5.0.1" + dependencies: + defer-to-connect: "npm:^2.0.1" + checksum: 10c0/4629d2fbb2ea67c2e9dc03af235c0991c79ebdddcbc19aed5d5732fb29ce01c13331e9b1a491584b9069bd6ecde6581dcbf871f11b7eefdebbab34de6cf2197e + languageName: node + linkType: hard + +"@tybys/wasm-util@npm:^0.10.1": + version: 0.10.1 + resolution: "@tybys/wasm-util@npm:0.10.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/b255094f293794c6d2289300c5fbcafbb5532a3aed3a5ffd2f8dc1828e639b88d75f6a376dd8f94347a44813fd7a7149d8463477a9a49525c8b2dcaa38c2d1e8 + languageName: node + linkType: hard + +"@types/acorn@npm:^4.0.0": + version: 4.0.6 + resolution: "@types/acorn@npm:4.0.6" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/5a65a1d7e91fc95703f0a717897be60fa7ccd34b17f5462056274a246e6690259fe0a1baabc86fd3260354f87245cb3dc483346d7faad2b78fc199763978ede9 + languageName: node + linkType: hard + +"@types/body-parser@npm:*": + version: 1.19.6 + resolution: "@types/body-parser@npm:1.19.6" + dependencies: + "@types/connect": "npm:*" + "@types/node": "npm:*" + checksum: 10c0/542da05c924dce58ee23f50a8b981fee36921850c82222e384931fda3e106f750f7880c47be665217d72dbe445129049db6eb1f44e7a06b09d62af8f3cca8ea7 + languageName: node + linkType: hard + +"@types/bonjour@npm:^3.5.13": + version: 3.5.13 + resolution: "@types/bonjour@npm:3.5.13" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/eebedbca185ac3c39dd5992ef18d9e2a9f99e7f3c2f52f5561f90e9ed482c5d224c7962db95362712f580ed5713264e777a98d8f0bd8747f4eadf62937baed16 + languageName: node + linkType: hard + +"@types/connect-history-api-fallback@npm:^1.5.4": + version: 1.5.4 + resolution: "@types/connect-history-api-fallback@npm:1.5.4" + dependencies: + "@types/express-serve-static-core": "npm:*" + "@types/node": "npm:*" + checksum: 10c0/1b4035b627dcd714b05a22557f942e24a57ca48e7377dde0d2f86313fe685bc0a6566512a73257a55b5665b96c3041fb29228ac93331d8133011716215de8244 + languageName: node + linkType: hard + +"@types/connect@npm:*": + version: 3.4.38 + resolution: "@types/connect@npm:3.4.38" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/2e1cdba2c410f25649e77856505cd60223250fa12dff7a503e492208dbfdd25f62859918f28aba95315251fd1f5e1ffbfca1e25e73037189ab85dd3f8d0a148c + languageName: node + linkType: hard + +"@types/d3-array@npm:*": + version: 3.2.2 + resolution: "@types/d3-array@npm:3.2.2" + checksum: 10c0/6137cb97302f8a4f18ca22c0560c585cfcb823f276b23d89f2c0c005d72697ec13bca671c08e68b4b0cabd622e3f0e91782ee221580d6774074050be96dd7028 + languageName: node + linkType: hard + +"@types/d3-axis@npm:*": + version: 3.0.6 + resolution: "@types/d3-axis@npm:3.0.6" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/d756d42360261f44d8eefd0950c5bb0a4f67a46dd92069da3f723ac36a1e8cb2b9ce6347d836ef19d5b8aef725dbcf8fdbbd6cfbff676ca4b0642df2f78b599a + languageName: node + linkType: hard + +"@types/d3-brush@npm:*": + version: 3.0.6 + resolution: "@types/d3-brush@npm:3.0.6" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/fd6e2ac7657a354f269f6b9c58451ffae9d01b89ccb1eb6367fd36d635d2f1990967215ab498e0c0679ff269429c57fad6a2958b68f4d45bc9f81d81672edc01 + languageName: node + linkType: hard + +"@types/d3-chord@npm:*": + version: 3.0.6 + resolution: "@types/d3-chord@npm:3.0.6" + checksum: 10c0/c5a25eb5389db01e63faec0c5c2ec7cc41c494e9b3201630b494c4e862a60f1aa83fabbc33a829e7e1403941e3c30d206c741559b14406ac2a4239cfdf4b4c17 + languageName: node + linkType: hard + +"@types/d3-color@npm:*": + version: 3.1.3 + resolution: "@types/d3-color@npm:3.1.3" + checksum: 10c0/65eb0487de606eb5ad81735a9a5b3142d30bc5ea801ed9b14b77cb14c9b909f718c059f13af341264ee189acf171508053342142bdf99338667cea26a2d8d6ae + languageName: node + linkType: hard + +"@types/d3-contour@npm:*": + version: 3.0.6 + resolution: "@types/d3-contour@npm:3.0.6" + dependencies: + "@types/d3-array": "npm:*" + "@types/geojson": "npm:*" + checksum: 10c0/e7d83e94719af4576ceb5ac7f277c5806f83ba6c3631744ae391cffc3641f09dfa279470b83053cd0b2acd6784e8749c71141d05bdffa63ca58ffb5b31a0f27c + languageName: node + linkType: hard + +"@types/d3-delaunay@npm:*": + version: 6.0.4 + resolution: "@types/d3-delaunay@npm:6.0.4" + checksum: 10c0/d154a8864f08c4ea23ecb9bdabcef1c406a25baa8895f0cb08a0ed2799de0d360e597552532ce7086ff0cdffa8f3563f9109d18f0191459d32bb620a36939123 + languageName: node + linkType: hard + +"@types/d3-dispatch@npm:*": + version: 3.0.7 + resolution: "@types/d3-dispatch@npm:3.0.7" + checksum: 10c0/38c6605ebf0bf0099dfb70eafe0dd4ae8213368b40b8f930b72a909ff2e7259d2bd8a54d100bb5a44eb4b36f4f2a62dcb37f8be59613ca6b507c7a2f910b3145 + languageName: node + linkType: hard + +"@types/d3-drag@npm:*": + version: 3.0.7 + resolution: "@types/d3-drag@npm:3.0.7" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/65e29fa32a87c72d26c44b5e2df3bf15af21cd128386bcc05bcacca255927c0397d0cd7e6062aed5f0abd623490544a9d061c195f5ed9f018fe0b698d99c079d + languageName: node + linkType: hard + +"@types/d3-dsv@npm:*": + version: 3.0.7 + resolution: "@types/d3-dsv@npm:3.0.7" + checksum: 10c0/c0f01da862465594c8a28278b51c850af3b4239cc22b14fd1a19d7a98f93d94efa477bf59d8071beb285dca45bf614630811451e18e7c52add3a0abfee0a1871 + languageName: node + linkType: hard + +"@types/d3-ease@npm:*": + version: 3.0.2 + resolution: "@types/d3-ease@npm:3.0.2" + checksum: 10c0/aff5a1e572a937ee9bff6465225d7ba27d5e0c976bd9eacdac2e6f10700a7cb0c9ea2597aff6b43a6ed850a3210030870238894a77ec73e309b4a9d0333f099c + languageName: node + linkType: hard + +"@types/d3-fetch@npm:*": + version: 3.0.7 + resolution: "@types/d3-fetch@npm:3.0.7" + dependencies: + "@types/d3-dsv": "npm:*" + checksum: 10c0/3d147efa52a26da1a5d40d4d73e6cebaaa964463c378068062999b93ea3731b27cc429104c21ecbba98c6090e58ef13429db6399238c5e3500162fb3015697a0 + languageName: node + linkType: hard + +"@types/d3-force@npm:*": + version: 3.0.10 + resolution: "@types/d3-force@npm:3.0.10" + checksum: 10c0/c82b459079a106b50e346c9b79b141f599f2fc4f598985a5211e72c7a2e20d35bd5dc6e91f306b323c8bfa325c02c629b1645f5243f1c6a55bd51bc85cccfa92 + languageName: node + linkType: hard + +"@types/d3-format@npm:*": + version: 3.0.4 + resolution: "@types/d3-format@npm:3.0.4" + checksum: 10c0/3ac1600bf9061a59a228998f7cd3f29e85cbf522997671ba18d4d84d10a2a1aff4f95aceb143fa9960501c3ec351e113fc75884e6a504ace44dc1744083035ee + languageName: node + linkType: hard + +"@types/d3-geo@npm:*": + version: 3.1.0 + resolution: "@types/d3-geo@npm:3.1.0" + dependencies: + "@types/geojson": "npm:*" + checksum: 10c0/3745a93439038bb5b0b38facf435f7079812921d46406f5d38deaee59e90084ff742443c7ea0a8446df81a0d81eaf622fe7068cf4117a544bd4aa3b2dc182f88 + languageName: node + linkType: hard + +"@types/d3-hierarchy@npm:*": + version: 3.1.7 + resolution: "@types/d3-hierarchy@npm:3.1.7" + checksum: 10c0/873711737d6b8e7b6f1dda0bcd21294a48f75024909ae510c5d2c21fad2e72032e0958def4d9f68319d3aaac298ad09c49807f8bfc87a145a82693b5208613c7 + languageName: node + linkType: hard + +"@types/d3-interpolate@npm:*": + version: 3.0.4 + resolution: "@types/d3-interpolate@npm:3.0.4" + dependencies: + "@types/d3-color": "npm:*" + checksum: 10c0/066ebb8da570b518dd332df6b12ae3b1eaa0a7f4f0c702e3c57f812cf529cc3500ec2aac8dc094f31897790346c6b1ebd8cd7a077176727f4860c2b181a65ca4 + languageName: node + linkType: hard + +"@types/d3-path@npm:*": + version: 3.1.1 + resolution: "@types/d3-path@npm:3.1.1" + checksum: 10c0/2c36eb31ebaf2ce4712e793fd88087117976f7c4ed69cc2431825f999c8c77cca5cea286f3326432b770739ac6ccd5d04d851eb65e7a4dbcc10c982b49ad2c02 + languageName: node + linkType: hard + +"@types/d3-polygon@npm:*": + version: 3.0.2 + resolution: "@types/d3-polygon@npm:3.0.2" + checksum: 10c0/f46307bb32b6c2aef8c7624500e0f9b518de8f227ccc10170b869dc43e4c542560f6c8d62e9f087fac45e198d6e4b623e579c0422e34c85baf56717456d3f439 + languageName: node + linkType: hard + +"@types/d3-quadtree@npm:*": + version: 3.0.6 + resolution: "@types/d3-quadtree@npm:3.0.6" + checksum: 10c0/7eaa0a4d404adc856971c9285e1c4ab17e9135ea669d847d6db7e0066126a28ac751864e7ce99c65d526e130f56754a2e437a1617877098b3bdcc3ef23a23616 + languageName: node + linkType: hard + +"@types/d3-random@npm:*": + version: 3.0.3 + resolution: "@types/d3-random@npm:3.0.3" + checksum: 10c0/5f4fea40080cd6d4adfee05183d00374e73a10c530276a6455348983dda341003a251def28565a27c25d9cf5296a33e870e397c9d91ff83fb7495a21c96b6882 + languageName: node + linkType: hard + +"@types/d3-scale-chromatic@npm:*": + version: 3.1.0 + resolution: "@types/d3-scale-chromatic@npm:3.1.0" + checksum: 10c0/93c564e02d2e97a048e18fe8054e4a935335da6ab75a56c3df197beaa87e69122eef0dfbeb7794d4a444a00e52e3123514ee27cec084bd21f6425b7037828cc2 + languageName: node + linkType: hard + +"@types/d3-scale@npm:*": + version: 4.0.9 + resolution: "@types/d3-scale@npm:4.0.9" + dependencies: + "@types/d3-time": "npm:*" + checksum: 10c0/4ac44233c05cd50b65b33ecb35d99fdf07566bcdbc55bc1306b2f27d1c5134d8c560d356f2c8e76b096e9125ffb8d26d95f78d56e210d1c542cb255bdf31d6c8 + languageName: node + linkType: hard + +"@types/d3-selection@npm:*": + version: 3.0.11 + resolution: "@types/d3-selection@npm:3.0.11" + checksum: 10c0/0c512956c7503ff5def4bb32e0c568cc757b9a2cc400a104fc0f4cfe5e56d83ebde2a97821b6f2cb26a7148079d3b86a2f28e11d68324ed311cf35c2ed980d1d + languageName: node + linkType: hard + +"@types/d3-shape@npm:*": + version: 3.1.8 + resolution: "@types/d3-shape@npm:3.1.8" + dependencies: + "@types/d3-path": "npm:*" + checksum: 10c0/49ec2172b9eb66fc1d036e2a23966216bb972e9af51ddbed134df24bd71aedf207bb1ef81903a119eb4e1f5e927cf44beacaf64c9af86474e5548594b102b574 + languageName: node + linkType: hard + +"@types/d3-time-format@npm:*": + version: 4.0.3 + resolution: "@types/d3-time-format@npm:4.0.3" + checksum: 10c0/9ef5e8e2b96b94799b821eed5d61a3d432c7903247966d8ad951b8ce5797fe46554b425cb7888fa5bf604b4663c369d7628c0328ffe80892156671c58d1a7f90 + languageName: node + linkType: hard + +"@types/d3-time@npm:*": + version: 3.0.4 + resolution: "@types/d3-time@npm:3.0.4" + checksum: 10c0/6d9e2255d63f7a313a543113920c612e957d70da4fb0890931da6c2459010291b8b1f95e149a538500c1c99e7e6c89ffcce5554dd29a31ff134a38ea94b6d174 + languageName: node + linkType: hard + +"@types/d3-timer@npm:*": + version: 3.0.2 + resolution: "@types/d3-timer@npm:3.0.2" + checksum: 10c0/c644dd9571fcc62b1aa12c03bcad40571553020feeb5811f1d8a937ac1e65b8a04b759b4873aef610e28b8714ac71c9885a4d6c127a048d95118f7e5b506d9e1 + languageName: node + linkType: hard + +"@types/d3-transition@npm:*": + version: 3.0.9 + resolution: "@types/d3-transition@npm:3.0.9" + dependencies: + "@types/d3-selection": "npm:*" + checksum: 10c0/4f68b9df7ac745b3491216c54203cbbfa0f117ae4c60e2609cdef2db963582152035407fdff995b10ee383bae2f05b7743493f48e1b8e46df54faa836a8fb7b5 + languageName: node + linkType: hard + +"@types/d3-zoom@npm:*": + version: 3.0.8 + resolution: "@types/d3-zoom@npm:3.0.8" + dependencies: + "@types/d3-interpolate": "npm:*" + "@types/d3-selection": "npm:*" + checksum: 10c0/1dbdbcafddcae12efb5beb6948546963f29599e18bc7f2a91fb69cc617c2299a65354f2d47e282dfb86fec0968406cd4fb7f76ba2d2fb67baa8e8d146eb4a547 + languageName: node + linkType: hard + +"@types/d3@npm:^7.4.3": + version: 7.4.3 + resolution: "@types/d3@npm:7.4.3" + dependencies: + "@types/d3-array": "npm:*" + "@types/d3-axis": "npm:*" + "@types/d3-brush": "npm:*" + "@types/d3-chord": "npm:*" + "@types/d3-color": "npm:*" + "@types/d3-contour": "npm:*" + "@types/d3-delaunay": "npm:*" + "@types/d3-dispatch": "npm:*" + "@types/d3-drag": "npm:*" + "@types/d3-dsv": "npm:*" + "@types/d3-ease": "npm:*" + "@types/d3-fetch": "npm:*" + "@types/d3-force": "npm:*" + "@types/d3-format": "npm:*" + "@types/d3-geo": "npm:*" + "@types/d3-hierarchy": "npm:*" + "@types/d3-interpolate": "npm:*" + "@types/d3-path": "npm:*" + "@types/d3-polygon": "npm:*" + "@types/d3-quadtree": "npm:*" + "@types/d3-random": "npm:*" + "@types/d3-scale": "npm:*" + "@types/d3-scale-chromatic": "npm:*" + "@types/d3-selection": "npm:*" + "@types/d3-shape": "npm:*" + "@types/d3-time": "npm:*" + "@types/d3-time-format": "npm:*" + "@types/d3-timer": "npm:*" + "@types/d3-transition": "npm:*" + "@types/d3-zoom": "npm:*" + checksum: 10c0/a9c6d65b13ef3b42c87f2a89ea63a6d5640221869f97d0657b0cb2f1dac96a0f164bf5605643c0794e0de3aa2bf05df198519aaf15d24ca135eb0e8bd8a9d879 + languageName: node + linkType: hard + +"@types/debug@npm:^4.0.0": + version: 4.1.12 + resolution: "@types/debug@npm:4.1.12" + dependencies: + "@types/ms": "npm:*" + checksum: 10c0/5dcd465edbb5a7f226e9a5efd1f399c6172407ef5840686b73e3608ce135eeca54ae8037dcd9f16bdb2768ac74925b820a8b9ecc588a58ca09eca6acabe33e2f + languageName: node + linkType: hard + +"@types/eslint-scope@npm:^3.7.7": + version: 3.7.7 + resolution: "@types/eslint-scope@npm:3.7.7" + dependencies: + "@types/eslint": "npm:*" + "@types/estree": "npm:*" + checksum: 10c0/a0ecbdf2f03912679440550817ff77ef39a30fa8bfdacaf6372b88b1f931828aec392f52283240f0d648cf3055c5ddc564544a626bcf245f3d09fcb099ebe3cc + languageName: node + linkType: hard + +"@types/eslint@npm:*": + version: 9.6.1 + resolution: "@types/eslint@npm:9.6.1" + dependencies: + "@types/estree": "npm:*" + "@types/json-schema": "npm:*" + checksum: 10c0/69ba24fee600d1e4c5abe0df086c1a4d798abf13792d8cfab912d76817fe1a894359a1518557d21237fbaf6eda93c5ab9309143dee4c59ef54336d1b3570420e + languageName: node + linkType: hard + +"@types/estree-jsx@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree-jsx@npm:1.0.5" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/07b354331516428b27a3ab99ee397547d47eb223c34053b48f84872fafb841770834b90cc1a0068398e7c7ccb15ec51ab00ec64b31dc5e3dbefd624638a35c6d + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": + version: 1.0.6 + resolution: "@types/estree@npm:1.0.6" + checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a + languageName: node + linkType: hard + +"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.21, @types/express-serve-static-core@npm:^4.17.33": + version: 4.19.8 + resolution: "@types/express-serve-static-core@npm:4.19.8" + dependencies: + "@types/node": "npm:*" + "@types/qs": "npm:*" + "@types/range-parser": "npm:*" + "@types/send": "npm:*" + checksum: 10c0/6fb58a85b209e0e421b29c52e0a51dbf7c039b711c604cf45d46470937a5c7c16b30aa5ce9bf7da0bd8a2e9361c95b5055599c0500a96bf4414d26c81f02d7fe + languageName: node + linkType: hard + +"@types/express@npm:*, @types/express@npm:^4.17.25": + version: 4.17.25 + resolution: "@types/express@npm:4.17.25" + dependencies: + "@types/body-parser": "npm:*" + "@types/express-serve-static-core": "npm:^4.17.33" + "@types/qs": "npm:*" + "@types/serve-static": "npm:^1" + checksum: 10c0/f42b616d2c9dbc50352c820db7de182f64ebbfa8dba6fb6c98e5f8f0e2ef3edde0131719d9dc6874803d25ad9ca2d53471d0fec2fbc60a6003a43d015bab72c4 + languageName: node + linkType: hard + +"@types/geojson@npm:*": + version: 7946.0.16 + resolution: "@types/geojson@npm:7946.0.16" + checksum: 10c0/1ff24a288bd5860b766b073ead337d31d73bdc715e5b50a2cee5cb0af57a1ed02cc04ef295f5fa68dc40fe3e4f104dd31282b2b818a5ba3231bc1001ba084e3c + languageName: node + linkType: hard + +"@types/gtag.js@npm:^0.0.20": + version: 0.0.20 + resolution: "@types/gtag.js@npm:0.0.20" + checksum: 10c0/eb878aa3cfab6b98f5e69ef3383e9788aaea6a4d0611c72078678374dcbb4731f533ff2bf479a865536f1626a57887b1198279ff35a65d223fe4f93d9c76dbdd + languageName: node + linkType: hard + +"@types/hast@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + +"@types/history@npm:^4.7.11": + version: 4.7.11 + resolution: "@types/history@npm:4.7.11" + checksum: 10c0/3facf37c2493d1f92b2e93a22cac7ea70b06351c2ab9aaceaa3c56aa6099fb63516f6c4ec1616deb5c56b4093c026a043ea2d3373e6c0644d55710364d02c934 + languageName: node + linkType: hard + +"@types/html-minifier-terser@npm:^6.0.0": + version: 6.1.0 + resolution: "@types/html-minifier-terser@npm:6.1.0" + checksum: 10c0/a62fb8588e2f3818d82a2d7b953ad60a4a52fd767ae04671de1c16f5788bd72f1ed3a6109ed63fd190c06a37d919e3c39d8adbc1793a005def76c15a3f5f5dab + languageName: node + linkType: hard + +"@types/http-cache-semantics@npm:^4.0.2": + version: 4.0.4 + resolution: "@types/http-cache-semantics@npm:4.0.4" + checksum: 10c0/51b72568b4b2863e0fe8d6ce8aad72a784b7510d72dc866215642da51d84945a9459fa89f49ec48f1e9a1752e6a78e85a4cda0ded06b1c73e727610c925f9ce6 + languageName: node + linkType: hard + +"@types/http-errors@npm:*": + version: 2.0.5 + resolution: "@types/http-errors@npm:2.0.5" + checksum: 10c0/00f8140fbc504f47356512bd88e1910c2f07e04233d99c88c854b3600ce0523c8cd0ba7d1897667243282eb44c59abb9245959e2428b9de004f93937f52f7c15 + languageName: node + linkType: hard + +"@types/http-proxy@npm:^1.17.8": + version: 1.17.17 + resolution: "@types/http-proxy@npm:1.17.17" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/547e322a5eecf0b50d08f6a46bd89c8c8663d67dbdcd472da5daf968b03e63a82f6b3650443378abe6c10a46475dac52015f30e8c74ba2ea5820dd4e9cdef2d4 + languageName: node + linkType: hard + +"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0": + version: 2.0.6 + resolution: "@types/istanbul-lib-coverage@npm:2.0.6" + checksum: 10c0/3948088654f3eeb45363f1db158354fb013b362dba2a5c2c18c559484d5eb9f6fd85b23d66c0a7c2fcfab7308d0a585b14dadaca6cc8bf89ebfdc7f8f5102fb7 + languageName: node + linkType: hard + +"@types/istanbul-lib-report@npm:*": + version: 3.0.3 + resolution: "@types/istanbul-lib-report@npm:3.0.3" + dependencies: + "@types/istanbul-lib-coverage": "npm:*" + checksum: 10c0/247e477bbc1a77248f3c6de5dadaae85ff86ac2d76c5fc6ab1776f54512a745ff2a5f791d22b942e3990ddbd40f3ef5289317c4fca5741bedfaa4f01df89051c + languageName: node + linkType: hard + +"@types/istanbul-reports@npm:^3.0.0": + version: 3.0.4 + resolution: "@types/istanbul-reports@npm:3.0.4" + dependencies: + "@types/istanbul-lib-report": "npm:*" + checksum: 10c0/1647fd402aced5b6edac87274af14ebd6b3a85447ef9ad11853a70fd92a98d35f81a5d3ea9fcb5dbb5834e800c6e35b64475e33fcae6bfa9acc70d61497c54ee + languageName: node + linkType: hard + +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db + languageName: node + linkType: hard + +"@types/mdast@npm:^4.0.0, @types/mdast@npm:^4.0.2": + version: 4.0.4 + resolution: "@types/mdast@npm:4.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/84f403dbe582ee508fd9c7643ac781ad8597fcbfc9ccb8d4715a2c92e4545e5772cbd0dbdf18eda65789386d81b009967fdef01b24faf6640f817287f54d9c82 + languageName: node + linkType: hard + +"@types/mdx@npm:^2.0.0": + version: 2.0.13 + resolution: "@types/mdx@npm:2.0.13" + checksum: 10c0/5edf1099505ac568da55f9ae8a93e7e314e8cbc13d3445d0be61b75941226b005e1390d9b95caecf5dcb00c9d1bab2f1f60f6ff9876dc091a48b547495007720 + languageName: node + linkType: hard + +"@types/mime@npm:^1": + version: 1.3.5 + resolution: "@types/mime@npm:1.3.5" + checksum: 10c0/c2ee31cd9b993804df33a694d5aa3fa536511a49f2e06eeab0b484fef59b4483777dbb9e42a4198a0809ffbf698081fdbca1e5c2218b82b91603dfab10a10fbc + languageName: node + linkType: hard + +"@types/ms@npm:*": + version: 2.1.0 + resolution: "@types/ms@npm:2.1.0" + checksum: 10c0/5ce692ffe1549e1b827d99ef8ff71187457e0eb44adbae38fdf7b9a74bae8d20642ee963c14516db1d35fa2652e65f47680fdf679dcbde52bbfadd021f497225 + languageName: node + linkType: hard + +"@types/node@npm:*": + version: 22.13.10 + resolution: "@types/node@npm:22.13.10" + dependencies: + undici-types: "npm:~6.20.0" + checksum: 10c0/a3865f9503d6f718002374f7b87efaadfae62faa499c1a33b12c527cfb9fd86f733e1a1b026b80c5a0e4a965701174bc3305595a7d36078aa1abcf09daa5dee9 + languageName: node + linkType: hard + +"@types/node@npm:^17.0.5": + version: 17.0.45 + resolution: "@types/node@npm:17.0.45" + checksum: 10c0/0db377133d709b33a47892581a21a41cd7958f22723a3cc6c71d55ac018121382de42fbfc7970d5ae3e7819dbe5f40e1c6a5174aedf7e7964e9cb8fa72b580b0 + languageName: node + linkType: hard + +"@types/prismjs@npm:^1.26.0": + version: 1.26.5 + resolution: "@types/prismjs@npm:1.26.5" + checksum: 10c0/5619cb449e0d8df098c8759d6f47bf8fdd510abf5dbdfa999e55c6a2545efbd1e209cc85a33d8d9f4ff2898089a1a6d9a70737c9baffaae635c46852c40d384a + languageName: node + linkType: hard + +"@types/qs@npm:*": + version: 6.15.0 + resolution: "@types/qs@npm:6.15.0" + checksum: 10c0/1b104cac50e655fc41d7fc1de2c2aba2908c4cf833a555b6808fb4c96752662b439238f2392a15d2590a7a6ca75dbd40e42d9378ac2be0d548ee484954363688 + languageName: node + linkType: hard + +"@types/range-parser@npm:*": + version: 1.2.7 + resolution: "@types/range-parser@npm:1.2.7" + checksum: 10c0/361bb3e964ec5133fa40644a0b942279ed5df1949f21321d77de79f48b728d39253e5ce0408c9c17e4e0fd95ca7899da36841686393b9f7a1e209916e9381a3c + languageName: node + linkType: hard + +"@types/react-router-config@npm:*, @types/react-router-config@npm:^5.0.7": + version: 5.0.11 + resolution: "@types/react-router-config@npm:5.0.11" + dependencies: + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + "@types/react-router": "npm:^5.1.0" + checksum: 10c0/3fa4daf8c14689a05f34e289fc53c4a892e97f35715455c507a8048d9875b19cd3d3142934ca973effed6a6c38f33539b6e173cd254f67e2021ecd5458d551c8 + languageName: node + linkType: hard + +"@types/react-router-dom@npm:*": + version: 5.3.3 + resolution: "@types/react-router-dom@npm:5.3.3" + dependencies: + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + "@types/react-router": "npm:*" + checksum: 10c0/a9231a16afb9ed5142678147eafec9d48582809295754fb60946e29fcd3757a4c7a3180fa94b45763e4c7f6e3f02379e2fcb8dd986db479dcab40eff5fc62a91 + languageName: node + linkType: hard + +"@types/react-router@npm:*, @types/react-router@npm:^5.1.0": + version: 5.1.20 + resolution: "@types/react-router@npm:5.1.20" + dependencies: + "@types/history": "npm:^4.7.11" + "@types/react": "npm:*" + checksum: 10c0/1f7eee61981d2f807fa01a34a0ef98ebc0774023832b6611a69c7f28fdff01de5a38cabf399f32e376bf8099dcb7afaf724775bea9d38870224492bea4cb5737 + languageName: node + linkType: hard + +"@types/react@npm:*": + version: 19.0.11 + resolution: "@types/react@npm:19.0.11" + dependencies: + csstype: "npm:^3.0.2" + checksum: 10c0/386cdde579b60e22160d6894a985655742703346bdc71fed9809f8f90ca87e2dd0252e86b81f92621a2c1de8d0fbf35e3963996db8c451cc670570061ed62f29 + languageName: node + linkType: hard + +"@types/retry@npm:0.12.2": + version: 0.12.2 + resolution: "@types/retry@npm:0.12.2" + checksum: 10c0/07481551a988cc90b423351919928b9ddcd14e3f5591cac3ab950851bb20646e55a10e89141b38bc3093d2056d4df73700b22ff2612976ac86a6367862381884 + languageName: node + linkType: hard + +"@types/sax@npm:^1.2.1": + version: 1.2.7 + resolution: "@types/sax@npm:1.2.7" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/d077a761a0753b079bf8279b3993948030ca86ed9125437b9b29c1de40db9b2deb7fddc369f014b58861d450e8b8cc75f163aa29dc8cea81952efbfd859168cf + languageName: node + linkType: hard + +"@types/send@npm:*": + version: 1.2.1 + resolution: "@types/send@npm:1.2.1" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/7673747f8c2d8e67f3b1b3b57e9d4d681801a4f7b526ecf09987bb9a84a61cf94aa411c736183884dc762c1c402a61681eb1ef200d8d45d7e5ec0ab67ea5f6c1 + languageName: node + linkType: hard + +"@types/send@npm:<1": + version: 0.17.6 + resolution: "@types/send@npm:0.17.6" + dependencies: + "@types/mime": "npm:^1" + "@types/node": "npm:*" + checksum: 10c0/a9d76797f0637738062f1b974e0fcf3d396a28c5dc18c3f95ecec5dabda82e223afbc2d56a0bca46b6326fd7bb229979916cea40de2270a98128fd94441b87c2 + languageName: node + linkType: hard + +"@types/serve-index@npm:^1.9.4": + version: 1.9.4 + resolution: "@types/serve-index@npm:1.9.4" + dependencies: + "@types/express": "npm:*" + checksum: 10c0/94c1b9e8f1ea36a229e098e1643d5665d9371f8c2658521718e259130a237c447059b903bac0dcc96ee2c15fd63f49aa647099b7d0d437a67a6946527a837438 + languageName: node + linkType: hard + +"@types/serve-static@npm:^1, @types/serve-static@npm:^1.15.5": + version: 1.15.10 + resolution: "@types/serve-static@npm:1.15.10" + dependencies: + "@types/http-errors": "npm:*" + "@types/node": "npm:*" + "@types/send": "npm:<1" + checksum: 10c0/842fca14c9e80468f89b6cea361773f2dcd685d4616a9f59013b55e1e83f536e4c93d6d8e3ba5072d40c4e7e64085210edd6646b15d538ded94512940a23021f + languageName: node + linkType: hard + +"@types/sockjs@npm:^0.3.36": + version: 0.3.36 + resolution: "@types/sockjs@npm:0.3.36" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/b20b7820ee813f22de4f2ce98bdd12c68c930e016a8912b1ed967595ac0d8a4cbbff44f4d486dd97f77f5927e7b5725bdac7472c9ec5b27f53a5a13179f0612f + languageName: node + linkType: hard + +"@types/stack-trace@npm:0.0.29": + version: 0.0.29 + resolution: "@types/stack-trace@npm:0.0.29" + checksum: 10c0/401a1f80039706dd9f058336c797702ef3837bf34a663e4213c3b58be255b0649d699f65f8652976fb517146926c2ed5ebc8b6897e7460b99e16b84adc7fc985 + languageName: node + linkType: hard + +"@types/trusted-types@npm:^2.0.7": + version: 2.0.7 + resolution: "@types/trusted-types@npm:2.0.7" + checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c + languageName: node + linkType: hard + +"@types/unist@npm:*, @types/unist@npm:^3.0.0": + version: 3.0.3 + resolution: "@types/unist@npm:3.0.3" + checksum: 10c0/2b1e4adcab78388e088fcc3c0ae8700f76619dbcb4741d7d201f87e2cb346bfc29a89003cfea2d76c996e1061452e14fcd737e8b25aacf949c1f2d6b2bc3dd60 + languageName: node + linkType: hard + +"@types/unist@npm:^2.0.0": + version: 2.0.11 + resolution: "@types/unist@npm:2.0.11" + checksum: 10c0/24dcdf25a168f453bb70298145eb043cfdbb82472db0bc0b56d6d51cd2e484b9ed8271d4ac93000a80da568f2402e9339723db262d0869e2bf13bc58e081768d + languageName: node + linkType: hard + +"@types/ws@npm:^8.5.10": + version: 8.18.1 + resolution: "@types/ws@npm:8.18.1" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/61aff1129143fcc4312f083bc9e9e168aa3026b7dd6e70796276dcfb2c8211c4292603f9c4864fae702f2ed86e4abd4d38aa421831c2fd7f856c931a481afbab + languageName: node + linkType: hard + +"@types/yargs-parser@npm:*": + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: 10c0/e71c3bd9d0b73ca82e10bee2064c384ab70f61034bbfb78e74f5206283fc16a6d85267b606b5c22cb2a3338373586786fed595b2009825d6a9115afba36560a0 + languageName: node + linkType: hard + +"@types/yargs@npm:^17.0.8": + version: 17.0.35 + resolution: "@types/yargs@npm:17.0.35" + dependencies: + "@types/yargs-parser": "npm:*" + checksum: 10c0/609557826a6b85e73ccf587923f6429850d6dc70e420b455bab4601b670bfadf684b09ae288bccedab042c48ba65f1666133cf375814204b544009f57d6eef63 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.0.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 10c0/0fc3097c2540ada1fc340ee56d58d96b5b536a2a0dab6e3ec17d4bfc8c4c86db345f61a375a8185f9da96f01c69678f836a2b57eeaa9e4b8eeafd26428e57b0a + languageName: node + linkType: hard + +"@upsetjs/venn.js@npm:^2.0.0": + version: 2.0.0 + resolution: "@upsetjs/venn.js@npm:2.0.0" + dependencies: + d3-selection: "npm:^3.0.0" + d3-transition: "npm:^3.0.1" + dependenciesMeta: + d3-selection: + optional: true + d3-transition: + optional: true + checksum: 10c0/b12014d94708ab4df7f5a4b6205c6f23ff235cca2ffe91df3314862b109b826e52f9020c2a2f7527d3712d21c578d6db9cdb60ce46a528739cc18e58d111f724 + languageName: node + linkType: hard + +"@webassemblyjs/ast@npm:1.14.1, @webassemblyjs/ast@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/ast@npm:1.14.1" + dependencies: + "@webassemblyjs/helper-numbers": "npm:1.13.2" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + checksum: 10c0/67a59be8ed50ddd33fbb2e09daa5193ac215bf7f40a9371be9a0d9797a114d0d1196316d2f3943efdb923a3d809175e1563a3cb80c814fb8edccd1e77494972b + languageName: node + linkType: hard + +"@webassemblyjs/floating-point-hex-parser@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.13.2" + checksum: 10c0/0e88bdb8b50507d9938be64df0867f00396b55eba9df7d3546eb5dc0ca64d62e06f8d881ec4a6153f2127d0f4c11d102b6e7d17aec2f26bb5ff95a5e60652412 + languageName: node + linkType: hard + +"@webassemblyjs/helper-api-error@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-api-error@npm:1.13.2" + checksum: 10c0/31be497f996ed30aae4c08cac3cce50c8dcd5b29660383c0155fce1753804fc55d47fcba74e10141c7dd2899033164e117b3bcfcda23a6b043e4ded4f1003dfb + languageName: node + linkType: hard + +"@webassemblyjs/helper-buffer@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/helper-buffer@npm:1.14.1" + checksum: 10c0/0d54105dc373c0fe6287f1091e41e3a02e36cdc05e8cf8533cdc16c59ff05a646355415893449d3768cda588af451c274f13263300a251dc11a575bc4c9bd210 + languageName: node + linkType: hard + +"@webassemblyjs/helper-numbers@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-numbers@npm:1.13.2" + dependencies: + "@webassemblyjs/floating-point-hex-parser": "npm:1.13.2" + "@webassemblyjs/helper-api-error": "npm:1.13.2" + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/9c46852f31b234a8fb5a5a9d3f027bc542392a0d4de32f1a9c0075d5e8684aa073cb5929b56df565500b3f9cc0a2ab983b650314295b9bf208d1a1651bfc825a + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-bytecode@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.13.2" + checksum: 10c0/c4355d14f369b30cf3cbdd3acfafc7d0488e086be6d578e3c9780bd1b512932352246be96e034e2a7fcfba4f540ec813352f312bfcbbfe5bcfbf694f82ccc682 + languageName: node + linkType: hard + +"@webassemblyjs/helper-wasm-section@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/helper-wasm-section@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + checksum: 10c0/1f9b33731c3c6dbac3a9c483269562fa00d1b6a4e7133217f40e83e975e636fd0f8736e53abd9a47b06b66082ecc976c7384391ab0a68e12d509ea4e4b948d64 + languageName: node + linkType: hard + +"@webassemblyjs/ieee754@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/ieee754@npm:1.13.2" + dependencies: + "@xtuc/ieee754": "npm:^1.2.0" + checksum: 10c0/2e732ca78c6fbae3c9b112f4915d85caecdab285c0b337954b180460290ccd0fb00d2b1dc4bb69df3504abead5191e0d28d0d17dfd6c9d2f30acac8c4961c8a7 + languageName: node + linkType: hard + +"@webassemblyjs/leb128@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/leb128@npm:1.13.2" + dependencies: + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/dad5ef9e383c8ab523ce432dfd80098384bf01c45f70eb179d594f85ce5db2f80fa8c9cba03adafd85684e6d6310f0d3969a882538975989919329ac4c984659 + languageName: node + linkType: hard + +"@webassemblyjs/utf8@npm:1.13.2": + version: 1.13.2 + resolution: "@webassemblyjs/utf8@npm:1.13.2" + checksum: 10c0/d3fac9130b0e3e5a1a7f2886124a278e9323827c87a2b971e6d0da22a2ba1278ac9f66a4f2e363ecd9fac8da42e6941b22df061a119e5c0335f81006de9ee799 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-edit@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-edit@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/helper-wasm-section": "npm:1.14.1" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + "@webassemblyjs/wasm-opt": "npm:1.14.1" + "@webassemblyjs/wasm-parser": "npm:1.14.1" + "@webassemblyjs/wast-printer": "npm:1.14.1" + checksum: 10c0/5ac4781086a2ca4b320bdbfd965a209655fe8a208ca38d89197148f8597e587c9a2c94fb6bd6f1a7dbd4527c49c6844fcdc2af981f8d793a97bf63a016aa86d2 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-gen@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-gen@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/ieee754": "npm:1.13.2" + "@webassemblyjs/leb128": "npm:1.13.2" + "@webassemblyjs/utf8": "npm:1.13.2" + checksum: 10c0/d678810d7f3f8fecb2e2bdadfb9afad2ec1d2bc79f59e4711ab49c81cec578371e22732d4966f59067abe5fba8e9c54923b57060a729d28d408e608beef67b10 + languageName: node + linkType: hard + +"@webassemblyjs/wasm-opt@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-opt@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-buffer": "npm:1.14.1" + "@webassemblyjs/wasm-gen": "npm:1.14.1" + "@webassemblyjs/wasm-parser": "npm:1.14.1" + checksum: 10c0/515bfb15277ee99ba6b11d2232ddbf22aed32aad6d0956fe8a0a0a004a1b5a3a277a71d9a3a38365d0538ac40d1b7b7243b1a244ad6cd6dece1c1bb2eb5de7ee + languageName: node + linkType: hard + +"@webassemblyjs/wasm-parser@npm:1.14.1, @webassemblyjs/wasm-parser@npm:^1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wasm-parser@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@webassemblyjs/helper-api-error": "npm:1.13.2" + "@webassemblyjs/helper-wasm-bytecode": "npm:1.13.2" + "@webassemblyjs/ieee754": "npm:1.13.2" + "@webassemblyjs/leb128": "npm:1.13.2" + "@webassemblyjs/utf8": "npm:1.13.2" + checksum: 10c0/95427b9e5addbd0f647939bd28e3e06b8deefdbdadcf892385b5edc70091bf9b92fa5faac3fce8333554437c5d85835afef8c8a7d9d27ab6ba01ffab954db8c6 + languageName: node + linkType: hard + +"@webassemblyjs/wast-printer@npm:1.14.1": + version: 1.14.1 + resolution: "@webassemblyjs/wast-printer@npm:1.14.1" + dependencies: + "@webassemblyjs/ast": "npm:1.14.1" + "@xtuc/long": "npm:4.2.2" + checksum: 10c0/8d7768608996a052545251e896eac079c98e0401842af8dd4de78fba8d90bd505efb6c537e909cd6dae96e09db3fa2e765a6f26492553a675da56e2db51f9d24 + languageName: node + linkType: hard + +"@xtuc/ieee754@npm:^1.2.0": + version: 1.2.0 + resolution: "@xtuc/ieee754@npm:1.2.0" + checksum: 10c0/a8565d29d135039bd99ae4b2220d3e167d22cf53f867e491ed479b3f84f895742d0097f935b19aab90265a23d5d46711e4204f14c479ae3637fbf06c4666882f + languageName: node + linkType: hard + +"@xtuc/long@npm:4.2.2": + version: 4.2.2 + resolution: "@xtuc/long@npm:4.2.2" + checksum: 10c0/8582cbc69c79ad2d31568c412129bf23d2b1210a1dfb60c82d5a1df93334da4ee51f3057051658569e2c196d8dc33bc05ae6b974a711d0d16e801e1d0647ccd1 + languageName: node + linkType: hard + +"abbrev@npm:^4.0.0": + version: 4.0.0 + resolution: "abbrev@npm:4.0.0" + checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 + languageName: node + linkType: hard + +"accepts@npm:~1.3.8": + version: 1.3.8 + resolution: "accepts@npm:1.3.8" + dependencies: + mime-types: "npm:~2.1.34" + negotiator: "npm:0.6.3" + checksum: 10c0/3a35c5f5586cfb9a21163ca47a5f77ac34fa8ceb5d17d2fa2c0d81f41cbd7f8c6fa52c77e2c039acc0f4d09e71abdc51144246900f6bef5e3c4b333f77d89362 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.0.0": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 + languageName: node + linkType: hard + +"acorn-walk@npm:^8.0.0": + version: 8.3.4 + resolution: "acorn-walk@npm:8.3.4" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10c0/76537ac5fb2c37a64560feaf3342023dadc086c46da57da363e64c6148dc21b57d49ace26f949e225063acb6fb441eabffd89f7a3066de5ad37ab3e328927c62 + languageName: node + linkType: hard + +"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.14.0, acorn@npm:^8.8.2": + version: 8.14.1 + resolution: "acorn@npm:8.14.1" + bin: + acorn: bin/acorn + checksum: 10c0/dbd36c1ed1d2fa3550140000371fcf721578095b18777b85a79df231ca093b08edc6858d75d6e48c73e431c174dcf9214edbd7e6fa5911b93bd8abfa54e47123 + languageName: node + linkType: hard + +"acorn@npm:^8.16.0": + version: 8.16.0 + resolution: "acorn@npm:8.16.0" + bin: + acorn: bin/acorn + checksum: 10c0/c9c52697227661b68d0debaf972222d4f622aa06b185824164e153438afa7b08273432ca43ea792cadb24dada1d46f6f6bb1ef8de9956979288cc1b96bf9914e + languageName: node + linkType: hard + +"address@npm:^1.0.1": + version: 1.2.2 + resolution: "address@npm:1.2.2" + checksum: 10c0/1c8056b77fb124456997b78ed682ecc19d2fd7ea8bd5850a2aa8c3e3134c913847c57bcae418622efd32ba858fa1e242a40a251ac31da0515664fc0ac03a047d + languageName: node + linkType: hard + +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe + languageName: node + linkType: hard + +"aggregate-error@npm:^3.0.0": + version: 3.1.0 + resolution: "aggregate-error@npm:3.1.0" + dependencies: + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 + languageName: node + linkType: hard + +"ajv-formats@npm:^2.1.1": + version: 2.1.1 + resolution: "ajv-formats@npm:2.1.1" + dependencies: + ajv: "npm:^8.0.0" + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 10c0/e43ba22e91b6a48d96224b83d260d3a3a561b42d391f8d3c6d2c1559f9aa5b253bfb306bc94bbeca1d967c014e15a6efe9a207309e95b3eaae07fcbcdc2af662 + languageName: node + linkType: hard + +"ajv-keywords@npm:^3.5.2": + version: 3.5.2 + resolution: "ajv-keywords@npm:3.5.2" + peerDependencies: + ajv: ^6.9.1 + checksum: 10c0/0c57a47cbd656e8cdfd99d7c2264de5868918ffa207c8d7a72a7f63379d4333254b2ba03d69e3c035e996a3fd3eb6d5725d7a1597cca10694296e32510546360 + languageName: node + linkType: hard + +"ajv-keywords@npm:^5.1.0": + version: 5.1.0 + resolution: "ajv-keywords@npm:5.1.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + peerDependencies: + ajv: ^8.8.2 + checksum: 10c0/18bec51f0171b83123ba1d8883c126e60c6f420cef885250898bf77a8d3e65e3bfb9e8564f497e30bdbe762a83e0d144a36931328616a973ee669dc74d4a9590 + languageName: node + linkType: hard + +"ajv@npm:^6.12.5": + version: 6.14.0 + resolution: "ajv@npm:6.14.0" + dependencies: + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/a2bc39b0555dc9802c899f86990eb8eed6e366cddbf65be43d5aa7e4f3c4e1a199d5460fd7ca4fb3d864000dbbc049253b72faa83b3b30e641ca52cb29a68c22 + languageName: node + linkType: hard + +"ajv@npm:^8.0.0, ajv@npm:^8.9.0": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35 + languageName: node + linkType: hard + +"algoliasearch-helper@npm:^3.26.0": + version: 3.28.0 + resolution: "algoliasearch-helper@npm:3.28.0" + dependencies: + "@algolia/events": "npm:^4.0.1" + peerDependencies: + algoliasearch: ">= 3.1 < 6" + checksum: 10c0/a354f6a5074dd5c548ef112f5aec51720cdb0f28ad6144f4d6d9c8829f934722b55f1aa34dfb261a7247330fd7a0de1b6028846a08419b6ca4090456ab0d57fb + languageName: node + linkType: hard + +"algoliasearch@npm:^5.37.0": + version: 5.49.2 + resolution: "algoliasearch@npm:5.49.2" + dependencies: + "@algolia/abtesting": "npm:1.15.2" + "@algolia/client-abtesting": "npm:5.49.2" + "@algolia/client-analytics": "npm:5.49.2" + "@algolia/client-common": "npm:5.49.2" + "@algolia/client-insights": "npm:5.49.2" + "@algolia/client-personalization": "npm:5.49.2" + "@algolia/client-query-suggestions": "npm:5.49.2" + "@algolia/client-search": "npm:5.49.2" + "@algolia/ingestion": "npm:1.49.2" + "@algolia/monitoring": "npm:1.49.2" + "@algolia/recommend": "npm:5.49.2" + "@algolia/requester-browser-xhr": "npm:5.49.2" + "@algolia/requester-fetch": "npm:5.49.2" + "@algolia/requester-node-http": "npm:5.49.2" + checksum: 10c0/af3f3b743393755c649c96c9221e2cc385c032d3ac66cc83e1d6e1ca9f47dcb20929f9f0b6dd7fa4f06af2c19fc6d9b623a676a7e652f370095ad98f7c4b824b + languageName: node + linkType: hard + +"ansi-align@npm:^3.0.1": + version: 3.0.1 + resolution: "ansi-align@npm:3.0.1" + dependencies: + string-width: "npm:^4.1.0" + checksum: 10c0/ad8b755a253a1bc8234eb341e0cec68a857ab18bf97ba2bda529e86f6e30460416523e0ec58c32e5c21f0ca470d779503244892873a5895dbd0c39c788e82467 + languageName: node + linkType: hard + +"ansi-escapes@npm:^4.3.2": + version: 4.3.2 + resolution: "ansi-escapes@npm:4.3.2" + dependencies: + type-fest: "npm:^0.21.3" + checksum: 10c0/da917be01871525a3dfcf925ae2977bc59e8c513d4423368645634bf5d4ceba5401574eb705c1e92b79f7292af5a656f78c5725a4b0e1cec97c4b413705c1d50 + languageName: node + linkType: hard + +"ansi-html-community@npm:^0.0.8": + version: 0.0.8 + resolution: "ansi-html-community@npm:0.0.8" + bin: + ansi-html: bin/ansi-html + checksum: 10c0/45d3a6f0b4f10b04fdd44bef62972e2470bfd917bf00439471fa7473d92d7cbe31369c73db863cc45dda115cb42527f39e232e9256115534b8ee5806b0caeed4 + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.1.0 + resolution: "ansi-regex@npm:6.1.0" + checksum: 10c0/a91daeddd54746338478eef88af3439a7edf30f8e23196e2d6ed182da9add559c601266dbef01c2efa46a958ad6f1f8b176799657616c702b5b02e799e7fd8dc + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: "npm:^2.0.1" + checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c + languageName: node + linkType: hard + +"anymatch@npm:~3.1.2": + version: 3.1.3 + resolution: "anymatch@npm:3.1.3" + dependencies: + normalize-path: "npm:^3.0.0" + picomatch: "npm:^2.0.4" + checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac + languageName: node + linkType: hard + +"arg@npm:^5.0.0": + version: 5.0.2 + resolution: "arg@npm:5.0.2" + checksum: 10c0/ccaf86f4e05d342af6666c569f844bec426595c567d32a8289715087825c2ca7edd8a3d204e4d2fb2aa4602e09a57d0c13ea8c9eea75aac3dbb4af5514e6800e + languageName: node + linkType: hard + +"argparse@npm:^1.0.7": + version: 1.0.10 + resolution: "argparse@npm:1.0.10" + dependencies: + sprintf-js: "npm:~1.0.2" + checksum: 10c0/b2972c5c23c63df66bca144dbc65d180efa74f25f8fd9b7d9a0a6c88ae839db32df3d54770dcb6460cf840d232b60695d1a6b1053f599d84e73f7437087712de + languageName: node + linkType: hard + +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e + languageName: node + linkType: hard + +"array-flatten@npm:1.1.1": + version: 1.1.1 + resolution: "array-flatten@npm:1.1.1" + checksum: 10c0/806966c8abb2f858b08f5324d9d18d7737480610f3bd5d3498aaae6eb5efdc501a884ba019c9b4a8f02ff67002058749d05548fd42fa8643f02c9c7f22198b91 + languageName: node + linkType: hard + +"array-union@npm:^2.1.0": + version: 2.1.0 + resolution: "array-union@npm:2.1.0" + checksum: 10c0/429897e68110374f39b771ec47a7161fc6a8fc33e196857c0a396dc75df0b5f65e4d046674db764330b6bb66b39ef48dd7c53b6a2ee75cfb0681e0c1a7033962 + languageName: node + linkType: hard + +"asn1js@npm:^3.0.6": + version: 3.0.7 + resolution: "asn1js@npm:3.0.7" + dependencies: + pvtsutils: "npm:^1.3.6" + pvutils: "npm:^1.1.3" + tslib: "npm:^2.8.1" + checksum: 10c0/7e79795edf1bcc86532c4084aa7c8c0ebc57f7dd6f964ad6de956abf617329722f6964b7af3a5d1c4554dd61b4b148ae1580e63e3ec2e70e7fba34f6df072b29 + languageName: node + linkType: hard + +"astring@npm:^1.8.0": + version: 1.9.0 + resolution: "astring@npm:1.9.0" + bin: + astring: bin/astring + checksum: 10c0/e7519544d9824494e80ef0e722bb3a0c543a31440d59691c13aeaceb75b14502af536b23f08db50aa6c632dafaade54caa25f0788aa7550b6b2d6e2df89e0830 + languageName: node + linkType: hard + +"autoprefixer@npm:^10.4.19, autoprefixer@npm:^10.4.23": + version: 10.4.27 + resolution: "autoprefixer@npm:10.4.27" + dependencies: + browserslist: "npm:^4.28.1" + caniuse-lite: "npm:^1.0.30001774" + fraction.js: "npm:^5.3.4" + picocolors: "npm:^1.1.1" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.1.0 + bin: + autoprefixer: bin/autoprefixer + checksum: 10c0/698ad9e23436635af1806d4a8b80393020135174d1d4a97eb81887cdddac2f297f198d1d717932db8503b325f9f2dc3accb6e290b2d3ce1a7ddeb947100e5b25 + languageName: node + linkType: hard + +"babel-loader@npm:^9.2.1": + version: 9.2.1 + resolution: "babel-loader@npm:9.2.1" + dependencies: + find-cache-dir: "npm:^4.0.0" + schema-utils: "npm:^4.0.0" + peerDependencies: + "@babel/core": ^7.12.0 + webpack: ">=5" + checksum: 10c0/efb82faff4c7c27e9c15bb28bf11c73200e61cf365118a9514e8d74dd489d0afc2a0d5aaa62cb4254eefc2ab631579224d95a03fd245410f28ea75e24de54ba4 + languageName: node + linkType: hard + +"babel-plugin-dynamic-import-node@npm:^2.3.3": + version: 2.3.3 + resolution: "babel-plugin-dynamic-import-node@npm:2.3.3" + dependencies: + object.assign: "npm:^4.1.0" + checksum: 10c0/1bd80df981e1fc1aff0cd4e390cf27aaa34f95f7620cd14dff07ba3bad56d168c098233a7d2deb2c9b1dc13643e596a6b94fc608a3412ee3c56e74a25cd2167e + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs2@npm:^0.4.14, babel-plugin-polyfill-corejs2@npm:^0.4.15": + version: 0.4.17 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.17" + dependencies: + "@babel/compat-data": "npm:^7.28.6" + "@babel/helper-define-polyfill-provider": "npm:^0.6.8" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/1284960ea403c63b0dd598f338666c4b17d489aefee30b4da6a7313eff1d91edffb0ccf26341a6e5d94231684b74e016eade66b3921ea112f8b0e4980fa08a5c + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs3@npm:^0.13.0": + version: 0.13.0 + resolution: "babel-plugin-polyfill-corejs3@npm:0.13.0" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.5" + core-js-compat: "npm:^3.43.0" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/5d8e228da425edc040d8c868486fd01ba10b0440f841156a30d9f8986f330f723e2ee61553c180929519563ef5b64acce2caac36a5a847f095d708dda5d8206d + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs3@npm:^0.14.0": + version: 0.14.2 + resolution: "babel-plugin-polyfill-corejs3@npm:0.14.2" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.8" + core-js-compat: "npm:^3.48.0" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/32f70442f142d0f5607f4b57c121c573b106e09da8659c0f03108a85bf1d09ba5bdc89595a82b34ff76c19f1faf3d1c831b56166f03babf69c024f36da77c3bf + languageName: node + linkType: hard + +"babel-plugin-polyfill-regenerator@npm:^0.6.5, babel-plugin-polyfill-regenerator@npm:^0.6.6": + version: 0.6.8 + resolution: "babel-plugin-polyfill-regenerator@npm:0.6.8" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.8" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10c0/7c8b2497c29fa880e0acdc8e7b93e29b81b154179b83beb0476eb2c4e7a78b6b42fc35c2554ca250c9bd6d39941eaf75416254b8592ce50979f9a12e1d51c049 + languageName: node + linkType: hard + +"bail@npm:^2.0.0": + version: 2.0.2 + resolution: "bail@npm:2.0.2" + checksum: 10c0/25cbea309ef6a1f56214187004e8f34014eb015713ea01fa5b9b7e9e776ca88d0fdffd64143ac42dc91966c915a4b7b683411b56e14929fad16153fc026ffb8b + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee + languageName: node + linkType: hard + +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b + languageName: node + linkType: hard + +"baseline-browser-mapping@npm:^2.10.12": + version: 2.10.16 + resolution: "baseline-browser-mapping@npm:2.10.16" + bin: + baseline-browser-mapping: dist/cli.cjs + checksum: 10c0/9947243bb8f16db3f8e05397c5c3e7a91243dcf2d1ec6a681ad5ffabeadee36c1061cd18e5f0432088df6798fa0689890ba26db173b9ad23c5650709b7b2e7cf + languageName: node + linkType: hard + +"baseline-browser-mapping@npm:^2.9.0": + version: 2.10.10 + resolution: "baseline-browser-mapping@npm:2.10.10" + bin: + baseline-browser-mapping: dist/cli.cjs + checksum: 10c0/39dee9d955a5e017852f338cb9057feee8d938c82f217d63158f04ccdbbc1c19e80bbed8d15223e3d410ee8b3703829d41fd7eb345e6e44230034ea9adaf8a1d + languageName: node + linkType: hard + +"batch@npm:0.6.1": + version: 0.6.1 + resolution: "batch@npm:0.6.1" + checksum: 10c0/925a13897b4db80d4211082fe287bcf96d297af38e26448c857cee3e095c9792e3b8f26b37d268812e7f38a589f694609de8534a018b1937d7dc9f84e6b387c5 + languageName: node + linkType: hard + +"big.js@npm:^5.2.2": + version: 5.2.2 + resolution: "big.js@npm:5.2.2" + checksum: 10c0/230520f1ff920b2d2ce3e372d77a33faa4fa60d802fe01ca4ffbc321ee06023fe9a741ac02793ee778040a16b7e497f7d60c504d1c402b8fdab6f03bb785a25f + languageName: node + linkType: hard + +"binary-extensions@npm:^2.0.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: 10c0/75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 + languageName: node + linkType: hard + +"body-parser@npm:~1.20.3": + version: 1.20.4 + resolution: "body-parser@npm:1.20.4" + dependencies: + bytes: "npm:~3.1.2" + content-type: "npm:~1.0.5" + debug: "npm:2.6.9" + depd: "npm:2.0.0" + destroy: "npm:~1.2.0" + http-errors: "npm:~2.0.1" + iconv-lite: "npm:~0.4.24" + on-finished: "npm:~2.4.1" + qs: "npm:~6.14.0" + raw-body: "npm:~2.5.3" + type-is: "npm:~1.6.18" + unpipe: "npm:~1.0.0" + checksum: 10c0/569c1e896297d1fcd8f34026c8d0ab70b90d45343c15c5d8dff5de2bad08125fc1e2f8c2f3f4c1ac6c0caaad115218202594d37dcb8d89d9b5dcae1c2b736aa9 + languageName: node + linkType: hard + +"bonjour-service@npm:^1.2.1": + version: 1.3.0 + resolution: "bonjour-service@npm:1.3.0" + dependencies: + fast-deep-equal: "npm:^3.1.3" + multicast-dns: "npm:^7.2.5" + checksum: 10c0/5721fd9f9bb968e9cc16c1e8116d770863dd2329cb1f753231de1515870648c225142b7eefa71f14a5c22bc7b37ddd7fdeb018700f28a8c936d50d4162d433c7 + languageName: node + linkType: hard + +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 10c0/e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf + languageName: node + linkType: hard + +"boxen@npm:^6.2.1": + version: 6.2.1 + resolution: "boxen@npm:6.2.1" + dependencies: + ansi-align: "npm:^3.0.1" + camelcase: "npm:^6.2.0" + chalk: "npm:^4.1.2" + cli-boxes: "npm:^3.0.0" + string-width: "npm:^5.0.1" + type-fest: "npm:^2.5.0" + widest-line: "npm:^4.0.1" + wrap-ansi: "npm:^8.0.1" + checksum: 10c0/2a50d059c950a50d9f3c873093702747740814ce8819225c4f8cbe92024c9f5a9219d2b7128f5cfa17c022644d929bbbc88b9591de67249c6ebe07f7486bdcfd + languageName: node + linkType: hard + +"boxen@npm:^7.0.0": + version: 7.1.1 + resolution: "boxen@npm:7.1.1" + dependencies: + ansi-align: "npm:^3.0.1" + camelcase: "npm:^7.0.1" + chalk: "npm:^5.2.0" + cli-boxes: "npm:^3.0.0" + string-width: "npm:^5.1.2" + type-fest: "npm:^2.13.0" + widest-line: "npm:^4.0.1" + wrap-ansi: "npm:^8.1.0" + checksum: 10c0/3a9891dc98ac40d582c9879e8165628258e2c70420c919e70fff0a53ccc7b42825e73cda6298199b2fbc1f41f5d5b93b492490ad2ae27623bed3897ddb4267f8 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.11 + resolution: "brace-expansion@npm:1.1.11" + dependencies: + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668 + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.2": + version: 5.0.5 + resolution: "brace-expansion@npm:5.0.5" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10c0/4d238e14ed4f5cc9c07285550a41cef23121ca08ba99fa9eb5b55b580dcb6bf868b8210aa10526bdc9f8dc97f33ca2a7259039c4cc131a93042beddb424c48e3 + languageName: node + linkType: hard + +"braces@npm:^3.0.3, braces@npm:~3.0.2": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: "npm:^7.1.1" + checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 + languageName: node + linkType: hard + +"browserslist@npm:^4.0.0, browserslist@npm:^4.23.0, browserslist@npm:^4.24.0, browserslist@npm:^4.28.1": + version: 4.28.1 + resolution: "browserslist@npm:4.28.1" + dependencies: + baseline-browser-mapping: "npm:^2.9.0" + caniuse-lite: "npm:^1.0.30001759" + electron-to-chromium: "npm:^1.5.263" + node-releases: "npm:^2.0.27" + update-browserslist-db: "npm:^1.2.0" + bin: + browserslist: cli.js + checksum: 10c0/545a5fa9d7234e3777a7177ec1e9134bb2ba60a69e6b95683f6982b1473aad347c77c1264ccf2ac5dea609a9731fbfbda6b85782bdca70f80f86e28a402504bd + languageName: node + linkType: hard + +"browserslist@npm:^4.24.2": + version: 4.28.2 + resolution: "browserslist@npm:4.28.2" + dependencies: + baseline-browser-mapping: "npm:^2.10.12" + caniuse-lite: "npm:^1.0.30001782" + electron-to-chromium: "npm:^1.5.328" + node-releases: "npm:^2.0.36" + update-browserslist-db: "npm:^1.2.3" + bin: + browserslist: cli.js + checksum: 10c0/c0228b6330f785b7fa59d2d360124ec6d9322f96ed9f3ee1f873e33ecc9503a6f0ffc3b71191a28c4ff6e930b753b30043da1c33844a9548f3018d491f09ce60 + languageName: node + linkType: hard + +"buffer-from@npm:^1.0.0": + version: 1.1.2 + resolution: "buffer-from@npm:1.1.2" + checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 + languageName: node + linkType: hard + +"bundle-name@npm:^4.1.0": + version: 4.1.0 + resolution: "bundle-name@npm:4.1.0" + dependencies: + run-applescript: "npm:^7.0.0" + checksum: 10c0/8e575981e79c2bcf14d8b1c027a3775c095d362d1382312f444a7c861b0e21513c0bd8db5bd2b16e50ba0709fa622d4eab6b53192d222120305e68359daece29 + languageName: node + linkType: hard + +"busboy@npm:^0.3.1": + version: 0.3.1 + resolution: "busboy@npm:0.3.1" + dependencies: + dicer: "npm:0.3.0" + checksum: 10c0/15b3382816f657302956ba68e48342891b4f36ae1164f1ad47d96302dd2cda634672513d03c7e5dde0dc90e2889becf3fa32f9b3b391d0f8ab4a5a675b5b5581 + languageName: node + linkType: hard + +"bytes@npm:3.0.0": + version: 3.0.0 + resolution: "bytes@npm:3.0.0" + checksum: 10c0/91d42c38601c76460519ffef88371caacaea483a354c8e4b8808e7b027574436a5713337c003ea3de63ee4991c2a9a637884fdfe7f761760d746929d9e8fec60 + languageName: node + linkType: hard + +"bytes@npm:3.1.2, bytes@npm:~3.1.2": + version: 3.1.2 + resolution: "bytes@npm:3.1.2" + checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e + languageName: node + linkType: hard + +"bytestreamjs@npm:^2.0.1": + version: 2.0.1 + resolution: "bytestreamjs@npm:2.0.1" + checksum: 10c0/edd66b7ca3f94aae99a1009304a42d82ca4c2085eb934192ff47a81f59215c975dc9d3cd8f23c40a2f43ef5b2fa6f01ace70b10ad247766cec6ec641b89eab48 + languageName: node + linkType: hard + +"cacache@npm:^20.0.1": + version: 20.0.4 + resolution: "cacache@npm:20.0.4" + dependencies: + "@npmcli/fs": "npm:^5.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^13.0.0" + lru-cache: "npm:^11.1.0" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^13.0.0" + checksum: 10c0/539bf4020e44ba9ca5afc2ec435623ed7e0dd80c020097677e6b4a0545df5cc9d20b473212d01209c8b4aea43c0d095af0bb6da97bcb991642ea6fac0d7c462b + languageName: node + linkType: hard + +"cacheable-lookup@npm:^7.0.0": + version: 7.0.0 + resolution: "cacheable-lookup@npm:7.0.0" + checksum: 10c0/63a9c144c5b45cb5549251e3ea774c04d63063b29e469f7584171d059d3a88f650f47869a974e2d07de62116463d742c287a81a625e791539d987115cb081635 + languageName: node + linkType: hard + +"cacheable-request@npm:^10.2.8": + version: 10.2.14 + resolution: "cacheable-request@npm:10.2.14" + dependencies: + "@types/http-cache-semantics": "npm:^4.0.2" + get-stream: "npm:^6.0.1" + http-cache-semantics: "npm:^4.1.1" + keyv: "npm:^4.5.3" + mimic-response: "npm:^4.0.0" + normalize-url: "npm:^8.0.0" + responselike: "npm:^3.0.0" + checksum: 10c0/41b6658db369f20c03128227ecd219ca7ac52a9d24fc0f499cc9aa5d40c097b48b73553504cebd137024d957c0ddb5b67cf3ac1439b136667f3586257763f88d + languageName: node + linkType: hard + +"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 + languageName: node + linkType: hard + +"call-bind@npm:^1.0.8": + version: 1.0.8 + resolution: "call-bind@npm:1.0.8" + dependencies: + call-bind-apply-helpers: "npm:^1.0.0" + es-define-property: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" + set-function-length: "npm:^1.2.2" + checksum: 10c0/a13819be0681d915144467741b69875ae5f4eba8961eb0bf322aab63ec87f8250eb6d6b0dcbb2e1349876412a56129ca338592b3829ef4343527f5f18a0752d4 + languageName: node + linkType: hard + +"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + get-intrinsic: "npm:^1.3.0" + checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 + languageName: node + linkType: hard + +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 + languageName: node + linkType: hard + +"camel-case@npm:^4.1.2": + version: 4.1.2 + resolution: "camel-case@npm:4.1.2" + dependencies: + pascal-case: "npm:^3.1.2" + tslib: "npm:^2.0.3" + checksum: 10c0/bf9eefaee1f20edbed2e9a442a226793bc72336e2b99e5e48c6b7252b6f70b080fc46d8246ab91939e2af91c36cdd422e0af35161e58dd089590f302f8f64c8a + languageName: node + linkType: hard + +"camelcase@npm:^6.2.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 + languageName: node + linkType: hard + +"camelcase@npm:^7.0.1": + version: 7.0.1 + resolution: "camelcase@npm:7.0.1" + checksum: 10c0/3adfc9a0e96d51b3a2f4efe90a84dad3e206aaa81dfc664f1bd568270e1bf3b010aad31f01db16345b4ffe1910e16ab411c7273a19a859addd1b98ef7cf4cfbd + languageName: node + linkType: hard + +"caniuse-api@npm:^3.0.0": + version: 3.0.0 + resolution: "caniuse-api@npm:3.0.0" + dependencies: + browserslist: "npm:^4.0.0" + caniuse-lite: "npm:^1.0.0" + lodash.memoize: "npm:^4.1.2" + lodash.uniq: "npm:^4.5.0" + checksum: 10c0/60f9e85a3331e6d761b1b03eec71ca38ef7d74146bece34694853033292156b815696573ed734b65583acf493e88163618eda915c6c826d46a024c71a9572b4c + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001759, caniuse-lite@npm:^1.0.30001774": + version: 1.0.30001780 + resolution: "caniuse-lite@npm:1.0.30001780" + checksum: 10c0/8a88f39758a228852d6f3ac92362ecb7694b1b2b022f194d8dfe59123ad40a5de6202bf2dff0fe316bb3d5ca9caf316c22056e0da693459c3be2771cde4f4bf9 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001782": + version: 1.0.30001786 + resolution: "caniuse-lite@npm:1.0.30001786" + checksum: 10c0/9895f0add1991eefb91cfae98e7baa9daffc6b862b0996c983d30e6be90ef679b6aef32dcb6eca312977fb67c2636ee575820f101213e69c1e0dbffd6ee8e09e + languageName: node + linkType: hard + +"ccount@npm:^2.0.0": + version: 2.0.1 + resolution: "ccount@npm:2.0.1" + checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350 + languageName: node + linkType: hard + +"chalk@npm:^4.0.0, chalk@npm:^4.1.2": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 + languageName: node + linkType: hard + +"chalk@npm:^5.0.1, chalk@npm:^5.2.0": + version: 5.4.1 + resolution: "chalk@npm:5.4.1" + checksum: 10c0/b23e88132c702f4855ca6d25cb5538b1114343e41472d5263ee8a37cccfccd9c4216d111e1097c6a27830407a1dc81fecdf2a56f2c63033d4dbbd88c10b0dcef + languageName: node + linkType: hard + +"char-regex@npm:^1.0.2": + version: 1.0.2 + resolution: "char-regex@npm:1.0.2" + checksum: 10c0/57a09a86371331e0be35d9083ba429e86c4f4648ecbe27455dbfb343037c16ee6fdc7f6b61f433a57cc5ded5561d71c56a150e018f40c2ffb7bc93a26dae341e + languageName: node + linkType: hard + +"character-entities-html4@npm:^2.0.0": + version: 2.1.0 + resolution: "character-entities-html4@npm:2.1.0" + checksum: 10c0/fe61b553f083400c20c0b0fd65095df30a0b445d960f3bbf271536ae6c3ba676f39cb7af0b4bf2755812f08ab9b88f2feed68f9aebb73bb153f7a115fe5c6e40 + languageName: node + linkType: hard + +"character-entities-legacy@npm:^3.0.0": + version: 3.0.0 + resolution: "character-entities-legacy@npm:3.0.0" + checksum: 10c0/ec4b430af873661aa754a896a2b55af089b4e938d3d010fad5219299a6b6d32ab175142699ee250640678cd64bdecd6db3c9af0b8759ab7b155d970d84c4c7d1 + languageName: node + linkType: hard + +"character-entities@npm:^2.0.0": + version: 2.0.2 + resolution: "character-entities@npm:2.0.2" + checksum: 10c0/b0c645a45bcc90ff24f0e0140f4875a8436b8ef13b6bcd31ec02cfb2ca502b680362aa95386f7815bdc04b6464d48cf191210b3840d7c04241a149ede591a308 + languageName: node + linkType: hard + +"character-reference-invalid@npm:^2.0.0": + version: 2.0.1 + resolution: "character-reference-invalid@npm:2.0.1" + checksum: 10c0/2ae0dec770cd8659d7e8b0ce24392d83b4c2f0eb4a3395c955dce5528edd4cc030a794cfa06600fcdd700b3f2de2f9b8e40e309c0011c4180e3be64a0b42e6a1 + languageName: node + linkType: hard + +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + dependencies: + boolbase: "npm:^1.0.0" + css-select: "npm:^5.1.0" + css-what: "npm:^6.1.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + checksum: 10c0/2242097e593919dba4aacb97d7b8275def8b9ec70b00aa1f43335456870cfc9e284eae2080bdc832ed232dabb9eefcf56c722d152da4a154813fb8814a55d282 + languageName: node + linkType: hard + +"cheerio@npm:1.0.0-rc.12": + version: 1.0.0-rc.12 + resolution: "cheerio@npm:1.0.0-rc.12" + dependencies: + cheerio-select: "npm:^2.1.0" + dom-serializer: "npm:^2.0.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + htmlparser2: "npm:^8.0.1" + parse5: "npm:^7.0.0" + parse5-htmlparser2-tree-adapter: "npm:^7.0.0" + checksum: 10c0/c85d2f2461e3f024345b78e0bb16ad8e41492356210470dd1e7d5a91391da9fcf6c0a7cb48a9ba8820330153f0cedb4d0a60c7af15d96ecdb3092299b9d9c0cc + languageName: node + linkType: hard + +"chevrotain-allstar@npm:~0.3.1": + version: 0.3.1 + resolution: "chevrotain-allstar@npm:0.3.1" + dependencies: + lodash-es: "npm:^4.17.21" + peerDependencies: + chevrotain: ^11.0.0 + checksum: 10c0/5cadedffd3114eb06b15fd3939bb1aa6c75412dbd737fe302b52c5c24334f9cb01cee8edc1d1067d98ba80dddf971f1d0e94b387de51423fc6cf3c5d8b7ef27a + languageName: node + linkType: hard + +"chevrotain@npm:~11.1.1": + version: 11.1.2 + resolution: "chevrotain@npm:11.1.2" + dependencies: + "@chevrotain/cst-dts-gen": "npm:11.1.2" + "@chevrotain/gast": "npm:11.1.2" + "@chevrotain/regexp-to-ast": "npm:11.1.2" + "@chevrotain/types": "npm:11.1.2" + "@chevrotain/utils": "npm:11.1.2" + lodash-es: "npm:4.17.23" + checksum: 10c0/7f0b5780035c582d4c620c81e1fbb58c9f41a69f1c7efdae96819c7bc0928ddb4f046bb8239e71539f383b3b8ce460bd11f44b5fb5107e1d45a0cc91bd6a4198 + languageName: node + linkType: hard + +"chokidar@npm:^3.5.3, chokidar@npm:^3.6.0": + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" + dependencies: + anymatch: "npm:~3.1.2" + braces: "npm:~3.0.2" + fsevents: "npm:~2.3.2" + glob-parent: "npm:~5.1.2" + is-binary-path: "npm:~2.1.0" + is-glob: "npm:~4.0.1" + normalize-path: "npm:~3.0.0" + readdirp: "npm:~3.6.0" + dependenciesMeta: + fsevents: + optional: true + checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 + languageName: node + linkType: hard + +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + +"chrome-trace-event@npm:^1.0.2": + version: 1.0.4 + resolution: "chrome-trace-event@npm:1.0.4" + checksum: 10c0/3058da7a5f4934b87cf6a90ef5fb68ebc5f7d06f143ed5a4650208e5d7acae47bc03ec844b29fbf5ba7e46e8daa6acecc878f7983a4f4bb7271593da91e61ff5 + languageName: node + linkType: hard + +"ci-info@npm:^3.2.0": + version: 3.9.0 + resolution: "ci-info@npm:3.9.0" + checksum: 10c0/6f0109e36e111684291d46123d491bc4e7b7a1934c3a20dea28cba89f1d4a03acd892f5f6a81ed3855c38647e285a150e3c9ba062e38943bef57fee6c1554c3a + languageName: node + linkType: hard + +"clean-css@npm:^5.2.2, clean-css@npm:^5.3.3, clean-css@npm:~5.3.2": + version: 5.3.3 + resolution: "clean-css@npm:5.3.3" + dependencies: + source-map: "npm:~0.6.0" + checksum: 10c0/381de7523e23f3762eb180e327dcc0cedafaf8cb1cd8c26b7cc1fc56e0829a92e734729c4f955394d65ed72fb62f82d8baf78af34b33b8a7d41ebad2accdd6fb + languageName: node + linkType: hard + +"clean-stack@npm:^2.0.0": + version: 2.2.0 + resolution: "clean-stack@npm:2.2.0" + checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 + languageName: node + linkType: hard + +"cli-boxes@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-boxes@npm:3.0.0" + checksum: 10c0/4db3e8fbfaf1aac4fb3a6cbe5a2d3fa048bee741a45371b906439b9ffc821c6e626b0f108bdcd3ddf126a4a319409aedcf39a0730573ff050fdd7b6731e99fb9 + languageName: node + linkType: hard + +"cli-table3@npm:^0.6.3": + version: 0.6.5 + resolution: "cli-table3@npm:0.6.5" + dependencies: + "@colors/colors": "npm:1.5.0" + string-width: "npm:^4.2.0" + dependenciesMeta: + "@colors/colors": + optional: true + checksum: 10c0/d7cc9ed12212ae68241cc7a3133c52b844113b17856e11f4f81308acc3febcea7cc9fd298e70933e294dd642866b29fd5d113c2c098948701d0c35f09455de78 + languageName: node + linkType: hard + +"clone-deep@npm:^4.0.1": + version: 4.0.1 + resolution: "clone-deep@npm:4.0.1" + dependencies: + is-plain-object: "npm:^2.0.4" + kind-of: "npm:^6.0.2" + shallow-clone: "npm:^3.0.0" + checksum: 10c0/637753615aa24adf0f2d505947a1bb75e63964309034a1cf56ba4b1f30af155201edd38d26ffe26911adaae267a3c138b344a4947d39f5fc1b6d6108125aa758 + languageName: node + linkType: hard + +"clsx@npm:^1.1.1": + version: 1.2.1 + resolution: "clsx@npm:1.2.1" + checksum: 10c0/34dead8bee24f5e96f6e7937d711978380647e936a22e76380290e35486afd8634966ce300fc4b74a32f3762c7d4c0303f442c3e259f4ce02374eb0c82834f27 + languageName: node + linkType: hard + +"clsx@npm:^2.0.0": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 + languageName: node + linkType: hard + +"collapse-white-space@npm:^2.0.0": + version: 2.1.0 + resolution: "collapse-white-space@npm:2.1.0" + checksum: 10c0/b2e2800f4ab261e62eb27a1fbe853378296e3a726d6695117ed033e82d61fb6abeae4ffc1465d5454499e237005de9cfc52c9562dc7ca4ac759b9a222ef14453 + languageName: node + linkType: hard + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 + languageName: node + linkType: hard + +"colord@npm:^2.9.3": + version: 2.9.3 + resolution: "colord@npm:2.9.3" + checksum: 10c0/9699e956894d8996b28c686afe8988720785f476f59335c80ce852ded76ab3ebe252703aec53d9bef54f6219aea6b960fb3d9a8300058a1d0c0d4026460cd110 + languageName: node + linkType: hard + +"colorette@npm:^2.0.10": + version: 2.0.20 + resolution: "colorette@npm:2.0.20" + checksum: 10c0/e94116ff33b0ff56f3b83b9ace895e5bf87c2a7a47b3401b8c3f3226e050d5ef76cf4072fb3325f9dc24d1698f9b730baf4e05eeaf861d74a1883073f4c98a40 + languageName: node + linkType: hard + +"combine-promises@npm:^1.1.0": + version: 1.2.0 + resolution: "combine-promises@npm:1.2.0" + checksum: 10c0/906ebf056006eff93c11548df0415053b6756145dae1f5a89579e743cb15fceeb0604555791321db4fba5072aa39bb4de6547e9cdf14589fe949b33d1613422c + languageName: node + linkType: hard + +"comma-separated-tokens@npm:^2.0.0": + version: 2.0.3 + resolution: "comma-separated-tokens@npm:2.0.3" + checksum: 10c0/91f90f1aae320f1755d6957ef0b864fe4f54737f3313bd95e0802686ee2ca38bff1dd381964d00ae5db42912dd1f4ae5c2709644e82706ffc6f6842a813cdd67 + languageName: node + linkType: hard + +"commander@npm:7, commander@npm:^7.2.0": + version: 7.2.0 + resolution: "commander@npm:7.2.0" + checksum: 10c0/8d690ff13b0356df7e0ebbe6c59b4712f754f4b724d4f473d3cc5b3fdcf978e3a5dc3078717858a2ceb50b0f84d0660a7f22a96cdc50fb877d0c9bb31593d23a + languageName: node + linkType: hard + +"commander@npm:^10.0.0": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 10c0/53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 + languageName: node + linkType: hard + +"commander@npm:^2.20.0": + version: 2.20.3 + resolution: "commander@npm:2.20.3" + checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 + languageName: node + linkType: hard + +"commander@npm:^5.1.0": + version: 5.1.0 + resolution: "commander@npm:5.1.0" + checksum: 10c0/da9d71dbe4ce039faf1fe9eac3771dca8c11d66963341f62602f7b66e36d2a3f8883407af4f9a37b1db1a55c59c0c1325f186425764c2e963dc1d67aec2a4b6d + languageName: node + linkType: hard + +"commander@npm:^8.3.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 10c0/8b043bb8322ea1c39664a1598a95e0495bfe4ca2fad0d84a92d7d1d8d213e2a155b441d2470c8e08de7c4a28cf2bc6e169211c49e1b21d9f7edc6ae4d9356060 + languageName: node + linkType: hard + +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: 10c0/c4a74294e1b1570f4a8ab435285d185a03976c323caa16359053e749db4fde44e3e6586c29cd051100335e11895767cbbd27ea389108e327d62f38daf4548fdb + languageName: node + linkType: hard + +"compressible@npm:~2.0.18": + version: 2.0.18 + resolution: "compressible@npm:2.0.18" + dependencies: + mime-db: "npm:>= 1.43.0 < 2" + checksum: 10c0/8a03712bc9f5b9fe530cc5a79e164e665550d5171a64575d7dcf3e0395d7b4afa2d79ab176c61b5b596e28228b350dd07c1a2a6ead12fd81d1b6cd632af2fef7 + languageName: node + linkType: hard + +"compression@npm:^1.8.1": + version: 1.8.1 + resolution: "compression@npm:1.8.1" + dependencies: + bytes: "npm:3.1.2" + compressible: "npm:~2.0.18" + debug: "npm:2.6.9" + negotiator: "npm:~0.6.4" + on-headers: "npm:~1.1.0" + safe-buffer: "npm:5.2.1" + vary: "npm:~1.1.2" + checksum: 10c0/85114b0b91c16594dc8c671cd9b05ef5e465066a60e5a4ed8b4551661303559a896ed17bb72c4234c04064e078f6ca86a34b8690349499a43f6fc4b844475da4 + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f + languageName: node + linkType: hard + +"confbox@npm:^0.1.8": + version: 0.1.8 + resolution: "confbox@npm:0.1.8" + checksum: 10c0/fc2c68d97cb54d885b10b63e45bd8da83a8a71459d3ecf1825143dd4c7f9f1b696b3283e07d9d12a144c1301c2ebc7842380bdf0014e55acc4ae1c9550102418 + languageName: node + linkType: hard + +"config-chain@npm:^1.1.11": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" + dependencies: + ini: "npm:^1.3.4" + proto-list: "npm:~1.2.1" + checksum: 10c0/39d1df18739d7088736cc75695e98d7087aea43646351b028dfabd5508d79cf6ef4c5bcd90471f52cd87ae470d1c5490c0a8c1a292fbe6ee9ff688061ea0963e + languageName: node + linkType: hard + +"configstore@npm:^6.0.0": + version: 6.0.0 + resolution: "configstore@npm:6.0.0" + dependencies: + dot-prop: "npm:^6.0.1" + graceful-fs: "npm:^4.2.6" + unique-string: "npm:^3.0.0" + write-file-atomic: "npm:^3.0.3" + xdg-basedir: "npm:^5.0.1" + checksum: 10c0/6681a96038ab3e0397cbdf55e6e1624ac3dfa3afe955e219f683df060188a418bda043c9114a59a337e7aec9562b0a0c838ed7db24289e6d0c266bc8313b9580 + languageName: node + linkType: hard + +"connect-history-api-fallback@npm:^2.0.0": + version: 2.0.0 + resolution: "connect-history-api-fallback@npm:2.0.0" + checksum: 10c0/90fa8b16ab76e9531646cc70b010b1dbd078153730c510d3142f6cf07479ae8a812c5a3c0e40a28528dd1681a62395d0cfdef67da9e914c4772ac85d69a3ed87 + languageName: node + linkType: hard + +"consola@npm:^3.2.3": + version: 3.4.2 + resolution: "consola@npm:3.4.2" + checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a + languageName: node + linkType: hard + +"content-disposition@npm:0.5.2": + version: 0.5.2 + resolution: "content-disposition@npm:0.5.2" + checksum: 10c0/49eebaa0da1f9609b192e99d7fec31d1178cb57baa9d01f5b63b29787ac31e9d18b5a1033e854c68c9b6cce790e700a6f7fa60e43f95e2e416404e114a8f2f49 + languageName: node + linkType: hard + +"content-disposition@npm:~0.5.4": + version: 0.5.4 + resolution: "content-disposition@npm:0.5.4" + dependencies: + safe-buffer: "npm:5.2.1" + checksum: 10c0/bac0316ebfeacb8f381b38285dc691c9939bf0a78b0b7c2d5758acadad242d04783cee5337ba7d12a565a19075af1b3c11c728e1e4946de73c6ff7ce45f3f1bb + languageName: node + linkType: hard + +"content-type@npm:~1.0.4, content-type@npm:~1.0.5": + version: 1.0.5 + resolution: "content-type@npm:1.0.5" + checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af + languageName: node + linkType: hard + +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + +"cookie-signature@npm:~1.0.6": + version: 1.0.7 + resolution: "cookie-signature@npm:1.0.7" + checksum: 10c0/e7731ad2995ae2efeed6435ec1e22cdd21afef29d300c27281438b1eab2bae04ef0d1a203928c0afec2cee72aa36540b8747406ebe308ad23c8e8cc3c26c9c51 + languageName: node + linkType: hard + +"cookie@npm:^0.4.1": + version: 0.4.2 + resolution: "cookie@npm:0.4.2" + checksum: 10c0/beab41fbd7c20175e3a2799ba948c1dcc71ef69f23fe14eeeff59fc09f50c517b0f77098db87dbb4c55da802f9d86ee86cdc1cd3efd87760341551838d53fca2 + languageName: node + linkType: hard + +"cookie@npm:~0.7.1": + version: 0.7.2 + resolution: "cookie@npm:0.7.2" + checksum: 10c0/9596e8ccdbf1a3a88ae02cf5ee80c1c50959423e1022e4e60b91dd87c622af1da309253d8abdb258fb5e3eacb4f08e579dc58b4897b8087574eee0fd35dfa5d2 + languageName: node + linkType: hard + +"copy-text-to-clipboard@npm:^3.2.0": + version: 3.2.2 + resolution: "copy-text-to-clipboard@npm:3.2.2" + checksum: 10c0/451796734a380f7da7b0af27c4d94e449719d3a2f2170e99c7e46eeee54cf3c4b4fdeabc185f6d6e8cbdf932e350831d05e8387c4bae8dcedb7fb961c600ddd4 + languageName: node + linkType: hard + +"copy-webpack-plugin@npm:^11.0.0": + version: 11.0.0 + resolution: "copy-webpack-plugin@npm:11.0.0" + dependencies: + fast-glob: "npm:^3.2.11" + glob-parent: "npm:^6.0.1" + globby: "npm:^13.1.1" + normalize-path: "npm:^3.0.0" + schema-utils: "npm:^4.0.0" + serialize-javascript: "npm:^6.0.0" + peerDependencies: + webpack: ^5.1.0 + checksum: 10c0/a667dd226b26f148584a35fb705f5af926d872584912cf9fd203c14f2b3a68f473a1f5cf768ec1dd5da23820823b850e5d50458b685c468e4a224b25c12a15b4 + languageName: node + linkType: hard + +"core-js-compat@npm:^3.43.0, core-js-compat@npm:^3.48.0": + version: 3.49.0 + resolution: "core-js-compat@npm:3.49.0" + dependencies: + browserslist: "npm:^4.28.1" + checksum: 10c0/546e64b7ce45f724825bc13c1347f35c0459a6e71c0dcccff3ec21fbff463f5b0b97fc1220e6d90302153863489301793276fe2bf96f46001ff555ead4140308 + languageName: node + linkType: hard + +"core-js-pure@npm:^3.48.0": + version: 3.49.0 + resolution: "core-js-pure@npm:3.49.0" + checksum: 10c0/b4580a57b917d0bf1029356b1a60abf0f9b99562b67bf39c01485d58891f23603459ed71bde1d7f75c0a9a346829d8c281b255c525fb119726341364c513e82e + languageName: node + linkType: hard + +"core-js@npm:^3.31.1": + version: 3.41.0 + resolution: "core-js@npm:3.41.0" + checksum: 10c0/a29ed0b7fe81acf49d04ce5c17a1947166b1c15197327a5d12f95bbe84b46d60c3c13de701d808f41da06fa316285f3f55ce5903abc8d5642afc1eac4457afc8 + languageName: node + linkType: hard + +"core-util-is@npm:~1.0.0": + version: 1.0.3 + resolution: "core-util-is@npm:1.0.3" + checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 + languageName: node + linkType: hard + +"cose-base@npm:^1.0.0": + version: 1.0.3 + resolution: "cose-base@npm:1.0.3" + dependencies: + layout-base: "npm:^1.0.0" + checksum: 10c0/a6e400b1d101393d6af0967c1353355777c1106c40417c5acaef6ca8bdda41e2fc9398f466d6c85be30290943ad631f2590569f67b3fd5368a0d8318946bd24f + languageName: node + linkType: hard + +"cose-base@npm:^2.2.0": + version: 2.2.0 + resolution: "cose-base@npm:2.2.0" + dependencies: + layout-base: "npm:^2.0.0" + checksum: 10c0/14b9f8100ac322a00777ffb1daeb3321af368bbc9cabe3103943361273baee2003202ffe38e4ab770960b600214224e9c196195a78d589521540aa694df7cdec + languageName: node + linkType: hard + +"cosmiconfig@npm:^8.1.3, cosmiconfig@npm:^8.3.5": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a + languageName: node + linkType: hard + +"cron-schedule@npm:^3.0.4": + version: 3.0.6 + resolution: "cron-schedule@npm:3.0.6" + checksum: 10c0/e41963db8f2673f1e791c64eb16f5d78bf51079324ed890ce4a26b36ca7383568e3f32153c15f73e1aafa758de13cc35541655a22beb2baf0e0e5076acea55f5 + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.3": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 + languageName: node + linkType: hard + +"crypto-random-string@npm:^4.0.0": + version: 4.0.0 + resolution: "crypto-random-string@npm:4.0.0" + dependencies: + type-fest: "npm:^1.0.1" + checksum: 10c0/16e11a3c8140398f5408b7fded35a961b9423c5dac39a60cbbd08bd3f0e07d7de130e87262adea7db03ec1a7a4b7551054e0db07ee5408b012bac5400cfc07a5 + languageName: node + linkType: hard + +"css-blank-pseudo@npm:^7.0.1": + version: 7.0.1 + resolution: "css-blank-pseudo@npm:7.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/46c3d3a611972fdb0c264db7c0b34fe437bc4300961d11945145cf04962f52a545a6ef55bc8ff4afd82b605bd692b4970f2b54582616dea00441105e725d4618 + languageName: node + linkType: hard + +"css-declaration-sorter@npm:^7.2.0": + version: 7.3.1 + resolution: "css-declaration-sorter@npm:7.3.1" + peerDependencies: + postcss: ^8.0.9 + checksum: 10c0/8348ec76157e4b370ce4383a80e23fde28dde53901572ae5bcb5cd02cfc2ba0a76a7b5433c361524ed4cea713023802abc7b56e2304aad0721e449011fa83b37 + languageName: node + linkType: hard + +"css-has-pseudo@npm:^7.0.3": + version: 7.0.3 + resolution: "css-has-pseudo@npm:7.0.3" + dependencies: + "@csstools/selector-specificity": "npm:^5.0.0" + postcss-selector-parser: "npm:^7.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/c89f68e17bed229e9a3e98da5032e1360c83d45d974bc3fb8d6b5358399bca80cce7929e4a621a516a75536edb78678dc486eb41841eeed28cca79e3be4bdc27 + languageName: node + linkType: hard + +"css-loader@npm:^6.11.0": + version: 6.11.0 + resolution: "css-loader@npm:6.11.0" + dependencies: + icss-utils: "npm:^5.1.0" + postcss: "npm:^8.4.33" + postcss-modules-extract-imports: "npm:^3.1.0" + postcss-modules-local-by-default: "npm:^4.0.5" + postcss-modules-scope: "npm:^3.2.0" + postcss-modules-values: "npm:^4.0.0" + postcss-value-parser: "npm:^4.2.0" + semver: "npm:^7.5.4" + peerDependencies: + "@rspack/core": 0.x || 1.x + webpack: ^5.0.0 + peerDependenciesMeta: + "@rspack/core": + optional: true + webpack: + optional: true + checksum: 10c0/bb52434138085fed06a33e2ffbdae9ee9014ad23bf60f59d6b7ee67f28f26c6b1764024d3030bd19fd884d6ee6ee2224eaed64ad19eb18fbbb23d148d353a965 + languageName: node + linkType: hard + +"css-minimizer-webpack-plugin@npm:^5.0.1": + version: 5.0.1 + resolution: "css-minimizer-webpack-plugin@npm:5.0.1" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.18" + cssnano: "npm:^6.0.1" + jest-worker: "npm:^29.4.3" + postcss: "npm:^8.4.24" + schema-utils: "npm:^4.0.1" + serialize-javascript: "npm:^6.0.1" + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + "@parcel/css": + optional: true + "@swc/css": + optional: true + clean-css: + optional: true + csso: + optional: true + esbuild: + optional: true + lightningcss: + optional: true + checksum: 10c0/1792259e18f7c5ee25b6bbf60b38b64201747add83d1f751c8c654159b46ebacd0d1103d35f17d97197033e21e02d2ba4a4e9aa14c9c0d067b7c7653c721814e + languageName: node + linkType: hard + +"css-prefers-color-scheme@npm:^10.0.0": + version: 10.0.0 + resolution: "css-prefers-color-scheme@npm:10.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/a66c727bb2455328b18862f720819fc98ff5c1486b69f758bdb5c66f46cc6d484f9fc0bfa4f00f2693c5da6707ad136ca789496982f713ade693f08af624930e + languageName: node + linkType: hard + +"css-select@npm:^4.1.3": + version: 4.3.0 + resolution: "css-select@npm:4.3.0" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.0.1" + domhandler: "npm:^4.3.1" + domutils: "npm:^2.8.0" + nth-check: "npm:^2.0.1" + checksum: 10c0/a489d8e5628e61063d5a8fe0fa1cc7ae2478cb334a388a354e91cf2908154be97eac9fa7ed4dffe87a3e06cf6fcaa6016553115335c4fd3377e13dac7bd5a8e1 + languageName: node + linkType: hard + +"css-select@npm:^5.1.0": + version: 5.2.2 + resolution: "css-select@npm:5.2.2" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.1.0" + domhandler: "npm:^5.0.2" + domutils: "npm:^3.0.1" + nth-check: "npm:^2.0.1" + checksum: 10c0/d79fffa97106007f2802589f3ed17b8c903f1c961c0fc28aa8a051eee0cbad394d8446223862efd4c1b40445a6034f626bb639cf2035b0bfc468544177593c99 + languageName: node + linkType: hard + +"css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" + dependencies: + mdn-data: "npm:2.0.30" + source-map-js: "npm:^1.0.1" + checksum: 10c0/6f8c1a11d5e9b14bf02d10717fc0351b66ba12594166f65abfbd8eb8b5b490dd367f5c7721db241a3c792d935fc6751fbc09f7e1598d421477ad9fadc30f4f24 + languageName: node + linkType: hard + +"css-tree@npm:~2.2.0": + version: 2.2.1 + resolution: "css-tree@npm:2.2.1" + dependencies: + mdn-data: "npm:2.0.28" + source-map-js: "npm:^1.0.1" + checksum: 10c0/47e87b0f02f8ac22f57eceb65c58011dd142d2158128882a0bf963cf2eabb81a4ebbc2e3790c8289be7919fa8b83750c7b69272bd66772c708143b772ba3c186 + languageName: node + linkType: hard + +"css-what@npm:^6.0.1, css-what@npm:^6.1.0": + version: 6.1.0 + resolution: "css-what@npm:6.1.0" + checksum: 10c0/a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746 + languageName: node + linkType: hard + +"cssdb@npm:^8.6.0": + version: 8.8.0 + resolution: "cssdb@npm:8.8.0" + checksum: 10c0/cee2e249935df02d37f0d6212c9f4aa7d46de6fb331b4f6090507a7eaa4d7b7f431c5e522146ff7e944e79f0d592d370f2e0bd6a001744cea0d55da533f0a84f + languageName: node + linkType: hard + +"cssesc@npm:^3.0.0": + version: 3.0.0 + resolution: "cssesc@npm:3.0.0" + bin: + cssesc: bin/cssesc + checksum: 10c0/6bcfd898662671be15ae7827120472c5667afb3d7429f1f917737f3bf84c4176003228131b643ae74543f17a394446247df090c597bb9a728cce298606ed0aa7 + languageName: node + linkType: hard + +"cssnano-preset-advanced@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano-preset-advanced@npm:6.1.2" + dependencies: + autoprefixer: "npm:^10.4.19" + browserslist: "npm:^4.23.0" + cssnano-preset-default: "npm:^6.1.2" + postcss-discard-unused: "npm:^6.0.5" + postcss-merge-idents: "npm:^6.0.3" + postcss-reduce-idents: "npm:^6.0.3" + postcss-zindex: "npm:^6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/22d3ddab258e6b31e7e2e7c48712f023b60fadb2813929752dace0326e28cd250830b5420a33f81b01df52d2460cb5f999fff5907f58508809efe1a8a739a707 + languageName: node + linkType: hard + +"cssnano-preset-default@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano-preset-default@npm:6.1.2" + dependencies: + browserslist: "npm:^4.23.0" + css-declaration-sorter: "npm:^7.2.0" + cssnano-utils: "npm:^4.0.2" + postcss-calc: "npm:^9.0.1" + postcss-colormin: "npm:^6.1.0" + postcss-convert-values: "npm:^6.1.0" + postcss-discard-comments: "npm:^6.0.2" + postcss-discard-duplicates: "npm:^6.0.3" + postcss-discard-empty: "npm:^6.0.3" + postcss-discard-overridden: "npm:^6.0.2" + postcss-merge-longhand: "npm:^6.0.5" + postcss-merge-rules: "npm:^6.1.1" + postcss-minify-font-values: "npm:^6.1.0" + postcss-minify-gradients: "npm:^6.0.3" + postcss-minify-params: "npm:^6.1.0" + postcss-minify-selectors: "npm:^6.0.4" + postcss-normalize-charset: "npm:^6.0.2" + postcss-normalize-display-values: "npm:^6.0.2" + postcss-normalize-positions: "npm:^6.0.2" + postcss-normalize-repeat-style: "npm:^6.0.2" + postcss-normalize-string: "npm:^6.0.2" + postcss-normalize-timing-functions: "npm:^6.0.2" + postcss-normalize-unicode: "npm:^6.1.0" + postcss-normalize-url: "npm:^6.0.2" + postcss-normalize-whitespace: "npm:^6.0.2" + postcss-ordered-values: "npm:^6.0.2" + postcss-reduce-initial: "npm:^6.1.0" + postcss-reduce-transforms: "npm:^6.0.2" + postcss-svgo: "npm:^6.0.3" + postcss-unique-selectors: "npm:^6.0.4" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/af99021f936763850f5f35dc9e6a9dfb0da30856dea36e0420b011da2a447099471db2a5f3d1f5f52c0489da186caf9a439d8f048a80f82617077efb018333fa + languageName: node + linkType: hard + +"cssnano-utils@npm:^4.0.2": + version: 4.0.2 + resolution: "cssnano-utils@npm:4.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/260b8c8ffa48b908aa77ef129f9b8648ecd92aed405b20e7fe6b8370779dd603530344fc9d96683d53533246e48b36ac9d2aa5a476b4f81c547bbad86d187f35 + languageName: node + linkType: hard + +"cssnano@npm:^6.0.1, cssnano@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano@npm:6.1.2" + dependencies: + cssnano-preset-default: "npm:^6.1.2" + lilconfig: "npm:^3.1.1" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/4df0dc0389b34b38acb09b7cfb07267b0eda95349c6d5e9b7666acc7200bb33359650869a60168e9d878298b05f4ad2c7f070815c90551720a3f4e1037f79691 + languageName: node + linkType: hard + +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" + dependencies: + css-tree: "npm:~2.2.0" + checksum: 10c0/ab4beb1e97dd7e207c10e9925405b45f15a6cd1b4880a8686ad573aa6d476aed28b4121a666cffd26c37a26179f7b54741f7c257543003bfb244d06a62ad569b + languageName: node + linkType: hard + +"csstype@npm:^3.0.2": + version: 3.1.3 + resolution: "csstype@npm:3.1.3" + checksum: 10c0/80c089d6f7e0c5b2bd83cf0539ab41474198579584fa10d86d0cafe0642202343cbc119e076a0b1aece191989477081415d66c9fefbf3c957fc2fc4b7009f248 + languageName: node + linkType: hard + +"cytoscape-cose-bilkent@npm:^4.1.0": + version: 4.1.0 + resolution: "cytoscape-cose-bilkent@npm:4.1.0" + dependencies: + cose-base: "npm:^1.0.0" + peerDependencies: + cytoscape: ^3.2.0 + checksum: 10c0/5e2480ddba9da1a68e700ed2c674cbfd51e9efdbd55788f1971a68de4eb30708e3b3a5e808bf5628f7a258680406bbe6586d87a9133e02a9bdc1ab1a92f512f2 + languageName: node + linkType: hard + +"cytoscape-fcose@npm:^2.2.0": + version: 2.2.0 + resolution: "cytoscape-fcose@npm:2.2.0" + dependencies: + cose-base: "npm:^2.2.0" + peerDependencies: + cytoscape: ^3.2.0 + checksum: 10c0/ce472c9f85b9057e75c5685396f8e1f2468895e71b184913e05ad56dcf3092618fe59a1054f29cb0995051ba8ebe566ad0dd49a58d62845145624bd60cd44917 + languageName: node + linkType: hard + +"cytoscape@npm:^3.33.1": + version: 3.33.1 + resolution: "cytoscape@npm:3.33.1" + checksum: 10c0/dffcf5f74df4d91517c4faf394df880d8283ce76edef19edba0c762941cf4f18daf7c4c955ec50c794f476ace39ad4394f8c98483222bd2682e1fd206e976411 + languageName: node + linkType: hard + +"d3-array@npm:1 - 2": + version: 2.12.1 + resolution: "d3-array@npm:2.12.1" + dependencies: + internmap: "npm:^1.0.0" + checksum: 10c0/7eca10427a9f113a4ca6a0f7301127cab26043fd5e362631ef5a0edd1c4b2dd70c56ed317566700c31e4a6d88b55f3951aaba192291817f243b730cb2352882e + languageName: node + linkType: hard + +"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:2.5.0 - 3, d3-array@npm:3, d3-array@npm:^3.2.0": + version: 3.2.4 + resolution: "d3-array@npm:3.2.4" + dependencies: + internmap: "npm:1 - 2" + checksum: 10c0/08b95e91130f98c1375db0e0af718f4371ccacef7d5d257727fe74f79a24383e79aba280b9ffae655483ffbbad4fd1dec4ade0119d88c4749f388641c8bf8c50 + languageName: node + linkType: hard + +"d3-axis@npm:3": + version: 3.0.0 + resolution: "d3-axis@npm:3.0.0" + checksum: 10c0/a271e70ba1966daa5aaf6a7f959ceca3e12997b43297e757c7b945db2e1ead3c6ee226f2abcfa22abbd4e2e28bd2b71a0911794c4e5b911bbba271328a582c78 + languageName: node + linkType: hard + +"d3-brush@npm:3": + version: 3.0.0 + resolution: "d3-brush@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-drag: "npm:2 - 3" + d3-interpolate: "npm:1 - 3" + d3-selection: "npm:3" + d3-transition: "npm:3" + checksum: 10c0/07baf00334c576da2f68a91fc0da5732c3a5fa19bd3d7aed7fd24d1d674a773f71a93e9687c154176f7246946194d77c48c2d8fed757f5dcb1a4740067ec50a8 + languageName: node + linkType: hard + +"d3-chord@npm:3": + version: 3.0.1 + resolution: "d3-chord@npm:3.0.1" + dependencies: + d3-path: "npm:1 - 3" + checksum: 10c0/baa6013914af3f4fe1521f0d16de31a38eb8a71d08ff1dec4741f6f45a828661e5cd3935e39bd14e3032bdc78206c283ca37411da21d46ec3cfc520be6e7a7ce + languageName: node + linkType: hard + +"d3-color@npm:1 - 3, d3-color@npm:3": + version: 3.1.0 + resolution: "d3-color@npm:3.1.0" + checksum: 10c0/a4e20e1115fa696fce041fbe13fbc80dc4c19150fa72027a7c128ade980bc0eeeba4bcf28c9e21f0bce0e0dbfe7ca5869ef67746541dcfda053e4802ad19783c + languageName: node + linkType: hard + +"d3-contour@npm:4": + version: 4.0.2 + resolution: "d3-contour@npm:4.0.2" + dependencies: + d3-array: "npm:^3.2.0" + checksum: 10c0/98bc5fbed6009e08707434a952076f39f1cd6ed8b9288253cc3e6a3286e4e80c63c62d84954b20e64bf6e4ededcc69add54d3db25e990784a59c04edd3449032 + languageName: node + linkType: hard + +"d3-delaunay@npm:6": + version: 6.0.4 + resolution: "d3-delaunay@npm:6.0.4" + dependencies: + delaunator: "npm:5" + checksum: 10c0/57c3aecd2525664b07c4c292aa11cf49b2752c0cf3f5257f752999399fe3c592de2d418644d79df1f255471eec8057a9cc0c3062ed7128cb3348c45f69597754 + languageName: node + linkType: hard + +"d3-dispatch@npm:1 - 3, d3-dispatch@npm:3": + version: 3.0.1 + resolution: "d3-dispatch@npm:3.0.1" + checksum: 10c0/6eca77008ce2dc33380e45d4410c67d150941df7ab45b91d116dbe6d0a3092c0f6ac184dd4602c796dc9e790222bad3ff7142025f5fd22694efe088d1d941753 + languageName: node + linkType: hard + +"d3-drag@npm:2 - 3, d3-drag@npm:3": + version: 3.0.0 + resolution: "d3-drag@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-selection: "npm:3" + checksum: 10c0/d2556e8dc720741a443b595a30af403dd60642dfd938d44d6e9bfc4c71a962142f9a028c56b61f8b4790b65a34acad177d1263d66f103c3c527767b0926ef5aa + languageName: node + linkType: hard + +"d3-dsv@npm:1 - 3, d3-dsv@npm:3": + version: 3.0.1 + resolution: "d3-dsv@npm:3.0.1" + dependencies: + commander: "npm:7" + iconv-lite: "npm:0.6" + rw: "npm:1" + bin: + csv2json: bin/dsv2json.js + csv2tsv: bin/dsv2dsv.js + dsv2dsv: bin/dsv2dsv.js + dsv2json: bin/dsv2json.js + json2csv: bin/json2dsv.js + json2dsv: bin/json2dsv.js + json2tsv: bin/json2dsv.js + tsv2csv: bin/dsv2dsv.js + tsv2json: bin/dsv2json.js + checksum: 10c0/10e6af9e331950ed258f34ab49ac1b7060128ef81dcf32afc790bd1f7e8c3cc2aac7f5f875250a83f21f39bb5925fbd0872bb209f8aca32b3b77d32bab8a65ab + languageName: node + linkType: hard + +"d3-ease@npm:1 - 3, d3-ease@npm:3": + version: 3.0.1 + resolution: "d3-ease@npm:3.0.1" + checksum: 10c0/fec8ef826c0cc35cda3092c6841e07672868b1839fcaf556e19266a3a37e6bc7977d8298c0fcb9885e7799bfdcef7db1baaba9cd4dcf4bc5e952cf78574a88b0 + languageName: node + linkType: hard + +"d3-fetch@npm:3": + version: 3.0.1 + resolution: "d3-fetch@npm:3.0.1" + dependencies: + d3-dsv: "npm:1 - 3" + checksum: 10c0/4f467a79bf290395ac0cbb5f7562483f6a18668adc4c8eb84c9d3eff048b6f6d3b6f55079ba1ebf1908dabe000c941d46be447f8d78453b2dad5fb59fb6aa93b + languageName: node + linkType: hard + +"d3-force@npm:3": + version: 3.0.0 + resolution: "d3-force@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-quadtree: "npm:1 - 3" + d3-timer: "npm:1 - 3" + checksum: 10c0/220a16a1a1ac62ba56df61028896e4b52be89c81040d20229c876efc8852191482c233f8a52bb5a4e0875c321b8e5cb6413ef3dfa4d8fe79eeb7d52c587f52cf + languageName: node + linkType: hard + +"d3-format@npm:1 - 3, d3-format@npm:3": + version: 3.1.2 + resolution: "d3-format@npm:3.1.2" + checksum: 10c0/0de452ae07585238e7f01607a7e0066665c34609652188b6ac7dc9f424f69465a425e07d16d79bd0e5955202ac7f241c66d0c76f68a79fc6f4857c94cf420652 + languageName: node + linkType: hard + +"d3-geo@npm:3": + version: 3.1.1 + resolution: "d3-geo@npm:3.1.1" + dependencies: + d3-array: "npm:2.5.0 - 3" + checksum: 10c0/d32270dd2dc8ac3ea63e8805d63239c4c8ec6c0d339d73b5e5a30a87f8f54db22a78fb434369799465eae169503b25f9a107c642c8a16c32a3285bc0e6d8e8c1 + languageName: node + linkType: hard + +"d3-hierarchy@npm:3": + version: 3.1.2 + resolution: "d3-hierarchy@npm:3.1.2" + checksum: 10c0/6dcdb480539644aa7fc0d72dfc7b03f99dfbcdf02714044e8c708577e0d5981deb9d3e99bbbb2d26422b55bcc342ac89a0fa2ea6c9d7302e2fc0951dd96f89cf + languageName: node + linkType: hard + +"d3-interpolate@npm:1 - 3, d3-interpolate@npm:1.2.0 - 3, d3-interpolate@npm:3": + version: 3.0.1 + resolution: "d3-interpolate@npm:3.0.1" + dependencies: + d3-color: "npm:1 - 3" + checksum: 10c0/19f4b4daa8d733906671afff7767c19488f51a43d251f8b7f484d5d3cfc36c663f0a66c38fe91eee30f40327443d799be17169f55a293a3ba949e84e57a33e6a + languageName: node + linkType: hard + +"d3-path@npm:1": + version: 1.0.9 + resolution: "d3-path@npm:1.0.9" + checksum: 10c0/e35e84df5abc18091f585725b8235e1fa97efc287571585427d3a3597301e6c506dea56b11dfb3c06ca5858b3eb7f02c1bf4f6a716aa9eade01c41b92d497eb5 + languageName: node + linkType: hard + +"d3-path@npm:1 - 3, d3-path@npm:3, d3-path@npm:^3.1.0": + version: 3.1.0 + resolution: "d3-path@npm:3.1.0" + checksum: 10c0/dc1d58ec87fa8319bd240cf7689995111a124b141428354e9637aa83059eb12e681f77187e0ada5dedfce346f7e3d1f903467ceb41b379bfd01cd8e31721f5da + languageName: node + linkType: hard + +"d3-polygon@npm:3": + version: 3.0.1 + resolution: "d3-polygon@npm:3.0.1" + checksum: 10c0/e236aa7f33efa9a4072907af7dc119f85b150a0716759d4fe5f12f62573018264a6cbde8617fbfa6944a7ae48c1c0c8d3f39ae72e11f66dd471e9b5e668385df + languageName: node + linkType: hard + +"d3-quadtree@npm:1 - 3, d3-quadtree@npm:3": + version: 3.0.1 + resolution: "d3-quadtree@npm:3.0.1" + checksum: 10c0/18302d2548bfecaef788152397edec95a76400fd97d9d7f42a089ceb68d910f685c96579d74e3712d57477ed042b056881b47cd836a521de683c66f47ce89090 + languageName: node + linkType: hard + +"d3-random@npm:3": + version: 3.0.1 + resolution: "d3-random@npm:3.0.1" + checksum: 10c0/987a1a1bcbf26e6cf01fd89d5a265b463b2cea93560fc17d9b1c45e8ed6ff2db5924601bcceb808de24c94133f000039eb7fa1c469a7a844ccbf1170cbb25b41 + languageName: node + linkType: hard + +"d3-sankey@npm:^0.12.3": + version: 0.12.3 + resolution: "d3-sankey@npm:0.12.3" + dependencies: + d3-array: "npm:1 - 2" + d3-shape: "npm:^1.2.0" + checksum: 10c0/261debb01a13269f6fc53b9ebaef174a015d5ad646242c23995bf514498829ab8b8f920a7873724a7494288b46bea3ce7ebc5a920b745bc8ae4caa5885cf5204 + languageName: node + linkType: hard + +"d3-scale-chromatic@npm:3": + version: 3.1.0 + resolution: "d3-scale-chromatic@npm:3.1.0" + dependencies: + d3-color: "npm:1 - 3" + d3-interpolate: "npm:1 - 3" + checksum: 10c0/9a3f4671ab0b971f4a411b42180d7cf92bfe8e8584e637ce7e698d705e18d6d38efbd20ec64f60cc0dfe966c20d40fc172565bc28aaa2990c0a006360eed91af + languageName: node + linkType: hard + +"d3-scale@npm:4": + version: 4.0.2 + resolution: "d3-scale@npm:4.0.2" + dependencies: + d3-array: "npm:2.10.0 - 3" + d3-format: "npm:1 - 3" + d3-interpolate: "npm:1.2.0 - 3" + d3-time: "npm:2.1.1 - 3" + d3-time-format: "npm:2 - 4" + checksum: 10c0/65d9ad8c2641aec30ed5673a7410feb187a224d6ca8d1a520d68a7d6eac9d04caedbff4713d1e8545be33eb7fec5739983a7ab1d22d4e5ad35368c6729d362f1 + languageName: node + linkType: hard + +"d3-selection@npm:2 - 3, d3-selection@npm:3, d3-selection@npm:^3.0.0": + version: 3.0.0 + resolution: "d3-selection@npm:3.0.0" + checksum: 10c0/e59096bbe8f0cb0daa1001d9bdd6dbc93a688019abc97d1d8b37f85cd3c286a6875b22adea0931b0c88410d025563e1643019161a883c516acf50c190a11b56b + languageName: node + linkType: hard + +"d3-shape@npm:3": + version: 3.2.0 + resolution: "d3-shape@npm:3.2.0" + dependencies: + d3-path: "npm:^3.1.0" + checksum: 10c0/f1c9d1f09926daaf6f6193ae3b4c4b5521e81da7d8902d24b38694517c7f527ce3c9a77a9d3a5722ad1e3ff355860b014557b450023d66a944eabf8cfde37132 + languageName: node + linkType: hard + +"d3-shape@npm:^1.2.0": + version: 1.3.7 + resolution: "d3-shape@npm:1.3.7" + dependencies: + d3-path: "npm:1" + checksum: 10c0/548057ce59959815decb449f15632b08e2a1bdce208f9a37b5f98ec7629dda986c2356bc7582308405ce68aedae7d47b324df41507404df42afaf352907577ae + languageName: node + linkType: hard + +"d3-time-format@npm:2 - 4, d3-time-format@npm:4": + version: 4.1.0 + resolution: "d3-time-format@npm:4.1.0" + dependencies: + d3-time: "npm:1 - 3" + checksum: 10c0/735e00fb25a7fd5d418fac350018713ae394eefddb0d745fab12bbff0517f9cdb5f807c7bbe87bb6eeb06249662f8ea84fec075f7d0cd68609735b2ceb29d206 + languageName: node + linkType: hard + +"d3-time@npm:1 - 3, d3-time@npm:2.1.1 - 3, d3-time@npm:3": + version: 3.1.0 + resolution: "d3-time@npm:3.1.0" + dependencies: + d3-array: "npm:2 - 3" + checksum: 10c0/a984f77e1aaeaa182679b46fbf57eceb6ebdb5f67d7578d6f68ef933f8eeb63737c0949991618a8d29472dbf43736c7d7f17c452b2770f8c1271191cba724ca1 + languageName: node + linkType: hard + +"d3-timer@npm:1 - 3, d3-timer@npm:3": + version: 3.0.1 + resolution: "d3-timer@npm:3.0.1" + checksum: 10c0/d4c63cb4bb5461d7038aac561b097cd1c5673969b27cbdd0e87fa48d9300a538b9e6f39b4a7f0e3592ef4f963d858c8a9f0e92754db73116770856f2fc04561a + languageName: node + linkType: hard + +"d3-transition@npm:2 - 3, d3-transition@npm:3, d3-transition@npm:^3.0.1": + version: 3.0.1 + resolution: "d3-transition@npm:3.0.1" + dependencies: + d3-color: "npm:1 - 3" + d3-dispatch: "npm:1 - 3" + d3-ease: "npm:1 - 3" + d3-interpolate: "npm:1 - 3" + d3-timer: "npm:1 - 3" + peerDependencies: + d3-selection: 2 - 3 + checksum: 10c0/4e74535dda7024aa43e141635b7522bb70cf9d3dfefed975eb643b36b864762eca67f88fafc2ca798174f83ca7c8a65e892624f824b3f65b8145c6a1a88dbbad + languageName: node + linkType: hard + +"d3-zoom@npm:3": + version: 3.0.0 + resolution: "d3-zoom@npm:3.0.0" + dependencies: + d3-dispatch: "npm:1 - 3" + d3-drag: "npm:2 - 3" + d3-interpolate: "npm:1 - 3" + d3-selection: "npm:2 - 3" + d3-transition: "npm:2 - 3" + checksum: 10c0/ee2036479049e70d8c783d594c444fe00e398246048e3f11a59755cd0e21de62ece3126181b0d7a31bf37bcf32fd726f83ae7dea4495ff86ec7736ce5ad36fd3 + languageName: node + linkType: hard + +"d3@npm:^7.9.0": + version: 7.9.0 + resolution: "d3@npm:7.9.0" + dependencies: + d3-array: "npm:3" + d3-axis: "npm:3" + d3-brush: "npm:3" + d3-chord: "npm:3" + d3-color: "npm:3" + d3-contour: "npm:4" + d3-delaunay: "npm:6" + d3-dispatch: "npm:3" + d3-drag: "npm:3" + d3-dsv: "npm:3" + d3-ease: "npm:3" + d3-fetch: "npm:3" + d3-force: "npm:3" + d3-format: "npm:3" + d3-geo: "npm:3" + d3-hierarchy: "npm:3" + d3-interpolate: "npm:3" + d3-path: "npm:3" + d3-polygon: "npm:3" + d3-quadtree: "npm:3" + d3-random: "npm:3" + d3-scale: "npm:4" + d3-scale-chromatic: "npm:3" + d3-selection: "npm:3" + d3-shape: "npm:3" + d3-time: "npm:3" + d3-time-format: "npm:4" + d3-timer: "npm:3" + d3-transition: "npm:3" + d3-zoom: "npm:3" + checksum: 10c0/3dd9c08c73cfaa69c70c49e603c85e049c3904664d9c79a1a52a0f52795828a1ff23592dc9a7b2257e711d68a615472a13103c212032f38e016d609796e087e8 + languageName: node + linkType: hard + +"dagre-d3-es@npm:7.0.14": + version: 7.0.14 + resolution: "dagre-d3-es@npm:7.0.14" + dependencies: + d3: "npm:^7.9.0" + lodash-es: "npm:^4.17.21" + checksum: 10c0/0dc91fc79300eb0a4eab5a48a76c2baf3ce439c389d19e2f015729bb57dafd75e1e9a4c2880daf016e81ee45caca7b21745c13b23b6cd2a786ce84767e88323e + languageName: node + linkType: hard + +"dayjs@npm:^1.11.19": + version: 1.11.20 + resolution: "dayjs@npm:1.11.20" + checksum: 10c0/8af525e2aa100c8db9923d706c42b2b2d30579faf89456619413a5c10916efc92c2b166e193c27c02eb3174b30aa440ee1e7b72b0a2876b3da651d204db848a0 + languageName: node + linkType: hard + +"debounce@npm:^1.2.1": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 10c0/6c9320aa0973fc42050814621a7a8a78146c1975799b5b3cc1becf1f77ba9a5aa583987884230da0842a03f385def452fad5d60db97c3d1c8b824e38a8edf500 + languageName: node + linkType: hard + +"debug@npm:2.6.9": + version: 2.6.9 + resolution: "debug@npm:2.6.9" + dependencies: + ms: "npm:2.0.0" + checksum: 10c0/121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.4, debug@npm:^4.4.3": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 + languageName: node + linkType: hard + +"decode-named-character-reference@npm:^1.0.0": + version: 1.1.0 + resolution: "decode-named-character-reference@npm:1.1.0" + dependencies: + character-entities: "npm:^2.0.0" + checksum: 10c0/359c76305b47e67660ec096c5cd3f65972ed75b8a53a40435a7a967cfab3e9516e64b443cbe0c7edcf5ab77f65a6924f12fb1872b1e09e2f044f28f4fd10996a + languageName: node + linkType: hard + +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e + languageName: node + linkType: hard + +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + languageName: node + linkType: hard + +"deepmerge@npm:^4.3.1": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044 + languageName: node + linkType: hard + +"default-browser-id@npm:^5.0.0": + version: 5.0.1 + resolution: "default-browser-id@npm:5.0.1" + checksum: 10c0/5288b3094c740ef3a86df9b999b04ff5ba4dee6b64e7b355c0fff5217752c8c86908d67f32f6cba9bb4f9b7b61a1b640c0a4f9e34c57e0ff3493559a625245ee + languageName: node + linkType: hard + +"default-browser@npm:^5.2.1": + version: 5.5.0 + resolution: "default-browser@npm:5.5.0" + dependencies: + bundle-name: "npm:^4.1.0" + default-browser-id: "npm:^5.0.0" + checksum: 10c0/576593b617b17a7223014b4571bfe1c06a2581a4eb8b130985d90d253afa3f40999caec70eb0e5776e80d4af6a41cce91018cd3f86e57ad578bf59e46fb19abe + languageName: node + linkType: hard + +"defer-to-connect@npm:^2.0.1": + version: 2.0.1 + resolution: "defer-to-connect@npm:2.0.1" + checksum: 10c0/625ce28e1b5ad10cf77057b9a6a727bf84780c17660f6644dab61dd34c23de3001f03cedc401f7d30a4ed9965c2e8a7336e220a329146f2cf85d4eddea429782 + languageName: node + linkType: hard + +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.0.1" + checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 + languageName: node + linkType: hard + +"define-lazy-prop@npm:^2.0.0": + version: 2.0.0 + resolution: "define-lazy-prop@npm:2.0.0" + checksum: 10c0/db6c63864a9d3b7dc9def55d52764968a5af296de87c1b2cc71d8be8142e445208071953649e0386a8cc37cfcf9a2067a47207f1eb9ff250c2a269658fdae422 + languageName: node + linkType: hard + +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 10c0/5ab0b2bf3fa58b3a443140bbd4cd3db1f91b985cc8a246d330b9ac3fc0b6a325a6d82bddc0b055123d745b3f9931afeea74a5ec545439a1630b9c8512b0eeb49 + languageName: node + linkType: hard + +"define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" + dependencies: + define-data-property: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 + languageName: node + linkType: hard + +"delaunator@npm:5": + version: 5.1.0 + resolution: "delaunator@npm:5.1.0" + dependencies: + robust-predicates: "npm:^3.0.2" + checksum: 10c0/6489e3598212ab8759575e30f3ac26063471846e25c779048f441f2ccefd25efb9a52275e7e8e3dcc5bf5bc5c35169cf1de27f985d359fd5a24057be88fd1817 + languageName: node + linkType: hard + +"depd@npm:2.0.0, depd@npm:~2.0.0": + version: 2.0.0 + resolution: "depd@npm:2.0.0" + checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c + languageName: node + linkType: hard + +"depd@npm:~1.1.2": + version: 1.1.2 + resolution: "depd@npm:1.1.2" + checksum: 10c0/acb24aaf936ef9a227b6be6d495f0d2eb20108a9a6ad40585c5bda1a897031512fef6484e4fdbb80bd249fdaa82841fa1039f416ece03188e677ba11bcfda249 + languageName: node + linkType: hard + +"dequal@npm:^2.0.0": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + +"destroy@npm:1.2.0, destroy@npm:~1.2.0": + version: 1.2.0 + resolution: "destroy@npm:1.2.0" + checksum: 10c0/bd7633942f57418f5a3b80d5cb53898127bcf53e24cdf5d5f4396be471417671f0fee48a4ebe9a1e9defbde2a31280011af58a57e090ff822f589b443ed4e643 + languageName: node + linkType: hard + +"detect-libc@npm:^2.0.3": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4 + languageName: node + linkType: hard + +"detect-node@npm:^2.0.4": + version: 2.1.0 + resolution: "detect-node@npm:2.1.0" + checksum: 10c0/f039f601790f2e9d4654e499913259a798b1f5246ae24f86ab5e8bd4aaf3bce50484234c494f11fb00aecb0c6e2733aa7b1cf3f530865640b65fbbd65b2c4e09 + languageName: node + linkType: hard + +"detect-port@npm:^1.5.1": + version: 1.6.1 + resolution: "detect-port@npm:1.6.1" + dependencies: + address: "npm:^1.0.1" + debug: "npm:4" + bin: + detect: bin/detect-port.js + detect-port: bin/detect-port.js + checksum: 10c0/4ea9eb46a637cb21220dd0a62b6074792894fc77b2cacbc9de533d1908b2eedafa7bfd7547baaa2ac1e9c7ba7c289b34b17db896dca6da142f4fc6e2060eee17 + languageName: node + linkType: hard + +"devlop@npm:^1.0.0, devlop@npm:^1.1.0": + version: 1.1.0 + resolution: "devlop@npm:1.1.0" + dependencies: + dequal: "npm:^2.0.0" + checksum: 10c0/e0928ab8f94c59417a2b8389c45c55ce0a02d9ac7fd74ef62d01ba48060129e1d594501b77de01f3eeafc7cb00773819b0df74d96251cf20b31c5b3071f45c0e + languageName: node + linkType: hard + +"dicer@npm:0.3.0": + version: 0.3.0 + resolution: "dicer@npm:0.3.0" + dependencies: + streamsearch: "npm:0.1.2" + checksum: 10c0/4486f0448233145216cfadd5f6bbb4c26c3a28824da5344322b06051632e99d6af2b44f893fa8b30f1749ad175b4e565d301c760d0437226d9e41ccdb6546f35 + languageName: node + linkType: hard + +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: "npm:^4.0.0" + checksum: 10c0/dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c + languageName: node + linkType: hard + +"dns-packet@npm:^5.2.2": + version: 5.6.1 + resolution: "dns-packet@npm:5.6.1" + dependencies: + "@leichtgewicht/ip-codec": "npm:^2.0.1" + checksum: 10c0/8948d3d03063fb68e04a1e386875f8c3bcc398fc375f535f2b438fad8f41bf1afa6f5e70893ba44f4ae884c089247e0a31045722fa6ff0f01d228da103f1811d + languageName: node + linkType: hard + +"docusaurus-theme-github-codeblock@npm:^2.0.2": + version: 2.0.2 + resolution: "docusaurus-theme-github-codeblock@npm:2.0.2" + dependencies: + "@docusaurus/types": "npm:^3.0.0" + checksum: 10c0/9de760df4b3811f219eecbe877fbc574685f8c01d8ad6547dea657c91c06b09cc16220491470ea7d913c93bfaa0464b7a0ffef4e49cf884efc3c86fe9013dd8c + languageName: node + linkType: hard + +"dom-converter@npm:^0.2.0": + version: 0.2.0 + resolution: "dom-converter@npm:0.2.0" + dependencies: + utila: "npm:~0.4" + checksum: 10c0/e96aa63bd8c6ee3cd9ce19c3aecfc2c42e50a460e8087114794d4f5ecf3a4f052b34ea3bf2d73b5d80b4da619073b49905e6d7d788ceb7814ca4c29be5354a11 + languageName: node + linkType: hard + +"dom-serializer@npm:^1.0.1": + version: 1.4.1 + resolution: "dom-serializer@npm:1.4.1" + dependencies: + domelementtype: "npm:^2.0.1" + domhandler: "npm:^4.2.0" + entities: "npm:^2.0.0" + checksum: 10c0/67d775fa1ea3de52035c98168ddcd59418356943b5eccb80e3c8b3da53adb8e37edb2cc2f885802b7b1765bf5022aec21dfc32910d7f9e6de4c3148f095ab5e0 + languageName: node + linkType: hard + +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2 + languageName: node + linkType: hard + +"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 + languageName: node + linkType: hard + +"domhandler@npm:^4.0.0, domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": + version: 4.3.1 + resolution: "domhandler@npm:4.3.1" + dependencies: + domelementtype: "npm:^2.2.0" + checksum: 10c0/5c199c7468cb052a8b5ab80b13528f0db3d794c64fc050ba793b574e158e67c93f8336e87fd81e9d5ee43b0e04aea4d8b93ed7be4899cb726a1601b3ba18538b + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a + languageName: node + linkType: hard + +"dompurify@npm:^3.3.1": + version: 3.3.3 + resolution: "dompurify@npm:3.3.3" + dependencies: + "@types/trusted-types": "npm:^2.0.7" + dependenciesMeta: + "@types/trusted-types": + optional: true + checksum: 10c0/097c14a21a3f6cb95beded9ecd255f7c3512c42767b048390c747b0fe35736f6a71e02320fc50a9ac2be645834b463e4760915d595d502a56452daf339d0ea9c + languageName: node + linkType: hard + +"domutils@npm:^2.5.2, domutils@npm:^2.8.0": + version: 2.8.0 + resolution: "domutils@npm:2.8.0" + dependencies: + dom-serializer: "npm:^1.0.1" + domelementtype: "npm:^2.2.0" + domhandler: "npm:^4.2.0" + checksum: 10c0/d58e2ae01922f0dd55894e61d18119924d88091837887bf1438f2327f32c65eb76426bd9384f81e7d6dcfb048e0f83c19b222ad7101176ad68cdc9c695b563db + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 10c0/47938f473b987ea71cd59e59626eb8666d3aa8feba5266e45527f3b636c7883cca7e582d901531961f742c519d7514636b7973353b648762b2e3bedbf235fada + languageName: node + linkType: hard + +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/5b859ea65097a7ea870e2c91b5768b72ddf7fa947223fd29e167bcdff58fe731d941c48e47a38ec8aa8e43044c8fbd15cd8fa21689a526bc34b6548197cd5b05 + languageName: node + linkType: hard + +"dot-prop@npm:^6.0.1": + version: 6.0.1 + resolution: "dot-prop@npm:6.0.1" + dependencies: + is-obj: "npm:^2.0.0" + checksum: 10c0/30e51ec6408978a6951b21e7bc4938aad01a86f2fdf779efe52330205c6bb8a8ea12f35925c2029d6dc9d1df22f916f32f828ce1e9b259b1371c580541c22b5a + languageName: node + linkType: hard + +"dotenv@npm:^10.0.0": + version: 10.0.0 + resolution: "dotenv@npm:10.0.0" + checksum: 10c0/2d8d4ba64bfaff7931402aa5e8cbb8eba0acbc99fe9ae442300199af021079eafa7171ce90e150821a5cb3d74f0057721fbe7ec201a6044b68c8a7615f8c123f + languageName: node + linkType: hard + +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.2.0" + checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 + languageName: node + linkType: hard + +"duplexer@npm:^0.1.2": + version: 0.1.2 + resolution: "duplexer@npm:0.1.2" + checksum: 10c0/c57bcd4bdf7e623abab2df43a7b5b23d18152154529d166c1e0da6bee341d84c432d157d7e97b32fecb1bf3a8b8857dd85ed81a915789f550637ed25b8e64fc2 + languageName: node + linkType: hard + +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 + languageName: node + linkType: hard + +"ee-first@npm:1.1.1": + version: 1.1.1 + resolution: "ee-first@npm:1.1.1" + checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.5.263": + version: 1.5.321 + resolution: "electron-to-chromium@npm:1.5.321" + checksum: 10c0/1272703857b8ac9868a75d495c141b71bad36adcb0df53393196da3819012fa2596ba48fccac750bdcb746a523d2a33543b36e9dc0ae727a55e7a6f00b2b155a + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.5.328": + version: 1.5.332 + resolution: "electron-to-chromium@npm:1.5.332" + checksum: 10c0/0e9aedd5634e81f323919a5fba7e1cf34c18860262a50915fb2371a6c65324cbfa50eaea231d05d235cc40b1b60cfaf0c1546d3f2daa6ad6c03e89dfe21cb55f + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 + languageName: node + linkType: hard + +"emojilib@npm:^2.4.0": + version: 2.4.0 + resolution: "emojilib@npm:2.4.0" + checksum: 10c0/6e66ba8921175842193f974e18af448bb6adb0cf7aeea75e08b9d4ea8e9baba0e4a5347b46ed901491dcaba277485891c33a8d70b0560ca5cc9672a94c21ab8f + languageName: node + linkType: hard + +"emojis-list@npm:^3.0.0": + version: 3.0.0 + resolution: "emojis-list@npm:3.0.0" + checksum: 10c0/7dc4394b7b910444910ad64b812392159a21e1a7ecc637c775a440227dcb4f80eff7fe61f4453a7d7603fa23d23d30cc93fe9e4b5ed985b88d6441cd4a35117b + languageName: node + linkType: hard + +"emoticon@npm:^4.0.1": + version: 4.1.0 + resolution: "emoticon@npm:4.1.0" + checksum: 10c0/b3bc0a9b370445ac1e980ccba7baea614b4648199cc6fa0a51696a6d2393733e8f985edc4f1af381a1903f625789483dd155de427ec9fa2ea415fac116adc06d + languageName: node + linkType: hard + +"encodeurl@npm:~2.0.0": + version: 2.0.0 + resolution: "encodeurl@npm:2.0.0" + checksum: 10c0/5d317306acb13e6590e28e27924c754163946a2480de11865c991a3a7eed4315cd3fba378b543ca145829569eefe9b899f3d84bb09870f675ae60bc924b01ceb + languageName: node + linkType: hard + +"enhanced-resolve@npm:^5.17.1": + version: 5.18.1 + resolution: "enhanced-resolve@npm:5.18.1" + dependencies: + graceful-fs: "npm:^4.2.4" + tapable: "npm:^2.2.0" + checksum: 10c0/4cffd9b125225184e2abed9fdf0ed3dbd2224c873b165d0838fd066cde32e0918626cba2f1f4bf6860762f13a7e2364fd89a82b99566be2873d813573ac71846 + languageName: node + linkType: hard + +"entities@npm:^2.0.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 10c0/7fba6af1f116300d2ba1c5673fc218af1961b20908638391b4e1e6d5850314ee2ac3ec22d741b3a8060479911c99305164aed19b6254bde75e7e6b1b2c3f3aa3 + languageName: node + linkType: hard + +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 10c0/ed836ddac5acb34341094eb495185d527bd70e8632b6c0d59548cbfa23defdbae70b96f9a405c82904efa421230b5b3fd2283752447d737beffd3f3e6ee74414 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"error-ex@npm:^1.3.1": + version: 1.3.4 + resolution: "error-ex@npm:1.3.4" + dependencies: + is-arrayish: "npm:^0.2.1" + checksum: 10c0/b9e34ff4778b8f3b31a8377e1c654456f4c41aeaa3d10a1138c3b7635d8b7b2e03eb2475d46d8ae055c1f180a1063e100bffabf64ea7e7388b37735df5328664 + languageName: node + linkType: hard + +"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 + languageName: node + linkType: hard + +"es-module-lexer@npm:^1.2.1": + version: 1.6.0 + resolution: "es-module-lexer@npm:1.6.0" + checksum: 10c0/667309454411c0b95c476025929881e71400d74a746ffa1ff4cb450bd87f8e33e8eef7854d68e401895039ac0bac64e7809acbebb6253e055dd49ea9e3ea9212 + languageName: node + linkType: hard + +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: "npm:^1.3.0" + checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c + languageName: node + linkType: hard + +"esast-util-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "esast-util-from-estree@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-visit: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + checksum: 10c0/6c619bc6963314f8f64b32e3b101b321bf121f659e62b11e70f425619c2db6f1d25f4c594a57fd00908da96c67d9bfbf876eb5172abf9e13f47a71796f6630ff + languageName: node + linkType: hard + +"esast-util-from-js@npm:^2.0.0": + version: 2.0.1 + resolution: "esast-util-from-js@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + acorn: "npm:^8.0.0" + esast-util-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3a446fb0b0d7bcd7e0157aa44b3b692802a08c93edbea81cc0f7fe4437bfdfb4b72e4563fe63b4e36d390086b71185dba4ac921f4180cc6349985c263cc74421 + languageName: node + linkType: hard + +"esbuild-android-arm64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-android-arm64@npm:0.14.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"esbuild-darwin-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-darwin-64@npm:0.14.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"esbuild-darwin-arm64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-darwin-arm64@npm:0.14.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"esbuild-freebsd-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-freebsd-64@npm:0.14.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"esbuild-freebsd-arm64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-freebsd-arm64@npm:0.14.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"esbuild-linux-32@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-linux-32@npm:0.14.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"esbuild-linux-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-linux-64@npm:0.14.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"esbuild-linux-arm64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-linux-arm64@npm:0.14.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"esbuild-linux-arm@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-linux-arm@npm:0.14.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"esbuild-linux-mips64le@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-linux-mips64le@npm:0.14.1" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"esbuild-linux-ppc64le@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-linux-ppc64le@npm:0.14.1" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"esbuild-netbsd-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-netbsd-64@npm:0.14.1" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"esbuild-openbsd-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-openbsd-64@npm:0.14.1" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"esbuild-sunos-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-sunos-64@npm:0.14.1" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"esbuild-windows-32@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-windows-32@npm:0.14.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"esbuild-windows-64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-windows-64@npm:0.14.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"esbuild-windows-arm64@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild-windows-arm64@npm:0.14.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"esbuild@npm:0.14.1": + version: 0.14.1 + resolution: "esbuild@npm:0.14.1" + dependencies: + esbuild-android-arm64: "npm:0.14.1" + esbuild-darwin-64: "npm:0.14.1" + esbuild-darwin-arm64: "npm:0.14.1" + esbuild-freebsd-64: "npm:0.14.1" + esbuild-freebsd-arm64: "npm:0.14.1" + esbuild-linux-32: "npm:0.14.1" + esbuild-linux-64: "npm:0.14.1" + esbuild-linux-arm: "npm:0.14.1" + esbuild-linux-arm64: "npm:0.14.1" + esbuild-linux-mips64le: "npm:0.14.1" + esbuild-linux-ppc64le: "npm:0.14.1" + esbuild-netbsd-64: "npm:0.14.1" + esbuild-openbsd-64: "npm:0.14.1" + esbuild-sunos-64: "npm:0.14.1" + esbuild-windows-32: "npm:0.14.1" + esbuild-windows-64: "npm:0.14.1" + esbuild-windows-arm64: "npm:0.14.1" + dependenciesMeta: + esbuild-android-arm64: + optional: true + esbuild-darwin-64: + optional: true + esbuild-darwin-arm64: + optional: true + esbuild-freebsd-64: + optional: true + esbuild-freebsd-arm64: + optional: true + esbuild-linux-32: + optional: true + esbuild-linux-64: + optional: true + esbuild-linux-arm: + optional: true + esbuild-linux-arm64: + optional: true + esbuild-linux-mips64le: + optional: true + esbuild-linux-ppc64le: + optional: true + esbuild-netbsd-64: + optional: true + esbuild-openbsd-64: + optional: true + esbuild-sunos-64: + optional: true + esbuild-windows-32: + optional: true + esbuild-windows-64: + optional: true + esbuild-windows-arm64: + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/a276d7032ebf6b0f222eb093ce251e3b892c90181f7e31e9617bf2ce532b2ca3611345029239286c8b943b79819d0234732d65b1d5461696b1a5e3dc4d16b2f9 + languageName: node + linkType: hard + +"escalade@npm:^3.1.1, escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 + languageName: node + linkType: hard + +"escape-goat@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-goat@npm:4.0.0" + checksum: 10c0/9d2a8314e2370f2dd9436d177f6b3b1773525df8f895c8f3e1acb716f5fd6b10b336cb1cd9862d4709b36eb207dbe33664838deca9c6d55b8371be4eebb972f6 + languageName: node + linkType: hard + +"escape-html@npm:^1.0.3, escape-html@npm:~1.0.3": + version: 1.0.3 + resolution: "escape-html@npm:1.0.3" + checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 10c0/6366f474c6f37a802800a435232395e04e9885919873e382b157ab7e8f0feb8fed71497f84a6f6a81a49aab41815522f5839112bd38026d203aea0c91622df95 + languageName: node + linkType: hard + +"eslint-scope@npm:5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a + languageName: node + linkType: hard + +"esprima@npm:^4.0.0": + version: 4.0.1 + resolution: "esprima@npm:4.0.1" + bin: + esparse: ./bin/esparse.js + esvalidate: ./bin/esvalidate.js + checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 + languageName: node + linkType: hard + +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d + languageName: node + linkType: hard + +"estraverse@npm:^5.2.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 + languageName: node + linkType: hard + +"estree-util-attach-comments@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-attach-comments@npm:3.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/ee69bb5c45e2ad074725b90ed181c1c934b29d81bce4b0c7761431e83c4c6ab1b223a6a3d6a4fbeb92128bc5d5ee201d5dd36cf1770aa5e16a40b0cf36e8a1f1 + languageName: node + linkType: hard + +"estree-util-build-jsx@npm:^3.0.0": + version: 3.0.1 + resolution: "estree-util-build-jsx@npm:3.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + estree-walker: "npm:^3.0.0" + checksum: 10c0/274c119817b8e7caa14a9778f1e497fea56cdd2b01df1a1ed037f843178992d3afe85e0d364d485e1e2e239255763553d1b647b15e4a7ba50851bcb43dc6bf80 + languageName: node + linkType: hard + +"estree-util-is-identifier-name@npm:^3.0.0": + version: 3.0.0 + resolution: "estree-util-is-identifier-name@npm:3.0.0" + checksum: 10c0/d1881c6ed14bd588ebd508fc90bf2a541811dbb9ca04dec2f39d27dcaa635f85b5ed9bbbe7fc6fb1ddfca68744a5f7c70456b4b7108b6c4c52780631cc787c5b + languageName: node + linkType: hard + +"estree-util-scope@npm:^1.0.0": + version: 1.0.0 + resolution: "estree-util-scope@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + checksum: 10c0/ef8a573cc899277c613623a1722f630e2163abbc6e9e2f49e758c59b81b484e248b585df6df09a38c00fbfb6390117997cc80c1347b7a86bc1525d9e462b60d5 + languageName: node + linkType: hard + +"estree-util-to-js@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-to-js@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + astring: "npm:^1.8.0" + source-map: "npm:^0.7.0" + checksum: 10c0/ac88cb831401ef99e365f92f4af903755d56ae1ce0e0f0fb8ff66e678141f3d529194f0fb15f6c78cd7554c16fda36854df851d58f9e05cfab15bddf7a97cea0 + languageName: node + linkType: hard + +"estree-util-value-to-estree@npm:^3.0.1": + version: 3.5.0 + resolution: "estree-util-value-to-estree@npm:3.5.0" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/05c8d4b3338598929122cbfd6b127b22de4600dda8178b789b0d139e5b296e57a2343e487d6e108d8c39b18550dae2af3a110093698684db810954f353e9099b + languageName: node + linkType: hard + +"estree-util-visit@npm:^2.0.0": + version: 2.0.0 + resolution: "estree-util-visit@npm:2.0.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/unist": "npm:^3.0.0" + checksum: 10c0/acda8b03cc8f890d79c7c7361f6c95331ba84b7ccc0c32b49f447fc30206b20002b37ffdfc97b6ad16e6fe065c63ecbae1622492e2b6b4775c15966606217f39 + languageName: node + linkType: hard + +"estree-walker@npm:^3.0.0": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 + languageName: node + linkType: hard + +"eta@npm:^2.2.0": + version: 2.2.0 + resolution: "eta@npm:2.2.0" + checksum: 10c0/643b54d9539d2761bf6c5f4f48df1a5ea2d46c7f5a5fdc47a7d4802a8aa2b6262d4d61f724452e226c18cf82db02d48e65293fcc548f26a3f9d75a5ba7c3b859 + languageName: node + linkType: hard + +"etag@npm:~1.8.1": + version: 1.8.1 + resolution: "etag@npm:1.8.1" + checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 + languageName: node + linkType: hard + +"eval@npm:^0.1.8": + version: 0.1.8 + resolution: "eval@npm:0.1.8" + dependencies: + "@types/node": "npm:*" + require-like: "npm:>= 0.1.1" + checksum: 10c0/258e700bff09e3ce3344273d5b6691b8ec5b043538d84f738f14d8b0aded33d64c00c15b380de725b1401b15f428ab35a9e7ca19a7d25f162c4f877c71586be9 + languageName: node + linkType: hard + +"eventemitter3@npm:^4.0.0, eventemitter3@npm:^4.0.4": + version: 4.0.7 + resolution: "eventemitter3@npm:4.0.7" + checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b + languageName: node + linkType: hard + +"events@npm:^3.2.0": + version: 3.3.0 + resolution: "events@npm:3.3.0" + checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 + languageName: node + linkType: hard + +"execa@npm:5.1.1, execa@npm:^5.1.1": + version: 5.1.1 + resolution: "execa@npm:5.1.1" + dependencies: + cross-spawn: "npm:^7.0.3" + get-stream: "npm:^6.0.0" + human-signals: "npm:^2.1.0" + is-stream: "npm:^2.0.0" + merge-stream: "npm:^2.0.0" + npm-run-path: "npm:^4.0.1" + onetime: "npm:^5.1.2" + signal-exit: "npm:^3.0.3" + strip-final-newline: "npm:^2.0.0" + checksum: 10c0/c8e615235e8de4c5addf2fa4c3da3e3aa59ce975a3e83533b4f6a71750fb816a2e79610dc5f1799b6e28976c9ae86747a36a606655bf8cb414a74d8d507b304f + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 + languageName: node + linkType: hard + +"express@npm:^4.22.1": + version: 4.22.1 + resolution: "express@npm:4.22.1" + dependencies: + accepts: "npm:~1.3.8" + array-flatten: "npm:1.1.1" + body-parser: "npm:~1.20.3" + content-disposition: "npm:~0.5.4" + content-type: "npm:~1.0.4" + cookie: "npm:~0.7.1" + cookie-signature: "npm:~1.0.6" + debug: "npm:2.6.9" + depd: "npm:2.0.0" + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + etag: "npm:~1.8.1" + finalhandler: "npm:~1.3.1" + fresh: "npm:~0.5.2" + http-errors: "npm:~2.0.0" + merge-descriptors: "npm:1.0.3" + methods: "npm:~1.1.2" + on-finished: "npm:~2.4.1" + parseurl: "npm:~1.3.3" + path-to-regexp: "npm:~0.1.12" + proxy-addr: "npm:~2.0.7" + qs: "npm:~6.14.0" + range-parser: "npm:~1.2.1" + safe-buffer: "npm:5.2.1" + send: "npm:~0.19.0" + serve-static: "npm:~1.16.2" + setprototypeof: "npm:1.2.0" + statuses: "npm:~2.0.1" + type-is: "npm:~1.6.18" + utils-merge: "npm:1.0.1" + vary: "npm:~1.1.2" + checksum: 10c0/ea57f512ab1e05e26b53a14fd432f65a10ec735ece342b37d0b63a7bcb8d337ffbb830ecb8ca15bcdfe423fbff88cea09786277baff200e8cde3ab40faa665cd + languageName: node + linkType: hard + +"extend-shallow@npm:^2.0.1": + version: 2.0.1 + resolution: "extend-shallow@npm:2.0.1" + dependencies: + is-extendable: "npm:^0.1.0" + checksum: 10c0/ee1cb0a18c9faddb42d791b2d64867bd6cfd0f3affb711782eb6e894dd193e2934a7f529426aac7c8ddb31ac5d38000a00aa2caf08aa3dfc3e1c8ff6ba340bd9 + languageName: node + linkType: hard + +"extend@npm:^3.0.0": + version: 3.0.2 + resolution: "extend@npm:3.0.2" + checksum: 10c0/73bf6e27406e80aa3e85b0d1c4fd987261e628064e170ca781125c0b635a3dabad5e05adbf07595ea0cf1e6c5396cacb214af933da7cbaf24fe75ff14818e8f9 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 + languageName: node + linkType: hard + +"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": + version: 3.3.3 + resolution: "fast-glob@npm:3.3.3" + dependencies: + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.8" + checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe + languageName: node + linkType: hard + +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b + languageName: node + linkType: hard + +"fast-uri@npm:^3.0.1": + version: 3.0.6 + resolution: "fast-uri@npm:3.0.6" + checksum: 10c0/74a513c2af0584448aee71ce56005185f81239eab7a2343110e5bad50c39ad4fb19c5a6f99783ead1cac7ccaf3461a6034fda89fffa2b30b6d99b9f21c2f9d29 + languageName: node + linkType: hard + +"fastq@npm:^1.6.0": + version: 1.20.1 + resolution: "fastq@npm:1.20.1" + dependencies: + reusify: "npm:^1.0.4" + checksum: 10c0/e5dd725884decb1f11e5c822221d76136f239d0236f176fab80b7b8f9e7619ae57e6b4e5b73defc21e6b9ef99437ee7b545cff8e6c2c337819633712fa9d352e + languageName: node + linkType: hard + +"fault@npm:^2.0.0": + version: 2.0.1 + resolution: "fault@npm:2.0.1" + dependencies: + format: "npm:^0.2.0" + checksum: 10c0/b80fbf1019b9ce8b08ee09ce86e02b028563e13a32ac3be34e42bfac00a97b96d8dee6d31e26578ffc16224eb6729e01ff1f97ddfeee00494f4f56c0aeed4bdd + languageName: node + linkType: hard + +"faye-websocket@npm:^0.11.3": + version: 0.11.4 + resolution: "faye-websocket@npm:0.11.4" + dependencies: + websocket-driver: "npm:>=0.5.1" + checksum: 10c0/c6052a0bb322778ce9f89af92890f6f4ce00d5ec92418a35e5f4c6864a4fe736fec0bcebd47eac7c0f0e979b01530746b1c85c83cb04bae789271abf19737420 + languageName: node + linkType: hard + +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f + languageName: node + linkType: hard + +"feed@npm:^4.2.2": + version: 4.2.2 + resolution: "feed@npm:4.2.2" + dependencies: + xml-js: "npm:^1.6.11" + checksum: 10c0/c0849bde569da94493224525db00614fd1855a5d7c2e990f6e8637bd0298e85c3d329efe476cba77e711e438c3fb48af60cd5ef0c409da5bcd1f479790b0a372 + languageName: node + linkType: hard + +"figures@npm:^3.2.0": + version: 3.2.0 + resolution: "figures@npm:3.2.0" + dependencies: + escape-string-regexp: "npm:^1.0.5" + checksum: 10c0/9c421646ede432829a50bc4e55c7a4eb4bcb7cc07b5bab2f471ef1ab9a344595bbebb6c5c21470093fbb730cd81bbca119624c40473a125293f656f49cb47629 + languageName: node + linkType: hard + +"file-loader@npm:^6.2.0": + version: 6.2.0 + resolution: "file-loader@npm:6.2.0" + dependencies: + loader-utils: "npm:^2.0.0" + schema-utils: "npm:^3.0.0" + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: 10c0/e176a57c2037ab0f78e5755dbf293a6b7f0f8392350a120bd03cc2ce2525bea017458ba28fea14ca535ff1848055e86d1a3a216bdb2561ef33395b27260a1dd3 + languageName: node + linkType: hard + +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: "npm:^5.0.1" + checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 + languageName: node + linkType: hard + +"finalhandler@npm:~1.3.1": + version: 1.3.2 + resolution: "finalhandler@npm:1.3.2" + dependencies: + debug: "npm:2.6.9" + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + on-finished: "npm:~2.4.1" + parseurl: "npm:~1.3.3" + statuses: "npm:~2.0.2" + unpipe: "npm:~1.0.0" + checksum: 10c0/435a4fd65e4e4e4c71bb5474980090b73c353a123dd415583f67836bdd6516e528cf07298e219a82b94631dee7830eae5eece38d3c178073cf7df4e8c182f413 + languageName: node + linkType: hard + +"find-cache-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "find-cache-dir@npm:4.0.0" + dependencies: + common-path-prefix: "npm:^3.0.0" + pkg-dir: "npm:^7.0.0" + checksum: 10c0/0faa7956974726c8769671de696d24c643ca1e5b8f7a2401283caa9e07a5da093293e0a0f4bd18c920ec981d2ef945c7f5b946cde268dfc9077d833ad0293cff + languageName: node + linkType: hard + +"find-up@npm:^6.3.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: "npm:^7.1.0" + path-exists: "npm:^5.0.0" + checksum: 10c0/07e0314362d316b2b13f7f11ea4692d5191e718ca3f7264110127520f3347996349bf9e16805abae3e196805814bc66ef4bff2b8904dc4a6476085fc9b0eba07 + languageName: node + linkType: hard + +"flat@npm:^5.0.2": + version: 5.0.2 + resolution: "flat@npm:5.0.2" + bin: + flat: cli.js + checksum: 10c0/f178b13482f0cd80c7fede05f4d10585b1f2fdebf26e12edc138e32d3150c6ea6482b7f12813a1091143bad52bb6d3596bca51a162257a21163c0ff438baa5fe + languageName: node + linkType: hard + +"flet-dev@workspace:.": + version: 0.0.0-use.local + resolution: "flet-dev@workspace:." + dependencies: + "@docsearch/docusaurus-adapter": "npm:^4.6.2" + "@docusaurus/core": "npm:^3.10.0" + "@docusaurus/faster": "npm:^3.10.0" + "@docusaurus/plugin-client-redirects": "npm:^3.10.0" + "@docusaurus/preset-classic": "npm:^3.10.0" + "@docusaurus/theme-mermaid": "npm:^3.10.0" + "@hcaptcha/react-hcaptcha": "npm:^1.0.0" + "@mdx-js/react": "npm:^3.0.0" + clsx: "npm:^1.1.1" + docusaurus-theme-github-codeblock: "npm:^2.0.2" + prism-react-renderer: "npm:^2.1.0" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + wrangler: "npm:^0.0.7" + languageName: unknown + linkType: soft + +"follow-redirects@npm:^1.0.0": + version: 1.15.11 + resolution: "follow-redirects@npm:1.15.11" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343 + languageName: node + linkType: hard + +"form-data-encoder@npm:^2.1.2": + version: 2.1.4 + resolution: "form-data-encoder@npm:2.1.4" + checksum: 10c0/4c06ae2b79ad693a59938dc49ebd020ecb58e4584860a90a230f80a68b026483b022ba5e4143cff06ae5ac8fd446a0b500fabc87bbac3d1f62f2757f8dabcaf7 + languageName: node + linkType: hard + +"format@npm:^0.2.0": + version: 0.2.2 + resolution: "format@npm:0.2.2" + checksum: 10c0/6032ba747541a43abf3e37b402b2f72ee08ebcb58bf84d816443dd228959837f1cddf1e8775b29fa27ff133f4bd146d041bfca5f9cf27f048edf3d493cf8fee6 + languageName: node + linkType: hard + +"forwarded@npm:0.2.0": + version: 0.2.0 + resolution: "forwarded@npm:0.2.0" + checksum: 10c0/9b67c3fac86acdbc9ae47ba1ddd5f2f81526fa4c8226863ede5600a3f7c7416ef451f6f1e240a3cc32d0fd79fcfe6beb08fd0da454f360032bde70bf80afbb33 + languageName: node + linkType: hard + +"fraction.js@npm:^5.3.4": + version: 5.3.4 + resolution: "fraction.js@npm:5.3.4" + checksum: 10c0/f90079fe9bfc665e0a07079938e8ff71115bce9462f17b32fc283f163b0540ec34dc33df8ed41bb56f028316b04361b9a9995b9ee9258617f8338e0b05c5f95a + languageName: node + linkType: hard + +"fresh@npm:~0.5.2": + version: 0.5.2 + resolution: "fresh@npm:0.5.2" + checksum: 10c0/c6d27f3ed86cc5b601404822f31c900dd165ba63fff8152a3ef714e2012e7535027063bc67ded4cb5b3a49fa596495d46cacd9f47d6328459cf570f08b7d9e5a + languageName: node + linkType: hard + +"fs-extra@npm:^11.1.1, fs-extra@npm:^11.2.0": + version: 11.3.0 + resolution: "fs-extra@npm:11.3.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/5f95e996186ff45463059feb115a22fb048bdaf7e487ecee8a8646c78ed8fdca63630e3077d4c16ce677051f5e60d3355a06f3cd61f3ca43f48cc58822a44d0a + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 + languageName: node + linkType: hard + +"fsevents@npm:~2.3.2": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 + languageName: node + linkType: hard + +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.3.0": + version: 1.3.0 + resolution: "get-intrinsic@npm:1.3.0" + dependencies: + call-bind-apply-helpers: "npm:^1.0.2" + es-define-property: "npm:^1.0.1" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.1.1" + function-bind: "npm:^1.1.2" + get-proto: "npm:^1.0.1" + gopd: "npm:^1.2.0" + has-symbols: "npm:^1.1.0" + hasown: "npm:^2.0.2" + math-intrinsics: "npm:^1.1.0" + checksum: 10c0/52c81808af9a8130f581e6a6a83e1ba4a9f703359e7a438d1369a5267a25412322f03dcbd7c549edaef0b6214a0630a28511d7df0130c93cfd380f4fa0b5b66a + languageName: node + linkType: hard + +"get-own-enumerable-property-symbols@npm:^3.0.0": + version: 3.0.2 + resolution: "get-own-enumerable-property-symbols@npm:3.0.2" + checksum: 10c0/103999855f3d1718c631472437161d76962cbddcd95cc642a34c07bfb661ed41b6c09a9c669ccdff89ee965beb7126b80eec7b2101e20e31e9cc6c4725305e10 + languageName: node + linkType: hard + +"get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: "npm:^1.0.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c + languageName: node + linkType: hard + +"get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": + version: 6.0.1 + resolution: "get-stream@npm:6.0.1" + checksum: 10c0/49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 + languageName: node + linkType: hard + +"github-slugger@npm:^1.5.0": + version: 1.5.0 + resolution: "github-slugger@npm:1.5.0" + checksum: 10c0/116f99732925f939cbfd6f2e57db1aa7e111a460db0d103e3b3f2fce6909d44311663d4542350706cad806345b9892358cc3b153674f88eeae77f43380b3bfca + languageName: node + linkType: hard + +"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: "npm:^4.0.1" + checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee + languageName: node + linkType: hard + +"glob-parent@npm:^6.0.1": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 + languageName: node + linkType: hard + +"glob-to-regex.js@npm:^1.0.0, glob-to-regex.js@npm:^1.0.1": + version: 1.2.0 + resolution: "glob-to-regex.js@npm:1.2.0" + peerDependencies: + tslib: 2 + checksum: 10c0/011c81ae2a4d7ac5fd617038209fd9639d54c76211cc88fe8dd85d1a0850bc683a63cf5b1eae370141fca7dd2c834dfb9684dfdd8bf7472f2c1e4ef6ab6e34f9 + languageName: node + linkType: hard + +"glob-to-regexp@npm:^0.4.1": + version: 0.4.1 + resolution: "glob-to-regexp@npm:0.4.1" + checksum: 10c0/0486925072d7a916f052842772b61c3e86247f0a80cc0deb9b5a3e8a1a9faad5b04fb6f58986a09f34d3e96cd2a22a24b7e9882fb1cf904c31e9a310de96c429 + languageName: node + linkType: hard + +"glob@npm:^13.0.0": + version: 13.0.6 + resolution: "glob@npm:13.0.6" + dependencies: + minimatch: "npm:^10.2.2" + minipass: "npm:^7.1.3" + path-scurry: "npm:^2.0.2" + checksum: 10c0/269c236f11a9b50357fe7a8c6aadac667e01deb5242b19c84975628f05f4438d8ee1354bb62c5d6c10f37fd59911b54d7799730633a2786660d8c69f1d18120a + languageName: node + linkType: hard + +"global-dirs@npm:^3.0.0": + version: 3.0.1 + resolution: "global-dirs@npm:3.0.1" + dependencies: + ini: "npm:2.0.0" + checksum: 10c0/ef65e2241a47ff978f7006a641302bc7f4c03dfb98783d42bf7224c136e3a06df046e70ee3a010cf30214114755e46c9eb5eb1513838812fbbe0d92b14c25080 + languageName: node + linkType: hard + +"globby@npm:^11.1.0": + version: 11.1.0 + resolution: "globby@npm:11.1.0" + dependencies: + array-union: "npm:^2.1.0" + dir-glob: "npm:^3.0.1" + fast-glob: "npm:^3.2.9" + ignore: "npm:^5.2.0" + merge2: "npm:^1.4.1" + slash: "npm:^3.0.0" + checksum: 10c0/b39511b4afe4bd8a7aead3a27c4ade2b9968649abab0a6c28b1a90141b96ca68ca5db1302f7c7bd29eab66bf51e13916b8e0a3d0ac08f75e1e84a39b35691189 + languageName: node + linkType: hard + +"globby@npm:^13.1.1": + version: 13.2.2 + resolution: "globby@npm:13.2.2" + dependencies: + dir-glob: "npm:^3.0.1" + fast-glob: "npm:^3.3.0" + ignore: "npm:^5.2.4" + merge2: "npm:^1.4.1" + slash: "npm:^4.0.0" + checksum: 10c0/a8d7cc7cbe5e1b2d0f81d467bbc5bc2eac35f74eaded3a6c85fc26d7acc8e6de22d396159db8a2fc340b8a342e74cac58de8f4aee74146d3d146921a76062664 + languageName: node + linkType: hard + +"gopd@npm:^1.0.1, gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead + languageName: node + linkType: hard + +"got@npm:^12.1.0": + version: 12.6.1 + resolution: "got@npm:12.6.1" + dependencies: + "@sindresorhus/is": "npm:^5.2.0" + "@szmarczak/http-timer": "npm:^5.0.1" + cacheable-lookup: "npm:^7.0.0" + cacheable-request: "npm:^10.2.8" + decompress-response: "npm:^6.0.0" + form-data-encoder: "npm:^2.1.2" + get-stream: "npm:^6.0.1" + http2-wrapper: "npm:^2.1.10" + lowercase-keys: "npm:^3.0.0" + p-cancelable: "npm:^3.0.0" + responselike: "npm:^3.0.0" + checksum: 10c0/2fe97fcbd7a9ffc7c2d0ecf59aca0a0562e73a7749cadada9770eeb18efbdca3086262625fb65590594edc220a1eca58fab0d26b0c93c2f9a008234da71ca66b + languageName: node + linkType: hard + +"graceful-fs@npm:4.2.10": + version: 4.2.10 + resolution: "graceful-fs@npm:4.2.10" + checksum: 10c0/4223a833e38e1d0d2aea630c2433cfb94ddc07dfc11d511dbd6be1d16688c5be848acc31f9a5d0d0ddbfb56d2ee5a6ae0278aceeb0ca6a13f27e06b9956fb952 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 + languageName: node + linkType: hard + +"gray-matter@npm:^4.0.3": + version: 4.0.3 + resolution: "gray-matter@npm:4.0.3" + dependencies: + js-yaml: "npm:^3.13.1" + kind-of: "npm:^6.0.2" + section-matter: "npm:^1.0.0" + strip-bom-string: "npm:^1.0.0" + checksum: 10c0/e38489906dad4f162ca01e0dcbdbed96d1a53740cef446b9bf76d80bec66fa799af07776a18077aee642346c5e1365ed95e4c91854a12bf40ba0d4fb43a625a6 + languageName: node + linkType: hard + +"gzip-size@npm:^6.0.0": + version: 6.0.0 + resolution: "gzip-size@npm:6.0.0" + dependencies: + duplexer: "npm:^0.1.2" + checksum: 10c0/4ccb924626c82125897a997d1c84f2377846a6ef57fbee38f7c0e6b41387fba4d00422274440747b58008b5d60114bac2349c2908e9aba55188345281af40a3f + languageName: node + linkType: hard + +"hachure-fill@npm:^0.5.2": + version: 0.5.2 + resolution: "hachure-fill@npm:0.5.2" + checksum: 10c0/307e3b6f9f2d3c11a82099c3f71eecbb9c440c00c1f896ac1732c23e6dbff16a92bb893d222b8b721b89cf11e58649ca60b4c24e5663f705f877cefd40153429 + languageName: node + linkType: hard + +"handle-thing@npm:^2.0.0": + version: 2.0.1 + resolution: "handle-thing@npm:2.0.1" + checksum: 10c0/7ae34ba286a3434f1993ebd1cc9c9e6b6d8ea672182db28b1afc0a7119229552fa7031e3e5f3cd32a76430ece4e94b7da6f12af2eb39d6239a7693e4bd63a998 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 + languageName: node + linkType: hard + +"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" + dependencies: + es-define-property: "npm:^1.0.0" + checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 + languageName: node + linkType: hard + +"has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e + languageName: node + linkType: hard + +"has-yarn@npm:^3.0.0": + version: 3.0.0 + resolution: "has-yarn@npm:3.0.0" + checksum: 10c0/38c76618cb764e4a98ea114a3938e0bed6ceafb6bacab2ffb32e7c7d1e18b5e09cd03387d507ee87072388e1f20b1f80947fee62c41fc450edfbbdc02a665787 + languageName: node + linkType: hard + +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 + languageName: node + linkType: hard + +"hast-util-from-parse5@npm:^8.0.0": + version: 8.0.3 + resolution: "hast-util-from-parse5@npm:8.0.3" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + hastscript: "npm:^9.0.0" + property-information: "npm:^7.0.0" + vfile: "npm:^6.0.0" + vfile-location: "npm:^5.0.0" + web-namespaces: "npm:^2.0.0" + checksum: 10c0/40ace6c0ad43c26f721c7499fe408e639cde917b2350c9299635e6326559855896dae3c3ebf7440df54766b96c4276a7823e8f376a2b6a28b37b591f03412545 + languageName: node + linkType: hard + +"hast-util-parse-selector@npm:^4.0.0": + version: 4.0.0 + resolution: "hast-util-parse-selector@npm:4.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/5e98168cb44470dc274aabf1a28317e4feb09b1eaf7a48bbaa8c1de1b43a89cd195cb1284e535698e658e3ec26ad91bc5e52c9563c36feb75abbc68aaf68fb9f + languageName: node + linkType: hard + +"hast-util-raw@npm:^9.0.0": + version: 9.1.0 + resolution: "hast-util-raw@npm:9.1.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + hast-util-from-parse5: "npm:^8.0.0" + hast-util-to-parse5: "npm:^8.0.0" + html-void-elements: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + parse5: "npm:^7.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/d0d909d2aedecef6a06f0005cfae410d6475e6e182d768bde30c3af9fcbbe4f9beb0522bdc21d0679cb3c243c0df40385797ed255148d68b3d3f12e82d12aacc + languageName: node + linkType: hard + +"hast-util-to-estree@npm:^3.0.0": + version: 3.1.3 + resolution: "hast-util-to-estree@npm:3.1.3" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-attach-comments: "npm:^3.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/8e86c075319082c8a6304c5bcdf24ec02466074571e993f58bfa2cfd70850ef46d33b5c402208597a87fe0f02f1e620bda5958217efb1b7396c81c486373b75f + languageName: node + linkType: hard + +"hast-util-to-jsx-runtime@npm:^2.0.0": + version: 2.3.6 + resolution: "hast-util-to-jsx-runtime@npm:2.3.6" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/unist": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + hast-util-whitespace: "npm:^3.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + style-to-js: "npm:^1.0.0" + unist-util-position: "npm:^5.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/27297e02848fe37ef219be04a26ce708d17278a175a807689e94a821dcffc88aa506d62c3a85beed1f9a8544f7211bdcbcde0528b7b456a57c2e342c3fd11056 + languageName: node + linkType: hard + +"hast-util-to-parse5@npm:^8.0.0": + version: 8.0.1 + resolution: "hast-util-to-parse5@npm:8.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + devlop: "npm:^1.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + web-namespaces: "npm:^2.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/8e8a1817c7ff8906ac66e7201b1b8d19d9e1b705e695a6e71620270d498d982ec1ecc0e227bd517f723e91e7fdfb90ef75f9ae64d14b3b65239a7d5e1194d7dd + languageName: node + linkType: hard + +"hast-util-whitespace@npm:^3.0.0": + version: 3.0.0 + resolution: "hast-util-whitespace@npm:3.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + checksum: 10c0/b898bc9fe27884b272580d15260b6bbdabe239973a147e97fa98c45fa0ffec967a481aaa42291ec34fb56530dc2d484d473d7e2bae79f39c83f3762307edfea8 + languageName: node + linkType: hard + +"hastscript@npm:^9.0.0": + version: 9.0.1 + resolution: "hastscript@npm:9.0.1" + dependencies: + "@types/hast": "npm:^3.0.0" + comma-separated-tokens: "npm:^2.0.0" + hast-util-parse-selector: "npm:^4.0.0" + property-information: "npm:^7.0.0" + space-separated-tokens: "npm:^2.0.0" + checksum: 10c0/18dc8064e5c3a7a2ae862978e626b97a254e1c8a67ee9d0c9f06d373bba155ed805fc5b5ce21b990fb7bc174624889e5e1ce1cade264f1b1d58b48f994bc85ce + languageName: node + linkType: hard + +"he@npm:^1.2.0": + version: 1.2.0 + resolution: "he@npm:1.2.0" + bin: + he: bin/he + checksum: 10c0/a27d478befe3c8192f006cdd0639a66798979dfa6e2125c6ac582a19a5ebfec62ad83e8382e6036170d873f46e4536a7e795bf8b95bf7c247f4cc0825ccc8c17 + languageName: node + linkType: hard + +"history@npm:^4.9.0": + version: 4.10.1 + resolution: "history@npm:4.10.1" + dependencies: + "@babel/runtime": "npm:^7.1.2" + loose-envify: "npm:^1.2.0" + resolve-pathname: "npm:^3.0.0" + tiny-invariant: "npm:^1.0.2" + tiny-warning: "npm:^1.0.0" + value-equal: "npm:^1.0.1" + checksum: 10c0/35377694e4f10f2cf056a9cb1a8ee083e04e4b4717a63baeee4afd565658a62c7e73700bf9e82aa53dbe1ec94e0a25a83c080d63bad8ee6b274a98d2fbc5ed4c + languageName: node + linkType: hard + +"hoist-non-react-statics@npm:^3.1.0": + version: 3.3.2 + resolution: "hoist-non-react-statics@npm:3.3.2" + dependencies: + react-is: "npm:^16.7.0" + checksum: 10c0/fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74 + languageName: node + linkType: hard + +"hpack.js@npm:^2.1.6": + version: 2.1.6 + resolution: "hpack.js@npm:2.1.6" + dependencies: + inherits: "npm:^2.0.1" + obuf: "npm:^1.0.0" + readable-stream: "npm:^2.0.1" + wbuf: "npm:^1.1.0" + checksum: 10c0/55b9e824430bab82a19d079cb6e33042d7d0640325678c9917fcc020c61d8a08ca671b6c942c7f0aae9bb6e4b67ffb50734a72f9e21d66407c3138c1983b70f0 + languageName: node + linkType: hard + +"html-escaper@npm:^2.0.2": + version: 2.0.2 + resolution: "html-escaper@npm:2.0.2" + checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 + languageName: node + linkType: hard + +"html-minifier-terser@npm:^6.0.2": + version: 6.1.0 + resolution: "html-minifier-terser@npm:6.1.0" + dependencies: + camel-case: "npm:^4.1.2" + clean-css: "npm:^5.2.2" + commander: "npm:^8.3.0" + he: "npm:^1.2.0" + param-case: "npm:^3.0.4" + relateurl: "npm:^0.2.7" + terser: "npm:^5.10.0" + bin: + html-minifier-terser: cli.js + checksum: 10c0/1aa4e4f01cf7149e3ac5ea84fb7a1adab86da40d38d77a6fff42852b5ee3daccb78b615df97264e3a6a5c33e57f0c77f471d607ca1e1debd1dab9b58286f4b5a + languageName: node + linkType: hard + +"html-minifier-terser@npm:^7.2.0": + version: 7.2.0 + resolution: "html-minifier-terser@npm:7.2.0" + dependencies: + camel-case: "npm:^4.1.2" + clean-css: "npm:~5.3.2" + commander: "npm:^10.0.0" + entities: "npm:^4.4.0" + param-case: "npm:^3.0.4" + relateurl: "npm:^0.2.7" + terser: "npm:^5.15.1" + bin: + html-minifier-terser: cli.js + checksum: 10c0/ffc97c17299d9ec30e17269781b816ea2fc411a9206fc9e768be8f2decb1ea1470892809babb23bb4e3ab1f64d606d97e1803bf526ae3af71edc0fd3070b94b9 + languageName: node + linkType: hard + +"html-rewriter-wasm@npm:^0.3.2": + version: 0.3.2 + resolution: "html-rewriter-wasm@npm:0.3.2" + checksum: 10c0/6933f55fd153449f7d7e114c45e76eeca8ec92682464a0c83a706167db2e9e00156adccde6b1980c5c89876c0635bcf8f91955b882ea2dd2cede5941fc26384d + languageName: node + linkType: hard + +"html-tags@npm:^3.3.1": + version: 3.3.1 + resolution: "html-tags@npm:3.3.1" + checksum: 10c0/680165e12baa51bad7397452d247dbcc5a5c29dac0e6754b1187eee3bf26f514bc1907a431dd2f7eb56207611ae595ee76a0acc8eaa0d931e72c791dd6463d79 + languageName: node + linkType: hard + +"html-void-elements@npm:^3.0.0": + version: 3.0.0 + resolution: "html-void-elements@npm:3.0.0" + checksum: 10c0/a8b9ec5db23b7c8053876dad73a0336183e6162bf6d2677376d8b38d654fdc59ba74fdd12f8812688f7db6fad451210c91b300e472afc0909224e0a44c8610d2 + languageName: node + linkType: hard + +"html-webpack-plugin@npm:^5.6.0": + version: 5.6.3 + resolution: "html-webpack-plugin@npm:5.6.3" + dependencies: + "@types/html-minifier-terser": "npm:^6.0.0" + html-minifier-terser: "npm:^6.0.2" + lodash: "npm:^4.17.21" + pretty-error: "npm:^4.0.0" + tapable: "npm:^2.0.0" + peerDependencies: + "@rspack/core": 0.x || 1.x + webpack: ^5.20.0 + peerDependenciesMeta: + "@rspack/core": + optional: true + webpack: + optional: true + checksum: 10c0/25a21f83a8823d3711396dd8050bc0080c0ae55537352d432903eff58a7d9838fc811e3c26462419036190720357e67c7977efd106fb9a252770632824f0cc25 + languageName: node + linkType: hard + +"htmlparser2@npm:^6.1.0": + version: 6.1.0 + resolution: "htmlparser2@npm:6.1.0" + dependencies: + domelementtype: "npm:^2.0.1" + domhandler: "npm:^4.0.0" + domutils: "npm:^2.5.2" + entities: "npm:^2.0.0" + checksum: 10c0/3058499c95634f04dc66be8c2e0927cd86799413b2d6989d8ae542ca4dbf5fa948695d02c27d573acf44843af977aec6d9a7bdd0f6faa6b2d99e2a729b2a31b6 + languageName: node + linkType: hard + +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + entities: "npm:^4.4.0" + checksum: 10c0/609cca85886d0bf2c9a5db8c6926a89f3764596877492e2caa7a25a789af4065bc6ee2cdc81807fe6b1d03a87bf8a373b5a754528a4cc05146b713c20575aab4 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc + languageName: node + linkType: hard + +"http-deceiver@npm:^1.2.7": + version: 1.2.7 + resolution: "http-deceiver@npm:1.2.7" + checksum: 10c0/8bb9b716f5fc55f54a451da7f49b9c695c3e45498a789634daec26b61e4add7c85613a4a9e53726c39d09de7a163891ecd6eb5809adb64500a840fd86fe81d03 + languageName: node + linkType: hard + +"http-errors@npm:~1.8.0": + version: 1.8.1 + resolution: "http-errors@npm:1.8.1" + dependencies: + depd: "npm:~1.1.2" + inherits: "npm:2.0.4" + setprototypeof: "npm:1.2.0" + statuses: "npm:>= 1.5.0 < 2" + toidentifier: "npm:1.0.1" + checksum: 10c0/f01aeecd76260a6fe7f08e192fcbe9b2f39ed20fc717b852669a69930167053b01790998275c6297d44f435cf0e30edd50c05223d1bec9bc484e6cf35b2d6f43 + languageName: node + linkType: hard + +"http-errors@npm:~2.0.0, http-errors@npm:~2.0.1": + version: 2.0.1 + resolution: "http-errors@npm:2.0.1" + dependencies: + depd: "npm:~2.0.0" + inherits: "npm:~2.0.4" + setprototypeof: "npm:~1.2.0" + statuses: "npm:~2.0.2" + toidentifier: "npm:~1.0.1" + checksum: 10c0/fb38906cef4f5c83952d97661fe14dc156cb59fe54812a42cd448fa57b5c5dfcb38a40a916957737bd6b87aab257c0648d63eb5b6a9ca9f548e105b6072712d4 + languageName: node + linkType: hard + +"http-parser-js@npm:>=0.5.1": + version: 0.5.10 + resolution: "http-parser-js@npm:0.5.10" + checksum: 10c0/8bbcf1832a8d70b2bd515270112116333add88738a2cc05bfb94ba6bde3be4b33efee5611584113818d2bcf654fdc335b652503be5a6b4c0b95e46f214187d93 + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + +"http-proxy-middleware@npm:^2.0.9": + version: 2.0.9 + resolution: "http-proxy-middleware@npm:2.0.9" + dependencies: + "@types/http-proxy": "npm:^1.17.8" + http-proxy: "npm:^1.18.1" + is-glob: "npm:^4.0.1" + is-plain-obj: "npm:^3.0.0" + micromatch: "npm:^4.0.2" + peerDependencies: + "@types/express": ^4.17.13 + peerDependenciesMeta: + "@types/express": + optional: true + checksum: 10c0/8e9032af625f7c9f2f0d318f6cdb14eb725cc16ffe7b4ccccea25cf591fa819bb7c3bb579e0b543e0ae9c73059b505a6d728290c757bff27bae526a6ed11c05e + languageName: node + linkType: hard + +"http-proxy@npm:^1.18.1": + version: 1.18.1 + resolution: "http-proxy@npm:1.18.1" + dependencies: + eventemitter3: "npm:^4.0.0" + follow-redirects: "npm:^1.0.0" + requires-port: "npm:^1.0.0" + checksum: 10c0/148dfa700a03fb421e383aaaf88ac1d94521dfc34072f6c59770528c65250983c2e4ec996f2f03aa9f3fe46cd1270a593126068319311e3e8d9e610a37533e94 + languageName: node + linkType: hard + +"http2-wrapper@npm:^2.1.10": + version: 2.2.1 + resolution: "http2-wrapper@npm:2.2.1" + dependencies: + quick-lru: "npm:^5.1.1" + resolve-alpn: "npm:^1.2.0" + checksum: 10c0/7207201d3c6e53e72e510c9b8912e4f3e468d3ecc0cf3bf52682f2aac9cd99358b896d1da4467380adc151cf97c412bedc59dc13dae90c523f42053a7449eedb + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:4" + checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac + languageName: node + linkType: hard + +"human-signals@npm:^2.1.0": + version: 2.1.0 + resolution: "human-signals@npm:2.1.0" + checksum: 10c0/695edb3edfcfe9c8b52a76926cd31b36978782062c0ed9b1192b36bebc75c4c87c82e178dfcb0ed0fc27ca59d434198aac0bd0be18f5781ded775604db22304a + languageName: node + linkType: hard + +"hyperdyperid@npm:^1.2.0": + version: 1.2.0 + resolution: "hyperdyperid@npm:1.2.0" + checksum: 10c0/885ba3177c7181d315a856ee9c0005ff8eb5dcb1ce9e9d61be70987895d934d84686c37c981cceeb53216d4c9c15c1cc25f1804e84cc6a74a16993c5d7fd0893 + languageName: node + linkType: hard + +"iconv-lite@npm:0.6": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + languageName: node + linkType: hard + +"iconv-lite@npm:^0.7.2": + version: 0.7.2 + resolution: "iconv-lite@npm:0.7.2" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/3c228920f3bd307f56bf8363706a776f4a060eb042f131cd23855ceca962951b264d0997ab38a1ad340e1c5df8499ed26e1f4f0db6b2a2ad9befaff22f14b722 + languageName: node + linkType: hard + +"iconv-lite@npm:~0.4.24": + version: 0.4.24 + resolution: "iconv-lite@npm:0.4.24" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3" + checksum: 10c0/c6886a24cc00f2a059767440ec1bc00d334a89f250db8e0f7feb4961c8727118457e27c495ba94d082e51d3baca378726cd110aaf7ded8b9bbfd6a44760cf1d4 + languageName: node + linkType: hard + +"icss-utils@npm:^5.0.0, icss-utils@npm:^5.1.0": + version: 5.1.0 + resolution: "icss-utils@npm:5.1.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 10c0/39c92936fabd23169c8611d2b5cc39e39d10b19b0d223352f20a7579f75b39d5f786114a6b8fc62bee8c5fed59ba9e0d38f7219a4db383e324fb3061664b043d + languageName: node + linkType: hard + +"ignore@npm:^5.1.8, ignore@npm:^5.2.0, ignore@npm:^5.2.4": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 + languageName: node + linkType: hard + +"image-size@npm:^2.0.2": + version: 2.0.2 + resolution: "image-size@npm:2.0.2" + bin: + image-size: bin/image-size.js + checksum: 10c0/f09dd0f7cf8511cd20e4f756bdb5a7cb6d2240de3323f41bde266bed8373392a293892bf12e907e2995f52833fd88dd27cf6b1a52ab93968afc716cb78cd7b79 + languageName: node + linkType: hard + +"import-fresh@npm:^3.3.0": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" + dependencies: + parent-module: "npm:^1.0.0" + resolve-from: "npm:^4.0.0" + checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec + languageName: node + linkType: hard + +"import-lazy@npm:^4.0.0": + version: 4.0.0 + resolution: "import-lazy@npm:4.0.0" + checksum: 10c0/a3520313e2c31f25c0b06aa66d167f329832b68a4f957d7c9daf6e0fa41822b6e84948191648b9b9d8ca82f94740cdf15eecf2401a5b42cd1c33fd84f2225cca + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 + languageName: node + linkType: hard + +"indent-string@npm:^4.0.0": + version: 4.0.0 + resolution: "indent-string@npm:4.0.0" + checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f + languageName: node + linkType: hard + +"infima@npm:0.2.0-alpha.45": + version: 0.2.0-alpha.45 + resolution: "infima@npm:0.2.0-alpha.45" + checksum: 10c0/b50d103f6864687742067414d09392ccf3be363cf27503925a943ff56bb2392118e2bfdb6b2f89933417015e1770e58f81b2b0caf823f2adfb67f32b1702d469 + languageName: node + linkType: hard + +"inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:~2.0.3, inherits@npm:~2.0.4": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 + languageName: node + linkType: hard + +"ini@npm:2.0.0": + version: 2.0.0 + resolution: "ini@npm:2.0.0" + checksum: 10c0/2e0c8f386369139029da87819438b20a1ff3fe58372d93fb1a86e9d9344125ace3a806b8ec4eb160a46e64cbc422fe68251869441676af49b7fc441af2389c25 + languageName: node + linkType: hard + +"ini@npm:^1.3.4, ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a + languageName: node + linkType: hard + +"inline-style-parser@npm:0.2.4": + version: 0.2.4 + resolution: "inline-style-parser@npm:0.2.4" + checksum: 10c0/ddc0b210eaa03e0f98d677b9836242c583c7c6051e84ce0e704ae4626e7871c5b78f8e30853480218b446355745775df318d4f82d33087ff7e393245efa9a881 + languageName: node + linkType: hard + +"internmap@npm:1 - 2": + version: 2.0.3 + resolution: "internmap@npm:2.0.3" + checksum: 10c0/8cedd57f07bbc22501516fbfc70447f0c6812871d471096fad9ea603516eacc2137b633633daf432c029712df0baefd793686388ddf5737e3ea15074b877f7ed + languageName: node + linkType: hard + +"internmap@npm:^1.0.0": + version: 1.0.1 + resolution: "internmap@npm:1.0.1" + checksum: 10c0/60942be815ca19da643b6d4f23bd0bf4e8c97abbd080fb963fe67583b60bdfb3530448ad4486bae40810e92317bded9995cc31411218acc750d72cd4e8646eee + languageName: node + linkType: hard + +"invariant@npm:^2.2.4": + version: 2.2.4 + resolution: "invariant@npm:2.2.4" + dependencies: + loose-envify: "npm:^1.0.0" + checksum: 10c0/5af133a917c0bcf65e84e7f23e779e7abc1cd49cb7fdc62d00d1de74b0d8c1b5ee74ac7766099fb3be1b05b26dfc67bab76a17030d2fe7ea2eef867434362dfc + languageName: node + linkType: hard + +"ip-address@npm:^10.0.1": + version: 10.1.0 + resolution: "ip-address@npm:10.1.0" + checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 + languageName: node + linkType: hard + +"ipaddr.js@npm:1.9.1": + version: 1.9.1 + resolution: "ipaddr.js@npm:1.9.1" + checksum: 10c0/0486e775047971d3fdb5fb4f063829bac45af299ae0b82dcf3afa2145338e08290563a2a70f34b732d795ecc8311902e541a8530eeb30d75860a78ff4e94ce2a + languageName: node + linkType: hard + +"ipaddr.js@npm:^2.1.0": + version: 2.3.0 + resolution: "ipaddr.js@npm:2.3.0" + checksum: 10c0/084bab99e2f6875d7a62adc3325e1c64b038a12c9521e35fb967b5e263a8b3afb1b8884dd77c276092331f5d63298b767491e10997ef147c62da01b143780bbd + languageName: node + linkType: hard + +"is-alphabetical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphabetical@npm:2.0.1" + checksum: 10c0/932367456f17237533fd1fc9fe179df77957271020b83ea31da50e5cc472d35ef6b5fb8147453274ffd251134472ce24eb6f8d8398d96dee98237cdb81a6c9a7 + languageName: node + linkType: hard + +"is-alphanumerical@npm:^2.0.0": + version: 2.0.1 + resolution: "is-alphanumerical@npm:2.0.1" + dependencies: + is-alphabetical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + checksum: 10c0/4b35c42b18e40d41378293f82a3ecd9de77049b476f748db5697c297f686e1e05b072a6aaae2d16f54d2a57f85b00cbbe755c75f6d583d1c77d6657bd0feb5a2 + languageName: node + linkType: hard + +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 + languageName: node + linkType: hard + +"is-binary-path@npm:~2.1.0": + version: 2.1.0 + resolution: "is-binary-path@npm:2.1.0" + dependencies: + binary-extensions: "npm:^2.0.0" + checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 + languageName: node + linkType: hard + +"is-ci@npm:^3.0.1": + version: 3.0.1 + resolution: "is-ci@npm:3.0.1" + dependencies: + ci-info: "npm:^3.2.0" + bin: + is-ci: bin.js + checksum: 10c0/0e81caa62f4520d4088a5bef6d6337d773828a88610346c4b1119fb50c842587ed8bef1e5d9a656835a599e7209405b5761ddf2339668f2d0f4e889a92fe6051 + languageName: node + linkType: hard + +"is-core-module@npm:^2.16.1": + version: 2.16.1 + resolution: "is-core-module@npm:2.16.1" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd + languageName: node + linkType: hard + +"is-decimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-decimal@npm:2.0.1" + checksum: 10c0/8085dd66f7d82f9de818fba48b9e9c0429cb4291824e6c5f2622e96b9680b54a07a624cfc663b24148b8e853c62a1c987cfe8b0b5a13f5156991afaf6736e334 + languageName: node + linkType: hard + +"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": + version: 2.2.1 + resolution: "is-docker@npm:2.2.1" + bin: + is-docker: cli.js + checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc + languageName: node + linkType: hard + +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: 10c0/d2c4f8e6d3e34df75a5defd44991b6068afad4835bb783b902fa12d13ebdb8f41b2a199dcb0b5ed2cb78bfee9e4c0bbdb69c2d9646f4106464674d3e697a5856 + languageName: node + linkType: hard + +"is-extendable@npm:^0.1.0": + version: 0.1.1 + resolution: "is-extendable@npm:0.1.1" + checksum: 10c0/dd5ca3994a28e1740d1e25192e66eed128e0b2ff161a7ea348e87ae4f616554b486854de423877a2a2c171d5f7cd6e8093b91f54533bc88a59ee1c9838c43879 + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc + languageName: node + linkType: hard + +"is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a + languageName: node + linkType: hard + +"is-hexadecimal@npm:^2.0.0": + version: 2.0.1 + resolution: "is-hexadecimal@npm:2.0.1" + checksum: 10c0/3eb60fe2f1e2bbc760b927dcad4d51eaa0c60138cf7fc671803f66353ad90c301605b502c7ea4c6bb0548e1c7e79dfd37b73b632652e3b76030bba603a7e9626 + languageName: node + linkType: hard + +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: "npm:^3.0.0" + bin: + is-inside-container: cli.js + checksum: 10c0/a8efb0e84f6197e6ff5c64c52890fa9acb49b7b74fed4da7c95383965da6f0fa592b4dbd5e38a79f87fc108196937acdbcd758fcefc9b140e479b39ce1fcd1cd + languageName: node + linkType: hard + +"is-installed-globally@npm:^0.4.0": + version: 0.4.0 + resolution: "is-installed-globally@npm:0.4.0" + dependencies: + global-dirs: "npm:^3.0.0" + is-path-inside: "npm:^3.0.2" + checksum: 10c0/f3e6220ee5824b845c9ed0d4b42c24272701f1f9926936e30c0e676254ca5b34d1b92c6205cae11b283776f9529212c0cdabb20ec280a6451677d6493ca9c22d + languageName: node + linkType: hard + +"is-network-error@npm:^1.0.0": + version: 1.3.1 + resolution: "is-network-error@npm:1.3.1" + checksum: 10c0/389b4a4cc6838bc5764c1d4ab8af11ec68c63825d53f7ce9f5a31aa4d2c9e5d33896c052f4c44100911e8db47bcf854c4aae6c03d6b1d84700f7c6aa72d16693 + languageName: node + linkType: hard + +"is-npm@npm:^6.0.0": + version: 6.0.0 + resolution: "is-npm@npm:6.0.0" + checksum: 10c0/1f064c66325cba6e494783bee4e635caa2655aad7f853a0e045d086e0bb7d83d2d6cdf1745dc9a7c7c93dacbf816fbee1f8d9179b02d5d01674d4f92541dc0d9 + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 + languageName: node + linkType: hard + +"is-obj@npm:^1.0.1": + version: 1.0.1 + resolution: "is-obj@npm:1.0.1" + checksum: 10c0/5003acba0af7aa47dfe0760e545a89bbac89af37c12092c3efadc755372cdaec034f130e7a3653a59eb3c1843cfc72ca71eaf1a6c3bafe5a0bab3611a47f9945 + languageName: node + linkType: hard + +"is-obj@npm:^2.0.0": + version: 2.0.0 + resolution: "is-obj@npm:2.0.0" + checksum: 10c0/85044ed7ba8bd169e2c2af3a178cacb92a97aa75de9569d02efef7f443a824b5e153eba72b9ae3aca6f8ce81955271aa2dc7da67a8b720575d3e38104208cb4e + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.2": + version: 3.0.3 + resolution: "is-path-inside@npm:3.0.3" + checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 + languageName: node + linkType: hard + +"is-plain-obj@npm:^3.0.0": + version: 3.0.0 + resolution: "is-plain-obj@npm:3.0.0" + checksum: 10c0/8e6483bfb051d42ec9c704c0ede051a821c6b6f9a6c7a3e3b55aa855e00981b0580c8f3b1f5e2e62649b39179b1abfee35d6f8086d999bfaa32c1908d29b07bc + languageName: node + linkType: hard + +"is-plain-obj@npm:^4.0.0": + version: 4.1.0 + resolution: "is-plain-obj@npm:4.1.0" + checksum: 10c0/32130d651d71d9564dc88ba7e6fda0e91a1010a3694648e9f4f47bb6080438140696d3e3e15c741411d712e47ac9edc1a8a9de1fe76f3487b0d90be06ac9975e + languageName: node + linkType: hard + +"is-plain-object@npm:^2.0.4": + version: 2.0.4 + resolution: "is-plain-object@npm:2.0.4" + dependencies: + isobject: "npm:^3.0.1" + checksum: 10c0/f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 + languageName: node + linkType: hard + +"is-regexp@npm:^1.0.0": + version: 1.0.0 + resolution: "is-regexp@npm:1.0.0" + checksum: 10c0/34cacda1901e00f6e44879378f1d2fa96320ea956c1bec27713130aaf1d44f6e7bd963eed28945bfe37e600cb27df1cf5207302680dad8bdd27b9baff8ecf611 + languageName: node + linkType: hard + +"is-stream@npm:^2.0.0": + version: 2.0.1 + resolution: "is-stream@npm:2.0.1" + checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 + languageName: node + linkType: hard + +"is-typedarray@npm:^1.0.0": + version: 1.0.0 + resolution: "is-typedarray@npm:1.0.0" + checksum: 10c0/4c096275ba041a17a13cca33ac21c16bc4fd2d7d7eb94525e7cd2c2f2c1a3ab956e37622290642501ff4310601e413b675cf399ad6db49855527d2163b3eeeec + languageName: node + linkType: hard + +"is-wsl@npm:^2.2.0": + version: 2.2.0 + resolution: "is-wsl@npm:2.2.0" + dependencies: + is-docker: "npm:^2.0.0" + checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e + languageName: node + linkType: hard + +"is-wsl@npm:^3.1.0": + version: 3.1.1 + resolution: "is-wsl@npm:3.1.1" + dependencies: + is-inside-container: "npm:^1.0.0" + checksum: 10c0/7e5023522bfb8f27de4de960b0d82c4a8146c0bddb186529a3616d78b5bbbfc19ef0c5fc60d0b3a3cc0bf95a415fbdedc18454310ea3049587c879b07ace5107 + languageName: node + linkType: hard + +"is-yarn-global@npm:^0.4.0": + version: 0.4.1 + resolution: "is-yarn-global@npm:0.4.1" + checksum: 10c0/8ff66f33454614f8e913ad91cc4de0d88d519a46c1ed41b3f589da79504ed0fcfa304064fe3096dda9360c5f35aa210cb8e978fd36798f3118cb66a4de64d365 + languageName: node + linkType: hard + +"isarray@npm:0.0.1": + version: 0.0.1 + resolution: "isarray@npm:0.0.1" + checksum: 10c0/ed1e62da617f71fe348907c71743b5ed550448b455f8d269f89a7c7ddb8ae6e962de3dab6a74a237b06f5eb7f6ece7a45ada8ce96d87fe972926530f91ae3311 + languageName: node + linkType: hard + +"isarray@npm:~1.0.0": + version: 1.0.0 + resolution: "isarray@npm:1.0.0" + checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d + languageName: node + linkType: hard + +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce + languageName: node + linkType: hard + +"isobject@npm:^3.0.1": + version: 3.0.1 + resolution: "isobject@npm:3.0.1" + checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db + languageName: node + linkType: hard + +"jest-util@npm:^29.7.0": + version: 29.7.0 + resolution: "jest-util@npm:29.7.0" + dependencies: + "@jest/types": "npm:^29.6.3" + "@types/node": "npm:*" + chalk: "npm:^4.0.0" + ci-info: "npm:^3.2.0" + graceful-fs: "npm:^4.2.9" + picomatch: "npm:^2.2.3" + checksum: 10c0/bc55a8f49fdbb8f51baf31d2a4f312fb66c9db1483b82f602c9c990e659cdd7ec529c8e916d5a89452ecbcfae4949b21b40a7a59d4ffc0cd813a973ab08c8150 + languageName: node + linkType: hard + +"jest-worker@npm:^27.4.5": + version: 27.5.1 + resolution: "jest-worker@npm:27.5.1" + dependencies: + "@types/node": "npm:*" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.0.0" + checksum: 10c0/8c4737ffd03887b3c6768e4cc3ca0269c0336c1e4b1b120943958ddb035ed2a0fc6acab6dc99631720a3720af4e708ff84fb45382ad1e83c27946adf3623969b + languageName: node + linkType: hard + +"jest-worker@npm:^29.4.3": + version: 29.7.0 + resolution: "jest-worker@npm:29.7.0" + dependencies: + "@types/node": "npm:*" + jest-util: "npm:^29.7.0" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^8.0.0" + checksum: 10c0/5570a3a005b16f46c131968b8a5b56d291f9bbb85ff4217e31c80bd8a02e7de799e59a54b95ca28d5c302f248b54cbffde2d177c2f0f52ffcee7504c6eabf660 + languageName: node + linkType: hard + +"jiti@npm:^1.20.0": + version: 1.21.7 + resolution: "jiti@npm:1.21.7" + bin: + jiti: bin/jiti.js + checksum: 10c0/77b61989c758ff32407cdae8ddc77f85e18e1a13fc4977110dbd2e05fc761842f5f71bce684d9a01316e1c4263971315a111385759951080bbfe17cbb5de8f7a + languageName: node + linkType: hard + +"joi@npm:^17.9.2": + version: 17.13.3 + resolution: "joi@npm:17.13.3" + dependencies: + "@hapi/hoek": "npm:^9.3.0" + "@hapi/topo": "npm:^5.1.0" + "@sideway/address": "npm:^4.1.5" + "@sideway/formula": "npm:^3.0.1" + "@sideway/pinpoint": "npm:^2.0.0" + checksum: 10c0/9262aef1da3f1bec5b03caf50c46368899fe03b8ff26cbe3d53af4584dd1049079fc97230bbf1500b6149db7cc765b9ee45f0deb24bb6fc3fa06229d7148c17f + languageName: node + linkType: hard + +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + +"js-yaml@npm:^3.13.1": + version: 3.14.2 + resolution: "js-yaml@npm:3.14.2" + dependencies: + argparse: "npm:^1.0.7" + esprima: "npm:^4.0.0" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/3261f25912f5dd76605e5993d0a126c2b6c346311885d3c483706cd722efe34f697ea0331f654ce27c00a42b426e524518ec89d65ed02ea47df8ad26dcc8ce69 + languageName: node + linkType: hard + +"js-yaml@npm:^4.1.0": + version: 4.1.1 + resolution: "js-yaml@npm:4.1.1" + dependencies: + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7 + languageName: node + linkType: hard + +"jsesc@npm:^3.0.2, jsesc@npm:~3.1.0": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 + languageName: node + linkType: hard + +"json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce + languageName: node + linkType: hard + +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 + languageName: node + linkType: hard + +"json5@npm:^2.1.2, json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c + languageName: node + linkType: hard + +"jsonfile@npm:^6.0.1": + version: 6.1.0 + resolution: "jsonfile@npm:6.1.0" + dependencies: + graceful-fs: "npm:^4.1.6" + universalify: "npm:^2.0.0" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10c0/4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 + languageName: node + linkType: hard + +"katex@npm:^0.16.25": + version: 0.16.44 + resolution: "katex@npm:0.16.44" + dependencies: + commander: "npm:^8.3.0" + bin: + katex: cli.js + checksum: 10c0/f4466978dee30ba221457d864296225c9bec2efe0925a37b692e7736d67f05ebd99885bf0910f099cb34db9cce27df17910f89029bcfdcb78ea73524f9c33e11 + languageName: node + linkType: hard + +"keyv@npm:^4.5.3": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e + languageName: node + linkType: hard + +"khroma@npm:^2.1.0": + version: 2.1.0 + resolution: "khroma@npm:2.1.0" + checksum: 10c0/634d98753ff5d2540491cafeb708fc98de0d43f4e6795256d5c8f6e3ad77de93049ea41433928fda3697adf7bbe6fe27351858f6d23b78f8b5775ef314c59891 + languageName: node + linkType: hard + +"kind-of@npm:^6.0.0, kind-of@npm:^6.0.2": + version: 6.0.3 + resolution: "kind-of@npm:6.0.3" + checksum: 10c0/61cdff9623dabf3568b6445e93e31376bee1cdb93f8ba7033d86022c2a9b1791a1d9510e026e6465ebd701a6dd2f7b0808483ad8838341ac52f003f512e0b4c4 + languageName: node + linkType: hard + +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b + languageName: node + linkType: hard + +"kleur@npm:^4.1.4": + version: 4.1.5 + resolution: "kleur@npm:4.1.5" + checksum: 10c0/e9de6cb49657b6fa70ba2d1448fd3d691a5c4370d8f7bbf1c2f64c24d461270f2117e1b0afe8cb3114f13bbd8e51de158c2a224953960331904e636a5e4c0f2a + languageName: node + linkType: hard + +"langium@npm:^4.0.0": + version: 4.2.1 + resolution: "langium@npm:4.2.1" + dependencies: + chevrotain: "npm:~11.1.1" + chevrotain-allstar: "npm:~0.3.1" + vscode-languageserver: "npm:~9.0.1" + vscode-languageserver-textdocument: "npm:~1.0.11" + vscode-uri: "npm:~3.1.0" + checksum: 10c0/19ddf79cc3c435ec70f8eb50de255571711db7cea89d171cf80bc97e7ed73d4d0bb6b4215899df8369fa6d0e17f442f30af4ec2e9657041bf2f93be1310ba50a + languageName: node + linkType: hard + +"latest-version@npm:^7.0.0": + version: 7.0.0 + resolution: "latest-version@npm:7.0.0" + dependencies: + package-json: "npm:^8.1.0" + checksum: 10c0/68045f5e419e005c12e595ae19687dd88317dd0108b83a8773197876622c7e9d164fe43aacca4f434b2cba105c92848b89277f658eabc5d50e81fb743bbcddb1 + languageName: node + linkType: hard + +"launch-editor@npm:^2.6.1": + version: 2.13.2 + resolution: "launch-editor@npm:2.13.2" + dependencies: + picocolors: "npm:^1.1.1" + shell-quote: "npm:^1.8.3" + checksum: 10c0/5057fc8d3d0b0a92055b09b99192ffb5860b3e8a3f8ba56ef9b7f252fd78650d6b4182b725f4a1dcb8b04e350fa053874d819bb84362f2cfd6c3e84f556066dd + languageName: node + linkType: hard + +"layout-base@npm:^1.0.0": + version: 1.0.2 + resolution: "layout-base@npm:1.0.2" + checksum: 10c0/2a55d0460fd9f6ed53d7e301b9eb3dea19bda03815d616a40665ce6dc75c1f4d62e1ca19a897da1cfaf6de1b91de59cd6f2f79ba1258f3d7fccc7d46ca7f3337 + languageName: node + linkType: hard + +"layout-base@npm:^2.0.0": + version: 2.0.1 + resolution: "layout-base@npm:2.0.1" + checksum: 10c0/a44df9ef3cbff9916a10f616635e22b5787c89fa62b2fec6f99e8e6ee512c7cebd22668ce32dab5a83c934ba0a309c51a678aa0b40d70853de6c357893c0a88b + languageName: node + linkType: hard + +"leven@npm:^3.1.0": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 10c0/cd778ba3fbab0f4d0500b7e87d1f6e1f041507c56fdcd47e8256a3012c98aaee371d4c15e0a76e0386107af2d42e2b7466160a2d80688aaa03e66e49949f42df + languageName: node + linkType: hard + +"lightningcss-android-arm64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-android-arm64@npm:1.32.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-arm64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-darwin-arm64@npm:1.32.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-x64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-darwin-x64@npm:1.32.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-freebsd-x64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-freebsd-x64@npm:1.32.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-linux-arm-gnueabihf@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.32.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"lightningcss-linux-arm64-gnu@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm64-gnu@npm:1.32.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-arm64-musl@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm64-musl@npm:1.32.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-linux-x64-gnu@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-x64-gnu@npm:1.32.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-x64-musl@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-x64-musl@npm:1.32.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-win32-arm64-msvc@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-win32-arm64-msvc@npm:1.32.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-win32-x64-msvc@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-win32-x64-msvc@npm:1.32.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"lightningcss@npm:^1.27.0": + version: 1.32.0 + resolution: "lightningcss@npm:1.32.0" + dependencies: + detect-libc: "npm:^2.0.3" + lightningcss-android-arm64: "npm:1.32.0" + lightningcss-darwin-arm64: "npm:1.32.0" + lightningcss-darwin-x64: "npm:1.32.0" + lightningcss-freebsd-x64: "npm:1.32.0" + lightningcss-linux-arm-gnueabihf: "npm:1.32.0" + lightningcss-linux-arm64-gnu: "npm:1.32.0" + lightningcss-linux-arm64-musl: "npm:1.32.0" + lightningcss-linux-x64-gnu: "npm:1.32.0" + lightningcss-linux-x64-musl: "npm:1.32.0" + lightningcss-win32-arm64-msvc: "npm:1.32.0" + lightningcss-win32-x64-msvc: "npm:1.32.0" + dependenciesMeta: + lightningcss-android-arm64: + optional: true + lightningcss-darwin-arm64: + optional: true + lightningcss-darwin-x64: + optional: true + lightningcss-freebsd-x64: + optional: true + lightningcss-linux-arm-gnueabihf: + optional: true + lightningcss-linux-arm64-gnu: + optional: true + lightningcss-linux-arm64-musl: + optional: true + lightningcss-linux-x64-gnu: + optional: true + lightningcss-linux-x64-musl: + optional: true + lightningcss-win32-arm64-msvc: + optional: true + lightningcss-win32-x64-msvc: + optional: true + checksum: 10c0/70945bd55097af46fc9fab7f5ed09cd5869d85940a2acab7ee06d0117004a1d68155708a2d462531cea2fc3c67aefc9333a7068c80b0b78dd404c16838809e03 + languageName: node + linkType: hard + +"lilconfig@npm:^3.1.1": + version: 3.1.3 + resolution: "lilconfig@npm:3.1.3" + checksum: 10c0/f5604e7240c5c275743561442fbc5abf2a84ad94da0f5adc71d25e31fa8483048de3dcedcb7a44112a942fed305fd75841cdf6c9681c7f640c63f1049e9a5dcc + languageName: node + linkType: hard + +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d + languageName: node + linkType: hard + +"loader-runner@npm:^4.2.0": + version: 4.3.0 + resolution: "loader-runner@npm:4.3.0" + checksum: 10c0/a44d78aae0907a72f73966fe8b82d1439c8c485238bd5a864b1b9a2a3257832effa858790241e6b37876b5446a78889adf2fcc8dd897ce54c089ecc0a0ce0bf0 + languageName: node + linkType: hard + +"loader-utils@npm:^2.0.0": + version: 2.0.4 + resolution: "loader-utils@npm:2.0.4" + dependencies: + big.js: "npm:^5.2.2" + emojis-list: "npm:^3.0.0" + json5: "npm:^2.1.2" + checksum: 10c0/d5654a77f9d339ec2a03d88221a5a695f337bf71eb8dea031b3223420bb818964ba8ed0069145c19b095f6c8b8fd386e602a3fc7ca987042bd8bb1dcc90d7100 + languageName: node + linkType: hard + +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: "npm:^6.0.0" + checksum: 10c0/139e8a7fe11cfbd7f20db03923cacfa5db9e14fa14887ea121345597472b4a63c1a42a8a5187defeeff6acf98fd568da7382aa39682d38f0af27433953a97751 + languageName: node + linkType: hard + +"lodash-es@npm:4.17.23, lodash-es@npm:^4.17.21, lodash-es@npm:^4.17.23": + version: 4.17.23 + resolution: "lodash-es@npm:4.17.23" + checksum: 10c0/3150fb6660c14c7a6b5f23bd11597d884b140c0e862a17fdb415aaa5ef7741523182904a6b7929f04e5f60a11edb5a79499eb448734381c99ffb3c4734beeddd + languageName: node + linkType: hard + +"lodash.debounce@npm:^4.0.8": + version: 4.0.8 + resolution: "lodash.debounce@npm:4.0.8" + checksum: 10c0/762998a63e095412b6099b8290903e0a8ddcb353ac6e2e0f2d7e7d03abd4275fe3c689d88960eb90b0dde4f177554d51a690f22a343932ecbc50a5d111849987 + languageName: node + linkType: hard + +"lodash.memoize@npm:^4.1.2": + version: 4.1.2 + resolution: "lodash.memoize@npm:4.1.2" + checksum: 10c0/c8713e51eccc650422716a14cece1809cfe34bc5ab5e242b7f8b4e2241c2483697b971a604252807689b9dd69bfe3a98852e19a5b89d506b000b4187a1285df8 + languageName: node + linkType: hard + +"lodash.uniq@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.uniq@npm:4.5.0" + checksum: 10c0/262d400bb0952f112162a320cc4a75dea4f66078b9e7e3075ffbc9c6aa30b3e9df3cf20e7da7d566105e1ccf7804e4fbd7d804eee0b53de05d83f16ffbf41c5e + languageName: node + linkType: hard + +"lodash@npm:^4.17.20, lodash@npm:^4.17.21": + version: 4.17.21 + resolution: "lodash@npm:4.17.21" + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c + languageName: node + linkType: hard + +"longest-streak@npm:^3.0.0": + version: 3.1.0 + resolution: "longest-streak@npm:3.1.0" + checksum: 10c0/7c2f02d0454b52834d1bcedef79c557bd295ee71fdabb02d041ff3aa9da48a90b5df7c0409156dedbc4df9b65da18742652aaea4759d6ece01f08971af6a7eaa + languageName: node + linkType: hard + +"loose-envify@npm:^1.0.0, loose-envify@npm:^1.1.0, loose-envify@npm:^1.2.0, loose-envify@npm:^1.3.1, loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + languageName: node + linkType: hard + +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/3d925e090315cf7dc1caa358e0477e186ffa23947740e4314a7429b6e62d72742e0bbe7536a5ae56d19d7618ce998aba05caca53c2902bd5742fdca5fc57fd7b + languageName: node + linkType: hard + +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 10c0/ef62b9fa5690ab0a6e4ef40c94efce68e3ed124f583cc3be38b26ff871da0178a28b9a84ce0c209653bb25ca135520ab87fea7cd411a54ac4899cb2f30501430 + languageName: node + linkType: hard + +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": + version: 11.2.7 + resolution: "lru-cache@npm:11.2.7" + checksum: 10c0/549cdb59488baa617135fc12159cafb1a97f91079f35093bb3bcad72e849fc64ace636d244212c181dfdf1a99bbfa90757ff303f98561958ee4d0f885d9bd5f7 + languageName: node + linkType: hard + +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + languageName: node + linkType: hard + +"make-fetch-happen@npm:^15.0.0": + version: 15.0.5 + resolution: "make-fetch-happen@npm:15.0.5" + dependencies: + "@gar/promise-retry": "npm:^1.0.0" + "@npmcli/agent": "npm:^4.0.0" + "@npmcli/redact": "npm:^4.0.0" + cacache: "npm:^20.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^5.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^6.0.0" + ssri: "npm:^13.0.0" + checksum: 10c0/527580eb5e5476e6ad07a4e3bd017d13e935f4be815674b442081ae5a721c13d3af5715006619e6be79a85723067e047f83a0c9e699f41d8cec43609a8de4f7b + languageName: node + linkType: hard + +"markdown-extensions@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-extensions@npm:2.0.0" + checksum: 10c0/406139da2aa0d5ebad86195c8e8c02412f873c452b4c087ae7bc767af37956141be449998223bb379eea179b5fd38dfa610602b6f29c22ddab5d51e627a7e41d + languageName: node + linkType: hard + +"markdown-table@npm:^2.0.0": + version: 2.0.0 + resolution: "markdown-table@npm:2.0.0" + dependencies: + repeat-string: "npm:^1.0.0" + checksum: 10c0/f257e0781ea50eb946919df84bdee4ba61f983971b277a369ca7276f89740fd0e2749b9b187163a42df4c48682b71962d4007215ce3523480028f06c11ddc2e6 + languageName: node + linkType: hard + +"markdown-table@npm:^3.0.0": + version: 3.0.4 + resolution: "markdown-table@npm:3.0.4" + checksum: 10c0/1257b31827629a54c24a5030a3dac952256c559174c95ce3ef89bebd6bff0cb1444b1fd667b1a1bb53307f83278111505b3e26f0c4e7b731e0060d435d2d930b + languageName: node + linkType: hard + +"marked@npm:^16.3.0": + version: 16.4.2 + resolution: "marked@npm:16.4.2" + bin: + marked: bin/marked.js + checksum: 10c0/fc6051142172454f2023f3d6b31cca92879ec8e1b96457086a54c70354c74b00e1b6543a76a1fad6d399366f52b90a848f6ffb8e1d65a5baff87f3ba9b8f1847 + languageName: node + linkType: hard + +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f + languageName: node + linkType: hard + +"mdast-util-directive@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-directive@npm:3.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + parse-entities: "npm:^4.0.0" + stringify-entities: "npm:^4.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/596b093b940197cf43af4d0de12e82a1d2b1eb5add73dd16077aa80e0d0e1f208ea642c420726e59ccd352c193d6ecd5c106d6fab769f252617c75333f91a314 + languageName: node + linkType: hard + +"mdast-util-find-and-replace@npm:^3.0.0, mdast-util-find-and-replace@npm:^3.0.1": + version: 3.0.2 + resolution: "mdast-util-find-and-replace@npm:3.0.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + escape-string-regexp: "npm:^5.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/c8417a35605d567772ff5c1aa08363ff3010b0d60c8ea68c53cba09bf25492e3dd261560425c1756535f3b7107f62e7ff3857cdd8fb1e62d1b2cc2ea6e074ca2 + languageName: node + linkType: hard + +"mdast-util-from-markdown@npm:^2.0.0": + version: 2.0.2 + resolution: "mdast-util-from-markdown@npm:2.0.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark: "npm:^4.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/76eb2bd2c6f7a0318087c73376b8af6d7561c1e16654e7667e640f391341096c56142618fd0ff62f6d39e5ab4895898b9789c84cd7cec2874359a437a0e1ff15 + languageName: node + linkType: hard + +"mdast-util-frontmatter@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-frontmatter@npm:2.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + escape-string-regexp: "npm:^5.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + micromark-extension-frontmatter: "npm:^2.0.0" + checksum: 10c0/d9b0b70dd9c574cc0220d4e05dd8e9d86ac972a6a5af9e0c49c839b31cb750d4313445cfbbdf9264a7fbe3f8c8d920b45358b8500f4286e6b9dc830095b25b9a + languageName: node + linkType: hard + +"mdast-util-gfm-autolink-literal@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-gfm-autolink-literal@npm:2.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.0.0" + mdast-util-find-and-replace: "npm:^3.0.0" + micromark-util-character: "npm:^2.0.0" + checksum: 10c0/963cd22bd42aebdec7bdd0a527c9494d024d1ad0739c43dc040fee35bdfb5e29c22564330a7418a72b5eab51d47a6eff32bc0255ef3ccb5cebfe8970e91b81b6 + languageName: node + linkType: hard + +"mdast-util-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "mdast-util-gfm-footnote@npm:2.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + checksum: 10c0/8ab965ee6be3670d76ec0e95b2ba3101fc7444eec47564943ab483d96ac17d29da2a4e6146a2a288be30c21b48c4f3938a1e54b9a46fbdd321d49a5bc0077ed0 + languageName: node + linkType: hard + +"mdast-util-gfm-strikethrough@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-strikethrough@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/b053e93d62c7545019bd914271ea9e5667ad3b3b57d16dbf68e56fea39a7e19b4a345e781312714eb3d43fdd069ff7ee22a3ca7f6149dfa774554f19ce3ac056 + languageName: node + linkType: hard + +"mdast-util-gfm-table@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-table@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + markdown-table: "npm:^3.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/128af47c503a53bd1c79f20642561e54a510ad5e2db1e418d28fefaf1294ab839e6c838e341aef5d7e404f9170b9ca3d1d89605f234efafde93ee51174a6e31e + languageName: node + linkType: hard + +"mdast-util-gfm-task-list-item@npm:^2.0.0": + version: 2.0.0 + resolution: "mdast-util-gfm-task-list-item@npm:2.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/258d725288482b636c0a376c296431390c14b4f29588675297cb6580a8598ed311fc73ebc312acfca12cc8546f07a3a285a53a3b082712e2cbf5c190d677d834 + languageName: node + linkType: hard + +"mdast-util-gfm@npm:^3.0.0": + version: 3.1.0 + resolution: "mdast-util-gfm@npm:3.1.0" + dependencies: + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-gfm-autolink-literal: "npm:^2.0.0" + mdast-util-gfm-footnote: "npm:^2.0.0" + mdast-util-gfm-strikethrough: "npm:^2.0.0" + mdast-util-gfm-table: "npm:^2.0.0" + mdast-util-gfm-task-list-item: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4bedcfb6a20e39901c8772f0d2bb2d7a64ae87a54c13cbd92eec062cf470fbb68c2ad754e149af5b30794e2de61c978ab1de1ace03c0c40f443ca9b9b8044f81 + languageName: node + linkType: hard + +"mdast-util-mdx-expression@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdx-expression@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/9a1e57940f66431f10312fa239096efa7627f375e7933b5d3162c0b5c1712a72ac87447aff2b6838d2bbd5c1311b188718cc90b33b67dc67a88550e0a6ef6183 + languageName: node + linkType: hard + +"mdast-util-mdx-jsx@npm:^3.0.0": + version: 3.2.0 + resolution: "mdast-util-mdx-jsx@npm:3.2.0" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + ccount: "npm:^2.0.0" + devlop: "npm:^1.1.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + parse-entities: "npm:^4.0.0" + stringify-entities: "npm:^4.0.0" + unist-util-stringify-position: "npm:^4.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/3acadaf3b962254f7ad2990fed4729961dc0217ca31fde9917986e880843f3ecf3392b1f22d569235cacd180d50894ad266db7af598aedca69d330d33c7ac613 + languageName: node + linkType: hard + +"mdast-util-mdx@npm:^3.0.0": + version: 3.0.0 + resolution: "mdast-util-mdx@npm:3.0.0" + dependencies: + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-mdx-expression: "npm:^2.0.0" + mdast-util-mdx-jsx: "npm:^3.0.0" + mdast-util-mdxjs-esm: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/4faea13f77d6bc9aa64ee41a5e4779110b73444a17fda363df6ebe880ecfa58b321155b71f8801c3faa6d70d6222a32a00cbd6dbf5fad8db417f4688bc9c74e1 + languageName: node + linkType: hard + +"mdast-util-mdxjs-esm@npm:^2.0.0": + version: 2.0.1 + resolution: "mdast-util-mdxjs-esm@npm:2.0.1" + dependencies: + "@types/estree-jsx": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + checksum: 10c0/5bda92fc154141705af2b804a534d891f28dac6273186edf1a4c5e3f045d5b01dbcac7400d27aaf91b7e76e8dce007c7b2fdf136c11ea78206ad00bdf9db46bc + languageName: node + linkType: hard + +"mdast-util-phrasing@npm:^4.0.0": + version: 4.1.0 + resolution: "mdast-util-phrasing@npm:4.1.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/bf6c31d51349aa3d74603d5e5a312f59f3f65662ed16c58017169a5fb0f84ca98578f626c5ee9e4aa3e0a81c996db8717096705521bddb4a0185f98c12c9b42f + languageName: node + linkType: hard + +"mdast-util-to-hast@npm:^13.0.0": + version: 13.2.0 + resolution: "mdast-util-to-hast@npm:13.2.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + "@ungap/structured-clone": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + trim-lines: "npm:^3.0.0" + unist-util-position: "npm:^5.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/9ee58def9287df8350cbb6f83ced90f9c088d72d4153780ad37854f87144cadc6f27b20347073b285173b1649b0723ddf0b9c78158608a804dcacb6bda6e1816 + languageName: node + linkType: hard + +"mdast-util-to-markdown@npm:^2.0.0": + version: 2.1.2 + resolution: "mdast-util-to-markdown@npm:2.1.2" + dependencies: + "@types/mdast": "npm:^4.0.0" + "@types/unist": "npm:^3.0.0" + longest-streak: "npm:^3.0.0" + mdast-util-phrasing: "npm:^4.0.0" + mdast-util-to-string: "npm:^4.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-decode-string: "npm:^2.0.0" + unist-util-visit: "npm:^5.0.0" + zwitch: "npm:^2.0.0" + checksum: 10c0/4649722a6099f12e797bd8d6469b2b43b44e526b5182862d9c7766a3431caad2c0112929c538a972f214e63c015395e5d3f54bd81d9ac1b16e6d8baaf582f749 + languageName: node + linkType: hard + +"mdast-util-to-string@npm:^4.0.0": + version: 4.0.0 + resolution: "mdast-util-to-string@npm:4.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + checksum: 10c0/2d3c1af29bf3fe9c20f552ee9685af308002488f3b04b12fa66652c9718f66f41a32f8362aa2d770c3ff464c034860b41715902ada2306bb0a055146cef064d7 + languageName: node + linkType: hard + +"mdn-data@npm:2.0.28": + version: 2.0.28 + resolution: "mdn-data@npm:2.0.28" + checksum: 10c0/20000932bc4cd1cde9cba4e23f08cc4f816398af4c15ec81040ed25421d6bf07b5cf6b17095972577fb498988f40f4cb589e3169b9357bb436a12d8e07e5ea7b + languageName: node + linkType: hard + +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: 10c0/a2c472ea16cee3911ae742593715aa4c634eb3d4b9f1e6ada0902aa90df13dcbb7285d19435f3ff213ebaa3b2e0c0265c1eb0e3fb278fda7f8919f046a410cd9 + languageName: node + linkType: hard + +"media-typer@npm:0.3.0": + version: 0.3.0 + resolution: "media-typer@npm:0.3.0" + checksum: 10c0/d160f31246907e79fed398470285f21bafb45a62869dc469b1c8877f3f064f5eabc4bcc122f9479b8b605bc5c76187d7871cf84c4ee3ecd3e487da1993279928 + languageName: node + linkType: hard + +"memfs@npm:^4.43.1": + version: 4.57.1 + resolution: "memfs@npm:4.57.1" + dependencies: + "@jsonjoy.com/fs-core": "npm:4.57.1" + "@jsonjoy.com/fs-fsa": "npm:4.57.1" + "@jsonjoy.com/fs-node": "npm:4.57.1" + "@jsonjoy.com/fs-node-builtins": "npm:4.57.1" + "@jsonjoy.com/fs-node-to-fsa": "npm:4.57.1" + "@jsonjoy.com/fs-node-utils": "npm:4.57.1" + "@jsonjoy.com/fs-print": "npm:4.57.1" + "@jsonjoy.com/fs-snapshot": "npm:4.57.1" + "@jsonjoy.com/json-pack": "npm:^1.11.0" + "@jsonjoy.com/util": "npm:^1.9.0" + glob-to-regex.js: "npm:^1.0.1" + thingies: "npm:^2.5.0" + tree-dump: "npm:^1.0.3" + tslib: "npm:^2.0.0" + peerDependencies: + tslib: 2 + checksum: 10c0/5cbfcf07945a1eef8dacb31d2516f4adbc7989ef7f2ab57255a2ec69905010108b37b72fe132f8710a41d3a2eef2e5f1e7a63b54de6d272e34b579bbe8620ec9 + languageName: node + linkType: hard + +"merge-descriptors@npm:1.0.3": + version: 1.0.3 + resolution: "merge-descriptors@npm:1.0.3" + checksum: 10c0/866b7094afd9293b5ea5dcd82d71f80e51514bed33b4c4e9f516795dc366612a4cbb4dc94356e943a8a6914889a914530badff27f397191b9b75cda20b6bae93 + languageName: node + linkType: hard + +"merge-stream@npm:^2.0.0": + version: 2.0.0 + resolution: "merge-stream@npm:2.0.0" + checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 + languageName: node + linkType: hard + +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb + languageName: node + linkType: hard + +"mermaid@npm:>=11.6.0": + version: 11.13.0 + resolution: "mermaid@npm:11.13.0" + dependencies: + "@braintree/sanitize-url": "npm:^7.1.1" + "@iconify/utils": "npm:^3.0.2" + "@mermaid-js/parser": "npm:^1.0.1" + "@types/d3": "npm:^7.4.3" + "@upsetjs/venn.js": "npm:^2.0.0" + cytoscape: "npm:^3.33.1" + cytoscape-cose-bilkent: "npm:^4.1.0" + cytoscape-fcose: "npm:^2.2.0" + d3: "npm:^7.9.0" + d3-sankey: "npm:^0.12.3" + dagre-d3-es: "npm:7.0.14" + dayjs: "npm:^1.11.19" + dompurify: "npm:^3.3.1" + katex: "npm:^0.16.25" + khroma: "npm:^2.1.0" + lodash-es: "npm:^4.17.23" + marked: "npm:^16.3.0" + roughjs: "npm:^4.6.6" + stylis: "npm:^4.3.6" + ts-dedent: "npm:^2.2.0" + uuid: "npm:^11.1.0" + checksum: 10c0/9d908314d26cdb23d8fbb6a1183f3dc48440efa2cf25f31fd5f75ef3f72e973ef7c3b77768eb8399898035366d2b4a3a2bf0a0de9e35757848754935bf1288c0 + languageName: node + linkType: hard + +"methods@npm:~1.1.2": + version: 1.1.2 + resolution: "methods@npm:1.1.2" + checksum: 10c0/bdf7cc72ff0a33e3eede03708c08983c4d7a173f91348b4b1e4f47d4cdbf734433ad971e7d1e8c77247d9e5cd8adb81ea4c67b0a2db526b758b2233d7814b8b2 + languageName: node + linkType: hard + +"micromark-core-commonmark@npm:^2.0.0": + version: 2.0.3 + resolution: "micromark-core-commonmark@npm:2.0.3" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-destination: "npm:^2.0.0" + micromark-factory-label: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-factory-title: "npm:^2.0.0" + micromark-factory-whitespace: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-html-tag-name: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bd4a794fdc9e88dbdf59eaf1c507ddf26e5f7ddf4e52566c72239c0f1b66adbcd219ba2cd42350debbe24471434d5f5e50099d2b3f4e5762ca222ba8e5b549ee + languageName: node + linkType: hard + +"micromark-extension-directive@npm:^3.0.0": + version: 3.0.2 + resolution: "micromark-extension-directive@npm:3.0.2" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-factory-whitespace: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + parse-entities: "npm:^4.0.0" + checksum: 10c0/74137485375f02c1b640c2120dd6b9f6aa1e39ca5cd2463df7974ef1cc80203f5ef90448ce009973355a49ba169ef1441eabe57a36877c7b86373788612773da + languageName: node + linkType: hard + +"micromark-extension-frontmatter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-frontmatter@npm:2.0.0" + dependencies: + fault: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/7d0d876e598917a67146d29f536d6fbbf9d1b2401a77e2f64a3f80f934a63ff26fa94b01759c9185c24b2a91e4e6abf908fa7aa246f00a7778a6b37a17464300 + languageName: node + linkType: hard + +"micromark-extension-gfm-autolink-literal@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-autolink-literal@npm:2.1.0" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/84e6fbb84ea7c161dfa179665dc90d51116de4c28f3e958260c0423e5a745372b7dcbc87d3cde98213b532e6812f847eef5ae561c9397d7f7da1e59872ef3efe + languageName: node + linkType: hard + +"micromark-extension-gfm-footnote@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-footnote@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d172e4218968b7371b9321af5cde8c77423f73b233b2b0fcf3ff6fd6f61d2e0d52c49123a9b7910612478bf1f0d5e88c75a3990dd68f70f3933fe812b9f77edc + languageName: node + linkType: hard + +"micromark-extension-gfm-strikethrough@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-strikethrough@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-classify-character: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/ef4f248b865bdda71303b494671b7487808a340b25552b11ca6814dff3fcfaab9be8d294643060bbdb50f79313e4a686ab18b99cbe4d3ee8a4170fcd134234fb + languageName: node + linkType: hard + +"micromark-extension-gfm-table@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-extension-gfm-table@npm:2.1.1" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/04bc00e19b435fa0add62cd029d8b7eb6137522f77832186b1d5ef34544a9bd030c9cf85e92ddfcc5c31f6f0a58a43d4b96dba4fc21316037c734630ee12c912 + languageName: node + linkType: hard + +"micromark-extension-gfm-tagfilter@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-gfm-tagfilter@npm:2.0.0" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/995558843fff137ae4e46aecb878d8a4691cdf23527dcf1e2f0157d66786be9f7bea0109c52a8ef70e68e3f930af811828ba912239438e31a9cfb9981f44d34d + languageName: node + linkType: hard + +"micromark-extension-gfm-task-list-item@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-extension-gfm-task-list-item@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/78aa537d929e9309f076ba41e5edc99f78d6decd754b6734519ccbbfca8abd52e1c62df68d41a6ae64d2a3fc1646cea955893c79680b0b4385ced4c52296181f + languageName: node + linkType: hard + +"micromark-extension-gfm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-gfm@npm:3.0.0" + dependencies: + micromark-extension-gfm-autolink-literal: "npm:^2.0.0" + micromark-extension-gfm-footnote: "npm:^2.0.0" + micromark-extension-gfm-strikethrough: "npm:^2.0.0" + micromark-extension-gfm-table: "npm:^2.0.0" + micromark-extension-gfm-tagfilter: "npm:^2.0.0" + micromark-extension-gfm-task-list-item: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/970e28df6ebdd7c7249f52a0dda56e0566fbfa9ae56c8eeeb2445d77b6b89d44096880cd57a1c01e7821b1f4e31009109fbaca4e89731bff7b83b8519690e5d9 + languageName: node + linkType: hard + +"micromark-extension-mdx-expression@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdx-expression@npm:3.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-mdx-expression: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/fa799c594d8ff9ecbbd28e226959c4928590cfcddb60a926d9d859d00fc7acd25684b6f78dbe6a7f0830879a402b4a3628efd40bb9df1f5846e6d2b7332715f7 + languageName: node + linkType: hard + +"micromark-extension-mdx-jsx@npm:^3.0.0": + version: 3.0.1 + resolution: "micromark-extension-mdx-jsx@npm:3.0.1" + dependencies: + "@types/acorn": "npm:^4.0.0" + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + estree-util-is-identifier-name: "npm:^3.0.0" + micromark-factory-mdx-expression: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/11e65abd6b57bcf82665469cd1ff238b7cfc4ebb4942a0361df2dc7dd4ab133681b2bcbd4c388dddf6e4db062665d31efeb48cc844ee61c8d8de9d167cc946d8 + languageName: node + linkType: hard + +"micromark-extension-mdx-md@npm:^2.0.0": + version: 2.0.0 + resolution: "micromark-extension-mdx-md@npm:2.0.0" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bae91c61273de0e5ba80a980c03470e6cd9d7924aa936f46fbda15d780704d9386e945b99eda200e087b96254fbb4271a9545d5ce02676cd6ae67886a8bf82df + languageName: node + linkType: hard + +"micromark-extension-mdxjs-esm@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs-esm@npm:3.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/13e3f726495a960650cdedcba39198ace5bdc953ccb12c14d71fc9ed9bb88e40cc3ba9231e973f6984da3b3573e7ddb23ce409f7c16f52a8d57b608bf46c748d + languageName: node + linkType: hard + +"micromark-extension-mdxjs@npm:^3.0.0": + version: 3.0.0 + resolution: "micromark-extension-mdxjs@npm:3.0.0" + dependencies: + acorn: "npm:^8.0.0" + acorn-jsx: "npm:^5.0.0" + micromark-extension-mdx-expression: "npm:^3.0.0" + micromark-extension-mdx-jsx: "npm:^3.0.0" + micromark-extension-mdx-md: "npm:^2.0.0" + micromark-extension-mdxjs-esm: "npm:^3.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/fd84f036ddad0aabbc12e7f1b3e9dcfe31573bbc413c5ae903779ef0366d7a4c08193547e7ba75718c9f45654e45f52e575cfc2f23a5f89205a8a70d9a506aea + languageName: node + linkType: hard + +"micromark-factory-destination@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-destination@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bbafcf869cee5bf511161354cb87d61c142592fbecea051000ff116068dc85216e6d48519d147890b9ea5d7e2864a6341c0c09d9948c203bff624a80a476023c + languageName: node + linkType: hard + +"micromark-factory-label@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-label@npm:2.0.1" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/0137716b4ecb428114165505e94a2f18855c8bbea21b07a8b5ce514b32a595ed789d2b967125718fc44c4197ceaa48f6609d58807a68e778138d2e6b91b824e8 + languageName: node + linkType: hard + +"micromark-factory-mdx-expression@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-factory-mdx-expression@npm:2.0.2" + dependencies: + "@types/estree": "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-events-to-acorn: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unist-util-position-from-estree: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/87372775ae06478ab754efa058a5e382972f634c14f0afa303111037c30abf733fe65329a7e59cda969266e63f82104d9ed8ff9ada39189eab0651b6540ca64a + languageName: node + linkType: hard + +"micromark-factory-space@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-factory-space@npm:1.1.0" + dependencies: + micromark-util-character: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/3da81187ce003dd4178c7adc4674052fb8befc8f1a700ae4c8227755f38581a4ae963866dc4857488d62d1dc9837606c9f2f435fa1332f62a0f1c49b83c6a822 + languageName: node + linkType: hard + +"micromark-factory-space@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-space@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f9ed43f1c0652d8d898de0ac2be3f77f776fffe7dd96bdbba1e02d7ce33d3853c6ff5daa52568fc4fa32cdf3a62d86b85ead9b9189f7211e1d69ff2163c450fb + languageName: node + linkType: hard + +"micromark-factory-title@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-title@npm:2.0.1" + dependencies: + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/e72fad8d6e88823514916890099a5af20b6a9178ccf78e7e5e05f4de99bb8797acb756257d7a3a57a53854cb0086bf8aab15b1a9e9db8982500dd2c9ff5948b6 + languageName: node + linkType: hard + +"micromark-factory-whitespace@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-factory-whitespace@npm:2.0.1" + dependencies: + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/20a1ec58698f24b766510a309b23a10175034fcf1551eaa9da3adcbed3e00cd53d1ebe5f030cf873f76a1cec3c34eb8c50cc227be3344caa9ed25d56cf611224 + languageName: node + linkType: hard + +"micromark-util-character@npm:^1.0.0, micromark-util-character@npm:^1.1.0": + version: 1.2.0 + resolution: "micromark-util-character@npm:1.2.0" + dependencies: + micromark-util-symbol: "npm:^1.0.0" + micromark-util-types: "npm:^1.0.0" + checksum: 10c0/3390a675a50731b58a8e5493cd802e190427f10fa782079b455b00f6b54e406e36882df7d4a3bd32b709f7a2c3735b4912597ebc1c0a99566a8d8d0b816e2cd4 + languageName: node + linkType: hard + +"micromark-util-character@npm:^2.0.0": + version: 2.1.1 + resolution: "micromark-util-character@npm:2.1.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/d3fe7a5e2c4060fc2a076f9ce699c82a2e87190a3946e1e5eea77f563869b504961f5668d9c9c014724db28ac32fa909070ea8b30c3a39bd0483cc6c04cc76a1 + languageName: node + linkType: hard + +"micromark-util-chunked@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-chunked@npm:2.0.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/b68c0c16fe8106949537bdcfe1be9cf36c0ccd3bc54c4007003cb0984c3750b6cdd0fd77d03f269a3382b85b0de58bde4f6eedbe7ecdf7244759112289b1ab56 + languageName: node + linkType: hard + +"micromark-util-classify-character@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-classify-character@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/8a02e59304005c475c332f581697e92e8c585bcd45d5d225a66c1c1b14ab5a8062705188c2ccec33cc998d33502514121478b2091feddbc751887fc9c290ed08 + languageName: node + linkType: hard + +"micromark-util-combine-extensions@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-combine-extensions@npm:2.0.1" + dependencies: + micromark-util-chunked: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/f15e282af24c8372cbb10b9b0b3e2c0aa681fea0ca323a44d6bc537dc1d9382c819c3689f14eaa000118f5a163245358ce6276b2cda9a84439cdb221f5d86ae7 + languageName: node + linkType: hard + +"micromark-util-decode-numeric-character-reference@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-decode-numeric-character-reference@npm:2.0.2" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/9c8a9f2c790e5593ffe513901c3a110e9ec8882a08f466da014112a25e5059b51551ca0aeb7ff494657d86eceb2f02ee556c6558b8d66aadc61eae4a240da0df + languageName: node + linkType: hard + +"micromark-util-decode-string@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-decode-string@npm:2.0.1" + dependencies: + decode-named-character-reference: "npm:^1.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/f24d75b2e5310be6e7b6dee532e0d17d3bf46996841d6295f2a9c87a2046fff4ab603c52ab9d7a7a6430a8b787b1574ae895849c603d262d1b22eef71736b5cb + languageName: node + linkType: hard + +"micromark-util-encode@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-encode@npm:2.0.1" + checksum: 10c0/b2b29f901093845da8a1bf997ea8b7f5e061ffdba85070dfe14b0197c48fda64ffcf82bfe53c90cf9dc185e69eef8c5d41cae3ba918b96bc279326921b59008a + languageName: node + linkType: hard + +"micromark-util-events-to-acorn@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-events-to-acorn@npm:2.0.2" + dependencies: + "@types/acorn": "npm:^4.0.0" + "@types/estree": "npm:^1.0.0" + "@types/unist": "npm:^3.0.0" + devlop: "npm:^1.0.0" + estree-util-visit: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/2bd2660a49efddb625e6adcabdc3384ae4c50c7a04270737270f4aab53d09e8253e6d2607cd947c4c77f8a9900278915babb240e61fd143dc5bab51d9fd50709 + languageName: node + linkType: hard + +"micromark-util-html-tag-name@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-html-tag-name@npm:2.0.1" + checksum: 10c0/ae80444db786fde908e9295f19a27a4aa304171852c77414516418650097b8afb401961c9edb09d677b06e97e8370cfa65638dde8438ebd41d60c0a8678b85b9 + languageName: node + linkType: hard + +"micromark-util-normalize-identifier@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-normalize-identifier@npm:2.0.1" + dependencies: + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/5299265fa360769fc499a89f40142f10a9d4a5c3dd8e6eac8a8ef3c2e4a6570e4c009cf75ea46dce5ee31c01f25587bde2f4a5cc0a935584ae86dd857f2babbd + languageName: node + linkType: hard + +"micromark-util-resolve-all@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-resolve-all@npm:2.0.1" + dependencies: + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bb6ca28764696bb479dc44a2d5b5fe003e7177aeae1d6b0d43f24cc223bab90234092d9c3ce4a4d2b8df095ccfd820537b10eb96bb7044d635f385d65a4c984a + languageName: node + linkType: hard + +"micromark-util-sanitize-uri@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-sanitize-uri@npm:2.0.1" + dependencies: + micromark-util-character: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + checksum: 10c0/60e92166e1870fd4f1961468c2651013ff760617342918e0e0c3c4e872433aa2e60c1e5a672bfe5d89dc98f742d6b33897585cf86ae002cda23e905a3c02527c + languageName: node + linkType: hard + +"micromark-util-subtokenize@npm:^2.0.0": + version: 2.1.0 + resolution: "micromark-util-subtokenize@npm:2.1.0" + dependencies: + devlop: "npm:^1.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/bee69eece4393308e657c293ba80d92ebcb637e5f55e21dcf9c3fa732b91a8eda8ac248d76ff375e675175bfadeae4712e5158ef97eef1111789da1ce7ab5067 + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^1.0.0, micromark-util-symbol@npm:^1.0.1": + version: 1.1.0 + resolution: "micromark-util-symbol@npm:1.1.0" + checksum: 10c0/10ceaed33a90e6bfd3a5d57053dbb53f437d4809cc11430b5a09479c0ba601577059be9286df4a7eae6e350a60a2575dc9fa9d9872b5b8d058c875e075c33803 + languageName: node + linkType: hard + +"micromark-util-symbol@npm:^2.0.0": + version: 2.0.1 + resolution: "micromark-util-symbol@npm:2.0.1" + checksum: 10c0/f2d1b207771e573232436618e78c5e46cd4b5c560dd4a6d63863d58018abbf49cb96ec69f7007471e51434c60de3c9268ef2bf46852f26ff4aacd10f9da16fe9 + languageName: node + linkType: hard + +"micromark-util-types@npm:^1.0.0": + version: 1.1.0 + resolution: "micromark-util-types@npm:1.1.0" + checksum: 10c0/a9749cb0a12a252ff536baabcb7012421b6fad4d91a5fdd80d7b33dc7b4c22e2d0c4637dfe5b902d00247fe6c9b01f4a24fce6b572b16ccaa4da90e6ce2a11e4 + languageName: node + linkType: hard + +"micromark-util-types@npm:^2.0.0": + version: 2.0.2 + resolution: "micromark-util-types@npm:2.0.2" + checksum: 10c0/c8c15b96c858db781c4393f55feec10004bf7df95487636c9a9f7209e51002a5cca6a047c5d2a5dc669ff92da20e57aaa881e81a268d9ccadb647f9dce305298 + languageName: node + linkType: hard + +"micromark@npm:^4.0.0": + version: 4.0.2 + resolution: "micromark@npm:4.0.2" + dependencies: + "@types/debug": "npm:^4.0.0" + debug: "npm:^4.0.0" + decode-named-character-reference: "npm:^1.0.0" + devlop: "npm:^1.0.0" + micromark-core-commonmark: "npm:^2.0.0" + micromark-factory-space: "npm:^2.0.0" + micromark-util-character: "npm:^2.0.0" + micromark-util-chunked: "npm:^2.0.0" + micromark-util-combine-extensions: "npm:^2.0.0" + micromark-util-decode-numeric-character-reference: "npm:^2.0.0" + micromark-util-encode: "npm:^2.0.0" + micromark-util-normalize-identifier: "npm:^2.0.0" + micromark-util-resolve-all: "npm:^2.0.0" + micromark-util-sanitize-uri: "npm:^2.0.0" + micromark-util-subtokenize: "npm:^2.0.0" + micromark-util-symbol: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + checksum: 10c0/07462287254219d6eda6eac8a3cebaff2994e0575499e7088027b825105e096e4f51e466b14b2a81b71933a3b6c48ee069049d87bc2c2127eee50d9cc69e8af6 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.2, micromatch@npm:^4.0.5, micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa + languageName: node + linkType: hard + +"mime-db@npm:>= 1.43.0 < 2, mime-db@npm:^1.54.0": + version: 1.54.0 + resolution: "mime-db@npm:1.54.0" + checksum: 10c0/8d907917bc2a90fa2df842cdf5dfeaf509adc15fe0531e07bb2f6ab15992416479015828d6a74200041c492e42cce3ebf78e5ce714388a0a538ea9c53eece284 + languageName: node + linkType: hard + +"mime-db@npm:~1.33.0": + version: 1.33.0 + resolution: "mime-db@npm:1.33.0" + checksum: 10c0/79172ce5468c8503b49dddfdddc18d3f5fe2599f9b5fe1bc321a8cbee14c96730fc6db22f907b23701b05b2936f865795f62ec3a78a7f3c8cb2450bb68c6763e + languageName: node + linkType: hard + +"mime-types@npm:2.1.18": + version: 2.1.18 + resolution: "mime-types@npm:2.1.18" + dependencies: + mime-db: "npm:~1.33.0" + checksum: 10c0/a96a8d12f4bb98bc7bfac6a8ccbd045f40368fc1030d9366050c3613825d3715d1c1f393e10a75a885d2cdc1a26cd6d5e11f3a2a0d5c4d361f00242139430a0f + languageName: node + linkType: hard + +"mime-types@npm:^2.1.27, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34, mime-types@npm:~2.1.35": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 + languageName: node + linkType: hard + +"mime-types@npm:^3.0.1": + version: 3.0.2 + resolution: "mime-types@npm:3.0.2" + dependencies: + mime-db: "npm:^1.54.0" + checksum: 10c0/35a0dd1035d14d185664f346efcdb72e93ef7a9b6e9ae808bd1f6358227010267fab52657b37562c80fc888ff76becb2b2938deb5e730818b7983bf8bd359767 + languageName: node + linkType: hard + +"mime@npm:1.6.0": + version: 1.6.0 + resolution: "mime@npm:1.6.0" + bin: + mime: cli.js + checksum: 10c0/b92cd0adc44888c7135a185bfd0dddc42c32606401c72896a842ae15da71eb88858f17669af41e498b463cd7eb998f7b48939a25b08374c7924a9c8a6f8a81b0 + languageName: node + linkType: hard + +"mimic-fn@npm:^2.1.0": + version: 2.1.0 + resolution: "mimic-fn@npm:2.1.0" + checksum: 10c0/b26f5479d7ec6cc2bce275a08f146cf78f5e7b661b18114e2506dd91ec7ec47e7a25bf4360e5438094db0560bcc868079fb3b1fb3892b833c1ecbf63f80c95a4 + languageName: node + linkType: hard + +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 + languageName: node + linkType: hard + +"mimic-response@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-response@npm:4.0.0" + checksum: 10c0/761d788d2668ae9292c489605ffd4fad220f442fbae6832adce5ebad086d691e906a6d5240c290293c7a11e99fbdbbef04abbbed498bf8699a4ee0f31315e3fb + languageName: node + linkType: hard + +"mini-css-extract-plugin@npm:^2.9.2": + version: 2.10.1 + resolution: "mini-css-extract-plugin@npm:2.10.1" + dependencies: + schema-utils: "npm:^4.0.0" + tapable: "npm:^2.2.1" + peerDependencies: + webpack: ^5.0.0 + checksum: 10c0/2e90dacdca5bc35862e601e6b3989673e498217c789c4bb270a35bbd22b4d6e85f091795d0324d5cda5a9e2aa2a8f1f3340b6db5a96d66ec208c627659bebb08 + languageName: node + linkType: hard + +"miniflare@npm:2.0.0-rc.5": + version: 2.0.0-rc.5 + resolution: "miniflare@npm:2.0.0-rc.5" + dependencies: + "@miniflare/cache": "npm:2.0.0-rc.5" + "@miniflare/cli-parser": "npm:2.0.0-rc.5" + "@miniflare/core": "npm:2.0.0-rc.5" + "@miniflare/durable-objects": "npm:2.0.0-rc.5" + "@miniflare/html-rewriter": "npm:2.0.0-rc.5" + "@miniflare/http-server": "npm:2.0.0-rc.5" + "@miniflare/kv": "npm:2.0.0-rc.5" + "@miniflare/runner-vm": "npm:2.0.0-rc.5" + "@miniflare/scheduler": "npm:2.0.0-rc.5" + "@miniflare/shared": "npm:2.0.0-rc.5" + "@miniflare/sites": "npm:2.0.0-rc.5" + "@miniflare/storage-file": "npm:2.0.0-rc.5" + "@miniflare/storage-memory": "npm:2.0.0-rc.5" + "@miniflare/watcher": "npm:2.0.0-rc.5" + "@miniflare/web-sockets": "npm:2.0.0-rc.5" + kleur: "npm:^4.1.4" + semiver: "npm:^1.1.0" + source-map-support: "npm:^0.5.20" + undici: "npm:^4.11.1" + peerDependencies: + "@miniflare/storage-redis": 2.0.0-rc.5 + cron-schedule: ^3.0.4 + ioredis: ^4.27.9 + peerDependenciesMeta: + "@miniflare/storage-redis": + optional: true + ioredis: + optional: true + bin: + miniflare: bootstrap.js + checksum: 10c0/c8d28ccd5e32b74eb228140f06f2345f7cf2b2e1fd1fae8f5949dfbadb5a46b5f9957d5acd20955697975ff3b43be5569f36d3ee37373900ef5e88258bae4284 + languageName: node + linkType: hard + +"minimalistic-assert@npm:^1.0.0": + version: 1.0.1 + resolution: "minimalistic-assert@npm:1.0.1" + checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd + languageName: node + linkType: hard + +"minimatch@npm:3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + languageName: node + linkType: hard + +"minimatch@npm:3.1.5": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 + languageName: node + linkType: hard + +"minimatch@npm:^10.2.2": + version: 10.2.4 + resolution: "minimatch@npm:10.2.4" + dependencies: + brace-expansion: "npm:^5.0.2" + checksum: 10c0/35f3dfb7b99b51efd46afd378486889f590e7efb10e0f6a10ba6800428cf65c9a8dedb74427d0570b318d749b543dc4e85f06d46d2858bc8cac7e1eb49a95945 + languageName: node + linkType: hard + +"minimist@npm:^1.2.0": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e + languageName: node + linkType: hard + +"minipass-fetch@npm:^5.0.0": + version: 5.0.2 + resolution: "minipass-fetch@npm:5.0.2" + dependencies: + iconv-lite: "npm:^0.7.2" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^2.0.0" + minizlib: "npm:^3.0.1" + dependenciesMeta: + iconv-lite: + optional: true + checksum: 10c0/ce4ab9f21cfabaead2097d95dd33f485af8072fbc6b19611bce694965393453a1639d641c2bcf1c48f2ea7d41ea7fab8278373f1d0bee4e63b0a5b2cdd0ef649 + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 + languageName: node + linkType: hard + +"minipass-sized@npm:^2.0.0": + version: 2.0.0 + resolution: "minipass-sized@npm:2.0.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/f9201696a6f6d68610d04c9c83e3d2e5cb9c026aae1c8cbf7e17f386105cb79c1bb088dbc21bf0b1eb4f3fb5df384fd1e7aa3bf1f33868c416ae8c8a92679db8 + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: "npm:^4.0.0" + checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c + languageName: node + linkType: hard + +"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb + languageName: node + linkType: hard + +"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: "npm:^7.1.2" + checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec + languageName: node + linkType: hard + +"mlly@npm:^1.7.4, mlly@npm:^1.8.0": + version: 1.8.2 + resolution: "mlly@npm:1.8.2" + dependencies: + acorn: "npm:^8.16.0" + pathe: "npm:^2.0.3" + pkg-types: "npm:^1.3.1" + ufo: "npm:^1.6.3" + checksum: 10c0/aa826683a6daddf2aef65f9c8142e362731cf8e415a5591faf92fd51040a76697e45ab6dbb7a3b38be74e0f8c464825a7eabe827750455c7472421953f5da733 + languageName: node + linkType: hard + +"mrmime@npm:^2.0.0": + version: 2.0.1 + resolution: "mrmime@npm:2.0.1" + checksum: 10c0/af05afd95af202fdd620422f976ad67dc18e6ee29beb03dd1ce950ea6ef664de378e44197246df4c7cdd73d47f2e7143a6e26e473084b9e4aa2095c0ad1e1761 + languageName: node + linkType: hard + +"ms@npm:2.0.0": + version: 2.0.0 + resolution: "ms@npm:2.0.0" + checksum: 10c0/f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d + languageName: node + linkType: hard + +"ms@npm:2.1.3, ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 + languageName: node + linkType: hard + +"multicast-dns@npm:^7.2.5": + version: 7.2.5 + resolution: "multicast-dns@npm:7.2.5" + dependencies: + dns-packet: "npm:^5.2.2" + thunky: "npm:^1.0.2" + bin: + multicast-dns: cli.js + checksum: 10c0/5120171d4bdb1577764c5afa96e413353bff530d1b37081cb29cccc747f989eb1baf40574fe8e27060fc1aef72b59c042f72b9b208413de33bcf411343c69057 + languageName: node + linkType: hard + +"mustache@npm:^4.2.0": + version: 4.2.0 + resolution: "mustache@npm:4.2.0" + bin: + mustache: bin/mustache + checksum: 10c0/1f8197e8a19e63645a786581d58c41df7853da26702dbc005193e2437c98ca49b255345c173d50c08fe4b4dbb363e53cb655ecc570791f8deb09887248dd34a2 + languageName: node + linkType: hard + +"nanoid@npm:^3.3.11": + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" + bin: + nanoid: bin/nanoid.cjs + checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b + languageName: node + linkType: hard + +"negotiator@npm:0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 + languageName: node + linkType: hard + +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b + languageName: node + linkType: hard + +"negotiator@npm:~0.6.4": + version: 0.6.4 + resolution: "negotiator@npm:0.6.4" + checksum: 10c0/3e677139c7fb7628a6f36335bf11a885a62c21d5390204590a1a214a5631fcbe5ea74ef6a610b60afe84b4d975cbe0566a23f20ee17c77c73e74b80032108dea + languageName: node + linkType: hard + +"neo-async@npm:^2.6.2": + version: 2.6.2 + resolution: "neo-async@npm:2.6.2" + checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d + languageName: node + linkType: hard + +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: "npm:^2.0.2" + tslib: "npm:^2.0.3" + checksum: 10c0/8ef545f0b3f8677c848f86ecbd42ca0ff3cd9dd71c158527b344c69ba14710d816d8489c746b6ca225e7b615108938a0bda0a54706f8c255933703ac1cf8e703 + languageName: node + linkType: hard + +"node-emoji@npm:^2.1.0": + version: 2.2.0 + resolution: "node-emoji@npm:2.2.0" + dependencies: + "@sindresorhus/is": "npm:^4.6.0" + char-regex: "npm:^1.0.2" + emojilib: "npm:^2.4.0" + skin-tone: "npm:^2.0.0" + checksum: 10c0/9525defbd90a82a2131758c2470203fa2a2faa8edd177147a8654a26307fe03594e52847ecbe2746d06cfc5c50acd12bd500f035350a7609e8217c9894c19aad + languageName: node + linkType: hard + +"node-forge@npm:^0.10.0": + version: 0.10.0 + resolution: "node-forge@npm:0.10.0" + checksum: 10c0/9cbf9ac8fc3889a5a46b0248f7238ee4014770bf31d22e04c0c7f04ed91c8be4584c5f534cdf6037e99f236c636c925cba960501ed2b850e077512e152760663 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 12.2.0 + resolution: "node-gyp@npm:12.2.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^15.0.0" + nopt: "npm:^9.0.0" + proc-log: "npm:^6.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.5.4" + tinyglobby: "npm:^0.2.12" + which: "npm:^6.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/3ed046746a5a7d90950cd8b0547332b06598443f31fe213ef4332a7174c7b7d259e1704835feda79b87d3f02e59d7791842aac60642ede4396ab25fdf0f8f759 + languageName: node + linkType: hard + +"node-releases@npm:^2.0.27": + version: 2.0.36 + resolution: "node-releases@npm:2.0.36" + checksum: 10c0/85d8d7f4b6248c8372831cbcc3829ce634cb2b01dbd85e55705cefc8a9eda4ce8121bd218b9629cf2579aef8a360541bad409f3925a35675c825b9471a49d7e9 + languageName: node + linkType: hard + +"node-releases@npm:^2.0.36": + version: 2.0.37 + resolution: "node-releases@npm:2.0.37" + checksum: 10c0/306df89190b3225d0cb001260de52f0befd225a782ec85311ce97b0aa3b2e22f5e4e4c00395c6dc9bc9ef440c64723f6205fe1e27d32b8dd1d140891fbadf901 + languageName: node + linkType: hard + +"nopt@npm:^9.0.0": + version: 9.0.0 + resolution: "nopt@npm:9.0.0" + dependencies: + abbrev: "npm:^4.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd + languageName: node + linkType: hard + +"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": + version: 3.0.0 + resolution: "normalize-path@npm:3.0.0" + checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 + languageName: node + linkType: hard + +"normalize-url@npm:^8.0.0": + version: 8.0.1 + resolution: "normalize-url@npm:8.0.1" + checksum: 10c0/eb439231c4b84430f187530e6fdac605c5048ef4ec556447a10c00a91fc69b52d8d8298d9d608e68d3e0f7dc2d812d3455edf425e0f215993667c3183bcab1ef + languageName: node + linkType: hard + +"npm-run-path@npm:^4.0.1": + version: 4.0.1 + resolution: "npm-run-path@npm:4.0.1" + dependencies: + path-key: "npm:^3.0.0" + checksum: 10c0/6f9353a95288f8455cf64cbeb707b28826a7f29690244c1e4bb61ec573256e021b6ad6651b394eb1ccfd00d6ec50147253aba2c5fe58a57ceb111fad62c519ac + languageName: node + linkType: hard + +"nprogress@npm:^0.2.0": + version: 0.2.0 + resolution: "nprogress@npm:0.2.0" + checksum: 10c0/eab9a923a1ad1eed71a455ecfbc358442dd9bcd71b9fa3fa1c67eddf5159360b182c218f76fca320c97541a1b45e19ced04e6dcb044a662244c5419f8ae9e821 + languageName: node + linkType: hard + +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: "npm:^1.0.0" + checksum: 10c0/5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479 + languageName: node + linkType: hard + +"null-loader@npm:^4.0.1": + version: 4.0.1 + resolution: "null-loader@npm:4.0.1" + dependencies: + loader-utils: "npm:^2.0.0" + schema-utils: "npm:^3.0.0" + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + checksum: 10c0/fe9a74a928c9ddc1eab7be0e4322516439562d6efd6feeb0f7c61777d4b79a6a8e5a6bc8133deb59408f3f423bdf84c154a88168154a583154e9e33d544b4d42 + languageName: node + linkType: hard + +"object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 + languageName: node + linkType: hard + +"object-inspect@npm:^1.13.3": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 + languageName: node + linkType: hard + +"object-keys@npm:^1.1.1": + version: 1.1.1 + resolution: "object-keys@npm:1.1.1" + checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d + languageName: node + linkType: hard + +"object.assign@npm:^4.1.0": + version: 4.1.7 + resolution: "object.assign@npm:4.1.7" + dependencies: + call-bind: "npm:^1.0.8" + call-bound: "npm:^1.0.3" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + has-symbols: "npm:^1.1.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc + languageName: node + linkType: hard + +"obuf@npm:^1.0.0, obuf@npm:^1.1.2": + version: 1.1.2 + resolution: "obuf@npm:1.1.2" + checksum: 10c0/520aaac7ea701618eacf000fc96ae458e20e13b0569845800fc582f81b386731ab22d55354b4915d58171db00e79cfcd09c1638c02f89577ef092b38c65b7d81 + languageName: node + linkType: hard + +"on-finished@npm:^2.4.1, on-finished@npm:~2.4.1": + version: 2.4.1 + resolution: "on-finished@npm:2.4.1" + dependencies: + ee-first: "npm:1.1.1" + checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 + languageName: node + linkType: hard + +"on-headers@npm:~1.1.0": + version: 1.1.0 + resolution: "on-headers@npm:1.1.0" + checksum: 10c0/2c3b6b0d68ec9adbd561dc2d61c9b14da8ac03d8a2f0fd9e97bdf0600c887d5d97f664ff3be6876cf40cda6e3c587d73a4745e10b426ac50c7664fc5a0dfc0a1 + languageName: node + linkType: hard + +"onetime@npm:^5.1.2": + version: 5.1.2 + resolution: "onetime@npm:5.1.2" + dependencies: + mimic-fn: "npm:^2.1.0" + checksum: 10c0/ffcef6fbb2692c3c40749f31ea2e22677a876daea92959b8a80b521d95cca7a668c884d8b2045d1d8ee7d56796aa405c405462af112a1477594cc63531baeb8f + languageName: node + linkType: hard + +"open@npm:^10.0.3": + version: 10.2.0 + resolution: "open@npm:10.2.0" + dependencies: + default-browser: "npm:^5.2.1" + define-lazy-prop: "npm:^3.0.0" + is-inside-container: "npm:^1.0.0" + wsl-utils: "npm:^0.1.0" + checksum: 10c0/5a36d0c1fd2f74ce553beb427ca8b8494b623fc22c6132d0c1688f246a375e24584ea0b44c67133d9ab774fa69be8e12fbe1ff12504b1142bd960fb09671948f + languageName: node + linkType: hard + +"open@npm:^8.4.0": + version: 8.4.2 + resolution: "open@npm:8.4.2" + dependencies: + define-lazy-prop: "npm:^2.0.0" + is-docker: "npm:^2.1.1" + is-wsl: "npm:^2.2.0" + checksum: 10c0/bb6b3a58401dacdb0aad14360626faf3fb7fba4b77816b373495988b724fb48941cad80c1b65d62bb31a17609b2cd91c41a181602caea597ca80dfbcc27e84c9 + languageName: node + linkType: hard + +"opener@npm:^1.5.2": + version: 1.5.2 + resolution: "opener@npm:1.5.2" + bin: + opener: bin/opener-bin.js + checksum: 10c0/dd56256ab0cf796585617bc28e06e058adf09211781e70b264c76a1dbe16e90f868c974e5bf5309c93469157c7d14b89c35dc53fe7293b0e40b4d2f92073bc79 + languageName: node + linkType: hard + +"p-cancelable@npm:^3.0.0": + version: 3.0.0 + resolution: "p-cancelable@npm:3.0.0" + checksum: 10c0/948fd4f8e87b956d9afc2c6c7392de9113dac817cb1cecf4143f7a3d4c57ab5673614a80be3aba91ceec5e4b69fd8c869852d7e8048bc3d9273c4c36ce14b9aa + languageName: node + linkType: hard + +"p-finally@npm:^1.0.0": + version: 1.0.0 + resolution: "p-finally@npm:1.0.0" + checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 + languageName: node + linkType: hard + +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: "npm:^1.0.0" + checksum: 10c0/a56af34a77f8df2ff61ddfb29431044557fcbcb7642d5a3233143ebba805fc7306ac1d448de724352861cb99de934bc9ab74f0d16fe6a5460bdbdf938de875ad + languageName: node + linkType: hard + +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: "npm:^4.0.0" + checksum: 10c0/d72fa2f41adce59c198270aa4d3c832536c87a1806e0f69dffb7c1a7ca998fb053915ca833d90f166a8c082d3859eabfed95f01698a3214c20df6bb8de046312 + languageName: node + linkType: hard + +"p-map@npm:^4.0.0": + version: 4.0.0 + resolution: "p-map@npm:4.0.0" + dependencies: + aggregate-error: "npm:^3.0.0" + checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 + languageName: node + linkType: hard + +"p-map@npm:^7.0.2": + version: 7.0.4 + resolution: "p-map@npm:7.0.4" + checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd + languageName: node + linkType: hard + +"p-queue@npm:^6.6.2": + version: 6.6.2 + resolution: "p-queue@npm:6.6.2" + dependencies: + eventemitter3: "npm:^4.0.4" + p-timeout: "npm:^3.2.0" + checksum: 10c0/5739ecf5806bbeadf8e463793d5e3004d08bb3f6177bd1a44a005da8fd81bb90f80e4633e1fb6f1dfd35ee663a5c0229abe26aebb36f547ad5a858347c7b0d3e + languageName: node + linkType: hard + +"p-retry@npm:^6.2.0": + version: 6.2.1 + resolution: "p-retry@npm:6.2.1" + dependencies: + "@types/retry": "npm:0.12.2" + is-network-error: "npm:^1.0.0" + retry: "npm:^0.13.1" + checksum: 10c0/10d014900107da2c7071ad60fffe4951675f09930b7a91681643ea224ae05649c05001d9e78436d902fe8b116d520dd1f60e72e091de097e2640979d56f3fb60 + languageName: node + linkType: hard + +"p-timeout@npm:^3.2.0": + version: 3.2.0 + resolution: "p-timeout@npm:3.2.0" + dependencies: + p-finally: "npm:^1.0.0" + checksum: 10c0/524b393711a6ba8e1d48137c5924749f29c93d70b671e6db761afa784726572ca06149c715632da8f70c090073afb2af1c05730303f915604fd38ee207b70a61 + languageName: node + linkType: hard + +"package-json@npm:^8.1.0": + version: 8.1.1 + resolution: "package-json@npm:8.1.1" + dependencies: + got: "npm:^12.1.0" + registry-auth-token: "npm:^5.0.1" + registry-url: "npm:^6.0.0" + semver: "npm:^7.3.7" + checksum: 10c0/83b057878bca229033aefad4ef51569b484e63a65831ddf164dc31f0486817e17ffcb58c819c7af3ef3396042297096b3ffc04e107fd66f8f48756f6d2071c8f + languageName: node + linkType: hard + +"package-manager-detector@npm:^1.3.0": + version: 1.6.0 + resolution: "package-manager-detector@npm:1.6.0" + checksum: 10c0/6419d0b840be64fd45bcdcb7a19f09b81b65456d5e7f7a3daac305a4c90643052122f6ac0308afe548ffee75e36148532a2002ea9d292754f1e385aa2e1ea03b + languageName: node + linkType: hard + +"param-case@npm:^3.0.4": + version: 3.0.4 + resolution: "param-case@npm:3.0.4" + dependencies: + dot-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/ccc053f3019f878eca10e70ec546d92f51a592f762917dafab11c8b532715dcff58356118a6f350976e4ab109e321756f05739643ed0ca94298e82291e6f9e76 + languageName: node + linkType: hard + +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" + dependencies: + callsites: "npm:^3.0.0" + checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 + languageName: node + linkType: hard + +"parse-entities@npm:^4.0.0": + version: 4.0.2 + resolution: "parse-entities@npm:4.0.2" + dependencies: + "@types/unist": "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + character-reference-invalid: "npm:^2.0.0" + decode-named-character-reference: "npm:^1.0.0" + is-alphanumerical: "npm:^2.0.0" + is-decimal: "npm:^2.0.0" + is-hexadecimal: "npm:^2.0.0" + checksum: 10c0/a13906b1151750b78ed83d386294066daf5fb559e08c5af9591b2d98cc209123103016a01df776f65f8219ad26652d6d6b210d0974d452049cddfc53a8916c34 + languageName: node + linkType: hard + +"parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + dependencies: + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 + languageName: node + linkType: hard + +"parse-numeric-range@npm:^1.3.0": + version: 1.3.0 + resolution: "parse-numeric-range@npm:1.3.0" + checksum: 10c0/53465afaa92111e86697281b684aa4574427360889cc23a1c215488c06b72441febdbf09f47ab0bef9a0c701e059629f3eebd2fe6fb241a254ad7a7a642aebe8 + languageName: node + linkType: hard + +"parse5-htmlparser2-tree-adapter@npm:^7.0.0": + version: 7.1.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.1.0" + dependencies: + domhandler: "npm:^5.0.3" + parse5: "npm:^7.0.0" + checksum: 10c0/e5a4e0b834c84c9e244b5749f8d007f4baaeafac7a1da2c54be3421ffd9ef8fdec4f198bf55cda22e88e6ba95e9943f6ed5aa3ae5900b39972ebf5dc8c3f4722 + languageName: node + linkType: hard + +"parse5@npm:^7.0.0": + version: 7.3.0 + resolution: "parse5@npm:7.3.0" + dependencies: + entities: "npm:^6.0.0" + checksum: 10c0/7fd2e4e247e85241d6f2a464d0085eed599a26d7b0a5233790c49f53473232eb85350e8133344d9b3fd58b89339e7ad7270fe1f89d28abe50674ec97b87f80b5 + languageName: node + linkType: hard + +"parseurl@npm:~1.3.3": + version: 1.3.3 + resolution: "parseurl@npm:1.3.3" + checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 + languageName: node + linkType: hard + +"pascal-case@npm:^3.1.2": + version: 3.1.2 + resolution: "pascal-case@npm:3.1.2" + dependencies: + no-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/05ff7c344809fd272fc5030ae0ee3da8e4e63f36d47a1e0a4855ca59736254192c5a27b5822ed4bae96e54048eec5f6907713cfcfff7cdf7a464eaf7490786d8 + languageName: node + linkType: hard + +"path-data-parser@npm:0.1.0, path-data-parser@npm:^0.1.0": + version: 0.1.0 + resolution: "path-data-parser@npm:0.1.0" + checksum: 10c0/ba22d54669a8bc4a3df27431fe667900685585d1196085b803d0aa4066b83e709bbf2be7c1d2b56e706b49cc698231d55947c22abbfc4843ca424bbf8c985745 + languageName: node + linkType: hard + +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 10c0/b170f3060b31604cde93eefdb7392b89d832dfbc1bed717c9718cbe0f230c1669b7e75f87e19901da2250b84d092989a0f9e44d2ef41deb09aa3ad28e691a40a + languageName: node + linkType: hard + +"path-is-inside@npm:1.0.2": + version: 1.0.2 + resolution: "path-is-inside@npm:1.0.2" + checksum: 10c0/7fdd4b41672c70461cce734fc222b33e7b447fa489c7c4377c95e7e6852d83d69741f307d88ec0cc3b385b41cb4accc6efac3c7c511cd18512e95424f5fa980c + languageName: node + linkType: hard + +"path-key@npm:^3.0.0, path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 + languageName: node + linkType: hard + +"path-scurry@npm:^2.0.2": + version: 2.0.2 + resolution: "path-scurry@npm:2.0.2" + dependencies: + lru-cache: "npm:^11.0.0" + minipass: "npm:^7.1.2" + checksum: 10c0/b35ad37cf6557a87fd057121ce2be7695380c9138d93e87ae928609da259ea0a170fac6f3ef1eb3ece8a068e8b7f2f3adf5bb2374cf4d4a57fe484954fcc9482 + languageName: node + linkType: hard + +"path-to-regexp@npm:3.3.0": + version: 3.3.0 + resolution: "path-to-regexp@npm:3.3.0" + checksum: 10c0/ffa0ebe7088d38d435a8d08b0fe6e8c93ceb2a81a65d4dd1d9a538f52e09d5e3474ed5f553cb3b180d894b0caa10698a68737ab599fd1e56b4663d1a64c9f77b + languageName: node + linkType: hard + +"path-to-regexp@npm:^1.7.0": + version: 1.9.0 + resolution: "path-to-regexp@npm:1.9.0" + dependencies: + isarray: "npm:0.0.1" + checksum: 10c0/de9ddb01b84d9c2c8e2bed18630d8d039e2d6f60a6538595750fa08c7a6482512257464c8da50616f266ab2cdd2428387e85f3b089e4c3f25d0c537e898a0751 + languageName: node + linkType: hard + +"path-to-regexp@npm:^6.2.0": + version: 6.3.0 + resolution: "path-to-regexp@npm:6.3.0" + checksum: 10c0/73b67f4638b41cde56254e6354e46ae3a2ebc08279583f6af3d96fe4664fc75788f74ed0d18ca44fa4a98491b69434f9eee73b97bb5314bd1b5adb700f5c18d6 + languageName: node + linkType: hard + +"path-to-regexp@npm:~0.1.12": + version: 0.1.12 + resolution: "path-to-regexp@npm:0.1.12" + checksum: 10c0/1c6ff10ca169b773f3bba943bbc6a07182e332464704572962d277b900aeee81ac6aa5d060ff9e01149636c30b1f63af6e69dd7786ba6e0ddb39d4dee1f0645b + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c + languageName: node + linkType: hard + +"pathe@npm:^2.0.1, pathe@npm:^2.0.3": + version: 2.0.3 + resolution: "pathe@npm:2.0.3" + checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 + languageName: node + linkType: hard + +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be + languageName: node + linkType: hard + +"picomatch@npm:^4.0.3": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 + languageName: node + linkType: hard + +"pkg-dir@npm:^7.0.0": + version: 7.0.0 + resolution: "pkg-dir@npm:7.0.0" + dependencies: + find-up: "npm:^6.3.0" + checksum: 10c0/1afb23d2efb1ec9d8b2c4a0c37bf146822ad2774f074cb05b853be5dca1b40815c5960dd126df30ab8908349262a266f31b771e877235870a3b8fd313beebec5 + languageName: node + linkType: hard + +"pkg-types@npm:^1.3.1": + version: 1.3.1 + resolution: "pkg-types@npm:1.3.1" + dependencies: + confbox: "npm:^0.1.8" + mlly: "npm:^1.7.4" + pathe: "npm:^2.0.1" + checksum: 10c0/19e6cb8b66dcc66c89f2344aecfa47f2431c988cfa3366bdfdcfb1dd6695f87dcce37fbd90fe9d1605e2f4440b77f391e83c23255347c35cf84e7fd774d7fcea + languageName: node + linkType: hard + +"pkijs@npm:^3.3.3": + version: 3.4.0 + resolution: "pkijs@npm:3.4.0" + dependencies: + "@noble/hashes": "npm:1.4.0" + asn1js: "npm:^3.0.6" + bytestreamjs: "npm:^2.0.1" + pvtsutils: "npm:^1.3.6" + pvutils: "npm:^1.1.3" + tslib: "npm:^2.8.1" + checksum: 10c0/33cfab9283702782ae228bd2d4a51b1e9b2e0d6e2141207f29ee95716101ac4fe6e6821882da5f5eca28c74be3964b181b09e95cbbb757b2bd9dca918a5765fd + languageName: node + linkType: hard + +"points-on-curve@npm:0.2.0, points-on-curve@npm:^0.2.0": + version: 0.2.0 + resolution: "points-on-curve@npm:0.2.0" + checksum: 10c0/f0d92343fcc2ad1f48334633e580574c1e0e28038a756133e171e537f270d6d64203feada5ee556e36f448a1b46e0306dee07b30f589f4e3ad720f6ee38ef48c + languageName: node + linkType: hard + +"points-on-path@npm:^0.2.1": + version: 0.2.1 + resolution: "points-on-path@npm:0.2.1" + dependencies: + path-data-parser: "npm:0.1.0" + points-on-curve: "npm:0.2.0" + checksum: 10c0/a7010340f9f196976f61838e767bb7b0b7f6273ab4fb9eb37c61001fe26fbfc3fcd63c96d5e85b9a4ab579213ab366f2ddaaf60e2a9253e2b91a62db33f395ba + languageName: node + linkType: hard + +"postcss-attribute-case-insensitive@npm:^7.0.1": + version: 7.0.1 + resolution: "postcss-attribute-case-insensitive@npm:7.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/48945abe2024e2d2e4c37d30b8c1aaf37af720f24f6a996f7ea7e7ed33621f5c22cf247ed22028c0c922de040c58c0802729bc39b903cb1693f4b63c0b49da34 + languageName: node + linkType: hard + +"postcss-calc@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-calc@npm:9.0.1" + dependencies: + postcss-selector-parser: "npm:^6.0.11" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.2.2 + checksum: 10c0/e0df07337162dbcaac5d6e030c7fd289e21da8766a9daca5d6b2b3c8094bb524ae5d74c70048ea7fe5fe4960ce048c60ac97922d917c3bbff34f58e9d2b0eb0e + languageName: node + linkType: hard + +"postcss-clamp@npm:^4.1.0": + version: 4.1.0 + resolution: "postcss-clamp@npm:4.1.0" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.6 + checksum: 10c0/701261026b38a4c27b3c3711635fac96005f36d3270adb76dbdb1eebc950fc841db45283ee66068a7121565592e9d7967d5534e15b6e4dd266afcabf9eafa905 + languageName: node + linkType: hard + +"postcss-color-functional-notation@npm:^7.0.12": + version: 7.0.12 + resolution: "postcss-color-functional-notation@npm:7.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/dc80ba1a956ae9b396596bda72d9bdb92de96874378a38ba4e2177ffa35339dc76d894920bb013b6f10c9b75cfb41778e09956a438c2e9ea41b684f766c55f4a + languageName: node + linkType: hard + +"postcss-color-hex-alpha@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-color-hex-alpha@npm:10.0.0" + dependencies: + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/8a6dcb27403d04b55d6de88bf3074622bcea537fc4436bbcb346e92289c4d17059444e2e6c3554c325e7a777bb4cdc711e764a83123b4000aec211052e957d5b + languageName: node + linkType: hard + +"postcss-color-rebeccapurple@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-color-rebeccapurple@npm:10.0.0" + dependencies: + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/308e33f76f2b48c1c2121d4502fc053e869f3415898de7d30314353df680e79b37497e7b628e3447edc1049091da3672f7d891e45604f238598e846e06b893ed + languageName: node + linkType: hard + +"postcss-colormin@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-colormin@npm:6.1.0" + dependencies: + browserslist: "npm:^4.23.0" + caniuse-api: "npm:^3.0.0" + colord: "npm:^2.9.3" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/0802963fa0d8f2fe408b2e088117670f5303c69a58c135f0ecf0e5ceff69e95e87111b22c4e29c9adb2f69aa8d3bc175f4e8e8708eeb99c9ffc36c17064de427 + languageName: node + linkType: hard + +"postcss-convert-values@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-convert-values@npm:6.1.0" + dependencies: + browserslist: "npm:^4.23.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/a80066965cb58fe8fcaf79f306b32c83fc678e1f0678e43f4db3e9fee06eed6db92cf30631ad348a17492769d44757400493c91a33ee865ee8dedea9234a11f5 + languageName: node + linkType: hard + +"postcss-custom-media@npm:^11.0.6": + version: 11.0.6 + resolution: "postcss-custom-media@npm:11.0.6" + dependencies: + "@csstools/cascade-layer-name-parser": "npm:^2.0.5" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/media-query-list-parser": "npm:^4.0.3" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/62dcb2858fd490d90aab32062621d58892a7b2a54948ee63af81a2cd61807a11815d28d4ef6bc800c5e142ac73098f7e56822c7cc63192eb20d5b16071543a73 + languageName: node + linkType: hard + +"postcss-custom-properties@npm:^14.0.6": + version: 14.0.6 + resolution: "postcss-custom-properties@npm:14.0.6" + dependencies: + "@csstools/cascade-layer-name-parser": "npm:^2.0.5" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/0eeef77bc713551f5cb8fa5982d24da4e854075f3af020f1c94366c47a23a4cc225ebfecc978bdb17f00ee0bdee9d2c784e0d01adc64a447321e408abbe2c83b + languageName: node + linkType: hard + +"postcss-custom-selectors@npm:^8.0.5": + version: 8.0.5 + resolution: "postcss-custom-selectors@npm:8.0.5" + dependencies: + "@csstools/cascade-layer-name-parser": "npm:^2.0.5" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/bd8f2f85bbec4bd56ff408cb699d9fe649e2af0db82d5752eee05481ae522f06f5a47950ca22fcb4c8601071c03346df67cf20b0b0bcade32ce58d07ebaf9b32 + languageName: node + linkType: hard + +"postcss-dir-pseudo-class@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-dir-pseudo-class@npm:9.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/da9d3387648c5c3161a653d354c8f3e70a299108df3977e8aa65cf10793e4dd58a2711b3426cd63716245b13584ca8d95adcd6e10e3c9adbc61d08743e2d8690 + languageName: node + linkType: hard + +"postcss-discard-comments@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-discard-comments@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/338a1fcba7e2314d956e5e5b9bd1e12e6541991bf85ac72aed6e229a029bf60edb31f11576b677623576169aa7d9c75e1be259ac7b50d0b735b841b5518f9da9 + languageName: node + linkType: hard + +"postcss-discard-duplicates@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-discard-duplicates@npm:6.0.3" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/24d2f00e54668f2837eb38a64b1751d7a4a73b2752f9749e61eb728f1fae837984bc2b339f7f5207aff5f66f72551253489114b59b9ba21782072677a81d7d1b + languageName: node + linkType: hard + +"postcss-discard-empty@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-discard-empty@npm:6.0.3" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/1af08bb29f18eda41edf3602b257d89a4cf0a16f79fc773cfebd4a37251f8dbd9b77ac18efe55d0677d000b43a8adf2ef9328d31961c810e9433a38494a1fa65 + languageName: node + linkType: hard + +"postcss-discard-overridden@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-discard-overridden@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/fda70ef3cd4cb508369c5bbbae44d7760c40ec9f2e65df1cd1b6e0314317fb1d25ae7f64987ca84e66889c1e9d1862487a6ce391c159dfe04d536597bfc5030d + languageName: node + linkType: hard + +"postcss-discard-unused@npm:^6.0.5": + version: 6.0.5 + resolution: "postcss-discard-unused@npm:6.0.5" + dependencies: + postcss-selector-parser: "npm:^6.0.16" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/fca82f17395a7fcc78eab4e03dfb05958beb240c10cacb3836b832c6ea99f5259980c70890a9b7d8b67adf8071b61f3fcf1b432c7a116397aaf67909366da5cc + languageName: node + linkType: hard + +"postcss-double-position-gradients@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-double-position-gradients@npm:6.0.4" + dependencies: + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/6dbbe7a3855e84a9319df434e210225f6dfa7262e5959611355f1769c2c9d30d37a19737712f20eac6354876fff4ba556d8d0b12a90c78d8ab97c9a8da534a7c + languageName: node + linkType: hard + +"postcss-focus-visible@npm:^10.0.1": + version: 10.0.1 + resolution: "postcss-focus-visible@npm:10.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/c5ecc8536a708a49a99d0abd68a88a160664e6c832c808db8edd9f0221e7017a258daa87e49daf2cb098cb037005d46cf492403c8c9c92ad8835d30adaccf665 + languageName: node + linkType: hard + +"postcss-focus-within@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-focus-within@npm:9.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/d6ab49d2a7f33485a9e137dc77ec92c5619a3ec92e1e672734fc604853ff1f3c0c189085c12461614be4fcb03ea0347d91791a45986a18d50b5228d161eda57a + languageName: node + linkType: hard + +"postcss-font-variant@npm:^5.0.0": + version: 5.0.0 + resolution: "postcss-font-variant@npm:5.0.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 10c0/ccc96460cf6a52b5439c26c9a5ea0589882e46161e3c2331d4353de7574448f5feef667d1a68f7f39b9fe3ee75d85957383ae82bbfcf87c3162c7345df4a444e + languageName: node + linkType: hard + +"postcss-gap-properties@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-gap-properties@npm:6.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/4e07e0d3927d0e65d67eaf047ac39e08d39cb1bf74e16e10c7df7f0d01b184a77ea59f63fd5691b5ed6df159970b972db28cb784d883e26e981137696460897d + languageName: node + linkType: hard + +"postcss-image-set-function@npm:^7.0.0": + version: 7.0.0 + resolution: "postcss-image-set-function@npm:7.0.0" + dependencies: + "@csstools/utilities": "npm:^2.0.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/913fd9492f00122aa0c2550fb0d72130428cbe1e6465bc65e8fe71e9deb10ac0c01d7caceb68b560da759139e8cbc6c90ed22dfe6cf34949af49bb86bcbf4d3a + languageName: node + linkType: hard + +"postcss-lab-function@npm:^7.0.12": + version: 7.0.12 + resolution: "postcss-lab-function@npm:7.0.12" + dependencies: + "@csstools/css-color-parser": "npm:^3.1.0" + "@csstools/css-parser-algorithms": "npm:^3.0.5" + "@csstools/css-tokenizer": "npm:^3.0.4" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/utilities": "npm:^2.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/de39b59da3b97c18d055d81fba68993e93253184ed76f103c888273584f868c551d047814dd54445980a1bdc5987e8f8af141383d84ecc641e5a6ee7bd901095 + languageName: node + linkType: hard + +"postcss-loader@npm:^7.3.4": + version: 7.3.4 + resolution: "postcss-loader@npm:7.3.4" + dependencies: + cosmiconfig: "npm:^8.3.5" + jiti: "npm:^1.20.0" + semver: "npm:^7.5.4" + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + checksum: 10c0/1bf7614aeea9ad1f8ee6be3a5451576c059391688ea67f825aedc2674056369597faeae4e4a81fe10843884c9904a71403d9a54197e1f560e8fbb9e61f2a2680 + languageName: node + linkType: hard + +"postcss-logical@npm:^8.1.0": + version: 8.1.0 + resolution: "postcss-logical@npm:8.1.0" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/0e2e9e901d8a550db7f682d46b1f7e4f363c1ada061dc8e4548e2b563c5e39f3684a2d7c3f11fe061188782bca37874e34967fc6179fa6d98a49ff66a0076d27 + languageName: node + linkType: hard + +"postcss-merge-idents@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-merge-idents@npm:6.0.3" + dependencies: + cssnano-utils: "npm:^4.0.2" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/fdb51d971df33218bd5fdd9619e5a4d854e23affcea51f96bf4391260cb8d0bec937854582fa9a19bde1fa1b2a43fa5a2f179da23a3adeb8e8d292a4749a8ed7 + languageName: node + linkType: hard + +"postcss-merge-longhand@npm:^6.0.5": + version: 6.0.5 + resolution: "postcss-merge-longhand@npm:6.0.5" + dependencies: + postcss-value-parser: "npm:^4.2.0" + stylehacks: "npm:^6.1.1" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/5a223a7f698c05ab42e9997108a7ff27ea1e0c33a11a353d65a04fc89c3b5b750b9e749550d76b6406329117a055adfc79dde7fee48dca5c8e167a2854ae3fea + languageName: node + linkType: hard + +"postcss-merge-rules@npm:^6.1.1": + version: 6.1.1 + resolution: "postcss-merge-rules@npm:6.1.1" + dependencies: + browserslist: "npm:^4.23.0" + caniuse-api: "npm:^3.0.0" + cssnano-utils: "npm:^4.0.2" + postcss-selector-parser: "npm:^6.0.16" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/6d8952dbb19b1e59bf5affe0871fa1be6515103466857cff5af879d6cf619659f8642ec7a931cabb7cdbd393d8c1e91748bf70bee70fa3edea010d4e25786d04 + languageName: node + linkType: hard + +"postcss-minify-font-values@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-minify-font-values@npm:6.1.0" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/0d6567170c22a7db42096b5eac298f041614890fbe01759a9fa5ccda432f2bb09efd399d92c11bf6675ae13ccd259db4602fad3c358317dee421df5f7ab0a003 + languageName: node + linkType: hard + +"postcss-minify-gradients@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-minify-gradients@npm:6.0.3" + dependencies: + colord: "npm:^2.9.3" + cssnano-utils: "npm:^4.0.2" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/7fcbcec94fe5455b89fe1b424a451198e60e0407c894bbacdc062d9fdef2f8571b483b5c3bb17f22d2f1249431251b2de22e1e4e8b0614d10624f8ee6e71afd2 + languageName: node + linkType: hard + +"postcss-minify-params@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-minify-params@npm:6.1.0" + dependencies: + browserslist: "npm:^4.23.0" + cssnano-utils: "npm:^4.0.2" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/e5c38c3e5fb42e2ca165764f983716e57d854a63a477f7389ccc94cd2ab8123707006613bd7f29acc6eafd296fff513aa6d869c98ac52590f886d641cb21a59e + languageName: node + linkType: hard + +"postcss-minify-selectors@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-minify-selectors@npm:6.0.4" + dependencies: + postcss-selector-parser: "npm:^6.0.16" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/695ec2e1e3a7812b0cabe1105d0ed491760be3d8e9433914fb5af1fc30a84e6dc24089cd31b7e300de620b8e7adf806526c1acf8dd14077a7d1d2820c60a327c + languageName: node + linkType: hard + +"postcss-modules-extract-imports@npm:^3.1.0": + version: 3.1.0 + resolution: "postcss-modules-extract-imports@npm:3.1.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 10c0/402084bcab376083c4b1b5111b48ec92974ef86066f366f0b2d5b2ac2b647d561066705ade4db89875a13cb175b33dd6af40d16d32b2ea5eaf8bac63bd2bf219 + languageName: node + linkType: hard + +"postcss-modules-local-by-default@npm:^4.0.5": + version: 4.2.0 + resolution: "postcss-modules-local-by-default@npm:4.2.0" + dependencies: + icss-utils: "npm:^5.0.0" + postcss-selector-parser: "npm:^7.0.0" + postcss-value-parser: "npm:^4.1.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 10c0/b0b83feb2a4b61f5383979d37f23116c99bc146eba1741ca3cf1acca0e4d0dbf293ac1810a6ab4eccbe1ee76440dd0a9eb2db5b3bba4f99fc1b3ded16baa6358 + languageName: node + linkType: hard + +"postcss-modules-scope@npm:^3.2.0": + version: 3.2.1 + resolution: "postcss-modules-scope@npm:3.2.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 10c0/bd2d81f79e3da0ef6365b8e2c78cc91469d05b58046b4601592cdeef6c4050ed8fe1478ae000a1608042fc7e692cb51fecbd2d9bce3f4eace4d32e883ffca10b + languageName: node + linkType: hard + +"postcss-modules-values@npm:^4.0.0": + version: 4.0.0 + resolution: "postcss-modules-values@npm:4.0.0" + dependencies: + icss-utils: "npm:^5.0.0" + peerDependencies: + postcss: ^8.1.0 + checksum: 10c0/dd18d7631b5619fb9921b198c86847a2a075f32e0c162e0428d2647685e318c487a2566cc8cc669fc2077ef38115cde7a068e321f46fb38be3ad49646b639dbc + languageName: node + linkType: hard + +"postcss-nesting@npm:^13.0.2": + version: 13.0.2 + resolution: "postcss-nesting@npm:13.0.2" + dependencies: + "@csstools/selector-resolve-nested": "npm:^3.1.0" + "@csstools/selector-specificity": "npm:^5.0.0" + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/bfa0578b3b686c6374f5a7b2f6ef955cb7e13400de95a919975a982ae43c1e25db37385618f210715ff15393dc7ff8c26c7b156f06b8fb3118a426099cf7f1f2 + languageName: node + linkType: hard + +"postcss-normalize-charset@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-charset@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/af32a3b4cf94163d728b8aa935b2494c9f69fbc96a33b35f67ae15dbdef7fcc8732569df97cbaaf20ca6c0103c39adad0cfce2ba07ffed283796787f6c36f410 + languageName: node + linkType: hard + +"postcss-normalize-display-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-display-values@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/782761850c7e697fdb6c3ff53076de716a71b60f9e835efb2f7ef238de347c88b5d55f0d43cf5c608e1ee58de65360e3d9fccd5f20774bba08ded7c87d8a5651 + languageName: node + linkType: hard + +"postcss-normalize-positions@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-positions@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/9fdd42a47226bbda5f68774f3c4c3a90eb4fa708aef5a997c6a52fe6cac06585c9774038fe3bc1aa86a203c29223b8d8db6ebe7580c1aa293154f2b48db0b038 + languageName: node + linkType: hard + +"postcss-normalize-repeat-style@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-repeat-style@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/9133ccbdf1286920c1cd0d01c1c5fa0bd3251b717f2f3e47d691dcc44978ac1dc419d20d9ae5428bd48ee542059e66b823ba699356f5968ccced5606c7c7ca34 + languageName: node + linkType: hard + +"postcss-normalize-string@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-string@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/fecc2d52c4029b24fecf2ca2fb45df5dbdf9f35012194ad4ea80bc7be3252cdcb21a0976400902320595aa6178f2cc625cc804c6b6740aef6efa42105973a205 + languageName: node + linkType: hard + +"postcss-normalize-timing-functions@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-timing-functions@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/a22af0b3374704e59ae70bbbcc66b7029137e284f04e30a2ad548818d1540d6c1ed748dd8f689b9b6df5c1064085a00ad07b6f7e25ffaad49d4e661b616cdeae + languageName: node + linkType: hard + +"postcss-normalize-unicode@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-normalize-unicode@npm:6.1.0" + dependencies: + browserslist: "npm:^4.23.0" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/ff5746670d94dd97b49a0955c3c71ff516fb4f54bbae257f877d179bacc44a62e50a0fd6e7ddf959f2ca35c335de4266b0c275d880bb57ad7827189339ab1582 + languageName: node + linkType: hard + +"postcss-normalize-url@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-url@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/4718f1c0657788d2c560b340ee8e0a4eb3eb053eba6fbbf489e9a6e739b4c5f9ce1957f54bd03497c50a1f39962bf6ab9ff6ba4976b69dd160f6afd1670d69b7 + languageName: node + linkType: hard + +"postcss-normalize-whitespace@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-whitespace@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/d5275a88e29a894aeb83a2a833e816d2456dbf3f39961628df596ce205dcc4895186a023812ff691945e0804241ccc53e520d16591b5812288474b474bbaf652 + languageName: node + linkType: hard + +"postcss-opacity-percentage@npm:^3.0.0": + version: 3.0.0 + resolution: "postcss-opacity-percentage@npm:3.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/15c7d66036fa966d265c8737196646b3f93deb83d4eea0b17ed5033460599afc31d3a989345e4d7c472963b2a2bb75c83d06979d5d30d6a60fcc7f74cb6d8d40 + languageName: node + linkType: hard + +"postcss-ordered-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-ordered-values@npm:6.0.2" + dependencies: + cssnano-utils: "npm:^4.0.2" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/aece23a289228aa804217a85f8da198d22b9123f02ca1310b81834af380d6fbe115e4300683599b4a2ab7f1c6a1dbd6789724c47c38e2b0a3774f2ea4b4f0963 + languageName: node + linkType: hard + +"postcss-overflow-shorthand@npm:^6.0.0": + version: 6.0.0 + resolution: "postcss-overflow-shorthand@npm:6.0.0" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/6598321b2ed0b68461135395bba9c7f76a4672617770df1e8487f459bc975f4ded6c3d37b6f72a44f4f77f7b6789e0c6f927e66dbbf1bcde1537167dbea39968 + languageName: node + linkType: hard + +"postcss-page-break@npm:^3.0.4": + version: 3.0.4 + resolution: "postcss-page-break@npm:3.0.4" + peerDependencies: + postcss: ^8 + checksum: 10c0/eaaf4d8922b35f2acd637eb059f7e2510b24d65eb8f31424799dd5a98447b6ef010b41880c26e78f818e00f842295638ec75f89d5d489067f53e3dd3db74a00f + languageName: node + linkType: hard + +"postcss-place@npm:^10.0.0": + version: 10.0.0 + resolution: "postcss-place@npm:10.0.0" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/ebb13deaac7648ba6042622375a31f78fbcc5209b7d196e478debbdf94525963fe621c932f4737a5b6b3d487af3b5ed6d059ed6193fdcbff6d3d5b150886ccc1 + languageName: node + linkType: hard + +"postcss-preset-env@npm:^10.2.1": + version: 10.6.1 + resolution: "postcss-preset-env@npm:10.6.1" + dependencies: + "@csstools/postcss-alpha-function": "npm:^1.0.1" + "@csstools/postcss-cascade-layers": "npm:^5.0.2" + "@csstools/postcss-color-function": "npm:^4.0.12" + "@csstools/postcss-color-function-display-p3-linear": "npm:^1.0.1" + "@csstools/postcss-color-mix-function": "npm:^3.0.12" + "@csstools/postcss-color-mix-variadic-function-arguments": "npm:^1.0.2" + "@csstools/postcss-content-alt-text": "npm:^2.0.8" + "@csstools/postcss-contrast-color-function": "npm:^2.0.12" + "@csstools/postcss-exponential-functions": "npm:^2.0.9" + "@csstools/postcss-font-format-keywords": "npm:^4.0.0" + "@csstools/postcss-gamut-mapping": "npm:^2.0.11" + "@csstools/postcss-gradients-interpolation-method": "npm:^5.0.12" + "@csstools/postcss-hwb-function": "npm:^4.0.12" + "@csstools/postcss-ic-unit": "npm:^4.0.4" + "@csstools/postcss-initial": "npm:^2.0.1" + "@csstools/postcss-is-pseudo-class": "npm:^5.0.3" + "@csstools/postcss-light-dark-function": "npm:^2.0.11" + "@csstools/postcss-logical-float-and-clear": "npm:^3.0.0" + "@csstools/postcss-logical-overflow": "npm:^2.0.0" + "@csstools/postcss-logical-overscroll-behavior": "npm:^2.0.0" + "@csstools/postcss-logical-resize": "npm:^3.0.0" + "@csstools/postcss-logical-viewport-units": "npm:^3.0.4" + "@csstools/postcss-media-minmax": "npm:^2.0.9" + "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^3.0.5" + "@csstools/postcss-nested-calc": "npm:^4.0.0" + "@csstools/postcss-normalize-display-values": "npm:^4.0.1" + "@csstools/postcss-oklab-function": "npm:^4.0.12" + "@csstools/postcss-position-area-property": "npm:^1.0.0" + "@csstools/postcss-progressive-custom-properties": "npm:^4.2.1" + "@csstools/postcss-property-rule-prelude-list": "npm:^1.0.0" + "@csstools/postcss-random-function": "npm:^2.0.1" + "@csstools/postcss-relative-color-syntax": "npm:^3.0.12" + "@csstools/postcss-scope-pseudo-class": "npm:^4.0.1" + "@csstools/postcss-sign-functions": "npm:^1.1.4" + "@csstools/postcss-stepped-value-functions": "npm:^4.0.9" + "@csstools/postcss-syntax-descriptor-syntax-production": "npm:^1.0.1" + "@csstools/postcss-system-ui-font-family": "npm:^1.0.0" + "@csstools/postcss-text-decoration-shorthand": "npm:^4.0.3" + "@csstools/postcss-trigonometric-functions": "npm:^4.0.9" + "@csstools/postcss-unset-value": "npm:^4.0.0" + autoprefixer: "npm:^10.4.23" + browserslist: "npm:^4.28.1" + css-blank-pseudo: "npm:^7.0.1" + css-has-pseudo: "npm:^7.0.3" + css-prefers-color-scheme: "npm:^10.0.0" + cssdb: "npm:^8.6.0" + postcss-attribute-case-insensitive: "npm:^7.0.1" + postcss-clamp: "npm:^4.1.0" + postcss-color-functional-notation: "npm:^7.0.12" + postcss-color-hex-alpha: "npm:^10.0.0" + postcss-color-rebeccapurple: "npm:^10.0.0" + postcss-custom-media: "npm:^11.0.6" + postcss-custom-properties: "npm:^14.0.6" + postcss-custom-selectors: "npm:^8.0.5" + postcss-dir-pseudo-class: "npm:^9.0.1" + postcss-double-position-gradients: "npm:^6.0.4" + postcss-focus-visible: "npm:^10.0.1" + postcss-focus-within: "npm:^9.0.1" + postcss-font-variant: "npm:^5.0.0" + postcss-gap-properties: "npm:^6.0.0" + postcss-image-set-function: "npm:^7.0.0" + postcss-lab-function: "npm:^7.0.12" + postcss-logical: "npm:^8.1.0" + postcss-nesting: "npm:^13.0.2" + postcss-opacity-percentage: "npm:^3.0.0" + postcss-overflow-shorthand: "npm:^6.0.0" + postcss-page-break: "npm:^3.0.4" + postcss-place: "npm:^10.0.0" + postcss-pseudo-class-any-link: "npm:^10.0.1" + postcss-replace-overflow-wrap: "npm:^4.0.0" + postcss-selector-not: "npm:^8.0.1" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/e8da96f208918ebc0dc9acc8ba8961a92569f1d130b29abe25adaf7dbd56ef29fc6f778b75964c80fe7f3469012c763ea9447e5c2f559a002a155bc0462cce35 + languageName: node + linkType: hard + +"postcss-pseudo-class-any-link@npm:^10.0.1": + version: 10.0.1 + resolution: "postcss-pseudo-class-any-link@npm:10.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/95e883996e87baf14fc09d25f9a763a2e9d599eb3b9c6b736e83a8c3d0b55841bcb886bccdf51b5b7fefc128cbd0187ad8841f59878f85bd1613642e592d7673 + languageName: node + linkType: hard + +"postcss-reduce-idents@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-reduce-idents@npm:6.0.3" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/d9f9209e52ebb3d1d7feefc0be24fc74792e064e0fdec99554f050c6b882c61073d5d40986c545061b30e5ead881615e92c965dc765d8d83b2dec10d6a664e1f + languageName: node + linkType: hard + +"postcss-reduce-initial@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-reduce-initial@npm:6.1.0" + dependencies: + browserslist: "npm:^4.23.0" + caniuse-api: "npm:^3.0.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/a8f28cf51ce9a1b9423cce1a01c1d7cbee90125930ec36435a0073e73aef402d90affe2fd3600c964b679cf738869fda447b95a9acce74414e9d67d5c6ba8646 + languageName: node + linkType: hard + +"postcss-reduce-transforms@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-reduce-transforms@npm:6.0.2" + dependencies: + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/755ef27b3d083f586ac831f0c611a66e76f504d27e2100dc7674f6b86afad597901b4520cb889fe58ca70e852aa7fd0c0acb69a63d39dfe6a95860b472394e7c + languageName: node + linkType: hard + +"postcss-replace-overflow-wrap@npm:^4.0.0": + version: 4.0.0 + resolution: "postcss-replace-overflow-wrap@npm:4.0.0" + peerDependencies: + postcss: ^8.0.3 + checksum: 10c0/451361b714528cd3632951256ef073769cde725a46cda642a6864f666fb144921fa55e614aec1bcf5946f37d6ffdcca3b932b76f3d997c07b076e8db152b128d + languageName: node + linkType: hard + +"postcss-selector-not@npm:^8.0.1": + version: 8.0.1 + resolution: "postcss-selector-not@npm:8.0.1" + dependencies: + postcss-selector-parser: "npm:^7.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/491ea3dcc421cd90135be786078521605e2062fb93624ea8813cfd5ba0d35143f931e2e608d5f20effd5ea7d3f4786d2afea2afa42d117779a0288e135f132b6 + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.16": + version: 6.1.2 + resolution: "postcss-selector-parser@npm:6.1.2" + dependencies: + cssesc: "npm:^3.0.0" + util-deprecate: "npm:^1.0.2" + checksum: 10c0/523196a6bd8cf660bdf537ad95abd79e546d54180f9afb165a4ab3e651ac705d0f8b8ce6b3164fb9e3279ce482c5f751a69eb2d3a1e8eb0fd5e82294fb3ef13e + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^7.0.0": + version: 7.1.1 + resolution: "postcss-selector-parser@npm:7.1.1" + dependencies: + cssesc: "npm:^3.0.0" + util-deprecate: "npm:^1.0.2" + checksum: 10c0/02d3b1589ddcddceed4b583b098b95a7266dacd5135f041e5d913ebb48e874fd333a36e564cc9a2ec426a464cb18db11cb192ac76247aced5eba8c951bf59507 + languageName: node + linkType: hard + +"postcss-sort-media-queries@npm:^5.2.0": + version: 5.2.0 + resolution: "postcss-sort-media-queries@npm:5.2.0" + dependencies: + sort-css-media-queries: "npm:2.2.0" + peerDependencies: + postcss: ^8.4.23 + checksum: 10c0/5e7f265a21999bdbf6592f7e15b3e889dd93bc9b15fe048958e8f85603ac276e69ef50305e8b41b10f4eea68917c9c25c7956fa9c3ba7f8577c1149416d35c4e + languageName: node + linkType: hard + +"postcss-svgo@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-svgo@npm:6.0.3" + dependencies: + postcss-value-parser: "npm:^4.2.0" + svgo: "npm:^3.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/994b15a88cbb411f32cfa98957faa5623c76f2d75fede51f5f47238f06b367ebe59c204fecbdaf21ccb9e727239a4b290087e04c502392658a0c881ddfbd61f2 + languageName: node + linkType: hard + +"postcss-unique-selectors@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-unique-selectors@npm:6.0.4" + dependencies: + postcss-selector-parser: "npm:^6.0.16" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/bfb99d8a7c675c93f2e65c9d9d563477bfd46fdce9e2727d42d57982b31ccbaaf944e8034bfbefe48b3119e77fba7eb1b181c19b91cb3a5448058fa66a7c9ae9 + languageName: node + linkType: hard + +"postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": + version: 4.2.0 + resolution: "postcss-value-parser@npm:4.2.0" + checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161 + languageName: node + linkType: hard + +"postcss-zindex@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-zindex@npm:6.0.2" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/346291703e1f2dd954144d2bb251713dad6ae10e8aa05c3873dee2fc7a30d72da7866bec060abd932b9b839bc1495f73d813dde5312750a69d7ad33c435ce7ea + languageName: node + linkType: hard + +"postcss@npm:^8.4.21, postcss@npm:^8.4.24, postcss@npm:^8.4.33, postcss@npm:^8.5.4": + version: 8.5.8 + resolution: "postcss@npm:8.5.8" + dependencies: + nanoid: "npm:^3.3.11" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/dd918f7127ee7c60a0295bae2e72b3787892296e1d1c3c564d7a2a00c68d8df83cadc3178491259daa19ccc54804fb71ed8c937c6787e08d8bd4bedf8d17044c + languageName: node + linkType: hard + +"pretty-error@npm:^4.0.0": + version: 4.0.0 + resolution: "pretty-error@npm:4.0.0" + dependencies: + lodash: "npm:^4.17.20" + renderkid: "npm:^3.0.0" + checksum: 10c0/dc292c087e2857b2e7592784ab31e37a40f3fa918caa11eba51f9fb2853e1d4d6e820b219917e35f5721d833cfd20fdf4f26ae931a90fd1ad0cae2125c345138 + languageName: node + linkType: hard + +"pretty-time@npm:^1.1.0": + version: 1.1.0 + resolution: "pretty-time@npm:1.1.0" + checksum: 10c0/ba9d7af19cd43838fb2b147654990949575e400dc2cc24bf71ec4a6c4033a38ba8172b1014b597680c6d4d3c075e94648b2c13a7206c5f0c90b711c7388726f3 + languageName: node + linkType: hard + +"prism-react-renderer@npm:^2.1.0, prism-react-renderer@npm:^2.3.0": + version: 2.4.1 + resolution: "prism-react-renderer@npm:2.4.1" + dependencies: + "@types/prismjs": "npm:^1.26.0" + clsx: "npm:^2.0.0" + peerDependencies: + react: ">=16.0.0" + checksum: 10c0/ebbe8feb975224344bbdd046b3a937d121592dbe4b8f22ba0be31f5af37b9a8219f441138ef6cab1c5b96f2aa6b529015200959f7e5e85b60ca69c81d35edcd4 + languageName: node + linkType: hard + +"prismjs@npm:^1.29.0": + version: 1.30.0 + resolution: "prismjs@npm:1.30.0" + checksum: 10c0/f56205bfd58ef71ccfcbcb691fd0eb84adc96c6ff21b0b69fc6fdcf02be42d6ef972ba4aed60466310de3d67733f6a746f89f2fb79c00bf217406d465b3e8f23 + languageName: node + linkType: hard + +"proc-log@npm:^6.0.0": + version: 6.1.0 + resolution: "proc-log@npm:6.1.0" + checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82 + languageName: node + linkType: hard + +"process-nextick-args@npm:~2.0.0": + version: 2.0.1 + resolution: "process-nextick-args@npm:2.0.1" + checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 + languageName: node + linkType: hard + +"prompts@npm:^2.4.2": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" + dependencies: + kleur: "npm:^3.0.3" + sisteransi: "npm:^1.0.5" + checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 + languageName: node + linkType: hard + +"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2": + version: 15.8.1 + resolution: "prop-types@npm:15.8.1" + dependencies: + loose-envify: "npm:^1.4.0" + object-assign: "npm:^4.1.1" + react-is: "npm:^16.13.1" + checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 + languageName: node + linkType: hard + +"property-information@npm:^7.0.0": + version: 7.0.0 + resolution: "property-information@npm:7.0.0" + checksum: 10c0/bf443e3bbdfc154da8f4ff4c85ed97c3d21f5e5f77cce84d2fd653c6dfb974a75ad61eafbccb2b8d2285942be35d763eaa99d51e29dccc28b40917d3f018107e + languageName: node + linkType: hard + +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: 10c0/b9179f99394ec8a68b8afc817690185f3b03933f7b46ce2e22c1930dc84b60d09f5ad222beab4e59e58c6c039c7f7fcf620397235ef441a356f31f9744010e12 + languageName: node + linkType: hard + +"proxy-addr@npm:~2.0.7": + version: 2.0.7 + resolution: "proxy-addr@npm:2.0.7" + dependencies: + forwarded: "npm:0.2.0" + ipaddr.js: "npm:1.9.1" + checksum: 10c0/c3eed999781a35f7fd935f398b6d8920b6fb00bbc14287bc6de78128ccc1a02c89b95b56742bf7cf0362cc333c61d138532049c7dedc7a328ef13343eff81210 + languageName: node + linkType: hard + +"punycode@npm:^2.1.0": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 + languageName: node + linkType: hard + +"pupa@npm:^3.1.0": + version: 3.1.0 + resolution: "pupa@npm:3.1.0" + dependencies: + escape-goat: "npm:^4.0.0" + checksum: 10c0/02afa6e4547a733484206aaa8f8eb3fbfb12d3dd17d7ca4fa1ea390a7da2cb8f381e38868bbf68009c4d372f8f6059f553171b6a712d8f2802c7cd43d513f06c + languageName: node + linkType: hard + +"pvtsutils@npm:^1.3.6": + version: 1.3.6 + resolution: "pvtsutils@npm:1.3.6" + dependencies: + tslib: "npm:^2.8.1" + checksum: 10c0/b1b42646370505ccae536dcffa662303b2c553995211330c8e39dec9ab8c197585d7751c2c5b9ab2f186feda0219d9bb23c34ee1e565573be96450f79d89a13c + languageName: node + linkType: hard + +"pvutils@npm:^1.1.3": + version: 1.1.5 + resolution: "pvutils@npm:1.1.5" + checksum: 10c0/e968b07b78a58fec9377fe7aa6342c8cfa21c8fb4afc4e51e1489bd42bec6dc71b8a52541d0aede0aea17adec7ca3f89f29f56efdc31d0083cc02e9bb5721bcf + languageName: node + linkType: hard + +"qs@npm:~6.14.0": + version: 6.14.2 + resolution: "qs@npm:6.14.2" + dependencies: + side-channel: "npm:^1.1.0" + checksum: 10c0/646110124476fc9acf3c80994c8c3a0600cbad06a4ede1c9e93341006e8426d64e85e048baf8f0c4995f0f1bf0f37d1f3acc5ec1455850b81978792969a60ef6 + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 + languageName: node + linkType: hard + +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: 10c0/a24cba5da8cec30d70d2484be37622580f64765fb6390a928b17f60cd69e8dbd32a954b3ff9176fa1b86d86ff2ba05252fae55dc4d40d0291c60412b0ad096da + languageName: node + linkType: hard + +"randombytes@npm:^2.1.0": + version: 2.1.0 + resolution: "randombytes@npm:2.1.0" + dependencies: + safe-buffer: "npm:^5.1.0" + checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 + languageName: node + linkType: hard + +"range-parser@npm:1.2.0": + version: 1.2.0 + resolution: "range-parser@npm:1.2.0" + checksum: 10c0/c7aef4f6588eb974c475649c157f197d07437d8c6c8ff7e36280a141463fb5ab7a45918417334ebd7b665c6b8321cf31c763f7631dd5f5db9372249261b8b02a + languageName: node + linkType: hard + +"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1": + version: 1.2.1 + resolution: "range-parser@npm:1.2.1" + checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 + languageName: node + linkType: hard + +"raw-body@npm:~2.5.3": + version: 2.5.3 + resolution: "raw-body@npm:2.5.3" + dependencies: + bytes: "npm:~3.1.2" + http-errors: "npm:~2.0.1" + iconv-lite: "npm:~0.4.24" + unpipe: "npm:~1.0.0" + checksum: 10c0/449844344fc90547fb994383a494b83300e4f22199f146a79f68d78a199a8f2a923ea9fd29c3be979bfd50291a3884733619ffc15ba02a32e703b612f8d3f74a + languageName: node + linkType: hard + +"rc@npm:1.2.8": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 + languageName: node + linkType: hard + +"react-dom@npm:^18.2.0": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.2" + peerDependencies: + react: ^18.3.1 + checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 + languageName: node + linkType: hard + +"react-fast-compare@npm:^3.2.0": + version: 3.2.2 + resolution: "react-fast-compare@npm:3.2.2" + checksum: 10c0/0bbd2f3eb41ab2ff7380daaa55105db698d965c396df73e6874831dbafec8c4b5b08ba36ff09df01526caa3c61595247e3269558c284e37646241cba2b90a367 + languageName: node + linkType: hard + +"react-helmet-async@npm:@slorber/react-helmet-async@1.3.0": + version: 1.3.0 + resolution: "@slorber/react-helmet-async@npm:1.3.0" + dependencies: + "@babel/runtime": "npm:^7.12.5" + invariant: "npm:^2.2.4" + prop-types: "npm:^15.7.2" + react-fast-compare: "npm:^3.2.0" + shallowequal: "npm:^1.1.0" + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 10c0/7a13470a0d27d6305657c7fa6b066443c94acdb22bd0decca772298bc852ce04fdc65f1207f0d546995bf7d4ca09e21c81f96b4954544937c01eda82e2caa142 + languageName: node + linkType: hard + +"react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0": + version: 16.13.1 + resolution: "react-is@npm:16.13.1" + checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 + languageName: node + linkType: hard + +"react-json-view-lite@npm:^2.3.0": + version: 2.5.0 + resolution: "react-json-view-lite@npm:2.5.0" + peerDependencies: + react: ^18.0.0 || ^19.0.0 + checksum: 10c0/8ecaa23d2fddea03f84892ca96577c5416d60a59ed2cad01dff648a60d25b799dac75dea1771e2b9b639ad026ce1efa7b44e6e636bf497b1d6ea0bac5962b96d + languageName: node + linkType: hard + +"react-loadable-ssr-addon-v5-slorber@npm:^1.0.1": + version: 1.0.1 + resolution: "react-loadable-ssr-addon-v5-slorber@npm:1.0.1" + dependencies: + "@babel/runtime": "npm:^7.10.3" + peerDependencies: + react-loadable: "*" + webpack: ">=4.41.1 || 5.x" + checksum: 10c0/7b0645f66adec56646f985ba8094c66a1c0a4627d96ad80eea32431d773ef1f79aa47d3247a8f21db3b064a0c6091653c5b5d3483b7046722eb64e55bffe635c + languageName: node + linkType: hard + +"react-loadable-ssr-addon-v5-slorber@npm:^1.0.3": + version: 1.0.3 + resolution: "react-loadable-ssr-addon-v5-slorber@npm:1.0.3" + dependencies: + "@babel/runtime": "npm:^7.10.3" + peerDependencies: + react-loadable: "*" + webpack: ">=4.41.1 || 5.x" + checksum: 10c0/6f7af924ad0187c41925dda948587452e30b6d5306465468795daa0382524406e6421dcf5be100a4d285dcb0acc916fcce511a35865eb53ab2d7306ecb525f32 + languageName: node + linkType: hard + +"react-loadable@npm:@docusaurus/react-loadable@6.0.0": + version: 6.0.0 + resolution: "@docusaurus/react-loadable@npm:6.0.0" + dependencies: + "@types/react": "npm:*" + peerDependencies: + react: "*" + checksum: 10c0/6b145d1a8d2e7342ceef58dd154aa990322f72a6cb98955ab8ce8e3f0dc7f0c5d00f9c2e4efa8d356c5effed72a130b5588857332b11faba0398f5429b484b04 + languageName: node + linkType: hard + +"react-router-config@npm:^5.1.1": + version: 5.1.1 + resolution: "react-router-config@npm:5.1.1" + dependencies: + "@babel/runtime": "npm:^7.1.2" + peerDependencies: + react: ">=15" + react-router: ">=5" + checksum: 10c0/1f8f4e55ca68b7b012293e663eb0ee4d670a3df929b78928f713ef98cd9d62c7f5c30a098d6668e64bbb11c7d6bb24e9e6b9c985a8b82465a1858dc7ba663f2b + languageName: node + linkType: hard + +"react-router-dom@npm:^5.3.4": + version: 5.3.4 + resolution: "react-router-dom@npm:5.3.4" + dependencies: + "@babel/runtime": "npm:^7.12.13" + history: "npm:^4.9.0" + loose-envify: "npm:^1.3.1" + prop-types: "npm:^15.6.2" + react-router: "npm:5.3.4" + tiny-invariant: "npm:^1.0.2" + tiny-warning: "npm:^1.0.0" + peerDependencies: + react: ">=15" + checksum: 10c0/f04f727e2ed2e9d1d3830af02cc61690ff67b1524c0d18690582bfba0f4d14142ccc88fb6da6befad644fddf086f5ae4c2eb7048c67da8a0b0929c19426421b0 + languageName: node + linkType: hard + +"react-router@npm:5.3.4, react-router@npm:^5.3.4": + version: 5.3.4 + resolution: "react-router@npm:5.3.4" + dependencies: + "@babel/runtime": "npm:^7.12.13" + history: "npm:^4.9.0" + hoist-non-react-statics: "npm:^3.1.0" + loose-envify: "npm:^1.3.1" + path-to-regexp: "npm:^1.7.0" + prop-types: "npm:^15.6.2" + react-is: "npm:^16.6.0" + tiny-invariant: "npm:^1.0.2" + tiny-warning: "npm:^1.0.0" + peerDependencies: + react: ">=15" + checksum: 10c0/e15c00dfef199249b4c6e6d98e5e76cc352ce66f3270f13df37cc069ddf7c05e43281e8c308fc407e4435d72924373baef1d2890e0f6b0b1eb423cf47315a053 + languageName: node + linkType: hard + +"react@npm:^18.2.0": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 + languageName: node + linkType: hard + +"readable-stream@npm:^2.0.1": + version: 2.3.8 + resolution: "readable-stream@npm:2.3.8" + dependencies: + core-util-is: "npm:~1.0.0" + inherits: "npm:~2.0.3" + isarray: "npm:~1.0.0" + process-nextick-args: "npm:~2.0.0" + safe-buffer: "npm:~5.1.1" + string_decoder: "npm:~1.1.1" + util-deprecate: "npm:~1.0.1" + checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa + languageName: node + linkType: hard + +"readable-stream@npm:^3.0.6": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: "npm:^2.0.3" + string_decoder: "npm:^1.1.1" + util-deprecate: "npm:^1.0.1" + checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 + languageName: node + linkType: hard + +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" + dependencies: + picomatch: "npm:^2.2.1" + checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b + languageName: node + linkType: hard + +"recma-build-jsx@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-build-jsx@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-util-build-jsx: "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/ca30f5163887b44c74682355da2625f7b49f33267699d22247913e513e043650cbdd6a7497cf13c60f09ad9e7bc2bd35bd20853672773c19188569814b56bb04 + languageName: node + linkType: hard + +"recma-jsx@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-jsx@npm:1.0.0" + dependencies: + acorn-jsx: "npm:^5.0.0" + estree-util-to-js: "npm:^2.0.0" + recma-parse: "npm:^1.0.0" + recma-stringify: "npm:^1.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/26c2af6dd69336c810468b778be1e4cbac5702cf9382454f17c29cf9b03a4fde47d10385bb26a7ccb34f36fe01af34c24cab9fb0deeed066ea53294be0081f07 + languageName: node + linkType: hard + +"recma-parse@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-parse@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + esast-util-from-js: "npm:^2.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/37c0990859a562d082e02d475ca5f4c8ef0840d285270f6699fe888cbb06260f97eb098585eda4aae416182c207fd19cf05e4f0b2dcf55cbf81dde4406d95545 + languageName: node + linkType: hard + +"recma-stringify@npm:^1.0.0": + version: 1.0.0 + resolution: "recma-stringify@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + estree-util-to-js: "npm:^2.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/c2ed4c0e8cf8a09aedcd47c5d016d47f6e1ff6c2d4b220e2abaf1b77713bf404756af2ea3ea7999aec5862e8825aff035edceb370c7fd8603a7e9da03bd6987e + languageName: node + linkType: hard + +"reflect-metadata@npm:^0.2.2": + version: 0.2.2 + resolution: "reflect-metadata@npm:0.2.2" + checksum: 10c0/1cd93a15ea291e420204955544637c264c216e7aac527470e393d54b4bb075f10a17e60d8168ec96600c7e0b9fcc0cb0bb6e91c3fbf5b0d8c9056f04e6ac1ec2 + languageName: node + linkType: hard + +"regenerate-unicode-properties@npm:^10.2.2": + version: 10.2.2 + resolution: "regenerate-unicode-properties@npm:10.2.2" + dependencies: + regenerate: "npm:^1.4.2" + checksum: 10c0/66a1d6a1dbacdfc49afd88f20b2319a4c33cee56d245163e4d8f5f283e0f45d1085a78f7f7406dd19ea3a5dd7a7799cd020cd817c97464a7507f9d10fbdce87c + languageName: node + linkType: hard + +"regenerate@npm:^1.4.2": + version: 1.4.2 + resolution: "regenerate@npm:1.4.2" + checksum: 10c0/f73c9eba5d398c818edc71d1c6979eaa05af7a808682749dd079f8df2a6d91a9b913db216c2c9b03e0a8ba2bba8701244a93f45211afbff691c32c7b275db1b8 + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 + languageName: node + linkType: hard + +"regexpu-core@npm:^6.3.1": + version: 6.4.0 + resolution: "regexpu-core@npm:6.4.0" + dependencies: + regenerate: "npm:^1.4.2" + regenerate-unicode-properties: "npm:^10.2.2" + regjsgen: "npm:^0.8.0" + regjsparser: "npm:^0.13.0" + unicode-match-property-ecmascript: "npm:^2.0.0" + unicode-match-property-value-ecmascript: "npm:^2.2.1" + checksum: 10c0/1eed9783c023dd06fb1f3ce4b6e3fdf0bc1e30cb036f30aeb2019b351e5e0b74355b40462282ea5db092c79a79331c374c7e9897e44a5ca4509e9f0b570263de + languageName: node + linkType: hard + +"registry-auth-token@npm:^5.0.1": + version: 5.1.0 + resolution: "registry-auth-token@npm:5.1.0" + dependencies: + "@pnpm/npm-conf": "npm:^2.1.0" + checksum: 10c0/316229bd8a4acc29a362a7a3862ff809e608256f0fd9e0b133412b43d6a9ea18743756a0ec5ee1467a5384e1023602b85461b3d88d1336b11879e42f7cf02c12 + languageName: node + linkType: hard + +"registry-url@npm:^6.0.0": + version: 6.0.1 + resolution: "registry-url@npm:6.0.1" + dependencies: + rc: "npm:1.2.8" + checksum: 10c0/66e2221c8113fc35ee9d23fe58cb516fc8d556a189fb8d6f1011a02efccc846c4c9b5075b4027b99a5d5c9ad1345ac37f297bea3c0ca30d607ec8084bf561b90 + languageName: node + linkType: hard + +"regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "regjsgen@npm:0.8.0" + checksum: 10c0/44f526c4fdbf0b29286101a282189e4dbb303f4013cf3fea058668d96d113b9180d3d03d1e13f6d4cbde38b7728bf951aecd9dc199938c080093a9a6f0d7a6bd + languageName: node + linkType: hard + +"regjsparser@npm:^0.13.0": + version: 0.13.0 + resolution: "regjsparser@npm:0.13.0" + dependencies: + jsesc: "npm:~3.1.0" + bin: + regjsparser: bin/parser + checksum: 10c0/4702f85cda09f67747c1b2fb673a0f0e5d1ba39d55f177632265a0be471ba59e3f320623f411649141f752b126b8126eac3ff4c62d317921e430b0472bfc6071 + languageName: node + linkType: hard + +"rehype-raw@npm:^7.0.0": + version: 7.0.0 + resolution: "rehype-raw@npm:7.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + hast-util-raw: "npm:^9.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1435b4b6640a5bc3abe3b2133885c4dbff5ef2190ef9cfe09d6a63f74dd7d7ffd0cede70603278560ccf1acbfb9da9faae4b68065a28bc5aa88ad18e40f32d52 + languageName: node + linkType: hard + +"rehype-recma@npm:^1.0.0": + version: 1.0.0 + resolution: "rehype-recma@npm:1.0.0" + dependencies: + "@types/estree": "npm:^1.0.0" + "@types/hast": "npm:^3.0.0" + hast-util-to-estree: "npm:^3.0.0" + checksum: 10c0/be60d7433a7f788a14f41da3e93ba9d9272c908ddef47757026cc4bbcc912f6301d56810349adf876d294a8d048626a0dbf6988aaa574afbfc29eac1ddc1eb74 + languageName: node + linkType: hard + +"relateurl@npm:^0.2.7": + version: 0.2.7 + resolution: "relateurl@npm:0.2.7" + checksum: 10c0/c248b4e3b32474f116a804b537fa6343d731b80056fb506dffd91e737eef4cac6be47a65aae39b522b0db9d0b1011d1a12e288d82a109ecd94a5299d82f6573a + languageName: node + linkType: hard + +"remark-directive@npm:^3.0.0": + version: 3.0.1 + resolution: "remark-directive@npm:3.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-directive: "npm:^3.0.0" + micromark-extension-directive: "npm:^3.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/ac0e60bdfd97063e2b4e18a96842567ae2ffea75f2545fcd7e4fe54806fb31629d60cef55b565333bda172eddee36766fe2535ca0b59208394bde676cd98094c + languageName: node + linkType: hard + +"remark-emoji@npm:^4.0.0": + version: 4.0.1 + resolution: "remark-emoji@npm:4.0.1" + dependencies: + "@types/mdast": "npm:^4.0.2" + emoticon: "npm:^4.0.1" + mdast-util-find-and-replace: "npm:^3.0.1" + node-emoji: "npm:^2.1.0" + unified: "npm:^11.0.4" + checksum: 10c0/27f88892215f3efe8f25c43f226a82d70144a1ae5906d36f6e09390b893b2d5524d5949bd8ca6a02be0e3cb5cba908b35c4221f4e07f34e93d13d6ff9347dbb8 + languageName: node + linkType: hard + +"remark-frontmatter@npm:^5.0.0": + version: 5.0.0 + resolution: "remark-frontmatter@npm:5.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-frontmatter: "npm:^2.0.0" + micromark-extension-frontmatter: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/102325d5edbcf30eaf74de8a0a6e03096cc2370dfef19080fd2dd208f368fbb2323388751ac9931a1aa38a4f2828fa4bad6c52dc5249dcadcd34861693b52bf9 + languageName: node + linkType: hard + +"remark-gfm@npm:^4.0.0": + version: 4.0.1 + resolution: "remark-gfm@npm:4.0.1" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-gfm: "npm:^3.0.0" + micromark-extension-gfm: "npm:^3.0.0" + remark-parse: "npm:^11.0.0" + remark-stringify: "npm:^11.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/427ecc6af3e76222662061a5f670a3e4e33ec5fffe2cabf04034da6a3f9a1bda1fc023e838a636385ba314e66e2bebbf017ca61ebea357eb0f5200fe0625a4b7 + languageName: node + linkType: hard + +"remark-mdx@npm:^3.0.0": + version: 3.1.0 + resolution: "remark-mdx@npm:3.1.0" + dependencies: + mdast-util-mdx: "npm:^3.0.0" + micromark-extension-mdxjs: "npm:^3.0.0" + checksum: 10c0/247800fa8561624bdca5776457c5965d99e5e60080e80262c600fe12ddd573862e029e39349e1e36e4c3bf79c8e571ecf4d3d2d8c13485b758391fb500e24a1a + languageName: node + linkType: hard + +"remark-parse@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-parse@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-from-markdown: "npm:^2.0.0" + micromark-util-types: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/6eed15ddb8680eca93e04fcb2d1b8db65a743dcc0023f5007265dda558b09db595a087f622062ccad2630953cd5cddc1055ce491d25a81f3317c858348a8dd38 + languageName: node + linkType: hard + +"remark-rehype@npm:^11.0.0": + version: 11.1.1 + resolution: "remark-rehype@npm:11.1.1" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + mdast-util-to-hast: "npm:^13.0.0" + unified: "npm:^11.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/68f986e8ee758d415e93babda2a0d89477c15b7c200edc23b8b1d914dd6e963c5fc151a11cbbbcfa7dd237367ff3ef86e302be90f31f37a17b0748668bd8c65b + languageName: node + linkType: hard + +"remark-stringify@npm:^11.0.0": + version: 11.0.0 + resolution: "remark-stringify@npm:11.0.0" + dependencies: + "@types/mdast": "npm:^4.0.0" + mdast-util-to-markdown: "npm:^2.0.0" + unified: "npm:^11.0.0" + checksum: 10c0/0cdb37ce1217578f6f847c7ec9f50cbab35df5b9e3903d543e74b405404e67c07defcb23cd260a567b41b769400f6de03c2c3d9cd6ae7a6707d5c8d89ead489f + languageName: node + linkType: hard + +"renderkid@npm:^3.0.0": + version: 3.0.0 + resolution: "renderkid@npm:3.0.0" + dependencies: + css-select: "npm:^4.1.3" + dom-converter: "npm:^0.2.0" + htmlparser2: "npm:^6.1.0" + lodash: "npm:^4.17.21" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/24a9fae4cc50e731d059742d1b3eec163dc9e3872b12010d120c3fcbd622765d9cda41f79a1bbb4bf63c1d3442f18a08f6e1642cb5d7ebf092a0ce3f7a3bd143 + languageName: node + linkType: hard + +"repeat-string@npm:^1.0.0": + version: 1.6.1 + resolution: "repeat-string@npm:1.6.1" + checksum: 10c0/87fa21bfdb2fbdedc44b9a5b118b7c1239bdd2c2c1e42742ef9119b7d412a5137a1d23f1a83dc6bb686f4f27429ac6f542e3d923090b44181bafa41e8ac0174d + languageName: node + linkType: hard + +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 + languageName: node + linkType: hard + +"require-like@npm:>= 0.1.1": + version: 0.1.2 + resolution: "require-like@npm:0.1.2" + checksum: 10c0/9035ff6c4000a56ede6fc51dd5c56541fafa5a7dddc9b1c3a5f9148d95ee21c603c9bf5c6e37b19fc7de13d9294260842d8590b2ffd6c7c773e78603d1af8050 + languageName: node + linkType: hard + +"requires-port@npm:^1.0.0": + version: 1.0.0 + resolution: "requires-port@npm:1.0.0" + checksum: 10c0/b2bfdd09db16c082c4326e573a82c0771daaf7b53b9ce8ad60ea46aa6e30aaf475fe9b164800b89f93b748d2c234d8abff945d2551ba47bf5698e04cd7713267 + languageName: node + linkType: hard + +"resolve-alpn@npm:^1.2.0": + version: 1.2.1 + resolution: "resolve-alpn@npm:1.2.1" + checksum: 10c0/b70b29c1843bc39781ef946c8cd4482e6d425976599c0f9c138cec8209e4e0736161bf39319b01676a847000085dfdaf63583c6fb4427bf751a10635bd2aa0c4 + languageName: node + linkType: hard + +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 + languageName: node + linkType: hard + +"resolve-pathname@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-pathname@npm:3.0.0" + checksum: 10c0/c6ec49b670dc35b9a303c47fa83ba9348a71e92d64a4c4bb85e1b659a29b407aa1ac1cb14a9b5b502982132ca77482bd80534bca147439d66880d35a137fe723 + languageName: node + linkType: hard + +"resolve@npm:^1.22.11": + version: 1.22.11 + resolution: "resolve@npm:1.22.11" + dependencies: + is-core-module: "npm:^2.16.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.22.11#optional!builtin": + version: 1.22.11 + resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.16.1" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63 + languageName: node + linkType: hard + +"responselike@npm:^3.0.0": + version: 3.0.0 + resolution: "responselike@npm:3.0.0" + dependencies: + lowercase-keys: "npm:^3.0.0" + checksum: 10c0/8af27153f7e47aa2c07a5f2d538cb1e5872995f0e9ff77def858ecce5c3fe677d42b824a62cde502e56d275ab832b0a8bd350d5cd6b467ac0425214ac12ae658 + languageName: node + linkType: hard + +"retry@npm:^0.13.1": + version: 0.13.1 + resolution: "retry@npm:0.13.1" + checksum: 10c0/9ae822ee19db2163497e074ea919780b1efa00431d197c7afdb950e42bf109196774b92a49fc9821f0b8b328a98eea6017410bfc5e8a0fc19c85c6d11adb3772 + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.1.0 + resolution: "reusify@npm:1.1.0" + checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa + languageName: node + linkType: hard + +"robust-predicates@npm:^3.0.2": + version: 3.0.3 + resolution: "robust-predicates@npm:3.0.3" + checksum: 10c0/ae23a0318be809545f091a076818747848f144495491e24e6df5d767f2bad0a1501bbeac34e78b74681d1437ecff0585f593ebfe6c8d49a50e79c5053b962693 + languageName: node + linkType: hard + +"roughjs@npm:^4.6.6": + version: 4.6.6 + resolution: "roughjs@npm:4.6.6" + dependencies: + hachure-fill: "npm:^0.5.2" + path-data-parser: "npm:^0.1.0" + points-on-curve: "npm:^0.2.0" + points-on-path: "npm:^0.2.1" + checksum: 10c0/68c11bf4516aa014cef2fe52426a9bab237c2f500d13e1a4f13b523cb5723667bf2d92b9619325efdc5bc2a193588ff5af8d51683df17cfb8720e96fe2b92b0c + languageName: node + linkType: hard + +"rtlcss@npm:^4.1.0": + version: 4.3.0 + resolution: "rtlcss@npm:4.3.0" + dependencies: + escalade: "npm:^3.1.1" + picocolors: "npm:^1.0.0" + postcss: "npm:^8.4.21" + strip-json-comments: "npm:^3.1.1" + bin: + rtlcss: bin/rtlcss.js + checksum: 10c0/ec59db839e1446b4cd6dcef618c8986f00d67e0ac3c2d40bd9041f1909aaacd668072c90849906ca692dea25cd993f46e9188b4c36adfa5bd3eebeb945fb28f2 + languageName: node + linkType: hard + +"run-applescript@npm:^7.0.0": + version: 7.1.0 + resolution: "run-applescript@npm:7.1.0" + checksum: 10c0/ab826c57c20f244b2ee807704b1ef4ba7f566aa766481ae5922aac785e2570809e297c69afcccc3593095b538a8a77d26f2b2e9a1d9dffee24e0e039502d1a03 + languageName: node + linkType: hard + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: "npm:^1.2.2" + checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 + languageName: node + linkType: hard + +"rw@npm:1": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: 10c0/b1e1ef37d1e79d9dc7050787866e30b6ddcb2625149276045c262c6b4d53075ddc35f387a856a8e76f0d0df59f4cd58fe24707e40797ebee66e542b840ed6a53 + languageName: node + linkType: hard + +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 + languageName: node + linkType: hard + +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + languageName: node + linkType: hard + +"sax@npm:^1.2.4, sax@npm:^1.5.0": + version: 1.6.0 + resolution: "sax@npm:1.6.0" + checksum: 10c0/e5593f4a91eb25761a688c4d96902e4e95a0dd6017bc65146b6f21236e3d715cf893333b76bc758923c9574c2fb5a7a76c3a81e96ea15432f2624f906c027c1e + languageName: node + linkType: hard + +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 + languageName: node + linkType: hard + +"schema-dts@npm:^1.1.2": + version: 1.1.5 + resolution: "schema-dts@npm:1.1.5" + checksum: 10c0/babe23a1577c75c5df79d73acf34af3399e60928eab46f2236a0c4212061f5778d613a31c9e9ec86a2807d20b1ea460673d72d3fe1f64fb7543867460e607f76 + languageName: node + linkType: hard + +"schema-utils@npm:^3.0.0": + version: 3.3.0 + resolution: "schema-utils@npm:3.3.0" + dependencies: + "@types/json-schema": "npm:^7.0.8" + ajv: "npm:^6.12.5" + ajv-keywords: "npm:^3.5.2" + checksum: 10c0/fafdbde91ad8aa1316bc543d4b61e65ea86970aebbfb750bfb6d8a6c287a23e415e0e926c2498696b242f63af1aab8e585252637fabe811fd37b604351da6500 + languageName: node + linkType: hard + +"schema-utils@npm:^4.0.0, schema-utils@npm:^4.0.1, schema-utils@npm:^4.2.0, schema-utils@npm:^4.3.0": + version: 4.3.0 + resolution: "schema-utils@npm:4.3.0" + dependencies: + "@types/json-schema": "npm:^7.0.9" + ajv: "npm:^8.9.0" + ajv-formats: "npm:^2.1.1" + ajv-keywords: "npm:^5.1.0" + checksum: 10c0/c23f0fa73ef71a01d4a2bb7af4c91e0d356ec640e071aa2d06ea5e67f042962bb7ac7c29a60a295bb0125878801bc3209197a2b8a833dd25bd38e37c3ed21427 + languageName: node + linkType: hard + +"section-matter@npm:^1.0.0": + version: 1.0.0 + resolution: "section-matter@npm:1.0.0" + dependencies: + extend-shallow: "npm:^2.0.1" + kind-of: "npm:^6.0.0" + checksum: 10c0/8007f91780adc5aaa781a848eaae50b0f680bbf4043b90cf8a96778195b8fab690c87fe7a989e02394ce69890e330811ec8dab22397d384673ce59f7d750641d + languageName: node + linkType: hard + +"select-hose@npm:^2.0.0": + version: 2.0.0 + resolution: "select-hose@npm:2.0.0" + checksum: 10c0/01cc52edd29feddaf379efb4328aededa633f0ac43c64b11a8abd075ff34f05b0d280882c4fbcbdf1a0658202c9cd2ea8d5985174dcf9a2dac7e3a4996fa9b67 + languageName: node + linkType: hard + +"selfsigned@npm:^1.10.11": + version: 1.10.14 + resolution: "selfsigned@npm:1.10.14" + dependencies: + node-forge: "npm:^0.10.0" + checksum: 10c0/cb7c92e28a3e8a34e91a3b20b9dd7d237a1bffccd9890c434f74eef65ae8bfffe7c1ab3379faac017b957ea44522923e06e2b41e0858c643edb01137a507cd16 + languageName: node + linkType: hard + +"selfsigned@npm:^5.5.0": + version: 5.5.0 + resolution: "selfsigned@npm:5.5.0" + dependencies: + "@peculiar/x509": "npm:^1.14.2" + pkijs: "npm:^3.3.3" + checksum: 10c0/a31e9d928e22cd6f4e14759a099feba79d9d789c852c7cf65ff8e2f62d7f6313fe477639590e7ed06115b4516a4bebbe0dec5d072a2d01cc372a9cfd58eb893b + languageName: node + linkType: hard + +"semiver@npm:^1.1.0": + version: 1.1.0 + resolution: "semiver@npm:1.1.0" + checksum: 10c0/f208555fcdf8726d25a5d5acd5079b1f6a274a9be291da6981c70867cca9abd43721648b338bac914fbc7874e2594217a5943a2e91410ce24b5a80a641d4468b + languageName: node + linkType: hard + +"semver-diff@npm:^4.0.0": + version: 4.0.0 + resolution: "semver-diff@npm:4.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/3ed1bb22f39b4b6e98785bb066e821eabb9445d3b23e092866c50e7df8b9bd3eda617b242f81db4159586e0e39b0deb908dd160a24f783bd6f52095b22cd68ea + languageName: node + linkType: hard + +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.4": + version: 7.7.1 + resolution: "semver@npm:7.7.1" + bin: + semver: bin/semver.js + checksum: 10c0/fd603a6fb9c399c6054015433051bdbe7b99a940a8fb44b85c2b524c4004b023d7928d47cb22154f8d054ea7ee8597f586605e05b52047f048278e4ac56ae958 + languageName: node + linkType: hard + +"send@npm:~0.19.0, send@npm:~0.19.1": + version: 0.19.2 + resolution: "send@npm:0.19.2" + dependencies: + debug: "npm:2.6.9" + depd: "npm:2.0.0" + destroy: "npm:1.2.0" + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + etag: "npm:~1.8.1" + fresh: "npm:~0.5.2" + http-errors: "npm:~2.0.1" + mime: "npm:1.6.0" + ms: "npm:2.1.3" + on-finished: "npm:~2.4.1" + range-parser: "npm:~1.2.1" + statuses: "npm:~2.0.2" + checksum: 10c0/20c2389fe0fdf3fc499938cac598bc32272287e993c4960717381a10de8550028feadfb9076f959a3a3ebdea42e1f690e116f0d16468fa56b9fd41866d3dc267 + languageName: node + linkType: hard + +"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.1, serialize-javascript@npm:^6.0.2": + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" + dependencies: + randombytes: "npm:^2.1.0" + checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 + languageName: node + linkType: hard + +"serve-handler@npm:^6.1.6": + version: 6.1.6 + resolution: "serve-handler@npm:6.1.6" + dependencies: + bytes: "npm:3.0.0" + content-disposition: "npm:0.5.2" + mime-types: "npm:2.1.18" + minimatch: "npm:3.1.2" + path-is-inside: "npm:1.0.2" + path-to-regexp: "npm:3.3.0" + range-parser: "npm:1.2.0" + checksum: 10c0/1e1cb6bbc51ee32bc1505f2e0605bdc2e96605c522277c977b67f83be9d66bd1eec8604388714a4d728e036d86b629bc9aec02120ea030d3d2c3899d44696503 + languageName: node + linkType: hard + +"serve-handler@npm:^6.1.7": + version: 6.1.7 + resolution: "serve-handler@npm:6.1.7" + dependencies: + bytes: "npm:3.0.0" + content-disposition: "npm:0.5.2" + mime-types: "npm:2.1.18" + minimatch: "npm:3.1.5" + path-is-inside: "npm:1.0.2" + path-to-regexp: "npm:3.3.0" + range-parser: "npm:1.2.0" + checksum: 10c0/35afb68d81afd3c38d15792a5bc2451915b739bef2898a47ebd190db6a4e29846530ac00292b8008fe7297a819257c3948be2deaf4ffd32c96689e8947cf0ae9 + languageName: node + linkType: hard + +"serve-index@npm:^1.9.1": + version: 1.9.2 + resolution: "serve-index@npm:1.9.2" + dependencies: + accepts: "npm:~1.3.8" + batch: "npm:0.6.1" + debug: "npm:2.6.9" + escape-html: "npm:~1.0.3" + http-errors: "npm:~1.8.0" + mime-types: "npm:~2.1.35" + parseurl: "npm:~1.3.3" + checksum: 10c0/b4e48da75c9262cfcf6a4707748a33a127f6c3cd3a095782c22312c4915545b7695071fedc8f5717bae165e6e63053cd963847013b1f1e984213f07186f78a74 + languageName: node + linkType: hard + +"serve-static@npm:~1.16.2": + version: 1.16.3 + resolution: "serve-static@npm:1.16.3" + dependencies: + encodeurl: "npm:~2.0.0" + escape-html: "npm:~1.0.3" + parseurl: "npm:~1.3.3" + send: "npm:~0.19.1" + checksum: 10c0/36320397a073c71bedf58af48a4a100fe6d93f07459af4d6f08b9a7217c04ce2a4939e0effd842dc7bece93ffcd59eb52f58c4fff2a8e002dc29ae6b219cd42b + languageName: node + linkType: hard + +"set-cookie-parser@npm:^2.4.8": + version: 2.7.1 + resolution: "set-cookie-parser@npm:2.7.1" + checksum: 10c0/060c198c4c92547ac15988256f445eae523f57f2ceefeccf52d30d75dedf6bff22b9c26f756bd44e8e560d44ff4ab2130b178bd2e52ef5571bf7be3bd7632d9a + languageName: node + linkType: hard + +"set-function-length@npm:^1.2.2": + version: 1.2.2 + resolution: "set-function-length@npm:1.2.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c + languageName: node + linkType: hard + +"setprototypeof@npm:1.2.0, setprototypeof@npm:~1.2.0": + version: 1.2.0 + resolution: "setprototypeof@npm:1.2.0" + checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc + languageName: node + linkType: hard + +"shallow-clone@npm:^3.0.0": + version: 3.0.1 + resolution: "shallow-clone@npm:3.0.1" + dependencies: + kind-of: "npm:^6.0.2" + checksum: 10c0/7bab09613a1b9f480c85a9823aebec533015579fa055ba6634aa56ba1f984380670eaf33b8217502931872aa1401c9fcadaa15f9f604d631536df475b05bcf1e + languageName: node + linkType: hard + +"shallowequal@npm:^1.1.0": + version: 1.1.0 + resolution: "shallowequal@npm:1.1.0" + checksum: 10c0/b926efb51cd0f47aa9bc061add788a4a650550bbe50647962113a4579b60af2abe7b62f9b02314acc6f97151d4cf87033a2b15fc20852fae306d1a095215396c + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 + languageName: node + linkType: hard + +"shell-quote@npm:^1.8.3": + version: 1.8.3 + resolution: "shell-quote@npm:1.8.3" + checksum: 10c0/bee87c34e1e986cfb4c30846b8e6327d18874f10b535699866f368ade11ea4ee45433d97bf5eada22c4320c27df79c3a6a7eb1bf3ecfc47f2c997d9e5e2672fd + languageName: node + linkType: hard + +"side-channel-list@npm:^1.0.0": + version: 1.0.0 + resolution: "side-channel-list@npm:1.0.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + dependencies: + call-bound: "npm:^1.0.2" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.5" + object-inspect: "npm:^1.13.3" + side-channel-map: "npm:^1.0.1" + checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 + languageName: node + linkType: hard + +"side-channel@npm:^1.1.0": + version: 1.1.0 + resolution: "side-channel@npm:1.1.0" + dependencies: + es-errors: "npm:^1.3.0" + object-inspect: "npm:^1.13.3" + side-channel-list: "npm:^1.0.0" + side-channel-map: "npm:^1.0.1" + side-channel-weakmap: "npm:^1.0.2" + checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 + languageName: node + linkType: hard + +"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 + languageName: node + linkType: hard + +"sirv@npm:^2.0.3": + version: 2.0.4 + resolution: "sirv@npm:2.0.4" + dependencies: + "@polka/url": "npm:^1.0.0-next.24" + mrmime: "npm:^2.0.0" + totalist: "npm:^3.0.0" + checksum: 10c0/68f8ee857f6a9415e9c07a1f31c7c561df8d5f1b1ba79bee3de583fa37da8718def5309f6b1c6e2c3ef77de45d74f5e49efc7959214443aa92d42e9c99180a4e + languageName: node + linkType: hard + +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 + languageName: node + linkType: hard + +"sitemap@npm:^7.1.1": + version: 7.1.3 + resolution: "sitemap@npm:7.1.3" + dependencies: + "@types/node": "npm:^17.0.5" + "@types/sax": "npm:^1.2.1" + arg: "npm:^5.0.0" + sax: "npm:^1.2.4" + bin: + sitemap: dist/cli.js + checksum: 10c0/9c284fcfa9163cee3df1c77ddfecc564d8fd079db560e5188ed5b408468c85db3087ca818cfff6d2de74a9e2dddcc330cc9f3abd9067f4e13e09d7ea89cd84e5 + languageName: node + linkType: hard + +"skin-tone@npm:^2.0.0": + version: 2.0.0 + resolution: "skin-tone@npm:2.0.0" + dependencies: + unicode-emoji-modifier-base: "npm:^1.0.0" + checksum: 10c0/82d4c2527864f9cbd6cb7f3c4abb31e2224752234d5013b881d3e34e9ab543545b05206df5a17d14b515459fcb265ce409f9cfe443903176b0360cd20e4e4ba5 + languageName: node + linkType: hard + +"slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b + languageName: node + linkType: hard + +"slash@npm:^4.0.0": + version: 4.0.0 + resolution: "slash@npm:4.0.0" + checksum: 10c0/b522ca75d80d107fd30d29df0549a7b2537c83c4c4ecd12cd7d4ea6c8aaca2ab17ada002e7a1d78a9d736a0261509f26ea5b489082ee443a3a810586ef8eff18 + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 + languageName: node + linkType: hard + +"snake-case@npm:^3.0.4": + version: 3.0.4 + resolution: "snake-case@npm:3.0.4" + dependencies: + dot-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/ab19a913969f58f4474fe9f6e8a026c8a2142a01f40b52b79368068343177f818cdfef0b0c6b9558f298782441d5ca8ed5932eb57822439fad791d866e62cecd + languageName: node + linkType: hard + +"sockjs@npm:^0.3.24": + version: 0.3.24 + resolution: "sockjs@npm:0.3.24" + dependencies: + faye-websocket: "npm:^0.11.3" + uuid: "npm:^8.3.2" + websocket-driver: "npm:^0.7.4" + checksum: 10c0/aa102c7d921bf430215754511c81ea7248f2dcdf268fbdb18e4d8183493a86b8793b164c636c52f474a886f747447c962741df2373888823271efdb9d2594f33 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.7 + resolution: "socks@npm:2.8.7" + dependencies: + ip-address: "npm:^10.0.1" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 + languageName: node + linkType: hard + +"sort-css-media-queries@npm:2.2.0": + version: 2.2.0 + resolution: "sort-css-media-queries@npm:2.2.0" + checksum: 10c0/7478308c7ca93409f959ab993d41de2f0515ed5f51b671908ecb777aae0d63be97b454d59d80e14ee4874884618a2e825d4ae7ccb225779276904dd175f4e766 + languageName: node + linkType: hard + +"source-map-js@npm:^1.0.1, source-map-js@npm:^1.2.1": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + +"source-map-support@npm:^0.5.20, source-map-support@npm:~0.5.20": + version: 0.5.21 + resolution: "source-map-support@npm:0.5.21" + dependencies: + buffer-from: "npm:^1.0.0" + source-map: "npm:^0.6.0" + checksum: 10c0/9ee09942f415e0f721d6daad3917ec1516af746a8120bba7bb56278707a37f1eb8642bde456e98454b8a885023af81a16e646869975f06afc1a711fb90484e7d + languageName: node + linkType: hard + +"source-map@npm:^0.6.0, source-map@npm:~0.6.0": + version: 0.6.1 + resolution: "source-map@npm:0.6.1" + checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 + languageName: node + linkType: hard + +"source-map@npm:^0.7.0": + version: 0.7.4 + resolution: "source-map@npm:0.7.4" + checksum: 10c0/dc0cf3768fe23c345ea8760487f8c97ef6fca8a73c83cd7c9bf2fde8bc2c34adb9c0824d6feb14bc4f9e37fb522e18af621543f1289038a66ac7586da29aa7dc + languageName: node + linkType: hard + +"space-separated-tokens@npm:^2.0.0": + version: 2.0.2 + resolution: "space-separated-tokens@npm:2.0.2" + checksum: 10c0/6173e1d903dca41dcab6a2deed8b4caf61bd13b6d7af8374713500570aa929ff9414ae09a0519f4f8772df993300305a395d4871f35bc4ca72b6db57e1f30af8 + languageName: node + linkType: hard + +"spdy-transport@npm:^3.0.0": + version: 3.0.0 + resolution: "spdy-transport@npm:3.0.0" + dependencies: + debug: "npm:^4.1.0" + detect-node: "npm:^2.0.4" + hpack.js: "npm:^2.1.6" + obuf: "npm:^1.1.2" + readable-stream: "npm:^3.0.6" + wbuf: "npm:^1.7.3" + checksum: 10c0/eaf7440fa90724fffc813c386d4a8a7427d967d6e46d7c51d8f8a533d1a6911b9823ea9218703debbae755337e85f110185d7a00ae22ec5c847077b908ce71bb + languageName: node + linkType: hard + +"spdy@npm:^4.0.2": + version: 4.0.2 + resolution: "spdy@npm:4.0.2" + dependencies: + debug: "npm:^4.1.0" + handle-thing: "npm:^2.0.0" + http-deceiver: "npm:^1.2.7" + select-hose: "npm:^2.0.0" + spdy-transport: "npm:^3.0.0" + checksum: 10c0/983509c0be9d06fd00bb9dff713c5b5d35d3ffd720db869acdd5ad7aa6fc0e02c2318b58f75328957d8ff772acdf1f7d19382b6047df342044ff3e2d6805ccdf + languageName: node + linkType: hard + +"sprintf-js@npm:~1.0.2": + version: 1.0.3 + resolution: "sprintf-js@npm:1.0.3" + checksum: 10c0/ecadcfe4c771890140da5023d43e190b7566d9cf8b2d238600f31bec0fc653f328da4450eb04bd59a431771a8e9cc0e118f0aa3974b683a4981b4e07abc2a5bb + languageName: node + linkType: hard + +"srcset@npm:^4.0.0": + version: 4.0.0 + resolution: "srcset@npm:4.0.0" + checksum: 10c0/0685c3bd2423b33831734fb71560cd8784f024895e70ee2ac2c392e30047c27ffd9481e001950fb0503f4906bc3fe963145935604edad77944d09c9800990660 + languageName: node + linkType: hard + +"ssri@npm:^13.0.0": + version: 13.0.1 + resolution: "ssri@npm:13.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/cf6408a18676c57ff2ed06b8a20dc64bb3e748e5c7e095332e6aecaa2b8422b1e94a739a8453bf65156a8a47afe23757ba4ab52d3ea3b62322dc40875763e17a + languageName: node + linkType: hard + +"stack-trace@npm:0.0.10": + version: 0.0.10 + resolution: "stack-trace@npm:0.0.10" + checksum: 10c0/9ff3dabfad4049b635a85456f927a075c9d0c210e3ea336412d18220b2a86cbb9b13ec46d6c37b70a302a4ea4d49e30e5d4944dd60ae784073f1cde778ac8f4b + languageName: node + linkType: hard + +"statuses@npm:>= 1.5.0 < 2": + version: 1.5.0 + resolution: "statuses@npm:1.5.0" + checksum: 10c0/e433900956357b3efd79b1c547da4d291799ac836960c016d10a98f6a810b1b5c0dcc13b5a7aa609a58239b5190e1ea176ad9221c2157d2fd1c747393e6b2940 + languageName: node + linkType: hard + +"statuses@npm:~2.0.1, statuses@npm:~2.0.2": + version: 2.0.2 + resolution: "statuses@npm:2.0.2" + checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f + languageName: node + linkType: hard + +"std-env@npm:^3.7.0": + version: 3.10.0 + resolution: "std-env@npm:3.10.0" + checksum: 10c0/1814927a45004d36dde6707eaf17552a546769bc79a6421be2c16ce77d238158dfe5de30910b78ec30d95135cc1c59ea73ee22d2ca170f8b9753f84da34c427f + languageName: node + linkType: hard + +"streamsearch@npm:0.1.2": + version: 0.1.2 + resolution: "streamsearch@npm:0.1.2" + checksum: 10c0/408a3db5b5643c1d6eb65c9d8ccc011b4857bfca41946d808b7f165b5b85f47755b2ff56ec1c4bbbeb5a496afcde9adfea12f9f67bd09ff3f04ae3f1f58d37c6 + languageName: node + linkType: hard + +"string-width@npm:^4.1.0, string-width@npm:^4.2.0": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b + languageName: node + linkType: hard + +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: "npm:~5.2.0" + checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d + languageName: node + linkType: hard + +"string_decoder@npm:~1.1.1": + version: 1.1.1 + resolution: "string_decoder@npm:1.1.1" + dependencies: + safe-buffer: "npm:~5.1.0" + checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e + languageName: node + linkType: hard + +"stringify-entities@npm:^4.0.0": + version: 4.0.4 + resolution: "stringify-entities@npm:4.0.4" + dependencies: + character-entities-html4: "npm:^2.0.0" + character-entities-legacy: "npm:^3.0.0" + checksum: 10c0/537c7e656354192406bdd08157d759cd615724e9d0873602d2c9b2f6a5c0a8d0b1d73a0a08677848105c5eebac6db037b57c0b3a4ec86331117fa7319ed50448 + languageName: node + linkType: hard + +"stringify-object@npm:^3.3.0": + version: 3.3.0 + resolution: "stringify-object@npm:3.3.0" + dependencies: + get-own-enumerable-property-symbols: "npm:^3.0.0" + is-obj: "npm:^1.0.1" + is-regexp: "npm:^1.0.0" + checksum: 10c0/ba8078f84128979ee24b3de9a083489cbd3c62cb8572a061b47d4d82601a8ae4b4d86fa8c54dd955593da56bb7c16a6de51c27221fdc6b7139bb4f29d815f35b + languageName: node + linkType: hard + +"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: "npm:^5.0.1" + checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 + languageName: node + linkType: hard + +"strip-bom-string@npm:^1.0.0": + version: 1.0.0 + resolution: "strip-bom-string@npm:1.0.0" + checksum: 10c0/5c5717e2643225aa6a6d659d34176ab2657037f1fe2423ac6fcdb488f135e14fef1022030e426d8b4d0989e09adbd5c3288d5d3b9c632abeefd2358dfc512bca + languageName: node + linkType: hard + +"strip-final-newline@npm:^2.0.0": + version: 2.0.0 + resolution: "strip-final-newline@npm:2.0.0" + checksum: 10c0/bddf8ccd47acd85c0e09ad7375409d81653f645fda13227a9d459642277c253d877b68f2e5e4d819fe75733b0e626bac7e954c04f3236f6d196f79c94fa4a96f + languageName: node + linkType: hard + +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd + languageName: node + linkType: hard + +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + languageName: node + linkType: hard + +"style-to-js@npm:^1.0.0": + version: 1.1.16 + resolution: "style-to-js@npm:1.1.16" + dependencies: + style-to-object: "npm:1.0.8" + checksum: 10c0/578a4dff804539ec7e64d3cc8d327540befb9ad30e3cd0b6b0392f93f793f3a028f90084a9aaff088bffb87818fa2c6c153f0df576f61f9ab0b0938b582bcac7 + languageName: node + linkType: hard + +"style-to-object@npm:1.0.8": + version: 1.0.8 + resolution: "style-to-object@npm:1.0.8" + dependencies: + inline-style-parser: "npm:0.2.4" + checksum: 10c0/daa6646b1ff18258c0ca33ed281fbe73485c8391192db1b56ce89d40c93ea64507a41e8701d0dadfe771bc2f540c46c9b295135f71584c8e5cb23d6a19be9430 + languageName: node + linkType: hard + +"stylehacks@npm:^6.1.1": + version: 6.1.1 + resolution: "stylehacks@npm:6.1.1" + dependencies: + browserslist: "npm:^4.23.0" + postcss-selector-parser: "npm:^6.0.16" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/2dd2bccfd8311ff71492e63a7b8b86c3d7b1fff55d4ba5a2357aff97743e633d351cdc2f5ae3c0057637d00dab4ef5fc5b218a1b370e4585a41df22b5a5128be + languageName: node + linkType: hard + +"stylis@npm:^4.3.6": + version: 4.3.6 + resolution: "stylis@npm:4.3.6" + checksum: 10c0/e736d484983a34f7c65d362c67dc79b7bce388054b261c2b7b23d02eaaf280617033f65d44b1ea341854f4331a5074b885668ac8741f98c13a6cfd6443ae85d0 + languageName: node + linkType: hard + +"supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 + languageName: node + linkType: hard + +"supports-color@npm:^8.0.0": + version: 8.1.1 + resolution: "supports-color@npm:8.1.1" + dependencies: + has-flag: "npm:^4.0.0" + checksum: 10c0/ea1d3c275dd604c974670f63943ed9bd83623edc102430c05adb8efc56ba492746b6e95386e7831b872ec3807fd89dd8eb43f735195f37b5ec343e4234cc7e89 + languageName: node + linkType: hard + +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 + languageName: node + linkType: hard + +"svg-parser@npm:^2.0.4": + version: 2.0.4 + resolution: "svg-parser@npm:2.0.4" + checksum: 10c0/02f6cb155dd7b63ebc2f44f36365bc294543bebb81b614b7628f1af3c54ab64f7e1cec20f06e252bf95bdde78441ae295a412c68ad1678f16a6907d924512b7a + languageName: node + linkType: hard + +"svgo@npm:^3.0.2, svgo@npm:^3.2.0": + version: 3.3.3 + resolution: "svgo@npm:3.3.3" + dependencies: + commander: "npm:^7.2.0" + css-select: "npm:^5.1.0" + css-tree: "npm:^2.3.1" + css-what: "npm:^6.1.0" + csso: "npm:^5.0.5" + picocolors: "npm:^1.0.0" + sax: "npm:^1.5.0" + bin: + svgo: ./bin/svgo + checksum: 10c0/06568c6b0430f96748c557f0b17dc7de79b19fa16d13d7523527ede0ec727fc6d8e6a10e13ff106dc4372d2e6063a1dca7c455c495efb1b83857480425f9b965 + languageName: node + linkType: hard + +"swc-loader@npm:^0.2.6": + version: 0.2.7 + resolution: "swc-loader@npm:0.2.7" + dependencies: + "@swc/counter": "npm:^0.1.3" + peerDependencies: + "@swc/core": ^1.2.147 + webpack: ">=2" + checksum: 10c0/9c1b275adf9b83d7245e0e30a1dd41b0f6dbb0164267f772f855adc325a615c30a9d343e7362b585834350e2d9632ecd2239e03fa8f15a2d2e699a99e438d363 + languageName: node + linkType: hard + +"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0, tapable@npm:^2.2.1": + version: 2.2.1 + resolution: "tapable@npm:2.2.1" + checksum: 10c0/bc40e6efe1e554d075469cedaba69a30eeb373552aaf41caeaaa45bf56ffacc2674261b106245bd566b35d8f3329b52d838e851ee0a852120acae26e622925c9 + languageName: node + linkType: hard + +"tar@npm:^7.5.4": + version: 7.5.13 + resolution: "tar@npm:7.5.13" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.1.0" + yallist: "npm:^5.0.0" + checksum: 10c0/5c65b8084799bde7a791593a1c1a45d3d6ee98182e3700b24c247b7b8f8654df4191642abbdb07ff25043d45dcff35620827c3997b88ae6c12040f64bed5076b + languageName: node + linkType: hard + +"terser-webpack-plugin@npm:^5.3.11, terser-webpack-plugin@npm:^5.3.9": + version: 5.3.14 + resolution: "terser-webpack-plugin@npm:5.3.14" + dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.25" + jest-worker: "npm:^27.4.5" + schema-utils: "npm:^4.3.0" + serialize-javascript: "npm:^6.0.2" + terser: "npm:^5.31.1" + peerDependencies: + webpack: ^5.1.0 + peerDependenciesMeta: + "@swc/core": + optional: true + esbuild: + optional: true + uglify-js: + optional: true + checksum: 10c0/9b060947241af43bd6fd728456f60e646186aef492163672a35ad49be6fbc7f63b54a7356c3f6ff40a8f83f00a977edc26f044b8e106cc611c053c8c0eaf8569 + languageName: node + linkType: hard + +"terser@npm:^5.10.0, terser@npm:^5.15.1, terser@npm:^5.31.1": + version: 5.39.0 + resolution: "terser@npm:5.39.0" + dependencies: + "@jridgewell/source-map": "npm:^0.3.3" + acorn: "npm:^8.8.2" + commander: "npm:^2.20.0" + source-map-support: "npm:~0.5.20" + bin: + terser: bin/terser + checksum: 10c0/83326545ea1aecd6261030568b6191ccfa4cb6aa61d9ea41746a52479f50017a78b77e4725fbbc207c5df841ffa66a773c5ac33636e95c7ab94fe7e0379ae5c7 + languageName: node + linkType: hard + +"thingies@npm:^2.5.0": + version: 2.6.0 + resolution: "thingies@npm:2.6.0" + peerDependencies: + tslib: ^2 + checksum: 10c0/6357247872cfd0ef5407455eab2724ccbf591f0b1a56a230c66ab139dc0a8bb4acaf85c177af0eee7a49740a4674c424529eca3e573b439eb256afed4e433fac + languageName: node + linkType: hard + +"thunky@npm:^1.0.2": + version: 1.1.0 + resolution: "thunky@npm:1.1.0" + checksum: 10c0/369764f39de1ce1de2ba2fa922db4a3f92e9c7f33bcc9a713241bc1f4a5238b484c17e0d36d1d533c625efb00e9e82c3e45f80b47586945557b45abb890156d2 + languageName: node + linkType: hard + +"tiny-invariant@npm:^1.0.2": + version: 1.3.3 + resolution: "tiny-invariant@npm:1.3.3" + checksum: 10c0/65af4a07324b591a059b35269cd696aba21bef2107f29b9f5894d83cc143159a204b299553435b03874ebb5b94d019afa8b8eff241c8a4cfee95872c2e1c1c4a + languageName: node + linkType: hard + +"tiny-warning@npm:^1.0.0": + version: 1.0.3 + resolution: "tiny-warning@npm:1.0.3" + checksum: 10c0/ef8531f581b30342f29670cb41ca248001c6fd7975ce22122bd59b8d62b4fc84ad4207ee7faa95cde982fa3357cd8f4be650142abc22805538c3b1392d7084fa + languageName: node + linkType: hard + +"tinyexec@npm:^1.0.1": + version: 1.0.4 + resolution: "tinyexec@npm:1.0.4" + checksum: 10c0/d4a5bbcf6bdb23527a4b74c4aa566f41432167112fe76f420ec7e3a90a3ecfd3a7d944383e2719fc3987b69400f7b928daf08700d145fb527c2e80ec01e198bd + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.3" + checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 + languageName: node + linkType: hard + +"tinypool@npm:^1.0.2": + version: 1.1.1 + resolution: "tinypool@npm:1.1.1" + checksum: 10c0/bf26727d01443061b04fa863f571016950888ea994ba0cd8cba3a1c51e2458d84574341ab8dbc3664f1c3ab20885c8cf9ff1cc4b18201f04c2cde7d317fff69b + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 + languageName: node + linkType: hard + +"toidentifier@npm:1.0.1, toidentifier@npm:~1.0.1": + version: 1.0.1 + resolution: "toidentifier@npm:1.0.1" + checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 + languageName: node + linkType: hard + +"totalist@npm:^3.0.0": + version: 3.0.1 + resolution: "totalist@npm:3.0.1" + checksum: 10c0/4bb1fadb69c3edbef91c73ebef9d25b33bbf69afe1e37ce544d5f7d13854cda15e47132f3e0dc4cafe300ddb8578c77c50a65004d8b6e97e77934a69aa924863 + languageName: node + linkType: hard + +"tree-dump@npm:^1.0.3, tree-dump@npm:^1.1.0": + version: 1.1.0 + resolution: "tree-dump@npm:1.1.0" + peerDependencies: + tslib: 2 + checksum: 10c0/079f0f0163b68ee2eedc65cab1de6fb121487eba9ae135c106a8bc5e4ab7906ae0b57d86016e4a7da8c0ee906da1eae8c6a1490cd6e2a5e5ccbca321e1f959ca + languageName: node + linkType: hard + +"trim-lines@npm:^3.0.0": + version: 3.0.1 + resolution: "trim-lines@npm:3.0.1" + checksum: 10c0/3a1611fa9e52aa56a94c69951a9ea15b8aaad760eaa26c56a65330dc8adf99cb282fc07cc9d94968b7d4d88003beba220a7278bbe2063328eb23fb56f9509e94 + languageName: node + linkType: hard + +"trough@npm:^2.0.0": + version: 2.2.0 + resolution: "trough@npm:2.2.0" + checksum: 10c0/58b671fc970e7867a48514168894396dd94e6d9d6456aca427cc299c004fe67f35ed7172a36449086b2edde10e78a71a284ec0076809add6834fb8f857ccb9b0 + languageName: node + linkType: hard + +"ts-dedent@npm:^2.2.0": + version: 2.2.0 + resolution: "ts-dedent@npm:2.2.0" + checksum: 10c0/175adea838468cc2ff7d5e97f970dcb798bbcb623f29c6088cb21aa2880d207c5784be81ab1741f56b9ac37840cbaba0c0d79f7f8b67ffe61c02634cafa5c303 + languageName: node + linkType: hard + +"tslib@npm:^1.9.3": + version: 1.14.1 + resolution: "tslib@npm:1.14.1" + checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 + languageName: node + linkType: hard + +"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.4.0, tslib@npm:^2.6.0, tslib@npm:^2.8.1": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + +"tsyringe@npm:^4.10.0": + version: 4.10.0 + resolution: "tsyringe@npm:4.10.0" + dependencies: + tslib: "npm:^1.9.3" + checksum: 10c0/918594b4dfac97beb8be2c041c6ec45f078ef3768ed4edfe35ae2c709ab503e2e6b454b2b37e692c658572d1972a428fbfdbc0a2b42fee727a83c1c685fbe5e1 + languageName: node + linkType: hard + +"type-fest@npm:^0.21.3": + version: 0.21.3 + resolution: "type-fest@npm:0.21.3" + checksum: 10c0/902bd57bfa30d51d4779b641c2bc403cdf1371fb9c91d3c058b0133694fcfdb817aef07a47f40faf79039eecbaa39ee9d3c532deff244f3a19ce68cea71a61e8 + languageName: node + linkType: hard + +"type-fest@npm:^1.0.1": + version: 1.4.0 + resolution: "type-fest@npm:1.4.0" + checksum: 10c0/a3c0f4ee28ff6ddf800d769eafafcdeab32efa38763c1a1b8daeae681920f6e345d7920bf277245235561d8117dab765cb5f829c76b713b4c9de0998a5397141 + languageName: node + linkType: hard + +"type-fest@npm:^2.13.0, type-fest@npm:^2.5.0": + version: 2.19.0 + resolution: "type-fest@npm:2.19.0" + checksum: 10c0/a5a7ecf2e654251613218c215c7493574594951c08e52ab9881c9df6a6da0aeca7528c213c622bc374b4e0cb5c443aa3ab758da4e3c959783ce884c3194e12cb + languageName: node + linkType: hard + +"type-is@npm:~1.6.18": + version: 1.6.18 + resolution: "type-is@npm:1.6.18" + dependencies: + media-typer: "npm:0.3.0" + mime-types: "npm:~2.1.24" + checksum: 10c0/a23daeb538591b7efbd61ecf06b6feb2501b683ffdc9a19c74ef5baba362b4347e42f1b4ed81f5882a8c96a3bfff7f93ce3ffaf0cbbc879b532b04c97a55db9d + languageName: node + linkType: hard + +"typedarray-to-buffer@npm:^3.1.5": + version: 3.1.5 + resolution: "typedarray-to-buffer@npm:3.1.5" + dependencies: + is-typedarray: "npm:^1.0.0" + checksum: 10c0/4ac5b7a93d604edabf3ac58d3a2f7e07487e9f6e98195a080e81dbffdc4127817f470f219d794a843b87052cedef102b53ac9b539855380b8c2172054b7d5027 + languageName: node + linkType: hard + +"ufo@npm:^1.6.3": + version: 1.6.3 + resolution: "ufo@npm:1.6.3" + checksum: 10c0/bf0e4ebff99e54da1b9c7182ac2f40475988b41faa881d579bc97bc2a0509672107b0a0e94c4b8d31a0ab8c4bf07f4aa0b469ac6da8536d56bda5b085ea2e953 + languageName: node + linkType: hard + +"undici-types@npm:~6.20.0": + version: 6.20.0 + resolution: "undici-types@npm:6.20.0" + checksum: 10c0/68e659a98898d6a836a9a59e6adf14a5d799707f5ea629433e025ac90d239f75e408e2e5ff086afc3cace26f8b26ee52155293564593fbb4a2f666af57fc59bf + languageName: node + linkType: hard + +"undici@npm:^4.11.1": + version: 4.16.0 + resolution: "undici@npm:4.16.0" + checksum: 10c0/f0b709016eef145e37254c1894a9ca6c769e11e5995d9beb02409be1fc372c2eb53df90299181140d9bdb3f89c4d0f162e03213511a4e75e19757157d325acb7 + languageName: node + linkType: hard + +"unicode-canonical-property-names-ecmascript@npm:^2.0.0": + version: 2.0.1 + resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.1" + checksum: 10c0/f83bc492fdbe662860795ef37a85910944df7310cac91bd778f1c19ebc911e8b9cde84e703de631e5a2fcca3905e39896f8fc5fc6a44ddaf7f4aff1cda24f381 + languageName: node + linkType: hard + +"unicode-emoji-modifier-base@npm:^1.0.0": + version: 1.0.0 + resolution: "unicode-emoji-modifier-base@npm:1.0.0" + checksum: 10c0/b37623fcf0162186debd20f116483e035a2d5b905b932a2c472459d9143d446ebcbefb2a494e2fe4fa7434355396e2a95ec3fc1f0c29a3bc8f2c827220e79c66 + languageName: node + linkType: hard + +"unicode-match-property-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-match-property-ecmascript@npm:2.0.0" + dependencies: + unicode-canonical-property-names-ecmascript: "npm:^2.0.0" + unicode-property-aliases-ecmascript: "npm:^2.0.0" + checksum: 10c0/4d05252cecaf5c8e36d78dc5332e03b334c6242faf7cf16b3658525441386c0a03b5f603d42cbec0f09bb63b9fd25c9b3b09667aee75463cac3efadae2cd17ec + languageName: node + linkType: hard + +"unicode-match-property-value-ecmascript@npm:^2.2.1": + version: 2.2.1 + resolution: "unicode-match-property-value-ecmascript@npm:2.2.1" + checksum: 10c0/93acd1ad9496b600e5379d1aaca154cf551c5d6d4a0aefaf0984fc2e6288e99220adbeb82c935cde461457fb6af0264a1774b8dfd4d9a9e31548df3352a4194d + languageName: node + linkType: hard + +"unicode-property-aliases-ecmascript@npm:^2.0.0": + version: 2.2.0 + resolution: "unicode-property-aliases-ecmascript@npm:2.2.0" + checksum: 10c0/b338529831c988ac696f2bdbcd4579d1c5cc844b24eda7269973c457fa81989bdb49a366af37a448eb1a60f1dae89559ea2a5854db2797e972a0162eee0778c6 + languageName: node + linkType: hard + +"unified@npm:^11.0.0, unified@npm:^11.0.3, unified@npm:^11.0.4": + version: 11.0.5 + resolution: "unified@npm:11.0.5" + dependencies: + "@types/unist": "npm:^3.0.0" + bail: "npm:^2.0.0" + devlop: "npm:^1.0.0" + extend: "npm:^3.0.0" + is-plain-obj: "npm:^4.0.0" + trough: "npm:^2.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/53c8e685f56d11d9d458a43e0e74328a4d6386af51c8ac37a3dcabec74ce5026da21250590d4aff6733ccd7dc203116aae2b0769abc18cdf9639a54ae528dfc9 + languageName: node + linkType: hard + +"unique-string@npm:^3.0.0": + version: 3.0.0 + resolution: "unique-string@npm:3.0.0" + dependencies: + crypto-random-string: "npm:^4.0.0" + checksum: 10c0/b35ea034b161b2a573666ec16c93076b4b6106b8b16c2415808d747ab3a0566b5db0c4be231d4b11cfbc16d7fd915c9d8a45884bff0e2db11b799775b2e1e017 + languageName: node + linkType: hard + +"unist-util-is@npm:^6.0.0": + version: 6.0.0 + resolution: "unist-util-is@npm:6.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/9419352181eaa1da35eca9490634a6df70d2217815bb5938a04af3a662c12c5607a2f1014197ec9c426fbef18834f6371bfdb6f033040fa8aa3e965300d70e7e + languageName: node + linkType: hard + +"unist-util-position-from-estree@npm:^2.0.0": + version: 2.0.0 + resolution: "unist-util-position-from-estree@npm:2.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/39127bf5f0594e0a76d9241dec4f7aa26323517120ce1edd5ed91c8c1b9df7d6fb18af556e4b6250f1c7368825720ed892e2b6923be5cdc08a9bb16536dc37b3 + languageName: node + linkType: hard + +"unist-util-position@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-position@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dde3b31e314c98f12b4dc6402f9722b2bf35e96a4f2d463233dd90d7cde2d4928074a7a11eff0a5eb1f4e200f27fc1557e0a64a7e8e4da6558542f251b1b7400 + languageName: node + linkType: hard + +"unist-util-stringify-position@npm:^4.0.0": + version: 4.0.0 + resolution: "unist-util-stringify-position@npm:4.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + checksum: 10c0/dfe1dbe79ba31f589108cb35e523f14029b6675d741a79dea7e5f3d098785045d556d5650ec6a8338af11e9e78d2a30df12b1ee86529cded1098da3f17ee999e + languageName: node + linkType: hard + +"unist-util-visit-parents@npm:^6.0.0": + version: 6.0.1 + resolution: "unist-util-visit-parents@npm:6.0.1" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + checksum: 10c0/51b1a5b0aa23c97d3e03e7288f0cdf136974df2217d0999d3de573c05001ef04cccd246f51d2ebdfb9e8b0ed2704451ad90ba85ae3f3177cf9772cef67f56206 + languageName: node + linkType: hard + +"unist-util-visit@npm:^5.0.0": + version: 5.0.0 + resolution: "unist-util-visit@npm:5.0.0" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-is: "npm:^6.0.0" + unist-util-visit-parents: "npm:^6.0.0" + checksum: 10c0/51434a1d80252c1540cce6271a90fd1a106dbe624997c09ed8879279667fb0b2d3a685e02e92bf66598dcbe6cdffa7a5f5fb363af8fdf90dda6c855449ae39a5 + languageName: node + linkType: hard + +"universalify@npm:^2.0.0": + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: 10c0/73e8ee3809041ca8b818efb141801a1004e3fc0002727f1531f4de613ea281b494a40909596dae4a042a4fb6cd385af5d4db2e137b1362e0e91384b828effd3a + languageName: node + linkType: hard + +"unpipe@npm:~1.0.0": + version: 1.0.0 + resolution: "unpipe@npm:1.0.0" + checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c + languageName: node + linkType: hard + +"update-browserslist-db@npm:^1.2.0, update-browserslist-db@npm:^1.2.3": + version: 1.2.3 + resolution: "update-browserslist-db@npm:1.2.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec + languageName: node + linkType: hard + +"update-notifier@npm:^6.0.2": + version: 6.0.2 + resolution: "update-notifier@npm:6.0.2" + dependencies: + boxen: "npm:^7.0.0" + chalk: "npm:^5.0.1" + configstore: "npm:^6.0.0" + has-yarn: "npm:^3.0.0" + import-lazy: "npm:^4.0.0" + is-ci: "npm:^3.0.1" + is-installed-globally: "npm:^0.4.0" + is-npm: "npm:^6.0.0" + is-yarn-global: "npm:^0.4.0" + latest-version: "npm:^7.0.0" + pupa: "npm:^3.1.0" + semver: "npm:^7.3.7" + semver-diff: "npm:^4.0.0" + xdg-basedir: "npm:^5.1.0" + checksum: 10c0/ad3980073312df904133a6e6c554a7f9d0832ed6275e55f5a546313fe77a0f20f23a7b1b4aeb409e20a78afb06f4d3b2b28b332d9cfb55745b5d1ea155810bcc + languageName: node + linkType: hard + +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c + languageName: node + linkType: hard + +"url-loader@npm:^4.1.1": + version: 4.1.1 + resolution: "url-loader@npm:4.1.1" + dependencies: + loader-utils: "npm:^2.0.0" + mime-types: "npm:^2.1.27" + schema-utils: "npm:^3.0.0" + peerDependencies: + file-loader: "*" + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + file-loader: + optional: true + checksum: 10c0/71b6300e02ce26c70625eae1a2297c0737635038c62691bb3007ac33e85c0130efc74bfb444baf5c6b3bad5953491159d31d66498967d1417865d0c7e7cd1a64 + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 + languageName: node + linkType: hard + +"utila@npm:~0.4": + version: 0.4.0 + resolution: "utila@npm:0.4.0" + checksum: 10c0/2791604e09ca4f77ae314df83e80d1805f867eb5c7e13e7413caee01273c278cf2c9a3670d8d25c889a877f7b149d892fe61b0181a81654b425e9622ab23d42e + languageName: node + linkType: hard + +"utility-types@npm:^3.10.0": + version: 3.11.0 + resolution: "utility-types@npm:3.11.0" + checksum: 10c0/2f1580137b0c3e6cf5405f37aaa8f5249961a76d26f1ca8efc0ff49a2fc0e0b2db56de8e521a174d075758e0c7eb3e590edec0832eb44478b958f09914920f19 + languageName: node + linkType: hard + +"utils-merge@npm:1.0.1": + version: 1.0.1 + resolution: "utils-merge@npm:1.0.1" + checksum: 10c0/02ba649de1b7ca8854bfe20a82f1dfbdda3fb57a22ab4a8972a63a34553cf7aa51bc9081cf7e001b035b88186d23689d69e71b510e610a09a4c66f68aa95b672 + languageName: node + linkType: hard + +"uuid@npm:^11.1.0": + version: 11.1.0 + resolution: "uuid@npm:11.1.0" + bin: + uuid: dist/esm/bin/uuid + checksum: 10c0/34aa51b9874ae398c2b799c88a127701408cd581ee89ec3baa53509dd8728cbb25826f2a038f9465f8b7be446f0fbf11558862965b18d21c993684297628d4d3 + languageName: node + linkType: hard + +"uuid@npm:^8.3.2": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 + languageName: node + linkType: hard + +"value-equal@npm:^1.0.1": + version: 1.0.1 + resolution: "value-equal@npm:1.0.1" + checksum: 10c0/79068098355483ef29f4d3753999ad880875b87625d7e9055cad9346ea4b7662aad3a66f87976801b0dd7a6f828ba973d28b1669ebcd37eaf88cc5f687c1a691 + languageName: node + linkType: hard + +"vary@npm:~1.1.2": + version: 1.1.2 + resolution: "vary@npm:1.1.2" + checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f + languageName: node + linkType: hard + +"vfile-location@npm:^5.0.0": + version: 5.0.3 + resolution: "vfile-location@npm:5.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile: "npm:^6.0.0" + checksum: 10c0/1711f67802a5bc175ea69750d59863343ed43d1b1bb25c0a9063e4c70595e673e53e2ed5cdbb6dcdc370059b31605144d95e8c061b9361bcc2b036b8f63a4966 + languageName: node + linkType: hard + +"vfile-message@npm:^4.0.0": + version: 4.0.2 + resolution: "vfile-message@npm:4.0.2" + dependencies: + "@types/unist": "npm:^3.0.0" + unist-util-stringify-position: "npm:^4.0.0" + checksum: 10c0/07671d239a075f888b78f318bc1d54de02799db4e9dce322474e67c35d75ac4a5ac0aaf37b18801d91c9f8152974ea39678aa72d7198758b07f3ba04fb7d7514 + languageName: node + linkType: hard + +"vfile@npm:^6.0.0, vfile@npm:^6.0.1": + version: 6.0.3 + resolution: "vfile@npm:6.0.3" + dependencies: + "@types/unist": "npm:^3.0.0" + vfile-message: "npm:^4.0.0" + checksum: 10c0/e5d9eb4810623f23758cfc2205323e33552fb5972e5c2e6587babe08fe4d24859866277404fb9e2a20afb71013860d96ec806cb257536ae463c87d70022ab9ef + languageName: node + linkType: hard + +"vscode-jsonrpc@npm:8.2.0": + version: 8.2.0 + resolution: "vscode-jsonrpc@npm:8.2.0" + checksum: 10c0/0789c227057a844f5ead55c84679206227a639b9fb76e881185053abc4e9848aa487245966cc2393fcb342c4541241b015a1a2559fddd20ac1e68945c95344e6 + languageName: node + linkType: hard + +"vscode-languageserver-protocol@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-protocol@npm:3.17.5" + dependencies: + vscode-jsonrpc: "npm:8.2.0" + vscode-languageserver-types: "npm:3.17.5" + checksum: 10c0/5f38fd80da9868d706eaa4a025f4aff9c3faad34646bcde1426f915cbd8d7e8b6c3755ce3fef6eebd256ba3145426af1085305f8a76e34276d2e95aaf339a90b + languageName: node + linkType: hard + +"vscode-languageserver-textdocument@npm:~1.0.11": + version: 1.0.12 + resolution: "vscode-languageserver-textdocument@npm:1.0.12" + checksum: 10c0/534349894b059602c4d97615a1147b6c4c031141c2093e59657f54e38570f5989c21b376836f13b9375419869242e9efb4066643208b21ab1e1dee111a0f00fb + languageName: node + linkType: hard + +"vscode-languageserver-types@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-types@npm:3.17.5" + checksum: 10c0/1e1260de79a2cc8de3e46f2e0182cdc94a7eddab487db5a3bd4ee716f67728e685852707d72c059721ce500447be9a46764a04f0611e94e4321ffa088eef36f8 + languageName: node + linkType: hard + +"vscode-languageserver@npm:~9.0.1": + version: 9.0.1 + resolution: "vscode-languageserver@npm:9.0.1" + dependencies: + vscode-languageserver-protocol: "npm:3.17.5" + bin: + installServerIntoExtension: bin/installServerIntoExtension + checksum: 10c0/8a0838d77c98a211c76e54bd3a6249fc877e4e1a73322673fb0e921168d8e91de4f170f1d4ff7e8b6289d0698207afc6aba6662d4c1cd8e4bd7cae96afd6b0c2 + languageName: node + linkType: hard + +"vscode-uri@npm:~3.1.0": + version: 3.1.0 + resolution: "vscode-uri@npm:3.1.0" + checksum: 10c0/5f6c9c10fd9b1664d71fab4e9fbbae6be93c7f75bb3a1d9d74399a88ab8649e99691223fd7cef4644376cac6e94fa2c086d802521b9a8e31c5af3e60f0f35624 + languageName: node + linkType: hard + +"watchpack@npm:^2.4.1": + version: 2.4.2 + resolution: "watchpack@npm:2.4.2" + dependencies: + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.1.2" + checksum: 10c0/ec60a5f0e9efaeca0102fd9126346b3b2d523e01c34030d3fddf5813a7125765121ebdc2552981136dcd2c852deb1af0b39340f2fcc235f292db5399d0283577 + languageName: node + linkType: hard + +"wbuf@npm:^1.1.0, wbuf@npm:^1.7.3": + version: 1.7.3 + resolution: "wbuf@npm:1.7.3" + dependencies: + minimalistic-assert: "npm:^1.0.0" + checksum: 10c0/56edcc5ef2b3d30913ba8f1f5cccc364d180670b24d5f3f8849c1e6fb514e5c7e3a87548ae61227a82859eba6269c11393ae24ce12a2ea1ecb9b465718ddced7 + languageName: node + linkType: hard + +"web-namespaces@npm:^2.0.0": + version: 2.0.1 + resolution: "web-namespaces@npm:2.0.1" + checksum: 10c0/df245f466ad83bd5cd80bfffc1674c7f64b7b84d1de0e4d2c0934fb0782e0a599164e7197a4bce310ee3342fd61817b8047ff04f076a1ce12dd470584142a4bd + languageName: node + linkType: hard + +"webpack-bundle-analyzer@npm:^4.10.2": + version: 4.10.2 + resolution: "webpack-bundle-analyzer@npm:4.10.2" + dependencies: + "@discoveryjs/json-ext": "npm:0.5.7" + acorn: "npm:^8.0.4" + acorn-walk: "npm:^8.0.0" + commander: "npm:^7.2.0" + debounce: "npm:^1.2.1" + escape-string-regexp: "npm:^4.0.0" + gzip-size: "npm:^6.0.0" + html-escaper: "npm:^2.0.2" + opener: "npm:^1.5.2" + picocolors: "npm:^1.0.0" + sirv: "npm:^2.0.3" + ws: "npm:^7.3.1" + bin: + webpack-bundle-analyzer: lib/bin/analyzer.js + checksum: 10c0/00603040e244ead15b2d92981f0559fa14216381349412a30070a7358eb3994cd61a8221d34a3b3fb8202dc3d1c5ee1fbbe94c5c52da536e5b410aa1cf279a48 + languageName: node + linkType: hard + +"webpack-dev-middleware@npm:^7.4.2": + version: 7.4.5 + resolution: "webpack-dev-middleware@npm:7.4.5" + dependencies: + colorette: "npm:^2.0.10" + memfs: "npm:^4.43.1" + mime-types: "npm:^3.0.1" + on-finished: "npm:^2.4.1" + range-parser: "npm:^1.2.1" + schema-utils: "npm:^4.0.0" + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + webpack: + optional: true + checksum: 10c0/e72fa7de3b1589c0c518976358f946d9ec97699a3eb90bfd40718f4be3e9d5d13dc80f748c5c16662efbf1400cedbb523c79f56a778e6e8ffbdf1bd93be547eb + languageName: node + linkType: hard + +"webpack-dev-server@npm:^5.2.2": + version: 5.2.3 + resolution: "webpack-dev-server@npm:5.2.3" + dependencies: + "@types/bonjour": "npm:^3.5.13" + "@types/connect-history-api-fallback": "npm:^1.5.4" + "@types/express": "npm:^4.17.25" + "@types/express-serve-static-core": "npm:^4.17.21" + "@types/serve-index": "npm:^1.9.4" + "@types/serve-static": "npm:^1.15.5" + "@types/sockjs": "npm:^0.3.36" + "@types/ws": "npm:^8.5.10" + ansi-html-community: "npm:^0.0.8" + bonjour-service: "npm:^1.2.1" + chokidar: "npm:^3.6.0" + colorette: "npm:^2.0.10" + compression: "npm:^1.8.1" + connect-history-api-fallback: "npm:^2.0.0" + express: "npm:^4.22.1" + graceful-fs: "npm:^4.2.6" + http-proxy-middleware: "npm:^2.0.9" + ipaddr.js: "npm:^2.1.0" + launch-editor: "npm:^2.6.1" + open: "npm:^10.0.3" + p-retry: "npm:^6.2.0" + schema-utils: "npm:^4.2.0" + selfsigned: "npm:^5.5.0" + serve-index: "npm:^1.9.1" + sockjs: "npm:^0.3.24" + spdy: "npm:^4.0.2" + webpack-dev-middleware: "npm:^7.4.2" + ws: "npm:^8.18.0" + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + webpack: + optional: true + webpack-cli: + optional: true + bin: + webpack-dev-server: bin/webpack-dev-server.js + checksum: 10c0/a716f1d509635ad9f2779baf242657740e6ad516ce210fe094cbf3b16f25f114e477c45a751ad2bbf1c601cbbe67b6ba9b8b43159b7c01fc3342c95b985fe963 + languageName: node + linkType: hard + +"webpack-merge@npm:^5.9.0": + version: 5.10.0 + resolution: "webpack-merge@npm:5.10.0" + dependencies: + clone-deep: "npm:^4.0.1" + flat: "npm:^5.0.2" + wildcard: "npm:^2.0.0" + checksum: 10c0/b607c84cabaf74689f965420051a55a08722d897bdd6c29cb0b2263b451c090f962d41ecf8c9bf56b0ab3de56e65476ace0a8ecda4f4a4663684243d90e0512b + languageName: node + linkType: hard + +"webpack-merge@npm:^6.0.1": + version: 6.0.1 + resolution: "webpack-merge@npm:6.0.1" + dependencies: + clone-deep: "npm:^4.0.1" + flat: "npm:^5.0.2" + wildcard: "npm:^2.0.1" + checksum: 10c0/bf1429567858b353641801b8a2696ca0aac270fc8c55d4de8a7b586fe07d27fdcfc83099a98ab47e6162383db8dd63bb8cc25b1beb2ec82150422eec843b0dc0 + languageName: node + linkType: hard + +"webpack-sources@npm:^3.2.3": + version: 3.2.3 + resolution: "webpack-sources@npm:3.2.3" + checksum: 10c0/2ef63d77c4fad39de4a6db17323d75eb92897b32674e97d76f0a1e87c003882fc038571266ad0ef581ac734cbe20952912aaa26155f1905e96ce251adbb1eb4e + languageName: node + linkType: hard + +"webpack@npm:^5.88.1, webpack@npm:^5.95.0": + version: 5.98.0 + resolution: "webpack@npm:5.98.0" + dependencies: + "@types/eslint-scope": "npm:^3.7.7" + "@types/estree": "npm:^1.0.6" + "@webassemblyjs/ast": "npm:^1.14.1" + "@webassemblyjs/wasm-edit": "npm:^1.14.1" + "@webassemblyjs/wasm-parser": "npm:^1.14.1" + acorn: "npm:^8.14.0" + browserslist: "npm:^4.24.0" + chrome-trace-event: "npm:^1.0.2" + enhanced-resolve: "npm:^5.17.1" + es-module-lexer: "npm:^1.2.1" + eslint-scope: "npm:5.1.1" + events: "npm:^3.2.0" + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.2.11" + json-parse-even-better-errors: "npm:^2.3.1" + loader-runner: "npm:^4.2.0" + mime-types: "npm:^2.1.27" + neo-async: "npm:^2.6.2" + schema-utils: "npm:^4.3.0" + tapable: "npm:^2.1.1" + terser-webpack-plugin: "npm:^5.3.11" + watchpack: "npm:^2.4.1" + webpack-sources: "npm:^3.2.3" + peerDependenciesMeta: + webpack-cli: + optional: true + bin: + webpack: bin/webpack.js + checksum: 10c0/bee4fa77f444802f0beafb2ff30eb5454a606163ad7d3cc9a5dcc9d24033c62407bed04601b25dea49ea3969b352c1b530a86c753246f42560a4a084eefb094e + languageName: node + linkType: hard + +"webpackbar@npm:^6.0.1": + version: 6.0.1 + resolution: "webpackbar@npm:6.0.1" + dependencies: + ansi-escapes: "npm:^4.3.2" + chalk: "npm:^4.1.2" + consola: "npm:^3.2.3" + figures: "npm:^3.2.0" + markdown-table: "npm:^2.0.0" + pretty-time: "npm:^1.1.0" + std-env: "npm:^3.7.0" + wrap-ansi: "npm:^7.0.0" + peerDependencies: + webpack: 3 || 4 || 5 + checksum: 10c0/8dfa2c55f8122f729c7efd515a2b50fb752c0d0cb27ec2ecdbc70d90a86d5f69f466c9c5d01004f71b500dafba957ecd4413fca196a98cf99a39b705f98cae97 + languageName: node + linkType: hard + +"websocket-driver@npm:>=0.5.1, websocket-driver@npm:^0.7.4": + version: 0.7.4 + resolution: "websocket-driver@npm:0.7.4" + dependencies: + http-parser-js: "npm:>=0.5.1" + safe-buffer: "npm:>=5.1.0" + websocket-extensions: "npm:>=0.1.1" + checksum: 10c0/5f09547912b27bdc57bac17b7b6527d8993aa4ac8a2d10588bb74aebaf785fdcf64fea034aae0c359b7adff2044dd66f3d03866e4685571f81b13e548f9021f1 + languageName: node + linkType: hard + +"websocket-extensions@npm:>=0.1.1": + version: 0.1.4 + resolution: "websocket-extensions@npm:0.1.4" + checksum: 10c0/bbc8c233388a0eb8a40786ee2e30d35935cacbfe26ab188b3e020987e85d519c2009fe07cfc37b7f718b85afdba7e54654c9153e6697301f72561bfe429177e0 + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: "npm:^2.0.0" + bin: + node-which: ./bin/node-which + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + languageName: node + linkType: hard + +"which@npm:^6.0.0": + version: 6.0.1 + resolution: "which@npm:6.0.1" + dependencies: + isexe: "npm:^4.0.0" + bin: + node-which: bin/which.js + checksum: 10c0/7e710e54ea36d2d6183bee2f9caa27a3b47b9baf8dee55a199b736fcf85eab3b9df7556fca3d02b50af7f3dfba5ea3a45644189836df06267df457e354da66d5 + languageName: node + linkType: hard + +"widest-line@npm:^4.0.1": + version: 4.0.1 + resolution: "widest-line@npm:4.0.1" + dependencies: + string-width: "npm:^5.0.1" + checksum: 10c0/7da9525ba45eaf3e4ed1a20f3dcb9b85bd9443962450694dae950f4bdd752839747bbc14713522b0b93080007de8e8af677a61a8c2114aa553ad52bde72d0f9c + languageName: node + linkType: hard + +"wildcard@npm:^2.0.0, wildcard@npm:^2.0.1": + version: 2.0.1 + resolution: "wildcard@npm:2.0.1" + checksum: 10c0/08f70cd97dd9a20aea280847a1fe8148e17cae7d231640e41eb26d2388697cbe65b67fd9e68715251c39b080c5ae4f76d71a9a69fa101d897273efdfb1b58bf7 + languageName: node + linkType: hard + +"wrangler@npm:^0.0.7": + version: 0.0.7 + resolution: "wrangler@npm:0.0.7" + dependencies: + esbuild: "npm:0.14.1" + fsevents: "npm:~2.3.2" + miniflare: "npm:2.0.0-rc.5" + path-to-regexp: "npm:^6.2.0" + semiver: "npm:^1.1.0" + dependenciesMeta: + fsevents: + optional: true + bin: + wrangler: bin/wrangler.js + wrangler2: bin/wrangler.js + checksum: 10c0/49a7e1876dd746d7e55d816f5edcd7d12e6fd8aa851230a20f5c8ca6312a3dee696899a5072db0ff7bb5f3d9524350e36d249d03b0f75f30320b0fe401278dbe + languageName: node + linkType: hard + +"wrap-ansi@npm:^7.0.0": + version: 7.0.0 + resolution: "wrap-ansi@npm:7.0.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.0.1, wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 + languageName: node + linkType: hard + +"write-file-atomic@npm:^3.0.3": + version: 3.0.3 + resolution: "write-file-atomic@npm:3.0.3" + dependencies: + imurmurhash: "npm:^0.1.4" + is-typedarray: "npm:^1.0.0" + signal-exit: "npm:^3.0.2" + typedarray-to-buffer: "npm:^3.1.5" + checksum: 10c0/7fb67affd811c7a1221bed0c905c26e28f0041e138fb19ccf02db57a0ef93ea69220959af3906b920f9b0411d1914474cdd90b93a96e5cd9e8368d9777caac0e + languageName: node + linkType: hard + +"ws@npm:^7.3.1": + version: 7.5.10 + resolution: "ws@npm:7.5.10" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/bd7d5f4aaf04fae7960c23dcb6c6375d525e00f795dd20b9385902bd008c40a94d3db3ce97d878acc7573df852056ca546328b27b39f47609f80fb22a0a9b61d + languageName: node + linkType: hard + +"ws@npm:^8.18.0": + version: 8.20.0 + resolution: "ws@npm:8.20.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/956ac5f11738c914089b65878b9223692ace77337ba55379ae68e1ecbeae9b47a0c6eb9403688f609999a58c80d83d99865fe0029b229d308b08c1ef93d4ea14 + languageName: node + linkType: hard + +"ws@npm:^8.2.2": + version: 8.18.1 + resolution: "ws@npm:8.18.1" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/e498965d6938c63058c4310ffb6967f07d4fa06789d3364829028af380d299fe05762961742971c764973dce3d1f6a2633fe8b2d9410c9b52e534b4b882a99fa + languageName: node + linkType: hard + +"wsl-utils@npm:^0.1.0": + version: 0.1.0 + resolution: "wsl-utils@npm:0.1.0" + dependencies: + is-wsl: "npm:^3.1.0" + checksum: 10c0/44318f3585eb97be994fc21a20ddab2649feaf1fbe893f1f866d936eea3d5f8c743bec6dc02e49fbdd3c0e69e9b36f449d90a0b165a4f47dd089747af4cf2377 + languageName: node + linkType: hard + +"xdg-basedir@npm:^5.0.1, xdg-basedir@npm:^5.1.0": + version: 5.1.0 + resolution: "xdg-basedir@npm:5.1.0" + checksum: 10c0/c88efabc71ffd996ba9ad8923a8cc1c7c020a03e2c59f0ffa72e06be9e724ad2a0fccef488757bc6ed3d8849d753dd25082d1035d95cb179e79eae4d034d0b80 + languageName: node + linkType: hard + +"xml-js@npm:^1.6.11": + version: 1.6.11 + resolution: "xml-js@npm:1.6.11" + dependencies: + sax: "npm:^1.2.4" + bin: + xml-js: ./bin/cli.js + checksum: 10c0/c83631057f10bf90ea785cee434a8a1a0030c7314fe737ad9bf568a281083b565b28b14c9e9ba82f11fc9dc582a3a907904956af60beb725be1c9ad4b030bc5a + languageName: node + linkType: hard + +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a + languageName: node + linkType: hard + +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard + +"yocto-queue@npm:^1.0.0": + version: 1.2.2 + resolution: "yocto-queue@npm:1.2.2" + checksum: 10c0/36d4793e9cf7060f9da543baf67c55e354f4862c8d3d34de1a1b1d7c382d44171315cc54abf84d8900b8113d742b830108a1434f4898fb244f9b7e8426d4b8f5 + languageName: node + linkType: hard + +"youch@npm:^2.2.2": + version: 2.2.2 + resolution: "youch@npm:2.2.2" + dependencies: + "@types/stack-trace": "npm:0.0.29" + cookie: "npm:^0.4.1" + mustache: "npm:^4.2.0" + stack-trace: "npm:0.0.10" + checksum: 10c0/6e21211e6177a464b993480a79dbcf29bbdc747605e1cff240f473d2f5ef7e43c58dc98aa202292063f96c175d317843dfd65ad3d0d810ca4650015822f9f6af + languageName: node + linkType: hard + +"zwitch@npm:^2.0.0": + version: 2.0.4 + resolution: "zwitch@npm:2.0.4" + checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e + languageName: node + linkType: hard

    + Crocodocs +